diff -urN oldtree/Documentation/Changes newtree/Documentation/Changes
--- oldtree/Documentation/Changes	2006-02-19 11:40:58.167621664 +0000
+++ newtree/Documentation/Changes	2006-02-21 15:58:33.925989024 +0000
@@ -54,6 +54,7 @@
 o  e2fsprogs              1.29                    # tune2fs
 o  jfsutils               1.1.3                   # fsck.jfs -V
 o  reiserfsprogs          3.6.3                   # reiserfsck -V 2>&1|grep reiserfsprogs
+o  reiser4progs           1.0.0                   # fsck.reiser4 -V
 o  xfsprogs               2.6.0                   # xfs_db -V
 o  pcmciautils            004
 o  pcmcia-cs              3.1.21                  # cardmgr -V
@@ -163,6 +164,13 @@
 versions of mkreiserfs, resize_reiserfs, debugreiserfs and
 reiserfsck. These utils work on both i386 and alpha platforms.
 
+Reiser4progs
+------------
+
+The reiser4progs package contains utilities for the reiser4 file system.
+Detailed instructions are provided in the README file located at:
+<ftp://ftp.namesys.com/pub/reiser4progs/README>.
+
 Xfsprogs
 --------
 
@@ -344,6 +352,10 @@
 -------------
 o  <http://www.namesys.com/pub/reiserfsprogs/reiserfsprogs-3.6.3.tar.gz>
 
+Reiser4progs
+------------
+o  <ftp://ftp.namesys.com/pub/reiser4progs/>
+
 Xfsprogs
 --------
 o  <ftp://oss.sgi.com/projects/xfs/download/>
diff -urN oldtree/Documentation/acpi/sony_acpi.txt newtree/Documentation/acpi/sony_acpi.txt
--- oldtree/Documentation/acpi/sony_acpi.txt	1970-01-01 00:00:00.000000000 +0000
+++ newtree/Documentation/acpi/sony_acpi.txt	2006-02-21 15:58:11.065464352 +0000
@@ -0,0 +1,87 @@
+ACPI Sony Notebook Control Driver (SNC) Readme
+----------------------------------------------
+	Copyright (C) 2004- 2005 Stelian Pop <stelian@popies.net>
+
+This mini-driver drives the ACPI SNC device present in the
+ACPI BIOS of the Sony Vaio laptops.
+
+It gives access to some extra laptop functionalities. In
+its current form, this driver is mainly useful for controlling the
+screen brightness, but it may do more in the future.
+
+You should probably start by trying the sonypi driver, and try
+sony_acpi only if sonypi doesn't work for you.
+
+Usage:
+------
+
+Loading the sony_acpi module will create a /proc/acpi/sony/
+directory populated with a couple of files.
+
+You then read/write integer values from/to those files by using
+standard UNIX tools.
+
+The files are:
+	brightness		current screen brightness
+	brightness_default	screen brightness which will be set
+				when the laptop will be rebooted
+	cdpower			power on/off the internal CD drive
+
+Note that some files may be missing if they are not supported
+by your particular laptop model.
+
+Example usage:
+	# echo "1" > /proc/acpi/sony/brightness
+sets the lowest screen brightness,
+	# echo "8" > /proc/acpi/sony/brightness
+sets the highest screen brightness,
+	# cat /proc/acpi/sony/brightness
+retrieves the current screen brightness.
+
+Development:
+------------
+
+If you want to help with the development of this driver (and
+you are not afraid of any side effects doing strange things with
+your ACPI BIOS could have on your laptop), load the driver and
+pass the option 'debug=1'.
+
+REPEAT: DON'T DO THIS IF YOU DON'T LIKE RISKY BUSINESS.
+
+In your kernel logs you will find the list of all ACPI methods
+the SNC device has on your laptop. You can see the GBRT/SBRT methods
+used to get/set the brightness, but there are others.
+
+I HAVE NO IDEA WHAT THOSE METHODS DO.
+
+The sony_acpi driver creates, for some of those methods (the most
+current ones found on several Vaio models), an entry under
+/proc/acpi/sony/, just like the 'brightness' one. You can create
+other entries corresponding to your own laptop methods by further
+editing the source (see the 'sony_acpi_values' table, and add a new
+structure to this table with your get/set method names).
+
+Your mission, should you accept it, is to try finding out what
+those entries are for, by reading/writing random values from/to those
+files and find out what is the impact on your laptop.
+
+Should you find anything interesting, please report it back to me,
+I will not disavow all knowledge of your actions :)
+
+Bugs/Limitations:
+-----------------
+
+* This driver is not based on official documentation from Sony
+  (because there is none), so there is no guarantee this driver
+  will work at all, or do the right thing. Although this hasn't
+  happened to me, this driver could do very bad things to your
+  laptop, including permanent damage.
+
+* The sony_acpi and sonypi drivers do not interact at all. In the
+  future, sonypi could use sony_acpi to do (part of) its business.
+
+* spicctrl, which is the userspace tool used to communicate with the
+  sonypi driver (through /dev/sonypi) does not try to use the
+  sony_acpi driver. In the future, spicctrl could try sonypi first,
+  and if it isn't present, try sony_acpi instead.
+
diff -urN oldtree/Documentation/aoe/mkdevs.sh newtree/Documentation/aoe/mkdevs.sh
--- oldtree/Documentation/aoe/mkdevs.sh	2006-01-03 03:21:10.000000000 +0000
+++ newtree/Documentation/aoe/mkdevs.sh	2006-02-21 15:58:12.982172968 +0000
@@ -27,6 +27,8 @@
 mknod -m 0200 $dir/discover c $MAJOR 3
 rm -f $dir/interfaces
 mknod -m 0200 $dir/interfaces c $MAJOR 4
+rm -f $dir/revalidate
+mknod -m 0200 $dir/revalidate c $MAJOR 5
 
 export n_partitions
 mkshelf=`echo $0 | sed 's!mkdevs!mkshelf!'`
diff -urN oldtree/Documentation/aoe/udev.txt newtree/Documentation/aoe/udev.txt
--- oldtree/Documentation/aoe/udev.txt	2006-01-03 03:21:10.000000000 +0000
+++ newtree/Documentation/aoe/udev.txt	2006-02-21 15:58:12.982172968 +0000
@@ -18,6 +18,7 @@
 SUBSYSTEM="aoe", KERNEL="discover",	NAME="etherd/%k", GROUP="disk", MODE="0220"
 SUBSYSTEM="aoe", KERNEL="err",		NAME="etherd/%k", GROUP="disk", MODE="0440"
 SUBSYSTEM="aoe", KERNEL="interfaces",	NAME="etherd/%k", GROUP="disk", MODE="0220"
+SUBSYSTEM="aoe", KERNEL="revalidate",	NAME="etherd/%k", GROUP="disk", MODE="0220"
 
 # aoe block devices     
 KERNEL="etherd*",       NAME="%k", GROUP="disk"
diff -urN oldtree/Documentation/cpusets.txt newtree/Documentation/cpusets.txt
--- oldtree/Documentation/cpusets.txt	2006-02-19 11:40:58.178619992 +0000
+++ newtree/Documentation/cpusets.txt	2006-02-21 15:58:29.568651440 +0000
@@ -17,7 +17,8 @@
   1.4 What are exclusive cpusets ?
   1.5 What does notify_on_release do ?
   1.6 What is memory_pressure ?
-  1.7 How do I use cpusets ?
+  1.7 What is memory spread ?
+  1.8 How do I use cpusets ?
 2. Usage Examples and Syntax
   2.1 Basic Usage
   2.2 Adding/removing cpus
@@ -315,7 +316,78 @@
 times 1000.
 
 
-1.7 How do I use cpusets ?
+1.7 What is memory spread ?
+---------------------------
+There are two boolean flag files per cpuset that control where the
+kernel allocates pages for the file system buffers and related in
+kernel data structures.  They are called 'memory_spread_page' and
+'memory_spread_slab'.
+
+If the per-cpuset boolean flag file 'memory_spread_page' is set, then
+the kernel will spread the file system buffers (page cache) evenly
+over all the nodes that the faulting task is allowed to use, instead
+of preferring to put those pages on the node where the task is running.
+
+If the per-cpuset boolean flag file 'memory_spread_slab' is set,
+then the kernel will spread some file system related slab caches,
+such as for inodes and dentries evenly over all the nodes that the
+faulting task is allowed to use, instead of preferring to put those
+pages on the node where the task is running.
+
+The setting of these flags does not affect anonymous data segment or
+stack segment pages of a task.
+
+By default, both kinds of memory spreading are off, and memory
+pages are allocated on the node local to where the task is running,
+except perhaps as modified by the tasks NUMA mempolicy or cpuset
+configuration, so long as sufficient free memory pages are available.
+
+When new cpusets are created, they inherit the memory spread settings
+of their parent.
+
+Setting memory spreading causes allocations for the affected page
+or slab caches to ignore the tasks NUMA mempolicy and be spread
+instead.    Tasks using mbind() or set_mempolicy() calls to set NUMA
+mempolicies will not notice any change in these calls as a result of
+their containing tasks memory spread settings.  If memory spreading
+is turned off, then the currently specified NUMA mempolicy once again
+applies to memory page allocations.
+
+Both 'memory_spread_page' and 'memory_spread_slab' are boolean flag
+files.  By default they contain "0", meaning that the feature is off
+for that cpuset.  If a "1" is written to that file, then that turns
+the named feature on.
+
+The implementation is simple.
+
+Setting the flag 'memory_spread_page' turns on a per-process flag
+PF_SPREAD_PAGE for each task that is in that cpuset or subsequently
+joins that cpuset.  The page allocation calls for the page cache
+is modified to perform an inline check for this PF_SPREAD_PAGE task
+flag, and if set, a call to a new routine cpuset_mem_spread_node()
+returns the node to prefer for the allocation.
+
+Similarly, setting 'memory_spread_cache' turns on the flag
+PF_SPREAD_SLAB, and appropriately marked slab caches will allocate
+pages from the node returned by cpuset_mem_spread_node().
+
+The cpuset_mem_spread_node() routine is also simple.  It uses the
+value of a per-task rotor cpuset_mem_spread_rotor to select the next
+node in the current tasks mems_allowed to prefer for the allocation.
+
+This memory placement policy is also known (in other contexts) as
+round-robin or interleave.
+
+This policy can provide substantial improvements for jobs that need
+to place thread local data on the corresponding node, but that need
+to access large file system data sets that need to be spread across
+the several nodes in the jobs cpuset in order to fit.  Without this
+policy, especially for jobs that might have one thread reading in the
+data set, the memory allocation across the nodes in the jobs cpuset
+can become very uneven.
+
+
+1.8 How do I use cpusets ?
 --------------------------
 
 In order to minimize the impact of cpusets on critical kernel
diff -urN oldtree/Documentation/feature-removal-schedule.txt newtree/Documentation/feature-removal-schedule.txt
--- oldtree/Documentation/feature-removal-schedule.txt	2006-02-19 11:40:58.184619080 +0000
+++ newtree/Documentation/feature-removal-schedule.txt	2006-02-21 15:58:30.183557960 +0000
@@ -26,7 +26,7 @@
 ---------------------------
 
 What:	drivers depending on OBSOLETE_OSS_DRIVER
-When:	January 2006
+When:	before 2.6.18
 Why:	OSS drivers with ALSA replacements
 Who:	Adrian Bunk <bunk@stusta.de>
 
@@ -151,6 +151,13 @@
 
 ---------------------------
 
+What:   eepro100 network driver
+When:   January 2007
+Why:    replaced by the e100 driver
+Who:    Adrian Bunk <bunk@stusta.de>
+
+---------------------------
+
 What:	Legacy /proc/pci interface (PCI_LEGACY_PROC)
 When:	March 2006
 Why:	deprecated since 2.5.53 in favor of lspci(8)
@@ -171,3 +178,22 @@
 	probing is also known to cause trouble in at least one case (see
 	bug #5889.)
 Who:	Jean Delvare <khali@linux-fr.org>
+
+---------------------------
+
+What:	USB driver API moves to EXPORT_SYMBOL_GPL
+When:	Febuary 2008
+Files:	include/linux/usb.h, drivers/usb/core/driver.c
+Why:	The USB subsystem has changed a lot over time, and it has been
+	possible to create userspace USB drivers using usbfs/libusb/gadgetfs
+	that operate as fast as the USB bus allows.  Because of this, the USB
+	subsystem will not be allowing closed source kernel drivers to
+	register with it, after this grace period is over.  If anyone needs
+	any help in converting their closed source drivers over to use the
+	userspace filesystems, please contact the
+	linux-usb-devel@lists.sourceforge.net mailing list, and the developers
+	there will be glad to help you out.
+Who:	Greg Kroah-Hartman <gregkh@suse.de>
+
+---------------------------
+
diff -urN oldtree/Documentation/filesystems/00-INDEX newtree/Documentation/filesystems/00-INDEX
--- oldtree/Documentation/filesystems/00-INDEX	2006-02-19 11:40:58.185618928 +0000
+++ newtree/Documentation/filesystems/00-INDEX	2006-02-21 15:58:33.131109864 +0000
@@ -6,6 +6,8 @@
 	- info and mount options for the Acorn Advanced Disc Filing System.
 affs.txt
 	- info and mount options for the Amiga Fast File System.
+asfs.txt
+	- info and mount options for the Amiga Smart File System.
 bfs.txt
 	- info for the SCO UnixWare Boot Filesystem (BFS).
 cifs.txt
diff -urN oldtree/Documentation/filesystems/asfs.txt newtree/Documentation/filesystems/asfs.txt
--- oldtree/Documentation/filesystems/asfs.txt	1970-01-01 00:00:00.000000000 +0000
+++ newtree/Documentation/filesystems/asfs.txt	2006-02-21 15:58:33.131109864 +0000
@@ -0,0 +1,161 @@
+
+Amiga SmartFileSystem, Linux implementation
+===========================================
+
+ASFS is a Amiga Smart FileSystem driver for Linux. It supports reading
+files and directories. From version 1.0 there is also an experimental
+(almost full) write support. Experimental means that it hasn't been
+tested enough yet, so use it with care. Symbolic links (in AmigaOS
+called soft links) are also supported read/write. Read notes below
+about symlinks support.
+
+
+Unsupported features of Amiga SFS
+================================
+
+ASFS currently does not support safe-delete feature of Amiga SFS
+filesystem. It simply deletes files instead of moving them to
+".recycled" directory. It also doesn't remove files from ".recycled"
+directory, when there is no space left on drive.
+
+If there is no space left, you need to manually remove files from
+".recycled" directory. Also if you want to delete a file in a safe
+way, you need to move it to ".recycled" directory by hand.
+
+Because of all of above, the amount of free space on disk does not
+include space used by all files from ".recycled" directory.
+
+
+Limitations
+===========
+
+There is no Amiga protection bits into Linux permission bits tranlation
+and vice versa. If you need this feature, mail me.
+
+ASFS will always keep some amount of blocks free. This means that you
+cannot fill the drive completely. It is because Amiga SFS uses some
+special methods of writing data (called safe write), which needs some
+additional free space.
+
+File systems with unfinished transactions (this happens when system crashed
+during writing data to disk on AmigaOS/MorphOS) will be mounted read-only
+to protect data. The only way to fix such filesystem is to mount it under
+AmigaOS or MorphOS.
+
+Do not try to mount and write to filesystem with errors. Bad things will
+happen.
+
+
+Mount options for the ASFS
+==========================
+
+setuid=uid
+		This sets the owner of all files and directories in the file
+		system to uid.
+
+setgid=gid
+		Same as above, but for gid.
+
+mode=mode
+		Sets the mode flags to the given (octal) value. Directories
+		will get an x permission if the corresponding r bit is set.
+		The default mode is 0644, which means that everybody are allowed
+		to read files, but only root can write to them.
+		(for directories this means also that search bits are set).
+
+prefix=path
+		Path will be prefixed to every absolute path name of symbolic
+		links on an ASFS/AFFS partition. Default = "/". (See below.)
+
+volume=name
+		When symbolic links with an absolute path are created
+		on an ASFS/AFFS partition, name will be prepended as the
+		volume name. Default = "" (empty string). (See below.)
+
+lowercasevol
+		Translate all volume names in symlinks to lower case.
+		Disabled by default. (See below.)
+
+iocharset=name
+		Character set to use for converting file names. Specifies
+		character set used by your Linux system.
+codepage=name
+		Set the codepage number for converting file names. Specifies
+		character set used by your Amiga. Use full name (for example
+		'cp1251' instead of '1251') here, this allows to specify any
+		character set, not only numbered one (like 'iso8859-2').
+		Use special name 'none' to disable the NLS file name
+		translation.
+
+Symbolic links
+==============
+
+Although the Amiga and Linux file systems resemble each other, there
+are some, not always subtle, differences. One of them becomes apparent
+with symbolic links. While Linux has a file system with exactly one
+root directory, the Amiga has a separate root directory for each
+file system (for example, partition, floppy disk, ...). With the Amiga,
+these entities are called "volumes". They have symbolic names which
+can be used to access them. Thus, symbolic links can point to a
+different volume. ASFS turns the volume name into a directory name
+and prepends the prefix path (see prefix option) to it. When option
+"lowercasevol" is set, it also translates volume names to lower case.
+If the volume name is the same as a name given in "volume" option,
+it will be ignored and an absolute path will be created.
+
+Example:
+You mount all your Amiga partitions under /amiga/<volume> (where
+<volume> is the name of the volume), and you give options
+`prefix="/amiga/",volume="Linux",lowercasevol' when mounting all your
+ASFS partitions. (They might be "User", "WB" and "Graphics", the mount
+points /amiga/user, /amiga/wb and /amiga/graphics).
+
+A symbolic link referring to "USER:sc/include/dos/dos.h" will be
+translated to "/amiga/user/sc/include/dos/dos.h".
+A symbolic link referring to "Linux:etc/fstab" will be translated to
+"/etc/fstab".
+If you create a symlink referring to "/amiga/graphics/data/pict.jpg",
+it will be saved as "graphics:data/pict.jpg".
+If you create a symlink referring to "/boot/System.map", it will be
+saved as "Linux:boot/System.map".
+
+
+Other information
+=================
+
+Supported block sizes are: 512, 1024, 2048 and 4096 bytes. Larger blocks
+speed up almost everything at the expense of wasted disk space. The speed
+gain above 4K seems not really worth the price, so you don't lose too
+much here, either.
+
+This file system has been tested on Motorola PPC and 68k, as well as
+Intel x86 systems. I don't know, if it works on other Linux systems.
+
+This filesystem is in BETA STAGE. This means that driver MIGHT corrupt
+or damage data on your disk. Remember! YOU USE IT ON YOUR OWN RISK!
+
+I made almost all I could to minimalize this risk. On my systems several
+gigabytes has been succesfully copied from and to SFS disks. I would also
+appreciate any infomation if this filesystem works on your system or not.
+See next paragraph for my email.
+
+Some parts of this documentation has been adapted from AFFS driver docs.
+
+
+Author, contact and copyright infos
+===================================
+
+ASFS has been written by Marek 'March' Szyprowski <marek@amiga.pl>.
+Mail me if you have any suggestions or found a bug.
+
+Copyright (C) 2003,2004,2005  Marek 'March' Szyprowski <marek@amiga.pl>
+
+Thanks to Marcin Kurek (Morgoth/Dreamolers-CAPS) for help and parts
+of original amiga version of SmartFilesystem source code.
+
+SmartFilesystem is copyrighted (C) 2003,2004 by: John Hendrikx,
+Ralph Schmidt, Emmanuel Lesueur, David Gerber and Marcin Kurek
+
+The ASFS driver is realased under the terms of of the GNU General
+Public License. See source code for more details.
+
diff -urN oldtree/Documentation/filesystems/reiser4.txt newtree/Documentation/filesystems/reiser4.txt
--- oldtree/Documentation/filesystems/reiser4.txt	1970-01-01 00:00:00.000000000 +0000
+++ newtree/Documentation/filesystems/reiser4.txt	2006-02-21 15:58:33.939986896 +0000
@@ -0,0 +1,75 @@
+Reiser4 filesystem
+==================
+Reiser4 is a file system based on dancing tree algorithms, and is
+described at http://www.namesys.com
+
+
+References
+==========
+web page		http://namesys.com/v4/v4.html
+source code		ftp://ftp.namesys.com/pub/reiser4-for-2.6/
+userland tools		ftp://ftp.namesys.com/pub/reiser4progs/
+install page		http://www.namesys.com/install_v4.html
+
+Compile options
+===============
+Enable reiser4 debug mode
+       This checks everything imaginable while reiser4
+       runs
+
+Mount options
+=============
+tmgr.atom_max_size=N
+	Atoms containing more than N blocks will be forced to commit.
+	N is decimal.
+	Default is nr_free_pagecache_pages() / 2 at mount time.
+
+tmgr.atom_max_age=N
+	Atoms older than N seconds will be forced to commit. N is decimal.
+	Default is 600.
+
+tmgr.atom_max_flushers=N
+	Limit of concurrent flushers for one atom. 0 means no limit.
+	Default is 0.
+
+tree.cbk_cache.nr_slots=N
+	Number of slots in the cbk cache.
+
+flush.relocate_threshold=N
+	If flush finds more than N adjacent dirty leaf-level blocks it
+	will force them to be relocated.
+	Default is 64.
+
+flush.relocate_distance=N
+	If flush finds can find a block allocation closer than at most
+	N from the preceder it will relocate to that position.
+	Default is 64.
+
+flush.scan_maxnodes=N
+	The maximum number of nodes to scan left on a level during
+	flush.
+	Default is 10000.
+
+optimal_io_size=N
+	Preferred IO size. This value is used to set st_blksize of
+	struct stat.
+	Default is 65536.
+
+bsdgroups
+	Turn on BSD-style gid assignment.
+
+32bittimes
+	By default file in reiser4 have 64 bit timestamps. Files
+	created when filesystem is mounted with 32bittimes mount
+	option will get 32 bit timestamps.
+
+mtflush
+	Turn off concurrent flushing.
+
+nopseudo
+	Disable pseudo files support. See
+	http://namesys.com/v4/pseudo.html for more about pseudo files.
+
+dont_load_bitmap
+	Don't load all bitmap blocks at mount time, it is useful for
+	machines with tiny RAM and large disks.
diff -urN oldtree/Documentation/hwmon/w83627hf newtree/Documentation/hwmon/w83627hf
--- oldtree/Documentation/hwmon/w83627hf	2006-02-19 11:40:58.196617256 +0000
+++ newtree/Documentation/hwmon/w83627hf	2006-02-21 15:58:14.370961840 +0000
@@ -18,6 +18,10 @@
     Prefix: 'w83637hf'
     Addresses scanned: ISA address retrieved from Super I/O registers
     Datasheet: http://www.winbond.com/PDF/sheet/w83637hf.pdf
+  * Winbond W83687THF
+    Prefix: 'w83687thf'
+    Addresses scanned: ISA address retrieved from Super I/O registers
+    Datasheet: Provided by Winbond on request
 
 Authors:
         Frodo Looijaard <frodol@dds.nl>,
diff -urN oldtree/Documentation/hwmon/w83781d newtree/Documentation/hwmon/w83781d
--- oldtree/Documentation/hwmon/w83781d	2006-01-03 03:21:10.000000000 +0000
+++ newtree/Documentation/hwmon/w83781d	2006-02-21 15:58:14.430952720 +0000
@@ -36,6 +36,11 @@
   Use 'init=0' to bypass initializing the chip.
   Try this if your computer crashes when you load the module.
 
+* reset int
+  (default 0)
+  The driver used to reset the chip on load, but does no more. Use
+  'reset=1' to restore the old behavior. Report if you need to do this.
+
 force_subclients=bus,caddr,saddr,saddr
   This is used to force the i2c addresses for subclients of
   a certain chip. Typical usage is `force_subclients=0,0x2d,0x4a,0x4b'
@@ -123,6 +128,25 @@
 your computer speaker. It is possible to enable all beeping globally,
 or only the beeping for some alarms.
 
+Individual alarm and beep bits:
+
+0x000001: in0
+0x000002: in1
+0x000004: in2
+0x000008: in3
+0x000010: temp1
+0x000020: temp2 (+temp3 on W83781D)
+0x000040: fan1
+0x000080: fan2
+0x000100: in4
+0x000200: in5
+0x000400: in6
+0x000800: fan3
+0x001000: chassis
+0x002000: temp3 (W83782D and W83627HF only)
+0x010000: in7 (W83782D and W83627HF only)
+0x020000: in8 (W83782D and W83627HF only)
+
 If an alarm triggers, it will remain triggered until the hardware register
 is read at least once. This means that the cause for the alarm may
 already have disappeared! Note that in the current implementation, all
diff -urN oldtree/Documentation/i2c/busses/scx200_acb newtree/Documentation/i2c/busses/scx200_acb
--- oldtree/Documentation/i2c/busses/scx200_acb	2006-01-03 03:21:10.000000000 +0000
+++ newtree/Documentation/i2c/busses/scx200_acb	2006-02-21 15:58:14.032013368 +0000
@@ -6,9 +6,10 @@
 -----------------
 
 * base: int
-  Base addresses for the ACCESS.bus controllers
+  Base addresses for the ACCESS.bus controllers on SCx200 and SC1100 devices
 
 Description
 -----------
 
-Enable the use of the ACCESS.bus controllers of a SCx200 processor.
+Enable the use of the ACCESS.bus controller on the Geode SCx200 and
+SC1100 processors and the CS5535 and CS5536 Geode companion devices.
diff -urN oldtree/Documentation/leds-class.txt newtree/Documentation/leds-class.txt
--- oldtree/Documentation/leds-class.txt	1970-01-01 00:00:00.000000000 +0000
+++ newtree/Documentation/leds-class.txt	2006-02-21 15:58:31.124414928 +0000
@@ -0,0 +1,71 @@
+LED handling under Linux
+========================
+
+If you're reading this and thinking about keyboard leds, these are
+handled by the input subsystem and the led class is *not* needed.
+
+In its simplest form, the LED class just allows control of LEDs from
+userspace. LEDs appear in /sys/class/leds/. The brightness file will
+set the brightness of the LED (taking a value 0-255). Most LEDs don't
+have hardware brightness support so will just be turned on for non-zero
+brightness settings.
+
+The class also introduces the optional concept of an LED trigger. A trigger
+is a kernel based source of led events. Triggers can either be simple or
+complex. A simple trigger isn't configurable and is designed to slot into
+existing subsystems with minimal additional code. Examples are the ide-disk,
+nand-disk and sharpsl-charge triggers. With led triggers disabled, the code
+optimises away.
+
+Complex triggers whilst available to all LEDs have LED specific
+parameters and work on a per LED basis. The timer trigger is an example.
+
+You can change triggers in a similar manner to the way an IO scheduler
+is chosen (via /sys/class/leds/<device>/trigger). Trigger specific
+parameters can appear in /sys/class/leds/<device> once a given trigger is
+selected.
+
+
+Design Philosophy
+=================
+
+The underlying design philosophy is simplicity. LEDs are simple devices
+and the aim is to keep a small amount of code giving as much functionality
+as possible.  Please keep this in mind when suggesting enhancements.
+
+
+LED Device Naming
+=================
+
+Is currently of the form:
+
+"devicename:colour"
+
+There have been calls for LED properties such as colour to be exported as
+individual led class attributes. As a solution which doesn't incur as much
+overhead, I suggest these become part of the device name. The naming scheme
+above leaves scope for further attributes should they be needed.
+
+
+Known Issues
+============
+
+The LED Trigger core cannot be a module as the simple trigger functions
+would cause nightmare dependency issues. I see this as a minor issue
+compared to the benefits the simple trigger functionality brings. The
+rest of the LED subsystem can be modular.
+
+Some leds can be programmed to flash in hardware. As this isn't a generic
+LED device property, this should be exported as a device specific sysfs
+attribute rather than part of the class if this functionality is required.
+
+
+Future Development
+==================
+
+At the moment, a trigger can't be created specifically for a single LED.
+There are a number of cases where a trigger might only be mappable to a
+particular LED (ACPI?). The addition of triggers provided by the LED driver
+should cover this option and be possible to add without breaking the
+current interface.
+
diff -urN oldtree/Documentation/networking/ip-sysctl.txt newtree/Documentation/networking/ip-sysctl.txt
--- oldtree/Documentation/networking/ip-sysctl.txt	2006-02-19 11:40:58.209615280 +0000
+++ newtree/Documentation/networking/ip-sysctl.txt	2006-02-21 15:58:16.108697664 +0000
@@ -717,6 +717,33 @@
 	Functional default: enabled if local forwarding is disabled.
 			    disabled if local forwarding is enabled.
 
+accept_ra_defrtr - BOOLEAN
+	Learn default router in Router Advertisement.
+
+	Functional default: enabled if accept_ra is enabled.
+			    disabled if accept_ra is disabled.
+
+accept_ra_pinfo - BOOLEAN
+	Learn Prefix Inforamtion in Router Advertisement.
+
+	Functional default: enabled if accept_ra is enabled.
+			    disabled if accept_ra is disabled.
+
+accept_ra_rt_info_max_plen - INTEGER
+	Maximum prefix length of Route Information in RA.
+
+	Route Information w/ prefix larger than or equal to this
+	variable shall be ignored.
+
+	Functional default: 0 if accept_ra_rtr_pref is enabled.
+			    -1 if accept_ra_rtr_pref is disabled.
+
+accept_ra_rtr_pref - BOOLEAN
+	Accept Router Preference in RA.
+
+	Functional default: enabled if accept_ra is enabled.
+			    disabled if accept_ra is disabled.
+
 accept_redirects - BOOLEAN
 	Accept Redirects.
 
@@ -727,8 +754,8 @@
 	Autoconfigure addresses using Prefix Information in Router 
 	Advertisements.
 
-	Functional default: enabled if accept_ra is enabled.
-			    disabled if accept_ra is disabled.
+	Functional default: enabled if accept_ra_pinfo is enabled.
+			    disabled if accept_ra_pinfo is disabled.
 
 dad_transmits - INTEGER
 	The amount of Duplicate Address Detection probes to send.
@@ -771,6 +798,12 @@
 	Default Maximum Transfer Unit
 	Default: 1280 (IPv6 required minimum)
 
+router_probe_interval - INTEGER
+	Minimum interval (in seconds) between Router Probing described
+	in RFC4191.
+
+	Default: 60
+
 router_solicitation_delay - INTEGER
 	Number of seconds to wait after interface is brought up
 	before sending Router Solicitations.
diff -urN oldtree/Documentation/nfsroot.txt newtree/Documentation/nfsroot.txt
--- oldtree/Documentation/nfsroot.txt	2006-01-03 03:21:10.000000000 +0000
+++ newtree/Documentation/nfsroot.txt	2006-02-21 15:58:30.096571184 +0000
@@ -3,6 +3,7 @@
 
 Written 1996 by Gero Kuhlmann <gero@gkminix.han.de>
 Updated 1997 by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+Updated 2006 by Nico Schottelius <nico-kernel-nfsroot@schottelius.org>
 
 
 
@@ -168,7 +169,6 @@
 	root. If it got a BOOTP answer the directory name in that answer
 	is used.
 
-
 3.2) Using LILO
 	When using LILO you can specify all necessary command line
 	parameters with the 'append=' command in the LILO configuration
@@ -177,7 +177,11 @@
 	LILO and its 'append=' command please refer to the LILO
 	documentation.
 
-3.3) Using loadlin
+3.3) Using GRUB
+	When you use GRUB, you simply append the parameters after the kernel
+	specification: "kernel <kernel> <parameters>" (without the quotes).
+
+3.4) Using loadlin
 	When you want to boot Linux from a DOS command prompt without
 	having a local hard disk to mount as root, you can use loadlin.
 	I was told that it works, but haven't used it myself yet. In
@@ -185,7 +189,7 @@
 	lar to how LILO is doing it. Please refer to the loadlin docu-
 	mentation for further information.
 
-3.4) Using a boot ROM
+3.5) Using a boot ROM
 	This is probably the most elegant way of booting a diskless
 	client. With a boot ROM the kernel gets loaded using the TFTP
 	protocol. As far as I know, no commercial boot ROMs yet
@@ -194,6 +198,13 @@
 	and its mirrors. They are called 'netboot-nfs' and 'etherboot'.
 	Both contain everything you need to boot a diskless Linux client.
 
+3.6) Using pxelinux
+	Using pxelinux you specify the kernel you built with
+	"kernel <relative-path-below /tftpboot>". The nfsroot parameters
+	are passed to the kernel by adding them to the "append" line.
+	You may perhaps also want to fine tune the console output,
+	see Documentation/serial-console.txt for serial console help.
+
 
 
 
diff -urN oldtree/Documentation/powerpc/eeh-pci-error-recovery.txt newtree/Documentation/powerpc/eeh-pci-error-recovery.txt
--- oldtree/Documentation/powerpc/eeh-pci-error-recovery.txt	2006-02-19 11:40:58.217614064 +0000
+++ newtree/Documentation/powerpc/eeh-pci-error-recovery.txt	2006-02-21 15:58:17.483488664 +0000
@@ -121,7 +121,7 @@
 
 EEH must be enabled in the PHB's very early during the boot process,
 and if a PCI slot is hot-plugged. The former is performed by
-eeh_init() in arch/ppc64/kernel/eeh.c, and the later by
+eeh_init() in arch/powerpc/platforms/pseries/eeh.c, and the later by
 drivers/pci/hotplug/pSeries_pci.c calling in to the eeh.c code.
 EEH must be enabled before a PCI scan of the device can proceed.
 Current Power5 hardware will not work unless EEH is enabled;
@@ -133,7 +133,7 @@
 pci_get_device_by_addr() will find the pci device associated
 with that address (if any).
 
-The default include/asm-ppc64/io.h macros readb(), inb(), insb(),
+The default include/asm-powerpc/io.h macros readb(), inb(), insb(),
 etc. include a check to see if the i/o read returned all-0xff's.
 If so, these make a call to eeh_dn_check_failure(), which in turn
 asks the firmware if the all-ff's value is the sign of a true EEH
@@ -143,11 +143,12 @@
 all of these occur during boot, when the PCI bus is scanned, where
 a large number of 0xff reads are part of the bus scan procedure.
 
-If a frozen slot is detected, code in arch/ppc64/kernel/eeh.c will
-print a stack trace to syslog (/var/log/messages).  This stack trace
-has proven to be very useful to device-driver authors for finding
-out at what point the EEH error was detected, as the error itself
-usually occurs slightly beforehand.
+If a frozen slot is detected, code in 
+arch/powerpc/platforms/pseries/eeh.c will print a stack trace to 
+syslog (/var/log/messages).  This stack trace has proven to be very 
+useful to device-driver authors for finding out at what point the EEH 
+error was detected, as the error itself usually occurs slightly 
+beforehand.
 
 Next, it uses the Linux kernel notifier chain/work queue mechanism to
 allow any interested parties to find out about the failure.  Device
diff -urN oldtree/Documentation/scsi/ChangeLog.arcmsr newtree/Documentation/scsi/ChangeLog.arcmsr
--- oldtree/Documentation/scsi/ChangeLog.arcmsr	1970-01-01 00:00:00.000000000 +0000
+++ newtree/Documentation/scsi/ChangeLog.arcmsr	2006-02-21 15:58:20.131086168 +0000
@@ -0,0 +1,56 @@
+**************************************************************************
+** History
+**
+**   REV#         DATE             NAME         DESCRIPTION
+** 1.00.00.00    3/31/2004       Erich Chen     First release
+** 1.10.00.04    7/28/2004       Erich Chen     modify for ioctl
+** 1.10.00.06    8/28/2004       Erich Chen     modify for 2.6.x
+** 1.10.00.08    9/28/2004       Erich Chen     modify for x86_64
+** 1.10.00.10   10/10/2004       Erich Chen     bug fix for SMP & ioctl
+** 1.20.00.00   11/29/2004       Erich Chen     bug fix with arcmsr_bus_reset when PHY error
+** 1.20.00.02   12/09/2004       Erich Chen     bug fix with over 2T bytes RAID Volume
+** 1.20.00.04    1/09/2005       Erich Chen     fits for Debian linux kernel version 2.2.xx
+** 1.20.00.05    2/20/2005       Erich Chen     cleanly as look like a Linux driver at 2.6.x
+**                                              thanks for peoples kindness comment
+**						Kornel Wieliczek
+**						Christoph Hellwig
+**						Adrian Bunk
+**						Andrew Morton
+**						Christoph Hellwig
+**						James Bottomley
+**						Arjan van de Ven
+** 1.20.00.06    3/12/2005       Erich Chen     fix with arcmsr_pci_unmap_dma "unsigned long" cast,
+**						modify PCCB POOL allocated by "dma_alloc_coherent"
+**						(Kornel Wieliczek's comment)
+** 1.20.00.07    3/23/2005       Erich Chen     bug fix with arcmsr_scsi_host_template_init
+**						occur segmentation fault,
+**						if RAID adapter does not on PCI slot
+**						and modprobe/rmmod this driver twice.
+**						bug fix enormous stack usage (Adrian Bunk's comment)
+** 1.20.00.08    6/23/2005       Erich Chen     bug fix with abort command,
+**						in case of heavy loading when sata cable
+**						working on low quality connection
+** 1.20.00.09    9/12/2005       Erich Chen     bug fix with abort command handling, firmware version check
+**						and firmware update notify for hardware bug fix
+** 1.20.00.10    9/23/2005       Erich Chen     enhance sysfs function for change driver's max tag Q number.
+**						add DMA_64BIT_MASK for backward compatible with all 2.6.x
+**						add some useful message for abort command
+**						add ioctl code 'ARCMSR_IOCTL_FLUSH_ADAPTER_CACHE'
+**						customer can send this command for sync raid volume data
+** 1.20.00.11    9/29/2005       Erich Chen     by comment of Arjan van de Ven fix incorrect msleep redefine
+**						cast off sizeof(dma_addr_t) condition for 64bit pci_set_dma_mask
+** 1.20.00.12    9/30/2005       Erich Chen     bug fix with 64bit platform's ccbs using if over 4G system memory
+**						change 64bit pci_set_consistent_dma_mask into 32bit
+**						increcct adapter count if adapter initialize fail.
+**						miss edit at arcmsr_build_ccb....
+**						psge += sizeof(struct _SG64ENTRY *) =>
+**						psge += sizeof(struct _SG64ENTRY)
+**						64 bits sg entry would be incorrectly calculated
+**						thanks Kornel Wieliczek give me kindly notify
+**						and detail description
+** 1.20.00.13   11/15/2005       Erich Chen     scheduling pending ccb with FIFO
+**						change the architecture of arcmsr command queue list
+**						for linux standard list
+**						enable usage of pci message signal interrupt
+**						follow Randy.Danlup kindness suggestion cleanup this code
+**************************************************************************
\ No newline at end of file
diff -urN oldtree/Documentation/sound/alsa/ALSA-Configuration.txt newtree/Documentation/sound/alsa/ALSA-Configuration.txt
--- oldtree/Documentation/sound/alsa/ALSA-Configuration.txt	2006-02-19 11:40:58.222613304 +0000
+++ newtree/Documentation/sound/alsa/ALSA-Configuration.txt	2006-02-21 15:58:11.125455232 +0000
@@ -513,6 +513,8 @@
 
     This module supports multiple cards and autoprobe.
     
+    The power-management is supported.
+
   Module snd-ens1371
   ------------------
 
@@ -526,6 +528,8 @@
 
     This module supports multiple cards and autoprobe.
     
+    The power-management is supported.
+
   Module snd-es968
   ----------------
 
@@ -671,6 +675,8 @@
 
     model	- force the model name
     position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)
+    single_cmd  - Use single immediate commands to communicate with
+		codecs (for debugging only)
 
     This module supports one card and autoprobe.
 
@@ -723,6 +729,17 @@
 	    (Usually SD_LPLIB register is more accurate than the
 	    position buffer.)
 
+    NB: If you get many "azx_get_response timeout" messages at
+    loading, it's likely a problem of interrupts (e.g. ACPI irq
+    routing).  Try to boot with options like "pci=noacpi".  Also, you
+    can try "single_cmd=1" module option.  This will switch the
+    communication method between HDA controller and codecs to the
+    single immediate commands instead of CORB/RIRB.  Basically, the
+    single command mode is provided only for BIOS, and you won't get
+    unsolicited events, too.  But, at least, this works independently
+    from the irq.  Remember this is a last resort, and should be
+    avoided as much as possible...
+    
     The power-management is supported.
 
   Module snd-hdsp
@@ -802,6 +819,7 @@
   ------------------
 
     Module for Envy24HT (VT/ICE1724), Envy24PT (VT1720) based PCI sound cards.
+			* MidiMan M Audio Revolution 5.1
 			* MidiMan M Audio Revolution 7.1
 			* AMP Ltd AUDIO2000
 			* TerraTec Aureon 5.1 Sky
@@ -810,6 +828,7 @@
 			* TerraTec Phase 22
 			* TerraTec Phase 28
 			* AudioTrak Prodigy 7.1
+			* AudioTrak Prodigy 7.1LT
 			* AudioTrak Prodigy 192
 			* Pontis MS300
 			* Albatron K8X800 Pro II 
@@ -820,9 +839,9 @@
 			* Shuttle SN25P
 
     model       - Use the given board model, one of the following:
-		  revo71, amp2000, prodigy71, prodigy192, aureon51,
-		  aureon71, universe, k8x800, phase22, phase28, ms300,
-		  av710
+		  revo51, revo71, amp2000, prodigy71, prodigy71lt,
+		  prodigy192, aureon51, aureon71, universe,
+		  k8x800, phase22, phase28, ms300, av710
 
     This module supports multiple cards and autoprobe.
 
diff -urN oldtree/Documentation/synchro-test.txt newtree/Documentation/synchro-test.txt
--- oldtree/Documentation/synchro-test.txt	1970-01-01 00:00:00.000000000 +0000
+++ newtree/Documentation/synchro-test.txt	2006-02-21 15:58:31.991283144 +0000
@@ -0,0 +1,59 @@
+The synchro-test.ko module can be used for testing and benchmarking mutexes,
+semaphores and R/W semaphores.
+
+The module is compiled by setting CONFIG_DEBUG_SYNCHRO_TEST to "m" when
+configuring the kernel.
+
+Using it is simple:
+
+	insmod synchro-test.ko <args>
+
+It will exit with error ENOANO after running the tests and printing the
+results to the kernel console log.
+
+The available arguments are:
+
+ (*) mx=N
+
+	Start up to N mutex thrashing threads, where N is at most 20. All will
+	try and thrash the same mutex.
+
+ (*) sm=N
+
+	Start up to N counting semaphore thrashing threads, where N is at most
+	20. All will try and thrash the same semaphore.
+
+ (*) ism=M
+
+	Initialise the counting semaphore with M, where M is any positive
+	integer greater than zero. The default is 4.
+
+ (*) rd=N
+ (*) wr=O
+ (*) dg=P
+
+	Start up to N reader thrashing threads, O writer thrashing threads and
+	P downgrader thrashing threads, where N, O and P are at most 20
+	apiece. All will try and thrash the same read/write semaphore.
+
+ (*) elapse=N
+
+	Run the tests for N seconds. The default is 5.
+
+ (*) load=N
+
+	Each thread delays for N uS whilst holding the lock. The default is 0.
+
+ (*) interval=N
+
+	Each thread delays for N uS whilst not holding the lock. The default
+	is 0.
+
+ (*) do_sched=1
+
+	Each thread will call schedule if required after each iteration.
+
+ (*) v=1
+
+	Print more verbose information, including a thread iteration
+	distribution list.
diff -urN oldtree/Documentation/sysctl/kernel.txt newtree/Documentation/sysctl/kernel.txt
--- oldtree/Documentation/sysctl/kernel.txt	2006-01-03 03:21:10.000000000 +0000
+++ newtree/Documentation/sysctl/kernel.txt	2006-02-21 15:58:08.801808480 +0000
@@ -16,6 +16,7 @@
 
 Currently, these files might (depending on your configuration)
 show up in /proc/sys/kernel:
+- acpi_video_flags
 - acct
 - core_pattern
 - core_uses_pid
@@ -57,6 +58,15 @@
 
 ==============================================================
 
+acpi_video_flags:
+
+flags
+
+See Doc*/kernel/power/video.txt, it allows mode of video boot to be
+set during run time.
+
+==============================================================
+
 acct:
 
 highwater lowwater frequency
diff -urN oldtree/Documentation/w1/masters/ds2482 newtree/Documentation/w1/masters/ds2482
--- oldtree/Documentation/w1/masters/ds2482	1970-01-01 00:00:00.000000000 +0000
+++ newtree/Documentation/w1/masters/ds2482	2006-02-21 15:58:14.599927032 +0000
@@ -0,0 +1,31 @@
+Kernel driver ds2482
+====================
+
+Supported chips:
+  * Maxim DS2482-100, Maxim DS2482-800
+    Prefix: 'ds2482'
+    Addresses scanned: None
+    Datasheets:
+        http://pdfserv.maxim-ic.com/en/ds/DS2482-100-DS2482S-100.pdf
+        http://pdfserv.maxim-ic.com/en/ds/DS2482-800-DS2482S-800.pdf
+
+Author: Ben Gardner <bgardner@wabtec.com>
+
+
+Description
+-----------
+
+The Maixm/Dallas Semiconductor DS2482 is a I2C device that provides
+one (DS2482-100) or eight (DS2482-800) 1-wire busses.
+
+
+General Remarks
+---------------
+
+Valid addresses are 0x18, 0x19, 0x1a, and 0x1b.
+However, the device cannot be detected without writing to the i2c bus, so no
+detection is done.
+You should force the device address.
+
+$ modprobe ds2482 force=0,0x18
+
diff -urN oldtree/MAINTAINERS newtree/MAINTAINERS
--- oldtree/MAINTAINERS	2006-02-19 11:40:58.239610720 +0000
+++ newtree/MAINTAINERS	2006-02-21 15:58:32.800160176 +0000
@@ -798,6 +798,13 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+DLM, DISTRIBUTED LOCK MANAGER
+P:	David Teigland
+M:	teigland@redhat.com
+L:	linux-cluster@redhat.com
+W:	http://sources.redhat.com/cluster
+S:	Maintained
+
 DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
 P:	Tobias Ringstrom
 M:	tori@unhappy.mine.nu
@@ -1028,6 +1035,15 @@
 W:	http://www.kernel.org/pub/linux/utils/net/hdlc/
 S:	Maintained
 
+GIGASET ISDN DRIVERS
+P:	Hansjoerg Lipp
+M:	hjlipp@web.de
+P:	Tilman Schmidt
+M:	tilman@imap.cc
+L:	gigaset307x-common@lists.sourceforge.net
+W:	http://gigaset307x.sourceforge.net/
+S:	Maintained
+
 HARDWARE MONITORING
 P:	Jean Delvare
 M:	khali@linux-fr.org
@@ -2490,6 +2506,13 @@
 L:	pcihpd-discuss@lists.sourceforge.net
 S:	Maintained
 
+SECURE DIGITAL HOST CONTROLLER INTERFACE DRIVER
+P:	Pierre Ossman
+M:	drzeus-sdhci@drzeus.cx
+L:	sdhci-devel@list.drzeus.cx
+W:	http://mmc.drzeus.cx/wiki/Linux/Drivers/sdhci
+S:	Maintained
+
 SKGE, SKY2 10/100/1000 GIGABIT ETHERNET DRIVERS
 P:	Stephen Hemminger
 M:	shemminger@osdl.org
diff -urN oldtree/Makefile newtree/Makefile
--- oldtree/Makefile	2006-02-19 11:40:58.240610568 +0000
+++ newtree/Makefile	2006-02-21 15:58:36.954528616 +0000
@@ -306,7 +306,7 @@
 
 AS		= $(CROSS_COMPILE)as
 LD		= $(CROSS_COMPILE)ld
-CC		= $(CROSS_COMPILE)gcc
+CC		= ccache $(CROSS_COMPILE)gcc
 CPP		= $(CC) -E
 AR		= $(CROSS_COMPILE)ar
 NM		= $(CROSS_COMPILE)nm
@@ -517,6 +517,10 @@
 CFLAGS		+= -fomit-frame-pointer
 endif
 
+ifdef CONFIG_UNWIND_INFO
+CFLAGS		+= -fasynchronous-unwind-tables
+endif
+
 ifdef CONFIG_DEBUG_INFO
 CFLAGS		+= -g
 endif
diff -urN oldtree/arch/arm/Kconfig newtree/arch/arm/Kconfig
--- oldtree/arch/arm/Kconfig	2006-02-19 11:40:58.247609504 +0000
+++ newtree/arch/arm/Kconfig	2006-02-21 15:58:31.147411432 +0000
@@ -807,6 +807,8 @@
 
 source "drivers/mfd/Kconfig"
 
+source "drivers/leds/Kconfig"
+
 source "drivers/media/Kconfig"
 
 source "drivers/video/Kconfig"
diff -urN oldtree/arch/arm/common/locomo.c newtree/arch/arm/common/locomo.c
--- oldtree/arch/arm/common/locomo.c	2006-02-19 11:40:58.255608288 +0000
+++ newtree/arch/arm/common/locomo.c	2006-02-21 15:58:12.421258240 +0000
@@ -767,6 +767,8 @@
 	if (!mem)
 		return -EINVAL;
 	irq = platform_get_irq(dev, 0);
+	if (irq < 0)
+		return -ENXIO;
 
 	return __locomo_probe(&dev->dev, mem, irq);
 }
diff -urN oldtree/arch/arm/common/sa1111.c newtree/arch/arm/common/sa1111.c
--- oldtree/arch/arm/common/sa1111.c	2006-02-19 11:40:58.256608136 +0000
+++ newtree/arch/arm/common/sa1111.c	2006-02-21 15:58:12.422258088 +0000
@@ -943,6 +943,8 @@
 	if (!mem)
 		return -EINVAL;
 	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return -ENXIO;
 
 	return __sa1111_probe(&pdev->dev, mem, irq);
 }
diff -urN oldtree/arch/arm/common/sharpsl_pm.c newtree/arch/arm/common/sharpsl_pm.c
--- oldtree/arch/arm/common/sharpsl_pm.c	2006-02-19 11:40:58.258607832 +0000
+++ newtree/arch/arm/common/sharpsl_pm.c	2006-02-21 15:58:31.200403376 +0000
@@ -22,6 +22,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/leds.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
@@ -75,6 +76,7 @@
 struct sharpsl_pm_status sharpsl_pm;
 DECLARE_WORK(toggle_charger, sharpsl_charge_toggle, NULL);
 DECLARE_WORK(sharpsl_bat, sharpsl_battery_thread, NULL);
+DEFINE_LED_TRIGGER(sharpsl_charge_led_trigger);
 
 
 static int get_percentage(int voltage)
@@ -190,10 +192,10 @@
 		dev_err(sharpsl_pm.dev, "Charging Error!\n");
 	} else if (val == SHARPSL_LED_ON) {
 		dev_dbg(sharpsl_pm.dev, "Charge LED On\n");
-
+		led_trigger_event(sharpsl_charge_led_trigger, LED_FULL);
 	} else {
 		dev_dbg(sharpsl_pm.dev, "Charge LED Off\n");
-
+		led_trigger_event(sharpsl_charge_led_trigger, LED_OFF);
 	}
 }
 
@@ -786,6 +788,8 @@
 	init_timer(&sharpsl_pm.chrg_full_timer);
 	sharpsl_pm.chrg_full_timer.function = sharpsl_chrg_full_timer;
 
+	led_trigger_register_simple("sharpsl-charge", &sharpsl_charge_led_trigger);
+
 	sharpsl_pm.machinfo->init();
 
 	device_create_file(&pdev->dev, &dev_attr_battery_percentage);
@@ -807,6 +811,8 @@
 	device_remove_file(&pdev->dev, &dev_attr_battery_percentage);
 	device_remove_file(&pdev->dev, &dev_attr_battery_voltage);
 
+	led_trigger_unregister_simple(sharpsl_charge_led_trigger);
+
 	sharpsl_pm.machinfo->exit();
 
 	del_timer_sync(&sharpsl_pm.chrg_full_timer);
diff -urN oldtree/arch/arm/mach-pxa/corgi.c newtree/arch/arm/mach-pxa/corgi.c
--- oldtree/arch/arm/mach-pxa/corgi.c	2006-02-19 11:40:58.501570896 +0000
+++ newtree/arch/arm/mach-pxa/corgi.c	2006-02-21 15:58:31.219400488 +0000
@@ -165,6 +165,14 @@
 
 
 /*
+ * Corgi LEDs
+ */
+static struct platform_device corgiled_device = {
+	.name		= "corgi-led",
+	.id		= -1,
+};
+
+/*
  * Corgi Touch Screen Device
  */
 static struct resource corgits_resources[] = {
@@ -298,6 +306,7 @@
 	&corgikbd_device,
 	&corgibl_device,
 	&corgits_device,
+	&corgiled_device,
 };
 
 static void __init corgi_init(void)
diff -urN oldtree/arch/arm/mach-pxa/mainstone.c newtree/arch/arm/mach-pxa/mainstone.c
--- oldtree/arch/arm/mach-pxa/mainstone.c	2006-02-19 11:40:58.503570592 +0000
+++ newtree/arch/arm/mach-pxa/mainstone.c	2006-02-21 15:58:11.148451736 +0000
@@ -157,14 +157,14 @@
 	.resource	= smc91x_resources,
 };
 
-static int mst_audio_startup(snd_pcm_substream_t *substream, void *priv)
+static int mst_audio_startup(struct snd_pcm_substream *substream, void *priv)
 {
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		MST_MSCWR2 &= ~MST_MSCWR2_AC97_SPKROFF;
 	return 0;
 }
 
-static void mst_audio_shutdown(snd_pcm_substream_t *substream, void *priv)
+static void mst_audio_shutdown(struct snd_pcm_substream *substream, void *priv)
 {
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF;
diff -urN oldtree/arch/arm/mach-pxa/spitz.c newtree/arch/arm/mach-pxa/spitz.c
--- oldtree/arch/arm/mach-pxa/spitz.c	2006-02-19 11:40:58.507569984 +0000
+++ newtree/arch/arm/mach-pxa/spitz.c	2006-02-21 15:58:31.222400032 +0000
@@ -243,6 +243,14 @@
 
 
 /*
+ * Spitz LEDs
+ */
+static struct platform_device spitzled_device = {
+	.name		= "spitz-led",
+	.id		= -1,
+};
+
+/*
  * Spitz Touch Screen Device
  */
 static struct resource spitzts_resources[] = {
@@ -419,6 +427,7 @@
 	&spitzkbd_device,
 	&spitzts_device,
 	&spitzbl_device,
+	&spitzled_device,
 };
 
 static void __init common_init(void)
diff -urN oldtree/arch/arm/mach-pxa/tosa.c newtree/arch/arm/mach-pxa/tosa.c
--- oldtree/arch/arm/mach-pxa/tosa.c	2006-02-19 11:40:58.508569832 +0000
+++ newtree/arch/arm/mach-pxa/tosa.c	2006-02-21 15:58:31.319385288 +0000
@@ -252,10 +252,19 @@
 	.id		= -1,
 };
 
+/*
+ * Tosa LEDs
+ */
+static struct platform_device tosaled_device = {
+    .name   = "tosa-led",
+    .id     = -1,
+};
+
 static struct platform_device *devices[] __initdata = {
 	&tosascoop_device,
 	&tosascoop_jc_device,
 	&tosakbd_device,
+	&tosaled_device,
 };
 
 static void __init tosa_init(void)
diff -urN oldtree/arch/arm26/kernel/traps.c newtree/arch/arm26/kernel/traps.c
--- oldtree/arch/arm26/kernel/traps.c	2006-02-19 11:40:58.570560408 +0000
+++ newtree/arch/arm26/kernel/traps.c	2006-02-21 15:58:24.112480904 +0000
@@ -34,7 +34,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include "ptrace.h"
 
@@ -207,19 +207,19 @@
     	die(str, regs, err);
 }
 
-static DECLARE_MUTEX(undef_sem);
+static DEFINE_MUTEX(undef_mutex);
 static int (*undef_hook)(struct pt_regs *);
 
 int request_undef_hook(int (*fn)(struct pt_regs *))
 {
 	int ret = -EBUSY;
 
-	down(&undef_sem);
+	mutex_lock(&undef_mutex);
 	if (undef_hook == NULL) {
 		undef_hook = fn;
 		ret = 0;
 	}
-	up(&undef_sem);
+	mutex_unlock(&undef_mutex);
 
 	return ret;
 }
@@ -228,12 +228,12 @@
 {
 	int ret = -EINVAL;
 
-	down(&undef_sem);
+	mutex_lock(&undef_mutex);
 	if (undef_hook == fn) {
 		undef_hook = NULL;
 		ret = 0;
 	}
-	up(&undef_sem);
+	mutex_unlock(&undef_mutex);
 
 	return ret;
 }
diff -urN oldtree/arch/cris/arch-v32/drivers/cryptocop.c newtree/arch/cris/arch-v32/drivers/cryptocop.c
--- oldtree/arch/cris/arch-v32/drivers/cryptocop.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/cris/arch-v32/drivers/cryptocop.c	2006-02-21 15:58:29.905600216 +0000
@@ -2944,7 +2944,7 @@
 		int spdl_err;
 		/* Mark output pages dirty. */
 		spdl_err = set_page_dirty_lock(outpages[i]);
-		DEBUG(if (spdl_err)printk("cryptocop_ioctl_process: set_page_dirty_lock returned %d\n", spdl_err));
+		DEBUG(if (spdl_err < 0)printk("cryptocop_ioctl_process: set_page_dirty_lock returned %d\n", spdl_err));
 	}
 	for (i = 0; i < nooutpages; i++){
 		put_page(outpages[i]);
diff -urN oldtree/arch/frv/kernel/entry.S newtree/arch/frv/kernel/entry.S
--- oldtree/arch/frv/kernel/entry.S	2006-02-19 11:40:58.581558736 +0000
+++ newtree/arch/frv/kernel/entry.S	2006-02-21 15:58:36.114656296 +0000
@@ -1480,7 +1480,7 @@
 	.long sys_mknodat
 	.long sys_fchownat
 	.long sys_futimesat
-	.long sys_newfstatat		/* 300 */
+	.long sys_fstatat64		/* 300 */
 	.long sys_unlinkat
 	.long sys_renameat
 	.long sys_linkat
diff -urN oldtree/arch/frv/kernel/irq-routing.c newtree/arch/frv/kernel/irq-routing.c
--- oldtree/arch/frv/kernel/irq-routing.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/frv/kernel/irq-routing.c	2006-02-21 15:58:36.118655688 +0000
@@ -112,7 +112,7 @@
 #define __CPUUART(X, A)						\
 	[X] = {							\
 		.muxname	= "uart",			\
-		.muxdata	= (volatile void __iomem *) A,	\
+		.muxdata	= (volatile void __iomem *)(unsigned long)A,\
 		.irqmask	= 1 << IRQ_CPU_UART##X,		\
 		.doirq		= frv_cpuuart_doirq,		\
 	}
@@ -136,7 +136,7 @@
 #define __CPUDMA(X, A)						\
 	[X] = {							\
 		.muxname	= "dma",			\
-		.muxdata	= (volatile void __iomem *) A,	\
+		.muxdata	= (volatile void __iomem *)(unsigned long)A,\
 		.irqmask	= 1 << IRQ_CPU_DMA##X,		\
 		.doirq		= frv_cpudma_doirq,		\
 	}
@@ -164,7 +164,7 @@
 #define __CPUTIMER(X)						\
 	[X] = {							\
 		.muxname	= "timer",			\
-		.muxdata	= 0,				\
+		.muxdata	= NULL,				\
 		.irqmask	= 1 << IRQ_CPU_TIMER##X,	\
 		.doirq		= frv_cputimer_doirq,		\
 	}
@@ -187,7 +187,7 @@
 #define __CPUEXTERNAL(X)					\
 	[X] = {							\
 		.muxname	= "ext",			\
-		.muxdata	= 0,				\
+		.muxdata	= NULL,				\
 		.irqmask	= 1 << IRQ_CPU_EXTERNAL##X,	\
 		.doirq		= frv_cpuexternal_doirq,	\
 	}
diff -urN oldtree/arch/frv/kernel/irq.c newtree/arch/frv/kernel/irq.c
--- oldtree/arch/frv/kernel/irq.c	2006-02-19 11:40:58.614553720 +0000
+++ newtree/arch/frv/kernel/irq.c	2006-02-21 15:58:36.118655688 +0000
@@ -627,7 +627,7 @@
 
 #define HEX_DIGITS 8
 
-static unsigned int parse_hex_value (const char *buffer,
+static unsigned int parse_hex_value (const char __user *buffer,
 				     unsigned long count, unsigned long *ret)
 {
 	unsigned char hexnum [HEX_DIGITS];
@@ -674,7 +674,7 @@
 	return sprintf (page, "%08lx\n", *mask);
 }
 
-static int prof_cpu_mask_write_proc (struct file *file, const char *buffer,
+static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer,
 					unsigned long count, void *data)
 {
 	unsigned long *mask = (unsigned long *) data, full_count = count, err;
@@ -713,7 +713,7 @@
 	int i;
 
 	/* create /proc/irq */
-	root_irq_dir = proc_mkdir("irq", 0);
+	root_irq_dir = proc_mkdir("irq", NULL);
 
 	/* create /proc/irq/prof_cpu_mask */
 	entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
diff -urN oldtree/arch/frv/kernel/pm.c newtree/arch/frv/kernel/pm.c
--- oldtree/arch/frv/kernel/pm.c	2006-02-19 11:40:58.615553568 +0000
+++ newtree/arch/frv/kernel/pm.c	2006-02-21 15:58:36.119655536 +0000
@@ -137,7 +137,7 @@
 #define CTL_PM_P0 4
 #define CTL_PM_CM 5
 
-static int user_atoi(char *ubuf, size_t len)
+static int user_atoi(char __user *ubuf, size_t len)
 {
 	char buf[16];
 	unsigned long ret;
@@ -159,7 +159,7 @@
  * Send us to sleep.
  */
 static int sysctl_pm_do_suspend(ctl_table *ctl, int write, struct file *filp,
-				void *buffer, size_t *lenp, loff_t *fpos)
+				void __user *buffer, size_t *lenp, loff_t *fpos)
 {
 	int retval, mode;
 
@@ -215,7 +215,7 @@
 
 
 static int cmode_procctl(ctl_table *ctl, int write, struct file *filp,
-			 void *buffer, size_t *lenp, loff_t *fpos)
+			 void __user *buffer, size_t *lenp, loff_t *fpos)
 {
 	int new_cmode;
 
@@ -227,9 +227,9 @@
 	return try_set_cmode(new_cmode)?:*lenp;
 }
 
-static int cmode_sysctl(ctl_table *table, int *name, int nlen,
-			void *oldval, size_t *oldlenp,
-			void *newval, size_t newlen, void **context)
+static int cmode_sysctl(ctl_table *table, int __user *name, int nlen,
+			void __user *oldval, size_t __user *oldlenp,
+			void __user *newval, size_t newlen, void **context)
 {
 	if (oldval && oldlenp) {
 		size_t oldlen;
@@ -240,7 +240,7 @@
 		if (oldlen != sizeof(int))
 			return -EINVAL;
 
-		if (put_user(clock_cmode_current, (unsigned int *)oldval) ||
+		if (put_user(clock_cmode_current, (unsigned __user *)oldval) ||
 		    put_user(sizeof(int), oldlenp))
 			return -EFAULT;
 	}
@@ -250,7 +250,7 @@
 		if (newlen != sizeof(int))
 			return -EINVAL;
 
-		if (get_user(new_cmode, (int *)newval))
+		if (get_user(new_cmode, (int __user *)newval))
 			return -EFAULT;
 
 		return try_set_cmode(new_cmode)?:1;
@@ -318,7 +318,7 @@
 }
 
 static int p0_procctl(ctl_table *ctl, int write, struct file *filp,
-		      void *buffer, size_t *lenp, loff_t *fpos)
+		      void __user *buffer, size_t *lenp, loff_t *fpos)
 {
 	int new_p0;
 
@@ -330,9 +330,9 @@
 	return try_set_p0(new_p0)?:*lenp;
 }
 
-static int p0_sysctl(ctl_table *table, int *name, int nlen,
-		     void *oldval, size_t *oldlenp,
-		     void *newval, size_t newlen, void **context)
+static int p0_sysctl(ctl_table *table, int __user *name, int nlen,
+		     void __user *oldval, size_t __user *oldlenp,
+		     void __user *newval, size_t newlen, void **context)
 {
 	if (oldval && oldlenp) {
 		size_t oldlen;
@@ -343,7 +343,7 @@
 		if (oldlen != sizeof(int))
 			return -EINVAL;
 
-		if (put_user(clock_p0_current, (unsigned int *)oldval) ||
+		if (put_user(clock_p0_current, (unsigned __user *)oldval) ||
 		    put_user(sizeof(int), oldlenp))
 			return -EFAULT;
 	}
@@ -353,7 +353,7 @@
 		if (newlen != sizeof(int))
 			return -EINVAL;
 
-		if (get_user(new_p0, (int *)newval))
+		if (get_user(new_p0, (int __user *)newval))
 			return -EFAULT;
 
 		return try_set_p0(new_p0)?:1;
@@ -362,7 +362,7 @@
 }
 
 static int cm_procctl(ctl_table *ctl, int write, struct file *filp,
-		      void *buffer, size_t *lenp, loff_t *fpos)
+		      void __user *buffer, size_t *lenp, loff_t *fpos)
 {
 	int new_cm;
 
@@ -374,9 +374,9 @@
 	return try_set_cm(new_cm)?:*lenp;
 }
 
-static int cm_sysctl(ctl_table *table, int *name, int nlen,
-		     void *oldval, size_t *oldlenp,
-		     void *newval, size_t newlen, void **context)
+static int cm_sysctl(ctl_table *table, int __user *name, int nlen,
+		     void __user *oldval, size_t __user *oldlenp,
+		     void __user *newval, size_t newlen, void **context)
 {
 	if (oldval && oldlenp) {
 		size_t oldlen;
@@ -387,7 +387,7 @@
 		if (oldlen != sizeof(int))
 			return -EINVAL;
 
-		if (put_user(clock_cm_current, (unsigned int *)oldval) ||
+		if (put_user(clock_cm_current, (unsigned __user *)oldval) ||
 		    put_user(sizeof(int), oldlenp))
 			return -EFAULT;
 	}
@@ -397,7 +397,7 @@
 		if (newlen != sizeof(int))
 			return -EINVAL;
 
-		if (get_user(new_cm, (int *)newval))
+		if (get_user(new_cm, (int __user *)newval))
 			return -EFAULT;
 
 		return try_set_cm(new_cm)?:1;
diff -urN oldtree/arch/frv/kernel/process.c newtree/arch/frv/kernel/process.c
--- oldtree/arch/frv/kernel/process.c	2006-02-19 11:40:58.615553568 +0000
+++ newtree/arch/frv/kernel/process.c	2006-02-21 15:58:36.120655384 +0000
@@ -246,7 +246,7 @@
 /*
  * sys_execve() executes a new program.
  */
-asmlinkage int sys_execve(char *name, char **argv, char **envp)
+asmlinkage int sys_execve(char __user *name, char __user * __user *argv, char __user * __user *envp)
 {
 	int error;
 	char * filename;
diff -urN oldtree/arch/frv/kernel/signal.c newtree/arch/frv/kernel/signal.c
--- oldtree/arch/frv/kernel/signal.c	2006-02-19 11:40:58.617553264 +0000
+++ newtree/arch/frv/kernel/signal.c	2006-02-21 15:58:36.121655232 +0000
@@ -98,7 +98,7 @@
 
 struct sigframe
 {
-	void (*pretcode)(void);
+	__sigrestore_t pretcode;
 	int sig;
 	struct sigcontext sc;
 	unsigned long extramask[_NSIG_WORDS-1];
@@ -107,10 +107,10 @@
 
 struct rt_sigframe
 {
-	void (*pretcode)(void);
+	__sigrestore_t pretcode;
 	int sig;
-	struct siginfo *pinfo;
-	void *puc;
+	struct siginfo __user *pinfo;
+	void __user *puc;
 	struct siginfo info;
 	struct ucontext uc;
 	uint32_t retcode[2];
@@ -284,7 +284,7 @@
 		 *	setlos	#__NR_sigreturn,gr7
 		 *	tira	gr0,0
 		 */
-		if (__put_user((void (*)(void))frame->retcode, &frame->pretcode) ||
+		if (__put_user((__sigrestore_t)frame->retcode, &frame->pretcode) ||
 		    __put_user(0x8efc0000|__NR_sigreturn, &frame->retcode[0]) ||
 		    __put_user(0xc0700000, &frame->retcode[1]))
 			goto give_sigsegv;
@@ -300,7 +300,7 @@
 
 	if (get_personality & FDPIC_FUNCPTRS) {
 		struct fdpic_func_descriptor __user *funcptr =
-			(struct fdpic_func_descriptor *) ka->sa.sa_handler;
+			(struct fdpic_func_descriptor __user *) ka->sa.sa_handler;
 		__get_user(__frame->pc, &funcptr->text);
 		__get_user(__frame->gr15, &funcptr->GOT);
 	} else {
@@ -359,8 +359,8 @@
 
 	/* Create the ucontext.  */
 	if (__put_user(0, &frame->uc.uc_flags) ||
-	    __put_user(0, &frame->uc.uc_link) ||
-	    __put_user((void*)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp) ||
+	    __put_user(NULL, &frame->uc.uc_link) ||
+	    __put_user((void __user *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp) ||
 	    __put_user(sas_ss_flags(__frame->sp), &frame->uc.uc_stack.ss_flags) ||
 	    __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size))
 		goto give_sigsegv;
@@ -382,7 +382,7 @@
 		 *	setlos	#__NR_sigreturn,gr7
 		 *	tira	gr0,0
 		 */
-		if (__put_user((void (*)(void))frame->retcode, &frame->pretcode) ||
+		if (__put_user((__sigrestore_t)frame->retcode, &frame->pretcode) ||
 		    __put_user(0x8efc0000|__NR_rt_sigreturn, &frame->retcode[0]) ||
 		    __put_user(0xc0700000, &frame->retcode[1]))
 			goto give_sigsegv;
@@ -398,7 +398,7 @@
 	__frame->gr9 = (unsigned long) &frame->info;
 
 	if (get_personality & FDPIC_FUNCPTRS) {
-		struct fdpic_func_descriptor *funcptr =
+		struct fdpic_func_descriptor __user *funcptr =
 			(struct fdpic_func_descriptor __user *) ka->sa.sa_handler;
 		__get_user(__frame->pc, &funcptr->text);
 		__get_user(__frame->gr15, &funcptr->GOT);
diff -urN oldtree/arch/frv/kernel/sys_frv.c newtree/arch/frv/kernel/sys_frv.c
--- oldtree/arch/frv/kernel/sys_frv.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/frv/kernel/sys_frv.c	2006-02-21 15:58:36.121655232 +0000
@@ -32,7 +32,7 @@
  * sys_pipe() is the normal C calling standard for creating
  * a pipe. It's not the way unix traditionally does this, though.
  */
-asmlinkage long sys_pipe(unsigned long * fildes)
+asmlinkage long sys_pipe(unsigned long __user * fildes)
 {
 	int fd[2];
 	int error;
diff -urN oldtree/arch/frv/kernel/sysctl.c newtree/arch/frv/kernel/sysctl.c
--- oldtree/arch/frv/kernel/sysctl.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/frv/kernel/sysctl.c	2006-02-21 15:58:36.121655232 +0000
@@ -49,7 +49,7 @@
  * handle requests to dynamically switch the write caching mode delivered by /proc
  */
 static int procctl_frv_cachemode(ctl_table *table, int write, struct file *filp,
-				 void *buffer, size_t *lenp, loff_t *ppos)
+				 void __user *buffer, size_t *lenp, loff_t *ppos)
 {
 	unsigned long hsr0;
 	char buff[8];
@@ -123,7 +123,7 @@
  */
 #ifdef CONFIG_MMU
 static int procctl_frv_pin_cxnr(ctl_table *table, int write, struct file *filp,
-				void *buffer, size_t *lenp, loff_t *ppos)
+				void __user *buffer, size_t *lenp, loff_t *ppos)
 {
 	pid_t pid;
 	char buff[16], *p;
diff -urN oldtree/arch/frv/kernel/uaccess.c newtree/arch/frv/kernel/uaccess.c
--- oldtree/arch/frv/kernel/uaccess.c	2006-02-19 11:40:58.618553112 +0000
+++ newtree/arch/frv/kernel/uaccess.c	2006-02-21 15:58:36.122655080 +0000
@@ -17,7 +17,7 @@
 /*
  * copy a null terminated string from userspace
  */
-long strncpy_from_user(char *dst, const char *src, long count)
+long strncpy_from_user(char *dst, const char __user *src, long count)
 {
 	unsigned long max;
 	char *p, ch;
@@ -70,9 +70,9 @@
  *
  * Return 0 on exception, a value greater than N if too long
  */
-long strnlen_user(const char *src, long count)
+long strnlen_user(const char __user *src, long count)
 {
-	const char *p;
+	const char __user *p;
 	long err = 0;
 	char ch;
 
diff -urN oldtree/arch/frv/mb93090-mb00/pci-irq.c newtree/arch/frv/mb93090-mb00/pci-irq.c
--- oldtree/arch/frv/mb93090-mb00/pci-irq.c	2006-02-19 11:40:58.622552504 +0000
+++ newtree/arch/frv/mb93090-mb00/pci-irq.c	2006-02-21 15:58:36.122655080 +0000
@@ -32,11 +32,11 @@
  */
 
 static const uint8_t __initdata pci_bus0_irq_routing[32][4] = {
-	[0 ] {	IRQ_FPGA_MB86943_PCI_INTA },
-	[16] {	IRQ_FPGA_RTL8029_INTA },
-	[17] {	IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD, IRQ_FPGA_PCI_INTA, IRQ_FPGA_PCI_INTB },
-	[18] {	IRQ_FPGA_PCI_INTB, IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD, IRQ_FPGA_PCI_INTA },
-	[19] {	IRQ_FPGA_PCI_INTA, IRQ_FPGA_PCI_INTB, IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD },
+	[0 ] = { IRQ_FPGA_MB86943_PCI_INTA },
+	[16] = { IRQ_FPGA_RTL8029_INTA },
+	[17] = { IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD, IRQ_FPGA_PCI_INTA, IRQ_FPGA_PCI_INTB },
+	[18] = { IRQ_FPGA_PCI_INTB, IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD, IRQ_FPGA_PCI_INTA },
+	[19] = { IRQ_FPGA_PCI_INTA, IRQ_FPGA_PCI_INTB, IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD },
 };
 
 void __init pcibios_irq_init(void)
diff -urN oldtree/arch/frv/mm/kmap.c newtree/arch/frv/mm/kmap.c
--- oldtree/arch/frv/mm/kmap.c	2006-02-19 11:40:58.623552352 +0000
+++ newtree/arch/frv/mm/kmap.c	2006-02-21 15:58:36.132653560 +0000
@@ -31,15 +31,15 @@
  * Map some physical address range into the kernel address space.
  */
 
-void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
+void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
 {
-	return (void *)physaddr;
+	return (void __iomem *)physaddr;
 }
 
 /*
  * Unmap a ioremap()ed region again
  */
-void iounmap(void *addr)
+void iounmap(void volatile __iomem *addr)
 {
 }
 
diff -urN oldtree/arch/i386/Kconfig.debug newtree/arch/i386/Kconfig.debug
--- oldtree/arch/i386/Kconfig.debug	2006-02-19 11:40:58.629551440 +0000
+++ newtree/arch/i386/Kconfig.debug	2006-02-21 15:58:36.001673472 +0000
@@ -53,14 +53,15 @@
 	  If in doubt, say "N".
 
 config 4KSTACKS
-	bool "Use 4Kb for kernel stacks instead of 8Kb"
-	depends on DEBUG_KERNEL
+	bool "Use 4Kb + 4Kb for kernel stacks instead of 8Kb" if DEBUG_KERNEL
+	default y
 	help
 	  If you say Y here the kernel will use a 4Kb stacksize for the
 	  kernel stack attached to each process/thread. This facilitates
 	  running more threads on a system and also reduces the pressure
 	  on the VM subsystem for higher order allocations. This option
-	  will also use IRQ stacks to compensate for the reduced stackspace.
+	  will also use separate 4Kb IRQ stacks to compensate for the
+	  reduced stackspace.
 
 config X86_FIND_SMP_CONFIG
 	bool
diff -urN oldtree/arch/i386/kernel/acpi/processor.c newtree/arch/i386/kernel/acpi/processor.c
--- oldtree/arch/i386/kernel/acpi/processor.c	2006-02-19 11:40:58.638550072 +0000
+++ newtree/arch/i386/kernel/acpi/processor.c	2006-02-21 15:58:09.826652680 +0000
@@ -47,7 +47,7 @@
 	buf[2] = ACPI_PDC_C_CAPABILITY_SMP;
 
 	if (cpu_has(c, X86_FEATURE_EST))
-		buf[2] |= ACPI_PDC_EST_CAPABILITY_SMP;
+		buf[2] |= ACPI_PDC_EST_CAPABILITY_SWSMP;
 
 	obj->type = ACPI_TYPE_BUFFER;
 	obj->buffer.length = 12;
diff -urN oldtree/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c newtree/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
--- oldtree/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c	2006-02-19 11:40:58.643549312 +0000
+++ newtree/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c	2006-02-21 15:58:10.583537616 +0000
@@ -48,12 +48,13 @@
 
 
 struct cpufreq_acpi_io {
-	struct acpi_processor_performance	acpi_data;
+	struct acpi_processor_performance	*acpi_data;
 	struct cpufreq_frequency_table		*freq_table;
 	unsigned int				resume;
 };
 
 static struct cpufreq_acpi_io	*acpi_io_data[NR_CPUS];
+static struct acpi_processor_performance	*acpi_perf_data[NR_CPUS];
 
 static struct cpufreq_driver acpi_cpufreq_driver;
 
@@ -104,64 +105,43 @@
 {
 	u16			port = 0;
 	u8			bit_width = 0;
+	int			i = 0;
 	int			ret = 0;
 	u32			value = 0;
-	int			i = 0;
-	struct cpufreq_freqs    cpufreq_freqs;
-	cpumask_t		saved_mask;
 	int			retval;
+	struct acpi_processor_performance	*perf;
 
 	dprintk("acpi_processor_set_performance\n");
 
-	/*
-	 * TBD: Use something other than set_cpus_allowed.
-	 * As set_cpus_allowed is a bit racy, 
-	 * with any other set_cpus_allowed for this process.
-	 */
-	saved_mask = current->cpus_allowed;
-	set_cpus_allowed(current, cpumask_of_cpu(cpu));
-	if (smp_processor_id() != cpu) {
-		return (-EAGAIN);
-	}
-	
-	if (state == data->acpi_data.state) {
+	retval = 0;
+	perf = data->acpi_data;	
+	if (state == perf->state) {
 		if (unlikely(data->resume)) {
 			dprintk("Called after resume, resetting to P%d\n", state);
 			data->resume = 0;
 		} else {
 			dprintk("Already at target state (P%d)\n", state);
-			retval = 0;
-			goto migrate_end;
+			return (retval);
 		}
 	}
 
-	dprintk("Transitioning from P%d to P%d\n",
-		data->acpi_data.state, state);
-
-	/* cpufreq frequency struct */
-	cpufreq_freqs.cpu = cpu;
-	cpufreq_freqs.old = data->freq_table[data->acpi_data.state].frequency;
-	cpufreq_freqs.new = data->freq_table[state].frequency;
-
-	/* notify cpufreq */
-	cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
+	dprintk("Transitioning from P%d to P%d\n", perf->state, state);
 
 	/*
 	 * First we write the target state's 'control' value to the
 	 * control_register.
 	 */
 
-	port = data->acpi_data.control_register.address;
-	bit_width = data->acpi_data.control_register.bit_width;
-	value = (u32) data->acpi_data.states[state].control;
+	port = perf->control_register.address;
+	bit_width = perf->control_register.bit_width;
+	value = (u32) perf->states[state].control;
 
 	dprintk("Writing 0x%08x to port 0x%04x\n", value, port);
 
 	ret = acpi_processor_write_port(port, bit_width, value);
 	if (ret) {
 		dprintk("Invalid port width 0x%04x\n", bit_width);
-		retval = ret;
-		goto migrate_end;
+		return (ret);
 	}
 
 	/*
@@ -177,49 +157,36 @@
 		 * before giving up.
 		 */
 
-		port = data->acpi_data.status_register.address;
-		bit_width = data->acpi_data.status_register.bit_width;
+		port = perf->status_register.address;
+		bit_width = perf->status_register.bit_width;
 
 		dprintk("Looking for 0x%08x from port 0x%04x\n",
-			(u32) data->acpi_data.states[state].status, port);
+			(u32) perf->states[state].status, port);
 
-		for (i=0; i<100; i++) {
+		for (i = 0; i < 100; i++) {
 			ret = acpi_processor_read_port(port, bit_width, &value);
 			if (ret) {	
 				dprintk("Invalid port width 0x%04x\n", bit_width);
-				retval = ret;
-				goto migrate_end;
+				return (ret);
 			}
-			if (value == (u32) data->acpi_data.states[state].status)
+			if (value == (u32) perf->states[state].status)
 				break;
 			udelay(10);
 		}
 	} else {
 		i = 0;
-		value = (u32) data->acpi_data.states[state].status;
+		value = (u32) perf->states[state].status;
 	}
 
-	/* notify cpufreq */
-	cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
-
-	if (unlikely(value != (u32) data->acpi_data.states[state].status)) {
-		unsigned int tmp = cpufreq_freqs.new;
-		cpufreq_freqs.new = cpufreq_freqs.old;
-		cpufreq_freqs.old = tmp;
-		cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
-		cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
+	if (unlikely(value != (u32) perf->states[state].status)) {
 		printk(KERN_WARNING "acpi-cpufreq: Transition failed\n");
 		retval = -ENODEV;
-		goto migrate_end;
+		return (retval);
 	}
 
 	dprintk("Transition successful after %d microseconds\n", i * 10);
 
-	data->acpi_data.state = state;
-
-	retval = 0;
-migrate_end:
-	set_cpus_allowed(current, saved_mask);
+	perf->state = state;
 	return (retval);
 }
 
@@ -231,8 +198,17 @@
 	unsigned int relation)
 {
 	struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
+	struct acpi_processor_performance *perf;
+	struct cpufreq_freqs freqs;
+	cpumask_t online_policy_cpus;
+	cpumask_t saved_mask;
+	cpumask_t set_mask;
+	cpumask_t covered_cpus;
+	unsigned int cur_state = 0;
 	unsigned int next_state = 0;
 	unsigned int result = 0;
+	unsigned int j;
+	unsigned int tmp;
 
 	dprintk("acpi_cpufreq_setpolicy\n");
 
@@ -241,11 +217,93 @@
 			target_freq,
 			relation,
 			&next_state);
-	if (result)
+	if (unlikely(result))
 		return (result);
 
-	result = acpi_processor_set_performance (data, policy->cpu, next_state);
+	perf = data->acpi_data;
+	cur_state = perf->state;
+	freqs.old = data->freq_table[cur_state].frequency;
+	freqs.new = data->freq_table[next_state].frequency;
+
+#ifdef CONFIG_SMP
+	/* cpufreq holds the hotplug lock, so we are safe from here on */
+	cpus_and(online_policy_cpus, cpu_online_map, policy->cpus);
+#endif
+
+	for_each_cpu_mask(j, online_policy_cpus) {
+		freqs.cpu = j;
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	}
+
+	/*
+	 * We need to call driver->target() on all or any CPU in
+	 * policy->cpus, depending on policy->shared_type.
+	 */
+	saved_mask = current->cpus_allowed;
+	cpus_clear(covered_cpus);
+	for_each_cpu_mask(j, online_policy_cpus) {
+		/*
+		 * Support for SMP systems.
+		 * Make sure we are running on CPU that wants to change freq
+		 */
+		cpus_clear(set_mask);
+		if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
+			cpus_or(set_mask, set_mask, online_policy_cpus);
+		else
+			cpu_set(j, set_mask);
+
+		set_cpus_allowed(current, set_mask);
+		if (unlikely(!cpu_isset(smp_processor_id(), set_mask))) {
+			dprintk("couldn't limit to CPUs in this domain\n");
+			result = -EAGAIN;
+			break;
+		}
+
+		result = acpi_processor_set_performance (data, j, next_state);
+		if (result) {
+			result = -EAGAIN;
+			break;
+		}
 
+		if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
+			break;
+ 
+		cpu_set(j, covered_cpus);
+	}
+
+	for_each_cpu_mask(j, online_policy_cpus) {
+		freqs.cpu = j;
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	}
+
+	if (unlikely(result)) {
+		/*
+		 * We have failed halfway through the frequency change.
+		 * We have sent callbacks to online_policy_cpus and
+		 * acpi_processor_set_performance() has been called on 
+		 * coverd_cpus. Best effort undo..
+		 */
+
+		if (!cpus_empty(covered_cpus)) {
+			for_each_cpu_mask(j, covered_cpus) {
+				policy->cpu = j;
+				acpi_processor_set_performance (data, 
+						j, 
+						cur_state);
+			}
+		}
+
+		tmp = freqs.new;
+		freqs.new = freqs.old;
+		freqs.old = tmp;
+		for_each_cpu_mask(j, online_policy_cpus) {
+			freqs.cpu = j;
+			cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+			cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+		}
+	}
+
+	set_cpus_allowed(current, saved_mask);
 	return (result);
 }
 
@@ -271,30 +329,65 @@
 	struct cpufreq_acpi_io	*data,
 	unsigned int		cpu)
 {
+	struct acpi_processor_performance	*perf = data->acpi_data;
+
 	if (cpu_khz) {
 		/* search the closest match to cpu_khz */
 		unsigned int i;
 		unsigned long freq;
-		unsigned long freqn = data->acpi_data.states[0].core_frequency * 1000;
+		unsigned long freqn = perf->states[0].core_frequency * 1000;
 
-		for (i=0; i < (data->acpi_data.state_count - 1); i++) {
+		for (i = 0; i < (perf->state_count - 1); i++) {
 			freq = freqn;
-			freqn = data->acpi_data.states[i+1].core_frequency * 1000;
+			freqn = perf->states[i+1].core_frequency * 1000;
 			if ((2 * cpu_khz) > (freqn + freq)) {
-				data->acpi_data.state = i;
+				perf->state = i;
 				return (freq);
 			}
 		}
-		data->acpi_data.state = data->acpi_data.state_count - 1;
+		perf->state = perf->state_count - 1;
 		return (freqn);
-	} else
+	} else {
 		/* assume CPU is at P0... */
-		data->acpi_data.state = 0;
-		return data->acpi_data.states[0].core_frequency * 1000;
-	
+		perf->state = 0;
+		return perf->states[0].core_frequency * 1000;
+	}
 }
 
 
+/*
+ * acpi_cpufreq_early_init - initialize ACPI P-States library
+ *
+ * Initialize the ACPI P-States library (drivers/acpi/processor_perflib.c)
+ * in order to determine correct frequency and voltage pairings. We can
+ * do _PDC and _PSD and find out the processor dependency for the
+ * actual init that will happen later...
+ */
+static int acpi_cpufreq_early_init_acpi(void)
+{
+	struct acpi_processor_performance	*data;
+	unsigned int				i, j;
+
+	dprintk("acpi_cpufreq_early_init\n");
+
+	for_each_cpu(i) {
+		data = kzalloc(sizeof(struct acpi_processor_performance), 
+			GFP_KERNEL);
+		if (!data) {
+			for_each_cpu(j) {
+				kfree(acpi_perf_data[j]);
+				acpi_perf_data[j] = NULL;
+			}
+			return (-ENOMEM);
+		}
+		acpi_perf_data[i] = data;
+	}
+
+	/* Do initialization in ACPI core */
+	acpi_processor_preregister_performance(acpi_perf_data);
+	return 0;
+}
+
 static int
 acpi_cpufreq_cpu_init (
 	struct cpufreq_policy   *policy)
@@ -304,41 +397,51 @@
 	struct cpufreq_acpi_io	*data;
 	unsigned int		result = 0;
 	struct cpuinfo_x86 *c = &cpu_data[policy->cpu];
+	struct acpi_processor_performance	*perf;
 
 	dprintk("acpi_cpufreq_cpu_init\n");
 
+	if (!acpi_perf_data[cpu])
+		return (-ENODEV);
+
 	data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
 	if (!data)
 		return (-ENOMEM);
 
+	data->acpi_data = acpi_perf_data[cpu];
 	acpi_io_data[cpu] = data;
 
-	result = acpi_processor_register_performance(&data->acpi_data, cpu);
+	result = acpi_processor_register_performance(data->acpi_data, cpu);
 
 	if (result)
 		goto err_free;
 
+	perf = data->acpi_data;
+	policy->cpus = perf->shared_cpu_map;
+	policy->shared_type = perf->shared_type;
+
 	if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) {
 		acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS;
 	}
 
 	/* capability check */
-	if (data->acpi_data.state_count <= 1) {
+	if (perf->state_count <= 1) {
 		dprintk("No P-States\n");
 		result = -ENODEV;
 		goto err_unreg;
 	}
-	if ((data->acpi_data.control_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO) ||
-	    (data->acpi_data.status_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
+
+	if ((perf->control_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO) ||
+	    (perf->status_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
 		dprintk("Unsupported address space [%d, %d]\n",
-			(u32) (data->acpi_data.control_register.space_id),
-			(u32) (data->acpi_data.status_register.space_id));
+			(u32) (perf->control_register.space_id),
+			(u32) (perf->status_register.space_id));
 		result = -ENODEV;
 		goto err_unreg;
 	}
 
 	/* alloc freq_table */
-	data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * (data->acpi_data.state_count + 1), GFP_KERNEL);
+	data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * (perf->state_count + 1), GFP_KERNEL);
 	if (!data->freq_table) {
 		result = -ENOMEM;
 		goto err_unreg;
@@ -346,9 +449,9 @@
 
 	/* detect transition latency */
 	policy->cpuinfo.transition_latency = 0;
-	for (i=0; i<data->acpi_data.state_count; i++) {
-		if ((data->acpi_data.states[i].transition_latency * 1000) > policy->cpuinfo.transition_latency)
-			policy->cpuinfo.transition_latency = data->acpi_data.states[i].transition_latency * 1000;
+	for (i=0; i<perf->state_count; i++) {
+		if ((perf->states[i].transition_latency * 1000) > policy->cpuinfo.transition_latency)
+			policy->cpuinfo.transition_latency = perf->states[i].transition_latency * 1000;
 	}
 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 
@@ -356,11 +459,11 @@
 	policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu);
 
 	/* table init */
-	for (i=0; i<=data->acpi_data.state_count; i++)
+	for (i=0; i<=perf->state_count; i++)
 	{
 		data->freq_table[i].index = i;
-		if (i<data->acpi_data.state_count)
-			data->freq_table[i].frequency = data->acpi_data.states[i].core_frequency * 1000;
+		if (i<perf->state_count)
+			data->freq_table[i].frequency = perf->states[i].core_frequency * 1000;
 		else
 			data->freq_table[i].frequency = CPUFREQ_TABLE_END;
 	}
@@ -375,12 +478,12 @@
 
 	printk(KERN_INFO "acpi-cpufreq: CPU%u - ACPI performance management activated.\n",
 	       cpu);
-	for (i = 0; i < data->acpi_data.state_count; i++)
+	for (i = 0; i < perf->state_count; i++)
 		dprintk("     %cP%d: %d MHz, %d mW, %d uS\n",
-			(i == data->acpi_data.state?'*':' '), i,
-			(u32) data->acpi_data.states[i].core_frequency,
-			(u32) data->acpi_data.states[i].power,
-			(u32) data->acpi_data.states[i].transition_latency);
+			(i == perf->state?'*':' '), i,
+			(u32) perf->states[i].core_frequency,
+			(u32) perf->states[i].power,
+			(u32) perf->states[i].transition_latency);
 
 	cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu);
 	
@@ -395,7 +498,7 @@
  err_freqfree:
 	kfree(data->freq_table);
  err_unreg:
-	acpi_processor_unregister_performance(&data->acpi_data, cpu);
+	acpi_processor_unregister_performance(perf, cpu);
  err_free:
 	kfree(data);
 	acpi_io_data[cpu] = NULL;
@@ -416,7 +519,7 @@
 	if (data) {
 		cpufreq_frequency_table_put_attr(policy->cpu);
 		acpi_io_data[policy->cpu] = NULL;
-		acpi_processor_unregister_performance(&data->acpi_data, policy->cpu);
+		acpi_processor_unregister_performance(data->acpi_data, policy->cpu);
 		kfree(data);
 	}
 
@@ -462,7 +565,10 @@
 
 	dprintk("acpi_cpufreq_init\n");
 
- 	result = cpufreq_register_driver(&acpi_cpufreq_driver);
+	result = acpi_cpufreq_early_init_acpi();
+
+	if (!result)
+ 		result = cpufreq_register_driver(&acpi_cpufreq_driver);
 	
 	return (result);
 }
@@ -471,10 +577,15 @@
 static void __exit
 acpi_cpufreq_exit (void)
 {
+	unsigned int	i;
 	dprintk("acpi_cpufreq_exit\n");
 
 	cpufreq_unregister_driver(&acpi_cpufreq_driver);
 
+	for_each_cpu(i) {
+		kfree(acpi_perf_data[i]);
+		acpi_perf_data[i] = NULL;
+	}
 	return;
 }
 
diff -urN oldtree/arch/i386/kernel/cpu/cpufreq/powernow-k8.c newtree/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
--- oldtree/arch/i386/kernel/cpu/cpufreq/powernow-k8.c	2006-02-19 11:40:58.645549008 +0000
+++ newtree/arch/i386/kernel/cpu/cpufreq/powernow-k8.c	2006-02-21 15:58:24.123479232 +0000
@@ -40,6 +40,7 @@
 
 #ifdef CONFIG_X86_POWERNOW_K8_ACPI
 #include <linux/acpi.h>
+#include <linux/mutex.h>
 #include <acpi/processor.h>
 #endif
 
@@ -49,7 +50,7 @@
 #include "powernow-k8.h"
 
 /* serialize freq changes  */
-static DECLARE_MUTEX(fidvid_sem);
+static DEFINE_MUTEX(fidvid_mutex);
 
 static struct powernow_k8_data *powernow_data[NR_CPUS];
 
@@ -945,14 +946,14 @@
 	if (cpufreq_frequency_table_target(pol, data->powernow_table, targfreq, relation, &newstate))
 		goto err_out;
 
-	down(&fidvid_sem);
+	mutex_lock(&fidvid_mutex);
 
 	powernow_k8_acpi_pst_values(data, newstate);
 
 	if (transition_frequency(data, newstate)) {
 		printk(KERN_ERR PFX "transition frequency failed\n");
 		ret = 1;
-		up(&fidvid_sem);
+		mutex_unlock(&fidvid_mutex);
 		goto err_out;
 	}
 
@@ -961,7 +962,7 @@
 		powernow_data[i]->currvid = data->currvid;
 		powernow_data[i]->currfid = data->currfid;
 	}	
-	up(&fidvid_sem);
+	mutex_unlock(&fidvid_mutex);
 
 	pol->cur = find_khz_freq_from_fid(data->currfid);
 	ret = 0;
diff -urN oldtree/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c newtree/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
--- oldtree/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c	2006-02-19 11:40:58.646548856 +0000
+++ newtree/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c	2006-02-21 15:58:10.594535944 +0000
@@ -351,7 +351,36 @@
 
 #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
 
-static struct acpi_processor_performance p;
+static struct acpi_processor_performance *acpi_perf_data[NR_CPUS];
+
+/*
+ * centrino_cpu_early_init_acpi - Do the preregistering with ACPI P-States
+ * library
+ *
+ * Before doing the actual init, we need to do _PSD related setup whenever
+ * supported by the BIOS. These are handled by this early_init routine.
+ */
+static int centrino_cpu_early_init_acpi(void)
+{
+	unsigned int	i, j;
+	struct acpi_processor_performance	*data;
+
+	for_each_cpu(i) {
+		data = kzalloc(sizeof(struct acpi_processor_performance), 
+				GFP_KERNEL);
+		if (!data) {
+			for_each_cpu(j) {
+				kfree(acpi_perf_data[j]);
+				acpi_perf_data[j] = NULL;
+			}
+			return (-ENOMEM);
+		}
+		acpi_perf_data[i] = data;
+	}
+
+	acpi_processor_preregister_performance(acpi_perf_data);
+	return 0;
+}
 
 /*
  * centrino_cpu_init_acpi - register with ACPI P-States library
@@ -365,46 +394,51 @@
 	unsigned long			cur_freq;
 	int				result = 0, i;
 	unsigned int			cpu = policy->cpu;
+	struct acpi_processor_performance	*p;
+
+	p = acpi_perf_data[cpu];
 
 	/* register with ACPI core */
-	if (acpi_processor_register_performance(&p, cpu)) {
+	if (acpi_processor_register_performance(p, cpu)) {
 		dprintk(KERN_INFO PFX "obtaining ACPI data failed\n");
 		return -EIO;
 	}
+	policy->cpus = p->shared_cpu_map;
+	policy->shared_type = p->shared_type;
 
 	/* verify the acpi_data */
-	if (p.state_count <= 1) {
+	if (p->state_count <= 1) {
 		dprintk("No P-States\n");
 		result = -ENODEV;
 		goto err_unreg;
 	}
 
-	if ((p.control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) ||
-	    (p.status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
+	if ((p->control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) ||
+	    (p->status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
 		dprintk("Invalid control/status registers (%x - %x)\n",
-			p.control_register.space_id, p.status_register.space_id);
+			p->control_register.space_id, p->status_register.space_id);
 		result = -EIO;
 		goto err_unreg;
 	}
 
-	for (i=0; i<p.state_count; i++) {
-		if (p.states[i].control != p.states[i].status) {
+	for (i=0; i<p->state_count; i++) {
+		if (p->states[i].control != p->states[i].status) {
 			dprintk("Different control (%llu) and status values (%llu)\n",
-				p.states[i].control, p.states[i].status);
+				p->states[i].control, p->states[i].status);
 			result = -EINVAL;
 			goto err_unreg;
 		}
 
-		if (!p.states[i].core_frequency) {
+		if (!p->states[i].core_frequency) {
 			dprintk("Zero core frequency for state %u\n", i);
 			result = -EINVAL;
 			goto err_unreg;
 		}
 
-		if (p.states[i].core_frequency > p.states[0].core_frequency) {
+		if (p->states[i].core_frequency > p->states[0].core_frequency) {
 			dprintk("P%u has larger frequency (%llu) than P0 (%llu), skipping\n", i,
-				p.states[i].core_frequency, p.states[0].core_frequency);
-			p.states[i].core_frequency = 0;
+				p->states[i].core_frequency, p->states[0].core_frequency);
+			p->states[i].core_frequency = 0;
 			continue;
 		}
 	}
@@ -416,26 +450,26 @@
 	}
 
 	centrino_model[cpu]->model_name=NULL;
-	centrino_model[cpu]->max_freq = p.states[0].core_frequency * 1000;
+	centrino_model[cpu]->max_freq = p->states[0].core_frequency * 1000;
 	centrino_model[cpu]->op_points =  kmalloc(sizeof(struct cpufreq_frequency_table) *
-					     (p.state_count + 1), GFP_KERNEL);
+					     (p->state_count + 1), GFP_KERNEL);
         if (!centrino_model[cpu]->op_points) {
                 result = -ENOMEM;
                 goto err_kfree;
         }
 
-        for (i=0; i<p.state_count; i++) {
-		centrino_model[cpu]->op_points[i].index = p.states[i].control;
-		centrino_model[cpu]->op_points[i].frequency = p.states[i].core_frequency * 1000;
+        for (i=0; i<p->state_count; i++) {
+		centrino_model[cpu]->op_points[i].index = p->states[i].control;
+		centrino_model[cpu]->op_points[i].frequency = p->states[i].core_frequency * 1000;
 		dprintk("adding state %i with frequency %u and control value %04x\n", 
 			i, centrino_model[cpu]->op_points[i].frequency, centrino_model[cpu]->op_points[i].index);
 	}
-	centrino_model[cpu]->op_points[p.state_count].frequency = CPUFREQ_TABLE_END;
+	centrino_model[cpu]->op_points[p->state_count].frequency = CPUFREQ_TABLE_END;
 
 	cur_freq = get_cur_freq(cpu);
 
-	for (i=0; i<p.state_count; i++) {
-		if (!p.states[i].core_frequency) {
+	for (i=0; i<p->state_count; i++) {
+		if (!p->states[i].core_frequency) {
 			dprintk("skipping state %u\n", i);
 			centrino_model[cpu]->op_points[i].frequency = CPUFREQ_ENTRY_INVALID;
 			continue;
@@ -451,7 +485,7 @@
 		}
 
 		if (cur_freq == centrino_model[cpu]->op_points[i].frequency)
-			p.state = i;
+			p->state = i;
 	}
 
 	/* notify BIOS that we exist */
@@ -464,12 +498,13 @@
  err_kfree:
 	kfree(centrino_model[cpu]);
  err_unreg:
-	acpi_processor_unregister_performance(&p, cpu);
+	acpi_processor_unregister_performance(p, cpu);
 	dprintk(KERN_INFO PFX "invalid ACPI data\n");
 	return (result);
 }
 #else
 static inline int centrino_cpu_init_acpi(struct cpufreq_policy *policy) { return -ENODEV; }
+static inline int centrino_cpu_early_init_acpi(void) { return 0; }
 #endif
 
 static int centrino_cpu_init(struct cpufreq_policy *policy)
@@ -557,10 +592,15 @@
 
 #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
 	if (!centrino_model[cpu]->model_name) {
-		dprintk("unregistering and freeing ACPI data\n");
-		acpi_processor_unregister_performance(&p, cpu);
-		kfree(centrino_model[cpu]->op_points);
-		kfree(centrino_model[cpu]);
+		static struct acpi_processor_performance *p;
+
+		if (acpi_perf_data[cpu]) {
+			p = acpi_perf_data[cpu];
+			dprintk("unregistering and freeing ACPI data\n");
+			acpi_processor_unregister_performance(p, cpu);
+			kfree(centrino_model[cpu]->op_points);
+			kfree(centrino_model[cpu]);
+		}
 	}
 #endif
 
@@ -594,63 +634,126 @@
 			    unsigned int relation)
 {
 	unsigned int    newstate = 0;
-	unsigned int	msr, oldmsr, h, cpu = policy->cpu;
+	unsigned int	msr, oldmsr = 0, h = 0, cpu = policy->cpu;
 	struct cpufreq_freqs	freqs;
+	cpumask_t		online_policy_cpus;
 	cpumask_t		saved_mask;
-	int			retval;
+	cpumask_t		set_mask;
+	cpumask_t		covered_cpus;
+	int			retval = 0;
+	unsigned int		j, k, first_cpu, tmp;
 
-	if (centrino_model[cpu] == NULL)
+	if (unlikely(centrino_model[cpu] == NULL))
 		return -ENODEV;
 
-	/*
-	 * Support for SMP systems.
-	 * Make sure we are running on the CPU that wants to change frequency
-	 */
-	saved_mask = current->cpus_allowed;
-	set_cpus_allowed(current, policy->cpus);
-	if (!cpu_isset(smp_processor_id(), policy->cpus)) {
-		dprintk("couldn't limit to CPUs in this domain\n");
-		return(-EAGAIN);
-	}
-
-	if (cpufreq_frequency_table_target(policy, centrino_model[cpu]->op_points, target_freq,
-					   relation, &newstate)) {
-		retval = -EINVAL;
-		goto migrate_end;
+	if (unlikely(cpufreq_frequency_table_target(policy,
+			centrino_model[cpu]->op_points,
+			target_freq,
+			relation,
+			&newstate))) {
+		return -EINVAL;
 	}
 
-	msr = centrino_model[cpu]->op_points[newstate].index;
-	rdmsr(MSR_IA32_PERF_CTL, oldmsr, h);
-
-	if (msr == (oldmsr & 0xffff)) {
-		retval = 0;
-		dprintk("no change needed - msr was and needs to be %x\n", oldmsr);
-		goto migrate_end;
-	}
-
-	freqs.cpu = cpu;
-	freqs.old = extract_clock(oldmsr, cpu, 0);
-	freqs.new = extract_clock(msr, cpu, 0);
+#ifdef CONFIG_SMP
+	/* cpufreq holds the hotplug lock, so we are safe from here on */
+	cpus_and(online_policy_cpus, cpu_online_map, policy->cpus);
+#endif
 
-	dprintk("target=%dkHz old=%d new=%d msr=%04x\n",
-		target_freq, freqs.old, freqs.new, msr);
+	saved_mask = current->cpus_allowed;
+	first_cpu = 1;
+	cpus_clear(covered_cpus);
+	for_each_cpu_mask(j, online_policy_cpus) {
+		/*
+		 * Support for SMP systems.
+		 * Make sure we are running on CPU that wants to change freq
+		 */
+		cpus_clear(set_mask);
+		if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
+			cpus_or(set_mask, set_mask, online_policy_cpus);
+		else
+			cpu_set(j, set_mask);
+
+		set_cpus_allowed(current, set_mask);
+		if (unlikely(!cpu_isset(smp_processor_id(), set_mask))) {
+			dprintk("couldn't limit to CPUs in this domain\n");
+			retval = -EAGAIN;
+			if (first_cpu) {
+				/* We haven't started the transition yet. */
+				goto migrate_end;
+			}
+			break;
+		}
 
-	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+		msr = centrino_model[cpu]->op_points[newstate].index;
 
-	/* all but 16 LSB are "reserved", so treat them with
-	   care */
-	oldmsr &= ~0xffff;
-	msr &= 0xffff;
-	oldmsr |= msr;
+		if (first_cpu) {
+			rdmsr(MSR_IA32_PERF_CTL, oldmsr, h);
+			if (msr == (oldmsr & 0xffff)) {
+				dprintk("no change needed - msr was and needs "
+					"to be %x\n", oldmsr);
+				retval = 0;
+				goto migrate_end;
+			}
+
+			freqs.old = extract_clock(oldmsr, cpu, 0);
+			freqs.new = extract_clock(msr, cpu, 0);
+
+			dprintk("target=%dkHz old=%d new=%d msr=%04x\n",
+				target_freq, freqs.old, freqs.new, msr);
+
+			for_each_cpu_mask(k, online_policy_cpus) {
+				freqs.cpu = k;
+				cpufreq_notify_transition(&freqs,
+					CPUFREQ_PRECHANGE);
+			}
+
+			first_cpu = 0;
+			/* all but 16 LSB are reserved, treat them with care */
+			oldmsr &= ~0xffff;
+			msr &= 0xffff;
+			oldmsr |= msr;
+		}
 
-	wrmsr(MSR_IA32_PERF_CTL, oldmsr, h);
+		wrmsr(MSR_IA32_PERF_CTL, oldmsr, h);
+		if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
+			break;
+
+		cpu_set(j, covered_cpus);
+	}
+
+	for_each_cpu_mask(k, online_policy_cpus) {
+		freqs.cpu = k;
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	}
+
+	if (unlikely(retval)) {
+		/*
+		 * We have failed halfway through the frequency change.
+		 * We have sent callbacks to policy->cpus and
+		 * MSRs have already been written on coverd_cpus.
+		 * Best effort undo..
+		 */
+
+		if (!cpus_empty(covered_cpus)) {
+			for_each_cpu_mask(j, covered_cpus) {
+				set_cpus_allowed(current, cpumask_of_cpu(j));
+				wrmsr(MSR_IA32_PERF_CTL, oldmsr, h);
+			}
+		}
 
-	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+		tmp = freqs.new;
+		freqs.new = freqs.old;
+		freqs.old = tmp;
+		for_each_cpu_mask(j, online_policy_cpus) {
+			freqs.cpu = j;
+			cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+			cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+		}
+	}
 
-	retval = 0;
 migrate_end:
 	set_cpus_allowed(current, saved_mask);
-	return (retval);
+	return 0;
 }
 
 static struct freq_attr* centrino_attr[] = {
@@ -692,12 +795,25 @@
 	if (!cpu_has(cpu, X86_FEATURE_EST))
 		return -ENODEV;
 
+	centrino_cpu_early_init_acpi();
+
 	return cpufreq_register_driver(&centrino_driver);
 }
 
 static void __exit centrino_exit(void)
 {
+#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
+	unsigned int j;
+#endif
+	
 	cpufreq_unregister_driver(&centrino_driver);
+
+#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
+	for_each_cpu(j) {
+		kfree(acpi_perf_data[j]);
+		acpi_perf_data[j] = NULL;
+	}
+#endif
 }
 
 MODULE_AUTHOR ("Jeremy Fitzhardinge <jeremy@goop.org>");
diff -urN oldtree/arch/i386/kernel/cpu/mtrr/main.c newtree/arch/i386/kernel/cpu/mtrr/main.c
--- oldtree/arch/i386/kernel/cpu/mtrr/main.c	2006-02-19 11:40:58.696541256 +0000
+++ newtree/arch/i386/kernel/cpu/mtrr/main.c	2006-02-21 15:58:24.127478624 +0000
@@ -36,6 +36,7 @@
 #include <linux/pci.h>
 #include <linux/smp.h>
 #include <linux/cpu.h>
+#include <linux/mutex.h>
 
 #include <asm/mtrr.h>
 
@@ -47,7 +48,7 @@
 u32 num_var_ranges = 0;
 
 unsigned int *usage_table;
-static DECLARE_MUTEX(mtrr_sem);
+static DEFINE_MUTEX(mtrr_mutex);
 
 u32 size_or_mask, size_and_mask;
 
@@ -333,7 +334,7 @@
 	/* No CPU hotplug when we change MTRR entries */
 	lock_cpu_hotplug();
 	/*  Search for existing MTRR  */
-	down(&mtrr_sem);
+	mutex_lock(&mtrr_mutex);
 	for (i = 0; i < num_var_ranges; ++i) {
 		mtrr_if->get(i, &lbase, &lsize, &ltype);
 		if (base >= lbase + lsize)
@@ -371,7 +372,7 @@
 		printk(KERN_INFO "mtrr: no more MTRRs available\n");
 	error = i;
  out:
-	up(&mtrr_sem);
+	mutex_unlock(&mtrr_mutex);
 	unlock_cpu_hotplug();
 	return error;
 }
@@ -464,7 +465,7 @@
 	max = num_var_ranges;
 	/* No CPU hotplug when we change MTRR entries */
 	lock_cpu_hotplug();
-	down(&mtrr_sem);
+	mutex_lock(&mtrr_mutex);
 	if (reg < 0) {
 		/*  Search for existing MTRR  */
 		for (i = 0; i < max; ++i) {
@@ -503,7 +504,7 @@
 		set_mtrr(reg, 0, 0, 0);
 	error = reg;
  out:
-	up(&mtrr_sem);
+	mutex_unlock(&mtrr_mutex);
 	unlock_cpu_hotplug();
 	return error;
 }
@@ -685,7 +686,7 @@
 	if (!mtrr_if || !use_intel())
 		return;
 	/*
-	 * Ideally we should hold mtrr_sem here to avoid mtrr entries changed,
+	 * Ideally we should hold mtrr_mutex here to avoid mtrr entries changed,
 	 * but this routine will be called in cpu boot time, holding the lock
 	 * breaks it. This routine is called in two cases: 1.very earily time
 	 * of software resume, when there absolutely isn't mtrr entry changes;
diff -urN oldtree/arch/i386/kernel/microcode.c newtree/arch/i386/kernel/microcode.c
--- oldtree/arch/i386/kernel/microcode.c	2006-02-19 11:40:58.704540040 +0000
+++ newtree/arch/i386/kernel/microcode.c	2006-02-21 15:58:24.134477560 +0000
@@ -80,6 +80,7 @@
 #include <linux/miscdevice.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
+#include <linux/mutex.h>
 
 #include <asm/msr.h>
 #include <asm/uaccess.h>
@@ -113,7 +114,7 @@
 static DEFINE_SPINLOCK(microcode_update_lock);
 
 /* no concurrent ->write()s are allowed on /dev/cpu/microcode */
-static DECLARE_MUTEX(microcode_sem);
+static DEFINE_MUTEX(microcode_mutex);
 
 static void __user *user_buffer;	/* user area microcode data buffer */
 static unsigned int user_buffer_size;	/* it's size */
@@ -444,7 +445,7 @@
 		return -EINVAL;
 	}
 
-	down(&microcode_sem);
+	mutex_lock(&microcode_mutex);
 
 	user_buffer = (void __user *) buf;
 	user_buffer_size = (int) len;
@@ -453,7 +454,7 @@
 	if (!ret)
 		ret = (ssize_t)len;
 
-	up(&microcode_sem);
+	mutex_unlock(&microcode_mutex);
 
 	return ret;
 }
diff -urN oldtree/arch/i386/kernel/mpparse.c newtree/arch/i386/kernel/mpparse.c
--- oldtree/arch/i386/kernel/mpparse.c	2006-02-19 11:40:58.705539888 +0000
+++ newtree/arch/i386/kernel/mpparse.c	2006-02-21 15:58:22.762686104 +0000
@@ -828,6 +828,8 @@
 		smp_scan_config(address, 0x400);
 }
 
+int es7000_plat;
+
 /* --------------------------------------------------------------------------
                             ACPI-based MP Configuration
    -------------------------------------------------------------------------- */
@@ -1005,8 +1007,6 @@
 	return;
 }
 
-int es7000_plat;
-
 void __init mp_config_acpi_legacy_irqs (void)
 {
 	struct mpc_config_intsrc intsrc;
diff -urN oldtree/arch/i386/kernel/time_hpet.c newtree/arch/i386/kernel/time_hpet.c
--- oldtree/arch/i386/kernel/time_hpet.c	2006-02-19 11:40:58.713538672 +0000
+++ newtree/arch/i386/kernel/time_hpet.c	2006-02-21 15:58:22.902664824 +0000
@@ -411,9 +411,45 @@
 
 int hpet_rtc_dropped_irq(void)
 {
+	unsigned int cnt, ticks_per_int, lost_ints;
+
 	if (!is_hpet_enabled())
 		return 0;
 
+	if (UIE_on | PIE_on | AIE_on) {
+		/*
+		 * The interrupt handler schedules the next interrupt at a
+		 * constant offset from the time the current interrupt was
+		 * scheduled, without regard to the actual time. When the
+		 * handler is delayed too long, it tries to schedule the next
+		 * interrupt in the past and the hardware would not interrupt
+		 * until the counter had wrapped around. We catch it here.
+		 */
+		cnt = hpet_readl(HPET_COUNTER);
+		/* was the comparator set to a time in the past? */
+		if ((int)(cnt - hpet_t1_cmp) > 0) {
+			/* determine how many interrupts were actually lost */
+			ticks_per_int = (hpet_tick * HZ) / hpet_rtc_int_freq;
+			lost_ints = (cnt - hpet_t1_cmp) / ticks_per_int + 1;
+			/*
+			 * Make sure that, even with the time needed to execute
+			 * this code, the next scheduled interrupt has been
+			 * moved back to the future.
+			 */
+			lost_ints++;
+
+			cnt = hpet_t1_cmp + lost_ints * ticks_per_int;
+			hpet_writel(cnt, HPET_T1_CMP);
+			hpet_t1_cmp = cnt;
+
+			if (PIE_on)
+				PIE_count += lost_ints;
+
+			printk(KERN_WARNING "rtc: lost some interrupts"
+			       " at %ldHz.\n", hpet_rtc_int_freq);
+		}
+	}
+
 	return 1;
 }
 
diff -urN oldtree/arch/i386/kernel/traps.c newtree/arch/i386/kernel/traps.c
--- oldtree/arch/i386/kernel/traps.c	2006-02-19 11:40:58.714538520 +0000
+++ newtree/arch/i386/kernel/traps.c	2006-02-21 15:58:12.801200480 +0000
@@ -365,7 +365,8 @@
 #endif
 		if (nl)
 			printk("\n");
-	notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
+		sysfs_printk_last_file();
+		notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
 		show_registers(regs);
   	} else
 		printk(KERN_EMERG "Recursive die() failure, output suppressed\n");
diff -urN oldtree/arch/i386/kernel/vm86.c newtree/arch/i386/kernel/vm86.c
--- oldtree/arch/i386/kernel/vm86.c	2006-02-19 11:40:58.715538368 +0000
+++ newtree/arch/i386/kernel/vm86.c	2006-02-21 15:58:11.716365400 +0000
@@ -43,6 +43,7 @@
 #include <linux/smp_lock.h>
 #include <linux/highmem.h>
 #include <linux/ptrace.h>
+#include <linux/audit.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -252,6 +253,7 @@
 static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk)
 {
 	struct tss_struct *tss;
+	long eax;
 /*
  * make sure the vm86() system call doesn't try to do anything silly
  */
@@ -305,13 +307,19 @@
 	tsk->thread.screen_bitmap = info->screen_bitmap;
 	if (info->flags & VM86_SCREEN_BITMAP)
 		mark_screen_rdonly(tsk->mm);
+	__asm__ __volatile__("xorl %eax,%eax; movl %eax,%fs; movl %eax,%gs\n\t");
+	__asm__ __volatile__("movl %%eax, %0\n" :"=r"(eax));
+
+	/*call audit_syscall_exit since we do not exit via the normal paths */
+	if (unlikely(current->audit_context))
+		audit_syscall_exit(current, AUDITSC_RESULT(eax), eax);
+
 	__asm__ __volatile__(
-		"xorl %%eax,%%eax; movl %%eax,%%fs; movl %%eax,%%gs\n\t"
 		"movl %0,%%esp\n\t"
 		"movl %1,%%ebp\n\t"
 		"jmp resume_userspace"
 		: /* no outputs */
-		:"r" (&info->regs), "r" (task_thread_info(tsk)) : "ax");
+		:"r" (&info->regs), "r" (task_thread_info(tsk)));
 	/* we never return here */
 }
 
diff -urN oldtree/arch/i386/mach-es7000/es7000.h newtree/arch/i386/mach-es7000/es7000.h
--- oldtree/arch/i386/mach-es7000/es7000.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/i386/mach-es7000/es7000.h	2006-02-21 15:58:22.763685952 +0000
@@ -83,6 +83,7 @@
 	struct psai psai;
 };
 
+#ifdef CONFIG_ACPI
 struct acpi_table_sdt {
 	unsigned long pa;
 	unsigned long count;
@@ -99,6 +100,9 @@
 	u32 OEMTableSize;
 };
 
+extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
+#endif
+
 struct mip_reg {
 	unsigned long long off_0;
 	unsigned long long off_8;
@@ -114,7 +118,6 @@
 #define	MIP_FUNC(VALUE) 	(VALUE & 0xff)
 
 extern int parse_unisys_oem (char *oemptr);
-extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
 extern void setup_unisys(void);
 extern int es7000_start_cpu(int cpu, unsigned long eip);
 extern void es7000_sw_apic(void);
diff -urN oldtree/arch/i386/mach-es7000/es7000plat.c newtree/arch/i386/mach-es7000/es7000plat.c
--- oldtree/arch/i386/mach-es7000/es7000plat.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/i386/mach-es7000/es7000plat.c	2006-02-21 15:58:22.773684432 +0000
@@ -51,8 +51,6 @@
 int 			mip_port;
 unsigned long		mip_addr, host_addr;
 
-#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_ACPI)
-
 /*
  * GSI override for ES7000 platforms.
  */
@@ -76,8 +74,6 @@
 	return gsi;
 }
 
-#endif	/* (CONFIG_X86_IO_APIC) && (CONFIG_ACPI) */
-
 void __init
 setup_unisys(void)
 {
@@ -160,6 +156,7 @@
 	return es7000_plat;
 }
 
+#ifdef CONFIG_ACPI
 int __init
 find_unisys_acpi_oem_table(unsigned long *oem_addr)
 {
@@ -212,6 +209,7 @@
 	}
 	return -1;
 }
+#endif
 
 static void
 es7000_spin(int n)
diff -urN oldtree/arch/i386/pci/Makefile newtree/arch/i386/pci/Makefile
--- oldtree/arch/i386/pci/Makefile	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/i386/pci/Makefile	2006-02-21 15:58:18.684306112 +0000
@@ -1,4 +1,4 @@
-obj-y				:= i386.o
+obj-y				:= i386.o init.o
 
 obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
 obj-$(CONFIG_PCI_MMCONFIG)	+= mmconfig.o direct.o
diff -urN oldtree/arch/i386/pci/acpi.c newtree/arch/i386/pci/acpi.c
--- oldtree/arch/i386/pci/acpi.c	2006-02-19 11:40:58.719537760 +0000
+++ newtree/arch/i386/pci/acpi.c	2006-02-21 15:58:17.903424824 +0000
@@ -8,20 +8,37 @@
 struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum)
 {
 	struct pci_bus *bus;
+	struct pci_sysdata *sd;
 
+	/* Allocate per-root-bus (not per bus) arch-specific data.
+	 * TODO: leak; this memory is never freed.
+	 * It's arguable whether it's worth the trouble to care.
+	 */
+	sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+	if (!sd) {
+		printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum);
+		return NULL;
+	}
+
+#ifdef CONFIG_PCI_DOMAINS
+	sd->domain = domain;
+#else
 	if (domain != 0) {
 		printk(KERN_WARNING "PCI: Multiple domains not supported\n");
 		return NULL;
 	}
+#endif /* CONFIG_PCI_DOMAINS */
 
-	bus = pcibios_scan_root(busnum);
+	bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
+	if (!bus)
+		kfree(sd);
 #ifdef CONFIG_ACPI_NUMA
 	if (bus != NULL) {
 		int pxm = acpi_get_pxm(device->handle);
 		if (pxm >= 0) {
-			bus->sysdata = (void *)(unsigned long)pxm_to_node(pxm);
-			printk("bus %d -> pxm %d -> node %ld\n",
-				busnum, pxm, (long)(bus->sysdata));
+			sd->node = pxm_to_node(pxm);
+			printk("bus %d -> pxm %d -> node %d\n",
+				busnum, pxm, sd->node);
 		}
 	}
 #endif
diff -urN oldtree/arch/i386/pci/common.c newtree/arch/i386/pci/common.c
--- oldtree/arch/i386/pci/common.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/i386/pci/common.c	2006-02-21 15:58:17.928421024 +0000
@@ -29,14 +29,18 @@
 struct pci_bus *pci_root_bus;
 struct pci_raw_ops *raw_pci_ops;
 
+struct pci_sysdata pci_default_sysdata = { .node = -1 };
+
 static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
 {
-	return raw_pci_ops->read(0, bus->number, devfn, where, size, value);
+	return raw_pci_ops->read(pci_domain_nr(bus), bus->number,
+				 devfn, where, size, value);
 }
 
 static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
 {
-	return raw_pci_ops->write(0, bus->number, devfn, where, size, value);
+	return raw_pci_ops->write(pci_domain_nr(bus), bus->number,
+				  devfn, where, size, value);
 }
 
 struct pci_ops pci_root_ops = {
@@ -124,6 +128,7 @@
 struct pci_bus * __devinit pcibios_scan_root(int busnum)
 {
 	struct pci_bus *bus = NULL;
+	struct pci_sysdata *sd;
 
 	while ((bus = pci_find_next_bus(bus)) != NULL) {
 		if (bus->number == busnum) {
@@ -132,9 +137,19 @@
 		}
 	}
 
+	/* Allocate per-root-bus (not per bus) arch-specific data.
+	 * TODO: leak; this memory is never freed.
+	 * It's arguable whether it's worth the trouble to care.
+	 */
+	sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+	if (!sd) {
+		printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum);
+		return NULL;
+	}
+
 	printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);
 
-	return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, NULL);
+	return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
 }
 
 extern u8 pci_cache_line_size;
diff -urN oldtree/arch/i386/pci/direct.c newtree/arch/i386/pci/direct.c
--- oldtree/arch/i386/pci/direct.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/i386/pci/direct.c	2006-02-21 15:58:18.676307328 +0000
@@ -245,7 +245,7 @@
 	return works;
 }
 
-static int __init pci_direct_init(void)
+void __init pci_direct_init(void)
 {
 	struct resource *region, *region2;
 
@@ -258,16 +258,16 @@
 	if (pci_check_type1()) {
 		printk(KERN_INFO "PCI: Using configuration type 1\n");
 		raw_pci_ops = &pci_direct_conf1;
-		return 0;
+		return;
 	}
 	release_resource(region);
 
  type2:
 	if ((pci_probe & PCI_PROBE_CONF2) == 0)
-		goto out;
+		return;
 	region = request_region(0xCF8, 4, "PCI conf2");
 	if (!region)
-		goto out;
+		return;
 	region2 = request_region(0xC000, 0x1000, "PCI conf2");
 	if (!region2)
 		goto fail2;
@@ -275,15 +275,10 @@
 	if (pci_check_type2()) {
 		printk(KERN_INFO "PCI: Using configuration type 2\n");
 		raw_pci_ops = &pci_direct_conf2;
-		return 0;
+		return;
 	}
 
 	release_resource(region2);
  fail2:
 	release_resource(region);
-
- out:
-	return 0;
 }
-
-arch_initcall(pci_direct_init);
diff -urN oldtree/arch/i386/pci/fixup.c newtree/arch/i386/pci/fixup.c
--- oldtree/arch/i386/pci/fixup.c	2006-02-19 11:40:58.719537760 +0000
+++ newtree/arch/i386/pci/fixup.c	2006-02-21 15:58:17.948417984 +0000
@@ -25,9 +25,11 @@
 		pci_read_config_byte(d, reg++, &subb);
 		DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
 		if (busno)
-			pci_scan_bus(busno, &pci_root_ops, NULL);	/* Bus A */
+			pci_scan_bus(busno, &pci_root_ops,
+					&pci_default_sysdata);	/* Bus A */
 		if (suba < subb)
-			pci_scan_bus(suba+1, &pci_root_ops, NULL);	/* Bus B */
+			pci_scan_bus(suba+1, &pci_root_ops,
+					&pci_default_sysdata);	/* Bus B */
 	}
 	pcibios_last_bus = -1;
 }
@@ -42,7 +44,7 @@
 	u8 busno;
 	pci_read_config_byte(d, 0x4a, &busno);
 	printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", pci_name(d), busno);
-	pci_scan_bus(busno, &pci_root_ops, NULL);
+	pci_scan_bus(busno, &pci_root_ops, &pci_default_sysdata);
 	pcibios_last_bus = -1;
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx);
diff -urN oldtree/arch/i386/pci/init.c newtree/arch/i386/pci/init.c
--- oldtree/arch/i386/pci/init.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/i386/pci/init.c	2006-02-21 15:58:18.684306112 +0000
@@ -0,0 +1,25 @@
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include "pci.h"
+
+/* arch_initcall has too random ordering, so call the initializers
+   in the right sequence from here. */
+static __init int pci_access_init(void)
+{
+#ifdef CONFIG_PCI_MMCONFIG
+	pci_mmcfg_init();
+#endif
+	if (raw_pci_ops)
+		return 0;
+#ifdef CONFIG_PCI_DIRECT
+	pci_direct_init();
+#endif
+	if (raw_pci_ops)
+		return 0;
+#ifdef CONFIG_PCI_BIOS
+	pci_pcbios_init();
+#endif
+	return 0;
+}
+arch_initcall(pci_access_init);
diff -urN oldtree/arch/i386/pci/legacy.c newtree/arch/i386/pci/legacy.c
--- oldtree/arch/i386/pci/legacy.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/i386/pci/legacy.c	2006-02-21 15:58:17.948417984 +0000
@@ -26,7 +26,8 @@
 			    l != 0x0000 && l != 0xffff) {
 				DBG("Found device at %02x:%02x [%04x]\n", n, devfn, l);
 				printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n);
-				pci_scan_bus(n, &pci_root_ops, NULL);
+				pci_scan_bus(n, &pci_root_ops,
+						&pci_default_sysdata);
 				break;
 			}
 		}
diff -urN oldtree/arch/i386/pci/mmconfig.c newtree/arch/i386/pci/mmconfig.c
--- oldtree/arch/i386/pci/mmconfig.c	2006-02-19 11:40:58.721537456 +0000
+++ newtree/arch/i386/pci/mmconfig.c	2006-02-21 15:58:18.677307176 +0000
@@ -172,25 +172,20 @@
 	}
 }
 
-static int __init pci_mmcfg_init(void)
+void __init pci_mmcfg_init(void)
 {
 	if ((pci_probe & PCI_PROBE_MMCONF) == 0)
-		goto out;
+		return;
 
 	acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
 	if ((pci_mmcfg_config_num == 0) ||
 	    (pci_mmcfg_config == NULL) ||
 	    (pci_mmcfg_config[0].base_address == 0))
-		goto out;
+		return;
 
 	printk(KERN_INFO "PCI: Using MMCONFIG\n");
 	raw_pci_ops = &pci_mmcfg;
 	pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
 
 	unreachable_devices();
-
- out:
-	return 0;
 }
-
-arch_initcall(pci_mmcfg_init);
diff -urN oldtree/arch/i386/pci/numa.c newtree/arch/i386/pci/numa.c
--- oldtree/arch/i386/pci/numa.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/i386/pci/numa.c	2006-02-21 15:58:17.950417680 +0000
@@ -97,9 +97,11 @@
 		pci_read_config_byte(d, reg++, &subb);
 		DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
 		if (busno)
-			pci_scan_bus(QUADLOCAL2BUS(quad,busno), &pci_root_ops, NULL);	/* Bus A */
+			pci_scan_bus(QUADLOCAL2BUS(quad,busno), &pci_root_ops,
+					&pci_default_sysdata);	/* Bus A */
 		if (suba < subb)
-			pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), &pci_root_ops, NULL);	/* Bus B */
+			pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), &pci_root_ops,
+					&pci_default_sysdata);	/* Bus B */
 	}
 	pcibios_last_bus = -1;
 }
@@ -124,7 +126,7 @@
 			printk("Scanning PCI bus %d for quad %d\n", 
 				QUADLOCAL2BUS(quad,0), quad);
 			pci_scan_bus(QUADLOCAL2BUS(quad,0), 
-				&pci_root_ops, NULL);
+				&pci_root_ops, &pci_default_sysdata);
 		}
 	return 0;
 }
diff -urN oldtree/arch/i386/pci/pcbios.c newtree/arch/i386/pci/pcbios.c
--- oldtree/arch/i386/pci/pcbios.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/i386/pci/pcbios.c	2006-02-21 15:58:18.683306264 +0000
@@ -476,14 +476,12 @@
 }
 EXPORT_SYMBOL(pcibios_set_irq_routing);
 
-static int __init pci_pcbios_init(void)
+void __init pci_pcbios_init(void)
 {
 	if ((pci_probe & PCI_PROBE_BIOS) 
 		&& ((raw_pci_ops = pci_find_bios()))) {
 		pci_probe |= PCI_BIOS_SORT;
 		pci_bios_present = 1;
 	}
-	return 0;
 }
 
-arch_initcall(pci_pcbios_init);
diff -urN oldtree/arch/i386/pci/pci.h newtree/arch/i386/pci/pci.h
--- oldtree/arch/i386/pci/pci.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/i386/pci/pci.h	2006-02-21 15:58:18.683306264 +0000
@@ -80,4 +80,7 @@
 extern int pci_conf1_read(unsigned int seg, unsigned int bus,
 			  unsigned int devfn, int reg, int len, u32 *value);
 
+extern void pci_direct_init(void);
+extern void pci_pcbios_init(void);
+extern void pci_mmcfg_init(void);
 
diff -urN oldtree/arch/i386/pci/visws.c newtree/arch/i386/pci/visws.c
--- oldtree/arch/i386/pci/visws.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/i386/pci/visws.c	2006-02-21 15:58:17.950417680 +0000
@@ -102,8 +102,8 @@
 		"bridge B (PIIX4) bus: %u\n", pci_bus1, pci_bus0);
 
 	raw_pci_ops = &pci_direct_conf1;
-	pci_scan_bus(pci_bus0, &pci_root_ops, NULL);
-	pci_scan_bus(pci_bus1, &pci_root_ops, NULL);
+	pci_scan_bus(pci_bus0, &pci_root_ops, &pci_default_sysdata);
+	pci_scan_bus(pci_bus1, &pci_root_ops, &pci_default_sysdata);
 	pci_fixup_irqs(visws_swizzle, visws_map_irq);
 	pcibios_resource_survey();
 	return 0;
diff -urN oldtree/arch/ia64/kernel/efi.c newtree/arch/ia64/kernel/efi.c
--- oldtree/arch/ia64/kernel/efi.c	2006-02-19 11:40:58.735535328 +0000
+++ newtree/arch/ia64/kernel/efi.c	2006-02-21 15:58:36.140652344 +0000
@@ -630,7 +630,7 @@
 		if (phys_addr - md->phys_addr < (md->num_pages << EFI_PAGE_SHIFT))
 			 return md;
 	}
-	return 0;
+	return NULL;
 }
 
 static int
@@ -868,7 +868,7 @@
 void
 efi_memmap_init(unsigned long *s, unsigned long *e)
 {
-	struct kern_memdesc *k, *prev = 0;
+	struct kern_memdesc *k, *prev = NULL;
 	u64	contig_low=0, contig_high=0;
 	u64	as, ae, lim;
 	void *efi_map_start, *efi_map_end, *p, *q;
diff -urN oldtree/arch/ia64/kernel/irq_ia64.c newtree/arch/ia64/kernel/irq_ia64.c
--- oldtree/arch/ia64/kernel/irq_ia64.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ia64/kernel/irq_ia64.c	2006-02-21 15:58:17.796441088 +0000
@@ -46,6 +46,10 @@
 
 #define IRQ_DEBUG	0
 
+/* These can be overridden in platform_irq_init */
+int ia64_first_device_vector = IA64_DEF_FIRST_DEVICE_VECTOR;
+int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR;
+
 /* default base addr of IPI table */
 void __iomem *ipi_base_addr = ((void __iomem *)
 			       (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR));
@@ -60,7 +64,7 @@
 };
 EXPORT_SYMBOL(isa_irq_to_vector_map);
 
-static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)];
+static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_MAX_DEVICE_VECTORS)];
 
 int
 assign_irq_vector (int irq)
@@ -89,6 +93,19 @@
 		printk(KERN_WARNING "%s: double free!\n", __FUNCTION__);
 }
 
+int
+reserve_irq_vector (int vector)
+{
+	int pos;
+
+	if (vector < IA64_FIRST_DEVICE_VECTOR ||
+	    vector > IA64_LAST_DEVICE_VECTOR)
+		return -EINVAL;
+
+	pos = vector - IA64_FIRST_DEVICE_VECTOR;
+	return test_and_set_bit(pos, ia64_vector_mask);
+}
+
 #ifdef CONFIG_SMP
 #	define IS_RESCHEDULE(vec)	(vec == IA64_IPI_RESCHEDULE)
 #else
diff -urN oldtree/arch/ia64/kernel/ptrace.c newtree/arch/ia64/kernel/ptrace.c
--- oldtree/arch/ia64/kernel/ptrace.c	2006-02-19 11:40:58.776529096 +0000
+++ newtree/arch/ia64/kernel/ptrace.c	2006-02-21 15:58:11.724364184 +0000
@@ -1656,8 +1656,14 @@
 		     long arg4, long arg5, long arg6, long arg7,
 		     struct pt_regs regs)
 {
-	if (unlikely(current->audit_context))
-		audit_syscall_exit(current, AUDITSC_RESULT(regs.r10), regs.r8);
+	if (unlikely(current->audit_context)) {
+		int success = AUDITSC_RESULT(regs.r10);
+		long result = regs.r8;
+
+		if (success != AUDITSC_SUCCESS)
+			result = -result;
+		audit_syscall_exit(current, success, result);
+	}
 
 	if (test_thread_flag(TIF_SYSCALL_TRACE)
 	    && (current->ptrace & PT_PTRACED))
diff -urN oldtree/arch/ia64/sn/kernel/irq.c newtree/arch/ia64/sn/kernel/irq.c
--- oldtree/arch/ia64/sn/kernel/irq.c	2006-02-19 11:40:58.792526664 +0000
+++ newtree/arch/ia64/sn/kernel/irq.c	2006-02-21 15:58:17.805439720 +0000
@@ -202,6 +202,9 @@
 	int i;
 	irq_desc_t *base_desc = irq_desc;
 
+	ia64_first_device_vector = IA64_SN2_FIRST_DEVICE_VECTOR;
+	ia64_last_device_vector = IA64_SN2_LAST_DEVICE_VECTOR;
+
 	for (i = 0; i < NR_IRQS; i++) {
 		if (base_desc[i].handler == &no_irq_type) {
 			base_desc[i].handler = &irq_type_sn;
@@ -285,6 +288,7 @@
 	/* link it into the sn_irq[irq] list */
 	spin_lock(&sn_irq_info_lock);
 	list_add_rcu(&sn_irq_info->list, sn_irq_lh[sn_irq_info->irq_irq]);
+	reserve_irq_vector(sn_irq_info->irq_irq);
 	spin_unlock(&sn_irq_info_lock);
 
 	register_intr_pda(sn_irq_info);
@@ -310,8 +314,11 @@
 	spin_lock(&sn_irq_info_lock);
 	list_del_rcu(&sn_irq_info->list);
 	spin_unlock(&sn_irq_info_lock);
+	if (list_empty(sn_irq_lh[sn_irq_info->irq_irq]))
+		free_irq_vector(sn_irq_info->irq_irq);
 	call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
 	pci_dev_put(pci_dev);
+
 }
 
 static inline void
diff -urN oldtree/arch/m32r/kernel/entry.S newtree/arch/m32r/kernel/entry.S
--- oldtree/arch/m32r/kernel/entry.S	2006-02-19 11:40:58.842519064 +0000
+++ newtree/arch/m32r/kernel/entry.S	2006-02-21 15:58:36.158649608 +0000
@@ -301,7 +301,7 @@
 
 	.global	eit_vector
 
-	.equ ei_vec_table, eit_vector + 0x0200
+#define ei_vec_table eit_vector + 0x0200
 
 /*
  * EI handler routine
diff -urN oldtree/arch/m32r/kernel/setup.c newtree/arch/m32r/kernel/setup.c
--- oldtree/arch/m32r/kernel/setup.c	2006-02-19 11:40:58.847518304 +0000
+++ newtree/arch/m32r/kernel/setup.c	2006-02-21 15:58:36.159649456 +0000
@@ -371,10 +371,10 @@
 }
 
 struct seq_operations cpuinfo_op = {
-	start:	c_start,
-	next:	c_next,
-	stop:	c_stop,
-	show:	show_cpuinfo,
+	.start = c_start,
+	.next = c_next,
+	.stop = c_stop,
+	.show = show_cpuinfo,
 };
 #endif	/* CONFIG_PROC_FS */
 
diff -urN oldtree/arch/m32r/kernel/setup_mappi.c newtree/arch/m32r/kernel/setup_mappi.c
--- oldtree/arch/m32r/kernel/setup_mappi.c	2006-02-19 11:40:58.849518000 +0000
+++ newtree/arch/m32r/kernel/setup_mappi.c	2006-02-21 15:58:36.160649304 +0000
@@ -96,7 +96,7 @@
 	/* MFT2 : system timer */
 	irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
 	irq_desc[M32R_IRQ_MFT2].handler = &mappi_irq_type;
-	irq_desc[M32R_IRQ_MFT2].action = 0;
+	irq_desc[M32R_IRQ_MFT2].action = NULL;
 	irq_desc[M32R_IRQ_MFT2].depth = 1;
 	icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
 	disable_mappi_irq(M32R_IRQ_MFT2);
@@ -105,7 +105,7 @@
 	/* SIO0_R : uart receive data */
 	irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
 	irq_desc[M32R_IRQ_SIO0_R].handler = &mappi_irq_type;
-	irq_desc[M32R_IRQ_SIO0_R].action = 0;
+	irq_desc[M32R_IRQ_SIO0_R].action = NULL;
 	irq_desc[M32R_IRQ_SIO0_R].depth = 1;
 	icu_data[M32R_IRQ_SIO0_R].icucr = 0;
 	disable_mappi_irq(M32R_IRQ_SIO0_R);
@@ -113,7 +113,7 @@
 	/* SIO0_S : uart send data */
 	irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
 	irq_desc[M32R_IRQ_SIO0_S].handler = &mappi_irq_type;
-	irq_desc[M32R_IRQ_SIO0_S].action = 0;
+	irq_desc[M32R_IRQ_SIO0_S].action = NULL;
 	irq_desc[M32R_IRQ_SIO0_S].depth = 1;
 	icu_data[M32R_IRQ_SIO0_S].icucr = 0;
 	disable_mappi_irq(M32R_IRQ_SIO0_S);
@@ -121,7 +121,7 @@
 	/* SIO1_R : uart receive data */
 	irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
 	irq_desc[M32R_IRQ_SIO1_R].handler = &mappi_irq_type;
-	irq_desc[M32R_IRQ_SIO1_R].action = 0;
+	irq_desc[M32R_IRQ_SIO1_R].action = NULL;
 	irq_desc[M32R_IRQ_SIO1_R].depth = 1;
 	icu_data[M32R_IRQ_SIO1_R].icucr = 0;
 	disable_mappi_irq(M32R_IRQ_SIO1_R);
@@ -129,7 +129,7 @@
 	/* SIO1_S : uart send data */
 	irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
 	irq_desc[M32R_IRQ_SIO1_S].handler = &mappi_irq_type;
-	irq_desc[M32R_IRQ_SIO1_S].action = 0;
+	irq_desc[M32R_IRQ_SIO1_S].action = NULL;
 	irq_desc[M32R_IRQ_SIO1_S].depth = 1;
 	icu_data[M32R_IRQ_SIO1_S].icucr = 0;
 	disable_mappi_irq(M32R_IRQ_SIO1_S);
@@ -139,7 +139,7 @@
 	/* INT1 : pccard0 interrupt */
 	irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED;
 	irq_desc[M32R_IRQ_INT1].handler = &mappi_irq_type;
-	irq_desc[M32R_IRQ_INT1].action = 0;
+	irq_desc[M32R_IRQ_INT1].action = NULL;
 	irq_desc[M32R_IRQ_INT1].depth = 1;
 	icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00;
 	disable_mappi_irq(M32R_IRQ_INT1);
@@ -147,7 +147,7 @@
 	/* INT2 : pccard1 interrupt */
 	irq_desc[M32R_IRQ_INT2].status = IRQ_DISABLED;
 	irq_desc[M32R_IRQ_INT2].handler = &mappi_irq_type;
-	irq_desc[M32R_IRQ_INT2].action = 0;
+	irq_desc[M32R_IRQ_INT2].action = NULL;
 	irq_desc[M32R_IRQ_INT2].depth = 1;
 	icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00;
 	disable_mappi_irq(M32R_IRQ_INT2);
diff -urN oldtree/arch/m32r/kernel/signal.c newtree/arch/m32r/kernel/signal.c
--- oldtree/arch/m32r/kernel/signal.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/m32r/kernel/signal.c	2006-02-21 15:58:36.160649304 +0000
@@ -34,7 +34,7 @@
 int do_signal(struct pt_regs *, sigset_t *);
 
 asmlinkage int
-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
+sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize,
 		  unsigned long r2, unsigned long r3, unsigned long r4,
 		  unsigned long r5, unsigned long r6, struct pt_regs regs)
 {
@@ -79,8 +79,8 @@
 struct rt_sigframe
 {
 	int sig;
-	struct siginfo *pinfo;
-	void *puc;
+	struct siginfo __user *pinfo;
+	void __user *puc;
 	struct siginfo info;
 	struct ucontext uc;
 //	struct _fpstate fpstate;
diff -urN oldtree/arch/m32r/kernel/smp.c newtree/arch/m32r/kernel/smp.c
--- oldtree/arch/m32r/kernel/smp.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/m32r/kernel/smp.c	2006-02-21 15:58:36.161649152 +0000
@@ -231,7 +231,7 @@
 	local_irq_save(flags);
 	__flush_tlb_all();
 	local_irq_restore(flags);
-	smp_call_function(flush_tlb_all_ipi, 0, 1, 1);
+	smp_call_function(flush_tlb_all_ipi, NULL, 1, 1);
 	preempt_enable();
 }
 
diff -urN oldtree/arch/m32r/kernel/traps.c newtree/arch/m32r/kernel/traps.c
--- oldtree/arch/m32r/kernel/traps.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/m32r/kernel/traps.c	2006-02-21 15:58:36.162649000 +0000
@@ -269,7 +269,7 @@
 #define DO_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
-	do_trap(trapnr, signr, 0, regs, error_code, NULL); \
+	do_trap(trapnr, signr, NULL, regs, error_code, NULL); \
 }
 
 #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
diff -urN oldtree/arch/m32r/mm/mmu.S newtree/arch/m32r/mm/mmu.S
--- oldtree/arch/m32r/mm/mmu.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/m32r/mm/mmu.S	2006-02-21 15:58:36.162649000 +0000
@@ -140,7 +140,7 @@
 ;;   r2: pte_data
 ;;   r3: free
 	; pgd = *(unsigned long *)MPTB;
-	ld24	r2, #(-MPTB - 1)
+	ld24	r2, #(0xffffffff-MPTB)
 	srl3	r3, r0, #22
 #ifdef CONFIG_ISA_DUAL_ISSUE
 	not	r2, r2		    ||	slli	r3, #2	; r3: pgd offset
@@ -255,7 +255,7 @@
 ; r0: address, r2: entry
 ; r1,r3,r4: (free)
 	; pgd = *(unsigned long *)MPTB;
-	ld24	r1, #(-MPTB-1)
+	ld24	r1, #(0xffffffff-MPTB)
 	not	r1, r1
 	ld	r1, @r1
 	srl3	r4, r0, #22
diff -urN oldtree/arch/m68k/kernel/process.c newtree/arch/m68k/kernel/process.c
--- oldtree/arch/m68k/kernel/process.c	2006-02-19 11:40:58.918507512 +0000
+++ newtree/arch/m68k/kernel/process.c	2006-02-21 15:58:36.167648240 +0000
@@ -129,6 +129,9 @@
 	for (;;);
 }
 
+void (*pm_power_off)(void) = machine_power_off;
+EXPORT_SYMBOL(pm_power_off);
+
 void show_regs(struct pt_regs * regs)
 {
 	printk("\n");
@@ -219,13 +222,13 @@
 {
 	unsigned long clone_flags;
 	unsigned long newsp;
-	int *parent_tidptr, *child_tidptr;
+	int __user *parent_tidptr, *child_tidptr;
 
 	/* syscall2 puts clone_flags in d1 and usp in d2 */
 	clone_flags = regs->d1;
 	newsp = regs->d2;
-	parent_tidptr = (int *)regs->d3;
-	child_tidptr = (int *)regs->d4;
+	parent_tidptr = (int __user *)regs->d3;
+	child_tidptr = (int __user *)regs->d4;
 	if (!newsp)
 		newsp = rdusp();
 	return do_fork(clone_flags, newsp, regs, 0,
@@ -359,7 +362,7 @@
 /*
  * sys_execve() executes a new program.
  */
-asmlinkage int sys_execve(char *name, char **argv, char **envp)
+asmlinkage int sys_execve(char __user *name, char __user * __user *argv, char __user * __user *envp)
 {
 	int error;
 	char * filename;
diff -urN oldtree/arch/m68k/kernel/traps.c newtree/arch/m68k/kernel/traps.c
--- oldtree/arch/m68k/kernel/traps.c	2006-02-19 11:40:58.921507056 +0000
+++ newtree/arch/m68k/kernel/traps.c	2006-02-21 15:58:36.171647632 +0000
@@ -114,7 +114,7 @@
 	if(MACH_IS_SUN3X) {
 		extern e_vector *sun3x_prom_vbr;
 
-		__asm__ volatile ("movec %%vbr, %0" : "=r" ((void*)sun3x_prom_vbr));
+		__asm__ volatile ("movec %%vbr, %0" : "=r" (sun3x_prom_vbr));
 	}
 
 	/* setup the exception vector table */
@@ -369,13 +369,13 @@
 
 	switch (wbs & WBSIZ_040) {
 	case BA_SIZE_BYTE:
-		res = put_user(wbd & 0xff, (char *)wba);
+		res = put_user(wbd & 0xff, (char __user *)wba);
 		break;
 	case BA_SIZE_WORD:
-		res = put_user(wbd & 0xffff, (short *)wba);
+		res = put_user(wbd & 0xffff, (short __user *)wba);
 		break;
 	case BA_SIZE_LONG:
-		res = put_user(wbd, (int *)wba);
+		res = put_user(wbd, (int __user *)wba);
 		break;
 	}
 
diff -urN oldtree/arch/m68k/math-emu/fp_cond.S newtree/arch/m68k/math-emu/fp_cond.S
--- oldtree/arch/m68k/math-emu/fp_cond.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/m68k/math-emu/fp_cond.S	2006-02-21 15:58:36.172647480 +0000
@@ -163,7 +163,7 @@
 
 fp_do_scc:
 	swap	%d1
-	putuser.b %d1,(%a0),fp_err_ua1,%a0
+	putuser .b,%d1,(%a0),fp_err_ua1,%a0
 	printf	PDECODE,"\n"
 	jra	fp_end
 
diff -urN oldtree/arch/m68k/math-emu/fp_decode.h newtree/arch/m68k/math-emu/fp_decode.h
--- oldtree/arch/m68k/math-emu/fp_decode.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/m68k/math-emu/fp_decode.h	2006-02-21 15:58:36.176646872 +0000
@@ -311,7 +311,7 @@
 	btst	#2,%d2
 	jne	1f
 	printf	PDECODE,")@("
-	getuser.l (%a1),%a1,fp_err_ua1,%a1
+	getuser .l,(%a1),%a1,fp_err_ua1,%a1
 debug	jra	"2f"
 1:	printf	PDECODE,","
 2:
@@ -322,7 +322,7 @@
 	btst	#2,%d2
 	jeq	1f
 	printf	PDECODE,")@("
-	getuser.l (%a1),%a1,fp_err_ua1,%a1
+	getuser .l,(%a1),%a1,fp_err_ua1,%a1
 debug	jra	"2f"
 1:	printf	PDECODE,","
 2:
diff -urN oldtree/arch/m68k/math-emu/fp_move.S newtree/arch/m68k/math-emu/fp_move.S
--- oldtree/arch/m68k/math-emu/fp_move.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/m68k/math-emu/fp_move.S	2006-02-21 15:58:36.177646720 +0000
@@ -200,12 +200,12 @@
 
 fp_format_long:
 	jsr	fp_conv_ext2long
-	putuser.l %d0,(%a1),fp_err_ua1,%a1
+	putuser .l,%d0,(%a1),fp_err_ua1,%a1
 	jra	fp_finish_move
 
 fp_format_single:
 	jsr	fp_conv_ext2single
-	putuser.l %d0,(%a1),fp_err_ua1,%a1
+	putuser .l,%d0,(%a1),fp_err_ua1,%a1
 	jra	fp_finish_move
 
 fp_format_extended:
@@ -213,11 +213,11 @@
 	lsl.w	#1,%d0
 	lsl.l	#7,%d0
 	lsl.l	#8,%d0
-	putuser.l %d0,(%a1)+,fp_err_ua1,%a1
+	putuser .l,%d0,"(%a1)+",fp_err_ua1,%a1
 	move.l	(%a0)+,%d0
-	putuser.l %d0,(%a1)+,fp_err_ua1,%a1
+	putuser .l,%d0,"(%a1)+",fp_err_ua1,%a1
 	move.l	(%a0),%d0
-	putuser.l %d0,(%a1),fp_err_ua1,%a1
+	putuser .l,%d0,(%a1),fp_err_ua1,%a1
 	jra	fp_finish_move
 
 fp_format_packed:
@@ -227,7 +227,7 @@
 
 fp_format_word:
 	jsr	fp_conv_ext2short
-	putuser.w %d0,(%a1),fp_err_ua1,%a1
+	putuser .w,%d0,(%a1),fp_err_ua1,%a1
 	jra	fp_finish_move
 
 fp_format_double:
@@ -236,7 +236,7 @@
 
 fp_format_byte:
 	jsr	fp_conv_ext2byte
-	putuser.b %d0,(%a1),fp_err_ua1,%a1
+	putuser .b,%d0,(%a1),fp_err_ua1,%a1
 |	jra	fp_finish_move
 
 fp_finish_move:
diff -urN oldtree/arch/m68k/math-emu/fp_movem.S newtree/arch/m68k/math-emu/fp_movem.S
--- oldtree/arch/m68k/math-emu/fp_movem.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/m68k/math-emu/fp_movem.S	2006-02-21 15:58:36.177646720 +0000
@@ -141,14 +141,14 @@
 	| move register from memory into fpu
 	jra	3f
 1:	printf	PMOVEM,"(%p>%p)",2,%a0,%a1
-	getuser.l (%a0)+,%d2,fp_err_ua1,%a0
+	getuser .l,"(%a0)+",%d2,fp_err_ua1,%a0
 	lsr.l	#8,%d2
 	lsr.l	#7,%d2
 	lsr.w	#1,%d2
 	move.l	%d2,(%a1)+
-	getuser.l (%a0)+,%d2,fp_err_ua1,%a0
+	getuser .l,"(%a0)+",%d2,fp_err_ua1,%a0
 	move.l	%d2,(%a1)+
-	getuser.l (%a0),%d2,fp_err_ua1,%a0
+	getuser .l,(%a0),%d2,fp_err_ua1,%a0
 	move.l	%d2,(%a1)
 	subq.l	#8,%a0
 	subq.l	#8,%a1
@@ -164,11 +164,11 @@
 	lsl.w	#1,%d2
 	lsl.l	#7,%d2
 	lsl.l	#8,%d2
-	putuser.l %d2,(%a0)+,fp_err_ua1,%a0
+	putuser .l,%d2,"(%a0)+",fp_err_ua1,%a0
 	move.l	(%a1)+,%d2
-	putuser.l %d2,(%a0)+,fp_err_ua1,%a0
+	putuser .l,%d2,"(%a0)+",fp_err_ua1,%a0
 	move.l	(%a1),%d2
-	putuser.l %d2,(%a0),fp_err_ua1,%a0
+	putuser .l,%d2,(%a0),fp_err_ua1,%a0
 	subq.l	#8,%a1
 	subq.l	#8,%a0
 	add.l	%d0,%a0
@@ -325,7 +325,7 @@
 	| move register from memory into fpu
 	jra	3f
 1:	printf	PMOVEM,"(%p>%p)",2,%a0,%a1
-	getuser.l (%a0)+,%d0,fp_err_ua1,%a0
+	getuser .l,"(%a0)+",%d0,fp_err_ua1,%a0
 	move.l	%d0,(%a1)
 2:	addq.l	#4,%a1
 3:	lsl.b	#1,%d1
@@ -336,7 +336,7 @@
 	| move register from fpu into memory
 1:	printf	PMOVEM,"(%p>%p)",2,%a1,%a0
 	move.l	(%a1),%d0
-	putuser.l %d0,(%a0)+,fp_err_ua1,%a0
+	putuser .l,%d0,"(%a0)+",fp_err_ua1,%a0
 2:	addq.l	#4,%a1
 4:	lsl.b	#1,%d1
 	jcs	1b
diff -urN oldtree/arch/m68k/math-emu/fp_scan.S newtree/arch/m68k/math-emu/fp_scan.S
--- oldtree/arch/m68k/math-emu/fp_scan.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/m68k/math-emu/fp_scan.S	2006-02-21 15:58:36.178646568 +0000
@@ -64,7 +64,7 @@
 | normal fpu instruction? (this excludes fsave/frestore)
 	fp_get_pc %a0
 	printf	PDECODE,"%08x: ",1,%a0
-	getuser.b (%a0),%d0,fp_err_ua1,%a0
+	getuser .b,(%a0),%d0,fp_err_ua1,%a0
 #if 1
 	cmp.b	#0xf2,%d0		| cpid = 1
 #else
@@ -72,7 +72,7 @@
 #endif
 	jne	fp_nonstd
 | first two instruction words are kept in %d2
-	getuser.l (%a0)+,%d2,fp_err_ua1,%a0
+	getuser .l,"(%a0)+",%d2,fp_err_ua1,%a0
 	fp_put_pc %a0
 fp_decode_cond:				| separate conditional instr
 	fp_decode_cond_instr_type
@@ -230,7 +230,7 @@
 	movel	%a0,%a1
 	clr.l	%d1
 	jra	2f
-1:	getuser.b (%a1)+,%d1,fp_err_ua1,%a1
+1:	getuser .b,(%a1)+,%d1,fp_err_ua1,%a1
 	printf	PDECODE,"%02x",1,%d1
 2:	dbra	%d0,1b
 	movem.l	(%sp)+,%d0/%d1
@@ -252,24 +252,24 @@
 	.long	fp_byte, fp_ill
 
 fp_long:
-	getuser.l (%a1),%d0,fp_err_ua1,%a1
+	getuser .l,(%a1),%d0,fp_err_ua1,%a1
 	jsr	fp_conv_long2ext
 	jra	fp_getdest
 
 fp_single:
-	getuser.l (%a1),%d0,fp_err_ua1,%a1
+	getuser .l,(%a1),%d0,fp_err_ua1,%a1
 	jsr	fp_conv_single2ext
 	jra	fp_getdest
 
 fp_ext:
-	getuser.l (%a1)+,%d0,fp_err_ua1,%a1
+	getuser .l,"(%a1)+",%d0,fp_err_ua1,%a1
 	lsr.l	#8,%d0
 	lsr.l	#7,%d0
 	lsr.w	#1,%d0
 	move.l	%d0,(%a0)+
-	getuser.l (%a1)+,%d0,fp_err_ua1,%a1
+	getuser .l,"(%a1)+",%d0,fp_err_ua1,%a1
 	move.l	%d0,(%a0)+
-	getuser.l (%a1),%d0,fp_err_ua1,%a1
+	getuser .l,(%a1),%d0,fp_err_ua1,%a1
 	move.l	%d0,(%a0)
 	subq.l	#8,%a0
 	jra	fp_getdest
@@ -279,7 +279,7 @@
 	jra	fp_ill
 
 fp_word:
-	getuser.w (%a1),%d0,fp_err_ua1,%a1
+	getuser .w,(%a1),%d0,fp_err_ua1,%a1
 	ext.l	%d0
 	jsr	fp_conv_long2ext
 	jra	fp_getdest
@@ -289,7 +289,7 @@
 	jra	fp_getdest
 
 fp_byte:
-	getuser.b (%a1),%d0,fp_err_ua1,%a1
+	getuser .b,(%a1),%d0,fp_err_ua1,%a1
 	extb.l	%d0
 	jsr	fp_conv_long2ext
 |	jra	fp_getdest
@@ -465,7 +465,7 @@
 
 fp_nonstd:
 	fp_get_pc %a0
-	getuser.l (%a0),%d0,fp_err_ua1,%a0
+	getuser .l,(%a0),%d0,fp_err_ua1,%a0
 	printf	,"nonstd ((%08x)=%08x)\n",2,%a0,%d0
 	moveq	#-1,%d0
 	rts
diff -urN oldtree/arch/m68k/math-emu/fp_util.S newtree/arch/m68k/math-emu/fp_util.S
--- oldtree/arch/m68k/math-emu/fp_util.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/m68k/math-emu/fp_util.S	2006-02-21 15:58:36.183645808 +0000
@@ -160,11 +160,11 @@
 
 fp_conv_double2ext:
 #ifdef FPU_EMU_DEBUG
-	getuser.l %a1@(0),%d0,fp_err_ua2,%a1
-	getuser.l %a1@(4),%d1,fp_err_ua2,%a1
+	getuser .l,%a1@(0),%d0,fp_err_ua2,%a1
+	getuser .l,%a1@(4),%d1,fp_err_ua2,%a1
 	printf	PCONV,"d2e: %p%p -> %p(",3,%d0,%d1,%a0
 #endif
-	getuser.l (%a1)+,%d0,fp_err_ua2,%a1
+	getuser .l,"(%a1)+",%d0,fp_err_ua2,%a1
 	move.l	%d0,%d1
 	lsl.l	#8,%d0			| shift high mantissa
 	lsl.l	#3,%d0
@@ -178,7 +178,7 @@
 	add.w	#0x3fff-0x3ff,%d1	| re-bias the exponent.
 9:	move.l	%d1,(%a0)+		| fp_ext.sign, fp_ext.exp
 	move.l	%d0,(%a0)+
-	getuser.l (%a1)+,%d0,fp_err_ua2,%a1
+	getuser .l,"(%a1)+",%d0,fp_err_ua2,%a1
 	move.l	%d0,%d1
 	lsl.l	#8,%d0
 	lsl.l	#3,%d0
@@ -1287,17 +1287,17 @@
 	lsr.l	#4,%d0
 	lsr.l	#8,%d0
 	or.l	%d2,%d0
-	putuser.l %d0,(%a1)+,fp_err_ua2,%a1
+	putuser .l,%d0,"(%a1)+",fp_err_ua2,%a1
 	moveq	#21,%d0
 	lsl.l	%d0,%d1
 	move.l	(%a0),%d0
 	lsr.l	#4,%d0
 	lsr.l	#7,%d0
 	or.l	%d1,%d0
-	putuser.l %d0,(%a1),fp_err_ua2,%a1
+	putuser .l,%d0,(%a1),fp_err_ua2,%a1
 #ifdef FPU_EMU_DEBUG
-	getuser.l %a1@(-4),%d0,fp_err_ua2,%a1
-	getuser.l %a1@(0),%d1,fp_err_ua2,%a1
+	getuser .l,%a1@(-4),%d0,fp_err_ua2,%a1
+	getuser .l,%a1@(0),%d1,fp_err_ua2,%a1
 	printf	PCONV,"%p(%08x%08x)\n",3,%a1,%d0,%d1
 #endif
 	rts
diff -urN oldtree/arch/m68knommu/kernel/vmlinux.lds.S newtree/arch/m68knommu/kernel/vmlinux.lds.S
--- oldtree/arch/m68knommu/kernel/vmlinux.lds.S	2006-02-19 11:40:58.932505384 +0000
+++ newtree/arch/m68knommu/kernel/vmlinux.lds.S	2006-02-21 15:58:12.678219176 +0000
@@ -269,6 +269,11 @@
 		*(__ksymtab_gpl)
 		__stop___ksymtab_gpl = .;
 
+		/* Kernel symbol table: GPL-future symbols */
+		__start___ksymtab_gpl_future = .;
+		*(__ksymtab_gpl_future)
+		__stop___ksymtab_gpl_future = .;
+
 		/* Kernel symbol table: Normal symbols */
 		__start___kcrctab = .;
 		*(__kcrctab)
@@ -279,6 +284,11 @@
 		*(__kcrctab_gpl)
 		__stop___kcrctab_gpl = .;
 
+		/* Kernel symbol table: GPL-future symbols */
+		__start___kcrctab_gpl_future = .;
+		*(__kcrctab_gpl_future)
+		__stop___kcrctab_gpl_future = .;
+
 		/* Kernel symbol table: strings */
 		*(__ksymtab_strings)
 
diff -urN oldtree/arch/mips/lasat/sysctl.c newtree/arch/mips/lasat/sysctl.c
--- oldtree/arch/mips/lasat/sysctl.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/mips/lasat/sysctl.c	2006-02-21 15:58:24.142476344 +0000
@@ -30,12 +30,13 @@
 #include <linux/string.h>
 #include <linux/net.h>
 #include <linux/inet.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include "sysctl.h"
 #include "ds1603.h"
 
-static DECLARE_MUTEX(lasat_info_sem);
+static DEFINE_MUTEX(lasat_info_mutex);
 
 /* Strategy function to write EEPROM after changing string entry */
 int sysctl_lasatstring(ctl_table *table, int *name, int nlen,
@@ -43,17 +44,17 @@
 		void *newval, size_t newlen, void **context)
 {
 	int r;
-	down(&lasat_info_sem);
+	mutex_lock(&lasat_info_mutex);
 	r = sysctl_string(table, name,
 			  nlen, oldval, oldlenp, newval, newlen, context);
 	if (r < 0) {
-		up(&lasat_info_sem);
+		mutex_unlock(&lasat_info_mutex);
 		return r;
 	}
 	if (newval && newlen) {
 		lasat_write_eeprom_info();
 	}
-	up(&lasat_info_sem);
+	mutex_unlock(&lasat_info_mutex);
 	return 1;
 }
 
@@ -63,14 +64,14 @@
 		       void *buffer, size_t *lenp, loff_t *ppos)
 {
 	int r;
-	down(&lasat_info_sem);
+	mutex_lock(&lasat_info_mutex);
 	r = proc_dostring(table, write, filp, buffer, lenp, ppos);
 	if ( (!write) || r) {
-		up(&lasat_info_sem);
+		mutex_unlock(&lasat_info_mutex);
 		return r;
 	}
 	lasat_write_eeprom_info();
-	up(&lasat_info_sem);
+	mutex_unlock(&lasat_info_mutex);
 	return 0;
 }
 
@@ -79,14 +80,14 @@
 		       void *buffer, size_t *lenp, loff_t *ppos)
 {
 	int r;
-	down(&lasat_info_sem);
+	mutex_lock(&lasat_info_mutex);
 	r = proc_dointvec(table, write, filp, buffer, lenp, ppos);
 	if ( (!write) || r) {
-		up(&lasat_info_sem);
+		mutex_unlock(&lasat_info_mutex);
 		return r;
 	}
 	lasat_write_eeprom_info();
-	up(&lasat_info_sem);
+	mutex_unlock(&lasat_info_mutex);
 	return 0;
 }
 
@@ -98,7 +99,7 @@
 		       void *buffer, size_t *lenp, loff_t *ppos)
 {
 	int r;
-	down(&lasat_info_sem);
+	mutex_lock(&lasat_info_mutex);
 	if (!write) {
 		rtctmp = ds1603_read();
 		/* check for time < 0 and set to 0 */
@@ -107,11 +108,11 @@
 	}
 	r = proc_dointvec(table, write, filp, buffer, lenp, ppos);
 	if ( (!write) || r) {
-		up(&lasat_info_sem);
+		mutex_unlock(&lasat_info_mutex);
 		return r;
 	}
 	ds1603_set(rtctmp);
-	up(&lasat_info_sem);
+	mutex_unlock(&lasat_info_mutex);
 	return 0;
 }
 #endif
@@ -122,16 +123,16 @@
 		    void *newval, size_t newlen, void **context)
 {
 	int r;
-	down(&lasat_info_sem);
+	mutex_lock(&lasat_info_mutex);
 	r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen, context);
 	if (r < 0) {
-		up(&lasat_info_sem);
+		mutex_unlock(&lasat_info_mutex);
 		return r;
 	}
 	if (newval && newlen) {
 		lasat_write_eeprom_info();
 	}
-	up(&lasat_info_sem);
+	mutex_unlock(&lasat_info_mutex);
 	return 1;
 }
 
@@ -142,19 +143,19 @@
 		    void *newval, size_t newlen, void **context)
 {
 	int r;
-	down(&lasat_info_sem);
+	mutex_lock(&lasat_info_mutex);
 	rtctmp = ds1603_read();
 	if (rtctmp < 0)
 		rtctmp = 0;
 	r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen, context);
 	if (r < 0) {
-		up(&lasat_info_sem);
+		mutex_unlock(&lasat_info_mutex);
 		return r;
 	}
 	if (newval && newlen) {
 		ds1603_set(rtctmp);
 	}
-	up(&lasat_info_sem);
+	mutex_unlock(&lasat_info_mutex);
 	return 1;
 }
 #endif
@@ -192,13 +193,13 @@
 		return 0;
 	}
 
-	down(&lasat_info_sem);
+	mutex_lock(&lasat_info_mutex);
 	if (write) {
 		len = 0;
 		p = buffer;
 		while (len < *lenp) {
 			if(get_user(c, p++)) {
-				up(&lasat_info_sem);
+				mutex_unlock(&lasat_info_mutex);
 				return -EFAULT;
 			}
 			if (c == 0 || c == '\n')
@@ -209,7 +210,7 @@
 			len = sizeof(proc_lasat_ipbuf) - 1;
 		if (copy_from_user(proc_lasat_ipbuf, buffer, len))
 		{
-			up(&lasat_info_sem);
+			mutex_unlock(&lasat_info_mutex);
 			return -EFAULT;
 		}
 		proc_lasat_ipbuf[len] = 0;
@@ -230,12 +231,12 @@
 			len = *lenp;
 		if (len)
 			if(copy_to_user(buffer, proc_lasat_ipbuf, len)) {
-				up(&lasat_info_sem);
+				mutex_unlock(&lasat_info_mutex);
 				return -EFAULT;
 			}
 		if (len < *lenp) {
 			if(put_user('\n', ((char *) buffer) + len)) {
-				up(&lasat_info_sem);
+				mutex_unlock(&lasat_info_mutex);
 				return -EFAULT;
 			}
 			len++;
@@ -244,7 +245,7 @@
 		*ppos += len;
 	}
 	update_bcastaddr();
-	up(&lasat_info_sem);
+	mutex_unlock(&lasat_info_mutex);
 	return 0;
 }
 #endif /* defined(CONFIG_INET) */
@@ -256,10 +257,10 @@
 {
 	int r;
 
-	down(&lasat_info_sem);
+	mutex_lock(&lasat_info_mutex);
 	r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen, context);
 	if (r < 0) {
-		up(&lasat_info_sem);
+		mutex_unlock(&lasat_info_mutex);
 		return r;
 	}
 
@@ -271,7 +272,7 @@
 		lasat_write_eeprom_info();
 		lasat_init_board_info();
 	}
-	up(&lasat_info_sem);
+	mutex_unlock(&lasat_info_mutex);
 
 	return 0;
 }
@@ -280,10 +281,10 @@
 		       void *buffer, size_t *lenp, loff_t *ppos)
 {
 	int r;
-	down(&lasat_info_sem);
+	mutex_lock(&lasat_info_mutex);
 	r = proc_dointvec(table, write, filp, buffer, lenp, ppos);
 	if ( (!write) || r) {
-		up(&lasat_info_sem);
+		mutex_unlock(&lasat_info_mutex);
 		return r;
 	}
 	if (filp && filp->f_dentry)
@@ -294,7 +295,7 @@
 			lasat_board_info.li_eeprom_info.debugaccess = lasat_board_info.li_debugaccess;
 	}
 	lasat_write_eeprom_info();
-	up(&lasat_info_sem);
+	mutex_unlock(&lasat_info_mutex);
 	return 0;
 }
 
diff -urN oldtree/arch/powerpc/Kconfig newtree/arch/powerpc/Kconfig
--- oldtree/arch/powerpc/Kconfig	2006-02-19 11:40:59.150472248 +0000
+++ newtree/arch/powerpc/Kconfig	2006-02-21 15:58:17.111545208 +0000
@@ -89,6 +89,12 @@
 	  Used to allow a board to specify it wants a uImage built by default
 	default n
 
+config DEFAULT_UIMAGE
+	bool
+	help
+	  Used to allow a board to specify it wants a uImage built by default
+	default n
+
 menu "Processor support"
 choice
 	prompt "Processor Type"
@@ -127,6 +133,12 @@
 	select 83xx
 	select PPC_FPU
 
+config PPC_85xx
+	bool "Freescale 85xx"
+	select E500
+	select FSL_SOC
+	select 85xx
+
 config 40x
 	bool "AMCC 40x"
 
@@ -139,8 +151,6 @@
 config E200
 	bool "Freescale e200"
 
-config E500
-	bool "Freescale e500"
 endchoice
 
 config POWER4_ONLY
@@ -168,6 +178,13 @@
 config 83xx
 	bool
 
+# this is temp to handle compat with arch=ppc
+config 85xx
+	bool
+
+config E500
+	bool
+
 config PPC_FPU
 	bool
 	default y if PPC64
@@ -217,6 +234,7 @@
 config SPE
 	bool "SPE Support"
 	depends on E200 || E500
+	default y
 	---help---
 	  This option enables kernel support for the Signal Processing
 	  Extensions (SPE) to the PowerPC processor. The kernel currently
@@ -734,13 +752,12 @@
 
 config PPC_I8259
 	bool
-	default y if 85xx
 	default n
 
 config PPC_INDIRECT_PCI
 	bool
 	depends on PCI
-	default y if 40x || 44x || 85xx
+	default y if 40x || 44x
 	default n
 
 config EISA
@@ -757,8 +774,8 @@
 	bool
 
 config PCI
-	bool "PCI support" if 40x || CPM2 || PPC_83xx || 85xx || PPC_MPC52xx || (EMBEDDED && PPC_ISERIES)
-	default y if !40x && !CPM2 && !8xx && !APUS && !PPC_83xx && !85xx
+	bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_MPC52xx || (EMBEDDED && PPC_ISERIES)
+	default y if !40x && !CPM2 && !8xx && !APUS && !PPC_83xx && !PPC_85xx
 	default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && APUS
 	default PCI_QSPAN if !4xx && !CPM2 && 8xx
 	help
diff -urN oldtree/arch/powerpc/boot/install.sh newtree/arch/powerpc/boot/install.sh
--- oldtree/arch/powerpc/boot/install.sh	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/boot/install.sh	2006-02-21 15:58:17.098547184 +0000
@@ -1,7 +1,5 @@
 #!/bin/sh
 #
-# arch/ppc64/boot/install.sh
-#
 # This file is subject to the terms and conditions of the GNU General Public
 # License.  See the file "COPYING" in the main directory of this archive
 # for more details.
diff -urN oldtree/arch/powerpc/boot/main.c newtree/arch/powerpc/boot/main.c
--- oldtree/arch/powerpc/boot/main.c	2006-02-19 11:40:59.153471792 +0000
+++ newtree/arch/powerpc/boot/main.c	2006-02-21 15:58:17.108545664 +0000
@@ -152,7 +152,7 @@
 	elf64ph = (Elf64_Phdr *)((unsigned long)elf64 +
 				 (unsigned long)elf64->e_phoff);
 	for (i = 0; i < (unsigned int)elf64->e_phnum; i++, elf64ph++)
-		if (elf64ph->p_type == PT_LOAD && elf64ph->p_offset != 0)
+		if (elf64ph->p_type == PT_LOAD)
 			break;
 	if (i >= (unsigned int)elf64->e_phnum)
 		return 0;
@@ -193,7 +193,7 @@
 	elf32 = (Elf32_Ehdr *)elfheader;
 	elf32ph = (Elf32_Phdr *) ((unsigned long)elf32 + elf32->e_phoff);
 	for (i = 0; i < elf32->e_phnum; i++, elf32ph++)
-		if (elf32ph->p_type == PT_LOAD && elf32ph->p_offset != 0)
+		if (elf32ph->p_type == PT_LOAD)
 			break;
 	if (i >= elf32->e_phnum)
 		return 0;
diff -urN oldtree/arch/powerpc/configs/mpc8540_ads_defconfig newtree/arch/powerpc/configs/mpc8540_ads_defconfig
--- oldtree/arch/powerpc/configs/mpc8540_ads_defconfig	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/powerpc/configs/mpc8540_ads_defconfig	2006-02-21 15:58:17.109545512 +0000
@@ -0,0 +1,721 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 
+# Sat Jan 14 15:57:54 2006
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_52xx is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+CONFIG_PPC_85xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_85xx=y
+CONFIG_E500=y
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_MPIC=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Platform support
+#
+CONFIG_MPC8540_ADS=y
+CONFIG_MPC8540=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+CONFIG_MATH_EMULATION=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+# CONFIG_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+
+#
+# SN Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUGGER is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG_LPAR is not set
+# CONFIG_PPC_EARLY_DEBUG_G5 is not set
+# CONFIG_PPC_EARLY_DEBUG_RTAS is not set
+# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set
+# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
diff -urN oldtree/arch/powerpc/kernel/cputable.c newtree/arch/powerpc/kernel/cputable.c
--- oldtree/arch/powerpc/kernel/cputable.c	2006-02-19 11:40:59.169469360 +0000
+++ newtree/arch/powerpc/kernel/cputable.c	2006-02-21 15:58:17.123543384 +0000
@@ -891,7 +891,7 @@
 		.platform		= "ppc405",
 	},
 	{	/* Xilinx Virtex-II Pro  */
-		.pvr_mask		= 0xffff0000,
+		.pvr_mask		= 0xfffff000,
 		.pvr_value		= 0x20010000,
 		.cpu_name		= "Virtex-II Pro",
 		.cpu_features		= CPU_FTRS_40X,
@@ -901,6 +901,16 @@
 		.dcache_bsize		= 32,
 		.platform		= "ppc405",
 	},
+	{	/* Xilinx Virtex-4 FX */
+		.pvr_mask		= 0xfffff000,
+		.pvr_value		= 0x20011000,
+		.cpu_name		= "Virtex-4 FX",
+		.cpu_features		= CPU_FTRS_40X,
+		.cpu_user_features	= PPC_FEATURE_32 |
+			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+		.icache_bsize		= 32,
+		.dcache_bsize		= 32,
+	},
 	{	/* 405EP */
 		.pvr_mask		= 0xffff0000,
 		.pvr_value		= 0x51210000,
diff -urN oldtree/arch/powerpc/kernel/entry_64.S newtree/arch/powerpc/kernel/entry_64.S
--- oldtree/arch/powerpc/kernel/entry_64.S	2006-02-19 11:40:59.172468904 +0000
+++ newtree/arch/powerpc/kernel/entry_64.S	2006-02-21 15:58:17.124543232 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc64/kernel/entry.S
- *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
@@ -374,7 +372,7 @@
  * the fork code also.
  *
  * The code which creates the new task context is in 'copy_thread'
- * in arch/ppc64/kernel/process.c
+ * in arch/powerpc/kernel/process.c 
  */
 	.align	7
 _GLOBAL(_switch)
diff -urN oldtree/arch/powerpc/kernel/firmware.c newtree/arch/powerpc/kernel/firmware.c
--- oldtree/arch/powerpc/kernel/firmware.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/kernel/firmware.c	2006-02-21 15:58:17.124543232 +0000
@@ -18,28 +18,3 @@
 #include <asm/firmware.h>
 
 unsigned long ppc64_firmware_features;
-
-#ifdef CONFIG_PPC_PSERIES
-firmware_feature_t firmware_features_table[FIRMWARE_MAX_FEATURES] = {
-	{FW_FEATURE_PFT,		"hcall-pft"},
-	{FW_FEATURE_TCE,		"hcall-tce"},
-	{FW_FEATURE_SPRG0,		"hcall-sprg0"},
-	{FW_FEATURE_DABR,		"hcall-dabr"},
-	{FW_FEATURE_COPY,		"hcall-copy"},
-	{FW_FEATURE_ASR,		"hcall-asr"},
-	{FW_FEATURE_DEBUG,		"hcall-debug"},
-	{FW_FEATURE_PERF,		"hcall-perf"},
-	{FW_FEATURE_DUMP,		"hcall-dump"},
-	{FW_FEATURE_INTERRUPT,		"hcall-interrupt"},
-	{FW_FEATURE_MIGRATE,		"hcall-migrate"},
-	{FW_FEATURE_PERFMON,		"hcall-perfmon"},
-	{FW_FEATURE_CRQ,		"hcall-crq"},
-	{FW_FEATURE_VIO,		"hcall-vio"},
-	{FW_FEATURE_RDMA,		"hcall-rdma"},
-	{FW_FEATURE_LLAN,		"hcall-lLAN"},
-	{FW_FEATURE_BULK,		"hcall-bulk"},
-	{FW_FEATURE_XDABR,		"hcall-xdabr"},
-	{FW_FEATURE_MULTITCE,		"hcall-multi-tce"},
-	{FW_FEATURE_SPLPAR,		"hcall-splpar"},
-};
-#endif
diff -urN oldtree/arch/powerpc/kernel/head_44x.S newtree/arch/powerpc/kernel/head_44x.S
--- oldtree/arch/powerpc/kernel/head_44x.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/kernel/head_44x.S	2006-02-21 15:58:17.127542776 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/kernel/head_44x.S
- *
  * Kernel execution entry point code.
  *
  *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
diff -urN oldtree/arch/powerpc/kernel/head_64.S newtree/arch/powerpc/kernel/head_64.S
--- oldtree/arch/powerpc/kernel/head_64.S	2006-02-19 11:40:59.175468448 +0000
+++ newtree/arch/powerpc/kernel/head_64.S	2006-02-21 15:58:17.130542320 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc64/kernel/head.S
- *
  *  PowerPC version
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *
diff -urN oldtree/arch/powerpc/kernel/head_8xx.S newtree/arch/powerpc/kernel/head_8xx.S
--- oldtree/arch/powerpc/kernel/head_8xx.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/kernel/head_8xx.S	2006-02-21 15:58:17.130542320 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/kernel/except_8xx.S
- *
  *  PowerPC version
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
diff -urN oldtree/arch/powerpc/kernel/head_booke.h newtree/arch/powerpc/kernel/head_booke.h
--- oldtree/arch/powerpc/kernel/head_booke.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/powerpc/kernel/head_booke.h	2006-02-21 15:58:17.132542016 +0000
@@ -0,0 +1,363 @@
+#ifndef __HEAD_BOOKE_H__
+#define __HEAD_BOOKE_H__
+
+/*
+ * Macros used for common Book-e exception handling
+ */
+
+#define SET_IVOR(vector_number, vector_label)		\
+		li	r26,vector_label@l; 		\
+		mtspr	SPRN_IVOR##vector_number,r26;	\
+		sync
+
+#define NORMAL_EXCEPTION_PROLOG						     \
+	mtspr	SPRN_SPRG0,r10;		/* save two registers to work with */\
+	mtspr	SPRN_SPRG1,r11;						     \
+	mtspr	SPRN_SPRG4W,r1;						     \
+	mfcr	r10;			/* save CR in r10 for now	   */\
+	mfspr	r11,SPRN_SRR1;		/* check whether user or kernel    */\
+	andi.	r11,r11,MSR_PR;						     \
+	beq	1f;							     \
+	mfspr	r1,SPRN_SPRG3;		/* if from user, start at top of   */\
+	lwz	r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack   */\
+	addi	r1,r1,THREAD_SIZE;					     \
+1:	subi	r1,r1,INT_FRAME_SIZE;	/* Allocate an exception frame     */\
+	mr	r11,r1;							     \
+	stw	r10,_CCR(r11);          /* save various registers	   */\
+	stw	r12,GPR12(r11);						     \
+	stw	r9,GPR9(r11);						     \
+	mfspr	r10,SPRN_SPRG0;						     \
+	stw	r10,GPR10(r11);						     \
+	mfspr	r12,SPRN_SPRG1;						     \
+	stw	r12,GPR11(r11);						     \
+	mflr	r10;							     \
+	stw	r10,_LINK(r11);						     \
+	mfspr	r10,SPRN_SPRG4R;					     \
+	mfspr	r12,SPRN_SRR0;						     \
+	stw	r10,GPR1(r11);						     \
+	mfspr	r9,SPRN_SRR1;						     \
+	stw	r10,0(r11);						     \
+	rlwinm	r9,r9,0,14,12;		/* clear MSR_WE (necessary?)	   */\
+	stw	r0,GPR0(r11);						     \
+	SAVE_4GPRS(3, r11);						     \
+	SAVE_2GPRS(7, r11)
+
+/* To handle the additional exception priority levels on 40x and Book-E
+ * processors we allocate a 4k stack per additional priority level. The various
+ * head_xxx.S files allocate space (exception_stack_top) for each priority's
+ * stack times the number of CPUs
+ *
+ * On 40x critical is the only additional level
+ * On 44x/e500 we have critical and machine check
+ * On e200 we have critical and debug (machine check occurs via critical)
+ *
+ * Additionally we reserve a SPRG for each priority level so we can free up a
+ * GPR to use as the base for indirect access to the exception stacks.  This
+ * is necessary since the MMU is always on, for Book-E parts, and the stacks
+ * are offset from KERNELBASE.
+ *
+ */
+#define BOOKE_EXCEPTION_STACK_SIZE	(8192)
+
+/* CRIT_SPRG only used in critical exception handling */
+#define CRIT_SPRG	SPRN_SPRG2
+/* MCHECK_SPRG only used in machine check exception handling */
+#define MCHECK_SPRG	SPRN_SPRG6W
+
+#define MCHECK_STACK_TOP	(exception_stack_top - 4096)
+#define CRIT_STACK_TOP		(exception_stack_top)
+
+/* only on e200 for now */
+#define DEBUG_STACK_TOP		(exception_stack_top - 4096)
+#define DEBUG_SPRG		SPRN_SPRG6W
+
+#ifdef CONFIG_SMP
+#define BOOKE_LOAD_EXC_LEVEL_STACK(level)		\
+	mfspr	r8,SPRN_PIR;				\
+	mulli	r8,r8,BOOKE_EXCEPTION_STACK_SIZE;	\
+	neg	r8,r8;					\
+	addis	r8,r8,level##_STACK_TOP@ha;		\
+	addi	r8,r8,level##_STACK_TOP@l
+#else
+#define BOOKE_LOAD_EXC_LEVEL_STACK(level)		\
+	lis	r8,level##_STACK_TOP@h;			\
+	ori	r8,r8,level##_STACK_TOP@l
+#endif
+
+/*
+ * Exception prolog for critical/machine check exceptions.  This is a
+ * little different from the normal exception prolog above since a
+ * critical/machine check exception can potentially occur at any point
+ * during normal exception processing. Thus we cannot use the same SPRG
+ * registers as the normal prolog above. Instead we use a portion of the
+ * critical/machine check exception stack at low physical addresses.
+ */
+#define EXC_LEVEL_EXCEPTION_PROLOG(exc_level, exc_level_srr0, exc_level_srr1) \
+	mtspr	exc_level##_SPRG,r8;					     \
+	BOOKE_LOAD_EXC_LEVEL_STACK(exc_level);/* r8 points to the exc_level stack*/ \
+	stw	r10,GPR10-INT_FRAME_SIZE(r8);				     \
+	stw	r11,GPR11-INT_FRAME_SIZE(r8);				     \
+	mfcr	r10;			/* save CR in r10 for now	   */\
+	mfspr	r11,exc_level_srr1;	/* check whether user or kernel    */\
+	andi.	r11,r11,MSR_PR;						     \
+	mr	r11,r8;							     \
+	mfspr	r8,exc_level##_SPRG;					     \
+	beq	1f;							     \
+	/* COMING FROM USER MODE */					     \
+	mfspr	r11,SPRN_SPRG3;		/* if from user, start at top of   */\
+	lwz	r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
+	addi	r11,r11,THREAD_SIZE;					     \
+1:	subi	r11,r11,INT_FRAME_SIZE;	/* Allocate an exception frame     */\
+	stw	r10,_CCR(r11);          /* save various registers	   */\
+	stw	r12,GPR12(r11);						     \
+	stw	r9,GPR9(r11);						     \
+	mflr	r10;							     \
+	stw	r10,_LINK(r11);						     \
+	mfspr	r12,SPRN_DEAR;		/* save DEAR and ESR in the frame  */\
+	stw	r12,_DEAR(r11);		/* since they may have had stuff   */\
+	mfspr	r9,SPRN_ESR;		/* in them at the point where the  */\
+	stw	r9,_ESR(r11);		/* exception was taken		   */\
+	mfspr	r12,exc_level_srr0;					     \
+	stw	r1,GPR1(r11);						     \
+	mfspr	r9,exc_level_srr1;					     \
+	stw	r1,0(r11);						     \
+	mr	r1,r11;							     \
+	rlwinm	r9,r9,0,14,12;		/* clear MSR_WE (necessary?)	   */\
+	stw	r0,GPR0(r11);						     \
+	SAVE_4GPRS(3, r11);						     \
+	SAVE_2GPRS(7, r11)
+
+#define CRITICAL_EXCEPTION_PROLOG \
+		EXC_LEVEL_EXCEPTION_PROLOG(CRIT, SPRN_CSRR0, SPRN_CSRR1)
+#define DEBUG_EXCEPTION_PROLOG \
+		EXC_LEVEL_EXCEPTION_PROLOG(DEBUG, SPRN_DSRR0, SPRN_DSRR1)
+#define MCHECK_EXCEPTION_PROLOG \
+		EXC_LEVEL_EXCEPTION_PROLOG(MCHECK, SPRN_MCSRR0, SPRN_MCSRR1)
+
+/*
+ * Exception vectors.
+ */
+#define	START_EXCEPTION(label)						     \
+        .align 5;              						     \
+label:
+
+#define FINISH_EXCEPTION(func)					\
+	bl	transfer_to_handler_full;			\
+	.long	func;						\
+	.long	ret_from_except_full
+
+#define EXCEPTION(n, label, hdlr, xfer)				\
+	START_EXCEPTION(label);					\
+	NORMAL_EXCEPTION_PROLOG;				\
+	addi	r3,r1,STACK_FRAME_OVERHEAD;			\
+	xfer(n, hdlr)
+
+#define CRITICAL_EXCEPTION(n, label, hdlr)			\
+	START_EXCEPTION(label);					\
+	CRITICAL_EXCEPTION_PROLOG;				\
+	addi	r3,r1,STACK_FRAME_OVERHEAD;			\
+	EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
+			  NOCOPY, crit_transfer_to_handler, \
+			  ret_from_crit_exc)
+
+#define MCHECK_EXCEPTION(n, label, hdlr)			\
+	START_EXCEPTION(label);					\
+	MCHECK_EXCEPTION_PROLOG;				\
+	mfspr	r5,SPRN_ESR;					\
+	stw	r5,_ESR(r11);					\
+	addi	r3,r1,STACK_FRAME_OVERHEAD;			\
+	EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
+			  NOCOPY, mcheck_transfer_to_handler,   \
+			  ret_from_mcheck_exc)
+
+#define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret)	\
+	li	r10,trap;					\
+	stw	r10,_TRAP(r11);					\
+	lis	r10,msr@h;					\
+	ori	r10,r10,msr@l;					\
+	copyee(r10, r9);					\
+	bl	tfer;		 				\
+	.long	hdlr;						\
+	.long	ret
+
+#define COPY_EE(d, s)		rlwimi d,s,0,16,16
+#define NOCOPY(d, s)
+
+#define EXC_XFER_STD(n, hdlr)		\
+	EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \
+			  ret_from_except_full)
+
+#define EXC_XFER_LITE(n, hdlr)		\
+	EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \
+			  ret_from_except)
+
+#define EXC_XFER_EE(n, hdlr)		\
+	EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \
+			  ret_from_except_full)
+
+#define EXC_XFER_EE_LITE(n, hdlr)	\
+	EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \
+			  ret_from_except)
+
+/* Check for a single step debug exception while in an exception
+ * handler before state has been saved.  This is to catch the case
+ * where an instruction that we are trying to single step causes
+ * an exception (eg ITLB/DTLB miss) and thus the first instruction of
+ * the exception handler generates a single step debug exception.
+ *
+ * If we get a debug trap on the first instruction of an exception handler,
+ * we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is
+ * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR).
+ * The exception handler was handling a non-critical interrupt, so it will
+ * save (and later restore) the MSR via SPRN_CSRR1, which will still have
+ * the MSR_DE bit set.
+ */
+#ifdef CONFIG_E200
+#define DEBUG_EXCEPTION							      \
+	START_EXCEPTION(Debug);						      \
+	DEBUG_EXCEPTION_PROLOG;						      \
+									      \
+	/*								      \
+	 * If there is a single step or branch-taken exception in an	      \
+	 * exception entry sequence, it was probably meant to apply to	      \
+	 * the code where the exception occurred (since exception entry	      \
+	 * doesn't turn off DE automatically).  We simulate the effect	      \
+	 * of turning off DE on entry to an exception handler by turning      \
+	 * off DE in the CSRR1 value and clearing the debug status.	      \
+	 */								      \
+	mfspr	r10,SPRN_DBSR;		/* check single-step/branch taken */  \
+	andis.	r10,r10,DBSR_IC@h;					      \
+	beq+	2f;							      \
+									      \
+	lis	r10,KERNELBASE@h;	/* check if exception in vectors */   \
+	ori	r10,r10,KERNELBASE@l;					      \
+	cmplw	r12,r10;						      \
+	blt+	2f;			/* addr below exception vectors */    \
+									      \
+	lis	r10,Debug@h;						      \
+	ori	r10,r10,Debug@l;					      \
+	cmplw	r12,r10;						      \
+	bgt+	2f;			/* addr above exception vectors */    \
+									      \
+	/* here it looks like we got an inappropriate debug exception. */     \
+1:	rlwinm	r9,r9,0,~MSR_DE;	/* clear DE in the CDRR1 value */     \
+	lis	r10,DBSR_IC@h;		/* clear the IC event */	      \
+	mtspr	SPRN_DBSR,r10;						      \
+	/* restore state and get out */					      \
+	lwz	r10,_CCR(r11);						      \
+	lwz	r0,GPR0(r11);						      \
+	lwz	r1,GPR1(r11);						      \
+	mtcrf	0x80,r10;						      \
+	mtspr	SPRN_DSRR0,r12;						      \
+	mtspr	SPRN_DSRR1,r9;						      \
+	lwz	r9,GPR9(r11);						      \
+	lwz	r12,GPR12(r11);						      \
+	mtspr	DEBUG_SPRG,r8;						      \
+	BOOKE_LOAD_EXC_LEVEL_STACK(DEBUG); /* r8 points to the debug stack */ \
+	lwz	r10,GPR10-INT_FRAME_SIZE(r8);				      \
+	lwz	r11,GPR11-INT_FRAME_SIZE(r8);				      \
+	mfspr	r8,DEBUG_SPRG;						      \
+									      \
+	RFDI;								      \
+	b	.;							      \
+									      \
+	/* continue normal handling for a critical exception... */	      \
+2:	mfspr	r4,SPRN_DBSR;						      \
+	addi	r3,r1,STACK_FRAME_OVERHEAD;				      \
+	EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, debug_transfer_to_handler, ret_from_debug_exc)
+#else
+#define DEBUG_EXCEPTION							      \
+	START_EXCEPTION(Debug);						      \
+	CRITICAL_EXCEPTION_PROLOG;					      \
+									      \
+	/*								      \
+	 * If there is a single step or branch-taken exception in an	      \
+	 * exception entry sequence, it was probably meant to apply to	      \
+	 * the code where the exception occurred (since exception entry	      \
+	 * doesn't turn off DE automatically).  We simulate the effect	      \
+	 * of turning off DE on entry to an exception handler by turning      \
+	 * off DE in the CSRR1 value and clearing the debug status.	      \
+	 */								      \
+	mfspr	r10,SPRN_DBSR;		/* check single-step/branch taken */  \
+	andis.	r10,r10,DBSR_IC@h;					      \
+	beq+	2f;							      \
+									      \
+	lis	r10,KERNELBASE@h;	/* check if exception in vectors */   \
+	ori	r10,r10,KERNELBASE@l;					      \
+	cmplw	r12,r10;						      \
+	blt+	2f;			/* addr below exception vectors */    \
+									      \
+	lis	r10,Debug@h;						      \
+	ori	r10,r10,Debug@l;					      \
+	cmplw	r12,r10;						      \
+	bgt+	2f;			/* addr above exception vectors */    \
+									      \
+	/* here it looks like we got an inappropriate debug exception. */     \
+1:	rlwinm	r9,r9,0,~MSR_DE;	/* clear DE in the CSRR1 value */     \
+	lis	r10,DBSR_IC@h;		/* clear the IC event */	      \
+	mtspr	SPRN_DBSR,r10;						      \
+	/* restore state and get out */					      \
+	lwz	r10,_CCR(r11);						      \
+	lwz	r0,GPR0(r11);						      \
+	lwz	r1,GPR1(r11);						      \
+	mtcrf	0x80,r10;						      \
+	mtspr	SPRN_CSRR0,r12;						      \
+	mtspr	SPRN_CSRR1,r9;						      \
+	lwz	r9,GPR9(r11);						      \
+	lwz	r12,GPR12(r11);						      \
+	mtspr	CRIT_SPRG,r8;						      \
+	BOOKE_LOAD_EXC_LEVEL_STACK(CRIT); /* r8 points to the debug stack */  \
+	lwz	r10,GPR10-INT_FRAME_SIZE(r8);				      \
+	lwz	r11,GPR11-INT_FRAME_SIZE(r8);				      \
+	mfspr	r8,CRIT_SPRG;						      \
+									      \
+	rfci;								      \
+	b	.;							      \
+									      \
+	/* continue normal handling for a critical exception... */	      \
+2:	mfspr	r4,SPRN_DBSR;						      \
+	addi	r3,r1,STACK_FRAME_OVERHEAD;				      \
+	EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)
+#endif
+
+#define INSTRUCTION_STORAGE_EXCEPTION					      \
+	START_EXCEPTION(InstructionStorage)				      \
+	NORMAL_EXCEPTION_PROLOG;					      \
+	mfspr	r5,SPRN_ESR;		/* Grab the ESR and save it */	      \
+	stw	r5,_ESR(r11);						      \
+	mr      r4,r12;                 /* Pass SRR0 as arg2 */		      \
+	li      r5,0;                   /* Pass zero as arg3 */		      \
+	EXC_XFER_EE_LITE(0x0400, handle_page_fault)
+
+#define ALIGNMENT_EXCEPTION						      \
+	START_EXCEPTION(Alignment)					      \
+	NORMAL_EXCEPTION_PROLOG;					      \
+	mfspr   r4,SPRN_DEAR;           /* Grab the DEAR and save it */	      \
+	stw     r4,_DEAR(r11);						      \
+	addi    r3,r1,STACK_FRAME_OVERHEAD;				      \
+	EXC_XFER_EE(0x0600, alignment_exception)
+
+#define PROGRAM_EXCEPTION						      \
+	START_EXCEPTION(Program)					      \
+	NORMAL_EXCEPTION_PROLOG;					      \
+	mfspr	r4,SPRN_ESR;		/* Grab the ESR and save it */	      \
+	stw	r4,_ESR(r11);						      \
+	addi	r3,r1,STACK_FRAME_OVERHEAD;				      \
+	EXC_XFER_STD(0x0700, program_check_exception)
+
+#define DECREMENTER_EXCEPTION						      \
+	START_EXCEPTION(Decrementer)					      \
+	NORMAL_EXCEPTION_PROLOG;					      \
+	lis     r0,TSR_DIS@h;           /* Setup the DEC interrupt mask */    \
+	mtspr   SPRN_TSR,r0;		/* Clear the DEC interrupt */	      \
+	addi    r3,r1,STACK_FRAME_OVERHEAD;				      \
+	EXC_XFER_LITE(0x0900, timer_interrupt)
+
+#define FP_UNAVAILABLE_EXCEPTION					      \
+	START_EXCEPTION(FloatingPointUnavailable)			      \
+	NORMAL_EXCEPTION_PROLOG;					      \
+	bne	load_up_fpu;		/* if from user, just load it up */   \
+	addi	r3,r1,STACK_FRAME_OVERHEAD;				      \
+	EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception)
+
+#endif /* __HEAD_BOOKE_H__ */
diff -urN oldtree/arch/powerpc/kernel/head_fsl_booke.S newtree/arch/powerpc/kernel/head_fsl_booke.S
--- oldtree/arch/powerpc/kernel/head_fsl_booke.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/kernel/head_fsl_booke.S	2006-02-21 15:58:17.133541864 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/kernel/head_fsl_booke.S
- *
  * Kernel execution entry point code.
  *
  *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
@@ -316,6 +314,7 @@
 	 */
 	lis	r2,DBCR0_IDM@h
 	mtspr	SPRN_DBCR0,r2
+	isync
 	/* clear any residual debug events */
 	li	r2,-1
 	mtspr	SPRN_DBSR,r2
@@ -1002,12 +1001,15 @@
 _GLOBAL(abort)
 	li	r13,0
         mtspr   SPRN_DBCR0,r13		/* disable all debug events */
+	isync
 	mfmsr	r13
 	ori	r13,r13,MSR_DE@l	/* Enable Debug Events */
 	mtmsr	r13
+	isync
         mfspr   r13,SPRN_DBCR0
         lis	r13,(DBCR0_IDM|DBCR0_RST_CHIP)@h
         mtspr   SPRN_DBCR0,r13
+	isync
 
 _GLOBAL(set_context)
 
diff -urN oldtree/arch/powerpc/kernel/iomap.c newtree/arch/powerpc/kernel/iomap.c
--- oldtree/arch/powerpc/kernel/iomap.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/kernel/iomap.c	2006-02-21 15:58:17.133541864 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc64/kernel/iomap.c
- *
  * ppc64 "iomap" interface implementation.
  *
  * (C) Copyright 2004 Linus Torvalds
diff -urN oldtree/arch/powerpc/kernel/iommu.c newtree/arch/powerpc/kernel/iommu.c
--- oldtree/arch/powerpc/kernel/iommu.c	2006-02-19 11:40:59.177468144 +0000
+++ newtree/arch/powerpc/kernel/iommu.c	2006-02-21 15:58:17.134541712 +0000
@@ -1,5 +1,4 @@
 /*
- * arch/ppc64/kernel/iommu.c
  * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation
  * 
  * Rewrite, cleanup, new allocation schemes, virtual merging: 
diff -urN oldtree/arch/powerpc/kernel/irq.c newtree/arch/powerpc/kernel/irq.c
--- oldtree/arch/powerpc/kernel/irq.c	2006-02-19 11:40:59.178467992 +0000
+++ newtree/arch/powerpc/kernel/irq.c	2006-02-21 15:58:17.134541712 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/kernel/irq.c
- *
  *  Derived from arch/i386/kernel/irq.c
  *    Copyright (C) 1992 Linus Torvalds
  *  Adapted from arch/i386 by Gary Thomas
diff -urN oldtree/arch/powerpc/kernel/kprobes.c newtree/arch/powerpc/kernel/kprobes.c
--- oldtree/arch/powerpc/kernel/kprobes.c	2006-02-19 11:40:59.179467840 +0000
+++ newtree/arch/powerpc/kernel/kprobes.c	2006-02-21 15:58:26.031189216 +0000
@@ -1,6 +1,5 @@
 /*
  *  Kernel Probes (KProbes)
- *  arch/ppc64/kernel/kprobes.c
  *
  * 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
@@ -82,9 +81,9 @@
 
 void __kprobes arch_remove_kprobe(struct kprobe *p)
 {
-	down(&kprobe_mutex);
+	mutex_lock(&kprobe_mutex);
 	free_insn_slot(p->ainsn.insn);
-	up(&kprobe_mutex);
+	mutex_unlock(&kprobe_mutex);
 }
 
 static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
diff -urN oldtree/arch/powerpc/kernel/legacy_serial.c newtree/arch/powerpc/kernel/legacy_serial.c
--- oldtree/arch/powerpc/kernel/legacy_serial.c	2006-02-19 11:40:59.180467688 +0000
+++ newtree/arch/powerpc/kernel/legacy_serial.c	2006-02-21 15:58:36.214641096 +0000
@@ -37,7 +37,7 @@
 static int __init add_legacy_port(struct device_node *np, int want_index,
 				  int iotype, phys_addr_t base,
 				  phys_addr_t taddr, unsigned long irq,
-				  unsigned int flags)
+				  upf_t flags)
 {
 	u32 *clk, *spd, clock = BASE_BAUD * 16;
 	int index;
@@ -113,7 +113,7 @@
 {
 	phys_addr_t addr;
 	u32 *addrp;
-	unsigned int flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
+	upf_t flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
 
 	/* We only support ports that have a clock frequency properly
 	 * encoded in the device-tree.
diff -urN oldtree/arch/powerpc/kernel/pci_iommu.c newtree/arch/powerpc/kernel/pci_iommu.c
--- oldtree/arch/powerpc/kernel/pci_iommu.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/kernel/pci_iommu.c	2006-02-21 15:58:17.137541256 +0000
@@ -1,5 +1,4 @@
 /*
- * arch/ppc64/kernel/pci_iommu.c
  * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation
  *
  * Rewrite, cleanup, new allocation schemes:
diff -urN oldtree/arch/powerpc/kernel/ppc_ksyms.c newtree/arch/powerpc/kernel/ppc_ksyms.c
--- oldtree/arch/powerpc/kernel/ppc_ksyms.c	2006-02-19 11:40:59.231459936 +0000
+++ newtree/arch/powerpc/kernel/ppc_ksyms.c	2006-02-21 15:58:17.138541104 +0000
@@ -57,7 +57,6 @@
 extern void alignment_exception(struct pt_regs *regs);
 extern void program_check_exception(struct pt_regs *regs);
 extern void single_step_exception(struct pt_regs *regs);
-extern int pmac_newworld;
 extern int sys_sigreturn(struct pt_regs *regs);
 
 EXPORT_SYMBOL(clear_pages);
diff -urN oldtree/arch/powerpc/kernel/process.c newtree/arch/powerpc/kernel/process.c
--- oldtree/arch/powerpc/kernel/process.c	2006-02-19 11:40:59.232459784 +0000
+++ newtree/arch/powerpc/kernel/process.c	2006-02-21 15:58:17.139540952 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/kernel/process.c
- *
  *  Derived from "arch/i386/kernel/process.c"
  *    Copyright (C) 1995  Linus Torvalds
  *
diff -urN oldtree/arch/powerpc/kernel/prom.c newtree/arch/powerpc/kernel/prom.c
--- oldtree/arch/powerpc/kernel/prom.c	2006-02-19 11:40:59.234459480 +0000
+++ newtree/arch/powerpc/kernel/prom.c	2006-02-21 15:58:17.140540800 +0000
@@ -831,10 +831,6 @@
 
 	/* Allocate memory for the expanded device tree */
 	mem = lmb_alloc(size + 4, __alignof__(struct device_node));
-	if (!mem) {
-		DBG("Couldn't allocate memory with lmb_alloc()!\n");
-		panic("Couldn't allocate memory with lmb_alloc()!\n");
-	}
 	mem = (unsigned long) __va(mem);
 
 	((u32 *)mem)[size / 4] = 0xdeadbeef;
diff -urN oldtree/arch/powerpc/kernel/ptrace-common.h newtree/arch/powerpc/kernel/ptrace-common.h
--- oldtree/arch/powerpc/kernel/ptrace-common.h	2006-02-19 11:40:59.237459024 +0000
+++ newtree/arch/powerpc/kernel/ptrace-common.h	2006-02-21 15:58:17.149539432 +0000
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/ppc64/kernel/ptrace-common.h
- *
  *    Copyright (c) 2002 Stephen Rothwell, IBM Coproration
  *    Extracted from ptrace.c and ptrace32.c
  *
diff -urN oldtree/arch/powerpc/kernel/rtas-proc.c newtree/arch/powerpc/kernel/rtas-proc.c
--- oldtree/arch/powerpc/kernel/rtas-proc.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/kernel/rtas-proc.c	2006-02-21 15:58:17.150539280 +0000
@@ -1,5 +1,4 @@
 /*
- *   arch/ppc64/kernel/rtas-proc.c
  *   Copyright (C) 2000 Tilmann Bitterberg
  *   (tilmann@bitterberg.de)
  *
diff -urN oldtree/arch/powerpc/kernel/rtas_pci.c newtree/arch/powerpc/kernel/rtas_pci.c
--- oldtree/arch/powerpc/kernel/rtas_pci.c	2006-02-19 11:40:59.239458720 +0000
+++ newtree/arch/powerpc/kernel/rtas_pci.c	2006-02-21 15:58:17.149539432 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc64/kernel/rtas_pci.c
- *
  * Copyright (C) 2001 Dave Engebretsen, IBM Corporation
  * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
  *
diff -urN oldtree/arch/powerpc/kernel/signal_64.c newtree/arch/powerpc/kernel/signal_64.c
--- oldtree/arch/powerpc/kernel/signal_64.c	2006-02-19 11:40:59.244457960 +0000
+++ newtree/arch/powerpc/kernel/signal_64.c	2006-02-21 15:58:17.151539128 +0000
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/ppc64/kernel/signal.c
- *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *
diff -urN oldtree/arch/powerpc/kernel/vdso.c newtree/arch/powerpc/kernel/vdso.c
--- oldtree/arch/powerpc/kernel/vdso.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/kernel/vdso.c	2006-02-21 15:58:17.152538976 +0000
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/ppc64/kernel/vdso.c
- *
  *    Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp.
  *			 <benh@kernel.crashing.org>
  *
diff -urN oldtree/arch/powerpc/lib/copypage_64.S newtree/arch/powerpc/lib/copypage_64.S
--- oldtree/arch/powerpc/lib/copypage_64.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/lib/copypage_64.S	2006-02-21 15:58:17.152538976 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc64/lib/copypage.S
- *
  * Copyright (C) 2002 Paul Mackerras, IBM Corp.
  *
  * This program is free software; you can redistribute it and/or
diff -urN oldtree/arch/powerpc/lib/copyuser_64.S newtree/arch/powerpc/lib/copyuser_64.S
--- oldtree/arch/powerpc/lib/copyuser_64.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/lib/copyuser_64.S	2006-02-21 15:58:17.152538976 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc64/lib/copyuser.S
- *
  * Copyright (C) 2002 Paul Mackerras, IBM Corp.
  *
  * This program is free software; you can redistribute it and/or
diff -urN oldtree/arch/powerpc/lib/e2a.c newtree/arch/powerpc/lib/e2a.c
--- oldtree/arch/powerpc/lib/e2a.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/lib/e2a.c	2006-02-21 15:58:17.153538824 +0000
@@ -1,9 +1,7 @@
 /*
- *  arch/ppc64/lib/e2a.c
- *
  *  EBCDIC to ASCII conversion
  *
- * This function moved here from arch/ppc64/kernel/viopath.c
+ * This function moved here from arch/powerpc/platforms/iseries/viopath.c 
  *
  * (C) Copyright 2000-2004 IBM Corporation
  *
diff -urN oldtree/arch/powerpc/lib/memcpy_64.S newtree/arch/powerpc/lib/memcpy_64.S
--- oldtree/arch/powerpc/lib/memcpy_64.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/lib/memcpy_64.S	2006-02-21 15:58:17.153538824 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc64/lib/memcpy.S
- *
  * Copyright (C) 2002 Paul Mackerras, IBM Corp.
  *
  * This program is free software; you can redistribute it and/or
diff -urN oldtree/arch/powerpc/lib/rheap.c newtree/arch/powerpc/lib/rheap.c
--- oldtree/arch/powerpc/lib/rheap.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/lib/rheap.c	2006-02-21 15:58:17.154538672 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/rheap.c
- *
  * A Remote Heap.  Remote means that we don't touch the memory that the
  * heap points to. Normal heap implementations use the memory they manage
  * to place their list. We cannot do that because the memory we manage may
diff -urN oldtree/arch/powerpc/mm/fault.c newtree/arch/powerpc/mm/fault.c
--- oldtree/arch/powerpc/mm/fault.c	2006-02-19 11:40:59.252456744 +0000
+++ newtree/arch/powerpc/mm/fault.c	2006-02-21 15:58:17.154538672 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/mm/fault.c
- *
  *  PowerPC version
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *
diff -urN oldtree/arch/powerpc/mm/hash_low_32.S newtree/arch/powerpc/mm/hash_low_32.S
--- oldtree/arch/powerpc/mm/hash_low_32.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/mm/hash_low_32.S	2006-02-21 15:58:17.155538520 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/kernel/hashtable.S
- *
  *  $Id: hashtable.S,v 1.6 1999/10/08 01:56:15 paulus Exp $
  *
  *  PowerPC version
diff -urN oldtree/arch/powerpc/mm/hash_utils_64.c newtree/arch/powerpc/mm/hash_utils_64.c
--- oldtree/arch/powerpc/mm/hash_utils_64.c	2006-02-19 11:40:59.252456744 +0000
+++ newtree/arch/powerpc/mm/hash_utils_64.c	2006-02-21 15:58:17.156538368 +0000
@@ -430,7 +430,6 @@
 		 * the absolute address space.
 		 */
 		table = lmb_alloc(htab_size_bytes, htab_size_bytes);
-		BUG_ON(table == 0);
 
 		DBG("Hash table allocated at %lx, size: %lx\n", table,
 		    htab_size_bytes);
diff -urN oldtree/arch/powerpc/mm/imalloc.c newtree/arch/powerpc/mm/imalloc.c
--- oldtree/arch/powerpc/mm/imalloc.c	2006-02-19 11:40:59.254456440 +0000
+++ newtree/arch/powerpc/mm/imalloc.c	2006-02-21 15:58:24.152474824 +0000
@@ -13,12 +13,12 @@
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/cacheflush.h>
 
 #include "mmu_decl.h"
 
-static DECLARE_MUTEX(imlist_sem);
+static DEFINE_MUTEX(imlist_mutex);
 struct vm_struct * imlist = NULL;
 
 static int get_free_im_addr(unsigned long size, unsigned long *im_addr)
@@ -257,7 +257,7 @@
 	struct vm_struct *area;
 	unsigned long addr;
 	
-	down(&imlist_sem);
+	mutex_lock(&imlist_mutex);
 	if (get_free_im_addr(size, &addr)) {
 		printk(KERN_ERR "%s() cannot obtain addr for size 0x%lx\n",
 				__FUNCTION__, size);
@@ -272,7 +272,7 @@
 			__FUNCTION__, addr, size);
 	}
 next_im_done:
-	up(&imlist_sem);
+	mutex_unlock(&imlist_mutex);
 	return area;
 }
 
@@ -281,9 +281,9 @@
 {
 	struct vm_struct *area;
 
-	down(&imlist_sem);
+	mutex_lock(&imlist_mutex);
 	area = __im_get_area(v_addr, size, criteria);
-	up(&imlist_sem);
+	mutex_unlock(&imlist_mutex);
 	return area;
 }
 
@@ -297,17 +297,17 @@
 		printk(KERN_ERR "Trying to %s bad address (%p)\n", __FUNCTION__,			addr);
 		return;
 	}
-	down(&imlist_sem);
+	mutex_lock(&imlist_mutex);
 	for (p = &imlist ; (tmp = *p) ; p = &tmp->next) {
 		if (tmp->addr == addr) {
 			*p = tmp->next;
 			unmap_vm_area(tmp);
 			kfree(tmp);
-			up(&imlist_sem);
+			mutex_unlock(&imlist_mutex);
 			return;
 		}
 	}
-	up(&imlist_sem);
+	mutex_unlock(&imlist_mutex);
 	printk(KERN_ERR "Trying to %s nonexistent area (%p)\n", __FUNCTION__,
 			addr);
 }
diff -urN oldtree/arch/powerpc/mm/lmb.c newtree/arch/powerpc/mm/lmb.c
--- oldtree/arch/powerpc/mm/lmb.c	2006-02-19 11:40:59.254456440 +0000
+++ newtree/arch/powerpc/mm/lmb.c	2006-02-21 15:58:17.156538368 +0000
@@ -31,6 +31,8 @@
 #define DBG(fmt...)
 #endif
 
+#define LMB_ALLOC_ANYWHERE	0
+
 struct lmb lmb;
 
 void lmb_dump_all(void)
@@ -226,6 +228,20 @@
 unsigned long __init lmb_alloc_base(unsigned long size, unsigned long align,
 				    unsigned long max_addr)
 {
+	unsigned long alloc;
+
+	alloc = __lmb_alloc_base(size, align, max_addr);
+
+	if (alloc < 0)
+		panic("ERROR: Failed to allocate 0x%lx bytes below 0x%lx.\n",
+				size, max_addr);
+
+	return alloc;
+}
+
+unsigned long __init __lmb_alloc_base(unsigned long size, unsigned long align,
+				    unsigned long max_addr)
+{
 	long i, j;
 	unsigned long base = 0;
 
diff -urN oldtree/arch/powerpc/mm/mem.c newtree/arch/powerpc/mm/mem.c
--- oldtree/arch/powerpc/mm/mem.c	2006-02-19 11:40:59.255456288 +0000
+++ newtree/arch/powerpc/mm/mem.c	2006-02-21 15:58:17.165537000 +0000
@@ -249,7 +249,6 @@
 	bootmap_pages = bootmem_bootmap_pages(total_pages);
 
 	start = lmb_alloc(bootmap_pages << PAGE_SHIFT, PAGE_SIZE);
-	BUG_ON(!start);
 
 	boot_mapsize = init_bootmem(start >> PAGE_SHIFT, total_pages);
 
diff -urN oldtree/arch/powerpc/mm/mmap.c newtree/arch/powerpc/mm/mmap.c
--- oldtree/arch/powerpc/mm/mmap.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/mm/mmap.c	2006-02-21 15:58:17.165537000 +0000
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/ppc64/mm/mmap.c
- *
  *  flexible mmap layout support
  *
  * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
diff -urN oldtree/arch/powerpc/mm/numa.c newtree/arch/powerpc/mm/numa.c
--- oldtree/arch/powerpc/mm/numa.c	2006-02-19 11:40:59.256456136 +0000
+++ newtree/arch/powerpc/mm/numa.c	2006-02-21 15:58:17.166536848 +0000
@@ -570,11 +570,11 @@
 				       unsigned long end_pfn)
 {
 	int new_nid;
-	unsigned long ret = lmb_alloc_base(size, align, end_pfn << PAGE_SHIFT);
+	unsigned long ret = __lmb_alloc_base(size, align, end_pfn << PAGE_SHIFT);
 
 	/* retry over all memory */
 	if (!ret)
-		ret = lmb_alloc_base(size, align, lmb_end_of_DRAM());
+		ret = __lmb_alloc_base(size, align, lmb_end_of_DRAM());
 
 	if (!ret)
 		panic("numa.c: cannot allocate %lu bytes on node %d",
diff -urN oldtree/arch/powerpc/mm/slb_low.S newtree/arch/powerpc/mm/slb_low.S
--- oldtree/arch/powerpc/mm/slb_low.S	2006-02-19 11:40:59.257455984 +0000
+++ newtree/arch/powerpc/mm/slb_low.S	2006-02-21 15:58:17.167536696 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc64/mm/slb_low.S
- *
  * Low-level SLB routines
  *
  * Copyright (C) 2004 David Gibson <dwg@au.ibm.com>, IBM
diff -urN oldtree/arch/powerpc/mm/stab.c newtree/arch/powerpc/mm/stab.c
--- oldtree/arch/powerpc/mm/stab.c	2006-02-19 11:40:59.258455832 +0000
+++ newtree/arch/powerpc/mm/stab.c	2006-02-21 15:58:17.168536544 +0000
@@ -247,10 +247,6 @@
 
 		newstab = lmb_alloc_base(HW_PAGE_SIZE, HW_PAGE_SIZE,
 					 1<<SID_SHIFT);
-		if (! newstab)
-			panic("Unable to allocate segment table for CPU %d.\n",
-			      cpu);
-
 		newstab = (unsigned long)__va(newstab);
 
 		memset((void *)newstab, 0, HW_PAGE_SIZE);
diff -urN oldtree/arch/powerpc/mm/tlb_64.c newtree/arch/powerpc/mm/tlb_64.c
--- oldtree/arch/powerpc/mm/tlb_64.c	2006-02-19 11:40:59.258455832 +0000
+++ newtree/arch/powerpc/mm/tlb_64.c	2006-02-21 15:58:17.168536544 +0000
@@ -36,7 +36,7 @@
 DEFINE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch);
 
 /* This is declared as we are using the more or less generic
- * include/asm-ppc64/tlb.h file -- tgall
+ * include/asm-powerpc/tlb.h file -- tgall
  */
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
diff -urN oldtree/arch/powerpc/platforms/83xx/Makefile newtree/arch/powerpc/platforms/83xx/Makefile
--- oldtree/arch/powerpc/platforms/83xx/Makefile	2006-02-19 11:40:59.261455376 +0000
+++ newtree/arch/powerpc/platforms/83xx/Makefile	2006-02-21 15:58:17.169536392 +0000
@@ -1,4 +1,6 @@
 #
 # Makefile for the PowerPC 83xx linux kernel.
 #
-obj-$(CONFIG_MPC834x_SYS)	+= mpc834x_sys.o pci.o
+obj-y				:= misc.o
+obj-$(CONFIG_PCI)		+= pci.o
+obj-$(CONFIG_MPC834x_SYS)	+= mpc834x_sys.o
diff -urN oldtree/arch/powerpc/platforms/83xx/misc.c newtree/arch/powerpc/platforms/83xx/misc.c
--- oldtree/arch/powerpc/platforms/83xx/misc.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/powerpc/platforms/83xx/misc.c	2006-02-21 15:58:17.169536392 +0000
@@ -0,0 +1,55 @@
+/*
+ * misc setup functions for MPC83xx
+ *
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+
+#include <asm/io.h>
+#include <asm/hw_irq.h>
+#include <sysdev/fsl_soc.h>
+
+#include "mpc83xx.h"
+
+void mpc83xx_restart(char *cmd)
+{
+#define RST_OFFSET	0x00000900
+#define RST_PROT_REG	0x00000018
+#define RST_CTRL_REG	0x0000001c
+	__be32 __iomem *reg;
+
+	/* map reset register space */
+	reg = ioremap(get_immrbase() + 0x900, 0xff);
+
+	local_irq_disable();
+
+	/* enable software reset "RSTE" */
+	out_be32(reg + (RST_PROT_REG >> 2), 0x52535445);
+
+	/* set software hard reset */
+	out_be32(reg + (RST_CTRL_REG >> 2), 0x52535445);
+	for (;;) ;
+}
+
+long __init mpc83xx_time_init(void)
+{
+#define SPCR_OFFSET	0x00000110
+#define SPCR_TBEN	0x00400000
+	__be32 __iomem *spcr = ioremap(get_immrbase() + SPCR_OFFSET, 4);
+	__be32 tmp;
+
+	tmp = in_be32(spcr);
+	out_be32(spcr, tmp | SPCR_TBEN);
+
+	iounmap(spcr);
+
+	return 0;
+}
diff -urN oldtree/arch/powerpc/platforms/83xx/mpc834x_sys.c newtree/arch/powerpc/platforms/83xx/mpc834x_sys.c
--- oldtree/arch/powerpc/platforms/83xx/mpc834x_sys.c	2006-02-19 11:40:59.261455376 +0000
+++ newtree/arch/powerpc/platforms/83xx/mpc834x_sys.c	2006-02-21 15:58:17.169536392 +0000
@@ -24,22 +24,15 @@
 #include <linux/delay.h>
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
-#include <linux/module.h>
-#include <linux/fsl_devices.h>
 
 #include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
 #include <asm/atomic.h>
 #include <asm/time.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
 #include <asm/ipic.h>
 #include <asm/bootinfo.h>
-#include <asm/pci-bridge.h>
-#include <asm/mpc83xx.h>
 #include <asm/irq.h>
-#include <mm/mmu_decl.h>
 #include <asm/prom.h>
 #include <asm/udbg.h>
 #include <sysdev/fsl_soc.h>
@@ -52,8 +45,6 @@
 #endif
 
 #ifdef CONFIG_PCI
-extern int mpc83xx_pci2_busno;
-
 static int
 mpc83xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
 {
@@ -78,26 +69,14 @@
 	const long min_idsel = 0x11, max_idsel = 0x20, irqs_per_slot = 4;
 	return PCI_IRQ_TABLE_LOOKUP;
 }
-
-static int
-mpc83xx_exclude_device(u_char bus, u_char devfn)
-{
-	if (bus == 0 && PCI_SLOT(devfn) == 0)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	if (mpc83xx_pci2_busno)
-		if (bus == (mpc83xx_pci2_busno) && PCI_SLOT(devfn) == 0)
-			return PCIBIOS_DEVICE_NOT_FOUND;
-	return PCIBIOS_SUCCESSFUL;
-}
-#endif /* CONFIG_PCI */
+#endif				/* CONFIG_PCI */
 
 /* ************************************************************************
  *
  * Setup the architecture
  *
  */
-static void __init
-mpc834x_sys_setup_arch(void)
+static void __init mpc834x_sys_setup_arch(void)
 {
 	struct device_node *np;
 
@@ -106,14 +85,14 @@
 
 	np = of_find_node_by_type(NULL, "cpu");
 	if (np != 0) {
-		unsigned int *fp = (int *) get_property(np, "clock-frequency", NULL);
+		unsigned int *fp =
+		    (int *)get_property(np, "clock-frequency", NULL);
 		if (fp != 0)
 			loops_per_jiffy = *fp / HZ;
 		else
 			loops_per_jiffy = 50000000 / HZ;
 		of_node_put(np);
 	}
-
 #ifdef CONFIG_PCI
 	for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
 		add_bridge(np);
@@ -124,14 +103,13 @@
 #endif
 
 #ifdef  CONFIG_ROOT_NFS
-		ROOT_DEV = Root_NFS;
+	ROOT_DEV = Root_NFS;
 #else
-		ROOT_DEV = Root_HDA1;
+	ROOT_DEV = Root_HDA1;
 #endif
 }
 
-void __init
-mpc834x_sys_init_IRQ(void)
+void __init mpc834x_sys_init_IRQ(void)
 {
 	u8 senses[8] = {
 		0,			/* EXT 0 */
@@ -160,64 +138,27 @@
 }
 
 #if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374)
-extern ulong	ds1374_get_rtc_time(void);
-extern int	ds1374_set_rtc_time(ulong);
+extern ulong ds1374_get_rtc_time(void);
+extern int ds1374_set_rtc_time(ulong);
 
-static int __init
-mpc834x_rtc_hookup(void)
+static int __init mpc834x_rtc_hookup(void)
 {
-	struct timespec	tv;
+	struct timespec tv;
 
 	ppc_md.get_rtc_time = ds1374_get_rtc_time;
 	ppc_md.set_rtc_time = ds1374_set_rtc_time;
 
 	tv.tv_nsec = 0;
-	tv.tv_sec = (ppc_md.get_rtc_time)();
+	tv.tv_sec = (ppc_md.get_rtc_time) ();
 	do_settimeofday(&tv);
 
 	return 0;
 }
+
 late_initcall(mpc834x_rtc_hookup);
 #endif
 
-static void
-mpc83xx_restart(char *cmd)
-{
-#define RST_OFFSET	0x00000900
-#define RST_PROT_REG	0x00000018
-#define RST_CTRL_REG	0x0000001c
-	__be32 __iomem *reg;
-
-	// map reset register space
-	reg = ioremap(get_immrbase() + 0x900, 0xff);
-
-	local_irq_disable();
-
-	/* enable software reset "RSTE" */
-	out_be32(reg + (RST_PROT_REG >> 2), 0x52535445);
-
-	/* set software hard reset */
-	out_be32(reg + (RST_CTRL_REG >> 2), 0x52535445);
-	for(;;);
-}
-
-static long __init
-mpc83xx_time_init(void)
-{
-#define SPCR_OFFSET	0x00000110
-#define SPCR_TBEN	0x00400000
-	__be32 __iomem *spcr = ioremap(get_immrbase() + SPCR_OFFSET, 4);
-	__be32 tmp;
-
-	tmp = in_be32(spcr);
-	out_be32(spcr, tmp|SPCR_TBEN);
-
-	iounmap(spcr);
-
-	return 0;
-}
-void __init
-platform_init(void)
+void __init platform_init(void)
 {
 	/* setup the PowerPC module struct */
 	ppc_md.setup_arch = mpc834x_sys_setup_arch;
@@ -239,5 +180,3 @@
 
 	return;
 }
-
-
diff -urN oldtree/arch/powerpc/platforms/83xx/mpc834x_sys.h newtree/arch/powerpc/platforms/83xx/mpc834x_sys.h
--- oldtree/arch/powerpc/platforms/83xx/mpc834x_sys.h	2006-02-19 11:40:59.262455224 +0000
+++ newtree/arch/powerpc/platforms/83xx/mpc834x_sys.h	2006-02-21 15:58:17.170536240 +0000
@@ -20,4 +20,4 @@
 #define PIRQC	MPC83xx_IRQ_EXT6
 #define PIRQD	MPC83xx_IRQ_EXT7
 
-#endif                /* __MACH_MPC83XX_SYS_H__ */
+#endif				/* __MACH_MPC83XX_SYS_H__ */
diff -urN oldtree/arch/powerpc/platforms/83xx/mpc83xx.h newtree/arch/powerpc/platforms/83xx/mpc83xx.h
--- oldtree/arch/powerpc/platforms/83xx/mpc83xx.h	2006-02-19 11:40:59.262455224 +0000
+++ newtree/arch/powerpc/platforms/83xx/mpc83xx.h	2006-02-21 15:58:17.170536240 +0000
@@ -10,5 +10,8 @@
  */
 
 extern int add_bridge(struct device_node *dev);
+extern int mpc83xx_exclude_device(u_char bus, u_char devfn);
+extern void mpc83xx_restart(char *cmd);
+extern long mpc83xx_time_init(void);
 
-#endif /* __MPC83XX_H__ */
+#endif				/* __MPC83XX_H__ */
diff -urN oldtree/arch/powerpc/platforms/83xx/pci.c newtree/arch/powerpc/platforms/83xx/pci.c
--- oldtree/arch/powerpc/platforms/83xx/pci.c	2006-02-19 11:40:59.262455224 +0000
+++ newtree/arch/powerpc/platforms/83xx/pci.c	2006-02-21 15:58:17.171536088 +0000
@@ -36,7 +36,16 @@
 
 int mpc83xx_pci2_busno;
 
-#ifdef CONFIG_PCI
+int mpc83xx_exclude_device(u_char bus, u_char devfn)
+{
+	if (bus == 0 && PCI_SLOT(devfn) == 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	if (mpc83xx_pci2_busno)
+		if (bus == (mpc83xx_pci2_busno) && PCI_SLOT(devfn) == 0)
+			return PCIBIOS_DEVICE_NOT_FOUND;
+	return PCIBIOS_SUCCESSFUL;
+}
+
 int __init add_bridge(struct device_node *dev)
 {
 	int len;
@@ -52,7 +61,7 @@
 	has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
 
 	/* Get bus range if any */
-	bus_range = (int *) get_property(dev, "bus-range", &len);
+	bus_range = (int *)get_property(dev, "bus-range", &len);
 	if (bus_range == NULL || len < 2 * sizeof(int)) {
 		printk(KERN_WARNING "Can't get bus-range for %s, assume"
 		       " bus 0\n", dev->full_name);
@@ -74,7 +83,7 @@
 	if ((rsrc.start & 0xfffff) == 0x8500) {
 		setup_indirect_pci(hose, immr + 0x8300, immr + 0x8304);
 	}
-	/* PCI 2*/
+	/* PCI 2 */
 	if ((rsrc.start & 0xfffff) == 0x8600) {
 		setup_indirect_pci(hose, immr + 0x8380, immr + 0x8384);
 		primary = 0;
@@ -84,10 +93,10 @@
 
 	printk(KERN_INFO "Found MPC83xx PCI host bridge at 0x%08lx. "
 	       "Firmware bus number: %d->%d\n",
-		rsrc.start, hose->first_busno, hose->last_busno);
+	       rsrc.start, hose->first_busno, hose->last_busno);
 
 	DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
-		hose, hose->cfg_addr, hose->cfg_data);
+	    hose, hose->cfg_addr, hose->cfg_data);
 
 	/* Interpret the "ranges" property */
 	/* This also maps the I/O region and sets isa_io/mem_base */
@@ -95,5 +104,3 @@
 
 	return 0;
 }
-
-#endif
diff -urN oldtree/arch/powerpc/platforms/85xx/Kconfig newtree/arch/powerpc/platforms/85xx/Kconfig
--- oldtree/arch/powerpc/platforms/85xx/Kconfig	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/platforms/85xx/Kconfig	2006-02-21 15:58:17.171536088 +0000
@@ -1,86 +1,30 @@
-config 85xx
-	bool
-	depends on E500
-	default y
-
-config PPC_INDIRECT_PCI_BE
-	bool
-	depends on 85xx
-	default y
-
-menu "Freescale 85xx options"
-	depends on E500
+menu "Platform support"
+	depends on PPC_85xx
 
 choice
 	prompt "Machine Type"
-	depends on 85xx
 	default MPC8540_ADS
 
 config MPC8540_ADS
 	bool "Freescale MPC8540 ADS"
 	help
-	  This option enables support for the MPC 8540 ADS evaluation board.
-
-config MPC8548_CDS
-	bool "Freescale MPC8548 CDS"
-	help
-	  This option enablese support for the MPC8548 CDS evaluation board.
-
-config MPC8555_CDS
-	bool "Freescale MPC8555 CDS"
-	help
-	  This option enablese support for the MPC8555 CDS evaluation board.
-
-config MPC8560_ADS
-	bool "Freescale MPC8560 ADS"
-	help
-	  This option enables support for the MPC 8560 ADS evaluation board.
-
-config SBC8560
-	bool "WindRiver PowerQUICC III SBC8560"
-	help
-	  This option enables support for the WindRiver PowerQUICC III 
-	  SBC8560 board.
-
-config STX_GP3
-	bool "Silicon Turnkey Express GP3"
-	help
-	  This option enables support for the Silicon Turnkey Express GP3
-	  board.
+	  This option enables support for the MPC 8540 ADS board
 
 endchoice
 
-# It's often necessary to know the specific 85xx processor type.
-# Fortunately, it is implied (so far) from the board type, so we
-# don't need to ask more redundant questions.
 config MPC8540
 	bool
-	depends on MPC8540_ADS
-	default y
-
-config MPC8548
-	bool
-	depends on MPC8548_CDS
-	default y
+	select PPC_UDBG_16550
+	select PPC_INDIRECT_PCI
+	default y if MPC8540_ADS
 
-config MPC8555
-	bool
-	depends on MPC8555_CDS
-	default y
-
-config MPC8560
+config PPC_INDIRECT_PCI_BE
 	bool
-	depends on SBC8560 || MPC8560_ADS || STX_GP3
-	default y
-
-config 85xx_PCI2
-	bool "Supprt for 2nd PCI host controller"
-	depends on MPC8555_CDS
+	depends on PPC_85xx
 	default y
 
-config PPC_GEN550
+config MPIC
 	bool
-	depends on MPC8540 || SBC8560 || MPC8555
 	default y
 
 endmenu
diff -urN oldtree/arch/powerpc/platforms/85xx/Makefile newtree/arch/powerpc/platforms/85xx/Makefile
--- oldtree/arch/powerpc/platforms/85xx/Makefile	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/platforms/85xx/Makefile	2006-02-21 15:58:17.171536088 +0000
@@ -1 +1,4 @@
-# empty makefile so make clean works
+#
+# Makefile for the PowerPC 85xx linux kernel.
+#
+obj-$(CONFIG_PPC_85xx)	+= misc.o mpc85xx_ads.o
diff -urN oldtree/arch/powerpc/platforms/85xx/misc.c newtree/arch/powerpc/platforms/85xx/misc.c
--- oldtree/arch/powerpc/platforms/85xx/misc.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/powerpc/platforms/85xx/misc.c	2006-02-21 15:58:17.171536088 +0000
@@ -0,0 +1,31 @@
+/*
+ * MPC85xx generic code.
+ *
+ * Maintained by Kumar Gala (see MAINTAINERS for contact information)
+ *
+ * Copyright 2005 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <asm/irq.h>
+
+extern void abort(void);
+
+void mpc85xx_restart(char *cmd)
+{
+	local_irq_disable();
+	abort();
+}
+
+/* For now this is a pass through */
+phys_addr_t fixup_bigphys_addr(phys_addr_t addr, phys_addr_t size)
+{
+	return addr;
+};
+
+EXPORT_SYMBOL(fixup_bigphys_addr);
diff -urN oldtree/arch/powerpc/platforms/85xx/mpc8540_ads.h newtree/arch/powerpc/platforms/85xx/mpc8540_ads.h
--- oldtree/arch/powerpc/platforms/85xx/mpc8540_ads.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/powerpc/platforms/85xx/mpc8540_ads.h	2006-02-21 15:58:17.172535936 +0000
@@ -0,0 +1,60 @@
+/*
+ * arch/ppc/platforms/85xx/mpc8540_ads.h
+ *
+ * MPC8540ADS board definitions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef __MACH_MPC8540ADS_H__
+#define __MACH_MPC8540ADS_H__
+
+#include <linux/config.h>
+#include <linux/initrd.h>
+
+#define BOARD_CCSRBAR		((uint)0xe0000000)
+#define BCSR_ADDR		((uint)0xf8000000)
+#define BCSR_SIZE		((uint)(32 * 1024))
+
+/* PCI interrupt controller */
+#define PIRQA		MPC85xx_IRQ_EXT1
+#define PIRQB		MPC85xx_IRQ_EXT2
+#define PIRQC		MPC85xx_IRQ_EXT3
+#define PIRQD		MPC85xx_IRQ_EXT4
+
+#define MPC85XX_PCI1_LOWER_IO	0x00000000
+#define MPC85XX_PCI1_UPPER_IO	0x00ffffff
+
+#define MPC85XX_PCI1_LOWER_MEM	0x80000000
+#define MPC85XX_PCI1_UPPER_MEM	0x9fffffff
+
+#define MPC85XX_PCI1_IO_BASE	0xe2000000
+#define MPC85XX_PCI1_MEM_OFFSET	0x00000000
+
+#define MPC85XX_PCI1_IO_SIZE	0x01000000
+
+/* PCI config */
+#define PCI1_CFG_ADDR_OFFSET	(0x8000)
+#define PCI1_CFG_DATA_OFFSET	(0x8004)
+
+#define PCI2_CFG_ADDR_OFFSET	(0x9000)
+#define PCI2_CFG_DATA_OFFSET	(0x9004)
+
+/* Additional register for PCI-X configuration */
+#define PCIX_NEXT_CAP	0x60
+#define PCIX_CAP_ID	0x61
+#define PCIX_COMMAND	0x62
+#define PCIX_STATUS	0x64
+
+/* Offset of CPM register space */
+#define CPM_MAP_ADDR	(CCSRBAR + MPC85xx_CPM_OFFSET)
+
+#endif				/* __MACH_MPC8540ADS_H__ */
diff -urN oldtree/arch/powerpc/platforms/85xx/mpc85xx.h newtree/arch/powerpc/platforms/85xx/mpc85xx.h
--- oldtree/arch/powerpc/platforms/85xx/mpc85xx.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/powerpc/platforms/85xx/mpc85xx.h	2006-02-21 15:58:17.172535936 +0000
@@ -0,0 +1,17 @@
+/*
+ * arch/ppc/platforms/85xx/mpc85xx.h
+ *
+ * MPC85xx soc definitions/function decls
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2005 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+extern void mpc85xx_restart(char *);
diff -urN oldtree/arch/powerpc/platforms/85xx/mpc85xx_ads.c newtree/arch/powerpc/platforms/85xx/mpc85xx_ads.c
--- oldtree/arch/powerpc/platforms/85xx/mpc85xx_ads.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/powerpc/platforms/85xx/mpc85xx_ads.c	2006-02-21 15:58:17.172535936 +0000
@@ -0,0 +1,177 @@
+/*
+ * MPC85xx setup and early boot code plus other random bits.
+ *
+ * Maintained by Kumar Gala (see MAINTAINERS for contact information)
+ *
+ * Copyright 2005 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc85xx.h>
+#include <asm/prom.h>
+#include <asm/mpic.h>
+#include <mm/mmu_decl.h>
+#include <asm/udbg.h>
+
+#include <sysdev/fsl_soc.h>
+#include "mpc85xx.h"
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+/*
+ * Internal interrupts are all Level Sensitive, and Positive Polarity
+ *
+ * Note:  Likely, this table and the following function should be
+ *        obtained and derived from the OF Device Tree.
+ */
+static u_char mpc85xx_ads_openpic_initsenses[] __initdata = {
+	MPC85XX_INTERNAL_IRQ_SENSES,
+	0x0,			/* External  0: */
+#if defined(CONFIG_PCI)
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* Ext 1: PCI slot 0 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* Ext 2: PCI slot 1 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* Ext 3: PCI slot 2 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* Ext 4: PCI slot 3 */
+#else
+	0x0,			/* External  1: */
+	0x0,			/* External  2: */
+	0x0,			/* External  3: */
+	0x0,			/* External  4: */
+#endif
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External 5: PHY */
+	0x0,			/* External  6: */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External 7: PHY */
+	0x0,			/* External  8: */
+	0x0,			/* External  9: */
+	0x0,			/* External 10: */
+	0x0,			/* External 11: */
+};
+
+void __init mpc85xx_ads_pic_init(void)
+{
+	struct mpic *mpic1;
+	phys_addr_t OpenPIC_PAddr;
+
+	/* Determine the Physical Address of the OpenPIC regs */
+	OpenPIC_PAddr = get_immrbase() + MPC85xx_OPENPIC_OFFSET;
+
+	mpic1 = mpic_alloc(OpenPIC_PAddr,
+			   MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+			   4, MPC85xx_OPENPIC_IRQ_OFFSET, 0, 250,
+			   mpc85xx_ads_openpic_initsenses,
+			   sizeof(mpc85xx_ads_openpic_initsenses),
+			   " OpenPIC  ");
+	BUG_ON(mpic1 == NULL);
+	mpic_assign_isu(mpic1, 0, OpenPIC_PAddr + 0x10200);
+	mpic_assign_isu(mpic1, 1, OpenPIC_PAddr + 0x10280);
+	mpic_assign_isu(mpic1, 2, OpenPIC_PAddr + 0x10300);
+	mpic_assign_isu(mpic1, 3, OpenPIC_PAddr + 0x10380);
+	mpic_assign_isu(mpic1, 4, OpenPIC_PAddr + 0x10400);
+	mpic_assign_isu(mpic1, 5, OpenPIC_PAddr + 0x10480);
+	mpic_assign_isu(mpic1, 6, OpenPIC_PAddr + 0x10500);
+	mpic_assign_isu(mpic1, 7, OpenPIC_PAddr + 0x10580);
+
+	/* dummy mappings to get to 48 */
+	mpic_assign_isu(mpic1, 8, OpenPIC_PAddr + 0x10600);
+	mpic_assign_isu(mpic1, 9, OpenPIC_PAddr + 0x10680);
+	mpic_assign_isu(mpic1, 10, OpenPIC_PAddr + 0x10700);
+	mpic_assign_isu(mpic1, 11, OpenPIC_PAddr + 0x10780);
+
+	/* External ints */
+	mpic_assign_isu(mpic1, 12, OpenPIC_PAddr + 0x10000);
+	mpic_assign_isu(mpic1, 13, OpenPIC_PAddr + 0x10080);
+	mpic_assign_isu(mpic1, 14, OpenPIC_PAddr + 0x10100);
+	mpic_init(mpic1);
+}
+
+/*
+ * Setup the architecture
+ */
+static void __init mpc85xx_ads_setup_arch(void)
+{
+	struct device_node *cpu;
+
+	if (ppc_md.progress)
+		ppc_md.progress("mpc85xx_ads_setup_arch()", 0);
+
+	cpu = of_find_node_by_type(NULL, "cpu");
+	if (cpu != 0) {
+		unsigned int *fp;
+
+		fp = (int *)get_property(cpu, "clock-frequency", NULL);
+		if (fp != 0)
+			loops_per_jiffy = *fp / HZ;
+		else
+			loops_per_jiffy = 50000000 / HZ;
+		of_node_put(cpu);
+	}
+#ifdef  CONFIG_ROOT_NFS
+	ROOT_DEV = Root_NFS;
+#else
+	ROOT_DEV = Root_HDA1;
+#endif
+}
+
+void mpc85xx_ads_show_cpuinfo(struct seq_file *m)
+{
+	uint pvid, svid, phid1;
+	uint memsize = total_memory;
+
+	pvid = mfspr(SPRN_PVR);
+	svid = mfspr(SPRN_SVR);
+
+	seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
+	seq_printf(m, "Machine\t\t: mpc85xx\n");
+	seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
+	seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+
+	/* Display cpu Pll setting */
+	phid1 = mfspr(SPRN_HID1);
+	seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
+
+	/* Display the amount of memory */
+	seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
+}
+
+void __init platform_init(void)
+{
+	ppc_md.setup_arch = mpc85xx_ads_setup_arch;
+	ppc_md.show_cpuinfo = mpc85xx_ads_show_cpuinfo;
+
+	ppc_md.init_IRQ = mpc85xx_ads_pic_init;
+	ppc_md.get_irq = mpic_get_irq;
+
+	ppc_md.restart = mpc85xx_restart;
+	ppc_md.power_off = NULL;
+	ppc_md.halt = NULL;
+
+	ppc_md.time_init = NULL;
+	ppc_md.set_rtc_time = NULL;
+	ppc_md.get_rtc_time = NULL;
+	ppc_md.calibrate_decr = generic_calibrate_decr;
+
+	ppc_md.progress = udbg_progress;
+
+	if (ppc_md.progress)
+		ppc_md.progress("mpc85xx_ads platform_init(): exit", 0);
+}
diff -urN oldtree/arch/powerpc/platforms/Makefile newtree/arch/powerpc/platforms/Makefile
--- oldtree/arch/powerpc/platforms/Makefile	2006-02-19 11:40:59.263455072 +0000
+++ newtree/arch/powerpc/platforms/Makefile	2006-02-21 15:58:17.174535632 +0000
@@ -8,7 +8,7 @@
 obj-$(CONFIG_PPC_CHRP)		+= chrp/
 obj-$(CONFIG_4xx)		+= 4xx/
 obj-$(CONFIG_PPC_83xx)		+= 83xx/
-obj-$(CONFIG_85xx)		+= 85xx/
+obj-$(CONFIG_PPC_85xx)		+= 85xx/
 obj-$(CONFIG_PPC_PSERIES)	+= pseries/
 obj-$(CONFIG_PPC_ISERIES)	+= iseries/
 obj-$(CONFIG_PPC_MAPLE)		+= maple/
diff -urN oldtree/arch/powerpc/platforms/cell/spu_base.c newtree/arch/powerpc/platforms/cell/spu_base.c
--- oldtree/arch/powerpc/platforms/cell/spu_base.c	2006-02-19 11:40:59.297449904 +0000
+++ newtree/arch/powerpc/platforms/cell/spu_base.c	2006-02-21 15:58:24.157474064 +0000
@@ -32,7 +32,7 @@
 
 #include <asm/io.h>
 #include <asm/prom.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/spu.h>
 #include <asm/mmu_context.h>
 
@@ -342,7 +342,7 @@
 }
 
 static LIST_HEAD(spu_list);
-static DECLARE_MUTEX(spu_mutex);
+static DEFINE_MUTEX(spu_mutex);
 
 static void spu_init_channels(struct spu *spu)
 {
@@ -382,7 +382,7 @@
 {
 	struct spu *spu;
 
-	down(&spu_mutex);
+	mutex_lock(&spu_mutex);
 	if (!list_empty(&spu_list)) {
 		spu = list_entry(spu_list.next, struct spu, list);
 		list_del_init(&spu->list);
@@ -391,7 +391,7 @@
 		pr_debug("No SPU left\n");
 		spu = NULL;
 	}
-	up(&spu_mutex);
+	mutex_unlock(&spu_mutex);
 
 	if (spu)
 		spu_init_channels(spu);
@@ -402,9 +402,9 @@
 
 void spu_free(struct spu *spu)
 {
-	down(&spu_mutex);
+	mutex_lock(&spu_mutex);
 	list_add_tail(&spu->list, &spu_list);
-	up(&spu_mutex);
+	mutex_unlock(&spu_mutex);
 }
 EXPORT_SYMBOL_GPL(spu_free);
 
@@ -633,14 +633,14 @@
 	spu->wbox_callback = NULL;
 	spu->stop_callback = NULL;
 
-	down(&spu_mutex);
+	mutex_lock(&spu_mutex);
 	spu->number = number++;
 	ret = spu_request_irqs(spu);
 	if (ret)
 		goto out_unmap;
 
 	list_add(&spu->list, &spu_list);
-	up(&spu_mutex);
+	mutex_unlock(&spu_mutex);
 
 	pr_debug(KERN_DEBUG "Using SPE %s %02x %p %p %p %p %d\n",
 		spu->name, spu->isrc, spu->local_store,
@@ -648,7 +648,7 @@
 	goto out;
 
 out_unmap:
-	up(&spu_mutex);
+	mutex_unlock(&spu_mutex);
 	spu_unmap(spu);
 out_free:
 	kfree(spu);
@@ -668,10 +668,10 @@
 static void cleanup_spu_base(void)
 {
 	struct spu *spu, *tmp;
-	down(&spu_mutex);
+	mutex_lock(&spu_mutex);
 	list_for_each_entry_safe(spu, tmp, &spu_list, list)
 		destroy_spu(spu);
-	up(&spu_mutex);
+	mutex_unlock(&spu_mutex);
 }
 module_exit(cleanup_spu_base);
 
diff -urN oldtree/arch/powerpc/platforms/chrp/pegasos_eth.c newtree/arch/powerpc/platforms/chrp/pegasos_eth.c
--- oldtree/arch/powerpc/platforms/chrp/pegasos_eth.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/platforms/chrp/pegasos_eth.c	2006-02-21 15:58:17.173535784 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/platforms/chrp_pegasos_eth.c
- *
  *  Copyright (C) 2005 Sven Luther <sl@bplan-gmbh.de>
  *  Thanks to :
  *	Dale Farnsworth <dale@farnsworth.org>
diff -urN oldtree/arch/powerpc/platforms/chrp/setup.c newtree/arch/powerpc/platforms/chrp/setup.c
--- oldtree/arch/powerpc/platforms/chrp/setup.c	2006-02-19 11:40:59.312447624 +0000
+++ newtree/arch/powerpc/platforms/chrp/setup.c	2006-02-21 15:58:17.174535632 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/platforms/setup.c
- *
  *  Copyright (C) 1995  Linus Torvalds
  *  Adapted from 'alpha' version by Gary Thomas
  *  Modified by Cort Dougan (cort@cs.nmt.edu)
diff -urN oldtree/arch/powerpc/platforms/chrp/time.c newtree/arch/powerpc/platforms/chrp/time.c
--- oldtree/arch/powerpc/platforms/chrp/time.c	2006-02-19 11:40:59.312447624 +0000
+++ newtree/arch/powerpc/platforms/chrp/time.c	2006-02-21 15:58:17.174535632 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/platforms/chrp_time.c
- *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
  *
  * Adapted for PowerPC (PReP) by Gary Thomas
diff -urN oldtree/arch/powerpc/platforms/maple/time.c newtree/arch/powerpc/platforms/maple/time.c
--- oldtree/arch/powerpc/platforms/maple/time.c	2006-02-19 11:40:59.321446256 +0000
+++ newtree/arch/powerpc/platforms/maple/time.c	2006-02-21 15:58:17.228527424 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc64/kernel/maple_time.c
- *
  *  (c) Copyright 2004 Benjamin Herrenschmidt (benh@kernel.crashing.org),
  *                     IBM Corp. 
  *
diff -urN oldtree/arch/powerpc/platforms/powermac/cpufreq_32.c newtree/arch/powerpc/platforms/powermac/cpufreq_32.c
--- oldtree/arch/powerpc/platforms/powermac/cpufreq_32.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/platforms/powermac/cpufreq_32.c	2006-02-21 15:58:17.229527272 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/platforms/pmac_cpufreq.c
- *
  *  Copyright (C) 2002 - 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>
  *  Copyright (C) 2004        John Steele Scott <toojays@toojays.net>
  *
diff -urN oldtree/arch/powerpc/platforms/powermac/cpufreq_64.c newtree/arch/powerpc/platforms/powermac/cpufreq_64.c
--- oldtree/arch/powerpc/platforms/powermac/cpufreq_64.c	2006-02-19 11:40:59.324445800 +0000
+++ newtree/arch/powerpc/platforms/powermac/cpufreq_64.c	2006-02-21 15:58:24.163473152 +0000
@@ -21,6 +21,7 @@
 #include <linux/cpufreq.h>
 #include <linux/init.h>
 #include <linux/completion.h>
+#include <linux/mutex.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/irq.h>
@@ -90,7 +91,7 @@
 static int (*g5_switch_freq)(int speed_mode);
 static int (*g5_query_freq)(void);
 
-static DECLARE_MUTEX(g5_switch_mutex);
+static DEFINE_MUTEX(g5_switch_mutex);
 
 
 static struct smu_sdbp_fvt *g5_fvt_table;	/* table of op. points */
@@ -327,7 +328,7 @@
 	if (g5_pmode_cur == newstate)
 		return 0;
 
-	down(&g5_switch_mutex);
+	mutex_lock(&g5_switch_mutex);
 
 	freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency;
 	freqs.new = g5_cpu_freqs[newstate].frequency;
@@ -337,7 +338,7 @@
 	rc = g5_switch_freq(newstate);
 	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 
-	up(&g5_switch_mutex);
+	mutex_unlock(&g5_switch_mutex);
 
 	return rc;
 }
diff -urN oldtree/arch/powerpc/platforms/powermac/feature.c newtree/arch/powerpc/platforms/powermac/feature.c
--- oldtree/arch/powerpc/platforms/powermac/feature.c	2006-02-19 11:40:59.325445648 +0000
+++ newtree/arch/powerpc/platforms/powermac/feature.c	2006-02-21 15:58:17.230527120 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/platforms/pmac_feature.c
- *
  *  Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au)
  *                          Ben. Herrenschmidt (benh@kernel.crashing.org)
  *
@@ -1646,10 +1644,10 @@
 		  KL0_SCC_CELL_ENABLE);
 
 	MACIO_BIC(KEYLARGO_FCR1,
-		  /*KL1_USB2_CELL_ENABLE |*/
 		KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
 		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
-		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE);
+		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
+		KL1_EIDE0_ENABLE);
 	if (pmac_mb.board_flags & PMAC_MB_MOBILE)
 		MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);
 
@@ -2183,7 +2181,7 @@
 	},
 	{	"PowerMac10,1",			"Mac mini",
 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
-		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER,
+		PMAC_MB_MAY_SLEEP,
 	},
 	{	"iMac,1",			"iMac (first generation)",
 		PMAC_TYPE_ORIG_IMAC,		paddington_features,
@@ -2295,11 +2293,11 @@
 	},
 	{	"PowerBook5,8",			"PowerBook G4 15\"",
 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
-		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+		PMAC_MB_MAY_SLEEP  | PMAC_MB_MOBILE,
 	},
 	{	"PowerBook5,9",			"PowerBook G4 17\"",
 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
-		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+		PMAC_MB_MAY_SLEEP | PMAC_MB_MOBILE,
 	},
 	{	"PowerBook6,1",			"PowerBook G4 12\"",
 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
diff -urN oldtree/arch/powerpc/platforms/powermac/nvram.c newtree/arch/powerpc/platforms/powermac/nvram.c
--- oldtree/arch/powerpc/platforms/powermac/nvram.c	2006-02-19 11:40:59.329445040 +0000
+++ newtree/arch/powerpc/platforms/powermac/nvram.c	2006-02-21 15:58:17.231526968 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/platforms/pmac_nvram.c
- *
  *  Copyright (C) 2002 Benjamin Herrenschmidt (benh@kernel.crashing.org)
  *
  *  This program is free software; you can redistribute it and/or
diff -urN oldtree/arch/powerpc/platforms/powermac/setup.c newtree/arch/powerpc/platforms/powermac/setup.c
--- oldtree/arch/powerpc/platforms/powermac/setup.c	2006-02-19 11:40:59.335444128 +0000
+++ newtree/arch/powerpc/platforms/powermac/setup.c	2006-02-21 15:58:17.232526816 +0000
@@ -86,11 +86,10 @@
 int ppc_override_l2cr_value;
 int has_l2cache = 0;
 
-int pmac_newworld = 1;
+int pmac_newworld;
 
 static int current_root_goodness = -1;
 
-extern int pmac_newworld;
 extern struct machdep_calls pmac_md;
 
 #define DEFAULT_ROOT_DEVICE Root_SDA1	/* sda1 - slightly silly choice */
@@ -308,9 +307,10 @@
 	for (ic = NULL; (ic = of_find_all_nodes(ic)) != NULL; )
 		if (get_property(ic, "interrupt-controller", NULL))
 			break;
-	pmac_newworld = (ic != NULL);
-	if (ic)
+	if (ic) {
+		pmac_newworld = 1;
 		of_node_put(ic);
+	}
 
 	/* Lookup PCI hosts */
 	pmac_pci_init();
diff -urN oldtree/arch/powerpc/platforms/pseries/Makefile newtree/arch/powerpc/platforms/pseries/Makefile
--- oldtree/arch/powerpc/platforms/pseries/Makefile	2006-02-19 11:40:59.375438048 +0000
+++ newtree/arch/powerpc/platforms/pseries/Makefile	2006-02-21 15:58:17.234526512 +0000
@@ -1,5 +1,6 @@
 obj-y			:= pci.o lpar.o hvCall.o nvram.o reconfig.o \
-			   setup.o iommu.o ras.o rtasd.o pci_dlpar.o
+			   setup.o iommu.o ras.o rtasd.o pci_dlpar.o \
+			   firmware.o
 obj-$(CONFIG_SMP)	+= smp.o
 obj-$(CONFIG_IBMVIO)	+= vio.o
 obj-$(CONFIG_XICS)	+= xics.o
diff -urN oldtree/arch/powerpc/platforms/pseries/firmware.c newtree/arch/powerpc/platforms/pseries/firmware.c
--- oldtree/arch/powerpc/platforms/pseries/firmware.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/powerpc/platforms/pseries/firmware.c	2006-02-21 15:58:17.232526816 +0000
@@ -0,0 +1,103 @@
+/*
+ *  pSeries firmware setup code.
+ *
+ *  Portions from arch/powerpc/platforms/pseries/setup.c:
+ *   Copyright (C) 1995  Linus Torvalds
+ *   Adapted from 'alpha' version by Gary Thomas
+ *   Modified by Cort Dougan (cort@cs.nmt.edu)
+ *   Modified by PPC64 Team, IBM Corp
+ *
+ *  Portions from arch/powerpc/kernel/firmware.c
+ *   Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)
+ *   Modifications for ppc64:
+ *    Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com>
+ *    Copyright (C) 2005 Stephen Rothwell, IBM Corporation
+ *
+ *  Copyright 2006 IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#undef DEBUG
+
+#include <asm/firmware.h>
+#include <asm/prom.h>
+
+#ifdef DEBUG
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+typedef struct {
+    unsigned long val;
+    char * name;
+} firmware_feature_t;
+
+static __initdata firmware_feature_t
+firmware_features_table[FIRMWARE_MAX_FEATURES] = {
+	{FW_FEATURE_PFT,		"hcall-pft"},
+	{FW_FEATURE_TCE,		"hcall-tce"},
+	{FW_FEATURE_SPRG0,		"hcall-sprg0"},
+	{FW_FEATURE_DABR,		"hcall-dabr"},
+	{FW_FEATURE_COPY,		"hcall-copy"},
+	{FW_FEATURE_ASR,		"hcall-asr"},
+	{FW_FEATURE_DEBUG,		"hcall-debug"},
+	{FW_FEATURE_PERF,		"hcall-perf"},
+	{FW_FEATURE_DUMP,		"hcall-dump"},
+	{FW_FEATURE_INTERRUPT,		"hcall-interrupt"},
+	{FW_FEATURE_MIGRATE,		"hcall-migrate"},
+	{FW_FEATURE_PERFMON,		"hcall-perfmon"},
+	{FW_FEATURE_CRQ,		"hcall-crq"},
+	{FW_FEATURE_VIO,		"hcall-vio"},
+	{FW_FEATURE_RDMA,		"hcall-rdma"},
+	{FW_FEATURE_LLAN,		"hcall-lLAN"},
+	{FW_FEATURE_BULK,		"hcall-bulk"},
+	{FW_FEATURE_XDABR,		"hcall-xdabr"},
+	{FW_FEATURE_MULTITCE,		"hcall-multi-tce"},
+	{FW_FEATURE_SPLPAR,		"hcall-splpar"},
+};
+
+/* Build up the firmware features bitmask using the contents of
+ * device-tree/ibm,hypertas-functions.  Ultimately this functionality may
+ * be moved into prom.c prom_init().
+ */
+void __init fw_feature_init(void)
+{
+	struct device_node *dn;
+	char *hypertas, *s;
+	int len, i;
+
+	DBG(" -> fw_feature_init()\n");
+
+	dn = of_find_node_by_path("/rtas");
+	if (dn == NULL) {
+		printk(KERN_ERR "WARNING! Cannot find RTAS in device-tree!\n");
+		goto out;
+	}
+
+	hypertas = get_property(dn, "ibm,hypertas-functions", &len);
+	if (hypertas == NULL)
+		goto out;
+
+	for (s = hypertas; s < hypertas + len; s += strlen(s) + 1) {
+		for (i = 0; i < FIRMWARE_MAX_FEATURES; i++) {
+			/* check value against table of strings */
+			if (!firmware_features_table[i].name ||
+			    strcmp(firmware_features_table[i].name, s))
+				continue;
+
+			/* we have a match */
+			ppc64_firmware_features |=
+				firmware_features_table[i].val;
+			break;
+		}
+	}
+
+out:
+	of_node_put(dn);
+	DBG(" <- fw_feature_init()\n");
+}
diff -urN oldtree/arch/powerpc/platforms/pseries/firmware.h newtree/arch/powerpc/platforms/pseries/firmware.h
--- oldtree/arch/powerpc/platforms/pseries/firmware.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/powerpc/platforms/pseries/firmware.h	2006-02-21 15:58:17.233526664 +0000
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2006 IBM Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _PSERIES_FIRMWARE_H
+#define _PSERIES_FIRMWARE_H
+
+#include <asm/firmware.h>
+
+extern void __init fw_feature_init(void);
+
+#endif /* _PSERIES_FIRMWARE_H */
diff -urN oldtree/arch/powerpc/platforms/pseries/hvCall.S newtree/arch/powerpc/platforms/pseries/hvCall.S
--- oldtree/arch/powerpc/platforms/pseries/hvCall.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/platforms/pseries/hvCall.S	2006-02-21 15:58:17.233526664 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc64/kernel/pSeries_hvCall.S
- *
  * This file contains the generic code to perform a call to the
  * pSeries LPAR hypervisor.
  * NOTE: this file will go away when we move to inline this work.
diff -urN oldtree/arch/powerpc/platforms/pseries/iommu.c newtree/arch/powerpc/platforms/pseries/iommu.c
--- oldtree/arch/powerpc/platforms/pseries/iommu.c	2006-02-19 11:40:59.380437288 +0000
+++ newtree/arch/powerpc/platforms/pseries/iommu.c	2006-02-21 15:58:17.234526512 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc64/kernel/pSeries_iommu.c
- *
  * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation
  *
  * Rewrite, cleanup: 
diff -urN oldtree/arch/powerpc/platforms/pseries/pci.c newtree/arch/powerpc/platforms/pseries/pci.c
--- oldtree/arch/powerpc/platforms/pseries/pci.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/platforms/pseries/pci.c	2006-02-21 15:58:17.235526360 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc64/kernel/pSeries_pci.c
- *
  * Copyright (C) 2001 Dave Engebretsen, IBM Corporation
  * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
  *
diff -urN oldtree/arch/powerpc/platforms/pseries/setup.c newtree/arch/powerpc/platforms/pseries/setup.c
--- oldtree/arch/powerpc/platforms/pseries/setup.c	2006-02-19 11:40:59.384436680 +0000
+++ newtree/arch/powerpc/platforms/pseries/setup.c	2006-02-21 15:58:17.235526360 +0000
@@ -60,7 +60,6 @@
 #include <asm/time.h>
 #include <asm/nvram.h>
 #include "xics.h"
-#include <asm/firmware.h>
 #include <asm/pmc.h>
 #include <asm/mpic.h>
 #include <asm/ppc-pci.h>
@@ -70,6 +69,7 @@
 
 #include "plpar_wrappers.h"
 #include "ras.h"
+#include "firmware.h"
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
@@ -262,53 +262,6 @@
 }
 arch_initcall(pSeries_init_panel);
 
-
-/* Build up the ppc64_firmware_features bitmask field
- * using contents of device-tree/ibm,hypertas-functions.
- * Ultimately this functionality may be moved into prom.c prom_init().
- */
-static void __init fw_feature_init(void)
-{
-	struct device_node * dn;
-	char * hypertas;
-	unsigned int len;
-
-	DBG(" -> fw_feature_init()\n");
-
-	ppc64_firmware_features = 0;
-	dn = of_find_node_by_path("/rtas");
-	if (dn == NULL) {
-		printk(KERN_ERR "WARNING ! Cannot find RTAS in device-tree !\n");
-		goto no_rtas;
-	}
-
-	hypertas = get_property(dn, "ibm,hypertas-functions", &len);
-	if (hypertas) {
-		while (len > 0){
-			int i, hypertas_len;
-			/* check value against table of strings */
-			for(i=0; i < FIRMWARE_MAX_FEATURES ;i++) {
-				if ((firmware_features_table[i].name) &&
-				    (strcmp(firmware_features_table[i].name,hypertas))==0) {
-					/* we have a match */
-					ppc64_firmware_features |= 
-						(firmware_features_table[i].val);
-					break;
-				} 
-			}
-			hypertas_len = strlen(hypertas);
-			len -= hypertas_len +1;
-			hypertas+= hypertas_len +1;
-		}
-	}
-
-	of_node_put(dn);
-no_rtas:
-
-	DBG(" <- fw_feature_init()\n");
-}
-
-
 static  void __init pSeries_discover_pic(void)
 {
 	struct device_node *np;
diff -urN oldtree/arch/powerpc/sysdev/dart_iommu.c newtree/arch/powerpc/sysdev/dart_iommu.c
--- oldtree/arch/powerpc/sysdev/dart_iommu.c	2006-02-19 11:40:59.387436224 +0000
+++ newtree/arch/powerpc/sysdev/dart_iommu.c	2006-02-21 15:58:17.236526208 +0000
@@ -194,8 +194,6 @@
 	 * prefetching into invalid pages and corrupting data
 	 */
 	tmp = lmb_alloc(DART_PAGE_SIZE, DART_PAGE_SIZE);
-	if (!tmp)
-		panic("DART: Cannot allocate spare page!");
 	dart_emptyval = DARTMAP_VALID | ((tmp >> DART_PAGE_SHIFT) &
 					 DARTMAP_RPNMASK);
 
diff -urN oldtree/arch/powerpc/sysdev/dcr.S newtree/arch/powerpc/sysdev/dcr.S
--- oldtree/arch/powerpc/sysdev/dcr.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/powerpc/sysdev/dcr.S	2006-02-21 15:58:17.236526208 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/dcr.S
- *
  * "Indirect" DCR access
  *
  * Copyright (c) 2004 Eugene Surovegin <ebs@ebshome.net>
diff -urN oldtree/arch/powerpc/sysdev/fsl_soc.c newtree/arch/powerpc/sysdev/fsl_soc.c
--- oldtree/arch/powerpc/sysdev/fsl_soc.c	2006-02-19 11:40:59.387436224 +0000
+++ newtree/arch/powerpc/sysdev/fsl_soc.c	2006-02-21 15:58:17.237526056 +0000
@@ -40,7 +40,7 @@
 		return immrbase;
 
 	soc = of_find_node_by_type(NULL, "soc");
-	if (soc != 0) {
+	if (soc) {
 		unsigned int size;
 		void *prop = get_property(soc, "reg", &size);
 		immrbase = of_translate_address(soc, prop);
@@ -49,21 +49,20 @@
 
 	return immrbase;
 }
-EXPORT_SYMBOL(get_immrbase);
 
-static const char * gfar_tx_intr = "tx";
-static const char * gfar_rx_intr = "rx";
-static const char * gfar_err_intr = "error";
+EXPORT_SYMBOL(get_immrbase);
 
-static int __init gfar_of_init(void)
+static int __init gfar_mdio_of_init(void)
 {
 	struct device_node *np;
 	unsigned int i;
-	struct platform_device *mdio_dev, *gfar_dev;
+	struct platform_device *mdio_dev;
 	struct resource res;
 	int ret;
 
-	for (np = NULL, i = 0; (np = of_find_compatible_node(np, "mdio", "gianfar")) != NULL; i++) {
+	for (np = NULL, i = 0;
+	     (np = of_find_compatible_node(np, "mdio", "gianfar")) != NULL;
+	     i++) {
 		int k;
 		struct device_node *child = NULL;
 		struct gianfar_mdio_data mdio_data;
@@ -73,12 +72,14 @@
 
 		ret = of_address_to_resource(np, 0, &res);
 		if (ret)
-			goto mdio_err;
+			goto err;
 
-		mdio_dev = platform_device_register_simple("fsl-gianfar_mdio", res.start, &res, 1);
+		mdio_dev =
+		    platform_device_register_simple("fsl-gianfar_mdio",
+						    res.start, &res, 1);
 		if (IS_ERR(mdio_dev)) {
 			ret = PTR_ERR(mdio_dev);
-			goto mdio_err;
+			goto err;
 		}
 
 		for (k = 0; k < 32; k++)
@@ -86,17 +87,44 @@
 
 		while ((child = of_get_next_child(np, child)) != NULL) {
 			if (child->n_intrs) {
-				u32 *id = (u32 *) get_property(child, "reg", NULL);
+				u32 *id =
+				    (u32 *) get_property(child, "reg", NULL);
 				mdio_data.irq[*id] = child->intrs[0].line;
 			}
 		}
 
-		ret = platform_device_add_data(mdio_dev, &mdio_data, sizeof(struct gianfar_mdio_data));
+		ret =
+		    platform_device_add_data(mdio_dev, &mdio_data,
+					     sizeof(struct gianfar_mdio_data));
 		if (ret)
-			goto mdio_unreg;
+			goto unreg;
 	}
 
-	for (np = NULL, i = 0; (np = of_find_compatible_node(np, "network", "gianfar")) != NULL; i++) {
+	return 0;
+
+unreg:
+	platform_device_unregister(mdio_dev);
+err:
+	return ret;
+}
+
+arch_initcall(gfar_mdio_of_init);
+
+static const char *gfar_tx_intr = "tx";
+static const char *gfar_rx_intr = "rx";
+static const char *gfar_err_intr = "error";
+
+static int __init gfar_of_init(void)
+{
+	struct device_node *np;
+	unsigned int i;
+	struct platform_device *gfar_dev;
+	struct resource res;
+	int ret;
+
+	for (np = NULL, i = 0;
+	     (np = of_find_compatible_node(np, "network", "gianfar")) != NULL;
+	     i++) {
 		struct resource r[4];
 		struct device_node *phy, *mdio;
 		struct gianfar_platform_data gfar_data;
@@ -110,7 +138,7 @@
 
 		ret = of_address_to_resource(np, 0, &r[0]);
 		if (ret)
-			goto gfar_err;
+			goto err;
 
 		r[1].start = np->intrs[0].line;
 		r[1].end = np->intrs[0].line;
@@ -133,11 +161,13 @@
 			r[3].flags = IORESOURCE_IRQ;
 		}
 
-		gfar_dev = platform_device_register_simple("fsl-gianfar", i, &r[0], np->n_intrs + 1);
+		gfar_dev =
+		    platform_device_register_simple("fsl-gianfar", i, &r[0],
+						    np->n_intrs + 1);
 
 		if (IS_ERR(gfar_dev)) {
 			ret = PTR_ERR(gfar_dev);
-			goto gfar_err;
+			goto err;
 		}
 
 		mac_addr = get_property(np, "address", NULL);
@@ -145,26 +175,26 @@
 
 		if (model && !strcasecmp(model, "TSEC"))
 			gfar_data.device_flags =
-				FSL_GIANFAR_DEV_HAS_GIGABIT |
-				FSL_GIANFAR_DEV_HAS_COALESCE |
-				FSL_GIANFAR_DEV_HAS_RMON |
-				FSL_GIANFAR_DEV_HAS_MULTI_INTR;
+			    FSL_GIANFAR_DEV_HAS_GIGABIT |
+			    FSL_GIANFAR_DEV_HAS_COALESCE |
+			    FSL_GIANFAR_DEV_HAS_RMON |
+			    FSL_GIANFAR_DEV_HAS_MULTI_INTR;
 		if (model && !strcasecmp(model, "eTSEC"))
 			gfar_data.device_flags =
-				FSL_GIANFAR_DEV_HAS_GIGABIT |
-				FSL_GIANFAR_DEV_HAS_COALESCE |
-				FSL_GIANFAR_DEV_HAS_RMON |
-				FSL_GIANFAR_DEV_HAS_MULTI_INTR |
-				FSL_GIANFAR_DEV_HAS_CSUM |
-				FSL_GIANFAR_DEV_HAS_VLAN |
-				FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;
+			    FSL_GIANFAR_DEV_HAS_GIGABIT |
+			    FSL_GIANFAR_DEV_HAS_COALESCE |
+			    FSL_GIANFAR_DEV_HAS_RMON |
+			    FSL_GIANFAR_DEV_HAS_MULTI_INTR |
+			    FSL_GIANFAR_DEV_HAS_CSUM |
+			    FSL_GIANFAR_DEV_HAS_VLAN |
+			    FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;
 
 		ph = (phandle *) get_property(np, "phy-handle", NULL);
 		phy = of_find_node_by_phandle(*ph);
 
 		if (phy == NULL) {
 			ret = -ENODEV;
-			goto gfar_unreg;
+			goto unreg;
 		}
 
 		mdio = of_get_parent(phy);
@@ -174,7 +204,7 @@
 		if (ret) {
 			of_node_put(phy);
 			of_node_put(mdio);
-			goto gfar_unreg;
+			goto unreg;
 		}
 
 		gfar_data.phy_id = *id;
@@ -183,23 +213,22 @@
 		of_node_put(phy);
 		of_node_put(mdio);
 
-		ret = platform_device_add_data(gfar_dev, &gfar_data, sizeof(struct gianfar_platform_data));
+		ret =
+		    platform_device_add_data(gfar_dev, &gfar_data,
+					     sizeof(struct
+						    gianfar_platform_data));
 		if (ret)
-			goto gfar_unreg;
+			goto unreg;
 	}
 
 	return 0;
 
-mdio_unreg:
-	platform_device_unregister(mdio_dev);
-mdio_err:
-	return ret;
-
-gfar_unreg:
+unreg:
 	platform_device_unregister(gfar_dev);
-gfar_err:
+err:
 	return ret;
 }
+
 arch_initcall(gfar_of_init);
 
 static int __init fsl_i2c_of_init(void)
@@ -209,17 +238,19 @@
 	struct platform_device *i2c_dev;
 	int ret;
 
-	for (np = NULL, i = 0; (np = of_find_compatible_node(np, "i2c", "fsl-i2c")) != NULL; i++) {
+	for (np = NULL, i = 0;
+	     (np = of_find_compatible_node(np, "i2c", "fsl-i2c")) != NULL;
+	     i++) {
 		struct resource r[2];
 		struct fsl_i2c_platform_data i2c_data;
-		unsigned char * flags = NULL;
+		unsigned char *flags = NULL;
 
 		memset(&r, 0, sizeof(r));
 		memset(&i2c_data, 0, sizeof(i2c_data));
 
 		ret = of_address_to_resource(np, 0, &r[0]);
 		if (ret)
-			goto i2c_err;
+			goto err;
 
 		r[1].start = np->intrs[0].line;
 		r[1].end = np->intrs[0].line;
@@ -228,7 +259,7 @@
 		i2c_dev = platform_device_register_simple("fsl-i2c", i, r, 2);
 		if (IS_ERR(i2c_dev)) {
 			ret = PTR_ERR(i2c_dev);
-			goto i2c_err;
+			goto err;
 		}
 
 		i2c_data.device_flags = 0;
@@ -240,18 +271,22 @@
 		if (flags)
 			i2c_data.device_flags |= FSL_I2C_DEV_CLOCK_5200;
 
-		ret = platform_device_add_data(i2c_dev, &i2c_data, sizeof(struct fsl_i2c_platform_data));
+		ret =
+		    platform_device_add_data(i2c_dev, &i2c_data,
+					     sizeof(struct
+						    fsl_i2c_platform_data));
 		if (ret)
-			goto i2c_unreg;
+			goto unreg;
 	}
 
 	return 0;
 
-i2c_unreg:
+unreg:
 	platform_device_unregister(i2c_dev);
-i2c_err:
+err:
 	return ret;
 }
+
 arch_initcall(fsl_i2c_of_init);
 
 #ifdef CONFIG_PPC_83xx
@@ -267,51 +302,192 @@
 
 	if (!np) {
 		ret = -ENODEV;
-		goto mpc83xx_wdt_nodev;
+		goto nodev;
 	}
 
 	soc = of_find_node_by_type(NULL, "soc");
 
 	if (!soc) {
 		ret = -ENODEV;
-		goto mpc83xx_wdt_nosoc;
+		goto nosoc;
 	}
 
 	freq = (unsigned int *)get_property(soc, "bus-frequency", NULL);
 	if (!freq) {
 		ret = -ENODEV;
-		goto mpc83xx_wdt_err;
+		goto err;
 	}
 
 	memset(&r, 0, sizeof(r));
 
 	ret = of_address_to_resource(np, 0, &r);
 	if (ret)
-		goto mpc83xx_wdt_err;
+		goto err;
 
 	dev = platform_device_register_simple("mpc83xx_wdt", 0, &r, 1);
 	if (IS_ERR(dev)) {
 		ret = PTR_ERR(dev);
-		goto mpc83xx_wdt_err;
+		goto err;
 	}
 
 	ret = platform_device_add_data(dev, freq, sizeof(int));
 	if (ret)
-		goto mpc83xx_wdt_unreg;
+		goto unreg;
 
 	of_node_put(soc);
 	of_node_put(np);
 
 	return 0;
 
-mpc83xx_wdt_unreg:
+unreg:
 	platform_device_unregister(dev);
-mpc83xx_wdt_err:
+err:
 	of_node_put(soc);
-mpc83xx_wdt_nosoc:
+nosoc:
 	of_node_put(np);
-mpc83xx_wdt_nodev:
+nodev:
 	return ret;
 }
+
 arch_initcall(mpc83xx_wdt_init);
 #endif
+
+static enum fsl_usb2_phy_modes determine_usb_phy(char * phy_type)
+{
+	if (!phy_type)
+		return FSL_USB2_PHY_NONE;
+	if (!strcasecmp(phy_type, "ulpi"))
+		return FSL_USB2_PHY_ULPI;
+	if (!strcasecmp(phy_type, "utmi"))
+		return FSL_USB2_PHY_UTMI;
+	if (!strcasecmp(phy_type, "utmi_wide"))
+		return FSL_USB2_PHY_UTMI_WIDE;
+	if (!strcasecmp(phy_type, "serial"))
+		return FSL_USB2_PHY_SERIAL;
+
+	return FSL_USB2_PHY_NONE;
+}
+
+static int __init fsl_usb_of_init(void)
+{
+	struct device_node *np;
+	unsigned int i;
+	struct platform_device *usb_dev;
+	int ret;
+
+	for (np = NULL, i = 0;
+	     (np = of_find_compatible_node(np, "usb", "fsl-usb2-mph")) != NULL;
+	     i++) {
+		struct resource r[2];
+		struct fsl_usb2_platform_data usb_data;
+		unsigned char *prop = NULL;
+
+		memset(&r, 0, sizeof(r));
+		memset(&usb_data, 0, sizeof(usb_data));
+
+		ret = of_address_to_resource(np, 0, &r[0]);
+		if (ret)
+			goto err;
+
+		r[1].start = np->intrs[0].line;
+		r[1].end = np->intrs[0].line;
+		r[1].flags = IORESOURCE_IRQ;
+
+		usb_dev =
+		    platform_device_register_simple("fsl-usb2-mph", i, r, 2);
+		if (IS_ERR(usb_dev)) {
+			ret = PTR_ERR(usb_dev);
+			goto err;
+		}
+
+		usb_dev->dev.coherent_dma_mask = 0xffffffffUL;
+		usb_dev->dev.dma_mask = &usb_dev->dev.coherent_dma_mask;
+
+		usb_data.operating_mode = FSL_USB2_MPH_HOST;
+
+		prop = get_property(np, "port0", NULL);
+		if (prop)
+			usb_data.port_enables |= FSL_USB2_PORT0_ENABLED;
+
+		prop = get_property(np, "port1", NULL);
+		if (prop)
+			usb_data.port_enables |= FSL_USB2_PORT1_ENABLED;
+
+		prop = get_property(np, "phy_type", NULL);
+		usb_data.phy_mode = determine_usb_phy(prop);
+
+		ret =
+		    platform_device_add_data(usb_dev, &usb_data,
+					     sizeof(struct
+						    fsl_usb2_platform_data));
+		if (ret)
+			goto unreg;
+	}
+
+	return 0;
+
+unreg:
+	platform_device_unregister(usb_dev);
+err:
+	return ret;
+}
+
+arch_initcall(fsl_usb_of_init);
+
+static int __init fsl_usb_dr_of_init(void)
+{
+	struct device_node *np;
+	unsigned int i;
+	struct platform_device *usb_dev;
+	int ret;
+
+	for (np = NULL, i = 0;
+	     (np = of_find_compatible_node(np, "usb", "fsl-usb2-dr")) != NULL;
+	     i++) {
+		struct resource r[2];
+		struct fsl_usb2_platform_data usb_data;
+		unsigned char *prop = NULL;
+
+		memset(&r, 0, sizeof(r));
+		memset(&usb_data, 0, sizeof(usb_data));
+
+		ret = of_address_to_resource(np, 0, &r[0]);
+		if (ret)
+			goto err;
+
+		r[1].start = np->intrs[0].line;
+		r[1].end = np->intrs[0].line;
+		r[1].flags = IORESOURCE_IRQ;
+
+		usb_dev =
+		    platform_device_register_simple("fsl-usb2-dr", i, r, 2);
+		if (IS_ERR(usb_dev)) {
+			ret = PTR_ERR(usb_dev);
+			goto err;
+		}
+
+		usb_dev->dev.coherent_dma_mask = 0xffffffffUL;
+		usb_dev->dev.dma_mask = &usb_dev->dev.coherent_dma_mask;
+
+		usb_data.operating_mode = FSL_USB2_DR_HOST;
+
+		prop = get_property(np, "phy_type", NULL);
+		usb_data.phy_mode = determine_usb_phy(prop);
+
+		ret =
+		    platform_device_add_data(usb_dev, &usb_data,
+					     sizeof(struct
+						    fsl_usb2_platform_data));
+		if (ret)
+			goto unreg;
+	}
+
+	return 0;
+
+unreg:
+	platform_device_unregister(usb_dev);
+err:
+	return ret;
+}
+
+arch_initcall(fsl_usb_dr_of_init);
diff -urN oldtree/arch/powerpc/sysdev/ipic.h newtree/arch/powerpc/sysdev/ipic.h
--- oldtree/arch/powerpc/sysdev/ipic.h	2006-02-19 11:40:59.388436072 +0000
+++ newtree/arch/powerpc/sysdev/ipic.h	2006-02-21 15:58:17.238525904 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/kernel/ipic.h
- *
  * IPIC private definitions and structure.
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/4xx_io/serial_sicc.c newtree/arch/ppc/4xx_io/serial_sicc.c
--- oldtree/arch/ppc/4xx_io/serial_sicc.c	2006-02-19 11:40:59.395435008 +0000
+++ newtree/arch/ppc/4xx_io/serial_sicc.c	2006-02-21 15:58:17.239525752 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/4xx_io/serial_sicc.c
- *
  *  Driver for IBM STB3xxx SICC serial port
  *
  *  Based on drivers/char/serial_amba.c, by ARM Ltd.
diff -urN oldtree/arch/ppc/8xx_io/commproc.c newtree/arch/ppc/8xx_io/commproc.c
--- oldtree/arch/ppc/8xx_io/commproc.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/8xx_io/commproc.c	2006-02-21 15:58:17.241525448 +0000
@@ -73,7 +73,7 @@
 {
 	int cpm_vec = irq - CPM_IRQ_OFFSET;
 
-	out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr, in_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr) & ~(1 << cpm_vec));
+	clrbits32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr, (1 << cpm_vec));
 }
 
 static void
@@ -81,7 +81,7 @@
 {
 	int cpm_vec = irq - CPM_IRQ_OFFSET;
 
-	out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr, in_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr) | (1 << cpm_vec));
+	setbits32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr, (1 << cpm_vec));
 }
 
 static void
@@ -198,7 +198,7 @@
 	if (setup_irq(CPM_IRQ_OFFSET + CPMVEC_ERROR, &cpm_error_irqaction))
 		panic("Could not allocate CPM error IRQ!");
 
-	out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr, in_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr) | CICR_IEN);
+	setbits32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr, CICR_IEN);
 }
 
 /*
diff -urN oldtree/arch/ppc/Kconfig newtree/arch/ppc/Kconfig
--- oldtree/arch/ppc/Kconfig	2006-02-19 11:40:59.396434856 +0000
+++ newtree/arch/ppc/Kconfig	2006-02-21 15:58:17.259522712 +0000
@@ -481,6 +481,53 @@
 
 endchoice
 
+menu "Freescale Ethernet driver platform-specific options"
+	depends on FS_ENET
+
+	config MPC8xx_SECOND_ETH
+	bool "Second Ethernet channel"
+	depends on (MPC885ADS || MPC86XADS)
+	default y
+	help
+	  This enables support for second Ethernet on MPC885ADS and MPC86xADS boards.
+	  The latter will use SCC1, for 885ADS you can select it below.
+
+	choice
+		prompt "Second Ethernet channel"
+		depends on MPC8xx_SECOND_ETH
+		default MPC8xx_SECOND_ETH_FEC2
+
+		config MPC8xx_SECOND_ETH_FEC2
+		bool "FEC2"
+		depends on MPC885ADS
+		help
+		  Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2
+		  (often 2-nd UART) will not work if this is enabled.
+
+		config MPC8xx_SECOND_ETH_SCC1
+		bool "SCC1"
+		depends on MPC86XADS
+		select MPC8xx_SCC_ENET_FIXED
+		help
+		  Enable SCC1 to serve as 2-nd Ethernet channel. Note that SMC1
+		  (often 1-nd UART) will not work if this is enabled.
+
+		config MPC8xx_SECOND_ETH_SCC3
+		bool "SCC3"
+		depends on MPC885ADS
+		help
+		  Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1
+		  (often 1-nd UART) will not work if this is enabled.
+
+	endchoice
+
+	config MPC8xx_SCC_ENET_FIXED
+	depends on MPC8xx_SECOND_ETH_SCC
+	default n
+	bool "Use fixed MII-less mode for SCC Ethernet"
+
+endmenu
+
 choice
 	prompt "Machine Type"
 	depends on 6xx || POWER3
diff -urN oldtree/arch/ppc/Kconfig.debug newtree/arch/ppc/Kconfig.debug
--- oldtree/arch/ppc/Kconfig.debug	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/Kconfig.debug	2006-02-21 15:58:37.482448360 +0000
@@ -67,7 +67,7 @@
 
 config PPC_OCP
 	bool
-	depends on IBM_OCP || XILINX_OCP
+	depends on IBM_OCP
 	default y
 
 endmenu
diff -urN oldtree/arch/ppc/amiga/amiints.c newtree/arch/ppc/amiga/amiints.c
--- oldtree/arch/ppc/amiga/amiints.c	2006-02-19 11:40:59.397434704 +0000
+++ newtree/arch/ppc/amiga/amiints.c	2006-02-21 15:58:17.242525296 +0000
@@ -1,5 +1,5 @@
 /*
- * arch/ppc/amiga/amiints.c -- Amiga Linux interrupt handling code
+ * Amiga Linux interrupt handling code
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file COPYING in the main directory of this archive
diff -urN oldtree/arch/ppc/amiga/bootinfo.c newtree/arch/ppc/amiga/bootinfo.c
--- oldtree/arch/ppc/amiga/bootinfo.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/amiga/bootinfo.c	2006-02-21 15:58:17.242525296 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/amiga/bootinfo.c
- *
  *  Extracted from arch/m68k/kernel/setup.c.
  *  Should be properly generalized and put somewhere else.
  *                              Jesper
diff -urN oldtree/arch/ppc/amiga/cia.c newtree/arch/ppc/amiga/cia.c
--- oldtree/arch/ppc/amiga/cia.c	2006-02-19 11:40:59.398434552 +0000
+++ newtree/arch/ppc/amiga/cia.c	2006-02-21 15:58:17.242525296 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/amiga/cia.c - CIA support
- *
  *  Copyright (C) 1996 Roman Zippel
  *
  *  The concept of some functions bases on the original Amiga OS function
diff -urN oldtree/arch/ppc/amiga/config.c newtree/arch/ppc/amiga/config.c
--- oldtree/arch/ppc/amiga/config.c	2006-02-19 11:40:59.399434400 +0000
+++ newtree/arch/ppc/amiga/config.c	2006-02-21 15:58:17.243525144 +0000
@@ -1,8 +1,6 @@
 #define m68k_debug_device debug_device
 
 /*
- *  arch/ppc/amiga/config.c
- *
  *  Copyright (C) 1993 Hamish Macdonald
  *
  * This file is subject to the terms and conditions of the GNU General Public
diff -urN oldtree/arch/ppc/amiga/ints.c newtree/arch/ppc/amiga/ints.c
--- oldtree/arch/ppc/amiga/ints.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/amiga/ints.c	2006-02-21 15:58:17.243525144 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/amiga/ints.c
- *
  *  Linux/m68k general interrupt handling code from arch/m68k/kernel/ints.c
  *  Needed to drive the m68k emulating IRQ hardware on the PowerUp boards.
  */
diff -urN oldtree/arch/ppc/boot/Makefile newtree/arch/ppc/boot/Makefile
--- oldtree/arch/ppc/boot/Makefile	2006-02-19 11:40:59.399434400 +0000
+++ newtree/arch/ppc/boot/Makefile	2006-02-21 15:58:17.246524688 +0000
@@ -1,6 +1,3 @@
-#
-# arch/ppc/boot/Makefile
-#
 # This file is subject to the terms and conditions of the GNU General Public
 # License.  See the file "COPYING" in the main directory of this archive
 # for more details.
diff -urN oldtree/arch/ppc/boot/common/Makefile newtree/arch/ppc/boot/common/Makefile
--- oldtree/arch/ppc/boot/common/Makefile	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/common/Makefile	2006-02-21 15:58:17.244524992 +0000
@@ -1,6 +1,3 @@
-#
-# arch/ppc/boot/common/Makefile
-#
 # This file is subject to the terms and conditions of the GNU General Public
 # License.  See the file "COPYING" in the main directory of this archive
 # for more details.
diff -urN oldtree/arch/ppc/boot/common/bootinfo.c newtree/arch/ppc/boot/common/bootinfo.c
--- oldtree/arch/ppc/boot/common/bootinfo.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/common/bootinfo.c	2006-02-21 15:58:17.244524992 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/common/bootinfo.c
- *
  * General bootinfo record utilities
  * Author: Randy Vinson <rvinson@mvista.com>
  *
diff -urN oldtree/arch/ppc/boot/common/misc-common.c newtree/arch/ppc/boot/common/misc-common.c
--- oldtree/arch/ppc/boot/common/misc-common.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/common/misc-common.c	2006-02-21 15:58:17.244524992 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/common/misc-common.c
- *
  * Misc. bootloader code (almost) all platforms can use
  *
  * Author: Johnnie Peters <jpeters@mvista.com>
diff -urN oldtree/arch/ppc/boot/common/ns16550.c newtree/arch/ppc/boot/common/ns16550.c
--- oldtree/arch/ppc/boot/common/ns16550.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/common/ns16550.c	2006-02-21 15:58:17.245524840 +0000
@@ -8,6 +8,9 @@
 #include <linux/serial_reg.h>
 #include <asm/serial.h>
 
+#if defined(CONFIG_XILINX_VIRTEX)
+#include <platforms/4xx/xparameters/xparameters.h>
+#endif
 #include "nonstdio.h"
 #include "serial.h"
 
diff -urN oldtree/arch/ppc/boot/common/serial_stub.c newtree/arch/ppc/boot/common/serial_stub.c
--- oldtree/arch/ppc/boot/common/serial_stub.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/common/serial_stub.c	2006-02-21 15:58:17.245524840 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/common/serial_stub.c
- *
  * This is a few stub routines to make the boot code cleaner looking when
  * there is no serial port support doesn't need to be closed, for example.
  *
diff -urN oldtree/arch/ppc/boot/common/util.S newtree/arch/ppc/boot/common/util.S
--- oldtree/arch/ppc/boot/common/util.S	2006-02-19 11:40:59.399434400 +0000
+++ newtree/arch/ppc/boot/common/util.S	2006-02-21 15:58:17.245524840 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/common/util.S
- *
  * Useful bootup functions, which are more easily done in asm than C.
  *
  * NOTE:  Be very very careful about the registers you use here.
diff -urN oldtree/arch/ppc/boot/include/mpc10x.h newtree/arch/ppc/boot/include/mpc10x.h
--- oldtree/arch/ppc/boot/include/mpc10x.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/include/mpc10x.h	2006-02-21 15:58:17.246524688 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/include/mpc10.h
- *
  * Common defines for the Motorola SPS MPC106/8240/107 Host bridge/Mem
  * ctrl/EPIC/etc.
  *
diff -urN oldtree/arch/ppc/boot/simple/Makefile newtree/arch/ppc/boot/simple/Makefile
--- oldtree/arch/ppc/boot/simple/Makefile	2006-02-19 11:40:59.402433944 +0000
+++ newtree/arch/ppc/boot/simple/Makefile	2006-02-21 15:58:17.248524384 +0000
@@ -192,6 +192,7 @@
 boot-$(CONFIG_8260)		+= embed_config.o
 boot-$(CONFIG_EP405)		+= embed_config.o
 boot-$(CONFIG_XILINX_ML300)	+= embed_config.o
+boot-$(CONFIG_XILINX_ML403)	+= embed_config.o
 boot-$(CONFIG_BSEIP)		+= iic.o
 boot-$(CONFIG_MBX)		+= iic.o pci.o qspan_pci.o
 boot-$(CONFIG_MV64X60)		+= misc-mv64x60.o
diff -urN oldtree/arch/ppc/boot/simple/cpc700_memory.c newtree/arch/ppc/boot/simple/cpc700_memory.c
--- oldtree/arch/ppc/boot/simple/cpc700_memory.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/simple/cpc700_memory.c	2006-02-21 15:58:17.246524688 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/common/cpc700_memory.c
- *
  * Find memory based upon settings in the CPC700 bridge
  *
  * Author: Dan Cox
diff -urN oldtree/arch/ppc/boot/simple/embed_config.c newtree/arch/ppc/boot/simple/embed_config.c
--- oldtree/arch/ppc/boot/simple/embed_config.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/simple/embed_config.c	2006-02-21 15:58:17.247524536 +0000
@@ -21,6 +21,9 @@
 #ifdef CONFIG_40x
 #include <asm/io.h>
 #endif
+#ifdef CONFIG_XILINX_VIRTEX
+#include <platforms/4xx/xparameters/xparameters.h>
+#endif
 extern unsigned long timebase_period_ns;
 
 /* For those boards that don't provide one.
@@ -742,7 +745,7 @@
 }
 #endif /* WILLOW */
 
-#ifdef CONFIG_XILINX_ML300
+#if defined(CONFIG_XILINX_ML300) || defined(CONFIG_XILINX_ML403)
 void
 embed_config(bd_t ** bdp)
 {
@@ -779,7 +782,7 @@
 	timebase_period_ns = 1000000000 / bd->bi_tbfreq;
 	/* see bi_tbfreq definition in arch/ppc/platforms/4xx/xilinx_ml300.h */
 }
-#endif /* CONFIG_XILINX_ML300 */
+#endif /* CONFIG_XILINX_ML300 || CONFIG_XILINX_ML403 */
 
 #ifdef CONFIG_IBM_OPENBIOS
 /* This could possibly work for all treeboot roms.
diff -urN oldtree/arch/ppc/boot/simple/head.S newtree/arch/ppc/boot/simple/head.S
--- oldtree/arch/ppc/boot/simple/head.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/simple/head.S	2006-02-21 15:58:17.247524536 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/simple/head.S
- *
  * Initial board bringup code for many different boards.
  *
  * Author: Tom Rini
@@ -65,6 +63,13 @@
 			 */
 #endif
 
+#if defined(CONFIG_XILINX_VIRTEX_4_FX)
+	/* PPC errata 213: only for Virtex-4 FX */
+	mfccr0  0
+	oris    0,0,0x50000000@h
+	mtccr0  0
+#endif
+
 	mflr	r3	/* Save our actual starting address. */
 
 	/* The following functions we call must not modify r3 or r4.....
diff -urN oldtree/arch/ppc/boot/simple/misc-chestnut.c newtree/arch/ppc/boot/simple/misc-chestnut.c
--- oldtree/arch/ppc/boot/simple/misc-chestnut.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/simple/misc-chestnut.c	2006-02-21 15:58:17.248524384 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/simple/misc-chestnut.c
- *
  * Setup for the IBM Chestnut (ibm-750fxgx_eval)
  *
  * Author: Mark A. Greer <mgreer@mvista.com>
diff -urN oldtree/arch/ppc/boot/simple/misc-cpci690.c newtree/arch/ppc/boot/simple/misc-cpci690.c
--- oldtree/arch/ppc/boot/simple/misc-cpci690.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/simple/misc-cpci690.c	2006-02-21 15:58:17.249524232 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/simple/misc-cpci690.c
- *
  * Add birec data for Force CPCI690 board.
  *
  * Author: Mark A. Greer <source@mvista.com>
diff -urN oldtree/arch/ppc/boot/simple/misc-ev64260.c newtree/arch/ppc/boot/simple/misc-ev64260.c
--- oldtree/arch/ppc/boot/simple/misc-ev64260.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/simple/misc-ev64260.c	2006-02-21 15:58:17.249524232 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/simple/misc-ev64260.c
- *
  * Host bridge init code for the Marvell/Galileo EV-64260-BP evaluation board
  * with a GT64260 onboard.
  *
diff -urN oldtree/arch/ppc/boot/simple/misc-ev64360.c newtree/arch/ppc/boot/simple/misc-ev64360.c
--- oldtree/arch/ppc/boot/simple/misc-ev64360.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/simple/misc-ev64360.c	2006-02-21 15:58:17.249524232 +0000
@@ -1,5 +1,4 @@
 /*
- * arch/ppc/boot/simple/misc-ev64360.c
  * Copyright (C) 2005 Lee Nicks <allinux@gmail.com>
  *
  * Based on arch/ppc/boot/simple/misc-katana.c from:
diff -urN oldtree/arch/ppc/boot/simple/misc-katana.c newtree/arch/ppc/boot/simple/misc-katana.c
--- oldtree/arch/ppc/boot/simple/misc-katana.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/simple/misc-katana.c	2006-02-21 15:58:17.250524080 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/simple/misc-katana.c
- *
  * Set up MPSC values to bootwrapper can prompt user.
  *
  * Author: Mark A. Greer <source@mvista.com>
diff -urN oldtree/arch/ppc/boot/simple/misc-mv64x60.c newtree/arch/ppc/boot/simple/misc-mv64x60.c
--- oldtree/arch/ppc/boot/simple/misc-mv64x60.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/simple/misc-mv64x60.c	2006-02-21 15:58:17.250524080 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/simple/misc-mv64x60.c
- *
  * Relocate bridge's register base and call board specific routine.
  *
  * Author: Mark A. Greer <source@mvista.com>
diff -urN oldtree/arch/ppc/boot/simple/misc-prep.c newtree/arch/ppc/boot/simple/misc-prep.c
--- oldtree/arch/ppc/boot/simple/misc-prep.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/simple/misc-prep.c	2006-02-21 15:58:17.250524080 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/simple/misc-prep.c
- *
  * Maintainer: Tom Rini <trini@kernel.crashing.org>
  *
  * In the past: Gary Thomas, Cort Dougan <cort@cs.nmt.edu>
diff -urN oldtree/arch/ppc/boot/simple/misc-radstone_ppc7d.c newtree/arch/ppc/boot/simple/misc-radstone_ppc7d.c
--- oldtree/arch/ppc/boot/simple/misc-radstone_ppc7d.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/simple/misc-radstone_ppc7d.c	2006-02-21 15:58:17.251523928 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/simple/misc-radstone_ppc7d.c
- *
  * Misc data for Radstone PPC7D board.
  *
  * Author: James Chapman <jchapman@katalix.com>
diff -urN oldtree/arch/ppc/boot/simple/misc-spruce.c newtree/arch/ppc/boot/simple/misc-spruce.c
--- oldtree/arch/ppc/boot/simple/misc-spruce.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/simple/misc-spruce.c	2006-02-21 15:58:17.251523928 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/spruce/misc.c
- *
  * Misc. bootloader code for IBM Spruce reference platform
  *
  * Authors: Johnnie Peters <jpeters@mvista.com>
diff -urN oldtree/arch/ppc/boot/simple/misc.c newtree/arch/ppc/boot/simple/misc.c
--- oldtree/arch/ppc/boot/simple/misc.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/simple/misc.c	2006-02-21 15:58:17.248524384 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/simple/misc.c
- *
  * Misc. bootloader code for many machines.  This assumes you have are using
  * a 6xx/7xx/74xx CPU in your machine.  This assumes the chunk of memory
  * below 8MB is free.  Finally, it assumes you have a NS16550-style uart for
diff -urN oldtree/arch/ppc/boot/simple/mpc10x_memory.c newtree/arch/ppc/boot/simple/mpc10x_memory.c
--- oldtree/arch/ppc/boot/simple/mpc10x_memory.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/simple/mpc10x_memory.c	2006-02-21 15:58:17.252523776 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/common/mpc10x_common.c
- *
  * A routine to find out how much memory the machine has.
  *
  * Based on:
diff -urN oldtree/arch/ppc/boot/simple/mpc52xx_tty.c newtree/arch/ppc/boot/simple/mpc52xx_tty.c
--- oldtree/arch/ppc/boot/simple/mpc52xx_tty.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/simple/mpc52xx_tty.c	2006-02-21 15:58:17.252523776 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/simple/mpc52xx_tty.c
- *
  * Minimal serial functions needed to send messages out a MPC52xx
  * Programmable Serial Controller (PSC).
  *
diff -urN oldtree/arch/ppc/boot/simple/mv64x60_tty.c newtree/arch/ppc/boot/simple/mv64x60_tty.c
--- oldtree/arch/ppc/boot/simple/mv64x60_tty.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/simple/mv64x60_tty.c	2006-02-21 15:58:17.253523624 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/simple/mv64x60_tty.c
- *
  * Bootloader version of the embedded MPSC/UART driver for the Marvell 64x60.
  * Note: Due to a GT64260A erratum, DMA will be used for UART input (via SDMA).
  *
diff -urN oldtree/arch/ppc/boot/simple/openbios.c newtree/arch/ppc/boot/simple/openbios.c
--- oldtree/arch/ppc/boot/simple/openbios.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/simple/openbios.c	2006-02-21 15:58:17.253523624 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/simple/openbios.c
- *
  * Copyright (c) 2005 DENX Software Engineering
  * Stefan Roese <sr@denx.de>
  *
diff -urN oldtree/arch/ppc/boot/simple/relocate.S newtree/arch/ppc/boot/simple/relocate.S
--- oldtree/arch/ppc/boot/simple/relocate.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/simple/relocate.S	2006-02-21 15:58:17.253523624 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/simple/relocate.S
- *
  * This is the common part of the loader relocation and initialization
  * process.  All of the board/processor specific initialization is
  * done before we get here.
diff -urN oldtree/arch/ppc/boot/utils/mkbugboot.c newtree/arch/ppc/boot/utils/mkbugboot.c
--- oldtree/arch/ppc/boot/utils/mkbugboot.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/boot/utils/mkbugboot.c	2006-02-21 15:58:17.254523472 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/boot/utils/mkbugboot.c
- *
  * Makes a Motorola PPCBUG ROM bootable image which can be flashed
  * into one of the FLASH banks on a Motorola PowerPlus board.
  *
diff -urN oldtree/arch/ppc/configs/ml300_defconfig newtree/arch/ppc/configs/ml300_defconfig
--- oldtree/arch/ppc/configs/ml300_defconfig	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/ppc/configs/ml300_defconfig	2006-02-21 15:58:17.254523472 +0000
@@ -0,0 +1,739 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.16-rc1
+# Wed Jan 18 00:49:20 2006
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_LBD=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+CONFIG_40x=y
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+# CONFIG_E500 is not set
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_KEXEC is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_4xx=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# IBM 4xx options
+#
+# CONFIG_BUBINGA is not set
+# CONFIG_CPCI405 is not set
+# CONFIG_EP405 is not set
+# CONFIG_REDWOOD_5 is not set
+# CONFIG_REDWOOD_6 is not set
+# CONFIG_SYCAMORE is not set
+# CONFIG_WALNUT is not set
+CONFIG_XILINX_ML300=y
+CONFIG_IBM405_ERR77=y
+CONFIG_IBM405_ERR51=y
+CONFIG_XILINX_VIRTEX=y
+CONFIG_EMBEDDEDBOOT=y
+# CONFIG_PPC4xx_DMA is not set
+CONFIG_PPC_GEN550=y
+CONFIG_UART0_TTYS0=y
+# CONFIG_UART0_TTYS1 is not set
+CONFIG_NOT_COHERENT_CACHE=y
+
+#
+# Platform options
+#
+# CONFIG_PC_KEYBOARD is not set
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,9600"
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_START=0xff100000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_BOOT_LOAD=0x00400000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON 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_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=65536
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
+
+#
+# PHY device support
+#
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+# CONFIG_IBM_EMAC is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+
+#
+# SN Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# 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_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# 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=y
+
+#
+# IBM 40x options
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_KGDB is not set
+CONFIG_XMON=y
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
diff -urN oldtree/arch/ppc/configs/ml403_defconfig newtree/arch/ppc/configs/ml403_defconfig
--- oldtree/arch/ppc/configs/ml403_defconfig	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/ppc/configs/ml403_defconfig	2006-02-21 15:58:17.257523016 +0000
@@ -0,0 +1,740 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.16-rc1
+# Wed Jan 18 01:11:41 2006
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_LBD=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+CONFIG_40x=y
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+# CONFIG_E500 is not set
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_KEXEC is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_4xx=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# IBM 4xx options
+#
+# CONFIG_BUBINGA is not set
+# CONFIG_CPCI405 is not set
+# CONFIG_EP405 is not set
+# CONFIG_REDWOOD_5 is not set
+# CONFIG_REDWOOD_6 is not set
+# CONFIG_SYCAMORE is not set
+# CONFIG_WALNUT is not set
+# CONFIG_XILINX_ML300 is not set
+CONFIG_XILINX_ML403=y
+CONFIG_IBM405_ERR77=y
+CONFIG_IBM405_ERR51=y
+CONFIG_XILINX_VIRTEX=y
+CONFIG_EMBEDDEDBOOT=y
+# CONFIG_PPC4xx_DMA is not set
+CONFIG_PPC_GEN550=y
+CONFIG_UART0_TTYS0=y
+# CONFIG_UART0_TTYS1 is not set
+CONFIG_NOT_COHERENT_CACHE=y
+
+#
+# Platform options
+#
+# CONFIG_PC_KEYBOARD is not set
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,9600"
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_START=0xff100000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_BOOT_LOAD=0x00400000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON 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_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=65536
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
+
+#
+# PHY device support
+#
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+# CONFIG_IBM_EMAC is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+
+#
+# SN Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# 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_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# 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=y
+
+#
+# IBM 40x options
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_KGDB is not set
+CONFIG_XMON=y
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
diff -urN oldtree/arch/ppc/kernel/head_44x.S newtree/arch/ppc/kernel/head_44x.S
--- oldtree/arch/ppc/kernel/head_44x.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/kernel/head_44x.S	2006-02-21 15:58:17.260522560 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/kernel/head_44x.S
- *
  * Kernel execution entry point code.
  *
  *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
diff -urN oldtree/arch/ppc/kernel/head_8xx.S newtree/arch/ppc/kernel/head_8xx.S
--- oldtree/arch/ppc/kernel/head_8xx.S	2006-02-19 11:40:59.412432424 +0000
+++ newtree/arch/ppc/kernel/head_8xx.S	2006-02-21 15:58:17.261522408 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/kernel/except_8xx.S
- *
  *  PowerPC version
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
diff -urN oldtree/arch/ppc/kernel/head_fsl_booke.S newtree/arch/ppc/kernel/head_fsl_booke.S
--- oldtree/arch/ppc/kernel/head_fsl_booke.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/kernel/head_fsl_booke.S	2006-02-21 15:58:17.263522104 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/kernel/head_fsl_booke.S
- *
  * Kernel execution entry point code.
  *
  *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
@@ -316,6 +314,7 @@
 	 */
 	lis	r2,DBCR0_IDM@h
 	mtspr	SPRN_DBCR0,r2
+	isync
 	/* clear any residual debug events */
 	li	r2,-1
 	mtspr	SPRN_DBSR,r2
@@ -1002,12 +1001,15 @@
 _GLOBAL(abort)
 	li	r13,0
         mtspr   SPRN_DBCR0,r13		/* disable all debug events */
+	isync
 	mfmsr	r13
 	ori	r13,r13,MSR_DE@l	/* Enable Debug Events */
 	mtmsr	r13
+	isync
         mfspr   r13,SPRN_DBCR0
         lis	r13,(DBCR0_IDM|DBCR0_RST_CHIP)@h
         mtspr   SPRN_DBCR0,r13
+	isync
 
 _GLOBAL(set_context)
 
diff -urN oldtree/arch/ppc/kernel/traps.c newtree/arch/ppc/kernel/traps.c
--- oldtree/arch/ppc/kernel/traps.c	2006-02-19 11:40:59.452426344 +0000
+++ newtree/arch/ppc/kernel/traps.c	2006-02-21 15:58:17.263522104 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/kernel/traps.c
- *
  *  Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
  *
  *  This program is free software; you can redistribute it and/or
diff -urN oldtree/arch/ppc/lib/rheap.c newtree/arch/ppc/lib/rheap.c
--- oldtree/arch/ppc/lib/rheap.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/lib/rheap.c	2006-02-21 15:58:17.264521952 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/rheap.c
- *
  * A Remote Heap.  Remote means that we don't touch the memory that the
  * heap points to. Normal heap implementations use the memory they manage
  * to place their list. We cannot do that because the memory we manage may
diff -urN oldtree/arch/ppc/math-emu/math.c newtree/arch/ppc/math-emu/math.c
--- oldtree/arch/ppc/math-emu/math.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/math-emu/math.c	2006-02-21 15:58:17.265521800 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/math-emu/math.c
- *
  * Copyright (C) 1999  Eddie C. Dost  (ecd@atecom.com)
  */
 
diff -urN oldtree/arch/ppc/mm/44x_mmu.c newtree/arch/ppc/mm/44x_mmu.c
--- oldtree/arch/ppc/mm/44x_mmu.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/mm/44x_mmu.c	2006-02-21 15:58:17.266521648 +0000
@@ -104,7 +104,7 @@
 
 	/* Determine number of entries necessary to cover lowmem */
 	pinned_tlbs = (unsigned int)
-		(_ALIGN(total_lowmem, PPC44x_PIN_SIZE) >> PPC44x_PIN_SHIFT);
+		(_ALIGN(total_lowmem, PPC_PIN_SIZE) >> PPC44x_PIN_SHIFT);
 
 	/* Write upper watermark to save location */
 	tlb_44x_hwater = PPC44x_LOW_SLOT - pinned_tlbs;
@@ -112,7 +112,7 @@
 	/* If necessary, set additional pinned TLBs */
 	if (pinned_tlbs > 1)
 		for (i = (PPC44x_LOW_SLOT-(pinned_tlbs-1)); i < PPC44x_LOW_SLOT; i++) {
-			unsigned int phys_addr = (PPC44x_LOW_SLOT-i) * PPC44x_PIN_SIZE;
+			unsigned int phys_addr = (PPC44x_LOW_SLOT-i) * PPC_PIN_SIZE;
 			ppc44x_pin_tlb(i, phys_addr+PAGE_OFFSET, phys_addr);
 		}
 
diff -urN oldtree/arch/ppc/mm/fault.c newtree/arch/ppc/mm/fault.c
--- oldtree/arch/ppc/mm/fault.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/mm/fault.c	2006-02-21 15:58:17.267521496 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/mm/fault.c
- *
  *  PowerPC version
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *
diff -urN oldtree/arch/ppc/mm/hashtable.S newtree/arch/ppc/mm/hashtable.S
--- oldtree/arch/ppc/mm/hashtable.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/mm/hashtable.S	2006-02-21 15:58:17.267521496 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/kernel/hashtable.S
- *
  *  $Id: hashtable.S,v 1.6 1999/10/08 01:56:15 paulus Exp $
  *
  *  PowerPC version
diff -urN oldtree/arch/ppc/platforms/4xx/Kconfig newtree/arch/ppc/platforms/4xx/Kconfig
--- oldtree/arch/ppc/platforms/4xx/Kconfig	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/Kconfig	2006-02-21 15:58:17.286518608 +0000
@@ -57,6 +57,10 @@
 	help
 	  This option enables support for the Xilinx ML300 evaluation board.
 
+config XILINX_ML403
+	bool "Xilinx-ML403"
+	help
+	  This option enables support for the Xilinx ML403 evaluation board.
 endchoice
 
 choice
@@ -172,11 +176,6 @@
 	depends on ASH || BAMBOO || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || YUCCA || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT
 	default y
 
-config XILINX_OCP
-	bool
-	depends on XILINX_ML300
-	default y
-
 config IBM_EMAC4
 	bool
 	depends on 440GX || 440SP || 440SPE
@@ -208,11 +207,21 @@
 	depends on SYCAMORE
 	default y
 
-config VIRTEX_II_PRO
+config XILINX_VIRTEX_II_PRO
 	bool
 	depends on XILINX_ML300
 	default y
 
+config XILINX_VIRTEX_4_FX
+	bool
+	depends on XILINX_ML403
+	default y
+
+config XILINX_VIRTEX
+	bool
+	depends on XILINX_VIRTEX_II_PRO || XILINX_VIRTEX_4_FX
+	default y
+
 config STB03xxx
 	bool
 	depends on REDWOOD_5 || REDWOOD_6
@@ -220,7 +229,7 @@
 
 config EMBEDDEDBOOT
 	bool
-	depends on EP405 || XILINX_ML300
+	depends on EP405 || XILINX_ML300 || XILINX_ML403
 	default y
 
 config IBM_OPENBIOS
diff -urN oldtree/arch/ppc/platforms/4xx/Makefile newtree/arch/ppc/platforms/4xx/Makefile
--- oldtree/arch/ppc/platforms/4xx/Makefile	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/Makefile	2006-02-21 15:58:17.332511616 +0000
@@ -14,6 +14,7 @@
 obj-$(CONFIG_SYCAMORE)		+= sycamore.o
 obj-$(CONFIG_WALNUT)		+= walnut.o
 obj-$(CONFIG_XILINX_ML300)	+= xilinx_ml300.o
+obj-$(CONFIG_XILINX_ML403)	+= xilinx_ml403.o
 
 obj-$(CONFIG_405GP)		+= ibm405gp.o
 obj-$(CONFIG_REDWOOD_5)		+= ibmstb4.o
@@ -26,4 +27,5 @@
 obj-$(CONFIG_440SPE)		+= ppc440spe.o
 obj-$(CONFIG_405EP)		+= ibm405ep.o
 obj-$(CONFIG_405GPR)		+= ibm405gpr.o
-obj-$(CONFIG_VIRTEX_II_PRO)	+= virtex-ii_pro.o
+obj-$(CONFIG_XILINX_VIRTEX)	+= virtex.o
+
diff -urN oldtree/arch/ppc/platforms/4xx/bamboo.c newtree/arch/ppc/platforms/4xx/bamboo.c
--- oldtree/arch/ppc/platforms/4xx/bamboo.c	2006-02-19 11:40:59.454426040 +0000
+++ newtree/arch/ppc/platforms/4xx/bamboo.c	2006-02-21 15:58:17.268521344 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/bamboo.c
- *
  * Bamboo board specific routines
  *
  * Wade Farnsworth <wfarnsworth@mvista.com>
diff -urN oldtree/arch/ppc/platforms/4xx/bamboo.h newtree/arch/ppc/platforms/4xx/bamboo.h
--- oldtree/arch/ppc/platforms/4xx/bamboo.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/bamboo.h	2006-02-21 15:58:17.269521192 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/bamboo.h
- *
  * Bamboo board definitions
  *
  * Wade Farnsworth <wfarnsworth@mvista.com>
diff -urN oldtree/arch/ppc/platforms/4xx/bubinga.h newtree/arch/ppc/platforms/4xx/bubinga.h
--- oldtree/arch/ppc/platforms/4xx/bubinga.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/bubinga.h	2006-02-21 15:58:17.269521192 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/bubinga.h
- *
  * Bubinga board definitions
  *
  * Copyright (c) 2005 DENX Software Engineering
diff -urN oldtree/arch/ppc/platforms/4xx/cpci405.c newtree/arch/ppc/platforms/4xx/cpci405.c
--- oldtree/arch/ppc/platforms/4xx/cpci405.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/cpci405.c	2006-02-21 15:58:17.277519976 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/cpci405.c
- *
  * Board setup routines for the esd CPCI-405 cPCI Board.
  *
  * Author: Stefan Roese
diff -urN oldtree/arch/ppc/platforms/4xx/ebony.c newtree/arch/ppc/platforms/4xx/ebony.c
--- oldtree/arch/ppc/platforms/4xx/ebony.c	2006-02-19 11:40:59.454426040 +0000
+++ newtree/arch/ppc/platforms/4xx/ebony.c	2006-02-21 15:58:17.278519824 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ebony.c
- *
  * Ebony board specific routines
  *
  * Matt Porter <mporter@kernel.crashing.org>
diff -urN oldtree/arch/ppc/platforms/4xx/ebony.h newtree/arch/ppc/platforms/4xx/ebony.h
--- oldtree/arch/ppc/platforms/4xx/ebony.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ebony.h	2006-02-21 15:58:17.278519824 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/ebony.h
- *
  * Ebony board definitions
  *
  * Matt Porter <mporter@mvista.com>
diff -urN oldtree/arch/ppc/platforms/4xx/ep405.c newtree/arch/ppc/platforms/4xx/ep405.c
--- oldtree/arch/ppc/platforms/4xx/ep405.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ep405.c	2006-02-21 15:58:17.278519824 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ep405.c
- *
  * Embedded Planet 405GP board
  * http://www.embeddedplanet.com
  *
diff -urN oldtree/arch/ppc/platforms/4xx/ep405.h newtree/arch/ppc/platforms/4xx/ep405.h
--- oldtree/arch/ppc/platforms/4xx/ep405.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ep405.h	2006-02-21 15:58:17.279519672 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ep405.h
- *
  * Embedded Planet 405GP board
  * http://www.embeddedplanet.com
  *
diff -urN oldtree/arch/ppc/platforms/4xx/ibm405ep.c newtree/arch/ppc/platforms/4xx/ibm405ep.c
--- oldtree/arch/ppc/platforms/4xx/ibm405ep.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ibm405ep.c	2006-02-21 15:58:17.279519672 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/ibm405ep.c
- *
  * Support for IBM PPC 405EP processors.
  *
  * Author: SAW (IBM), derived from ibmnp405l.c.
diff -urN oldtree/arch/ppc/platforms/4xx/ibm405ep.h newtree/arch/ppc/platforms/4xx/ibm405ep.h
--- oldtree/arch/ppc/platforms/4xx/ibm405ep.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ibm405ep.h	2006-02-21 15:58:17.279519672 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ibm405ep.h
- *
  * IBM PPC 405EP processor defines.
  *
  * Author: SAW (IBM), derived from ibm405gp.h.
diff -urN oldtree/arch/ppc/platforms/4xx/ibm405gp.h newtree/arch/ppc/platforms/4xx/ibm405gp.h
--- oldtree/arch/ppc/platforms/4xx/ibm405gp.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ibm405gp.h	2006-02-21 15:58:17.279519672 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ibm405gp.h
- *
  * Author: Armin Kuster akuster@mvista.com
  *
  * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
diff -urN oldtree/arch/ppc/platforms/4xx/ibm405gpr.c newtree/arch/ppc/platforms/4xx/ibm405gpr.c
--- oldtree/arch/ppc/platforms/4xx/ibm405gpr.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ibm405gpr.c	2006-02-21 15:58:17.280519520 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ibm405gpr.c
- *
  * Author: Armin Kuster <akuster@mvista.com>
  *
  * 2002 (c) MontaVista, Software, Inc.  This file is licensed under
diff -urN oldtree/arch/ppc/platforms/4xx/ibm405gpr.h newtree/arch/ppc/platforms/4xx/ibm405gpr.h
--- oldtree/arch/ppc/platforms/4xx/ibm405gpr.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ibm405gpr.h	2006-02-21 15:58:17.280519520 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ibm405gpr.h
- *
  * Author: Armin Kuster <akuster@mvista.com>
  *
  * 2002 (c) MontaVista, Software, Inc.  This file is licensed under
diff -urN oldtree/arch/ppc/platforms/4xx/ibm440ep.c newtree/arch/ppc/platforms/4xx/ibm440ep.c
--- oldtree/arch/ppc/platforms/4xx/ibm440ep.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ibm440ep.c	2006-02-21 15:58:17.281519368 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ibm440ep.c
- *
  * PPC440EP I/O descriptions
  *
  * Wade Farnsworth <wfarnsworth@mvista.com>
diff -urN oldtree/arch/ppc/platforms/4xx/ibm440ep.h newtree/arch/ppc/platforms/4xx/ibm440ep.h
--- oldtree/arch/ppc/platforms/4xx/ibm440ep.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ibm440ep.h	2006-02-21 15:58:17.281519368 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ibm440ep.h
- *
  * PPC440EP definitions
  *
  * Wade Farnsworth <wfarnsworth@mvista.com>
diff -urN oldtree/arch/ppc/platforms/4xx/ibm440gp.c newtree/arch/ppc/platforms/4xx/ibm440gp.c
--- oldtree/arch/ppc/platforms/4xx/ibm440gp.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ibm440gp.c	2006-02-21 15:58:17.281519368 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ibm440gp.c
- *
  * PPC440GP I/O descriptions
  *
  * Matt Porter <mporter@mvista.com>
diff -urN oldtree/arch/ppc/platforms/4xx/ibm440gp.h newtree/arch/ppc/platforms/4xx/ibm440gp.h
--- oldtree/arch/ppc/platforms/4xx/ibm440gp.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ibm440gp.h	2006-02-21 15:58:17.282519216 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ibm440gp.h
- *
  * PPC440GP definitions
  *
  * Roland Dreier <roland@digitalvampire.org>
diff -urN oldtree/arch/ppc/platforms/4xx/ibm440gx.c newtree/arch/ppc/platforms/4xx/ibm440gx.c
--- oldtree/arch/ppc/platforms/4xx/ibm440gx.c	2006-02-19 11:40:59.455425888 +0000
+++ newtree/arch/ppc/platforms/4xx/ibm440gx.c	2006-02-21 15:58:17.282519216 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ibm440gx.c
- *
  * PPC440GX I/O descriptions
  *
  * Matt Porter <mporter@mvista.com>
diff -urN oldtree/arch/ppc/platforms/4xx/ibm440gx.h newtree/arch/ppc/platforms/4xx/ibm440gx.h
--- oldtree/arch/ppc/platforms/4xx/ibm440gx.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ibm440gx.h	2006-02-21 15:58:17.283519064 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/ibm440gx.h
- *
  * PPC440GX definitions
  *
  * Matt Porter <mporter@mvista.com>
diff -urN oldtree/arch/ppc/platforms/4xx/ibm440sp.c newtree/arch/ppc/platforms/4xx/ibm440sp.c
--- oldtree/arch/ppc/platforms/4xx/ibm440sp.c	2006-02-19 11:40:59.456425736 +0000
+++ newtree/arch/ppc/platforms/4xx/ibm440sp.c	2006-02-21 15:58:17.283519064 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ibm440sp.c
- *
  * PPC440SP I/O descriptions
  *
  * Matt Porter <mporter@kernel.crashing.org>
diff -urN oldtree/arch/ppc/platforms/4xx/ibm440sp.h newtree/arch/ppc/platforms/4xx/ibm440sp.h
--- oldtree/arch/ppc/platforms/4xx/ibm440sp.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ibm440sp.h	2006-02-21 15:58:17.283519064 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ibm440sp.h
- *
  * PPC440SP definitions
  *
  * Matt Porter <mporter@kernel.crashing.org>
diff -urN oldtree/arch/ppc/platforms/4xx/ibmnp405h.c newtree/arch/ppc/platforms/4xx/ibmnp405h.c
--- oldtree/arch/ppc/platforms/4xx/ibmnp405h.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ibmnp405h.c	2006-02-21 15:58:17.284518912 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ibmnp405h.c
- *
  * Author: Armin Kuster <akuster@mvista.com>
  *
  * 2000-2002 (c) MontaVista, Software, Inc.  This file is licensed under
diff -urN oldtree/arch/ppc/platforms/4xx/ibmnp405h.h newtree/arch/ppc/platforms/4xx/ibmnp405h.h
--- oldtree/arch/ppc/platforms/4xx/ibmnp405h.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ibmnp405h.h	2006-02-21 15:58:17.284518912 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ibmnp405h.h
- *
  * Author: Armin Kuster <akuster@mvista.com>
  *
  * 2002 (c) MontaVista, Software, Inc.  This file is licensed under
diff -urN oldtree/arch/ppc/platforms/4xx/ibmstb4.c newtree/arch/ppc/platforms/4xx/ibmstb4.c
--- oldtree/arch/ppc/platforms/4xx/ibmstb4.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ibmstb4.c	2006-02-21 15:58:17.285518760 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ibmstb4.c
- *
  * Author: Armin Kuster <akuster@mvista.com>
  *
  * 2000-2001 (c) MontaVista, Software, Inc.  This file is licensed under
diff -urN oldtree/arch/ppc/platforms/4xx/ibmstb4.h newtree/arch/ppc/platforms/4xx/ibmstb4.h
--- oldtree/arch/ppc/platforms/4xx/ibmstb4.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ibmstb4.h	2006-02-21 15:58:17.285518760 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ibmstb4.h
- *
  * Author: Armin Kuster <akuster@mvista.com>
  *
  * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
diff -urN oldtree/arch/ppc/platforms/4xx/ibmstbx25.c newtree/arch/ppc/platforms/4xx/ibmstbx25.c
--- oldtree/arch/ppc/platforms/4xx/ibmstbx25.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ibmstbx25.c	2006-02-21 15:58:17.285518760 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ibmstbx25.c
- *
  * Author: Armin Kuster <akuster@mvista.com>
  *
  * 2000-2002 (c) MontaVista, Software, Inc.  This file is licensed under
diff -urN oldtree/arch/ppc/platforms/4xx/ibmstbx25.h newtree/arch/ppc/platforms/4xx/ibmstbx25.h
--- oldtree/arch/ppc/platforms/4xx/ibmstbx25.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ibmstbx25.h	2006-02-21 15:58:17.286518608 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ibmstbx25.h
- *
  * Author: Armin Kuster <akuster@mvista.com>
  *
  * 2002 (c) MontaVista, Software, Inc.  This file is licensed under
diff -urN oldtree/arch/ppc/platforms/4xx/luan.c newtree/arch/ppc/platforms/4xx/luan.c
--- oldtree/arch/ppc/platforms/4xx/luan.c	2006-02-19 11:40:59.456425736 +0000
+++ newtree/arch/ppc/platforms/4xx/luan.c	2006-02-21 15:58:17.287518456 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/luan.c
- *
  * Luan board specific routines
  *
  * Matt Porter <mporter@kernel.crashing.org>
diff -urN oldtree/arch/ppc/platforms/4xx/luan.h newtree/arch/ppc/platforms/4xx/luan.h
--- oldtree/arch/ppc/platforms/4xx/luan.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/luan.h	2006-02-21 15:58:17.287518456 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/luan.h
- *
  * Luan board definitions
  *
  * Matt Porter <mporter@kernel.crashing.org>
diff -urN oldtree/arch/ppc/platforms/4xx/ocotea.c newtree/arch/ppc/platforms/4xx/ocotea.c
--- oldtree/arch/ppc/platforms/4xx/ocotea.c	2006-02-19 11:40:59.456425736 +0000
+++ newtree/arch/ppc/platforms/4xx/ocotea.c	2006-02-21 15:58:17.332511616 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ocotea.c
- *
  * Ocotea board specific routines
  *
  * Matt Porter <mporter@kernel.crashing.org>
diff -urN oldtree/arch/ppc/platforms/4xx/ocotea.h newtree/arch/ppc/platforms/4xx/ocotea.h
--- oldtree/arch/ppc/platforms/4xx/ocotea.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ocotea.h	2006-02-21 15:58:17.333511464 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/ocotea.h
- *
  * Ocotea board definitions
  *
  * Matt Porter <mporter@kernel.crashing.org>
diff -urN oldtree/arch/ppc/platforms/4xx/ppc440spe.c newtree/arch/ppc/platforms/4xx/ppc440spe.c
--- oldtree/arch/ppc/platforms/4xx/ppc440spe.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ppc440spe.c	2006-02-21 15:58:17.333511464 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ppc440spe.c
- *
  * PPC440SPe I/O descriptions
  *
  * Roland Dreier <rolandd@cisco.com>
diff -urN oldtree/arch/ppc/platforms/4xx/ppc440spe.h newtree/arch/ppc/platforms/4xx/ppc440spe.h
--- oldtree/arch/ppc/platforms/4xx/ppc440spe.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/ppc440spe.h	2006-02-21 15:58:17.333511464 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/ibm440spe.h
- *
  * PPC440SPe definitions
  *
  * Roland Dreier <rolandd@cisco.com>
diff -urN oldtree/arch/ppc/platforms/4xx/redwood5.c newtree/arch/ppc/platforms/4xx/redwood5.c
--- oldtree/arch/ppc/platforms/4xx/redwood5.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/redwood5.c	2006-02-21 15:58:17.334511312 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/redwood5.c
- *
  * Support for the IBM redwood5 eval board file
  *
  * Author: Armin Kuster <akuster@mvista.com>
diff -urN oldtree/arch/ppc/platforms/4xx/redwood5.h newtree/arch/ppc/platforms/4xx/redwood5.h
--- oldtree/arch/ppc/platforms/4xx/redwood5.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/redwood5.h	2006-02-21 15:58:17.334511312 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/redwood5.h
- *
  * Macros, definitions, and data structures specific to the IBM PowerPC
  * STB03xxx "Redwood" evaluation board.
  *
diff -urN oldtree/arch/ppc/platforms/4xx/redwood6.c newtree/arch/ppc/platforms/4xx/redwood6.c
--- oldtree/arch/ppc/platforms/4xx/redwood6.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/redwood6.c	2006-02-21 15:58:17.334511312 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/redwood6.c
- *
  * Author: Armin Kuster <akuster@mvista.com>
  *
  * 2002 (c) MontaVista, Software, Inc.  This file is licensed under
diff -urN oldtree/arch/ppc/platforms/4xx/redwood6.h newtree/arch/ppc/platforms/4xx/redwood6.h
--- oldtree/arch/ppc/platforms/4xx/redwood6.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/redwood6.h	2006-02-21 15:58:17.335511160 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/redwood6.h
- *
  * Macros, definitions, and data structures specific to the IBM PowerPC
  * STBx25xx "Redwood6" evaluation board.
  *
diff -urN oldtree/arch/ppc/platforms/4xx/sycamore.c newtree/arch/ppc/platforms/4xx/sycamore.c
--- oldtree/arch/ppc/platforms/4xx/sycamore.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/sycamore.c	2006-02-21 15:58:17.335511160 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/sycamore.c
- *
  * Architecture- / platform-specific boot-time initialization code for
  * IBM PowerPC 4xx based boards.
  *
diff -urN oldtree/arch/ppc/platforms/4xx/sycamore.h newtree/arch/ppc/platforms/4xx/sycamore.h
--- oldtree/arch/ppc/platforms/4xx/sycamore.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/sycamore.h	2006-02-21 15:58:17.335511160 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/sycamore.h
- *
  * Sycamore board definitions
  *
  * Copyright (c) 2005 DENX Software Engineering
diff -urN oldtree/arch/ppc/platforms/4xx/virtex-ii_pro.c newtree/arch/ppc/platforms/4xx/virtex-ii_pro.c
--- oldtree/arch/ppc/platforms/4xx/virtex-ii_pro.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/virtex-ii_pro.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,60 +0,0 @@
-/*
- * arch/ppc/platforms/4xx/virtex-ii_pro.c
- *
- * Author: MontaVista Software, Inc.
- *         source@mvista.com
- *
- * 2002-2004 (c) MontaVista Software, Inc.  This file is licensed under the
- * terms of the GNU General Public License version 2.  This program is licensed
- * "as is" without any warranty of any kind, whether express or implied.
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <asm/ocp.h>
-#include "virtex-ii_pro.h"
-
-/* Have OCP take care of the serial ports. */
-struct ocp_def core_ocp[] = {
-#ifdef XPAR_UARTNS550_0_BASEADDR
-	{ .vendor	= OCP_VENDOR_XILINX,
-	  .function	= OCP_FUNC_16550,
-	  .index	= 0,
-	  .paddr	= XPAR_UARTNS550_0_BASEADDR,
-	  .irq		= XPAR_INTC_0_UARTNS550_0_VEC_ID,
-	  .pm		= OCP_CPM_NA
-	},
-#ifdef XPAR_UARTNS550_1_BASEADDR
-	{ .vendor	= OCP_VENDOR_XILINX,
-	  .function	= OCP_FUNC_16550,
-	  .index	= 1,
-	  .paddr	= XPAR_UARTNS550_1_BASEADDR,
-	  .irq		= XPAR_INTC_0_UARTNS550_1_VEC_ID,
-	  .pm		= OCP_CPM_NA
-	},
-#ifdef XPAR_UARTNS550_2_BASEADDR
-	{ .vendor	= OCP_VENDOR_XILINX,
-	  .function	= OCP_FUNC_16550,
-	  .index	= 2,
-	  .paddr	= XPAR_UARTNS550_2_BASEADDR,
-	  .irq		= XPAR_INTC_0_UARTNS550_2_VEC_ID,
-	  .pm		= OCP_CPM_NA
-	},
-#ifdef XPAR_UARTNS550_3_BASEADDR
-	{ .vendor	= OCP_VENDOR_XILINX,
-	  .function	= OCP_FUNC_16550,
-	  .index	= 3,
-	  .paddr	= XPAR_UARTNS550_3_BASEADDR,
-	  .irq		= XPAR_INTC_0_UARTNS550_3_VEC_ID,
-	  .pm		= OCP_CPM_NA
-	},
-#ifdef XPAR_UARTNS550_4_BASEADDR
-#error Edit this file to add more devices.
-#endif			/* 4 */
-#endif			/* 3 */
-#endif			/* 2 */
-#endif			/* 1 */
-#endif			/* 0 */
-	{ .vendor	= OCP_VENDOR_INVALID
-	}
-};
diff -urN oldtree/arch/ppc/platforms/4xx/virtex-ii_pro.h newtree/arch/ppc/platforms/4xx/virtex-ii_pro.h
--- oldtree/arch/ppc/platforms/4xx/virtex-ii_pro.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/virtex-ii_pro.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,99 +0,0 @@
-/*
- * arch/ppc/platforms/4xx/virtex-ii_pro.h
- *
- * Include file that defines the Xilinx Virtex-II Pro processor
- *
- * Author: MontaVista Software, Inc.
- *         source@mvista.com
- *
- * 2002-2004 (c) MontaVista Software, Inc.  This file is licensed under the
- * terms of the GNU General Public License version 2.  This program is licensed
- * "as is" without any warranty of any kind, whether express or implied.
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_VIRTEXIIPRO_H__
-#define __ASM_VIRTEXIIPRO_H__
-
-#include <linux/config.h>
-#include <asm/xparameters.h>
-
-/* serial defines */
-
-#define RS_TABLE_SIZE  4	/* change this and add more devices below
-				   if you have more then 4 16x50 UARTs */
-
-#define BASE_BAUD		(XPAR_UARTNS550_0_CLOCK_FREQ_HZ/16)
-
-/* The serial ports in the Virtex-II Pro have each I/O byte in the
- * LSByte of a word.  This means that iomem_reg_shift needs to be 2 to
- * change the byte offsets into word offsets.  In addition the base
- * addresses need to have 3 added to them to get to the LSByte.
- */
-#define STD_UART_OP(num)						 \
-	{ 0, BASE_BAUD, 0, XPAR_INTC_0_UARTNS550_##num##_VEC_ID,	 \
-		ASYNC_BOOT_AUTOCONF,		 			 \
-		.iomem_base = (u8 *)XPAR_UARTNS550_##num##_BASEADDR + 3, \
-		.iomem_reg_shift = 2,					 \
-		.io_type = SERIAL_IO_MEM},
-
-#if defined(XPAR_INTC_0_UARTNS550_0_VEC_ID)
-#define ML300_UART0 STD_UART_OP(0)
-#else
-#define ML300_UART0
-#endif
-
-#if defined(XPAR_INTC_0_UARTNS550_1_VEC_ID)
-#define ML300_UART1 STD_UART_OP(1)
-#else
-#define ML300_UART1
-#endif
-
-#if defined(XPAR_INTC_0_UARTNS550_2_VEC_ID)
-#define ML300_UART2 STD_UART_OP(2)
-#else
-#define ML300_UART2
-#endif
-
-#if defined(XPAR_INTC_0_UARTNS550_3_VEC_ID)
-#define ML300_UART3 STD_UART_OP(3)
-#else
-#define ML300_UART3
-#endif
-
-#if defined(XPAR_INTC_0_UARTNS550_4_VEC_ID)
-#error Edit this file to add more devices.
-#elif defined(XPAR_INTC_0_UARTNS550_3_VEC_ID)
-#define NR_SER_PORTS	4
-#elif defined(XPAR_INTC_0_UARTNS550_2_VEC_ID)
-#define NR_SER_PORTS	3
-#elif defined(XPAR_INTC_0_UARTNS550_1_VEC_ID)
-#define NR_SER_PORTS	2
-#elif defined(XPAR_INTC_0_UARTNS550_0_VEC_ID)
-#define NR_SER_PORTS	1
-#else
-#define NR_SER_PORTS	0
-#endif
-
-#if defined(CONFIG_UART0_TTYS0)
-#define SERIAL_PORT_DFNS	\
-	ML300_UART0		\
-	ML300_UART1		\
-	ML300_UART2		\
-	ML300_UART3
-#endif
-
-#if defined(CONFIG_UART0_TTYS1)
-#define SERIAL_PORT_DFNS	\
-	ML300_UART1		\
-	ML300_UART0		\
-	ML300_UART2		\
-	ML300_UART3
-#endif
-
-#define DCRN_CPMFR_BASE	0
-
-#include <asm/ibm405.h>
-
-#endif				/* __ASM_VIRTEXIIPRO_H__ */
-#endif				/* __KERNEL__ */
diff -urN oldtree/arch/ppc/platforms/4xx/virtex.c newtree/arch/ppc/platforms/4xx/virtex.c
--- oldtree/arch/ppc/platforms/4xx/virtex.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/virtex.c	2006-02-21 15:58:17.336511008 +0000
@@ -0,0 +1,56 @@
+/*
+ * Virtex-II Pro & Virtex-4 FX common infrastructure
+ *
+ * Maintainer: Grant Likely <grant.likely@secretlab.ca>
+ *
+ * Copyright 2005 Secret Lab Technologies Ltd.
+ * Copyright 2005 General Dynamics Canada Ltd.
+ * Copyright 2005 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/serial_8250.h>
+#include <asm/ppc_sys.h>
+#include <platforms/4xx/virtex.h>
+#include <platforms/4xx/xparameters/xparameters.h>
+
+#define XPAR_UART(num) { \
+		.mapbase  = XPAR_UARTNS550_##num##_BASEADDR + 3, \
+		.irq	  = XPAR_INTC_0_UARTNS550_##num##_VEC_ID, \
+		.iotype	  = UPIO_MEM, \
+		.uartclk  = XPAR_UARTNS550_##num##_CLOCK_FREQ_HZ, \
+		.flags	  = UPF_BOOT_AUTOCONF, \
+		.regshift = 2, \
+	}
+
+struct plat_serial8250_port serial_platform_data[] = {
+#ifdef XPAR_UARTNS550_0_BASEADDR
+	XPAR_UART(0),
+#endif
+#ifdef XPAR_UARTNS550_1_BASEADDR
+	XPAR_UART(1),
+#endif
+#ifdef XPAR_UARTNS550_2_BASEADDR
+	XPAR_UART(2),
+#endif
+#ifdef XPAR_UARTNS550_3_BASEADDR
+	XPAR_UART(3),
+#endif
+	{ }, /* terminated by empty record */
+};
+
+struct platform_device ppc_sys_platform_devices[] = {
+	[VIRTEX_UART] = {
+		.name		= "serial8250",
+		.id		= 0,
+		.dev.platform_data = serial_platform_data,
+	},
+};
+
diff -urN oldtree/arch/ppc/platforms/4xx/virtex.h newtree/arch/ppc/platforms/4xx/virtex.h
--- oldtree/arch/ppc/platforms/4xx/virtex.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/virtex.h	2006-02-21 15:58:17.336511008 +0000
@@ -0,0 +1,35 @@
+/*
+ * arch/ppc/platforms/4xx/virtex.h
+ *
+ * Include file that defines the Xilinx Virtex-II Pro processor
+ *
+ * Author: MontaVista Software, Inc.
+ *         source@mvista.com
+ *
+ * 2002-2004 (c) MontaVista Software, Inc.  This file is licensed under the
+ * terms of the GNU General Public License version 2.  This program is licensed
+ * "as is" without any warranty of any kind, whether express or implied.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_VIRTEX_H__
+#define __ASM_VIRTEX_H__
+
+/* serial defines */
+
+#include <asm/ibm405.h>
+
+/* Ugly, ugly, ugly! BASE_BAUD defined here to keep 8250.c happy. */
+#if !defined(BASE_BAUD)
+ #define BASE_BAUD		(0) /* dummy value; not used */
+#endif
+  
+/* Device type enumeration for platform bus definitions */
+#ifndef __ASSEMBLY__
+enum ppc_sys_devices {
+	VIRTEX_UART,
+};
+#endif
+  
+#endif				/* __ASM_VIRTEX_H__ */
+#endif				/* __KERNEL__ */
diff -urN oldtree/arch/ppc/platforms/4xx/walnut.c newtree/arch/ppc/platforms/4xx/walnut.c
--- oldtree/arch/ppc/platforms/4xx/walnut.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/walnut.c	2006-02-21 15:58:17.338510704 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/walnut.c
- *
  * Architecture- / platform-specific boot-time initialization code for
  * IBM PowerPC 4xx based boards. Adapted from original
  * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
diff -urN oldtree/arch/ppc/platforms/4xx/walnut.h newtree/arch/ppc/platforms/4xx/walnut.h
--- oldtree/arch/ppc/platforms/4xx/walnut.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/walnut.h	2006-02-21 15:58:17.338510704 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/walnut.h
- *
  * Walnut board definitions
  *
  * Copyright (c) 2005 DENX Software Engineering
diff -urN oldtree/arch/ppc/platforms/4xx/xilinx_ml300.c newtree/arch/ppc/platforms/4xx/xilinx_ml300.c
--- oldtree/arch/ppc/platforms/4xx/xilinx_ml300.c	2006-02-19 11:40:59.457425584 +0000
+++ newtree/arch/ppc/platforms/4xx/xilinx_ml300.c	2006-02-21 15:58:17.338510704 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/xilinx_ml300.c
- *
  * Xilinx ML300 evaluation board initialization
  *
  * Author: MontaVista Software, Inc.
@@ -17,12 +15,14 @@
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 #include <linux/serialP.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
-#include <asm/ocp.h>
+#include <asm/ppc_sys.h>
 
-#include <platforms/4xx/virtex-ii_pro.h>	/* for NR_SER_PORTS */
+#include <syslib/gen550.h>
+#include <platforms/4xx/xparameters/xparameters.h>
 
 /*
  * As an overview of how the following functions (platform_init,
@@ -54,6 +54,22 @@
  *          ppc4xx_pic_init			arch/ppc/syslib/xilinx_pic.c
  */
 
+/* Board specifications structures */
+struct ppc_sys_spec *cur_ppc_sys_spec;
+struct ppc_sys_spec ppc_sys_specs[] = {
+	{
+		/* Only one entry, always assume the same design */
+		.ppc_sys_name	= "Xilinx ML300 Reference Design",
+		.mask 		= 0x00000000,
+		.value 		= 0x00000000,
+		.num_devices	= 1,
+		.device_list	= (enum ppc_sys_devices[])
+		{
+			VIRTEX_UART,
+		},
+	},
+};
+
 #if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
 
 static volatile unsigned *powerdown_base =
@@ -80,28 +96,39 @@
 #endif
 }
 
+/* Early serial support functions */
 static void __init
+ml300_early_serial_init(int num, struct plat_serial8250_port *pdata)
+{
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	struct uart_port serial_req;
+
+	memset(&serial_req, 0, sizeof(serial_req));
+	serial_req.mapbase	= pdata->mapbase;
+	serial_req.membase	= pdata->membase;
+	serial_req.irq		= pdata->irq;
+	serial_req.uartclk	= pdata->uartclk;
+	serial_req.regshift	= pdata->regshift;
+	serial_req.iotype	= pdata->iotype;
+	serial_req.flags	= pdata->flags;
+	gen550_init(num, &serial_req);
+#endif
+}
+
+void __init
 ml300_early_serial_map(void)
 {
 #ifdef CONFIG_SERIAL_8250
-	struct serial_state old_ports[] = { SERIAL_PORT_DFNS };
-	struct uart_port port;
-	int i;
-
-	/* Setup ioremapped serial port access */
-	for (i = 0; i < ARRAY_SIZE(old_ports); i++ ) {
-		memset(&port, 0, sizeof(port));
-		port.membase = ioremap((phys_addr_t)(old_ports[i].iomem_base), 16);
-		port.irq = old_ports[i].irq;
-		port.uartclk = old_ports[i].baud_base * 16;
-		port.regshift = old_ports[i].iomem_reg_shift;
-		port.iotype = UPIO_MEM;
-		port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
-		port.line = i;
-
-		if (early_serial_setup(&port) != 0) {
-			printk("Early serial init of port %d failed\n", i);
-		}
+	struct plat_serial8250_port *pdata;
+	int i = 0;
+
+	pdata = (struct plat_serial8250_port *) ppc_sys_get_pdata(VIRTEX_UART);
+	while(pdata && pdata->flags)
+	{
+		pdata->membase = ioremap(pdata->mapbase, 0x100);
+		ml300_early_serial_init(i, pdata);
+		pdata++;
+		i++;
 	}
 #endif /* CONFIG_SERIAL_8250 */
 }
@@ -109,9 +136,8 @@
 void __init
 ml300_setup_arch(void)
 {
-	ppc4xx_setup_arch();	/* calls ppc4xx_find_bridges() */
-
 	ml300_early_serial_map();
+	ppc4xx_setup_arch();	/* calls ppc4xx_find_bridges() */
 
 	/* Identify the system */
 	printk(KERN_INFO "Xilinx Virtex-II Pro port\n");
@@ -131,6 +157,8 @@
 {
 	ppc4xx_init(r3, r4, r5, r6, r7);
 
+	identify_ppc_sys_by_id(mfspr(SPRN_PVR));
+
 	ppc_md.setup_arch = ml300_setup_arch;
 	ppc_md.setup_io_mappings = ml300_map_io;
 	ppc_md.init_IRQ = ml300_init_irq;
diff -urN oldtree/arch/ppc/platforms/4xx/xilinx_ml300.h newtree/arch/ppc/platforms/4xx/xilinx_ml300.h
--- oldtree/arch/ppc/platforms/4xx/xilinx_ml300.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/xilinx_ml300.h	2006-02-21 15:58:17.339510552 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/xilinx_ml300.h
- *
  * Include file that defines the Xilinx ML300 evaluation board
  *
  * Author: MontaVista Software, Inc.
@@ -16,7 +14,7 @@
 #define __ASM_XILINX_ML300_H__
 
 /* ML300 has a Xilinx Virtex-II Pro processor */
-#include <platforms/4xx/virtex-ii_pro.h>
+#include <platforms/4xx/virtex.h>
 
 #ifndef __ASSEMBLY__
 
@@ -41,7 +39,7 @@
 #define PPC4xx_ONB_IO_VADDR	0u
 #define PPC4xx_ONB_IO_SIZE	0u
 
-#define PPC4xx_MACHINE_NAME "Xilinx ML300"
+#define PPC4xx_MACHINE_NAME "Xilinx ML300 Reference System"
 
 #endif /* __ASM_XILINX_ML300_H__ */
 #endif /* __KERNEL__ */
diff -urN oldtree/arch/ppc/platforms/4xx/xilinx_ml403.c newtree/arch/ppc/platforms/4xx/xilinx_ml403.c
--- oldtree/arch/ppc/platforms/4xx/xilinx_ml403.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/xilinx_ml403.c	2006-02-21 15:58:17.339510552 +0000
@@ -0,0 +1,177 @@
+/*
+ * arch/ppc/platforms/4xx/xilinx_ml403.c
+ *
+ * Xilinx ML403 evaluation board initialization
+ *
+ * Author: Grant Likely <grant.likely@secretlab.ca>
+ *
+ * 2005 (c) Secret Lab Technologies Ltd.
+ * 2002-2004 (c) MontaVista Software, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+#include <linux/serialP.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ppc_sys.h>
+
+#include <syslib/gen550.h>
+#include <platforms/4xx/xparameters/xparameters.h>
+
+/*
+ * As an overview of how the following functions (platform_init,
+ * ml403_map_io, ml403_setup_arch and ml403_init_IRQ) fit into the
+ * kernel startup procedure, here's a call tree:
+ *
+ * start_here					arch/ppc/kernel/head_4xx.S
+ *  early_init					arch/ppc/kernel/setup.c
+ *  machine_init				arch/ppc/kernel/setup.c
+ *    platform_init				this file
+ *      ppc4xx_init				arch/ppc/syslib/ppc4xx_setup.c
+ *        parse_bootinfo
+ *          find_bootinfo
+ *        "setup some default ppc_md pointers"
+ *  MMU_init					arch/ppc/mm/init.c
+ *    *ppc_md.setup_io_mappings == ml403_map_io	this file
+ *      ppc4xx_map_io				arch/ppc/syslib/ppc4xx_setup.c
+ *  start_kernel				init/main.c
+ *    setup_arch				arch/ppc/kernel/setup.c
+ * #if defined(CONFIG_KGDB)
+ *      *ppc_md.kgdb_map_scc() == gen550_kgdb_map_scc
+ * #endif
+ *      *ppc_md.setup_arch == ml403_setup_arch	this file
+ *        ppc4xx_setup_arch			arch/ppc/syslib/ppc4xx_setup.c
+ *          ppc4xx_find_bridges			arch/ppc/syslib/ppc405_pci.c
+ *    init_IRQ					arch/ppc/kernel/irq.c
+ *      *ppc_md.init_IRQ == ml403_init_IRQ	this file
+ *        ppc4xx_init_IRQ			arch/ppc/syslib/ppc4xx_setup.c
+ *          ppc4xx_pic_init			arch/ppc/syslib/xilinx_pic.c
+ */
+
+/* Board specifications structures */
+struct ppc_sys_spec *cur_ppc_sys_spec;
+struct ppc_sys_spec ppc_sys_specs[] = {
+	{
+		/* Only one entry, always assume the same design */
+		.ppc_sys_name	= "Xilinx ML403 Reference Design",
+		.mask 		= 0x00000000,
+		.value 		= 0x00000000,
+		.num_devices	= 1,
+		.device_list	= (enum ppc_sys_devices[])
+		{
+			VIRTEX_UART,
+		},
+	},
+};
+
+#if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
+
+static volatile unsigned *powerdown_base =
+    (volatile unsigned *) XPAR_POWER_0_POWERDOWN_BASEADDR;
+
+static void
+xilinx_power_off(void)
+{
+	local_irq_disable();
+	out_be32(powerdown_base, XPAR_POWER_0_POWERDOWN_VALUE);
+	while (1) ;
+}
+#endif
+
+void __init
+ml403_map_io(void)
+{
+	ppc4xx_map_io();
+
+#if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
+	powerdown_base = ioremap((unsigned long) powerdown_base,
+				 XPAR_POWER_0_POWERDOWN_HIGHADDR -
+				 XPAR_POWER_0_POWERDOWN_BASEADDR + 1);
+#endif
+}
+
+/* Early serial support functions */
+static void __init
+ml403_early_serial_init(int num, struct plat_serial8250_port *pdata)
+{
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	struct uart_port serial_req;
+
+	memset(&serial_req, 0, sizeof(serial_req));
+	serial_req.mapbase	= pdata->mapbase;
+	serial_req.membase	= pdata->membase;
+	serial_req.irq		= pdata->irq;
+	serial_req.uartclk	= pdata->uartclk;
+	serial_req.regshift	= pdata->regshift;
+	serial_req.iotype	= pdata->iotype;
+	serial_req.flags	= pdata->flags;
+	gen550_init(num, &serial_req);
+#endif
+}
+
+void __init
+ml403_early_serial_map(void)
+{
+#ifdef CONFIG_SERIAL_8250
+	struct plat_serial8250_port *pdata;
+	int i = 0;
+
+	pdata = (struct plat_serial8250_port *) ppc_sys_get_pdata(VIRTEX_UART);
+	while(pdata && pdata->flags)
+	{
+		pdata->membase = ioremap(pdata->mapbase, 0x100);
+		ml403_early_serial_init(i, pdata);
+		pdata++;
+		i++;
+	}
+#endif /* CONFIG_SERIAL_8250 */
+}
+
+void __init
+ml403_setup_arch(void)
+{
+	ml403_early_serial_map();
+	ppc4xx_setup_arch();	/* calls ppc4xx_find_bridges() */
+
+	/* Identify the system */
+	printk(KERN_INFO "Xilinx ML403 Reference System (Virtex-4 FX)\n");
+}
+
+/* Called after board_setup_irq from ppc4xx_init_IRQ(). */
+void __init
+ml403_init_irq(void)
+{
+	ppc4xx_init_IRQ();
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
+{
+	ppc4xx_init(r3, r4, r5, r6, r7);
+
+	identify_ppc_sys_by_id(mfspr(SPRN_PVR));
+
+	ppc_md.setup_arch = ml403_setup_arch;
+	ppc_md.setup_io_mappings = ml403_map_io;
+	ppc_md.init_IRQ = ml403_init_irq;
+
+#if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
+	ppc_md.power_off = xilinx_power_off;
+#endif
+
+#ifdef CONFIG_KGDB
+	ppc_md.early_serial_map = ml403_early_serial_map;
+#endif
+}
+
diff -urN oldtree/arch/ppc/platforms/4xx/xilinx_ml403.h newtree/arch/ppc/platforms/4xx/xilinx_ml403.h
--- oldtree/arch/ppc/platforms/4xx/xilinx_ml403.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/xilinx_ml403.h	2006-02-21 15:58:17.340510400 +0000
@@ -0,0 +1,49 @@
+/*
+ * arch/ppc/platforms/4xx/xilinx_ml403.h
+ *
+ * Include file that defines the Xilinx ML403 reference design
+ *
+ * Author: Grant Likely <grant.likely@secretlab.ca>
+ *
+ * 2005 (c) Secret Lab Technologies Ltd.
+ * 2002-2004 (c) MontaVista Software, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_XILINX_ML403_H__
+#define __ASM_XILINX_ML403_H__
+
+/* ML403 has a Xilinx Virtex-4 FPGA with a PPC405 hard core */
+#include <platforms/4xx/virtex.h>
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+typedef struct board_info {
+	unsigned int	 bi_memsize;		/* DRAM installed, in bytes */
+	unsigned char	 bi_enetaddr[6];	/* Local Ethernet MAC address */
+	unsigned int	 bi_intfreq;		/* Processor speed, in Hz */
+	unsigned int	 bi_busfreq;		/* PLB Bus speed, in Hz */
+	unsigned int	 bi_pci_busfreq;	/* PCI Bus speed, in Hz */
+} bd_t;
+
+/* Some 4xx parts use a different timebase frequency from the internal clock.
+*/
+#define bi_tbfreq bi_intfreq
+
+#endif /* !__ASSEMBLY__ */
+
+/* We don't need anything mapped.  Size of zero will accomplish that. */
+#define PPC4xx_ONB_IO_PADDR	0u
+#define PPC4xx_ONB_IO_VADDR	0u
+#define PPC4xx_ONB_IO_SIZE	0u
+
+#define PPC4xx_MACHINE_NAME "Xilinx ML403 Reference Design"
+
+#endif /* __ASM_XILINX_ML403_H__ */
+#endif /* __KERNEL__ */
diff -urN oldtree/arch/ppc/platforms/4xx/xparameters/xparameters.h newtree/arch/ppc/platforms/4xx/xparameters/xparameters.h
--- oldtree/arch/ppc/platforms/4xx/xparameters/xparameters.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/xparameters/xparameters.h	2006-02-21 15:58:17.340510400 +0000
@@ -0,0 +1,37 @@
+/*
+ * include/asm-ppc/xparameters.h
+ *
+ * This file includes the correct xparameters.h for the CONFIG'ed board plus
+ * fixups to translate board specific XPAR values to a common set of names
+ *
+ * Author: MontaVista Software, Inc.
+ *         source@mvista.com
+ *
+ * 2004 (c) MontaVista Software, Inc.  This file is licensed under the terms
+ * of the GNU General Public License version 2.  This program is licensed
+ * "as is" without any warranty of any kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+
+#if defined(CONFIG_XILINX_ML300)
+  #include "xparameters_ml300.h"
+#elif defined(CONFIG_XILINX_ML403)
+  #include "xparameters_ml403.h"
+#else
+  /* Add other board xparameter includes here before the #else */
+  #error No xparameters_*.h file included
+#endif
+
+#ifndef SERIAL_PORT_DFNS
+  /* zImage serial port definitions */
+  #define RS_TABLE_SIZE 1
+  #define SERIAL_PORT_DFNS {						\
+	.baud_base	 = XPAR_UARTNS550_0_CLOCK_FREQ_HZ/16,		\
+	.irq		 = XPAR_INTC_0_UARTNS550_0_VEC_ID,		\
+	.flags		 = ASYNC_BOOT_AUTOCONF,				\
+	.iomem_base	 = (u8 *)XPAR_UARTNS550_0_BASEADDR + 3,		\
+	.iomem_reg_shift = 2,						\
+	.io_type	 = SERIAL_IO_MEM,				\
+  },
+#endif
diff -urN oldtree/arch/ppc/platforms/4xx/xparameters/xparameters_ml403.h newtree/arch/ppc/platforms/4xx/xparameters/xparameters_ml403.h
--- oldtree/arch/ppc/platforms/4xx/xparameters/xparameters_ml403.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/xparameters/xparameters_ml403.h	2006-02-21 15:58:17.341510248 +0000
@@ -0,0 +1,243 @@
+
+/*******************************************************************
+*
+* CAUTION: This file is automatically generated by libgen.
+* Version: Xilinx EDK 7.1.2 EDK_H.12.5.1
+* DO NOT EDIT.
+*
+* Copyright (c) 2005 Xilinx, Inc.  All rights reserved. 
+* 
+* Description: Driver parameters
+*
+*******************************************************************/
+
+#define XPAR_PLB_BRAM_IF_CNTLR_0_BASEADDR 0xFFFF0000
+#define XPAR_PLB_BRAM_IF_CNTLR_0_HIGHADDR 0xFFFFFFFF
+
+/******************************************************************/
+
+#define XPAR_OPB_EMC_0_MEM0_BASEADDR 0x20000000
+#define XPAR_OPB_EMC_0_MEM0_HIGHADDR 0x200FFFFF
+#define XPAR_OPB_EMC_0_MEM1_BASEADDR 0x28000000
+#define XPAR_OPB_EMC_0_MEM1_HIGHADDR 0x287FFFFF
+#define XPAR_OPB_AC97_CONTROLLER_REF_0_BASEADDR 0xA6000000
+#define XPAR_OPB_AC97_CONTROLLER_REF_0_HIGHADDR 0xA60000FF
+#define XPAR_OPB_EMC_USB_0_MEM0_BASEADDR 0xA5000000
+#define XPAR_OPB_EMC_USB_0_MEM0_HIGHADDR 0xA50000FF
+#define XPAR_PLB_DDR_0_MEM0_BASEADDR 0x00000000
+#define XPAR_PLB_DDR_0_MEM0_HIGHADDR 0x0FFFFFFF
+
+/******************************************************************/
+
+#define XPAR_XEMAC_NUM_INSTANCES 1
+#define XPAR_OPB_ETHERNET_0_BASEADDR 0x60000000
+#define XPAR_OPB_ETHERNET_0_HIGHADDR 0x60003FFF
+#define XPAR_OPB_ETHERNET_0_DEVICE_ID 0
+#define XPAR_OPB_ETHERNET_0_ERR_COUNT_EXIST 1
+#define XPAR_OPB_ETHERNET_0_DMA_PRESENT 1
+#define XPAR_OPB_ETHERNET_0_MII_EXIST 1
+
+/******************************************************************/
+
+#define XPAR_XUARTNS550_NUM_INSTANCES 1
+#define XPAR_XUARTNS550_CLOCK_HZ 100000000
+#define XPAR_OPB_UART16550_0_BASEADDR 0xA0000000
+#define XPAR_OPB_UART16550_0_HIGHADDR 0xA0001FFF
+#define XPAR_OPB_UART16550_0_DEVICE_ID 0
+
+/******************************************************************/
+
+#define XPAR_XGPIO_NUM_INSTANCES 3
+#define XPAR_OPB_GPIO_0_BASEADDR 0x90000000
+#define XPAR_OPB_GPIO_0_HIGHADDR 0x900001FF
+#define XPAR_OPB_GPIO_0_DEVICE_ID 0
+#define XPAR_OPB_GPIO_0_INTERRUPT_PRESENT 0
+#define XPAR_OPB_GPIO_0_IS_DUAL 1
+#define XPAR_OPB_GPIO_EXP_HDR_0_BASEADDR 0x90001000
+#define XPAR_OPB_GPIO_EXP_HDR_0_HIGHADDR 0x900011FF
+#define XPAR_OPB_GPIO_EXP_HDR_0_DEVICE_ID 1
+#define XPAR_OPB_GPIO_EXP_HDR_0_INTERRUPT_PRESENT 0
+#define XPAR_OPB_GPIO_EXP_HDR_0_IS_DUAL 1
+#define XPAR_OPB_GPIO_CHAR_LCD_0_BASEADDR 0x90002000
+#define XPAR_OPB_GPIO_CHAR_LCD_0_HIGHADDR 0x900021FF
+#define XPAR_OPB_GPIO_CHAR_LCD_0_DEVICE_ID 2
+#define XPAR_OPB_GPIO_CHAR_LCD_0_INTERRUPT_PRESENT 0
+#define XPAR_OPB_GPIO_CHAR_LCD_0_IS_DUAL 0
+
+/******************************************************************/
+
+#define XPAR_XPS2_NUM_INSTANCES 2
+#define XPAR_OPB_PS2_DUAL_REF_0_DEVICE_ID_0 0
+#define XPAR_OPB_PS2_DUAL_REF_0_BASEADDR_0 0xA9000000
+#define XPAR_OPB_PS2_DUAL_REF_0_HIGHADDR_0 (0xA9000000+0x3F)
+#define XPAR_OPB_PS2_DUAL_REF_0_DEVICE_ID_1 1
+#define XPAR_OPB_PS2_DUAL_REF_0_BASEADDR_1 (0xA9000000+0x1000)
+#define XPAR_OPB_PS2_DUAL_REF_0_HIGHADDR_1 (0xA9000000+0x103F)
+
+/******************************************************************/
+
+#define XPAR_XIIC_NUM_INSTANCES 1
+#define XPAR_OPB_IIC_0_BASEADDR 0xA8000000
+#define XPAR_OPB_IIC_0_HIGHADDR 0xA80001FF
+#define XPAR_OPB_IIC_0_DEVICE_ID 0
+#define XPAR_OPB_IIC_0_TEN_BIT_ADR 0
+#define XPAR_OPB_IIC_0_GPO_WIDTH 1
+
+/******************************************************************/
+
+#define XPAR_INTC_MAX_NUM_INTR_INPUTS 10
+#define XPAR_XINTC_HAS_IPR 1
+#define XPAR_XINTC_USE_DCR 0
+#define XPAR_XINTC_NUM_INSTANCES 1
+#define XPAR_OPB_INTC_0_BASEADDR 0xD1000FC0
+#define XPAR_OPB_INTC_0_HIGHADDR 0xD1000FDF
+#define XPAR_OPB_INTC_0_DEVICE_ID 0
+#define XPAR_OPB_INTC_0_KIND_OF_INTR 0x00000000
+
+/******************************************************************/
+
+#define XPAR_INTC_SINGLE_BASEADDR 0xD1000FC0
+#define XPAR_INTC_SINGLE_HIGHADDR 0xD1000FDF
+#define XPAR_INTC_SINGLE_DEVICE_ID XPAR_OPB_INTC_0_DEVICE_ID
+#define XPAR_OPB_ETHERNET_0_IP2INTC_IRPT_MASK 0X000001
+#define XPAR_OPB_INTC_0_OPB_ETHERNET_0_IP2INTC_IRPT_INTR 0
+#define XPAR_SYSTEM_USB_HPI_INT_MASK 0X000002
+#define XPAR_OPB_INTC_0_SYSTEM_USB_HPI_INT_INTR 1
+#define XPAR_MISC_LOGIC_0_PHY_MII_INT_MASK 0X000004
+#define XPAR_OPB_INTC_0_MISC_LOGIC_0_PHY_MII_INT_INTR 2
+#define XPAR_OPB_SYSACE_0_SYSACE_IRQ_MASK 0X000008
+#define XPAR_OPB_INTC_0_OPB_SYSACE_0_SYSACE_IRQ_INTR 3
+#define XPAR_OPB_AC97_CONTROLLER_REF_0_RECORD_INTERRUPT_MASK 0X000010
+#define XPAR_OPB_INTC_0_OPB_AC97_CONTROLLER_REF_0_RECORD_INTERRUPT_INTR 4
+#define XPAR_OPB_AC97_CONTROLLER_REF_0_PLAYBACK_INTERRUPT_MASK 0X000020
+#define XPAR_OPB_INTC_0_OPB_AC97_CONTROLLER_REF_0_PLAYBACK_INTERRUPT_INTR 5
+#define XPAR_OPB_IIC_0_IP2INTC_IRPT_MASK 0X000040
+#define XPAR_OPB_INTC_0_OPB_IIC_0_IP2INTC_IRPT_INTR 6
+#define XPAR_OPB_PS2_DUAL_REF_0_SYS_INTR2_MASK 0X000080
+#define XPAR_OPB_INTC_0_OPB_PS2_DUAL_REF_0_SYS_INTR2_INTR 7
+#define XPAR_OPB_PS2_DUAL_REF_0_SYS_INTR1_MASK 0X000100
+#define XPAR_OPB_INTC_0_OPB_PS2_DUAL_REF_0_SYS_INTR1_INTR 8
+#define XPAR_OPB_UART16550_0_IP2INTC_IRPT_MASK 0X000200
+#define XPAR_OPB_INTC_0_OPB_UART16550_0_IP2INTC_IRPT_INTR 9
+
+/******************************************************************/
+
+#define XPAR_XTFT_NUM_INSTANCES 1
+#define XPAR_PLB_TFT_CNTLR_REF_0_DCR_BASEADDR 0xD0000200
+#define XPAR_PLB_TFT_CNTLR_REF_0_DCR_HIGHADDR 0xD0000207
+#define XPAR_PLB_TFT_CNTLR_REF_0_DEVICE_ID 0
+
+/******************************************************************/
+
+#define XPAR_XSYSACE_MEM_WIDTH 16
+#define XPAR_XSYSACE_NUM_INSTANCES 1
+#define XPAR_OPB_SYSACE_0_BASEADDR 0xCF000000
+#define XPAR_OPB_SYSACE_0_HIGHADDR 0xCF0001FF
+#define XPAR_OPB_SYSACE_0_DEVICE_ID 0
+#define XPAR_OPB_SYSACE_0_MEM_WIDTH 16
+
+/******************************************************************/
+
+#define XPAR_CPU_PPC405_CORE_CLOCK_FREQ_HZ 300000000
+
+/******************************************************************/
+
+
+/******************************************************************/
+
+/* Linux Redefines */
+
+/******************************************************************/
+
+#define XPAR_UARTNS550_0_BASEADDR (XPAR_OPB_UART16550_0_BASEADDR+0x1000)
+#define XPAR_UARTNS550_0_HIGHADDR XPAR_OPB_UART16550_0_HIGHADDR
+#define XPAR_UARTNS550_0_CLOCK_FREQ_HZ XPAR_XUARTNS550_CLOCK_HZ
+#define XPAR_UARTNS550_0_DEVICE_ID XPAR_OPB_UART16550_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_INTC_0_BASEADDR XPAR_OPB_INTC_0_BASEADDR
+#define XPAR_INTC_0_HIGHADDR XPAR_OPB_INTC_0_HIGHADDR
+#define XPAR_INTC_0_KIND_OF_INTR XPAR_OPB_INTC_0_KIND_OF_INTR
+#define XPAR_INTC_0_DEVICE_ID XPAR_OPB_INTC_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_INTC_0_EMAC_0_VEC_ID XPAR_OPB_INTC_0_OPB_ETHERNET_0_IP2INTC_IRPT_INTR
+#define XPAR_INTC_0_SYSACE_0_VEC_ID XPAR_OPB_INTC_0_OPB_SYSACE_0_SYSACE_IRQ_INTR
+#define XPAR_INTC_0_IIC_0_VEC_ID XPAR_OPB_INTC_0_OPB_IIC_0_IP2INTC_IRPT_INTR
+#define XPAR_INTC_0_PS2_1_VEC_ID XPAR_OPB_INTC_0_OPB_PS2_DUAL_REF_0_SYS_INTR2_INTR
+#define XPAR_INTC_0_PS2_0_VEC_ID XPAR_OPB_INTC_0_OPB_PS2_DUAL_REF_0_SYS_INTR1_INTR
+#define XPAR_INTC_0_UARTNS550_0_VEC_ID XPAR_OPB_INTC_0_OPB_UART16550_0_IP2INTC_IRPT_INTR
+
+/******************************************************************/
+
+#define XPAR_TFT_0_BASEADDR XPAR_PLB_TFT_CNTLR_REF_0_DCR_BASEADDR
+
+/******************************************************************/
+
+#define XPAR_EMAC_0_BASEADDR XPAR_OPB_ETHERNET_0_BASEADDR
+#define XPAR_EMAC_0_HIGHADDR XPAR_OPB_ETHERNET_0_HIGHADDR
+#define XPAR_EMAC_0_DMA_PRESENT XPAR_OPB_ETHERNET_0_DMA_PRESENT
+#define XPAR_EMAC_0_MII_EXIST XPAR_OPB_ETHERNET_0_MII_EXIST
+#define XPAR_EMAC_0_ERR_COUNT_EXIST XPAR_OPB_ETHERNET_0_ERR_COUNT_EXIST
+#define XPAR_EMAC_0_DEVICE_ID XPAR_OPB_ETHERNET_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_GPIO_0_BASEADDR XPAR_OPB_GPIO_0_BASEADDR_0
+#define XPAR_GPIO_0_HIGHADDR XPAR_OPB_GPIO_0_HIGHADDR_0
+#define XPAR_GPIO_0_DEVICE_ID XPAR_OPB_GPIO_0_DEVICE_ID_0
+#define XPAR_GPIO_1_BASEADDR XPAR_OPB_GPIO_0_BASEADDR_1
+#define XPAR_GPIO_1_HIGHADDR XPAR_OPB_GPIO_0_HIGHADDR_1
+#define XPAR_GPIO_1_DEVICE_ID XPAR_OPB_GPIO_0_DEVICE_ID_1
+#define XPAR_GPIO_2_BASEADDR XPAR_OPB_GPIO_EXP_HDR_0_BASEADDR_0
+#define XPAR_GPIO_2_HIGHADDR XPAR_OPB_GPIO_EXP_HDR_0_HIGHADDR_0
+#define XPAR_GPIO_2_DEVICE_ID XPAR_OPB_GPIO_EXP_HDR_0_DEVICE_ID_0
+#define XPAR_GPIO_3_BASEADDR XPAR_OPB_GPIO_EXP_HDR_0_BASEADDR_1
+#define XPAR_GPIO_3_HIGHADDR XPAR_OPB_GPIO_EXP_HDR_0_HIGHADDR_1
+#define XPAR_GPIO_3_DEVICE_ID XPAR_OPB_GPIO_EXP_HDR_0_DEVICE_ID_1
+#define XPAR_GPIO_4_BASEADDR XPAR_OPB_GPIO_CHAR_LCD_0_BASEADDR
+#define XPAR_GPIO_4_HIGHADDR XPAR_OPB_GPIO_CHAR_LCD_0_HIGHADDR
+#define XPAR_GPIO_4_DEVICE_ID XPAR_OPB_GPIO_CHAR_LCD_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_PS2_0_BASEADDR XPAR_OPB_PS2_DUAL_REF_0_BASEADDR_0
+#define XPAR_PS2_0_HIGHADDR XPAR_OPB_PS2_DUAL_REF_0_HIGHADDR_0
+#define XPAR_PS2_0_DEVICE_ID XPAR_OPB_PS2_DUAL_REF_0_DEVICE_ID_0
+#define XPAR_PS2_1_BASEADDR XPAR_OPB_PS2_DUAL_REF_0_BASEADDR_1
+#define XPAR_PS2_1_HIGHADDR XPAR_OPB_PS2_DUAL_REF_0_HIGHADDR_1
+#define XPAR_PS2_1_DEVICE_ID XPAR_OPB_PS2_DUAL_REF_0_DEVICE_ID_1
+
+/******************************************************************/
+
+#define XPAR_SYSACE_0_BASEADDR XPAR_OPB_SYSACE_0_BASEADDR
+#define XPAR_SYSACE_0_HIGHADDR XPAR_OPB_SYSACE_0_HIGHADDR
+#define XPAR_SYSACE_0_DEVICE_ID XPAR_OPB_SYSACE_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_IIC_0_BASEADDR XPAR_OPB_IIC_0_BASEADDR
+#define XPAR_IIC_0_HIGHADDR XPAR_OPB_IIC_0_HIGHADDR
+#define XPAR_IIC_0_TEN_BIT_ADR XPAR_OPB_IIC_0_TEN_BIT_ADR
+#define XPAR_IIC_0_DEVICE_ID XPAR_OPB_IIC_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_PLB_CLOCK_FREQ_HZ 100000000
+#define XPAR_CORE_CLOCK_FREQ_HZ XPAR_CPU_PPC405_CORE_CLOCK_FREQ_HZ
+#define XPAR_DDR_0_SIZE 0x4000000
+
+/******************************************************************/
+
+#define XPAR_PERSISTENT_0_IIC_0_BASEADDR 0x00000400
+#define XPAR_PERSISTENT_0_IIC_0_HIGHADDR 0x000007FF
+#define XPAR_PERSISTENT_0_IIC_0_EEPROMADDR 0xA0
+
+/******************************************************************/
+
+#define XPAR_PCI_0_CLOCK_FREQ_HZ    0
+
+/******************************************************************/
+
diff -urN oldtree/arch/ppc/platforms/4xx/yucca.c newtree/arch/ppc/platforms/4xx/yucca.c
--- oldtree/arch/ppc/platforms/4xx/yucca.c	2006-02-19 11:40:59.457425584 +0000
+++ newtree/arch/ppc/platforms/4xx/yucca.c	2006-02-21 15:58:17.341510248 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/yucca.c
- *
  * Yucca board specific routines
  *
  * Roland Dreier <rolandd@cisco.com> (based on luan.c by Matt Porter)
diff -urN oldtree/arch/ppc/platforms/4xx/yucca.h newtree/arch/ppc/platforms/4xx/yucca.h
--- oldtree/arch/ppc/platforms/4xx/yucca.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/4xx/yucca.h	2006-02-21 15:58:17.341510248 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/4xx/yucca.h
- *
  * Yucca board definitions
  *
  * Roland Dreier <rolandd@cisco.com> (based on luan.h by Matt Porter)
diff -urN oldtree/arch/ppc/platforms/83xx/mpc834x_sys.c newtree/arch/ppc/platforms/83xx/mpc834x_sys.c
--- oldtree/arch/ppc/platforms/83xx/mpc834x_sys.c	2006-02-19 11:40:59.458425432 +0000
+++ newtree/arch/ppc/platforms/83xx/mpc834x_sys.c	2006-02-21 15:58:17.342510096 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/83xx/mpc834x_sys.c
- *
  * MPC834x SYS board specific routines
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/platforms/83xx/mpc834x_sys.h newtree/arch/ppc/platforms/83xx/mpc834x_sys.h
--- oldtree/arch/ppc/platforms/83xx/mpc834x_sys.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/83xx/mpc834x_sys.h	2006-02-21 15:58:17.342510096 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/83xx/mpc834x_sys.h
- *
  * MPC834X SYS common board definitions
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/platforms/85xx/mpc8540_ads.c newtree/arch/ppc/platforms/85xx/mpc8540_ads.c
--- oldtree/arch/ppc/platforms/85xx/mpc8540_ads.c	2006-02-19 11:40:59.459425280 +0000
+++ newtree/arch/ppc/platforms/85xx/mpc8540_ads.c	2006-02-21 15:58:17.343509944 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/85xx/mpc8540_ads.c
- *
  * MPC8540ADS board specific routines
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/platforms/85xx/mpc8540_ads.h newtree/arch/ppc/platforms/85xx/mpc8540_ads.h
--- oldtree/arch/ppc/platforms/85xx/mpc8540_ads.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/85xx/mpc8540_ads.h	2006-02-21 15:58:17.343509944 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/85xx/mpc8540_ads.h
- *
  * MPC8540ADS board definitions
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/platforms/85xx/mpc8555_cds.h newtree/arch/ppc/platforms/85xx/mpc8555_cds.h
--- oldtree/arch/ppc/platforms/85xx/mpc8555_cds.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/85xx/mpc8555_cds.h	2006-02-21 15:58:17.343509944 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/mpc8555_cds.h
- *
  * MPC8555CDS board definitions
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/platforms/85xx/mpc8560_ads.c newtree/arch/ppc/platforms/85xx/mpc8560_ads.c
--- oldtree/arch/ppc/platforms/85xx/mpc8560_ads.c	2006-02-19 11:40:59.459425280 +0000
+++ newtree/arch/ppc/platforms/85xx/mpc8560_ads.c	2006-02-21 15:58:17.344509792 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/85xx/mpc8560_ads.c
- *
  * MPC8560ADS board specific routines
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/platforms/85xx/mpc8560_ads.h newtree/arch/ppc/platforms/85xx/mpc8560_ads.h
--- oldtree/arch/ppc/platforms/85xx/mpc8560_ads.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/85xx/mpc8560_ads.h	2006-02-21 15:58:17.344509792 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/mpc8560_ads.h
- *
  * MPC8540ADS board definitions
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/platforms/85xx/mpc85xx_ads_common.c newtree/arch/ppc/platforms/85xx/mpc85xx_ads_common.c
--- oldtree/arch/ppc/platforms/85xx/mpc85xx_ads_common.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/85xx/mpc85xx_ads_common.c	2006-02-21 15:58:17.344509792 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/85xx/mpc85xx_ads_common.c
- *
  * MPC85xx ADS board common routines
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/platforms/85xx/mpc85xx_ads_common.h newtree/arch/ppc/platforms/85xx/mpc85xx_ads_common.h
--- oldtree/arch/ppc/platforms/85xx/mpc85xx_ads_common.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/85xx/mpc85xx_ads_common.h	2006-02-21 15:58:17.345509640 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/85xx/mpc85xx_ads_common.h
- *
  * MPC85XX ADS common board definitions
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/platforms/85xx/mpc85xx_cds_common.c newtree/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
--- oldtree/arch/ppc/platforms/85xx/mpc85xx_cds_common.c	2006-02-19 11:40:59.460425128 +0000
+++ newtree/arch/ppc/platforms/85xx/mpc85xx_cds_common.c	2006-02-21 15:58:17.345509640 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platform/85xx/mpc85xx_cds_common.c
- *
  * MPC85xx CDS board specific routines
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/platforms/85xx/mpc85xx_cds_common.h newtree/arch/ppc/platforms/85xx/mpc85xx_cds_common.h
--- oldtree/arch/ppc/platforms/85xx/mpc85xx_cds_common.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/85xx/mpc85xx_cds_common.h	2006-02-21 15:58:17.346509488 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/85xx/mpc85xx_cds_common.h
- *
  * MPC85xx CDS board definitions
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/platforms/85xx/sbc8560.c newtree/arch/ppc/platforms/85xx/sbc8560.c
--- oldtree/arch/ppc/platforms/85xx/sbc8560.c	2006-02-19 11:40:59.460425128 +0000
+++ newtree/arch/ppc/platforms/85xx/sbc8560.c	2006-02-21 15:58:17.346509488 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/85xx/sbc8560.c
- * 
  * Wind River SBC8560 board specific routines
  * 
  * Maintainer: Kumar Gala
diff -urN oldtree/arch/ppc/platforms/85xx/sbc8560.h newtree/arch/ppc/platforms/85xx/sbc8560.h
--- oldtree/arch/ppc/platforms/85xx/sbc8560.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/85xx/sbc8560.h	2006-02-21 15:58:17.346509488 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/85xx/sbc8560.h
- *
  * Wind River SBC8560 board definitions
  *
  * Copyright 2003 Motorola Inc.
diff -urN oldtree/arch/ppc/platforms/85xx/sbc85xx.c newtree/arch/ppc/platforms/85xx/sbc85xx.c
--- oldtree/arch/ppc/platforms/85xx/sbc85xx.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/85xx/sbc85xx.c	2006-02-21 15:58:17.347509336 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platform/85xx/sbc85xx.c
- * 
  * WindRiver PowerQUICC III SBC85xx board common routines
  *
  * Copyright 2002, 2003 Motorola Inc.
diff -urN oldtree/arch/ppc/platforms/85xx/sbc85xx.h newtree/arch/ppc/platforms/85xx/sbc85xx.h
--- oldtree/arch/ppc/platforms/85xx/sbc85xx.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/85xx/sbc85xx.h	2006-02-21 15:58:17.347509336 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/85xx/sbc85xx.h
- *
  * WindRiver PowerQUICC III SBC85xx common board definitions
  *
  * Copyright 2003 Motorola Inc.
diff -urN oldtree/arch/ppc/platforms/85xx/stx_gp3.c newtree/arch/ppc/platforms/85xx/stx_gp3.c
--- oldtree/arch/ppc/platforms/85xx/stx_gp3.c	2006-02-19 11:40:59.461424976 +0000
+++ newtree/arch/ppc/platforms/85xx/stx_gp3.c	2006-02-21 15:58:17.348509184 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/85xx/stx_gp3.c
- *
  * STx GP3 board specific routines
  *
  * Dan Malek <dan@embeddededge.com>
diff -urN oldtree/arch/ppc/platforms/85xx/stx_gp3.h newtree/arch/ppc/platforms/85xx/stx_gp3.h
--- oldtree/arch/ppc/platforms/85xx/stx_gp3.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/85xx/stx_gp3.h	2006-02-21 15:58:17.348509184 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/stx8560_gp3.h
- *
  * STx GP3 board definitions
  *
  * Dan Malek (dan@embeddededge.com)
diff -urN oldtree/arch/ppc/platforms/85xx/tqm85xx.c newtree/arch/ppc/platforms/85xx/tqm85xx.c
--- oldtree/arch/ppc/platforms/85xx/tqm85xx.c	2006-02-19 11:40:59.462424824 +0000
+++ newtree/arch/ppc/platforms/85xx/tqm85xx.c	2006-02-21 15:58:17.348509184 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/85xx/tqm85xx.c
- *
  * TQM85xx (40/41/55/60) board specific routines
  *
  * Copyright (c) 2005 DENX Software Engineering
diff -urN oldtree/arch/ppc/platforms/85xx/tqm85xx.h newtree/arch/ppc/platforms/85xx/tqm85xx.h
--- oldtree/arch/ppc/platforms/85xx/tqm85xx.h	2006-02-19 11:40:59.462424824 +0000
+++ newtree/arch/ppc/platforms/85xx/tqm85xx.h	2006-02-21 15:58:17.349509032 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/85xx/tqm85xx.h
- *
  * TQM85xx (40/41/55/60) board definitions
  *
  * Copyright (c) 2005 DENX Software Engineering
diff -urN oldtree/arch/ppc/platforms/Makefile newtree/arch/ppc/platforms/Makefile
--- oldtree/arch/ppc/platforms/Makefile	2006-02-19 11:40:59.462424824 +0000
+++ newtree/arch/ppc/platforms/Makefile	2006-02-21 15:58:17.385503560 +0000
@@ -37,6 +37,9 @@
 obj-$(CONFIG_SPRUCE)		+= spruce.o
 obj-$(CONFIG_LITE5200)		+= lite5200.o
 obj-$(CONFIG_EV64360)		+= ev64360.o
+obj-$(CONFIG_MPC86XADS)		+= mpc866ads_setup.o
+obj-$(CONFIG_MPC885ADS)		+= mpc885ads_setup.o
+obj-$(CONFIG_ADS8272)		+= mpc8272ads_setup.o
 
 ifeq ($(CONFIG_SMP),y)
 obj-$(CONFIG_PPC_CHRP)		+= chrp_smp.o
diff -urN oldtree/arch/ppc/platforms/apus_setup.c newtree/arch/ppc/platforms/apus_setup.c
--- oldtree/arch/ppc/platforms/apus_setup.c	2006-02-19 11:40:59.463424672 +0000
+++ newtree/arch/ppc/platforms/apus_setup.c	2006-02-21 15:58:17.354508272 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/platforms/apus_setup.c
- *
  *  Copyright (C) 1998, 1999  Jesper Skov
  *
  *  Basically what is needed to replace functionality found in
diff -urN oldtree/arch/ppc/platforms/chestnut.c newtree/arch/ppc/platforms/chestnut.c
--- oldtree/arch/ppc/platforms/chestnut.c	2006-02-19 11:40:59.463424672 +0000
+++ newtree/arch/ppc/platforms/chestnut.c	2006-02-21 15:58:17.355508120 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/chestnut.c
- *
  * Board setup routines for IBM Chestnut
  *
  * Author: <source@mvista.com>
diff -urN oldtree/arch/ppc/platforms/chestnut.h newtree/arch/ppc/platforms/chestnut.h
--- oldtree/arch/ppc/platforms/chestnut.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/chestnut.h	2006-02-21 15:58:17.363506904 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/chestnut.h
- *
  * Definitions for IBM 750FXGX Eval (Chestnut)
  *
  * Author: <source@mvista.com>
diff -urN oldtree/arch/ppc/platforms/chrp_pegasos_eth.c newtree/arch/ppc/platforms/chrp_pegasos_eth.c
--- oldtree/arch/ppc/platforms/chrp_pegasos_eth.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/chrp_pegasos_eth.c	2006-02-21 15:58:17.363506904 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/platforms/chrp_pegasos_eth.c
- *
  *  Copyright (C) 2005 Sven Luther <sl@bplan-gmbh.de>
  *  Thanks to :
  *	Dale Farnsworth <dale@farnsworth.org>
diff -urN oldtree/arch/ppc/platforms/chrp_setup.c newtree/arch/ppc/platforms/chrp_setup.c
--- oldtree/arch/ppc/platforms/chrp_setup.c	2006-02-19 11:40:59.464424520 +0000
+++ newtree/arch/ppc/platforms/chrp_setup.c	2006-02-21 15:58:17.364506752 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/platforms/setup.c
- *
  *  Copyright (C) 1995  Linus Torvalds
  *  Adapted from 'alpha' version by Gary Thomas
  *  Modified by Cort Dougan (cort@cs.nmt.edu)
diff -urN oldtree/arch/ppc/platforms/chrp_time.c newtree/arch/ppc/platforms/chrp_time.c
--- oldtree/arch/ppc/platforms/chrp_time.c	2006-02-19 11:40:59.465424368 +0000
+++ newtree/arch/ppc/platforms/chrp_time.c	2006-02-21 15:58:17.364506752 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/platforms/chrp_time.c
- *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
  *
  * Adapted for PowerPC (PReP) by Gary Thomas
diff -urN oldtree/arch/ppc/platforms/cpci690.c newtree/arch/ppc/platforms/cpci690.c
--- oldtree/arch/ppc/platforms/cpci690.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/cpci690.c	2006-02-21 15:58:17.365506600 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/cpci690.c
- *
  * Board setup routines for the Force CPCI690 board.
  *
  * Author: Mark A. Greer <mgreer@mvista.com>
diff -urN oldtree/arch/ppc/platforms/cpci690.h newtree/arch/ppc/platforms/cpci690.h
--- oldtree/arch/ppc/platforms/cpci690.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/cpci690.h	2006-02-21 15:58:17.365506600 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/cpci690.h
- *
  * Definitions for Force CPCI690
  *
  * Author: Mark A. Greer <mgreer@mvista.com>
diff -urN oldtree/arch/ppc/platforms/ev64260.c newtree/arch/ppc/platforms/ev64260.c
--- oldtree/arch/ppc/platforms/ev64260.c	2006-02-19 11:40:59.466424216 +0000
+++ newtree/arch/ppc/platforms/ev64260.c	2006-02-21 15:58:17.366506448 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/ev64260.c
- *
  * Board setup routines for the Marvell/Galileo EV-64260-BP Evaluation Board.
  *
  * Author: Mark A. Greer <mgreer@mvista.com>
diff -urN oldtree/arch/ppc/platforms/ev64260.h newtree/arch/ppc/platforms/ev64260.h
--- oldtree/arch/ppc/platforms/ev64260.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/ev64260.h	2006-02-21 15:58:17.367506296 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/ev64260.h
- *
  * Definitions for Marvell/Galileo EV-64260-BP Evaluation Board.
  *
  * Author: Mark A. Greer <mgreer@mvista.com>
diff -urN oldtree/arch/ppc/platforms/ev64360.c newtree/arch/ppc/platforms/ev64360.c
--- oldtree/arch/ppc/platforms/ev64360.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/ev64360.c	2006-02-21 15:58:17.367506296 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/ev64360.c
- *
  * Board setup routines for the Marvell EV-64360-BP Evaluation Board.
  *
  * Author: Lee Nicks <allinux@gmail.com>
diff -urN oldtree/arch/ppc/platforms/ev64360.h newtree/arch/ppc/platforms/ev64360.h
--- oldtree/arch/ppc/platforms/ev64360.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/ev64360.h	2006-02-21 15:58:17.368506144 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/ev64360.h
- *
  * Definitions for Marvell EV-64360-BP Evaluation Board.
  *
  * Author: Lee Nicks <allinux@gmail.com>
diff -urN oldtree/arch/ppc/platforms/fads.h newtree/arch/ppc/platforms/fads.h
--- oldtree/arch/ppc/platforms/fads.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/fads.h	2006-02-21 15:58:17.369505992 +0000
@@ -112,7 +112,7 @@
 
 /* CPM Ethernet through SCC1 or SCC2 */
 
-#ifdef CONFIG_SCC1_ENET		/* Probably 860 variant */
+#if defined(CONFIG_SCC1_ENET) || defined(CONFIG_MPC8xx_SECOND_ETH_SCC1)		/* Probably 860 variant */
 /* Bits in parallel I/O port registers that have to be set/cleared
  * to configure the pins for SCC1 use.
  * TCLK - CLK1, RCLK - CLK2.
diff -urN oldtree/arch/ppc/platforms/gemini.h newtree/arch/ppc/platforms/gemini.h
--- oldtree/arch/ppc/platforms/gemini.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/gemini.h	2006-02-21 15:58:17.376504928 +0000
@@ -1,7 +1,4 @@
 /*
- *  arch/ppc/platforms/gemini.h
- *
- *
  *  Onboard registers and descriptions for Synergy Microsystems'
  *  "Gemini" boards.
  *
diff -urN oldtree/arch/ppc/platforms/gemini_prom.S newtree/arch/ppc/platforms/gemini_prom.S
--- oldtree/arch/ppc/platforms/gemini_prom.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/gemini_prom.S	2006-02-21 15:58:17.377504776 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/platforms/gemini_prom.S
- *
  *  Not really prom support code (yet), but sort of anti-prom code.  The current
  *  bootloader does a number of things it shouldn't and doesn't do things that it
  *  should.  The stuff in here is mainly a hodge-podge collection of setup code
diff -urN oldtree/arch/ppc/platforms/gemini_setup.c newtree/arch/ppc/platforms/gemini_setup.c
--- oldtree/arch/ppc/platforms/gemini_setup.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/gemini_setup.c	2006-02-21 15:58:17.381504168 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/platforms/gemini_setup.c
- *
  *  Copyright (C) 1995 Linus Torvalds
  *  Adapted from 'alpha' version by Gary Thomas
  *  Modified by Cort Dougan (cort@cs.nmt.edu)
diff -urN oldtree/arch/ppc/platforms/hdpu.c newtree/arch/ppc/platforms/hdpu.c
--- oldtree/arch/ppc/platforms/hdpu.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/hdpu.c	2006-02-21 15:58:17.382504016 +0000
@@ -1,7 +1,4 @@
-
 /*
- * arch/ppc/platforms/hdpu_setup.c
- *
  * Board setup routines for the Sky Computers HDPU Compute Blade.
  *
  * Written by Brian Waite <waite@skycomputers.com>
@@ -319,11 +316,10 @@
 	struct mv643xx_eth_platform_data *eth_pd;
 	eth_pd = pd->dev.platform_data;
 
-	eth_pd->port_serial_control =
-	    mv64x60_read(&bh, MV643XX_ETH_PORT_SERIAL_CONTROL_REG(pd->id) & ~1);
-
 	eth_pd->force_phy_addr = 1;
 	eth_pd->phy_addr = pd->id;
+	eth_pd->speed = SPEED_100;
+	eth_pd->duplex = DUPLEX_FULL;
 	eth_pd->tx_queue_size = 400;
 	eth_pd->rx_queue_size = 800;
 }
diff -urN oldtree/arch/ppc/platforms/hdpu.h newtree/arch/ppc/platforms/hdpu.h
--- oldtree/arch/ppc/platforms/hdpu.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/hdpu.h	2006-02-21 15:58:17.382504016 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/hdpu.h
- *
  * Definitions for Sky Computers HDPU board.
  *
  * Brian Waite <waite@skycomputers.com>
diff -urN oldtree/arch/ppc/platforms/katana.c newtree/arch/ppc/platforms/katana.c
--- oldtree/arch/ppc/platforms/katana.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/katana.c	2006-02-21 15:58:17.383503864 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/katana.c
- *
  * Board setup routines for the Artesyn Katana cPCI boards.
  *
  * Author: Tim Montgomery <timm@artesyncp.com>
diff -urN oldtree/arch/ppc/platforms/katana.h newtree/arch/ppc/platforms/katana.h
--- oldtree/arch/ppc/platforms/katana.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/katana.h	2006-02-21 15:58:17.384503712 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/katana.h
- *
  * Definitions for Artesyn Katana750i/3750 board.
  *
  * Author: Tim Montgomery <timm@artesyncp.com>
diff -urN oldtree/arch/ppc/platforms/lite5200.c newtree/arch/ppc/platforms/lite5200.c
--- oldtree/arch/ppc/platforms/lite5200.c	2006-02-19 11:40:59.466424216 +0000
+++ newtree/arch/ppc/platforms/lite5200.c	2006-02-21 15:58:17.384503712 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/lite5200.c
- *
  * Platform support file for the Freescale LITE5200 based on MPC52xx.
  * A maximum of this file should be moved to syslib/mpc52xx_?????
  * so that new platform based on MPC52xx need a minimal platform file
diff -urN oldtree/arch/ppc/platforms/lite5200.h newtree/arch/ppc/platforms/lite5200.h
--- oldtree/arch/ppc/platforms/lite5200.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/lite5200.h	2006-02-21 15:58:17.384503712 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/lite5200.h
- * 
  * Definitions for Freescale LITE5200 : MPC52xx Standard Development
  * Platform board support
  * 
diff -urN oldtree/arch/ppc/platforms/lopec.c newtree/arch/ppc/platforms/lopec.c
--- oldtree/arch/ppc/platforms/lopec.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/lopec.c	2006-02-21 15:58:17.385503560 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/lopec.c
- *
  * Setup routines for the Motorola LoPEC.
  *
  * Author: Dan Cox
diff -urN oldtree/arch/ppc/platforms/mpc8272ads_setup.c newtree/arch/ppc/platforms/mpc8272ads_setup.c
--- oldtree/arch/ppc/platforms/mpc8272ads_setup.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/ppc/platforms/mpc8272ads_setup.c	2006-02-21 15:58:17.385503560 +0000
@@ -0,0 +1,236 @@
+/*
+ * arch/ppc/platforms/82xx/pq2ads_pd.c
+ *
+ * MPC82xx Board-specific PlatformDevice descriptions
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <linux/fs_enet_pd.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <asm/mpc8260.h>
+#include <asm/cpm2.h>
+#include <asm/immap_cpm2.h>
+#include <asm/irq.h>
+#include <asm/ppc_sys.h>
+#include <asm/ppcboot.h>
+
+#include "pq2ads_pd.h"
+
+static void init_fcc1_ioports(void);
+static void init_fcc2_ioports(void);
+
+static struct fs_mii_bus_info mii_bus_info = {
+	.method                 = fsmii_bitbang,
+	.id                     = 0,
+	.i.bitbang = {
+		.mdio_port	= fsiop_portc,
+		.mdio_bit	= 18,
+		.mdc_port	= fsiop_portc,
+		.mdc_bit	= 19,
+		.delay		= 1,
+	},
+};
+
+static struct fs_platform_info mpc82xx_fcc1_pdata = {
+	.fs_no		= fsid_fcc1,
+	.cp_page	= CPM_CR_FCC1_PAGE,
+	.cp_block 	= CPM_CR_FCC1_SBLOCK,
+	.clk_trx 	= (PC_F1RXCLK | PC_F1TXCLK),
+	.clk_route	= CMX1_CLK_ROUTE,
+	.clk_mask	= CMX1_CLK_MASK,
+	.init_ioports 	= init_fcc1_ioports,
+
+	.phy_addr	= 0,
+#ifdef PHY_INTERRUPT
+	.phy_irq	= PHY_INTERRUPT,
+#else
+	.phy_irq	= -1;
+#endif
+	.mem_offset	= FCC1_MEM_OFFSET,
+	.bus_info	= &mii_bus_info,
+	.rx_ring	= 32,
+	.tx_ring	= 32,
+	.rx_copybreak	= 240,
+	.use_napi	= 0,
+	.napi_weight	= 17,
+};
+
+static struct fs_platform_info mpc82xx_fcc2_pdata = {
+	.fs_no		= fsid_fcc2,
+	.cp_page	= CPM_CR_FCC2_PAGE,
+	.cp_block 	= CPM_CR_FCC2_SBLOCK,
+	.clk_trx 	= (PC_F2RXCLK | PC_F2TXCLK),
+	.clk_route	= CMX2_CLK_ROUTE,
+	.clk_mask	= CMX2_CLK_MASK,
+	.init_ioports	= init_fcc2_ioports,
+
+	.phy_addr	= 3,
+#ifdef PHY_INTERRUPT
+	.phy_irq	= PHY_INTERRUPT,
+#else
+	.phy_irq	= -1;
+#endif
+	.mem_offset	= FCC2_MEM_OFFSET,
+	.bus_info	= &mii_bus_info,
+	.rx_ring	= 32,
+	.tx_ring	= 32,
+	.rx_copybreak	= 240,
+	.use_napi	= 0,
+	.napi_weight	= 17,
+};
+
+static void init_fcc1_ioports(void)
+{
+	struct io_port *io;
+	u32 tempval;
+	cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t));
+	u32 *bcsr = ioremap(BCSR_ADDR+4, sizeof(u32));
+
+	io = &immap->im_ioport;
+
+	/* Enable the PHY */
+	clrbits32(bcsr, BCSR1_FETHIEN);
+	setbits32(bcsr, BCSR1_FETH_RST);
+
+	/* FCC1 pins are on port A/C. */
+	/* Configure port A and C pins for FCC1 Ethernet. */
+
+	tempval = in_be32(&io->iop_pdira);
+	tempval &= ~PA1_DIRA0;
+	tempval |= PA1_DIRA1;
+	out_be32(&io->iop_pdira, tempval);
+
+	tempval = in_be32(&io->iop_psora);
+	tempval &= ~PA1_PSORA0;
+	tempval |= PA1_PSORA1;
+	out_be32(&io->iop_psora, tempval);
+
+	setbits32(&io->iop_ppara,PA1_DIRA0 | PA1_DIRA1);
+
+	/* Alter clocks */
+	tempval = PC_F1TXCLK|PC_F1RXCLK;
+
+	clrbits32(&io->iop_psorc, tempval);
+	clrbits32(&io->iop_pdirc, tempval);
+	setbits32(&io->iop_pparc, tempval);
+
+	clrbits32(&immap->im_cpmux.cmx_fcr, CMX1_CLK_MASK);
+	setbits32(&immap->im_cpmux.cmx_fcr, CMX1_CLK_ROUTE);
+	iounmap(bcsr);
+	iounmap(immap);
+}
+
+static void init_fcc2_ioports(void)
+{
+	cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t));
+	u32 *bcsr = ioremap(BCSR_ADDR+12, sizeof(u32));
+
+	struct io_port *io;
+	u32 tempval;
+
+	immap = cpm2_immr;
+
+	io = &immap->im_ioport;
+
+	/* Enable the PHY */
+	clrbits32(bcsr, BCSR3_FETHIEN2);
+	setbits32(bcsr, BCSR3_FETH2_RST);
+
+	/* FCC2 are port B/C. */
+	/* Configure port A and C pins for FCC2 Ethernet. */
+
+	tempval = in_be32(&io->iop_pdirb);
+	tempval &= ~PB2_DIRB0;
+	tempval |= PB2_DIRB1;
+	out_be32(&io->iop_pdirb, tempval);
+
+	tempval = in_be32(&io->iop_psorb);
+	tempval &= ~PB2_PSORB0;
+	tempval |= PB2_PSORB1;
+	out_be32(&io->iop_psorb, tempval);
+
+	setbits32(&io->iop_pparb,PB2_DIRB0 | PB2_DIRB1);
+
+	tempval = PC_F2RXCLK|PC_F2TXCLK;
+
+	/* Alter clocks */
+	clrbits32(&io->iop_psorc,tempval);
+	clrbits32(&io->iop_pdirc,tempval);
+	setbits32(&io->iop_pparc,tempval);
+
+	clrbits32(&immap->im_cpmux.cmx_fcr, CMX2_CLK_MASK);
+	setbits32(&immap->im_cpmux.cmx_fcr, CMX2_CLK_ROUTE);
+
+	iounmap(bcsr);
+	iounmap(immap);
+}
+
+
+static void __init mpc8272ads_fixup_enet_pdata(struct platform_device *pdev,
+					      int idx)
+{
+	bd_t* bi = (void*)__res;
+	int fs_no = fsid_fcc1+pdev->id-1;
+
+	mpc82xx_fcc1_pdata.dpram_offset = mpc82xx_fcc2_pdata.dpram_offset = (u32)cpm2_immr->im_dprambase;
+	mpc82xx_fcc1_pdata.fcc_regs_c = mpc82xx_fcc2_pdata.fcc_regs_c = (u32)cpm2_immr->im_fcc_c;
+
+	switch(fs_no) {
+		case fsid_fcc1:
+			memcpy(&mpc82xx_fcc1_pdata.macaddr,bi->bi_enetaddr,6);
+			pdev->dev.platform_data = &mpc82xx_fcc1_pdata;
+		break;
+		case fsid_fcc2:
+			memcpy(&mpc82xx_fcc2_pdata.macaddr,bi->bi_enetaddr,6);
+			mpc82xx_fcc2_pdata.macaddr[5] ^= 1;
+			pdev->dev.platform_data = &mpc82xx_fcc2_pdata;
+		break;
+	}
+}
+
+static int mpc8272ads_platform_notify(struct device *dev)
+{
+	static const struct platform_notify_dev_map dev_map[] = {
+		{
+			.bus_id = "fsl-cpm-fcc",
+			.rtn = mpc8272ads_fixup_enet_pdata
+		},
+		{
+			.bus_id = NULL
+		}
+	};
+	platform_notify_map(dev_map,dev);
+
+	return 0;
+
+}
+
+int __init mpc8272ads_init(void)
+{
+	printk(KERN_NOTICE "mpc8272ads: Init\n");
+
+	platform_notify = mpc8272ads_platform_notify;
+
+	ppc_sys_device_initfunc();
+
+	ppc_sys_device_disable_all();
+	ppc_sys_device_enable(MPC82xx_CPM_FCC1);
+	ppc_sys_device_enable(MPC82xx_CPM_FCC2);
+
+	return 0;
+}
+
+arch_initcall(mpc8272ads_init);
diff -urN oldtree/arch/ppc/platforms/mpc866ads_setup.c newtree/arch/ppc/platforms/mpc866ads_setup.c
--- oldtree/arch/ppc/platforms/mpc866ads_setup.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/ppc/platforms/mpc866ads_setup.c	2006-02-21 15:58:17.386503408 +0000
@@ -0,0 +1,273 @@
+/*arch/ppc/platforms/mpc885ads-setup.c
+ *
+ * Platform setup for the Freescale mpc885ads board
+ *
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * Copyright 2005 MontaVista Software Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+
+#include <linux/fs_enet_pd.h>
+#include <linux/mii.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/ppcboot.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+#include <asm/ppc_sys.h>
+#include <asm/mpc8xx.h>
+
+extern unsigned char __res[];
+
+static struct fs_mii_bus_info fec_mii_bus_info = {
+	.method = fsmii_fec,
+	.id = 0,
+};
+
+static struct fs_mii_bus_info scc_mii_bus_info = {
+	.method = fsmii_fixed,
+	.id = 0,
+	.i.fixed.speed = 10,
+	.i.fixed.duplex = 0,
+};
+
+static struct fs_platform_info mpc8xx_fec_pdata[] = {
+	{
+	 .rx_ring = 128,
+	 .tx_ring = 16,
+	 .rx_copybreak = 240,
+
+	 .use_napi = 1,
+	 .napi_weight = 17,
+
+	 .phy_addr = 15,
+	 .phy_irq = -1,
+
+	 .use_rmii = 0,
+
+	 .bus_info = &fec_mii_bus_info,
+	 }
+};
+
+static struct fs_platform_info mpc8xx_scc_pdata = {
+	.rx_ring = 64,
+	.tx_ring = 8,
+	.rx_copybreak = 240,
+
+	.use_napi = 1,
+	.napi_weight = 17,
+
+	.phy_addr = -1,
+	.phy_irq = -1,
+
+	.bus_info = &scc_mii_bus_info,
+};
+
+void __init board_init(void)
+{
+	volatile cpm8xx_t *cp = cpmp;
+	unsigned *bcsr_io;
+
+	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+	if (bcsr_io == NULL) {
+		printk(KERN_CRIT "Could not remap BCSR1\n");
+		return;
+	}
+#ifdef CONFIG_SERIAL_CPM_SMC1
+	cp->cp_simode &= ~(0xe0000000 >> 17);	/* brg1 */
+	clrbits32(bcsr_io,(0x80000000 >> 7));
+#else
+	setbits32(bcsr_io,(0x80000000 >> 7));
+
+	cp->cp_pbpar &= ~(0x000000c0);
+	cp->cp_pbdir |= 0x000000c0;
+	cp->cp_smc[0].smc_smcmr = 0;
+	cp->cp_smc[0].smc_smce = 0;
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SMC2
+	cp->cp_simode &= ~(0xe0000000 >> 1);
+	cp->cp_simode |= (0x20000000 >> 1);	/* brg2 */
+	clrbits32(bcsr_io,(0x80000000 >> 13));
+#else
+	clrbits32(bcsr_io,(0x80000000 >> 13));
+	cp->cp_pbpar &= ~(0x00000c00);
+	cp->cp_pbdir |= 0x00000c00;
+	cp->cp_smc[1].smc_smcmr = 0;
+	cp->cp_smc[1].smc_smce = 0;
+#endif
+	iounmap(bcsr_io);
+}
+
+static void setup_fec1_ioports(void)
+{
+	immap_t *immap = (immap_t *) IMAP_ADDR;
+
+	setbits16(&immap->im_ioport.iop_pdpar, 0x1fff);
+	setbits16(&immap->im_ioport.iop_pddir, 0x1fff);
+}
+
+static void setup_scc1_ioports(void)
+{
+	immap_t *immap = (immap_t *) IMAP_ADDR;
+	unsigned *bcsr_io;
+
+	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+	if (bcsr_io == NULL) {
+		printk(KERN_CRIT "Could not remap BCSR1\n");
+		return;
+	}
+
+	/* Enable the PHY.
+	 */
+	clrbits32(bcsr_io,BCSR1_ETHEN);
+
+	/* Configure port A pins for Txd and Rxd.
+	 */
+	/* Disable receive and transmit in case EPPC-Bug started it.
+	 */
+	setbits16(&immap->im_ioport.iop_papar, PA_ENET_RXD | PA_ENET_TXD);
+	clrbits16(&immap->im_ioport.iop_padir, PA_ENET_RXD | PA_ENET_TXD);
+	clrbits16(&immap->im_ioport.iop_paodr, PA_ENET_TXD);
+
+	/* Configure port C pins to enable CLSN and RENA.
+	 */
+	clrbits16(&immap->im_ioport.iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA);
+	clrbits16(&immap->im_ioport.iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA);
+	setbits16(&immap->im_ioport.iop_pcso, PC_ENET_CLSN | PC_ENET_RENA);
+	/* Configure port A for TCLK and RCLK.
+	 */
+	setbits16(&immap->im_ioport.iop_papar, PA_ENET_TCLK | PA_ENET_RCLK);
+	clrbits16(&immap->im_ioport.iop_padir, PA_ENET_TCLK | PA_ENET_RCLK);
+	clrbits32(&immap->im_cpm.cp_pbpar, PB_ENET_TENA);
+	clrbits32(&immap->im_cpm.cp_pbdir, PB_ENET_TENA);
+
+	/* Configure Serial Interface clock routing.
+	 * First, clear all SCC bits to zero, then set the ones we want.
+	 */
+	clrbits32(&immap->im_cpm.cp_sicr, SICR_ENET_MASK);
+	setbits32(&immap->im_cpm.cp_sicr, SICR_ENET_CLKRT);
+
+	/* In the original SCC enet driver the following code is placed at
+	the end of the initialization */
+	setbits32(&immap->im_cpm.cp_pbpar, PB_ENET_TENA);
+	setbits32(&immap->im_cpm.cp_pbdir, PB_ENET_TENA);
+
+}
+
+static void mpc866ads_fixup_enet_pdata(struct platform_device *pdev, int fs_no)
+{
+	struct fs_platform_info *fpi = pdev->dev.platform_data;
+
+	volatile cpm8xx_t *cp;
+	bd_t *bd = (bd_t *) __res;
+	char *e;
+	int i;
+
+	/* Get pointer to Communication Processor */
+	cp = cpmp;
+	switch (fs_no) {
+	case fsid_fec1:
+		fpi = &mpc8xx_fec_pdata[0];
+		fpi->init_ioports = &setup_fec1_ioports;
+
+		break;
+	case fsid_scc1:
+		fpi = &mpc8xx_scc_pdata;
+		fpi->init_ioports = &setup_scc1_ioports;
+
+		break;
+	default:
+		printk(KERN_WARNING"Device %s is not supported!\n", pdev->name);
+		return;
+	}
+
+	pdev->dev.platform_data = fpi;
+	fpi->fs_no = fs_no;
+
+	e = (unsigned char *)&bd->bi_enetaddr;
+	for (i = 0; i < 6; i++)
+		fpi->macaddr[i] = *e++;
+
+	fpi->macaddr[5 - pdev->id]++;
+
+}
+
+static void mpc866ads_fixup_fec_enet_pdata(struct platform_device *pdev,
+					   int idx)
+{
+	/* This is for FEC devices only */
+	if (!pdev || !pdev->name || (!strstr(pdev->name, "fsl-cpm-fec")))
+		return;
+	mpc866ads_fixup_enet_pdata(pdev, fsid_fec1 + pdev->id - 1);
+}
+
+static void mpc866ads_fixup_scc_enet_pdata(struct platform_device *pdev,
+					   int idx)
+{
+	/* This is for SCC devices only */
+	if (!pdev || !pdev->name || (!strstr(pdev->name, "fsl-cpm-scc")))
+		return;
+
+	mpc866ads_fixup_enet_pdata(pdev, fsid_scc1 + pdev->id - 1);
+}
+
+static int mpc866ads_platform_notify(struct device *dev)
+{
+	static const struct platform_notify_dev_map dev_map[] = {
+		{
+			.bus_id = "fsl-cpm-fec",
+			.rtn = mpc866ads_fixup_fec_enet_pdata,
+		},
+		{
+			.bus_id = "fsl-cpm-scc",
+			.rtn = mpc866ads_fixup_scc_enet_pdata,
+		},
+		{
+			.bus_id = NULL
+		}
+	};
+
+	platform_notify_map(dev_map,dev);
+
+	return 0;
+}
+
+int __init mpc866ads_init(void)
+{
+	printk(KERN_NOTICE "mpc866ads: Init\n");
+
+	platform_notify = mpc866ads_platform_notify;
+
+	ppc_sys_device_initfunc();
+	ppc_sys_device_disable_all();
+
+#ifdef MPC8xx_SECOND_ETH_SCC1
+	ppc_sys_device_enable(MPC8xx_CPM_SCC1);
+#endif
+	ppc_sys_device_enable(MPC8xx_CPM_FEC1);
+
+	return 0;
+}
+
+arch_initcall(mpc866ads_init);
diff -urN oldtree/arch/ppc/platforms/mpc885ads_setup.c newtree/arch/ppc/platforms/mpc885ads_setup.c
--- oldtree/arch/ppc/platforms/mpc885ads_setup.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/ppc/platforms/mpc885ads_setup.c	2006-02-21 15:58:17.427497176 +0000
@@ -0,0 +1,389 @@
+/*arch/ppc/platforms/mpc885ads-setup.c
+ *
+ * Platform setup for the Freescale mpc885ads board
+ *
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * Copyright 2005 MontaVista Software Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+
+#include <linux/fs_enet_pd.h>
+#include <linux/mii.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/ppcboot.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+#include <asm/ppc_sys.h>
+
+extern unsigned char __res[];
+
+static void __init mpc885ads_scc_phy_init(char);
+
+static struct fs_mii_bus_info fec_mii_bus_info = {
+	.method = fsmii_fec,
+	.id = 0,
+};
+
+static struct fs_mii_bus_info scc_mii_bus_info = {
+#ifdef CONFIG_SCC_ENET_8xx_FIXED
+	.method = fsmii_fixed,
+#else
+	.method = fsmii_fec,
+#endif
+
+	.id = 0,
+};
+
+static struct fs_platform_info mpc8xx_fec_pdata[] = {
+	{
+	 .rx_ring = 128,
+	 .tx_ring = 16,
+	 .rx_copybreak = 240,
+
+	 .use_napi = 1,
+	 .napi_weight = 17,
+
+	 .phy_addr = 0,
+	 .phy_irq = SIU_IRQ7,
+
+	 .bus_info = &fec_mii_bus_info,
+	 }, {
+	     .rx_ring = 128,
+	     .tx_ring = 16,
+	     .rx_copybreak = 240,
+
+	     .use_napi = 1,
+	     .napi_weight = 17,
+
+	     .phy_addr = 1,
+	     .phy_irq = SIU_IRQ7,
+
+	     .bus_info = &fec_mii_bus_info,
+	     }
+};
+
+static struct fs_platform_info mpc8xx_scc_pdata = {
+	.rx_ring = 64,
+	.tx_ring = 8,
+	.rx_copybreak = 240,
+
+	.use_napi = 1,
+	.napi_weight = 17,
+
+	.phy_addr = 2,
+#ifdef CONFIG_MPC8xx_SCC_ENET_FIXED
+	.phy_irq = -1,
+#else
+	.phy_irq = SIU_IRQ7,
+#endif
+
+	.bus_info = &scc_mii_bus_info,
+};
+
+void __init board_init(void)
+{
+	volatile cpm8xx_t *cp = cpmp;
+	unsigned int *bcsr_io;
+
+#ifdef CONFIG_FS_ENET
+	immap_t *immap = (immap_t *) IMAP_ADDR;
+#endif
+	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+	if (bcsr_io == NULL) {
+		printk(KERN_CRIT "Could not remap BCSR\n");
+		return;
+	}
+#ifdef CONFIG_SERIAL_CPM_SMC1
+	cp->cp_simode &= ~(0xe0000000 >> 17);	/* brg1 */
+	clrbits32(bcsr_io, BCSR1_RS232EN_1);
+#else
+	setbits32(bcsr_io,BCSR1_RS232EN_1);
+	cp->cp_smc[0].smc_smcmr = 0;
+	cp->cp_smc[0].smc_smce = 0;
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SMC2
+	cp->cp_simode &= ~(0xe0000000 >> 1);
+	cp->cp_simode |= (0x20000000 >> 1);	/* brg2 */
+	clrbits32(bcsr_io,BCSR1_RS232EN_2);
+#else
+	setbits32(bcsr_io,BCSR1_RS232EN_2);
+	cp->cp_smc[1].smc_smcmr = 0;
+	cp->cp_smc[1].smc_smce = 0;
+#endif
+	iounmap(bcsr_io);
+
+#ifdef CONFIG_FS_ENET
+	/* use MDC for MII (common) */
+	setbits16(&immap->im_ioport.iop_pdpar, 0x0080);
+	clrbits16(&immap->im_ioport.iop_pddir, 0x0080);
+#endif
+}
+
+static void setup_fec1_ioports(void)
+{
+	immap_t *immap = (immap_t *) IMAP_ADDR;
+
+	/* configure FEC1 pins  */
+	setbits16(&immap->im_ioport.iop_papar, 0xf830);
+	setbits16(&immap->im_ioport.iop_padir, 0x0830);
+	clrbits16(&immap->im_ioport.iop_padir, 0xf000);
+	setbits32(&immap->im_cpm.cp_pbpar, 0x00001001);
+
+	clrbits32(&immap->im_cpm.cp_pbdir, 0x00001001);
+	setbits16(&immap->im_ioport.iop_pcpar, 0x000c);
+	clrbits16(&immap->im_ioport.iop_pcdir, 0x000c);
+	setbits32(&immap->im_cpm.cp_pepar, 0x00000003);
+
+	setbits32(&immap->im_cpm.cp_pedir, 0x00000003);
+	clrbits32(&immap->im_cpm.cp_peso, 0x00000003);
+	clrbits32(&immap->im_cpm.cp_cptr, 0x00000100);
+}
+
+static void setup_fec2_ioports(void)
+{
+	immap_t *immap = (immap_t *) IMAP_ADDR;
+
+	/* configure FEC2 pins */
+	setbits32(&immap->im_cpm.cp_pepar, 0x0003fffc);
+	setbits32(&immap->im_cpm.cp_pedir, 0x0003fffc);
+	setbits32(&immap->im_cpm.cp_peso, 0x00037800);
+	clrbits32(&immap->im_cpm.cp_peso, 0x000087fc);
+	clrbits32(&immap->im_cpm.cp_cptr, 0x00000080);
+}
+
+static void setup_scc3_ioports(void)
+{
+	immap_t *immap = (immap_t *) IMAP_ADDR;
+	unsigned *bcsr_io;
+
+	bcsr_io = ioremap(BCSR_ADDR, BCSR_SIZE);
+
+	if (bcsr_io == NULL) {
+		printk(KERN_CRIT "Could not remap BCSR\n");
+		return;
+	}
+
+	/* Enable the PHY.
+	 */
+	setbits32(bcsr_io+4, BCSR4_ETH10_RST);
+	/* Configure port A pins for Txd and Rxd.
+	 */
+	setbits16(&immap->im_ioport.iop_papar, PA_ENET_RXD | PA_ENET_TXD);
+	clrbits16(&immap->im_ioport.iop_padir, PA_ENET_RXD | PA_ENET_TXD);
+
+	/* Configure port C pins to enable CLSN and RENA.
+	 */
+	clrbits16(&immap->im_ioport.iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA);
+	clrbits16(&immap->im_ioport.iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA);
+	setbits16(&immap->im_ioport.iop_pcso, PC_ENET_CLSN | PC_ENET_RENA);
+
+	/* Configure port E for TCLK and RCLK.
+	 */
+	setbits32(&immap->im_cpm.cp_pepar, PE_ENET_TCLK | PE_ENET_RCLK);
+	clrbits32(&immap->im_cpm.cp_pepar, PE_ENET_TENA);
+	clrbits32(&immap->im_cpm.cp_pedir,
+		  PE_ENET_TCLK | PE_ENET_RCLK | PE_ENET_TENA);
+	clrbits32(&immap->im_cpm.cp_peso, PE_ENET_TCLK | PE_ENET_RCLK);
+	setbits32(&immap->im_cpm.cp_peso, PE_ENET_TENA);
+
+	/* Configure Serial Interface clock routing.
+	 * First, clear all SCC bits to zero, then set the ones we want.
+	 */
+	clrbits32(&immap->im_cpm.cp_sicr, SICR_ENET_MASK);
+	setbits32(&immap->im_cpm.cp_sicr, SICR_ENET_CLKRT);
+
+	/* Disable Rx and Tx. SMC1 sshould be stopped if SCC3 eternet are used.
+	 */
+	immap->im_cpm.cp_smc[0].smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+	/* On the MPC885ADS SCC ethernet PHY is initialized in the full duplex mode
+	 * by H/W setting after reset. SCC ethernet controller support only half duplex.
+	 * This discrepancy of modes causes a lot of carrier lost errors.
+	 */
+
+	/* In the original SCC enet driver the following code is placed at
+	   the end of the initialization */
+	setbits32(&immap->im_cpm.cp_pepar, PE_ENET_TENA);
+	clrbits32(&immap->im_cpm.cp_pedir, PE_ENET_TENA);
+	setbits32(&immap->im_cpm.cp_peso, PE_ENET_TENA);
+
+	setbits32(bcsr_io+1, BCSR1_ETHEN);
+	iounmap(bcsr_io);
+}
+
+static void mpc885ads_fixup_enet_pdata(struct platform_device *pdev, int fs_no)
+{
+	struct fs_platform_info *fpi = pdev->dev.platform_data;
+
+	volatile cpm8xx_t *cp;
+	bd_t *bd = (bd_t *) __res;
+	char *e;
+	int i;
+
+	/* Get pointer to Communication Processor */
+	cp = cpmp;
+	switch (fs_no) {
+	case fsid_fec1:
+		fpi = &mpc8xx_fec_pdata[0];
+		fpi->init_ioports = &setup_fec1_ioports;
+		break;
+	case fsid_fec2:
+		fpi = &mpc8xx_fec_pdata[1];
+		fpi->init_ioports = &setup_fec2_ioports;
+		break;
+	case fsid_scc3:
+		fpi = &mpc8xx_scc_pdata;
+		fpi->init_ioports = &setup_scc3_ioports;
+		mpc885ads_scc_phy_init(fpi->phy_addr);
+		break;
+	default:
+    	        printk(KERN_WARNING"Device %s is not supported!\n", pdev->name);
+	        return;
+	}
+
+	pdev->dev.platform_data = fpi;
+	fpi->fs_no = fs_no;
+
+	e = (unsigned char *)&bd->bi_enetaddr;
+	for (i = 0; i < 6; i++)
+		fpi->macaddr[i] = *e++;
+
+	fpi->macaddr[5 - pdev->id]++;
+
+}
+
+static void mpc885ads_fixup_fec_enet_pdata(struct platform_device *pdev,
+					   int idx)
+{
+	/* This is for FEC devices only */
+	if (!pdev || !pdev->name || (!strstr(pdev->name, "fsl-cpm-fec")))
+		return;
+	mpc885ads_fixup_enet_pdata(pdev, fsid_fec1 + pdev->id - 1);
+}
+
+static void __init mpc885ads_fixup_scc_enet_pdata(struct platform_device *pdev,
+						  int idx)
+{
+	/* This is for SCC devices only */
+	if (!pdev || !pdev->name || (!strstr(pdev->name, "fsl-cpm-scc")))
+		return;
+
+	mpc885ads_fixup_enet_pdata(pdev, fsid_scc1 + pdev->id - 1);
+}
+
+/* SCC ethernet controller does not have MII management channel. FEC1 MII
+ * channel is used to communicate with the 10Mbit PHY.
+ */
+
+#define MII_ECNTRL_PINMUX        0x4
+#define FEC_ECNTRL_PINMUX        0x00000004
+#define FEC_RCNTRL_MII_MODE        0x00000004
+
+/* Make MII read/write commands.
+ */
+#define mk_mii_write(REG, VAL, PHY_ADDR)    (0x50020000 | (((REG) & 0x1f) << 18) | \
+                ((VAL) & 0xffff) | ((PHY_ADDR) << 23))
+
+static void mpc885ads_scc_phy_init(char phy_addr)
+{
+	volatile immap_t *immap;
+	volatile fec_t *fecp;
+	bd_t *bd;
+
+	bd = (bd_t *) __res;
+	immap = (immap_t *) IMAP_ADDR;	/* pointer to internal registers */
+	fecp = &(immap->im_cpm.cp_fec);
+
+	/* Enable MII pins of the FEC1
+	 */
+	setbits16(&immap->im_ioport.iop_pdpar, 0x0080);
+	clrbits16(&immap->im_ioport.iop_pddir, 0x0080);
+	/* Set MII speed to 2.5 MHz
+	 */
+	out_be32(&fecp->fec_mii_speed,
+		 ((((bd->bi_intfreq + 4999999) / 2500000) / 2) & 0x3F) << 1);
+
+	/* Enable FEC pin MUX
+	 */
+	setbits32(&fecp->fec_ecntrl, MII_ECNTRL_PINMUX);
+	setbits32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);
+
+	out_be32(&fecp->fec_mii_data,
+		 mk_mii_write(MII_BMCR, BMCR_ISOLATE, phy_addr));
+	udelay(100);
+	out_be32(&fecp->fec_mii_data,
+		 mk_mii_write(MII_ADVERTISE,
+			      ADVERTISE_10HALF | ADVERTISE_CSMA, phy_addr));
+	udelay(100);
+
+	/* Disable FEC MII settings
+	 */
+	clrbits32(&fecp->fec_ecntrl, MII_ECNTRL_PINMUX);
+	clrbits32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);
+	out_be32(&fecp->fec_mii_speed, 0);
+}
+
+static int mpc885ads_platform_notify(struct device *dev)
+{
+
+	static const struct platform_notify_dev_map dev_map[] = {
+		{
+			.bus_id = "fsl-cpm-fec",
+			.rtn = mpc885ads_fixup_fec_enet_pdata,
+		},
+		{
+			.bus_id = "fsl-cpm-scc",
+			.rtn = mpc885ads_fixup_scc_enet_pdata,
+		},
+		{
+			.bus_id = NULL
+		}
+	};
+
+	platform_notify_map(dev_map,dev);
+
+}
+
+int __init mpc885ads_init(void)
+{
+	printk(KERN_NOTICE "mpc885ads: Init\n");
+
+	platform_notify = mpc885ads_platform_notify;
+
+	ppc_sys_device_initfunc();
+	ppc_sys_device_disable_all();
+
+	ppc_sys_device_enable(MPC8xx_CPM_FEC1);
+
+#ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3
+	ppc_sys_device_enable(MPC8xx_CPM_SCC1);
+
+#endif
+#ifdef CONFIG_MPC8xx_SECOND_ETH_FEC2
+	ppc_sys_device_enable(MPC8xx_CPM_FEC2);
+#endif
+
+	return 0;
+}
+
+arch_initcall(mpc885ads_init);
diff -urN oldtree/arch/ppc/platforms/mvme5100.c newtree/arch/ppc/platforms/mvme5100.c
--- oldtree/arch/ppc/platforms/mvme5100.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/mvme5100.c	2006-02-21 15:58:17.428497024 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/mvme5100.c
- *
  * Board setup routines for the Motorola MVME5100.
  *
  * Author: Matt Porter <mporter@mvista.com>
diff -urN oldtree/arch/ppc/platforms/pal4.h newtree/arch/ppc/platforms/pal4.h
--- oldtree/arch/ppc/platforms/pal4.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/pal4.h	2006-02-21 15:58:17.428497024 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/pal4.h
- *
  * Definitions for SBS Palomar IV board
  *
  * Author: Dan Cox
diff -urN oldtree/arch/ppc/platforms/pal4_pci.c newtree/arch/ppc/platforms/pal4_pci.c
--- oldtree/arch/ppc/platforms/pal4_pci.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/pal4_pci.c	2006-02-21 15:58:17.428497024 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/pal4_pci.c
- *
  * PCI support for SBS Palomar IV
  *
  * Author: Dan Cox
diff -urN oldtree/arch/ppc/platforms/pal4_serial.h newtree/arch/ppc/platforms/pal4_serial.h
--- oldtree/arch/ppc/platforms/pal4_serial.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/pal4_serial.h	2006-02-21 15:58:17.429496872 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/pal4_serial.h
- *
  * Definitions for SBS PalomarIV serial support
  *
  * Author: Dan Cox
diff -urN oldtree/arch/ppc/platforms/pal4_setup.c newtree/arch/ppc/platforms/pal4_setup.c
--- oldtree/arch/ppc/platforms/pal4_setup.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/pal4_setup.c	2006-02-21 15:58:17.429496872 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/pal4_setup.c
- *
  * Board setup routines for the SBS PalomarIV.
  *
  * Author: Dan Cox
diff -urN oldtree/arch/ppc/platforms/powerpmc250.c newtree/arch/ppc/platforms/powerpmc250.c
--- oldtree/arch/ppc/platforms/powerpmc250.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/powerpmc250.c	2006-02-21 15:58:17.429496872 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/powerpmc250.c
- *
  * Board setup routines for Force PowerPMC-250 Processor PMC
  *
  * Author: Troy Benjegerdes <tbenjegerdes@mvista.com>
diff -urN oldtree/arch/ppc/platforms/pplus.c newtree/arch/ppc/platforms/pplus.c
--- oldtree/arch/ppc/platforms/pplus.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/pplus.c	2006-02-21 15:58:17.430496720 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/pplus.c
- *
  * Board and PCI setup routines for MCG PowerPlus
  *
  * Author: Randy Vinson <rvinson@mvista.com>
diff -urN oldtree/arch/ppc/platforms/pplus.h newtree/arch/ppc/platforms/pplus.h
--- oldtree/arch/ppc/platforms/pplus.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/pplus.h	2006-02-21 15:58:17.431496568 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/pplus.h
- *
  * Definitions for Motorola MCG Falcon/Raven & HAWK North Bridge & Memory ctlr.
  *
  * Author: Mark A. Greerinclude/asm-ppc/hawk.h
diff -urN oldtree/arch/ppc/platforms/pq2ads.c newtree/arch/ppc/platforms/pq2ads.c
--- oldtree/arch/ppc/platforms/pq2ads.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/pq2ads.c	2006-02-21 15:58:17.431496568 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/pq2ads.c
- *
  * PQ2ADS platform support
  *
  * Author: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/platforms/pq2ads.h newtree/arch/ppc/platforms/pq2ads.h
--- oldtree/arch/ppc/platforms/pq2ads.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/pq2ads.h	2006-02-21 15:58:17.431496568 +0000
@@ -13,6 +13,10 @@
 
 #include <asm/ppcboot.h>
 
+#if defined(CONFIG_ADS8272)
+#define BOARD_CHIP_NAME "8272"
+#endif
+
 /* Memory map is configured by the PROM startup.
  * We just map a few things we need.  The CSR is actually 4 byte-wide
  * registers that can be accessed as 8-, 16-, or 32-bit values.
diff -urN oldtree/arch/ppc/platforms/pq2ads_pd.h newtree/arch/ppc/platforms/pq2ads_pd.h
--- oldtree/arch/ppc/platforms/pq2ads_pd.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/ppc/platforms/pq2ads_pd.h	2006-02-21 15:58:17.432496416 +0000
@@ -0,0 +1,114 @@
+#ifndef __PQ2ADS_PD_H
+#define __PQ2ADS_PD_H
+/*
+ * arch/ppc/platforms/82xx/pq2ads_pd.h
+ *
+ * Some defines for MPC82xx board-specific PlatformDevice descriptions
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/* FCC1 Clock Source Configuration.  These can be redefined in the board specific file.
+   Can only choose from CLK9-12 */
+
+#define F1_RXCLK	11
+#define F1_TXCLK	10
+
+/* FCC2 Clock Source Configuration.  These can be redefined in the board specific file.
+   Can only choose from CLK13-16 */
+#define F2_RXCLK	15
+#define F2_TXCLK	16
+
+/* FCC3 Clock Source Configuration.  These can be redefined in the board specific file.
+   Can only choose from CLK13-16 */
+#define F3_RXCLK	13
+#define F3_TXCLK	14
+
+/* Automatically generates register configurations */
+#define PC_CLK(x)	((uint)(1<<(x-1)))	/* FCC CLK I/O ports */
+
+#define CMXFCR_RF1CS(x)	((uint)((x-5)<<27))	/* FCC1 Receive Clock Source */
+#define CMXFCR_TF1CS(x)	((uint)((x-5)<<24))	/* FCC1 Transmit Clock Source */
+#define CMXFCR_RF2CS(x)	((uint)((x-9)<<19))	/* FCC2 Receive Clock Source */
+#define CMXFCR_TF2CS(x) ((uint)((x-9)<<16))	/* FCC2 Transmit Clock Source */
+#define CMXFCR_RF3CS(x)	((uint)((x-9)<<11))	/* FCC3 Receive Clock Source */
+#define CMXFCR_TF3CS(x) ((uint)((x-9)<<8))	/* FCC3 Transmit Clock Source */
+
+#define PC_F1RXCLK	PC_CLK(F1_RXCLK)
+#define PC_F1TXCLK	PC_CLK(F1_TXCLK)
+#define CMX1_CLK_ROUTE	(CMXFCR_RF1CS(F1_RXCLK) | CMXFCR_TF1CS(F1_TXCLK))
+#define CMX1_CLK_MASK	((uint)0xff000000)
+
+#define PC_F2RXCLK	PC_CLK(F2_RXCLK)
+#define PC_F2TXCLK	PC_CLK(F2_TXCLK)
+#define CMX2_CLK_ROUTE	(CMXFCR_RF2CS(F2_RXCLK) | CMXFCR_TF2CS(F2_TXCLK))
+#define CMX2_CLK_MASK	((uint)0x00ff0000)
+
+#define PC_F3RXCLK	PC_CLK(F3_RXCLK)
+#define PC_F3TXCLK	PC_CLK(F3_TXCLK)
+#define CMX3_CLK_ROUTE	(CMXFCR_RF3CS(F3_RXCLK) | CMXFCR_TF3CS(F3_TXCLK))
+#define CMX3_CLK_MASK	((uint)0x0000ff00)
+
+/* I/O Pin assignment for FCC1.  I don't yet know the best way to do this,
+ * but there is little variation among the choices.
+ */
+#define PA1_COL		0x00000001U
+#define PA1_CRS		0x00000002U
+#define PA1_TXER	0x00000004U
+#define PA1_TXEN	0x00000008U
+#define PA1_RXDV	0x00000010U
+#define PA1_RXER	0x00000020U
+#define PA1_TXDAT	0x00003c00U
+#define PA1_RXDAT	0x0003c000U
+#define PA1_PSORA0	(PA1_RXDAT | PA1_TXDAT)
+#define PA1_PSORA1	(PA1_COL | PA1_CRS | PA1_TXER | PA1_TXEN | \
+		PA1_RXDV | PA1_RXER)
+#define PA1_DIRA0	(PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV)
+#define PA1_DIRA1	(PA1_TXDAT | PA1_TXEN | PA1_TXER)
+
+
+/* I/O Pin assignment for FCC2.  I don't yet know the best way to do this,
+ * but there is little variation among the choices.
+ */
+#define PB2_TXER	0x00000001U
+#define PB2_RXDV	0x00000002U
+#define PB2_TXEN	0x00000004U
+#define PB2_RXER	0x00000008U
+#define PB2_COL		0x00000010U
+#define PB2_CRS		0x00000020U
+#define PB2_TXDAT	0x000003c0U
+#define PB2_RXDAT	0x00003c00U
+#define PB2_PSORB0	(PB2_RXDAT | PB2_TXDAT | PB2_CRS | PB2_COL | \
+		PB2_RXER | PB2_RXDV | PB2_TXER)
+#define PB2_PSORB1	(PB2_TXEN)
+#define PB2_DIRB0	(PB2_RXDAT | PB2_CRS | PB2_COL | PB2_RXER | PB2_RXDV)
+#define PB2_DIRB1	(PB2_TXDAT | PB2_TXEN | PB2_TXER)
+
+
+/* I/O Pin assignment for FCC3.  I don't yet know the best way to do this,
+ * but there is little variation among the choices.
+ */
+#define PB3_RXDV	0x00004000U
+#define PB3_RXER	0x00008000U
+#define PB3_TXER	0x00010000U
+#define PB3_TXEN	0x00020000U
+#define PB3_COL		0x00040000U
+#define PB3_CRS		0x00080000U
+#define PB3_TXDAT	0x0f000000U
+#define PB3_RXDAT	0x00f00000U
+#define PB3_PSORB0	(PB3_RXDAT | PB3_TXDAT | PB3_CRS | PB3_COL | \
+		PB3_RXER | PB3_RXDV | PB3_TXER | PB3_TXEN)
+#define PB3_PSORB1	0
+#define PB3_DIRB0	(PB3_RXDAT | PB3_CRS | PB3_COL | PB3_RXER | PB3_RXDV)
+#define PB3_DIRB1	(PB3_TXDAT | PB3_TXEN | PB3_TXER)
+
+#define FCC_MEM_OFFSET(x) (CPM_FCC_SPECIAL_BASE + (x*128))
+#define FCC1_MEM_OFFSET FCC_MEM_OFFSET(0)
+#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(1)
+
+#endif
diff -urN oldtree/arch/ppc/platforms/prep_setup.c newtree/arch/ppc/platforms/prep_setup.c
--- oldtree/arch/ppc/platforms/prep_setup.c	2006-02-19 11:40:59.482421784 +0000
+++ newtree/arch/ppc/platforms/prep_setup.c	2006-02-21 15:58:17.432496416 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/platforms/setup.c
- *
  *  Copyright (C) 1995  Linus Torvalds
  *  Adapted from 'alpha' version by Gary Thomas
  *  Modified by Cort Dougan (cort@cs.nmt.edu)
diff -urN oldtree/arch/ppc/platforms/prpmc750.c newtree/arch/ppc/platforms/prpmc750.c
--- oldtree/arch/ppc/platforms/prpmc750.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/prpmc750.c	2006-02-21 15:58:17.433496264 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/prpmc750_setup.c
- *
  * Board setup routines for Motorola PrPMC750
  *
  * Author: Matt Porter <mporter@mvista.com>
diff -urN oldtree/arch/ppc/platforms/prpmc800.c newtree/arch/ppc/platforms/prpmc800.c
--- oldtree/arch/ppc/platforms/prpmc800.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/prpmc800.c	2006-02-21 15:58:17.434496112 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/prpmc800.c
- *
  * Author: Dale Farnsworth <dale.farnsworth@mvista.com>
  *
  * 2001-2004 (c) MontaVista, Software, Inc.  This file is licensed under
diff -urN oldtree/arch/ppc/platforms/radstone_ppc7d.c newtree/arch/ppc/platforms/radstone_ppc7d.c
--- oldtree/arch/ppc/platforms/radstone_ppc7d.c	2006-02-19 11:40:59.483421632 +0000
+++ newtree/arch/ppc/platforms/radstone_ppc7d.c	2006-02-21 15:58:17.435495960 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/radstone_ppc7d.c
- *
  * Board setup routines for the Radstone PPC7D boards.
  *
  * Author: James Chapman <jchapman@katalix.com>
diff -urN oldtree/arch/ppc/platforms/radstone_ppc7d.h newtree/arch/ppc/platforms/radstone_ppc7d.h
--- oldtree/arch/ppc/platforms/radstone_ppc7d.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/radstone_ppc7d.h	2006-02-21 15:58:17.436495808 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/radstone_ppc7d.h
- *
  * Board definitions for the Radstone PPC7D boards.
  *
  * Author: James Chapman <jchapman@katalix.com>
diff -urN oldtree/arch/ppc/platforms/sandpoint.c newtree/arch/ppc/platforms/sandpoint.c
--- oldtree/arch/ppc/platforms/sandpoint.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/sandpoint.c	2006-02-21 15:58:17.439495352 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/sandpoint_setup.c
- *
  * Board setup routines for the Motorola SPS Sandpoint Test Platform.
  *
  * Author: Mark A. Greer
diff -urN oldtree/arch/ppc/platforms/sandpoint.h newtree/arch/ppc/platforms/sandpoint.h
--- oldtree/arch/ppc/platforms/sandpoint.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/sandpoint.h	2006-02-21 15:58:17.439495352 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/sandpoint.h
- *
  * Definitions for Motorola SPS Sandpoint Test Platform
  *
  * Author: Mark A. Greer
diff -urN oldtree/arch/ppc/platforms/sbc82xx.c newtree/arch/ppc/platforms/sbc82xx.c
--- oldtree/arch/ppc/platforms/sbc82xx.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/sbc82xx.c	2006-02-21 15:58:17.440495200 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/sbc82xx.c
- *
  * SBC82XX platform support
  *
  * Author: Guy Streeter <streeter@redhat.com>
diff -urN oldtree/arch/ppc/platforms/spruce.c newtree/arch/ppc/platforms/spruce.c
--- oldtree/arch/ppc/platforms/spruce.c	2006-02-19 11:40:59.484421480 +0000
+++ newtree/arch/ppc/platforms/spruce.c	2006-02-21 15:58:17.440495200 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/spruce.c
- *
  * Board and PCI setup routines for IBM Spruce
  *
  * Author: MontaVista Software <source@mvista.com>
diff -urN oldtree/arch/ppc/platforms/tqm8260_setup.c newtree/arch/ppc/platforms/tqm8260_setup.c
--- oldtree/arch/ppc/platforms/tqm8260_setup.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/platforms/tqm8260_setup.c	2006-02-21 15:58:17.440495200 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/tqm8260_setup.c
- *
  * TQM8260 platform support
  *
  * Author: Allen Curtis <acurtis@onz.com>
diff -urN oldtree/arch/ppc/syslib/Makefile newtree/arch/ppc/syslib/Makefile
--- oldtree/arch/ppc/syslib/Makefile	2006-02-19 11:40:59.484421480 +0000
+++ newtree/arch/ppc/syslib/Makefile	2006-02-21 15:58:17.449493832 +0000
@@ -17,8 +17,8 @@
 obj-$(CONFIG_440SP)		+= ibm440gx_common.o ibm440sp_common.o
 obj-$(CONFIG_440SPE)		+= ibm440gx_common.o ibm440sp_common.o ppc440spe_pcie.o
 ifeq ($(CONFIG_4xx),y)
-ifeq ($(CONFIG_VIRTEX_II_PRO),y)
-obj-$(CONFIG_40x)		+= xilinx_pic.o
+ifeq ($(CONFIG_XILINX_VIRTEX),y)
+obj-$(CONFIG_40x)		+= xilinx_pic.o ppc_sys.o
 else
 ifeq ($(CONFIG_403),y)
 obj-$(CONFIG_40x)		+= ppc403_pic.o
diff -urN oldtree/arch/ppc/syslib/cpc700.h newtree/arch/ppc/syslib/cpc700.h
--- oldtree/arch/ppc/syslib/cpc700.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/cpc700.h	2006-02-21 15:58:17.441495048 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/cpc700.h
- *
  * Header file for IBM CPC700 Host Bridge, et. al.
  *
  * Author: Mark A. Greer
diff -urN oldtree/arch/ppc/syslib/cpc700_pic.c newtree/arch/ppc/syslib/cpc700_pic.c
--- oldtree/arch/ppc/syslib/cpc700_pic.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/cpc700_pic.c	2006-02-21 15:58:17.441495048 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/cpc700_pic.c
- *
  * Interrupt controller support for IBM Spruce
  *
  * Authors: Mark Greer, Matt Porter, and Johnnie Peters
diff -urN oldtree/arch/ppc/syslib/cpc710.h newtree/arch/ppc/syslib/cpc710.h
--- oldtree/arch/ppc/syslib/cpc710.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/cpc710.h	2006-02-21 15:58:17.441495048 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/cpc710.h
- *
  * Definitions for the IBM CPC710 PCI Host Bridge
  *
  * Author: Matt Porter <mporter@mvista.com>
diff -urN oldtree/arch/ppc/syslib/gen550.h newtree/arch/ppc/syslib/gen550.h
--- oldtree/arch/ppc/syslib/gen550.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/gen550.h	2006-02-21 15:58:17.442494896 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/gen550.h
- *
  * gen550 prototypes
  *
  * Matt Porter <mporter@kernel.crashing.org>
diff -urN oldtree/arch/ppc/syslib/gen550_dbg.c newtree/arch/ppc/syslib/gen550_dbg.c
--- oldtree/arch/ppc/syslib/gen550_dbg.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/gen550_dbg.c	2006-02-21 15:58:17.442494896 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/gen550_dbg.c
- *
  * A library of polled 16550 serial routines.  These are intended to
  * be used to support progress messages, xmon, kgdb, etc. on a
  * variety of platforms.
diff -urN oldtree/arch/ppc/syslib/gen550_kgdb.c newtree/arch/ppc/syslib/gen550_kgdb.c
--- oldtree/arch/ppc/syslib/gen550_kgdb.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/gen550_kgdb.c	2006-02-21 15:58:17.442494896 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/gen550_kgdb.c
- *
  * Generic 16550 kgdb support intended to be useful on a variety
  * of platforms.  To enable this support, it is necessary to set
  * the CONFIG_GEN550 option.  Any virtual mapping of the serial
diff -urN oldtree/arch/ppc/syslib/gt64260_pic.c newtree/arch/ppc/syslib/gt64260_pic.c
--- oldtree/arch/ppc/syslib/gt64260_pic.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/gt64260_pic.c	2006-02-21 15:58:17.443494744 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/gt64260_pic.c
- *
  * Interrupt controller support for Galileo's GT64260.
  *
  * Author: Chris Zankel <source@mvista.com>
diff -urN oldtree/arch/ppc/syslib/harrier.c newtree/arch/ppc/syslib/harrier.c
--- oldtree/arch/ppc/syslib/harrier.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/harrier.c	2006-02-21 15:58:17.443494744 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/harrier.c
- *
  * Motorola MCG Harrier northbridge/memory controller support
  *
  * Author: Dale Farnsworth
diff -urN oldtree/arch/ppc/syslib/hawk_common.c newtree/arch/ppc/syslib/hawk_common.c
--- oldtree/arch/ppc/syslib/hawk_common.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/hawk_common.c	2006-02-21 15:58:17.444494592 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/hawk_common.c
- *
  * Common Motorola PowerPlus Platform--really Falcon/Raven or HAWK.
  *
  * Author: Mark A. Greer
diff -urN oldtree/arch/ppc/syslib/ibm440gp_common.c newtree/arch/ppc/syslib/ibm440gp_common.c
--- oldtree/arch/ppc/syslib/ibm440gp_common.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/ibm440gp_common.c	2006-02-21 15:58:17.444494592 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/ibm440gp_common.c
- *
  * PPC440GP system library
  *
  * Matt Porter <mporter@mvista.com>
diff -urN oldtree/arch/ppc/syslib/ibm440gp_common.h newtree/arch/ppc/syslib/ibm440gp_common.h
--- oldtree/arch/ppc/syslib/ibm440gp_common.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/ibm440gp_common.h	2006-02-21 15:58:17.444494592 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/kernel/ibm440gp_common.h
- *
  * PPC440GP system library
  *
  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
diff -urN oldtree/arch/ppc/syslib/ibm440gx_common.c newtree/arch/ppc/syslib/ibm440gx_common.c
--- oldtree/arch/ppc/syslib/ibm440gx_common.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/ibm440gx_common.c	2006-02-21 15:58:17.445494440 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/kernel/ibm440gx_common.c
- *
  * PPC440GX system library
  *
  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
diff -urN oldtree/arch/ppc/syslib/ibm440gx_common.h newtree/arch/ppc/syslib/ibm440gx_common.h
--- oldtree/arch/ppc/syslib/ibm440gx_common.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/ibm440gx_common.h	2006-02-21 15:58:17.445494440 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/kernel/ibm440gx_common.h
- *
  * PPC440GX system library
  *
  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
diff -urN oldtree/arch/ppc/syslib/ibm440sp_common.c newtree/arch/ppc/syslib/ibm440sp_common.c
--- oldtree/arch/ppc/syslib/ibm440sp_common.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/ibm440sp_common.c	2006-02-21 15:58:17.445494440 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/ibm440sp_common.c
- *
  * PPC440SP/PPC440SPe system library
  *
  * Matt Porter <mporter@kernel.crashing.org>
diff -urN oldtree/arch/ppc/syslib/ibm440sp_common.h newtree/arch/ppc/syslib/ibm440sp_common.h
--- oldtree/arch/ppc/syslib/ibm440sp_common.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/ibm440sp_common.h	2006-02-21 15:58:17.446494288 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/ibm440sp_common.h
- *
  * PPC440SP system library
  *
  * Matt Porter <mporter@kernel.crashing.org>
diff -urN oldtree/arch/ppc/syslib/ibm44x_common.c newtree/arch/ppc/syslib/ibm44x_common.c
--- oldtree/arch/ppc/syslib/ibm44x_common.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/ibm44x_common.c	2006-02-21 15:58:17.446494288 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/ibm44x_common.c
- *
  * PPC44x system library
  *
  * Matt Porter <mporter@kernel.crashing.org>
diff -urN oldtree/arch/ppc/syslib/ibm44x_common.h newtree/arch/ppc/syslib/ibm44x_common.h
--- oldtree/arch/ppc/syslib/ibm44x_common.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/ibm44x_common.h	2006-02-21 15:58:17.446494288 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/kernel/ibm44x_common.h
- *
  * PPC44x system library
  *
  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
diff -urN oldtree/arch/ppc/syslib/m8260_pci_erratum9.c newtree/arch/ppc/syslib/m8260_pci_erratum9.c
--- oldtree/arch/ppc/syslib/m8260_pci_erratum9.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/m8260_pci_erratum9.c	2006-02-21 15:58:17.447494136 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/mpc8260_pci9.c
- *
  * Workaround for device erratum PCI 9.
  * See Motorola's "XPC826xA Family Device Errata Reference."
  * The erratum applies to all 8260 family Hip4 processors.  It is scheduled 
diff -urN oldtree/arch/ppc/syslib/m8260_setup.c newtree/arch/ppc/syslib/m8260_setup.c
--- oldtree/arch/ppc/syslib/m8260_setup.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/m8260_setup.c	2006-02-21 15:58:17.448493984 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/syslib/m8260_setup.c
- *
  *  Copyright (C) 1995  Linus Torvalds
  *  Adapted from 'alpha' version by Gary Thomas
  *  Modified by Cort Dougan (cort@cs.nmt.edu)
diff -urN oldtree/arch/ppc/syslib/m8xx_setup.c newtree/arch/ppc/syslib/m8xx_setup.c
--- oldtree/arch/ppc/syslib/m8xx_setup.c	2006-02-19 11:40:59.486421176 +0000
+++ newtree/arch/ppc/syslib/m8xx_setup.c	2006-02-21 15:58:17.448493984 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/kernel/setup.c
- *
  *  Copyright (C) 1995  Linus Torvalds
  *  Adapted from 'alpha' version by Gary Thomas
  *  Modified by Cort Dougan (cort@cs.nmt.edu)
@@ -34,6 +32,13 @@
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
 
+#if defined(CONFIG_MTD) && defined(CONFIG_MTD_PHYSMAP)
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#endif
+
 #include <asm/mmu.h>
 #include <asm/reg.h>
 #include <asm/residual.h>
@@ -49,6 +54,34 @@
 
 #include "ppc8xx_pic.h"
 
+#ifdef CONFIG_MTD_PHYSMAP
+#define MPC8xxADS_BANK_WIDTH 4
+#endif
+
+#define MPC8xxADS_U_BOOT_SIZE          0x80000
+#define MPC8xxADS_FREE_AREA_OFFSET     MPC8xxADS_U_BOOT_SIZE
+
+#if defined(CONFIG_MTD_PARTITIONS)
+ /*
+   NOTE: bank width and interleave relative to the installed flash
+   should have been chosen within MTD_CFI_GEOMETRY options.
+ */
+static struct mtd_partition mpc8xxads_partitions[] = {
+	{
+		.name = "bootloader",
+		.size = MPC8xxADS_U_BOOT_SIZE,
+		.offset = 0,
+		.mask_flags   = MTD_WRITEABLE,  /* force read-only */
+	}, {
+		.name = "User FS",
+		.offset = MPC8xxADS_FREE_AREA_OFFSET
+	}
+};
+
+#define mpc8xxads_part_num (sizeof (mpc8xxads_partitions) / sizeof (mpc8xxads_partitions[0]))
+
+#endif
+
 static int m8xx_set_rtc_time(unsigned long time);
 static unsigned long m8xx_get_rtc_time(void);
 void m8xx_calibrate_decr(void);
@@ -71,6 +104,10 @@
 void __init
 m8xx_setup_arch(void)
 {
+#if defined(CONFIG_MTD) && defined(CONFIG_MTD_PHYSMAP)
+	bd_t *binfo = (bd_t *)__res;
+#endif
+
 	/* Reset the Communication Processor Module.
 	*/
 	m8xx_cpm_reset();
@@ -106,6 +143,17 @@
 	}
 #endif
 #endif
+
+#if defined (CONFIG_MPC86XADS) || defined (CONFIG_MPC885ADS)
+#if defined(CONFIG_MTD_PHYSMAP)
+       physmap_configure(binfo->bi_flashstart, binfo->bi_flashsize,
+                                               MPC8xxADS_BANK_WIDTH, NULL);
+#ifdef CONFIG_MTD_PARTITIONS
+       physmap_set_partitions(mpc8xxads_partitions, mpc8xxads_part_num);
+#endif /* CONFIG_MTD_PARTITIONS */
+#endif /* CONFIG_MTD_PHYSMAP */
+#endif
+
 	board_init();
 }
 
@@ -140,9 +188,11 @@
 init_internal_rtc(void)
 {
 	/* Disable the RTC one second and alarm interrupts. */
-	out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) & ~(RTCSC_SIE | RTCSC_ALE));
+	clrbits16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, (RTCSC_SIE | RTCSC_ALE));
+
 	/* Enable the RTC */
-	out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) | (RTCSC_RTF | RTCSC_RTE));
+	setbits16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, (RTCSC_RTF | RTCSC_RTE));
+
 }
 
 /* The decrementer counts at the system (internal) clock frequency divided by
@@ -159,8 +209,7 @@
 	out_be32(&((immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk, KAPWR_KEY);
 
 	/* Force all 8xx processors to use divide by 16 processor clock. */
-	out_be32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_sccr,
-		in_be32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_sccr)|0x02000000);
+	setbits32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_sccr, 0x02000000);
 	/* Processor frequency is MHz.
 	 * The value 'fp' is the number of decrementer ticks per second.
 	 */
@@ -239,8 +288,8 @@
 	__volatile__ unsigned char dummy;
 
 	local_irq_disable();
-	out_be32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr, in_be32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr) | 0x00000080);
 
+	setbits32(&((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr, 0x00000080);
 	/* Clear the ME bit in MSR to cause checkstop on machine check
 	*/
 	mtmsr(mfmsr() & ~0x1000);
@@ -310,8 +359,8 @@
 	i8259_init(0);
 
 	/* The i8259 cascade interrupt must be level sensitive. */
-	out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel, in_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel & ~(0x80000000 >> ISA_BRIDGE_INT)));
 
+	clrbits32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel, (0x80000000 >> ISA_BRIDGE_INT));
 	if (setup_irq(ISA_BRIDGE_INT, &mbx_i8259_irqaction))
 		enable_irq(ISA_BRIDGE_INT);
 #endif	/* CONFIG_PCI */
diff -urN oldtree/arch/ppc/syslib/m8xx_wdt.c newtree/arch/ppc/syslib/m8xx_wdt.c
--- oldtree/arch/ppc/syslib/m8xx_wdt.c	2006-02-19 11:40:59.487421024 +0000
+++ newtree/arch/ppc/syslib/m8xx_wdt.c	2006-02-21 15:58:17.449493832 +0000
@@ -41,8 +41,7 @@
 
 	m8xx_wdt_reset();
 
-	out_be16(&imap->im_sit.sit_piscr, in_be16(&imap->im_sit.sit_piscr) | PISCR_PS);	/* clear irq */
-
+	setbits16(&imap->im_sit.sit_piscr, PISCR_PS);
 	return IRQ_HANDLED;
 }
 
diff -urN oldtree/arch/ppc/syslib/mpc10x_common.c newtree/arch/ppc/syslib/mpc10x_common.c
--- oldtree/arch/ppc/syslib/mpc10x_common.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/mpc10x_common.c	2006-02-21 15:58:17.450493680 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/mpc10x_common.c
- *
  * Common routines for the Motorola SPS MPC106, MPC107 and MPC8240 Host bridge,
  * Mem ctlr, EPIC, etc.
  *
diff -urN oldtree/arch/ppc/syslib/mpc52xx_devices.c newtree/arch/ppc/syslib/mpc52xx_devices.c
--- oldtree/arch/ppc/syslib/mpc52xx_devices.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/mpc52xx_devices.c	2006-02-21 15:58:17.450493680 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/mpc52xx_devices.c
- *
  * Freescale MPC52xx device descriptions
  *
  *
diff -urN oldtree/arch/ppc/syslib/mpc52xx_pci.c newtree/arch/ppc/syslib/mpc52xx_pci.c
--- oldtree/arch/ppc/syslib/mpc52xx_pci.c	2006-02-19 11:40:59.524415400 +0000
+++ newtree/arch/ppc/syslib/mpc52xx_pci.c	2006-02-21 15:58:17.451493528 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/mpc52xx_pci.c
- *
  * PCI code for the Freescale MPC52xx embedded CPU.
  *
  *
diff -urN oldtree/arch/ppc/syslib/mpc52xx_pci.h newtree/arch/ppc/syslib/mpc52xx_pci.h
--- oldtree/arch/ppc/syslib/mpc52xx_pci.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/mpc52xx_pci.h	2006-02-21 15:58:17.451493528 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/mpc52xx_pci.h
- *
  * PCI Include file the Freescale MPC52xx embedded cpu chips
  *
  *
diff -urN oldtree/arch/ppc/syslib/mpc52xx_pic.c newtree/arch/ppc/syslib/mpc52xx_pic.c
--- oldtree/arch/ppc/syslib/mpc52xx_pic.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/mpc52xx_pic.c	2006-02-21 15:58:17.451493528 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/mpc52xx_pic.c
- *
  * Programmable Interrupt Controller functions for the Freescale MPC52xx 
  * embedded CPU.
  *
diff -urN oldtree/arch/ppc/syslib/mpc52xx_setup.c newtree/arch/ppc/syslib/mpc52xx_setup.c
--- oldtree/arch/ppc/syslib/mpc52xx_setup.c	2006-02-19 11:40:59.524415400 +0000
+++ newtree/arch/ppc/syslib/mpc52xx_setup.c	2006-02-21 15:58:17.452493376 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/mpc52xx_setup.c
- *
  * Common code for the boards based on Freescale MPC52xx embedded CPU.
  *
  * 
diff -urN oldtree/arch/ppc/syslib/mpc52xx_sys.c newtree/arch/ppc/syslib/mpc52xx_sys.c
--- oldtree/arch/ppc/syslib/mpc52xx_sys.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/mpc52xx_sys.c	2006-02-21 15:58:17.452493376 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/mpc52xx_sys.c
- *
  * Freescale MPC52xx system descriptions
  *
  *
diff -urN oldtree/arch/ppc/syslib/mpc83xx_devices.c newtree/arch/ppc/syslib/mpc83xx_devices.c
--- oldtree/arch/ppc/syslib/mpc83xx_devices.c	2006-02-19 11:40:59.525415248 +0000
+++ newtree/arch/ppc/syslib/mpc83xx_devices.c	2006-02-21 15:58:17.453493224 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/83xx/mpc83xx_devices.c
- *
  * MPC83xx Device descriptions
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/syslib/mpc83xx_sys.c newtree/arch/ppc/syslib/mpc83xx_sys.c
--- oldtree/arch/ppc/syslib/mpc83xx_sys.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/mpc83xx_sys.c	2006-02-21 15:58:17.453493224 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/83xx/mpc83xx_sys.c
- *
  * MPC83xx System descriptions
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/syslib/mpc85xx_devices.c newtree/arch/ppc/syslib/mpc85xx_devices.c
--- oldtree/arch/ppc/syslib/mpc85xx_devices.c	2006-02-19 11:40:59.525415248 +0000
+++ newtree/arch/ppc/syslib/mpc85xx_devices.c	2006-02-21 15:58:17.454493072 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/85xx/mpc85xx_devices.c
- *
  * MPC85xx Device descriptions
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/syslib/mpc85xx_sys.c newtree/arch/ppc/syslib/mpc85xx_sys.c
--- oldtree/arch/ppc/syslib/mpc85xx_sys.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/mpc85xx_sys.c	2006-02-21 15:58:17.454493072 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/85xx/mpc85xx_sys.c
- *
  * MPC85xx System descriptions
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/syslib/mpc8xx_devices.c newtree/arch/ppc/syslib/mpc8xx_devices.c
--- oldtree/arch/ppc/syslib/mpc8xx_devices.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/mpc8xx_devices.c	2006-02-21 15:58:17.454493072 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/mpc8xx_devices.c
- *
  * MPC8xx Device descriptions
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/syslib/mpc8xx_sys.c newtree/arch/ppc/syslib/mpc8xx_sys.c
--- oldtree/arch/ppc/syslib/mpc8xx_sys.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/mpc8xx_sys.c	2006-02-21 15:58:17.455492920 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/platforms/mpc8xx_sys.c
- *
  * MPC8xx System descriptions
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/syslib/mv64360_pic.c newtree/arch/ppc/syslib/mv64360_pic.c
--- oldtree/arch/ppc/syslib/mv64360_pic.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/mv64360_pic.c	2006-02-21 15:58:17.455492920 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/kernel/mv64360_pic.c
- *
  * Interrupt controller support for Marvell's MV64360.
  *
  * Author: Rabeeh Khoury <rabeeh@galileo.co.il>
diff -urN oldtree/arch/ppc/syslib/mv64x60.c newtree/arch/ppc/syslib/mv64x60.c
--- oldtree/arch/ppc/syslib/mv64x60.c	2006-02-19 11:40:59.526415096 +0000
+++ newtree/arch/ppc/syslib/mv64x60.c	2006-02-21 15:58:17.457492616 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/mv64x60.c
- *
  * Common routines for the Marvell/Galileo Discovery line of host bridges
  * (gt64260, mv64360, mv64460, ...).
  *
diff -urN oldtree/arch/ppc/syslib/mv64x60_dbg.c newtree/arch/ppc/syslib/mv64x60_dbg.c
--- oldtree/arch/ppc/syslib/mv64x60_dbg.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/mv64x60_dbg.c	2006-02-21 15:58:17.458492464 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/mv64x60_dbg.c
- *
  * KGDB and progress routines for the Marvell/Galileo MV64x60 (Discovery).
  *
  * Author: Mark A. Greer <mgreer@mvista.com>
diff -urN oldtree/arch/ppc/syslib/mv64x60_win.c newtree/arch/ppc/syslib/mv64x60_win.c
--- oldtree/arch/ppc/syslib/mv64x60_win.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/mv64x60_win.c	2006-02-21 15:58:17.459492312 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/mv64x60_win.c
- *
  * Tables with info on how to manipulate the 32 & 64 bit windows on the
  * various types of Marvell bridge chips.
  *
diff -urN oldtree/arch/ppc/syslib/open_pic.c newtree/arch/ppc/syslib/open_pic.c
--- oldtree/arch/ppc/syslib/open_pic.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/open_pic.c	2006-02-21 15:58:17.461492008 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
- *
  *  Copyright (C) 1997 Geert Uytterhoeven
  *
  *  This file is subject to the terms and conditions of the GNU General Public
diff -urN oldtree/arch/ppc/syslib/open_pic2.c newtree/arch/ppc/syslib/open_pic2.c
--- oldtree/arch/ppc/syslib/open_pic2.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/open_pic2.c	2006-02-21 15:58:17.460492160 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
- *
  *  Copyright (C) 1997 Geert Uytterhoeven
  *
  *  This file is subject to the terms and conditions of the GNU General Public
diff -urN oldtree/arch/ppc/syslib/open_pic_defs.h newtree/arch/ppc/syslib/open_pic_defs.h
--- oldtree/arch/ppc/syslib/open_pic_defs.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/open_pic_defs.h	2006-02-21 15:58:17.461492008 +0000
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc/kernel/open_pic_defs.h -- OpenPIC definitions
- *
  *  Copyright (C) 1997 Geert Uytterhoeven
  *
  *  This file is based on the following documentation:
diff -urN oldtree/arch/ppc/syslib/pci_auto.c newtree/arch/ppc/syslib/pci_auto.c
--- oldtree/arch/ppc/syslib/pci_auto.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/pci_auto.c	2006-02-21 15:58:17.462491856 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/pci_auto.c
- *
  * PCI autoconfiguration library
  *
  * Author: Matt Porter <mporter@mvista.com>
diff -urN oldtree/arch/ppc/syslib/ppc4xx_dma.c newtree/arch/ppc/syslib/ppc4xx_dma.c
--- oldtree/arch/ppc/syslib/ppc4xx_dma.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/ppc4xx_dma.c	2006-02-21 15:58:17.463491704 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/kernel/ppc4xx_dma.c
- *
  * IBM PPC4xx DMA engine core library
  *
  * Copyright 2000-2004 MontaVista Software Inc.
diff -urN oldtree/arch/ppc/syslib/ppc4xx_pic.c newtree/arch/ppc/syslib/ppc4xx_pic.c
--- oldtree/arch/ppc/syslib/ppc4xx_pic.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/ppc4xx_pic.c	2006-02-21 15:58:17.463491704 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/ppc4xx_pic.c
- *
  * Interrupt controller driver for PowerPC 4xx-based processors.
  *
  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
diff -urN oldtree/arch/ppc/syslib/ppc4xx_pm.c newtree/arch/ppc/syslib/ppc4xx_pm.c
--- oldtree/arch/ppc/syslib/ppc4xx_pm.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/ppc4xx_pm.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,47 +0,0 @@
-/*
- * Author: Armin Kuster <akuster@mvista.com>
- *
- * 2002 (c) MontaVista, Software, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- *
- * This an attempt to get Power Management going for the IBM 4xx processor.
- * This was derived from the ppc4xx._setup.c file
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-
-#include <asm/ibm4xx.h>
-
-void __init
-ppc4xx_pm_init(void)
-{
-
-	unsigned int value = 0;
-
-	/* turn off unused hardware to save power */
-#ifdef CONFIG_405GP
-	value |= CPM_DCP;	/* CodePack */
-#endif
-
-#if !defined(CONFIG_IBM_OCP_GPIO)
-	value |= CPM_GPIO0;
-#endif
-
-#if !defined(CONFIG_PPC405_I2C_ADAP)
-	value |= CPM_IIC0;
-#ifdef CONFIG_STB03xxx
-	value |= CPM_IIC1;
-#endif
-#endif
-
-
-#if !defined(CONFIG_405_DMA)
-	value |= CPM_DMA;
-#endif
-
-	mtdcr(DCRN_CPMFR, value);
-
-}
diff -urN oldtree/arch/ppc/syslib/ppc4xx_sgdma.c newtree/arch/ppc/syslib/ppc4xx_sgdma.c
--- oldtree/arch/ppc/syslib/ppc4xx_sgdma.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/ppc4xx_sgdma.c	2006-02-21 15:58:17.465491400 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/kernel/ppc4xx_sgdma.c
- *
  * IBM PPC4xx DMA engine scatter/gather library
  *
  * Copyright 2002-2003 MontaVista Software Inc.
diff -urN oldtree/arch/ppc/syslib/ppc83xx_setup.c newtree/arch/ppc/syslib/ppc83xx_setup.c
--- oldtree/arch/ppc/syslib/ppc83xx_setup.c	2006-02-19 11:40:59.528414792 +0000
+++ newtree/arch/ppc/syslib/ppc83xx_setup.c	2006-02-21 15:58:17.466491248 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/ppc83xx_setup.c
- *
  * MPC83XX common board code
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/syslib/ppc83xx_setup.h newtree/arch/ppc/syslib/ppc83xx_setup.h
--- oldtree/arch/ppc/syslib/ppc83xx_setup.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/ppc83xx_setup.h	2006-02-21 15:58:17.466491248 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/ppc83xx_setup.h
- *
  * MPC83XX common board definitions
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/syslib/ppc85xx_common.c newtree/arch/ppc/syslib/ppc85xx_common.c
--- oldtree/arch/ppc/syslib/ppc85xx_common.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/ppc85xx_common.c	2006-02-21 15:58:17.466491248 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/ppc85xx_common.c
- *
  * MPC85xx support routines
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/syslib/ppc85xx_common.h newtree/arch/ppc/syslib/ppc85xx_common.h
--- oldtree/arch/ppc/syslib/ppc85xx_common.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/ppc85xx_common.h	2006-02-21 15:58:17.466491248 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/ppc85xx_common.h
- *
  * MPC85xx support routines
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/syslib/ppc85xx_setup.c newtree/arch/ppc/syslib/ppc85xx_setup.c
--- oldtree/arch/ppc/syslib/ppc85xx_setup.c	2006-02-19 11:40:59.528414792 +0000
+++ newtree/arch/ppc/syslib/ppc85xx_setup.c	2006-02-21 15:58:17.467491096 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/ppc85xx_setup.c
- *
  * MPC85XX common board code
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/syslib/ppc85xx_setup.h newtree/arch/ppc/syslib/ppc85xx_setup.h
--- oldtree/arch/ppc/syslib/ppc85xx_setup.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/ppc85xx_setup.h	2006-02-21 15:58:17.468490944 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/ppc85xx_setup.h
- *
  * MPC85XX common board definitions
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/syslib/ppc_sys.c newtree/arch/ppc/syslib/ppc_sys.c
--- oldtree/arch/ppc/syslib/ppc_sys.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/ppc_sys.c	2006-02-21 15:58:17.468490944 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/ppc_sys.c
- *
  * PPC System library functions
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
@@ -15,11 +13,22 @@
  */
 
 #include <linux/string.h>
+#include <linux/bootmem.h>
 #include <asm/ppc_sys.h>
 
 int (*ppc_sys_device_fixup) (struct platform_device * pdev);
 
 static int ppc_sys_inited;
+static int ppc_sys_func_inited;
+
+static const char *ppc_sys_func_names[] = {
+	[PPC_SYS_FUNC_DUMMY] = "dummy",
+	[PPC_SYS_FUNC_ETH] = "eth",
+	[PPC_SYS_FUNC_UART] = "uart",
+	[PPC_SYS_FUNC_HLDC] = "hldc",
+	[PPC_SYS_FUNC_USB] = "usb",
+	[PPC_SYS_FUNC_IRDA] = "irda",
+};
 
 void __init identify_ppc_sys_by_id(u32 id)
 {
@@ -38,13 +47,13 @@
 void __init identify_ppc_sys_by_name(char *name)
 {
 	unsigned int i = 0;
-	while (ppc_sys_specs[i].ppc_sys_name[0])
-	{
+	while (ppc_sys_specs[i].ppc_sys_name[0]) {
 		if (!strcmp(ppc_sys_specs[i].ppc_sys_name, name))
 			break;
 		i++;
 	}
 	cur_ppc_sys_spec = &ppc_sys_specs[i];
+
 	return;
 }
 
@@ -128,6 +137,165 @@
 	}
 }
 
+/* Platform-notify mapping
+ * Helper function for BSP code to assign board-specific platfom-divice bits
+ */
+
+void platform_notify_map(const struct platform_notify_dev_map *map,
+			 struct device *dev)
+{
+	struct platform_device *pdev;
+	int len, idx;
+	const char *s;
+
+	/* do nothing if no device or no bus_id */
+	if (!dev || !dev->bus_id)
+		return;
+
+	/* call per device map */
+	while (map->bus_id != NULL) {
+		idx = -1;
+		s = strrchr(dev->bus_id, '.');
+		if (s != NULL)
+			idx = (int)simple_strtol(s + 1, NULL, 10);
+		else
+			s = dev->bus_id;
+
+		len = s - dev->bus_id;
+
+		if (!strncmp(dev->bus_id, map->bus_id, len)) {
+			pdev = container_of(dev, struct platform_device, dev);
+			map->rtn(pdev, idx);
+		}
+		map++;
+	}
+}
+
+/*
+   Function assignment stuff.
+ Intended to work as follows:
+ the device name defined in foo_devices.c will be concatenated with :"func",
+ where func is string map of respective function from platfom_device_func enum
+
+ The PPC_SYS_FUNC_DUMMY function is intended to remove all assignments, making the device to appear
+ in platform bus with unmodified name.
+ */
+
+/*
+   Here we'll replace .name pointers with fixed-lenght strings
+   Hereby, this should be called *before* any func stuff triggeded.
+ */
+void ppc_sys_device_initfunc(void)
+{
+	int i;
+	const char *name;
+	static char new_names[NUM_PPC_SYS_DEVS][BUS_ID_SIZE];
+	enum ppc_sys_devices cur_dev;
+
+	/* If inited yet, do nothing */
+	if (ppc_sys_func_inited)
+		return;
+
+	for (i = 0; i < cur_ppc_sys_spec->num_devices; i++) {
+		if ((cur_dev = cur_ppc_sys_spec->device_list[i]) < 0)
+			continue;
+
+		if (ppc_sys_platform_devices[cur_dev].name) {
+			/*backup name */
+			name = ppc_sys_platform_devices[cur_dev].name;
+			strlcpy(new_names[i], name, BUS_ID_SIZE);
+			ppc_sys_platform_devices[cur_dev].name = new_names[i];
+		}
+	}
+
+	ppc_sys_func_inited = 1;
+}
+
+/*The "engine" of the func stuff. Here we either concat specified function string description
+ to the name, or remove it if PPC_SYS_FUNC_DUMMY parameter is passed here*/
+void ppc_sys_device_setfunc(enum ppc_sys_devices dev,
+			    enum platform_device_func func)
+{
+	char *s;
+	char *name = (char *)ppc_sys_platform_devices[dev].name;
+	char tmp[BUS_ID_SIZE];
+
+	if (!ppc_sys_func_inited) {
+		printk(KERN_ERR "Unable to alter function - not inited!\n");
+		return;
+	}
+
+	if (ppc_sys_inited) {
+		platform_device_unregister(&ppc_sys_platform_devices[dev]);
+	}
+
+	if ((s = (char *)strchr(name, ':')) != NULL) {	/* reassign */
+		/* Either change the name after ':' or remove func modifications */
+		if (func != PPC_SYS_FUNC_DUMMY)
+			strlcpy(s + 1, ppc_sys_func_names[func], BUS_ID_SIZE);
+		else
+			*s = 0;
+	} else if (func != PPC_SYS_FUNC_DUMMY) {
+		/* do assignment if it is not just "clear"  request */
+		sprintf(tmp, "%s:%s", name, ppc_sys_func_names[func]);
+		strlcpy(name, tmp, BUS_ID_SIZE);
+	}
+
+	if (ppc_sys_inited) {
+		platform_device_register(&ppc_sys_platform_devices[dev]);
+	}
+}
+
+void ppc_sys_device_disable(enum ppc_sys_devices dev)
+{
+	BUG_ON(cur_ppc_sys_spec == NULL);
+
+	/*Check if it is enabled*/
+	if(!(cur_ppc_sys_spec->config[dev] & PPC_SYS_CONFIG_DISABLED)) {
+		if (ppc_sys_inited) {
+			platform_device_unregister(&ppc_sys_platform_devices[dev]);
+		}
+		cur_ppc_sys_spec->config[dev] |= PPC_SYS_CONFIG_DISABLED;
+	}
+}
+
+void ppc_sys_device_enable(enum ppc_sys_devices dev)
+{
+	BUG_ON(cur_ppc_sys_spec == NULL);
+
+	/*Check if it is disabled*/
+	if(cur_ppc_sys_spec->config[dev] & PPC_SYS_CONFIG_DISABLED) {
+		if (ppc_sys_inited) {
+			platform_device_register(&ppc_sys_platform_devices[dev]);
+		}
+		cur_ppc_sys_spec->config[dev] &= ~PPC_SYS_CONFIG_DISABLED;
+	}
+
+}
+
+void ppc_sys_device_enable_all(void)
+{
+	enum ppc_sys_devices cur_dev;
+	int i;
+
+	for (i = 0; i < cur_ppc_sys_spec->num_devices; i++) {
+		cur_dev = cur_ppc_sys_spec->device_list[i];
+		ppc_sys_device_enable(cur_dev);
+	}
+}
+
+void ppc_sys_device_disable_all(void)
+{
+	enum ppc_sys_devices cur_dev;
+	int i;
+
+	for (i = 0; i < cur_ppc_sys_spec->num_devices; i++) {
+		cur_dev = cur_ppc_sys_spec->device_list[i];
+		ppc_sys_device_disable(cur_dev);
+	}
+}
+
+
 static int __init ppc_sys_init(void)
 {
 	unsigned int i, dev_id, ret = 0;
@@ -136,7 +304,8 @@
 
 	for (i = 0; i < cur_ppc_sys_spec->num_devices; i++) {
 		dev_id = cur_ppc_sys_spec->device_list[i];
-		if (dev_id != -1) {
+		if ((dev_id != -1) &&
+		!(cur_ppc_sys_spec->config[dev_id] & PPC_SYS_CONFIG_DISABLED)) {
 			if (ppc_sys_device_fixup != NULL)
 				ppc_sys_device_fixup(&ppc_sys_platform_devices
 						     [dev_id]);
diff -urN oldtree/arch/ppc/syslib/pq2_devices.c newtree/arch/ppc/syslib/pq2_devices.c
--- oldtree/arch/ppc/syslib/pq2_devices.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/pq2_devices.c	2006-02-21 15:58:17.469490792 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/pq2_devices.c
- *
  * PQ2 Device descriptions
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/syslib/pq2_sys.c newtree/arch/ppc/syslib/pq2_sys.c
--- oldtree/arch/ppc/syslib/pq2_sys.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/pq2_sys.c	2006-02-21 15:58:17.469490792 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/pq2_devices.c
- *
  * PQ2 System descriptions
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
diff -urN oldtree/arch/ppc/syslib/prep_nvram.c newtree/arch/ppc/syslib/prep_nvram.c
--- oldtree/arch/ppc/syslib/prep_nvram.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/prep_nvram.c	2006-02-21 15:58:17.470490640 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/kernel/prep_nvram.c
- *
  * Copyright (C) 1998  Corey Minyard
  *
  * This reads the NvRAM on PReP compliant machines (generally from IBM or
diff -urN oldtree/arch/ppc/syslib/todc_time.c newtree/arch/ppc/syslib/todc_time.c
--- oldtree/arch/ppc/syslib/todc_time.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/todc_time.c	2006-02-21 15:58:17.478489424 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/todc_time.c
- *
  * Time of Day Clock support for the M48T35, M48T37, M48T59, and MC146818
  * Real Time Clocks/Timekeepers.
  *
diff -urN oldtree/arch/ppc/syslib/xilinx_pic.c newtree/arch/ppc/syslib/xilinx_pic.c
--- oldtree/arch/ppc/syslib/xilinx_pic.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/ppc/syslib/xilinx_pic.c	2006-02-21 15:58:17.478489424 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/syslib/xilinx_pic.c
- *
  * Interrupt controller driver for Xilinx Virtex-II Pro.
  *
  * Author: MontaVista Software, Inc.
@@ -15,7 +13,7 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <asm/io.h>
-#include <asm/xparameters.h>
+#include <platforms/4xx/xparameters/xparameters.h>
 #include <asm/ibm4xx.h>
 #include <asm/machdep.h>
 
diff -urN oldtree/arch/s390/kernel/Makefile newtree/arch/s390/kernel/Makefile
--- oldtree/arch/s390/kernel/Makefile	2006-02-19 11:40:59.540412968 +0000
+++ newtree/arch/s390/kernel/Makefile	2006-02-21 15:58:23.516571496 +0000
@@ -6,7 +6,8 @@
 
 obj-y	:=  bitmap.o traps.o time.o process.o \
             setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
-            semaphore.o s390_ext.o debug.o profile.o irq.o reipl_diag.o
+            semaphore.o s390_ext.o debug.o profile.o irq.o sgrb.o \
+            statistic.o reipl_diag.o
 
 obj-y	+= $(if $(CONFIG_64BIT),entry64.o,entry.o)
 obj-y	+= $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
diff -urN oldtree/arch/s390/kernel/sgrb.c newtree/arch/s390/kernel/sgrb.c
--- oldtree/arch/s390/kernel/sgrb.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/s390/kernel/sgrb.c	2006-02-21 15:58:23.516571496 +0000
@@ -0,0 +1,303 @@
+/*
+ * arch/s390/kernel/sgrb.c
+ *
+ * a ringbuffer made up of scattered buffers; holds fixed-size entries
+ * (resizing has not been implemented)
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define SGRB_C_REVISION "$Revision: 1.3 $"
+
+#include <linux/module.h>
+
+#include <asm/sgrb.h>
+
+static struct sgrb_seg *
+sgrb_seg_alloc(struct list_head *lh, int size, unsigned int gfp)
+{
+	struct sgrb_seg *seg;
+
+	seg = kmalloc(sizeof(struct sgrb_seg), gfp);
+	if (!seg)
+		return NULL;
+	seg->offset = 0;
+	seg->size = size;
+	seg->address = kmalloc(size, gfp);
+	if (!seg->address) {
+		kfree(seg);
+		return NULL;
+	}
+	list_add_tail(&seg->list, lh);
+	return seg;
+}
+
+/**
+ * sgrb_seg_find - find room for another entry
+ * @lh: list_head that holds list of scattered buffers used to store entries
+ * @size: entry size (should be identical for all entries of same buffer list)
+ * @gfp: GFP_* flags used if another buffer needs to be allocated
+ *
+ * tries to find room for an entry in buffer alloacted last, and, on failure,
+ * allocates another buffer
+ */
+struct sgrb_seg *
+sgrb_seg_find(struct list_head *lh, int size, unsigned int gfp)
+{
+	struct sgrb_seg *seg;
+
+	list_for_each_entry_reverse(seg, lh, list) {
+		if ((seg->size - seg->offset) >= size)
+			return seg;
+		break;
+	}
+	return sgrb_seg_alloc(lh, SGRB_BUFFER_SIZE, gfp);
+}
+EXPORT_SYMBOL(sgrb_seg_find);
+
+/**
+ * sgrb_seg_release_all - releases scatter-gather buffer
+ * @lh: list_head that holds list of scattered buffer parts
+ */
+void
+sgrb_seg_release_all(struct list_head *lh)
+{
+	struct sgrb_seg *seg, *tmp;
+
+	list_for_each_entry_safe(seg, tmp, lh, list) {
+		list_del(&seg->list);
+		kfree(seg->address);
+		kfree(seg);
+	}
+}
+EXPORT_SYMBOL(sgrb_seg_release_all);
+
+static inline int
+sgrb_ptr_identical(
+	struct sgrb_ptr *a,
+	struct sgrb_ptr *b)
+{
+	if (a->seg == b->seg &&
+	    a->offset == b->offset)
+		return 1;
+	else
+		return 0;
+}
+
+static inline int
+sgrb_ptr_valid(struct sgrb_ptr *a)
+{
+	return (a->offset >= 0);
+}
+
+static inline void
+sgrb_ptr_invalidate(struct sgrb *rb, struct sgrb_ptr *a)
+{
+	a->offset = -rb->entry_size;
+}
+
+static inline void
+sgrb_init(struct sgrb *rb)
+{
+	sgrb_ptr_invalidate(rb, &rb->first);
+	sgrb_ptr_invalidate(rb, &rb->last);
+	rb->entries = 0;
+}
+
+/**
+ * sgrb_alloc - prepare a new ringbuffer for use
+ *
+ * @rb: a ringbuffer struct provided by the exploiter
+ * @entry_size: size of entries in ringbuffer
+ * @entry_num: total number of entries in ringbuffer
+ * @seg_size: size of individual, scatter-gathered segments used to build up
+ *            ringbuffer
+ * @gfp: kmalloc flags
+ *
+ * Returns 0 on success.
+ * Returns -ENOMEM if some memory allocation failed.
+ **/
+int
+sgrb_alloc(
+	struct sgrb *rb,
+	int entry_size, int entry_num, int seg_size, int gfp)
+{
+	int i;
+	struct sgrb_seg *seg;
+	int entries_per_seg = (seg_size / entry_size);
+	int seg_num = entry_num / entries_per_seg;
+	int residual = (entry_num % entries_per_seg) * entry_size;
+
+	rb->entry_size = entry_size;
+	INIT_LIST_HEAD(&rb->seg_lh);
+	for (i = 0; i < seg_num; i++)
+		if (!sgrb_seg_alloc(&rb->seg_lh, seg_size, gfp))
+			return -ENOMEM;
+	if (residual)
+		if (!sgrb_seg_alloc(&rb->seg_lh, residual, gfp))
+			return -ENOMEM;
+	list_for_each_entry(seg, &rb->seg_lh, list)
+		break;
+	rb->first.seg = seg;
+	rb->last.seg = seg;
+	sgrb_init(rb);
+	return 0;
+}
+EXPORT_SYMBOL(sgrb_alloc);
+
+/**
+ * sgrb_release - destroy a ringbuffer
+ *
+ * @rb: the ringbuffer to release
+ **/
+void
+sgrb_release(struct sgrb *rb)
+{
+	sgrb_seg_release_all(&rb->seg_lh);
+	memset(rb, 0, sizeof(struct sgrb));
+}
+EXPORT_SYMBOL(sgrb_release);
+
+static void
+sgrb_next_entry(
+	struct sgrb *rb,
+	struct sgrb_ptr *pos,
+	struct sgrb_ptr *next)
+{
+	sgrb_ptr_copy(next, pos);
+	next->offset += rb->entry_size;
+	if ((next->offset + rb->entry_size) - 1 > next->seg->size) {
+		if (rb->seg_lh.prev == &next->seg->list) {
+			next->seg = NULL;
+			next->seg = list_prepare_entry(next->seg, &rb->seg_lh, list);
+		}
+		list_for_each_entry_continue(next->seg, &rb->seg_lh, list)
+			break;
+		next->offset = 0;
+	}
+}
+
+/**
+ * sgrb_produce_overwrite - put an entry into the ringbuffer and
+ *     overwrite an older entry not yet consumed if required
+ *
+ * @rb: the ringbuffer pointer to use
+ *
+ * Always returns address of the new entry.
+ **/
+void *
+sgrb_produce_overwrite(struct sgrb *rb)
+{
+	struct sgrb_ptr next;
+
+	sgrb_next_entry(rb, &rb->last, &next);
+	if (!sgrb_ptr_valid(&rb->first))
+		sgrb_ptr_copy(&rb->first, &next);
+	else if (sgrb_ptr_identical(&next, &rb->first))
+		sgrb_consume_delete(rb);
+	sgrb_ptr_copy(&rb->last, &next);
+	rb->entries++;
+	return sgrb_entry(&next);
+}
+EXPORT_SYMBOL(sgrb_produce_overwrite);
+
+/**
+ * sgrb_produce_nooverwrite - put an entry into the ringbuffer
+ *     if there is room whithout the need to overwrite the oldest
+ *     entry not yet consumed
+ *
+ * @rb: the ringbuffer to use
+ *
+ * Returns address of the new entry, if there is room for it.
+ * Returns NULL otherwise.
+ **/
+void *
+sgrb_produce_nooverwrite(struct sgrb *rb)
+{
+	struct sgrb_ptr next;
+
+	sgrb_next_entry(rb, &rb->last, &next);
+	if (!sgrb_ptr_valid(&rb->first))
+		sgrb_ptr_copy(&rb->first, &next);
+	else if (sgrb_ptr_identical(&next, &rb->first))
+		return NULL;
+	rb->entries++;
+	return sgrb_entry(&next);
+}
+EXPORT_SYMBOL(sgrb_produce_nooverwrite);
+
+/**
+ * sgrb_consume_delete - get an entry from the ringbuffer and
+ *     delete the entry from the ringbuffer so that it can't
+ *     be consumed twice, and in order to free up its slot for
+ *     another entry
+ *
+ * @rb: the ringbuffer to use
+ *
+ * Returns address of the entry read, if there is an entry available.
+ * Returns NULL otherwise.
+ **/
+void *
+sgrb_consume_delete(struct sgrb *rb)
+{
+	struct sgrb_ptr prev;
+
+	if (!sgrb_ptr_valid(&rb->first))
+		return NULL;
+	sgrb_ptr_copy(&prev, &rb->first);
+	if (sgrb_ptr_identical(&rb->last, &rb->first))
+		sgrb_init(rb);
+	else
+		sgrb_next_entry(rb, &rb->first, &rb->first);
+	rb->entries--;
+	return sgrb_entry(&prev);
+}
+EXPORT_SYMBOL(sgrb_consume_delete);
+
+/**
+ * sgrb_consume_delete - get an entry from the ringbuffer
+ *     while keeping this entry in the ringbuffer so that it can
+ *     be consumed again
+ *
+ * @rb: the ringbuffer to use
+ * @pos:  the ringbuffer pointer that determines which entry to consume
+ *
+ * Use sgrb_ptr_copy() to prepare pos prior to iterating over the ringbuffer
+ * (copy rb->first, the producers tail and the consumers head, to pos).
+ *
+ * Returns address of the new entry, if there is room for it.
+ * Returns NULL otherwise.
+ **/
+void *
+sgrb_consume_nodelete(
+	struct sgrb *rb,
+	struct sgrb_ptr *pos)
+{
+	struct sgrb_ptr prev;
+
+	if (!sgrb_ptr_valid(pos))
+		return NULL;
+	sgrb_ptr_copy(&prev, pos);
+	if (sgrb_ptr_identical(&rb->last, pos))
+		sgrb_ptr_invalidate(rb, pos);
+	else
+		sgrb_next_entry(rb, pos, pos);
+	return sgrb_entry(&prev);
+}
+EXPORT_SYMBOL(sgrb_consume_nodelete);
diff -urN oldtree/arch/s390/kernel/statistic.c newtree/arch/s390/kernel/statistic.c
--- oldtree/arch/s390/kernel/statistic.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/s390/kernel/statistic.c	2006-02-21 15:58:23.519571040 +0000
@@ -0,0 +1,2236 @@
+/*
+ *  arch/s390/kernel/statistic.c
+ *   S/390 statistic facility
+ *
+ *    Copyright (C) 2005 IBM Deutschland Entwicklung GmbH,
+ *                       IBM Corporation
+ *
+ *    Author(s): Martin Peschke (mpeschke@de.ibm.com),
+ *
+ *    Bugreports to: <Linux390@de.ibm.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *    todos:
+ *	- dev. team: define a set of agreed names or a naming scheme for
+ *	  consistency and comparability across exploiters
+ *	  (e.g. similar statistic names for latencies of dasd driver
+ *	  and zfcp driver); this entails an agreement about granularities
+ *	  as well (e.g. seperate statistic for read/write/no-data commands);
+ *	  a common set of unit strings would be nice then, too, of course
+ *	  (e.g. "seconds", "milliseconds", "microseconds", ...)
+ *
+ *
+ *    another bunch of ideas being pondered:
+ *	- provide a (perl?) script for automatic reformating and processing of
+ *	  the contents of "data" files (for generating fancy tables, diagrams
+ *	  in ASCII-art, XML-output ready to be imported into the OpenOffice
+ *	  spreadsheet/diagram tool, ... you name it); a generic script that
+ *	  takes hints from "definition" files into account would basically
+ *	  suffice for all exploiters
+ *	- slim down struct statistic and move on/off/reset/started/stopped
+ *        etc. up to struct statistic_interface???
+ *	  (Is there a need to turn individual statistic on and off etc; or
+ *	  is it more handy and sufficient to allow that only for the entirety
+ *	  of all statistic attached to an interface?)
+ *	- some user-configurable that allows to release unused resources
+ *	  of stopped statistic; or release on stop / allocate on start?
+ *	- perf. opt. of array: table lookup of values, binary search for values
+ *	- another statistic disclipline based on some sort of tree, but
+ *	  similar in semantics to list discipline (for high-perf. histograms of
+ *	  discrete values)
+ *	- use list entries (visible in data file) for hits_out_of_range/
+ *	  hits_missed instead of meta data values (visible in definition file)
+ *	  on analogy to first and last entries of array discipline (<=range_min,
+ *	  >range_max)???
+ *	- allow for more than a single "view" on data at the same time by
+ *	  providing the capability to attach several (a list of) "definitions"
+ *	  to a struct statistic
+ *	  (e.g. show histogram of requests sizes and history of megabytes/sec.
+ *	  at the same time)
+ *	- group similar statitistics in classes and allow for redefinitions
+ *	  per group
+ *	  (e.g. [automagically?] group all list disciplines of request sizes
+ *	  gathered by zfcp in order to allow for a single-operation redefinition
+ *	  of range_max for all of them)
+ *	- multi-dimensional statistic (combination of two or more
+ *	  characteristics/discriminators); worth the effort??
+ *	  (e.g. a matrix of occurences for latencies of requests of
+ *	  particular sizes)
+ *	- allow exploiters to register a callback with every struct statistic
+ *	  (or statistic interface?) in order to be able to do another
+ *	  statitics update when the user reads the data file; would be useful
+ *	  for gathering statistic data about any ongoing condition
+ *	- have exploiters always provide the best granularity possible
+ *	  (like nanoseconds instead of milliseconds) in order to keep
+ *	  flexibility, and have the statitics user interface handle any
+ *	  desired computation (like from nanoseconds to milliseconds)
+ *	- allow user to choose hex/oct/dec representation of numbers
+ *	- make "history" an extra option that allows it to combine with
+ *	  any other type/discipline??? (history request size lists???)
+ *
+ *
+ *    locking rules (provided "as is" ;)
+ *	- We grab a global semaphore on calls to statistic_interface_create() /
+ *	  statistic_interface_remove() to make sure various exploiters do not
+ *	  interfere with each other by corrupting internal global data (list).
+ *	- Once an interface has been created, it is assumed that the exploiter
+ *	  serialises any other setup or closure business related to statistic
+ *	  attached to an interface. No locking by us for this purpose!
+ *	- data reading vs. data gathering vs. redefinition (incl. on/off/reset):
+ *	  We hold the interface's spinlock to make sure that statistic' meta
+ *	  data as well its data is accessible (unaccesible during redefinition),
+ *	  and coherent on reading (concurrent updates shall not interfere).
+ *	- data gathering vs. removal of statistic: It is assumed that the
+ *	  exploiter makes sure that data gathering has been turned off and
+ *	  ceased prior to removing any statistic. We cross-check on removal
+ *	  that data gatherig has been turned off.
+ *	- multiple related data updates in the scope of a single interface:
+ *	  We provide *_nolock variants of the statistic_inc() /
+ *	  statistic_add() routines, and thus allow exploiters to manage
+ *	  locking during updates. This way multiple updates can be made in
+ *	  an atomic fashion. Exploiters are encouraged to make use of this
+ *	  if an atomic update of more than one statistic is required to
+ *	  generate the next valid state as to the coherence of different
+ *	  statistic.
+ *	- touching files by user vs. removal of anything: tbd
+ */
+
+#define STATISTIC_C_REVISION "$Revision: 1.16 $"
+
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/parser.h>
+#include <linux/time.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+
+#include <asm/bug.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+
+#include <asm/sgrb.h>
+#include <asm/statistic.h>
+
+extern void tod_to_timeval(__u64, struct timespec *);
+
+struct statistic_global_data statistic_globals;
+
+static int statistic_interface_generic_close(struct inode *inode, struct file *file);
+static ssize_t statistic_interface_generic_read(struct file *, char __user *, size_t, loff_t *);
+static ssize_t statistic_interface_generic_write(struct file *, const char __user *, size_t, loff_t *);
+
+static int statistic_interface_def_open(struct inode *, struct file *);
+static int statistic_interface_def_close(struct inode *, struct file *);
+
+static int statistic_interface_data_open(struct inode *, struct file *);
+
+struct file_operations statistic_def_file_ops = {
+	.owner		= THIS_MODULE,
+	.read		= statistic_interface_generic_read,
+	.write		= statistic_interface_generic_write,
+	.open		= statistic_interface_def_open,
+	.release	= statistic_interface_def_close,
+};
+
+struct file_operations statistic_data_file_ops = {
+	.owner		= THIS_MODULE,
+	.read		= statistic_interface_generic_read,
+	.open		= statistic_interface_data_open,
+	.release	= statistic_interface_generic_close,
+};
+
+// FIXME: get rid of statistic_strings, by merging it into statistic_def? anyone?
+static char * statistic_strings[] = {
+	"name=",
+	"units=",
+	"type=value",
+	"type=range",
+	"type=array",
+	"type=list",
+	"type=raw",
+	"type=history",
+	"on=1",
+	"on=0",
+	"started=",
+	"stopped=",
+	"range_min=",
+	"range_max=",
+	"scale=lin",
+	"scale=log2",
+	"entries_max=",
+	"base_interval=",
+	"hits_missed=",
+	"hits_out_of_range=",
+	"data=",
+	"mode=increments",
+	"mode=products",
+	"mode=range",
+	"period=",
+	NULL
+};
+
+static match_table_t statistic_def = {
+	{STATISTIC_DEF_NAME, "name=%s"},
+	{STATISTIC_DEF_UNIT, "units="},
+	{STATISTIC_DEF_TYPE_VALUE, "type=value"},
+	{STATISTIC_DEF_TYPE_RANGE, "type=range"},
+	{STATISTIC_DEF_TYPE_ARRAY, "type=array"},
+	{STATISTIC_DEF_TYPE_LIST, "type=list"},
+	{STATISTIC_DEF_TYPE_RAW, "type=raw"},
+	{STATISTIC_DEF_TYPE_HISTORY, "type=history"},
+	{STATISTIC_DEF_ON, "on=1"},
+	{STATISTIC_DEF_OFF, "on=0"},
+	{STATISTIC_DEF_STARTED, "started="},
+	{STATISTIC_DEF_STOPPED, "stopped="},
+	{STATISTIC_DEF_RANGEMIN, "range_min=%s"},
+	{STATISTIC_DEF_RANGEMAX, "range_max=%s"},
+	{STATISTIC_DEF_SCALE_LIN, "scale=lin"},
+	{STATISTIC_DEF_SCALE_LOG2, "scale=log2"},
+	{STATISTIC_DEF_ENTRIESMAX, "entries_max=%u"},
+	{STATISTIC_DEF_BASEINT, "base_interval=%s"},
+	{STATISTIC_DEF_HITSMISSED, "hits_missed="},
+	{STATISTIC_DEF_HITSOUT, "hits_out_of_range="},
+	{STATISTIC_DEF_RESET, "data=reset"},
+	{STATISTIC_DEF_MODE_INC, "mode=increments"},
+	{STATISTIC_DEF_MODE_PROD, "mode=products"},
+	{STATISTIC_DEF_MODE_RANGE, "mode=range"},
+	{STATISTIC_DEF_PERIOD, "period=%s"},
+	{STATISTIC_DEF_VOID, NULL}
+};
+
+/* code concerned with module matters */
+
+int
+__init statistic_init(void)
+{
+	sema_init(&statistic_globals.sem, 1);
+	INIT_LIST_HEAD(&statistic_globals.interface_lh);
+	statistic_globals.root_dir = debugfs_create_dir(STATISTIC_ROOT_DIR, NULL);
+	return 0;
+}
+
+void
+__exit statistic_exit(void)
+{
+	// FIXME: any need to cleanup any statistic possibly still allocated?
+	debugfs_remove(statistic_globals.root_dir);
+}
+
+/* basic helper routines for time handling */
+
+static inline void
+statistic_nsec_to_timespec(u64 nsec, struct timespec *xtime)
+{
+	unsigned long long sec;
+
+        sec = nsec;
+        do_div(sec, 1000000000);
+        xtime->tv_sec = sec;
+        xtime->tv_nsec = nsec - sec * 1000000000;
+}
+
+static inline u64
+statistic_timespec_to_nsec(struct timespec *xtime)
+{
+	return (xtime->tv_sec * 1000000000 + xtime->tv_nsec);
+}
+
+static inline void
+statistic_tod_to_timespec(u64 tod, struct timespec *xtime)
+{
+	tod -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
+	tod_to_timeval(tod, xtime);
+}
+
+static inline u64
+statistic_tod_to_nsec(u64 tod)
+{
+	struct timespec xtime;
+
+	statistic_tod_to_timespec(tod, &xtime);
+	return statistic_timespec_to_nsec(&xtime);
+}
+
+static inline u64
+statistic_get_clock_nsec(void)
+{
+	return statistic_tod_to_nsec(get_clock());
+}
+
+static inline char *
+statistic_timespec_to_string(struct timespec *xtime, char *s)
+{
+	sprintf(s, "%011lu:%06lu", xtime->tv_sec, xtime->tv_nsec / 1000);
+	return s;
+}
+
+static inline char *
+statistic_tod_to_string(u64 tod, char *s)
+{
+	struct timespec xtime;
+
+	statistic_tod_to_timespec(tod, &xtime);
+	return statistic_timespec_to_string(&xtime, s);
+}
+
+static inline char *
+statistic_nsec_to_string(u64 nsec, char *s)
+{
+	struct timespec xtime;
+
+	statistic_nsec_to_timespec(nsec, &xtime);
+	return statistic_timespec_to_string(&xtime, s);
+}
+
+/* code mostly concerned with accounting */
+
+static inline void
+statistic_release(struct statistic *stat)
+{
+	if (stat->release)
+		stat->release(stat);
+	stat->reset = 0;
+}
+
+static inline int
+statistic_alloc(struct statistic *stat)
+{
+	int retval = 0;
+
+	if (stat->alloc)
+		retval = stat->alloc(stat);
+
+	if (retval)
+		statistic_release(stat);
+	else
+		stat->reset = get_clock();
+
+	return retval;
+}
+
+static inline int
+statistic_start_nolock(struct statistic *stat)
+{
+	int retval = stat->on;
+
+	stat->on = STATISTIC_DEF_ON;
+	stat->started = get_clock();
+
+	return retval;
+}
+
+/**
+ * statistic_start - enable statistic for data gathering
+ * @stat: statistic to be enabled
+ *
+ * Start data gathering without discarding old data.
+ * Function is both available to exploiting device drivers as well as to
+ * the user through the "definition" file.
+ *
+ * On success, returns the previous on/off state.
+ **/
+int
+statistic_start(struct statistic *stat)
+{
+	unsigned long flags;
+	int retval;
+
+	spin_lock_irqsave(&stat->interface->lock, flags);
+	retval = statistic_start_nolock(stat);
+	spin_unlock_irqrestore(&stat->interface->lock, flags);
+
+	return retval;
+}
+
+static inline int
+statistic_stop_nolock(struct statistic *stat)
+{
+	int retval = stat->on;
+
+	stat->on = STATISTIC_DEF_OFF;
+	stat->stopped = get_clock();
+
+	return retval;
+}
+
+/**
+ * statistic_stop - disable statistic for data gathering
+ * @stat: statistic to be disabled
+ *
+ * Stop data gathering without discarding old data.
+ * Function is both available to exploiting device drivers as well as to
+ * the user through the "definition" file.
+ *
+ * On success, returns the previous on/off state.
+ **/
+int
+statistic_stop(struct statistic *stat)
+{
+	unsigned long flags;
+	int retval;
+
+	spin_lock_irqsave(&stat->interface->lock, flags);
+	retval = statistic_stop_nolock(stat);
+	spin_unlock_irqrestore(&stat->interface->lock, flags);
+
+	return retval;
+}
+
+static inline int
+statistic_reset_nolock(struct statistic *stat)
+{
+	statistic_release(stat);
+	return statistic_alloc(stat);
+}
+
+/**
+ * statistic_reset - reset statistic as to data gathered so far
+ * @stat: statistic to be disabled
+ *
+ * Discard any gathered data without changing the on/off state.
+ * Function is both available to exploiting device drivers as well as to
+ * the user through the "definition" file.
+ *
+ * On success, returns the previous on/off state.
+ *
+ * If some required memory could not be (re-)allocated this routine fails,
+ * and -ENOMEM is returned.
+ **/
+int
+statistic_reset(struct statistic *stat)
+{
+	unsigned long flags;
+	int retval;
+
+	spin_lock_irqsave(&stat->interface->lock, flags);
+	retval = statistic_reset_nolock(stat);
+	spin_unlock_irqrestore(&stat->interface->lock, flags);
+
+	return retval;
+}
+
+/**
+ * statistic_create - create a statistic and attach it to a given interface
+ * @stat_ptr: reference to struct statistic pointer
+ * @interface_ptr: reference to struct statistic_interface pointer
+ * @name: name of statistic to be created and as seen in "data" and
+ *        "definition" files
+ *
+ * Create a statistic, which - after being defined and enabled - is ready
+ * to capture and compute data provided by the exploiter. A line in the
+ * interface's "definition" file will hold specifics about the named statistic.
+ *
+ * On success, 0 is returned, the struct statistic pointer
+ * provided by the caller points to a newly alloacted struct,
+ * and the statistic is defined as type "value" by default.
+ *
+ * If the struct statistic pointer provided by the caller
+ * is not NULL (used), this routine fails, the struct statistic
+ * pointer is not changed, and -EINVAL is returned.
+ *
+ * If some required memory could not be allocated this routine fails,
+ * the struct statistic pointer is not changed, and -ENOMEM is returned.
+ **/
+int
+statistic_create(
+	struct statistic **stat_ptr,
+	struct statistic_interface *interface,
+	const char *name,
+	const char *units)
+{
+	struct statistic *stat;
+
+	if (*stat_ptr || !interface)
+		return -EINVAL;
+
+	stat = kmalloc(sizeof(struct statistic), GFP_KERNEL);
+	if (!stat)
+		return -ENOMEM;
+	memset(stat, 0, sizeof(struct statistic));
+
+	stat->interface = interface;
+	strlcpy(stat->name, name, sizeof(stat->name));
+	strlcpy(stat->units, units, sizeof(stat->units));
+	statistic_define_value(stat, STATISTIC_RANGE_MIN, STATISTIC_RANGE_MAX,
+				STATISTIC_DEF_MODE_INC);
+	statistic_stop_nolock(stat);
+	stat->started = stat->stopped;
+	stat->stat_ptr = stat_ptr;
+
+	list_add_tail(&stat->list, &interface->statistic_lh);
+
+	*stat_ptr = stat;
+
+	return 0;
+}
+
+/**
+ * statistic_remove - remove given statistic
+ * @stat_ptr: reference to struct statistic_interface pointer
+ *
+ * Remove statistic along with its recent data an definition.
+ *
+ * On success, 0 is returned and the struct statistic pointer
+ * provided by the caller is set to NULL.
+ *
+ * If the struct statistic pointer provided by the caller
+ * is NULL (unused), this routine fails, the struct statistic
+ * pointer is not changed, and -EINVAL is returned.
+ **/
+int
+statistic_remove(struct statistic **stat_ptr)
+{
+	if (!*stat_ptr)
+		return -EINVAL;
+
+	statistic_release(*stat_ptr);
+	list_del(&(*stat_ptr)->list);
+	kfree(*stat_ptr);
+	*stat_ptr = NULL;
+
+	return 0;
+}
+
+static int
+statistic_format_def(struct statistic *stat, struct statistic_file_private *private)
+{
+	struct sgrb_seg *seg;
+	char t0[22], t1[22], t2[22];
+
+	seg = sgrb_seg_find(&private->read_seg_lh, 1024, GFP_ATOMIC);
+	if (!seg)
+		return -ENOMEM;
+
+	seg->offset += sprintf(seg->address + seg->offset,
+				"%s%s %s %s %s%lld %s%lld",
+				statistic_strings[STATISTIC_DEF_NAME],
+				stat->name,
+				statistic_strings[stat->on],
+				statistic_strings[stat->type],
+				statistic_strings[STATISTIC_DEF_RANGEMIN],
+				(long long signed)stat->range_min,
+				statistic_strings[STATISTIC_DEF_RANGEMAX],
+				(long long signed)stat->range_max);
+
+	if (stat->format_def)
+		seg->offset += stat->format_def(stat,
+						seg->address + seg->offset);
+
+	seg->offset += sprintf(seg->address + seg->offset,
+				" %s%llu %s%s %s%s %s%s %s%s\n\n",
+				statistic_strings[STATISTIC_DEF_HITSOUT],
+				(long long unsigned)stat->hits_out_of_range,
+				statistic_strings[STATISTIC_DEF_RESET],
+				(stat->reset ?
+				 statistic_tod_to_string(stat->reset, t0) :
+				 "NOMEM"),
+				statistic_strings[STATISTIC_DEF_STARTED],
+				statistic_tod_to_string(stat->started, t1),
+				statistic_strings[STATISTIC_DEF_STOPPED],
+				statistic_tod_to_string(stat->stopped, t2),
+				statistic_strings[STATISTIC_DEF_UNIT],
+				stat->units);
+
+	return 0;
+}
+
+/* code concerned with single value statistic */
+
+static int
+statistic_alloc_value(struct statistic *stat)
+{
+	stat->data.value.hits = 0;
+	return 0;
+}
+
+static inline void
+_statistic_format_data_value(
+	struct statistic *stat, struct sgrb_seg *seg, char *s,
+	u64 value)
+{
+	seg->offset += sprintf(seg->address + seg->offset, "%s%s %llu\n",
+				stat->name, s,
+				(unsigned long long)stat->data.value.hits);
+}
+
+static int
+statistic_format_data_value(
+	struct statistic *stat, struct statistic_file_private *private)
+{
+	struct sgrb_seg *seg;
+
+	seg = sgrb_seg_find(&private->read_seg_lh, 128, GFP_ATOMIC);
+	if (!seg)
+		return -ENOMEM;
+
+	_statistic_format_data_value(stat, seg, "", stat->data.value.hits);
+	return 0;
+}
+
+static int
+statistic_format_def_value(struct statistic *stat, char *line)
+{
+	return sprintf(line, " %s", statistic_strings[stat->data.value.mode]);
+}
+
+static inline u64
+_statistic_add_value_increments(s64 *single, s64 value, u64 incr)
+{
+	return (*single += incr);
+}
+
+static inline u64
+_statistic_add_value_products(s64 *single, s64 value, u64 incr)
+{
+	if (value < 0)
+		value = -value;
+	return (*single += value * incr);
+}
+
+static u64
+statistic_add_value_increments(struct statistic *stat, s64 value, u64 incr)
+{
+	if (value < stat->range_min || value > stat->range_max) {
+		stat->hits_out_of_range++;
+		return 0;
+	}
+	return _statistic_add_value_increments(
+			&stat->data.value.hits, value, incr);
+}
+
+static u64
+statistic_add_value_products(struct statistic *stat, s64 value, u64 incr)
+{
+	if (value < stat->range_min || value > stat->range_max) {
+		stat->hits_out_of_range++;
+		return 0;
+	}
+	return _statistic_add_value_products(
+			&stat->data.value.hits, value, incr);
+}
+
+/**
+ * statistic_define_value - instantiate statistic as single value (counter)
+ * @stat: statistic to be defined
+ * @range_min: lower bound of discriminators
+ * @range_max: upper bound of discriminators
+ * @mode: accumulate increments only, or products of discriminator and increment
+ *
+ * Determines that the statistic accumulates all increments - regardless of the
+ * value of the discriminator - into a single value. It can be seen as a
+ * histogram collapsed into a single counter providing the total of all
+ * increments.
+ *
+ * Depending on the definition, accumulation is done as
+ *
+ * a) <total> += <increment N>				(mode=increments)
+ * b) <total> += ABS(<discriminator N>) * <increment N>	(mode=products)
+ *
+ * The output format of a single value statistic found in the "data" file is:
+ * <statistic name> <total>
+ *
+ * This (re)definition function is available both to exploiting device drivers
+ * and to the user through the "definition" file. Device driver programmers
+ * might find it user-friendly to provide a default definition for
+ * particular statistic by calling this or a related function. A previous
+ * definition is replaced by the new one. Next, the statistic must be enabled
+ * in order to make it gather data. A line in the interface's "definition"
+ * file will hold specifics about the named statistic.
+ *
+ * On success, 0 is returned.
+ *
+ * If some required memory could not be allocated this routine fails,
+ * and -ENOMEM is returned.
+ **/
+int statistic_define_value(
+	struct statistic *stat, s64 range_min, s64 range_max, int mode)
+{
+	unsigned long flags;
+	int retval;
+
+	if (mode != STATISTIC_DEF_MODE_INC &&
+	    mode != STATISTIC_DEF_MODE_PROD)
+		return -EINVAL;
+
+	spin_lock_irqsave(&stat->interface->lock, flags);
+
+	statistic_release(stat);
+
+	stat->type = STATISTIC_DEF_TYPE_VALUE;
+	stat->range_min = range_min;
+	stat->range_max = range_max;
+	stat->data.value.mode = mode;
+
+	stat->alloc = statistic_alloc_value;
+	stat->release = NULL;
+	stat->format_data = statistic_format_data_value;
+	stat->format_def = statistic_format_def_value;
+	if (mode == STATISTIC_DEF_MODE_INC)
+		stat->add = statistic_add_value_increments;
+	else
+		stat->add = statistic_add_value_products;
+
+	retval = statistic_alloc(stat);
+
+	spin_unlock_irqrestore(&stat->interface->lock, flags);
+
+	return retval;
+}
+
+/* code concerned with range statistic */
+
+static inline void
+_statistic_alloc_range(
+	struct statistic_entry_range *range, s64 range_min, s64 range_max)
+{
+	range->num = 0;
+	range->acc = 0;
+	range->min = range_max + 1;
+	range->max = range_min - 1;
+}
+
+static int
+statistic_alloc_range(struct statistic *stat)
+{
+	_statistic_alloc_range(
+		&stat->data.range.range, stat->range_min, stat->range_max);
+	return 0;
+}
+
+static inline void
+_statistic_format_data_range(
+	struct statistic *stat, struct sgrb_seg *seg, char *s,
+	struct statistic_entry_range *range)
+{
+	long long unsigned whole = 0;
+	long long signed min = 0, max = 0, decimal = 0, last_digit;
+
+	if (range->num) {
+		whole = range->acc;
+		do_div(whole, range->num);
+		decimal  = range->acc * 10000;
+		do_div(decimal, range->num);
+		decimal -= whole * 10000;
+		if (decimal < 0)
+			decimal = -decimal;
+		last_digit = decimal;
+		do_div(last_digit, 10);
+		last_digit = decimal - last_digit * 10;
+		if (last_digit >= 5)
+			decimal += 10;
+		do_div(decimal, 10);
+		min = range->min;
+		max = range->max;
+	}
+
+	seg->offset += sprintf(seg->address + seg->offset,
+				"%s%s %llu %lld %lld.%03lld %lld\n",
+				stat->name, s,
+				(long long unsigned)range->num,
+				(long long signed)min,
+				whole, decimal,
+				(long long signed)max);
+}
+
+static int
+statistic_format_data_range(
+	struct statistic *stat, struct statistic_file_private *private)
+{
+	struct sgrb_seg *seg;
+
+	seg = sgrb_seg_find(&private->read_seg_lh, 128, GFP_ATOMIC);
+	if (!seg)
+		return -ENOMEM;
+
+	_statistic_format_data_range(
+		stat, seg, "", &stat->data.range.range);
+	return 0;
+}
+
+static inline u64
+_statistic_add_range(struct statistic_entry_range *range, s64 value, u64 incr)
+{
+	range->num += incr;
+	range->acc += value * incr;
+	if (value < range->min)
+		range->min = value;
+	if (value > range->max)
+		range->max = value;
+	return range->num;
+}
+
+static u64
+statistic_add_range(struct statistic *stat, s64 value, u64 incr)
+{
+	if (value < stat->range_min || value > stat->range_max) {
+		stat->hits_out_of_range++;
+		return 0;
+	}
+	return _statistic_add_range(&stat->data.range.range, value, incr);
+}
+
+/**
+ * statistic_define_range - instantiate statistic as small set of values
+ *    that describe a range
+ * @stat: statistic to be defined
+ * @range_min: lower bound of discriminators
+ * @range_max: upper bound of discriminators
+ *
+ * Determines that the statistic provides the minimum, average and maximum
+ * of the numbers reported by the exploiter. Besides the number of updates
+ * is counted. Statistics events with increments larger than 1 are counted
+ * as multiple occurences of a particular discrimintator with regard to
+ * the computation of average.
+ * For example, this statistic type could be used as a fill level or
+ * utilisation indicator for queues.
+ *
+ * The output format of a range statistic found in the "data" file is:
+ * <statistic name> <total of increments> <minimum> <average> <maximum>
+ *
+ * This (re)definition function is available both to exploiting device drivers
+ * and to the user through the "definition" file. Device driver programmers
+ * might find it user-friendly to provide a default definition for
+ * particular statistic by calling this or a related function. A previous
+ * definition is replaced by the new one. Next, the statistic must be enabled
+ * in order to make it gather data. A line in the interface's "definition"
+ * file will hold specifics about the named statistic.
+ *
+ * On success, 0 is returned.
+ *
+ * If some required memory could not be allocated this routine fails,
+ * and -ENOMEM is returned.
+ **/
+int statistic_define_range(
+	struct statistic *stat, s64 range_min, s64 range_max)
+{
+	unsigned long flags;
+	int retval;
+
+	spin_lock_irqsave(&stat->interface->lock, flags);
+
+	statistic_release(stat);
+
+	stat->type = STATISTIC_DEF_TYPE_RANGE;
+	stat->range_min = range_min;
+	stat->range_max = range_max;
+
+	stat->alloc = statistic_alloc_range;
+	stat->release = NULL;
+	stat->format_data = statistic_format_data_range;
+	stat->format_def = NULL;
+	stat->add = statistic_add_range;
+
+	retval = statistic_alloc(stat);
+
+	spin_unlock_irqrestore(&stat->interface->lock, flags);
+
+	return retval;
+}
+
+/* code concerned with fixed array statistic */
+
+static inline s64
+statistic_array_calc_value_lin(struct statistic *stat, int index)
+{
+	return stat->range_min + (stat->data.array.base_interval * index);
+}
+
+static inline s64
+statistic_array_calc_value_log2(struct statistic *stat, int index)
+{
+	return stat->range_min +
+		(index ? (stat->data.array.base_interval << (index - 1)) : 0);
+}
+
+static inline s64
+statistic_array_calc_value(struct statistic *stat, int index)
+{
+	if (stat->data.array.scale == STATISTIC_DEF_SCALE_LIN)
+		return statistic_array_calc_value_lin(stat, index);
+	else
+		return statistic_array_calc_value_log2(stat, index);
+}
+
+static inline int
+statistic_array_calc_index_lin(struct statistic *stat, s64 value)
+{
+	unsigned long long index = value - stat->range_min;
+	do_div(index, stat->data.array.base_interval);
+	return index;
+}
+
+static inline int
+statistic_array_calc_index_log2(struct statistic *stat, s64 value)
+{
+	unsigned long long index;
+
+	for (index = 0;
+	     index < (stat->data.array.entries - 1) &&
+	     value > statistic_array_calc_value_log2(stat, index);
+	     index++);
+	return index;
+}
+
+static inline int
+statistic_array_calc_index(struct statistic *stat, s64 value)
+{
+	if (stat->data.array.scale == STATISTIC_DEF_SCALE_LIN)
+		return statistic_array_calc_index_lin(stat, value);
+	else
+		return statistic_array_calc_index_log2(stat, value);
+}
+
+static int
+statistic_alloc_array(struct statistic *stat)
+{
+	int i, size;
+
+	for (i = 0;
+	     statistic_array_calc_value(stat, i) <= stat->range_max;
+	     i++);
+	i++;
+	if (i < 2)
+		return -EINVAL;
+	stat->data.array.entries = i;
+
+	size = stat->data.array.entries * sizeof(u64);
+	stat->data.array.hits = kmalloc(size, GFP_ATOMIC);
+	if (!stat->data.array.hits)
+		return -ENOMEM;
+	memset(stat->data.array.hits, 0, size);
+	return 0;
+}
+
+static void
+statistic_release_array(struct statistic *stat)
+{
+	kfree(stat->data.array.hits);
+	stat->data.array.hits = NULL;
+}
+
+static inline int
+statistic_format_data_array_line(
+	struct statistic *stat, struct statistic_file_private *private,
+	int i, const char *prefix, u64 value)
+{
+	struct sgrb_seg *seg;
+
+	seg = sgrb_seg_find(&private->read_seg_lh, 256, GFP_ATOMIC);
+	if (!seg)
+		return -ENOMEM;
+
+	seg->offset += sprintf(seg->address + seg->offset,
+				"%s %s%lld %llu\n", stat->name,
+				prefix, (long long signed)value,
+				(long long unsigned)stat->data.array.hits[i]);
+	return 0;
+}
+
+static int
+statistic_format_data_array(
+	struct statistic *stat, struct statistic_file_private *private)
+{
+	int i;
+	int retval;
+
+	for (i = 0; i < (stat->data.array.entries - 1); i++) {
+		retval = statistic_format_data_array_line(
+				stat, private, i, "<=",
+				statistic_array_calc_value(stat, i));
+		if (retval)
+			return retval;
+	}
+	retval = statistic_format_data_array_line(
+			stat, private, i, ">",
+			statistic_array_calc_value(stat, i - 1));
+	return retval;
+}
+
+static int
+statistic_format_def_array(struct statistic *stat, char *line)
+{
+	return  sprintf(line,
+			" %s%llu %s",
+			statistic_strings[STATISTIC_DEF_BASEINT],
+			(long long unsigned)stat->data.array.base_interval,
+			statistic_strings[stat->data.array.scale]);
+}
+
+static u64
+statistic_add_array_lin(struct statistic *stat, s64 value, u64 incr)
+{
+	int index = statistic_array_calc_index_lin(stat, value);
+	return (stat->data.array.hits[index] += incr);
+}
+
+static u64
+statistic_add_array_log2(struct statistic *stat, s64 value, u64 incr)
+{
+	int index = statistic_array_calc_index_log2(stat, value);
+	return (stat->data.array.hits[index] += incr);
+}
+
+/**
+ * statistic_define_array - instantiate statistic as fixed size array of
+ *    discriminator/counter pairs (histogram for intervals)
+ * @stat: statistic to be defined
+ * @range_min: lower bound of discriminators
+ * @range_max: upper bound of discriminators
+ * @base_interval: width of intervals between two discriminators (linear scale);
+ *         starting width of intervals (logarithmic scale, base 2)
+ * @scale: scale applied to discriminators (linear/logarithmic)
+ *
+ * Determines that the statistic maintains a counter for each interval
+ * as determined by the above parameters. These counters hold the total
+ * of the increments applicable to particular intervals. The first interval
+ * is determined by (<the smallest s64 value>, range_min). The last interval
+ * is (range_max, <the largest s64 value>). That means, this statistic
+ * discpline is capable of giving account of hits out of the specified range.
+ * Basically, the function implemented by this statistic discipline is a
+ * histogram for intervals.
+ *
+ * The output format of a fixed-size array statistic found in the "data" file
+ * is:
+ *
+ * <statistic name> "<="<discriminator 0> <total of increments for interval
+ *                                          (smallest s64, discriminator 0)>
+ * <statistic name> "<="<discriminator 1> <total of increments for interval
+ *                                          (discriminator 0, discriminator 1)>
+ * ...
+ * <statistic name> "<="<discriminator N> <total of increments for interval
+ *                                          (discrminator N-1, discrminator N)>
+ * <statistic name> ">"<discriminator N> <total of increments for interval
+ *                                         (discrminator N, largest s64)>
+ *
+ * This (re)definition function is available both to exploiting device drivers
+ * and to the user through the "definition" file. Device driver programmers
+ * might find it user-friendly to provide a default definition for
+ * particular statistic by calling this or a related function. A previous
+ * definition is replaced by the new one. Next, the statistic must be enabled
+ * in order to make it gather data. A line in the interface's "definition"
+ * file will hold specifics about the named statistic.
+ *
+ * On success, 0 is returned.
+ *
+ * If some required memory could not be allocated this routine fails,
+ * and -ENOMEM is returned.
+ **/
+int statistic_define_array(
+	struct statistic *stat, s64 range_min, s64 range_max,
+	u32 base_interval, u8 scale)
+{
+	unsigned long flags;
+	int retval;
+
+	if (stat->range_min > stat->range_max)
+		return -EINVAL;
+
+	if (scale != STATISTIC_DEF_SCALE_LIN &&
+	    scale != STATISTIC_DEF_SCALE_LOG2)
+		return -EINVAL;
+
+	spin_lock_irqsave(&stat->interface->lock, flags);
+
+	statistic_release(stat);
+
+	stat->type = STATISTIC_DEF_TYPE_ARRAY;
+
+	stat->range_min = range_min;
+	stat->range_max = range_max;
+	stat->data.array.base_interval = base_interval;
+	stat->data.array.scale = scale;
+
+	stat->alloc = statistic_alloc_array;
+	stat->release = statistic_release_array;
+	stat->format_data = statistic_format_data_array;
+	stat->format_def = statistic_format_def_array;
+	if (scale == STATISTIC_DEF_SCALE_LIN)
+		stat->add = statistic_add_array_lin;
+	else
+		stat->add = statistic_add_array_log2;
+
+	retval = statistic_alloc(stat);
+
+	spin_unlock_irqrestore(&stat->interface->lock, flags);
+
+	return retval;
+}
+
+/* code concerned with adaptable list statistic */
+
+static int
+statistic_alloc_list(struct statistic *stat)
+{
+	INIT_LIST_HEAD(&stat->data.list.entry_lh);
+	stat->data.list.hits_missed = 0;
+	stat->data.list.entries = 0;
+	return 0;
+}
+
+static void
+statistic_release_list(struct statistic *stat)
+{
+	struct statistic_entry_list *entry, *tmp;
+
+	list_for_each_entry_safe(entry, tmp, &stat->data.list.entry_lh, list) {
+		list_del(&entry->list);
+		kfree(entry);
+	}
+}
+
+static int
+statistic_format_data_list(
+		struct statistic *stat, struct statistic_file_private *private)
+{
+	struct sgrb_seg *seg;
+	struct statistic_entry_list *entry;
+
+	list_for_each_entry(entry, &stat->data.list.entry_lh, list) {
+		seg = sgrb_seg_find(&private->read_seg_lh, 256, GFP_ATOMIC);
+		if (!seg)
+			return -ENOMEM;
+		seg->offset += sprintf(seg->address + seg->offset,
+					"%s 0x%llx %llu\n",
+					stat->name,
+					(long long signed)entry->value,
+					(long long unsigned)entry->hits);
+	}
+	return 0;
+}
+
+static int
+statistic_format_def_list(struct statistic *stat, char *line)
+{
+	return sprintf(line,
+			" %s%u %s%llu",
+			statistic_strings[STATISTIC_DEF_ENTRIESMAX],
+			stat->data.list.entries_max,
+			statistic_strings[STATISTIC_DEF_HITSMISSED],
+			(long long unsigned)stat->data.list.hits_missed);
+}
+
+static inline void
+statistic_add_list_sort(
+		struct list_head *head,
+		struct statistic_entry_list *entry)
+{
+	struct statistic_entry_list *sort =
+		list_prepare_entry(entry, head, list);
+
+	list_for_each_entry_continue_reverse(sort, head, list)
+		if (sort->hits >= entry->hits)
+			break;
+	if (sort->list.next != &entry->list &&
+	    (&sort->list == head || sort->hits >= entry->hits))
+		list_move(&entry->list, &sort->list);
+}
+
+static inline int
+statistic_add_list_new(
+		struct statistic *stat,
+		s64 value,
+		u64 incr)
+{
+	struct statistic_entry_list *entry;
+
+	if (stat->data.list.entries == stat->data.list.entries_max)
+		return -ENOMEM;
+
+	entry = kmalloc(sizeof(struct statistic_entry_list), GFP_ATOMIC);
+	if (entry) {
+		entry->value = value;
+		entry->hits = incr;
+		stat->data.list.entries++;
+		list_add_tail(&entry->list, &stat->data.list.entry_lh);
+		return 0;
+	} else	return -ENOMEM;
+}
+
+static u64
+statistic_add_list(struct statistic *stat, s64 value, u64 incr)
+{
+	struct statistic_entry_list *entry;
+	struct list_head *head = &stat->data.list.entry_lh;
+
+	if (value < stat->range_min || value > stat->range_max) {
+		stat->hits_out_of_range++;
+		return 0;
+	}
+
+	list_for_each_entry(entry, head, list) {
+		if (entry->value == value) {
+			entry->hits += incr;
+			statistic_add_list_sort(head, entry);
+			return entry->hits;
+		}
+	}
+	if (statistic_add_list_new(stat, value, incr)) {
+		stat->data.list.hits_missed++;
+		return 0;
+	} else
+		return incr;
+}
+
+/**
+ * statistic_define_list - instantiate statistic as adaptable size list of
+ *    discriminator/counter pairs (histogram for discrete values)
+ * @stat: statistic to be defined
+ * @range_min: lower bound of discriminators
+ * @range_max: upper bound of discriminators
+ * @entries_max: limits the list size
+ *
+ * Determines that the statistic maintains a counter for each discrete
+ * discriminator that is reported along with increments by the exploiter.
+ * These counters hold the total of the increments applicable to particular
+ * discrminators. Hits that were out of the specified range, or that would have
+ * required list entries beyond the specified maximum, are discarded and their
+ * numbers are visible through the "definition" file.
+ * Basically, the function implemented by this statistic discipline is a
+ * histogram for discrete values. Which values make it into the histogram is
+ * determined by their order of appearance (first come, ...).
+ *
+ * The output format of an adaptable-size list statistic found in the "data"
+ * file is:
+ *
+ * <statistic name> <discriminator 0> <total of increments for discriminator 0>
+ * <statistic name> <discriminator 1> <total of increments for discriminator 1>
+ * ...
+ * <statistic name> <discriminator N> <total of increments for discriminator N>
+ *
+ * This (re)definition function is available both to exploiting device drivers
+ * and to the user through the "definition" file. Device driver programmers
+ * might find it user-friendly to provide a default definition for
+ * particular statistic by calling this or a related function. A previous
+ * definition is replaced by the new one. Next, the statistic must be enabled
+ * in order to make it gather data. A line in the interface's "definition"
+ * file will hold specifics about the named statistic.
+ *
+ * On success, 0 is returned.
+ *
+ * If some required memory could not be allocated this routine fails,
+ * and -ENOMEM is returned.
+ **/
+int
+statistic_define_list(
+	struct statistic *stat, s64 range_min, s64 range_max, u32 entries_max)
+{
+	unsigned long flags;
+	int retval;
+
+	spin_lock_irqsave(&stat->interface->lock, flags);
+
+	statistic_release(stat);
+
+	stat->type = STATISTIC_DEF_TYPE_LIST;
+
+	stat->range_min = range_min;
+	stat->range_max = range_max;
+	stat->data.list.entries_max = entries_max;
+
+	stat->alloc = statistic_alloc_list;
+	stat->release = statistic_release_list;
+	stat->format_data = statistic_format_data_list;
+	stat->format_def = statistic_format_def_list;
+	stat->add = statistic_add_list;
+
+	retval = statistic_alloc(stat);
+
+	spin_unlock_irqrestore(&stat->interface->lock, flags);
+
+	return retval;
+}
+
+/* code concerned with raw, timestamped statistic events */
+
+static int
+statistic_alloc_raw(struct statistic *stat)
+{
+	stat->data.raw.next_serial = 0;
+	return sgrb_alloc(
+			&stat->data.raw.rb,
+			sizeof(struct statistic_entry_raw),
+			stat->data.raw.entries_max, PAGE_SIZE, GFP_ATOMIC);
+}
+
+static void
+statistic_release_raw(struct statistic *stat)
+{
+	sgrb_release(&stat->data.raw.rb);
+}
+
+static int
+statistic_format_data_raw(
+	struct statistic *stat, struct statistic_file_private *private)
+{
+	struct sgrb_seg *seg;
+	struct sgrb_ptr ptr;
+	struct statistic_entry_raw *entry;
+	char t[22];
+
+	sgrb_ptr_copy(&ptr, &stat->data.raw.rb.first);
+	while ((entry = sgrb_consume_nodelete(&stat->data.raw.rb, &ptr))) {
+		seg = sgrb_seg_find(&private->read_seg_lh, 256, GFP_ATOMIC);
+		if (!seg)
+			return -ENOMEM;
+		seg->offset += sprintf(seg->address + seg->offset,
+					"%s %s %llu %lld %llu\n",
+					stat->name,
+					statistic_tod_to_string
+						(entry->clock, t),
+					(long long unsigned)entry->serial,
+					(long long signed)entry->value,
+					(long long unsigned)entry->incr);
+	}
+	return 0;
+}
+
+static int
+statistic_format_def_raw(struct statistic *stat, char *line)
+{
+	return sprintf(line,
+			" %s%u",
+			statistic_strings[STATISTIC_DEF_ENTRIESMAX],
+			stat->data.raw.entries_max);
+}
+
+static u64
+statistic_add_raw(struct statistic *stat, s64 value, u64 incr)
+{
+	struct statistic_entry_raw *entry;
+
+	if (value < stat->range_min || value > stat->range_max) {
+		stat->hits_out_of_range++;
+		return 0;
+	}
+
+	entry = sgrb_produce_overwrite(&stat->data.raw.rb);
+
+	entry->clock = get_clock();
+	entry->serial = stat->data.raw.next_serial++;
+	entry->value = value;
+	entry->incr = incr;
+
+	return incr;
+}
+
+/**
+ * statistic_define_raw - instantiate statistic as a record of incremental
+ *    updates as they have happened (history of statistic events)
+ * @stat: statistic to be defined
+ * @range_min: lower bound of discriminators
+ * @range_max: upper bound of discriminators
+ * @entries_max: maximum number of entries in ringbuffer
+ *
+ * Determines that the statistic does not maintain counters for any increments,
+ * but that it accumulates the reported updates in the form of a history of
+ * these updates. Updates out of the specified range are dropped, though their
+ * total number is readable through the "definition" file. Besides, once the
+ * allocated pages are completely occupied, new entries are written over the
+ * oldest ones (ringbuffer). Each entry is tagged with a unique serial number
+ * and a timestamp. A single entry consumes 32 bytes.
+ *
+ * The output format of a "raw" statistic found in the "data" file is:
+ *
+ * <statistic name> <discriminator> <increments> <serial> <timestamp>
+ *
+ * This (re)definition function is available both to exploiting device drivers
+ * and to the user through the "definition" file. Device driver programmers
+ * might find it user-friendly to provide a default definition for
+ * particular statistic by calling this or a related function. A previous
+ * definition is replaced by the new one. Next, the statistic must be enabled
+ * in order to make it gather data. A line in the interface's "definition"
+ * file will hold specifics about the named statistic.
+ *
+ * On success, 0 is returned.
+ *
+ * If some required memory could not be allocated this routine fails,
+ * and -ENOMEM is returned.
+ **/
+int statistic_define_raw(
+	struct statistic *stat, s64 range_min, s64 range_max, u32 entries_max)
+{
+	unsigned long flags;
+	int retval;
+
+	spin_lock_irqsave(&stat->interface->lock, flags);
+
+	statistic_release(stat);
+
+	stat->type = STATISTIC_DEF_TYPE_RAW;
+
+	stat->range_min = range_min;
+	stat->range_max = range_max;
+	stat->data.raw.entries_max = entries_max;
+
+	stat->alloc = statistic_alloc_raw;
+	stat->release = statistic_release_raw;
+	stat->format_data = statistic_format_data_raw;
+	stat->format_def = statistic_format_def_raw;
+	stat->add = statistic_add_raw;
+
+	retval = statistic_alloc(stat);
+
+	spin_unlock_irqrestore(&stat->interface->lock, flags);
+
+	return retval;
+}
+
+/* code concerned with history statistic */
+
+static int
+statistic_alloc_history(struct statistic *stat)
+{
+	int entry_size = (STATISTIC_DEF_MODE_RANGE ?
+				sizeof(struct statistic_entry_range) :
+				sizeof(s64)) ;
+	int retval = sgrb_alloc(&stat->data.history.rb, entry_size,
+				stat->data.history.entries_max,
+				PAGE_SIZE, GFP_ATOMIC);
+	if (retval)
+		return retval;
+
+	stat->data.history.checkpoint = statistic_get_clock_nsec();
+
+	return 0;
+}
+
+static void
+statistic_release_history(struct statistic *stat)
+{
+	sgrb_release(&stat->data.history.rb);
+}
+
+static inline void *
+statistic_add_history_entry(struct statistic *stat)
+{
+	u64 now, then, window, period, checkp, elapsed;
+	void *entry = NULL;
+
+	window = stat->data.history.window;
+	period = stat->data.history.period;
+	checkp = stat->data.history.checkpoint;
+
+	now = statistic_get_clock_nsec();
+	if (now <= checkp)
+		entry = sgrb_entry(&stat->data.history.rb.last);
+	else	{
+		then = checkp;
+		elapsed = now - then;
+		/*
+		 * FIXME: replace loops by formula for supposedly
+		 * improved performance
+		 *  - would require something like do_div64_64()
+		 */
+#if 0
+		if (elapsed > window)
+			then = (now - window) + (period - elapsed % period);
+#endif
+
+		if (elapsed > window) {
+			for (; then < now - 2 * window; then += window);
+			for (; then < now - window; then += period);
+		}
+		for (; then < now; then += period) {
+			entry = sgrb_produce_overwrite(&stat->data.history.rb);
+			memset(entry, 0, stat->data.history.rb.entry_size);
+		}
+		if (stat->data.history.mode == STATISTIC_DEF_MODE_RANGE)
+			_statistic_alloc_range(
+				(struct statistic_entry_range *)entry,
+				stat->range_min,
+				stat->range_max);
+		stat->data.history.checkpoint = then;
+	}
+	return entry;
+}
+
+static inline int
+statistic_format_data_history(
+	struct statistic *stat, struct statistic_file_private *private)
+{
+	struct sgrb_seg *seg;
+	struct sgrb_ptr ptr;
+	void *entry;
+	u64 time;
+	char t[23];
+
+	/* enforce update in case of inactivity */
+	statistic_add_history_entry(stat);
+	time = stat->data.history.checkpoint -
+	       stat->data.history.period *
+			(stat->data.history.rb.entries - 1);
+	sgrb_ptr_copy(&ptr, &stat->data.history.rb.first);
+	while ((entry = sgrb_consume_nodelete(&stat->data.history.rb, &ptr))) {
+		seg = sgrb_seg_find(&private->read_seg_lh, 256, GFP_ATOMIC);
+		if (!seg)
+			return -ENOMEM;
+		t[0] = ' ';
+		statistic_nsec_to_string(time, &t[1]);
+		switch (stat->data.history.mode) {
+		case STATISTIC_DEF_MODE_INC :
+		case STATISTIC_DEF_MODE_PROD :
+			_statistic_format_data_value(
+				stat, seg, t, *(u64*)entry);
+			break;
+		case STATISTIC_DEF_MODE_RANGE :
+			_statistic_format_data_range(
+				stat, seg, t,
+				(struct statistic_entry_range *)entry);
+			break;
+		default :
+			break;
+		}
+		time += stat->data.history.period;
+	}
+	return 0;
+}
+
+static inline int
+statistic_format_def_history(struct statistic *stat, char *line)
+{
+	unsigned long long period = stat->data.history.period;
+
+	do_div(period, 1000);
+	return sprintf(line,
+			" %s%u %s %s%llu",
+			statistic_strings[STATISTIC_DEF_ENTRIESMAX],
+			stat->data.history.entries_max,
+	    		statistic_strings[stat->data.history.mode],
+			statistic_strings[STATISTIC_DEF_PERIOD],
+			period);
+}
+
+static u64
+statistic_add_history_increments(struct statistic *stat, s64 value, u64 incr)
+{
+	if (value < stat->range_min || value > stat->range_max) {
+		stat->hits_out_of_range++;
+		return 0;
+	}
+	return _statistic_add_value_increments(
+			(s64*) statistic_add_history_entry(stat), value, incr);
+}
+
+static u64
+statistic_add_history_products(struct statistic *stat, s64 value, u64 incr)
+{
+	if (value < stat->range_min || value > stat->range_max) {
+		stat->hits_out_of_range++;
+		return 0;
+	}
+	return _statistic_add_value_products(
+			(s64*) statistic_add_history_entry(stat), value, incr);
+}
+
+static u64
+statistic_add_history_range(struct statistic *stat, s64 value, u64 incr)
+{
+	if (value < stat->range_min || value > stat->range_max) {
+		stat->hits_out_of_range++;
+		return 0;
+	}
+	return _statistic_add_range(
+			(struct statistic_entry_range *)
+				statistic_add_history_entry(stat),
+			value, incr);
+}
+
+/**
+ * statistic_define_history - instantiate statistic as a history
+ *    that accumulates all updates per defined period of time
+ * @stat: statistic to be defined
+ * @range_min: lower bound of discriminators
+ * @range_max: upper bound of discriminators
+ * @entries: number of entries of the history buffer
+ * @mode: accumulate increments only, or products of discriminator and increment
+ * @period: time to elapse for each entry in history
+ *
+ * Determines that the statistic does not maintain counters per a fixed period
+ * of time. All updates within a particular period of time are added up. When
+ * that period has passed, the next entry in the history buffer is used to start
+ * over with accumulation. The history buffer is a ringbuffer, that is, the
+ * oldest entry is replaced by the newest, if the history buffer has been filled
+ * up. Updates out of the specified range are dropped, though their total number
+ * is readable through the "definition" file. Each entry is tagged with a
+ * and a timestamp. Each entry consumes 8 bytes (mode=increments, mode=products)
+ * or 32 bytes (mode=range).
+ *
+ * Depending on the definition, accumulation is done as
+ *
+ * a) mode=increments	: see statistic_define_value()
+ * b) mode=products	: see statistic_define_value()
+ * c) mode=range	: see statistic_define_range()
+ *
+ * The output format of a "history" statistic found in the "data" file is
+ * (for mode=increments and mode=products):
+ *
+ * <statistic name> <timestamp> <total for period of time>
+ *
+ * This (re)definition function is available both to exploiting device drivers
+ * and to the user through the "definition" file. Device driver programmers
+ * might find it user-friendly to provide a default definition for
+ * particular statistic by calling this or a related function. A previous
+ * definition is replaced by the new one. Next, the statistic must be enabled
+ * in order to make it gather data. A line in the interface's "definition"
+ * file will hold specifics about the named statistic.
+ *
+ * On success, 0 is returned.
+ *
+ * If some required memory could not be allocated this routine fails,
+ * and -ENOMEM is returned.
+ **/
+int statistic_define_history(
+	struct statistic *stat, s64 range_min, s64 range_max, u32 entries_max,
+	u64 period, int mode)
+{
+	unsigned long flags;
+	int retval;
+
+	if (mode != STATISTIC_DEF_MODE_INC &&
+	    mode != STATISTIC_DEF_MODE_PROD &&
+	    mode != STATISTIC_DEF_MODE_RANGE)
+		return -EINVAL;
+
+	spin_lock_irqsave(&stat->interface->lock, flags);
+
+	statistic_release(stat);
+
+	period *= 1000;	/* microseconds to nanoseconds */
+
+	stat->type = STATISTIC_DEF_TYPE_HISTORY;
+	stat->range_min = range_min;
+	stat->range_max = range_max;
+	stat->data.history.entries_max = entries_max;
+	stat->data.history.mode = mode;
+	stat->data.history.period = period;
+	stat->data.history.window = entries_max * period;
+
+	stat->alloc = statistic_alloc_history;
+	stat->release = statistic_release_history;
+	stat->format_data = statistic_format_data_history;
+	stat->format_def = statistic_format_def_history;
+	if (mode == STATISTIC_DEF_MODE_INC)
+		stat->add = statistic_add_history_increments;
+	else if (mode == STATISTIC_DEF_MODE_PROD)
+		stat->add = statistic_add_history_products;
+	else
+		stat->add = statistic_add_history_range;
+
+	retval = statistic_alloc(stat);
+
+	spin_unlock_irqrestore(&stat->interface->lock, flags);
+
+	return retval;
+}
+
+/* code concerned with user interface */
+
+/**
+ * statistic_interface_create - create debugfs files for statistic
+ * @interface_ptr: reference to struct statistic_interface pointer
+ * @name: name of debugfs directory to be created
+ *
+ * Create a debugfs directory in "s390stat" as well as the "data" and
+ * "definition" files. Creating this user interface is prequisite for
+ * attaching statistic to an interface.
+ *
+ * On success, 0 is returned and the struct statistic_interface pointer
+ * provided by the caller points to a newly alloacted struct.
+ *
+ * If the struct statistic_interface pointer provided by the caller
+ * is not NULL (used), this routine fails, the struct statistic_interface
+ * pointer is not changed, and -EINVAL is returned.
+ *
+ * If some required memory could not be allocated, or the creation
+ * of debugfs entries failed, this routine fails, the struct
+ * statistic_interface pointer is not changed, and -ENOMEM is returned.
+ **/
+int
+statistic_interface_create(
+	struct statistic_interface **interface_ptr,
+	const char *name)
+{
+	struct statistic_interface *interface;
+	int retval;
+
+	if (*interface_ptr)
+		return -EINVAL;
+
+	interface = kmalloc(sizeof(struct statistic_interface), GFP_KERNEL);
+	if (!interface)
+		return -ENOMEM;
+	memset(interface, 0, sizeof(struct statistic_interface));
+	INIT_LIST_HEAD(&interface->statistic_lh);
+	spin_lock_init(&interface->lock);
+
+	down(&statistic_globals.sem);
+
+	interface->debugfs_dir = debugfs_create_dir(
+					name, statistic_globals.root_dir);
+	if (!interface->debugfs_dir) {
+		retval = -ENOMEM;
+		goto failed_dir;
+	}
+
+	interface->data_file = debugfs_create_file(
+					STATISTIC_FILENAME_DATA,
+					S_IFREG | S_IRUSR,
+					interface->debugfs_dir,
+					(void*) interface,
+					&statistic_data_file_ops);
+	if (!interface->data_file) {
+		retval = -ENOMEM;
+		goto failed_data;
+	}
+
+	interface->def_file = debugfs_create_file(
+					STATISTIC_FILENAME_DEF,
+					S_IFREG | S_IRUSR | S_IWUSR,
+					interface->debugfs_dir,
+					(void*) interface,
+					&statistic_def_file_ops);
+	if (!interface->def_file) {
+		retval = -ENOMEM;
+		goto failed_def;
+	}
+
+	list_add_tail(&interface->list, &statistic_globals.interface_lh);
+	*interface_ptr = interface;
+	retval = 0;
+	goto out;
+
+failed_def:
+	debugfs_remove(interface->data_file);
+
+failed_data:
+failed_dir:
+	kfree(interface);
+	interface = NULL;
+
+out:
+	up(&statistic_globals.sem);
+
+	return retval;
+}
+
+/**
+ * statistic_interface_remove - remove debugfs files for statistic
+ * @interface_ptr: reference to struct statistic_interface pointer
+ *
+ * Remove a debugfs directory in "s390stat" along with its "data" and
+ * "definition" files. Removing this user interface also causes the removal
+ * of all statistic attached to the interface.
+ *
+ * On success, 0 is returned and the struct statistic_interface pointer
+ * provided by the caller is set to NULL.
+ *
+ * If the struct statistic_interface pointer provided by the caller
+ * is NULL (unused), this routine fails, the struct statistic_interface
+ * pointer is not changed, and -EINVAL is returned.
+ **/
+int
+statistic_interface_remove(struct statistic_interface **interface_ptr)
+{
+	struct statistic_interface *interface = *interface_ptr;
+	struct statistic *stat, *tmp;
+
+	if (!interface)
+		return -EINVAL;
+
+	down(&statistic_globals.sem);
+
+	list_for_each_entry_safe(stat, tmp, &interface->statistic_lh, list)
+		statistic_remove(stat->stat_ptr);
+
+	debugfs_remove(interface->data_file);
+	debugfs_remove(interface->def_file);
+	debugfs_remove(interface->debugfs_dir);
+
+	list_del(&interface->list);
+	kfree(interface);
+	*interface_ptr = NULL;
+
+	up(&statistic_globals.sem);
+
+	return 0;
+}
+
+static int
+statistic_interface_generic_open(
+		struct inode *inode, struct file *file,
+		struct statistic_interface **interface,
+		struct statistic_file_private **private)
+{
+	*interface = (struct statistic_interface *) inode->u.generic_ip;
+	BUG_ON(!interface);
+
+	*private = kmalloc(sizeof(struct statistic_file_private), GFP_KERNEL);
+	if (!(*private))
+		return -ENOMEM;
+
+	memset(*private, 0, sizeof(struct statistic_file_private));
+	INIT_LIST_HEAD(&(*private)->read_seg_lh);
+	INIT_LIST_HEAD(&(*private)->write_seg_lh);
+	file->private_data = *private;
+	return 0;
+}
+
+static int
+statistic_interface_generic_close(struct inode *inode, struct file *file)
+{
+	struct statistic_file_private *private;
+
+	private = (struct statistic_file_private *) file->private_data;
+	BUG_ON(!private);
+
+	sgrb_seg_release_all(&private->read_seg_lh);
+	sgrb_seg_release_all(&private->write_seg_lh);
+
+	kfree(private);
+	return 0;
+}
+
+static ssize_t
+statistic_interface_generic_read(struct file *file, char __user *buf, size_t len, loff_t *offset)
+{
+	struct statistic_file_private *private;
+	struct sgrb_seg *seg;
+	size_t seg_offset, seg_residual, seg_transfer;
+	size_t transfered = 0;
+	loff_t pos = 0;
+
+	private = (struct statistic_file_private *) file->private_data;
+	BUG_ON(!private);
+
+	list_for_each_entry(seg, &private->read_seg_lh, list) {
+		if (!len)
+			break;
+		if (*offset >= pos  &&
+		    *offset <= (pos + seg->offset)) {
+			seg_offset = *offset - pos;
+			seg_residual = seg->offset - seg_offset;
+			seg_transfer = min(len, seg_residual);
+			if (copy_to_user(buf + transfered,
+					 seg->address + seg_offset,
+					 seg_transfer))
+				return -EFAULT;
+			transfered += seg_transfer;
+			*offset += seg_transfer;
+			pos += seg_transfer + seg_offset;
+			len -= seg_transfer;
+		} else
+			pos += seg->offset;
+	}
+	return transfered;
+}
+
+static ssize_t
+statistic_interface_generic_write(struct file *file, const char __user *buf, size_t len, loff_t *offset)
+{
+	struct statistic_file_private *private;
+	struct sgrb_seg *seg;
+	size_t seg_residual, seg_transfer;
+	size_t transfered = 0;
+
+	private = (struct statistic_file_private *) file->private_data;
+	BUG_ON(!private);
+
+	if (*offset != private->write_seg_total_size)
+		return -EPIPE;
+
+	while (len) {
+		seg = sgrb_seg_find(&private->write_seg_lh, 1, GFP_KERNEL);
+		if (!seg)
+			return -ENOMEM;
+		seg_residual = seg->size - seg->offset;
+		seg_transfer = min(len, seg_residual);
+		if (copy_from_user(seg->address + seg->offset,
+				   buf + transfered,
+				   seg_transfer))
+			return -EFAULT;
+		private->write_seg_total_size += seg_transfer;
+		seg->offset += seg_transfer;
+		transfered += seg_transfer;
+		*offset += seg_transfer;
+		len -= seg_transfer;
+	}
+	return transfered;
+}
+
+static int
+statistic_interface_def_open(struct inode *inode, struct file *file)
+{
+	struct statistic_interface *interface;
+	struct statistic_file_private *private;
+	struct statistic *stat;
+	unsigned long flags;
+	int retval = 0;
+
+	retval = statistic_interface_generic_open(
+			inode, file, &interface, &private);
+	if (retval)
+		return retval;
+
+	spin_lock_irqsave(&interface->lock, flags);
+	list_for_each_entry(stat, &interface->statistic_lh, list) {
+		retval = statistic_format_def(stat, private);
+		if (retval) {
+			statistic_interface_def_close(inode, file);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&interface->lock, flags);
+	return retval;
+}
+
+static int
+statistic_parse_definitions_line(
+		struct statistic_interface *interface, char *def)
+{
+	struct statistic *stat;
+	char * p;
+	substring_t args[MAX_OPT_ARGS];
+	int token, type = 0, scale = 0;
+	u32 entries_max, base_interval;
+	s64 range_min, range_max;
+	u64 period = 0;
+	int mode = 0;
+	char *name = NULL;
+	int retval = 0;
+	unsigned long flags;
+	int got_type = 0, got_scale = 0, got_entries_max = 0,
+	    got_range_min = 0, got_range_max = 0,
+	    got_base_interval = 0, got_period = 0, got_mode = 0, got_reset = 0,
+	    got_on = 0, got_off = 0,redefinition = 0, new_type = 0,
+	    was_on = 0;
+
+	if (!def)
+		return 1;
+
+	while ((p = strsep (&def, " ")) != NULL) {
+		token = match_token(p, statistic_def, args);
+		switch (token) {
+		case STATISTIC_DEF_NAME :
+			if (!name)
+				name = match_strdup(&args[0]);
+			break;
+		case STATISTIC_DEF_TYPE_VALUE :
+		case STATISTIC_DEF_TYPE_RANGE :
+		case STATISTIC_DEF_TYPE_ARRAY :
+		case STATISTIC_DEF_TYPE_LIST :
+		case STATISTIC_DEF_TYPE_RAW :
+		case STATISTIC_DEF_TYPE_HISTORY :
+			type = token;
+			got_type = 1;
+			break;
+		case STATISTIC_DEF_ON :
+			got_on = 1;
+			break;
+		case STATISTIC_DEF_OFF :
+			got_off = 1;
+			break;
+		case STATISTIC_DEF_SCALE_LIN :
+		case STATISTIC_DEF_SCALE_LOG2 :
+			scale = token;
+			got_scale = 1;
+			break;
+		case STATISTIC_DEF_ENTRIESMAX :
+			match_int(&args[0], &entries_max);
+			got_entries_max = 1;
+			break;
+		case STATISTIC_DEF_RANGEMIN :
+			match_s64(&args[0], &range_min, 0);
+			got_range_min = 1;
+			break;
+		case STATISTIC_DEF_RANGEMAX :
+			match_s64(&args[0], &range_max, 0);
+			got_range_max = 1;
+			break;
+		case STATISTIC_DEF_BASEINT :
+			match_int(&args[0], &base_interval);
+			got_base_interval = 1;
+			break;
+		case STATISTIC_DEF_PERIOD :
+			match_u64(&args[0], &period, 0);
+			got_period = 1;
+			break;
+		case STATISTIC_DEF_MODE_INC :
+		case STATISTIC_DEF_MODE_PROD :
+		case STATISTIC_DEF_MODE_RANGE :
+			mode = token;
+			got_mode = 1;
+			break;
+		case STATISTIC_DEF_RESET :
+			got_reset = 1;
+			break;
+		default :
+			break;
+		}
+	}
+
+	redefinition =  got_type | got_mode | got_scale | got_entries_max |
+			got_range_min | got_range_max |
+			got_base_interval | got_period;
+
+	if (!name) {
+		if (redefinition)
+			goto out;
+		spin_lock_irqsave(&interface->lock, flags);
+		if (got_on)
+			list_for_each_entry(stat, &interface->statistic_lh, list)
+				statistic_start_nolock(stat);
+		if (got_off)
+			list_for_each_entry(stat, &interface->statistic_lh, list)
+				statistic_stop_nolock(stat);
+		if (got_reset) {
+			list_for_each_entry(stat, &interface->statistic_lh, list)
+				statistic_reset_nolock(stat);
+		}
+		spin_unlock_irqrestore(&interface->lock, flags);
+		goto out;
+	}
+
+	spin_lock_irqsave(&interface->lock, flags);
+	list_for_each_entry(stat, &interface->statistic_lh, list) {
+		if (!strcmp(stat->name, name))
+			break;
+	}
+	spin_unlock_irqrestore(&interface->lock, flags);
+	if (strcmp(stat->name, name))
+		goto out;
+
+	if (!redefinition) {
+		if (got_on)
+			statistic_start(stat);
+		if (got_off)
+			statistic_stop(stat);
+		if (got_reset)
+			statistic_reset(stat);
+		goto out;
+	}
+
+	if (statistic_stop(stat) == STATISTIC_DEF_ON)
+		was_on = 1;
+
+	if (!got_type)
+		type = stat->type;
+	else if (type != stat->type)
+		new_type = 1;
+
+	if (!got_range_min)
+		range_min = stat->range_min;
+	if (!got_range_max)
+		range_max = stat->range_max;
+
+        switch (type) {
+        case STATISTIC_DEF_TYPE_VALUE :
+		if (new_type && !got_mode) {
+			retval = -EINVAL;
+			break;
+		}
+		if (!got_mode)
+			mode = stat->data.value.mode;
+		retval = statistic_define_value(
+				stat, range_min, range_max, mode);
+		break;
+        case STATISTIC_DEF_TYPE_RANGE :
+		retval = statistic_define_range(
+				stat, range_min, range_max);
+		break;
+        case STATISTIC_DEF_TYPE_ARRAY :
+		if (new_type && (!got_base_interval || !got_scale)) {
+			retval = -EINVAL;
+			break;
+		}
+		if (!got_base_interval)
+			base_interval = stat->data.array.base_interval;
+		if (!got_scale)
+			scale = stat->data.array.scale;
+		retval = statistic_define_array(
+				stat, range_min, range_max, base_interval, scale);
+		break;
+        case STATISTIC_DEF_TYPE_LIST :
+		if (new_type && !got_entries_max) {
+			retval = -EINVAL;
+			break;
+		}
+		if (!got_entries_max)
+			entries_max = stat->data.list.entries_max;
+		retval = statistic_define_list(
+				stat, range_min, range_max, entries_max);
+		break;
+        case STATISTIC_DEF_TYPE_RAW :
+		if (new_type && !got_entries_max) {
+			retval = -EINVAL;
+			break;
+		}
+		if (!got_entries_max)
+			entries_max = stat->data.raw.entries_max;
+		retval = statistic_define_raw(
+				stat, range_min, range_max, entries_max);
+		break;
+        case STATISTIC_DEF_TYPE_HISTORY :
+		if (new_type && (!got_entries_max || !got_period ||
+				 !got_mode)) {
+			retval = -EINVAL;
+			break;
+		}
+		if (!got_entries_max)
+			entries_max = stat->data.history.entries_max;
+		if (!got_period)
+			period = stat->data.history.period;
+		if (!got_mode)
+			mode = stat->data.history.mode;
+		retval = statistic_define_history(
+				stat, range_min, range_max, entries_max,
+				period, mode);
+		break;
+        default :
+                retval = -EINVAL;
+        }
+
+	if (got_on || was_on)
+		statistic_start(stat);
+
+out:
+	kfree(name);
+	return retval;
+}
+
+static void
+statistic_interface_def_close_parse(
+		struct statistic_interface *interface,
+		struct list_head *line_lh, size_t *line_size)
+{
+	struct sgrb_seg *seg, *tmp;
+	char *buf;
+	int offset = 0;
+
+	if (!*line_size)
+		return;
+
+	buf = kmalloc(*line_size + 2, GFP_KERNEL);
+	buf[*line_size] = ' ';
+	buf[*line_size + 1] = '\0';
+	*line_size = 0;
+	if (!buf)
+		return;
+
+	list_for_each_entry_safe(seg, tmp, line_lh, list) {
+		memcpy(buf + offset, seg->address, seg->size);
+		offset += seg->size;
+		list_del(&seg->list);
+		kfree(seg);
+	}
+
+	statistic_parse_definitions_line(interface, buf);
+
+	kfree(buf);
+}
+
+static int
+statistic_interface_def_close(struct inode *inode, struct file *file)
+{
+	struct statistic_interface *interface;
+	struct statistic_file_private *private;
+	struct sgrb_seg *seg, *seg_nl;
+	int offset;
+	struct list_head line_lh;
+	char *nl;
+	size_t line_size = 0;
+
+	INIT_LIST_HEAD(&line_lh);
+	interface = (struct statistic_interface *) inode->u.generic_ip;
+	private = (struct statistic_file_private *) file->private_data;
+
+	list_for_each_entry(seg, &private->write_seg_lh, list) {
+		for (offset = 0; offset < seg->offset; offset += seg_nl->size) {
+			seg_nl = kmalloc(sizeof(struct sgrb_seg),
+					 GFP_KERNEL);
+			seg_nl->address = seg->address + offset;
+			nl = strnchr(seg_nl->address,
+				     seg->offset - offset, '\n');
+			if (nl) {
+				seg_nl->offset = nl - seg_nl->address;
+				if (seg_nl->offset)
+					seg_nl->offset--;
+			} else
+				seg_nl->offset = seg->offset - offset;
+			seg_nl->size = seg_nl->offset + 1;
+			line_size += seg_nl->size;
+			list_add_tail(&seg_nl->list, &line_lh);
+			if (nl)
+				statistic_interface_def_close_parse(
+					interface, &line_lh, &line_size);
+		}
+	}
+	if (!list_empty(&line_lh))
+		statistic_interface_def_close_parse(
+			interface, &line_lh, &line_size);
+
+	return statistic_interface_generic_close(inode, file);
+}
+
+static int
+statistic_interface_data_open(struct inode *inode, struct file *file)
+{
+	struct statistic_interface *interface;
+	struct statistic_file_private *private;
+	struct statistic *stat;
+	unsigned long flags;
+	int retval = 0;
+
+	retval = statistic_interface_generic_open(
+			inode, file, &interface, &private);
+	if (retval)
+		return retval;
+
+	spin_lock_irqsave(&interface->lock, flags);
+	list_for_each_entry(stat, &interface->statistic_lh, list) {
+		if (stat->format_data) {
+			retval = stat->format_data(stat, private);
+			if (retval) {
+				statistic_interface_generic_close(inode, file);
+				break;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&interface->lock, flags);
+
+	return retval;
+}
+
+postcore_initcall(statistic_init);
+module_exit(statistic_exit);
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(statistic_interface_create);
+EXPORT_SYMBOL(statistic_interface_remove);
+EXPORT_SYMBOL(statistic_create);
+EXPORT_SYMBOL(statistic_remove);
+EXPORT_SYMBOL(statistic_define_value);
+EXPORT_SYMBOL(statistic_define_range);
+EXPORT_SYMBOL(statistic_define_array);
+EXPORT_SYMBOL(statistic_define_list);
+EXPORT_SYMBOL(statistic_define_raw);
+EXPORT_SYMBOL(statistic_define_history);
+EXPORT_SYMBOL(statistic_start);
+EXPORT_SYMBOL(statistic_stop);
+EXPORT_SYMBOL(statistic_reset);
diff -urN oldtree/arch/sparc64/kernel/Makefile newtree/arch/sparc64/kernel/Makefile
--- oldtree/arch/sparc64/kernel/Makefile	2006-02-19 11:41:00.070332408 +0000
+++ newtree/arch/sparc64/kernel/Makefile	2006-02-21 15:58:20.173079784 +0000
@@ -14,7 +14,8 @@
 		   power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o
 
 obj-$(CONFIG_PCI)	 += ebus.o isa.o pci_common.o pci_iommu.o \
-			    pci_psycho.o pci_sabre.o pci_schizo.o
+			    pci_psycho.o pci_sabre.o pci_schizo.o \
+			    pci_sun4v.o pci_sun4v_asm.o
 obj-$(CONFIG_SMP)	 += smp.o trampoline.o
 obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o
 obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o
@@ -38,5 +39,5 @@
   CMODEL_CFLAG := -m64 -mcmodel=medlow
 endif
 
-head.o: head.S ttable.S itlb_base.S dtlb_base.S dtlb_backend.S dtlb_prot.S \
+head.o: head.S ttable.S itlb_miss.S dtlb_miss.S ktlb.S tsb.S \
 	etrap.S rtrap.S winfixup.S entry.S
diff -urN oldtree/arch/sparc64/kernel/binfmt_aout32.c newtree/arch/sparc64/kernel/binfmt_aout32.c
--- oldtree/arch/sparc64/kernel/binfmt_aout32.c	2006-02-19 11:41:00.071332256 +0000
+++ newtree/arch/sparc64/kernel/binfmt_aout32.c	2006-02-21 15:58:20.185077960 +0000
@@ -31,6 +31,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
+#include <asm/mmu_context.h>
 
 static int load_aout32_binary(struct linux_binprm *, struct pt_regs * regs);
 static int load_aout32_library(struct file*);
@@ -329,15 +330,8 @@
 
 	current->mm->start_stack =
 		(unsigned long) create_aout32_tables((char __user *)bprm->p, bprm);
-	if (!(orig_thr_flags & _TIF_32BIT)) {
-		unsigned long pgd_cache = get_pgd_cache(current->mm->pgd);
+	tsb_context_switch(mm);
 
-		__asm__ __volatile__("stxa\t%0, [%1] %2\n\t"
-				     "membar #Sync"
-				     : /* no outputs */
-				     : "r" (pgd_cache),
-				       "r" (TSB_REG), "i" (ASI_DMMU));
-	}
 	start_thread32(regs, ex.a_entry, current->mm->start_stack);
 	if (current->ptrace & PT_PTRACED)
 		send_sig(SIGTRAP, current, 0);
diff -urN oldtree/arch/sparc64/kernel/cpu.c newtree/arch/sparc64/kernel/cpu.c
--- oldtree/arch/sparc64/kernel/cpu.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/kernel/cpu.c	2006-02-21 15:58:20.185077960 +0000
@@ -13,6 +13,7 @@
 #include <asm/system.h>
 #include <asm/fpumacro.h>
 #include <asm/cpudata.h>
+#include <asm/spitfire.h>
 
 DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };
 
@@ -71,6 +72,12 @@
 	unsigned long ver, fpu_vers, manuf, impl, fprs;
 	int i;
 	
+	if (tlb_type == hypervisor) {
+		sparc_cpu_type = "UltraSparc T1 (Niagara)";
+		sparc_fpu_type = "UltraSparc T1 integrated FPU";
+		return;
+	}
+
 	fprs = fprs_read();
 	fprs_write(FPRS_FEF);
 	__asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]"
diff -urN oldtree/arch/sparc64/kernel/devices.c newtree/arch/sparc64/kernel/devices.c
--- oldtree/arch/sparc64/kernel/devices.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/kernel/devices.c	2006-02-21 15:58:20.186077808 +0000
@@ -12,6 +12,7 @@
 #include <linux/string.h>
 #include <linux/spinlock.h>
 #include <linux/errno.h>
+#include <linux/bootmem.h>
 
 #include <asm/page.h>
 #include <asm/oplib.h>
@@ -20,6 +21,8 @@
 #include <asm/spitfire.h>
 #include <asm/timer.h>
 #include <asm/cpudata.h>
+#include <asm/vdev.h>
+#include <asm/irq.h>
 
 /* Used to synchronize acceses to NatSemi SUPER I/O chip configure
  * operations in asm/ns87303.h
@@ -29,13 +32,158 @@
 extern void cpu_probe(void);
 extern void central_probe(void);
 
-static char *cpu_mid_prop(void)
+u32 sun4v_vdev_devhandle;
+int sun4v_vdev_root;
+
+struct vdev_intmap {
+	unsigned int phys;
+	unsigned int irq;
+	unsigned int cnode;
+	unsigned int cinterrupt;
+};
+
+struct vdev_intmask {
+	unsigned int phys;
+	unsigned int interrupt;
+	unsigned int __unused;
+};
+
+static struct vdev_intmap *vdev_intmap;
+static int vdev_num_intmap;
+static struct vdev_intmask vdev_intmask;
+
+static void __init sun4v_virtual_device_probe(void)
+{
+	struct linux_prom64_registers regs;
+	struct vdev_intmap *ip;
+	int node, sz, err;
+
+	if (tlb_type != hypervisor)
+		return;
+
+	node = prom_getchild(prom_root_node);
+	node = prom_searchsiblings(node, "virtual-devices");
+	if (!node) {
+		prom_printf("SUN4V: Fatal error, no virtual-devices node.\n");
+		prom_halt();
+	}
+
+	sun4v_vdev_root = node;
+
+	prom_getproperty(node, "reg", (char *)&regs, sizeof(regs));
+	sun4v_vdev_devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff;
+
+	sz = prom_getproplen(node, "interrupt-map");
+	if (sz <= 0) {
+		prom_printf("SUN4V: Error, no vdev interrupt-map.\n");
+		prom_halt();
+	}
+
+	if ((sz % sizeof(*ip)) != 0) {
+		prom_printf("SUN4V: Bogus interrupt-map property size %d\n",
+			    sz);
+		prom_halt();
+	}
+
+	vdev_intmap = ip = alloc_bootmem_low_pages(sz);
+	if (!vdev_intmap) {
+		prom_printf("SUN4V: Error, cannot allocate vdev_intmap.\n");
+		prom_halt();
+	}
+
+	err = prom_getproperty(node, "interrupt-map", (char *) ip, sz);
+	if (err == -1) {
+		prom_printf("SUN4V: Fatal error, no vdev interrupt-map.\n");
+		prom_halt();
+	}
+	if (err != sz) {
+		prom_printf("SUN4V: Inconsistent interrupt-map size, "
+			    "proplen(%d) vs getprop(%d).\n", sz,err);
+		prom_halt();
+	}
+
+	vdev_num_intmap = err / sizeof(*ip);
+
+	err = prom_getproperty(node, "interrupt-map-mask",
+			       (char *) &vdev_intmask,
+			       sizeof(vdev_intmask));
+	if (err <= 0) {
+		prom_printf("SUN4V: Fatal error, no vdev "
+			    "interrupt-map-mask.\n");
+		prom_halt();
+	}
+	if (err % sizeof(vdev_intmask)) {
+		prom_printf("SUN4V: Bogus interrupt-map-mask "
+			    "property size %d\n", err);
+		prom_halt();
+	}
+
+	printk("SUN4V: virtual-devices devhandle[%x]\n",
+	       sun4v_vdev_devhandle);
+}
+
+unsigned int sun4v_vdev_device_interrupt(unsigned int dev_node)
+{
+	unsigned int irq, reg;
+	int err, i;
+
+	err = prom_getproperty(dev_node, "interrupts",
+			       (char *) &irq, sizeof(irq));
+	if (err <= 0) {
+		printk("VDEV: Cannot get \"interrupts\" "
+		       "property for OBP node %x\n", dev_node);
+		return 0;
+	}
+
+	err = prom_getproperty(dev_node, "reg",
+			       (char *) &reg, sizeof(reg));
+	if (err <= 0) {
+		printk("VDEV: Cannot get \"reg\" "
+		       "property for OBP node %x\n", dev_node);
+		return 0;
+	}
+
+	for (i = 0; i < vdev_num_intmap; i++) {
+		if (vdev_intmap[i].phys == (reg & vdev_intmask.phys) &&
+		    vdev_intmap[i].irq == (irq & vdev_intmask.interrupt)) {
+			irq = vdev_intmap[i].cinterrupt;
+			break;
+		}
+	}
+
+	if (i == vdev_num_intmap) {
+		printk("VDEV: No matching interrupt map entry "
+		       "for OBP node %x\n", dev_node);
+		return 0;
+	}
+
+	return sun4v_build_irq(sun4v_vdev_devhandle, irq, 4, 0);
+}
+
+static const char *cpu_mid_prop(void)
 {
 	if (tlb_type == spitfire)
 		return "upa-portid";
 	return "portid";
 }
 
+static int get_cpu_mid(int prom_node)
+{
+	if (tlb_type == hypervisor) {
+		struct linux_prom64_registers reg;
+
+		if (prom_getproplen(prom_node, "cpuid") == 4)
+			return prom_getintdefault(prom_node, "cpuid", 0);
+
+		prom_getproperty(prom_node, "reg", (char *) &reg, sizeof(reg));
+		return (reg.phys_addr >> 32) & 0x0fffffffUL;
+	} else {
+		const char *prop_name = cpu_mid_prop();
+
+		return prom_getintdefault(prom_node, prop_name, 0);
+	}
+}
+
 static int check_cpu_node(int nd, int *cur_inst,
 			  int (*compare)(int, int, void *), void *compare_arg,
 			  int *prom_node, int *mid)
@@ -50,7 +198,7 @@
 		if (prom_node)
 			*prom_node = nd;
 		if (mid)
-			*mid = prom_getintdefault(nd, cpu_mid_prop(), 0);
+			*mid = get_cpu_mid(nd);
 		return 0;
 	}
 
@@ -105,7 +253,7 @@
 	int desired_mid = (int) (long) _arg;
 	int this_mid;
 
-	this_mid = prom_getintdefault(nd, cpu_mid_prop(), 0);
+	this_mid = get_cpu_mid(nd);
 	if (this_mid == desired_mid)
 		return 0;
 	return -ENODEV;
@@ -126,7 +274,8 @@
 
 #ifndef CONFIG_SMP
 	{
-		int err, cpu_node;
+		int err, cpu_node, def;
+
 		err = cpu_find_by_instance(0, &cpu_node, NULL);
 		if (err) {
 			prom_printf("No cpu nodes, cannot continue\n");
@@ -135,21 +284,40 @@
 		cpu_data(0).clock_tick = prom_getintdefault(cpu_node,
 							    "clock-frequency",
 							    0);
+
+		def = ((tlb_type == hypervisor) ?
+		       (8 * 1024) :
+		       (16 * 1024));
 		cpu_data(0).dcache_size = prom_getintdefault(cpu_node,
 							     "dcache-size",
-							     16 * 1024);
+							     def);
+
+		def = 32;
 		cpu_data(0).dcache_line_size =
-			prom_getintdefault(cpu_node, "dcache-line-size", 32);
+			prom_getintdefault(cpu_node, "dcache-line-size",
+					   def);
+
+		def = 16 * 1024;
 		cpu_data(0).icache_size = prom_getintdefault(cpu_node,
 							     "icache-size",
-							     16 * 1024);
+							     def);
+
+		def = 32;
 		cpu_data(0).icache_line_size =
-			prom_getintdefault(cpu_node, "icache-line-size", 32);
+			prom_getintdefault(cpu_node, "icache-line-size",
+					   def);
+
+		def = ((tlb_type == hypervisor) ?
+		       (3 * 1024 * 1024) :
+		       (4 * 1024 * 1024));
 		cpu_data(0).ecache_size = prom_getintdefault(cpu_node,
 							     "ecache-size",
-							     4 * 1024 * 1024);
+							     def);
+
+		def = 64;
 		cpu_data(0).ecache_line_size =
-			prom_getintdefault(cpu_node, "ecache-line-size", 64);
+			prom_getintdefault(cpu_node, "ecache-line-size",
+					   def);
 		printk("CPU[0]: Caches "
 		       "D[sz(%d):line_sz(%d)] "
 		       "I[sz(%d):line_sz(%d)] "
@@ -160,6 +328,7 @@
 	}
 #endif
 
+	sun4v_virtual_device_probe();
 	central_probe();
 
 	cpu_probe();
diff -urN oldtree/arch/sparc64/kernel/dtlb_backend.S newtree/arch/sparc64/kernel/dtlb_backend.S
--- oldtree/arch/sparc64/kernel/dtlb_backend.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/kernel/dtlb_backend.S	1970-01-01 00:00:00.000000000 +0000
@@ -1,170 +0,0 @@
-/* $Id: dtlb_backend.S,v 1.16 2001/10/09 04:02:11 davem Exp $
- * dtlb_backend.S: Back end to DTLB miss replacement strategy.
- *                 This is included directly into the trap table.
- *
- * Copyright (C) 1996,1998 David S. Miller (davem@redhat.com)
- * Copyright (C) 1997,1998 Jakub Jelinek   (jj@ultra.linux.cz)
- */
-
-#include <asm/pgtable.h>
-#include <asm/mmu.h>
-
-#define VALID_SZ_BITS	(_PAGE_VALID | _PAGE_SZBITS)
-
-#define VPTE_BITS		(_PAGE_CP | _PAGE_CV | _PAGE_P )
-#define VPTE_SHIFT		(PAGE_SHIFT - 3)
-
-/* Ways we can get here:
- *
- * 1) Nucleus loads and stores to/from PA-->VA direct mappings at tl>1.
- * 2) Nucleus loads and stores to/from user/kernel window save areas.
- * 3) VPTE misses from dtlb_base and itlb_base.
- *
- * We need to extract out the PMD and PGDIR indexes from the
- * linear virtual page table access address.  The PTE index
- * is at the bottom, but we are not concerned with it.  Bits
- * 0 to 2 are clear since each PTE is 8 bytes in size.  Each
- * PMD and PGDIR entry are 4 bytes in size.   Thus, this
- * address looks something like:
- *
- * |---------------------------------------------------------------|
- * |  ...   |    PGDIR index    |    PMD index    | PTE index  |   |
- * |---------------------------------------------------------------|
- *   63   F   E               D   C             B   A         3 2 0  <- bit nr
- *
- *  The variable bits above are defined as:
- *  A --> 3 + (PAGE_SHIFT - log2(8))
- *    --> 3 + (PAGE_SHIFT - 3) - 1
- *        (ie. this is "bit 3" + PAGE_SIZE - size of PTE entry in bits - 1)
- *  B --> A + 1
- *  C --> B + (PAGE_SHIFT - log2(4))
- *    -->  B + (PAGE_SHIFT - 2) - 1
- *        (ie. this is "bit B" + PAGE_SIZE - size of PMD entry in bits - 1)
- *  D --> C + 1
- *  E --> D + (PAGE_SHIFT - log2(4))
- *    --> D + (PAGE_SHIFT - 2) - 1
- *        (ie. this is "bit D" + PAGE_SIZE - size of PGDIR entry in bits - 1)
- *  F --> E + 1
- *
- * (Note how "B" always evalutes to PAGE_SHIFT, all the other constants
- *  cancel out.)
- *
- * For 8K PAGE_SIZE (thus, PAGE_SHIFT of 13) the bit numbers are:
- * A --> 12
- * B --> 13
- * C --> 23
- * D --> 24
- * E --> 34
- * F --> 35
- *
- * For 64K PAGE_SIZE (thus, PAGE_SHIFT of 16) the bit numbers are:
- * A --> 15
- * B --> 16
- * C --> 29
- * D --> 30
- * E --> 43
- * F --> 44
- *
- * Because bits both above and below each PGDIR and PMD index need to
- * be masked out, and the index can be as long as 14 bits (when using a
- * 64K PAGE_SIZE, and thus a PAGE_SHIFT of 16), we need 3 instructions
- * to extract each index out.
- *
- * Shifts do not pair very well on UltraSPARC-I, II, IIi, and IIe, so
- * we try to avoid using them for the entire operation.  We could setup
- * a mask anywhere from bit 31 down to bit 10 using the sethi instruction.
- *
- * We need a mask covering bits B --> C and one covering D --> E.
- * For 8K PAGE_SIZE these masks are 0x00ffe000 and 0x7ff000000.
- * For 64K PAGE_SIZE these masks are 0x3fff0000 and 0xfffc0000000.
- * The second in each set cannot be loaded with a single sethi
- * instruction, because the upper bits are past bit 32.  We would
- * need to use a sethi + a shift.
- *
- * For the time being, we use 2 shifts and a simple "and" mask.
- * We shift left to clear the bits above the index, we shift down
- * to clear the bits below the index (sans the log2(4 or 8) bits)
- * and a mask to clear the log2(4 or 8) bits.  We need therefore
- * define 4 shift counts, all of which are relative to PAGE_SHIFT.
- *
- * Although unsupportable for other reasons, this does mean that
- * 512K and 4MB page sizes would be generaally supported by the
- * kernel.  (ELF binaries would break with > 64K PAGE_SIZE since
- * the sections are only aligned that strongly).
- *
- * The operations performed for extraction are thus:
- *
- *      ((X << FOO_SHIFT_LEFT) >> FOO_SHIFT_RIGHT) & ~0x3
- *
- */
-
-#define A (3 + (PAGE_SHIFT - 3) - 1)
-#define B (A + 1)
-#define C (B + (PAGE_SHIFT - 2) - 1)
-#define D (C + 1)
-#define E (D + (PAGE_SHIFT - 2) - 1)
-#define F (E + 1)
-
-#define PMD_SHIFT_LEFT		(64 - D)
-#define PMD_SHIFT_RIGHT		(64 - (D - B) - 2)
-#define PGDIR_SHIFT_LEFT 	(64 - F)
-#define PGDIR_SHIFT_RIGHT	(64 - (F - D) - 2)
-#define LOW_MASK_BITS		0x3
-
-/* TLB1 ** ICACHE line 1: tl1 DTLB and quick VPTE miss	*/
-	ldxa		[%g1 + %g1] ASI_DMMU, %g4	! Get TAG_ACCESS
-	add		%g3, %g3, %g5			! Compute VPTE base
-	cmp		%g4, %g5			! VPTE miss?
-	bgeu,pt		%xcc, 1f			! Continue here
-	 andcc		%g4, TAG_CONTEXT_BITS, %g5	! tl0 miss Nucleus test
-	ba,a,pt		%xcc, from_tl1_trap		! Fall to tl0 miss
-1:	sllx		%g6, VPTE_SHIFT, %g4		! Position TAG_ACCESS
-	or		%g4, %g5, %g4			! Prepare TAG_ACCESS
-
-/* TLB1 ** ICACHE line 2: Quick VPTE miss	  	*/
-	mov		TSB_REG, %g1			! Grab TSB reg
-	ldxa		[%g1] ASI_DMMU, %g5		! Doing PGD caching?
-	sllx		%g6, PMD_SHIFT_LEFT, %g1	! Position PMD offset
-	be,pn		%xcc, sparc64_vpte_nucleus	! Is it from Nucleus?
-	 srlx		%g1, PMD_SHIFT_RIGHT, %g1	! Mask PMD offset bits
-	brnz,pt		%g5, sparc64_vpte_continue	! Yep, go like smoke
-	 andn		%g1, LOW_MASK_BITS, %g1		! Final PMD mask
-	sllx		%g6, PGDIR_SHIFT_LEFT, %g5	! Position PGD offset
-
-/* TLB1 ** ICACHE line 3: Quick VPTE miss	  	*/
-	srlx		%g5, PGDIR_SHIFT_RIGHT, %g5	! Mask PGD offset bits
-	andn		%g5, LOW_MASK_BITS, %g5		! Final PGD mask
-	lduwa		[%g7 + %g5] ASI_PHYS_USE_EC, %g5! Load PGD
-	brz,pn		%g5, vpte_noent			! Valid?
-sparc64_kpte_continue:
-	 sllx		%g5, 11, %g5			! Shift into place
-sparc64_vpte_continue:
-	lduwa		[%g5 + %g1] ASI_PHYS_USE_EC, %g5! Load PMD
-	sllx		%g5, 11, %g5			! Shift into place
-	brz,pn		%g5, vpte_noent			! Valid?
-
-/* TLB1 ** ICACHE line 4: Quick VPTE miss	  	*/
-	 mov		(VALID_SZ_BITS >> 61), %g1	! upper vpte into %g1
-	sllx		%g1, 61, %g1			! finish calc
-	or		%g5, VPTE_BITS, %g5		! Prepare VPTE data
-	or		%g5, %g1, %g5			! ...
-	mov		TLB_SFSR, %g1			! Restore %g1 value
-	stxa		%g5, [%g0] ASI_DTLB_DATA_IN	! Load VPTE into TLB
-	stxa		%g4, [%g1 + %g1] ASI_DMMU	! Restore previous TAG_ACCESS
-	retry						! Load PTE once again
-
-#undef VALID_SZ_BITS
-#undef VPTE_SHIFT
-#undef VPTE_BITS
-#undef A
-#undef B
-#undef C
-#undef D
-#undef E
-#undef F
-#undef PMD_SHIFT_LEFT
-#undef PMD_SHIFT_RIGHT
-#undef PGDIR_SHIFT_LEFT
-#undef PGDIR_SHIFT_RIGHT
-#undef LOW_MASK_BITS
-
diff -urN oldtree/arch/sparc64/kernel/dtlb_base.S newtree/arch/sparc64/kernel/dtlb_base.S
--- oldtree/arch/sparc64/kernel/dtlb_base.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/kernel/dtlb_base.S	1970-01-01 00:00:00.000000000 +0000
@@ -1,109 +0,0 @@
-/* $Id: dtlb_base.S,v 1.17 2001/10/11 22:33:52 davem Exp $
- * dtlb_base.S:	Front end to DTLB miss replacement strategy.
- *              This is included directly into the trap table.
- *
- * Copyright (C) 1996,1998 David S. Miller (davem@redhat.com)
- * Copyright (C) 1997,1998 Jakub Jelinek   (jj@ultra.linux.cz)
- */
-
-#include <asm/pgtable.h>
-#include <asm/mmu.h>
-
-/* %g1	TLB_SFSR	(%g1 + %g1 == TLB_TAG_ACCESS)
- * %g2	(KERN_HIGHBITS | KERN_LOWBITS)
- * %g3  VPTE base	(0xfffffffe00000000)	Spitfire/Blackbird (44-bit VA space)
- *			(0xffe0000000000000)	Cheetah		   (64-bit VA space)
- * %g7	__pa(current->mm->pgd)
- *
- * The VPTE base value is completely magic, but note that
- * few places in the kernel other than these TLB miss
- * handlers know anything about the VPTE mechanism or
- * how it works (see VPTE_SIZE, TASK_SIZE and PTRS_PER_PGD).
- * Consider the 44-bit VADDR Ultra-I/II case as an example:
- *
- * VA[0 :  (1<<43)] produce VPTE index [%g3                        :   0]
- * VA[0 : -(1<<43)] produce VPTE index [%g3-(1<<(43-PAGE_SHIFT+3)) : %g3]
- *
- * For Cheetah's 64-bit VADDR space this is:
- *
- * VA[0 :  (1<<63)] produce VPTE index [%g3                        :   0]
- * VA[0 : -(1<<63)] produce VPTE index [%g3-(1<<(63-PAGE_SHIFT+3)) : %g3]
- *
- * If you're paying attention you'll notice that this means half of
- * the VPTE table is above %g3 and half is below, low VA addresses
- * map progressively upwards from %g3, and high VA addresses map
- * progressively upwards towards %g3.  This trick was needed to make
- * the same 8 instruction handler work both for Spitfire/Blackbird's
- * peculiar VA space hole configuration and the full 64-bit VA space
- * one of Cheetah at the same time.
- */
-
-/* Ways we can get here:
- *
- * 1) Nucleus loads and stores to/from PA-->VA direct mappings.
- * 2) Nucleus loads and stores to/from vmalloc() areas.
- * 3) User loads and stores.
- * 4) User space accesses by nucleus at tl0
- */
-
-#if PAGE_SHIFT == 13
-/*
- * To compute vpte offset, we need to do ((addr >> 13) << 3),
- * which can be optimized to (addr >> 10) if bits 10/11/12 can
- * be guaranteed to be 0 ... mmu_context.h does guarantee this
- * by only using 10 bits in the hwcontext value.
- */
-#define CREATE_VPTE_OFFSET1(r1, r2) nop
-#define CREATE_VPTE_OFFSET2(r1, r2) \
-				srax	r1, 10, r2
-#else
-#define CREATE_VPTE_OFFSET1(r1, r2) \
-				srax	r1, PAGE_SHIFT, r2
-#define CREATE_VPTE_OFFSET2(r1, r2) \
-				sllx	r2, 3, r2
-#endif
-
-/* DTLB ** ICACHE line 1: Quick user TLB misses		*/
-	mov		TLB_SFSR, %g1
-	ldxa		[%g1 + %g1] ASI_DMMU, %g4	! Get TAG_ACCESS
-	andcc		%g4, TAG_CONTEXT_BITS, %g0	! From Nucleus?
-from_tl1_trap:
-	rdpr		%tl, %g5			! For TL==3 test
-	CREATE_VPTE_OFFSET1(%g4, %g6)			! Create VPTE offset
-	be,pn		%xcc, kvmap			! Yep, special processing
-	 CREATE_VPTE_OFFSET2(%g4, %g6)			! Create VPTE offset
-	cmp		%g5, 4				! Last trap level?
-
-/* DTLB ** ICACHE line 2: User finish + quick kernel TLB misses	*/
-	be,pn		%xcc, longpath			! Yep, cannot risk VPTE miss
-	 nop						! delay slot
-	ldxa		[%g3 + %g6] ASI_S, %g5		! Load VPTE
-1:	brgez,pn	%g5, longpath			! Invalid, branch out
-	 nop						! Delay-slot
-9:	stxa		%g5, [%g0] ASI_DTLB_DATA_IN	! Reload TLB
-	retry						! Trap return
-	nop
-
-/* DTLB ** ICACHE line 3: winfixups+real_faults		*/
-longpath:
-	rdpr		%pstate, %g5			! Move into alternate globals
-	wrpr		%g5, PSTATE_AG|PSTATE_MG, %pstate
-	rdpr		%tl, %g4			! See where we came from.
-	cmp		%g4, 1				! Is etrap/rtrap window fault?
-	mov		TLB_TAG_ACCESS, %g4		! Prepare for fault processing
-	ldxa		[%g4] ASI_DMMU, %g5		! Load faulting VA page
-	be,pt		%xcc, sparc64_realfault_common	! Jump to normal fault handling
-	 mov		FAULT_CODE_DTLB, %g4		! It was read from DTLB
-
-/* DTLB ** ICACHE line 4: Unused...	*/
-	ba,a,pt		%xcc, winfix_trampoline		! Call window fixup code
-	nop
-	nop
-	nop
-	nop
-	nop
-	nop
-	nop
-
-#undef CREATE_VPTE_OFFSET1
-#undef CREATE_VPTE_OFFSET2
diff -urN oldtree/arch/sparc64/kernel/dtlb_miss.S newtree/arch/sparc64/kernel/dtlb_miss.S
--- oldtree/arch/sparc64/kernel/dtlb_miss.S	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/sparc64/kernel/dtlb_miss.S	2006-02-21 15:58:20.197076136 +0000
@@ -0,0 +1,39 @@
+/* DTLB ** ICACHE line 1: Context 0 check and TSB load	*/
+	ldxa	[%g0] ASI_DMMU_TSB_8KB_PTR, %g1	! Get TSB 8K pointer
+	ldxa	[%g0] ASI_DMMU, %g6		! Get TAG TARGET
+	srlx	%g6, 48, %g5			! Get context
+	sllx	%g6, 22, %g6			! Zero out context
+	brz,pn	%g5, kvmap_dtlb			! Context 0 processing
+	 srlx	%g6, 22, %g6			! Delay slot
+	TSB_LOAD_QUAD(%g1, %g4)			! Load TSB entry
+	cmp	%g4, %g6			! Compare TAG
+
+/* DTLB ** ICACHE line 2: TSB compare and TLB load	*/
+	bne,pn	%xcc, tsb_miss_dtlb		! Miss
+	 mov	FAULT_CODE_DTLB, %g3
+	stxa	%g5, [%g0] ASI_DTLB_DATA_IN	! Load TLB
+	retry					! Trap done
+	nop
+	nop
+	nop
+	nop
+
+/* DTLB ** ICACHE line 3:				*/
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+/* DTLB ** ICACHE line 4: 				*/
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
diff -urN oldtree/arch/sparc64/kernel/entry.S newtree/arch/sparc64/kernel/entry.S
--- oldtree/arch/sparc64/kernel/entry.S	2006-02-19 11:41:00.072332104 +0000
+++ newtree/arch/sparc64/kernel/entry.S	2006-02-21 15:58:20.198075984 +0000
@@ -50,7 +50,8 @@
 	add		%g0, %g0, %g0
 	ba,a,pt		%xcc, rtrap_clr_l6
 
-1:	ldub		[%g6 + TI_FPSAVED], %g5
+1:	TRAP_LOAD_THREAD_REG(%g6, %g1)
+	ldub		[%g6 + TI_FPSAVED], %g5
 	wr		%g0, FPRS_FEF, %fprs
 	andcc		%g5, FPRS_FEF, %g0
 	be,a,pt		%icc, 1f
@@ -96,10 +97,22 @@
 	add		%g6, TI_FPREGS + 0x80, %g1
 	faddd		%f0, %f2, %f4
 	fmuld		%f0, %f2, %f6
-	ldxa		[%g3] ASI_DMMU, %g5
+
+661:	ldxa		[%g3] ASI_DMMU, %g5
+	.section	.sun4v_1insn_patch, "ax"
+	.word		661b
+	ldxa		[%g3] ASI_MMU, %g5
+	.previous
+
 	sethi		%hi(sparc64_kern_sec_context), %g2
 	ldx		[%g2 + %lo(sparc64_kern_sec_context)], %g2
-	stxa		%g2, [%g3] ASI_DMMU
+
+661:	stxa		%g2, [%g3] ASI_DMMU
+	.section	.sun4v_1insn_patch, "ax"
+	.word		661b
+	stxa		%g2, [%g3] ASI_MMU
+	.previous
+
 	membar		#Sync
 	add		%g6, TI_FPREGS + 0xc0, %g2
 	faddd		%f0, %f2, %f8
@@ -125,11 +138,23 @@
 	 fzero		%f32
 	mov		SECONDARY_CONTEXT, %g3
 	fzero		%f34
-	ldxa		[%g3] ASI_DMMU, %g5
+
+661:	ldxa		[%g3] ASI_DMMU, %g5
+	.section	.sun4v_1insn_patch, "ax"
+	.word		661b
+	ldxa		[%g3] ASI_MMU, %g5
+	.previous
+
 	add		%g6, TI_FPREGS, %g1
 	sethi		%hi(sparc64_kern_sec_context), %g2
 	ldx		[%g2 + %lo(sparc64_kern_sec_context)], %g2
-	stxa		%g2, [%g3] ASI_DMMU
+
+661:	stxa		%g2, [%g3] ASI_DMMU
+	.section	.sun4v_1insn_patch, "ax"
+	.word		661b
+	stxa		%g2, [%g3] ASI_MMU
+	.previous
+
 	membar		#Sync
 	add		%g6, TI_FPREGS + 0x40, %g2
 	faddd		%f32, %f34, %f36
@@ -154,10 +179,22 @@
 	 nop
 3:	mov		SECONDARY_CONTEXT, %g3
 	add		%g6, TI_FPREGS, %g1
-	ldxa		[%g3] ASI_DMMU, %g5
+
+661:	ldxa		[%g3] ASI_DMMU, %g5
+	.section	.sun4v_1insn_patch, "ax"
+	.word		661b
+	ldxa		[%g3] ASI_MMU, %g5
+	.previous
+
 	sethi		%hi(sparc64_kern_sec_context), %g2
 	ldx		[%g2 + %lo(sparc64_kern_sec_context)], %g2
-	stxa		%g2, [%g3] ASI_DMMU
+
+661:	stxa		%g2, [%g3] ASI_DMMU
+	.section	.sun4v_1insn_patch, "ax"
+	.word		661b
+	stxa		%g2, [%g3] ASI_MMU
+	.previous
+
 	membar		#Sync
 	mov		0x40, %g2
 	membar		#Sync
@@ -168,7 +205,13 @@
 	ldda		[%g1 + %g2] ASI_BLK_S, %f48
 	membar		#Sync
 fpdis_exit:
-	stxa		%g5, [%g3] ASI_DMMU
+
+661:	stxa		%g5, [%g3] ASI_DMMU
+	.section	.sun4v_1insn_patch, "ax"
+	.word		661b
+	stxa		%g5, [%g3] ASI_MMU
+	.previous
+
 	membar		#Sync
 fpdis_exit2:
 	wr		%g7, 0, %gsr
@@ -189,6 +232,7 @@
 	.globl		do_fpother_check_fitos
 	.align		32
 do_fpother_check_fitos:
+	TRAP_LOAD_THREAD_REG(%g6, %g1)
 	sethi		%hi(fp_other_bounce - 4), %g7
 	or		%g7, %lo(fp_other_bounce - 4), %g7
 
@@ -312,6 +356,7 @@
 	.globl		do_fptrap
 	.align		32
 do_fptrap:
+	TRAP_LOAD_THREAD_REG(%g6, %g1)
 	stx		%fsr, [%g6 + TI_XFSR]
 do_fptrap_after_fsr:
 	ldub		[%g6 + TI_FPSAVED], %g3
@@ -321,10 +366,22 @@
 	rd		%gsr, %g3
 	stx		%g3, [%g6 + TI_GSR]
 	mov		SECONDARY_CONTEXT, %g3
-	ldxa		[%g3] ASI_DMMU, %g5
+
+661:	ldxa		[%g3] ASI_DMMU, %g5
+	.section	.sun4v_1insn_patch, "ax"
+	.word		661b
+	ldxa		[%g3] ASI_MMU, %g5
+	.previous
+
 	sethi		%hi(sparc64_kern_sec_context), %g2
 	ldx		[%g2 + %lo(sparc64_kern_sec_context)], %g2
-	stxa		%g2, [%g3] ASI_DMMU
+
+661:	stxa		%g2, [%g3] ASI_DMMU
+	.section	.sun4v_1insn_patch, "ax"
+	.word		661b
+	stxa		%g2, [%g3] ASI_MMU
+	.previous
+
 	membar		#Sync
 	add		%g6, TI_FPREGS, %g2
 	andcc		%g1, FPRS_DL, %g0
@@ -339,7 +396,13 @@
 	stda		%f48, [%g2 + %g3] ASI_BLK_S
 5:	mov		SECONDARY_CONTEXT, %g1
 	membar		#Sync
-	stxa		%g5, [%g1] ASI_DMMU
+
+661:	stxa		%g5, [%g1] ASI_DMMU
+	.section	.sun4v_1insn_patch, "ax"
+	.word		661b
+	stxa		%g5, [%g1] ASI_MMU
+	.previous
+
 	membar		#Sync
 	ba,pt		%xcc, etrap
 	 wr		%g0, 0, %fprs
@@ -353,8 +416,6 @@
 	 *
 	 * With this method we can do most of the cross-call tlb/cache
 	 * flushing very quickly.
-	 *
-	 * Current CPU's IRQ worklist table is locked into %g6, don't touch.
 	 */
 	.text
 	.align		32
@@ -378,6 +439,8 @@
 	sllx		%g2, %g4, %g2
 	sllx		%g4, 2, %g4
 
+	TRAP_LOAD_IRQ_WORK(%g6, %g1)
+
 	lduw		[%g6 + %g4], %g5	/* g5 = irq_work(cpu, pil) */
 	stw		%g5, [%g3 + 0x00]	/* bucket->irq_chain = g5 */
 	stw		%g3, [%g6 + %g4]	/* irq_work(cpu, pil) = bucket */
@@ -399,76 +462,6 @@
 1:	jmpl		%g3, %g0
 	 nop
 
-	.globl		save_alternate_globals
-save_alternate_globals: /* %o0 = save_area */
-	rdpr		%pstate, %o5
-	andn		%o5, PSTATE_IE, %o1
-	wrpr		%o1, PSTATE_AG, %pstate
-	stx		%g0, [%o0 + 0x00]
-	stx		%g1, [%o0 + 0x08]
-	stx		%g2, [%o0 + 0x10]
-	stx		%g3, [%o0 + 0x18]
-	stx		%g4, [%o0 + 0x20]
-	stx		%g5, [%o0 + 0x28]
-	stx		%g6, [%o0 + 0x30]
-	stx		%g7, [%o0 + 0x38]
-	wrpr		%o1, PSTATE_IG, %pstate
-	stx		%g0, [%o0 + 0x40]
-	stx		%g1, [%o0 + 0x48]
-	stx		%g2, [%o0 + 0x50]
-	stx		%g3, [%o0 + 0x58]
-	stx		%g4, [%o0 + 0x60]
-	stx		%g5, [%o0 + 0x68]
-	stx		%g6, [%o0 + 0x70]
-	stx		%g7, [%o0 + 0x78]
-	wrpr		%o1, PSTATE_MG, %pstate
-	stx		%g0, [%o0 + 0x80]
-	stx		%g1, [%o0 + 0x88]
-	stx		%g2, [%o0 + 0x90]
-	stx		%g3, [%o0 + 0x98]
-	stx		%g4, [%o0 + 0xa0]
-	stx		%g5, [%o0 + 0xa8]
-	stx		%g6, [%o0 + 0xb0]
-	stx		%g7, [%o0 + 0xb8]
-	wrpr		%o5, 0x0, %pstate
-	retl
-	 nop
-
-	.globl		restore_alternate_globals
-restore_alternate_globals: /* %o0 = save_area */
-	rdpr		%pstate, %o5
-	andn		%o5, PSTATE_IE, %o1
-	wrpr		%o1, PSTATE_AG, %pstate
-	ldx		[%o0 + 0x00], %g0
-	ldx		[%o0 + 0x08], %g1
-	ldx		[%o0 + 0x10], %g2
-	ldx		[%o0 + 0x18], %g3
-	ldx		[%o0 + 0x20], %g4
-	ldx		[%o0 + 0x28], %g5
-	ldx		[%o0 + 0x30], %g6
-	ldx		[%o0 + 0x38], %g7
-	wrpr		%o1, PSTATE_IG, %pstate
-	ldx		[%o0 + 0x40], %g0
-	ldx		[%o0 + 0x48], %g1
-	ldx		[%o0 + 0x50], %g2
-	ldx		[%o0 + 0x58], %g3
-	ldx		[%o0 + 0x60], %g4
-	ldx		[%o0 + 0x68], %g5
-	ldx		[%o0 + 0x70], %g6
-	ldx		[%o0 + 0x78], %g7
-	wrpr		%o1, PSTATE_MG, %pstate
-	ldx		[%o0 + 0x80], %g0
-	ldx		[%o0 + 0x88], %g1
-	ldx		[%o0 + 0x90], %g2
-	ldx		[%o0 + 0x98], %g3
-	ldx		[%o0 + 0xa0], %g4
-	ldx		[%o0 + 0xa8], %g5
-	ldx		[%o0 + 0xb0], %g6
-	ldx		[%o0 + 0xb8], %g7
-	wrpr		%o5, 0x0, %pstate
-	retl
-	 nop
-
 	.globl		getcc, setcc
 getcc:
 	ldx		[%o0 + PT_V9_TSTATE], %o1
@@ -488,9 +481,24 @@
 	retl
 	 stx		%o1, [%o0 + PT_V9_TSTATE]
 
-	.globl		utrap, utrap_ill
-utrap:	brz,pn		%g1, etrap
+	.globl		utrap_trap
+utrap_trap:		/* %g3=handler,%g4=level */
+	TRAP_LOAD_THREAD_REG(%g6, %g1)
+	ldx		[%g6 + TI_UTRAPS], %g1
+	brnz,pt		%g1, invoke_utrap
 	 nop
+
+	ba,pt		%xcc, etrap
+	 rd		%pc, %g7
+	mov		%l4, %o1
+        call		bad_trap
+	 add		%sp, PTREGS_OFF, %o0
+	ba,pt		%xcc, rtrap
+	 clr		%l6
+
+invoke_utrap:
+	sllx		%g3, 3, %g3
+	ldx		[%g1 + %g3], %g1
 	save		%sp, -128, %sp
 	rdpr		%tstate, %l6
 	rdpr		%cwp, %l7
@@ -500,17 +508,6 @@
 	rdpr		%tnpc, %l7
 	wrpr		%g1, 0, %tnpc
 	done
-utrap_ill:
-        call		bad_trap
-	 add		%sp, PTREGS_OFF, %o0
-	ba,pt		%xcc, rtrap
-	 clr		%l6
-
-	/* XXX Here is stuff we still need to write... -DaveM XXX */
-	.globl		netbsd_syscall
-netbsd_syscall:
-	retl
-	 nop
 
 	/* We need to carefully read the error status, ACK
 	 * the errors, prevent recursive traps, and pass the
@@ -1001,7 +998,7 @@
 	 * %g3:		scratch
 	 * %g4:		AFSR
 	 * %g5:		AFAR
-	 * %g6:		current thread ptr
+	 * %g6:		unused, will have current thread ptr after etrap
 	 * %g7:		scratch
 	 */
 __cheetah_log_error:
@@ -1539,13 +1536,14 @@
 
 1:		b,pt		%xcc, ret_sys_call
 		 ldx		[%sp + PTREGS_OFF + PT_V9_I0], %o0
-sparc_exit:	wrpr		%g0, (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV), %pstate
+sparc_exit:	rdpr		%pstate, %g2
+		wrpr		%g2, PSTATE_IE, %pstate
 		rdpr		%otherwin, %g1
 		rdpr		%cansave, %g3
 		add		%g3, %g1, %g3
 		wrpr		%g3, 0x0, %cansave
 		wrpr		%g0, 0x0, %otherwin
-		wrpr		%g0, (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV | PSTATE_IE), %pstate
+		wrpr		%g2, 0x0, %pstate
 		ba,pt		%xcc, sys_exit
 		 stb		%g0, [%g6 + TI_WSAVED]
 
@@ -1690,3 +1688,101 @@
 	 restore	%g0, %g0, %g0
 2:	retl
 	 nop
+
+#ifdef CONFIG_SMP
+	.globl		hard_smp_processor_id
+hard_smp_processor_id:
+#endif
+	.globl		real_hard_smp_processor_id
+real_hard_smp_processor_id:
+	__GET_CPUID(%o0)
+	retl
+	 nop
+
+	/* %o0: devhandle
+	 * %o1:	devino
+	 *
+	 * returns %o0: sysino
+	 */
+	.globl	sun4v_devino_to_sysino
+sun4v_devino_to_sysino:
+	mov	HV_FAST_INTR_DEVINO2SYSINO, %o5
+	ta	HV_FAST_TRAP
+	retl
+	 mov	%o1, %o0
+
+	/* %o0: sysino
+	 *
+	 * returns %o0: intr_enabled (HV_INTR_{DISABLED,ENABLED})
+	 */
+	.globl	sun4v_intr_getenabled
+sun4v_intr_getenabled:
+	mov	HV_FAST_INTR_GETENABLED, %o5
+	ta	HV_FAST_TRAP
+	retl
+	 mov	%o1, %o0
+
+	/* %o0: sysino
+	 * %o1: intr_enabled (HV_INTR_{DISABLED,ENABLED})
+	 */
+	.globl	sun4v_intr_setenabled
+sun4v_intr_setenabled:
+	mov	HV_FAST_INTR_SETENABLED, %o5
+	ta	HV_FAST_TRAP
+	retl
+	 nop
+
+	/* %o0: sysino
+	 *
+	 * returns %o0: intr_state (HV_INTR_STATE_*)
+	 */
+	.globl	sun4v_intr_getstate
+sun4v_intr_getstate:
+	mov	HV_FAST_INTR_GETSTATE, %o5
+	ta	HV_FAST_TRAP
+	retl
+	 mov	%o1, %o0
+
+	/* %o0: sysino
+	 * %o1: intr_state (HV_INTR_STATE_*)
+	 */
+	.globl	sun4v_intr_setstate
+sun4v_intr_setstate:
+	mov	HV_FAST_INTR_SETSTATE, %o5
+	ta	HV_FAST_TRAP
+	retl
+	 nop
+
+	/* %o0: sysino
+	 *
+	 * returns %o0: cpuid
+	 */
+	.globl	sun4v_intr_gettarget
+sun4v_intr_gettarget:
+	mov	HV_FAST_INTR_GETTARGET, %o5
+	ta	HV_FAST_TRAP
+	retl
+	 mov	%o1, %o0
+
+	/* %o0: sysino
+	 * %o1: cpuid
+	 */
+	.globl	sun4v_intr_settarget
+sun4v_intr_settarget:
+	mov	HV_FAST_INTR_SETTARGET, %o5
+	ta	HV_FAST_TRAP
+	retl
+	 nop
+
+	/* %o0:	type
+	 * %o1:	queue paddr
+	 * %o2:	num queue entries
+	 *
+	 * returns %o0:	status
+	 */
+	.globl	sun4v_cpu_qconf
+sun4v_cpu_qconf:
+	mov	HV_FAST_CPU_QCONF, %o5
+	ta	HV_FAST_TRAP
+	retl
+	 nop
diff -urN oldtree/arch/sparc64/kernel/etrap.S newtree/arch/sparc64/kernel/etrap.S
--- oldtree/arch/sparc64/kernel/etrap.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/kernel/etrap.S	2006-02-21 15:58:20.199075832 +0000
@@ -31,6 +31,7 @@
 		.globl	etrap, etrap_irq, etraptl1
 etrap:		rdpr	%pil, %g2
 etrap_irq:
+		TRAP_LOAD_THREAD_REG(%g6, %g1)
 		rdpr	%tstate, %g1
 		sllx	%g2, 20, %g3
 		andcc	%g1, TSTATE_PRIV, %g0
@@ -54,7 +55,31 @@
 		rd	%y, %g3
 		stx	%g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC]
 		st	%g3, [%g2 + STACKFRAME_SZ + PT_V9_Y]
-		save	%g2, -STACK_BIAS, %sp	! Ordering here is critical
+
+		rdpr	%cansave, %g1
+		brnz,pt %g1, etrap_save
+		 nop
+
+		rdpr	%cwp, %g1
+		add	%g1, 2, %g1
+		wrpr	%g1, %cwp
+		be,pt	%xcc, etrap_user_spill
+		 mov	ASI_AIUP, %g3
+
+		rdpr	%otherwin, %g3
+		brz	%g3, etrap_kernel_spill
+		 mov	ASI_AIUS, %g3
+
+etrap_user_spill:
+
+		wr	%g3, 0x0, %asi
+		ldx	[%g6 + TI_FLAGS], %g3
+		and	%g3, _TIF_32BIT, %g3
+		brnz,pt	%g3, etrap_user_spill_32bit
+		 nop
+		ba,a,pt	%xcc, etrap_user_spill_64bit
+
+etrap_save:	save	%g2, -STACK_BIAS, %sp
 		mov	%g6, %l6
 
 		bne,pn	%xcc, 3f
@@ -70,42 +95,56 @@
 		wrpr	%g2, 0, %wstate
 		sethi	%hi(sparc64_kern_pri_context), %g2
 		ldx	[%g2 + %lo(sparc64_kern_pri_context)], %g3
-		stxa	%g3, [%l4] ASI_DMMU
-		flush	%l6
-		wr	%g0, ASI_AIUS, %asi
-2:		wrpr	%g0, 0x0, %tl
-		mov	%g4, %l4
+
+661:		stxa	%g3, [%l4] ASI_DMMU
+		.section .sun4v_1insn_patch, "ax"
+		.word	661b
+		stxa	%g3, [%l4] ASI_MMU
+		.previous
+
+		sethi	%hi(KERNBASE), %l4
+		flush	%l4
+		mov	ASI_AIUS, %l7
+2:		mov	%g4, %l4
 		mov	%g5, %l5
+		add	%g7, 4, %l2
+
+		/* Go to trap time globals so we can save them.  */
+661:		wrpr	%g0, ETRAP_PSTATE1, %pstate
+		.section .sun4v_1insn_patch, "ax"
+		.word	661b
+		SET_GL(0)
+		.previous
 
-		mov	%g7, %l2
-		wrpr	%g0, ETRAP_PSTATE1, %pstate
 		stx	%g1, [%sp + PTREGS_OFF + PT_V9_G1]
 		stx	%g2, [%sp + PTREGS_OFF + PT_V9_G2]
+		sllx	%l7, 24, %l7
 		stx	%g3, [%sp + PTREGS_OFF + PT_V9_G3]
+		rdpr	%cwp, %l0
 		stx	%g4, [%sp + PTREGS_OFF + PT_V9_G4]
 		stx	%g5, [%sp + PTREGS_OFF + PT_V9_G5]
 		stx	%g6, [%sp + PTREGS_OFF + PT_V9_G6]
-
 		stx	%g7, [%sp + PTREGS_OFF + PT_V9_G7]
+		or	%l7, %l0, %l7
+		sethi	%hi(TSTATE_RMO | TSTATE_PEF), %l0
+		or	%l7, %l0, %l7
+		wrpr	%l2, %tnpc
+		wrpr	%l7, (TSTATE_PRIV | TSTATE_IE), %tstate
 		stx	%i0, [%sp + PTREGS_OFF + PT_V9_I0]
 		stx	%i1, [%sp + PTREGS_OFF + PT_V9_I1]
 		stx	%i2, [%sp + PTREGS_OFF + PT_V9_I2]
 		stx	%i3, [%sp + PTREGS_OFF + PT_V9_I3]
 		stx	%i4, [%sp + PTREGS_OFF + PT_V9_I4]
 		stx	%i5, [%sp + PTREGS_OFF + PT_V9_I5]
-
 		stx	%i6, [%sp + PTREGS_OFF + PT_V9_I6]
-		stx	%i7, [%sp + PTREGS_OFF + PT_V9_I7]
-		wrpr	%g0, ETRAP_PSTATE2, %pstate
 		mov	%l6, %g6
-#ifdef CONFIG_SMP
-		mov	TSB_REG, %g3
-		ldxa	[%g3] ASI_IMMU, %g5
-#endif
-		jmpl	%l2 + 0x4, %g0
-		 ldx	[%g6 + TI_TASK], %g4
+		stx	%i7, [%sp + PTREGS_OFF + PT_V9_I7]
+		LOAD_PER_CPU_BASE(%g5, %g6, %g4, %g3, %l1)
+		ldx	[%g6 + TI_TASK], %g4
+		done
 
-3:		ldub	[%l6 + TI_FPDEPTH], %l5
+3:		mov	ASI_P, %l7
+		ldub	[%l6 + TI_FPDEPTH], %l5
 		add	%l6, TI_FPSAVED + 1, %l4
 		srl	%l5, 1, %l3
 		add	%l5, 2, %l5
@@ -125,6 +164,7 @@
 		 *	0x58	TL4's TT
 		 *	0x60	TL
 		 */
+		TRAP_LOAD_THREAD_REG(%g6, %g1)
 		sub	%sp, ((4 * 8) * 4) + 8, %g2
 		rdpr	%tl, %g1
 
@@ -148,6 +188,11 @@
 		rdpr	%tt, %g3
 		stx	%g3, [%g2 + STACK_BIAS + 0x38]
 
+		sethi	%hi(is_sun4v), %g3
+		lduw	[%g3 + %lo(is_sun4v)], %g3
+		brnz,pn	%g3, finish_tl1_capture
+		 nop
+
 		wrpr	%g0, 3, %tl
 		rdpr	%tstate, %g3
 		stx	%g3, [%g2 + STACK_BIAS + 0x40]
@@ -168,91 +213,20 @@
 		rdpr	%tt, %g3
 		stx	%g3, [%g2 + STACK_BIAS + 0x78]
 
-		wrpr	%g1, %tl
 		stx	%g1, [%g2 + STACK_BIAS + 0x80]
 
+finish_tl1_capture:
+		wrpr	%g0, 1, %tl
+661:		nop
+		.section .sun4v_1insn_patch, "ax"
+		.word	661b
+		SET_GL(1)
+		.previous
+
 		rdpr	%tstate, %g1
 		sub	%g2, STACKFRAME_SZ + TRACEREG_SZ - STACK_BIAS, %g2
 		ba,pt	%xcc, 1b
 		 andcc	%g1, TSTATE_PRIV, %g0
 
-		.align	64
-		.globl	scetrap
-scetrap:	rdpr	%pil, %g2
-		rdpr	%tstate, %g1
-		sllx	%g2, 20, %g3
-		andcc	%g1, TSTATE_PRIV, %g0
-		or	%g1, %g3, %g1
-		bne,pn	%xcc, 1f
-		 sub	%sp, (STACKFRAME_SZ+TRACEREG_SZ-STACK_BIAS), %g2
-		wrpr	%g0, 7, %cleanwin
-
-		sllx	%g1, 51, %g3
-		sethi	%hi(TASK_REGOFF), %g2
-		or	%g2, %lo(TASK_REGOFF), %g2
-		brlz,pn	%g3, 1f
-		 add	%g6, %g2, %g2
-		wr	%g0, 0, %fprs
-1:		rdpr	%tpc, %g3
-		stx	%g1, [%g2 + STACKFRAME_SZ + PT_V9_TSTATE]
-
-		rdpr	%tnpc, %g1
-		stx	%g3, [%g2 + STACKFRAME_SZ + PT_V9_TPC]
-		stx	%g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC]
-		save	%g2, -STACK_BIAS, %sp	! Ordering here is critical
-		mov	%g6, %l6
-		bne,pn	%xcc, 2f
-		 mov	ASI_P, %l7
-		rdpr	%canrestore, %g3
-
-		rdpr	%wstate, %g2
-		wrpr	%g0, 0, %canrestore
-		sll	%g2, 3, %g2
-		mov	PRIMARY_CONTEXT, %l4
-		wrpr	%g3, 0, %otherwin
-		wrpr	%g2, 0, %wstate
-		sethi	%hi(sparc64_kern_pri_context), %g2
-		ldx	[%g2 + %lo(sparc64_kern_pri_context)], %g3
-		stxa	%g3, [%l4] ASI_DMMU
-		flush	%l6
-
-		mov	ASI_AIUS, %l7
-2:		mov	%g4, %l4
-		mov	%g5, %l5
-		add	%g7, 0x4, %l2
-		wrpr	%g0, ETRAP_PSTATE1, %pstate
-		stx	%g1, [%sp + PTREGS_OFF + PT_V9_G1]
-		stx	%g2, [%sp + PTREGS_OFF + PT_V9_G2]
-		sllx	%l7, 24, %l7
-
-		stx	%g3, [%sp + PTREGS_OFF + PT_V9_G3]
-		rdpr	%cwp, %l0
-		stx	%g4, [%sp + PTREGS_OFF + PT_V9_G4]
-		stx	%g5, [%sp + PTREGS_OFF + PT_V9_G5]
-		stx	%g6, [%sp + PTREGS_OFF + PT_V9_G6]
-		stx	%g7, [%sp + PTREGS_OFF + PT_V9_G7]
-		or	%l7, %l0, %l7
-		sethi	%hi(TSTATE_RMO | TSTATE_PEF), %l0
-
-		or	%l7, %l0, %l7
-		wrpr	%l2, %tnpc
-		wrpr	%l7, (TSTATE_PRIV | TSTATE_IE), %tstate
-		stx	%i0, [%sp + PTREGS_OFF + PT_V9_I0]
-		stx	%i1, [%sp + PTREGS_OFF + PT_V9_I1]
-		stx	%i2, [%sp + PTREGS_OFF + PT_V9_I2]
-		stx	%i3, [%sp + PTREGS_OFF + PT_V9_I3]
-		stx	%i4, [%sp + PTREGS_OFF + PT_V9_I4]
-
-		stx	%i5, [%sp + PTREGS_OFF + PT_V9_I5]
-		stx	%i6, [%sp + PTREGS_OFF + PT_V9_I6]
-		mov	%l6, %g6
-		stx	%i7, [%sp + PTREGS_OFF + PT_V9_I7]
-#ifdef CONFIG_SMP
-		mov	TSB_REG, %g3
-		ldxa	[%g3] ASI_IMMU, %g5
-#endif
-		ldx	[%g6 + TI_TASK], %g4
-		done
-
 #undef TASK_REGOFF
 #undef ETRAP_PSTATE1
diff -urN oldtree/arch/sparc64/kernel/head.S newtree/arch/sparc64/kernel/head.S
--- oldtree/arch/sparc64/kernel/head.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/kernel/head.S	2006-02-21 15:58:20.200075680 +0000
@@ -26,6 +26,7 @@
 #include <asm/head.h>
 #include <asm/ttable.h>
 #include <asm/mmu.h>
+#include <asm/cpudata.h>
 	
 /* This section from from _start to sparc64_boot_end should fit into
  * 0x0000000000404000 to 0x0000000000408000.
@@ -94,12 +95,17 @@
 	wrpr	%g1, 0x0, %pstate
 	ba,a,pt	%xcc, 1f
 
-	.globl	prom_finddev_name, prom_chosen_path
-	.globl	prom_getprop_name, prom_mmu_name
-	.globl	prom_callmethod_name, prom_translate_name
+	.globl	prom_finddev_name, prom_chosen_path, prom_root_node
+	.globl	prom_getprop_name, prom_mmu_name, prom_peer_name
+	.globl	prom_callmethod_name, prom_translate_name, prom_root_compatible
 	.globl	prom_map_name, prom_unmap_name, prom_mmu_ihandle_cache
 	.globl	prom_boot_mapped_pc, prom_boot_mapping_mode
 	.globl	prom_boot_mapping_phys_high, prom_boot_mapping_phys_low
+	.globl	is_sun4v
+prom_peer_name:
+	.asciz	"peer"
+prom_compatible_name:
+	.asciz	"compatible"
 prom_finddev_name:
 	.asciz	"finddevice"
 prom_chosen_path:
@@ -116,7 +122,13 @@
 	.asciz	"map"
 prom_unmap_name:
 	.asciz	"unmap"
+prom_sun4v_name:
+	.asciz	"sun4v"
 	.align	4
+prom_root_compatible:
+	.skip	64
+prom_root_node:
+	.word	0
 prom_mmu_ihandle_cache:
 	.word	0
 prom_boot_mapped_pc:
@@ -128,8 +140,54 @@
 	.xword	0
 prom_boot_mapping_phys_low:
 	.xword	0
+is_sun4v:
+	.word	0
 1:
 	rd	%pc, %l0
+
+	mov	(1b - prom_peer_name), %l1
+	sub	%l0, %l1, %l1
+	mov	0, %l2
+
+	/* prom_root_node = prom_peer(0) */
+	stx	%l1, [%sp + 2047 + 128 + 0x00]	! service, "peer"
+	mov	1, %l3
+	stx	%l3, [%sp + 2047 + 128 + 0x08]	! num_args, 1
+	stx	%l3, [%sp + 2047 + 128 + 0x10]	! num_rets, 1
+	stx	%l2, [%sp + 2047 + 128 + 0x18]	! arg1, 0
+	stx	%g0, [%sp + 2047 + 128 + 0x20]	! ret1
+	call	%l7
+	 add	%sp, (2047 + 128), %o0		! argument array
+
+	ldx	[%sp + 2047 + 128 + 0x20], %l4	! prom root node
+	mov	(1b - prom_root_node), %l1
+	sub	%l0, %l1, %l1
+	stw	%l4, [%l1]
+
+	mov	(1b - prom_getprop_name), %l1
+	mov	(1b - prom_compatible_name), %l2
+	mov	(1b - prom_root_compatible), %l5
+	sub	%l0, %l1, %l1
+	sub	%l0, %l2, %l2
+	sub	%l0, %l5, %l5
+
+	/* prom_getproperty(prom_root_node, "compatible",
+	 *                  &prom_root_compatible, 64)
+	 */
+	stx	%l1, [%sp + 2047 + 128 + 0x00]	! service, "getprop"
+	mov	4, %l3
+	stx	%l3, [%sp + 2047 + 128 + 0x08]	! num_args, 4
+	mov	1, %l3
+	stx	%l3, [%sp + 2047 + 128 + 0x10]	! num_rets, 1
+	stx	%l4, [%sp + 2047 + 128 + 0x18]	! arg1, prom_root_node
+	stx	%l2, [%sp + 2047 + 128 + 0x20]	! arg2, "compatible"
+	stx	%l5, [%sp + 2047 + 128 + 0x28]	! arg3, &prom_root_compatible
+	mov	64, %l3
+	stx	%l3, [%sp + 2047 + 128 + 0x30]	! arg4, size
+	stx	%g0, [%sp + 2047 + 128 + 0x38]	! ret1
+	call	%l7
+	 add	%sp, (2047 + 128), %o0		! argument array
+
 	mov	(1b - prom_finddev_name), %l1
 	mov	(1b - prom_chosen_path), %l2
 	mov	(1b - prom_boot_mapped_pc), %l3
@@ -238,6 +296,27 @@
 	add	%sp, (192 + 128), %sp
 
 sparc64_boot_after_remap:
+	sethi	%hi(prom_root_compatible), %g1
+	or	%g1, %lo(prom_root_compatible), %g1
+	sethi	%hi(prom_sun4v_name), %g7
+	or	%g7, %lo(prom_sun4v_name), %g7
+	mov	5, %g3
+1:	ldub	[%g7], %g2
+	ldub	[%g1], %g4
+	cmp	%g2, %g4
+	bne,pn	%icc, 2f
+	 add	%g7, 1, %g7
+	subcc	%g3, 1, %g3
+	bne,pt	%xcc, 1b
+	 add	%g1, 1, %g1
+
+	sethi	%hi(is_sun4v), %g1
+	or	%g1, %lo(is_sun4v), %g1
+	mov	1, %g7
+	stw	%g7, [%g1]
+
+2:
+	BRANCH_IF_SUN4V(g1, jump_to_sun4u_init)
 	BRANCH_IF_CHEETAH_BASE(g1,g7,cheetah_boot)
 	BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,cheetah_plus_boot)
 	ba,pt	%xcc, spitfire_boot
@@ -301,20 +380,56 @@
 	 nop
 
 sun4u_init:
+	BRANCH_IF_SUN4V(g1, sun4v_init)
+
 	/* Set ctx 0 */
-	mov	PRIMARY_CONTEXT, %g7
-	stxa	%g0, [%g7] ASI_DMMU
-	membar	#Sync
+	mov		PRIMARY_CONTEXT, %g7
+	stxa		%g0, [%g7] ASI_DMMU
+	membar		#Sync
 
-	mov	SECONDARY_CONTEXT, %g7
-	stxa	%g0, [%g7] ASI_DMMU
+	mov		SECONDARY_CONTEXT, %g7
+	stxa		%g0, [%g7] ASI_DMMU
 	membar	#Sync
 
-	BRANCH_IF_ANY_CHEETAH(g1,g7,cheetah_tlb_fixup)
+	ba,pt		%xcc, sun4u_continue
+	 nop
+
+sun4v_init:
+	/* Set ctx 0 */
+	mov		PRIMARY_CONTEXT, %g7
+	stxa		%g0, [%g7] ASI_MMU
+	membar		#Sync
+
+	mov		SECONDARY_CONTEXT, %g7
+	stxa		%g0, [%g7] ASI_MMU
+	membar		#Sync
+	ba,pt		%xcc, niagara_tlb_fixup
+	 nop
+
+sun4u_continue:
+	BRANCH_IF_ANY_CHEETAH(g1, g7, cheetah_tlb_fixup)
 
 	ba,pt	%xcc, spitfire_tlb_fixup
 	 nop
 
+niagara_tlb_fixup:
+	mov	3, %g2		/* Set TLB type to hypervisor. */
+	sethi	%hi(tlb_type), %g1
+	stw	%g2, [%g1 + %lo(tlb_type)]
+
+	/* Patch copy/clear ops.  */
+	call	niagara_patch_copyops
+	 nop
+	call	niagara_patch_pageops
+	 nop
+
+	/* Patch TLB/cache ops.  */
+	call	hypervisor_patch_cachetlbops
+	 nop
+
+	ba,pt	%xcc, tlb_fixup_done
+	 nop
+
 cheetah_tlb_fixup:
 	mov	2, %g2		/* Set TLB type to cheetah+. */
 	BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,1f)
@@ -411,85 +526,55 @@
 	wrpr	%g0, 15, %pil
 
 	/* Make the firmware call to jump over to the Linux trap table.  */
-	call	prom_set_trap_table
+	sethi	%hi(is_sun4v), %o0
+	lduw	[%o0 + %lo(is_sun4v)], %o0
+	brz,pt	%o0, 1f
+	 nop
+
+	TRAP_LOAD_TRAP_BLOCK(%g2, %g3)
+	add	%g2, TRAP_PER_CPU_FAULT_INFO, %g2
+	stxa	%g2, [%g0] ASI_SCRATCHPAD
+
+	/* Compute physical address:
+	 *
+	 * paddr = kern_base + (mmfsa_vaddr - KERNBASE)
+	 */
+	sethi	%hi(KERNBASE), %g3
+	sub	%g2, %g3, %g2
+	sethi	%hi(kern_base), %g3
+	ldx	[%g3 + %lo(kern_base)], %g3
+	add	%g2, %g3, %o1
+
+	call	prom_set_trap_table_sun4v
+	 sethi	%hi(sparc64_ttable_tl0), %o0
+
+	ba,pt	%xcc, 2f
+	 nop
+
+1:	call	prom_set_trap_table
 	 sethi	%hi(sparc64_ttable_tl0), %o0
 
 	/* Start using proper page size encodings in ctx register.  */
-	sethi	%hi(sparc64_kern_pri_context), %g3
+2:	sethi	%hi(sparc64_kern_pri_context), %g3
 	ldx	[%g3 + %lo(sparc64_kern_pri_context)], %g2
-	mov	PRIMARY_CONTEXT, %g1
-	stxa	%g2, [%g1] ASI_DMMU
-	membar	#Sync
 
-	/* The Linux trap handlers expect various trap global registers
-	 * to be setup with some fixed values.  So here we set these
-	 * up very carefully.  These globals are:
-	 *
-	 * Alternate Globals (PSTATE_AG):
-	 *
-	 * %g6			--> current_thread_info()
-	 *
-	 * MMU Globals (PSTATE_MG):
-	 *
-	 * %g1			--> TLB_SFSR
-	 * %g2			--> ((_PAGE_VALID | _PAGE_SZ4MB |
-	 *			      _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
-	 *			     ^ 0xfffff80000000000)
-	 * (this %g2 value is used for computing the PAGE_OFFSET kernel
-	 *  TLB entries quickly, the virtual address of the fault XOR'd
-	 *  with this %g2 value is the PTE to load into the TLB)
-	 * %g3			--> VPTE_BASE_CHEETAH or VPTE_BASE_SPITFIRE
-	 *
-	 * Interrupt Globals (PSTATE_IG, setup by init_irqwork_curcpu()):
-	 *
-	 * %g6			--> __irq_work[smp_processor_id()]
-	 */
+	mov		PRIMARY_CONTEXT, %g1
 
-	rdpr	%pstate, %o1
-	mov	%g6, %o2
-	wrpr	%o1, PSTATE_AG, %pstate
-	mov	%o2, %g6
-
-#define KERN_HIGHBITS		((_PAGE_VALID|_PAGE_SZ4MB)^0xfffff80000000000)
-#define KERN_LOWBITS		(_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
-	wrpr	%o1, PSTATE_MG, %pstate
-	mov	TSB_REG, %g1
-	stxa	%g0, [%g1] ASI_DMMU
-	membar	#Sync
-	stxa	%g0, [%g1] ASI_IMMU
-	membar	#Sync
-	mov	TLB_SFSR, %g1
-	sethi	%uhi(KERN_HIGHBITS), %g2
-	or	%g2, %ulo(KERN_HIGHBITS), %g2
-	sllx	%g2, 32, %g2
-	or	%g2, KERN_LOWBITS, %g2
-
-	BRANCH_IF_ANY_CHEETAH(g3,g7,8f)
-	ba,pt	%xcc, 9f
-	 nop
-
-8:
-	sethi		%uhi(VPTE_BASE_CHEETAH), %g3
-	or		%g3, %ulo(VPTE_BASE_CHEETAH), %g3
-	ba,pt		%xcc, 2f
-	 sllx		%g3, 32, %g3
-
-9:
-	sethi		%uhi(VPTE_BASE_SPITFIRE), %g3
-	or		%g3, %ulo(VPTE_BASE_SPITFIRE), %g3
-	sllx		%g3, 32, %g3
+661:	stxa		%g2, [%g1] ASI_DMMU
+	.section	.sun4v_1insn_patch, "ax"
+	.word		661b
+	stxa		%g2, [%g1] ASI_MMU
+	.previous
 
-2:
-	clr	%g7
-#undef KERN_HIGHBITS
-#undef KERN_LOWBITS
+	membar	#Sync
 
 	/* Kill PROM timer */
 	sethi	%hi(0x80000000), %o2
 	sllx	%o2, 32, %o2
 	wr	%o2, 0, %tick_cmpr
 
-	BRANCH_IF_ANY_CHEETAH(o2,o3,1f)
+	BRANCH_IF_SUN4V(o2, 1f)
+	BRANCH_IF_ANY_CHEETAH(o2, o3, 1f)
 
 	ba,pt	%xcc, 2f
 	 nop
@@ -502,7 +587,6 @@
 
 2:
 	wrpr	%g0, %g0, %wstate
-	wrpr	%o1, 0x0, %pstate
 
 	call	init_irqwork_curcpu
 	 nop
@@ -517,7 +601,7 @@
 	 restore
 
 	.globl	setup_tba
-setup_tba:	/* i0 = is_starfire */
+setup_tba:
 	save	%sp, -192, %sp
 
 	/* The boot processor is the only cpu which invokes this
@@ -538,24 +622,27 @@
 
 #include "systbls.S"
 #include "ktlb.S"
+#include "tsb.S"
 #include "etrap.S"
 #include "rtrap.S"
 #include "winfixup.S"
 #include "entry.S"
+#include "sun4v_tlb_miss.S"
+#include "sun4v_ivec.S"
 
 /*
  * The following skip makes sure the trap table in ttable.S is aligned
  * on a 32K boundary as required by the v9 specs for TBA register.
+ *
+ * We align to a 32K boundary, then we have the 32K kernel TSB,
+ * then the 32K aligned trap table.
  */
 1:
 	.skip	0x4000 + _start - 1b
 
-#ifdef CONFIG_SBUS
-/* This is just a hack to fool make depend config.h discovering
-   strategy: As the .S files below need config.h, but
-   make depend does not find it for them, we include config.h
-   in head.S */
-#endif
+	.globl	swapper_tsb
+swapper_tsb:
+	.skip	(32 * 1024)
 
 ! 0x0000000000408000
 
diff -urN oldtree/arch/sparc64/kernel/irq.c newtree/arch/sparc64/kernel/irq.c
--- oldtree/arch/sparc64/kernel/irq.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/kernel/irq.c	2006-02-21 15:58:20.202075376 +0000
@@ -21,6 +21,7 @@
 #include <linux/delay.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/bootmem.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -39,6 +40,7 @@
 #include <asm/cache.h>
 #include <asm/cpudata.h>
 #include <asm/auxio.h>
+#include <asm/head.h>
 
 #ifdef CONFIG_SMP
 static void distribute_irqs(void);
@@ -136,12 +138,48 @@
 	return 0;
 }
 
+extern unsigned long real_hard_smp_processor_id(void);
+
+static unsigned int sun4u_compute_tid(unsigned long imap, unsigned long cpuid)
+{
+	unsigned int tid;
+
+	if (this_is_starfire) {
+		tid = starfire_translate(imap, cpuid);
+		tid <<= IMAP_TID_SHIFT;
+		tid &= IMAP_TID_UPA;
+	} else {
+		if (tlb_type == cheetah || tlb_type == cheetah_plus) {
+			unsigned long ver;
+
+			__asm__ ("rdpr %%ver, %0" : "=r" (ver));
+			if ((ver >> 32UL) == __JALAPENO_ID ||
+			    (ver >> 32UL) == __SERRANO_ID) {
+				tid = cpuid << IMAP_TID_SHIFT;
+				tid &= IMAP_TID_JBUS;
+			} else {
+				unsigned int a = cpuid & 0x1f;
+				unsigned int n = (cpuid >> 5) & 0x1f;
+
+				tid = ((a << IMAP_AID_SHIFT) |
+				       (n << IMAP_NID_SHIFT));
+				tid &= (IMAP_AID_SAFARI |
+					IMAP_NID_SAFARI);;
+			}
+		} else {
+			tid = cpuid << IMAP_TID_SHIFT;
+			tid &= IMAP_TID_UPA;
+		}
+	}
+
+	return tid;
+}
+
 /* Now these are always passed a true fully specified sun4u INO. */
 void enable_irq(unsigned int irq)
 {
 	struct ino_bucket *bucket = __bucket(irq);
-	unsigned long imap;
-	unsigned long tid;
+	unsigned long imap, cpuid;
 
 	imap = bucket->imap;
 	if (imap == 0UL)
@@ -149,46 +187,37 @@
 
 	preempt_disable();
 
-	if (tlb_type == cheetah || tlb_type == cheetah_plus) {
-		unsigned long ver;
+	/* This gets the physical processor ID, even on uniprocessor,
+	 * so we can always program the interrupt target correctly.
+	 */
+	cpuid = real_hard_smp_processor_id();
 
-		__asm__ ("rdpr %%ver, %0" : "=r" (ver));
-		if ((ver >> 32) == 0x003e0016) {
-			/* We set it to our JBUS ID. */
-			__asm__ __volatile__("ldxa [%%g0] %1, %0"
-					     : "=r" (tid)
-					     : "i" (ASI_JBUS_CONFIG));
-			tid = ((tid & (0x1fUL<<17)) << 9);
-			tid &= IMAP_TID_JBUS;
-		} else {
-			/* We set it to our Safari AID. */
-			__asm__ __volatile__("ldxa [%%g0] %1, %0"
-					     : "=r" (tid)
-					     : "i" (ASI_SAFARI_CONFIG));
-			tid = ((tid & (0x3ffUL<<17)) << 9);
-			tid &= IMAP_AID_SAFARI;
-		}
-	} else if (this_is_starfire == 0) {
-		/* We set it to our UPA MID. */
-		__asm__ __volatile__("ldxa [%%g0] %1, %0"
-				     : "=r" (tid)
-				     : "i" (ASI_UPA_CONFIG));
-		tid = ((tid & UPA_CONFIG_MID) << 9);
-		tid &= IMAP_TID_UPA;
+	if (tlb_type == hypervisor) {
+		unsigned int ino = __irq_ino(irq);
+		int err;
+
+		err = sun4v_intr_settarget(ino, cpuid);
+		if (err != HV_EOK)
+			printk("sun4v_intr_settarget(%x,%lu): err(%d)\n",
+			       ino, cpuid, err);
+		err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
+		if (err != HV_EOK)
+			printk("sun4v_intr_setenabled(%x): err(%d)\n",
+			       ino, err);
 	} else {
-		tid = (starfire_translate(imap, smp_processor_id()) << 26);
-		tid &= IMAP_TID_UPA;
-	}
+		unsigned int tid = sun4u_compute_tid(imap, cpuid);
 
-	/* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product
-	 * of this SYSIO's preconfigured IGN in the SYSIO Control
-	 * Register, the hardware just mirrors that value here.
-	 * However for Graphics and UPA Slave devices the full
-	 * IMAP_INR field can be set by the programmer here.
-	 *
-	 * Things like FFB can now be handled via the new IRQ mechanism.
-	 */
-	upa_writel(tid | IMAP_VALID, imap);
+		/* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product
+		 * of this SYSIO's preconfigured IGN in the SYSIO Control
+		 * Register, the hardware just mirrors that value here.
+		 * However for Graphics and UPA Slave devices the full
+		 * IMAP_INR field can be set by the programmer here.
+		 *
+		 * Things like FFB can now be handled via the new IRQ
+		 * mechanism.
+		 */
+		upa_writel(tid | IMAP_VALID, imap);
+	}
 
 	preempt_enable();
 }
@@ -201,16 +230,26 @@
 
 	imap = bucket->imap;
 	if (imap != 0UL) {
-		u32 tmp;
+		if (tlb_type == hypervisor) {
+			unsigned int ino = __irq_ino(irq);
+			int err;
+
+			err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED);
+			if (err != HV_EOK)
+				printk("sun4v_intr_setenabled(%x): "
+				       "err(%d)\n", ino, err);
+		} else {
+			u32 tmp;
 
-		/* NOTE: We do not want to futz with the IRQ clear registers
-		 *       and move the state to IDLE, the SCSI code does call
-		 *       disable_irq() to assure atomicity in the queue cmd
-		 *       SCSI adapter driver code.  Thus we'd lose interrupts.
-		 */
-		tmp = upa_readl(imap);
-		tmp &= ~IMAP_VALID;
-		upa_writel(tmp, imap);
+			/* NOTE: We do not want to futz with the IRQ clear registers
+			 *       and move the state to IDLE, the SCSI code does call
+			 *       disable_irq() to assure atomicity in the queue cmd
+			 *       SCSI adapter driver code.  Thus we'd lose interrupts.
+			 */
+			tmp = upa_readl(imap);
+			tmp &= ~IMAP_VALID;
+			upa_writel(tmp, imap);
+		}
 	}
 }
 
@@ -248,6 +287,8 @@
 		return __irq(&pil0_dummy_bucket);
 	}
 
+	BUG_ON(tlb_type == hypervisor);
+
 	/* RULE: Both must be specified in all other cases. */
 	if (iclr == 0UL || imap == 0UL) {
 		prom_printf("Invalid build_irq %d %d %016lx %016lx\n",
@@ -294,6 +335,38 @@
 	return __irq(bucket);
 }
 
+unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, int pil, unsigned char flags)
+{
+	struct ino_bucket *bucket;
+	unsigned long sysino;
+
+	sysino = sun4v_devino_to_sysino(devhandle, devino);
+
+	bucket = &ivector_table[sysino];
+
+	/* Catch accidental accesses to these things.  IMAP/ICLR handling
+	 * is done by hypervisor calls on sun4v platforms, not by direct
+	 * register accesses.
+	 *
+	 * But we need to make them look unique for the disable_irq() logic
+	 * in free_irq().
+	 */
+	bucket->imap = ~0UL - sysino;
+	bucket->iclr = ~0UL - sysino;
+
+	bucket->pil = pil;
+	bucket->flags = flags;
+
+	bucket->irq_info = kmalloc(sizeof(struct irq_desc), GFP_ATOMIC);
+	if (!bucket->irq_info) {
+		prom_printf("IRQ: Error, kmalloc(irq_desc) failed.\n");
+		prom_halt();
+	}
+	memset(bucket->irq_info, 0, sizeof(struct irq_desc));
+
+	return __irq(bucket);
+}
+
 static void atomic_bucket_insert(struct ino_bucket *bucket)
 {
 	unsigned long pstate;
@@ -482,7 +555,6 @@
 	bucket = __bucket(irq);
 	if (bucket != &pil0_dummy_bucket) {
 		struct irq_desc *desc = bucket->irq_info;
-		unsigned long imap = bucket->imap;
 		int ent, i;
 
 		for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) {
@@ -495,6 +567,8 @@
 		}
 
 		if (!desc->action_active_mask) {
+			unsigned long imap = bucket->imap;
+
 			/* This unique interrupt source is now inactive. */
 			bucket->flags &= ~IBF_ACTIVE;
 
@@ -592,7 +666,18 @@
 			break;
 	}
 	if (bp->pil != 0) {
-		upa_writel(ICLR_IDLE, bp->iclr);
+		if (tlb_type == hypervisor) {
+			unsigned int ino = __irq_ino(bp);
+			int err;
+
+			err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
+			if (err != HV_EOK)
+				printk("sun4v_intr_setstate(%x): "
+				       "err(%d)\n", ino, err);
+		} else {
+			upa_writel(ICLR_IDLE, bp->iclr);
+		}
+
 		/* Test and add entropy */
 		if (random & SA_SAMPLE_RANDOM)
 			add_interrupt_randomness(irq);
@@ -727,25 +812,23 @@
 static int retarget_one_irq(struct irqaction *p, int goal_cpu)
 {
 	struct ino_bucket *bucket = get_ino_in_irqaction(p) + ivector_table;
-	unsigned long imap = bucket->imap;
-	unsigned int tid;
 
 	while (!cpu_online(goal_cpu)) {
 		if (++goal_cpu >= NR_CPUS)
 			goal_cpu = 0;
 	}
 
-	if (tlb_type == cheetah || tlb_type == cheetah_plus) {
-		tid = goal_cpu << 26;
-		tid &= IMAP_AID_SAFARI;
-	} else if (this_is_starfire == 0) {
-		tid = goal_cpu << 26;
-		tid &= IMAP_TID_UPA;
+	if (tlb_type == hypervisor) {
+		unsigned int ino = __irq_ino(bucket);
+
+		sun4v_intr_settarget(ino, goal_cpu);
+		sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
 	} else {
-		tid = (starfire_translate(imap, goal_cpu) << 26);
-		tid &= IMAP_TID_UPA;
+		unsigned long imap = bucket->imap;
+		unsigned int tid = sun4u_compute_tid(imap, goal_cpu);
+
+		upa_writel(tid | IMAP_VALID, imap);
 	}
-	upa_writel(tid | IMAP_VALID, imap);
 
 	do {
 		if (++goal_cpu >= NR_CPUS)
@@ -848,33 +931,114 @@
 
 void init_irqwork_curcpu(void)
 {
-	register struct irq_work_struct *workp asm("o2");
-	register unsigned long tmp asm("o3");
 	int cpu = hard_smp_processor_id();
 
-	memset(__irq_work + cpu, 0, sizeof(*workp));
+	memset(__irq_work + cpu, 0, sizeof(struct irq_work_struct));
+}
+
+static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type)
+{
+	unsigned long num_entries = 128;
+	unsigned long status;
+
+	status = sun4v_cpu_qconf(type, paddr, num_entries);
+	if (status != HV_EOK) {
+		prom_printf("SUN4V: sun4v_cpu_qconf(%lu:%lx:%lu) failed, "
+			    "err %lu\n", type, paddr, num_entries, status);
+		prom_halt();
+	}
+}
+
+static void __cpuinit sun4v_register_mondo_queues(int this_cpu)
+{
+	struct trap_per_cpu *tb = &trap_block[this_cpu];
+
+	register_one_mondo(tb->cpu_mondo_pa, HV_CPU_QUEUE_CPU_MONDO);
+	register_one_mondo(tb->dev_mondo_pa, HV_CPU_QUEUE_DEVICE_MONDO);
+	register_one_mondo(tb->resum_mondo_pa, HV_CPU_QUEUE_RES_ERROR);
+	register_one_mondo(tb->nonresum_mondo_pa, HV_CPU_QUEUE_NONRES_ERROR);
+}
 
-	/* Make sure we are called with PSTATE_IE disabled.  */
-	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
-			     : "=r" (tmp));
-	if (tmp & PSTATE_IE) {
-		prom_printf("BUG: init_irqwork_curcpu() called with "
-			    "PSTATE_IE enabled, bailing.\n");
-		__asm__ __volatile__("mov	%%i7, %0\n\t"
-				     : "=r" (tmp));
-		prom_printf("BUG: Called from %lx\n", tmp);
+static void __cpuinit alloc_one_mondo(unsigned long *pa_ptr, int use_bootmem)
+{
+	void *page;
+
+	if (use_bootmem)
+		page = alloc_bootmem_low_pages(PAGE_SIZE);
+	else
+		page = (void *) get_zeroed_page(GFP_ATOMIC);
+
+	if (!page) {
+		prom_printf("SUN4V: Error, cannot allocate mondo queue.\n");
 		prom_halt();
 	}
 
-	/* Set interrupt globals.  */
-	workp = &__irq_work[cpu];
-	__asm__ __volatile__(
-	"rdpr	%%pstate, %0\n\t"
-	"wrpr	%0, %1, %%pstate\n\t"
-	"mov	%2, %%g6\n\t"
-	"wrpr	%0, 0x0, %%pstate\n\t"
-	: "=&r" (tmp)
-	: "i" (PSTATE_IG), "r" (workp));
+	*pa_ptr = __pa(page);
+}
+
+static void __cpuinit alloc_one_kbuf(unsigned long *pa_ptr, int use_bootmem)
+{
+	void *page;
+
+	if (use_bootmem)
+		page = alloc_bootmem_low_pages(PAGE_SIZE);
+	else
+		page = (void *) get_zeroed_page(GFP_ATOMIC);
+
+	if (!page) {
+		prom_printf("SUN4V: Error, cannot allocate kbuf page.\n");
+		prom_halt();
+	}
+
+	*pa_ptr = __pa(page);
+}
+
+static void __cpuinit init_cpu_send_mondo_info(struct trap_per_cpu *tb, int use_bootmem)
+{
+#ifdef CONFIG_SMP
+	void *page;
+
+	BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64));
+
+	if (use_bootmem)
+		page = alloc_bootmem_low_pages(PAGE_SIZE);
+	else
+		page = (void *) get_zeroed_page(GFP_ATOMIC);
+
+	if (!page) {
+		prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n");
+		prom_halt();
+	}
+
+	tb->cpu_mondo_block_pa = __pa(page);
+	tb->cpu_list_pa = __pa(page + 64);
+#endif
+}
+
+/* Allocate and register the mondo and error queues for this cpu.  */
+void __cpuinit sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load)
+{
+	struct trap_per_cpu *tb = &trap_block[cpu];
+
+	if (alloc) {
+		alloc_one_mondo(&tb->cpu_mondo_pa, use_bootmem);
+		alloc_one_mondo(&tb->dev_mondo_pa, use_bootmem);
+		alloc_one_mondo(&tb->resum_mondo_pa, use_bootmem);
+		alloc_one_kbuf(&tb->resum_kernel_buf_pa, use_bootmem);
+		alloc_one_mondo(&tb->nonresum_mondo_pa, use_bootmem);
+		alloc_one_kbuf(&tb->nonresum_kernel_buf_pa, use_bootmem);
+
+		init_cpu_send_mondo_info(tb, use_bootmem);
+	}
+
+	if (load) {
+		if (cpu != hard_smp_processor_id()) {
+			prom_printf("SUN4V: init mondo on cpu %d not %d\n",
+				    cpu, hard_smp_processor_id());
+			prom_halt();
+		}
+		sun4v_register_mondo_queues(cpu);
+	}
 }
 
 /* Only invoked on boot processor. */
@@ -884,6 +1048,9 @@
 	kill_prom_timer();
 	memset(&ivector_table[0], 0, sizeof(ivector_table));
 
+	if (tlb_type == hypervisor)
+		sun4v_init_mondo_queues(1, hard_smp_processor_id(), 1, 1);
+
 	/* We need to clear any IRQ's pending in the soft interrupt
 	 * registers, a spurious one could be left around from the
 	 * PROM timer which we just disabled.
diff -urN oldtree/arch/sparc64/kernel/itlb_base.S newtree/arch/sparc64/kernel/itlb_base.S
--- oldtree/arch/sparc64/kernel/itlb_base.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/kernel/itlb_base.S	1970-01-01 00:00:00.000000000 +0000
@@ -1,79 +0,0 @@
-/* $Id: itlb_base.S,v 1.12 2002/02/09 19:49:30 davem Exp $
- * itlb_base.S:	Front end to ITLB miss replacement strategy.
- *              This is included directly into the trap table.
- *
- * Copyright (C) 1996,1998 David S. Miller (davem@redhat.com)
- * Copyright (C) 1997,1998 Jakub Jelinek   (jj@ultra.linux.cz)
- */
-
-#if PAGE_SHIFT == 13
-/*
- * To compute vpte offset, we need to do ((addr >> 13) << 3),
- * which can be optimized to (addr >> 10) if bits 10/11/12 can
- * be guaranteed to be 0 ... mmu_context.h does guarantee this
- * by only using 10 bits in the hwcontext value.
- */
-#define CREATE_VPTE_OFFSET1(r1, r2) \
-				srax	r1, 10, r2
-#define CREATE_VPTE_OFFSET2(r1, r2) nop
-#else /* PAGE_SHIFT */
-#define CREATE_VPTE_OFFSET1(r1, r2) \
-				srax	r1, PAGE_SHIFT, r2
-#define CREATE_VPTE_OFFSET2(r1, r2) \
-				sllx	r2, 3, r2
-#endif /* PAGE_SHIFT */
-
-
-/* Ways we can get here:
- *
- * 1) Nucleus instruction misses from module code.
- * 2) All user instruction misses.
- *
- * All real page faults merge their code paths to the
- * sparc64_realfault_common label below.
- */
-
-/* ITLB ** ICACHE line 1: Quick user TLB misses		*/
-	mov		TLB_SFSR, %g1
-	ldxa		[%g1 + %g1] ASI_IMMU, %g4	! Get TAG_ACCESS
-	CREATE_VPTE_OFFSET1(%g4, %g6)			! Create VPTE offset
-	CREATE_VPTE_OFFSET2(%g4, %g6)			! Create VPTE offset
-	ldxa		[%g3 + %g6] ASI_P, %g5		! Load VPTE
-1:	brgez,pn	%g5, 3f				! Not valid, branch out
-	 sethi		%hi(_PAGE_EXEC), %g4		! Delay-slot
-	andcc		%g5, %g4, %g0			! Executable?
-
-/* ITLB ** ICACHE line 2: Real faults			*/
-	be,pn		%xcc, 3f			! Nope, branch.
-	 nop						! Delay-slot
-2:	stxa		%g5, [%g0] ASI_ITLB_DATA_IN	! Load PTE into TLB
-	retry						! Trap return
-3:	rdpr		%pstate, %g4			! Move into alt-globals
-	wrpr		%g4, PSTATE_AG|PSTATE_MG, %pstate
-	rdpr		%tpc, %g5			! And load faulting VA
-	mov		FAULT_CODE_ITLB, %g4		! It was read from ITLB
-
-/* ITLB ** ICACHE line 3: Finish faults	*/
-sparc64_realfault_common:				! Called by dtlb_miss
-	stb		%g4, [%g6 + TI_FAULT_CODE]
-	stx		%g5, [%g6 + TI_FAULT_ADDR]
-	ba,pt		%xcc, etrap			! Save state
-1:	 rd		%pc, %g7			! ...
-	call		do_sparc64_fault		! Call fault handler
-	 add		%sp, PTREGS_OFF, %o0! Compute pt_regs arg
-	ba,pt		%xcc, rtrap_clr_l6		! Restore cpu state
-	 nop
-
-/* ITLB ** ICACHE line 4: Window fixups */
-winfix_trampoline:
-	rdpr		%tpc, %g3			! Prepare winfixup TNPC
-	or		%g3, 0x7c, %g3			! Compute branch offset
-	wrpr		%g3, %tnpc			! Write it into TNPC
-	done						! Do it to it
-	nop
-	nop
-	nop
-	nop
-
-#undef CREATE_VPTE_OFFSET1
-#undef CREATE_VPTE_OFFSET2
diff -urN oldtree/arch/sparc64/kernel/itlb_miss.S newtree/arch/sparc64/kernel/itlb_miss.S
--- oldtree/arch/sparc64/kernel/itlb_miss.S	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/sparc64/kernel/itlb_miss.S	2006-02-21 15:58:20.210074160 +0000
@@ -0,0 +1,39 @@
+/* ITLB ** ICACHE line 1: Context 0 check and TSB load	*/
+	ldxa	[%g0] ASI_IMMU_TSB_8KB_PTR, %g1	! Get TSB 8K pointer
+	ldxa	[%g0] ASI_IMMU, %g6		! Get TAG TARGET
+	srlx	%g6, 48, %g5			! Get context
+	sllx	%g6, 22, %g6			! Zero out context
+	brz,pn	%g5, kvmap_itlb			! Context 0 processing
+	 srlx	%g6, 22, %g6			! Delay slot
+	TSB_LOAD_QUAD(%g1, %g4)			! Load TSB entry
+	cmp	%g4, %g6			! Compare TAG
+
+/* ITLB ** ICACHE line 2: TSB compare and TLB load	*/
+	sethi	%hi(PAGE_EXEC), %g4		! Setup exec check
+	ldx	[%g4 + %lo(PAGE_EXEC)], %g4
+	bne,pn	%xcc, tsb_miss_itlb		! Miss
+	 mov	FAULT_CODE_ITLB, %g3
+	andcc	%g5, %g4, %g0			! Executable?
+	be,pn	%xcc, tsb_do_fault
+	 nop					! Delay slot, fill me
+	nop
+
+/* ITLB ** ICACHE line 3: 				*/
+	stxa	%g5, [%g0] ASI_ITLB_DATA_IN	! Load TLB
+	retry					! Trap done
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+/* ITLB ** ICACHE line 4: 				*/
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
diff -urN oldtree/arch/sparc64/kernel/ktlb.S newtree/arch/sparc64/kernel/ktlb.S
--- oldtree/arch/sparc64/kernel/ktlb.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/kernel/ktlb.S	2006-02-21 15:58:20.211074008 +0000
@@ -4,191 +4,237 @@
  * Copyright (C) 1996 Eddie C. Dost        (ecd@brainaid.de)
  * Copyright (C) 1996 Miguel de Icaza      (miguel@nuclecu.unam.mx)
  * Copyright (C) 1996,98,99 Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
-*/
+ */
 
 #include <linux/config.h>
 #include <asm/head.h>
 #include <asm/asi.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/tsb.h>
 
 	.text
 	.align		32
 
-/*
- * On a second level vpte miss, check whether the original fault is to the OBP 
- * range (note that this is only possible for instruction miss, data misses to
- * obp range do not use vpte). If so, go back directly to the faulting address.
- * This is because we want to read the tpc, otherwise we have no way of knowing
- * the 8k aligned faulting address if we are using >8k kernel pagesize. This
- * also ensures no vpte range addresses are dropped into tlb while obp is
- * executing (see inherit_locked_prom_mappings() rant).
- */
-sparc64_vpte_nucleus:
-	/* Note that kvmap below has verified that the address is
-	 * in the range MODULES_VADDR --> VMALLOC_END already.  So
-	 * here we need only check if it is an OBP address or not.
+kvmap_itlb:
+	/* g6: TAG TARGET */
+	mov		TLB_TAG_ACCESS, %g4
+	ldxa		[%g4] ASI_IMMU, %g4
+
+	/* sun4v_itlb_miss branches here with the missing virtual
+	 * address already loaded into %g4
 	 */
+kvmap_itlb_4v:
+
+kvmap_itlb_nonlinear:
+	/* Catch kernel NULL pointer calls.  */
+	sethi		%hi(PAGE_SIZE), %g5
+	cmp		%g4, %g5
+	bleu,pn		%xcc, kvmap_dtlb_longpath
+	 nop
+
+	KERN_TSB_LOOKUP_TL1(%g4, %g6, %g5, %g1, %g2, %g3, kvmap_itlb_load)
+
+kvmap_itlb_tsb_miss:
 	sethi		%hi(LOW_OBP_ADDRESS), %g5
 	cmp		%g4, %g5
-	blu,pn		%xcc, kern_vpte
+	blu,pn		%xcc, kvmap_itlb_vmalloc_addr
 	 mov		0x1, %g5
 	sllx		%g5, 32, %g5
 	cmp		%g4, %g5
-	blu,pn		%xcc, vpte_insn_obp
+	blu,pn		%xcc, kvmap_itlb_obp
 	 nop
 
-	/* These two instructions are patched by paginig_init().  */
-kern_vpte:
-	sethi		%hi(swapper_pgd_zero), %g5
-	lduw		[%g5 + %lo(swapper_pgd_zero)], %g5
-
-	/* With kernel PGD in %g5, branch back into dtlb_backend.  */
-	ba,pt		%xcc, sparc64_kpte_continue
-	 andn		%g1, 0x3, %g1	/* Finish PMD offset adjustment.  */
-
-vpte_noent:
-	/* Restore previous TAG_ACCESS, %g5 is zero, and we will
-	 * skip over the trap instruction so that the top level
-	 * TLB miss handler will thing this %g5 value is just an
-	 * invalid PTE, thus branching to full fault processing.
-	 */
-	mov		TLB_SFSR, %g1
-	stxa		%g4, [%g1 + %g1] ASI_DMMU
-	done
-
-vpte_insn_obp:
-	/* Behave as if we are at TL0.  */
-	wrpr		%g0, 1, %tl
-	rdpr		%tpc, %g4	/* Find original faulting iaddr */
-	srlx		%g4, 13, %g4	/* Throw out context bits */
-	sllx		%g4, 13, %g4	/* g4 has vpn + ctx0 now */
-
-	/* Restore previous TAG_ACCESS.  */
-	mov		TLB_SFSR, %g1
-	stxa		%g4, [%g1 + %g1] ASI_IMMU
-
-	sethi		%hi(prom_trans), %g5
-	or		%g5, %lo(prom_trans), %g5
-
-1:	ldx		[%g5 + 0x00], %g6	! base
-	brz,a,pn	%g6, longpath		! no more entries, fail
-	 mov		TLB_SFSR, %g1		! and restore %g1
-	ldx		[%g5 + 0x08], %g1	! len
-	add		%g6, %g1, %g1		! end
-	cmp		%g6, %g4
-	bgu,pt		%xcc, 2f
-	 cmp		%g4, %g1
-	bgeu,pt		%xcc, 2f
-	 ldx		[%g5 + 0x10], %g1	! PTE
-
-	/* TLB load, restore %g1, and return from trap.  */
-	sub		%g4, %g6, %g6
-	add		%g1, %g6, %g5
-	mov		TLB_SFSR, %g1
-	stxa		%g5, [%g0] ASI_ITLB_DATA_IN
-	retry
+kvmap_itlb_vmalloc_addr:
+	KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_itlb_longpath)
+
+	KTSB_LOCK_TAG(%g1, %g2, %g7)
+
+	/* Load and check PTE.  */
+	ldxa		[%g5] ASI_PHYS_USE_EC, %g5
+	mov		1, %g7
+	sllx		%g7, TSB_TAG_INVALID_BIT, %g7
+	brgez,a,pn	%g5, kvmap_itlb_longpath
+	 KTSB_STORE(%g1, %g7)
 
-2:	ba,pt		%xcc, 1b
-	 add		%g5, (3 * 8), %g5	! next entry
+	KTSB_WRITE(%g1, %g5, %g6)
 
-kvmap_do_obp:
-	sethi		%hi(prom_trans), %g5
-	or		%g5, %lo(prom_trans), %g5
-	srlx		%g4, 13, %g4
-	sllx		%g4, 13, %g4
-
-1:	ldx		[%g5 + 0x00], %g6	! base
-	brz,a,pn	%g6, longpath		! no more entries, fail
-	 mov		TLB_SFSR, %g1		! and restore %g1
-	ldx		[%g5 + 0x08], %g1	! len
-	add		%g6, %g1, %g1		! end
-	cmp		%g6, %g4
-	bgu,pt		%xcc, 2f
-	 cmp		%g4, %g1
-	bgeu,pt		%xcc, 2f
-	 ldx		[%g5 + 0x10], %g1	! PTE
-
-	/* TLB load, restore %g1, and return from trap.  */
-	sub		%g4, %g6, %g6
-	add		%g1, %g6, %g5
-	mov		TLB_SFSR, %g1
-	stxa		%g5, [%g0] ASI_DTLB_DATA_IN
+	/* fallthrough to TLB load */
+
+kvmap_itlb_load:
+
+661:	stxa		%g5, [%g0] ASI_ITLB_DATA_IN
 	retry
+	.section	.sun4v_2insn_patch, "ax"
+	.word		661b
+	nop
+	nop
+	.previous
+
+	/* For sun4v the ASI_ITLB_DATA_IN store and the retry
+	 * instruction get nop'd out and we get here to branch
+	 * to the sun4v tlb load code.  The registers are setup
+	 * as follows:
+	 *
+	 * %g4: vaddr
+	 * %g5: PTE
+	 * %g6:	TAG
+	 *
+	 * The sun4v TLB load wants the PTE in %g3 so we fix that
+	 * up here.
+	 */
+	ba,pt		%xcc, sun4v_itlb_load
+	 mov		%g5, %g3
 
-2:	ba,pt		%xcc, 1b
-	 add		%g5, (3 * 8), %g5	! next entry
+kvmap_itlb_longpath:
+
+661:	rdpr	%pstate, %g5
+	wrpr	%g5, PSTATE_AG | PSTATE_MG, %pstate
+	.section .sun4v_2insn_patch, "ax"
+	.word	661b
+	SET_GL(1)
+	nop
+	.previous
+
+	rdpr	%tpc, %g5
+	ba,pt	%xcc, sparc64_realfault_common
+	 mov	FAULT_CODE_ITLB, %g4
+
+kvmap_itlb_obp:
+	OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_itlb_longpath)
+
+	KTSB_LOCK_TAG(%g1, %g2, %g7)
+
+	KTSB_WRITE(%g1, %g5, %g6)
+
+	ba,pt		%xcc, kvmap_itlb_load
+	 nop
+
+kvmap_dtlb_obp:
+	OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_dtlb_longpath)
+
+	KTSB_LOCK_TAG(%g1, %g2, %g7)
+
+	KTSB_WRITE(%g1, %g5, %g6)
+
+	ba,pt		%xcc, kvmap_dtlb_load
+	 nop
 
-/*
- * On a first level data miss, check whether this is to the OBP range (note
- * that such accesses can be made by prom, as well as by kernel using
- * prom_getproperty on "address"), and if so, do not use vpte access ...
- * rather, use information saved during inherit_prom_mappings() using 8k
- * pagesize.
- */
 	.align		32
-kvmap:
-	brgez,pn	%g4, kvmap_nonlinear
+kvmap_dtlb:
+	/* %g6: TAG TARGET */
+	mov		TLB_TAG_ACCESS, %g4
+	ldxa		[%g4] ASI_DMMU, %g4
+
+	/* sun4v_dtlb_miss branches here with the missing virtual
+	 * address already loaded into %g4
+	 */
+kvmap_dtlb_4v:
+	brgez,pn	%g4, kvmap_dtlb_nonlinear
 	 nop
 
-#ifdef CONFIG_DEBUG_PAGEALLOC
+	sethi		%hi(kern_linear_pte_xor), %g2
+	ldx		[%g2 + %lo(kern_linear_pte_xor)], %g2
+
 	.globl		kvmap_linear_patch
 kvmap_linear_patch:
-#endif
-	ba,pt		%xcc, kvmap_load
+	ba,pt		%xcc, kvmap_dtlb_load
 	 xor		%g2, %g4, %g5
 
-#ifdef CONFIG_DEBUG_PAGEALLOC
-	sethi		%hi(swapper_pg_dir), %g5
-	or		%g5, %lo(swapper_pg_dir), %g5
-	sllx		%g4, 64 - (PGDIR_SHIFT + PGDIR_BITS), %g6
-	srlx		%g6, 64 - PAGE_SHIFT, %g6
-	andn		%g6, 0x3, %g6
-	lduw		[%g5 + %g6], %g5
-	brz,pn		%g5, longpath
-	 sllx		%g4, 64 - (PMD_SHIFT + PMD_BITS), %g6
-	srlx		%g6, 64 - PAGE_SHIFT, %g6
-	sllx		%g5, 11, %g5
-	andn		%g6, 0x3, %g6
-	lduwa		[%g5 + %g6] ASI_PHYS_USE_EC, %g5
-	brz,pn		%g5, longpath
-	 sllx		%g4, 64 - PMD_SHIFT, %g6
-	srlx		%g6, 64 - PAGE_SHIFT, %g6
-	sllx		%g5, 11, %g5
-	andn		%g6, 0x7, %g6
-	ldxa		[%g5 + %g6] ASI_PHYS_USE_EC, %g5
-	brz,pn		%g5, longpath
+kvmap_dtlb_vmalloc_addr:
+	KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_dtlb_longpath)
+
+	KTSB_LOCK_TAG(%g1, %g2, %g7)
+
+	/* Load and check PTE.  */
+	ldxa		[%g5] ASI_PHYS_USE_EC, %g5
+	mov		1, %g7
+	sllx		%g7, TSB_TAG_INVALID_BIT, %g7
+	brgez,a,pn	%g5, kvmap_dtlb_longpath
+	 KTSB_STORE(%g1, %g7)
+
+	KTSB_WRITE(%g1, %g5, %g6)
+
+	/* fallthrough to TLB load */
+
+kvmap_dtlb_load:
+
+661:	stxa		%g5, [%g0] ASI_DTLB_DATA_IN	! Reload TLB
+	retry
+	.section	.sun4v_2insn_patch, "ax"
+	.word		661b
+	nop
+	nop
+	.previous
+
+	/* For sun4v the ASI_DTLB_DATA_IN store and the retry
+	 * instruction get nop'd out and we get here to branch
+	 * to the sun4v tlb load code.  The registers are setup
+	 * as follows:
+	 *
+	 * %g4: vaddr
+	 * %g5: PTE
+	 * %g6:	TAG
+	 *
+	 * The sun4v TLB load wants the PTE in %g3 so we fix that
+	 * up here.
+	 */
+	ba,pt		%xcc, sun4v_dtlb_load
+	 mov		%g5, %g3
+
+kvmap_dtlb_nonlinear:
+	/* Catch kernel NULL pointer derefs.  */
+	sethi		%hi(PAGE_SIZE), %g5
+	cmp		%g4, %g5
+	bleu,pn		%xcc, kvmap_dtlb_longpath
 	 nop
-	ba,a,pt		%xcc, kvmap_load
-#endif
 
-kvmap_nonlinear:
+	KERN_TSB_LOOKUP_TL1(%g4, %g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load)
+
+kvmap_dtlb_tsbmiss:
 	sethi		%hi(MODULES_VADDR), %g5
 	cmp		%g4, %g5
-	blu,pn		%xcc, longpath
+	blu,pn		%xcc, kvmap_dtlb_longpath
 	 mov		(VMALLOC_END >> 24), %g5
 	sllx		%g5, 24, %g5
 	cmp		%g4, %g5
-	bgeu,pn		%xcc, longpath
+	bgeu,pn		%xcc, kvmap_dtlb_longpath
 	 nop
 
 kvmap_check_obp:
 	sethi		%hi(LOW_OBP_ADDRESS), %g5
 	cmp		%g4, %g5
-	blu,pn		%xcc, kvmap_vmalloc_addr
+	blu,pn		%xcc, kvmap_dtlb_vmalloc_addr
 	 mov		0x1, %g5
 	sllx		%g5, 32, %g5
 	cmp		%g4, %g5
-	blu,pn		%xcc, kvmap_do_obp
+	blu,pn		%xcc, kvmap_dtlb_obp
 	 nop
-
-kvmap_vmalloc_addr:
-	/* If we get here, a vmalloc addr was accessed, load kernel VPTE.  */
-	ldxa		[%g3 + %g6] ASI_N, %g5
-	brgez,pn	%g5, longpath
+	ba,pt		%xcc, kvmap_dtlb_vmalloc_addr
 	 nop
 
-kvmap_load:
-	/* PTE is valid, load into TLB and return from trap.  */
-	stxa		%g5, [%g0] ASI_DTLB_DATA_IN	! Reload TLB
-	retry
+kvmap_dtlb_longpath:
+
+661:	rdpr	%pstate, %g5
+	wrpr	%g5, PSTATE_AG | PSTATE_MG, %pstate
+	.section .sun4v_2insn_patch, "ax"
+	.word	661b
+	SET_GL(1)
+	ldxa		[%g0] ASI_SCRATCHPAD, %g5
+	.previous
+
+	rdpr	%tl, %g3
+	cmp	%g3, 1
+
+661:	mov	TLB_TAG_ACCESS, %g4
+	ldxa	[%g4] ASI_DMMU, %g5
+	.section .sun4v_2insn_patch, "ax"
+	.word	661b
+	ldx	[%g5 + HV_FAULT_D_ADDR_OFFSET], %g5
+	nop
+	.previous
+
+	be,pt	%xcc, sparc64_realfault_common
+	 mov	FAULT_CODE_DTLB, %g4
+	ba,pt	%xcc, winfix_trampoline
+	 nop
diff -urN oldtree/arch/sparc64/kernel/pci.c newtree/arch/sparc64/kernel/pci.c
--- oldtree/arch/sparc64/kernel/pci.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/kernel/pci.c	2006-02-21 15:58:20.212073856 +0000
@@ -188,6 +188,7 @@
 extern void schizo_init(int, char *);
 extern void schizo_plus_init(int, char *);
 extern void tomatillo_init(int, char *);
+extern void sun4v_pci_init(int, char *);
 
 static struct {
 	char *model_name;
@@ -204,6 +205,7 @@
 	{ "pci108e,8002", schizo_plus_init },
 	{ "SUNW,tomatillo", tomatillo_init },
 	{ "pci108e,a801", tomatillo_init },
+	{ "SUNW,sun4v-pci", sun4v_pci_init },
 };
 #define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \
 				  sizeof(pci_controller_table[0]))
@@ -283,6 +285,12 @@
 	return pci_controller_scan(pci_is_controller);
 }
 
+struct pci_iommu_ops *pci_iommu_ops;
+EXPORT_SYMBOL(pci_iommu_ops);
+
+extern struct pci_iommu_ops pci_sun4u_iommu_ops,
+	pci_sun4v_iommu_ops;
+
 /* Find each controller in the system, attach and initialize
  * software state structure for each and link into the
  * pci_controller_root.  Setup the controller enough such
@@ -290,6 +298,11 @@
  */
 static void __init pci_controller_probe(void)
 {
+	if (tlb_type == hypervisor)
+		pci_iommu_ops = &pci_sun4v_iommu_ops;
+	else
+		pci_iommu_ops = &pci_sun4u_iommu_ops;
+
 	printk("PCI: Probing for controllers.\n");
 
 	pci_controller_scan(pci_controller_init);
diff -urN oldtree/arch/sparc64/kernel/pci_common.c newtree/arch/sparc64/kernel/pci_common.c
--- oldtree/arch/sparc64/kernel/pci_common.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/kernel/pci_common.c	2006-02-21 15:58:20.213073704 +0000
@@ -39,6 +39,8 @@
 {
 	int node;
 
+	*nregs = 0;
+
 	/*
 	 * Return the PBM's PROM node in case we are it's PCI device,
 	 * as the PBM's reg property is different to standard PCI reg
@@ -51,10 +53,8 @@
 	     pdev->device == PCI_DEVICE_ID_SUN_SCHIZO ||
 	     pdev->device == PCI_DEVICE_ID_SUN_TOMATILLO ||
 	     pdev->device == PCI_DEVICE_ID_SUN_SABRE ||
-	     pdev->device == PCI_DEVICE_ID_SUN_HUMMINGBIRD)) {
-		*nregs = 0;
+	     pdev->device == PCI_DEVICE_ID_SUN_HUMMINGBIRD))
 		return bus_prom_node;
-	}
 
 	node = prom_getchild(bus_prom_node);
 	while (node != 0) {
@@ -541,135 +541,183 @@
 		pci_assign_unassigned(pbm, bus);
 }
 
-static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt)
-{
-	struct linux_prom_pci_intmap bridge_local_intmap[PROM_PCIIMAP_MAX], *intmap;
-	struct linux_prom_pci_intmask bridge_local_intmask, *intmask;
-	struct pcidev_cookie *dev_pcp = pdev->sysdata;
-	struct pci_pbm_info *pbm = dev_pcp->pbm;
-	struct linux_prom_pci_registers *pregs = dev_pcp->prom_regs;
-	unsigned int hi, mid, lo, irq;
-	int i, num_intmap, map_slot;
+static inline unsigned int pci_slot_swivel(struct pci_pbm_info *pbm,
+					   struct pci_dev *toplevel_pdev,
+					   struct pci_dev *pdev,
+					   unsigned int interrupt)
+{
+	unsigned int ret;
+
+	if (unlikely(interrupt < 1 || interrupt > 4)) {
+		printk("%s: Device %s interrupt value of %u is strange.\n",
+		       pbm->name, pci_name(pdev), interrupt);
+		return interrupt;
+	}
+
+	ret = ((interrupt - 1 + (PCI_SLOT(pdev->devfn) & 3)) & 3) + 1;
+
+	printk("%s: %s IRQ Swivel %s [%x:%x] -> [%x]\n",
+	       pbm->name, pci_name(toplevel_pdev), pci_name(pdev),
+	       interrupt, PCI_SLOT(pdev->devfn), ret);
+
+	return ret;
+}
+
+static inline unsigned int pci_apply_intmap(struct pci_pbm_info *pbm,
+					    struct pci_dev *toplevel_pdev,
+					    struct pci_dev *pbus,
+					    struct pci_dev *pdev,
+					    unsigned int interrupt,
+					    unsigned int *cnode)
+{
+	struct linux_prom_pci_intmap imap[PROM_PCIIMAP_MAX];
+	struct linux_prom_pci_intmask imask;
+	struct pcidev_cookie *pbus_pcp = pbus->sysdata;
+	struct pcidev_cookie *pdev_pcp = pdev->sysdata;
+	struct linux_prom_pci_registers *pregs = pdev_pcp->prom_regs;
+	int plen, num_imap, i;
+	unsigned int hi, mid, lo, irq, orig_interrupt;
+
+	*cnode = pbus_pcp->prom_node;
+
+	plen = prom_getproperty(pbus_pcp->prom_node, "interrupt-map",
+				(char *) &imap[0], sizeof(imap));
+	if (plen <= 0 ||
+	    (plen % sizeof(struct linux_prom_pci_intmap)) != 0) {
+		printk("%s: Device %s interrupt-map has bad len %d\n",
+		       pbm->name, pci_name(pbus), plen);
+		goto no_intmap;
+	}
+	num_imap = plen / sizeof(struct linux_prom_pci_intmap);
+
+	plen = prom_getproperty(pbus_pcp->prom_node, "interrupt-map-mask",
+				(char *) &imask, sizeof(imask));
+	if (plen <= 0 ||
+	    (plen % sizeof(struct linux_prom_pci_intmask)) != 0) {
+		printk("%s: Device %s interrupt-map-mask has bad len %d\n",
+		       pbm->name, pci_name(pbus), plen);
+		goto no_intmap;
+	}
+
+	orig_interrupt = interrupt;
+
+	hi   = pregs->phys_hi & imask.phys_hi;
+	mid  = pregs->phys_mid & imask.phys_mid;
+	lo   = pregs->phys_lo & imask.phys_lo;
+	irq  = interrupt & imask.interrupt;
+
+	for (i = 0; i < num_imap; i++) {
+		if (imap[i].phys_hi  == hi   &&
+		    imap[i].phys_mid == mid  &&
+		    imap[i].phys_lo  == lo   &&
+		    imap[i].interrupt == irq) {
+			*cnode = imap[i].cnode;
+			interrupt = imap[i].cinterrupt;
+		}
+	}
 
-	intmap = &pbm->pbm_intmap[0];
-	intmask = &pbm->pbm_intmask;
-	num_intmap = pbm->num_pbm_intmap;
-	map_slot = 0;
-
-	/* If we are underneath a PCI bridge, use PROM register
-	 * property of the parent bridge which is closest to
-	 * the PBM.
-	 *
-	 * However if that parent bridge has interrupt map/mask
-	 * properties of its own we use the PROM register property
-	 * of the next child device on the path to PDEV.
-	 *
-	 * In detail the two cases are (note that the 'X' below is the
-	 * 'next child on the path to PDEV' mentioned above):
-	 *
-	 * 1) PBM --> PCI bus lacking int{map,mask} --> X ... PDEV
-	 *
-	 *    Here we use regs of 'PCI bus' device.
-	 *
-	 * 2) PBM --> PCI bus with int{map,mask} --> X ... PDEV
-	 *
-	 *    Here we use regs of 'X'.  Note that X can be PDEV.
-	 */
-	if (pdev->bus->number != pbm->pci_first_busno) {
-		struct pcidev_cookie *bus_pcp, *regs_pcp;
-		struct pci_dev *bus_dev, *regs_dev;
+	printk("%s: %s MAP BUS %s DEV %s [%x] -> [%x]\n",
+	       pbm->name, pci_name(toplevel_pdev),
+	       pci_name(pbus), pci_name(pdev),
+	       orig_interrupt, interrupt);
+
+no_intmap:
+	return interrupt;
+}
+
+/* For each PCI bus on the way to the root:
+ * 1) If it has an interrupt-map property, apply it.
+ * 2) Else, swivel the interrupt number based upon the PCI device number.
+ *
+ * Return the "IRQ controller" node.  If this is the PBM's device node,
+ * all interrupt translations are complete, else we should use that node's
+ * "reg" property to apply the PBM's "interrupt-{map,mask}" to the interrupt.
+ */
+static unsigned int __init pci_intmap_match_to_root(struct pci_pbm_info *pbm,
+						    struct pci_dev *pdev,
+						    unsigned int *interrupt)
+{
+	struct pci_dev *toplevel_pdev = pdev;
+	struct pcidev_cookie *toplevel_pcp = toplevel_pdev->sysdata;
+	unsigned int cnode = toplevel_pcp->prom_node;
+
+	while (pdev->bus->number != pbm->pci_first_busno) {
+		struct pci_dev *pbus = pdev->bus->self;
+		struct pcidev_cookie *pcp = pbus->sysdata;
 		int plen;
 
-		bus_dev = pdev->bus->self;
-		regs_dev = pdev;
-
-		while (bus_dev->bus &&
-		       bus_dev->bus->number != pbm->pci_first_busno) {
-			regs_dev = bus_dev;
-			bus_dev = bus_dev->bus->self;
-		}
-
-		regs_pcp = regs_dev->sysdata;
-		pregs = regs_pcp->prom_regs;
-
-		bus_pcp = bus_dev->sysdata;
-
-		/* But if the PCI bridge has it's own interrupt map
-		 * and mask properties, use that and the regs of the
-		 * PCI entity at the next level down on the path to the
-		 * device.
-		 */
-		plen = prom_getproperty(bus_pcp->prom_node, "interrupt-map",
-					(char *) &bridge_local_intmap[0],
-					sizeof(bridge_local_intmap));
-		if (plen != -1) {
-			intmap = &bridge_local_intmap[0];
-			num_intmap = plen / sizeof(struct linux_prom_pci_intmap);
-			plen = prom_getproperty(bus_pcp->prom_node,
-						"interrupt-map-mask",
-						(char *) &bridge_local_intmask,
-						sizeof(bridge_local_intmask));
-			if (plen == -1) {
-				printk("pci_intmap_match: Warning! Bridge has intmap "
-				       "but no intmask.\n");
-				printk("pci_intmap_match: Trying to recover.\n");
-				return 0;
-			}
-
-			if (pdev->bus->self != bus_dev)
-				map_slot = 1;
+		plen = prom_getproplen(pcp->prom_node, "interrupt-map");
+		if (plen <= 0) {
+			*interrupt = pci_slot_swivel(pbm, toplevel_pdev,
+						     pdev, *interrupt);
+			cnode = pcp->prom_node;
 		} else {
-			pregs = bus_pcp->prom_regs;
-			map_slot = 1;
+			*interrupt = pci_apply_intmap(pbm, toplevel_pdev,
+						      pbus, pdev,
+						      *interrupt, &cnode);
+
+			while (pcp->prom_node != cnode &&
+			       pbus->bus->number != pbm->pci_first_busno) {
+				pbus = pbus->bus->self;
+				pcp = pbus->sysdata;
+			}
 		}
-	}
+		pdev = pbus;
 
-	if (map_slot) {
-		*interrupt = ((*interrupt
-			       - 1
-			       + PCI_SLOT(pdev->devfn)) & 0x3) + 1;
+		if (cnode == pbm->prom_node)
+			break;
 	}
 
-	hi   = pregs->phys_hi & intmask->phys_hi;
-	mid  = pregs->phys_mid & intmask->phys_mid;
-	lo   = pregs->phys_lo & intmask->phys_lo;
-	irq  = *interrupt & intmask->interrupt;
+	return cnode;
+}
 
-	for (i = 0; i < num_intmap; i++) {
-		if (intmap[i].phys_hi  == hi	&&
-		    intmap[i].phys_mid == mid	&&
-		    intmap[i].phys_lo  == lo	&&
-		    intmap[i].interrupt == irq) {
-			*interrupt = intmap[i].cinterrupt;
-			printk("PCI-IRQ: Routing bus[%2x] slot[%2x] map[%d] to INO[%02x]\n",
-			       pdev->bus->number, PCI_SLOT(pdev->devfn),
-			       map_slot, *interrupt);
-			return 1;
-		}
-	}
+static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt)
+{
+	struct pcidev_cookie *dev_pcp = pdev->sysdata;
+	struct pci_pbm_info *pbm = dev_pcp->pbm;
+	struct linux_prom_pci_registers reg[PROMREG_MAX];
+	unsigned int hi, mid, lo, irq;
+	int i, cnode, plen;
 
-	/* We will run this code even if pbm->num_pbm_intmap is zero, just so
-	 * we can apply the slot mapping to the PROM interrupt property value.
-	 * So do not spit out these warnings in that case.
-	 */
-	if (num_intmap != 0) {
-		/* Print it both to OBP console and kernel one so that if bootup
-		 * hangs here the user has the information to report.
-		 */
-		prom_printf("pci_intmap_match: bus %02x, devfn %02x: ",
-			    pdev->bus->number, pdev->devfn);
-		prom_printf("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n",
-			    pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt);
-		prom_printf("Please email this information to davem@redhat.com\n");
-
-		printk("pci_intmap_match: bus %02x, devfn %02x: ",
-		       pdev->bus->number, pdev->devfn);
-		printk("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n",
-		       pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt);
-		printk("Please email this information to davem@redhat.com\n");
+	cnode = pci_intmap_match_to_root(pbm, pdev, interrupt);
+	if (cnode == pbm->prom_node)
+		goto success;
+
+	plen = prom_getproperty(cnode, "reg", (char *) reg, sizeof(reg));
+	if (plen <= 0 ||
+	    (plen % sizeof(struct linux_prom_pci_registers)) != 0) {
+		printk("%s: OBP node %x reg property has bad len %d\n",
+		       pbm->name, cnode, plen);
+		goto fail;
+	}
+
+	hi   = reg[0].phys_hi & pbm->pbm_intmask.phys_hi;
+	mid  = reg[0].phys_mid & pbm->pbm_intmask.phys_mid;
+	lo   = reg[0].phys_lo & pbm->pbm_intmask.phys_lo;
+	irq  = *interrupt & pbm->pbm_intmask.interrupt;
+
+	for (i = 0; i < pbm->num_pbm_intmap; i++) {
+		struct linux_prom_pci_intmap *intmap;
+
+		intmap = &pbm->pbm_intmap[i];
+
+		if (intmap->phys_hi  == hi  &&
+		    intmap->phys_mid == mid &&
+		    intmap->phys_lo  == lo  &&
+		    intmap->interrupt == irq) {
+			*interrupt = intmap->cinterrupt;
+			goto success;
+		}
 	}
 
+fail:
 	return 0;
+
+success:
+	printk("PCI-IRQ: Routing bus[%2x] slot[%2x] to INO[%02x]\n",
+	       pdev->bus->number, PCI_SLOT(pdev->devfn),
+	       *interrupt);
+	return 1;
 }
 
 static void __init pdev_fixup_irq(struct pci_dev *pdev)
@@ -703,16 +751,18 @@
 		return;
 	}
 
-	/* Fully specified already? */
-	if (((prom_irq & PCI_IRQ_IGN) >> 6) == portid) {
-		pdev->irq = p->irq_build(pbm, pdev, prom_irq);
-		goto have_irq;
-	}
+	if (tlb_type != hypervisor) {
+		/* Fully specified already? */
+		if (((prom_irq & PCI_IRQ_IGN) >> 6) == portid) {
+			pdev->irq = p->irq_build(pbm, pdev, prom_irq);
+			goto have_irq;
+		}
 
-	/* An onboard device? (bit 5 set) */
-	if ((prom_irq & PCI_IRQ_INO) & 0x20) {
-		pdev->irq = p->irq_build(pbm, pdev, (portid << 6 | prom_irq));
-		goto have_irq;
+		/* An onboard device? (bit 5 set) */
+		if ((prom_irq & PCI_IRQ_INO) & 0x20) {
+			pdev->irq = p->irq_build(pbm, pdev, (portid << 6 | prom_irq));
+			goto have_irq;
+		}
 	}
 
 	/* Can we find a matching entry in the interrupt-map? */
diff -urN oldtree/arch/sparc64/kernel/pci_iommu.c newtree/arch/sparc64/kernel/pci_iommu.c
--- oldtree/arch/sparc64/kernel/pci_iommu.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/kernel/pci_iommu.c	2006-02-21 15:58:20.214073552 +0000
@@ -219,7 +219,7 @@
  * DMA for PCI device PDEV.  Return non-NULL cpu-side address if
  * successful and set *DMA_ADDRP to the PCI side dma address.
  */
-void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp)
+static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp)
 {
 	struct pcidev_cookie *pcp;
 	struct pci_iommu *iommu;
@@ -267,7 +267,7 @@
 }
 
 /* Free and unmap a consistent DMA translation. */
-void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma)
+static void pci_4u_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma)
 {
 	struct pcidev_cookie *pcp;
 	struct pci_iommu *iommu;
@@ -294,7 +294,7 @@
 /* Map a single buffer at PTR of SZ bytes for PCI DMA
  * in streaming mode.
  */
-dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction)
+static dma_addr_t pci_4u_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction)
 {
 	struct pcidev_cookie *pcp;
 	struct pci_iommu *iommu;
@@ -415,7 +415,7 @@
 }
 
 /* Unmap a single streaming mode DMA translation. */
-void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
+static void pci_4u_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
 {
 	struct pcidev_cookie *pcp;
 	struct pci_iommu *iommu;
@@ -548,7 +548,7 @@
  * When making changes here, inspect the assembly output. I was having
  * hard time to kepp this routine out of using stack slots for holding variables.
  */
-int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
+static int pci_4u_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
 {
 	struct pcidev_cookie *pcp;
 	struct pci_iommu *iommu;
@@ -562,9 +562,9 @@
 	/* Fast path single entry scatterlists. */
 	if (nelems == 1) {
 		sglist->dma_address =
-			pci_map_single(pdev,
-				       (page_address(sglist->page) + sglist->offset),
-				       sglist->length, direction);
+			pci_4u_map_single(pdev,
+					  (page_address(sglist->page) + sglist->offset),
+					  sglist->length, direction);
 		if (unlikely(sglist->dma_address == PCI_DMA_ERROR_CODE))
 			return 0;
 		sglist->dma_length = sglist->length;
@@ -635,7 +635,7 @@
 }
 
 /* Unmap a set of streaming mode DMA translations. */
-void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
+static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
 {
 	struct pcidev_cookie *pcp;
 	struct pci_iommu *iommu;
@@ -695,7 +695,7 @@
 /* Make physical memory consistent for a single
  * streaming mode DMA translation after a transfer.
  */
-void pci_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
+static void pci_4u_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
 {
 	struct pcidev_cookie *pcp;
 	struct pci_iommu *iommu;
@@ -735,7 +735,7 @@
 /* Make physical memory consistent for a set of streaming
  * mode DMA translations after a transfer.
  */
-void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
+static void pci_4u_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
 {
 	struct pcidev_cookie *pcp;
 	struct pci_iommu *iommu;
@@ -776,6 +776,17 @@
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
+struct pci_iommu_ops pci_sun4u_iommu_ops = {
+	.alloc_consistent		= pci_4u_alloc_consistent,
+	.free_consistent		= pci_4u_free_consistent,
+	.map_single			= pci_4u_map_single,
+	.unmap_single			= pci_4u_unmap_single,
+	.map_sg				= pci_4u_map_sg,
+	.unmap_sg			= pci_4u_unmap_sg,
+	.dma_sync_single_for_cpu	= pci_4u_dma_sync_single_for_cpu,
+	.dma_sync_sg_for_cpu		= pci_4u_dma_sync_sg_for_cpu,
+};
+
 static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit)
 {
 	struct pci_dev *ali_isa_bridge;
diff -urN oldtree/arch/sparc64/kernel/pci_sun4v.c newtree/arch/sparc64/kernel/pci_sun4v.c
--- oldtree/arch/sparc64/kernel/pci_sun4v.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/sparc64/kernel/pci_sun4v.c	2006-02-21 15:58:20.215073400 +0000
@@ -0,0 +1,1147 @@
+/* pci_sun4v.c: SUN4V specific PCI controller support.
+ *
+ * Copyright (C) 2006 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/percpu.h>
+
+#include <asm/pbm.h>
+#include <asm/iommu.h>
+#include <asm/irq.h>
+#include <asm/upa.h>
+#include <asm/pstate.h>
+#include <asm/oplib.h>
+#include <asm/hypervisor.h>
+
+#include "pci_impl.h"
+#include "iommu_common.h"
+
+#include "pci_sun4v.h"
+
+#define PGLIST_NENTS	(PAGE_SIZE / sizeof(u64))
+
+struct pci_iommu_batch {
+	struct pci_dev	*pdev;		/* Device mapping is for.	*/
+	unsigned long	prot;		/* IOMMU page protections	*/
+	unsigned long	entry;		/* Index into IOTSB.		*/
+	u64		*pglist;	/* List of physical pages	*/
+	unsigned long	npages;		/* Number of pages in list.	*/
+};
+
+static DEFINE_PER_CPU(struct pci_iommu_batch, pci_iommu_batch);
+
+/* Interrupts must be disabled.  */
+static inline void pci_iommu_batch_start(struct pci_dev *pdev, unsigned long prot, unsigned long entry)
+{
+	struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch);
+
+	p->pdev		= pdev;
+	p->prot		= prot;
+	p->entry	= entry;
+	p->npages	= 0;
+}
+
+/* Interrupts must be disabled.  */
+static long pci_iommu_batch_flush(struct pci_iommu_batch *p)
+{
+	struct pcidev_cookie *pcp = p->pdev->sysdata;
+	unsigned long devhandle = pcp->pbm->devhandle;
+	unsigned long prot = p->prot;
+	unsigned long entry = p->entry;
+	u64 *pglist = p->pglist;
+	unsigned long npages = p->npages;
+
+	while (npages != 0) {
+		long num;
+
+		num = pci_sun4v_iommu_map(devhandle, HV_PCI_TSBID(0, entry),
+					  npages, prot, __pa(pglist));
+		if (unlikely(num < 0)) {
+			if (printk_ratelimit())
+				printk("pci_iommu_batch_flush: IOMMU map of "
+				       "[%08lx:%08lx:%lx:%lx:%lx] failed with "
+				       "status %ld\n",
+				       devhandle, HV_PCI_TSBID(0, entry),
+				       npages, prot, __pa(pglist), num);
+			return -1;
+		}
+
+		entry += num;
+		npages -= num;
+		pglist += num;
+	}
+
+	p->entry = entry;
+	p->npages = 0;
+
+	return 0;
+}
+
+/* Interrupts must be disabled.  */
+static inline long pci_iommu_batch_add(u64 phys_page)
+{
+	struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch);
+
+	BUG_ON(p->npages >= PGLIST_NENTS);
+
+	p->pglist[p->npages++] = phys_page;
+	if (p->npages == PGLIST_NENTS)
+		return pci_iommu_batch_flush(p);
+
+	return 0;
+}
+
+/* Interrupts must be disabled.  */
+static inline long pci_iommu_batch_end(void)
+{
+	struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch);
+
+	BUG_ON(p->npages >= PGLIST_NENTS);
+
+	return pci_iommu_batch_flush(p);
+}
+
+static long pci_arena_alloc(struct pci_iommu_arena *arena, unsigned long npages)
+{
+	unsigned long n, i, start, end, limit;
+	int pass;
+
+	limit = arena->limit;
+	start = arena->hint;
+	pass = 0;
+
+again:
+	n = find_next_zero_bit(arena->map, limit, start);
+	end = n + npages;
+	if (unlikely(end >= limit)) {
+		if (likely(pass < 1)) {
+			limit = start;
+			start = 0;
+			pass++;
+			goto again;
+		} else {
+			/* Scanned the whole thing, give up. */
+			return -1;
+		}
+	}
+
+	for (i = n; i < end; i++) {
+		if (test_bit(i, arena->map)) {
+			start = i + 1;
+			goto again;
+		}
+	}
+
+	for (i = n; i < end; i++)
+		__set_bit(i, arena->map);
+
+	arena->hint = end;
+
+	return n;
+}
+
+static void pci_arena_free(struct pci_iommu_arena *arena, unsigned long base, unsigned long npages)
+{
+	unsigned long i;
+
+	for (i = base; i < (base + npages); i++)
+		__clear_bit(i, arena->map);
+}
+
+static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp)
+{
+	struct pcidev_cookie *pcp;
+	struct pci_iommu *iommu;
+	unsigned long flags, order, first_page, npages, n;
+	void *ret;
+	long entry;
+
+	size = IO_PAGE_ALIGN(size);
+	order = get_order(size);
+	if (unlikely(order >= MAX_ORDER))
+		return NULL;
+
+	npages = size >> IO_PAGE_SHIFT;
+
+	first_page = __get_free_pages(GFP_ATOMIC, order);
+	if (unlikely(first_page == 0UL))
+		return NULL;
+
+	memset((char *)first_page, 0, PAGE_SIZE << order);
+
+	pcp = pdev->sysdata;
+	iommu = pcp->pbm->iommu;
+
+	spin_lock_irqsave(&iommu->lock, flags);
+	entry = pci_arena_alloc(&iommu->arena, npages);
+	spin_unlock_irqrestore(&iommu->lock, flags);
+
+	if (unlikely(entry < 0L))
+		goto arena_alloc_fail;
+
+	*dma_addrp = (iommu->page_table_map_base +
+		      (entry << IO_PAGE_SHIFT));
+	ret = (void *) first_page;
+	first_page = __pa(first_page);
+
+	local_irq_save(flags);
+
+	pci_iommu_batch_start(pdev,
+			      (HV_PCI_MAP_ATTR_READ |
+			       HV_PCI_MAP_ATTR_WRITE),
+			      entry);
+
+	for (n = 0; n < npages; n++) {
+		long err = pci_iommu_batch_add(first_page + (n * PAGE_SIZE));
+		if (unlikely(err < 0L))
+			goto iommu_map_fail;
+	}
+
+	if (unlikely(pci_iommu_batch_end() < 0L))
+		goto iommu_map_fail;
+
+	local_irq_restore(flags);
+
+	return ret;
+
+iommu_map_fail:
+	/* Interrupts are disabled.  */
+	spin_lock(&iommu->lock);
+	pci_arena_free(&iommu->arena, entry, npages);
+	spin_unlock_irqrestore(&iommu->lock, flags);
+
+arena_alloc_fail:
+	free_pages(first_page, order);
+	return NULL;
+}
+
+static void pci_4v_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma)
+{
+	struct pcidev_cookie *pcp;
+	struct pci_iommu *iommu;
+	unsigned long flags, order, npages, entry;
+	u32 devhandle;
+
+	npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT;
+	pcp = pdev->sysdata;
+	iommu = pcp->pbm->iommu;
+	devhandle = pcp->pbm->devhandle;
+	entry = ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
+
+	spin_lock_irqsave(&iommu->lock, flags);
+
+	pci_arena_free(&iommu->arena, entry, npages);
+
+	do {
+		unsigned long num;
+
+		num = pci_sun4v_iommu_demap(devhandle, HV_PCI_TSBID(0, entry),
+					    npages);
+		entry += num;
+		npages -= num;
+	} while (npages != 0);
+
+	spin_unlock_irqrestore(&iommu->lock, flags);
+
+	order = get_order(size);
+	if (order < 10)
+		free_pages((unsigned long)cpu, order);
+}
+
+static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction)
+{
+	struct pcidev_cookie *pcp;
+	struct pci_iommu *iommu;
+	unsigned long flags, npages, oaddr;
+	unsigned long i, base_paddr;
+	u32 bus_addr, ret;
+	unsigned long prot;
+	long entry;
+
+	pcp = pdev->sysdata;
+	iommu = pcp->pbm->iommu;
+
+	if (unlikely(direction == PCI_DMA_NONE))
+		goto bad;
+
+	oaddr = (unsigned long)ptr;
+	npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK);
+	npages >>= IO_PAGE_SHIFT;
+
+	spin_lock_irqsave(&iommu->lock, flags);
+	entry = pci_arena_alloc(&iommu->arena, npages);
+	spin_unlock_irqrestore(&iommu->lock, flags);
+
+	if (unlikely(entry < 0L))
+		goto bad;
+
+	bus_addr = (iommu->page_table_map_base +
+		    (entry << IO_PAGE_SHIFT));
+	ret = bus_addr | (oaddr & ~IO_PAGE_MASK);
+	base_paddr = __pa(oaddr & IO_PAGE_MASK);
+	prot = HV_PCI_MAP_ATTR_READ;
+	if (direction != PCI_DMA_TODEVICE)
+		prot |= HV_PCI_MAP_ATTR_WRITE;
+
+	local_irq_save(flags);
+
+	pci_iommu_batch_start(pdev, prot, entry);
+
+	for (i = 0; i < npages; i++, base_paddr += IO_PAGE_SIZE) {
+		long err = pci_iommu_batch_add(base_paddr);
+		if (unlikely(err < 0L))
+			goto iommu_map_fail;
+	}
+	if (unlikely(pci_iommu_batch_end() < 0L))
+		goto iommu_map_fail;
+
+	local_irq_restore(flags);
+
+	return ret;
+
+bad:
+	if (printk_ratelimit())
+		WARN_ON(1);
+	return PCI_DMA_ERROR_CODE;
+
+iommu_map_fail:
+	/* Interrupts are disabled.  */
+	spin_lock(&iommu->lock);
+	pci_arena_free(&iommu->arena, entry, npages);
+	spin_unlock_irqrestore(&iommu->lock, flags);
+
+	return PCI_DMA_ERROR_CODE;
+}
+
+static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
+{
+	struct pcidev_cookie *pcp;
+	struct pci_iommu *iommu;
+	unsigned long flags, npages;
+	long entry;
+	u32 devhandle;
+
+	if (unlikely(direction == PCI_DMA_NONE)) {
+		if (printk_ratelimit())
+			WARN_ON(1);
+		return;
+	}
+
+	pcp = pdev->sysdata;
+	iommu = pcp->pbm->iommu;
+	devhandle = pcp->pbm->devhandle;
+
+	npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
+	npages >>= IO_PAGE_SHIFT;
+	bus_addr &= IO_PAGE_MASK;
+
+	spin_lock_irqsave(&iommu->lock, flags);
+
+	entry = (bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT;
+	pci_arena_free(&iommu->arena, entry, npages);
+
+	do {
+		unsigned long num;
+
+		num = pci_sun4v_iommu_demap(devhandle, HV_PCI_TSBID(0, entry),
+					    npages);
+		entry += num;
+		npages -= num;
+	} while (npages != 0);
+
+	spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+#define SG_ENT_PHYS_ADDRESS(SG)	\
+	(__pa(page_address((SG)->page)) + (SG)->offset)
+
+static inline long fill_sg(long entry, struct pci_dev *pdev,
+			   struct scatterlist *sg,
+			   int nused, int nelems, unsigned long prot)
+{
+	struct scatterlist *dma_sg = sg;
+	struct scatterlist *sg_end = sg + nelems;
+	unsigned long flags;
+	int i;
+
+	local_irq_save(flags);
+
+	pci_iommu_batch_start(pdev, prot, entry);
+
+	for (i = 0; i < nused; i++) {
+		unsigned long pteval = ~0UL;
+		u32 dma_npages;
+
+		dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) +
+			      dma_sg->dma_length +
+			      ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT;
+		do {
+			unsigned long offset;
+			signed int len;
+
+			/* If we are here, we know we have at least one
+			 * more page to map.  So walk forward until we
+			 * hit a page crossing, and begin creating new
+			 * mappings from that spot.
+			 */
+			for (;;) {
+				unsigned long tmp;
+
+				tmp = SG_ENT_PHYS_ADDRESS(sg);
+				len = sg->length;
+				if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) {
+					pteval = tmp & IO_PAGE_MASK;
+					offset = tmp & (IO_PAGE_SIZE - 1UL);
+					break;
+				}
+				if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) {
+					pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK;
+					offset = 0UL;
+					len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL)));
+					break;
+				}
+				sg++;
+			}
+
+			pteval = (pteval & IOPTE_PAGE);
+			while (len > 0) {
+				long err;
+
+				err = pci_iommu_batch_add(pteval);
+				if (unlikely(err < 0L))
+					goto iommu_map_failed;
+
+				pteval += IO_PAGE_SIZE;
+				len -= (IO_PAGE_SIZE - offset);
+				offset = 0;
+				dma_npages--;
+			}
+
+			pteval = (pteval & IOPTE_PAGE) + len;
+			sg++;
+
+			/* Skip over any tail mappings we've fully mapped,
+			 * adjusting pteval along the way.  Stop when we
+			 * detect a page crossing event.
+			 */
+			while (sg < sg_end &&
+			       (pteval << (64 - IO_PAGE_SHIFT)) != 0UL &&
+			       (pteval == SG_ENT_PHYS_ADDRESS(sg)) &&
+			       ((pteval ^
+				 (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) {
+				pteval += sg->length;
+				sg++;
+			}
+			if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL)
+				pteval = ~0UL;
+		} while (dma_npages != 0);
+		dma_sg++;
+	}
+
+	if (unlikely(pci_iommu_batch_end() < 0L))
+		goto iommu_map_failed;
+
+	local_irq_restore(flags);
+	return 0;
+
+iommu_map_failed:
+	local_irq_restore(flags);
+	return -1L;
+}
+
+static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
+{
+	struct pcidev_cookie *pcp;
+	struct pci_iommu *iommu;
+	unsigned long flags, npages, prot;
+	u32 dma_base;
+	struct scatterlist *sgtmp;
+	long entry, err;
+	int used;
+
+	/* Fast path single entry scatterlists. */
+	if (nelems == 1) {
+		sglist->dma_address =
+			pci_4v_map_single(pdev,
+					  (page_address(sglist->page) + sglist->offset),
+					  sglist->length, direction);
+		if (unlikely(sglist->dma_address == PCI_DMA_ERROR_CODE))
+			return 0;
+		sglist->dma_length = sglist->length;
+		return 1;
+	}
+
+	pcp = pdev->sysdata;
+	iommu = pcp->pbm->iommu;
+	
+	if (unlikely(direction == PCI_DMA_NONE))
+		goto bad;
+
+	/* Step 1: Prepare scatter list. */
+	npages = prepare_sg(sglist, nelems);
+
+	/* Step 2: Allocate a cluster and context, if necessary. */
+	spin_lock_irqsave(&iommu->lock, flags);
+	entry = pci_arena_alloc(&iommu->arena, npages);
+	spin_unlock_irqrestore(&iommu->lock, flags);
+
+	if (unlikely(entry < 0L))
+		goto bad;
+
+	dma_base = iommu->page_table_map_base +
+		(entry << IO_PAGE_SHIFT);
+
+	/* Step 3: Normalize DMA addresses. */
+	used = nelems;
+
+	sgtmp = sglist;
+	while (used && sgtmp->dma_length) {
+		sgtmp->dma_address += dma_base;
+		sgtmp++;
+		used--;
+	}
+	used = nelems - used;
+
+	/* Step 4: Create the mappings. */
+	prot = HV_PCI_MAP_ATTR_READ;
+	if (direction != PCI_DMA_TODEVICE)
+		prot |= HV_PCI_MAP_ATTR_WRITE;
+
+	err = fill_sg(entry, pdev, sglist, used, nelems, prot);
+	if (unlikely(err < 0L))
+		goto iommu_map_failed;
+
+	return used;
+
+bad:
+	if (printk_ratelimit())
+		WARN_ON(1);
+	return 0;
+
+iommu_map_failed:
+	spin_lock_irqsave(&iommu->lock, flags);
+	pci_arena_free(&iommu->arena, entry, npages);
+	spin_unlock_irqrestore(&iommu->lock, flags);
+
+	return 0;
+}
+
+static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
+{
+	struct pcidev_cookie *pcp;
+	struct pci_iommu *iommu;
+	unsigned long flags, i, npages;
+	long entry;
+	u32 devhandle, bus_addr;
+
+	if (unlikely(direction == PCI_DMA_NONE)) {
+		if (printk_ratelimit())
+			WARN_ON(1);
+	}
+
+	pcp = pdev->sysdata;
+	iommu = pcp->pbm->iommu;
+	devhandle = pcp->pbm->devhandle;
+	
+	bus_addr = sglist->dma_address & IO_PAGE_MASK;
+
+	for (i = 1; i < nelems; i++)
+		if (sglist[i].dma_length == 0)
+			break;
+	i--;
+	npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) -
+		  bus_addr) >> IO_PAGE_SHIFT;
+
+	entry = ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
+
+	spin_lock_irqsave(&iommu->lock, flags);
+
+	pci_arena_free(&iommu->arena, entry, npages);
+
+	do {
+		unsigned long num;
+
+		num = pci_sun4v_iommu_demap(devhandle, HV_PCI_TSBID(0, entry),
+					    npages);
+		entry += num;
+		npages -= num;
+	} while (npages != 0);
+
+	spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+static void pci_4v_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
+{
+	/* Nothing to do... */
+}
+
+static void pci_4v_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
+{
+	/* Nothing to do... */
+}
+
+struct pci_iommu_ops pci_sun4v_iommu_ops = {
+	.alloc_consistent		= pci_4v_alloc_consistent,
+	.free_consistent		= pci_4v_free_consistent,
+	.map_single			= pci_4v_map_single,
+	.unmap_single			= pci_4v_unmap_single,
+	.map_sg				= pci_4v_map_sg,
+	.unmap_sg			= pci_4v_unmap_sg,
+	.dma_sync_single_for_cpu	= pci_4v_dma_sync_single_for_cpu,
+	.dma_sync_sg_for_cpu		= pci_4v_dma_sync_sg_for_cpu,
+};
+
+/* SUN4V PCI configuration space accessors. */
+
+static inline int pci_sun4v_out_of_range(struct pci_pbm_info *pbm, unsigned int bus, unsigned int device, unsigned int func)
+{
+	if (bus == pbm->pci_first_busno) {
+		if (device == 0 && func == 0)
+			return 0;
+		return 1;
+	}
+
+	if (bus < pbm->pci_first_busno ||
+	    bus > pbm->pci_last_busno)
+		return 1;
+	return 0;
+}
+
+static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
+				  int where, int size, u32 *value)
+{
+	struct pci_pbm_info *pbm = bus_dev->sysdata;
+	u32 devhandle = pbm->devhandle;
+	unsigned int bus = bus_dev->number;
+	unsigned int device = PCI_SLOT(devfn);
+	unsigned int func = PCI_FUNC(devfn);
+	unsigned long ret;
+
+	if (pci_sun4v_out_of_range(pbm, bus, device, func)) {
+		ret = ~0UL;
+	} else {
+		ret = pci_sun4v_config_get(devhandle,
+				HV_PCI_DEVICE_BUILD(bus, device, func),
+				where, size);
+#if 0
+		printk("rcfg: [%x:%x:%x:%d]=[%lx]\n",
+		       devhandle, HV_PCI_DEVICE_BUILD(bus, device, func),
+		       where, size, ret);
+#endif
+	}
+	switch (size) {
+	case 1:
+		*value = ret & 0xff;
+		break;
+	case 2:
+		*value = ret & 0xffff;
+		break;
+	case 4:
+		*value = ret & 0xffffffff;
+		break;
+	};
+
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
+				   int where, int size, u32 value)
+{
+	struct pci_pbm_info *pbm = bus_dev->sysdata;
+	u32 devhandle = pbm->devhandle;
+	unsigned int bus = bus_dev->number;
+	unsigned int device = PCI_SLOT(devfn);
+	unsigned int func = PCI_FUNC(devfn);
+	unsigned long ret;
+
+	if (pci_sun4v_out_of_range(pbm, bus, device, func)) {
+		/* Do nothing. */
+	} else {
+		ret = pci_sun4v_config_put(devhandle,
+				HV_PCI_DEVICE_BUILD(bus, device, func),
+				where, size, value);
+#if 0
+		printk("wcfg: [%x:%x:%x:%d] v[%x] == [%lx]\n",
+		       devhandle, HV_PCI_DEVICE_BUILD(bus, device, func),
+		       where, size, value, ret);
+#endif
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops pci_sun4v_ops = {
+	.read =		pci_sun4v_read_pci_cfg,
+	.write =	pci_sun4v_write_pci_cfg,
+};
+
+
+static void pbm_scan_bus(struct pci_controller_info *p,
+			 struct pci_pbm_info *pbm)
+{
+	struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL);
+
+	if (!cookie) {
+		prom_printf("%s: Critical allocation failure.\n", pbm->name);
+		prom_halt();
+	}
+
+	/* All we care about is the PBM. */
+	memset(cookie, 0, sizeof(*cookie));
+	cookie->pbm = pbm;
+
+	pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, p->pci_ops, pbm);
+#if 0
+	pci_fixup_host_bridge_self(pbm->pci_bus);
+	pbm->pci_bus->self->sysdata = cookie;
+#endif
+	pci_fill_in_pbm_cookies(pbm->pci_bus, pbm,
+				pbm->prom_node);
+	pci_record_assignments(pbm, pbm->pci_bus);
+	pci_assign_unassigned(pbm, pbm->pci_bus);
+	pci_fixup_irq(pbm, pbm->pci_bus);
+	pci_determine_66mhz_disposition(pbm, pbm->pci_bus);
+	pci_setup_busmastering(pbm, pbm->pci_bus);
+}
+
+static void pci_sun4v_scan_bus(struct pci_controller_info *p)
+{
+	if (p->pbm_A.prom_node) {
+		p->pbm_A.is_66mhz_capable =
+			prom_getbool(p->pbm_A.prom_node, "66mhz-capable");
+
+		pbm_scan_bus(p, &p->pbm_A);
+	}
+	if (p->pbm_B.prom_node) {
+		p->pbm_B.is_66mhz_capable =
+			prom_getbool(p->pbm_B.prom_node, "66mhz-capable");
+
+		pbm_scan_bus(p, &p->pbm_B);
+	}
+
+	/* XXX register error interrupt handlers XXX */
+}
+
+static unsigned int pci_sun4v_irq_build(struct pci_pbm_info *pbm,
+					struct pci_dev *pdev,
+					unsigned int devino)
+{
+	u32 devhandle = pbm->devhandle;
+	int pil;
+
+	pil = 4;
+	if (pdev) {
+		switch ((pdev->class >> 16) & 0xff) {
+		case PCI_BASE_CLASS_STORAGE:
+			pil = 4;
+			break;
+
+		case PCI_BASE_CLASS_NETWORK:
+			pil = 6;
+			break;
+
+		case PCI_BASE_CLASS_DISPLAY:
+			pil = 9;
+			break;
+
+		case PCI_BASE_CLASS_MULTIMEDIA:
+		case PCI_BASE_CLASS_MEMORY:
+		case PCI_BASE_CLASS_BRIDGE:
+		case PCI_BASE_CLASS_SERIAL:
+			pil = 10;
+			break;
+
+		default:
+			pil = 4;
+			break;
+		};
+	}
+	BUG_ON(PIL_RESERVED(pil));
+
+	return sun4v_build_irq(devhandle, devino, pil, IBF_PCI);
+}
+
+static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource)
+{
+	struct pcidev_cookie *pcp = pdev->sysdata;
+	struct pci_pbm_info *pbm = pcp->pbm;
+	struct resource *res, *root;
+	u32 reg;
+	int where, size, is_64bit;
+
+	res = &pdev->resource[resource];
+	if (resource < 6) {
+		where = PCI_BASE_ADDRESS_0 + (resource * 4);
+	} else if (resource == PCI_ROM_RESOURCE) {
+		where = pdev->rom_base_reg;
+	} else {
+		/* Somebody might have asked allocation of a non-standard resource */
+		return;
+	}
+
+	/* XXX 64-bit MEM handling is not %100 correct... XXX */
+	is_64bit = 0;
+	if (res->flags & IORESOURCE_IO)
+		root = &pbm->io_space;
+	else {
+		root = &pbm->mem_space;
+		if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
+		    == PCI_BASE_ADDRESS_MEM_TYPE_64)
+			is_64bit = 1;
+	}
+
+	size = res->end - res->start;
+	pci_read_config_dword(pdev, where, &reg);
+	reg = ((reg & size) |
+	       (((u32)(res->start - root->start)) & ~size));
+	if (resource == PCI_ROM_RESOURCE) {
+		reg |= PCI_ROM_ADDRESS_ENABLE;
+		res->flags |= IORESOURCE_ROM_ENABLE;
+	}
+	pci_write_config_dword(pdev, where, reg);
+
+	/* This knows that the upper 32-bits of the address
+	 * must be zero.  Our PCI common layer enforces this.
+	 */
+	if (is_64bit)
+		pci_write_config_dword(pdev, where + 4, 0);
+}
+
+static void pci_sun4v_resource_adjust(struct pci_dev *pdev,
+				      struct resource *res,
+				      struct resource *root)
+{
+	res->start += root->start;
+	res->end += root->start;
+}
+
+/* Use ranges property to determine where PCI MEM, I/O, and Config
+ * space are for this PCI bus module.
+ */
+static void pci_sun4v_determine_mem_io_space(struct pci_pbm_info *pbm)
+{
+	int i, saw_mem, saw_io;
+
+	saw_mem = saw_io = 0;
+	for (i = 0; i < pbm->num_pbm_ranges; i++) {
+		struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i];
+		unsigned long a;
+		int type;
+
+		type = (pr->child_phys_hi >> 24) & 0x3;
+		a = (((unsigned long)pr->parent_phys_hi << 32UL) |
+		     ((unsigned long)pr->parent_phys_lo  <<  0UL));
+
+		switch (type) {
+		case 1:
+			/* 16-bit IO space, 16MB */
+			pbm->io_space.start = a;
+			pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL);
+			pbm->io_space.flags = IORESOURCE_IO;
+			saw_io = 1;
+			break;
+
+		case 2:
+			/* 32-bit MEM space, 2GB */
+			pbm->mem_space.start = a;
+			pbm->mem_space.end = a + (0x80000000UL - 1UL);
+			pbm->mem_space.flags = IORESOURCE_MEM;
+			saw_mem = 1;
+			break;
+
+		case 3:
+			/* XXX 64-bit MEM handling XXX */
+
+		default:
+			break;
+		};
+	}
+
+	if (!saw_io || !saw_mem) {
+		prom_printf("%s: Fatal error, missing %s PBM range.\n",
+			    pbm->name,
+			    (!saw_io ? "IO" : "MEM"));
+		prom_halt();
+	}
+
+	printk("%s: PCI IO[%lx] MEM[%lx]\n",
+	       pbm->name,
+	       pbm->io_space.start,
+	       pbm->mem_space.start);
+}
+
+static void pbm_register_toplevel_resources(struct pci_controller_info *p,
+					    struct pci_pbm_info *pbm)
+{
+	pbm->io_space.name = pbm->mem_space.name = pbm->name;
+
+	request_resource(&ioport_resource, &pbm->io_space);
+	request_resource(&iomem_resource, &pbm->mem_space);
+	pci_register_legacy_regions(&pbm->io_space,
+				    &pbm->mem_space);
+}
+
+static unsigned long probe_existing_entries(struct pci_pbm_info *pbm,
+					    struct pci_iommu *iommu)
+{
+	struct pci_iommu_arena *arena = &iommu->arena;
+	unsigned long i, cnt = 0;
+	u32 devhandle;
+
+	devhandle = pbm->devhandle;
+	for (i = 0; i < arena->limit; i++) {
+		unsigned long ret, io_attrs, ra;
+
+		ret = pci_sun4v_iommu_getmap(devhandle,
+					     HV_PCI_TSBID(0, i),
+					     &io_attrs, &ra);
+		if (ret == HV_EOK) {
+			cnt++;
+			__set_bit(i, arena->map);
+		}
+	}
+
+	return cnt;
+}
+
+static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
+{
+	struct pci_iommu *iommu = pbm->iommu;
+	unsigned long num_tsb_entries, sz;
+	u32 vdma[2], dma_mask, dma_offset;
+	int err, tsbsize;
+
+	err = prom_getproperty(pbm->prom_node, "virtual-dma",
+			       (char *)&vdma[0], sizeof(vdma));
+	if (err == 0 || err == -1) {
+		/* No property, use default values. */
+		vdma[0] = 0x80000000;
+		vdma[1] = 0x80000000;
+	}
+
+	dma_mask = vdma[0];
+	switch (vdma[1]) {
+		case 0x20000000:
+			dma_mask |= 0x1fffffff;
+			tsbsize = 64;
+			break;
+
+		case 0x40000000:
+			dma_mask |= 0x3fffffff;
+			tsbsize = 128;
+			break;
+
+		case 0x80000000:
+			dma_mask |= 0x7fffffff;
+			tsbsize = 256;
+			break;
+
+		default:
+			prom_printf("PCI-SUN4V: strange virtual-dma size.\n");
+			prom_halt();
+	};
+
+	tsbsize *= (8 * 1024);
+
+	num_tsb_entries = tsbsize / sizeof(iopte_t);
+
+	dma_offset = vdma[0];
+
+	/* Setup initial software IOMMU state. */
+	spin_lock_init(&iommu->lock);
+	iommu->ctx_lowest_free = 1;
+	iommu->page_table_map_base = dma_offset;
+	iommu->dma_addr_mask = dma_mask;
+
+	/* Allocate and initialize the free area map.  */
+	sz = num_tsb_entries / 8;
+	sz = (sz + 7UL) & ~7UL;
+	iommu->arena.map = kmalloc(sz, GFP_KERNEL);
+	if (!iommu->arena.map) {
+		prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n");
+		prom_halt();
+	}
+	memset(iommu->arena.map, 0, sz);
+	iommu->arena.limit = num_tsb_entries;
+
+	sz = probe_existing_entries(pbm, iommu);
+
+	printk("%s: TSB entries [%lu], existing mapings [%lu]\n",
+	       pbm->name, num_tsb_entries, sz);
+}
+
+static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm)
+{
+	unsigned int busrange[2];
+	int prom_node = pbm->prom_node;
+	int err;
+
+	err = prom_getproperty(prom_node, "bus-range",
+			       (char *)&busrange[0],
+			       sizeof(busrange));
+	if (err == 0 || err == -1) {
+		prom_printf("%s: Fatal error, no bus-range.\n", pbm->name);
+		prom_halt();
+	}
+
+	pbm->pci_first_busno = busrange[0];
+	pbm->pci_last_busno = busrange[1];
+
+}
+
+static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32 devhandle)
+{
+	struct pci_pbm_info *pbm;
+	int err, i;
+
+	if (devhandle & 0x40)
+		pbm = &p->pbm_B;
+	else
+		pbm = &p->pbm_A;
+
+	pbm->parent = p;
+	pbm->prom_node = prom_node;
+	pbm->pci_first_slot = 1;
+
+	pbm->devhandle = devhandle;
+
+	sprintf(pbm->name, "SUN4V-PCI%d PBM%c",
+		p->index, (pbm == &p->pbm_A ? 'A' : 'B'));
+
+	printk("%s: devhandle[%x] prom_node[%x:%x]\n",
+	       pbm->name, pbm->devhandle,
+	       pbm->prom_node, prom_getchild(pbm->prom_node));
+
+	prom_getstring(prom_node, "name",
+		       pbm->prom_name, sizeof(pbm->prom_name));
+
+	err = prom_getproperty(prom_node, "ranges",
+			       (char *) pbm->pbm_ranges,
+			       sizeof(pbm->pbm_ranges));
+	if (err == 0 || err == -1) {
+		prom_printf("%s: Fatal error, no ranges property.\n",
+			    pbm->name);
+		prom_halt();
+	}
+
+	pbm->num_pbm_ranges =
+		(err / sizeof(struct linux_prom_pci_ranges));
+
+	/* Mask out the top 8 bits of the ranges, leaving the real
+	 * physical address.
+	 */
+	for (i = 0; i < pbm->num_pbm_ranges; i++)
+		pbm->pbm_ranges[i].parent_phys_hi &= 0x0fffffff;
+
+	pci_sun4v_determine_mem_io_space(pbm);
+	pbm_register_toplevel_resources(p, pbm);
+
+	err = prom_getproperty(prom_node, "interrupt-map",
+			       (char *)pbm->pbm_intmap,
+			       sizeof(pbm->pbm_intmap));
+	if (err == 0 || err == -1) {
+		prom_printf("%s: Fatal error, no interrupt-map property.\n",
+			    pbm->name);
+		prom_halt();
+	}
+
+	pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
+	err = prom_getproperty(prom_node, "interrupt-map-mask",
+			       (char *)&pbm->pbm_intmask,
+			       sizeof(pbm->pbm_intmask));
+	if (err == 0 || err == -1) {
+		prom_printf("%s: Fatal error, no interrupt-map-mask.\n",
+			    pbm->name);
+		prom_halt();
+	}
+
+	pci_sun4v_get_bus_range(pbm);
+	pci_sun4v_iommu_init(pbm);
+}
+
+void sun4v_pci_init(int node, char *model_name)
+{
+	struct pci_controller_info *p;
+	struct pci_iommu *iommu;
+	struct linux_prom64_registers regs;
+	u32 devhandle;
+	int i;
+
+	prom_getproperty(node, "reg", (char *)&regs, sizeof(regs));
+	devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff;
+
+	for (p = pci_controller_root; p; p = p->next) {
+		struct pci_pbm_info *pbm;
+
+		if (p->pbm_A.prom_node && p->pbm_B.prom_node)
+			continue;
+
+		pbm = (p->pbm_A.prom_node ?
+		       &p->pbm_A :
+		       &p->pbm_B);
+
+		if (pbm->devhandle == (devhandle ^ 0x40)) {
+			pci_sun4v_pbm_init(p, node, devhandle);
+			return;
+		}
+	}
+
+	for_each_cpu(i) {
+		unsigned long page = get_zeroed_page(GFP_ATOMIC);
+
+		if (!page)
+			goto fatal_memory_error;
+
+		per_cpu(pci_iommu_batch, i).pglist = (u64 *) page;
+	}
+
+	p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
+	if (!p)
+		goto fatal_memory_error;
+
+	memset(p, 0, sizeof(*p));
+
+	iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
+	if (!iommu)
+		goto fatal_memory_error;
+
+	memset(iommu, 0, sizeof(*iommu));
+	p->pbm_A.iommu = iommu;
+
+	iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
+	if (!iommu)
+		goto fatal_memory_error;
+
+	memset(iommu, 0, sizeof(*iommu));
+	p->pbm_B.iommu = iommu;
+
+	p->next = pci_controller_root;
+	pci_controller_root = p;
+
+	p->index = pci_num_controllers++;
+	p->pbms_same_domain = 0;
+
+	p->scan_bus = pci_sun4v_scan_bus;
+	p->irq_build = pci_sun4v_irq_build;
+	p->base_address_update = pci_sun4v_base_address_update;
+	p->resource_adjust = pci_sun4v_resource_adjust;
+	p->pci_ops = &pci_sun4v_ops;
+
+	/* Like PSYCHO and SCHIZO we have a 2GB aligned area
+	 * for memory space.
+	 */
+	pci_memspace_mask = 0x7fffffffUL;
+
+	pci_sun4v_pbm_init(p, node, devhandle);
+	return;
+
+fatal_memory_error:
+	prom_printf("SUN4V_PCI: Fatal memory allocation error.\n");
+	prom_halt();
+}
diff -urN oldtree/arch/sparc64/kernel/pci_sun4v.h newtree/arch/sparc64/kernel/pci_sun4v.h
--- oldtree/arch/sparc64/kernel/pci_sun4v.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/sparc64/kernel/pci_sun4v.h	2006-02-21 15:58:20.216073248 +0000
@@ -0,0 +1,31 @@
+/* pci_sun4v.h: SUN4V specific PCI controller support.
+ *
+ * Copyright (C) 2006 David S. Miller (davem@davemloft.net)
+ */
+
+#ifndef _PCI_SUN4V_H
+#define _PCI_SUN4V_H
+
+extern long pci_sun4v_iommu_map(unsigned long devhandle,
+				unsigned long tsbid,
+				unsigned long num_ttes,
+				unsigned long io_attributes,
+				unsigned long io_page_list_pa);
+extern unsigned long pci_sun4v_iommu_demap(unsigned long devhandle,
+					   unsigned long tsbid,
+					   unsigned long num_ttes);
+extern unsigned long pci_sun4v_iommu_getmap(unsigned long devhandle,
+					    unsigned long tsbid,
+					    unsigned long *io_attributes,
+					    unsigned long *real_address);
+extern unsigned long pci_sun4v_config_get(unsigned long devhandle,
+					  unsigned long pci_device,
+					  unsigned long config_offset,
+					  unsigned long size);
+extern int pci_sun4v_config_put(unsigned long devhandle,
+				unsigned long pci_device,
+				unsigned long config_offset,
+				unsigned long size,
+				unsigned long data);
+
+#endif /* !(_PCI_SUN4V_H) */
diff -urN oldtree/arch/sparc64/kernel/pci_sun4v_asm.S newtree/arch/sparc64/kernel/pci_sun4v_asm.S
--- oldtree/arch/sparc64/kernel/pci_sun4v_asm.S	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/sparc64/kernel/pci_sun4v_asm.S	2006-02-21 15:58:20.216073248 +0000
@@ -0,0 +1,95 @@
+/* pci_sun4v_asm: Hypervisor calls for PCI support.
+ *
+ * Copyright (C) 2006 David S. Miller <davem@davemloft.net>
+ */
+
+#include <asm/hypervisor.h>
+
+	/* %o0: devhandle
+	 * %o1:	tsbid
+	 * %o2:	num ttes
+	 * %o3:	io_attributes
+	 * %o4:	io_page_list phys address
+	 *
+	 * returns %o0:	-status if status was non-zero, else
+	 *         %o0:	num pages mapped
+	 */
+	.globl	pci_sun4v_iommu_map
+pci_sun4v_iommu_map:
+	mov	%o5, %g1
+	mov	HV_FAST_PCI_IOMMU_MAP, %o5
+	ta	HV_FAST_TRAP
+	brnz,pn %o0, 1f
+	 sub	%g0, %o0, %o0
+	mov	%o1, %o0
+1:	retl
+	 nop
+
+	/* %o0: devhandle
+	 * %o1:	tsbid
+	 * %o2:	num ttes
+	 *
+	 * returns %o0:	num ttes demapped
+	 */
+	.globl	pci_sun4v_iommu_demap
+pci_sun4v_iommu_demap:
+	mov	HV_FAST_PCI_IOMMU_DEMAP, %o5
+	ta	HV_FAST_TRAP
+	retl
+	 mov	%o1, %o0
+
+	/* %o0: devhandle
+	 * %o1:	tsbid
+	 * %o2:	&io_attributes
+	 * %o3:	&real_address
+	 *
+	 * returns %o0:	status
+	 */
+	.globl	pci_sun4v_iommu_getmap
+pci_sun4v_iommu_getmap:
+	mov	%o2, %o4
+	mov	HV_FAST_PCI_IOMMU_GETMAP, %o5
+	ta	HV_FAST_TRAP
+	stx	%o1, [%o4]
+	stx	%o2, [%o3]
+	retl
+	 mov	%o0, %o0
+
+	/* %o0: devhandle
+	 * %o1:	pci_device
+	 * %o2:	pci_config_offset
+	 * %o3:	size
+	 *
+	 * returns %o0:	data
+	 *
+	 * If there is an error, the data will be returned
+	 * as all 1's.
+	 */
+	.globl	pci_sun4v_config_get
+pci_sun4v_config_get:
+	mov	HV_FAST_PCI_CONFIG_GET, %o5
+	ta	HV_FAST_TRAP
+	brnz,a,pn %o1, 1f
+	 mov	-1, %o2
+1:	retl
+	 mov	%o2, %o0
+
+	/* %o0: devhandle
+	 * %o1:	pci_device
+	 * %o2:	pci_config_offset
+	 * %o3:	size
+	 * %o4:	data
+	 *
+	 * returns %o0:	status
+	 *
+	 * status will be zero if the operation completed
+	 * successfully, else -1 if not
+	 */
+	.globl	pci_sun4v_config_put
+pci_sun4v_config_put:
+	mov	HV_FAST_PCI_CONFIG_PUT, %o5
+	ta	HV_FAST_TRAP
+	brnz,a,pn %o1, 1f
+	 mov	-1, %o1
+1:	retl
+	 mov	%o1, %o0
diff -urN oldtree/arch/sparc64/kernel/process.c newtree/arch/sparc64/kernel/process.c
--- oldtree/arch/sparc64/kernel/process.c	2006-02-19 11:41:00.075331648 +0000
+++ newtree/arch/sparc64/kernel/process.c	2006-02-21 15:58:20.217073096 +0000
@@ -44,6 +44,7 @@
 #include <asm/fpumacro.h>
 #include <asm/head.h>
 #include <asm/cpudata.h>
+#include <asm/mmu_context.h>
 #include <asm/unistd.h>
 
 /* #define VERBOSE_SHOWREGS */
@@ -354,6 +355,7 @@
 	extern long etrap, etraptl1;
 #endif
 	__show_regs(regs);
+#if 0
 #ifdef CONFIG_SMP
 	{
 		extern void smp_report_regs(void);
@@ -361,6 +363,7 @@
 		smp_report_regs();
 	}
 #endif
+#endif
 
 #ifdef VERBOSE_SHOWREGS	
 	if (regs->tpc >= &etrap && regs->tpc < &etraptl1 &&
@@ -433,30 +436,15 @@
 void flush_thread(void)
 {
 	struct thread_info *t = current_thread_info();
+	struct mm_struct *mm;
 
 	if (t->flags & _TIF_ABI_PENDING)
 		t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT);
 
-	if (t->task->mm) {
-		unsigned long pgd_cache = 0UL;
-		if (test_thread_flag(TIF_32BIT)) {
-			struct mm_struct *mm = t->task->mm;
-			pgd_t *pgd0 = &mm->pgd[0];
-			pud_t *pud0 = pud_offset(pgd0, 0);
-
-			if (pud_none(*pud0)) {
-				pmd_t *page = pmd_alloc_one(mm, 0);
-				pud_set(pud0, page);
-			}
-			pgd_cache = get_pgd_cache(pgd0);
-		}
-		__asm__ __volatile__("stxa %0, [%1] %2\n\t"
-				     "membar #Sync"
-				     : /* no outputs */
-				     : "r" (pgd_cache),
-				     "r" (TSB_REG),
-				     "i" (ASI_DMMU));
-	}
+	mm = t->task->mm;
+	if (mm)
+		tsb_context_switch(mm);
+
 	set_thread_wsaved(0);
 
 	/* Turn off performance counters if on. */
@@ -555,6 +543,18 @@
 	}
 }
 
+static void stack_unaligned(unsigned long sp)
+{
+	siginfo_t info;
+
+	info.si_signo = SIGBUS;
+	info.si_errno = 0;
+	info.si_code = BUS_ADRALN;
+	info.si_addr = (void __user *) sp;
+	info.si_trapno = 0;
+	force_sig_info(SIGBUS, &info, current);
+}
+
 void fault_in_user_windows(void)
 {
 	struct thread_info *t = current_thread_info();
@@ -570,13 +570,17 @@
 	flush_user_windows();
 	window = get_thread_wsaved();
 
-	if (window != 0) {
+	if (likely(window != 0)) {
 		window -= 1;
 		do {
 			unsigned long sp = (t->rwbuf_stkptrs[window] + bias);
 			struct reg_window *rwin = &t->reg_window[window];
 
-			if (copy_to_user((char __user *)sp, rwin, winsize))
+			if (unlikely(sp & 0x7UL))
+				stack_unaligned(sp);
+
+			if (unlikely(copy_to_user((char __user *)sp,
+						  rwin, winsize)))
 				goto barf;
 		} while (window--);
 	}
diff -urN oldtree/arch/sparc64/kernel/ptrace.c newtree/arch/sparc64/kernel/ptrace.c
--- oldtree/arch/sparc64/kernel/ptrace.c	2006-02-19 11:41:00.076331496 +0000
+++ newtree/arch/sparc64/kernel/ptrace.c	2006-02-21 15:58:20.217073096 +0000
@@ -124,6 +124,9 @@
 {
 	BUG_ON(len > PAGE_SIZE);
 
+	if (tlb_type == hypervisor)
+		return;
+
 #ifdef DCACHE_ALIASING_POSSIBLE
 	/* If bit 13 of the kernel address we used to access the
 	 * user page is the same as the virtual address that page
diff -urN oldtree/arch/sparc64/kernel/rtrap.S newtree/arch/sparc64/kernel/rtrap.S
--- oldtree/arch/sparc64/kernel/rtrap.S	2006-02-19 11:41:00.076331496 +0000
+++ newtree/arch/sparc64/kernel/rtrap.S	2006-02-21 15:58:20.218072944 +0000
@@ -223,12 +223,26 @@
 		ldx			[%sp + PTREGS_OFF + PT_V9_G3], %g3
 		ldx			[%sp + PTREGS_OFF + PT_V9_G4], %g4
 		ldx			[%sp + PTREGS_OFF + PT_V9_G5], %g5
-		mov			TSB_REG, %g6
-		brnz,a,pn		%l3, 1f
-		 ldxa			[%g6] ASI_IMMU, %g5
-1:		ldx			[%sp + PTREGS_OFF + PT_V9_G6], %g6
+		brz,pt			%l3, 1f
+		mov			%g6, %l2
+
+		/* Must do this before thread reg is clobbered below.  */
+		LOAD_PER_CPU_BASE(%g5, %g6, %i0, %i1, %i2)
+1:
+		ldx			[%sp + PTREGS_OFF + PT_V9_G6], %g6
 		ldx			[%sp + PTREGS_OFF + PT_V9_G7], %g7
-		wrpr			%g0, RTRAP_PSTATE_AG_IRQOFF, %pstate
+
+		/* Normal globals are restored, go to trap globals.  */
+661:		wrpr			%g0, RTRAP_PSTATE_AG_IRQOFF, %pstate
+		nop
+		.section		.sun4v_2insn_patch, "ax"
+		.word			661b
+		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
+		SET_GL(1)
+		.previous
+
+		mov			%l2, %g6
+
 		ldx			[%sp + PTREGS_OFF + PT_V9_I0], %i0
 		ldx			[%sp + PTREGS_OFF + PT_V9_I1], %i1
 
@@ -252,27 +266,107 @@
 
 		brnz,pn			%l3, kern_rtt
 		 mov			PRIMARY_CONTEXT, %l7
-		ldxa			[%l7 + %l7] ASI_DMMU, %l0
+
+661:		ldxa			[%l7 + %l7] ASI_DMMU, %l0
+		.section		.sun4v_1insn_patch, "ax"
+		.word			661b
+		ldxa			[%l7 + %l7] ASI_MMU, %l0
+		.previous
+
 		sethi			%hi(sparc64_kern_pri_nuc_bits), %l1
 		ldx			[%l1 + %lo(sparc64_kern_pri_nuc_bits)], %l1
 		or			%l0, %l1, %l0
-		stxa			%l0, [%l7] ASI_DMMU
-		flush			%g6
+
+661:		stxa			%l0, [%l7] ASI_DMMU
+		.section		.sun4v_1insn_patch, "ax"
+		.word			661b
+		stxa			%l0, [%l7] ASI_MMU
+		.previous
+
+		sethi			%hi(KERNBASE), %l7
+		flush			%l7
 		rdpr			%wstate, %l1
 		rdpr			%otherwin, %l2
 		srl			%l1, 3, %l1
 
 		wrpr			%l2, %g0, %canrestore
 		wrpr			%l1, %g0, %wstate
-		wrpr			%g0, %g0, %otherwin
+		brnz,pt			%l2, user_rtt_restore
+		 wrpr			%g0, %g0, %otherwin
+
+		ldx			[%g6 + TI_FLAGS], %g3
+		wr			%g0, ASI_AIUP, %asi
+		rdpr			%cwp, %g1
+		andcc			%g3, _TIF_32BIT, %g0
+		sub			%g1, 1, %g1
+		bne,pt			%xcc, user_rtt_fill_32bit
+		 wrpr			%g1, %cwp
+		ba,a,pt			%xcc, user_rtt_fill_64bit
+
+user_rtt_fill_fixup:
+		rdpr	%cwp, %g1
+		add	%g1, 1, %g1
+		wrpr	%g1, 0x0, %cwp
+
+		rdpr	%wstate, %g2
+		sll	%g2, 3, %g2
+		wrpr	%g2, 0x0, %wstate
+
+		/* We know %canrestore and %otherwin are both zero.  */
+
+		sethi	%hi(sparc64_kern_pri_context), %g2
+		ldx	[%g2 + %lo(sparc64_kern_pri_context)], %g2
+		mov	PRIMARY_CONTEXT, %g1
+
+661:		stxa	%g2, [%g1] ASI_DMMU
+		.section .sun4v_1insn_patch, "ax"
+		.word	661b
+		stxa	%g2, [%g1] ASI_MMU
+		.previous
+
+		sethi	%hi(KERNBASE), %g1
+		flush	%g1
+
+		or	%g4, FAULT_CODE_WINFIXUP, %g4
+		stb	%g4, [%g6 + TI_FAULT_CODE]
+		stx	%g5, [%g6 + TI_FAULT_ADDR]
+
+		mov	%g6, %l1
+		wrpr	%g0, 0x0, %tl
+		wrpr	%g0, RTRAP_PSTATE, %pstate
+
+661:		nop
+		.section		.sun4v_1insn_patch, "ax"
+		.word			661b
+		SET_GL(0)
+		.previous
+
+		mov	%l1, %g6
+		ldx	[%g6 + TI_TASK], %g4
+		LOAD_PER_CPU_BASE(%g5, %g6, %g1, %g2, %g3)
+		call	do_sparc64_fault
+		 add	%sp, PTREGS_OFF, %o0
+		ba,pt	%xcc, rtrap
+		 nop
+
+user_rtt_pre_restore:
+		add			%g1, 1, %g1
+		wrpr			%g1, 0x0, %cwp
+
+user_rtt_restore:
 		restore
 		rdpr			%canrestore, %g1
 		wrpr			%g1, 0x0, %cleanwin
 		retry
 		nop
 
-kern_rtt:	restore
+kern_rtt:	rdpr			%canrestore, %g1
+		brz,pn			%g1, kern_rtt_fill
+		 nop
+kern_rtt_restore:
+		restore
 		retry
+
 to_kernel:
 #ifdef CONFIG_PREEMPT
 		ldsw			[%g6 + TI_PRE_COUNT], %l5
diff -urN oldtree/arch/sparc64/kernel/setup.c newtree/arch/sparc64/kernel/setup.c
--- oldtree/arch/sparc64/kernel/setup.c	2006-02-19 11:41:00.077331344 +0000
+++ newtree/arch/sparc64/kernel/setup.c	2006-02-21 15:58:20.220072640 +0000
@@ -64,12 +64,6 @@
 	16                      /* orig-video-points */
 };
 
-/* Typing sync at the prom prompt calls the function pointed to by
- * the sync callback which I set to the following function.
- * This should sync all filesystems and return, for now it just
- * prints out pretty messages and returns.
- */
-
 void (*prom_palette)(int);
 void (*prom_keyboard)(void);
 
@@ -79,259 +73,6 @@
 	prom_write(s, n);
 }
 
-static struct console prom_console = {
-	.name =		"prom",
-	.write =	prom_console_write,
-	.flags =	CON_CONSDEV | CON_ENABLED,
-	.index =	-1,
-};
-
-#define PROM_TRUE	-1
-#define PROM_FALSE	0
-
-/* Pretty sick eh? */
-int prom_callback(long *args)
-{
-	struct console *cons, *saved_console = NULL;
-	unsigned long flags;
-	char *cmd;
-	extern spinlock_t prom_entry_lock;
-
-	if (!args)
-		return -1;
-	if (!(cmd = (char *)args[0]))
-		return -1;
-
-	/*
-	 * The callback can be invoked on the cpu that first dropped 
-	 * into prom_cmdline after taking the serial interrupt, or on 
-	 * a slave processor that was smp_captured() if the 
-	 * administrator has done a switch-cpu inside obp. In either 
-	 * case, the cpu is marked as in-interrupt. Drop IRQ locks.
-	 */
-	irq_exit();
-
-	/* XXX Revisit the locking here someday.  This is a debugging
-	 * XXX feature so it isnt all that critical.  -DaveM
-	 */
-	local_irq_save(flags);
-
-	spin_unlock(&prom_entry_lock);
-	cons = console_drivers;
-	while (cons) {
-		unregister_console(cons);
-		cons->flags &= ~(CON_PRINTBUFFER);
-		cons->next = saved_console;
-		saved_console = cons;
-		cons = console_drivers;
-	}
-	register_console(&prom_console);
-	if (!strcmp(cmd, "sync")) {
-		prom_printf("PROM `%s' command...\n", cmd);
-		show_free_areas();
-		if (current->pid != 0) {
-			local_irq_enable();
-			sys_sync();
-			local_irq_disable();
-		}
-		args[2] = 0;
-		args[args[1] + 3] = -1;
-		prom_printf("Returning to PROM\n");
-	} else if (!strcmp(cmd, "va>tte-data")) {
-		unsigned long ctx, va;
-		unsigned long tte = 0;
-		long res = PROM_FALSE;
-
-		ctx = args[3];
-		va = args[4];
-		if (ctx) {
-			/*
-			 * Find process owning ctx, lookup mapping.
-			 */
-			struct task_struct *p;
-			struct mm_struct *mm = NULL;
-			pgd_t *pgdp;
-			pud_t *pudp;
-			pmd_t *pmdp;
-			pte_t *ptep;
-			pte_t pte;
-
-			for_each_process(p) {
-				mm = p->mm;
-				if (CTX_NRBITS(mm->context) == ctx)
-					break;
-			}
-			if (!mm ||
-			    CTX_NRBITS(mm->context) != ctx)
-				goto done;
-
-			pgdp = pgd_offset(mm, va);
-			if (pgd_none(*pgdp))
-				goto done;
-			pudp = pud_offset(pgdp, va);
-			if (pud_none(*pudp))
-				goto done;
-			pmdp = pmd_offset(pudp, va);
-			if (pmd_none(*pmdp))
-				goto done;
-
-			/* Preemption implicitly disabled by virtue of
-			 * being called from inside OBP.
-			 */
-			ptep = pte_offset_map(pmdp, va);
-			pte = *ptep;
-			if (pte_present(pte)) {
-				tte = pte_val(pte);
-				res = PROM_TRUE;
-			}
-			pte_unmap(ptep);
-			goto done;
-		}
-
-		if ((va >= KERNBASE) && (va < (KERNBASE + (4 * 1024 * 1024)))) {
-			extern unsigned long sparc64_kern_pri_context;
-
-			/* Spitfire Errata #32 workaround */
-			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
-					     "flush	%%g6"
-					     : /* No outputs */
-					     : "r" (sparc64_kern_pri_context),
-					       "r" (PRIMARY_CONTEXT),
-					       "i" (ASI_DMMU));
-
-			/*
-			 * Locked down tlb entry.
-			 */
-
-			if (tlb_type == spitfire)
-				tte = spitfire_get_dtlb_data(SPITFIRE_HIGHEST_LOCKED_TLBENT);
-			else if (tlb_type == cheetah || tlb_type == cheetah_plus)
-				tte = cheetah_get_ldtlb_data(CHEETAH_HIGHEST_LOCKED_TLBENT);
-
-			res = PROM_TRUE;
-			goto done;
-		}
-
-		if (va < PGDIR_SIZE) {
-			/*
-			 * vmalloc or prom_inherited mapping.
-			 */
-			pgd_t *pgdp;
-			pud_t *pudp;
-			pmd_t *pmdp;
-			pte_t *ptep;
-			pte_t pte;
-			int error;
-
-			if ((va >= LOW_OBP_ADDRESS) && (va < HI_OBP_ADDRESS)) {
-				tte = prom_virt_to_phys(va, &error);
-				if (!error)
-					res = PROM_TRUE;
-				goto done;
-			}
-			pgdp = pgd_offset_k(va);
-			if (pgd_none(*pgdp))
-				goto done;
-			pudp = pud_offset(pgdp, va);
-			if (pud_none(*pudp))
-				goto done;
-			pmdp = pmd_offset(pudp, va);
-			if (pmd_none(*pmdp))
-				goto done;
-
-			/* Preemption implicitly disabled by virtue of
-			 * being called from inside OBP.
-			 */
-			ptep = pte_offset_kernel(pmdp, va);
-			pte = *ptep;
-			if (pte_present(pte)) {
-				tte = pte_val(pte);
-				res = PROM_TRUE;
-			}
-			goto done;
-		}
-
-		if (va < PAGE_OFFSET) {
-			/*
-			 * No mappings here.
-			 */
-			goto done;
-		}
-
-		if (va & (1UL << 40)) {
-			/*
-			 * I/O page.
-			 */
-
-			tte = (__pa(va) & _PAGE_PADDR) |
-			      _PAGE_VALID | _PAGE_SZ4MB |
-			      _PAGE_E | _PAGE_P | _PAGE_W;
-			res = PROM_TRUE;
-			goto done;
-		}
-
-		/*
-		 * Normal page.
-		 */
-		tte = (__pa(va) & _PAGE_PADDR) |
-		      _PAGE_VALID | _PAGE_SZ4MB |
-		      _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W;
-		res = PROM_TRUE;
-
-	done:
-		if (res == PROM_TRUE) {
-			args[2] = 3;
-			args[args[1] + 3] = 0;
-			args[args[1] + 4] = res;
-			args[args[1] + 5] = tte;
-		} else {
-			args[2] = 2;
-			args[args[1] + 3] = 0;
-			args[args[1] + 4] = res;
-		}
-	} else if (!strcmp(cmd, ".soft1")) {
-		unsigned long tte;
-
-		tte = args[3];
-		prom_printf("%lx:\"%s%s%s%s%s\" ",
-			    (tte & _PAGE_SOFT) >> 7,
-			    tte & _PAGE_MODIFIED ? "M" : "-",
-			    tte & _PAGE_ACCESSED ? "A" : "-",
-			    tte & _PAGE_READ     ? "W" : "-",
-			    tte & _PAGE_WRITE    ? "R" : "-",
-			    tte & _PAGE_PRESENT  ? "P" : "-");
-
-		args[2] = 2;
-		args[args[1] + 3] = 0;
-		args[args[1] + 4] = PROM_TRUE;
-	} else if (!strcmp(cmd, ".soft2")) {
-		unsigned long tte;
-
-		tte = args[3];
-		prom_printf("%lx ", (tte & 0x07FC000000000000UL) >> 50);
-
-		args[2] = 2;
-		args[args[1] + 3] = 0;
-		args[args[1] + 4] = PROM_TRUE;
-	} else {
-		prom_printf("unknown PROM `%s' command...\n", cmd);
-	}
-	unregister_console(&prom_console);
-	while (saved_console) {
-		cons = saved_console;
-		saved_console = cons->next;
-		register_console(cons);
-	}
-	spin_lock(&prom_entry_lock);
-	local_irq_restore(flags);
-
-	/*
-	 * Restore in-interrupt status for a resume from obp.
-	 */
-	irq_enter();
-	return 0;
-}
-
 unsigned int boot_flags = 0;
 #define BOOTME_DEBUG  0x1
 #define BOOTME_SINGLE 0x2
@@ -479,15 +220,99 @@
 
 static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
 
-void register_prom_callbacks(void)
+static void __init per_cpu_patch(void)
 {
-	prom_setcallback(prom_callback);
-	prom_feval(": linux-va>tte-data 2 \" va>tte-data\" $callback drop ; "
-		   "' linux-va>tte-data to va>tte-data");
-	prom_feval(": linux-.soft1 1 \" .soft1\" $callback 2drop ; "
-		   "' linux-.soft1 to .soft1");
-	prom_feval(": linux-.soft2 1 \" .soft2\" $callback 2drop ; "
-		   "' linux-.soft2 to .soft2");
+	struct cpuid_patch_entry *p;
+	unsigned long ver;
+	int is_jbus;
+
+	if (tlb_type == spitfire && !this_is_starfire)
+		return;
+
+	is_jbus = 0;
+	if (tlb_type != hypervisor) {
+		__asm__ ("rdpr %%ver, %0" : "=r" (ver));
+		is_jbus = ((ver >> 32UL) == __JALAPENO_ID ||
+			   (ver >> 32UL) == __SERRANO_ID);
+	}
+
+	p = &__cpuid_patch;
+	while (p < &__cpuid_patch_end) {
+		unsigned long addr = p->addr;
+		unsigned int *insns;
+
+		switch (tlb_type) {
+		case spitfire:
+			insns = &p->starfire[0];
+			break;
+		case cheetah:
+		case cheetah_plus:
+			if (is_jbus)
+				insns = &p->cheetah_jbus[0];
+			else
+				insns = &p->cheetah_safari[0];
+			break;
+		case hypervisor:
+			insns = &p->sun4v[0];
+			break;
+		default:
+			prom_printf("Unknown cpu type, halting.\n");
+			prom_halt();
+		};
+
+		*(unsigned int *) (addr +  0) = insns[0];
+		wmb();
+		__asm__ __volatile__("flush	%0" : : "r" (addr +  0));
+
+		*(unsigned int *) (addr +  4) = insns[1];
+		wmb();
+		__asm__ __volatile__("flush	%0" : : "r" (addr +  4));
+
+		*(unsigned int *) (addr +  8) = insns[2];
+		wmb();
+		__asm__ __volatile__("flush	%0" : : "r" (addr +  8));
+
+		*(unsigned int *) (addr + 12) = insns[3];
+		wmb();
+		__asm__ __volatile__("flush	%0" : : "r" (addr + 12));
+
+		p++;
+	}
+}
+
+static void __init sun4v_patch(void)
+{
+	struct sun4v_1insn_patch_entry *p1;
+	struct sun4v_2insn_patch_entry *p2;
+
+	if (tlb_type != hypervisor)
+		return;
+
+	p1 = &__sun4v_1insn_patch;
+	while (p1 < &__sun4v_1insn_patch_end) {
+		unsigned long addr = p1->addr;
+
+		*(unsigned int *) (addr +  0) = p1->insn;
+		wmb();
+		__asm__ __volatile__("flush	%0" : : "r" (addr +  0));
+
+		p1++;
+	}
+
+	p2 = &__sun4v_2insn_patch;
+	while (p2 < &__sun4v_2insn_patch_end) {
+		unsigned long addr = p2->addr;
+
+		*(unsigned int *) (addr +  0) = p2->insns[0];
+		wmb();
+		__asm__ __volatile__("flush	%0" : : "r" (addr +  0));
+
+		*(unsigned int *) (addr +  4) = p2->insns[1];
+		wmb();
+		__asm__ __volatile__("flush	%0" : : "r" (addr +  4));
+
+		p2++;
+	}
 }
 
 void __init setup_arch(char **cmdline_p)
@@ -496,7 +321,10 @@
 	*cmdline_p = prom_getbootargs();
 	strcpy(saved_command_line, *cmdline_p);
 
-	printk("ARCH: SUN4U\n");
+	if (tlb_type == hypervisor)
+		printk("ARCH: SUN4V\n");
+	else
+		printk("ARCH: SUN4U\n");
 
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
@@ -507,6 +335,13 @@
 	/* Work out if we are starfire early on */
 	check_if_starfire();
 
+	/* Now we know enough to patch the get_cpuid sequences
+	 * used by trap code.
+	 */
+	per_cpu_patch();
+
+	sun4v_patch();
+
 	boot_flags_init(*cmdline_p);
 
 	idprom_init();
@@ -542,6 +377,9 @@
 	}
 #endif
 
+	/* Get boot processor trap_block[] setup.  */
+	init_cur_cpu_trap(current_thread_info());
+
 	paging_init();
 }
 
@@ -563,6 +401,12 @@
 		serial_console = 2;
 	} else if (idev == PROMDEV_IRSC && odev == PROMDEV_ORSC) {
 		serial_console = 3;
+	} else if (idev == PROMDEV_IVCONS && odev == PROMDEV_OVCONS) {
+		/* sunhv_console_init() doesn't check the serial_console
+		 * value anyways...
+		 */
+		serial_console = 4;
+		return add_preferred_console("ttyHV", 0, NULL);
 	} else {
 		prom_printf("Inconsistent console: "
 			    "input %d, output %d\n",
diff -urN oldtree/arch/sparc64/kernel/smp.c newtree/arch/sparc64/kernel/smp.c
--- oldtree/arch/sparc64/kernel/smp.c	2006-02-19 11:41:00.158319032 +0000
+++ newtree/arch/sparc64/kernel/smp.c	2006-02-21 15:58:20.271064888 +0000
@@ -38,6 +38,7 @@
 #include <asm/timer.h>
 #include <asm/starfire.h>
 #include <asm/tlb.h>
+#include <asm/sections.h>
 
 extern void calibrate_delay(void);
 
@@ -77,7 +78,7 @@
 
 void __init smp_store_cpu_info(int id)
 {
-	int cpu_node;
+	int cpu_node, def;
 
 	/* multiplier and counter set by
 	   smp_setup_percpu_timer()  */
@@ -87,24 +88,34 @@
 	cpu_data(id).clock_tick = prom_getintdefault(cpu_node,
 						     "clock-frequency", 0);
 
-	cpu_data(id).pgcache_size		= 0;
-	cpu_data(id).pte_cache[0]		= NULL;
-	cpu_data(id).pte_cache[1]		= NULL;
-	cpu_data(id).pgd_cache			= NULL;
 	cpu_data(id).idle_volume		= 1;
 
+	def = ((tlb_type == hypervisor) ? (8 * 1024) : (16 * 1024));
 	cpu_data(id).dcache_size = prom_getintdefault(cpu_node, "dcache-size",
-						      16 * 1024);
+						      def);
+
+	def = 32;
 	cpu_data(id).dcache_line_size =
-		prom_getintdefault(cpu_node, "dcache-line-size", 32);
+		prom_getintdefault(cpu_node, "dcache-line-size", def);
+
+	def = 16 * 1024;
 	cpu_data(id).icache_size = prom_getintdefault(cpu_node, "icache-size",
-						      16 * 1024);
+						      def);
+
+	def = 32;
 	cpu_data(id).icache_line_size =
-		prom_getintdefault(cpu_node, "icache-line-size", 32);
+		prom_getintdefault(cpu_node, "icache-line-size", def);
+
+	def = ((tlb_type == hypervisor) ?
+	       (3 * 1024 * 1024) :
+	       (4 * 1024 * 1024));
 	cpu_data(id).ecache_size = prom_getintdefault(cpu_node, "ecache-size",
-						      4 * 1024 * 1024);
+						      def);
+
+	def = 64;
 	cpu_data(id).ecache_line_size =
-		prom_getintdefault(cpu_node, "ecache-line-size", 64);
+		prom_getintdefault(cpu_node, "ecache-line-size", def);
+
 	printk("CPU[%d]: Caches "
 	       "D[sz(%d):line_sz(%d)] "
 	       "I[sz(%d):line_sz(%d)] "
@@ -119,27 +130,16 @@
 
 static volatile unsigned long callin_flag = 0;
 
-extern void inherit_locked_prom_mappings(int save_p);
-
-static inline void cpu_setup_percpu_base(unsigned long cpu_id)
-{
-	__asm__ __volatile__("mov	%0, %%g5\n\t"
-			     "stxa	%0, [%1] %2\n\t"
-			     "membar	#Sync"
-			     : /* no outputs */
-			     : "r" (__per_cpu_offset(cpu_id)),
-			       "r" (TSB_REG), "i" (ASI_IMMU));
-}
-
 void __init smp_callin(void)
 {
 	int cpuid = hard_smp_processor_id();
 
-	inherit_locked_prom_mappings(0);
+	__local_per_cpu_offset = __per_cpu_offset(cpuid);
 
-	__flush_tlb_all();
+	if (tlb_type == hypervisor)
+		sun4v_ktsb_register();
 
-	cpu_setup_percpu_base(cpuid);
+	__flush_tlb_all();
 
 	smp_setup_percpu_timer();
 
@@ -316,6 +316,8 @@
 	spin_unlock_irqrestore(&itc_sync_lock, flags);
 }
 
+extern void sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load);
+
 extern unsigned long sparc64_cpu_startup;
 
 /* The OBP cpu startup callback truncates the 3rd arg cookie to
@@ -331,21 +333,31 @@
 	unsigned long cookie =
 		(unsigned long)(&cpu_new_thread);
 	struct task_struct *p;
-	int timeout, ret, cpu_node;
+	int timeout, ret;
 
 	p = fork_idle(cpu);
 	callin_flag = 0;
 	cpu_new_thread = task_thread_info(p);
 	cpu_set(cpu, cpu_callout_map);
 
-	cpu_find_by_mid(cpu, &cpu_node);
-	prom_startcpu(cpu_node, entry, cookie);
+	if (tlb_type == hypervisor) {
+		/* Alloc the mondo queues, cpu will load them.  */
+		sun4v_init_mondo_queues(0, cpu, 1, 0);
+
+		prom_startcpu_cpuid(cpu, entry, cookie);
+	} else {
+		int cpu_node;
+
+		cpu_find_by_mid(cpu, &cpu_node);
+		prom_startcpu(cpu_node, entry, cookie);
+	}
 
 	for (timeout = 0; timeout < 5000000; timeout++) {
 		if (callin_flag)
 			break;
 		udelay(100);
 	}
+
 	if (callin_flag) {
 		ret = 0;
 	} else {
@@ -441,7 +453,7 @@
 static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask)
 {
 	u64 pstate, ver;
-	int nack_busy_id, is_jalapeno;
+	int nack_busy_id, is_jbus;
 
 	if (cpus_empty(mask))
 		return;
@@ -451,7 +463,8 @@
 	 * derivative processor.
 	 */
 	__asm__ ("rdpr %%ver, %0" : "=r" (ver));
-	is_jalapeno = ((ver >> 32) == 0x003e0016);
+	is_jbus = ((ver >> 32) == __JALAPENO_ID ||
+		   (ver >> 32) == __SERRANO_ID);
 
 	__asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
 
@@ -476,7 +489,7 @@
 		for_each_cpu_mask(i, mask) {
 			u64 target = (i << 14) | 0x70;
 
-			if (!is_jalapeno)
+			if (!is_jbus)
 				target |= (nack_busy_id << 24);
 			__asm__ __volatile__(
 				"stxa	%%g0, [%0] %1\n\t"
@@ -529,7 +542,7 @@
 			for_each_cpu_mask(i, mask) {
 				u64 check_mask;
 
-				if (is_jalapeno)
+				if (is_jbus)
 					check_mask = (0x2UL << (2*i));
 				else
 					check_mask = (0x2UL <<
@@ -544,6 +557,134 @@
 	}
 }
 
+#if 0
+/* Multi-cpu list version.  */
+static int init_cpu_list(u16 *list, cpumask_t mask)
+{
+	int i, cnt;
+
+	cnt = 0;
+	for_each_cpu_mask(i, mask)
+		list[cnt++] = i;
+
+	return cnt;
+}
+
+static int update_cpu_list(u16 *list, int orig_cnt, cpumask_t mask)
+{
+	int i;
+
+	for (i = 0; i < orig_cnt; i++) {
+		if (list[i] == 0xffff)
+			cpu_clear(i, mask);
+	}
+
+	return init_cpu_list(list, mask);
+}
+
+static void hypervisor_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask)
+{
+	int this_cpu = get_cpu();
+	struct trap_per_cpu *tb = &trap_block[this_cpu];
+	u64 *mondo = __va(tb->cpu_mondo_block_pa);
+	u16 *cpu_list = __va(tb->cpu_list_pa);
+	int cnt, retries;
+
+	mondo[0] = data0;
+	mondo[1] = data1;
+	mondo[2] = data2;
+	wmb();
+
+	retries = 0;
+	cnt = init_cpu_list(cpu_list, mask);
+	do {
+		register unsigned long func __asm__("%o5");
+		register unsigned long arg0 __asm__("%o0");
+		register unsigned long arg1 __asm__("%o1");
+		register unsigned long arg2 __asm__("%o2");
+
+		func = HV_FAST_CPU_MONDO_SEND;
+		arg0 = cnt;
+		arg1 = tb->cpu_list_pa;
+		arg2 = tb->cpu_mondo_block_pa;
+
+		__asm__ __volatile__("ta	%8"
+				     : "=&r" (func), "=&r" (arg0),
+				       "=&r" (arg1), "=&r" (arg2)
+				     : "0" (func), "1" (arg0),
+				       "2" (arg1), "3" (arg2),
+				       "i" (HV_FAST_TRAP)
+				     : "memory");
+		if (likely(arg0 == HV_EOK))
+			break;
+
+		if (unlikely(++retries > 100)) {
+			printk("CPU[%d]: sun4v mondo error %lu\n",
+			       this_cpu, func);
+			break;
+		}
+
+		cnt = update_cpu_list(cpu_list, cnt, mask);
+
+		udelay(2 * cnt);
+	} while (1);
+
+	put_cpu();
+}
+#else
+/* Single-cpu list version.  */
+static void hypervisor_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask)
+{
+	int this_cpu = get_cpu();
+	struct trap_per_cpu *tb = &trap_block[this_cpu];
+	u64 *mondo = __va(tb->cpu_mondo_block_pa);
+	u16 *cpu_list = __va(tb->cpu_list_pa);
+	int i;
+
+	mondo[0] = data0;
+	mondo[1] = data1;
+	mondo[2] = data2;
+	wmb();
+
+	for_each_cpu_mask(i, mask) {
+		int retries = 0;
+
+		do {
+			register unsigned long func __asm__("%o5");
+			register unsigned long arg0 __asm__("%o0");
+			register unsigned long arg1 __asm__("%o1");
+			register unsigned long arg2 __asm__("%o2");
+
+			cpu_list[0] = i;
+			func = HV_FAST_CPU_MONDO_SEND;
+			arg0 = 1;
+			arg1 = tb->cpu_list_pa;
+			arg2 = tb->cpu_mondo_block_pa;
+
+			__asm__ __volatile__("ta	%8"
+					     : "=&r" (func), "=&r" (arg0),
+					       "=&r" (arg1), "=&r" (arg2)
+					     : "0" (func), "1" (arg0),
+					       "2" (arg1), "3" (arg2),
+					       "i" (HV_FAST_TRAP)
+					     : "memory");
+			if (likely(arg0 == HV_EOK))
+				break;
+
+			if (unlikely(++retries > 100)) {
+				printk("CPU[%d]: sun4v mondo error %lu\n",
+				       this_cpu, func);
+				break;
+			}
+
+			udelay(2 * i);
+		} while (1);
+	}
+
+	put_cpu();
+}
+#endif
+
 /* Send cross call to all processors mentioned in MASK
  * except self.
  */
@@ -557,8 +698,10 @@
 
 	if (tlb_type == spitfire)
 		spitfire_xcall_deliver(data0, data1, data2, mask);
-	else
+	else if (tlb_type == cheetah || tlb_type == cheetah_plus)
 		cheetah_xcall_deliver(data0, data1, data2, mask);
+	else
+		hypervisor_xcall_deliver(data0, data1, data2, mask);
 	/* NOTE: Caller runs local copy on master. */
 
 	put_cpu();
@@ -594,11 +737,11 @@
  * You must not call this function with disabled interrupts or from a
  * hardware interrupt handler or from a bottom half handler.
  */
-int smp_call_function(void (*func)(void *info), void *info,
-		      int nonatomic, int wait)
+static int smp_call_function_mask(void (*func)(void *info), void *info,
+				  int nonatomic, int wait, cpumask_t mask)
 {
 	struct call_data_struct data;
-	int cpus = num_online_cpus() - 1;
+	int cpus = cpus_weight(mask) - 1;
 	long timeout;
 
 	if (!cpus)
@@ -616,7 +759,7 @@
 
 	call_data = &data;
 
-	smp_cross_call(&xcall_call_function, 0, 0, 0);
+	smp_cross_call_masked(&xcall_call_function, 0, 0, 0, mask);
 
 	/* 
 	 * Wait for other cpus to complete function or at
@@ -642,6 +785,13 @@
 	return 0;
 }
 
+int smp_call_function(void (*func)(void *info), void *info,
+		      int nonatomic, int wait)
+{
+	return smp_call_function_mask(func, info, nonatomic, wait,
+				      cpu_online_map);
+}
+
 void smp_call_function_client(int irq, struct pt_regs *regs)
 {
 	void (*func) (void *info) = call_data->func;
@@ -659,11 +809,22 @@
 	}
 }
 
+static void tsb_sync(void *info)
+{
+	struct mm_struct *mm = info;
+
+	if (current->active_mm == mm)
+		tsb_context_switch(mm);
+}
+
+void smp_tsb_sync(struct mm_struct *mm)
+{
+	smp_call_function_mask(tsb_sync, mm, 0, 1, mm->cpu_vm_mask);
+}
+
 extern unsigned long xcall_flush_tlb_mm;
 extern unsigned long xcall_flush_tlb_pending;
 extern unsigned long xcall_flush_tlb_kernel_range;
-extern unsigned long xcall_flush_tlb_all_spitfire;
-extern unsigned long xcall_flush_tlb_all_cheetah;
 extern unsigned long xcall_report_regs;
 extern unsigned long xcall_receive_signal;
 
@@ -693,11 +854,17 @@
 void smp_flush_dcache_page_impl(struct page *page, int cpu)
 {
 	cpumask_t mask = cpumask_of_cpu(cpu);
-	int this_cpu = get_cpu();
+	int this_cpu;
+
+	if (tlb_type == hypervisor)
+		return;
 
 #ifdef CONFIG_DEBUG_DCFLUSH
 	atomic_inc(&dcpage_flushes);
 #endif
+
+	this_cpu = get_cpu();
+
 	if (cpu == this_cpu) {
 		__local_flush_dcache_page(page);
 	} else if (cpu_online(cpu)) {
@@ -713,7 +880,7 @@
 					       __pa(pg_addr),
 					       (u64) pg_addr,
 					       mask);
-		} else {
+		} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 #ifdef DCACHE_ALIASING_POSSIBLE
 			data0 =
 				((u64)&xcall_flush_dcache_page_cheetah);
@@ -735,7 +902,12 @@
 	void *pg_addr = page_address(page);
 	cpumask_t mask = cpu_online_map;
 	u64 data0;
-	int this_cpu = get_cpu();
+	int this_cpu;
+
+	if (tlb_type == hypervisor)
+		return;
+
+	this_cpu = get_cpu();
 
 	cpu_clear(this_cpu, mask);
 
@@ -752,7 +924,7 @@
 				       __pa(pg_addr),
 				       (u64) pg_addr,
 				       mask);
-	} else {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 #ifdef DCACHE_ALIASING_POSSIBLE
 		data0 = ((u64)&xcall_flush_dcache_page_cheetah);
 		cheetah_xcall_deliver(data0,
@@ -778,8 +950,10 @@
 
 		if (tlb_type == spitfire)
 			spitfire_xcall_deliver(data0, 0, 0, mask);
-		else
+		else if (tlb_type == cheetah || tlb_type == cheetah_plus)
 			cheetah_xcall_deliver(data0, 0, 0, mask);
+		else if (tlb_type == hypervisor)
+			hypervisor_xcall_deliver(data0, 0, 0, mask);
 	}
 }
 
@@ -794,15 +968,6 @@
 	smp_cross_call(&xcall_report_regs, 0, 0, 0);
 }
 
-void smp_flush_tlb_all(void)
-{
-	if (tlb_type == spitfire)
-		smp_cross_call(&xcall_flush_tlb_all_spitfire, 0, 0, 0);
-	else
-		smp_cross_call(&xcall_flush_tlb_all_cheetah, 0, 0, 0);
-	__flush_tlb_all();
-}
-
 /* We know that the window frames of the user have been flushed
  * to the stack before we get here because all callers of us
  * are flush_tlb_*() routines, and these run after flush_cache_*()
@@ -944,24 +1109,19 @@
  * can service tlb flush xcalls...
  */
 extern void prom_world(int);
-extern void save_alternate_globals(unsigned long *);
-extern void restore_alternate_globals(unsigned long *);
+
 void smp_penguin_jailcell(int irq, struct pt_regs *regs)
 {
-	unsigned long global_save[24];
-
 	clear_softint(1 << irq);
 
 	preempt_disable();
 
 	__asm__ __volatile__("flushw");
-	save_alternate_globals(global_save);
 	prom_world(1);
 	atomic_inc(&smp_capture_registry);
 	membar_storeload_storestore();
 	while (penguins_are_doing_time)
 		rmb();
-	restore_alternate_globals(global_save);
 	atomic_dec(&smp_capture_registry);
 	prom_world(0);
 
@@ -1107,12 +1267,15 @@
 
 void __devinit smp_prepare_boot_cpu(void)
 {
-	if (hard_smp_processor_id() >= NR_CPUS) {
+	int cpu = hard_smp_processor_id();
+
+	if (cpu >= NR_CPUS) {
 		prom_printf("Serious problem, boot cpu id >= NR_CPUS\n");
 		prom_halt();
 	}
 
-	current_thread_info()->cpu = hard_smp_processor_id();
+	current_thread_info()->cpu = cpu;
+	__local_per_cpu_offset = __per_cpu_offset(cpu);
 
 	cpu_set(smp_processor_id(), cpu_online_map);
 	cpu_set(smp_processor_id(), phys_cpu_present_map);
@@ -1129,7 +1292,11 @@
 		if (!cpu_isset(cpu, cpu_online_map)) {
 			ret = -ENODEV;
 		} else {
-			smp_synchronize_one_tick(cpu);
+			/* On SUN4V, writes to %tick and %stick are
+			 * not allowed.
+			 */
+			if (tlb_type != hypervisor)
+				smp_synchronize_one_tick(cpu);
 		}
 	}
 	return ret;
@@ -1173,12 +1340,9 @@
 {
 	unsigned long goal, size, i;
 	char *ptr;
-	/* Created by linker magic */
-	extern char __per_cpu_start[], __per_cpu_end[];
 
 	/* Copy section for each CPU (we discard the original) */
-	goal = ALIGN(__per_cpu_end - __per_cpu_start, PAGE_SIZE);
-
+	goal = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES);
 #ifdef CONFIG_MODULES
 	if (goal < PERCPU_ENOUGH_ROOM)
 		goal = PERCPU_ENOUGH_ROOM;
@@ -1187,31 +1351,10 @@
 	for (size = 1UL; size < goal; size <<= 1UL)
 		__per_cpu_shift++;
 
-	/* Make sure the resulting __per_cpu_base value
-	 * will fit in the 43-bit sign extended IMMU
-	 * TSB register.
-	 */
-	ptr = __alloc_bootmem(size * NR_CPUS, PAGE_SIZE,
-			      (unsigned long) __per_cpu_start);
+	ptr = alloc_bootmem(size * NR_CPUS);
 
 	__per_cpu_base = ptr - __per_cpu_start;
 
-	if ((__per_cpu_shift < PAGE_SHIFT) ||
-	    (__per_cpu_base & ~PAGE_MASK) ||
-	    (__per_cpu_base != (((long) __per_cpu_base << 20) >> 20))) {
-		prom_printf("PER_CPU: Invalid layout, "
-			    "ptr[%p] shift[%lx] base[%lx]\n",
-			    ptr, __per_cpu_shift, __per_cpu_base);
-		prom_halt();
-	}
-
 	for (i = 0; i < NR_CPUS; i++, ptr += size)
 		memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
-
-	/* Finally, load in the boot cpu's base value.
-	 * We abuse the IMMU TSB register for trap handler
-	 * entry and exit loading of %g5.  That is why it
-	 * has to be page aligned.
-	 */
-	cpu_setup_percpu_base(hard_smp_processor_id());
 }
diff -urN oldtree/arch/sparc64/kernel/sparc64_ksyms.c newtree/arch/sparc64/kernel/sparc64_ksyms.c
--- oldtree/arch/sparc64/kernel/sparc64_ksyms.c	2006-02-19 11:41:00.158319032 +0000
+++ newtree/arch/sparc64/kernel/sparc64_ksyms.c	2006-02-21 15:58:20.271064888 +0000
@@ -241,10 +241,6 @@
 #endif
 
 EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(pte_alloc_one_kernel);
-#ifndef CONFIG_SMP
-EXPORT_SYMBOL(pgt_quicklists);
-#endif
 EXPORT_SYMBOL(put_fs_struct);
 
 /* math-emu wants this */
@@ -339,7 +335,7 @@
 EXPORT_SYMBOL(copy_from_user_fixup);
 EXPORT_SYMBOL(copy_in_user_fixup);
 EXPORT_SYMBOL(__strncpy_from_user);
-EXPORT_SYMBOL(__bzero_noasi);
+EXPORT_SYMBOL(__clear_user);
 
 /* Various address conversion macros use this. */
 EXPORT_SYMBOL(phys_base);
diff -urN oldtree/arch/sparc64/kernel/sun4v_ivec.S newtree/arch/sparc64/kernel/sun4v_ivec.S
--- oldtree/arch/sparc64/kernel/sun4v_ivec.S	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/sparc64/kernel/sun4v_ivec.S	2006-02-21 15:58:20.272064736 +0000
@@ -0,0 +1,334 @@
+/* sun4v_ivec.S: Sun4v interrupt vector handling.
+ *
+ * Copyright (C) 2006 <davem@davemloft.net>
+ */
+
+#include <asm/cpudata.h>
+#include <asm/intr_queue.h>
+
+	.text
+	.align	32
+
+sun4v_cpu_mondo:
+	/* Head offset in %g2, tail offset in %g4.
+	 * If they are the same, no work.
+	 */
+	mov	INTRQ_CPU_MONDO_HEAD, %g2
+	ldxa	[%g2] ASI_QUEUE, %g2
+	mov	INTRQ_CPU_MONDO_TAIL, %g4
+	ldxa	[%g4] ASI_QUEUE, %g4
+	cmp	%g2, %g4
+	be,pn	%xcc, sun4v_cpu_mondo_queue_empty
+	 nop
+
+	/* Get &trap_block[smp_processor_id()] into %g3.  */
+	ldxa	[%g0] ASI_SCRATCHPAD, %g3
+	sub	%g3, TRAP_PER_CPU_FAULT_INFO, %g3
+
+	/* Get CPU mondo queue base phys address into %g7.  */
+	ldx	[%g3 + TRAP_PER_CPU_CPU_MONDO_PA], %g7
+
+	/* Now get the cross-call arguments and handler PC, same
+	 * layout as sun4u:
+	 *
+	 * 1st 64-bit word: low half is 32-bit PC, put into %g3 and jmpl to it
+	 *                  high half is context arg to MMU flushes, into %g5
+	 * 2nd 64-bit word: 64-bit arg, load into %g1
+	 * 3rd 64-bit word: 64-bit arg, load into %g7
+	 */
+	ldxa	[%g7 + %g2] ASI_PHYS_USE_EC, %g3
+	add	%g2, 0x8, %g2
+	srlx	%g3, 32, %g5
+	ldxa	[%g7 + %g2] ASI_PHYS_USE_EC, %g1
+	add	%g2, 0x8, %g2
+	srl	%g3, 0, %g3
+	ldxa	[%g7 + %g2] ASI_PHYS_USE_EC, %g7
+	add	%g2, 0x40 - 0x8 - 0x8, %g2
+
+	/* Update queue head pointer.  */
+	sethi	%hi(8192 - 1), %g4
+	or	%g4, %lo(8192 - 1), %g4
+	and	%g2, %g4, %g2
+
+	mov	INTRQ_CPU_MONDO_HEAD, %g4
+	stxa	%g2, [%g4] ASI_QUEUE
+	membar	#Sync
+
+	jmpl	%g3, %g0
+	 nop
+
+sun4v_cpu_mondo_queue_empty:
+	retry
+
+sun4v_dev_mondo:
+	/* Head offset in %g2, tail offset in %g4.  */
+	mov	INTRQ_DEVICE_MONDO_HEAD, %g2
+	ldxa	[%g2] ASI_QUEUE, %g2
+	mov	INTRQ_DEVICE_MONDO_TAIL, %g4
+	ldxa	[%g4] ASI_QUEUE, %g4
+	cmp	%g2, %g4
+	be,pn	%xcc, sun4v_dev_mondo_queue_empty
+	 nop
+
+	/* Get &trap_block[smp_processor_id()] into %g3.  */
+	ldxa	[%g0] ASI_SCRATCHPAD, %g3
+	sub	%g3, TRAP_PER_CPU_FAULT_INFO, %g3
+
+	/* Get DEV mondo queue base phys address into %g5.  */
+	ldx	[%g3 + TRAP_PER_CPU_DEV_MONDO_PA], %g5
+
+	/* Load IVEC into %g3.  */
+	ldxa	[%g5 + %g2] ASI_PHYS_USE_EC, %g3
+	add	%g2, 0x40, %g2
+
+	/* XXX There can be a full 64-byte block of data here.
+	 * XXX This is how we can get at MSI vector data.
+	 * XXX Current we do not capture this, but when we do we'll
+	 * XXX need to add a 64-byte storage area in the struct ino_bucket
+	 * XXX or the struct irq_desc.
+	 */
+
+	/* Update queue head pointer, this frees up some registers.  */
+	sethi	%hi(8192 - 1), %g4
+	or	%g4, %lo(8192 - 1), %g4
+	and	%g2, %g4, %g2
+
+	mov	INTRQ_DEVICE_MONDO_HEAD, %g4
+	stxa	%g2, [%g4] ASI_QUEUE
+	membar	#Sync
+
+	/* Get &__irq_work[smp_processor_id()] into %g1.  */
+	TRAP_LOAD_IRQ_WORK(%g1, %g4)
+
+	/* Get &ivector_table[IVEC] into %g4.  */
+	sethi	%hi(ivector_table), %g4
+	sllx	%g3, 5, %g3
+	or	%g4, %lo(ivector_table), %g4
+	add	%g4, %g3, %g4
+
+	/* Load IRQ %pil into %g5.  */
+	ldub	[%g4 + 0x04], %g5
+
+	/* Insert ivector_table[] entry into __irq_work[] queue.  */
+	sllx	%g5, 2, %g3
+	lduw	[%g1 + %g3], %g2	/* g2 = irq_work(cpu, pil) */
+	stw	%g2, [%g4 + 0x00]	/* bucket->irq_chain = g2 */
+	stw	%g4, [%g1 + %g3]	/* irq_work(cpu, pil) = bucket */
+
+	/* Signal the interrupt by setting (1 << pil) in %softint.  */
+	mov	1, %g2
+	sllx	%g2, %g5, %g2
+	wr	%g2, 0x0, %set_softint
+
+sun4v_dev_mondo_queue_empty:
+	retry
+
+sun4v_res_mondo:
+	/* Head offset in %g2, tail offset in %g4.  */
+	mov	INTRQ_RESUM_MONDO_HEAD, %g2
+	ldxa	[%g2] ASI_QUEUE, %g2
+	mov	INTRQ_RESUM_MONDO_TAIL, %g4
+	ldxa	[%g4] ASI_QUEUE, %g4
+	cmp	%g2, %g4
+	be,pn	%xcc, sun4v_res_mondo_queue_empty
+	 nop
+
+	/* Get &trap_block[smp_processor_id()] into %g3.  */
+	ldxa	[%g0] ASI_SCRATCHPAD, %g3
+	sub	%g3, TRAP_PER_CPU_FAULT_INFO, %g3
+
+	/* Get RES mondo queue base phys address into %g5.  */
+	ldx	[%g3 + TRAP_PER_CPU_RESUM_MONDO_PA], %g5
+
+	/* Get RES kernel buffer base phys address into %g7.  */
+	ldx	[%g3 + TRAP_PER_CPU_RESUM_KBUF_PA], %g7
+
+	/* If the first word is non-zero, queue is full.  */
+	ldxa	[%g7 + %g2] ASI_PHYS_USE_EC, %g1
+	brnz,pn	%g1, sun4v_res_mondo_queue_full
+	 nop
+
+	/* Remember this entry's offset in %g1.  */
+	mov	%g2, %g1
+
+	/* Copy 64-byte queue entry into kernel buffer.  */
+	ldxa	[%g5 + %g2] ASI_PHYS_USE_EC, %g3
+	stxa	%g3, [%g7 + %g2] ASI_PHYS_USE_EC
+	add	%g2, 0x08, %g2
+	ldxa	[%g5 + %g2] ASI_PHYS_USE_EC, %g3
+	stxa	%g3, [%g7 + %g2] ASI_PHYS_USE_EC
+	add	%g2, 0x08, %g2
+	ldxa	[%g5 + %g2] ASI_PHYS_USE_EC, %g3
+	stxa	%g3, [%g7 + %g2] ASI_PHYS_USE_EC
+	add	%g2, 0x08, %g2
+	ldxa	[%g5 + %g2] ASI_PHYS_USE_EC, %g3
+	stxa	%g3, [%g7 + %g2] ASI_PHYS_USE_EC
+	add	%g2, 0x08, %g2
+	ldxa	[%g5 + %g2] ASI_PHYS_USE_EC, %g3
+	stxa	%g3, [%g7 + %g2] ASI_PHYS_USE_EC
+	add	%g2, 0x08, %g2
+	ldxa	[%g5 + %g2] ASI_PHYS_USE_EC, %g3
+	stxa	%g3, [%g7 + %g2] ASI_PHYS_USE_EC
+	add	%g2, 0x08, %g2
+	ldxa	[%g5 + %g2] ASI_PHYS_USE_EC, %g3
+	stxa	%g3, [%g7 + %g2] ASI_PHYS_USE_EC
+	add	%g2, 0x08, %g2
+	ldxa	[%g5 + %g2] ASI_PHYS_USE_EC, %g3
+	stxa	%g3, [%g7 + %g2] ASI_PHYS_USE_EC
+	add	%g2, 0x08, %g2
+
+	/* Update queue head pointer.  */
+	sethi	%hi(8192 - 1), %g4
+	or	%g4, %lo(8192 - 1), %g4
+	and	%g2, %g4, %g2
+
+	mov	INTRQ_RESUM_MONDO_HEAD, %g4
+	stxa	%g2, [%g4] ASI_QUEUE
+	membar	#Sync
+
+	/* Disable interrupts and save register state so we can call
+	 * C code.  The etrap handling will leave %g4 in %l4 for us
+	 * when it's done.
+	 */
+	rdpr	%pil, %g2
+	wrpr	%g0, 15, %pil
+	mov	%g1, %g4
+	ba,pt	%xcc, etrap_irq
+	 rd	%pc, %g7
+
+	/* Log the event.  */
+	add	%sp, PTREGS_OFF, %o0
+	call	sun4v_resum_error
+	 mov	%l4, %o1
+
+	/* Return from trap.  */
+	ba,pt	%xcc, rtrap_irq
+	 nop
+
+sun4v_res_mondo_queue_empty:
+	retry
+
+sun4v_res_mondo_queue_full:
+	/* The queue is full, consolidate our damage by setting
+	 * the head equal to the tail.  We'll just trap again otherwise.
+	 * Call C code to log the event.
+	 */
+	mov	INTRQ_RESUM_MONDO_HEAD, %g2
+	stxa	%g4, [%g2] ASI_QUEUE
+	membar	#Sync
+
+	rdpr	%pil, %g2
+	wrpr	%g0, 15, %pil
+	ba,pt	%xcc, etrap_irq
+	 rd	%pc, %g7
+
+	call	sun4v_resum_overflow
+	 add	%sp, PTREGS_OFF, %o0
+
+	ba,pt	%xcc, rtrap_irq
+	 nop
+
+sun4v_nonres_mondo:
+	/* Head offset in %g2, tail offset in %g4.  */
+	mov	INTRQ_NONRESUM_MONDO_HEAD, %g2
+	ldxa	[%g2] ASI_QUEUE, %g2
+	mov	INTRQ_NONRESUM_MONDO_TAIL, %g4
+	ldxa	[%g4] ASI_QUEUE, %g4
+	cmp	%g2, %g4
+	be,pn	%xcc, sun4v_nonres_mondo_queue_empty
+	 nop
+
+	/* Get &trap_block[smp_processor_id()] into %g3.  */
+	ldxa	[%g0] ASI_SCRATCHPAD, %g3
+	sub	%g3, TRAP_PER_CPU_FAULT_INFO, %g3
+
+	/* Get RES mondo queue base phys address into %g5.  */
+	ldx	[%g3 + TRAP_PER_CPU_NONRESUM_MONDO_PA], %g5
+
+	/* Get RES kernel buffer base phys address into %g7.  */
+	ldx	[%g3 + TRAP_PER_CPU_NONRESUM_KBUF_PA], %g7
+
+	/* If the first word is non-zero, queue is full.  */
+	ldxa	[%g7 + %g2] ASI_PHYS_USE_EC, %g1
+	brnz,pn	%g1, sun4v_nonres_mondo_queue_full
+	 nop
+
+	/* Remember this entry's offset in %g1.  */
+	mov	%g2, %g1
+
+	/* Copy 64-byte queue entry into kernel buffer.  */
+	ldxa	[%g5 + %g2] ASI_PHYS_USE_EC, %g3
+	stxa	%g3, [%g7 + %g2] ASI_PHYS_USE_EC
+	add	%g2, 0x08, %g2
+	ldxa	[%g5 + %g2] ASI_PHYS_USE_EC, %g3
+	stxa	%g3, [%g7 + %g2] ASI_PHYS_USE_EC
+	add	%g2, 0x08, %g2
+	ldxa	[%g5 + %g2] ASI_PHYS_USE_EC, %g3
+	stxa	%g3, [%g7 + %g2] ASI_PHYS_USE_EC
+	add	%g2, 0x08, %g2
+	ldxa	[%g5 + %g2] ASI_PHYS_USE_EC, %g3
+	stxa	%g3, [%g7 + %g2] ASI_PHYS_USE_EC
+	add	%g2, 0x08, %g2
+	ldxa	[%g5 + %g2] ASI_PHYS_USE_EC, %g3
+	stxa	%g3, [%g7 + %g2] ASI_PHYS_USE_EC
+	add	%g2, 0x08, %g2
+	ldxa	[%g5 + %g2] ASI_PHYS_USE_EC, %g3
+	stxa	%g3, [%g7 + %g2] ASI_PHYS_USE_EC
+	add	%g2, 0x08, %g2
+	ldxa	[%g5 + %g2] ASI_PHYS_USE_EC, %g3
+	stxa	%g3, [%g7 + %g2] ASI_PHYS_USE_EC
+	add	%g2, 0x08, %g2
+	ldxa	[%g5 + %g2] ASI_PHYS_USE_EC, %g3
+	stxa	%g3, [%g7 + %g2] ASI_PHYS_USE_EC
+	add	%g2, 0x08, %g2
+
+	/* Update queue head pointer.  */
+	sethi	%hi(8192 - 1), %g4
+	or	%g4, %lo(8192 - 1), %g4
+	and	%g2, %g4, %g2
+
+	mov	INTRQ_NONRESUM_MONDO_HEAD, %g4
+	stxa	%g2, [%g4] ASI_QUEUE
+	membar	#Sync
+
+	/* Disable interrupts and save register state so we can call
+	 * C code.  The etrap handling will leave %g4 in %l4 for us
+	 * when it's done.
+	 */
+	rdpr	%pil, %g2
+	wrpr	%g0, 15, %pil
+	mov	%g1, %g4
+	ba,pt	%xcc, etrap_irq
+	 rd	%pc, %g7
+
+	/* Log the event.  */
+	add	%sp, PTREGS_OFF, %o0
+	call	sun4v_nonresum_error
+	 mov	%l4, %o1
+
+	/* Return from trap.  */
+	ba,pt	%xcc, rtrap_irq
+	 nop
+
+sun4v_nonres_mondo_queue_empty:
+	retry
+
+sun4v_nonres_mondo_queue_full:
+	/* The queue is full, consolidate our damage by setting
+	 * the head equal to the tail.  We'll just trap again otherwise.
+	 * Call C code to log the event.
+	 */
+	mov	INTRQ_NONRESUM_MONDO_HEAD, %g2
+	stxa	%g4, [%g2] ASI_QUEUE
+	membar	#Sync
+
+	rdpr	%pil, %g2
+	wrpr	%g0, 15, %pil
+	ba,pt	%xcc, etrap_irq
+	 rd	%pc, %g7
+
+	call	sun4v_nonresum_overflow
+	 add	%sp, PTREGS_OFF, %o0
+
+	ba,pt	%xcc, rtrap_irq
+	 nop
diff -urN oldtree/arch/sparc64/kernel/sun4v_tlb_miss.S newtree/arch/sparc64/kernel/sun4v_tlb_miss.S
--- oldtree/arch/sparc64/kernel/sun4v_tlb_miss.S	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/sparc64/kernel/sun4v_tlb_miss.S	2006-02-21 15:58:20.272064736 +0000
@@ -0,0 +1,423 @@
+/* sun4v_tlb_miss.S: Sun4v TLB miss handlers.
+ *
+ * Copyright (C) 2006 <davem@davemloft.net>
+ */
+
+	.text
+	.align	32
+
+	/* Load ITLB fault information into VADDR and CTX, using BASE.  */
+#define LOAD_ITLB_INFO(BASE, VADDR, CTX) \
+	ldx	[BASE + HV_FAULT_I_ADDR_OFFSET], VADDR; \
+	ldx	[BASE + HV_FAULT_I_CTX_OFFSET], CTX;
+
+	/* Load DTLB fault information into VADDR and CTX, using BASE.  */
+#define LOAD_DTLB_INFO(BASE, VADDR, CTX) \
+	ldx	[BASE + HV_FAULT_D_ADDR_OFFSET], VADDR; \
+	ldx	[BASE + HV_FAULT_D_CTX_OFFSET], CTX;
+
+	/* DEST = (VADDR >> 22)
+	 *
+	 * Branch to ZERO_CTX_LABEL is context is zero.
+	 */
+#define	COMPUTE_TAG_TARGET(DEST, VADDR, CTX, ZERO_CTX_LABEL) \
+	srlx	VADDR, 22, DEST; \
+	brz,pn	CTX, ZERO_CTX_LABEL; \
+	 nop;
+
+	/* Create TSB pointer.  This is something like:
+	 *
+	 * index_mask = (512 << (tsb_reg & 0x7UL)) - 1UL;
+	 * tsb_base = tsb_reg & ~0x7UL;
+	 * tsb_index = ((vaddr >> PAGE_SHIFT) & tsb_mask);
+	 * tsb_ptr = tsb_base + (tsb_index * 16);
+	 */
+#define COMPUTE_TSB_PTR(TSB_PTR, VADDR, TMP1, TMP2)	\
+	and	TSB_PTR, 0x7, TMP1;			\
+	mov	512, TMP2;				\
+	andn	TSB_PTR, 0x7, TSB_PTR;			\
+	sllx	TMP2, TMP1, TMP2;			\
+	srlx	VADDR, PAGE_SHIFT, TMP1;		\
+	sub	TMP2, 1, TMP2;				\
+	and	TMP1, TMP2, TMP1;			\
+	sllx	TMP1, 4, TMP1;				\
+	add	TSB_PTR, TMP1, TSB_PTR;
+
+sun4v_itlb_miss:
+	/* Load MMU Miss base into %g2.  */
+	ldxa	[%g0] ASI_SCRATCHPAD, %g2
+	
+	/* Load UTSB reg into %g1.  */
+	mov	SCRATCHPAD_UTSBREG1, %g1
+	ldxa	[%g1] ASI_SCRATCHPAD, %g1
+
+	LOAD_ITLB_INFO(%g2, %g4, %g5)
+	COMPUTE_TAG_TARGET(%g6, %g4, %g5, kvmap_itlb_4v)
+	COMPUTE_TSB_PTR(%g1, %g4, %g3, %g7)
+
+	/* Load TSB tag/pte into %g2/%g3 and compare the tag.  */
+	ldda	[%g1] ASI_QUAD_LDD_PHYS_4V, %g2
+	cmp	%g2, %g6
+	sethi	%hi(PAGE_EXEC), %g7
+	ldx	[%g7 + %lo(PAGE_EXEC)], %g7
+	bne,a,pn %xcc, tsb_miss_page_table_walk
+	 mov	FAULT_CODE_ITLB, %g3
+	andcc	%g3, %g7, %g0
+	be,a,pn	%xcc, tsb_do_fault
+	 mov	FAULT_CODE_ITLB, %g3
+
+	/* We have a valid entry, make hypervisor call to load
+	 * I-TLB and return from trap.
+	 *
+	 * %g3:	PTE
+	 * %g4:	vaddr
+	 */
+sun4v_itlb_load:
+	ldxa	[%g0] ASI_SCRATCHPAD, %g6
+	mov	%o0, %g1		! save %o0
+	mov	%o1, %g2		! save %o1
+	mov	%o2, %g5		! save %o2
+	mov	%o3, %g7		! save %o3
+	mov	%g4, %o0		! vaddr
+	ldx	[%g6 + HV_FAULT_I_CTX_OFFSET], %o1	! ctx
+	mov	%g3, %o2		! PTE
+	mov	HV_MMU_IMMU, %o3	! flags
+	ta	HV_MMU_MAP_ADDR_TRAP
+	brnz,pn	%o0, sun4v_itlb_error
+	 mov	%g2, %o1		! restore %o1
+	mov	%g1, %o0		! restore %o0
+	mov	%g5, %o2		! restore %o2
+	mov	%g7, %o3		! restore %o3
+
+	retry
+
+sun4v_dtlb_miss:
+	/* Load MMU Miss base into %g2.  */
+	ldxa	[%g0] ASI_SCRATCHPAD, %g2
+	
+	/* Load UTSB reg into %g1.  */
+	mov	SCRATCHPAD_UTSBREG1, %g1
+	ldxa	[%g1] ASI_SCRATCHPAD, %g1
+
+	LOAD_DTLB_INFO(%g2, %g4, %g5)
+	COMPUTE_TAG_TARGET(%g6, %g4, %g5, kvmap_dtlb_4v)
+	COMPUTE_TSB_PTR(%g1, %g4, %g3, %g7)
+
+	/* Load TSB tag/pte into %g2/%g3 and compare the tag.  */
+	ldda	[%g1] ASI_QUAD_LDD_PHYS_4V, %g2
+	cmp	%g2, %g6
+	bne,a,pn %xcc, tsb_miss_page_table_walk
+	 mov	FAULT_CODE_ITLB, %g3
+
+	/* We have a valid entry, make hypervisor call to load
+	 * D-TLB and return from trap.
+	 *
+	 * %g3:	PTE
+	 * %g4:	vaddr
+	 */
+sun4v_dtlb_load:
+	ldxa	[%g0] ASI_SCRATCHPAD, %g6
+	mov	%o0, %g1		! save %o0
+	mov	%o1, %g2		! save %o1
+	mov	%o2, %g5		! save %o2
+	mov	%o3, %g7		! save %o3
+	mov	%g4, %o0		! vaddr
+	ldx	[%g6 + HV_FAULT_D_CTX_OFFSET], %o1	! ctx
+	mov	%g3, %o2		! PTE
+	mov	HV_MMU_DMMU, %o3	! flags
+	ta	HV_MMU_MAP_ADDR_TRAP
+	brnz,pn	%o0, sun4v_dtlb_error
+	 mov	%g2, %o1		! restore %o1
+	mov	%g1, %o0		! restore %o0
+	mov	%g5, %o2		! restore %o2
+	mov	%g7, %o3		! restore %o3
+
+	retry
+
+sun4v_dtlb_prot:
+	SET_GL(1)
+
+	/* Load MMU Miss base into %g5.  */
+	ldxa	[%g0] ASI_SCRATCHPAD, %g5
+	
+	ldx	[%g5 + HV_FAULT_D_ADDR_OFFSET], %g5
+	rdpr	%tl, %g1
+	cmp	%g1, 1
+	bgu,pn	%xcc, winfix_trampoline
+	 nop
+	ba,pt	%xcc, sparc64_realfault_common
+	 mov	FAULT_CODE_DTLB | FAULT_CODE_WRITE, %g4
+
+	/* Called from trap table:
+	 * %g4:	vaddr
+	 * %g5:	context
+	 * %g6: TAG TARGET
+	 */
+sun4v_itsb_miss:
+	mov	SCRATCHPAD_UTSBREG1, %g1
+	ldxa	[%g1] ASI_SCRATCHPAD, %g1
+	brz,pn	%g5, kvmap_itlb_4v
+	 mov	FAULT_CODE_ITLB, %g3
+	ba,a,pt	%xcc, sun4v_tsb_miss_common
+
+	/* Called from trap table:
+	 * %g4:	vaddr
+	 * %g5:	context
+	 * %g6: TAG TARGET
+	 */
+sun4v_dtsb_miss:
+	mov	SCRATCHPAD_UTSBREG1, %g1
+	ldxa	[%g1] ASI_SCRATCHPAD, %g1
+	brz,pn	%g5, kvmap_dtlb_4v
+	 mov	FAULT_CODE_DTLB, %g3
+
+	/* fallthrough */
+
+	/* Create TSB pointer into %g1.  This is something like:
+	 *
+	 * index_mask = (512 << (tsb_reg & 0x7UL)) - 1UL;
+	 * tsb_base = tsb_reg & ~0x7UL;
+	 * tsb_index = ((vaddr >> PAGE_SHIFT) & tsb_mask);
+	 * tsb_ptr = tsb_base + (tsb_index * 16);
+	 */
+sun4v_tsb_miss_common:
+	COMPUTE_TSB_PTR(%g1, %g4, %g5, %g7)
+
+	/* Branch directly to page table lookup.  We have SCRATCHPAD_MMU_MISS
+	 * still in %g2, so it's quite trivial to get at the PGD PHYS value
+	 * so we can preload it into %g7.
+	 */
+	sub	%g2, TRAP_PER_CPU_FAULT_INFO, %g2
+	ba,pt	%xcc, tsb_miss_page_table_walk_sun4v_fastpath
+	 ldx	[%g2 + TRAP_PER_CPU_PGD_PADDR], %g7
+
+sun4v_itlb_error:
+	sethi	%hi(sun4v_err_itlb_vaddr), %g1
+	stx	%g4, [%g1 + %lo(sun4v_err_itlb_vaddr)]
+	sethi	%hi(sun4v_err_itlb_ctx), %g1
+	ldxa	[%g0] ASI_SCRATCHPAD, %g6
+	ldx	[%g6 + HV_FAULT_I_CTX_OFFSET], %o1
+	stx	%o1, [%g1 + %lo(sun4v_err_itlb_ctx)]
+	sethi	%hi(sun4v_err_itlb_pte), %g1
+	stx	%g3, [%g1 + %lo(sun4v_err_itlb_pte)]
+	sethi	%hi(sun4v_err_itlb_error), %g1
+	stx	%o0, [%g1 + %lo(sun4v_err_itlb_error)]
+
+	rdpr	%tl, %g4
+	cmp	%g4, 1
+	ble,pt	%icc, 1f
+	 sethi	%hi(2f), %g7
+	ba,pt	%xcc, etraptl1
+	 or	%g7, %lo(2f), %g7
+
+1:	ba,pt	%xcc, etrap
+2:	 or	%g7, %lo(2b), %g7
+	call	sun4v_itlb_error_report
+	 add	%sp, PTREGS_OFF, %o0
+
+	/* NOTREACHED */
+
+sun4v_dtlb_error:
+	sethi	%hi(sun4v_err_dtlb_vaddr), %g1
+	stx	%g4, [%g1 + %lo(sun4v_err_dtlb_vaddr)]
+	sethi	%hi(sun4v_err_dtlb_ctx), %g1
+	ldxa	[%g0] ASI_SCRATCHPAD, %g6
+	ldx	[%g6 + HV_FAULT_D_CTX_OFFSET], %o1
+	stx	%o1, [%g1 + %lo(sun4v_err_dtlb_ctx)]
+	sethi	%hi(sun4v_err_dtlb_pte), %g1
+	stx	%g3, [%g1 + %lo(sun4v_err_dtlb_pte)]
+	sethi	%hi(sun4v_err_dtlb_error), %g1
+	stx	%o0, [%g1 + %lo(sun4v_err_dtlb_error)]
+
+	rdpr	%tl, %g4
+	cmp	%g4, 1
+	ble,pt	%icc, 1f
+	 sethi	%hi(2f), %g7
+	ba,pt	%xcc, etraptl1
+	 or	%g7, %lo(2f), %g7
+
+1:	ba,pt	%xcc, etrap
+2:	 or	%g7, %lo(2b), %g7
+	call	sun4v_dtlb_error_report
+	 add	%sp, PTREGS_OFF, %o0
+
+	/* NOTREACHED */
+
+	/* Instruction Access Exception, tl0. */
+sun4v_iacc:
+	ldxa	[%g0] ASI_SCRATCHPAD, %g2
+	ldx	[%g2 + HV_FAULT_I_TYPE_OFFSET], %g3
+	ldx	[%g2 + HV_FAULT_I_ADDR_OFFSET], %g4
+	ldx	[%g2 + HV_FAULT_I_CTX_OFFSET], %g5
+	sllx	%g3, 16, %g3
+	or	%g5, %g3, %g5
+	ba,pt	%xcc, etrap
+	 rd	%pc, %g7
+	mov	%l4, %o1
+	mov	%l5, %o2
+	call	sun4v_insn_access_exception
+	 add	%sp, PTREGS_OFF, %o0
+	ba,a,pt	%xcc, rtrap_clr_l6
+
+	/* Instruction Access Exception, tl1. */
+sun4v_iacc_tl1:
+	ldxa	[%g0] ASI_SCRATCHPAD, %g2
+	ldx	[%g2 + HV_FAULT_I_TYPE_OFFSET], %g3
+	ldx	[%g2 + HV_FAULT_I_ADDR_OFFSET], %g4
+	ldx	[%g2 + HV_FAULT_I_CTX_OFFSET], %g5
+	sllx	%g3, 16, %g3
+	or	%g5, %g3, %g5
+	ba,pt	%xcc, etraptl1
+	 rd	%pc, %g7
+	mov	%l4, %o1
+	mov	%l5, %o2
+	call	sun4v_insn_access_exception_tl1
+	 add	%sp, PTREGS_OFF, %o0
+	ba,a,pt	%xcc, rtrap_clr_l6
+
+	/* Data Access Exception, tl0. */
+sun4v_dacc:
+	ldxa	[%g0] ASI_SCRATCHPAD, %g2
+	ldx	[%g2 + HV_FAULT_D_TYPE_OFFSET], %g3
+	ldx	[%g2 + HV_FAULT_D_ADDR_OFFSET], %g4
+	ldx	[%g2 + HV_FAULT_D_CTX_OFFSET], %g5
+	sllx	%g3, 16, %g3
+	or	%g5, %g3, %g5
+	ba,pt	%xcc, etrap
+	 rd	%pc, %g7
+	mov	%l4, %o1
+	mov	%l5, %o2
+	call	sun4v_data_access_exception
+	 add	%sp, PTREGS_OFF, %o0
+	ba,a,pt	%xcc, rtrap_clr_l6
+
+	/* Data Access Exception, tl1. */
+sun4v_dacc_tl1:
+	ldxa	[%g0] ASI_SCRATCHPAD, %g2
+	ldx	[%g2 + HV_FAULT_D_TYPE_OFFSET], %g3
+	ldx	[%g2 + HV_FAULT_D_ADDR_OFFSET], %g4
+	ldx	[%g2 + HV_FAULT_D_CTX_OFFSET], %g5
+	sllx	%g3, 16, %g3
+	or	%g5, %g3, %g5
+	ba,pt	%xcc, etraptl1
+	 rd	%pc, %g7
+	mov	%l4, %o1
+	mov	%l5, %o2
+	call	sun4v_data_access_exception_tl1
+	 add	%sp, PTREGS_OFF, %o0
+	ba,a,pt	%xcc, rtrap_clr_l6
+
+	/* Memory Address Unaligned.  */
+sun4v_mna:
+	/* Window fixup? */
+	rdpr	%tl, %g2
+	cmp	%g2, 1
+	ble,pt	%icc, 1f
+	 nop
+
+	SET_GL(1)
+	ldxa	[%g0] ASI_SCRATCHPAD, %g5
+	ldx	[%g5 + HV_FAULT_D_ADDR_OFFSET], %g5
+	mov	HV_FAULT_TYPE_UNALIGNED, %g3
+	ldx	[%g5 + HV_FAULT_D_CTX_OFFSET], %g4
+	sllx	%g3, 16, %g3
+	or	%g4, %g3, %g4
+	ba,pt	%xcc, winfix_mna
+	 rdpr	%tpc, %g3
+	/* not reached */
+
+1:	ldxa	[%g0] ASI_SCRATCHPAD, %g2
+	mov	HV_FAULT_TYPE_UNALIGNED, %g3
+	ldx	[%g2 + HV_FAULT_D_ADDR_OFFSET], %g4
+	ldx	[%g2 + HV_FAULT_D_CTX_OFFSET], %g5
+	sllx	%g3, 16, %g3
+	or	%g5, %g3, %g5
+
+	ba,pt	%xcc, etrap
+	 rd	%pc, %g7
+	mov	%l4, %o1
+	mov	%l5, %o2
+	call	sun4v_do_mna
+	 add	%sp, PTREGS_OFF, %o0
+	ba,a,pt	%xcc, rtrap_clr_l6
+
+	/* Privileged Action.  */
+sun4v_privact:
+	ba,pt	%xcc, etrap
+	 rd	%pc, %g7
+	call	do_privact
+	 add	%sp, PTREGS_OFF, %o0
+	ba,a,pt	%xcc, rtrap_clr_l6
+
+	/* Unaligned ldd float, tl0. */
+sun4v_lddfmna:
+	ldxa	[%g0] ASI_SCRATCHPAD, %g2
+	ldx	[%g2 + HV_FAULT_D_TYPE_OFFSET], %g3
+	ldx	[%g2 + HV_FAULT_D_ADDR_OFFSET], %g4
+	ldx	[%g2 + HV_FAULT_D_CTX_OFFSET], %g5
+	sllx	%g3, 16, %g3
+	or	%g5, %g3, %g5
+	ba,pt	%xcc, etrap
+	 rd	%pc, %g7
+	mov	%l4, %o1
+	mov	%l5, %o2
+	call	handle_lddfmna
+	 add	%sp, PTREGS_OFF, %o0
+	ba,a,pt	%xcc, rtrap_clr_l6
+
+	/* Unaligned std float, tl0. */
+sun4v_stdfmna:
+	ldxa	[%g0] ASI_SCRATCHPAD, %g2
+	ldx	[%g2 + HV_FAULT_D_TYPE_OFFSET], %g3
+	ldx	[%g2 + HV_FAULT_D_ADDR_OFFSET], %g4
+	ldx	[%g2 + HV_FAULT_D_CTX_OFFSET], %g5
+	sllx	%g3, 16, %g3
+	or	%g5, %g3, %g5
+	ba,pt	%xcc, etrap
+	 rd	%pc, %g7
+	mov	%l4, %o1
+	mov	%l5, %o2
+	call	handle_stdfmna
+	 add	%sp, PTREGS_OFF, %o0
+	ba,a,pt	%xcc, rtrap_clr_l6
+
+#define BRANCH_ALWAYS	0x10680000
+#define NOP		0x01000000
+#define SUN4V_DO_PATCH(OLD, NEW)	\
+	sethi	%hi(NEW), %g1; \
+	or	%g1, %lo(NEW), %g1; \
+	sethi	%hi(OLD), %g2; \
+	or	%g2, %lo(OLD), %g2; \
+	sub	%g1, %g2, %g1; \
+	sethi	%hi(BRANCH_ALWAYS), %g3; \
+	sll	%g1, 11, %g1; \
+	srl	%g1, 11 + 2, %g1; \
+	or	%g3, %lo(BRANCH_ALWAYS), %g3; \
+	or	%g3, %g1, %g3; \
+	stw	%g3, [%g2]; \
+	sethi	%hi(NOP), %g3; \
+	or	%g3, %lo(NOP), %g3; \
+	stw	%g3, [%g2 + 0x4]; \
+	flush	%g2;
+
+	.globl	sun4v_patch_tlb_handlers
+	.type	sun4v_patch_tlb_handlers,#function
+sun4v_patch_tlb_handlers:
+	SUN4V_DO_PATCH(tl0_iamiss, sun4v_itlb_miss)
+	SUN4V_DO_PATCH(tl1_iamiss, sun4v_itlb_miss)
+	SUN4V_DO_PATCH(tl0_damiss, sun4v_dtlb_miss)
+	SUN4V_DO_PATCH(tl1_damiss, sun4v_dtlb_miss)
+	SUN4V_DO_PATCH(tl0_daprot, sun4v_dtlb_prot)
+	SUN4V_DO_PATCH(tl1_daprot, sun4v_dtlb_prot)
+	SUN4V_DO_PATCH(tl0_iax, sun4v_iacc)
+	SUN4V_DO_PATCH(tl1_iax, sun4v_iacc_tl1)
+	SUN4V_DO_PATCH(tl0_dax, sun4v_dacc)
+	SUN4V_DO_PATCH(tl1_dax, sun4v_dacc_tl1)
+	SUN4V_DO_PATCH(tl0_mna, sun4v_mna)
+	SUN4V_DO_PATCH(tl1_mna, sun4v_mna)
+	SUN4V_DO_PATCH(tl0_lddfmna, sun4v_lddfmna)
+	SUN4V_DO_PATCH(tl0_stdfmna, sun4v_stdfmna)
+	SUN4V_DO_PATCH(tl0_privact, sun4v_privact)
+	retl
+	 nop
+	.size	sun4v_patch_tlb_handlers,.-sun4v_patch_tlb_handlers
diff -urN oldtree/arch/sparc64/kernel/time.c newtree/arch/sparc64/kernel/time.c
--- oldtree/arch/sparc64/kernel/time.c	2006-02-19 11:41:00.162318424 +0000
+++ newtree/arch/sparc64/kernel/time.c	2006-02-21 15:58:20.274064432 +0000
@@ -193,16 +193,22 @@
 
 static void stick_init_tick(unsigned long offset)
 {
-	tick_disable_protection();
+	/* Writes to the %tick and %stick register are not
+	 * allowed on sun4v.  The Hypervisor controls that
+	 * bit, per-strand.
+	 */
+	if (tlb_type != hypervisor) {
+		tick_disable_protection();
 
-	/* Let the user get at STICK too. */
-	__asm__ __volatile__(
-	"	rd	%%asr24, %%g2\n"
-	"	andn	%%g2, %0, %%g2\n"
-	"	wr	%%g2, 0, %%asr24"
-	: /* no outputs */
-	: "r" (TICK_PRIV_BIT)
-	: "g1", "g2");
+		/* Let the user get at STICK too. */
+		__asm__ __volatile__(
+		"	rd	%%asr24, %%g2\n"
+		"	andn	%%g2, %0, %%g2\n"
+		"	wr	%%g2, 0, %%asr24"
+		: /* no outputs */
+		: "r" (TICK_PRIV_BIT)
+		: "g1", "g2");
+	}
 
 	__asm__ __volatile__(
 	"	rd	%%asr24, %%g1\n"
@@ -683,6 +689,48 @@
 	}
 }
 
+/* davem suggests we keep this within the 4M locked kernel image */
+static u32 starfire_get_time(void)
+{
+	static char obp_gettod[32];
+	static u32 unix_tod;
+
+	sprintf(obp_gettod, "h# %08x unix-gettod",
+		(unsigned int) (long) &unix_tod);
+	prom_feval(obp_gettod);
+
+	return unix_tod;
+}
+
+static u32 hypervisor_get_time(void)
+{
+	register unsigned long func asm("%o5");
+	register unsigned long arg0 asm("%o0");
+	register unsigned long arg1 asm("%o1");
+	int retries = 10000;
+
+retry:
+	func = HV_FAST_TOD_GET;
+	arg0 = 0;
+	arg1 = 0;
+	__asm__ __volatile__("ta	%6"
+			     : "=&r" (func), "=&r" (arg0), "=&r" (arg1)
+			     : "0" (func), "1" (arg0), "2" (arg1),
+			       "i" (HV_FAST_TRAP));
+	if (arg0 == HV_EOK)
+		return arg1;
+	if (arg0 == HV_EWOULDBLOCK) {
+		if (--retries > 0) {
+			udelay(100);
+			goto retry;
+		}
+		printk(KERN_WARNING "SUN4V: tod_get() timed out.\n");
+		return 0;
+	}
+	printk(KERN_WARNING "SUN4V: tod_get() not supported.\n");
+	return 0;
+}
+
 void __init clock_probe(void)
 {
 	struct linux_prom_registers clk_reg[2];
@@ -702,14 +750,14 @@
 
 
 	if (this_is_starfire) {
-		/* davem suggests we keep this within the 4M locked kernel image */
-		static char obp_gettod[256];
-		static u32 unix_tod;
-
-		sprintf(obp_gettod, "h# %08x unix-gettod",
-			(unsigned int) (long) &unix_tod);
-		prom_feval(obp_gettod);
-		xtime.tv_sec = unix_tod;
+		xtime.tv_sec = starfire_get_time();
+		xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
+		set_normalized_timespec(&wall_to_monotonic,
+		                        -xtime.tv_sec, -xtime.tv_nsec);
+		return;
+	}
+	if (tlb_type == hypervisor) {
+		xtime.tv_sec = hypervisor_get_time();
 		xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
 		set_normalized_timespec(&wall_to_monotonic,
 		                        -xtime.tv_sec, -xtime.tv_nsec);
@@ -981,11 +1029,10 @@
 }
 
 struct freq_table {
-	unsigned long udelay_val_ref;
 	unsigned long clock_tick_ref;
 	unsigned int ref_freq;
 };
-static DEFINE_PER_CPU(struct freq_table, sparc64_freq_table) = { 0, 0, 0 };
+static DEFINE_PER_CPU(struct freq_table, sparc64_freq_table) = { 0, 0 };
 
 unsigned long sparc64_get_clock_tick(unsigned int cpu)
 {
@@ -1007,16 +1054,11 @@
 
 	if (!ft->ref_freq) {
 		ft->ref_freq = freq->old;
-		ft->udelay_val_ref = cpu_data(cpu).udelay_val;
 		ft->clock_tick_ref = cpu_data(cpu).clock_tick;
 	}
 	if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
 	    (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
 	    (val == CPUFREQ_RESUMECHANGE)) {
-		cpu_data(cpu).udelay_val =
-			cpufreq_scale(ft->udelay_val_ref,
-				      ft->ref_freq,
-				      freq->new);
 		cpu_data(cpu).clock_tick =
 			cpufreq_scale(ft->clock_tick_ref,
 				      ft->ref_freq,
diff -urN oldtree/arch/sparc64/kernel/trampoline.S newtree/arch/sparc64/kernel/trampoline.S
--- oldtree/arch/sparc64/kernel/trampoline.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/kernel/trampoline.S	2006-02-21 15:58:20.275064280 +0000
@@ -16,6 +16,8 @@
 #include <asm/processor.h>
 #include <asm/thread_info.h>
 #include <asm/mmu.h>
+#include <asm/hypervisor.h>
+#include <asm/cpudata.h>
 
 	.data
 	.align	8
@@ -28,14 +30,19 @@
 dtlb_load:
 	.asciz	"SUNW,dtlb-load"
 
+	/* XXX __cpuinit this thing XXX */
+#define TRAMP_STACK_SIZE	1024
+	.align	16
+tramp_stack:
+	.skip	TRAMP_STACK_SIZE
+
 	.text
 	.align		8
 	.globl		sparc64_cpu_startup, sparc64_cpu_startup_end
 sparc64_cpu_startup:
-	flushw
-
-	BRANCH_IF_CHEETAH_BASE(g1,g5,cheetah_startup)
-	BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g5,cheetah_plus_startup)
+	BRANCH_IF_SUN4V(g1, niagara_startup)
+	BRANCH_IF_CHEETAH_BASE(g1, g5, cheetah_startup)
+	BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1, g5, cheetah_plus_startup)
 
 	ba,pt	%xcc, spitfire_startup
 	 nop
@@ -55,6 +62,7 @@
 	or	%g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5
 	stxa	%g5, [%g0] ASI_DCU_CONTROL_REG
 	membar	#Sync
+	/* fallthru */
 
 cheetah_generic_startup:
 	mov	TSB_EXTENSION_P, %g3
@@ -70,7 +78,9 @@
 	stxa	%g0, [%g3] ASI_DMMU
 	stxa	%g0, [%g3] ASI_IMMU
 	membar	#Sync
+	/* fallthru */
 
+niagara_startup:
 	/* Disable STICK_INT interrupts. */
 	sethi		%hi(0x80000000), %g5
 	sllx		%g5, 32, %g5
@@ -85,17 +95,17 @@
 	membar		#Sync
 
 startup_continue:
-	wrpr		%g0, 15, %pil
-
 	sethi		%hi(0x80000000), %g2
 	sllx		%g2, 32, %g2
 	wr		%g2, 0, %tick_cmpr
 
+	mov		%o0, %l0
+
+	BRANCH_IF_SUN4V(g1, niagara_lock_tlb)
+
 	/* Call OBP by hand to lock KERNBASE into i/d tlbs.
 	 * We lock 2 consequetive entries if we are 'bigkernel'.
 	 */
-	mov		%o0, %l0
-
 	sethi		%hi(prom_entry_lock), %g2
 1:	ldstub		[%g2 + %lo(prom_entry_lock)], %g1
 	membar		#StoreLoad | #StoreStore
@@ -105,7 +115,6 @@
 	sethi		%hi(p1275buf), %g2
 	or		%g2, %lo(p1275buf), %g2
 	ldx		[%g2 + 0x10], %l2
-	mov		%sp, %l1
 	add		%l2, -(192 + 128), %sp
 	flushw
 
@@ -142,8 +151,7 @@
 
 	sethi		%hi(bigkernel), %g2
 	lduw		[%g2 + %lo(bigkernel)], %g2
-	cmp		%g2, 0
-	be,pt		%icc, do_dtlb
+	brz,pt		%g2, do_dtlb
 	 nop
 
 	sethi		%hi(call_method), %g2
@@ -214,8 +222,7 @@
 
 	sethi		%hi(bigkernel), %g2
 	lduw		[%g2 + %lo(bigkernel)], %g2
-	cmp		%g2, 0
-	be,pt		%icc, do_unlock
+	brz,pt		%g2, do_unlock
 	 nop
 
 	sethi		%hi(call_method), %g2
@@ -257,99 +264,180 @@
 	stb		%g0, [%g2 + %lo(prom_entry_lock)]
 	membar		#StoreStore | #StoreLoad
 
-	mov		%l1, %sp
-	flushw
+	ba,pt		%xcc, after_lock_tlb
+	 nop
+
+niagara_lock_tlb:
+	mov		HV_FAST_MMU_MAP_PERM_ADDR, %o5
+	sethi		%hi(KERNBASE), %o0
+	clr		%o1
+	sethi		%hi(kern_locked_tte_data), %o2
+	ldx		[%o2 + %lo(kern_locked_tte_data)], %o2
+	mov		HV_MMU_IMMU, %o3
+	ta		HV_FAST_TRAP
+
+	mov		HV_FAST_MMU_MAP_PERM_ADDR, %o5
+	sethi		%hi(KERNBASE), %o0
+	clr		%o1
+	sethi		%hi(kern_locked_tte_data), %o2
+	ldx		[%o2 + %lo(kern_locked_tte_data)], %o2
+	mov		HV_MMU_DMMU, %o3
+	ta		HV_FAST_TRAP
+
+	sethi		%hi(bigkernel), %g2
+	lduw		[%g2 + %lo(bigkernel)], %g2
+	brz,pt		%g2, after_lock_tlb
+	 nop
 
-	mov		%l0, %o0
+	mov		HV_FAST_MMU_MAP_PERM_ADDR, %o5
+	sethi		%hi(KERNBASE + 0x400000), %o0
+	clr		%o1
+	sethi		%hi(kern_locked_tte_data), %o2
+	ldx		[%o2 + %lo(kern_locked_tte_data)], %o2
+	sethi		%hi(0x400000), %o3
+	add		%o2, %o3, %o2
+	mov		HV_MMU_IMMU, %o3
+	ta		HV_FAST_TRAP
+
+	mov		HV_FAST_MMU_MAP_PERM_ADDR, %o5
+	sethi		%hi(KERNBASE + 0x400000), %o0
+	clr		%o1
+	sethi		%hi(kern_locked_tte_data), %o2
+	ldx		[%o2 + %lo(kern_locked_tte_data)], %o2
+	sethi		%hi(0x400000), %o3
+	add		%o2, %o3, %o2
+	mov		HV_MMU_DMMU, %o3
+	ta		HV_FAST_TRAP
 
+after_lock_tlb:
 	wrpr		%g0, (PSTATE_PRIV | PSTATE_PEF), %pstate
 	wr		%g0, 0, %fprs
 
-	/* XXX Buggy PROM... */
-	srl		%o0, 0, %o0
-	ldx		[%o0], %g6
-
 	wr		%g0, ASI_P, %asi
 
 	mov		PRIMARY_CONTEXT, %g7
-	stxa		%g0, [%g7] ASI_DMMU
+
+661:	stxa		%g0, [%g7] ASI_DMMU
+	.section	.sun4v_1insn_patch, "ax"
+	.word		661b
+	stxa		%g0, [%g7] ASI_MMU
+	.previous
+
 	membar		#Sync
 	mov		SECONDARY_CONTEXT, %g7
-	stxa		%g0, [%g7] ASI_DMMU
+
+661:	stxa		%g0, [%g7] ASI_DMMU
+	.section	.sun4v_1insn_patch, "ax"
+	.word		661b
+	stxa		%g0, [%g7] ASI_MMU
+	.previous
+
 	membar		#Sync
 
-	mov		1, %g5
-	sllx		%g5, THREAD_SHIFT, %g5
-	sub		%g5, (STACKFRAME_SZ + STACK_BIAS), %g5
-	add		%g6, %g5, %sp
+	/* Everything we do here, until we properly take over the
+	 * trap table, must be done with extreme care.  We cannot
+	 * make any references to %g6 (current thread pointer),
+	 * %g4 (current task pointer), or %g5 (base of current cpu's
+	 * per-cpu area) until we properly take over the trap table
+	 * from the firmware and hypervisor.
+	 *
+	 * Get onto temporary stack which is in the locked kernel image.
+	 */
+	sethi		%hi(tramp_stack), %g1
+	or		%g1, %lo(tramp_stack), %g1
+	add		%g1, TRAMP_STACK_SIZE, %g1
+	sub		%g1, STACKFRAME_SZ + STACK_BIAS, %sp
 	mov		0, %fp
 
-	wrpr		%g0, 0, %wstate
-	wrpr		%g0, 0, %tl
-
-	/* Setup the trap globals, then we can resurface. */
-	rdpr		%pstate, %o1
-	mov		%g6, %o2
-	wrpr		%o1, PSTATE_AG, %pstate
-	sethi		%hi(sparc64_ttable_tl0), %g5
-	wrpr		%g5, %tba
-	mov		%o2, %g6
-
-	wrpr		%o1, PSTATE_MG, %pstate
-#define KERN_HIGHBITS		((_PAGE_VALID|_PAGE_SZ4MB)^0xfffff80000000000)
-#define KERN_LOWBITS		(_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
+	/* Put garbage in these registers to trap any access to them.  */
+	set		0xdeadbeef, %g4
+	set		0xdeadbeef, %g5
+	set		0xdeadbeef, %g6
 
-	mov		TSB_REG, %g1
-	stxa		%g0, [%g1] ASI_DMMU
-	membar		#Sync
-	mov		TLB_SFSR, %g1
-	sethi		%uhi(KERN_HIGHBITS), %g2
-	or		%g2, %ulo(KERN_HIGHBITS), %g2
-	sllx		%g2, 32, %g2
-	or		%g2, KERN_LOWBITS, %g2
+	call		init_irqwork_curcpu
+	 nop
 
-	BRANCH_IF_ANY_CHEETAH(g3,g7,9f)
+	sethi		%hi(tlb_type), %g3
+	lduw		[%g3 + %lo(tlb_type)], %g2
+	cmp		%g2, 3
+	bne,pt		%icc, 1f
+	 nop
 
-	ba,pt		%xcc, 1f
+	call		hard_smp_processor_id
 	 nop
+	
+	mov		%o0, %o1
+	mov		0, %o0
+	mov		0, %o2
+	call		sun4v_init_mondo_queues
+	 mov		1, %o3
 
-9:
-	sethi		%uhi(VPTE_BASE_CHEETAH), %g3
-	or		%g3, %ulo(VPTE_BASE_CHEETAH), %g3
-	ba,pt		%xcc, 2f
-	 sllx		%g3, 32, %g3
-1:
-	sethi		%uhi(VPTE_BASE_SPITFIRE), %g3
-	or		%g3, %ulo(VPTE_BASE_SPITFIRE), %g3
-	sllx		%g3, 32, %g3
-
-2:
-	clr	%g7
-#undef KERN_HIGHBITS
-#undef KERN_LOWBITS
+1:	call		init_cur_cpu_trap
+	 ldx		[%l0], %o0
 
-	wrpr		%o1, 0x0, %pstate
-	ldx		[%g6 + TI_TASK], %g4
+	/* Start using proper page size encodings in ctx register.  */
+	sethi		%hi(sparc64_kern_pri_context), %g3
+	ldx		[%g3 + %lo(sparc64_kern_pri_context)], %g2
+	mov		PRIMARY_CONTEXT, %g1
+
+661:	stxa		%g2, [%g1] ASI_DMMU
+	.section	.sun4v_1insn_patch, "ax"
+	.word		661b
+	stxa		%g2, [%g1] ASI_MMU
+	.previous
+
+	membar		#Sync
 
 	wrpr		%g0, 0, %wstate
 
-	call		init_irqwork_curcpu
+	/* As a hack, put &init_thread_union into %g6.
+	 * prom_world() loads from here to restore the %asi
+	 * register.
+	 */
+	sethi		%hi(init_thread_union), %g6
+	or		%g6, %lo(init_thread_union), %g6
+
+	sethi		%hi(is_sun4v), %o0
+	lduw		[%o0 + %lo(is_sun4v)], %o0
+	brz,pt		%o0, 1f
 	 nop
 
-	/* Start using proper page size encodings in ctx register.  */
-	sethi	%hi(sparc64_kern_pri_context), %g3
-	ldx	[%g3 + %lo(sparc64_kern_pri_context)], %g2
-	mov	PRIMARY_CONTEXT, %g1
-	stxa	%g2, [%g1] ASI_DMMU
-	membar	#Sync
+	TRAP_LOAD_TRAP_BLOCK(%g2, %g3)
+	add		%g2, TRAP_PER_CPU_FAULT_INFO, %g2
+	stxa		%g2, [%g0] ASI_SCRATCHPAD
+
+	/* Compute physical address:
+	 *
+	 * paddr = kern_base + (mmfsa_vaddr - KERNBASE)
+	 */
+	sethi		%hi(KERNBASE), %g3
+	sub		%g2, %g3, %g2
+	sethi		%hi(kern_base), %g3
+	ldx		[%g3 + %lo(kern_base)], %g3
+	add		%g2, %g3, %o1
+
+	call		prom_set_trap_table_sun4v
+	 sethi		%hi(sparc64_ttable_tl0), %o0
+
+	ba,pt		%xcc, 2f
+	 nop
+
+1:	call		prom_set_trap_table
+	 sethi		%hi(sparc64_ttable_tl0), %o0
+
+2:	ldx		[%l0], %g6
+	ldx		[%g6 + TI_TASK], %g4
+
+	mov		1, %g5
+	sllx		%g5, THREAD_SHIFT, %g5
+	sub		%g5, (STACKFRAME_SZ + STACK_BIAS), %g5
+	add		%g6, %g5, %sp
+	mov		0, %fp
 
 	rdpr		%pstate, %o1
 	or		%o1, PSTATE_IE, %o1
 	wrpr		%o1, 0, %pstate
 
-	call		prom_set_trap_table
-	 sethi		%hi(sparc64_ttable_tl0), %o0
-
 	call		smp_callin
 	 nop
 	call		cpu_idle
diff -urN oldtree/arch/sparc64/kernel/traps.c newtree/arch/sparc64/kernel/traps.c
--- oldtree/arch/sparc64/kernel/traps.c	2006-02-19 11:41:00.163318272 +0000
+++ newtree/arch/sparc64/kernel/traps.c	2006-02-21 15:58:20.286062608 +0000
@@ -38,6 +38,7 @@
 #include <asm/processor.h>
 #include <asm/timer.h>
 #include <asm/kdebug.h>
+#include <asm/head.h>
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
 #endif
@@ -72,12 +73,14 @@
 
 static void dump_tl1_traplog(struct tl1_traplog *p)
 {
-	int i;
+	int i, limit;
+
+	printk(KERN_EMERG "TRAPLOG: Error at trap level 0x%lx, "
+	       "dumping track stack.\n", p->tl);
 
-	printk("TRAPLOG: Error at trap level 0x%lx, dumping track stack.\n",
-	       p->tl);
-	for (i = 0; i < 4; i++) {
-		printk(KERN_CRIT
+	limit = (tlb_type == hypervisor) ? 2 : 4;
+	for (i = 0; i < limit; i++) {
+		printk(KERN_EMERG
 		       "TRAPLOG: Trap level %d TSTATE[%016lx] TPC[%016lx] "
 		       "TNPC[%016lx] TT[%lx]\n",
 		       i + 1,
@@ -179,6 +182,45 @@
 	spitfire_insn_access_exception(regs, sfsr, sfar);
 }
 
+void sun4v_insn_access_exception(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx)
+{
+	unsigned short type = (type_ctx >> 16);
+	unsigned short ctx  = (type_ctx & 0xffff);
+	siginfo_t info;
+
+	if (notify_die(DIE_TRAP, "instruction access exception", regs,
+		       0, 0x8, SIGTRAP) == NOTIFY_STOP)
+		return;
+
+	if (regs->tstate & TSTATE_PRIV) {
+		printk("sun4v_insn_access_exception: ADDR[%016lx] "
+		       "CTX[%04x] TYPE[%04x], going.\n",
+		       addr, ctx, type);
+		die_if_kernel("Iax", regs);
+	}
+
+	if (test_thread_flag(TIF_32BIT)) {
+		regs->tpc &= 0xffffffff;
+		regs->tnpc &= 0xffffffff;
+	}
+	info.si_signo = SIGSEGV;
+	info.si_errno = 0;
+	info.si_code = SEGV_MAPERR;
+	info.si_addr = (void __user *) addr;
+	info.si_trapno = 0;
+	force_sig_info(SIGSEGV, &info, current);
+}
+
+void sun4v_insn_access_exception_tl1(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx)
+{
+	if (notify_die(DIE_TRAP_TL1, "instruction access exception tl1", regs,
+		       0, 0x8, SIGTRAP) == NOTIFY_STOP)
+		return;
+
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
+	sun4v_insn_access_exception(regs, addr, type_ctx);
+}
+
 void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
 {
 	siginfo_t info;
@@ -227,6 +269,45 @@
 	spitfire_data_access_exception(regs, sfsr, sfar);
 }
 
+void sun4v_data_access_exception(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx)
+{
+	unsigned short type = (type_ctx >> 16);
+	unsigned short ctx  = (type_ctx & 0xffff);
+	siginfo_t info;
+
+	if (notify_die(DIE_TRAP, "data access exception", regs,
+		       0, 0x8, SIGTRAP) == NOTIFY_STOP)
+		return;
+
+	if (regs->tstate & TSTATE_PRIV) {
+		printk("sun4v_data_access_exception: ADDR[%016lx] "
+		       "CTX[%04x] TYPE[%04x], going.\n",
+		       addr, ctx, type);
+		die_if_kernel("Dax", regs);
+	}
+
+	if (test_thread_flag(TIF_32BIT)) {
+		regs->tpc &= 0xffffffff;
+		regs->tnpc &= 0xffffffff;
+	}
+	info.si_signo = SIGSEGV;
+	info.si_errno = 0;
+	info.si_code = SEGV_MAPERR;
+	info.si_addr = (void __user *) addr;
+	info.si_trapno = 0;
+	force_sig_info(SIGSEGV, &info, current);
+}
+
+void sun4v_data_access_exception_tl1(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx)
+{
+	if (notify_die(DIE_TRAP_TL1, "data access exception tl1", regs,
+		       0, 0x8, SIGTRAP) == NOTIFY_STOP)
+		return;
+
+	dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
+	sun4v_data_access_exception(regs, addr, type_ctx);
+}
+
 #ifdef CONFIG_PCI
 /* This is really pathetic... */
 extern volatile int pci_poke_in_progress;
@@ -788,7 +869,8 @@
 		cheetah_error_log[i].afsr = CHAFSR_INVALID;
 
 	__asm__ ("rdpr %%ver, %0" : "=r" (ver));
-	if ((ver >> 32) == 0x003e0016) {
+	if ((ver >> 32) == __JALAPENO_ID ||
+	    (ver >> 32) == __SERRANO_ID) {
 		cheetah_error_table = &__jalapeno_error_table[0];
 		cheetah_afsr_errors = JPAFSR_ERRORS;
 	} else if ((ver >> 32) == 0x003e0015) {
@@ -1666,6 +1748,226 @@
 	       regs->tpc);
 }
 
+struct sun4v_error_entry {
+	u64		err_handle;
+	u64		err_stick;
+
+	u32		err_type;
+#define SUN4V_ERR_TYPE_UNDEFINED	0
+#define SUN4V_ERR_TYPE_UNCORRECTED_RES	1
+#define SUN4V_ERR_TYPE_PRECISE_NONRES	2
+#define SUN4V_ERR_TYPE_DEFERRED_NONRES	3
+#define SUN4V_ERR_TYPE_WARNING_RES	4
+
+	u32		err_attrs;
+#define SUN4V_ERR_ATTRS_PROCESSOR	0x00000001
+#define SUN4V_ERR_ATTRS_MEMORY		0x00000002
+#define SUN4V_ERR_ATTRS_PIO		0x00000004
+#define SUN4V_ERR_ATTRS_INT_REGISTERS	0x00000008
+#define SUN4V_ERR_ATTRS_FPU_REGISTERS	0x00000010
+#define SUN4V_ERR_ATTRS_USER_MODE	0x01000000
+#define SUN4V_ERR_ATTRS_PRIV_MODE	0x02000000
+#define SUN4V_ERR_ATTRS_RES_QUEUE_FULL	0x80000000
+
+	u64		err_raddr;
+	u32		err_size;
+	u16		err_cpu;
+	u16		err_pad;
+};
+
+static atomic_t sun4v_resum_oflow_cnt = ATOMIC_INIT(0);
+static atomic_t sun4v_nonresum_oflow_cnt = ATOMIC_INIT(0);
+
+static const char *sun4v_err_type_to_str(u32 type)
+{
+	switch (type) {
+	case SUN4V_ERR_TYPE_UNDEFINED:
+		return "undefined";
+	case SUN4V_ERR_TYPE_UNCORRECTED_RES:
+		return "uncorrected resumable";
+	case SUN4V_ERR_TYPE_PRECISE_NONRES:
+		return "precise nonresumable";
+	case SUN4V_ERR_TYPE_DEFERRED_NONRES:
+		return "deferred nonresumable";
+	case SUN4V_ERR_TYPE_WARNING_RES:
+		return "warning resumable";
+	default:
+		return "unknown";
+	};
+}
+
+static void sun4v_log_error(struct sun4v_error_entry *ent, int cpu, const char *pfx, atomic_t *ocnt)
+{
+	int cnt;
+
+	printk("%s: Reporting on cpu %d\n", pfx, cpu);
+	printk("%s: err_handle[%lx] err_stick[%lx] err_type[%08x:%s]\n",
+	       pfx,
+	       ent->err_handle, ent->err_stick,
+	       ent->err_type,
+	       sun4v_err_type_to_str(ent->err_type));
+	printk("%s: err_attrs[%08x:%s %s %s %s %s %s %s %s]\n",
+	       pfx,
+	       ent->err_attrs,
+	       ((ent->err_attrs & SUN4V_ERR_ATTRS_PROCESSOR) ?
+		"processor" : ""),
+	       ((ent->err_attrs & SUN4V_ERR_ATTRS_MEMORY) ?
+		"memory" : ""),
+	       ((ent->err_attrs & SUN4V_ERR_ATTRS_PIO) ?
+		"pio" : ""),
+	       ((ent->err_attrs & SUN4V_ERR_ATTRS_INT_REGISTERS) ?
+		"integer-regs" : ""),
+	       ((ent->err_attrs & SUN4V_ERR_ATTRS_FPU_REGISTERS) ?
+		"fpu-regs" : ""),
+	       ((ent->err_attrs & SUN4V_ERR_ATTRS_USER_MODE) ?
+		"user" : ""),
+	       ((ent->err_attrs & SUN4V_ERR_ATTRS_PRIV_MODE) ?
+		"privileged" : ""),
+	       ((ent->err_attrs & SUN4V_ERR_ATTRS_RES_QUEUE_FULL) ?
+		"queue-full" : ""));
+	printk("%s: err_raddr[%016lx] err_size[%u] err_cpu[%u]\n",
+	       pfx,
+	       ent->err_raddr, ent->err_size, ent->err_cpu);
+
+	if ((cnt = atomic_read(ocnt)) != 0) {
+		atomic_set(ocnt, 0);
+		wmb();
+		printk("%s: Queue overflowed %d times.\n",
+		       pfx, cnt);
+	}
+}
+
+/* We run with %pil set to 15 and PSTATE_IE enabled in %pstate.
+ * Log the event and clear the first word of the entry.
+ */
+void sun4v_resum_error(struct pt_regs *regs, unsigned long offset)
+{
+	struct sun4v_error_entry *ent, local_copy;
+	struct trap_per_cpu *tb;
+	unsigned long paddr;
+	int cpu;
+
+	cpu = get_cpu();
+
+	tb = &trap_block[cpu];
+	paddr = tb->resum_kernel_buf_pa + offset;
+	ent = __va(paddr);
+
+	memcpy(&local_copy, ent, sizeof(struct sun4v_error_entry));
+
+	/* We have a local copy now, so release the entry.  */
+	ent->err_handle = 0;
+	wmb();
+
+	put_cpu();
+
+	sun4v_log_error(&local_copy, cpu,
+			KERN_ERR "RESUMABLE ERROR",
+			&sun4v_resum_oflow_cnt);
+}
+
+/* If we try to printk() we'll probably make matters worse, by trying
+ * to retake locks this cpu already holds or causing more errors. So
+ * just bump a counter, and we'll report these counter bumps above.
+ */
+void sun4v_resum_overflow(struct pt_regs *regs)
+{
+	atomic_inc(&sun4v_resum_oflow_cnt);
+}
+
+/* We run with %pil set to 15 and PSTATE_IE enabled in %pstate.
+ * Log the event, clear the first word of the entry, and die.
+ */
+void sun4v_nonresum_error(struct pt_regs *regs, unsigned long offset)
+{
+	struct sun4v_error_entry *ent, local_copy;
+	struct trap_per_cpu *tb;
+	unsigned long paddr;
+	int cpu;
+
+	cpu = get_cpu();
+
+	tb = &trap_block[cpu];
+	paddr = tb->nonresum_kernel_buf_pa + offset;
+	ent = __va(paddr);
+
+	memcpy(&local_copy, ent, sizeof(struct sun4v_error_entry));
+
+	/* We have a local copy now, so release the entry.  */
+	ent->err_handle = 0;
+	wmb();
+
+	put_cpu();
+
+#ifdef CONFIG_PCI
+	/* Check for the special PCI poke sequence. */
+	if (pci_poke_in_progress && pci_poke_cpu == cpu) {
+		pci_poke_faulted = 1;
+		regs->tpc += 4;
+		regs->tnpc = regs->tpc + 4;
+		return;
+	}
+#endif
+
+	sun4v_log_error(&local_copy, cpu,
+			KERN_EMERG "NON-RESUMABLE ERROR",
+			&sun4v_nonresum_oflow_cnt);
+
+	panic("Non-resumable error.");
+}
+
+/* If we try to printk() we'll probably make matters worse, by trying
+ * to retake locks this cpu already holds or causing more errors. So
+ * just bump a counter, and we'll report these counter bumps above.
+ */
+void sun4v_nonresum_overflow(struct pt_regs *regs)
+{
+	/* XXX Actually even this can make not that much sense.  Perhaps
+	 * XXX we should just pull the plug and panic directly from here?
+	 */
+	atomic_inc(&sun4v_nonresum_oflow_cnt);
+}
+
+unsigned long sun4v_err_itlb_vaddr;
+unsigned long sun4v_err_itlb_ctx;
+unsigned long sun4v_err_itlb_pte;
+unsigned long sun4v_err_itlb_error;
+
+void sun4v_itlb_error_report(struct pt_regs *regs, int tl)
+{
+	if (tl > 1)
+		dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
+
+	printk(KERN_EMERG "SUN4V-ITLB: Error at TPC[%lx], tl %d\n",
+	       regs->tpc, tl);
+	printk(KERN_EMERG "SUN4V-ITLB: vaddr[%lx] ctx[%lx] "
+	       "pte[%lx] error[%lx]\n",
+	       sun4v_err_itlb_vaddr, sun4v_err_itlb_ctx,
+	       sun4v_err_itlb_pte, sun4v_err_itlb_error);
+
+	prom_halt();
+}
+
+unsigned long sun4v_err_dtlb_vaddr;
+unsigned long sun4v_err_dtlb_ctx;
+unsigned long sun4v_err_dtlb_pte;
+unsigned long sun4v_err_dtlb_error;
+
+void sun4v_dtlb_error_report(struct pt_regs *regs, int tl)
+{
+	if (tl > 1)
+		dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
+
+	printk(KERN_EMERG "SUN4V-DTLB: Error at TPC[%lx], tl %d\n",
+	       regs->tpc, tl);
+	printk(KERN_EMERG "SUN4V-DTLB: vaddr[%lx] ctx[%lx] "
+	       "pte[%lx] error[%lx]\n",
+	       sun4v_err_dtlb_vaddr, sun4v_err_dtlb_ctx,
+	       sun4v_err_dtlb_pte, sun4v_err_dtlb_error);
+
+	prom_halt();
+}
+
 void do_fpe_common(struct pt_regs *regs)
 {
 	if (regs->tstate & TSTATE_PRIV) {
@@ -1924,10 +2226,11 @@
 		}
 		user_instruction_dump ((unsigned int __user *) regs->tpc);
 	}
+#if 0
 #ifdef CONFIG_SMP
 	smp_report_regs();
 #endif
-                                                	
+#endif                                                	
 	if (regs->tstate & TSTATE_PRIV)
 		do_exit(SIGKILL);
 	do_exit(SIGSEGV);
@@ -1968,6 +2271,8 @@
 	force_sig_info(SIGILL, &info, current);
 }
 
+extern void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn);
+
 void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr)
 {
 	siginfo_t info;
@@ -1977,13 +2282,7 @@
 		return;
 
 	if (regs->tstate & TSTATE_PRIV) {
-		extern void kernel_unaligned_trap(struct pt_regs *regs,
-						  unsigned int insn, 
-						  unsigned long sfar,
-						  unsigned long sfsr);
-
-		kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc),
-				      sfar, sfsr);
+		kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc));
 		return;
 	}
 	info.si_signo = SIGBUS;
@@ -1994,6 +2293,26 @@
 	force_sig_info(SIGBUS, &info, current);
 }
 
+void sun4v_do_mna(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx)
+{
+	siginfo_t info;
+
+	if (notify_die(DIE_TRAP, "memory address unaligned", regs,
+		       0, 0x34, SIGSEGV) == NOTIFY_STOP)
+		return;
+
+	if (regs->tstate & TSTATE_PRIV) {
+		kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc));
+		return;
+	}
+	info.si_signo = SIGBUS;
+	info.si_errno = 0;
+	info.si_code = BUS_ADRALN;
+	info.si_addr = (void __user *) addr;
+	info.si_trapno = 0;
+	force_sig_info(SIGBUS, &info, current);
+}
+
 void do_privop(struct pt_regs *regs)
 {
 	siginfo_t info;
@@ -2130,7 +2449,22 @@
 	}
 }
 
+struct trap_per_cpu trap_block[NR_CPUS];
+
+/* This can get invoked before sched_init() so play it super safe
+ * and use hard_smp_processor_id().
+ */
+void init_cur_cpu_trap(struct thread_info *t)
+{
+	int cpu = hard_smp_processor_id();
+	struct trap_per_cpu *p = &trap_block[cpu];
+
+	p->thread = t;
+	p->pgd_paddr = 0;
+}
+
 extern void thread_info_offsets_are_bolixed_dave(void);
+extern void trap_per_cpu_offsets_are_bolixed_dave(void);
 
 /* Only invoked on boot processor. */
 void __init trap_init(void)
@@ -2154,7 +2488,6 @@
 	    TI_KERN_CNTD0 != offsetof(struct thread_info, kernel_cntd0) ||
 	    TI_KERN_CNTD1 != offsetof(struct thread_info, kernel_cntd1) ||
 	    TI_PCR != offsetof(struct thread_info, pcr_reg) ||
-	    TI_CEE_STUFF != offsetof(struct thread_info, cee_stuff) ||
 	    TI_PRE_COUNT != offsetof(struct thread_info, preempt_count) ||
 	    TI_NEW_CHILD != offsetof(struct thread_info, new_child) ||
 	    TI_SYS_NOERROR != offsetof(struct thread_info, syscall_noerror) ||
@@ -2165,6 +2498,29 @@
 	    (TI_FPREGS & (64 - 1)))
 		thread_info_offsets_are_bolixed_dave();
 
+	if (TRAP_PER_CPU_THREAD != offsetof(struct trap_per_cpu, thread) ||
+	    (TRAP_PER_CPU_PGD_PADDR !=
+	     offsetof(struct trap_per_cpu, pgd_paddr)) ||
+	    (TRAP_PER_CPU_CPU_MONDO_PA !=
+	     offsetof(struct trap_per_cpu, cpu_mondo_pa)) ||
+	    (TRAP_PER_CPU_DEV_MONDO_PA !=
+	     offsetof(struct trap_per_cpu, dev_mondo_pa)) ||
+	    (TRAP_PER_CPU_RESUM_MONDO_PA !=
+	     offsetof(struct trap_per_cpu, resum_mondo_pa)) ||
+	    (TRAP_PER_CPU_RESUM_KBUF_PA !=
+	     offsetof(struct trap_per_cpu, resum_kernel_buf_pa)) ||
+	    (TRAP_PER_CPU_NONRESUM_MONDO_PA !=
+	     offsetof(struct trap_per_cpu, nonresum_mondo_pa)) ||
+	    (TRAP_PER_CPU_NONRESUM_KBUF_PA !=
+	     offsetof(struct trap_per_cpu, nonresum_kernel_buf_pa)) ||
+	    (TRAP_PER_CPU_FAULT_INFO !=
+	     offsetof(struct trap_per_cpu, fault_info)) ||
+	    (TRAP_PER_CPU_CPU_MONDO_BLOCK_PA !=
+	     offsetof(struct trap_per_cpu, cpu_mondo_block_pa)) ||
+	    (TRAP_PER_CPU_CPU_LIST_PA !=
+	     offsetof(struct trap_per_cpu, cpu_list_pa)))
+		trap_per_cpu_offsets_are_bolixed_dave();
+
 	/* Attach to the address space of init_task.  On SMP we
 	 * do this in smp.c:smp_callin for other cpus.
 	 */
diff -urN oldtree/arch/sparc64/kernel/tsb.S newtree/arch/sparc64/kernel/tsb.S
--- oldtree/arch/sparc64/kernel/tsb.S	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/sparc64/kernel/tsb.S	2006-02-21 15:58:20.287062456 +0000
@@ -0,0 +1,309 @@
+/* tsb.S: Sparc64 TSB table handling.
+ *
+ * Copyright (C) 2006 David S. Miller <davem@davemloft.net>
+ */
+
+#include <asm/tsb.h>
+#include <asm/hypervisor.h>
+
+	.text
+	.align	32
+
+	/* Invoked from TLB miss handler, we are in the
+	 * MMU global registers and they are setup like
+	 * this:
+	 *
+	 * %g1: TSB entry pointer
+	 * %g2:	available temporary
+	 * %g3:	FAULT_CODE_{D,I}TLB
+	 * %g4:	available temporary
+	 * %g5:	available temporary
+	 * %g6: TAG TARGET
+	 * %g7:	available temporary, will be loaded by us with
+	 *      the physical address base of the linux page
+	 *      tables for the current address space
+	 */
+tsb_miss_dtlb:
+	mov		TLB_TAG_ACCESS, %g4
+	ba,pt		%xcc, tsb_miss_page_table_walk
+	 ldxa		[%g4] ASI_DMMU, %g4
+
+tsb_miss_itlb:
+	mov		TLB_TAG_ACCESS, %g4
+	ba,pt		%xcc, tsb_miss_page_table_walk
+	 ldxa		[%g4] ASI_IMMU, %g4
+
+	/* At this point we have:
+	 * %g4 --	missing virtual address
+	 * %g1 --	TSB entry address
+	 * %g6 --	TAG TARGET (vaddr >> 22)
+	 */
+tsb_miss_page_table_walk:
+	TRAP_LOAD_PGD_PHYS(%g7, %g5)
+
+	/* And now we have the PGD base physical address in %g7.  */
+tsb_miss_page_table_walk_sun4v_fastpath:
+	USER_PGTABLE_WALK_TL1(%g4, %g7, %g5, %g2, tsb_do_fault)
+
+tsb_reload:
+	TSB_LOCK_TAG(%g1, %g2, %g7)
+
+	/* Load and check PTE.  */
+	ldxa		[%g5] ASI_PHYS_USE_EC, %g5
+	mov		1, %g7
+	sllx		%g7, TSB_TAG_INVALID_BIT, %g7
+	brgez,a,pn	%g5, tsb_do_fault
+	 TSB_STORE(%g1, %g7)
+
+	/* If it is larger than the base page size, don't
+	 * bother putting it into the TSB.
+	 */
+	sethi		%hi(_PAGE_ALL_SZ_BITS), %g7
+	ldx		[%g7 + %lo(_PAGE_ALL_SZ_BITS)], %g7
+	and		%g5, %g7, %g2
+	sethi		%hi(_PAGE_SZBITS), %g7
+	ldx		[%g7 + %lo(_PAGE_SZBITS)], %g7
+	cmp		%g2, %g7
+	mov		1, %g7
+	sllx		%g7, TSB_TAG_INVALID_BIT, %g7
+	bne,a,pn	%xcc, tsb_tlb_reload
+	 TSB_STORE(%g1, %g7)
+
+	TSB_WRITE(%g1, %g5, %g6)
+
+	/* Finally, load TLB and return from trap.  */
+tsb_tlb_reload:
+	cmp		%g3, FAULT_CODE_DTLB
+	bne,pn		%xcc, tsb_itlb_load
+	 nop
+
+tsb_dtlb_load:
+
+661:	stxa		%g5, [%g0] ASI_DTLB_DATA_IN
+	retry
+	.section	.sun4v_2insn_patch, "ax"
+	.word		661b
+	nop
+	nop
+	.previous
+
+	/* For sun4v the ASI_DTLB_DATA_IN store and the retry
+	 * instruction get nop'd out and we get here to branch
+	 * to the sun4v tlb load code.  The registers are setup
+	 * as follows:
+	 *
+	 * %g4: vaddr
+	 * %g5: PTE
+	 * %g6:	TAG
+	 *
+	 * The sun4v TLB load wants the PTE in %g3 so we fix that
+	 * up here.
+	 */
+	ba,pt		%xcc, sun4v_dtlb_load
+	 mov		%g5, %g3
+
+tsb_itlb_load:
+
+661:	stxa		%g5, [%g0] ASI_ITLB_DATA_IN
+	retry
+	.section	.sun4v_2insn_patch, "ax"
+	.word		661b
+	nop
+	nop
+	.previous
+
+	/* For sun4v the ASI_ITLB_DATA_IN store and the retry
+	 * instruction get nop'd out and we get here to branch
+	 * to the sun4v tlb load code.  The registers are setup
+	 * as follows:
+	 *
+	 * %g4: vaddr
+	 * %g5: PTE
+	 * %g6:	TAG
+	 *
+	 * The sun4v TLB load wants the PTE in %g3 so we fix that
+	 * up here.
+	 */
+	ba,pt		%xcc, sun4v_itlb_load
+	 mov		%g5, %g3
+
+	/* No valid entry in the page tables, do full fault
+	 * processing.
+	 */
+
+	.globl		tsb_do_fault
+tsb_do_fault:
+	cmp		%g3, FAULT_CODE_DTLB
+
+661:	rdpr		%pstate, %g5
+	wrpr		%g5, PSTATE_AG | PSTATE_MG, %pstate
+	.section	.sun4v_2insn_patch, "ax"
+	.word		661b
+	SET_GL(1)
+	ldxa		[%g0] ASI_SCRATCHPAD, %g4
+	.previous
+
+	bne,pn		%xcc, tsb_do_itlb_fault
+	 nop
+
+tsb_do_dtlb_fault:
+	rdpr	%tl, %g3
+	cmp	%g3, 1
+
+661:	mov	TLB_TAG_ACCESS, %g4
+	ldxa	[%g4] ASI_DMMU, %g5
+	.section .sun4v_2insn_patch, "ax"
+	.word	661b
+	ldx	[%g4 + HV_FAULT_D_ADDR_OFFSET], %g5
+	nop
+	.previous
+
+	be,pt	%xcc, sparc64_realfault_common
+	 mov	FAULT_CODE_DTLB, %g4
+	ba,pt	%xcc, winfix_trampoline
+	 nop
+
+tsb_do_itlb_fault:
+	rdpr	%tpc, %g5
+	ba,pt	%xcc, sparc64_realfault_common
+	 mov	FAULT_CODE_ITLB, %g4
+
+	.globl	sparc64_realfault_common
+sparc64_realfault_common:
+	/* fault code in %g4, fault address in %g5, etrap will
+	 * preserve these two values in %l4 and %l5 respectively
+	 */
+	ba,pt	%xcc, etrap			! Save trap state
+1:	 rd	%pc, %g7			! ...
+	stb	%l4, [%g6 + TI_FAULT_CODE]	! Save fault code
+	stx	%l5, [%g6 + TI_FAULT_ADDR]	! Save fault address
+	call	do_sparc64_fault		! Call fault handler
+	 add	%sp, PTREGS_OFF, %o0		! Compute pt_regs arg
+	ba,pt	%xcc, rtrap_clr_l6		! Restore cpu state
+	 nop					! Delay slot (fill me)
+
+winfix_trampoline:
+	rdpr	%tpc, %g3			! Prepare winfixup TNPC
+	or	%g3, 0x7c, %g3			! Compute branch offset
+	wrpr	%g3, %tnpc			! Write it into TNPC
+	done					! Trap return
+
+	/* Insert an entry into the TSB.
+	 *
+	 * %o0: TSB entry pointer (virt or phys address)
+	 * %o1: tag
+	 * %o2:	pte
+	 */
+	.align	32
+	.globl	__tsb_insert
+__tsb_insert:
+	rdpr	%pstate, %o5
+	wrpr	%o5, PSTATE_IE, %pstate
+	TSB_LOCK_TAG(%o0, %g2, %g3)
+	TSB_WRITE(%o0, %o2, %o1)
+	wrpr	%o5, %pstate
+	retl
+	 nop
+
+	/* Flush the given TSB entry if it has the matching
+	 * tag.
+	 *
+	 * %o0: TSB entry pointer (virt or phys address)
+	 * %o1:	tag
+	 */
+	.align	32
+	.globl	tsb_flush
+tsb_flush:
+	sethi	%hi(TSB_TAG_LOCK_HIGH), %g2
+1:	TSB_LOAD_TAG(%o0, %g1)
+	srlx	%g1, 32, %o3
+	andcc	%o3, %g2, %g0
+	bne,pn	%icc, 1b
+	 membar	#LoadLoad
+	cmp	%g1, %o1
+	mov	1, %o3
+	bne,pt	%xcc, 2f
+	 sllx	%o3, TSB_TAG_INVALID_BIT, %o3
+	TSB_CAS_TAG(%o0, %g1, %o3)
+	cmp	%g1, %o3
+	bne,pn	%xcc, 1b
+	 nop
+2:	retl
+	 TSB_MEMBAR
+
+	/* Reload MMU related context switch state at
+	 * schedule() time.
+	 *
+	 * %o0: page table physical address
+	 * %o1:	TSB register value
+	 * %o2:	TSB virtual address
+	 * %o3:	TSB mapping locked PTE
+	 * %o4:	Hypervisor TSB descriptor physical address
+	 *
+	 * We have to run this whole thing with interrupts
+	 * disabled so that the current cpu doesn't change
+	 * due to preemption.
+	 */
+	.align	32
+	.globl	__tsb_context_switch
+__tsb_context_switch:
+	rdpr	%pstate, %o5
+	wrpr	%o5, PSTATE_IE, %pstate
+
+	ldub	[%g6 + TI_CPU], %g1
+	sethi	%hi(trap_block), %g2
+	sllx	%g1, TRAP_BLOCK_SZ_SHIFT, %g1
+	or	%g2, %lo(trap_block), %g2
+	add	%g2, %g1, %g2
+	stx	%o0, [%g2 + TRAP_PER_CPU_PGD_PADDR]
+
+	sethi	%hi(tlb_type), %g1
+	lduw	[%g1 + %lo(tlb_type)], %g1
+	cmp	%g1, 3
+	bne,pt	%icc, 1f
+	 nop
+
+	/* Hypervisor TSB switch. */
+	mov	SCRATCHPAD_UTSBREG1, %g1
+	stxa	%o1, [%g1] ASI_SCRATCHPAD
+	mov	-1, %g2
+	mov	SCRATCHPAD_UTSBREG2, %g1
+	stxa	%g2, [%g1] ASI_SCRATCHPAD
+
+	/* Save away %o5's %pstate, we have to use %o5 for
+	 * the hypervisor call.
+	 */
+	mov	%o5, %g1
+
+	mov	HV_FAST_MMU_TSB_CTXNON0, %o5
+	mov	1, %o0
+	mov	%o4, %o1
+	ta	HV_FAST_TRAP
+
+	/* Finish up and restore %o5.  */
+	ba,pt	%xcc, 9f
+	 mov	%g1, %o5
+
+	/* SUN4U TSB switch.  */
+1:	mov	TSB_REG, %g1
+	stxa	%o1, [%g1] ASI_DMMU
+	membar	#Sync
+	stxa	%o1, [%g1] ASI_IMMU
+	membar	#Sync
+
+2:	brz	%o2, 9f
+	 nop
+
+	sethi	%hi(sparc64_highest_unlocked_tlb_ent), %g2
+	mov	TLB_TAG_ACCESS, %g1
+	lduw	[%g2 + %lo(sparc64_highest_unlocked_tlb_ent)], %g2
+	stxa	%o2, [%g1] ASI_DMMU
+	membar	#Sync
+	sllx	%g2, 3, %g2
+	stxa	%o3, [%g2] ASI_DTLB_DATA_ACCESS
+	membar	#Sync
+9:
+	wrpr	%o5, %pstate
+
+	retl
+	 nop
diff -urN oldtree/arch/sparc64/kernel/ttable.S newtree/arch/sparc64/kernel/ttable.S
--- oldtree/arch/sparc64/kernel/ttable.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/kernel/ttable.S	2006-02-21 15:58:20.289062152 +0000
@@ -1,7 +1,6 @@
-/* $Id: ttable.S,v 1.38 2002/02/09 19:49:30 davem Exp $
- * ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah extensions.
+/* ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah/SUN4V extensions.
  *
- * Copyright (C) 1996, 2001 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996, 2001, 2006 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/config.h>
@@ -19,7 +18,7 @@
 tl0_resv004:	BTRAP(0x4)  BTRAP(0x5) BTRAP(0x6) BTRAP(0x7)
 tl0_iax:	membar #Sync
 		TRAP_NOSAVE_7INSNS(__spitfire_insn_access_exception)
-tl0_resv009:	BTRAP(0x9)
+tl0_itsb_4v:	SUN4V_ITSB_MISS
 tl0_iae:	membar #Sync
 		TRAP_NOSAVE_7INSNS(__spitfire_access_error)
 tl0_resv00b:	BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf)
@@ -38,7 +37,7 @@
 tl0_resv029:	BTRAP(0x29) BTRAP(0x2a) BTRAP(0x2b) BTRAP(0x2c) BTRAP(0x2d) BTRAP(0x2e)
 tl0_resv02f:	BTRAP(0x2f)
 tl0_dax:	TRAP_NOSAVE(__spitfire_data_access_exception)
-tl0_resv031:	BTRAP(0x31)
+tl0_dtsb_4v:	SUN4V_DTSB_MISS
 tl0_dae:	membar #Sync
 		TRAP_NOSAVE_7INSNS(__spitfire_access_error)
 tl0_resv033:	BTRAP(0x33)
@@ -78,9 +77,9 @@
 tl0_cee:	membar #Sync
 		TRAP_NOSAVE_7INSNS(__spitfire_cee_trap)
 tl0_iamiss:
-#include	"itlb_base.S"
+#include	"itlb_miss.S"
 tl0_damiss:
-#include	"dtlb_base.S"
+#include	"dtlb_miss.S"
 tl0_daprot:
 #include	"dtlb_prot.S"
 tl0_fecc:	BTRAP(0x70)	/* Fast-ECC on Cheetah */
@@ -88,15 +87,18 @@
 tl0_icpe:	BTRAP(0x72)	/* I-cache Parity Error on Cheetah+ */
 tl0_resv073:	BTRAP(0x73) BTRAP(0x74) BTRAP(0x75)
 tl0_resv076:	BTRAP(0x76) BTRAP(0x77) BTRAP(0x78) BTRAP(0x79) BTRAP(0x7a) BTRAP(0x7b)
-tl0_resv07c:	BTRAP(0x7c) BTRAP(0x7d) BTRAP(0x7e) BTRAP(0x7f)
+tl0_cpu_mondo:	TRAP_NOSAVE(sun4v_cpu_mondo)
+tl0_dev_mondo:	TRAP_NOSAVE(sun4v_dev_mondo)
+tl0_res_mondo:	TRAP_NOSAVE(sun4v_res_mondo)
+tl0_nres_mondo:	TRAP_NOSAVE(sun4v_nonres_mondo)
 tl0_s0n:	SPILL_0_NORMAL
 tl0_s1n:	SPILL_1_NORMAL
 tl0_s2n:	SPILL_2_NORMAL
-tl0_s3n:	SPILL_3_NORMAL
-tl0_s4n:	SPILL_4_NORMAL
-tl0_s5n:	SPILL_5_NORMAL
-tl0_s6n:	SPILL_6_NORMAL
-tl0_s7n:	SPILL_7_NORMAL
+tl0_s3n:	SPILL_0_NORMAL_ETRAP
+tl0_s4n:	SPILL_1_GENERIC_ETRAP
+tl0_s5n:	SPILL_1_GENERIC_ETRAP_FIXUP
+tl0_s6n:	SPILL_2_GENERIC_ETRAP
+tl0_s7n:	SPILL_2_GENERIC_ETRAP_FIXUP
 tl0_s0o:	SPILL_0_OTHER
 tl0_s1o:	SPILL_1_OTHER
 tl0_s2o:	SPILL_2_OTHER
@@ -110,9 +112,9 @@
 tl0_f2n:	FILL_2_NORMAL
 tl0_f3n:	FILL_3_NORMAL
 tl0_f4n:	FILL_4_NORMAL
-tl0_f5n:	FILL_5_NORMAL
-tl0_f6n:	FILL_6_NORMAL
-tl0_f7n:	FILL_7_NORMAL
+tl0_f5n:	FILL_0_NORMAL_RTRAP
+tl0_f6n:	FILL_1_GENERIC_RTRAP
+tl0_f7n:	FILL_2_GENERIC_RTRAP
 tl0_f0o:	FILL_0_OTHER
 tl0_f1o:	FILL_1_OTHER
 tl0_f2o:	FILL_2_OTHER
@@ -128,7 +130,7 @@
 tl0_resv104:	BTRAP(0x104) BTRAP(0x105) BTRAP(0x106) BTRAP(0x107)
 		.globl tl0_solaris
 tl0_solaris:	SOLARIS_SYSCALL_TRAP
-tl0_netbsd:	NETBSD_SYSCALL_TRAP
+tl0_resv109:	BTRAP(0x109)
 tl0_resv10a:	BTRAP(0x10a) BTRAP(0x10b) BTRAP(0x10c) BTRAP(0x10d) BTRAP(0x10e)
 tl0_resv10f:	BTRAP(0x10f)
 tl0_linux32:	LINUX_32BIT_SYSCALL_TRAP
@@ -179,7 +181,7 @@
 tl1_resv000:	BOOT_KERNEL    BTRAPTL1(0x1) BTRAPTL1(0x2) BTRAPTL1(0x3)
 tl1_resv004:	BTRAPTL1(0x4)  BTRAPTL1(0x5) BTRAPTL1(0x6) BTRAPTL1(0x7)
 tl1_iax:	TRAP_NOSAVE(__spitfire_insn_access_exception_tl1)
-tl1_resv009:	BTRAPTL1(0x9)
+tl1_itsb_4v:	SUN4V_ITSB_MISS
 tl1_iae:	membar #Sync
 		TRAP_NOSAVE_7INSNS(__spitfire_access_error)
 tl1_resv00b:	BTRAPTL1(0xb) BTRAPTL1(0xc) BTRAPTL1(0xd) BTRAPTL1(0xe) BTRAPTL1(0xf)
@@ -198,7 +200,7 @@
 tl1_resv029:	BTRAPTL1(0x29) BTRAPTL1(0x2a) BTRAPTL1(0x2b) BTRAPTL1(0x2c)
 tl1_resv02d:	BTRAPTL1(0x2d) BTRAPTL1(0x2e) BTRAPTL1(0x2f)
 tl1_dax:	TRAP_NOSAVE(__spitfire_data_access_exception_tl1)
-tl1_resv031:	BTRAPTL1(0x31)
+tl1_dtsb_4v:	SUN4V_DTSB_MISS
 tl1_dae:	membar #Sync
 		TRAP_NOSAVE_7INSNS(__spitfire_access_error)
 tl1_resv033:	BTRAPTL1(0x33)
@@ -222,26 +224,10 @@
 tl1_ivec:	TRAP_IVEC
 tl1_paw:	TRAPTL1(do_paw_tl1)
 tl1_vaw:	TRAPTL1(do_vaw_tl1)
-
-		/* The grotty trick to save %g1 into current->thread.cee_stuff
-		 * is because when we take this trap we could be interrupting
-		 * trap code already using the trap alternate global registers.
-		 *
-		 * We cross our fingers and pray that this store/load does
-		 * not cause yet another CEE trap.
-		 */
-tl1_cee:	membar	#Sync
-		stx	%g1, [%g6 + TI_CEE_STUFF]
-		ldxa	[%g0] ASI_AFSR, %g1
-		membar	#Sync
-		stxa	%g1, [%g0] ASI_AFSR
-		membar	#Sync
-		ldx	[%g6 + TI_CEE_STUFF], %g1
-		retry
-
+tl1_cee:	BTRAPTL1(0x63)
 tl1_iamiss:	BTRAPTL1(0x64) BTRAPTL1(0x65) BTRAPTL1(0x66) BTRAPTL1(0x67)
 tl1_damiss:
-#include	"dtlb_backend.S"
+#include	"dtlb_miss.S"
 tl1_daprot:
 #include	"dtlb_prot.S"
 tl1_fecc:	BTRAPTL1(0x70)	/* Fast-ECC on Cheetah */
diff -urN oldtree/arch/sparc64/kernel/unaligned.c newtree/arch/sparc64/kernel/unaligned.c
--- oldtree/arch/sparc64/kernel/unaligned.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/kernel/unaligned.c	2006-02-21 15:58:20.292061696 +0000
@@ -277,7 +277,7 @@
 	regs->tstate |= (ASI_AIUS << 24UL);
 }
 
-asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, unsigned long sfar, unsigned long sfsr)
+asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
 {
 	enum direction dir = decode_direction(insn);
 	int size = decode_access_size(insn);
@@ -405,6 +405,9 @@
 extern void spitfire_data_access_exception(struct pt_regs *regs,
 					   unsigned long sfsr,
 					   unsigned long sfar);
+extern void sun4v_data_access_exception(struct pt_regs *regs,
+					unsigned long addr,
+					unsigned long type_ctx);
 
 int handle_ldf_stq(u32 insn, struct pt_regs *regs)
 {
@@ -447,14 +450,20 @@
 				break;
 			}
 		default:
-			spitfire_data_access_exception(regs, 0, addr);
+			if (tlb_type == hypervisor)
+				sun4v_data_access_exception(regs, addr, 0);
+			else
+				spitfire_data_access_exception(regs, 0, addr);
 			return 1;
 		}
 		if (put_user (first >> 32, (u32 __user *)addr) ||
 		    __put_user ((u32)first, (u32 __user *)(addr + 4)) ||
 		    __put_user (second >> 32, (u32 __user *)(addr + 8)) ||
 		    __put_user ((u32)second, (u32 __user *)(addr + 12))) {
-		    	spitfire_data_access_exception(regs, 0, addr);
+			if (tlb_type == hypervisor)
+				sun4v_data_access_exception(regs, addr, 0);
+			else
+				spitfire_data_access_exception(regs, 0, addr);
 		    	return 1;
 		}
 	} else {
@@ -467,7 +476,10 @@
 			do_privact(regs);
 			return 1;
 		} else if (asi > ASI_SNFL) {
-			spitfire_data_access_exception(regs, 0, addr);
+			if (tlb_type == hypervisor)
+				sun4v_data_access_exception(regs, addr, 0);
+			else
+				spitfire_data_access_exception(regs, 0, addr);
 			return 1;
 		}
 		switch (insn & 0x180000) {
@@ -484,7 +496,10 @@
 				err |= __get_user (data[i], (u32 __user *)(addr + 4*i));
 		}
 		if (err && !(asi & 0x2 /* NF */)) {
-			spitfire_data_access_exception(regs, 0, addr);
+			if (tlb_type == hypervisor)
+				sun4v_data_access_exception(regs, addr, 0);
+			else
+				spitfire_data_access_exception(regs, 0, addr);
 			return 1;
 		}
 		if (asi & 0x8) /* Little */ {
@@ -548,7 +563,7 @@
 	u32 insn;
 	u32 first, second;
 	u64 value;
-	u8 asi, freg;
+	u8 freg;
 	int flag;
 	struct fpustate *f = FPUSTATE;
 
@@ -557,7 +572,7 @@
 	if (test_thread_flag(TIF_32BIT))
 		pc = (u32)pc;
 	if (get_user(insn, (u32 __user *) pc) != -EFAULT) {
-		asi = sfsr >> 16;
+		int asi = decode_asi(insn, regs);
 		if ((asi > ASI_SNFL) ||
 		    (asi < ASI_P))
 			goto daex;
@@ -587,7 +602,11 @@
 		*(u64 *)(f->regs + freg) = value;
 		current_thread_info()->fpsaved[0] |= flag;
 	} else {
-daex:		spitfire_data_access_exception(regs, sfsr, sfar);
+daex:
+		if (tlb_type == hypervisor)
+			sun4v_data_access_exception(regs, sfar, sfsr);
+		else
+			spitfire_data_access_exception(regs, sfsr, sfar);
 		return;
 	}
 	advance(regs);
@@ -600,7 +619,7 @@
 	unsigned long tstate = regs->tstate;
 	u32 insn;
 	u64 value;
-	u8 asi, freg;
+	u8 freg;
 	int flag;
 	struct fpustate *f = FPUSTATE;
 
@@ -609,8 +628,8 @@
 	if (test_thread_flag(TIF_32BIT))
 		pc = (u32)pc;
 	if (get_user(insn, (u32 __user *) pc) != -EFAULT) {
+		int asi = decode_asi(insn, regs);
 		freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20);
-		asi = sfsr >> 16;
 		value = 0;
 		flag = (freg < 32) ? FPRS_DL : FPRS_DU;
 		if ((asi > ASI_SNFL) ||
@@ -631,7 +650,11 @@
 		    __put_user ((u32)value, (u32 __user *)(sfar + 4)))
 			goto daex;
 	} else {
-daex:		spitfire_data_access_exception(regs, sfsr, sfar);
+daex:
+		if (tlb_type == hypervisor)
+			sun4v_data_access_exception(regs, sfar, sfsr);
+		else
+			spitfire_data_access_exception(regs, sfsr, sfar);
 		return;
 	}
 	advance(regs);
diff -urN oldtree/arch/sparc64/kernel/us2e_cpufreq.c newtree/arch/sparc64/kernel/us2e_cpufreq.c
--- oldtree/arch/sparc64/kernel/us2e_cpufreq.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/kernel/us2e_cpufreq.c	2006-02-21 15:58:20.292061696 +0000
@@ -346,6 +346,9 @@
 	unsigned long manuf, impl, ver;
 	int ret;
 
+	if (tlb_type != spitfire)
+		return -ENODEV;
+
 	__asm__("rdpr %%ver, %0" : "=r" (ver));
 	manuf = ((ver >> 48) & 0xffff);
 	impl  = ((ver >> 32) & 0xffff);
diff -urN oldtree/arch/sparc64/kernel/us3_cpufreq.c newtree/arch/sparc64/kernel/us3_cpufreq.c
--- oldtree/arch/sparc64/kernel/us3_cpufreq.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/kernel/us3_cpufreq.c	2006-02-21 15:58:20.292061696 +0000
@@ -203,6 +203,9 @@
 	unsigned long manuf, impl, ver;
 	int ret;
 
+	if (tlb_type != cheetah && tlb_type != cheetah_plus)
+		return -ENODEV;
+
 	__asm__("rdpr %%ver, %0" : "=r" (ver));
 	manuf = ((ver >> 48) & 0xffff);
 	impl  = ((ver >> 32) & 0xffff);
diff -urN oldtree/arch/sparc64/kernel/vmlinux.lds.S newtree/arch/sparc64/kernel/vmlinux.lds.S
--- oldtree/arch/sparc64/kernel/vmlinux.lds.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/kernel/vmlinux.lds.S	2006-02-21 15:58:20.293061544 +0000
@@ -70,6 +70,22 @@
   .con_initcall.init : { *(.con_initcall.init) }
   __con_initcall_end = .;
   SECURITY_INIT
+  . = ALIGN(4);
+  __tsb_ldquad_phys_patch = .;
+  .tsb_ldquad_phys_patch : { *(.tsb_ldquad_phys_patch) }
+  __tsb_ldquad_phys_patch_end = .;
+  __tsb_phys_patch = .;
+  .tsb_phys_patch : { *(.tsb_phys_patch) }
+  __tsb_phys_patch_end = .;
+  __cpuid_patch = .;
+  .cpuid_patch : { *(.cpuid_patch) }
+  __cpuid_patch_end = .;
+  __sun4v_1insn_patch = .;
+  .sun4v_1insn_patch : { *(.sun4v_1insn_patch) }
+  __sun4v_1insn_patch_end = .;
+  __sun4v_2insn_patch = .;
+  .sun4v_2insn_patch : { *(.sun4v_2insn_patch) }
+  __sun4v_2insn_patch_end = .;
   . = ALIGN(8192); 
   __initramfs_start = .;
   .init.ramfs : { *(.init.ramfs) }
diff -urN oldtree/arch/sparc64/kernel/winfixup.S newtree/arch/sparc64/kernel/winfixup.S
--- oldtree/arch/sparc64/kernel/winfixup.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/kernel/winfixup.S	2006-02-21 15:58:20.295061240 +0000
@@ -1,8 +1,6 @@
-/* $Id: winfixup.S,v 1.30 2002/02/09 19:49:30 davem Exp $
+/* winfixup.S: Handle cases where user stack pointer is found to be bogus.
  *
- * winfixup.S: Handle cases where user stack pointer is found to be bogus.
- *
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997, 2006 David S. Miller (davem@davemloft.net)
  */
 
 #include <asm/asi.h>
@@ -15,374 +13,144 @@
 
 	.text
 
-set_pcontext:
-	sethi	%hi(sparc64_kern_pri_context), %l1
-	ldx	[%l1 + %lo(sparc64_kern_pri_context)], %l1
-	mov	PRIMARY_CONTEXT, %g1
-	stxa	%l1, [%g1] ASI_DMMU
-	flush	%g6
-	retl
-	 nop
+	/* It used to be the case that these register window fault
+	 * handlers could run via the save and restore instructions
+	 * done by the trap entry and exit code.  They now do the
+	 * window spill/fill by hand, so that case no longer can occur.
+	 */
 
 	.align	32
-
-	/* Here are the rules, pay attention.
-	 *
-	 * The kernel is disallowed from touching user space while
-	 * the trap level is greater than zero, except for from within
-	 * the window spill/fill handlers.  This must be followed
-	 * so that we can easily detect the case where we tried to
-	 * spill/fill with a bogus (or unmapped) user stack pointer.
-	 *
-	 * These are layed out in a special way for cache reasons,
-	 * don't touch...
-	 */
-	.globl	fill_fixup, spill_fixup
 fill_fixup:
-	rdpr		%tstate, %g1
-	andcc		%g1, TSTATE_PRIV, %g0
-	or		%g4, FAULT_CODE_WINFIXUP, %g4
-	be,pt		%xcc, window_scheisse_from_user_common
-	 and		%g1, TSTATE_CWP, %g1
-
-	/* This is the extremely complex case, but it does happen from
-	 * time to time if things are just right.  Essentially the restore
-	 * done in rtrap right before going back to user mode, with tl=1
-	 * and that levels trap stack registers all setup, took a fill trap,
-	 * the user stack was not mapped in the tlb, and tlb miss occurred,
-	 * the pte found was not valid, and a simple ref bit watch update
-	 * could not satisfy the miss, so we got here.
-	 *
-	 * We must carefully unwind the state so we get back to tl=0, preserve
-	 * all the register values we were going to give to the user.  Luckily
-	 * most things are where they need to be, we also have the address
-	 * which triggered the fault handy as well.
-	 *
-	 * Also note that we must preserve %l5 and %l6.  If the user was
-	 * returning from a system call, we must make it look this way
-	 * after we process the fill fault on the users stack.
-	 *
-	 * First, get into the window where the original restore was executed.
-	 */
-
-	rdpr		%wstate, %g2			! Grab user mode wstate.
-	wrpr		%g1, %cwp			! Get into the right window.
-	sll		%g2, 3, %g2			! NORMAL-->OTHER
-
-	wrpr		%g0, 0x0, %canrestore		! Standard etrap stuff.
-	wrpr		%g2, 0x0, %wstate		! This must be consistent.
-	wrpr		%g0, 0x0, %otherwin		! We know this.
-	call		set_pcontext			! Change contexts...
+	TRAP_LOAD_THREAD_REG(%g6, %g1)
+	rdpr	%tstate, %g1
+	and	%g1, TSTATE_CWP, %g1
+	or	%g4, FAULT_CODE_WINFIXUP, %g4
+	stb	%g4, [%g6 + TI_FAULT_CODE]
+	stx	%g5, [%g6 + TI_FAULT_ADDR]
+	wrpr	%g1, %cwp
+	ba,pt	%xcc, etrap
+	 rd	%pc, %g7
+	call	do_sparc64_fault
+	 add	%sp, PTREGS_OFF, %o0
+	ba,pt	%xcc, rtrap_clr_l6
 	 nop
-	rdpr		%pstate, %l1			! Prepare to change globals.
-	mov		%g6, %o7			! Get current.
-
-	andn		%l1, PSTATE_MM, %l1		! We want to be in RMO
-	stb		%g4, [%g6 + TI_FAULT_CODE]
-	stx		%g5, [%g6 + TI_FAULT_ADDR]
-	wrpr		%g0, 0x0, %tl			! Out of trap levels.
-	wrpr		%l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate
-	mov		%o7, %g6
-	ldx		[%g6 + TI_TASK], %g4
-#ifdef CONFIG_SMP
-	mov		TSB_REG, %g1
-	ldxa		[%g1] ASI_IMMU, %g5
-#endif
 
-	/* This is the same as below, except we handle this a bit special
-	 * since we must preserve %l5 and %l6, see comment above.
-	 */
-	call		do_sparc64_fault
-	 add		%sp, PTREGS_OFF, %o0
-	ba,pt		%xcc, rtrap
-	 nop						! yes, nop is correct
-
-	/* Be very careful about usage of the alternate globals here.
-	 * You cannot touch %g4/%g5 as that has the fault information
-	 * should this be from usermode.  Also be careful for the case
-	 * where we get here from the save instruction in etrap.S when
-	 * coming from either user or kernel (does not matter which, it
-	 * is the same problem in both cases).  Essentially this means
-	 * do not touch %g7 or %g2 so we handle the two cases fine.
+	/* Be very careful about usage of the trap globals here.
+	 * You cannot touch %g5 as that has the fault information.
 	 */
 spill_fixup:
-	ldx		[%g6 + TI_FLAGS], %g1
-	andcc		%g1, _TIF_32BIT, %g0
-	ldub		[%g6 + TI_WSAVED], %g1
-
-	sll		%g1, 3, %g3
-	add		%g6, %g3, %g3
-	stx		%sp, [%g3 + TI_RWIN_SPTRS]
-	sll		%g1, 7, %g3
-	bne,pt		%xcc, 1f
-	 add		%g6, %g3, %g3
-	stx		%l0, [%g3 + TI_REG_WINDOW + 0x00]
-	stx		%l1, [%g3 + TI_REG_WINDOW + 0x08]
-
-	stx		%l2, [%g3 + TI_REG_WINDOW + 0x10]
-	stx		%l3, [%g3 + TI_REG_WINDOW + 0x18]
-	stx		%l4, [%g3 + TI_REG_WINDOW + 0x20]
-	stx		%l5, [%g3 + TI_REG_WINDOW + 0x28]
-	stx		%l6, [%g3 + TI_REG_WINDOW + 0x30]
-	stx		%l7, [%g3 + TI_REG_WINDOW + 0x38]
-	stx		%i0, [%g3 + TI_REG_WINDOW + 0x40]
-	stx		%i1, [%g3 + TI_REG_WINDOW + 0x48]
-
-	stx		%i2, [%g3 + TI_REG_WINDOW + 0x50]
-	stx		%i3, [%g3 + TI_REG_WINDOW + 0x58]
-	stx		%i4, [%g3 + TI_REG_WINDOW + 0x60]
-	stx		%i5, [%g3 + TI_REG_WINDOW + 0x68]
-	stx		%i6, [%g3 + TI_REG_WINDOW + 0x70]
-	b,pt		%xcc, 2f
-	 stx		%i7, [%g3 + TI_REG_WINDOW + 0x78]
-1:	stw		%l0, [%g3 + TI_REG_WINDOW + 0x00]
-
-	stw		%l1, [%g3 + TI_REG_WINDOW + 0x04]
-	stw		%l2, [%g3 + TI_REG_WINDOW + 0x08]
-	stw		%l3, [%g3 + TI_REG_WINDOW + 0x0c]
-	stw		%l4, [%g3 + TI_REG_WINDOW + 0x10]
-	stw		%l5, [%g3 + TI_REG_WINDOW + 0x14]
-	stw		%l6, [%g3 + TI_REG_WINDOW + 0x18]
-	stw		%l7, [%g3 + TI_REG_WINDOW + 0x1c]
-	stw		%i0, [%g3 + TI_REG_WINDOW + 0x20]
-
-	stw		%i1, [%g3 + TI_REG_WINDOW + 0x24]
-	stw		%i2, [%g3 + TI_REG_WINDOW + 0x28]
-	stw		%i3, [%g3 + TI_REG_WINDOW + 0x2c]
-	stw		%i4, [%g3 + TI_REG_WINDOW + 0x30]
-	stw		%i5, [%g3 + TI_REG_WINDOW + 0x34]
-	stw		%i6, [%g3 + TI_REG_WINDOW + 0x38]
-	stw		%i7, [%g3 + TI_REG_WINDOW + 0x3c]
-2:	add		%g1, 1, %g1
-
-	stb		%g1, [%g6 + TI_WSAVED]
-	rdpr		%tstate, %g1
-	andcc		%g1, TSTATE_PRIV, %g0
+spill_fixup_mna:
+spill_fixup_dax:
+	TRAP_LOAD_THREAD_REG(%g6, %g1)
+	ldx	[%g6 + TI_FLAGS], %g1
+	andcc	%g1, _TIF_32BIT, %g0
+	ldub	[%g6 + TI_WSAVED], %g1
+	sll	%g1, 3, %g3
+	add	%g6, %g3, %g3
+	stx	%sp, [%g3 + TI_RWIN_SPTRS]
+	sll	%g1, 7, %g3
+	bne,pt	%xcc, 1f
+	 add	%g6, %g3, %g3
+	stx	%l0, [%g3 + TI_REG_WINDOW + 0x00]
+	stx	%l1, [%g3 + TI_REG_WINDOW + 0x08]
+	stx	%l2, [%g3 + TI_REG_WINDOW + 0x10]
+	stx	%l3, [%g3 + TI_REG_WINDOW + 0x18]
+	stx	%l4, [%g3 + TI_REG_WINDOW + 0x20]
+	stx	%l5, [%g3 + TI_REG_WINDOW + 0x28]
+	stx	%l6, [%g3 + TI_REG_WINDOW + 0x30]
+	stx	%l7, [%g3 + TI_REG_WINDOW + 0x38]
+	stx	%i0, [%g3 + TI_REG_WINDOW + 0x40]
+	stx	%i1, [%g3 + TI_REG_WINDOW + 0x48]
+	stx	%i2, [%g3 + TI_REG_WINDOW + 0x50]
+	stx	%i3, [%g3 + TI_REG_WINDOW + 0x58]
+	stx	%i4, [%g3 + TI_REG_WINDOW + 0x60]
+	stx	%i5, [%g3 + TI_REG_WINDOW + 0x68]
+	stx	%i6, [%g3 + TI_REG_WINDOW + 0x70]
+	ba,pt	%xcc, 2f
+	 stx	%i7, [%g3 + TI_REG_WINDOW + 0x78]
+1:	stw	%l0, [%g3 + TI_REG_WINDOW + 0x00]
+	stw	%l1, [%g3 + TI_REG_WINDOW + 0x04]
+	stw	%l2, [%g3 + TI_REG_WINDOW + 0x08]
+	stw	%l3, [%g3 + TI_REG_WINDOW + 0x0c]
+	stw	%l4, [%g3 + TI_REG_WINDOW + 0x10]
+	stw	%l5, [%g3 + TI_REG_WINDOW + 0x14]
+	stw	%l6, [%g3 + TI_REG_WINDOW + 0x18]
+	stw	%l7, [%g3 + TI_REG_WINDOW + 0x1c]
+	stw	%i0, [%g3 + TI_REG_WINDOW + 0x20]
+	stw	%i1, [%g3 + TI_REG_WINDOW + 0x24]
+	stw	%i2, [%g3 + TI_REG_WINDOW + 0x28]
+	stw	%i3, [%g3 + TI_REG_WINDOW + 0x2c]
+	stw	%i4, [%g3 + TI_REG_WINDOW + 0x30]
+	stw	%i5, [%g3 + TI_REG_WINDOW + 0x34]
+	stw	%i6, [%g3 + TI_REG_WINDOW + 0x38]
+	stw	%i7, [%g3 + TI_REG_WINDOW + 0x3c]
+2:	add	%g1, 1, %g1
+	stb	%g1, [%g6 + TI_WSAVED]
+	rdpr	%tstate, %g1
+	andcc	%g1, TSTATE_PRIV, %g0
 	saved
-	and		%g1, TSTATE_CWP, %g1
-	be,pn		%xcc, window_scheisse_from_user_common
-	 mov		FAULT_CODE_WRITE | FAULT_CODE_DTLB | FAULT_CODE_WINFIXUP, %g4
+	be,pn	%xcc, 1f
+	 and	%g1, TSTATE_CWP, %g1
 	retry
+1:	mov	FAULT_CODE_WRITE | FAULT_CODE_DTLB | FAULT_CODE_WINFIXUP, %g4
+	stb	%g4, [%g6 + TI_FAULT_CODE]
+	stx	%g5, [%g6 + TI_FAULT_ADDR]
+	wrpr	%g1, %cwp
+	ba,pt	%xcc, etrap
+	 rd	%pc, %g7
+	call	do_sparc64_fault
+	 add	%sp, PTREGS_OFF, %o0
+	ba,a,pt	%xcc, rtrap_clr_l6
 
-window_scheisse_from_user_common:
-	stb		%g4, [%g6 + TI_FAULT_CODE]
-	stx		%g5, [%g6 + TI_FAULT_ADDR]
-	wrpr		%g1, %cwp
-	ba,pt		%xcc, etrap
-	 rd		%pc, %g7
-	call		do_sparc64_fault
-	 add		%sp, PTREGS_OFF, %o0
-	ba,a,pt		%xcc, rtrap_clr_l6
-
-	.globl		winfix_mna, fill_fixup_mna, spill_fixup_mna
 winfix_mna:
-	andn		%g3, 0x7f, %g3
-	add		%g3, 0x78, %g3
-	wrpr		%g3, %tnpc
+	andn	%g3, 0x7f, %g3
+	add	%g3, 0x78, %g3
+	wrpr	%g3, %tnpc
 	done
-fill_fixup_mna:
-	rdpr		%tstate, %g1
-	andcc		%g1, TSTATE_PRIV, %g0
-	be,pt		%xcc, window_mna_from_user_common
-	 and		%g1, TSTATE_CWP, %g1
 
-	/* Please, see fill_fixup commentary about why we must preserve
-	 * %l5 and %l6 to preserve absolute correct semantics.
-	 */
-	rdpr		%wstate, %g2			! Grab user mode wstate.
-	wrpr		%g1, %cwp			! Get into the right window.
-	sll		%g2, 3, %g2			! NORMAL-->OTHER
-	wrpr		%g0, 0x0, %canrestore		! Standard etrap stuff.
-
-	wrpr		%g2, 0x0, %wstate		! This must be consistent.
-	wrpr		%g0, 0x0, %otherwin		! We know this.
-	call		set_pcontext			! Change contexts...
+fill_fixup_mna:
+	rdpr	%tstate, %g1
+	and	%g1, TSTATE_CWP, %g1
+	wrpr	%g1, %cwp
+	ba,pt	%xcc, etrap
+	 rd	%pc, %g7
+	sethi	%hi(tlb_type), %g1
+	lduw	[%g1 + %lo(tlb_type)], %g1
+	cmp	%g1, 3
+	bne,pt	%icc, 1f
+	 add	%sp, PTREGS_OFF, %o0
+	mov	%l4, %o2
+	call	sun4v_do_mna
+	 mov	%l5, %o1
+	ba,a,pt	%xcc, rtrap_clr_l6
+1:	mov	%l4, %o1
+	mov	%l5, %o2
+	call	mem_address_unaligned
 	 nop
-	rdpr		%pstate, %l1			! Prepare to change globals.
-	mov		%g4, %o2			! Setup args for
-	mov		%g5, %o1			! final call to mem_address_unaligned.
-	andn		%l1, PSTATE_MM, %l1		! We want to be in RMO
+	ba,a,pt	%xcc, rtrap_clr_l6
 
-	mov		%g6, %o7			! Stash away current.
-	wrpr		%g0, 0x0, %tl			! Out of trap levels.
-	wrpr		%l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate
-	mov		%o7, %g6			! Get current back.
-	ldx		[%g6 + TI_TASK], %g4		! Finish it.
-#ifdef CONFIG_SMP
-	mov		TSB_REG, %g1
-	ldxa		[%g1] ASI_IMMU, %g5
-#endif
-	call		mem_address_unaligned
-	 add		%sp, PTREGS_OFF, %o0
-
-	b,pt		%xcc, rtrap
-	 nop						! yes, the nop is correct
-spill_fixup_mna:
-	ldx		[%g6 + TI_FLAGS], %g1
-	andcc		%g1, _TIF_32BIT, %g0
-	ldub		[%g6 + TI_WSAVED], %g1
-	sll		%g1, 3, %g3
-	add		%g6, %g3, %g3
-	stx		%sp, [%g3 + TI_RWIN_SPTRS]
-
-	sll		%g1, 7, %g3
-	bne,pt		%xcc, 1f
-	 add		%g6, %g3, %g3
-	stx		%l0, [%g3 + TI_REG_WINDOW + 0x00]
-	stx		%l1, [%g3 + TI_REG_WINDOW + 0x08]
-	stx		%l2, [%g3 + TI_REG_WINDOW + 0x10]
-	stx		%l3, [%g3 + TI_REG_WINDOW + 0x18]
-	stx		%l4, [%g3 + TI_REG_WINDOW + 0x20]
-
-	stx		%l5, [%g3 + TI_REG_WINDOW + 0x28]
-	stx		%l6, [%g3 + TI_REG_WINDOW + 0x30]
-	stx		%l7, [%g3 + TI_REG_WINDOW + 0x38]
-	stx		%i0, [%g3 + TI_REG_WINDOW + 0x40]
-	stx		%i1, [%g3 + TI_REG_WINDOW + 0x48]
-	stx		%i2, [%g3 + TI_REG_WINDOW + 0x50]
-	stx		%i3, [%g3 + TI_REG_WINDOW + 0x58]
-	stx		%i4, [%g3 + TI_REG_WINDOW + 0x60]
-
-	stx		%i5, [%g3 + TI_REG_WINDOW + 0x68]
-	stx		%i6, [%g3 + TI_REG_WINDOW + 0x70]
-	stx		%i7, [%g3 + TI_REG_WINDOW + 0x78]
-	b,pt		%xcc, 2f
-	 add		%g1, 1, %g1
-1:	std		%l0, [%g3 + TI_REG_WINDOW + 0x00]
-	std		%l2, [%g3 + TI_REG_WINDOW + 0x08]
-	std		%l4, [%g3 + TI_REG_WINDOW + 0x10]
-
-	std		%l6, [%g3 + TI_REG_WINDOW + 0x18]
-	std		%i0, [%g3 + TI_REG_WINDOW + 0x20]
-	std		%i2, [%g3 + TI_REG_WINDOW + 0x28]
-	std		%i4, [%g3 + TI_REG_WINDOW + 0x30]
-	std		%i6, [%g3 + TI_REG_WINDOW + 0x38]
-	add		%g1, 1, %g1
-2:	stb		%g1, [%g6 + TI_WSAVED]
-	rdpr		%tstate, %g1
-
-	andcc		%g1, TSTATE_PRIV, %g0
-	saved
-	be,pn		%xcc, window_mna_from_user_common
-	 and		%g1, TSTATE_CWP, %g1
-	retry
-window_mna_from_user_common:
-	wrpr		%g1, %cwp
-	sethi		%hi(109f), %g7
-	ba,pt		%xcc, etrap
-109:	 or		%g7, %lo(109b), %g7
-	mov		%l4, %o2
-	mov		%l5, %o1
-	call		mem_address_unaligned
-	 add		%sp, PTREGS_OFF, %o0
-	ba,pt		%xcc, rtrap
-	 clr		%l6
-	
-	/* These are only needed for 64-bit mode processes which
-	 * put their stack pointer into the VPTE area and there
-	 * happens to be a VPTE tlb entry mapped there during
-	 * a spill/fill trap to that stack frame.
-	 */
-	.globl		winfix_dax, fill_fixup_dax, spill_fixup_dax
 winfix_dax:
-	andn		%g3, 0x7f, %g3
-	add		%g3, 0x74, %g3
-	wrpr		%g3, %tnpc
+	andn	%g3, 0x7f, %g3
+	add	%g3, 0x74, %g3
+	wrpr	%g3, %tnpc
 	done
-fill_fixup_dax:
-	rdpr		%tstate, %g1
-	andcc		%g1, TSTATE_PRIV, %g0
-	be,pt		%xcc, window_dax_from_user_common
-	 and		%g1, TSTATE_CWP, %g1
-
-	/* Please, see fill_fixup commentary about why we must preserve
-	 * %l5 and %l6 to preserve absolute correct semantics.
-	 */
-	rdpr		%wstate, %g2			! Grab user mode wstate.
-	wrpr		%g1, %cwp			! Get into the right window.
-	sll		%g2, 3, %g2			! NORMAL-->OTHER
-	wrpr		%g0, 0x0, %canrestore		! Standard etrap stuff.
 
-	wrpr		%g2, 0x0, %wstate		! This must be consistent.
-	wrpr		%g0, 0x0, %otherwin		! We know this.
-	call		set_pcontext			! Change contexts...
+fill_fixup_dax:
+	rdpr	%tstate, %g1
+	and	%g1, TSTATE_CWP, %g1
+	wrpr	%g1, %cwp
+	ba,pt	%xcc, etrap
+	 rd	%pc, %g7
+	sethi	%hi(tlb_type), %g1
+	mov	%l4, %o1
+	lduw	[%g1 + %lo(tlb_type)], %g1
+	mov	%l5, %o2
+	cmp	%g1, 3
+	bne,pt	%icc, 1f
+	 add	%sp, PTREGS_OFF, %o0
+	call	sun4v_data_access_exception
 	 nop
-	rdpr		%pstate, %l1			! Prepare to change globals.
-	mov		%g4, %o1			! Setup args for
-	mov		%g5, %o2			! final call to spitfire_data_access_exception.
-	andn		%l1, PSTATE_MM, %l1		! We want to be in RMO
-
-	mov		%g6, %o7			! Stash away current.
-	wrpr		%g0, 0x0, %tl			! Out of trap levels.
-	wrpr		%l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate
-	mov		%o7, %g6			! Get current back.
-	ldx		[%g6 + TI_TASK], %g4		! Finish it.
-#ifdef CONFIG_SMP
-	mov		TSB_REG, %g1
-	ldxa		[%g1] ASI_IMMU, %g5
-#endif
-	call		spitfire_data_access_exception
-	 add		%sp, PTREGS_OFF, %o0
-
-	b,pt		%xcc, rtrap
-	 nop						! yes, the nop is correct
-spill_fixup_dax:
-	ldx		[%g6 + TI_FLAGS], %g1
-	andcc		%g1, _TIF_32BIT, %g0
-	ldub		[%g6 + TI_WSAVED], %g1
-	sll		%g1, 3, %g3
-	add		%g6, %g3, %g3
-	stx		%sp, [%g3 + TI_RWIN_SPTRS]
-
-	sll		%g1, 7, %g3
-	bne,pt		%xcc, 1f
-	 add		%g6, %g3, %g3
-	stx		%l0, [%g3 + TI_REG_WINDOW + 0x00]
-	stx		%l1, [%g3 + TI_REG_WINDOW + 0x08]
-	stx		%l2, [%g3 + TI_REG_WINDOW + 0x10]
-	stx		%l3, [%g3 + TI_REG_WINDOW + 0x18]
-	stx		%l4, [%g3 + TI_REG_WINDOW + 0x20]
-
-	stx		%l5, [%g3 + TI_REG_WINDOW + 0x28]
-	stx		%l6, [%g3 + TI_REG_WINDOW + 0x30]
-	stx		%l7, [%g3 + TI_REG_WINDOW + 0x38]
-	stx		%i0, [%g3 + TI_REG_WINDOW + 0x40]
-	stx		%i1, [%g3 + TI_REG_WINDOW + 0x48]
-	stx		%i2, [%g3 + TI_REG_WINDOW + 0x50]
-	stx		%i3, [%g3 + TI_REG_WINDOW + 0x58]
-	stx		%i4, [%g3 + TI_REG_WINDOW + 0x60]
-
-	stx		%i5, [%g3 + TI_REG_WINDOW + 0x68]
-	stx		%i6, [%g3 + TI_REG_WINDOW + 0x70]
-	stx		%i7, [%g3 + TI_REG_WINDOW + 0x78]
-	b,pt		%xcc, 2f
-	 add		%g1, 1, %g1
-1:	std		%l0, [%g3 + TI_REG_WINDOW + 0x00]
-	std		%l2, [%g3 + TI_REG_WINDOW + 0x08]
-	std		%l4, [%g3 + TI_REG_WINDOW + 0x10]
-
-	std		%l6, [%g3 + TI_REG_WINDOW + 0x18]
-	std		%i0, [%g3 + TI_REG_WINDOW + 0x20]
-	std		%i2, [%g3 + TI_REG_WINDOW + 0x28]
-	std		%i4, [%g3 + TI_REG_WINDOW + 0x30]
-	std		%i6, [%g3 + TI_REG_WINDOW + 0x38]
-	add		%g1, 1, %g1
-2:	stb		%g1, [%g6 + TI_WSAVED]
-	rdpr		%tstate, %g1
-
-	andcc		%g1, TSTATE_PRIV, %g0
-	saved
-	be,pn		%xcc, window_dax_from_user_common
-	 and		%g1, TSTATE_CWP, %g1
-	retry
-window_dax_from_user_common:
-	wrpr		%g1, %cwp
-	sethi		%hi(109f), %g7
-	ba,pt		%xcc, etrap
-109:	 or		%g7, %lo(109b), %g7
-	mov		%l4, %o1
-	mov		%l5, %o2
-	call		spitfire_data_access_exception
-	 add		%sp, PTREGS_OFF, %o0
-	ba,pt		%xcc, rtrap
-	 clr		%l6
+	ba,a,pt	%xcc, rtrap_clr_l6
+1:	call	spitfire_data_access_exception
+	 nop
+	ba,a,pt	%xcc, rtrap_clr_l6
diff -urN oldtree/arch/sparc64/lib/Makefile newtree/arch/sparc64/lib/Makefile
--- oldtree/arch/sparc64/lib/Makefile	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/lib/Makefile	2006-02-21 15:58:20.295061240 +0000
@@ -11,6 +11,8 @@
 	 VISsave.o atomic.o bitops.o \
 	 U1memcpy.o U1copy_from_user.o U1copy_to_user.o \
 	 U3memcpy.o U3copy_from_user.o U3copy_to_user.o U3patch.o \
+	 NGmemcpy.o NGcopy_from_user.o NGcopy_to_user.o NGpatch.o \
+	 NGpage.o \
 	 copy_in_user.o user_fixup.o memmove.o \
 	 mcount.o ipcsum.o rwsem.o xor.o find_bit.o delay.o
 
diff -urN oldtree/arch/sparc64/lib/NGcopy_from_user.S newtree/arch/sparc64/lib/NGcopy_from_user.S
--- oldtree/arch/sparc64/lib/NGcopy_from_user.S	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/sparc64/lib/NGcopy_from_user.S	2006-02-21 15:58:20.295061240 +0000
@@ -0,0 +1,36 @@
+/* NGcopy_from_user.S: Niagara optimized copy from userspace.
+ *
+ * Copyright (C) 2006 David S. Miller (davem@davemloft.net)
+ */
+
+#define EX_LD(x)		\
+98:	x;			\
+	.section .fixup;	\
+	.align 4;		\
+99:	retl;			\
+	 mov	1, %o0;		\
+	.section __ex_table;	\
+	.align 4;		\
+	.word 98b, 99b;		\
+	.text;			\
+	.align 4;
+
+#ifndef ASI_AIUS
+#define ASI_AIUS	0x11
+#endif
+
+#define FUNC_NAME		NGcopy_from_user
+#define LOAD(type,addr,dest)	type##a [addr] ASI_AIUS, dest
+#define LOAD_TWIN(addr_reg,dest0,dest1)	\
+	ldda [addr_reg] ASI_BLK_INIT_QUAD_LDD_AIUS, dest0
+#define EX_RETVAL(x)		0
+
+#ifdef __KERNEL__
+#define PREAMBLE					\
+	rd		%asi, %g1;			\
+	cmp		%g1, ASI_AIUS;			\
+	bne,pn		%icc, memcpy_user_stub;		\
+	 nop
+#endif
+
+#include "NGmemcpy.S"
diff -urN oldtree/arch/sparc64/lib/NGcopy_to_user.S newtree/arch/sparc64/lib/NGcopy_to_user.S
--- oldtree/arch/sparc64/lib/NGcopy_to_user.S	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/sparc64/lib/NGcopy_to_user.S	2006-02-21 15:58:20.296061088 +0000
@@ -0,0 +1,39 @@
+/* NGcopy_to_user.S: Niagara optimized copy to userspace.
+ *
+ * Copyright (C) 2006 David S. Miller (davem@davemloft.net)
+ */
+
+#define EX_ST(x)		\
+98:	x;			\
+	.section .fixup;	\
+	.align 4;		\
+99:	retl;			\
+	 mov	1, %o0;		\
+	.section __ex_table;	\
+	.align 4;		\
+	.word 98b, 99b;		\
+	.text;			\
+	.align 4;
+
+#ifndef ASI_AIUS
+#define ASI_AIUS	0x11
+#endif
+
+#define FUNC_NAME		NGcopy_to_user
+#define STORE(type,src,addr)	type##a src, [addr] ASI_AIUS
+#define STORE_ASI		ASI_BLK_INIT_QUAD_LDD_AIUS
+#define EX_RETVAL(x)		0
+
+#ifdef __KERNEL__
+	/* Writing to %asi is _expensive_ so we hardcode it.
+	 * Reading %asi to check for KERNEL_DS is comparatively
+	 * cheap.
+	 */
+#define PREAMBLE					\
+	rd		%asi, %g1;			\
+	cmp		%g1, ASI_AIUS;			\
+	bne,pn		%icc, memcpy_user_stub;		\
+	 nop
+#endif
+
+#include "NGmemcpy.S"
diff -urN oldtree/arch/sparc64/lib/NGmemcpy.S newtree/arch/sparc64/lib/NGmemcpy.S
--- oldtree/arch/sparc64/lib/NGmemcpy.S	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/sparc64/lib/NGmemcpy.S	2006-02-21 15:58:20.296061088 +0000
@@ -0,0 +1,368 @@
+/* NGmemcpy.S: Niagara optimized memcpy.
+ *
+ * Copyright (C) 2006 David S. Miller (davem@davemloft.net)
+ */
+
+#ifdef __KERNEL__
+#include <asm/asi.h>
+#include <asm/thread_info.h>
+#define GLOBAL_SPARE	%g7
+#define RESTORE_ASI(TMP)	\
+	ldub	[%g6 + TI_CURRENT_DS], TMP;  \
+	wr	TMP, 0x0, %asi;
+#else
+#define GLOBAL_SPARE	%g5
+#define RESTORE_ASI(TMP)	\
+	wr	%g0, ASI_PNF, %asi
+#endif
+
+#ifndef STORE_ASI
+#define STORE_ASI	ASI_BLK_INIT_QUAD_LDD_P
+#endif
+
+#ifndef EX_LD
+#define EX_LD(x)	x
+#endif
+
+#ifndef EX_ST
+#define EX_ST(x)	x
+#endif
+
+#ifndef EX_RETVAL
+#define EX_RETVAL(x)	x
+#endif
+
+#ifndef LOAD
+#ifndef MEMCPY_DEBUG
+#define LOAD(type,addr,dest)	type [addr], dest
+#else
+#define LOAD(type,addr,dest)	type##a [addr] 0x80, dest
+#endif
+#endif
+
+#ifndef LOAD_TWIN
+#define LOAD_TWIN(addr_reg,dest0,dest1)	\
+	ldda [addr_reg] ASI_BLK_INIT_QUAD_LDD_P, dest0
+#endif
+
+#ifndef STORE
+#define STORE(type,src,addr)	type src, [addr]
+#endif
+
+#ifndef STORE_INIT
+#define STORE_INIT(src,addr)	stxa src, [addr] %asi
+#endif
+
+#ifndef FUNC_NAME
+#define FUNC_NAME	NGmemcpy
+#endif
+
+#ifndef PREAMBLE
+#define PREAMBLE
+#endif
+
+#ifndef XCC
+#define XCC xcc
+#endif
+
+	.register	%g2,#scratch
+	.register	%g3,#scratch
+
+	.text
+	.align		64
+
+	.globl	FUNC_NAME
+	.type	FUNC_NAME,#function
+FUNC_NAME:	/* %o0=dst, %o1=src, %o2=len */
+	srlx		%o2, 31, %g2
+	cmp		%g2, 0
+	tne		%xcc, 5
+	PREAMBLE
+	mov		%o0, GLOBAL_SPARE
+	cmp		%o2, 0
+	be,pn		%XCC, 85f
+	 or		%o0, %o1, %o3
+	cmp		%o2, 16
+	blu,a,pn	%XCC, 80f
+	 or		%o3, %o2, %o3
+
+	/* 2 blocks (128 bytes) is the minimum we can do the block
+	 * copy with.  We need to ensure that we'll iterate at least
+	 * once in the block copy loop.  At worst we'll need to align
+	 * the destination to a 64-byte boundary which can chew up
+	 * to (64 - 1) bytes from the length before we perform the
+	 * block copy loop.
+	 */
+	cmp		%o2, (2 * 64)
+	blu,pt		%XCC, 70f
+	 andcc		%o3, 0x7, %g0
+
+	/* %o0:	dst
+	 * %o1:	src
+	 * %o2:	len  (known to be >= 128)
+	 *
+	 * The block copy loops will use %o4/%o5,%g2/%g3 as
+	 * temporaries while copying the data.
+	 */
+
+	LOAD(prefetch, %o1, #one_read)
+	wr		%g0, STORE_ASI, %asi
+
+	/* Align destination on 64-byte boundary.  */
+	andcc		%o0, (64 - 1), %o4
+	be,pt		%XCC, 2f
+	 sub		%o4, 64, %o4
+	sub		%g0, %o4, %o4	! bytes to align dst
+	sub		%o2, %o4, %o2
+1:	subcc		%o4, 1, %o4
+	EX_LD(LOAD(ldub, %o1, %g1))
+	EX_ST(STORE(stb, %g1, %o0))
+	add		%o1, 1, %o1
+	bne,pt		%XCC, 1b
+	add		%o0, 1, %o0
+
+	/* If the source is on a 16-byte boundary we can do
+	 * the direct block copy loop.  If it is 8-byte aligned
+	 * we can do the 16-byte loads offset by -8 bytes and the
+	 * init stores offset by one register.
+	 *
+	 * If the source is not even 8-byte aligned, we need to do
+	 * shifting and masking (basically integer faligndata).
+	 *
+	 * The careful bit with init stores is that if we store
+	 * to any part of the cache line we have to store the whole
+	 * cacheline else we can end up with corrupt L2 cache line
+	 * contents.  Since the loop works on 64-bytes of 64-byte
+	 * aligned store data at a time, this is easy to ensure.
+	 */
+2:
+	andcc		%o1, (16 - 1), %o4
+	andn		%o2, (64 - 1), %g1	! block copy loop iterator
+	sub		%o2, %g1, %o2		! final sub-block copy bytes
+	be,pt		%XCC, 50f
+	 cmp		%o4, 8
+	be,a,pt		%XCC, 10f
+	 sub		%o1, 0x8, %o1
+
+	/* Neither 8-byte nor 16-byte aligned, shift and mask.  */
+	mov		%g1, %o4
+	and		%o1, 0x7, %g1
+	sll		%g1, 3, %g1
+	mov		64, %o3
+	andn		%o1, 0x7, %o1
+	EX_LD(LOAD(ldx, %o1, %g2))
+	sub		%o3, %g1, %o3
+	sllx		%g2, %g1, %g2
+
+#define SWIVEL_ONE_DWORD(SRC, TMP1, TMP2, PRE_VAL, PRE_SHIFT, POST_SHIFT, DST)\
+	EX_LD(LOAD(ldx, SRC, TMP1)); \
+	srlx		TMP1, PRE_SHIFT, TMP2; \
+	or		TMP2, PRE_VAL, TMP2; \
+	EX_ST(STORE_INIT(TMP2, DST)); \
+	sllx		TMP1, POST_SHIFT, PRE_VAL;
+
+1:	add		%o1, 0x8, %o1
+	SWIVEL_ONE_DWORD(%o1, %g3, %o5, %g2, %o3, %g1, %o0 + 0x00)
+	add		%o1, 0x8, %o1
+	SWIVEL_ONE_DWORD(%o1, %g3, %o5, %g2, %o3, %g1, %o0 + 0x08)
+	add		%o1, 0x8, %o1
+	SWIVEL_ONE_DWORD(%o1, %g3, %o5, %g2, %o3, %g1, %o0 + 0x10)
+	add		%o1, 0x8, %o1
+	SWIVEL_ONE_DWORD(%o1, %g3, %o5, %g2, %o3, %g1, %o0 + 0x18)
+	add		%o1, 32, %o1
+	LOAD(prefetch, %o1, #one_read)
+	sub		%o1, 32 - 8, %o1
+	SWIVEL_ONE_DWORD(%o1, %g3, %o5, %g2, %o3, %g1, %o0 + 0x20)
+	add		%o1, 8, %o1
+	SWIVEL_ONE_DWORD(%o1, %g3, %o5, %g2, %o3, %g1, %o0 + 0x28)
+	add		%o1, 8, %o1
+	SWIVEL_ONE_DWORD(%o1, %g3, %o5, %g2, %o3, %g1, %o0 + 0x30)
+	add		%o1, 8, %o1
+	SWIVEL_ONE_DWORD(%o1, %g3, %o5, %g2, %o3, %g1, %o0 + 0x38)
+	subcc		%o4, 64, %o4
+	bne,pt		%XCC, 1b
+	 add		%o0, 64, %o0
+
+#undef SWIVEL_ONE_DWORD
+
+	srl		%g1, 3, %g1
+	ba,pt		%XCC, 60f
+	 add		%o1, %g1, %o1
+
+10:	/* Destination is 64-byte aligned, source was only 8-byte
+	 * aligned but it has been subtracted by 8 and we perform
+	 * one twin load ahead, then add 8 back into source when
+	 * we finish the loop.
+	 */
+	EX_LD(LOAD_TWIN(%o1, %o4, %o5))
+1:	add		%o1, 16, %o1
+	EX_LD(LOAD_TWIN(%o1, %g2, %g3))
+	add		%o1, 16 + 32, %o1
+	LOAD(prefetch, %o1, #one_read)
+	sub		%o1, 32, %o1
+	EX_ST(STORE_INIT(%o5, %o0 + 0x00))	! initializes cache line
+	EX_ST(STORE_INIT(%g2, %o0 + 0x08))
+	EX_LD(LOAD_TWIN(%o1, %o4, %o5))
+	add		%o1, 16, %o1
+	EX_ST(STORE_INIT(%g3, %o0 + 0x10))
+	EX_ST(STORE_INIT(%o4, %o0 + 0x18))
+	EX_LD(LOAD_TWIN(%o1, %g2, %g3))
+	add		%o1, 16, %o1
+	EX_ST(STORE_INIT(%o5, %o0 + 0x20))
+	EX_ST(STORE_INIT(%g2, %o0 + 0x28))
+	EX_LD(LOAD_TWIN(%o1, %o4, %o5))
+	EX_ST(STORE_INIT(%g3, %o0 + 0x30))
+	EX_ST(STORE_INIT(%o4, %o0 + 0x38))
+	subcc		%g1, 64, %g1
+	bne,pt		%XCC, 1b
+	 add		%o0, 64, %o0
+
+	ba,pt		%XCC, 60f
+	 add		%o1, 0x8, %o1
+
+50:	/* Destination is 64-byte aligned, and source is 16-byte
+	 * aligned.
+	 */
+1:	EX_LD(LOAD_TWIN(%o1, %o4, %o5))
+	add	%o1, 16, %o1
+	EX_LD(LOAD_TWIN(%o1, %g2, %g3))
+	add	%o1, 16 + 32, %o1
+	LOAD(prefetch, %o1, #one_read)
+	sub	%o1, 32, %o1
+	EX_ST(STORE_INIT(%o4, %o0 + 0x00))	! initializes cache line
+	EX_ST(STORE_INIT(%o5, %o0 + 0x08))
+	EX_LD(LOAD_TWIN(%o1, %o4, %o5))
+	add	%o1, 16, %o1
+	EX_ST(STORE_INIT(%g2, %o0 + 0x10))
+	EX_ST(STORE_INIT(%g3, %o0 + 0x18))
+	EX_LD(LOAD_TWIN(%o1, %g2, %g3))
+	add	%o1, 16, %o1
+	EX_ST(STORE_INIT(%o4, %o0 + 0x20))
+	EX_ST(STORE_INIT(%o5, %o0 + 0x28))
+	EX_ST(STORE_INIT(%g2, %o0 + 0x30))
+	EX_ST(STORE_INIT(%g3, %o0 + 0x38))
+	subcc	%g1, 64, %g1
+	bne,pt	%XCC, 1b
+	 add	%o0, 64, %o0
+	/* fall through */
+
+60:	
+	/* %o2 contains any final bytes still needed to be copied
+	 * over. If anything is left, we copy it one byte at a time.
+	 */
+	RESTORE_ASI(%o3)
+	brz,pt		%o2, 85f
+	 sub		%o0, %o1, %o3
+	ba,a,pt		%XCC, 90f
+
+	.align		64
+70: /* 16 < len <= 64 */
+	bne,pn		%XCC, 75f
+	 sub		%o0, %o1, %o3
+
+72:
+	andn		%o2, 0xf, %o4
+	and		%o2, 0xf, %o2
+1:	subcc		%o4, 0x10, %o4
+	EX_LD(LOAD(ldx, %o1, %o5))
+	add		%o1, 0x08, %o1
+	EX_LD(LOAD(ldx, %o1, %g1))
+	sub		%o1, 0x08, %o1
+	EX_ST(STORE(stx, %o5, %o1 + %o3))
+	add		%o1, 0x8, %o1
+	EX_ST(STORE(stx, %g1, %o1 + %o3))
+	bgu,pt		%XCC, 1b
+	 add		%o1, 0x8, %o1
+73:	andcc		%o2, 0x8, %g0
+	be,pt		%XCC, 1f
+	 nop
+	sub		%o2, 0x8, %o2
+	EX_LD(LOAD(ldx, %o1, %o5))
+	EX_ST(STORE(stx, %o5, %o1 + %o3))
+	add		%o1, 0x8, %o1
+1:	andcc		%o2, 0x4, %g0
+	be,pt		%XCC, 1f
+	 nop
+	sub		%o2, 0x4, %o2
+	EX_LD(LOAD(lduw, %o1, %o5))
+	EX_ST(STORE(stw, %o5, %o1 + %o3))
+	add		%o1, 0x4, %o1
+1:	cmp		%o2, 0
+	be,pt		%XCC, 85f
+	 nop
+	ba,pt		%xcc, 90f
+	 nop
+
+75:
+	andcc		%o0, 0x7, %g1
+	sub		%g1, 0x8, %g1
+	be,pn		%icc, 2f
+	 sub		%g0, %g1, %g1
+	sub		%o2, %g1, %o2
+
+1:	subcc		%g1, 1, %g1
+	EX_LD(LOAD(ldub, %o1, %o5))
+	EX_ST(STORE(stb, %o5, %o1 + %o3))
+	bgu,pt		%icc, 1b
+	 add		%o1, 1, %o1
+
+2:	add		%o1, %o3, %o0
+	andcc		%o1, 0x7, %g1
+	bne,pt		%icc, 8f
+	 sll		%g1, 3, %g1
+
+	cmp		%o2, 16
+	bgeu,pt		%icc, 72b
+	 nop
+	ba,a,pt		%xcc, 73b
+
+8:	mov		64, %o3
+	andn		%o1, 0x7, %o1
+	EX_LD(LOAD(ldx, %o1, %g2))
+	sub		%o3, %g1, %o3
+	andn		%o2, 0x7, %o4
+	sllx		%g2, %g1, %g2
+1:	add		%o1, 0x8, %o1
+	EX_LD(LOAD(ldx, %o1, %g3))
+	subcc		%o4, 0x8, %o4
+	srlx		%g3, %o3, %o5
+	or		%o5, %g2, %o5
+	EX_ST(STORE(stx, %o5, %o0))
+	add		%o0, 0x8, %o0
+	bgu,pt		%icc, 1b
+	 sllx		%g3, %g1, %g2
+
+	srl		%g1, 3, %g1
+	andcc		%o2, 0x7, %o2
+	be,pn		%icc, 85f
+	 add		%o1, %g1, %o1
+	ba,pt		%xcc, 90f
+	 sub		%o0, %o1, %o3
+
+	.align		64
+80: /* 0 < len <= 16 */
+	andcc		%o3, 0x3, %g0
+	bne,pn		%XCC, 90f
+	 sub		%o0, %o1, %o3
+
+1:
+	subcc		%o2, 4, %o2
+	EX_LD(LOAD(lduw, %o1, %g1))
+	EX_ST(STORE(stw, %g1, %o1 + %o3))
+	bgu,pt		%XCC, 1b
+	 add		%o1, 4, %o1
+
+85:	retl
+	 mov		EX_RETVAL(GLOBAL_SPARE), %o0
+
+	.align		32
+90:
+	subcc		%o2, 1, %o2
+	EX_LD(LOAD(ldub, %o1, %g1))
+	EX_ST(STORE(stb, %g1, %o1 + %o3))
+	bgu,pt		%XCC, 90b
+	 add		%o1, 1, %o1
+	retl
+	 mov		EX_RETVAL(GLOBAL_SPARE), %o0
+
+	.size		FUNC_NAME, .-FUNC_NAME
diff -urN oldtree/arch/sparc64/lib/NGpage.S newtree/arch/sparc64/lib/NGpage.S
--- oldtree/arch/sparc64/lib/NGpage.S	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/sparc64/lib/NGpage.S	2006-02-21 15:58:20.297060936 +0000
@@ -0,0 +1,96 @@
+/* NGpage.S: Niagara optimize clear and copy page.
+ *
+ * Copyright (C) 2006 (davem@davemloft.net)
+ */
+
+#include <asm/asi.h>
+#include <asm/page.h>
+
+	.text
+	.align	32
+
+	/* This is heavily simplified from the sun4u variants
+	 * because Niagara does not have any D-cache aliasing issues
+	 * and also we don't need to use the FPU in order to implement
+	 * an optimal page copy/clear.
+	 */
+
+NGcopy_user_page:	/* %o0=dest, %o1=src, %o2=vaddr */
+	prefetch	[%o1 + 0x00], #one_read
+	mov		8, %g1
+	mov		16, %g2
+	mov		24, %g3
+	set		PAGE_SIZE, %g7
+
+1:	ldda		[%o1 + %g0] ASI_BLK_INIT_QUAD_LDD_P, %o2
+	ldda		[%o1 + %g2] ASI_BLK_INIT_QUAD_LDD_P, %o4
+	prefetch	[%o1 + 0x40], #one_read
+	add		%o1, 32, %o1
+	stxa		%o2, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P
+	stxa		%o3, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P
+	ldda		[%o1 + %g0] ASI_BLK_INIT_QUAD_LDD_P, %o2
+	stxa		%o4, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P
+	stxa		%o5, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P
+	ldda		[%o1 + %g2] ASI_BLK_INIT_QUAD_LDD_P, %o4
+	add		%o1, 32, %o1
+	add		%o0, 32, %o0
+	stxa		%o2, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P
+	stxa		%o3, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P
+	stxa		%o4, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P
+	stxa		%o5, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P
+	subcc		%g7, 64, %g7
+	bne,pt		%xcc, 1b
+	 add		%o0, 32, %o0
+	retl
+	 nop
+
+NGclear_page:		/* %o0=dest */
+NGclear_user_page:	/* %o0=dest, %o1=vaddr */
+	mov		8, %g1
+	mov		16, %g2
+	mov		24, %g3
+	set		PAGE_SIZE, %g7
+
+1:	stxa		%g0, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P
+	stxa		%g0, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P
+	stxa		%g0, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P
+	stxa		%g0, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P
+	add		%o0, 32, %o0
+	stxa		%g0, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P
+	stxa		%g0, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P
+	stxa		%g0, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P
+	stxa		%g0, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P
+	subcc		%g7, 64, %g7
+	bne,pt		%xcc, 1b
+	 add		%o0, 32, %o0
+	retl
+	 nop
+
+#define BRANCH_ALWAYS	0x10680000
+#define NOP		0x01000000
+#define NG_DO_PATCH(OLD, NEW)	\
+	sethi	%hi(NEW), %g1; \
+	or	%g1, %lo(NEW), %g1; \
+	sethi	%hi(OLD), %g2; \
+	or	%g2, %lo(OLD), %g2; \
+	sub	%g1, %g2, %g1; \
+	sethi	%hi(BRANCH_ALWAYS), %g3; \
+	sll	%g1, 11, %g1; \
+	srl	%g1, 11 + 2, %g1; \
+	or	%g3, %lo(BRANCH_ALWAYS), %g3; \
+	or	%g3, %g1, %g3; \
+	stw	%g3, [%g2]; \
+	sethi	%hi(NOP), %g3; \
+	or	%g3, %lo(NOP), %g3; \
+	stw	%g3, [%g2 + 0x4]; \
+	flush	%g2;
+
+	.globl	niagara_patch_pageops
+	.type	niagara_patch_pageops,#function
+niagara_patch_pageops:
+	NG_DO_PATCH(copy_user_page, NGcopy_user_page)
+	NG_DO_PATCH(_clear_page, NGclear_page)
+	NG_DO_PATCH(clear_user_page, NGclear_user_page)
+	retl
+	 nop
+	.size	niagara_patch_pageops,.-niagara_patch_pageops
diff -urN oldtree/arch/sparc64/lib/NGpatch.S newtree/arch/sparc64/lib/NGpatch.S
--- oldtree/arch/sparc64/lib/NGpatch.S	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/sparc64/lib/NGpatch.S	2006-02-21 15:58:20.297060936 +0000
@@ -0,0 +1,33 @@
+/* NGpatch.S: Patch Ultra-I routines with Niagara variant.
+ *
+ * Copyright (C) 2006 David S. Miller <davem@davemloft.net>
+ */
+
+#define BRANCH_ALWAYS	0x10680000
+#define NOP		0x01000000
+#define NG_DO_PATCH(OLD, NEW)	\
+	sethi	%hi(NEW), %g1; \
+	or	%g1, %lo(NEW), %g1; \
+	sethi	%hi(OLD), %g2; \
+	or	%g2, %lo(OLD), %g2; \
+	sub	%g1, %g2, %g1; \
+	sethi	%hi(BRANCH_ALWAYS), %g3; \
+	sll	%g1, 11, %g1; \
+	srl	%g1, 11 + 2, %g1; \
+	or	%g3, %lo(BRANCH_ALWAYS), %g3; \
+	or	%g3, %g1, %g3; \
+	stw	%g3, [%g2]; \
+	sethi	%hi(NOP), %g3; \
+	or	%g3, %lo(NOP), %g3; \
+	stw	%g3, [%g2 + 0x4]; \
+	flush	%g2;
+
+	.globl	niagara_patch_copyops
+	.type	niagara_patch_copyops,#function
+niagara_patch_copyops:
+	NG_DO_PATCH(memcpy, NGmemcpy)
+	NG_DO_PATCH(___copy_from_user, NGcopy_from_user)
+	NG_DO_PATCH(___copy_to_user, NGcopy_to_user)
+	retl
+	 nop
+	.size	niagara_patch_copyops,.-niagara_patch_copyops
diff -urN oldtree/arch/sparc64/lib/U3patch.S newtree/arch/sparc64/lib/U3patch.S
--- oldtree/arch/sparc64/lib/U3patch.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/lib/U3patch.S	2006-02-21 15:58:20.297060936 +0000
@@ -12,7 +12,8 @@
 	or	%g2, %lo(OLD), %g2; \
 	sub	%g1, %g2, %g1; \
 	sethi	%hi(BRANCH_ALWAYS), %g3; \
-	srl	%g1, 2, %g1; \
+	sll	%g1, 11, %g1; \
+	srl	%g1, 11 + 2, %g1; \
 	or	%g3, %lo(BRANCH_ALWAYS), %g3; \
 	or	%g3, %g1, %g3; \
 	stw	%g3, [%g2]; \
diff -urN oldtree/arch/sparc64/lib/bzero.S newtree/arch/sparc64/lib/bzero.S
--- oldtree/arch/sparc64/lib/bzero.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/lib/bzero.S	2006-02-21 15:58:20.299060632 +0000
@@ -98,12 +98,12 @@
 	.text;			\
 	.align 4;
 
-	.globl	__bzero_noasi
-	.type	__bzero_noasi, #function
-__bzero_noasi:		/* %o0=buf, %o1=len */
-	brz,pn		%o1, __bzero_noasi_done
+	.globl	__clear_user
+	.type	__clear_user, #function
+__clear_user:		/* %o0=buf, %o1=len */
+	brz,pn		%o1, __clear_user_done
 	 cmp		%o1, 16
-	bl,pn		%icc, __bzero_noasi_tiny
+	bl,pn		%icc, __clear_user_tiny
 	 EX_ST(prefetcha [%o0 + 0x00] %asi, #n_writes)
 	andcc		%o0, 0x3, %g0
 	be,pt		%icc, 2f
@@ -145,14 +145,14 @@
 	subcc		%g1, 8, %g1
 	bne,pt		%icc, 5b
 	 add		%o0, 0x8, %o0
-6:	brz,pt		%o1, __bzero_noasi_done
+6:	brz,pt		%o1, __clear_user_done
 	 nop
-__bzero_noasi_tiny:
+__clear_user_tiny:
 1:	EX_ST(stba	%g0, [%o0 + 0x00] %asi)
 	subcc		%o1, 1, %o1
 	bne,pt		%icc, 1b
 	 add		%o0, 1, %o0
-__bzero_noasi_done:
+__clear_user_done:
 	retl
 	 clr		%o0
-	.size		__bzero_noasi, .-__bzero_noasi
+	.size		__clear_user, .-__clear_user
diff -urN oldtree/arch/sparc64/lib/clear_page.S newtree/arch/sparc64/lib/clear_page.S
--- oldtree/arch/sparc64/lib/clear_page.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/lib/clear_page.S	2006-02-21 15:58:20.300060480 +0000
@@ -9,6 +9,7 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/spitfire.h>
+#include <asm/head.h>
 
 	/* What we used to do was lock a TLB entry into a specific
 	 * TLB slot, clear the page with interrupts disabled, then
@@ -22,9 +23,6 @@
 	 * disable preemption during the clear.
 	 */
 
-#define TTE_BITS_TOP	(_PAGE_VALID | _PAGE_SZBITS)
-#define TTE_BITS_BOTTOM	(_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W)
-
 	.text
 
 	.globl		_clear_page
@@ -43,12 +41,11 @@
 	sethi		%hi(PAGE_SIZE), %o4
 
 	sllx		%g2, 32, %g2
-	sethi		%uhi(TTE_BITS_TOP), %g3
+	sethi		%hi(PAGE_KERNEL_LOCKED), %g3
 
-	sllx		%g3, 32, %g3
+	ldx		[%g3 + %lo(PAGE_KERNEL_LOCKED)], %g3
 	sub		%o0, %g2, %g1		! paddr
 
-	or		%g3, TTE_BITS_BOTTOM, %g3
 	and		%o1, %o4, %o0		! vaddr D-cache alias bit
 
 	or		%g1, %g3, %g1		! TTE data
@@ -66,7 +63,8 @@
 	wrpr		%o4, PSTATE_IE, %pstate
 	stxa		%o0, [%g3] ASI_DMMU
 	stxa		%g1, [%g0] ASI_DTLB_DATA_IN
-	flush		%g6
+	sethi		%hi(KERNBASE), %g1
+	flush		%g1
 	wrpr		%o4, 0x0, %pstate
 
 	mov		1, %o4
diff -urN oldtree/arch/sparc64/lib/copy_page.S newtree/arch/sparc64/lib/copy_page.S
--- oldtree/arch/sparc64/lib/copy_page.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/lib/copy_page.S	2006-02-21 15:58:20.302060176 +0000
@@ -23,8 +23,6 @@
 	 * disable preemption during the clear.
 	 */
 
-#define TTE_BITS_TOP	(_PAGE_VALID | _PAGE_SZBITS)
-#define TTE_BITS_BOTTOM	(_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W)
 #define	DCACHE_SIZE	(PAGE_SIZE * 2)
 
 #if (PAGE_SHIFT == 13) || (PAGE_SHIFT == 19)
@@ -52,13 +50,12 @@
 	sethi		%hi(PAGE_SIZE), %o3
 
 	sllx		%g2, 32, %g2
-	sethi		%uhi(TTE_BITS_TOP), %g3
+	sethi		%hi(PAGE_KERNEL_LOCKED), %g3
 
-	sllx		%g3, 32, %g3
+	ldx		[%g3 + %lo(PAGE_KERNEL_LOCKED)], %g3
 	sub		%o0, %g2, %g1		! dest paddr
 
 	sub		%o1, %g2, %g2		! src paddr
-	or		%g3, TTE_BITS_BOTTOM, %g3
 
 	and		%o2, %o3, %o0		! vaddr D-cache alias bit
 	or		%g1, %g3, %g1		! dest TTE data
diff -urN oldtree/arch/sparc64/lib/delay.c newtree/arch/sparc64/lib/delay.c
--- oldtree/arch/sparc64/lib/delay.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/lib/delay.c	2006-02-21 15:58:20.305059720 +0000
@@ -1,6 +1,6 @@
 /* delay.c: Delay loops for sparc64
  *
- * Copyright (C) 2004 David S. Miller <davem@redhat.com>
+ * Copyright (C) 2004, 2006 David S. Miller <davem@davemloft.net>
  *
  * Based heavily upon x86 variant which is:
  *	Copyright (C) 1993 Linus Torvalds
@@ -8,19 +8,16 @@
  */
 
 #include <linux/delay.h>
+#include <asm/timer.h>
 
 void __delay(unsigned long loops)
 {
-	__asm__ __volatile__(
-"	b,pt	%%xcc, 1f\n"
-"	 cmp	%0, 0\n"
-"	.align	32\n"
-"1:\n"
-"	bne,pt	%%xcc, 1b\n"
-"	 subcc	%0, 1, %0\n"
-	: "=&r" (loops)
-	: "0" (loops)
-	: "cc");
+	unsigned long bclock, now;
+	
+	bclock = tick_ops->get_tick();
+	do {
+		now = tick_ops->get_tick();
+	} while ((now-bclock) < loops);
 }
 
 /* We used to multiply by HZ after shifting down by 32 bits
diff -urN oldtree/arch/sparc64/mm/Makefile newtree/arch/sparc64/mm/Makefile
--- oldtree/arch/sparc64/mm/Makefile	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/mm/Makefile	2006-02-21 15:58:20.306059568 +0000
@@ -5,6 +5,6 @@
 EXTRA_AFLAGS := -ansi
 EXTRA_CFLAGS := -Werror
 
-obj-y    := ultra.o tlb.o fault.o init.o generic.o
+obj-y    := ultra.o tlb.o tsb.o fault.o init.o generic.o
 
 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
diff -urN oldtree/arch/sparc64/mm/fault.c newtree/arch/sparc64/mm/fault.c
--- oldtree/arch/sparc64/mm/fault.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/mm/fault.c	2006-02-21 15:58:20.319057592 +0000
@@ -91,12 +91,13 @@
 	die_if_kernel("Oops", regs);
 }
 
-static void bad_kernel_pc(struct pt_regs *regs)
+static void bad_kernel_pc(struct pt_regs *regs, unsigned long vaddr)
 {
 	unsigned long *ksp;
 
 	printk(KERN_CRIT "OOPS: Bogus kernel PC [%016lx] in fault handler\n",
 	       regs->tpc);
+	printk(KERN_CRIT "OOPS: Fault was to vaddr[%lx]\n", vaddr);
 	__asm__("mov %%sp, %0" : "=r" (ksp));
 	show_stack(current, ksp);
 	unhandled_fault(regs->tpc, current, regs);
@@ -137,7 +138,7 @@
 	if (!pte_present(pte))
 		goto out;
 
-	pa  = (pte_val(pte) & _PAGE_PADDR);
+	pa  = (pte_pfn(pte) << PAGE_SHIFT);
 	pa += (tpc & ~PAGE_MASK);
 
 	/* Use phys bypass so we don't pollute dtlb/dcache. */
@@ -280,7 +281,7 @@
 		    (tpc >= MODULES_VADDR && tpc < MODULES_END)) {
 			/* Valid, no problems... */
 		} else {
-			bad_kernel_pc(regs);
+			bad_kernel_pc(regs, address);
 			return;
 		}
 	}
diff -urN oldtree/arch/sparc64/mm/generic.c newtree/arch/sparc64/mm/generic.c
--- oldtree/arch/sparc64/mm/generic.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/mm/generic.c	2006-02-21 15:58:20.334055312 +0000
@@ -15,15 +15,6 @@
 #include <asm/page.h>
 #include <asm/tlbflush.h>
 
-static inline pte_t mk_pte_io(unsigned long page, pgprot_t prot, int space)
-{
-	pte_t pte;
-	pte_val(pte) = (((page) | pgprot_val(prot) | _PAGE_E) &
-			~(unsigned long)_PAGE_CACHE);
-	pte_val(pte) |= (((unsigned long)space) << 32);
-	return pte;
-}
-
 /* Remap IO memory, the same way as remap_pfn_range(), but use
  * the obio memory space.
  *
@@ -48,24 +39,29 @@
 		pte_t entry;
 		unsigned long curend = address + PAGE_SIZE;
 		
-		entry = mk_pte_io(offset, prot, space);
+		entry = mk_pte_io(offset, prot, space, PAGE_SIZE);
 		if (!(address & 0xffff)) {
-			if (!(address & 0x3fffff) && !(offset & 0x3ffffe) && end >= address + 0x400000) {
-				entry = mk_pte_io(offset,
-						  __pgprot(pgprot_val (prot) | _PAGE_SZ4MB),
-						  space);
+			if (PAGE_SIZE < (4 * 1024 * 1024) &&
+			    !(address & 0x3fffff) &&
+			    !(offset & 0x3ffffe) &&
+			    end >= address + 0x400000) {
+				entry = mk_pte_io(offset, prot, space,
+						  4 * 1024 * 1024);
 				curend = address + 0x400000;
 				offset += 0x400000;
-			} else if (!(address & 0x7ffff) && !(offset & 0x7fffe) && end >= address + 0x80000) {
-				entry = mk_pte_io(offset,
-						  __pgprot(pgprot_val (prot) | _PAGE_SZ512K),
-						  space);
+			} else if (PAGE_SIZE < (512 * 1024) &&
+				   !(address & 0x7ffff) &&
+				   !(offset & 0x7fffe) &&
+				   end >= address + 0x80000) {
+				entry = mk_pte_io(offset, prot, space,
+						  512 * 1024 * 1024);
 				curend = address + 0x80000;
 				offset += 0x80000;
-			} else if (!(offset & 0xfffe) && end >= address + 0x10000) {
-				entry = mk_pte_io(offset,
-						  __pgprot(pgprot_val (prot) | _PAGE_SZ64K),
-						  space);
+			} else if (PAGE_SIZE < (64 * 1024) &&
+				   !(offset & 0xfffe) &&
+				   end >= address + 0x10000) {
+				entry = mk_pte_io(offset, prot, space,
+						  64 * 1024);
 				curend = address + 0x10000;
 				offset += 0x10000;
 			} else
diff -urN oldtree/arch/sparc64/mm/init.c newtree/arch/sparc64/mm/init.c
--- oldtree/arch/sparc64/mm/init.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/mm/init.c	2006-02-21 15:58:20.377048776 +0000
@@ -6,6 +6,7 @@
  */
  
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -39,6 +40,8 @@
 #include <asm/tlb.h>
 #include <asm/spitfire.h>
 #include <asm/sections.h>
+#include <asm/tsb.h>
+#include <asm/hypervisor.h>
 
 extern void device_scan(void);
 
@@ -116,6 +119,7 @@
 unsigned long kern_base __read_mostly;
 unsigned long kern_size __read_mostly;
 unsigned long pfn_base __read_mostly;
+unsigned long kern_linear_pte_xor __read_mostly;
 
 /* get_new_mmu_context() uses "cache + 1".  */
 DEFINE_SPINLOCK(ctx_alloc_lock);
@@ -141,24 +145,25 @@
 
 int bigkernel = 0;
 
-/* XXX Tune this... */
-#define PGT_CACHE_LOW	25
-#define PGT_CACHE_HIGH	50
-
-void check_pgt_cache(void)
-{
-	preempt_disable();
-	if (pgtable_cache_size > PGT_CACHE_HIGH) {
-		do {
-			if (pgd_quicklist)
-				free_pgd_slow(get_pgd_fast());
-			if (pte_quicklist[0])
-				free_pte_slow(pte_alloc_one_fast(NULL, 0));
-			if (pte_quicklist[1])
-				free_pte_slow(pte_alloc_one_fast(NULL, 1 << (PAGE_SHIFT + 10)));
-		} while (pgtable_cache_size > PGT_CACHE_LOW);
+kmem_cache_t *pgtable_cache __read_mostly;
+
+static void zero_ctor(void *addr, kmem_cache_t *cache, unsigned long flags)
+{
+	clear_page(addr);
+}
+
+void pgtable_cache_init(void)
+{
+	pgtable_cache = kmem_cache_create("pgtable_cache",
+					  PAGE_SIZE, PAGE_SIZE,
+					  SLAB_HWCACHE_ALIGN |
+					  SLAB_MUST_HWCACHE_ALIGN,
+					  zero_ctor,
+					  NULL);
+	if (!pgtable_cache) {
+		prom_printf("pgtable_cache_init(): Could not create!\n");
+		prom_halt();
 	}
-	preempt_enable();
 }
 
 #ifdef CONFIG_DEBUG_DCFLUSH
@@ -243,8 +248,22 @@
 			     : "g1", "g7");
 }
 
+static inline void tsb_insert(struct tsb *ent, unsigned long tag, unsigned long pte)
+{
+	unsigned long tsb_addr = (unsigned long) ent;
+
+	if (tlb_type == cheetah_plus || tlb_type == hypervisor)
+		tsb_addr = __pa(tsb_addr);
+
+	__tsb_insert(tsb_addr, tag, pte);
+}
+
+unsigned long _PAGE_ALL_SZ_BITS __read_mostly;
+unsigned long _PAGE_SZBITS __read_mostly;
+
 void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 {
+	struct mm_struct *mm;
 	struct page *page;
 	unsigned long pfn;
 	unsigned long pg_flags;
@@ -269,6 +288,17 @@
 
 		put_cpu();
 	}
+
+	mm = vma->vm_mm;
+	if ((pte_val(pte) & _PAGE_ALL_SZ_BITS) == _PAGE_SZBITS) {
+		struct tsb *tsb;
+		unsigned long tag;
+
+		tsb = &mm->context.tsb[(address >> PAGE_SHIFT) &
+				       (mm->context.tsb_nentries - 1UL)];
+		tag = (address >> 22UL);
+		tsb_insert(tsb, tag, pte_val(pte));
+	}
 }
 
 void flush_dcache_page(struct page *page)
@@ -311,7 +341,7 @@
 
 void __kprobes flush_icache_range(unsigned long start, unsigned long end)
 {
-	/* Cheetah has coherent I-cache. */
+	/* Cheetah and Hypervisor platform cpus have coherent I-cache. */
 	if (tlb_type == spitfire) {
 		unsigned long kaddr;
 
@@ -338,7 +368,6 @@
 	       nr_swap_pages << (PAGE_SHIFT-10));
 	printk("%ld pages of RAM\n", num_physpages);
 	printk("%d free pages\n", nr_free_pages());
-	printk("%d pages in page table cache\n",pgtable_cache_size);
 }
 
 void mmu_info(struct seq_file *m)
@@ -349,6 +378,8 @@
 		seq_printf(m, "MMU Type\t: Cheetah+\n");
 	else if (tlb_type == spitfire)
 		seq_printf(m, "MMU Type\t: Spitfire\n");
+	else if (tlb_type == hypervisor)
+		seq_printf(m, "MMU Type\t: Hypervisor (sun4v)\n");
 	else
 		seq_printf(m, "MMU Type\t: ???\n");
 
@@ -371,45 +402,13 @@
 /* Exported for kernel TLB miss handling in ktlb.S */
 struct linux_prom_translation prom_trans[512] __read_mostly;
 unsigned int prom_trans_ents __read_mostly;
-unsigned int swapper_pgd_zero __read_mostly;
-
-extern unsigned long prom_boot_page;
-extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle);
-extern int prom_get_mmu_ihandle(void);
-extern void register_prom_callbacks(void);
 
 /* Exported for SMP bootup purposes. */
 unsigned long kern_locked_tte_data;
 
-/*
- * Translate PROM's mapping we capture at boot time into physical address.
- * The second parameter is only set from prom_callback() invocations.
- */
-unsigned long prom_virt_to_phys(unsigned long promva, int *error)
-{
-	int i;
-
-	for (i = 0; i < prom_trans_ents; i++) {
-		struct linux_prom_translation *p = &prom_trans[i];
-
-		if (promva >= p->virt &&
-		    promva < (p->virt + p->size)) {
-			unsigned long base = p->data & _PAGE_PADDR;
-
-			if (error)
-				*error = 0;
-			return base + (promva & (8192 - 1));
-		}
-	}
-	if (error)
-		*error = 1;
-	return 0UL;
-}
-
 /* The obp translations are saved based on 8k pagesize, since obp can
  * use a mixture of pagesizes. Misses to the LOW_OBP_ADDRESS ->
- * HI_OBP_ADDRESS range are handled in ktlb.S and do not use the vpte
- * scheme (also, see rant in inherit_locked_prom_mappings()).
+ * HI_OBP_ADDRESS range are handled in ktlb.S.
  */
 static inline int in_obp_range(unsigned long vaddr)
 {
@@ -490,6 +489,36 @@
 	}
 }
 
+static void __init hypervisor_tlb_lock(unsigned long vaddr,
+				       unsigned long pte,
+				       unsigned long mmu)
+{
+	register unsigned long func asm("%o5");
+	register unsigned long arg0 asm("%o0");
+	register unsigned long arg1 asm("%o1");
+	register unsigned long arg2 asm("%o2");
+	register unsigned long arg3 asm("%o3");
+
+	func = HV_FAST_MMU_MAP_PERM_ADDR;
+	arg0 = vaddr;
+	arg1 = 0;
+	arg2 = pte;
+	arg3 = mmu;
+	__asm__ __volatile__("ta	0x80"
+			     : "=&r" (func), "=&r" (arg0),
+			       "=&r" (arg1), "=&r" (arg2),
+			       "=&r" (arg3)
+			     : "0" (func), "1" (arg0), "2" (arg1),
+			       "3" (arg2), "4" (arg3));
+	if (arg0 != 0) {
+		prom_printf("hypervisor_tlb_lock[%lx:%lx:%lx:%lx]: "
+			    "errors with %lx\n", vaddr, 0, pte, mmu, arg0);
+		prom_halt();
+	}
+}
+
+static unsigned long kern_large_tte(unsigned long paddr);
+
 static void __init remap_kernel(void)
 {
 	unsigned long phys_page, tte_vaddr, tte_data;
@@ -497,25 +526,34 @@
 
 	tte_vaddr = (unsigned long) KERNBASE;
 	phys_page = (prom_boot_mapping_phys_low >> 22UL) << 22UL;
-	tte_data = (phys_page | (_PAGE_VALID | _PAGE_SZ4MB |
-				 _PAGE_CP | _PAGE_CV | _PAGE_P |
-				 _PAGE_L | _PAGE_W));
+	tte_data = kern_large_tte(phys_page);
 
 	kern_locked_tte_data = tte_data;
 
-	/* Now lock us into the TLBs via OBP. */
-	prom_dtlb_load(tlb_ent, tte_data, tte_vaddr);
-	prom_itlb_load(tlb_ent, tte_data, tte_vaddr);
-	if (bigkernel) {
-		tlb_ent -= 1;
-		prom_dtlb_load(tlb_ent,
-			       tte_data + 0x400000, 
-			       tte_vaddr + 0x400000);
-		prom_itlb_load(tlb_ent,
-			       tte_data + 0x400000, 
-			       tte_vaddr + 0x400000);
+	/* Now lock us into the TLBs via Hypervisor or OBP. */
+	if (tlb_type == hypervisor) {
+		hypervisor_tlb_lock(tte_vaddr, tte_data, HV_MMU_DMMU);
+		hypervisor_tlb_lock(tte_vaddr, tte_data, HV_MMU_IMMU);
+		if (bigkernel) {
+			tte_vaddr += 0x400000;
+			tte_data += 0x400000;
+			hypervisor_tlb_lock(tte_vaddr, tte_data, HV_MMU_DMMU);
+			hypervisor_tlb_lock(tte_vaddr, tte_data, HV_MMU_IMMU);
+		}
+	} else {
+		prom_dtlb_load(tlb_ent, tte_data, tte_vaddr);
+		prom_itlb_load(tlb_ent, tte_data, tte_vaddr);
+		if (bigkernel) {
+			tlb_ent -= 1;
+			prom_dtlb_load(tlb_ent,
+				       tte_data + 0x400000, 
+				       tte_vaddr + 0x400000);
+			prom_itlb_load(tlb_ent,
+				       tte_data + 0x400000, 
+				       tte_vaddr + 0x400000);
+		}
+		sparc64_highest_unlocked_tlb_ent = tlb_ent - 1;
 	}
-	sparc64_highest_unlocked_tlb_ent = tlb_ent - 1;
 	if (tlb_type == cheetah_plus) {
 		sparc64_kern_pri_context = (CTX_CHEETAH_PLUS_CTX0 |
 					    CTX_CHEETAH_PLUS_NUC);
@@ -533,372 +571,14 @@
 	prom_printf("Remapping the kernel... ");
 	remap_kernel();
 	prom_printf("done.\n");
-
-	prom_printf("Registering callbacks... ");
-	register_prom_callbacks();
-	prom_printf("done.\n");
-}
-
-/* The OBP specifications for sun4u mark 0xfffffffc00000000 and
- * upwards as reserved for use by the firmware (I wonder if this
- * will be the same on Cheetah...).  We use this virtual address
- * range for the VPTE table mappings of the nucleus so we need
- * to zap them when we enter the PROM.  -DaveM
- */
-static void __flush_nucleus_vptes(void)
-{
-	unsigned long prom_reserved_base = 0xfffffffc00000000UL;
-	int i;
-
-	/* Only DTLB must be checked for VPTE entries. */
-	if (tlb_type == spitfire) {
-		for (i = 0; i < 63; i++) {
-			unsigned long tag;
-
-			/* Spitfire Errata #32 workaround */
-			/* NOTE: Always runs on spitfire, so no cheetah+
-			 *       page size encodings.
-			 */
-			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
-					     "flush	%%g6"
-					     : /* No outputs */
-					     : "r" (0),
-					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
-
-			tag = spitfire_get_dtlb_tag(i);
-			if (((tag & ~(PAGE_MASK)) == 0) &&
-			    ((tag &  (PAGE_MASK)) >= prom_reserved_base)) {
-				__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
-						     "membar #Sync"
-						     : /* no outputs */
-						     : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
-				spitfire_put_dtlb_data(i, 0x0UL);
-			}
-		}
-	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
-		for (i = 0; i < 512; i++) {
-			unsigned long tag = cheetah_get_dtlb_tag(i, 2);
-
-			if ((tag & ~PAGE_MASK) == 0 &&
-			    (tag & PAGE_MASK) >= prom_reserved_base) {
-				__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
-						     "membar #Sync"
-						     : /* no outputs */
-						     : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
-				cheetah_put_dtlb_data(i, 0x0UL, 2);
-			}
-
-			if (tlb_type != cheetah_plus)
-				continue;
-
-			tag = cheetah_get_dtlb_tag(i, 3);
-
-			if ((tag & ~PAGE_MASK) == 0 &&
-			    (tag & PAGE_MASK) >= prom_reserved_base) {
-				__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
-						     "membar #Sync"
-						     : /* no outputs */
-						     : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
-				cheetah_put_dtlb_data(i, 0x0UL, 3);
-			}
-		}
-	} else {
-		/* Implement me :-) */
-		BUG();
-	}
 }
 
-static int prom_ditlb_set;
-struct prom_tlb_entry {
-	int		tlb_ent;
-	unsigned long	tlb_tag;
-	unsigned long	tlb_data;
-};
-struct prom_tlb_entry prom_itlb[16], prom_dtlb[16];
-
 void prom_world(int enter)
 {
-	unsigned long pstate;
-	int i;
-
 	if (!enter)
 		set_fs((mm_segment_t) { get_thread_current_ds() });
 
-	if (!prom_ditlb_set)
-		return;
-
-	/* Make sure the following runs atomically. */
-	__asm__ __volatile__("flushw\n\t"
-			     "rdpr	%%pstate, %0\n\t"
-			     "wrpr	%0, %1, %%pstate"
-			     : "=r" (pstate)
-			     : "i" (PSTATE_IE));
-
-	if (enter) {
-		/* Kick out nucleus VPTEs. */
-		__flush_nucleus_vptes();
-
-		/* Install PROM world. */
-		for (i = 0; i < 16; i++) {
-			if (prom_dtlb[i].tlb_ent != -1) {
-				__asm__ __volatile__("stxa %0, [%1] %2\n\t"
-						     "membar #Sync"
-					: : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
-					"i" (ASI_DMMU));
-				if (tlb_type == spitfire)
-					spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
-							       prom_dtlb[i].tlb_data);
-				else if (tlb_type == cheetah || tlb_type == cheetah_plus)
-					cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent,
-							       prom_dtlb[i].tlb_data);
-			}
-			if (prom_itlb[i].tlb_ent != -1) {
-				__asm__ __volatile__("stxa %0, [%1] %2\n\t"
-						     "membar #Sync"
-						     : : "r" (prom_itlb[i].tlb_tag),
-						     "r" (TLB_TAG_ACCESS),
-						     "i" (ASI_IMMU));
-				if (tlb_type == spitfire)
-					spitfire_put_itlb_data(prom_itlb[i].tlb_ent,
-							       prom_itlb[i].tlb_data);
-				else if (tlb_type == cheetah || tlb_type == cheetah_plus)
-					cheetah_put_litlb_data(prom_itlb[i].tlb_ent,
-							       prom_itlb[i].tlb_data);
-			}
-		}
-	} else {
-		for (i = 0; i < 16; i++) {
-			if (prom_dtlb[i].tlb_ent != -1) {
-				__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
-						     "membar #Sync"
-					: : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
-				if (tlb_type == spitfire)
-					spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, 0x0UL);
-				else
-					cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent, 0x0UL);
-			}
-			if (prom_itlb[i].tlb_ent != -1) {
-				__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
-						     "membar #Sync"
-						     : : "r" (TLB_TAG_ACCESS),
-						     "i" (ASI_IMMU));
-				if (tlb_type == spitfire)
-					spitfire_put_itlb_data(prom_itlb[i].tlb_ent, 0x0UL);
-				else
-					cheetah_put_litlb_data(prom_itlb[i].tlb_ent, 0x0UL);
-			}
-		}
-	}
-	__asm__ __volatile__("wrpr	%0, 0, %%pstate"
-			     : : "r" (pstate));
-}
-
-void inherit_locked_prom_mappings(int save_p)
-{
-	int i;
-	int dtlb_seen = 0;
-	int itlb_seen = 0;
-
-	/* Fucking losing PROM has more mappings in the TLB, but
-	 * it (conveniently) fails to mention any of these in the
-	 * translations property.  The only ones that matter are
-	 * the locked PROM tlb entries, so we impose the following
-	 * irrecovable rule on the PROM, it is allowed 8 locked
-	 * entries in the ITLB and 8 in the DTLB.
-	 *
-	 * Supposedly the upper 16GB of the address space is
-	 * reserved for OBP, BUT I WISH THIS WAS DOCUMENTED
-	 * SOMEWHERE!!!!!!!!!!!!!!!!!  Furthermore the entire interface
-	 * used between the client program and the firmware on sun5
-	 * systems to coordinate mmu mappings is also COMPLETELY
-	 * UNDOCUMENTED!!!!!! Thanks S(t)un!
-	 */
-	if (save_p) {
-		for (i = 0; i < 16; i++) {
-			prom_itlb[i].tlb_ent = -1;
-			prom_dtlb[i].tlb_ent = -1;
-		}
-	}
-	if (tlb_type == spitfire) {
-		int high = sparc64_highest_unlocked_tlb_ent;
-		for (i = 0; i <= high; i++) {
-			unsigned long data;
-
-			/* Spitfire Errata #32 workaround */
-			/* NOTE: Always runs on spitfire, so no cheetah+
-			 *       page size encodings.
-			 */
-			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
-					     "flush	%%g6"
-					     : /* No outputs */
-					     : "r" (0),
-					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
-
-			data = spitfire_get_dtlb_data(i);
-			if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
-				unsigned long tag;
-
-				/* Spitfire Errata #32 workaround */
-				/* NOTE: Always runs on spitfire, so no
-				 *       cheetah+ page size encodings.
-				 */
-				__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
-						     "flush	%%g6"
-						     : /* No outputs */
-						     : "r" (0),
-						     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
-
-				tag = spitfire_get_dtlb_tag(i);
-				if (save_p) {
-					prom_dtlb[dtlb_seen].tlb_ent = i;
-					prom_dtlb[dtlb_seen].tlb_tag = tag;
-					prom_dtlb[dtlb_seen].tlb_data = data;
-				}
-				__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
-						     "membar #Sync"
-						     : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
-				spitfire_put_dtlb_data(i, 0x0UL);
-
-				dtlb_seen++;
-				if (dtlb_seen > 15)
-					break;
-			}
-		}
-
-		for (i = 0; i < high; i++) {
-			unsigned long data;
-
-			/* Spitfire Errata #32 workaround */
-			/* NOTE: Always runs on spitfire, so no
-			 *       cheetah+ page size encodings.
-			 */
-			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
-					     "flush	%%g6"
-					     : /* No outputs */
-					     : "r" (0),
-					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
-
-			data = spitfire_get_itlb_data(i);
-			if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
-				unsigned long tag;
-
-				/* Spitfire Errata #32 workaround */
-				/* NOTE: Always runs on spitfire, so no
-				 *       cheetah+ page size encodings.
-				 */
-				__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
-						     "flush	%%g6"
-						     : /* No outputs */
-						     : "r" (0),
-						     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
-
-				tag = spitfire_get_itlb_tag(i);
-				if (save_p) {
-					prom_itlb[itlb_seen].tlb_ent = i;
-					prom_itlb[itlb_seen].tlb_tag = tag;
-					prom_itlb[itlb_seen].tlb_data = data;
-				}
-				__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
-						     "membar #Sync"
-						     : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
-				spitfire_put_itlb_data(i, 0x0UL);
-
-				itlb_seen++;
-				if (itlb_seen > 15)
-					break;
-			}
-		}
-	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
-		int high = sparc64_highest_unlocked_tlb_ent;
-
-		for (i = 0; i <= high; i++) {
-			unsigned long data;
-
-			data = cheetah_get_ldtlb_data(i);
-			if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
-				unsigned long tag;
-
-				tag = cheetah_get_ldtlb_tag(i);
-				if (save_p) {
-					prom_dtlb[dtlb_seen].tlb_ent = i;
-					prom_dtlb[dtlb_seen].tlb_tag = tag;
-					prom_dtlb[dtlb_seen].tlb_data = data;
-				}
-				__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
-						     "membar #Sync"
-						     : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
-				cheetah_put_ldtlb_data(i, 0x0UL);
-
-				dtlb_seen++;
-				if (dtlb_seen > 15)
-					break;
-			}
-		}
-
-		for (i = 0; i < high; i++) {
-			unsigned long data;
-
-			data = cheetah_get_litlb_data(i);
-			if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
-				unsigned long tag;
-
-				tag = cheetah_get_litlb_tag(i);
-				if (save_p) {
-					prom_itlb[itlb_seen].tlb_ent = i;
-					prom_itlb[itlb_seen].tlb_tag = tag;
-					prom_itlb[itlb_seen].tlb_data = data;
-				}
-				__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
-						     "membar #Sync"
-						     : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
-				cheetah_put_litlb_data(i, 0x0UL);
-
-				itlb_seen++;
-				if (itlb_seen > 15)
-					break;
-			}
-		}
-	} else {
-		/* Implement me :-) */
-		BUG();
-	}
-	if (save_p)
-		prom_ditlb_set = 1;
-}
-
-/* Give PROM back his world, done during reboots... */
-void prom_reload_locked(void)
-{
-	int i;
-
-	for (i = 0; i < 16; i++) {
-		if (prom_dtlb[i].tlb_ent != -1) {
-			__asm__ __volatile__("stxa %0, [%1] %2\n\t"
-					     "membar #Sync"
-				: : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
-				"i" (ASI_DMMU));
-			if (tlb_type == spitfire)
-				spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
-						       prom_dtlb[i].tlb_data);
-			else if (tlb_type == cheetah || tlb_type == cheetah_plus)
-				cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent,
-						      prom_dtlb[i].tlb_data);
-		}
-
-		if (prom_itlb[i].tlb_ent != -1) {
-			__asm__ __volatile__("stxa %0, [%1] %2\n\t"
-					     "membar #Sync"
-					     : : "r" (prom_itlb[i].tlb_tag),
-					     "r" (TLB_TAG_ACCESS),
-					     "i" (ASI_IMMU));
-			if (tlb_type == spitfire)
-				spitfire_put_itlb_data(prom_itlb[i].tlb_ent,
-						       prom_itlb[i].tlb_data);
-			else
-				cheetah_put_litlb_data(prom_itlb[i].tlb_ent,
-						       prom_itlb[i].tlb_data);
-		}
-	}
+	__asm__ __volatile__("flushw");
 }
 
 #ifdef DCACHE_ALIASING_POSSIBLE
@@ -914,7 +594,7 @@
 			if (++n >= 512)
 				break;
 		}
-	} else {
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
 		start = __pa(start);
 		end = __pa(end);
 		for (va = start; va < end; va += 32)
@@ -927,63 +607,6 @@
 }
 #endif /* DCACHE_ALIASING_POSSIBLE */
 
-/* If not locked, zap it. */
-void __flush_tlb_all(void)
-{
-	unsigned long pstate;
-	int i;
-
-	__asm__ __volatile__("flushw\n\t"
-			     "rdpr	%%pstate, %0\n\t"
-			     "wrpr	%0, %1, %%pstate"
-			     : "=r" (pstate)
-			     : "i" (PSTATE_IE));
-	if (tlb_type == spitfire) {
-		for (i = 0; i < 64; i++) {
-			/* Spitfire Errata #32 workaround */
-			/* NOTE: Always runs on spitfire, so no
-			 *       cheetah+ page size encodings.
-			 */
-			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
-					     "flush	%%g6"
-					     : /* No outputs */
-					     : "r" (0),
-					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
-
-			if (!(spitfire_get_dtlb_data(i) & _PAGE_L)) {
-				__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
-						     "membar #Sync"
-						     : /* no outputs */
-						     : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
-				spitfire_put_dtlb_data(i, 0x0UL);
-			}
-
-			/* Spitfire Errata #32 workaround */
-			/* NOTE: Always runs on spitfire, so no
-			 *       cheetah+ page size encodings.
-			 */
-			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
-					     "flush	%%g6"
-					     : /* No outputs */
-					     : "r" (0),
-					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
-
-			if (!(spitfire_get_itlb_data(i) & _PAGE_L)) {
-				__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
-						     "membar #Sync"
-						     : /* no outputs */
-						     : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
-				spitfire_put_itlb_data(i, 0x0UL);
-			}
-		}
-	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
-		cheetah_flush_dtlb_all();
-		cheetah_flush_itlb_all();
-	}
-	__asm__ __volatile__("wrpr	%0, 0, %%pstate"
-			     : : "r" (pstate));
-}
-
 /* Caller does TLB context flushing on local CPU if necessary.
  * The caller also ensures that CTX_VALID(mm->context) is false.
  *
@@ -1035,78 +658,6 @@
 	spin_unlock(&ctx_alloc_lock);
 }
 
-#ifndef CONFIG_SMP
-struct pgtable_cache_struct pgt_quicklists;
-#endif
-
-/* OK, we have to color these pages. The page tables are accessed
- * by non-Dcache enabled mapping in the VPTE area by the dtlb_backend.S
- * code, as well as by PAGE_OFFSET range direct-mapped addresses by 
- * other parts of the kernel. By coloring, we make sure that the tlbmiss 
- * fast handlers do not get data from old/garbage dcache lines that 
- * correspond to an old/stale virtual address (user/kernel) that 
- * previously mapped the pagetable page while accessing vpte range 
- * addresses. The idea is that if the vpte color and PAGE_OFFSET range 
- * color is the same, then when the kernel initializes the pagetable 
- * using the later address range, accesses with the first address
- * range will see the newly initialized data rather than the garbage.
- */
-#ifdef DCACHE_ALIASING_POSSIBLE
-#define DC_ALIAS_SHIFT	1
-#else
-#define DC_ALIAS_SHIFT	0
-#endif
-pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
-{
-	struct page *page;
-	unsigned long color;
-
-	{
-		pte_t *ptep = pte_alloc_one_fast(mm, address);
-
-		if (ptep)
-			return ptep;
-	}
-
-	color = VPTE_COLOR(address);
-	page = alloc_pages(GFP_KERNEL|__GFP_REPEAT, DC_ALIAS_SHIFT);
-	if (page) {
-		unsigned long *to_free;
-		unsigned long paddr;
-		pte_t *pte;
-
-#ifdef DCACHE_ALIASING_POSSIBLE
-		set_page_count(page, 1);
-		ClearPageCompound(page);
-
-		set_page_count((page + 1), 1);
-		ClearPageCompound(page + 1);
-#endif
-		paddr = (unsigned long) page_address(page);
-		memset((char *)paddr, 0, (PAGE_SIZE << DC_ALIAS_SHIFT));
-
-		if (!color) {
-			pte = (pte_t *) paddr;
-			to_free = (unsigned long *) (paddr + PAGE_SIZE);
-		} else {
-			pte = (pte_t *) (paddr + PAGE_SIZE);
-			to_free = (unsigned long *) paddr;
-		}
-
-#ifdef DCACHE_ALIASING_POSSIBLE
-		/* Now free the other one up, adjust cache size. */
-		preempt_disable();
-		*to_free = (unsigned long) pte_quicklist[color ^ 0x1];
-		pte_quicklist[color ^ 0x1] = to_free;
-		pgtable_cache_size++;
-		preempt_enable();
-#endif
-
-		return pte;
-	}
-	return NULL;
-}
-
 void sparc_ultra_dump_itlb(void)
 {
         int slot;
@@ -1419,6 +970,9 @@
 	kernel_map_range(phys_start, phys_end,
 			 (enable ? PAGE_KERNEL : __pgprot(0)));
 
+	flush_tsb_kernel_range(PAGE_OFFSET + phys_start,
+			       PAGE_OFFSET + phys_end);
+
 	/* we should perform an IPI and flush all tlbs,
 	 * but that can deadlock->flush only current cpu.
 	 */
@@ -1439,18 +993,139 @@
 	return ~0UL;
 }
 
+static void __init tsb_phys_patch(void)
+{
+	struct tsb_ldquad_phys_patch_entry *pquad;
+	struct tsb_phys_patch_entry *p;
+
+	pquad = &__tsb_ldquad_phys_patch;
+	while (pquad < &__tsb_ldquad_phys_patch_end) {
+		unsigned long addr = pquad->addr;
+
+		if (tlb_type == hypervisor)
+			*(unsigned int *) addr = pquad->sun4v_insn;
+		else
+			*(unsigned int *) addr = pquad->sun4u_insn;
+		wmb();
+		__asm__ __volatile__("flush	%0"
+				     : /* no outputs */
+				     : "r" (addr));
+
+		pquad++;
+	}
+
+	p = &__tsb_phys_patch;
+	while (p < &__tsb_phys_patch_end) {
+		unsigned long addr = p->addr;
+
+		*(unsigned int *) addr = p->insn;
+		wmb();
+		__asm__ __volatile__("flush	%0"
+				     : /* no outputs */
+				     : "r" (addr));
+
+		p++;
+	}
+}
+
+/* Don't mark as init, we give this to the Hypervisor.  */
+static struct hv_tsb_descr ktsb_descr[2];
+extern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES];
+
+static void __init sun4v_ktsb_init(void)
+{
+	unsigned long ktsb_pa;
+
+	ktsb_pa = kern_base + ((unsigned long)&swapper_tsb[0] - KERNBASE);
+
+	switch (PAGE_SIZE) {
+	case 8 * 1024:
+	default:
+		ktsb_descr[0].pgsz_idx = HV_PGSZ_IDX_8K;
+		ktsb_descr[0].pgsz_mask = HV_PGSZ_MASK_8K;
+		break;
+
+	case 64 * 1024:
+		ktsb_descr[0].pgsz_idx = HV_PGSZ_IDX_64K;
+		ktsb_descr[0].pgsz_mask = HV_PGSZ_MASK_64K;
+		break;
+
+	case 512 * 1024:
+		ktsb_descr[0].pgsz_idx = HV_PGSZ_IDX_512K;
+		ktsb_descr[0].pgsz_mask = HV_PGSZ_MASK_512K;
+		break;
+
+	case 4 * 1024 * 1024:
+		ktsb_descr[0].pgsz_idx = HV_PGSZ_IDX_4MB;
+		ktsb_descr[0].pgsz_mask = HV_PGSZ_MASK_4MB;
+		break;
+	};
+
+	ktsb_descr[0].assoc = 1;
+	ktsb_descr[0].num_ttes = KERNEL_TSB_NENTRIES;
+	ktsb_descr[0].ctx_idx = 0;
+	ktsb_descr[0].tsb_base = ktsb_pa;
+	ktsb_descr[0].resv = 0;
+
+	/* XXX When we have a kernel large page size TSB, describe
+	 * XXX it in ktsb_descr[1] here.
+	 */
+}
+
+void __cpuinit sun4v_ktsb_register(void)
+{
+	register unsigned long func asm("%o5");
+	register unsigned long arg0 asm("%o0");
+	register unsigned long arg1 asm("%o1");
+	unsigned long pa;
+
+	pa = kern_base + ((unsigned long)&ktsb_descr[0] - KERNBASE);
+
+	func = HV_FAST_MMU_TSB_CTX0;
+	/* XXX set arg0 to 2 when we use ktsb_descr[1], see above XXX */
+	arg0 = 1;
+	arg1 = pa;
+	__asm__ __volatile__("ta	%6"
+			     : "=&r" (func), "=&r" (arg0), "=&r" (arg1)
+			     : "0" (func), "1" (arg0), "2" (arg1),
+			       "i" (HV_FAST_TRAP));
+}
+
 /* paging_init() sets up the page tables */
 
 extern void cheetah_ecache_flush_init(void);
+extern void sun4v_patch_tlb_handlers(void);
 
 static unsigned long last_valid_pfn;
 pgd_t swapper_pg_dir[2048];
 
+static void sun4u_pgprot_init(void);
+static void sun4v_pgprot_init(void);
+
 void __init paging_init(void)
 {
 	unsigned long end_pfn, pages_avail, shift;
 	unsigned long real_end, i;
 
+	kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL;
+	kern_size = (unsigned long)&_end - (unsigned long)KERNBASE;
+
+	memset(swapper_tsb, 0x40, sizeof(swapper_tsb));
+
+	if (tlb_type == hypervisor)
+		sun4v_pgprot_init();
+	else
+		sun4u_pgprot_init();
+
+	if (tlb_type == cheetah_plus ||
+	    tlb_type == hypervisor)
+		tsb_phys_patch();
+
+	if (tlb_type == hypervisor) {
+		sun4v_patch_tlb_handlers();
+		sun4v_ktsb_init();
+	}
+
 	/* Find available physical memory... */
 	read_obp_memory("available", &pavail[0], &pavail_ents);
 
@@ -1460,9 +1135,6 @@
 
 	pfn_base = phys_base >> PAGE_SHIFT;
 
-	kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL;
-	kern_size = (unsigned long)&_end - (unsigned long)KERNBASE;
-
 	set_bit(0, mmu_context_bmap);
 
 	shift = kern_base + PAGE_OFFSET - ((unsigned long)KERNBASE);
@@ -1486,24 +1158,16 @@
 	pud_set(pud_offset(&swapper_pg_dir[0], 0),
 		swapper_low_pmd_dir + (shift / sizeof(pgd_t)));
 	
-	swapper_pgd_zero = pgd_val(swapper_pg_dir[0]);
-	
 	inherit_prom_mappings();
 	
-	/* Ok, we can use our TLB miss and window trap handlers safely.
-	 * We need to do a quick peek here to see if we are on StarFire
-	 * or not, so setup_tba can setup the IRQ globals correctly (it
-	 * needs to get the hard smp processor id correctly).
-	 */
-	{
-		extern void setup_tba(int);
-		setup_tba(this_is_starfire);
-	}
-
-	inherit_locked_prom_mappings(1);
+	/* Ok, we can use our TLB miss and window trap handlers safely.  */
+	setup_tba();
 
 	__flush_tlb_all();
 
+	if (tlb_type == hypervisor)
+		sun4v_ktsb_register();
+
 	/* Setup bootmem... */
 	pages_avail = 0;
 	last_valid_pfn = end_pfn = bootmem_init(&pages_avail);
@@ -1676,3 +1340,312 @@
 	}
 }
 #endif
+
+#define _PAGE_CACHE_4U	(_PAGE_CP_4U | _PAGE_CV_4U)
+#define _PAGE_CACHE_4V	(_PAGE_CP_4V | _PAGE_CV_4V)
+#define __DIRTY_BITS_4U	 (_PAGE_MODIFIED_4U | _PAGE_WRITE_4U | _PAGE_W_4U)
+#define __DIRTY_BITS_4V	 (_PAGE_MODIFIED_4V | _PAGE_WRITE_4V | _PAGE_W_4V)
+#define __ACCESS_BITS_4U (_PAGE_ACCESSED_4U | _PAGE_READ_4U | _PAGE_R)
+#define __ACCESS_BITS_4V (_PAGE_ACCESSED_4V | _PAGE_READ_4V | _PAGE_R)
+
+pgprot_t PAGE_KERNEL __read_mostly;
+EXPORT_SYMBOL(PAGE_KERNEL);
+
+pgprot_t PAGE_KERNEL_LOCKED __read_mostly;
+pgprot_t PAGE_COPY __read_mostly;
+
+pgprot_t PAGE_SHARED __read_mostly;
+EXPORT_SYMBOL(PAGE_SHARED);
+
+pgprot_t PAGE_EXEC __read_mostly;
+unsigned long pg_iobits __read_mostly;
+
+unsigned long _PAGE_IE __read_mostly;
+unsigned long _PAGE_E __read_mostly;
+unsigned long _PAGE_CACHE __read_mostly;
+
+static void prot_init_common(unsigned long page_none,
+			     unsigned long page_shared,
+			     unsigned long page_copy,
+			     unsigned long page_readonly,
+			     unsigned long page_exec_bit)
+{
+	PAGE_COPY = __pgprot(page_copy);
+	PAGE_SHARED = __pgprot(page_shared);
+
+	protection_map[0x0] = __pgprot(page_none);
+	protection_map[0x1] = __pgprot(page_readonly & ~page_exec_bit);
+	protection_map[0x2] = __pgprot(page_copy & ~page_exec_bit);
+	protection_map[0x3] = __pgprot(page_copy & ~page_exec_bit);
+	protection_map[0x4] = __pgprot(page_readonly);
+	protection_map[0x5] = __pgprot(page_readonly);
+	protection_map[0x6] = __pgprot(page_copy);
+	protection_map[0x7] = __pgprot(page_copy);
+	protection_map[0x8] = __pgprot(page_none);
+	protection_map[0x9] = __pgprot(page_readonly & ~page_exec_bit);
+	protection_map[0xa] = __pgprot(page_shared & ~page_exec_bit);
+	protection_map[0xb] = __pgprot(page_shared & ~page_exec_bit);
+	protection_map[0xc] = __pgprot(page_readonly);
+	protection_map[0xd] = __pgprot(page_readonly);
+	protection_map[0xe] = __pgprot(page_shared);
+	protection_map[0xf] = __pgprot(page_shared);
+}
+
+static void __init sun4u_pgprot_init(void)
+{
+	unsigned long page_none, page_shared, page_copy, page_readonly;
+	unsigned long page_exec_bit;
+
+	PAGE_KERNEL = __pgprot (_PAGE_PRESENT_4U | _PAGE_VALID |
+				_PAGE_CACHE_4U | _PAGE_P_4U |
+				__ACCESS_BITS_4U | __DIRTY_BITS_4U |
+				_PAGE_EXEC_4U);
+	PAGE_KERNEL_LOCKED = __pgprot (_PAGE_PRESENT_4U | _PAGE_VALID |
+				       _PAGE_CACHE_4U | _PAGE_P_4U |
+				       __ACCESS_BITS_4U | __DIRTY_BITS_4U |
+				       _PAGE_EXEC_4U | _PAGE_L_4U);
+	PAGE_EXEC = __pgprot(_PAGE_EXEC_4U);
+
+	_PAGE_IE = _PAGE_IE_4U;
+	_PAGE_E = _PAGE_E_4U;
+	_PAGE_CACHE = _PAGE_CACHE_4U;
+
+	pg_iobits = (_PAGE_VALID | _PAGE_PRESENT_4U | __DIRTY_BITS_4U |
+		     __ACCESS_BITS_4U | _PAGE_E_4U);
+
+	kern_linear_pte_xor = (_PAGE_VALID | _PAGE_SZ4MB_4U) ^
+		0xfffff80000000000;
+	kern_linear_pte_xor |= (_PAGE_CP_4U | _PAGE_CV_4U |
+				_PAGE_P_4U | _PAGE_W_4U);
+
+	_PAGE_SZBITS = _PAGE_SZBITS_4U;
+	_PAGE_ALL_SZ_BITS =  (_PAGE_SZ4MB_4U | _PAGE_SZ512K_4U |
+			      _PAGE_SZ64K_4U | _PAGE_SZ8K_4U |
+			      _PAGE_SZ32MB_4U | _PAGE_SZ256MB_4U);
+
+
+	page_none = _PAGE_PRESENT_4U | _PAGE_ACCESSED_4U | _PAGE_CACHE_4U;
+	page_shared = (_PAGE_VALID | _PAGE_PRESENT_4U | _PAGE_CACHE_4U |
+		       __ACCESS_BITS_4U | _PAGE_WRITE_4U | _PAGE_EXEC_4U);
+	page_copy   = (_PAGE_VALID | _PAGE_PRESENT_4U | _PAGE_CACHE_4U |
+		       __ACCESS_BITS_4U | _PAGE_EXEC_4U);
+	page_readonly   = (_PAGE_VALID | _PAGE_PRESENT_4U | _PAGE_CACHE_4U |
+			   __ACCESS_BITS_4U | _PAGE_EXEC_4U);
+
+	page_exec_bit = _PAGE_EXEC_4U;
+
+	prot_init_common(page_none, page_shared, page_copy, page_readonly,
+			 page_exec_bit);
+}
+
+static void __init sun4v_pgprot_init(void)
+{
+	unsigned long page_none, page_shared, page_copy, page_readonly;
+	unsigned long page_exec_bit;
+
+	PAGE_KERNEL = __pgprot (_PAGE_PRESENT_4V | _PAGE_VALID |
+				_PAGE_CACHE_4V | _PAGE_P_4V |
+				__ACCESS_BITS_4V | __DIRTY_BITS_4V |
+				_PAGE_EXEC_4V);
+	PAGE_KERNEL_LOCKED = PAGE_KERNEL;
+	PAGE_EXEC = __pgprot(_PAGE_EXEC_4V);
+
+	_PAGE_IE = _PAGE_IE_4V;
+	_PAGE_E = _PAGE_E_4V;
+	_PAGE_CACHE = _PAGE_CACHE_4V;
+
+	kern_linear_pte_xor = (_PAGE_VALID | _PAGE_SZ4MB_4V) ^
+		0xfffff80000000000;
+	kern_linear_pte_xor |= (_PAGE_CP_4V | _PAGE_CV_4V |
+				_PAGE_P_4V | _PAGE_W_4V);
+
+	pg_iobits = (_PAGE_VALID | _PAGE_PRESENT_4V | __DIRTY_BITS_4V |
+		     __ACCESS_BITS_4V | _PAGE_E_4V);
+
+	_PAGE_SZBITS = _PAGE_SZBITS_4V;
+	_PAGE_ALL_SZ_BITS = (_PAGE_SZ16GB_4V | _PAGE_SZ2GB_4V |
+			     _PAGE_SZ256MB_4V | _PAGE_SZ32MB_4V |
+			     _PAGE_SZ4MB_4V | _PAGE_SZ512K_4V |
+			     _PAGE_SZ64K_4V | _PAGE_SZ8K_4V);
+
+	page_none = _PAGE_PRESENT_4V | _PAGE_ACCESSED_4V | _PAGE_CACHE_4V;
+	page_shared = (_PAGE_VALID | _PAGE_PRESENT_4V | _PAGE_CACHE_4V |
+		       __ACCESS_BITS_4V | _PAGE_WRITE_4V | _PAGE_EXEC_4V);
+	page_copy   = (_PAGE_VALID | _PAGE_PRESENT_4V | _PAGE_CACHE_4V |
+		       __ACCESS_BITS_4V | _PAGE_EXEC_4V);
+	page_readonly = (_PAGE_VALID | _PAGE_PRESENT_4V | _PAGE_CACHE_4V |
+			 __ACCESS_BITS_4V | _PAGE_EXEC_4V);
+
+	page_exec_bit = _PAGE_EXEC_4V;
+
+	prot_init_common(page_none, page_shared, page_copy, page_readonly,
+			 page_exec_bit);
+}
+
+unsigned long pte_sz_bits(unsigned long sz)
+{
+	if (tlb_type == hypervisor) {
+		switch (sz) {
+		case 8 * 1024:
+		default:
+			return _PAGE_SZ8K_4V;
+		case 64 * 1024:
+			return _PAGE_SZ64K_4V;
+		case 512 * 1024:
+			return _PAGE_SZ512K_4V;
+		case 4 * 1024 * 1024:
+			return _PAGE_SZ4MB_4V;
+		};
+	} else {
+		switch (sz) {
+		case 8 * 1024:
+		default:
+			return _PAGE_SZ8K_4U;
+		case 64 * 1024:
+			return _PAGE_SZ64K_4U;
+		case 512 * 1024:
+			return _PAGE_SZ512K_4U;
+		case 4 * 1024 * 1024:
+			return _PAGE_SZ4MB_4U;
+		};
+	}
+}
+
+pte_t mk_pte_io(unsigned long page, pgprot_t prot, int space, unsigned long page_size)
+{
+	pte_t pte;
+
+	pte_val(pte)  = page | pgprot_val(pgprot_noncached(prot));
+	pte_val(pte) |= (((unsigned long)space) << 32);
+	pte_val(pte) |= pte_sz_bits(page_size);
+
+	return pte;
+}
+
+static unsigned long kern_large_tte(unsigned long paddr)
+{
+	unsigned long val;
+
+	val = (_PAGE_VALID | _PAGE_SZ4MB_4U |
+	       _PAGE_CP_4U | _PAGE_CV_4U | _PAGE_P_4U |
+	       _PAGE_EXEC_4U | _PAGE_L_4U | _PAGE_W_4U);
+	if (tlb_type == hypervisor)
+		val = (_PAGE_VALID | _PAGE_SZ4MB_4V |
+		       _PAGE_CP_4V | _PAGE_CV_4V | _PAGE_P_4V |
+		       _PAGE_EXEC_4V | _PAGE_W_4V);
+
+	return val | paddr;
+}
+
+/*
+ * Translate PROM's mapping we capture at boot time into physical address.
+ * The second parameter is only set from prom_callback() invocations.
+ */
+unsigned long prom_virt_to_phys(unsigned long promva, int *error)
+{
+	unsigned long mask;
+	int i;
+
+	mask = _PAGE_PADDR_4U;
+	if (tlb_type == hypervisor)
+		mask = _PAGE_PADDR_4V;
+
+	for (i = 0; i < prom_trans_ents; i++) {
+		struct linux_prom_translation *p = &prom_trans[i];
+
+		if (promva >= p->virt &&
+		    promva < (p->virt + p->size)) {
+			unsigned long base = p->data & mask;
+
+			if (error)
+				*error = 0;
+			return base + (promva & (8192 - 1));
+		}
+	}
+	if (error)
+		*error = 1;
+	return 0UL;
+}
+
+/* XXX We should kill off this ugly thing at so me point. XXX */
+unsigned long sun4u_get_pte(unsigned long addr)
+{
+	pgd_t *pgdp;
+	pud_t *pudp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+	unsigned long mask = _PAGE_PADDR_4U;
+
+	if (tlb_type == hypervisor)
+		mask = _PAGE_PADDR_4V;
+
+	if (addr >= PAGE_OFFSET)
+		return addr & mask;
+
+	if ((addr >= LOW_OBP_ADDRESS) && (addr < HI_OBP_ADDRESS))
+		return prom_virt_to_phys(addr, NULL);
+
+	pgdp = pgd_offset_k(addr);
+	pudp = pud_offset(pgdp, addr);
+	pmdp = pmd_offset(pudp, addr);
+	ptep = pte_offset_kernel(pmdp, addr);
+
+	return pte_val(*ptep) & mask;
+}
+
+/* If not locked, zap it. */
+void __flush_tlb_all(void)
+{
+	unsigned long pstate;
+	int i;
+
+	__asm__ __volatile__("flushw\n\t"
+			     "rdpr	%%pstate, %0\n\t"
+			     "wrpr	%0, %1, %%pstate"
+			     : "=r" (pstate)
+			     : "i" (PSTATE_IE));
+	if (tlb_type == spitfire) {
+		for (i = 0; i < 64; i++) {
+			/* Spitfire Errata #32 workaround */
+			/* NOTE: Always runs on spitfire, so no
+			 *       cheetah+ page size encodings.
+			 */
+			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+					     "flush	%%g6"
+					     : /* No outputs */
+					     : "r" (0),
+					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
+			if (!(spitfire_get_dtlb_data(i) & _PAGE_L_4U)) {
+				__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
+						     "membar #Sync"
+						     : /* no outputs */
+						     : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
+				spitfire_put_dtlb_data(i, 0x0UL);
+			}
+
+			/* Spitfire Errata #32 workaround */
+			/* NOTE: Always runs on spitfire, so no
+			 *       cheetah+ page size encodings.
+			 */
+			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+					     "flush	%%g6"
+					     : /* No outputs */
+					     : "r" (0),
+					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
+			if (!(spitfire_get_itlb_data(i) & _PAGE_L_4U)) {
+				__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
+						     "membar #Sync"
+						     : /* no outputs */
+						     : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
+				spitfire_put_itlb_data(i, 0x0UL);
+			}
+		}
+	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
+		cheetah_flush_dtlb_all();
+		cheetah_flush_itlb_all();
+	}
+	__asm__ __volatile__("wrpr	%0, 0, %%pstate"
+			     : : "r" (pstate));
+}
diff -urN oldtree/arch/sparc64/mm/tlb.c newtree/arch/sparc64/mm/tlb.c
--- oldtree/arch/sparc64/mm/tlb.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/mm/tlb.c	2006-02-21 15:58:20.377048776 +0000
@@ -25,6 +25,8 @@
 	struct mmu_gather *mp = &__get_cpu_var(mmu_gathers);
 
 	if (mp->tlb_nr) {
+		flush_tsb_user(mp);
+
 		if (CTX_VALID(mp->mm->context)) {
 #ifdef CONFIG_SMP
 			smp_flush_tlb_pending(mp->mm, mp->tlb_nr,
@@ -89,62 +91,3 @@
 	if (nr >= TLB_BATCH_NR)
 		flush_tlb_pending();
 }
-
-void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end)
-{
-	struct mmu_gather *mp = &__get_cpu_var(mmu_gathers);
-	unsigned long nr = mp->tlb_nr;
-	long s = start, e = end, vpte_base;
-
-	if (mp->fullmm)
-		return;
-
-	/* If start is greater than end, that is a real problem.  */
-	BUG_ON(start > end);
-
-	/* However, straddling the VA space hole is quite normal. */
-	s &= PMD_MASK;
-	e = (e + PMD_SIZE - 1) & PMD_MASK;
-
-	vpte_base = (tlb_type == spitfire ?
-		     VPTE_BASE_SPITFIRE :
-		     VPTE_BASE_CHEETAH);
-
-	if (unlikely(nr != 0 && mm != mp->mm)) {
-		flush_tlb_pending();
-		nr = 0;
-	}
-
-	if (nr == 0)
-		mp->mm = mm;
-
-	start = vpte_base + (s >> (PAGE_SHIFT - 3));
-	end = vpte_base + (e >> (PAGE_SHIFT - 3));
-
-	/* If the request straddles the VA space hole, we
-	 * need to swap start and end.  The reason this
-	 * occurs is that "vpte_base" is the center of
-	 * the linear page table mapping area.  Thus,
-	 * high addresses with the sign bit set map to
-	 * addresses below vpte_base and non-sign bit
-	 * addresses map to addresses above vpte_base.
-	 */
-	if (end < start) {
-		unsigned long tmp = start;
-
-		start = end;
-		end = tmp;
-	}
-
-	while (start < end) {
-		mp->vaddrs[nr] = start;
-		mp->tlb_nr = ++nr;
-		if (nr >= TLB_BATCH_NR) {
-			flush_tlb_pending();
-			nr = 0;
-		}
-		start += PAGE_SIZE;
-	}
-	if (nr)
-		flush_tlb_pending();
-}
diff -urN oldtree/arch/sparc64/mm/tsb.c newtree/arch/sparc64/mm/tsb.c
--- oldtree/arch/sparc64/mm/tsb.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/arch/sparc64/mm/tsb.c	2006-02-21 15:58:20.378048624 +0000
@@ -0,0 +1,394 @@
+/* arch/sparc64/mm/tsb.c
+ *
+ * Copyright (C) 2006 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <asm/system.h>
+#include <asm/page.h>
+#include <asm/tlbflush.h>
+#include <asm/tlb.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+#include <asm/tsb.h>
+
+extern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES];
+
+static inline unsigned long tsb_hash(unsigned long vaddr, unsigned long nentries)
+{
+	vaddr >>= PAGE_SHIFT;
+	return vaddr & (nentries - 1);
+}
+
+static inline int tag_compare(unsigned long tag, unsigned long vaddr)
+{
+	return (tag == (vaddr >> 22));
+}
+
+/* TSB flushes need only occur on the processor initiating the address
+ * space modification, not on each cpu the address space has run on.
+ * Only the TLB flush needs that treatment.
+ */
+
+void flush_tsb_kernel_range(unsigned long start, unsigned long end)
+{
+	unsigned long v;
+
+	for (v = start; v < end; v += PAGE_SIZE) {
+		unsigned long hash = tsb_hash(v, KERNEL_TSB_NENTRIES);
+		struct tsb *ent = &swapper_tsb[hash];
+
+		if (tag_compare(ent->tag, v)) {
+			ent->tag = (1UL << TSB_TAG_INVALID_BIT);
+			membar_storeload_storestore();
+		}
+	}
+}
+
+void flush_tsb_user(struct mmu_gather *mp)
+{
+	struct mm_struct *mm = mp->mm;
+	struct tsb *tsb = mm->context.tsb;
+	unsigned long nentries = mm->context.tsb_nentries;
+	unsigned long base;
+	int i;
+
+	if (tlb_type == cheetah_plus || tlb_type == hypervisor)
+		base = __pa(tsb);
+	else
+		base = (unsigned long) tsb;
+	
+	for (i = 0; i < mp->tlb_nr; i++) {
+		unsigned long v = mp->vaddrs[i];
+		unsigned long tag, ent, hash;
+
+		v &= ~0x1UL;
+
+		hash = tsb_hash(v, nentries);
+		ent = base + (hash * sizeof(struct tsb));
+		tag = (v >> 22UL);
+
+		tsb_flush(ent, tag);
+	}
+}
+
+static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_bytes)
+{
+	unsigned long tsb_reg, base, tsb_paddr;
+	unsigned long page_sz, tte;
+
+	mm->context.tsb_nentries = tsb_bytes / sizeof(struct tsb);
+
+	base = TSBMAP_BASE;
+	tte = pgprot_val(PAGE_KERNEL_LOCKED);
+	tsb_paddr = __pa(mm->context.tsb);
+	BUG_ON(tsb_paddr & (tsb_bytes - 1UL));
+
+	/* Use the smallest page size that can map the whole TSB
+	 * in one TLB entry.
+	 */
+	switch (tsb_bytes) {
+	case 8192 << 0:
+		tsb_reg = 0x0UL;
+#ifdef DCACHE_ALIASING_POSSIBLE
+		base += (tsb_paddr & 8192);
+#endif
+		page_sz = 8192;
+		break;
+
+	case 8192 << 1:
+		tsb_reg = 0x1UL;
+		page_sz = 64 * 1024;
+		break;
+
+	case 8192 << 2:
+		tsb_reg = 0x2UL;
+		page_sz = 64 * 1024;
+		break;
+
+	case 8192 << 3:
+		tsb_reg = 0x3UL;
+		page_sz = 64 * 1024;
+		break;
+
+	case 8192 << 4:
+		tsb_reg = 0x4UL;
+		page_sz = 512 * 1024;
+		break;
+
+	case 8192 << 5:
+		tsb_reg = 0x5UL;
+		page_sz = 512 * 1024;
+		break;
+
+	case 8192 << 6:
+		tsb_reg = 0x6UL;
+		page_sz = 512 * 1024;
+		break;
+
+	case 8192 << 7:
+		tsb_reg = 0x7UL;
+		page_sz = 4 * 1024 * 1024;
+		break;
+
+	default:
+		BUG();
+	};
+	tte |= pte_sz_bits(page_sz);
+
+	if (tlb_type == cheetah_plus || tlb_type == hypervisor) {
+		/* Physical mapping, no locked TLB entry for TSB.  */
+		tsb_reg |= tsb_paddr;
+
+		mm->context.tsb_reg_val = tsb_reg;
+		mm->context.tsb_map_vaddr = 0;
+		mm->context.tsb_map_pte = 0;
+	} else {
+		tsb_reg |= base;
+		tsb_reg |= (tsb_paddr & (page_sz - 1UL));
+		tte |= (tsb_paddr & ~(page_sz - 1UL));
+
+		mm->context.tsb_reg_val = tsb_reg;
+		mm->context.tsb_map_vaddr = base;
+		mm->context.tsb_map_pte = tte;
+	}
+
+	/* Setup the Hypervisor TSB descriptor.  */
+	if (tlb_type == hypervisor) {
+		struct hv_tsb_descr *hp = &mm->context.tsb_descr;
+
+		switch (PAGE_SIZE) {
+		case 8192:
+		default:
+			hp->pgsz_idx = HV_PGSZ_IDX_8K;
+			break;
+
+		case 64 * 1024:
+			hp->pgsz_idx = HV_PGSZ_IDX_64K;
+			break;
+
+		case 512 * 1024:
+			hp->pgsz_idx = HV_PGSZ_IDX_512K;
+			break;
+
+		case 4 * 1024 * 1024:
+			hp->pgsz_idx = HV_PGSZ_IDX_4MB;
+			break;
+		};
+		hp->assoc = 1;
+		hp->num_ttes = tsb_bytes / 16;
+		hp->ctx_idx = 0;
+		switch (PAGE_SIZE) {
+		case 8192:
+		default:
+			hp->pgsz_mask = HV_PGSZ_MASK_8K;
+			break;
+
+		case 64 * 1024:
+			hp->pgsz_mask = HV_PGSZ_MASK_64K;
+			break;
+
+		case 512 * 1024:
+			hp->pgsz_mask = HV_PGSZ_MASK_512K;
+			break;
+
+		case 4 * 1024 * 1024:
+			hp->pgsz_mask = HV_PGSZ_MASK_4MB;
+			break;
+		};
+		hp->tsb_base = tsb_paddr;
+		hp->resv = 0;
+	}
+}
+
+/* The page tables are locked against modifications while this
+ * runs.
+ *
+ * XXX do some prefetching...
+ */
+static void copy_tsb(struct tsb *old_tsb, unsigned long old_size,
+		     struct tsb *new_tsb, unsigned long new_size)
+{
+	unsigned long old_nentries = old_size / sizeof(struct tsb);
+	unsigned long new_nentries = new_size / sizeof(struct tsb);
+	unsigned long i;
+
+	for (i = 0; i < old_nentries; i++) {
+		register unsigned long tag asm("o4");
+		register unsigned long pte asm("o5");
+		unsigned long v, hash;
+
+		if (tlb_type == hypervisor) {
+			__asm__ __volatile__(
+				"ldda [%2] %3, %0"
+				: "=r" (tag), "=r" (pte)
+				: "r" (__pa(&old_tsb[i])),
+				  "i" (ASI_QUAD_LDD_PHYS_4V));
+		} else if (tlb_type == cheetah_plus) {
+			__asm__ __volatile__(
+				"ldda [%2] %3, %0"
+				: "=r" (tag), "=r" (pte)
+				: "r" (__pa(&old_tsb[i])),
+				  "i" (ASI_QUAD_LDD_PHYS));
+		} else {
+			__asm__ __volatile__(
+				"ldda [%2] %3, %0"
+				: "=r" (tag), "=r" (pte)
+				: "r" (&old_tsb[i]),
+				  "i" (ASI_NUCLEUS_QUAD_LDD));
+		}
+
+		if (tag & ((1UL << TSB_TAG_LOCK_BIT) |
+			   (1UL << TSB_TAG_INVALID_BIT)))
+			continue;
+
+		/* We only put base page size PTEs into the TSB,
+		 * but that might change in the future.  This code
+		 * would need to be changed if we start putting larger
+		 * page size PTEs into there.
+		 */
+		WARN_ON((pte & _PAGE_ALL_SZ_BITS) != _PAGE_SZBITS);
+
+		/* The tag holds bits 22 to 63 of the virtual address
+		 * and the context.  Clear out the context, and shift
+		 * up to make a virtual address.
+		 */
+		v = (tag & ((1UL << 42UL) - 1UL)) << 22UL;
+
+		/* The implied bits of the tag (bits 13 to 21) are
+		 * determined by the TSB entry index, so fill that in.
+		 */
+		v |= (i & (512UL - 1UL)) << 13UL;
+
+		hash = tsb_hash(v, new_nentries);
+		if (tlb_type == cheetah_plus ||
+		    tlb_type == hypervisor) {
+			__asm__ __volatile__(
+				"stxa	%0, [%1] %2\n\t"
+				"stxa	%3, [%4] %2"
+				: /* no outputs */
+				: "r" (tag),
+				  "r" (__pa(&new_tsb[hash].tag)),
+				  "i" (ASI_PHYS_USE_EC),
+				  "r" (pte),
+				  "r" (__pa(&new_tsb[hash].pte)));
+		} else {
+			new_tsb[hash].tag = tag;
+			new_tsb[hash].pte = pte;
+		}
+	}
+}
+
+/* When the RSS of an address space exceeds mm->context.tsb_rss_limit,
+ * update_mmu_cache() invokes this routine to try and grow the TSB.
+ * When we reach the maximum TSB size supported, we stick ~0UL into
+ * mm->context.tsb_rss_limit so the grow checks in update_mmu_cache()
+ * will not trigger any longer.
+ *
+ * The TSB can be anywhere from 8K to 1MB in size, in increasing powers
+ * of two.  The TSB must be aligned to it's size, so f.e. a 512K TSB
+ * must be 512K aligned.
+ *
+ * The idea here is to grow the TSB when the RSS of the process approaches
+ * the number of entries that the current TSB can hold at once.  Currently,
+ * we trigger when the RSS hits 3/4 of the TSB capacity.
+ */
+void tsb_grow(struct mm_struct *mm, unsigned long rss, gfp_t gfp_flags)
+{
+	unsigned long max_tsb_size = 1 * 1024 * 1024;
+	unsigned long size, old_size;
+	struct page *page;
+	struct tsb *old_tsb;
+
+	if (max_tsb_size > (PAGE_SIZE << MAX_ORDER))
+		max_tsb_size = (PAGE_SIZE << MAX_ORDER);
+
+	for (size = PAGE_SIZE; size < max_tsb_size; size <<= 1UL) {
+		unsigned long n_entries = size / sizeof(struct tsb);
+
+		n_entries = (n_entries * 3) / 4;
+		if (n_entries > rss)
+			break;
+	}
+
+	page = alloc_pages(gfp_flags, get_order(size));
+	if (unlikely(!page))
+		return;
+
+	/* Mark all tags as invalid.  */
+	memset(page_address(page), 0x40, size);
+
+	if (size == max_tsb_size)
+		mm->context.tsb_rss_limit = ~0UL;
+	else
+		mm->context.tsb_rss_limit =
+			((size / sizeof(struct tsb)) * 3) / 4;
+
+	old_tsb = mm->context.tsb;
+	old_size = mm->context.tsb_nentries * sizeof(struct tsb);
+
+	if (old_tsb)
+		copy_tsb(old_tsb, old_size, page_address(page), size);
+
+	mm->context.tsb = page_address(page);
+	setup_tsb_params(mm, size);
+
+	/* If old_tsb is NULL, we're being invoked for the first time
+	 * from init_new_context().
+	 */
+	if (old_tsb) {
+		/* Now force all other processors to reload the new
+		 * TSB state.
+		 */
+		smp_tsb_sync(mm);
+
+		/* Finally reload it on the local cpu.  No further
+		 * references will remain to the old TSB and we can
+		 * thus free it up.
+		 */
+		tsb_context_switch(mm);
+
+		free_pages((unsigned long) old_tsb, get_order(old_size));
+	}
+}
+
+int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+
+	mm->context.sparc64_ctx_val = 0UL;
+
+	/* copy_mm() copies over the parent's mm_struct before calling
+	 * us, so we need to zero out the TSB pointer or else tsb_grow()
+	 * will be confused and think there is an older TSB to free up.
+	 */
+	mm->context.tsb = NULL;
+	tsb_grow(mm, 0, GFP_KERNEL);
+
+	if (unlikely(!mm->context.tsb))
+		return -ENOMEM;
+
+	return 0;
+}
+
+void destroy_context(struct mm_struct *mm)
+{
+	unsigned long size = mm->context.tsb_nentries * sizeof(struct tsb);
+
+	free_pages((unsigned long) mm->context.tsb, get_order(size));
+
+	/* We can remove these later, but for now it's useful
+	 * to catch any bogus post-destroy_context() references
+	 * to the TSB.
+	 */
+	mm->context.tsb = NULL;
+	mm->context.tsb_reg_val = 0UL;
+
+	spin_lock(&ctx_alloc_lock);
+
+	if (CTX_VALID(mm->context)) {
+		unsigned long nr = CTX_NRBITS(mm->context);
+		mmu_context_bmap[nr>>6] &= ~(1UL << (nr & 63));
+	}
+
+	spin_unlock(&ctx_alloc_lock);
+}
diff -urN oldtree/arch/sparc64/mm/ultra.S newtree/arch/sparc64/mm/ultra.S
--- oldtree/arch/sparc64/mm/ultra.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/mm/ultra.S	2006-02-21 15:58:20.383047864 +0000
@@ -15,6 +15,7 @@
 #include <asm/head.h>
 #include <asm/thread_info.h>
 #include <asm/cacheflush.h>
+#include <asm/hypervisor.h>
 
 	/* Basically, most of the Spitfire vs. Cheetah madness
 	 * has to do with the fact that Cheetah does not support
@@ -29,16 +30,18 @@
 	.text
 	.align		32
 	.globl		__flush_tlb_mm
-__flush_tlb_mm: /* %o0=(ctx & TAG_CONTEXT_BITS), %o1=SECONDARY_CONTEXT */
+__flush_tlb_mm:		/* 18 insns */
+	/* %o0=(ctx & TAG_CONTEXT_BITS), %o1=SECONDARY_CONTEXT */
 	ldxa		[%o1] ASI_DMMU, %g2
 	cmp		%g2, %o0
 	bne,pn		%icc, __spitfire_flush_tlb_mm_slow
 	 mov		0x50, %g3
 	stxa		%g0, [%g3] ASI_DMMU_DEMAP
 	stxa		%g0, [%g3] ASI_IMMU_DEMAP
+	sethi		%hi(KERNBASE), %g3
+	flush		%g3
 	retl
-	 flush		%g6
-	nop
+	 nop
 	nop
 	nop
 	nop
@@ -51,7 +54,7 @@
 
 	.align		32
 	.globl		__flush_tlb_pending
-__flush_tlb_pending:
+__flush_tlb_pending:	/* 26 insns */
 	/* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
 	rdpr		%pstate, %g7
 	sllx		%o1, 3, %o1
@@ -72,7 +75,8 @@
 	brnz,pt		%o1, 1b
 	 nop
 	stxa		%g2, [%o4] ASI_DMMU
-	flush		%g6
+	sethi		%hi(KERNBASE), %o4
+	flush		%o4
 	retl
 	 wrpr		%g7, 0x0, %pstate
 	nop
@@ -82,7 +86,8 @@
 
 	.align		32
 	.globl		__flush_tlb_kernel_range
-__flush_tlb_kernel_range:	/* %o0=start, %o1=end */
+__flush_tlb_kernel_range:	/* 16 insns */
+	/* %o0=start, %o1=end */
 	cmp		%o0, %o1
 	be,pn		%xcc, 2f
 	 sethi		%hi(PAGE_SIZE), %o4
@@ -94,8 +99,11 @@
 	membar		#Sync
 	brnz,pt		%o3, 1b
 	 sub		%o3, %o4, %o3
-2:	retl
-	 flush		%g6
+2:	sethi		%hi(KERNBASE), %o3
+	flush		%o3
+	retl
+	 nop
+	nop
 
 __spitfire_flush_tlb_mm_slow:
 	rdpr		%pstate, %g1
@@ -105,7 +113,8 @@
 	stxa		%g0, [%g3] ASI_IMMU_DEMAP
 	flush		%g6
 	stxa		%g2, [%o1] ASI_DMMU
-	flush		%g6
+	sethi		%hi(KERNBASE), %o1
+	flush		%o1
 	retl
 	 wrpr		%g1, 0, %pstate
 
@@ -181,7 +190,7 @@
 	.previous
 
 	/* Cheetah specific versions, patched at boot time. */
-__cheetah_flush_tlb_mm: /* 18 insns */
+__cheetah_flush_tlb_mm: /* 19 insns */
 	rdpr		%pstate, %g7
 	andn		%g7, PSTATE_IE, %g2
 	wrpr		%g2, 0x0, %pstate
@@ -196,12 +205,13 @@
 	stxa		%g0, [%g3] ASI_DMMU_DEMAP
 	stxa		%g0, [%g3] ASI_IMMU_DEMAP
 	stxa		%g2, [%o2] ASI_DMMU
-	flush		%g6
+	sethi		%hi(KERNBASE), %o2
+	flush		%o2
 	wrpr		%g0, 0, %tl
 	retl
 	 wrpr		%g7, 0x0, %pstate
 
-__cheetah_flush_tlb_pending:	/* 26 insns */
+__cheetah_flush_tlb_pending:	/* 27 insns */
 	/* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
 	rdpr		%pstate, %g7
 	sllx		%o1, 3, %o1
@@ -225,7 +235,8 @@
 	brnz,pt		%o1, 1b
 	 nop
 	stxa		%g2, [%o4] ASI_DMMU
-	flush		%g6
+	sethi		%hi(KERNBASE), %o4
+	flush		%o4
 	wrpr		%g0, 0, %tl
 	retl
 	 wrpr		%g7, 0x0, %pstate
@@ -245,7 +256,63 @@
 	 nop
 #endif /* DCACHE_ALIASING_POSSIBLE */
 
-cheetah_patch_one:
+	/* Hypervisor specific versions, patched at boot time.  */
+__hypervisor_flush_tlb_mm: /* 8 insns */
+	mov		%o0, %o2	/* ARG2: mmu context */
+	mov		0, %o0		/* ARG0: CPU lists unimplemented */
+	mov		0, %o1		/* ARG1: CPU lists unimplemented */
+	mov		HV_MMU_ALL, %o3	/* ARG3: flags */
+	mov		HV_FAST_MMU_DEMAP_CTX, %o5
+	ta		HV_FAST_TRAP
+	retl
+	 nop
+
+__hypervisor_flush_tlb_pending: /* 15 insns */
+	/* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
+	sllx		%o1, 3, %g1
+	mov		%o2, %g2
+	mov		%o0, %g3
+1:	sub		%g1, (1 << 3), %g1
+	ldx		[%g2 + %g1], %o0      /* ARG0: vaddr + IMMU-bit */
+	mov		%g3, %o1	      /* ARG1: mmu context */
+	mov		HV_MMU_DMMU, %o2
+	andcc		%o0, 1, %g0
+	movne		%icc, HV_MMU_ALL, %o2 /* ARG2: flags */
+	andn		%o0, 1, %o0
+	ta		HV_MMU_UNMAP_ADDR_TRAP
+	brnz,pt		%g1, 1b
+	 nop
+	retl
+	 nop
+
+__hypervisor_flush_tlb_kernel_range: /* 14 insns */
+	/* %o0=start, %o1=end */
+	cmp		%o0, %o1
+	be,pn		%xcc, 2f
+	 sethi		%hi(PAGE_SIZE), %g3
+	mov		%o0, %g1
+	sub		%o1, %g1, %g2
+	sub		%g2, %g3, %g2
+1:	add		%g1, %g2, %o0	/* ARG0: virtual address */
+	mov		0, %o1		/* ARG1: mmu context */
+	mov		HV_MMU_ALL, %o2	/* ARG2: flags */
+	ta		HV_MMU_UNMAP_ADDR_TRAP
+	brnz,pt		%g2, 1b
+	 sub		%g2, %g3, %g2
+2:	retl
+	 nop
+
+#ifdef DCACHE_ALIASING_POSSIBLE
+	/* XXX Niagara and friends have an 8K cache, so no aliasing is
+	 * XXX possible, but nothing explicit in the Hypervisor API
+	 * XXX guarantees this.
+	 */
+__hypervisor_flush_dcache_page:	/* 2 insns */
+	retl
+	 nop
+#endif
+
+tlb_patch_one:
 1:	lduw		[%o1], %g1
 	stw		%g1, [%o0]
 	flush		%o0
@@ -264,22 +331,22 @@
 	or		%o0, %lo(__flush_tlb_mm), %o0
 	sethi		%hi(__cheetah_flush_tlb_mm), %o1
 	or		%o1, %lo(__cheetah_flush_tlb_mm), %o1
-	call		cheetah_patch_one
-	 mov		18, %o2
+	call		tlb_patch_one
+	 mov		19, %o2
 
 	sethi		%hi(__flush_tlb_pending), %o0
 	or		%o0, %lo(__flush_tlb_pending), %o0
 	sethi		%hi(__cheetah_flush_tlb_pending), %o1
 	or		%o1, %lo(__cheetah_flush_tlb_pending), %o1
-	call		cheetah_patch_one
-	 mov		26, %o2
+	call		tlb_patch_one
+	 mov		27, %o2
 
 #ifdef DCACHE_ALIASING_POSSIBLE
 	sethi		%hi(__flush_dcache_page), %o0
 	or		%o0, %lo(__flush_dcache_page), %o0
 	sethi		%hi(__cheetah_flush_dcache_page), %o1
 	or		%o1, %lo(__cheetah_flush_dcache_page), %o1
-	call		cheetah_patch_one
+	call		tlb_patch_one
 	 mov		11, %o2
 #endif /* DCACHE_ALIASING_POSSIBLE */
 
@@ -295,16 +362,14 @@
 	 *   %g1	address arg 1	(tlb page and range flushes)
 	 *   %g7	address arg 2	(tlb range flush only)
 	 *
-	 *   %g6	ivector table, don't touch
-	 *   %g2	scratch 1
-	 *   %g3	scratch 2
-	 *   %g4	scratch 3
-	 *
-	 * TODO: Make xcall TLB range flushes use the tricks above... -DaveM
+	 *   %g6	scratch 1
+	 *   %g2	scratch 2
+	 *   %g3	scratch 3
+	 *   %g4	scratch 4
 	 */
 	.align		32
 	.globl		xcall_flush_tlb_mm
-xcall_flush_tlb_mm:
+xcall_flush_tlb_mm:	/* 18 insns */
 	mov		PRIMARY_CONTEXT, %g2
 	ldxa		[%g2] ASI_DMMU, %g3
 	srlx		%g3, CTX_PGSZ1_NUC_SHIFT, %g4
@@ -316,9 +381,16 @@
 	stxa		%g0, [%g4] ASI_IMMU_DEMAP
 	stxa		%g3, [%g2] ASI_DMMU
 	retry
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
 
 	.globl		xcall_flush_tlb_pending
-xcall_flush_tlb_pending:
+xcall_flush_tlb_pending:	/* 20 insns */
 	/* %g5=context, %g1=nr, %g7=vaddrs[] */
 	sllx		%g1, 3, %g1
 	mov		PRIMARY_CONTEXT, %g4
@@ -343,7 +415,7 @@
 	retry
 
 	.globl		xcall_flush_tlb_kernel_range
-xcall_flush_tlb_kernel_range:
+xcall_flush_tlb_kernel_range:	/* 22 insns */
 	sethi		%hi(PAGE_SIZE - 1), %g2
 	or		%g2, %lo(PAGE_SIZE - 1), %g2
 	andn		%g1, %g2, %g1
@@ -360,14 +432,27 @@
 	retry
 	nop
 	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
 
 	/* This runs in a very controlled environment, so we do
 	 * not need to worry about BH races etc.
 	 */
 	.globl		xcall_sync_tick
 xcall_sync_tick:
-	rdpr		%pstate, %g2
+
+661:	rdpr		%pstate, %g2
 	wrpr		%g2, PSTATE_IG | PSTATE_AG, %pstate
+	.section	.sun4v_2insn_patch, "ax"
+	.word		661b
+	nop
+	nop
+	.previous
+
 	rdpr		%pil, %g2
 	wrpr		%g0, 15, %pil
 	sethi		%hi(109f), %g7
@@ -390,8 +475,15 @@
 	 */
 	.globl		xcall_report_regs
 xcall_report_regs:
-	rdpr		%pstate, %g2
+
+661:	rdpr		%pstate, %g2
 	wrpr		%g2, PSTATE_IG | PSTATE_AG, %pstate
+	.section	.sun4v_2insn_patch, "ax"
+	.word		661b
+	nop
+	nop
+	.previous
+
 	rdpr		%pil, %g2
 	wrpr		%g0, 15, %pil
 	sethi		%hi(109f), %g7
@@ -453,62 +545,74 @@
 	nop
 	nop
 
-	.data
-
-errata32_hwbug:
-	.xword	0
-
-	.text
-
-	/* These two are not performance critical... */
-	.globl		xcall_flush_tlb_all_spitfire
-xcall_flush_tlb_all_spitfire:
-	/* Spitfire Errata #32 workaround. */
-	sethi		%hi(errata32_hwbug), %g4
-	stx		%g0, [%g4 + %lo(errata32_hwbug)]
-
-	clr		%g2
-	clr		%g3
-1:	ldxa		[%g3] ASI_DTLB_DATA_ACCESS, %g4
-	and		%g4, _PAGE_L, %g5
-	brnz,pn		%g5, 2f
-	 mov		TLB_TAG_ACCESS, %g7
-
-	stxa		%g0, [%g7] ASI_DMMU
+	.globl		__hypervisor_xcall_flush_tlb_mm
+__hypervisor_xcall_flush_tlb_mm: /* 18 insns */
+	/* %g5=ctx, g1,g2,g3,g4,g7=scratch, %g6=unusable */
+	mov		%o0, %g2
+	mov		%o1, %g3
+	mov		%o2, %g4
+	mov		%o3, %g1
+	mov		%o5, %g7
+	clr		%o0		/* ARG0: CPU lists unimplemented */
+	clr		%o1		/* ARG1: CPU lists unimplemented */
+	mov		%g5, %o2	/* ARG2: mmu context */
+	mov		HV_MMU_ALL, %o3	/* ARG3: flags */
+	mov		HV_FAST_MMU_DEMAP_CTX, %o5
+	ta		HV_FAST_TRAP
+	mov		%g2, %o0
+	mov		%g3, %o1
+	mov		%g4, %o2
+	mov		%g1, %o3
+	mov		%g7, %o5
 	membar		#Sync
-	stxa		%g0, [%g3] ASI_DTLB_DATA_ACCESS
-	membar		#Sync
-
-	/* Spitfire Errata #32 workaround. */
-	sethi		%hi(errata32_hwbug), %g4
-	stx		%g0, [%g4 + %lo(errata32_hwbug)]
-
-2:	ldxa		[%g3] ASI_ITLB_DATA_ACCESS, %g4
-	and		%g4, _PAGE_L, %g5
-	brnz,pn		%g5, 2f
-	 mov		TLB_TAG_ACCESS, %g7
+	retry
 
-	stxa		%g0, [%g7] ASI_IMMU
-	membar		#Sync
-	stxa		%g0, [%g3] ASI_ITLB_DATA_ACCESS
+	.globl		__hypervisor_xcall_flush_tlb_pending
+__hypervisor_xcall_flush_tlb_pending: /* 18 insns */
+	/* %g5=ctx, %g1=nr, %g7=vaddrs[], %g2,%g3,%g4=scratch, %g6=unusable */
+	sllx		%g1, 3, %g1
+	mov		%o0, %g2
+	mov		%o1, %g3
+	mov		%o2, %g4
+1:	sub		%g1, (1 << 3), %g1
+	ldx		[%g7 + %g1], %o0	/* ARG0: virtual address */
+	mov		%g5, %o1		/* ARG1: mmu context */
+	mov		HV_MMU_DMMU, %o2
+	andcc		%o0, 1, %g0
+	movne		%icc, HV_MMU_ALL, %o2	/* ARG2: flags */
+	ta		HV_MMU_UNMAP_ADDR_TRAP
+	brnz,pt		%g1, 1b
+	 nop
+	mov		%g2, %o0
+	mov		%g3, %o1
+	mov		%g4, %o2
 	membar		#Sync
-
-	/* Spitfire Errata #32 workaround. */
-	sethi		%hi(errata32_hwbug), %g4
-	stx		%g0, [%g4 + %lo(errata32_hwbug)]
-
-2:	add		%g2, 1, %g2
-	cmp		%g2, SPITFIRE_HIGHEST_LOCKED_TLBENT
-	ble,pt		%icc, 1b
-	 sll		%g2, 3, %g3
-	flush		%g6
 	retry
 
-	.globl		xcall_flush_tlb_all_cheetah
-xcall_flush_tlb_all_cheetah:
-	mov		0x80, %g2
-	stxa		%g0, [%g2] ASI_DMMU_DEMAP
-	stxa		%g0, [%g2] ASI_IMMU_DEMAP
+	.globl		__hypervisor_xcall_flush_tlb_kernel_range
+__hypervisor_xcall_flush_tlb_kernel_range: /* 22 insns */
+	/* %g1=start, %g7=end, g2,g3,g4,g5=scratch, g6=unusable */
+	sethi		%hi(PAGE_SIZE - 1), %g2
+	or		%g2, %lo(PAGE_SIZE - 1), %g2
+	andn		%g1, %g2, %g1
+	andn		%g7, %g2, %g7
+	sub		%g7, %g1, %g3
+	add		%g2, 1, %g2
+	sub		%g3, %g2, %g3
+	mov		%o0, %g2
+	mov		%o1, %g4
+	mov		%o2, %g5
+1:	add		%g1, %g3, %o0	/* ARG0: virtual address */
+	mov		0, %o1		/* ARG1: mmu context */
+	mov		HV_MMU_ALL, %o2	/* ARG2: flags */
+	ta		HV_MMU_UNMAP_ADDR_TRAP
+	sethi		%hi(PAGE_SIZE), %o2
+	brnz,pt		%g3, 1b
+	 sub		%g3, %o2, %g3
+	mov		%g2, %o0
+	mov		%g4, %o1
+	mov		%g5, %o2
+	membar		#Sync
 	retry
 
 	/* These just get rescheduled to PIL vectors. */
@@ -528,3 +632,64 @@
 	retry
 
 #endif /* CONFIG_SMP */
+
+
+	.globl		hypervisor_patch_cachetlbops
+hypervisor_patch_cachetlbops:
+	save		%sp, -128, %sp
+
+	sethi		%hi(__flush_tlb_mm), %o0
+	or		%o0, %lo(__flush_tlb_mm), %o0
+	sethi		%hi(__hypervisor_flush_tlb_mm), %o1
+	or		%o1, %lo(__hypervisor_flush_tlb_mm), %o1
+	call		tlb_patch_one
+	 mov		8, %o2
+
+	sethi		%hi(__flush_tlb_pending), %o0
+	or		%o0, %lo(__flush_tlb_pending), %o0
+	sethi		%hi(__hypervisor_flush_tlb_pending), %o1
+	or		%o1, %lo(__hypervisor_flush_tlb_pending), %o1
+	call		tlb_patch_one
+	 mov		15, %o2
+
+	sethi		%hi(__flush_tlb_kernel_range), %o0
+	or		%o0, %lo(__flush_tlb_kernel_range), %o0
+	sethi		%hi(__hypervisor_flush_tlb_kernel_range), %o1
+	or		%o1, %lo(__hypervisor_flush_tlb_kernel_range), %o1
+	call		tlb_patch_one
+	 mov		14, %o2
+
+#ifdef DCACHE_ALIASING_POSSIBLE
+	sethi		%hi(__flush_dcache_page), %o0
+	or		%o0, %lo(__flush_dcache_page), %o0
+	sethi		%hi(__hypervisor_flush_dcache_page), %o1
+	or		%o1, %lo(__hypervisor_flush_dcache_page), %o1
+	call		tlb_patch_one
+	 mov		2, %o2
+#endif /* DCACHE_ALIASING_POSSIBLE */
+
+#ifdef CONFIG_SMP
+	sethi		%hi(xcall_flush_tlb_mm), %o0
+	or		%o0, %lo(xcall_flush_tlb_mm), %o0
+	sethi		%hi(__hypervisor_xcall_flush_tlb_mm), %o1
+	or		%o1, %lo(__hypervisor_xcall_flush_tlb_mm), %o1
+	call		tlb_patch_one
+	 mov		18, %o2
+
+	sethi		%hi(xcall_flush_tlb_pending), %o0
+	or		%o0, %lo(xcall_flush_tlb_pending), %o0
+	sethi		%hi(__hypervisor_xcall_flush_tlb_pending), %o1
+	or		%o1, %lo(__hypervisor_xcall_flush_tlb_pending), %o1
+	call		tlb_patch_one
+	 mov		18, %o2
+
+	sethi		%hi(xcall_flush_tlb_kernel_range), %o0
+	or		%o0, %lo(xcall_flush_tlb_kernel_range), %o0
+	sethi		%hi(__hypervisor_xcall_flush_tlb_kernel_range), %o1
+	or		%o1, %lo(__hypervisor_xcall_flush_tlb_kernel_range), %o1
+	call		tlb_patch_one
+	 mov		22, %o2
+#endif /* CONFIG_SMP */
+
+	ret
+	 restore
diff -urN oldtree/arch/sparc64/prom/cif.S newtree/arch/sparc64/prom/cif.S
--- oldtree/arch/sparc64/prom/cif.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/prom/cif.S	2006-02-21 15:58:20.396045888 +0000
@@ -1,10 +1,12 @@
 /* cif.S: PROM entry/exit assembler trampolines.
  *
- * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 2005 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 1996, 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 2005, 2006 David S. Miller <davem@davemloft.net>
  */
 
 #include <asm/pstate.h>
+#include <asm/cpudata.h>
+#include <asm/thread_info.h>
 
 	.text
 	.globl	prom_cif_interface
@@ -12,78 +14,16 @@
 	sethi	%hi(p1275buf), %o0
 	or	%o0, %lo(p1275buf), %o0
 	ldx	[%o0 + 0x010], %o1	! prom_cif_stack
-	save	%o1, -0x190, %sp
+	save	%o1, -192, %sp
 	ldx	[%i0 + 0x008], %l2	! prom_cif_handler
-	rdpr	%pstate, %l4
-	wrpr	%g0, 0x15, %pstate	! save alternate globals
-	stx	%g1, [%sp + 2047 + 0x0b0]
-	stx	%g2, [%sp + 2047 + 0x0b8]
-	stx	%g3, [%sp + 2047 + 0x0c0]
-	stx	%g4, [%sp + 2047 + 0x0c8]
-	stx	%g5, [%sp + 2047 + 0x0d0]
-	stx	%g6, [%sp + 2047 + 0x0d8]
-	stx	%g7, [%sp + 2047 + 0x0e0]
-	wrpr	%g0, 0x814, %pstate	! save interrupt globals
-	stx	%g1, [%sp + 2047 + 0x0e8]
-	stx	%g2, [%sp + 2047 + 0x0f0]
-	stx	%g3, [%sp + 2047 + 0x0f8]
-	stx	%g4, [%sp + 2047 + 0x100]
-	stx	%g5, [%sp + 2047 + 0x108]
-	stx	%g6, [%sp + 2047 + 0x110]
-	stx	%g7, [%sp + 2047 + 0x118]
-	wrpr	%g0, 0x14, %pstate	! save normal globals
-	stx	%g1, [%sp + 2047 + 0x120]
-	stx	%g2, [%sp + 2047 + 0x128]
-	stx	%g3, [%sp + 2047 + 0x130]
-	stx	%g4, [%sp + 2047 + 0x138]
-	stx	%g5, [%sp + 2047 + 0x140]
-	stx	%g6, [%sp + 2047 + 0x148]
-	stx	%g7, [%sp + 2047 + 0x150]
-	wrpr	%g0, 0x414, %pstate	! save mmu globals
-	stx	%g1, [%sp + 2047 + 0x158]
-	stx	%g2, [%sp + 2047 + 0x160]
-	stx	%g3, [%sp + 2047 + 0x168]
-	stx	%g4, [%sp + 2047 + 0x170]
-	stx	%g5, [%sp + 2047 + 0x178]
-	stx	%g6, [%sp + 2047 + 0x180]
-	stx	%g7, [%sp + 2047 + 0x188]
-	mov	%g1, %l0		! also save to locals, so we can handle
-	mov	%g2, %l1		! tlb faults later on, when accessing
-	mov	%g3, %l3		! the stack.
-	mov	%g7, %l5
-	wrpr	%l4, PSTATE_IE, %pstate	! turn off interrupts
+	mov	%g4, %l0
+	mov	%g5, %l1
+	mov	%g6, %l3
 	call	%l2
 	 add	%i0, 0x018, %o0		! prom_args
-	wrpr	%g0, 0x414, %pstate	! restore mmu globals
-	mov	%l0, %g1
-	mov	%l1, %g2
-	mov	%l3, %g3
-	mov	%l5, %g7
-	wrpr	%g0, 0x14, %pstate	! restore normal globals
-	ldx	[%sp + 2047 + 0x120], %g1
-	ldx	[%sp + 2047 + 0x128], %g2
-	ldx	[%sp + 2047 + 0x130], %g3
-	ldx	[%sp + 2047 + 0x138], %g4
-	ldx	[%sp + 2047 + 0x140], %g5
-	ldx	[%sp + 2047 + 0x148], %g6
-	ldx	[%sp + 2047 + 0x150], %g7
-	wrpr	%g0, 0x814, %pstate	! restore interrupt globals
-	ldx	[%sp + 2047 + 0x0e8], %g1
-	ldx	[%sp + 2047 + 0x0f0], %g2
-	ldx	[%sp + 2047 + 0x0f8], %g3
-	ldx	[%sp + 2047 + 0x100], %g4
-	ldx	[%sp + 2047 + 0x108], %g5
-	ldx	[%sp + 2047 + 0x110], %g6
-	ldx	[%sp + 2047 + 0x118], %g7
-	wrpr	%g0, 0x15, %pstate	! restore alternate globals
-	ldx	[%sp + 2047 + 0x0b0], %g1
-	ldx	[%sp + 2047 + 0x0b8], %g2
-	ldx	[%sp + 2047 + 0x0c0], %g3
-	ldx	[%sp + 2047 + 0x0c8], %g4
-	ldx	[%sp + 2047 + 0x0d0], %g5
-	ldx	[%sp + 2047 + 0x0d8], %g6
-	ldx	[%sp + 2047 + 0x0e0], %g7
-	wrpr	%l4, 0, %pstate	! restore original pstate
+	mov	%l0, %g4
+	mov	%l1, %g5
+	mov	%l3, %g6
 	ret
 	 restore
 
@@ -91,135 +31,18 @@
 prom_cif_callback:
 	sethi	%hi(p1275buf), %o1
 	or	%o1, %lo(p1275buf), %o1
-	save	%sp, -0x270, %sp
-	rdpr	%pstate, %l4
-	wrpr	%g0, 0x15, %pstate	! save PROM alternate globals
-	stx	%g1, [%sp + 2047 + 0x0b0]
-	stx	%g2, [%sp + 2047 + 0x0b8]
-	stx	%g3, [%sp + 2047 + 0x0c0]
-	stx	%g4, [%sp + 2047 + 0x0c8]
-	stx	%g5, [%sp + 2047 + 0x0d0]
-	stx	%g6, [%sp + 2047 + 0x0d8]
-	stx	%g7, [%sp + 2047 + 0x0e0]
-					! restore Linux alternate globals
-	ldx	[%sp + 2047 + 0x190], %g1
-	ldx	[%sp + 2047 + 0x198], %g2
-	ldx	[%sp + 2047 + 0x1a0], %g3
-	ldx	[%sp + 2047 + 0x1a8], %g4
-	ldx	[%sp + 2047 + 0x1b0], %g5
-	ldx	[%sp + 2047 + 0x1b8], %g6
-	ldx	[%sp + 2047 + 0x1c0], %g7
-	wrpr	%g0, 0x814, %pstate	! save PROM interrupt globals
-	stx	%g1, [%sp + 2047 + 0x0e8]
-	stx	%g2, [%sp + 2047 + 0x0f0]
-	stx	%g3, [%sp + 2047 + 0x0f8]
-	stx	%g4, [%sp + 2047 + 0x100]
-	stx	%g5, [%sp + 2047 + 0x108]
-	stx	%g6, [%sp + 2047 + 0x110]
-	stx	%g7, [%sp + 2047 + 0x118]
-					! restore Linux interrupt globals
-	ldx	[%sp + 2047 + 0x1c8], %g1
-	ldx	[%sp + 2047 + 0x1d0], %g2
-	ldx	[%sp + 2047 + 0x1d8], %g3
-	ldx	[%sp + 2047 + 0x1e0], %g4
-	ldx	[%sp + 2047 + 0x1e8], %g5
-	ldx	[%sp + 2047 + 0x1f0], %g6
-	ldx	[%sp + 2047 + 0x1f8], %g7
-	wrpr	%g0, 0x14, %pstate	! save PROM normal globals
-	stx	%g1, [%sp + 2047 + 0x120]
-	stx	%g2, [%sp + 2047 + 0x128]
-	stx	%g3, [%sp + 2047 + 0x130]
-	stx	%g4, [%sp + 2047 + 0x138]
-	stx	%g5, [%sp + 2047 + 0x140]
-	stx	%g6, [%sp + 2047 + 0x148]
-	stx	%g7, [%sp + 2047 + 0x150]
-					! restore Linux normal globals
-	ldx	[%sp + 2047 + 0x200], %g1
-	ldx	[%sp + 2047 + 0x208], %g2
-	ldx	[%sp + 2047 + 0x210], %g3
-	ldx	[%sp + 2047 + 0x218], %g4
-	ldx	[%sp + 2047 + 0x220], %g5
-	ldx	[%sp + 2047 + 0x228], %g6
-	ldx	[%sp + 2047 + 0x230], %g7
-	wrpr	%g0, 0x414, %pstate	! save PROM mmu globals
-	stx	%g1, [%sp + 2047 + 0x158]
-	stx	%g2, [%sp + 2047 + 0x160]
-	stx	%g3, [%sp + 2047 + 0x168]
-	stx	%g4, [%sp + 2047 + 0x170]
-	stx	%g5, [%sp + 2047 + 0x178]
-	stx	%g6, [%sp + 2047 + 0x180]
-	stx	%g7, [%sp + 2047 + 0x188]
-					! restore Linux mmu globals
-	ldx	[%sp + 2047 + 0x238], %o0
-	ldx	[%sp + 2047 + 0x240], %o1
-	ldx	[%sp + 2047 + 0x248], %l2
-	ldx	[%sp + 2047 + 0x250], %l3
-	ldx	[%sp + 2047 + 0x258], %l5
-	ldx	[%sp + 2047 + 0x260], %l6
-	ldx	[%sp + 2047 + 0x268], %l7
-					! switch to Linux tba
-	sethi	%hi(sparc64_ttable_tl0), %l1
-	rdpr	%tba, %l0		! save PROM tba
-	mov	%o0, %g1
-	mov	%o1, %g2
-	mov	%l2, %g3
-	mov	%l3, %g4
-	mov	%l5, %g5
-	mov	%l6, %g6
-	mov	%l7, %g7
-	wrpr	%l1, %tba		! install Linux tba
-	wrpr	%l4, 0, %pstate		! restore PSTATE
+	save	%sp, -192, %sp
+	TRAP_LOAD_THREAD_REG(%g6, %g1)
+	LOAD_PER_CPU_BASE(%g5, %g6, %g4, %g3, %o0)
+	ldx	[%g6 + TI_TASK], %g4
 	call	prom_world
-	 mov	%g0, %o0
+	 mov	0, %o0
 	ldx	[%i1 + 0x000], %l2
 	call	%l2
 	 mov	%i0, %o0
 	mov	%o0, %l1
 	call	prom_world
-	 or	%g0, 1, %o0
-	wrpr	%g0, 0x14, %pstate	! interrupts off
-					! restore PROM mmu globals
-	ldx	[%sp + 2047 + 0x158], %o0
-	ldx	[%sp + 2047 + 0x160], %o1
-	ldx	[%sp + 2047 + 0x168], %l2
-	ldx	[%sp + 2047 + 0x170], %l3
-	ldx	[%sp + 2047 + 0x178], %l5
-	ldx	[%sp + 2047 + 0x180], %l6
-	ldx	[%sp + 2047 + 0x188], %l7
-	wrpr	%g0, 0x414, %pstate	! restore PROM mmu globals
-	mov	%o0, %g1
-	mov	%o1, %g2
-	mov	%l2, %g3
-	mov	%l3, %g4
-	mov	%l5, %g5
-	mov	%l6, %g6
-	mov	%l7, %g7
-	wrpr	%l0, %tba		! restore PROM tba
-	wrpr	%g0, 0x14, %pstate	! restore PROM normal globals
-	ldx	[%sp + 2047 + 0x120], %g1
-	ldx	[%sp + 2047 + 0x128], %g2
-	ldx	[%sp + 2047 + 0x130], %g3
-	ldx	[%sp + 2047 + 0x138], %g4
-	ldx	[%sp + 2047 + 0x140], %g5
-	ldx	[%sp + 2047 + 0x148], %g6
-	ldx	[%sp + 2047 + 0x150], %g7
-	wrpr	%g0, 0x814, %pstate	! restore PROM interrupt globals
-	ldx	[%sp + 2047 + 0x0e8], %g1
-	ldx	[%sp + 2047 + 0x0f0], %g2
-	ldx	[%sp + 2047 + 0x0f8], %g3
-	ldx	[%sp + 2047 + 0x100], %g4
-	ldx	[%sp + 2047 + 0x108], %g5
-	ldx	[%sp + 2047 + 0x110], %g6
-	ldx	[%sp + 2047 + 0x118], %g7
-	wrpr	%g0, 0x15, %pstate	! restore PROM alternate globals
-	ldx	[%sp + 2047 + 0x0b0], %g1
-	ldx	[%sp + 2047 + 0x0b8], %g2
-	ldx	[%sp + 2047 + 0x0c0], %g3
-	ldx	[%sp + 2047 + 0x0c8], %g4
-	ldx	[%sp + 2047 + 0x0d0], %g5
-	ldx	[%sp + 2047 + 0x0d8], %g6
-	ldx	[%sp + 2047 + 0x0e0], %g7
-	wrpr	%l4, 0, %pstate
+	 mov	1, %o0
 	ret
 	 restore %l1, 0, %o0
 
diff -urN oldtree/arch/sparc64/prom/console.c newtree/arch/sparc64/prom/console.c
--- oldtree/arch/sparc64/prom/console.c	2006-02-19 11:41:00.163318272 +0000
+++ newtree/arch/sparc64/prom/console.c	2006-02-21 15:58:20.398045584 +0000
@@ -102,6 +102,9 @@
 	if (!strncmp (propb, "rsc", 3))
 		return PROMDEV_IRSC;
 
+	if (!strncmp (propb, "virtual-console", 3))
+		return PROMDEV_IVCONS;
+
 	if (strncmp (propb, "tty", 3) || !propb[3])
 		return PROMDEV_I_UNK;
 
@@ -143,6 +146,9 @@
 	if (!strncmp (propb, "rsc", 3))
 		return PROMDEV_ORSC;
 
+	if (!strncmp (propb, "virtual-console", 3))
+		return PROMDEV_OVCONS;
+
 	if (strncmp (propb, "tty", 3) || !propb[3])
 		return PROMDEV_O_UNK;
 
diff -urN oldtree/arch/sparc64/prom/init.c newtree/arch/sparc64/prom/init.c
--- oldtree/arch/sparc64/prom/init.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/prom/init.c	2006-02-21 15:58:20.400045280 +0000
@@ -18,7 +18,6 @@
 unsigned int prom_rev, prom_prev;
 
 /* The root node of the prom device tree. */
-int prom_root_node;
 int prom_stdin, prom_stdout;
 int prom_chosen_node;
 
@@ -41,26 +40,22 @@
 
 	prom_cif_init(cif_handler, cif_stack);
 
-	prom_root_node = prom_getsibling(0);
-	if((prom_root_node == 0) || (prom_root_node == -1))
-		prom_halt();
-
 	prom_chosen_node = prom_finddevice(prom_chosen_path);
 	if (!prom_chosen_node || prom_chosen_node == -1)
 		prom_halt();
 
-	prom_stdin = prom_getint (prom_chosen_node, "stdin");
-	prom_stdout = prom_getint (prom_chosen_node, "stdout");
+	prom_stdin = prom_getint(prom_chosen_node, "stdin");
+	prom_stdout = prom_getint(prom_chosen_node, "stdout");
 
 	node = prom_finddevice("/openprom");
 	if (!node || node == -1)
 		prom_halt();
 
-	prom_getstring (node, "version", buffer, sizeof (buffer));
+	prom_getstring(node, "version", buffer, sizeof (buffer));
 
-	prom_printf ("\n");
+	prom_printf("\n");
 
-	if (strncmp (buffer, "OBP ", 4))
+	if (strncmp(buffer, "OBP ", 4))
 		goto strange_version;
 
 	/*
@@ -70,7 +65,7 @@
 	 * accordingly. -spot
 	 */
 
-	if (strncmp (buffer, "OBP  ", 5))
+	if (strncmp(buffer, "OBP  ", 5))
 		bufadjust = 4;
 	else
 		bufadjust = 5;
@@ -87,7 +82,8 @@
 	prom_rev = ints[1];
 	prom_prev = (ints[0] << 16) | (ints[1] << 8) | ints[2];
 
-	printk ("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + bufadjust);
+	printk("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + bufadjust);
+	printk("PROMLIB: Root node compatible: %s\n", prom_root_compatible);
 
 	/* Initialization successful. */
 	return;
diff -urN oldtree/arch/sparc64/prom/misc.c newtree/arch/sparc64/prom/misc.c
--- oldtree/arch/sparc64/prom/misc.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/prom/misc.c	2006-02-21 15:58:20.437039656 +0000
@@ -136,6 +136,11 @@
 	p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba);
 }
 
+void prom_set_trap_table_sun4v(unsigned long tba, unsigned long mmfsa)
+{
+	p1275_cmd("SUNW,set-trap-table", P1275_INOUT(2, 0), tba, mmfsa);
+}
+
 int prom_get_mmu_ihandle(void)
 {
 	int node, ret;
@@ -303,9 +308,21 @@
 }
 
 #ifdef CONFIG_SMP
-void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0)
+void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg)
+{
+	p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, arg);
+}
+
+void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg)
+{
+	p1275_cmd("SUNW,start-cpu-by-cpuid", P1275_INOUT(3, 0),
+		  cpuid, pc, arg);
+}
+
+void prom_stopcpu_cpuid(int cpuid)
 {
-	p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, o0);
+	p1275_cmd("SUNW,stop-cpu-by-cpuid", P1275_INOUT(1, 0),
+		  cpuid);
 }
 
 void prom_stopself(void)
diff -urN oldtree/arch/sparc64/prom/p1275.c newtree/arch/sparc64/prom/p1275.c
--- oldtree/arch/sparc64/prom/p1275.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/prom/p1275.c	2006-02-21 15:58:20.438039504 +0000
@@ -30,16 +30,6 @@
 extern void prom_cif_interface(void);
 extern void prom_cif_callback(void);
 
-static inline unsigned long spitfire_get_primary_context(void)
-{
-	unsigned long ctx;
-
-	__asm__ __volatile__("ldxa	[%1] %2, %0"
-			     : "=r" (ctx)
-			     : "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
-	return ctx;
-}
-
 /*
  * This provides SMP safety on the p1275buf. prom_callback() drops this lock
  * to allow recursuve acquisition.
@@ -55,7 +45,6 @@
 	long attrs, x;
 	
 	p = p1275buf.prom_buffer;
-	BUG_ON((spitfire_get_primary_context() & CTX_NR_MASK) != 0);
 
 	spin_lock_irqsave(&prom_entry_lock, flags);
 
diff -urN oldtree/arch/sparc64/prom/tree.c newtree/arch/sparc64/prom/tree.c
--- oldtree/arch/sparc64/prom/tree.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/sparc64/prom/tree.c	2006-02-21 15:58:20.439039352 +0000
@@ -51,7 +51,7 @@
 __inline__ int
 __prom_getsibling(int node)
 {
-	return p1275_cmd ("peer", P1275_INOUT(1, 1), node);
+	return p1275_cmd(prom_peer_name, P1275_INOUT(1, 1), node);
 }
 
 __inline__ int
@@ -59,9 +59,12 @@
 {
 	int sibnode;
 
-	if(node == -1) return 0;
+	if (node == -1)
+		return 0;
 	sibnode = __prom_getsibling(node);
-	if(sibnode == -1) return 0;
+	if (sibnode == -1)
+		return 0;
+
 	return sibnode;
 }
 
diff -urN oldtree/arch/um/Kconfig newtree/arch/um/Kconfig
--- oldtree/arch/um/Kconfig	2006-02-19 11:41:00.165317968 +0000
+++ newtree/arch/um/Kconfig	2006-02-21 15:58:36.232638360 +0000
@@ -22,6 +22,9 @@
 config PCI
 	bool
 
+config PCMCIA
+	bool
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
diff -urN oldtree/arch/um/Makefile newtree/arch/um/Makefile
--- oldtree/arch/um/Makefile	2006-02-19 11:41:00.166317816 +0000
+++ newtree/arch/um/Makefile	2006-02-21 15:58:36.245636384 +0000
@@ -126,7 +126,7 @@
 	-DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \
 	-DELF_FORMAT="$(ELF_FORMAT)" $(CPP_MODE-y) \
 	-DKERNEL_STACK_SIZE=$(STACK_SIZE) \
-	-DUNMAP_PATH=arch/um/sys-$(SUBARCH)/unmap_fin.o
+	-DUNMAP_PATH=arch/um/sys-$(SUBARCH)/unmap.o
 
 #The wrappers will select whether using "malloc" or the kernel allocator.
 LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
@@ -147,8 +147,7 @@
 	$(ARCH_DIR)/include/user_constants.h \
 	$(ARCH_DIR)/include/kern_constants.h $(ARCH_DIR)/Kconfig.arch
 
-MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \
-	$(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) $(ARCH_DIR)/os
+MRPROPER_FILES += $(ARCH_SYMLINKS)
 
 archclean:
 	@find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \
diff -urN oldtree/arch/um/Makefile-x86_64 newtree/arch/um/Makefile-x86_64
--- oldtree/arch/um/Makefile-x86_64	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/um/Makefile-x86_64	2006-02-21 15:58:36.245636384 +0000
@@ -1,7 +1,7 @@
 # Copyright 2003 - 2004 Pathscale, Inc
 # Released under the GPL
 
-libs-y += arch/um/sys-x86_64/
+core-y += arch/um/sys-x86_64/
 START := 0x60000000
 
 #We #undef __x86_64__ for kernelspace, not for userspace where
diff -urN oldtree/arch/um/drivers/harddog_kern.c newtree/arch/um/drivers/harddog_kern.c
--- oldtree/arch/um/drivers/harddog_kern.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/um/drivers/harddog_kern.c	2006-02-21 15:58:36.225639424 +0000
@@ -104,7 +104,7 @@
 
 extern int ping_watchdog(int fd);
 
-static ssize_t harddog_write(struct file *file, const char *data, size_t len,
+static ssize_t harddog_write(struct file *file, const char __user *data, size_t len,
 			     loff_t *ppos)
 {
 	/*
@@ -118,6 +118,7 @@
 static int harddog_ioctl(struct inode *inode, struct file *file,
 			 unsigned int cmd, unsigned long arg)
 {
+	void __user *argp= (void __user *)arg;
 	static struct watchdog_info ident = {
 		WDIOC_SETTIMEOUT,
 		0,
@@ -127,13 +128,12 @@
 		default:
 			return -ENOTTY;
 		case WDIOC_GETSUPPORT:
-			if(copy_to_user((struct harddog_info *)arg, &ident,
-					sizeof(ident)))
+			if(copy_to_user(argp, &ident, sizeof(ident)))
 				return -EFAULT;
 			return 0;
 		case WDIOC_GETSTATUS:
 		case WDIOC_GETBOOTSTATUS:
-			return put_user(0,(int *)arg);
+			return put_user(0,(int __user *)argp);
 		case WDIOC_KEEPALIVE:
 			return(ping_watchdog(harddog_out_fd));
 	}
diff -urN oldtree/arch/um/drivers/hostaudio_kern.c newtree/arch/um/drivers/hostaudio_kern.c
--- oldtree/arch/um/drivers/hostaudio_kern.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/um/drivers/hostaudio_kern.c	2006-02-21 15:58:36.226639272 +0000
@@ -67,7 +67,7 @@
 
 /* /dev/dsp file operations */
 
-static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count, 
+static ssize_t hostaudio_read(struct file *file, char __user *buffer, size_t count, 
 			      loff_t *ppos)
 {
         struct hostaudio_state *state = file->private_data;
@@ -94,7 +94,7 @@
 	return(err);
 }
 
-static ssize_t hostaudio_write(struct file *file, const char *buffer, 
+static ssize_t hostaudio_write(struct file *file, const char __user *buffer, 
 			       size_t count, loff_t *ppos)
 {
         struct hostaudio_state *state = file->private_data;
@@ -152,7 +152,7 @@
 	case SNDCTL_DSP_CHANNELS:
 	case SNDCTL_DSP_SUBDIVIDE:
 	case SNDCTL_DSP_SETFRAGMENT:
-		if(get_user(data, (int *) arg))
+		if(get_user(data, (int __user *) arg))
 			return(-EFAULT);
 		break;
 	default:
@@ -168,7 +168,7 @@
 	case SNDCTL_DSP_CHANNELS:
 	case SNDCTL_DSP_SUBDIVIDE:
 	case SNDCTL_DSP_SETFRAGMENT:
-		if(put_user(data, (int *) arg))
+		if(put_user(data, (int __user *) arg))
 			return(-EFAULT);
 		break;
 	default:
diff -urN oldtree/arch/um/drivers/mconsole_kern.c newtree/arch/um/drivers/mconsole_kern.c
--- oldtree/arch/um/drivers/mconsole_kern.c	2006-02-19 11:41:00.253304592 +0000
+++ newtree/arch/um/drivers/mconsole_kern.c	2006-02-21 15:58:36.227639120 +0000
@@ -478,7 +478,7 @@
 		return;
 
 	while(1){
-		n = min(len, ARRAY_SIZE(console_buf) - console_index);
+		n = min((size_t)len, ARRAY_SIZE(console_buf) - console_index);
 		strncpy(&console_buf[console_index], string, n);
 		console_index += n;
 		string += n;
diff -urN oldtree/arch/um/drivers/slirp_kern.c newtree/arch/um/drivers/slirp_kern.c
--- oldtree/arch/um/drivers/slirp_kern.c	2006-02-19 11:41:00.255304288 +0000
+++ newtree/arch/um/drivers/slirp_kern.c	2006-02-21 15:58:36.228638968 +0000
@@ -77,7 +77,7 @@
 	int i=0;
 
 	*init = ((struct slirp_init)
-		{ argw :		{ { "slirp", NULL  } } });
+		{ .argw = { { "slirp", NULL  } } });
 
 	str = split_if_spec(str, mac_out, NULL);
 
diff -urN oldtree/arch/um/include/line.h newtree/arch/um/include/line.h
--- oldtree/arch/um/include/line.h	2006-02-19 11:41:00.260303528 +0000
+++ newtree/arch/um/include/line.h	2006-02-21 15:58:36.229638816 +0000
@@ -58,23 +58,17 @@
 };
 
 #define LINE_INIT(str, d) \
-	{ init_str :	str, \
-	  init_pri :	INIT_STATIC, \
-	  valid :	1, \
-	  throttled :	0, \
-	  lock :	SPIN_LOCK_UNLOCKED, \
-	  buffer :	NULL, \
-	  head :	NULL, \
-	  tail :	NULL, \
-	  sigio :	0, \
-	  driver :	d, \
-	  have_irq :	0 }
+	{ .init_str =	str, \
+	  .init_pri =	INIT_STATIC, \
+	  .valid =	1, \
+	  .lock =	SPIN_LOCK_UNLOCKED, \
+ 	  .driver =	d }
 
 struct lines {
 	int num;
 };
 
-#define LINES_INIT(n) {  num :		n }
+#define LINES_INIT(n) {  .num =	n }
 
 extern void line_close(struct tty_struct *tty, struct file * filp);
 extern int line_open(struct line *lines, struct tty_struct *tty);
diff -urN oldtree/arch/um/include/sysdep-i386/checksum.h newtree/arch/um/include/sysdep-i386/checksum.h
--- oldtree/arch/um/include/sysdep-i386/checksum.h	2006-02-19 11:41:00.264302920 +0000
+++ newtree/arch/um/include/sysdep-i386/checksum.h	2006-02-21 15:58:36.229638816 +0000
@@ -48,7 +48,8 @@
  */
 
 static __inline__
-unsigned int csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst,
+unsigned int csum_partial_copy_from_user(const unsigned char __user *src,
+					 unsigned char *dst,
 					 int len, int sum, int *err_ptr)
 {
 	if(copy_from_user(dst, src, len)){
@@ -192,7 +193,7 @@
  */
 #define HAVE_CSUM_COPY_USER
 static __inline__ unsigned int csum_and_copy_to_user(const unsigned char *src,
-						     unsigned char *dst,
+						     unsigned char __user *dst,
 						     int len, int sum, int *err_ptr)
 {
 	if (access_ok(VERIFY_WRITE, dst, len)){
diff -urN oldtree/arch/um/kernel/exec_kern.c newtree/arch/um/kernel/exec_kern.c
--- oldtree/arch/um/kernel/exec_kern.c	2006-02-19 11:41:00.269302160 +0000
+++ newtree/arch/um/kernel/exec_kern.c	2006-02-21 15:58:36.242636840 +0000
@@ -60,14 +60,14 @@
 	return(err);
 }
 
-long sys_execve(char *file, char __user *__user *argv,
+long sys_execve(char __user *file, char __user *__user *argv,
 		char __user *__user *env)
 {
 	long error;
 	char *filename;
 
 	lock_kernel();
-	filename = getname((char __user *) file);
+	filename = getname(file);
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename)) goto out;
 	error = execve1(filename, argv, env);
diff -urN oldtree/arch/um/kernel/process_kern.c newtree/arch/um/kernel/process_kern.c
--- oldtree/arch/um/kernel/process_kern.c	2006-02-19 11:41:00.317294864 +0000
+++ newtree/arch/um/kernel/process_kern.c	2006-02-21 15:58:36.243636688 +0000
@@ -407,7 +407,7 @@
 	return strlen(buf);
 }
 
-static int proc_write_sysemu(struct file *file,const char *buf, unsigned long count,void *data)
+static int proc_write_sysemu(struct file *file,const char __user *buf, unsigned long count,void *data)
 {
 	char tmp[2];
 
diff -urN oldtree/arch/um/kernel/ptrace.c newtree/arch/um/kernel/ptrace.c
--- oldtree/arch/um/kernel/ptrace.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/um/kernel/ptrace.c	2006-02-21 15:58:36.243636688 +0000
@@ -46,6 +46,7 @@
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
 	int i, ret;
+	unsigned long __user *p = (void __user *)(unsigned long)data;
 
 	switch (request) {
 		/* when I and D space are separate, these will need to be fixed. */
@@ -58,7 +59,7 @@
 		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
 		if (copied != sizeof(tmp))
 			break;
-		ret = put_user(tmp, (unsigned long __user *) data);
+		ret = put_user(tmp, p);
 		break;
 	}
 
@@ -136,15 +137,13 @@
 
 #ifdef PTRACE_GETREGS
 	case PTRACE_GETREGS: { /* Get all gp regs from the child. */
-	  	if (!access_ok(VERIFY_WRITE, (unsigned long *)data, 
-			       MAX_REG_OFFSET)) {
+	  	if (!access_ok(VERIFY_WRITE, p, MAX_REG_OFFSET)) {
 			ret = -EIO;
 			break;
 		}
 		for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
-			__put_user(getreg(child, i),
-				   (unsigned long __user *) data);
-			data += sizeof(long);
+			__put_user(getreg(child, i), p);
+			p++;
 		}
 		ret = 0;
 		break;
@@ -153,15 +152,14 @@
 #ifdef PTRACE_SETREGS
 	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
 		unsigned long tmp = 0;
-	  	if (!access_ok(VERIFY_READ, (unsigned *)data, 
-			       MAX_REG_OFFSET)) {
+	  	if (!access_ok(VERIFY_READ, p, MAX_REG_OFFSET)) {
 			ret = -EIO;
 			break;
 		}
 		for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
-			__get_user(tmp, (unsigned long __user *) data);
+			__get_user(tmp, p);
 			putreg(child, i, tmp);
-			data += sizeof(long);
+			p++;
 		}
 		ret = 0;
 		break;
@@ -192,8 +190,7 @@
                  * but transfer max. sizeof(struct ptrace_faultinfo).
                  * On i386, ptrace_faultinfo is smaller!
                  */
-                ret = copy_to_user((unsigned long __user *) data,
-                                   &child->thread.arch.faultinfo,
+                ret = copy_to_user(p, &child->thread.arch.faultinfo,
                                    sizeof(struct ptrace_faultinfo));
 		if(ret)
 			break;
@@ -204,8 +201,7 @@
 	case PTRACE_LDT: {
 		struct ptrace_ldt ldt;
 
-		if(copy_from_user(&ldt, (unsigned long __user *) data,
-				  sizeof(ldt))){
+		if(copy_from_user(&ldt, p, sizeof(ldt))){
 			ret = -EIO;
 			break;
 		}
diff -urN oldtree/arch/um/kernel/syscall_kern.c newtree/arch/um/kernel/syscall_kern.c
--- oldtree/arch/um/kernel/syscall_kern.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/um/kernel/syscall_kern.c	2006-02-21 15:58:36.244636536 +0000
@@ -104,7 +104,7 @@
 }
 
 
-long sys_uname(struct old_utsname * name)
+long sys_uname(struct old_utsname __user * name)
 {
 	long err;
 	if (!name)
@@ -115,7 +115,7 @@
 	return err?-EFAULT:0;
 }
 
-long sys_olduname(struct oldold_utsname * name)
+long sys_olduname(struct oldold_utsname __user * name)
 {
 	long error;
 
diff -urN oldtree/arch/um/kernel/trap_kern.c newtree/arch/um/kernel/trap_kern.c
--- oldtree/arch/um/kernel/trap_kern.c	2006-02-19 11:41:00.335292128 +0000
+++ newtree/arch/um/kernel/trap_kern.c	2006-02-21 15:58:36.245636384 +0000
@@ -198,7 +198,7 @@
 		si.si_signo = SIGBUS;
 		si.si_errno = 0;
 		si.si_code = BUS_ADRERR;
-		si.si_addr = (void *)address;
+		si.si_addr = (void __user *)address;
                 current->thread.arch.faultinfo = fi;
 		force_sig_info(SIGBUS, &si, current);
 	} else if (err == -ENOMEM) {
@@ -207,7 +207,7 @@
 	} else {
 		BUG_ON(err != -EFAULT);
 		si.si_signo = SIGSEGV;
-		si.si_addr = (void *) address;
+		si.si_addr = (void __user *) address;
                 current->thread.arch.faultinfo = fi;
 		force_sig_info(SIGSEGV, &si, current);
 	}
@@ -220,7 +220,7 @@
 
 	si.si_signo = SIGSEGV;
 	si.si_code = SEGV_ACCERR;
-        si.si_addr = (void *) FAULT_ADDRESS(fi);
+        si.si_addr = (void __user *) FAULT_ADDRESS(fi);
         current->thread.arch.faultinfo = fi;
 	force_sig_info(SIGSEGV, &si, current);
 }
diff -urN oldtree/arch/um/os-Linux/Makefile newtree/arch/um/os-Linux/Makefile
--- oldtree/arch/um/os-Linux/Makefile	2006-02-19 11:41:00.342291064 +0000
+++ newtree/arch/um/os-Linux/Makefile	2006-02-21 15:58:36.246636232 +0000
@@ -12,9 +12,6 @@
 USER_OBJS := aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \
 	start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o util.o
 
-elf_aux.o: $(ARCH_DIR)/kernel-offsets.h
-CFLAGS_elf_aux.o += -I$(objtree)/arch/um
-
 CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH)
 
 HAVE_AIO_ABI := $(shell [ -r /usr/include/linux/aio_abi.h ] && \
diff -urN oldtree/arch/um/scripts/Makefile.rules newtree/arch/um/scripts/Makefile.rules
--- oldtree/arch/um/scripts/Makefile.rules	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/um/scripts/Makefile.rules	2006-02-21 15:58:36.246636232 +0000
@@ -20,25 +20,7 @@
 	$(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1)))
 endef
 
-
-# cmd_make_link checks to see if the $(foo-dir) variable starts with a /.  If
-# so, it's considered to be a path relative to $(srcdir) rather than
-# $(srcdir)/arch/$(SUBARCH).  This is because x86_64 wants to get ldt.c from
-# arch/um/sys-i386 rather than arch/i386 like the other borrowed files.  So,
-# it sets $(ldt.c-dir) to /arch/um/sys-i386.
-quiet_cmd_make_link = SYMLINK $@
-cmd_make_link       = rm -f $@; ln -sf $(srctree)$(if $(filter-out /%,$($(notdir $@)-dir)),/arch/$(SUBARCH))/$($(notdir $@)-dir)/$(notdir $@) $@
-
-# this needs to be before the foreach, because targets does not accept
-# complete paths like $(obj)/$(f). To make sure this works, use a := assignment
-# or we will get $(obj)/$(f) in the "targets" value.
-# Also, this forces you to use the := syntax when assigning to targets.
-# Otherwise the line below will cause an infinite loop (if you don't know why,
-# just do it).
-
-targets := $(targets) $(SYMLINKS)
-
-SYMLINKS := $(foreach f,$(SYMLINKS),$(obj)/$(f))
-
-$(SYMLINKS): FORCE
-	$(call if_changed,make_link)
+ifdef subarch-obj-y
+obj-y += subarch.o
+subarch-y = $(addprefix ../../$(SUBARCH)/,$(subarch-obj-y))
+endif
diff -urN oldtree/arch/um/scripts/Makefile.unmap newtree/arch/um/scripts/Makefile.unmap
--- oldtree/arch/um/scripts/Makefile.unmap	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/um/scripts/Makefile.unmap	1970-01-01 00:00:00.000000000 +0000
@@ -1,22 +0,0 @@
-clean-files += unmap_tmp.o unmap_fin.o unmap.o
-
-ifdef CONFIG_MODE_TT
-
-#Always build unmap_fin.o
-extra-y += unmap_fin.o
-#Do dependency tracking for unmap.o (it will be always built, but won't get the tracking unless we use this).
-targets += unmap.o
-
-#XXX: partially copied from arch/um/scripts/Makefile.rules
-$(obj)/unmap.o: _c_flags = $(call unprofile,$(CFLAGS))
-
-quiet_cmd_wrapld = LD      $@
-define cmd_wrapld
-	$(LD) $(LDFLAGS) -r -o $(obj)/unmap_tmp.o $< ; \
-	$(OBJCOPY) $(UML_OBJCOPYFLAGS) $(obj)/unmap_tmp.o $@ -G switcheroo
-endef
-
-$(obj)/unmap_fin.o : $(obj)/unmap.o FORCE
-	$(call if_changed,wrapld)
-
-endif
diff -urN oldtree/arch/um/sys-i386/Makefile newtree/arch/um/sys-i386/Makefile
--- oldtree/arch/um/sys-i386/Makefile	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/um/sys-i386/Makefile	2006-02-21 15:58:36.247636080 +0000
@@ -1,23 +1,17 @@
-obj-y := bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
-	ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o \
-	sys_call_table.o
+obj-y = bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
+	ptrace_user.o signal.o sigcontext.o syscalls.o sysrq.o sys_call_table.o
 
 obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
 
-obj-$(CONFIG_HIGHMEM) += highmem.o
-obj-$(CONFIG_MODULES) += module.o
+subarch-obj-y = lib/bitops.o kernel/semaphore.o
+subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem.o
+subarch-obj-$(CONFIG_MODULES) += kernel/module.o
 
 USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o stub_segv.o
 
-SYMLINKS = bitops.c semaphore.c highmem.c module.c
-
 include arch/um/scripts/Makefile.rules
 
-bitops.c-dir = lib
-semaphore.c-dir = kernel
-highmem.c-dir = mm
-module.c-dir = kernel
-
-$(obj)/stub_segv.o : _c_flags = $(call unprofile,$(CFLAGS))
+extra-$(CONFIG_MODE_TT) += unmap.o
 
-include arch/um/scripts/Makefile.unmap
+$(obj)/stub_segv.o $(obj)/unmap.o: \
+	_c_flags = $(call unprofile,$(CFLAGS))
diff -urN oldtree/arch/um/sys-i386/ptrace.c newtree/arch/um/sys-i386/ptrace.c
--- oldtree/arch/um/sys-i386/ptrace.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/um/sys-i386/ptrace.c	2006-02-21 15:58:36.250635624 +0000
@@ -130,7 +130,7 @@
                 addr = addr >> 2;
                 tmp = child->thread.arch.debugregs[addr];
         }
-        return put_user(tmp, (unsigned long *) data);
+        return put_user(tmp, (unsigned long __user *) data);
 }
 
 struct i387_fxsave_struct {
diff -urN oldtree/arch/um/sys-i386/signal.c newtree/arch/um/sys-i386/signal.c
--- oldtree/arch/um/sys-i386/signal.c	2006-02-19 11:41:00.401282096 +0000
+++ newtree/arch/um/sys-i386/signal.c	2006-02-21 15:58:36.252635320 +0000
@@ -19,7 +19,7 @@
 #include "skas.h"
 
 static int copy_sc_from_user_skas(struct pt_regs *regs,
-				  struct sigcontext *from)
+				  struct sigcontext __user *from)
 {
   	struct sigcontext sc;
 	unsigned long fpregs[HOST_FP_SIZE];
@@ -57,7 +57,7 @@
 	return(0);
 }
 
-int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp,
+int copy_sc_to_user_skas(struct sigcontext __user *to, struct _fpstate __user *to_fp,
                          struct pt_regs *regs)
 {
   	struct sigcontext sc;
@@ -92,7 +92,7 @@
 		       "errno = %d\n", err);
 		return(1);
 	}
-	to_fp = (to_fp ? to_fp : (struct _fpstate *) (to + 1));
+	to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (to + 1));
 	sc.fpstate = to_fp;
 
 	if(err)
@@ -113,10 +113,11 @@
  * saved pointer is in the kernel, but the sigcontext is in userspace, so we
  * copy_to_user it.
  */
-int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from,
+int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext __user *from,
 			 int fpsize)
 {
-	struct _fpstate *to_fp, *from_fp;
+	struct _fpstate *to_fp;
+	struct _fpstate __user *from_fp;
 	unsigned long sigs;
 	int err;
 
@@ -131,13 +132,14 @@
 	return(err);
 }
 
-int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp,
+int copy_sc_to_user_tt(struct sigcontext __user *to, struct _fpstate __user *fp,
 		       struct sigcontext *from, int fpsize)
 {
-	struct _fpstate *to_fp, *from_fp;
+	struct _fpstate __user *to_fp;
+	struct _fpstate *from_fp;
 	int err;
 
-	to_fp =	(fp ? fp : (struct _fpstate *) (to + 1));
+	to_fp =	(fp ? fp : (struct _fpstate __user *) (to + 1));
 	from_fp = from->fpstate;
 	err = copy_to_user(to, from, sizeof(*to));
 	if(from_fp != NULL){
@@ -158,7 +160,7 @@
 	return(ret);
 }
 
-static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp,
+static int copy_sc_to_user(struct sigcontext __user *to, struct _fpstate __user *fp,
 			   struct pt_regs *from)
 {
 	return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs),
@@ -166,7 +168,7 @@
                            copy_sc_to_user_skas(to, fp, from)));
 }
 
-static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp,
+static int copy_ucontext_to_user(struct ucontext __user *uc, struct _fpstate __user *fp,
 				 sigset_t *set, unsigned long sp)
 {
 	int err = 0;
@@ -181,7 +183,7 @@
 
 struct sigframe
 {
-	char *pretcode;
+	char __user *pretcode;
 	int sig;
 	struct sigcontext sc;
 	struct _fpstate fpstate;
@@ -191,10 +193,10 @@
 
 struct rt_sigframe
 {
-	char *pretcode;
+	char __user *pretcode;
 	int sig;
-	struct siginfo *pinfo;
-	void *puc;
+	struct siginfo __user *pinfo;
+	void __user *puc;
 	struct siginfo info;
 	struct ucontext uc;
 	struct _fpstate fpstate;
@@ -206,15 +208,15 @@
 			  sigset_t *mask)
 {
 	struct sigframe __user *frame;
-	void *restorer;
+	void __user *restorer;
 	int err = 0;
 
 	stack_top &= -8UL;
-	frame = (struct sigframe *) stack_top - 1;
+	frame = (struct sigframe __user *) stack_top - 1;
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 		return 1;
 
-	restorer = (void *) frame->retcode;
+	restorer = frame->retcode;
 	if(ka->sa.sa_flags & SA_RESTORER)
 		restorer = ka->sa.sa_restorer;
 
@@ -256,15 +258,15 @@
 			  siginfo_t *info, sigset_t *mask)
 {
 	struct rt_sigframe __user *frame;
-	void *restorer;
+	void __user *restorer;
 	int err = 0;
 
 	stack_top &= -8UL;
-	frame = (struct rt_sigframe *) stack_top - 1;
+	frame = (struct rt_sigframe __user *) stack_top - 1;
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 		return 1;
 
-	restorer = (void *) frame->retcode;
+	restorer = frame->retcode;
 	if(ka->sa.sa_flags & SA_RESTORER)
 		restorer = ka->sa.sa_restorer;
 
@@ -304,7 +306,7 @@
 long sys_sigreturn(struct pt_regs regs)
 {
 	unsigned long sp = PT_REGS_SP(&current->thread.regs);
-	struct sigframe __user *frame = (struct sigframe *)(sp - 8);
+	struct sigframe __user *frame = (struct sigframe __user *)(sp - 8);
 	sigset_t set;
 	struct sigcontext __user *sc = &frame->sc;
 	unsigned long __user *oldmask = &sc->oldmask;
@@ -336,8 +338,8 @@
 
 long sys_rt_sigreturn(struct pt_regs regs)
 {
-	unsigned long __user sp = PT_REGS_SP(&current->thread.regs);
-	struct rt_sigframe __user *frame = (struct rt_sigframe *) (sp - 4);
+	unsigned long sp = PT_REGS_SP(&current->thread.regs);
+	struct rt_sigframe __user *frame = (struct rt_sigframe __user *) (sp - 4);
 	sigset_t set;
 	struct ucontext __user *uc = &frame->uc;
 	int sig_size = _NSIG_WORDS * sizeof(unsigned long);
diff -urN oldtree/arch/um/sys-i386/syscalls.c newtree/arch/um/sys-i386/syscalls.c
--- oldtree/arch/um/sys-i386/syscalls.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/um/sys-i386/syscalls.c	2006-02-21 15:58:36.252635320 +0000
@@ -104,7 +104,7 @@
 		union semun fourth;
 		if (!ptr)
 			return -EINVAL;
-		if (get_user(fourth.__pad, (void **) ptr))
+		if (get_user(fourth.__pad, (void __user * __user *) ptr))
 			return -EFAULT;
 		return sys_semctl (first, second, third, fourth);
 	}
diff -urN oldtree/arch/um/sys-x86_64/Makefile newtree/arch/um/sys-x86_64/Makefile
--- oldtree/arch/um/sys-x86_64/Makefile	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/um/sys-x86_64/Makefile	2006-02-21 15:58:36.253635168 +0000
@@ -4,31 +4,22 @@
 # Licensed under the GPL
 #
 
-#XXX: why into lib-y?
-lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o ldt.o mem.o memcpy.o \
-	ptrace.o ptrace_user.o sigcontext.o signal.o syscalls.o \
-	syscall_table.o sysrq.o thunk.o
-lib-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
+obj-y = bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \
+	sigcontext.o signal.o syscalls.o syscall_table.o sysrq.o ksyms.o
 
-obj-y := ksyms.o
-obj-$(CONFIG_MODULES) += module.o um_module.o
+obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
+obj-$(CONFIG_MODULES) += um_module.o
 
-USER_OBJS := ptrace_user.o sigcontext.o stub_segv.o
+subarch-obj-y = lib/bitops.o lib/csum-partial.o lib/memcpy.o lib/thunk.o
+subarch-obj-$(CONFIG_MODULES) += kernel/module.o
 
-SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c ldt.c memcpy.S \
-	thunk.S module.c
+ldt-y = ../sys-i386/ldt.o
 
-include arch/um/scripts/Makefile.rules
+USER_OBJS := ptrace_user.o sigcontext.o stub_segv.o
 
-bitops.c-dir = lib
-csum-copy.S-dir = lib
-csum-partial.c-dir = lib
-csum-wrappers.c-dir = lib
-ldt.c-dir = /arch/um/sys-i386
-memcpy.S-dir = lib
-thunk.S-dir = lib
-module.c-dir = kernel
+include arch/um/scripts/Makefile.rules
 
-$(obj)/stub_segv.o: _c_flags = $(call unprofile,$(CFLAGS))
+extra-$(CONFIG_MODE_TT) += unmap.o
 
-include arch/um/scripts/Makefile.unmap
+$(obj)/stub_segv.o $(obj)/unmap.o: \
+	_c_flags = $(call unprofile,$(CFLAGS))
diff -urN oldtree/arch/v850/kernel/vmlinux.lds.S newtree/arch/v850/kernel/vmlinux.lds.S
--- oldtree/arch/v850/kernel/vmlinux.lds.S	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/v850/kernel/vmlinux.lds.S	2006-02-21 15:58:12.687217808 +0000
@@ -64,6 +64,10 @@
 		___start___ksymtab_gpl = .;				      \
 			*(__ksymtab_gpl)				      \
 		___stop___ksymtab_gpl = .;				      \
+		/* Kernel symbol table: GPL-future symbols */		      \
+		___start___ksymtab_gpl_future = .;			      \
+			*(__ksymtab_gpl_future)				      \
+		___stop___ksymtab_gpl_future = .;			      \
 		/* Kernel symbol table: strings */			      \
 			*(__ksymtab_strings)				      \
 		/* Kernel symbol table: Normal symbols */		      \
@@ -74,6 +78,10 @@
 		___start___kcrctab_gpl = .;				      \
 			*(__kcrctab_gpl)				      \
 		___stop___kcrctab_gpl = .;				      \
+		/* Kernel symbol table: GPL-future symbols */		      \
+		___start___kcrctab_gpl_future = .;			      \
+			*(__kcrctab_gpl_future)				      \
+		___stop___kcrctab_gpl_future = .;			      \
 		/* Built-in module parameters */			      \
 		. = ALIGN (4) ;						      \
 		___start___param = .;					      \
diff -urN oldtree/arch/x86_64/kernel/acpi/Makefile newtree/arch/x86_64/kernel/acpi/Makefile
--- oldtree/arch/x86_64/kernel/acpi/Makefile	2006-02-19 11:41:00.417279664 +0000
+++ newtree/arch/x86_64/kernel/acpi/Makefile	2006-02-21 15:58:09.840650552 +0000
@@ -4,5 +4,6 @@
 
 ifneq ($(CONFIG_ACPI_PROCESSOR),)
 obj-y			+= processor.o
+processor-y		:= ../../../i386/kernel/acpi/processor.o ../../../i386/kernel/acpi/cstate.o
 endif
 
diff -urN oldtree/arch/x86_64/kernel/acpi/processor.c newtree/arch/x86_64/kernel/acpi/processor.c
--- oldtree/arch/x86_64/kernel/acpi/processor.c	2006-02-19 11:41:00.417279664 +0000
+++ newtree/arch/x86_64/kernel/acpi/processor.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,72 +0,0 @@
-/*
- * arch/x86_64/kernel/acpi/processor.c
- *
- * Copyright (C) 2005 Intel Corporation
- * 	Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
- * 	- Added _PDC for platforms with Intel CPUs
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/acpi.h>
-
-#include <acpi/processor.h>
-#include <asm/acpi.h>
-
-static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c)
-{
-	struct acpi_object_list *obj_list;
-	union acpi_object *obj;
-	u32 *buf;
-
-	/* allocate and initialize pdc. It will be used later. */
-	obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL);
-	if (!obj_list) {
-		printk(KERN_ERR "Memory allocation error\n");
-		return;
-	}
-
-	obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL);
-	if (!obj) {
-		printk(KERN_ERR "Memory allocation error\n");
-		kfree(obj_list);
-		return;
-	}
-
-	buf = kmalloc(12, GFP_KERNEL);
-	if (!buf) {
-		printk(KERN_ERR "Memory allocation error\n");
-		kfree(obj);
-		kfree(obj_list);
-		return;
-	}
-
-	buf[0] = ACPI_PDC_REVISION_ID;
-	buf[1] = 1;
-	buf[2] = ACPI_PDC_EST_CAPABILITY_SMP;
-
-	obj->type = ACPI_TYPE_BUFFER;
-	obj->buffer.length = 12;
-	obj->buffer.pointer = (u8 *) buf;
-	obj_list->count = 1;
-	obj_list->pointer = obj;
-	pr->pdc = obj_list;
-
-	return;
-}
-
-/* Initialize _PDC data based on the CPU vendor */
-void arch_acpi_processor_init_pdc(struct acpi_processor *pr)
-{
-	unsigned int cpu = pr->id;
-	struct cpuinfo_x86 *c = cpu_data + cpu;
-
-	pr->pdc = NULL;
-	if (c->x86_vendor == X86_VENDOR_INTEL && cpu_has(c, X86_FEATURE_EST))
-		init_intel_pdc(pr, c);
-
-	return;
-}
-
-EXPORT_SYMBOL(arch_acpi_processor_init_pdc);
diff -urN oldtree/arch/x86_64/kernel/kprobes.c newtree/arch/x86_64/kernel/kprobes.c
--- oldtree/arch/x86_64/kernel/kprobes.c	2006-02-19 11:41:00.429277840 +0000
+++ newtree/arch/x86_64/kernel/kprobes.c	2006-02-21 15:58:26.057185264 +0000
@@ -222,9 +222,9 @@
 
 void __kprobes arch_remove_kprobe(struct kprobe *p)
 {
-	down(&kprobe_mutex);
+	mutex_lock(&kprobe_mutex);
 	free_insn_slot(p->ainsn.insn);
-	up(&kprobe_mutex);
+	mutex_unlock(&kprobe_mutex);
 }
 
 static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb)
diff -urN oldtree/arch/x86_64/kernel/time.c newtree/arch/x86_64/kernel/time.c
--- oldtree/arch/x86_64/kernel/time.c	2006-02-19 11:41:00.486269176 +0000
+++ newtree/arch/x86_64/kernel/time.c	2006-02-21 15:58:22.909663760 +0000
@@ -1268,9 +1268,45 @@
 
 int hpet_rtc_dropped_irq(void)
 {
+	unsigned int cnt, ticks_per_int, lost_ints;
+
 	if (!is_hpet_enabled())
 		return 0;
 
+	if (UIE_on | PIE_on | AIE_on) {
+		/*
+		 * The interrupt handler schedules the next interrupt at a
+		 * constant offset from the time the current interrupt was
+		 * scheduled, without regard to the actual time. When the
+		 * handler is delayed too long, it tries to schedule the next
+		 * interrupt in the past and the hardware would not interrupt
+		 * until the counter had wrapped around. We catch it here.
+		 */
+		cnt = hpet_readl(HPET_COUNTER);
+		/* was the comparator set to a time in the past? */
+		if ((int)(cnt - hpet_t1_cmp) > 0) {
+			/* determine how many interrupts were actually lost */
+			ticks_per_int = (hpet_tick * HZ) / hpet_rtc_int_freq;
+			lost_ints = (cnt - hpet_t1_cmp) / ticks_per_int + 1;
+			/*
+			 * Make sure that, even with the time needed to execute
+			 * this code, the next scheduled interrupt has been
+			 * moved back to the future.
+			 */
+			lost_ints++;
+
+			cnt = hpet_t1_cmp + lost_ints * ticks_per_int;
+			hpet_writel(cnt, HPET_T1_CMP);
+			hpet_t1_cmp = cnt;
+
+			if (PIE_on)
+				PIE_count += lost_ints;
+
+			printk(KERN_WARNING "rtc: lost some interrupts"
+			       " at %ldHz.\n", hpet_rtc_int_freq);
+		}
+	}
+
 	return 1;
 }
 
diff -urN oldtree/arch/x86_64/kernel/traps.c newtree/arch/x86_64/kernel/traps.c
--- oldtree/arch/x86_64/kernel/traps.c	2006-02-19 11:41:00.488268872 +0000
+++ newtree/arch/x86_64/kernel/traps.c	2006-02-21 15:58:12.810199112 +0000
@@ -428,6 +428,7 @@
 	printk("DEBUG_PAGEALLOC");
 #endif
 	printk("\n");
+	sysfs_printk_last_file();
 	notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV);
 	show_registers(regs);
 	/* Executive summary in case the oops scrolled away */
diff -urN oldtree/arch/x86_64/pci/Makefile newtree/arch/x86_64/pci/Makefile
--- oldtree/arch/x86_64/pci/Makefile	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/x86_64/pci/Makefile	2006-02-21 15:58:18.683306264 +0000
@@ -7,7 +7,7 @@
 
 obj-y		:= i386.o
 obj-$(CONFIG_PCI_DIRECT)+= direct.o
-obj-y		+= fixup.o
+obj-y		+= fixup.o init.o
 obj-$(CONFIG_ACPI)	+= acpi.o
 obj-y			+= legacy.o irq.o common.o
 # mmconfig has a 64bit special
@@ -22,3 +22,4 @@
 common-y += ../../i386/pci/common.o
 fixup-y  += ../../i386/pci/fixup.o
 i386-y  += ../../i386/pci/i386.o
+init-y += ../../i386/pci/init.o
diff -urN oldtree/arch/x86_64/pci/k8-bus.c newtree/arch/x86_64/pci/k8-bus.c
--- oldtree/arch/x86_64/pci/k8-bus.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/arch/x86_64/pci/k8-bus.c	2006-02-21 15:58:17.878428624 +0000
@@ -59,6 +59,8 @@
 				     j <= SUBORDINATE_LDT_BUS_NUMBER(ldtbus);
 				     j++) { 
 					struct pci_bus *bus;
+					struct pci_sysdata *sd;
+
 					long node = NODE_ID(nid);
 					/* Algorithm a bit dumb, but
  					   it shouldn't matter here */
@@ -67,7 +69,9 @@
 						continue;
 					if (!node_online(node))
 						node = 0;
-					bus->sysdata = (void *)node;
+
+					sd = bus->sysdata;
+					sd->node = node;
 				}		
 			}
 		}
diff -urN oldtree/block/Kconfig newtree/block/Kconfig
--- oldtree/block/Kconfig	2006-02-19 11:41:00.501266896 +0000
+++ newtree/block/Kconfig	2006-02-21 15:58:11.897337888 +0000
@@ -11,4 +11,15 @@
 	  your machine, or if you want to have a raid or loopback device
 	  bigger than 2TB.  Otherwise say N.
 
+config BLK_DEV_IO_TRACE
+	bool "Support for tracing block io actions"
+	select RELAYFS_FS
+	help
+	  Say Y here, if you want to be able to trace the block layer actions
+	  on a given queue. Tracing allows you to see any traffic happening
+	  on a block device queue. For more information (and the user space
+	  support tools needed), fetch the blktrace app from:
+
+	  git://brick.kernel.dk/data/git/blktrace.git
+
 source block/Kconfig.iosched
diff -urN oldtree/block/Makefile newtree/block/Makefile
--- oldtree/block/Makefile	2006-01-03 03:21:10.000000000 +0000
+++ newtree/block/Makefile	2006-02-21 15:58:11.897337888 +0000
@@ -8,3 +8,5 @@
 obj-$(CONFIG_IOSCHED_AS)	+= as-iosched.o
 obj-$(CONFIG_IOSCHED_DEADLINE)	+= deadline-iosched.o
 obj-$(CONFIG_IOSCHED_CFQ)	+= cfq-iosched.o
+
+obj-$(CONFIG_BLK_DEV_IO_TRACE)	+= blktrace.o
diff -urN oldtree/block/blktrace.c newtree/block/blktrace.c
--- oldtree/block/blktrace.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/block/blktrace.c	2006-02-21 15:58:24.522418584 +0000
@@ -0,0 +1,593 @@
+/*
+ * Copyright (C) 2006 Jens Axboe <axboe@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/blktrace_api.h>
+#include <linux/percpu.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <asm/uaccess.h>
+
+static DEFINE_PER_CPU(unsigned long long, blk_trace_cpu_offset) = { 0, };
+static unsigned int blktrace_seq __read_mostly = 1;
+
+/*
+ * Send out a notify for this process, if we haven't done so since a trace
+ * started
+ */
+static void trace_note_tsk(struct blk_trace *bt, struct task_struct *tsk)
+{
+	struct blk_io_trace *t;
+
+	t = relay_reserve(bt->rchan, sizeof(*t) + sizeof(tsk->comm));
+	if (t) {
+		t->magic = BLK_IO_TRACE_MAGIC | BLK_IO_TRACE_VERSION;
+		t->device = bt->dev;
+		t->action = BLK_TC_ACT(BLK_TC_NOTIFY);
+		t->pid = tsk->pid;
+		t->cpu = smp_processor_id();
+		t->pdu_len = sizeof(tsk->comm);
+		memcpy((void *) t + sizeof(*t), tsk->comm, t->pdu_len);
+		tsk->btrace_seq = blktrace_seq;
+	}
+}
+
+static int act_log_check(struct blk_trace *bt, u32 what, sector_t sector,
+			 pid_t pid)
+{
+	if (((bt->act_mask << BLK_TC_SHIFT) & what) == 0)
+		return 1;
+	if (sector < bt->start_lba || sector > bt->end_lba)
+		return 1;
+	if (bt->pid && pid != bt->pid)
+		return 1;
+
+	return 0;
+}
+
+/*
+ * Data direction bit lookup
+ */
+static u32 ddir_act[2] __read_mostly = { BLK_TC_ACT(BLK_TC_READ), BLK_TC_ACT(BLK_TC_WRITE) };
+
+/*
+ * Bio action bits of interest
+ */
+static u32 bio_act[3] __read_mostly = { 0, BLK_TC_ACT(BLK_TC_BARRIER), BLK_TC_ACT(BLK_TC_SYNC) };
+
+/*
+ * More could be added as needed, taking care to increment the decrementer
+ * to get correct indexing
+ */
+#define trace_barrier_bit(rw)	\
+	(((rw) & (1 << BIO_RW_BARRIER)) >> (BIO_RW_BARRIER - 0))
+#define trace_sync_bit(rw)	\
+	(((rw) & (1 << BIO_RW_SYNC)) >> (BIO_RW_SYNC - 1))
+
+/*
+ * The worker for the various blk_add_trace*() types. Fills out a
+ * blk_io_trace structure and places it in a per-cpu subbuffer.
+ */
+void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
+		     int rw, u32 what, int error, int pdu_len, void *pdu_data)
+{
+	struct task_struct *tsk = current;
+	struct blk_io_trace *t;
+	unsigned long flags;
+	unsigned long *sequence;
+	pid_t pid;
+	int cpu;
+
+	if (unlikely(bt->trace_state != Blktrace_running))
+		return;
+
+	what |= ddir_act[rw & WRITE];
+	what |= bio_act[trace_barrier_bit(rw)];
+	what |= bio_act[trace_sync_bit(rw)];
+
+	pid = tsk->pid;
+	if (unlikely(act_log_check(bt, what, sector, pid)))
+		return;
+
+	/*
+	 * A word about the locking here - we disable interrupts to reserve
+	 * some space in the relayfs per-cpu buffer, to prevent an irq
+	 * from coming in and stepping on our toes. Once reserved, it's
+	 * enough to get preemption disabled to prevent read of this data
+	 * before we are through filling it. get_cpu()/put_cpu() does this
+	 * for us
+	 */
+	local_irq_save(flags);
+
+	if (unlikely(tsk->btrace_seq != blktrace_seq))
+		trace_note_tsk(bt, tsk);
+
+	t = relay_reserve(bt->rchan, sizeof(*t) + pdu_len);
+	if (t) {
+		cpu = smp_processor_id();
+		sequence = per_cpu_ptr(bt->sequence, cpu);
+
+		t->magic = BLK_IO_TRACE_MAGIC | BLK_IO_TRACE_VERSION;
+		t->sequence = ++(*sequence);
+		t->time = sched_clock() - per_cpu(blk_trace_cpu_offset, cpu);
+		t->sector = sector;
+		t->bytes = bytes;
+		t->action = what;
+		t->pid = pid;
+		t->device = bt->dev;
+		t->cpu = cpu;
+		t->error = error;
+		t->pdu_len = pdu_len;
+
+		if (pdu_len)
+			memcpy((void *) t + sizeof(*t), pdu_data, pdu_len);
+	}
+
+	local_irq_restore(flags);
+}
+
+EXPORT_SYMBOL_GPL(__blk_add_trace);
+
+static struct dentry *blk_tree_root;
+static struct mutex blk_tree_mutex;
+
+static inline void blk_remove_root(void)
+{
+	if (relayfs_remove_dir(blk_tree_root) != -ENOTEMPTY)
+		blk_tree_root = NULL;
+}
+
+static void blk_remove_tree(struct dentry *dir)
+{
+	mutex_lock(&blk_tree_mutex);
+	relayfs_remove_dir(dir);
+	blk_remove_root();
+	mutex_unlock(&blk_tree_mutex);
+}
+
+static struct dentry *blk_create_tree(const char *blk_name)
+{
+	struct dentry *dir = NULL;
+
+	mutex_lock(&blk_tree_mutex);
+
+	if (!blk_tree_root) {
+		blk_tree_root = relayfs_create_dir("block", NULL);
+		if (!blk_tree_root)
+			goto err;
+	}
+
+	dir = relayfs_create_dir(blk_name, blk_tree_root);
+	if (!dir)
+		blk_remove_root();
+
+err:
+	mutex_unlock(&blk_tree_mutex);
+	return dir;
+}
+
+static int blk_padding_open(struct inode *inode, struct file *filp)
+{
+	filp->private_data = inode->u.generic_ip;
+	
+	return 0;
+}
+
+static ssize_t blk_padding_read(struct file *filp, char __user *buffer,
+				size_t count, loff_t *ppos)
+{
+	struct rchan_buf *buf = filp->private_data;
+	size_t s = buf->chan->n_subbufs * sizeof(*buf->padding);
+
+	return simple_read_from_buffer(buffer, count, ppos, buf->padding, s);
+}
+
+static struct file_operations blk_padding_fops = {
+	.owner =	THIS_MODULE,
+	.open =		blk_padding_open,
+	.read =		blk_padding_read,
+};
+
+static void remove_channel_controls(struct blk_trace *bt)
+{
+	int i;
+
+	for (i = 0; i < NR_CPUS; i++) {
+		if (bt->ctrl->padding[i]) {
+			relayfs_remove_file(bt->ctrl->padding[i]);
+			continue;
+		}
+		break;
+	}
+	kfree(bt->ctrl);
+	bt->ctrl = NULL;
+}
+
+static int create_channel_controls(struct blk_trace *bt,
+				   struct dentry *parent,
+				   const char *base_filename)
+{
+	unsigned int i;
+	char *tmpname;
+	
+	tmpname = kmalloc(NAME_MAX + 1, GFP_KERNEL);
+	if (!tmpname)
+		return -ENOMEM;
+
+	bt->ctrl = kzalloc(sizeof(struct rchan_ctrl), GFP_KERNEL);
+	if (!bt->ctrl)
+		goto cleanup_control_files;
+
+	for_each_cpu(i) {
+		sprintf(tmpname, "%s%d.padding", base_filename, i);
+		bt->ctrl->padding[i] = relayfs_create_file(tmpname,
+							   parent,
+							   0,
+							   &blk_padding_fops,
+							   bt->rchan->buf[i]);
+		if (!bt->ctrl->padding[i]) {
+			printk("Couldn't create padding file %s.\n", tmpname);
+			goto cleanup_control_files;
+		}
+	}
+	kfree(tmpname);
+	return 0;
+
+cleanup_control_files:
+	remove_channel_controls(bt);
+	kfree(tmpname);
+	
+	return -ENOMEM;
+}
+
+static void blk_trace_cleanup(struct blk_trace *bt)
+{
+	relay_close(bt->rchan);
+	relayfs_remove_file(bt->dropped_file);
+	remove_channel_controls(bt);
+	blk_remove_tree(bt->dir);
+	free_percpu(bt->sequence);
+	kfree(bt);
+}
+
+static int blk_trace_remove(request_queue_t *q)
+{
+	struct blk_trace *bt;
+
+	bt = xchg(&q->blk_trace, NULL);
+	if (!bt)
+		return -EINVAL;
+
+	if (bt->trace_state == Blktrace_setup ||
+	    bt->trace_state == Blktrace_stopped)
+		blk_trace_cleanup(bt);
+
+	return 0;
+}
+
+static int blk_dropped_open(struct inode *inode, struct file *filp)
+{
+	filp->private_data = inode->u.generic_ip;
+	
+	return 0;
+}
+
+static ssize_t blk_dropped_read(struct file *filp, char __user *buffer,
+				size_t count, loff_t *ppos)
+{
+	struct blk_trace *bt = filp->private_data;
+	char buf[16];
+
+	snprintf(buf, sizeof(buf), "%u\n", atomic_read(&bt->dropped));
+	
+	return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
+}
+
+static struct file_operations blk_dropped_fops = {
+	.owner =	THIS_MODULE,
+	.open =		blk_dropped_open,
+	.read =		blk_dropped_read,
+};
+
+/*
+ * Keep track of how many times we encountered a full subbuffer, to aid
+ * the user space app in telling how many lost events there were.
+ */
+static int blk_subbuf_start_callback(struct rchan_buf *buf, void *subbuf,
+				     void *prev_subbuf, size_t prev_padding)
+{
+	struct blk_trace *bt;
+
+	if (!relay_buf_full(buf))
+		return 1;
+
+	bt = buf->chan->private_data;
+	atomic_inc(&bt->dropped);
+	return 0;
+}
+
+static struct rchan_callbacks blk_relay_callbacks = {
+	.subbuf_start = blk_subbuf_start_callback,
+};
+
+/*
+ * Setup everything required to start tracing
+ */
+static int blk_trace_setup(request_queue_t *q, struct block_device *bdev,
+			   char __user *arg)
+{
+	struct blk_user_trace_setup buts;
+	struct blk_trace *old_bt, *bt = NULL;
+	struct dentry *dir = NULL;
+	char b[BDEVNAME_SIZE];
+	int ret, i;
+
+	if (copy_from_user(&buts, arg, sizeof(buts)))
+		return -EFAULT;
+
+	if (!buts.buf_size || !buts.buf_nr)
+		return -EINVAL;
+
+	strcpy(buts.name, bdevname(bdev, b));
+
+	/*
+	 * some device names have larger paths - convert the slashes
+	 * to underscores for this to work as expected
+	 */
+	for (i = 0; i < strlen(buts.name); i++)
+		if (buts.name[i] == '/')
+			buts.name[i] = '_';
+
+	if (copy_to_user(arg, &buts, sizeof(buts)))
+		return -EFAULT;
+
+	ret = -ENOMEM;
+	bt = kzalloc(sizeof(*bt), GFP_KERNEL);
+	if (!bt)
+		goto err;
+
+	bt->sequence = alloc_percpu(unsigned long);
+	if (!bt->sequence)
+		goto err;
+
+	ret = -ENOENT;
+	dir = blk_create_tree(buts.name);
+	if (!dir)
+		goto err;
+
+	bt->dir = dir;
+	bt->dev = bdev->bd_dev;
+	atomic_set(&bt->dropped, 0);
+
+	ret = -EIO;
+	bt->dropped_file = relayfs_create_file("dropped", dir, 0, &blk_dropped_fops, bt);
+	if (!bt->dropped_file)
+		goto err;
+
+	bt->rchan = relay_open("trace", dir, buts.buf_size, buts.buf_nr, &blk_relay_callbacks);
+	if (!bt->rchan)
+		goto err;
+	bt->rchan->private_data = bt;
+
+	if (create_channel_controls(bt, dir, "trace"))
+		goto err;
+
+	bt->act_mask = buts.act_mask;
+	if (!bt->act_mask)
+		bt->act_mask = (u16) -1;
+
+	bt->start_lba = buts.start_lba;
+	bt->end_lba = buts.end_lba;
+	if (!bt->end_lba)
+		bt->end_lba = -1ULL;
+
+	bt->pid = buts.pid;
+	bt->trace_state = Blktrace_setup;
+
+	ret = -EBUSY;
+	old_bt = xchg(&q->blk_trace, bt);
+	if (old_bt) {
+		xchg(&q->blk_trace, old_bt);
+		goto err;
+	}
+
+	return 0;
+err:
+	if (dir)
+		blk_remove_tree(dir);
+	if (bt) {
+		if (bt->dropped_file)
+			relayfs_remove_file(bt->dropped_file);
+		if (bt->ctrl)
+			remove_channel_controls(bt);
+		if (bt->sequence)
+			free_percpu(bt->sequence);
+		if (bt->rchan)
+			relay_close(bt->rchan);
+		kfree(bt);
+	}
+	return ret;
+}
+
+static int blk_trace_startstop(request_queue_t *q, int start)
+{
+	struct blk_trace *bt;
+	int ret;
+
+	if ((bt = q->blk_trace) == NULL)
+		return -EINVAL;
+
+	/*
+	 * For starting a trace, we can transition from a setup or stopped
+	 * trace. For stopping a trace, the state must be running
+	 */
+	ret = -EINVAL;
+	if (start) {
+		if (bt->trace_state == Blktrace_setup ||
+		    bt->trace_state == Blktrace_stopped) {
+			blktrace_seq++;
+			smp_mb();
+			bt->trace_state = Blktrace_running;
+			ret = 0;
+		}
+	} else {
+		if (bt->trace_state == Blktrace_running) {
+			bt->trace_state = Blktrace_stopped;
+			relay_flush(bt->rchan);
+			ret = 0;
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * blk_trace_ioctl: - handle the ioctls associated with tracing
+ * @bdev:	the block device
+ * @cmd: 	the ioctl cmd
+ * @arg:	the argument data, if any
+ *
+ **/
+int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg)
+{
+	request_queue_t *q;
+	int ret, start = 0;
+
+	q = bdev_get_queue(bdev);
+	if (!q)
+		return -ENXIO;
+
+	mutex_lock(&bdev->bd_mutex);
+
+	switch (cmd) {
+	case BLKTRACESETUP:
+		ret = blk_trace_setup(q, bdev, arg);
+		break;
+	case BLKTRACESTART:
+		start = 1;
+	case BLKTRACESTOP:
+		ret = blk_trace_startstop(q, start);
+		break;
+	case BLKTRACETEARDOWN:
+		ret = blk_trace_remove(q);
+		break;
+	default:
+		ret = -ENOTTY;
+		break;
+	}
+
+	mutex_unlock(&bdev->bd_mutex);
+	return ret;
+}
+
+/**
+ * blk_trace_shutdown: - stop and cleanup trace structures
+ * @q:    the request queue associated with the device
+ *
+ **/
+void blk_trace_shutdown(request_queue_t *q)
+{
+	blk_trace_startstop(q, 0);
+	blk_trace_remove(q);
+}
+
+/*
+ * Average offset over two calls to sched_clock() with a gettimeofday()
+ * in the middle
+ */
+static void blk_check_time(unsigned long long *t)
+{
+	unsigned long long a, b;
+	struct timeval tv;
+
+	a = sched_clock();
+	do_gettimeofday(&tv);
+	b = sched_clock();
+
+	*t = tv.tv_sec * 1000000000 + tv.tv_usec * 1000;
+	*t -= (a + b) / 2;
+}
+
+static void blk_trace_check_cpu_time(void *data)
+{
+	unsigned long long *t;
+	int cpu = get_cpu();
+
+	t = &per_cpu(blk_trace_cpu_offset, cpu);
+
+	/*
+	 * Just call it twice, hopefully the second call will be cache hot
+	 * and a little more precise
+	 */
+	blk_check_time(t);
+	blk_check_time(t);
+
+	put_cpu();
+}
+
+/*
+ * Call blk_trace_check_cpu_time() on each CPU to calibrate our inter-CPU
+ * timings
+ */
+static void blk_trace_calibrate_offsets(void)
+{
+	unsigned long flags;
+
+	smp_call_function(blk_trace_check_cpu_time, NULL, 1, 1);
+	local_irq_save(flags);
+	blk_trace_check_cpu_time(NULL);
+	local_irq_restore(flags);
+}
+
+static void blk_trace_set_ht_offsets(void)
+{
+#if defined(CONFIG_SCHED_SMT)
+	int cpu, i;
+
+	/*
+	 * now make sure HT siblings have the same time offset
+	 */
+	preempt_disable();
+	for_each_online_cpu(cpu) {
+		unsigned long long *cpu_off, *sibling_off;
+
+		for_each_cpu_mask(i, cpu_sibling_map[cpu]) {
+			if (i == cpu)
+				continue;
+
+			cpu_off = &per_cpu(blk_trace_cpu_offset, cpu);
+			sibling_off = &per_cpu(blk_trace_cpu_offset, i);
+			*sibling_off = *cpu_off;
+		}
+	}
+	preempt_enable();
+#endif
+}
+
+static __init int blk_trace_init(void)
+{
+	mutex_init(&blk_tree_mutex);
+	blk_trace_calibrate_offsets();
+	blk_trace_set_ht_offsets();
+
+	return 0;
+}
+
+module_init(blk_trace_init);
+
diff -urN oldtree/block/cfq-iosched.c newtree/block/cfq-iosched.c
--- oldtree/block/cfq-iosched.c	2006-02-19 11:41:00.503266592 +0000
+++ newtree/block/cfq-iosched.c	2006-02-21 15:58:30.849456728 +0000
@@ -34,13 +34,12 @@
 static const int cfq_slice_sync = HZ / 10;
 static int cfq_slice_async = HZ / 25;
 static const int cfq_slice_async_rq = 2;
-static int cfq_slice_idle = HZ / 100;
+static int cfq_slice_idle = HZ / 70;
 
 #define CFQ_IDLE_GRACE		(HZ / 10)
 #define CFQ_SLICE_SCALE		(5)
 
 #define CFQ_KEY_ASYNC		(0)
-#define CFQ_KEY_ANY		(0xffff)
 
 /*
  * disable queueing at the driver/hardware level
@@ -105,6 +104,8 @@
 #define cfq_cfqq_sync(cfqq)		\
 	(cfq_cfqq_class_sync(cfqq) || (cfqq)->on_dispatch[SYNC])
 
+#define sample_valid(samples)	((samples) > 80)
+
 /*
  * Per block device queue structure
  */
@@ -116,8 +117,9 @@
 	 * rr list of queues with requests and the count of them
 	 */
 	struct list_head rr_list[CFQ_PRIO_LISTS];
-	struct list_head busy_rr;
 	struct list_head cur_rr;
+	unsigned short cur_prio;
+
 	struct list_head idle_rr;
 	unsigned int busy_queues;
 
@@ -153,7 +155,6 @@
 
 	struct cfq_queue *active_queue;
 	struct cfq_io_context *active_cic;
-	int cur_prio, cur_end_prio;
 	unsigned int dispatch_slice;
 
 	struct timer_list idle_class_timer;
@@ -211,8 +212,13 @@
 	int on_dispatch[2];
 
 	/* io prio of this group */
-	unsigned short ioprio, org_ioprio;
-	unsigned short ioprio_class, org_ioprio_class;
+	unsigned short ioprio_class, ioprio;
+
+	/* current dynamic stair priority */
+	unsigned short dyn_ioprio;
+
+	/* same as real ioprio, except if queue has been elevated */
+	unsigned short org_ioprio_class, org_ioprio;
 
 	/* various state flags, see below */
 	unsigned int flags;
@@ -347,6 +353,14 @@
 	return !cfqd->busy_queues;
 }
 
+static inline pid_t cfq_queue_pid(struct task_struct *task, int rw)
+{
+	if (rw == READ || process_sync(task))
+		return task->pid;
+
+	return CFQ_KEY_ASYNC;
+}
+
 /*
  * Lifted from AS - choose which of crq1 and crq2 that is best served now.
  * We choose the request that is closest to the head right now. Distance
@@ -471,25 +485,13 @@
 		list = &cfqd->cur_rr;
 	else if (cfq_class_idle(cfqq))
 		list = &cfqd->idle_rr;
-	else {
-		/*
-		 * if cfqq has requests in flight, don't allow it to be
-		 * found in cfq_set_active_queue before it has finished them.
-		 * this is done to increase fairness between a process that
-		 * has lots of io pending vs one that only generates one
-		 * sporadically or synchronously
-		 */
-		if (cfq_cfqq_dispatched(cfqq))
-			list = &cfqd->busy_rr;
-		else
-			list = &cfqd->rr_list[cfqq->ioprio];
-	}
+	else
+		list = &cfqd->rr_list[cfqq->dyn_ioprio];
 
 	/*
-	 * if queue was preempted, just add to front to be fair. busy_rr
-	 * isn't sorted.
+	 * if queue was preempted, just add to front to be fair.
 	 */
-	if (preempted || list == &cfqd->busy_rr) {
+	if (preempted) {
 		list_add(&cfqq->cfq_list, list);
 		return;
 	}
@@ -501,6 +503,8 @@
 	while ((entry = entry->prev) != list) {
 		struct cfq_queue *__cfqq = list_entry_cfqq(entry);
 
+		if (__cfqq->ioprio < cfqq->ioprio)
+			break;
 		if (!__cfqq->service_last)
 			break;
 		if (time_before(__cfqq->service_last, cfqq->service_last))
@@ -616,15 +620,20 @@
 	cfq_add_crq_rb(crq);
 }
 
-static struct request *cfq_find_rq_rb(struct cfq_data *cfqd, sector_t sector)
-
+static struct request *
+cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio)
 {
-	struct cfq_queue *cfqq = cfq_find_cfq_hash(cfqd, current->pid, CFQ_KEY_ANY);
+	struct task_struct *tsk = current;
+	pid_t key = cfq_queue_pid(tsk, bio_data_dir(bio));
+	struct cfq_queue *cfqq;
 	struct rb_node *n;
+	sector_t sector;
 
+	cfqq = cfq_find_cfq_hash(cfqd, key, tsk->ioprio);
 	if (!cfqq)
 		goto out;
 
+	sector = bio->bi_sector + bio_sectors(bio);
 	n = cfqq->sort_list.rb_node;
 	while (n) {
 		struct cfq_rq *crq = rb_entry_crq(n);
@@ -678,7 +687,7 @@
 		goto out;
 	}
 
-	__rq = cfq_find_rq_rb(cfqd, bio->bi_sector + bio_sectors(bio));
+	__rq = cfq_find_rq_fmerge(cfqd, bio);
 	if (__rq && elv_rq_merge_ok(__rq, bio)) {
 		ret = ELEVATOR_FRONT_MERGE;
 		goto out;
@@ -722,81 +731,100 @@
 	cfq_remove_request(next);
 }
 
+/*
+ * Scale schedule slice based on io priority. Use the sync time slice only
+ * if a queue is marked sync and has sync io queued. A sync queue with async
+ * io only, should not get full sync slice length.
+ */
+static inline int
+cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+	const int base_slice = cfqd->cfq_slice[cfq_cfqq_sync(cfqq)];
+	unsigned short prio = cfqq->dyn_ioprio;
+
+	WARN_ON(prio >= IOPRIO_BE_NR);
+
+	if (cfq_class_rt(cfqq))
+		prio = 0;
+
+	return base_slice + (base_slice / CFQ_SLICE_SCALE * (4 - prio));
+}
+
 static inline void
-__cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
-	if (cfqq) {
-		/*
-		 * stop potential idle class queues waiting service
-		 */
-		del_timer(&cfqd->idle_class_timer);
+	cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies;
+}
 
-		cfqq->slice_start = jiffies;
-		cfqq->slice_end = 0;
-		cfqq->slice_left = 0;
-		cfq_clear_cfqq_must_alloc_slice(cfqq);
-		cfq_clear_cfqq_fifo_expire(cfqq);
-		cfq_clear_cfqq_expired(cfqq);
-	}
+static inline int
+cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+	const int base_rq = cfqd->cfq_slice_async_rq;
+	unsigned short prio = cfqq->dyn_ioprio;
 
-	cfqd->active_queue = cfqq;
+	WARN_ON(cfqq->dyn_ioprio >= IOPRIO_BE_NR);
+
+	if (cfq_class_rt(cfqq))
+		prio = 0;
+
+	return 2 * (base_rq + base_rq * (CFQ_PRIO_LISTS - 1 - prio));
 }
 
-/*
- * 0
- * 0,1
- * 0,1,2
- * 0,1,2,3
- * 0,1,2,3,4
- * 0,1,2,3,4,5
- * 0,1,2,3,4,5,6
- * 0,1,2,3,4,5,6,7
- */
-static int cfq_get_next_prio_level(struct cfq_data *cfqd)
+static inline void cfq_prio_inc(unsigned short *p, unsigned int low_p)
 {
-	int prio, wrap;
+	if (++(*p) == CFQ_PRIO_LISTS)
+		*p = low_p;
+}
 
-	prio = -1;
-	wrap = 0;
-	do {
-		int p;
+static struct cfq_queue *cfq_get_next_cfqq(struct cfq_data *cfqd)
+{
+	if (!cfqd->busy_queues)
+		return NULL;
 
-		for (p = cfqd->cur_prio; p <= cfqd->cur_end_prio; p++) {
-			if (!list_empty(&cfqd->rr_list[p])) {
-				prio = p;
+	if (list_empty(&cfqd->cur_rr)) {
+		unsigned short prio = cfqd->cur_prio;
+
+		do {
+			struct list_head *list = &cfqd->rr_list[prio];
+
+			if (!list_empty(list)) {
+				list_splice_init(list, &cfqd->cur_rr);
 				break;
 			}
-		}
 
-		if (prio != -1)
-			break;
-		cfqd->cur_prio = 0;
-		if (++cfqd->cur_end_prio == CFQ_PRIO_LISTS) {
-			cfqd->cur_end_prio = 0;
-			if (wrap)
-				break;
-			wrap = 1;
-		}
-	} while (1);
+			cfq_prio_inc(&prio, 0);
 
-	if (unlikely(prio == -1))
-		return -1;
+		} while (prio != cfqd->cur_prio);
 
-	BUG_ON(prio >= CFQ_PRIO_LISTS);
+		cfq_prio_inc(&cfqd->cur_prio, 0);
+	}
 
-	list_splice_init(&cfqd->rr_list[prio], &cfqd->cur_rr);
+	if (!list_empty(&cfqd->cur_rr));
+		return list_entry_cfqq(cfqd->cur_rr.next);
 
-	cfqd->cur_prio = prio + 1;
-	if (cfqd->cur_prio > cfqd->cur_end_prio) {
-		cfqd->cur_end_prio = cfqd->cur_prio;
-		cfqd->cur_prio = 0;
-	}
-	if (cfqd->cur_end_prio == CFQ_PRIO_LISTS) {
-		cfqd->cur_prio = 0;
-		cfqd->cur_end_prio = 0;
+	return NULL;
+}
+
+static inline void
+__cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+	if (cfqq) {
+		WARN_ON(RB_EMPTY(&cfqq->sort_list));
+
+		/*
+		 * stop potential idle class queues waiting service
+		 */
+		del_timer(&cfqd->idle_class_timer);
+
+		cfqq->slice_start = jiffies;
+		cfqq->slice_end = 0;
+		cfqq->slice_left = 0;
+		cfq_clear_cfqq_must_alloc_slice(cfqq);
+		cfq_clear_cfqq_fifo_expire(cfqq);
+		cfq_clear_cfqq_expired(cfqq);
 	}
 
-	return prio;
+	cfqd->active_queue = cfqq;
 }
 
 static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd)
@@ -809,15 +837,10 @@
 	 */
 	if ((cfqq = cfqd->active_queue) != NULL) {
 		if (cfq_cfqq_expired(cfqq) && cfq_cfqq_dispatched(cfqq))
-			return NULL;
+			return cfqq;
 	}
 
-	/*
-	 * if current list is non-empty, grab first entry. if it is empty,
-	 * get next prio level and grab first entry then if any are spliced
-	 */
-	if (!list_empty(&cfqd->cur_rr) || cfq_get_next_prio_level(cfqd) != -1)
-		cfqq = list_entry_cfqq(cfqd->cur_rr.next);
+	cfqq = cfq_get_next_cfqq(cfqd);
 
 	/*
 	 * if we have idle queues and no rt or be queues had pending
@@ -842,7 +865,7 @@
  */
 static void
 __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
-		    int preempted)
+		    int preempted, int force)
 {
 	unsigned long now = jiffies;
 
@@ -864,39 +887,44 @@
 	else
 		cfqq->slice_left = 0;
 
+	cfq_prio_inc(&cfqq->dyn_ioprio, cfqq->ioprio);
+
 	if (cfq_cfqq_on_rr(cfqq))
 		cfq_resort_rr_list(cfqq, preempted);
 
-	if (cfqq == cfqd->active_queue)
-		cfqd->active_queue = NULL;
+	/*
+	 * use deferred expiry, if there are requests in progress as
+	 * not to disturb the slice of the next queue
+	 */
+	if (cfq_cfqq_dispatched(cfqq) && !force)
+		cfq_mark_cfqq_expired(cfqq);
+	else {
+		if (cfqq == cfqd->active_queue)
+			cfqd->active_queue = NULL;
+
+		if (cfqd->active_cic) {
+			put_io_context(cfqd->active_cic->ioc);
+			cfqd->active_cic = NULL;
+		}
 
-	if (cfqd->active_cic) {
-		put_io_context(cfqd->active_cic->ioc);
-		cfqd->active_cic = NULL;
+		cfqd->dispatch_slice = 0;
 	}
-
-	cfqd->dispatch_slice = 0;
 }
 
 static inline void cfq_slice_expired(struct cfq_data *cfqd, int preempted)
 {
 	struct cfq_queue *cfqq = cfqd->active_queue;
 
-	if (cfqq) {
-		/*
-		 * use deferred expiry, if there are requests in progress as
-		 * not to disturb the slice of the next queue
-		 */
-		if (cfq_cfqq_dispatched(cfqq))
-			cfq_mark_cfqq_expired(cfqq);
-		else
-			__cfq_slice_expired(cfqd, cfqq, preempted);
-	}
+	if (cfqq)
+		__cfq_slice_expired(cfqd, cfqq, preempted, 0);
 }
 
 static int cfq_arm_slice_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 
 {
+	struct cfq_io_context *cic;
+	unsigned long sl;
+
 	WARN_ON(!RB_EMPTY(&cfqq->sort_list));
 	WARN_ON(cfqq != cfqd->active_queue);
 
@@ -910,19 +938,31 @@
 	/*
 	 * task has exited, don't wait
 	 */
-	if (cfqd->active_cic && !cfqd->active_cic->ioc->task)
+	cic = cfqd->active_cic;
+	if (!cic || !cic->ioc->task)
 		return 0;
 
+	/*
+	 * If timer is already running, continue waiting. If not, mark
+	 * us as waiting for a request and arm the idle timer
+	 */
+	if (timer_pending(&cfqd->idle_slice_timer))
+		return 1;
+
 	cfq_mark_cfqq_must_dispatch(cfqq);
 	cfq_mark_cfqq_wait_request(cfqq);
 
-	if (!timer_pending(&cfqd->idle_slice_timer)) {
-		unsigned long slice_left = min(cfqq->slice_end - 1, (unsigned long) cfqd->cfq_slice_idle);
-
-		cfqd->idle_slice_timer.expires = jiffies + slice_left;
-		add_timer(&cfqd->idle_slice_timer);
-	}
+	sl = min(cfqq->slice_end - 1, (unsigned long) cfqd->cfq_slice_idle);
+	/*
+	 * we don't want to idle for seeks, but we do want to allow
+	 * fair distribution of slice time for a process doing back-to-back
+	 * seeks. so allow a little bit of time for him to submit a new rq
+	 */
+	if (sample_valid(cic->seek_samples) && cic->seek_mean > 131072)
+		sl = 2;
 
+	cfqd->idle_slice_timer.expires = jiffies + sl;
+	add_timer(&cfqd->idle_slice_timer);
 	return 1;
 }
 
@@ -964,37 +1004,6 @@
 }
 
 /*
- * Scale schedule slice based on io priority. Use the sync time slice only
- * if a queue is marked sync and has sync io queued. A sync queue with async
- * io only, should not get full sync slice length.
- */
-static inline int
-cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
-{
-	const int base_slice = cfqd->cfq_slice[cfq_cfqq_sync(cfqq)];
-
-	WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);
-
-	return base_slice + (base_slice/CFQ_SLICE_SCALE * (4 - cfqq->ioprio));
-}
-
-static inline void
-cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
-{
-	cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies;
-}
-
-static inline int
-cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
-{
-	const int base_rq = cfqd->cfq_slice_async_rq;
-
-	WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);
-
-	return 2 * (base_rq + base_rq * (CFQ_PRIO_LISTS - 1 - cfqq->ioprio));
-}
-
-/*
  * get next queue for service
  */
 static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
@@ -1007,7 +1016,7 @@
 		goto new_queue;
 
 	if (cfq_cfqq_expired(cfqq))
-		goto new_queue;
+		goto keep_queue;
 
 	/*
 	 * slice has expired
@@ -1114,7 +1123,6 @@
 	for (i = 0; i < CFQ_PRIO_LISTS; i++)
 		dispatched += cfq_forced_dispatch_cfqqs(&cfqd->rr_list[i]);
 
-	dispatched += cfq_forced_dispatch_cfqqs(&cfqd->busy_rr);
 	dispatched += cfq_forced_dispatch_cfqqs(&cfqd->cur_rr);
 	dispatched += cfq_forced_dispatch_cfqqs(&cfqd->idle_rr);
 
@@ -1141,6 +1149,9 @@
 	if (cfqq) {
 		int max_dispatch;
 
+		if (cfq_cfqq_expired(cfqq))
+			return 0;
+
 		/*
 		 * if idle window is disabled, allow queue buildup
 		 */
@@ -1182,18 +1193,18 @@
 	BUG_ON(cfq_cfqq_on_rr(cfqq));
 
 	if (unlikely(cfqd->active_queue == cfqq)) {
-		__cfq_slice_expired(cfqd, cfqq, 0);
+		__cfq_slice_expired(cfqd, cfqq, 0, 1);
 		cfq_schedule_dispatch(cfqd);
 	}
 
-	cfq_put_cfqd(cfqq->cfqd);
-
 	/*
 	 * it's on the empty list and still hashed
 	 */
 	list_del(&cfqq->cfq_list);
 	hlist_del(&cfqq->cfq_hash);
 	kmem_cache_free(cfq_pool, cfqq);
+
+	cfq_put_cfqd(cfqd);
 }
 
 static inline struct cfq_queue *
@@ -1201,13 +1212,13 @@
 		    const int hashval)
 {
 	struct hlist_head *hash_list = &cfqd->cfq_hash[hashval];
-	struct hlist_node *entry, *next;
+	struct hlist_node *entry;
+	struct cfq_queue *__cfqq;
 
-	hlist_for_each_safe(entry, next, hash_list) {
-		struct cfq_queue *__cfqq = list_entry_qhash(entry);
+	hlist_for_each_entry(__cfqq, entry, hash_list, cfq_hash) {
 		const unsigned short __p = IOPRIO_PRIO_VALUE(__cfqq->ioprio_class, __cfqq->ioprio);
 
-		if (__cfqq->key == key && (__p == prio || prio == CFQ_KEY_ANY))
+		if (__cfqq->key == key && (__p == prio || !prio))
 			return __cfqq;
 	}
 
@@ -1220,17 +1231,17 @@
 	return __cfq_find_cfq_hash(cfqd, key, prio, hash_long(key, CFQ_QHASH_SHIFT));
 }
 
-static void cfq_free_io_context(struct cfq_io_context *cic)
+static void cfq_free_io_context(struct io_context *ioc)
 {
 	struct cfq_io_context *__cic;
-	struct list_head *entry, *next;
+	struct rb_node *n;
+
+	while ((n = rb_first(&ioc->cic_root)) != NULL) {
+		__cic = rb_entry(n, struct cfq_io_context, rb_node);
 
-	list_for_each_safe(entry, next, &cic->list) {
-		__cic = list_entry(entry, struct cfq_io_context, list);
+		rb_erase(&__cic->rb_node, &ioc->cic_root);
 		kmem_cache_free(cfq_ioc_pool, __cic);
 	}
-
-	kmem_cache_free(cfq_ioc_pool, cic);
 }
 
 /*
@@ -1246,7 +1257,7 @@
 	spin_lock(q->queue_lock);
 
 	if (unlikely(cic->cfqq == cfqd->active_queue)) {
-		__cfq_slice_expired(cfqd, cic->cfqq, 0);
+		__cfq_slice_expired(cfqd, cic->cfqq, 0, 1);
 		cfq_schedule_dispatch(cfqd);
 	}
 
@@ -1255,27 +1266,25 @@
 	spin_unlock(q->queue_lock);
 }
 
-/*
- * Another task may update the task cic list, if it is doing a queue lookup
- * on its behalf. cfq_cic_lock excludes such concurrent updates
- */
-static void cfq_exit_io_context(struct cfq_io_context *cic)
+static void cfq_exit_io_context(struct io_context *ioc)
 {
 	struct cfq_io_context *__cic;
-	struct list_head *entry;
 	unsigned long flags;
+	struct rb_node *n;
 
 	local_irq_save(flags);
 
 	/*
 	 * put the reference this task is holding to the various queues
 	 */
-	list_for_each(entry, &cic->list) {
-		__cic = list_entry(entry, struct cfq_io_context, list);
+	n = rb_first(&ioc->cic_root);
+	while (n != NULL) {
+		__cic = rb_entry(n, struct cfq_io_context, rb_node);
+
 		cfq_exit_single_io_context(__cic);
+		n = rb_next(n);
 	}
 
-	cfq_exit_single_io_context(cic);
 	local_irq_restore(flags);
 }
 
@@ -1285,9 +1294,9 @@
 	struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask);
 
 	if (cic) {
-		INIT_LIST_HEAD(&cic->list);
-		cic->cfqq = NULL;
+		RB_CLEAR(&cic->rb_node);
 		cic->key = NULL;
+		cic->cfqq = NULL;
 		cic->last_end_request = jiffies;
 		cic->ttime_total = 0;
 		cic->ttime_samples = 0;
@@ -1340,6 +1349,11 @@
 	cfqq->org_ioprio = cfqq->ioprio;
 	cfqq->org_ioprio_class = cfqq->ioprio_class;
 
+	/*
+	 * start priority
+	 */
+	cfqq->dyn_ioprio = cfqq->ioprio;
+
 	if (cfq_cfqq_on_rr(cfqq))
 		cfq_resort_rr_list(cfqq, 0);
 
@@ -1363,12 +1377,16 @@
  */
 static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio)
 {
-	struct cfq_io_context *cic = ioc->cic;
+	struct cfq_io_context *cic;
+	struct rb_node *n;
 
-	changed_ioprio(cic->cfqq);
+	n = rb_first(&ioc->cic_root);
+	while (n != NULL) {
+		cic = rb_entry(n, struct cfq_io_context, rb_node);
 
-	list_for_each_entry(cic, &cic->list, list)
 		changed_ioprio(cic->cfqq);
+		n = rb_next(n);
+	}
 
 	return 0;
 }
@@ -1429,14 +1447,62 @@
 	return cfqq;
 }
 
+static struct cfq_io_context *
+cfq_cic_rb_lookup(struct cfq_data *cfqd, struct io_context *ioc)
+{
+	struct rb_node *n = ioc->cic_root.rb_node;
+	struct cfq_io_context *cic;
+	void *key = cfqd;
+
+	while (n) {
+		cic = rb_entry(n, struct cfq_io_context, rb_node);
+
+		if (key < cic->key)
+			n = n->rb_left;
+		else if (key > cic->key)
+			n = n->rb_right;
+		else
+			return cic;
+	}
+
+	return NULL;
+}
+
+static inline void
+cfq_cic_rb_add(struct cfq_data *cfqd, struct io_context *ioc,
+	       struct cfq_io_context *cic)
+{
+	struct rb_node **p = &ioc->cic_root.rb_node;
+	struct rb_node *parent = NULL;
+	struct cfq_io_context *__cic;
+
+	cic->ioc = ioc;
+	cic->key = cfqd;
+
+	while (*p) {
+		parent = *p;
+		__cic = rb_entry(parent, struct cfq_io_context, rb_node);
+
+		if (cic->key < __cic->key)
+			p = &(*p)->rb_left;
+		else if (cic->key > __cic->key)
+			p = &(*p)->rb_right;
+		else
+			BUG();
+	}
+
+	rb_link_node(&cic->rb_node, parent, p);
+	rb_insert_color(&cic->rb_node, &ioc->cic_root);
+	atomic_inc(&cfqd->ref);
+}
+
 /*
  * Setup general io context and cfq io context. There can be several cfq
  * io contexts per general io context, if this process is doing io to more
- * than one device managed by cfq. Note that caller is holding a reference to
- * cfqq, so we don't need to worry about it disappearing
+ * than one device managed by cfq.
  */
 static struct cfq_io_context *
-cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask)
+cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
 {
 	struct io_context *ioc = NULL;
 	struct cfq_io_context *cic;
@@ -1447,61 +1513,17 @@
 	if (!ioc)
 		return NULL;
 
-	if ((cic = ioc->cic) == NULL) {
-		cic = cfq_alloc_io_context(cfqd, gfp_mask);
-
-		if (cic == NULL)
-			goto err;
-
-		/*
-		 * manually increment generic io_context usage count, it
-		 * cannot go away since we are already holding one ref to it
-		 */
-		ioc->cic = cic;
-		ioc->set_ioprio = cfq_ioc_set_ioprio;
-		cic->ioc = ioc;
-		cic->key = cfqd;
-		atomic_inc(&cfqd->ref);
-	} else {
-		struct cfq_io_context *__cic;
-
-		/*
-		 * the first cic on the list is actually the head itself
-		 */
-		if (cic->key == cfqd)
-			goto out;
-
-		/*
-		 * cic exists, check if we already are there. linear search
-		 * should be ok here, the list will usually not be more than
-		 * 1 or a few entries long
-		 */
-		list_for_each_entry(__cic, &cic->list, list) {
-			/*
-			 * this process is already holding a reference to
-			 * this queue, so no need to get one more
-			 */
-			if (__cic->key == cfqd) {
-				cic = __cic;
-				goto out;
-			}
-		}
+	ioc->set_ioprio = cfq_ioc_set_ioprio;
 
-		/*
-		 * nope, process doesn't have a cic assoicated with this
-		 * cfqq yet. get a new one and add to list
-		 */
-		__cic = cfq_alloc_io_context(cfqd, gfp_mask);
-		if (__cic == NULL)
-			goto err;
+	cic = cfq_cic_rb_lookup(cfqd, ioc);
+	if (cic)
+		goto out;
 
-		__cic->ioc = ioc;
-		__cic->key = cfqd;
-		atomic_inc(&cfqd->ref);
-		list_add(&__cic->list, &cic->list);
-		cic = __cic;
-	}
+	cic = cfq_alloc_io_context(cfqd, gfp_mask);
+	if (cic == NULL)
+		goto err;
 
+	cfq_cic_rb_add(cfqd, ioc, cic);
 out:
 	return cic;
 err:
@@ -1534,7 +1556,33 @@
 	cic->ttime_mean = (cic->ttime_total + 128) / cic->ttime_samples;
 }
 
-#define sample_valid(samples)	((samples) > 80)
+static void
+cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic,
+		       struct cfq_rq *crq)
+{
+	sector_t sdist;
+	u64 total;
+
+	if (cic->last_request_pos < crq->request->sector)
+		sdist = crq->request->sector - cic->last_request_pos;
+	else
+		sdist = cic->last_request_pos - crq->request->sector;
+
+	/*
+	 * Don't allow the seek distance to get too large from the
+	 * odd fragment, pagein, etc
+	 */
+	if (cic->seek_samples <= 60) /* second&third seek */
+		sdist = min(sdist, (cic->seek_mean * 4) + 2*1024*1024);
+	else
+		sdist = min(sdist, (cic->seek_mean * 4)	+ 2*1024*64);
+
+	cic->seek_samples = (7*cic->seek_samples + 256) / 8;
+	cic->seek_total = (7*cic->seek_total + (u64)256*sdist) / 8;
+	total = cic->seek_total + (cic->seek_samples/2);
+	do_div(total, cic->seek_samples);
+	cic->seek_mean = (sector_t)total;
+}
 
 /*
  * Disable idle window if the process thinks too long or seeks so much that
@@ -1608,7 +1656,7 @@
 		cfqq->slice_left = cfq_prio_to_slice(cfqd, cfqq) / 2;
 
 	cfqq->slice_end = cfqq->slice_left + jiffies;
-	__cfq_slice_expired(cfqd, cfqq, 1);
+	__cfq_slice_expired(cfqd, cfqq, 1, 1);
 	__cfq_set_active_queue(cfqd, cfqq);
 }
 
@@ -1647,9 +1695,11 @@
 	cic = crq->io_context;
 
 	cfq_update_io_thinktime(cfqd, cic);
+	cfq_update_io_seektime(cfqd, cic, crq);
 	cfq_update_idle_window(cfqd, cfqq, cic);
 
 	cic->last_queue = jiffies;
+	cic->last_request_pos = crq->request->sector + crq->request->nr_sectors;
 
 	if (cfqq == cfqd->active_queue) {
 		/*
@@ -1716,7 +1766,7 @@
 			cfq_resort_rr_list(cfqq, 0);
 		}
 		if (cfq_cfqq_expired(cfqq)) {
-			__cfq_slice_expired(cfqd, cfqq, 0);
+			__cfq_slice_expired(cfqd, cfqq, 0, 1);
 			cfq_schedule_dispatch(cfqd);
 		}
 	}
@@ -1785,14 +1835,6 @@
 		cfq_resort_rr_list(cfqq, 0);
 }
 
-static inline pid_t cfq_queue_pid(struct task_struct *task, int rw)
-{
-	if (rw == READ || process_sync(task))
-		return task->pid;
-
-	return CFQ_KEY_ASYNC;
-}
-
 static inline int
 __cfq_may_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq,
 		struct task_struct *task, int rw)
@@ -1924,21 +1966,22 @@
 
 	might_sleep_if(gfp_mask & __GFP_WAIT);
 
-	cic = cfq_get_io_context(cfqd, key, gfp_mask);
+	cic = cfq_get_io_context(cfqd, gfp_mask);
 
 	spin_lock_irqsave(q->queue_lock, flags);
 
 	if (!cic)
 		goto queue_fail;
 
-	if (!cic->cfqq) {
+	cfqq = cic->cfqq;
+	if (!cfqq || cfqq->key != key) {
 		cfqq = cfq_get_queue(cfqd, key, tsk->ioprio, gfp_mask);
 		if (!cfqq)
 			goto queue_fail;
 
-		cic->cfqq = cfqq;
-	} else
-		cfqq = cic->cfqq;
+		if (!cic->cfqq)
+			cic->cfqq = cfqq;
+	}
 
 	cfqq->allocated[rw]++;
 	cfq_clear_cfqq_must_alloc(cfqq);
@@ -2124,7 +2167,6 @@
 	for (i = 0; i < CFQ_PRIO_LISTS; i++)
 		INIT_LIST_HEAD(&cfqd->rr_list[i]);
 
-	INIT_LIST_HEAD(&cfqd->busy_rr);
 	INIT_LIST_HEAD(&cfqd->cur_rr);
 	INIT_LIST_HEAD(&cfqd->idle_rr);
 	INIT_LIST_HEAD(&cfqd->empty_list);
@@ -2137,7 +2179,7 @@
 	if (!cfqd->cfq_hash)
 		goto out_cfqhash;
 
-	cfqd->crq_pool = mempool_create(BLKDEV_MIN_RQ, mempool_alloc_slab, mempool_free_slab, crq_pool);
+	cfqd->crq_pool = mempool_create_slab_pool(BLKDEV_MIN_RQ, crq_pool);
 	if (!cfqd->crq_pool)
 		goto out_crqpool;
 
diff -urN oldtree/block/elevator.c newtree/block/elevator.c
--- oldtree/block/elevator.c	2006-02-19 11:41:00.505266288 +0000
+++ newtree/block/elevator.c	2006-02-21 15:58:12.018319496 +0000
@@ -33,6 +33,7 @@
 #include <linux/init.h>
 #include <linux/compiler.h>
 #include <linux/delay.h>
+#include <linux/blktrace_api.h>
 
 #include <asm/uaccess.h>
 
@@ -315,6 +316,8 @@
 	struct list_head *pos;
 	unsigned ordseq;
 
+	blk_add_trace_rq(q, rq, BLK_TA_INSERT);
+
 	rq->q = q;
 
 	switch (where) {
@@ -481,6 +484,7 @@
 			 * not be passed by new incoming requests
 			 */
 			rq->flags |= REQ_STARTED;
+			blk_add_trace_rq(q, rq, BLK_TA_ISSUE);
 		}
 
 		if (!q->boundary_rq || q->boundary_rq == rq) {
@@ -678,12 +682,18 @@
 	read_lock(&tasklist_lock);
 	do_each_thread(g, p) {
 		struct io_context *ioc = p->io_context;
-		if (ioc && ioc->cic) {
-			ioc->cic->exit(ioc->cic);
-			ioc->cic->dtor(ioc->cic);
-			ioc->cic = NULL;
+		struct cfq_io_context *cic;
+
+		if (!ioc)
+			continue;
+
+		if (ioc->cic_root.rb_node != NULL) {
+			cic = rb_entry(rb_first(&ioc->cic_root), struct cfq_io_context, rb_node);
+			cic->exit(ioc);
+			cic->dtor(ioc);
 		}
-		if (ioc && ioc->aic) {
+
+		if (ioc->aic) {
 			ioc->aic->exit(ioc->aic);
 			ioc->aic->dtor(ioc->aic);
 			ioc->aic = NULL;
diff -urN oldtree/block/genhd.c newtree/block/genhd.c
--- oldtree/block/genhd.c	2006-02-19 11:41:00.604251240 +0000
+++ newtree/block/genhd.c	2006-02-21 15:58:12.575234832 +0000
@@ -15,12 +15,13 @@
 #include <linux/kmod.h>
 #include <linux/kobj_map.h>
 #include <linux/buffer_head.h>
+#include <linux/mutex.h>
 
 #define MAX_PROBE_HASH 255	/* random */
 
 static struct subsystem block_subsys;
 
-static DECLARE_MUTEX(block_subsys_sem);
+static DEFINE_MUTEX(block_subsys_lock);
 
 /*
  * Can be deleted altogether. Later.
@@ -46,7 +47,7 @@
 /*
  * iterate over a list of blkdev_info structures.  allows
  * the major_names array to be iterated over from outside this file
- * must be called with the block_subsys_sem held
+ * must be called with the block_subsys_lock held
  */
 void *get_next_blkdev(void *dev)
 {
@@ -85,20 +86,20 @@
 
 void *acquire_blkdev_list(void)
 {
-        down(&block_subsys_sem);
+        mutex_lock(&block_subsys_lock);
         return get_next_blkdev(NULL);
 }
 
 void release_blkdev_list(void *dev)
 {
-        up(&block_subsys_sem);
+        mutex_unlock(&block_subsys_lock);
         kfree(dev);
 }
 
 
 /*
  * Count the number of records in the blkdev_list.
- * must be called with the block_subsys_sem held
+ * must be called with the block_subsys_lock held
  */
 int count_blkdev_list(void)
 {
@@ -118,7 +119,7 @@
 /*
  * extract the major and name values from a blkdev_info struct
  * passed in as a void to *dev.  Must be called with
- * block_subsys_sem held
+ * block_subsys_lock held
  */
 int get_blkdev_info(void *dev, int *major, char **name)
 {
@@ -138,7 +139,7 @@
 	struct blk_major_name **n, *p;
 	int index, ret = 0;
 
-	down(&block_subsys_sem);
+	mutex_lock(&block_subsys_lock);
 
 	/* temporary */
 	if (major == 0) {
@@ -183,7 +184,7 @@
 		kfree(p);
 	}
 out:
-	up(&block_subsys_sem);
+	mutex_unlock(&block_subsys_lock);
 	return ret;
 }
 
@@ -197,7 +198,7 @@
 	int index = major_to_index(major);
 	int ret = 0;
 
-	down(&block_subsys_sem);
+	mutex_lock(&block_subsys_lock);
 	for (n = &major_names[index]; *n; n = &(*n)->next)
 		if ((*n)->major == major)
 			break;
@@ -207,7 +208,7 @@
 		p = *n;
 		*n = p->next;
 	}
-	up(&block_subsys_sem);
+	mutex_unlock(&block_subsys_lock);
 	kfree(p);
 
 	return ret;
@@ -301,7 +302,7 @@
 	struct list_head *p;
 	loff_t l = *pos;
 
-	down(&block_subsys_sem);
+	mutex_lock(&block_subsys_lock);
 	list_for_each(p, &block_subsys.kset.list)
 		if (!l--)
 			return list_entry(p, struct gendisk, kobj.entry);
@@ -318,7 +319,7 @@
 
 static void part_stop(struct seq_file *part, void *v)
 {
-	up(&block_subsys_sem);
+	mutex_unlock(&block_subsys_lock);
 }
 
 static int show_partition(struct seq_file *part, void *v)
@@ -377,7 +378,7 @@
 
 static int __init genhd_device_init(void)
 {
-	bdev_map = kobj_map_init(base_probe, &block_subsys_sem);
+	bdev_map = kobj_map_init(base_probe, &block_subsys_lock);
 	blk_dev_init();
 	subsystem_register(&block_subsys);
 	return 0;
@@ -611,7 +612,7 @@
 	loff_t k = *pos;
 	struct list_head *p;
 
-	down(&block_subsys_sem);
+	mutex_lock(&block_subsys_lock);
 	list_for_each(p, &block_subsys.kset.list)
 		if (!k--)
 			return list_entry(p, struct gendisk, kobj.entry);
@@ -628,7 +629,7 @@
 
 static void diskstats_stop(struct seq_file *part, void *v)
 {
-	up(&block_subsys_sem);
+	mutex_unlock(&block_subsys_lock);
 }
 
 static int diskstats_show(struct seq_file *s, void *v)
diff -urN oldtree/block/ioctl.c newtree/block/ioctl.c
--- oldtree/block/ioctl.c	2006-02-19 11:41:00.605251088 +0000
+++ newtree/block/ioctl.c	2006-02-21 15:58:24.301452176 +0000
@@ -5,6 +5,7 @@
 #include <linux/backing-dev.h>
 #include <linux/buffer_head.h>
 #include <linux/smp_lock.h>
+#include <linux/blktrace_api.h>
 #include <asm/uaccess.h>
 
 static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user *arg)
@@ -42,9 +43,9 @@
 					return -EINVAL;
 			}
 			/* partition number in use? */
-			down(&bdev->bd_sem);
+			mutex_lock(&bdev->bd_mutex);
 			if (disk->part[part - 1]) {
-				up(&bdev->bd_sem);
+				mutex_unlock(&bdev->bd_mutex);
 				return -EBUSY;
 			}
 			/* overlap? */
@@ -55,13 +56,13 @@
 					continue;
 				if (!(start+length <= s->start_sect ||
 				      start >= s->start_sect + s->nr_sects)) {
-					up(&bdev->bd_sem);
+					mutex_unlock(&bdev->bd_mutex);
 					return -EBUSY;
 				}
 			}
 			/* all seems OK */
 			add_partition(disk, part, start, length);
-			up(&bdev->bd_sem);
+			mutex_unlock(&bdev->bd_mutex);
 			return 0;
 		case BLKPG_DEL_PARTITION:
 			if (!disk->part[part-1])
@@ -71,9 +72,9 @@
 			bdevp = bdget_disk(disk, part);
 			if (!bdevp)
 				return -ENOMEM;
-			down(&bdevp->bd_sem);
+			mutex_lock(&bdevp->bd_mutex);
 			if (bdevp->bd_openers) {
-				up(&bdevp->bd_sem);
+				mutex_unlock(&bdevp->bd_mutex);
 				bdput(bdevp);
 				return -EBUSY;
 			}
@@ -81,10 +82,10 @@
 			fsync_bdev(bdevp);
 			invalidate_bdev(bdevp, 0);
 
-			down(&bdev->bd_sem);
+			mutex_lock(&bdev->bd_mutex);
 			delete_partition(disk, part);
-			up(&bdev->bd_sem);
-			up(&bdevp->bd_sem);
+			mutex_unlock(&bdev->bd_mutex);
+			mutex_unlock(&bdevp->bd_mutex);
 			bdput(bdevp);
 
 			return 0;
@@ -102,10 +103,10 @@
 		return -EINVAL;
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
-	if (down_trylock(&bdev->bd_sem))
+	if (!mutex_trylock(&bdev->bd_mutex))
 		return -EBUSY;
 	res = rescan_partitions(disk, bdev);
-	up(&bdev->bd_sem);
+	mutex_unlock(&bdev->bd_mutex);
 	return res;
 }
 
@@ -189,6 +190,11 @@
 		return put_ulong(arg, bdev->bd_inode->i_size >> 9);
 	case BLKGETSIZE64:
 		return put_u64(arg, bdev->bd_inode->i_size);
+	case BLKTRACESTART:
+	case BLKTRACESTOP:
+	case BLKTRACESETUP:
+	case BLKTRACETEARDOWN:
+		return blk_trace_ioctl(bdev, cmd, (char __user *) arg);
 	}
 	return -ENOIOCTLCMD;
 }
diff -urN oldtree/block/ll_rw_blk.c newtree/block/ll_rw_blk.c
--- oldtree/block/ll_rw_blk.c	2006-02-19 11:41:00.607250784 +0000
+++ newtree/block/ll_rw_blk.c	2006-02-21 15:58:35.651726672 +0000
@@ -28,6 +28,7 @@
 #include <linux/writeback.h>
 #include <linux/interrupt.h>
 #include <linux/cpu.h>
+#include <linux/blktrace_api.h>
 
 /*
  * for max sense size
@@ -1551,8 +1552,10 @@
 	if (test_bit(QUEUE_FLAG_STOPPED, &q->queue_flags))
 		return;
 
-	if (!test_and_set_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags))
+	if (!test_and_set_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags)) {
 		mod_timer(&q->unplug_timer, jiffies + q->unplug_delay);
+		blk_add_trace_generic(q, NULL, 0, BLK_TA_PLUG);
+	}
 }
 
 EXPORT_SYMBOL(blk_plug_device);
@@ -1616,14 +1619,21 @@
 	/*
 	 * devices don't necessarily have an ->unplug_fn defined
 	 */
-	if (q->unplug_fn)
+	if (q->unplug_fn) {
+		blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_IO, NULL,
+					q->rq.count[READ] + q->rq.count[WRITE]);
+
 		q->unplug_fn(q);
+	}
 }
 
 static void blk_unplug_work(void *data)
 {
 	request_queue_t *q = data;
 
+	blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_IO, NULL,
+				q->rq.count[READ] + q->rq.count[WRITE]);
+
 	q->unplug_fn(q);
 }
 
@@ -1631,6 +1641,9 @@
 {
 	request_queue_t *q = (request_queue_t *)data;
 
+	blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_TIMER, NULL,
+				q->rq.count[READ] + q->rq.count[WRITE]);
+
 	kblockd_schedule_work(&q->unplug_work);
 }
 
@@ -1753,6 +1766,9 @@
 	if (q->queue_tags)
 		__blk_queue_free_tags(q);
 
+	if (q->blk_trace)
+		blk_trace_shutdown(q);
+
 	kmem_cache_free(requestq_cachep, q);
 }
 
@@ -2104,6 +2120,8 @@
 	
 	rq_init(q, rq);
 	rq->rl = rl;
+
+	blk_add_trace_generic(q, bio, rw, BLK_TA_GETRQ);
 out:
 	return rq;
 }
@@ -2132,6 +2150,8 @@
 		if (!rq) {
 			struct io_context *ioc;
 
+			blk_add_trace_generic(q, bio, rw, BLK_TA_SLEEPRQ);
+
 			__generic_unplug_device(q);
 			spin_unlock_irq(q->queue_lock);
 			io_schedule();
@@ -2185,6 +2205,8 @@
  */
 void blk_requeue_request(request_queue_t *q, struct request *rq)
 {
+	blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
+
 	if (blk_rq_tagged(rq))
 		blk_queue_end_tag(q, rq);
 
@@ -2819,6 +2841,8 @@
 			if (!q->back_merge_fn(q, req, bio))
 				break;
 
+			blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE);
+
 			req->biotail->bi_next = bio;
 			req->biotail = bio;
 			req->nr_sectors = req->hard_nr_sectors += nr_sectors;
@@ -2834,6 +2858,8 @@
 			if (!q->front_merge_fn(q, req, bio))
 				break;
 
+			blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE);
+
 			bio->bi_next = req->bio;
 			req->bio = bio;
 
@@ -2946,11 +2972,12 @@
  * bi_sector for remaps as it sees fit.  So the values of these fields
  * should NOT be depended on after the call to generic_make_request.
  */
-void generic_make_request(struct bio *bio)
+static inline void __generic_make_request(struct bio *bio)
 {
 	request_queue_t *q;
 	sector_t maxsector;
 	int ret, nr_sectors = bio_sectors(bio);
+	dev_t old_dev;
 
 	might_sleep();
 	/* Test device or partition size, when known. */
@@ -2977,6 +3004,8 @@
 	 * NOTE: we don't repeat the blk_size check for each new device.
 	 * Stacking drivers are expected to know what they are doing.
 	 */
+	maxsector = -1;
+	old_dev = 0;
 	do {
 		char b[BDEVNAME_SIZE];
 
@@ -3009,10 +3038,70 @@
 		 */
 		blk_partition_remap(bio);
 
+		if (maxsector != -1)
+			blk_add_trace_remap(q, bio, old_dev, bio->bi_sector, 
+					    maxsector);
+
+		blk_add_trace_bio(q, bio, BLK_TA_QUEUE);
+
+		maxsector = bio->bi_sector;
+		old_dev = bio->bi_bdev->bd_dev;
+
 		ret = q->make_request_fn(q, bio);
 	} while (ret);
 }
 
+/*
+ * We only want one ->make_request_fn to be active at a time,
+ * else stack usage with stacked devices could be a problem.
+ * So use current->bio_{list,tail} to keep a list of requests
+ * submited by a make_request_fn function.
+ * current->bio_tail is also used as a flag to say if
+ * generic_make_request is currently active in this task or not.
+ * If it is NULL, then no make_request is active.  If it is non-NULL,
+ * then a make_request is active, and new requests should be added
+ * at the tail
+ */
+void generic_make_request(struct bio *bio)
+{
+	if (current->bio_tail) {
+		/* make_request is active */
+		*(current->bio_tail) = bio;
+		bio->bi_next = NULL;
+		current->bio_tail = &bio->bi_next;
+		return;
+	}
+	/* following loop may be a bit non-obvious, and so deserves some
+	 * explanation.
+	 * Before entering the loop, bio->bi_next is NULL (as all callers
+	 * ensure that) so we have a list with a single bio.
+	 * We pretend that we have just taken it off a longer list, so
+	 * we assign bio_list to the next (which is NULL) and bio_tail
+	 * to &bio_list, thus initialising the bio_list of new bios to be
+	 * added.  __generic_make_request may indeed add some more bios
+	 * through a recursive call to generic_make_request.  If it
+	 * did, we find a non-NULL value in bio_list and re-enter the loop
+	 * from the top.  In this case we really did just take the bio
+	 * of the top of the list (no pretending) and so fixup bio_list and
+	 * bio_tail or bi_next, and call into __generic_make_request again.
+	 *
+	 * The loop was structured like this to make only one call to
+	 * __generic_make_request (which is important as it is large and
+	 * inlined) and to keep the structure simple.
+	 */
+	BUG_ON(bio->bi_next);
+	do {
+		current->bio_list = bio->bi_next;
+		if (bio->bi_next == NULL)
+			current->bio_tail = &current->bio_list;
+		else
+			bio->bi_next = NULL;
+		__generic_make_request(bio);
+		bio = current->bio_list;
+	} while (bio);
+	current->bio_tail = NULL; /* deactivate */
+}
+
 EXPORT_SYMBOL(generic_make_request);
 
 /**
@@ -3128,6 +3217,8 @@
 	int total_bytes, bio_nbytes, error, next_idx = 0;
 	struct bio *bio;
 
+	blk_add_trace_rq(req->q, req, BLK_TA_COMPLETE);
+
 	/*
 	 * extend uptodate bool to allow < 0 value to be direct io error
 	 */
@@ -3472,10 +3563,15 @@
 	BUG_ON(atomic_read(&ioc->refcount) == 0);
 
 	if (atomic_dec_and_test(&ioc->refcount)) {
+		struct cfq_io_context *cic;
+
 		if (ioc->aic && ioc->aic->dtor)
 			ioc->aic->dtor(ioc->aic);
-		if (ioc->cic && ioc->cic->dtor)
-			ioc->cic->dtor(ioc->cic);
+
+		if (ioc->cic_root.rb_node != NULL) {
+			cic = rb_entry(rb_first(&ioc->cic_root), struct cfq_io_context, rb_node);
+			cic->dtor(ioc);
+		}
 
 		kmem_cache_free(iocontext_cachep, ioc);
 	}
@@ -3487,6 +3583,7 @@
 {
 	unsigned long flags;
 	struct io_context *ioc;
+	struct cfq_io_context *cic;
 
 	local_irq_save(flags);
 	task_lock(current);
@@ -3498,8 +3595,11 @@
 
 	if (ioc->aic && ioc->aic->exit)
 		ioc->aic->exit(ioc->aic);
-	if (ioc->cic && ioc->cic->exit)
-		ioc->cic->exit(ioc->cic);
+
+	if (ioc->cic_root.rb_node != NULL) {
+		cic = rb_entry(rb_first(&ioc->cic_root), struct cfq_io_context, rb_node);
+		cic->exit(ioc);
+	}
 
 	put_io_context(ioc);
 }
@@ -3529,7 +3629,8 @@
 		ret->last_waited = jiffies; /* doesn't matter... */
 		ret->nr_batch_requests = 0; /* because this is 0 */
 		ret->aic = NULL;
-		ret->cic = NULL;
+		ret->cic_root.rb_node = NULL;
+
 		tsk->io_context = ret;
 	}
 
diff -urN oldtree/crypto/serpent.c newtree/crypto/serpent.c
--- oldtree/crypto/serpent.c	2006-02-19 11:41:00.619248960 +0000
+++ newtree/crypto/serpent.c	2006-02-21 15:58:36.261633952 +0000
@@ -368,10 +368,10 @@
 static void serpent_encrypt(void *ctx, u8 *dst, const u8 *src)
 {
 	const u32
-		*k = ((struct serpent_ctx *)ctx)->expkey,
-		*s = (const u32 *)src;
-	u32	*d = (u32 *)dst,
-		r0, r1, r2, r3, r4;
+		*k = ((struct serpent_ctx *)ctx)->expkey;
+	const __le32 *s = (const __le32 *)src;
+	__le32	*d = (__le32 *)dst;
+	u32	r0, r1, r2, r3, r4;
 
 /*
  * Note: The conversions between u8* and u32* might cause trouble
@@ -426,10 +426,10 @@
 static void serpent_decrypt(void *ctx, u8 *dst, const u8 *src)
 {
 	const u32
-		*k = ((struct serpent_ctx *)ctx)->expkey,
-		*s = (const u32 *)src;
-	u32	*d = (u32 *)dst,
-		r0, r1, r2, r3, r4;
+		*k = ((struct serpent_ctx *)ctx)->expkey;
+	const __le32 *s = (const __le32 *)src;
+	__le32	*d = (__le32 *)dst;
+	u32	r0, r1, r2, r3, r4;
 
 	r0 = le32_to_cpu(s[0]);
 	r1 = le32_to_cpu(s[1]);
diff -urN oldtree/drivers/Kconfig newtree/drivers/Kconfig
--- oldtree/drivers/Kconfig	2006-02-19 11:41:00.629247440 +0000
+++ newtree/drivers/Kconfig	2006-02-21 15:58:32.510204256 +0000
@@ -64,10 +64,14 @@
 
 source "drivers/mmc/Kconfig"
 
+source "drivers/leds/Kconfig"
+
 source "drivers/infiniband/Kconfig"
 
 source "drivers/sn/Kconfig"
 
 source "drivers/edac/Kconfig"
 
+source "drivers/dlm/Kconfig"
+
 endmenu
diff -urN oldtree/drivers/Makefile newtree/drivers/Makefile
--- oldtree/drivers/Makefile	2006-02-19 11:41:00.630247288 +0000
+++ newtree/drivers/Makefile	2006-02-21 15:58:32.511204104 +0000
@@ -59,6 +59,7 @@
 obj-$(CONFIG_I2C)		+= i2c/
 obj-$(CONFIG_W1)		+= w1/
 obj-$(CONFIG_HWMON)		+= hwmon/
+obj-$(CONFIG_DLM)		+= dlm/
 obj-$(CONFIG_PHONE)		+= telephony/
 obj-$(CONFIG_MD)		+= md/
 obj-$(CONFIG_BT)		+= bluetooth/
@@ -68,6 +69,7 @@
 obj-$(CONFIG_EISA)		+= eisa/
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
 obj-$(CONFIG_MMC)		+= mmc/
+obj-$(CONFIG_NEW_LEDS)		+= leds/
 obj-$(CONFIG_INFINIBAND)	+= infiniband/
 obj-$(CONFIG_SGI_SN)		+= sn/
 obj-y				+= firmware/
diff -urN oldtree/drivers/acpi/Kconfig newtree/drivers/acpi/Kconfig
--- oldtree/drivers/acpi/Kconfig	2006-02-19 11:41:00.634246680 +0000
+++ newtree/drivers/acpi/Kconfig	2006-02-21 15:58:11.066464200 +0000
@@ -231,6 +231,20 @@
 	  If you have a legacy free Toshiba laptop (such as the Libretto L1
 	  series), say Y.
 
+config ACPI_SONY
+	tristate "Sony Laptop Extras"
+	depends on X86 && ACPI
+	default m
+	  ---help---
+	  This mini-driver drives the ACPI SNC device present in the
+	  ACPI BIOS of the Sony Vaio laptops.
+
+	  It gives access to some extra laptop functionalities. In
+	  its current form, the only thing this driver does is letting
+	  the user set or query the screen brightness.
+
+	  Read <file:Documentation/acpi/sony_acpi.txt> for more information.
+
 config ACPI_CUSTOM_DSDT
 	bool "Include Custom DSDT"
 	depends on !STANDALONE
diff -urN oldtree/drivers/acpi/Makefile newtree/drivers/acpi/Makefile
--- oldtree/drivers/acpi/Makefile	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/acpi/Makefile	2006-02-21 15:58:11.066464200 +0000
@@ -55,5 +55,6 @@
 obj-$(CONFIG_ACPI_ASUS)		+= asus_acpi.o
 obj-$(CONFIG_ACPI_IBM)		+= ibm_acpi.o
 obj-$(CONFIG_ACPI_TOSHIBA)	+= toshiba_acpi.o
+obj-$(CONFIG_ACPI_SONY)		+= sony_acpi.o
 obj-y				+= scan.o motherboard.o
 obj-$(CONFIG_ACPI_HOTPLUG_MEMORY)	+= acpi_memhotplug.o
diff -urN oldtree/drivers/acpi/ac.c newtree/drivers/acpi/ac.c
--- oldtree/drivers/acpi/ac.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/acpi/ac.c	2006-02-21 15:58:09.854648424 +0000
@@ -91,8 +91,7 @@
 
 	status = acpi_evaluate_integer(ac->handle, "_PSR", NULL, &ac->state);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error reading AC Adapter state\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Error reading AC Adapter state"));
 		ac->state = ACPI_AC_STATUS_UNKNOWN;
 		return_VALUE(-ENODEV);
 	}
@@ -159,9 +158,7 @@
 	entry = create_proc_entry(ACPI_AC_FILE_STATE,
 				  S_IRUGO, acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create '%s' fs entry\n",
-				  ACPI_AC_FILE_STATE));
+		return_VALUE(-ENODEV);
 	else {
 		entry->proc_fops = &acpi_ac_fops;
 		entry->data = acpi_driver_data(device);
@@ -249,8 +246,6 @@
 					     ACPI_DEVICE_NOTIFY, acpi_ac_notify,
 					     ac);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error installing notify handler\n"));
 		result = -ENODEV;
 		goto end;
 	}
@@ -282,9 +277,6 @@
 
 	status = acpi_remove_notify_handler(ac->handle,
 					    ACPI_DEVICE_NOTIFY, acpi_ac_notify);
-	if (ACPI_FAILURE(status))
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error removing notify handler\n"));
 
 	acpi_ac_remove_fs(device);
 
diff -urN oldtree/drivers/acpi/acpi_memhotplug.c newtree/drivers/acpi/acpi_memhotplug.c
--- oldtree/drivers/acpi/acpi_memhotplug.c	2006-02-19 11:41:00.635246528 +0000
+++ newtree/drivers/acpi/acpi_memhotplug.c	2006-02-21 15:58:09.858647816 +0000
@@ -126,15 +126,14 @@
 
 	status = acpi_get_parent(handle, &phandle);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error in acpi_get_parent\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Cannot find acpi parent"));
 		return_VALUE(-EINVAL);
 	}
 
 	/* Get the parent device */
 	status = acpi_bus_get_device(phandle, &pdevice);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error in acpi_bus_get_device\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Cannot get acpi bus device"));
 		return_VALUE(-EINVAL);
 	}
 
@@ -144,7 +143,7 @@
 	 */
 	status = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error in acpi_bus_add\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Cannot add acpi bus"));
 		return_VALUE(-EINVAL);
 	}
 
@@ -189,8 +188,7 @@
 	/* Get the range from the _CRS */
 	result = acpi_memory_get_device_resources(mem_device);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "\nget_device_resources failed\n"));
+		ACPI_ERROR((AE_INFO, "get_device_resources failed"));
 		mem_device->state = MEMORY_INVALID_STATE;
 		return result;
 	}
@@ -202,7 +200,7 @@
 	result = add_memory(mem_device->start_addr,
 			    (mem_device->end_addr - mem_device->start_addr) + 1);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "\nadd_memory failed\n"));
+		ACPI_ERROR((AE_INFO, "add_memory failed"));
 		mem_device->state = MEMORY_INVALID_STATE;
 		return result;
 	}
@@ -228,7 +226,7 @@
 				      "_EJ0", &arg_list, NULL);
 	/* Return on _EJ0 failure */
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "_EJ0 failed.\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "_EJ0 failed"));
 		return_VALUE(-ENODEV);
 	}
 
@@ -258,16 +256,12 @@
 	 * Note: Assume that this function returns zero on success
 	 */
 	result = remove_memory(start, len);
-	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Hot-Remove failed.\n"));
+	if (result)
 		return_VALUE(result);
-	}
 
 	/* Power-off and eject the device */
 	result = acpi_memory_powerdown_device(mem_device);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Device Power Down failed.\n"));
 		/* Set the status of the device to invalid */
 		mem_device->state = MEMORY_INVALID_STATE;
 		return result;
@@ -294,15 +288,14 @@
 			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 					  "\nReceived DEVICE CHECK notification for device\n"));
 		if (acpi_memory_get_device(handle, &mem_device)) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Error in finding driver data\n"));
+			ACPI_ERROR((AE_INFO, "Cannot find driver data"));
 			return_VOID;
 		}
 
 		if (!acpi_memory_check_device(mem_device)) {
 			if (acpi_memory_enable_device(mem_device))
-				ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-						  "Error in acpi_memory_enable_device\n"));
+				ACPI_ERROR((AE_INFO,
+					    "Cannot enable memory device"));
 		}
 		break;
 	case ACPI_NOTIFY_EJECT_REQUEST:
@@ -310,14 +303,12 @@
 				  "\nReceived EJECT REQUEST notification for device\n"));
 
 		if (acpi_bus_get_device(handle, &device)) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Device doesn't exist\n"));
+			ACPI_ERROR((AE_INFO, "Device doesn't exist"));
 			break;
 		}
 		mem_device = acpi_driver_data(device);
 		if (!mem_device) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Driver Data is NULL\n"));
+			ACPI_ERROR((AE_INFO, "Driver Data is NULL"));
 			break;
 		}
 
@@ -328,8 +319,8 @@
 		 *      with generic sysfs driver
 		 */
 		if (acpi_memory_disable_device(mem_device))
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Error in acpi_memory_disable_device\n"));
+			ACPI_ERROR((AE_INFO,
+				    "Disable memory device\n"));
 		/*
 		 * TBD: Invoke acpi_bus_remove to cleanup data structures
 		 */
@@ -407,7 +398,7 @@
 
 	status = acpi_get_object_info(handle, &buffer);
 	if (ACPI_FAILURE(status))
-		return_ACPI_STATUS(AE_ERROR);
+		return_ACPI_STATUS(status);
 
 	info = buffer.pointer;
 	if (!(info->valid & ACPI_VALID_HID)) {
@@ -433,18 +424,15 @@
 	ACPI_FUNCTION_TRACE("acpi_memory_register_notify_handler");
 
 	status = is_memory_device(handle);
-	if (ACPI_FAILURE(status))
+	if (ACPI_FAILURE(status)){
+		ACPI_EXCEPTION((AE_INFO, status, "handle is no memory device"));
 		return_ACPI_STATUS(AE_OK);	/* continue */
+	}
 
 	status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
 					     acpi_memory_device_notify, NULL);
-	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error installing notify handler\n"));
-		return_ACPI_STATUS(AE_OK);	/* continue */
-	}
-
-	return_ACPI_STATUS(status);
+	/* continue */
+	return_ACPI_STATUS(AE_OK);
 }
 
 static acpi_status
@@ -456,19 +444,16 @@
 	ACPI_FUNCTION_TRACE("acpi_memory_deregister_notify_handler");
 
 	status = is_memory_device(handle);
-	if (ACPI_FAILURE(status))
+	if (ACPI_FAILURE(status)){
+		ACPI_EXCEPTION((AE_INFO, status, "handle is no memory device"));
 		return_ACPI_STATUS(AE_OK);	/* continue */
+	}
 
 	status = acpi_remove_notify_handler(handle,
 					    ACPI_SYSTEM_NOTIFY,
 					    acpi_memory_device_notify);
-	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error removing notify handler\n"));
-		return_ACPI_STATUS(AE_OK);	/* continue */
-	}
 
-	return_ACPI_STATUS(status);
+	return_ACPI_STATUS(AE_OK);	/* continue */
 }
 
 static int __init acpi_memory_device_init(void)
@@ -489,7 +474,7 @@
 				     NULL, NULL);
 
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "walk_namespace failed\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
 		acpi_bus_unregister_driver(&acpi_memory_device_driver);
 		return_VALUE(-ENODEV);
 	}
@@ -513,7 +498,7 @@
 				     NULL, NULL);
 
 	if (ACPI_FAILURE(status))
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "walk_namespace failed\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
 
 	acpi_bus_unregister_driver(&acpi_memory_device_driver);
 
diff -urN oldtree/drivers/acpi/asus_acpi.c newtree/drivers/acpi/asus_acpi.c
--- oldtree/drivers/acpi/asus_acpi.c	2006-02-19 11:41:00.636246376 +0000
+++ newtree/drivers/acpi/asus_acpi.c	2006-02-21 15:58:11.031469520 +0000
@@ -490,13 +490,13 @@
  */
 
 /* Generic LED functions */
-static int read_led(const char *ledname, int ledmask)
+static int read_led(const char *ledname, int ledmask, int invert)
 {
 	if (ledname) {
 		int led_status;
 
 		if (read_acpi_int(NULL, ledname, &led_status))
-			return led_status;
+			return (invert) ? !led_status : led_status;
 		else
 			printk(KERN_WARNING "Asus ACPI: Error reading LED "
 			       "status\n");
@@ -552,7 +552,7 @@
 	       void *data)
 {
 	return sprintf(page, "%d\n",
-		       read_led(hotk->methods->mled_status, MLED_ON));
+		       read_led(hotk->methods->mled_status, MLED_ON, 0));
 }
 
 static int
@@ -570,7 +570,7 @@
 	       void *data)
 {
 	return sprintf(page, "%d\n",
-		       read_led(hotk->methods->wled_status, WLED_ON));
+		       read_led(hotk->methods->wled_status, WLED_ON, 1));
 }
 
 static int
@@ -588,7 +588,7 @@
 	       void *data)
 {
 	return sprintf(page, "%d\n",
-		       read_led(hotk->methods->tled_status, TLED_ON));
+		       read_led(hotk->methods->tled_status, TLED_ON, 0));
 }
 
 static int
diff -urN oldtree/drivers/acpi/battery.c newtree/drivers/acpi/battery.c
--- oldtree/drivers/acpi/battery.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/acpi/battery.c	2006-02-21 15:58:09.859647664 +0000
@@ -141,7 +141,7 @@
 
 	status = acpi_evaluate_object(battery->handle, "_BIF", NULL, &buffer);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BIF\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF"));
 		return_VALUE(-ENODEV);
 	}
 
@@ -151,7 +151,7 @@
 
 	status = acpi_extract_package(package, &format, &data);
 	if (status != AE_BUFFER_OVERFLOW) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BIF\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
 		result = -ENODEV;
 		goto end;
 	}
@@ -165,7 +165,7 @@
 
 	status = acpi_extract_package(package, &format, &data);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BIF\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
 		kfree(data.pointer);
 		result = -ENODEV;
 		goto end;
@@ -202,7 +202,7 @@
 
 	status = acpi_evaluate_object(battery->handle, "_BST", NULL, &buffer);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BST\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST"));
 		return_VALUE(-ENODEV);
 	}
 
@@ -212,7 +212,7 @@
 
 	status = acpi_extract_package(package, &format, &data);
 	if (status != AE_BUFFER_OVERFLOW) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BST\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
 		result = -ENODEV;
 		goto end;
 	}
@@ -226,7 +226,7 @@
 
 	status = acpi_extract_package(package, &format, &data);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BST\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
 		kfree(data.pointer);
 		result = -ENODEV;
 		goto end;
@@ -458,8 +458,6 @@
 	if ((bst->state & 0x01) && (bst->state & 0x02)) {
 		seq_printf(seq,
 			   "charging state:          charging/discharging\n");
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Battery Charging and Discharging?\n"));
 	} else if (bst->state & 0x01)
 		seq_printf(seq, "charging state:          discharging\n");
 	else if (bst->state & 0x02)
@@ -609,9 +607,7 @@
 	entry = create_proc_entry(ACPI_BATTERY_FILE_INFO,
 				  S_IRUGO, acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create '%s' fs entry\n",
-				  ACPI_BATTERY_FILE_INFO));
+		return_VALUE(-ENODEV);
 	else {
 		entry->proc_fops = &acpi_battery_info_ops;
 		entry->data = acpi_driver_data(device);
@@ -622,9 +618,7 @@
 	entry = create_proc_entry(ACPI_BATTERY_FILE_STATUS,
 				  S_IRUGO, acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create '%s' fs entry\n",
-				  ACPI_BATTERY_FILE_STATUS));
+		return_VALUE(-ENODEV);
 	else {
 		entry->proc_fops = &acpi_battery_state_ops;
 		entry->data = acpi_driver_data(device);
@@ -636,9 +630,7 @@
 				  S_IFREG | S_IRUGO | S_IWUSR,
 				  acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create '%s' fs entry\n",
-				  ACPI_BATTERY_FILE_ALARM));
+		return_VALUE(-ENODEV);
 	else {
 		entry->proc_fops = &acpi_battery_alarm_ops;
 		entry->data = acpi_driver_data(device);
@@ -732,8 +724,6 @@
 					     ACPI_DEVICE_NOTIFY,
 					     acpi_battery_notify, battery);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error installing notify handler\n"));
 		result = -ENODEV;
 		goto end;
 	}
@@ -766,9 +756,6 @@
 	status = acpi_remove_notify_handler(battery->handle,
 					    ACPI_DEVICE_NOTIFY,
 					    acpi_battery_notify);
-	if (ACPI_FAILURE(status))
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error removing notify handler\n"));
 
 	acpi_battery_remove_fs(device);
 
diff -urN oldtree/drivers/acpi/bus.c newtree/drivers/acpi/bus.c
--- oldtree/drivers/acpi/bus.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/acpi/bus.c	2006-02-21 15:58:09.860647512 +0000
@@ -69,8 +69,7 @@
 
 	status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device);
 	if (ACPI_FAILURE(status) || !*device) {
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "No context for object [%p]\n",
-				  handle));
+		ACPI_EXCEPTION((AE_INFO, status, "No context for object [%p]", handle));
 		return_VALUE(-ENODEV);
 	}
 
@@ -197,8 +196,7 @@
 	/* Make sure this is a valid target state */
 
 	if (!device->flags.power_manageable) {
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-				  "Device is not power manageable\n"));
+		ACPI_INFO((AE_INFO, "Device is not power manageable"));
 		return_VALUE(-ENODEV);
 	}
 	/*
@@ -213,13 +211,13 @@
 		return_VALUE(0);
 	}
 	if (!device->power.states[state].flags.valid) {
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device does not support D%d\n",
-				  state));
+		ACPI_WARNING((AE_INFO, "Device does not support D%d", state));
 		return_VALUE(-ENODEV);
 	}
 	if (device->parent && (state < device->parent->power.state)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-				  "Cannot set device to a higher-powered state than parent\n"));
+		ACPI_WARNING((AE_INFO,
+			      "Cannot set device to a higher-powered"
+			      " state than parent"));
 		return_VALUE(-ENODEV);
 	}
 
@@ -262,9 +260,9 @@
 
       end:
 	if (result)
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-				  "Error transitioning device [%s] to D%d\n",
-				  device->pnp.bus_id, state));
+		ACPI_WARNING((AE_INFO,
+			      "Transitioning device [%s] to D%d",
+			      device->pnp.bus_id, state));
 	else
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Device [%s] transitioned to D%d\n",
@@ -579,7 +577,7 @@
 
 	status = acpi_evaluate_object(NULL, "\\_PIC", &arg_list, NULL);
 	if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PIC\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC"));
 		return_VALUE(-ENODEV);
 	}
 
diff -urN oldtree/drivers/acpi/button.c newtree/drivers/acpi/button.c
--- oldtree/drivers/acpi/button.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/acpi/button.c	2006-02-21 15:58:09.861647360 +0000
@@ -207,9 +207,7 @@
 	entry = create_proc_entry(ACPI_BUTTON_FILE_INFO,
 				  S_IRUGO, acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create '%s' fs entry\n",
-				  ACPI_BUTTON_FILE_INFO));
+		return_VALUE(-ENODEV);
 	else {
 		entry->proc_fops = &acpi_button_info_fops;
 		entry->data = acpi_driver_data(device);
@@ -221,9 +219,7 @@
 		entry = create_proc_entry(ACPI_BUTTON_FILE_STATE,
 					  S_IRUGO, acpi_device_dir(device));
 		if (!entry)
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Unable to create '%s' fs entry\n",
-					  ACPI_BUTTON_FILE_INFO));
+			return -ENODEV;
 		else {
 			entry->proc_fops = &acpi_button_state_fops;
 			entry->data = acpi_driver_data(device);
@@ -349,8 +345,8 @@
 		sprintf(acpi_device_class(device), "%s/%s",
 			ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
 	} else {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unsupported hid [%s]\n",
-				  acpi_device_hid(device)));
+		ACPI_ERROR((AE_INFO, "Unsupported hid [%s]",
+			    acpi_device_hid(device)));
 		result = -ENODEV;
 		goto end;
 	}
@@ -381,8 +377,6 @@
 	}
 
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error installing notify handler\n"));
 		result = -ENODEV;
 		goto end;
 	}
@@ -440,10 +434,6 @@
 		break;
 	}
 
-	if (ACPI_FAILURE(status))
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error removing notify handler\n"));
-
 	acpi_button_remove_fs(device);
 
 	kfree(button);
diff -urN oldtree/drivers/acpi/container.c newtree/drivers/acpi/container.c
--- oldtree/drivers/acpi/container.c	2006-02-19 11:41:00.637246224 +0000
+++ newtree/drivers/acpi/container.c	2006-02-21 15:58:09.861647360 +0000
@@ -94,7 +94,7 @@
 	ACPI_FUNCTION_TRACE("acpi_container_add");
 
 	if (!device) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "device is NULL\n"));
+		ACPI_ERROR((AE_INFO, "device is NULL"));
 		return_VALUE(-EINVAL);
 	}
 
diff -urN oldtree/drivers/acpi/debug.c newtree/drivers/acpi/debug.c
--- oldtree/drivers/acpi/debug.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/acpi/debug.c	2006-02-21 15:58:09.862647208 +0000
@@ -216,12 +216,9 @@
 	return_VALUE(error);
 
       Error:
-	ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-			  "Unable to create '%s' proc fs entry\n", name));
-
 	remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LEVEL, acpi_root_dir);
 	remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LAYER, acpi_root_dir);
-	error = -EFAULT;
+	error = -ENODEV;
 	goto Done;
 }
 
diff -urN oldtree/drivers/acpi/dispatcher/dsfield.c newtree/drivers/acpi/dispatcher/dsfield.c
--- oldtree/drivers/acpi/dispatcher/dsfield.c	2006-02-19 11:41:00.638246072 +0000
+++ newtree/drivers/acpi/dispatcher/dsfield.c	2006-02-21 15:58:09.871645840 +0000
@@ -425,6 +425,7 @@
 	 * Walk the list of entries in the field_list
 	 */
 	while (arg) {
+
 		/* Ignore OFFSET and ACCESSAS terms here */
 
 		if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
diff -urN oldtree/drivers/acpi/dispatcher/dsmethod.c newtree/drivers/acpi/dispatcher/dsmethod.c
--- oldtree/drivers/acpi/dispatcher/dsmethod.c	2006-02-19 11:41:00.640245768 +0000
+++ newtree/drivers/acpi/dispatcher/dsmethod.c	2006-02-21 15:58:09.872645688 +0000
@@ -81,6 +81,7 @@
 	/* Invoke the global exception handler */
 
 	if (acpi_gbl_exception_handler) {
+
 		/* Exit the interpreter, allow handler to execute methods */
 
 		acpi_ex_exit_interpreter();
@@ -100,6 +101,7 @@
 	}
 #ifdef ACPI_DISASSEMBLER
 	if (ACPI_FAILURE(status)) {
+
 		/* Display method locals/args if disassembler is present */
 
 		acpi_dm_dump_method_info(status, walk_state, walk_state->op);
@@ -249,6 +251,7 @@
 	}
 
 	if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) {
+
 		/* 1) Parse: Create a new walk state for the preempting walk */
 
 		next_walk_state =
@@ -378,9 +381,11 @@
 	/* Did the called method return a value? */
 
 	if (return_desc) {
+
 		/* Are we actually going to use the return value? */
 
 		if (walk_state->return_used) {
+
 			/* Save the return value from the previous method */
 
 			status = acpi_ds_result_push(return_desc, walk_state);
diff -urN oldtree/drivers/acpi/dispatcher/dsmthdat.c newtree/drivers/acpi/dispatcher/dsmthdat.c
--- oldtree/drivers/acpi/dispatcher/dsmthdat.c	2006-02-19 11:41:00.641245616 +0000
+++ newtree/drivers/acpi/dispatcher/dsmthdat.c	2006-02-21 15:58:09.873645536 +0000
@@ -701,6 +701,7 @@
 
 	object = acpi_ns_get_attached_object(node);
 	if (!object) {
+
 		/* Uninitialized local/arg, return TYPE_ANY */
 
 		return_VALUE(ACPI_TYPE_ANY);
diff -urN oldtree/drivers/acpi/dispatcher/dsobject.c newtree/drivers/acpi/dispatcher/dsobject.c
--- oldtree/drivers/acpi/dispatcher/dsobject.c	2006-02-19 11:41:00.642245464 +0000
+++ newtree/drivers/acpi/dispatcher/dsobject.c	2006-02-21 15:58:09.874645384 +0000
@@ -103,6 +103,7 @@
 									 common.
 									 node)));
 			if (ACPI_FAILURE(status)) {
+
 				/* Check if we are resolving a named reference within a package */
 
 				if ((status == AE_NOT_FOUND)
@@ -195,6 +196,7 @@
 	 */
 	obj_desc = *obj_desc_ptr;
 	if (!obj_desc) {
+
 		/* Create a new buffer object */
 
 		obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_BUFFER);
@@ -355,6 +357,7 @@
 	arg = arg->common.next;
 	for (i = 0; arg; i++) {
 		if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {
+
 			/* Object (package or buffer) is already built */
 
 			obj_desc->package.elements[i] =
@@ -408,6 +411,7 @@
 	}
 
 	if (!op->common.value.arg) {
+
 		/* No arguments, there is nothing to do */
 
 		return_ACPI_STATUS(AE_OK);
@@ -469,6 +473,7 @@
 	obj_desc = *ret_obj_desc;
 	op_info = acpi_ps_get_opcode_info(opcode);
 	if (op_info->class == AML_CLASS_UNKNOWN) {
+
 		/* Unknown opcode */
 
 		return_ACPI_STATUS(AE_TYPE);
@@ -626,6 +631,7 @@
 		default:	/* Other literals, etc.. */
 
 			if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) {
+
 				/* Node was saved in Op */
 
 				obj_desc->reference.node = op->common.node;
diff -urN oldtree/drivers/acpi/dispatcher/dsopcode.c newtree/drivers/acpi/dispatcher/dsopcode.c
--- oldtree/drivers/acpi/dispatcher/dsopcode.c	2006-02-19 11:41:00.643245312 +0000
+++ newtree/drivers/acpi/dispatcher/dsopcode.c	2006-02-21 15:58:09.875645232 +0000
@@ -640,6 +640,7 @@
 	/* Initialize the Buffer Field */
 
 	if (op->common.aml_opcode == AML_CREATE_FIELD_OP) {
+
 		/* NOTE: Slightly different operands for this opcode */
 
 		status =
@@ -984,6 +985,7 @@
 		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op));
 
 		if (walk_state->control_state->common.value) {
+
 			/* Predicate was true, go back and evaluate it again! */
 
 			status = AE_CTRL_PENDING;
@@ -1014,6 +1016,7 @@
 		 * has been bubbled up the tree
 		 */
 		if (op->common.value.arg) {
+
 			/* Since we have a real Return(), delete any implicit return */
 
 			acpi_ds_clear_implicit_return(walk_state);
@@ -1047,6 +1050,7 @@
 			walk_state->return_desc = walk_state->operands[0];
 		} else if ((walk_state->results) &&
 			   (walk_state->results->results.num_results > 0)) {
+
 			/* Since we have a real Return(), delete any implicit return */
 
 			acpi_ds_clear_implicit_return(walk_state);
diff -urN oldtree/drivers/acpi/dispatcher/dsutils.c newtree/drivers/acpi/dispatcher/dsutils.c
--- oldtree/drivers/acpi/dispatcher/dsutils.c	2006-02-19 11:41:00.644245160 +0000
+++ newtree/drivers/acpi/dispatcher/dsutils.c	2006-02-21 15:58:09.876645080 +0000
@@ -202,6 +202,7 @@
 	 */
 	if ((!op->common.parent) ||
 	    (op->common.parent->common.aml_opcode == AML_SCOPE_OP)) {
+
 		/* No parent, the return value cannot possibly be used */
 
 		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
@@ -352,6 +353,7 @@
 	}
 
 	if (!acpi_ds_is_result_used(op, walk_state)) {
+
 		/* Must pop the result stack (obj_desc should be equal to result_obj) */
 
 		status = acpi_ds_result_pop(&obj_desc, walk_state);
@@ -498,7 +500,9 @@
 		 */
 		if ((walk_state->deferred_node) &&
 		    (walk_state->deferred_node->type == ACPI_TYPE_BUFFER_FIELD)
-		    && (arg_index != 0)) {
+		    && (arg_index ==
+			(u32) ((walk_state->opcode ==
+				AML_CREATE_FIELD_OP) ? 3 : 2))) {
 			obj_desc =
 			    ACPI_CAST_PTR(union acpi_operand_object,
 					  walk_state->deferred_node);
@@ -521,6 +525,7 @@
 			    && (parent_op->common.aml_opcode != AML_REGION_OP)
 			    && (parent_op->common.aml_opcode !=
 				AML_INT_NAMEPATH_OP)) {
+
 				/* Enter name into namespace if not found */
 
 				interpreter_mode = ACPI_IMODE_LOAD_PASS2;
diff -urN oldtree/drivers/acpi/dispatcher/dswexec.c newtree/drivers/acpi/dispatcher/dswexec.c
--- oldtree/drivers/acpi/dispatcher/dswexec.c	2006-02-19 11:41:00.676240296 +0000
+++ newtree/drivers/acpi/dispatcher/dswexec.c	2006-02-21 15:58:09.876645080 +0000
@@ -409,6 +409,7 @@
 		 * being the object_type and size_of operators.
 		 */
 		if (!(walk_state->op_info->flags & AML_NO_OPERAND_RESOLVE)) {
+
 			/* Resolve all operands */
 
 			status = acpi_ex_resolve_operands(walk_state->opcode,
@@ -548,6 +549,7 @@
 			 */
 			status = acpi_ds_resolve_operands(walk_state);
 			if (ACPI_FAILURE(status)) {
+
 				/* On error, clear all resolved operands */
 
 				acpi_ds_clear_operands(walk_state);
@@ -722,6 +724,7 @@
       cleanup:
 
 	if (walk_state->result_obj) {
+
 		/* Break to debugger to display result */
 
 		ACPI_DEBUGGER_EXEC(acpi_db_display_result_object
diff -urN oldtree/drivers/acpi/dispatcher/dswload.c newtree/drivers/acpi/dispatcher/dswload.c
--- oldtree/drivers/acpi/dispatcher/dswload.c	2006-02-19 11:41:00.677240144 +0000
+++ newtree/drivers/acpi/dispatcher/dswload.c	2006-02-21 15:58:09.877644928 +0000
@@ -261,6 +261,7 @@
 		 */
 
 		if (walk_state->deferred_node) {
+
 			/* This name is already in the namespace, get the node */
 
 			node = walk_state->deferred_node;
@@ -311,6 +312,7 @@
 	/* Common exit */
 
 	if (!op) {
+
 		/* Create a new op */
 
 		op = acpi_ps_alloc_op(walk_state->opcode);
@@ -413,6 +415,7 @@
 #endif
 
 	if (op->common.aml_opcode == AML_NAME_OP) {
+
 		/* For Name opcode, get the object type from the argument */
 
 		if (op->common.value.arg) {
@@ -521,6 +524,7 @@
 		if ((walk_state->control_state) &&
 		    (walk_state->control_state->common.state ==
 		     ACPI_CONTROL_CONDITIONAL_EXECUTING)) {
+
 			/* We are executing a while loop outside of a method */
 
 			status = acpi_ds_exec_begin_op(walk_state, out_op);
@@ -554,10 +558,12 @@
 		/* Get the name we are going to enter or lookup in the namespace */
 
 		if (walk_state->opcode == AML_INT_NAMEPATH_OP) {
+
 			/* For Namepath op, get the path string */
 
 			buffer_ptr = op->common.value.string;
 			if (!buffer_ptr) {
+
 				/* No name, just exit */
 
 				return_ACPI_STATUS(AE_OK);
@@ -680,6 +686,7 @@
 		/* All other opcodes */
 
 		if (op && op->common.node) {
+
 			/* This op/node was previously entered into the namespace */
 
 			node = op->common.node;
@@ -705,6 +712,7 @@
 		 * Note: Name may already exist if we are executing a deferred opcode.
 		 */
 		if (walk_state->deferred_node) {
+
 			/* This name is already in the namespace, get the node */
 
 			node = walk_state->deferred_node;
@@ -727,6 +735,7 @@
 	}
 
 	if (!op) {
+
 		/* Create a new op */
 
 		op = acpi_ps_alloc_op(walk_state->opcode);
diff -urN oldtree/drivers/acpi/dispatcher/dswscope.c newtree/drivers/acpi/dispatcher/dswscope.c
--- oldtree/drivers/acpi/dispatcher/dswscope.c	2006-02-19 11:41:00.678239992 +0000
+++ newtree/drivers/acpi/dispatcher/dswscope.c	2006-02-21 15:58:09.878644776 +0000
@@ -66,6 +66,7 @@
 	ACPI_FUNCTION_NAME("ds_scope_stack_clear");
 
 	while (walk_state->scope_info) {
+
 		/* Pop a scope off the stack */
 
 		scope_info = walk_state->scope_info;
@@ -105,6 +106,7 @@
 	ACPI_FUNCTION_TRACE("ds_scope_stack_push");
 
 	if (!node) {
+
 		/* Invalid scope   */
 
 		ACPI_ERROR((AE_INFO, "Null scope parameter"));
diff -urN oldtree/drivers/acpi/dispatcher/dswstate.c newtree/drivers/acpi/dispatcher/dswstate.c
--- oldtree/drivers/acpi/dispatcher/dswstate.c	2006-02-19 11:41:00.679239840 +0000
+++ newtree/drivers/acpi/dispatcher/dswstate.c	2006-02-21 15:58:09.879644624 +0000
@@ -170,6 +170,7 @@
 	state->results.num_results--;
 
 	for (index = ACPI_OBJ_NUM_OPERANDS; index; index--) {
+
 		/* Check for a valid result object */
 
 		if (state->results.obj_desc[index - 1]) {
@@ -448,6 +449,7 @@
 	ACPI_FUNCTION_NAME("ds_obj_stack_pop");
 
 	for (i = 0; i < pop_count; i++) {
+
 		/* Check for stack underflow */
 
 		if (walk_state->num_operands == 0) {
@@ -494,6 +496,7 @@
 	ACPI_FUNCTION_NAME("ds_obj_stack_pop_and_delete");
 
 	for (i = 0; i < pop_count; i++) {
+
 		/* Check for stack underflow */
 
 		if (walk_state->num_operands == 0) {
@@ -598,6 +601,7 @@
 	walk_state = thread->walk_state_list;
 
 	if (walk_state) {
+
 		/* Next walk state becomes the current walk state */
 
 		thread->walk_state_list = walk_state->next;
@@ -778,6 +782,7 @@
 		}
 
 		if (parser_state->start_node) {
+
 			/* Push start scope on scope stack and make it current  */
 
 			status =
diff -urN oldtree/drivers/acpi/ec.c newtree/drivers/acpi/ec.c
--- oldtree/drivers/acpi/ec.c	2006-02-19 11:41:00.681239536 +0000
+++ newtree/drivers/acpi/ec.c	2006-02-21 15:58:09.880644472 +0000
@@ -279,7 +279,7 @@
 	atomic_set(&ec->intr.leaving_burst, 0);
 	return_VALUE(0);
       end:
-	printk(KERN_WARNING PREFIX "Error in acpi_ec_wait\n");
+	ACPI_EXCEPTION ((AE_INFO, status, "EC wait, burst mode");
 	return_VALUE(-1);
 }
 
@@ -300,7 +300,7 @@
 	atomic_set(&ec->intr.leaving_burst, 1);
 	return_VALUE(0);
 end:
-	printk(KERN_WARNING PREFIX "leave burst_mode:error\n");
+	ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode");
 	return_VALUE(-1);
 }
 #endif /* ACPI_FUTURE_USAGE */
@@ -957,9 +957,7 @@
 	entry = create_proc_entry(ACPI_EC_FILE_INFO, S_IRUGO,
 				  acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-				  "Unable to create '%s' fs entry\n",
-				  ACPI_EC_FILE_INFO));
+		return_VALUE(-ENODEV);
 	else {
 		entry->proc_fops = &acpi_ec_info_ops;
 		entry->data = acpi_driver_data(device);
@@ -1034,8 +1032,7 @@
 	    acpi_evaluate_integer(ec->common.handle, "_GPE", NULL,
 				  &ec->common.gpe_bit);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error obtaining GPE bit assignment\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Obtaining GPE bit"));
 		result = -ENODEV;
 		goto end;
 	}
@@ -1108,8 +1105,7 @@
 	    acpi_evaluate_integer(ec->common.handle, "_GPE", NULL,
 				  &ec->common.gpe_bit);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error obtaining GPE bit assignment\n"));
+		ACPI_ERROR((AE_INFO, "Obtaining GPE bit assignment"));
 		result = -ENODEV;
 		goto end;
 	}
@@ -1203,8 +1199,7 @@
 				     acpi_ec_io_ports, ec);
 	if (ACPI_FAILURE(status)
 	    || ec->common.command_addr.register_bit_width == 0) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error getting I/O port addresses"));
+		ACPI_ERROR((AE_INFO, "Error getting I/O port addresses"));
 		return_VALUE(-ENODEV);
 	}
 
diff -urN oldtree/drivers/acpi/event.c newtree/drivers/acpi/event.c
--- oldtree/drivers/acpi/event.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/acpi/event.c	2006-02-21 15:58:09.880644472 +0000
@@ -122,10 +122,7 @@
 	if (entry)
 		entry->proc_fops = &acpi_system_event_ops;
 	else {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create '%s' proc fs entry\n",
-				  "event"));
-		error = -EFAULT;
+		error = -ENODEV;
 	}
 	return_VALUE(error);
 }
diff -urN oldtree/drivers/acpi/events/evevent.c newtree/drivers/acpi/events/evevent.c
--- oldtree/drivers/acpi/events/evevent.c	2006-02-19 11:41:00.682239384 +0000
+++ newtree/drivers/acpi/events/evevent.c	2006-02-21 15:58:09.881644320 +0000
@@ -260,12 +260,14 @@
 	 * Check for all possible Fixed Events and dispatch those that are active
 	 */
 	for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
+
 		/* Both the status and enable bits must be on for this event */
 
 		if ((fixed_status & acpi_gbl_fixed_event_info[i].
 		     status_bit_mask)
 		    && (fixed_enable & acpi_gbl_fixed_event_info[i].
 			enable_bit_mask)) {
+
 			/* Found an active (signalled) event */
 
 			int_status |= acpi_ev_fixed_event_dispatch((u32) i);
diff -urN oldtree/drivers/acpi/events/evgpe.c newtree/drivers/acpi/events/evgpe.c
--- oldtree/drivers/acpi/events/evgpe.c	2006-02-19 11:41:00.682239384 +0000
+++ newtree/drivers/acpi/events/evgpe.c	2006-02-21 15:58:09.882644168 +0000
@@ -207,6 +207,7 @@
 		ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);
 
 		if (write_to_hardware) {
+
 			/* Clear the GPE (of stale events), then enable it */
 
 			status = acpi_hw_clear_gpe(gpe_event_info);
@@ -313,6 +314,7 @@
 	/* A NULL gpe_block means use the FADT-defined GPE block(s) */
 
 	if (!gpe_device) {
+
 		/* Examine GPE Block 0 and 1 (These blocks are permanent) */
 
 		for (i = 0; i < ACPI_MAX_GPE_BLOCKS; i++) {
@@ -402,6 +404,7 @@
 		 * Find all currently active GP events.
 		 */
 		for (i = 0; i < gpe_block->register_count; i++) {
+
 			/* Get the next status/enable pair */
 
 			gpe_register_info = &gpe_block->register_info[i];
@@ -437,6 +440,7 @@
 
 			enabled_status_byte = (u8) (status_reg & enable_reg);
 			if (!enabled_status_byte) {
+
 				/* No active GPEs in this register, move on */
 
 				continue;
@@ -445,6 +449,7 @@
 			/* Now look at the individual GPEs in this byte register */
 
 			for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
+
 				/* Examine one GPE bit */
 
 				if (enabled_status_byte &
diff -urN oldtree/drivers/acpi/events/evgpeblk.c newtree/drivers/acpi/events/evgpeblk.c
--- oldtree/drivers/acpi/events/evgpeblk.c	2006-02-19 11:41:00.684239080 +0000
+++ newtree/drivers/acpi/events/evgpeblk.c	2006-02-21 15:58:09.883644016 +0000
@@ -146,10 +146,12 @@
 
 	gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
 	while (gpe_xrupt_info) {
+
 		/* Walk all Gpe Blocks attached to this interrupt level */
 
 		gpe_block = gpe_xrupt_info->gpe_block_list_head;
 		while (gpe_block) {
+
 			/* One callback per GPE block */
 
 			status = gpe_walk_callback(gpe_xrupt_info, gpe_block);
@@ -195,6 +197,7 @@
 	/* Examine each GPE Register within the block */
 
 	for (i = 0; i < gpe_block->register_count; i++) {
+
 		/* Now look at the individual GPEs in this byte register */
 
 		for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
@@ -289,6 +292,7 @@
 
 	gpe_number = ACPI_STRTOUL(&name[2], NULL, 16);
 	if (gpe_number == ACPI_UINT32_MAX) {
+
 		/* Conversion failed; invalid method, just ignore it */
 
 		ACPI_ERROR((AE_INFO,
@@ -371,6 +375,7 @@
 	status = acpi_ut_evaluate_object(obj_handle, METHOD_NAME__PRW,
 					 ACPI_BTYPE_PACKAGE, &pkg_desc);
 	if (ACPI_FAILURE(status)) {
+
 		/* Ignore all errors from _PRW, we don't want to abort the subsystem */
 
 		return_ACPI_STATUS(AE_OK);
@@ -394,6 +399,7 @@
 	obj_desc = pkg_desc->package.elements[0];
 
 	if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) {
+
 		/* Use FADT-defined GPE device (from definition of _PRW) */
 
 		target_gpe_device = acpi_gbl_fadt_gpe_device;
@@ -402,6 +408,7 @@
 
 		gpe_number = (u32) obj_desc->integer.value;
 	} else if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_PACKAGE) {
+
 		/* Package contains a GPE reference and GPE number within a GPE block */
 
 		if ((obj_desc->package.count < 2) ||
@@ -679,6 +686,7 @@
 	status = acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block);
 
 	if (!gpe_block->previous && !gpe_block->next) {
+
 		/* This is the last gpe_block on this interrupt */
 
 		status = acpi_ev_delete_gpe_xrupt(gpe_block->xrupt_block);
@@ -780,6 +788,7 @@
 	this_event = gpe_event_info;
 
 	for (i = 0; i < gpe_block->register_count; i++) {
+
 		/* Init the register_info for this GPE register (8 GPEs) */
 
 		this_register->base_gpe_number =
@@ -1013,6 +1022,7 @@
 
 	for (i = 0; i < gpe_block->register_count; i++) {
 		for (j = 0; j < 8; j++) {
+
 			/* Get the info block for this particular GPE */
 
 			gpe_event_info =
@@ -1099,6 +1109,7 @@
 	 * particular block is not supported.
 	 */
 	if (acpi_gbl_FADT->gpe0_blk_len && acpi_gbl_FADT->xgpe0_blk.address) {
+
 		/* GPE block 0 exists (has both length and address > 0) */
 
 		register_count0 = (u16) (acpi_gbl_FADT->gpe0_blk_len / 2);
@@ -1121,6 +1132,7 @@
 	}
 
 	if (acpi_gbl_FADT->gpe1_blk_len && acpi_gbl_FADT->xgpe1_blk.address) {
+
 		/* GPE block 1 exists (has both length and address > 0) */
 
 		register_count1 = (u16) (acpi_gbl_FADT->gpe1_blk_len / 2);
@@ -1168,6 +1180,7 @@
 	/* Exit if there are no GPE registers */
 
 	if ((register_count0 + register_count1) == 0) {
+
 		/* GPEs are not required by ACPI, this is OK */
 
 		ACPI_DEBUG_PRINT((ACPI_DB_INIT,
diff -urN oldtree/drivers/acpi/events/evmisc.c newtree/drivers/acpi/events/evmisc.c
--- oldtree/drivers/acpi/events/evmisc.c	2006-02-19 11:41:00.685238928 +0000
+++ newtree/drivers/acpi/events/evmisc.c	2006-02-21 15:58:09.884643864 +0000
@@ -150,6 +150,7 @@
 
 	obj_desc = acpi_ns_get_attached_object(node);
 	if (obj_desc) {
+
 		/* We have the notify object, Get the right handler */
 
 		switch (node->type) {
@@ -240,6 +241,7 @@
 	 * to the device.
 	 */
 	if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) {
+
 		/* Global system notification handler */
 
 		if (acpi_gbl_system_notify.handler) {
@@ -297,6 +299,7 @@
 	/* Signal threads that are waiting for the lock */
 
 	if (acpi_gbl_global_lock_thread_count) {
+
 		/* Send sufficient units to the semaphore */
 
 		status =
@@ -335,6 +338,7 @@
 	 */
 	ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired);
 	if (acquired) {
+
 		/* Got the lock, now wake all threads waiting for it */
 
 		acpi_gbl_global_lock_acquired = TRUE;
@@ -439,6 +443,7 @@
 
 	ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired);
 	if (acquired) {
+
 		/* We got the lock */
 
 		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
@@ -492,6 +497,7 @@
 
 	acpi_gbl_global_lock_thread_count--;
 	if (acpi_gbl_global_lock_thread_count) {
+
 		/* There are still some threads holding the lock, cannot release */
 
 		return_ACPI_STATUS(AE_OK);
diff -urN oldtree/drivers/acpi/events/evregion.c newtree/drivers/acpi/events/evregion.c
--- oldtree/drivers/acpi/events/evregion.c	2006-02-19 11:41:00.686238776 +0000
+++ newtree/drivers/acpi/events/evregion.c	2006-02-21 15:58:09.885643712 +0000
@@ -164,6 +164,7 @@
 	 * Run the _REG methods for op_regions in each default address space
 	 */
 	for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) {
+
 		/* TBD: Make sure handler is the DEFAULT handler, otherwise
 		 * _REG will have already been run.
 		 */
@@ -315,6 +316,7 @@
 		 */
 		region_setup = handler_desc->address_space.setup;
 		if (!region_setup) {
+
 			/* No initialization routine, exit with error */
 
 			ACPI_ERROR((AE_INFO,
@@ -361,6 +363,7 @@
 			region_obj->region.flags |= AOPOBJ_SETUP_COMPLETE;
 
 			if (region_obj2->extra.region_context) {
+
 				/* The handler for this region was already installed */
 
 				ACPI_MEM_FREE(region_context);
@@ -463,6 +466,7 @@
 
 	handler_obj = region_obj->region.handler;
 	if (!handler_obj) {
+
 		/* This region has no handler, all done */
 
 		return_VOID;
@@ -474,6 +478,7 @@
 	last_obj_ptr = &handler_obj->address_space.region_list;
 
 	while (obj_desc) {
+
 		/* Is this the correct Region? */
 
 		if (obj_desc == region_obj) {
@@ -666,6 +671,7 @@
 
 	obj_desc = acpi_ns_get_attached_object(node);
 	if (!obj_desc) {
+
 		/* No object, just exit */
 
 		return (AE_OK);
@@ -674,10 +680,12 @@
 	/* Devices are handled different than regions */
 
 	if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_DEVICE) {
+
 		/* Check if this Device already has a handler for this address space */
 
 		next_handler_obj = obj_desc->device.handler;
 		while (next_handler_obj) {
+
 			/* Found a handler, is it for the same address space? */
 
 			if (next_handler_obj->address_space.space_id ==
@@ -839,6 +847,7 @@
 		/* Walk the handler list for this device */
 
 		while (handler_obj) {
+
 			/* Same space_id indicates a handler already installed */
 
 			if (handler_obj->address_space.space_id == space_id) {
@@ -1035,6 +1044,7 @@
 
 	obj_desc = acpi_ns_get_attached_object(node);
 	if (!obj_desc) {
+
 		/* No object, just exit */
 
 		return (AE_OK);
diff -urN oldtree/drivers/acpi/events/evrgnini.c newtree/drivers/acpi/events/evrgnini.c
--- oldtree/drivers/acpi/events/evrgnini.c	2006-02-19 11:41:00.686238776 +0000
+++ newtree/drivers/acpi/events/evrgnini.c	2006-02-21 15:58:09.886643560 +0000
@@ -199,6 +199,7 @@
 	 * handlers with that device.
 	 */
 	if (handler_obj->address_space.node == acpi_gbl_root_node) {
+
 		/* Start search from the parent object */
 
 		pci_root_node = parent_node;
@@ -220,6 +221,7 @@
 					PCI_EXPRESS_ROOT_HID_STRING,
 					sizeof(PCI_EXPRESS_ROOT_HID_STRING)))))
 				{
+
 					/* Install a handler for this PCI root bridge */
 
 					status =
@@ -478,11 +480,13 @@
 	 * ie: acpi_gbl_root_node->parent_entry being set to NULL
 	 */
 	while (node) {
+
 		/* Check to see if a handler exists */
 
 		handler_obj = NULL;
 		obj_desc = acpi_ns_get_attached_object(node);
 		if (obj_desc) {
+
 			/* Can only be a handler if the object exists */
 
 			switch (node->type) {
@@ -507,10 +511,12 @@
 			}
 
 			while (handler_obj) {
+
 				/* Is this handler of the correct type? */
 
 				if (handler_obj->address_space.space_id ==
 				    space_id) {
+
 					/* Found correct handler */
 
 					ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
diff -urN oldtree/drivers/acpi/events/evxface.c newtree/drivers/acpi/events/evxface.c
--- oldtree/drivers/acpi/events/evxface.c	2006-02-19 11:41:00.687238624 +0000
+++ newtree/drivers/acpi/events/evxface.c	2006-02-21 15:58:09.887643408 +0000
@@ -275,6 +275,7 @@
 	 * only one <external> global handler can be regsitered (per notify type).
 	 */
 	if (device == ACPI_ROOT_OBJECT) {
+
 		/* Make sure the handler is not already installed */
 
 		if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
@@ -317,6 +318,7 @@
 
 		obj_desc = acpi_ns_get_attached_object(node);
 		if (obj_desc) {
+
 			/* Object exists - make sure there's no handler */
 
 			if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
@@ -370,6 +372,7 @@
 		}
 
 		if (handler_type == ACPI_ALL_NOTIFY) {
+
 			/* Extra ref if installed in both */
 
 			acpi_ut_add_reference(notify_obj);
@@ -415,12 +418,13 @@
 
 	if ((!device) ||
 	    (!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
+		status = AE_BAD_PARAMETER;
+		goto exit;
 	}
 
 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
 	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
+		goto exit;
 	}
 
 	/* Convert and validate the device handle */
@@ -428,7 +432,7 @@
 	node = acpi_ns_map_handle_to_node(device);
 	if (!node) {
 		status = AE_BAD_PARAMETER;
-		goto unlock_and_exit;
+		goto unlock;
 	}
 
 	/* Root Object */
@@ -442,7 +446,7 @@
 		    ((handler_type & ACPI_DEVICE_NOTIFY) &&
 		     !acpi_gbl_device_notify.handler)) {
 			status = AE_NOT_EXIST;
-			goto unlock_and_exit;
+			goto unlock;
 		}
 
 		/* Make sure all deferred tasks are completed */
@@ -451,7 +455,7 @@
 		acpi_os_wait_events_complete(NULL);
 		status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
 		if (ACPI_FAILURE(status)) {
-			return_ACPI_STATUS(status);
+			goto exit;
 		}
 
 		if (handler_type & ACPI_SYSTEM_NOTIFY) {
@@ -474,7 +478,7 @@
 
 		if (!acpi_ev_is_notify_object(node)) {
 			status = AE_TYPE;
-			goto unlock_and_exit;
+			goto unlock;
 		}
 
 		/* Check for an existing internal object */
@@ -482,7 +486,7 @@
 		obj_desc = acpi_ns_get_attached_object(node);
 		if (!obj_desc) {
 			status = AE_NOT_EXIST;
-			goto unlock_and_exit;
+			goto unlock;
 		}
 
 		/* Object exists - make sure there's an existing handler */
@@ -492,7 +496,7 @@
 			if ((!notify_obj) ||
 			    (notify_obj->notify.handler != handler)) {
 				status = AE_BAD_PARAMETER;
-				goto unlock_and_exit;
+				goto unlock;
 			}
 			/* Make sure all deferred tasks are completed */
 
@@ -500,7 +504,7 @@
 			acpi_os_wait_events_complete(NULL);
 			status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
 			if (ACPI_FAILURE(status)) {
-				return_ACPI_STATUS(status);
+				goto exit;
 			}
 
 			/* Remove the handler */
@@ -513,7 +517,7 @@
 			if ((!notify_obj) ||
 			    (notify_obj->notify.handler != handler)) {
 				status = AE_BAD_PARAMETER;
-				goto unlock_and_exit;
+				goto unlock;
 			}
 			/* Make sure all deferred tasks are completed */
 
@@ -521,7 +525,7 @@
 			acpi_os_wait_events_complete(NULL);
 			status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
 			if (ACPI_FAILURE(status)) {
-				return_ACPI_STATUS(status);
+				goto exit;
 			}
 
 			/* Remove the handler */
@@ -530,8 +534,11 @@
 		}
 	}
 
-      unlock_and_exit:
+unlock:
 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+exit:
+	if (ACPI_FAILURE(status))
+		ACPI_EXCEPTION((AE_INFO, status, "Removing notify handler"));
 	return_ACPI_STATUS(status);
 }
 
@@ -570,12 +577,13 @@
 	/* Parameter validation */
 
 	if ((!address) || (type > ACPI_GPE_XRUPT_TYPE_MASK)) {
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
+		status = AE_BAD_PARAMETER;
+		goto exit;
 	}
 
 	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
 	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
+		goto exit;
 	}
 
 	/* Ensure that we have a valid GPE number */
@@ -583,7 +591,7 @@
 	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
 	if (!gpe_event_info) {
 		status = AE_BAD_PARAMETER;
-		goto unlock_and_exit;
+		goto unlock;
 	}
 
 	/* Make sure that there isn't a handler there already */
@@ -591,7 +599,7 @@
 	if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
 	    ACPI_GPE_DISPATCH_HANDLER) {
 		status = AE_ALREADY_EXISTS;
-		goto unlock_and_exit;
+		goto unlock;
 	}
 
 	/* Allocate and init handler object */
@@ -599,7 +607,7 @@
 	handler = ACPI_MEM_CALLOCATE(sizeof(struct acpi_handler_info));
 	if (!handler) {
 		status = AE_NO_MEMORY;
-		goto unlock_and_exit;
+		goto unlock;
 	}
 
 	handler->address = address;
@@ -610,7 +618,7 @@
 
 	status = acpi_ev_disable_gpe(gpe_event_info);
 	if (ACPI_FAILURE(status)) {
-		goto unlock_and_exit;
+		goto unlock;
 	}
 
 	/* Install the handler */
@@ -625,8 +633,12 @@
 
 	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 
-      unlock_and_exit:
+unlock:
 	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+exit:
+	if (ACPI_FAILURE(status))
+		ACPI_EXCEPTION((AE_INFO, status,
+				"Installing notify handler failed"));
 	return_ACPI_STATUS(status);
 }
 
diff -urN oldtree/drivers/acpi/events/evxfevnt.c newtree/drivers/acpi/events/evxfevnt.c
--- oldtree/drivers/acpi/events/evxfevnt.c	2006-02-19 11:41:00.688238472 +0000
+++ newtree/drivers/acpi/events/evxfevnt.c	2006-02-21 15:58:09.887643408 +0000
@@ -636,6 +636,7 @@
 
 	obj_desc = acpi_ns_get_attached_object(node);
 	if (!obj_desc) {
+
 		/* No object, create a new one */
 
 		obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_DEVICE);
diff -urN oldtree/drivers/acpi/events/evxfregn.c newtree/drivers/acpi/events/evxfregn.c
--- oldtree/drivers/acpi/events/evxfregn.c	2006-02-19 11:41:00.688238472 +0000
+++ newtree/drivers/acpi/events/evxfregn.c	2006-02-21 15:58:09.888643256 +0000
@@ -176,9 +176,11 @@
 	handler_obj = obj_desc->device.handler;
 	last_obj_ptr = &obj_desc->device.handler;
 	while (handler_obj) {
+
 		/* We have a handler, see if user requested this one */
 
 		if (handler_obj->address_space.space_id == space_id) {
+
 			/* Matched space_id, first dereference this in the Regions */
 
 			ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
diff -urN oldtree/drivers/acpi/executer/exconfig.c newtree/drivers/acpi/executer/exconfig.c
--- oldtree/drivers/acpi/executer/exconfig.c	2006-02-19 11:41:00.689238320 +0000
+++ newtree/drivers/acpi/executer/exconfig.c	2006-02-21 15:58:09.889643104 +0000
@@ -110,6 +110,7 @@
 
 	if (ACPI_FAILURE(status)) {
 		if (status == AE_ALREADY_EXISTS) {
+
 			/* Table already exists, just return the handle */
 
 			return_ACPI_STATUS(AE_OK);
@@ -121,6 +122,7 @@
 
 	status = acpi_ns_load_table(table_info.installed_desc, parent_node);
 	if (ACPI_FAILURE(status)) {
+
 		/* Uninstall table on error */
 
 		(void)acpi_tb_uninstall_table(table_info.installed_desc);
@@ -169,6 +171,7 @@
 	 */
 	status = acpi_tb_match_signature(operand[0]->string.pointer, NULL);
 	if (status == AE_OK) {
+
 		/* Signature matched -- don't allow override */
 
 		return_ACPI_STATUS(AE_ALREADY_EXISTS);
@@ -252,6 +255,7 @@
 	/* Parameter Data (optional) */
 
 	if (parameter_node) {
+
 		/* Store the parameter data into the optional parameter object */
 
 		status = acpi_ex_store(operand[5],
@@ -424,6 +428,7 @@
 
 	status = acpi_ex_add_table(table_ptr, acpi_gbl_root_node, &ddb_handle);
 	if (ACPI_FAILURE(status)) {
+
 		/* On error, table_ptr was deallocated above */
 
 		return_ACPI_STATUS(status);
diff -urN oldtree/drivers/acpi/executer/exconvrt.c newtree/drivers/acpi/executer/exconvrt.c
--- oldtree/drivers/acpi/executer/exconvrt.c	2006-02-19 11:41:00.690238168 +0000
+++ newtree/drivers/acpi/executer/exconvrt.c	2006-02-21 15:58:09.889643104 +0000
@@ -319,6 +319,7 @@
 		remainder = 0;
 
 		for (i = decimal_length; i > 0; i--) {
+
 			/* Divide by nth factor of 10 */
 
 			digit = integer;
@@ -346,6 +347,7 @@
 
 		hex_length = (acpi_native_uint) ACPI_MUL_2(data_width);
 		for (i = 0, j = (hex_length - 1); i < hex_length; i++, j--) {
+
 			/* Get one hex digit, most significant digits first */
 
 			string[k] =
diff -urN oldtree/drivers/acpi/executer/exdump.c newtree/drivers/acpi/executer/exdump.c
--- oldtree/drivers/acpi/executer/exdump.c	2006-02-19 11:41:00.692237864 +0000
+++ newtree/drivers/acpi/executer/exdump.c	2006-02-21 15:58:09.890642952 +0000
@@ -463,6 +463,7 @@
 	}
 
 	if (!obj_desc) {
+
 		/* This could be a null element of a package */
 
 		ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Null Object Descriptor\n"));
@@ -532,6 +533,7 @@
 				       obj_desc->reference.offset);
 
 			if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) {
+
 				/* Value is an Integer */
 
 				acpi_os_printf(" value is [%8.8X%8.8x]",
diff -urN oldtree/drivers/acpi/executer/exfield.c newtree/drivers/acpi/executer/exfield.c
--- oldtree/drivers/acpi/executer/exfield.c	2006-02-19 11:41:00.692237864 +0000
+++ newtree/drivers/acpi/executer/exfield.c	2006-02-21 15:58:09.891642800 +0000
@@ -142,6 +142,7 @@
 	length =
 	    (acpi_size) ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length);
 	if (length > acpi_gbl_integer_byte_width) {
+
 		/* Field is too large for an Integer, create a Buffer instead */
 
 		buffer_desc = acpi_ut_create_buffer_object(length);
@@ -329,6 +330,7 @@
 	    ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length);
 
 	if (length < required_length) {
+
 		/* We need to create a new buffer */
 
 		new_buffer = ACPI_MEM_CALLOCATE(required_length);
diff -urN oldtree/drivers/acpi/executer/exfldio.c newtree/drivers/acpi/executer/exfldio.c
--- oldtree/drivers/acpi/executer/exfldio.c	2006-02-19 11:41:00.792222664 +0000
+++ newtree/drivers/acpi/executer/exfldio.c	2006-02-21 15:58:09.892642648 +0000
@@ -113,6 +113,7 @@
 	}
 
 	if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS) {
+
 		/* SMBus has a non-linear address space */
 
 		return_ACPI_STATUS(AE_OK);
@@ -491,6 +492,7 @@
 				  value));
 
 		if (read_write == ACPI_READ) {
+
 			/* Read the datum from the data_register */
 
 			status =
@@ -568,6 +570,7 @@
 	/* If the mask is all ones, we don't need to worry about the update rule */
 
 	if (mask != ACPI_INTEGER_MAX) {
+
 		/* Decode the update rule */
 
 		switch (obj_desc->common_field.
@@ -704,6 +707,7 @@
 	/* Read the rest of the field */
 
 	for (i = 1; i < field_datum_count; i++) {
+
 		/* Get next input datum from the field */
 
 		field_offset += obj_desc->common_field.access_byte_width;
@@ -817,6 +821,7 @@
 	/* Write the entire field */
 
 	for (i = 1; i < field_datum_count; i++) {
+
 		/* Write merged datum to the target field */
 
 		merged_datum &= mask;
diff -urN oldtree/drivers/acpi/executer/exmisc.c newtree/drivers/acpi/executer/exmisc.c
--- oldtree/drivers/acpi/executer/exmisc.c	2006-02-19 11:41:00.793222512 +0000
+++ newtree/drivers/acpi/executer/exmisc.c	2006-02-21 15:58:09.893642496 +0000
@@ -649,6 +649,7 @@
 			/* Length and all bytes must be equal */
 
 			if ((length0 == length1) && (compare == 0)) {
+
 				/* Length and all bytes match ==> TRUE */
 
 				local_result = TRUE;
diff -urN oldtree/drivers/acpi/executer/exmutex.c newtree/drivers/acpi/executer/exmutex.c
--- oldtree/drivers/acpi/executer/exmutex.c	2006-02-19 11:41:00.794222360 +0000
+++ newtree/drivers/acpi/executer/exmutex.c	2006-02-21 15:58:09.893642496 +0000
@@ -173,6 +173,7 @@
 	/* Support for multiple acquires by the owning thread */
 
 	if (obj_desc->mutex.owner_thread) {
+
 		/* Special case for Global Lock, allow all threads */
 
 		if ((obj_desc->mutex.owner_thread->thread_id ==
@@ -192,6 +193,7 @@
 
 	status = acpi_ex_system_acquire_mutex(time_desc, obj_desc);
 	if (ACPI_FAILURE(status)) {
+
 		/* Includes failure from a timeout on time_desc */
 
 		return_ACPI_STATUS(status);
@@ -286,6 +288,7 @@
 
 	obj_desc->mutex.acquisition_depth--;
 	if (obj_desc->mutex.acquisition_depth != 0) {
+
 		/* Just decrement the depth and return */
 
 		return_ACPI_STATUS(AE_OK);
diff -urN oldtree/drivers/acpi/executer/exnames.c newtree/drivers/acpi/executer/exnames.c
--- oldtree/drivers/acpi/executer/exnames.c	2006-02-19 11:41:00.794222360 +0000
+++ newtree/drivers/acpi/executer/exnames.c	2006-02-21 15:58:09.894642344 +0000
@@ -85,6 +85,7 @@
 	 * This may actually be somewhat longer than needed.
 	 */
 	if (prefix_count == ACPI_UINT32_MAX) {
+
 		/* Special case for root */
 
 		size_needed = 1 + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1;
@@ -119,11 +120,13 @@
 	/* Set up Dual or Multi prefixes if needed */
 
 	if (num_name_segs > 2) {
+
 		/* Set up multi prefixes   */
 
 		*temp_ptr++ = AML_MULTI_NAME_PREFIX_OP;
 		*temp_ptr++ = (char)num_name_segs;
 	} else if (2 == num_name_segs) {
+
 		/* Set up dual prefixes */
 
 		*temp_ptr++ = AML_DUAL_NAME_PREFIX;
@@ -184,6 +187,7 @@
 	/* Valid name segment  */
 
 	if (index == 4) {
+
 		/* Found 4 valid characters */
 
 		char_buf[4] = '\0';
@@ -254,6 +258,7 @@
 	if (ACPI_TYPE_LOCAL_REGION_FIELD == data_type ||
 	    ACPI_TYPE_LOCAL_BANK_FIELD == data_type ||
 	    ACPI_TYPE_LOCAL_INDEX_FIELD == data_type) {
+
 		/* Disallow prefixes for types associated with field_unit names */
 
 		name_string = acpi_ex_allocate_name_string(0, 1);
@@ -410,6 +415,7 @@
 	}
 
 	if (AE_CTRL_PENDING == status && has_prefix) {
+
 		/* Ran out of segments after processing a prefix */
 
 		ACPI_ERROR((AE_INFO, "Malformed Name at %p", name_string));
diff -urN oldtree/drivers/acpi/executer/exoparg1.c newtree/drivers/acpi/executer/exoparg1.c
--- oldtree/drivers/acpi/executer/exoparg1.c	2006-02-19 11:41:00.795222208 +0000
+++ newtree/drivers/acpi/executer/exoparg1.c	2006-02-21 15:58:09.895642192 +0000
@@ -342,6 +342,7 @@
 			for (i = 0;
 			     (i < acpi_gbl_integer_nybble_width) && (digit > 0);
 			     i++) {
+
 				/* Get the least significant 4-bit BCD digit */
 
 				temp32 = ((u32) digit) & 0xF;
@@ -487,6 +488,7 @@
 		status = acpi_ex_convert_to_string(operand[0], &return_desc,
 						   ACPI_EXPLICIT_CONVERT_DECIMAL);
 		if (return_desc == operand[0]) {
+
 			/* No conversion performed, add ref to handle return value */
 			acpi_ut_add_reference(return_desc);
 		}
@@ -497,6 +499,7 @@
 		status = acpi_ex_convert_to_string(operand[0], &return_desc,
 						   ACPI_EXPLICIT_CONVERT_HEX);
 		if (return_desc == operand[0]) {
+
 			/* No conversion performed, add ref to handle return value */
 			acpi_ut_add_reference(return_desc);
 		}
@@ -506,6 +509,7 @@
 
 		status = acpi_ex_convert_to_buffer(operand[0], &return_desc);
 		if (return_desc == operand[0]) {
+
 			/* No conversion performed, add ref to handle return value */
 			acpi_ut_add_reference(return_desc);
 		}
@@ -516,6 +520,7 @@
 		status = acpi_ex_convert_to_integer(operand[0], &return_desc,
 						    ACPI_ANY_BASE);
 		if (return_desc == operand[0]) {
+
 			/* No conversion performed, add ref to handle return value */
 			acpi_ut_add_reference(return_desc);
 		}
@@ -541,6 +546,7 @@
 	}
 
 	if (ACPI_SUCCESS(status)) {
+
 		/* Store the return value computed above into the target object */
 
 		status = acpi_ex_store(return_desc, operand[1], walk_state);
@@ -625,6 +631,7 @@
 		temp_desc = operand[0];
 		if (ACPI_GET_DESCRIPTOR_TYPE(temp_desc) ==
 		    ACPI_DESC_TYPE_OPERAND) {
+
 			/* Internal reference object - prevent deletion */
 
 			acpi_ut_add_reference(temp_desc);
@@ -777,8 +784,25 @@
 
 		/* Check for a method local or argument, or standalone String */
 
-		if (ACPI_GET_DESCRIPTOR_TYPE(operand[0]) !=
+		if (ACPI_GET_DESCRIPTOR_TYPE(operand[0]) ==
 		    ACPI_DESC_TYPE_NAMED) {
+			temp_desc =
+			    acpi_ns_get_attached_object((struct
+							 acpi_namespace_node *)
+							operand[0]);
+			if (temp_desc
+			    &&
+			    ((ACPI_GET_OBJECT_TYPE(temp_desc) ==
+			      ACPI_TYPE_STRING)
+			     || (ACPI_GET_OBJECT_TYPE(temp_desc) ==
+				 ACPI_TYPE_LOCAL_REFERENCE))) {
+				operand[0] = temp_desc;
+				acpi_ut_add_reference(temp_desc);
+			} else {
+				status = AE_AML_OPERAND_TYPE;
+				goto cleanup;
+			}
+		} else {
 			switch (ACPI_GET_OBJECT_TYPE(operand[0])) {
 			case ACPI_TYPE_LOCAL_REFERENCE:
 				/*
@@ -827,13 +851,24 @@
 				break;
 
 			case ACPI_TYPE_STRING:
+				break;
 
+			default:
+				status = AE_AML_OPERAND_TYPE;
+				goto cleanup;
+			}
+		}
+
+		if (ACPI_GET_DESCRIPTOR_TYPE(operand[0]) !=
+		    ACPI_DESC_TYPE_NAMED) {
+			if (ACPI_GET_OBJECT_TYPE(operand[0]) ==
+			    ACPI_TYPE_STRING) {
 				/*
 				 * This is a deref_of (String). The string is a reference
 				 * to a named ACPI object.
 				 *
 				 * 1) Find the owning Node
-				 * 2) Dereference the node to an actual object.  Could be a
+				 * 2) Dereference the node to an actual object. Could be a
 				 *    Field, so we need to resolve the node to a value.
 				 */
 				status =
@@ -857,11 +892,6 @@
 				     (struct acpi_namespace_node, &return_desc),
 				     walk_state);
 				goto cleanup;
-
-			default:
-
-				status = AE_AML_OPERAND_TYPE;
-				goto cleanup;
 			}
 		}
 
diff -urN oldtree/drivers/acpi/executer/exoparg2.c newtree/drivers/acpi/executer/exoparg2.c
--- oldtree/drivers/acpi/executer/exoparg2.c	2006-02-19 11:41:00.796222056 +0000
+++ newtree/drivers/acpi/executer/exoparg2.c	2006-02-21 15:58:09.896642040 +0000
@@ -138,6 +138,7 @@
 			    acpi_ev_check_for_wake_only_gpe(walk_state->
 							    gpe_event_info);
 			if (ACPI_FAILURE(status)) {
+
 				/* AE_WAKE_ONLY_GPE only error, means ignore this notify */
 
 				return_ACPI_STATUS(AE_OK)
@@ -252,6 +253,7 @@
 	acpi_ut_remove_reference(return_desc2);
 
 	if (ACPI_FAILURE(status)) {
+
 		/* Delete the return object */
 
 		acpi_ut_remove_reference(return_desc1);
@@ -287,6 +289,7 @@
 	/* Execute the opcode */
 
 	if (walk_state->op_info->flags & AML_MATH) {
+
 		/* All simple math opcodes (add, etc.) */
 
 		return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
@@ -383,54 +386,70 @@
 			goto cleanup;
 		}
 
+		/* Initialize the Index reference object */
+
 		index = operand[1]->integer.value;
+		return_desc->reference.offset = (u32) index;
+		return_desc->reference.opcode = AML_INDEX_OP;
+		return_desc->reference.object = operand[0];
+
+		/*
+		 * At this point, the Source operand is a String, Buffer, or Package.
+		 * Verify that the index is within range.
+		 */
+		switch (ACPI_GET_OBJECT_TYPE(operand[0])) {
+		case ACPI_TYPE_STRING:
+
+			if (index >= operand[0]->string.length) {
+				status = AE_AML_STRING_LIMIT;
+			}
+
+			return_desc->reference.target_type =
+			    ACPI_TYPE_BUFFER_FIELD;
+			break;
+
+		case ACPI_TYPE_BUFFER:
+
+			if (index >= operand[0]->buffer.length) {
+				status = AE_AML_BUFFER_LIMIT;
+			}
 
-		/* At this point, the Source operand is a Package, Buffer, or String */
+			return_desc->reference.target_type =
+			    ACPI_TYPE_BUFFER_FIELD;
+			break;
 
-		if (ACPI_GET_OBJECT_TYPE(operand[0]) == ACPI_TYPE_PACKAGE) {
-			/* Object to be indexed is a Package */
+		case ACPI_TYPE_PACKAGE:
 
 			if (index >= operand[0]->package.count) {
-				ACPI_ERROR((AE_INFO,
-					    "Index value (%X%8.8X) beyond package end (%X)",
-					    ACPI_FORMAT_UINT64(index),
-					    operand[0]->package.count));
 				status = AE_AML_PACKAGE_LIMIT;
-				goto cleanup;
 			}
 
 			return_desc->reference.target_type = ACPI_TYPE_PACKAGE;
-			return_desc->reference.object = operand[0];
 			return_desc->reference.where =
 			    &operand[0]->package.elements[index];
-		} else {
-			/* Object to be indexed is a Buffer/String */
+			break;
 
-			if (index >= operand[0]->buffer.length) {
-				ACPI_ERROR((AE_INFO,
-					    "Index value (%X%8.8X) beyond end of buffer (%X)",
-					    ACPI_FORMAT_UINT64(index),
-					    operand[0]->buffer.length));
-				status = AE_AML_BUFFER_LIMIT;
-				goto cleanup;
-			}
+		default:
 
-			return_desc->reference.target_type =
-			    ACPI_TYPE_BUFFER_FIELD;
-			return_desc->reference.object = operand[0];
+			status = AE_AML_INTERNAL;
+			goto cleanup;
+		}
+
+		/* Failure means that the Index was beyond the end of the object */
+
+		if (ACPI_FAILURE(status)) {
+			ACPI_EXCEPTION((AE_INFO, status,
+					"Index (%X%8.8X) is beyond end of object",
+					ACPI_FORMAT_UINT64(index)));
+			goto cleanup;
 		}
 
 		/*
 		 * Add a reference to the target package/buffer/string for the life
-		 * of the index.
+		 * of the index
 		 */
 		acpi_ut_add_reference(operand[0]);
 
-		/* Complete the Index reference object */
-
-		return_desc->reference.opcode = AML_INDEX_OP;
-		return_desc->reference.offset = (u32) index;
-
 		/* Store the reference to the Target */
 
 		status = acpi_ex_store(return_desc, operand[2], walk_state);
@@ -509,6 +528,7 @@
 	/* Execute the Opcode */
 
 	if (walk_state->op_info->flags & AML_LOGICAL_NUMERIC) {
+
 		/* logical_op (Operand0, Operand1) */
 
 		status = acpi_ex_do_logical_numeric_op(walk_state->opcode,
@@ -518,6 +538,7 @@
 						       value, &logical_result);
 		goto store_logical_result;
 	} else if (walk_state->op_info->flags & AML_LOGICAL) {
+
 		/* logical_op (Operand0, Operand1) */
 
 		status = acpi_ex_do_logical_op(walk_state->opcode, operand[0],
diff -urN oldtree/drivers/acpi/executer/exoparg3.c newtree/drivers/acpi/executer/exoparg3.c
--- oldtree/drivers/acpi/executer/exoparg3.c	2006-02-19 11:41:00.796222056 +0000
+++ newtree/drivers/acpi/executer/exoparg3.c	2006-02-21 15:58:09.897641888 +0000
@@ -208,6 +208,7 @@
 			/* If the requested length is zero, don't allocate a buffer */
 
 			if (length > 0) {
+
 				/* Allocate a new buffer for the Buffer */
 
 				buffer = ACPI_MEM_CALLOCATE(length);
@@ -225,6 +226,7 @@
 		}
 
 		if (buffer) {
+
 			/* We have a buffer, copy the portion requested */
 
 			ACPI_MEMCPY(buffer, operand[0]->string.pointer + index,
diff -urN oldtree/drivers/acpi/executer/exoparg6.c newtree/drivers/acpi/executer/exoparg6.c
--- oldtree/drivers/acpi/executer/exoparg6.c	2006-02-19 11:41:00.797221904 +0000
+++ newtree/drivers/acpi/executer/exoparg6.c	2006-02-21 15:58:09.897641888 +0000
@@ -276,6 +276,7 @@
 		 * match was found.
 		 */
 		for (; index < operand[0]->package.count; index++) {
+
 			/* Get the current package element */
 
 			this_element = operand[0]->package.elements[index];
diff -urN oldtree/drivers/acpi/executer/exregion.c newtree/drivers/acpi/executer/exregion.c
--- oldtree/drivers/acpi/executer/exregion.c	2006-02-19 11:41:00.798221752 +0000
+++ newtree/drivers/acpi/executer/exregion.c	2006-02-21 15:58:09.898641736 +0000
@@ -135,6 +135,7 @@
 		 * Delete the existing mapping and create a new one.
 		 */
 		if (mem_info->mapped_length) {
+
 			/* Valid mapping, delete it */
 
 			acpi_os_unmap_memory(mem_info->mapped_logical_address,
diff -urN oldtree/drivers/acpi/executer/exresnte.c newtree/drivers/acpi/executer/exresnte.c
--- oldtree/drivers/acpi/executer/exresnte.c	2006-02-19 11:41:00.799221600 +0000
+++ newtree/drivers/acpi/executer/exresnte.c	2006-02-21 15:58:09.898641736 +0000
@@ -103,6 +103,7 @@
 
 	if ((entry_type == ACPI_TYPE_LOCAL_ALIAS) ||
 	    (entry_type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) {
+
 		/* There is always exactly one level of indirection */
 
 		node = ACPI_CAST_PTR(struct acpi_namespace_node, node->object);
@@ -141,6 +142,7 @@
 
 		status = acpi_ds_get_package_arguments(source_desc);
 		if (ACPI_SUCCESS(status)) {
+
 			/* Return an additional reference to the object */
 
 			obj_desc = source_desc;
@@ -158,6 +160,7 @@
 
 		status = acpi_ds_get_buffer_arguments(source_desc);
 		if (ACPI_SUCCESS(status)) {
+
 			/* Return an additional reference to the object */
 
 			obj_desc = source_desc;
@@ -240,6 +243,8 @@
 			/* This is a ddb_handle */
 			/* Return an additional reference to the object */
 
+		case AML_REF_OF_OP:
+
 			obj_desc = source_desc;
 			acpi_ut_add_reference(obj_desc);
 			break;
diff -urN oldtree/drivers/acpi/executer/exresolv.c newtree/drivers/acpi/executer/exresolv.c
--- oldtree/drivers/acpi/executer/exresolv.c	2006-02-19 11:41:00.800221448 +0000
+++ newtree/drivers/acpi/executer/exresolv.c	2006-02-21 15:58:09.900641432 +0000
@@ -382,10 +382,16 @@
 	while (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_REFERENCE) {
 		switch (obj_desc->reference.opcode) {
 		case AML_REF_OF_OP:
+		case AML_INT_NAMEPATH_OP:
 
 			/* Dereference the reference pointer */
 
-			node = obj_desc->reference.object;
+			if (obj_desc->reference.opcode == AML_REF_OF_OP) {
+				node = obj_desc->reference.object;
+			} else {	/* AML_INT_NAMEPATH_OP */
+
+				node = obj_desc->reference.node;
+			}
 
 			/* All "References" point to a NS node */
 
@@ -401,6 +407,7 @@
 
 			obj_desc = acpi_ns_get_attached_object(node);
 			if (!obj_desc) {
+
 				/* No object, use the NS node type */
 
 				type = acpi_ns_get_type(node);
@@ -432,6 +439,7 @@
 			 */
 			obj_desc = *(obj_desc->reference.where);
 			if (!obj_desc) {
+
 				/* NULL package elements are allowed */
 
 				type = 0;	/* Uninitialized */
@@ -439,39 +447,6 @@
 			}
 			break;
 
-		case AML_INT_NAMEPATH_OP:
-
-			/* Dereference the reference pointer */
-
-			node = obj_desc->reference.node;
-
-			/* All "References" point to a NS node */
-
-			if (ACPI_GET_DESCRIPTOR_TYPE(node) !=
-			    ACPI_DESC_TYPE_NAMED) {
-				ACPI_ERROR((AE_INFO, "Not a NS node %p [%s]",
-					    node,
-					    acpi_ut_get_descriptor_name(node)));
-				return_ACPI_STATUS(AE_AML_INTERNAL);
-			}
-
-			/* Get the attached object */
-
-			obj_desc = acpi_ns_get_attached_object(node);
-			if (!obj_desc) {
-				/* No object, use the NS node type */
-
-				type = acpi_ns_get_type(node);
-				goto exit;
-			}
-
-			/* Check for circular references */
-
-			if (obj_desc == operand) {
-				return_ACPI_STATUS(AE_AML_CIRCULAR_REFERENCE);
-			}
-			break;
-
 		case AML_LOCAL_OP:
 		case AML_ARG_OP:
 
diff -urN oldtree/drivers/acpi/executer/exresop.c newtree/drivers/acpi/executer/exresop.c
--- oldtree/drivers/acpi/executer/exresop.c	2006-02-19 11:41:00.800221448 +0000
+++ newtree/drivers/acpi/executer/exresop.c	2006-02-21 15:58:09.900641432 +0000
@@ -77,6 +77,7 @@
 	ACPI_FUNCTION_ENTRY();
 
 	if (type_needed == ACPI_TYPE_ANY) {
+
 		/* All types OK, so we don't perform any typechecks */
 
 		return (AE_OK);
@@ -224,6 +225,7 @@
 			}
 
 			if (object_type == (u8) ACPI_TYPE_LOCAL_REFERENCE) {
+
 				/* Decode the Reference */
 
 				op_info = acpi_ps_get_opcode_info(opcode);
@@ -332,6 +334,7 @@
 			}
 
 			if (obj_desc->reference.opcode == AML_NAME_OP) {
+
 				/* Convert a named reference to the actual named object */
 
 				temp_node = obj_desc->reference.object;
@@ -662,6 +665,7 @@
 				}
 
 				if (target_op == AML_DEBUG_OP) {
+
 					/* Allow store of any object to the Debug object */
 
 					break;
diff -urN oldtree/drivers/acpi/executer/exstore.c newtree/drivers/acpi/executer/exstore.c
--- oldtree/drivers/acpi/executer/exstore.c	2006-02-19 11:41:00.801221296 +0000
+++ newtree/drivers/acpi/executer/exstore.c	2006-02-21 15:58:09.901641280 +0000
@@ -423,6 +423,7 @@
 		}
 
 		if (obj_desc) {
+
 			/* Decrement reference count by the ref count of the parent package */
 
 			for (i = 0; i < ((union acpi_operand_object *)
@@ -572,6 +573,7 @@
 	/* If no implicit conversion, drop into the default case below */
 
 	if ((!implicit_conversion) || (walk_state->opcode == AML_COPY_OP)) {
+
 		/* Force execution of default (no implicit conversion) */
 
 		target_type = ACPI_TYPE_ANY;
diff -urN oldtree/drivers/acpi/executer/exstoren.c newtree/drivers/acpi/executer/exstoren.c
--- oldtree/drivers/acpi/executer/exstoren.c	2006-02-19 11:41:00.802221144 +0000
+++ newtree/drivers/acpi/executer/exstoren.c	2006-02-21 15:58:09.902641128 +0000
@@ -97,6 +97,7 @@
 		 */
 		if (ACPI_GET_OBJECT_TYPE(source_desc) ==
 		    ACPI_TYPE_LOCAL_REFERENCE) {
+
 			/* Resolve a reference object first */
 
 			status =
@@ -121,6 +122,7 @@
 		    !((ACPI_GET_OBJECT_TYPE(source_desc) ==
 		       ACPI_TYPE_LOCAL_REFERENCE)
 		      && (source_desc->reference.opcode == AML_LOAD_OP))) {
+
 			/* Conversion successful but still not a valid type */
 
 			ACPI_ERROR((AE_INFO,
@@ -289,6 +291,7 @@
 	}
 
 	if (actual_src_desc != source_desc) {
+
 		/* Delete the intermediate (temporary) source object */
 
 		acpi_ut_remove_reference(actual_src_desc);
diff -urN oldtree/drivers/acpi/executer/exstorob.c newtree/drivers/acpi/executer/exstorob.c
--- oldtree/drivers/acpi/executer/exstorob.c	2006-02-19 11:41:00.802221144 +0000
+++ newtree/drivers/acpi/executer/exstorob.c	2006-02-21 15:58:09.902641128 +0000
@@ -91,6 +91,7 @@
 	/* Copy source buffer to target buffer */
 
 	if (length <= target_desc->buffer.length) {
+
 		/* Clear existing buffer and copy in the new one */
 
 		ACPI_MEMSET(target_desc->buffer.pointer, 0,
@@ -113,6 +114,7 @@
 		 * copy must not truncate the original buffer.
 		 */
 		if (original_src_type == ACPI_TYPE_STRING) {
+
 			/* Set the new length of the target */
 
 			target_desc->buffer.length = length;
@@ -183,6 +185,7 @@
 		 */
 		if (target_desc->string.pointer &&
 		    (!(target_desc->common.flags & AOPOBJ_STATIC_POINTER))) {
+
 			/* Only free if not a pointer into the DSDT */
 
 			ACPI_MEM_FREE(target_desc->string.pointer);
diff -urN oldtree/drivers/acpi/executer/exsystem.c newtree/drivers/acpi/executer/exsystem.c
--- oldtree/drivers/acpi/executer/exsystem.c	2006-02-19 11:41:00.803220992 +0000
+++ newtree/drivers/acpi/executer/exsystem.c	2006-02-21 15:58:09.903640976 +0000
@@ -76,6 +76,7 @@
 	}
 
 	if (status == AE_TIME) {
+
 		/* We must wait, so unlock the interpreter */
 
 		acpi_ex_exit_interpreter();
@@ -90,6 +91,7 @@
 
 		status2 = acpi_ex_enter_interpreter();
 		if (ACPI_FAILURE(status2)) {
+
 			/* Report fatal error, could not acquire interpreter */
 
 			return_ACPI_STATUS(status2);
diff -urN oldtree/drivers/acpi/executer/exutils.c newtree/drivers/acpi/executer/exutils.c
--- oldtree/drivers/acpi/executer/exutils.c	2006-02-19 11:41:00.803220992 +0000
+++ newtree/drivers/acpi/executer/exutils.c	2006-02-21 15:58:09.903640976 +0000
@@ -194,6 +194,7 @@
 	/* Only attempt lock if the always_lock bit is set */
 
 	if (field_flags & AML_FIELD_LOCK_RULE_MASK) {
+
 		/* We should attempt to get the lock, wait forever */
 
 		status = acpi_ev_acquire_global_lock(ACPI_WAIT_FOREVER);
@@ -230,10 +231,12 @@
 	/* Only attempt unlock if the caller locked it */
 
 	if (locked_by_me) {
+
 		/* OK, now release the lock */
 
 		status = acpi_ev_release_global_lock();
 		if (ACPI_FAILURE(status)) {
+
 			/* Report the error, but there isn't much else we can do */
 
 			ACPI_EXCEPTION((AE_INFO, status,
diff -urN oldtree/drivers/acpi/fan.c newtree/drivers/acpi/fan.c
--- oldtree/drivers/acpi/fan.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/acpi/fan.c	2006-02-21 15:58:09.904640824 +0000
@@ -149,9 +149,7 @@
 				  S_IFREG | S_IRUGO | S_IWUSR,
 				  acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create '%s' fs entry\n",
-				  ACPI_FAN_FILE_STATE));
+		return_VALUE(-ENODEV);
 	else {
 		entry->proc_fops = &acpi_fan_state_ops;
 		entry->data = acpi_driver_data(device);
@@ -201,8 +199,7 @@
 
 	result = acpi_bus_get_power(fan->handle, &state);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error reading power state\n"));
+		ACPI_ERROR((AE_INFO, "Reading power state"));
 		goto end;
 	}
 
diff -urN oldtree/drivers/acpi/hardware/hwgpe.c newtree/drivers/acpi/hardware/hwgpe.c
--- oldtree/drivers/acpi/hardware/hwgpe.c	2006-02-19 11:41:00.804220840 +0000
+++ newtree/drivers/acpi/hardware/hwgpe.c	2006-02-21 15:58:09.904640824 +0000
@@ -214,6 +214,7 @@
 	/* Examine each GPE Register within the block */
 
 	for (i = 0; i < gpe_block->register_count; i++) {
+
 		/* Disable all GPEs in this register */
 
 		status = acpi_hw_low_level_write(8, 0x00,
@@ -250,6 +251,7 @@
 	/* Examine each GPE Register within the block */
 
 	for (i = 0; i < gpe_block->register_count; i++) {
+
 		/* Clear status on all GPEs in this register */
 
 		status = acpi_hw_low_level_write(8, 0xFF,
diff -urN oldtree/drivers/acpi/hardware/hwregs.c newtree/drivers/acpi/hardware/hwregs.c
--- oldtree/drivers/acpi/hardware/hwregs.c	2006-02-19 11:41:00.805220688 +0000
+++ newtree/drivers/acpi/hardware/hwregs.c	2006-02-21 15:58:09.905640672 +0000
@@ -295,6 +295,7 @@
 	}
 
 	if (ACPI_SUCCESS(status)) {
+
 		/* Normalize the value that was read */
 
 		register_value =
diff -urN oldtree/drivers/acpi/hardware/hwsleep.c newtree/drivers/acpi/hardware/hwsleep.c
--- oldtree/drivers/acpi/hardware/hwsleep.c	2006-02-19 11:41:00.806220536 +0000
+++ newtree/drivers/acpi/hardware/hwsleep.c	2006-02-21 15:58:09.906640520 +0000
@@ -490,6 +490,7 @@
 					       ACPI_REGISTER_PM1_CONTROL,
 					       &PM1Acontrol);
 		if (ACPI_SUCCESS(status)) {
+
 			/* Clear SLP_EN and SLP_TYP fields */
 
 			PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask |
diff -urN oldtree/drivers/acpi/hardware/hwtimer.c newtree/drivers/acpi/hardware/hwtimer.c
--- oldtree/drivers/acpi/hardware/hwtimer.c	2006-02-19 11:41:00.807220384 +0000
+++ newtree/drivers/acpi/hardware/hwtimer.c	2006-02-21 15:58:09.906640520 +0000
@@ -155,6 +155,7 @@
 		delta_ticks = end_ticks - start_ticks;
 	} else if (start_ticks > end_ticks) {
 		if (0 == acpi_gbl_FADT->tmr_val_ext) {
+
 			/* 24-bit Timer */
 
 			delta_ticks =
diff -urN oldtree/drivers/acpi/hotkey.c newtree/drivers/acpi/hotkey.c
--- oldtree/drivers/acpi/hotkey.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/acpi/hotkey.c	2006-02-21 15:58:09.907640368 +0000
@@ -356,9 +356,6 @@
 	proc = create_proc_entry(proc_name, mode, hotkey_proc_dir);
 
 	if (!proc) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Hotkey: Unable to create %s entry\n",
-				  device->poll_hotkey.poll_method));
 		return_VALUE(-ENODEV);
 	} else {
 		proc->proc_fops = &hotkey_polling_fops;
@@ -769,7 +766,7 @@
 
 	if (copy_from_user(config_record, buffer, count)) {
 		kfree(config_record);
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data \n"));
+		ACPI_ERROR((AE_INFO, "Invalid data"));
 		return_VALUE(-EINVAL);
 	}
 	config_record[count] = 0;
@@ -790,8 +787,7 @@
 		kfree(bus_method);
 		kfree(action_handle);
 		kfree(method);
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Invalid data format ret=%d\n", ret));
+		ACPI_ERROR((AE_INFO, "Invalid data format ret=%d", ret));
 		return_VALUE(-EINVAL);
 	}
 
@@ -804,7 +800,7 @@
 		tmp = get_hotkey_by_event(&global_hotkey_list,
 					  internal_event_num);
 		if (!tmp)
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid key"));
+			ACPI_ERROR((AE_INFO, "Invalid key"));
 		else
 			memcpy(key, tmp, sizeof(union acpi_hotkey));
 		goto cont_cmd;
@@ -826,7 +822,7 @@
 		else
 			free_poll_hotkey_buffer(key);
 		kfree(key);
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid hotkey \n"));
+		ACPI_ERROR((AE_INFO, "Invalid hotkey"));
 		return_VALUE(-EINVAL);
 	}
 
@@ -860,7 +856,7 @@
 	else
 		free_poll_hotkey_buffer(key);
 	kfree(key);
-	ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid key\n"));
+	ACPI_ERROR((AE_INFO, "invalid key"));
 	return_VALUE(-EINVAL);
 }
 
@@ -905,7 +901,7 @@
 		val->integer.value = out_obj.integer.value;
 		val->type = out_obj.type;
 	} else
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "null val pointer"));
+		ACPI_ERROR((AE_INFO, "null val pointer"));
 	return_VALUE((status == AE_OK)
 		     && (out_obj.type == ACPI_TYPE_INTEGER));
 }
@@ -952,14 +948,14 @@
 
 	if (copy_from_user(arg, buffer, count)) {
 		kfree(arg);
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 2"));
+		ACPI_ERROR((AE_INFO, "Invalid argument 2"));
 		return_VALUE(-EINVAL);
 	}
 
 	if (sscanf(arg, "%d:%d:%d:%d", &event, &method_type, &type, &value) !=
 	    4) {
 		kfree(arg);
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 3"));
+		ACPI_ERROR((AE_INFO, "Invalid argument 3"));
 		return_VALUE(-EINVAL);
 	}
 	kfree(arg);
@@ -985,7 +981,7 @@
 
 		}
 	} else {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Not supported"));
+		ACPI_WARNING((AE_INFO, "Not supported"));
 		return_VALUE(-EINVAL);
 	}
 	return_VALUE(count);
@@ -1011,9 +1007,6 @@
 
 	hotkey_proc_dir = proc_mkdir(HOTKEY_PROC, acpi_root_dir);
 	if (!hotkey_proc_dir) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Hotkey: Unable to create %s entry\n",
-				  HOTKEY_PROC));
 		return (-ENODEV);
 	}
 	hotkey_proc_dir->owner = THIS_MODULE;
@@ -1021,9 +1014,6 @@
 	hotkey_config =
 	    create_proc_entry(HOTKEY_EV_CONFIG, mode, hotkey_proc_dir);
 	if (!hotkey_config) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Hotkey: Unable to create %s entry\n",
-				  HOTKEY_EV_CONFIG));
 		goto do_fail1;
 	} else {
 		hotkey_config->proc_fops = &hotkey_config_fops;
@@ -1036,10 +1026,6 @@
 	hotkey_poll_config =
 	    create_proc_entry(HOTKEY_PL_CONFIG, mode, hotkey_proc_dir);
 	if (!hotkey_poll_config) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Hotkey: Unable to create %s entry\n",
-				  HOTKEY_EV_CONFIG));
-
 		goto do_fail2;
 	} else {
 		hotkey_poll_config->proc_fops = &hotkey_poll_config_fops;
@@ -1051,9 +1037,6 @@
 
 	hotkey_action = create_proc_entry(HOTKEY_ACTION, mode, hotkey_proc_dir);
 	if (!hotkey_action) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Hotkey: Unable to create %s entry\n",
-				  HOTKEY_ACTION));
 		goto do_fail3;
 	} else {
 		hotkey_action->proc_fops = &hotkey_action_fops;
@@ -1064,9 +1047,6 @@
 
 	hotkey_info = create_proc_entry(HOTKEY_INFO, mode, hotkey_proc_dir);
 	if (!hotkey_info) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Hotkey: Unable to create %s entry\n",
-				  HOTKEY_INFO));
 		goto do_fail4;
 	} else {
 		hotkey_info->proc_fops = &hotkey_info_fops;
diff -urN oldtree/drivers/acpi/namespace/nsaccess.c newtree/drivers/acpi/namespace/nsaccess.c
--- oldtree/drivers/acpi/namespace/nsaccess.c	2006-02-19 11:41:00.808220232 +0000
+++ newtree/drivers/acpi/namespace/nsaccess.c	2006-02-21 15:58:09.908640216 +0000
@@ -98,6 +98,7 @@
 			  "Entering predefined entries into namespace\n"));
 
 	for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) {
+
 		/* _OSI is optional for now, will be permanent later */
 
 		if (!ACPI_STRCMP(init_val->name, "_OSI")
@@ -365,6 +366,7 @@
 	 * Begin examination of the actual pathname
 	 */
 	if (!pathname) {
+
 		/* A Null name_path is allowed and refers to the root */
 
 		num_segments = 0;
@@ -389,6 +391,7 @@
 		 * to the current scope).
 		 */
 		if (*path == (u8) AML_ROOT_PREFIX) {
+
 			/* Pathname is fully qualified, start from the root */
 
 			this_node = acpi_gbl_root_node;
@@ -416,6 +419,7 @@
 			this_node = prefix_node;
 			num_carats = 0;
 			while (*path == (u8) AML_PARENT_PREFIX) {
+
 				/* Name is fully qualified, no search rules apply */
 
 				search_parent_flag = ACPI_NS_NO_UPSEARCH;
@@ -430,6 +434,7 @@
 				num_carats++;
 				this_node = acpi_ns_get_parent_node(this_node);
 				if (!this_node) {
+
 					/* Current scope has no parent scope */
 
 					ACPI_ERROR((AE_INFO,
@@ -569,6 +574,7 @@
 					     &this_node);
 		if (ACPI_FAILURE(status)) {
 			if (status == AE_NOT_FOUND) {
+
 				/* Name not found in ACPI namespace */
 
 				ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
@@ -602,6 +608,7 @@
 		    (type_to_check_for != ACPI_TYPE_LOCAL_SCOPE) &&
 		    (this_node->type != ACPI_TYPE_ANY) &&
 		    (this_node->type != type_to_check_for)) {
+
 			/* Complain about a type mismatch */
 
 			ACPI_WARNING((AE_INFO,
diff -urN oldtree/drivers/acpi/namespace/nsalloc.c newtree/drivers/acpi/namespace/nsalloc.c
--- oldtree/drivers/acpi/namespace/nsalloc.c	2006-02-19 11:41:00.809220080 +0000
+++ newtree/drivers/acpi/namespace/nsalloc.c	2006-02-21 15:58:09.909640064 +0000
@@ -115,6 +115,7 @@
 	}
 
 	if (prev_node) {
+
 		/* Node is not first child, unlink it */
 
 		prev_node->peer = next_node->peer;
@@ -125,6 +126,7 @@
 		/* Node is first child (has no previous peer) */
 
 		if (next_node->flags & ANOBJ_END_OF_PEER_LIST) {
+
 			/* No peers at all */
 
 			parent_node->child = NULL;
@@ -264,6 +266,7 @@
 	 * Deallocate all children at this level
 	 */
 	do {
+
 		/* Get the things we need */
 
 		next_node = child_node->peer;
@@ -352,11 +355,13 @@
 	 * to where we started.
 	 */
 	while (level > 0) {
+
 		/* Get the next node in this scope (NULL if none) */
 
 		child_node = acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node,
 						   child_node);
 		if (child_node) {
+
 			/* Found a child node - detach any attached object */
 
 			acpi_ns_detach_object(child_node);
@@ -427,6 +432,7 @@
 	 */
 	this_node = node;
 	while (this_node) {
+
 		/* Prepare to move up to parent */
 
 		parent_node = acpi_ns_get_parent_node(this_node);
@@ -438,6 +444,7 @@
 		/* Delete the node if no more references */
 
 		if (!this_node->reference_count) {
+
 			/* Delete all children and delete the node */
 
 			acpi_ns_delete_children(this_node);
@@ -500,6 +507,7 @@
 
 		if (child_node) {
 			if (child_node->owner_id == owner_id) {
+
 				/* Found a matching child node - detach any attached object */
 
 				acpi_ns_detach_object(child_node);
diff -urN oldtree/drivers/acpi/namespace/nsdump.c newtree/drivers/acpi/namespace/nsdump.c
--- oldtree/drivers/acpi/namespace/nsdump.c	2006-02-19 11:41:00.809220080 +0000
+++ newtree/drivers/acpi/namespace/nsdump.c	2006-02-21 15:58:09.910639912 +0000
@@ -191,6 +191,7 @@
 	}
 
 	if (!(info->display_type & ACPI_DISPLAY_SHORT)) {
+
 		/* Indent the object according to the level */
 
 		acpi_os_printf("%2d%*s", (u32) level - 1, (int)level * 2, " ");
@@ -226,6 +227,7 @@
 	case ACPI_DISPLAY_SUMMARY:
 
 		if (!obj_desc) {
+
 			/* No attached object, we are done */
 
 			acpi_os_printf("\n");
@@ -419,6 +421,7 @@
 
 		acpi_os_printf("O:%p", obj_desc);
 		if (!obj_desc) {
+
 			/* No attached object, we are done */
 
 			acpi_os_printf("\n");
@@ -682,6 +685,7 @@
 	}
 
 	if (ACPI_NS_ALL == search_base) {
+
 		/* Entire namespace */
 
 		search_handle = acpi_gbl_root_node;
diff -urN oldtree/drivers/acpi/namespace/nseval.c newtree/drivers/acpi/namespace/nseval.c
--- oldtree/drivers/acpi/namespace/nseval.c	2006-02-19 11:41:00.810219928 +0000
+++ newtree/drivers/acpi/namespace/nseval.c	2006-02-21 15:58:09.913639456 +0000
@@ -326,6 +326,7 @@
 	 * Check if there is a return value on the stack that must be dealt with
 	 */
 	if (status == AE_CTRL_RETURN_VALUE) {
+
 		/* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */
 
 		status = AE_OK;
diff -urN oldtree/drivers/acpi/namespace/nsinit.c newtree/drivers/acpi/namespace/nsinit.c
--- oldtree/drivers/acpi/namespace/nsinit.c	2006-02-19 11:41:00.811219776 +0000
+++ newtree/drivers/acpi/namespace/nsinit.c	2006-02-21 15:58:09.914639304 +0000
@@ -366,6 +366,7 @@
 	status = acpi_ns_search_node(*ACPI_CAST_PTR(u32, METHOD_NAME__INI),
 				     device_node, ACPI_TYPE_METHOD, &ini_node);
 	if (ACPI_FAILURE(status)) {
+
 		/* No _INI method found - move on to next device */
 
 		return_ACPI_STATUS(AE_OK);
@@ -386,6 +387,7 @@
 
 	status = acpi_ut_execute_STA(pinfo.node, &flags);
 	if (ACPI_FAILURE(status)) {
+
 		/* Ignore error and move on to next device */
 
 		return_ACPI_STATUS(AE_OK);
@@ -396,6 +398,7 @@
 	}
 
 	if (!(flags & ACPI_STA_DEVICE_PRESENT)) {
+
 		/* Don't look at children of a not present device */
 
 		return_ACPI_STATUS(AE_CTRL_DEPTH);
@@ -412,6 +415,7 @@
 	pinfo.node = ini_node;
 	status = acpi_ns_evaluate_by_handle(&pinfo);
 	if (ACPI_FAILURE(status)) {
+
 		/* Ignore error and move on to next device */
 
 #ifdef ACPI_DEBUG_OUTPUT
@@ -435,6 +439,7 @@
 	}
 
 	if (acpi_gbl_init_handler) {
+
 		/* External initialization handler is present, call it */
 
 		status =
diff -urN oldtree/drivers/acpi/namespace/nsload.c newtree/drivers/acpi/namespace/nsload.c
--- oldtree/drivers/acpi/namespace/nsload.c	2006-02-19 11:41:00.811219776 +0000
+++ newtree/drivers/acpi/namespace/nsload.c	2006-02-21 15:58:09.915639152 +0000
@@ -84,6 +84,7 @@
 	if (!
 	    (acpi_gbl_table_data[table_desc->type].
 	     flags & ACPI_TABLE_EXECUTABLE)) {
+
 		/* Just ignore this table */
 
 		return_ACPI_STATUS(AE_OK);
@@ -325,6 +326,7 @@
 	 * to where we started.
 	 */
 	while (level > 0) {
+
 		/* Attempt to get the next object in this scope */
 
 		status = acpi_get_next_object(ACPI_TYPE_ANY, parent_handle,
@@ -335,6 +337,7 @@
 		/* Did we get a new object? */
 
 		if (ACPI_SUCCESS(status)) {
+
 			/* Check if this object has any children */
 
 			if (ACPI_SUCCESS
diff -urN oldtree/drivers/acpi/namespace/nsobject.c newtree/drivers/acpi/namespace/nsobject.c
--- oldtree/drivers/acpi/namespace/nsobject.c	2006-02-19 11:41:00.812219624 +0000
+++ newtree/drivers/acpi/namespace/nsobject.c	2006-02-21 15:58:09.915639152 +0000
@@ -82,6 +82,7 @@
 	 * Parameter validation
 	 */
 	if (!node) {
+
 		/* Invalid handle */
 
 		ACPI_ERROR((AE_INFO, "Null named_obj handle"));
@@ -89,6 +90,7 @@
 	}
 
 	if (!object && (ACPI_TYPE_ANY != type)) {
+
 		/* Null object */
 
 		ACPI_ERROR((AE_INFO,
@@ -97,6 +99,7 @@
 	}
 
 	if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) {
+
 		/* Not a name handle */
 
 		ACPI_ERROR((AE_INFO, "Invalid handle %p [%s]",
diff -urN oldtree/drivers/acpi/namespace/nssearch.c newtree/drivers/acpi/namespace/nssearch.c
--- oldtree/drivers/acpi/namespace/nssearch.c	2006-02-19 11:41:00.813219472 +0000
+++ newtree/drivers/acpi/namespace/nssearch.c	2006-02-21 15:58:09.916639000 +0000
@@ -114,9 +114,11 @@
 	 */
 	next_node = node->child;
 	while (next_node) {
+
 		/* Check for match against the name */
 
 		if (next_node->name.integer == target_name) {
+
 			/* Resolve a control method alias if any */
 
 			if (acpi_ns_get_type(next_node) ==
@@ -146,6 +148,7 @@
 		 * so a flag is used to indicate the end-of-list
 		 */
 		if (next_node->flags & ANOBJ_END_OF_PEER_LIST) {
+
 			/* Searched entire list, we are done */
 
 			break;
diff -urN oldtree/drivers/acpi/namespace/nsutils.c newtree/drivers/acpi/namespace/nsutils.c
--- oldtree/drivers/acpi/namespace/nsutils.c	2006-02-19 11:41:00.814219320 +0000
+++ newtree/drivers/acpi/namespace/nsutils.c	2006-02-21 15:58:09.917638848 +0000
@@ -83,6 +83,7 @@
 	acpi_ut_report_error(module_name, line_number);
 
 	if (lookup_status == AE_BAD_CHARACTER) {
+
 		/* There is a non-ascii character in the name */
 
 		acpi_os_printf("[0x%4.4X] (NON-ASCII)",
@@ -267,6 +268,7 @@
 	ACPI_FUNCTION_TRACE("ns_local");
 
 	if (!acpi_ut_valid_object_type(type)) {
+
 		/* Type code out of range  */
 
 		ACPI_WARNING((AE_INFO, "Invalid Object Type %X", type));
@@ -411,6 +413,7 @@
 		for (i = 0; i < ACPI_NAME_SIZE; i++) {
 			if (acpi_ns_valid_path_separator(*external_name) ||
 			    (*external_name == 0)) {
+
 				/* Pad the segment with underscore(s) if segment is short */
 
 				result[i] = '_';
@@ -795,6 +798,7 @@
 	ACPI_FUNCTION_TRACE_STR("ns_opens_scope", acpi_ut_get_type_name(type));
 
 	if (!acpi_ut_valid_object_type(type)) {
+
 		/* type code out of range  */
 
 		ACPI_WARNING((AE_INFO, "Invalid Object Type %X", type));
@@ -838,6 +842,7 @@
 	ACPI_FUNCTION_TRACE_PTR("ns_get_node_by_path", pathname);
 
 	if (pathname) {
+
 		/* Convert path to internal representation */
 
 		status = acpi_ns_internalize_name(pathname, &internal_path);
@@ -963,6 +968,7 @@
 	ACPI_FUNCTION_TRACE("ns_find_parent_name");
 
 	if (child_node) {
+
 		/* Valid entry.  Get the parent Node */
 
 		parent_node = acpi_ns_get_parent_node(child_node);
diff -urN oldtree/drivers/acpi/namespace/nswalk.c newtree/drivers/acpi/namespace/nswalk.c
--- oldtree/drivers/acpi/namespace/nswalk.c	2006-02-19 11:41:00.815219168 +0000
+++ newtree/drivers/acpi/namespace/nswalk.c	2006-02-21 15:58:09.918638696 +0000
@@ -76,6 +76,7 @@
 	ACPI_FUNCTION_ENTRY();
 
 	if (!child_node) {
+
 		/* It's really the parent's _scope_ that we want */
 
 		if (parent_node->child) {
@@ -92,6 +93,7 @@
 	/* If any type is OK, we are done */
 
 	if (type == ACPI_TYPE_ANY) {
+
 		/* next_node is NULL if we are at the end-of-list */
 
 		return (next_node);
@@ -100,6 +102,7 @@
 	/* Must search for the node -- but within this scope only */
 
 	while (next_node) {
+
 		/* If type matches, we are done */
 
 		if (next_node->type == type) {
@@ -182,6 +185,7 @@
 	 * bubbled up to (and passed) the original parent handle (start_entry)
 	 */
 	while (level > 0) {
+
 		/* Get the next node in this scope.  Null if not found */
 
 		status = AE_OK;
diff -urN oldtree/drivers/acpi/namespace/nsxfeval.c newtree/drivers/acpi/namespace/nsxfeval.c
--- oldtree/drivers/acpi/namespace/nsxfeval.c	2006-02-19 11:41:00.816219016 +0000
+++ newtree/drivers/acpi/namespace/nsxfeval.c	2006-02-21 15:58:09.919638544 +0000
@@ -110,6 +110,7 @@
 	}
 
 	if (return_buffer->length == 0) {
+
 		/* Error because caller specifically asked for a return value */
 
 		ACPI_ERROR((AE_INFO, "No return value"));
@@ -131,6 +132,7 @@
 		    acpi_ut_get_type_name(return_type)));
 
 	if (must_free) {
+
 		/* Caller used ACPI_ALLOCATE_BUFFER, free the return buffer */
 
 		acpi_os_free(return_buffer->pointer);
@@ -224,9 +226,9 @@
 	 * 3) Valid handle
 	 */
 	if ((pathname) && (acpi_ns_valid_root_prefix(pathname[0]))) {
-		/*
-		 *  The path is fully qualified, just evaluate by name
-		 */
+
+		/* The path is fully qualified, just evaluate by name */
+
 		status = acpi_ns_evaluate_by_name(pathname, &info);
 	} else if (!handle) {
 		/*
@@ -235,11 +237,12 @@
 		 * qualified names above, this is an error
 		 */
 		if (!pathname) {
-			ACPI_ERROR((AE_INFO,
-				    "Both Handle and Pathname are NULL"));
+			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+					  "Both Handle and Pathname are NULL"));
 		} else {
-			ACPI_ERROR((AE_INFO,
-				    "Handle is NULL and Pathname is relative"));
+			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+					  "Null Handle with relative pathname [%s]",
+					  pathname));
 		}
 
 		status = AE_BAD_PARAMETER;
@@ -256,9 +259,8 @@
 			 */
 			status = acpi_ns_evaluate_by_handle(&info);
 		} else {
-			/*
-			 * Both a Handle and a relative Pathname
-			 */
+			/* Both a Handle and a relative Pathname */
+
 			status = acpi_ns_evaluate_relative(pathname, &info);
 		}
 	}
@@ -295,6 +297,7 @@
 				    acpi_ut_get_object_size(info.return_object,
 							    &buffer_space_needed);
 				if (ACPI_SUCCESS(status)) {
+
 					/* Validate/Allocate/Clear caller buffer */
 
 					status =
@@ -303,7 +306,8 @@
 					     buffer_space_needed);
 					if (ACPI_FAILURE(status)) {
 						/*
-						 * Caller's buffer is too small or a new one can't be allocated
+						 * Caller's buffer is too small or a new one can't
+						 * be allocated
 						 */
 						ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 								  "Needed buffer size %X, %s\n",
@@ -312,9 +316,8 @@
 								  acpi_format_exception
 								  (status)));
 					} else {
-						/*
-						 *  We have enough space for the object, build it
-						 */
+						/* We have enough space for the object, build it */
+
 						status =
 						    acpi_ut_copy_iobject_to_eobject
 						    (info.return_object,
@@ -341,10 +344,10 @@
 		}
 	}
 
-	/*
-	 * Free the input parameter list (if we created one),
-	 */
+	/* Free the input parameter list (if we created one) */
+
 	if (info.parameters) {
+
 		/* Free the allocated parameter block */
 
 		acpi_ut_delete_internal_object_list(info.parameters);
@@ -473,6 +476,7 @@
 	}
 
 	if (!(flags & ACPI_STA_DEVICE_PRESENT)) {
+
 		/* Don't examine children of the device if not present */
 
 		return (AE_CTRL_DEPTH);
@@ -489,6 +493,7 @@
 		}
 
 		if (ACPI_STRNCMP(hid.value, info->hid, sizeof(hid.value)) != 0) {
+
 			/* Get the list of Compatible IDs */
 
 			status = acpi_ut_execute_CID(node, &cid);
@@ -563,9 +568,9 @@
 	 * We're going to call their callback from OUR callback, so we need
 	 * to know what it is, and their context parameter.
 	 */
+	info.hid = HID;
 	info.context = context;
 	info.user_function = user_function;
-	info.hid = HID;
 
 	/*
 	 * Lock the namespace around the walk.
@@ -578,9 +583,8 @@
 		return_ACPI_STATUS(status);
 	}
 
-	status = acpi_ns_walk_namespace(ACPI_TYPE_DEVICE,
-					ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
-					ACPI_NS_WALK_UNLOCK,
+	status = acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+					ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK,
 					acpi_ns_get_device_callback, &info,
 					return_value);
 
diff -urN oldtree/drivers/acpi/namespace/nsxfname.c newtree/drivers/acpi/namespace/nsxfname.c
--- oldtree/drivers/acpi/namespace/nsxfname.c	2006-02-19 11:41:00.816219016 +0000
+++ newtree/drivers/acpi/namespace/nsxfname.c	2006-02-21 15:58:09.920638392 +0000
@@ -162,6 +162,7 @@
 	}
 
 	if (name_type == ACPI_FULL_PATHNAME) {
+
 		/* Get the full pathname (From the namespace root) */
 
 		status = acpi_ns_handle_to_pathname(handle, buffer);
diff -urN oldtree/drivers/acpi/namespace/nsxfobj.c newtree/drivers/acpi/namespace/nsxfobj.c
--- oldtree/drivers/acpi/namespace/nsxfobj.c	2006-02-19 11:41:00.816219016 +0000
+++ newtree/drivers/acpi/namespace/nsxfobj.c	2006-02-21 15:58:09.921638240 +0000
@@ -206,6 +206,7 @@
 	/* If null handle, use the parent */
 
 	if (!child) {
+
 		/* Start search at the beginning of the specified scope */
 
 		parent_node = acpi_ns_map_handle_to_node(parent);
diff -urN oldtree/drivers/acpi/osl.c newtree/drivers/acpi/osl.c
--- oldtree/drivers/acpi/osl.c	2006-02-19 11:41:00.817218864 +0000
+++ newtree/drivers/acpi/osl.c	2006-02-21 15:58:09.921638240 +0000
@@ -136,6 +136,7 @@
 #endif
 }
 
+
 extern int acpi_in_resume;
 void *acpi_os_allocate(acpi_size size)
 {
@@ -623,7 +624,7 @@
 
 	dpc = (struct acpi_os_dpc *)context;
 	if (!dpc) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid (NULL) context.\n"));
+		ACPI_ERROR((AE_INFO, "Invalid (NULL) context"));
 		return_VOID;
 	}
 
@@ -675,8 +676,7 @@
 	INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc);
 
 	if (!queue_work(kacpid_wq, task)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Call to queue_work() failed.\n"));
+		ACPI_ERROR((AE_INFO, "Call to queue_work() failed"));
 		kfree(dpc);
 		status = AE_ERROR;
 	}
@@ -850,13 +850,13 @@
 	}
 
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Failed to acquire semaphore[%p|%d|%d], %s\n",
+		ACPI_EXCEPTION((AE_INFO, status,
+				  "Failed to acquire semaphore[%p|%d|%d], %s",
 				  handle, units, timeout,
 				  acpi_format_exception(status)));
 	} else {
 		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
-				  "Acquired semaphore[%p|%d|%d]\n", handle,
+				  "Acquired semaphore[%p|%d|%d]", handle,
 				  units, timeout));
 	}
 
diff -urN oldtree/drivers/acpi/parser/psargs.c newtree/drivers/acpi/parser/psargs.c
--- oldtree/drivers/acpi/parser/psargs.c	2006-02-19 11:41:00.819218560 +0000
+++ newtree/drivers/acpi/parser/psargs.c	2006-02-21 15:58:09.922638088 +0000
@@ -275,6 +275,7 @@
 	 */
 	if (ACPI_SUCCESS(status) &&
 	    possible_method_call && (node->type == ACPI_TYPE_METHOD)) {
+
 		/* This name is actually a control method invocation */
 
 		method_desc = acpi_ns_get_attached_object(node);
@@ -319,6 +320,7 @@
 	 * some not_found cases are allowed
 	 */
 	if (status == AE_NOT_FOUND) {
+
 		/* 1) not_found is ok during load pass 1/2 (allow forward references) */
 
 		if ((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) !=
@@ -354,6 +356,7 @@
 
 		if ((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) ==
 		    ACPI_PARSE_EXECUTE) {
+
 			/* Report a control method execution error */
 
 			status = acpi_ds_method_error(status, walk_state);
@@ -620,6 +623,7 @@
 	case ARGP_FIELDLIST:
 
 		if (parser_state->aml < parser_state->pkg_end) {
+
 			/* Non-empty list */
 
 			while (parser_state->aml < parser_state->pkg_end) {
@@ -645,6 +649,7 @@
 	case ARGP_BYTELIST:
 
 		if (parser_state->aml < parser_state->pkg_end) {
+
 			/* Non-empty list */
 
 			arg = acpi_ps_alloc_op(AML_INT_BYTELIST_OP);
@@ -673,6 +678,7 @@
 		if (subop == 0 ||
 		    acpi_ps_is_leading_char(subop) ||
 		    acpi_ps_is_prefix_char(subop)) {
+
 			/* null_name or name_string */
 
 			arg = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP);
@@ -703,6 +709,7 @@
 	case ARGP_OBJLIST:
 
 		if (parser_state->aml < parser_state->pkg_end) {
+
 			/* Non-empty list of variable arguments, nothing returned */
 
 			walk_state->arg_count = ACPI_VAR_ARGS;
diff -urN oldtree/drivers/acpi/parser/psloop.c newtree/drivers/acpi/parser/psloop.c
--- oldtree/drivers/acpi/parser/psloop.c	2006-02-19 11:41:00.819218560 +0000
+++ newtree/drivers/acpi/parser/psloop.c	2006-02-21 15:58:09.923637936 +0000
@@ -95,6 +95,7 @@
 #if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
 
 	if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) {
+
 		/* We are restarting a preempted control method */
 
 		if (acpi_ps_has_completed_scope(parser_state)) {
@@ -143,6 +144,7 @@
 			ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
 					  "Popped scope, Op=%p\n", op));
 		} else if (walk_state->prev_op) {
+
 			/* We were in the middle of an op */
 
 			op = walk_state->prev_op;
@@ -156,6 +158,7 @@
 	while ((parser_state->aml < parser_state->aml_end) || (op)) {
 		aml_op_start = parser_state->aml;
 		if (!op) {
+
 			/* Get the next opcode from the AML stream */
 
 			walk_state->aml_offset =
@@ -213,6 +216,7 @@
 			/* Create Op structure and append to parent's argument list */
 
 			if (walk_state->op_info->flags & AML_NAMED) {
+
 				/* Allocate a new pre_op if necessary */
 
 				if (!pre_op) {
@@ -388,6 +392,7 @@
 		/* Are there any arguments that must be processed? */
 
 		if (walk_state->arg_types) {
+
 			/* Get arguments */
 
 			switch (op->common.aml_opcode) {
@@ -853,6 +858,7 @@
 				}
 
 				else if (ACPI_FAILURE(status)) {
+
 					/* First error is most important */
 
 					(void)
diff -urN oldtree/drivers/acpi/parser/psopcode.c newtree/drivers/acpi/parser/psopcode.c
--- oldtree/drivers/acpi/parser/psopcode.c	2006-02-19 11:41:00.820218408 +0000
+++ newtree/drivers/acpi/parser/psopcode.c	2006-02-21 15:58:09.924637784 +0000
@@ -731,6 +731,7 @@
 	 * Detect normal 8-bit opcode or extended 16-bit opcode
 	 */
 	if (!(opcode & 0xFF00)) {
+
 		/* Simple (8-bit) opcode: 0-255, can't index beyond table  */
 
 		return (&acpi_gbl_aml_op_info
@@ -739,6 +740,7 @@
 
 	if (((opcode & 0xFF00) == AML_EXTENDED_OPCODE) &&
 	    (((u8) opcode) <= MAX_EXTENDED_OPCODE)) {
+
 		/* Valid extended (16-bit) opcode */
 
 		return (&acpi_gbl_aml_op_info
diff -urN oldtree/drivers/acpi/parser/psparse.c newtree/drivers/acpi/parser/psparse.c
--- oldtree/drivers/acpi/parser/psparse.c	2006-02-19 11:41:00.821218256 +0000
+++ newtree/drivers/acpi/parser/psparse.c	2006-02-21 15:58:09.933636416 +0000
@@ -106,6 +106,7 @@
 	opcode = (u16) ACPI_GET8(aml);
 
 	if (opcode == AML_EXTENDED_OP_PREFIX) {
+
 		/* Extended opcode, get the second opcode byte */
 
 		aml++;
@@ -158,6 +159,7 @@
 	if (op->common.parent) {
 		prev = op->common.parent->common.value.arg;
 		if (!prev) {
+
 			/* Nothing more to do */
 
 			goto cleanup;
@@ -245,6 +247,7 @@
 		/* We must unlink this op from the parent tree */
 
 		if (prev == op) {
+
 			/* This op is the first in the list */
 
 			if (replacement_op) {
@@ -265,6 +268,7 @@
 
 		else
 			while (prev) {
+
 				/* Traverse all siblings in the parent's argument list */
 
 				next = prev->common.next;
@@ -510,6 +514,7 @@
 		} else if (status == AE_CTRL_TERMINATE) {
 			status = AE_OK;
 		} else if ((status != AE_OK) && (walk_state->method_desc)) {
+
 			/* Either the method parse or actual execution failed */
 
 			ACPI_ERROR_METHOD("Method parse/execution failed",
@@ -551,6 +556,7 @@
 		if (((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) ==
 		     ACPI_PARSE_EXECUTE) || (ACPI_FAILURE(status))) {
 			if (walk_state->method_desc) {
+
 				/* Decrement the thread count on the method parse tree */
 
 				if (walk_state->method_desc->method.
@@ -633,12 +639,14 @@
 			}
 		} else {
 			if (previous_walk_state->return_desc) {
+
 				/* Caller doesn't want it, must delete it */
 
 				acpi_ut_remove_reference(previous_walk_state->
 							 return_desc);
 			}
 			if (previous_walk_state->implicit_return_obj) {
+
 				/* Caller doesn't want it, must delete it */
 
 				acpi_ut_remove_reference(previous_walk_state->
diff -urN oldtree/drivers/acpi/parser/psscope.c newtree/drivers/acpi/parser/psscope.c
--- oldtree/drivers/acpi/parser/psscope.c	2006-02-19 11:41:00.822218104 +0000
+++ newtree/drivers/acpi/parser/psscope.c	2006-02-21 15:58:09.934636264 +0000
@@ -165,6 +165,7 @@
 	acpi_ut_push_generic_state(&parser_state->scope, scope);
 
 	if (arg_count == ACPI_VAR_ARGS) {
+
 		/* Multiple arguments */
 
 		scope->parse_scope.arg_end = parser_state->pkg_end;
diff -urN oldtree/drivers/acpi/parser/pstree.c newtree/drivers/acpi/parser/pstree.c
--- oldtree/drivers/acpi/parser/pstree.c	2006-02-19 11:41:00.823217952 +0000
+++ newtree/drivers/acpi/parser/pstree.c	2006-02-21 15:58:09.934636264 +0000
@@ -77,6 +77,7 @@
 
 	op_info = acpi_ps_get_opcode_info(op->common.aml_opcode);
 	if (op_info->class == AML_CLASS_UNKNOWN) {
+
 		/* Invalid opcode or ASCII character */
 
 		return (NULL);
@@ -85,6 +86,7 @@
 	/* Check if this opcode requires argument sub-objects */
 
 	if (!(op_info->flags & AML_HAS_ARGS)) {
+
 		/* Has no linked argument objects */
 
 		return (NULL);
@@ -130,6 +132,7 @@
 
 	op_info = acpi_ps_get_opcode_info(op->common.aml_opcode);
 	if (op_info->class == AML_CLASS_UNKNOWN) {
+
 		/* Invalid opcode */
 
 		ACPI_ERROR((AE_INFO, "Invalid AML Opcode: 0x%2.2X",
@@ -140,6 +143,7 @@
 	/* Check if this opcode requires argument sub-objects */
 
 	if (!(op_info->flags & AML_HAS_ARGS)) {
+
 		/* Has no linked argument objects */
 
 		return;
@@ -148,6 +152,7 @@
 	/* Append the argument to the linked argument list */
 
 	if (op->common.value.arg) {
+
 		/* Append to existing argument list */
 
 		prev_arg = op->common.value.arg;
@@ -222,12 +227,14 @@
 		}
 
 		if (arg == origin) {
+
 			/* Reached parent of origin, end search */
 
 			return (NULL);
 		}
 
 		if (parent->common.next) {
+
 			/* Found sibling of parent */
 
 			return (parent->common.next);
diff -urN oldtree/drivers/acpi/parser/psutils.c newtree/drivers/acpi/parser/psutils.c
--- oldtree/drivers/acpi/parser/psutils.c	2006-02-19 11:41:00.823217952 +0000
+++ newtree/drivers/acpi/parser/psutils.c	2006-02-21 15:58:09.935636112 +0000
@@ -135,6 +135,7 @@
 	/* Allocate the minimum required size object */
 
 	if (flags == ACPI_PARSEOP_GENERIC) {
+
 		/* The generic op (default) is by far the most common (16 to 1) */
 
 		op = acpi_os_acquire_object(acpi_gbl_ps_node_cache);
diff -urN oldtree/drivers/acpi/parser/pswalk.c newtree/drivers/acpi/parser/pswalk.c
--- oldtree/drivers/acpi/parser/pswalk.c	2006-02-19 11:41:00.824217800 +0000
+++ newtree/drivers/acpi/parser/pswalk.c	2006-02-21 15:58:09.935636112 +0000
@@ -69,13 +69,16 @@
 	/* Visit all nodes in the subtree */
 
 	while (op) {
+
 		/* Check if we are not ascending */
 
 		if (op != parent) {
+
 			/* Look for an argument or child of the current op */
 
 			next = acpi_ps_get_arg(op, 0);
 			if (next) {
+
 				/* Still going downward in tree (Op is not completed yet) */
 
 				op = next;
diff -urN oldtree/drivers/acpi/parser/psxface.c newtree/drivers/acpi/parser/psxface.c
--- oldtree/drivers/acpi/parser/psxface.c	2006-02-19 11:41:00.824217800 +0000
+++ newtree/drivers/acpi/parser/psxface.c	2006-02-21 15:58:09.935636112 +0000
@@ -317,9 +317,11 @@
 	acpi_native_uint i;
 
 	if ((info->parameter_type == ACPI_PARAM_ARGS) && (info->parameters)) {
+
 		/* Update reference count for each parameter */
 
 		for (i = 0; info->parameters[i]; i++) {
+
 			/* Ignore errors, just do them all */
 
 			(void)acpi_ut_update_object_reference(info->
diff -urN oldtree/drivers/acpi/pci_bind.c newtree/drivers/acpi/pci_bind.c
--- oldtree/drivers/acpi/pci_bind.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/acpi/pci_bind.c	2006-02-21 15:58:09.936635960 +0000
@@ -75,17 +75,17 @@
 
 	result = acpi_bus_get_device(handle, &device);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Invalid ACPI Bus context for device %s\n",
-				  acpi_device_bid(device)));
+		ACPI_ERROR((AE_INFO,
+			    "Invalid ACPI Bus context for device %s",
+			    acpi_device_bid(device)));
 		return_ACPI_STATUS(AE_NOT_EXIST);
 	}
 
 	status = acpi_get_data(handle, acpi_pci_data_handler, (void **)&data);
 	if (ACPI_FAILURE(status) || !data) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Invalid ACPI-PCI context for device %s\n",
-				  acpi_device_bid(device)));
+		ACPI_EXCEPTION((AE_INFO, status,
+				"Invalid ACPI-PCI context for device %s",
+				acpi_device_bid(device)));
 		return_ACPI_STATUS(status);
 	}
 
@@ -151,9 +151,9 @@
 	status = acpi_get_data(device->parent->handle, acpi_pci_data_handler,
 			       (void **)&pdata);
 	if (ACPI_FAILURE(status) || !pdata || !pdata->bus) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Invalid ACPI-PCI context for parent device %s\n",
-				  acpi_device_bid(device->parent)));
+		ACPI_EXCEPTION((AE_INFO, status,
+				"Invalid ACPI-PCI context for parent device %s",
+				acpi_device_bid(device->parent)));
 		result = -ENODEV;
 		goto end;
 	}
@@ -206,10 +206,10 @@
 		goto end;
 	}
 	if (!data->dev->bus) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Device %02x:%02x:%02x.%02x has invalid 'bus' field\n",
-				  data->id.segment, data->id.bus,
-				  data->id.device, data->id.function));
+		ACPI_ERROR((AE_INFO,
+			    "Device %02x:%02x:%02x.%02x has invalid 'bus' field",
+			    data->id.segment, data->id.bus,
+			    data->id.device, data->id.function));
 		result = -ENODEV;
 		goto end;
 	}
@@ -237,9 +237,9 @@
 	 */
 	status = acpi_attach_data(device->handle, acpi_pci_data_handler, data);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to attach ACPI-PCI context to device %s\n",
-				  acpi_device_bid(device)));
+		ACPI_EXCEPTION((AE_INFO, status,
+				"Unable to attach ACPI-PCI context to device %s",
+				acpi_device_bid(device)));
 		result = -ENODEV;
 		goto end;
 	}
@@ -301,18 +301,18 @@
 	    acpi_get_data(device->handle, acpi_pci_data_handler,
 			  (void **)&data);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to get data from device %s\n",
-				  acpi_device_bid(device)));
+		ACPI_EXCEPTION((AE_INFO, status,
+				"Unable to get data from device %s",
+				acpi_device_bid(device)));
 		result = -ENODEV;
 		goto end;
 	}
 
 	status = acpi_detach_data(device->handle, acpi_pci_data_handler);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to detach data from device %s\n",
-				  acpi_device_bid(device)));
+		ACPI_EXCEPTION((AE_INFO, status,
+				"Unable to detach data from device %s",
+				acpi_device_bid(device)));
 		result = -ENODEV;
 		goto end;
 	}
@@ -369,9 +369,9 @@
 
 	status = acpi_attach_data(device->handle, acpi_pci_data_handler, data);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to attach ACPI-PCI context to device %s\n",
-				  pathname));
+		ACPI_EXCEPTION((AE_INFO, status,
+				"Unable to attach ACPI-PCI context to device %s",
+				pathname));
 		result = -ENODEV;
 		goto end;
 	}
diff -urN oldtree/drivers/acpi/pci_irq.c newtree/drivers/acpi/pci_irq.c
--- oldtree/drivers/acpi/pci_irq.c	2006-02-19 11:41:00.825217648 +0000
+++ newtree/drivers/acpi/pci_irq.c	2006-02-21 15:58:09.937635808 +0000
@@ -197,8 +197,8 @@
 	kfree(pathname);
 	status = acpi_get_irq_routing_table(handle, &buffer);
 	if (status != AE_BUFFER_OVERFLOW) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRT [%s]\n",
-				  acpi_format_exception(status)));
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]",
+				acpi_format_exception(status)));
 		return_VALUE(-ENODEV);
 	}
 
@@ -211,8 +211,8 @@
 
 	status = acpi_get_irq_routing_table(handle, &buffer);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRT [%s]\n",
-				  acpi_format_exception(status)));
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]",
+				acpi_format_exception(status)));
 		kfree(buffer.pointer);
 		return_VALUE(-ENODEV);
 	}
@@ -269,8 +269,8 @@
 						 entry->link.index, triggering,
 						 polarity, link);
 		if (irq < 0) {
-			ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-					  "Invalid IRQ link routing entry\n"));
+			ACPI_WARNING((AE_INFO,
+				      "Invalid IRQ link routing entry"));
 			return_VALUE(-1);
 		}
 	} else {
@@ -379,9 +379,8 @@
 	}
 
 	if (irq < 0) {
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-				  "Unable to derive IRQ for device %s\n",
-				  pci_name(dev)));
+		ACPI_WARNING((AE_INFO, "Unable to derive IRQ for device %s",
+			      pci_name(dev)));
 		return_VALUE(-1);
 	}
 
@@ -421,8 +420,7 @@
 	pin--;
 
 	if (!dev->bus) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Invalid (NULL) 'bus' field\n"));
+		ACPI_ERROR((AE_INFO, "Invalid (NULL) 'bus' field"));
 		return_VALUE(-ENODEV);
 	}
 
diff -urN oldtree/drivers/acpi/pci_link.c newtree/drivers/acpi/pci_link.c
--- oldtree/drivers/acpi/pci_link.c	2006-02-19 11:41:00.827217344 +0000
+++ newtree/drivers/acpi/pci_link.c	2006-02-21 15:58:10.746512840 +0000
@@ -38,6 +38,7 @@
 #include <linux/spinlock.h>
 #include <linux/pm.h>
 #include <linux/pci.h>
+#include <linux/mutex.h>
 
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
@@ -91,7 +92,7 @@
 	int count;
 	struct list_head entries;
 } acpi_link;
-DECLARE_MUTEX(acpi_link_lock);
+DEFINE_MUTEX(acpi_link_lock);
 
 /* --------------------------------------------------------------------------
                             PCI Link Device Management
@@ -115,17 +116,15 @@
 		{
 			struct acpi_resource_irq *p = &resource->data.irq;
 			if (!p || !p->interrupt_count) {
-				ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-						  "Blank IRQ resource\n"));
+				ACPI_WARNING((AE_INFO, "Blank IRQ resource"));
 				return_ACPI_STATUS(AE_OK);
 			}
 			for (i = 0;
 			     (i < p->interrupt_count
 			      && i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
 				if (!p->interrupts[i]) {
-					ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-							  "Invalid IRQ %d\n",
-							  p->interrupts[i]));
+					ACPI_WARNING((AE_INFO, "Invalid IRQ %d",
+						      p->interrupts[i]));
 					continue;
 				}
 				link->irq.possible[i] = p->interrupts[i];
@@ -141,17 +140,16 @@
 			struct acpi_resource_extended_irq *p =
 			    &resource->data.extended_irq;
 			if (!p || !p->interrupt_count) {
-				ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-						  "Blank EXT IRQ resource\n"));
+				ACPI_WARNING((AE_INFO,
+					      "Blank EXT IRQ resource"));
 				return_ACPI_STATUS(AE_OK);
 			}
 			for (i = 0;
 			     (i < p->interrupt_count
 			      && i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
 				if (!p->interrupts[i]) {
-					ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-							  "Invalid IRQ %d\n",
-							  p->interrupts[i]));
+					ACPI_WARNING((AE_INFO, "Invalid IRQ %d",
+						      p->interrupts[i]));
 					continue;
 				}
 				link->irq.possible[i] = p->interrupts[i];
@@ -163,8 +161,7 @@
 			break;
 		}
 	default:
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Resource is not an IRQ entry\n"));
+		ACPI_ERROR((AE_INFO, "Resource is not an IRQ entry\n"));
 		return_ACPI_STATUS(AE_OK);
 	}
 
@@ -183,7 +180,7 @@
 	status = acpi_walk_resources(link->handle, METHOD_NAME__PRS,
 				     acpi_pci_link_check_possible, link);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRS\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRS"));
 		return_VALUE(-ENODEV);
 	}
 
@@ -226,8 +223,8 @@
 				 * extended IRQ descriptors must
 				 * return at least 1 IRQ
 				 */
-				ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-						  "Blank EXT IRQ resource\n"));
+				ACPI_WARNING((AE_INFO,
+					      "Blank EXT IRQ resource"));
 				return_ACPI_STATUS(AE_OK);
 			}
 			*irq = p->interrupts[0];
@@ -235,7 +232,7 @@
 		}
 		break;
 	default:
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Resource %d isn't an IRQ\n", resource->type));
+		ACPI_ERROR((AE_INFO, "Resource %d isn't an IRQ", resource->type));
 	case ACPI_RESOURCE_TYPE_END_TAG:
 		return_ACPI_STATUS(AE_OK);
 	}
@@ -267,8 +264,7 @@
 		/* Query _STA, set link->device->status */
 		result = acpi_bus_get_status(link->device);
 		if (result) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Unable to read status\n"));
+			ACPI_ERROR((AE_INFO, "Unable to read status"));
 			goto end;
 		}
 
@@ -285,13 +281,13 @@
 	status = acpi_walk_resources(link->handle, METHOD_NAME__CRS,
 				     acpi_pci_link_check_current, &irq);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _CRS\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _CRS"));
 		result = -ENODEV;
 		goto end;
 	}
 
 	if (acpi_strict && !irq) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "_CRS returned 0\n"));
+		ACPI_ERROR((AE_INFO, "_CRS returned 0"));
 		result = -ENODEV;
 	}
 
@@ -361,7 +357,7 @@
 		/* ignore resource_source, it's optional */
 		break;
 	default:
-		printk("ACPI BUG: resource_type %d\n", link->irq.resource_type);
+		ACPI_ERROR((AE_INFO, "Invalid Resource_type %d\n", link->irq.resource_type));
 		result = -EINVAL;
 		goto end;
 
@@ -373,7 +369,7 @@
 
 	/* check for total failure */
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SRS\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SRS"));
 		result = -ENODEV;
 		goto end;
 	}
@@ -381,14 +377,14 @@
 	/* Query _STA, set device->status */
 	result = acpi_bus_get_status(link->device);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n"));
+		ACPI_ERROR((AE_INFO, "Unable to read status"));
 		goto end;
 	}
 	if (!link->device->status.enabled) {
-		printk(KERN_WARNING PREFIX
-		       "%s [%s] disabled and referenced, BIOS bug.\n",
-		       acpi_device_name(link->device),
-		       acpi_device_bid(link->device));
+		ACPI_WARNING((AE_INFO,
+			      "%s [%s] disabled and referenced, BIOS bug",
+			      acpi_device_name(link->device),
+			      acpi_device_bid(link->device)));
 	}
 
 	/* Query _CRS, set link->irq.active */
@@ -406,10 +402,10 @@
 		 * policy: when _CRS doesn't return what we just _SRS
 		 * assume _SRS worked and override _CRS value.
 		 */
-		printk(KERN_WARNING PREFIX
-		       "%s [%s] BIOS reported IRQ %d, using IRQ %d\n",
-		       acpi_device_name(link->device),
-		       acpi_device_bid(link->device), link->irq.active, irq);
+		ACPI_WARNING((AE_INFO,
+			      "%s [%s] BIOS reported IRQ %d, using IRQ %d",
+			      acpi_device_name(link->device),
+			      acpi_device_bid(link->device), link->irq.active, irq));
 		link->irq.active = irq;
 	}
 
@@ -500,8 +496,7 @@
 
 		link = list_entry(node, struct acpi_pci_link, node);
 		if (!link) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Invalid link context\n"));
+			ACPI_ERROR((AE_INFO, "Invalid link context"));
 			continue;
 		}
 
@@ -560,8 +555,8 @@
 	 */
 	if (i == link->irq.possible_count) {
 		if (acpi_strict)
-			printk(KERN_WARNING PREFIX "_CRS %d not found"
-			       " in _PRS\n", link->irq.active);
+			ACPI_WARNING((AE_INFO, "_CRS %d not found"
+				      " in _PRS", link->irq.active));
 		link->irq.active = 0;
 	}
 
@@ -588,11 +583,10 @@
 
 	/* Attempt to enable the link device at this IRQ. */
 	if (acpi_pci_link_set(link, irq)) {
-		printk(PREFIX
-		       "Unable to set IRQ for %s [%s] (likely buggy ACPI BIOS).\n"
-		       "Try pci=noacpi or acpi=off\n",
-		       acpi_device_name(link->device),
-		       acpi_device_bid(link->device));
+		ACPI_ERROR((AE_INFO, "Unable to set IRQ for %s [%s]. "
+			    "Try pci=noacpi or acpi=off",
+			    acpi_device_name(link->device),
+			    acpi_device_bid(link->device)));
 		return_VALUE(-ENODEV);
 	} else {
 		acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING;
@@ -625,35 +619,35 @@
 
 	result = acpi_bus_get_device(handle, &device);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link device\n"));
+		ACPI_ERROR((AE_INFO, "Invalid link device"));
 		return_VALUE(-1);
 	}
 
 	link = (struct acpi_pci_link *)acpi_driver_data(device);
 	if (!link) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n"));
+		ACPI_ERROR((AE_INFO, "Invalid link context"));
 		return_VALUE(-1);
 	}
 
 	/* TBD: Support multiple index (IRQ) entries per Link Device */
 	if (index) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid index %d\n", index));
+		ACPI_ERROR((AE_INFO, "Invalid index %d", index));
 		return_VALUE(-1);
 	}
 
-	down(&acpi_link_lock);
+	mutex_lock(&acpi_link_lock);
 	if (acpi_pci_link_allocate(link)) {
-		up(&acpi_link_lock);
+		mutex_unlock(&acpi_link_lock);
 		return_VALUE(-1);
 	}
 
 	if (!link->irq.active) {
-		up(&acpi_link_lock);
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link active IRQ is 0!\n"));
+		mutex_unlock(&acpi_link_lock);
+		ACPI_ERROR((AE_INFO, "Link active IRQ is 0!"));
 		return_VALUE(-1);
 	}
 	link->refcnt++;
-	up(&acpi_link_lock);
+	mutex_unlock(&acpi_link_lock);
 
 	if (triggering)
 		*triggering = link->irq.triggering;
@@ -681,20 +675,20 @@
 
 	result = acpi_bus_get_device(handle, &device);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link device\n"));
+		ACPI_ERROR((AE_INFO, "Invalid link device"));
 		return_VALUE(-1);
 	}
 
 	link = (struct acpi_pci_link *)acpi_driver_data(device);
 	if (!link) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n"));
+		ACPI_ERROR((AE_INFO, "Invalid link context"));
 		return_VALUE(-1);
 	}
 
-	down(&acpi_link_lock);
+	mutex_lock(&acpi_link_lock);
 	if (!link->irq.initialized) {
-		up(&acpi_link_lock);
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link isn't initialized\n"));
+		mutex_unlock(&acpi_link_lock);
+		ACPI_ERROR((AE_INFO, "Link isn't initialized"));
 		return_VALUE(-1);
 	}
 #ifdef	FUTURE_USE
@@ -716,7 +710,7 @@
 	if (link->refcnt == 0) {
 		acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL);
 	}
-	up(&acpi_link_lock);
+	mutex_unlock(&acpi_link_lock);
 	return_VALUE(link->irq.active);
 }
 
@@ -747,7 +741,7 @@
 	strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS);
 	acpi_driver_data(device) = link;
 
-	down(&acpi_link_lock);
+	mutex_lock(&acpi_link_lock);
 	result = acpi_pci_link_get_possible(link);
 	if (result)
 		goto end;
@@ -782,7 +776,7 @@
       end:
 	/* disable all links -- to be activated on use */
 	acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL);
-	up(&acpi_link_lock);
+	mutex_unlock(&acpi_link_lock);
 
 	if (result)
 		kfree(link);
@@ -816,8 +810,7 @@
 	list_for_each(node, &acpi_link.entries) {
 		link = list_entry(node, struct acpi_pci_link, node);
 		if (!link) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Invalid link context\n"));
+			ACPI_ERROR((AE_INFO, "Invalid link context"));
 			continue;
 		}
 		acpi_pci_link_resume(link);
@@ -837,9 +830,9 @@
 
 	link = (struct acpi_pci_link *)acpi_driver_data(device);
 
-	down(&acpi_link_lock);
+	mutex_lock(&acpi_link_lock);
 	list_del(&link->node);
-	up(&acpi_link_lock);
+	mutex_unlock(&acpi_link_lock);
 
 	kfree(link);
 
diff -urN oldtree/drivers/acpi/pci_root.c newtree/drivers/acpi/pci_root.c
--- oldtree/drivers/acpi/pci_root.c	2006-02-19 11:41:00.828217192 +0000
+++ newtree/drivers/acpi/pci_root.c	2006-02-21 15:58:09.939635504 +0000
@@ -198,7 +198,7 @@
 		root->id.segment = 0;
 		break;
 	default:
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SEG\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SEG"));
 		result = -ENODEV;
 		goto end;
 	}
@@ -219,7 +219,7 @@
 		root->id.bus = 0;
 		break;
 	default:
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BBN\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BBN"));
 		result = -ENODEV;
 		goto end;
 	}
@@ -231,8 +231,9 @@
 			int bus = 0;
 			acpi_status status;
 
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Wrong _BBN value, please reboot and using option 'pci=noacpi'\n"));
+			ACPI_ERROR((AE_INFO,
+				    "Wrong _BBN value, reboot"
+				    " and use option 'pci=noacpi'"));
 
 			status = try_get_root_bridge_busnr(root->handle, &bus);
 			if (ACPI_FAILURE(status))
@@ -273,9 +274,9 @@
 	 */
 	root->bus = pci_acpi_scan_root(device, root->id.segment, root->id.bus);
 	if (!root->bus) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Bus %04x:%02x not present in PCI namespace\n",
-				  root->id.segment, root->id.bus));
+		ACPI_ERROR((AE_INFO,
+			    "Bus %04x:%02x not present in PCI namespace",
+			    root->id.segment, root->id.bus));
 		result = -ENODEV;
 		goto end;
 	}
diff -urN oldtree/drivers/acpi/power.c newtree/drivers/acpi/power.c
--- oldtree/drivers/acpi/power.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/acpi/power.c	2006-02-21 15:58:09.940635352 +0000
@@ -105,8 +105,7 @@
 
 	result = acpi_bus_get_device(handle, &device);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error getting context [%p]\n",
-				  handle));
+		ACPI_WARNING((AE_INFO, "Getting context [%p]", handle));
 		return_VALUE(result);
 	}
 
@@ -292,8 +291,7 @@
 	for (i = 0; i < dev->wakeup.resources.count; i++) {
 		ret = acpi_power_on(dev->wakeup.resources.handles[i]);
 		if (ret) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Error transition power state\n"));
+			ACPI_ERROR((AE_INFO, "Transition power state"));
 			dev->wakeup.flags.valid = 0;
 			return_VALUE(-1);
 		}
@@ -302,7 +300,7 @@
 	/* Execute PSW */
 	status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL);
 	if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluate _PSW\n"));
+		ACPI_ERROR((AE_INFO, "Evaluate _PSW"));
 		dev->wakeup.flags.valid = 0;
 		ret = -1;
 	}
@@ -332,7 +330,7 @@
 	/* Execute PSW */
 	status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL);
 	if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluate _PSW\n"));
+		ACPI_ERROR((AE_INFO, "Evaluate _PSW"));
 		dev->wakeup.flags.valid = 0;
 		return_VALUE(-1);
 	}
@@ -341,8 +339,7 @@
 	for (i = 0; i < dev->wakeup.resources.count; i++) {
 		ret = acpi_power_off_device(dev->wakeup.resources.handles[i]);
 		if (ret) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Error transition power state\n"));
+			ACPI_ERROR((AE_INFO, "Transition power state"));
 			dev->wakeup.flags.valid = 0;
 			return_VALUE(-1);
 		}
@@ -444,9 +441,8 @@
 	device->power.state = state;
       end:
 	if (result)
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-				  "Error transitioning device [%s] to D%d\n",
-				  device->pnp.bus_id, state));
+		ACPI_WARNING((AE_INFO, "Transitioning device [%s] to D%d",
+			      device->pnp.bus_id, state));
 
 	return_VALUE(result);
 }
@@ -516,9 +512,7 @@
 	entry = create_proc_entry(ACPI_POWER_FILE_STATUS,
 				  S_IRUGO, acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create '%s' fs entry\n",
-				  ACPI_POWER_FILE_STATUS));
+		return_VALUE(-EIO);
 	else {
 		entry->proc_fops = &acpi_power_fops;
 		entry->data = acpi_driver_data(device);
diff -urN oldtree/drivers/acpi/processor_core.c newtree/drivers/acpi/processor_core.c
--- oldtree/drivers/acpi/processor_core.c	2006-02-19 11:41:00.829217040 +0000
+++ newtree/drivers/acpi/processor_core.c	2006-02-21 15:58:09.941635200 +0000
@@ -328,9 +328,7 @@
 	entry = create_proc_entry(ACPI_PROCESSOR_FILE_INFO,
 				  S_IRUGO, acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create '%s' fs entry\n",
-				  ACPI_PROCESSOR_FILE_INFO));
+		return_VALUE(-EIO);
 	else {
 		entry->proc_fops = &acpi_processor_info_fops;
 		entry->data = acpi_driver_data(device);
@@ -342,9 +340,7 @@
 				  S_IFREG | S_IRUGO | S_IWUSR,
 				  acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create '%s' fs entry\n",
-				  ACPI_PROCESSOR_FILE_THROTTLING));
+		return_VALUE(-EIO);
 	else {
 		entry->proc_fops = &acpi_processor_throttling_fops;
 		entry->data = acpi_driver_data(device);
@@ -356,9 +352,7 @@
 				  S_IFREG | S_IRUGO | S_IWUSR,
 				  acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create '%s' fs entry\n",
-				  ACPI_PROCESSOR_FILE_LIMIT));
+		return_VALUE( -EIO);
 	else {
 		entry->proc_fops = &acpi_processor_limit_fops;
 		entry->data = acpi_driver_data(device);
@@ -459,8 +453,7 @@
 	 */
 	status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error evaluating processor object\n"));
+		ACPI_ERROR((AE_INFO, "Evaluating processor object"));
 		return_VALUE(-ENODEV);
 	}
 
@@ -490,9 +483,9 @@
 	if (cpu_index >= NR_CPUS) {
 		if (ACPI_FAILURE
 		    (acpi_processor_hotadd_init(pr->handle, &pr->id))) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Error getting cpuindex for acpiid 0x%x\n",
-					  pr->acpi_id));
+			ACPI_ERROR((AE_INFO,
+				    "Getting cpuindex for acpiid 0x%x",
+				    pr->acpi_id));
 			return_VALUE(-ENODEV);
 		}
 	}
@@ -503,8 +496,8 @@
 	if (!object.processor.pblk_address)
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n"));
 	else if (object.processor.pblk_length != 6)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid PBLK length [%d]\n",
-				  object.processor.pblk_length));
+		ACPI_ERROR((AE_INFO, "Invalid PBLK length [%d]",
+			    object.processor.pblk_length));
 	else {
 		pr->throttling.address = object.processor.pblk_address;
 		pr->throttling.duty_offset = acpi_fadt.duty_offset;
@@ -558,8 +551,8 @@
 	 */
 	if (processor_device_array[pr->id] != NULL &&
 	    processor_device_array[pr->id] != (void *)device) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "BIOS reporting wrong ACPI id"
-			"for the processor\n"));
+		ACPI_WARNING((AE_INFO, "BIOS reporting wrong ACPI id"
+			    "for the processor"));
 		return_VALUE(-ENODEV);
 	}
 	processor_device_array[pr->id] = (void *)device;
@@ -572,10 +565,6 @@
 
 	status = acpi_install_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
 					     acpi_processor_notify, pr);
-	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error installing device notify handler\n"));
-	}
 
 	/* _PDC call should be done before doing anything else (if reqd.). */
 	arch_acpi_processor_init_pdc(pr);
@@ -675,10 +664,6 @@
 
 	status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
 					    acpi_processor_notify);
-	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error removing notify handler\n"));
-	}
 
 	acpi_processor_remove_fs(device);
 
@@ -705,8 +690,7 @@
 
 	status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
 	if (ACPI_FAILURE(status) || !(sta & ACPI_STA_PRESENT)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Processor Device is not present\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present"));
 		return_VALUE(0);
 	}
 	return_VALUE(1);
@@ -767,15 +751,14 @@
 		if (acpi_bus_get_device(handle, &device)) {
 			result = acpi_processor_device_add(handle, &device);
 			if (result)
-				ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-						  "Unable to add the device\n"));
+				ACPI_ERROR((AE_INFO,
+					    "Unable to add the device"));
 			break;
 		}
 
 		pr = acpi_driver_data(device);
 		if (!pr) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Driver data is NULL\n"));
+			ACPI_ERROR((AE_INFO, "Driver data is NULL"));
 			break;
 		}
 
@@ -788,9 +771,8 @@
 		if ((!result) && ((pr->id >= 0) && (pr->id < NR_CPUS))) {
 			kobject_uevent(&device->kobj, KOBJ_ONLINE);
 		} else {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Device [%s] failed to start\n",
-					  acpi_device_bid(device)));
+			ACPI_ERROR((AE_INFO, "Device [%s] failed to start",
+				    acpi_device_bid(device)));
 		}
 		break;
 	case ACPI_NOTIFY_EJECT_REQUEST:
@@ -798,14 +780,14 @@
 				  "received ACPI_NOTIFY_EJECT_REQUEST\n"));
 
 		if (acpi_bus_get_device(handle, &device)) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Device don't exist, dropping EJECT\n"));
+			ACPI_ERROR((AE_INFO,
+				    "Device don't exist, dropping EJECT"));
 			break;
 		}
 		pr = acpi_driver_data(device);
 		if (!pr) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Driver data is NULL, dropping EJECT\n"));
+			ACPI_ERROR((AE_INFO,
+				    "Driver data is NULL, dropping EJECT"));
 			return_VOID;
 		}
 
diff -urN oldtree/drivers/acpi/processor_idle.c newtree/drivers/acpi/processor_idle.c
--- oldtree/drivers/acpi/processor_idle.c	2006-02-19 11:41:00.830216888 +0000
+++ newtree/drivers/acpi/processor_idle.c	2006-02-21 15:58:09.942635048 +0000
@@ -665,8 +665,7 @@
 
 	/* There must be at least 2 elements */
 	if (!cst || (cst->type != ACPI_TYPE_PACKAGE) || cst->package.count < 2) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "not enough elements in _CST\n"));
+		ACPI_ERROR((AE_INFO, "not enough elements in _CST"));
 		status = -EFAULT;
 		goto end;
 	}
@@ -675,8 +674,7 @@
 
 	/* Validate number of power states. */
 	if (count < 1 || count != cst->package.count - 1) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "count given by _CST is not valid\n"));
+		ACPI_ERROR((AE_INFO, "count given by _CST is not valid"));
 		status = -EFAULT;
 		goto end;
 	}
@@ -1096,8 +1094,8 @@
 		status =
 		    acpi_os_write_port(acpi_fadt.smi_cmd, acpi_fadt.cst_cnt, 8);
 		if (ACPI_FAILURE(status)) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Notifying BIOS of _CST ability failed\n"));
+			ACPI_EXCEPTION((AE_INFO, status,
+					"Notifying BIOS of _CST ability failed"));
 		}
 	}
 
@@ -1126,9 +1124,7 @@
 	entry = create_proc_entry(ACPI_PROCESSOR_FILE_POWER,
 				  S_IRUGO, acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create '%s' fs entry\n",
-				  ACPI_PROCESSOR_FILE_POWER));
+		return -EIO;
 	else {
 		entry->proc_fops = &acpi_processor_power_fops;
 		entry->data = acpi_driver_data(device);
diff -urN oldtree/drivers/acpi/processor_perflib.c newtree/drivers/acpi/processor_perflib.c
--- oldtree/drivers/acpi/processor_perflib.c	2006-02-19 11:41:00.830216888 +0000
+++ newtree/drivers/acpi/processor_perflib.c	2006-02-21 15:58:10.606534120 +0000
@@ -34,6 +34,7 @@
 #ifdef CONFIG_X86_ACPI_CPUFREQ_PROC_INTF
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 #endif
@@ -48,7 +49,7 @@
 #define _COMPONENT		ACPI_PROCESSOR_COMPONENT
 ACPI_MODULE_NAME("acpi_processor")
 
-static DECLARE_MUTEX(performance_sem);
+static DEFINE_MUTEX(performance_mutex);
 
 /*
  * _PPC support is implemented as a CPUfreq policy notifier:
@@ -72,7 +73,7 @@
 	struct acpi_processor *pr;
 	unsigned int ppc = 0;
 
-	down(&performance_sem);
+	mutex_lock(&performance_mutex);
 
 	if (event != CPUFREQ_INCOMPATIBLE)
 		goto out;
@@ -93,7 +94,7 @@
 				     core_frequency * 1000);
 
       out:
-	up(&performance_sem);
+	mutex_unlock(&performance_mutex);
 
 	return 0;
 }
@@ -122,7 +123,7 @@
 		acpi_processor_ppc_status |= PPC_IN_USE;
 
 	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PPC\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PPC"));
 		return_VALUE(-ENODEV);
 	}
 
@@ -171,14 +172,14 @@
 
 	status = acpi_evaluate_object(pr->handle, "_PCT", NULL, &buffer);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PCT\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PCT"));
 		return_VALUE(-ENODEV);
 	}
 
 	pct = (union acpi_object *)buffer.pointer;
 	if (!pct || (pct->type != ACPI_TYPE_PACKAGE)
 	    || (pct->package.count != 2)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PCT data\n"));
+		ACPI_ERROR((AE_INFO, "Invalid _PCT data"));
 		result = -EFAULT;
 		goto end;
 	}
@@ -192,8 +193,7 @@
 	if ((obj.type != ACPI_TYPE_BUFFER)
 	    || (obj.buffer.length < sizeof(struct acpi_pct_register))
 	    || (obj.buffer.pointer == NULL)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Invalid _PCT data (control_register)\n"));
+		ACPI_ERROR((AE_INFO, "Invalid _PCT data (control_register)"));
 		result = -EFAULT;
 		goto end;
 	}
@@ -209,8 +209,7 @@
 	if ((obj.type != ACPI_TYPE_BUFFER)
 	    || (obj.buffer.length < sizeof(struct acpi_pct_register))
 	    || (obj.buffer.pointer == NULL)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Invalid _PCT data (status_register)\n"));
+		ACPI_ERROR((AE_INFO, "Invalid _PCT data (status_register)"));
 		result = -EFAULT;
 		goto end;
 	}
@@ -238,13 +237,13 @@
 
 	status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PSS\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PSS"));
 		return_VALUE(-ENODEV);
 	}
 
 	pss = (union acpi_object *)buffer.pointer;
 	if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data\n"));
+		ACPI_ERROR((AE_INFO, "Invalid _PSS data"));
 		result = -EFAULT;
 		goto end;
 	}
@@ -273,8 +272,7 @@
 		status = acpi_extract_package(&(pss->package.elements[i]),
 					      &format, &state);
 		if (ACPI_FAILURE(status)) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Invalid _PSS data\n"));
+			ACPI_EXCEPTION((AE_INFO, status, "Invalid _PSS data"));
 			result = -EFAULT;
 			kfree(pr->performance->states);
 			goto end;
@@ -290,8 +288,8 @@
 				  (u32) px->control, (u32) px->status));
 
 		if (!px->core_frequency) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Invalid _PSS data: freq is zero\n"));
+			ACPI_ERROR((AE_INFO,
+				    "Invalid _PSS data: freq is zero"));
 			result = -EFAULT;
 			kfree(pr->performance->states);
 			goto end;
@@ -386,10 +384,10 @@
 	status = acpi_os_write_port(acpi_fadt.smi_cmd,
 				    (u32) acpi_fadt.pstate_cnt, 8);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Failed to write pstate_cnt [0x%x] to "
-				  "smi_cmd [0x%x]\n", acpi_fadt.pstate_cnt,
-				  acpi_fadt.smi_cmd));
+		ACPI_EXCEPTION((AE_INFO, status,
+				"Failed to write pstate_cnt [0x%x] to "
+				"smi_cmd [0x%x]", acpi_fadt.pstate_cnt,
+				acpi_fadt.smi_cmd));
 		module_put(calling_module);
 		return_VALUE(status);
 	}
@@ -513,11 +511,7 @@
 	entry = create_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE,
 				  S_IFREG | S_IRUGO | S_IWUSR,
 				  acpi_device_dir(device));
-	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create '%s' fs entry\n",
-				  ACPI_PROCESSOR_FILE_PERFORMANCE));
-	else {
+	if (entry){
 		acpi_processor_perf_fops.write = acpi_processor_write_performance;
 		entry->proc_fops = &acpi_processor_perf_fops;
 		entry->data = acpi_driver_data(device);
@@ -553,6 +547,234 @@
 }
 #endif				/* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */
 
+static int acpi_processor_get_psd(struct acpi_processor	*pr)
+{
+	int result = 0;
+	acpi_status status = AE_OK;
+	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	struct acpi_buffer format = {sizeof("NNNNN"), "NNNNN"};
+	struct acpi_buffer state = {0, NULL};
+	union acpi_object  *psd = NULL;
+	struct acpi_psd_package *pdomain;
+
+	ACPI_FUNCTION_TRACE("acpi_processor_get_psd");
+
+	status = acpi_evaluate_object(pr->handle, "_PSD", NULL, &buffer);
+	if (ACPI_FAILURE(status)) {
+		return_VALUE(-ENODEV);
+	}
+
+	psd = (union acpi_object *) buffer.pointer;
+	if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
+		result = -EFAULT;
+		goto end;
+	}
+
+	if (psd->package.count != 1) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
+		result = -EFAULT;
+		goto end;
+	}
+
+	pdomain = &(pr->performance->domain_info);
+
+	state.length = sizeof(struct acpi_psd_package);
+	state.pointer = pdomain;
+
+	status = acpi_extract_package(&(psd->package.elements[0]),
+		&format, &state);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
+		result = -EFAULT;
+		goto end;
+	}
+
+	if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:num_entries\n"));
+		result = -EFAULT;
+		goto end;
+	}
+
+	if (pdomain->revision != ACPI_PSD_REV0_REVISION) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:revision\n"));
+		result = -EFAULT;
+		goto end;
+	}
+
+end:
+	acpi_os_free(buffer.pointer);
+	return_VALUE(result);
+}
+
+int acpi_processor_preregister_performance(
+		struct acpi_processor_performance **performance)
+{
+	int count, count_target;
+	int retval = 0;
+	unsigned int i, j;
+	cpumask_t covered_cpus;
+	struct acpi_processor *pr;
+	struct acpi_psd_package *pdomain;
+	struct acpi_processor *match_pr;
+	struct acpi_psd_package *match_pdomain;
+
+	ACPI_FUNCTION_TRACE("acpi_processor_preregister_performance");
+
+	mutex_lock(&performance_mutex);
+
+	retval = 0;
+
+	/* Call _PSD for all CPUs */
+	for_each_cpu(i) {
+		pr = processors[i];
+		if (!pr) {
+			/* Look only at processors in ACPI namespace */
+			continue;
+		}
+
+		if (pr->performance) {
+			retval = -EBUSY;
+			continue;
+		}
+
+		if (!performance || !performance[i]) {
+			retval = -EINVAL;
+			continue;
+		}
+
+		pr->performance = performance[i];
+		cpu_set(i, pr->performance->shared_cpu_map);
+		if (acpi_processor_get_psd(pr)) {
+			retval = -EINVAL;
+			continue;
+		}
+	}
+	if (retval)
+		goto err_ret;
+
+	/*
+	 * Now that we have _PSD data from all CPUs, lets setup P-state 
+	 * domain info.
+	 */
+	for_each_cpu(i) {
+		pr = processors[i];
+		if (!pr)
+			continue;
+
+		/* Basic validity check for domain info */
+		pdomain = &(pr->performance->domain_info);
+		if ((pdomain->revision != ACPI_PSD_REV0_REVISION) ||
+		    (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES)) {
+			retval = -EINVAL;
+			goto err_ret;
+		}
+		if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL &&
+		    pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY &&
+		    pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) {
+			retval = -EINVAL;
+			goto err_ret;
+		}
+	}
+
+	cpus_clear(covered_cpus);
+	for_each_cpu(i) {
+		pr = processors[i];
+		if (!pr)
+			continue;
+
+		if (cpu_isset(i, covered_cpus))
+			continue;
+
+		pdomain = &(pr->performance->domain_info);
+		cpu_set(i, pr->performance->shared_cpu_map);
+		cpu_set(i, covered_cpus);
+		if (pdomain->num_processors <= 1)
+			continue;
+
+		/* Validate the Domain info */
+		count_target = pdomain->num_processors;
+		count = 1;
+		if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL ||
+		    pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL) {
+			pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL;
+		} else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY) {
+			pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+		}
+
+		for_each_cpu(j) {
+			if (i == j)
+				continue;
+
+			match_pr = processors[j];
+			if (!match_pr)
+				continue;
+
+			match_pdomain = &(match_pr->performance->domain_info);
+			if (match_pdomain->domain != pdomain->domain)
+				continue;
+
+			/* Here i and j are in the same domain */
+
+			if (match_pdomain->num_processors != count_target) {
+				retval = -EINVAL;
+				goto err_ret;
+			}
+
+			if (pdomain->coord_type != match_pdomain->coord_type) {
+				retval = -EINVAL;
+				goto err_ret;
+			}
+
+			cpu_set(j, covered_cpus);
+			cpu_set(j, pr->performance->shared_cpu_map);
+			count++;
+		}
+
+		for_each_cpu(j) {
+			if (i == j)
+				continue;
+
+			match_pr = processors[j];
+			if (!match_pr)
+				continue;
+
+			match_pdomain = &(match_pr->performance->domain_info);
+			if (match_pdomain->domain != pdomain->domain)
+				continue;
+
+			match_pr->performance->shared_type = 
+					pr->performance->shared_type;
+			match_pr->performance->shared_cpu_map =
+				pr->performance->shared_cpu_map;
+		}
+	}
+
+err_ret:
+	if (retval) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error while parsing _PSD domain information. Assuming no coordination\n"));
+	}
+
+	for_each_cpu(i) {
+		pr = processors[i];
+		if (!pr || !pr->performance)
+			continue;
+
+		/* Assume no coordination on any error parsing domain info */
+		if (retval) {
+			cpus_clear(pr->performance->shared_cpu_map);
+			cpu_set(i, pr->performance->shared_cpu_map);
+			pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL;
+		}
+		pr->performance = NULL; /* Will be set for real in register */
+	}
+
+	mutex_unlock(&performance_mutex);
+	return_VALUE(retval);
+}
+EXPORT_SYMBOL(acpi_processor_preregister_performance);
+
+
 int
 acpi_processor_register_performance(struct acpi_processor_performance
 				    *performance, unsigned int cpu)
@@ -564,16 +786,16 @@
 	if (!(acpi_processor_ppc_status & PPC_REGISTERED))
 		return_VALUE(-EINVAL);
 
-	down(&performance_sem);
+	mutex_lock(&performance_mutex);
 
 	pr = processors[cpu];
 	if (!pr) {
-		up(&performance_sem);
+		mutex_unlock(&performance_mutex);
 		return_VALUE(-ENODEV);
 	}
 
 	if (pr->performance) {
-		up(&performance_sem);
+		mutex_unlock(&performance_mutex);
 		return_VALUE(-EBUSY);
 	}
 
@@ -581,13 +803,13 @@
 
 	if (acpi_processor_get_performance_info(pr)) {
 		pr->performance = NULL;
-		up(&performance_sem);
+		mutex_unlock(&performance_mutex);
 		return_VALUE(-EIO);
 	}
 
 	acpi_cpufreq_add_file(pr);
 
-	up(&performance_sem);
+	mutex_unlock(&performance_mutex);
 	return_VALUE(0);
 }
 
@@ -601,11 +823,11 @@
 
 	ACPI_FUNCTION_TRACE("acpi_processor_unregister_performance");
 
-	down(&performance_sem);
+	mutex_lock(&performance_mutex);
 
 	pr = processors[cpu];
 	if (!pr) {
-		up(&performance_sem);
+		mutex_unlock(&performance_mutex);
 		return_VOID;
 	}
 
@@ -614,7 +836,7 @@
 
 	acpi_cpufreq_remove_file(pr);
 
-	up(&performance_sem);
+	mutex_unlock(&performance_mutex);
 
 	return_VOID;
 }
diff -urN oldtree/drivers/acpi/processor_thermal.c newtree/drivers/acpi/processor_thermal.c
--- oldtree/drivers/acpi/processor_thermal.c	2006-02-19 11:41:00.831216736 +0000
+++ newtree/drivers/acpi/processor_thermal.c	2006-02-21 15:58:10.045619392 +0000
@@ -82,7 +82,7 @@
 
       end:
 	if (result)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to set limit\n"));
+		ACPI_ERROR((AE_INFO, "Unable to set limit"));
 
 	return_VALUE(result);
 }
@@ -289,8 +289,7 @@
 
 		result = acpi_processor_apply_limit(pr);
 		if (result)
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Unable to set thermal limit\n"));
+			ACPI_ERROR((AE_INFO, "Unable to set thermal limit"));
 
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Thermal limit now (P%d:T%d)\n",
 				  pr->limit.thermal.px, pr->limit.thermal.tx));
@@ -362,25 +361,23 @@
 	ACPI_FUNCTION_TRACE("acpi_processor_write_limit");
 
 	if (!pr || (count > sizeof(limit_string) - 1)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument\n"));
 		return_VALUE(-EINVAL);
 	}
 
 	if (copy_from_user(limit_string, buffer, count)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data\n"));
 		return_VALUE(-EFAULT);
 	}
 
 	limit_string[count] = '\0';
 
 	if (sscanf(limit_string, "%d:%d", &px, &tx) != 2) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n"));
+		ACPI_ERROR((AE_INFO, "Invalid data format"));
 		return_VALUE(-EINVAL);
 	}
 
 	if (pr->flags.throttling) {
 		if ((tx < 0) || (tx > (pr->throttling.state_count - 1))) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid tx\n"));
+			ACPI_ERROR((AE_INFO, "Invalid tx"));
 			return_VALUE(-EINVAL);
 		}
 		pr->limit.user.tx = tx;
diff -urN oldtree/drivers/acpi/processor_throttling.c newtree/drivers/acpi/processor_throttling.c
--- oldtree/drivers/acpi/processor_throttling.c	2006-02-19 11:41:00.832216584 +0000
+++ newtree/drivers/acpi/processor_throttling.c	2006-02-21 15:58:10.045619392 +0000
@@ -196,7 +196,7 @@
 	}
 	/* TBD: Support duty_cycle values that span bit 4. */
 	else if ((pr->throttling.duty_offset + pr->throttling.duty_width) > 4) {
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "duty_cycle spans bit 4\n"));
+		ACPI_WARNING((AE_INFO, "duty_cycle spans bit 4"));
 		return_VALUE(0);
 	}
 
diff -urN oldtree/drivers/acpi/resources/rscalc.c newtree/drivers/acpi/resources/rscalc.c
--- oldtree/drivers/acpi/resources/rscalc.c	2006-02-19 11:41:00.867211264 +0000
+++ newtree/drivers/acpi/resources/rscalc.c	2006-02-21 15:58:10.046619240 +0000
@@ -78,6 +78,7 @@
 	ACPI_FUNCTION_ENTRY();
 
 	for (bits_set = 0; bit_field; bits_set++) {
+
 		/* Zero the least significant bit that is set */
 
 		bit_field &= (bit_field - 1);
@@ -154,6 +155,7 @@
 	 * length, minus one byte for the resource_source_index itself.
 	 */
 	if (resource_length > minimum_aml_resource_length) {
+
 		/* Compute the length of the optional string */
 
 		string_length =
@@ -162,7 +164,7 @@
 
 	/* Round up length to 32 bits for internal structure alignment */
 
-	return (ACPI_ROUND_UP_to_32_bITS(string_length));
+	return ((u32) ACPI_ROUND_UP_to_32_bITS(string_length));
 }
 
 /*******************************************************************************
@@ -191,6 +193,7 @@
 	/* Traverse entire list of internal resource descriptors */
 
 	while (resource) {
+
 		/* Validate the descriptor type */
 
 		if (resource->type > ACPI_RESOURCE_TYPE_MAX) {
@@ -214,6 +217,7 @@
 			 * is a Large Resource data type.
 			 */
 			if (resource->data.vendor.byte_length > 7) {
+
 				/* Base size of a Large resource descriptor */
 
 				total_size =
@@ -346,6 +350,7 @@
 	/* Walk the list of AML resource descriptors */
 
 	while (aml_buffer < end_aml) {
+
 		/* Validate the Resource Type and Resource Length */
 
 		status = acpi_ut_validate_resource(aml_buffer, &resource_index);
@@ -429,7 +434,7 @@
 			 */
 			buffer++;
 
-			extra_struct_bytes =
+			extra_struct_bytes = (u32)
 			    /*
 			     * Add 4 bytes for each additional interrupt. Note: at
 			     * least one interrupt is required and is included in
@@ -448,7 +453,7 @@
 			 * Add the size of any optional data (resource_source)
 			 * Ensure a 64-bit boundary for the structure
 			 */
-			extra_struct_bytes =
+			extra_struct_bytes = (u32)
 			    ACPI_ROUND_UP_to_64_bITS
 			    (acpi_rs_stream_option_length
 			     (resource_length, minimum_aml_resource_length));
@@ -523,6 +528,7 @@
 	top_object_list = package_object->package.elements;
 
 	for (index = 0; index < number_of_elements; index++) {
+
 		/* Dereference the sub-package */
 
 		package_element = *top_object_list;
diff -urN oldtree/drivers/acpi/resources/rslist.c newtree/drivers/acpi/resources/rslist.c
--- oldtree/drivers/acpi/resources/rslist.c	2006-02-19 11:41:00.875210048 +0000
+++ newtree/drivers/acpi/resources/rslist.c	2006-02-21 15:58:10.047619088 +0000
@@ -77,6 +77,7 @@
 	/* Loop until end-of-buffer or an end_tag is found */
 
 	while (aml < end_aml) {
+
 		/* Validate the Resource Type and Resource Length */
 
 		status = acpi_ut_validate_resource(aml, &resource_index);
@@ -155,6 +156,7 @@
 	/* Walk the resource descriptor list, convert each descriptor */
 
 	while (aml < end_aml) {
+
 		/* Validate the (internal) Resource Type */
 
 		if (resource->type > ACPI_RESOURCE_TYPE_MAX) {
@@ -191,6 +193,7 @@
 		/* Check for end-of-list, normal exit */
 
 		if (resource->type == ACPI_RESOURCE_TYPE_END_TAG) {
+
 			/* An End Tag indicates the end of the input Resource Template */
 
 			return_ACPI_STATUS(AE_OK);
diff -urN oldtree/drivers/acpi/resources/rsmisc.c newtree/drivers/acpi/resources/rsmisc.c
--- oldtree/drivers/acpi/resources/rsmisc.c	2006-02-19 11:41:00.879209440 +0000
+++ newtree/drivers/acpi/resources/rsmisc.c	2006-02-21 15:58:10.048618936 +0000
@@ -84,6 +84,7 @@
 	ACPI_FUNCTION_TRACE("rs_get_resource");
 
 	if (((acpi_native_uint) resource) & 0x3) {
+
 		/* Each internal resource struct is expected to be 32-bit aligned */
 
 		ACPI_WARNING((AE_INFO,
@@ -295,9 +296,11 @@
 
       exit:
 	if (!flags_mode) {
+
 		/* Round the resource struct length up to the next 32-bit boundary */
 
-		resource->length = ACPI_ROUND_UP_to_32_bITS(resource->length);
+		resource->length =
+		    (u32) ACPI_ROUND_UP_to_32_bITS(resource->length);
 	}
 	return_ACPI_STATUS(AE_OK);
 }
@@ -535,6 +538,7 @@
 
 resource->data.extended_irq.interrupt_count = temp8;
 if (temp8 < 1) {
+
 	/* Must have at least one IRQ */
 
 	return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH);
diff -urN oldtree/drivers/acpi/resources/rsutils.c newtree/drivers/acpi/resources/rsutils.c
--- oldtree/drivers/acpi/resources/rsutils.c	2006-02-19 11:41:00.880209288 +0000
+++ newtree/drivers/acpi/resources/rsutils.c	2006-02-21 15:58:10.048618936 +0000
@@ -205,6 +205,7 @@
 	/* Length is stored differently for large and small descriptors */
 
 	if (aml->small_header.descriptor_type & ACPI_RESOURCE_NAME_LARGE) {
+
 		/* Large descriptor -- bytes 1-2 contain the 16-bit length */
 
 		ACPI_MOVE_16_TO_16(&aml->large_header.resource_length,
@@ -328,6 +329,7 @@
 	 * we add 1 to the minimum length.
 	 */
 	if (total_length > (acpi_rsdesc_size) (minimum_length + 1)) {
+
 		/* Get the resource_source_index */
 
 		resource_source->index = aml_resource_source[0];
@@ -351,16 +353,20 @@
 		 * Zero the entire area of the buffer.
 		 */
 		total_length =
+		    (u32)
 		    ACPI_ROUND_UP_to_32_bITS(ACPI_STRLEN
-					     ((char *)&aml_resource_source[1]) +
-					     1);
+					     (ACPI_CAST_PTR
+					      (char,
+					       &aml_resource_source[1])) + 1);
+
 		ACPI_MEMSET(resource_source->string_ptr, 0, total_length);
 
 		/* Copy the resource_source string to the destination */
 
 		resource_source->string_length =
 		    acpi_rs_strcpy(resource_source->string_ptr,
-				   (char *)&aml_resource_source[1]);
+				   ACPI_CAST_PTR(char,
+						 &aml_resource_source[1]));
 
 		return ((acpi_rs_length) total_length);
 	}
@@ -405,6 +411,7 @@
 	/* Non-zero string length indicates presence of a resource_source */
 
 	if (resource_source->string_length) {
+
 		/* Point to the end of the AML descriptor */
 
 		aml_resource_source = ACPI_ADD_PTR(u8, aml, minimum_length);
@@ -415,7 +422,7 @@
 
 		/* Copy the resource_source string */
 
-		ACPI_STRCPY((char *)&aml_resource_source[1],
+		ACPI_STRCPY(ACPI_CAST_PTR(char, &aml_resource_source[1]),
 			    resource_source->string_ptr);
 
 		/*
@@ -435,9 +442,9 @@
  *
  * FUNCTION:    acpi_rs_get_prt_method_data
  *
- * PARAMETERS:  Handle          - a handle to the containing object
- *              ret_buffer      - a pointer to a buffer structure for the
- *                                  results
+ * PARAMETERS:  Handle          - Handle to the containing object
+ *              ret_buffer      - Pointer to a buffer structure for the
+ *                                results
  *
  * RETURN:      Status
  *
@@ -483,9 +490,9 @@
  *
  * FUNCTION:    acpi_rs_get_crs_method_data
  *
- * PARAMETERS:  Handle          - a handle to the containing object
- *              ret_buffer      - a pointer to a buffer structure for the
- *                                  results
+ * PARAMETERS:  Handle          - Handle to the containing object
+ *              ret_buffer      - Pointer to a buffer structure for the
+ *                                results
  *
  * RETURN:      Status
  *
@@ -532,9 +539,9 @@
  *
  * FUNCTION:    acpi_rs_get_prs_method_data
  *
- * PARAMETERS:  Handle          - a handle to the containing object
- *              ret_buffer      - a pointer to a buffer structure for the
- *                                  results
+ * PARAMETERS:  Handle          - Handle to the containing object
+ *              ret_buffer      - Pointer to a buffer structure for the
+ *                                results
  *
  * RETURN:      Status
  *
@@ -583,10 +590,10 @@
  *
  * FUNCTION:    acpi_rs_get_method_data
  *
- * PARAMETERS:  Handle          - a handle to the containing object
+ * PARAMETERS:  Handle          - Handle to the containing object
  *              Path            - Path to method, relative to Handle
- *              ret_buffer      - a pointer to a buffer structure for the
- *                                  results
+ *              ret_buffer      - Pointer to a buffer structure for the
+ *                                results
  *
  * RETURN:      Status
  *
@@ -634,9 +641,9 @@
  *
  * FUNCTION:    acpi_rs_set_srs_method_data
  *
- * PARAMETERS:  Handle          - a handle to the containing object
- *              in_buffer       - a pointer to a buffer structure of the
- *                                  parameter
+ * PARAMETERS:  Handle          - Handle to the containing object
+ *              in_buffer       - Pointer to a buffer structure of the
+ *                                parameter
  *
  * RETURN:      Status
  *
@@ -696,6 +703,7 @@
 
 	status = acpi_ns_evaluate_relative(METHOD_NAME__SRS, &info);
 	if (ACPI_SUCCESS(status)) {
+
 		/* Delete any return object (especially if implicit_return is enabled) */
 
 		if (info.return_object) {
diff -urN oldtree/drivers/acpi/resources/rsxface.c newtree/drivers/acpi/resources/rsxface.c
--- oldtree/drivers/acpi/resources/rsxface.c	2006-02-19 11:41:00.881209136 +0000
+++ newtree/drivers/acpi/resources/rsxface.c	2006-02-21 15:58:10.049618784 +0000
@@ -279,6 +279,7 @@
 	/* Walk the resource list until the end_tag is found (or buffer end) */
 
 	while (resource < resource_end) {
+
 		/* Sanity check the resource */
 
 		if (resource->type > ACPI_RESOURCE_TYPE_MAX) {
@@ -291,6 +292,7 @@
 		status = user_function(resource, context);
 		if (ACPI_FAILURE(status)) {
 			if (status == AE_CTRL_TERMINATE) {
+
 				/* This is an OK termination by the user function */
 
 				status = AE_OK;
diff -urN oldtree/drivers/acpi/scan.c newtree/drivers/acpi/scan.c
--- oldtree/drivers/acpi/scan.c	2006-02-19 11:41:00.882208984 +0000
+++ newtree/drivers/acpi/scan.c	2006-02-21 15:58:10.607533968 +0000
@@ -5,6 +5,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/acpi.h>
+#include <linux/mutex.h>
 
 #include <acpi/acpi_drivers.h>
 #include <acpi/acinterp.h>	/* for acpi_ex_eisa_id_to_string() */
@@ -321,15 +322,14 @@
 	/* _PRW */
 	status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRW\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW"));
 		goto end;
 	}
 
 	package = (union acpi_object *)buffer.pointer;
 	status = acpi_bus_extract_wakeup_device_power_package(device, package);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error extracting _PRW package\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package"));
 		goto end;
 	}
 
@@ -472,7 +472,7 @@
    -------------------------------------------------------------------------- */
 
 static LIST_HEAD(acpi_bus_drivers);
-static DECLARE_MUTEX(acpi_bus_drivers_lock);
+static DEFINE_MUTEX(acpi_bus_drivers_lock);
 
 /**
  * acpi_bus_match - match device IDs to driver's supported IDs
@@ -1001,7 +1001,7 @@
 
 	device = kmalloc(sizeof(struct acpi_device), GFP_KERNEL);
 	if (!device) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Memory allocation error\n"));
+		ACPI_ERROR((AE_INFO, "Memory allocation error"));
 		return_VALUE(-ENOMEM);
 	}
 	memset(device, 0, sizeof(struct acpi_device));
diff -urN oldtree/drivers/acpi/sony_acpi.c newtree/drivers/acpi/sony_acpi.c
--- oldtree/drivers/acpi/sony_acpi.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/acpi/sony_acpi.c	2006-02-21 15:58:11.067464048 +0000
@@ -0,0 +1,392 @@
+/*
+ * ACPI Sony Notebook Control Driver (SNC)
+ *
+ * Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net>
+ *
+ * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c
+ * which are copyrighted by their respective authors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acpi_bus.h>
+#include <asm/uaccess.h>
+
+#define ACPI_SNC_CLASS		"sony"
+#define ACPI_SNC_HID		"SNY5001"
+#define ACPI_SNC_DRIVER_NAME	"ACPI Sony Notebook Control Driver v0.2"
+
+#define LOG_PFX			KERN_WARNING "sony_acpi: "
+
+MODULE_AUTHOR("Stelian Pop");
+MODULE_DESCRIPTION(ACPI_SNC_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help "
+			"the development of this driver");
+
+static int sony_acpi_add (struct acpi_device *device);
+static int sony_acpi_remove (struct acpi_device *device, int type);
+
+static struct acpi_driver sony_acpi_driver = {
+	.name	= ACPI_SNC_DRIVER_NAME,
+	.class	= ACPI_SNC_CLASS,
+	.ids	= ACPI_SNC_HID,
+	.ops	= {
+			.add	= sony_acpi_add,
+			.remove	= sony_acpi_remove,
+		  },
+};
+
+static acpi_handle sony_acpi_handle;
+static struct proc_dir_entry *sony_acpi_dir;
+
+static struct sony_acpi_value {
+	char			*name;	 /* name of the entry */
+	struct proc_dir_entry 	*proc;	 /* /proc entry */
+	char			*acpiget;/* name of the ACPI get function */
+	char			*acpiset;/* name of the ACPI get function */
+	int 			min;	 /* minimum allowed value or -1 */
+	int			max;	 /* maximum allowed value or -1 */
+	int			debug;	 /* active only in debug mode ? */
+} sony_acpi_values[] = {
+	{
+		.name		= "brightness",
+		.acpiget	= "GBRT",
+		.acpiset	= "SBRT",
+		.min		= 1,
+		.max		= 8,
+		.debug		= 0,
+	},
+	{
+		.name		= "brightness_default",
+		.acpiget	= "GPBR",
+		.acpiset	= "SPBR",
+		.min		= 1,
+		.max		= 8,
+		.debug		= 0,
+	},
+	{
+		.name		= "cdpower",
+		.acpiget	= "GCDP",
+		.acpiset	= "SCDP",
+		.min		= -1,
+		.max		= -1,
+		.debug		= 0,
+	},
+	{
+		.name		= "PID",
+		.acpiget	= "GPID",
+		.debug		= 1,
+	},
+	{
+		.name		= "CTR",
+		.acpiget	= "GCTR",
+		.acpiset	= "SCTR",
+		.min		= -1,
+		.max		= -1,
+		.debug		= 1,
+	},
+	{
+		.name		= "PCR",
+		.acpiget	= "GPCR",
+		.acpiset	= "SPCR",
+		.min		= -1,
+		.max		= -1,
+		.debug		= 1,
+	},
+	{
+		.name		= "CMI",
+		.acpiget	= "GCMI",
+		.acpiset	= "SCMI",
+		.min		= -1,
+		.max		= -1,
+		.debug		= 1,
+	},
+	{
+		.name		= NULL,
+	}
+};
+
+static int acpi_callgetfunc(acpi_handle handle, char *name, int *result)
+{
+	struct acpi_buffer output;
+	union acpi_object out_obj;
+	acpi_status status;
+
+	output.length = sizeof(out_obj);
+	output.pointer = &out_obj;
+
+	status = acpi_evaluate_object(handle, name, NULL, &output);
+	if ((status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER)) {
+		*result = out_obj.integer.value;
+		return 0;
+	}
+
+	printk(LOG_PFX "acpi_callreadfunc failed\n");
+
+	return -1;
+}
+
+static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
+			    int *result)
+{
+	struct acpi_object_list params;
+	union acpi_object in_obj;
+	struct acpi_buffer output;
+	union acpi_object out_obj;
+	acpi_status status;
+
+	params.count = 1;
+	params.pointer = &in_obj;
+	in_obj.type = ACPI_TYPE_INTEGER;
+	in_obj.integer.value = value;
+
+	output.length = sizeof(out_obj);
+	output.pointer = &out_obj;
+
+	status = acpi_evaluate_object(handle, name, &params, &output);
+	if (status == AE_OK) {
+		if (result != NULL) {
+			if (out_obj.type != ACPI_TYPE_INTEGER) {
+				printk(LOG_PFX "acpi_evaluate_object bad "
+				       "return type\n");
+				return -1;
+			}
+			*result = out_obj.integer.value;
+		}
+		return 0;
+	}
+
+	printk(LOG_PFX "acpi_evaluate_object failed\n");
+
+	return -1;
+}
+
+static int parse_buffer(const char __user *buffer, unsigned long count,
+			int *val) {
+	char s[32];
+	int ret;
+
+	if (count > 31)
+		return -EINVAL;
+	if (copy_from_user(s, buffer, count))
+		return -EFAULT;
+	s[count] = '\0';
+	ret = simple_strtoul(s, NULL, 10);
+	*val = ret;
+	return 0;
+}
+
+static int sony_acpi_read(char* page, char** start, off_t off, int count,
+			  int* eof, void *data)
+{
+	struct sony_acpi_value *item = data;
+	int value;
+
+	if (!item->acpiget)
+		return -EIO;
+
+	if (acpi_callgetfunc(sony_acpi_handle, item->acpiget, &value) < 0)
+		return -EIO;
+
+	return sprintf(page, "%d\n", value);
+}
+
+static int sony_acpi_write(struct file *file, const char __user *buffer,
+			   unsigned long count, void *data)
+{
+	struct sony_acpi_value *item = data;
+	int result;
+	int value;
+
+	if (!item->acpiset)
+		return -EIO;
+
+	if ((result = parse_buffer(buffer, count, &value)) < 0)
+		return result;
+
+	if (item->min != -1 && value < item->min)
+		return -EINVAL;
+	if (item->max != -1 && value > item->max)
+		return -EINVAL;
+
+	if (acpi_callsetfunc(sony_acpi_handle, item->acpiset, value, NULL) < 0)
+		return -EIO;
+
+	return count;
+}
+
+static void sony_acpi_notify(acpi_handle handle, u32 event, void *data)
+{
+	printk(LOG_PFX "sony_acpi_notify\n");
+}
+
+static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
+				      void *context, void **return_value)
+{
+	struct acpi_namespace_node *node;
+	union acpi_operand_object *operand;
+
+	node = (struct acpi_namespace_node *) handle;
+	operand = (union acpi_operand_object *) node->object;
+
+	printk(LOG_PFX "method: name: %4.4s, args %X\n", node->name.ascii,
+	       (u32) operand->method.param_count);
+
+	return AE_OK;
+}
+
+static int __init sony_acpi_add(struct acpi_device *device)
+{
+	acpi_status status;
+	int result;
+	struct sony_acpi_value *item;
+
+	sony_acpi_handle = device->handle;
+
+	acpi_driver_data(device) = NULL;
+	acpi_device_dir(device) = sony_acpi_dir;
+
+	if (debug) {
+		status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_acpi_handle,
+					     1, sony_walk_callback, NULL, NULL);
+		if (ACPI_FAILURE(status)) {
+			printk(LOG_PFX "unable to walk acpi resources\n");
+			result = -ENODEV;
+			goto outwalk;
+		}
+
+		status = acpi_install_notify_handler(sony_acpi_handle,
+						     ACPI_DEVICE_NOTIFY,
+						     sony_acpi_notify,
+						     NULL);
+		if (ACPI_FAILURE(status)) {
+			printk(LOG_PFX "unable to install notify handler\n");
+			result = -ENODEV;
+			goto outnotify;
+		}
+	}
+
+	for (item = sony_acpi_values; item->name; ++item) {
+		acpi_handle handle;
+
+		if (!debug && item->debug)
+			continue;
+
+		if (item->acpiget &&
+		    ACPI_FAILURE(acpi_get_handle(sony_acpi_handle,
+		    		 item->acpiget, &handle)))
+		    	continue;
+
+		if (item->acpiset &&
+		    ACPI_FAILURE(acpi_get_handle(sony_acpi_handle,
+		    		 item->acpiset, &handle)))
+		    	continue;
+
+		item->proc = create_proc_entry(item->name, 0600,
+					       acpi_device_dir(device));
+		if (!item->proc) {
+			printk(LOG_PFX "unable to create proc entry\n");
+			result = -EIO;
+			goto outproc;
+		}
+
+		item->proc->read_proc = sony_acpi_read;
+		item->proc->write_proc = sony_acpi_write;
+		item->proc->data = item;
+		item->proc->owner = THIS_MODULE;
+	}
+
+	printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully installed\n");
+
+	return 0;
+
+outproc:
+	if (debug) {
+		status = acpi_remove_notify_handler(sony_acpi_handle,
+						    ACPI_DEVICE_NOTIFY,
+						    sony_acpi_notify);
+		if (ACPI_FAILURE(status))
+			printk(LOG_PFX "unable to remove notify handler\n");
+	}
+outnotify:
+	for (item = sony_acpi_values; item->name; ++item)
+		if (item->proc)
+			remove_proc_entry(item->name, acpi_device_dir(device));
+outwalk:
+	return result;
+}
+
+
+static int __exit sony_acpi_remove(struct acpi_device *device, int type)
+{
+	acpi_status status;
+	struct sony_acpi_value *item;
+
+	if (debug) {
+		status = acpi_remove_notify_handler(sony_acpi_handle,
+						    ACPI_DEVICE_NOTIFY,
+						    sony_acpi_notify);
+		if (ACPI_FAILURE(status))
+			printk(LOG_PFX "unable to remove notify handler\n");
+	}
+
+	for (item = sony_acpi_values; item->name; ++item)
+		if (item->proc)
+			remove_proc_entry(item->name, acpi_device_dir(device));
+
+	printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully removed\n");
+
+	return 0;
+}
+
+static int __init sony_acpi_init(void)
+{
+	int result;
+
+	sony_acpi_dir = proc_mkdir("sony", acpi_root_dir);
+	if (!sony_acpi_dir) {
+		printk(LOG_PFX "unable to create /proc entry\n");
+		return -ENODEV;
+	}
+	sony_acpi_dir->owner = THIS_MODULE;
+
+	result = acpi_bus_register_driver(&sony_acpi_driver);
+	if (result < 0) {
+		remove_proc_entry("sony", acpi_root_dir);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+
+static void __exit sony_acpi_exit(void)
+{
+	acpi_bus_unregister_driver(&sony_acpi_driver);
+	remove_proc_entry("sony", acpi_root_dir);
+}
+
+module_init(sony_acpi_init);
+module_exit(sony_acpi_exit);
diff -urN oldtree/drivers/acpi/system.c newtree/drivers/acpi/system.c
--- oldtree/drivers/acpi/system.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/acpi/system.c	2006-02-21 15:58:10.051618480 +0000
@@ -161,9 +161,6 @@
 	return_VALUE(error);
 
       Error:
-	ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-			  "Unable to create '%s' proc fs entry\n", name));
-
 	remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir);
 	remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir);
 	remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir);
diff -urN oldtree/drivers/acpi/tables/tbconvrt.c newtree/drivers/acpi/tables/tbconvrt.c
--- oldtree/drivers/acpi/tables/tbconvrt.c	2006-02-19 11:41:00.884208680 +0000
+++ newtree/drivers/acpi/tables/tbconvrt.c	2006-02-21 15:58:10.051618480 +0000
@@ -147,6 +147,7 @@
 	/* Copy the table pointers */
 
 	for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
+
 		/* RSDT pointers are 32 bits, XSDT pointers are 64 bits */
 
 		if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
@@ -515,6 +516,7 @@
 
 	if (acpi_gbl_FADT->revision >= FADT2_REVISION_ID) {
 		if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor_rev2)) {
+
 			/* Length is too short to be a V2.0 table */
 
 			ACPI_WARNING((AE_INFO,
@@ -603,6 +605,7 @@
 	if ((acpi_gbl_RSDP->revision < 2) ||
 	    (acpi_gbl_FACS->length < 32) ||
 	    (!(acpi_gbl_FACS->xfirmware_waking_vector))) {
+
 		/* ACPI 1.0 FACS or short table or optional X_ field is zero */
 
 		acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR(u64,
diff -urN oldtree/drivers/acpi/tables/tbget.c newtree/drivers/acpi/tables/tbget.c
--- oldtree/drivers/acpi/tables/tbget.c	2006-02-19 11:41:00.884208680 +0000
+++ newtree/drivers/acpi/tables/tbget.c	2006-02-21 15:58:10.053618176 +0000
@@ -148,6 +148,10 @@
 					    sizeof(struct acpi_table_header),
 					    (void *)&header);
 		if (ACPI_FAILURE(status)) {
+			ACPI_ERROR((AE_INFO,
+				    "Could not map memory at %8.8X%8.8X for table header",
+				    ACPI_FORMAT_UINT64(address->pointer.
+						       physical)));
 			return_ACPI_STATUS(status);
 		}
 
@@ -208,6 +212,7 @@
 
 	status = acpi_tb_table_override(header, table_info);
 	if (ACPI_SUCCESS(status)) {
+
 		/* Table was overridden by the host OS */
 
 		return_ACPI_STATUS(status);
@@ -250,6 +255,7 @@
 	 */
 	status = acpi_os_table_override(header, &new_table);
 	if (ACPI_FAILURE(status)) {
+
 		/* Some severe error from the OSL, but we basically ignore it */
 
 		ACPI_EXCEPTION((AE_INFO, status,
@@ -258,6 +264,7 @@
 	}
 
 	if (!new_table) {
+
 		/* No table override */
 
 		return_ACPI_STATUS(AE_NO_ACPI_TABLES);
@@ -381,6 +388,7 @@
 
 #if (!ACPI_CHECKSUM_ABORT)
 		if (ACPI_FAILURE(status)) {
+
 			/* Ignore the error if configuration says so */
 
 			status = AE_OK;
@@ -440,6 +448,7 @@
 	 * instance is always in the list head.
 	 */
 	if (instance == 1) {
+
 		/* Get the first */
 
 		*table_ptr_loc = NULL;
diff -urN oldtree/drivers/acpi/tables/tbgetall.c newtree/drivers/acpi/tables/tbgetall.c
--- oldtree/drivers/acpi/tables/tbgetall.c	2006-02-19 11:41:00.885208528 +0000
+++ newtree/drivers/acpi/tables/tbgetall.c	2006-02-21 15:58:10.053618176 +0000
@@ -223,6 +223,7 @@
 	 * any SSDTs.
 	 */
 	for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
+
 		/* Get the table address from the common internal XSDT */
 
 		address.pointer.value = acpi_gbl_XSDT->table_offset_entry[i];
diff -urN oldtree/drivers/acpi/tables/tbinstal.c newtree/drivers/acpi/tables/tbinstal.c
--- oldtree/drivers/acpi/tables/tbinstal.c	2006-02-19 11:41:00.886208376 +0000
+++ newtree/drivers/acpi/tables/tbinstal.c	2006-02-21 15:58:10.054618024 +0000
@@ -84,6 +84,7 @@
 
 		if (!ACPI_STRNCMP(signature, acpi_gbl_table_data[i].signature,
 				  acpi_gbl_table_data[i].sig_length)) {
+
 			/* Found a signature match, return index if requested */
 
 			if (table_info) {
diff -urN oldtree/drivers/acpi/tables/tbrsdt.c newtree/drivers/acpi/tables/tbrsdt.c
--- oldtree/drivers/acpi/tables/tbrsdt.c	2006-02-19 11:41:00.886208376 +0000
+++ newtree/drivers/acpi/tables/tbrsdt.c	2006-02-21 15:58:10.054618024 +0000
@@ -190,6 +190,7 @@
 	}
 
 	if (no_match) {
+
 		/* Invalid RSDT or XSDT signature */
 
 		ACPI_ERROR((AE_INFO,
diff -urN oldtree/drivers/acpi/tables/tbutils.c newtree/drivers/acpi/tables/tbutils.c
--- oldtree/drivers/acpi/tables/tbutils.c	2006-02-19 11:41:00.887208224 +0000
+++ newtree/drivers/acpi/tables/tbutils.c	2006-02-21 15:58:10.055617872 +0000
@@ -96,6 +96,7 @@
 		    (!ACPI_MEMCMP
 		     (table_desc->pointer, new_table_desc->pointer,
 		      new_table_desc->pointer->length))) {
+
 			/* Match: this table is already installed */
 
 			ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
@@ -249,6 +250,7 @@
 	u8 sum = 0;
 
 	if (buffer && length) {
+
 		/*  Buffer and Length are valid   */
 
 		end_buffer = ACPI_ADD_PTR(u8, buffer, length);
diff -urN oldtree/drivers/acpi/tables/tbxface.c newtree/drivers/acpi/tables/tbxface.c
--- oldtree/drivers/acpi/tables/tbxface.c	2006-02-19 11:41:00.888208072 +0000
+++ newtree/drivers/acpi/tables/tbxface.c	2006-02-21 15:58:10.055617872 +0000
@@ -174,6 +174,7 @@
 	status = acpi_tb_install_table(&table_info);
 	if (ACPI_FAILURE(status)) {
 		if (status == AE_ALREADY_EXISTS) {
+
 			/* Table already exists, no error */
 
 			status = AE_OK;
@@ -208,6 +209,7 @@
 	}
 
 	if (ACPI_FAILURE(status)) {
+
 		/* Uninstall table and free the buffer */
 
 		(void)acpi_tb_uninstall_table(table_info.installed_desc);
@@ -397,6 +399,7 @@
 	/* Get the table length */
 
 	if (table_type == ACPI_TABLE_RSDP) {
+
 		/* RSD PTR is the only "table" without a header */
 
 		table_length = sizeof(struct rsdp_descriptor);
diff -urN oldtree/drivers/acpi/tables/tbxfroot.c newtree/drivers/acpi/tables/tbxfroot.c
--- oldtree/drivers/acpi/tables/tbxfroot.c	2006-02-19 11:41:00.888208072 +0000
+++ newtree/drivers/acpi/tables/tbxfroot.c	2006-02-21 15:58:10.056617720 +0000
@@ -75,6 +75,7 @@
 	 *  The signature and checksum must both be correct
 	 */
 	if (ACPI_STRNCMP((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0) {
+
 		/* Nope, BAD Signature */
 
 		return (AE_BAD_SIGNATURE);
@@ -217,6 +218,7 @@
 	/* Ensure that we have a RSDP */
 
 	if (!acpi_gbl_RSDP) {
+
 		/* Get the RSDP */
 
 		status = acpi_os_get_root_pointer(flags, &address);
@@ -327,10 +329,12 @@
 		/* Compare table signatures and table instance */
 
 		if (!ACPI_STRNCMP(header->signature, signature, ACPI_NAME_SIZE)) {
+
 			/* An instance of the table was found */
 
 			j++;
 			if (j >= instance) {
+
 				/* Found the correct instance, get the entire table */
 
 				status =
@@ -434,12 +438,14 @@
 
 	for (mem_rover = start_address; mem_rover < end_address;
 	     mem_rover += ACPI_RSDP_SCAN_STEP) {
+
 		/* The RSDP signature and checksum must both be correct */
 
 		status =
 		    acpi_tb_validate_rsdp(ACPI_CAST_PTR
 					  (struct rsdp_descriptor, mem_rover));
 		if (ACPI_SUCCESS(status)) {
+
 			/* Sig and checksum valid, we have found a real RSDP */
 
 			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -495,6 +501,7 @@
 	 * Scan supports either logical addressing or physical addressing
 	 */
 	if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
+
 		/* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
 
 		status = acpi_os_map_memory((acpi_physical_address)
@@ -542,6 +549,7 @@
 			acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE);
 
 			if (mem_rover) {
+
 				/* Return the physical address */
 
 				physical_address +=
@@ -576,6 +584,7 @@
 		acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
 
 		if (mem_rover) {
+
 			/* Return the physical address */
 
 			physical_address =
@@ -609,6 +618,7 @@
 							 (physical_address),
 							 ACPI_EBDA_WINDOW_SIZE);
 			if (mem_rover) {
+
 				/* Return the physical address */
 
 				table_info->physical_address =
@@ -624,6 +634,7 @@
 						 (ACPI_HI_RSDP_WINDOW_BASE),
 						 ACPI_HI_RSDP_WINDOW_SIZE);
 		if (mem_rover) {
+
 			/* Found it, return the physical address */
 
 			table_info->physical_address =
diff -urN oldtree/drivers/acpi/thermal.c newtree/drivers/acpi/thermal.c
--- oldtree/drivers/acpi/thermal.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/acpi/thermal.c	2006-02-21 15:58:10.058617416 +0000
@@ -323,7 +323,7 @@
 				       &tz->trips.critical.temperature);
 	if (ACPI_FAILURE(status)) {
 		tz->trips.critical.flags.valid = 0;
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No critical threshold\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "No critical threshold"));
 		return_VALUE(-ENODEV);
 	} else {
 		tz->trips.critical.flags.valid = 1;
@@ -382,8 +382,7 @@
 			tz->trips.passive.flags.valid = 0;
 
 		if (!tz->trips.passive.flags.valid)
-			ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-					  "Invalid passive threshold\n"));
+			ACPI_WARNING((AE_INFO, "Invalid passive threshold"));
 		else
 			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 					  "Found passive threshold [%lu]\n",
@@ -412,9 +411,8 @@
 					  "Found active threshold [%d]:[%lu]\n",
 					  i, tz->trips.active[i].temperature));
 		} else
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Invalid active threshold [%d]\n",
-					  i));
+			ACPI_EXCEPTION((AE_INFO, status,
+					"Invalid active threshold [%d]", i));
 	}
 
 	return_VALUE(0);
@@ -469,7 +467,7 @@
 		return_VALUE(-EINVAL);
 
 	if (tz->temperature >= tz->trips.critical.temperature) {
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Critical trip point\n"));
+		ACPI_WARNING((AE_INFO, "Critical trip point"));
 		tz->trips.critical.flags.enabled = 1;
 	} else if (tz->trips.critical.flags.enabled)
 		tz->trips.critical.flags.enabled = 0;
@@ -500,7 +498,7 @@
 		return_VALUE(-EINVAL);
 
 	if (tz->temperature >= tz->trips.hot.temperature) {
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Hot trip point\n"));
+		ACPI_WARNING((AE_INFO, "Hot trip point"));
 		tz->trips.hot.flags.enabled = 1;
 	} else if (tz->trips.hot.flags.enabled)
 		tz->trips.hot.flags.enabled = 0;
@@ -640,10 +638,10 @@
 						       handles[j],
 						       ACPI_STATE_D0);
 				if (result) {
-					ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-							  "Unable to turn cooling device [%p] 'on'\n",
-							  active->devices.
-							  handles[j]));
+					ACPI_WARNING((AE_INFO,
+						      "Unable to turn cooling device [%p] 'on'",
+						      active->devices.
+						      handles[j]));
 					continue;
 				}
 				active->flags.enabled = 1;
@@ -665,9 +663,9 @@
 			result = acpi_bus_set_power(active->devices.handles[j],
 						    ACPI_STATE_D3);
 			if (result) {
-				ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-						  "Unable to turn cooling device [%p] 'off'\n",
-						  active->devices.handles[j]));
+				ACPI_WARNING((AE_INFO,
+					      "Unable to turn cooling device [%p] 'off'",
+					      active->devices.handles[j]));
 				continue;
 			}
 			active->flags.enabled = 0;
@@ -699,7 +697,7 @@
 	ACPI_FUNCTION_TRACE("acpi_thermal_check");
 
 	if (!tz) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid (NULL) context.\n"));
+		ACPI_ERROR((AE_INFO, "Invalid (NULL) context"));
 		return_VOID;
 	}
 
@@ -946,13 +944,11 @@
 		return_VALUE(-ENOMEM);
 
 	if (!tz || (count > ACPI_THERMAL_MAX_LIMIT_STR_LEN - 1)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument\n"));
 		count = -EINVAL;
 		goto end;
 	}
 
 	if (copy_from_user(limit_string, buffer, count)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data\n"));
 		count = -EFAULT;
 		goto end;
 	}
@@ -965,7 +961,6 @@
 		     &active[5], &active[6], &active[7], &active[8],
 		     &active[9]);
 	if (!(num >= 5 && num < (ACPI_THERMAL_MAX_ACTIVE + 3))) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n"));
 		count = -EINVAL;
 		goto end;
 	}
@@ -1125,9 +1120,7 @@
 	entry = create_proc_entry(ACPI_THERMAL_FILE_STATE,
 				  S_IRUGO, acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create '%s' fs entry\n",
-				  ACPI_THERMAL_FILE_STATE));
+		return_VALUE(-ENODEV);
 	else {
 		entry->proc_fops = &acpi_thermal_state_fops;
 		entry->data = acpi_driver_data(device);
@@ -1138,9 +1131,7 @@
 	entry = create_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
 				  S_IRUGO, acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create '%s' fs entry\n",
-				  ACPI_THERMAL_FILE_TEMPERATURE));
+		return_VALUE(-ENODEV);
 	else {
 		entry->proc_fops = &acpi_thermal_temp_fops;
 		entry->data = acpi_driver_data(device);
@@ -1152,9 +1143,7 @@
 				  S_IFREG | S_IRUGO | S_IWUSR,
 				  acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create '%s' fs entry\n",
-				  ACPI_THERMAL_FILE_TRIP_POINTS));
+		return_VALUE(-ENODEV);
 	else {
 		entry->proc_fops = &acpi_thermal_trip_fops;
 		entry->data = acpi_driver_data(device);
@@ -1166,9 +1155,7 @@
 				  S_IFREG | S_IRUGO | S_IWUSR,
 				  acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create '%s' fs entry\n",
-				  ACPI_THERMAL_FILE_COOLING_MODE));
+		return_VALUE(-ENODEV);
 	else {
 		entry->proc_fops = &acpi_thermal_cooling_fops;
 		entry->data = acpi_driver_data(device);
@@ -1180,9 +1167,7 @@
 				  S_IFREG | S_IRUGO | S_IWUSR,
 				  acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create '%s' fs entry\n",
-				  ACPI_THERMAL_FILE_POLLING_FREQ));
+		return_VALUE(-ENODEV);
 	else {
 		entry->proc_fops = &acpi_thermal_polling_fops;
 		entry->data = acpi_driver_data(device);
@@ -1352,8 +1337,6 @@
 					     ACPI_DEVICE_NOTIFY,
 					     acpi_thermal_notify, tz);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error installing notify handler\n"));
 		result = -ENODEV;
 		goto end;
 	}
@@ -1395,9 +1378,6 @@
 	status = acpi_remove_notify_handler(tz->handle,
 					    ACPI_DEVICE_NOTIFY,
 					    acpi_thermal_notify);
-	if (ACPI_FAILURE(status))
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error removing notify handler\n"));
 
 	/* Terminate policy */
 	if (tz->trips.passive.flags.valid && tz->trips.passive.flags.enabled) {
diff -urN oldtree/drivers/acpi/utilities/utalloc.c newtree/drivers/acpi/utilities/utalloc.c
--- oldtree/drivers/acpi/utilities/utalloc.c	2006-02-19 11:41:00.890207768 +0000
+++ newtree/drivers/acpi/utilities/utalloc.c	2006-02-21 15:58:10.058617416 +0000
@@ -308,6 +308,7 @@
 
 	allocation = acpi_os_allocate(size);
 	if (!allocation) {
+
 		/* Report allocation error */
 
 		ACPI_ERROR((module, line,
@@ -351,6 +352,7 @@
 
 	allocation = acpi_os_allocate(size);
 	if (!allocation) {
+
 		/* Report allocation error */
 
 		ACPI_ERROR((module, line,
@@ -477,6 +479,7 @@
 	    acpi_ut_callocate(size + sizeof(struct acpi_debug_mem_header),
 			      component, module, line);
 	if (!allocation) {
+
 		/* Report allocation error */
 
 		ACPI_ERROR((module, line,
@@ -681,6 +684,7 @@
 
 	mem_list = acpi_gbl_global_list;
 	if (NULL == mem_list->list_head) {
+
 		/* No allocations! */
 
 		ACPI_ERROR((module, line,
@@ -807,6 +811,7 @@
 		if ((element->component & component) &&
 		    ((module == NULL)
 		     || (0 == ACPI_STRCMP(module, element->module)))) {
+
 			/* Ignore allocated objects that are in a cache */
 
 			descriptor =
diff -urN oldtree/drivers/acpi/utilities/utcache.c newtree/drivers/acpi/utilities/utcache.c
--- oldtree/drivers/acpi/utilities/utcache.c	2006-02-19 11:41:00.891207616 +0000
+++ newtree/drivers/acpi/utilities/utcache.c	2006-02-21 15:58:10.059617264 +0000
@@ -118,6 +118,7 @@
 	/* Walk the list of objects in this cache */
 
 	while (cache->list_head) {
+
 		/* Delete and unlink one cached state object */
 
 		next = *(ACPI_CAST_INDIRECT_PTR(char,
@@ -259,6 +260,7 @@
 	/* Check the cache first */
 
 	if (cache->list_head) {
+
 		/* There is an object available, use it */
 
 		object = cache->list_head;
diff -urN oldtree/drivers/acpi/utilities/utcopy.c newtree/drivers/acpi/utilities/utcopy.c
--- oldtree/drivers/acpi/utilities/utcopy.c	2006-02-19 11:41:00.891207616 +0000
+++ newtree/drivers/acpi/utilities/utcopy.c	2006-02-21 15:58:10.060617112 +0000
@@ -882,6 +882,7 @@
 					   acpi_ut_copy_ielement_to_ielement,
 					   walk_state);
 	if (ACPI_FAILURE(status)) {
+
 		/* On failure, delete the destination package object */
 
 		acpi_ut_remove_reference(dest_obj);
diff -urN oldtree/drivers/acpi/utilities/utdebug.c newtree/drivers/acpi/utilities/utdebug.c
--- oldtree/drivers/acpi/utilities/utdebug.c	2006-02-19 11:41:00.892207464 +0000
+++ newtree/drivers/acpi/utilities/utdebug.c	2006-02-21 15:58:10.061616960 +0000
@@ -123,12 +123,14 @@
 	/* All Function names are longer than 4 chars, check is safe */
 
 	if (*(ACPI_CAST_PTR(u32, function_name)) == ACPI_PREFIX_MIXED) {
+
 		/* This is the case where the original source has not been modified */
 
 		return (function_name + 4);
 	}
 
 	if (*(ACPI_CAST_PTR(u32, function_name)) == ACPI_PREFIX_LOWER) {
+
 		/* This is the case where the source has been 'linuxized' */
 
 		return (function_name + 5);
@@ -545,6 +547,7 @@
 	/* Nasty little dump buffer routine! */
 
 	while (i < count) {
+
 		/* Print current offset */
 
 		acpi_os_printf("%6.4X: ", (u32) i);
@@ -553,6 +556,7 @@
 
 		for (j = 0; j < 16;) {
 			if (i + j >= count) {
+
 				/* Dump fill spaces */
 
 				acpi_os_printf("%*s", ((display * 2) + 1), " ");
diff -urN oldtree/drivers/acpi/utilities/utdelete.c newtree/drivers/acpi/utilities/utdelete.c
--- oldtree/drivers/acpi/utilities/utdelete.c	2006-02-19 11:41:00.893207312 +0000
+++ newtree/drivers/acpi/utilities/utdelete.c	2006-02-21 15:58:10.061616960 +0000
@@ -96,6 +96,7 @@
 		/* Free the actual string buffer */
 
 		if (!(object->common.flags & AOPOBJ_STATIC_POINTER)) {
+
 			/* But only if it is NOT a pointer into an ACPI table */
 
 			obj_pointer = object->string.pointer;
@@ -111,6 +112,7 @@
 		/* Free the actual buffer */
 
 		if (!(object->common.flags & AOPOBJ_STATIC_POINTER)) {
+
 			/* But only if it is NOT a pointer into an ACPI table */
 
 			obj_pointer = object->buffer.pointer;
@@ -415,6 +417,7 @@
 	ACPI_FUNCTION_TRACE_PTR("ut_update_object_reference", object);
 
 	while (object) {
+
 		/* Make sure that this isn't a namespace handle */
 
 		if (ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_NAMED) {
diff -urN oldtree/drivers/acpi/utilities/uteval.c newtree/drivers/acpi/utilities/uteval.c
--- oldtree/drivers/acpi/utilities/uteval.c	2006-02-19 11:41:00.893207312 +0000
+++ newtree/drivers/acpi/utilities/uteval.c	2006-02-21 15:58:10.062616808 +0000
@@ -98,6 +98,7 @@
 				 ACPI_CAST_PTR(char,
 					       acpi_gbl_valid_osi_strings[i])))
 		{
+
 			/* This string is supported */
 
 			return_desc->integer.value = 0xFFFFFFFF;
@@ -343,6 +344,7 @@
 	}
 
 	if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) {
+
 		/* Convert the Numeric HID to string */
 
 		acpi_ex_eisa_id_to_string((u32) obj_desc->integer.value,
@@ -479,6 +481,7 @@
 	/* The _CID object can be either a single CID or a package (list) of CIDs */
 
 	if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_PACKAGE) {
+
 		/* Translate each package element */
 
 		for (i = 0; i < count; i++) {
@@ -543,6 +546,7 @@
 	}
 
 	if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) {
+
 		/* Convert the Numeric UID to string */
 
 		acpi_ex_unsigned_integer_to_string(obj_desc->integer.value,
diff -urN oldtree/drivers/acpi/utilities/utglobal.c newtree/drivers/acpi/utilities/utglobal.c
--- oldtree/drivers/acpi/utilities/utglobal.c	2006-02-19 11:41:00.894207160 +0000
+++ newtree/drivers/acpi/utilities/utglobal.c	2006-02-21 15:58:10.063616656 +0000
@@ -119,6 +119,7 @@
 	}
 
 	if (!exception) {
+
 		/* Exception code was not recognized */
 
 		ACPI_ERROR((AE_INFO,
@@ -747,6 +748,7 @@
 {
 
 	if (type > ACPI_TYPE_LOCAL_MAX) {
+
 		/* Note: Assumes all TYPEs are contiguous (external/local) */
 
 		return (FALSE);
diff -urN oldtree/drivers/acpi/utilities/utmisc.c newtree/drivers/acpi/utilities/utmisc.c
--- oldtree/drivers/acpi/utilities/utmisc.c	2006-02-19 11:41:00.896206856 +0000
+++ newtree/drivers/acpi/utilities/utmisc.c	2006-02-21 15:58:10.076614680 +0000
@@ -41,6 +41,8 @@
  * POSSIBILITY OF SUCH DAMAGES.
  */
 
+#include <linux/module.h>
+
 #include <acpi/acpi.h>
 #include <acpi/acnamesp.h>
 
@@ -97,6 +99,7 @@
 
 		for (k = acpi_gbl_next_owner_id_offset; k < 32; k++) {
 			if (acpi_gbl_owner_id_mask[j] == ACPI_UINT32_MAX) {
+
 				/* There are no free IDs in this mask */
 
 				break;
@@ -273,6 +276,7 @@
 
 	acpi_os_printf("\"");
 	for (i = 0; string[i] && (i < max_length); i++) {
+
 		/* Escape sequences */
 
 		switch (string[i]) {
@@ -601,11 +605,13 @@
 
 	while (*string) {
 		if (ACPI_IS_DIGIT(*string)) {
+
 			/* Convert ASCII 0-9 to Decimal value */
 
 			this_digit = ((u8) * string) - '0';
 		} else {
 			if (base == 10) {
+
 				/* Digit is out of range */
 
 				goto error_exit;
@@ -613,6 +619,7 @@
 
 			this_digit = (u8) ACPI_TOUPPER(*string);
 			if (ACPI_IS_XDIGIT((char)this_digit)) {
+
 				/* Convert ASCII Hex char to value */
 
 				this_digit = this_digit - 'A' + 10;
@@ -727,6 +734,7 @@
 	}
 
 	while (state) {
+
 		/* Get one element of the package */
 
 		this_index = state->pkg.index;
@@ -814,31 +822,6 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ut_generate_checksum
- *
- * PARAMETERS:  Buffer          - Buffer to be scanned
- *              Length          - number of bytes to examine
- *
- * RETURN:      The generated checksum
- *
- * DESCRIPTION: Generate a checksum on a raw buffer
- *
- ******************************************************************************/
-
-u8 acpi_ut_generate_checksum(u8 * buffer, u32 length)
-{
-	u32 i;
-	signed char sum = 0;
-
-	for (i = 0; i < length; i++) {
-		sum = (signed char)(sum + buffer[i]);
-	}
-
-	return ((u8) (0 - sum));
-}
-
-/*******************************************************************************
- *
  * FUNCTION:    acpi_ut_error, acpi_ut_warning, acpi_ut_info
  *
  * PARAMETERS:  module_name         - Caller's module name (for error output)
@@ -862,6 +845,7 @@
 	acpi_os_vprintf(format, args);
 	acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
 }
+EXPORT_SYMBOL(acpi_ut_error);
 
 void ACPI_INTERNAL_VAR_XFACE
 acpi_ut_exception(char *module_name,
@@ -876,6 +860,7 @@
 	acpi_os_vprintf(format, args);
 	acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
 }
+EXPORT_SYMBOL(acpi_ut_exception);
 
 void ACPI_INTERNAL_VAR_XFACE
 acpi_ut_warning(char *module_name, u32 line_number, char *format, ...)
@@ -888,7 +873,7 @@
 	acpi_os_vprintf(format, args);
 	acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
 }
-
+EXPORT_SYMBOL(acpi_ut_warning);
 void ACPI_INTERNAL_VAR_XFACE
 acpi_ut_info(char *module_name, u32 line_number, char *format, ...)
 {
diff -urN oldtree/drivers/acpi/utilities/utobject.c newtree/drivers/acpi/utilities/utobject.c
--- oldtree/drivers/acpi/utilities/utobject.c	2006-02-19 11:41:00.898206552 +0000
+++ newtree/drivers/acpi/utilities/utobject.c	2006-02-21 15:58:10.173599936 +0000
@@ -173,6 +173,7 @@
 	/* Create an actual buffer only if size > 0 */
 
 	if (buffer_size > 0) {
+
 		/* Allocate the actual buffer */
 
 		buffer = ACPI_MEM_CALLOCATE(buffer_size);
@@ -397,6 +398,7 @@
 	length = sizeof(union acpi_object);
 
 	if (ACPI_GET_DESCRIPTOR_TYPE(internal_object) == ACPI_DESC_TYPE_NAMED) {
+
 		/* Object is a named object (reference), just return the length */
 
 		*obj_length = ACPI_ROUND_UP_TO_NATIVE_WORD(length);
diff -urN oldtree/drivers/acpi/utilities/utresrc.c newtree/drivers/acpi/utilities/utresrc.c
--- oldtree/drivers/acpi/utilities/utresrc.c	2006-02-19 11:41:00.899206400 +0000
+++ newtree/drivers/acpi/utilities/utresrc.c	2006-02-21 15:58:10.298580936 +0000
@@ -273,6 +273,7 @@
 	 * Examine the large/small bit in the resource header
 	 */
 	if (resource_type & ACPI_RESOURCE_NAME_LARGE) {
+
 		/* Verify the large resource type (name) against the max */
 
 		if (resource_type > ACPI_RESOURCE_NAME_LARGE_MAX) {
@@ -376,6 +377,7 @@
 	 * Examine the large/small bit in the resource header
 	 */
 	if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
+
 		/* Large Resource Type -- bits 6:0 contain the name */
 
 		return (ACPI_GET8(aml));
@@ -411,6 +413,7 @@
 	 * Examine the large/small bit in the resource header
 	 */
 	if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
+
 		/* Large Resource type -- bytes 1-2 contain the 16-bit length */
 
 		ACPI_MOVE_16_TO_16(&resource_length, ACPI_ADD_PTR(u8, aml, 1));
@@ -515,6 +518,7 @@
 	/* Walk the resource template, one descriptor per iteration */
 
 	while (aml < end_aml) {
+
 		/* Validate the Resource Type and Resource Length */
 
 		status = acpi_ut_validate_resource(aml, NULL);
diff -urN oldtree/drivers/acpi/utilities/utstate.c newtree/drivers/acpi/utilities/utstate.c
--- oldtree/drivers/acpi/utilities/utstate.c	2006-02-19 11:41:00.899206400 +0000
+++ newtree/drivers/acpi/utilities/utstate.c	2006-02-21 15:58:10.311578960 +0000
@@ -129,6 +129,7 @@
 
 	state = *list_head;
 	if (state) {
+
 		/* Update the list head */
 
 		*list_head = state->common.next;
@@ -158,6 +159,7 @@
 
 	state = acpi_os_acquire_object(acpi_gbl_state_cache);
 	if (state) {
+
 		/* Initialize */
 		memset(state, 0, sizeof(union acpi_generic_state));
 		state->common.data_type = ACPI_DESC_TYPE_STATE;
diff -urN oldtree/drivers/acpi/utils.c newtree/drivers/acpi/utils.c
--- oldtree/drivers/acpi/utils.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/acpi/utils.c	2006-02-21 15:58:10.417562848 +0000
@@ -62,26 +62,25 @@
 
 	if (!package || (package->type != ACPI_TYPE_PACKAGE)
 	    || (package->package.count < 1)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-				  "Invalid 'package' argument\n"));
+		ACPI_WARNING((AE_INFO, "Invalid package argument"));
 		return_ACPI_STATUS(AE_BAD_PARAMETER);
 	}
 
 	if (!format || !format->pointer || (format->length < 1)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid 'format' argument\n"));
+		ACPI_WARNING((AE_INFO, "Invalid format argument"));
 		return_ACPI_STATUS(AE_BAD_PARAMETER);
 	}
 
 	if (!buffer) {
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid 'buffer' argument\n"));
+		ACPI_WARNING((AE_INFO, "Invalid buffer argument"));
 		return_ACPI_STATUS(AE_BAD_PARAMETER);
 	}
 
 	format_count = (format->length / sizeof(char)) - 1;
 	if (format_count > package->package.count) {
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-				  "Format specifies more objects [%d] than exist in package [%d].",
-				  format_count, package->package.count));
+		ACPI_WARNING((AE_INFO, "Format specifies more objects [%d]"
+			      " than exist in package [%d].",
+			      format_count, package->package.count));
 		return_ACPI_STATUS(AE_BAD_DATA);
 	}
 
@@ -113,9 +112,10 @@
 				tail_offset += sizeof(char *);
 				break;
 			default:
-				ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-						  "Invalid package element [%d]: got number, expecing [%c].\n",
-						  i, format_string[i]));
+				ACPI_WARNING((AE_INFO, "Invalid package element"
+					      " [%d]: got number, expecing"
+					      " [%c]",
+					      i, format_string[i]));
 				return_ACPI_STATUS(AE_BAD_DATA);
 				break;
 			}
@@ -138,9 +138,10 @@
 				tail_offset += sizeof(u8 *);
 				break;
 			default:
-				ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-						  "Invalid package element [%d] got string/buffer, expecing [%c].\n",
-						  i, format_string[i]));
+				ACPI_WARNING((AE_INFO, "Invalid package element"
+					      " [%d] got string/buffer,"
+					      " expecing [%c]",
+					      i, format_string[i]));
 				return_ACPI_STATUS(AE_BAD_DATA);
 				break;
 			}
@@ -323,7 +324,7 @@
 
 	*data = kmalloc(element->string.length + 1, GFP_KERNEL);
 	if (!data) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Memory allocation error\n"));
+		ACPI_ERROR((AE_INFO, "Memory allocation"));
 		return_VALUE(-ENOMEM);
 	}
 	memset(*data, 0, element->string.length + 1);
@@ -365,25 +366,22 @@
 	package = (union acpi_object *)buffer.pointer;
 
 	if ((buffer.length == 0) || !package) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "No return object (len %X ptr %p)\n",
-				  (unsigned)buffer.length, package));
+		ACPI_ERROR((AE_INFO, "No return object (len %X ptr %p)",
+			    (unsigned)buffer.length, package));
 		status = AE_BAD_DATA;
 		acpi_util_eval_error(handle, pathname, status);
 		goto end;
 	}
 	if (package->type != ACPI_TYPE_PACKAGE) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Expecting a [Package], found type %X\n",
-				  package->type));
+		ACPI_ERROR((AE_INFO, "Expecting a [Package], found type %X",
+			    package->type));
 		status = AE_BAD_DATA;
 		acpi_util_eval_error(handle, pathname, status);
 		goto end;
 	}
 	if (!package->package.count) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "[Package] has zero elements (%p)\n",
-				  package));
+		ACPI_ERROR((AE_INFO, "[Package] has zero elements (%p)",
+			    package));
 		status = AE_BAD_DATA;
 		acpi_util_eval_error(handle, pathname, status);
 		goto end;
@@ -402,9 +400,9 @@
 
 		if (element->type != ACPI_TYPE_ANY) {
 			status = AE_BAD_DATA;
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Expecting a [Reference] package element, found type %X\n",
-					  element->type));
+			ACPI_ERROR((AE_INFO,
+				    "Expecting a [Reference] package element, found type %X",
+				    element->type));
 			acpi_util_eval_error(handle, pathname, status);
 			break;
 		}
diff -urN oldtree/drivers/acpi/video.c newtree/drivers/acpi/video.c
--- oldtree/drivers/acpi/video.c	2006-02-19 11:41:00.901206096 +0000
+++ newtree/drivers/acpi/video.c	2006-02-21 15:58:10.419562544 +0000
@@ -324,7 +324,7 @@
 		return_VALUE(status);
 	obj = (union acpi_object *)buffer.pointer;
 	if (!obj && (obj->type != ACPI_TYPE_PACKAGE)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _BCL data\n"));
+		ACPI_ERROR((AE_INFO, "Invalid _BCL data"));
 		status = -EFAULT;
 		goto err;
 	}
@@ -399,7 +399,7 @@
 	if (obj && obj->type == ACPI_TYPE_BUFFER)
 		*edid = obj;
 	else {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _DDC data\n"));
+		ACPI_ERROR((AE_INFO, "Invalid _DDC data"));
 		status = -EFAULT;
 		kfree(obj);
 	}
@@ -560,8 +560,7 @@
 				o = (union acpi_object *)&obj->package.
 				    elements[i];
 				if (o->type != ACPI_TYPE_INTEGER) {
-					ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-							  "Invalid data\n"));
+					ACPI_ERROR((AE_INFO, "Invalid data"));
 					continue;
 				}
 				br->levels[count] = (u32) o->integer.value;
@@ -904,8 +903,7 @@
 	/* 'info' [R] */
 	entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create 'info' fs entry\n"));
+		return_VALUE(-ENODEV);
 	else {
 		entry->proc_fops = &acpi_video_device_info_fops;
 		entry->data = acpi_driver_data(device);
@@ -917,8 +915,7 @@
 	    create_proc_entry("state", S_IFREG | S_IRUGO | S_IWUSR,
 			      acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create 'state' fs entry\n"));
+		return_VALUE(-ENODEV);
 	else {
 		acpi_video_device_state_fops.write = acpi_video_device_write_state;
 		entry->proc_fops = &acpi_video_device_state_fops;
@@ -931,8 +928,7 @@
 	    create_proc_entry("brightness", S_IFREG | S_IRUGO | S_IWUSR,
 			      acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create 'brightness' fs entry\n"));
+		return_VALUE(-ENODEV);
 	else {
 		acpi_video_device_brightness_fops.write = acpi_video_device_write_brightness;
 		entry->proc_fops = &acpi_video_device_brightness_fops;
@@ -943,8 +939,7 @@
 	/* 'EDID' [R] */
 	entry = create_proc_entry("EDID", S_IRUGO, acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create 'brightness' fs entry\n"));
+		return_VALUE(-ENODEV);
 	else {
 		entry->proc_fops = &acpi_video_device_EDID_fops;
 		entry->data = acpi_driver_data(device);
@@ -1200,8 +1195,7 @@
 	/* 'info' [R] */
 	entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create 'info' fs entry\n"));
+		return_VALUE(-ENODEV);
 	else {
 		entry->proc_fops = &acpi_video_bus_info_fops;
 		entry->data = acpi_driver_data(device);
@@ -1211,8 +1205,7 @@
 	/* 'ROM' [R] */
 	entry = create_proc_entry("ROM", S_IRUGO, acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create 'ROM' fs entry\n"));
+		return_VALUE(-ENODEV);
 	else {
 		entry->proc_fops = &acpi_video_bus_ROM_fops;
 		entry->data = acpi_driver_data(device);
@@ -1223,8 +1216,7 @@
 	entry =
 	    create_proc_entry("POST_info", S_IRUGO, acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create 'POST_info' fs entry\n"));
+		return_VALUE(-ENODEV);
 	else {
 		entry->proc_fops = &acpi_video_bus_POST_info_fops;
 		entry->data = acpi_driver_data(device);
@@ -1236,8 +1228,7 @@
 	    create_proc_entry("POST", S_IFREG | S_IRUGO | S_IRUSR,
 			      acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create 'POST' fs entry\n"));
+		return_VALUE(-ENODEV);
 	else {
 		acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST;
 		entry->proc_fops = &acpi_video_bus_POST_fops;
@@ -1250,8 +1241,7 @@
 	    create_proc_entry("DOS", S_IFREG | S_IRUGO | S_IRUSR,
 			      acpi_device_dir(device));
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Unable to create 'DOS' fs entry\n"));
+		return_VALUE(-ENODEV);
 	else {
 		acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS;
 		entry->proc_fops = &acpi_video_bus_DOS_fops;
@@ -1344,8 +1334,6 @@
 						     acpi_video_device_notify,
 						     data);
 		if (ACPI_FAILURE(status)) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Error installing notify handler\n"));
 			result = -ENODEV;
 			goto end;
 		}
@@ -1444,13 +1432,13 @@
 
 	status = acpi_evaluate_object(video->handle, "_DOD", NULL, &buffer);
 	if (!ACPI_SUCCESS(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _DOD\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _DOD"));
 		return_VALUE(status);
 	}
 
 	dod = (union acpi_object *)buffer.pointer;
 	if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _DOD data\n"));
+		ACPI_EXCEPTION((AE_INFO, status, "Invalid _DOD data"));
 		status = -EFAULT;
 		goto out;
 	}
@@ -1474,8 +1462,7 @@
 		obj = (union acpi_object *)&dod->package.elements[i];
 
 		if (obj->type != ACPI_TYPE_INTEGER) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Invalid _DOD data\n"));
+			ACPI_ERROR((AE_INFO, "Invalid _DOD data"));
 			active_device_list[i].value.int_val =
 			    ACPI_VIDEO_HEAD_INVALID;
 		}
@@ -1589,8 +1576,7 @@
 
 		status = acpi_video_bus_get_one_device(dev, video);
 		if (ACPI_FAILURE(status)) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "Cant attach device\n"));
+			ACPI_EXCEPTION((AE_INFO, status, "Cant attach device"));
 			continue;
 		}
 
@@ -1618,9 +1604,6 @@
 	status = acpi_remove_notify_handler(device->handle,
 					    ACPI_DEVICE_NOTIFY,
 					    acpi_video_device_notify);
-	if (ACPI_FAILURE(status))
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error removing notify handler\n"));
 
 	return_VALUE(0);
 }
@@ -1783,8 +1766,6 @@
 					     ACPI_DEVICE_NOTIFY,
 					     acpi_video_bus_notify, video);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error installing notify handler\n"));
 		result = -ENODEV;
 		goto end;
 	}
@@ -1821,9 +1802,6 @@
 	status = acpi_remove_notify_handler(video->handle,
 					    ACPI_DEVICE_NOTIFY,
 					    acpi_video_bus_notify);
-	if (ACPI_FAILURE(status))
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "Error removing notify handler\n"));
 
 	acpi_video_bus_put_devices(video);
 	acpi_video_bus_remove_fs(device);
diff -urN oldtree/drivers/atm/firestream.c newtree/drivers/atm/firestream.c
--- oldtree/drivers/atm/firestream.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/atm/firestream.c	2006-02-21 15:58:35.851696272 +0000
@@ -576,7 +576,7 @@
 }
 
 
-static inline u32  read_fs (struct fs_dev *dev, int offset)
+static inline u32 read_fs (struct fs_dev *dev, int offset)
 {
 	return readl (dev->base + offset);
 }
@@ -1497,7 +1497,7 @@
 		ne->skb = skb;
 		ne->fp = fp;
 
-		qe = (struct FS_BPENTRY *) (read_fs (dev, FP_EA(fp->offset)));
+		qe = (struct FS_BPENTRY *)(long)(read_fs (dev, FP_EA(fp->offset)));
 		fs_dprintk (FS_DEBUG_QUEUE, "link at %p\n", qe);
 		if (qe) {
 			qe = bus_to_virt ((long) qe);
diff -urN oldtree/drivers/base/core.c newtree/drivers/base/core.c
--- oldtree/drivers/base/core.c	2006-02-19 11:41:00.933201232 +0000
+++ newtree/drivers/base/core.c	2006-02-21 15:58:12.137301408 +0000
@@ -340,6 +340,7 @@
  */
 void put_device(struct device * dev)
 {
+	might_sleep();
 	if (dev)
 		kobject_put(&dev->kobj);
 }
diff -urN oldtree/drivers/base/firmware_class.c newtree/drivers/base/firmware_class.c
--- oldtree/drivers/base/firmware_class.c	2006-02-19 11:41:00.936200776 +0000
+++ newtree/drivers/base/firmware_class.c	2006-02-21 15:58:13.317122048 +0000
@@ -211,18 +211,20 @@
 fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
 {
 	u8 *new_data;
+	int new_size = fw_priv->alloc_size;
 
 	if (min_size <= fw_priv->alloc_size)
 		return 0;
 
-	new_data = vmalloc(fw_priv->alloc_size + PAGE_SIZE);
+	new_size = ALIGN(min_size, PAGE_SIZE);
+	new_data = vmalloc(new_size);
 	if (!new_data) {
 		printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__);
 		/* Make sure that we don't keep incomplete data */
 		fw_load_abort(fw_priv);
 		return -ENOMEM;
 	}
-	fw_priv->alloc_size += PAGE_SIZE;
+	fw_priv->alloc_size = new_size;
 	if (fw_priv->fw->data) {
 		memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size);
 		vfree(fw_priv->fw->data);
diff -urN oldtree/drivers/base/map.c newtree/drivers/base/map.c
--- oldtree/drivers/base/map.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/base/map.c	2006-02-21 15:58:12.579234224 +0000
@@ -11,6 +11,7 @@
 
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
 #include <linux/kdev_t.h>
 #include <linux/kobject.h>
 #include <linux/kobj_map.h>
@@ -25,7 +26,7 @@
 		int (*lock)(dev_t, void *);
 		void *data;
 	} *probes[255];
-	struct semaphore *sem;
+	struct mutex *lock;
 };
 
 int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
@@ -53,7 +54,7 @@
 		p->range = range;
 		p->data = data;
 	}
-	down(domain->sem);
+	mutex_lock(domain->lock);
 	for (i = 0, p -= n; i < n; i++, p++, index++) {
 		struct probe **s = &domain->probes[index % 255];
 		while (*s && (*s)->range < range)
@@ -61,7 +62,7 @@
 		p->next = *s;
 		*s = p;
 	}
-	up(domain->sem);
+	mutex_unlock(domain->lock);
 	return 0;
 }
 
@@ -75,7 +76,7 @@
 	if (n > 255)
 		n = 255;
 
-	down(domain->sem);
+	mutex_lock(domain->lock);
 	for (i = 0; i < n; i++, index++) {
 		struct probe **s;
 		for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) {
@@ -88,7 +89,7 @@
 			}
 		}
 	}
-	up(domain->sem);
+	mutex_unlock(domain->lock);
 	kfree(found);
 }
 
@@ -99,7 +100,7 @@
 	unsigned long best = ~0UL;
 
 retry:
-	down(domain->sem);
+	mutex_lock(domain->lock);
 	for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) {
 		struct kobject *(*probe)(dev_t, int *, void *);
 		struct module *owner;
@@ -120,7 +121,7 @@
 			module_put(owner);
 			continue;
 		}
-		up(domain->sem);
+		mutex_unlock(domain->lock);
 		kobj = probe(dev, index, data);
 		/* Currently ->owner protects _only_ ->probe() itself. */
 		module_put(owner);
@@ -128,11 +129,11 @@
 			return kobj;
 		goto retry;
 	}
-	up(domain->sem);
+	mutex_unlock(domain->lock);
 	return NULL;
 }
 
-struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem)
+struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct mutex *lock)
 {
 	struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);
 	struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL);
@@ -149,6 +150,6 @@
 	base->get = base_probe;
 	for (i = 0; i < 255; i++)
 		p->probes[i] = base;
-	p->sem = sem;
+	p->lock = lock;
 	return p;
 }
diff -urN oldtree/drivers/base/platform.c newtree/drivers/base/platform.c
--- oldtree/drivers/base/platform.c	2006-02-19 11:41:00.937200624 +0000
+++ newtree/drivers/base/platform.c	2006-02-21 15:58:12.386263560 +0000
@@ -61,7 +61,7 @@
 {
 	struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num);
 
-	return r ? r->start : 0;
+	return r ? r->start : -ENXIO;
 }
 EXPORT_SYMBOL_GPL(platform_get_irq);
 
@@ -98,7 +98,7 @@
 {
 	struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
 
-	return r ? r->start : 0;
+	return r ? r->start : -ENXIO;
 }
 EXPORT_SYMBOL_GPL(platform_get_irq_byname);
 
diff -urN oldtree/drivers/base/power/resume.c newtree/drivers/base/power/resume.c
--- oldtree/drivers/base/power/resume.c	2006-02-19 11:41:00.937200624 +0000
+++ newtree/drivers/base/power/resume.c	2006-02-21 15:58:23.241613296 +0000
@@ -24,23 +24,25 @@
 	int error = 0;
 
 	down(&dev->sem);
-	if (dev->power.pm_parent
-			&& dev->power.pm_parent->power.power_state.event) {
-		dev_err(dev, "PM: resume from %d, parent %s still %d\n",
-			dev->power.power_state.event,
+	if (dev->power.pm_parent &&
+	    dev->power.pm_parent->power.power_state.state) {
+		dev_err(dev, "PM: resume from state %u, parent %s still in "
+					"state %u\n",
+			dev->power.power_state.state,
 			dev->power.pm_parent->bus_id,
-			dev->power.pm_parent->power.power_state.event);
+			dev->power.pm_parent->power.power_state.state);
 	}
 	if (dev->bus && dev->bus->resume) {
 		dev_dbg(dev,"resuming\n");
 		error = dev->bus->resume(dev);
 	}
+	dev->power.prev_state = dev->power.power_state;
+	dev->power.power_state.state = 0;
+	dev->power.power_state.event = PM_EVENT_ON;
 	up(&dev->sem);
 	return error;
 }
 
-
-
 void dpm_resume(void)
 {
 	down(&dpm_list_sem);
diff -urN oldtree/drivers/base/power/runtime.c newtree/drivers/base/power/runtime.c
--- oldtree/drivers/base/power/runtime.c	2006-02-19 11:41:00.938200472 +0000
+++ newtree/drivers/base/power/runtime.c	2006-02-21 15:58:23.242613144 +0000
@@ -45,19 +45,20 @@
  *	@state:	State to enter.
  */
 
-int dpm_runtime_suspend(struct device * dev, pm_message_t state)
+int dpm_runtime_suspend(struct device * dev, pm_message_t msg)
 {
 	int error = 0;
 
 	down(&dpm_sem);
-	if (dev->power.power_state.event == state.event)
+	if (dev->power.power_state.event == msg.event &&
+	    dev->power.power_state.state == msg.state)
 		goto Done;
 
-	if (dev->power.power_state.event)
+	if (dev->power.power_state.event != PM_EVENT_ON)
 		runtime_resume(dev);
 
-	if (!(error = suspend_device(dev, state)))
-		dev->power.power_state = state;
+	if (!(error = suspend_device(dev, msg)))
+		dev->power.power_state = msg;
  Done:
 	up(&dpm_sem);
 	return error;
diff -urN oldtree/drivers/base/power/suspend.c newtree/drivers/base/power/suspend.c
--- oldtree/drivers/base/power/suspend.c	2006-02-19 11:41:00.938200472 +0000
+++ newtree/drivers/base/power/suspend.c	2006-02-21 15:58:35.908687608 +0000
@@ -33,36 +33,37 @@
  *	@dev:	Device.
  *	@state:	Power state device is entering.
  */
-
-int suspend_device(struct device * dev, pm_message_t state)
+int suspend_device(struct device *dev, pm_message_t msg)
 {
+	struct device * pm_parent;
 	int error = 0;
 
+	dev_dbg(dev, "Suspend [Event %d: %u --> %u]\n",
+		msg.event, dev->power.power_state.state, msg.state);
+
 	down(&dev->sem);
-	if (dev->power.power_state.event) {
-		dev_dbg(dev, "PM: suspend %d-->%d\n",
-			dev->power.power_state.event, state.event);
-	}
+	pm_parent = dev->power.pm_parent;
 	if (dev->power.pm_parent
-			&& dev->power.pm_parent->power.power_state.event) {
-		dev_err(dev,
-			"PM: suspend %d->%d, parent %s already %d\n",
-			dev->power.power_state.event, state.event,
-			dev->power.pm_parent->bus_id,
-			dev->power.pm_parent->power.power_state.event);
+	    && dev->power.pm_parent->power.power_state.state) {
+		dev_err(dev, "Suspend [Event %d: %u --> %u], parent %s "
+				"already in [State %u]\n",
+			msg.event, dev->power.power_state.state, msg.state,
+			pm_parent->bus_id, pm_parent->power.power_state.state);
 	}
 
-	dev->power.prev_state = dev->power.power_state;
-
-	if (dev->bus && dev->bus->suspend && !dev->power.power_state.event) {
+	if (dev->bus && dev->bus->suspend) {
 		dev_dbg(dev, "suspending\n");
-		error = dev->bus->suspend(dev, state);
+		error = dev->bus->suspend(dev, msg);
+	}
+
+	if (!error) {
+		dev->power.prev_state = dev->power.power_state;
+		dev->power.power_state = msg;
 	}
 	up(&dev->sem);
 	return error;
 }
 
-
 /**
  *	device_suspend - Save state and stop all devices in system.
  *	@state:		Power state to put each device in.
@@ -91,6 +92,8 @@
 		get_device(dev);
 		up(&dpm_list_sem);
 
+		printk("Suspending device %s\n", kobject_name(&dev->kobj));
+
 		error = suspend_device(dev, state);
 
 		down(&dpm_list_sem);
diff -urN oldtree/drivers/base/power/sysfs.c newtree/drivers/base/power/sysfs.c
--- oldtree/drivers/base/power/sysfs.c	2006-02-19 11:41:00.939200320 +0000
+++ newtree/drivers/base/power/sysfs.c	2006-02-21 15:58:23.229615120 +0000
@@ -7,50 +7,62 @@
 #include "power.h"
 
 
+#define PM_STATE_OFF	INT_MAX
+
 /**
  *	state - Control current power state of device
  *
  *	show() returns the current power state of the device. '0' indicates
  *	the device is on. Other values (1-3) indicate the device is in a low
  *	power state.
- *
- *	store() sets the current power state, which is an integer value
- *	between 0-3. If the device is on ('0'), and the value written is
- *	greater than 0, then the device is placed directly into the low-power
- *	state (via its driver's ->suspend() method).
- *	If the device is currently in a low-power state, and the value is 0,
- *	the device is powered back on (via the ->resume() method).
- *	If the device is in a low-power state, and a different low-power state
- *	is requested, the device is first resumed, then suspended into the new
- *	low-power state.
+ *	A value of INT_MAX (0x0fffffff) indicates that the device is off - it is
+ *	suspended, but the actual state is unknown (for devices and buses that only
+ *	support "on" and "off").
+ *
+ *	store() takes an integer value and changes the current power state of the
+ *	device. If this value is 0, the device is resumed - a PM message with event
+ *	type PM_EVENT_ON, and a state of 0 is passed to dpm_runtime_resume().
+ *	Otherwise, the device is suspended. A PM message with event type
+ *	PM_EVENT_SUSPEND is passed to the device, with the state being the value
+ *	written to this file.
+ *
+ *	The meaning of the integer value states are bus and/or device specific, with
+ *	the exception of 0 - that always means "on".
+ *	The core will not do any further interpretation of the values. It is up to
+ *	the bus and/or device drivers to both document and check the values that are
+ *	read and written from this file.
+ *	For buses and devices that only support "on" and "off", any non-zero number
+ *	can be used to indicate "off".
  */
 
 static ssize_t state_show(struct device * dev, struct device_attribute *attr, char * buf)
 {
-	if (dev->power.power_state.event)
-		return sprintf(buf, "2\n");
-	else
-		return sprintf(buf, "0\n");
+	u32 state = 0;
+
+	if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
+		state = dev->power.power_state.state;
+		if (!state)
+			state = PM_STATE_OFF;
+	}
+	return sprintf(buf, "%x\n", dev->power.power_state.state);
 }
 
 static ssize_t state_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t n)
 {
-	pm_message_t state;
-	int error = -EINVAL;
+	pm_message_t msg = {
+		.event = PM_EVENT_SUSPEND,
+	};
+	char * rest;
+	int error = 0;
 
-	state.event = PM_EVENT_SUSPEND;
-	/* Older apps expected to write "3" here - confused with PCI D3 */
-	if ((n == 1) && !strcmp(buf, "3"))
-		error = dpm_runtime_suspend(dev, state);
-
-	if ((n == 1) && !strcmp(buf, "2"))
-		error = dpm_runtime_suspend(dev, state);
+	msg.state = simple_strtoul(buf, &rest, 0);
+	if (*rest)
+		return -EINVAL;
 
-	if ((n == 1) && !strcmp(buf, "0")) {
+	if (msg.state)
+		error = dpm_runtime_suspend(dev, msg);
+	else
 		dpm_runtime_resume(dev);
-		error = 0;
-	}
-
 	return error ? error : n;
 }
 
diff -urN oldtree/drivers/block/Makefile newtree/drivers/block/Makefile
--- oldtree/drivers/block/Makefile	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/block/Makefile	2006-02-21 15:58:29.836610704 +0000
@@ -7,7 +7,6 @@
 
 obj-$(CONFIG_MAC_FLOPPY)	+= swim3.o
 obj-$(CONFIG_BLK_DEV_FD)	+= floppy.o
-obj-$(CONFIG_BLK_DEV_FD98)	+= floppy98.o
 obj-$(CONFIG_AMIGA_FLOPPY)	+= amiflop.o
 obj-$(CONFIG_ATARI_FLOPPY)	+= ataflop.o
 obj-$(CONFIG_BLK_DEV_SWIM_IOP)	+= swim_iop.o
diff -urN oldtree/drivers/block/aoe/aoe.h newtree/drivers/block/aoe/aoe.h
--- oldtree/drivers/block/aoe/aoe.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/block/aoe/aoe.h	2006-02-21 15:58:13.143148496 +0000
@@ -1,5 +1,5 @@
 /* Copyright (c) 2004 Coraid, Inc.  See COPYING for GPL terms. */
-#define VERSION "14"
+#define VERSION "22"
 #define AOE_MAJOR 152
 #define DEVICE_NAME "aoe"
 
@@ -75,8 +75,9 @@
 	DEVFL_TKILL = (1<<1),	/* flag for timer to know when to kill self */
 	DEVFL_EXT = (1<<2),	/* device accepts lba48 commands */
 	DEVFL_CLOSEWAIT = (1<<3), /* device is waiting for all closes to revalidate */
-	DEVFL_WC_UPDATE = (1<<4), /* this device needs to update write cache status */
-	DEVFL_WORKON = (1<<4),
+	DEVFL_GDALLOC = (1<<4),	/* need to alloc gendisk */
+	DEVFL_PAUSE = (1<<5),
+	DEVFL_NEWSIZE = (1<<6),	/* need to update dev size in block layer */
 
 	BUFFL_FAIL = 1,
 };
@@ -152,16 +153,17 @@
 void aoechr_error(char *);
 
 void aoecmd_work(struct aoedev *d);
-void aoecmd_cfg(ushort, unsigned char);
+void aoecmd_cfg(ushort aoemajor, unsigned char aoeminor);
 void aoecmd_ata_rsp(struct sk_buff *);
 void aoecmd_cfg_rsp(struct sk_buff *);
+void aoecmd_sleepwork(void *vp);
 
 int aoedev_init(void);
 void aoedev_exit(void);
 struct aoedev *aoedev_by_aoeaddr(int maj, int min);
+struct aoedev *aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt);
 void aoedev_downdev(struct aoedev *d);
-struct aoedev *aoedev_set(ulong, unsigned char *, struct net_device *, ulong);
-int aoedev_busy(void);
+int aoedev_isbusy(struct aoedev *d);
 
 int aoenet_init(void);
 void aoenet_exit(void);
diff -urN oldtree/drivers/block/aoe/aoeblk.c newtree/drivers/block/aoe/aoeblk.c
--- oldtree/drivers/block/aoe/aoeblk.c	2006-02-19 11:41:00.947199104 +0000
+++ newtree/drivers/block/aoe/aoeblk.c	2006-02-21 15:58:30.856455664 +0000
@@ -22,7 +22,9 @@
 	return snprintf(page, PAGE_SIZE,
 			"%s%s\n",
 			(d->flags & DEVFL_UP) ? "up" : "down",
-			(d->flags & DEVFL_CLOSEWAIT) ? ",closewait" : "");
+			(d->flags & DEVFL_PAUSE) ? ",paused" :
+			(d->nopen && !(d->flags & DEVFL_UP)) ? ",closewait" : "");
+	/* I'd rather see nopen exported so we can ditch closewait */
 }
 static ssize_t aoedisk_show_mac(struct gendisk * disk, char *page)
 {
@@ -107,8 +109,7 @@
 
 	spin_lock_irqsave(&d->lock, flags);
 
-	if (--d->nopen == 0 && (d->flags & DEVFL_CLOSEWAIT)) {
-		d->flags &= ~DEVFL_CLOSEWAIT;
+	if (--d->nopen == 0) {
 		spin_unlock_irqrestore(&d->lock, flags);
 		aoecmd_cfg(d->aoemajor, d->aoeminor);
 		return 0;
@@ -158,14 +159,14 @@
 	}
 
 	list_add_tail(&buf->bufs, &d->bufq);
-	aoecmd_work(d);
 
+	aoecmd_work(d);
 	sl = d->sendq_hd;
 	d->sendq_hd = d->sendq_tl = NULL;
 
 	spin_unlock_irqrestore(&d->lock, flags);
-
 	aoenet_xmit(sl);
+
 	return 0;
 }
 
@@ -205,20 +206,18 @@
 		printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate disk "
 			"structure for %ld.%ld\n", d->aoemajor, d->aoeminor);
 		spin_lock_irqsave(&d->lock, flags);
-		d->flags &= ~DEVFL_WORKON;
+		d->flags &= ~DEVFL_GDALLOC;
 		spin_unlock_irqrestore(&d->lock, flags);
 		return;
 	}
 
-	d->bufpool = mempool_create(MIN_BUFS,
-				    mempool_alloc_slab, mempool_free_slab,
-				    buf_pool_cache);
+	d->bufpool = mempool_create_slab_pool(MIN_BUFS, buf_pool_cache);
 	if (d->bufpool == NULL) {
 		printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate bufpool "
 			"for %ld.%ld\n", d->aoemajor, d->aoeminor);
 		put_disk(gd);
 		spin_lock_irqsave(&d->lock, flags);
-		d->flags &= ~DEVFL_WORKON;
+		d->flags &= ~DEVFL_GDALLOC;
 		spin_unlock_irqrestore(&d->lock, flags);
 		return;
 	}
@@ -235,18 +234,13 @@
 
 	gd->queue = &d->blkq;
 	d->gd = gd;
-	d->flags &= ~DEVFL_WORKON;
+	d->flags &= ~DEVFL_GDALLOC;
 	d->flags |= DEVFL_UP;
 
 	spin_unlock_irqrestore(&d->lock, flags);
 
 	add_disk(gd);
 	aoedisk_add_sysfs(d);
-	
-	printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu "
-		"sectors\n", (unsigned long long)mac_addr(d->addr),
-		d->aoemajor, d->aoeminor,
-		d->fw_ver, (long long)d->ssize);
 }
 
 void
diff -urN oldtree/drivers/block/aoe/aoechr.c newtree/drivers/block/aoe/aoechr.c
--- oldtree/drivers/block/aoe/aoechr.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/block/aoe/aoechr.c	2006-02-21 15:58:12.984172664 +0000
@@ -13,6 +13,7 @@
 	MINOR_ERR = 2,
 	MINOR_DISCOVER,
 	MINOR_INTERFACES,
+	MINOR_REVALIDATE,
 	MSGSZ = 2048,
 	NARGS = 10,
 	NMSG = 100,		/* message backlog to retain */
@@ -41,6 +42,7 @@
 	{ MINOR_ERR, "err" },
 	{ MINOR_DISCOVER, "discover" },
 	{ MINOR_INTERFACES, "interfaces" },
+	{ MINOR_REVALIDATE, "revalidate" },
 };
 
 static int
@@ -62,6 +64,39 @@
 	return 0;
 }
 
+static int
+revalidate(const char __user *str, size_t size)
+{
+	int major, minor, n;
+	ulong flags;
+	struct aoedev *d;
+	char buf[16];
+
+	if (size >= sizeof buf)
+		return -EINVAL;
+	buf[sizeof buf - 1] = '\0';
+	if (copy_from_user(buf, str, size))
+		return -EFAULT;
+
+	/* should be e%d.%d format */
+	n = sscanf(buf, "e%d.%d", &major, &minor);
+	if (n != 2) {
+		printk(KERN_ERR "aoe: %s: invalid device specification\n",
+			__FUNCTION__);
+		return -EINVAL;
+	}
+	d = aoedev_by_aoeaddr(major, minor);
+	if (!d)
+		return -EINVAL;
+
+	spin_lock_irqsave(&d->lock, flags);
+	d->flags |= DEVFL_PAUSE;
+	spin_unlock_irqrestore(&d->lock, flags);
+	aoecmd_cfg(major, minor);
+
+	return 0;
+}
+
 void
 aoechr_error(char *msg)
 {
@@ -114,6 +149,8 @@
 	case MINOR_INTERFACES:
 		ret = interfaces(buf, cnt);
 		break;
+	case MINOR_REVALIDATE:
+		ret = revalidate(buf, cnt);
 	}
 	if (ret == 0)
 		ret = cnt;
diff -urN oldtree/drivers/block/aoe/aoecmd.c newtree/drivers/block/aoe/aoecmd.c
--- oldtree/drivers/block/aoe/aoecmd.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/block/aoe/aoecmd.c	2006-02-21 15:58:13.131150320 +0000
@@ -8,6 +8,7 @@
 #include <linux/blkdev.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
+#include <linux/genhd.h>
 #include <asm/unaligned.h>
 #include "aoe.h"
 
@@ -28,6 +29,7 @@
 		skb->protocol = __constant_htons(ETH_P_AOE);
 		skb->priority = 0;
 		skb_put(skb, len);
+		memset(skb->head, 0, len);
 		skb->next = skb->prev = NULL;
 
 		/* tell the network layer not to perform IP checksums
@@ -188,12 +190,67 @@
 	}
 }
 
+/* some callers cannot sleep, and they can call this function,
+ * transmitting the packets later, when interrupts are on
+ */
+static struct sk_buff *
+aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail)
+{
+	struct aoe_hdr *h;
+	struct aoe_cfghdr *ch;
+	struct sk_buff *skb, *sl, *sl_tail;
+	struct net_device *ifp;
+
+	sl = sl_tail = NULL;
+
+	read_lock(&dev_base_lock);
+	for (ifp = dev_base; ifp; dev_put(ifp), ifp = ifp->next) {
+		dev_hold(ifp);
+		if (!is_aoe_netif(ifp))
+			continue;
+
+		skb = new_skb(ifp, sizeof *h + sizeof *ch);
+		if (skb == NULL) {
+			printk(KERN_INFO "aoe: aoecmd_cfg: skb alloc failure\n");
+			continue;
+		}
+		if (sl_tail == NULL)
+			sl_tail = skb;
+		h = (struct aoe_hdr *) skb->mac.raw;
+		memset(h, 0, sizeof *h + sizeof *ch);
+
+		memset(h->dst, 0xff, sizeof h->dst);
+		memcpy(h->src, ifp->dev_addr, sizeof h->src);
+		h->type = __constant_cpu_to_be16(ETH_P_AOE);
+		h->verfl = AOE_HVER;
+		h->major = cpu_to_be16(aoemajor);
+		h->minor = aoeminor;
+		h->cmd = AOECMD_CFG;
+
+		skb->next = sl;
+		sl = skb;
+	}
+	read_unlock(&dev_base_lock);
+
+	if (tail != NULL)
+		*tail = sl_tail;
+	return sl;
+}
+
 /* enters with d->lock held */
 void
 aoecmd_work(struct aoedev *d)
 {
 	struct frame *f;
 	struct buf *buf;
+
+	if (d->flags & DEVFL_PAUSE) {
+		if (!aoedev_isbusy(d))
+			d->sendq_hd = aoecmd_cfg_pkts(d->aoemajor,
+						d->aoeminor, &d->sendq_tl);
+		return;
+	}
+
 loop:
 	f = getframe(d, FREETAG);
 	if (f == NULL)
@@ -229,6 +286,8 @@
 	h = (struct aoe_hdr *) f->data;
 	f->tag = n;
 	h->tag = cpu_to_be32(n);
+	memcpy(h->dst, d->addr, sizeof h->dst);
+	memcpy(h->src, d->ifp->dev_addr, sizeof h->src);
 
 	skb = skb_prepare(d, f);
 	if (skb) {
@@ -272,7 +331,7 @@
 	spin_lock_irqsave(&d->lock, flags);
 
 	if (d->flags & DEVFL_TKILL) {
-tdie:		spin_unlock_irqrestore(&d->lock, flags);
+		spin_unlock_irqrestore(&d->lock, flags);
 		return;
 	}
 	f = d->frames;
@@ -283,7 +342,7 @@
 			n /= HZ;
 			if (n > MAXWAIT) { /* waited too long.  device failure. */
 				aoedev_downdev(d);
-				goto tdie;
+				break;
 			}
 			rexmit(d, f);
 		}
@@ -305,6 +364,37 @@
 	aoenet_xmit(sl);
 }
 
+/* this function performs work that has been deferred until sleeping is OK
+ */
+void
+aoecmd_sleepwork(void *vp)
+{
+	struct aoedev *d = (struct aoedev *) vp;
+
+	if (d->flags & DEVFL_GDALLOC)
+		aoeblk_gdalloc(d);
+
+	if (d->flags & DEVFL_NEWSIZE) {
+		struct block_device *bd;
+		unsigned long flags;
+		u64 ssize;
+
+		ssize = d->gd->capacity;
+		bd = bdget_disk(d->gd, 0);
+
+		if (bd) {
+			mutex_lock(&bd->bd_inode->i_mutex);
+			i_size_write(bd->bd_inode, (loff_t)ssize<<9);
+			mutex_unlock(&bd->bd_inode->i_mutex);
+			bdput(bd);
+		}
+		spin_lock_irqsave(&d->lock, flags);
+		d->flags |= DEVFL_UP;
+		d->flags &= ~DEVFL_NEWSIZE;
+		spin_unlock_irqrestore(&d->lock, flags);
+	}
+}
+
 static void
 ataid_complete(struct aoedev *d, unsigned char *id)
 {
@@ -339,21 +429,29 @@
 		d->geo.heads = le16_to_cpu(get_unaligned((__le16 *) &id[55<<1]));
 		d->geo.sectors = le16_to_cpu(get_unaligned((__le16 *) &id[56<<1]));
 	}
+
+	if (d->ssize != ssize)
+		printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu "
+			"sectors\n", (unsigned long long)mac_addr(d->addr),
+			d->aoemajor, d->aoeminor,
+			d->fw_ver, (long long)ssize);
 	d->ssize = ssize;
 	d->geo.start = 0;
 	if (d->gd != NULL) {
 		d->gd->capacity = ssize;
-		d->flags |= DEVFL_UP;
-		return;
-	}
-	if (d->flags & DEVFL_WORKON) {
-		printk(KERN_INFO "aoe: ataid_complete: can't schedule work, it's already on!  "
-			"(This really shouldn't happen).\n");
-		return;
+		d->flags |= DEVFL_NEWSIZE;
+	} else {
+		if (d->flags & DEVFL_GDALLOC) {
+			printk(KERN_INFO "aoe: %s: %s e%lu.%lu, %s\n",
+			       __FUNCTION__,
+			       "can't schedule work for",
+			       d->aoemajor, d->aoeminor,
+			       "it's already on! (This really shouldn't happen).\n");
+			return;
+		}
+		d->flags |= DEVFL_GDALLOC;
 	}
-	INIT_WORK(&d->work, aoeblk_gdalloc, d);
 	schedule_work(&d->work);
-	d->flags |= DEVFL_WORKON;
 }
 
 static void
@@ -419,6 +517,8 @@
 	ahout = (struct aoe_atahdr *) (f->data + sizeof(struct aoe_hdr));
 	buf = f->buf;
 
+	if (ahout->cmdstat == WIN_IDENTIFY)
+		d->flags &= ~DEVFL_PAUSE;
 	if (ahin->cmdstat & 0xa9) {	/* these bits cleared on success */
 		printk(KERN_CRIT "aoe: aoecmd_ata_rsp: ata error cmd=%2.2Xh "
 			"stat=%2.2Xh from e%ld.%ld\n", 
@@ -451,7 +551,6 @@
 				return;
 			}
 			ataid_complete(d, (char *) (ahin+1));
-			/* d->flags |= DEVFL_WC_UPDATE; */
 			break;
 		default:
 			printk(KERN_INFO "aoe: aoecmd_ata_rsp: unrecognized "
@@ -484,51 +583,19 @@
 	f->tag = FREETAG;
 
 	aoecmd_work(d);
-
 	sl = d->sendq_hd;
 	d->sendq_hd = d->sendq_tl = NULL;
 
 	spin_unlock_irqrestore(&d->lock, flags);
-
 	aoenet_xmit(sl);
 }
 
 void
 aoecmd_cfg(ushort aoemajor, unsigned char aoeminor)
 {
-	struct aoe_hdr *h;
-	struct aoe_cfghdr *ch;
-	struct sk_buff *skb, *sl;
-	struct net_device *ifp;
-
-	sl = NULL;
-
-	read_lock(&dev_base_lock);
-	for (ifp = dev_base; ifp; dev_put(ifp), ifp = ifp->next) {
-		dev_hold(ifp);
-		if (!is_aoe_netif(ifp))
-			continue;
-
-		skb = new_skb(ifp, sizeof *h + sizeof *ch);
-		if (skb == NULL) {
-			printk(KERN_INFO "aoe: aoecmd_cfg: skb alloc failure\n");
-			continue;
-		}
-		h = (struct aoe_hdr *) skb->mac.raw;
-		memset(h, 0, sizeof *h + sizeof *ch);
-
-		memset(h->dst, 0xff, sizeof h->dst);
-		memcpy(h->src, ifp->dev_addr, sizeof h->src);
-		h->type = __constant_cpu_to_be16(ETH_P_AOE);
-		h->verfl = AOE_HVER;
-		h->major = cpu_to_be16(aoemajor);
-		h->minor = aoeminor;
-		h->cmd = AOECMD_CFG;
+	struct sk_buff *sl;
 
-		skb->next = sl;
-		sl = skb;
-	}
-	read_unlock(&dev_base_lock);
+	sl = aoecmd_cfg_pkts(aoemajor, aoeminor, NULL);
 
 	aoenet_xmit(sl);
 }
@@ -561,9 +628,6 @@
 	f->waited = 0;
 	f->writedatalen = 0;
 
-	/* this message initializes the device, so we reset the rttavg */
-	d->rttavg = MAXTIMER;
-
 	/* set up ata header */
 	ah->scnt = 1;
 	ah->cmdstat = WIN_IDENTIFY;
@@ -571,12 +635,8 @@
 
 	skb = skb_prepare(d, f);
 
-	/* we now want to start the rexmit tracking */
-	d->flags &= ~DEVFL_TKILL;
-	d->timer.data = (ulong) d;
+	d->rttavg = MAXTIMER;
 	d->timer.function = rexmit_timer;
-	d->timer.expires = jiffies + TIMERTICK;
-	add_timer(&d->timer);
 
 	return skb;
 }
@@ -590,7 +650,7 @@
 	ulong flags, sysminor, aoemajor;
 	u16 bufcnt;
 	struct sk_buff *sl;
-	enum { MAXFRAMES = 8 };
+	enum { MAXFRAMES = 16 };
 
 	h = (struct aoe_hdr *) skb->mac.raw;
 	ch = (struct aoe_cfghdr *) (h+1);
@@ -618,23 +678,28 @@
 	if (bufcnt > MAXFRAMES)	/* keep it reasonable */
 		bufcnt = MAXFRAMES;
 
-	d = aoedev_set(sysminor, h->src, skb->dev, bufcnt);
+	d = aoedev_by_sysminor_m(sysminor, bufcnt);
 	if (d == NULL) {
-		printk(KERN_INFO "aoe: aoecmd_cfg_rsp: device set failure\n");
+		printk(KERN_INFO "aoe: aoecmd_cfg_rsp: device sysminor_m failure\n");
 		return;
 	}
 
 	spin_lock_irqsave(&d->lock, flags);
 
-	if (d->flags & (DEVFL_UP | DEVFL_CLOSEWAIT)) {
+	/* permit device to migrate mac and network interface */
+	d->ifp = skb->dev;
+	memcpy(d->addr, h->src, sizeof d->addr);
+
+	/* don't change users' perspective */
+	if (d->nopen && !(d->flags & DEVFL_PAUSE)) {
 		spin_unlock_irqrestore(&d->lock, flags);
 		return;
 	}
-
+	d->flags |= DEVFL_PAUSE;	/* force pause */
 	d->fw_ver = be16_to_cpu(ch->fwver);
 
-	/* we get here only if the device is new */
-	sl = aoecmd_ata_id(d);
+	/* check for already outstanding ataid */
+	sl = aoedev_isbusy(d) == 0 ? aoecmd_ata_id(d) : NULL;
 
 	spin_unlock_irqrestore(&d->lock, flags);
 
diff -urN oldtree/drivers/block/aoe/aoedev.c newtree/drivers/block/aoe/aoedev.c
--- oldtree/drivers/block/aoe/aoedev.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/block/aoe/aoedev.c	2006-02-21 15:58:12.985172512 +0000
@@ -12,6 +12,24 @@
 static struct aoedev *devlist;
 static spinlock_t devlist_lock;
 
+int
+aoedev_isbusy(struct aoedev *d)
+{
+	struct frame *f, *e;
+
+	f = d->frames;
+	e = f + d->nframes;
+	do {
+		if (f->tag != FREETAG) {
+			printk(KERN_DEBUG "aoe: %ld.%ld isbusy\n",
+				d->aoemajor, d->aoeminor);
+			return 1;
+		}
+	} while (++f < e);
+
+	return 0;
+}
+
 struct aoedev *
 aoedev_by_aoeaddr(int maj, int min)
 {
@@ -28,6 +46,18 @@
 	return d;
 }
 
+static void
+dummy_timer(ulong vp)
+{
+	struct aoedev *d;
+
+	d = (struct aoedev *)vp;
+	if (d->flags & DEVFL_TKILL)
+		return;
+	d->timer.expires = jiffies + HZ;
+	add_timer(&d->timer);
+}
+
 /* called with devlist lock held */
 static struct aoedev *
 aoedev_newdev(ulong nframes)
@@ -44,6 +74,8 @@
 		return NULL;
 	}
 
+	INIT_WORK(&d->work, aoecmd_sleepwork, d);
+
 	d->nframes = nframes;
 	d->frames = f;
 	e = f + nframes;
@@ -52,6 +84,10 @@
 
 	spin_lock_init(&d->lock);
 	init_timer(&d->timer);
+	d->timer.data = (ulong) d;
+	d->timer.function = dummy_timer;
+	d->timer.expires = jiffies + HZ;
+	add_timer(&d->timer);
 	d->bufpool = NULL;	/* defer to aoeblk_gdalloc */
 	INIT_LIST_HEAD(&d->bufq);
 	d->next = devlist;
@@ -67,9 +103,6 @@
 	struct buf *buf;
 	struct bio *bio;
 
-	d->flags |= DEVFL_TKILL;
-	del_timer(&d->timer);
-
 	f = d->frames;
 	e = f + d->nframes;
 	for (; f<e; f->tag = FREETAG, f->buf = NULL, f++) {
@@ -92,16 +125,15 @@
 		bio_endio(bio, bio->bi_size, -EIO);
 	}
 
-	if (d->nopen)
-		d->flags |= DEVFL_CLOSEWAIT;
 	if (d->gd)
 		d->gd->capacity = 0;
 
-	d->flags &= ~DEVFL_UP;
+	d->flags &= ~(DEVFL_UP | DEVFL_PAUSE);
 }
 
+/* find it or malloc it */
 struct aoedev *
-aoedev_set(ulong sysminor, unsigned char *addr, struct net_device *ifp, ulong bufcnt)
+aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt)
 {
 	struct aoedev *d;
 	ulong flags;
@@ -112,25 +144,19 @@
 		if (d->sysminor == sysminor)
 			break;
 
-	if (d == NULL && (d = aoedev_newdev(bufcnt)) == NULL) {
-		spin_unlock_irqrestore(&devlist_lock, flags);
-		printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n");
-		return NULL;
-	} /* if newdev, (d->flags & DEVFL_UP) == 0 for below */
-
-	spin_unlock_irqrestore(&devlist_lock, flags);
-	spin_lock_irqsave(&d->lock, flags);
-
-	d->ifp = ifp;
-	memcpy(d->addr, addr, sizeof d->addr);
-	if ((d->flags & DEVFL_UP) == 0) {
-		aoedev_downdev(d); /* flushes outstanding frames */
+	if (d == NULL) {
+		d = aoedev_newdev(bufcnt);
+	 	if (d == NULL) {
+			spin_unlock_irqrestore(&devlist_lock, flags);
+			printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n");
+			return NULL;
+		}
 		d->sysminor = sysminor;
 		d->aoemajor = AOEMAJOR(sysminor);
 		d->aoeminor = AOEMINOR(sysminor);
 	}
 
-	spin_unlock_irqrestore(&d->lock, flags);
+	spin_unlock_irqrestore(&devlist_lock, flags);
 	return d;
 }
 
@@ -161,6 +187,7 @@
 
 		spin_lock_irqsave(&d->lock, flags);
 		aoedev_downdev(d);
+		d->flags |= DEVFL_TKILL;
 		spin_unlock_irqrestore(&d->lock, flags);
 
 		del_timer_sync(&d->timer);
diff -urN oldtree/drivers/block/aoe/aoemain.c newtree/drivers/block/aoe/aoemain.c
--- oldtree/drivers/block/aoe/aoemain.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/block/aoe/aoemain.c	2006-02-21 15:58:13.068159896 +0000
@@ -11,7 +11,7 @@
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Sam Hopkins <sah@coraid.com>");
-MODULE_DESCRIPTION("AoE block/char driver for 2.6.[0-9]+");
+MODULE_DESCRIPTION("AoE block/char driver for 2.6.2 and newer 2.6 kernels");
 MODULE_VERSION(VERSION);
 
 enum { TINIT, TRUN, TKILL };
@@ -89,7 +89,7 @@
 	}
 
 	printk(KERN_INFO
-	       "aoe: aoe_init: AoE v2.6-%s initialised.\n",
+	       "aoe: aoe_init: AoE v%s initialised.\n",
 	       VERSION);
 	discover_timer(TINIT);
 	return 0;
diff -urN oldtree/drivers/block/aoe/aoenet.c newtree/drivers/block/aoe/aoenet.c
--- oldtree/drivers/block/aoe/aoenet.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/block/aoe/aoenet.c	2006-02-21 15:58:13.119152144 +0000
@@ -92,18 +92,6 @@
 	return __be64_to_cpu(n);
 }
 
-static struct sk_buff *
-skb_check(struct sk_buff *skb)
-{
-	if (skb_is_nonlinear(skb))
-	if ((skb = skb_share_check(skb, GFP_ATOMIC)))
-	if (skb_linearize(skb, GFP_ATOMIC) < 0) {
-		dev_kfree_skb(skb);
-		return NULL;
-	}
-	return skb;
-}
-
 void
 aoenet_xmit(struct sk_buff *sl)
 {
@@ -125,14 +113,14 @@
 	struct aoe_hdr *h;
 	u32 n;
 
-	skb = skb_check(skb);
-	if (!skb)
+	skb = skb_share_check(skb, GFP_ATOMIC);
+	if (skb == NULL)
 		return 0;
-
+	if (skb_is_nonlinear(skb))
+	if (skb_linearize(skb, GFP_ATOMIC) < 0)
+		goto exit;
 	if (!is_aoe_netif(ifp))
 		goto exit;
-
-	//skb->len += ETH_HLEN;	/* (1) */
 	skb_push(skb, ETH_HLEN);	/* (1) */
 
 	h = (struct aoe_hdr *) skb->mac.raw;
diff -urN oldtree/drivers/block/cciss.c newtree/drivers/block/cciss.c
--- oldtree/drivers/block/cciss.c	2006-02-19 11:41:01.038185272 +0000
+++ newtree/drivers/block/cciss.c	2006-02-21 15:58:18.737298056 +0000
@@ -38,6 +38,7 @@
 #include <linux/hdreg.h>
 #include <linux/spinlock.h>
 #include <linux/compat.h>
+#include <linux/blktrace_api.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
@@ -2331,6 +2332,7 @@
 
 	cmd->rq->completion_data = cmd;
 	cmd->rq->errors = status;
+	blk_add_trace_rq(cmd->rq->q, cmd->rq, BLK_TA_COMPLETE);
 	blk_complete_request(cmd->rq);
 }
 
@@ -3251,8 +3253,7 @@
 
 clean4:
 #ifdef CONFIG_CISS_SCSI_TAPE
-	if(hba[i]->scsi_rejects.complete)
-		kfree(hba[i]->scsi_rejects.complete);
+	kfree(hba[i]->scsi_rejects.complete);
 #endif
 	kfree(hba[i]->cmd_pool_bits);
 	if(hba[i]->cmd_pool)
diff -urN oldtree/drivers/block/floppy.c newtree/drivers/block/floppy.c
--- oldtree/drivers/block/floppy.c	2006-02-19 11:41:01.071180256 +0000
+++ newtree/drivers/block/floppy.c	2006-02-21 15:58:24.022494584 +0000
@@ -179,6 +179,7 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/platform_device.h>
 #include <linux/buffer_head.h>	/* for invalidate_buffers() */
+#include <linux/mutex.h>
 
 /*
  * PS/2 floppies have much slower step rates than regular floppies.
@@ -413,7 +414,7 @@
 static struct timer_list motor_off_timer[N_DRIVE];
 static struct gendisk *disks[N_DRIVE];
 static struct block_device *opened_bdev[N_DRIVE];
-static DECLARE_MUTEX(open_lock);
+static DEFINE_MUTEX(open_lock);
 static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
 
 /*
@@ -3333,7 +3334,7 @@
 	if (type) {
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		down(&open_lock);
+		mutex_lock(&open_lock);
 		LOCK_FDC(drive, 1);
 		floppy_type[type] = *g;
 		floppy_type[type].name = "user format";
@@ -3347,7 +3348,7 @@
 				continue;
 			__invalidate_device(bdev);
 		}
-		up(&open_lock);
+		mutex_unlock(&open_lock);
 	} else {
 		int oldStretch;
 		LOCK_FDC(drive, 1);
@@ -3674,7 +3675,7 @@
 {
 	int drive = (long)inode->i_bdev->bd_disk->private_data;
 
-	down(&open_lock);
+	mutex_lock(&open_lock);
 	if (UDRS->fd_ref < 0)
 		UDRS->fd_ref = 0;
 	else if (!UDRS->fd_ref--) {
@@ -3684,7 +3685,7 @@
 	if (!UDRS->fd_ref)
 		opened_bdev[drive] = NULL;
 	floppy_release_irq_and_dma();
-	up(&open_lock);
+	mutex_unlock(&open_lock);
 	return 0;
 }
 
@@ -3702,7 +3703,7 @@
 	char *tmp;
 
 	filp->private_data = (void *)0;
-	down(&open_lock);
+	mutex_lock(&open_lock);
 	old_dev = UDRS->fd_device;
 	if (opened_bdev[drive] && opened_bdev[drive] != inode->i_bdev)
 		goto out2;
@@ -3785,7 +3786,7 @@
 		if ((filp->f_mode & 2) && !(UTESTF(FD_DISK_WRITABLE)))
 			goto out;
 	}
-	up(&open_lock);
+	mutex_unlock(&open_lock);
 	return 0;
 out:
 	if (UDRS->fd_ref < 0)
@@ -3796,7 +3797,7 @@
 		opened_bdev[drive] = NULL;
 	floppy_release_irq_and_dma();
 out2:
-	up(&open_lock);
+	mutex_unlock(&open_lock);
 	return res;
 }
 
diff -urN oldtree/drivers/block/loop.c newtree/drivers/block/loop.c
--- oldtree/drivers/block/loop.c	2006-02-19 11:41:01.072180104 +0000
+++ newtree/drivers/block/loop.c	2006-02-21 15:58:26.291149696 +0000
@@ -1144,7 +1144,7 @@
 	struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
 	int err;
 
-	down(&lo->lo_ctl_mutex);
+	mutex_lock(&lo->lo_ctl_mutex);
 	switch (cmd) {
 	case LOOP_SET_FD:
 		err = loop_set_fd(lo, file, inode->i_bdev, arg);
@@ -1170,7 +1170,7 @@
 	default:
 		err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL;
 	}
-	up(&lo->lo_ctl_mutex);
+	mutex_unlock(&lo->lo_ctl_mutex);
 	return err;
 }
 
@@ -1178,9 +1178,9 @@
 {
 	struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
 
-	down(&lo->lo_ctl_mutex);
+	mutex_lock(&lo->lo_ctl_mutex);
 	lo->lo_refcnt++;
-	up(&lo->lo_ctl_mutex);
+	mutex_unlock(&lo->lo_ctl_mutex);
 
 	return 0;
 }
@@ -1189,9 +1189,9 @@
 {
 	struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
 
-	down(&lo->lo_ctl_mutex);
+	mutex_lock(&lo->lo_ctl_mutex);
 	--lo->lo_refcnt;
-	up(&lo->lo_ctl_mutex);
+	mutex_unlock(&lo->lo_ctl_mutex);
 
 	return 0;
 }
@@ -1233,12 +1233,12 @@
 	xfer_funcs[n] = NULL;
 
 	for (lo = &loop_dev[0]; lo < &loop_dev[max_loop]; lo++) {
-		down(&lo->lo_ctl_mutex);
+		mutex_lock(&lo->lo_ctl_mutex);
 
 		if (lo->lo_encryption == xfer)
 			loop_release_xfer(lo);
 
-		up(&lo->lo_ctl_mutex);
+		mutex_unlock(&lo->lo_ctl_mutex);
 	}
 
 	return 0;
@@ -1285,7 +1285,7 @@
 		lo->lo_queue = blk_alloc_queue(GFP_KERNEL);
 		if (!lo->lo_queue)
 			goto out_mem4;
-		init_MUTEX(&lo->lo_ctl_mutex);
+		mutex_init(&lo->lo_ctl_mutex);
 		init_completion(&lo->lo_done);
 		init_completion(&lo->lo_bh_done);
 		lo->lo_number = i;
diff -urN oldtree/drivers/block/nbd.c newtree/drivers/block/nbd.c
--- oldtree/drivers/block/nbd.c	2006-02-19 11:41:01.073179952 +0000
+++ newtree/drivers/block/nbd.c	2006-02-21 15:58:26.351140576 +0000
@@ -459,9 +459,9 @@
 		req->errors = 0;
 		spin_unlock_irq(q->queue_lock);
 
-		down(&lo->tx_lock);
+		mutex_lock(&lo->tx_lock);
 		if (unlikely(!lo->sock)) {
-			up(&lo->tx_lock);
+			mutex_unlock(&lo->tx_lock);
 			printk(KERN_ERR "%s: Attempted send on closed socket\n",
 			       lo->disk->disk_name);
 			req->errors++;
@@ -484,7 +484,7 @@
 		}
 
 		lo->active_req = NULL;
-		up(&lo->tx_lock);
+		mutex_unlock(&lo->tx_lock);
 		wake_up_all(&lo->active_wq);
 
 		spin_lock_irq(q->queue_lock);
@@ -534,9 +534,9 @@
  
 	case NBD_CLEAR_SOCK:
 		error = 0;
-		down(&lo->tx_lock);
+		mutex_lock(&lo->tx_lock);
 		lo->sock = NULL;
-		up(&lo->tx_lock);
+		mutex_unlock(&lo->tx_lock);
 		file = lo->file;
 		lo->file = NULL;
 		nbd_clear_que(lo);
@@ -590,7 +590,7 @@
 		 * FIXME: This code is duplicated from sys_shutdown, but
 		 * there should be a more generic interface rather than
 		 * calling socket ops directly here */
-		down(&lo->tx_lock);
+		mutex_lock(&lo->tx_lock);
 		if (lo->sock) {
 			printk(KERN_WARNING "%s: shutting down socket\n",
 				lo->disk->disk_name);
@@ -598,7 +598,7 @@
 				SEND_SHUTDOWN|RCV_SHUTDOWN);
 			lo->sock = NULL;
 		}
-		up(&lo->tx_lock);
+		mutex_unlock(&lo->tx_lock);
 		file = lo->file;
 		lo->file = NULL;
 		nbd_clear_que(lo);
@@ -683,7 +683,7 @@
 		nbd_dev[i].flags = 0;
 		spin_lock_init(&nbd_dev[i].queue_lock);
 		INIT_LIST_HEAD(&nbd_dev[i].queue_head);
-		init_MUTEX(&nbd_dev[i].tx_lock);
+		mutex_init(&nbd_dev[i].tx_lock);
 		init_waitqueue_head(&nbd_dev[i].active_wq);
 		nbd_dev[i].blksize = 1024;
 		nbd_dev[i].bytesize = 0x7ffffc00ULL << 10; /* 2TB */
diff -urN oldtree/drivers/block/pktcdvd.c newtree/drivers/block/pktcdvd.c
--- oldtree/drivers/block/pktcdvd.c	2006-02-19 11:41:01.078179192 +0000
+++ newtree/drivers/block/pktcdvd.c	2006-02-21 15:58:30.744472688 +0000
@@ -56,8 +56,10 @@
 #include <linux/seq_file.h>
 #include <linux/miscdevice.h>
 #include <linux/suspend.h>
+#include <linux/mutex.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_ioctl.h>
+#include <scsi/scsi.h>
 
 #include <asm/uaccess.h>
 
@@ -80,7 +82,7 @@
 static struct pktcdvd_device *pkt_devs[MAX_WRITERS];
 static struct proc_dir_entry *pkt_proc;
 static int pkt_major;
-static struct semaphore ctl_mutex;	/* Serialize open/close/setup/teardown */
+static struct mutex ctl_mutex;	/* Serialize open/close/setup/teardown */
 static mempool_t *psd_pool;
 
 
@@ -228,16 +230,6 @@
 	return 1;
 }
 
-static void *pkt_rb_alloc(gfp_t gfp_mask, void *data)
-{
-	return kmalloc(sizeof(struct pkt_rb_node), gfp_mask);
-}
-
-static void pkt_rb_free(void *ptr, void *data)
-{
-	kfree(ptr);
-}
-
 static inline struct pkt_rb_node *pkt_rbtree_next(struct pkt_rb_node *node)
 {
 	struct rb_node *n = rb_next(&node->rb_node);
@@ -380,6 +372,7 @@
 	memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE);
 	if (sizeof(rq->cmd) > CDROM_PACKET_SIZE)
 		memset(rq->cmd + CDROM_PACKET_SIZE, 0, sizeof(rq->cmd) - CDROM_PACKET_SIZE);
+	rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
 
 	rq->ref_count++;
 	rq->flags |= REQ_NOMERGE;
@@ -1495,40 +1488,42 @@
 }
 
 /*
- * 0 -- we can write to this track, 1 -- we can't
+ * 1 -- we can write to this track, 0 -- we can't
  */
-static int pkt_good_track(track_information *ti)
+static int pkt_writable_track(struct pktcdvd_device *pd, track_information *ti)
 {
-	/*
-	 * only good for CD-RW at the moment, not DVD-RW
-	 */
+	switch (pd->mmc3_profile) {
+		case 0x1a: /* DVD+RW */
+		case 0x12: /* DVD-RAM */
+			/* The track is always writable on DVD+RW/DVD-RAM */
+			return 1;
+		default:
+			break;
+	}
 
-	/*
-	 * FIXME: only for FP
-	 */
-	if (ti->fp == 0)
+	if (!ti->packet || !ti->fp)
 		return 0;
 
 	/*
 	 * "good" settings as per Mt Fuji.
 	 */
-	if (ti->rt == 0 && ti->blank == 0 && ti->packet == 1)
-		return 0;
+	if (ti->rt == 0 && ti->blank == 0)
+		return 1;
 
-	if (ti->rt == 0 && ti->blank == 1 && ti->packet == 1)
-		return 0;
+	if (ti->rt == 0 && ti->blank == 1)
+		return 1;
 
-	if (ti->rt == 1 && ti->blank == 0 && ti->packet == 1)
-		return 0;
+	if (ti->rt == 1 && ti->blank == 0)
+		return 1;
 
 	printk("pktcdvd: bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet);
-	return 1;
+	return 0;
 }
 
 /*
- * 0 -- we can write to this disc, 1 -- we can't
+ * 1 -- we can write to this disc, 0 -- we can't
  */
-static int pkt_good_disc(struct pktcdvd_device *pd, disc_information *di)
+static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di)
 {
 	switch (pd->mmc3_profile) {
 		case 0x0a: /* CD-RW */
@@ -1537,10 +1532,10 @@
 		case 0x1a: /* DVD+RW */
 		case 0x13: /* DVD-RW */
 		case 0x12: /* DVD-RAM */
-			return 0;
+			return 1;
 		default:
 			VPRINTK("pktcdvd: Wrong disc profile (%x)\n", pd->mmc3_profile);
-			return 1;
+			return 0;
 	}
 
 	/*
@@ -1549,25 +1544,25 @@
 	 */
 	if (di->disc_type == 0xff) {
 		printk("pktcdvd: Unknown disc. No track?\n");
-		return 1;
+		return 0;
 	}
 
 	if (di->disc_type != 0x20 && di->disc_type != 0) {
 		printk("pktcdvd: Wrong disc type (%x)\n", di->disc_type);
-		return 1;
+		return 0;
 	}
 
 	if (di->erasable == 0) {
 		printk("pktcdvd: Disc not erasable\n");
-		return 1;
+		return 0;
 	}
 
 	if (di->border_status == PACKET_SESSION_RESERVED) {
 		printk("pktcdvd: Can't write to last track (reserved)\n");
-		return 1;
+		return 0;
 	}
 
-	return 0;
+	return 1;
 }
 
 static int pkt_probe_settings(struct pktcdvd_device *pd)
@@ -1592,23 +1587,9 @@
 		return ret;
 	}
 
-	if (pkt_good_disc(pd, &di))
-		return -ENXIO;
+	if (!pkt_writable_disc(pd, &di))
+		return -EROFS;
 
-	switch (pd->mmc3_profile) {
-		case 0x1a: /* DVD+RW */
-			printk("pktcdvd: inserted media is DVD+RW\n");
-			break;
-		case 0x13: /* DVD-RW */
-			printk("pktcdvd: inserted media is DVD-RW\n");
-			break;
-		case 0x12: /* DVD-RAM */
-			printk("pktcdvd: inserted media is DVD-RAM\n");
-			break;
-		default:
-			printk("pktcdvd: inserted media is CD-R%s\n", di.erasable ? "W" : "");
-			break;
-	}
 	pd->type = di.erasable ? PACKET_CDRW : PACKET_CDR;
 
 	track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */
@@ -1617,9 +1598,9 @@
 		return ret;
 	}
 
-	if (pkt_good_track(&ti)) {
+	if (!pkt_writable_track(pd, &ti)) {
 		printk("pktcdvd: can't write to this track\n");
-		return -ENXIO;
+		return -EROFS;
 	}
 
 	/*
@@ -1633,7 +1614,7 @@
 	}
 	if (pd->settings.size > PACKET_MAX_SECTORS) {
 		printk("pktcdvd: packet size is too big\n");
-		return -ENXIO;
+		return -EROFS;
 	}
 	pd->settings.fp = ti.fp;
 	pd->offset = (be32_to_cpu(ti.track_start) << 2) & (pd->settings.size - 1);
@@ -1675,7 +1656,7 @@
 			break;
 		default:
 			printk("pktcdvd: unknown data mode\n");
-			return 1;
+			return -EROFS;
 	}
 	return 0;
 }
@@ -1886,7 +1867,7 @@
 
 	if ((ret = pkt_probe_settings(pd))) {
 		VPRINTK("pktcdvd: %s failed probe\n", pd->name);
-		return -EROFS;
+		return ret;
 	}
 
 	if ((ret = pkt_set_write_settings(pd))) {
@@ -2028,7 +2009,7 @@
 
 	VPRINTK("pktcdvd: entering open\n");
 
-	down(&ctl_mutex);
+	mutex_lock(&ctl_mutex);
 	pd = pkt_find_dev_from_minor(iminor(inode));
 	if (!pd) {
 		ret = -ENODEV;
@@ -2054,14 +2035,14 @@
 		set_blocksize(inode->i_bdev, CD_FRAMESIZE);
 	}
 
-	up(&ctl_mutex);
+	mutex_unlock(&ctl_mutex);
 	return 0;
 
 out_dec:
 	pd->refcnt--;
 out:
 	VPRINTK("pktcdvd: failed open (%d)\n", ret);
-	up(&ctl_mutex);
+	mutex_unlock(&ctl_mutex);
 	return ret;
 }
 
@@ -2070,28 +2051,18 @@
 	struct pktcdvd_device *pd = inode->i_bdev->bd_disk->private_data;
 	int ret = 0;
 
-	down(&ctl_mutex);
+	mutex_lock(&ctl_mutex);
 	pd->refcnt--;
 	BUG_ON(pd->refcnt < 0);
 	if (pd->refcnt == 0) {
 		int flush = test_bit(PACKET_WRITABLE, &pd->flags);
 		pkt_release_dev(pd, flush);
 	}
-	up(&ctl_mutex);
+	mutex_unlock(&ctl_mutex);
 	return ret;
 }
 
 
-static void *psd_pool_alloc(gfp_t gfp_mask, void *data)
-{
-	return kmalloc(sizeof(struct packet_stacked_data), gfp_mask);
-}
-
-static void psd_pool_free(void *ptr, void *data)
-{
-	kfree(ptr);
-}
-
 static int pkt_end_io_read_cloned(struct bio *bio, unsigned int bytes_done, int err)
 {
 	struct packet_stacked_data *psd = bio->bi_private;
@@ -2484,7 +2455,8 @@
 	if (!pd)
 		return ret;
 
-	pd->rb_pool = mempool_create(PKT_RB_POOL_SIZE, pkt_rb_alloc, pkt_rb_free, NULL);
+	pd->rb_pool = mempool_create_kmalloc_pool(PKT_RB_POOL_SIZE,
+						  sizeof(struct pkt_rb_node));
 	if (!pd->rb_pool)
 		goto out_mem;
 
@@ -2606,21 +2578,21 @@
 	case PKT_CTRL_CMD_SETUP:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		down(&ctl_mutex);
+		mutex_lock(&ctl_mutex);
 		ret = pkt_setup_dev(&ctrl_cmd);
-		up(&ctl_mutex);
+		mutex_unlock(&ctl_mutex);
 		break;
 	case PKT_CTRL_CMD_TEARDOWN:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		down(&ctl_mutex);
+		mutex_lock(&ctl_mutex);
 		ret = pkt_remove_dev(&ctrl_cmd);
-		up(&ctl_mutex);
+		mutex_unlock(&ctl_mutex);
 		break;
 	case PKT_CTRL_CMD_STATUS:
-		down(&ctl_mutex);
+		mutex_lock(&ctl_mutex);
 		pkt_get_status(&ctrl_cmd);
-		up(&ctl_mutex);
+		mutex_unlock(&ctl_mutex);
 		break;
 	default:
 		return -ENOTTY;
@@ -2648,7 +2620,8 @@
 {
 	int ret;
 
-	psd_pool = mempool_create(PSD_POOL_SIZE, psd_pool_alloc, psd_pool_free, NULL);
+	psd_pool = mempool_create_kmalloc_pool(PSD_POOL_SIZE,
+					sizeof(struct packet_stacked_data));
 	if (!psd_pool)
 		return -ENOMEM;
 
@@ -2666,7 +2639,7 @@
 		goto out;
 	}
 
-	init_MUTEX(&ctl_mutex);
+	mutex_init(&ctl_mutex);
 
 	pkt_proc = proc_mkdir("pktcdvd", proc_root_driver);
 
diff -urN oldtree/drivers/block/rd.c newtree/drivers/block/rd.c
--- oldtree/drivers/block/rd.c	2006-02-19 11:41:01.079179040 +0000
+++ newtree/drivers/block/rd.c	2006-02-21 15:58:29.906600064 +0000
@@ -186,7 +186,8 @@
  */
 static int ramdisk_set_page_dirty(struct page *page)
 {
-	SetPageDirty(page);
+	if (!TestSetPageDirty(page))
+		return 1;
 	return 0;
 }
 
@@ -310,12 +311,12 @@
 	 * cache
 	 */
 	error = -EBUSY;
-	down(&bdev->bd_sem);
+	mutex_lock(&bdev->bd_mutex);
 	if (bdev->bd_openers <= 2) {
 		truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
 		error = 0;
 	}
-	up(&bdev->bd_sem);
+	mutex_unlock(&bdev->bd_mutex);
 	return error;
 }
 
diff -urN oldtree/drivers/cdrom/cdrom.c newtree/drivers/cdrom/cdrom.c
--- oldtree/drivers/cdrom/cdrom.c	2006-02-19 11:41:01.096176456 +0000
+++ newtree/drivers/cdrom/cdrom.c	2006-02-21 15:58:36.262633800 +0000
@@ -705,7 +705,7 @@
 {
 	struct packet_command cgc;
 	char buffer[16];
-	__u16 *feature_code;
+	__be16 *feature_code;
 	int ret;
 
 	init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
@@ -718,7 +718,7 @@
 	if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
 		return ret;
 
-	feature_code = (__u16 *) &buffer[sizeof(struct feature_header)];
+	feature_code = (__be16 *) &buffer[sizeof(struct feature_header)];
 	if (be16_to_cpu(*feature_code) == CDF_HWDM)
 		return 0;
 
@@ -2196,395 +2196,592 @@
 	return cdrom_read_cdda_old(cdi, ubuf, lba, nframes);	
 }
 
-/* Just about every imaginable ioctl is supported in the Uniform layer
- * these days. ATAPI / SCSI specific code now mainly resides in
- * mmc_ioct().
- */
-int cdrom_ioctl(struct file * file, struct cdrom_device_info *cdi,
-		struct inode *ip, unsigned int cmd, unsigned long arg)
+static int cdrom_ioctl_multisession(struct cdrom_device_info *cdi,
+		void __user *argp)
 {
-	struct cdrom_device_ops *cdo = cdi->ops;
+	struct cdrom_multisession ms_info;
+	u8 requested_format;
 	int ret;
 
-	/* Try the generic SCSI command ioctl's first.. */
-	ret = scsi_cmd_ioctl(file, ip->i_bdev->bd_disk, cmd, (void __user *)arg);
-	if (ret != -ENOTTY)
+	cdinfo(CD_DO_IOCTL, "entering CDROMMULTISESSION\n");
+
+	if (!(cdi->ops->capability & CDC_MULTI_SESSION))
+		return -ENOSYS;
+
+	if (copy_from_user(&ms_info, argp, sizeof(ms_info)))
+		return -EFAULT;
+
+	requested_format = ms_info.addr_format;
+	if (requested_format != CDROM_MSF && requested_format != CDROM_LBA)
+		return -EINVAL;
+	ms_info.addr_format = CDROM_LBA;
+
+	ret = cdi->ops->get_last_session(cdi, &ms_info);
+	if (ret)
 		return ret;
 
-	/* the first few commands do not deal with audio drive_info, but
-	   only with routines in cdrom device operations. */
-	switch (cmd) {
-	case CDROMMULTISESSION: {
-		struct cdrom_multisession ms_info;
-		u_char requested_format;
-		cdinfo(CD_DO_IOCTL, "entering CDROMMULTISESSION\n"); 
-                if (!(cdo->capability & CDC_MULTI_SESSION))
-                        return -ENOSYS;
-		IOCTL_IN(arg, struct cdrom_multisession, ms_info);
-		requested_format = ms_info.addr_format;
-		if (!((requested_format == CDROM_MSF) ||
-			(requested_format == CDROM_LBA)))
-				return -EINVAL;
-		ms_info.addr_format = CDROM_LBA;
-		if ((ret=cdo->get_last_session(cdi, &ms_info)))
+	sanitize_format(&ms_info.addr, &ms_info.addr_format, requested_format);
+
+	if (copy_to_user(argp, &ms_info, sizeof(ms_info)))
+		return -EFAULT;
+
+	cdinfo(CD_DO_IOCTL, "CDROMMULTISESSION successful\n");
+	return 0;
+}
+
+static int cdrom_ioctl_eject(struct cdrom_device_info *cdi)
+{
+	cdinfo(CD_DO_IOCTL, "entering CDROMEJECT\n");
+
+	if (!CDROM_CAN(CDC_OPEN_TRAY))
+		return -ENOSYS;
+	if (cdi->use_count != 1 || keeplocked)
+		return -EBUSY;
+	if (CDROM_CAN(CDC_LOCK)) {
+		int ret = cdi->ops->lock_door(cdi, 0);
+		if (ret)
 			return ret;
-		sanitize_format(&ms_info.addr, &ms_info.addr_format,
-				requested_format);
-		IOCTL_OUT(arg, struct cdrom_multisession, ms_info);
-		cdinfo(CD_DO_IOCTL, "CDROMMULTISESSION successful\n"); 
-		return 0;
-		}
+	}
 
-	case CDROMEJECT: {
-		cdinfo(CD_DO_IOCTL, "entering CDROMEJECT\n"); 
-		if (!CDROM_CAN(CDC_OPEN_TRAY))
-			return -ENOSYS;
-		if (cdi->use_count != 1 || keeplocked)
-			return -EBUSY;
-		if (CDROM_CAN(CDC_LOCK))
-			if ((ret=cdo->lock_door(cdi, 0)))
-				return ret;
+	return cdi->ops->tray_move(cdi, 1);
+}
 
-		return cdo->tray_move(cdi, 1);
-		}
+static int cdrom_ioctl_closetray(struct cdrom_device_info *cdi)
+{
+	cdinfo(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n");
 
-	case CDROMCLOSETRAY: {
-		cdinfo(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n"); 
-		if (!CDROM_CAN(CDC_CLOSE_TRAY))
-			return -ENOSYS;
-		return cdo->tray_move(cdi, 0);
-		}
+	if (!CDROM_CAN(CDC_CLOSE_TRAY))
+		return -ENOSYS;
+	return cdi->ops->tray_move(cdi, 0);
+}
 
-	case CDROMEJECT_SW: {
-		cdinfo(CD_DO_IOCTL, "entering CDROMEJECT_SW\n"); 
-		if (!CDROM_CAN(CDC_OPEN_TRAY))
-			return -ENOSYS;
-		if (keeplocked)
-			return -EBUSY;
-		cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT);
-		if (arg)
-			cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT;
-		return 0;
-		}
+static int cdrom_ioctl_eject_sw(struct cdrom_device_info *cdi,
+		unsigned long arg)
+{
+	cdinfo(CD_DO_IOCTL, "entering CDROMEJECT_SW\n");
+
+	if (!CDROM_CAN(CDC_OPEN_TRAY))
+		return -ENOSYS;
+	if (keeplocked)
+		return -EBUSY;
 
-	case CDROM_MEDIA_CHANGED: {
-		struct cdrom_changer_info *info;
-		int changed;
+	cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT);
+	if (arg)
+		cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT;
+	return 0;
+}
+
+static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi,
+		unsigned long arg)
+{
+	struct cdrom_changer_info *info;
+	int ret;
+
+	cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n");
+
+	if (!CDROM_CAN(CDC_MEDIA_CHANGED))
+		return -ENOSYS;
+
+	/* cannot select disc or select current disc */
+	if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT)
+		return media_changed(cdi, 1);
+
+	if ((unsigned int)arg >= cdi->capacity)
+		return -EINVAL;
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	ret = cdrom_read_mech_status(cdi, info);
+	if (!ret)
+		ret = info->slots[arg].change;
+	kfree(info);
+	return ret;
+}
 
-		cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n"); 
-		if (!CDROM_CAN(CDC_MEDIA_CHANGED))
+static int cdrom_ioctl_set_options(struct cdrom_device_info *cdi,
+		unsigned long arg)
+{
+	cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n");
+
+	/*
+	 * Options need to be in sync with capability.
+	 * Too late for that, so we have to check each one separately.
+	 */
+	switch (arg) {
+	case CDO_USE_FFLAGS:
+	case CDO_CHECK_TYPE:
+		break;
+	case CDO_LOCK:
+		if (!CDROM_CAN(CDC_LOCK))
 			return -ENOSYS;
+		break;
+	case 0:
+		return cdi->options;
+	/* default is basically CDO_[AUTO_CLOSE|AUTO_EJECT] */
+	default:
+		if (!CDROM_CAN(arg))
+			return -ENOSYS;
+	}
+	cdi->options |= (int) arg;
+	return cdi->options;
+}
 
-		/* cannot select disc or select current disc */
-		if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT)
-			return media_changed(cdi, 1);
+static int cdrom_ioctl_clear_options(struct cdrom_device_info *cdi,
+		unsigned long arg)
+{
+	cdinfo(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n");
+
+	cdi->options &= ~(int) arg;
+	return cdi->options;
+}
+
+static int cdrom_ioctl_select_speed(struct cdrom_device_info *cdi,
+		unsigned long arg)
+{
+	cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n");
 
-		if ((unsigned int)arg >= cdi->capacity)
+	if (!CDROM_CAN(CDC_SELECT_SPEED))
+		return -ENOSYS;
+	return cdi->ops->select_speed(cdi, arg);
+}
+
+static int cdrom_ioctl_select_disc(struct cdrom_device_info *cdi,
+		unsigned long arg)
+{
+	cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n");
+
+	if (!CDROM_CAN(CDC_SELECT_DISC))
+		return -ENOSYS;
+
+	if (arg != CDSL_CURRENT && arg != CDSL_NONE) {
+		if ((int)arg >= cdi->capacity)
 			return -EINVAL;
+	}
 
-		info = kmalloc(sizeof(*info), GFP_KERNEL);
-		if (!info)
-			return -ENOMEM;
+	/*
+	 * ->select_disc is a hook to allow a driver-specific way of
+	 * seleting disc.  However, since there is no equivalent hook for
+	 * cdrom_slot_status this may not actually be useful...
+	 */
+	if (cdi->ops->select_disc)
+		return cdi->ops->select_disc(cdi, arg);
 
-		if ((ret = cdrom_read_mech_status(cdi, info))) {
-			kfree(info);
-			return ret;
-		}
+	cdinfo(CD_CHANGER, "Using generic cdrom_select_disc()\n");
+	return cdrom_select_disc(cdi, arg);
+}
 
-		changed = info->slots[arg].change;
-		kfree(info);
-		return changed;
-		}
+static int cdrom_ioctl_reset(struct cdrom_device_info *cdi,
+		struct block_device *bdev)
+{
+	cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n");
 
-	case CDROM_SET_OPTIONS: {
-		cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n"); 
-		/* options need to be in sync with capability. too late for
-		   that, so we have to check each one separately... */
-		switch (arg) {
-		case CDO_USE_FFLAGS:
-		case CDO_CHECK_TYPE:
-			break;
-		case CDO_LOCK:
-			if (!CDROM_CAN(CDC_LOCK))
-				return -ENOSYS;
-			break;
-		case 0:
-			return cdi->options;
-		/* default is basically CDO_[AUTO_CLOSE|AUTO_EJECT] */
-		default:
-			if (!CDROM_CAN(arg))
-				return -ENOSYS;
-		}
-		cdi->options |= (int) arg;
-		return cdi->options;
-		}
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	if (!CDROM_CAN(CDC_RESET))
+		return -ENOSYS;
+	invalidate_bdev(bdev, 0);
+	return cdi->ops->reset(cdi);
+}
 
-	case CDROM_CLEAR_OPTIONS: {
-		cdinfo(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n"); 
-		cdi->options &= ~(int) arg;
-		return cdi->options;
-		}
+static int cdrom_ioctl_lock_door(struct cdrom_device_info *cdi,
+		unsigned long arg)
+{
+	cdinfo(CD_DO_IOCTL, "%socking door.\n", arg ? "L" : "Unl");
 
-	case CDROM_SELECT_SPEED: {
-		cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n"); 
-		if (!CDROM_CAN(CDC_SELECT_SPEED))
-			return -ENOSYS;
-		return cdo->select_speed(cdi, arg);
-		}
+	if (!CDROM_CAN(CDC_LOCK))
+		return -EDRIVE_CANT_DO_THIS;
 
-	case CDROM_SELECT_DISC: {
-		cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n"); 
-		if (!CDROM_CAN(CDC_SELECT_DISC))
-			return -ENOSYS;
+	keeplocked = arg ? 1 : 0;
 
-                if ((arg != CDSL_CURRENT) && (arg != CDSL_NONE))
-			if ((int)arg >= cdi->capacity)
-				return -EINVAL;
-
-		/* cdo->select_disc is a hook to allow a driver-specific
-		 * way of seleting disc.  However, since there is no
-		 * equiv hook for cdrom_slot_status this may not 
-		 * actually be useful...
-		 */
-		if (cdo->select_disc != NULL)
-			return cdo->select_disc(cdi, arg);
-
-		/* no driver specific select_disc(), call our own */
-		cdinfo(CD_CHANGER, "Using generic cdrom_select_disc()\n"); 
-		return cdrom_select_disc(cdi, arg);
-		}
-
-	case CDROMRESET: {
-		if (!capable(CAP_SYS_ADMIN))
-			return -EACCES;
-		cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n");
-		if (!CDROM_CAN(CDC_RESET))
-			return -ENOSYS;
-		invalidate_bdev(ip->i_bdev, 0);
-		return cdo->reset(cdi);
-		}
+	/*
+	 * Don't unlock the door on multiple opens by default, but allow
+	 * root to do so.
+	 */
+	if (cdi->use_count != 1 && !arg && !capable(CAP_SYS_ADMIN))
+		return -EBUSY;
+	return cdi->ops->lock_door(cdi, arg);
+}
 
-	case CDROM_LOCKDOOR: {
-		cdinfo(CD_DO_IOCTL, "%socking door.\n", arg ? "L" : "Unl");
-		if (!CDROM_CAN(CDC_LOCK))
-			return -EDRIVE_CANT_DO_THIS;
-		keeplocked = arg ? 1 : 0;
-		/* don't unlock the door on multiple opens,but allow root
-		 * to do so */
-		if ((cdi->use_count != 1) && !arg && !capable(CAP_SYS_ADMIN))
-			return -EBUSY;
-		return cdo->lock_door(cdi, arg);
-		}
+static int cdrom_ioctl_debug(struct cdrom_device_info *cdi,
+		unsigned long arg)
+{
+	cdinfo(CD_DO_IOCTL, "%sabling debug.\n", arg ? "En" : "Dis");
 
-	case CDROM_DEBUG: {
-		if (!capable(CAP_SYS_ADMIN))
-			return -EACCES;
-		cdinfo(CD_DO_IOCTL, "%sabling debug.\n", arg ? "En" : "Dis");
-		debug = arg ? 1 : 0;
-		return debug;
-		}
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	debug = arg ? 1 : 0;
+	return debug;
+}
 
-	case CDROM_GET_CAPABILITY: {
-		cdinfo(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n");
-		return (cdo->capability & ~cdi->mask);
-		}
+static int cdrom_ioctl_get_capability(struct cdrom_device_info *cdi)
+{
+	cdinfo(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n");
+	return (cdi->ops->capability & ~cdi->mask);
+}
 
-/* The following function is implemented, although very few audio
+/*
+ * The following function is implemented, although very few audio
  * discs give Universal Product Code information, which should just be
  * the Medium Catalog Number on the box.  Note, that the way the code
  * is written on the CD is /not/ uniform across all discs!
  */
-	case CDROM_GET_MCN: {
-		struct cdrom_mcn mcn;
-		cdinfo(CD_DO_IOCTL, "entering CDROM_GET_MCN\n"); 
-		if (!(cdo->capability & CDC_MCN))
-			return -ENOSYS;
-		if ((ret=cdo->get_mcn(cdi, &mcn)))
-			return ret;
-		IOCTL_OUT(arg, struct cdrom_mcn, mcn);
-		cdinfo(CD_DO_IOCTL, "CDROM_GET_MCN successful\n"); 
-		return 0;
-		}
+static int cdrom_ioctl_get_mcn(struct cdrom_device_info *cdi,
+		void __user *argp)
+{
+	struct cdrom_mcn mcn;
+	int ret;
 
-	case CDROM_DRIVE_STATUS: {
-		cdinfo(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n"); 
-		if (!(cdo->capability & CDC_DRIVE_STATUS))
-			return -ENOSYS;
-		if (!CDROM_CAN(CDC_SELECT_DISC))
-			return cdo->drive_status(cdi, CDSL_CURRENT);
-                if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE)) 
-			return cdo->drive_status(cdi, CDSL_CURRENT);
-		if (((int)arg >= cdi->capacity))
-			return -EINVAL;
-		return cdrom_slot_status(cdi, arg);
-		}
+	cdinfo(CD_DO_IOCTL, "entering CDROM_GET_MCN\n");
 
-	/* Ok, this is where problems start.  The current interface for the
-	   CDROM_DISC_STATUS ioctl is flawed.  It makes the false assumption
-	   that CDs are all CDS_DATA_1 or all CDS_AUDIO, etc.  Unfortunatly,
-	   while this is often the case, it is also very common for CDs to
-	   have some tracks with data, and some tracks with audio.  Just 
-	   because I feel like it, I declare the following to be the best
-	   way to cope.  If the CD has ANY data tracks on it, it will be
-	   returned as a data CD.  If it has any XA tracks, I will return
-	   it as that.  Now I could simplify this interface by combining these 
-	   returns with the above, but this more clearly demonstrates
-	   the problem with the current interface.  Too bad this wasn't 
-	   designed to use bitmasks...         -Erik 
-
-	   Well, now we have the option CDS_MIXED: a mixed-type CD. 
-	   User level programmers might feel the ioctl is not very useful.
-	   					---david
-	*/
-	case CDROM_DISC_STATUS: {
-		tracktype tracks;
-		cdinfo(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n"); 
-		cdrom_count_tracks(cdi, &tracks);
-		if (tracks.error) 
-			return(tracks.error);
-
-		/* Policy mode on */
-		if (tracks.audio > 0) {
-			if (tracks.data==0 && tracks.cdi==0 && tracks.xa==0) 
-				return CDS_AUDIO;
-			else
-				return CDS_MIXED;
-		}
-		if (tracks.cdi > 0) return CDS_XA_2_2;
-		if (tracks.xa > 0) return CDS_XA_2_1;
-		if (tracks.data > 0) return CDS_DATA_1;
-		/* Policy mode off */
+	if (!(cdi->ops->capability & CDC_MCN))
+		return -ENOSYS;
+	ret = cdi->ops->get_mcn(cdi, &mcn);
+	if (ret)
+		return ret;
 
-		cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognize!\n");
-		return CDS_NO_INFO;
-		}
+	if (copy_to_user(argp, &mcn, sizeof(mcn)))
+		return -EFAULT;
+	cdinfo(CD_DO_IOCTL, "CDROM_GET_MCN successful\n");
+	return 0;
+}
 
-	case CDROM_CHANGER_NSLOTS: {
-		cdinfo(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n"); 
-		return cdi->capacity;
-		}
+static int cdrom_ioctl_drive_status(struct cdrom_device_info *cdi,
+		unsigned long arg)
+{
+	cdinfo(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n");
+
+	if (!(cdi->ops->capability & CDC_DRIVE_STATUS))
+		return -ENOSYS;
+	if (!CDROM_CAN(CDC_SELECT_DISC) ||
+	    (arg == CDSL_CURRENT || arg == CDSL_NONE))
+		return cdi->ops->drive_status(cdi, CDSL_CURRENT);
+	if (((int)arg >= cdi->capacity))
+		return -EINVAL;
+	return cdrom_slot_status(cdi, arg);
+}
+
+/*
+ * Ok, this is where problems start.  The current interface for the
+ * CDROM_DISC_STATUS ioctl is flawed.  It makes the false assumption that
+ * CDs are all CDS_DATA_1 or all CDS_AUDIO, etc.  Unfortunatly, while this
+ * is often the case, it is also very common for CDs to have some tracks
+ * with data, and some tracks with audio.  Just because I feel like it,
+ * I declare the following to be the best way to cope.  If the CD has ANY
+ * data tracks on it, it will be returned as a data CD.  If it has any XA
+ * tracks, I will return it as that.  Now I could simplify this interface
+ * by combining these  returns with the above, but this more clearly
+ * demonstrates the problem with the current interface.  Too bad this
+ * wasn't designed to use bitmasks...         -Erik
+ *
+ * Well, now we have the option CDS_MIXED: a mixed-type CD.
+ * User level programmers might feel the ioctl is not very useful.
+ *					---david
+ */
+static int cdrom_ioctl_disc_status(struct cdrom_device_info *cdi)
+{
+	tracktype tracks;
+
+	cdinfo(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n");
+
+	cdrom_count_tracks(cdi, &tracks);
+	if (tracks.error)
+		return tracks.error;
+
+	/* Policy mode on */
+	if (tracks.audio > 0) {
+		if (!tracks.data && !tracks.cdi && !tracks.xa)
+			return CDS_AUDIO;
+		else
+			return CDS_MIXED;
 	}
 
-	/* use the ioctls that are implemented through the generic_packet()
-	   interface. this may look at bit funny, but if -ENOTTY is
-	   returned that particular ioctl is not implemented and we
-	   let it go through the device specific ones. */
+	if (tracks.cdi > 0)
+		return CDS_XA_2_2;
+	if (tracks.xa > 0)
+		return CDS_XA_2_1;
+	if (tracks.data > 0)
+		return CDS_DATA_1;
+	/* Policy mode off */
+
+	cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognize!\n");
+	return CDS_NO_INFO;
+}
+
+static int cdrom_ioctl_changer_nslots(struct cdrom_device_info *cdi)
+{
+	cdinfo(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n");
+	return cdi->capacity;
+}
+
+static int cdrom_ioctl_get_subchnl(struct cdrom_device_info *cdi,
+		void __user *argp)
+{
+	struct cdrom_subchnl q;
+	u8 requested, back;
+	int ret;
+
+	/* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/
+
+	if (!CDROM_CAN(CDC_PLAY_AUDIO))
+		return -ENOSYS;
+	if (copy_from_user(&q, argp, sizeof(q)))
+		return -EFAULT;
+
+	requested = q.cdsc_format;
+	if (requested != CDROM_MSF && requested != CDROM_LBA)
+		return -EINVAL;
+	q.cdsc_format = CDROM_MSF;
+
+	ret = cdi->ops->audio_ioctl(cdi, CDROMSUBCHNL, &q);
+	if (ret)
+		return ret;
+
+	back = q.cdsc_format; /* local copy */
+	sanitize_format(&q.cdsc_absaddr, &back, requested);
+	sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested);
+
+	if (copy_to_user(argp, &q, sizeof(q)))
+		return -EFAULT;
+	/* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */
+	return 0;
+}
+
+static int cdrom_ioctl_read_tochdr(struct cdrom_device_info *cdi,
+		void __user *argp)
+{
+	struct cdrom_tochdr header;
+	int ret;
+
+	/* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */
+
+	if (!CDROM_CAN(CDC_PLAY_AUDIO))
+		return -ENOSYS;
+	if (copy_from_user(&header, argp, sizeof(header)))
+		return -EFAULT;
+
+	ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header);
+	if (ret)
+		return ret;
+
+	if (copy_to_user(argp, &header, sizeof(header)))
+		return -EFAULT;
+	/* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */
+	return 0;
+}
+
+static int cdrom_ioctl_read_tocentry(struct cdrom_device_info *cdi,
+		void __user *argp)
+{
+	struct cdrom_tocentry entry;
+	u8 requested_format;
+	int ret;
+
+	/* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */
+
+	if (!CDROM_CAN(CDC_PLAY_AUDIO))
+		return -ENOSYS;
+	if (copy_from_user(&entry, argp, sizeof(entry)))
+		return -EFAULT;
+
+	requested_format = entry.cdte_format;
+	if (requested_format != CDROM_MSF && requested_format != CDROM_LBA)
+		return -EINVAL;
+	/* make interface to low-level uniform */
+	entry.cdte_format = CDROM_MSF;
+	ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry);
+	if (ret)
+		return ret;
+	sanitize_format(&entry.cdte_addr, &entry.cdte_format, requested_format);
+
+	if (copy_to_user(argp, &entry, sizeof(entry)))
+		return -EFAULT;
+	/* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */
+	return 0;
+}
+
+static int cdrom_ioctl_play_msf(struct cdrom_device_info *cdi,
+		void __user *argp)
+{
+	struct cdrom_msf msf;
+
+	cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");
+
+	if (!CDROM_CAN(CDC_PLAY_AUDIO))
+		return -ENOSYS;
+	if (copy_from_user(&msf, argp, sizeof(msf)))
+		return -EFAULT;
+	return cdi->ops->audio_ioctl(cdi, CDROMPLAYMSF, &msf);
+}
+
+static int cdrom_ioctl_play_trkind(struct cdrom_device_info *cdi,
+		void __user *argp)
+{
+	struct cdrom_ti ti;
+	int ret;
+
+	cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n");
+
+	if (!CDROM_CAN(CDC_PLAY_AUDIO))
+		return -ENOSYS;
+	if (copy_from_user(&ti, argp, sizeof(ti)))
+		return -EFAULT;
+
+	ret = check_for_audio_disc(cdi, cdi->ops);
+	if (ret)
+		return ret;
+	return cdi->ops->audio_ioctl(cdi, CDROMPLAYTRKIND, &ti);
+}
+static int cdrom_ioctl_volctrl(struct cdrom_device_info *cdi,
+		void __user *argp)
+{
+	struct cdrom_volctrl volume;
+
+	cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n");
+
+	if (!CDROM_CAN(CDC_PLAY_AUDIO))
+		return -ENOSYS;
+	if (copy_from_user(&volume, argp, sizeof(volume)))
+		return -EFAULT;
+	return cdi->ops->audio_ioctl(cdi, CDROMVOLCTRL, &volume);
+}
+
+static int cdrom_ioctl_volread(struct cdrom_device_info *cdi,
+		void __user *argp)
+{
+	struct cdrom_volctrl volume;
+	int ret;
+
+	cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n");
+
+	if (!CDROM_CAN(CDC_PLAY_AUDIO))
+		return -ENOSYS;
+
+	ret = cdi->ops->audio_ioctl(cdi, CDROMVOLREAD, &volume);
+	if (ret)
+		return ret;
+
+	if (copy_to_user(argp, &volume, sizeof(volume)))
+		return -EFAULT;
+	return 0;
+}
+
+static int cdrom_ioctl_audioctl(struct cdrom_device_info *cdi,
+		unsigned int cmd)
+{
+	int ret;
+
+	cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n");
+
+	if (!CDROM_CAN(CDC_PLAY_AUDIO))
+		return -ENOSYS;
+	ret = check_for_audio_disc(cdi, cdi->ops);
+	if (ret)
+		return ret;
+	return cdi->ops->audio_ioctl(cdi, cmd, NULL);
+}
+
+/*
+ * Just about every imaginable ioctl is supported in the Uniform layer
+ * these days.
+ * ATAPI / SCSI specific code now mainly resides in mmc_ioctl().
+ */
+int cdrom_ioctl(struct file * file, struct cdrom_device_info *cdi,
+		struct inode *ip, unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int ret;
+
+	/*
+	 * Try the generic SCSI command ioctl's first.
+	 */
+	ret = scsi_cmd_ioctl(file, ip->i_bdev->bd_disk, cmd, argp);
+	if (ret != -ENOTTY)
+		return ret;
+
+	switch (cmd) {
+	case CDROMMULTISESSION:
+		return cdrom_ioctl_multisession(cdi, argp);
+	case CDROMEJECT:
+		return cdrom_ioctl_eject(cdi);
+	case CDROMCLOSETRAY:
+		return cdrom_ioctl_closetray(cdi);
+	case CDROMEJECT_SW:
+		return cdrom_ioctl_eject_sw(cdi, arg);
+	case CDROM_MEDIA_CHANGED:
+		return cdrom_ioctl_media_changed(cdi, arg);
+	case CDROM_SET_OPTIONS:
+		return cdrom_ioctl_set_options(cdi, arg);
+	case CDROM_CLEAR_OPTIONS:
+		return cdrom_ioctl_clear_options(cdi, arg);
+	case CDROM_SELECT_SPEED:
+		return cdrom_ioctl_select_speed(cdi, arg);
+	case CDROM_SELECT_DISC:
+		return cdrom_ioctl_select_disc(cdi, arg);
+	case CDROMRESET:
+		return cdrom_ioctl_reset(cdi, ip->i_bdev);
+	case CDROM_LOCKDOOR:
+		return cdrom_ioctl_lock_door(cdi, arg);
+	case CDROM_DEBUG:
+		return cdrom_ioctl_debug(cdi, arg);
+	case CDROM_GET_CAPABILITY:
+		return cdrom_ioctl_get_capability(cdi);
+	case CDROM_GET_MCN:
+		return cdrom_ioctl_get_mcn(cdi, argp);
+	case CDROM_DRIVE_STATUS:
+		return cdrom_ioctl_drive_status(cdi, arg);
+	case CDROM_DISC_STATUS:
+		return cdrom_ioctl_disc_status(cdi);
+	case CDROM_CHANGER_NSLOTS:
+		return cdrom_ioctl_changer_nslots(cdi);
+	}
+
+	/*
+	 * Use the ioctls that are implemented through the generic_packet()
+	 * interface. this may look at bit funny, but if -ENOTTY is
+	 * returned that particular ioctl is not implemented and we
+	 * let it go through the device specific ones.
+	 */
 	if (CDROM_CAN(CDC_GENERIC_PACKET)) {
 		ret = mmc_ioctl(cdi, cmd, arg);
-		if (ret != -ENOTTY) {
+		if (ret != -ENOTTY)
 			return ret;
-		}
 	}
 
-	/* note: most of the cdinfo() calls are commented out here,
-	   because they fill up the sys log when CD players poll
-	   the drive. */
+	/*
+	 * Note: most of the cdinfo() calls are commented out here,
+	 * because they fill up the sys log when CD players poll
+	 * the drive.
+	 */
 	switch (cmd) {
-	case CDROMSUBCHNL: {
-		struct cdrom_subchnl q;
-		u_char requested, back;
-		if (!CDROM_CAN(CDC_PLAY_AUDIO))
-			return -ENOSYS;
-		/* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/ 
-		IOCTL_IN(arg, struct cdrom_subchnl, q);
-		requested = q.cdsc_format;
-		if (!((requested == CDROM_MSF) ||
-		      (requested == CDROM_LBA)))
-			return -EINVAL;
-		q.cdsc_format = CDROM_MSF;
-		if ((ret=cdo->audio_ioctl(cdi, cmd, &q)))
-			return ret;
-		back = q.cdsc_format; /* local copy */
-		sanitize_format(&q.cdsc_absaddr, &back, requested);
-		sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested);
-		IOCTL_OUT(arg, struct cdrom_subchnl, q);
-		/* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ 
-		return 0;
-		}
-	case CDROMREADTOCHDR: {
-		struct cdrom_tochdr header;
-		if (!CDROM_CAN(CDC_PLAY_AUDIO))
-			return -ENOSYS;
-		/* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */ 
-		IOCTL_IN(arg, struct cdrom_tochdr, header);
-		if ((ret=cdo->audio_ioctl(cdi, cmd, &header)))
-			return ret;
-		IOCTL_OUT(arg, struct cdrom_tochdr, header);
-		/* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */ 
-		return 0;
-		}
-	case CDROMREADTOCENTRY: {
-		struct cdrom_tocentry entry;
-		u_char requested_format;
-		if (!CDROM_CAN(CDC_PLAY_AUDIO))
-			return -ENOSYS;
-		/* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */ 
-		IOCTL_IN(arg, struct cdrom_tocentry, entry);
-		requested_format = entry.cdte_format;
-		if (!((requested_format == CDROM_MSF) || 
-			(requested_format == CDROM_LBA)))
-				return -EINVAL;
-		/* make interface to low-level uniform */
-		entry.cdte_format = CDROM_MSF;
-		if ((ret=cdo->audio_ioctl(cdi, cmd, &entry)))
-			return ret;
-		sanitize_format(&entry.cdte_addr,
-		&entry.cdte_format, requested_format);
-		IOCTL_OUT(arg, struct cdrom_tocentry, entry);
-		/* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */ 
-		return 0;
-		}
-	case CDROMPLAYMSF: {
-		struct cdrom_msf msf;
-		if (!CDROM_CAN(CDC_PLAY_AUDIO))
-			return -ENOSYS;
-		cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); 
-		IOCTL_IN(arg, struct cdrom_msf, msf);
-		return cdo->audio_ioctl(cdi, cmd, &msf);
-		}
-	case CDROMPLAYTRKIND: {
-		struct cdrom_ti ti;
-		if (!CDROM_CAN(CDC_PLAY_AUDIO))
-			return -ENOSYS;
-		cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); 
-		IOCTL_IN(arg, struct cdrom_ti, ti);
-		CHECKAUDIO;
-		return cdo->audio_ioctl(cdi, cmd, &ti);
-		}
-	case CDROMVOLCTRL: {
-		struct cdrom_volctrl volume;
-		if (!CDROM_CAN(CDC_PLAY_AUDIO))
-			return -ENOSYS;
-		cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n"); 
-		IOCTL_IN(arg, struct cdrom_volctrl, volume);
-		return cdo->audio_ioctl(cdi, cmd, &volume);
-		}
-	case CDROMVOLREAD: {
-		struct cdrom_volctrl volume;
-		if (!CDROM_CAN(CDC_PLAY_AUDIO))
-			return -ENOSYS;
-		cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n"); 
-		if ((ret=cdo->audio_ioctl(cdi, cmd, &volume)))
-			return ret;
-		IOCTL_OUT(arg, struct cdrom_volctrl, volume);
-		return 0;
-		}
+	case CDROMSUBCHNL:
+		return cdrom_ioctl_get_subchnl(cdi, argp);
+	case CDROMREADTOCHDR:
+		return cdrom_ioctl_read_tochdr(cdi, argp);
+	case CDROMREADTOCENTRY:
+		return cdrom_ioctl_read_tocentry(cdi, argp);
+	case CDROMPLAYMSF:
+		return cdrom_ioctl_play_msf(cdi, argp);
+	case CDROMPLAYTRKIND:
+		return cdrom_ioctl_play_trkind(cdi, argp);
+	case CDROMVOLCTRL:
+		return cdrom_ioctl_volctrl(cdi, argp);
+	case CDROMVOLREAD:
+		return cdrom_ioctl_volread(cdi, argp);
 	case CDROMSTART:
 	case CDROMSTOP:
 	case CDROMPAUSE:
-	case CDROMRESUME: {
-		if (!CDROM_CAN(CDC_PLAY_AUDIO))
-			return -ENOSYS;
-		cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n"); 
-		CHECKAUDIO;
-		return cdo->audio_ioctl(cdi, cmd, NULL);
-		}
-	} /* switch */
+	case CDROMRESUME:
+		return cdrom_ioctl_audioctl(cdi, cmd);
+	}
 
-	/* do the device specific ioctls */
+	/*
+	 * Finally, do the device specific ioctls
+	 */
 	if (CDROM_CAN(CDC_IOCTLS))
-		return cdo->dev_ioctl(cdi, cmd, arg);
-	
+		return cdi->ops->dev_ioctl(cdi, cmd, arg);
+
 	return -ENOSYS;
 }
 
@@ -2772,7 +2969,7 @@
 		   how much data is available for transfer. buffer[1] is
 		   unfortunately ambigious and the only reliable way seem
 		   to be to simply skip over the block descriptor... */
-		offset = 8 + be16_to_cpu(*(unsigned short *)(buffer+6));
+		offset = 8 + be16_to_cpu(*(__be16 *)(buffer+6));
 
 		if (offset + 16 > sizeof(buffer))
 			return -E2BIG;
diff -urN oldtree/drivers/char/Kconfig newtree/drivers/char/Kconfig
--- oldtree/drivers/char/Kconfig	2006-02-19 11:41:01.101175696 +0000
+++ newtree/drivers/char/Kconfig	2006-02-21 15:58:36.263633648 +0000
@@ -153,7 +153,7 @@
 
 config ESPSERIAL
 	tristate "Hayes ESP serial port support"
-	depends on SERIAL_NONSTANDARD && ISA && ISA_DMA_API
+	depends on SERIAL_NONSTANDARD && ISA && ISA_DMA_API && (BROKEN || !PPC)
 	help
 	  This is a driver which supports Hayes ESP serial ports.  Both single
 	  port cards and multiport cards are supported.  Make sure to read
@@ -695,7 +695,7 @@
 
 config RTC
 	tristate "Enhanced Real Time Clock Support"
-	depends on !PPC32 && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV
+	depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV
 	---help---
 	  If you say Y here and create a character special file /dev/rtc with
 	  major number 10 and minor number 135 using mknod ("man mknod"), you
diff -urN oldtree/drivers/char/agp/Kconfig newtree/drivers/char/agp/Kconfig
--- oldtree/drivers/char/agp/Kconfig	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/char/agp/Kconfig	2006-02-21 15:58:11.086461160 +0000
@@ -15,22 +15,23 @@
 	  due to kernel allocation issues), you could use PCI accesses
 	  and have up to a couple gigs of texture space.
 
-	  Note that this is the only means to have XFree4/GLX use
+	  Note that this is the only means to have X/GLX use
 	  write-combining with MTRR support on the AGP bus. Without it, OpenGL
 	  direct rendering will be a lot slower but still faster than PIO.
 
-	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
-	  use GLX or DRI.  If unsure, say N.
-
 	  To compile this driver as a module, choose M here: the
 	  module will be called agpgart.
 
+	  You should say Y here if you want to use GLX or DRI.
+
+	  If unsure, say N.
+
 config AGP_ALI
 	tristate "ALI chipset support"
 	depends on AGP && X86_32
 	---help---
 	  This option gives you AGP support for the GLX component of
-	  XFree86 4.x on the following ALi chipsets.  The supported chipsets
+	  X on the following ALi chipsets.  The supported chipsets
 	  include M1541, M1621, M1631, M1632, M1641,M1647,and M1651.
 	  For the ALi-chipset question, ALi suggests you refer to
 	  <http://www.ali.com.tw/eng/support/index.shtml>.
@@ -40,28 +41,19 @@
 	  timing issues, this chipset cannot do AGP 2x with the G200.
 	  This is a hardware limitation. AGP 1x seems to be fine, though.
 
-	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
-	  use GLX or DRI.  If unsure, say N.
-
 config AGP_ATI
 	tristate "ATI chipset support"
 	depends on AGP && X86_32
 	---help---
-      This option gives you AGP support for the GLX component of
-      XFree86 4.x on the ATI RadeonIGP family of chipsets.
-
-      You should say Y here if you use XFree86 3.3.6 or 4.x and want to
-      use GLX or DRI.  If unsure, say N.
+	  This option gives you AGP support for the GLX component of
+	  X on the ATI RadeonIGP family of chipsets.
 
 config AGP_AMD
 	tristate "AMD Irongate, 761, and 762 chipset support"
 	depends on AGP && X86_32
 	help
 	  This option gives you AGP support for the GLX component of
-	  XFree86 4.x on AMD Irongate, 761, and 762 chipsets.
-
-	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
-	  use GLX or DRI.  If unsure, say N.
+	  X on AMD Irongate, 761, and 762 chipsets.
 
 config AGP_AMD64
 	tristate "AMD Opteron/Athlon64 on-CPU GART support" if !GART_IOMMU
@@ -69,45 +61,38 @@
 	default y if GART_IOMMU
 	help
 	  This option gives you AGP support for the GLX component of
-	  XFree86 4.x using the on-CPU northbridge of the AMD Athlon64/Opteron CPUs.
+	  X using the on-CPU northbridge of the AMD Athlon64/Opteron CPUs.
 	  You still need an external AGP bridge like the AMD 8151, VIA
           K8T400M, SiS755. It may also support other AGP bridges when loaded
 	  with agp_try_unsupported=1.
-	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
-	  use GLX or DRI.  If unsure, say Y
 
 config AGP_INTEL
 	tristate "Intel 440LX/BX/GX, I8xx and E7x05 chipset support"
 	depends on AGP && X86
 	help
-	  This option gives you AGP support for the GLX component of XFree86 4.x
+	  This option gives you AGP support for the GLX component of X
 	  on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850, 860, 875,
-	  E7205 and E7505 chipsets and full support for the 810, 815, 830M, 845G,
-	  852GM, 855GM, 865G and I915 integrated graphics chipsets.
+	  E7205 and E7505 chipsets and full support for the 810, 815, 830M,
+	  845G, 852GM, 855GM, 865G and I915 integrated graphics chipsets.
+
 
-	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
-	  use GLX or DRI, or if you have any Intel integrated graphics
-	  chipsets.  If unsure, say Y.
 
 config AGP_NVIDIA
 	tristate "NVIDIA nForce/nForce2 chipset support"
 	depends on AGP && X86_32
 	help
 	  This option gives you AGP support for the GLX component of
-	  XFree86 4.x on the following NVIDIA chipsets.  The supported chipsets
-	  include nForce and nForce2
+	  X on NVIDIA chipsets including nForce and nForce2
 
 config AGP_SIS
 	tristate "SiS chipset support"
 	depends on AGP && X86_32
 	help
 	  This option gives you AGP support for the GLX component of
-	  XFree86 4.x on Silicon Integrated Systems [SiS] chipsets.
+	  X on Silicon Integrated Systems [SiS] chipsets.
 
 	  Note that 5591/5592 AGP chipsets are NOT supported.
 
-	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
-	  use GLX or DRI.  If unsure, say N.
 
 config AGP_SWORKS
 	tristate "Serverworks LE/HE chipset support"
@@ -121,10 +106,7 @@
 	depends on AGP && X86_32
 	help
 	  This option gives you AGP support for the GLX component of
-	  XFree86 4.x on VIA MVP3/Apollo Pro chipsets.
-
-	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
-	  use GLX or DRI.  If unsure, say N.
+	  X on VIA MVP3/Apollo Pro chipsets.
 
 config AGP_I460
 	tristate "Intel 460GX chipset support"
@@ -159,9 +141,6 @@
 	  This option gives you AGP support for the Transmeta Efficeon
 	  series processors with integrated northbridges.
 
-	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
-	  use GLX or DRI.  If unsure, say Y.
-
 config AGP_SGI_TIOCA
         tristate "SGI TIO chipset AGP support"
         depends on AGP && (IA64_SGI_SN2 || IA64_GENERIC)
diff -urN oldtree/drivers/char/agp/sworks-agp.c newtree/drivers/char/agp/sworks-agp.c
--- oldtree/drivers/char/agp/sworks-agp.c	2006-02-19 11:41:01.105175088 +0000
+++ newtree/drivers/char/agp/sworks-agp.c	2006-02-21 15:58:11.092460248 +0000
@@ -468,9 +468,7 @@
 
 	switch (pdev->device) {
 	case 0x0006:
-		/* ServerWorks CNB20HE
-		Fail silently.*/
-		printk (KERN_ERR PFX "Detected ServerWorks CNB20HE chipset: No AGP present.\n");
+		printk (KERN_ERR PFX "ServerWorks CNB20HE is unsupported due to lack of documentation.\n");
 		return -ENODEV;
 
 	case PCI_DEVICE_ID_SERVERWORKS_HE:
diff -urN oldtree/drivers/char/drm/i915_irq.c newtree/drivers/char/drm/i915_irq.c
--- oldtree/drivers/char/drm/i915_irq.c	2006-02-19 11:41:01.331140736 +0000
+++ newtree/drivers/char/drm/i915_irq.c	2006-02-21 15:58:13.373113536 +0000
@@ -202,10 +202,15 @@
 void i915_driver_irq_uninstall(drm_device_t * dev)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	u16 temp;
+
 	if (!dev_priv)
 		return;
 
 	I915_WRITE16(I915REG_HWSTAM, 0xffff);
 	I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
 	I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
+
+	temp = I915_READ16(I915REG_INT_IDENTITY_R);
+	I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
 }
diff -urN oldtree/drivers/char/drm/r300_cmdbuf.c newtree/drivers/char/drm/r300_cmdbuf.c
--- oldtree/drivers/char/drm/r300_cmdbuf.c	2006-02-19 11:41:01.346138456 +0000
+++ newtree/drivers/char/drm/r300_cmdbuf.c	2006-02-21 15:58:13.379112624 +0000
@@ -161,6 +161,7 @@
 	ADD_RANGE(R300_VAP_PVS_CNTL_1, 3);
 	ADD_RANGE(R300_GB_ENABLE, 1);
 	ADD_RANGE(R300_GB_MSPOS0, 5);
+	ADD_RANGE(R300_TX_CNTL, 1);
 	ADD_RANGE(R300_TX_ENABLE, 1);
 	ADD_RANGE(0x4200, 4);
 	ADD_RANGE(0x4214, 1);
@@ -251,7 +252,7 @@
 	   This code is correct for now (does the same thing as the
 	   code that sets MC_FB_LOCATION) in radeon_cp.c */
 	if ((offset >= dev_priv->fb_location) &&
-	    (offset < dev_priv->gart_vm_start))
+	    (offset < dev_priv->fb_location + dev_priv->fb_size))
 		return 0;
 	if ((offset >= dev_priv->gart_vm_start) &&
 	    (offset < dev_priv->gart_vm_start + dev_priv->gart_size))
@@ -489,6 +490,52 @@
 
 	return 0;
 }
+static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
+					     drm_radeon_kcmd_buffer_t *cmdbuf)
+{
+	u32 *cmd = (u32 *) cmdbuf->buf;
+	int count, ret;
+	RING_LOCALS;
+
+	count=(cmd[0]>>16) & 0x3fff;
+
+	if (cmd[0] & 0x8000) {
+		u32 offset;
+
+		if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL 
+			      | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
+			offset = cmd[2] << 10;
+			ret = r300_check_offset(dev_priv, offset);
+			if (ret)
+			{
+				DRM_ERROR("Invalid bitblt first offset is %08X\n", offset);
+				return DRM_ERR(EINVAL);
+			}
+		}
+
+		if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
+		    (cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
+			offset = cmd[3] << 10;
+			ret = r300_check_offset(dev_priv, offset);
+			if (ret)
+			{
+				DRM_ERROR("Invalid bitblt second offset is %08X\n", offset);
+				return DRM_ERR(EINVAL);
+			}
+			
+		}
+	}
+
+	BEGIN_RING(count+2);
+	OUT_RING(cmd[0]);
+	OUT_RING_TABLE((int *)(cmdbuf->buf + 4), count + 1);
+	ADVANCE_RING();
+
+	cmdbuf->buf += (count+2)*4;
+	cmdbuf->bufsz -= (count+2)*4;
+
+	return 0;
+}
 
 static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
 					    drm_radeon_kcmd_buffer_t *cmdbuf)
@@ -527,6 +574,9 @@
 	case RADEON_3D_LOAD_VBPNTR:	/* load vertex array pointers */
 		return r300_emit_3d_load_vbpntr(dev_priv, cmdbuf, header);
 
+	case RADEON_CNTL_BITBLT_MULTI:
+		return r300_emit_bitblt_multi(dev_priv, cmdbuf);
+
 	case RADEON_CP_3D_DRAW_IMMD_2:	/* triggers drawing using in-packet vertex data */
 	case RADEON_CP_3D_DRAW_VBUF_2:	/* triggers drawing of vertex buffers setup elsewhere */
 	case RADEON_CP_3D_DRAW_INDX_2:	/* triggers drawing using indices to vertex buffer */
diff -urN oldtree/drivers/char/drm/r300_reg.h newtree/drivers/char/drm/r300_reg.h
--- oldtree/drivers/char/drm/r300_reg.h	2006-02-19 11:41:01.347138304 +0000
+++ newtree/drivers/char/drm/r300_reg.h	2006-02-21 15:58:13.389111104 +0000
@@ -451,6 +451,9 @@
 /* END */
 
 /* gap */
+/* Zero to flush caches. */
+#define R300_TX_CNTL                        0x4100
+
 /* The upper enable bits are guessed, based on fglrx reported limits. */
 #define R300_TX_ENABLE                      0x4104
 #       define R300_TX_ENABLE_0                  (1 << 0)
diff -urN oldtree/drivers/char/drm/radeon_cp.c newtree/drivers/char/drm/radeon_cp.c
--- oldtree/drivers/char/drm/radeon_cp.c	2006-02-19 11:41:01.349138000 +0000
+++ newtree/drivers/char/drm/radeon_cp.c	2006-02-21 15:58:13.391110800 +0000
@@ -1118,14 +1118,20 @@
 {
 	u32 ring_start, cur_read_ptr;
 	u32 tmp;
-
-	/* Initialize the memory controller */
-	RADEON_WRITE(RADEON_MC_FB_LOCATION,
-		     ((dev_priv->gart_vm_start - 1) & 0xffff0000)
-		     | (dev_priv->fb_location >> 16));
+	
+	/* Initialize the memory controller. With new memory map, the fb location
+	 * is not changed, it should have been properly initialized already. Part
+	 * of the problem is that the code below is bogus, assuming the GART is
+	 * always appended to the fb which is not necessarily the case
+	 */
+	if (!dev_priv->new_memmap)
+		RADEON_WRITE(RADEON_MC_FB_LOCATION,
+			     ((dev_priv->gart_vm_start - 1) & 0xffff0000)
+			     | (dev_priv->fb_location >> 16));
 
 #if __OS_HAS_AGP
 	if (dev_priv->flags & CHIP_IS_AGP) {
+		RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base);
 		RADEON_WRITE(RADEON_MC_AGP_LOCATION,
 			     (((dev_priv->gart_vm_start - 1 +
 				dev_priv->gart_size) & 0xffff0000) |
@@ -1153,8 +1159,6 @@
 
 #if __OS_HAS_AGP
 	if (dev_priv->flags & CHIP_IS_AGP) {
-		/* set RADEON_AGP_BASE here instead of relying on X from user space */
-		RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base);
 		RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR,
 			     dev_priv->ring_rptr->offset
 			     - dev->agp->base + dev_priv->gart_vm_start);
@@ -1174,6 +1178,17 @@
 			  entry->handle + tmp_ofs);
 	}
 
+	/* Set ring buffer size */
+#ifdef __BIG_ENDIAN
+	RADEON_WRITE(RADEON_CP_RB_CNTL,
+		     dev_priv->ring.size_l2qw | RADEON_BUF_SWAP_32BIT);
+#else
+	RADEON_WRITE(RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw);
+#endif
+
+	/* Start with assuming that writeback doesn't work */
+	dev_priv->writeback_works = 0;
+
 	/* Initialize the scratch register pointer.  This will cause
 	 * the scratch register values to be written out to memory
 	 * whenever they are updated.
@@ -1190,28 +1205,9 @@
 
 	RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7);
 
-	/* Writeback doesn't seem to work everywhere, test it first */
-	DRM_WRITE32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0);
-	RADEON_WRITE(RADEON_SCRATCH_REG1, 0xdeadbeef);
-
-	for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) {
-		if (DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1)) ==
-		    0xdeadbeef)
-			break;
-		DRM_UDELAY(1);
-	}
-
-	if (tmp < dev_priv->usec_timeout) {
-		dev_priv->writeback_works = 1;
-		DRM_DEBUG("writeback test succeeded, tmp=%d\n", tmp);
-	} else {
-		dev_priv->writeback_works = 0;
-		DRM_DEBUG("writeback test failed\n");
-	}
-	if (radeon_no_wb == 1) {
-		dev_priv->writeback_works = 0;
-		DRM_DEBUG("writeback forced off\n");
-	}
+	/* Turn on bus mastering */
+	tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
+	RADEON_WRITE(RADEON_BUS_CNTL, tmp);
 
 	dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0;
 	RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame);
@@ -1223,26 +1219,45 @@
 	dev_priv->sarea_priv->last_clear = dev_priv->scratch[2] = 0;
 	RADEON_WRITE(RADEON_LAST_CLEAR_REG, dev_priv->sarea_priv->last_clear);
 
-	/* Set ring buffer size */
-#ifdef __BIG_ENDIAN
-	RADEON_WRITE(RADEON_CP_RB_CNTL,
-		     dev_priv->ring.size_l2qw | RADEON_BUF_SWAP_32BIT);
-#else
-	RADEON_WRITE(RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw);
-#endif
-
 	radeon_do_wait_for_idle(dev_priv);
 
-	/* Turn on bus mastering */
-	tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
-	RADEON_WRITE(RADEON_BUS_CNTL, tmp);
-
 	/* Sync everything up */
 	RADEON_WRITE(RADEON_ISYNC_CNTL,
 		     (RADEON_ISYNC_ANY2D_IDLE3D |
 		      RADEON_ISYNC_ANY3D_IDLE2D |
 		      RADEON_ISYNC_WAIT_IDLEGUI |
 		      RADEON_ISYNC_CPSCRATCH_IDLEGUI));
+
+}
+
+static void radeon_test_writeback(drm_radeon_private_t * dev_priv)
+{
+	u32 tmp;
+
+	/* Writeback doesn't seem to work everywhere, test it here and possibly
+	 * enable it if it appears to work
+	 */
+	DRM_WRITE32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0);
+	RADEON_WRITE(RADEON_SCRATCH_REG1, 0xdeadbeef);
+
+	for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) {
+		if (DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1)) ==
+		    0xdeadbeef)
+			break;
+		DRM_UDELAY(1);
+	}
+
+	if (tmp < dev_priv->usec_timeout) {
+		dev_priv->writeback_works = 1;
+		DRM_INFO("writeback test succeeded in %d usecs\n", tmp);
+	} else {
+		dev_priv->writeback_works = 0;
+		DRM_INFO("writeback test failed\n");
+	}
+	if (radeon_no_wb == 1) {
+		dev_priv->writeback_works = 0;
+		DRM_INFO("writeback forced off\n");
+	}
 }
 
 /* Enable or disable PCI-E GART on the chip */
@@ -1496,6 +1511,9 @@
 
 	dev_priv->fb_location = (RADEON_READ(RADEON_MC_FB_LOCATION)
 				 & 0xffff) << 16;
+	dev_priv->fb_size = 
+		((RADEON_READ(RADEON_MC_FB_LOCATION) & 0xffff0000u) + 0x10000)
+		- dev_priv->fb_location;
 
 	dev_priv->front_pitch_offset = (((dev_priv->front_pitch / 64) << 22) |
 					((dev_priv->front_offset
@@ -1510,8 +1528,46 @@
 					  + dev_priv->fb_location) >> 10));
 
 	dev_priv->gart_size = init->gart_size;
-	dev_priv->gart_vm_start = dev_priv->fb_location
-	    + RADEON_READ(RADEON_CONFIG_APER_SIZE);
+
+	/* New let's set the memory map ... */
+	if (dev_priv->new_memmap) {
+		u32 base = 0;
+
+		DRM_INFO("Setting GART location based on new memory map\n");
+
+		/* If using AGP, try to locate the AGP aperture at the same
+		 * location in the card and on the bus, though we have to
+		 * align it down.
+		 */
+#if __OS_HAS_AGP
+		if (dev_priv->flags & CHIP_IS_AGP) {
+			base = dev->agp->base;
+			/* Check if valid */
+			if ((base + dev_priv->gart_size) > dev_priv->fb_location &&
+			    base < (dev_priv->fb_location + dev_priv->fb_size)) {
+				DRM_INFO("Can't use AGP base @0x%08lx, won't fit\n",
+					 dev->agp->base);
+				base = 0;
+			}
+		}
+#endif
+		/* If not or if AGP is at 0 (Macs), try to put it elsewhere */
+		if (base == 0) {
+			base = dev_priv->fb_location + dev_priv->fb_size;
+			if (((base + dev_priv->gart_size) & 0xfffffffful)
+			    < base)
+				base = dev_priv->fb_location
+					- dev_priv->gart_size;
+		}		
+		dev_priv->gart_vm_start = base & 0xffc00000u;
+		if (dev_priv->gart_vm_start != base)
+			DRM_INFO("GART aligned down from 0x%08x to 0x%08x\n",
+				 base, dev_priv->gart_vm_start);
+	} else {
+		DRM_INFO("Setting GART location based on old memory map\n");
+		dev_priv->gart_vm_start = dev_priv->fb_location +
+			RADEON_READ(RADEON_CONFIG_APER_SIZE);
+	}
 
 #if __OS_HAS_AGP
 	if (dev_priv->flags & CHIP_IS_AGP)
@@ -1596,6 +1652,7 @@
 	dev_priv->last_buf = 0;
 
 	radeon_do_engine_reset(dev);
+	radeon_test_writeback(dev_priv);
 
 	return 0;
 }
diff -urN oldtree/drivers/char/drm/radeon_drm.h newtree/drivers/char/drm/radeon_drm.h
--- oldtree/drivers/char/drm/radeon_drm.h	2006-02-19 11:41:01.375134048 +0000
+++ newtree/drivers/char/drm/radeon_drm.h	2006-02-21 15:58:13.392110648 +0000
@@ -698,6 +698,8 @@
 #define RADEON_SETPARAM_SWITCH_TILING  2	/* enable/disable color tiling */
 #define RADEON_SETPARAM_PCIGART_LOCATION 3	/* PCI Gart Location */
 
+#define RADEON_SETPARAM_NEW_MEMMAP 4		/* Use new memory map */
+
 /* 1.14: Clients can allocate/free a surface
  */
 typedef struct drm_radeon_surface_alloc {
diff -urN oldtree/drivers/char/drm/radeon_drv.h newtree/drivers/char/drm/radeon_drv.h
--- oldtree/drivers/char/drm/radeon_drv.h	2006-02-19 11:41:01.377133744 +0000
+++ newtree/drivers/char/drm/radeon_drv.h	2006-02-21 15:58:13.393110496 +0000
@@ -90,9 +90,11 @@
  * 1.19- Add support for gart table in FB memory and PCIE r300
  * 1.20- Add support for r300 texrect
  * 1.21- Add support for card type getparam
+ * 1.22- Add support for texture cache flushes (R300_TX_CNTL)
+ * 1,23- Add new radeon memory map work from benh
  */
 #define DRIVER_MAJOR		1
-#define DRIVER_MINOR		21
+#define DRIVER_MINOR		23
 #define DRIVER_PATCHLEVEL	0
 
 /*
@@ -137,7 +139,8 @@
 	CHIP_IS_PCIE = 0x00200000UL,
 };
 
-#define GET_RING_HEAD(dev_priv)		DRM_READ32(  (dev_priv)->ring_rptr, 0 )
+#define GET_RING_HEAD(dev_priv)	(dev_priv->writeback_works ? \
+        DRM_READ32(  (dev_priv)->ring_rptr, 0 ) : RADEON_READ(RADEON_CP_RB_RPTR))
 #define SET_RING_HEAD(dev_priv,val)	DRM_WRITE32( (dev_priv)->ring_rptr, 0, (val) )
 
 typedef struct drm_radeon_freelist {
@@ -198,6 +201,8 @@
 	drm_radeon_sarea_t *sarea_priv;
 
 	u32 fb_location;
+	u32 fb_size;
+	int new_memmap;
 
 	int gart_size;
 	u32 gart_vm_start;
diff -urN oldtree/drivers/char/drm/radeon_state.c newtree/drivers/char/drm/radeon_state.c
--- oldtree/drivers/char/drm/radeon_state.c	2006-02-19 11:41:01.380133288 +0000
+++ newtree/drivers/char/drm/radeon_state.c	2006-02-21 15:58:13.395110192 +0000
@@ -45,22 +45,53 @@
 	u32 off = *offset;
 	struct drm_radeon_driver_file_fields *radeon_priv;
 
-	if (off >= dev_priv->fb_location &&
-	    off < (dev_priv->gart_vm_start + dev_priv->gart_size))
+	/* Hrm ... the story of the offset ... So this function converts
+	 * the various ideas of what userland clients might have for an
+	 * offset in the card address space into an offset into the card
+	 * address space :) So with a sane client, it should just keep
+	 * the value intact and just do some boundary checking. However,
+	 * not all clients are sane. Some older clients pass us 0 based
+	 * offsets relative to the start of the framebuffer and some may
+	 * assume the AGP aperture it appended to the framebuffer, so we
+	 * try to detect those cases and fix them up.
+	 *
+	 * Note: It might be a good idea here to make sure the offset lands
+	 * in some "allowed" area to protect things like the PCIE GART...
+	 */
+
+	/* First, the best case, the offset already lands in either the
+	 * framebuffer or the GART mapped space
+	 */
+	if ((off >= dev_priv->fb_location &&
+	     off < (dev_priv->fb_location + dev_priv->fb_size)) ||
+	    (off >= dev_priv->gart_vm_start &&
+	     off < (dev_priv->gart_vm_start + dev_priv->gart_size)))
 		return 0;
 
-	radeon_priv = filp_priv->driver_priv;
-	off += radeon_priv->radeon_fb_delta;
-
-	DRM_DEBUG("offset fixed up to 0x%x\n", off);
-
-	if (off < dev_priv->fb_location ||
-	    off >= (dev_priv->gart_vm_start + dev_priv->gart_size))
-		return DRM_ERR(EINVAL);
-
-	*offset = off;
+	/* Ok, that didn't happen... now check if we have a zero based
+	 * offset that fits in the framebuffer + gart space, apply the
+	 * magic offset we get from SETPARAM or calculated from fb_location
+	 */
+	if (off < (dev_priv->fb_size + dev_priv->gart_size)) {
+		radeon_priv = filp_priv->driver_priv;
+		off += radeon_priv->radeon_fb_delta;
+	}
 
-	return 0;
+	/* Finally, assume we aimed at a GART offset if beyond the fb */
+	if (off > (dev_priv->fb_location + dev_priv->fb_size))
+		off = off - (dev_priv->fb_location + dev_priv->fb_size) +
+			dev_priv->gart_vm_start;
+
+	/* Now recheck and fail if out of bounds */
+	if ((off >= dev_priv->fb_location &&
+	     off < (dev_priv->fb_location + dev_priv->fb_size)) ||
+	    (off >= dev_priv->gart_vm_start &&
+	     off < (dev_priv->gart_vm_start + dev_priv->gart_size))) {
+		DRM_DEBUG("offset fixed up to 0x%x\n", off);
+		*offset = off;
+		return 0;
+	}
+	return DRM_ERR(EINVAL);
 }
 
 static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
@@ -3012,6 +3043,9 @@
 	case RADEON_SETPARAM_PCIGART_LOCATION:
 		dev_priv->pcigart_offset = sp.value;
 		break;
+	case RADEON_SETPARAM_NEW_MEMMAP:
+		dev_priv->new_memmap = sp.value;
+		break;
 	default:
 		DRM_DEBUG("Invalid parameter %d\n", sp.param);
 		return DRM_ERR(EINVAL);
diff -urN oldtree/drivers/char/generic_serial.c newtree/drivers/char/generic_serial.c
--- oldtree/drivers/char/generic_serial.c	2006-02-19 11:41:01.401130096 +0000
+++ newtree/drivers/char/generic_serial.c	2006-02-21 15:58:28.328839920 +0000
@@ -48,8 +48,8 @@
 #define NEW_WRITE_LOCKING 1
 #if NEW_WRITE_LOCKING
 #define DECL      /* Nothing */
-#define LOCKIT    down (& port->port_write_sem);
-#define RELEASEIT up (&port->port_write_sem);
+#define LOCKIT    mutex_lock(& port->port_write_mutex);
+#define RELEASEIT mutex_unlock(&port->port_write_mutex);
 #else
 #define DECL      unsigned long flags;
 #define LOCKIT    save_flags (flags);cli ()
@@ -124,14 +124,14 @@
 	/* get exclusive "write" access to this port (problem 3) */
 	/* This is not a spinlock because we can have a disk access (page 
 		 fault) in copy_from_user */
-	down (& port->port_write_sem);
+	mutex_lock(& port->port_write_mutex);
 
 	while (1) {
 
 		c = count;
  
 		/* This is safe because we "OWN" the "head". Noone else can 
-		   change the "head": we own the port_write_sem. */
+		   change the "head": we own the port_write_mutex. */
 		/* Don't overrun the end of the buffer */
 		t = SERIAL_XMIT_SIZE - port->xmit_head;
 		if (t < c) c = t;
@@ -153,7 +153,7 @@
 		count -= c;
 		total += c;
 	}
-	up (& port->port_write_sem);
+	mutex_unlock(& port->port_write_mutex);
 
 	gs_dprintk (GS_DEBUG_WRITE, "write: interrupts are %s\n", 
 	            (port->flags & GS_TX_INTEN)?"enabled": "disabled"); 
@@ -214,7 +214,7 @@
 		c = count;
 
 		/* This is safe because we "OWN" the "head". Noone else can 
-		   change the "head": we own the port_write_sem. */
+		   change the "head": we own the port_write_mutex. */
 		/* Don't overrun the end of the buffer */
 		t = SERIAL_XMIT_SIZE - port->xmit_head;
 		if (t < c) c = t;
@@ -888,7 +888,7 @@
 	spin_lock_irqsave (&port->driver_lock, flags);
 	if (port->tty) 
 		clear_bit(TTY_IO_ERROR, &port->tty->flags);
-	init_MUTEX(&port->port_write_sem);
+	mutex_init(&port->port_write_mutex);
 	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
 	spin_unlock_irqrestore(&port->driver_lock, flags);
 	gs_set_termios(port->tty, NULL);
diff -urN oldtree/drivers/char/hpet.c newtree/drivers/char/hpet.c
--- oldtree/drivers/char/hpet.c	2006-02-19 11:41:01.402129944 +0000
+++ newtree/drivers/char/hpet.c	2006-02-21 15:58:10.991475600 +0000
@@ -925,11 +925,8 @@
 	status = acpi_resource_to_address64(res, &addr);
 
 	if (ACPI_SUCCESS(status)) {
-		unsigned long size;
-
-		size = addr.maximum - addr.minimum + 1;
 		hdp->hd_phys_address = addr.minimum;
-		hdp->hd_address = ioremap(addr.minimum, size);
+		hdp->hd_address = ioremap(addr.minimum, addr.address_length);
 
 		if (hpet_is_known(hdp)) {
 			printk(KERN_DEBUG "%s: 0x%lx is busy\n",
diff -urN oldtree/drivers/char/hvcs.c newtree/drivers/char/hvcs.c
--- oldtree/drivers/char/hvcs.c	2006-02-19 11:41:01.404129640 +0000
+++ newtree/drivers/char/hvcs.c	2006-02-21 15:58:17.522482736 +0000
@@ -118,7 +118,7 @@
  * the hvcs_final_close() function in order to get it out of the spinlock.
  * Rearranged hvcs_close().  Cleaned up some printks and did some housekeeping
  * on the changelog.  Removed local CLC_LENGTH and used HVCS_CLC_LENGTH from
- * arch/ppc64/hvcserver.h.
+ * include/asm-powerpc/hvcserver.h 
  *
  * 1.3.2 -> 1.3.3 Replaced yield() in hvcs_close() with tty_wait_until_sent() to
  * prevent possible lockup with realtime scheduling as similarily pointed out by
@@ -168,9 +168,10 @@
 
 /*
  * The hcall interface involves putting 8 chars into each of two registers.
- * We load up those 2 registers (in arch/ppc64/hvconsole.c) by casting char[16]
- * to long[2].  It would work without __ALIGNED__, but a little (tiny) bit
- * slower because an unaligned load is slower than aligned load.
+ * We load up those 2 registers (in arch/powerpc/platforms/pseries/hvconsole.c)
+ * by casting char[16] to long[2].  It would work without __ALIGNED__, but a 
+ * little (tiny) bit slower because an unaligned load is slower than aligned 
+ * load.
  */
 #define __ALIGNED__	__attribute__((__aligned__(8)))
 
diff -urN oldtree/drivers/char/istallion.c newtree/drivers/char/istallion.c
--- oldtree/drivers/char/istallion.c	2006-02-19 11:41:01.444123560 +0000
+++ newtree/drivers/char/istallion.c	2006-02-21 15:58:24.047490784 +0000
@@ -181,7 +181,6 @@
  *	is already swapping a shared buffer won't make things any worse.
  */
 static char			*stli_tmpwritebuf;
-static DECLARE_MUTEX(stli_tmpwritesem);
 
 #define	STLI_TXBUFSIZE		4096
 
diff -urN oldtree/drivers/char/keyboard.c newtree/drivers/char/keyboard.c
--- oldtree/drivers/char/keyboard.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/char/keyboard.c	2006-02-21 15:58:14.945874440 +0000
@@ -900,6 +900,8 @@
 	if (leds != ledstate) {
 		list_for_each(node, &kbd_handler.h_list) {
 			struct input_handle * handle = to_handle_h(node);
+			if (handle->dev->grab)
+				continue;
 			input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01));
 			input_event(handle->dev, EV_LED, LED_NUML,    !!(leds & 0x02));
 			input_event(handle->dev, EV_LED, LED_CAPSL,   !!(leds & 0x04));
diff -urN oldtree/drivers/char/n_tty.c newtree/drivers/char/n_tty.c
--- oldtree/drivers/char/n_tty.c	2006-02-19 11:41:01.452122344 +0000
+++ newtree/drivers/char/n_tty.c	2006-02-21 15:58:25.486272056 +0000
@@ -132,7 +132,7 @@
  *	We test the TTY_THROTTLED bit first so that it always
  *	indicates the current state. The decision about whether
  *	it is worth allowing more input has been taken by the caller.
- *	Can sleep, may be called under the atomic_read semaphore but
+ *	Can sleep, may be called under the atomic_read_lock mutex but
  *	this is not guaranteed.
  */
  
@@ -1132,7 +1132,7 @@
  *	buffer, and once to drain the space from the (physical) beginning of
  *	the buffer to head pointer.
  *
- *	Called under the tty->atomic_read sem and with TTY_DONT_FLIP set
+ *	Called under the tty->atomic_read_lock sem and with TTY_DONT_FLIP set
  *
  */
  
@@ -1262,11 +1262,11 @@
 	 *	Internal serialization of reads.
 	 */
 	if (file->f_flags & O_NONBLOCK) {
-		if (down_trylock(&tty->atomic_read))
+		if (!mutex_trylock(&tty->atomic_read_lock))
 			return -EAGAIN;
 	}
 	else {
-		if (down_interruptible(&tty->atomic_read))
+		if (mutex_lock_interruptible(&tty->atomic_read_lock))
 			return -ERESTARTSYS;
 	}
 
@@ -1393,7 +1393,7 @@
 			timeout = time;
 	}
 	clear_bit(TTY_DONT_FLIP, &tty->flags);
-	up(&tty->atomic_read);
+	mutex_unlock(&tty->atomic_read_lock);
 	remove_wait_queue(&tty->read_wait, &wait);
 
 	if (!waitqueue_active(&tty->read_wait))
diff -urN oldtree/drivers/char/nwflash.c newtree/drivers/char/nwflash.c
--- oldtree/drivers/char/nwflash.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/char/nwflash.c	2006-02-21 15:58:24.057489264 +0000
@@ -27,6 +27,7 @@
 #include <linux/rwsem.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #include <asm/hardware/dec21285.h>
 #include <asm/io.h>
@@ -56,7 +57,7 @@
 static int gbWriteBase64Enable;
 static volatile unsigned char *FLASH_BASE;
 static int gbFlashSize = KFLASH_SIZE;
-static DECLARE_MUTEX(nwflash_sem);
+static DEFINE_MUTEX(nwflash_mutex);
 
 extern spinlock_t gpio_lock;
 
@@ -140,7 +141,7 @@
 		/*
 		 * We now lock against reads and writes. --rmk
 		 */
-		if (down_interruptible(&nwflash_sem))
+		if (mutex_lock_interruptible(&nwflash_mutex))
 			return -ERESTARTSYS;
 
 		ret = copy_to_user(buf, (void *)(FLASH_BASE + p), count);
@@ -149,7 +150,7 @@
 			*ppos += count;
 		} else
 			ret = -EFAULT;
-		up(&nwflash_sem);
+		mutex_unlock(&nwflash_mutex);
 	}
 	return ret;
 }
@@ -188,7 +189,7 @@
 	/*
 	 * We now lock against reads and writes. --rmk
 	 */
-	if (down_interruptible(&nwflash_sem))
+	if (mutex_lock_interruptible(&nwflash_mutex))
 		return -ERESTARTSYS;
 
 	written = 0;
@@ -277,7 +278,7 @@
 	 */
 	leds_event(led_release);
 
-	up(&nwflash_sem);
+	mutex_unlock(&nwflash_mutex);
 
 	return written;
 }
diff -urN oldtree/drivers/char/raw.c newtree/drivers/char/raw.c
--- oldtree/drivers/char/raw.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/char/raw.c	2006-02-21 15:58:23.777531824 +0000
@@ -19,6 +19,7 @@
 #include <linux/uio.h>
 #include <linux/cdev.h>
 #include <linux/device.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 
@@ -29,7 +30,7 @@
 
 static struct class *raw_class;
 static struct raw_device_data raw_devices[MAX_RAW_MINORS];
-static DECLARE_MUTEX(raw_mutex);
+static DEFINE_MUTEX(raw_mutex);
 static struct file_operations raw_ctl_fops;	     /* forward declaration */
 
 /*
@@ -53,7 +54,7 @@
 		return 0;
 	}
 
-	down(&raw_mutex);
+	mutex_lock(&raw_mutex);
 
 	/*
 	 * All we need to do on open is check that the device is bound.
@@ -78,7 +79,7 @@
 		filp->f_dentry->d_inode->i_mapping =
 			bdev->bd_inode->i_mapping;
 	filp->private_data = bdev;
-	up(&raw_mutex);
+	mutex_unlock(&raw_mutex);
 	return 0;
 
 out2:
@@ -86,7 +87,7 @@
 out1:
 	blkdev_put(bdev);
 out:
-	up(&raw_mutex);
+	mutex_unlock(&raw_mutex);
 	return err;
 }
 
@@ -99,14 +100,14 @@
 	const int minor= iminor(inode);
 	struct block_device *bdev;
 
-	down(&raw_mutex);
+	mutex_lock(&raw_mutex);
 	bdev = raw_devices[minor].binding;
 	if (--raw_devices[minor].inuse == 0) {
 		/* Here  inode->i_mapping == bdev->bd_inode->i_mapping  */
 		inode->i_mapping = &inode->i_data;
 		inode->i_mapping->backing_dev_info = &default_backing_dev_info;
 	}
-	up(&raw_mutex);
+	mutex_unlock(&raw_mutex);
 
 	bd_release(bdev);
 	blkdev_put(bdev);
@@ -187,9 +188,9 @@
 				goto out;
 			}
 
-			down(&raw_mutex);
+			mutex_lock(&raw_mutex);
 			if (rawdev->inuse) {
-				up(&raw_mutex);
+				mutex_unlock(&raw_mutex);
 				err = -EBUSY;
 				goto out;
 			}
@@ -211,11 +212,11 @@
 					bind_device(&rq);
 				}
 			}
-			up(&raw_mutex);
+			mutex_unlock(&raw_mutex);
 		} else {
 			struct block_device *bdev;
 
-			down(&raw_mutex);
+			mutex_lock(&raw_mutex);
 			bdev = rawdev->binding;
 			if (bdev) {
 				rq.block_major = MAJOR(bdev->bd_dev);
@@ -223,7 +224,7 @@
 			} else {
 				rq.block_major = rq.block_minor = 0;
 			}
-			up(&raw_mutex);
+			mutex_unlock(&raw_mutex);
 			if (copy_to_user((void __user *)arg, &rq, sizeof(rq))) {
 				err = -EFAULT;
 				goto out;
diff -urN oldtree/drivers/char/s3c2410-rtc.c newtree/drivers/char/s3c2410-rtc.c
--- oldtree/drivers/char/s3c2410-rtc.c	2006-02-19 11:41:01.887056224 +0000
+++ newtree/drivers/char/s3c2410-rtc.c	2006-02-21 15:58:12.432256568 +0000
@@ -448,13 +448,13 @@
 	/* find the IRQs */
 
 	s3c2410_rtc_tickno = platform_get_irq(pdev, 1);
-	if (s3c2410_rtc_tickno <= 0) {
+	if (s3c2410_rtc_tickno < 0) {
 		dev_err(&pdev->dev, "no irq for rtc tick\n");
 		return -ENOENT;
 	}
 
 	s3c2410_rtc_alarmno = platform_get_irq(pdev, 0);
-	if (s3c2410_rtc_alarmno <= 0) {
+	if (s3c2410_rtc_alarmno < 0) {
 		dev_err(&pdev->dev, "no irq for alarm\n");
 		return -ENOENT;
 	}
diff -urN oldtree/drivers/char/ser_a2232.c newtree/drivers/char/ser_a2232.c
--- oldtree/drivers/char/ser_a2232.c	2006-02-19 11:41:01.889055920 +0000
+++ newtree/drivers/char/ser_a2232.c	2006-02-21 15:58:28.331839464 +0000
@@ -97,7 +97,7 @@
 #include <asm/amigahw.h>
 #include <linux/zorro.h>
 #include <asm/irq.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include <linux/delay.h>
 
@@ -654,7 +654,7 @@
 		port->gs.closing_wait = 30 * HZ;
 		port->gs.rd = &a2232_real_driver;
 #ifdef NEW_WRITE_LOCKING
-		init_MUTEX(&(port->gs.port_write_sem));
+		init_MUTEX(&(port->gs.port_write_mutex));
 #endif
 		init_waitqueue_head(&port->gs.open_wait);
 		init_waitqueue_head(&port->gs.close_wait);
diff -urN oldtree/drivers/char/stallion.c newtree/drivers/char/stallion.c
--- oldtree/drivers/char/stallion.c	2006-02-19 11:41:01.897054704 +0000
+++ newtree/drivers/char/stallion.c	2006-02-21 15:58:24.073486832 +0000
@@ -148,7 +148,6 @@
  *	is already swapping a shared buffer won't make things any worse.
  */
 static char			*stl_tmpwritebuf;
-static DECLARE_MUTEX(stl_tmpwritesem);
 
 /*
  *	Define a local default termios struct. All ports will be created
diff -urN oldtree/drivers/char/sx.c newtree/drivers/char/sx.c
--- oldtree/drivers/char/sx.c	2006-02-19 11:41:01.898054552 +0000
+++ newtree/drivers/char/sx.c	2006-02-21 15:58:28.340838096 +0000
@@ -2314,7 +2314,7 @@
 			port->board = board;
 			port->gs.rd = &sx_real_driver;
 #ifdef NEW_WRITE_LOCKING
-			port->gs.port_write_sem = MUTEX;
+			port->gs.port_write_mutex = MUTEX;
 #endif
 			port->gs.driver_lock = SPIN_LOCK_UNLOCKED;
 			/*
diff -urN oldtree/drivers/char/tty_io.c newtree/drivers/char/tty_io.c
--- oldtree/drivers/char/tty_io.c	2006-02-19 11:41:02.001038896 +0000
+++ newtree/drivers/char/tty_io.c	2006-02-21 15:58:25.604254120 +0000
@@ -130,7 +130,7 @@
 
 /* Semaphore to protect creating and releasing a tty. This is shared with
    vt.c for deeply disgusting hack reasons */
-DECLARE_MUTEX(tty_sem);
+DEFINE_MUTEX(tty_mutex);
 
 #ifdef CONFIG_UNIX98_PTYS
 extern struct tty_driver *ptm_driver;	/* Unix98 pty masters; for /dev/ptmx */
@@ -1188,11 +1188,11 @@
 
 	lock_kernel();
 
-	down(&tty_sem);
+	mutex_lock(&tty_mutex);
 	tty = current->signal->tty;
 	if (tty) {
 		tty_pgrp = tty->pgrp;
-		up(&tty_sem);
+		mutex_unlock(&tty_mutex);
 		if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
 			tty_vhangup(tty);
 	} else {
@@ -1200,7 +1200,7 @@
 			kill_pg(current->signal->tty_old_pgrp, SIGHUP, on_exit);
 			kill_pg(current->signal->tty_old_pgrp, SIGCONT, on_exit);
 		}
-		up(&tty_sem);
+		mutex_unlock(&tty_mutex);
 		unlock_kernel();	
 		return;
 	}
@@ -1211,7 +1211,7 @@
 	}
 
 	/* Must lock changes to tty_old_pgrp */
-	down(&tty_sem);
+	mutex_lock(&tty_mutex);
 	current->signal->tty_old_pgrp = 0;
 	tty->session = 0;
 	tty->pgrp = -1;
@@ -1222,7 +1222,7 @@
 		p->signal->tty = NULL;
 	} while_each_task_pid(current->signal->session, PIDTYPE_SID, p);
 	read_unlock(&tasklist_lock);
-	up(&tty_sem);
+	mutex_unlock(&tty_mutex);
 	unlock_kernel();
 }
 
@@ -1306,7 +1306,7 @@
 	ssize_t ret = 0, written = 0;
 	unsigned int chunk;
 	
-	if (down_interruptible(&tty->atomic_write)) {
+	if (mutex_lock_interruptible(&tty->atomic_write_lock)) {
 		return -ERESTARTSYS;
 	}
 
@@ -1329,7 +1329,7 @@
 	if (count < chunk)
 		chunk = count;
 
-	/* write_buf/write_cnt is protected by the atomic_write semaphore */
+	/* write_buf/write_cnt is protected by the atomic_write_lock mutex */
 	if (tty->write_cnt < chunk) {
 		unsigned char *buf;
 
@@ -1338,7 +1338,7 @@
 
 		buf = kmalloc(chunk, GFP_KERNEL);
 		if (!buf) {
-			up(&tty->atomic_write);
+			mutex_unlock(&tty->atomic_write_lock);
 			return -ENOMEM;
 		}
 		kfree(tty->write_buf);
@@ -1374,7 +1374,7 @@
 		inode->i_mtime = current_fs_time(inode->i_sb);
 		ret = written;
 	}
-	up(&tty->atomic_write);
+	mutex_unlock(&tty->atomic_write_lock);
 	return ret;
 }
 
@@ -1442,8 +1442,8 @@
 
 /*
  * WSH 06/09/97: Rewritten to remove races and properly clean up after a
- * failed open.  The new code protects the open with a semaphore, so it's
- * really quite straightforward.  The semaphore locking can probably be
+ * failed open.  The new code protects the open with a mutex, so it's
+ * really quite straightforward.  The mutex locking can probably be
  * relaxed for the (most common) case of reopening a tty.
  */
 static int init_dev(struct tty_driver *driver, int idx,
@@ -1640,7 +1640,7 @@
 success:
 	*ret_tty = tty;
 	
-	/* All paths come through here to release the semaphore */
+	/* All paths come through here to release the mutex */
 end_init:
 	return retval;
 
@@ -1837,7 +1837,7 @@
 		/* Guard against races with tty->count changes elsewhere and
 		   opens on /dev/tty */
 		   
-		down(&tty_sem);
+		mutex_lock(&tty_mutex);
 		tty_closing = tty->count <= 1;
 		o_tty_closing = o_tty &&
 			(o_tty->count <= (pty_master ? 1 : 0));
@@ -1868,7 +1868,7 @@
 
 		printk(KERN_WARNING "release_dev: %s: read/write wait queue "
 				    "active!\n", tty_name(tty, buf));
-		up(&tty_sem);
+		mutex_unlock(&tty_mutex);
 		schedule();
 	}	
 
@@ -1934,7 +1934,7 @@
 		read_unlock(&tasklist_lock);
 	}
 
-	up(&tty_sem);
+	mutex_unlock(&tty_mutex);
 
 	/* check whether both sides are closing ... */
 	if (!tty_closing || (o_tty && !o_tty_closing))
@@ -2040,11 +2040,11 @@
 	index  = -1;
 	retval = 0;
 	
-	down(&tty_sem);
+	mutex_lock(&tty_mutex);
 
 	if (device == MKDEV(TTYAUX_MAJOR,0)) {
 		if (!current->signal->tty) {
-			up(&tty_sem);
+			mutex_unlock(&tty_mutex);
 			return -ENXIO;
 		}
 		driver = current->signal->tty->driver;
@@ -2070,18 +2070,18 @@
 			noctty = 1;
 			goto got_driver;
 		}
-		up(&tty_sem);
+		mutex_unlock(&tty_mutex);
 		return -ENODEV;
 	}
 
 	driver = get_tty_driver(device, &index);
 	if (!driver) {
-		up(&tty_sem);
+		mutex_unlock(&tty_mutex);
 		return -ENODEV;
 	}
 got_driver:
 	retval = init_dev(driver, index, &tty);
-	up(&tty_sem);
+	mutex_unlock(&tty_mutex);
 	if (retval)
 		return retval;
 
@@ -2167,9 +2167,9 @@
 	}
 	up(&allocated_ptys_lock);
 
-	down(&tty_sem);
+	mutex_lock(&tty_mutex);
 	retval = init_dev(ptm_driver, index, &tty);
-	up(&tty_sem);
+	mutex_unlock(&tty_mutex);
 	
 	if (retval)
 		goto out;
@@ -2915,8 +2915,8 @@
 	init_waitqueue_head(&tty->write_wait);
 	init_waitqueue_head(&tty->read_wait);
 	INIT_WORK(&tty->hangup_work, do_tty_hangup, tty);
-	sema_init(&tty->atomic_read, 1);
-	sema_init(&tty->atomic_write, 1);
+	mutex_init(&tty->atomic_read_lock);
+	mutex_init(&tty->atomic_write_lock);
 	spin_lock_init(&tty->read_lock);
 	INIT_LIST_HEAD(&tty->tty_files);
 	INIT_WORK(&tty->SAK_work, NULL, NULL);
diff -urN oldtree/drivers/char/vme_scc.c newtree/drivers/char/vme_scc.c
--- oldtree/drivers/char/vme_scc.c	2006-02-19 11:41:02.007037984 +0000
+++ newtree/drivers/char/vme_scc.c	2006-02-21 15:58:28.350836576 +0000
@@ -184,7 +184,7 @@
 		port->gs.closing_wait = 30 * HZ;
 		port->gs.rd = &scc_real_driver;
 #ifdef NEW_WRITE_LOCKING
-		port->gs.port_write_sem = MUTEX;
+		port->gs.port_write_mutex = MUTEX;
 #endif
 		init_waitqueue_head(&port->gs.open_wait);
 		init_waitqueue_head(&port->gs.close_wait);
diff -urN oldtree/drivers/char/vt.c newtree/drivers/char/vt.c
--- oldtree/drivers/char/vt.c	2006-02-19 11:41:02.010037528 +0000
+++ newtree/drivers/char/vt.c	2006-02-21 15:58:25.617252144 +0000
@@ -2489,7 +2489,7 @@
 }
 
 /*
- * We take tty_sem in here to prevent another thread from coming in via init_dev
+ * We take tty_mutex in here to prevent another thread from coming in via init_dev
  * and taking a ref against the tty while we're in the process of forgetting
  * about it and cleaning things up.
  *
@@ -2497,7 +2497,7 @@
  */
 static void con_close(struct tty_struct *tty, struct file *filp)
 {
-	down(&tty_sem);
+	mutex_lock(&tty_mutex);
 	acquire_console_sem();
 	if (tty && tty->count == 1) {
 		struct vc_data *vc = tty->driver_data;
@@ -2507,15 +2507,15 @@
 		tty->driver_data = NULL;
 		release_console_sem();
 		vcs_remove_devfs(tty);
-		up(&tty_sem);
+		mutex_unlock(&tty_mutex);
 		/*
-		 * tty_sem is released, but we still hold BKL, so there is
+		 * tty_mutex is released, but we still hold BKL, so there is
 		 * still exclusion against init_dev()
 		 */
 		return;
 	}
 	release_console_sem();
-	up(&tty_sem);
+	mutex_unlock(&tty_mutex);
 }
 
 static void vc_init(struct vc_data *vc, unsigned int rows,
@@ -2869,9 +2869,9 @@
 }
 
 /*
- * We defer the timer blanking to work queue so it can take the console semaphore
+ * We defer the timer blanking to work queue so it can take the console mutex
  * (console operations can still happen at irq time, but only from printk which
- * has the console semaphore. Not perfect yet, but better than no locking
+ * has the console mutex. Not perfect yet, but better than no locking
  */
 static void blank_screen_t(unsigned long dummy)
 {
diff -urN oldtree/drivers/char/watchdog/mpcore_wdt.c newtree/drivers/char/watchdog/mpcore_wdt.c
--- oldtree/drivers/char/watchdog/mpcore_wdt.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/char/watchdog/mpcore_wdt.c	2006-02-21 15:58:12.438255656 +0000
@@ -338,6 +338,10 @@
 
 	wdt->dev = &dev->dev;
 	wdt->irq = platform_get_irq(dev, 0);
+	if (wdt->irq < 0) {
+		ret = -ENXIO;
+		goto err_free;
+	}
 	wdt->base = ioremap(res->start, res->end - res->start + 1);
 	if (!wdt->base) {
 		ret = -ENOMEM;
diff -urN oldtree/drivers/char/watchdog/pcwd_usb.c newtree/drivers/char/watchdog/pcwd_usb.c
--- oldtree/drivers/char/watchdog/pcwd_usb.c	2006-02-19 11:41:02.015036768 +0000
+++ newtree/drivers/char/watchdog/pcwd_usb.c	2006-02-21 15:58:24.079485920 +0000
@@ -42,6 +42,7 @@
 #include <linux/completion.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 
 
 #ifdef CONFIG_USB_DEBUG
@@ -143,7 +144,7 @@
 static struct usb_pcwd_private *usb_pcwd_device;
 
 /* prevent races between open() and disconnect() */
-static DECLARE_MUTEX (disconnect_sem);
+static DEFINE_MUTEX(disconnect_mutex);
 
 /* local function prototypes */
 static int usb_pcwd_probe	(struct usb_interface *interface, const struct usb_device_id *id);
@@ -723,7 +724,7 @@
 	struct usb_pcwd_private *usb_pcwd;
 
 	/* prevent races with open() */
-	down (&disconnect_sem);
+	mutex_lock(&disconnect_mutex);
 
 	usb_pcwd = usb_get_intfdata (interface);
 	usb_set_intfdata (interface, NULL);
@@ -749,7 +750,7 @@
 
 	cards_found--;
 
-	up (&disconnect_sem);
+	mutex_unlock(&disconnect_mutex);
 
 	printk(KERN_INFO PFX "USB PC Watchdog disconnected\n");
 }
diff -urN oldtree/drivers/connector/connector.c newtree/drivers/connector/connector.c
--- oldtree/drivers/connector/connector.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/connector/connector.c	2006-02-21 15:58:23.786530456 +0000
@@ -26,6 +26,7 @@
 #include <linux/netlink.h>
 #include <linux/moduleparam.h>
 #include <linux/connector.h>
+#include <linux/mutex.h>
 
 #include <net/sock.h>
 
@@ -41,7 +42,7 @@
 MODULE_PARM_DESC(cn_idx, "Connector's main device idx.");
 MODULE_PARM_DESC(cn_val, "Connector's main device val.");
 
-static DECLARE_MUTEX(notify_lock);
+static DEFINE_MUTEX(notify_lock);
 static LIST_HEAD(notify_list);
 
 static struct cn_dev cdev;
@@ -259,7 +260,7 @@
 {
 	struct cn_ctl_entry *ent;
 
-	down(&notify_lock);
+	mutex_lock(&notify_lock);
 	list_for_each_entry(ent, &notify_list, notify_entry) {
 		int i;
 		struct cn_notify_req *req;
@@ -292,7 +293,7 @@
 			cn_netlink_send(&m, ctl->group, GFP_KERNEL);
 		}
 	}
-	up(&notify_lock);
+	mutex_unlock(&notify_lock);
 }
 
 /*
@@ -406,14 +407,14 @@
 	if (ctl->group == 0) {
 		struct cn_ctl_entry *n;
 
-		down(&notify_lock);
+		mutex_lock(&notify_lock);
 		list_for_each_entry_safe(ent, n, &notify_list, notify_entry) {
 			if (cn_ctl_msg_equals(ent->msg, ctl)) {
 				list_del(&ent->notify_entry);
 				kfree(ent);
 			}
 		}
-		up(&notify_lock);
+		mutex_unlock(&notify_lock);
 
 		return;
 	}
@@ -428,9 +429,9 @@
 
 	memcpy(ent->msg, ctl, size - sizeof(*ent));
 
-	down(&notify_lock);
+	mutex_lock(&notify_lock);
 	list_add(&ent->notify_entry, &notify_list);
-	up(&notify_lock);
+	mutex_unlock(&notify_lock);
 }
 
 static int __init cn_init(void)
diff -urN oldtree/drivers/dlm/Kconfig newtree/drivers/dlm/Kconfig
--- oldtree/drivers/dlm/Kconfig	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/Kconfig	2006-02-21 15:58:32.655182216 +0000
@@ -0,0 +1,30 @@
+menu "Distributed Lock Manager"
+	depends on INET && EXPERIMENTAL
+
+config DLM
+	tristate "Distributed Lock Manager (DLM)"
+	depends on SYSFS
+	depends on IPV6 || IPV6=n
+	select IP_SCTP
+	select CONFIGFS_FS
+	help
+	A general purpose distributed lock manager for kernel or userspace
+	applications.
+
+config DLM_DEVICE
+	tristate "DLM device for userspace access"
+	depends on DLM
+	help
+	This module creates a misc device through which the dlm lockspace
+	and locking functions become available to userspace applications
+	(usually through the libdlm library).
+
+config DLM_DEBUG
+	bool "DLM debugging"
+	depends on DLM
+	help
+	Under the debugfs mount point, the name of each lockspace will
+	appear as a file in the "dlm" directory.  The output is the
+	list of resource and locks the local node knows about.
+
+endmenu
diff -urN oldtree/drivers/dlm/Makefile newtree/drivers/dlm/Makefile
--- oldtree/drivers/dlm/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/Makefile	2006-02-21 15:58:32.670179936 +0000
@@ -0,0 +1,21 @@
+obj-$(CONFIG_DLM) +=		dlm.o
+obj-$(CONFIG_DLM_DEVICE) +=	dlm_device.o
+
+dlm-y :=			ast.o \
+				config.o \
+				dir.o \
+				lock.o \
+				lockspace.o \
+				lowcomms.o \
+				main.o \
+				member.o \
+				memory.o \
+				midcomms.o \
+				rcom.o \
+				recover.o \
+				recoverd.o \
+				requestqueue.o \
+				util.o
+dlm-$(CONFIG_DLM_DEBUG) +=	debug_fs.o
+
+dlm_device-y :=			device.o
diff -urN oldtree/drivers/dlm/ast.c newtree/drivers/dlm/ast.c
--- oldtree/drivers/dlm/ast.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/ast.c	2006-02-21 15:58:32.775163976 +0000
@@ -0,0 +1,167 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lock.h"
+#include "ast.h"
+
+#define WAKE_ASTS  0
+
+static struct list_head		ast_queue;
+static spinlock_t		ast_queue_lock;
+static struct task_struct *	astd_task;
+static unsigned long		astd_wakeflags;
+static struct mutex		astd_running;
+
+
+void dlm_del_ast(struct dlm_lkb *lkb)
+{
+	spin_lock(&ast_queue_lock);
+	if (lkb->lkb_ast_type & (AST_COMP | AST_BAST))
+		list_del(&lkb->lkb_astqueue);
+	spin_unlock(&ast_queue_lock);
+}
+
+void dlm_add_ast(struct dlm_lkb *lkb, int type)
+{
+	spin_lock(&ast_queue_lock);
+	if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) {
+		kref_get(&lkb->lkb_ref);
+		list_add_tail(&lkb->lkb_astqueue, &ast_queue);
+	}
+	lkb->lkb_ast_type |= type;
+	spin_unlock(&ast_queue_lock);
+
+	set_bit(WAKE_ASTS, &astd_wakeflags);
+	wake_up_process(astd_task);
+}
+
+static void process_asts(void)
+{
+	struct dlm_ls *ls = NULL;
+	struct dlm_rsb *r = NULL;
+	struct dlm_lkb *lkb;
+	void (*cast) (long param);
+	void (*bast) (long param, int mode);
+	int type = 0, found, bmode;
+
+	for (;;) {
+		found = 0;
+		spin_lock(&ast_queue_lock);
+		list_for_each_entry(lkb, &ast_queue, lkb_astqueue) {
+			r = lkb->lkb_resource;
+			ls = r->res_ls;
+
+			if (dlm_locking_stopped(ls))
+				continue;
+
+			list_del(&lkb->lkb_astqueue);
+			type = lkb->lkb_ast_type;
+			lkb->lkb_ast_type = 0;
+			found = 1;
+			break;
+		}
+		spin_unlock(&ast_queue_lock);
+
+		if (!found)
+			break;
+
+		cast = lkb->lkb_astaddr;
+		bast = lkb->lkb_bastaddr;
+		bmode = lkb->lkb_bastmode;
+
+		if ((type & AST_COMP) && cast)
+			cast(lkb->lkb_astparam);
+
+		/* FIXME: Is it safe to look at lkb_grmode here
+		   without doing a lock_rsb() ?
+		   Look at other checks in v1 to avoid basts. */
+
+		if ((type & AST_BAST) && bast)
+			if (!dlm_modes_compat(lkb->lkb_grmode, bmode))
+				bast(lkb->lkb_astparam, bmode);
+
+		/* this removes the reference added by dlm_add_ast
+		   and may result in the lkb being freed */
+		dlm_put_lkb(lkb);
+
+		schedule();
+	}
+}
+
+static inline int no_asts(void)
+{
+	int ret;
+
+	spin_lock(&ast_queue_lock);
+	ret = list_empty(&ast_queue);
+	spin_unlock(&ast_queue_lock);
+	return ret;
+}
+
+static int dlm_astd(void *data)
+{
+	while (!kthread_should_stop()) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (!test_bit(WAKE_ASTS, &astd_wakeflags))
+			schedule();
+		set_current_state(TASK_RUNNING);
+
+		mutex_lock(&astd_running);
+		if (test_and_clear_bit(WAKE_ASTS, &astd_wakeflags))
+			process_asts();
+		mutex_unlock(&astd_running);
+	}
+	return 0;
+}
+
+void dlm_astd_wake(void)
+{
+	if (!no_asts()) {
+		set_bit(WAKE_ASTS, &astd_wakeflags);
+		wake_up_process(astd_task);
+	}
+}
+
+int dlm_astd_start(void)
+{
+	struct task_struct *p;
+	int error = 0;
+
+	INIT_LIST_HEAD(&ast_queue);
+	spin_lock_init(&ast_queue_lock);
+	mutex_init(&astd_running);
+
+	p = kthread_run(dlm_astd, NULL, "dlm_astd");
+	if (IS_ERR(p))
+		error = PTR_ERR(p);
+	else
+		astd_task = p;
+	return error;
+}
+
+void dlm_astd_stop(void)
+{
+	kthread_stop(astd_task);
+}
+
+void dlm_astd_suspend(void)
+{
+	mutex_lock(&astd_running);
+}
+
+void dlm_astd_resume(void)
+{
+	mutex_unlock(&astd_running);
+}
+
diff -urN oldtree/drivers/dlm/ast.h newtree/drivers/dlm/ast.h
--- oldtree/drivers/dlm/ast.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/ast.h	2006-02-21 15:58:32.273240280 +0000
@@ -0,0 +1,26 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __ASTD_DOT_H__
+#define __ASTD_DOT_H__
+
+void dlm_add_ast(struct dlm_lkb *lkb, int type);
+void dlm_del_ast(struct dlm_lkb *lkb);
+
+void dlm_astd_wake(void);
+int dlm_astd_start(void);
+void dlm_astd_stop(void);
+void dlm_astd_suspend(void);
+void dlm_astd_resume(void);
+
+#endif
+
diff -urN oldtree/drivers/dlm/config.c newtree/drivers/dlm/config.c
--- oldtree/drivers/dlm/config.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/config.c	2006-02-21 15:58:32.776163824 +0000
@@ -0,0 +1,787 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/configfs.h>
+#include <net/sock.h>
+
+#include "config.h"
+
+/*
+ * /config/dlm/<cluster>/spaces/<space>/nodes/<node>/nodeid
+ * /config/dlm/<cluster>/spaces/<space>/nodes/<node>/weight
+ * /config/dlm/<cluster>/comms/<comm>/nodeid
+ * /config/dlm/<cluster>/comms/<comm>/local
+ * /config/dlm/<cluster>/comms/<comm>/addr
+ * The <cluster> level is useless, but I haven't figured out how to avoid it.
+ */
+
+static struct config_group *space_list;
+static struct config_group *comm_list;
+static struct comm *local_comm;
+
+struct clusters;
+struct cluster;
+struct spaces;
+struct space;
+struct comms;
+struct comm;
+struct nodes;
+struct node;
+
+static struct config_group *make_cluster(struct config_group *, const char *);
+static void drop_cluster(struct config_group *, struct config_item *);
+static void release_cluster(struct config_item *);
+static struct config_group *make_space(struct config_group *, const char *);
+static void drop_space(struct config_group *, struct config_item *);
+static void release_space(struct config_item *);
+static struct config_item *make_comm(struct config_group *, const char *);
+static void drop_comm(struct config_group *, struct config_item *);
+static void release_comm(struct config_item *);
+static struct config_item *make_node(struct config_group *, const char *);
+static void drop_node(struct config_group *, struct config_item *);
+static void release_node(struct config_item *);
+
+static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,
+			 char *buf);
+static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a,
+			  const char *buf, size_t len);
+static ssize_t show_node(struct config_item *i, struct configfs_attribute *a,
+			 char *buf);
+static ssize_t store_node(struct config_item *i, struct configfs_attribute *a,
+			  const char *buf, size_t len);
+
+static ssize_t comm_nodeid_read(struct comm *cm, char *buf);
+static ssize_t comm_nodeid_write(struct comm *cm, const char *buf, size_t len);
+static ssize_t comm_local_read(struct comm *cm, char *buf);
+static ssize_t comm_local_write(struct comm *cm, const char *buf, size_t len);
+static ssize_t comm_addr_write(struct comm *cm, const char *buf, size_t len);
+static ssize_t node_nodeid_read(struct node *nd, char *buf);
+static ssize_t node_nodeid_write(struct node *nd, const char *buf, size_t len);
+static ssize_t node_weight_read(struct node *nd, char *buf);
+static ssize_t node_weight_write(struct node *nd, const char *buf, size_t len);
+
+enum {
+	COMM_ATTR_NODEID = 0,
+	COMM_ATTR_LOCAL,
+	COMM_ATTR_ADDR,
+};
+
+struct comm_attribute {
+	struct configfs_attribute attr;
+	ssize_t (*show)(struct comm *, char *);
+	ssize_t (*store)(struct comm *, const char *, size_t);
+};
+
+static struct comm_attribute comm_attr_nodeid = {
+	.attr   = { .ca_owner = THIS_MODULE,
+                    .ca_name = "nodeid",
+                    .ca_mode = S_IRUGO | S_IWUSR },
+	.show   = comm_nodeid_read,
+	.store  = comm_nodeid_write,
+};
+
+static struct comm_attribute comm_attr_local = {
+	.attr   = { .ca_owner = THIS_MODULE,
+                    .ca_name = "local",
+                    .ca_mode = S_IRUGO | S_IWUSR },
+	.show   = comm_local_read,
+	.store  = comm_local_write,
+};
+
+static struct comm_attribute comm_attr_addr = {
+	.attr   = { .ca_owner = THIS_MODULE,
+                    .ca_name = "addr",
+                    .ca_mode = S_IRUGO | S_IWUSR },
+	.store  = comm_addr_write,
+};
+
+static struct configfs_attribute *comm_attrs[] = {
+	[COMM_ATTR_NODEID] = &comm_attr_nodeid.attr,
+	[COMM_ATTR_LOCAL] = &comm_attr_local.attr,
+	[COMM_ATTR_ADDR] = &comm_attr_addr.attr,
+	NULL,
+};
+
+enum {
+	NODE_ATTR_NODEID = 0,
+	NODE_ATTR_WEIGHT,
+};
+
+struct node_attribute {
+	struct configfs_attribute attr;
+	ssize_t (*show)(struct node *, char *);
+	ssize_t (*store)(struct node *, const char *, size_t);
+};
+
+static struct node_attribute node_attr_nodeid = {
+	.attr   = { .ca_owner = THIS_MODULE,
+                    .ca_name = "nodeid",
+                    .ca_mode = S_IRUGO | S_IWUSR },
+	.show   = node_nodeid_read,
+	.store  = node_nodeid_write,
+};
+
+static struct node_attribute node_attr_weight = {
+	.attr   = { .ca_owner = THIS_MODULE,
+                    .ca_name = "weight",
+                    .ca_mode = S_IRUGO | S_IWUSR },
+	.show   = node_weight_read,
+	.store  = node_weight_write,
+};
+
+static struct configfs_attribute *node_attrs[] = {
+	[NODE_ATTR_NODEID] = &node_attr_nodeid.attr,
+	[NODE_ATTR_WEIGHT] = &node_attr_weight.attr,
+	NULL,
+};
+
+struct clusters {
+	struct configfs_subsystem subsys;
+};
+
+struct cluster {
+	struct config_group group;
+};
+
+struct spaces {
+	struct config_group ss_group;
+};
+
+struct space {
+	struct config_group group;
+	struct list_head members;
+	struct mutex members_lock;
+	int members_count;
+};
+
+struct comms {
+	struct config_group cs_group;
+};
+
+struct comm {
+	struct config_item item;
+	int nodeid;
+	int local;
+	int addr_count;
+	struct sockaddr_storage *addr[DLM_MAX_ADDR_COUNT];
+};
+
+struct nodes {
+	struct config_group ns_group;
+};
+
+struct node {
+	struct config_item item;
+	struct list_head list; /* space->members */
+	int nodeid;
+	int weight;
+};
+
+static struct configfs_group_operations clusters_ops = {
+	.make_group = make_cluster,
+	.drop_item = drop_cluster,
+};
+
+static struct configfs_item_operations cluster_ops = {
+	.release = release_cluster,
+};
+
+static struct configfs_group_operations spaces_ops = {
+	.make_group = make_space,
+	.drop_item = drop_space,
+};
+
+static struct configfs_item_operations space_ops = {
+	.release = release_space,
+};
+
+static struct configfs_group_operations comms_ops = {
+	.make_item = make_comm,
+	.drop_item = drop_comm,
+};
+
+static struct configfs_item_operations comm_ops = {
+	.release = release_comm,
+	.show_attribute = show_comm,
+	.store_attribute = store_comm,
+};
+
+static struct configfs_group_operations nodes_ops = {
+	.make_item = make_node,
+	.drop_item = drop_node,
+};
+
+static struct configfs_item_operations node_ops = {
+	.release = release_node,
+	.show_attribute = show_node,
+	.store_attribute = store_node,
+};
+
+static struct config_item_type clusters_type = {
+	.ct_group_ops = &clusters_ops,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type cluster_type = {
+	.ct_item_ops = &cluster_ops,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type spaces_type = {
+	.ct_group_ops = &spaces_ops,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type space_type = {
+	.ct_item_ops = &space_ops,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type comms_type = {
+	.ct_group_ops = &comms_ops,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type comm_type = {
+	.ct_item_ops = &comm_ops,
+	.ct_attrs = comm_attrs,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type nodes_type = {
+	.ct_group_ops = &nodes_ops,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type node_type = {
+	.ct_item_ops = &node_ops,
+	.ct_attrs = node_attrs,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct cluster *to_cluster(struct config_item *i)
+{
+	return i ? container_of(to_config_group(i), struct cluster, group):NULL;
+}
+
+static struct space *to_space(struct config_item *i)
+{
+	return i ? container_of(to_config_group(i), struct space, group) : NULL;
+}
+
+static struct comm *to_comm(struct config_item *i)
+{
+	return i ? container_of(i, struct comm, item) : NULL;
+}
+
+static struct node *to_node(struct config_item *i)
+{
+	return i ? container_of(i, struct node, item) : NULL;
+}
+
+static struct config_group *make_cluster(struct config_group *g,
+					 const char *name)
+{
+	struct cluster *cl = NULL;
+	struct spaces *sps = NULL;
+	struct comms *cms = NULL;
+	void *gps = NULL;
+
+	cl = kzalloc(sizeof(struct cluster), GFP_KERNEL);
+	gps = kcalloc(3, sizeof(struct config_group *), GFP_KERNEL);
+	sps = kzalloc(sizeof(struct spaces), GFP_KERNEL);
+	cms = kzalloc(sizeof(struct comms), GFP_KERNEL);
+
+	if (!cl || !gps || !sps || !cms)
+		goto fail;
+
+	config_group_init_type_name(&cl->group, name, &cluster_type);
+	config_group_init_type_name(&sps->ss_group, "spaces", &spaces_type);
+	config_group_init_type_name(&cms->cs_group, "comms", &comms_type);
+
+	cl->group.default_groups = gps;
+	cl->group.default_groups[0] = &sps->ss_group;
+	cl->group.default_groups[1] = &cms->cs_group;
+	cl->group.default_groups[2] = NULL;
+
+	space_list = &sps->ss_group;
+	comm_list = &cms->cs_group;
+	return &cl->group;
+
+ fail:
+	kfree(cl);
+	kfree(gps);
+	kfree(sps);
+	kfree(cms);
+	return NULL;
+}
+
+static void drop_cluster(struct config_group *g, struct config_item *i)
+{
+	struct cluster *cl = to_cluster(i);
+	struct config_item *tmp;
+	int j;
+
+	for (j = 0; cl->group.default_groups[j]; j++) {
+		tmp = &cl->group.default_groups[j]->cg_item;
+		cl->group.default_groups[j] = NULL;
+		config_item_put(tmp);
+	}
+
+	space_list = NULL;
+	comm_list = NULL;
+
+	config_item_put(i);
+}
+
+static void release_cluster(struct config_item *i)
+{
+	struct cluster *cl = to_cluster(i);
+	kfree(cl->group.default_groups);
+	kfree(cl);
+}
+
+static struct config_group *make_space(struct config_group *g, const char *name)
+{
+	struct space *sp = NULL;
+	struct nodes *nds = NULL;
+	void *gps = NULL;
+
+	sp = kzalloc(sizeof(struct space), GFP_KERNEL);
+	gps = kcalloc(2, sizeof(struct config_group *), GFP_KERNEL);
+	nds = kzalloc(sizeof(struct nodes), GFP_KERNEL);
+
+	if (!sp || !gps || !nds)
+		goto fail;
+
+	config_group_init_type_name(&sp->group, name, &space_type);
+	config_group_init_type_name(&nds->ns_group, "nodes", &nodes_type);
+
+	sp->group.default_groups = gps;
+	sp->group.default_groups[0] = &nds->ns_group;
+	sp->group.default_groups[1] = NULL;
+
+	INIT_LIST_HEAD(&sp->members);
+	mutex_init(&sp->members_lock);
+	sp->members_count = 0;
+	return &sp->group;
+
+ fail:
+	kfree(sp);
+	kfree(gps);
+	kfree(nds);
+	return NULL;
+}
+
+static void drop_space(struct config_group *g, struct config_item *i)
+{
+	struct space *sp = to_space(i);
+	struct config_item *tmp;
+	int j;
+
+	/* assert list_empty(&sp->members) */
+
+	for (j = 0; sp->group.default_groups[j]; j++) {
+		tmp = &sp->group.default_groups[j]->cg_item;
+		sp->group.default_groups[j] = NULL;
+		config_item_put(tmp);
+	}
+
+	config_item_put(i);
+}
+
+static void release_space(struct config_item *i)
+{
+	struct space *sp = to_space(i);
+	kfree(sp->group.default_groups);
+	kfree(sp);
+}
+
+static struct config_item *make_comm(struct config_group *g, const char *name)
+{
+	struct comm *cm;
+
+	cm = kzalloc(sizeof(struct comm), GFP_KERNEL);
+	if (!cm)
+		return NULL;
+
+	config_item_init_type_name(&cm->item, name, &comm_type);
+	cm->nodeid = -1;
+	cm->local = 0;
+	cm->addr_count = 0;
+	return &cm->item;
+}
+
+static void drop_comm(struct config_group *g, struct config_item *i)
+{
+	struct comm *cm = to_comm(i);
+	if (local_comm == cm)
+		local_comm = NULL;
+	while (cm->addr_count--)
+		kfree(cm->addr[cm->addr_count]);
+	config_item_put(i);
+}
+
+static void release_comm(struct config_item *i)
+{
+	struct comm *cm = to_comm(i);
+	kfree(cm);
+}
+
+static struct config_item *make_node(struct config_group *g, const char *name)
+{
+	struct space *sp = to_space(g->cg_item.ci_parent);
+	struct node *nd;
+
+	nd = kzalloc(sizeof(struct node), GFP_KERNEL);
+	if (!nd)
+		return NULL;
+
+	config_item_init_type_name(&nd->item, name, &node_type);
+	nd->nodeid = -1;
+	nd->weight = 1;  /* default weight of 1 if none is set */
+
+	mutex_lock(&sp->members_lock);
+	list_add(&nd->list, &sp->members);
+	sp->members_count++;
+	mutex_unlock(&sp->members_lock);
+
+	return &nd->item;
+}
+
+static void drop_node(struct config_group *g, struct config_item *i)
+{
+	struct space *sp = to_space(g->cg_item.ci_parent);
+	struct node *nd = to_node(i);
+
+	mutex_lock(&sp->members_lock);
+	list_del(&nd->list);
+	sp->members_count--;
+	mutex_unlock(&sp->members_lock);
+
+	config_item_put(i);
+}
+
+static void release_node(struct config_item *i)
+{
+	struct node *nd = to_node(i);
+	kfree(nd);
+}
+
+static struct clusters clusters_root = {
+	.subsys = {
+		.su_group = {
+			.cg_item = {
+				.ci_namebuf = "dlm",
+				.ci_type = &clusters_type,
+			},
+		},
+	},
+};
+
+int dlm_config_init(void)
+{
+	config_group_init(&clusters_root.subsys.su_group);
+	init_MUTEX(&clusters_root.subsys.su_sem);
+	return configfs_register_subsystem(&clusters_root.subsys);
+}
+
+void dlm_config_exit(void)
+{
+	configfs_unregister_subsystem(&clusters_root.subsys);
+}
+
+/*
+ * Functions for user space to read/write attributes
+ */
+
+static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,
+			 char *buf)
+{
+	struct comm *cm = to_comm(i);
+	struct comm_attribute *cma =
+			container_of(a, struct comm_attribute, attr);
+	return cma->show ? cma->show(cm, buf) : 0;
+}
+
+static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a,
+			  const char *buf, size_t len)
+{
+	struct comm *cm = to_comm(i);
+	struct comm_attribute *cma =
+		container_of(a, struct comm_attribute, attr);
+	return cma->store ? cma->store(cm, buf, len) : -EINVAL;
+}
+
+static ssize_t comm_nodeid_read(struct comm *cm, char *buf)
+{
+	return sprintf(buf, "%d\n", cm->nodeid);
+}
+
+static ssize_t comm_nodeid_write(struct comm *cm, const char *buf, size_t len)
+{
+	cm->nodeid = simple_strtol(buf, NULL, 0);
+	return len;
+}
+
+static ssize_t comm_local_read(struct comm *cm, char *buf)
+{
+	return sprintf(buf, "%d\n", cm->local);
+}
+
+static ssize_t comm_local_write(struct comm *cm, const char *buf, size_t len)
+{
+	cm->local= simple_strtol(buf, NULL, 0);
+	if (cm->local && !local_comm)
+		local_comm = cm;
+	return len;
+}
+
+static ssize_t comm_addr_write(struct comm *cm, const char *buf, size_t len)
+{
+	struct sockaddr_storage *addr;
+
+	if (len != sizeof(struct sockaddr_storage))
+		return -EINVAL;
+
+	if (cm->addr_count >= DLM_MAX_ADDR_COUNT)
+		return -ENOSPC;
+
+	addr = kzalloc(sizeof(*addr), GFP_KERNEL);
+	if (!addr)
+		return -ENOMEM;
+
+	memcpy(addr, buf, len);
+	cm->addr[cm->addr_count++] = addr;
+	return len;
+}
+
+static ssize_t show_node(struct config_item *i, struct configfs_attribute *a,
+			 char *buf)
+{
+	struct node *nd = to_node(i);
+	struct node_attribute *nda =
+			container_of(a, struct node_attribute, attr);
+	return nda->show ? nda->show(nd, buf) : 0;
+}
+
+static ssize_t store_node(struct config_item *i, struct configfs_attribute *a,
+			  const char *buf, size_t len)
+{
+	struct node *nd = to_node(i);
+	struct node_attribute *nda =
+		container_of(a, struct node_attribute, attr);
+	return nda->store ? nda->store(nd, buf, len) : -EINVAL;
+}
+
+static ssize_t node_nodeid_read(struct node *nd, char *buf)
+{
+	return sprintf(buf, "%d\n", nd->nodeid);
+}
+
+static ssize_t node_nodeid_write(struct node *nd, const char *buf, size_t len)
+{
+	nd->nodeid = simple_strtol(buf, NULL, 0);
+	return len;
+}
+
+static ssize_t node_weight_read(struct node *nd, char *buf)
+{
+	return sprintf(buf, "%d\n", nd->weight);
+}
+
+static ssize_t node_weight_write(struct node *nd, const char *buf, size_t len)
+{
+	nd->weight = simple_strtol(buf, NULL, 0);
+	return len;
+}
+
+/*
+ * Functions for the dlm to get the info that's been configured
+ */
+
+static struct space *get_space(char *name)
+{
+	if (!space_list)
+		return NULL;
+	return to_space(config_group_find_obj(space_list, name));
+}
+
+static void put_space(struct space *sp)
+{
+	config_item_put(&sp->group.cg_item);
+}
+
+static struct comm *get_comm(int nodeid, struct sockaddr_storage *addr)
+{
+	struct config_item *i;
+	struct comm *cm = NULL;
+	int found = 0;
+
+	if (!comm_list)
+		return NULL;
+
+	down(&clusters_root.subsys.su_sem);
+
+	list_for_each_entry(i, &comm_list->cg_children, ci_entry) {
+		cm = to_comm(i);
+
+		if (nodeid) {
+			if (cm->nodeid != nodeid)
+				continue;
+			found = 1;
+			break;
+		} else {
+			if (!cm->addr_count ||
+			    memcmp(cm->addr[0], addr, sizeof(*addr)))
+				continue;
+			found = 1;
+			break;
+		}
+	}
+	up(&clusters_root.subsys.su_sem);
+
+	if (found)
+		config_item_get(i);
+	else
+		cm = NULL;
+	return cm;
+}
+
+static void put_comm(struct comm *cm)
+{
+	config_item_put(&cm->item);
+}
+
+/* caller must free mem */
+int dlm_nodeid_list(char *lsname, int **ids_out)
+{
+	struct space *sp;
+	struct node *nd;
+	int i = 0, rv = 0;
+	int *ids;
+
+	sp = get_space(lsname);
+	if (!sp)
+		return -EEXIST;
+
+	mutex_lock(&sp->members_lock);
+	if (!sp->members_count) {
+		rv = 0;
+		goto out;
+	}
+
+	ids = kcalloc(sp->members_count, sizeof(int), GFP_KERNEL);
+	if (!ids) {
+		rv = -ENOMEM;
+		goto out;
+	}
+
+	rv = sp->members_count;
+	list_for_each_entry(nd, &sp->members, list)
+		ids[i++] = nd->nodeid;
+
+	if (rv != i)
+		printk("bad nodeid count %d %d\n", rv, i);
+
+	*ids_out = ids;
+ out:
+	mutex_unlock(&sp->members_lock);
+	put_space(sp);
+	return rv;
+}
+
+int dlm_node_weight(char *lsname, int nodeid)
+{
+	struct space *sp;
+	struct node *nd;
+	int w = -EEXIST;
+
+	sp = get_space(lsname);
+	if (!sp)
+		goto out;
+
+	mutex_lock(&sp->members_lock);
+	list_for_each_entry(nd, &sp->members, list) {
+		if (nd->nodeid != nodeid)
+			continue;
+		w = nd->weight;
+		break;
+	}
+	mutex_unlock(&sp->members_lock);
+	put_space(sp);
+ out:
+	return w;
+}
+
+int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr)
+{
+	struct comm *cm = get_comm(nodeid, NULL);
+	if (!cm)
+		return -EEXIST;
+	if (!cm->addr_count)
+		return -ENOENT;
+	memcpy(addr, cm->addr[0], sizeof(*addr));
+	put_comm(cm);
+	return 0;
+}
+
+int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid)
+{
+	struct comm *cm = get_comm(0, addr);
+	if (!cm)
+		return -EEXIST;
+	*nodeid = cm->nodeid;
+	put_comm(cm);
+	return 0;
+}
+
+int dlm_our_nodeid(void)
+{
+	return local_comm ? local_comm->nodeid : 0;
+}
+
+/* num 0 is first addr, num 1 is second addr */
+int dlm_our_addr(struct sockaddr_storage *addr, int num)
+{
+	if (!local_comm)
+		return -1;
+	if (num + 1 > local_comm->addr_count)
+		return -1;
+	memcpy(addr, local_comm->addr[num], sizeof(*addr));
+	return 0;
+}
+
+/* Config file defaults */
+#define DEFAULT_TCP_PORT       21064
+#define DEFAULT_BUFFER_SIZE     4096
+#define DEFAULT_RSBTBL_SIZE      256
+#define DEFAULT_LKBTBL_SIZE     1024
+#define DEFAULT_DIRTBL_SIZE      512
+#define DEFAULT_RECOVER_TIMER      5
+#define DEFAULT_TOSS_SECS         10
+#define DEFAULT_SCAN_SECS          5
+
+struct dlm_config_info dlm_config = {
+	.tcp_port = DEFAULT_TCP_PORT,
+	.buffer_size = DEFAULT_BUFFER_SIZE,
+	.rsbtbl_size = DEFAULT_RSBTBL_SIZE,
+	.lkbtbl_size = DEFAULT_LKBTBL_SIZE,
+	.dirtbl_size = DEFAULT_DIRTBL_SIZE,
+	.recover_timer = DEFAULT_RECOVER_TIMER,
+	.toss_secs = DEFAULT_TOSS_SECS,
+	.scan_secs = DEFAULT_SCAN_SECS
+};
+
diff -urN oldtree/drivers/dlm/config.h newtree/drivers/dlm/config.h
--- oldtree/drivers/dlm/config.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/config.h	2006-02-21 15:58:32.649183128 +0000
@@ -0,0 +1,42 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __CONFIG_DOT_H__
+#define __CONFIG_DOT_H__
+
+#define DLM_MAX_ADDR_COUNT 3
+
+struct dlm_config_info {
+	int tcp_port;
+	int buffer_size;
+	int rsbtbl_size;
+	int lkbtbl_size;
+	int dirtbl_size;
+	int recover_timer;
+	int toss_secs;
+	int scan_secs;
+};
+
+extern struct dlm_config_info dlm_config;
+
+int dlm_config_init(void);
+void dlm_config_exit(void);
+int dlm_node_weight(char *lsname, int nodeid);
+int dlm_nodeid_list(char *lsname, int **ids_out);
+int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr);
+int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid);
+int dlm_our_nodeid(void);
+int dlm_our_addr(struct sockaddr_storage *addr, int num);
+
+#endif				/* __CONFIG_DOT_H__ */
+
diff -urN oldtree/drivers/dlm/debug_fs.c newtree/drivers/dlm/debug_fs.c
--- oldtree/drivers/dlm/debug_fs.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/debug_fs.c	2006-02-21 15:58:32.578193920 +0000
@@ -0,0 +1,310 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/debugfs.h>
+
+#include "dlm_internal.h"
+
+
+static struct dentry *dlm_root;
+
+struct rsb_iter {
+	int entry;
+	struct dlm_ls *ls;
+	struct list_head *next;
+	struct dlm_rsb *rsb;
+};
+
+static char *print_lockmode(int mode)
+{
+	switch (mode) {
+	case DLM_LOCK_IV:
+		return "--";
+	case DLM_LOCK_NL:
+		return "NL";
+	case DLM_LOCK_CR:
+		return "CR";
+	case DLM_LOCK_CW:
+		return "CW";
+	case DLM_LOCK_PR:
+		return "PR";
+	case DLM_LOCK_PW:
+		return "PW";
+	case DLM_LOCK_EX:
+		return "EX";
+	default:
+		return "??";
+	}
+}
+
+static void print_lock(struct seq_file *s, struct dlm_lkb *lkb,
+		       struct dlm_rsb *res)
+{
+	seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode));
+
+	if (lkb->lkb_status == DLM_LKSTS_CONVERT
+	    || lkb->lkb_status == DLM_LKSTS_WAITING)
+		seq_printf(s, " (%s)", print_lockmode(lkb->lkb_rqmode));
+
+	if (lkb->lkb_range) {
+		/* FIXME: this warns on Alpha */
+		if (lkb->lkb_status == DLM_LKSTS_CONVERT
+		    || lkb->lkb_status == DLM_LKSTS_GRANTED)
+			seq_printf(s, " %llx-%llx",
+				   lkb->lkb_range[GR_RANGE_START],
+				   lkb->lkb_range[GR_RANGE_END]);
+		if (lkb->lkb_status == DLM_LKSTS_CONVERT
+		    || lkb->lkb_status == DLM_LKSTS_WAITING)
+			seq_printf(s, " (%llx-%llx)",
+				   lkb->lkb_range[RQ_RANGE_START],
+				   lkb->lkb_range[RQ_RANGE_END]);
+	}
+
+	if (lkb->lkb_nodeid) {
+		if (lkb->lkb_nodeid != res->res_nodeid)
+			seq_printf(s, " Remote: %3d %08x", lkb->lkb_nodeid,
+				   lkb->lkb_remid);
+		else
+			seq_printf(s, " Master:     %08x", lkb->lkb_remid);
+	}
+
+	if (lkb->lkb_wait_type)
+		seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
+
+	seq_printf(s, "\n");
+}
+
+static int print_resource(struct dlm_rsb *res, struct seq_file *s)
+{
+	struct dlm_lkb *lkb;
+	int i, lvblen = res->res_ls->ls_lvblen;
+
+	seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length);
+	for (i = 0; i < res->res_length; i++) {
+		if (isprint(res->res_name[i]))
+			seq_printf(s, "%c", res->res_name[i]);
+		else
+			seq_printf(s, "%c", '.');
+	}
+	if (res->res_nodeid > 0)
+		seq_printf(s, "\"  \nLocal Copy, Master is node %d\n",
+			   res->res_nodeid);
+	else if (res->res_nodeid == 0)
+		seq_printf(s, "\"  \nMaster Copy\n");
+	else if (res->res_nodeid == -1)
+		seq_printf(s, "\"  \nLooking up master (lkid %x)\n",
+			   res->res_first_lkid);
+	else
+		seq_printf(s, "\"  \nInvalid master %d\n", res->res_nodeid);
+
+	/* Print the LVB: */
+	if (res->res_lvbptr) {
+		seq_printf(s, "LVB: ");
+		for (i = 0; i < lvblen; i++) {
+			if (i == lvblen / 2)
+				seq_printf(s, "\n     ");
+			seq_printf(s, "%02x ",
+				   (unsigned char) res->res_lvbptr[i]);
+		}
+		if (rsb_flag(res, RSB_VALNOTVALID))
+			seq_printf(s, " (INVALID)");
+		seq_printf(s, "\n");
+	}
+
+	/* Print the locks attached to this resource */
+	seq_printf(s, "Granted Queue\n");
+	list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue)
+		print_lock(s, lkb, res);
+
+	seq_printf(s, "Conversion Queue\n");
+	list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue)
+		print_lock(s, lkb, res);
+
+	seq_printf(s, "Waiting Queue\n");
+	list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue)
+		print_lock(s, lkb, res);
+
+	return 0;
+}
+
+static int rsb_iter_next(struct rsb_iter *ri)
+{
+	struct dlm_ls *ls = ri->ls;
+	int i;
+
+	if (!ri->next) {
+ top:
+		/* Find the next non-empty hash bucket */
+		for (i = ri->entry; i < ls->ls_rsbtbl_size; i++) {
+			read_lock(&ls->ls_rsbtbl[i].lock);
+			if (!list_empty(&ls->ls_rsbtbl[i].list)) {
+				ri->next = ls->ls_rsbtbl[i].list.next;
+				read_unlock(&ls->ls_rsbtbl[i].lock);
+				break;
+			}
+			read_unlock(&ls->ls_rsbtbl[i].lock);
+                }
+		ri->entry = i;
+
+		if (ri->entry >= ls->ls_rsbtbl_size)
+			return 1;
+	} else {
+		i = ri->entry;
+		read_lock(&ls->ls_rsbtbl[i].lock);
+		ri->next = ri->next->next;
+		if (ri->next->next == ls->ls_rsbtbl[i].list.next) {
+			/* End of list - move to next bucket */
+			ri->next = NULL;
+			ri->entry++;
+			read_unlock(&ls->ls_rsbtbl[i].lock);
+			goto top;
+                }
+		read_unlock(&ls->ls_rsbtbl[i].lock);
+	}
+	ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain);
+
+	return 0;
+}
+
+static void rsb_iter_free(struct rsb_iter *ri)
+{
+	kfree(ri);
+}
+
+static struct rsb_iter *rsb_iter_init(struct dlm_ls *ls)
+{
+	struct rsb_iter *ri;
+
+	ri = kmalloc(sizeof *ri, GFP_KERNEL);
+	if (!ri)
+		return NULL;
+
+	ri->ls = ls;
+	ri->entry = 0;
+	ri->next = NULL;
+
+	if (rsb_iter_next(ri)) {
+		rsb_iter_free(ri);
+		return NULL;
+	}
+
+	return ri;
+}
+
+static void *seq_start(struct seq_file *file, loff_t *pos)
+{
+	struct rsb_iter *ri;
+	loff_t n = *pos;
+
+	ri = rsb_iter_init(file->private);
+	if (!ri)
+		return NULL;
+
+	while (n--) {
+		if (rsb_iter_next(ri)) {
+			rsb_iter_free(ri);
+			return NULL;
+		}
+	}
+
+	return ri;
+}
+
+static void *seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos)
+{
+	struct rsb_iter *ri = iter_ptr;
+
+	(*pos)++;
+
+	if (rsb_iter_next(ri)) {
+		rsb_iter_free(ri);
+		return NULL;
+	}
+
+	return ri;
+}
+
+static void seq_stop(struct seq_file *file, void *iter_ptr)
+{
+	/* nothing for now */
+}
+
+static int seq_show(struct seq_file *file, void *iter_ptr)
+{
+	struct rsb_iter *ri = iter_ptr;
+
+	print_resource(ri->rsb, file);
+
+	return 0;
+}
+
+static struct seq_operations dlm_seq_ops = {
+	.start = seq_start,
+	.next  = seq_next,
+	.stop  = seq_stop,
+	.show  = seq_show,
+};
+
+static int do_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq;
+	int ret;
+
+	ret = seq_open(file, &dlm_seq_ops);
+	if (ret)
+		return ret;
+
+	seq = file->private_data;
+	seq->private = inode->u.generic_ip;
+
+	return 0;
+}
+
+static struct file_operations dlm_fops = {
+	.owner   = THIS_MODULE,
+	.open    = do_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release
+};
+
+int dlm_create_debug_file(struct dlm_ls *ls)
+{
+	ls->ls_debug_dentry = debugfs_create_file(ls->ls_name,
+						  S_IFREG | S_IRUGO,
+						  dlm_root,
+						  ls,
+						  &dlm_fops);
+	return ls->ls_debug_dentry ? 0 : -ENOMEM;
+}
+
+void dlm_delete_debug_file(struct dlm_ls *ls)
+{
+	if (ls->ls_debug_dentry)
+		debugfs_remove(ls->ls_debug_dentry);
+}
+
+int dlm_register_debugfs(void)
+{
+	dlm_root = debugfs_create_dir("dlm", NULL);
+	return dlm_root ? 0 : -ENOMEM;
+}
+
+void dlm_unregister_debugfs(void)
+{
+	debugfs_remove(dlm_root);
+}
+
diff -urN oldtree/drivers/dlm/device.c newtree/drivers/dlm/device.c
--- oldtree/drivers/dlm/device.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/device.c	2006-02-21 15:58:32.776163824 +0000
@@ -0,0 +1,1095 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+/*
+ * device.c
+ *
+ * This is the userland interface to the DLM.
+ *
+ * The locking is done via a misc char device (find the
+ * registered minor number in /proc/misc).
+ *
+ * User code should not use this interface directly but
+ * call the library routines in libdlm.a instead.
+ *
+ */
+
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/signal.h>
+#include <linux/spinlock.h>
+#include <linux/idr.h>
+
+#include <linux/dlm.h>
+#include <linux/dlm_device.h>
+
+#include "lvb_table.h"
+
+static struct file_operations _dlm_fops;
+static const char *name_prefix="dlm";
+static struct list_head user_ls_list;
+static struct mutex user_ls_lock;
+
+/* Lock infos are stored in here indexed by lock ID */
+static DEFINE_IDR(lockinfo_idr);
+static rwlock_t lockinfo_lock;
+
+/* Flags in li_flags */
+#define LI_FLAG_COMPLETE   1
+#define LI_FLAG_FIRSTLOCK  2
+#define LI_FLAG_PERSISTENT 3
+#define LI_FLAG_ONLIST     4
+
+/* flags in ls_flags*/
+#define LS_FLAG_DELETED   1
+#define LS_FLAG_AUTOFREE  2
+
+
+#define LOCKINFO_MAGIC 0x53595324
+
+struct lock_info {
+	uint32_t li_magic;
+	uint8_t li_cmd;
+	int8_t	li_grmode;
+	int8_t  li_rqmode;
+	struct dlm_lksb li_lksb;
+	wait_queue_head_t li_waitq;
+	unsigned long li_flags;
+	void __user *li_castparam;
+	void __user *li_castaddr;
+	void __user *li_bastparam;
+	void __user *li_bastaddr;
+	void __user *li_pend_bastparam;
+	void __user *li_pend_bastaddr;
+	struct list_head li_ownerqueue;
+	struct file_info *li_file;
+	struct dlm_lksb __user *li_user_lksb;
+	struct semaphore li_firstlock;
+};
+
+/* A queued AST no less */
+struct ast_info {
+	struct dlm_lock_result result;
+	struct list_head list;
+	uint32_t lvb_updated;
+	uint32_t progress;      /* How much has been read */
+};
+
+/* One of these per userland lockspace */
+struct user_ls {
+	void    *ls_lockspace;
+	atomic_t ls_refcnt;
+	long     ls_flags;
+
+	/* Passed into misc_register() */
+	struct miscdevice ls_miscinfo;
+	struct list_head  ls_list;
+};
+
+/* misc_device info for the control device */
+static struct miscdevice ctl_device;
+
+/*
+ * Stuff we hang off the file struct.
+ * The first two are to cope with unlocking all the
+ * locks help by a process when it dies.
+ */
+struct file_info {
+	struct list_head    fi_li_list;  /* List of active lock_infos */
+	spinlock_t          fi_li_lock;
+	struct list_head    fi_ast_list; /* Queue of ASTs to be delivered */
+	spinlock_t          fi_ast_lock;
+	wait_queue_head_t   fi_wait;
+	struct user_ls     *fi_ls;
+	atomic_t            fi_refcnt;   /* Number of users */
+	unsigned long       fi_flags;    /* Bit 1 means the device is open */
+};
+
+
+/* get and put ops for file_info.
+   Actually I don't really like "get" and "put", but everyone
+   else seems to use them and I can't think of anything
+   nicer at the moment */
+static void get_file_info(struct file_info *f)
+{
+	atomic_inc(&f->fi_refcnt);
+}
+
+static void put_file_info(struct file_info *f)
+{
+	if (atomic_dec_and_test(&f->fi_refcnt))
+		kfree(f);
+}
+
+static void release_lockinfo(struct lock_info *li)
+{
+	put_file_info(li->li_file);
+
+	write_lock(&lockinfo_lock);
+	idr_remove(&lockinfo_idr, li->li_lksb.sb_lkid);
+	write_unlock(&lockinfo_lock);
+
+	if (li->li_lksb.sb_lvbptr)
+		kfree(li->li_lksb.sb_lvbptr);
+	kfree(li);
+
+	module_put(THIS_MODULE);
+}
+
+static struct lock_info *get_lockinfo(uint32_t lockid)
+{
+	struct lock_info *li;
+
+	read_lock(&lockinfo_lock);
+	li = idr_find(&lockinfo_idr, lockid);
+	read_unlock(&lockinfo_lock);
+
+	return li;
+}
+
+static int add_lockinfo(struct lock_info *li)
+{
+	int n;
+	int r;
+	int ret = -EINVAL;
+
+	write_lock(&lockinfo_lock);
+
+	if (idr_find(&lockinfo_idr, li->li_lksb.sb_lkid))
+		goto out_up;
+
+	ret = -ENOMEM;
+	r = idr_pre_get(&lockinfo_idr, GFP_KERNEL);
+	if (!r)
+		goto out_up;
+
+	r = idr_get_new_above(&lockinfo_idr, li, li->li_lksb.sb_lkid, &n);
+	if (r)
+		goto out_up;
+
+	if (n != li->li_lksb.sb_lkid) {
+		idr_remove(&lockinfo_idr, n);
+		goto out_up;
+	}
+
+	ret = 0;
+
+ out_up:
+	write_unlock(&lockinfo_lock);
+
+	return ret;
+}
+
+
+static struct user_ls *__find_lockspace(int minor)
+{
+	struct user_ls *lsinfo;
+
+	list_for_each_entry(lsinfo, &user_ls_list, ls_list) {
+		if (lsinfo->ls_miscinfo.minor == minor)
+			return lsinfo;
+	}
+	return NULL;
+}
+
+/* Find a lockspace struct given the device minor number */
+static struct user_ls *find_lockspace(int minor)
+{
+	struct user_ls *lsinfo;
+
+	mutex_lock(&user_ls_lock);
+	lsinfo = __find_lockspace(minor);
+	mutex_unlock(&user_ls_lock);
+
+	return lsinfo;
+}
+
+static void add_lockspace_to_list(struct user_ls *lsinfo)
+{
+	mutex_lock(&user_ls_lock);
+	list_add(&lsinfo->ls_list, &user_ls_list);
+	mutex_unlock(&user_ls_lock);
+}
+
+/* Register a lockspace with the DLM and create a misc
+   device for userland to access it */
+static int register_lockspace(char *name, struct user_ls **ls, int flags)
+{
+	struct user_ls *newls;
+	int status;
+	int namelen;
+
+	namelen = strlen(name)+strlen(name_prefix)+2;
+
+	newls = kzalloc(sizeof(struct user_ls), GFP_KERNEL);
+	if (!newls)
+		return -ENOMEM;
+
+	newls->ls_miscinfo.name = kzalloc(namelen, GFP_KERNEL);
+	if (!newls->ls_miscinfo.name) {
+		kfree(newls);
+		return -ENOMEM;
+	}
+
+	status = dlm_new_lockspace(name, strlen(name), &newls->ls_lockspace, 0,
+				   DLM_USER_LVB_LEN);
+	if (status != 0) {
+		kfree(newls->ls_miscinfo.name);
+		kfree(newls);
+		return status;
+	}
+
+	snprintf((char*)newls->ls_miscinfo.name, namelen, "%s_%s",
+		 name_prefix, name);
+
+	newls->ls_miscinfo.fops = &_dlm_fops;
+	newls->ls_miscinfo.minor = MISC_DYNAMIC_MINOR;
+
+	status = misc_register(&newls->ls_miscinfo);
+	if (status) {
+		printk(KERN_ERR "dlm: misc register failed for %s\n", name);
+		dlm_release_lockspace(newls->ls_lockspace, 0);
+		kfree(newls->ls_miscinfo.name);
+		kfree(newls);
+		return status;
+	}
+
+	if (flags & DLM_USER_LSFLG_AUTOFREE)
+		set_bit(LS_FLAG_AUTOFREE, &newls->ls_flags);
+
+	add_lockspace_to_list(newls);
+	*ls = newls;
+	return 0;
+}
+
+/* Called with the user_ls_lock mutex held */
+static int unregister_lockspace(struct user_ls *lsinfo, int force)
+{
+	int status;
+
+	status = dlm_release_lockspace(lsinfo->ls_lockspace, force);
+	if (status)
+		return status;
+
+	status = misc_deregister(&lsinfo->ls_miscinfo);
+	if (status)
+		return status;
+
+	list_del(&lsinfo->ls_list);
+	set_bit(LS_FLAG_DELETED, &lsinfo->ls_flags);
+	lsinfo->ls_lockspace = NULL;
+	if (atomic_read(&lsinfo->ls_refcnt) == 0) {
+		kfree(lsinfo->ls_miscinfo.name);
+		kfree(lsinfo);
+	}
+
+	return 0;
+}
+
+/* Add it to userland's AST queue */
+static void add_to_astqueue(struct lock_info *li, void *astaddr, void *astparam,
+			    int lvb_updated)
+{
+	struct ast_info *ast = kzalloc(sizeof(struct ast_info), GFP_KERNEL);
+	if (!ast)
+		return;
+
+	ast->result.user_astparam = astparam;
+	ast->result.user_astaddr  = astaddr;
+	ast->result.user_lksb     = li->li_user_lksb;
+	memcpy(&ast->result.lksb, &li->li_lksb, sizeof(struct dlm_lksb));
+	ast->lvb_updated = lvb_updated;
+
+	spin_lock(&li->li_file->fi_ast_lock);
+	list_add_tail(&ast->list, &li->li_file->fi_ast_list);
+	spin_unlock(&li->li_file->fi_ast_lock);
+	wake_up_interruptible(&li->li_file->fi_wait);
+}
+
+static void bast_routine(void *param, int mode)
+{
+	struct lock_info *li = param;
+
+	if (li && li->li_bastaddr)
+		add_to_astqueue(li, li->li_bastaddr, li->li_bastparam, 0);
+}
+
+/*
+ * This is the kernel's AST routine.
+ * All lock, unlock & query operations complete here.
+ * The only syncronous ops are those done during device close.
+ */
+static void ast_routine(void *param)
+{
+	struct lock_info *li = param;
+
+	/* Param may be NULL if a persistent lock is unlocked by someone else */
+	if (!li)
+		return;
+
+	/* If this is a succesful conversion then activate the blocking ast
+	 * args from the conversion request */
+	if (!test_bit(LI_FLAG_FIRSTLOCK, &li->li_flags) &&
+	    li->li_lksb.sb_status == 0) {
+
+		li->li_bastparam = li->li_pend_bastparam;
+		li->li_bastaddr = li->li_pend_bastaddr;
+		li->li_pend_bastaddr = NULL;
+	}
+
+	/* If it's an async request then post data to the user's AST queue. */
+	if (li->li_castaddr) {
+		int lvb_updated = 0;
+
+		/* See if the lvb has been updated */
+		if (dlm_lvb_operations[li->li_grmode+1][li->li_rqmode+1] == 1)
+			lvb_updated = 1;
+
+		if (li->li_lksb.sb_status == 0)
+			li->li_grmode = li->li_rqmode;
+
+		/* Only queue AST if the device is still open */
+		if (test_bit(1, &li->li_file->fi_flags))
+			add_to_astqueue(li, li->li_castaddr, li->li_castparam,
+					lvb_updated);
+
+		/* If it's a new lock operation that failed, then
+		 * remove it from the owner queue and free the
+		 * lock_info.
+		 */
+		if (test_and_clear_bit(LI_FLAG_FIRSTLOCK, &li->li_flags) &&
+		    li->li_lksb.sb_status != 0) {
+
+			/* Wait till dlm_lock() has finished */
+			down(&li->li_firstlock);
+			up(&li->li_firstlock);
+
+			spin_lock(&li->li_file->fi_li_lock);
+			list_del(&li->li_ownerqueue);
+			clear_bit(LI_FLAG_ONLIST, &li->li_flags);
+			spin_unlock(&li->li_file->fi_li_lock);
+			release_lockinfo(li);
+			return;
+		}
+		/* Free unlocks & queries */
+		if (li->li_lksb.sb_status == -DLM_EUNLOCK ||
+		    li->li_cmd == DLM_USER_QUERY) {
+			release_lockinfo(li);
+		}
+	} else {
+		/* Synchronous request, just wake up the caller */
+		set_bit(LI_FLAG_COMPLETE, &li->li_flags);
+		wake_up_interruptible(&li->li_waitq);
+	}
+}
+
+/*
+ * Wait for the lock op to complete and return the status.
+ */
+static int wait_for_ast(struct lock_info *li)
+{
+	/* Wait for the AST routine to complete */
+	set_task_state(current, TASK_INTERRUPTIBLE);
+	while (!test_bit(LI_FLAG_COMPLETE, &li->li_flags))
+		schedule();
+
+	set_task_state(current, TASK_RUNNING);
+
+	return li->li_lksb.sb_status;
+}
+
+
+/* Open on control device */
+static int dlm_ctl_open(struct inode *inode, struct file *file)
+{
+	file->private_data = NULL;
+	return 0;
+}
+
+/* Close on control device */
+static int dlm_ctl_close(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+/* Open on lockspace device */
+static int dlm_open(struct inode *inode, struct file *file)
+{
+	struct file_info *f;
+	struct user_ls *lsinfo;
+
+	lsinfo = find_lockspace(iminor(inode));
+	if (!lsinfo)
+		return -ENOENT;
+
+	f = kzalloc(sizeof(struct file_info), GFP_KERNEL);
+	if (!f)
+		return -ENOMEM;
+
+	atomic_inc(&lsinfo->ls_refcnt);
+	INIT_LIST_HEAD(&f->fi_li_list);
+	INIT_LIST_HEAD(&f->fi_ast_list);
+	spin_lock_init(&f->fi_li_lock);
+	spin_lock_init(&f->fi_ast_lock);
+	init_waitqueue_head(&f->fi_wait);
+	f->fi_ls = lsinfo;
+	f->fi_flags = 0;
+	get_file_info(f);
+	set_bit(1, &f->fi_flags);
+
+	file->private_data = f;
+
+	return 0;
+}
+
+/* Check the user's version matches ours */
+static int check_version(struct dlm_write_request *req)
+{
+	if (req->version[0] != DLM_DEVICE_VERSION_MAJOR ||
+	    (req->version[0] == DLM_DEVICE_VERSION_MAJOR &&
+	     req->version[1] > DLM_DEVICE_VERSION_MINOR)) {
+
+		printk(KERN_DEBUG "dlm: process %s (%d) version mismatch "
+		       "user (%d.%d.%d) kernel (%d.%d.%d)\n",
+		       current->comm,
+		       current->pid,
+		       req->version[0],
+		       req->version[1],
+		       req->version[2],
+		       DLM_DEVICE_VERSION_MAJOR,
+		       DLM_DEVICE_VERSION_MINOR,
+		       DLM_DEVICE_VERSION_PATCH);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* Close on lockspace device */
+static int dlm_close(struct inode *inode, struct file *file)
+{
+	struct file_info *f = file->private_data;
+	struct lock_info li;
+	struct lock_info *old_li, *safe;
+	sigset_t tmpsig;
+	sigset_t allsigs;
+	struct user_ls *lsinfo;
+	DECLARE_WAITQUEUE(wq, current);
+
+	lsinfo = find_lockspace(iminor(inode));
+	if (!lsinfo)
+		return -ENOENT;
+
+	/* Mark this closed so that ASTs will not be delivered any more */
+	clear_bit(1, &f->fi_flags);
+
+	/* Block signals while we are doing this */
+	sigfillset(&allsigs);
+	sigprocmask(SIG_BLOCK, &allsigs, &tmpsig);
+
+	/* We use our own lock_info struct here, so that any
+	 * outstanding "real" ASTs will be delivered with the
+	 * corresponding "real" params, thus freeing the lock_info
+	 * that belongs the lock. This catches the corner case where
+	 * a lock is BUSY when we try to unlock it here
+	 */
+	memset(&li, 0, sizeof(li));
+	clear_bit(LI_FLAG_COMPLETE, &li.li_flags);
+	init_waitqueue_head(&li.li_waitq);
+	add_wait_queue(&li.li_waitq, &wq);
+
+	/*
+	 * Free any outstanding locks, they are on the
+	 * list in LIFO order so there should be no problems
+	 * about unlocking parents before children.
+	 */
+	list_for_each_entry_safe(old_li, safe, &f->fi_li_list, li_ownerqueue) {
+		int status;
+		int flags = 0;
+
+		/* Don't unlock persistent locks, just mark them orphaned */
+		if (test_bit(LI_FLAG_PERSISTENT, &old_li->li_flags)) {
+			list_del(&old_li->li_ownerqueue);
+
+			/* Update master copy */
+			/* TODO: Check locking core updates the local and
+			   remote ORPHAN flags */
+			li.li_lksb.sb_lkid = old_li->li_lksb.sb_lkid;
+			status = dlm_lock(f->fi_ls->ls_lockspace,
+					  old_li->li_grmode, &li.li_lksb,
+					  DLM_LKF_CONVERT|DLM_LKF_ORPHAN,
+					  NULL, 0, 0, ast_routine, NULL,
+					  NULL, NULL);
+			if (status != 0)
+				printk("dlm: Error orphaning lock %x: %d\n",
+				       old_li->li_lksb.sb_lkid, status);
+
+			/* But tidy our references in it */
+			release_lockinfo(old_li);
+			continue;
+		}
+
+		clear_bit(LI_FLAG_COMPLETE, &li.li_flags);
+
+		flags = DLM_LKF_FORCEUNLOCK;
+		if (old_li->li_grmode >= DLM_LOCK_PW)
+			flags |= DLM_LKF_IVVALBLK;
+
+		status = dlm_unlock(f->fi_ls->ls_lockspace,
+				    old_li->li_lksb.sb_lkid, flags,
+				    &li.li_lksb, &li);
+
+		/* Must wait for it to complete as the next lock could be its
+		 * parent */
+		if (status == 0)
+			wait_for_ast(&li);
+
+		/* Unlock suceeded, free the lock_info struct. */
+		if (status == 0)
+			release_lockinfo(old_li);
+	}
+
+	remove_wait_queue(&li.li_waitq, &wq);
+
+	/*
+	 * If this is the last reference to the lockspace
+	 * then free the struct. If it's an AUTOFREE lockspace
+	 * then free the whole thing.
+	 */
+	mutex_lock(&user_ls_lock);
+	if (atomic_dec_and_test(&lsinfo->ls_refcnt)) {
+
+		if (lsinfo->ls_lockspace) {
+			if (test_bit(LS_FLAG_AUTOFREE, &lsinfo->ls_flags)) {
+				unregister_lockspace(lsinfo, 1);
+			}
+		} else {
+			kfree(lsinfo->ls_miscinfo.name);
+			kfree(lsinfo);
+		}
+	}
+	mutex_unlock(&user_ls_lock);
+	put_file_info(f);
+
+	/* Restore signals */
+	sigprocmask(SIG_SETMASK, &tmpsig, NULL);
+	recalc_sigpending();
+
+	return 0;
+}
+
+static int do_user_create_lockspace(struct file_info *fi, uint8_t cmd,
+				    struct dlm_lspace_params *kparams)
+{
+	int status;
+	struct user_ls *lsinfo;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	status = register_lockspace(kparams->name, &lsinfo, kparams->flags);
+
+	/* If it succeeded then return the minor number */
+	if (status == 0)
+		status = lsinfo->ls_miscinfo.minor;
+
+	return status;
+}
+
+static int do_user_remove_lockspace(struct file_info *fi, uint8_t cmd,
+				    struct dlm_lspace_params *kparams)
+{
+	int status;
+	int force = 1;
+	struct user_ls *lsinfo;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	mutex_lock(&user_ls_lock);
+	lsinfo = __find_lockspace(kparams->minor);
+	if (!lsinfo) {
+		mutex_unlock(&user_ls_lock);
+		return -EINVAL;
+	}
+
+	if (kparams->flags & DLM_USER_LSFLG_FORCEFREE)
+		force = 2;
+
+	status = unregister_lockspace(lsinfo, force);
+	mutex_unlock(&user_ls_lock);
+
+	return status;
+}
+
+/* Read call, might block if no ASTs are waiting.
+ * It will only ever return one message at a time, regardless
+ * of how many are pending.
+ */
+static ssize_t dlm_read(struct file *file, char __user *buffer, size_t count,
+			loff_t *ppos)
+{
+	struct file_info *fi = file->private_data;
+	struct ast_info *ast;
+	int data_size;
+	int offset;
+	DECLARE_WAITQUEUE(wait, current);
+
+	if (count < sizeof(struct dlm_lock_result))
+		return -EINVAL;
+
+	spin_lock(&fi->fi_ast_lock);
+	if (list_empty(&fi->fi_ast_list)) {
+
+		/* No waiting ASTs.
+		 * Return EOF if the lockspace been deleted.
+		 */
+		if (test_bit(LS_FLAG_DELETED, &fi->fi_ls->ls_flags))
+			return 0;
+
+		if (file->f_flags & O_NONBLOCK) {
+			spin_unlock(&fi->fi_ast_lock);
+			return -EAGAIN;
+		}
+
+		add_wait_queue(&fi->fi_wait, &wait);
+
+	repeat:
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (list_empty(&fi->fi_ast_list) &&
+		    !signal_pending(current)) {
+
+			spin_unlock(&fi->fi_ast_lock);
+			schedule();
+			spin_lock(&fi->fi_ast_lock);
+			goto repeat;
+		}
+
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&fi->fi_wait, &wait);
+
+		if (signal_pending(current)) {
+			spin_unlock(&fi->fi_ast_lock);
+			return -ERESTARTSYS;
+		}
+	}
+
+	ast = list_entry(fi->fi_ast_list.next, struct ast_info, list);
+	list_del(&ast->list);
+	spin_unlock(&fi->fi_ast_lock);
+
+	/* Work out the size of the returned data */
+	data_size = sizeof(struct dlm_lock_result);
+	if (ast->lvb_updated && ast->result.lksb.sb_lvbptr)
+		data_size += DLM_USER_LVB_LEN;
+
+	offset = sizeof(struct dlm_lock_result);
+
+	/* Room for the extended data ? */
+	if (count >= data_size) {
+
+		if (ast->lvb_updated && ast->result.lksb.sb_lvbptr) {
+			if (copy_to_user(buffer+offset,
+					 ast->result.lksb.sb_lvbptr,
+					 DLM_USER_LVB_LEN))
+				return -EFAULT;
+			ast->result.lvb_offset = offset;
+			offset += DLM_USER_LVB_LEN;
+		}
+	}
+
+	ast->result.length = data_size;
+	/* Copy the header now it has all the offsets in it */
+	if (copy_to_user(buffer, &ast->result, sizeof(struct dlm_lock_result)))
+		offset = -EFAULT;
+
+	/* If we only returned a header and there's more to come then put it
+	   back on the list */
+	if (count < data_size) {
+		spin_lock(&fi->fi_ast_lock);
+		list_add(&ast->list, &fi->fi_ast_list);
+		spin_unlock(&fi->fi_ast_lock);
+	} else
+		kfree(ast);
+	return offset;
+}
+
+static unsigned int dlm_poll(struct file *file, poll_table *wait)
+{
+	struct file_info *fi = file->private_data;
+
+	poll_wait(file, &fi->fi_wait, wait);
+
+	spin_lock(&fi->fi_ast_lock);
+	if (!list_empty(&fi->fi_ast_list)) {
+		spin_unlock(&fi->fi_ast_lock);
+		return POLLIN | POLLRDNORM;
+	}
+
+	spin_unlock(&fi->fi_ast_lock);
+	return 0;
+}
+
+static struct lock_info *allocate_lockinfo(struct file_info *fi, uint8_t cmd,
+					   struct dlm_lock_params *kparams)
+{
+	struct lock_info *li;
+
+	if (!try_module_get(THIS_MODULE))
+		return NULL;
+
+	li = kzalloc(sizeof(struct lock_info), GFP_KERNEL);
+	if (li) {
+		li->li_magic     = LOCKINFO_MAGIC;
+		li->li_file      = fi;
+		li->li_cmd       = cmd;
+		li->li_flags     = 0;
+		li->li_grmode    = -1;
+		li->li_rqmode    = -1;
+		li->li_pend_bastparam = NULL;
+		li->li_pend_bastaddr  = NULL;
+		li->li_castaddr   = NULL;
+		li->li_castparam  = NULL;
+		li->li_lksb.sb_lvbptr = NULL;
+		li->li_bastaddr  = kparams->bastaddr;
+		li->li_bastparam = kparams->bastparam;
+
+		get_file_info(fi);
+	}
+	return li;
+}
+
+static int do_user_lock(struct file_info *fi, uint8_t cmd,
+			struct dlm_lock_params *kparams)
+{
+	struct lock_info *li;
+	int status;
+
+	/*
+	 * Validate things that we need to have correct.
+	 */
+	if (!kparams->castaddr)
+		return -EINVAL;
+
+	if (!kparams->lksb)
+		return -EINVAL;
+
+	/* Persistent child locks are not available yet */
+	if ((kparams->flags & DLM_LKF_PERSISTENT) && kparams->parent)
+		return -EINVAL;
+
+        /* For conversions, there should already be a lockinfo struct,
+	   unless we are adopting an orphaned persistent lock */
+	if (kparams->flags & DLM_LKF_CONVERT) {
+
+		li = get_lockinfo(kparams->lkid);
+
+		/* If this is a persistent lock we will have to create a
+		   lockinfo again */
+		if (!li && (kparams->flags & DLM_LKF_PERSISTENT)) {
+			li = allocate_lockinfo(fi, cmd, kparams);
+			if (!li)
+				return -ENOMEM;
+
+			li->li_lksb.sb_lkid = kparams->lkid;
+			li->li_castaddr  = kparams->castaddr;
+			li->li_castparam = kparams->castparam;
+
+			/* OK, this isn;t exactly a FIRSTLOCK but it is the
+			   first time we've used this lockinfo, and if things
+			   fail we want rid of it */
+			init_MUTEX_LOCKED(&li->li_firstlock);
+			set_bit(LI_FLAG_FIRSTLOCK, &li->li_flags);
+			add_lockinfo(li);
+
+			/* TODO: do a query to get the current state ?? */
+		}
+		if (!li)
+			return -EINVAL;
+
+		if (li->li_magic != LOCKINFO_MAGIC)
+			return -EINVAL;
+
+		/* For conversions don't overwrite the current blocking AST
+		   info so that:
+		   a) if a blocking AST fires before the conversion is queued
+		      it runs the current handler
+		   b) if the conversion is cancelled, the original blocking AST
+		      declaration is active
+		   The pend_ info is made active when the conversion
+		   completes.
+		*/
+		li->li_pend_bastaddr  = kparams->bastaddr;
+		li->li_pend_bastparam = kparams->bastparam;
+	} else {
+		li = allocate_lockinfo(fi, cmd, kparams);
+		if (!li)
+			return -ENOMEM;
+
+		/* semaphore to allow us to complete our work before
+  		   the AST routine runs. In fact we only need (and use) this
+		   when the initial lock fails */
+		init_MUTEX_LOCKED(&li->li_firstlock);
+		set_bit(LI_FLAG_FIRSTLOCK, &li->li_flags);
+	}
+
+	li->li_user_lksb = kparams->lksb;
+	li->li_castaddr  = kparams->castaddr;
+	li->li_castparam = kparams->castparam;
+	li->li_lksb.sb_lkid = kparams->lkid;
+	li->li_rqmode    = kparams->mode;
+	if (kparams->flags & DLM_LKF_PERSISTENT)
+		set_bit(LI_FLAG_PERSISTENT, &li->li_flags);
+
+	/* Copy in the value block */
+	if (kparams->flags & DLM_LKF_VALBLK) {
+		if (!li->li_lksb.sb_lvbptr) {
+			li->li_lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN,
+							GFP_KERNEL);
+			if (!li->li_lksb.sb_lvbptr) {
+				status = -ENOMEM;
+				goto out_err;
+			}
+		}
+
+		memcpy(li->li_lksb.sb_lvbptr, kparams->lvb, DLM_USER_LVB_LEN);
+	}
+
+	/* Lock it ... */
+	status = dlm_lock(fi->fi_ls->ls_lockspace,
+			  kparams->mode, &li->li_lksb,
+			  kparams->flags,
+			  kparams->name, kparams->namelen,
+			  kparams->parent,
+			  ast_routine,
+			  li,
+			  (li->li_pend_bastaddr || li->li_bastaddr) ?
+			   bast_routine : NULL,
+			  kparams->range.ra_end ? &kparams->range : NULL);
+	if (status)
+		goto out_err;
+
+	/* If it succeeded (this far) with a new lock then keep track of
+	   it on the file's lockinfo list */
+	if (!status && test_bit(LI_FLAG_FIRSTLOCK, &li->li_flags)) {
+
+		spin_lock(&fi->fi_li_lock);
+		list_add(&li->li_ownerqueue, &fi->fi_li_list);
+		set_bit(LI_FLAG_ONLIST, &li->li_flags);
+		spin_unlock(&fi->fi_li_lock);
+		if (add_lockinfo(li))
+			printk(KERN_WARNING "Add lockinfo failed\n");
+
+		up(&li->li_firstlock);
+	}
+
+	/* Return the lockid as the user needs it /now/ */
+	return li->li_lksb.sb_lkid;
+
+ out_err:
+	if (test_bit(LI_FLAG_FIRSTLOCK, &li->li_flags))
+		release_lockinfo(li);
+	return status;
+
+}
+
+static int do_user_unlock(struct file_info *fi, uint8_t cmd,
+			  struct dlm_lock_params *kparams)
+{
+	struct lock_info *li;
+	int status;
+	int convert_cancel = 0;
+
+	li = get_lockinfo(kparams->lkid);
+	if (!li) {
+		li = allocate_lockinfo(fi, cmd, kparams);
+		if (!li)
+			return -ENOMEM;
+		spin_lock(&fi->fi_li_lock);
+		list_add(&li->li_ownerqueue, &fi->fi_li_list);
+		set_bit(LI_FLAG_ONLIST, &li->li_flags);
+		spin_unlock(&fi->fi_li_lock);
+	}
+
+	if (li->li_magic != LOCKINFO_MAGIC)
+		return -EINVAL;
+
+	li->li_user_lksb = kparams->lksb;
+	li->li_castparam = kparams->castparam;
+	li->li_cmd       = cmd;
+
+	/* Cancelling a conversion doesn't remove the lock...*/
+	if (kparams->flags & DLM_LKF_CANCEL && li->li_grmode != -1)
+		convert_cancel = 1;
+
+	/* Wait until dlm_lock() has completed */
+	if (!test_bit(LI_FLAG_ONLIST, &li->li_flags)) {
+		down(&li->li_firstlock);
+		up(&li->li_firstlock);
+	}
+
+	/* dlm_unlock() passes a 0 for castaddr which means don't overwrite
+	   the existing li_castaddr as that's the completion routine for
+	   unlocks. dlm_unlock_wait() specifies a new AST routine to be
+	   executed when the unlock completes. */
+	if (kparams->castaddr)
+		li->li_castaddr = kparams->castaddr;
+
+	/* Use existing lksb & astparams */
+	status = dlm_unlock(fi->fi_ls->ls_lockspace,
+			     kparams->lkid,
+			     kparams->flags, &li->li_lksb, li);
+
+	if (!status && !convert_cancel) {
+		spin_lock(&fi->fi_li_lock);
+		list_del(&li->li_ownerqueue);
+		clear_bit(LI_FLAG_ONLIST, &li->li_flags);
+		spin_unlock(&fi->fi_li_lock);
+	}
+
+	return status;
+}
+
+/* Write call, submit a locking request */
+static ssize_t dlm_write(struct file *file, const char __user *buffer,
+			 size_t count, loff_t *ppos)
+{
+	struct file_info *fi = file->private_data;
+	struct dlm_write_request *kparams;
+	sigset_t tmpsig;
+	sigset_t allsigs;
+	int status;
+
+	/* -1 because lock name is optional */
+	if (count < sizeof(struct dlm_write_request)-1)
+		return -EINVAL;
+
+	/* Has the lockspace been deleted */
+	if (fi && test_bit(LS_FLAG_DELETED, &fi->fi_ls->ls_flags))
+		return -ENOENT;
+
+	kparams = kmalloc(count, GFP_KERNEL);
+	if (!kparams)
+		return -ENOMEM;
+
+	status = -EFAULT;
+	/* Get the command info */
+	if (copy_from_user(kparams, buffer, count))
+		goto out_free;
+
+	status = -EBADE;
+	if (check_version(kparams))
+		goto out_free;
+
+	/* Block signals while we are doing this */
+	sigfillset(&allsigs);
+	sigprocmask(SIG_BLOCK, &allsigs, &tmpsig);
+
+	status = -EINVAL;
+	switch (kparams->cmd)
+	{
+	case DLM_USER_LOCK:
+		if (!fi) goto out_sig;
+		status = do_user_lock(fi, kparams->cmd, &kparams->i.lock);
+		break;
+
+	case DLM_USER_UNLOCK:
+		if (!fi) goto out_sig;
+		status = do_user_unlock(fi, kparams->cmd, &kparams->i.lock);
+		break;
+
+	case DLM_USER_CREATE_LOCKSPACE:
+		if (fi) goto out_sig;
+		status = do_user_create_lockspace(fi, kparams->cmd,
+						  &kparams->i.lspace);
+		break;
+
+	case DLM_USER_REMOVE_LOCKSPACE:
+		if (fi) goto out_sig;
+		status = do_user_remove_lockspace(fi, kparams->cmd,
+						  &kparams->i.lspace);
+		break;
+	default:
+		printk("Unknown command passed to DLM device : %d\n",
+			kparams->cmd);
+		break;
+	}
+
+ out_sig:
+	/* Restore signals */
+	sigprocmask(SIG_SETMASK, &tmpsig, NULL);
+	recalc_sigpending();
+
+ out_free:
+	kfree(kparams);
+	if (status == 0)
+		return count;
+	else
+		return status;
+}
+
+static struct file_operations _dlm_fops = {
+      .open    = dlm_open,
+      .release = dlm_close,
+      .read    = dlm_read,
+      .write   = dlm_write,
+      .poll    = dlm_poll,
+      .owner   = THIS_MODULE,
+};
+
+static struct file_operations _dlm_ctl_fops = {
+      .open    = dlm_ctl_open,
+      .release = dlm_ctl_close,
+      .write   = dlm_write,
+      .owner   = THIS_MODULE,
+};
+
+/*
+ * Create control device
+ */
+static int __init dlm_device_init(void)
+{
+	int r;
+
+	INIT_LIST_HEAD(&user_ls_list);
+	mutex_init(&user_ls_lock);
+	rwlock_init(&lockinfo_lock);
+
+	ctl_device.name = "dlm-control";
+	ctl_device.fops = &_dlm_ctl_fops;
+	ctl_device.minor = MISC_DYNAMIC_MINOR;
+
+	r = misc_register(&ctl_device);
+	if (r) {
+		printk(KERN_ERR "dlm: misc_register failed for control dev\n");
+		return r;
+	}
+
+	return 0;
+}
+
+static void __exit dlm_device_exit(void)
+{
+	misc_deregister(&ctl_device);
+}
+
+MODULE_DESCRIPTION("Distributed Lock Manager device interface");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
+module_init(dlm_device_init);
+module_exit(dlm_device_exit);
diff -urN oldtree/drivers/dlm/dir.c newtree/drivers/dlm/dir.c
--- oldtree/drivers/dlm/dir.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/dir.c	2006-02-21 15:58:32.748168080 +0000
@@ -0,0 +1,423 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "member.h"
+#include "lowcomms.h"
+#include "rcom.h"
+#include "config.h"
+#include "memory.h"
+#include "recover.h"
+#include "util.h"
+#include "lock.h"
+#include "dir.h"
+
+
+static void put_free_de(struct dlm_ls *ls, struct dlm_direntry *de)
+{
+	spin_lock(&ls->ls_recover_list_lock);
+	list_add(&de->list, &ls->ls_recover_list);
+	spin_unlock(&ls->ls_recover_list_lock);
+}
+
+static struct dlm_direntry *get_free_de(struct dlm_ls *ls, int len)
+{
+	int found = 0;
+	struct dlm_direntry *de;
+
+	spin_lock(&ls->ls_recover_list_lock);
+	list_for_each_entry(de, &ls->ls_recover_list, list) {
+		if (de->length == len) {
+			list_del(&de->list);
+			de->master_nodeid = 0;
+			memset(de->name, 0, len);
+			found = 1;
+			break;
+		}
+	}
+	spin_unlock(&ls->ls_recover_list_lock);
+
+	if (!found)
+		de = allocate_direntry(ls, len);
+	return de;
+}
+
+void dlm_clear_free_entries(struct dlm_ls *ls)
+{
+	struct dlm_direntry *de;
+
+	spin_lock(&ls->ls_recover_list_lock);
+	while (!list_empty(&ls->ls_recover_list)) {
+		de = list_entry(ls->ls_recover_list.next, struct dlm_direntry,
+				list);
+		list_del(&de->list);
+		free_direntry(de);
+	}
+	spin_unlock(&ls->ls_recover_list_lock);
+}
+
+/*
+ * We use the upper 16 bits of the hash value to select the directory node.
+ * Low bits are used for distribution of rsb's among hash buckets on each node.
+ *
+ * To give the exact range wanted (0 to num_nodes-1), we apply a modulus of
+ * num_nodes to the hash value.  This value in the desired range is used as an
+ * offset into the sorted list of nodeid's to give the particular nodeid.
+ */
+
+int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash)
+{
+	struct list_head *tmp;
+	struct dlm_member *memb = NULL;
+	uint32_t node, n = 0;
+	int nodeid;
+
+	if (ls->ls_num_nodes == 1) {
+		nodeid = dlm_our_nodeid();
+		goto out;
+	}
+
+	if (ls->ls_node_array) {
+		node = (hash >> 16) % ls->ls_total_weight;
+		nodeid = ls->ls_node_array[node];
+		goto out;
+	}
+
+	/* make_member_array() failed to kmalloc ls_node_array... */
+
+	node = (hash >> 16) % ls->ls_num_nodes;
+
+	list_for_each(tmp, &ls->ls_nodes) {
+		if (n++ != node)
+			continue;
+		memb = list_entry(tmp, struct dlm_member, list);
+		break;
+	}
+
+	DLM_ASSERT(memb , printk("num_nodes=%u n=%u node=%u\n",
+				 ls->ls_num_nodes, n, node););
+	nodeid = memb->nodeid;
+ out:
+	return nodeid;
+}
+
+int dlm_dir_nodeid(struct dlm_rsb *r)
+{
+	return dlm_hash2nodeid(r->res_ls, r->res_hash);
+}
+
+static inline uint32_t dir_hash(struct dlm_ls *ls, char *name, int len)
+{
+	uint32_t val;
+
+	val = jhash(name, len, 0);
+	val &= (ls->ls_dirtbl_size - 1);
+
+	return val;
+}
+
+static void add_entry_to_hash(struct dlm_ls *ls, struct dlm_direntry *de)
+{
+	uint32_t bucket;
+
+	bucket = dir_hash(ls, de->name, de->length);
+	list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list);
+}
+
+static struct dlm_direntry *search_bucket(struct dlm_ls *ls, char *name,
+					  int namelen, uint32_t bucket)
+{
+	struct dlm_direntry *de;
+
+	list_for_each_entry(de, &ls->ls_dirtbl[bucket].list, list) {
+		if (de->length == namelen && !memcmp(name, de->name, namelen))
+			goto out;
+	}
+	de = NULL;
+ out:
+	return de;
+}
+
+void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int namelen)
+{
+	struct dlm_direntry *de;
+	uint32_t bucket;
+
+	bucket = dir_hash(ls, name, namelen);
+
+	write_lock(&ls->ls_dirtbl[bucket].lock);
+
+	de = search_bucket(ls, name, namelen, bucket);
+
+	if (!de) {
+		log_error(ls, "remove fr %u none", nodeid);
+		goto out;
+	}
+
+	if (de->master_nodeid != nodeid) {
+		log_error(ls, "remove fr %u ID %u", nodeid, de->master_nodeid);
+		goto out;
+	}
+
+	list_del(&de->list);
+	free_direntry(de);
+ out:
+	write_unlock(&ls->ls_dirtbl[bucket].lock);
+}
+
+void dlm_dir_clear(struct dlm_ls *ls)
+{
+	struct list_head *head;
+	struct dlm_direntry *de;
+	int i;
+
+	DLM_ASSERT(list_empty(&ls->ls_recover_list), );
+
+	for (i = 0; i < ls->ls_dirtbl_size; i++) {
+		write_lock(&ls->ls_dirtbl[i].lock);
+		head = &ls->ls_dirtbl[i].list;
+		while (!list_empty(head)) {
+			de = list_entry(head->next, struct dlm_direntry, list);
+			list_del(&de->list);
+			put_free_de(ls, de);
+		}
+		write_unlock(&ls->ls_dirtbl[i].lock);
+	}
+}
+
+int dlm_recover_directory(struct dlm_ls *ls)
+{
+	struct dlm_member *memb;
+	struct dlm_direntry *de;
+	char *b, *last_name = NULL;
+	int error = -ENOMEM, last_len, count = 0;
+	uint16_t namelen;
+
+	log_debug(ls, "dlm_recover_directory");
+
+	if (dlm_no_directory(ls))
+		goto out_status;
+
+	dlm_dir_clear(ls);
+
+	last_name = kmalloc(DLM_RESNAME_MAXLEN, GFP_KERNEL);
+	if (!last_name)
+		goto out;
+
+	list_for_each_entry(memb, &ls->ls_nodes, list) {
+		memset(last_name, 0, DLM_RESNAME_MAXLEN);
+		last_len = 0;
+
+		for (;;) {
+			error = dlm_recovery_stopped(ls);
+			if (error)
+				goto out_free;
+
+			error = dlm_rcom_names(ls, memb->nodeid,
+					       last_name, last_len);
+			if (error)
+				goto out_free;
+
+			schedule();
+
+			/*
+			 * pick namelen/name pairs out of received buffer
+			 */
+
+			b = ls->ls_recover_buf + sizeof(struct dlm_rcom);
+
+			for (;;) {
+				memcpy(&namelen, b, sizeof(uint16_t));
+				namelen = be16_to_cpu(namelen);
+				b += sizeof(uint16_t);
+
+				/* namelen of 0xFFFFF marks end of names for
+				   this node; namelen of 0 marks end of the
+				   buffer */
+
+				if (namelen == 0xFFFF)
+					goto done;
+				if (!namelen)
+					break;
+
+				error = -ENOMEM;
+				de = get_free_de(ls, namelen);
+				if (!de)
+					goto out_free;
+
+				de->master_nodeid = memb->nodeid;
+				de->length = namelen;
+				last_len = namelen;
+				memcpy(de->name, b, namelen);
+				memcpy(last_name, b, namelen);
+				b += namelen;
+
+				add_entry_to_hash(ls, de);
+				count++;
+			}
+		}
+         done:
+		;
+	}
+
+ out_status:
+	error = 0;
+	dlm_set_recover_status(ls, DLM_RS_DIR);
+	log_debug(ls, "dlm_recover_directory %d entries", count);
+ out_free:
+	kfree(last_name);
+ out:
+	dlm_clear_free_entries(ls);
+	return error;
+}
+
+static int get_entry(struct dlm_ls *ls, int nodeid, char *name,
+		     int namelen, int *r_nodeid)
+{
+	struct dlm_direntry *de, *tmp;
+	uint32_t bucket;
+
+	bucket = dir_hash(ls, name, namelen);
+
+	write_lock(&ls->ls_dirtbl[bucket].lock);
+	de = search_bucket(ls, name, namelen, bucket);
+	if (de) {
+		*r_nodeid = de->master_nodeid;
+		write_unlock(&ls->ls_dirtbl[bucket].lock);
+		if (*r_nodeid == nodeid)
+			return -EEXIST;
+		return 0;
+	}
+
+	write_unlock(&ls->ls_dirtbl[bucket].lock);
+
+	de = allocate_direntry(ls, namelen);
+	if (!de)
+		return -ENOMEM;
+
+	de->master_nodeid = nodeid;
+	de->length = namelen;
+	memcpy(de->name, name, namelen);
+
+	write_lock(&ls->ls_dirtbl[bucket].lock);
+	tmp = search_bucket(ls, name, namelen, bucket);
+	if (tmp) {
+		free_direntry(de);
+		de = tmp;
+	} else {
+		list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list);
+	}
+	*r_nodeid = de->master_nodeid;
+	write_unlock(&ls->ls_dirtbl[bucket].lock);
+	return 0;
+}
+
+int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen,
+		   int *r_nodeid)
+{
+	return get_entry(ls, nodeid, name, namelen, r_nodeid);
+}
+
+/* Copy the names of master rsb's into the buffer provided.
+   Only select names whose dir node is the given nodeid. */
+
+void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen,
+ 			   char *outbuf, int outlen, int nodeid)
+{
+	struct list_head *list;
+	struct dlm_rsb *start_r = NULL, *r = NULL;
+	int offset = 0, start_namelen, error, dir_nodeid;
+	char *start_name;
+	uint16_t be_namelen;
+
+	/*
+	 * Find the rsb where we left off (or start again)
+	 */
+
+	start_namelen = inlen;
+	start_name = inbuf;
+
+	if (start_namelen > 1) {
+		/*
+		 * We could also use a find_rsb_root() function here that
+		 * searched the ls_root_list.
+		 */
+		error = dlm_find_rsb(ls, start_name, start_namelen, R_MASTER,
+				     &start_r);
+		DLM_ASSERT(!error && start_r,
+			   printk("error %d\n", error););
+		DLM_ASSERT(!list_empty(&start_r->res_root_list),
+			   dlm_print_rsb(start_r););
+		dlm_put_rsb(start_r);
+	}
+
+	/*
+	 * Send rsb names for rsb's we're master of and whose directory node
+	 * matches the requesting node.
+	 */
+
+	down_read(&ls->ls_root_sem);
+	if (start_r)
+		list = start_r->res_root_list.next;
+	else
+		list = ls->ls_root_list.next;
+
+	for (offset = 0; list != &ls->ls_root_list; list = list->next) {
+		r = list_entry(list, struct dlm_rsb, res_root_list);
+		if (r->res_nodeid)
+			continue;
+
+		dir_nodeid = dlm_dir_nodeid(r);
+		if (dir_nodeid != nodeid)
+			continue;
+
+		/*
+		 * The block ends when we can't fit the following in the
+		 * remaining buffer space:
+		 * namelen (uint16_t) +
+		 * name (r->res_length) +
+		 * end-of-block record 0x0000 (uint16_t)
+		 */
+
+		if (offset + sizeof(uint16_t)*2 + r->res_length > outlen) {
+			/* Write end-of-block record */
+			be_namelen = 0;
+			memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t));
+			offset += sizeof(uint16_t);
+			goto out;
+		}
+
+		be_namelen = cpu_to_be16(r->res_length);
+		memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t));
+		offset += sizeof(uint16_t);
+		memcpy(outbuf + offset, r->res_name, r->res_length);
+		offset += r->res_length;
+	}
+
+	/*
+	 * If we've reached the end of the list (and there's room) write a
+	 * terminating record.
+	 */
+
+	if ((list == &ls->ls_root_list) &&
+	    (offset + sizeof(uint16_t) <= outlen)) {
+		be_namelen = 0xFFFF;
+		memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t));
+		offset += sizeof(uint16_t);
+	}
+
+ out:
+	up_read(&ls->ls_root_sem);
+}
+
diff -urN oldtree/drivers/dlm/dir.h newtree/drivers/dlm/dir.h
--- oldtree/drivers/dlm/dir.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/dir.h	2006-02-21 15:58:32.595191336 +0000
@@ -0,0 +1,30 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __DIR_DOT_H__
+#define __DIR_DOT_H__
+
+
+int dlm_dir_nodeid(struct dlm_rsb *rsb);
+int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash);
+void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int len);
+void dlm_dir_clear(struct dlm_ls *ls);
+void dlm_clear_free_entries(struct dlm_ls *ls);
+int dlm_recover_directory(struct dlm_ls *ls);
+int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen,
+	int *r_nodeid);
+void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen,
+	char *outbuf, int outlen, int nodeid);
+
+#endif				/* __DIR_DOT_H__ */
+
diff -urN oldtree/drivers/dlm/dlm_internal.h newtree/drivers/dlm/dlm_internal.h
--- oldtree/drivers/dlm/dlm_internal.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/dlm_internal.h	2006-02-21 15:58:32.777163672 +0000
@@ -0,0 +1,505 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __DLM_INTERNAL_DOT_H__
+#define __DLM_INTERNAL_DOT_H__
+
+/*
+ * This is the main header file to be included in each DLM source file.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/spinlock.h>
+#include <linux/vmalloc.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/random.h>
+#include <linux/delay.h>
+#include <linux/socket.h>
+#include <linux/kthread.h>
+#include <linux/kobject.h>
+#include <linux/kref.h>
+#include <linux/kernel.h>
+#include <linux/jhash.h>
+#include <linux/mutex.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include <linux/dlm.h>
+
+#define DLM_LOCKSPACE_LEN	64
+
+/* Size of the temp buffer midcomms allocates on the stack.
+   We try to make this large enough so most messages fit.
+   FIXME: should sctp make this unnecessary? */
+
+#define DLM_INBUF_LEN		148
+
+struct dlm_ls;
+struct dlm_lkb;
+struct dlm_rsb;
+struct dlm_member;
+struct dlm_lkbtable;
+struct dlm_rsbtable;
+struct dlm_dirtable;
+struct dlm_direntry;
+struct dlm_recover;
+struct dlm_header;
+struct dlm_message;
+struct dlm_rcom;
+struct dlm_mhandle;
+
+#define log_print(fmt, args...) \
+	printk(KERN_ERR "dlm: "fmt"\n" , ##args)
+#define log_error(ls, fmt, args...) \
+	printk(KERN_ERR "dlm: %s: " fmt "\n", (ls)->ls_name , ##args)
+
+#ifdef DLM_LOG_DEBUG
+#define log_debug(ls, fmt, args...) log_error(ls, fmt, ##args)
+#else
+#define log_debug(ls, fmt, args...)
+#endif
+
+#define DLM_ASSERT(x, do) \
+{ \
+  if (!(x)) \
+  { \
+    printk(KERN_ERR "\nDLM:  Assertion failed on line %d of file %s\n" \
+               "DLM:  assertion:  \"%s\"\n" \
+               "DLM:  time = %lu\n", \
+               __LINE__, __FILE__, #x, jiffies); \
+    {do} \
+    printk("\n"); \
+    BUG(); \
+    panic("DLM:  Record message above and reboot.\n"); \
+  } \
+}
+
+
+struct dlm_direntry {
+	struct list_head	list;
+	uint32_t		master_nodeid;
+	uint16_t		length;
+	char			name[1];
+};
+
+struct dlm_dirtable {
+	struct list_head	list;
+	rwlock_t		lock;
+};
+
+struct dlm_rsbtable {
+	struct list_head	list;
+	struct list_head	toss;
+	rwlock_t		lock;
+};
+
+struct dlm_lkbtable {
+	struct list_head	list;
+	rwlock_t		lock;
+	uint16_t		counter;
+};
+
+/*
+ * Lockspace member (per node in a ls)
+ */
+
+struct dlm_member {
+	struct list_head	list;
+	int			nodeid;
+	int			weight;
+};
+
+/*
+ * Save and manage recovery state for a lockspace.
+ */
+
+struct dlm_recover {
+	struct list_head	list;
+	int			*nodeids;
+	int			node_count;
+	uint64_t		seq;
+};
+
+/*
+ * Pass input args to second stage locking function.
+ */
+
+struct dlm_args {
+	uint32_t		flags;
+	void			*astaddr;
+	long			astparam;
+	void			*bastaddr;
+	int			mode;
+	struct dlm_lksb		*lksb;
+	struct dlm_range	*range;
+};
+
+
+/*
+ * Lock block
+ *
+ * A lock can be one of three types:
+ *
+ * local copy      lock is mastered locally
+ *                 (lkb_nodeid is zero and DLM_LKF_MSTCPY is not set)
+ * process copy    lock is mastered on a remote node
+ *                 (lkb_nodeid is non-zero and DLM_LKF_MSTCPY is not set)
+ * master copy     master node's copy of a lock owned by remote node
+ *                 (lkb_nodeid is non-zero and DLM_LKF_MSTCPY is set)
+ *
+ * lkb_exflags: a copy of the most recent flags arg provided to dlm_lock or
+ * dlm_unlock.  The dlm does not modify these or use any private flags in
+ * this field; it only contains DLM_LKF_ flags from dlm.h.  These flags
+ * are sent as-is to the remote master when the lock is remote.
+ *
+ * lkb_flags: internal dlm flags (DLM_IFL_ prefix) from dlm_internal.h.
+ * Some internal flags are shared between the master and process nodes;
+ * these shared flags are kept in the lower two bytes.  One of these
+ * flags set on the master copy will be propagated to the process copy
+ * and v.v.  Other internal flags are private to the master or process
+ * node (e.g. DLM_IFL_MSTCPY).  These are kept in the high two bytes.
+ *
+ * lkb_sbflags: status block flags.  These flags are copied directly into
+ * the caller's lksb.sb_flags prior to the dlm_lock/dlm_unlock completion
+ * ast.  All defined in dlm.h with DLM_SBF_ prefix.
+ *
+ * lkb_status: the lock status indicates which rsb queue the lock is
+ * on, grant, convert, or wait.  DLM_LKSTS_ WAITING/GRANTED/CONVERT
+ *
+ * lkb_wait_type: the dlm message type (DLM_MSG_ prefix) for which a
+ * reply is needed.  Only set when the lkb is on the lockspace waiters
+ * list awaiting a reply from a remote node.
+ *
+ * lkb_nodeid: when the lkb is a local copy, nodeid is 0; when the lkb
+ * is a master copy, nodeid specifies the remote lock holder, when the
+ * lkb is a process copy, the nodeid specifies the lock master.
+ */
+
+/* lkb_ast_type */
+
+#define AST_COMP		1
+#define AST_BAST		2
+
+/* lkb_range[] */
+
+#define GR_RANGE_START		0
+#define GR_RANGE_END		1
+#define RQ_RANGE_START		2
+#define RQ_RANGE_END		3
+
+/* lkb_status */
+
+#define DLM_LKSTS_WAITING	1
+#define DLM_LKSTS_GRANTED	2
+#define DLM_LKSTS_CONVERT	3
+
+/* lkb_flags */
+
+#define DLM_IFL_MSTCPY		0x00010000
+#define DLM_IFL_RESEND		0x00020000
+#define DLM_IFL_RANGE		0x00000001
+
+struct dlm_lkb {
+	struct dlm_rsb		*lkb_resource;	/* the rsb */
+	struct kref		lkb_ref;
+	int			lkb_nodeid;	/* copied from rsb */
+	int			lkb_ownpid;	/* pid of lock owner */
+	uint32_t		lkb_id;		/* our lock ID */
+	uint32_t		lkb_remid;	/* lock ID on remote partner */
+	uint32_t		lkb_exflags;	/* external flags from caller */
+	uint32_t		lkb_sbflags;	/* lksb flags */
+	uint32_t		lkb_flags;	/* internal flags */
+	uint32_t		lkb_lvbseq;	/* lvb sequence number */
+
+	int8_t			lkb_status;     /* granted, waiting, convert */
+	int8_t			lkb_rqmode;	/* requested lock mode */
+	int8_t			lkb_grmode;	/* granted lock mode */
+	int8_t			lkb_bastmode;	/* requested mode */
+	int8_t			lkb_highbast;	/* highest mode bast sent for */
+
+	int8_t			lkb_wait_type;	/* type of reply waiting for */
+	int8_t			lkb_ast_type;	/* type of ast queued for */
+
+	struct list_head	lkb_idtbl_list;	/* lockspace lkbtbl */
+	struct list_head	lkb_statequeue;	/* rsb g/c/w list */
+	struct list_head	lkb_rsb_lookup;	/* waiting for rsb lookup */
+	struct list_head	lkb_wait_reply;	/* waiting for remote reply */
+	struct list_head	lkb_astqueue;	/* need ast to be sent */
+
+	uint64_t		*lkb_range;	/* array of gr/rq ranges */
+	char			*lkb_lvbptr;
+	struct dlm_lksb		*lkb_lksb;      /* caller's status block */
+	void			*lkb_astaddr;	/* caller's ast function */
+	void			*lkb_bastaddr;	/* caller's bast function */
+	long			lkb_astparam;	/* caller's ast arg */
+};
+
+
+struct dlm_rsb {
+	struct dlm_ls		*res_ls;	/* the lockspace */
+	struct kref		res_ref;
+	struct mutex		res_mutex;
+	unsigned long		res_flags;
+	int			res_length;	/* length of rsb name */
+	int			res_nodeid;
+	uint32_t                res_lvbseq;
+	uint32_t		res_hash;
+	uint32_t		res_bucket;	/* rsbtbl */
+	unsigned long		res_toss_time;
+	uint32_t		res_first_lkid;
+	struct list_head	res_lookup;	/* lkbs waiting on first */
+	struct list_head	res_hashchain;	/* rsbtbl */
+	struct list_head	res_grantqueue;
+	struct list_head	res_convertqueue;
+	struct list_head	res_waitqueue;
+
+	struct list_head	res_root_list;	    /* used for recovery */
+	struct list_head	res_recover_list;   /* used for recovery */
+	int			res_recover_locks_count;
+
+	char			*res_lvbptr;
+	char			res_name[1];
+};
+
+/* find_rsb() flags */
+
+#define R_MASTER		1	/* only return rsb if it's a master */
+#define R_CREATE		2	/* create/add rsb if not found */
+
+/* rsb_flags */
+
+enum rsb_flags {
+	RSB_MASTER_UNCERTAIN,
+	RSB_VALNOTVALID,
+	RSB_VALNOTVALID_PREV,
+	RSB_NEW_MASTER,
+	RSB_NEW_MASTER2,
+	RSB_RECOVER_CONVERT,
+};
+
+static inline void rsb_set_flag(struct dlm_rsb *r, enum rsb_flags flag)
+{
+	__set_bit(flag, &r->res_flags);
+}
+
+static inline void rsb_clear_flag(struct dlm_rsb *r, enum rsb_flags flag)
+{
+	__clear_bit(flag, &r->res_flags);
+}
+
+static inline int rsb_flag(struct dlm_rsb *r, enum rsb_flags flag)
+{
+	return test_bit(flag, &r->res_flags);
+}
+
+
+/* dlm_header is first element of all structs sent between nodes */
+
+#define DLM_HEADER_MAJOR	0x00020000
+#define DLM_HEADER_MINOR	0x00000001
+
+#define DLM_MSG			1
+#define DLM_RCOM		2
+
+struct dlm_header {
+	uint32_t		h_version;
+	uint32_t		h_lockspace;
+	uint32_t		h_nodeid;	/* nodeid of sender */
+	uint16_t		h_length;
+	uint8_t			h_cmd;		/* DLM_MSG, DLM_RCOM */
+	uint8_t			h_pad;
+};
+
+
+#define DLM_MSG_REQUEST		1
+#define DLM_MSG_CONVERT		2
+#define DLM_MSG_UNLOCK		3
+#define DLM_MSG_CANCEL		4
+#define DLM_MSG_REQUEST_REPLY	5
+#define DLM_MSG_CONVERT_REPLY	6
+#define DLM_MSG_UNLOCK_REPLY	7
+#define DLM_MSG_CANCEL_REPLY	8
+#define DLM_MSG_GRANT		9
+#define DLM_MSG_BAST		10
+#define DLM_MSG_LOOKUP		11
+#define DLM_MSG_REMOVE		12
+#define DLM_MSG_LOOKUP_REPLY	13
+
+struct dlm_message {
+	struct dlm_header	m_header;
+	uint32_t		m_type;		/* DLM_MSG_ */
+	uint32_t		m_nodeid;
+	uint32_t		m_pid;
+	uint32_t		m_lkid;		/* lkid on sender */
+	uint32_t		m_remid;	/* lkid on receiver */
+	uint32_t		m_parent_lkid;
+	uint32_t		m_parent_remid;
+	uint32_t		m_exflags;
+	uint32_t		m_sbflags;
+	uint32_t		m_flags;
+	uint32_t		m_lvbseq;
+	uint32_t		m_hash;
+	int			m_status;
+	int			m_grmode;
+	int			m_rqmode;
+	int			m_bastmode;
+	int			m_asts;
+	int			m_result;	/* 0 or -EXXX */
+	uint64_t		m_range[2];
+	char			m_extra[0];	/* name or lvb */
+};
+
+
+#define DLM_RS_NODES		0x00000001
+#define DLM_RS_NODES_ALL	0x00000002
+#define DLM_RS_DIR		0x00000004
+#define DLM_RS_DIR_ALL		0x00000008
+#define DLM_RS_LOCKS		0x00000010
+#define DLM_RS_LOCKS_ALL	0x00000020
+#define DLM_RS_DONE		0x00000040
+#define DLM_RS_DONE_ALL		0x00000080
+
+#define DLM_RCOM_STATUS		1
+#define DLM_RCOM_NAMES		2
+#define DLM_RCOM_LOOKUP		3
+#define DLM_RCOM_LOCK		4
+#define DLM_RCOM_STATUS_REPLY	5
+#define DLM_RCOM_NAMES_REPLY	6
+#define DLM_RCOM_LOOKUP_REPLY	7
+#define DLM_RCOM_LOCK_REPLY	8
+
+struct dlm_rcom {
+	struct dlm_header	rc_header;
+	uint32_t		rc_type;	/* DLM_RCOM_ */
+	int			rc_result;	/* multi-purpose */
+	uint64_t		rc_id;		/* match reply with request */
+	char			rc_buf[0];
+};
+
+struct rcom_config {
+	uint32_t		rf_lvblen;
+	uint32_t		rf_lsflags;
+	uint64_t		rf_unused;
+};
+
+struct rcom_lock {
+	uint32_t		rl_ownpid;
+	uint32_t		rl_lkid;
+	uint32_t		rl_remid;
+	uint32_t		rl_parent_lkid;
+	uint32_t		rl_parent_remid;
+	uint32_t		rl_exflags;
+	uint32_t		rl_flags;
+	uint32_t		rl_lvbseq;
+	int			rl_result;
+	int8_t			rl_rqmode;
+	int8_t			rl_grmode;
+	int8_t			rl_status;
+	int8_t			rl_asts;
+	uint16_t		rl_wait_type;
+	uint16_t		rl_namelen;
+	uint64_t		rl_range[4];
+	char			rl_name[DLM_RESNAME_MAXLEN];
+	char			rl_lvb[0];
+};
+
+struct dlm_ls {
+	struct list_head	ls_list;	/* list of lockspaces */
+	uint32_t		ls_global_id;	/* global unique lockspace ID */
+	uint32_t		ls_exflags;
+	int			ls_lvblen;
+	int			ls_count;	/* reference count */
+	unsigned long		ls_flags;	/* LSFL_ */
+	struct kobject		ls_kobj;
+
+	struct dlm_rsbtable	*ls_rsbtbl;
+	uint32_t		ls_rsbtbl_size;
+
+	struct dlm_lkbtable	*ls_lkbtbl;
+	uint32_t		ls_lkbtbl_size;
+
+	struct dlm_dirtable	*ls_dirtbl;
+	uint32_t		ls_dirtbl_size;
+
+	struct mutex		ls_waiters_mutex;
+	struct list_head	ls_waiters;	/* lkbs needing a reply */
+
+	struct list_head	ls_nodes;	/* current nodes in ls */
+	struct list_head	ls_nodes_gone;	/* dead node list, recovery */
+	int			ls_num_nodes;	/* number of nodes in ls */
+	int			ls_low_nodeid;
+	int			ls_total_weight;
+	int			*ls_node_array;
+
+	struct dlm_rsb		ls_stub_rsb;	/* for returning errors */
+	struct dlm_lkb		ls_stub_lkb;	/* for returning errors */
+	struct dlm_message	ls_stub_ms;	/* for faking a reply */
+
+	struct dentry		*ls_debug_dentry; /* debugfs */
+
+	wait_queue_head_t	ls_uevent_wait;	/* user part of join/leave */
+	int			ls_uevent_result;
+
+	/* recovery related */
+
+	struct timer_list	ls_timer;
+	struct task_struct	*ls_recoverd_task;
+	struct mutex		ls_recoverd_active;
+	spinlock_t		ls_recover_lock;
+	uint32_t		ls_recover_status; /* DLM_RS_ */
+	uint64_t		ls_recover_seq;
+	struct dlm_recover	*ls_recover_args;
+	struct rw_semaphore	ls_in_recovery;	/* block local requests */
+	struct list_head	ls_requestqueue;/* queue remote requests */
+	struct mutex		ls_requestqueue_mutex;
+	char			*ls_recover_buf;
+	struct list_head	ls_recover_list;
+	spinlock_t		ls_recover_list_lock;
+	int			ls_recover_list_count;
+	wait_queue_head_t	ls_wait_general;
+
+	struct list_head	ls_root_list;	/* root resources */
+	struct rw_semaphore	ls_root_sem;	/* protect root_list */
+
+	int			ls_namelen;
+	char			ls_name[1];
+};
+
+#define LSFL_WORK		0
+#define LSFL_RUNNING		1
+#define LSFL_RECOVERY_STOP	2
+#define LSFL_RCOM_READY		3
+#define LSFL_UEVENT_WAIT	4
+
+static inline int dlm_locking_stopped(struct dlm_ls *ls)
+{
+	return !test_bit(LSFL_RUNNING, &ls->ls_flags);
+}
+
+static inline int dlm_recovery_stopped(struct dlm_ls *ls)
+{
+	return test_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
+}
+
+static inline int dlm_no_directory(struct dlm_ls *ls)
+{
+	return (ls->ls_exflags & DLM_LSFL_NODIR) ? 1 : 0;
+}
+
+#endif				/* __DLM_INTERNAL_DOT_H__ */
+
diff -urN oldtree/drivers/dlm/lock.c newtree/drivers/dlm/lock.c
--- oldtree/drivers/dlm/lock.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/lock.c	2006-02-21 15:58:32.781163064 +0000
@@ -0,0 +1,3610 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+/* Central locking logic has four stages:
+
+   dlm_lock()
+   dlm_unlock()
+
+   request_lock(ls, lkb)
+   convert_lock(ls, lkb)
+   unlock_lock(ls, lkb)
+   cancel_lock(ls, lkb)
+
+   _request_lock(r, lkb)
+   _convert_lock(r, lkb)
+   _unlock_lock(r, lkb)
+   _cancel_lock(r, lkb)
+
+   do_request(r, lkb)
+   do_convert(r, lkb)
+   do_unlock(r, lkb)
+   do_cancel(r, lkb)
+
+   Stage 1 (lock, unlock) is mainly about checking input args and
+   splitting into one of the four main operations:
+
+       dlm_lock          = request_lock
+       dlm_lock+CONVERT  = convert_lock
+       dlm_unlock        = unlock_lock
+       dlm_unlock+CANCEL = cancel_lock
+
+   Stage 2, xxxx_lock(), just finds and locks the relevant rsb which is
+   provided to the next stage.
+
+   Stage 3, _xxxx_lock(), determines if the operation is local or remote.
+   When remote, it calls send_xxxx(), when local it calls do_xxxx().
+
+   Stage 4, do_xxxx(), is the guts of the operation.  It manipulates the
+   given rsb and lkb and queues callbacks.
+
+   For remote operations, send_xxxx() results in the corresponding do_xxxx()
+   function being executed on the remote node.  The connecting send/receive
+   calls on local (L) and remote (R) nodes:
+
+   L: send_xxxx()              ->  R: receive_xxxx()
+                                   R: do_xxxx()
+   L: receive_xxxx_reply()     <-  R: send_xxxx_reply()
+*/
+
+#include "dlm_internal.h"
+#include "memory.h"
+#include "lowcomms.h"
+#include "requestqueue.h"
+#include "util.h"
+#include "dir.h"
+#include "member.h"
+#include "lockspace.h"
+#include "ast.h"
+#include "lock.h"
+#include "rcom.h"
+#include "recover.h"
+#include "lvb_table.h"
+#include "config.h"
+
+static int send_request(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static int send_convert(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static int send_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static int send_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static int send_grant(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static int send_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int mode);
+static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static int send_remove(struct dlm_rsb *r);
+static int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
+				    struct dlm_message *ms);
+static int receive_extralen(struct dlm_message *ms);
+
+/*
+ * Lock compatibilty matrix - thanks Steve
+ * UN = Unlocked state. Not really a state, used as a flag
+ * PD = Padding. Used to make the matrix a nice power of two in size
+ * Other states are the same as the VMS DLM.
+ * Usage: matrix[grmode+1][rqmode+1]  (although m[rq+1][gr+1] is the same)
+ */
+
+static const int __dlm_compat_matrix[8][8] = {
+      /* UN NL CR CW PR PW EX PD */
+        {1, 1, 1, 1, 1, 1, 1, 0},       /* UN */
+        {1, 1, 1, 1, 1, 1, 1, 0},       /* NL */
+        {1, 1, 1, 1, 1, 1, 0, 0},       /* CR */
+        {1, 1, 1, 1, 0, 0, 0, 0},       /* CW */
+        {1, 1, 1, 0, 1, 0, 0, 0},       /* PR */
+        {1, 1, 1, 0, 0, 0, 0, 0},       /* PW */
+        {1, 1, 0, 0, 0, 0, 0, 0},       /* EX */
+        {0, 0, 0, 0, 0, 0, 0, 0}        /* PD */
+};
+
+/*
+ * This defines the direction of transfer of LVB data.
+ * Granted mode is the row; requested mode is the column.
+ * Usage: matrix[grmode+1][rqmode+1]
+ * 1 = LVB is returned to the caller
+ * 0 = LVB is written to the resource
+ * -1 = nothing happens to the LVB
+ */
+
+const int dlm_lvb_operations[8][8] = {
+        /* UN   NL  CR  CW  PR  PW  EX  PD*/
+        {  -1,  1,  1,  1,  1,  1,  1, -1 }, /* UN */
+        {  -1,  1,  1,  1,  1,  1,  1,  0 }, /* NL */
+        {  -1, -1,  1,  1,  1,  1,  1,  0 }, /* CR */
+        {  -1, -1, -1,  1,  1,  1,  1,  0 }, /* CW */
+        {  -1, -1, -1, -1,  1,  1,  1,  0 }, /* PR */
+        {  -1,  0,  0,  0,  0,  0,  1,  0 }, /* PW */
+        {  -1,  0,  0,  0,  0,  0,  0,  0 }, /* EX */
+        {  -1,  0,  0,  0,  0,  0,  0,  0 }  /* PD */
+};
+EXPORT_SYMBOL_GPL(dlm_lvb_operations);
+
+#define modes_compat(gr, rq) \
+	__dlm_compat_matrix[(gr)->lkb_grmode + 1][(rq)->lkb_rqmode + 1]
+
+int dlm_modes_compat(int mode1, int mode2)
+{
+	return __dlm_compat_matrix[mode1 + 1][mode2 + 1];
+}
+
+/*
+ * Compatibility matrix for conversions with QUECVT set.
+ * Granted mode is the row; requested mode is the column.
+ * Usage: matrix[grmode+1][rqmode+1]
+ */
+
+static const int __quecvt_compat_matrix[8][8] = {
+      /* UN NL CR CW PR PW EX PD */
+        {0, 0, 0, 0, 0, 0, 0, 0},       /* UN */
+        {0, 0, 1, 1, 1, 1, 1, 0},       /* NL */
+        {0, 0, 0, 1, 1, 1, 1, 0},       /* CR */
+        {0, 0, 0, 0, 1, 1, 1, 0},       /* CW */
+        {0, 0, 0, 1, 0, 1, 1, 0},       /* PR */
+        {0, 0, 0, 0, 0, 0, 1, 0},       /* PW */
+        {0, 0, 0, 0, 0, 0, 0, 0},       /* EX */
+        {0, 0, 0, 0, 0, 0, 0, 0}        /* PD */
+};
+
+static void dlm_print_lkb(struct dlm_lkb *lkb)
+{
+	printk(KERN_ERR "lkb: nodeid %d id %x remid %x exflags %x flags %x\n"
+	       "     status %d rqmode %d grmode %d wait_type %d ast_type %d\n",
+	       lkb->lkb_nodeid, lkb->lkb_id, lkb->lkb_remid, lkb->lkb_exflags,
+	       lkb->lkb_flags, lkb->lkb_status, lkb->lkb_rqmode,
+	       lkb->lkb_grmode, lkb->lkb_wait_type, lkb->lkb_ast_type);
+}
+
+void dlm_print_rsb(struct dlm_rsb *r)
+{
+	printk(KERN_ERR "rsb: nodeid %d flags %lx first %x rlc %d name %s\n",
+	       r->res_nodeid, r->res_flags, r->res_first_lkid,
+	       r->res_recover_locks_count, r->res_name);
+}
+
+/* Threads cannot use the lockspace while it's being recovered */
+
+static inline void lock_recovery(struct dlm_ls *ls)
+{
+	down_read(&ls->ls_in_recovery);
+}
+
+static inline void unlock_recovery(struct dlm_ls *ls)
+{
+	up_read(&ls->ls_in_recovery);
+}
+
+static inline int lock_recovery_try(struct dlm_ls *ls)
+{
+	return down_read_trylock(&ls->ls_in_recovery);
+}
+
+static inline int can_be_queued(struct dlm_lkb *lkb)
+{
+	return !(lkb->lkb_exflags & DLM_LKF_NOQUEUE);
+}
+
+static inline int force_blocking_asts(struct dlm_lkb *lkb)
+{
+	return (lkb->lkb_exflags & DLM_LKF_NOQUEUEBAST);
+}
+
+static inline int is_demoted(struct dlm_lkb *lkb)
+{
+	return (lkb->lkb_sbflags & DLM_SBF_DEMOTED);
+}
+
+static inline int is_remote(struct dlm_rsb *r)
+{
+	DLM_ASSERT(r->res_nodeid >= 0, dlm_print_rsb(r););
+	return !!r->res_nodeid;
+}
+
+static inline int is_process_copy(struct dlm_lkb *lkb)
+{
+	return (lkb->lkb_nodeid && !(lkb->lkb_flags & DLM_IFL_MSTCPY));
+}
+
+static inline int is_master_copy(struct dlm_lkb *lkb)
+{
+	if (lkb->lkb_flags & DLM_IFL_MSTCPY)
+		DLM_ASSERT(lkb->lkb_nodeid, dlm_print_lkb(lkb););
+	return (lkb->lkb_flags & DLM_IFL_MSTCPY) ? 1 : 0;
+}
+
+static inline int middle_conversion(struct dlm_lkb *lkb)
+{
+	if ((lkb->lkb_grmode==DLM_LOCK_PR && lkb->lkb_rqmode==DLM_LOCK_CW) ||
+	    (lkb->lkb_rqmode==DLM_LOCK_PR && lkb->lkb_grmode==DLM_LOCK_CW))
+		return 1;
+	return 0;
+}
+
+static inline int down_conversion(struct dlm_lkb *lkb)
+{
+	return (!middle_conversion(lkb) && lkb->lkb_rqmode < lkb->lkb_grmode);
+}
+
+static void queue_cast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
+{
+	if (is_master_copy(lkb))
+		return;
+
+	DLM_ASSERT(lkb->lkb_lksb, dlm_print_lkb(lkb););
+
+	lkb->lkb_lksb->sb_status = rv;
+	lkb->lkb_lksb->sb_flags = lkb->lkb_sbflags;
+
+	dlm_add_ast(lkb, AST_COMP);
+}
+
+static void queue_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rqmode)
+{
+	if (is_master_copy(lkb))
+		send_bast(r, lkb, rqmode);
+	else {
+		lkb->lkb_bastmode = rqmode;
+		dlm_add_ast(lkb, AST_BAST);
+	}
+}
+
+/*
+ * Basic operations on rsb's and lkb's
+ */
+
+static struct dlm_rsb *create_rsb(struct dlm_ls *ls, char *name, int len)
+{
+	struct dlm_rsb *r;
+
+	r = allocate_rsb(ls, len);
+	if (!r)
+		return NULL;
+
+	r->res_ls = ls;
+	r->res_length = len;
+	memcpy(r->res_name, name, len);
+	mutex_init(&r->res_mutex);
+
+	INIT_LIST_HEAD(&r->res_lookup);
+	INIT_LIST_HEAD(&r->res_grantqueue);
+	INIT_LIST_HEAD(&r->res_convertqueue);
+	INIT_LIST_HEAD(&r->res_waitqueue);
+	INIT_LIST_HEAD(&r->res_root_list);
+	INIT_LIST_HEAD(&r->res_recover_list);
+
+	return r;
+}
+
+static int search_rsb_list(struct list_head *head, char *name, int len,
+			   unsigned int flags, struct dlm_rsb **r_ret)
+{
+	struct dlm_rsb *r;
+	int error = 0;
+
+	list_for_each_entry(r, head, res_hashchain) {
+		if (len == r->res_length && !memcmp(name, r->res_name, len))
+			goto found;
+	}
+	return -ENOENT;
+
+ found:
+	if (r->res_nodeid && (flags & R_MASTER))
+		error = -ENOTBLK;
+	*r_ret = r;
+	return error;
+}
+
+static int _search_rsb(struct dlm_ls *ls, char *name, int len, int b,
+		       unsigned int flags, struct dlm_rsb **r_ret)
+{
+	struct dlm_rsb *r;
+	int error;
+
+	error = search_rsb_list(&ls->ls_rsbtbl[b].list, name, len, flags, &r);
+	if (!error) {
+		kref_get(&r->res_ref);
+		goto out;
+	}
+	error = search_rsb_list(&ls->ls_rsbtbl[b].toss, name, len, flags, &r);
+	if (error)
+		goto out;
+
+	list_move(&r->res_hashchain, &ls->ls_rsbtbl[b].list);
+
+	if (dlm_no_directory(ls))
+		goto out;
+
+	if (r->res_nodeid == -1) {
+		rsb_clear_flag(r, RSB_MASTER_UNCERTAIN);
+		r->res_first_lkid = 0;
+	} else if (r->res_nodeid > 0) {
+		rsb_set_flag(r, RSB_MASTER_UNCERTAIN);
+		r->res_first_lkid = 0;
+	} else {
+		DLM_ASSERT(r->res_nodeid == 0, dlm_print_rsb(r););
+		DLM_ASSERT(!rsb_flag(r, RSB_MASTER_UNCERTAIN),);
+	}
+ out:
+	*r_ret = r;
+	return error;
+}
+
+static int search_rsb(struct dlm_ls *ls, char *name, int len, int b,
+		      unsigned int flags, struct dlm_rsb **r_ret)
+{
+	int error;
+	write_lock(&ls->ls_rsbtbl[b].lock);
+	error = _search_rsb(ls, name, len, b, flags, r_ret);
+	write_unlock(&ls->ls_rsbtbl[b].lock);
+	return error;
+}
+
+/*
+ * Find rsb in rsbtbl and potentially create/add one
+ *
+ * Delaying the release of rsb's has a similar benefit to applications keeping
+ * NL locks on an rsb, but without the guarantee that the cached master value
+ * will still be valid when the rsb is reused.  Apps aren't always smart enough
+ * to keep NL locks on an rsb that they may lock again shortly; this can lead
+ * to excessive master lookups and removals if we don't delay the release.
+ *
+ * Searching for an rsb means looking through both the normal list and toss
+ * list.  When found on the toss list the rsb is moved to the normal list with
+ * ref count of 1; when found on normal list the ref count is incremented.
+ */
+
+static int find_rsb(struct dlm_ls *ls, char *name, int namelen,
+		    unsigned int flags, struct dlm_rsb **r_ret)
+{
+	struct dlm_rsb *r, *tmp;
+	uint32_t hash, bucket;
+	int error = 0;
+
+	if (dlm_no_directory(ls))
+		flags |= R_CREATE;
+
+	hash = jhash(name, namelen, 0);
+	bucket = hash & (ls->ls_rsbtbl_size - 1);
+
+	error = search_rsb(ls, name, namelen, bucket, flags, &r);
+	if (!error)
+		goto out;
+
+	if (error == -ENOENT && !(flags & R_CREATE))
+		goto out;
+
+	/* the rsb was found but wasn't a master copy */
+	if (error == -ENOTBLK)
+		goto out;
+
+	error = -ENOMEM;
+	r = create_rsb(ls, name, namelen);
+	if (!r)
+		goto out;
+
+	r->res_hash = hash;
+	r->res_bucket = bucket;
+	r->res_nodeid = -1;
+	kref_init(&r->res_ref);
+
+	/* With no directory, the master can be set immediately */
+	if (dlm_no_directory(ls)) {
+		int nodeid = dlm_dir_nodeid(r);
+		if (nodeid == dlm_our_nodeid())
+			nodeid = 0;
+		r->res_nodeid = nodeid;
+	}
+
+	write_lock(&ls->ls_rsbtbl[bucket].lock);
+	error = _search_rsb(ls, name, namelen, bucket, 0, &tmp);
+	if (!error) {
+		write_unlock(&ls->ls_rsbtbl[bucket].lock);
+		free_rsb(r);
+		r = tmp;
+		goto out;
+	}
+	list_add(&r->res_hashchain, &ls->ls_rsbtbl[bucket].list);
+	write_unlock(&ls->ls_rsbtbl[bucket].lock);
+	error = 0;
+ out:
+	*r_ret = r;
+	return error;
+}
+
+int dlm_find_rsb(struct dlm_ls *ls, char *name, int namelen,
+		 unsigned int flags, struct dlm_rsb **r_ret)
+{
+	return find_rsb(ls, name, namelen, flags, r_ret);
+}
+
+/* This is only called to add a reference when the code already holds
+   a valid reference to the rsb, so there's no need for locking. */
+
+static inline void hold_rsb(struct dlm_rsb *r)
+{
+	kref_get(&r->res_ref);
+}
+
+void dlm_hold_rsb(struct dlm_rsb *r)
+{
+	hold_rsb(r);
+}
+
+static void toss_rsb(struct kref *kref)
+{
+	struct dlm_rsb *r = container_of(kref, struct dlm_rsb, res_ref);
+	struct dlm_ls *ls = r->res_ls;
+
+	DLM_ASSERT(list_empty(&r->res_root_list), dlm_print_rsb(r););
+	kref_init(&r->res_ref);
+	list_move(&r->res_hashchain, &ls->ls_rsbtbl[r->res_bucket].toss);
+	r->res_toss_time = jiffies;
+	if (r->res_lvbptr) {
+		free_lvb(r->res_lvbptr);
+		r->res_lvbptr = NULL;
+	}
+}
+
+/* When all references to the rsb are gone it's transfered to
+   the tossed list for later disposal. */
+
+static void put_rsb(struct dlm_rsb *r)
+{
+	struct dlm_ls *ls = r->res_ls;
+	uint32_t bucket = r->res_bucket;
+
+	write_lock(&ls->ls_rsbtbl[bucket].lock);
+	kref_put(&r->res_ref, toss_rsb);
+	write_unlock(&ls->ls_rsbtbl[bucket].lock);
+}
+
+void dlm_put_rsb(struct dlm_rsb *r)
+{
+	put_rsb(r);
+}
+
+/* See comment for unhold_lkb */
+
+static void unhold_rsb(struct dlm_rsb *r)
+{
+	int rv;
+	rv = kref_put(&r->res_ref, toss_rsb);
+	DLM_ASSERT(!rv, dlm_print_rsb(r););
+}
+
+static void kill_rsb(struct kref *kref)
+{
+	struct dlm_rsb *r = container_of(kref, struct dlm_rsb, res_ref);
+
+	/* All work is done after the return from kref_put() so we
+	   can release the write_lock before the remove and free. */
+
+	DLM_ASSERT(list_empty(&r->res_lookup),);
+	DLM_ASSERT(list_empty(&r->res_grantqueue),);
+	DLM_ASSERT(list_empty(&r->res_convertqueue),);
+	DLM_ASSERT(list_empty(&r->res_waitqueue),);
+	DLM_ASSERT(list_empty(&r->res_root_list),);
+	DLM_ASSERT(list_empty(&r->res_recover_list),);
+}
+
+/* Attaching/detaching lkb's from rsb's is for rsb reference counting.
+   The rsb must exist as long as any lkb's for it do. */
+
+static void attach_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	hold_rsb(r);
+	lkb->lkb_resource = r;
+}
+
+static void detach_lkb(struct dlm_lkb *lkb)
+{
+	if (lkb->lkb_resource) {
+		put_rsb(lkb->lkb_resource);
+		lkb->lkb_resource = NULL;
+	}
+}
+
+static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
+{
+	struct dlm_lkb *lkb, *tmp;
+	uint32_t lkid = 0;
+	uint16_t bucket;
+
+	lkb = allocate_lkb(ls);
+	if (!lkb)
+		return -ENOMEM;
+
+	lkb->lkb_nodeid = -1;
+	lkb->lkb_grmode = DLM_LOCK_IV;
+	kref_init(&lkb->lkb_ref);
+
+	get_random_bytes(&bucket, sizeof(bucket));
+	bucket &= (ls->ls_lkbtbl_size - 1);
+
+	write_lock(&ls->ls_lkbtbl[bucket].lock);
+
+	/* counter can roll over so we must verify lkid is not in use */
+
+	while (lkid == 0) {
+		lkid = bucket | (ls->ls_lkbtbl[bucket].counter++ << 16);
+
+		list_for_each_entry(tmp, &ls->ls_lkbtbl[bucket].list,
+				    lkb_idtbl_list) {
+			if (tmp->lkb_id != lkid)
+				continue;
+			lkid = 0;
+			break;
+		}
+	}
+
+	lkb->lkb_id = lkid;
+	list_add(&lkb->lkb_idtbl_list, &ls->ls_lkbtbl[bucket].list);
+	write_unlock(&ls->ls_lkbtbl[bucket].lock);
+
+	*lkb_ret = lkb;
+	return 0;
+}
+
+static struct dlm_lkb *__find_lkb(struct dlm_ls *ls, uint32_t lkid)
+{
+	uint16_t bucket = lkid & 0xFFFF;
+	struct dlm_lkb *lkb;
+
+	list_for_each_entry(lkb, &ls->ls_lkbtbl[bucket].list, lkb_idtbl_list) {
+		if (lkb->lkb_id == lkid)
+			return lkb;
+	}
+	return NULL;
+}
+
+static int find_lkb(struct dlm_ls *ls, uint32_t lkid, struct dlm_lkb **lkb_ret)
+{
+	struct dlm_lkb *lkb;
+	uint16_t bucket = lkid & 0xFFFF;
+
+	if (bucket >= ls->ls_lkbtbl_size)
+		return -EBADSLT;
+
+	read_lock(&ls->ls_lkbtbl[bucket].lock);
+	lkb = __find_lkb(ls, lkid);
+	if (lkb)
+		kref_get(&lkb->lkb_ref);
+	read_unlock(&ls->ls_lkbtbl[bucket].lock);
+
+	*lkb_ret = lkb;
+	return lkb ? 0 : -ENOENT;
+}
+
+static void kill_lkb(struct kref *kref)
+{
+	struct dlm_lkb *lkb = container_of(kref, struct dlm_lkb, lkb_ref);
+
+	/* All work is done after the return from kref_put() so we
+	   can release the write_lock before the detach_lkb */
+
+	DLM_ASSERT(!lkb->lkb_status, dlm_print_lkb(lkb););
+}
+
+static int put_lkb(struct dlm_lkb *lkb)
+{
+	struct dlm_ls *ls = lkb->lkb_resource->res_ls;
+	uint16_t bucket = lkb->lkb_id & 0xFFFF;
+
+	write_lock(&ls->ls_lkbtbl[bucket].lock);
+	if (kref_put(&lkb->lkb_ref, kill_lkb)) {
+		list_del(&lkb->lkb_idtbl_list);
+		write_unlock(&ls->ls_lkbtbl[bucket].lock);
+
+		detach_lkb(lkb);
+
+		/* for local/process lkbs, lvbptr points to caller's lksb */
+		if (lkb->lkb_lvbptr && is_master_copy(lkb))
+			free_lvb(lkb->lkb_lvbptr);
+		if (lkb->lkb_range)
+			free_range(lkb->lkb_range);
+		free_lkb(lkb);
+		return 1;
+	} else {
+		write_unlock(&ls->ls_lkbtbl[bucket].lock);
+		return 0;
+	}
+}
+
+int dlm_put_lkb(struct dlm_lkb *lkb)
+{
+	return put_lkb(lkb);
+}
+
+/* This is only called to add a reference when the code already holds
+   a valid reference to the lkb, so there's no need for locking. */
+
+static inline void hold_lkb(struct dlm_lkb *lkb)
+{
+	kref_get(&lkb->lkb_ref);
+}
+
+/* This is called when we need to remove a reference and are certain
+   it's not the last ref.  e.g. del_lkb is always called between a
+   find_lkb/put_lkb and is always the inverse of a previous add_lkb.
+   put_lkb would work fine, but would involve unnecessary locking */
+
+static inline void unhold_lkb(struct dlm_lkb *lkb)
+{
+	int rv;
+	rv = kref_put(&lkb->lkb_ref, kill_lkb);
+	DLM_ASSERT(!rv, dlm_print_lkb(lkb););
+}
+
+static void lkb_add_ordered(struct list_head *new, struct list_head *head,
+			    int mode)
+{
+	struct dlm_lkb *lkb = NULL;
+
+	list_for_each_entry(lkb, head, lkb_statequeue)
+		if (lkb->lkb_rqmode < mode)
+			break;
+
+	if (!lkb)
+		list_add_tail(new, head);
+	else
+		__list_add(new, lkb->lkb_statequeue.prev, &lkb->lkb_statequeue);
+}
+
+/* add/remove lkb to rsb's grant/convert/wait queue */
+
+static void add_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int status)
+{
+	kref_get(&lkb->lkb_ref);
+
+	DLM_ASSERT(!lkb->lkb_status, dlm_print_lkb(lkb););
+
+	lkb->lkb_status = status;
+
+	switch (status) {
+	case DLM_LKSTS_WAITING:
+		if (lkb->lkb_exflags & DLM_LKF_HEADQUE)
+			list_add(&lkb->lkb_statequeue, &r->res_waitqueue);
+		else
+			list_add_tail(&lkb->lkb_statequeue, &r->res_waitqueue);
+		break;
+	case DLM_LKSTS_GRANTED:
+		/* convention says granted locks kept in order of grmode */
+		lkb_add_ordered(&lkb->lkb_statequeue, &r->res_grantqueue,
+				lkb->lkb_grmode);
+		break;
+	case DLM_LKSTS_CONVERT:
+		if (lkb->lkb_exflags & DLM_LKF_HEADQUE)
+			list_add(&lkb->lkb_statequeue, &r->res_convertqueue);
+		else
+			list_add_tail(&lkb->lkb_statequeue,
+				      &r->res_convertqueue);
+		break;
+	default:
+		DLM_ASSERT(0, dlm_print_lkb(lkb); printk("sts=%d\n", status););
+	}
+}
+
+static void del_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	lkb->lkb_status = 0;
+	list_del(&lkb->lkb_statequeue);
+	unhold_lkb(lkb);
+}
+
+static void move_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int sts)
+{
+	hold_lkb(lkb);
+	del_lkb(r, lkb);
+	add_lkb(r, lkb, sts);
+	unhold_lkb(lkb);
+}
+
+/* add/remove lkb from global waiters list of lkb's waiting for
+   a reply from a remote node */
+
+static void add_to_waiters(struct dlm_lkb *lkb, int mstype)
+{
+	struct dlm_ls *ls = lkb->lkb_resource->res_ls;
+
+	mutex_lock(&ls->ls_waiters_mutex);
+	if (lkb->lkb_wait_type) {
+		log_print("add_to_waiters error %d", lkb->lkb_wait_type);
+		goto out;
+	}
+	lkb->lkb_wait_type = mstype;
+	kref_get(&lkb->lkb_ref);
+	list_add(&lkb->lkb_wait_reply, &ls->ls_waiters);
+ out:
+	mutex_unlock(&ls->ls_waiters_mutex);
+}
+
+static int _remove_from_waiters(struct dlm_lkb *lkb)
+{
+	int error = 0;
+
+	if (!lkb->lkb_wait_type) {
+		log_print("remove_from_waiters error");
+		error = -EINVAL;
+		goto out;
+	}
+	lkb->lkb_wait_type = 0;
+	list_del(&lkb->lkb_wait_reply);
+	unhold_lkb(lkb);
+ out:
+	return error;
+}
+
+static int remove_from_waiters(struct dlm_lkb *lkb)
+{
+	struct dlm_ls *ls = lkb->lkb_resource->res_ls;
+	int error;
+
+	mutex_lock(&ls->ls_waiters_mutex);
+	error = _remove_from_waiters(lkb);
+	mutex_unlock(&ls->ls_waiters_mutex);
+	return error;
+}
+
+static void dir_remove(struct dlm_rsb *r)
+{
+	int to_nodeid;
+
+	if (dlm_no_directory(r->res_ls))
+		return;
+
+	to_nodeid = dlm_dir_nodeid(r);
+	if (to_nodeid != dlm_our_nodeid())
+		send_remove(r);
+	else
+		dlm_dir_remove_entry(r->res_ls, to_nodeid,
+				     r->res_name, r->res_length);
+}
+
+/* FIXME: shouldn't this be able to exit as soon as one non-due rsb is
+   found since they are in order of newest to oldest? */
+
+static int shrink_bucket(struct dlm_ls *ls, int b)
+{
+	struct dlm_rsb *r;
+	int count = 0, found;
+
+	for (;;) {
+		found = 0;
+		write_lock(&ls->ls_rsbtbl[b].lock);
+		list_for_each_entry_reverse(r, &ls->ls_rsbtbl[b].toss,
+					    res_hashchain) {
+			if (!time_after_eq(jiffies, r->res_toss_time +
+					   dlm_config.toss_secs * HZ))
+				continue;
+			found = 1;
+			break;
+		}
+
+		if (!found) {
+			write_unlock(&ls->ls_rsbtbl[b].lock);
+			break;
+		}
+
+		if (kref_put(&r->res_ref, kill_rsb)) {
+			list_del(&r->res_hashchain);
+			write_unlock(&ls->ls_rsbtbl[b].lock);
+
+			if (is_master(r))
+				dir_remove(r);
+			free_rsb(r);
+			count++;
+		} else {
+			write_unlock(&ls->ls_rsbtbl[b].lock);
+			log_error(ls, "tossed rsb in use %s", r->res_name);
+		}
+	}
+
+	return count;
+}
+
+void dlm_scan_rsbs(struct dlm_ls *ls)
+{
+	int i;
+
+	if (dlm_locking_stopped(ls))
+		return;
+
+	for (i = 0; i < ls->ls_rsbtbl_size; i++) {
+		shrink_bucket(ls, i);
+		cond_resched();
+	}
+}
+
+/* lkb is master or local copy */
+
+static void set_lvb_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	int b, len = r->res_ls->ls_lvblen;
+
+	/* b=1 lvb returned to caller
+	   b=0 lvb written to rsb or invalidated
+	   b=-1 do nothing */
+
+	b =  dlm_lvb_operations[lkb->lkb_grmode + 1][lkb->lkb_rqmode + 1];
+
+	if (b == 1) {
+		if (!lkb->lkb_lvbptr)
+			return;
+
+		if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
+			return;
+
+		if (!r->res_lvbptr)
+			return;
+
+		memcpy(lkb->lkb_lvbptr, r->res_lvbptr, len);
+		lkb->lkb_lvbseq = r->res_lvbseq;
+
+	} else if (b == 0) {
+		if (lkb->lkb_exflags & DLM_LKF_IVVALBLK) {
+			rsb_set_flag(r, RSB_VALNOTVALID);
+			return;
+		}
+
+		if (!lkb->lkb_lvbptr)
+			return;
+
+		if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
+			return;
+
+		if (!r->res_lvbptr)
+			r->res_lvbptr = allocate_lvb(r->res_ls);
+
+		if (!r->res_lvbptr)
+			return;
+
+		memcpy(r->res_lvbptr, lkb->lkb_lvbptr, len);
+		r->res_lvbseq++;
+		lkb->lkb_lvbseq = r->res_lvbseq;
+		rsb_clear_flag(r, RSB_VALNOTVALID);
+	}
+
+	if (rsb_flag(r, RSB_VALNOTVALID))
+		lkb->lkb_sbflags |= DLM_SBF_VALNOTVALID;
+}
+
+static void set_lvb_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	if (lkb->lkb_grmode < DLM_LOCK_PW)
+		return;
+
+	if (lkb->lkb_exflags & DLM_LKF_IVVALBLK) {
+		rsb_set_flag(r, RSB_VALNOTVALID);
+		return;
+	}
+
+	if (!lkb->lkb_lvbptr)
+		return;
+
+	if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
+		return;
+
+	if (!r->res_lvbptr)
+		r->res_lvbptr = allocate_lvb(r->res_ls);
+
+	if (!r->res_lvbptr)
+		return;
+
+	memcpy(r->res_lvbptr, lkb->lkb_lvbptr, r->res_ls->ls_lvblen);
+	r->res_lvbseq++;
+	rsb_clear_flag(r, RSB_VALNOTVALID);
+}
+
+/* lkb is process copy (pc) */
+
+static void set_lvb_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb,
+			    struct dlm_message *ms)
+{
+	int b;
+
+	if (!lkb->lkb_lvbptr)
+		return;
+
+	if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
+		return;
+
+	b =  dlm_lvb_operations[lkb->lkb_grmode + 1][lkb->lkb_rqmode + 1];
+	if (b == 1) {
+		int len = receive_extralen(ms);
+		memcpy(lkb->lkb_lvbptr, ms->m_extra, len);
+		lkb->lkb_lvbseq = ms->m_lvbseq;
+	}
+}
+
+/* Manipulate lkb's on rsb's convert/granted/waiting queues
+   remove_lock -- used for unlock, removes lkb from granted
+   revert_lock -- used for cancel, moves lkb from convert to granted
+   grant_lock  -- used for request and convert, adds lkb to granted or
+                  moves lkb from convert or waiting to granted
+
+   Each of these is used for master or local copy lkb's.  There is
+   also a _pc() variation used to make the corresponding change on
+   a process copy (pc) lkb. */
+
+static void _remove_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	del_lkb(r, lkb);
+	lkb->lkb_grmode = DLM_LOCK_IV;
+	/* this unhold undoes the original ref from create_lkb()
+	   so this leads to the lkb being freed */
+	unhold_lkb(lkb);
+}
+
+static void remove_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	set_lvb_unlock(r, lkb);
+	_remove_lock(r, lkb);
+}
+
+static void remove_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	_remove_lock(r, lkb);
+}
+
+static void revert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	lkb->lkb_rqmode = DLM_LOCK_IV;
+
+	switch (lkb->lkb_status) {
+	case DLM_LKSTS_CONVERT:
+		move_lkb(r, lkb, DLM_LKSTS_GRANTED);
+		break;
+	case DLM_LKSTS_WAITING:
+		del_lkb(r, lkb);
+		lkb->lkb_grmode = DLM_LOCK_IV;
+		/* this unhold undoes the original ref from create_lkb()
+		   so this leads to the lkb being freed */
+		unhold_lkb(lkb);
+		break;
+	default:
+		log_print("invalid status for revert %d", lkb->lkb_status);
+	}
+}
+
+static void revert_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	revert_lock(r, lkb);
+}
+
+static void _grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	if (lkb->lkb_grmode != lkb->lkb_rqmode) {
+		lkb->lkb_grmode = lkb->lkb_rqmode;
+		if (lkb->lkb_status)
+			move_lkb(r, lkb, DLM_LKSTS_GRANTED);
+		else
+			add_lkb(r, lkb, DLM_LKSTS_GRANTED);
+	}
+
+	lkb->lkb_rqmode = DLM_LOCK_IV;
+
+	if (lkb->lkb_range) {
+		lkb->lkb_range[GR_RANGE_START] = lkb->lkb_range[RQ_RANGE_START];
+		lkb->lkb_range[GR_RANGE_END] = lkb->lkb_range[RQ_RANGE_END];
+	}
+}
+
+static void grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	set_lvb_lock(r, lkb);
+	_grant_lock(r, lkb);
+	lkb->lkb_highbast = 0;
+}
+
+static void grant_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb,
+			  struct dlm_message *ms)
+{
+	set_lvb_lock_pc(r, lkb, ms);
+	_grant_lock(r, lkb);
+}
+
+/* called by grant_pending_locks() which means an async grant message must
+   be sent to the requesting node in addition to granting the lock if the
+   lkb belongs to a remote node. */
+
+static void grant_lock_pending(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	grant_lock(r, lkb);
+	if (is_master_copy(lkb))
+		send_grant(r, lkb);
+	else
+		queue_cast(r, lkb, 0);
+}
+
+static inline int first_in_list(struct dlm_lkb *lkb, struct list_head *head)
+{
+	struct dlm_lkb *first = list_entry(head->next, struct dlm_lkb,
+					   lkb_statequeue);
+	if (lkb->lkb_id == first->lkb_id)
+		return 1;
+
+	return 0;
+}
+
+/* Return 1 if the locks' ranges overlap.  If the lkb has no range then it is
+   assumed to cover 0-ffffffff.ffffffff */
+
+static inline int ranges_overlap(struct dlm_lkb *lkb1, struct dlm_lkb *lkb2)
+{
+	if (!lkb1->lkb_range || !lkb2->lkb_range)
+		return 1;
+
+	if (lkb1->lkb_range[RQ_RANGE_END] < lkb2->lkb_range[GR_RANGE_START] ||
+	    lkb1->lkb_range[RQ_RANGE_START] > lkb2->lkb_range[GR_RANGE_END])
+		return 0;
+
+	return 1;
+}
+
+/* Check if the given lkb conflicts with another lkb on the queue. */
+
+static int queue_conflict(struct list_head *head, struct dlm_lkb *lkb)
+{
+	struct dlm_lkb *this;
+
+	list_for_each_entry(this, head, lkb_statequeue) {
+		if (this == lkb)
+			continue;
+		if (ranges_overlap(lkb, this) && !modes_compat(this, lkb))
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * "A conversion deadlock arises with a pair of lock requests in the converting
+ * queue for one resource.  The granted mode of each lock blocks the requested
+ * mode of the other lock."
+ *
+ * Part 2: if the granted mode of lkb is preventing the first lkb in the
+ * convert queue from being granted, then demote lkb (set grmode to NL).
+ * This second form requires that we check for conv-deadlk even when
+ * now == 0 in _can_be_granted().
+ *
+ * Example:
+ * Granted Queue: empty
+ * Convert Queue: NL->EX (first lock)
+ *                PR->EX (second lock)
+ *
+ * The first lock can't be granted because of the granted mode of the second
+ * lock and the second lock can't be granted because it's not first in the
+ * list.  We demote the granted mode of the second lock (the lkb passed to this
+ * function).
+ *
+ * After the resolution, the "grant pending" function needs to go back and try
+ * to grant locks on the convert queue again since the first lock can now be
+ * granted.
+ */
+
+static int conversion_deadlock_detect(struct dlm_rsb *rsb, struct dlm_lkb *lkb)
+{
+	struct dlm_lkb *this, *first = NULL, *self = NULL;
+
+	list_for_each_entry(this, &rsb->res_convertqueue, lkb_statequeue) {
+		if (!first)
+			first = this;
+		if (this == lkb) {
+			self = lkb;
+			continue;
+		}
+
+		if (!ranges_overlap(lkb, this))
+			continue;
+
+		if (!modes_compat(this, lkb) && !modes_compat(lkb, this))
+			return 1;
+	}
+
+	/* if lkb is on the convert queue and is preventing the first
+	   from being granted, then there's deadlock and we demote lkb.
+	   multiple converting locks may need to do this before the first
+	   converting lock can be granted. */
+
+	if (self && self != first) {
+		if (!modes_compat(lkb, first) &&
+		    !queue_conflict(&rsb->res_grantqueue, first))
+			return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Return 1 if the lock can be granted, 0 otherwise.
+ * Also detect and resolve conversion deadlocks.
+ *
+ * lkb is the lock to be granted
+ *
+ * now is 1 if the function is being called in the context of the
+ * immediate request, it is 0 if called later, after the lock has been
+ * queued.
+ *
+ * References are from chapter 6 of "VAXcluster Principles" by Roy Davis
+ */
+
+static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now)
+{
+	int8_t conv = (lkb->lkb_grmode != DLM_LOCK_IV);
+
+	/*
+	 * 6-10: Version 5.4 introduced an option to address the phenomenon of
+	 * a new request for a NL mode lock being blocked.
+	 *
+	 * 6-11: If the optional EXPEDITE flag is used with the new NL mode
+	 * request, then it would be granted.  In essence, the use of this flag
+	 * tells the Lock Manager to expedite theis request by not considering
+	 * what may be in the CONVERTING or WAITING queues...  As of this
+	 * writing, the EXPEDITE flag can be used only with new requests for NL
+	 * mode locks.  This flag is not valid for conversion requests.
+	 *
+	 * A shortcut.  Earlier checks return an error if EXPEDITE is used in a
+	 * conversion or used with a non-NL requested mode.  We also know an
+	 * EXPEDITE request is always granted immediately, so now must always
+	 * be 1.  The full condition to grant an expedite request: (now &&
+	 * !conv && lkb->rqmode == DLM_LOCK_NL && (flags & EXPEDITE)) can
+	 * therefore be shortened to just checking the flag.
+	 */
+
+	if (lkb->lkb_exflags & DLM_LKF_EXPEDITE)
+		return 1;
+
+	/*
+	 * A shortcut. Without this, !queue_conflict(grantqueue, lkb) would be
+	 * added to the remaining conditions.
+	 */
+
+	if (queue_conflict(&r->res_grantqueue, lkb))
+		goto out;
+
+	/*
+	 * 6-3: By default, a conversion request is immediately granted if the
+	 * requested mode is compatible with the modes of all other granted
+	 * locks
+	 */
+
+	if (queue_conflict(&r->res_convertqueue, lkb))
+		goto out;
+
+	/*
+	 * 6-5: But the default algorithm for deciding whether to grant or
+	 * queue conversion requests does not by itself guarantee that such
+	 * requests are serviced on a "first come first serve" basis.  This, in
+	 * turn, can lead to a phenomenon known as "indefinate postponement".
+	 *
+	 * 6-7: This issue is dealt with by using the optional QUECVT flag with
+	 * the system service employed to request a lock conversion.  This flag
+	 * forces certain conversion requests to be queued, even if they are
+	 * compatible with the granted modes of other locks on the same
+	 * resource.  Thus, the use of this flag results in conversion requests
+	 * being ordered on a "first come first servce" basis.
+	 *
+	 * DCT: This condition is all about new conversions being able to occur
+	 * "in place" while the lock remains on the granted queue (assuming
+	 * nothing else conflicts.)  IOW if QUECVT isn't set, a conversion
+	 * doesn't _have_ to go onto the convert queue where it's processed in
+	 * order.  The "now" variable is necessary to distinguish converts
+	 * being received and processed for the first time now, because once a
+	 * convert is moved to the conversion queue the condition below applies
+	 * requiring fifo granting.
+	 */
+
+	if (now && conv && !(lkb->lkb_exflags & DLM_LKF_QUECVT))
+		return 1;
+
+	/*
+	 * When using range locks the NOORDER flag is set to avoid the standard
+	 * vms rules on grant order.
+	 */
+
+	if (lkb->lkb_exflags & DLM_LKF_NOORDER)
+		return 1;
+
+	/*
+	 * 6-3: Once in that queue [CONVERTING], a conversion request cannot be
+	 * granted until all other conversion requests ahead of it are granted
+	 * and/or canceled.
+	 */
+
+	if (!now && conv && first_in_list(lkb, &r->res_convertqueue))
+		return 1;
+
+	/*
+	 * 6-4: By default, a new request is immediately granted only if all
+	 * three of the following conditions are satisfied when the request is
+	 * issued:
+	 * - The queue of ungranted conversion requests for the resource is
+	 *   empty.
+	 * - The queue of ungranted new requests for the resource is empty.
+	 * - The mode of the new request is compatible with the most
+	 *   restrictive mode of all granted locks on the resource.
+	 */
+
+	if (now && !conv && list_empty(&r->res_convertqueue) &&
+	    list_empty(&r->res_waitqueue))
+		return 1;
+
+	/*
+	 * 6-4: Once a lock request is in the queue of ungranted new requests,
+	 * it cannot be granted until the queue of ungranted conversion
+	 * requests is empty, all ungranted new requests ahead of it are
+	 * granted and/or canceled, and it is compatible with the granted mode
+	 * of the most restrictive lock granted on the resource.
+	 */
+
+	if (!now && !conv && list_empty(&r->res_convertqueue) &&
+	    first_in_list(lkb, &r->res_waitqueue))
+		return 1;
+
+ out:
+	/*
+	 * The following, enabled by CONVDEADLK, departs from VMS.
+	 */
+
+	if (conv && (lkb->lkb_exflags & DLM_LKF_CONVDEADLK) &&
+	    conversion_deadlock_detect(r, lkb)) {
+		lkb->lkb_grmode = DLM_LOCK_NL;
+		lkb->lkb_sbflags |= DLM_SBF_DEMOTED;
+	}
+
+	return 0;
+}
+
+/*
+ * The ALTPR and ALTCW flags aren't traditional lock manager flags, but are a
+ * simple way to provide a big optimization to applications that can use them.
+ */
+
+static int can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now)
+{
+	uint32_t flags = lkb->lkb_exflags;
+	int rv;
+	int8_t alt = 0, rqmode = lkb->lkb_rqmode;
+
+	rv = _can_be_granted(r, lkb, now);
+	if (rv)
+		goto out;
+
+	if (lkb->lkb_sbflags & DLM_SBF_DEMOTED)
+		goto out;
+
+	if (rqmode != DLM_LOCK_PR && flags & DLM_LKF_ALTPR)
+		alt = DLM_LOCK_PR;
+	else if (rqmode != DLM_LOCK_CW && flags & DLM_LKF_ALTCW)
+		alt = DLM_LOCK_CW;
+
+	if (alt) {
+		lkb->lkb_rqmode = alt;
+		rv = _can_be_granted(r, lkb, now);
+		if (rv)
+			lkb->lkb_sbflags |= DLM_SBF_ALTMODE;
+		else
+			lkb->lkb_rqmode = rqmode;
+	}
+ out:
+	return rv;
+}
+
+static int grant_pending_convert(struct dlm_rsb *r, int high)
+{
+	struct dlm_lkb *lkb, *s;
+	int hi, demoted, quit, grant_restart, demote_restart;
+
+	quit = 0;
+ restart:
+	grant_restart = 0;
+	demote_restart = 0;
+	hi = DLM_LOCK_IV;
+
+	list_for_each_entry_safe(lkb, s, &r->res_convertqueue, lkb_statequeue) {
+		demoted = is_demoted(lkb);
+		if (can_be_granted(r, lkb, 0)) {
+			grant_lock_pending(r, lkb);
+			grant_restart = 1;
+		} else {
+			hi = max_t(int, lkb->lkb_rqmode, hi);
+			if (!demoted && is_demoted(lkb))
+				demote_restart = 1;
+		}
+	}
+
+	if (grant_restart)
+		goto restart;
+	if (demote_restart && !quit) {
+		quit = 1;
+		goto restart;
+	}
+
+	return max_t(int, high, hi);
+}
+
+static int grant_pending_wait(struct dlm_rsb *r, int high)
+{
+	struct dlm_lkb *lkb, *s;
+
+	list_for_each_entry_safe(lkb, s, &r->res_waitqueue, lkb_statequeue) {
+		if (can_be_granted(r, lkb, 0))
+			grant_lock_pending(r, lkb);
+                else
+			high = max_t(int, lkb->lkb_rqmode, high);
+	}
+
+	return high;
+}
+
+static void grant_pending_locks(struct dlm_rsb *r)
+{
+	struct dlm_lkb *lkb, *s;
+	int high = DLM_LOCK_IV;
+
+	DLM_ASSERT(is_master(r), dlm_print_rsb(r););
+
+	high = grant_pending_convert(r, high);
+	high = grant_pending_wait(r, high);
+
+	if (high == DLM_LOCK_IV)
+		return;
+
+	/*
+	 * If there are locks left on the wait/convert queue then send blocking
+	 * ASTs to granted locks based on the largest requested mode (high)
+	 * found above.  This can generate spurious blocking ASTs for range
+	 * locks. FIXME: highbast < high comparison not valid for PR/CW.
+	 */
+
+	list_for_each_entry_safe(lkb, s, &r->res_grantqueue, lkb_statequeue) {
+		if (lkb->lkb_bastaddr && (lkb->lkb_highbast < high) &&
+		    !__dlm_compat_matrix[lkb->lkb_grmode+1][high+1]) {
+			queue_bast(r, lkb, high);
+			lkb->lkb_highbast = high;
+		}
+	}
+}
+
+static void send_bast_queue(struct dlm_rsb *r, struct list_head *head,
+			    struct dlm_lkb *lkb)
+{
+	struct dlm_lkb *gr;
+
+	list_for_each_entry(gr, head, lkb_statequeue) {
+		if (gr->lkb_bastaddr &&
+		    gr->lkb_highbast < lkb->lkb_rqmode &&
+		    ranges_overlap(lkb, gr) && !modes_compat(gr, lkb)) {
+			queue_bast(r, gr, lkb->lkb_rqmode);
+			gr->lkb_highbast = lkb->lkb_rqmode;
+		}
+	}
+}
+
+static void send_blocking_asts(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	send_bast_queue(r, &r->res_grantqueue, lkb);
+}
+
+static void send_blocking_asts_all(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	send_bast_queue(r, &r->res_grantqueue, lkb);
+	send_bast_queue(r, &r->res_convertqueue, lkb);
+}
+
+/* set_master(r, lkb) -- set the master nodeid of a resource
+
+   The purpose of this function is to set the nodeid field in the given
+   lkb using the nodeid field in the given rsb.  If the rsb's nodeid is
+   known, it can just be copied to the lkb and the function will return
+   0.  If the rsb's nodeid is _not_ known, it needs to be looked up
+   before it can be copied to the lkb.
+
+   When the rsb nodeid is being looked up remotely, the initial lkb
+   causing the lookup is kept on the ls_waiters list waiting for the
+   lookup reply.  Other lkb's waiting for the same rsb lookup are kept
+   on the rsb's res_lookup list until the master is verified.
+
+   Return values:
+   0: nodeid is set in rsb/lkb and the caller should go ahead and use it
+   1: the rsb master is not available and the lkb has been placed on
+      a wait queue
+*/
+
+static int set_master(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	struct dlm_ls *ls = r->res_ls;
+	int error, dir_nodeid, ret_nodeid, our_nodeid = dlm_our_nodeid();
+
+	if (rsb_flag(r, RSB_MASTER_UNCERTAIN)) {
+		rsb_clear_flag(r, RSB_MASTER_UNCERTAIN);
+		r->res_first_lkid = lkb->lkb_id;
+		lkb->lkb_nodeid = r->res_nodeid;
+		return 0;
+	}
+
+	if (r->res_first_lkid && r->res_first_lkid != lkb->lkb_id) {
+		list_add_tail(&lkb->lkb_rsb_lookup, &r->res_lookup);
+		return 1;
+	}
+
+	if (r->res_nodeid == 0) {
+		lkb->lkb_nodeid = 0;
+		return 0;
+	}
+
+	if (r->res_nodeid > 0) {
+		lkb->lkb_nodeid = r->res_nodeid;
+		return 0;
+	}
+
+	DLM_ASSERT(r->res_nodeid == -1, dlm_print_rsb(r););
+
+	dir_nodeid = dlm_dir_nodeid(r);
+
+	if (dir_nodeid != our_nodeid) {
+		r->res_first_lkid = lkb->lkb_id;
+		send_lookup(r, lkb);
+		return 1;
+	}
+
+	for (;;) {
+		/* It's possible for dlm_scand to remove an old rsb for
+		   this same resource from the toss list, us to create
+		   a new one, look up the master locally, and find it
+		   already exists just before dlm_scand does the
+		   dir_remove() on the previous rsb. */
+
+		error = dlm_dir_lookup(ls, our_nodeid, r->res_name,
+				       r->res_length, &ret_nodeid);
+		if (!error)
+			break;
+		log_debug(ls, "dir_lookup error %d %s", error, r->res_name);
+		schedule();
+	}
+
+	if (ret_nodeid == our_nodeid) {
+		r->res_first_lkid = 0;
+		r->res_nodeid = 0;
+		lkb->lkb_nodeid = 0;
+	} else {
+		r->res_first_lkid = lkb->lkb_id;
+		r->res_nodeid = ret_nodeid;
+		lkb->lkb_nodeid = ret_nodeid;
+	}
+	return 0;
+}
+
+static void process_lookup_list(struct dlm_rsb *r)
+{
+	struct dlm_lkb *lkb, *safe;
+
+	list_for_each_entry_safe(lkb, safe, &r->res_lookup, lkb_rsb_lookup) {
+		list_del(&lkb->lkb_rsb_lookup);
+		_request_lock(r, lkb);
+		schedule();
+	}
+}
+
+/* confirm_master -- confirm (or deny) an rsb's master nodeid */
+
+static void confirm_master(struct dlm_rsb *r, int error)
+{
+	struct dlm_lkb *lkb;
+
+	if (!r->res_first_lkid)
+		return;
+
+	switch (error) {
+	case 0:
+	case -EINPROGRESS:
+		r->res_first_lkid = 0;
+		process_lookup_list(r);
+		break;
+
+	case -EAGAIN:
+		/* the remote master didn't queue our NOQUEUE request;
+		   make a waiting lkb the first_lkid */
+
+		r->res_first_lkid = 0;
+
+		if (!list_empty(&r->res_lookup)) {
+			lkb = list_entry(r->res_lookup.next, struct dlm_lkb,
+					 lkb_rsb_lookup);
+			list_del(&lkb->lkb_rsb_lookup);
+			r->res_first_lkid = lkb->lkb_id;
+			_request_lock(r, lkb);
+		} else
+			r->res_nodeid = -1;
+		break;
+
+	default:
+		log_error(r->res_ls, "confirm_master unknown error %d", error);
+	}
+}
+
+static int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags,
+			 int namelen, uint32_t parent_lkid, void *ast,
+			 void *astarg, void *bast, struct dlm_range *range,
+			 struct dlm_args *args)
+{
+	int rv = -EINVAL;
+
+	/* check for invalid arg usage */
+
+	if (mode < 0 || mode > DLM_LOCK_EX)
+		goto out;
+
+	if (!(flags & DLM_LKF_CONVERT) && (namelen > DLM_RESNAME_MAXLEN))
+		goto out;
+
+	if (flags & DLM_LKF_CANCEL)
+		goto out;
+
+	if (flags & DLM_LKF_QUECVT && !(flags & DLM_LKF_CONVERT))
+		goto out;
+
+	if (flags & DLM_LKF_CONVDEADLK && !(flags & DLM_LKF_CONVERT))
+		goto out;
+
+	if (flags & DLM_LKF_CONVDEADLK && flags & DLM_LKF_NOQUEUE)
+		goto out;
+
+	if (flags & DLM_LKF_EXPEDITE && flags & DLM_LKF_CONVERT)
+		goto out;
+
+	if (flags & DLM_LKF_EXPEDITE && flags & DLM_LKF_QUECVT)
+		goto out;
+
+	if (flags & DLM_LKF_EXPEDITE && flags & DLM_LKF_NOQUEUE)
+		goto out;
+
+	if (flags & DLM_LKF_EXPEDITE && mode != DLM_LOCK_NL)
+		goto out;
+
+	if (!ast || !lksb)
+		goto out;
+
+	if (flags & DLM_LKF_VALBLK && !lksb->sb_lvbptr)
+		goto out;
+
+	/* parent/child locks not yet supported */
+	if (parent_lkid)
+		goto out;
+
+	if (flags & DLM_LKF_CONVERT && !lksb->sb_lkid)
+		goto out;
+
+	/* these args will be copied to the lkb in validate_lock_args,
+	   it cannot be done now because when converting locks, fields in
+	   an active lkb cannot be modified before locking the rsb */
+
+	args->flags = flags;
+	args->astaddr = ast;
+	args->astparam = (long) astarg;
+	args->bastaddr = bast;
+	args->mode = mode;
+	args->lksb = lksb;
+	args->range = range;
+	rv = 0;
+ out:
+	return rv;
+}
+
+static int set_unlock_args(uint32_t flags, void *astarg, struct dlm_args *args)
+{
+	if (flags & ~(DLM_LKF_CANCEL | DLM_LKF_VALBLK | DLM_LKF_IVVALBLK |
+ 		      DLM_LKF_FORCEUNLOCK))
+		return -EINVAL;
+
+	args->flags = flags;
+	args->astparam = (long) astarg;
+	return 0;
+}
+
+static int validate_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
+			      struct dlm_args *args)
+{
+	int rv = -EINVAL;
+
+	if (args->flags & DLM_LKF_CONVERT) {
+		if (lkb->lkb_flags & DLM_IFL_MSTCPY)
+			goto out;
+
+		if (args->flags & DLM_LKF_QUECVT &&
+		    !__quecvt_compat_matrix[lkb->lkb_grmode+1][args->mode+1])
+			goto out;
+
+		rv = -EBUSY;
+		if (lkb->lkb_status != DLM_LKSTS_GRANTED)
+			goto out;
+
+		if (lkb->lkb_wait_type)
+			goto out;
+	}
+
+	lkb->lkb_exflags = args->flags;
+	lkb->lkb_sbflags = 0;
+	lkb->lkb_astaddr = args->astaddr;
+	lkb->lkb_astparam = args->astparam;
+	lkb->lkb_bastaddr = args->bastaddr;
+	lkb->lkb_rqmode = args->mode;
+	lkb->lkb_lksb = args->lksb;
+	lkb->lkb_lvbptr = args->lksb->sb_lvbptr;
+	lkb->lkb_ownpid = (int) current->pid;
+
+	rv = 0;
+	if (!args->range)
+		goto out;
+
+	if (!lkb->lkb_range) {
+		rv = -ENOMEM;
+		lkb->lkb_range = allocate_range(ls);
+		if (!lkb->lkb_range)
+			goto out;
+		/* This is needed for conversions that contain ranges
+		   where the original lock didn't but it's harmless for
+		   new locks too. */
+		lkb->lkb_range[GR_RANGE_START] = 0LL;
+		lkb->lkb_range[GR_RANGE_END] = 0xffffffffffffffffULL;
+	}
+
+	lkb->lkb_range[RQ_RANGE_START] = args->range->ra_start;
+	lkb->lkb_range[RQ_RANGE_END] = args->range->ra_end;
+	lkb->lkb_flags |= DLM_IFL_RANGE;
+	rv = 0;
+ out:
+	return rv;
+}
+
+static int validate_unlock_args(struct dlm_lkb *lkb, struct dlm_args *args)
+{
+	int rv = -EINVAL;
+
+	if (lkb->lkb_flags & DLM_IFL_MSTCPY)
+		goto out;
+
+	if (args->flags & DLM_LKF_FORCEUNLOCK)
+		goto out_ok;
+
+	if (args->flags & DLM_LKF_CANCEL &&
+	    lkb->lkb_status == DLM_LKSTS_GRANTED)
+		goto out;
+
+	if (!(args->flags & DLM_LKF_CANCEL) &&
+	    lkb->lkb_status != DLM_LKSTS_GRANTED)
+		goto out;
+
+	rv = -EBUSY;
+	if (lkb->lkb_wait_type)
+		goto out;
+
+ out_ok:
+	lkb->lkb_exflags = args->flags;
+	lkb->lkb_sbflags = 0;
+	lkb->lkb_astparam = args->astparam;
+
+	rv = 0;
+ out:
+	return rv;
+}
+
+/*
+ * Four stage 4 varieties:
+ * do_request(), do_convert(), do_unlock(), do_cancel()
+ * These are called on the master node for the given lock and
+ * from the central locking logic.
+ */
+
+static int do_request(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	int error = 0;
+
+	if (can_be_granted(r, lkb, 1)) {
+		grant_lock(r, lkb);
+		queue_cast(r, lkb, 0);
+		goto out;
+	}
+
+	if (can_be_queued(lkb)) {
+		error = -EINPROGRESS;
+		add_lkb(r, lkb, DLM_LKSTS_WAITING);
+		send_blocking_asts(r, lkb);
+		goto out;
+	}
+
+	error = -EAGAIN;
+	if (force_blocking_asts(lkb))
+		send_blocking_asts_all(r, lkb);
+	queue_cast(r, lkb, -EAGAIN);
+
+ out:
+	return error;
+}
+
+static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	int error = 0;
+
+	/* changing an existing lock may allow others to be granted */
+
+	if (can_be_granted(r, lkb, 1)) {
+		grant_lock(r, lkb);
+		queue_cast(r, lkb, 0);
+		grant_pending_locks(r);
+		goto out;
+	}
+
+	if (can_be_queued(lkb)) {
+		if (is_demoted(lkb))
+			grant_pending_locks(r);
+		error = -EINPROGRESS;
+		del_lkb(r, lkb);
+		add_lkb(r, lkb, DLM_LKSTS_CONVERT);
+		send_blocking_asts(r, lkb);
+		goto out;
+	}
+
+	error = -EAGAIN;
+	if (force_blocking_asts(lkb))
+		send_blocking_asts_all(r, lkb);
+	queue_cast(r, lkb, -EAGAIN);
+
+ out:
+	return error;
+}
+
+static int do_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	remove_lock(r, lkb);
+	queue_cast(r, lkb, -DLM_EUNLOCK);
+	grant_pending_locks(r);
+	return -DLM_EUNLOCK;
+}
+
+static int do_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	revert_lock(r, lkb);
+	queue_cast(r, lkb, -DLM_ECANCEL);
+	grant_pending_locks(r);
+	return -DLM_ECANCEL;
+}
+
+/*
+ * Four stage 3 varieties:
+ * _request_lock(), _convert_lock(), _unlock_lock(), _cancel_lock()
+ */
+
+/* add a new lkb to a possibly new rsb, called by requesting process */
+
+static int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	int error;
+
+	/* set_master: sets lkb nodeid from r */
+
+	error = set_master(r, lkb);
+	if (error < 0)
+		goto out;
+	if (error) {
+		error = 0;
+		goto out;
+	}
+
+	if (is_remote(r))
+		/* receive_request() calls do_request() on remote node */
+		error = send_request(r, lkb);
+	else
+		error = do_request(r, lkb);
+ out:
+	return error;
+}
+
+/* change some property of an existing lkb, e.g. mode, range */
+
+static int _convert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	int error;
+
+	if (is_remote(r))
+		/* receive_convert() calls do_convert() on remote node */
+		error = send_convert(r, lkb);
+	else
+		error = do_convert(r, lkb);
+
+	return error;
+}
+
+/* remove an existing lkb from the granted queue */
+
+static int _unlock_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	int error;
+
+	if (is_remote(r))
+		/* receive_unlock() calls do_unlock() on remote node */
+		error = send_unlock(r, lkb);
+	else
+		error = do_unlock(r, lkb);
+
+	return error;
+}
+
+/* remove an existing lkb from the convert or wait queue */
+
+static int _cancel_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	int error;
+
+	if (is_remote(r))
+		/* receive_cancel() calls do_cancel() on remote node */
+		error = send_cancel(r, lkb);
+	else
+		error = do_cancel(r, lkb);
+
+	return error;
+}
+
+/*
+ * Four stage 2 varieties:
+ * request_lock(), convert_lock(), unlock_lock(), cancel_lock()
+ */
+
+static int request_lock(struct dlm_ls *ls, struct dlm_lkb *lkb, char *name,
+			int len, struct dlm_args *args)
+{
+	struct dlm_rsb *r;
+	int error;
+
+	error = validate_lock_args(ls, lkb, args);
+	if (error)
+		goto out;
+
+	error = find_rsb(ls, name, len, R_CREATE, &r);
+	if (error)
+		goto out;
+
+	lock_rsb(r);
+
+	attach_lkb(r, lkb);
+	lkb->lkb_lksb->sb_lkid = lkb->lkb_id;
+
+	error = _request_lock(r, lkb);
+
+	unlock_rsb(r);
+	put_rsb(r);
+
+ out:
+	return error;
+}
+
+static int convert_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,
+			struct dlm_args *args)
+{
+	struct dlm_rsb *r;
+	int error;
+
+	r = lkb->lkb_resource;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	error = validate_lock_args(ls, lkb, args);
+	if (error)
+		goto out;
+
+	error = _convert_lock(r, lkb);
+ out:
+	unlock_rsb(r);
+	put_rsb(r);
+	return error;
+}
+
+static int unlock_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,
+		       struct dlm_args *args)
+{
+	struct dlm_rsb *r;
+	int error;
+
+	r = lkb->lkb_resource;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	error = validate_unlock_args(lkb, args);
+	if (error)
+		goto out;
+
+	error = _unlock_lock(r, lkb);
+ out:
+	unlock_rsb(r);
+	put_rsb(r);
+	return error;
+}
+
+static int cancel_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,
+		       struct dlm_args *args)
+{
+	struct dlm_rsb *r;
+	int error;
+
+	r = lkb->lkb_resource;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	error = validate_unlock_args(lkb, args);
+	if (error)
+		goto out;
+
+	error = _cancel_lock(r, lkb);
+ out:
+	unlock_rsb(r);
+	put_rsb(r);
+	return error;
+}
+
+/*
+ * Two stage 1 varieties:  dlm_lock() and dlm_unlock()
+ */
+
+int dlm_lock(dlm_lockspace_t *lockspace,
+	     int mode,
+	     struct dlm_lksb *lksb,
+	     uint32_t flags,
+	     void *name,
+	     unsigned int namelen,
+	     uint32_t parent_lkid,
+	     void (*ast) (void *astarg),
+	     void *astarg,
+	     void (*bast) (void *astarg, int mode),
+	     struct dlm_range *range)
+{
+	struct dlm_ls *ls;
+	struct dlm_lkb *lkb;
+	struct dlm_args args;
+	int error, convert = flags & DLM_LKF_CONVERT;
+
+	ls = dlm_find_lockspace_local(lockspace);
+	if (!ls)
+		return -EINVAL;
+
+	lock_recovery(ls);
+
+	if (convert)
+		error = find_lkb(ls, lksb->sb_lkid, &lkb);
+	else
+		error = create_lkb(ls, &lkb);
+
+	if (error)
+		goto out;
+
+	error = set_lock_args(mode, lksb, flags, namelen, parent_lkid, ast,
+			      astarg, bast, range, &args);
+	if (error)
+		goto out_put;
+
+	if (convert)
+		error = convert_lock(ls, lkb, &args);
+	else
+		error = request_lock(ls, lkb, name, namelen, &args);
+
+	if (error == -EINPROGRESS)
+		error = 0;
+ out_put:
+	if (convert || error)
+		put_lkb(lkb);
+	if (error == -EAGAIN)
+		error = 0;
+ out:
+	unlock_recovery(ls);
+	dlm_put_lockspace(ls);
+	return error;
+}
+
+int dlm_unlock(dlm_lockspace_t *lockspace,
+	       uint32_t lkid,
+	       uint32_t flags,
+	       struct dlm_lksb *lksb,
+	       void *astarg)
+{
+	struct dlm_ls *ls;
+	struct dlm_lkb *lkb;
+	struct dlm_args args;
+	int error;
+
+	ls = dlm_find_lockspace_local(lockspace);
+	if (!ls)
+		return -EINVAL;
+
+	lock_recovery(ls);
+
+	error = find_lkb(ls, lkid, &lkb);
+	if (error)
+		goto out;
+
+	error = set_unlock_args(flags, astarg, &args);
+	if (error)
+		goto out_put;
+
+	if (flags & DLM_LKF_CANCEL)
+		error = cancel_lock(ls, lkb, &args);
+	else
+		error = unlock_lock(ls, lkb, &args);
+
+	if (error == -DLM_EUNLOCK || error == -DLM_ECANCEL)
+		error = 0;
+ out_put:
+	put_lkb(lkb);
+ out:
+	unlock_recovery(ls);
+	dlm_put_lockspace(ls);
+	return error;
+}
+
+/*
+ * send/receive routines for remote operations and replies
+ *
+ * send_args
+ * send_common
+ * send_request			receive_request
+ * send_convert			receive_convert
+ * send_unlock			receive_unlock
+ * send_cancel			receive_cancel
+ * send_grant			receive_grant
+ * send_bast			receive_bast
+ * send_lookup			receive_lookup
+ * send_remove			receive_remove
+ *
+ * 				send_common_reply
+ * receive_request_reply	send_request_reply
+ * receive_convert_reply	send_convert_reply
+ * receive_unlock_reply		send_unlock_reply
+ * receive_cancel_reply		send_cancel_reply
+ * receive_lookup_reply		send_lookup_reply
+ */
+
+static int create_message(struct dlm_rsb *r, struct dlm_lkb *lkb,
+			  int to_nodeid, int mstype,
+			  struct dlm_message **ms_ret,
+			  struct dlm_mhandle **mh_ret)
+{
+	struct dlm_message *ms;
+	struct dlm_mhandle *mh;
+	char *mb;
+	int mb_len = sizeof(struct dlm_message);
+
+	switch (mstype) {
+	case DLM_MSG_REQUEST:
+	case DLM_MSG_LOOKUP:
+	case DLM_MSG_REMOVE:
+		mb_len += r->res_length;
+		break;
+	case DLM_MSG_CONVERT:
+	case DLM_MSG_UNLOCK:
+	case DLM_MSG_REQUEST_REPLY:
+	case DLM_MSG_CONVERT_REPLY:
+	case DLM_MSG_GRANT:
+		if (lkb && lkb->lkb_lvbptr)
+			mb_len += r->res_ls->ls_lvblen;
+		break;
+	}
+
+	/* get_buffer gives us a message handle (mh) that we need to
+	   pass into lowcomms_commit and a message buffer (mb) that we
+	   write our data into */
+
+	mh = dlm_lowcomms_get_buffer(to_nodeid, mb_len, GFP_KERNEL, &mb);
+	if (!mh)
+		return -ENOBUFS;
+
+	memset(mb, 0, mb_len);
+
+	ms = (struct dlm_message *) mb;
+
+	ms->m_header.h_version = (DLM_HEADER_MAJOR | DLM_HEADER_MINOR);
+	ms->m_header.h_lockspace = r->res_ls->ls_global_id;
+	ms->m_header.h_nodeid = dlm_our_nodeid();
+	ms->m_header.h_length = mb_len;
+	ms->m_header.h_cmd = DLM_MSG;
+
+	ms->m_type = mstype;
+
+	*mh_ret = mh;
+	*ms_ret = ms;
+	return 0;
+}
+
+/* further lowcomms enhancements or alternate implementations may make
+   the return value from this function useful at some point */
+
+static int send_message(struct dlm_mhandle *mh, struct dlm_message *ms)
+{
+	dlm_message_out(ms);
+	dlm_lowcomms_commit_buffer(mh);
+	return 0;
+}
+
+static void send_args(struct dlm_rsb *r, struct dlm_lkb *lkb,
+		      struct dlm_message *ms)
+{
+	ms->m_nodeid   = lkb->lkb_nodeid;
+	ms->m_pid      = lkb->lkb_ownpid;
+	ms->m_lkid     = lkb->lkb_id;
+	ms->m_remid    = lkb->lkb_remid;
+	ms->m_exflags  = lkb->lkb_exflags;
+	ms->m_sbflags  = lkb->lkb_sbflags;
+	ms->m_flags    = lkb->lkb_flags;
+	ms->m_lvbseq   = lkb->lkb_lvbseq;
+	ms->m_status   = lkb->lkb_status;
+	ms->m_grmode   = lkb->lkb_grmode;
+	ms->m_rqmode   = lkb->lkb_rqmode;
+	ms->m_hash     = r->res_hash;
+
+	/* m_result and m_bastmode are set from function args,
+	   not from lkb fields */
+
+	if (lkb->lkb_bastaddr)
+		ms->m_asts |= AST_BAST;
+	if (lkb->lkb_astaddr)
+		ms->m_asts |= AST_COMP;
+
+	if (lkb->lkb_range) {
+		ms->m_range[0] = lkb->lkb_range[RQ_RANGE_START];
+		ms->m_range[1] = lkb->lkb_range[RQ_RANGE_END];
+	}
+
+	if (ms->m_type == DLM_MSG_REQUEST || ms->m_type == DLM_MSG_LOOKUP)
+		memcpy(ms->m_extra, r->res_name, r->res_length);
+
+	else if (lkb->lkb_lvbptr)
+		memcpy(ms->m_extra, lkb->lkb_lvbptr, r->res_ls->ls_lvblen);
+
+}
+
+static int send_common(struct dlm_rsb *r, struct dlm_lkb *lkb, int mstype)
+{
+	struct dlm_message *ms;
+	struct dlm_mhandle *mh;
+	int to_nodeid, error;
+
+	add_to_waiters(lkb, mstype);
+
+	to_nodeid = r->res_nodeid;
+
+	error = create_message(r, lkb, to_nodeid, mstype, &ms, &mh);
+	if (error)
+		goto fail;
+
+	send_args(r, lkb, ms);
+
+	error = send_message(mh, ms);
+	if (error)
+		goto fail;
+	return 0;
+
+ fail:
+	remove_from_waiters(lkb);
+	return error;
+}
+
+static int send_request(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	return send_common(r, lkb, DLM_MSG_REQUEST);
+}
+
+static int send_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	int error;
+
+	error = send_common(r, lkb, DLM_MSG_CONVERT);
+
+	/* down conversions go without a reply from the master */
+	if (!error && down_conversion(lkb)) {
+		remove_from_waiters(lkb);
+		r->res_ls->ls_stub_ms.m_result = 0;
+		__receive_convert_reply(r, lkb, &r->res_ls->ls_stub_ms);
+	}
+
+	return error;
+}
+
+/* FIXME: if this lkb is the only lock we hold on the rsb, then set
+   MASTER_UNCERTAIN to force the next request on the rsb to confirm
+   that the master is still correct. */
+
+static int send_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	return send_common(r, lkb, DLM_MSG_UNLOCK);
+}
+
+static int send_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	return send_common(r, lkb, DLM_MSG_CANCEL);
+}
+
+static int send_grant(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	struct dlm_message *ms;
+	struct dlm_mhandle *mh;
+	int to_nodeid, error;
+
+	to_nodeid = lkb->lkb_nodeid;
+
+	error = create_message(r, lkb, to_nodeid, DLM_MSG_GRANT, &ms, &mh);
+	if (error)
+		goto out;
+
+	send_args(r, lkb, ms);
+
+	ms->m_result = 0;
+
+	error = send_message(mh, ms);
+ out:
+	return error;
+}
+
+static int send_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int mode)
+{
+	struct dlm_message *ms;
+	struct dlm_mhandle *mh;
+	int to_nodeid, error;
+
+	to_nodeid = lkb->lkb_nodeid;
+
+	error = create_message(r, NULL, to_nodeid, DLM_MSG_BAST, &ms, &mh);
+	if (error)
+		goto out;
+
+	send_args(r, lkb, ms);
+
+	ms->m_bastmode = mode;
+
+	error = send_message(mh, ms);
+ out:
+	return error;
+}
+
+static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	struct dlm_message *ms;
+	struct dlm_mhandle *mh;
+	int to_nodeid, error;
+
+	add_to_waiters(lkb, DLM_MSG_LOOKUP);
+
+	to_nodeid = dlm_dir_nodeid(r);
+
+	error = create_message(r, NULL, to_nodeid, DLM_MSG_LOOKUP, &ms, &mh);
+	if (error)
+		goto fail;
+
+	send_args(r, lkb, ms);
+
+	error = send_message(mh, ms);
+	if (error)
+		goto fail;
+	return 0;
+
+ fail:
+	remove_from_waiters(lkb);
+	return error;
+}
+
+static int send_remove(struct dlm_rsb *r)
+{
+	struct dlm_message *ms;
+	struct dlm_mhandle *mh;
+	int to_nodeid, error;
+
+	to_nodeid = dlm_dir_nodeid(r);
+
+	error = create_message(r, NULL, to_nodeid, DLM_MSG_REMOVE, &ms, &mh);
+	if (error)
+		goto out;
+
+	memcpy(ms->m_extra, r->res_name, r->res_length);
+	ms->m_hash = r->res_hash;
+
+	error = send_message(mh, ms);
+ out:
+	return error;
+}
+
+static int send_common_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
+			     int mstype, int rv)
+{
+	struct dlm_message *ms;
+	struct dlm_mhandle *mh;
+	int to_nodeid, error;
+
+	to_nodeid = lkb->lkb_nodeid;
+
+	error = create_message(r, lkb, to_nodeid, mstype, &ms, &mh);
+	if (error)
+		goto out;
+
+	send_args(r, lkb, ms);
+
+	ms->m_result = rv;
+
+	error = send_message(mh, ms);
+ out:
+	return error;
+}
+
+static int send_request_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
+{
+	return send_common_reply(r, lkb, DLM_MSG_REQUEST_REPLY, rv);
+}
+
+static int send_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
+{
+	return send_common_reply(r, lkb, DLM_MSG_CONVERT_REPLY, rv);
+}
+
+static int send_unlock_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
+{
+	return send_common_reply(r, lkb, DLM_MSG_UNLOCK_REPLY, rv);
+}
+
+static int send_cancel_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
+{
+	return send_common_reply(r, lkb, DLM_MSG_CANCEL_REPLY, rv);
+}
+
+static int send_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms_in,
+			     int ret_nodeid, int rv)
+{
+	struct dlm_rsb *r = &ls->ls_stub_rsb;
+	struct dlm_message *ms;
+	struct dlm_mhandle *mh;
+	int error, nodeid = ms_in->m_header.h_nodeid;
+
+	error = create_message(r, NULL, nodeid, DLM_MSG_LOOKUP_REPLY, &ms, &mh);
+	if (error)
+		goto out;
+
+	ms->m_lkid = ms_in->m_lkid;
+	ms->m_result = rv;
+	ms->m_nodeid = ret_nodeid;
+
+	error = send_message(mh, ms);
+ out:
+	return error;
+}
+
+/* which args we save from a received message depends heavily on the type
+   of message, unlike the send side where we can safely send everything about
+   the lkb for any type of message */
+
+static void receive_flags(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+	lkb->lkb_exflags = ms->m_exflags;
+	lkb->lkb_flags = (lkb->lkb_flags & 0xFFFF0000) |
+		         (ms->m_flags & 0x0000FFFF);
+}
+
+static void receive_flags_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+	lkb->lkb_sbflags = ms->m_sbflags;
+	lkb->lkb_flags = (lkb->lkb_flags & 0xFFFF0000) |
+		         (ms->m_flags & 0x0000FFFF);
+}
+
+static int receive_extralen(struct dlm_message *ms)
+{
+	return (ms->m_header.h_length - sizeof(struct dlm_message));
+}
+
+static int receive_range(struct dlm_ls *ls, struct dlm_lkb *lkb,
+			 struct dlm_message *ms)
+{
+	if (lkb->lkb_flags & DLM_IFL_RANGE) {
+		if (!lkb->lkb_range)
+			lkb->lkb_range = allocate_range(ls);
+		if (!lkb->lkb_range)
+			return -ENOMEM;
+		lkb->lkb_range[RQ_RANGE_START] = ms->m_range[0];
+		lkb->lkb_range[RQ_RANGE_END] = ms->m_range[1];
+	}
+	return 0;
+}
+
+static int receive_lvb(struct dlm_ls *ls, struct dlm_lkb *lkb,
+		       struct dlm_message *ms)
+{
+	int len;
+
+	if (lkb->lkb_exflags & DLM_LKF_VALBLK) {
+		if (!lkb->lkb_lvbptr)
+			lkb->lkb_lvbptr = allocate_lvb(ls);
+		if (!lkb->lkb_lvbptr)
+			return -ENOMEM;
+		len = receive_extralen(ms);
+		memcpy(lkb->lkb_lvbptr, ms->m_extra, len);
+	}
+	return 0;
+}
+
+static int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
+				struct dlm_message *ms)
+{
+	lkb->lkb_nodeid = ms->m_header.h_nodeid;
+	lkb->lkb_ownpid = ms->m_pid;
+	lkb->lkb_remid = ms->m_lkid;
+	lkb->lkb_grmode = DLM_LOCK_IV;
+	lkb->lkb_rqmode = ms->m_rqmode;
+	lkb->lkb_bastaddr = (void *) (long) (ms->m_asts & AST_BAST);
+	lkb->lkb_astaddr = (void *) (long) (ms->m_asts & AST_COMP);
+
+	DLM_ASSERT(is_master_copy(lkb), dlm_print_lkb(lkb););
+
+	if (receive_range(ls, lkb, ms))
+		return -ENOMEM;
+
+	if (receive_lvb(ls, lkb, ms))
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int receive_convert_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
+				struct dlm_message *ms)
+{
+	if (lkb->lkb_nodeid != ms->m_header.h_nodeid) {
+		log_error(ls, "convert_args nodeid %d %d lkid %x %x",
+			  lkb->lkb_nodeid, ms->m_header.h_nodeid,
+			  lkb->lkb_id, lkb->lkb_remid);
+		return -EINVAL;
+	}
+
+	if (!is_master_copy(lkb))
+		return -EINVAL;
+
+	if (lkb->lkb_status != DLM_LKSTS_GRANTED)
+		return -EBUSY;
+
+	if (receive_range(ls, lkb, ms))
+		return -ENOMEM;
+	if (lkb->lkb_range) {
+		lkb->lkb_range[GR_RANGE_START] = 0LL;
+		lkb->lkb_range[GR_RANGE_END] = 0xffffffffffffffffULL;
+	}
+
+	if (receive_lvb(ls, lkb, ms))
+		return -ENOMEM;
+
+	lkb->lkb_rqmode = ms->m_rqmode;
+	lkb->lkb_lvbseq = ms->m_lvbseq;
+
+	return 0;
+}
+
+static int receive_unlock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
+			       struct dlm_message *ms)
+{
+	if (!is_master_copy(lkb))
+		return -EINVAL;
+	if (receive_lvb(ls, lkb, ms))
+		return -ENOMEM;
+	return 0;
+}
+
+/* We fill in the stub-lkb fields with the info that send_xxxx_reply()
+   uses to send a reply and that the remote end uses to process the reply. */
+
+static void setup_stub_lkb(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb = &ls->ls_stub_lkb;
+	lkb->lkb_nodeid = ms->m_header.h_nodeid;
+	lkb->lkb_remid = ms->m_lkid;
+}
+
+static void receive_request(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *r;
+	int error, namelen;
+
+	error = create_lkb(ls, &lkb);
+	if (error)
+		goto fail;
+
+	receive_flags(lkb, ms);
+	lkb->lkb_flags |= DLM_IFL_MSTCPY;
+	error = receive_request_args(ls, lkb, ms);
+	if (error) {
+		put_lkb(lkb);
+		goto fail;
+	}
+
+	namelen = receive_extralen(ms);
+
+	error = find_rsb(ls, ms->m_extra, namelen, R_MASTER, &r);
+	if (error) {
+		put_lkb(lkb);
+		goto fail;
+	}
+
+	lock_rsb(r);
+
+	attach_lkb(r, lkb);
+	error = do_request(r, lkb);
+	send_request_reply(r, lkb, error);
+
+	unlock_rsb(r);
+	put_rsb(r);
+
+	if (error == -EINPROGRESS)
+		error = 0;
+	if (error)
+		put_lkb(lkb);
+	return;
+
+ fail:
+	setup_stub_lkb(ls, ms);
+	send_request_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+}
+
+static void receive_convert(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *r;
+	int error, reply = 1;
+
+	error = find_lkb(ls, ms->m_remid, &lkb);
+	if (error)
+		goto fail;
+
+	r = lkb->lkb_resource;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	receive_flags(lkb, ms);
+	error = receive_convert_args(ls, lkb, ms);
+	if (error)
+		goto out;
+	reply = !down_conversion(lkb);
+
+	error = do_convert(r, lkb);
+ out:
+	if (reply)
+		send_convert_reply(r, lkb, error);
+
+	unlock_rsb(r);
+	put_rsb(r);
+	put_lkb(lkb);
+	return;
+
+ fail:
+	setup_stub_lkb(ls, ms);
+	send_convert_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+}
+
+static void receive_unlock(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *r;
+	int error;
+
+	error = find_lkb(ls, ms->m_remid, &lkb);
+	if (error)
+		goto fail;
+
+	r = lkb->lkb_resource;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	receive_flags(lkb, ms);
+	error = receive_unlock_args(ls, lkb, ms);
+	if (error)
+		goto out;
+
+	error = do_unlock(r, lkb);
+ out:
+	send_unlock_reply(r, lkb, error);
+
+	unlock_rsb(r);
+	put_rsb(r);
+	put_lkb(lkb);
+	return;
+
+ fail:
+	setup_stub_lkb(ls, ms);
+	send_unlock_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+}
+
+static void receive_cancel(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *r;
+	int error;
+
+	error = find_lkb(ls, ms->m_remid, &lkb);
+	if (error)
+		goto fail;
+
+	receive_flags(lkb, ms);
+
+	r = lkb->lkb_resource;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	error = do_cancel(r, lkb);
+	send_cancel_reply(r, lkb, error);
+
+	unlock_rsb(r);
+	put_rsb(r);
+	put_lkb(lkb);
+	return;
+
+ fail:
+	setup_stub_lkb(ls, ms);
+	send_cancel_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+}
+
+static void receive_grant(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *r;
+	int error;
+
+	error = find_lkb(ls, ms->m_remid, &lkb);
+	if (error) {
+		log_error(ls, "receive_grant no lkb");
+		return;
+	}
+	DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+	r = lkb->lkb_resource;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	receive_flags_reply(lkb, ms);
+	grant_lock_pc(r, lkb, ms);
+	queue_cast(r, lkb, 0);
+
+	unlock_rsb(r);
+	put_rsb(r);
+	put_lkb(lkb);
+}
+
+static void receive_bast(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *r;
+	int error;
+
+	error = find_lkb(ls, ms->m_remid, &lkb);
+	if (error) {
+		log_error(ls, "receive_bast no lkb");
+		return;
+	}
+	DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+	r = lkb->lkb_resource;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	queue_bast(r, lkb, ms->m_bastmode);
+
+	unlock_rsb(r);
+	put_rsb(r);
+	put_lkb(lkb);
+}
+
+static void receive_lookup(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	int len, error, ret_nodeid, dir_nodeid, from_nodeid, our_nodeid;
+
+	from_nodeid = ms->m_header.h_nodeid;
+	our_nodeid = dlm_our_nodeid();
+
+	len = receive_extralen(ms);
+
+	dir_nodeid = dlm_hash2nodeid(ls, ms->m_hash);
+	if (dir_nodeid != our_nodeid) {
+		log_error(ls, "lookup dir_nodeid %d from %d",
+			  dir_nodeid, from_nodeid);
+		error = -EINVAL;
+		ret_nodeid = -1;
+		goto out;
+	}
+
+	error = dlm_dir_lookup(ls, from_nodeid, ms->m_extra, len, &ret_nodeid);
+
+	/* Optimization: we're master so treat lookup as a request */
+	if (!error && ret_nodeid == our_nodeid) {
+		receive_request(ls, ms);
+		return;
+	}
+ out:
+	send_lookup_reply(ls, ms, ret_nodeid, error);
+}
+
+static void receive_remove(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	int len, dir_nodeid, from_nodeid;
+
+	from_nodeid = ms->m_header.h_nodeid;
+
+	len = receive_extralen(ms);
+
+	dir_nodeid = dlm_hash2nodeid(ls, ms->m_hash);
+	if (dir_nodeid != dlm_our_nodeid()) {
+		log_error(ls, "remove dir entry dir_nodeid %d from %d",
+			  dir_nodeid, from_nodeid);
+		return;
+	}
+
+	dlm_dir_remove_entry(ls, from_nodeid, ms->m_extra, len);
+}
+
+static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *r;
+	int error, mstype;
+
+	error = find_lkb(ls, ms->m_remid, &lkb);
+	if (error) {
+		log_error(ls, "receive_request_reply no lkb");
+		return;
+	}
+	DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+	mstype = lkb->lkb_wait_type;
+	error = remove_from_waiters(lkb);
+	if (error) {
+		log_error(ls, "receive_request_reply not on waiters");
+		goto out;
+	}
+
+	/* this is the value returned from do_request() on the master */
+	error = ms->m_result;
+
+	r = lkb->lkb_resource;
+	hold_rsb(r);
+	lock_rsb(r);
+
+	/* Optimization: the dir node was also the master, so it took our
+	   lookup as a request and sent request reply instead of lookup reply */
+	if (mstype == DLM_MSG_LOOKUP) {
+		r->res_nodeid = ms->m_header.h_nodeid;
+		lkb->lkb_nodeid = r->res_nodeid;
+	}
+
+	switch (error) {
+	case -EAGAIN:
+		/* request would block (be queued) on remote master;
+		   the unhold undoes the original ref from create_lkb()
+		   so it leads to the lkb being freed */
+		queue_cast(r, lkb, -EAGAIN);
+		confirm_master(r, -EAGAIN);
+		unhold_lkb(lkb);
+		break;
+
+	case -EINPROGRESS:
+	case 0:
+		/* request was queued or granted on remote master */
+		receive_flags_reply(lkb, ms);
+		lkb->lkb_remid = ms->m_lkid;
+		if (error)
+			add_lkb(r, lkb, DLM_LKSTS_WAITING);
+		else {
+			grant_lock_pc(r, lkb, ms);
+			queue_cast(r, lkb, 0);
+		}
+		confirm_master(r, error);
+		break;
+
+	case -ENOENT:
+	case -ENOTBLK:
+		/* find_rsb failed to find rsb or rsb wasn't master */
+		r->res_nodeid = -1;
+		lkb->lkb_nodeid = -1;
+		_request_lock(r, lkb);
+		break;
+
+	default:
+		log_error(ls, "receive_request_reply error %d", error);
+	}
+
+	unlock_rsb(r);
+	put_rsb(r);
+ out:
+	put_lkb(lkb);
+}
+
+static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
+				    struct dlm_message *ms)
+{
+	int error = ms->m_result;
+
+	/* this is the value returned from do_convert() on the master */
+
+	switch (error) {
+	case -EAGAIN:
+		/* convert would block (be queued) on remote master */
+		queue_cast(r, lkb, -EAGAIN);
+		break;
+
+	case -EINPROGRESS:
+		/* convert was queued on remote master */
+		del_lkb(r, lkb);
+		add_lkb(r, lkb, DLM_LKSTS_CONVERT);
+		break;
+
+	case 0:
+		/* convert was granted on remote master */
+		receive_flags_reply(lkb, ms);
+		grant_lock_pc(r, lkb, ms);
+		queue_cast(r, lkb, 0);
+		break;
+
+	default:
+		log_error(r->res_ls, "receive_convert_reply error %d", error);
+	}
+}
+
+static void _receive_convert_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+	struct dlm_rsb *r = lkb->lkb_resource;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	__receive_convert_reply(r, lkb, ms);
+
+	unlock_rsb(r);
+	put_rsb(r);
+}
+
+static void receive_convert_reply(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	int error;
+
+	error = find_lkb(ls, ms->m_remid, &lkb);
+	if (error) {
+		log_error(ls, "receive_convert_reply no lkb");
+		return;
+	}
+	DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+	error = remove_from_waiters(lkb);
+	if (error) {
+		log_error(ls, "receive_convert_reply not on waiters");
+		goto out;
+	}
+
+	_receive_convert_reply(lkb, ms);
+ out:
+	put_lkb(lkb);
+}
+
+static void _receive_unlock_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+	struct dlm_rsb *r = lkb->lkb_resource;
+	int error = ms->m_result;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	/* this is the value returned from do_unlock() on the master */
+
+	switch (error) {
+	case -DLM_EUNLOCK:
+		receive_flags_reply(lkb, ms);
+		remove_lock_pc(r, lkb);
+		queue_cast(r, lkb, -DLM_EUNLOCK);
+		break;
+	default:
+		log_error(r->res_ls, "receive_unlock_reply error %d", error);
+	}
+
+	unlock_rsb(r);
+	put_rsb(r);
+}
+
+static void receive_unlock_reply(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	int error;
+
+	error = find_lkb(ls, ms->m_remid, &lkb);
+	if (error) {
+		log_error(ls, "receive_unlock_reply no lkb");
+		return;
+	}
+	DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+	error = remove_from_waiters(lkb);
+	if (error) {
+		log_error(ls, "receive_unlock_reply not on waiters");
+		goto out;
+	}
+
+	_receive_unlock_reply(lkb, ms);
+ out:
+	put_lkb(lkb);
+}
+
+static void _receive_cancel_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+	struct dlm_rsb *r = lkb->lkb_resource;
+	int error = ms->m_result;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	/* this is the value returned from do_cancel() on the master */
+
+	switch (error) {
+	case -DLM_ECANCEL:
+		receive_flags_reply(lkb, ms);
+		revert_lock_pc(r, lkb);
+		queue_cast(r, lkb, -DLM_ECANCEL);
+		break;
+	default:
+		log_error(r->res_ls, "receive_cancel_reply error %d", error);
+	}
+
+	unlock_rsb(r);
+	put_rsb(r);
+}
+
+static void receive_cancel_reply(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	int error;
+
+	error = find_lkb(ls, ms->m_remid, &lkb);
+	if (error) {
+		log_error(ls, "receive_cancel_reply no lkb");
+		return;
+	}
+	DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+	error = remove_from_waiters(lkb);
+	if (error) {
+		log_error(ls, "receive_cancel_reply not on waiters");
+		goto out;
+	}
+
+	_receive_cancel_reply(lkb, ms);
+ out:
+	put_lkb(lkb);
+}
+
+static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *r;
+	int error, ret_nodeid;
+
+	error = find_lkb(ls, ms->m_lkid, &lkb);
+	if (error) {
+		log_error(ls, "receive_lookup_reply no lkb");
+		return;
+	}
+
+	error = remove_from_waiters(lkb);
+	if (error) {
+		log_error(ls, "receive_lookup_reply not on waiters");
+		goto out;
+	}
+
+	/* this is the value returned by dlm_dir_lookup on dir node
+	   FIXME: will a non-zero error ever be returned? */
+	error = ms->m_result;
+
+	r = lkb->lkb_resource;
+	hold_rsb(r);
+	lock_rsb(r);
+
+	ret_nodeid = ms->m_nodeid;
+	if (ret_nodeid == dlm_our_nodeid()) {
+		r->res_nodeid = 0;
+		ret_nodeid = 0;
+		r->res_first_lkid = 0;
+	} else {
+		/* set_master() will copy res_nodeid to lkb_nodeid */
+		r->res_nodeid = ret_nodeid;
+	}
+
+	_request_lock(r, lkb);
+
+	if (!ret_nodeid)
+		process_lookup_list(r);
+
+	unlock_rsb(r);
+	put_rsb(r);
+ out:
+	put_lkb(lkb);
+}
+
+int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery)
+{
+	struct dlm_message *ms = (struct dlm_message *) hd;
+	struct dlm_ls *ls;
+	int error;
+
+	if (!recovery)
+		dlm_message_in(ms);
+
+	ls = dlm_find_lockspace_global(hd->h_lockspace);
+	if (!ls) {
+		log_print("drop message %d from %d for unknown lockspace %d",
+			  ms->m_type, nodeid, hd->h_lockspace);
+		return -EINVAL;
+	}
+
+	/* recovery may have just ended leaving a bunch of backed-up requests
+	   in the requestqueue; wait while dlm_recoverd clears them */
+
+	if (!recovery)
+		dlm_wait_requestqueue(ls);
+
+	/* recovery may have just started while there were a bunch of
+	   in-flight requests -- save them in requestqueue to be processed
+	   after recovery.  we can't let dlm_recvd block on the recovery
+	   lock.  if dlm_recoverd is calling this function to clear the
+	   requestqueue, it needs to be interrupted (-EINTR) if another
+	   recovery operation is starting. */
+
+	while (1) {
+		if (dlm_locking_stopped(ls)) {
+			if (!recovery)
+				dlm_add_requestqueue(ls, nodeid, hd);
+			error = -EINTR;
+			goto out;
+		}
+
+		if (lock_recovery_try(ls))
+			break;
+		schedule();
+	}
+
+	switch (ms->m_type) {
+
+	/* messages sent to a master node */
+
+	case DLM_MSG_REQUEST:
+		receive_request(ls, ms);
+		break;
+
+	case DLM_MSG_CONVERT:
+		receive_convert(ls, ms);
+		break;
+
+	case DLM_MSG_UNLOCK:
+		receive_unlock(ls, ms);
+		break;
+
+	case DLM_MSG_CANCEL:
+		receive_cancel(ls, ms);
+		break;
+
+	/* messages sent from a master node (replies to above) */
+
+	case DLM_MSG_REQUEST_REPLY:
+		receive_request_reply(ls, ms);
+		break;
+
+	case DLM_MSG_CONVERT_REPLY:
+		receive_convert_reply(ls, ms);
+		break;
+
+	case DLM_MSG_UNLOCK_REPLY:
+		receive_unlock_reply(ls, ms);
+		break;
+
+	case DLM_MSG_CANCEL_REPLY:
+		receive_cancel_reply(ls, ms);
+		break;
+
+	/* messages sent from a master node (only two types of async msg) */
+
+	case DLM_MSG_GRANT:
+		receive_grant(ls, ms);
+		break;
+
+	case DLM_MSG_BAST:
+		receive_bast(ls, ms);
+		break;
+
+	/* messages sent to a dir node */
+
+	case DLM_MSG_LOOKUP:
+		receive_lookup(ls, ms);
+		break;
+
+	case DLM_MSG_REMOVE:
+		receive_remove(ls, ms);
+		break;
+
+	/* messages sent from a dir node (remove has no reply) */
+
+	case DLM_MSG_LOOKUP_REPLY:
+		receive_lookup_reply(ls, ms);
+		break;
+
+	default:
+		log_error(ls, "unknown message type %d", ms->m_type);
+	}
+
+	unlock_recovery(ls);
+ out:
+	dlm_put_lockspace(ls);
+	dlm_astd_wake();
+	return 0;
+}
+
+
+/*
+ * Recovery related
+ */
+
+static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb)
+{
+	if (middle_conversion(lkb)) {
+		hold_lkb(lkb);
+		ls->ls_stub_ms.m_result = -EINPROGRESS;
+		_remove_from_waiters(lkb);
+		_receive_convert_reply(lkb, &ls->ls_stub_ms);
+
+		/* Same special case as in receive_rcom_lock_args() */
+		lkb->lkb_grmode = DLM_LOCK_IV;
+		rsb_set_flag(lkb->lkb_resource, RSB_RECOVER_CONVERT);
+		unhold_lkb(lkb);
+
+	} else if (lkb->lkb_rqmode >= lkb->lkb_grmode) {
+		lkb->lkb_flags |= DLM_IFL_RESEND;
+	}
+
+	/* lkb->lkb_rqmode < lkb->lkb_grmode shouldn't happen since down
+	   conversions are async; there's no reply from the remote master */
+}
+
+/* A waiting lkb needs recovery if the master node has failed, or
+   the master node is changing (only when no directory is used) */
+
+static int waiter_needs_recovery(struct dlm_ls *ls, struct dlm_lkb *lkb)
+{
+	if (dlm_is_removed(ls, lkb->lkb_nodeid))
+		return 1;
+
+	if (!dlm_no_directory(ls))
+		return 0;
+
+	if (dlm_dir_nodeid(lkb->lkb_resource) != lkb->lkb_nodeid)
+		return 1;
+
+	return 0;
+}
+
+/* Recovery for locks that are waiting for replies from nodes that are now
+   gone.  We can just complete unlocks and cancels by faking a reply from the
+   dead node.  Requests and up-conversions we flag to be resent after
+   recovery.  Down-conversions can just be completed with a fake reply like
+   unlocks.  Conversions between PR and CW need special attention. */
+
+void dlm_recover_waiters_pre(struct dlm_ls *ls)
+{
+	struct dlm_lkb *lkb, *safe;
+
+	mutex_lock(&ls->ls_waiters_mutex);
+
+	list_for_each_entry_safe(lkb, safe, &ls->ls_waiters, lkb_wait_reply) {
+		log_debug(ls, "pre recover waiter lkid %x type %d flags %x",
+			  lkb->lkb_id, lkb->lkb_wait_type, lkb->lkb_flags);
+
+		/* all outstanding lookups, regardless of destination  will be
+		   resent after recovery is done */
+
+		if (lkb->lkb_wait_type == DLM_MSG_LOOKUP) {
+			lkb->lkb_flags |= DLM_IFL_RESEND;
+			continue;
+		}
+
+		if (!waiter_needs_recovery(ls, lkb))
+			continue;
+
+		switch (lkb->lkb_wait_type) {
+
+		case DLM_MSG_REQUEST:
+			lkb->lkb_flags |= DLM_IFL_RESEND;
+			break;
+
+		case DLM_MSG_CONVERT:
+			recover_convert_waiter(ls, lkb);
+			break;
+
+		case DLM_MSG_UNLOCK:
+			hold_lkb(lkb);
+			ls->ls_stub_ms.m_result = -DLM_EUNLOCK;
+			_remove_from_waiters(lkb);
+			_receive_unlock_reply(lkb, &ls->ls_stub_ms);
+			put_lkb(lkb);
+			break;
+
+		case DLM_MSG_CANCEL:
+			hold_lkb(lkb);
+			ls->ls_stub_ms.m_result = -DLM_ECANCEL;
+			_remove_from_waiters(lkb);
+			_receive_cancel_reply(lkb, &ls->ls_stub_ms);
+			put_lkb(lkb);
+			break;
+
+		default:
+			log_error(ls, "invalid lkb wait_type %d",
+				  lkb->lkb_wait_type);
+		}
+	}
+	mutex_unlock(&ls->ls_waiters_mutex);
+}
+
+static int remove_resend_waiter(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
+{
+	struct dlm_lkb *lkb;
+	int rv = 0;
+
+	mutex_lock(&ls->ls_waiters_mutex);
+	list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
+		if (lkb->lkb_flags & DLM_IFL_RESEND) {
+			rv = lkb->lkb_wait_type;
+			_remove_from_waiters(lkb);
+			lkb->lkb_flags &= ~DLM_IFL_RESEND;
+			break;
+		}
+	}
+	mutex_unlock(&ls->ls_waiters_mutex);
+
+	if (!rv)
+		lkb = NULL;
+	*lkb_ret = lkb;
+	return rv;
+}
+
+/* Deal with lookups and lkb's marked RESEND from _pre.  We may now be the
+   master or dir-node for r.  Processing the lkb may result in it being placed
+   back on waiters. */
+
+int dlm_recover_waiters_post(struct dlm_ls *ls)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *r;
+	int error = 0, mstype;
+
+	while (1) {
+		if (dlm_locking_stopped(ls)) {
+			log_debug(ls, "recover_waiters_post aborted");
+			error = -EINTR;
+			break;
+		}
+
+		mstype = remove_resend_waiter(ls, &lkb);
+		if (!mstype)
+			break;
+
+		r = lkb->lkb_resource;
+
+		log_debug(ls, "recover_waiters_post %x type %d flags %x %s",
+			  lkb->lkb_id, mstype, lkb->lkb_flags, r->res_name);
+
+		switch (mstype) {
+
+		case DLM_MSG_LOOKUP:
+			hold_rsb(r);
+			lock_rsb(r);
+			_request_lock(r, lkb);
+			if (is_master(r))
+				confirm_master(r, 0);
+			unlock_rsb(r);
+			put_rsb(r);
+			break;
+
+		case DLM_MSG_REQUEST:
+			hold_rsb(r);
+			lock_rsb(r);
+			_request_lock(r, lkb);
+			unlock_rsb(r);
+			put_rsb(r);
+			break;
+
+		case DLM_MSG_CONVERT:
+			hold_rsb(r);
+			lock_rsb(r);
+			_convert_lock(r, lkb);
+			unlock_rsb(r);
+			put_rsb(r);
+			break;
+
+		default:
+			log_error(ls, "recover_waiters_post type %d", mstype);
+		}
+	}
+
+	return error;
+}
+
+static void purge_queue(struct dlm_rsb *r, struct list_head *queue,
+			int (*test)(struct dlm_ls *ls, struct dlm_lkb *lkb))
+{
+	struct dlm_ls *ls = r->res_ls;
+	struct dlm_lkb *lkb, *safe;
+
+	list_for_each_entry_safe(lkb, safe, queue, lkb_statequeue) {
+		if (test(ls, lkb)) {
+			del_lkb(r, lkb);
+			/* this put should free the lkb */
+			if (!put_lkb(lkb))
+				log_error(ls, "purged lkb not released");
+		}
+	}
+}
+
+static int purge_dead_test(struct dlm_ls *ls, struct dlm_lkb *lkb)
+{
+	return (is_master_copy(lkb) && dlm_is_removed(ls, lkb->lkb_nodeid));
+}
+
+static int purge_mstcpy_test(struct dlm_ls *ls, struct dlm_lkb *lkb)
+{
+	return is_master_copy(lkb);
+}
+
+static void purge_dead_locks(struct dlm_rsb *r)
+{
+	purge_queue(r, &r->res_grantqueue, &purge_dead_test);
+	purge_queue(r, &r->res_convertqueue, &purge_dead_test);
+	purge_queue(r, &r->res_waitqueue, &purge_dead_test);
+}
+
+void dlm_purge_mstcpy_locks(struct dlm_rsb *r)
+{
+	purge_queue(r, &r->res_grantqueue, &purge_mstcpy_test);
+	purge_queue(r, &r->res_convertqueue, &purge_mstcpy_test);
+	purge_queue(r, &r->res_waitqueue, &purge_mstcpy_test);
+}
+
+/* Get rid of locks held by nodes that are gone. */
+
+int dlm_purge_locks(struct dlm_ls *ls)
+{
+	struct dlm_rsb *r;
+
+	log_debug(ls, "dlm_purge_locks");
+
+	down_write(&ls->ls_root_sem);
+	list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
+		hold_rsb(r);
+		lock_rsb(r);
+		if (is_master(r))
+			purge_dead_locks(r);
+		unlock_rsb(r);
+		unhold_rsb(r);
+
+		schedule();
+	}
+	up_write(&ls->ls_root_sem);
+
+	return 0;
+}
+
+int dlm_grant_after_purge(struct dlm_ls *ls)
+{
+	struct dlm_rsb *r;
+	int i;
+
+	for (i = 0; i < ls->ls_rsbtbl_size; i++) {
+		read_lock(&ls->ls_rsbtbl[i].lock);
+		list_for_each_entry(r, &ls->ls_rsbtbl[i].list, res_hashchain) {
+			hold_rsb(r);
+			lock_rsb(r);
+			if (is_master(r)) {
+				grant_pending_locks(r);
+				confirm_master(r, 0);
+			}
+			unlock_rsb(r);
+			put_rsb(r);
+		}
+		read_unlock(&ls->ls_rsbtbl[i].lock);
+	}
+
+	return 0;
+}
+
+static struct dlm_lkb *search_remid_list(struct list_head *head, int nodeid,
+					 uint32_t remid)
+{
+	struct dlm_lkb *lkb;
+
+	list_for_each_entry(lkb, head, lkb_statequeue) {
+		if (lkb->lkb_nodeid == nodeid && lkb->lkb_remid == remid)
+			return lkb;
+	}
+	return NULL;
+}
+
+static struct dlm_lkb *search_remid(struct dlm_rsb *r, int nodeid,
+				    uint32_t remid)
+{
+	struct dlm_lkb *lkb;
+
+	lkb = search_remid_list(&r->res_grantqueue, nodeid, remid);
+	if (lkb)
+		return lkb;
+	lkb = search_remid_list(&r->res_convertqueue, nodeid, remid);
+	if (lkb)
+		return lkb;
+	lkb = search_remid_list(&r->res_waitqueue, nodeid, remid);
+	if (lkb)
+		return lkb;
+	return NULL;
+}
+
+static int receive_rcom_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
+				  struct dlm_rsb *r, struct dlm_rcom *rc)
+{
+	struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
+	int lvblen;
+
+	lkb->lkb_nodeid = rc->rc_header.h_nodeid;
+	lkb->lkb_ownpid = rl->rl_ownpid;
+	lkb->lkb_remid = rl->rl_lkid;
+	lkb->lkb_exflags = rl->rl_exflags;
+	lkb->lkb_flags = rl->rl_flags & 0x0000FFFF;
+	lkb->lkb_flags |= DLM_IFL_MSTCPY;
+	lkb->lkb_lvbseq = rl->rl_lvbseq;
+	lkb->lkb_rqmode = rl->rl_rqmode;
+	lkb->lkb_grmode = rl->rl_grmode;
+	/* don't set lkb_status because add_lkb wants to itself */
+
+	lkb->lkb_bastaddr = (void *) (long) (rl->rl_asts & AST_BAST);
+	lkb->lkb_astaddr = (void *) (long) (rl->rl_asts & AST_COMP);
+
+	if (lkb->lkb_flags & DLM_IFL_RANGE) {
+		lkb->lkb_range = allocate_range(ls);
+		if (!lkb->lkb_range)
+			return -ENOMEM;
+		memcpy(lkb->lkb_range, rl->rl_range, 4*sizeof(uint64_t));
+	}
+
+	if (lkb->lkb_exflags & DLM_LKF_VALBLK) {
+		lkb->lkb_lvbptr = allocate_lvb(ls);
+		if (!lkb->lkb_lvbptr)
+			return -ENOMEM;
+		lvblen = rc->rc_header.h_length - sizeof(struct dlm_rcom) -
+			 sizeof(struct rcom_lock);
+		memcpy(lkb->lkb_lvbptr, rl->rl_lvb, lvblen);
+	}
+
+	/* Conversions between PR and CW (middle modes) need special handling.
+	   The real granted mode of these converting locks cannot be determined
+	   until all locks have been rebuilt on the rsb (recover_conversion) */
+
+	if (rl->rl_wait_type == DLM_MSG_CONVERT && middle_conversion(lkb)) {
+		rl->rl_status = DLM_LKSTS_CONVERT;
+		lkb->lkb_grmode = DLM_LOCK_IV;
+		rsb_set_flag(r, RSB_RECOVER_CONVERT);
+	}
+
+	return 0;
+}
+
+/* This lkb may have been recovered in a previous aborted recovery so we need
+   to check if the rsb already has an lkb with the given remote nodeid/lkid.
+   If so we just send back a standard reply.  If not, we create a new lkb with
+   the given values and send back our lkid.  We send back our lkid by sending
+   back the rcom_lock struct we got but with the remid field filled in. */
+
+int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
+{
+	struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
+	struct dlm_rsb *r;
+	struct dlm_lkb *lkb;
+	int error;
+
+	if (rl->rl_parent_lkid) {
+		error = -EOPNOTSUPP;
+		goto out;
+	}
+
+	error = find_rsb(ls, rl->rl_name, rl->rl_namelen, R_MASTER, &r);
+	if (error)
+		goto out;
+
+	lock_rsb(r);
+
+	lkb = search_remid(r, rc->rc_header.h_nodeid, rl->rl_lkid);
+	if (lkb) {
+		error = -EEXIST;
+		goto out_remid;
+	}
+
+	error = create_lkb(ls, &lkb);
+	if (error)
+		goto out_unlock;
+
+	error = receive_rcom_lock_args(ls, lkb, r, rc);
+	if (error) {
+		put_lkb(lkb);
+		goto out_unlock;
+	}
+
+	attach_lkb(r, lkb);
+	add_lkb(r, lkb, rl->rl_status);
+	error = 0;
+
+ out_remid:
+	/* this is the new value returned to the lock holder for
+	   saving in its process-copy lkb */
+	rl->rl_remid = lkb->lkb_id;
+
+ out_unlock:
+	unlock_rsb(r);
+	put_rsb(r);
+ out:
+	if (error)
+		log_print("recover_master_copy %d %x", error, rl->rl_lkid);
+	rl->rl_result = error;
+	return error;
+}
+
+int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
+{
+	struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
+	struct dlm_rsb *r;
+	struct dlm_lkb *lkb;
+	int error;
+
+	error = find_lkb(ls, rl->rl_lkid, &lkb);
+	if (error) {
+		log_error(ls, "recover_process_copy no lkid %x", rl->rl_lkid);
+		return error;
+	}
+
+	DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+	error = rl->rl_result;
+
+	r = lkb->lkb_resource;
+	hold_rsb(r);
+	lock_rsb(r);
+
+	switch (error) {
+	case -EEXIST:
+		log_debug(ls, "master copy exists %x", lkb->lkb_id);
+		/* fall through */
+	case 0:
+		lkb->lkb_remid = rl->rl_remid;
+		break;
+	default:
+		log_error(ls, "dlm_recover_process_copy unknown error %d %x",
+			  error, lkb->lkb_id);
+	}
+
+	/* an ack for dlm_recover_locks() which waits for replies from
+	   all the locks it sends to new masters */
+	dlm_recovered_lock(r);
+
+	unlock_rsb(r);
+	put_rsb(r);
+	put_lkb(lkb);
+
+	return 0;
+}
+
diff -urN oldtree/drivers/dlm/lock.h newtree/drivers/dlm/lock.h
--- oldtree/drivers/dlm/lock.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/lock.h	2006-02-21 15:58:32.781163064 +0000
@@ -0,0 +1,50 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __LOCK_DOT_H__
+#define __LOCK_DOT_H__
+
+void dlm_print_rsb(struct dlm_rsb *r);
+int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery);
+int dlm_modes_compat(int mode1, int mode2);
+int dlm_find_rsb(struct dlm_ls *ls, char *name, int namelen,
+	unsigned int flags, struct dlm_rsb **r_ret);
+void dlm_put_rsb(struct dlm_rsb *r);
+void dlm_hold_rsb(struct dlm_rsb *r);
+int dlm_put_lkb(struct dlm_lkb *lkb);
+void dlm_scan_rsbs(struct dlm_ls *ls);
+
+int dlm_purge_locks(struct dlm_ls *ls);
+void dlm_purge_mstcpy_locks(struct dlm_rsb *r);
+int dlm_grant_after_purge(struct dlm_ls *ls);
+int dlm_recover_waiters_post(struct dlm_ls *ls);
+void dlm_recover_waiters_pre(struct dlm_ls *ls);
+int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc);
+int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc);
+
+static inline int is_master(struct dlm_rsb *r)
+{
+	return !r->res_nodeid;
+}
+
+static inline void lock_rsb(struct dlm_rsb *r)
+{
+	mutex_lock(&r->res_mutex);
+}
+
+static inline void unlock_rsb(struct dlm_rsb *r)
+{
+	mutex_unlock(&r->res_mutex);
+}
+
+#endif
+
diff -urN oldtree/drivers/dlm/lockspace.c newtree/drivers/dlm/lockspace.c
--- oldtree/drivers/dlm/lockspace.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/lockspace.c	2006-02-21 15:58:32.782162912 +0000
@@ -0,0 +1,665 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "member.h"
+#include "recoverd.h"
+#include "ast.h"
+#include "dir.h"
+#include "lowcomms.h"
+#include "config.h"
+#include "memory.h"
+#include "lock.h"
+
+#ifdef CONFIG_DLM_DEBUG
+int dlm_create_debug_file(struct dlm_ls *ls);
+void dlm_delete_debug_file(struct dlm_ls *ls);
+#else
+static inline int dlm_create_debug_file(struct dlm_ls *ls) { return 0; }
+static inline void dlm_delete_debug_file(struct dlm_ls *ls) { }
+#endif
+
+static int			ls_count;
+static struct mutex		ls_lock;
+static struct list_head		lslist;
+static spinlock_t		lslist_lock;
+static struct task_struct *	scand_task;
+
+
+static ssize_t dlm_control_store(struct dlm_ls *ls, const char *buf, size_t len)
+{
+	ssize_t ret = len;
+	int n = simple_strtol(buf, NULL, 0);
+
+	switch (n) {
+	case 0:
+		dlm_ls_stop(ls);
+		break;
+	case 1:
+		dlm_ls_start(ls);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static ssize_t dlm_event_store(struct dlm_ls *ls, const char *buf, size_t len)
+{
+	ls->ls_uevent_result = simple_strtol(buf, NULL, 0);
+	set_bit(LSFL_UEVENT_WAIT, &ls->ls_flags);
+	wake_up(&ls->ls_uevent_wait);
+	return len;
+}
+
+static ssize_t dlm_id_show(struct dlm_ls *ls, char *buf)
+{
+	return sprintf(buf, "%u\n", ls->ls_global_id);
+}
+
+static ssize_t dlm_id_store(struct dlm_ls *ls, const char *buf, size_t len)
+{
+	ls->ls_global_id = simple_strtoul(buf, NULL, 0);
+	return len;
+}
+
+struct dlm_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct dlm_ls *, char *);
+	ssize_t (*store)(struct dlm_ls *, const char *, size_t);
+};
+
+static struct dlm_attr dlm_attr_control = {
+	.attr  = {.name = "control", .mode = S_IWUSR},
+	.store = dlm_control_store
+};
+
+static struct dlm_attr dlm_attr_event = {
+	.attr  = {.name = "event_done", .mode = S_IWUSR},
+	.store = dlm_event_store
+};
+
+static struct dlm_attr dlm_attr_id = {
+	.attr  = {.name = "id", .mode = S_IRUGO | S_IWUSR},
+	.show  = dlm_id_show,
+	.store = dlm_id_store
+};
+
+static struct attribute *dlm_attrs[] = {
+	&dlm_attr_control.attr,
+	&dlm_attr_event.attr,
+	&dlm_attr_id.attr,
+	NULL,
+};
+
+static ssize_t dlm_attr_show(struct kobject *kobj, struct attribute *attr,
+			     char *buf)
+{
+	struct dlm_ls *ls  = container_of(kobj, struct dlm_ls, ls_kobj);
+	struct dlm_attr *a = container_of(attr, struct dlm_attr, attr);
+	return a->show ? a->show(ls, buf) : 0;
+}
+
+static ssize_t dlm_attr_store(struct kobject *kobj, struct attribute *attr,
+			      const char *buf, size_t len)
+{
+	struct dlm_ls *ls  = container_of(kobj, struct dlm_ls, ls_kobj);
+	struct dlm_attr *a = container_of(attr, struct dlm_attr, attr);
+	return a->store ? a->store(ls, buf, len) : len;
+}
+
+static struct sysfs_ops dlm_attr_ops = {
+	.show  = dlm_attr_show,
+	.store = dlm_attr_store,
+};
+
+static struct kobj_type dlm_ktype = {
+	.default_attrs = dlm_attrs,
+	.sysfs_ops     = &dlm_attr_ops,
+};
+
+static struct kset dlm_kset = {
+	.subsys = &kernel_subsys,
+	.kobj   = {.name = "dlm",},
+	.ktype  = &dlm_ktype,
+};
+
+static int kobject_setup(struct dlm_ls *ls)
+{
+	char lsname[DLM_LOCKSPACE_LEN];
+	int error;
+
+	memset(lsname, 0, DLM_LOCKSPACE_LEN);
+	snprintf(lsname, DLM_LOCKSPACE_LEN, "%s", ls->ls_name);
+
+	error = kobject_set_name(&ls->ls_kobj, "%s", lsname);
+	if (error)
+		return error;
+
+	ls->ls_kobj.kset = &dlm_kset;
+	ls->ls_kobj.ktype = &dlm_ktype;
+	return 0;
+}
+
+static int do_uevent(struct dlm_ls *ls, int in)
+{
+	int error;
+
+	if (in)
+		kobject_uevent(&ls->ls_kobj, KOBJ_ONLINE);
+	else
+		kobject_uevent(&ls->ls_kobj, KOBJ_OFFLINE);
+
+	error = wait_event_interruptible(ls->ls_uevent_wait,
+			test_and_clear_bit(LSFL_UEVENT_WAIT, &ls->ls_flags));
+	if (error)
+		goto out;
+
+	error = ls->ls_uevent_result;
+ out:
+	return error;
+}
+
+
+int dlm_lockspace_init(void)
+{
+	int error;
+
+	ls_count = 0;
+	mutex_init(&ls_lock);
+	INIT_LIST_HEAD(&lslist);
+	spin_lock_init(&lslist_lock);
+
+	error = kset_register(&dlm_kset);
+	if (error)
+		printk("dlm_lockspace_init: cannot register kset %d\n", error);
+	return error;
+}
+
+void dlm_lockspace_exit(void)
+{
+	kset_unregister(&dlm_kset);
+}
+
+static int dlm_scand(void *data)
+{
+	struct dlm_ls *ls;
+
+	while (!kthread_should_stop()) {
+		list_for_each_entry(ls, &lslist, ls_list)
+			dlm_scan_rsbs(ls);
+		schedule_timeout_interruptible(dlm_config.scan_secs * HZ);
+	}
+	return 0;
+}
+
+static int dlm_scand_start(void)
+{
+	struct task_struct *p;
+	int error = 0;
+
+	p = kthread_run(dlm_scand, NULL, "dlm_scand");
+	if (IS_ERR(p))
+		error = PTR_ERR(p);
+	else
+		scand_task = p;
+	return error;
+}
+
+static void dlm_scand_stop(void)
+{
+	kthread_stop(scand_task);
+}
+
+static struct dlm_ls *dlm_find_lockspace_name(char *name, int namelen)
+{
+	struct dlm_ls *ls;
+
+	spin_lock(&lslist_lock);
+
+	list_for_each_entry(ls, &lslist, ls_list) {
+		if (ls->ls_namelen == namelen &&
+		    memcmp(ls->ls_name, name, namelen) == 0)
+			goto out;
+	}
+	ls = NULL;
+ out:
+	spin_unlock(&lslist_lock);
+	return ls;
+}
+
+struct dlm_ls *dlm_find_lockspace_global(uint32_t id)
+{
+	struct dlm_ls *ls;
+
+	spin_lock(&lslist_lock);
+
+	list_for_each_entry(ls, &lslist, ls_list) {
+		if (ls->ls_global_id == id) {
+			ls->ls_count++;
+			goto out;
+		}
+	}
+	ls = NULL;
+ out:
+	spin_unlock(&lslist_lock);
+	return ls;
+}
+
+struct dlm_ls *dlm_find_lockspace_local(void *id)
+{
+	struct dlm_ls *ls = id;
+
+	spin_lock(&lslist_lock);
+	ls->ls_count++;
+	spin_unlock(&lslist_lock);
+	return ls;
+}
+
+void dlm_put_lockspace(struct dlm_ls *ls)
+{
+	spin_lock(&lslist_lock);
+	ls->ls_count--;
+	spin_unlock(&lslist_lock);
+}
+
+static void remove_lockspace(struct dlm_ls *ls)
+{
+	for (;;) {
+		spin_lock(&lslist_lock);
+		if (ls->ls_count == 0) {
+			list_del(&ls->ls_list);
+			spin_unlock(&lslist_lock);
+			return;
+		}
+		spin_unlock(&lslist_lock);
+		ssleep(1);
+	}
+}
+
+static int threads_start(void)
+{
+	int error;
+
+	/* Thread which process lock requests for all lockspace's */
+	error = dlm_astd_start();
+	if (error) {
+		log_print("cannot start dlm_astd thread %d", error);
+		goto fail;
+	}
+
+	error = dlm_scand_start();
+	if (error) {
+		log_print("cannot start dlm_scand thread %d", error);
+		goto astd_fail;
+	}
+
+	/* Thread for sending/receiving messages for all lockspace's */
+	error = dlm_lowcomms_start();
+	if (error) {
+		log_print("cannot start dlm lowcomms %d", error);
+		goto scand_fail;
+	}
+
+	return 0;
+
+ scand_fail:
+	dlm_scand_stop();
+ astd_fail:
+	dlm_astd_stop();
+ fail:
+	return error;
+}
+
+static void threads_stop(void)
+{
+	dlm_scand_stop();
+	dlm_lowcomms_stop();
+	dlm_astd_stop();
+}
+
+static int new_lockspace(char *name, int namelen, void **lockspace,
+			 uint32_t flags, int lvblen)
+{
+	struct dlm_ls *ls;
+	int i, size, error = -ENOMEM;
+
+	if (namelen > DLM_LOCKSPACE_LEN)
+		return -EINVAL;
+
+	if (!lvblen || (lvblen % 8))
+		return -EINVAL;
+
+	if (!try_module_get(THIS_MODULE))
+		return -EINVAL;
+
+	ls = dlm_find_lockspace_name(name, namelen);
+	if (ls) {
+		*lockspace = ls;
+		module_put(THIS_MODULE);
+		return -EEXIST;
+	}
+
+	ls = kzalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL);
+	if (!ls)
+		goto out;
+	memcpy(ls->ls_name, name, namelen);
+	ls->ls_namelen = namelen;
+	ls->ls_exflags = flags;
+	ls->ls_lvblen = lvblen;
+	ls->ls_count = 0;
+	ls->ls_flags = 0;
+
+	size = dlm_config.rsbtbl_size;
+	ls->ls_rsbtbl_size = size;
+
+	ls->ls_rsbtbl = kmalloc(sizeof(struct dlm_rsbtable) * size, GFP_KERNEL);
+	if (!ls->ls_rsbtbl)
+		goto out_lsfree;
+	for (i = 0; i < size; i++) {
+		INIT_LIST_HEAD(&ls->ls_rsbtbl[i].list);
+		INIT_LIST_HEAD(&ls->ls_rsbtbl[i].toss);
+		rwlock_init(&ls->ls_rsbtbl[i].lock);
+	}
+
+	size = dlm_config.lkbtbl_size;
+	ls->ls_lkbtbl_size = size;
+
+	ls->ls_lkbtbl = kmalloc(sizeof(struct dlm_lkbtable) * size, GFP_KERNEL);
+	if (!ls->ls_lkbtbl)
+		goto out_rsbfree;
+	for (i = 0; i < size; i++) {
+		INIT_LIST_HEAD(&ls->ls_lkbtbl[i].list);
+		rwlock_init(&ls->ls_lkbtbl[i].lock);
+		ls->ls_lkbtbl[i].counter = 1;
+	}
+
+	size = dlm_config.dirtbl_size;
+	ls->ls_dirtbl_size = size;
+
+	ls->ls_dirtbl = kmalloc(sizeof(struct dlm_dirtable) * size, GFP_KERNEL);
+	if (!ls->ls_dirtbl)
+		goto out_lkbfree;
+	for (i = 0; i < size; i++) {
+		INIT_LIST_HEAD(&ls->ls_dirtbl[i].list);
+		rwlock_init(&ls->ls_dirtbl[i].lock);
+	}
+
+	INIT_LIST_HEAD(&ls->ls_waiters);
+	mutex_init(&ls->ls_waiters_mutex);
+
+	INIT_LIST_HEAD(&ls->ls_nodes);
+	INIT_LIST_HEAD(&ls->ls_nodes_gone);
+	ls->ls_num_nodes = 0;
+	ls->ls_low_nodeid = 0;
+	ls->ls_total_weight = 0;
+	ls->ls_node_array = NULL;
+
+	memset(&ls->ls_stub_rsb, 0, sizeof(struct dlm_rsb));
+	ls->ls_stub_rsb.res_ls = ls;
+
+	ls->ls_debug_dentry = NULL;
+
+	init_waitqueue_head(&ls->ls_uevent_wait);
+	ls->ls_uevent_result = 0;
+
+	ls->ls_recoverd_task = NULL;
+	mutex_init(&ls->ls_recoverd_active);
+	spin_lock_init(&ls->ls_recover_lock);
+	ls->ls_recover_status = 0;
+	ls->ls_recover_seq = 0;
+	ls->ls_recover_args = NULL;
+	init_rwsem(&ls->ls_in_recovery);
+	INIT_LIST_HEAD(&ls->ls_requestqueue);
+	mutex_init(&ls->ls_requestqueue_mutex);
+
+	ls->ls_recover_buf = kmalloc(dlm_config.buffer_size, GFP_KERNEL);
+	if (!ls->ls_recover_buf)
+		goto out_dirfree;
+
+	INIT_LIST_HEAD(&ls->ls_recover_list);
+	spin_lock_init(&ls->ls_recover_list_lock);
+	ls->ls_recover_list_count = 0;
+	init_waitqueue_head(&ls->ls_wait_general);
+	INIT_LIST_HEAD(&ls->ls_root_list);
+	init_rwsem(&ls->ls_root_sem);
+
+	down_write(&ls->ls_in_recovery);
+
+	error = dlm_recoverd_start(ls);
+	if (error) {
+		log_error(ls, "can't start dlm_recoverd %d", error);
+		goto out_rcomfree;
+	}
+
+	spin_lock(&lslist_lock);
+	list_add(&ls->ls_list, &lslist);
+	spin_unlock(&lslist_lock);
+
+	dlm_create_debug_file(ls);
+
+	error = kobject_setup(ls);
+	if (error)
+		goto out_del;
+
+	error = kobject_register(&ls->ls_kobj);
+	if (error)
+		goto out_del;
+
+	error = do_uevent(ls, 1);
+	if (error)
+		goto out_unreg;
+
+	*lockspace = ls;
+	return 0;
+
+ out_unreg:
+	kobject_unregister(&ls->ls_kobj);
+ out_del:
+	dlm_delete_debug_file(ls);
+	spin_lock(&lslist_lock);
+	list_del(&ls->ls_list);
+	spin_unlock(&lslist_lock);
+	dlm_recoverd_stop(ls);
+ out_rcomfree:
+	kfree(ls->ls_recover_buf);
+ out_dirfree:
+	kfree(ls->ls_dirtbl);
+ out_lkbfree:
+	kfree(ls->ls_lkbtbl);
+ out_rsbfree:
+	kfree(ls->ls_rsbtbl);
+ out_lsfree:
+	kfree(ls);
+ out:
+	module_put(THIS_MODULE);
+	return error;
+}
+
+int dlm_new_lockspace(char *name, int namelen, void **lockspace,
+		      uint32_t flags, int lvblen)
+{
+	int error = 0;
+
+	mutex_lock(&ls_lock);
+	if (!ls_count)
+		error = threads_start();
+	if (error)
+		goto out;
+
+	error = new_lockspace(name, namelen, lockspace, flags, lvblen);
+	if (!error)
+		ls_count++;
+ out:
+	mutex_unlock(&ls_lock);
+	return error;
+}
+
+/* Return 1 if the lockspace still has active remote locks,
+ *        2 if the lockspace still has active local locks.
+ */
+static int lockspace_busy(struct dlm_ls *ls)
+{
+	int i, lkb_found = 0;
+	struct dlm_lkb *lkb;
+
+	/* NOTE: We check the lockidtbl here rather than the resource table.
+	   This is because there may be LKBs queued as ASTs that have been
+	   unlinked from their RSBs and are pending deletion once the AST has
+	   been delivered */
+
+	for (i = 0; i < ls->ls_lkbtbl_size; i++) {
+		read_lock(&ls->ls_lkbtbl[i].lock);
+		if (!list_empty(&ls->ls_lkbtbl[i].list)) {
+			lkb_found = 1;
+			list_for_each_entry(lkb, &ls->ls_lkbtbl[i].list,
+					    lkb_idtbl_list) {
+				if (!lkb->lkb_nodeid) {
+					read_unlock(&ls->ls_lkbtbl[i].lock);
+					return 2;
+				}
+			}
+		}
+		read_unlock(&ls->ls_lkbtbl[i].lock);
+	}
+	return lkb_found;
+}
+
+static int release_lockspace(struct dlm_ls *ls, int force)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *rsb;
+	struct list_head *head;
+	int i;
+	int busy = lockspace_busy(ls);
+
+	if (busy > force)
+		return -EBUSY;
+
+	if (force < 3)
+		do_uevent(ls, 0);
+
+	dlm_recoverd_stop(ls);
+
+	remove_lockspace(ls);
+
+	dlm_delete_debug_file(ls);
+
+	dlm_astd_suspend();
+
+	kfree(ls->ls_recover_buf);
+
+	/*
+	 * Free direntry structs.
+	 */
+
+	dlm_dir_clear(ls);
+	kfree(ls->ls_dirtbl);
+
+	/*
+	 * Free all lkb's on lkbtbl[] lists.
+	 */
+
+	for (i = 0; i < ls->ls_lkbtbl_size; i++) {
+		head = &ls->ls_lkbtbl[i].list;
+		while (!list_empty(head)) {
+			lkb = list_entry(head->next, struct dlm_lkb,
+					 lkb_idtbl_list);
+
+			list_del(&lkb->lkb_idtbl_list);
+
+			dlm_del_ast(lkb);
+
+			if (lkb->lkb_lvbptr && lkb->lkb_flags & DLM_IFL_MSTCPY)
+				free_lvb(lkb->lkb_lvbptr);
+
+			free_lkb(lkb);
+		}
+	}
+	dlm_astd_resume();
+
+	kfree(ls->ls_lkbtbl);
+
+	/*
+	 * Free all rsb's on rsbtbl[] lists
+	 */
+
+	for (i = 0; i < ls->ls_rsbtbl_size; i++) {
+		head = &ls->ls_rsbtbl[i].list;
+		while (!list_empty(head)) {
+			rsb = list_entry(head->next, struct dlm_rsb,
+					 res_hashchain);
+
+			list_del(&rsb->res_hashchain);
+			free_rsb(rsb);
+		}
+
+		head = &ls->ls_rsbtbl[i].toss;
+		while (!list_empty(head)) {
+			rsb = list_entry(head->next, struct dlm_rsb,
+					 res_hashchain);
+			list_del(&rsb->res_hashchain);
+			free_rsb(rsb);
+		}
+	}
+
+	kfree(ls->ls_rsbtbl);
+
+	/*
+	 * Free structures on any other lists
+	 */
+
+	kfree(ls->ls_recover_args);
+	dlm_clear_free_entries(ls);
+	dlm_clear_members(ls);
+	dlm_clear_members_gone(ls);
+	kfree(ls->ls_node_array);
+	kobject_unregister(&ls->ls_kobj);
+	kfree(ls);
+
+	mutex_lock(&ls_lock);
+	ls_count--;
+	if (!ls_count)
+		threads_stop();
+	mutex_unlock(&ls_lock);
+
+	module_put(THIS_MODULE);
+	return 0;
+}
+
+/*
+ * Called when a system has released all its locks and is not going to use the
+ * lockspace any longer.  We free everything we're managing for this lockspace.
+ * Remaining nodes will go through the recovery process as if we'd died.  The
+ * lockspace must continue to function as usual, participating in recoveries,
+ * until this returns.
+ *
+ * Force has 4 possible values:
+ * 0 - don't destroy locksapce if it has any LKBs
+ * 1 - destroy lockspace if it has remote LKBs but not if it has local LKBs
+ * 2 - destroy lockspace regardless of LKBs
+ * 3 - destroy lockspace as part of a forced shutdown
+ */
+
+int dlm_release_lockspace(void *lockspace, int force)
+{
+	struct dlm_ls *ls;
+
+	ls = dlm_find_lockspace_local(lockspace);
+	if (!ls)
+		return -EINVAL;
+	dlm_put_lockspace(ls);
+	return release_lockspace(ls, force);
+}
+
diff -urN oldtree/drivers/dlm/lockspace.h newtree/drivers/dlm/lockspace.h
--- oldtree/drivers/dlm/lockspace.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/lockspace.h	2006-02-21 15:58:32.734170208 +0000
@@ -0,0 +1,24 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __LOCKSPACE_DOT_H__
+#define __LOCKSPACE_DOT_H__
+
+int dlm_lockspace_init(void);
+void dlm_lockspace_exit(void);
+struct dlm_ls *dlm_find_lockspace_global(uint32_t id);
+struct dlm_ls *dlm_find_lockspace_local(void *id);
+void dlm_put_lockspace(struct dlm_ls *ls);
+
+#endif				/* __LOCKSPACE_DOT_H__ */
+
diff -urN oldtree/drivers/dlm/lowcomms.c newtree/drivers/dlm/lowcomms.c
--- oldtree/drivers/dlm/lowcomms.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/lowcomms.c	2006-02-21 15:58:32.651182824 +0000
@@ -0,0 +1,1218 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+/*
+ * lowcomms.c
+ *
+ * This is the "low-level" comms layer.
+ *
+ * It is responsible for sending/receiving messages
+ * from other nodes in the cluster.
+ *
+ * Cluster nodes are referred to by their nodeids. nodeids are
+ * simply 32 bit numbers to the locking module - if they need to
+ * be expanded for the cluster infrastructure then that is it's
+ * responsibility. It is this layer's
+ * responsibility to resolve these into IP address or
+ * whatever it needs for inter-node communication.
+ *
+ * The comms level is two kernel threads that deal mainly with
+ * the receiving of messages from other nodes and passing them
+ * up to the mid-level comms layer (which understands the
+ * message format) for execution by the locking core, and
+ * a send thread which does all the setting up of connections
+ * to remote nodes and the sending of data. Threads are not allowed
+ * to send their own data because it may cause them to wait in times
+ * of high load. Also, this way, the sending thread can collect together
+ * messages bound for one node and send them in one block.
+ *
+ * I don't see any problem with the recv thread executing the locking
+ * code on behalf of remote processes as the locking code is
+ * short, efficient and never (well, hardly ever) waits.
+ *
+ */
+
+#include <asm/ioctls.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <net/sctp/user.h>
+#include <linux/pagemap.h>
+#include <linux/socket.h>
+#include <linux/idr.h>
+
+#include "dlm_internal.h"
+#include "lowcomms.h"
+#include "config.h"
+#include "midcomms.h"
+
+static struct sockaddr_storage *local_addr[DLM_MAX_ADDR_COUNT];
+static int			local_count;
+static int			local_nodeid;
+
+/* One of these per connected node */
+
+#define NI_INIT_PENDING 1
+#define NI_WRITE_PENDING 2
+
+struct nodeinfo {
+	spinlock_t		lock;
+	sctp_assoc_t		assoc_id;
+	unsigned long		flags;
+	struct list_head	write_list; /* nodes with pending writes */
+	struct list_head	writequeue; /* outgoing writequeue_entries */
+	spinlock_t		writequeue_lock;
+	int			nodeid;
+};
+
+static DEFINE_IDR(nodeinfo_idr);
+static struct rw_semaphore	nodeinfo_lock;
+static int			max_nodeid;
+
+struct cbuf {
+	unsigned		base;
+	unsigned		len;
+	unsigned		mask;
+};
+
+/* Just the one of these, now. But this struct keeps
+   the connection-specific variables together */
+
+#define CF_READ_PENDING 1
+
+struct connection {
+	struct socket          *sock;
+	unsigned long		flags;
+	struct page            *rx_page;
+	atomic_t		waiting_requests;
+	struct cbuf		cb;
+	int                     eagain_flag;
+};
+
+/* An entry waiting to be sent */
+
+struct writequeue_entry {
+	struct list_head	list;
+	struct page            *page;
+	int			offset;
+	int			len;
+	int			end;
+	int			users;
+	struct nodeinfo        *ni;
+};
+
+#define CBUF_ADD(cb, n) do { (cb)->len += n; } while(0)
+#define CBUF_EMPTY(cb) ((cb)->len == 0)
+#define CBUF_MAY_ADD(cb, n) (((cb)->len + (n)) < ((cb)->mask + 1))
+#define CBUF_DATA(cb) (((cb)->base + (cb)->len) & (cb)->mask)
+
+#define CBUF_INIT(cb, size) \
+do { \
+	(cb)->base = (cb)->len = 0; \
+	(cb)->mask = ((size)-1); \
+} while(0)
+
+#define CBUF_EAT(cb, n) \
+do { \
+	(cb)->len  -= (n); \
+	(cb)->base += (n); \
+	(cb)->base &= (cb)->mask; \
+} while(0)
+
+
+/* List of nodes which have writes pending */
+static struct list_head write_nodes;
+static spinlock_t write_nodes_lock;
+
+/* Maximum number of incoming messages to process before
+ * doing a schedule()
+ */
+#define MAX_RX_MSG_COUNT 25
+
+/* Manage daemons */
+static struct task_struct *recv_task;
+static struct task_struct *send_task;
+static wait_queue_head_t lowcomms_recv_wait;
+static atomic_t accepting;
+
+/* The SCTP connection */
+static struct connection sctp_con;
+
+
+static int nodeid_to_addr(int nodeid, struct sockaddr *retaddr)
+{
+	struct sockaddr_storage addr;
+	int error;
+
+	if (!local_count)
+		return -1;
+
+	error = dlm_nodeid_to_addr(nodeid, &addr);
+	if (error)
+		return error;
+
+	if (local_addr[0]->ss_family == AF_INET) {
+	        struct sockaddr_in *in4  = (struct sockaddr_in *) &addr;
+		struct sockaddr_in *ret4 = (struct sockaddr_in *) retaddr;
+		ret4->sin_addr.s_addr = in4->sin_addr.s_addr;
+	} else {
+	        struct sockaddr_in6 *in6  = (struct sockaddr_in6 *) &addr;
+		struct sockaddr_in6 *ret6 = (struct sockaddr_in6 *) retaddr;
+		memcpy(&ret6->sin6_addr, &in6->sin6_addr,
+		       sizeof(in6->sin6_addr));
+	}
+
+	return 0;
+}
+
+static struct nodeinfo *nodeid2nodeinfo(int nodeid, int alloc)
+{
+	struct nodeinfo *ni;
+	int r;
+	int n;
+
+	down_read(&nodeinfo_lock);
+	ni = idr_find(&nodeinfo_idr, nodeid);
+	up_read(&nodeinfo_lock);
+
+	if (!ni && alloc) {
+		down_write(&nodeinfo_lock);
+
+		ni = idr_find(&nodeinfo_idr, nodeid);
+		if (ni)
+			goto out_up;
+
+		r = idr_pre_get(&nodeinfo_idr, alloc);
+		if (!r)
+			goto out_up;
+
+		ni = kmalloc(sizeof(struct nodeinfo), alloc);
+		if (!ni)
+			goto out_up;
+
+		r = idr_get_new_above(&nodeinfo_idr, ni, nodeid, &n);
+		if (r) {
+			kfree(ni);
+			ni = NULL;
+			goto out_up;
+		}
+		if (n != nodeid) {
+			idr_remove(&nodeinfo_idr, n);
+			kfree(ni);
+			ni = NULL;
+			goto out_up;
+		}
+		memset(ni, 0, sizeof(struct nodeinfo));
+		spin_lock_init(&ni->lock);
+		INIT_LIST_HEAD(&ni->writequeue);
+		spin_lock_init(&ni->writequeue_lock);
+		ni->nodeid = nodeid;
+
+		if (nodeid > max_nodeid)
+			max_nodeid = nodeid;
+	out_up:
+		up_write(&nodeinfo_lock);
+	}
+
+	return ni;
+}
+
+/* Don't call this too often... */
+static struct nodeinfo *assoc2nodeinfo(sctp_assoc_t assoc)
+{
+	int i;
+	struct nodeinfo *ni;
+
+	for (i=1; i<=max_nodeid; i++) {
+		ni = nodeid2nodeinfo(i, 0);
+		if (ni && ni->assoc_id == assoc)
+			return ni;
+	}
+	return NULL;
+}
+
+/* Data or notification available on socket */
+static void lowcomms_data_ready(struct sock *sk, int count_unused)
+{
+	atomic_inc(&sctp_con.waiting_requests);
+	if (test_and_set_bit(CF_READ_PENDING, &sctp_con.flags))
+		return;
+
+	wake_up_interruptible(&lowcomms_recv_wait);
+}
+
+
+/* Add the port number to an IP6 or 4 sockaddr and return the address length.
+   Also padd out the struct with zeros to make comparisons meaningful */
+
+static void make_sockaddr(struct sockaddr_storage *saddr, uint16_t port,
+			  int *addr_len)
+{
+	struct sockaddr_in *local4_addr;
+	struct sockaddr_in6 *local6_addr;
+
+	if (!local_count)
+		return;
+
+	if (!port) {
+		if (local_addr[0]->ss_family == AF_INET) {
+			local4_addr = (struct sockaddr_in *)local_addr[0];
+			port = be16_to_cpu(local4_addr->sin_port);
+		} else {
+			local6_addr = (struct sockaddr_in6 *)local_addr[0];
+			port = be16_to_cpu(local6_addr->sin6_port);
+		}
+	}
+
+	saddr->ss_family = local_addr[0]->ss_family;
+	if (local_addr[0]->ss_family == AF_INET) {
+		struct sockaddr_in *in4_addr = (struct sockaddr_in *)saddr;
+		in4_addr->sin_port = cpu_to_be16(port);
+		memset(&in4_addr->sin_zero, 0, sizeof(in4_addr->sin_zero));
+		memset(in4_addr+1, 0, sizeof(struct sockaddr_storage) -
+				      sizeof(struct sockaddr_in));
+		*addr_len = sizeof(struct sockaddr_in);
+	} else {
+		struct sockaddr_in6 *in6_addr = (struct sockaddr_in6 *)saddr;
+		in6_addr->sin6_port = cpu_to_be16(port);
+		memset(in6_addr+1, 0, sizeof(struct sockaddr_storage) -
+				      sizeof(struct sockaddr_in6));
+		*addr_len = sizeof(struct sockaddr_in6);
+	}
+}
+
+/* Close the connection and tidy up */
+static void close_connection(void)
+{
+	if (sctp_con.sock) {
+		sock_release(sctp_con.sock);
+		sctp_con.sock = NULL;
+	}
+
+	if (sctp_con.rx_page) {
+		__free_page(sctp_con.rx_page);
+		sctp_con.rx_page = NULL;
+	}
+}
+
+/* We only send shutdown messages to nodes that are not part of the cluster */
+static void send_shutdown(sctp_assoc_t associd)
+{
+	static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+	struct msghdr outmessage;
+	struct cmsghdr *cmsg;
+	struct sctp_sndrcvinfo *sinfo;
+	int ret;
+
+	outmessage.msg_name = NULL;
+	outmessage.msg_namelen = 0;
+	outmessage.msg_control = outcmsg;
+	outmessage.msg_controllen = sizeof(outcmsg);
+	outmessage.msg_flags = MSG_EOR;
+
+	cmsg = CMSG_FIRSTHDR(&outmessage);
+	cmsg->cmsg_level = IPPROTO_SCTP;
+	cmsg->cmsg_type = SCTP_SNDRCV;
+	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+	outmessage.msg_controllen = cmsg->cmsg_len;
+	sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+	memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+
+	sinfo->sinfo_flags |= MSG_EOF;
+	sinfo->sinfo_assoc_id = associd;
+
+	ret = kernel_sendmsg(sctp_con.sock, &outmessage, NULL, 0, 0);
+
+	if (ret != 0)
+		log_print("send EOF to node failed: %d", ret);
+}
+
+
+/* INIT failed but we don't know which node...
+   restart INIT on all pending nodes */
+static void init_failed(void)
+{
+	int i;
+	struct nodeinfo *ni;
+
+	for (i=1; i<=max_nodeid; i++) {
+		ni = nodeid2nodeinfo(i, 0);
+		if (!ni)
+			continue;
+
+		if (test_and_clear_bit(NI_INIT_PENDING, &ni->flags)) {
+			ni->assoc_id = 0;
+			if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
+				spin_lock_bh(&write_nodes_lock);
+				list_add_tail(&ni->write_list, &write_nodes);
+				spin_unlock_bh(&write_nodes_lock);
+			}
+		}
+	}
+	wake_up_process(send_task);
+}
+
+/* Something happened to an association */
+static void process_sctp_notification(struct msghdr *msg, char *buf)
+{
+	union sctp_notification *sn = (union sctp_notification *)buf;
+
+	if (sn->sn_header.sn_type == SCTP_ASSOC_CHANGE) {
+		switch (sn->sn_assoc_change.sac_state) {
+
+		case SCTP_COMM_UP:
+		case SCTP_RESTART:
+		{
+			/* Check that the new node is in the lockspace */
+			struct sctp_prim prim;
+			mm_segment_t fs;
+			int nodeid;
+			int prim_len, ret;
+			int addr_len;
+			struct nodeinfo *ni;
+
+			/* This seems to happen when we received a connection
+			 * too early... or something...  anyway, it happens but
+			 * we always seem to get a real message too, see
+			 * receive_from_sock */
+
+			if ((int)sn->sn_assoc_change.sac_assoc_id <= 0) {
+				log_print("COMM_UP for invalid assoc ID %d",
+					 (int)sn->sn_assoc_change.sac_assoc_id);
+				init_failed();
+				return;
+			}
+			memset(&prim, 0, sizeof(struct sctp_prim));
+			prim_len = sizeof(struct sctp_prim);
+			prim.ssp_assoc_id = sn->sn_assoc_change.sac_assoc_id;
+
+			fs = get_fs();
+			set_fs(get_ds());
+			ret = sctp_con.sock->ops->getsockopt(sctp_con.sock,
+						IPPROTO_SCTP, SCTP_PRIMARY_ADDR,
+						(char*)&prim, &prim_len);
+			set_fs(fs);
+			if (ret < 0) {
+				struct nodeinfo *ni;
+
+				log_print("getsockopt/sctp_primary_addr on "
+					  "new assoc %d failed : %d",
+				    (int)sn->sn_assoc_change.sac_assoc_id, ret);
+
+				/* Retry INIT later */
+				ni = assoc2nodeinfo(sn->sn_assoc_change.sac_assoc_id);
+				if (ni)
+					clear_bit(NI_INIT_PENDING, &ni->flags);
+				return;
+			}
+			make_sockaddr(&prim.ssp_addr, 0, &addr_len);
+			if (dlm_addr_to_nodeid(&prim.ssp_addr, &nodeid)) {
+				log_print("reject connect from unknown addr");
+				send_shutdown(prim.ssp_assoc_id);
+				return;
+			}
+
+			ni = nodeid2nodeinfo(nodeid, GFP_KERNEL);
+			if (!ni)
+				return;
+
+			/* Save the assoc ID */
+			spin_lock(&ni->lock);
+			ni->assoc_id = sn->sn_assoc_change.sac_assoc_id;
+			spin_unlock(&ni->lock);
+
+			log_print("got new/restarted association %d nodeid %d",
+			       (int)sn->sn_assoc_change.sac_assoc_id, nodeid);
+
+			/* Send any pending writes */
+			clear_bit(NI_INIT_PENDING, &ni->flags);
+			if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
+				spin_lock_bh(&write_nodes_lock);
+				list_add_tail(&ni->write_list, &write_nodes);
+				spin_unlock_bh(&write_nodes_lock);
+			}
+			wake_up_process(send_task);
+		}
+		break;
+
+		case SCTP_COMM_LOST:
+		case SCTP_SHUTDOWN_COMP:
+		{
+			struct nodeinfo *ni;
+
+			ni = assoc2nodeinfo(sn->sn_assoc_change.sac_assoc_id);
+			if (ni) {
+				spin_lock(&ni->lock);
+				ni->assoc_id = 0;
+				spin_unlock(&ni->lock);
+			}
+		}
+		break;
+
+		/* We don't know which INIT failed, so clear the PENDING flags
+		 * on them all.  if assoc_id is zero then it will then try
+		 * again */
+
+		case SCTP_CANT_STR_ASSOC:
+		{
+			log_print("Can't start SCTP association - retrying");
+			init_failed();
+		}
+		break;
+
+		default:
+			log_print("unexpected SCTP assoc change id=%d state=%d",
+				  (int)sn->sn_assoc_change.sac_assoc_id,
+				  sn->sn_assoc_change.sac_state);
+		}
+	}
+}
+
+/* Data received from remote end */
+static int receive_from_sock(void)
+{
+	int ret = 0;
+	struct msghdr msg;
+	struct kvec iov[2];
+	unsigned len;
+	int r;
+	struct sctp_sndrcvinfo *sinfo;
+	struct cmsghdr *cmsg;
+	struct nodeinfo *ni;
+
+	/* These two are marginally too big for stack allocation, but this
+	 * function is (currently) only called by dlm_recvd so static should be
+	 * OK.
+	 */
+	static struct sockaddr_storage msgname;
+	static char incmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+
+	if (sctp_con.sock == NULL)
+		goto out;
+
+	if (sctp_con.rx_page == NULL) {
+		/*
+		 * This doesn't need to be atomic, but I think it should
+		 * improve performance if it is.
+		 */
+		sctp_con.rx_page = alloc_page(GFP_ATOMIC);
+		if (sctp_con.rx_page == NULL)
+			goto out_resched;
+		CBUF_INIT(&sctp_con.cb, PAGE_CACHE_SIZE);
+	}
+
+	memset(&incmsg, 0, sizeof(incmsg));
+	memset(&msgname, 0, sizeof(msgname));
+
+	memset(incmsg, 0, sizeof(incmsg));
+	msg.msg_name = &msgname;
+	msg.msg_namelen = sizeof(msgname);
+	msg.msg_flags = 0;
+	msg.msg_control = incmsg;
+	msg.msg_controllen = sizeof(incmsg);
+
+	/* I don't see why this circular buffer stuff is necessary for SCTP
+	 * which is a packet-based protocol, but the whole thing breaks under
+	 * load without it! The overhead is minimal (and is in the TCP lowcomms
+	 * anyway, of course) so I'll leave it in until I can figure out what's
+	 * really happening.
+	 */
+
+	/*
+	 * iov[0] is the bit of the circular buffer between the current end
+	 * point (cb.base + cb.len) and the end of the buffer.
+	 */
+	iov[0].iov_len = sctp_con.cb.base - CBUF_DATA(&sctp_con.cb);
+	iov[0].iov_base = page_address(sctp_con.rx_page) +
+			  CBUF_DATA(&sctp_con.cb);
+	iov[1].iov_len = 0;
+
+	/*
+	 * iov[1] is the bit of the circular buffer between the start of the
+	 * buffer and the start of the currently used section (cb.base)
+	 */
+	if (CBUF_DATA(&sctp_con.cb) >= sctp_con.cb.base) {
+		iov[0].iov_len = PAGE_CACHE_SIZE - CBUF_DATA(&sctp_con.cb);
+		iov[1].iov_len = sctp_con.cb.base;
+		iov[1].iov_base = page_address(sctp_con.rx_page);
+		msg.msg_iovlen = 2;
+	}
+	len = iov[0].iov_len + iov[1].iov_len;
+
+	r = ret = kernel_recvmsg(sctp_con.sock, &msg, iov, 1, len,
+				 MSG_NOSIGNAL | MSG_DONTWAIT);
+	if (ret <= 0)
+		goto out_close;
+
+	msg.msg_control = incmsg;
+	msg.msg_controllen = sizeof(incmsg);
+	cmsg = CMSG_FIRSTHDR(&msg);
+	sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+
+	if (msg.msg_flags & MSG_NOTIFICATION) {
+		process_sctp_notification(&msg, page_address(sctp_con.rx_page));
+		return 0;
+	}
+
+	/* Is this a new association ? */
+	ni = nodeid2nodeinfo(le32_to_cpu(sinfo->sinfo_ppid), GFP_KERNEL);
+	if (ni) {
+		ni->assoc_id = sinfo->sinfo_assoc_id;
+		if (test_and_clear_bit(NI_INIT_PENDING, &ni->flags)) {
+
+			if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
+				spin_lock_bh(&write_nodes_lock);
+				list_add_tail(&ni->write_list, &write_nodes);
+				spin_unlock_bh(&write_nodes_lock);
+			}
+			wake_up_process(send_task);
+		}
+	}
+
+	/* INIT sends a message with length of 1 - ignore it */
+	if (r == 1)
+		return 0;
+
+	CBUF_ADD(&sctp_con.cb, ret);
+	ret = dlm_process_incoming_buffer(cpu_to_le32(sinfo->sinfo_ppid),
+					  page_address(sctp_con.rx_page),
+					  sctp_con.cb.base, sctp_con.cb.len,
+					  PAGE_CACHE_SIZE);
+	if (ret < 0)
+		goto out_close;
+	CBUF_EAT(&sctp_con.cb, ret);
+
+      out:
+	ret = 0;
+	goto out_ret;
+
+      out_resched:
+	lowcomms_data_ready(sctp_con.sock->sk, 0);
+	ret = 0;
+	schedule();
+	goto out_ret;
+
+      out_close:
+	if (ret != -EAGAIN)
+		log_print("error reading from sctp socket: %d", ret);
+      out_ret:
+	return ret;
+}
+
+/* Bind to an IP address. SCTP allows multiple address so it can do multi-homing */
+static int add_bind_addr(struct sockaddr_storage *addr, int addr_len, int num)
+{
+	mm_segment_t fs;
+	int result = 0;
+
+	fs = get_fs();
+	set_fs(get_ds());
+	if (num == 1)
+		result = sctp_con.sock->ops->bind(sctp_con.sock,
+					(struct sockaddr *) addr, addr_len);
+	else
+		result = sctp_con.sock->ops->setsockopt(sctp_con.sock, SOL_SCTP,
+				SCTP_SOCKOPT_BINDX_ADD, (char *)addr, addr_len);
+	set_fs(fs);
+
+	if (result < 0)
+		log_print("Can't bind to port %d addr number %d",
+			  dlm_config.tcp_port, num);
+
+	return result;
+}
+
+static void init_local(void)
+{
+	struct sockaddr_storage sas, *addr;
+	int i;
+
+	local_nodeid = dlm_our_nodeid();
+
+	for (i = 0; i < DLM_MAX_ADDR_COUNT - 1; i++) {
+		if (dlm_our_addr(&sas, i))
+			break;
+
+		addr = kmalloc(sizeof(*addr), GFP_KERNEL);
+		if (!addr)
+			break;
+		memcpy(addr, &sas, sizeof(*addr));
+		local_addr[local_count++] = addr;
+	}
+}
+
+/* Initialise SCTP socket and bind to all interfaces */
+static int init_sock(void)
+{
+	mm_segment_t fs;
+	struct socket *sock = NULL;
+	struct sockaddr_storage localaddr;
+	struct sctp_event_subscribe subscribe;
+	int result = -EINVAL, num = 1, i, addr_len;
+
+	if (!local_count) {
+		init_local();
+		if (!local_count) {
+			log_print("no local IP address has been set");
+			goto out;
+		}
+	}
+
+	result = sock_create_kern(local_addr[0]->ss_family, SOCK_SEQPACKET,
+				  IPPROTO_SCTP, &sock);
+	if (result < 0) {
+		log_print("Can't create comms socket, check SCTP is loaded");
+		goto out;
+	}
+
+	/* Listen for events */
+	memset(&subscribe, 0, sizeof(subscribe));
+	subscribe.sctp_data_io_event = 1;
+	subscribe.sctp_association_event = 1;
+	subscribe.sctp_send_failure_event = 1;
+	subscribe.sctp_shutdown_event = 1;
+	subscribe.sctp_partial_delivery_event = 1;
+
+	fs = get_fs();
+	set_fs(get_ds());
+	result = sock->ops->setsockopt(sock, SOL_SCTP, SCTP_EVENTS,
+				       (char *)&subscribe, sizeof(subscribe));
+	set_fs(fs);
+
+	if (result < 0) {
+		log_print("Failed to set SCTP_EVENTS on socket: result=%d",
+			  result);
+		goto create_delsock;
+	}
+
+	/* Init con struct */
+	sock->sk->sk_user_data = &sctp_con;
+	sctp_con.sock = sock;
+	sctp_con.sock->sk->sk_data_ready = lowcomms_data_ready;
+
+	/* Bind to all interfaces. */
+	for (i = 0; i < local_count; i++) {
+		memcpy(&localaddr, local_addr[i], sizeof(localaddr));
+		make_sockaddr(&localaddr, dlm_config.tcp_port, &addr_len);
+
+		result = add_bind_addr(&localaddr, addr_len, num);
+		if (result)
+			goto create_delsock;
+		++num;
+	}
+
+	result = sock->ops->listen(sock, 5);
+	if (result < 0) {
+		log_print("Can't set socket listening");
+		goto create_delsock;
+	}
+
+	return 0;
+
+ create_delsock:
+	sock_release(sock);
+	sctp_con.sock = NULL;
+ out:
+	return result;
+}
+
+
+static struct writequeue_entry *new_writequeue_entry(int allocation)
+{
+	struct writequeue_entry *entry;
+
+	entry = kmalloc(sizeof(struct writequeue_entry), allocation);
+	if (!entry)
+		return NULL;
+
+	entry->page = alloc_page(allocation);
+	if (!entry->page) {
+		kfree(entry);
+		return NULL;
+	}
+
+	entry->offset = 0;
+	entry->len = 0;
+	entry->end = 0;
+	entry->users = 0;
+
+	return entry;
+}
+
+void *dlm_lowcomms_get_buffer(int nodeid, int len, int allocation, char **ppc)
+{
+	struct writequeue_entry *e;
+	int offset = 0;
+	int users = 0;
+	struct nodeinfo *ni;
+
+	if (!atomic_read(&accepting))
+		return NULL;
+
+	ni = nodeid2nodeinfo(nodeid, allocation);
+	if (!ni)
+		return NULL;
+
+	spin_lock(&ni->writequeue_lock);
+	e = list_entry(ni->writequeue.prev, struct writequeue_entry, list);
+	if (((struct list_head *) e == &ni->writequeue) ||
+	    (PAGE_CACHE_SIZE - e->end < len)) {
+		e = NULL;
+	} else {
+		offset = e->end;
+		e->end += len;
+		users = e->users++;
+	}
+	spin_unlock(&ni->writequeue_lock);
+
+	if (e) {
+	      got_one:
+		if (users == 0)
+			kmap(e->page);
+		*ppc = page_address(e->page) + offset;
+		return e;
+	}
+
+	e = new_writequeue_entry(allocation);
+	if (e) {
+		spin_lock(&ni->writequeue_lock);
+		offset = e->end;
+		e->end += len;
+		e->ni = ni;
+		users = e->users++;
+		list_add_tail(&e->list, &ni->writequeue);
+		spin_unlock(&ni->writequeue_lock);
+		goto got_one;
+	}
+	return NULL;
+}
+
+void dlm_lowcomms_commit_buffer(void *arg)
+{
+	struct writequeue_entry *e = (struct writequeue_entry *) arg;
+	int users;
+	struct nodeinfo *ni = e->ni;
+
+	if (!atomic_read(&accepting))
+		return;
+
+	spin_lock(&ni->writequeue_lock);
+	users = --e->users;
+	if (users)
+		goto out;
+	e->len = e->end - e->offset;
+	kunmap(e->page);
+	spin_unlock(&ni->writequeue_lock);
+
+	if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
+		spin_lock_bh(&write_nodes_lock);
+		list_add_tail(&ni->write_list, &write_nodes);
+		spin_unlock_bh(&write_nodes_lock);
+		wake_up_process(send_task);
+	}
+	return;
+
+      out:
+	spin_unlock(&ni->writequeue_lock);
+	return;
+}
+
+static void free_entry(struct writequeue_entry *e)
+{
+	__free_page(e->page);
+	kfree(e);
+}
+
+/* Initiate an SCTP association. In theory we could just use sendmsg() on
+   the first IP address and it should work, but this allows us to set up the
+   association before sending any valuable data that we can't afford to lose.
+   It also keeps the send path clean as it can now always use the association ID */
+static void initiate_association(int nodeid)
+{
+	struct sockaddr_storage rem_addr;
+	static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+	struct msghdr outmessage;
+	struct cmsghdr *cmsg;
+	struct sctp_sndrcvinfo *sinfo;
+	int ret;
+	int addrlen;
+	char buf[1];
+	struct kvec iov[1];
+	struct nodeinfo *ni;
+
+	log_print("Initiating association with node %d", nodeid);
+
+	ni = nodeid2nodeinfo(nodeid, GFP_KERNEL);
+	if (!ni)
+		return;
+
+	if (nodeid_to_addr(nodeid, (struct sockaddr *)&rem_addr)) {
+		log_print("no address for nodeid %d", nodeid);
+		return;
+	}
+
+	make_sockaddr(&rem_addr, dlm_config.tcp_port, &addrlen);
+
+	outmessage.msg_name = &rem_addr;
+	outmessage.msg_namelen = addrlen;
+	outmessage.msg_control = outcmsg;
+	outmessage.msg_controllen = sizeof(outcmsg);
+	outmessage.msg_flags = MSG_EOR;
+
+	iov[0].iov_base = buf;
+	iov[0].iov_len = 1;
+
+	/* Real INIT messages seem to cause trouble. Just send a 1 byte message
+	   we can afford to lose */
+	cmsg = CMSG_FIRSTHDR(&outmessage);
+	cmsg->cmsg_level = IPPROTO_SCTP;
+	cmsg->cmsg_type = SCTP_SNDRCV;
+	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+	sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+	memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+	sinfo->sinfo_ppid = cpu_to_le32(local_nodeid);
+
+	outmessage.msg_controllen = cmsg->cmsg_len;
+	ret = kernel_sendmsg(sctp_con.sock, &outmessage, iov, 1, 1);
+	if (ret < 0) {
+		log_print("send INIT to node failed: %d", ret);
+		/* Try again later */
+		clear_bit(NI_INIT_PENDING, &ni->flags);
+	}
+}
+
+/* Send a message */
+static int send_to_sock(struct nodeinfo *ni)
+{
+	int ret = 0;
+	struct writequeue_entry *e;
+	int len, offset;
+	struct msghdr outmsg;
+	static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+	struct cmsghdr *cmsg;
+	struct sctp_sndrcvinfo *sinfo;
+	struct kvec iov;
+
+        /* See if we need to init an association before we start
+	   sending precious messages */
+	spin_lock(&ni->lock);
+	if (!ni->assoc_id && !test_and_set_bit(NI_INIT_PENDING, &ni->flags)) {
+		spin_unlock(&ni->lock);
+		initiate_association(ni->nodeid);
+		return 0;
+	}
+	spin_unlock(&ni->lock);
+
+	outmsg.msg_name = NULL; /* We use assoc_id */
+	outmsg.msg_namelen = 0;
+	outmsg.msg_control = outcmsg;
+	outmsg.msg_controllen = sizeof(outcmsg);
+	outmsg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL | MSG_EOR;
+
+	cmsg = CMSG_FIRSTHDR(&outmsg);
+	cmsg->cmsg_level = IPPROTO_SCTP;
+	cmsg->cmsg_type = SCTP_SNDRCV;
+	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+	sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+	memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+	sinfo->sinfo_ppid = cpu_to_le32(local_nodeid);
+	sinfo->sinfo_assoc_id = ni->assoc_id;
+	outmsg.msg_controllen = cmsg->cmsg_len;
+
+	spin_lock(&ni->writequeue_lock);
+	for (;;) {
+		if (list_empty(&ni->writequeue))
+			break;
+		e = list_entry(ni->writequeue.next, struct writequeue_entry,
+			       list);
+		kmap(e->page);
+		len = e->len;
+		offset = e->offset;
+		BUG_ON(len == 0 && e->users == 0);
+		spin_unlock(&ni->writequeue_lock);
+
+		ret = 0;
+		if (len) {
+			iov.iov_base = page_address(e->page)+offset;
+			iov.iov_len = len;
+
+			ret = kernel_sendmsg(sctp_con.sock, &outmsg, &iov, 1,
+					     len);
+			if (ret == -EAGAIN) {
+				sctp_con.eagain_flag = 1;
+				goto out;
+			} else if (ret < 0)
+				goto send_error;
+		} else {
+			/* Don't starve people filling buffers */
+			schedule();
+		}
+
+		spin_lock(&ni->writequeue_lock);
+		e->offset += ret;
+		e->len -= ret;
+
+		if (e->len == 0 && e->users == 0) {
+			list_del(&e->list);
+			free_entry(e);
+			continue;
+		}
+	}
+	spin_unlock(&ni->writequeue_lock);
+ out:
+	return ret;
+
+ send_error:
+	log_print("Error sending to node %d %d", ni->nodeid, ret);
+	spin_lock(&ni->lock);
+	if (!test_and_set_bit(NI_INIT_PENDING, &ni->flags)) {
+		ni->assoc_id = 0;
+		spin_unlock(&ni->lock);
+		initiate_association(ni->nodeid);
+	} else
+		spin_unlock(&ni->lock);
+
+	return ret;
+}
+
+/* Try to send any messages that are pending */
+static void process_output_queue(void)
+{
+	struct list_head *list;
+	struct list_head *temp;
+
+	spin_lock_bh(&write_nodes_lock);
+	list_for_each_safe(list, temp, &write_nodes) {
+		struct nodeinfo *ni =
+		    list_entry(list, struct nodeinfo, write_list);
+		clear_bit(NI_WRITE_PENDING, &ni->flags);
+		list_del(&ni->write_list);
+
+		spin_unlock_bh(&write_nodes_lock);
+
+		send_to_sock(ni);
+		spin_lock_bh(&write_nodes_lock);
+	}
+	spin_unlock_bh(&write_nodes_lock);
+}
+
+/* Called after we've had -EAGAIN and been woken up */
+static void refill_write_queue(void)
+{
+	int i;
+
+	for (i=1; i<=max_nodeid; i++) {
+		struct nodeinfo *ni = nodeid2nodeinfo(i, 0);
+
+		if (ni) {
+			if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
+				spin_lock_bh(&write_nodes_lock);
+				list_add_tail(&ni->write_list, &write_nodes);
+				spin_unlock_bh(&write_nodes_lock);
+			}
+		}
+	}
+}
+
+static void clean_one_writequeue(struct nodeinfo *ni)
+{
+	struct list_head *list;
+	struct list_head *temp;
+
+	spin_lock(&ni->writequeue_lock);
+	list_for_each_safe(list, temp, &ni->writequeue) {
+		struct writequeue_entry *e =
+			list_entry(list, struct writequeue_entry, list);
+		list_del(&e->list);
+		free_entry(e);
+	}
+	spin_unlock(&ni->writequeue_lock);
+}
+
+static void clean_writequeues(void)
+{
+	int i;
+
+	for (i=1; i<=max_nodeid; i++) {
+		struct nodeinfo *ni = nodeid2nodeinfo(i, 0);
+		if (ni)
+			clean_one_writequeue(ni);
+	}
+}
+
+
+static void dealloc_nodeinfo(void)
+{
+	int i;
+
+	for (i=1; i<=max_nodeid; i++) {
+		struct nodeinfo *ni = nodeid2nodeinfo(i, 0);
+		if (ni) {
+			idr_remove(&nodeinfo_idr, i);
+			kfree(ni);
+		}
+	}
+}
+
+static int write_list_empty(void)
+{
+	int status;
+
+	spin_lock_bh(&write_nodes_lock);
+	status = list_empty(&write_nodes);
+	spin_unlock_bh(&write_nodes_lock);
+
+	return status;
+}
+
+static int dlm_recvd(void *data)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	while (!kthread_should_stop()) {
+		int count = 0;
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&lowcomms_recv_wait, &wait);
+		if (!test_bit(CF_READ_PENDING, &sctp_con.flags))
+			schedule();
+		remove_wait_queue(&lowcomms_recv_wait, &wait);
+		set_current_state(TASK_RUNNING);
+
+		if (test_and_clear_bit(CF_READ_PENDING, &sctp_con.flags)) {
+			int ret;
+
+			do {
+				ret = receive_from_sock();
+
+				/* Don't starve out everyone else */
+				if (++count >= MAX_RX_MSG_COUNT) {
+					schedule();
+					count = 0;
+				}
+			} while (!kthread_should_stop() && ret >=0);
+		}
+		schedule();
+	}
+
+	return 0;
+}
+
+static int dlm_sendd(void *data)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	add_wait_queue(sctp_con.sock->sk->sk_sleep, &wait);
+
+	while (!kthread_should_stop()) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (write_list_empty())
+			schedule();
+		set_current_state(TASK_RUNNING);
+
+		if (sctp_con.eagain_flag) {
+			sctp_con.eagain_flag = 0;
+			refill_write_queue();
+		}
+		process_output_queue();
+	}
+
+	remove_wait_queue(sctp_con.sock->sk->sk_sleep, &wait);
+
+	return 0;
+}
+
+static void daemons_stop(void)
+{
+	kthread_stop(recv_task);
+	kthread_stop(send_task);
+}
+
+static int daemons_start(void)
+{
+	struct task_struct *p;
+	int error;
+
+	p = kthread_run(dlm_recvd, NULL, "dlm_recvd");
+	error = IS_ERR(p);
+       	if (error) {
+		log_print("can't start dlm_recvd %d", error);
+		return error;
+	}
+	recv_task = p;
+
+	p = kthread_run(dlm_sendd, NULL, "dlm_sendd");
+	error = IS_ERR(p);
+       	if (error) {
+		log_print("can't start dlm_sendd %d", error);
+		kthread_stop(recv_task);
+		return error;
+	}
+	send_task = p;
+
+	return 0;
+}
+
+/*
+ * This is quite likely to sleep...
+ */
+int dlm_lowcomms_start(void)
+{
+	int error;
+
+	spin_lock_init(&write_nodes_lock);
+	INIT_LIST_HEAD(&write_nodes);
+	init_rwsem(&nodeinfo_lock);
+
+	error = init_sock();
+	if (error)
+		goto fail_sock;
+	error = daemons_start();
+	if (error)
+		goto fail_sock;
+	atomic_set(&accepting, 1);
+	return 0;
+
+ fail_sock:
+	close_connection();
+	return error;
+}
+
+/* Set all the activity flags to prevent any socket activity. */
+
+void dlm_lowcomms_stop(void)
+{
+	atomic_set(&accepting, 0);
+	sctp_con.flags = 0x7;
+	daemons_stop();
+	clean_writequeues();
+	close_connection();
+	dealloc_nodeinfo();
+	max_nodeid = 0;
+}
+
+int dlm_lowcomms_init(void)
+{
+	init_waitqueue_head(&lowcomms_recv_wait);
+	return 0;
+}
+
+void dlm_lowcomms_exit(void)
+{
+	int i;
+
+	for (i = 0; i < local_count; i++)
+		kfree(local_addr[i]);
+	local_count = 0;
+	local_nodeid = 0;
+}
+
diff -urN oldtree/drivers/dlm/lowcomms.h newtree/drivers/dlm/lowcomms.h
--- oldtree/drivers/dlm/lowcomms.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/lowcomms.h	2006-02-21 15:58:32.651182824 +0000
@@ -0,0 +1,25 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __LOWCOMMS_DOT_H__
+#define __LOWCOMMS_DOT_H__
+
+int dlm_lowcomms_init(void);
+void dlm_lowcomms_exit(void);
+int dlm_lowcomms_start(void);
+void dlm_lowcomms_stop(void);
+void *dlm_lowcomms_get_buffer(int nodeid, int len, int allocation, char **ppc);
+void dlm_lowcomms_commit_buffer(void *mh);
+
+#endif				/* __LOWCOMMS_DOT_H__ */
+
diff -urN oldtree/drivers/dlm/lvb_table.h newtree/drivers/dlm/lvb_table.h
--- oldtree/drivers/dlm/lvb_table.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/lvb_table.h	2006-02-21 15:58:32.277239672 +0000
@@ -0,0 +1,18 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __LVB_TABLE_DOT_H__
+#define __LVB_TABLE_DOT_H__
+
+extern const int dlm_lvb_operations[8][8];
+
+#endif
diff -urN oldtree/drivers/dlm/main.c newtree/drivers/dlm/main.c
--- oldtree/drivers/dlm/main.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/main.c	2006-02-21 15:58:32.670179936 +0000
@@ -0,0 +1,89 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "lock.h"
+#include "memory.h"
+#include "lowcomms.h"
+#include "config.h"
+
+#ifdef CONFIG_DLM_DEBUG
+int dlm_register_debugfs(void);
+void dlm_unregister_debugfs(void);
+#else
+static inline int dlm_register_debugfs(void) { return 0; }
+static inline void dlm_unregister_debugfs(void) { }
+#endif
+
+static int __init init_dlm(void)
+{
+	int error;
+
+	error = dlm_memory_init();
+	if (error)
+		goto out;
+
+	error = dlm_lockspace_init();
+	if (error)
+		goto out_mem;
+
+	error = dlm_config_init();
+	if (error)
+		goto out_lockspace;
+
+	error = dlm_register_debugfs();
+	if (error)
+		goto out_config;
+
+	error = dlm_lowcomms_init();
+	if (error)
+		goto out_debug;
+
+	printk("DLM (built %s %s) installed\n", __DATE__, __TIME__);
+
+	return 0;
+
+ out_debug:
+	dlm_unregister_debugfs();
+ out_config:
+	dlm_config_exit();
+ out_lockspace:
+	dlm_lockspace_exit();
+ out_mem:
+	dlm_memory_exit();
+ out:
+	return error;
+}
+
+static void __exit exit_dlm(void)
+{
+	dlm_lowcomms_exit();
+	dlm_config_exit();
+	dlm_memory_exit();
+	dlm_lockspace_exit();
+	dlm_unregister_debugfs();
+}
+
+module_init(init_dlm);
+module_exit(exit_dlm);
+
+MODULE_DESCRIPTION("Distributed Lock Manager");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL_GPL(dlm_new_lockspace);
+EXPORT_SYMBOL_GPL(dlm_release_lockspace);
+EXPORT_SYMBOL_GPL(dlm_lock);
+EXPORT_SYMBOL_GPL(dlm_unlock);
+
diff -urN oldtree/drivers/dlm/member.c newtree/drivers/dlm/member.c
--- oldtree/drivers/dlm/member.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/member.c	2006-02-21 15:58:32.671179784 +0000
@@ -0,0 +1,313 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "member.h"
+#include "recoverd.h"
+#include "recover.h"
+#include "lowcomms.h"
+#include "rcom.h"
+#include "config.h"
+
+/*
+ * Following called by dlm_recoverd thread
+ */
+
+static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new)
+{
+	struct dlm_member *memb = NULL;
+	struct list_head *tmp;
+	struct list_head *newlist = &new->list;
+	struct list_head *head = &ls->ls_nodes;
+
+	list_for_each(tmp, head) {
+		memb = list_entry(tmp, struct dlm_member, list);
+		if (new->nodeid < memb->nodeid)
+			break;
+	}
+
+	if (!memb)
+		list_add_tail(newlist, head);
+	else {
+		/* FIXME: can use list macro here */
+		newlist->prev = tmp->prev;
+		newlist->next = tmp;
+		tmp->prev->next = newlist;
+		tmp->prev = newlist;
+	}
+}
+
+static int dlm_add_member(struct dlm_ls *ls, int nodeid)
+{
+	struct dlm_member *memb;
+	int w;
+
+	memb = kzalloc(sizeof(struct dlm_member), GFP_KERNEL);
+	if (!memb)
+		return -ENOMEM;
+
+	w = dlm_node_weight(ls->ls_name, nodeid);
+	if (w < 0)
+		return w;
+
+	memb->nodeid = nodeid;
+	memb->weight = w;
+	add_ordered_member(ls, memb);
+	ls->ls_num_nodes++;
+	return 0;
+}
+
+static void dlm_remove_member(struct dlm_ls *ls, struct dlm_member *memb)
+{
+	list_move(&memb->list, &ls->ls_nodes_gone);
+	ls->ls_num_nodes--;
+}
+
+static int dlm_is_member(struct dlm_ls *ls, int nodeid)
+{
+	struct dlm_member *memb;
+
+	list_for_each_entry(memb, &ls->ls_nodes, list) {
+		if (memb->nodeid == nodeid)
+			return 1;
+	}
+	return 0;
+}
+
+int dlm_is_removed(struct dlm_ls *ls, int nodeid)
+{
+	struct dlm_member *memb;
+
+	list_for_each_entry(memb, &ls->ls_nodes_gone, list) {
+		if (memb->nodeid == nodeid)
+			return 1;
+	}
+	return 0;
+}
+
+static void clear_memb_list(struct list_head *head)
+{
+	struct dlm_member *memb;
+
+	while (!list_empty(head)) {
+		memb = list_entry(head->next, struct dlm_member, list);
+		list_del(&memb->list);
+		kfree(memb);
+	}
+}
+
+void dlm_clear_members(struct dlm_ls *ls)
+{
+	clear_memb_list(&ls->ls_nodes);
+	ls->ls_num_nodes = 0;
+}
+
+void dlm_clear_members_gone(struct dlm_ls *ls)
+{
+	clear_memb_list(&ls->ls_nodes_gone);
+}
+
+static void make_member_array(struct dlm_ls *ls)
+{
+	struct dlm_member *memb;
+	int i, w, x = 0, total = 0, all_zero = 0, *array;
+
+	kfree(ls->ls_node_array);
+	ls->ls_node_array = NULL;
+
+	list_for_each_entry(memb, &ls->ls_nodes, list) {
+		if (memb->weight)
+			total += memb->weight;
+	}
+
+	/* all nodes revert to weight of 1 if all have weight 0 */
+
+	if (!total) {
+		total = ls->ls_num_nodes;
+		all_zero = 1;
+	}
+
+	ls->ls_total_weight = total;
+
+	array = kmalloc(sizeof(int) * total, GFP_KERNEL);
+	if (!array)
+		return;
+
+	list_for_each_entry(memb, &ls->ls_nodes, list) {
+		if (!all_zero && !memb->weight)
+			continue;
+
+		if (all_zero)
+			w = 1;
+		else
+			w = memb->weight;
+
+		DLM_ASSERT(x < total, printk("total %d x %d\n", total, x););
+
+		for (i = 0; i < w; i++)
+			array[x++] = memb->nodeid;
+	}
+
+	ls->ls_node_array = array;
+}
+
+/* send a status request to all members just to establish comms connections */
+
+static void ping_members(struct dlm_ls *ls)
+{
+	struct dlm_member *memb;
+	list_for_each_entry(memb, &ls->ls_nodes, list)
+		dlm_rcom_status(ls, memb->nodeid);
+}
+
+int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out)
+{
+	struct dlm_member *memb, *safe;
+	int i, error, found, pos = 0, neg = 0, low = -1;
+
+	/* move departed members from ls_nodes to ls_nodes_gone */
+
+	list_for_each_entry_safe(memb, safe, &ls->ls_nodes, list) {
+		found = 0;
+		for (i = 0; i < rv->node_count; i++) {
+			if (memb->nodeid == rv->nodeids[i]) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (!found) {
+			neg++;
+			dlm_remove_member(ls, memb);
+			log_debug(ls, "remove member %d", memb->nodeid);
+		}
+	}
+
+	/* add new members to ls_nodes */
+
+	for (i = 0; i < rv->node_count; i++) {
+		if (dlm_is_member(ls, rv->nodeids[i]))
+			continue;
+		dlm_add_member(ls, rv->nodeids[i]);
+		pos++;
+		log_debug(ls, "add member %d", rv->nodeids[i]);
+	}
+
+	list_for_each_entry(memb, &ls->ls_nodes, list) {
+		if (low == -1 || memb->nodeid < low)
+			low = memb->nodeid;
+	}
+	ls->ls_low_nodeid = low;
+
+	make_member_array(ls);
+	dlm_set_recover_status(ls, DLM_RS_NODES);
+	*neg_out = neg;
+
+	ping_members(ls);
+
+	error = dlm_recover_members_wait(ls);
+	log_debug(ls, "total members %d", ls->ls_num_nodes);
+	return error;
+}
+
+/*
+ * Following called from lockspace.c
+ */
+
+int dlm_ls_stop(struct dlm_ls *ls)
+{
+	int new;
+
+	/*
+	 * A stop cancels any recovery that's in progress (see RECOVERY_STOP,
+	 * dlm_recovery_stopped()) and prevents any new locks from being
+	 * processed (see RUNNING, dlm_locking_stopped()).
+	 */
+
+	spin_lock(&ls->ls_recover_lock);
+	set_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
+	new = test_and_clear_bit(LSFL_RUNNING, &ls->ls_flags);
+	ls->ls_recover_seq++;
+	spin_unlock(&ls->ls_recover_lock);
+
+	/*
+	 * This in_recovery lock does two things:
+	 *
+	 * 1) Keeps this function from returning until all threads are out
+	 *    of locking routines and locking is truely stopped.
+	 * 2) Keeps any new requests from being processed until it's unlocked
+	 *    when recovery is complete.
+	 */
+
+	if (new)
+		down_write(&ls->ls_in_recovery);
+
+	/*
+	 * The recoverd suspend/resume makes sure that dlm_recoverd (if
+	 * running) has noticed the clearing of RUNNING above and quit
+	 * processing the previous recovery.  This will be true for all nodes
+	 * before any nodes start the new recovery.
+	 */
+
+	dlm_recoverd_suspend(ls);
+	ls->ls_recover_status = 0;
+	dlm_recoverd_resume(ls);
+	return 0;
+}
+
+int dlm_ls_start(struct dlm_ls *ls)
+{
+	struct dlm_recover *rv = NULL, *rv_old;
+	int *ids = NULL;
+	int error, count;
+
+	rv = kzalloc(sizeof(struct dlm_recover), GFP_KERNEL);
+	if (!rv)
+		return -ENOMEM;
+
+	error = count = dlm_nodeid_list(ls->ls_name, &ids);
+	if (error <= 0)
+		goto fail;
+
+	spin_lock(&ls->ls_recover_lock);
+
+	/* the lockspace needs to be stopped before it can be started */
+
+	if (!dlm_locking_stopped(ls)) {
+		spin_unlock(&ls->ls_recover_lock);
+		log_error(ls, "start ignored: lockspace running");
+		error = -EINVAL;
+		goto fail;
+	}
+
+	rv->nodeids = ids;
+	rv->node_count = count;
+	rv->seq = ++ls->ls_recover_seq;
+	rv_old = ls->ls_recover_args;
+	ls->ls_recover_args = rv;
+	spin_unlock(&ls->ls_recover_lock);
+
+	if (rv_old) {
+		kfree(rv_old->nodeids);
+		kfree(rv_old);
+	}
+
+	dlm_recoverd_kick(ls);
+	return 0;
+
+ fail:
+	kfree(rv);
+	kfree(ids);
+	return error;
+}
+
diff -urN oldtree/drivers/dlm/member.h newtree/drivers/dlm/member.h
--- oldtree/drivers/dlm/member.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/member.h	2006-02-21 15:58:32.561196504 +0000
@@ -0,0 +1,24 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __MEMBER_DOT_H__
+#define __MEMBER_DOT_H__
+
+int dlm_ls_stop(struct dlm_ls *ls);
+int dlm_ls_start(struct dlm_ls *ls);
+void dlm_clear_members(struct dlm_ls *ls);
+void dlm_clear_members_gone(struct dlm_ls *ls);
+int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv,int *neg_out);
+int dlm_is_removed(struct dlm_ls *ls, int nodeid);
+
+#endif                          /* __MEMBER_DOT_H__ */
+
diff -urN oldtree/drivers/dlm/memory.c newtree/drivers/dlm/memory.c
--- oldtree/drivers/dlm/memory.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/memory.c	2006-02-21 15:58:32.757166712 +0000
@@ -0,0 +1,122 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "config.h"
+#include "memory.h"
+
+static kmem_cache_t *lkb_cache;
+
+
+int dlm_memory_init(void)
+{
+	int ret = 0;
+
+	lkb_cache = kmem_cache_create("dlm_lkb", sizeof(struct dlm_lkb),
+				__alignof__(struct dlm_lkb), 0, NULL, NULL);
+	if (!lkb_cache)
+		ret = -ENOMEM;
+	return ret;
+}
+
+void dlm_memory_exit(void)
+{
+	if (lkb_cache)
+		kmem_cache_destroy(lkb_cache);
+}
+
+char *allocate_lvb(struct dlm_ls *ls)
+{
+	char *p;
+
+	p = kmalloc(ls->ls_lvblen, GFP_KERNEL);
+	if (p)
+		memset(p, 0, ls->ls_lvblen);
+	return p;
+}
+
+void free_lvb(char *p)
+{
+	kfree(p);
+}
+
+uint64_t *allocate_range(struct dlm_ls *ls)
+{
+	int ralen = 4*sizeof(uint64_t);
+	uint64_t *p;
+
+	p = kmalloc(ralen, GFP_KERNEL);
+	if (p)
+		memset(p, 0, ralen);
+	return p;
+}
+
+void free_range(uint64_t *p)
+{
+	kfree(p);
+}
+
+/* FIXME: have some minimal space built-in to rsb for the name and
+   kmalloc a separate name if needed, like dentries are done */
+
+struct dlm_rsb *allocate_rsb(struct dlm_ls *ls, int namelen)
+{
+	struct dlm_rsb *r;
+
+	DLM_ASSERT(namelen <= DLM_RESNAME_MAXLEN,);
+
+	r = kmalloc(sizeof(*r) + namelen, GFP_KERNEL);
+	if (r)
+		memset(r, 0, sizeof(*r) + namelen);
+	return r;
+}
+
+void free_rsb(struct dlm_rsb *r)
+{
+	if (r->res_lvbptr)
+		free_lvb(r->res_lvbptr);
+	kfree(r);
+}
+
+struct dlm_lkb *allocate_lkb(struct dlm_ls *ls)
+{
+	struct dlm_lkb *lkb;
+
+	lkb = kmem_cache_alloc(lkb_cache, GFP_KERNEL);
+	if (lkb)
+		memset(lkb, 0, sizeof(*lkb));
+	return lkb;
+}
+
+void free_lkb(struct dlm_lkb *lkb)
+{
+	kmem_cache_free(lkb_cache, lkb);
+}
+
+struct dlm_direntry *allocate_direntry(struct dlm_ls *ls, int namelen)
+{
+	struct dlm_direntry *de;
+
+	DLM_ASSERT(namelen <= DLM_RESNAME_MAXLEN,);
+
+	de = kmalloc(sizeof(*de) + namelen, GFP_KERNEL);
+	if (de)
+		memset(de, 0, sizeof(*de) + namelen);
+	return de;
+}
+
+void free_direntry(struct dlm_direntry *de)
+{
+	kfree(de);
+}
+
diff -urN oldtree/drivers/dlm/memory.h newtree/drivers/dlm/memory.h
--- oldtree/drivers/dlm/memory.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/memory.h	2006-02-21 15:58:32.278239520 +0000
@@ -0,0 +1,31 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __MEMORY_DOT_H__
+#define __MEMORY_DOT_H__
+
+int dlm_memory_init(void);
+void dlm_memory_exit(void);
+struct dlm_rsb *allocate_rsb(struct dlm_ls *ls, int namelen);
+void free_rsb(struct dlm_rsb *r);
+struct dlm_lkb *allocate_lkb(struct dlm_ls *ls);
+void free_lkb(struct dlm_lkb *l);
+struct dlm_direntry *allocate_direntry(struct dlm_ls *ls, int namelen);
+void free_direntry(struct dlm_direntry *de);
+char *allocate_lvb(struct dlm_ls *ls);
+void free_lvb(char *l);
+uint64_t *allocate_range(struct dlm_ls *ls);
+void free_range(uint64_t *l);
+
+#endif		/* __MEMORY_DOT_H__ */
+
diff -urN oldtree/drivers/dlm/midcomms.c newtree/drivers/dlm/midcomms.c
--- oldtree/drivers/dlm/midcomms.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/midcomms.c	2006-02-21 15:58:32.758166560 +0000
@@ -0,0 +1,140 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+/*
+ * midcomms.c
+ *
+ * This is the appallingly named "mid-level" comms layer.
+ *
+ * Its purpose is to take packets from the "real" comms layer,
+ * split them up into packets and pass them to the interested
+ * part of the locking mechanism.
+ *
+ * It also takes messages from the locking layer, formats them
+ * into packets and sends them to the comms layer.
+ */
+
+#include "dlm_internal.h"
+#include "lowcomms.h"
+#include "config.h"
+#include "rcom.h"
+#include "lock.h"
+#include "midcomms.h"
+
+
+static void copy_from_cb(void *dst, const void *base, unsigned offset,
+			 unsigned len, unsigned limit)
+{
+	unsigned copy = len;
+
+	if ((copy + offset) > limit)
+		copy = limit - offset;
+	memcpy(dst, base + offset, copy);
+	len -= copy;
+	if (len)
+		memcpy(dst + copy, base, len);
+}
+
+/*
+ * Called from the low-level comms layer to process a buffer of
+ * commands.
+ *
+ * Only complete messages are processed here, any "spare" bytes from
+ * the end of a buffer are saved and tacked onto the front of the next
+ * message that comes in. I doubt this will happen very often but we
+ * need to be able to cope with it and I don't want the task to be waiting
+ * for packets to come in when there is useful work to be done.
+ */
+
+int dlm_process_incoming_buffer(int nodeid, const void *base,
+				unsigned offset, unsigned len, unsigned limit)
+{
+	unsigned char __tmp[DLM_INBUF_LEN];
+	struct dlm_header *msg = (struct dlm_header *) __tmp;
+	int ret = 0;
+	int err = 0;
+	uint16_t msglen;
+	uint32_t lockspace;
+
+	while (len > sizeof(struct dlm_header)) {
+
+		/* Copy just the header to check the total length.  The
+		   message may wrap around the end of the buffer back to the
+		   start, so we need to use a temp buffer and copy_from_cb. */
+
+		copy_from_cb(msg, base, offset, sizeof(struct dlm_header),
+			     limit);
+
+		msglen = le16_to_cpu(msg->h_length);
+		lockspace = msg->h_lockspace;
+
+		err = -EINVAL;
+		if (msglen < sizeof(struct dlm_header))
+			break;
+		err = -E2BIG;
+		if (msglen > dlm_config.buffer_size) {
+			log_print("message size %d from %d too big, buf len %d",
+				  msglen, nodeid, len);
+			break;
+		}
+		err = 0;
+
+		/* If only part of the full message is contained in this
+		   buffer, then do nothing and wait for lowcomms to call
+		   us again later with more data.  We return 0 meaning
+		   we've consumed none of the input buffer. */
+
+		if (msglen > len)
+			break;
+
+		/* Allocate a larger temp buffer if the full message won't fit
+		   in the buffer on the stack (which should work for most
+		   ordinary messages). */
+
+		if (msglen > sizeof(__tmp) &&
+		    msg == (struct dlm_header *) __tmp) {
+			msg = kmalloc(dlm_config.buffer_size, GFP_KERNEL);
+			if (msg == NULL)
+				return ret;
+		}
+
+		copy_from_cb(msg, base, offset, msglen, limit);
+
+		BUG_ON(lockspace != msg->h_lockspace);
+
+		ret += msglen;
+		offset += msglen;
+		offset &= (limit - 1);
+		len -= msglen;
+
+		switch (msg->h_cmd) {
+		case DLM_MSG:
+			dlm_receive_message(msg, nodeid, 0);
+			break;
+
+		case DLM_RCOM:
+			dlm_receive_rcom(msg, nodeid);
+			break;
+
+		default:
+			log_print("unknown msg type %x from %u: %u %u %u %u",
+				  msg->h_cmd, nodeid, msglen, len, offset, ret);
+		}
+	}
+
+	if (msg != (struct dlm_header *) __tmp)
+		kfree(msg);
+
+	return err ? err : ret;
+}
+
diff -urN oldtree/drivers/dlm/midcomms.h newtree/drivers/dlm/midcomms.h
--- oldtree/drivers/dlm/midcomms.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/midcomms.h	2006-02-21 15:58:32.296236784 +0000
@@ -0,0 +1,21 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __MIDCOMMS_DOT_H__
+#define __MIDCOMMS_DOT_H__
+
+int dlm_process_incoming_buffer(int nodeid, const void *base, unsigned offset,
+				unsigned len, unsigned limit);
+
+#endif				/* __MIDCOMMS_DOT_H__ */
+
diff -urN oldtree/drivers/dlm/rcom.c newtree/drivers/dlm/rcom.c
--- oldtree/drivers/dlm/rcom.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/rcom.c	2006-02-21 15:58:32.628186320 +0000
@@ -0,0 +1,460 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "member.h"
+#include "lowcomms.h"
+#include "midcomms.h"
+#include "rcom.h"
+#include "recover.h"
+#include "dir.h"
+#include "config.h"
+#include "memory.h"
+#include "lock.h"
+#include "util.h"
+
+
+static int rcom_response(struct dlm_ls *ls)
+{
+	return test_bit(LSFL_RCOM_READY, &ls->ls_flags);
+}
+
+static int create_rcom(struct dlm_ls *ls, int to_nodeid, int type, int len,
+		       struct dlm_rcom **rc_ret, struct dlm_mhandle **mh_ret)
+{
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	char *mb;
+	int mb_len = sizeof(struct dlm_rcom) + len;
+
+	mh = dlm_lowcomms_get_buffer(to_nodeid, mb_len, GFP_KERNEL, &mb);
+	if (!mh) {
+		log_print("create_rcom to %d type %d len %d ENOBUFS",
+			  to_nodeid, type, len);
+		return -ENOBUFS;
+	}
+	memset(mb, 0, mb_len);
+
+	rc = (struct dlm_rcom *) mb;
+
+	rc->rc_header.h_version = (DLM_HEADER_MAJOR | DLM_HEADER_MINOR);
+	rc->rc_header.h_lockspace = ls->ls_global_id;
+	rc->rc_header.h_nodeid = dlm_our_nodeid();
+	rc->rc_header.h_length = mb_len;
+	rc->rc_header.h_cmd = DLM_RCOM;
+
+	rc->rc_type = type;
+
+	*mh_ret = mh;
+	*rc_ret = rc;
+	return 0;
+}
+
+static void send_rcom(struct dlm_ls *ls, struct dlm_mhandle *mh,
+		      struct dlm_rcom *rc)
+{
+	dlm_rcom_out(rc);
+	dlm_lowcomms_commit_buffer(mh);
+}
+
+/* When replying to a status request, a node also sends back its
+   configuration values.  The requesting node then checks that the remote
+   node is configured the same way as itself. */
+
+static void make_config(struct dlm_ls *ls, struct rcom_config *rf)
+{
+	rf->rf_lvblen = ls->ls_lvblen;
+	rf->rf_lsflags = ls->ls_exflags;
+}
+
+static int check_config(struct dlm_ls *ls, struct rcom_config *rf, int nodeid)
+{
+	if (rf->rf_lvblen != ls->ls_lvblen ||
+	    rf->rf_lsflags != ls->ls_exflags) {
+		log_error(ls, "config mismatch: %d,%x nodeid %d: %d,%x",
+			  ls->ls_lvblen, ls->ls_exflags,
+			  nodeid, rf->rf_lvblen, rf->rf_lsflags);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int dlm_rcom_status(struct dlm_ls *ls, int nodeid)
+{
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	int error = 0;
+
+	memset(ls->ls_recover_buf, 0, dlm_config.buffer_size);
+
+	if (nodeid == dlm_our_nodeid()) {
+		rc = (struct dlm_rcom *) ls->ls_recover_buf;
+		rc->rc_result = dlm_recover_status(ls);
+		goto out;
+	}
+
+	error = create_rcom(ls, nodeid, DLM_RCOM_STATUS, 0, &rc, &mh);
+	if (error)
+		goto out;
+
+	send_rcom(ls, mh, rc);
+
+	error = dlm_wait_function(ls, &rcom_response);
+	clear_bit(LSFL_RCOM_READY, &ls->ls_flags);
+	if (error)
+		goto out;
+
+	rc = (struct dlm_rcom *) ls->ls_recover_buf;
+
+	if (rc->rc_result == -ESRCH) {
+		/* we pretend the remote lockspace exists with 0 status */
+		log_debug(ls, "remote node %d not ready", nodeid);
+		rc->rc_result = 0;
+	} else
+		error = check_config(ls, (struct rcom_config *) rc->rc_buf,
+				     nodeid);
+	/* the caller looks at rc_result for the remote recovery status */
+ out:
+	return error;
+}
+
+static void receive_rcom_status(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	int error, nodeid = rc_in->rc_header.h_nodeid;
+
+	error = create_rcom(ls, nodeid, DLM_RCOM_STATUS_REPLY,
+			    sizeof(struct rcom_config), &rc, &mh);
+	if (error)
+		return;
+	rc->rc_result = dlm_recover_status(ls);
+	make_config(ls, (struct rcom_config *) rc->rc_buf);
+
+	send_rcom(ls, mh, rc);
+}
+
+static void receive_rcom_status_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+	memcpy(ls->ls_recover_buf, rc_in, rc_in->rc_header.h_length);
+	set_bit(LSFL_RCOM_READY, &ls->ls_flags);
+	wake_up(&ls->ls_wait_general);
+}
+
+int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len)
+{
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	int error = 0, len = sizeof(struct dlm_rcom);
+
+	memset(ls->ls_recover_buf, 0, dlm_config.buffer_size);
+
+	if (nodeid == dlm_our_nodeid()) {
+		dlm_copy_master_names(ls, last_name, last_len,
+		                      ls->ls_recover_buf + len,
+		                      dlm_config.buffer_size - len, nodeid);
+		goto out;
+	}
+
+	error = create_rcom(ls, nodeid, DLM_RCOM_NAMES, last_len, &rc, &mh);
+	if (error)
+		goto out;
+	memcpy(rc->rc_buf, last_name, last_len);
+
+	send_rcom(ls, mh, rc);
+
+	error = dlm_wait_function(ls, &rcom_response);
+	clear_bit(LSFL_RCOM_READY, &ls->ls_flags);
+ out:
+	return error;
+}
+
+static void receive_rcom_names(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	int error, inlen, outlen;
+	int nodeid = rc_in->rc_header.h_nodeid;
+	uint32_t status = dlm_recover_status(ls);
+
+	/*
+	 * We can't run dlm_dir_rebuild_send (which uses ls_nodes) while
+	 * dlm_recoverd is running ls_nodes_reconfig (which changes ls_nodes).
+	 * It could only happen in rare cases where we get a late NAMES
+	 * message from a previous instance of recovery.
+	 */
+
+	if (!(status & DLM_RS_NODES)) {
+		log_debug(ls, "ignoring RCOM_NAMES from %u", nodeid);
+		return;
+	}
+
+	nodeid = rc_in->rc_header.h_nodeid;
+	inlen = rc_in->rc_header.h_length - sizeof(struct dlm_rcom);
+	outlen = dlm_config.buffer_size - sizeof(struct dlm_rcom);
+
+	error = create_rcom(ls, nodeid, DLM_RCOM_NAMES_REPLY, outlen, &rc, &mh);
+	if (error)
+		return;
+
+	dlm_copy_master_names(ls, rc_in->rc_buf, inlen, rc->rc_buf, outlen,
+			      nodeid);
+	send_rcom(ls, mh, rc);
+}
+
+static void receive_rcom_names_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+	memcpy(ls->ls_recover_buf, rc_in, rc_in->rc_header.h_length);
+	set_bit(LSFL_RCOM_READY, &ls->ls_flags);
+	wake_up(&ls->ls_wait_general);
+}
+
+int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid)
+{
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	struct dlm_ls *ls = r->res_ls;
+	int error;
+
+	error = create_rcom(ls, dir_nodeid, DLM_RCOM_LOOKUP, r->res_length,
+			    &rc, &mh);
+	if (error)
+		goto out;
+	memcpy(rc->rc_buf, r->res_name, r->res_length);
+	rc->rc_id = (unsigned long) r;
+
+	send_rcom(ls, mh, rc);
+ out:
+	return error;
+}
+
+static void receive_rcom_lookup(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	int error, ret_nodeid, nodeid = rc_in->rc_header.h_nodeid;
+	int len = rc_in->rc_header.h_length - sizeof(struct dlm_rcom);
+
+	error = create_rcom(ls, nodeid, DLM_RCOM_LOOKUP_REPLY, 0, &rc, &mh);
+	if (error)
+		return;
+
+	error = dlm_dir_lookup(ls, nodeid, rc_in->rc_buf, len, &ret_nodeid);
+	if (error)
+		ret_nodeid = error;
+	rc->rc_result = ret_nodeid;
+	rc->rc_id = rc_in->rc_id;
+
+	send_rcom(ls, mh, rc);
+}
+
+static void receive_rcom_lookup_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+	dlm_recover_master_reply(ls, rc_in);
+}
+
+static void pack_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb,
+			   struct rcom_lock *rl)
+{
+	memset(rl, 0, sizeof(*rl));
+
+	rl->rl_ownpid = lkb->lkb_ownpid;
+	rl->rl_lkid = lkb->lkb_id;
+	rl->rl_exflags = lkb->lkb_exflags;
+	rl->rl_flags = lkb->lkb_flags;
+	rl->rl_lvbseq = lkb->lkb_lvbseq;
+	rl->rl_rqmode = lkb->lkb_rqmode;
+	rl->rl_grmode = lkb->lkb_grmode;
+	rl->rl_status = lkb->lkb_status;
+	rl->rl_wait_type = lkb->lkb_wait_type;
+
+	if (lkb->lkb_bastaddr)
+		rl->rl_asts |= AST_BAST;
+	if (lkb->lkb_astaddr)
+		rl->rl_asts |= AST_COMP;
+
+	if (lkb->lkb_range)
+		memcpy(rl->rl_range, lkb->lkb_range, 4*sizeof(uint64_t));
+
+	rl->rl_namelen = r->res_length;
+	memcpy(rl->rl_name, r->res_name, r->res_length);
+
+	/* FIXME: might we have an lvb without DLM_LKF_VALBLK set ?
+	   If so, receive_rcom_lock_args() won't take this copy. */
+
+	if (lkb->lkb_lvbptr)
+		memcpy(rl->rl_lvb, lkb->lkb_lvbptr, r->res_ls->ls_lvblen);
+}
+
+int dlm_send_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	struct dlm_ls *ls = r->res_ls;
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	struct rcom_lock *rl;
+	int error, len = sizeof(struct rcom_lock);
+
+	if (lkb->lkb_lvbptr)
+		len += ls->ls_lvblen;
+
+	error = create_rcom(ls, r->res_nodeid, DLM_RCOM_LOCK, len, &rc, &mh);
+	if (error)
+		goto out;
+
+	rl = (struct rcom_lock *) rc->rc_buf;
+	pack_rcom_lock(r, lkb, rl);
+	rc->rc_id = (unsigned long) r;
+
+	send_rcom(ls, mh, rc);
+ out:
+	return error;
+}
+
+static void receive_rcom_lock(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	int error, nodeid = rc_in->rc_header.h_nodeid;
+
+	dlm_recover_master_copy(ls, rc_in);
+
+	error = create_rcom(ls, nodeid, DLM_RCOM_LOCK_REPLY,
+			    sizeof(struct rcom_lock), &rc, &mh);
+	if (error)
+		return;
+
+	/* We send back the same rcom_lock struct we received, but
+	   dlm_recover_master_copy() has filled in rl_remid and rl_result */
+
+	memcpy(rc->rc_buf, rc_in->rc_buf, sizeof(struct rcom_lock));
+	rc->rc_id = rc_in->rc_id;
+
+	send_rcom(ls, mh, rc);
+}
+
+static void receive_rcom_lock_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+	uint32_t status = dlm_recover_status(ls);
+
+	if (!(status & DLM_RS_DIR)) {
+		log_debug(ls, "ignoring RCOM_LOCK_REPLY from %u",
+			  rc_in->rc_header.h_nodeid);
+		return;
+	}
+
+	dlm_recover_process_copy(ls, rc_in);
+}
+
+static int send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in)
+{
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	char *mb;
+	int mb_len = sizeof(struct dlm_rcom);
+
+	mh = dlm_lowcomms_get_buffer(nodeid, mb_len, GFP_KERNEL, &mb);
+	if (!mh)
+		return -ENOBUFS;
+	memset(mb, 0, mb_len);
+
+	rc = (struct dlm_rcom *) mb;
+
+	rc->rc_header.h_version = (DLM_HEADER_MAJOR | DLM_HEADER_MINOR);
+	rc->rc_header.h_lockspace = rc_in->rc_header.h_lockspace;
+	rc->rc_header.h_nodeid = dlm_our_nodeid();
+	rc->rc_header.h_length = mb_len;
+	rc->rc_header.h_cmd = DLM_RCOM;
+
+	rc->rc_type = DLM_RCOM_STATUS_REPLY;
+	rc->rc_result = -ESRCH;
+
+	dlm_rcom_out(rc);
+	dlm_lowcomms_commit_buffer(mh);
+
+	return 0;
+}
+
+/* Called by dlm_recvd; corresponds to dlm_receive_message() but special
+   recovery-only comms are sent through here. */
+
+void dlm_receive_rcom(struct dlm_header *hd, int nodeid)
+{
+	struct dlm_rcom *rc = (struct dlm_rcom *) hd;
+	struct dlm_ls *ls;
+
+	dlm_rcom_in(rc);
+
+	/* If the lockspace doesn't exist then still send a status message
+	   back; it's possible that it just doesn't have its global_id yet. */
+
+	ls = dlm_find_lockspace_global(hd->h_lockspace);
+	if (!ls) {
+		log_print("lockspace %x from %d not found",
+			  hd->h_lockspace, nodeid);
+		send_ls_not_ready(nodeid, rc);
+		return;
+	}
+
+	if (dlm_recovery_stopped(ls) && (rc->rc_type != DLM_RCOM_STATUS)) {
+		log_error(ls, "ignoring recovery message %x from %d",
+			  rc->rc_type, nodeid);
+		goto out;
+	}
+
+	if (nodeid != rc->rc_header.h_nodeid) {
+		log_error(ls, "bad rcom nodeid %d from %d",
+			  rc->rc_header.h_nodeid, nodeid);
+		goto out;
+	}
+
+	switch (rc->rc_type) {
+	case DLM_RCOM_STATUS:
+		receive_rcom_status(ls, rc);
+		break;
+
+	case DLM_RCOM_NAMES:
+		receive_rcom_names(ls, rc);
+		break;
+
+	case DLM_RCOM_LOOKUP:
+		receive_rcom_lookup(ls, rc);
+		break;
+
+	case DLM_RCOM_LOCK:
+		receive_rcom_lock(ls, rc);
+		break;
+
+	case DLM_RCOM_STATUS_REPLY:
+		receive_rcom_status_reply(ls, rc);
+		break;
+
+	case DLM_RCOM_NAMES_REPLY:
+		receive_rcom_names_reply(ls, rc);
+		break;
+
+	case DLM_RCOM_LOOKUP_REPLY:
+		receive_rcom_lookup_reply(ls, rc);
+		break;
+
+	case DLM_RCOM_LOCK_REPLY:
+		receive_rcom_lock_reply(ls, rc);
+		break;
+
+	default:
+		DLM_ASSERT(0, printk("rc_type=%x\n", rc->rc_type););
+	}
+ out:
+	dlm_put_lockspace(ls);
+}
+
diff -urN oldtree/drivers/dlm/rcom.h newtree/drivers/dlm/rcom.h
--- oldtree/drivers/dlm/rcom.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/rcom.h	2006-02-21 15:58:32.312234352 +0000
@@ -0,0 +1,24 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __RCOM_DOT_H__
+#define __RCOM_DOT_H__
+
+int dlm_rcom_status(struct dlm_ls *ls, int nodeid);
+int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name,int last_len);
+int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid);
+int dlm_send_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);
+void dlm_receive_rcom(struct dlm_header *hd, int nodeid);
+
+#endif
+
diff -urN oldtree/drivers/dlm/recover.c newtree/drivers/dlm/recover.c
--- oldtree/drivers/dlm/recover.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/recover.c	2006-02-21 15:58:32.758166560 +0000
@@ -0,0 +1,762 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "dir.h"
+#include "config.h"
+#include "ast.h"
+#include "memory.h"
+#include "rcom.h"
+#include "lock.h"
+#include "lowcomms.h"
+#include "member.h"
+#include "recover.h"
+
+
+/*
+ * Recovery waiting routines: these functions wait for a particular reply from
+ * a remote node, or for the remote node to report a certain status.  They need
+ * to abort if the lockspace is stopped indicating a node has failed (perhaps
+ * the one being waited for).
+ */
+
+/*
+ * Wait until given function returns non-zero or lockspace is stopped
+ * (LS_RECOVERY_STOP set due to failure of a node in ls_nodes).  When another
+ * function thinks it could have completed the waited-on task, they should wake
+ * up ls_wait_general to get an immediate response rather than waiting for the
+ * timer to detect the result.  A timer wakes us up periodically while waiting
+ * to see if we should abort due to a node failure.  This should only be called
+ * by the dlm_recoverd thread.
+ */
+
+static void dlm_wait_timer_fn(unsigned long data)
+{
+	struct dlm_ls *ls = (struct dlm_ls *) data;
+	mod_timer(&ls->ls_timer, jiffies + (dlm_config.recover_timer * HZ));
+	wake_up(&ls->ls_wait_general);
+}
+
+int dlm_wait_function(struct dlm_ls *ls, int (*testfn) (struct dlm_ls *ls))
+{
+	int error = 0;
+
+	init_timer(&ls->ls_timer);
+	ls->ls_timer.function = dlm_wait_timer_fn;
+	ls->ls_timer.data = (long) ls;
+	ls->ls_timer.expires = jiffies + (dlm_config.recover_timer * HZ);
+	add_timer(&ls->ls_timer);
+
+	wait_event(ls->ls_wait_general, testfn(ls) || dlm_recovery_stopped(ls));
+	del_timer_sync(&ls->ls_timer);
+
+	if (dlm_recovery_stopped(ls)) {
+		log_debug(ls, "dlm_wait_function aborted");
+		error = -EINTR;
+	}
+	return error;
+}
+
+/*
+ * An efficient way for all nodes to wait for all others to have a certain
+ * status.  The node with the lowest nodeid polls all the others for their
+ * status (wait_status_all) and all the others poll the node with the low id
+ * for its accumulated result (wait_status_low).  When all nodes have set
+ * status flag X, then status flag X_ALL will be set on the low nodeid.
+ */
+
+uint32_t dlm_recover_status(struct dlm_ls *ls)
+{
+	uint32_t status;
+	spin_lock(&ls->ls_recover_lock);
+	status = ls->ls_recover_status;
+	spin_unlock(&ls->ls_recover_lock);
+	return status;
+}
+
+void dlm_set_recover_status(struct dlm_ls *ls, uint32_t status)
+{
+	spin_lock(&ls->ls_recover_lock);
+	ls->ls_recover_status |= status;
+	spin_unlock(&ls->ls_recover_lock);
+}
+
+static int wait_status_all(struct dlm_ls *ls, uint32_t wait_status)
+{
+	struct dlm_rcom *rc = (struct dlm_rcom *) ls->ls_recover_buf;
+	struct dlm_member *memb;
+	int error = 0, delay;
+
+	list_for_each_entry(memb, &ls->ls_nodes, list) {
+		delay = 0;
+		for (;;) {
+			if (dlm_recovery_stopped(ls)) {
+				error = -EINTR;
+				goto out;
+			}
+
+			error = dlm_rcom_status(ls, memb->nodeid);
+			if (error)
+				goto out;
+
+			if (rc->rc_result & wait_status)
+				break;
+			if (delay < 1000)
+				delay += 20;
+			msleep(delay);
+		}
+	}
+ out:
+	return error;
+}
+
+static int wait_status_low(struct dlm_ls *ls, uint32_t wait_status)
+{
+	struct dlm_rcom *rc = (struct dlm_rcom *) ls->ls_recover_buf;
+	int error = 0, delay = 0, nodeid = ls->ls_low_nodeid;
+
+	for (;;) {
+		if (dlm_recovery_stopped(ls)) {
+			error = -EINTR;
+			goto out;
+		}
+
+		error = dlm_rcom_status(ls, nodeid);
+		if (error)
+			break;
+
+		if (rc->rc_result & wait_status)
+			break;
+		if (delay < 1000)
+			delay += 20;
+		msleep(delay);
+	}
+ out:
+	return error;
+}
+
+static int wait_status(struct dlm_ls *ls, uint32_t status)
+{
+	uint32_t status_all = status << 1;
+	int error;
+
+	if (ls->ls_low_nodeid == dlm_our_nodeid()) {
+		error = wait_status_all(ls, status);
+		if (!error)
+			dlm_set_recover_status(ls, status_all);
+	} else
+		error = wait_status_low(ls, status_all);
+
+	return error;
+}
+
+int dlm_recover_members_wait(struct dlm_ls *ls)
+{
+	return wait_status(ls, DLM_RS_NODES);
+}
+
+int dlm_recover_directory_wait(struct dlm_ls *ls)
+{
+	return wait_status(ls, DLM_RS_DIR);
+}
+
+int dlm_recover_locks_wait(struct dlm_ls *ls)
+{
+	return wait_status(ls, DLM_RS_LOCKS);
+}
+
+int dlm_recover_done_wait(struct dlm_ls *ls)
+{
+	return wait_status(ls, DLM_RS_DONE);
+}
+
+/*
+ * The recover_list contains all the rsb's for which we've requested the new
+ * master nodeid.  As replies are returned from the resource directories the
+ * rsb's are removed from the list.  When the list is empty we're done.
+ *
+ * The recover_list is later similarly used for all rsb's for which we've sent
+ * new lkb's and need to receive new corresponding lkid's.
+ *
+ * We use the address of the rsb struct as a simple local identifier for the
+ * rsb so we can match an rcom reply with the rsb it was sent for.
+ */
+
+static int recover_list_empty(struct dlm_ls *ls)
+{
+	int empty;
+
+	spin_lock(&ls->ls_recover_list_lock);
+	empty = list_empty(&ls->ls_recover_list);
+	spin_unlock(&ls->ls_recover_list_lock);
+
+	return empty;
+}
+
+static void recover_list_add(struct dlm_rsb *r)
+{
+	struct dlm_ls *ls = r->res_ls;
+
+	spin_lock(&ls->ls_recover_list_lock);
+	if (list_empty(&r->res_recover_list)) {
+		list_add_tail(&r->res_recover_list, &ls->ls_recover_list);
+		ls->ls_recover_list_count++;
+		dlm_hold_rsb(r);
+	}
+	spin_unlock(&ls->ls_recover_list_lock);
+}
+
+static void recover_list_del(struct dlm_rsb *r)
+{
+	struct dlm_ls *ls = r->res_ls;
+
+	spin_lock(&ls->ls_recover_list_lock);
+	list_del_init(&r->res_recover_list);
+	ls->ls_recover_list_count--;
+	spin_unlock(&ls->ls_recover_list_lock);
+
+	dlm_put_rsb(r);
+}
+
+static struct dlm_rsb *recover_list_find(struct dlm_ls *ls, uint64_t id)
+{
+	struct dlm_rsb *r = NULL;
+
+	spin_lock(&ls->ls_recover_list_lock);
+
+	list_for_each_entry(r, &ls->ls_recover_list, res_recover_list) {
+		if (id == (unsigned long) r)
+			goto out;
+	}
+	r = NULL;
+ out:
+	spin_unlock(&ls->ls_recover_list_lock);
+	return r;
+}
+
+static void recover_list_clear(struct dlm_ls *ls)
+{
+	struct dlm_rsb *r, *s;
+
+	spin_lock(&ls->ls_recover_list_lock);
+	list_for_each_entry_safe(r, s, &ls->ls_recover_list, res_recover_list) {
+		list_del_init(&r->res_recover_list);
+		dlm_put_rsb(r);
+		ls->ls_recover_list_count--;
+	}
+
+	if (ls->ls_recover_list_count != 0) {
+		log_error(ls, "warning: recover_list_count %d",
+			  ls->ls_recover_list_count);
+		ls->ls_recover_list_count = 0;
+	}
+	spin_unlock(&ls->ls_recover_list_lock);
+}
+
+
+/* Master recovery: find new master node for rsb's that were
+   mastered on nodes that have been removed.
+
+   dlm_recover_masters
+   recover_master
+   dlm_send_rcom_lookup            ->  receive_rcom_lookup
+                                       dlm_dir_lookup
+   receive_rcom_lookup_reply       <-
+   dlm_recover_master_reply
+   set_new_master
+   set_master_lkbs
+   set_lock_master
+*/
+
+/*
+ * Set the lock master for all LKBs in a lock queue
+ * If we are the new master of the rsb, we may have received new
+ * MSTCPY locks from other nodes already which we need to ignore
+ * when setting the new nodeid.
+ */
+
+static void set_lock_master(struct list_head *queue, int nodeid)
+{
+	struct dlm_lkb *lkb;
+
+	list_for_each_entry(lkb, queue, lkb_statequeue)
+		if (!(lkb->lkb_flags & DLM_IFL_MSTCPY))
+			lkb->lkb_nodeid = nodeid;
+}
+
+static void set_master_lkbs(struct dlm_rsb *r)
+{
+	set_lock_master(&r->res_grantqueue, r->res_nodeid);
+	set_lock_master(&r->res_convertqueue, r->res_nodeid);
+	set_lock_master(&r->res_waitqueue, r->res_nodeid);
+}
+
+/*
+ * Propogate the new master nodeid to locks
+ * The NEW_MASTER flag tells dlm_recover_locks() which rsb's to consider.
+ * The NEW_MASTER2 flag tells recover_lvb() which rsb's to consider.
+ */
+
+static void set_new_master(struct dlm_rsb *r, int nodeid)
+{
+	lock_rsb(r);
+	r->res_nodeid = nodeid;
+	set_master_lkbs(r);
+	rsb_set_flag(r, RSB_NEW_MASTER);
+	rsb_set_flag(r, RSB_NEW_MASTER2);
+	unlock_rsb(r);
+}
+
+/*
+ * We do async lookups on rsb's that need new masters.  The rsb's
+ * waiting for a lookup reply are kept on the recover_list.
+ */
+
+static int recover_master(struct dlm_rsb *r)
+{
+	struct dlm_ls *ls = r->res_ls;
+	int error, dir_nodeid, ret_nodeid, our_nodeid = dlm_our_nodeid();
+
+	dir_nodeid = dlm_dir_nodeid(r);
+
+	if (dir_nodeid == our_nodeid) {
+		error = dlm_dir_lookup(ls, our_nodeid, r->res_name,
+				       r->res_length, &ret_nodeid);
+		if (error)
+			log_error(ls, "recover dir lookup error %d", error);
+
+		if (ret_nodeid == our_nodeid)
+			ret_nodeid = 0;
+		set_new_master(r, ret_nodeid);
+	} else {
+		recover_list_add(r);
+		error = dlm_send_rcom_lookup(r, dir_nodeid);
+	}
+
+	return error;
+}
+
+/*
+ * When not using a directory, most resource names will hash to a new static
+ * master nodeid and the resource will need to be remastered.
+ */
+
+static int recover_master_static(struct dlm_rsb *r)
+{
+	int master = dlm_dir_nodeid(r);
+
+	if (master == dlm_our_nodeid())
+		master = 0;
+
+	if (r->res_nodeid != master) {
+		if (is_master(r))
+			dlm_purge_mstcpy_locks(r);
+		set_new_master(r, master);
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * Go through local root resources and for each rsb which has a master which
+ * has departed, get the new master nodeid from the directory.  The dir will
+ * assign mastery to the first node to look up the new master.  That means
+ * we'll discover in this lookup if we're the new master of any rsb's.
+ *
+ * We fire off all the dir lookup requests individually and asynchronously to
+ * the correct dir node.
+ */
+
+int dlm_recover_masters(struct dlm_ls *ls)
+{
+	struct dlm_rsb *r;
+	int error = 0, count = 0;
+
+	log_debug(ls, "dlm_recover_masters");
+
+	down_read(&ls->ls_root_sem);
+	list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
+		if (dlm_recovery_stopped(ls)) {
+			up_read(&ls->ls_root_sem);
+			error = -EINTR;
+			goto out;
+		}
+
+		if (dlm_no_directory(ls))
+			count += recover_master_static(r);
+		else if (!is_master(r) && dlm_is_removed(ls, r->res_nodeid)) {
+			recover_master(r);
+			count++;
+		}
+
+		schedule();
+	}
+	up_read(&ls->ls_root_sem);
+
+	log_debug(ls, "dlm_recover_masters %d resources", count);
+
+	error = dlm_wait_function(ls, &recover_list_empty);
+ out:
+	if (error)
+		recover_list_clear(ls);
+	return error;
+}
+
+int dlm_recover_master_reply(struct dlm_ls *ls, struct dlm_rcom *rc)
+{
+	struct dlm_rsb *r;
+	int nodeid;
+
+	r = recover_list_find(ls, rc->rc_id);
+	if (!r) {
+		log_error(ls, "dlm_recover_master_reply no id %llx",
+			  rc->rc_id);
+		goto out;
+	}
+
+	nodeid = rc->rc_result;
+	if (nodeid == dlm_our_nodeid())
+		nodeid = 0;
+
+	set_new_master(r, nodeid);
+	recover_list_del(r);
+
+	if (recover_list_empty(ls))
+		wake_up(&ls->ls_wait_general);
+ out:
+	return 0;
+}
+
+
+/* Lock recovery: rebuild the process-copy locks we hold on a
+   remastered rsb on the new rsb master.
+
+   dlm_recover_locks
+   recover_locks
+   recover_locks_queue
+   dlm_send_rcom_lock              ->  receive_rcom_lock
+                                       dlm_recover_master_copy
+   receive_rcom_lock_reply         <-
+   dlm_recover_process_copy
+*/
+
+
+/*
+ * keep a count of the number of lkb's we send to the new master; when we get
+ * an equal number of replies then recovery for the rsb is done
+ */
+
+static int recover_locks_queue(struct dlm_rsb *r, struct list_head *head)
+{
+	struct dlm_lkb *lkb;
+	int error = 0;
+
+	list_for_each_entry(lkb, head, lkb_statequeue) {
+	   	error = dlm_send_rcom_lock(r, lkb);
+		if (error)
+			break;
+		r->res_recover_locks_count++;
+	}
+
+	return error;
+}
+
+static int all_queues_empty(struct dlm_rsb *r)
+{
+	if (!list_empty(&r->res_grantqueue) ||
+	    !list_empty(&r->res_convertqueue) ||
+	    !list_empty(&r->res_waitqueue))
+		return 0;
+	return 1;
+}
+
+static int recover_locks(struct dlm_rsb *r)
+{
+	int error = 0;
+
+	lock_rsb(r);
+	if (all_queues_empty(r))
+		goto out;
+
+	DLM_ASSERT(!r->res_recover_locks_count, dlm_print_rsb(r););
+
+	error = recover_locks_queue(r, &r->res_grantqueue);
+	if (error)
+		goto out;
+	error = recover_locks_queue(r, &r->res_convertqueue);
+	if (error)
+		goto out;
+	error = recover_locks_queue(r, &r->res_waitqueue);
+	if (error)
+		goto out;
+
+	if (r->res_recover_locks_count)
+		recover_list_add(r);
+	else
+		rsb_clear_flag(r, RSB_NEW_MASTER);
+ out:
+	unlock_rsb(r);
+	return error;
+}
+
+int dlm_recover_locks(struct dlm_ls *ls)
+{
+	struct dlm_rsb *r;
+	int error, count = 0;
+
+	log_debug(ls, "dlm_recover_locks");
+
+	down_read(&ls->ls_root_sem);
+	list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
+		if (is_master(r)) {
+			rsb_clear_flag(r, RSB_NEW_MASTER);
+			continue;
+		}
+
+		if (!rsb_flag(r, RSB_NEW_MASTER))
+			continue;
+
+		if (dlm_recovery_stopped(ls)) {
+			error = -EINTR;
+			up_read(&ls->ls_root_sem);
+			goto out;
+		}
+
+		error = recover_locks(r);
+		if (error) {
+			up_read(&ls->ls_root_sem);
+			goto out;
+		}
+
+		count += r->res_recover_locks_count;
+	}
+	up_read(&ls->ls_root_sem);
+
+	log_debug(ls, "dlm_recover_locks %d locks", count);
+
+	error = dlm_wait_function(ls, &recover_list_empty);
+ out:
+	if (error)
+		recover_list_clear(ls);
+	else
+		dlm_set_recover_status(ls, DLM_RS_LOCKS);
+	return error;
+}
+
+void dlm_recovered_lock(struct dlm_rsb *r)
+{
+	DLM_ASSERT(rsb_flag(r, RSB_NEW_MASTER), dlm_print_rsb(r););
+
+	r->res_recover_locks_count--;
+	if (!r->res_recover_locks_count) {
+		rsb_clear_flag(r, RSB_NEW_MASTER);
+		recover_list_del(r);
+	}
+
+	if (recover_list_empty(r->res_ls))
+		wake_up(&r->res_ls->ls_wait_general);
+}
+
+/*
+ * The lvb needs to be recovered on all master rsb's.  This includes setting
+ * the VALNOTVALID flag if necessary, and determining the correct lvb contents
+ * based on the lvb's of the locks held on the rsb.
+ *
+ * RSB_VALNOTVALID is set if there are only NL/CR locks on the rsb.  If it
+ * was already set prior to recovery, it's not cleared, regardless of locks.
+ *
+ * The LVB contents are only considered for changing when this is a new master
+ * of the rsb (NEW_MASTER2).  Then, the rsb's lvb is taken from any lkb with
+ * mode > CR.  If no lkb's exist with mode above CR, the lvb contents are taken
+ * from the lkb with the largest lvb sequence number.
+ */
+
+static void recover_lvb(struct dlm_rsb *r)
+{
+	struct dlm_lkb *lkb, *high_lkb = NULL;
+	uint32_t high_seq = 0;
+	int lock_lvb_exists = 0;
+	int big_lock_exists = 0;
+	int lvblen = r->res_ls->ls_lvblen;
+
+	list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
+		if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
+			continue;
+
+		lock_lvb_exists = 1;
+
+		if (lkb->lkb_grmode > DLM_LOCK_CR) {
+			big_lock_exists = 1;
+			goto setflag;
+		}
+
+		if (((int)lkb->lkb_lvbseq - (int)high_seq) >= 0) {
+			high_lkb = lkb;
+			high_seq = lkb->lkb_lvbseq;
+		}
+	}
+
+	list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
+		if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
+			continue;
+
+		lock_lvb_exists = 1;
+
+		if (lkb->lkb_grmode > DLM_LOCK_CR) {
+			big_lock_exists = 1;
+			goto setflag;
+		}
+
+		if (((int)lkb->lkb_lvbseq - (int)high_seq) >= 0) {
+			high_lkb = lkb;
+			high_seq = lkb->lkb_lvbseq;
+		}
+	}
+
+ setflag:
+	if (!lock_lvb_exists)
+		goto out;
+
+	if (!big_lock_exists)
+		rsb_set_flag(r, RSB_VALNOTVALID);
+
+	/* don't mess with the lvb unless we're the new master */
+	if (!rsb_flag(r, RSB_NEW_MASTER2))
+		goto out;
+
+	if (!r->res_lvbptr) {
+		r->res_lvbptr = allocate_lvb(r->res_ls);
+		if (!r->res_lvbptr)
+			goto out;
+	}
+
+	if (big_lock_exists) {
+		r->res_lvbseq = lkb->lkb_lvbseq;
+		memcpy(r->res_lvbptr, lkb->lkb_lvbptr, lvblen);
+	} else if (high_lkb) {
+		r->res_lvbseq = high_lkb->lkb_lvbseq;
+		memcpy(r->res_lvbptr, high_lkb->lkb_lvbptr, lvblen);
+	} else {
+		r->res_lvbseq = 0;
+		memset(r->res_lvbptr, 0, lvblen);
+	}
+ out:
+	return;
+}
+
+/* All master rsb's flagged RECOVER_CONVERT need to be looked at.  The locks
+   converting PR->CW or CW->PR need to have their lkb_grmode set. */
+
+static void recover_conversion(struct dlm_rsb *r)
+{
+	struct dlm_lkb *lkb;
+	int grmode = -1;
+
+	list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
+		if (lkb->lkb_grmode == DLM_LOCK_PR ||
+		    lkb->lkb_grmode == DLM_LOCK_CW) {
+			grmode = lkb->lkb_grmode;
+			break;
+		}
+	}
+
+	list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
+		if (lkb->lkb_grmode != DLM_LOCK_IV)
+			continue;
+		if (grmode == -1)
+			lkb->lkb_grmode = lkb->lkb_rqmode;
+		else
+			lkb->lkb_grmode = grmode;
+	}
+}
+
+void dlm_recover_rsbs(struct dlm_ls *ls)
+{
+	struct dlm_rsb *r;
+	int count = 0;
+
+	log_debug(ls, "dlm_recover_rsbs");
+
+	down_read(&ls->ls_root_sem);
+	list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
+		lock_rsb(r);
+		if (is_master(r)) {
+			if (rsb_flag(r, RSB_RECOVER_CONVERT))
+				recover_conversion(r);
+			recover_lvb(r);
+			count++;
+		}
+		rsb_clear_flag(r, RSB_RECOVER_CONVERT);
+		unlock_rsb(r);
+	}
+	up_read(&ls->ls_root_sem);
+
+	log_debug(ls, "dlm_recover_rsbs %d rsbs", count);
+}
+
+/* Create a single list of all root rsb's to be used during recovery */
+
+int dlm_create_root_list(struct dlm_ls *ls)
+{
+	struct dlm_rsb *r;
+	int i, error = 0;
+
+	down_write(&ls->ls_root_sem);
+	if (!list_empty(&ls->ls_root_list)) {
+		log_error(ls, "root list not empty");
+		error = -EINVAL;
+		goto out;
+	}
+
+	for (i = 0; i < ls->ls_rsbtbl_size; i++) {
+		read_lock(&ls->ls_rsbtbl[i].lock);
+		list_for_each_entry(r, &ls->ls_rsbtbl[i].list, res_hashchain) {
+			list_add(&r->res_root_list, &ls->ls_root_list);
+			dlm_hold_rsb(r);
+		}
+		read_unlock(&ls->ls_rsbtbl[i].lock);
+	}
+ out:
+	up_write(&ls->ls_root_sem);
+	return error;
+}
+
+void dlm_release_root_list(struct dlm_ls *ls)
+{
+	struct dlm_rsb *r, *safe;
+
+	down_write(&ls->ls_root_sem);
+	list_for_each_entry_safe(r, safe, &ls->ls_root_list, res_root_list) {
+		list_del_init(&r->res_root_list);
+		dlm_put_rsb(r);
+	}
+	up_write(&ls->ls_root_sem);
+}
+
+void dlm_clear_toss_list(struct dlm_ls *ls)
+{
+	struct dlm_rsb *r, *safe;
+	int i;
+
+	for (i = 0; i < ls->ls_rsbtbl_size; i++) {
+		write_lock(&ls->ls_rsbtbl[i].lock);
+		list_for_each_entry_safe(r, safe, &ls->ls_rsbtbl[i].toss,
+					 res_hashchain) {
+			list_del(&r->res_hashchain);
+			free_rsb(r);
+		}
+		write_unlock(&ls->ls_rsbtbl[i].lock);
+	}
+}
+
diff -urN oldtree/drivers/dlm/recover.h newtree/drivers/dlm/recover.h
--- oldtree/drivers/dlm/recover.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/recover.h	2006-02-21 15:58:32.564196048 +0000
@@ -0,0 +1,34 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __RECOVER_DOT_H__
+#define __RECOVER_DOT_H__
+
+int dlm_wait_function(struct dlm_ls *ls, int (*testfn) (struct dlm_ls *ls));
+uint32_t dlm_recover_status(struct dlm_ls *ls);
+void dlm_set_recover_status(struct dlm_ls *ls, uint32_t status);
+int dlm_recover_members_wait(struct dlm_ls *ls);
+int dlm_recover_directory_wait(struct dlm_ls *ls);
+int dlm_recover_locks_wait(struct dlm_ls *ls);
+int dlm_recover_done_wait(struct dlm_ls *ls);
+int dlm_recover_masters(struct dlm_ls *ls);
+int dlm_recover_master_reply(struct dlm_ls *ls, struct dlm_rcom *rc);
+int dlm_recover_locks(struct dlm_ls *ls);
+void dlm_recovered_lock(struct dlm_rsb *r);
+int dlm_create_root_list(struct dlm_ls *ls);
+void dlm_release_root_list(struct dlm_ls *ls);
+void dlm_clear_toss_list(struct dlm_ls *ls);
+void dlm_recover_rsbs(struct dlm_ls *ls);
+
+#endif				/* __RECOVER_DOT_H__ */
+
diff -urN oldtree/drivers/dlm/recoverd.c newtree/drivers/dlm/recoverd.c
--- oldtree/drivers/dlm/recoverd.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/recoverd.c	2006-02-21 15:58:32.782162912 +0000
@@ -0,0 +1,285 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "member.h"
+#include "dir.h"
+#include "ast.h"
+#include "recover.h"
+#include "lowcomms.h"
+#include "lock.h"
+#include "requestqueue.h"
+#include "recoverd.h"
+
+
+/* If the start for which we're re-enabling locking (seq) has been superseded
+   by a newer stop (ls_recover_seq), we need to leave locking disabled. */
+
+static int enable_locking(struct dlm_ls *ls, uint64_t seq)
+{
+	int error = -EINTR;
+
+	spin_lock(&ls->ls_recover_lock);
+	if (ls->ls_recover_seq == seq) {
+		set_bit(LSFL_RUNNING, &ls->ls_flags);
+		up_write(&ls->ls_in_recovery);
+		error = 0;
+	}
+	spin_unlock(&ls->ls_recover_lock);
+	return error;
+}
+
+static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
+{
+	unsigned long start;
+	int error, neg = 0;
+
+	log_debug(ls, "recover %llx", rv->seq);
+
+	mutex_lock(&ls->ls_recoverd_active);
+
+	/*
+	 * Suspending and resuming dlm_astd ensures that no lkb's from this ls
+	 * will be processed by dlm_astd during recovery.
+	 */
+
+	dlm_astd_suspend();
+	dlm_astd_resume();
+
+	/*
+	 * This list of root rsb's will be the basis of most of the recovery
+	 * routines.
+	 */
+
+	dlm_create_root_list(ls);
+
+	/*
+	 * Free all the tossed rsb's so we don't have to recover them.
+	 */
+
+	dlm_clear_toss_list(ls);
+
+	/*
+	 * Add or remove nodes from the lockspace's ls_nodes list.
+	 * Also waits for all nodes to complete dlm_recover_members.
+	 */
+
+	error = dlm_recover_members(ls, rv, &neg);
+	if (error) {
+		log_error(ls, "recover_members failed %d", error);
+		goto fail;
+	}
+	start = jiffies;
+
+	/*
+	 * Rebuild our own share of the directory by collecting from all other
+	 * nodes their master rsb names that hash to us.
+	 */
+
+	error = dlm_recover_directory(ls);
+	if (error) {
+		log_error(ls, "recover_directory failed %d", error);
+		goto fail;
+	}
+
+	/*
+	 * Purge directory-related requests that are saved in requestqueue.
+	 * All dir requests from before recovery are invalid now due to the dir
+	 * rebuild and will be resent by the requesting nodes.
+	 */
+
+	dlm_purge_requestqueue(ls);
+
+	/*
+	 * Wait for all nodes to complete directory rebuild.
+	 */
+
+	error = dlm_recover_directory_wait(ls);
+	if (error) {
+		log_error(ls, "recover_directory_wait failed %d", error);
+		goto fail;
+	}
+
+	/*
+	 * We may have outstanding operations that are waiting for a reply from
+	 * a failed node.  Mark these to be resent after recovery.  Unlock and
+	 * cancel ops can just be completed.
+	 */
+
+	dlm_recover_waiters_pre(ls);
+
+	error = dlm_recovery_stopped(ls);
+	if (error)
+		goto fail;
+
+	if (neg || dlm_no_directory(ls)) {
+		/*
+		 * Clear lkb's for departed nodes.
+		 */
+
+		dlm_purge_locks(ls);
+
+		/*
+		 * Get new master nodeid's for rsb's that were mastered on
+		 * departed nodes.
+		 */
+
+		error = dlm_recover_masters(ls);
+		if (error) {
+			log_error(ls, "recover_masters failed %d", error);
+			goto fail;
+		}
+
+		/*
+		 * Send our locks on remastered rsb's to the new masters.
+		 */
+
+		error = dlm_recover_locks(ls);
+		if (error) {
+			log_error(ls, "recover_locks failed %d", error);
+			goto fail;
+		}
+
+		error = dlm_recover_locks_wait(ls);
+		if (error) {
+			log_error(ls, "recover_locks_wait failed %d", error);
+			goto fail;
+		}
+
+		/*
+		 * Finalize state in master rsb's now that all locks can be
+		 * checked.  This includes conversion resolution and lvb
+		 * settings.
+		 */
+
+		dlm_recover_rsbs(ls);
+	}
+
+	dlm_release_root_list(ls);
+
+	dlm_set_recover_status(ls, DLM_RS_DONE);
+	error = dlm_recover_done_wait(ls);
+	if (error) {
+		log_error(ls, "recover_done_wait failed %d", error);
+		goto fail;
+	}
+
+	dlm_clear_members_gone(ls);
+
+	error = enable_locking(ls, rv->seq);
+	if (error) {
+		log_error(ls, "enable_locking failed %d", error);
+		goto fail;
+	}
+
+	error = dlm_process_requestqueue(ls);
+	if (error) {
+		log_error(ls, "process_requestqueue failed %d", error);
+		goto fail;
+	}
+
+	error = dlm_recover_waiters_post(ls);
+	if (error) {
+		log_error(ls, "recover_waiters_post failed %d", error);
+		goto fail;
+	}
+
+	dlm_grant_after_purge(ls);
+
+	dlm_astd_wake();
+
+	log_debug(ls, "recover %llx done: %u ms", rv->seq,
+		  jiffies_to_msecs(jiffies - start));
+	mutex_unlock(&ls->ls_recoverd_active);
+
+	return 0;
+
+ fail:
+	dlm_release_root_list(ls);
+	log_debug(ls, "recover %llx error %d", rv->seq, error);
+	mutex_unlock(&ls->ls_recoverd_active);
+	return error;
+}
+
+static void do_ls_recovery(struct dlm_ls *ls)
+{
+	struct dlm_recover *rv = NULL;
+
+	spin_lock(&ls->ls_recover_lock);
+	rv = ls->ls_recover_args;
+	ls->ls_recover_args = NULL;
+	clear_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
+	spin_unlock(&ls->ls_recover_lock);
+
+	if (rv) {
+		ls_recover(ls, rv);
+		kfree(rv->nodeids);
+		kfree(rv);
+	}
+}
+
+static int dlm_recoverd(void *arg)
+{
+	struct dlm_ls *ls;
+
+	ls = dlm_find_lockspace_local(arg);
+
+	while (!kthread_should_stop()) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (!test_bit(LSFL_WORK, &ls->ls_flags))
+			schedule();
+		set_current_state(TASK_RUNNING);
+
+		if (test_and_clear_bit(LSFL_WORK, &ls->ls_flags))
+			do_ls_recovery(ls);
+	}
+
+	dlm_put_lockspace(ls);
+	return 0;
+}
+
+void dlm_recoverd_kick(struct dlm_ls *ls)
+{
+	set_bit(LSFL_WORK, &ls->ls_flags);
+	wake_up_process(ls->ls_recoverd_task);
+}
+
+int dlm_recoverd_start(struct dlm_ls *ls)
+{
+	struct task_struct *p;
+	int error = 0;
+
+	p = kthread_run(dlm_recoverd, ls, "dlm_recoverd");
+	if (IS_ERR(p))
+		error = PTR_ERR(p);
+	else
+                ls->ls_recoverd_task = p;
+	return error;
+}
+
+void dlm_recoverd_stop(struct dlm_ls *ls)
+{
+	kthread_stop(ls->ls_recoverd_task);
+}
+
+void dlm_recoverd_suspend(struct dlm_ls *ls)
+{
+	mutex_lock(&ls->ls_recoverd_active);
+}
+
+void dlm_recoverd_resume(struct dlm_ls *ls)
+{
+	mutex_unlock(&ls->ls_recoverd_active);
+}
+
diff -urN oldtree/drivers/dlm/recoverd.h newtree/drivers/dlm/recoverd.h
--- oldtree/drivers/dlm/recoverd.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/recoverd.h	2006-02-21 15:58:32.314234048 +0000
@@ -0,0 +1,24 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __RECOVERD_DOT_H__
+#define __RECOVERD_DOT_H__
+
+void dlm_recoverd_kick(struct dlm_ls *ls);
+void dlm_recoverd_stop(struct dlm_ls *ls);
+int dlm_recoverd_start(struct dlm_ls *ls);
+void dlm_recoverd_suspend(struct dlm_ls *ls);
+void dlm_recoverd_resume(struct dlm_ls *ls);
+
+#endif				/* __RECOVERD_DOT_H__ */
+
diff -urN oldtree/drivers/dlm/requestqueue.c newtree/drivers/dlm/requestqueue.c
--- oldtree/drivers/dlm/requestqueue.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/requestqueue.c	2006-02-21 15:58:32.783162760 +0000
@@ -0,0 +1,184 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "member.h"
+#include "lock.h"
+#include "dir.h"
+#include "config.h"
+#include "requestqueue.h"
+
+struct rq_entry {
+	struct list_head list;
+	int nodeid;
+	char request[1];
+};
+
+/*
+ * Requests received while the lockspace is in recovery get added to the
+ * request queue and processed when recovery is complete.  This happens when
+ * the lockspace is suspended on some nodes before it is on others, or the
+ * lockspace is enabled on some while still suspended on others.
+ */
+
+void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd)
+{
+	struct rq_entry *e;
+	int length = hd->h_length;
+
+	if (dlm_is_removed(ls, nodeid))
+		return;
+
+	e = kmalloc(sizeof(struct rq_entry) + length, GFP_KERNEL);
+	if (!e) {
+		log_print("dlm_add_requestqueue: out of memory\n");
+		return;
+	}
+
+	e->nodeid = nodeid;
+	memcpy(e->request, hd, length);
+
+	mutex_lock(&ls->ls_requestqueue_mutex);
+	list_add_tail(&e->list, &ls->ls_requestqueue);
+	mutex_unlock(&ls->ls_requestqueue_mutex);
+}
+
+int dlm_process_requestqueue(struct dlm_ls *ls)
+{
+	struct rq_entry *e;
+	struct dlm_header *hd;
+	int error = 0;
+
+	mutex_lock(&ls->ls_requestqueue_mutex);
+
+	for (;;) {
+		if (list_empty(&ls->ls_requestqueue)) {
+			mutex_unlock(&ls->ls_requestqueue_mutex);
+			error = 0;
+			break;
+		}
+		e = list_entry(ls->ls_requestqueue.next, struct rq_entry, list);
+		mutex_unlock(&ls->ls_requestqueue_mutex);
+
+		hd = (struct dlm_header *) e->request;
+		error = dlm_receive_message(hd, e->nodeid, 1);
+
+		if (error == -EINTR) {
+			/* entry is left on requestqueue */
+			log_debug(ls, "process_requestqueue abort eintr");
+			break;
+		}
+
+		mutex_lock(&ls->ls_requestqueue_mutex);
+		list_del(&e->list);
+		kfree(e);
+
+		if (dlm_locking_stopped(ls)) {
+			log_debug(ls, "process_requestqueue abort running");
+			mutex_unlock(&ls->ls_requestqueue_mutex);
+			error = -EINTR;
+			break;
+		}
+		schedule();
+	}
+
+	return error;
+}
+
+/*
+ * After recovery is done, locking is resumed and dlm_recoverd takes all the
+ * saved requests and processes them as they would have been by dlm_recvd.  At
+ * the same time, dlm_recvd will start receiving new requests from remote
+ * nodes.  We want to delay dlm_recvd processing new requests until
+ * dlm_recoverd has finished processing the old saved requests.
+ */
+
+void dlm_wait_requestqueue(struct dlm_ls *ls)
+{
+	for (;;) {
+		mutex_lock(&ls->ls_requestqueue_mutex);
+		if (list_empty(&ls->ls_requestqueue))
+			break;
+		if (dlm_locking_stopped(ls))
+			break;
+		mutex_unlock(&ls->ls_requestqueue_mutex);
+		schedule();
+	}
+	mutex_unlock(&ls->ls_requestqueue_mutex);
+}
+
+static int purge_request(struct dlm_ls *ls, struct dlm_message *ms, int nodeid)
+{
+	uint32_t type = ms->m_type;
+
+	if (dlm_is_removed(ls, nodeid))
+		return 1;
+
+	/* directory operations are always purged because the directory is
+	   always rebuilt during recovery and the lookups resent */
+
+	if (type == DLM_MSG_REMOVE ||
+	    type == DLM_MSG_LOOKUP ||
+	    type == DLM_MSG_LOOKUP_REPLY)
+		return 1;
+
+	if (!dlm_no_directory(ls))
+		return 0;
+
+	/* with no directory, the master is likely to change as a part of
+	   recovery; requests to/from the defunct master need to be purged */
+
+	switch (type) {
+	case DLM_MSG_REQUEST:
+	case DLM_MSG_CONVERT:
+	case DLM_MSG_UNLOCK:
+	case DLM_MSG_CANCEL:
+		/* we're no longer the master of this resource, the sender
+		   will resend to the new master (see waiter_needs_recovery) */
+
+		if (dlm_hash2nodeid(ls, ms->m_hash) != dlm_our_nodeid())
+			return 1;
+		break;
+
+	case DLM_MSG_REQUEST_REPLY:
+	case DLM_MSG_CONVERT_REPLY:
+	case DLM_MSG_UNLOCK_REPLY:
+	case DLM_MSG_CANCEL_REPLY:
+	case DLM_MSG_GRANT:
+		/* this reply is from the former master of the resource,
+		   we'll resend to the new master if needed */
+
+		if (dlm_hash2nodeid(ls, ms->m_hash) != nodeid)
+			return 1;
+		break;
+	}
+
+	return 0;
+}
+
+void dlm_purge_requestqueue(struct dlm_ls *ls)
+{
+	struct dlm_message *ms;
+	struct rq_entry *e, *safe;
+
+	mutex_lock(&ls->ls_requestqueue_mutex);
+	list_for_each_entry_safe(e, safe, &ls->ls_requestqueue, list) {
+		ms = (struct dlm_message *) e->request;
+
+		if (purge_request(ls, ms, e->nodeid)) {
+			list_del(&e->list);
+			kfree(e);
+		}
+	}
+	mutex_unlock(&ls->ls_requestqueue_mutex);
+}
+
diff -urN oldtree/drivers/dlm/requestqueue.h newtree/drivers/dlm/requestqueue.h
--- oldtree/drivers/dlm/requestqueue.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/requestqueue.h	2006-02-21 15:58:32.315233896 +0000
@@ -0,0 +1,22 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __REQUESTQUEUE_DOT_H__
+#define __REQUESTQUEUE_DOT_H__
+
+void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd);
+int dlm_process_requestqueue(struct dlm_ls *ls);
+void dlm_wait_requestqueue(struct dlm_ls *ls);
+void dlm_purge_requestqueue(struct dlm_ls *ls);
+
+#endif
+
diff -urN oldtree/drivers/dlm/util.c newtree/drivers/dlm/util.c
--- oldtree/drivers/dlm/util.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/util.c	2006-02-21 15:58:32.760166256 +0000
@@ -0,0 +1,173 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "rcom.h"
+#include "util.h"
+
+static void header_out(struct dlm_header *hd)
+{
+	hd->h_version		= cpu_to_le32(hd->h_version);
+	hd->h_lockspace		= cpu_to_le32(hd->h_lockspace);
+	hd->h_nodeid		= cpu_to_le32(hd->h_nodeid);
+	hd->h_length		= cpu_to_le16(hd->h_length);
+}
+
+static void header_in(struct dlm_header *hd)
+{
+	hd->h_version		= le32_to_cpu(hd->h_version);
+	hd->h_lockspace		= le32_to_cpu(hd->h_lockspace);
+	hd->h_nodeid		= le32_to_cpu(hd->h_nodeid);
+	hd->h_length		= le16_to_cpu(hd->h_length);
+}
+
+void dlm_message_out(struct dlm_message *ms)
+{
+	struct dlm_header *hd = (struct dlm_header *) ms;
+
+	header_out(hd);
+
+	ms->m_type		= cpu_to_le32(ms->m_type);
+	ms->m_nodeid		= cpu_to_le32(ms->m_nodeid);
+	ms->m_pid		= cpu_to_le32(ms->m_pid);
+	ms->m_lkid		= cpu_to_le32(ms->m_lkid);
+	ms->m_remid		= cpu_to_le32(ms->m_remid);
+	ms->m_parent_lkid	= cpu_to_le32(ms->m_parent_lkid);
+	ms->m_parent_remid	= cpu_to_le32(ms->m_parent_remid);
+	ms->m_exflags		= cpu_to_le32(ms->m_exflags);
+	ms->m_sbflags		= cpu_to_le32(ms->m_sbflags);
+	ms->m_flags		= cpu_to_le32(ms->m_flags);
+	ms->m_lvbseq		= cpu_to_le32(ms->m_lvbseq);
+	ms->m_hash		= cpu_to_le32(ms->m_hash);
+	ms->m_status		= cpu_to_le32(ms->m_status);
+	ms->m_grmode		= cpu_to_le32(ms->m_grmode);
+	ms->m_rqmode		= cpu_to_le32(ms->m_rqmode);
+	ms->m_bastmode		= cpu_to_le32(ms->m_bastmode);
+	ms->m_asts		= cpu_to_le32(ms->m_asts);
+	ms->m_result		= cpu_to_le32(ms->m_result);
+	ms->m_range[0]		= cpu_to_le64(ms->m_range[0]);
+	ms->m_range[1]		= cpu_to_le64(ms->m_range[1]);
+}
+
+void dlm_message_in(struct dlm_message *ms)
+{
+	struct dlm_header *hd = (struct dlm_header *) ms;
+
+	header_in(hd);
+
+	ms->m_type		= le32_to_cpu(ms->m_type);
+	ms->m_nodeid		= le32_to_cpu(ms->m_nodeid);
+	ms->m_pid		= le32_to_cpu(ms->m_pid);
+	ms->m_lkid		= le32_to_cpu(ms->m_lkid);
+	ms->m_remid		= le32_to_cpu(ms->m_remid);
+	ms->m_parent_lkid	= le32_to_cpu(ms->m_parent_lkid);
+	ms->m_parent_remid	= le32_to_cpu(ms->m_parent_remid);
+	ms->m_exflags		= le32_to_cpu(ms->m_exflags);
+	ms->m_sbflags		= le32_to_cpu(ms->m_sbflags);
+	ms->m_flags		= le32_to_cpu(ms->m_flags);
+	ms->m_lvbseq		= le32_to_cpu(ms->m_lvbseq);
+	ms->m_hash		= le32_to_cpu(ms->m_hash);
+	ms->m_status		= le32_to_cpu(ms->m_status);
+	ms->m_grmode		= le32_to_cpu(ms->m_grmode);
+	ms->m_rqmode		= le32_to_cpu(ms->m_rqmode);
+	ms->m_bastmode		= le32_to_cpu(ms->m_bastmode);
+	ms->m_asts		= le32_to_cpu(ms->m_asts);
+	ms->m_result		= le32_to_cpu(ms->m_result);
+	ms->m_range[0]		= le64_to_cpu(ms->m_range[0]);
+	ms->m_range[1]		= le64_to_cpu(ms->m_range[1]);
+}
+
+static void rcom_lock_out(struct rcom_lock *rl)
+{
+	rl->rl_ownpid		= cpu_to_le32(rl->rl_ownpid);
+	rl->rl_lkid		= cpu_to_le32(rl->rl_lkid);
+	rl->rl_remid		= cpu_to_le32(rl->rl_remid);
+	rl->rl_parent_lkid	= cpu_to_le32(rl->rl_parent_lkid);
+	rl->rl_parent_remid	= cpu_to_le32(rl->rl_parent_remid);
+	rl->rl_exflags		= cpu_to_le32(rl->rl_exflags);
+	rl->rl_flags		= cpu_to_le32(rl->rl_flags);
+	rl->rl_lvbseq		= cpu_to_le32(rl->rl_lvbseq);
+	rl->rl_result		= cpu_to_le32(rl->rl_result);
+	rl->rl_wait_type	= cpu_to_le16(rl->rl_wait_type);
+	rl->rl_namelen		= cpu_to_le16(rl->rl_namelen);
+	rl->rl_range[0]		= cpu_to_le64(rl->rl_range[0]);
+	rl->rl_range[1]		= cpu_to_le64(rl->rl_range[1]);
+	rl->rl_range[2]		= cpu_to_le64(rl->rl_range[2]);
+	rl->rl_range[3]		= cpu_to_le64(rl->rl_range[3]);
+}
+
+static void rcom_lock_in(struct rcom_lock *rl)
+{
+	rl->rl_ownpid		= le32_to_cpu(rl->rl_ownpid);
+	rl->rl_lkid		= le32_to_cpu(rl->rl_lkid);
+	rl->rl_remid		= le32_to_cpu(rl->rl_remid);
+	rl->rl_parent_lkid	= le32_to_cpu(rl->rl_parent_lkid);
+	rl->rl_parent_remid	= le32_to_cpu(rl->rl_parent_remid);
+	rl->rl_exflags		= le32_to_cpu(rl->rl_exflags);
+	rl->rl_flags		= le32_to_cpu(rl->rl_flags);
+	rl->rl_lvbseq		= le32_to_cpu(rl->rl_lvbseq);
+	rl->rl_result		= le32_to_cpu(rl->rl_result);
+	rl->rl_wait_type	= le16_to_cpu(rl->rl_wait_type);
+	rl->rl_namelen		= le16_to_cpu(rl->rl_namelen);
+	rl->rl_range[0]		= le64_to_cpu(rl->rl_range[0]);
+	rl->rl_range[1]		= le64_to_cpu(rl->rl_range[1]);
+	rl->rl_range[2]		= le64_to_cpu(rl->rl_range[2]);
+	rl->rl_range[3]		= le64_to_cpu(rl->rl_range[3]);
+}
+
+static void rcom_config_out(struct rcom_config *rf)
+{
+	rf->rf_lvblen		= cpu_to_le32(rf->rf_lvblen);
+	rf->rf_lsflags		= cpu_to_le32(rf->rf_lsflags);
+}
+
+static void rcom_config_in(struct rcom_config *rf)
+{
+	rf->rf_lvblen		= le32_to_cpu(rf->rf_lvblen);
+	rf->rf_lsflags		= le32_to_cpu(rf->rf_lsflags);
+}
+
+void dlm_rcom_out(struct dlm_rcom *rc)
+{
+	struct dlm_header *hd = (struct dlm_header *) rc;
+	int type = rc->rc_type;
+
+	header_out(hd);
+
+	rc->rc_type		= cpu_to_le32(rc->rc_type);
+	rc->rc_result		= cpu_to_le32(rc->rc_result);
+	rc->rc_id		= cpu_to_le64(rc->rc_id);
+
+	if (type == DLM_RCOM_LOCK)
+		rcom_lock_out((struct rcom_lock *) rc->rc_buf);
+
+	else if (type == DLM_RCOM_STATUS_REPLY)
+		rcom_config_out((struct rcom_config *) rc->rc_buf);
+}
+
+void dlm_rcom_in(struct dlm_rcom *rc)
+{
+	struct dlm_header *hd = (struct dlm_header *) rc;
+
+	header_in(hd);
+
+	rc->rc_type		= le32_to_cpu(rc->rc_type);
+	rc->rc_result		= le32_to_cpu(rc->rc_result);
+	rc->rc_id		= le64_to_cpu(rc->rc_id);
+
+	if (rc->rc_type == DLM_RCOM_LOCK)
+		rcom_lock_in((struct rcom_lock *) rc->rc_buf);
+
+	else if (rc->rc_type == DLM_RCOM_STATUS_REPLY)
+		rcom_config_in((struct rcom_config *) rc->rc_buf);
+}
+
diff -urN oldtree/drivers/dlm/util.h newtree/drivers/dlm/util.h
--- oldtree/drivers/dlm/util.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/dlm/util.h	2006-02-21 15:58:32.687177352 +0000
@@ -0,0 +1,22 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __UTIL_DOT_H__
+#define __UTIL_DOT_H__
+
+void dlm_message_out(struct dlm_message *ms);
+void dlm_message_in(struct dlm_message *ms);
+void dlm_rcom_out(struct dlm_rcom *rc);
+void dlm_rcom_in(struct dlm_rcom *rc);
+
+#endif
+
diff -urN oldtree/drivers/eisa/eisa-bus.c newtree/drivers/eisa/eisa-bus.c
--- oldtree/drivers/eisa/eisa-bus.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/eisa/eisa-bus.c	2006-02-21 15:58:16.084701312 +0000
@@ -128,9 +128,36 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int eisa_bus_suspend(struct device *dev, pm_message_t state)
+{
+	int ret = 0;
+
+	if (dev->driver && dev->driver->suspend)
+		ret = dev->driver->suspend(dev, state);
+
+	return ret;
+}
+
+static int eisa_bus_resume(struct device *dev)
+{
+	int ret = 0;
+
+	if (dev->driver && dev->driver->resume)
+		ret = dev->driver->resume(dev);
+
+	return ret;
+}
+#else
+#define eisa_bus_suspend NULL
+#define eisa_bus_resume NULL
+#endif
+
 struct bus_type eisa_bus_type = {
 	.name  = "eisa",
 	.match = eisa_bus_match,
+	.suspend = eisa_bus_suspend,
+	.resume = eisa_bus_resume,
 };
 
 int eisa_driver_register (struct eisa_driver *edrv)
diff -urN oldtree/drivers/fc4/fc.c newtree/drivers/fc4/fc.c
--- oldtree/drivers/fc4/fc.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/fc4/fc.c	2006-02-21 15:58:09.802656328 +0000
@@ -1053,7 +1053,7 @@
 	int i;
 
 	fcmd = &_fcmd;
-	memset(fcmd, 0, sizeof(fcmd));
+	memset(fcmd, 0, sizeof(fcp_cmnd));
 	FCD(("PLOGI SID %d DID %d\n", fc->sid, alpa))
 	fch = &fcmd->fch;
 	FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, alpa);
diff -urN oldtree/drivers/firmware/dcdbas.c newtree/drivers/firmware/dcdbas.c
--- oldtree/drivers/firmware/dcdbas.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/firmware/dcdbas.c	2006-02-21 15:58:23.797528784 +0000
@@ -33,6 +33,7 @@
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 #include <asm/semaphore.h>
 
@@ -48,7 +49,7 @@
 static dma_addr_t smi_data_buf_handle;
 static unsigned long smi_data_buf_size;
 static u32 smi_data_buf_phys_addr;
-static DECLARE_MUTEX(smi_data_lock);
+static DEFINE_MUTEX(smi_data_lock);
 
 static unsigned int host_control_action;
 static unsigned int host_control_smi_type;
@@ -139,9 +140,9 @@
 	buf_size = simple_strtoul(buf, NULL, 10);
 
 	/* make sure SMI data buffer is at least buf_size */
-	down(&smi_data_lock);
+	mutex_lock(&smi_data_lock);
 	ret = smi_data_buf_realloc(buf_size);
-	up(&smi_data_lock);
+	mutex_unlock(&smi_data_lock);
 	if (ret)
 		return ret;
 
@@ -154,7 +155,7 @@
 	size_t max_read;
 	ssize_t ret;
 
-	down(&smi_data_lock);
+	mutex_lock(&smi_data_lock);
 
 	if (pos >= smi_data_buf_size) {
 		ret = 0;
@@ -165,7 +166,7 @@
 	ret = min(max_read, count);
 	memcpy(buf, smi_data_buf + pos, ret);
 out:
-	up(&smi_data_lock);
+	mutex_unlock(&smi_data_lock);
 	return ret;
 }
 
@@ -174,7 +175,7 @@
 {
 	ssize_t ret;
 
-	down(&smi_data_lock);
+	mutex_lock(&smi_data_lock);
 
 	ret = smi_data_buf_realloc(pos + count);
 	if (ret)
@@ -183,7 +184,7 @@
 	memcpy(smi_data_buf + pos, buf, count);
 	ret = count;
 out:
-	up(&smi_data_lock);
+	mutex_unlock(&smi_data_lock);
 	return ret;
 }
 
@@ -201,9 +202,9 @@
 	ssize_t ret;
 
 	/* make sure buffer is available for host control command */
-	down(&smi_data_lock);
+	mutex_lock(&smi_data_lock);
 	ret = smi_data_buf_realloc(sizeof(struct apm_cmd));
-	up(&smi_data_lock);
+	mutex_unlock(&smi_data_lock);
 	if (ret)
 		return ret;
 
@@ -302,7 +303,7 @@
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 	ssize_t ret;
 
-	down(&smi_data_lock);
+	mutex_lock(&smi_data_lock);
 
 	if (smi_data_buf_size < sizeof(struct smi_cmd)) {
 		ret = -ENODEV;
@@ -334,7 +335,7 @@
 	}
 
 out:
-	up(&smi_data_lock);
+	mutex_unlock(&smi_data_lock);
 	return ret;
 }
 
diff -urN oldtree/drivers/hwmon/Kconfig newtree/drivers/hwmon/Kconfig
--- oldtree/drivers/hwmon/Kconfig	2006-02-19 11:41:02.148016552 +0000
+++ newtree/drivers/hwmon/Kconfig	2006-02-21 15:58:14.371961688 +0000
@@ -406,13 +406,14 @@
 	  will be called w83l785ts.
 
 config SENSORS_W83627HF
-	tristate "Winbond W83627HF, W83627THF, W83637HF, W83697HF"
-	depends on HWMON && I2C && EXPERIMENTAL
+	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
+	depends on HWMON && I2C
 	select I2C_ISA
 	select HWMON_VID
 	help
 	  If you say yes here you get support for the Winbond W836X7 series
-	  of sensor chips: the W83627HF, W83627THF, W83637HF, and the W83697HF
+	  of sensor chips: the W83627HF, W83627THF, W83637HF, W83687THF and
+	  W83697HF.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called w83627hf.
diff -urN oldtree/drivers/hwmon/adm1021.c newtree/drivers/hwmon/adm1021.c
--- oldtree/drivers/hwmon/adm1021.c	2006-02-19 11:41:02.148016552 +0000
+++ newtree/drivers/hwmon/adm1021.c	2006-02-21 15:58:14.182990416 +0000
@@ -26,6 +26,7 @@
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 
 /* Addresses to scan */
@@ -92,7 +93,7 @@
 	struct class_device *class_dev;
 	enum chips type;
 
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 
@@ -162,10 +163,10 @@
 	struct adm1021_data *data = i2c_get_clientdata(client);	\
 	int temp = simple_strtoul(buf, NULL, 10);		\
 								\
-	down(&data->update_lock);				\
+	mutex_lock(&data->update_lock);				\
 	data->value = TEMP_TO_REG(temp);			\
 	adm1021_write_value(client, reg, data->value);		\
-	up(&data->update_lock);					\
+	mutex_unlock(&data->update_lock);			\
 	return count;						\
 }
 set(temp_max, ADM1021_REG_TOS_W);
@@ -275,7 +276,7 @@
 	strlcpy(new_client->name, type_name, I2C_NAME_SIZE);
 	data->type = kind;
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -351,7 +352,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1021_data *data = i2c_get_clientdata(client);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 	    || !data->valid) {
@@ -375,7 +376,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/adm1025.c newtree/drivers/hwmon/adm1025.c
--- oldtree/drivers/hwmon/adm1025.c	2006-02-19 11:41:02.149016400 +0000
+++ newtree/drivers/hwmon/adm1025.c	2006-02-21 15:58:14.183990264 +0000
@@ -53,6 +53,7 @@
 #include <linux/hwmon.h>
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 /*
  * Addresses to scan
@@ -133,7 +134,7 @@
 struct adm1025_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid; /* zero until following fields are valid */
 	unsigned long last_updated; /* in jiffies */
 
@@ -207,11 +208,11 @@
 	struct adm1025_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
  \
-	down(&data->update_lock); \
+	mutex_lock(&data->update_lock); \
 	data->in_min[offset] = IN_TO_REG(val, in_scale[offset]); \
 	i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(offset), \
 				  data->in_min[offset]); \
-	up(&data->update_lock); \
+	mutex_unlock(&data->update_lock); \
 	return count; \
 } \
 static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \
@@ -221,11 +222,11 @@
 	struct adm1025_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
  \
-	down(&data->update_lock); \
+	mutex_lock(&data->update_lock); \
 	data->in_max[offset] = IN_TO_REG(val, in_scale[offset]); \
 	i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(offset), \
 				  data->in_max[offset]); \
-	up(&data->update_lock); \
+	mutex_unlock(&data->update_lock); \
 	return count; \
 } \
 static DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \
@@ -247,11 +248,11 @@
 	struct adm1025_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
  \
-	down(&data->update_lock); \
+	mutex_lock(&data->update_lock); \
 	data->temp_min[offset-1] = TEMP_TO_REG(val); \
 	i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(offset-1), \
 				  data->temp_min[offset-1]); \
-	up(&data->update_lock); \
+	mutex_unlock(&data->update_lock); \
 	return count; \
 } \
 static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \
@@ -261,11 +262,11 @@
 	struct adm1025_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
  \
-	down(&data->update_lock); \
+	mutex_lock(&data->update_lock); \
 	data->temp_max[offset-1] = TEMP_TO_REG(val); \
 	i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(offset-1), \
 				  data->temp_max[offset-1]); \
-	up(&data->update_lock); \
+	mutex_unlock(&data->update_lock); \
 	return count; \
 } \
 static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
@@ -404,7 +405,7 @@
 	/* We can fill in the remaining client fields */
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -523,7 +524,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1025_data *data = i2c_get_clientdata(client);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
 		int i;
@@ -558,7 +559,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/adm1026.c newtree/drivers/hwmon/adm1026.c
--- oldtree/drivers/hwmon/adm1026.c	2006-02-19 11:41:02.150016248 +0000
+++ newtree/drivers/hwmon/adm1026.c	2006-02-21 15:58:14.185989960 +0000
@@ -32,6 +32,7 @@
 #include <linux/hwmon-sysfs.h>
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
@@ -260,10 +261,10 @@
 struct adm1026_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore lock;
+	struct mutex lock;
 	enum chips type;
 
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	int valid;		/* !=0 if following fields are valid */
 	unsigned long last_reading;	/* In jiffies */
 	unsigned long last_config;	/* In jiffies */
@@ -575,7 +576,7 @@
 	int i;
 	long value, alarms, gpio;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	if (!data->valid
 	    || time_after(jiffies, data->last_reading + ADM1026_DATA_INTERVAL)) {
 		/* Things that change quickly */
@@ -710,7 +711,7 @@
 	dev_dbg(&client->dev, "Setting VID from GPIO11-15.\n");
 	data->vid = (data->gpio >> 11) & 0x1f;
 	data->valid = 1;
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return data;
 }
 
@@ -739,10 +740,10 @@
 	struct adm1026_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_min[nr] = INS_TO_REG(nr, val);
 	adm1026_write_value(client, ADM1026_REG_IN_MIN[nr], data->in_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count; 
 }
 static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
@@ -762,10 +763,10 @@
 	struct adm1026_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_max[nr] = INS_TO_REG(nr, val);
 	adm1026_write_value(client, ADM1026_REG_IN_MAX[nr], data->in_max[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -813,10 +814,10 @@
 	struct adm1026_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_min[16] = INS_TO_REG(16, val + NEG12_OFFSET);
 	adm1026_write_value(client, ADM1026_REG_IN_MIN[16], data->in_min[16]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count; 
 }
 static ssize_t show_in16_max(struct device *dev, struct device_attribute *attr, char *buf)
@@ -831,10 +832,10 @@
 	struct adm1026_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_max[16] = INS_TO_REG(16, val+NEG12_OFFSET);
 	adm1026_write_value(client, ADM1026_REG_IN_MAX[16], data->in_max[16]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -874,11 +875,11 @@
 	struct adm1026_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->fan_min[nr] = FAN_TO_REG(val, data->fan_div[nr]);
 	adm1026_write_value(client, ADM1026_REG_FAN_MIN(nr),
 		data->fan_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -939,7 +940,7 @@
 	if (new_div == 0) {
 		return -EINVAL;
 	}
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	orig_div = data->fan_div[nr];
 	data->fan_div[nr] = DIV_FROM_REG(new_div);
 
@@ -958,7 +959,7 @@
 	if (data->fan_div[nr] != orig_div) {
 		fixup_fan_min(dev,nr,orig_div);
 	}
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -1001,11 +1002,11 @@
 	struct adm1026_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_min[nr] = TEMP_TO_REG(val);
 	adm1026_write_value(client, ADM1026_REG_TEMP_MIN[nr],
 		data->temp_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
@@ -1025,11 +1026,11 @@
 	struct adm1026_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_max[nr] = TEMP_TO_REG(val);
 	adm1026_write_value(client, ADM1026_REG_TEMP_MAX[nr],
 		data->temp_max[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -1064,11 +1065,11 @@
 	struct adm1026_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_offset[nr] = TEMP_TO_REG(val);
 	adm1026_write_value(client, ADM1026_REG_TEMP_OFFSET[nr],
 		data->temp_offset[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -1115,11 +1116,11 @@
 	struct adm1026_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_tmin[nr] = TEMP_TO_REG(val);
 	adm1026_write_value(client, ADM1026_REG_TEMP_TMIN[nr],
 		data->temp_tmin[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -1150,11 +1151,11 @@
 	int val = simple_strtol(buf, NULL, 10);
 
 	if ((val == 1) || (val==0)) {
-		down(&data->update_lock);
+		mutex_lock(&data->update_lock);
 		data->config1 = (data->config1 & ~CFG1_THERM_HOT) | (val << 4);
 		adm1026_write_value(client, ADM1026_REG_CONFIG1, 
 			data->config1);
-		up(&data->update_lock);
+		mutex_unlock(&data->update_lock);
 	}
 	return count;
 }
@@ -1184,11 +1185,11 @@
 	struct adm1026_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_crit[nr] = TEMP_TO_REG(val);
 	adm1026_write_value(client, ADM1026_REG_TEMP_THERM[nr],
 		data->temp_crit[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -1212,10 +1213,10 @@
 	struct adm1026_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->analog_out = DAC_TO_REG(val);
 	adm1026_write_value(client, ADM1026_REG_DAC, data->analog_out);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -1267,7 +1268,7 @@
 	int val = simple_strtol(buf, NULL, 10);
 	unsigned long mask;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->alarm_mask = val & 0x7fffffff;
 	mask = data->alarm_mask
 		| (data->gpio_mask & 0x10000 ? 0x80000000 : 0);
@@ -1282,7 +1283,7 @@
 	mask >>= 8;
 	adm1026_write_value(client, ADM1026_REG_MASK4,
 		mask & 0xff);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -1303,7 +1304,7 @@
 	int val = simple_strtol(buf, NULL, 10);
 	long   gpio;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->gpio = val & 0x1ffff;
 	gpio = data->gpio;
 	adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_0_7,gpio & 0xff);
@@ -1311,7 +1312,7 @@
 	adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_8_15,gpio & 0xff);
 	gpio = ((gpio >> 1) & 0x80) | (data->alarms >> 24 & 0x7f);
 	adm1026_write_value(client, ADM1026_REG_STATUS4,gpio & 0xff);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -1331,7 +1332,7 @@
 	int val = simple_strtol(buf, NULL, 10);
 	long   mask;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->gpio_mask = val & 0x1ffff;
 	mask = data->gpio_mask;
 	adm1026_write_value(client, ADM1026_REG_GPIO_MASK_0_7,mask & 0xff);
@@ -1339,7 +1340,7 @@
 	adm1026_write_value(client, ADM1026_REG_GPIO_MASK_8_15,mask & 0xff);
 	mask = ((mask >> 1) & 0x80) | (data->alarm_mask >> 24 & 0x7f);
 	adm1026_write_value(client, ADM1026_REG_MASK1,mask & 0xff);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -1359,10 +1360,10 @@
 	if (data->pwm1.enable == 1) {
 		int val = simple_strtol(buf, NULL, 10);
 
-		down(&data->update_lock);
+		mutex_lock(&data->update_lock);
 		data->pwm1.pwm = PWM_TO_REG(val);
 		adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm);
-		up(&data->update_lock);
+		mutex_unlock(&data->update_lock);
 	}
 	return count;
 }
@@ -1378,14 +1379,14 @@
 	struct adm1026_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->pwm1.auto_pwm_min = SENSORS_LIMIT(val,0,255);
 	if (data->pwm1.enable == 2) { /* apply immediately */
 		data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) |
 			PWM_MIN_TO_REG(data->pwm1.auto_pwm_min)); 
 		adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm);
 	}
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t show_auto_pwm_max(struct device *dev, struct device_attribute *attr, char *buf)
@@ -1406,7 +1407,7 @@
 	int     old_enable;
 
 	if ((val >= 0) && (val < 3)) {
-		down(&data->update_lock);
+		mutex_lock(&data->update_lock);
 		old_enable = data->pwm1.enable;
 		data->pwm1.enable = val;
 		data->config1 = (data->config1 & ~CFG1_PWM_AFC)
@@ -1424,7 +1425,7 @@
 			adm1026_write_value(client, ADM1026_REG_PWM, 
 				data->pwm1.pwm);
 		}
-		up(&data->update_lock);
+		mutex_unlock(&data->update_lock);
 	}
 	return count;
 }
@@ -1541,7 +1542,7 @@
 	/* Fill in the remaining client fields */
 	data->type = kind;
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
diff -urN oldtree/drivers/hwmon/adm1031.c newtree/drivers/hwmon/adm1031.c
--- oldtree/drivers/hwmon/adm1031.c	2006-02-19 11:41:02.151016096 +0000
+++ newtree/drivers/hwmon/adm1031.c	2006-02-21 15:58:14.186989808 +0000
@@ -28,6 +28,7 @@
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 /* Following macros takes channel parameter starting from 0 to 2 */
 #define ADM1031_REG_FAN_SPEED(nr)	(0x08 + (nr))
@@ -70,7 +71,7 @@
 struct adm1031_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	int chip_type;
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
@@ -262,10 +263,10 @@
 
 	old_fan_mode = data->conf1;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	
 	if ((ret = get_fan_auto_nearest(data, nr, val, data->conf1, &reg))) {
-		up(&data->update_lock);
+		mutex_unlock(&data->update_lock);
 		return ret;
 	}
 	if (((data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1)) & ADM1031_CONF1_AUTO_MODE) ^ 
@@ -288,7 +289,7 @@
 	}
 	data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1);
 	adm1031_write_value(client, ADM1031_REG_CONF1, data->conf1);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -329,11 +330,11 @@
 	struct adm1031_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]);
 	adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr),
 			    data->auto_temp[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t show_auto_temp_max(struct device *dev, char *buf, int nr)
@@ -349,11 +350,11 @@
 	struct adm1031_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr], data->pwm[nr]);
 	adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr),
 			    data->temp_max[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -405,11 +406,11 @@
 	int val = simple_strtol(buf, NULL, 10);
 	int reg;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) && 
 	    (((val>>4) & 0xf) != 5)) {
 		/* In automatic mode, the only PWM accepted is 33% */
-		up(&data->update_lock);
+		mutex_unlock(&data->update_lock);
 		return -EINVAL;
 	}
 	data->pwm[nr] = PWM_TO_REG(val);
@@ -417,7 +418,7 @@
 	adm1031_write_value(client, ADM1031_REG_PWM,
 			    nr ? ((data->pwm[nr] << 4) & 0xf0) | (reg & 0xf)
 			    : (data->pwm[nr] & 0xf) | (reg & 0xf0));
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -511,7 +512,7 @@
 	struct adm1031_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	if (val) {
 		data->fan_min[nr] = 
 			FAN_TO_REG(val, FAN_DIV_FROM_REG(data->fan_div[nr]));
@@ -519,7 +520,7 @@
 		data->fan_min[nr] = 0xff;
 	}
 	adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), data->fan_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t
@@ -540,7 +541,7 @@
 	if (tmp == 0xff)
 		return -EINVAL;
 	
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	old_div = FAN_DIV_FROM_REG(data->fan_div[nr]);
 	data->fan_div[nr] = (tmp & 0xC0) | (0x3f & data->fan_div[nr]);
 	new_min = data->fan_min[nr] * old_div / 
@@ -553,7 +554,7 @@
 			    data->fan_div[nr]);
 	adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), 
 			    data->fan_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -627,11 +628,11 @@
 
 	val = simple_strtol(buf, NULL, 10);
 	val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_min[nr] = TEMP_TO_REG(val);
 	adm1031_write_value(client, ADM1031_REG_TEMP_MIN(nr),
 			    data->temp_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t
@@ -643,11 +644,11 @@
 
 	val = simple_strtol(buf, NULL, 10);
 	val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_max[nr] = TEMP_TO_REG(val);
 	adm1031_write_value(client, ADM1031_REG_TEMP_MAX(nr),
 			    data->temp_max[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t
@@ -659,11 +660,11 @@
 
 	val = simple_strtol(buf, NULL, 10);
 	val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_crit[nr] = TEMP_TO_REG(val);
 	adm1031_write_value(client, ADM1031_REG_TEMP_CRIT(nr),
 			    data->temp_crit[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -778,7 +779,7 @@
 
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -891,7 +892,7 @@
 	struct adm1031_data *data = i2c_get_clientdata(client);
 	int chan;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 	    || !data->valid) {
@@ -965,7 +966,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/adm9240.c newtree/drivers/hwmon/adm9240.c
--- oldtree/drivers/hwmon/adm9240.c	2006-02-19 11:41:02.152015944 +0000
+++ newtree/drivers/hwmon/adm9240.c	2006-02-21 15:58:14.187989656 +0000
@@ -49,6 +49,7 @@
 #include <linux/hwmon.h>
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
@@ -150,7 +151,7 @@
 	enum chips type;
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid;
 	unsigned long last_updated_measure;
 	unsigned long last_updated_config;
@@ -195,11 +196,11 @@
 	struct adm9240_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_max[attr->index] = TEMP_TO_REG(val);
 	i2c_smbus_write_byte_data(client, ADM9240_REG_TEMP_MAX(attr->index),
 			data->temp_max[attr->index]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -246,11 +247,11 @@
 	struct adm9240_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_min[attr->index] = IN_TO_REG(val, attr->index);
 	i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MIN(attr->index),
 			data->in_min[attr->index]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -263,11 +264,11 @@
 	struct adm9240_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_max[attr->index] = IN_TO_REG(val, attr->index);
 	i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MAX(attr->index),
 			data->in_max[attr->index]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -350,7 +351,7 @@
 	int nr = attr->index;
 	u8 new_div;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (!val) {
 		data->fan_min[nr] = 255;
@@ -390,7 +391,7 @@
 	i2c_smbus_write_byte_data(client, ADM9240_REG_FAN_MIN(nr),
 			data->fan_min[nr]);
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -439,10 +440,10 @@
 	struct adm9240_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->aout = AOUT_TO_REG(val);
 	i2c_smbus_write_byte_data(client, ADM9240_REG_ANALOG_OUT, data->aout);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);
@@ -539,7 +540,7 @@
 	/* fill in the remaining client fields and attach */
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
 	data->type = kind;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	if ((err = i2c_attach_client(new_client)))
 		goto exit_free;
@@ -691,7 +692,7 @@
 	struct adm9240_data *data = i2c_get_clientdata(client);
 	int i;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	/* minimum measurement cycle: 1.75 seconds */
 	if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4))
@@ -771,7 +772,7 @@
 		data->last_updated_config = jiffies;
 		data->valid = 1;
 	}
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return data;
 }
 
diff -urN oldtree/drivers/hwmon/asb100.c newtree/drivers/hwmon/asb100.c
--- oldtree/drivers/hwmon/asb100.c	2006-02-19 11:41:02.153015792 +0000
+++ newtree/drivers/hwmon/asb100.c	2006-02-21 15:58:14.188989504 +0000
@@ -44,6 +44,7 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/jiffies.h>
+#include <linux/mutex.h>
 #include "lm75.h"
 
 /*
@@ -182,10 +183,10 @@
 struct asb100_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore lock;
+	struct mutex lock;
 	enum chips type;
 
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	unsigned long last_updated;	/* In jiffies */
 
 	/* array of 2 pointers to subclients */
@@ -245,11 +246,11 @@
 	struct asb100_data *data = i2c_get_clientdata(client); \
 	unsigned long val = simple_strtoul(buf, NULL, 10); \
  \
-	down(&data->update_lock); \
+	mutex_lock(&data->update_lock); \
 	data->in_##reg[nr] = IN_TO_REG(val); \
 	asb100_write_value(client, ASB100_REG_IN_##REG(nr), \
 		data->in_##reg[nr]); \
-	up(&data->update_lock); \
+	mutex_unlock(&data->update_lock); \
 	return count; \
 }
 
@@ -331,10 +332,10 @@
 	struct asb100_data *data = i2c_get_clientdata(client);
 	u32 val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
 	asb100_write_value(client, ASB100_REG_FAN_MIN(nr), data->fan_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -351,7 +352,7 @@
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 	int reg;
 	
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	min = FAN_FROM_REG(data->fan_min[nr],
 			DIV_FROM_REG(data->fan_div[nr]));
@@ -381,7 +382,7 @@
 		FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
 	asb100_write_value(client, ASB100_REG_FAN_MIN(nr), data->fan_min[nr]);
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return count;
 }
@@ -461,7 +462,7 @@
 	struct asb100_data *data = i2c_get_clientdata(client); \
 	unsigned long val = simple_strtoul(buf, NULL, 10); \
  \
-	down(&data->update_lock); \
+	mutex_lock(&data->update_lock); \
 	switch (nr) { \
 	case 1: case 2: \
 		data->reg[nr] = LM75_TEMP_TO_REG(val); \
@@ -472,7 +473,7 @@
 	} \
 	asb100_write_value(client, ASB100_REG_TEMP_##REG(nr+1), \
 			data->reg[nr]); \
-	up(&data->update_lock); \
+	mutex_unlock(&data->update_lock); \
 	return count; \
 }
 
@@ -574,11 +575,11 @@
 	struct asb100_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->pwm &= 0x80; /* keep the enable bit */
 	data->pwm |= (0x0f & ASB100_PWM_TO_REG(val));
 	asb100_write_value(client, ASB100_REG_PWM1, data->pwm);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -595,11 +596,11 @@
 	struct asb100_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->pwm &= 0x0f; /* keep the duty cycle bits */
 	data->pwm |= (val ? 0x80 : 0x00);
 	asb100_write_value(client, ASB100_REG_PWM1, data->pwm);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -729,7 +730,7 @@
 	}
 
 	new_client = &data->client;
-	init_MUTEX(&data->lock);
+	mutex_init(&data->lock);
 	i2c_set_clientdata(new_client, data);
 	new_client->addr = address;
 	new_client->adapter = adapter;
@@ -789,7 +790,7 @@
 	data->type = kind;
 
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -885,7 +886,7 @@
 	struct i2c_client *cl;
 	int res, bank;
 
-	down(&data->lock);
+	mutex_lock(&data->lock);
 
 	bank = (reg >> 8) & 0x0f;
 	if (bank > 2)
@@ -919,7 +920,7 @@
 	if (bank > 2)
 		i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0);
 
-	up(&data->lock);
+	mutex_unlock(&data->lock);
 
 	return res;
 }
@@ -930,7 +931,7 @@
 	struct i2c_client *cl;
 	int bank;
 
-	down(&data->lock);
+	mutex_lock(&data->lock);
 
 	bank = (reg >> 8) & 0x0f;
 	if (bank > 2)
@@ -960,7 +961,7 @@
 	if (bank > 2)
 		i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0);
 
-	up(&data->lock);
+	mutex_unlock(&data->lock);
 }
 
 static void asb100_init_client(struct i2c_client *client)
@@ -984,7 +985,7 @@
 	struct asb100_data *data = i2c_get_clientdata(client);
 	int i;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 		|| !data->valid) {
@@ -1042,7 +1043,7 @@
 		dev_dbg(&client->dev, "... device update complete\n");
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/atxp1.c newtree/drivers/hwmon/atxp1.c
--- oldtree/drivers/hwmon/atxp1.c	2006-02-19 11:41:02.153015792 +0000
+++ newtree/drivers/hwmon/atxp1.c	2006-02-21 15:58:14.189989352 +0000
@@ -26,6 +26,7 @@
 #include <linux/hwmon.h>
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("System voltages control via Attansic ATXP1");
@@ -60,7 +61,7 @@
 struct atxp1_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	unsigned long last_updated;
 	u8 valid;
 	struct {
@@ -80,7 +81,7 @@
 	client = to_i2c_client(dev);
 	data = i2c_get_clientdata(client);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
 
@@ -93,7 +94,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return(data);
 }
@@ -309,7 +310,7 @@
 
 	data->valid = 0;
 
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	err = i2c_attach_client(new_client);
 
diff -urN oldtree/drivers/hwmon/ds1621.c newtree/drivers/hwmon/ds1621.c
--- oldtree/drivers/hwmon/ds1621.c	2006-02-19 11:41:02.154015640 +0000
+++ newtree/drivers/hwmon/ds1621.c	2006-02-21 15:58:14.189989352 +0000
@@ -28,6 +28,7 @@
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 #include "lm75.h"
 
 /* Addresses to scan */
@@ -72,7 +73,7 @@
 struct ds1621_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid;			/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 
@@ -156,10 +157,10 @@
 	struct ds1621_data *data = ds1621_update_client(dev);		\
 	u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10));	\
 									\
-	down(&data->update_lock);					\
+	mutex_lock(&data->update_lock);					\
 	data->value = val;						\
 	ds1621_write_value(client, reg, data->value);			\
-	up(&data->update_lock);						\
+	mutex_unlock(&data->update_lock);				\
 	return count;							\
 }
 
@@ -242,7 +243,7 @@
 	/* Fill in remaining client fields and put it into the global list */
 	strlcpy(new_client->name, "ds1621", I2C_NAME_SIZE);
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -297,7 +298,7 @@
 	struct ds1621_data *data = i2c_get_clientdata(client);
 	u8 new_conf;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 	    || !data->valid) {
@@ -327,7 +328,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/f71805f.c newtree/drivers/hwmon/f71805f.c
--- oldtree/drivers/hwmon/f71805f.c	2006-02-19 11:41:02.156015336 +0000
+++ newtree/drivers/hwmon/f71805f.c	2006-02-21 15:58:14.232982816 +0000
@@ -30,6 +30,7 @@
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 
 static struct platform_device *pdev;
@@ -131,10 +132,10 @@
 struct f71805f_data {
 	unsigned short addr;
 	const char *name;
-	struct semaphore lock;
+	struct mutex lock;
 	struct class_device *class_dev;
 
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 	unsigned long last_limits;	/* In jiffies */
@@ -224,20 +225,20 @@
 {
 	u8 val;
 
-	down(&data->lock);
+	mutex_lock(&data->lock);
 	outb(reg, data->addr + ADDR_REG_OFFSET);
 	val = inb(data->addr + DATA_REG_OFFSET);
-	up(&data->lock);
+	mutex_unlock(&data->lock);
 
 	return val;
 }
 
 static void f71805f_write8(struct f71805f_data *data, u8 reg, u8 val)
 {
-	down(&data->lock);
+	mutex_lock(&data->lock);
 	outb(reg, data->addr + ADDR_REG_OFFSET);
 	outb(val, data->addr + DATA_REG_OFFSET);
-	up(&data->lock);
+	mutex_unlock(&data->lock);
 }
 
 /* It is important to read the MSB first, because doing so latches the
@@ -246,24 +247,24 @@
 {
 	u16 val;
 
-	down(&data->lock);
+	mutex_lock(&data->lock);
 	outb(reg, data->addr + ADDR_REG_OFFSET);
 	val = inb(data->addr + DATA_REG_OFFSET) << 8;
 	outb(++reg, data->addr + ADDR_REG_OFFSET);
 	val |= inb(data->addr + DATA_REG_OFFSET);
-	up(&data->lock);
+	mutex_unlock(&data->lock);
 
 	return val;
 }
 
 static void f71805f_write16(struct f71805f_data *data, u8 reg, u16 val)
 {
-	down(&data->lock);
+	mutex_lock(&data->lock);
 	outb(reg, data->addr + ADDR_REG_OFFSET);
 	outb(val >> 8, data->addr + DATA_REG_OFFSET);
 	outb(++reg, data->addr + ADDR_REG_OFFSET);
 	outb(val & 0xff, data->addr + DATA_REG_OFFSET);
-	up(&data->lock);
+	mutex_unlock(&data->lock);
 }
 
 static struct f71805f_data *f71805f_update_device(struct device *dev)
@@ -271,7 +272,7 @@
 	struct f71805f_data *data = dev_get_drvdata(dev);
 	int nr;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	/* Limit registers cache is refreshed after 60 seconds */
 	if (time_after(jiffies, data->last_updated + 60 * HZ)
@@ -323,7 +324,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
@@ -362,10 +363,10 @@
 	struct f71805f_data *data = dev_get_drvdata(dev);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_high[0] = in0_to_reg(val);
 	f71805f_write8(data, F71805F_REG_IN_HIGH(0), data->in_high[0]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return count;
 }
@@ -376,18 +377,14 @@
 	struct f71805f_data *data = dev_get_drvdata(dev);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_low[0] = in0_to_reg(val);
 	f71805f_write8(data, F71805F_REG_IN_LOW(0), data->in_low[0]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return count;
 }
 
-static DEVICE_ATTR(in0_input, S_IRUGO, show_in0, NULL);
-static DEVICE_ATTR(in0_max, S_IRUGO| S_IWUSR, show_in0_max, set_in0_max);
-static DEVICE_ATTR(in0_min, S_IRUGO| S_IWUSR, show_in0_min, set_in0_min);
-
 static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
 		       char *buf)
 {
@@ -426,10 +423,10 @@
 	int nr = attr->index;
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_high[nr] = in_to_reg(val);
 	f71805f_write8(data, F71805F_REG_IN_HIGH(nr), data->in_high[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return count;
 }
@@ -442,31 +439,14 @@
 	int nr = attr->index;
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_low[nr] = in_to_reg(val);
 	f71805f_write8(data, F71805F_REG_IN_LOW(nr), data->in_low[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return count;
 }
 
-#define sysfs_in(offset)					\
-static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,		\
-		show_in, NULL, offset);				\
-static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,	\
-		show_in_max, set_in_max, offset);		\
-static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,	\
-		show_in_min, set_in_min, offset)
-
-sysfs_in(1);
-sysfs_in(2);
-sysfs_in(3);
-sysfs_in(4);
-sysfs_in(5);
-sysfs_in(6);
-sysfs_in(7);
-sysfs_in(8);
-
 static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
 			char *buf)
 {
@@ -495,24 +475,14 @@
 	int nr = attr->index;
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->fan_low[nr] = fan_to_reg(val);
 	f71805f_write16(data, F71805F_REG_FAN_LOW(nr), data->fan_low[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return count;
 }
 
-#define sysfs_fan(offset)					\
-static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,		\
-		show_fan, NULL, offset - 1);			\
-static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,	\
-		show_fan_min, set_fan_min, offset - 1)
-
-sysfs_fan(1);
-sysfs_fan(2);
-sysfs_fan(3);
-
 static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
 			 char *buf)
 {
@@ -562,10 +532,10 @@
 	int nr = attr->index;
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_high[nr] = temp_to_reg(val);
 	f71805f_write8(data, F71805F_REG_TEMP_HIGH(nr), data->temp_high[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return count;
 }
@@ -578,28 +548,14 @@
 	int nr = attr->index;
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_hyst[nr] = temp_to_reg(val);
 	f71805f_write8(data, F71805F_REG_TEMP_HYST(nr), data->temp_hyst[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return count;
 }
 
-#define sysfs_temp(offset)						\
-static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO,		\
-		show_temp, NULL, offset - 1);				\
-static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,	\
-		show_temp_max, set_temp_max, offset - 1);		\
-static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR,	\
-		show_temp_hyst, set_temp_hyst, offset - 1);		\
-static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO,			\
-		show_temp_type, NULL, offset - 1)
-
-sysfs_temp(1);
-sysfs_temp(2);
-sysfs_temp(3);
-
 static ssize_t show_alarms_in(struct device *dev, struct device_attribute
 			      *devattr, char *buf)
 {
@@ -625,10 +581,6 @@
 	return sprintf(buf, "%d\n", (data->alarms[1] >> 3) & 0x07);
 }
 
-static DEVICE_ATTR(alarms_in, S_IRUGO, show_alarms_in, NULL);
-static DEVICE_ATTR(alarms_fan, S_IRUGO, show_alarms_fan, NULL);
-static DEVICE_ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL);
-
 static ssize_t show_name(struct device *dev, struct device_attribute
 			 *devattr, char *buf)
 {
@@ -637,7 +589,89 @@
 	return sprintf(buf, "%s\n", data->name);
 }
 
-static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+static struct device_attribute f71805f_dev_attr[] = {
+	__ATTR(in0_input, S_IRUGO, show_in0, NULL),
+	__ATTR(in0_max, S_IRUGO| S_IWUSR, show_in0_max, set_in0_max),
+	__ATTR(in0_min, S_IRUGO| S_IWUSR, show_in0_min, set_in0_min),
+	__ATTR(alarms_in, S_IRUGO, show_alarms_in, NULL),
+	__ATTR(alarms_fan, S_IRUGO, show_alarms_fan, NULL),
+	__ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL),
+	__ATTR(name, S_IRUGO, show_name, NULL),
+};
+
+static struct sensor_device_attribute f71805f_sensor_attr[] = {
+	SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
+	SENSOR_ATTR(in1_max, S_IRUGO | S_IWUSR,
+		    show_in_max, set_in_max, 1),
+	SENSOR_ATTR(in1_min, S_IRUGO | S_IWUSR,
+		    show_in_min, set_in_min, 1),
+	SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
+	SENSOR_ATTR(in2_max, S_IRUGO | S_IWUSR,
+		    show_in_max, set_in_max, 2),
+	SENSOR_ATTR(in2_min, S_IRUGO | S_IWUSR,
+		    show_in_min, set_in_min, 2),
+	SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
+	SENSOR_ATTR(in3_max, S_IRUGO | S_IWUSR,
+		    show_in_max, set_in_max, 3),
+	SENSOR_ATTR(in3_min, S_IRUGO | S_IWUSR,
+		    show_in_min, set_in_min, 3),
+	SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
+	SENSOR_ATTR(in4_max, S_IRUGO | S_IWUSR,
+		    show_in_max, set_in_max, 4),
+	SENSOR_ATTR(in4_min, S_IRUGO | S_IWUSR,
+		    show_in_min, set_in_min, 4),
+	SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
+	SENSOR_ATTR(in5_max, S_IRUGO | S_IWUSR,
+		    show_in_max, set_in_max, 5),
+	SENSOR_ATTR(in5_min, S_IRUGO | S_IWUSR,
+		    show_in_min, set_in_min, 5),
+	SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
+	SENSOR_ATTR(in6_max, S_IRUGO | S_IWUSR,
+		    show_in_max, set_in_max, 6),
+	SENSOR_ATTR(in6_min, S_IRUGO | S_IWUSR,
+		    show_in_min, set_in_min, 6),
+	SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
+	SENSOR_ATTR(in7_max, S_IRUGO | S_IWUSR,
+		    show_in_max, set_in_max, 7),
+	SENSOR_ATTR(in7_min, S_IRUGO | S_IWUSR,
+		    show_in_min, set_in_min, 7),
+	SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
+	SENSOR_ATTR(in8_max, S_IRUGO | S_IWUSR,
+		    show_in_max, set_in_max, 8),
+	SENSOR_ATTR(in8_min, S_IRUGO | S_IWUSR,
+		    show_in_min, set_in_min, 8),
+
+	SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
+	SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR,
+		    show_temp_max, set_temp_max, 0),
+	SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
+		    show_temp_hyst, set_temp_hyst, 0),
+	SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
+	SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
+	SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR,
+		    show_temp_max, set_temp_max, 1),
+	SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR,
+		    show_temp_hyst, set_temp_hyst, 1),
+	SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
+	SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
+	SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR,
+		    show_temp_max, set_temp_max, 2),
+	SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR,
+		    show_temp_hyst, set_temp_hyst, 2),
+	SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
+};
+
+static struct sensor_device_attribute f71805f_fan_attr[] = {
+	SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
+	SENSOR_ATTR(fan1_min, S_IRUGO | S_IWUSR,
+		    show_fan_min, set_fan_min, 0),
+	SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
+	SENSOR_ATTR(fan2_min, S_IRUGO | S_IWUSR,
+		    show_fan_min, set_fan_min, 1),
+	SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
+	SENSOR_ATTR(fan3_min, S_IRUGO | S_IWUSR,
+		    show_fan_min, set_fan_min, 2),
+};
 
 /*
  * Device registration and initialization
@@ -668,7 +702,7 @@
 {
 	struct f71805f_data *data;
 	struct resource *res;
-	int err;
+	int i, err;
 
 	if (!(data = kzalloc(sizeof(struct f71805f_data), GFP_KERNEL))) {
 		err = -ENOMEM;
@@ -678,9 +712,9 @@
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
 	data->addr = res->start;
-	init_MUTEX(&data->lock);
+	mutex_init(&data->lock);
 	data->name = "f71805f";
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	platform_set_drvdata(pdev, data);
 
@@ -695,76 +729,31 @@
 	f71805f_init_device(data);
 
 	/* Register sysfs interface files */
-	device_create_file(&pdev->dev, &dev_attr_in0_input);
-	device_create_file(&pdev->dev, &dev_attr_in0_max);
-	device_create_file(&pdev->dev, &dev_attr_in0_min);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in1_input.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in2_input.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in3_input.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in4_input.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in5_input.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in6_input.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in7_input.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in8_input.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in1_max.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in2_max.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in3_max.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in4_max.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in5_max.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in6_max.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in7_max.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in8_max.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in1_min.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in2_min.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in3_min.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in4_min.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in5_min.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in6_min.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in7_min.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_in8_min.dev_attr);
-	if (data->fan_enabled & (1 << 0)) {
-		device_create_file(&pdev->dev,
-				   &sensor_dev_attr_fan1_input.dev_attr);
-		device_create_file(&pdev->dev,
-				   &sensor_dev_attr_fan1_min.dev_attr);
-	}
-	if (data->fan_enabled & (1 << 1)) {
-		device_create_file(&pdev->dev,
-				   &sensor_dev_attr_fan2_input.dev_attr);
-		device_create_file(&pdev->dev,
-				   &sensor_dev_attr_fan2_min.dev_attr);
-	}
-	if (data->fan_enabled & (1 << 2)) {
-		device_create_file(&pdev->dev,
-				   &sensor_dev_attr_fan3_input.dev_attr);
-		device_create_file(&pdev->dev,
-				   &sensor_dev_attr_fan3_min.dev_attr);
-	}
-	device_create_file(&pdev->dev,
-			   &sensor_dev_attr_temp1_input.dev_attr);
-	device_create_file(&pdev->dev,
-			   &sensor_dev_attr_temp2_input.dev_attr);
-	device_create_file(&pdev->dev,
-			   &sensor_dev_attr_temp3_input.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_temp2_max.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_temp3_max.dev_attr);
-	device_create_file(&pdev->dev,
-			   &sensor_dev_attr_temp1_max_hyst.dev_attr);
-	device_create_file(&pdev->dev,
-			   &sensor_dev_attr_temp2_max_hyst.dev_attr);
-	device_create_file(&pdev->dev,
-			   &sensor_dev_attr_temp3_max_hyst.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_temp1_type.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_temp2_type.dev_attr);
-	device_create_file(&pdev->dev, &sensor_dev_attr_temp3_type.dev_attr);
-	device_create_file(&pdev->dev, &dev_attr_alarms_in);
-	device_create_file(&pdev->dev, &dev_attr_alarms_fan);
-	device_create_file(&pdev->dev, &dev_attr_alarms_temp);
-	device_create_file(&pdev->dev, &dev_attr_name);
+	for (i = 0; i < ARRAY_SIZE(f71805f_dev_attr); i++) {
+		err = device_create_file(&pdev->dev, &f71805f_dev_attr[i]);
+		if (err)
+			goto exit_class;
+	}
+	for (i = 0; i < ARRAY_SIZE(f71805f_sensor_attr); i++) {
+		err = device_create_file(&pdev->dev,
+					 &f71805f_sensor_attr[i].dev_attr);
+		if (err)
+			goto exit_class;
+	}
+	for (i = 0; i < ARRAY_SIZE(f71805f_fan_attr); i++) {
+		if (!(data->fan_enabled & (1 << (i / 2))))
+			continue;
+		err = device_create_file(&pdev->dev,
+					 &f71805f_fan_attr[i].dev_attr);
+		if (err)
+			goto exit_class;
+	}
 
 	return 0;
 
+exit_class:
+	dev_err(&pdev->dev, "Sysfs interface creation failed\n");
+	hwmon_device_unregister(data->class_dev);
 exit_free:
 	kfree(data);
 exit:
diff -urN oldtree/drivers/hwmon/fscher.c newtree/drivers/hwmon/fscher.c
--- oldtree/drivers/hwmon/fscher.c	2006-02-19 11:41:02.157015184 +0000
+++ newtree/drivers/hwmon/fscher.c	2006-02-21 15:58:14.190989200 +0000
@@ -33,6 +33,7 @@
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 /*
  * Addresses to scan
@@ -133,7 +134,7 @@
 struct fscher_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid; /* zero until following fields are valid */
 	unsigned long last_updated; /* in jiffies */
 
@@ -332,7 +333,7 @@
 	 * global list */
 	strlcpy(new_client->name, "fscher", I2C_NAME_SIZE);
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -417,7 +418,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct fscher_data *data = i2c_get_clientdata(client);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
 
@@ -457,7 +458,7 @@
 		data->valid = 1;                 
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
@@ -472,10 +473,10 @@
 	/* bits 0..1, 3..7 reserved => mask with 0x04 */  
 	unsigned long v = simple_strtoul(buf, NULL, 10) & 0x04;
 	
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->fan_status[FAN_INDEX_FROM_NUM(nr)] &= ~v;
 	fscher_write_value(client, reg, v);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -490,10 +491,10 @@
 {
 	unsigned long v = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->fan_min[FAN_INDEX_FROM_NUM(nr)] = v > 0xff ? 0xff : v;
 	fscher_write_value(client, reg, data->fan_min[FAN_INDEX_FROM_NUM(nr)]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -518,14 +519,14 @@
 		return -EINVAL;
 	}
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	/* bits 2..7 reserved => mask with 0x03 */
 	data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] &= ~0x03;
 	data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] |= v;
 
 	fscher_write_value(client, reg, data->fan_ripple[FAN_INDEX_FROM_NUM(nr)]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -552,10 +553,10 @@
 	/* bits 2..7 reserved, 0 read only => mask with 0x02 */  
 	unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_status[TEMP_INDEX_FROM_NUM(nr)] &= ~v;
 	fscher_write_value(client, reg, v);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -609,10 +610,10 @@
 	/* bits 1..7 reserved => mask with 0x01 */  
 	unsigned long v = simple_strtoul(buf, NULL, 10) & 0x01;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->global_control &= ~v;
 	fscher_write_value(client, reg, v);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -631,11 +632,11 @@
 	/* bits 0..3 reserved => mask with 0xf0 */  
 	unsigned long v = simple_strtoul(buf, NULL, 10) & 0xf0;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->watchdog[2] &= ~0xf0;
 	data->watchdog[2] |= v;
 	fscher_write_value(client, reg, data->watchdog[2]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -651,10 +652,10 @@
 	/* bits 0, 2..7 reserved => mask with 0x02 */  
 	unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->watchdog[1] &= ~v;
 	fscher_write_value(client, reg, v);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -669,10 +670,10 @@
 {
 	unsigned long v = simple_strtoul(buf, NULL, 10) & 0xff;
 	
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->watchdog[0] = v;
 	fscher_write_value(client, reg, data->watchdog[0]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
diff -urN oldtree/drivers/hwmon/fscpos.c newtree/drivers/hwmon/fscpos.c
--- oldtree/drivers/hwmon/fscpos.c	2006-02-19 11:41:02.158015032 +0000
+++ newtree/drivers/hwmon/fscpos.c	2006-02-21 15:58:14.191989048 +0000
@@ -37,6 +37,7 @@
 #include <linux/init.h>
 #include <linux/hwmon.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 /*
  * Addresses to scan
@@ -114,7 +115,7 @@
 struct fscpos_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid; 		/* 0 until following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 
@@ -208,13 +209,13 @@
 		return -EINVAL;
 	}
 	
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	/* bits 2..7 reserved => mask with 0x03 */
 	data->fan_ripple[nr - 1] &= ~0x03;
 	data->fan_ripple[nr - 1] |= v;
 	
 	fscpos_write_value(client, reg, data->fan_ripple[nr - 1]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -232,10 +233,10 @@
 	if (v < 0) v = 0;
 	if (v > 255) v = 255;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->pwm[nr - 1] = v;
 	fscpos_write_value(client, reg, data->pwm[nr - 1]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -278,11 +279,11 @@
 	/* bits 0..3 reserved => mask with 0xf0 */
 	unsigned long v = simple_strtoul(buf, NULL, 10) & 0xf0;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->wdog_control &= ~0xf0;
 	data->wdog_control |= v;
 	fscpos_write_value(client, reg, data->wdog_control);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -304,10 +305,10 @@
 		return -EINVAL;
 	}
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->wdog_state &= ~v;
 	fscpos_write_value(client, reg, v);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -321,10 +322,10 @@
 {
 	unsigned long v = simple_strtoul(buf, NULL, 10) & 0xff;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->wdog_preset = v;
 	fscpos_write_value(client, reg, data->wdog_preset);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -483,7 +484,7 @@
 	strlcpy(new_client->name, "fscpos", I2C_NAME_SIZE);
 
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -579,7 +580,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct fscpos_data *data = i2c_get_clientdata(client);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
 		int i;
@@ -625,7 +626,7 @@
 		data->last_updated = jiffies;
 		data->valid = 1;
 	}
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return data;
 }
 
diff -urN oldtree/drivers/hwmon/gl518sm.c newtree/drivers/hwmon/gl518sm.c
--- oldtree/drivers/hwmon/gl518sm.c	2006-02-19 11:41:02.158015032 +0000
+++ newtree/drivers/hwmon/gl518sm.c	2006-02-21 15:58:14.192988896 +0000
@@ -43,6 +43,7 @@
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
@@ -120,7 +121,7 @@
 	struct class_device *class_dev;
 	enum chips type;
 
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 
@@ -212,10 +213,10 @@
 	struct gl518_data *data = i2c_get_clientdata(client);		\
 	long val = simple_strtol(buf, NULL, 10);			\
 									\
-	down(&data->update_lock);					\
+	mutex_lock(&data->update_lock);					\
 	data->value = type##_TO_REG(val);				\
 	gl518_write_value(client, reg, data->value);			\
-	up(&data->update_lock);						\
+	mutex_unlock(&data->update_lock);				\
 	return count;							\
 }
 
@@ -228,12 +229,12 @@
 	int regvalue;							\
 	unsigned long val = simple_strtoul(buf, NULL, 10);		\
 									\
-	down(&data->update_lock);					\
+	mutex_lock(&data->update_lock);					\
 	regvalue = gl518_read_value(client, reg);			\
 	data->value = type##_TO_REG(val);				\
 	regvalue = (regvalue & ~mask) | (data->value << shift);		\
 	gl518_write_value(client, reg, regvalue);			\
-	up(&data->update_lock);						\
+	mutex_unlock(&data->update_lock);				\
 	return count;							\
 }
 
@@ -265,7 +266,7 @@
 	int regvalue;
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT);
 	data->fan_min[0] = FAN_TO_REG(val,
 		DIV_FROM_REG(data->fan_div[0]));
@@ -280,7 +281,7 @@
 	data->beep_mask &= data->alarm_mask;
 	gl518_write_value(client, GL518_REG_ALARM, data->beep_mask);
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -291,7 +292,7 @@
 	int regvalue;
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT);
 	data->fan_min[1] = FAN_TO_REG(val,
 		DIV_FROM_REG(data->fan_div[1]));
@@ -306,7 +307,7 @@
 	data->beep_mask &= data->alarm_mask;
 	gl518_write_value(client, GL518_REG_ALARM, data->beep_mask);
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -407,7 +408,7 @@
 	strlcpy(new_client->name, "gl518sm", I2C_NAME_SIZE);
 	data->type = kind;
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -525,7 +526,7 @@
 	struct gl518_data *data = i2c_get_clientdata(client);
 	int val;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 	    || !data->valid) {
@@ -586,7 +587,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/gl520sm.c newtree/drivers/hwmon/gl520sm.c
--- oldtree/drivers/hwmon/gl520sm.c	2006-02-19 11:41:02.159014880 +0000
+++ newtree/drivers/hwmon/gl520sm.c	2006-02-21 15:58:14.193988744 +0000
@@ -29,6 +29,7 @@
 #include <linux/hwmon.h>
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 /* Type of the extra sensor */
 static unsigned short extra_sensor_type;
@@ -121,7 +122,7 @@
 struct gl520_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid;		/* zero until the following fields are valid */
 	unsigned long last_updated;	/* in jiffies */
 
@@ -303,7 +304,7 @@
 	long v = simple_strtol(buf, NULL, 10);
 	u8 r;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (n == 0)
 		r = VDD_TO_REG(v);
@@ -317,7 +318,7 @@
 	else
 		gl520_write_value(client, reg, r);
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -331,7 +332,7 @@
 	else
 		r = IN_TO_REG(v);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	data->in_max[n] = r;
 
@@ -340,7 +341,7 @@
 	else
 		gl520_write_value(client, reg, r);
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -373,7 +374,7 @@
 	unsigned long v = simple_strtoul(buf, NULL, 10);
 	u8 r;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	r = FAN_TO_REG(v, data->fan_div[n - 1]);
 	data->fan_min[n - 1] = r;
 
@@ -390,7 +391,7 @@
 	data->beep_mask &= data->alarm_mask;
 	gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -409,7 +410,7 @@
 		return -EINVAL;
 	}
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->fan_div[n - 1] = r;
 
 	if (n == 1)
@@ -417,7 +418,7 @@
 	else
 		gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x30) | (r << 4));
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -425,10 +426,10 @@
 {
 	u8 r = simple_strtoul(buf, NULL, 10)?1:0;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->fan_off = r;
 	gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x0c) | (r << 2));
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -454,10 +455,10 @@
 {
 	long v = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_max[n - 1] = TEMP_TO_REG(v);;
 	gl520_write_value(client, reg, data->temp_max[n - 1]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -465,10 +466,10 @@
 {
 	long v = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_max_hyst[n - 1] = TEMP_TO_REG(v);
 	gl520_write_value(client, reg, data->temp_max_hyst[n - 1]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -491,10 +492,10 @@
 {
 	u8 r = simple_strtoul(buf, NULL, 10)?0:1;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->beep_enable = !r;
 	gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x04) | (r << 2));
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -502,11 +503,11 @@
 {
 	u8 r = simple_strtoul(buf, NULL, 10);
 	
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	r &= data->alarm_mask;
 	data->beep_mask = r;
 	gl520_write_value(client, reg, r);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -561,7 +562,7 @@
 	/* Fill in the remaining client fields */
 	strlcpy(new_client->name, "gl520sm", I2C_NAME_SIZE);
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -685,7 +686,7 @@
 	struct gl520_data *data = i2c_get_clientdata(client);
 	int val;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
 
@@ -750,7 +751,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/hdaps.c newtree/drivers/hwmon/hdaps.c
--- oldtree/drivers/hwmon/hdaps.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/hwmon/hdaps.c	2006-02-21 15:58:14.194988592 +0000
@@ -33,6 +33,7 @@
 #include <linux/module.h>
 #include <linux/timer.h>
 #include <linux/dmi.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 
 #define HDAPS_LOW_PORT		0x1600	/* first port used by hdaps */
@@ -70,10 +71,10 @@
 static int rest_x;
 static int rest_y;
 
-static DECLARE_MUTEX(hdaps_sem);
+static DEFINE_MUTEX(hdaps_mutex);
 
 /*
- * __get_latch - Get the value from a given port.  Callers must hold hdaps_sem.
+ * __get_latch - Get the value from a given port.  Callers must hold hdaps_mutex.
  */
 static inline u8 __get_latch(u16 port)
 {
@@ -82,7 +83,7 @@
 
 /*
  * __check_latch - Check a port latch for a given value.  Returns zero if the
- * port contains the given value.  Callers must hold hdaps_sem.
+ * port contains the given value.  Callers must hold hdaps_mutex.
  */
 static inline int __check_latch(u16 port, u8 val)
 {
@@ -93,7 +94,7 @@
 
 /*
  * __wait_latch - Wait up to 100us for a port latch to get a certain value,
- * returning zero if the value is obtained.  Callers must hold hdaps_sem.
+ * returning zero if the value is obtained.  Callers must hold hdaps_mutex.
  */
 static int __wait_latch(u16 port, u8 val)
 {
@@ -110,7 +111,7 @@
 
 /*
  * __device_refresh - request a refresh from the accelerometer.  Does not wait
- * for refresh to complete.  Callers must hold hdaps_sem.
+ * for refresh to complete.  Callers must hold hdaps_mutex.
  */
 static void __device_refresh(void)
 {
@@ -124,7 +125,7 @@
 /*
  * __device_refresh_sync - request a synchronous refresh from the
  * accelerometer.  We wait for the refresh to complete.  Returns zero if
- * successful and nonzero on error.  Callers must hold hdaps_sem.
+ * successful and nonzero on error.  Callers must hold hdaps_mutex.
  */
 static int __device_refresh_sync(void)
 {
@@ -134,7 +135,7 @@
 
 /*
  * __device_complete - indicate to the accelerometer that we are done reading
- * data, and then initiate an async refresh.  Callers must hold hdaps_sem.
+ * data, and then initiate an async refresh.  Callers must hold hdaps_mutex.
  */
 static inline void __device_complete(void)
 {
@@ -152,7 +153,7 @@
 {
 	int ret;
 
-	down(&hdaps_sem);
+	mutex_lock(&hdaps_mutex);
 
 	/* do a sync refresh -- we need to be sure that we read fresh data */
 	ret = __device_refresh_sync();
@@ -163,7 +164,7 @@
 	__device_complete();
 
 out:
-	up(&hdaps_sem);
+	mutex_unlock(&hdaps_mutex);
 	return ret;
 }
 
@@ -198,9 +199,9 @@
 {
 	int ret;
 
-	down(&hdaps_sem);
+	mutex_lock(&hdaps_mutex);
 	ret = __hdaps_read_pair(port1, port2, val1, val2);
-	up(&hdaps_sem);
+	mutex_unlock(&hdaps_mutex);
 
 	return ret;
 }
@@ -213,7 +214,7 @@
 {
 	int total, ret = -ENXIO;
 
-	down(&hdaps_sem);
+	mutex_lock(&hdaps_mutex);
 
 	outb(0x13, 0x1610);
 	outb(0x01, 0x161f);
@@ -279,7 +280,7 @@
 	}
 
 out:
-	up(&hdaps_sem);
+	mutex_unlock(&hdaps_mutex);
 	return ret;
 }
 
@@ -313,7 +314,7 @@
 };
 
 /*
- * hdaps_calibrate - Set our "resting" values.  Callers must hold hdaps_sem.
+ * hdaps_calibrate - Set our "resting" values.  Callers must hold hdaps_mutex.
  */
 static void hdaps_calibrate(void)
 {
@@ -325,7 +326,7 @@
 	int x, y;
 
 	/* Cannot sleep.  Try nonblockingly.  If we fail, try again later. */
-	if (down_trylock(&hdaps_sem)) {
+	if (!mutex_trylock(&hdaps_mutex)) {
 		mod_timer(&hdaps_timer,jiffies + HDAPS_POLL_PERIOD);
 		return;
 	}
@@ -340,7 +341,7 @@
 	mod_timer(&hdaps_timer, jiffies + HDAPS_POLL_PERIOD);
 
 out:
-	up(&hdaps_sem);
+	mutex_unlock(&hdaps_mutex);
 }
 
 
@@ -420,9 +421,9 @@
 				     struct device_attribute *attr,
 				     const char *buf, size_t count)
 {
-	down(&hdaps_sem);
+	mutex_lock(&hdaps_mutex);
 	hdaps_calibrate();
-	up(&hdaps_sem);
+	mutex_unlock(&hdaps_mutex);
 
 	return count;
 }
diff -urN oldtree/drivers/hwmon/hwmon-vid.c newtree/drivers/hwmon/hwmon-vid.c
--- oldtree/drivers/hwmon/hwmon-vid.c	2006-02-19 11:41:02.160014728 +0000
+++ newtree/drivers/hwmon/hwmon-vid.c	2006-02-21 15:58:14.383959864 +0000
@@ -54,6 +54,10 @@
     (IMVP-II). You can find more information in the datasheet of Max1718
     http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2452
 
+    The 13 specification corresponds to the Intel Pentium M series. There
+    doesn't seem to be any named specification for these. The conversion
+    tables are detailed directly in the various Pentium M datasheets:
+    http://www.intel.com/design/intarch/pentiumm/docs_pentiumm.htm
 */
 
 /* vrm is the VRM/VRD document version multiplied by 10.
@@ -100,6 +104,8 @@
 	case 17:		/* Intel IMVP-II */
 		return(val & 0x10 ? 975 - (val & 0xF) * 25 :
 				    1750 - val * 50);
+	case 13:
+		return(1708 - (val & 0x3f) * 16);
 	default:		/* report 0 for unknown */
 		printk(KERN_INFO "hwmon-vid: requested unknown VRM version\n");
 		return 0;
@@ -129,8 +135,9 @@
 static struct vrm_model vrm_models[] = {
 	{X86_VENDOR_AMD, 0x6, ANY, ANY, 90},		/* Athlon Duron etc */
 	{X86_VENDOR_AMD, 0xF, ANY, ANY, 24},		/* Athlon 64, Opteron and above VRM 24 */
-	{X86_VENDOR_INTEL, 0x6, 0x9, ANY, 85},		/* 0.13um too */
+	{X86_VENDOR_INTEL, 0x6, 0x9, ANY, 13},		/* Pentium M (130 nm) */
 	{X86_VENDOR_INTEL, 0x6, 0xB, ANY, 85},		/* Tualatin */
+	{X86_VENDOR_INTEL, 0x6, 0xD, ANY, 13},		/* Pentium M (90 nm) */
 	{X86_VENDOR_INTEL, 0x6, ANY, ANY, 82},		/* any P6 */
 	{X86_VENDOR_INTEL, 0x7, ANY, ANY, 0},		/* Itanium */
 	{X86_VENDOR_INTEL, 0xF, 0x0, ANY, 90},		/* P4 */
diff -urN oldtree/drivers/hwmon/it87.c newtree/drivers/hwmon/it87.c
--- oldtree/drivers/hwmon/it87.c	2006-02-19 11:41:02.160014728 +0000
+++ newtree/drivers/hwmon/it87.c	2006-02-21 15:58:14.197988136 +0000
@@ -41,6 +41,7 @@
 #include <linux/hwmon-sysfs.h>
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 
 
@@ -194,10 +195,10 @@
 struct it87_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore lock;
+	struct mutex lock;
 	enum chips type;
 
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 
@@ -290,11 +291,11 @@
 	struct it87_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_min[nr] = IN_TO_REG(val);
 	it87_write_value(client, IT87_REG_VIN_MIN(nr), 
 			data->in_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
@@ -307,11 +308,11 @@
 	struct it87_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_max[nr] = IN_TO_REG(val);
 	it87_write_value(client, IT87_REG_VIN_MAX(nr), 
 			data->in_max[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -381,10 +382,10 @@
 	struct it87_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_high[nr] = TEMP_TO_REG(val);
 	it87_write_value(client, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
@@ -397,10 +398,10 @@
 	struct it87_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_low[nr] = TEMP_TO_REG(val);
 	it87_write_value(client, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 #define show_temp_offset(offset)					\
@@ -440,7 +441,7 @@
 	struct it87_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	data->sensor &= ~(1 << nr);
 	data->sensor &= ~(8 << nr);
@@ -450,11 +451,11 @@
 	else if (val == 2)
 	    data->sensor |= 8 << nr;
 	else if (val != 0) {
-		up(&data->update_lock);
+		mutex_unlock(&data->update_lock);
 		return -EINVAL;
 	}
 	it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 #define show_sensor_offset(offset)					\
@@ -524,7 +525,7 @@
 	int val = simple_strtol(buf, NULL, 10);
 	u8 reg = it87_read_value(client, IT87_REG_FAN_DIV);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	switch (nr) {
 	case 0: data->fan_div[nr] = reg & 0x07; break;
 	case 1: data->fan_div[nr] = (reg >> 3) & 0x07; break;
@@ -533,7 +534,7 @@
 
 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
 	it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
@@ -548,7 +549,7 @@
 	int i, min[3];
 	u8 old;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	old = it87_read_value(client, IT87_REG_FAN_DIV);
 
 	for (i = 0; i < 3; i++)
@@ -576,7 +577,7 @@
 		data->fan_min[i]=FAN_TO_REG(min[i], DIV_FROM_REG(data->fan_div[i]));
 		it87_write_value(client, IT87_REG_FAN_MIN(i), data->fan_min[i]);
 	}
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t set_pwm_enable(struct device *dev,
@@ -589,7 +590,7 @@
 	struct it87_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (val == 0) {
 		int tmp;
@@ -606,11 +607,11 @@
 		/* set saved pwm value, clear FAN_CTLX PWM mode bit */
 		it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
 	} else {
-		up(&data->update_lock);
+		mutex_unlock(&data->update_lock);
 		return -EINVAL;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
@@ -626,11 +627,11 @@
 	if (val < 0 || val > 255)
 		return -EINVAL;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->manual_pwm_ctl[nr] = val;
 	if (data->fan_main_ctrl & (1 << nr))
 		it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -776,7 +777,7 @@
 
 	new_client = &data->client;
 	if (is_isa)
-		init_MUTEX(&data->lock);
+		mutex_init(&data->lock);
 	i2c_set_clientdata(new_client, data);
 	new_client->addr = address;
 	new_client->adapter = adapter;
@@ -823,7 +824,7 @@
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
 	data->type = kind;
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -950,10 +951,10 @@
 
 	int res;
 	if (i2c_is_isa_client(client)) {
-		down(&data->lock);
+		mutex_lock(&data->lock);
 		outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
 		res = inb_p(client->addr + IT87_DATA_REG_OFFSET);
-		up(&data->lock);
+		mutex_unlock(&data->lock);
 		return res;
 	} else
 		return i2c_smbus_read_byte_data(client, reg);
@@ -969,10 +970,10 @@
 	struct it87_data *data = i2c_get_clientdata(client);
 
 	if (i2c_is_isa_client(client)) {
-		down(&data->lock);
+		mutex_lock(&data->lock);
 		outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
 		outb_p(value, client->addr + IT87_DATA_REG_OFFSET);
-		up(&data->lock);
+		mutex_unlock(&data->lock);
 		return 0;
 	} else
 		return i2c_smbus_write_byte_data(client, reg, value);
@@ -1098,7 +1099,7 @@
 	struct it87_data *data = i2c_get_clientdata(client);
 	int i;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 	    || !data->valid) {
@@ -1160,7 +1161,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/lm63.c newtree/drivers/hwmon/lm63.c
--- oldtree/drivers/hwmon/lm63.c	2006-02-19 11:41:02.161014576 +0000
+++ newtree/drivers/hwmon/lm63.c	2006-02-21 15:58:14.198987984 +0000
@@ -45,6 +45,7 @@
 #include <linux/hwmon-sysfs.h>
 #include <linux/hwmon.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 /*
  * Addresses to scan
@@ -153,7 +154,7 @@
 struct lm63_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid; /* zero until following fields are valid */
 	unsigned long last_updated; /* in jiffies */
 
@@ -192,13 +193,13 @@
 	struct lm63_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->fan[1] = FAN_TO_REG(val);
 	i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB,
 				  data->fan[1] & 0xFF);
 	i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB,
 				  data->fan[1] >> 8);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -222,12 +223,12 @@
 		return -EPERM;
 
 	val = simple_strtoul(buf, NULL, 10);
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->pwm1_value = val <= 0 ? 0 :
 			   val >= 255 ? 2 * data->pwm1_freq :
 			   (val * data->pwm1_freq * 2 + 127) / 255;
 	i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1_value);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -253,10 +254,10 @@
 	struct lm63_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp8[1] = TEMP8_TO_REG(val);
 	i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -284,13 +285,13 @@
 	long val = simple_strtol(buf, NULL, 10);
 	int nr = attr->index;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp11[nr] = TEMP11_TO_REG(val);
 	i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
 				  data->temp11[nr] >> 8);
 	i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
 				  data->temp11[nr] & 0xff);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -314,11 +315,11 @@
 	long val = simple_strtol(buf, NULL, 10);
 	long hyst;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	hyst = TEMP8_FROM_REG(data->temp8[2]) - val;
 	i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST,
 				  HYST_TO_REG(hyst));
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -427,7 +428,7 @@
 
 	strlcpy(new_client->name, "lm63", I2C_NAME_SIZE);
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -530,7 +531,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm63_data *data = i2c_get_clientdata(client);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
 		if (data->config & 0x04) { /* tachometer enabled  */
@@ -582,7 +583,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/lm75.c newtree/drivers/hwmon/lm75.c
--- oldtree/drivers/hwmon/lm75.c	2006-02-19 11:41:02.162014424 +0000
+++ newtree/drivers/hwmon/lm75.c	2006-02-21 15:58:14.792897696 +0000
@@ -25,6 +25,7 @@
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 #include "lm75.h"
 
 
@@ -32,6 +33,19 @@
 static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
 					0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
 
+static struct i2c_device_id id[] = {
+	{ 0x48 },
+	{ 0x49 },
+	{ 0x4a },
+	{ 0x4b },
+	{ 0x4c },
+	{ 0x4d },
+	{ 0x4e },
+	{ 0x4f },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, id);
+
 /* Insmod parameters */
 I2C_CLIENT_INSMOD_1(lm75);
 
@@ -47,7 +61,7 @@
 struct lm75_data {
 	struct i2c_client	client;
 	struct class_device *class_dev;
-	struct semaphore	update_lock;
+	struct mutex		update_lock;
 	char			valid;		/* !=0 if following fields are valid */
 	unsigned long		last_updated;	/* In jiffies */
 	u16			temp_input;	/* Register values */
@@ -91,10 +105,10 @@
 	struct lm75_data *data = i2c_get_clientdata(client);	\
 	int temp = simple_strtoul(buf, NULL, 10);		\
 								\
-	down(&data->update_lock);				\
+	mutex_lock(&data->update_lock);				\
 	data->value = LM75_TEMP_TO_REG(temp);			\
 	lm75_write_value(client, reg, data->value);		\
-	up(&data->update_lock);					\
+	mutex_unlock(&data->update_lock);					\
 	return count;						\
 }
 set(temp_max, LM75_REG_TEMP_OS);
@@ -188,7 +202,7 @@
 	/* Fill in the remaining client fields and put it into the global list */
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -264,7 +278,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm75_data *data = i2c_get_clientdata(client);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 	    || !data->valid) {
@@ -277,7 +291,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/lm77.c newtree/drivers/hwmon/lm77.c
--- oldtree/drivers/hwmon/lm77.c	2006-02-19 11:41:02.162014424 +0000
+++ newtree/drivers/hwmon/lm77.c	2006-02-21 15:58:14.199987832 +0000
@@ -32,6 +32,7 @@
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, I2C_CLIENT_END };
@@ -51,7 +52,7 @@
 struct lm77_data {
 	struct i2c_client	client;
 	struct class_device *class_dev;
-	struct semaphore	update_lock;
+	struct mutex		update_lock;
 	char			valid;
 	unsigned long		last_updated;	/* In jiffies */
 	int			temp_input;	/* Temperatures */
@@ -139,10 +140,10 @@
 	struct lm77_data *data = i2c_get_clientdata(client);			\
 	long val = simple_strtoul(buf, NULL, 10);				\
 										\
-	down(&data->update_lock);						\
+	mutex_lock(&data->update_lock);						\
 	data->value = val;				\
 	lm77_write_value(client, reg, LM77_TEMP_TO_REG(data->value));		\
-	up(&data->update_lock);							\
+	mutex_unlock(&data->update_lock);					\
 	return count;								\
 }
 
@@ -157,11 +158,11 @@
 	struct lm77_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_hyst = data->temp_crit - val;
 	lm77_write_value(client, LM77_REG_TEMP_HYST,
 			 LM77_TEMP_TO_REG(data->temp_hyst));
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -173,7 +174,7 @@
 	long val = simple_strtoul(buf, NULL, 10);
 	int oldcrithyst;
 	
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	oldcrithyst = data->temp_crit - data->temp_hyst;
 	data->temp_crit = val;
 	data->temp_hyst = data->temp_crit - oldcrithyst;
@@ -181,7 +182,7 @@
 			 LM77_TEMP_TO_REG(data->temp_crit));
 	lm77_write_value(client, LM77_REG_TEMP_HYST,
 			 LM77_TEMP_TO_REG(data->temp_hyst));
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -306,7 +307,7 @@
 	/* Fill in the remaining client fields and put it into the global list */
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -380,7 +381,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm77_data *data = i2c_get_clientdata(client);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 	    || !data->valid) {
@@ -406,7 +407,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/lm78.c newtree/drivers/hwmon/lm78.c
--- oldtree/drivers/hwmon/lm78.c	2006-02-19 11:41:02.163014272 +0000
+++ newtree/drivers/hwmon/lm78.c	2006-02-21 15:58:14.200987680 +0000
@@ -27,6 +27,7 @@
 #include <linux/hwmon.h>
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 
 /* Addresses to scan */
@@ -131,10 +132,10 @@
 struct lm78_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore lock;
+	struct mutex lock;
 	enum chips type;
 
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 
@@ -207,10 +208,10 @@
 	struct lm78_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_min[nr] = IN_TO_REG(val);
 	lm78_write_value(client, LM78_REG_IN_MIN(nr), data->in_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -221,10 +222,10 @@
 	struct lm78_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_max[nr] = IN_TO_REG(val);
 	lm78_write_value(client, LM78_REG_IN_MAX(nr), data->in_max[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 	
@@ -288,10 +289,10 @@
 	struct lm78_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_over = TEMP_TO_REG(val);
 	lm78_write_value(client, LM78_REG_TEMP_OVER, data->temp_over);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -307,10 +308,10 @@
 	struct lm78_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_hyst = TEMP_TO_REG(val);
 	lm78_write_value(client, LM78_REG_TEMP_HYST, data->temp_hyst);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -342,10 +343,10 @@
 	struct lm78_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
 	lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -368,7 +369,7 @@
 	unsigned long min;
 	u8 reg;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	min = FAN_FROM_REG(data->fan_min[nr],
 			   DIV_FROM_REG(data->fan_div[nr]));
 
@@ -380,7 +381,7 @@
 	default:
 		dev_err(&client->dev, "fan_div value %ld not "
 			"supported. Choose one of 1, 2, 4 or 8!\n", val);
-		up(&data->update_lock);
+		mutex_unlock(&data->update_lock);
 		return -EINVAL;
 	}
 
@@ -398,7 +399,7 @@
 	data->fan_min[nr] =
 		FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
 	lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return count;
 }
@@ -548,7 +549,7 @@
 
 	new_client = &data->client;
 	if (is_isa)
-		init_MUTEX(&data->lock);
+		mutex_init(&data->lock);
 	i2c_set_clientdata(new_client, data);
 	new_client->addr = address;
 	new_client->adapter = adapter;
@@ -598,7 +599,7 @@
 	data->type = kind;
 
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -697,10 +698,10 @@
 	int res;
 	if (i2c_is_isa_client(client)) {
 		struct lm78_data *data = i2c_get_clientdata(client);
-		down(&data->lock);
+		mutex_lock(&data->lock);
 		outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET);
 		res = inb_p(client->addr + LM78_DATA_REG_OFFSET);
-		up(&data->lock);
+		mutex_unlock(&data->lock);
 		return res;
 	} else
 		return i2c_smbus_read_byte_data(client, reg);
@@ -717,10 +718,10 @@
 {
 	if (i2c_is_isa_client(client)) {
 		struct lm78_data *data = i2c_get_clientdata(client);
-		down(&data->lock);
+		mutex_lock(&data->lock);
 		outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET);
 		outb_p(value, client->addr + LM78_DATA_REG_OFFSET);
-		up(&data->lock);
+		mutex_unlock(&data->lock);
 		return 0;
 	} else
 		return i2c_smbus_write_byte_data(client, reg, value);
@@ -742,7 +743,7 @@
 	struct lm78_data *data = i2c_get_clientdata(client);
 	int i;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 	    || !data->valid) {
@@ -786,7 +787,7 @@
 		data->fan_div[2] = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/lm80.c newtree/drivers/hwmon/lm80.c
--- oldtree/drivers/hwmon/lm80.c	2006-02-19 11:41:02.164014120 +0000
+++ newtree/drivers/hwmon/lm80.c	2006-02-21 15:58:14.201987528 +0000
@@ -28,6 +28,7 @@
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c,
@@ -108,7 +109,7 @@
 struct lm80_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 
@@ -191,10 +192,10 @@
 	struct lm80_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
  \
-	down(&data->update_lock);\
+	mutex_lock(&data->update_lock);\
 	data->value = IN_TO_REG(val); \
 	lm80_write_value(client, reg, data->value); \
-	up(&data->update_lock);\
+	mutex_unlock(&data->update_lock);\
 	return count; \
 }
 set_in(min0, in_min[0], LM80_REG_IN_MIN(0));
@@ -241,10 +242,10 @@
 	struct lm80_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtoul(buf, NULL, 10); \
  \
-	down(&data->update_lock);\
+	mutex_lock(&data->update_lock);\
 	data->value = FAN_TO_REG(val, DIV_FROM_REG(data->div)); \
 	lm80_write_value(client, reg, data->value); \
-	up(&data->update_lock);\
+	mutex_unlock(&data->update_lock);\
 	return count; \
 }
 set_fan(min1, fan_min[0], LM80_REG_FAN_MIN(1), fan_div[0]);
@@ -263,7 +264,7 @@
 	u8 reg;
 
 	/* Save fan_min */
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	min = FAN_FROM_REG(data->fan_min[nr],
 			   DIV_FROM_REG(data->fan_div[nr]));
 
@@ -275,7 +276,7 @@
 	default:
 		dev_err(&client->dev, "fan_div value %ld not "
 			"supported. Choose one of 1, 2, 4 or 8!\n", val);
-		up(&data->update_lock);
+		mutex_unlock(&data->update_lock);
 		return -EINVAL;
 	}
 
@@ -286,7 +287,7 @@
 	/* Restore fan_min */
 	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
 	lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return count;
 }
@@ -325,10 +326,10 @@
 	struct lm80_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtoul(buf, NULL, 10); \
  \
-	down(&data->update_lock); \
+	mutex_lock(&data->update_lock); \
 	data->value = TEMP_LIMIT_TO_REG(val); \
 	lm80_write_value(client, reg, data->value); \
-	up(&data->update_lock); \
+	mutex_unlock(&data->update_lock); \
 	return count; \
 }
 set_temp(hot_max, temp_hot_max, LM80_REG_TEMP_HOT_MAX);
@@ -437,7 +438,7 @@
 	/* Fill in the remaining client fields and put it into the global list */
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -545,7 +546,7 @@
 	struct lm80_data *data = i2c_get_clientdata(client);
 	int i;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
 		dev_dbg(&client->dev, "Starting lm80 update\n");
@@ -585,7 +586,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/lm83.c newtree/drivers/hwmon/lm83.c
--- oldtree/drivers/hwmon/lm83.c	2006-02-19 11:41:02.164014120 +0000
+++ newtree/drivers/hwmon/lm83.c	2006-02-21 15:58:14.202987376 +0000
@@ -35,6 +35,7 @@
 #include <linux/hwmon-sysfs.h>
 #include <linux/hwmon.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 /*
  * Addresses to scan
@@ -139,7 +140,7 @@
 struct lm83_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid; /* zero until following fields are valid */
 	unsigned long last_updated; /* in jiffies */
 
@@ -171,11 +172,11 @@
 	long val = simple_strtol(buf, NULL, 10);
 	int nr = attr->index;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp[nr] = TEMP_TO_REG(val);
 	i2c_smbus_write_byte_data(client, LM83_REG_W_HIGH[nr - 4],
 				  data->temp[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -300,7 +301,7 @@
 	/* We can fill in the remaining client fields */
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -373,7 +374,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm83_data *data = i2c_get_clientdata(client);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
 		int nr;
@@ -393,7 +394,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/lm85.c newtree/drivers/hwmon/lm85.c
--- oldtree/drivers/hwmon/lm85.c	2006-02-19 11:41:02.165013968 +0000
+++ newtree/drivers/hwmon/lm85.c	2006-02-21 15:58:14.204987072 +0000
@@ -31,6 +31,7 @@
 #include <linux/hwmon.h>
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
@@ -331,10 +332,10 @@
 struct lm85_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore lock;
+	struct mutex lock;
 	enum chips type;
 
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	int valid;		/* !=0 if following fields are valid */
 	unsigned long last_reading;	/* In jiffies */
 	unsigned long last_config;	/* In jiffies */
@@ -407,10 +408,10 @@
 	struct lm85_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->fan_min[nr] = FAN_TO_REG(val);
 	lm85_write_value(client, LM85_REG_FAN_MIN(nr), data->fan_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -499,10 +500,10 @@
 	struct lm85_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->pwm[nr] = PWM_TO_REG(val);
 	lm85_write_value(client, LM85_REG_PWM(nr), data->pwm[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr)
@@ -559,10 +560,10 @@
 	struct lm85_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_min[nr] = INS_TO_REG(nr, val);
 	lm85_write_value(client, LM85_REG_IN_MIN(nr), data->in_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t show_in_max(struct device *dev, char *buf, int nr)
@@ -577,10 +578,10 @@
 	struct lm85_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_max[nr] = INS_TO_REG(nr, val);
 	lm85_write_value(client, LM85_REG_IN_MAX(nr), data->in_max[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 #define show_in_reg(offset)						\
@@ -640,10 +641,10 @@
 	struct lm85_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_min[nr] = TEMP_TO_REG(val);
 	lm85_write_value(client, LM85_REG_TEMP_MIN(nr), data->temp_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t show_temp_max(struct device *dev, char *buf, int nr)
@@ -658,10 +659,10 @@
 	struct lm85_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);	
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_max[nr] = TEMP_TO_REG(val);
 	lm85_write_value(client, LM85_REG_TEMP_MAX(nr), data->temp_max[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 #define show_temp_reg(offset)						\
@@ -713,12 +714,12 @@
 	struct lm85_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);   
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->autofan[nr].config = (data->autofan[nr].config & (~0xe0))
 		| ZONE_TO_REG(val) ;
 	lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr),
 		data->autofan[nr].config);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t show_pwm_auto_pwm_min(struct device *dev, char *buf, int nr)
@@ -733,11 +734,11 @@
 	struct lm85_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->autofan[nr].min_pwm = PWM_TO_REG(val);
 	lm85_write_value(client, LM85_REG_AFAN_MINPWM(nr),
 		data->autofan[nr].min_pwm);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t show_pwm_auto_pwm_minctl(struct device *dev, char *buf, int nr)
@@ -752,7 +753,7 @@
 	struct lm85_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->autofan[nr].min_off = val;
 	lm85_write_value(client, LM85_REG_AFAN_SPIKE1, data->smooth[0]
 		| data->syncpwm3
@@ -760,7 +761,7 @@
 		| (data->autofan[1].min_off ? 0x40 : 0)
 		| (data->autofan[2].min_off ? 0x80 : 0)
 	);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t show_pwm_auto_pwm_freq(struct device *dev, char *buf, int nr)
@@ -775,13 +776,13 @@
 	struct lm85_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->autofan[nr].freq = FREQ_TO_REG(val);
 	lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
 		(data->zone[nr].range << 4)
 		| data->autofan[nr].freq
 	); 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 #define pwm_auto(offset)						\
@@ -857,7 +858,7 @@
 	int min;
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	min = TEMP_FROM_REG(data->zone[nr].limit);
 	data->zone[nr].off_desired = TEMP_TO_REG(val);
 	data->zone[nr].hyst = HYST_TO_REG(min - val);
@@ -871,7 +872,7 @@
 			(data->zone[2].hyst << 4)
 		);
 	}
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t show_temp_auto_temp_min(struct device *dev, char *buf, int nr)
@@ -886,7 +887,7 @@
 	struct lm85_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->zone[nr].limit = TEMP_TO_REG(val);
 	lm85_write_value(client, LM85_REG_AFAN_LIMIT(nr),
 		data->zone[nr].limit);
@@ -913,7 +914,7 @@
 			(data->zone[2].hyst << 4)
 		);
 	}
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t show_temp_auto_temp_max(struct device *dev, char *buf, int nr)
@@ -930,7 +931,7 @@
 	int min;
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	min = TEMP_FROM_REG(data->zone[nr].limit);
 	data->zone[nr].max_desired = TEMP_TO_REG(val);
 	data->zone[nr].range = RANGE_TO_REG(
@@ -938,7 +939,7 @@
 	lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
 		((data->zone[nr].range & 0x0f) << 4)
 		| (data->autofan[nr].freq & 0x07));
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t show_temp_auto_temp_crit(struct device *dev, char *buf, int nr)
@@ -953,11 +954,11 @@
 	struct lm85_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->zone[nr].critical = TEMP_TO_REG(val);
 	lm85_write_value(client, LM85_REG_AFAN_CRITICAL(nr),
 		data->zone[nr].critical);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 #define temp_auto(offset)						\
@@ -1149,7 +1150,7 @@
 	/* Fill in the remaining client fields */
 	data->type = kind;
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -1368,7 +1369,7 @@
 	struct lm85_data *data = i2c_get_clientdata(client);
 	int i;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if ( !data->valid ||
 	     time_after(jiffies, data->last_reading + LM85_DATA_INTERVAL) ) {
@@ -1571,7 +1572,7 @@
 
 	data->valid = 1;
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/lm87.c newtree/drivers/hwmon/lm87.c
--- oldtree/drivers/hwmon/lm87.c	2006-02-19 11:41:02.166013816 +0000
+++ newtree/drivers/hwmon/lm87.c	2006-02-21 15:58:14.205986920 +0000
@@ -60,6 +60,7 @@
 #include <linux/hwmon.h>
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 /*
  * Addresses to scan
@@ -176,7 +177,7 @@
 struct lm87_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid; /* zero until following fields are valid */
 	unsigned long last_updated; /* In jiffies */
 
@@ -253,11 +254,11 @@
 	struct lm87_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_min[nr] = IN_TO_REG(val, data->in_scale[nr]);
 	lm87_write_value(client, nr<6 ? LM87_REG_IN_MIN(nr) :
 			 LM87_REG_AIN_MIN(nr-6), data->in_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 }
 
 static void set_in_max(struct device *dev, const char *buf, int nr)
@@ -266,11 +267,11 @@
 	struct lm87_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_max[nr] = IN_TO_REG(val, data->in_scale[nr]);
 	lm87_write_value(client, nr<6 ? LM87_REG_IN_MAX(nr) :
 			 LM87_REG_AIN_MAX(nr-6), data->in_max[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 }
 
 #define set_in(offset) \
@@ -327,10 +328,10 @@
 	struct lm87_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_low[nr] = TEMP_TO_REG(val);
 	lm87_write_value(client, LM87_REG_TEMP_LOW[nr], data->temp_low[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 }
 
 static void set_temp_high(struct device *dev, const char *buf, int nr)
@@ -339,10 +340,10 @@
 	struct lm87_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_high[nr] = TEMP_TO_REG(val);
 	lm87_write_value(client, LM87_REG_TEMP_HIGH[nr], data->temp_high[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 }
 
 #define set_temp(offset) \
@@ -411,11 +412,11 @@
 	struct lm87_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->fan_min[nr] = FAN_TO_REG(val,
 			    FAN_DIV_FROM_REG(data->fan_div[nr]));
 	lm87_write_value(client, LM87_REG_FAN_MIN(nr), data->fan_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 }
 
 /* Note: we save and restore the fan minimum here, because its value is
@@ -431,7 +432,7 @@
 	unsigned long min;
 	u8 reg;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	min = FAN_FROM_REG(data->fan_min[nr],
 			   FAN_DIV_FROM_REG(data->fan_div[nr]));
 
@@ -441,7 +442,7 @@
 	case 4: data->fan_div[nr] = 2; break;
 	case 8: data->fan_div[nr] = 3; break;
 	default:
-		up(&data->update_lock);
+		mutex_unlock(&data->update_lock);
 		return -EINVAL;
 	}
 
@@ -459,7 +460,7 @@
 	data->fan_min[nr] = FAN_TO_REG(min, val);
 	lm87_write_value(client, LM87_REG_FAN_MIN(nr),
 			 data->fan_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return count;
 }
@@ -522,10 +523,10 @@
 	struct lm87_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->aout = AOUT_TO_REG(val);
 	lm87_write_value(client, LM87_REG_AOUT, data->aout);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);
@@ -589,7 +590,7 @@
 	/* We can fill in the remaining client fields */
 	strlcpy(new_client->name, "lm87", I2C_NAME_SIZE);
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -744,7 +745,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm87_data *data = i2c_get_clientdata(client);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
 		int i, j;
@@ -813,7 +814,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/lm90.c newtree/drivers/hwmon/lm90.c
--- oldtree/drivers/hwmon/lm90.c	2006-02-19 11:41:02.166013816 +0000
+++ newtree/drivers/hwmon/lm90.c	2006-02-21 15:58:14.206986768 +0000
@@ -78,6 +78,7 @@
 #include <linux/hwmon-sysfs.h>
 #include <linux/hwmon.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 /*
  * Addresses to scan
@@ -201,7 +202,7 @@
 struct lm90_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid; /* zero until following fields are valid */
 	unsigned long last_updated; /* in jiffies */
 	int kind;
@@ -247,13 +248,13 @@
 	long val = simple_strtol(buf, NULL, 10);
 	int nr = attr->index;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	if (data->kind == adt7461)
 		data->temp8[nr] = TEMP1_TO_REG_ADT7461(val);
 	else
 		data->temp8[nr] = TEMP1_TO_REG(val);
 	i2c_smbus_write_byte_data(client, reg[nr - 1], data->temp8[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -281,7 +282,7 @@
 	long val = simple_strtol(buf, NULL, 10);
 	int nr = attr->index;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	if (data->kind == adt7461)
 		data->temp11[nr] = TEMP2_TO_REG_ADT7461(val);
 	else
@@ -290,7 +291,7 @@
 				  data->temp11[nr] >> 8);
 	i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
 				  data->temp11[nr] & 0xff);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -311,11 +312,11 @@
 	long val = simple_strtol(buf, NULL, 10);
 	long hyst;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	hyst = TEMP1_FROM_REG(data->temp8[3]) - val;
 	i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST,
 				  HYST_TO_REG(hyst));
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -558,7 +559,7 @@
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
 	data->valid = 0;
 	data->kind = kind;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -646,7 +647,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm90_data *data = i2c_get_clientdata(client);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
 		u8 oldh, newh, l;
@@ -692,7 +693,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/lm92.c newtree/drivers/hwmon/lm92.c
--- oldtree/drivers/hwmon/lm92.c	2006-02-19 11:41:02.167013664 +0000
+++ newtree/drivers/hwmon/lm92.c	2006-02-21 15:58:14.207986616 +0000
@@ -46,6 +46,7 @@
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 /* The LM92 and MAX6635 have 2 two-state pins for address selection,
    resulting in 4 possible addresses. */
@@ -96,7 +97,7 @@
 struct lm92_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid; /* zero until following fields are valid */
 	unsigned long last_updated; /* in jiffies */
 
@@ -114,7 +115,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm92_data *data = i2c_get_clientdata(client);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ)
 	 || !data->valid) {
@@ -134,7 +135,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
@@ -158,10 +159,10 @@
 	struct lm92_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
  \
-	down(&data->update_lock); \
+	mutex_lock(&data->update_lock); \
 	data->value = TEMP_TO_REG(val); \
 	i2c_smbus_write_word_data(client, reg, swab16(data->value)); \
-	up(&data->update_lock); \
+	mutex_unlock(&data->update_lock); \
 	return count; \
 }
 set_temp(temp1_crit, LM92_REG_TEMP_CRIT);
@@ -194,11 +195,11 @@
 	struct lm92_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp1_hyst = TEMP_FROM_REG(data->temp1_crit) - val;
 	i2c_smbus_write_word_data(client, LM92_REG_TEMP_HYST,
 				  swab16(TEMP_TO_REG(data->temp1_hyst)));
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -348,7 +349,7 @@
 	/* Fill in the remaining client fields */
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the i2c subsystem a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
diff -urN oldtree/drivers/hwmon/max1619.c newtree/drivers/hwmon/max1619.c
--- oldtree/drivers/hwmon/max1619.c	2006-02-19 11:41:02.168013512 +0000
+++ newtree/drivers/hwmon/max1619.c	2006-02-21 15:58:14.208986464 +0000
@@ -33,6 +33,7 @@
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
 					0x29, 0x2a, 0x2b,
@@ -104,7 +105,7 @@
 struct max1619_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid; /* zero until following fields are valid */
 	unsigned long last_updated; /* in jiffies */
 
@@ -141,10 +142,10 @@
 	struct max1619_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
  \
-	down(&data->update_lock); \
+	mutex_lock(&data->update_lock); \
 	data->value = TEMP_TO_REG(val); \
 	i2c_smbus_write_byte_data(client, reg, data->value); \
-	up(&data->update_lock); \
+	mutex_unlock(&data->update_lock); \
 	return count; \
 }
 
@@ -262,7 +263,7 @@
 	/* We can fill in the remaining client fields */
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -330,7 +331,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct max1619_data *data = i2c_get_clientdata(client);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
 		dev_dbg(&client->dev, "Updating max1619 data.\n");
@@ -353,7 +354,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/pc87360.c newtree/drivers/hwmon/pc87360.c
--- oldtree/drivers/hwmon/pc87360.c	2006-02-19 11:41:02.168013512 +0000
+++ newtree/drivers/hwmon/pc87360.c	2006-02-21 15:58:14.209986312 +0000
@@ -43,6 +43,7 @@
 #include <linux/hwmon-sysfs.h>
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 
 static u8 devid;
@@ -183,8 +184,8 @@
 struct pc87360_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore lock;
-	struct semaphore update_lock;
+	struct mutex lock;
+	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 
@@ -283,7 +284,7 @@
 	struct pc87360_data *data = i2c_get_clientdata(client);
 	long fan_min = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	fan_min = FAN_TO_REG(fan_min, FAN_DIV_FROM_REG(data->fan_status[attr->index]));
 
 	/* If it wouldn't fit, change clock divisor */
@@ -300,23 +301,31 @@
 	/* Write new divider, preserve alarm bits */
 	pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_STATUS(attr->index),
 			    data->fan_status[attr->index] & 0xF9);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return count;
 }
 
-#define show_and_set_fan(offset) \
-static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
-	show_fan_input, NULL, offset-1); \
-static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IWUSR | S_IRUGO, \
-	show_fan_min, set_fan_min, offset-1); \
-static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO, \
-	show_fan_div, NULL, offset-1); \
-static SENSOR_DEVICE_ATTR(fan##offset##_status, S_IRUGO, \
-	show_fan_status, NULL, offset-1);
-show_and_set_fan(1)
-show_and_set_fan(2)
-show_and_set_fan(3)
+static struct sensor_device_attribute fan_input[] = {
+	SENSOR_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0),
+	SENSOR_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1),
+	SENSOR_ATTR(fan3_input, S_IRUGO, show_fan_input, NULL, 2),
+};
+static struct sensor_device_attribute fan_status[] = {
+	SENSOR_ATTR(fan1_status, S_IRUGO, show_fan_status, NULL, 0),
+	SENSOR_ATTR(fan2_status, S_IRUGO, show_fan_status, NULL, 1),
+	SENSOR_ATTR(fan3_status, S_IRUGO, show_fan_status, NULL, 2),
+};
+static struct sensor_device_attribute fan_div[] = {
+	SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
+	SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
+	SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
+};
+static struct sensor_device_attribute fan_min[] = {
+	SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 0),
+	SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 1),
+	SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 2),
+};
 
 static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
 {
@@ -335,21 +344,20 @@
 	struct pc87360_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->pwm[attr->index] = PWM_TO_REG(val,
 			      FAN_CONFIG_INVERT(data->fan_conf, attr->index));
 	pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(attr->index),
 			    data->pwm[attr->index]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
-#define show_and_set_pwm(offset) \
-static SENSOR_DEVICE_ATTR(pwm##offset, S_IWUSR | S_IRUGO, \
-	show_pwm, set_pwm, offset-1);
-show_and_set_pwm(1)
-show_and_set_pwm(2)
-show_and_set_pwm(3)
+static struct sensor_device_attribute pwm[] = {
+	SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0),
+	SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1),
+	SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2),
+};
 
 static ssize_t show_in_input(struct device *dev, struct device_attribute *devattr, char *buf)
 {
@@ -386,11 +394,11 @@
 	struct pc87360_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_min[attr->index] = IN_TO_REG(val, data->in_vref);
 	pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_IN_MIN,
 			    data->in_min[attr->index]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t set_in_max(struct device *dev, struct device_attribute *devattr, const char *buf,
@@ -401,35 +409,67 @@
 	struct pc87360_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_max[attr->index] = IN_TO_REG(val,
 			       data->in_vref);
 	pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_IN_MAX,
 			    data->in_max[attr->index]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
-#define show_and_set_in(offset) \
-static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
-	show_in_input, NULL, offset); \
-static SENSOR_DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \
-	show_in_min, set_in_min, offset); \
-static SENSOR_DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \
-	show_in_max, set_in_max, offset); \
-static SENSOR_DEVICE_ATTR(in##offset##_status, S_IRUGO, \
-	show_in_status, NULL, offset);
-show_and_set_in(0)
-show_and_set_in(1)
-show_and_set_in(2)
-show_and_set_in(3)
-show_and_set_in(4)
-show_and_set_in(5)
-show_and_set_in(6)
-show_and_set_in(7)
-show_and_set_in(8)
-show_and_set_in(9)
-show_and_set_in(10)
+static struct sensor_device_attribute in_input[] = {
+	SENSOR_ATTR(in0_input, S_IRUGO, show_in_input, NULL, 0),
+	SENSOR_ATTR(in1_input, S_IRUGO, show_in_input, NULL, 1),
+	SENSOR_ATTR(in2_input, S_IRUGO, show_in_input, NULL, 2),
+	SENSOR_ATTR(in3_input, S_IRUGO, show_in_input, NULL, 3),
+	SENSOR_ATTR(in4_input, S_IRUGO, show_in_input, NULL, 4),
+	SENSOR_ATTR(in5_input, S_IRUGO, show_in_input, NULL, 5),
+	SENSOR_ATTR(in6_input, S_IRUGO, show_in_input, NULL, 6),
+	SENSOR_ATTR(in7_input, S_IRUGO, show_in_input, NULL, 7),
+	SENSOR_ATTR(in8_input, S_IRUGO, show_in_input, NULL, 8),
+	SENSOR_ATTR(in9_input, S_IRUGO, show_in_input, NULL, 9),
+	SENSOR_ATTR(in10_input, S_IRUGO, show_in_input, NULL, 10),
+};
+static struct sensor_device_attribute in_status[] = {
+	SENSOR_ATTR(in0_status, S_IRUGO, show_in_status, NULL, 0),
+	SENSOR_ATTR(in1_status, S_IRUGO, show_in_status, NULL, 1),
+	SENSOR_ATTR(in2_status, S_IRUGO, show_in_status, NULL, 2),
+	SENSOR_ATTR(in3_status, S_IRUGO, show_in_status, NULL, 3),
+	SENSOR_ATTR(in4_status, S_IRUGO, show_in_status, NULL, 4),
+	SENSOR_ATTR(in5_status, S_IRUGO, show_in_status, NULL, 5),
+	SENSOR_ATTR(in6_status, S_IRUGO, show_in_status, NULL, 6),
+	SENSOR_ATTR(in7_status, S_IRUGO, show_in_status, NULL, 7),
+	SENSOR_ATTR(in8_status, S_IRUGO, show_in_status, NULL, 8),
+	SENSOR_ATTR(in9_status, S_IRUGO, show_in_status, NULL, 9),
+	SENSOR_ATTR(in10_status, S_IRUGO, show_in_status, NULL, 10),
+};
+static struct sensor_device_attribute in_min[] = {
+	SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 0),
+	SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 1),
+	SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 2),
+	SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 3),
+	SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 4),
+	SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 5),
+	SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 6),
+	SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 7),
+	SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 8),
+	SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 9),
+	SENSOR_ATTR(in10_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 10),
+};
+static struct sensor_device_attribute in_max[] = {
+	SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 0),
+	SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 1),
+	SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 2),
+	SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 3),
+	SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 4),
+	SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 5),
+	SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 6),
+	SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 7),
+	SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 8),
+	SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 9),
+	SENSOR_ATTR(in10_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 10),
+};
 
 static ssize_t show_therm_input(struct device *dev, struct device_attribute *devattr, char *buf)
 {
@@ -473,11 +513,11 @@
 	struct pc87360_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_min[attr->index] = IN_TO_REG(val, data->in_vref);
 	pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_MIN,
 			    data->in_min[attr->index]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t set_therm_max(struct device *dev, struct device_attribute *devattr, const char *buf,
@@ -488,11 +528,11 @@
 	struct pc87360_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_max[attr->index] = IN_TO_REG(val, data->in_vref);
 	pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_MAX,
 			    data->in_max[attr->index]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t set_therm_crit(struct device *dev, struct device_attribute *devattr, const char *buf,
@@ -503,28 +543,51 @@
 	struct pc87360_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_crit[attr->index-11] = IN_TO_REG(val, data->in_vref);
 	pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_CRIT,
 			    data->in_crit[attr->index-11]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
-#define show_and_set_therm(offset) \
-static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
-	show_therm_input, NULL, 11+offset-4); \
-static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
-	show_therm_min, set_therm_min, 11+offset-4); \
-static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
-	show_therm_max, set_therm_max, 11+offset-4); \
-static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \
-	show_therm_crit, set_therm_crit, 11+offset-4); \
-static SENSOR_DEVICE_ATTR(temp##offset##_status, S_IRUGO, \
-	show_therm_status, NULL, 11+offset-4);
-show_and_set_therm(4)
-show_and_set_therm(5)
-show_and_set_therm(6)
+/* the +11 term below reflects the fact that VLM units 11,12,13 are
+   used in the chip to measure voltage across the thermistors
+*/
+static struct sensor_device_attribute therm_input[] = {
+	SENSOR_ATTR(temp4_input, S_IRUGO, show_therm_input, NULL, 0+11),
+	SENSOR_ATTR(temp5_input, S_IRUGO, show_therm_input, NULL, 1+11),
+	SENSOR_ATTR(temp6_input, S_IRUGO, show_therm_input, NULL, 2+11),
+};
+static struct sensor_device_attribute therm_status[] = {
+	SENSOR_ATTR(temp4_status, S_IRUGO, show_therm_status, NULL, 0+11),
+	SENSOR_ATTR(temp5_status, S_IRUGO, show_therm_status, NULL, 1+11),
+	SENSOR_ATTR(temp6_status, S_IRUGO, show_therm_status, NULL, 2+11),
+};
+static struct sensor_device_attribute therm_min[] = {
+	SENSOR_ATTR(temp4_min, S_IRUGO | S_IWUSR,
+		    show_therm_min, set_therm_min, 0+11),
+	SENSOR_ATTR(temp5_min, S_IRUGO | S_IWUSR,
+		    show_therm_min, set_therm_min, 1+11),
+	SENSOR_ATTR(temp6_min, S_IRUGO | S_IWUSR,
+		    show_therm_min, set_therm_min, 2+11),
+};
+static struct sensor_device_attribute therm_max[] = {
+	SENSOR_ATTR(temp4_max, S_IRUGO | S_IWUSR,
+		    show_therm_max, set_therm_max, 0+11),
+	SENSOR_ATTR(temp5_max, S_IRUGO | S_IWUSR,
+		    show_therm_max, set_therm_max, 1+11),
+	SENSOR_ATTR(temp6_max, S_IRUGO | S_IWUSR,
+		    show_therm_max, set_therm_max, 2+11),
+};
+static struct sensor_device_attribute therm_crit[] = {
+	SENSOR_ATTR(temp4_crit, S_IRUGO | S_IWUSR,
+		    show_therm_crit, set_therm_crit, 0+11),
+	SENSOR_ATTR(temp5_crit, S_IRUGO | S_IWUSR,
+		    show_therm_crit, set_therm_crit, 1+11),
+	SENSOR_ATTR(temp6_crit, S_IRUGO | S_IWUSR,
+		    show_therm_crit, set_therm_crit, 2+11),
+};
 
 static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -592,11 +655,11 @@
 	struct pc87360_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_min[attr->index] = TEMP_TO_REG(val);
 	pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_MIN,
 			    data->temp_min[attr->index]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t set_temp_max(struct device *dev, struct device_attribute *devattr, const char *buf,
@@ -607,11 +670,11 @@
 	struct pc87360_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_max[attr->index] = TEMP_TO_REG(val);
 	pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_MAX,
 			    data->temp_max[attr->index]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t set_temp_crit(struct device *dev, struct device_attribute *devattr, const char *buf,
@@ -622,28 +685,48 @@
 	struct pc87360_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_crit[attr->index] = TEMP_TO_REG(val);
 	pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_CRIT,
 			    data->temp_crit[attr->index]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
-#define show_and_set_temp(offset) \
-static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
-	show_temp_input, NULL, offset-1); \
-static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
-	show_temp_min, set_temp_min, offset-1); \
-static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
-	show_temp_max, set_temp_max, offset-1); \
-static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \
-	show_temp_crit, set_temp_crit, offset-1); \
-static SENSOR_DEVICE_ATTR(temp##offset##_status, S_IRUGO, \
-	show_temp_status, NULL, offset-1);
-show_and_set_temp(1)
-show_and_set_temp(2)
-show_and_set_temp(3)
+static struct sensor_device_attribute temp_input[] = {
+	SENSOR_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0),
+	SENSOR_ATTR(temp2_input, S_IRUGO, show_temp_input, NULL, 1),
+	SENSOR_ATTR(temp3_input, S_IRUGO, show_temp_input, NULL, 2),
+};
+static struct sensor_device_attribute temp_status[] = {
+	SENSOR_ATTR(temp1_status, S_IRUGO, show_temp_status, NULL, 0),
+	SENSOR_ATTR(temp2_status, S_IRUGO, show_temp_status, NULL, 1),
+	SENSOR_ATTR(temp3_status, S_IRUGO, show_temp_status, NULL, 2),
+};
+static struct sensor_device_attribute temp_min[] = {
+	SENSOR_ATTR(temp1_min, S_IRUGO | S_IWUSR,
+		    show_temp_min, set_temp_min, 0),
+	SENSOR_ATTR(temp2_min, S_IRUGO | S_IWUSR,
+		    show_temp_min, set_temp_min, 1),
+	SENSOR_ATTR(temp3_min, S_IRUGO | S_IWUSR,
+		    show_temp_min, set_temp_min, 2),
+};
+static struct sensor_device_attribute temp_max[] = {
+	SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR,
+		    show_temp_max, set_temp_max, 0),
+	SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR,
+		    show_temp_max, set_temp_max, 1),
+	SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR,
+		    show_temp_max, set_temp_max, 2),
+};
+static struct sensor_device_attribute temp_crit[] = {
+	SENSOR_ATTR(temp1_crit, S_IRUGO | S_IWUSR,
+		    show_temp_crit, set_temp_crit, 0),
+	SENSOR_ATTR(temp2_crit, S_IRUGO | S_IWUSR,
+		    show_temp_crit, set_temp_crit, 1),
+	SENSOR_ATTR(temp3_crit, S_IRUGO | S_IWUSR,
+		    show_temp_crit, set_temp_crit, 2),
+};
 
 static ssize_t show_temp_alarms(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -749,22 +832,24 @@
 static int pc87360_detect(struct i2c_adapter *adapter)
 {
 	int i;
-	struct i2c_client *new_client;
+	struct i2c_client *client;
 	struct pc87360_data *data;
 	int err = 0;
 	const char *name = "pc87360";
 	int use_thermistors = 0;
+	struct device *dev;
 
 	if (!(data = kzalloc(sizeof(struct pc87360_data), GFP_KERNEL)))
 		return -ENOMEM;
 
-	new_client = &data->client;
-	i2c_set_clientdata(new_client, data);
-	new_client->addr = address;
-	init_MUTEX(&data->lock);
-	new_client->adapter = adapter;
-	new_client->driver = &pc87360_driver;
-	new_client->flags = 0;
+	client = &data->client;
+	dev = &client->dev;
+	i2c_set_clientdata(client, data);
+	client->addr = address;
+	mutex_init(&data->lock);
+	client->adapter = adapter;
+	client->driver = &pc87360_driver;
+	client->flags = 0;
 
 	data->fannr = 2;
 	data->innr = 0;
@@ -792,15 +877,15 @@
 		break;
 	}
 
-	strcpy(new_client->name, name);
+	strlcpy(client->name, name, sizeof(client->name));
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	for (i = 0; i < 3; i++) {
 		if (((data->address[i] = extra_isa[i]))
 		 && !request_region(extra_isa[i], PC87360_EXTENT,
 		 		    pc87360_driver.driver.name)) {
-			dev_err(&new_client->dev, "Region 0x%x-0x%x already "
+			dev_err(&client->dev, "Region 0x%x-0x%x already "
 				"in use!\n", extra_isa[i],
 				extra_isa[i]+PC87360_EXTENT-1);
 			for (i--; i >= 0; i--)
@@ -814,7 +899,7 @@
 	if (data->fannr)
 		data->fan_conf = confreg[0] | (confreg[1] << 8);
 
-	if ((err = i2c_attach_client(new_client)))
+	if ((err = i2c_attach_client(client)))
 		goto ERROR2;
 
 	/* Use the correct reference voltage
@@ -828,7 +913,7 @@
 						PC87365_REG_TEMP_CONFIG);
 		}
 		data->in_vref = (i&0x02) ? 3025 : 2966;
-		dev_dbg(&new_client->dev, "Using %s reference voltage\n",
+		dev_dbg(&client->dev, "Using %s reference voltage\n",
 			(i&0x02) ? "external" : "internal");
 
 		data->vid_conf = confreg[3];
@@ -847,154 +932,64 @@
 		if (devid == 0xe9 && data->address[1]) /* PC87366 */
 			use_thermistors = confreg[2] & 0x40;
 
-		pc87360_init_client(new_client, use_thermistors);
+		pc87360_init_client(client, use_thermistors);
 	}
 
 	/* Register sysfs hooks */
-	data->class_dev = hwmon_device_register(&new_client->dev);
+	data->class_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->class_dev)) {
 		err = PTR_ERR(data->class_dev);
 		goto ERROR3;
 	}
 
 	if (data->innr) {
-		device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in9_input.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in10_input.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in8_min.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in9_min.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in10_min.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in8_max.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in9_max.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in10_max.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in0_status.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in1_status.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in2_status.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in3_status.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in4_status.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in5_status.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in6_status.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in7_status.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in8_status.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in9_status.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_in10_status.dev_attr);
-
-		device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
-		device_create_file(&new_client->dev, &dev_attr_vrm);
-		device_create_file(&new_client->dev, &dev_attr_alarms_in);
+		for (i = 0; i < 11; i++) {
+			device_create_file(dev, &in_input[i].dev_attr);
+			device_create_file(dev, &in_min[i].dev_attr);
+			device_create_file(dev, &in_max[i].dev_attr);
+			device_create_file(dev, &in_status[i].dev_attr);
+		}
+		device_create_file(dev, &dev_attr_cpu0_vid);
+		device_create_file(dev, &dev_attr_vrm);
+		device_create_file(dev, &dev_attr_alarms_in);
 	}
 
 	if (data->tempnr) {
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp1_crit.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp2_crit.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp1_status.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp2_status.dev_attr);
-
-		device_create_file(&new_client->dev, &dev_attr_alarms_temp);
-	}
-	if (data->tempnr == 3) {
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp3_crit.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp3_status.dev_attr);
+		for (i = 0; i < data->tempnr; i++) {
+			device_create_file(dev, &temp_input[i].dev_attr);
+			device_create_file(dev, &temp_min[i].dev_attr);
+			device_create_file(dev, &temp_max[i].dev_attr);
+			device_create_file(dev, &temp_crit[i].dev_attr);
+			device_create_file(dev, &temp_status[i].dev_attr);
+		}
+		device_create_file(dev, &dev_attr_alarms_temp);
 	}
+
 	if (data->innr == 14) {
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp4_input.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp5_input.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp6_input.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp4_min.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp5_min.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp6_min.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp4_max.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp5_max.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp6_max.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp4_crit.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp5_crit.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp6_crit.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp4_status.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp5_status.dev_attr);
-		device_create_file(&new_client->dev, &sensor_dev_attr_temp6_status.dev_attr);
-	}
-
-	if (data->fannr) {
-		if (FAN_CONFIG_MONITOR(data->fan_conf, 0)) {
-			device_create_file(&new_client->dev,
-					   &sensor_dev_attr_fan1_input.dev_attr);
-			device_create_file(&new_client->dev,
-					   &sensor_dev_attr_fan1_min.dev_attr);
-			device_create_file(&new_client->dev,
-					   &sensor_dev_attr_fan1_div.dev_attr);
-			device_create_file(&new_client->dev,
-					   &sensor_dev_attr_fan1_status.dev_attr);
-		}
-
-		if (FAN_CONFIG_MONITOR(data->fan_conf, 1)) {
-			device_create_file(&new_client->dev,
-					   &sensor_dev_attr_fan2_input.dev_attr);
-			device_create_file(&new_client->dev,
-					   &sensor_dev_attr_fan2_min.dev_attr);
-			device_create_file(&new_client->dev,
-					   &sensor_dev_attr_fan2_div.dev_attr);
-			device_create_file(&new_client->dev,
-					   &sensor_dev_attr_fan2_status.dev_attr);
-		}
-
-		if (FAN_CONFIG_CONTROL(data->fan_conf, 0))
-			device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr);
-		if (FAN_CONFIG_CONTROL(data->fan_conf, 1))
-			device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr);
-	}
-	if (data->fannr == 3) {
-		if (FAN_CONFIG_MONITOR(data->fan_conf, 2)) {
-			device_create_file(&new_client->dev,
-					   &sensor_dev_attr_fan3_input.dev_attr);
-			device_create_file(&new_client->dev,
-					   &sensor_dev_attr_fan3_min.dev_attr);
-			device_create_file(&new_client->dev,
-					   &sensor_dev_attr_fan3_div.dev_attr);
-			device_create_file(&new_client->dev,
-					   &sensor_dev_attr_fan3_status.dev_attr);
+		for (i = 0; i < 3; i++) {
+			device_create_file(dev, &therm_input[i].dev_attr);
+			device_create_file(dev, &therm_min[i].dev_attr);
+			device_create_file(dev, &therm_max[i].dev_attr);
+			device_create_file(dev, &therm_crit[i].dev_attr);
+			device_create_file(dev, &therm_status[i].dev_attr);
 		}
+	}
 
-		if (FAN_CONFIG_CONTROL(data->fan_conf, 2))
-			device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr);
+	for (i = 0; i < data->fannr; i++) {
+		if (FAN_CONFIG_MONITOR(data->fan_conf, i)) {
+			device_create_file(dev, &fan_input[i].dev_attr);
+			device_create_file(dev, &fan_min[i].dev_attr);
+			device_create_file(dev, &fan_div[i].dev_attr);
+			device_create_file(dev, &fan_status[i].dev_attr);
+		}
+		if (FAN_CONFIG_CONTROL(data->fan_conf, i))
+			device_create_file(dev, &pwm[i].dev_attr);
 	}
 
 	return 0;
 
 ERROR3:
-	i2c_detach_client(new_client);
+	i2c_detach_client(client);
 ERROR2:
 	for (i = 0; i < 3; i++) {
 		if (data->address[i]) {
@@ -1033,11 +1028,11 @@
 {
 	int res;
 
-	down(&(data->lock));
+	mutex_lock(&(data->lock));
 	if (bank != NO_BANK)
 		outb_p(bank, data->address[ldi] + PC87365_REG_BANK);
 	res = inb_p(data->address[ldi] + reg);
-	up(&(data->lock));
+	mutex_unlock(&(data->lock));
 
 	return res;
 }
@@ -1045,11 +1040,11 @@
 static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
 				u8 reg, u8 value)
 {
-	down(&(data->lock));
+	mutex_lock(&(data->lock));
 	if (bank != NO_BANK)
 		outb_p(bank, data->address[ldi] + PC87365_REG_BANK);
 	outb_p(value, data->address[ldi] + reg);
-	up(&(data->lock));
+	mutex_unlock(&(data->lock));
 }
 
 static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
@@ -1071,7 +1066,7 @@
 	}
 
 	nr = data->innr < 11 ? data->innr : 11;
-	for (i=0; i<nr; i++) {
+	for (i = 0; i < nr; i++) {
 		if (init >= init_in[i]) {
 			/* Forcibly enable voltage channel */
 			reg = pc87360_read_value(data, LD_IN, i,
@@ -1088,14 +1083,14 @@
 
 	/* We can't blindly trust the Super-I/O space configuration bit,
 	   most BIOS won't set it properly */
-	for (i=11; i<data->innr; i++) {
+	for (i = 11; i < data->innr; i++) {
 		reg = pc87360_read_value(data, LD_IN, i,
 					 PC87365_REG_TEMP_STATUS);
 		use_thermistors = use_thermistors || (reg & 0x01);
 	}
 
 	i = use_thermistors ? 2 : 0;
-	for (; i<data->tempnr; i++) {
+	for (; i < data->tempnr; i++) {
 		if (init >= init_temp[i]) {
 			/* Forcibly enable temperature channel */
 			reg = pc87360_read_value(data, LD_TEMP, i,
@@ -1111,7 +1106,7 @@
 	}
 
 	if (use_thermistors) {
-		for (i=11; i<data->innr; i++) {
+		for (i = 11; i < data->innr; i++) {
 			if (init >= init_in[i]) {
 				/* The pin may already be used by thermal
 				   diodes */
@@ -1221,7 +1216,7 @@
 	struct pc87360_data *data = i2c_get_clientdata(client);
 	u8 i;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
 		dev_dbg(&client->dev, "Data update\n");
@@ -1321,7 +1316,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/sis5595.c newtree/drivers/hwmon/sis5595.c
--- oldtree/drivers/hwmon/sis5595.c	2006-02-19 11:41:02.169013360 +0000
+++ newtree/drivers/hwmon/sis5595.c	2006-02-21 15:58:14.210986160 +0000
@@ -60,6 +60,7 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/jiffies.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 
 
@@ -167,9 +168,9 @@
 struct sis5595_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore lock;
+	struct mutex lock;
 
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 	char maxins;		/* == 3 if temp enabled, otherwise == 4 */
@@ -231,10 +232,10 @@
 	struct sis5595_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_min[nr] = IN_TO_REG(val);
 	sis5595_write_value(client, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -245,10 +246,10 @@
 	struct sis5595_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_max[nr] = IN_TO_REG(val);
 	sis5595_write_value(client, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -310,10 +311,10 @@
 	struct sis5595_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_over = TEMP_TO_REG(val);
 	sis5595_write_value(client, SIS5595_REG_TEMP_OVER, data->temp_over);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -329,10 +330,10 @@
 	struct sis5595_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_hyst = TEMP_TO_REG(val);
 	sis5595_write_value(client, SIS5595_REG_TEMP_HYST, data->temp_hyst);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -364,10 +365,10 @@
 	struct sis5595_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
 	sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -390,7 +391,7 @@
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 	int reg;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	min = FAN_FROM_REG(data->fan_min[nr],
 			DIV_FROM_REG(data->fan_div[nr]));
 	reg = sis5595_read_value(client, SIS5595_REG_FANDIV);
@@ -403,7 +404,7 @@
 	default:
 		dev_err(&client->dev, "fan_div value %ld not "
 			"supported. Choose one of 1, 2, 4 or 8!\n", val);
-		up(&data->update_lock);
+		mutex_unlock(&data->update_lock);
 		return -EINVAL;
 	}
 	
@@ -419,7 +420,7 @@
 	data->fan_min[nr] =
 		FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
 	sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -527,7 +528,7 @@
 
 	new_client = &data->client;
 	new_client->addr = address;
-	init_MUTEX(&data->lock);
+	mutex_init(&data->lock);
 	i2c_set_clientdata(new_client, data);
 	new_client->adapter = adapter;
 	new_client->driver = &sis5595_driver;
@@ -548,7 +549,7 @@
 	strlcpy(new_client->name, "sis5595", I2C_NAME_SIZE);
 
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -635,20 +636,20 @@
 	int res;
 
 	struct sis5595_data *data = i2c_get_clientdata(client);
-	down(&data->lock);
+	mutex_lock(&data->lock);
 	outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
 	res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET);
-	up(&data->lock);
+	mutex_unlock(&data->lock);
 	return res;
 }
 
 static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value)
 {
 	struct sis5595_data *data = i2c_get_clientdata(client);
-	down(&data->lock);
+	mutex_lock(&data->lock);
 	outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
 	outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET);
-	up(&data->lock);
+	mutex_unlock(&data->lock);
 	return 0;
 }
 
@@ -667,7 +668,7 @@
 	struct sis5595_data *data = i2c_get_clientdata(client);
 	int i;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 	    || !data->valid) {
@@ -707,7 +708,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/smsc47b397.c newtree/drivers/hwmon/smsc47b397.c
--- oldtree/drivers/hwmon/smsc47b397.c	2006-02-19 11:41:02.170013208 +0000
+++ newtree/drivers/hwmon/smsc47b397.c	2006-02-21 15:58:14.210986160 +0000
@@ -35,6 +35,7 @@
 #include <linux/hwmon.h>
 #include <linux/err.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 
 /* Address is autodetected, there is no default value */
@@ -92,9 +93,9 @@
 struct smsc47b397_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore lock;
+	struct mutex lock;
 
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	unsigned long last_updated; /* in jiffies */
 	int valid;
 
@@ -108,10 +109,10 @@
 	struct smsc47b397_data *data = i2c_get_clientdata(client);
 	int res;
 
-	down(&data->lock);
+	mutex_lock(&data->lock);
 	outb(reg, client->addr);
 	res = inb_p(client->addr + 1);
-	up(&data->lock);
+	mutex_unlock(&data->lock);
 	return res;
 }
 
@@ -121,7 +122,7 @@
 	struct smsc47b397_data *data = i2c_get_clientdata(client);
 	int i;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
 		dev_dbg(&client->dev, "starting device update...\n");
@@ -144,7 +145,7 @@
 		dev_dbg(&client->dev, "... device update complete\n");
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
@@ -254,14 +255,14 @@
 	new_client = &data->client;
 	i2c_set_clientdata(new_client, data);
 	new_client->addr = address;
-	init_MUTEX(&data->lock);
+	mutex_init(&data->lock);
 	new_client->adapter = adapter;
 	new_client->driver = &smsc47b397_driver;
 	new_client->flags = 0;
 
 	strlcpy(new_client->name, "smsc47b397", I2C_NAME_SIZE);
 
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	if ((err = i2c_attach_client(new_client)))
 		goto error_free;
diff -urN oldtree/drivers/hwmon/smsc47m1.c newtree/drivers/hwmon/smsc47m1.c
--- oldtree/drivers/hwmon/smsc47m1.c	2006-02-19 11:41:02.171013056 +0000
+++ newtree/drivers/hwmon/smsc47m1.c	2006-02-21 15:58:14.211986008 +0000
@@ -34,6 +34,7 @@
 #include <linux/hwmon.h>
 #include <linux/err.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 
 /* Address is autodetected, there is no default value */
@@ -102,9 +103,9 @@
 struct smsc47m1_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore lock;
+	struct mutex lock;
 
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	unsigned long last_updated;	/* In jiffies */
 
 	u8 fan[2];		/* Register value */
@@ -188,18 +189,18 @@
 	struct smsc47m1_data *data = i2c_get_clientdata(client);
 	long rpmdiv, val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]);
 
 	if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) {
-		up(&data->update_lock);
+		mutex_unlock(&data->update_lock);
 		return -EINVAL;
 	}
 
 	data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv);
 	smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr),
 			     data->fan_preload[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return count;
 }
@@ -220,14 +221,14 @@
 	if (new_div == old_div) /* No change */
 		return count;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	switch (new_div) {
 	case 1: data->fan_div[nr] = 0; break;
 	case 2: data->fan_div[nr] = 1; break;
 	case 4: data->fan_div[nr] = 2; break;
 	case 8: data->fan_div[nr] = 3; break;
 	default:
-		up(&data->update_lock);
+		mutex_unlock(&data->update_lock);
 		return -EINVAL;
 	}
 
@@ -241,7 +242,7 @@
 	data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191);
 	smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr),
 			     data->fan_preload[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return count;
 }
@@ -257,12 +258,12 @@
 	if (val < 0 || val > 255)
 		return -EINVAL;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->pwm[nr] &= 0x81; /* Preserve additional bits */
 	data->pwm[nr] |= PWM_TO_REG(val);
 	smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr),
 			     data->pwm[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return count;
 }
@@ -278,12 +279,12 @@
 	if (val != 0 && val != 1)
 		return -EINVAL;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->pwm[nr] &= 0xFE; /* preserve the other bits */
 	data->pwm[nr] |= !val;
 	smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr),
 			     data->pwm[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return count;
 }
@@ -408,13 +409,13 @@
 	new_client = &data->client;
 	i2c_set_clientdata(new_client, data);
 	new_client->addr = address;
-	init_MUTEX(&data->lock);
+	mutex_init(&data->lock);
 	new_client->adapter = adapter;
 	new_client->driver = &smsc47m1_driver;
 	new_client->flags = 0;
 
 	strlcpy(new_client->name, "smsc47m1", I2C_NAME_SIZE);
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* If no function is properly configured, there's no point in
 	   actually registering the chip. */
@@ -512,17 +513,17 @@
 {
 	int res;
 
-	down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
+	mutex_lock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
 	res = inb_p(client->addr + reg);
-	up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
+	mutex_unlock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
 	return res;
 }
 
 static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value)
 {
-	down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
+	mutex_lock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
 	outb_p(value, client->addr + reg);
-	up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
+	mutex_unlock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
 }
 
 static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
@@ -531,7 +532,7 @@
  	struct i2c_client *client = to_i2c_client(dev);
 	struct smsc47m1_data *data = i2c_get_clientdata(client);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) {
 		int i;
@@ -558,7 +559,7 @@
 		data->last_updated = jiffies;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return data;
 }
 
diff -urN oldtree/drivers/hwmon/via686a.c newtree/drivers/hwmon/via686a.c
--- oldtree/drivers/hwmon/via686a.c	2006-02-19 11:41:02.172012904 +0000
+++ newtree/drivers/hwmon/via686a.c	2006-02-21 15:58:14.213985704 +0000
@@ -39,6 +39,7 @@
 #include <linux/hwmon.h>
 #include <linux/err.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 
 
@@ -296,7 +297,7 @@
 struct via686a_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 
@@ -355,11 +356,11 @@
 	struct via686a_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_min[nr] = IN_TO_REG(val, nr);
 	via686a_write_value(client, VIA686A_REG_IN_MIN(nr),
 			data->in_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t set_in_max(struct device *dev, const char *buf,
@@ -368,11 +369,11 @@
 	struct via686a_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_max[nr] = IN_TO_REG(val, nr);
 	via686a_write_value(client, VIA686A_REG_IN_MAX(nr),
 			data->in_max[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 #define show_in_offset(offset)					\
@@ -432,11 +433,11 @@
 	struct via686a_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_over[nr] = TEMP_TO_REG(val);
 	via686a_write_value(client, VIA686A_REG_TEMP_OVER[nr],
 			    data->temp_over[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t set_temp_hyst(struct device *dev, const char *buf,
@@ -445,11 +446,11 @@
 	struct via686a_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_hyst[nr] = TEMP_TO_REG(val);
 	via686a_write_value(client, VIA686A_REG_TEMP_HYST[nr],
 			    data->temp_hyst[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 #define show_temp_offset(offset)					\
@@ -508,10 +509,10 @@
 	struct via686a_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
 	via686a_write_value(client, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t set_fan_div(struct device *dev, const char *buf,
@@ -521,12 +522,12 @@
 	int val = simple_strtol(buf, NULL, 10);
 	int old;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	old = via686a_read_value(client, VIA686A_REG_FANDIV);
 	data->fan_div[nr] = DIV_TO_REG(val);
 	old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
 	via686a_write_value(client, VIA686A_REG_FANDIV, old);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -639,7 +640,7 @@
 	strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
 
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
 		goto exit_free;
@@ -733,7 +734,7 @@
 	struct via686a_data *data = i2c_get_clientdata(client);
 	int i;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 	    || !data->valid) {
@@ -788,7 +789,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/vt8231.c newtree/drivers/hwmon/vt8231.c
--- oldtree/drivers/hwmon/vt8231.c	2006-02-19 11:41:02.174012600 +0000
+++ newtree/drivers/hwmon/vt8231.c	2006-02-21 15:58:14.214985552 +0000
@@ -35,6 +35,7 @@
 #include <linux/hwmon-sysfs.h>
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 
 static int force_addr;
@@ -148,7 +149,7 @@
 
 struct vt8231_data {
 	struct i2c_client client;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	struct class_device *class_dev;
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
@@ -223,10 +224,10 @@
 	struct vt8231_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_min[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255);
 	vt8231_write_value(client, regvoltmin[nr], data->in_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -239,10 +240,10 @@
 	struct vt8231_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_max[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255);
 	vt8231_write_value(client, regvoltmax[nr], data->in_max[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -281,11 +282,11 @@
 	struct vt8231_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_min[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3,
 					0, 255);
 	vt8231_write_value(client, regvoltmin[5], data->in_min[5]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -296,11 +297,11 @@
 	struct vt8231_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_max[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3,
 					0, 255);
 	vt8231_write_value(client, regvoltmax[5], data->in_max[5]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -351,10 +352,10 @@
 	struct vt8231_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_max[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255);
 	vt8231_write_value(client, regtempmax[0], data->temp_max[0]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t set_temp0_min(struct device *dev, struct device_attribute *attr,
@@ -364,10 +365,10 @@
 	struct vt8231_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_min[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255);
 	vt8231_write_value(client, regtempmin[0], data->temp_min[0]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -407,10 +408,10 @@
 	struct vt8231_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_max[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255);
 	vt8231_write_value(client, regtempmax[nr], data->temp_max[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
@@ -422,10 +423,10 @@
 	struct vt8231_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_min[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255);
 	vt8231_write_value(client, regtempmin[nr], data->temp_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -520,10 +521,10 @@
 	struct vt8231_data *data = i2c_get_clientdata(client);
 	int val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
 	vt8231_write_value(client, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -539,7 +540,7 @@
 	long min = FAN_FROM_REG(data->fan_min[nr],
 				 DIV_FROM_REG(data->fan_div[nr]));
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	switch (val) {
 	case 1: data->fan_div[nr] = 0; break;
 	case 2: data->fan_div[nr] = 1; break;
@@ -548,7 +549,7 @@
 	default:
 		dev_err(&client->dev, "fan_div value %ld not supported."
 		        "Choose one of 1, 2, 4 or 8!\n", val);
-		up(&data->update_lock);
+		mutex_unlock(&data->update_lock);
 		return -EINVAL;
 	}
 
@@ -558,7 +559,7 @@
 
 	old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
 	vt8231_write_value(client, VT8231_REG_FANDIV, old);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -660,7 +661,7 @@
 	/* Fill in the remaining client fields and put into the global list */
 	strlcpy(client->name, "vt8231", I2C_NAME_SIZE);
 
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(client)))
@@ -745,7 +746,7 @@
 	int i;
 	u16 low;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 	    || !data->valid) {
@@ -804,7 +805,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/w83627ehf.c newtree/drivers/hwmon/w83627ehf.c
--- oldtree/drivers/hwmon/w83627ehf.c	2006-02-19 11:41:02.176012296 +0000
+++ newtree/drivers/hwmon/w83627ehf.c	2006-02-21 15:58:14.395958040 +0000
@@ -42,7 +42,9 @@
 #include <linux/i2c.h>
 #include <linux/i2c-isa.h>
 #include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 #include "lm75.h"
 
@@ -177,9 +179,9 @@
 struct w83627ehf_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore lock;
+	struct mutex lock;
 
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 
@@ -230,7 +232,7 @@
 	struct w83627ehf_data *data = i2c_get_clientdata(client);
 	int res, word_sized = is_word_sized(reg);
 
-	down(&data->lock);
+	mutex_lock(&data->lock);
 
 	w83627ehf_set_bank(client, reg);
 	outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
@@ -242,7 +244,7 @@
 	}
 	w83627ehf_reset_bank(client, reg);
 
-	up(&data->lock);
+	mutex_unlock(&data->lock);
 
 	return res;
 }
@@ -252,7 +254,7 @@
 	struct w83627ehf_data *data = i2c_get_clientdata(client);
 	int word_sized = is_word_sized(reg);
 
-	down(&data->lock);
+	mutex_lock(&data->lock);
 
 	w83627ehf_set_bank(client, reg);
 	outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
@@ -264,7 +266,7 @@
 	outb_p(value & 0xff, client->addr + DATA_REG_OFFSET);
 	w83627ehf_reset_bank(client, reg);
 
-	up(&data->lock);
+	mutex_unlock(&data->lock);
 	return 0;
 }
 
@@ -322,7 +324,7 @@
 	struct w83627ehf_data *data = i2c_get_clientdata(client);
 	int i;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ)
 	 || !data->valid) {
@@ -397,7 +399,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return data;
 }
 
@@ -407,9 +409,12 @@
 
 #define show_fan_reg(reg) \
 static ssize_t \
-show_##reg(struct device *dev, char *buf, int nr) \
+show_##reg(struct device *dev, struct device_attribute *attr, \
+	   char *buf) \
 { \
 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	int nr = sensor_attr->index; \
 	return sprintf(buf, "%d\n", \
 		       fan_from_reg(data->reg[nr], \
 				    div_from_reg(data->fan_div[nr]))); \
@@ -418,23 +423,28 @@
 show_fan_reg(fan_min);
 
 static ssize_t
-show_fan_div(struct device *dev, char *buf, int nr)
+show_fan_div(struct device *dev, struct device_attribute *attr,
+	     char *buf)
 {
 	struct w83627ehf_data *data = w83627ehf_update_device(dev);
-	return sprintf(buf, "%u\n",
-		       div_from_reg(data->fan_div[nr]));
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
 }
 
 static ssize_t
-store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
+store_fan_min(struct device *dev, struct device_attribute *attr,
+	      const char *buf, size_t count)
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct w83627ehf_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
 	unsigned int val = simple_strtoul(buf, NULL, 10);
 	unsigned int reg;
 	u8 new_div;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	if (!val) {
 		/* No min limit, alarm disabled */
 		data->fan_min[nr] = 255;
@@ -482,63 +492,46 @@
 	}
 	w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr],
 			      data->fan_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return count;
 }
 
-#define sysfs_fan_offset(offset) \
-static ssize_t \
-show_reg_fan_##offset(struct device *dev, struct device_attribute *attr, \
-		      char *buf) \
-{ \
-	return show_fan(dev, buf, offset-1); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
-		   show_reg_fan_##offset, NULL);
+static struct sensor_device_attribute sda_fan_input[] = {
+	SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
+	SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
+	SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
+	SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
+	SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
+};
 
-#define sysfs_fan_min_offset(offset) \
-static ssize_t \
-show_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \
-			   char *buf) \
-{ \
-	return show_fan_min(dev, buf, offset-1); \
-} \
-static ssize_t \
-store_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \
-			    const char *buf, size_t count) \
-{ \
-	return store_fan_min(dev, buf, count, offset-1); \
-} \
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
-		   show_reg_fan##offset##_min, \
-		   store_reg_fan##offset##_min);
+static struct sensor_device_attribute sda_fan_min[] = {
+	SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    store_fan_min, 0),
+	SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    store_fan_min, 1),
+	SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    store_fan_min, 2),
+	SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    store_fan_min, 3),
+	SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
+		    store_fan_min, 4),
+};
 
-#define sysfs_fan_div_offset(offset) \
-static ssize_t \
-show_reg_fan##offset##_div(struct device *dev, struct device_attribute *attr, \
-			   char *buf) \
-{ \
-	return show_fan_div(dev, buf, offset - 1); \
-} \
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \
-		   show_reg_fan##offset##_div, NULL);
-
-sysfs_fan_offset(1);
-sysfs_fan_min_offset(1);
-sysfs_fan_div_offset(1);
-sysfs_fan_offset(2);
-sysfs_fan_min_offset(2);
-sysfs_fan_div_offset(2);
-sysfs_fan_offset(3);
-sysfs_fan_min_offset(3);
-sysfs_fan_div_offset(3);
-sysfs_fan_offset(4);
-sysfs_fan_min_offset(4);
-sysfs_fan_div_offset(4);
-sysfs_fan_offset(5);
-sysfs_fan_min_offset(5);
-sysfs_fan_div_offset(5);
+static struct sensor_device_attribute sda_fan_div[] = {
+	SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
+	SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
+	SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
+	SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
+	SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
+};
+
+static void device_create_file_fan(struct device *dev, int i)
+{
+	device_create_file(dev, &sda_fan_input[i].dev_attr);
+	device_create_file(dev, &sda_fan_div[i].dev_attr);
+	device_create_file(dev, &sda_fan_min[i].dev_attr);
+}
 
 #define show_temp1_reg(reg) \
 static ssize_t \
@@ -561,27 +554,24 @@
 	struct w83627ehf_data *data = i2c_get_clientdata(client); \
 	u32 val = simple_strtoul(buf, NULL, 10); \
  \
-	down(&data->update_lock); \
+	mutex_lock(&data->update_lock); \
 	data->temp1_##reg = temp1_to_reg(val); \
 	w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \
 			      data->temp1_##reg); \
-	up(&data->update_lock); \
+	mutex_unlock(&data->update_lock); \
 	return count; \
 }
 store_temp1_reg(OVER, max);
 store_temp1_reg(HYST, max_hyst);
 
-static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL);
-static DEVICE_ATTR(temp1_max, S_IRUGO| S_IWUSR,
-		   show_temp1_max, store_temp1_max);
-static DEVICE_ATTR(temp1_max_hyst, S_IRUGO| S_IWUSR,
-		   show_temp1_max_hyst, store_temp1_max_hyst);
-
 #define show_temp_reg(reg) \
 static ssize_t \
-show_##reg (struct device *dev, char *buf, int nr) \
+show_##reg(struct device *dev, struct device_attribute *attr, \
+	   char *buf) \
 { \
 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	int nr = sensor_attr->index; \
 	return sprintf(buf, "%d\n", \
 		       LM75_TEMP_FROM_REG(data->reg[nr])); \
 }
@@ -591,55 +581,42 @@
 
 #define store_temp_reg(REG, reg) \
 static ssize_t \
-store_##reg (struct device *dev, const char *buf, size_t count, int nr) \
+store_##reg(struct device *dev, struct device_attribute *attr, \
+	    const char *buf, size_t count) \
 { \
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct w83627ehf_data *data = i2c_get_clientdata(client); \
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	int nr = sensor_attr->index; \
 	u32 val = simple_strtoul(buf, NULL, 10); \
  \
-	down(&data->update_lock); \
+	mutex_lock(&data->update_lock); \
 	data->reg[nr] = LM75_TEMP_TO_REG(val); \
 	w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \
 			      data->reg[nr]); \
-	up(&data->update_lock); \
+	mutex_unlock(&data->update_lock); \
 	return count; \
 }
 store_temp_reg(OVER, temp_max);
 store_temp_reg(HYST, temp_max_hyst);
 
-#define sysfs_temp_offset(offset) \
-static ssize_t \
-show_reg_temp##offset (struct device *dev, struct device_attribute *attr, \
-		       char *buf) \
-{ \
-	return show_temp(dev, buf, offset - 2); \
-} \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
-		   show_reg_temp##offset, NULL);
-
-#define sysfs_temp_reg_offset(reg, offset) \
-static ssize_t \
-show_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \
-			      char *buf) \
-{ \
-	return show_temp_##reg(dev, buf, offset - 2); \
-} \
-static ssize_t \
-store_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \
-			       const char *buf, size_t count) \
-{ \
-	return store_temp_##reg(dev, buf, count, offset - 2); \
-} \
-static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \
-		   show_reg_temp##offset##_##reg, \
-		   store_reg_temp##offset##_##reg);
-
-sysfs_temp_offset(2);
-sysfs_temp_reg_offset(max, 2);
-sysfs_temp_reg_offset(max_hyst, 2);
-sysfs_temp_offset(3);
-sysfs_temp_reg_offset(max, 3);
-sysfs_temp_reg_offset(max_hyst, 3);
+static struct sensor_device_attribute sda_temp[] = {
+	SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
+	SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
+	SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1),
+	SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max,
+		    store_temp1_max, 0),
+	SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 0),
+	SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 1),
+	SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst,
+		    store_temp1_max_hyst, 0),
+	SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 0),
+	SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 1),
+};
 
 /*
  * Driver and client management
@@ -673,6 +650,7 @@
 {
 	struct i2c_client *client;
 	struct w83627ehf_data *data;
+	struct device *dev;
 	int i, err = 0;
 
 	if (!request_region(address + REGION_OFFSET, REGION_LENGTH,
@@ -689,14 +667,15 @@
 	client = &data->client;
 	i2c_set_clientdata(client, data);
 	client->addr = address;
-	init_MUTEX(&data->lock);
+	mutex_init(&data->lock);
 	client->adapter = adapter;
 	client->driver = &w83627ehf_driver;
 	client->flags = 0;
+	dev = &client->dev;
 
 	strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE);
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the i2c layer a new client has arrived */
 	if ((err = i2c_attach_client(client)))
@@ -720,42 +699,18 @@
 		data->has_fan |= (1 << 4);
 
 	/* Register sysfs hooks */
-	data->class_dev = hwmon_device_register(&client->dev);
+	data->class_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->class_dev)) {
 		err = PTR_ERR(data->class_dev);
 		goto exit_detach;
 	}
 
-	device_create_file(&client->dev, &dev_attr_fan1_input);
-	device_create_file(&client->dev, &dev_attr_fan1_min);
-	device_create_file(&client->dev, &dev_attr_fan1_div);
-	device_create_file(&client->dev, &dev_attr_fan2_input);
-	device_create_file(&client->dev, &dev_attr_fan2_min);
-	device_create_file(&client->dev, &dev_attr_fan2_div);
-	device_create_file(&client->dev, &dev_attr_fan3_input);
-	device_create_file(&client->dev, &dev_attr_fan3_min);
-	device_create_file(&client->dev, &dev_attr_fan3_div);
-
-	if (data->has_fan & (1 << 3)) {
-		device_create_file(&client->dev, &dev_attr_fan4_input);
-		device_create_file(&client->dev, &dev_attr_fan4_min);
-		device_create_file(&client->dev, &dev_attr_fan4_div);
-	}
-	if (data->has_fan & (1 << 4)) {
-		device_create_file(&client->dev, &dev_attr_fan5_input);
-		device_create_file(&client->dev, &dev_attr_fan5_min);
-		device_create_file(&client->dev, &dev_attr_fan5_div);
-	}
-
-	device_create_file(&client->dev, &dev_attr_temp1_input);
-	device_create_file(&client->dev, &dev_attr_temp1_max);
-	device_create_file(&client->dev, &dev_attr_temp1_max_hyst);
-	device_create_file(&client->dev, &dev_attr_temp2_input);
-	device_create_file(&client->dev, &dev_attr_temp2_max);
-	device_create_file(&client->dev, &dev_attr_temp2_max_hyst);
-	device_create_file(&client->dev, &dev_attr_temp3_input);
-	device_create_file(&client->dev, &dev_attr_temp3_max);
-	device_create_file(&client->dev, &dev_attr_temp3_max_hyst);
+	for (i = 0; i < 5; i++) {
+		if (data->has_fan & (1 << i))
+			device_create_file_fan(dev, i);
+	}
+	for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
+		device_create_file(dev, &sda_temp[i].dev_attr);
 
 	return 0;
 
diff -urN oldtree/drivers/hwmon/w83627hf.c newtree/drivers/hwmon/w83627hf.c
--- oldtree/drivers/hwmon/w83627hf.c	2006-02-19 11:41:02.177012144 +0000
+++ newtree/drivers/hwmon/w83627hf.c	2006-02-21 15:58:14.370961840 +0000
@@ -28,6 +28,7 @@
     w83627hf	9	3	2	3	0x20	0x5ca3	no	yes(LPC)
     w83627thf	7	3	3	3	0x90	0x5ca3	no	yes(LPC)
     w83637hf	7	3	3	3	0x80	0x5ca3	no	yes(LPC)
+    w83687thf	7	3	3	3	0x90	0x5ca3	no	yes(LPC)
     w83697hf	8	2	2	2	0x60	0x5ca3	no	yes(LPC)
 
     For other winbond chips, and for i2c support in the above chips,
@@ -46,6 +47,7 @@
 #include <linux/hwmon.h>
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 #include "lm75.h"
 
@@ -62,7 +64,7 @@
 static unsigned short address;
 
 /* Insmod parameters */
-enum chips { any_chip, w83627hf, w83627thf, w83697hf, w83637hf };
+enum chips { any_chip, w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
 
 static int reset;
 module_param(reset, bool, 0);
@@ -100,6 +102,10 @@
 #define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
 #define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
 
+#define W83687THF_VID_EN	0x29 /* w83687thf only */
+#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
+#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
+
 static inline void
 superio_outb(int reg, int val)
 {
@@ -138,6 +144,7 @@
 #define W627THF_DEVID 0x82
 #define W697_DEVID 0x60
 #define W637_DEVID 0x70
+#define W687THF_DEVID 0x85
 #define WINB_ACT_REG 0x30
 #define WINB_BASE_REG 0x60
 /* Constants specified below */
@@ -201,11 +208,11 @@
 #define W83627HF_REG_PWM1 0x5A
 #define W83627HF_REG_PWM2 0x5B
 
-#define W83627THF_REG_PWM1		0x01	/* 697HF and 637HF too */
-#define W83627THF_REG_PWM2		0x03	/* 697HF and 637HF too */
-#define W83627THF_REG_PWM3		0x11	/* 637HF too */
+#define W83627THF_REG_PWM1		0x01	/* 697HF/637HF/687THF too */
+#define W83627THF_REG_PWM2		0x03	/* 697HF/637HF/687THF too */
+#define W83627THF_REG_PWM3		0x11	/* 637HF/687THF too */
 
-#define W83627THF_REG_VRM_OVT_CFG 	0x18	/* 637HF too */
+#define W83627THF_REG_VRM_OVT_CFG 	0x18	/* 637HF/687THF too */
 
 static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };
 static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
@@ -285,10 +292,10 @@
 struct w83627hf_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore lock;
+	struct mutex lock;
 	enum chips type;
 
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 
@@ -318,7 +325,7 @@
 				   Default = 3435.
 				   Other Betas unimplemented */
 	u8 vrm;
-	u8 vrm_ovt;		/* Register value, 627thf & 637hf only */
+	u8 vrm_ovt;		/* Register value, 627THF/637HF/687THF only */
 };
 
 
@@ -360,12 +367,12 @@
 	 \
 	val = simple_strtoul(buf, NULL, 10); \
 	 \
-	down(&data->update_lock); \
+	mutex_lock(&data->update_lock); \
 	data->in_##reg[nr] = IN_TO_REG(val); \
 	w83627hf_write_value(client, W83781D_REG_IN_##REG(nr), \
 			    data->in_##reg[nr]); \
 	 \
-	up(&data->update_lock); \
+	mutex_unlock(&data->update_lock); \
 	return count; \
 }
 store_in_reg(MIN, min)
@@ -413,7 +420,8 @@
 	long in0;
 
 	if ((data->vrm_ovt & 0x01) &&
-		(w83627thf == data->type || w83637hf == data->type))
+		(w83627thf == data->type || w83637hf == data->type
+		 || w83687thf == data->type))
 
 		/* use VRM9 calculation */
 		in0 = (long)((reg * 488 + 70000 + 50) / 100);
@@ -451,10 +459,11 @@
 
 	val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	
 	if ((data->vrm_ovt & 0x01) &&
-		(w83627thf == data->type || w83637hf == data->type))
+		(w83627thf == data->type || w83637hf == data->type
+		 || w83687thf == data->type))
 
 		/* use VRM9 calculation */
 		data->in_min[0] =
@@ -465,7 +474,7 @@
 		data->in_min[0] = IN_TO_REG(val);
 
 	w83627hf_write_value(client, W83781D_REG_IN_MIN(0), data->in_min[0]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -478,10 +487,11 @@
 
 	val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if ((data->vrm_ovt & 0x01) &&
-		(w83627thf == data->type || w83637hf == data->type))
+		(w83627thf == data->type || w83637hf == data->type
+		 || w83687thf == data->type))
 		
 		/* use VRM9 calculation */
 		data->in_max[0] =
@@ -492,7 +502,7 @@
 		data->in_max[0] = IN_TO_REG(val);
 
 	w83627hf_write_value(client, W83781D_REG_IN_MAX(0), data->in_max[0]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -529,13 +539,13 @@
 
 	val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->fan_min[nr - 1] =
 	    FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1]));
 	w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr),
 			    data->fan_min[nr - 1]);
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -597,7 +607,7 @@
 	 \
 	val = simple_strtoul(buf, NULL, 10); \
 	 \
-	down(&data->update_lock); \
+	mutex_lock(&data->update_lock); \
 	 \
 	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
 		data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
@@ -609,7 +619,7 @@
 			data->temp_##reg); \
 	} \
 	 \
-	up(&data->update_lock); \
+	mutex_unlock(&data->update_lock); \
 	return count; \
 }
 store_temp_reg(OVER, max);
@@ -718,7 +728,7 @@
 
 	val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (update_mask == BEEP_MASK) {	/* We are storing beep_mask */
 		data->beep_mask = BEEP_MASK_TO_REG(val);
@@ -736,7 +746,7 @@
 	w83627hf_write_value(client, W83781D_REG_BEEP_INTS2,
 			    val2 | data->beep_enable << 7);
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -783,7 +793,7 @@
 	u8 reg;
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	/* Save fan_min */
 	min = FAN_FROM_REG(data->fan_min[nr],
@@ -805,7 +815,7 @@
 	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
 	w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -848,7 +858,7 @@
 
 	val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (data->type == w83627thf) {
 		/* bits 0-3 are reserved  in 627THF */
@@ -865,7 +875,7 @@
 				     data->pwm[nr - 1]);
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -907,7 +917,7 @@
 
 	val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	switch (val) {
 	case 1:		/* PII/Celeron diode */
@@ -941,7 +951,7 @@
 		break;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -980,7 +990,8 @@
 	if(val != W627_DEVID &&
 	   val != W627THF_DEVID &&
 	   val != W697_DEVID &&
-	   val != W637_DEVID) {
+	   val != W637_DEVID &&
+	   val != W687THF_DEVID) {
 		superio_exit();
 		return -ENODEV;
 	}
@@ -1034,6 +1045,8 @@
 		kind = w83627thf;
 	else if(val == W637_DEVID)
 		kind = w83637hf;
+	else if (val == W687THF_DEVID)
+		kind = w83687thf;
 	else {
 		dev_info(&adapter->dev,
 			 "Unsupported chip (dev_id=0x%02X).\n", val);
@@ -1057,7 +1070,7 @@
 	new_client = &data->client;
 	i2c_set_clientdata(new_client, data);
 	new_client->addr = address;
-	init_MUTEX(&data->lock);
+	mutex_init(&data->lock);
 	new_client->adapter = adapter;
 	new_client->driver = &w83627hf_driver;
 	new_client->flags = 0;
@@ -1071,13 +1084,15 @@
 		client_name = "w83697hf";
 	} else if (kind == w83637hf) {
 		client_name = "w83637hf";
+	} else if (kind == w83687thf) {
+		client_name = "w83687thf";
 	}
 
 	/* Fill in the remaining client fields and put into the global list */
 	strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
 	data->type = kind;
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -1106,7 +1121,7 @@
 	device_create_file_in(new_client, 2);
 	device_create_file_in(new_client, 3);
 	device_create_file_in(new_client, 4);
-	if (kind != w83627thf && kind != w83637hf) {
+	if (kind == w83627hf || kind == w83697hf) {
 		device_create_file_in(new_client, 5);
 		device_create_file_in(new_client, 6);
 	}
@@ -1139,7 +1154,7 @@
 
 	device_create_file_pwm(new_client, 1);
 	device_create_file_pwm(new_client, 2);
-	if (kind == w83627thf || kind == w83637hf)
+	if (kind == w83627thf || kind == w83637hf || kind == w83687thf)
 		device_create_file_pwm(new_client, 3);
 
 	device_create_file_sensor(new_client, 1);
@@ -1187,7 +1202,7 @@
 	struct w83627hf_data *data = i2c_get_clientdata(client);
 	int res, word_sized;
 
-	down(&data->lock);
+	mutex_lock(&data->lock);
 	word_sized = (((reg & 0xff00) == 0x100)
 		   || ((reg & 0xff00) == 0x200))
 		  && (((reg & 0x00ff) == 0x50)
@@ -1213,7 +1228,7 @@
 		       client->addr + W83781D_ADDR_REG_OFFSET);
 		outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
 	}
-	up(&data->lock);
+	mutex_unlock(&data->lock);
 	return res;
 }
 
@@ -1247,12 +1262,39 @@
 	return res;
 }
 
+static int w83687thf_read_vid(struct i2c_client *client)
+{
+	int res = 0xff;
+
+	superio_enter();
+	superio_select(W83627HF_LD_HWM);
+
+	/* Make sure these GPIO pins are enabled */
+	if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
+		dev_dbg(&client->dev, "VID disabled, no VID function\n");
+		goto exit;
+	}
+
+	/* Make sure the pins are configured for input */
+	if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
+		dev_dbg(&client->dev, "VID configured as output, "
+			"no VID function\n");
+		goto exit;
+	}
+
+	res = superio_inb(W83687THF_VID_DATA) & 0x3f;
+
+exit:
+	superio_exit();
+	return res;
+}
+
 static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value)
 {
 	struct w83627hf_data *data = i2c_get_clientdata(client);
 	int word_sized;
 
-	down(&data->lock);
+	mutex_lock(&data->lock);
 	word_sized = (((reg & 0xff00) == 0x100)
 		   || ((reg & 0xff00) == 0x200))
 		  && (((reg & 0x00ff) == 0x53)
@@ -1277,7 +1319,7 @@
 		       client->addr + W83781D_ADDR_REG_OFFSET);
 		outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
 	}
-	up(&data->lock);
+	mutex_unlock(&data->lock);
 	return 0;
 }
 
@@ -1324,10 +1366,13 @@
 		data->vid = (lo & 0x0f) | ((hi & 0x01) << 4);
 	} else if (w83627thf == data->type) {
 		data->vid = w83627thf_read_gpio5(client);
+	} else if (w83687thf == data->type) {
+		data->vid = w83687thf_read_vid(client);
 	}
 
 	/* Read VRM & OVT Config only once */
-	if (w83627thf == data->type || w83637hf == data->type) {
+	if (w83627thf == data->type || w83637hf == data->type
+	 || w83687thf == data->type) {
 		data->vrm_ovt = 
 			w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG);
 	}
@@ -1387,14 +1432,14 @@
 	struct w83627hf_data *data = i2c_get_clientdata(client);
 	int i;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 	    || !data->valid) {
 		for (i = 0; i <= 8; i++) {
 			/* skip missing sensors */
 			if (((data->type == w83697hf) && (i == 1)) ||
-			    ((data->type == w83627thf || data->type == w83637hf)
+			    ((data->type != w83627hf && data->type != w83697hf)
 			    && (i == 5 || i == 6)))
 				continue;
 			data->in[i] =
@@ -1470,7 +1515,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/w83781d.c newtree/drivers/hwmon/w83781d.c
--- oldtree/drivers/hwmon/w83781d.c	2006-02-19 11:41:02.178011992 +0000
+++ newtree/drivers/hwmon/w83781d.c	2006-02-21 15:58:14.430952720 +0000
@@ -42,6 +42,7 @@
 #include <linux/hwmon.h>
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 #include "lm75.h"
 
@@ -56,6 +57,10 @@
 I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
 		    "{bus, clientaddr, subclientaddr1, subclientaddr2}");
 
+static int reset;
+module_param(reset, bool, 0);
+MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
+
 static int init = 1;
 module_param(init, bool, 0);
 MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
@@ -226,10 +231,10 @@
 struct w83781d_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore lock;
+	struct mutex lock;
 	enum chips type;
 
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 
@@ -311,11 +316,11 @@
 	 \
 	val = simple_strtoul(buf, NULL, 10) / 10; \
 	 \
-	down(&data->update_lock); \
+	mutex_lock(&data->update_lock); \
 	data->in_##reg[nr] = IN_TO_REG(val); \
 	w83781d_write_value(client, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \
 	 \
-	up(&data->update_lock); \
+	mutex_unlock(&data->update_lock); \
 	return count; \
 }
 store_in_reg(MIN, min);
@@ -381,13 +386,13 @@
 
 	val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->fan_min[nr - 1] =
 	    FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1]));
 	w83781d_write_value(client, W83781D_REG_FAN_MIN(nr),
 			    data->fan_min[nr - 1]);
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -446,7 +451,7 @@
 	 \
 	val = simple_strtol(buf, NULL, 10); \
 	 \
-	down(&data->update_lock); \
+	mutex_lock(&data->update_lock); \
 	 \
 	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
 		data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
@@ -458,7 +463,7 @@
 			data->temp_##reg); \
 	} \
 	 \
-	up(&data->update_lock); \
+	mutex_unlock(&data->update_lock); \
 	return count; \
 }
 store_temp_reg(OVER, max);
@@ -571,7 +576,7 @@
 
 	val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (update_mask == BEEP_MASK) {	/* We are storing beep_mask */
 		data->beep_mask = BEEP_MASK_TO_REG(val, data->type);
@@ -592,7 +597,7 @@
 	w83781d_write_value(client, W83781D_REG_BEEP_INTS2,
 			    val2 | data->beep_enable << 7);
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -637,7 +642,7 @@
 	u8 reg;
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	
 	/* Save fan_min */
 	min = FAN_FROM_REG(data->fan_min[nr],
@@ -662,7 +667,7 @@
 	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
 	w83781d_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -709,10 +714,10 @@
 
 	val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->pwm[nr - 1] = PWM_TO_REG(val);
 	w83781d_write_value(client, W83781D_REG_PWM(nr), data->pwm[nr - 1]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -725,7 +730,7 @@
 
 	val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	switch (val) {
 	case 0:
@@ -742,11 +747,11 @@
 		break;
 
 	default:
-		up(&data->update_lock);
+		mutex_unlock(&data->update_lock);
 		return -EINVAL;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -808,7 +813,7 @@
 
 	val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	switch (val) {
 	case 1:		/* PII/Celeron diode */
@@ -841,7 +846,7 @@
 		break;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -1073,7 +1078,7 @@
 	new_client = &data->client;
 	i2c_set_clientdata(new_client, data);
 	new_client->addr = address;
-	init_MUTEX(&data->lock);
+	mutex_init(&data->lock);
 	new_client->adapter = adapter;
 	new_client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver;
 	new_client->flags = 0;
@@ -1178,7 +1183,7 @@
 	data->type = kind;
 
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -1325,7 +1330,7 @@
 	int res, word_sized, bank;
 	struct i2c_client *cl;
 
-	down(&data->lock);
+	mutex_lock(&data->lock);
 	if (i2c_is_isa_client(client)) {
 		word_sized = (((reg & 0xff00) == 0x100)
 			      || ((reg & 0xff00) == 0x200))
@@ -1383,7 +1388,7 @@
 		if (bank > 2)
 			i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
 	}
-	up(&data->lock);
+	mutex_unlock(&data->lock);
 	return res;
 }
 
@@ -1394,7 +1399,7 @@
 	int word_sized, bank;
 	struct i2c_client *cl;
 
-	down(&data->lock);
+	mutex_lock(&data->lock);
 	if (i2c_is_isa_client(client)) {
 		word_sized = (((reg & 0xff00) == 0x100)
 			      || ((reg & 0xff00) == 0x200))
@@ -1447,7 +1452,7 @@
 		if (bank > 2)
 			i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
 	}
-	up(&data->lock);
+	mutex_unlock(&data->lock);
 	return 0;
 }
 
@@ -1459,8 +1464,17 @@
 	int type = data->type;
 	u8 tmp;
 
-	if (init && type != as99127f) {	/* this resets registers we don't have
+	if (reset && type != as99127f) { /* this resets registers we don't have
 					   documentation for on the as99127f */
+		/* Resetting the chip has been the default for a long time,
+		   but it causes the BIOS initializations (fan clock dividers,
+		   thermal sensor types...) to be lost, so it is now optional.
+		   It might even go away if nobody reports it as being useful,
+		   as I see very little reason why this would be needed at
+		   all. */
+		dev_info(&client->dev, "If reset=1 solved a problem you were "
+			 "having, please report!\n");
+
 		/* save these registers */
 		i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG);
 		p = w83781d_read_value(client, W83781D_REG_PWMCLK12);
@@ -1477,6 +1491,13 @@
 		w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0);
 	}
 
+	/* Disable power-on abnormal beep, as advised by the datasheet.
+	   Already done if reset=1. */
+	if (init && !reset && type != as99127f) {
+		i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG);
+		w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80);
+	}
+
 	data->vrm = vid_which_vrm();
 
 	if ((type != w83781d) && (type != as99127f)) {
@@ -1533,7 +1554,7 @@
 	struct w83781d_data *data = i2c_get_clientdata(client);
 	int i;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 	    || !data->valid) {
@@ -1641,7 +1662,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/hwmon/w83792d.c newtree/drivers/hwmon/w83792d.c
--- oldtree/drivers/hwmon/w83792d.c	2006-02-19 11:41:02.180011688 +0000
+++ newtree/drivers/hwmon/w83792d.c	2006-02-21 15:58:14.219984792 +0000
@@ -43,6 +43,7 @@
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
@@ -271,7 +272,7 @@
 	struct class_device *class_dev;
 	enum chips type;
 
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 
@@ -382,30 +383,40 @@
 store_in_reg(MIN, min);
 store_in_reg(MAX, max);
 
-#define sysfs_in_reg(offset) \
-static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in, \
-				NULL, offset); \
-static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
-				show_in_min, store_in_min, offset); \
-static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
-				show_in_max, store_in_max, offset);
-
-sysfs_in_reg(0);
-sysfs_in_reg(1);
-sysfs_in_reg(2);
-sysfs_in_reg(3);
-sysfs_in_reg(4);
-sysfs_in_reg(5);
-sysfs_in_reg(6);
-sysfs_in_reg(7);
-sysfs_in_reg(8);
-
-#define device_create_file_in(client, offset) \
-do { \
-device_create_file(&client->dev, &sensor_dev_attr_in##offset##_input.dev_attr); \
-device_create_file(&client->dev, &sensor_dev_attr_in##offset##_max.dev_attr); \
-device_create_file(&client->dev, &sensor_dev_attr_in##offset##_min.dev_attr); \
-} while (0)
+static struct sensor_device_attribute sda_in_input[] = {
+	SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
+	SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
+	SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
+	SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
+	SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
+	SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
+	SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
+	SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
+	SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
+};
+static struct sensor_device_attribute sda_in_min[] = {
+       SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
+       SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
+       SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
+       SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
+       SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
+       SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
+       SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
+       SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
+       SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
+};
+static struct sensor_device_attribute sda_in_max[] = {
+       SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
+       SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
+       SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
+       SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
+       SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
+       SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
+       SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
+       SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
+       SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
+};
+
 
 #define show_fan_reg(reg) \
 static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
@@ -486,28 +497,33 @@
 	return count;
 }
 
-#define sysfs_fan(offset) \
-static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan, NULL, \
-				offset); \
-static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
-				show_fan_div, store_fan_div, offset); \
-static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
-				show_fan_min, store_fan_min, offset);
-
-sysfs_fan(1);
-sysfs_fan(2);
-sysfs_fan(3);
-sysfs_fan(4);
-sysfs_fan(5);
-sysfs_fan(6);
-sysfs_fan(7);
-
-#define device_create_file_fan(client, offset) \
-do { \
-device_create_file(&client->dev, &sensor_dev_attr_fan##offset##_input.dev_attr); \
-device_create_file(&client->dev, &sensor_dev_attr_fan##offset##_div.dev_attr); \
-device_create_file(&client->dev, &sensor_dev_attr_fan##offset##_min.dev_attr); \
-} while (0)
+static struct sensor_device_attribute sda_fan_input[] = {
+	SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 1),
+	SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 2),
+	SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 3),
+	SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 4),
+	SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 5),
+	SENSOR_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 6),
+	SENSOR_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 7),
+};
+static struct sensor_device_attribute sda_fan_min[] = {
+	SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 1),
+	SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 2),
+	SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 3),
+	SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 4),
+	SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 5),
+	SENSOR_ATTR(fan6_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 6),
+	SENSOR_ATTR(fan7_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 7),
+};
+static struct sensor_device_attribute sda_fan_div[] = {
+	SENSOR_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 1),
+	SENSOR_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 2),
+	SENSOR_ATTR(fan3_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 3),
+	SENSOR_ATTR(fan4_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 4),
+	SENSOR_ATTR(fan5_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 5),
+	SENSOR_ATTR(fan6_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 6),
+	SENSOR_ATTR(fan7_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 7),
+};
 
 
 /* read/write the temperature1, includes measured value and limits */
@@ -539,21 +555,6 @@
 	return count;
 }
 
-
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0);
-static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1,
-				store_temp1, 1);
-static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1,
-				store_temp1, 2);
-
-#define device_create_file_temp1(client) \
-do { \
-device_create_file(&client->dev, &sensor_dev_attr_temp1_input.dev_attr); \
-device_create_file(&client->dev, &sensor_dev_attr_temp1_max.dev_attr); \
-device_create_file(&client->dev, &sensor_dev_attr_temp1_max_hyst.dev_attr); \
-} while (0)
-
-
 /* read/write the temperature2-3, includes measured value and limits */
 
 static ssize_t show_temp23(struct device *dev, struct device_attribute *attr,
@@ -590,25 +591,23 @@
 	return count;
 }
 
-#define sysfs_temp23(name,idx) \
-static SENSOR_DEVICE_ATTR_2(name##_input, S_IRUGO, show_temp23, NULL, \
-				idx, 0); \
-static SENSOR_DEVICE_ATTR_2(name##_max, S_IRUGO | S_IWUSR, \
-				show_temp23, store_temp23, idx, 2); \
-static SENSOR_DEVICE_ATTR_2(name##_max_hyst, S_IRUGO | S_IWUSR, \
-				show_temp23, store_temp23, idx, 4);
-
-sysfs_temp23(temp2,0)
-sysfs_temp23(temp3,1)
-
-#define device_create_file_temp_add(client, offset) \
-do { \
-device_create_file(&client->dev, &sensor_dev_attr_temp##offset##_input.dev_attr); \
-device_create_file(&client->dev, &sensor_dev_attr_temp##offset##_max.dev_attr); \
-device_create_file(&client->dev, \
-&sensor_dev_attr_temp##offset##_max_hyst.dev_attr); \
-} while (0)
+static struct sensor_device_attribute_2 sda_temp_input[] = {
+	SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp1, NULL, 0, 0),
+	SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp23, NULL, 0, 0),
+	SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp23, NULL, 1, 0),
+};
 
+static struct sensor_device_attribute_2 sda_temp_max[] = {
+	SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp1, store_temp1, 0, 1),
+	SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 0, 2),
+	SENSOR_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 1, 2),
+};
+
+static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
+	SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1, store_temp1, 0, 2),
+	SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 0, 4),
+	SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 1, 4),
+};
 
 /* get reatime status of all sensors items: voltage, temp, fan */
 static ssize_t
@@ -620,10 +619,6 @@
 
 static
 DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
-#define device_create_file_alarms(client) \
-device_create_file(&client->dev, &dev_attr_alarms);
-
-
 
 static ssize_t
 show_pwm(struct device *dev, struct device_attribute *attr,
@@ -711,26 +706,19 @@
 	return count;
 }
 
-#define sysfs_pwm(offset) \
-static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
-				show_pwm, store_pwm, offset); \
-static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
-				show_pwmenable, store_pwmenable, offset); \
-
-sysfs_pwm(1);
-sysfs_pwm(2);
-sysfs_pwm(3);
-
-
-#define device_create_file_pwm(client, offset) \
-do { \
-device_create_file(&client->dev, &sensor_dev_attr_pwm##offset.dev_attr); \
-} while (0)
-
-#define device_create_file_pwmenable(client, offset) \
-do { \
-device_create_file(&client->dev, &sensor_dev_attr_pwm##offset##_enable.dev_attr); \
-} while (0)
+static struct sensor_device_attribute sda_pwm[] = {
+	SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
+	SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
+	SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
+};
+static struct sensor_device_attribute sda_pwm_enable[] = {
+	SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+		    show_pwmenable, store_pwmenable, 1),
+	SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
+		    show_pwmenable, store_pwmenable, 2),
+	SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO,
+		    show_pwmenable, store_pwmenable, 3),
+};
 
 
 static ssize_t
@@ -764,18 +752,14 @@
 	return count;
 }
 
-#define sysfs_pwm_mode(offset) \
-static SENSOR_DEVICE_ATTR(pwm##offset##_mode, S_IRUGO | S_IWUSR, \
-				show_pwm_mode, store_pwm_mode, offset);
-
-sysfs_pwm_mode(1);
-sysfs_pwm_mode(2);
-sysfs_pwm_mode(3);
-
-#define device_create_file_pwm_mode(client, offset) \
-do { \
-device_create_file(&client->dev, &sensor_dev_attr_pwm##offset##_mode.dev_attr); \
-} while (0)
+static struct sensor_device_attribute sda_pwm_mode[] = {
+	SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO,
+		    show_pwm_mode, store_pwm_mode, 1),
+	SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO,
+		    show_pwm_mode, store_pwm_mode, 2),
+	SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO,
+		    show_pwm_mode, store_pwm_mode, 3),
+};
 
 
 static ssize_t
@@ -788,12 +772,6 @@
 
 static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL);
 
-#define device_create_file_chassis(client) \
-do { \
-device_create_file(&client->dev, &dev_attr_chassis); \
-} while (0)
-
-
 static ssize_t
 show_chassis_clear(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -824,13 +802,6 @@
 static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR,
 		show_chassis_clear, store_chassis_clear);
 
-#define device_create_file_chassis_clear(client) \
-do { \
-device_create_file(&client->dev, &dev_attr_chassis_clear); \
-} while (0)
-
-
-
 /* For Smart Fan I / Thermal Cruise */
 static ssize_t
 show_thermal_cruise(struct device *dev, struct device_attribute *attr,
@@ -864,20 +835,14 @@
 	return count;
 }
 
-#define sysfs_thermal_cruise(offset) \
-static SENSOR_DEVICE_ATTR(thermal_cruise##offset, S_IRUGO | S_IWUSR, \
-			show_thermal_cruise, store_thermal_cruise, offset);
-
-sysfs_thermal_cruise(1);
-sysfs_thermal_cruise(2);
-sysfs_thermal_cruise(3);
-
-#define device_create_file_thermal_cruise(client, offset) \
-do { \
-device_create_file(&client->dev, \
-&sensor_dev_attr_thermal_cruise##offset.dev_attr); \
-} while (0)
-
+static struct sensor_device_attribute sda_thermal_cruise[] = {
+	SENSOR_ATTR(thermal_cruise1, S_IWUSR | S_IRUGO,
+		    show_thermal_cruise, store_thermal_cruise, 1),
+	SENSOR_ATTR(thermal_cruise2, S_IWUSR | S_IRUGO,
+		    show_thermal_cruise, store_thermal_cruise, 2),
+	SENSOR_ATTR(thermal_cruise3, S_IWUSR | S_IRUGO,
+		    show_thermal_cruise, store_thermal_cruise, 3),
+};
 
 /* For Smart Fan I/Thermal Cruise and Smart Fan II */
 static ssize_t
@@ -916,19 +881,14 @@
 	return count;
 }
 
-#define sysfs_tolerance(offset) \
-static SENSOR_DEVICE_ATTR(tolerance##offset, S_IRUGO | S_IWUSR, \
-				show_tolerance, store_tolerance, offset);
-
-sysfs_tolerance(1);
-sysfs_tolerance(2);
-sysfs_tolerance(3);
-
-#define device_create_file_tolerance(client, offset) \
-do { \
-device_create_file(&client->dev, &sensor_dev_attr_tolerance##offset.dev_attr); \
-} while (0)
-
+static struct sensor_device_attribute sda_tolerance[] = {
+	SENSOR_ATTR(tolerance1, S_IWUSR | S_IRUGO,
+		    show_tolerance, store_tolerance, 1),
+	SENSOR_ATTR(tolerance2, S_IWUSR | S_IRUGO,
+		    show_tolerance, store_tolerance, 2),
+	SENSOR_ATTR(tolerance3, S_IWUSR | S_IRUGO,
+		    show_tolerance, store_tolerance, 3),
+};
 
 /* For Smart Fan II */
 static ssize_t
@@ -964,28 +924,34 @@
 	return count;
 }
 
-#define sysfs_sf2_point(offset, index) \
-static SENSOR_DEVICE_ATTR_2(sf2_point##offset##_fan##index, S_IRUGO | S_IWUSR, \
-				show_sf2_point, store_sf2_point, offset, index);
-
-sysfs_sf2_point(1, 1);	/* Fan1 */
-sysfs_sf2_point(2, 1);	/* Fan1 */
-sysfs_sf2_point(3, 1);	/* Fan1 */
-sysfs_sf2_point(4, 1);	/* Fan1 */
-sysfs_sf2_point(1, 2);	/* Fan2 */
-sysfs_sf2_point(2, 2);	/* Fan2 */
-sysfs_sf2_point(3, 2);	/* Fan2 */
-sysfs_sf2_point(4, 2);	/* Fan2 */
-sysfs_sf2_point(1, 3);	/* Fan3 */
-sysfs_sf2_point(2, 3);	/* Fan3 */
-sysfs_sf2_point(3, 3);	/* Fan3 */
-sysfs_sf2_point(4, 3);	/* Fan3 */
-
-#define device_create_file_sf2_point(client, offset, index) \
-do { \
-device_create_file(&client->dev, \
-&sensor_dev_attr_sf2_point##offset##_fan##index.dev_attr); \
-} while (0)
+static struct sensor_device_attribute_2 sda_sf2_point[] = {
+	SENSOR_ATTR_2(sf2_point1_fan1, S_IRUGO | S_IWUSR,
+		      show_sf2_point, store_sf2_point, 1, 1),
+	SENSOR_ATTR_2(sf2_point2_fan1, S_IRUGO | S_IWUSR,
+		      show_sf2_point, store_sf2_point, 2, 1),
+	SENSOR_ATTR_2(sf2_point3_fan1, S_IRUGO | S_IWUSR,
+		      show_sf2_point, store_sf2_point, 3, 1),
+	SENSOR_ATTR_2(sf2_point4_fan1, S_IRUGO | S_IWUSR,
+		      show_sf2_point, store_sf2_point, 4, 1),
+
+	SENSOR_ATTR_2(sf2_point1_fan2, S_IRUGO | S_IWUSR,
+		      show_sf2_point, store_sf2_point, 1, 2),
+	SENSOR_ATTR_2(sf2_point2_fan2, S_IRUGO | S_IWUSR,
+		      show_sf2_point, store_sf2_point, 2, 2),
+	SENSOR_ATTR_2(sf2_point3_fan2, S_IRUGO | S_IWUSR,
+		      show_sf2_point, store_sf2_point, 3, 2),
+	SENSOR_ATTR_2(sf2_point4_fan2, S_IRUGO | S_IWUSR,
+		      show_sf2_point, store_sf2_point, 4, 2),
+
+	SENSOR_ATTR_2(sf2_point1_fan3, S_IRUGO | S_IWUSR,
+		      show_sf2_point, store_sf2_point, 1, 3),
+	SENSOR_ATTR_2(sf2_point2_fan3, S_IRUGO | S_IWUSR,
+		      show_sf2_point, store_sf2_point, 2, 3),
+	SENSOR_ATTR_2(sf2_point3_fan3, S_IRUGO | S_IWUSR,
+		      show_sf2_point, store_sf2_point, 3, 3),
+	SENSOR_ATTR_2(sf2_point4_fan3, S_IRUGO | S_IWUSR,
+		      show_sf2_point, store_sf2_point, 4, 3),
+};
 
 
 static ssize_t
@@ -1026,26 +992,28 @@
 	return count;
 }
 
-#define sysfs_sf2_level(offset, index) \
-static SENSOR_DEVICE_ATTR_2(sf2_level##offset##_fan##index, S_IRUGO | S_IWUSR, \
-				show_sf2_level, store_sf2_level, offset, index);
-
-sysfs_sf2_level(1, 1);	/* Fan1 */
-sysfs_sf2_level(2, 1);	/* Fan1 */
-sysfs_sf2_level(3, 1);	/* Fan1 */
-sysfs_sf2_level(1, 2);	/* Fan2 */
-sysfs_sf2_level(2, 2);	/* Fan2 */
-sysfs_sf2_level(3, 2);	/* Fan2 */
-sysfs_sf2_level(1, 3);	/* Fan3 */
-sysfs_sf2_level(2, 3);	/* Fan3 */
-sysfs_sf2_level(3, 3);	/* Fan3 */
-
-#define device_create_file_sf2_level(client, offset, index) \
-do { \
-device_create_file(&client->dev, \
-&sensor_dev_attr_sf2_level##offset##_fan##index.dev_attr); \
-} while (0)
-
+static struct sensor_device_attribute_2 sda_sf2_level[] = {
+	SENSOR_ATTR_2(sf2_level1_fan1, S_IRUGO | S_IWUSR,
+		      show_sf2_level, store_sf2_level, 1, 1),
+	SENSOR_ATTR_2(sf2_level2_fan1, S_IRUGO | S_IWUSR,
+		      show_sf2_level, store_sf2_level, 2, 1),
+	SENSOR_ATTR_2(sf2_level3_fan1, S_IRUGO | S_IWUSR,
+		      show_sf2_level, store_sf2_level, 3, 1),
+
+	SENSOR_ATTR_2(sf2_level1_fan2, S_IRUGO | S_IWUSR,
+		      show_sf2_level, store_sf2_level, 1, 2),
+	SENSOR_ATTR_2(sf2_level2_fan2, S_IRUGO | S_IWUSR,
+		      show_sf2_level, store_sf2_level, 2, 2),
+	SENSOR_ATTR_2(sf2_level3_fan2, S_IRUGO | S_IWUSR,
+		      show_sf2_level, store_sf2_level, 3, 2),
+
+	SENSOR_ATTR_2(sf2_level1_fan3, S_IRUGO | S_IWUSR,
+		      show_sf2_level, store_sf2_level, 1, 3),
+	SENSOR_ATTR_2(sf2_level2_fan3, S_IRUGO | S_IWUSR,
+		      show_sf2_level, store_sf2_level, 2, 3),
+	SENSOR_ATTR_2(sf2_level3_fan3, S_IRUGO | S_IWUSR,
+		      show_sf2_level, store_sf2_level, 3, 3),
+};
 
 /* This function is called when:
      * w83792d_driver is inserted (when this module is loaded), for each
@@ -1147,12 +1115,19 @@
 	return err;
 }
 
+static void device_create_file_fan(struct device *dev, int i)
+{
+	device_create_file(dev, &sda_fan_input[i].dev_attr);
+	device_create_file(dev, &sda_fan_div[i].dev_attr);
+	device_create_file(dev, &sda_fan_min[i].dev_attr);
+}
 
 static int
 w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
 {
 	int i = 0, val1 = 0, val2;
-	struct i2c_client *new_client;
+	struct i2c_client *client;
+	struct device *dev;
 	struct w83792d_data *data;
 	int err = 0;
 	const char *client_name = "";
@@ -1170,12 +1145,13 @@
 		goto ERROR0;
 	}
 
-	new_client = &data->client;
-	i2c_set_clientdata(new_client, data);
-	new_client->addr = address;
-	new_client->adapter = adapter;
-	new_client->driver = &w83792d_driver;
-	new_client->flags = 0;
+	client = &data->client;
+	dev = &client->dev;
+	i2c_set_clientdata(client, data);
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &w83792d_driver;
+	client->flags = 0;
 
 	/* Now, we do the remaining detection. */
 
@@ -1184,13 +1160,12 @@
 	   force_*=... parameter, and the Winbond will be reset to the right
 	   bank. */
 	if (kind < 0) {
-		if (w83792d_read_value(new_client, W83792D_REG_CONFIG) & 0x80) {
-			dev_warn(&new_client->dev, "Detection failed at step "
-				"3\n");
+		if (w83792d_read_value(client, W83792D_REG_CONFIG) & 0x80) {
+			dev_warn(dev, "Detection failed at step 3\n");
 			goto ERROR1;
 		}
-		val1 = w83792d_read_value(new_client, W83792D_REG_BANK);
-		val2 = w83792d_read_value(new_client, W83792D_REG_CHIPMAN);
+		val1 = w83792d_read_value(client, W83792D_REG_BANK);
+		val2 = w83792d_read_value(client, W83792D_REG_CHIPMAN);
 		/* Check for Winbond ID if in bank 0 */
 		if (!(val1 & 0x07)) {  /* is Bank0 */
 			if (((!(val1 & 0x80)) && (val2 != 0xa3)) ||
@@ -1200,34 +1175,33 @@
 		}
 		/* If Winbond chip, address of chip and W83792D_REG_I2C_ADDR
 		   should match */
-		if (w83792d_read_value(new_client,
+		if (w83792d_read_value(client,
 					W83792D_REG_I2C_ADDR) != address) {
-			dev_warn(&new_client->dev, "Detection failed "
-				"at step 5\n");
+			dev_warn(dev, "Detection failed at step 5\n");
 			goto ERROR1;
 		}
 	}
 
 	/* We have either had a force parameter, or we have already detected the
 	   Winbond. Put it now into bank 0 and Vendor ID High Byte */
-	w83792d_write_value(new_client,
+	w83792d_write_value(client,
 			    W83792D_REG_BANK,
-			    (w83792d_read_value(new_client,
+			    (w83792d_read_value(client,
 				W83792D_REG_BANK) & 0x78) | 0x80);
 
 	/* Determine the chip type. */
 	if (kind <= 0) {
 		/* get vendor ID */
-		val2 = w83792d_read_value(new_client, W83792D_REG_CHIPMAN);
+		val2 = w83792d_read_value(client, W83792D_REG_CHIPMAN);
 		if (val2 != 0x5c) {  /* the vendor is NOT Winbond */
 			goto ERROR1;
 		}
-		val1 = w83792d_read_value(new_client, W83792D_REG_WCHIPID);
+		val1 = w83792d_read_value(client, W83792D_REG_WCHIPID);
 		if (val1 == 0x7a) {
 			kind = w83792d;
 		} else {
 			if (kind == 0)
-					dev_warn(&new_client->dev,
+					dev_warn(dev,
 					"w83792d: Ignoring 'force' parameter for"
 					" unknown chip at adapter %d, address"
 					" 0x%02x\n", i2c_adapter_id(adapter),
@@ -1239,120 +1213,86 @@
 	if (kind == w83792d) {
 		client_name = "w83792d";
 	} else {
-		dev_err(&new_client->dev, "w83792d: Internal error: unknown"
+		dev_err(dev, "w83792d: Internal error: unknown"
 					  " kind (%d)?!?", kind);
 		goto ERROR1;
 	}
 
 	/* Fill in the remaining client fields and put into the global list */
-	strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
+	strlcpy(client->name, client_name, I2C_NAME_SIZE);
 	data->type = kind;
 
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
-	if ((err = i2c_attach_client(new_client)))
+	if ((err = i2c_attach_client(client)))
 		goto ERROR1;
 
 	if ((err = w83792d_detect_subclients(adapter, address,
-			kind, new_client)))
+			kind, client)))
 		goto ERROR2;
 
 	/* Initialize the chip */
-	w83792d_init_client(new_client);
+	w83792d_init_client(client);
 
 	/* A few vars need to be filled upon startup */
 	for (i = 0; i < 7; i++) {
-		data->fan_min[i] = w83792d_read_value(new_client,
+		data->fan_min[i] = w83792d_read_value(client,
 					W83792D_REG_FAN_MIN[i]);
 	}
 
 	/* Register sysfs hooks */
-	data->class_dev = hwmon_device_register(&new_client->dev);
+	data->class_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->class_dev)) {
 		err = PTR_ERR(data->class_dev);
 		goto ERROR3;
 	}
-	device_create_file_in(new_client, 0);
-	device_create_file_in(new_client, 1);
-	device_create_file_in(new_client, 2);
-	device_create_file_in(new_client, 3);
-	device_create_file_in(new_client, 4);
-	device_create_file_in(new_client, 5);
-	device_create_file_in(new_client, 6);
-	device_create_file_in(new_client, 7);
-	device_create_file_in(new_client, 8);
-
-	device_create_file_fan(new_client, 1);
-	device_create_file_fan(new_client, 2);
-	device_create_file_fan(new_client, 3);
+	for (i = 0; i < 9; i++) {
+		device_create_file(dev, &sda_in_input[i].dev_attr);
+		device_create_file(dev, &sda_in_max[i].dev_attr);
+		device_create_file(dev, &sda_in_min[i].dev_attr);
+	}
+	for (i = 0; i < 3; i++)
+		device_create_file_fan(dev, i);
 
 	/* Read GPIO enable register to check if pins for fan 4,5 are used as
 	   GPIO */
-	val1 = w83792d_read_value(new_client, W83792D_REG_GPIO_EN);
+	val1 = w83792d_read_value(client, W83792D_REG_GPIO_EN);
 	if (!(val1 & 0x40))
-		device_create_file_fan(new_client, 4);
+		device_create_file_fan(dev, 3);
 	if (!(val1 & 0x20))
-		device_create_file_fan(new_client, 5);
+		device_create_file_fan(dev, 4);
 
-	val1 = w83792d_read_value(new_client, W83792D_REG_PIN);
+	val1 = w83792d_read_value(client, W83792D_REG_PIN);
 	if (val1 & 0x40)
-		device_create_file_fan(new_client, 6);
+		device_create_file_fan(dev, 5);
 	if (val1 & 0x04)
-		device_create_file_fan(new_client, 7);
+		device_create_file_fan(dev, 6);
+
+	for (i = 0; i < 3; i++) {
+		device_create_file(dev, &sda_temp_input[i].dev_attr);
+		device_create_file(dev, &sda_temp_max[i].dev_attr);
+		device_create_file(dev, &sda_temp_max_hyst[i].dev_attr);
+		device_create_file(dev, &sda_thermal_cruise[i].dev_attr);
+		device_create_file(dev, &sda_tolerance[i].dev_attr);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(sda_pwm); i++) {
+		device_create_file(dev, &sda_pwm[i].dev_attr);
+		device_create_file(dev, &sda_pwm_enable[i].dev_attr);
+		device_create_file(dev, &sda_pwm_mode[i].dev_attr);
+	}
+
+	device_create_file(dev, &dev_attr_alarms);
+	device_create_file(dev, &dev_attr_chassis);
+	device_create_file(dev, &dev_attr_chassis_clear);
+
+	for (i = 0; i < ARRAY_SIZE(sda_sf2_point); i++)
+		device_create_file(dev, &sda_sf2_point[i].dev_attr);
 
-	device_create_file_temp1(new_client);		/* Temp1 */
-	device_create_file_temp_add(new_client, 2);	/* Temp2 */
-	device_create_file_temp_add(new_client, 3);	/* Temp3 */
-
-	device_create_file_alarms(new_client);
-
-	device_create_file_pwm(new_client, 1);
-	device_create_file_pwm(new_client, 2);
-	device_create_file_pwm(new_client, 3);
-
-	device_create_file_pwmenable(new_client, 1);
-	device_create_file_pwmenable(new_client, 2);
-	device_create_file_pwmenable(new_client, 3);
-
-	device_create_file_pwm_mode(new_client, 1);
-	device_create_file_pwm_mode(new_client, 2);
-	device_create_file_pwm_mode(new_client, 3);
-
-	device_create_file_chassis(new_client);
-	device_create_file_chassis_clear(new_client);
-
-	device_create_file_thermal_cruise(new_client, 1);
-	device_create_file_thermal_cruise(new_client, 2);
-	device_create_file_thermal_cruise(new_client, 3);
-
-	device_create_file_tolerance(new_client, 1);
-	device_create_file_tolerance(new_client, 2);
-	device_create_file_tolerance(new_client, 3);
-
-	device_create_file_sf2_point(new_client, 1, 1);	/* Fan1 */
-	device_create_file_sf2_point(new_client, 2, 1);	/* Fan1 */
-	device_create_file_sf2_point(new_client, 3, 1);	/* Fan1 */
-	device_create_file_sf2_point(new_client, 4, 1);	/* Fan1 */
-	device_create_file_sf2_point(new_client, 1, 2);	/* Fan2 */
-	device_create_file_sf2_point(new_client, 2, 2);	/* Fan2 */
-	device_create_file_sf2_point(new_client, 3, 2);	/* Fan2 */
-	device_create_file_sf2_point(new_client, 4, 2);	/* Fan2 */
-	device_create_file_sf2_point(new_client, 1, 3);	/* Fan3 */
-	device_create_file_sf2_point(new_client, 2, 3);	/* Fan3 */
-	device_create_file_sf2_point(new_client, 3, 3);	/* Fan3 */
-	device_create_file_sf2_point(new_client, 4, 3);	/* Fan3 */
-
-	device_create_file_sf2_level(new_client, 1, 1);	/* Fan1 */
-	device_create_file_sf2_level(new_client, 2, 1);	/* Fan1 */
-	device_create_file_sf2_level(new_client, 3, 1);	/* Fan1 */
-	device_create_file_sf2_level(new_client, 1, 2);	/* Fan2 */
-	device_create_file_sf2_level(new_client, 2, 2);	/* Fan2 */
-	device_create_file_sf2_level(new_client, 3, 2);	/* Fan2 */
-	device_create_file_sf2_level(new_client, 1, 3);	/* Fan3 */
-	device_create_file_sf2_level(new_client, 2, 3);	/* Fan3 */
-	device_create_file_sf2_level(new_client, 3, 3);	/* Fan3 */
+	for (i = 0; i < ARRAY_SIZE(sda_sf2_level); i++)
+		device_create_file(dev, &sda_sf2_level[i].dev_attr);
 
 	return 0;
 
@@ -1366,7 +1306,7 @@
 		kfree(data->lm75[1]);
 	}
 ERROR2:
-	i2c_detach_client(new_client);
+	i2c_detach_client(client);
 ERROR1:
 	kfree(data);
 ERROR0:
@@ -1434,7 +1374,7 @@
 	int i, j;
 	u8 reg_array_tmp[4], pwm_array_tmp[7], reg_tmp;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after
 	    (jiffies - data->last_updated, (unsigned long) (HZ * 3))
@@ -1545,7 +1485,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 #ifdef DEBUG
 	w83792d_print_debug(data, dev);
diff -urN oldtree/drivers/hwmon/w83l785ts.c newtree/drivers/hwmon/w83l785ts.c
--- oldtree/drivers/hwmon/w83l785ts.c	2006-02-19 11:41:02.181011536 +0000
+++ newtree/drivers/hwmon/w83l785ts.c	2006-02-21 15:58:14.220984640 +0000
@@ -39,6 +39,7 @@
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 
 /* How many retries on register read error */
 #define MAX_RETRIES	5
@@ -107,7 +108,7 @@
 struct w83l785ts_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid; /* zero until following fields are valid */
 	unsigned long last_updated; /* in jiffies */
 
@@ -221,7 +222,7 @@
 	/* We can fill in the remaining client fields. */
 	strlcpy(new_client->name, "w83l785ts", I2C_NAME_SIZE);
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Default values in case the first read fails (unlikely). */
 	data->temp[1] = data->temp[0] = 0;
@@ -299,7 +300,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct w83l785ts_data *data = i2c_get_clientdata(client);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (!data->valid || time_after(jiffies, data->last_updated + HZ * 2)) {
 		dev_dbg(&client->dev, "Updating w83l785ts data.\n");
@@ -312,7 +313,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff -urN oldtree/drivers/i2c/busses/Kconfig newtree/drivers/i2c/busses/Kconfig
--- oldtree/drivers/i2c/busses/Kconfig	2006-02-19 11:41:02.182011384 +0000
+++ newtree/drivers/i2c/busses/Kconfig	2006-02-21 15:58:14.044011544 +0000
@@ -389,10 +389,11 @@
 	  also be specified with a module parameter.
 
 config SCx200_ACB
-	tristate "NatSemi SCx200 ACCESS.bus"
-	depends on I2C && PCI
+	tristate "Geode ACCESS.bus support"
+	depends on X86_32 && I2C && PCI
 	help
-	  Enable the use of the ACCESS.bus controllers of a SCx200 processor.
+	  Enable the use of the ACCESS.bus controllers on the Geode SCx200 and
+	  SC1100 processors and the CS5535 and CS5536 Geode companion devices.
 
 	  If you don't know what to do here, say N.
 
diff -urN oldtree/drivers/i2c/busses/i2c-ali1535.c newtree/drivers/i2c/busses/i2c-ali1535.c
--- oldtree/drivers/i2c/busses/i2c-ali1535.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/i2c/busses/i2c-ali1535.c	2006-02-21 15:58:14.158994064 +0000
@@ -62,8 +62,8 @@
 #include <linux/ioport.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
-#include <asm/semaphore.h>
 
 
 /* ALI1535 SMBus address offsets */
@@ -136,7 +136,7 @@
 
 static struct pci_driver ali1535_driver;
 static unsigned short ali1535_smba;
-static DECLARE_MUTEX(i2c_ali1535_sem);
+static DEFINE_MUTEX(i2c_ali1535_mutex);
 
 /* Detect whether a ALI1535 can be found, and initialize it, where necessary.
    Note the differences between kernels with the old PCI BIOS interface and
@@ -345,7 +345,7 @@
 	int timeout;
 	s32 result = 0;
 
-	down(&i2c_ali1535_sem);
+	mutex_lock(&i2c_ali1535_mutex);
 	/* make sure SMBus is idle */
 	temp = inb_p(SMBHSTSTS);
 	for (timeout = 0;
@@ -460,7 +460,7 @@
 		break;
 	}
 EXIT:
-	up(&i2c_ali1535_sem);
+	mutex_unlock(&i2c_ali1535_mutex);
 	return result;
 }
 
diff -urN oldtree/drivers/i2c/busses/i2c-amd756-s4882.c newtree/drivers/i2c/busses/i2c-amd756-s4882.c
--- oldtree/drivers/i2c/busses/i2c-amd756-s4882.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/i2c/busses/i2c-amd756-s4882.c	2006-02-21 15:58:14.126998928 +0000
@@ -38,6 +38,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 
 extern struct i2c_adapter amd756_smbus;
 
@@ -45,7 +46,7 @@
 static struct i2c_algorithm *s4882_algo;
 
 /* Wrapper access functions for multiplexed SMBus */
-static struct semaphore amd756_lock;
+static struct mutex amd756_lock;
 
 static s32 amd756_access_virt0(struct i2c_adapter * adap, u16 addr,
 			       unsigned short flags, char read_write,
@@ -59,12 +60,12 @@
 	 || addr == 0x18)
 		return -1;
 
-	down(&amd756_lock);
+	mutex_lock(&amd756_lock);
 
 	error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write,
 					      command, size, data);
 
-	up(&amd756_lock);
+	mutex_unlock(&amd756_lock);
 
 	return error;
 }
@@ -87,7 +88,7 @@
 	if (addr != 0x4c && (addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30)
 		return -1;
 
-	down(&amd756_lock);
+	mutex_lock(&amd756_lock);
 
 	if (last_channels != channels) {
 		union i2c_smbus_data mplxdata;
@@ -105,7 +106,7 @@
 					      command, size, data);
 
 UNLOCK:
-	up(&amd756_lock);
+	mutex_unlock(&amd756_lock);
 	return error;
 }
 
@@ -166,7 +167,7 @@
 	}
 
 	printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4882\n");
-	init_MUTEX(&amd756_lock);
+	mutex_init(&amd756_lock);
 
 	/* Define the 5 virtual adapters and algorithms structures */
 	if (!(s4882_adapter = kzalloc(5 * sizeof(struct i2c_adapter),
diff -urN oldtree/drivers/i2c/busses/i2c-frodo.c newtree/drivers/i2c/busses/i2c-frodo.c
--- oldtree/drivers/i2c/busses/i2c-frodo.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/i2c/busses/i2c-frodo.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,85 +0,0 @@
-
-/*
- * linux/drivers/i2c/i2c-frodo.c
- *
- * Author: Abraham van der Merwe <abraham@2d3d.co.za>
- *
- * An I2C adapter driver for the 2d3D, Inc. StrongARM SA-1110
- * Development board (Frodo).
- *
- * This source code 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/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <asm/hardware.h>
-
-
-static void frodo_setsda (void *data,int state)
-{
-	if (state)
-		FRODO_CPLD_I2C |= FRODO_I2C_SDA_OUT;
-	else
-		FRODO_CPLD_I2C &= ~FRODO_I2C_SDA_OUT;
-}
-
-static void frodo_setscl (void *data,int state)
-{
-	if (state)
-		FRODO_CPLD_I2C |= FRODO_I2C_SCL_OUT;
-	else
-		FRODO_CPLD_I2C &= ~FRODO_I2C_SCL_OUT;
-}
-
-static int frodo_getsda (void *data)
-{
-	return ((FRODO_CPLD_I2C & FRODO_I2C_SDA_IN) != 0);
-}
-
-static int frodo_getscl (void *data)
-{
-	return ((FRODO_CPLD_I2C & FRODO_I2C_SCL_IN) != 0);
-}
-
-static struct i2c_algo_bit_data bit_frodo_data = {
-	.setsda		= frodo_setsda,
-	.setscl		= frodo_setscl,
-	.getsda		= frodo_getsda,
-	.getscl		= frodo_getscl,
-	.udelay		= 80,
-	.mdelay		= 80,
-	.timeout	= HZ
-};
-
-static struct i2c_adapter frodo_ops = {
-	.owner			= THIS_MODULE,
-	.id			= I2C_HW_B_FRODO,
-	.algo_data		= &bit_frodo_data,
-	.dev			= {
-		.name		= "Frodo adapter driver",
-	},
-};
-
-static int __init i2c_frodo_init (void)
-{
-	return i2c_bit_add_bus(&frodo_ops);
-}
-
-static void __exit i2c_frodo_exit (void)
-{
-	i2c_bit_del_bus(&frodo_ops);
-}
-
-MODULE_AUTHOR ("Abraham van der Merwe <abraham@2d3d.co.za>");
-MODULE_DESCRIPTION ("I2C-Bus adapter routines for Frodo");
-MODULE_LICENSE ("GPL");
-
-module_init (i2c_frodo_init);
-module_exit (i2c_frodo_exit);
-
diff -urN oldtree/drivers/i2c/busses/i2c-iop3xx.c newtree/drivers/i2c/busses/i2c-iop3xx.c
--- oldtree/drivers/i2c/busses/i2c-iop3xx.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/i2c/busses/i2c-iop3xx.c	2006-02-21 15:58:12.444254744 +0000
@@ -434,7 +434,7 @@
 iop3xx_i2c_probe(struct platform_device *pdev)
 {
 	struct resource *res;
-	int ret;
+	int ret, irq;
 	struct i2c_adapter *new_adapter;
 	struct i2c_algo_iop3xx_data *adapter_data;
 
@@ -470,7 +470,12 @@
 		goto release_region;
 	}
 
-	ret = request_irq(platform_get_irq(pdev, 0), iop3xx_i2c_irq_handler, 0,
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		ret = -ENXIO;
+		goto unmap;
+	}
+	ret = request_irq(irq, iop3xx_i2c_irq_handler, 0,
 				pdev->name, adapter_data);
 
 	if (ret) {
diff -urN oldtree/drivers/i2c/busses/i2c-isa.c newtree/drivers/i2c/busses/i2c-isa.c
--- oldtree/drivers/i2c/busses/i2c-isa.c	2006-02-19 11:41:02.207007584 +0000
+++ newtree/drivers/i2c/busses/i2c-isa.c	2006-02-21 15:58:14.133997864 +0000
@@ -125,7 +125,7 @@
 
 static int __init i2c_isa_init(void)
 {
-	init_MUTEX(&isa_adapter.clist_lock);
+	mutex_init(&isa_adapter.clist_lock);
 	INIT_LIST_HEAD(&isa_adapter.clients);
 
 	isa_adapter.nr = ANY_I2C_ISA_BUS;
diff -urN oldtree/drivers/i2c/busses/i2c-ite.c newtree/drivers/i2c/busses/i2c-ite.c
--- oldtree/drivers/i2c/busses/i2c-ite.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/i2c/busses/i2c-ite.c	2006-02-21 15:58:14.494942992 +0000
@@ -200,9 +200,7 @@
 	.owner		= THIS_MODULE,
 	.id		= I2C_HW_I_IIC,
 	.algo_data	= &iic_ite_data,
-	.dev		= {
-		.name	= "ITE IIC adapter",
-	},
+	.name		= "ITE IIC adapter",
 };
 
 /* Called when the module is loaded.  This function starts the
diff -urN oldtree/drivers/i2c/busses/i2c-mpc.c newtree/drivers/i2c/busses/i2c-mpc.c
--- oldtree/drivers/i2c/busses/i2c-mpc.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/i2c/busses/i2c-mpc.c	2006-02-21 15:58:12.445254592 +0000
@@ -302,6 +302,10 @@
 	}
 
 	i2c->irq = platform_get_irq(pdev, 0);
+	if (i2c->irq < 0) {
+		result = -ENXIO;
+		goto fail_get_irq;
+	}
 	i2c->flags = pdata->device_flags;
 	init_waitqueue_head(&i2c->queue);
 
@@ -340,6 +344,7 @@
       fail_irq:
 	iounmap(i2c->base);
       fail_map:
+      fail_get_irq:
 	kfree(i2c);
 	return result;
 };
diff -urN oldtree/drivers/i2c/busses/i2c-mv64xxx.c newtree/drivers/i2c/busses/i2c-mv64xxx.c
--- oldtree/drivers/i2c/busses/i2c-mv64xxx.c	2006-02-19 11:41:02.210007128 +0000
+++ newtree/drivers/i2c/busses/i2c-mv64xxx.c	2006-02-21 15:58:12.446254440 +0000
@@ -516,6 +516,10 @@
 	drv_data->freq_m = pdata->freq_m;
 	drv_data->freq_n = pdata->freq_n;
 	drv_data->irq = platform_get_irq(pd, 0);
+	if (drv_data->irq < 0) {
+		rc = -ENXIO;
+		goto exit_unmap_regs;
+	}
 	drv_data->adapter.id = I2C_HW_MV64XXX;
 	drv_data->adapter.algo = &mv64xxx_i2c_algo;
 	drv_data->adapter.owner = THIS_MODULE;
diff -urN oldtree/drivers/i2c/busses/i2c-pxa.c newtree/drivers/i2c/busses/i2c-pxa.c
--- oldtree/drivers/i2c/busses/i2c-pxa.c	2006-02-19 11:41:02.213006672 +0000
+++ newtree/drivers/i2c/busses/i2c-pxa.c	2006-02-21 15:58:14.159993912 +0000
@@ -647,7 +647,7 @@
 }
 
 /*
- * We are protected by the adapter bus semaphore.
+ * We are protected by the adapter bus mutex.
  */
 static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num)
 {
diff -urN oldtree/drivers/i2c/busses/scx200_acb.c newtree/drivers/i2c/busses/scx200_acb.c
--- oldtree/drivers/i2c/busses/scx200_acb.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/i2c/busses/scx200_acb.c	2006-02-21 15:58:14.159993912 +0000
@@ -1,27 +1,26 @@
-/*  linux/drivers/i2c/scx200_acb.c 
-
+/*
     Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
 
     National Semiconductor SCx200 ACCESS.bus support
-    
+    Also supports the AMD CS5535 and AMD CS5536
+
     Based on i2c-keywest.c which is:
         Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
         Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
-    
+
     This program is free software; you can redistribute it and/or
     modify it under the terms of the GNU General Public License as
     published by the Free Software Foundation; either version 2 of the
     License, or (at your option) any later version.
-   
+
     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     General Public License for more details.
-   
+
     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
 */
 
 #include <linux/module.h>
@@ -32,7 +31,9 @@
 #include <linux/smp_lock.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
+#include <asm/msr.h>
 
 #include <linux/scx200.h>
 
@@ -47,16 +48,7 @@
 module_param_array(base, int, NULL, 0);
 MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers");
 
-#ifdef DEBUG
-#define DBG(x...) printk(KERN_DEBUG NAME ": " x)
-#else
-#define DBG(x...)
-#endif
-
-/* The hardware supports interrupt driven mode too, but I haven't
-   implemented that. */
-#define POLLED_MODE 1
-#define POLL_TIMEOUT (HZ)
+#define POLL_TIMEOUT	(HZ/5)
 
 enum scx200_acb_state {
 	state_idle,
@@ -79,12 +71,11 @@
 };
 
 /* Physical interface */
-struct scx200_acb_iface
-{
+struct scx200_acb_iface {
 	struct scx200_acb_iface *next;
 	struct i2c_adapter adapter;
 	unsigned base;
-	struct semaphore sem;
+	struct mutex mutex;
 
 	/* State machine data */
 	enum scx200_acb_state state;
@@ -100,7 +91,7 @@
 #define ACBSDA		(iface->base + 0)
 #define ACBST		(iface->base + 1)
 #define    ACBST_SDAST		0x40 /* SDA Status */
-#define    ACBST_BER		0x20 
+#define    ACBST_BER		0x20
 #define    ACBST_NEGACK		0x10 /* Negative Acknowledge */
 #define    ACBST_STASTR		0x08 /* Stall After Start */
 #define    ACBST_MASTER		0x02
@@ -109,9 +100,9 @@
 #define ACBCTL1		(iface->base + 3)
 #define    ACBCTL1_STASTRE	0x80
 #define    ACBCTL1_NMINTE	0x40
-#define	   ACBCTL1_ACK		0x10
-#define	   ACBCTL1_STOP		0x02
-#define	   ACBCTL1_START	0x01
+#define    ACBCTL1_ACK		0x10
+#define    ACBCTL1_STOP		0x02
+#define    ACBCTL1_START	0x01
 #define ACBADDR		(iface->base + 4)
 #define ACBCTL2		(iface->base + 5)
 #define    ACBCTL2_ENABLE	0x01
@@ -122,8 +113,8 @@
 {
 	const char *errmsg;
 
-	DBG("state %s, status = 0x%02x\n", 
-	    scx200_acb_state_name[iface->state], status);
+	dev_dbg(&iface->adapter.dev, "state %s, status = 0x%02x\n",
+		scx200_acb_state_name[iface->state], status);
 
 	if (status & ACBST_BER) {
 		errmsg = "bus error";
@@ -133,8 +124,17 @@
 		errmsg = "not master";
 		goto error;
 	}
-	if (status & ACBST_NEGACK)
-		goto negack;
+	if (status & ACBST_NEGACK) {
+		dev_dbg(&iface->adapter.dev, "negative ack in state %s\n",
+			scx200_acb_state_name[iface->state]);
+
+		iface->state = state_idle;
+		iface->result = -ENXIO;
+
+		outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+		outb(ACBST_STASTR | ACBST_NEGACK, ACBST);
+		return;
+	}
 
 	switch (iface->state) {
 	case state_idle:
@@ -160,10 +160,10 @@
 	case state_repeat_start:
 		outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
 		/* fallthrough */
-		
+
 	case state_quick:
 		if (iface->address_byte & 1) {
-			if (iface->len == 1) 
+			if (iface->len == 1)
 				outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
 			else
 				outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
@@ -202,26 +202,15 @@
 			outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
 			break;
 		}
-		
+
 		outb(*iface->ptr++, ACBSDA);
 		--iface->len;
-		
+
 		break;
 	}
 
 	return;
 
- negack:
-	DBG("negative acknowledge in state %s\n", 
-	    scx200_acb_state_name[iface->state]);
-
-	iface->state = state_idle;
-	iface->result = -ENXIO;
-
-	outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
-	outb(ACBST_STASTR | ACBST_NEGACK, ACBST);
-	return;
-
  error:
 	dev_err(&iface->adapter.dev, "%s in state %s\n", errmsg,
 		scx200_acb_state_name[iface->state]);
@@ -231,20 +220,9 @@
 	iface->needs_reset = 1;
 }
 
-static void scx200_acb_timeout(struct scx200_acb_iface *iface) 
-{
-	dev_err(&iface->adapter.dev, "timeout in state %s\n",
-		scx200_acb_state_name[iface->state]);
-
-	iface->state = state_idle;
-	iface->result = -EIO;
-	iface->needs_reset = 1;
-}
-
-#ifdef POLLED_MODE
 static void scx200_acb_poll(struct scx200_acb_iface *iface)
 {
-	u8 status = 0;
+	u8 status;
 	unsigned long timeout;
 
 	timeout = jiffies + POLL_TIMEOUT;
@@ -254,17 +232,21 @@
 			scx200_acb_machine(iface, status);
 			return;
 		}
-		msleep(10);
+		yield();
 	}
 
-	scx200_acb_timeout(iface);
+	dev_err(&iface->adapter.dev, "timeout in state %s\n",
+		scx200_acb_state_name[iface->state]);
+
+	iface->state = state_idle;
+	iface->result = -EIO;
+	iface->needs_reset = 1;
 }
-#endif /* POLLED_MODE */
 
 static void scx200_acb_reset(struct scx200_acb_iface *iface)
 {
 	/* Disable the ACCESS.bus device and Configure the SCL
-           frequency: 16 clock cycles */
+	   frequency: 16 clock cycles */
 	outb(0x70, ACBCTL2);
 	/* Polling mode */
 	outb(0, ACBCTL1);
@@ -283,9 +265,9 @@
 }
 
 static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter,
-				u16 address, unsigned short flags,	
-				char rw, u8 command, int size, 
-				union i2c_smbus_data *data)
+				 u16 address, unsigned short flags,
+				 char rw, u8 command, int size,
+				 union i2c_smbus_data *data)
 {
 	struct scx200_acb_iface *iface = i2c_get_adapdata(adapter);
 	int len;
@@ -295,53 +277,47 @@
 
 	switch (size) {
 	case I2C_SMBUS_QUICK:
-	    	len = 0;
-	    	buffer = NULL;
-	    	break;
+		len = 0;
+		buffer = NULL;
+		break;
+
 	case I2C_SMBUS_BYTE:
-		if (rw == I2C_SMBUS_READ) {
-			len = 1;
-			buffer = &data->byte;
-		} else {
-			len = 1;
-			buffer = &command;
-		}
-	    	break;
+		len = 1;
+		buffer = rw ? &data->byte : &command;
+		break;
+
 	case I2C_SMBUS_BYTE_DATA:
-	    	len = 1;
-	    	buffer = &data->byte;
-	    	break;
+		len = 1;
+		buffer = &data->byte;
+		break;
+
 	case I2C_SMBUS_WORD_DATA:
 		len = 2;
-	    	cur_word = cpu_to_le16(data->word);
-	    	buffer = (u8 *)&cur_word;
+		cur_word = cpu_to_le16(data->word);
+		buffer = (u8 *)&cur_word;
 		break;
+
 	case I2C_SMBUS_BLOCK_DATA:
-	    	len = data->block[0];
-	    	buffer = &data->block[1];
+		len = data->block[0];
+		buffer = &data->block[1];
 		break;
+
 	default:
-	    	return -EINVAL;
+		return -EINVAL;
 	}
 
-	DBG("size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n",
-	    size, address, command, len, rw == I2C_SMBUS_READ);
+	dev_dbg(&adapter->dev,
+		"size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n",
+		size, address, command, len, rw);
 
 	if (!len && rw == I2C_SMBUS_READ) {
-		dev_warn(&adapter->dev, "zero length read\n");
+		dev_dbg(&adapter->dev, "zero length read\n");
 		return -EINVAL;
 	}
 
-	if (len && !buffer) {
-		dev_warn(&adapter->dev, "nonzero length but no buffer\n");
-		return -EFAULT;
-	}
-
-	down(&iface->sem);
+	mutex_lock(&iface->mutex);
 
-	iface->address_byte = address<<1;
-	if (rw == I2C_SMBUS_READ)
-		iface->address_byte |= 1;
+	iface->address_byte = (address << 1) | rw;
 	iface->command = command;
 	iface->ptr = buffer;
 	iface->len = len;
@@ -355,25 +331,21 @@
 	else
 		iface->state = state_address;
 
-#ifdef POLLED_MODE
 	while (iface->state != state_idle)
 		scx200_acb_poll(iface);
-#else /* POLLED_MODE */
-#error Interrupt driven mode not implemented
-#endif /* POLLED_MODE */	
 
 	if (iface->needs_reset)
 		scx200_acb_reset(iface);
 
 	rc = iface->result;
 
-	up(&iface->sem);
+	mutex_unlock(&iface->mutex);
 
 	if (rc == 0 && size == I2C_SMBUS_WORD_DATA && rw == I2C_SMBUS_READ)
-	    	data->word = le16_to_cpu(cur_word);
+		data->word = le16_to_cpu(cur_word);
 
 #ifdef DEBUG
-	DBG(": transfer done, result: %d", rc);
+	dev_dbg(&adapter->dev, "transfer done, result: %d", rc);
 	if (buffer) {
 		int i;
 		printk(" data:");
@@ -400,17 +372,18 @@
 };
 
 static struct scx200_acb_iface *scx200_acb_list;
+static DECLARE_MUTEX(scx200_acb_list_mutex);
 
 static int scx200_acb_probe(struct scx200_acb_iface *iface)
 {
 	u8 val;
 
 	/* Disable the ACCESS.bus device and Configure the SCL
-           frequency: 16 clock cycles */
+	   frequency: 16 clock cycles */
 	outb(0x70, ACBCTL2);
 
 	if (inb(ACBCTL2) != 0x70) {
-		DBG("ACBCTL2 readback failed\n");
+		pr_debug(NAME ": ACBCTL2 readback failed\n");
 		return -ENXIO;
 	}
 
@@ -418,7 +391,8 @@
 
 	val = inb(ACBCTL1);
 	if (val) {
-		DBG("disabled, but ACBCTL1=0x%02x\n", val);
+		pr_debug(NAME ": disabled, but ACBCTL1=0x%02x\n",
+			val);
 		return -ENXIO;
 	}
 
@@ -428,18 +402,19 @@
 
 	val = inb(ACBCTL1);
 	if ((val & ACBCTL1_NMINTE) != ACBCTL1_NMINTE) {
-		DBG("enabled, but NMINTE won't be set, ACBCTL1=0x%02x\n", val);
+		pr_debug(NAME ": enabled, but NMINTE won't be set, "
+			 "ACBCTL1=0x%02x\n", val);
 		return -ENXIO;
 	}
 
 	return 0;
 }
 
-static int  __init scx200_acb_create(int base, int index)
+static int  __init scx200_acb_create(const char *text, int base, int index)
 {
 	struct scx200_acb_iface *iface;
 	struct i2c_adapter *adapter;
-	int rc = 0;
+	int rc;
 	char description[64];
 
 	iface = kzalloc(sizeof(*iface), GFP_KERNEL);
@@ -451,50 +426,51 @@
 
 	adapter = &iface->adapter;
 	i2c_set_adapdata(adapter, iface);
-	snprintf(adapter->name, I2C_NAME_SIZE, "SCx200 ACB%d", index);
+	snprintf(adapter->name, I2C_NAME_SIZE, "%s ACB%d", text, index);
 	adapter->owner = THIS_MODULE;
 	adapter->id = I2C_HW_SMBUS_SCX200;
 	adapter->algo = &scx200_acb_algorithm;
 	adapter->class = I2C_CLASS_HWMON;
 
-	init_MUTEX(&iface->sem);
+	mutex_init(&iface->mutex);
+
+	snprintf(description, sizeof(description), "%s ACCESS.bus [%s]",
+		 text, adapter->name);
 
-	snprintf(description, sizeof(description), "NatSemi SCx200 ACCESS.bus [%s]", adapter->name);
 	if (request_region(base, 8, description) == 0) {
-		dev_err(&adapter->dev, "can't allocate io 0x%x-0x%x\n",
+		printk(KERN_ERR NAME ": can't allocate io 0x%x-0x%x\n",
 			base, base + 8-1);
 		rc = -EBUSY;
-		goto errout;
+		goto errout_free;
 	}
 	iface->base = base;
 
 	rc = scx200_acb_probe(iface);
 	if (rc) {
-		dev_warn(&adapter->dev, "probe failed\n");
-		goto errout;
+		printk(KERN_WARNING NAME ": probe failed\n");
+		goto errout_release;
 	}
 
 	scx200_acb_reset(iface);
 
 	if (i2c_add_adapter(adapter) < 0) {
-		dev_err(&adapter->dev, "failed to register\n");
+		printk(KERN_ERR NAME ": failed to register\n");
 		rc = -ENODEV;
-		goto errout;
+		goto errout_release;
 	}
 
-	lock_kernel();
+	down(&scx200_acb_list_mutex);
 	iface->next = scx200_acb_list;
 	scx200_acb_list = iface;
-	unlock_kernel();
+	up(&scx200_acb_list_mutex);
 
 	return 0;
 
+ errout_release:
+	release_region(iface->base, 8);
+ errout_free:
+	kfree(iface);
  errout:
-	if (iface) {
-		if (iface->base)
-			release_region(iface->base, 8);
-		kfree(iface);
-	}
 	return rc;
 }
 
@@ -504,50 +480,69 @@
 	{ },
 };
 
+static struct pci_device_id divil_pci[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_NS,  PCI_DEVICE_ID_NS_CS5535_ISA) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
+	{ } /* NULL entry */
+};
+
+#define MSR_LBAR_SMB		0x5140000B
+
+static int scx200_add_cs553x(void)
+{
+	u32	low, hi;
+	u32	smb_base;
+
+	/* Grab & reserve the SMB I/O range */
+	rdmsr(MSR_LBAR_SMB, low, hi);
+
+	/* Check the IO mask and whether SMB is enabled */
+	if (hi != 0x0000F001) {
+		printk(KERN_WARNING NAME ": SMBus not enabled\n");
+		return -ENODEV;
+	}
+
+	/* SMBus IO size is 8 bytes */
+	smb_base = low & 0x0000FFF8;
+
+	return scx200_acb_create("CS5535", smb_base, 0);
+}
+
 static int __init scx200_acb_init(void)
 {
 	int i;
-	int rc;
+	int	rc = -ENODEV;
 
 	pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
 
 	/* Verify that this really is a SCx200 processor */
-	if (pci_dev_present(scx200) == 0)
-		return -ENODEV;
+	if (pci_dev_present(scx200)) {
+		for (i = 0; i < MAX_DEVICES; ++i) {
+			if (base[i] > 0)
+				rc = scx200_acb_create("SCx200", base[i], i);
+		}
+	} else if (pci_dev_present(divil_pci))
+		rc = scx200_add_cs553x();
 
-	rc = -ENXIO;
-	for (i = 0; i < MAX_DEVICES; ++i) {
-		if (base[i] > 0)
-			rc = scx200_acb_create(base[i], i);
-	}
-	if (scx200_acb_list)
-		return 0;
 	return rc;
 }
 
 static void __exit scx200_acb_cleanup(void)
 {
 	struct scx200_acb_iface *iface;
-	lock_kernel();
+
+	down(&scx200_acb_list_mutex);
 	while ((iface = scx200_acb_list) != NULL) {
 		scx200_acb_list = iface->next;
-		unlock_kernel();
+		up(&scx200_acb_list_mutex);
 
 		i2c_del_adapter(&iface->adapter);
 		release_region(iface->base, 8);
 		kfree(iface);
-		lock_kernel();
+		down(&scx200_acb_list_mutex);
 	}
-	unlock_kernel();
+	up(&scx200_acb_list_mutex);
 }
 
 module_init(scx200_acb_init);
 module_exit(scx200_acb_cleanup);
-
-/*
-    Local variables:
-        compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
-        c-basic-offset: 8
-    End:
-*/
-
diff -urN oldtree/drivers/i2c/chips/ds1374.c newtree/drivers/i2c/chips/ds1374.c
--- oldtree/drivers/i2c/chips/ds1374.c	2006-02-19 11:41:02.215006368 +0000
+++ newtree/drivers/i2c/chips/ds1374.c	2006-02-21 15:58:13.788050456 +0000
@@ -26,6 +26,7 @@
 #include <linux/i2c.h>
 #include <linux/rtc.h>
 #include <linux/bcd.h>
+#include <linux/mutex.h>
 
 #define DS1374_REG_TOD0		0x00
 #define DS1374_REG_TOD1		0x01
@@ -41,7 +42,7 @@
 
 #define	DS1374_DRV_NAME		"ds1374"
 
-static DECLARE_MUTEX(ds1374_mutex);
+static DEFINE_MUTEX(ds1374_mutex);
 
 static struct i2c_driver ds1374_driver;
 static struct i2c_client *save_client;
@@ -114,7 +115,7 @@
 	ulong t1, t2;
 	int limit = 10;		/* arbitrary retry limit */
 
-	down(&ds1374_mutex);
+	mutex_lock(&ds1374_mutex);
 
 	/*
 	 * Since the reads are being performed one byte at a time using
@@ -127,7 +128,7 @@
 		t2 = ds1374_read_rtc();
 	} while (t1 != t2 && limit--);
 
-	up(&ds1374_mutex);
+	mutex_unlock(&ds1374_mutex);
 
 	if (t1 != t2) {
 		dev_warn(&save_client->dev,
@@ -145,7 +146,7 @@
 
 	t1 = *(ulong *) arg;
 
-	down(&ds1374_mutex);
+	mutex_lock(&ds1374_mutex);
 
 	/*
 	 * Since the writes are being performed one byte at a time using
@@ -158,7 +159,7 @@
 		t2 = ds1374_read_rtc();
 	} while (t1 != t2 && limit--);
 
-	up(&ds1374_mutex);
+	mutex_unlock(&ds1374_mutex);
 
 	if (t1 != t2)
 		dev_warn(&save_client->dev,
diff -urN oldtree/drivers/i2c/chips/eeprom.c newtree/drivers/i2c/chips/eeprom.c
--- oldtree/drivers/i2c/chips/eeprom.c	2006-02-19 11:41:02.215006368 +0000
+++ newtree/drivers/i2c/chips/eeprom.c	2006-02-21 15:58:14.133997864 +0000
@@ -33,6 +33,7 @@
 #include <linux/sched.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54,
@@ -54,7 +55,7 @@
 /* Each client has this additional data */
 struct eeprom_data {
 	struct i2c_client client;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	u8 valid;			/* bitfield, bit!=0 if slice is valid */
 	unsigned long last_updated[8];	/* In jiffies, 8 slices */
 	u8 data[EEPROM_SIZE];		/* Register values */
@@ -81,7 +82,7 @@
 	struct eeprom_data *data = i2c_get_clientdata(client);
 	int i, j;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (!(data->valid & (1 << slice)) ||
 	    time_after(jiffies, data->last_updated[slice] + 300 * HZ)) {
@@ -107,7 +108,7 @@
 		data->valid |= (1 << slice);
 	}
 exit:
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 }
 
 static ssize_t eeprom_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
@@ -187,7 +188,7 @@
 	/* Fill in the remaining client fields */
 	strlcpy(new_client->name, "eeprom", I2C_NAME_SIZE);
 	data->valid = 0;
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 	data->nature = UNKNOWN;
 
 	/* Tell the I2C layer a new client has arrived */
diff -urN oldtree/drivers/i2c/chips/isp1301_omap.c newtree/drivers/i2c/chips/isp1301_omap.c
--- oldtree/drivers/i2c/chips/isp1301_omap.c	2006-02-19 11:41:02.216006216 +0000
+++ newtree/drivers/i2c/chips/isp1301_omap.c	2006-02-21 15:58:14.507941016 +0000
@@ -1635,8 +1635,6 @@
 	.driver = {
 		.name	= "isp1301_omap",
 	},
-	.id		= 1301,		/* FIXME "official", i2c-ids.h */
-	.class		= I2C_CLASS_HWMON,
 	.attach_adapter	= isp1301_scan_bus,
 	.detach_client	= isp1301_detach_client,
 };
diff -urN oldtree/drivers/i2c/chips/m41t00.c newtree/drivers/i2c/chips/m41t00.c
--- oldtree/drivers/i2c/chips/m41t00.c	2006-02-19 11:41:02.217006064 +0000
+++ newtree/drivers/i2c/chips/m41t00.c	2006-02-21 15:58:13.800048632 +0000
@@ -24,13 +24,14 @@
 #include <linux/i2c.h>
 #include <linux/rtc.h>
 #include <linux/bcd.h>
+#include <linux/mutex.h>
 
 #include <asm/time.h>
 #include <asm/rtc.h>
 
 #define	M41T00_DRV_NAME		"m41t00"
 
-static DECLARE_MUTEX(m41t00_mutex);
+static DEFINE_MUTEX(m41t00_mutex);
 
 static struct i2c_driver m41t00_driver;
 static struct i2c_client *save_client;
@@ -54,7 +55,7 @@
 	sec = min = hour = day = mon = year = 0;
 	sec1 = min1 = hour1 = day1 = mon1 = year1 = 0;
 
-	down(&m41t00_mutex);
+	mutex_lock(&m41t00_mutex);
 	do {
 		if (((sec = i2c_smbus_read_byte_data(save_client, 0)) >= 0)
 			&& ((min = i2c_smbus_read_byte_data(save_client, 1))
@@ -80,7 +81,7 @@
 		mon1 = mon;
 		year1 = year;
 	} while (--limit > 0);
-	up(&m41t00_mutex);
+	mutex_unlock(&m41t00_mutex);
 
 	if (limit == 0) {
 		dev_warn(&save_client->dev,
@@ -125,7 +126,7 @@
 	BIN_TO_BCD(tm.tm_mday);
 	BIN_TO_BCD(tm.tm_year);
 
-	down(&m41t00_mutex);
+	mutex_lock(&m41t00_mutex);
 	if ((i2c_smbus_write_byte_data(save_client, 0, tm.tm_sec & 0x7f) < 0)
 		|| (i2c_smbus_write_byte_data(save_client, 1, tm.tm_min & 0x7f)
 			< 0)
@@ -140,7 +141,7 @@
 
 		dev_warn(&save_client->dev,"m41t00: can't write to rtc chip\n");
 
-	up(&m41t00_mutex);
+	mutex_unlock(&m41t00_mutex);
 	return;
 }
 
diff -urN oldtree/drivers/i2c/chips/max6875.c newtree/drivers/i2c/chips/max6875.c
--- oldtree/drivers/i2c/chips/max6875.c	2006-02-19 11:41:02.217006064 +0000
+++ newtree/drivers/i2c/chips/max6875.c	2006-02-21 15:58:14.134997712 +0000
@@ -31,7 +31,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 /* Do not scan - the MAX6875 access method will write to some EEPROM chips */
 static unsigned short normal_i2c[] = {I2C_CLIENT_END};
@@ -54,7 +54,7 @@
 /* Each client has this additional data */
 struct max6875_data {
 	struct i2c_client	client;
-	struct semaphore	update_lock;
+	struct mutex		update_lock;
 
 	u32			valid;
 	u8			data[USER_EEPROM_SIZE];
@@ -83,7 +83,7 @@
 	if (slice >= USER_EEPROM_SLICES)
 		return;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	buf = &data->data[slice << SLICE_BITS];
 
@@ -122,7 +122,7 @@
 		data->valid |= (1 << slice);
 	}
 exit_up:
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 }
 
 static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off,
@@ -196,7 +196,7 @@
 	real_client->driver = &max6875_driver;
 	real_client->flags = 0;
 	strlcpy(real_client->name, "max6875", I2C_NAME_SIZE);
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Init fake client data */
 	/* set the client data to the i2c_client so that it will get freed */
diff -urN oldtree/drivers/i2c/chips/pcf8591.c newtree/drivers/i2c/chips/pcf8591.c
--- oldtree/drivers/i2c/chips/pcf8591.c	2006-02-19 11:41:02.218005912 +0000
+++ newtree/drivers/i2c/chips/pcf8591.c	2006-02-21 15:58:14.135997560 +0000
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
@@ -74,7 +75,7 @@
 
 struct pcf8591_data {
 	struct i2c_client client;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 
 	u8 control;
 	u8 aout;
@@ -144,13 +145,13 @@
 	struct pcf8591_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	if (val)
 		data->control |= PCF8591_CONTROL_AOEF;
 	else
 		data->control &= ~PCF8591_CONTROL_AOEF;
 	i2c_smbus_write_byte(client, data->control);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -200,7 +201,7 @@
 	/* Fill in the remaining client fields and put it into the global 
 	   list */
 	strlcpy(new_client->name, "pcf8591", I2C_NAME_SIZE);
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(new_client)))
@@ -265,7 +266,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct pcf8591_data *data = i2c_get_clientdata(client);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if ((data->control & PCF8591_CONTROL_AICH_MASK) != channel) {
 		data->control = (data->control & ~PCF8591_CONTROL_AICH_MASK)
@@ -278,7 +279,7 @@
 	}
 	value = i2c_smbus_read_byte(client);
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	if ((channel == 2 && input_mode == 2) ||
 	    (channel != 3 && (input_mode == 1 || input_mode == 3)))
diff -urN oldtree/drivers/i2c/chips/tps65010.c newtree/drivers/i2c/chips/tps65010.c
--- oldtree/drivers/i2c/chips/tps65010.c	2006-02-19 11:41:02.220005608 +0000
+++ newtree/drivers/i2c/chips/tps65010.c	2006-02-21 15:58:14.136997408 +0000
@@ -32,6 +32,7 @@
 #include <linux/suspend.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
+#include <linux/mutex.h>
 
 #include <asm/irq.h>
 #include <asm/mach-types.h>
@@ -81,7 +82,7 @@
 
 struct tps65010 {
 	struct i2c_client	client;
-	struct semaphore	lock;
+	struct mutex		lock;
 	int			irq;
 	struct work_struct	work;
 	struct dentry		*file;
@@ -218,7 +219,7 @@
 	seq_printf(s, "driver  %s\nversion %s\nchip    %s\n\n",
 			DRIVER_NAME, DRIVER_VERSION, chip);
 
-	down(&tps->lock);
+	mutex_lock(&tps->lock);
 
 	/* FIXME how can we tell whether a battery is present?
 	 * likely involves a charge gauging chip (like BQ26501).
@@ -300,7 +301,7 @@
 				(v2 & (1 << (4 + i))) ? "rising" : "falling");
 	}
 
-	up(&tps->lock);
+	mutex_unlock(&tps->lock);
 	return 0;
 }
 
@@ -416,7 +417,7 @@
 {
 	struct tps65010		*tps = _tps;
 
-	down(&tps->lock);
+	mutex_lock(&tps->lock);
 
 	tps65010_interrupt(tps);
 
@@ -444,7 +445,7 @@
 	if (test_and_clear_bit(FLAG_IRQ_ENABLE, &tps->flags))
 		enable_irq(tps->irq);
 
-	up(&tps->lock);
+	mutex_unlock(&tps->lock);
 }
 
 static irqreturn_t tps65010_irq(int irq, void *_tps, struct pt_regs *regs)
@@ -505,7 +506,7 @@
 	if (!tps)
 		return 0;
 
-	init_MUTEX(&tps->lock);
+	mutex_init(&tps->lock);
 	INIT_WORK(&tps->work, tps65010_work, tps);
 	tps->irq = -1;
 	tps->client.addr = address;
@@ -695,7 +696,7 @@
 	if ((gpio < GPIO1) || (gpio > GPIO4))
 		return -EINVAL;
 
-	down(&the_tps->lock);
+	mutex_lock(&the_tps->lock);
 
 	defgpio = i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO);
 
@@ -720,7 +721,7 @@
 		gpio, value ? "high" : "low",
 		i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO));
 
-	up(&the_tps->lock);
+	mutex_unlock(&the_tps->lock);
 	return status;
 }
 EXPORT_SYMBOL(tps65010_set_gpio_out_value);
@@ -745,7 +746,7 @@
 		led = LED2;
 	}
 
-	down(&the_tps->lock);
+	mutex_lock(&the_tps->lock);
 
 	pr_debug("%s: led%i_on   0x%02x\n", DRIVER_NAME, led,
 		i2c_smbus_read_byte_data(&the_tps->client,
@@ -771,7 +772,7 @@
 	default:
 		printk(KERN_ERR "%s: Wrong mode parameter for set_led()\n",
 		       DRIVER_NAME);
-		up(&the_tps->lock);
+		mutex_unlock(&the_tps->lock);
 		return -EINVAL;
 	}
 
@@ -781,7 +782,7 @@
 	if (status != 0) {
 		printk(KERN_ERR "%s: Failed to write led%i_on register\n",
 		       DRIVER_NAME, led);
-		up(&the_tps->lock);
+		mutex_unlock(&the_tps->lock);
 		return status;
 	}
 
@@ -794,7 +795,7 @@
 	if (status != 0) {
 		printk(KERN_ERR "%s: Failed to write led%i_per register\n",
 		       DRIVER_NAME, led);
-		up(&the_tps->lock);
+		mutex_unlock(&the_tps->lock);
 		return status;
 	}
 
@@ -802,7 +803,7 @@
 		i2c_smbus_read_byte_data(&the_tps->client,
 				TPS_LED1_PER + offs));
 
-	up(&the_tps->lock);
+	mutex_unlock(&the_tps->lock);
 
 	return status;
 }
@@ -820,7 +821,7 @@
 	if (!the_tps)
 		return -ENODEV;
 
-	down(&the_tps->lock);
+	mutex_lock(&the_tps->lock);
 
 	vdcdc2 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC2);
 	vdcdc2 &= ~(1 << 1);
@@ -831,7 +832,7 @@
 
 	pr_debug("%s: vibrator %s\n", DRIVER_NAME, value ? "on" : "off");
 
-	up(&the_tps->lock);
+	mutex_unlock(&the_tps->lock);
 	return status;
 }
 EXPORT_SYMBOL(tps65010_set_vib);
@@ -848,7 +849,7 @@
 	if (!the_tps)
 		return -ENODEV;
 
-	down(&the_tps->lock);
+	mutex_lock(&the_tps->lock);
 
 	pr_debug("%s: %s low_pwr, vdcdc1 0x%02x\n", DRIVER_NAME,
 		mode ? "enable" : "disable",
@@ -876,7 +877,7 @@
 		pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME,
 			i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
 
-	up(&the_tps->lock);
+	mutex_unlock(&the_tps->lock);
 
 	return status;
 }
@@ -894,7 +895,7 @@
 	if (!the_tps)
 		return -ENODEV;
 
-	down(&the_tps->lock);
+	mutex_lock(&the_tps->lock);
 
 	pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME,
 			i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1));
@@ -909,7 +910,7 @@
 		pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME,
 			i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1));
 
-	up(&the_tps->lock);
+	mutex_unlock(&the_tps->lock);
 
 	return status;
 }
@@ -931,7 +932,7 @@
 	if (!the_tps || the_tps->por)
 		return -ENODEV;
 
-	down(&the_tps->lock);
+	mutex_lock(&the_tps->lock);
 
 	pr_debug("%s: %s low_pwr, chgconfig 0x%02x vdcdc1 0x%02x\n",
 		DRIVER_NAME,
@@ -959,7 +960,7 @@
 	if (status != 0) {
 		printk(KERN_ERR "%s: Failed to write chconfig register\n",
 	 DRIVER_NAME);
-		up(&the_tps->lock);
+		mutex_unlock(&the_tps->lock);
 		return status;
 	}
 
@@ -977,7 +978,7 @@
 		pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME,
 			i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
 
-	up(&the_tps->lock);
+	mutex_unlock(&the_tps->lock);
 
 	return status;
 }
diff -urN oldtree/drivers/i2c/i2c-core.c newtree/drivers/i2c/i2c-core.c
--- oldtree/drivers/i2c/i2c-core.c	2006-02-19 11:41:02.221005456 +0000
+++ newtree/drivers/i2c/i2c-core.c	2006-02-21 15:58:14.463947704 +0000
@@ -31,12 +31,13 @@
 #include <linux/idr.h>
 #include <linux/seq_file.h>
 #include <linux/platform_device.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 
 static LIST_HEAD(adapters);
 static LIST_HEAD(drivers);
-static DECLARE_MUTEX(core_lists);
+static DEFINE_MUTEX(core_lists);
 static DEFINE_IDR(i2c_adapter_idr);
 
 /* match always succeeds, as we want the probe() to tell if we really accept this match */
@@ -153,7 +154,7 @@
 	struct list_head   *item;
 	struct i2c_driver  *driver;
 
-	down(&core_lists);
+	mutex_lock(&core_lists);
 
 	if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) {
 		res = -ENOMEM;
@@ -168,8 +169,8 @@
 	}
 
 	adap->nr =  id & MAX_ID_MASK;
-	init_MUTEX(&adap->bus_lock);
-	init_MUTEX(&adap->clist_lock);
+	mutex_init(&adap->bus_lock);
+	mutex_init(&adap->clist_lock);
 	list_add_tail(&adap->list,&adapters);
 	INIT_LIST_HEAD(&adap->clients);
 
@@ -203,7 +204,7 @@
 	}
 
 out_unlock:
-	up(&core_lists);
+	mutex_unlock(&core_lists);
 	return res;
 }
 
@@ -216,7 +217,7 @@
 	struct i2c_client *client;
 	int res = 0;
 
-	down(&core_lists);
+	mutex_lock(&core_lists);
 
 	/* First make sure that this adapter was ever added */
 	list_for_each_entry(adap_from_list, &adapters, list) {
@@ -272,7 +273,7 @@
 	dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
 
  out_unlock:
-	up(&core_lists);
+	mutex_unlock(&core_lists);
 	return res;
 }
 
@@ -287,9 +288,7 @@
 {
 	struct list_head   *item;
 	struct i2c_adapter *adapter;
-	int res = 0;
-
-	down(&core_lists);
+	int res;
 
 	/* add the driver to the list of i2c drivers in the driver core */
 	driver->driver.owner = owner;
@@ -297,8 +296,10 @@
 
 	res = driver_register(&driver->driver);
 	if (res)
-		goto out_unlock;
+		return res;
 	
+	mutex_lock(&core_lists);
+
 	list_add_tail(&driver->list,&drivers);
 	pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
 
@@ -310,9 +311,8 @@
 		}
 	}
 
- out_unlock:
-	up(&core_lists);
-	return res;
+	mutex_unlock(&core_lists);
+	return 0;
 }
 EXPORT_SYMBOL(i2c_register_driver);
 
@@ -324,7 +324,7 @@
 	
 	int res = 0;
 
-	down(&core_lists);
+	mutex_lock(&core_lists);
 
 	/* Have a look at each adapter, if clients of this driver are still
 	 * attached. If so, detach them to be able to kill the driver 
@@ -363,7 +363,7 @@
 	pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
 
  out_unlock:
-	up(&core_lists);
+	mutex_unlock(&core_lists);
 	return 0;
 }
 
@@ -384,9 +384,9 @@
 {
 	int rval;
 
-	down(&adapter->clist_lock);
+	mutex_lock(&adapter->clist_lock);
 	rval = __i2c_check_addr(adapter, addr);
-	up(&adapter->clist_lock);
+	mutex_unlock(&adapter->clist_lock);
 
 	return rval;
 }
@@ -395,13 +395,13 @@
 {
 	struct i2c_adapter *adapter = client->adapter;
 
-	down(&adapter->clist_lock);
+	mutex_lock(&adapter->clist_lock);
 	if (__i2c_check_addr(client->adapter, client->addr)) {
-		up(&adapter->clist_lock);
+		mutex_unlock(&adapter->clist_lock);
 		return -EBUSY;
 	}
 	list_add_tail(&client->list,&adapter->clients);
-	up(&adapter->clist_lock);
+	mutex_unlock(&adapter->clist_lock);
 	
 	if (adapter->client_register)  {
 		if (adapter->client_register(client))  {
@@ -450,12 +450,12 @@
 		}
 	}
 
-	down(&adapter->clist_lock);
+	mutex_lock(&adapter->clist_lock);
 	list_del(&client->list);
 	init_completion(&client->released);
 	device_remove_file(&client->dev, &dev_attr_client_name);
 	device_unregister(&client->dev);
-	up(&adapter->clist_lock);
+	mutex_unlock(&adapter->clist_lock);
 	wait_for_completion(&client->released);
 
  out:
@@ -513,19 +513,19 @@
 	struct list_head  *item;
 	struct i2c_client *client;
 
-	down(&adap->clist_lock);
+	mutex_lock(&adap->clist_lock);
 	list_for_each(item,&adap->clients) {
 		client = list_entry(item, struct i2c_client, list);
 		if (!try_module_get(client->driver->driver.owner))
 			continue;
 		if (NULL != client->driver->command) {
-			up(&adap->clist_lock);
+			mutex_unlock(&adap->clist_lock);
 			client->driver->command(client,cmd,arg);
-			down(&adap->clist_lock);
+			mutex_lock(&adap->clist_lock);
 		}
 		module_put(client->driver->driver.owner);
        }
-       up(&adap->clist_lock);
+       mutex_unlock(&adap->clist_lock);
 }
 
 static int __init i2c_init(void)
@@ -569,9 +569,9 @@
 		}
 #endif
 
-		down(&adap->bus_lock);
+		mutex_lock(&adap->bus_lock);
 		ret = adap->algo->master_xfer(adap,msgs,num);
-		up(&adap->bus_lock);
+		mutex_unlock(&adap->bus_lock);
 
 		return ret;
 	} else {
@@ -779,12 +779,12 @@
 {
 	struct i2c_adapter *adapter;
 	
-	down(&core_lists);
+	mutex_lock(&core_lists);
 	adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id);
 	if (adapter && !try_module_get(adapter->owner))
 		adapter = NULL;
 
-	up(&core_lists);
+	mutex_unlock(&core_lists);
 	return adapter;
 }
 
@@ -919,12 +919,11 @@
 			       u8 length, u8 *values)
 {
 	union i2c_smbus_data data;
-	int i;
+
 	if (length > I2C_SMBUS_BLOCK_MAX)
 		length = I2C_SMBUS_BLOCK_MAX;
-	for (i = 1; i <= length; i++)
-		data.block[i] = values[i-1];
 	data.block[0] = length;
+	memcpy(&data.block[1], values, length);
 	return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
 			      I2C_SMBUS_WRITE,command,
 			      I2C_SMBUS_BLOCK_DATA,&data);
@@ -934,16 +933,14 @@
 s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *values)
 {
 	union i2c_smbus_data data;
-	int i;
+
 	if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
 	                      I2C_SMBUS_READ,command,
 	                      I2C_SMBUS_I2C_BLOCK_DATA,&data))
 		return -1;
-	else {
-		for (i = 1; i <= data.block[0]; i++)
-			values[i-1] = data.block[i];
-		return data.block[0];
-	}
+
+	memcpy(values, &data.block[1], data.block[0]);
+	return data.block[0];
 }
 
 s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command,
@@ -1118,10 +1115,10 @@
 	flags &= I2C_M_TEN | I2C_CLIENT_PEC;
 
 	if (adapter->algo->smbus_xfer) {
-		down(&adapter->bus_lock);
+		mutex_lock(&adapter->bus_lock);
 		res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
 		                                command,size,data);
-		up(&adapter->bus_lock);
+		mutex_unlock(&adapter->bus_lock);
 	} else
 		res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
 	                                      command,size,data);
diff -urN oldtree/drivers/ide/ide-cd.c newtree/drivers/ide/ide-cd.c
--- oldtree/drivers/ide/ide-cd.c	2006-02-19 11:41:02.224005000 +0000
+++ newtree/drivers/ide/ide-cd.c	2006-02-21 15:58:28.388830800 +0000
@@ -313,6 +313,7 @@
 #include <linux/cdrom.h>
 #include <linux/ide.h>
 #include <linux/completion.h>
+#include <linux/mutex.h>
 
 #include <scsi/scsi.h>	/* For SCSI -> ATAPI command conversion */
 
@@ -324,7 +325,7 @@
 
 #include "ide-cd.h"
 
-static DECLARE_MUTEX(idecd_ref_sem);
+static DEFINE_MUTEX(idecd_ref_mutex);
 
 #define to_ide_cd(obj) container_of(obj, struct cdrom_info, kref) 
 
@@ -335,11 +336,11 @@
 {
 	struct cdrom_info *cd = NULL;
 
-	down(&idecd_ref_sem);
+	mutex_lock(&idecd_ref_mutex);
 	cd = ide_cd_g(disk);
 	if (cd)
 		kref_get(&cd->kref);
-	up(&idecd_ref_sem);
+	mutex_unlock(&idecd_ref_mutex);
 	return cd;
 }
 
@@ -347,9 +348,9 @@
 
 static void ide_cd_put(struct cdrom_info *cd)
 {
-	down(&idecd_ref_sem);
+	mutex_lock(&idecd_ref_mutex);
 	kref_put(&cd->kref, ide_cd_release);
-	up(&idecd_ref_sem);
+	mutex_unlock(&idecd_ref_mutex);
 }
 
 /****************************************************************************
diff -urN oldtree/drivers/ide/ide-disk.c newtree/drivers/ide/ide-disk.c
--- oldtree/drivers/ide/ide-disk.c	2006-02-19 11:41:02.226004696 +0000
+++ newtree/drivers/ide/ide-disk.c	2006-02-21 15:58:28.390830496 +0000
@@ -60,6 +60,7 @@
 #include <linux/genhd.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
 
 #define _IDE_DISK
 
@@ -78,7 +79,7 @@
 	struct kref	kref;
 };
 
-static DECLARE_MUTEX(idedisk_ref_sem);
+static DEFINE_MUTEX(idedisk_ref_mutex);
 
 #define to_ide_disk(obj) container_of(obj, struct ide_disk_obj, kref)
 
@@ -89,11 +90,11 @@
 {
 	struct ide_disk_obj *idkp = NULL;
 
-	down(&idedisk_ref_sem);
+	mutex_lock(&idedisk_ref_mutex);
 	idkp = ide_disk_g(disk);
 	if (idkp)
 		kref_get(&idkp->kref);
-	up(&idedisk_ref_sem);
+	mutex_unlock(&idedisk_ref_mutex);
 	return idkp;
 }
 
@@ -101,9 +102,9 @@
 
 static void ide_disk_put(struct ide_disk_obj *idkp)
 {
-	down(&idedisk_ref_sem);
+	mutex_lock(&idedisk_ref_mutex);
 	kref_put(&idkp->kref, ide_disk_release);
-	up(&idedisk_ref_sem);
+	mutex_unlock(&idedisk_ref_mutex);
 }
 
 /*
diff -urN oldtree/drivers/ide/ide-floppy.c newtree/drivers/ide/ide-floppy.c
--- oldtree/drivers/ide/ide-floppy.c	2006-02-19 11:41:02.228004392 +0000
+++ newtree/drivers/ide/ide-floppy.c	2006-02-21 15:58:28.392830192 +0000
@@ -98,6 +98,7 @@
 #include <linux/cdrom.h>
 #include <linux/ide.h>
 #include <linux/bitops.h>
+#include <linux/mutex.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -517,7 +518,7 @@
 	u8		reserved[4];
 } idefloppy_mode_parameter_header_t;
 
-static DECLARE_MUTEX(idefloppy_ref_sem);
+static DEFINE_MUTEX(idefloppy_ref_mutex);
 
 #define to_ide_floppy(obj) container_of(obj, struct ide_floppy_obj, kref)
 
@@ -528,11 +529,11 @@
 {
 	struct ide_floppy_obj *floppy = NULL;
 
-	down(&idefloppy_ref_sem);
+	mutex_lock(&idefloppy_ref_mutex);
 	floppy = ide_floppy_g(disk);
 	if (floppy)
 		kref_get(&floppy->kref);
-	up(&idefloppy_ref_sem);
+	mutex_unlock(&idefloppy_ref_mutex);
 	return floppy;
 }
 
@@ -540,9 +541,9 @@
 
 static void ide_floppy_put(struct ide_floppy_obj *floppy)
 {
-	down(&idefloppy_ref_sem);
+	mutex_lock(&idefloppy_ref_mutex);
 	kref_put(&floppy->kref, ide_floppy_release);
-	up(&idefloppy_ref_sem);
+	mutex_unlock(&idefloppy_ref_mutex);
 }
 
 /*
diff -urN oldtree/drivers/ide/ide-tape.c newtree/drivers/ide/ide-tape.c
--- oldtree/drivers/ide/ide-tape.c	2006-02-19 11:41:02.233003632 +0000
+++ newtree/drivers/ide/ide-tape.c	2006-02-21 15:58:28.495814536 +0000
@@ -443,6 +443,7 @@
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
 #include <linux/bitops.h>
+#include <linux/mutex.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -1011,7 +1012,7 @@
          int debug_level; 
 } idetape_tape_t;
 
-static DECLARE_MUTEX(idetape_ref_sem);
+static DEFINE_MUTEX(idetape_ref_mutex);
 
 static struct class *idetape_sysfs_class;
 
@@ -1024,11 +1025,11 @@
 {
 	struct ide_tape_obj *tape = NULL;
 
-	down(&idetape_ref_sem);
+	mutex_lock(&idetape_ref_mutex);
 	tape = ide_tape_g(disk);
 	if (tape)
 		kref_get(&tape->kref);
-	up(&idetape_ref_sem);
+	mutex_unlock(&idetape_ref_mutex);
 	return tape;
 }
 
@@ -1036,9 +1037,9 @@
 
 static void ide_tape_put(struct ide_tape_obj *tape)
 {
-	down(&idetape_ref_sem);
+	mutex_lock(&idetape_ref_mutex);
 	kref_put(&tape->kref, ide_tape_release);
-	up(&idetape_ref_sem);
+	mutex_unlock(&idetape_ref_mutex);
 }
 
 /*
@@ -1290,11 +1291,11 @@
 {
 	struct ide_tape_obj *tape = NULL;
 
-	down(&idetape_ref_sem);
+	mutex_lock(&idetape_ref_mutex);
 	tape = idetape_devs[i];
 	if (tape)
 		kref_get(&tape->kref);
-	up(&idetape_ref_sem);
+	mutex_unlock(&idetape_ref_mutex);
 	return tape;
 }
 
@@ -4870,11 +4871,11 @@
 
 	drive->driver_data = tape;
 
-	down(&idetape_ref_sem);
+	mutex_lock(&idetape_ref_mutex);
 	for (minor = 0; idetape_devs[minor]; minor++)
 		;
 	idetape_devs[minor] = tape;
-	up(&idetape_ref_sem);
+	mutex_unlock(&idetape_ref_mutex);
 
 	idetape_setup(drive, tape, minor);
 
diff -urN oldtree/drivers/ide/ide-taskfile.c newtree/drivers/ide/ide-taskfile.c
--- oldtree/drivers/ide/ide-taskfile.c	2006-02-19 11:41:02.234003480 +0000
+++ newtree/drivers/ide/ide-taskfile.c	2006-02-21 15:58:31.369377688 +0000
@@ -375,7 +375,13 @@
 		}
 	}
 
-	ide_end_request(drive, 1, rq->hard_nr_sectors);
+	if (rq->rq_disk) {
+		ide_driver_t *drv;
+
+		drv = *(ide_driver_t **)rq->rq_disk->private_data;;
+		drv->end_request(drive, 1, rq->hard_nr_sectors);
+	} else
+		ide_end_request(drive, 1, rq->hard_nr_sectors);
 }
 
 /*
diff -urN oldtree/drivers/ide/mips/au1xxx-ide.c newtree/drivers/ide/mips/au1xxx-ide.c
--- oldtree/drivers/ide/mips/au1xxx-ide.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/ide/mips/au1xxx-ide.c	2006-02-21 15:58:12.458252616 +0000
@@ -674,6 +674,11 @@
 		ret = -ENODEV;
 		goto out;
 	}
+	if (ahwif->irq < 0) {
+		pr_debug("%s %d: no IRQ\n", DRV_NAME, pdev->id);
+		ret = -ENODEV;
+		goto out;
+	}
 
 	if (!request_mem_region (res->start, res->end-res->start, pdev->name)) {
 		pr_debug("%s: request_mem_region failed\n", DRV_NAME);
diff -urN oldtree/drivers/ide/pci/amd74xx.c newtree/drivers/ide/pci/amd74xx.c
--- oldtree/drivers/ide/pci/amd74xx.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/ide/pci/amd74xx.c	2006-02-21 15:58:35.528745368 +0000
@@ -347,10 +347,8 @@
 			break;
 
 		case AMD_UDMA_66:
-			pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);
-			for (i = 24; i >= 0; i -= 8)
-				if ((u >> i) & 4)
-					amd_80w |= (1 << (1 - (i >> 4)));
+			/* no host side cable detection */
+			amd_80w = 0x03;
 			break;
 	}
 
@@ -386,8 +384,6 @@
 	if (amd_clock < 20000 || amd_clock > 50000) {
 		printk(KERN_WARNING "%s: User given PCI clock speed impossible (%d), using 33 MHz instead.\n",
 			amd_chipset->name, amd_clock);
-		printk(KERN_WARNING "%s: Use ide0=ata66 if you want to assume 80-wire cable\n",
-			amd_chipset->name);
 		amd_clock = 33333;
 	}
 
diff -urN oldtree/drivers/ieee1394/Kconfig newtree/drivers/ieee1394/Kconfig
--- oldtree/drivers/ieee1394/Kconfig	2006-02-19 11:41:02.270997856 +0000
+++ newtree/drivers/ieee1394/Kconfig	2006-02-21 15:58:36.264633496 +0000
@@ -4,7 +4,7 @@
 
 config IEEE1394
 	tristate "IEEE 1394 (FireWire) support"
-	depends on PCI || BROKEN
+	depends on (PCI || BROKEN) && (BROKEN || !FRV)
 	select NET
 	help
 	  IEEE 1394 describes a high performance serial bus, which is also
diff -urN oldtree/drivers/ieee1394/hosts.c newtree/drivers/ieee1394/hosts.c
--- oldtree/drivers/ieee1394/hosts.c	2006-02-19 11:41:02.279996488 +0000
+++ newtree/drivers/ieee1394/hosts.c	2006-02-21 15:58:14.839890552 +0000
@@ -19,6 +19,7 @@
 #include <linux/pci.h>
 #include <linux/timer.h>
 #include <linux/jiffies.h>
+#include <linux/mutex.h>
 
 #include "csr1212.h"
 #include "ieee1394.h"
@@ -105,7 +106,7 @@
  * Return Value: a pointer to the &hpsb_host if succesful, %NULL if
  * no memory was available.
  */
-static DECLARE_MUTEX(host_num_alloc);
+static DEFINE_MUTEX(host_num_alloc);
 
 struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
 				  struct device *dev)
@@ -148,7 +149,7 @@
 	h->topology_map = h->csr.topology_map + 3;
 	h->speed_map = (u8 *)(h->csr.speed_map + 2);
 
-	down(&host_num_alloc);
+	mutex_lock(&host_num_alloc);
 
 	while (nodemgr_for_each_host(&hostnum, alloc_hostnum_cb))
 		hostnum++;
@@ -167,7 +168,7 @@
 	class_device_register(&h->class_dev);
 	get_device(&h->device);
 
-	up(&host_num_alloc);
+	mutex_unlock(&host_num_alloc);
 
 	return h;
 }
diff -urN oldtree/drivers/ieee1394/sbp2.c newtree/drivers/ieee1394/sbp2.c
--- oldtree/drivers/ieee1394/sbp2.c	2006-02-19 11:41:02.297993752 +0000
+++ newtree/drivers/ieee1394/sbp2.c	2006-02-21 15:58:36.275631824 +0000
@@ -2082,9 +2082,7 @@
 
 	SBP2_DEBUG("sbp2_check_sbp2_response");
 
-	switch (SCpnt->cmnd[0]) {
-
-	case INQUIRY:
+	if (SCpnt->cmnd[0] == INQUIRY && (SCpnt->cmnd[1] & 3) == 0) {
 		/*
 		 * Make sure data length is ok. Minimum length is 36 bytes
 		 */
@@ -2097,13 +2095,7 @@
 		 */
 		scsi_buf[2] |= 2;
 		scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2;
-
-		break;
-
-	default:
-		break;
 	}
-	return;
 }
 
 /*
diff -urN oldtree/drivers/infiniband/core/agent.c newtree/drivers/infiniband/core/agent.c
--- oldtree/drivers/infiniband/core/agent.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/infiniband/core/agent.c	2006-02-21 15:58:14.857887816 +0000
@@ -78,25 +78,6 @@
 	return entry;
 }
 
-int smi_check_local_dr_smp(struct ib_smp *smp,
-			   struct ib_device *device,
-			   int port_num)
-{
-	struct ib_agent_port_private *port_priv;
-
-	if (smp->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
-		return 1;
-
-	port_priv = ib_get_agent_port(device, port_num);
-	if (!port_priv) {
-		printk(KERN_DEBUG SPFX "smi_check_local_dr_smp %s port %d "
-		       "not open\n", device->name, port_num);
-		return 1;
-	}
-
-	return smi_check_local_smp(port_priv->agent[0], smp);
-}
-
 int agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
 			struct ib_wc *wc, struct ib_device *device,
 			int port_num, int qpn)
diff -urN oldtree/drivers/infiniband/core/fmr_pool.c newtree/drivers/infiniband/core/fmr_pool.c
--- oldtree/drivers/infiniband/core/fmr_pool.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/infiniband/core/fmr_pool.c	2006-02-21 15:58:14.859887512 +0000
@@ -278,9 +278,9 @@
 	{
 		struct ib_pool_fmr *fmr;
 		struct ib_fmr_attr attr = {
-			.max_pages = params->max_pages_per_fmr,
-			.max_maps  = IB_FMR_MAX_REMAPS,
-			.page_size = PAGE_SHIFT
+			.max_pages  = params->max_pages_per_fmr,
+			.max_maps   = IB_FMR_MAX_REMAPS,
+			.page_shift = params->page_shift
 		};
 
 		for (i = 0; i < params->pool_size; ++i) {
diff -urN oldtree/drivers/infiniband/core/mad.c newtree/drivers/infiniband/core/mad.c
--- oldtree/drivers/infiniband/core/mad.c	2006-02-19 11:41:02.339987368 +0000
+++ newtree/drivers/infiniband/core/mad.c	2006-02-21 15:58:14.862887056 +0000
@@ -679,8 +679,8 @@
 		goto out;
 	}
 	/* Check to post send on QP or process locally */
-	ret = smi_check_local_dr_smp(smp, device, port_num);
-	if (!ret || !device->process_mad)
+	ret = smi_check_local_smp(smp, device);
+	if (!ret)
 		goto out;
 
 	local = kmalloc(sizeof *local, GFP_ATOMIC);
@@ -1661,9 +1661,7 @@
 					    port_priv->device->node_type,
 					    port_priv->port_num))
 			goto out;
-		if (!smi_check_local_dr_smp(&recv->mad.smp,
-					    port_priv->device,
-					    port_priv->port_num))
+		if (!smi_check_local_smp(&recv->mad.smp, port_priv->device))
 			goto out;
 	}
 
diff -urN oldtree/drivers/infiniband/core/smi.h newtree/drivers/infiniband/core/smi.h
--- oldtree/drivers/infiniband/core/smi.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/infiniband/core/smi.h	2006-02-21 15:58:14.868886144 +0000
@@ -49,19 +49,16 @@
 extern int smi_handle_dr_smp_send(struct ib_smp *smp,
 				  u8 node_type,
 				  int port_num);
-extern int smi_check_local_dr_smp(struct ib_smp *smp,
-				  struct ib_device *device,
-				  int port_num);
 
 /*
  * Return 1 if the SMP should be handled by the local SMA/SM via process_mad
  */
-static inline int smi_check_local_smp(struct ib_mad_agent *mad_agent,
-                         	      struct ib_smp *smp)
+static inline int smi_check_local_smp(struct ib_smp *smp,
+				      struct ib_device *device)
 {
 	/* C14-9:3 -- We're at the end of the DR segment of path */
 	/* C14-9:4 -- Hop Pointer = Hop Count + 1 -> give to SMA/SM */
-	return ((mad_agent->device->process_mad &&
+	return ((device->process_mad &&
 		!ib_get_smp_direction(smp) &&
 		(smp->hop_ptr == smp->hop_cnt + 1)));
 }
diff -urN oldtree/drivers/infiniband/core/sysfs.c newtree/drivers/infiniband/core/sysfs.c
--- oldtree/drivers/infiniband/core/sysfs.c	2006-02-19 11:41:02.340987216 +0000
+++ newtree/drivers/infiniband/core/sysfs.c	2006-02-21 15:58:14.869885992 +0000
@@ -628,14 +628,42 @@
 		       be16_to_cpu(((__be16 *) &dev->node_guid)[3]));
 }
 
+static ssize_t show_node_desc(struct class_device *cdev, char *buf)
+{
+	struct ib_device *dev = container_of(cdev, struct ib_device, class_dev);
+
+	return sprintf(buf, "%.64s\n", dev->node_desc);
+}
+
+static ssize_t set_node_desc(struct class_device *cdev, const char *buf,
+			      size_t count)
+{
+	struct ib_device *dev = container_of(cdev, struct ib_device, class_dev);
+	struct ib_device_modify desc = {};
+	int ret;
+
+	if (!dev->modify_device)
+		return -EIO;
+
+	memcpy(desc.node_desc, buf, min_t(int, count, 64));
+	ret = ib_modify_device(dev, IB_DEVICE_MODIFY_NODE_DESC, &desc);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
 static CLASS_DEVICE_ATTR(node_type, S_IRUGO, show_node_type, NULL);
 static CLASS_DEVICE_ATTR(sys_image_guid, S_IRUGO, show_sys_image_guid, NULL);
 static CLASS_DEVICE_ATTR(node_guid, S_IRUGO, show_node_guid, NULL);
+static CLASS_DEVICE_ATTR(node_desc, S_IRUGO | S_IWUSR, show_node_desc,
+			 set_node_desc);
 
 static struct class_device_attribute *ib_class_attributes[] = {
 	&class_device_attr_node_type,
 	&class_device_attr_sys_image_guid,
-	&class_device_attr_node_guid
+	&class_device_attr_node_guid,
+	&class_device_attr_node_desc
 };
 
 static struct class ib_class = {
diff -urN oldtree/drivers/infiniband/core/uverbs.h newtree/drivers/infiniband/core/uverbs.h
--- oldtree/drivers/infiniband/core/uverbs.h	2006-02-19 11:41:02.343986760 +0000
+++ newtree/drivers/infiniband/core/uverbs.h	2006-02-21 15:58:14.869885992 +0000
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
  * Copyright (c) 2005 PathScale, Inc. All rights reserved.
@@ -178,10 +178,12 @@
 IB_UVERBS_DECLARE_CMD(dereg_mr);
 IB_UVERBS_DECLARE_CMD(create_comp_channel);
 IB_UVERBS_DECLARE_CMD(create_cq);
+IB_UVERBS_DECLARE_CMD(resize_cq);
 IB_UVERBS_DECLARE_CMD(poll_cq);
 IB_UVERBS_DECLARE_CMD(req_notify_cq);
 IB_UVERBS_DECLARE_CMD(destroy_cq);
 IB_UVERBS_DECLARE_CMD(create_qp);
+IB_UVERBS_DECLARE_CMD(query_qp);
 IB_UVERBS_DECLARE_CMD(modify_qp);
 IB_UVERBS_DECLARE_CMD(destroy_qp);
 IB_UVERBS_DECLARE_CMD(post_send);
@@ -193,6 +195,7 @@
 IB_UVERBS_DECLARE_CMD(detach_mcast);
 IB_UVERBS_DECLARE_CMD(create_srq);
 IB_UVERBS_DECLARE_CMD(modify_srq);
+IB_UVERBS_DECLARE_CMD(query_srq);
 IB_UVERBS_DECLARE_CMD(destroy_srq);
 
 #endif /* UVERBS_H */
diff -urN oldtree/drivers/infiniband/core/uverbs_cmd.c newtree/drivers/infiniband/core/uverbs_cmd.c
--- oldtree/drivers/infiniband/core/uverbs_cmd.c	2006-02-19 11:41:02.344986608 +0000
+++ newtree/drivers/infiniband/core/uverbs_cmd.c	2006-02-21 15:58:14.873885384 +0000
@@ -1,7 +1,8 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 PathScale, Inc.  All rights reserved.
+ * Copyright (c) 2006 Mellanox Technologies.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -675,6 +676,46 @@
 	return ret;
 }
 
+ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file,
+			    const char __user *buf, int in_len,
+			    int out_len)
+{
+	struct ib_uverbs_resize_cq	cmd;
+	struct ib_uverbs_resize_cq_resp	resp;
+	struct ib_udata                 udata;
+	struct ib_cq			*cq;
+	int				ret = -EINVAL;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	INIT_UDATA(&udata, buf + sizeof cmd,
+		   (unsigned long) cmd.response + sizeof resp,
+		   in_len - sizeof cmd, out_len - sizeof resp);
+
+	mutex_lock(&ib_uverbs_idr_mutex);
+
+	cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
+	if (!cq || cq->uobject->context != file->ucontext || !cq->device->resize_cq)
+		goto out;
+
+	ret = cq->device->resize_cq(cq, cmd.cqe, &udata);
+	if (ret)
+		goto out;
+
+	memset(&resp, 0, sizeof resp);
+	resp.cqe = cq->cqe;
+
+	if (copy_to_user((void __user *) (unsigned long) cmd.response,
+			 &resp, sizeof resp))
+		ret = -EFAULT;
+
+out:
+	mutex_unlock(&ib_uverbs_idr_mutex);
+
+	return ret ? ret : in_len;
+}
+
 ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
 			  const char __user *buf, int in_len,
 			  int out_len)
@@ -956,6 +997,106 @@
 	return ret;
 }
 
+ssize_t ib_uverbs_query_qp(struct ib_uverbs_file *file,
+			   const char __user *buf, int in_len,
+			   int out_len)
+{
+	struct ib_uverbs_query_qp      cmd;
+	struct ib_uverbs_query_qp_resp resp;
+	struct ib_qp                   *qp;
+	struct ib_qp_attr              *attr;
+	struct ib_qp_init_attr         *init_attr;
+	int                            ret;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	attr      = kmalloc(sizeof *attr, GFP_KERNEL);
+	init_attr = kmalloc(sizeof *init_attr, GFP_KERNEL);
+	if (!attr || !init_attr) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	mutex_lock(&ib_uverbs_idr_mutex);
+
+	qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
+	if (qp && qp->uobject->context == file->ucontext)
+		ret = ib_query_qp(qp, attr, cmd.attr_mask, init_attr);
+	else
+		ret = -EINVAL;
+
+	mutex_unlock(&ib_uverbs_idr_mutex);
+
+	if (ret)
+		goto out;
+
+	memset(&resp, 0, sizeof resp);
+
+	resp.qp_state               = attr->qp_state;
+	resp.cur_qp_state           = attr->cur_qp_state;
+	resp.path_mtu               = attr->path_mtu;
+	resp.path_mig_state         = attr->path_mig_state;
+	resp.qkey                   = attr->qkey;
+	resp.rq_psn                 = attr->rq_psn;
+	resp.sq_psn                 = attr->sq_psn;
+	resp.dest_qp_num            = attr->dest_qp_num;
+	resp.qp_access_flags        = attr->qp_access_flags;
+	resp.pkey_index             = attr->pkey_index;
+	resp.alt_pkey_index         = attr->alt_pkey_index;
+	resp.en_sqd_async_notify    = attr->en_sqd_async_notify;
+	resp.max_rd_atomic          = attr->max_rd_atomic;
+	resp.max_dest_rd_atomic     = attr->max_dest_rd_atomic;
+	resp.min_rnr_timer          = attr->min_rnr_timer;
+	resp.port_num               = attr->port_num;
+	resp.timeout                = attr->timeout;
+	resp.retry_cnt              = attr->retry_cnt;
+	resp.rnr_retry              = attr->rnr_retry;
+	resp.alt_port_num           = attr->alt_port_num;
+	resp.alt_timeout            = attr->alt_timeout;
+
+	memcpy(resp.dest.dgid, attr->ah_attr.grh.dgid.raw, 16);
+	resp.dest.flow_label        = attr->ah_attr.grh.flow_label;
+	resp.dest.sgid_index        = attr->ah_attr.grh.sgid_index;
+	resp.dest.hop_limit         = attr->ah_attr.grh.hop_limit;
+	resp.dest.traffic_class     = attr->ah_attr.grh.traffic_class;
+	resp.dest.dlid              = attr->ah_attr.dlid;
+	resp.dest.sl                = attr->ah_attr.sl;
+	resp.dest.src_path_bits     = attr->ah_attr.src_path_bits;
+	resp.dest.static_rate       = attr->ah_attr.static_rate;
+	resp.dest.is_global         = !!(attr->ah_attr.ah_flags & IB_AH_GRH);
+	resp.dest.port_num          = attr->ah_attr.port_num;
+
+	memcpy(resp.alt_dest.dgid, attr->alt_ah_attr.grh.dgid.raw, 16);
+	resp.alt_dest.flow_label    = attr->alt_ah_attr.grh.flow_label;
+	resp.alt_dest.sgid_index    = attr->alt_ah_attr.grh.sgid_index;
+	resp.alt_dest.hop_limit     = attr->alt_ah_attr.grh.hop_limit;
+	resp.alt_dest.traffic_class = attr->alt_ah_attr.grh.traffic_class;
+	resp.alt_dest.dlid          = attr->alt_ah_attr.dlid;
+	resp.alt_dest.sl            = attr->alt_ah_attr.sl;
+	resp.alt_dest.src_path_bits = attr->alt_ah_attr.src_path_bits;
+	resp.alt_dest.static_rate   = attr->alt_ah_attr.static_rate;
+	resp.alt_dest.is_global     = !!(attr->alt_ah_attr.ah_flags & IB_AH_GRH);
+	resp.alt_dest.port_num      = attr->alt_ah_attr.port_num;
+
+	resp.max_send_wr            = init_attr->cap.max_send_wr;
+	resp.max_recv_wr            = init_attr->cap.max_recv_wr;
+	resp.max_send_sge           = init_attr->cap.max_send_sge;
+	resp.max_recv_sge           = init_attr->cap.max_recv_sge;
+	resp.max_inline_data        = init_attr->cap.max_inline_data;
+	resp.sq_sig_all             = !!init_attr->sq_sig_type;
+
+	if (copy_to_user((void __user *) (unsigned long) cmd.response,
+			 &resp, sizeof resp))
+		ret = -EFAULT;
+
+out:
+	kfree(attr);
+	kfree(init_attr);
+
+	return ret ? ret : in_len;
+}
+
 ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
 			    const char __user *buf, int in_len,
 			    int out_len)
@@ -1094,8 +1235,8 @@
 }
 
 ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
-                            const char __user *buf, int in_len,
-                            int out_len)
+			    const char __user *buf, int in_len,
+			    int out_len)
 {
 	struct ib_uverbs_post_send      cmd;
 	struct ib_uverbs_post_send_resp resp;
@@ -1323,8 +1464,8 @@
 }
 
 ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file,
-                            const char __user *buf, int in_len,
-                            int out_len)
+			    const char __user *buf, int in_len,
+			    int out_len)
 {
 	struct ib_uverbs_post_recv      cmd;
 	struct ib_uverbs_post_recv_resp resp;
@@ -1374,8 +1515,8 @@
 }
 
 ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file,
-                            const char __user *buf, int in_len,
-                            int out_len)
+				const char __user *buf, int in_len,
+				int out_len)
 {
 	struct ib_uverbs_post_srq_recv      cmd;
 	struct ib_uverbs_post_srq_recv_resp resp;
@@ -1783,6 +1924,49 @@
 	return ret ? ret : in_len;
 }
 
+ssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file,
+			    const char __user *buf,
+			    int in_len, int out_len)
+{
+	struct ib_uverbs_query_srq      cmd;
+	struct ib_uverbs_query_srq_resp resp;
+	struct ib_srq_attr              attr;
+	struct ib_srq                   *srq;
+	int                             ret;
+
+	if (out_len < sizeof resp)
+		return -ENOSPC;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	mutex_lock(&ib_uverbs_idr_mutex);
+
+	srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
+	if (srq && srq->uobject->context == file->ucontext)
+		ret = ib_query_srq(srq, &attr);
+	else
+		ret = -EINVAL;
+
+	mutex_unlock(&ib_uverbs_idr_mutex);
+
+	if (ret)
+		goto out;
+
+	memset(&resp, 0, sizeof resp);
+
+	resp.max_wr    = attr.max_wr;
+	resp.max_sge   = attr.max_sge;
+	resp.srq_limit = attr.srq_limit;
+
+	if (copy_to_user((void __user *) (unsigned long) cmd.response,
+			 &resp, sizeof resp))
+		ret = -EFAULT;
+
+out:
+	return ret ? ret : in_len;
+}
+
 ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
 			      const char __user *buf, int in_len,
 			      int out_len)
diff -urN oldtree/drivers/infiniband/core/uverbs_main.c newtree/drivers/infiniband/core/uverbs_main.c
--- oldtree/drivers/infiniband/core/uverbs_main.c	2006-02-19 11:41:02.345986456 +0000
+++ newtree/drivers/infiniband/core/uverbs_main.c	2006-02-21 15:58:14.874885232 +0000
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
  * Copyright (c) 2005 PathScale, Inc. All rights reserved.
@@ -91,10 +91,12 @@
 	[IB_USER_VERBS_CMD_DEREG_MR]      	= ib_uverbs_dereg_mr,
 	[IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL] = ib_uverbs_create_comp_channel,
 	[IB_USER_VERBS_CMD_CREATE_CQ]     	= ib_uverbs_create_cq,
+	[IB_USER_VERBS_CMD_RESIZE_CQ]     	= ib_uverbs_resize_cq,
 	[IB_USER_VERBS_CMD_POLL_CQ]     	= ib_uverbs_poll_cq,
 	[IB_USER_VERBS_CMD_REQ_NOTIFY_CQ]     	= ib_uverbs_req_notify_cq,
 	[IB_USER_VERBS_CMD_DESTROY_CQ]    	= ib_uverbs_destroy_cq,
 	[IB_USER_VERBS_CMD_CREATE_QP]     	= ib_uverbs_create_qp,
+	[IB_USER_VERBS_CMD_QUERY_QP]     	= ib_uverbs_query_qp,
 	[IB_USER_VERBS_CMD_MODIFY_QP]     	= ib_uverbs_modify_qp,
 	[IB_USER_VERBS_CMD_DESTROY_QP]    	= ib_uverbs_destroy_qp,
 	[IB_USER_VERBS_CMD_POST_SEND]    	= ib_uverbs_post_send,
@@ -106,6 +108,7 @@
 	[IB_USER_VERBS_CMD_DETACH_MCAST]  	= ib_uverbs_detach_mcast,
 	[IB_USER_VERBS_CMD_CREATE_SRQ]    	= ib_uverbs_create_srq,
 	[IB_USER_VERBS_CMD_MODIFY_SRQ]    	= ib_uverbs_modify_srq,
+	[IB_USER_VERBS_CMD_QUERY_SRQ]     	= ib_uverbs_query_srq,
 	[IB_USER_VERBS_CMD_DESTROY_SRQ]   	= ib_uverbs_destroy_srq,
 };
 
@@ -461,7 +464,6 @@
 	ib_uverbs_async_handler(uobj->uverbs_file, uobj->uobject.user_handle,
 				event->event, &uobj->async_list,
 				&uobj->async_events_reported);
-				
 }
 
 void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr)
diff -urN oldtree/drivers/infiniband/core/verbs.c newtree/drivers/infiniband/core/verbs.c
--- oldtree/drivers/infiniband/core/verbs.c	2006-02-19 11:41:02.346986304 +0000
+++ newtree/drivers/infiniband/core/verbs.c	2006-02-21 15:58:14.875885080 +0000
@@ -5,7 +5,7 @@
  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
  * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -245,6 +245,258 @@
 }
 EXPORT_SYMBOL(ib_create_qp);
 
+static const struct {
+	int			valid;
+	enum ib_qp_attr_mask	req_param[IB_QPT_RAW_ETY + 1];
+	enum ib_qp_attr_mask	opt_param[IB_QPT_RAW_ETY + 1];
+} qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
+	[IB_QPS_RESET] = {
+		[IB_QPS_RESET] = { .valid = 1 },
+		[IB_QPS_ERR]   = { .valid = 1 },
+		[IB_QPS_INIT]  = {
+			.valid = 1,
+			.req_param = {
+				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
+						IB_QP_PORT			|
+						IB_QP_QKEY),
+				[IB_QPT_UC]  = (IB_QP_PKEY_INDEX		|
+						IB_QP_PORT			|
+						IB_QP_ACCESS_FLAGS),
+				[IB_QPT_RC]  = (IB_QP_PKEY_INDEX		|
+						IB_QP_PORT			|
+						IB_QP_ACCESS_FLAGS),
+				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
+						IB_QP_QKEY),
+				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
+						IB_QP_QKEY),
+			}
+		},
+	},
+	[IB_QPS_INIT]  = {
+		[IB_QPS_RESET] = { .valid = 1 },
+		[IB_QPS_ERR] =   { .valid = 1 },
+		[IB_QPS_INIT]  = {
+			.valid = 1,
+			.opt_param = {
+				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
+						IB_QP_PORT			|
+						IB_QP_QKEY),
+				[IB_QPT_UC]  = (IB_QP_PKEY_INDEX		|
+						IB_QP_PORT			|
+						IB_QP_ACCESS_FLAGS),
+				[IB_QPT_RC]  = (IB_QP_PKEY_INDEX		|
+						IB_QP_PORT			|
+						IB_QP_ACCESS_FLAGS),
+				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
+						IB_QP_QKEY),
+				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
+						IB_QP_QKEY),
+			}
+		},
+		[IB_QPS_RTR]   = {
+			.valid = 1,
+			.req_param = {
+				[IB_QPT_UC]  = (IB_QP_AV			|
+						IB_QP_PATH_MTU			|
+						IB_QP_DEST_QPN			|
+						IB_QP_RQ_PSN),
+				[IB_QPT_RC]  = (IB_QP_AV			|
+						IB_QP_PATH_MTU			|
+						IB_QP_DEST_QPN			|
+						IB_QP_RQ_PSN			|
+						IB_QP_MAX_DEST_RD_ATOMIC	|
+						IB_QP_MIN_RNR_TIMER),
+			},
+			.opt_param = {
+				 [IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
+						 IB_QP_QKEY),
+				 [IB_QPT_UC]  = (IB_QP_ALT_PATH			|
+						 IB_QP_ACCESS_FLAGS		|
+						 IB_QP_PKEY_INDEX),
+				 [IB_QPT_RC]  = (IB_QP_ALT_PATH			|
+						 IB_QP_ACCESS_FLAGS		|
+						 IB_QP_PKEY_INDEX),
+				 [IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
+						 IB_QP_QKEY),
+				 [IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
+						 IB_QP_QKEY),
+			 }
+		}
+	},
+	[IB_QPS_RTR]   = {
+		[IB_QPS_RESET] = { .valid = 1 },
+		[IB_QPS_ERR] =   { .valid = 1 },
+		[IB_QPS_RTS]   = {
+			.valid = 1,
+			.req_param = {
+				[IB_QPT_UD]  = IB_QP_SQ_PSN,
+				[IB_QPT_UC]  = IB_QP_SQ_PSN,
+				[IB_QPT_RC]  = (IB_QP_TIMEOUT			|
+						IB_QP_RETRY_CNT			|
+						IB_QP_RNR_RETRY			|
+						IB_QP_SQ_PSN			|
+						IB_QP_MAX_QP_RD_ATOMIC),
+				[IB_QPT_SMI] = IB_QP_SQ_PSN,
+				[IB_QPT_GSI] = IB_QP_SQ_PSN,
+			},
+			.opt_param = {
+				 [IB_QPT_UD]  = (IB_QP_CUR_STATE		|
+						 IB_QP_QKEY),
+				 [IB_QPT_UC]  = (IB_QP_CUR_STATE		|
+						 IB_QP_ALT_PATH			|
+						 IB_QP_ACCESS_FLAGS		|
+						 IB_QP_PATH_MIG_STATE),
+				 [IB_QPT_RC]  = (IB_QP_CUR_STATE		|
+						 IB_QP_ALT_PATH			|
+						 IB_QP_ACCESS_FLAGS		|
+						 IB_QP_MIN_RNR_TIMER		|
+						 IB_QP_PATH_MIG_STATE),
+				 [IB_QPT_SMI] = (IB_QP_CUR_STATE		|
+						 IB_QP_QKEY),
+				 [IB_QPT_GSI] = (IB_QP_CUR_STATE		|
+						 IB_QP_QKEY),
+			 }
+		}
+	},
+	[IB_QPS_RTS]   = {
+		[IB_QPS_RESET] = { .valid = 1 },
+		[IB_QPS_ERR] =   { .valid = 1 },
+		[IB_QPS_RTS]   = {
+			.valid = 1,
+			.opt_param = {
+				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
+						IB_QP_QKEY),
+				[IB_QPT_UC]  = (IB_QP_ACCESS_FLAGS		|
+						IB_QP_ALT_PATH			|
+						IB_QP_PATH_MIG_STATE),
+				[IB_QPT_RC]  = (IB_QP_ACCESS_FLAGS		|
+						IB_QP_ALT_PATH			|
+						IB_QP_PATH_MIG_STATE		|
+						IB_QP_MIN_RNR_TIMER),
+				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
+						IB_QP_QKEY),
+				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
+						IB_QP_QKEY),
+			}
+		},
+		[IB_QPS_SQD]   = {
+			.valid = 1,
+			.opt_param = {
+				[IB_QPT_UD]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
+				[IB_QPT_UC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
+				[IB_QPT_RC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
+				[IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
+				[IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY
+			}
+		},
+	},
+	[IB_QPS_SQD]   = {
+		[IB_QPS_RESET] = { .valid = 1 },
+		[IB_QPS_ERR] =   { .valid = 1 },
+		[IB_QPS_RTS]   = {
+			.valid = 1,
+			.opt_param = {
+				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
+						IB_QP_QKEY),
+				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
+						IB_QP_ALT_PATH			|
+						IB_QP_ACCESS_FLAGS		|
+						IB_QP_PATH_MIG_STATE),
+				[IB_QPT_RC]  = (IB_QP_CUR_STATE			|
+						IB_QP_ALT_PATH			|
+						IB_QP_ACCESS_FLAGS		|
+						IB_QP_MIN_RNR_TIMER		|
+						IB_QP_PATH_MIG_STATE),
+				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
+						IB_QP_QKEY),
+				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
+						IB_QP_QKEY),
+			}
+		},
+		[IB_QPS_SQD]   = {
+			.valid = 1,
+			.opt_param = {
+				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
+						IB_QP_QKEY),
+				[IB_QPT_UC]  = (IB_QP_AV			|
+						IB_QP_CUR_STATE			|
+						IB_QP_ALT_PATH			|
+						IB_QP_ACCESS_FLAGS		|
+						IB_QP_PKEY_INDEX		|
+						IB_QP_PATH_MIG_STATE),
+				[IB_QPT_RC]  = (IB_QP_PORT			|
+						IB_QP_AV			|
+						IB_QP_TIMEOUT			|
+						IB_QP_RETRY_CNT			|
+						IB_QP_RNR_RETRY			|
+						IB_QP_MAX_QP_RD_ATOMIC		|
+						IB_QP_MAX_DEST_RD_ATOMIC	|
+						IB_QP_CUR_STATE			|
+						IB_QP_ALT_PATH			|
+						IB_QP_ACCESS_FLAGS		|
+						IB_QP_PKEY_INDEX		|
+						IB_QP_MIN_RNR_TIMER		|
+						IB_QP_PATH_MIG_STATE),
+				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
+						IB_QP_QKEY),
+				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
+						IB_QP_QKEY),
+			}
+		}
+	},
+	[IB_QPS_SQE]   = {
+		[IB_QPS_RESET] = { .valid = 1 },
+		[IB_QPS_ERR] =   { .valid = 1 },
+		[IB_QPS_RTS]   = {
+			.valid = 1,
+			.opt_param = {
+				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
+						IB_QP_QKEY),
+				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
+						IB_QP_ACCESS_FLAGS),
+				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
+						IB_QP_QKEY),
+				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
+						IB_QP_QKEY),
+			}
+		}
+	},
+	[IB_QPS_ERR] = {
+		[IB_QPS_RESET] = { .valid = 1 },
+		[IB_QPS_ERR] =   { .valid = 1 }
+	}
+};
+
+int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
+		       enum ib_qp_type type, enum ib_qp_attr_mask mask)
+{
+	enum ib_qp_attr_mask req_param, opt_param;
+
+	if (cur_state  < 0 || cur_state  > IB_QPS_ERR ||
+	    next_state < 0 || next_state > IB_QPS_ERR)
+		return 0;
+
+	if (mask & IB_QP_CUR_STATE  &&
+	    cur_state != IB_QPS_RTR && cur_state != IB_QPS_RTS &&
+	    cur_state != IB_QPS_SQD && cur_state != IB_QPS_SQE)
+		return 0;
+
+	if (!qp_state_table[cur_state][next_state].valid)
+		return 0;
+
+	req_param = qp_state_table[cur_state][next_state].req_param[type];
+	opt_param = qp_state_table[cur_state][next_state].opt_param[type];
+
+	if ((mask & req_param) != req_param)
+		return 0;
+
+	if (mask & ~(req_param | opt_param | IB_QP_STATE))
+		return 0;
+
+	return 1;
+}
+EXPORT_SYMBOL(ib_modify_qp_is_ok);
+
 int ib_modify_qp(struct ib_qp *qp,
 		 struct ib_qp_attr *qp_attr,
 		 int qp_attr_mask)
@@ -322,11 +574,10 @@
 }
 EXPORT_SYMBOL(ib_destroy_cq);
 
-int ib_resize_cq(struct ib_cq *cq,
-                 int           cqe)
+int ib_resize_cq(struct ib_cq *cq, int cqe)
 {
 	return cq->device->resize_cq ?
-		cq->device->resize_cq(cq, cqe) : -ENOSYS;
+		cq->device->resize_cq(cq, cqe, NULL) : -ENOSYS;
 }
 EXPORT_SYMBOL(ib_resize_cq);
 
diff -urN oldtree/drivers/infiniband/hw/mthca/mthca_av.c newtree/drivers/infiniband/hw/mthca/mthca_av.c
--- oldtree/drivers/infiniband/hw/mthca/mthca_av.c	2006-02-19 11:41:02.346986304 +0000
+++ newtree/drivers/infiniband/hw/mthca/mthca_av.c	2006-02-21 15:58:14.876884928 +0000
@@ -147,7 +147,7 @@
 	switch (ah->type) {
 	case MTHCA_AH_ON_HCA:
 		mthca_free(&dev->av_table.alloc,
- 			   (ah->avdma - dev->av_table.ddr_av_base) /
+			   (ah->avdma - dev->av_table.ddr_av_base) /
 			   MTHCA_AV_SIZE);
 		break;
 
diff -urN oldtree/drivers/infiniband/hw/mthca/mthca_cmd.c newtree/drivers/infiniband/hw/mthca/mthca_cmd.c
--- oldtree/drivers/infiniband/hw/mthca/mthca_cmd.c	2006-02-19 11:41:02.347986152 +0000
+++ newtree/drivers/infiniband/hw/mthca/mthca_cmd.c	2006-02-21 15:58:14.878884624 +0000
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
- * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -275,7 +275,7 @@
 	}
 
 	if (out_is_imm)
-		*out_param = 
+		*out_param =
 			(u64) be32_to_cpu((__force __be32)
 					  __raw_readl(dev->hcr + HCR_OUT_PARAM_OFFSET)) << 32 |
 			(u64) be32_to_cpu((__force __be32)
@@ -1514,6 +1514,37 @@
 			     CMD_TIME_CLASS_A, status);
 }
 
+int mthca_RESIZE_CQ(struct mthca_dev *dev, int cq_num, u32 lkey, u8 log_size,
+		    u8 *status)
+{
+	struct mthca_mailbox *mailbox;
+	__be32 *inbox;
+	int err;
+
+#define RESIZE_CQ_IN_SIZE		0x40
+#define RESIZE_CQ_LOG_SIZE_OFFSET	0x0c
+#define RESIZE_CQ_LKEY_OFFSET		0x1c
+
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+	inbox = mailbox->buf;
+
+	memset(inbox, 0, RESIZE_CQ_IN_SIZE);
+	/*
+	 * Leave start address fields zeroed out -- mthca assumes that
+	 * MRs for CQs always start at virtual address 0.
+	 */
+	MTHCA_PUT(inbox, log_size, RESIZE_CQ_LOG_SIZE_OFFSET);
+	MTHCA_PUT(inbox, lkey,     RESIZE_CQ_LKEY_OFFSET);
+
+	err = mthca_cmd(dev, mailbox->dma, cq_num, 1, CMD_RESIZE_CQ,
+			CMD_TIME_CLASS_B, status);
+
+	mthca_free_mailbox(dev, mailbox);
+	return err;
+}
+
 int mthca_SW2HW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		    int srq_num, u8 *status)
 {
@@ -1529,37 +1560,69 @@
 			     CMD_TIME_CLASS_A, status);
 }
 
+int mthca_QUERY_SRQ(struct mthca_dev *dev, u32 num,
+		    struct mthca_mailbox *mailbox, u8 *status)
+{
+	return mthca_cmd_box(dev, 0, mailbox->dma, num, 0,
+			     CMD_QUERY_SRQ, CMD_TIME_CLASS_A, status);
+}
+
 int mthca_ARM_SRQ(struct mthca_dev *dev, int srq_num, int limit, u8 *status)
 {
 	return mthca_cmd(dev, limit, srq_num, 0, CMD_ARM_SRQ,
 			 CMD_TIME_CLASS_B, status);
 }
 
-int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
-		    int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
+int mthca_MODIFY_QP(struct mthca_dev *dev, enum ib_qp_state cur,
+		    enum ib_qp_state next, u32 num, int is_ee,
+		    struct mthca_mailbox *mailbox, u32 optmask,
 		    u8 *status)
 {
-	static const u16 op[] = {
-		[MTHCA_TRANS_RST2INIT]  = CMD_RST2INIT_QPEE,
-		[MTHCA_TRANS_INIT2INIT] = CMD_INIT2INIT_QPEE,
-		[MTHCA_TRANS_INIT2RTR]  = CMD_INIT2RTR_QPEE,
-		[MTHCA_TRANS_RTR2RTS]   = CMD_RTR2RTS_QPEE,
-		[MTHCA_TRANS_RTS2RTS]   = CMD_RTS2RTS_QPEE,
-		[MTHCA_TRANS_SQERR2RTS] = CMD_SQERR2RTS_QPEE,
-		[MTHCA_TRANS_ANY2ERR]   = CMD_2ERR_QPEE,
-		[MTHCA_TRANS_RTS2SQD]   = CMD_RTS2SQD_QPEE,
-		[MTHCA_TRANS_SQD2SQD]   = CMD_SQD2SQD_QPEE,
-		[MTHCA_TRANS_SQD2RTS]   = CMD_SQD2RTS_QPEE,
-		[MTHCA_TRANS_ANY2RST]   = CMD_ERR2RST_QPEE
+	static const u16 op[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
+		[IB_QPS_RESET] = {
+			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
+			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
+			[IB_QPS_INIT]	= CMD_RST2INIT_QPEE,
+		},
+		[IB_QPS_INIT]  = {
+			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
+			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
+			[IB_QPS_INIT]	= CMD_INIT2INIT_QPEE,
+			[IB_QPS_RTR]	= CMD_INIT2RTR_QPEE,
+		},
+		[IB_QPS_RTR]   = {
+			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
+			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
+			[IB_QPS_RTS]	= CMD_RTR2RTS_QPEE,
+		},
+		[IB_QPS_RTS]   = {
+			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
+			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
+			[IB_QPS_RTS]	= CMD_RTS2RTS_QPEE,
+			[IB_QPS_SQD]	= CMD_RTS2SQD_QPEE,
+		},
+		[IB_QPS_SQD] = {
+			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
+			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
+			[IB_QPS_RTS]	= CMD_SQD2RTS_QPEE,
+			[IB_QPS_SQD]	= CMD_SQD2SQD_QPEE,
+		},
+		[IB_QPS_SQE] = {
+			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
+			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
+			[IB_QPS_RTS]	= CMD_SQERR2RTS_QPEE,
+		},
+		[IB_QPS_ERR] = {
+			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
+			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
+		}
 	};
+
 	u8 op_mod = 0;
 	int my_mailbox = 0;
 	int err;
 
-	if (trans < 0 || trans >= ARRAY_SIZE(op))
-		return -EINVAL;
-
-	if (trans == MTHCA_TRANS_ANY2RST) {
+	if (op[cur][next] == CMD_ERR2RST_QPEE) {
 		op_mod = 3;	/* don't write outbox, any->reset */
 
 		/* For debugging */
@@ -1571,34 +1634,35 @@
 			} else
 				mailbox = NULL;
 		}
-	} else {
-		if (0) {
+
+		err = mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0,
+				    (!!is_ee << 24) | num, op_mod,
+				    op[cur][next], CMD_TIME_CLASS_C, status);
+
+		if (0 && mailbox) {
 			int i;
 			mthca_dbg(dev, "Dumping QP context:\n");
-			printk("  opt param mask: %08x\n", be32_to_cpup(mailbox->buf));
+			printk(" %08x\n", be32_to_cpup(mailbox->buf));
 			for (i = 0; i < 0x100 / 4; ++i) {
 				if (i % 8 == 0)
-					printk("  [%02x] ", i * 4);
+					printk("[%02x] ", i * 4);
 				printk(" %08x",
 				       be32_to_cpu(((__be32 *) mailbox->buf)[i + 2]));
 				if ((i + 1) % 8 == 0)
 					printk("\n");
 			}
 		}
-	}
-
-	if (trans == MTHCA_TRANS_ANY2RST) {
-		err = mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0,
-				    (!!is_ee << 24) | num, op_mod,
-				    op[trans], CMD_TIME_CLASS_C, status);
 
-		if (0 && mailbox) {
+		if (my_mailbox)
+			mthca_free_mailbox(dev, mailbox);
+	} else {
+		if (0) {
 			int i;
 			mthca_dbg(dev, "Dumping QP context:\n");
-			printk(" %08x\n", be32_to_cpup(mailbox->buf));
+			printk("  opt param mask: %08x\n", be32_to_cpup(mailbox->buf));
 			for (i = 0; i < 0x100 / 4; ++i) {
 				if (i % 8 == 0)
-					printk("[%02x] ", i * 4);
+					printk("  [%02x] ", i * 4);
 				printk(" %08x",
 				       be32_to_cpu(((__be32 *) mailbox->buf)[i + 2]));
 				if ((i + 1) % 8 == 0)
@@ -1606,12 +1670,9 @@
 			}
 		}
 
-	} else
-		err = mthca_cmd(dev, mailbox->dma, (!!is_ee << 24) | num,
-				op_mod, op[trans], CMD_TIME_CLASS_C, status);
-
-	if (my_mailbox)
-		mthca_free_mailbox(dev, mailbox);
+		err = mthca_cmd(dev, mailbox->dma, optmask | (!!is_ee << 24) | num,
+				op_mod, op[cur][next], CMD_TIME_CLASS_C, status);
+	}
 
 	return err;
 }
diff -urN oldtree/drivers/infiniband/hw/mthca/mthca_cmd.h newtree/drivers/infiniband/hw/mthca/mthca_cmd.h
--- oldtree/drivers/infiniband/hw/mthca/mthca_cmd.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/infiniband/hw/mthca/mthca_cmd.h	2006-02-21 15:58:14.884883712 +0000
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2006 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -73,9 +74,9 @@
 	MTHCA_CMD_STAT_REG_BOUND      = 0x21,
 	/* HCA local attached memory not present: */
 	MTHCA_CMD_STAT_LAM_NOT_PRE    = 0x22,
-        /* Bad management packet (silently discarded): */
+	/* Bad management packet (silently discarded): */
 	MTHCA_CMD_STAT_BAD_PKT 	      = 0x30,
-        /* More outstanding CQEs in CQ than new CQ size: */
+	/* More outstanding CQEs in CQ than new CQ size: */
 	MTHCA_CMD_STAT_BAD_SIZE       = 0x40
 };
 
@@ -298,13 +299,18 @@
 		   int cq_num, u8 *status);
 int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		   int cq_num, u8 *status);
+int mthca_RESIZE_CQ(struct mthca_dev *dev, int cq_num, u32 lkey, u8 log_size,
+		    u8 *status);
 int mthca_SW2HW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		    int srq_num, u8 *status);
 int mthca_HW2SW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		    int srq_num, u8 *status);
+int mthca_QUERY_SRQ(struct mthca_dev *dev, u32 num,
+		    struct mthca_mailbox *mailbox, u8 *status);
 int mthca_ARM_SRQ(struct mthca_dev *dev, int srq_num, int limit, u8 *status);
-int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
-		    int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
+int mthca_MODIFY_QP(struct mthca_dev *dev, enum ib_qp_state cur,
+		    enum ib_qp_state next, u32 num, int is_ee,
+		    struct mthca_mailbox *mailbox, u32 optmask,
 		    u8 *status);
 int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee,
 		   struct mthca_mailbox *mailbox, u8 *status);
diff -urN oldtree/drivers/infiniband/hw/mthca/mthca_cq.c newtree/drivers/infiniband/hw/mthca/mthca_cq.c
--- oldtree/drivers/infiniband/hw/mthca/mthca_cq.c	2006-02-19 11:41:02.348986000 +0000
+++ newtree/drivers/infiniband/hw/mthca/mthca_cq.c	2006-02-21 15:58:14.886883408 +0000
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
@@ -150,24 +150,29 @@
 #define MTHCA_ARBEL_CQ_DB_REQ_NOT      (2 << 24)
 #define MTHCA_ARBEL_CQ_DB_REQ_NOT_MULT (3 << 24)
 
-static inline struct mthca_cqe *get_cqe(struct mthca_cq *cq, int entry)
+static inline struct mthca_cqe *get_cqe_from_buf(struct mthca_cq_buf *buf,
+						 int entry)
 {
-	if (cq->is_direct)
-		return cq->queue.direct.buf + (entry * MTHCA_CQ_ENTRY_SIZE);
+	if (buf->is_direct)
+		return buf->queue.direct.buf + (entry * MTHCA_CQ_ENTRY_SIZE);
 	else
-		return cq->queue.page_list[entry * MTHCA_CQ_ENTRY_SIZE / PAGE_SIZE].buf
+		return buf->queue.page_list[entry * MTHCA_CQ_ENTRY_SIZE / PAGE_SIZE].buf
 			+ (entry * MTHCA_CQ_ENTRY_SIZE) % PAGE_SIZE;
 }
 
-static inline struct mthca_cqe *cqe_sw(struct mthca_cq *cq, int i)
+static inline struct mthca_cqe *get_cqe(struct mthca_cq *cq, int entry)
+{
+	return get_cqe_from_buf(&cq->buf, entry);
+}
+
+static inline struct mthca_cqe *cqe_sw(struct mthca_cqe *cqe)
 {
-	struct mthca_cqe *cqe = get_cqe(cq, i);
 	return MTHCA_CQ_ENTRY_OWNER_HW & cqe->owner ? NULL : cqe;
 }
 
 static inline struct mthca_cqe *next_cqe_sw(struct mthca_cq *cq)
 {
-	return cqe_sw(cq, cq->cons_index & cq->ibcq.cqe);
+	return cqe_sw(get_cqe(cq, cq->cons_index & cq->ibcq.cqe));
 }
 
 static inline void set_cqe_hw(struct mthca_cqe *cqe)
@@ -289,7 +294,7 @@
 	 * from our QP and therefore don't need to be checked.
 	 */
 	for (prod_index = cq->cons_index;
-	     cqe_sw(cq, prod_index & cq->ibcq.cqe);
+	     cqe_sw(get_cqe(cq, prod_index & cq->ibcq.cqe));
 	     ++prod_index)
 		if (prod_index == cq->cons_index + cq->ibcq.cqe)
 			break;
@@ -324,12 +329,58 @@
 		wake_up(&cq->wait);
 }
 
-static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
-			    struct mthca_qp *qp, int wqe_index, int is_send,
-			    struct mthca_err_cqe *cqe,
-			    struct ib_wc *entry, int *free_cqe)
+void mthca_cq_resize_copy_cqes(struct mthca_cq *cq)
+{
+	int i;
+
+	/*
+	 * In Tavor mode, the hardware keeps the consumer and producer
+	 * indices mod the CQ size.  Since we might be making the CQ
+	 * bigger, we need to deal with the case where the producer
+	 * index wrapped around before the CQ was resized.
+	 */
+	if (!mthca_is_memfree(to_mdev(cq->ibcq.device)) &&
+	    cq->ibcq.cqe < cq->resize_buf->cqe) {
+		cq->cons_index &= cq->ibcq.cqe;
+		if (cqe_sw(get_cqe(cq, cq->ibcq.cqe)))
+			cq->cons_index -= cq->ibcq.cqe + 1;
+	}
+
+	for (i = cq->cons_index; cqe_sw(get_cqe(cq, i & cq->ibcq.cqe)); ++i)
+		memcpy(get_cqe_from_buf(&cq->resize_buf->buf,
+					i & cq->resize_buf->cqe),
+		       get_cqe(cq, i & cq->ibcq.cqe), MTHCA_CQ_ENTRY_SIZE);
+}
+
+int mthca_alloc_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int nent)
+{
+	int ret;
+	int i;
+
+	ret = mthca_buf_alloc(dev, nent * MTHCA_CQ_ENTRY_SIZE,
+			      MTHCA_MAX_DIRECT_CQ_SIZE,
+			      &buf->queue, &buf->is_direct,
+			      &dev->driver_pd, 1, &buf->mr);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < nent; ++i)
+		set_cqe_hw(get_cqe_from_buf(buf, i));
+
+	return 0;
+}
+
+void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int cqe)
+{
+	mthca_buf_free(dev, (cqe + 1) * MTHCA_CQ_ENTRY_SIZE, &buf->queue,
+		       buf->is_direct, &buf->mr);
+}
+
+static void handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
+			     struct mthca_qp *qp, int wqe_index, int is_send,
+			     struct mthca_err_cqe *cqe,
+			     struct ib_wc *entry, int *free_cqe)
 {
-	int err;
 	int dbd;
 	__be32 new_wqe;
 
@@ -412,11 +463,9 @@
 	 * error case, so we don't have to check the doorbell count, etc.
 	 */
 	if (mthca_is_memfree(dev))
-		return 0;
+		return;
 
-	err = mthca_free_err_wqe(dev, qp, is_send, wqe_index, &dbd, &new_wqe);
-	if (err)
-		return err;
+	mthca_free_err_wqe(dev, qp, is_send, wqe_index, &dbd, &new_wqe);
 
 	/*
 	 * If we're at the end of the WQE chain, or we've used up our
@@ -424,15 +473,13 @@
 	 * the next poll operation.
 	 */
 	if (!(new_wqe & cpu_to_be32(0x3f)) || (!cqe->db_cnt && dbd))
-		return 0;
+		return;
 
 	cqe->db_cnt   = cpu_to_be16(be16_to_cpu(cqe->db_cnt) - dbd);
 	cqe->wqe      = new_wqe;
 	cqe->syndrome = SYNDROME_WR_FLUSH_ERR;
 
 	*free_cqe = 0;
-
-	return 0;
 }
 
 static inline int mthca_poll_one(struct mthca_dev *dev,
@@ -518,9 +565,9 @@
 	}
 
 	if (is_error) {
-		err = handle_error_cqe(dev, cq, *cur_qp, wqe_index, is_send,
-				       (struct mthca_err_cqe *) cqe,
-				       entry, &free_cqe);
+		handle_error_cqe(dev, cq, *cur_qp, wqe_index, is_send,
+				 (struct mthca_err_cqe *) cqe,
+				 entry, &free_cqe);
 		goto out;
 	}
 
@@ -614,11 +661,14 @@
 
 	spin_lock_irqsave(&cq->lock, flags);
 
-	for (npolled = 0; npolled < num_entries; ++npolled) {
+	npolled = 0;
+repoll:
+	while (npolled < num_entries) {
 		err = mthca_poll_one(dev, cq, &qp,
 				     &freed, entry + npolled);
 		if (err)
 			break;
+		++npolled;
 	}
 
 	if (freed) {
@@ -626,6 +676,42 @@
 		update_cons_index(dev, cq, freed);
 	}
 
+	/*
+	 * If a CQ resize is in progress and we discovered that the
+	 * old buffer is empty, then peek in the new buffer, and if
+	 * it's not empty, switch to the new buffer and continue
+	 * polling there.
+	 */
+	if (unlikely(err == -EAGAIN && cq->resize_buf &&
+		     cq->resize_buf->state == CQ_RESIZE_READY)) {
+		/*
+		 * In Tavor mode, the hardware keeps the producer
+		 * index modulo the CQ size.  Since we might be making
+		 * the CQ bigger, we need to mask our consumer index
+		 * using the size of the old CQ buffer before looking
+		 * in the new CQ buffer.
+		 */
+		if (!mthca_is_memfree(dev))
+			cq->cons_index &= cq->ibcq.cqe;
+
+		if (cqe_sw(get_cqe_from_buf(&cq->resize_buf->buf,
+					    cq->cons_index & cq->resize_buf->cqe))) {
+			struct mthca_cq_buf tbuf;
+			int tcqe;
+
+			tbuf         = cq->buf;
+			tcqe         = cq->ibcq.cqe;
+			cq->buf      = cq->resize_buf->buf;
+			cq->ibcq.cqe = cq->resize_buf->cqe;
+
+			cq->resize_buf->buf   = tbuf;
+			cq->resize_buf->cqe   = tcqe;
+			cq->resize_buf->state = CQ_RESIZE_SWAPPED;
+
+			goto repoll;
+		}
+	}
+
 	spin_unlock_irqrestore(&cq->lock, flags);
 
 	return err == 0 || err == -EAGAIN ? npolled : err;
@@ -684,24 +770,14 @@
 	return 0;
 }
 
-static void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq *cq)
-{
-	mthca_buf_free(dev, (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
-		       &cq->queue, cq->is_direct, &cq->mr);
-}
-
 int mthca_init_cq(struct mthca_dev *dev, int nent,
 		  struct mthca_ucontext *ctx, u32 pdn,
 		  struct mthca_cq *cq)
 {
-	int size = nent * MTHCA_CQ_ENTRY_SIZE;
 	struct mthca_mailbox *mailbox;
 	struct mthca_cq_context *cq_context;
 	int err = -ENOMEM;
 	u8 status;
-	int i;
-
-	might_sleep();
 
 	cq->ibcq.cqe  = nent - 1;
 	cq->is_kernel = !ctx;
@@ -739,14 +815,9 @@
 	cq_context = mailbox->buf;
 
 	if (cq->is_kernel) {
-		err = mthca_buf_alloc(dev, size, MTHCA_MAX_DIRECT_CQ_SIZE,
-				      &cq->queue, &cq->is_direct,
-				      &dev->driver_pd, 1, &cq->mr);
+		err = mthca_alloc_cq_buf(dev, &cq->buf, nent);
 		if (err)
 			goto err_out_mailbox;
-
-		for (i = 0; i < nent; ++i)
-			set_cqe_hw(get_cqe(cq, i));
 	}
 
 	spin_lock_init(&cq->lock);
@@ -765,7 +836,7 @@
 	cq_context->error_eqn       = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn);
 	cq_context->comp_eqn        = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_COMP].eqn);
 	cq_context->pd              = cpu_to_be32(pdn);
-	cq_context->lkey            = cpu_to_be32(cq->mr.ibmr.lkey);
+	cq_context->lkey            = cpu_to_be32(cq->buf.mr.ibmr.lkey);
 	cq_context->cqn             = cpu_to_be32(cq->cqn);
 
 	if (mthca_is_memfree(dev)) {
@@ -803,7 +874,7 @@
 
 err_out_free_mr:
 	if (cq->is_kernel)
-		mthca_free_cq_buf(dev, cq);
+		mthca_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe);
 
 err_out_mailbox:
 	mthca_free_mailbox(dev, mailbox);
@@ -832,8 +903,6 @@
 	int err;
 	u8 status;
 
-	might_sleep();
-
 	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 	if (IS_ERR(mailbox)) {
 		mthca_warn(dev, "No memory for mailbox to free CQ.\n");
@@ -871,7 +940,7 @@
 	wait_event(cq->wait, !atomic_read(&cq->refcount));
 
 	if (cq->is_kernel) {
-		mthca_free_cq_buf(dev, cq);
+		mthca_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe);
 		if (mthca_is_memfree(dev)) {
 			mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM,    cq->arm_db_index);
 			mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
diff -urN oldtree/drivers/infiniband/hw/mthca/mthca_dev.h newtree/drivers/infiniband/hw/mthca/mthca_dev.h
--- oldtree/drivers/infiniband/hw/mthca/mthca_dev.h	2006-02-19 11:41:02.349985848 +0000
+++ newtree/drivers/infiniband/hw/mthca/mthca_dev.h	2006-02-21 15:58:14.886883408 +0000
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
@@ -53,8 +53,8 @@
 
 #define DRV_NAME	"ib_mthca"
 #define PFX		DRV_NAME ": "
-#define DRV_VERSION	"0.07"
-#define DRV_RELDATE	"February 13, 2006"
+#define DRV_VERSION	"0.08"
+#define DRV_RELDATE	"February 14, 2006"
 
 enum {
 	MTHCA_FLAG_DDR_HIDDEN = 1 << 1,
@@ -470,12 +470,16 @@
 		    enum ib_event_type event_type);
 void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn,
 		    struct mthca_srq *srq);
+void mthca_cq_resize_copy_cqes(struct mthca_cq *cq);
+int mthca_alloc_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int nent);
+void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int cqe);
 
 int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
 		    struct ib_srq_attr *attr, struct mthca_srq *srq);
 void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq);
 int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
 		     enum ib_srq_attr_mask attr_mask);
+int mthca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr);
 void mthca_srq_event(struct mthca_dev *dev, u32 srqn,
 		     enum ib_event_type event_type);
 void mthca_free_srq_wqe(struct mthca_srq *srq, u32 wqe_addr);
@@ -486,6 +490,8 @@
 
 void mthca_qp_event(struct mthca_dev *dev, u32 qpn,
 		    enum ib_event_type event_type);
+int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask,
+		   struct ib_qp_init_attr *qp_init_attr);
 int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask);
 int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 			  struct ib_send_wr **bad_wr);
@@ -495,8 +501,8 @@
 			  struct ib_send_wr **bad_wr);
 int mthca_arbel_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
 			     struct ib_recv_wr **bad_wr);
-int mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
-		       int index, int *dbd, __be32 *new_wqe);
+void mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
+			int index, int *dbd, __be32 *new_wqe);
 int mthca_alloc_qp(struct mthca_dev *dev,
 		   struct mthca_pd *pd,
 		   struct mthca_cq *send_cq,
diff -urN oldtree/drivers/infiniband/hw/mthca/mthca_eq.c newtree/drivers/infiniband/hw/mthca/mthca_eq.c
--- oldtree/drivers/infiniband/hw/mthca/mthca_eq.c	2006-02-19 11:41:02.350985696 +0000
+++ newtree/drivers/infiniband/hw/mthca/mthca_eq.c	2006-02-21 15:58:14.887883256 +0000
@@ -497,7 +497,7 @@
 
 	eq->dev  = dev;
 	eq->nent = roundup_pow_of_two(max(nent, 2));
- 	npages = ALIGN(eq->nent * MTHCA_EQ_ENTRY_SIZE, PAGE_SIZE) / PAGE_SIZE;
+	npages = ALIGN(eq->nent * MTHCA_EQ_ENTRY_SIZE, PAGE_SIZE) / PAGE_SIZE;
 
 	eq->page_list = kmalloc(npages * sizeof *eq->page_list,
 				GFP_KERNEL);
diff -urN oldtree/drivers/infiniband/hw/mthca/mthca_mad.c newtree/drivers/infiniband/hw/mthca/mthca_mad.c
--- oldtree/drivers/infiniband/hw/mthca/mthca_mad.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/infiniband/hw/mthca/mthca_mad.c	2006-02-21 15:58:14.888883104 +0000
@@ -109,6 +109,19 @@
 	}
 }
 
+static void node_desc_override(struct ib_device *dev,
+			       struct ib_mad *mad)
+{
+	if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
+	     mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
+	    mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP &&
+	    mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) {
+		mutex_lock(&to_mdev(dev)->cap_mask_mutex);
+		memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64);
+		mutex_unlock(&to_mdev(dev)->cap_mask_mutex);
+	}
+}
+
 static void forward_trap(struct mthca_dev *dev,
 			 u8 port_num,
 			 struct ib_mad *mad)
@@ -207,8 +220,10 @@
 		return IB_MAD_RESULT_FAILURE;
 	}
 
-	if (!out_mad->mad_hdr.status)
+	if (!out_mad->mad_hdr.status) {
 		smp_snoop(ibdev, port_num, in_mad);
+		node_desc_override(ibdev, out_mad);
+	}
 
 	/* set return bit in status of directed route responses */
 	if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
diff -urN oldtree/drivers/infiniband/hw/mthca/mthca_mcg.c newtree/drivers/infiniband/hw/mthca/mthca_mcg.c
--- oldtree/drivers/infiniband/hw/mthca/mthca_mcg.c	2006-02-19 11:41:02.351985544 +0000
+++ newtree/drivers/infiniband/hw/mthca/mthca_mcg.c	2006-02-21 15:58:14.889882952 +0000
@@ -187,7 +187,7 @@
 
 	for (i = 0; i < MTHCA_QP_PER_MGM; ++i)
 		if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) {
-			mthca_dbg(dev, "QP %06x already a member of MGM\n", 
+			mthca_dbg(dev, "QP %06x already a member of MGM\n",
 				  ibqp->qp_num);
 			err = 0;
 			goto out;
diff -urN oldtree/drivers/infiniband/hw/mthca/mthca_mr.c newtree/drivers/infiniband/hw/mthca/mthca_mr.c
--- oldtree/drivers/infiniband/hw/mthca/mthca_mr.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/infiniband/hw/mthca/mthca_mr.c	2006-02-21 15:58:14.897881736 +0000
@@ -340,8 +340,6 @@
 	int err;
 	u8 status;
 
-	might_sleep();
-
 	WARN_ON(buffer_size_shift >= 32);
 
 	key = mthca_alloc(&dev->mr_table.mpt_alloc);
@@ -467,8 +465,6 @@
 	int err;
 	u8 status;
 
-	might_sleep();
-
 	err = mthca_HW2SW_MPT(dev, NULL,
 			      key_to_hw_index(dev, mr->ibmr.lkey) &
 			      (dev->limits.num_mpts - 1),
@@ -495,9 +491,7 @@
 	int err = -ENOMEM;
 	int i;
 
-	might_sleep();
-
-	if (mr->attr.page_size < 12 || mr->attr.page_size >= 32)
+	if (mr->attr.page_shift < 12 || mr->attr.page_shift >= 32)
 		return -EINVAL;
 
 	/* For Arbel, all MTTs must fit in the same page. */
@@ -523,7 +517,7 @@
 		BUG_ON(!mr->mem.arbel.mpt);
 	} else
 		mr->mem.tavor.mpt = dev->mr_table.tavor_fmr.mpt_base +
-		       	sizeof *(mr->mem.tavor.mpt) * idx;
+			sizeof *(mr->mem.tavor.mpt) * idx;
 
 	mr->mtt = __mthca_alloc_mtt(dev, list_len, dev->mr_table.fmr_mtt_buddy);
 	if (IS_ERR(mr->mtt))
@@ -549,7 +543,7 @@
 				       MTHCA_MPT_FLAG_REGION      |
 				       access);
 
-	mpt_entry->page_size = cpu_to_be32(mr->attr.page_size - 12);
+	mpt_entry->page_size = cpu_to_be32(mr->attr.page_shift - 12);
 	mpt_entry->key       = cpu_to_be32(key);
 	mpt_entry->pd        = cpu_to_be32(pd);
 	memset(&mpt_entry->start, 0,
@@ -617,7 +611,7 @@
 	if (list_len > fmr->attr.max_pages)
 		return -EINVAL;
 
-	page_mask = (1 << fmr->attr.page_size) - 1;
+	page_mask = (1 << fmr->attr.page_shift) - 1;
 
 	/* We are getting page lists, so va must be page aligned. */
 	if (iova & page_mask)
@@ -665,7 +659,7 @@
 	}
 
 	mpt_entry.lkey   = cpu_to_be32(key);
-	mpt_entry.length = cpu_to_be64(list_len * (1ull << fmr->attr.page_size));
+	mpt_entry.length = cpu_to_be64(list_len * (1ull << fmr->attr.page_shift));
 	mpt_entry.start  = cpu_to_be64(iova);
 
 	__raw_writel((__force u32) mpt_entry.lkey, &fmr->mem.tavor.mpt->key);
@@ -706,7 +700,7 @@
 
 	fmr->mem.arbel.mpt->key    = cpu_to_be32(key);
 	fmr->mem.arbel.mpt->lkey   = cpu_to_be32(key);
-	fmr->mem.arbel.mpt->length = cpu_to_be64(list_len * (1ull << fmr->attr.page_size));
+	fmr->mem.arbel.mpt->length = cpu_to_be64(list_len * (1ull << fmr->attr.page_shift));
 	fmr->mem.arbel.mpt->start  = cpu_to_be64(iova);
 
 	wmb();
@@ -785,7 +779,7 @@
 		}
 
 		dev->mr_table.tavor_fmr.mpt_base =
-		       	ioremap(dev->mr_table.mpt_base,
+			ioremap(dev->mr_table.mpt_base,
 				(1 << i) * sizeof (struct mthca_mpt_entry));
 
 		if (!dev->mr_table.tavor_fmr.mpt_base) {
@@ -813,7 +807,7 @@
 			goto err_reserve_fmr;
 
 		dev->mr_table.fmr_mtt_buddy =
-		       	&dev->mr_table.tavor_fmr.mtt_buddy;
+			&dev->mr_table.tavor_fmr.mtt_buddy;
 	} else
 		dev->mr_table.fmr_mtt_buddy = &dev->mr_table.mtt_buddy;
 
diff -urN oldtree/drivers/infiniband/hw/mthca/mthca_pd.c newtree/drivers/infiniband/hw/mthca/mthca_pd.c
--- oldtree/drivers/infiniband/hw/mthca/mthca_pd.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/infiniband/hw/mthca/mthca_pd.c	2006-02-21 15:58:14.898881584 +0000
@@ -43,8 +43,6 @@
 {
 	int err = 0;
 
-	might_sleep();
-
 	pd->privileged = privileged;
 
 	atomic_set(&pd->sqp_count, 0);
@@ -66,7 +64,6 @@
 
 void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd)
 {
-	might_sleep();
 	if (pd->privileged)
 		mthca_free_mr(dev, &pd->ntmr);
 	mthca_free(&dev->pd_table.alloc, pd->pd_num);
diff -urN oldtree/drivers/infiniband/hw/mthca/mthca_provider.c newtree/drivers/infiniband/hw/mthca/mthca_provider.c
--- oldtree/drivers/infiniband/hw/mthca/mthca_provider.c	2006-02-19 11:41:02.353985240 +0000
+++ newtree/drivers/infiniband/hw/mthca/mthca_provider.c	2006-02-21 15:58:14.899881432 +0000
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
@@ -108,12 +108,12 @@
 	props->max_srq_wr          = mdev->limits.max_srq_wqes;
 	props->max_srq_sge         = mdev->limits.max_sg;
 	props->local_ca_ack_delay  = mdev->limits.local_ca_ack_delay;
-	props->atomic_cap          = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ? 
+	props->atomic_cap          = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ?
 					IB_ATOMIC_HCA : IB_ATOMIC_NONE;
 	props->max_pkeys           = mdev->limits.pkey_table_len;
 	props->max_mcast_grp       = mdev->limits.num_mgms + mdev->limits.num_amgms;
 	props->max_mcast_qp_attach = MTHCA_QP_PER_MGM;
-	props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * 
+	props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
 					   props->max_mcast_grp;
 
 	err = 0;
@@ -176,6 +176,23 @@
 	return err;
 }
 
+static int mthca_modify_device(struct ib_device *ibdev,
+			       int mask,
+			       struct ib_device_modify *props)
+{
+	if (mask & ~IB_DEVICE_MODIFY_NODE_DESC)
+		return -EOPNOTSUPP;
+
+	if (mask & IB_DEVICE_MODIFY_NODE_DESC) {
+		if (mutex_lock_interruptible(&to_mdev(ibdev)->cap_mask_mutex))
+			return -ERESTARTSYS;
+		memcpy(ibdev->node_desc, props->node_desc, 64);
+		mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex);
+	}
+
+	return 0;
+}
+
 static int mthca_modify_port(struct ib_device *ibdev,
 			     u8 port, int port_modify_mask,
 			     struct ib_port_modify *props)
@@ -669,9 +686,9 @@
 	}
 
 	if (context) {
-		cq->mr.ibmr.lkey    = ucmd.lkey;
-		cq->set_ci_db_index = ucmd.set_db_index;
-		cq->arm_db_index    = ucmd.arm_db_index;
+		cq->buf.mr.ibmr.lkey = ucmd.lkey;
+		cq->set_ci_db_index  = ucmd.set_db_index;
+		cq->arm_db_index     = ucmd.arm_db_index;
 	}
 
 	for (nent = 1; nent <= entries; nent <<= 1)
@@ -689,6 +706,8 @@
 		goto err_free;
 	}
 
+	cq->resize_buf = NULL;
+
 	return &cq->ibcq;
 
 err_free:
@@ -707,6 +726,121 @@
 	return ERR_PTR(err);
 }
 
+static int mthca_alloc_resize_buf(struct mthca_dev *dev, struct mthca_cq *cq,
+				  int entries)
+{
+	int ret;
+
+	spin_lock_irq(&cq->lock);
+	if (cq->resize_buf) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_ATOMIC);
+	if (!cq->resize_buf) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	cq->resize_buf->state = CQ_RESIZE_ALLOC;
+
+	ret = 0;
+
+unlock:
+	spin_unlock_irq(&cq->lock);
+
+	if (ret)
+		return ret;
+
+	ret = mthca_alloc_cq_buf(dev, &cq->resize_buf->buf, entries);
+	if (ret) {
+		spin_lock_irq(&cq->lock);
+		kfree(cq->resize_buf);
+		cq->resize_buf = NULL;
+		spin_unlock_irq(&cq->lock);
+		return ret;
+	}
+
+	cq->resize_buf->cqe = entries - 1;
+
+	spin_lock_irq(&cq->lock);
+	cq->resize_buf->state = CQ_RESIZE_READY;
+	spin_unlock_irq(&cq->lock);
+
+	return 0;
+}
+
+static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
+{
+	struct mthca_dev *dev = to_mdev(ibcq->device);
+	struct mthca_cq *cq = to_mcq(ibcq);
+	struct mthca_resize_cq ucmd;
+	u32 lkey;
+	u8 status;
+	int ret;
+
+	if (entries < 1 || entries > dev->limits.max_cqes)
+		return -EINVAL;
+
+	entries = roundup_pow_of_two(entries + 1);
+	if (entries == ibcq->cqe + 1)
+		return 0;
+
+	if (cq->is_kernel) {
+		ret = mthca_alloc_resize_buf(dev, cq, entries);
+		if (ret)
+			return ret;
+		lkey = cq->resize_buf->buf.mr.ibmr.lkey;
+	} else {
+		if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
+			return -EFAULT;
+		lkey = ucmd.lkey;
+	}
+
+	ret = mthca_RESIZE_CQ(dev, cq->cqn, lkey, long_log2(entries), &status);
+	if (status)
+		ret = -EINVAL;
+
+	if (ret) {
+		if (cq->resize_buf) {
+			mthca_free_cq_buf(dev, &cq->resize_buf->buf,
+					  cq->resize_buf->cqe);
+			kfree(cq->resize_buf);
+			spin_lock_irq(&cq->lock);
+			cq->resize_buf = NULL;
+			spin_unlock_irq(&cq->lock);
+		}
+		return ret;
+	}
+
+	if (cq->is_kernel) {
+		struct mthca_cq_buf tbuf;
+		int tcqe;
+
+		spin_lock_irq(&cq->lock);
+		if (cq->resize_buf->state == CQ_RESIZE_READY) {
+			mthca_cq_resize_copy_cqes(cq);
+			tbuf         = cq->buf;
+			tcqe         = cq->ibcq.cqe;
+			cq->buf      = cq->resize_buf->buf;
+			cq->ibcq.cqe = cq->resize_buf->cqe;
+		} else {
+			tbuf = cq->resize_buf->buf;
+			tcqe = cq->resize_buf->cqe;
+		}
+
+		kfree(cq->resize_buf);
+		cq->resize_buf = NULL;
+		spin_unlock_irq(&cq->lock);
+
+		mthca_free_cq_buf(dev, &tbuf, tcqe);
+	} else
+		ibcq->cqe = entries - 1;
+
+	return 0;
+}
+
 static int mthca_destroy_cq(struct ib_cq *cq)
 {
 	if (cq->uobject) {
@@ -1070,6 +1204,20 @@
 		goto out;
 
 	init_query_mad(in_mad);
+	in_mad->attr_id = IB_SMP_ATTR_NODE_DESC;
+
+	err = mthca_MAD_IFC(dev, 1, 1,
+			    1, NULL, NULL, in_mad, out_mad,
+			    &status);
+	if (err)
+		goto out;
+	if (status) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	memcpy(dev->ib_dev.node_desc, out_mad->data, 64);
+
 	in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
 
 	err = mthca_MAD_IFC(dev, 1, 1,
@@ -1113,14 +1261,17 @@
 		(1ull << IB_USER_VERBS_CMD_DEREG_MR)		|
 		(1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL)	|
 		(1ull << IB_USER_VERBS_CMD_CREATE_CQ)		|
+		(1ull << IB_USER_VERBS_CMD_RESIZE_CQ)		|
 		(1ull << IB_USER_VERBS_CMD_DESTROY_CQ)		|
 		(1ull << IB_USER_VERBS_CMD_CREATE_QP)		|
+		(1ull << IB_USER_VERBS_CMD_QUERY_QP)		|
 		(1ull << IB_USER_VERBS_CMD_MODIFY_QP)		|
 		(1ull << IB_USER_VERBS_CMD_DESTROY_QP)		|
 		(1ull << IB_USER_VERBS_CMD_ATTACH_MCAST)	|
 		(1ull << IB_USER_VERBS_CMD_DETACH_MCAST)	|
 		(1ull << IB_USER_VERBS_CMD_CREATE_SRQ)		|
 		(1ull << IB_USER_VERBS_CMD_MODIFY_SRQ)		|
+		(1ull << IB_USER_VERBS_CMD_QUERY_SRQ)		|
 		(1ull << IB_USER_VERBS_CMD_DESTROY_SRQ);
 	dev->ib_dev.node_type            = IB_NODE_CA;
 	dev->ib_dev.phys_port_cnt        = dev->limits.num_ports;
@@ -1128,6 +1279,7 @@
 	dev->ib_dev.class_dev.dev        = &dev->pdev->dev;
 	dev->ib_dev.query_device         = mthca_query_device;
 	dev->ib_dev.query_port           = mthca_query_port;
+	dev->ib_dev.modify_device        = mthca_modify_device;
 	dev->ib_dev.modify_port          = mthca_modify_port;
 	dev->ib_dev.query_pkey           = mthca_query_pkey;
 	dev->ib_dev.query_gid            = mthca_query_gid;
@@ -1141,7 +1293,8 @@
 
 	if (dev->mthca_flags & MTHCA_FLAG_SRQ) {
 		dev->ib_dev.create_srq           = mthca_create_srq;
-		dev->ib_dev.modify_srq		 = mthca_modify_srq;
+		dev->ib_dev.modify_srq           = mthca_modify_srq;
+		dev->ib_dev.query_srq            = mthca_query_srq;
 		dev->ib_dev.destroy_srq          = mthca_destroy_srq;
 
 		if (mthca_is_memfree(dev))
@@ -1152,8 +1305,10 @@
 
 	dev->ib_dev.create_qp            = mthca_create_qp;
 	dev->ib_dev.modify_qp            = mthca_modify_qp;
+	dev->ib_dev.query_qp             = mthca_query_qp;
 	dev->ib_dev.destroy_qp           = mthca_destroy_qp;
 	dev->ib_dev.create_cq            = mthca_create_cq;
+	dev->ib_dev.resize_cq            = mthca_resize_cq;
 	dev->ib_dev.destroy_cq           = mthca_destroy_cq;
 	dev->ib_dev.poll_cq              = mthca_poll_cq;
 	dev->ib_dev.get_dma_mr           = mthca_get_dma_mr;
diff -urN oldtree/drivers/infiniband/hw/mthca/mthca_provider.h newtree/drivers/infiniband/hw/mthca/mthca_provider.h
--- oldtree/drivers/infiniband/hw/mthca/mthca_provider.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/infiniband/hw/mthca/mthca_provider.h	2006-02-21 15:58:14.900881280 +0000
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -164,9 +164,11 @@
  * - wait_event until ref count is zero
  *
  * It is the consumer's responsibilty to make sure that no QP
- * operations (WQE posting or state modification) are pending when the
+ * operations (WQE posting or state modification) are pending when a
  * QP is destroyed.  Also, the consumer must make sure that calls to
- * qp_modify are serialized.
+ * qp_modify are serialized.  Similarly, the consumer is responsible
+ * for ensuring that no CQ resize operations are pending when a CQ
+ * is destroyed.
  *
  * Possible optimizations (wait for profile data to see if/where we
  * have locks bouncing between CPUs):
@@ -176,25 +178,40 @@
  *   send queue and one for the receive queue)
  */
 
+struct mthca_cq_buf {
+	union mthca_buf		queue;
+	struct mthca_mr		mr;
+	int			is_direct;
+};
+
+struct mthca_cq_resize {
+	struct mthca_cq_buf	buf;
+	int			cqe;
+	enum {
+		CQ_RESIZE_ALLOC,
+		CQ_RESIZE_READY,
+		CQ_RESIZE_SWAPPED
+	}			state;
+};
+
 struct mthca_cq {
-	struct ib_cq           ibcq;
-	spinlock_t             lock;
-	atomic_t               refcount;
-	int                    cqn;
-	u32                    cons_index;
-	int                    is_direct;
-	int                    is_kernel;
+	struct ib_cq		ibcq;
+	spinlock_t		lock;
+	atomic_t		refcount;
+	int			cqn;
+	u32			cons_index;
+	struct mthca_cq_buf	buf;
+	struct mthca_cq_resize *resize_buf;
+	int			is_kernel;
 
 	/* Next fields are Arbel only */
-	int                    set_ci_db_index;
-	__be32                *set_ci_db;
-	int                    arm_db_index;
-	__be32                *arm_db;
-	int                    arm_sn;
+	int			set_ci_db_index;
+	__be32		       *set_ci_db;
+	int			arm_db_index;
+	__be32		       *arm_db;
+	int			arm_sn;
 
-	union mthca_buf        queue;
-	struct mthca_mr        mr;
-	wait_queue_head_t      wait;
+	wait_queue_head_t	wait;
 };
 
 struct mthca_srq {
diff -urN oldtree/drivers/infiniband/hw/mthca/mthca_qp.c newtree/drivers/infiniband/hw/mthca/mthca_qp.c
--- oldtree/drivers/infiniband/hw/mthca/mthca_qp.c	2006-02-19 11:41:02.355984936 +0000
+++ newtree/drivers/infiniband/hw/mthca/mthca_qp.c	2006-02-21 15:58:14.902880976 +0000
@@ -2,7 +2,7 @@
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Cisco Systems. All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
- * Copyright (c) 2004 Voltaire, Inc. All rights reserved. 
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -286,207 +286,6 @@
 	}
 }
 
-static const struct {
-	int trans;
-	u32 req_param[NUM_TRANS];
-	u32 opt_param[NUM_TRANS];
-} state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
-	[IB_QPS_RESET] = {
-		[IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-		[IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
-		[IB_QPS_INIT]  = {
-			.trans = MTHCA_TRANS_RST2INIT,
-			.req_param = {
-				[UD]  = (IB_QP_PKEY_INDEX |
-					 IB_QP_PORT       |
-					 IB_QP_QKEY),
-				[UC]  = (IB_QP_PKEY_INDEX |
-					 IB_QP_PORT       |
-					 IB_QP_ACCESS_FLAGS),
-				[RC]  = (IB_QP_PKEY_INDEX |
-					 IB_QP_PORT       |
-					 IB_QP_ACCESS_FLAGS),
-				[MLX] = (IB_QP_PKEY_INDEX |
-					 IB_QP_QKEY),
-			},
-			/* bug-for-bug compatibility with VAPI: */
-			.opt_param = {
-				[MLX] = IB_QP_PORT
-			}
-		},
-	},
-	[IB_QPS_INIT]  = {
-		[IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-		[IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
-		[IB_QPS_INIT]  = {
-			.trans = MTHCA_TRANS_INIT2INIT,
-			.opt_param = {
-				[UD]  = (IB_QP_PKEY_INDEX |
-					 IB_QP_PORT       |
-					 IB_QP_QKEY),
-				[UC]  = (IB_QP_PKEY_INDEX |
-					 IB_QP_PORT       |
-					 IB_QP_ACCESS_FLAGS),
-				[RC]  = (IB_QP_PKEY_INDEX |
-					 IB_QP_PORT       |
-					 IB_QP_ACCESS_FLAGS),
-				[MLX] = (IB_QP_PKEY_INDEX |
-					 IB_QP_QKEY),
-			}
-		},
-		[IB_QPS_RTR]   = {
-			.trans = MTHCA_TRANS_INIT2RTR,
-			.req_param = {
-				[UC]  = (IB_QP_AV                  |
-					 IB_QP_PATH_MTU            |
-					 IB_QP_DEST_QPN            |
-					 IB_QP_RQ_PSN),
-				[RC]  = (IB_QP_AV                  |
-					 IB_QP_PATH_MTU            |
-					 IB_QP_DEST_QPN            |
-					 IB_QP_RQ_PSN              |
-					 IB_QP_MAX_DEST_RD_ATOMIC  |
-					 IB_QP_MIN_RNR_TIMER),
-			},
-			.opt_param = {
-				[UD]  = (IB_QP_PKEY_INDEX |
-					 IB_QP_QKEY),
-				[UC]  = (IB_QP_ALT_PATH     |
-					 IB_QP_ACCESS_FLAGS |
-					 IB_QP_PKEY_INDEX),
-				[RC]  = (IB_QP_ALT_PATH     |
-					 IB_QP_ACCESS_FLAGS |
-					 IB_QP_PKEY_INDEX),
-				[MLX] = (IB_QP_PKEY_INDEX |
-					 IB_QP_QKEY),
-			}
-		}
-	},
-	[IB_QPS_RTR]   = {
-		[IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-		[IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
-		[IB_QPS_RTS]   = {
-			.trans = MTHCA_TRANS_RTR2RTS,
-			.req_param = {
-				[UD]  = IB_QP_SQ_PSN,
-				[UC]  = IB_QP_SQ_PSN,
-				[RC]  = (IB_QP_TIMEOUT           |
-					 IB_QP_RETRY_CNT         |
-					 IB_QP_RNR_RETRY         |
-					 IB_QP_SQ_PSN            |
-					 IB_QP_MAX_QP_RD_ATOMIC),
-				[MLX] = IB_QP_SQ_PSN,
-			},
-			.opt_param = {
-				[UD]  = (IB_QP_CUR_STATE             |
-					 IB_QP_QKEY),
-				[UC]  = (IB_QP_CUR_STATE             |
-					 IB_QP_ALT_PATH              |
-					 IB_QP_ACCESS_FLAGS          |
-					 IB_QP_PATH_MIG_STATE),
-				[RC]  = (IB_QP_CUR_STATE             |
-					 IB_QP_ALT_PATH              |
-					 IB_QP_ACCESS_FLAGS          |
-					 IB_QP_MIN_RNR_TIMER         |
-					 IB_QP_PATH_MIG_STATE),
-				[MLX] = (IB_QP_CUR_STATE             |
-					 IB_QP_QKEY),
-			}
-		}
-	},
-	[IB_QPS_RTS]   = {
-		[IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-		[IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
-		[IB_QPS_RTS]   = {
-			.trans = MTHCA_TRANS_RTS2RTS,
-			.opt_param = {
-				[UD]  = (IB_QP_CUR_STATE             |
-					 IB_QP_QKEY),
-				[UC]  = (IB_QP_ACCESS_FLAGS          |
-					 IB_QP_ALT_PATH              |
-					 IB_QP_PATH_MIG_STATE),
-				[RC]  = (IB_QP_ACCESS_FLAGS          |
-					 IB_QP_ALT_PATH              |
-					 IB_QP_PATH_MIG_STATE        |
-					 IB_QP_MIN_RNR_TIMER),
-				[MLX] = (IB_QP_CUR_STATE             |
-					 IB_QP_QKEY),
-			}
-		},
-		[IB_QPS_SQD]   = {
-			.trans = MTHCA_TRANS_RTS2SQD,
-		},
-	},
-	[IB_QPS_SQD]   = {
-		[IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-		[IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
-		[IB_QPS_RTS]   = {
-			.trans = MTHCA_TRANS_SQD2RTS,
-			.opt_param = {
-				[UD]  = (IB_QP_CUR_STATE             |
-					 IB_QP_QKEY),
-				[UC]  = (IB_QP_CUR_STATE             |
-					 IB_QP_ALT_PATH              |
-					 IB_QP_ACCESS_FLAGS          |
-					 IB_QP_PATH_MIG_STATE),
-				[RC]  = (IB_QP_CUR_STATE             |
-					 IB_QP_ALT_PATH              |
-					 IB_QP_ACCESS_FLAGS          |
-					 IB_QP_MIN_RNR_TIMER         |
-					 IB_QP_PATH_MIG_STATE),
-				[MLX] = (IB_QP_CUR_STATE             |
-					 IB_QP_QKEY),
-			}
-		},
-		[IB_QPS_SQD]   = {
-			.trans = MTHCA_TRANS_SQD2SQD,
-			.opt_param = {
-				[UD]  = (IB_QP_PKEY_INDEX            |
-					 IB_QP_QKEY),
-				[UC]  = (IB_QP_AV                    |
-					 IB_QP_CUR_STATE             |
-					 IB_QP_ALT_PATH              |
-					 IB_QP_ACCESS_FLAGS          |
-					 IB_QP_PKEY_INDEX            |
-					 IB_QP_PATH_MIG_STATE),
-				[RC]  = (IB_QP_AV                    |
-					 IB_QP_TIMEOUT               |
-					 IB_QP_RETRY_CNT             |
-					 IB_QP_RNR_RETRY             |
-					 IB_QP_MAX_QP_RD_ATOMIC      |
-					 IB_QP_MAX_DEST_RD_ATOMIC    |
-					 IB_QP_CUR_STATE             |
-					 IB_QP_ALT_PATH              |
-					 IB_QP_ACCESS_FLAGS          |
-					 IB_QP_PKEY_INDEX            |
-					 IB_QP_MIN_RNR_TIMER         |
-					 IB_QP_PATH_MIG_STATE),
-				[MLX] = (IB_QP_PKEY_INDEX            |
-					 IB_QP_QKEY),
-			}
-		}
-	},
-	[IB_QPS_SQE]   = {
-		[IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-		[IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
-		[IB_QPS_RTS]   = {
-			.trans = MTHCA_TRANS_SQERR2RTS,
-			.opt_param = {
-				[UD]  = (IB_QP_CUR_STATE             |
-					 IB_QP_QKEY),
-				[UC]  = (IB_QP_CUR_STATE             |
-					 IB_QP_ACCESS_FLAGS),
-				[MLX] = (IB_QP_CUR_STATE             |
-					 IB_QP_QKEY),
-			}
-		}
-	},
-	[IB_QPS_ERR] = {
-		[IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-		[IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR }
-	}
-};
-
 static void store_attrs(struct mthca_sqp *sqp, struct ib_qp_attr *attr,
 			int attr_mask)
 {
@@ -549,6 +348,136 @@
 	return cpu_to_be32(hw_access_flags);
 }
 
+static inline enum ib_qp_state to_ib_qp_state(int mthca_state)
+{
+	switch (mthca_state) {
+	case MTHCA_QP_STATE_RST:      return IB_QPS_RESET;
+	case MTHCA_QP_STATE_INIT:     return IB_QPS_INIT;
+	case MTHCA_QP_STATE_RTR:      return IB_QPS_RTR;
+	case MTHCA_QP_STATE_RTS:      return IB_QPS_RTS;
+	case MTHCA_QP_STATE_DRAINING:
+	case MTHCA_QP_STATE_SQD:      return IB_QPS_SQD;
+	case MTHCA_QP_STATE_SQE:      return IB_QPS_SQE;
+	case MTHCA_QP_STATE_ERR:      return IB_QPS_ERR;
+	default:                      return -1;
+	}
+}
+
+static inline enum ib_mig_state to_ib_mig_state(int mthca_mig_state)
+{
+	switch (mthca_mig_state) {
+	case 0:  return IB_MIG_ARMED;
+	case 1:  return IB_MIG_REARM;
+	case 3:  return IB_MIG_MIGRATED;
+	default: return -1;
+	}
+}
+
+static int to_ib_qp_access_flags(int mthca_flags)
+{
+	int ib_flags = 0;
+
+	if (mthca_flags & MTHCA_QP_BIT_RRE)
+		ib_flags |= IB_ACCESS_REMOTE_READ;
+	if (mthca_flags & MTHCA_QP_BIT_RWE)
+		ib_flags |= IB_ACCESS_REMOTE_WRITE;
+	if (mthca_flags & MTHCA_QP_BIT_RAE)
+		ib_flags |= IB_ACCESS_REMOTE_ATOMIC;
+
+	return ib_flags;
+}
+
+static void to_ib_ah_attr(struct mthca_dev *dev, struct ib_ah_attr *ib_ah_attr,
+				struct mthca_qp_path *path)
+{
+	memset(ib_ah_attr, 0, sizeof *path);
+	ib_ah_attr->port_num 	  = (be32_to_cpu(path->port_pkey) >> 24) & 0x3;
+	ib_ah_attr->dlid     	  = be16_to_cpu(path->rlid);
+	ib_ah_attr->sl       	  = be32_to_cpu(path->sl_tclass_flowlabel) >> 28;
+	ib_ah_attr->src_path_bits = path->g_mylmc & 0x7f;
+	ib_ah_attr->static_rate   = path->static_rate & 0x7;
+	ib_ah_attr->ah_flags      = (path->g_mylmc & (1 << 7)) ? IB_AH_GRH : 0;
+	if (ib_ah_attr->ah_flags) {
+		ib_ah_attr->grh.sgid_index = path->mgid_index & (dev->limits.gid_table_len - 1);
+		ib_ah_attr->grh.hop_limit  = path->hop_limit;
+		ib_ah_attr->grh.traffic_class =
+			(be32_to_cpu(path->sl_tclass_flowlabel) >> 20) & 0xff;
+		ib_ah_attr->grh.flow_label =
+			be32_to_cpu(path->sl_tclass_flowlabel) & 0xfffff;
+		memcpy(ib_ah_attr->grh.dgid.raw,
+			path->rgid, sizeof ib_ah_attr->grh.dgid.raw);
+	}
+}
+
+int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask,
+		   struct ib_qp_init_attr *qp_init_attr)
+{
+	struct mthca_dev *dev = to_mdev(ibqp->device);
+	struct mthca_qp *qp = to_mqp(ibqp);
+	int err;
+	struct mthca_mailbox *mailbox;
+	struct mthca_qp_param *qp_param;
+	struct mthca_qp_context *context;
+	int mthca_state;
+	u8 status;
+
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+
+	err = mthca_QUERY_QP(dev, qp->qpn, 0, mailbox, &status);
+	if (err)
+		goto out;
+
+	qp_param    = mailbox->buf;
+	context     = &qp_param->context;
+	mthca_state = be32_to_cpu(context->flags) >> 28;
+
+	qp_attr->qp_state 	     = to_ib_qp_state(mthca_state);
+	qp_attr->cur_qp_state 	     = qp_attr->qp_state;
+	qp_attr->path_mtu 	     = context->mtu_msgmax >> 5;
+	qp_attr->path_mig_state      =
+		to_ib_mig_state((be32_to_cpu(context->flags) >> 11) & 0x3);
+	qp_attr->qkey 		     = be32_to_cpu(context->qkey);
+	qp_attr->rq_psn 	     = be32_to_cpu(context->rnr_nextrecvpsn) & 0xffffff;
+	qp_attr->sq_psn 	     = be32_to_cpu(context->next_send_psn) & 0xffffff;
+	qp_attr->dest_qp_num 	     = be32_to_cpu(context->remote_qpn) & 0xffffff;
+	qp_attr->qp_access_flags     =
+		to_ib_qp_access_flags(be32_to_cpu(context->params2));
+	qp_attr->cap.max_send_wr     = qp->sq.max;
+	qp_attr->cap.max_recv_wr     = qp->rq.max;
+	qp_attr->cap.max_send_sge    = qp->sq.max_gs;
+	qp_attr->cap.max_recv_sge    = qp->rq.max_gs;
+	qp_attr->cap.max_inline_data = qp->max_inline_data;
+
+	to_ib_ah_attr(dev, &qp_attr->ah_attr, &context->pri_path);
+	to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context->alt_path);
+
+	qp_attr->pkey_index     = be32_to_cpu(context->pri_path.port_pkey) & 0x7f;
+	qp_attr->alt_pkey_index = be32_to_cpu(context->alt_path.port_pkey) & 0x7f;
+
+	/* qp_attr->en_sqd_async_notify is only applicable in modify qp */
+	qp_attr->sq_draining = mthca_state == MTHCA_QP_STATE_DRAINING;
+
+	qp_attr->max_rd_atomic = 1 << ((be32_to_cpu(context->params1) >> 21) & 0x7);
+
+	qp_attr->max_dest_rd_atomic =
+		1 << ((be32_to_cpu(context->params2) >> 21) & 0x7);
+	qp_attr->min_rnr_timer 	    =
+		(be32_to_cpu(context->rnr_nextrecvpsn) >> 24) & 0x1f;
+	qp_attr->port_num 	    = qp_attr->ah_attr.port_num;
+	qp_attr->timeout 	    = context->pri_path.ackto >> 3;
+	qp_attr->retry_cnt 	    = (be32_to_cpu(context->params1) >> 16) & 0x7;
+	qp_attr->rnr_retry 	    = context->pri_path.rnr_retry >> 5;
+	qp_attr->alt_port_num 	    = qp_attr->alt_ah_attr.port_num;
+	qp_attr->alt_timeout 	    = context->alt_path.ackto >> 3;
+	qp_init_attr->cap 	    = qp_attr->cap;
+
+out:
+	mthca_free_mailbox(dev, mailbox);
+	return err;
+}
+
 static void mthca_path_set(struct ib_ah_attr *ah, struct mthca_qp_path *path)
 {
 	path->g_mylmc     = ah->src_path_bits & 0x7f;
@@ -559,9 +488,9 @@
 		path->g_mylmc   |= 1 << 7;
 		path->mgid_index = ah->grh.sgid_index;
 		path->hop_limit  = ah->grh.hop_limit;
-		path->sl_tclass_flowlabel = 
+		path->sl_tclass_flowlabel =
 			cpu_to_be32((ah->sl << 28)                |
-				    (ah->grh.traffic_class << 20) | 
+				    (ah->grh.traffic_class << 20) |
 				    (ah->grh.flow_label));
 		memcpy(path->rgid, ah->grh.dgid.raw, 16);
 	} else
@@ -576,18 +505,12 @@
 	struct mthca_mailbox *mailbox;
 	struct mthca_qp_param *qp_param;
 	struct mthca_qp_context *qp_context;
-	u32 req_param, opt_param;
+	u32 sqd_event = 0;
 	u8 status;
 	int err;
 
 	if (attr_mask & IB_QP_CUR_STATE) {
-		if (attr->cur_qp_state != IB_QPS_RTR &&
-		    attr->cur_qp_state != IB_QPS_RTS &&
-		    attr->cur_qp_state != IB_QPS_SQD &&
-		    attr->cur_qp_state != IB_QPS_SQE)
-			return -EINVAL;
-		else
-			cur_state = attr->cur_qp_state;
+		cur_state = attr->cur_qp_state;
 	} else {
 		spin_lock_irq(&qp->sq.lock);
 		spin_lock(&qp->rq.lock);
@@ -596,44 +519,20 @@
 		spin_unlock_irq(&qp->sq.lock);
 	}
 
-	if (attr_mask & IB_QP_STATE) {
-               if (attr->qp_state < 0 || attr->qp_state > IB_QPS_ERR)
-			return -EINVAL;
-		new_state = attr->qp_state;
-	} else
-		new_state = cur_state;
+	new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state;
 
-	if (state_table[cur_state][new_state].trans == MTHCA_TRANS_INVALID) {
-		mthca_dbg(dev, "Illegal QP transition "
-			  "%d->%d\n", cur_state, new_state);
+	if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask)) {
+		mthca_dbg(dev, "Bad QP transition (transport %d) "
+			  "%d->%d with attr 0x%08x\n",
+			  qp->transport, cur_state, new_state,
+			  attr_mask);
 		return -EINVAL;
 	}
 
-	req_param = state_table[cur_state][new_state].req_param[qp->transport];
-	opt_param = state_table[cur_state][new_state].opt_param[qp->transport];
-
-	if ((req_param & attr_mask) != req_param) {
-		mthca_dbg(dev, "QP transition "
-			  "%d->%d missing req attr 0x%08x\n",
-			  cur_state, new_state,
-			  req_param & ~attr_mask);
-		return -EINVAL;
-	}
-
-	if (attr_mask & ~(req_param | opt_param | IB_QP_STATE)) {
-		mthca_dbg(dev, "QP transition (transport %d) "
-			  "%d->%d has extra attr 0x%08x\n",
-			  qp->transport,
-			  cur_state, new_state,
-			  attr_mask & ~(req_param | opt_param |
-						 IB_QP_STATE));
-		return -EINVAL;
-	}
-
-	if ((attr_mask & IB_QP_PKEY_INDEX) && 
+	if ((attr_mask & IB_QP_PKEY_INDEX) &&
 	     attr->pkey_index >= dev->limits.pkey_table_len) {
 		mthca_dbg(dev, "PKey index (%u) too large. max is %d\n",
-			  attr->pkey_index,dev->limits.pkey_table_len-1); 
+			  attr->pkey_index,dev->limits.pkey_table_len-1);
 		return -EINVAL;
 	}
 
@@ -733,7 +632,7 @@
 	if (attr_mask & IB_QP_RNR_RETRY) {
 		qp_context->alt_path.rnr_retry = qp_context->pri_path.rnr_retry =
 			attr->rnr_retry << 5;
-		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RNR_RETRY | 
+		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RNR_RETRY |
 							MTHCA_QP_OPTPAR_ALT_RNR_RETRY);
 	}
 
@@ -749,13 +648,13 @@
 
 	if (attr_mask & IB_QP_ALT_PATH) {
 		if (attr->alt_port_num == 0 || attr->alt_port_num > dev->limits.num_ports) {
-			mthca_dbg(dev, "Alternate port number (%u) is invalid\n", 
+			mthca_dbg(dev, "Alternate port number (%u) is invalid\n",
 				attr->alt_port_num);
 			return -EINVAL;
 		}
 
 		mthca_path_set(&attr->alt_ah_attr, &qp_context->alt_path);
-		qp_context->alt_path.port_pkey |= cpu_to_be32(attr->alt_pkey_index | 
+		qp_context->alt_path.port_pkey |= cpu_to_be32(attr->alt_pkey_index |
 							      attr->alt_port_num << 24);
 		qp_context->alt_path.ackto = attr->alt_timeout << 3;
 		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_ALT_ADDR_PATH);
@@ -841,11 +740,16 @@
 		qp_context->srqn = cpu_to_be32(1 << 24 |
 					       to_msrq(ibqp->srq)->srqn);
 
-	err = mthca_MODIFY_QP(dev, state_table[cur_state][new_state].trans,
-			      qp->qpn, 0, mailbox, 0, &status);
+	if (cur_state == IB_QPS_RTS && new_state == IB_QPS_SQD	&&
+	    attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY		&&
+	    attr->en_sqd_async_notify)
+		sqd_event = 1 << 31;
+
+	err = mthca_MODIFY_QP(dev, cur_state, new_state, qp->qpn, 0,
+			      mailbox, sqd_event, &status);
 	if (status) {
-		mthca_warn(dev, "modify QP %d returned status %02x.\n",
-			   state_table[cur_state][new_state].trans, status);
+		mthca_warn(dev, "modify QP %d->%d returned status %02x.\n",
+			   cur_state, new_state, status);
 		err = -EINVAL;
 	}
 
@@ -1078,10 +982,10 @@
 		if (ret)
 			goto err_qpc;
 
- 		ret = mthca_table_get(dev, dev->qp_table.rdb_table,
- 				      qp->qpn << dev->qp_table.rdb_shift);
- 		if (ret)
- 			goto err_eqpc;
+		ret = mthca_table_get(dev, dev->qp_table.rdb_table,
+				      qp->qpn << dev->qp_table.rdb_shift);
+		if (ret)
+			goto err_eqpc;
 
 	}
 
@@ -1393,7 +1297,8 @@
 	wait_event(qp->wait, !atomic_read(&qp->refcount));
 
 	if (qp->state != IB_QPS_RESET)
-		mthca_MODIFY_QP(dev, MTHCA_TRANS_ANY2RST, qp->qpn, 0, NULL, 0, &status);
+		mthca_MODIFY_QP(dev, qp->state, IB_QPS_RESET, qp->qpn, 0,
+				NULL, 0, &status);
 
 	/*
 	 * If this is a userspace QP, the buffers, MR, CQs and so on
@@ -2115,7 +2020,7 @@
 	int i;
 	void *wqe;
 
- 	spin_lock_irqsave(&qp->rq.lock, flags);
+	spin_lock_irqsave(&qp->rq.lock, flags);
 
 	/* XXX check that state is OK to post receive */
 
@@ -2182,8 +2087,8 @@
 	return err;
 }
 
-int mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
-		       int index, int *dbd, __be32 *new_wqe)
+void mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
+			int index, int *dbd, __be32 *new_wqe)
 {
 	struct mthca_next_seg *next;
 
@@ -2193,7 +2098,7 @@
 	 */
 	if (qp->ibqp.srq) {
 		*new_wqe = 0;
-		return 0;
+		return;
 	}
 
 	if (is_send)
@@ -2207,8 +2112,6 @@
 			(next->ee_nds & cpu_to_be32(0x3f));
 	else
 		*new_wqe = 0;
-
-	return 0;
 }
 
 int __devinit mthca_init_qp_table(struct mthca_dev *dev)
diff -urN oldtree/drivers/infiniband/hw/mthca/mthca_srq.c newtree/drivers/infiniband/hw/mthca/mthca_srq.c
--- oldtree/drivers/infiniband/hw/mthca/mthca_srq.c	2006-02-19 11:41:02.356984784 +0000
+++ newtree/drivers/infiniband/hw/mthca/mthca_srq.c	2006-02-21 15:58:14.903880824 +0000
@@ -339,7 +339,7 @@
 
 int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
 		     enum ib_srq_attr_mask attr_mask)
-{	
+{
 	struct mthca_dev *dev = to_mdev(ibsrq->device);
 	struct mthca_srq *srq = to_msrq(ibsrq);
 	int ret;
@@ -360,6 +360,38 @@
 	return 0;
 }
 
+int mthca_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
+{
+	struct mthca_dev *dev = to_mdev(ibsrq->device);
+	struct mthca_srq *srq = to_msrq(ibsrq);
+	struct mthca_mailbox *mailbox;
+	struct mthca_arbel_srq_context *arbel_ctx;
+	u8 status;
+	int err;
+
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+
+	err = mthca_QUERY_SRQ(dev, srq->srqn, mailbox, &status);
+	if (err)
+		goto out;
+
+	if (mthca_is_memfree(dev)) {
+		arbel_ctx = mailbox->buf;
+		srq_attr->srq_limit = arbel_ctx->limit_watermark;
+	} else
+		srq_attr->srq_limit = 0;
+
+	srq_attr->max_wr  = srq->max;
+	srq_attr->max_sge = srq->max_gs;
+
+out:
+	mthca_free_mailbox(dev, mailbox);
+
+	return err;
+}
+
 void mthca_srq_event(struct mthca_dev *dev, u32 srqn,
 		     enum ib_event_type event_type)
 {
diff -urN oldtree/drivers/infiniband/hw/mthca/mthca_user.h newtree/drivers/infiniband/hw/mthca/mthca_user.h
--- oldtree/drivers/infiniband/hw/mthca/mthca_user.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/infiniband/hw/mthca/mthca_user.h	2006-02-21 15:58:14.903880824 +0000
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -75,6 +75,11 @@
 	__u32 reserved;
 };
 
+struct mthca_resize_cq {
+	__u32 lkey;
+	__u32 reserved;
+};
+
 struct mthca_create_srq {
 	__u32 lkey;
 	__u32 db_index;
diff -urN oldtree/drivers/input/keyboard/atkbd.c newtree/drivers/input/keyboard/atkbd.c
--- oldtree/drivers/input/keyboard/atkbd.c	2006-02-19 11:41:02.374982048 +0000
+++ newtree/drivers/input/keyboard/atkbd.c	2006-02-21 15:58:33.087116552 +0000
@@ -339,7 +339,10 @@
 			atkbd_report_key(atkbd->dev, regs, KEY_HANJA, 3);
 			goto out;
 		case ATKBD_RET_ERR:
-			printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys);
+			/*
+			 * printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports "
+			 *	"too many keys pressed.\n", serio->phys);
+			 */
 			goto out;
 	}
 
diff -urN oldtree/drivers/input/mouse/Makefile newtree/drivers/input/mouse/Makefile
--- oldtree/drivers/input/mouse/Makefile	2006-02-19 11:41:02.417975512 +0000
+++ newtree/drivers/input/mouse/Makefile	2006-02-21 15:58:21.916814696 +0000
@@ -14,4 +14,5 @@
 obj-$(CONFIG_MOUSE_HIL)		+= hil_ptr.o
 obj-$(CONFIG_MOUSE_VSXXXAA)	+= vsxxxaa.o
 
-psmouse-objs  := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o trackpoint.o
+psmouse-objs  := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o \
+		trackpoint.o touchkit_ps2.o
diff -urN oldtree/drivers/input/mouse/psmouse-base.c newtree/drivers/input/mouse/psmouse-base.c
--- oldtree/drivers/input/mouse/psmouse-base.c	2006-02-19 11:41:02.421974904 +0000
+++ newtree/drivers/input/mouse/psmouse-base.c	2006-02-21 15:58:21.920814088 +0000
@@ -26,6 +26,7 @@
 #include "alps.h"
 #include "lifebook.h"
 #include "trackpoint.h"
+#include "touchkit_ps2.h"
 
 #define DRIVER_DESC	"PS/2 mouse driver"
 
@@ -609,6 +610,13 @@
 	if (max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse, set_properties) == 0)
 		return PSMOUSE_IMPS;
 
+	if (touchkit_ps2_detect(psmouse, set_properties) == 0) {
+		if (max_proto >= PSMOUSE_TOUCHKIT_PS2) {
+			if (!set_properties || touchkit_ps2_init(psmouse) == 0)
+				return PSMOUSE_TOUCHKIT_PS2;
+		}
+	}
+
 /*
  * Okay, all failed, we have a standard mouse here. The number of the buttons
  * is still a question, though. We assume 3.
@@ -695,6 +703,13 @@
 		.detect		= trackpoint_detect,
 	},
 	{
+		.type		= PSMOUSE_TOUCHKIT_PS2,
+		.name		= "touchkitPS/2",
+		.alias		= "touchkit",
+		.detect		= touchkit_ps2_detect,
+		.init		= touchkit_ps2_init,
+	},
+	{
 		.type		= PSMOUSE_AUTO,
 		.name		= "auto",
 		.alias		= "any",
diff -urN oldtree/drivers/input/mouse/psmouse.h newtree/drivers/input/mouse/psmouse.h
--- oldtree/drivers/input/mouse/psmouse.h	2006-02-19 11:41:02.421974904 +0000
+++ newtree/drivers/input/mouse/psmouse.h	2006-02-21 15:58:21.920814088 +0000
@@ -86,6 +86,7 @@
 	PSMOUSE_ALPS,
 	PSMOUSE_LIFEBOOK,
 	PSMOUSE_TRACKPOINT,
+	PSMOUSE_TOUCHKIT_PS2,
 	PSMOUSE_AUTO		/* This one should always be last */
 };
 
diff -urN oldtree/drivers/input/mouse/touchkit_ps2.c newtree/drivers/input/mouse/touchkit_ps2.c
--- oldtree/drivers/input/mouse/touchkit_ps2.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/input/mouse/touchkit_ps2.c	2006-02-21 15:58:21.921813936 +0000
@@ -0,0 +1,195 @@
+/* ----------------------------------------------------------------------------
+ * touchkit_ps2.c  --  Driver for eGalax TouchKit PS/2 Touchscreens
+ *
+ * Copyright (C) 2005 by Stefan Lucke
+ * Copyright (C) 2004 by Daniel Ritz
+ * Copyright (C) by Todd E. Johnson (mtouchusb.c)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Based upon touchkitusb.c
+ *
+ * Vendor documentation is available in support section of:
+ * http://www.egalax.com.tw/
+ *
+ */
+
+/*
+ * Changelog:
+ *
+ * 2005-10-14:	whitespace & indentaion cleanup
+ *		touchkit commands defined
+ * initial version 0.1
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/libps2.h>
+#include <linux/dmi.h>
+
+#include "psmouse.h"
+#include "touchkit_ps2.h"
+
+#define TOUCHKIT_MIN_XC			0x0
+#define TOUCHKIT_MAX_XC			0x07ff
+#define TOUCHKIT_XC_FUZZ		0x0
+#define TOUCHKIT_XC_FLAT		0x0
+#define TOUCHKIT_MIN_YC			0x0
+#define TOUCHKIT_MAX_YC			0x07ff
+#define TOUCHKIT_YC_FUZZ		0x0
+#define TOUCHKIT_YC_FLAT		0x0
+#define TOUCHKIT_REPORT_DATA_SIZE	8
+
+#define TOUCHKIT_CMD			0x0A
+#define TOUCHKIT_CMD_LENGTH		1
+
+#define TOUCHKIT_CMD_ACTIVE		'A'
+#define TOUCHKIT_CMD_FIRMWARE_VERSION	'D'
+#define TOUCHKIT_CMD_CONTROLLER_TYPE	'E'
+
+#define TOUCHKIT_SEND_PARMS(s,r,c)	((s) << 12 | (r) << 8 | (c))
+
+#define TOUCHKIT_DOWN			0x01
+#define TOUCHKIT_POINT_TOUCH		0x81
+#define TOUCHKIT_POINT_NOTOUCH		0x80
+
+#define TOUCHKIT_GET_TOUCHED(dat)	((((dat)[0]) & TOUCHKIT_DOWN) ? 1 : 0)
+#define TOUCHKIT_GET_X(dat)		(((dat)[1] << 7) | (dat)[2])
+#define TOUCHKIT_GET_Y(dat)		(((dat)[3] << 7) | (dat)[4])
+
+#define DRIVER_VERSION			"v0.2"
+#define DRIVER_AUTHOR			"Stefan Lucke <stefan@lucke.in-berlin.de>"
+#define DRIVER_DESC			"eGalax TouchKit PS/2 Touchscreen Driver"
+
+static int xyswap = 0;
+module_param(xyswap, bool, 0644);
+MODULE_PARM_DESC(xyswap, "If set X and Y axes are swapped.");
+
+static int  xinvert = 0;
+module_param(xinvert, bool, 0644);
+MODULE_PARM_DESC(xinvert, "Invert direction of x axis.");
+
+static int  yinvert = 0;
+module_param(yinvert, bool, 0644);
+MODULE_PARM_DESC(yinvert, "Invert direction of y axis.");
+
+static int  xfuzz = 0;
+module_param(xfuzz, uint, 0644);
+MODULE_PARM_DESC(xinvert, "Fuzz value for x axis.");
+
+static int  yfuzz = 0;
+module_param(yfuzz, uint, 0644);
+MODULE_PARM_DESC(yfuzz, "Fuzz value for y axis.");
+
+static int  smartpad = 0;
+module_param(smartpad, bool, 0644);
+MODULE_PARM_DESC(smartpad, "Act as a smartpad device.");
+
+static int  mouse = 0;
+module_param(mouse, bool, 0644);
+MODULE_PARM_DESC(mouse, "Report mouse button");
+
+static psmouse_ret_t touchkit_ps2_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+{
+	unsigned char 		*packet = psmouse->packet;
+	struct input_dev 	*dev = psmouse->dev;
+	int 			x,y;
+
+	if (psmouse->pktcnt != 5)
+		return PSMOUSE_GOOD_DATA;
+
+	input_regs(dev, regs);
+
+	if (xyswap) {
+		y = TOUCHKIT_GET_X(packet);
+		x = TOUCHKIT_GET_Y(packet);
+	} else {
+		x = TOUCHKIT_GET_X(packet);
+		y = TOUCHKIT_GET_Y(packet);
+	}
+
+	y = (yinvert) ? TOUCHKIT_MAX_YC - y : y;
+	x = (xinvert) ? TOUCHKIT_MAX_XC - x : x;
+
+	input_report_key(dev,
+			 (mouse) ? BTN_MOUSE : BTN_TOUCH,
+			 TOUCHKIT_GET_TOUCHED(packet));
+
+	if (smartpad)
+		input_report_key(dev, BTN_TOOL_FINGER, 1);
+
+	input_report_abs(dev, ABS_X, x);
+	input_report_abs(dev, ABS_Y, y);
+
+	input_sync(dev);
+
+	return PSMOUSE_FULL_PACKET;
+}
+
+int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties)
+{
+	unsigned char	param[3];
+	int		command;
+
+	param[0] = TOUCHKIT_CMD_LENGTH;
+	param[1] = TOUCHKIT_CMD_ACTIVE;
+	command = TOUCHKIT_SEND_PARMS(2, 3, TOUCHKIT_CMD);
+
+	if (ps2_command(&psmouse->ps2dev, param, command) == 0 &&
+	    param[0] == TOUCHKIT_CMD &&
+	    param[1] == 0x01 &&
+	    param[2] == TOUCHKIT_CMD_ACTIVE){
+		printk(KERN_INFO "touchkit_ps2: device detected\n");
+		if (set_properties) {
+			psmouse->vendor = "eGalax";
+			psmouse->name = "Touchscreen";
+		}
+		return 0;
+	}
+	return -1;
+}
+
+int touchkit_ps2_init(struct psmouse *psmouse)
+{
+	psmouse->dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+	set_bit((mouse) ? BTN_MOUSE : BTN_TOUCH,psmouse->dev->keybit);
+	if (smartpad)
+		set_bit(BTN_TOOL_FINGER,psmouse->dev->keybit);
+
+	psmouse->dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+
+	/* Used to Scale Compensated Data */
+	psmouse->dev->absmin[ABS_X] = TOUCHKIT_MIN_XC;
+	psmouse->dev->absmax[ABS_X] = TOUCHKIT_MAX_XC;
+	psmouse->dev->absfuzz[ABS_X] = xfuzz;
+	psmouse->dev->absflat[ABS_X] = TOUCHKIT_XC_FLAT;
+	psmouse->dev->absmin[ABS_Y] = TOUCHKIT_MIN_YC;
+	psmouse->dev->absmax[ABS_Y] = TOUCHKIT_MAX_YC;
+	psmouse->dev->absfuzz[ABS_Y] = yfuzz;
+	psmouse->dev->absflat[ABS_Y] = TOUCHKIT_YC_FLAT;
+
+	input_set_abs_params(psmouse->dev, ABS_X, 0, 0x07ff, xfuzz, 0);
+	input_set_abs_params(psmouse->dev, ABS_Y, 0, 0x07ff, yfuzz, 0);
+
+	psmouse->protocol_handler = touchkit_ps2_process_byte;
+	psmouse->pktsize = 5;
+
+	return 0;
+}
diff -urN oldtree/drivers/input/mouse/touchkit_ps2.h newtree/drivers/input/mouse/touchkit_ps2.h
--- oldtree/drivers/input/mouse/touchkit_ps2.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/input/mouse/touchkit_ps2.h	2006-02-21 15:58:21.921813936 +0000
@@ -0,0 +1,18 @@
+/* ----------------------------------------------------------------------------
+ * touchkit_ps2.h  --  Driver for eGalax TouchKit PS/2 Touchscreens
+ *
+ * Copyright (C) 2005 by Stefan Lucke
+ * Copyright (c) 2005 Vojtech Pavlik
+ *
+ * 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 _TOUCHKIT_PS2_H
+#define _TOUCHKIT_PS2_H
+
+int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties);
+int touchkit_ps2_init(struct psmouse *psmouse);
+
+#endif
diff -urN oldtree/drivers/isdn/Makefile newtree/drivers/isdn/Makefile
--- oldtree/drivers/isdn/Makefile	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/isdn/Makefile	2006-02-21 15:58:32.799160328 +0000
@@ -13,3 +13,4 @@
 obj-$(CONFIG_ISDN_DRV_LOOP)		+= isdnloop/
 obj-$(CONFIG_ISDN_DRV_ACT2000)		+= act2000/
 obj-$(CONFIG_HYSDN)			+= hysdn/
+obj-$(CONFIG_ISDN_DRV_GIGASET)		+= gigaset/
diff -urN oldtree/drivers/isdn/capi/kcapi.c newtree/drivers/isdn/capi/kcapi.c
--- oldtree/drivers/isdn/capi/kcapi.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/isdn/capi/kcapi.c	2006-02-21 15:58:23.763533952 +0000
@@ -32,6 +32,7 @@
 #ifdef CONFIG_AVMB1_COMPAT
 #include <linux/b1lli.h>
 #endif
+#include <linux/mutex.h>
 
 static char *revision = "$Revision: 1.1.2.8 $";
 
@@ -66,7 +67,7 @@
 DEFINE_RWLOCK(capi_drivers_list_lock);
 
 static DEFINE_RWLOCK(application_lock);
-static DECLARE_MUTEX(controller_sem);
+static DEFINE_MUTEX(controller_mutex);
 
 struct capi20_appl *capi_applications[CAPI_MAXAPPL];
 struct capi_ctr *capi_cards[CAPI_MAXCONTR];
@@ -395,20 +396,20 @@
 {
 	int i;
 
-	down(&controller_sem);
+	mutex_lock(&controller_mutex);
 
 	for (i = 0; i < CAPI_MAXCONTR; i++) {
 		if (capi_cards[i] == NULL)
 			break;
 	}
 	if (i == CAPI_MAXCONTR) {
-		up(&controller_sem);
+		mutex_unlock(&controller_mutex);
 		printk(KERN_ERR "kcapi: out of controller slots\n");
 	   	return -EBUSY;
 	}
 	capi_cards[i] = card;
 
-	up(&controller_sem);
+	mutex_unlock(&controller_mutex);
 
 	card->nrecvctlpkt = 0;
 	card->nrecvdatapkt = 0;
@@ -531,13 +532,13 @@
 
 	write_unlock_irqrestore(&application_lock, flags);
 	
-	down(&controller_sem);
+	mutex_lock(&controller_mutex);
 	for (i = 0; i < CAPI_MAXCONTR; i++) {
 		if (!capi_cards[i] || capi_cards[i]->cardstate != CARD_RUNNING)
 			continue;
 		register_appl(capi_cards[i], applid, &ap->rparam);
 	}
-	up(&controller_sem);
+	mutex_unlock(&controller_mutex);
 
 	if (showcapimsgs & 1) {
 		printk(KERN_DEBUG "kcapi: appl %d up\n", applid);
@@ -560,13 +561,13 @@
 	capi_applications[ap->applid - 1] = NULL;
 	write_unlock_irqrestore(&application_lock, flags);
 
-	down(&controller_sem);
+	mutex_lock(&controller_mutex);
 	for (i = 0; i < CAPI_MAXCONTR; i++) {
 		if (!capi_cards[i] || capi_cards[i]->cardstate != CARD_RUNNING)
 			continue;
 		release_appl(capi_cards[i], ap->applid);
 	}
-	up(&controller_sem);
+	mutex_unlock(&controller_mutex);
 
 	flush_scheduled_work();
 	skb_queue_purge(&ap->recv_queue);
diff -urN oldtree/drivers/isdn/gigaset/Kconfig newtree/drivers/isdn/gigaset/Kconfig
--- oldtree/drivers/isdn/gigaset/Kconfig	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/isdn/gigaset/Kconfig	2006-02-21 15:58:32.797160632 +0000
@@ -0,0 +1,42 @@
+menu "Siemens Gigaset"
+	depends on ISDN_I4L
+
+config ISDN_DRV_GIGASET
+	tristate "Siemens Gigaset support (isdn)"
+	depends on ISDN_I4L && m
+#	depends on ISDN_I4L && MODULES
+	help
+	  Say m here if you have a Gigaset or Sinus isdn device.
+
+if ISDN_DRV_GIGASET!=n
+
+config GIGASET_BASE
+	tristate "Gigaset base station support"
+	depends on ISDN_DRV_GIGASET && USB
+	help
+	  Say m here if you need to communicate with the base
+	  directly via USB.
+
+config GIGASET_M105
+	tristate "Gigaset M105 support"
+	depends on ISDN_DRV_GIGASET && USB
+	help
+	  Say m here if you need the driver for the Gigaset M105 device.
+
+config GIGASET_DEBUG
+	bool "Gigaset debugging"
+	help
+	  This enables debugging code in the Gigaset drivers.
+	  If in doubt, say yes.
+
+config GIGASET_UNDOCREQ
+	bool "Support for undocumented USB requests"
+	help
+	  This enables support for USB requests we only know from
+	  reverse engineering (currently M105 only). If you need
+	  features like configuration mode of M105, say yes. If you
+	  care about your device, say no.
+
+endif
+
+endmenu
diff -urN oldtree/drivers/isdn/gigaset/Makefile newtree/drivers/isdn/gigaset/Makefile
--- oldtree/drivers/isdn/gigaset/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/isdn/gigaset/Makefile	2006-02-21 15:58:32.798160480 +0000
@@ -0,0 +1,6 @@
+gigaset-y := common.o interface.o proc.o ev-layer.o i4l.o
+usb_gigaset-y := usb-gigaset.o asyncdata.o
+bas_gigaset-y := bas-gigaset.o isocdata.o
+
+obj-$(CONFIG_GIGASET_M105) += usb_gigaset.o gigaset.o
+obj-$(CONFIG_GIGASET_BASE) += bas_gigaset.o gigaset.o
diff -urN oldtree/drivers/isdn/gigaset/asyncdata.c newtree/drivers/isdn/gigaset/asyncdata.c
--- oldtree/drivers/isdn/gigaset/asyncdata.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/isdn/gigaset/asyncdata.c	2006-02-21 15:58:32.986131904 +0000
@@ -0,0 +1,597 @@
+/*
+ * Common data handling layer for ser_gigaset and usb_gigaset
+ *
+ * Copyright (c) 2005 by Tilman Schmidt <tilman@imap.cc>,
+ *                       Hansjoerg Lipp <hjlipp@web.de>,
+ *                       Stefan Eilers <Eilers.Stefan@epost.de>.
+ *
+ * =====================================================================
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation; either version 2 of
+ *	the License, or (at your option) any later version.
+ * =====================================================================
+ * ToDo: ...
+ * =====================================================================
+ * Version: $Id: asyncdata.c,v 1.2.2.7 2005/11/13 23:05:18 hjlipp Exp $
+ * =====================================================================
+ */
+
+#include "gigaset.h"
+#include <linux/crc-ccitt.h>
+
+//#define GIG_M10x_STUFF_VOICE_DATA
+
+/* check if byte must be stuffed/escaped
+ * I'm not sure which data should be encoded.
+ * Therefore I will go the hard way and decode every value
+ * less than 0x20, the flag sequence and the control escape char.
+ */
+static inline int muststuff(unsigned char c)
+{
+	if (c < PPP_TRANS) return 1;
+	if (c == PPP_FLAG) return 1;
+	if (c == PPP_ESCAPE) return 1;
+	/* other possible candidates: */
+	/* 0x91: XON with parity set */
+	/* 0x93: XOFF with parity set */
+	return 0;
+}
+
+/* == data input =========================================================== */
+
+/* process a block of received bytes in command mode (modem response)
+ * Return value:
+ *	number of processed bytes
+ */
+static inline int cmd_loop(unsigned char c, unsigned char *src, int numbytes,
+                           struct inbuf_t *inbuf)
+{
+	struct cardstate *cs = inbuf->cs;
+	unsigned cbytes      = cs->cbytes;
+	int inputstate = inbuf->inputstate;
+	int startbytes = numbytes;
+
+	for (;;) {
+		cs->respdata[cbytes] = c;
+		if (c == 10 || c == 13) {
+			dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)",
+			    __func__, cbytes);
+			cs->cbytes = cbytes;
+			gigaset_handle_modem_response(cs); /* can change cs->dle */
+			cbytes = 0;
+
+			if (cs->dle &&
+			    !(inputstate & INS_DLE_command)) {
+				inputstate &= ~INS_command;
+				break;
+			}
+		} else {
+			/* advance in line buffer, checking for overflow */
+			if (cbytes < MAX_RESP_SIZE - 1)
+				cbytes++;
+			else
+				warn("response too large");
+		}
+
+		if (!numbytes)
+			break;
+		c = *src++;
+		--numbytes;
+		if (c == DLE_FLAG &&
+		    (cs->dle || inputstate & INS_DLE_command)) {
+			inputstate |= INS_DLE_char;
+			break;
+		}
+	}
+
+	cs->cbytes = cbytes;
+	inbuf->inputstate = inputstate;
+
+	return startbytes - numbytes;
+}
+
+/* process a block of received bytes in lock mode (tty i/f)
+ * Return value:
+ *	number of processed bytes
+ */
+static inline int lock_loop(unsigned char *src, int numbytes,
+                            struct inbuf_t *inbuf)
+{
+	struct cardstate *cs = inbuf->cs;
+
+	gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response", numbytes, src, 0);
+	gigaset_if_receive(cs, src, numbytes);
+
+	return numbytes;
+}
+
+/* process a block of received bytes in HDLC data mode
+ * Collect HDLC frames, undoing byte stuffing and watching for DLE escapes.
+ * When a frame is complete, check the FCS and pass valid frames to the LL.
+ * If DLE is encountered, return immediately to let the caller handle it.
+ * Return value:
+ *	number of processed bytes
+ *	numbytes (all bytes processed) on error --FIXME
+ */
+static inline int hdlc_loop(unsigned char c, unsigned char *src, int numbytes,
+                            struct inbuf_t *inbuf)
+{
+	struct cardstate *cs = inbuf->cs;
+	struct bc_state *bcs = inbuf->bcs;
+	int inputstate;
+	__u16 fcs;
+	struct sk_buff *skb;
+	unsigned char error;
+	struct sk_buff *compskb;
+	int startbytes = numbytes;
+	int l;
+
+	IFNULLRETVAL(bcs, numbytes);
+	inputstate = bcs->inputstate;
+	fcs = bcs->fcs;
+	skb = bcs->skb;
+	IFNULLRETVAL(skb, numbytes);
+
+	if (unlikely(inputstate & INS_byte_stuff)) {
+		inputstate &= ~INS_byte_stuff;
+		goto byte_stuff;
+	}
+	for (;;) {
+		if (unlikely(c == PPP_ESCAPE)) {
+			if (unlikely(!numbytes)) {
+				inputstate |= INS_byte_stuff;
+				break;
+			}
+			c = *src++;
+			--numbytes;
+			if (unlikely(c == DLE_FLAG &&
+				     (cs->dle ||
+				      inbuf->inputstate & INS_DLE_command))) {
+				inbuf->inputstate |= INS_DLE_char;
+				inputstate |= INS_byte_stuff;
+				break;
+			}
+byte_stuff:
+			c ^= PPP_TRANS;
+#ifdef CONFIG_GIGASET_DEBUG
+			if (unlikely(!muststuff(c)))
+				dbg(DEBUG_HDLC,
+				    "byte stuffed: 0x%02x", c);
+#endif
+		} else if (unlikely(c == PPP_FLAG)) {
+			if (unlikely(inputstate & INS_skip_frame)) {
+				if (!(inputstate & INS_have_data)) { /* 7E 7E */
+					//dbg(DEBUG_HDLC, "(7e)7e------------------------");
+#ifdef CONFIG_GIGASET_DEBUG
+					++bcs->emptycount;
+#endif
+				} else
+					dbg(DEBUG_HDLC,
+					    "7e----------------------------");
+
+				/* end of frame */
+				error = 1;
+				gigaset_rcv_error(NULL, cs, bcs);
+			} else if (!(inputstate & INS_have_data)) { /* 7E 7E */
+				//dbg(DEBUG_HDLC, "(7e)7e------------------------");
+#ifdef CONFIG_GIGASET_DEBUG
+				++bcs->emptycount;
+#endif
+				break;
+			} else {
+				dbg(DEBUG_HDLC,
+				    "7e----------------------------");
+
+				/* end of frame */
+				error = 0;
+
+				if (unlikely(fcs != PPP_GOODFCS)) {
+					err("Packet checksum at %lu failed, "
+					    "packet is corrupted (%u bytes)!",
+					    bcs->rcvbytes, skb->len);
+					compskb = NULL;
+					gigaset_rcv_error(compskb, cs, bcs);
+					error = 1;
+				} else {
+					if (likely((l = skb->len) > 2)) {
+						skb->tail -= 2;
+						skb->len -= 2;
+					} else {
+						dev_kfree_skb(skb);
+						skb = NULL;
+						inputstate |= INS_skip_frame;
+						if (l == 1) {
+							err("invalid packet size (1)!");
+							error = 1;
+							gigaset_rcv_error(NULL, cs, bcs);
+						}
+					}
+					if (likely(!(error ||
+						     (inputstate &
+						      INS_skip_frame)))) {
+						gigaset_rcv_skb(skb, cs, bcs);
+					}
+				}
+			}
+
+			if (unlikely(error))
+				if (skb)
+					dev_kfree_skb(skb);
+
+			fcs = PPP_INITFCS;
+			inputstate &= ~(INS_have_data | INS_skip_frame);
+			if (unlikely(bcs->ignore)) {
+				inputstate |= INS_skip_frame;
+				skb = NULL;
+			} else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)) {
+				skb_reserve(skb, HW_HDR_LEN);
+			} else {
+				warn("could not allocate new skb");
+				inputstate |= INS_skip_frame;
+			}
+
+			break;
+#ifdef CONFIG_GIGASET_DEBUG
+		} else if (unlikely(muststuff(c))) {
+			/* Should not happen. Possible after ZDLE=1<CR><LF>. */
+			dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c);
+#endif
+		}
+
+		/* add character */
+
+#ifdef CONFIG_GIGASET_DEBUG
+		if (unlikely(!(inputstate & INS_have_data))) {
+			dbg(DEBUG_HDLC,
+			    "7e (%d x) ================", bcs->emptycount);
+			bcs->emptycount = 0;
+		}
+#endif
+
+		inputstate |= INS_have_data;
+
+		if (likely(!(inputstate & INS_skip_frame))) {
+			if (unlikely(skb->len == SBUFSIZE)) {
+				warn("received packet too long");
+				dev_kfree_skb_any(skb);
+				skb = NULL;
+				inputstate |= INS_skip_frame;
+				break;
+			}
+			*gigaset_skb_put_quick(skb, 1) = c;
+			/* *__skb_put (skb, 1) = c; */
+			fcs = crc_ccitt_byte(fcs, c);
+		}
+
+		if (unlikely(!numbytes))
+			break;
+		c = *src++;
+		--numbytes;
+		if (unlikely(c == DLE_FLAG &&
+			     (cs->dle ||
+			      inbuf->inputstate & INS_DLE_command))) {
+			inbuf->inputstate |= INS_DLE_char;
+			break;
+		}
+	}
+	bcs->inputstate = inputstate;
+	bcs->fcs = fcs;
+	bcs->skb = skb;
+	return startbytes - numbytes;
+}
+
+/* process a block of received bytes in transparent data mode
+ * Invert bytes, undoing byte stuffing and watching for DLE escapes.
+ * If DLE is encountered, return immediately to let the caller handle it.
+ * Return value:
+ *	number of processed bytes
+ *	numbytes (all bytes processed) on error --FIXME
+ */
+static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes,
+                            struct inbuf_t *inbuf)
+{
+	struct cardstate *cs = inbuf->cs;
+	struct bc_state *bcs = inbuf->bcs;
+	int inputstate;
+	struct sk_buff *skb;
+	int startbytes = numbytes;
+
+	IFNULLRETVAL(bcs, numbytes);
+	inputstate = bcs->inputstate;
+	skb = bcs->skb;
+	IFNULLRETVAL(skb, numbytes);
+
+	for (;;) {
+		/* add character */
+		inputstate |= INS_have_data;
+
+		if (likely(!(inputstate & INS_skip_frame))) {
+			if (unlikely(skb->len == SBUFSIZE)) {
+				//FIXME just pass skb up and allocate a new one
+				warn("received packet too long");
+				dev_kfree_skb_any(skb);
+				skb = NULL;
+				inputstate |= INS_skip_frame;
+				break;
+			}
+			*gigaset_skb_put_quick(skb, 1) = gigaset_invtab[c];
+		}
+
+		if (unlikely(!numbytes))
+			break;
+		c = *src++;
+		--numbytes;
+		if (unlikely(c == DLE_FLAG &&
+			     (cs->dle ||
+			      inbuf->inputstate & INS_DLE_command))) {
+			inbuf->inputstate |= INS_DLE_char;
+			break;
+		}
+	}
+
+	/* pass data up */
+	if (likely(inputstate & INS_have_data)) {
+		if (likely(!(inputstate & INS_skip_frame))) {
+			gigaset_rcv_skb(skb, cs, bcs);
+		}
+		inputstate &= ~(INS_have_data | INS_skip_frame);
+		if (unlikely(bcs->ignore)) {
+			inputstate |= INS_skip_frame;
+			skb = NULL;
+		} else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN))
+				  != NULL)) {
+			skb_reserve(skb, HW_HDR_LEN);
+		} else {
+			warn("could not allocate new skb");
+			inputstate |= INS_skip_frame;
+		}
+	}
+
+	bcs->inputstate = inputstate;
+	bcs->skb = skb;
+	return startbytes - numbytes;
+}
+
+/* process a block of data received from the device
+ */
+void gigaset_m10x_input(struct inbuf_t *inbuf)
+{
+	struct cardstate *cs;
+	unsigned tail, head, numbytes;
+	unsigned char *src, c;
+	int procbytes;
+
+	head = atomic_read(&inbuf->head);
+	tail = atomic_read(&inbuf->tail);
+	dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
+
+	if (head != tail) {
+		cs = inbuf->cs;
+		src = inbuf->data + head;
+		numbytes = (head > tail ? RBUFSIZE : tail) - head;
+		dbg(DEBUG_INTR, "processing %u bytes", numbytes);
+
+		while (numbytes) {
+			if (atomic_read(&cs->mstate) == MS_LOCKED) {
+				procbytes = lock_loop(src, numbytes, inbuf);
+				src += procbytes;
+				numbytes -= procbytes;
+			} else {
+				c = *src++;
+				--numbytes;
+				if (c == DLE_FLAG && (cs->dle ||
+				    inbuf->inputstate & INS_DLE_command)) {
+					if (!(inbuf->inputstate & INS_DLE_char)) {
+						inbuf->inputstate |= INS_DLE_char;
+						goto nextbyte;
+					}
+					/* <DLE> <DLE> => <DLE> in data stream */
+					inbuf->inputstate &= ~INS_DLE_char;
+				}
+
+				if (!(inbuf->inputstate & INS_DLE_char)) {
+
+					/* FIXME Einfach je nach Modus Funktionszeiger in cs setzen [hier+hdlc_loop]?  */
+					/* FIXME Spart folgendes "if" und ermoeglicht andere Protokolle */
+					if (inbuf->inputstate & INS_command)
+						procbytes = cmd_loop(c, src, numbytes, inbuf);
+					else if (inbuf->bcs->proto2 == ISDN_PROTO_L2_HDLC)
+						procbytes = hdlc_loop(c, src, numbytes, inbuf);
+					else
+						procbytes = iraw_loop(c, src, numbytes, inbuf);
+
+					src += procbytes;
+					numbytes -= procbytes;
+				} else {  /* DLE-char */
+					inbuf->inputstate &= ~INS_DLE_char;
+					switch (c) {
+					case 'X': /*begin of command*/
+#ifdef CONFIG_GIGASET_DEBUG
+						if (inbuf->inputstate & INS_command)
+							err("received <DLE> 'X' in command mode");
+#endif
+						inbuf->inputstate |=
+							INS_command | INS_DLE_command;
+						break;
+					case '.': /*end of command*/
+#ifdef CONFIG_GIGASET_DEBUG
+						if (!(inbuf->inputstate & INS_command))
+							err("received <DLE> '.' in hdlc mode");
+#endif
+						inbuf->inputstate &= cs->dle ?
+							~(INS_DLE_command|INS_command)
+							: ~INS_DLE_command;
+						break;
+					//case DLE_FLAG: /*DLE_FLAG in data stream*/ /* schon oben behandelt! */
+					default:
+						err("received 0x10 0x%02x!", (int) c);
+						/* FIXME: reset driver?? */
+					}
+				}
+			}
+nextbyte:
+			if (!numbytes) {
+				/* end of buffer, check for wrap */
+				if (head > tail) {
+					head = 0;
+					src = inbuf->data;
+					numbytes = tail;
+				} else {
+					head = tail;
+					break;
+				}
+			}
+		}
+
+		dbg(DEBUG_INTR, "setting head to %u", head);
+		atomic_set(&inbuf->head, head);
+	}
+}
+
+
+/* == data output ========================================================== */
+
+/* Encoding of a PPP packet into an octet stuffed HDLC frame
+ * with FCS, opening and closing flags.
+ * parameters:
+ *	skb	skb containing original packet (freed upon return)
+ *	head	number of headroom bytes to allocate in result skb
+ *	tail	number of tailroom bytes to allocate in result skb
+ * Return value:
+ *	pointer to newly allocated skb containing the result frame
+ */
+static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail)
+{
+	struct sk_buff *hdlc_skb;
+	__u16 fcs;
+	unsigned char c;
+	unsigned char *cp;
+	int len;
+	unsigned int stuf_cnt;
+
+	stuf_cnt = 0;
+	fcs = PPP_INITFCS;
+	cp = skb->data;
+	len = skb->len;
+	while (len--) {
+		if (muststuff(*cp))
+			stuf_cnt++;
+		fcs = crc_ccitt_byte(fcs, *cp++);
+	}
+	fcs ^= 0xffff;                 /* complement */
+
+	/* size of new buffer: original size + number of stuffing bytes
+	 * + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes
+	 */
+	hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + tail + head);
+	if (!hdlc_skb) {
+		err("unable to allocate memory for HDLC encoding!");
+		dev_kfree_skb(skb);
+		return NULL;
+	}
+	skb_reserve(hdlc_skb, head);
+
+	/* Copy acknowledge request into new skb */
+	memcpy(hdlc_skb->head, skb->head, 2);
+
+	/* Add flag sequence in front of everything.. */
+	*(skb_put(hdlc_skb, 1)) = PPP_FLAG;
+
+	/* Perform byte stuffing while copying data. */
+	while (skb->len--) {
+		if (muststuff(*skb->data)) {
+			*(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
+			*(skb_put(hdlc_skb, 1)) = (*skb->data++) ^ PPP_TRANS;
+		} else
+			*(skb_put(hdlc_skb, 1)) = *skb->data++;
+	}
+
+	/* Finally add FCS (byte stuffed) and flag sequence */
+	c = (fcs & 0x00ff);      /* least significant byte first */
+	if (muststuff(c)) {
+		*(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
+		c ^= PPP_TRANS;
+	}
+	*(skb_put(hdlc_skb, 1)) = c;
+
+	c = ((fcs >> 8) & 0x00ff);
+	if (muststuff(c)) {
+		*(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
+		c ^= PPP_TRANS;
+	}
+	*(skb_put(hdlc_skb, 1)) = c;
+
+	*(skb_put(hdlc_skb, 1)) = PPP_FLAG;
+
+	dev_kfree_skb(skb);
+	return hdlc_skb;
+}
+
+/* Encoding of a raw packet into an octet stuffed bit inverted frame
+ * parameters:
+ *	skb	skb containing original packet (freed upon return)
+ *	head	number of headroom bytes to allocate in result skb
+ *	tail	number of tailroom bytes to allocate in result skb
+ * Return value:
+ *	pointer to newly allocated skb containing the result frame
+ */
+static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
+{
+	struct sk_buff *iraw_skb;
+	unsigned char c;
+	unsigned char *cp;
+	int len;
+
+	/* worst case: every byte must be stuffed */
+	iraw_skb = dev_alloc_skb(2*skb->len + tail + head);
+	if (!iraw_skb) {
+		err("unable to allocate memory for HDLC encoding!");
+		dev_kfree_skb(skb);
+		return NULL;
+	}
+	skb_reserve(iraw_skb, head);
+
+	cp = skb->data;
+	len = skb->len;
+	while (len--) {
+		c = gigaset_invtab[*cp++];
+		if (c == DLE_FLAG)
+			*(skb_put(iraw_skb, 1)) = c;
+		*(skb_put(iraw_skb, 1)) = c;
+	}
+	dev_kfree_skb(skb);
+	return iraw_skb;
+}
+
+/* gigaset_send_skb
+ * called by common.c to queue an skb for sending
+ * and start transmission if necessary
+ * parameters:
+ *	B Channel control structure
+ *	skb
+ * Return value:
+ *	number of bytes accepted for sending
+ *	(skb->len if ok, 0 if out of buffer space)
+ *	or error code (< 0, eg. -EINVAL)
+ */
+int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb)
+{
+	unsigned len;
+
+	IFNULLRETVAL(bcs, -EFAULT);
+	IFNULLRETVAL(skb, -EFAULT);
+	len = skb->len;
+
+	if (bcs->proto2 == ISDN_PROTO_L2_HDLC)
+		skb = HDLC_Encode(skb, HW_HDR_LEN, 0);
+	else
+		skb = iraw_encode(skb, HW_HDR_LEN, 0);
+	if (!skb)
+		return -ENOMEM;
+
+	skb_queue_tail(&bcs->squeue, skb);
+	tasklet_schedule(&bcs->cs->write_tasklet);
+
+	return len;	/* ok so far */
+}
diff -urN oldtree/drivers/isdn/gigaset/bas-gigaset.c newtree/drivers/isdn/gigaset/bas-gigaset.c
--- oldtree/drivers/isdn/gigaset/bas-gigaset.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/isdn/gigaset/bas-gigaset.c	2006-02-21 15:58:32.956136464 +0000
@@ -0,0 +1,2365 @@
+/*
+ * USB driver for Gigaset 307x base via direct USB connection.
+ *
+ * Copyright (c) 2001 by Hansjoerg Lipp <hjlipp@web.de>,
+ *                       Tilman Schmidt <tilman@imap.cc>,
+ *                       Stefan Eilers <Eilers.Stefan@epost.de>.
+ *
+ * Based on usb-gigaset.c.
+ *
+ * =====================================================================
+ *	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.
+ * =====================================================================
+ * ToDo: ...
+ * =====================================================================
+ * Version: $Id: bas-gigaset.c,v 1.52.4.19 2006/02/04 18:28:16 hjlipp Exp $
+ * =====================================================================
+ */
+
+#include "gigaset.h"
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/usb.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+/* Version Information */
+#define DRIVER_AUTHOR "Tilman Schmidt <tilman@imap.cc>, Hansjoerg Lipp <hjlipp@web.de>, Stefan Eilers <Eilers.Stefan@epost.de>"
+#define DRIVER_DESC "USB Driver for Gigaset 307x"
+
+
+/* Module parameters */
+
+static int startmode = SM_ISDN;
+static int cidmode = 1;
+
+module_param(startmode, int, S_IRUGO);
+module_param(cidmode, int, S_IRUGO);
+MODULE_PARM_DESC(startmode, "start in isdn4linux mode");
+MODULE_PARM_DESC(cidmode, "Call-ID mode");
+
+#define GIGASET_MINORS     1
+#define GIGASET_MINOR      16
+#define GIGASET_MODULENAME "bas_gigaset"
+#define GIGASET_DEVFSNAME  "gig/bas/"
+#define GIGASET_DEVNAME    "ttyGB"
+
+#define IF_WRITEBUF 256 //FIXME
+
+/* Values for the Gigaset 307x */
+#define USB_GIGA_VENDOR_ID      0x0681
+#define USB_GIGA_PRODUCT_ID     0x0001
+#define USB_4175_PRODUCT_ID     0x0002
+#define USB_SX303_PRODUCT_ID    0x0021
+#define USB_SX353_PRODUCT_ID    0x0022
+
+/* table of devices that work with this driver */
+static struct usb_device_id gigaset_table [] = {
+	{ USB_DEVICE(USB_GIGA_VENDOR_ID, USB_GIGA_PRODUCT_ID) },
+	{ USB_DEVICE(USB_GIGA_VENDOR_ID, USB_4175_PRODUCT_ID) },
+	{ USB_DEVICE(USB_GIGA_VENDOR_ID, USB_SX303_PRODUCT_ID) },
+	{ USB_DEVICE(USB_GIGA_VENDOR_ID, USB_SX353_PRODUCT_ID) },
+	{ } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, gigaset_table);
+
+/* Get a minor range for your devices from the usb maintainer */
+#define USB_SKEL_MINOR_BASE	200
+
+/*======================= local function prototypes =============================*/
+
+/* This function is called if a new device is connected to the USB port. It
+ * checks whether this new device belongs to this driver.
+ */
+static int gigaset_probe(struct usb_interface *interface,
+			 const struct usb_device_id *id);
+
+/* Function will be called if the device is unplugged */
+static void gigaset_disconnect(struct usb_interface *interface);
+
+
+/*==============================================================================*/
+
+struct bas_cardstate {
+	struct usb_device       *udev;		/* USB device pointer */
+	struct usb_interface    *interface;	/* interface for this device */
+	unsigned char		minor;		/* starting minor number */
+
+	struct urb              *urb_ctrl;	/* control pipe default URB */
+	struct usb_ctrlrequest	dr_ctrl;
+	struct timer_list	timer_ctrl;	/* control request timeout */
+
+	struct timer_list	timer_atrdy;	/* AT command ready timeout */
+	struct urb              *urb_cmd_out;	/* for sending AT commands */
+	struct usb_ctrlrequest	dr_cmd_out;
+	int			retry_cmd_out;
+
+	struct urb              *urb_cmd_in;	/* for receiving AT replies */
+	struct usb_ctrlrequest	dr_cmd_in;
+	struct timer_list	timer_cmd_in;	/* receive request timeout */
+	unsigned char           *rcvbuf;	/* AT reply receive buffer */
+
+	struct urb              *urb_int_in;	/* URB for interrupt pipe */
+	unsigned char		int_in_buf[3];
+
+	spinlock_t		lock;		/* locks all following */
+	atomic_t		basstate;	/* bitmap (BS_*) */
+	int			pending;	/* uncompleted base request */
+	int			rcvbuf_size;	/* size of AT receive buffer */
+						/* 0: no receive in progress */
+	int			retry_cmd_in;	/* receive req retry count */
+};
+
+/* status of direct USB connection to 307x base (bits in basstate) */
+#define BS_ATOPEN	0x001
+#define BS_B1OPEN	0x002
+#define BS_B2OPEN	0x004
+#define BS_ATREADY	0x008
+#define BS_INIT		0x010
+#define BS_ATTIMER	0x020
+
+
+static struct gigaset_driver *driver = NULL;
+static struct cardstate *cardstate = NULL;
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver gigaset_usb_driver = {
+	.name =         GIGASET_MODULENAME,
+	.probe =        gigaset_probe,
+	.disconnect =   gigaset_disconnect,
+	.id_table =     gigaset_table,
+};
+
+/* get message text for USB status code
+ */
+static char *get_usb_statmsg(int status)
+{
+	static char unkmsg[28];
+
+	switch (status) {
+	case 0:
+		return "success";
+	case -ENOENT:
+		return "canceled";
+	case -ECONNRESET:
+		return "canceled (async)";
+	case -EINPROGRESS:
+		return "pending";
+	case -EPROTO:
+		return "bit stuffing or unknown USB error";
+	case -EILSEQ:
+		return "Illegal byte sequence (CRC mismatch)";
+	case -EPIPE:
+		return "babble detect or endpoint stalled";
+	case -ENOSR:
+		return "buffer error";
+	case -ETIMEDOUT:
+		return "timed out";
+	case -ENODEV:
+		return "device not present";
+	case -EREMOTEIO:
+		return "short packet detected";
+	case -EXDEV:
+		return "partial isochronous transfer";
+	case -EINVAL:
+		return "invalid argument";
+	case -ENXIO:
+		return "URB already queued";
+	case -EAGAIN:
+		return "isochronous start frame too early or too much scheduled";
+	case -EFBIG:
+		return "too many isochronous frames requested";
+	case -EMSGSIZE:
+		return "endpoint message size zero";
+	case -ESHUTDOWN:
+		return "endpoint shutdown";
+	case -EBUSY:
+		return "another request pending";
+	default:
+		snprintf(unkmsg, sizeof(unkmsg), "unknown error %d", status);
+		return unkmsg;
+	}
+}
+
+/* usb_pipetype_str
+ * retrieve string representation of USB pipe type
+ */
+static inline char *usb_pipetype_str(int pipe)
+{
+	if (usb_pipeisoc(pipe))
+		return "Isoc";
+	if (usb_pipeint(pipe))
+		return "Int";
+	if (usb_pipecontrol(pipe))
+		return "Ctrl";
+	if (usb_pipebulk(pipe))
+		return "Bulk";
+	return "?";
+}
+
+/* dump_urb
+ * write content of URB to syslog for debugging
+ */
+static inline void dump_urb(enum debuglevel level, const char *tag,
+                            struct urb *urb)
+{
+#ifdef CONFIG_GIGASET_DEBUG
+	int i;
+	IFNULLRET(tag);
+	dbg(level, "%s urb(0x%08lx)->{", tag, (unsigned long) urb);
+	if (urb) {
+		dbg(level,
+		    "  dev=0x%08lx, pipe=%s:EP%d/DV%d:%s, "
+		    "status=%d, hcpriv=0x%08lx, transfer_flags=0x%x,",
+		    (unsigned long) urb->dev,
+		    usb_pipetype_str(urb->pipe),
+		    usb_pipeendpoint(urb->pipe), usb_pipedevice(urb->pipe),
+		    usb_pipein(urb->pipe) ? "in" : "out",
+		    urb->status, (unsigned long) urb->hcpriv,
+		    urb->transfer_flags);
+		dbg(level,
+		    "  transfer_buffer=0x%08lx[%d], actual_length=%d, "
+		    "bandwidth=%d, setup_packet=0x%08lx,",
+		    (unsigned long) urb->transfer_buffer,
+		    urb->transfer_buffer_length, urb->actual_length,
+		    urb->bandwidth, (unsigned long) urb->setup_packet);
+		dbg(level,
+		    "  start_frame=%d, number_of_packets=%d, interval=%d, "
+		    "error_count=%d,",
+		    urb->start_frame, urb->number_of_packets, urb->interval,
+		    urb->error_count);
+		dbg(level,
+		    "  context=0x%08lx, complete=0x%08lx, iso_frame_desc[]={",
+		    (unsigned long) urb->context,
+		    (unsigned long) urb->complete);
+		for (i = 0; i < urb->number_of_packets; i++) {
+			struct usb_iso_packet_descriptor *pifd = &urb->iso_frame_desc[i];
+			dbg(level,
+			    "    {offset=%u, length=%u, actual_length=%u, "
+			    "status=%u}",
+			    pifd->offset, pifd->length, pifd->actual_length,
+			    pifd->status);
+		}
+	}
+	dbg(level, "}}");
+#endif
+}
+
+/* read/set modem control bits etc. (m10x only) */
+static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state,
+                                  unsigned new_state)
+{
+	return -EINVAL;
+}
+
+static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag)
+{
+	return -EINVAL;
+}
+
+static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
+{
+	return -EINVAL;
+}
+
+/* error_hangup
+ * hang up any existing connection because of an unrecoverable error
+ * This function may be called from any context and takes care of scheduling
+ * the necessary actions for execution outside of interrupt context.
+ * argument:
+ *	B channel control structure
+ */
+static inline void error_hangup(struct bc_state *bcs)
+{
+	struct cardstate *cs = bcs->cs;
+
+	dbg(DEBUG_ANY,
+	    "%s: scheduling HUP for channel %d", __func__, bcs->channel);
+
+	if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) {
+		//FIXME what should we do?
+		return;
+	}
+
+	gigaset_schedule_event(cs);
+}
+
+/* error_reset
+ * reset Gigaset device because of an unrecoverable error
+ * This function may be called from any context and takes care of scheduling
+ * the necessary actions for execution outside of interrupt context.
+ * argument:
+ *	controller state structure
+ */
+static inline void error_reset(struct cardstate *cs)
+{
+	//FIXME try to recover without bothering the user
+	err("unrecoverable error - please disconnect the Gigaset base to reset");
+}
+
+/* check_pending
+ * check for completion of pending control request
+ * parameter:
+ *	urb	USB request block of completed request
+ *		urb->context = hardware specific controller state structure
+ */
+static void check_pending(struct bas_cardstate *ucs)
+{
+	unsigned long flags;
+
+	IFNULLRET(ucs);
+	IFNULLRET(cardstate);
+
+	spin_lock_irqsave(&ucs->lock, flags);
+	switch (ucs->pending) {
+	case 0:
+		break;
+	case HD_OPEN_ATCHANNEL:
+		if (atomic_read(&ucs->basstate) & BS_ATOPEN)
+			ucs->pending = 0;
+		break;
+	case HD_OPEN_B1CHANNEL:
+		if (atomic_read(&ucs->basstate) & BS_B1OPEN)
+			ucs->pending = 0;
+		break;
+	case HD_OPEN_B2CHANNEL:
+		if (atomic_read(&ucs->basstate) & BS_B2OPEN)
+			ucs->pending = 0;
+		break;
+	case HD_CLOSE_ATCHANNEL:
+		if (!(atomic_read(&ucs->basstate) & BS_ATOPEN))
+			ucs->pending = 0;
+		//wake_up_interruptible(cs->initwait);
+		//FIXME need own wait queue?
+		break;
+	case HD_CLOSE_B1CHANNEL:
+		if (!(atomic_read(&ucs->basstate) & BS_B1OPEN))
+			ucs->pending = 0;
+		break;
+	case HD_CLOSE_B2CHANNEL:
+		if (!(atomic_read(&ucs->basstate) & BS_B2OPEN))
+			ucs->pending = 0;
+		break;
+	case HD_DEVICE_INIT_ACK:		/* no reply expected */
+		ucs->pending = 0;
+		break;
+	/* HD_READ_ATMESSAGE, HD_WRITE_ATMESSAGE, HD_RESET_INTERRUPTPIPE
+	 * are handled separately and should never end up here
+	 */
+	default:
+		warn("unknown pending request 0x%02x cleared", ucs->pending);
+		ucs->pending = 0;
+	}
+
+	if (!ucs->pending)
+		del_timer(&ucs->timer_ctrl);
+
+	spin_unlock_irqrestore(&ucs->lock, flags);
+}
+
+/* cmd_in_timeout
+ * timeout routine for command input request
+ * argument:
+ *	controller state structure
+ */
+static void cmd_in_timeout(unsigned long data)
+{
+	struct cardstate *cs = (struct cardstate *) data;
+	struct bas_cardstate *ucs;
+	unsigned long flags;
+
+	IFNULLRET(cs);
+	ucs = cs->hw.bas;
+	IFNULLRET(ucs);
+
+	spin_lock_irqsave(&cs->lock, flags);
+	if (!atomic_read(&cs->connected)) {
+		dbg(DEBUG_USBREQ, "%s: disconnected", __func__);
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return;
+	}
+	if (!ucs->rcvbuf_size) {
+		dbg(DEBUG_USBREQ, "%s: no receive in progress", __func__);
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return;
+	}
+	spin_unlock_irqrestore(&cs->lock, flags);
+
+	err("timeout reading AT response");
+	error_reset(cs);	//FIXME retry?
+}
+
+
+static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs);
+
+/* atread_submit
+ * submit an HD_READ_ATMESSAGE command URB
+ * parameters:
+ *	cs	controller state structure
+ *	timeout	timeout in 1/10 sec., 0: none
+ * return value:
+ *	0 on success
+ *	-EINVAL if a NULL pointer is encountered somewhere
+ *	-EBUSY if another request is pending
+ *	any URB submission error code
+ */
+static int atread_submit(struct cardstate *cs, int timeout)
+{
+	struct bas_cardstate *ucs;
+	int ret;
+
+	IFNULLRETVAL(cs, -EINVAL);
+	ucs = cs->hw.bas;
+	IFNULLRETVAL(ucs, -EINVAL);
+	IFNULLRETVAL(ucs->urb_cmd_in, -EINVAL);
+
+	dbg(DEBUG_USBREQ, "-------> HD_READ_ATMESSAGE (%d)", ucs->rcvbuf_size);
+
+	if (ucs->urb_cmd_in->status == -EINPROGRESS) {
+		err("could not submit HD_READ_ATMESSAGE: URB busy");
+		return -EBUSY;
+	}
+
+	ucs->dr_cmd_in.bRequestType = IN_VENDOR_REQ;
+	ucs->dr_cmd_in.bRequest = HD_READ_ATMESSAGE;
+	ucs->dr_cmd_in.wValue = 0;
+	ucs->dr_cmd_in.wIndex = 0;
+	ucs->dr_cmd_in.wLength = cpu_to_le16(ucs->rcvbuf_size);
+	usb_fill_control_urb(ucs->urb_cmd_in, ucs->udev,
+	                     usb_rcvctrlpipe(ucs->udev, 0),
+	                     (unsigned char*) & ucs->dr_cmd_in,
+	                     ucs->rcvbuf, ucs->rcvbuf_size,
+	                     read_ctrl_callback, cs->inbuf);
+
+	if ((ret = usb_submit_urb(ucs->urb_cmd_in, SLAB_ATOMIC)) != 0) {
+		err("could not submit HD_READ_ATMESSAGE: %s",
+		    get_usb_statmsg(ret));
+		return ret;
+	}
+
+	if (timeout > 0) {
+		dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout);
+		ucs->timer_cmd_in.expires = jiffies + timeout * HZ / 10;
+		ucs->timer_cmd_in.data = (unsigned long) cs;
+		ucs->timer_cmd_in.function = cmd_in_timeout;
+		add_timer(&ucs->timer_cmd_in);
+	}
+	return 0;
+}
+
+static void stopurbs(struct bas_bc_state *);
+static int start_cbsend(struct cardstate *);
+
+/* set/clear bits in base connection state
+ */
+inline static void update_basstate(struct bas_cardstate *ucs,
+				   int set, int clear)
+{
+	unsigned long flags;
+	int state;
+
+	spin_lock_irqsave(&ucs->lock, flags);
+	state = atomic_read(&ucs->basstate);
+	state &= ~clear;
+	state |= set;
+	atomic_set(&ucs->basstate, state);
+	spin_unlock_irqrestore(&ucs->lock, flags);
+}
+
+
+/* read_int_callback
+ * USB completion handler for interrupt pipe input
+ * called by the USB subsystem in interrupt context
+ * parameter:
+ *	urb	USB request block
+ *		urb->context = controller state structure
+ */
+static void read_int_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct cardstate *cs;
+	struct bas_cardstate *ucs;
+	struct bc_state *bcs;
+	unsigned long flags;
+	int status;
+	unsigned l;
+	int channel;
+
+	IFNULLRET(urb);
+	cs = (struct cardstate *) urb->context;
+	IFNULLRET(cs);
+	ucs = cs->hw.bas;
+	IFNULLRET(ucs);
+
+	if (unlikely(!atomic_read(&cs->connected))) {
+		warn("%s: disconnected", __func__);
+		return;
+	}
+
+	switch (urb->status) {
+	case 0:			/* success */
+		break;
+	case -ENOENT:			/* canceled */
+	case -ECONNRESET:		/* canceled (async) */
+	case -EINPROGRESS:		/* pending */
+		/* ignore silently */
+		dbg(DEBUG_USBREQ,
+		    "%s: %s", __func__, get_usb_statmsg(urb->status));
+		return;
+	default:		/* severe trouble */
+		warn("interrupt read: %s", get_usb_statmsg(urb->status));
+		//FIXME corrective action? resubmission always ok?
+		goto resubmit;
+	}
+
+	l = (unsigned) ucs->int_in_buf[1] +
+	    (((unsigned) ucs->int_in_buf[2]) << 8);
+
+	dbg(DEBUG_USBREQ,
+	    "<-------%d: 0x%02x (%u [0x%02x 0x%02x])", urb->actual_length,
+	    (int)ucs->int_in_buf[0], l,
+	    (int)ucs->int_in_buf[1], (int)ucs->int_in_buf[2]);
+
+	channel = 0;
+
+	switch (ucs->int_in_buf[0]) {
+	case HD_DEVICE_INIT_OK:
+		update_basstate(ucs, BS_INIT, 0);
+		break;
+
+	case HD_READY_SEND_ATDATA:
+		del_timer(&ucs->timer_atrdy);
+		update_basstate(ucs, BS_ATREADY, BS_ATTIMER);
+		start_cbsend(cs);
+		break;
+
+	case HD_OPEN_B2CHANNEL_ACK:
+		++channel;
+	case HD_OPEN_B1CHANNEL_ACK:
+		bcs = cs->bcs + channel;
+		update_basstate(ucs, BS_B1OPEN << channel, 0);
+		gigaset_bchannel_up(bcs);
+		break;
+
+	case HD_OPEN_ATCHANNEL_ACK:
+		update_basstate(ucs, BS_ATOPEN, 0);
+		start_cbsend(cs);
+		break;
+
+	case HD_CLOSE_B2CHANNEL_ACK:
+		++channel;
+	case HD_CLOSE_B1CHANNEL_ACK:
+		bcs = cs->bcs + channel;
+		update_basstate(ucs, 0, BS_B1OPEN << channel);
+		stopurbs(bcs->hw.bas);
+		gigaset_bchannel_down(bcs);
+		break;
+
+	case HD_CLOSE_ATCHANNEL_ACK:
+		update_basstate(ucs, 0, BS_ATOPEN);
+		break;
+
+	case HD_B2_FLOW_CONTROL:
+		++channel;
+	case HD_B1_FLOW_CONTROL:
+		bcs = cs->bcs + channel;
+		atomic_add((l - BAS_NORMFRAME) * BAS_CORRFRAMES,
+		           &bcs->hw.bas->corrbytes);
+		dbg(DEBUG_ISO,
+		    "Flow control (channel %d, sub %d): 0x%02x => %d",
+		    channel, bcs->hw.bas->numsub, l,
+		    atomic_read(&bcs->hw.bas->corrbytes));
+		break;
+
+	case HD_RECEIVEATDATA_ACK:	/* AT response ready to be received */
+		if (!l) {
+			warn("HD_RECEIVEATDATA_ACK with length 0 ignored");
+			break;
+		}
+		spin_lock_irqsave(&cs->lock, flags);
+		if (ucs->rcvbuf_size) {
+			spin_unlock_irqrestore(&cs->lock, flags);
+			err("receive AT data overrun, %d bytes lost", l);
+			error_reset(cs);	//FIXME reschedule
+			break;
+		}
+		if ((ucs->rcvbuf = kmalloc(l, GFP_ATOMIC)) == NULL) {
+			spin_unlock_irqrestore(&cs->lock, flags);
+			err("%s: out of memory, %d bytes lost", __func__, l);
+			error_reset(cs);	//FIXME reschedule
+			break;
+		}
+		ucs->rcvbuf_size = l;
+		ucs->retry_cmd_in = 0;
+		if ((status = atread_submit(cs, BAS_TIMEOUT)) < 0) {
+			kfree(ucs->rcvbuf);
+			ucs->rcvbuf = NULL;
+			ucs->rcvbuf_size = 0;
+			error_reset(cs);	//FIXME reschedule
+		}
+		spin_unlock_irqrestore(&cs->lock, flags);
+		break;
+
+	case HD_RESET_INTERRUPT_PIPE_ACK:
+		dbg(DEBUG_USBREQ, "HD_RESET_INTERRUPT_PIPE_ACK");
+		break;
+
+	case HD_SUSPEND_END:
+		dbg(DEBUG_USBREQ, "HD_SUSPEND_END");
+		break;
+
+	default:
+		warn("unknown Gigaset signal 0x%02x (%u) ignored",
+		     (int) ucs->int_in_buf[0], l);
+	}
+
+	check_pending(ucs);
+
+resubmit:
+	status = usb_submit_urb(urb, SLAB_ATOMIC);
+	if (unlikely(status)) {
+		err("could not resubmit interrupt URB: %s",
+		    get_usb_statmsg(status));
+		error_reset(cs);
+	}
+}
+
+/* read_ctrl_callback
+ * USB completion handler for control pipe input
+ * called by the USB subsystem in interrupt context
+ * parameter:
+ *	urb	USB request block
+ *		urb->context = inbuf structure for controller state
+ */
+static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct cardstate *cs;
+	struct bas_cardstate *ucs;
+	unsigned numbytes;
+	unsigned long flags;
+	struct inbuf_t *inbuf;
+	int have_data = 0;
+
+	IFNULLRET(urb);
+	inbuf = (struct inbuf_t *) urb->context;
+	IFNULLRET(inbuf);
+	cs = inbuf->cs;
+	IFNULLRET(cs);
+	ucs = cs->hw.bas;
+	IFNULLRET(ucs);
+
+	spin_lock_irqsave(&cs->lock, flags);
+	if (!atomic_read(&cs->connected)) {
+		warn("%s: disconnected", __func__);
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return;
+	}
+
+	if (!ucs->rcvbuf_size) {
+		warn("%s: no receive in progress", __func__);
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return;
+	}
+
+	del_timer(&ucs->timer_cmd_in);
+
+	switch (urb->status) {
+	case 0:				/* normal completion */
+		numbytes = urb->actual_length;
+		if (unlikely(numbytes == 0)) {
+			warn("control read: empty block received");
+			goto retry;
+		}
+		if (unlikely(numbytes != ucs->rcvbuf_size)) {
+			warn("control read: received %d chars, expected %d",
+			     numbytes, ucs->rcvbuf_size);
+			if (numbytes > ucs->rcvbuf_size)
+				numbytes = ucs->rcvbuf_size;
+		}
+
+		/* copy received bytes to inbuf */
+		have_data = gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes);
+
+		if (unlikely(numbytes < ucs->rcvbuf_size)) {
+			/* incomplete - resubmit for remaining bytes */
+			ucs->rcvbuf_size -= numbytes;
+			ucs->retry_cmd_in = 0;
+			goto retry;
+		}
+		break;
+
+	case -ENOENT:			/* canceled */
+	case -ECONNRESET:		/* canceled (async) */
+	case -EINPROGRESS:		/* pending */
+		/* no action necessary */
+		dbg(DEBUG_USBREQ,
+		    "%s: %s", __func__, get_usb_statmsg(urb->status));
+		break;
+
+	default:			/* severe trouble */
+		warn("control read: %s", get_usb_statmsg(urb->status));
+	retry:
+		if (ucs->retry_cmd_in++ < BAS_RETRY) {
+			notice("control read: retry %d", ucs->retry_cmd_in);
+			if (atread_submit(cs, BAS_TIMEOUT) >= 0) {
+				/* resubmitted - bypass regular exit block */
+				spin_unlock_irqrestore(&cs->lock, flags);
+				return;
+			}
+		} else {
+			err("control read: giving up after %d tries",
+			    ucs->retry_cmd_in);
+		}
+		error_reset(cs);
+	}
+
+	kfree(ucs->rcvbuf);
+	ucs->rcvbuf = NULL;
+	ucs->rcvbuf_size = 0;
+	spin_unlock_irqrestore(&cs->lock, flags);
+	if (have_data) {
+		dbg(DEBUG_INTR, "%s-->BH", __func__);
+		gigaset_schedule_event(cs);
+	}
+}
+
+/* read_iso_callback
+ * USB completion handler for B channel isochronous input
+ * called by the USB subsystem in interrupt context
+ * parameter:
+ *	urb	USB request block of completed request
+ *		urb->context = bc_state structure
+ */
+static void read_iso_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct bc_state *bcs;
+	struct bas_bc_state *ubc;
+	unsigned long flags;
+	int i, rc;
+
+	IFNULLRET(urb);
+	IFNULLRET(urb->context);
+	IFNULLRET(cardstate);
+
+	/* status codes not worth bothering the tasklet with */
+	if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET ||
+	             urb->status == -EINPROGRESS)) {
+		dbg(DEBUG_ISO,
+		    "%s: %s", __func__, get_usb_statmsg(urb->status));
+		return;
+	}
+
+	bcs = (struct bc_state *) urb->context;
+	ubc = bcs->hw.bas;
+	IFNULLRET(ubc);
+
+	spin_lock_irqsave(&ubc->isoinlock, flags);
+	if (likely(ubc->isoindone == NULL)) {
+		/* pass URB to tasklet */
+		ubc->isoindone = urb;
+		tasklet_schedule(&ubc->rcvd_tasklet);
+	} else {
+		/* tasklet still busy, drop data and resubmit URB */
+		ubc->loststatus = urb->status;
+		for (i = 0; i < BAS_NUMFRAMES; i++) {
+			ubc->isoinlost += urb->iso_frame_desc[i].actual_length;
+			if (unlikely(urb->iso_frame_desc[i].status != 0 &&
+				     urb->iso_frame_desc[i].status != -EINPROGRESS)) {
+				ubc->loststatus = urb->iso_frame_desc[i].status;
+			}
+			urb->iso_frame_desc[i].status = 0;
+			urb->iso_frame_desc[i].actual_length = 0;
+		}
+		if (likely(atomic_read(&ubc->running))) {
+			urb->dev = bcs->cs->hw.bas->udev;	/* clobbered by USB subsystem */
+			urb->transfer_flags = URB_ISO_ASAP;
+			urb->number_of_packets = BAS_NUMFRAMES;
+			dbg(DEBUG_ISO, "%s: isoc read overrun/resubmit", __func__);
+			rc = usb_submit_urb(urb, SLAB_ATOMIC);
+			if (unlikely(rc != 0)) {
+				err("could not resubmit isochronous read URB: %s",
+				    get_usb_statmsg(rc));
+				dump_urb(DEBUG_ISO, "isoc read", urb);
+				error_hangup(bcs);
+			}
+		}
+	}
+	spin_unlock_irqrestore(&ubc->isoinlock, flags);
+}
+
+/* write_iso_callback
+ * USB completion handler for B channel isochronous output
+ * called by the USB subsystem in interrupt context
+ * parameter:
+ *	urb	USB request block of completed request
+ *		urb->context = isow_urbctx_t structure
+ */
+static void write_iso_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct isow_urbctx_t *ucx;
+	struct bas_bc_state *ubc;
+	unsigned long flags;
+
+	IFNULLRET(urb);
+	IFNULLRET(urb->context);
+	IFNULLRET(cardstate);
+
+	/* status codes not worth bothering the tasklet with */
+	if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET ||
+	             urb->status == -EINPROGRESS)) {
+		dbg(DEBUG_ISO,
+		    "%s: %s", __func__, get_usb_statmsg(urb->status));
+		return;
+	}
+
+	/* pass URB context to tasklet */
+	ucx = (struct isow_urbctx_t *) urb->context;
+	IFNULLRET(ucx->bcs);
+	ubc = ucx->bcs->hw.bas;
+	IFNULLRET(ubc);
+
+	spin_lock_irqsave(&ubc->isooutlock, flags);
+	ubc->isooutovfl = ubc->isooutdone;
+	ubc->isooutdone = ucx;
+	spin_unlock_irqrestore(&ubc->isooutlock, flags);
+	tasklet_schedule(&ubc->sent_tasklet);
+}
+
+/* starturbs
+ * prepare and submit USB request blocks for isochronous input and output
+ * argument:
+ *	B channel control structure
+ * return value:
+ *	0 on success
+ *	< 0 on error (no URBs submitted)
+ */
+static int starturbs(struct bc_state *bcs)
+{
+	struct urb *urb;
+	struct bas_bc_state *ubc;
+	int j, k;
+	int rc;
+
+	IFNULLRETVAL(bcs, -EFAULT);
+	ubc = bcs->hw.bas;
+	IFNULLRETVAL(ubc, -EFAULT);
+
+	/* initialize L2 reception */
+	if (bcs->proto2 == ISDN_PROTO_L2_HDLC)
+		bcs->inputstate |= INS_flag_hunt;
+
+	/* submit all isochronous input URBs */
+	atomic_set(&ubc->running, 1);
+	for (k = 0; k < BAS_INURBS; k++) {
+		urb = ubc->isoinurbs[k];
+		if (!urb) {
+			err("isoinurbs[%d]==NULL", k);
+			rc = -EFAULT;
+			goto error;
+		}
+
+		urb->dev = bcs->cs->hw.bas->udev;
+		urb->pipe = usb_rcvisocpipe(urb->dev, 3 + 2 * bcs->channel);
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->transfer_buffer = ubc->isoinbuf + k * BAS_INBUFSIZE;
+		urb->transfer_buffer_length = BAS_INBUFSIZE;
+		urb->number_of_packets = BAS_NUMFRAMES;
+		urb->interval = BAS_FRAMETIME;
+		urb->complete = read_iso_callback;
+		urb->context = bcs;
+		for (j = 0; j < BAS_NUMFRAMES; j++) {
+			urb->iso_frame_desc[j].offset = j * BAS_MAXFRAME;
+			urb->iso_frame_desc[j].length = BAS_MAXFRAME;
+			urb->iso_frame_desc[j].status = 0;
+			urb->iso_frame_desc[j].actual_length = 0;
+		}
+
+		dump_urb(DEBUG_ISO, "Initial isoc read", urb);
+		if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) {
+			err("could not submit isochronous read URB %d: %s",
+			    k, get_usb_statmsg(rc));
+			goto error;
+		}
+	}
+
+	/* initialize L2 transmission */
+	gigaset_isowbuf_init(ubc->isooutbuf, PPP_FLAG);
+
+	/* set up isochronous output URBs for flag idling */
+	for (k = 0; k < BAS_OUTURBS; ++k) {
+		urb = ubc->isoouturbs[k].urb;
+		if (!urb) {
+			err("isoouturbs[%d].urb==NULL", k);
+			rc = -EFAULT;
+			goto error;
+		}
+		urb->dev = bcs->cs->hw.bas->udev;
+		urb->pipe = usb_sndisocpipe(urb->dev, 4 + 2 * bcs->channel);
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->transfer_buffer = ubc->isooutbuf->data;
+		urb->transfer_buffer_length = sizeof(ubc->isooutbuf->data);
+		urb->number_of_packets = BAS_NUMFRAMES;
+		urb->interval = BAS_FRAMETIME;
+		urb->complete = write_iso_callback;
+		urb->context = &ubc->isoouturbs[k];
+		for (j = 0; j < BAS_NUMFRAMES; ++j) {
+			urb->iso_frame_desc[j].offset = BAS_OUTBUFSIZE;
+			urb->iso_frame_desc[j].length = BAS_NORMFRAME;
+			urb->iso_frame_desc[j].status = 0;
+			urb->iso_frame_desc[j].actual_length = 0;
+		}
+		ubc->isoouturbs[k].limit = -1;
+	}
+
+	/* submit two URBs, keep third one */
+	for (k = 0; k < 2; ++k) {
+		dump_urb(DEBUG_ISO, "Initial isoc write", urb);
+		rc = usb_submit_urb(ubc->isoouturbs[k].urb, SLAB_ATOMIC);
+		if (rc != 0) {
+			err("could not submit isochronous write URB %d: %s",
+			    k, get_usb_statmsg(rc));
+			goto error;
+		}
+	}
+	dump_urb(DEBUG_ISO, "Initial isoc write (free)", urb);
+	ubc->isooutfree = &ubc->isoouturbs[2];
+	ubc->isooutdone = ubc->isooutovfl = NULL;
+	return 0;
+ error:
+	stopurbs(ubc);
+	return rc;
+}
+
+/* stopurbs
+ * cancel the USB request blocks for isochronous input and output
+ * errors are silently ignored
+ * argument:
+ *	B channel control structure
+ */
+static void stopurbs(struct bas_bc_state *ubc)
+{
+	int k, rc;
+
+	IFNULLRET(ubc);
+
+	atomic_set(&ubc->running, 0);
+
+	for (k = 0; k < BAS_INURBS; ++k) {
+		rc = usb_unlink_urb(ubc->isoinurbs[k]);
+		dbg(DEBUG_ISO, "%s: isoc input URB %d unlinked, result = %d",
+		    __func__, k, rc);
+	}
+
+	for (k = 0; k < BAS_OUTURBS; ++k) {
+		rc = usb_unlink_urb(ubc->isoouturbs[k].urb);
+		dbg(DEBUG_ISO, "%s: isoc output URB %d unlinked, result = %d",
+		    __func__, k, rc);
+	}
+}
+
+/* Isochronous Write - Bottom Half */
+/* =============================== */
+
+/* submit_iso_write_urb
+ * fill and submit the next isochronous write URB
+ * parameters:
+ *	bcs	B channel state structure
+ * return value:
+ *	number of frames submitted in URB
+ *	0 if URB not submitted because no data available (isooutbuf busy)
+ *	error code < 0 on error
+ */
+static int submit_iso_write_urb(struct isow_urbctx_t *ucx)
+{
+	struct urb *urb;
+	struct bas_bc_state *ubc;
+	struct usb_iso_packet_descriptor *ifd;
+	int corrbytes, nframe, rc;
+
+	IFNULLRETVAL(ucx, -EFAULT);
+	urb = ucx->urb;
+	IFNULLRETVAL(urb, -EFAULT);
+	IFNULLRETVAL(ucx->bcs, -EFAULT);
+	ubc = ucx->bcs->hw.bas;
+	IFNULLRETVAL(ubc, -EFAULT);
+
+	urb->dev = ucx->bcs->cs->hw.bas->udev;	/* clobbered by USB subsystem */
+	urb->transfer_flags = URB_ISO_ASAP;
+	urb->transfer_buffer = ubc->isooutbuf->data;
+	urb->transfer_buffer_length = sizeof(ubc->isooutbuf->data);
+
+	for (nframe = 0; nframe < BAS_NUMFRAMES; nframe++) {
+		ifd = &urb->iso_frame_desc[nframe];
+
+		/* compute frame length according to flow control */
+		ifd->length = BAS_NORMFRAME;
+		if ((corrbytes = atomic_read(&ubc->corrbytes)) != 0) {
+			dbg(DEBUG_ISO, "%s: corrbytes=%d", __func__, corrbytes);
+			if (corrbytes > BAS_HIGHFRAME - BAS_NORMFRAME)
+				corrbytes = BAS_HIGHFRAME - BAS_NORMFRAME;
+			else if (corrbytes < BAS_LOWFRAME - BAS_NORMFRAME)
+				corrbytes = BAS_LOWFRAME - BAS_NORMFRAME;
+			ifd->length += corrbytes;
+			atomic_add(-corrbytes, &ubc->corrbytes);
+		}
+		//dbg(DEBUG_ISO, "%s: frame %d length=%d", __func__, nframe, ifd->length);
+
+		/* retrieve block of data to send */
+		ifd->offset = gigaset_isowbuf_getbytes(ubc->isooutbuf, ifd->length);
+		if (ifd->offset < 0) {
+			if (ifd->offset == -EBUSY) {
+				dbg(DEBUG_ISO, "%s: buffer busy at frame %d",
+				    __func__, nframe);
+				/* tasklet will be restarted from gigaset_send_skb() */
+			} else {
+				err("%s: buffer error %d at frame %d",
+				    __func__, ifd->offset, nframe);
+				return ifd->offset;
+			}
+			break;
+		}
+		ucx->limit = atomic_read(&ubc->isooutbuf->nextread);
+		ifd->status = 0;
+		ifd->actual_length = 0;
+	}
+	if ((urb->number_of_packets = nframe) > 0) {
+		if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) {
+			err("could not submit isochronous write URB: %s",
+			    get_usb_statmsg(rc));
+			dump_urb(DEBUG_ISO, "isoc write", urb);
+			return rc;
+		}
+		++ubc->numsub;
+	}
+	return nframe;
+}
+
+/* write_iso_tasklet
+ * tasklet scheduled when an isochronous output URB from the Gigaset device
+ * has completed
+ * parameter:
+ *	data	B channel state structure
+ */
+static void write_iso_tasklet(unsigned long data)
+{
+	struct bc_state *bcs;
+	struct bas_bc_state *ubc;
+	struct cardstate *cs;
+	struct isow_urbctx_t *done, *next, *ovfl;
+	struct urb *urb;
+	struct usb_iso_packet_descriptor *ifd;
+	int offset;
+	unsigned long flags;
+	int i;
+	struct sk_buff *skb;
+	int len;
+
+	bcs = (struct bc_state *) data;
+	IFNULLRET(bcs);
+	ubc = bcs->hw.bas;
+	IFNULLRET(ubc);
+	cs = bcs->cs;
+	IFNULLRET(cs);
+
+	/* loop while completed URBs arrive in time */
+	for (;;) {
+		if (unlikely(!atomic_read(&cs->connected))) {
+			warn("%s: disconnected", __func__);
+			return;
+		}
+
+		if (unlikely(!(atomic_read(&ubc->running)))) {
+			dbg(DEBUG_ISO, "%s: not running", __func__);
+			return;
+		}
+
+		/* retrieve completed URBs */
+		spin_lock_irqsave(&ubc->isooutlock, flags);
+		done = ubc->isooutdone;
+		ubc->isooutdone = NULL;
+		ovfl = ubc->isooutovfl;
+		ubc->isooutovfl = NULL;
+		spin_unlock_irqrestore(&ubc->isooutlock, flags);
+		if (ovfl) {
+			err("isochronous write buffer underrun - buy a faster machine :-)");
+			error_hangup(bcs);
+			break;
+		}
+		if (!done)
+			break;
+
+		/* submit free URB if available */
+		spin_lock_irqsave(&ubc->isooutlock, flags);
+		next = ubc->isooutfree;
+		ubc->isooutfree = NULL;
+		spin_unlock_irqrestore(&ubc->isooutlock, flags);
+		if (next) {
+			if (submit_iso_write_urb(next) <= 0) {
+				/* could not submit URB, put it back */
+				spin_lock_irqsave(&ubc->isooutlock, flags);
+				if (ubc->isooutfree == NULL) {
+					ubc->isooutfree = next;
+					next = NULL;
+				}
+				spin_unlock_irqrestore(&ubc->isooutlock, flags);
+				if (next) {
+					/* couldn't put it back */
+					err("losing isochronous write URB");
+					error_hangup(bcs);
+				}
+			}
+		}
+
+		/* process completed URB */
+		urb = done->urb;
+		switch (urb->status) {
+		case 0:				/* normal completion */
+			break;
+		case -EXDEV:			/* inspect individual frames */
+			/* assumptions (for lack of documentation):
+			 * - actual_length bytes of the frame in error are successfully sent
+			 * - all following frames are not sent at all
+			 */
+			dbg(DEBUG_ISO, "%s: URB partially completed", __func__);
+			offset = done->limit;	/* just in case */
+			for (i = 0; i < BAS_NUMFRAMES; i++) {
+				ifd = &urb->iso_frame_desc[i];
+				if (ifd->status ||
+				    ifd->actual_length != ifd->length) {
+					warn("isochronous write: frame %d: %s, "
+					     "only %d of %d bytes sent",
+					     i, get_usb_statmsg(ifd->status),
+					     ifd->actual_length, ifd->length);
+					offset = (ifd->offset +
+					          ifd->actual_length)
+					         % BAS_OUTBUFSIZE;
+					break;
+				}
+			}
+#ifdef CONFIG_GIGASET_DEBUG
+			/* check assumption on remaining frames */
+			for (; i < BAS_NUMFRAMES; i++) {
+				ifd = &urb->iso_frame_desc[i];
+				if (ifd->status != -EINPROGRESS
+				    || ifd->actual_length != 0) {
+					warn("isochronous write: frame %d: %s, "
+					     "%d of %d bytes sent",
+					     i, get_usb_statmsg(ifd->status),
+					     ifd->actual_length, ifd->length);
+					offset = (ifd->offset +
+					          ifd->actual_length)
+					         % BAS_OUTBUFSIZE;
+					break;
+				}
+			}
+#endif
+			break;
+		case -EPIPE:			//FIXME is this the code for "underrun"?
+			err("isochronous write stalled");
+			error_hangup(bcs);
+			break;
+		default:			/* severe trouble */
+			warn("isochronous write: %s",
+			     get_usb_statmsg(urb->status));
+		}
+
+		/* mark the write buffer area covered by this URB as free */
+		if (done->limit >= 0)
+			atomic_set(&ubc->isooutbuf->read, done->limit);
+
+		/* mark URB as free */
+		spin_lock_irqsave(&ubc->isooutlock, flags);
+		next = ubc->isooutfree;
+		ubc->isooutfree = done;
+		spin_unlock_irqrestore(&ubc->isooutlock, flags);
+		if (next) {
+			/* only one URB still active - resubmit one */
+			if (submit_iso_write_urb(next) <= 0) {
+				/* couldn't submit */
+				error_hangup(bcs);
+			}
+		}
+	}
+
+	/* process queued SKBs */
+	while ((skb = skb_dequeue(&bcs->squeue))) {
+		/* copy to output buffer, doing L2 encapsulation */
+		len = skb->len;
+		if (gigaset_isoc_buildframe(bcs, skb->data, len) == -EAGAIN) {
+			/* insufficient buffer space, push back onto queue */
+			skb_queue_head(&bcs->squeue, skb);
+			dbg(DEBUG_ISO, "%s: skb requeued, qlen=%d",
+			    __func__, skb_queue_len(&bcs->squeue));
+			break;
+		}
+		skb_pull(skb, len);
+		gigaset_skb_sent(bcs, skb);
+		dev_kfree_skb_any(skb);
+	}
+}
+
+/* Isochronous Read - Bottom Half */
+/* ============================== */
+
+/* read_iso_tasklet
+ * tasklet scheduled when an isochronous input URB from the Gigaset device
+ * has completed
+ * parameter:
+ *	data	B channel state structure
+ */
+static void read_iso_tasklet(unsigned long data)
+{
+	struct bc_state *bcs;
+	struct bas_bc_state *ubc;
+	struct cardstate *cs;
+	struct urb *urb;
+	char *rcvbuf;
+	unsigned long flags;
+	int totleft, numbytes, offset, frame, rc;
+
+	bcs = (struct bc_state *) data;
+	IFNULLRET(bcs);
+	ubc = bcs->hw.bas;
+	IFNULLRET(ubc);
+	cs = bcs->cs;
+	IFNULLRET(cs);
+
+	/* loop while more completed URBs arrive in the meantime */
+	for (;;) {
+		if (!atomic_read(&cs->connected)) {
+			warn("%s: disconnected", __func__);
+			return;
+		}
+
+		/* retrieve URB */
+		spin_lock_irqsave(&ubc->isoinlock, flags);
+		if (!(urb = ubc->isoindone)) {
+			spin_unlock_irqrestore(&ubc->isoinlock, flags);
+			return;
+		}
+		ubc->isoindone = NULL;
+		if (unlikely(ubc->loststatus != -EINPROGRESS)) {
+			warn("isochronous read overrun, dropped URB with status: %s, %d bytes lost",
+			     get_usb_statmsg(ubc->loststatus), ubc->isoinlost);
+			ubc->loststatus = -EINPROGRESS;
+		}
+		spin_unlock_irqrestore(&ubc->isoinlock, flags);
+
+		if (unlikely(!(atomic_read(&ubc->running)))) {
+			dbg(DEBUG_ISO, "%s: channel not running, dropped URB with status: %s",
+			    __func__, get_usb_statmsg(urb->status));
+			return;
+		}
+
+		switch (urb->status) {
+		case 0:				/* normal completion */
+			break;
+		case -EXDEV:			/* inspect individual frames (we do that anyway) */
+			dbg(DEBUG_ISO, "%s: URB partially completed", __func__);
+			break;
+		case -ENOENT:
+		case -ECONNRESET:
+			dbg(DEBUG_ISO, "%s: URB canceled", __func__);
+			continue;		/* -> skip */
+		case -EINPROGRESS:		/* huh? */
+			dbg(DEBUG_ISO, "%s: URB still pending", __func__);
+			continue;		/* -> skip */
+		case -EPIPE:
+			err("isochronous read stalled");
+			error_hangup(bcs);
+			continue;		/* -> skip */
+		default:			/* severe trouble */
+			warn("isochronous read: %s",
+			     get_usb_statmsg(urb->status));
+			goto error;
+		}
+
+		rcvbuf = urb->transfer_buffer;
+		totleft = urb->actual_length;
+		for (frame = 0; totleft > 0 && frame < BAS_NUMFRAMES; frame++) {
+			if (unlikely(urb->iso_frame_desc[frame].status)) {
+				warn("isochronous read: frame %d: %s",
+				     frame, get_usb_statmsg(urb->iso_frame_desc[frame].status));
+				break;
+			}
+			numbytes = urb->iso_frame_desc[frame].actual_length;
+			if (unlikely(numbytes > BAS_MAXFRAME)) {
+				warn("isochronous read: frame %d: numbytes (%d) > BAS_MAXFRAME",
+				     frame, numbytes);
+				break;
+			}
+			if (unlikely(numbytes > totleft)) {
+				warn("isochronous read: frame %d: numbytes (%d) > totleft (%d)",
+				     frame, numbytes, totleft);
+				break;
+			}
+			offset = urb->iso_frame_desc[frame].offset;
+			if (unlikely(offset + numbytes > BAS_INBUFSIZE)) {
+				warn("isochronous read: frame %d: offset (%d) + numbytes (%d) > BAS_INBUFSIZE",
+				     frame, offset, numbytes);
+				break;
+			}
+			gigaset_isoc_receive(rcvbuf + offset, numbytes, bcs);
+			totleft -= numbytes;
+		}
+		if (unlikely(totleft > 0))
+			warn("isochronous read: %d data bytes missing",
+			     totleft);
+
+	error:
+		/* URB processed, resubmit */
+		for (frame = 0; frame < BAS_NUMFRAMES; frame++) {
+			urb->iso_frame_desc[frame].status = 0;
+			urb->iso_frame_desc[frame].actual_length = 0;
+		}
+		urb->dev = bcs->cs->hw.bas->udev;	/* clobbered by USB subsystem */
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->number_of_packets = BAS_NUMFRAMES;
+		if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) {
+			err("could not resubmit isochronous read URB: %s",
+			    get_usb_statmsg(rc));
+			dump_urb(DEBUG_ISO, "resubmit iso read", urb);
+			error_hangup(bcs);
+		}
+	}
+}
+
+/* Channel Operations */
+/* ================== */
+
+/* req_timeout
+ * timeout routine for control output request
+ * argument:
+ *	B channel control structure
+ */
+static void req_timeout(unsigned long data)
+{
+	struct bc_state *bcs = (struct bc_state *) data;
+	struct bas_cardstate *ucs;
+	int pending;
+	unsigned long flags;
+
+	IFNULLRET(bcs);
+	IFNULLRET(bcs->cs);
+	ucs = bcs->cs->hw.bas;
+	IFNULLRET(ucs);
+
+	check_pending(ucs);
+
+	spin_lock_irqsave(&ucs->lock, flags);
+	pending = ucs->pending;
+	ucs->pending = 0;
+	spin_unlock_irqrestore(&ucs->lock, flags);
+
+	switch (pending) {
+	case 0:					/* no pending request */
+		dbg(DEBUG_USBREQ, "%s: no request pending", __func__);
+		break;
+
+	case HD_OPEN_ATCHANNEL:
+		err("timeout opening AT channel");
+		error_reset(bcs->cs);
+		break;
+
+	case HD_OPEN_B2CHANNEL:
+	case HD_OPEN_B1CHANNEL:
+		err("timeout opening channel %d", bcs->channel + 1);
+		error_hangup(bcs);
+		break;
+
+	case HD_CLOSE_ATCHANNEL:
+		err("timeout closing AT channel");
+		//wake_up_interruptible(cs->initwait);
+		//FIXME need own wait queue?
+		break;
+
+	case HD_CLOSE_B2CHANNEL:
+	case HD_CLOSE_B1CHANNEL:
+		err("timeout closing channel %d", bcs->channel + 1);
+		break;
+
+	default:
+		warn("request 0x%02x timed out, clearing", pending);
+	}
+}
+
+/* write_ctrl_callback
+ * USB completion handler for control pipe output
+ * called by the USB subsystem in interrupt context
+ * parameter:
+ *	urb	USB request block of completed request
+ *		urb->context = hardware specific controller state structure
+ */
+static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct bas_cardstate *ucs;
+	unsigned long flags;
+
+	IFNULLRET(urb);
+	IFNULLRET(urb->context);
+	IFNULLRET(cardstate);
+
+	ucs = (struct bas_cardstate *) urb->context;
+	spin_lock_irqsave(&ucs->lock, flags);
+	if (urb->status && ucs->pending) {
+		err("control request 0x%02x failed: %s",
+		    ucs->pending, get_usb_statmsg(urb->status));
+		del_timer(&ucs->timer_ctrl);
+		ucs->pending = 0;
+	}
+	/* individual handling of specific request types */
+	switch (ucs->pending) {
+	case HD_DEVICE_INIT_ACK:		/* no reply expected */
+		ucs->pending = 0;
+		break;
+	}
+	spin_unlock_irqrestore(&ucs->lock, flags);
+}
+
+/* req_submit
+ * submit a control output request without message buffer to the Gigaset base
+ * and optionally start a timeout
+ * parameters:
+ *	bcs	B channel control structure
+ *	req	control request code (HD_*)
+ *	val	control request parameter value (set to 0 if unused)
+ *	timeout	timeout in seconds (0: no timeout)
+ * return value:
+ *	0 on success
+ *	-EINVAL if a NULL pointer is encountered somewhere
+ *	-EBUSY if another request is pending
+ *	any URB submission error code
+ */
+static int req_submit(struct bc_state *bcs, int req, int val, int timeout)
+{
+	struct bas_cardstate *ucs;
+	int ret;
+	unsigned long flags;
+
+	IFNULLRETVAL(bcs, -EINVAL);
+	IFNULLRETVAL(bcs->cs, -EINVAL);
+	ucs = bcs->cs->hw.bas;
+	IFNULLRETVAL(ucs, -EINVAL);
+	IFNULLRETVAL(ucs->urb_ctrl, -EINVAL);
+
+	dbg(DEBUG_USBREQ, "-------> 0x%02x (%d)", req, val);
+
+	spin_lock_irqsave(&ucs->lock, flags);
+	if (ucs->pending) {
+		spin_unlock_irqrestore(&ucs->lock, flags);
+		err("submission of request 0x%02x failed: request 0x%02x still pending",
+		    req, ucs->pending);
+		return -EBUSY;
+	}
+	if (ucs->urb_ctrl->status == -EINPROGRESS) {
+		spin_unlock_irqrestore(&ucs->lock, flags);
+		err("could not submit request 0x%02x: URB busy", req);
+		return -EBUSY;
+	}
+
+	ucs->dr_ctrl.bRequestType = OUT_VENDOR_REQ;
+	ucs->dr_ctrl.bRequest = req;
+	ucs->dr_ctrl.wValue = cpu_to_le16(val);
+	ucs->dr_ctrl.wIndex = 0;
+	ucs->dr_ctrl.wLength = 0;
+	usb_fill_control_urb(ucs->urb_ctrl, ucs->udev,
+                             usb_sndctrlpipe(ucs->udev, 0),
+                             (unsigned char*) &ucs->dr_ctrl, NULL, 0,
+                             write_ctrl_callback, ucs);
+	if ((ret = usb_submit_urb(ucs->urb_ctrl, SLAB_ATOMIC)) != 0) {
+		err("could not submit request 0x%02x: %s",
+		    req, get_usb_statmsg(ret));
+		spin_unlock_irqrestore(&ucs->lock, flags);
+		return ret;
+	}
+	ucs->pending = req;
+
+	if (timeout > 0) {
+		dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout);
+		ucs->timer_ctrl.expires = jiffies + timeout * HZ / 10;
+		ucs->timer_ctrl.data = (unsigned long) bcs;
+		ucs->timer_ctrl.function = req_timeout;
+		add_timer(&ucs->timer_ctrl);
+	}
+
+	spin_unlock_irqrestore(&ucs->lock, flags);
+	return 0;
+}
+
+/* gigaset_init_bchannel
+ * called by common.c to connect a B channel
+ * initialize isochronous I/O and tell the Gigaset base to open the channel
+ * argument:
+ *	B channel control structure
+ * return value:
+ *	0 on success, error code < 0 on error
+ */
+static int gigaset_init_bchannel(struct bc_state *bcs)
+{
+	int req, ret;
+
+	IFNULLRETVAL(bcs, -EINVAL);
+
+	if ((ret = starturbs(bcs)) < 0) {
+		err("could not start isochronous I/O for channel %d",
+		    bcs->channel + 1);
+		error_hangup(bcs);
+		return ret;
+	}
+
+	req = bcs->channel ? HD_OPEN_B2CHANNEL : HD_OPEN_B1CHANNEL;
+	if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) {
+		err("could not open channel %d: %s",
+		    bcs->channel + 1, get_usb_statmsg(ret));
+		stopurbs(bcs->hw.bas);
+		error_hangup(bcs);
+	}
+	return ret;
+}
+
+/* gigaset_close_bchannel
+ * called by common.c to disconnect a B channel
+ * tell the Gigaset base to close the channel
+ * stopping isochronous I/O and LL notification will be done when the
+ * acknowledgement for the close arrives
+ * argument:
+ *	B channel control structure
+ * return value:
+ *	0 on success, error code < 0 on error
+ */
+static int gigaset_close_bchannel(struct bc_state *bcs)
+{
+	int req, ret;
+
+	IFNULLRETVAL(bcs, -EINVAL);
+
+	if (!(atomic_read(&bcs->cs->hw.bas->basstate) &
+	      (bcs->channel ? BS_B2OPEN : BS_B1OPEN))) {
+		/* channel not running: just signal common.c */
+		gigaset_bchannel_down(bcs);
+		return 0;
+	}
+
+	req = bcs->channel ? HD_CLOSE_B2CHANNEL : HD_CLOSE_B1CHANNEL;
+	if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0)
+		err("could not submit HD_CLOSE_BxCHANNEL request: %s",
+		    get_usb_statmsg(ret));
+	return ret;
+}
+
+/* Device Operations */
+/* ================= */
+
+/* complete_cb
+ * unqueue first command buffer from queue, waking any sleepers
+ * must be called with cs->cmdlock held
+ * parameter:
+ *	cs	controller state structure
+ */
+static void complete_cb(struct cardstate *cs)
+{
+	struct cmdbuf_t *cb;
+
+	IFNULLRET(cs);
+	cb = cs->cmdbuf;
+	IFNULLRET(cb);
+
+	/* unqueue completed buffer */
+	cs->cmdbytes -= cs->curlen;
+	dbg(DEBUG_TRANSCMD | DEBUG_LOCKCMD,
+	    "write_command: sent %u bytes, %u left",
+	    cs->curlen, cs->cmdbytes);
+	if ((cs->cmdbuf = cb->next) != NULL) {
+		cs->cmdbuf->prev = NULL;
+		cs->curlen = cs->cmdbuf->len;
+	} else {
+		cs->lastcmdbuf = NULL;
+		cs->curlen = 0;
+	}
+
+	if (cb->wake_tasklet)
+		tasklet_schedule(cb->wake_tasklet);
+
+	kfree(cb);
+}
+
+static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len);
+
+/* write_command_callback
+ * USB completion handler for AT command transmission
+ * called by the USB subsystem in interrupt context
+ * parameter:
+ *	urb	USB request block of completed request
+ *		urb->context = controller state structure
+ */
+static void write_command_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct cardstate *cs;
+	unsigned long flags;
+	struct bas_cardstate *ucs;
+
+	IFNULLRET(urb);
+	cs = (struct cardstate *) urb->context;
+	IFNULLRET(cs);
+	ucs = cs->hw.bas;
+	IFNULLRET(ucs);
+
+	/* check status */
+	switch (urb->status) {
+	case 0:					/* normal completion */
+		break;
+	case -ENOENT:			/* canceled */
+	case -ECONNRESET:		/* canceled (async) */
+	case -EINPROGRESS:		/* pending */
+		/* ignore silently */
+		dbg(DEBUG_USBREQ,
+		    "%s: %s", __func__, get_usb_statmsg(urb->status));
+		return;
+	default:				/* any failure */
+		if (++ucs->retry_cmd_out > BAS_RETRY) {
+			warn("command write: %s, giving up after %d retries",
+			     get_usb_statmsg(urb->status), ucs->retry_cmd_out);
+			break;
+		}
+		if (cs->cmdbuf == NULL) {
+			warn("command write: %s, cannot retry - cmdbuf gone",
+			     get_usb_statmsg(urb->status));
+			break;
+		}
+		notice("command write: %s, retry %d",
+		       get_usb_statmsg(urb->status), ucs->retry_cmd_out);
+		if (atwrite_submit(cs, cs->cmdbuf->buf, cs->cmdbuf->len) >= 0)
+			/* resubmitted - bypass regular exit block */
+			return;
+		/* command send failed, assume base still waiting */
+		update_basstate(ucs, BS_ATREADY, 0);
+	}
+
+	spin_lock_irqsave(&cs->cmdlock, flags);
+	if (cs->cmdbuf != NULL)
+		complete_cb(cs);
+	spin_unlock_irqrestore(&cs->cmdlock, flags);
+}
+
+/* atrdy_timeout
+ * timeout routine for AT command transmission
+ * argument:
+ *	controller state structure
+ */
+static void atrdy_timeout(unsigned long data)
+{
+	struct cardstate *cs = (struct cardstate *) data;
+	struct bas_cardstate *ucs;
+
+	IFNULLRET(cs);
+	ucs = cs->hw.bas;
+	IFNULLRET(ucs);
+
+	warn("timeout waiting for HD_READY_SEND_ATDATA");
+
+	/* fake the missing signal - what else can I do? */
+	update_basstate(ucs, BS_ATREADY, BS_ATTIMER);
+	start_cbsend(cs);
+}
+
+/* atwrite_submit
+ * submit an HD_WRITE_ATMESSAGE command URB
+ * parameters:
+ *	cs	controller state structure
+ *	buf	buffer containing command to send
+ *	len	length of command to send
+ * return value:
+ *	0 on success
+ *	-EFAULT if a NULL pointer is encountered somewhere
+ *	-EBUSY if another request is pending
+ *	any URB submission error code
+ */
+static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len)
+{
+	struct bas_cardstate *ucs;
+	int ret;
+
+	IFNULLRETVAL(cs, -EFAULT);
+	ucs = cs->hw.bas;
+	IFNULLRETVAL(ucs, -EFAULT);
+	IFNULLRETVAL(ucs->urb_cmd_out, -EFAULT);
+
+	dbg(DEBUG_USBREQ, "-------> HD_WRITE_ATMESSAGE (%d)", len);
+
+	if (ucs->urb_cmd_out->status == -EINPROGRESS) {
+		err("could not submit HD_WRITE_ATMESSAGE: URB busy");
+		return -EBUSY;
+	}
+
+	ucs->dr_cmd_out.bRequestType = OUT_VENDOR_REQ;
+	ucs->dr_cmd_out.bRequest = HD_WRITE_ATMESSAGE;
+	ucs->dr_cmd_out.wValue = 0;
+	ucs->dr_cmd_out.wIndex = 0;
+	ucs->dr_cmd_out.wLength = cpu_to_le16(len);
+	usb_fill_control_urb(ucs->urb_cmd_out, ucs->udev,
+			     usb_sndctrlpipe(ucs->udev, 0),
+			     (unsigned char*) &ucs->dr_cmd_out, buf, len,
+			     write_command_callback, cs);
+
+	if ((ret = usb_submit_urb(ucs->urb_cmd_out, SLAB_ATOMIC)) != 0) {
+		err("could not submit HD_WRITE_ATMESSAGE: %s",
+		    get_usb_statmsg(ret));
+		return ret;
+	}
+
+	/* submitted successfully */
+	update_basstate(ucs, 0, BS_ATREADY);
+
+	/* start timeout if necessary */
+	if (!(atomic_read(&ucs->basstate) & BS_ATTIMER)) {
+		dbg(DEBUG_OUTPUT,
+		    "setting ATREADY timeout of %d/10 secs", ATRDY_TIMEOUT);
+		ucs->timer_atrdy.expires = jiffies + ATRDY_TIMEOUT * HZ / 10;
+		ucs->timer_atrdy.data = (unsigned long) cs;
+		ucs->timer_atrdy.function = atrdy_timeout;
+		add_timer(&ucs->timer_atrdy);
+		update_basstate(ucs, BS_ATTIMER, 0);
+	}
+	return 0;
+}
+
+/* start_cbsend
+ * start transmission of AT command queue if necessary
+ * parameter:
+ *	cs		controller state structure
+ * return value:
+ *	0 on success
+ *	error code < 0 on error
+ */
+static int start_cbsend(struct cardstate *cs)
+{
+	struct cmdbuf_t *cb;
+	struct bas_cardstate *ucs;
+	unsigned long flags;
+	int rc;
+	int retval = 0;
+
+	IFNULLRETVAL(cs, -EFAULT);
+	ucs = cs->hw.bas;
+	IFNULLRETVAL(ucs, -EFAULT);
+
+	/* check if AT channel is open */
+	if (!(atomic_read(&ucs->basstate) & BS_ATOPEN)) {
+		dbg(DEBUG_TRANSCMD | DEBUG_LOCKCMD, "AT channel not open");
+		rc = req_submit(cs->bcs, HD_OPEN_ATCHANNEL, 0, BAS_TIMEOUT);
+		if (rc < 0) {
+			err("could not open AT channel");
+			/* flush command queue */
+			spin_lock_irqsave(&cs->cmdlock, flags);
+			while (cs->cmdbuf != NULL)
+				complete_cb(cs);
+			spin_unlock_irqrestore(&cs->cmdlock, flags);
+		}
+		return rc;
+	}
+
+	/* try to send first command in queue */
+	spin_lock_irqsave(&cs->cmdlock, flags);
+
+	while ((cb = cs->cmdbuf) != NULL &&
+	       atomic_read(&ucs->basstate) & BS_ATREADY) {
+		ucs->retry_cmd_out = 0;
+		rc = atwrite_submit(cs, cb->buf, cb->len);
+		if (unlikely(rc)) {
+			retval = rc;
+			complete_cb(cs);
+		}
+	}
+
+	spin_unlock_irqrestore(&cs->cmdlock, flags);
+	return retval;
+}
+
+/* gigaset_write_cmd
+ * This function is called by the device independent part of the driver
+ * to transmit an AT command string to the Gigaset device.
+ * It encapsulates the device specific method for transmission over the
+ * direct USB connection to the base.
+ * The command string is added to the queue of commands to send, and
+ * USB transmission is started if necessary.
+ * parameters:
+ *	cs		controller state structure
+ *	buf		command string to send
+ *	len		number of bytes to send (max. IF_WRITEBUF)
+ *	wake_tasklet	tasklet to run when transmission is completed (NULL if none)
+ * return value:
+ *	number of bytes queued on success
+ *	error code < 0 on error
+ */
+static int gigaset_write_cmd(struct cardstate *cs,
+                             const unsigned char *buf, int len,
+                             struct tasklet_struct *wake_tasklet)
+{
+	struct cmdbuf_t *cb;
+	unsigned long flags;
+	int status;
+
+	gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
+	                     DEBUG_TRANSCMD : DEBUG_LOCKCMD,
+	                   "CMD Transmit", len, buf, 0);
+
+	if (!atomic_read(&cs->connected)) {
+		err("%s: not connected", __func__);
+		return -ENODEV;
+	}
+
+	if (len <= 0)
+		return 0;			/* nothing to do */
+
+	if (len > IF_WRITEBUF)
+		len = IF_WRITEBUF;
+	if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) {
+		err("%s: out of memory", __func__);
+		return -ENOMEM;
+	}
+
+	memcpy(cb->buf, buf, len);
+	cb->len = len;
+	cb->offset = 0;
+	cb->next = NULL;
+	cb->wake_tasklet = wake_tasklet;
+
+	spin_lock_irqsave(&cs->cmdlock, flags);
+	cb->prev = cs->lastcmdbuf;
+	if (cs->lastcmdbuf)
+		cs->lastcmdbuf->next = cb;
+	else {
+		cs->cmdbuf = cb;
+		cs->curlen = len;
+	}
+	cs->cmdbytes += len;
+	cs->lastcmdbuf = cb;
+	spin_unlock_irqrestore(&cs->cmdlock, flags);
+
+	status = start_cbsend(cs);
+
+	return status < 0 ? status : len;
+}
+
+/* gigaset_write_room
+ * tty_driver.write_room interface routine
+ * return number of characters the driver will accept to be written via gigaset_write_cmd
+ * parameter:
+ *	controller state structure
+ * return value:
+ *	number of characters
+ */
+static int gigaset_write_room(struct cardstate *cs)
+{
+	return IF_WRITEBUF;
+}
+
+/* gigaset_chars_in_buffer
+ * tty_driver.chars_in_buffer interface routine
+ * return number of characters waiting to be sent
+ * parameter:
+ *	controller state structure
+ * return value:
+ *	number of characters
+ */
+static int gigaset_chars_in_buffer(struct cardstate *cs)
+{
+	unsigned long flags;
+	unsigned bytes;
+
+	spin_lock_irqsave(&cs->cmdlock, flags);
+	bytes = cs->cmdbytes;
+	spin_unlock_irqrestore(&cs->cmdlock, flags);
+
+	return bytes;
+}
+
+/* gigaset_brkchars
+ * implementation of ioctl(GIGASET_BRKCHARS)
+ * parameter:
+ *	controller state structure
+ * return value:
+ *	-EINVAL (unimplemented function)
+ */
+static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6])
+{
+	return -EINVAL;
+}
+
+
+/* Device Initialization/Shutdown */
+/* ============================== */
+
+/* Free hardware dependent part of the B channel structure
+ * parameter:
+ *	bcs	B channel structure
+ * return value:
+ *	!=0 on success
+ */
+static int gigaset_freebcshw(struct bc_state *bcs)
+{
+	if (!bcs->hw.bas)
+		return 0;
+
+	if (bcs->hw.bas->isooutbuf)
+		kfree(bcs->hw.bas->isooutbuf);
+	kfree(bcs->hw.bas);
+	bcs->hw.bas = NULL;
+	return 1;
+}
+
+/* Initialize hardware dependent part of the B channel structure
+ * parameter:
+ *	bcs	B channel structure
+ * return value:
+ *	!=0 on success
+ */
+static int gigaset_initbcshw(struct bc_state *bcs)
+{
+	int i;
+	struct bas_bc_state *ubc;
+
+	bcs->hw.bas = ubc = kmalloc(sizeof(struct bas_bc_state), GFP_KERNEL);
+	if (!ubc) {
+		err("could not allocate bas_bc_state");
+		return 0;
+	}
+
+	atomic_set(&ubc->running, 0);
+	atomic_set(&ubc->corrbytes, 0);
+	spin_lock_init(&ubc->isooutlock);
+	for (i = 0; i < BAS_OUTURBS; ++i) {
+		ubc->isoouturbs[i].urb = NULL;
+		ubc->isoouturbs[i].bcs = bcs;
+	}
+	ubc->isooutdone = ubc->isooutfree = ubc->isooutovfl = NULL;
+	ubc->numsub = 0;
+	if (!(ubc->isooutbuf = kmalloc(sizeof(struct isowbuf_t), GFP_KERNEL))) {
+		err("could not allocate isochronous output buffer");
+		kfree(ubc);
+		bcs->hw.bas = NULL;
+		return 0;
+	}
+	tasklet_init(&ubc->sent_tasklet,
+	             &write_iso_tasklet, (unsigned long) bcs);
+
+	spin_lock_init(&ubc->isoinlock);
+	for (i = 0; i < BAS_INURBS; ++i)
+		ubc->isoinurbs[i] = NULL;
+	ubc->isoindone = NULL;
+	ubc->loststatus = -EINPROGRESS;
+	ubc->isoinlost = 0;
+	ubc->seqlen = 0;
+	ubc->inbyte = 0;
+	ubc->inbits = 0;
+	ubc->goodbytes = 0;
+	ubc->alignerrs = 0;
+	ubc->fcserrs = 0;
+	ubc->frameerrs = 0;
+	ubc->giants = 0;
+	ubc->runts = 0;
+	ubc->aborts = 0;
+	ubc->shared0s = 0;
+	ubc->stolen0s = 0;
+	tasklet_init(&ubc->rcvd_tasklet,
+	             &read_iso_tasklet, (unsigned long) bcs);
+	return 1;
+}
+
+static void gigaset_reinitbcshw(struct bc_state *bcs)
+{
+	struct bas_bc_state *ubc = bcs->hw.bas;
+
+	atomic_set(&bcs->hw.bas->running, 0);
+	atomic_set(&bcs->hw.bas->corrbytes, 0);
+	bcs->hw.bas->numsub = 0;
+	spin_lock_init(&ubc->isooutlock);
+	spin_lock_init(&ubc->isoinlock);
+	ubc->loststatus = -EINPROGRESS;
+}
+
+static void gigaset_freecshw(struct cardstate *cs)
+{
+	struct bas_cardstate *ucs = cs->hw.bas;
+
+	del_timer(&ucs->timer_ctrl);
+	del_timer(&ucs->timer_atrdy);
+	del_timer(&ucs->timer_cmd_in);
+
+	kfree(cs->hw.bas);
+}
+
+static int gigaset_initcshw(struct cardstate *cs)
+{
+	struct bas_cardstate *ucs;
+
+	cs->hw.bas = ucs = kmalloc(sizeof *ucs, GFP_KERNEL);
+	if (!ucs)
+		return 0;
+
+	ucs->urb_cmd_in = NULL;
+	ucs->urb_cmd_out = NULL;
+	ucs->rcvbuf = NULL;
+	ucs->rcvbuf_size = 0;
+
+	spin_lock_init(&ucs->lock);
+	ucs->pending = 0;
+
+	atomic_set(&ucs->basstate, 0);
+	init_timer(&ucs->timer_ctrl);
+	init_timer(&ucs->timer_atrdy);
+	init_timer(&ucs->timer_cmd_in);
+
+	return 1;
+}
+
+/* freeurbs
+ * unlink and deallocate all URBs unconditionally
+ * caller must make sure that no commands are still in progress
+ * parameter:
+ *	cs	controller state structure
+ */
+static void freeurbs(struct cardstate *cs)
+{
+	struct bas_cardstate *ucs;
+	struct bas_bc_state *ubc;
+	int i, j;
+
+	IFNULLRET(cs);
+	ucs = cs->hw.bas;
+	IFNULLRET(ucs);
+
+	for (j = 0; j < 2; ++j) {
+		ubc = cs->bcs[j].hw.bas;
+		IFNULLCONT(ubc);
+		for (i = 0; i < BAS_OUTURBS; ++i)
+			if (ubc->isoouturbs[i].urb) {
+				usb_kill_urb(ubc->isoouturbs[i].urb);
+				dbg(DEBUG_INIT,
+				    "%s: isoc output URB %d/%d unlinked",
+				    __func__, j, i);
+				usb_free_urb(ubc->isoouturbs[i].urb);
+				ubc->isoouturbs[i].urb = NULL;
+			}
+		for (i = 0; i < BAS_INURBS; ++i)
+			if (ubc->isoinurbs[i]) {
+				usb_kill_urb(ubc->isoinurbs[i]);
+				dbg(DEBUG_INIT,
+				    "%s: isoc input URB %d/%d unlinked",
+				    __func__, j, i);
+				usb_free_urb(ubc->isoinurbs[i]);
+				ubc->isoinurbs[i] = NULL;
+			}
+	}
+	if (ucs->urb_int_in) {
+		usb_kill_urb(ucs->urb_int_in);
+		dbg(DEBUG_INIT, "%s: interrupt input URB unlinked", __func__);
+		usb_free_urb(ucs->urb_int_in);
+		ucs->urb_int_in = NULL;
+	}
+	if (ucs->urb_cmd_out) {
+		usb_kill_urb(ucs->urb_cmd_out);
+		dbg(DEBUG_INIT, "%s: command output URB unlinked", __func__);
+		usb_free_urb(ucs->urb_cmd_out);
+		ucs->urb_cmd_out = NULL;
+	}
+	if (ucs->urb_cmd_in) {
+		usb_kill_urb(ucs->urb_cmd_in);
+		dbg(DEBUG_INIT, "%s: command input URB unlinked", __func__);
+		usb_free_urb(ucs->urb_cmd_in);
+		ucs->urb_cmd_in = NULL;
+	}
+	if (ucs->urb_ctrl) {
+		usb_kill_urb(ucs->urb_ctrl);
+		dbg(DEBUG_INIT, "%s: control output URB unlinked", __func__);
+		usb_free_urb(ucs->urb_ctrl);
+		ucs->urb_ctrl = NULL;
+	}
+}
+
+/* gigaset_probe
+ * This function is called when a new USB device is connected.
+ * It checks whether the new device is handled by this driver.
+ */
+static int gigaset_probe(struct usb_interface *interface,
+			 const struct usb_device_id *id)
+{
+	struct usb_host_interface *hostif;
+	struct usb_device *udev = interface_to_usbdev(interface);
+	struct cardstate *cs = NULL;
+	struct bas_cardstate *ucs = NULL;
+	struct bas_bc_state *ubc;
+	struct usb_endpoint_descriptor *endpoint;
+	int i, j;
+	int ret;
+
+	IFNULLRETVAL(udev, -ENODEV);
+
+	dbg(DEBUG_ANY,
+	    "%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)",
+	    __func__, le16_to_cpu(udev->descriptor.idVendor),
+	    le16_to_cpu(udev->descriptor.idProduct));
+
+	/* See if the device offered us matches what we can accept */
+	if ((le16_to_cpu(udev->descriptor.idVendor)  != USB_GIGA_VENDOR_ID) ||
+	    (le16_to_cpu(udev->descriptor.idProduct) != USB_GIGA_PRODUCT_ID &&
+	     le16_to_cpu(udev->descriptor.idProduct) != USB_4175_PRODUCT_ID &&
+	     le16_to_cpu(udev->descriptor.idProduct) != USB_SX303_PRODUCT_ID &&
+	     le16_to_cpu(udev->descriptor.idProduct) != USB_SX353_PRODUCT_ID)) {
+		dbg(DEBUG_ANY, "%s: unmatched ID - exiting", __func__);
+		return -ENODEV;
+	}
+
+	/* set required alternate setting */
+	hostif = interface->cur_altsetting;
+	if (hostif->desc.bAlternateSetting != 3) {
+		dbg(DEBUG_ANY,
+		    "%s: wrong alternate setting %d - trying to switch",
+		    __func__, hostif->desc.bAlternateSetting);
+		if (usb_set_interface(udev, hostif->desc.bInterfaceNumber, 3) < 0) {
+			warn("usb_set_interface failed, device %d interface %d altsetting %d",
+			     udev->devnum, hostif->desc.bInterfaceNumber,
+			     hostif->desc.bAlternateSetting);
+			return -ENODEV;
+		}
+		hostif = interface->cur_altsetting;
+	}
+
+	/* Reject application specific interfaces
+	 */
+	if (hostif->desc.bInterfaceClass != 255) {
+		warn("%s: bInterfaceClass == %d",
+		     __func__, hostif->desc.bInterfaceClass);
+		return -ENODEV;
+	}
+
+	info("%s: Device matched (Vendor: 0x%x, Product: 0x%x)",
+	     __func__, le16_to_cpu(udev->descriptor.idVendor),
+	     le16_to_cpu(udev->descriptor.idProduct));
+
+	cs = gigaset_getunassignedcs(driver);
+	if (!cs) {
+		err("%s: no free cardstate", __func__);
+		return -ENODEV;
+	}
+	ucs = cs->hw.bas;
+	ucs->udev = udev;
+	ucs->interface = interface;
+
+	/* allocate URBs:
+	 * - one for the interrupt pipe
+	 * - three for the different uses of the default control pipe
+	 * - three for each isochronous pipe
+	 */
+	ucs->urb_int_in = usb_alloc_urb(0, SLAB_KERNEL);
+	if (!ucs->urb_int_in) {
+		err("No free urbs available");
+		goto error;
+	}
+	ucs->urb_cmd_in = usb_alloc_urb(0, SLAB_KERNEL);
+	if (!ucs->urb_cmd_in) {
+		err("No free urbs available");
+		goto error;
+	}
+	ucs->urb_cmd_out = usb_alloc_urb(0, SLAB_KERNEL);
+	if (!ucs->urb_cmd_out) {
+		err("No free urbs available");
+		goto error;
+	}
+	ucs->urb_ctrl = usb_alloc_urb(0, SLAB_KERNEL);
+	if (!ucs->urb_ctrl) {
+		err("No free urbs available");
+		goto error;
+	}
+
+	for (j = 0; j < 2; ++j) {
+		ubc = cs->bcs[j].hw.bas;
+		for (i = 0; i < BAS_OUTURBS; ++i) {
+			ubc->isoouturbs[i].urb =
+				usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL);
+			if (!ubc->isoouturbs[i].urb) {
+				err("No free urbs available");
+				goto error;
+			}
+		}
+		for (i = 0; i < BAS_INURBS; ++i) {
+			ubc->isoinurbs[i] =
+				usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL);
+			if (!ubc->isoinurbs[i]) {
+				err("No free urbs available");
+				goto error;
+			}
+		}
+	}
+
+	ucs->rcvbuf = NULL;
+	ucs->rcvbuf_size = 0;
+
+	/* Fill the interrupt urb and send it to the core */
+	endpoint = &hostif->endpoint[0].desc;
+	usb_fill_int_urb(ucs->urb_int_in, udev,
+	                 usb_rcvintpipe(udev,
+	                                (endpoint->bEndpointAddress) & 0x0f),
+	                 ucs->int_in_buf, 3, read_int_callback, cs,
+	                 endpoint->bInterval);
+	ret = usb_submit_urb(ucs->urb_int_in, SLAB_KERNEL);
+	if (ret) {
+		err("could not submit interrupt URB: %s", get_usb_statmsg(ret));
+		goto error;
+	}
+
+	/* tell the device that the driver is ready */
+	if ((ret = req_submit(cs->bcs, HD_DEVICE_INIT_ACK, 0, 0)) != 0)
+		goto error;
+
+	/* tell common part that the device is ready */
+	if (startmode == SM_LOCKED)
+		atomic_set(&cs->mstate, MS_LOCKED);
+	if (!gigaset_start(cs))
+		goto error;
+
+	/* save address of controller structure */
+	usb_set_intfdata(interface, cs);
+
+	/* set up device sysfs */
+	gigaset_init_dev_sysfs(interface);
+	return 0;
+
+error:
+	freeurbs(cs);
+	gigaset_unassign(cs);
+	return -ENODEV;
+}
+
+/* gigaset_disconnect
+ * This function is called when the Gigaset base is unplugged.
+ */
+static void gigaset_disconnect(struct usb_interface *interface)
+{
+	struct cardstate *cs;
+	struct bas_cardstate *ucs;
+
+	/* clear device sysfs */
+	gigaset_free_dev_sysfs(interface);
+
+	cs = usb_get_intfdata(interface);
+	usb_set_intfdata(interface, NULL);
+
+	IFNULLRET(cs);
+	ucs = cs->hw.bas;
+	IFNULLRET(ucs);
+
+	info("disconnecting GigaSet base");
+	gigaset_stop(cs);
+	freeurbs(cs);
+	kfree(ucs->rcvbuf);
+	ucs->rcvbuf = NULL;
+	ucs->rcvbuf_size = 0;
+	atomic_set(&ucs->basstate, 0);
+	gigaset_unassign(cs);
+}
+
+static struct gigaset_ops gigops = {
+	gigaset_write_cmd,
+	gigaset_write_room,
+	gigaset_chars_in_buffer,
+	gigaset_brkchars,
+	gigaset_init_bchannel,
+	gigaset_close_bchannel,
+	gigaset_initbcshw,
+	gigaset_freebcshw,
+	gigaset_reinitbcshw,
+	gigaset_initcshw,
+	gigaset_freecshw,
+	gigaset_set_modem_ctrl,
+	gigaset_baud_rate,
+	gigaset_set_line_ctrl,
+	gigaset_isoc_send_skb,
+	gigaset_isoc_input,
+};
+
+/* bas_gigaset_init
+ * This function is called after the kernel module is loaded.
+ */
+static int __init bas_gigaset_init(void)
+{
+	int result;
+
+	/* allocate memory for our driver state and intialize it */
+	if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
+	                               GIGASET_MODULENAME, GIGASET_DEVNAME,
+	                               GIGASET_DEVFSNAME, &gigops,
+	                               THIS_MODULE)) == NULL)
+		goto error;
+
+	/* allocate memory for our device state and intialize it */
+	cardstate = gigaset_initcs(driver, 2, 0, 0, cidmode, GIGASET_MODULENAME);
+	if (!cardstate)
+		goto error;
+
+	/* register this driver with the USB subsystem */
+	result = usb_register(&gigaset_usb_driver);
+	if (result < 0) {
+		err("usb_register failed (error %d)", -result);
+		goto error;
+	}
+
+	info(DRIVER_AUTHOR);
+	info(DRIVER_DESC);
+	return 0;
+
+error:	if (cardstate)
+		gigaset_freecs(cardstate);
+	cardstate = NULL;
+	if (driver)
+		gigaset_freedriver(driver);
+	driver = NULL;
+	return -1;
+}
+
+/* bas_gigaset_exit
+ * This function is called before the kernel module is unloaded.
+ */
+static void __exit bas_gigaset_exit(void)
+{
+	gigaset_blockdriver(driver); /* => probe will fail
+	                              * => no gigaset_start any more
+	                              */
+
+	gigaset_shutdown(cardstate);
+	/* from now on, no isdn callback should be possible */
+
+	if (atomic_read(&cardstate->hw.bas->basstate) & BS_ATOPEN) {
+		dbg(DEBUG_ANY, "closing AT channel");
+		if (req_submit(cardstate->bcs,
+		               HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT) >= 0) {
+			/* successfully submitted - wait for completion */
+			//wait_event_interruptible(cs->initwait, !cs->hw.bas->pending);
+			//FIXME need own wait queue? wakeup?
+		}
+	}
+
+	/* deregister this driver with the USB subsystem */
+	usb_deregister(&gigaset_usb_driver);
+	/* this will call the disconnect-callback */
+	/* from now on, no disconnect/probe callback should be running */
+
+	gigaset_freecs(cardstate);
+	cardstate = NULL;
+	gigaset_freedriver(driver);
+	driver = NULL;
+}
+
+
+module_init(bas_gigaset_init);
+module_exit(bas_gigaset_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff -urN oldtree/drivers/isdn/gigaset/common.c newtree/drivers/isdn/gigaset/common.c
--- oldtree/drivers/isdn/gigaset/common.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/isdn/gigaset/common.c	2006-02-21 15:58:32.866150144 +0000
@@ -0,0 +1,1203 @@
+/*
+ * Stuff used by all variants of the driver
+ *
+ * Copyright (c) 2001 by Stefan Eilers <Eilers.Stefan@epost.de>,
+ *                       Hansjoerg Lipp <hjlipp@web.de>,
+ *                       Tilman Schmidt <tilman@imap.cc>.
+ *
+ * =====================================================================
+ *	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.
+ * =====================================================================
+ * ToDo: ...
+ * =====================================================================
+ * Version: $Id: common.c,v 1.104.4.22 2006/02/04 18:28:16 hjlipp Exp $
+ * =====================================================================
+ */
+
+#include "gigaset.h"
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+/* Version Information */
+#define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Tilman Schmidt <tilman@imap.cc>, Stefan Eilers <Eilers.Stefan@epost.de>"
+#define DRIVER_DESC "Driver for Gigaset 307x"
+
+/* Module parameters */
+int gigaset_debuglevel = DEBUG_DEFAULT;
+EXPORT_SYMBOL_GPL(gigaset_debuglevel);
+module_param_named(debug, gigaset_debuglevel, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(debug, "debug level");
+
+/*======================================================================
+  Prototypes of internal functions
+ */
+
+//static void gigaset_process_response(int resp_code, int parameter,
+//                                     struct at_state_t *at_state,
+//                                     unsigned char ** pstring);
+static struct cardstate *alloc_cs(struct gigaset_driver *drv);
+static void free_cs(struct cardstate *cs);
+static void make_valid(struct cardstate *cs, unsigned mask);
+static void make_invalid(struct cardstate *cs, unsigned mask);
+
+#define VALID_MINOR       0x01
+#define VALID_ID          0x02
+#define ASSIGNED          0x04
+
+/* bitwise byte inversion table */
+__u8 gigaset_invtab[256] = {
+	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+EXPORT_SYMBOL_GPL(gigaset_invtab);
+
+void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
+                        size_t len, const unsigned char *buf, int from_user)
+{
+	unsigned char outbuf[80];
+	unsigned char inbuf[80 - 1];
+	size_t numin;
+	const unsigned char *in;
+	size_t space = sizeof outbuf - 1;
+	unsigned char *out = outbuf;
+
+	if (!from_user) {
+		in = buf;
+		numin = len;
+	} else {
+		numin = len < sizeof inbuf ? len : sizeof inbuf;
+		in = inbuf;
+		if (copy_from_user(inbuf, (const unsigned char __user *) buf, numin)) {
+			strncpy(inbuf, "<FAULT>", sizeof inbuf);
+			numin = sizeof "<FAULT>" - 1;
+		}
+	}
+
+	for (; numin && space; --numin, ++in) {
+		--space;
+		if (*in >= 32)
+			*out++ = *in;
+		else {
+			*out++ = '^';
+			if (space) {
+				*out++ = '@' + *in;
+				--space;
+			}
+		}
+	}
+	*out = 0;
+
+	dbg(level, "%s (%u bytes): %s", msg, (unsigned) len, outbuf);
+}
+EXPORT_SYMBOL_GPL(gigaset_dbg_buffer);
+
+static int setflags(struct cardstate *cs, unsigned flags, unsigned delay)
+{
+	int r;
+
+	r = cs->ops->set_modem_ctrl(cs, cs->control_state, flags);
+	cs->control_state = flags;
+	if (r < 0)
+		return r;
+
+	if (delay) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(delay * HZ / 1000);
+	}
+
+	return 0;
+}
+
+int gigaset_enterconfigmode(struct cardstate *cs)
+{
+	int i, r;
+
+	if (!atomic_read(&cs->connected)) {
+		err("not connected!");
+		return -1;
+	}
+
+	cs->control_state = TIOCM_RTS; //FIXME
+
+	r = setflags(cs, TIOCM_DTR, 200);
+	if (r < 0)
+		goto error;
+	r = setflags(cs, 0, 200);
+	if (r < 0)
+		goto error;
+	for (i = 0; i < 5; ++i) {
+		r = setflags(cs, TIOCM_RTS, 100);
+		if (r < 0)
+			goto error;
+		r = setflags(cs, 0, 100);
+		if (r < 0)
+			goto error;
+	}
+	r = setflags(cs, TIOCM_RTS|TIOCM_DTR, 800);
+	if (r < 0)
+		goto error;
+
+	return 0;
+
+error:
+	err("error %d on setuartbits!\n", -r);
+	cs->control_state = TIOCM_RTS|TIOCM_DTR; // FIXME is this a good value?
+	cs->ops->set_modem_ctrl(cs, 0, TIOCM_RTS|TIOCM_DTR);
+
+	return -1; //r
+}
+
+static int test_timeout(struct at_state_t *at_state)
+{
+	if (!at_state->timer_expires)
+		return 0;
+
+	if (--at_state->timer_expires) {
+		dbg(DEBUG_MCMD, "decreased timer of %p to %lu",
+		    at_state, at_state->timer_expires);
+		return 0;
+	}
+
+	if (!gigaset_add_event(at_state->cs, at_state, EV_TIMEOUT, NULL,
+	                       atomic_read(&at_state->timer_index), NULL)) {
+		//FIXME what should we do?
+	}
+
+	return 1;
+}
+
+static void timer_tick(unsigned long data)
+{
+	struct cardstate *cs = (struct cardstate *) data;
+	unsigned long flags;
+	unsigned channel;
+	struct at_state_t *at_state;
+	int timeout = 0;
+
+	spin_lock_irqsave(&cs->lock, flags);
+
+	for (channel = 0; channel < cs->channels; ++channel)
+		if (test_timeout(&cs->bcs[channel].at_state))
+			timeout = 1;
+
+	if (test_timeout(&cs->at_state))
+		timeout = 1;
+
+	list_for_each_entry(at_state, &cs->temp_at_states, list)
+		if (test_timeout(at_state))
+			timeout = 1;
+
+	if (atomic_read(&cs->running)) {
+		mod_timer(&cs->timer, jiffies + GIG_TICK);
+		if (timeout) {
+			dbg(DEBUG_CMD, "scheduling timeout");
+			tasklet_schedule(&cs->event_tasklet);
+		}
+	}
+
+	spin_unlock_irqrestore(&cs->lock, flags);
+}
+
+int gigaset_get_channel(struct bc_state *bcs)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&bcs->cs->lock, flags);
+	if (bcs->use_count) {
+		dbg(DEBUG_ANY, "could not allocate channel %d", bcs->channel);
+		spin_unlock_irqrestore(&bcs->cs->lock, flags);
+		return 0;
+	}
+	++bcs->use_count;
+	bcs->busy = 1;
+	dbg(DEBUG_ANY, "allocated channel %d", bcs->channel);
+	spin_unlock_irqrestore(&bcs->cs->lock, flags);
+	return 1;
+}
+
+void gigaset_free_channel(struct bc_state *bcs)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&bcs->cs->lock, flags);
+	if (!bcs->busy) {
+		dbg(DEBUG_ANY, "could not free channel %d", bcs->channel);
+		spin_unlock_irqrestore(&bcs->cs->lock, flags);
+		return;
+	}
+	--bcs->use_count;
+	bcs->busy = 0;
+	dbg(DEBUG_ANY, "freed channel %d", bcs->channel);
+	spin_unlock_irqrestore(&bcs->cs->lock, flags);
+}
+
+int gigaset_get_channels(struct cardstate *cs)
+{
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	for (i = 0; i < cs->channels; ++i)
+		if (cs->bcs[i].use_count) {
+			spin_unlock_irqrestore(&cs->lock, flags);
+			dbg(DEBUG_ANY, "could not allocated all channels");
+			return 0;
+		}
+	for (i = 0; i < cs->channels; ++i)
+		++cs->bcs[i].use_count;
+	spin_unlock_irqrestore(&cs->lock, flags);
+
+	dbg(DEBUG_ANY, "allocated all channels");
+
+	return 1;
+}
+
+void gigaset_free_channels(struct cardstate *cs)
+{
+	unsigned long flags;
+	int i;
+
+	dbg(DEBUG_ANY, "unblocking all channels");
+	spin_lock_irqsave(&cs->lock, flags);
+	for (i = 0; i < cs->channels; ++i)
+		--cs->bcs[i].use_count;
+	spin_unlock_irqrestore(&cs->lock, flags);
+}
+
+void gigaset_block_channels(struct cardstate *cs)
+{
+	unsigned long flags;
+	int i;
+
+	dbg(DEBUG_ANY, "blocking all channels");
+	spin_lock_irqsave(&cs->lock, flags);
+	for (i = 0; i < cs->channels; ++i)
+		++cs->bcs[i].use_count;
+	spin_unlock_irqrestore(&cs->lock, flags);
+}
+
+static void clear_events(struct cardstate *cs)
+{
+	struct event_t *ev;
+	unsigned head, tail;
+
+	/* no locking needed (no reader/writer allowed) */
+
+	head = atomic_read(&cs->ev_head);
+	tail = atomic_read(&cs->ev_tail);
+
+	while (tail != head) {
+		ev = cs->events + head;
+		kfree(ev->ptr);
+
+		head = (head + 1) % MAX_EVENTS;
+	}
+
+	atomic_set(&cs->ev_head, tail);
+}
+
+struct event_t *gigaset_add_event(struct cardstate *cs,
+                                  struct at_state_t *at_state, int type,
+                                  void *ptr, int parameter, void *arg)
+{
+	unsigned long flags;
+	unsigned next, tail;
+	struct event_t *event = NULL;
+
+	spin_lock_irqsave(&cs->ev_lock, flags);
+
+	tail = atomic_read(&cs->ev_tail);
+	next = (tail + 1) % MAX_EVENTS;
+	if (unlikely(next == atomic_read(&cs->ev_head)))
+		err("event queue full");
+	else {
+		event = cs->events + tail;
+		event->type = type;
+		event->at_state = at_state;
+		event->cid = -1;
+		event->ptr = ptr;
+		event->arg = arg;
+		event->parameter = parameter;
+		atomic_set(&cs->ev_tail, next);
+	}
+
+	spin_unlock_irqrestore(&cs->ev_lock, flags);
+
+	return event;
+}
+EXPORT_SYMBOL_GPL(gigaset_add_event);
+
+static void free_strings(struct at_state_t *at_state)
+{
+	int i;
+
+	for (i = 0; i < STR_NUM; ++i) {
+		kfree(at_state->str_var[i]);
+		at_state->str_var[i] = NULL;
+	}
+}
+
+static void clear_at_state(struct at_state_t *at_state)
+{
+	free_strings(at_state);
+}
+
+static void dealloc_at_states(struct cardstate *cs)
+{
+	struct at_state_t *cur, *next;
+
+	list_for_each_entry_safe(cur, next, &cs->temp_at_states, list) {
+		list_del(&cur->list);
+		free_strings(cur);
+		kfree(cur);
+	}
+}
+
+static void gigaset_freebcs(struct bc_state *bcs)
+{
+	int i;
+
+	dbg(DEBUG_INIT, "freeing bcs[%d]->hw", bcs->channel);
+	if (!bcs->cs->ops->freebcshw(bcs)) {
+		dbg(DEBUG_INIT, "failed");
+	}
+
+	dbg(DEBUG_INIT, "clearing bcs[%d]->at_state", bcs->channel);
+	clear_at_state(&bcs->at_state);
+	dbg(DEBUG_INIT, "freeing bcs[%d]->skb", bcs->channel);
+
+	if (bcs->skb)
+		dev_kfree_skb(bcs->skb);
+	for (i = 0; i < AT_NUM; ++i) {
+		kfree(bcs->commands[i]);
+		bcs->commands[i] = NULL;
+	}
+}
+
+void gigaset_freecs(struct cardstate *cs)
+{
+	int i;
+	unsigned long flags;
+
+	if (!cs)
+		return;
+
+	down(&cs->sem);
+
+	if (!cs->bcs)
+		goto f_cs;
+	if (!cs->inbuf)
+		goto f_bcs;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	atomic_set(&cs->running, 0);
+	spin_unlock_irqrestore(&cs->lock, flags); /* event handler and timer are not rescheduled below */
+
+	tasklet_kill(&cs->event_tasklet);
+	del_timer_sync(&cs->timer);
+
+	switch (cs->cs_init) {
+	default:
+		gigaset_if_free(cs);
+
+		dbg(DEBUG_INIT, "clearing hw");
+		cs->ops->freecshw(cs);
+
+		//FIXME cmdbuf
+
+		/* fall through */
+	case 2: /* error in initcshw */
+		/* Deregister from LL */
+		make_invalid(cs, VALID_ID);
+		dbg(DEBUG_INIT, "clearing iif");
+		gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD);
+
+		/* fall through */
+	case 1: /* error when regestering to LL */
+		dbg(DEBUG_INIT, "clearing at_state");
+		clear_at_state(&cs->at_state);
+		dealloc_at_states(cs);
+
+		/* fall through */
+	case 0: /* error in one call to initbcs */
+		for (i = 0; i < cs->channels; ++i) {
+			dbg(DEBUG_INIT, "clearing bcs[%d]", i);
+			gigaset_freebcs(cs->bcs + i);
+		}
+
+		clear_events(cs);
+		dbg(DEBUG_INIT, "freeing inbuf");
+		kfree(cs->inbuf);
+	}
+f_bcs:	dbg(DEBUG_INIT, "freeing bcs[]");
+	kfree(cs->bcs);
+f_cs:	dbg(DEBUG_INIT, "freeing cs");
+	up(&cs->sem);
+	free_cs(cs);
+}
+EXPORT_SYMBOL_GPL(gigaset_freecs);
+
+void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs,
+                     struct cardstate *cs, int cid)
+{
+	int i;
+
+	INIT_LIST_HEAD(&at_state->list);
+	at_state->waiting = 0;
+	at_state->getstring = 0;
+	at_state->pending_commands = 0;
+	at_state->timer_expires = 0;
+	at_state->timer_active = 0;
+	atomic_set(&at_state->timer_index, 0);
+	atomic_set(&at_state->seq_index, 0);
+	at_state->ConState = 0;
+	for (i = 0; i < STR_NUM; ++i)
+		at_state->str_var[i] = NULL;
+	at_state->int_var[VAR_ZDLE] = 0;
+	at_state->int_var[VAR_ZCTP] = -1;
+	at_state->int_var[VAR_ZSAU] = ZSAU_NULL;
+	at_state->cs = cs;
+	at_state->bcs = bcs;
+	at_state->cid = cid;
+	if (!cid)
+		at_state->replystruct = cs->tabnocid;
+	else
+		at_state->replystruct = cs->tabcid;
+}
+
+
+static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct bc_state *bcs,
+                               struct cardstate *cs, int inputstate)
+/* inbuf->read must be allocated before! */
+{
+	atomic_set(&inbuf->head, 0);
+	atomic_set(&inbuf->tail, 0);
+	inbuf->cs = cs;
+	inbuf->bcs = bcs; /*base driver: NULL*/
+	inbuf->rcvbuf = NULL; //FIXME
+	inbuf->inputstate = inputstate;
+}
+
+/* Initialize the b-channel structure */
+static struct bc_state *gigaset_initbcs(struct bc_state *bcs,
+                                        struct cardstate *cs, int channel)
+{
+	int i;
+
+	bcs->tx_skb = NULL; //FIXME -> hw part
+
+	skb_queue_head_init(&bcs->squeue);
+
+	bcs->corrupted = 0;
+	bcs->trans_down = 0;
+	bcs->trans_up = 0;
+
+	dbg(DEBUG_INIT, "setting up bcs[%d]->at_state", channel);
+	gigaset_at_init(&bcs->at_state, bcs, cs, -1);
+
+	bcs->rcvbytes = 0;
+
+#ifdef CONFIG_GIGASET_DEBUG
+	bcs->emptycount = 0;
+#endif
+
+	dbg(DEBUG_INIT, "allocating bcs[%d]->skb", channel);
+	bcs->fcs = PPP_INITFCS;
+	bcs->inputstate = 0;
+	if (cs->ignoreframes) {
+		bcs->inputstate |= INS_skip_frame;
+		bcs->skb = NULL;
+	} else if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
+		skb_reserve(bcs->skb, HW_HDR_LEN);
+	else {
+		warn("could not allocate skb");
+		bcs->inputstate |= INS_skip_frame;
+	}
+
+	bcs->channel = channel;
+	bcs->cs = cs;
+
+	bcs->chstate = 0;
+	bcs->use_count = 1;
+	bcs->busy = 0;
+	bcs->ignore = cs->ignoreframes;
+
+	for (i = 0; i < AT_NUM; ++i)
+		bcs->commands[i] = NULL;
+
+	dbg(DEBUG_INIT, "  setting up bcs[%d]->hw", channel);
+	if (cs->ops->initbcshw(bcs))
+		return bcs;
+
+//error:
+	dbg(DEBUG_INIT, "  failed");
+
+	dbg(DEBUG_INIT, "  freeing bcs[%d]->skb", channel);
+	if (bcs->skb)
+		dev_kfree_skb(bcs->skb);
+
+	return NULL;
+}
+
+/* gigaset_initcs
+ * Allocate and initialize cardstate structure for Gigaset driver
+ * Calls hardware dependent gigaset_initcshw() function
+ * Calls B channel initialization function gigaset_initbcs() for each B channel
+ * parameters:
+ *      drv		hardware driver the device belongs to
+ *	channels	number of B channels supported by device
+ *	onechannel	!=0: B channel data and AT commands share one communication channel
+ *			==0: B channels have separate communication channels
+ *	ignoreframes	number of frames to ignore after setting up B channel
+ *	cidmode		!=0: start in CallID mode
+ *	modulename	name of driver module (used for I4L registration)
+ * return value:
+ *	pointer to cardstate structure
+ */
+struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
+				 int onechannel, int ignoreframes,
+				 int cidmode, const char *modulename)
+{
+	struct cardstate *cs = NULL;
+	int i;
+
+	dbg(DEBUG_INIT, "allocating cs");
+	cs = alloc_cs(drv);
+	if (!cs)
+		goto error;
+	dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1);
+	cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);
+	if (!cs->bcs)
+		goto error;
+	dbg(DEBUG_INIT, "allocating inbuf");
+	cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL);
+	if (!cs->inbuf)
+		goto error;
+
+	cs->cs_init = 0;
+	cs->channels = channels;
+	cs->onechannel = onechannel;
+	cs->ignoreframes = ignoreframes;
+	INIT_LIST_HEAD(&cs->temp_at_states);
+	atomic_set(&cs->running, 0);
+	init_timer(&cs->timer); /* clear next & prev */
+	spin_lock_init(&cs->ev_lock);
+	atomic_set(&cs->ev_tail, 0);
+	atomic_set(&cs->ev_head, 0);
+	init_MUTEX_LOCKED(&cs->sem);
+	tasklet_init(&cs->event_tasklet, &gigaset_handle_event, (unsigned long) cs);
+	atomic_set(&cs->commands_pending, 0);
+	cs->cur_at_seq = 0;
+	cs->gotfwver = -1;
+	cs->open_count = 0;
+	cs->tty = NULL;
+	atomic_set(&cs->cidmode, cidmode != 0);
+
+	//if(onechannel) { //FIXME
+		cs->tabnocid = gigaset_tab_nocid_m10x;
+		cs->tabcid = gigaset_tab_cid_m10x;
+	//} else {
+	//	cs->tabnocid = gigaset_tab_nocid;
+	//	cs->tabcid = gigaset_tab_cid;
+	//}
+
+	init_waitqueue_head(&cs->waitqueue);
+	cs->waiting = 0;
+
+	atomic_set(&cs->mode, M_UNKNOWN);
+	atomic_set(&cs->mstate, MS_UNINITIALIZED);
+
+	for (i = 0; i < channels; ++i) {
+		dbg(DEBUG_INIT, "setting up bcs[%d].read", i);
+		if (!gigaset_initbcs(cs->bcs + i, cs, i))
+			goto error;
+	}
+
+	++cs->cs_init;
+
+	dbg(DEBUG_INIT, "setting up at_state");
+	spin_lock_init(&cs->lock);
+	gigaset_at_init(&cs->at_state, NULL, cs, 0);
+	cs->dle = 0;
+	cs->cbytes = 0;
+
+	dbg(DEBUG_INIT, "setting up inbuf");
+	if (onechannel) {			//FIXME distinction necessary?
+		gigaset_inbuf_init(cs->inbuf, cs->bcs, cs, INS_command);
+	} else
+		gigaset_inbuf_init(cs->inbuf, NULL,    cs, INS_command);
+
+	atomic_set(&cs->connected, 0);
+
+	dbg(DEBUG_INIT, "setting up cmdbuf");
+	cs->cmdbuf = cs->lastcmdbuf = NULL;
+	spin_lock_init(&cs->cmdlock);
+	cs->curlen = 0;
+	cs->cmdbytes = 0;
+
+	/*
+	 * Tell the ISDN4Linux subsystem (the LL) that
+	 * a driver for a USB-Device is available !
+	 * If this is done, "isdnctrl" is able to bind a device for this driver even
+	 * if no physical usb-device is currently connected.
+	 * But this device will just be accessable if a physical USB device is connected
+	 * (via "gigaset_probe") .
+	 */
+	dbg(DEBUG_INIT, "setting up iif");
+	if (!gigaset_register_to_LL(cs, modulename)) {
+		err("register_isdn=>error");
+		goto error;
+	}
+
+	make_valid(cs, VALID_ID);
+	++cs->cs_init;
+	dbg(DEBUG_INIT, "setting up hw");
+	if (!cs->ops->initcshw(cs))
+		goto error;
+
+	++cs->cs_init;
+
+	gigaset_if_init(cs);
+
+	atomic_set(&cs->running, 1);
+	cs->timer.data = (unsigned long) cs;
+	cs->timer.function = timer_tick;
+	cs->timer.expires = jiffies + GIG_TICK;
+	/* FIXME: can jiffies increase too much until the timer is added?
+	 * Same problem(?) with mod_timer() in timer_tick(). */
+	add_timer(&cs->timer);
+
+	dbg(DEBUG_INIT, "cs initialized!");
+	up(&cs->sem);
+	return cs;
+
+error:	if (cs)
+		up(&cs->sem);
+	dbg(DEBUG_INIT, "failed");
+	gigaset_freecs(cs);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(gigaset_initcs);
+
+/* ReInitialize the b-channel structure */ /* e.g. called on hangup, disconnect */
+void gigaset_bcs_reinit(struct bc_state *bcs)
+{
+	struct sk_buff *skb;
+	struct cardstate *cs = bcs->cs;
+	unsigned long flags;
+
+	while ((skb = skb_dequeue(&bcs->squeue)) != NULL)
+		dev_kfree_skb(skb);
+
+	spin_lock_irqsave(&cs->lock, flags); //FIXME
+	clear_at_state(&bcs->at_state);
+	bcs->at_state.ConState = 0;
+	bcs->at_state.timer_active = 0;
+	bcs->at_state.timer_expires = 0;
+	bcs->at_state.cid = -1;                     /* No CID defined */
+	spin_unlock_irqrestore(&cs->lock, flags);
+
+	bcs->inputstate = 0;
+
+#ifdef CONFIG_GIGASET_DEBUG
+	bcs->emptycount = 0;
+#endif
+
+	bcs->fcs = PPP_INITFCS;
+	bcs->chstate = 0;
+
+	bcs->ignore = cs->ignoreframes;
+	if (bcs->ignore)
+		bcs->inputstate |= INS_skip_frame;
+
+
+	cs->ops->reinitbcshw(bcs);
+}
+
+static void cleanup_cs(struct cardstate *cs)
+{
+	struct cmdbuf_t *cb, *tcb;
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cs->lock, flags);
+
+	atomic_set(&cs->mode, M_UNKNOWN);
+	atomic_set(&cs->mstate, MS_UNINITIALIZED);
+
+	clear_at_state(&cs->at_state);
+	dealloc_at_states(cs);
+	free_strings(&cs->at_state);
+	gigaset_at_init(&cs->at_state, NULL, cs, 0);
+
+	kfree(cs->inbuf->rcvbuf);
+	cs->inbuf->rcvbuf = NULL;
+	cs->inbuf->inputstate = INS_command;
+	atomic_set(&cs->inbuf->head, 0);
+	atomic_set(&cs->inbuf->tail, 0);
+
+	cb = cs->cmdbuf;
+	while (cb) {
+		tcb = cb;
+		cb = cb->next;
+		kfree(tcb);
+	}
+	cs->cmdbuf = cs->lastcmdbuf = NULL;
+	cs->curlen = 0;
+	cs->cmdbytes = 0;
+	cs->gotfwver = -1;
+	cs->dle = 0;
+	cs->cur_at_seq = 0;
+	atomic_set(&cs->commands_pending, 0);
+	cs->cbytes = 0;
+
+	spin_unlock_irqrestore(&cs->lock, flags);
+
+	for (i = 0; i < cs->channels; ++i) {
+		gigaset_freebcs(cs->bcs + i);
+		if (!gigaset_initbcs(cs->bcs + i, cs, i))
+			break;			//FIXME error handling
+	}
+
+	if (cs->waiting) {
+		cs->cmd_result = -ENODEV;
+		cs->waiting = 0;
+		wake_up_interruptible(&cs->waitqueue);
+	}
+}
+
+
+int gigaset_start(struct cardstate *cs)
+{
+	if (down_interruptible(&cs->sem))
+		return 0;
+	//info("USB device for Gigaset 307x now attached to Dev %d", ucs->minor);
+
+	atomic_set(&cs->connected, 1);
+
+	if (atomic_read(&cs->mstate) != MS_LOCKED) {
+		cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
+		cs->ops->baud_rate(cs, B115200);
+		cs->ops->set_line_ctrl(cs, CS8);
+		cs->control_state = TIOCM_DTR|TIOCM_RTS;
+	} else {
+		//FIXME use some saved values?
+	}
+
+	cs->waiting = 1;
+
+	if (!gigaset_add_event(cs, &cs->at_state, EV_START, NULL, 0, NULL)) {
+		cs->waiting = 0;
+		//FIXME what should we do?
+		goto error;
+	}
+
+	dbg(DEBUG_CMD, "scheduling START");
+	gigaset_schedule_event(cs);
+
+	wait_event(cs->waitqueue, !cs->waiting);
+
+	up(&cs->sem);
+	return 1;
+
+error:
+	up(&cs->sem);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(gigaset_start);
+
+void gigaset_shutdown(struct cardstate *cs)
+{
+	down(&cs->sem);
+
+	cs->waiting = 1;
+
+	if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL)) {
+		//FIXME what should we do?
+		goto exit;
+	}
+
+	dbg(DEBUG_CMD, "scheduling SHUTDOWN");
+	gigaset_schedule_event(cs);
+
+	if (wait_event_interruptible(cs->waitqueue, !cs->waiting)) {
+		warn("aborted");
+		//FIXME
+	}
+
+	if (atomic_read(&cs->mstate) != MS_LOCKED) {
+		//FIXME?
+		//gigaset_baud_rate(cs, B115200);
+		//gigaset_set_line_ctrl(cs, CS8);
+		//gigaset_set_modem_ctrl(cs, TIOCM_DTR|TIOCM_RTS, 0);
+		//cs->control_state = 0;
+	} else {
+		//FIXME use some saved values?
+	}
+
+	cleanup_cs(cs);
+
+exit:
+	up(&cs->sem);
+}
+EXPORT_SYMBOL_GPL(gigaset_shutdown);
+
+void gigaset_stop(struct cardstate *cs)
+{
+	down(&cs->sem);
+
+	atomic_set(&cs->connected, 0);
+
+	cs->waiting = 1;
+
+	if (!gigaset_add_event(cs, &cs->at_state, EV_STOP, NULL, 0, NULL)) {
+		//FIXME what should we do?
+		goto exit;
+	}
+
+	dbg(DEBUG_CMD, "scheduling STOP");
+	gigaset_schedule_event(cs);
+
+	if (wait_event_interruptible(cs->waitqueue, !cs->waiting)) {
+		warn("aborted");
+		//FIXME
+	}
+
+	/* Tell the LL that the device is not available .. */
+	gigaset_i4l_cmd(cs, ISDN_STAT_STOP); // FIXME move to event layer?
+
+	cleanup_cs(cs);
+
+exit:
+	up(&cs->sem);
+}
+EXPORT_SYMBOL_GPL(gigaset_stop);
+
+static LIST_HEAD(drivers);
+static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED;
+
+struct cardstate *gigaset_get_cs_by_id(int id)
+{
+	unsigned long flags;
+	static struct cardstate *ret = NULL;
+	static struct cardstate *cs;
+	struct gigaset_driver *drv;
+	unsigned i;
+
+	spin_lock_irqsave(&driver_lock, flags);
+	list_for_each_entry(drv, &drivers, list) {
+		spin_lock(&drv->lock);
+		for (i = 0; i < drv->minors; ++i) {
+			if (drv->flags[i] & VALID_ID) {
+				cs = drv->cs + i;
+				if (cs->myid == id)
+					ret = cs;
+			}
+			if (ret)
+				break;
+		}
+		spin_unlock(&drv->lock);
+		if (ret)
+			break;
+	}
+	spin_unlock_irqrestore(&driver_lock, flags);
+	return ret;
+}
+
+void gigaset_debugdrivers(void)
+{
+	unsigned long flags;
+	static struct cardstate *cs;
+	struct gigaset_driver *drv;
+	unsigned i;
+
+	spin_lock_irqsave(&driver_lock, flags);
+	list_for_each_entry(drv, &drivers, list) {
+		dbg(DEBUG_DRIVER, "driver %p", drv);
+		spin_lock(&drv->lock);
+		for (i = 0; i < drv->minors; ++i) {
+			dbg(DEBUG_DRIVER, "  index %u", i);
+			dbg(DEBUG_DRIVER, "    flags 0x%02x", drv->flags[i]);
+			cs = drv->cs + i;
+			dbg(DEBUG_DRIVER, "    cardstate %p", cs);
+			dbg(DEBUG_DRIVER, "    minor_index %u", cs->minor_index);
+			dbg(DEBUG_DRIVER, "    driver %p", cs->driver);
+			dbg(DEBUG_DRIVER, "    i4l id %d", cs->myid);
+		}
+		spin_unlock(&drv->lock);
+	}
+	spin_unlock_irqrestore(&driver_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gigaset_debugdrivers);
+
+struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty)
+{
+	if (tty->index < 0 || tty->index >= tty->driver->num)
+		return NULL;
+	return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start);
+}
+
+struct cardstate *gigaset_get_cs_by_minor(unsigned minor)
+{
+	unsigned long flags;
+	static struct cardstate *ret = NULL;
+	struct gigaset_driver *drv;
+	unsigned index;
+
+	spin_lock_irqsave(&driver_lock, flags);
+	list_for_each_entry(drv, &drivers, list) {
+		if (minor < drv->minor || minor >= drv->minor + drv->minors)
+			continue;
+		index = minor - drv->minor;
+		spin_lock(&drv->lock);
+		if (drv->flags[index] & VALID_MINOR)
+			ret = drv->cs + index;
+		spin_unlock(&drv->lock);
+		if (ret)
+			break;
+	}
+	spin_unlock_irqrestore(&driver_lock, flags);
+	return ret;
+}
+
+void gigaset_freedriver(struct gigaset_driver *drv)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&driver_lock, flags);
+	list_del(&drv->list);
+	spin_unlock_irqrestore(&driver_lock, flags);
+
+	gigaset_if_freedriver(drv);
+	module_put(drv->owner);
+
+	kfree(drv->cs);
+	kfree(drv->flags);
+	kfree(drv);
+}
+EXPORT_SYMBOL_GPL(gigaset_freedriver);
+
+/* gigaset_initdriver
+ * Allocate and initialize gigaset_driver structure. Initialize interface.
+ * parameters:
+ *      minor           First minor number
+ *      minors          Number of minors this driver can handle
+ *      procname        Name of the driver (e.g. for /proc/tty/drivers, path in /proc/driver)
+ *      devname         Name of the device files (prefix without minor number)
+ *      devfsname       Devfs name of the device files without %d
+ * return value:
+ *      Pointer to the gigaset_driver structure on success, NULL on failure.
+ */
+struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
+                                          const char *procname,
+                                          const char *devname,
+                                          const char *devfsname,
+                                          const struct gigaset_ops *ops,
+                                          struct module *owner)
+{
+	struct gigaset_driver *drv;
+	unsigned long flags;
+	unsigned i;
+
+	drv = kmalloc(sizeof *drv, GFP_KERNEL);
+	if (!drv)
+		return NULL;
+	if (!try_module_get(owner))
+		return NULL;
+
+	drv->cs = NULL;
+	drv->have_tty = 0;
+	drv->minor = minor;
+	drv->minors = minors;
+	spin_lock_init(&drv->lock);
+	drv->blocked = 0;
+	drv->ops = ops;
+	drv->owner = owner;
+	INIT_LIST_HEAD(&drv->list);
+
+	drv->cs = kmalloc(minors * sizeof *drv->cs, GFP_KERNEL);
+	if (!drv->cs)
+		goto out1;
+	drv->flags = kmalloc(minors * sizeof *drv->flags, GFP_KERNEL);
+	if (!drv->flags)
+		goto out2;
+
+	for (i = 0; i < minors; ++i) {
+		drv->flags[i] = 0;
+		drv->cs[i].driver = drv;
+		drv->cs[i].ops = drv->ops;
+		drv->cs[i].minor_index = i;
+	}
+
+	gigaset_if_initdriver(drv, procname, devname, devfsname);
+
+	spin_lock_irqsave(&driver_lock, flags);
+	list_add(&drv->list, &drivers);
+	spin_unlock_irqrestore(&driver_lock, flags);
+
+	return drv;
+
+out2:
+	kfree(drv->cs);
+out1:
+	kfree(drv);
+	module_put(owner);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(gigaset_initdriver);
+
+static struct cardstate *alloc_cs(struct gigaset_driver *drv)
+{
+	unsigned long flags;
+	unsigned i;
+	static struct cardstate *ret = NULL;
+
+	spin_lock_irqsave(&drv->lock, flags);
+	for (i = 0; i < drv->minors; ++i) {
+		if (!(drv->flags[i] & VALID_MINOR)) {
+			drv->flags[i] = VALID_MINOR;
+			ret = drv->cs + i;
+		}
+		if (ret)
+			break;
+	}
+	spin_unlock_irqrestore(&drv->lock, flags);
+	return ret;
+}
+
+static void free_cs(struct cardstate *cs)
+{
+	unsigned long flags;
+	struct gigaset_driver *drv = cs->driver;
+	spin_lock_irqsave(&drv->lock, flags);
+	drv->flags[cs->minor_index] = 0;
+	spin_unlock_irqrestore(&drv->lock, flags);
+}
+
+static void make_valid(struct cardstate *cs, unsigned mask)
+{
+	unsigned long flags;
+	struct gigaset_driver *drv = cs->driver;
+	spin_lock_irqsave(&drv->lock, flags);
+	drv->flags[cs->minor_index] |= mask;
+	spin_unlock_irqrestore(&drv->lock, flags);
+}
+
+static void make_invalid(struct cardstate *cs, unsigned mask)
+{
+	unsigned long flags;
+	struct gigaset_driver *drv = cs->driver;
+	spin_lock_irqsave(&drv->lock, flags);
+	drv->flags[cs->minor_index] &= ~mask;
+	spin_unlock_irqrestore(&drv->lock, flags);
+}
+
+/* For drivers without fixed assignment device<->cardstate (usb) */
+struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv)
+{
+	unsigned long flags;
+	struct cardstate *cs = NULL;
+	unsigned i;
+
+	spin_lock_irqsave(&drv->lock, flags);
+	if (drv->blocked)
+		goto exit;
+	for (i = 0; i < drv->minors; ++i) {
+		if ((drv->flags[i] & VALID_MINOR) &&
+		    !(drv->flags[i] & ASSIGNED)) {
+			drv->flags[i] |= ASSIGNED;
+			cs = drv->cs + i;
+			break;
+		}
+	}
+exit:
+	spin_unlock_irqrestore(&drv->lock, flags);
+	return cs;
+}
+EXPORT_SYMBOL_GPL(gigaset_getunassignedcs);
+
+void gigaset_unassign(struct cardstate *cs)
+{
+	unsigned long flags;
+	unsigned *minor_flags;
+	struct gigaset_driver *drv;
+
+	if (!cs)
+		return;
+	drv = cs->driver;
+	spin_lock_irqsave(&drv->lock, flags);
+	minor_flags = drv->flags + cs->minor_index;
+	if (*minor_flags & VALID_MINOR)
+		*minor_flags &= ~ASSIGNED;
+	spin_unlock_irqrestore(&drv->lock, flags);
+}
+EXPORT_SYMBOL_GPL(gigaset_unassign);
+
+void gigaset_blockdriver(struct gigaset_driver *drv)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&drv->lock, flags);
+	drv->blocked = 1;
+	spin_unlock_irqrestore(&drv->lock, flags);
+}
+EXPORT_SYMBOL_GPL(gigaset_blockdriver);
+
+static int __init gigaset_init_module(void)
+{
+	/* in accordance with the principle of least astonishment,
+	 * setting the 'debug' parameter to 1 activates a sensible
+	 * set of default debug levels
+	 */
+	if (gigaset_debuglevel == 1)
+		gigaset_debuglevel = DEBUG_DEFAULT;
+
+	info(DRIVER_AUTHOR);
+	info(DRIVER_DESC);
+	return 0;
+}
+
+static void __exit gigaset_exit_module(void)
+{
+}
+
+module_init(gigaset_init_module);
+module_exit(gigaset_exit_module);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+
+MODULE_LICENSE("GPL");
diff -urN oldtree/drivers/isdn/gigaset/ev-layer.c newtree/drivers/isdn/gigaset/ev-layer.c
--- oldtree/drivers/isdn/gigaset/ev-layer.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/isdn/gigaset/ev-layer.c	2006-02-21 15:58:32.883147560 +0000
@@ -0,0 +1,1983 @@
+/*
+ * Stuff used by all variants of the driver
+ *
+ * Copyright (c) 2001 by Stefan Eilers <Eilers.Stefan@epost.de>,
+ *                       Hansjoerg Lipp <hjlipp@web.de>,
+ *                       Tilman Schmidt <tilman@imap.cc>.
+ *
+ * =====================================================================
+ *	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.
+ * =====================================================================
+ * ToDo: ...
+ * =====================================================================
+ * Version: $Id: ev-layer.c,v 1.4.2.18 2006/02/04 18:28:16 hjlipp Exp $
+ * =====================================================================
+ */
+
+#include "gigaset.h"
+
+/* ========================================================== */
+/* bit masks for pending commands */
+#define PC_INIT       0x004
+#define PC_DLE0       0x008
+#define PC_DLE1       0x010
+#define PC_CID        0x080
+#define PC_NOCID      0x100
+#define PC_HUP        0x002
+#define PC_DIAL       0x001
+#define PC_ACCEPT     0x040
+#define PC_SHUTDOWN   0x020
+#define PC_CIDMODE    0x200
+#define PC_UMMODE     0x400
+
+/* types of modem responses */
+#define RT_NOTHING 0
+#define RT_ZSAU    1
+#define RT_RING    2
+#define RT_NUMBER  3
+#define RT_STRING  4
+#define RT_HEX     5
+#define RT_ZCAU    6
+
+/* Possible ASCII responses */
+#define RSP_OK           0
+//#define RSP_BUSY       1
+//#define RSP_CONNECT    2
+#define RSP_ZGCI         3
+#define RSP_RING         4
+#define RSP_ZAOC         5
+#define RSP_ZCSTR        6
+#define RSP_ZCFGT        7
+#define RSP_ZCFG         8
+#define RSP_ZCCR         9
+#define RSP_EMPTY        10
+#define RSP_ZLOG         11
+#define RSP_ZCAU         12
+#define RSP_ZMWI         13
+#define RSP_ZABINFO      14
+#define RSP_ZSMLSTCHG    15
+#define RSP_VAR          100
+#define RSP_ZSAU         (RSP_VAR + VAR_ZSAU)
+#define RSP_ZDLE         (RSP_VAR + VAR_ZDLE)
+#define RSP_ZVLS         (RSP_VAR + VAR_ZVLS)
+#define RSP_ZCTP         (RSP_VAR + VAR_ZCTP)
+#define RSP_STR          (RSP_VAR + VAR_NUM)
+#define RSP_NMBR         (RSP_STR + STR_NMBR)
+#define RSP_ZCPN         (RSP_STR + STR_ZCPN)
+#define RSP_ZCON         (RSP_STR + STR_ZCON)
+#define RSP_ZBC          (RSP_STR + STR_ZBC)
+#define RSP_ZHLC         (RSP_STR + STR_ZHLC)
+#define RSP_ERROR       -1       /* ERROR              */
+#define RSP_WRONG_CID   -2       /* unknown cid in cmd */
+//#define RSP_EMPTY     -3
+#define RSP_UNKNOWN     -4       /* unknown response   */
+#define RSP_FAIL        -5       /* internal error     */
+#define RSP_INVAL       -6       /* invalid response   */
+
+#define RSP_NONE        -19
+#define RSP_STRING      -20
+#define RSP_NULL        -21
+//#define RSP_RETRYFAIL -22
+//#define RSP_RETRY     -23
+//#define RSP_SKIP      -24
+#define RSP_INIT        -27
+#define RSP_ANY         -26
+#define RSP_LAST        -28
+#define RSP_NODEV       -9
+
+/* actions for process_response */
+#define ACT_NOTHING		0
+#define ACT_SETDLE1		1
+#define ACT_SETDLE0		2
+#define ACT_FAILINIT		3
+#define ACT_HUPMODEM		4
+#define ACT_CONFIGMODE		5
+#define ACT_INIT		6
+#define ACT_DLE0		7
+#define ACT_DLE1		8
+#define ACT_FAILDLE0		9
+#define ACT_FAILDLE1		10
+#define ACT_RING		11
+#define ACT_CID			12
+#define ACT_FAILCID		13
+#define ACT_SDOWN		14
+#define ACT_FAILSDOWN		15
+#define ACT_DEBUG		16
+#define ACT_WARN		17
+#define ACT_DIALING		18
+#define ACT_ABORTDIAL		19
+#define ACT_DISCONNECT		20
+#define ACT_CONNECT		21
+#define ACT_REMOTEREJECT	22
+#define ACT_CONNTIMEOUT         23
+#define ACT_REMOTEHUP		24
+#define ACT_ABORTHUP		25
+#define ACT_ICALL		26
+#define ACT_ACCEPTED		27
+#define ACT_ABORTACCEPT		28
+#define ACT_TIMEOUT		29
+#define ACT_GETSTRING		30
+#define ACT_SETVER		31
+#define ACT_FAILVER		32
+#define ACT_GOTVER		33
+#define ACT_TEST		34
+#define ACT_ERROR		35
+#define ACT_ABORTCID		36
+#define ACT_ZCAU		37
+#define ACT_NOTIFY_BC_DOWN      38
+#define ACT_NOTIFY_BC_UP        39
+#define ACT_DIAL                40
+#define ACT_ACCEPT              41
+#define ACT_PROTO_L2            42
+#define ACT_HUP                 43
+#define ACT_IF_LOCK             44
+#define ACT_START               45
+#define ACT_STOP                46
+#define ACT_FAKEDLE0            47
+#define ACT_FAKEHUP             48
+#define ACT_FAKESDOWN           49
+#define ACT_SHUTDOWN            50
+#define ACT_PROC_CIDMODE        51
+#define ACT_UMODESET            52
+#define ACT_FAILUMODE           53
+#define ACT_CMODESET            54
+#define ACT_FAILCMODE           55
+#define ACT_IF_VER              56
+#define ACT_CMD			100
+
+/* at command sequences */
+#define SEQ_NONE      0
+#define SEQ_INIT      100
+#define SEQ_DLE0      200
+#define SEQ_DLE1      250
+#define SEQ_CID       300
+#define SEQ_NOCID     350
+#define SEQ_HUP       400
+#define SEQ_DIAL      600
+#define SEQ_ACCEPT    720
+#define SEQ_SHUTDOWN  500
+#define SEQ_CIDMODE   10
+#define SEQ_UMMODE    11
+
+
+// 100: init, 200: dle0, 250:dle1, 300: get cid (dial), 350: "hup" (no cid), 400: hup, 500: reset, 600: dial, 700: ring
+struct reply_t gigaset_tab_nocid_m10x[]= /* with dle mode */
+{
+	/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */
+
+	/* initialize device, set cid mode if possible */
+	//{RSP_INIT,     -1, -1,100,                900, 0, {ACT_TEST}},
+	//{RSP_ERROR,   900,900, -1,                  0, 0, {ACT_FAILINIT}},
+	//{RSP_OK,      900,900, -1,                100, INIT_TIMEOUT,
+	//                                                  {ACT_TIMEOUT}},
+
+	{RSP_INIT,     -1, -1,SEQ_INIT,           100, INIT_TIMEOUT,
+	                                                  {ACT_TIMEOUT}},                /* wait until device is ready */
+
+	{EV_TIMEOUT,  100,100, -1,                101, 3, {0},             "Z\r"},       /* device in transparent mode? try to initialize it. */
+	{RSP_OK,      101,103, -1,                120, 5, {ACT_GETSTRING}, "+GMR\r"},    /* get version */
+
+	{EV_TIMEOUT,  101,101, -1,                102, 5, {0},             "Z\r"},       /* timeout => try once again. */
+	{RSP_ERROR,   101,101, -1,                102, 5, {0},             "Z\r"},       /* error => try once again. */
+
+	{EV_TIMEOUT,  102,102, -1,                108, 5, {ACT_SETDLE1},   "^SDLE=0\r"}, /* timeout => try again in DLE mode. */
+	{RSP_OK,      108,108, -1,                104,-1},
+	{RSP_ZDLE,    104,104,  0,                103, 5, {0},             "Z\r"},
+	{EV_TIMEOUT,  104,104, -1,                  0, 0, {ACT_FAILINIT}},
+	{RSP_ERROR,   108,108, -1,                  0, 0, {ACT_FAILINIT}},
+
+	{EV_TIMEOUT,  108,108, -1,                105, 2, {ACT_SETDLE0,
+	                                                   ACT_HUPMODEM,
+	                                                   ACT_TIMEOUT}},                /* still timeout => connection in unimodem mode? */
+	{EV_TIMEOUT,  105,105, -1,                103, 5, {0},             "Z\r"},
+
+	{RSP_ERROR,   102,102, -1,                107, 5, {0},             "^GETPRE\r"}, /* ERROR on ATZ => maybe in config mode? */
+	{RSP_OK,      107,107, -1,                  0, 0, {ACT_CONFIGMODE}},
+	{RSP_ERROR,   107,107, -1,                  0, 0, {ACT_FAILINIT}},
+	{EV_TIMEOUT,  107,107, -1,                  0, 0, {ACT_FAILINIT}},
+
+	{RSP_ERROR,   103,103, -1,                  0, 0, {ACT_FAILINIT}},
+	{EV_TIMEOUT,  103,103, -1,                  0, 0, {ACT_FAILINIT}},
+
+	{RSP_STRING,  120,120, -1,                121,-1, {ACT_SETVER}},
+
+	{EV_TIMEOUT,  120,121, -1,                  0, 0, {ACT_FAILVER, ACT_INIT}},
+	{RSP_ERROR,   120,121, -1,                  0, 0, {ACT_FAILVER, ACT_INIT}},
+	{RSP_OK,      121,121, -1,                  0, 0, {ACT_GOTVER,  ACT_INIT}},
+#if 0
+	{EV_TIMEOUT,  120,121, -1,                130, 5, {ACT_FAILVER},   "^SGCI=1\r"},
+	{RSP_ERROR,   120,121, -1,                130, 5, {ACT_FAILVER},   "^SGCI=1\r"},
+	{RSP_OK,      121,121, -1,                130, 5, {ACT_GOTVER},    "^SGCI=1\r"},
+
+	{RSP_OK,      130,130, -1,                  0, 0, {ACT_INIT}},
+	{RSP_ERROR,   130,130, -1,                  0, 0, {ACT_FAILINIT}},
+	{EV_TIMEOUT,  130,130, -1,                  0, 0, {ACT_FAILINIT}},
+#endif
+
+	/* leave dle mode */
+	{RSP_INIT,      0,  0,SEQ_DLE0,           201, 5, {0},             "^SDLE=0\r"},
+	{RSP_OK,      201,201, -1,                202,-1},
+	//{RSP_ZDLE,    202,202,  0,                202, 0, {ACT_ERROR}},//DELETE
+	{RSP_ZDLE,    202,202,  0,                  0, 0, {ACT_DLE0}},
+	{RSP_NODEV,   200,249, -1,                  0, 0, {ACT_FAKEDLE0}},
+	{RSP_ERROR,   200,249, -1,                  0, 0, {ACT_FAILDLE0}},
+	{EV_TIMEOUT,  200,249, -1,                  0, 0, {ACT_FAILDLE0}},
+
+	/* enter dle mode */
+	{RSP_INIT,      0,  0,SEQ_DLE1,           251, 5, {0},             "^SDLE=1\r"},
+	{RSP_OK,      251,251, -1,                252,-1},
+	{RSP_ZDLE,    252,252,  1,                  0, 0, {ACT_DLE1}},
+	{RSP_ERROR,   250,299, -1,                  0, 0, {ACT_FAILDLE1}},
+	{EV_TIMEOUT,  250,299, -1,                  0, 0, {ACT_FAILDLE1}},
+
+	/* incoming call */
+	{RSP_RING,     -1, -1, -1,                 -1,-1, {ACT_RING}},
+
+	/* get cid */
+	//{RSP_INIT,      0,  0,300,                901, 0, {ACT_TEST}},
+	//{RSP_ERROR,   901,901, -1,                  0, 0, {ACT_FAILCID}},
+	//{RSP_OK,      901,901, -1,                301, 5, {0},             "^SGCI?\r"},
+
+	{RSP_INIT,      0,  0,SEQ_CID,            301, 5, {0},             "^SGCI?\r"},
+	{RSP_OK,      301,301, -1,                302,-1},
+	{RSP_ZGCI,    302,302, -1,                  0, 0, {ACT_CID}},
+	{RSP_ERROR,   301,349, -1,                  0, 0, {ACT_FAILCID}},
+	{EV_TIMEOUT,  301,349, -1,                  0, 0, {ACT_FAILCID}},
+
+	/* enter cid mode */
+	{RSP_INIT,      0,  0,SEQ_CIDMODE,        150, 5, {0},             "^SGCI=1\r"},
+	{RSP_OK,      150,150, -1,                  0, 0, {ACT_CMODESET}},
+	{RSP_ERROR,   150,150, -1,                  0, 0, {ACT_FAILCMODE}},
+	{EV_TIMEOUT,  150,150, -1,                  0, 0, {ACT_FAILCMODE}},
+
+	/* leave cid mode */
+	//{RSP_INIT,      0,  0,SEQ_UMMODE,         160, 5, {0},             "^SGCI=0\r"},
+	{RSP_INIT,      0,  0,SEQ_UMMODE,         160, 5, {0},             "Z\r"},
+	{RSP_OK,      160,160, -1,                  0, 0, {ACT_UMODESET}},
+	{RSP_ERROR,   160,160, -1,                  0, 0, {ACT_FAILUMODE}},
+	{EV_TIMEOUT,  160,160, -1,                  0, 0, {ACT_FAILUMODE}},
+
+	/* abort getting cid */
+	{RSP_INIT,      0,  0,SEQ_NOCID,            0, 0, {ACT_ABORTCID}},
+
+	/* reset */
+#if 0
+	{RSP_INIT,      0,  0,SEQ_SHUTDOWN,       503, 5, {0},             "^SGCI=0\r"},
+	{RSP_OK,      503,503, -1,                504, 5, {0},             "Z\r"},
+#endif
+	{RSP_INIT,      0,  0,SEQ_SHUTDOWN,       504, 5, {0},             "Z\r"},
+	{RSP_OK,      504,504, -1,                  0, 0, {ACT_SDOWN}},
+	{RSP_ERROR,   501,599, -1,                  0, 0, {ACT_FAILSDOWN}},
+	{EV_TIMEOUT,  501,599, -1,                  0, 0, {ACT_FAILSDOWN}},
+	{RSP_NODEV,   501,599, -1,                  0, 0, {ACT_FAKESDOWN}},
+
+	{EV_PROC_CIDMODE,-1, -1, -1,               -1,-1, {ACT_PROC_CIDMODE}}, //FIXME
+	{EV_IF_LOCK,   -1, -1, -1,                 -1,-1, {ACT_IF_LOCK}}, //FIXME
+	{EV_IF_VER,    -1, -1, -1,                 -1,-1, {ACT_IF_VER}}, //FIXME
+	{EV_START,     -1, -1, -1,                 -1,-1, {ACT_START}}, //FIXME
+	{EV_STOP,      -1, -1, -1,                 -1,-1, {ACT_STOP}}, //FIXME
+	{EV_SHUTDOWN,  -1, -1, -1,                 -1,-1, {ACT_SHUTDOWN}}, //FIXME
+
+	/* misc. */
+	{RSP_EMPTY,    -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+	{RSP_ZCFGT,    -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+	{RSP_ZCFG,     -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+	{RSP_ZLOG,     -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+	{RSP_ZMWI,     -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+	{RSP_ZABINFO,  -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+	{RSP_ZSMLSTCHG,-1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+
+	{RSP_ZCAU,     -1, -1, -1,                 -1,-1, {ACT_ZCAU}},
+	{RSP_NONE,     -1, -1, -1,                 -1,-1, {ACT_DEBUG}},
+	{RSP_ANY,      -1, -1, -1,                 -1,-1, {ACT_WARN}},
+	{RSP_LAST}
+};
+
+// 600: start dialing, 650: dial in progress, 800: connection is up, 700: ring, 400: hup, 750: accepted icall
+struct reply_t gigaset_tab_cid_m10x[] = /* for M10x */
+{
+	/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */
+
+	/* dial */
+	{EV_DIAL,      -1, -1, -1,                 -1,-1, {ACT_DIAL}}, //FIXME
+	{RSP_INIT,      0,  0,SEQ_DIAL,           601, 5, {ACT_CMD+AT_BC}},
+	{RSP_OK,      601,601, -1,                602, 5, {ACT_CMD+AT_HLC}},
+	{RSP_NULL,    602,602, -1,                603, 5, {ACT_CMD+AT_PROTO}},
+	{RSP_OK,      602,602, -1,                603, 5, {ACT_CMD+AT_PROTO}},
+	{RSP_OK,      603,603, -1,                604, 5, {ACT_CMD+AT_TYPE}},
+	{RSP_OK,      604,604, -1,                605, 5, {ACT_CMD+AT_MSN}},
+	{RSP_OK,      605,605, -1,                606, 5, {ACT_CMD+AT_ISO}},
+	{RSP_NULL,    605,605, -1,                606, 5, {ACT_CMD+AT_ISO}},
+	{RSP_OK,      606,606, -1,                607, 5, {0},             "+VLS=17\r"}, /* set "Endgeraetemodus" */
+	{RSP_OK,      607,607, -1,                608,-1},
+	//{RSP_ZSAU,    608,608,ZSAU_PROCEEDING,    608, 0, {ACT_ERROR}},//DELETE
+	{RSP_ZSAU,    608,608,ZSAU_PROCEEDING,    609, 5, {ACT_CMD+AT_DIAL}},
+	{RSP_OK,      609,609, -1,                650, 0, {ACT_DIALING}},
+
+	{RSP_ZVLS,    608,608, 17,                 -1,-1, {ACT_DEBUG}},
+	{RSP_ZCTP,    609,609, -1,                 -1,-1, {ACT_DEBUG}},
+	{RSP_ZCPN,    609,609, -1,                 -1,-1, {ACT_DEBUG}},
+	{RSP_ERROR,   601,609, -1,                  0, 0, {ACT_ABORTDIAL}},
+	{EV_TIMEOUT,  601,609, -1,                  0, 0, {ACT_ABORTDIAL}},
+
+	/* dialing */
+	{RSP_ZCTP,    650,650, -1,                 -1,-1, {ACT_DEBUG}},
+	{RSP_ZCPN,    650,650, -1,                 -1,-1, {ACT_DEBUG}},
+	{RSP_ZSAU,    650,650,ZSAU_CALL_DELIVERED, -1,-1, {ACT_DEBUG}}, /* some devices don't send this */
+
+	/* connection established  */
+	{RSP_ZSAU,    650,650,ZSAU_ACTIVE,        800,-1, {ACT_CONNECT}}, //FIXME -> DLE1
+	{RSP_ZSAU,    750,750,ZSAU_ACTIVE,        800,-1, {ACT_CONNECT}}, //FIXME -> DLE1
+
+	{EV_BC_OPEN,  800,800, -1,                800,-1, {ACT_NOTIFY_BC_UP}}, //FIXME new constate + timeout
+
+	/* remote hangup */
+	{RSP_ZSAU,    650,650,ZSAU_DISCONNECT_IND,  0, 0, {ACT_REMOTEREJECT}},
+	{RSP_ZSAU,    750,750,ZSAU_DISCONNECT_IND,  0, 0, {ACT_REMOTEHUP}},
+	{RSP_ZSAU,    800,800,ZSAU_DISCONNECT_IND,  0, 0, {ACT_REMOTEHUP}},
+
+	/* hangup */
+	{EV_HUP,       -1, -1, -1,                 -1,-1, {ACT_HUP}}, //FIXME
+	{RSP_INIT,     -1, -1,SEQ_HUP,            401, 5, {0},             "+VLS=0\r"}, /* hang up */ //-1,-1?
+	{RSP_OK,      401,401, -1,                402, 5},
+	{RSP_ZVLS,    402,402,  0,                403, 5},
+	{RSP_ZSAU,    403,403,ZSAU_DISCONNECT_REQ, -1,-1, {ACT_DEBUG}}, /* if not remote hup */
+	//{RSP_ZSAU,    403,403,ZSAU_NULL,          401, 0, {ACT_ERROR}}, //DELETE//FIXME -> DLE0 // should we do this _before_ hanging up for base driver?
+	{RSP_ZSAU,    403,403,ZSAU_NULL,            0, 0, {ACT_DISCONNECT}}, //FIXME -> DLE0 // should we do this _before_ hanging up for base driver?
+	{RSP_NODEV,   401,403, -1,                  0, 0, {ACT_FAKEHUP}}, //FIXME -> DLE0 // should we do this _before_ hanging up for base driver?
+	{RSP_ERROR,   401,401, -1,                  0, 0, {ACT_ABORTHUP}},
+	{EV_TIMEOUT,  401,403, -1,                  0, 0, {ACT_ABORTHUP}},
+
+	{EV_BC_CLOSED,  0,  0, -1,                  0,-1, {ACT_NOTIFY_BC_DOWN}}, //FIXME new constate + timeout
+
+	/* ring */
+	{RSP_ZBC,     700,700, -1,                 -1,-1, {0}},
+	{RSP_ZHLC,    700,700, -1,                 -1,-1, {0}},
+	{RSP_NMBR,    700,700, -1,                 -1,-1, {0}},
+	{RSP_ZCPN,    700,700, -1,                 -1,-1, {0}},
+	{RSP_ZCTP,    700,700, -1,                 -1,-1, {0}},
+	{EV_TIMEOUT,  700,700, -1,               720,720, {ACT_ICALL}},
+	{EV_BC_CLOSED,720,720, -1,                  0,-1, {ACT_NOTIFY_BC_DOWN}},
+
+	/*accept icall*/
+	{EV_ACCEPT,    -1, -1, -1,                 -1,-1, {ACT_ACCEPT}}, //FIXME
+	{RSP_INIT,    720,720,SEQ_ACCEPT,         721, 5, {ACT_CMD+AT_PROTO}},
+	{RSP_OK,      721,721, -1,                722, 5, {ACT_CMD+AT_ISO}},
+	{RSP_OK,      722,722, -1,                723, 5, {0},             "+VLS=17\r"}, /* set "Endgeraetemodus" */
+	{RSP_OK,      723,723, -1,                724, 5, {0}},
+	{RSP_ZVLS,    724,724, 17,                750,50, {ACT_ACCEPTED}},
+	{RSP_ERROR,   721,729, -1,                  0, 0, {ACT_ABORTACCEPT}},
+	{EV_TIMEOUT,  721,729, -1,                  0, 0, {ACT_ABORTACCEPT}},
+	{RSP_ZSAU,    700,729,ZSAU_NULL,            0, 0, {ACT_ABORTACCEPT}},
+	{RSP_ZSAU,    700,729,ZSAU_ACTIVE,          0, 0, {ACT_ABORTACCEPT}},
+	{RSP_ZSAU,    700,729,ZSAU_DISCONNECT_IND,  0, 0, {ACT_ABORTACCEPT}},
+
+	{EV_TIMEOUT,  750,750, -1,                  0, 0, {ACT_CONNTIMEOUT}},
+
+	/* misc. */
+	{EV_PROTO_L2,  -1, -1, -1,                 -1,-1, {ACT_PROTO_L2}}, //FIXME
+
+	{RSP_ZCON,     -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+	{RSP_ZCCR,     -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+	{RSP_ZAOC,     -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+	{RSP_ZCSTR,    -1, -1, -1,                 -1,-1, {ACT_DEBUG}}, //FIXME
+
+	{RSP_ZCAU,     -1, -1, -1,                 -1,-1, {ACT_ZCAU}},
+	{RSP_NONE,     -1, -1, -1,                 -1,-1, {ACT_DEBUG}},
+	{RSP_ANY,      -1, -1, -1,                 -1,-1, {ACT_WARN}},
+	{RSP_LAST}
+};
+
+
+#if 0
+static struct reply_t tab_nocid[]= /* no dle mode */ //FIXME aenderungen uebernehmen
+{
+	/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */
+
+	{RSP_ANY,      -1, -1, -1,                 -1,-1, ACT_WARN,         NULL},
+	{RSP_LAST,0,0,0,0,0,0}
+};
+
+static struct reply_t tab_cid[] = /* no dle mode */ //FIXME aenderungen uebernehmen
+{
+	/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */
+
+	{RSP_ANY,      -1, -1, -1,                 -1,-1, ACT_WARN,         NULL},
+	{RSP_LAST,0,0,0,0,0,0}
+};
+#endif
+
+static struct resp_type_t resp_type[]=
+{
+	/*{"",          RSP_EMPTY,  RT_NOTHING},*/
+	{"OK",        RSP_OK,     RT_NOTHING},
+	{"ERROR",     RSP_ERROR,  RT_NOTHING},
+	{"ZSAU",      RSP_ZSAU,   RT_ZSAU},
+	{"ZCAU",      RSP_ZCAU,   RT_ZCAU},
+	{"RING",      RSP_RING,   RT_RING},
+	{"ZGCI",      RSP_ZGCI,   RT_NUMBER},
+	{"ZVLS",      RSP_ZVLS,   RT_NUMBER},
+	{"ZCTP",      RSP_ZCTP,   RT_NUMBER},
+	{"ZDLE",      RSP_ZDLE,   RT_NUMBER},
+	{"ZCFGT",     RSP_ZCFGT,  RT_NUMBER},
+	{"ZCCR",      RSP_ZCCR,   RT_NUMBER},
+	{"ZMWI",      RSP_ZMWI,   RT_NUMBER},
+	{"ZHLC",      RSP_ZHLC,   RT_STRING},
+	{"ZBC",       RSP_ZBC,    RT_STRING},
+	{"NMBR",      RSP_NMBR,   RT_STRING},
+	{"ZCPN",      RSP_ZCPN,   RT_STRING},
+	{"ZCON",      RSP_ZCON,   RT_STRING},
+	{"ZAOC",      RSP_ZAOC,   RT_STRING},
+	{"ZCSTR",     RSP_ZCSTR,  RT_STRING},
+	{"ZCFG",      RSP_ZCFG,   RT_HEX},
+	{"ZLOG",      RSP_ZLOG,   RT_NOTHING},
+	{"ZABINFO",   RSP_ZABINFO, RT_NOTHING},
+	{"ZSMLSTCHG", RSP_ZSMLSTCHG, RT_NOTHING},
+	{NULL,0,0}
+};
+
+/*
+ * Get integer from char-pointer
+ */
+static int isdn_getnum(char *p)
+{
+	int v = -1;
+
+	IFNULLRETVAL(p, -1);
+
+	dbg(DEBUG_TRANSCMD, "string: %s", p);
+
+	while (*p >= '0' && *p <= '9')
+		v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p++) - '0');
+	if (*p)
+		v = -1; /* invalid Character */
+	return v;
+}
+
+/*
+ * Get integer from char-pointer
+ */
+static int isdn_gethex(char *p)
+{
+	int v = 0;
+	int c;
+
+	IFNULLRETVAL(p, -1);
+
+	dbg(DEBUG_TRANSCMD, "string: %s", p);
+
+	if (!*p)
+		return -1;
+
+	do {
+		if (v > (INT_MAX - 15) / 16)
+			return -1;
+		c = *p;
+		if (c >= '0' && c <= '9')
+			c -= '0';
+		else if (c >= 'a' && c <= 'f')
+			c -= 'a' - 10;
+		else if (c >= 'A' && c <= 'F')
+			c -= 'A' - 10;
+		else
+			return -1;
+		v = v * 16 + c;
+	} while (*++p);
+
+	return v;
+}
+
+static inline void new_index(atomic_t *index, int max)
+{
+	if (atomic_read(index) == max)	//FIXME race?
+		atomic_set(index, 0);
+	else
+		atomic_inc(index);
+}
+
+/* retrieve CID from parsed response
+ * returns 0 if no CID, -1 if invalid CID, or CID value 1..65535
+ */
+static int cid_of_response(char *s)
+{
+	int cid;
+
+	if (s[-1] != ';')
+		return 0;	/* no CID separator */
+	cid = isdn_getnum(s);
+	if (cid < 0)
+		return 0;	/* CID not numeric */
+	if (cid < 1 || cid > 65535)
+		return -1;	/* CID out of range */
+	return cid;
+	//FIXME is ;<digit>+ at end of non-CID response really impossible?
+}
+
+/* This function will be called via task queue from the callback handler.
+ * We received a modem response and have to handle it..
+ */
+void gigaset_handle_modem_response(struct cardstate *cs)
+{
+	unsigned char *argv[MAX_REC_PARAMS + 1];
+	int params;
+	int i, j;
+	struct resp_type_t *rt;
+	int curarg;
+	unsigned long flags;
+	unsigned next, tail, head;
+	struct event_t *event;
+	int resp_code;
+	int param_type;
+	int abort;
+	size_t len;
+	int cid;
+	int rawstring;
+
+	IFNULLRET(cs);
+
+	len = cs->cbytes;
+	if (!len) {
+		/* ignore additional LFs/CRs (M10x config mode or cx100) */
+		dbg(DEBUG_MCMD, "skipped EOL [%02X]", cs->respdata[len]);
+		return;
+	}
+	cs->respdata[len] = 0;
+	dbg(DEBUG_TRANSCMD, "raw string: '%s'", cs->respdata);
+	argv[0] = cs->respdata;
+	params = 1;
+	if (cs->at_state.getstring) {
+		/* getstring only allowed without cid at the moment */
+		cs->at_state.getstring = 0;
+		rawstring = 1;
+		cid = 0;
+	} else {
+		/* parse line */
+		for (i = 0; i < len; i++)
+			switch (cs->respdata[i]) {
+			case ';':
+			case ',':
+			case '=':
+				if (params > MAX_REC_PARAMS) {
+					warn("too many parameters in response");
+					/* need last parameter (might be CID) */
+					params--;
+				}
+				argv[params++] = cs->respdata + i + 1;
+			}
+
+		rawstring = 0;
+		cid = params > 1 ? cid_of_response(argv[params-1]) : 0;
+		if (cid < 0) {
+			gigaset_add_event(cs, &cs->at_state, RSP_INVAL,
+			                  NULL, 0, NULL);
+			return;
+		}
+
+		for (j = 1; j < params; ++j)
+			argv[j][-1] = 0;
+
+		dbg(DEBUG_TRANSCMD, "CMD received: %s", argv[0]);
+		if (cid) {
+			--params;
+			dbg(DEBUG_TRANSCMD, "CID: %s", argv[params]);
+		}
+		dbg(DEBUG_TRANSCMD, "available params: %d", params - 1);
+		for (j = 1; j < params; j++)
+			dbg(DEBUG_TRANSCMD, "param %d: %s", j, argv[j]);
+	}
+
+	spin_lock_irqsave(&cs->ev_lock, flags);
+	head = atomic_read(&cs->ev_head);
+	tail = atomic_read(&cs->ev_tail);
+
+	abort = 1;
+	curarg = 0;
+	while (curarg < params) {
+		next = (tail + 1) % MAX_EVENTS;
+		if (unlikely(next == head)) {
+			err("event queue full");
+			break;
+		}
+
+		event = cs->events + tail;
+		event->at_state = NULL;
+		event->cid = cid;
+		event->ptr = NULL;
+		event->arg = NULL;
+		tail = next;
+
+		if (rawstring) {
+			resp_code = RSP_STRING;
+			param_type = RT_STRING;
+		} else {
+			for (rt = resp_type; rt->response; ++rt)
+				if (!strcmp(argv[curarg], rt->response))
+					break;
+
+			if (!rt->response) {
+				event->type = RSP_UNKNOWN;
+				warn("unknown modem response: %s",
+				     argv[curarg]);
+				break;
+			}
+
+			resp_code = rt->resp_code;
+			param_type = rt->type;
+			++curarg;
+		}
+
+		event->type = resp_code;
+
+		switch (param_type) {
+		case RT_NOTHING:
+			break;
+		case RT_RING:
+			if (!cid) {
+				err("received RING without CID!");
+				event->type = RSP_INVAL;
+				abort = 1;
+			} else {
+				event->cid = 0;
+				event->parameter = cid;
+				abort = 0;
+			}
+			break;
+		case RT_ZSAU:
+			if (curarg >= params) {
+				event->parameter = ZSAU_NONE;
+				break;
+			}
+			if (!strcmp(argv[curarg], "OUTGOING_CALL_PROCEEDING"))
+				event->parameter = ZSAU_OUTGOING_CALL_PROCEEDING;
+			else if (!strcmp(argv[curarg], "CALL_DELIVERED"))
+				event->parameter = ZSAU_CALL_DELIVERED;
+			else if (!strcmp(argv[curarg], "ACTIVE"))
+				event->parameter = ZSAU_ACTIVE;
+			else if (!strcmp(argv[curarg], "DISCONNECT_IND"))
+				event->parameter = ZSAU_DISCONNECT_IND;
+			else if (!strcmp(argv[curarg], "NULL"))
+				event->parameter = ZSAU_NULL;
+			else if (!strcmp(argv[curarg], "DISCONNECT_REQ"))
+				event->parameter = ZSAU_DISCONNECT_REQ;
+			else {
+				event->parameter = ZSAU_UNKNOWN;
+				warn("%s: unknown parameter %s after ZSAU",
+				     __func__, argv[curarg]);
+			}
+			++curarg;
+			break;
+		case RT_STRING:
+			if (curarg < params) {
+				len = strlen(argv[curarg]) + 1;
+				event->ptr = kmalloc(len, GFP_ATOMIC);
+				if (event->ptr)
+					memcpy(event->ptr, argv[curarg], len);
+				else
+					err("no memory for string!");
+				++curarg;
+			}
+#ifdef CONFIG_GIGASET_DEBUG
+			if (!event->ptr)
+				dbg(DEBUG_CMD, "string==NULL");
+			else
+				dbg(DEBUG_CMD,
+				    "string==%s", (char *) event->ptr);
+#endif
+			break;
+		case RT_ZCAU:
+			event->parameter = -1;
+			if (curarg + 1 < params) {
+				i = isdn_gethex(argv[curarg]);
+				j = isdn_gethex(argv[curarg + 1]);
+				if (i >= 0 && i < 256 && j >= 0 && j < 256)
+					event->parameter = (unsigned) i << 8
+					                   | j;
+				curarg += 2;
+			} else
+				curarg = params - 1;
+			break;
+		case RT_NUMBER:
+		case RT_HEX:
+			if (curarg < params) {
+				if (param_type == RT_HEX)
+					event->parameter =
+						isdn_gethex(argv[curarg]);
+				else
+					event->parameter =
+						isdn_getnum(argv[curarg]);
+				++curarg;
+			} else
+				event->parameter = -1;
+#ifdef CONFIG_GIGASET_DEBUG
+			dbg(DEBUG_CMD, "parameter==%d", event->parameter);
+#endif
+			break;
+		}
+
+		if (resp_code == RSP_ZDLE)
+			cs->dle = event->parameter;
+
+		if (abort)
+			break;
+	}
+
+	atomic_set(&cs->ev_tail, tail);
+	spin_unlock_irqrestore(&cs->ev_lock, flags);
+
+	if (curarg != params)
+		dbg(DEBUG_ANY, "invalid number of processed parameters: %d/%d",
+		    curarg, params);
+}
+EXPORT_SYMBOL_GPL(gigaset_handle_modem_response);
+
+/* disconnect
+ * process closing of connection associated with given AT state structure
+ */
+static void disconnect(struct at_state_t **at_state_p)
+{
+	unsigned long flags;
+	struct bc_state *bcs;
+	struct cardstate *cs;
+
+	IFNULLRET(at_state_p);
+	IFNULLRET(*at_state_p);
+	bcs = (*at_state_p)->bcs;
+	cs = (*at_state_p)->cs;
+	IFNULLRET(cs);
+
+	new_index(&(*at_state_p)->seq_index, MAX_SEQ_INDEX);
+
+	/* revert to selected idle mode */
+	if (!atomic_read(&cs->cidmode)) {
+		cs->at_state.pending_commands |= PC_UMMODE;
+		atomic_set(&cs->commands_pending, 1); //FIXME
+		dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
+	}
+
+	if (bcs) {
+		/* B channel assigned: invoke hardware specific handler */
+		cs->ops->close_bchannel(bcs);
+	} else {
+		/* no B channel assigned: just deallocate */
+		spin_lock_irqsave(&cs->lock, flags);
+		list_del(&(*at_state_p)->list);
+		kfree(*at_state_p);
+		*at_state_p = NULL;
+		spin_unlock_irqrestore(&cs->lock, flags);
+	}
+}
+
+/* get_free_channel
+ * get a free AT state structure: either one of those associated with the
+ * B channels of the Gigaset device, or if none of those is available,
+ * a newly allocated one with bcs=NULL
+ * The structure should be freed by calling disconnect() after use.
+ */
+static inline struct at_state_t *get_free_channel(struct cardstate *cs,
+                                                  int cid)
+/* cids: >0: siemens-cid
+	  0: without cid
+	 -1: no cid assigned yet
+*/
+{
+	unsigned long flags;
+	int i;
+	struct at_state_t *ret;
+
+	for (i = 0; i < cs->channels; ++i)
+		if (gigaset_get_channel(cs->bcs + i)) {
+			ret = &cs->bcs[i].at_state;
+			ret->cid = cid;
+			return ret;
+		}
+
+	spin_lock_irqsave(&cs->lock, flags);
+	ret = kmalloc(sizeof(struct at_state_t), GFP_ATOMIC);
+	if (ret) {
+		gigaset_at_init(ret, NULL, cs, cid);
+		list_add(&ret->list, &cs->temp_at_states);
+	}
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return ret;
+}
+
+static void init_failed(struct cardstate *cs, int mode)
+{
+	int i;
+	struct at_state_t *at_state;
+
+	cs->at_state.pending_commands &= ~PC_INIT;
+	atomic_set(&cs->mode, mode);
+	atomic_set(&cs->mstate, MS_UNINITIALIZED);
+	gigaset_free_channels(cs);
+	for (i = 0; i < cs->channels; ++i) {
+		at_state = &cs->bcs[i].at_state;
+		if (at_state->pending_commands & PC_CID) {
+			at_state->pending_commands &= ~PC_CID;
+			at_state->pending_commands |= PC_NOCID;
+			atomic_set(&cs->commands_pending, 1);
+		}
+	}
+}
+
+static void schedule_init(struct cardstate *cs, int state)
+{
+	if (cs->at_state.pending_commands & PC_INIT) {
+		dbg(DEBUG_CMD, "not scheduling PC_INIT again");
+		return;
+	}
+	atomic_set(&cs->mstate, state);
+	atomic_set(&cs->mode, M_UNKNOWN);
+	gigaset_block_channels(cs);
+	cs->at_state.pending_commands |= PC_INIT;
+	atomic_set(&cs->commands_pending, 1);
+	dbg(DEBUG_CMD, "Scheduling PC_INIT");
+}
+
+/* Add "AT" to a command, add the cid, dle encode it, send the result to the hardware. */
+static void send_command(struct cardstate *cs, const char *cmd, int cid,
+                         int dle, gfp_t kmallocflags)
+{
+	size_t cmdlen, buflen;
+	char *cmdpos, *cmdbuf, *cmdtail;
+
+	cmdlen = strlen(cmd);
+	buflen = 11 + cmdlen;
+
+	if (likely(buflen > cmdlen)) {
+		cmdbuf = kmalloc(buflen, kmallocflags);
+		if (likely(cmdbuf != NULL)) {
+			cmdpos = cmdbuf + 9;
+			cmdtail = cmdpos + cmdlen;
+			memcpy(cmdpos, cmd, cmdlen);
+
+			if (cid > 0 && cid <= 65535) {
+				do {
+					*--cmdpos = '0' + cid % 10;
+					cid /= 10;
+					++cmdlen;
+				} while (cid);
+			}
+
+			cmdlen += 2;
+			*--cmdpos = 'T';
+			*--cmdpos = 'A';
+
+			if (dle) {
+				cmdlen += 4;
+				*--cmdpos = '(';
+				*--cmdpos = 0x10;
+				*cmdtail++ = 0x10;
+				*cmdtail++ = ')';
+			}
+
+			cs->ops->write_cmd(cs, cmdpos, cmdlen, NULL);
+			kfree(cmdbuf);
+		} else
+			err("no memory for command buffer");
+	} else
+		err("overflow in buflen");
+}
+
+static struct at_state_t *at_state_from_cid(struct cardstate *cs, int cid)
+{
+	struct at_state_t *at_state;
+	int i;
+	unsigned long flags;
+
+	if (cid == 0)
+		return &cs->at_state;
+
+	for (i = 0; i < cs->channels; ++i)
+		if (cid == cs->bcs[i].at_state.cid)
+			return &cs->bcs[i].at_state;
+
+	spin_lock_irqsave(&cs->lock, flags);
+
+	list_for_each_entry(at_state, &cs->temp_at_states, list)
+		if (cid == at_state->cid) {
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return at_state;
+		}
+
+	spin_unlock_irqrestore(&cs->lock, flags);
+
+	return NULL;
+}
+
+static void bchannel_down(struct bc_state *bcs)
+{
+	IFNULLRET(bcs);
+	IFNULLRET(bcs->cs);
+
+	if (bcs->chstate & CHS_B_UP) {
+		bcs->chstate &= ~CHS_B_UP;
+		gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BHUP);
+	}
+
+	if (bcs->chstate & (CHS_D_UP | CHS_NOTIFY_LL)) {
+		bcs->chstate &= ~(CHS_D_UP | CHS_NOTIFY_LL);
+		gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DHUP);
+	}
+
+	gigaset_free_channel(bcs);
+
+	gigaset_bcs_reinit(bcs);
+}
+
+static void bchannel_up(struct bc_state *bcs)
+{
+	IFNULLRET(bcs);
+
+	if (!(bcs->chstate & CHS_D_UP)) {
+		notice("%s: D channel not up", __func__);
+		bcs->chstate |= CHS_D_UP;
+		gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN);
+	}
+
+	if (bcs->chstate & CHS_B_UP) {
+		notice("%s: B channel already up", __func__);
+		return;
+	}
+
+	bcs->chstate |= CHS_B_UP;
+	gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN);
+}
+
+static void start_dial(struct at_state_t *at_state, void *data, int seq_index)
+{
+	struct bc_state *bcs = at_state->bcs;
+	struct cardstate *cs = at_state->cs;
+	int retval;
+
+	bcs->chstate |= CHS_NOTIFY_LL;
+	//atomic_set(&bcs->status, BCS_INIT);
+
+	if (atomic_read(&at_state->seq_index) != seq_index)
+		goto error;
+
+	retval = gigaset_isdn_setup_dial(at_state, data);
+	if (retval != 0)
+		goto error;
+
+
+	at_state->pending_commands |= PC_CID;
+	dbg(DEBUG_CMD, "Scheduling PC_CID");
+//#ifdef GIG_MAYINITONDIAL
+//	if (atomic_read(&cs->MState) == MS_UNKNOWN) {
+//		cs->at_state.pending_commands |= PC_INIT;
+//		dbg(DEBUG_CMD, "Scheduling PC_INIT");
+//	}
+//#endif
+	atomic_set(&cs->commands_pending, 1); //FIXME
+	return;
+
+error:
+	at_state->pending_commands |= PC_NOCID;
+	dbg(DEBUG_CMD, "Scheduling PC_NOCID");
+	atomic_set(&cs->commands_pending, 1); //FIXME
+	return;
+}
+
+static void start_accept(struct at_state_t *at_state)
+{
+	struct cardstate *cs = at_state->cs;
+	int retval;
+
+	retval = gigaset_isdn_setup_accept(at_state);
+
+	if (retval == 0) {
+		at_state->pending_commands |= PC_ACCEPT;
+		dbg(DEBUG_CMD, "Scheduling PC_ACCEPT");
+		atomic_set(&cs->commands_pending, 1); //FIXME
+	} else {
+		//FIXME
+		at_state->pending_commands |= PC_HUP;
+		dbg(DEBUG_CMD, "Scheduling PC_HUP");
+		atomic_set(&cs->commands_pending, 1); //FIXME
+	}
+}
+
+static void do_start(struct cardstate *cs)
+{
+	gigaset_free_channels(cs);
+
+	if (atomic_read(&cs->mstate) != MS_LOCKED)
+		schedule_init(cs, MS_INIT);
+
+	gigaset_i4l_cmd(cs, ISDN_STAT_RUN);
+	                                // FIXME: not in locked mode
+	                                // FIXME 2: only after init sequence
+
+	cs->waiting = 0;
+	wake_up(&cs->waitqueue);
+}
+
+static void finish_shutdown(struct cardstate *cs)
+{
+	if (atomic_read(&cs->mstate) != MS_LOCKED) {
+		atomic_set(&cs->mstate, MS_UNINITIALIZED);
+		atomic_set(&cs->mode, M_UNKNOWN);
+	}
+
+	/* The rest is done by cleanup_cs () in user mode. */
+
+	cs->cmd_result = -ENODEV;
+	cs->waiting = 0;
+	wake_up_interruptible(&cs->waitqueue);
+}
+
+static void do_shutdown(struct cardstate *cs)
+{
+	gigaset_block_channels(cs);
+
+	if (atomic_read(&cs->mstate) == MS_READY) {
+		atomic_set(&cs->mstate, MS_SHUTDOWN);
+		cs->at_state.pending_commands |= PC_SHUTDOWN;
+		atomic_set(&cs->commands_pending, 1); //FIXME
+		dbg(DEBUG_CMD, "Scheduling PC_SHUTDOWN"); //FIXME
+		//gigaset_schedule_event(cs); //FIXME
+	} else
+		finish_shutdown(cs);
+}
+
+static void do_stop(struct cardstate *cs)
+{
+	do_shutdown(cs);
+}
+
+/* Entering cid mode or getting a cid failed:
+ * try to initialize the device and try again.
+ *
+ * channel >= 0: getting cid for the channel failed
+ * channel < 0:  entering cid mode failed
+ *
+ * returns 0 on failure
+ */
+static int reinit_and_retry(struct cardstate *cs, int channel)
+{
+	int i;
+
+	if (--cs->retry_count <= 0)
+		return 0;
+
+	for (i = 0; i < cs->channels; ++i)
+		if (cs->bcs[i].at_state.cid > 0)
+			return 0;
+
+	if (channel < 0)
+		warn("Could not enter cid mode. Reinit device and try again.");
+	else {
+		warn("Could not get a call id. Reinit device and try again.");
+		cs->bcs[channel].at_state.pending_commands |= PC_CID;
+	}
+	schedule_init(cs, MS_INIT);
+	return 1;
+}
+
+static int at_state_invalid(struct cardstate *cs,
+                            struct at_state_t *test_ptr)
+{
+	unsigned long flags;
+	unsigned channel;
+	struct at_state_t *at_state;
+	int retval = 0;
+
+	spin_lock_irqsave(&cs->lock, flags);
+
+	if (test_ptr == &cs->at_state)
+		goto exit;
+
+	list_for_each_entry(at_state, &cs->temp_at_states, list)
+		if (at_state == test_ptr)
+			goto exit;
+
+	for (channel = 0; channel < cs->channels; ++channel)
+		if (&cs->bcs[channel].at_state == test_ptr)
+			goto exit;
+
+	retval = 1;
+exit:
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return retval;
+}
+
+static void handle_icall(struct cardstate *cs, struct bc_state *bcs,
+			 struct at_state_t **p_at_state)
+{
+	int retval;
+	struct at_state_t *at_state = *p_at_state;
+
+	retval = gigaset_isdn_icall(at_state);
+	switch (retval) {
+	case ICALL_ACCEPT:
+		break;
+	default:
+		err("internal error: disposition=%d", retval);
+		/* --v-- fall through --v-- */
+	case ICALL_IGNORE:
+	case ICALL_REJECT:
+		/* hang up actively
+		 * Device doc says that would reject the call.
+		 * In fact it doesn't.
+		 */
+		at_state->pending_commands |= PC_HUP;
+		atomic_set(&cs->commands_pending, 1);
+		break;
+	}
+}
+
+static int do_lock(struct cardstate *cs)
+{
+	int mode;
+	int i;
+
+	switch (atomic_read(&cs->mstate)) {
+	case MS_UNINITIALIZED:
+	case MS_READY:
+		if (cs->cur_at_seq || !list_empty(&cs->temp_at_states) ||
+		    cs->at_state.pending_commands)
+			return -EBUSY;
+
+		for (i = 0; i < cs->channels; ++i)
+			if (cs->bcs[i].at_state.pending_commands)
+				return -EBUSY;
+
+		if (!gigaset_get_channels(cs))
+			return -EBUSY;
+
+		break;
+	case MS_LOCKED:
+		//retval = -EACCES;
+		break;
+	default:
+		return -EBUSY;
+	}
+
+	mode = atomic_read(&cs->mode);
+	atomic_set(&cs->mstate, MS_LOCKED);
+	atomic_set(&cs->mode, M_UNKNOWN);
+	//FIXME reset card state / at states / bcs states
+
+	return mode;
+}
+
+static int do_unlock(struct cardstate *cs)
+{
+	if (atomic_read(&cs->mstate) != MS_LOCKED)
+		return -EINVAL;
+
+	atomic_set(&cs->mstate, MS_UNINITIALIZED);
+	atomic_set(&cs->mode, M_UNKNOWN);
+	gigaset_free_channels(cs);
+	//FIXME reset card state / at states / bcs states
+	if (atomic_read(&cs->connected))
+		schedule_init(cs, MS_INIT);
+
+	return 0;
+}
+
+static void do_action(int action, struct cardstate *cs,
+		      struct bc_state *bcs,
+		      struct at_state_t **p_at_state, char **pp_command,
+		      int *p_genresp, int *p_resp_code,
+		      struct event_t *ev)
+{
+	struct at_state_t *at_state = *p_at_state;
+	struct at_state_t *at_state2;
+	unsigned long flags;
+
+	int channel;
+
+	unsigned char *s, *e;
+	int i;
+	unsigned long val;
+
+	switch (action) {
+	case ACT_NOTHING:
+		break;
+	case ACT_TIMEOUT:
+		at_state->waiting = 1;
+		break;
+	case ACT_INIT:
+		//FIXME setup everything
+		cs->at_state.pending_commands &= ~PC_INIT;
+		cs->cur_at_seq = SEQ_NONE;
+		atomic_set(&cs->mode, M_UNIMODEM);
+		if (!atomic_read(&cs->cidmode)) {
+			gigaset_free_channels(cs);
+			atomic_set(&cs->mstate, MS_READY);
+			break;
+		}
+		cs->at_state.pending_commands |= PC_CIDMODE;
+		atomic_set(&cs->commands_pending, 1); //FIXME
+		dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
+		break;
+	case ACT_FAILINIT:
+		warn("Could not initialize the device.");
+		cs->dle = 0;
+		init_failed(cs, M_UNKNOWN);
+		cs->cur_at_seq = SEQ_NONE;
+		break;
+	case ACT_CONFIGMODE:
+		init_failed(cs, M_CONFIG);
+		cs->cur_at_seq = SEQ_NONE;
+		break;
+	case ACT_SETDLE1:
+		cs->dle = 1;
+		/* cs->inbuf[0].inputstate |= INS_command | INS_DLE_command; */
+		cs->inbuf[0].inputstate &=
+			~(INS_command | INS_DLE_command);
+		break;
+	case ACT_SETDLE0:
+		cs->dle = 0;
+		cs->inbuf[0].inputstate =
+			(cs->inbuf[0].inputstate & ~INS_DLE_command)
+			| INS_command;
+		break;
+	case ACT_CMODESET:
+		if (atomic_read(&cs->mstate) == MS_INIT ||
+		    atomic_read(&cs->mstate) == MS_RECOVER) {
+			gigaset_free_channels(cs);
+			atomic_set(&cs->mstate, MS_READY);
+		}
+		atomic_set(&cs->mode, M_CID);
+		cs->cur_at_seq = SEQ_NONE;
+		break;
+	case ACT_UMODESET:
+		atomic_set(&cs->mode, M_UNIMODEM);
+		cs->cur_at_seq = SEQ_NONE;
+		break;
+	case ACT_FAILCMODE:
+		cs->cur_at_seq = SEQ_NONE;
+		if (atomic_read(&cs->mstate) == MS_INIT ||
+		    atomic_read(&cs->mstate) == MS_RECOVER) {
+			init_failed(cs, M_UNKNOWN);
+			break;
+		}
+		if (!reinit_and_retry(cs, -1))
+			schedule_init(cs, MS_RECOVER);
+		break;
+	case ACT_FAILUMODE:
+		cs->cur_at_seq = SEQ_NONE;
+		schedule_init(cs, MS_RECOVER);
+		break;
+	case ACT_HUPMODEM:
+		/* send "+++" (hangup in unimodem mode) */
+		cs->ops->write_cmd(cs, "+++", 3, NULL);
+		break;
+	case ACT_RING:
+		/* get fresh AT state structure for new CID */
+		at_state2 = get_free_channel(cs, ev->parameter);
+		if (!at_state2) {
+			warn("RING ignored: "
+			     "could not allocate channel structure");
+			break;
+		}
+
+		/* initialize AT state structure
+		 * note that bcs may be NULL if no B channel is free
+		 */
+		at_state2->ConState = 700;
+		kfree(at_state2->str_var[STR_NMBR]);
+		at_state2->str_var[STR_NMBR] = NULL;
+		kfree(at_state2->str_var[STR_ZCPN]);
+		at_state2->str_var[STR_ZCPN] = NULL;
+		kfree(at_state2->str_var[STR_ZBC]);
+		at_state2->str_var[STR_ZBC] = NULL;
+		kfree(at_state2->str_var[STR_ZHLC]);
+		at_state2->str_var[STR_ZHLC] = NULL;
+		at_state2->int_var[VAR_ZCTP] = -1;
+
+		spin_lock_irqsave(&cs->lock, flags);
+		at_state2->timer_expires = RING_TIMEOUT;
+		at_state2->timer_active = 1;
+		spin_unlock_irqrestore(&cs->lock, flags);
+		break;
+	case ACT_ICALL:
+		handle_icall(cs, bcs, p_at_state);
+		at_state = *p_at_state;
+		break;
+	case ACT_FAILSDOWN:
+		warn("Could not shut down the device.");
+		/* fall through */
+	case ACT_FAKESDOWN:
+	case ACT_SDOWN:
+		cs->cur_at_seq = SEQ_NONE;
+		finish_shutdown(cs);
+		break;
+	case ACT_CONNECT:
+		if (cs->onechannel) {
+			at_state->pending_commands |= PC_DLE1;
+			atomic_set(&cs->commands_pending, 1);
+			break;
+		}
+		bcs->chstate |= CHS_D_UP;
+		gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN);
+		cs->ops->init_bchannel(bcs);
+		break;
+	case ACT_DLE1:
+		cs->cur_at_seq = SEQ_NONE;
+		bcs = cs->bcs + cs->curchannel;
+
+		bcs->chstate |= CHS_D_UP;
+		gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN);
+		cs->ops->init_bchannel(bcs);
+		break;
+	case ACT_FAKEHUP:
+		at_state->int_var[VAR_ZSAU] = ZSAU_NULL;
+		/* fall through */
+	case ACT_DISCONNECT:
+		cs->cur_at_seq = SEQ_NONE;
+		at_state->cid = -1;
+		if (bcs && cs->onechannel && cs->dle) {
+			/* Check for other open channels not needed:
+			 * DLE only used for M10x with one B channel.
+			 */
+			at_state->pending_commands |= PC_DLE0;
+			atomic_set(&cs->commands_pending, 1);
+		} else {
+			disconnect(p_at_state);
+			at_state = *p_at_state;
+		}
+		break;
+	case ACT_FAKEDLE0:
+		at_state->int_var[VAR_ZDLE] = 0;
+		cs->dle = 0;
+		/* fall through */
+	case ACT_DLE0:
+		cs->cur_at_seq = SEQ_NONE;
+		at_state2 = &cs->bcs[cs->curchannel].at_state;
+		disconnect(&at_state2);
+		break;
+	case ACT_ABORTHUP:
+		cs->cur_at_seq = SEQ_NONE;
+		warn("Could not hang up.");
+		at_state->cid = -1;
+		if (bcs && cs->onechannel)
+			at_state->pending_commands |= PC_DLE0;
+		else {
+			disconnect(p_at_state);
+			at_state = *p_at_state;
+		}
+		schedule_init(cs, MS_RECOVER);
+		break;
+	case ACT_FAILDLE0:
+		cs->cur_at_seq = SEQ_NONE;
+		warn("Could not leave DLE mode.");
+		at_state2 = &cs->bcs[cs->curchannel].at_state;
+		disconnect(&at_state2);
+		schedule_init(cs, MS_RECOVER);
+		break;
+	case ACT_FAILDLE1:
+		cs->cur_at_seq = SEQ_NONE;
+		warn("Could not enter DLE mode. Try to hang up.");
+		channel = cs->curchannel;
+		cs->bcs[channel].at_state.pending_commands |= PC_HUP;
+		atomic_set(&cs->commands_pending, 1);
+		break;
+
+	case ACT_CID: /* got cid; start dialing */
+		cs->cur_at_seq = SEQ_NONE;
+		channel = cs->curchannel;
+		if (ev->parameter > 0 && ev->parameter <= 65535) {
+			cs->bcs[channel].at_state.cid = ev->parameter;
+			cs->bcs[channel].at_state.pending_commands |=
+				PC_DIAL;
+			atomic_set(&cs->commands_pending, 1);
+			break;
+		}
+		/* fall through */
+	case ACT_FAILCID:
+		cs->cur_at_seq = SEQ_NONE;
+		channel = cs->curchannel;
+		if (!reinit_and_retry(cs, channel)) {
+			warn("Could not get a call id. Dialing not possible");
+			at_state2 = &cs->bcs[channel].at_state;
+			disconnect(&at_state2);
+		}
+		break;
+	case ACT_ABORTCID:
+		cs->cur_at_seq = SEQ_NONE;
+		at_state2 = &cs->bcs[cs->curchannel].at_state;
+		disconnect(&at_state2);
+		break;
+
+	case ACT_DIALING:
+	case ACT_ACCEPTED:
+		cs->cur_at_seq = SEQ_NONE;
+		break;
+
+	case ACT_ABORTACCEPT:	/* hangup/error/timeout during ICALL processing */
+		disconnect(p_at_state);
+		at_state = *p_at_state;
+		break;
+
+	case ACT_ABORTDIAL:	/* error/timeout during dial preparation */
+		cs->cur_at_seq = SEQ_NONE;
+		at_state->pending_commands |= PC_HUP;
+		atomic_set(&cs->commands_pending, 1);
+		break;
+
+	case ACT_REMOTEREJECT:	/* DISCONNECT_IND after dialling */
+	case ACT_CONNTIMEOUT:	/* timeout waiting for ZSAU=ACTIVE */
+	case ACT_REMOTEHUP:	/* DISCONNECT_IND with established connection */
+		at_state->pending_commands |= PC_HUP;
+		atomic_set(&cs->commands_pending, 1);
+		break;
+	case ACT_GETSTRING: /* warning: RING, ZDLE, ... are not handled properly any more */
+		at_state->getstring = 1;
+		break;
+	case ACT_SETVER:
+		if (!ev->ptr) {
+			*p_genresp = 1;
+			*p_resp_code = RSP_ERROR;
+			break;
+		}
+		s = ev->ptr;
+
+		if (!strcmp(s, "OK")) {
+			*p_genresp = 1;
+			*p_resp_code = RSP_ERROR;
+			break;
+		}
+
+		for (i = 0; i < 4; ++i) {
+			val = simple_strtoul(s, (char **) &e, 10);
+			if (val > INT_MAX || e == s)
+				break;
+			if (i == 3) {
+				if (*e)
+					break;
+			} else if (*e != '.')
+				break;
+			else
+				s = e + 1;
+			cs->fwver[i] = val;
+		}
+		if (i != 4) {
+			*p_genresp = 1;
+			*p_resp_code = RSP_ERROR;
+			break;
+		}
+		/*at_state->getstring = 1;*/
+		cs->gotfwver = 0;
+		break;
+	case ACT_GOTVER:
+		if (cs->gotfwver == 0) {
+			cs->gotfwver = 1;
+			dbg(DEBUG_ANY,
+			    "firmware version %02d.%03d.%02d.%02d",
+			    cs->fwver[0], cs->fwver[1],
+			    cs->fwver[2], cs->fwver[3]);
+			break;
+		}
+		/* fall through */
+	case ACT_FAILVER:
+		cs->gotfwver = -1;
+		err("could not read firmware version.");
+		break;
+#ifdef CONFIG_GIGASET_DEBUG
+	case ACT_ERROR:
+		*p_genresp = 1;
+		*p_resp_code = RSP_ERROR;
+		break;
+	case ACT_TEST:
+		{
+			static int count = 3; //2; //1;
+			*p_genresp = 1;
+			*p_resp_code = count ? RSP_ERROR : RSP_OK;
+			if (count > 0)
+				--count;
+		}
+		break;
+#endif
+	case ACT_DEBUG:
+		dbg(DEBUG_ANY, "%s: resp_code %d in ConState %d",
+			__func__, ev->type, at_state->ConState);
+		break;
+	case ACT_WARN:
+		warn("%s: resp_code %d in ConState %d!",
+			__func__, ev->type, at_state->ConState);
+		break;
+	case ACT_ZCAU:
+		warn("cause code %04x in connection state %d.",
+		     ev->parameter, at_state->ConState);
+		break;
+
+	/* events from the LL */
+	case ACT_DIAL:
+		start_dial(at_state, ev->ptr, ev->parameter);
+		break;
+	case ACT_ACCEPT:
+		start_accept(at_state);
+		break;
+	case ACT_PROTO_L2:
+		dbg(DEBUG_CMD,
+		    "set protocol to %u", (unsigned) ev->parameter);
+		at_state->bcs->proto2 = ev->parameter;
+		break;
+	case ACT_HUP:
+		at_state->pending_commands |= PC_HUP;
+		atomic_set(&cs->commands_pending, 1); //FIXME
+		dbg(DEBUG_CMD, "Scheduling PC_HUP");
+		break;
+
+	/* hotplug events */
+	case ACT_STOP:
+		do_stop(cs);
+		break;
+	case ACT_START:
+		do_start(cs);
+		break;
+
+	/* events from the interface */ // FIXME without ACT_xxxx?
+	case ACT_IF_LOCK:
+		cs->cmd_result = ev->parameter ? do_lock(cs) : do_unlock(cs);
+		cs->waiting = 0;
+		wake_up(&cs->waitqueue);
+		break;
+	case ACT_IF_VER:
+		if (ev->parameter != 0)
+			cs->cmd_result = -EINVAL;
+		else if (cs->gotfwver != 1) {
+			cs->cmd_result = -ENOENT;
+		} else {
+			memcpy(ev->arg, cs->fwver, sizeof cs->fwver);
+			cs->cmd_result = 0;
+		}
+		cs->waiting = 0;
+		wake_up(&cs->waitqueue);
+		break;
+
+	/* events from the proc file system */ // FIXME without ACT_xxxx?
+	case ACT_PROC_CIDMODE:
+		if (ev->parameter != atomic_read(&cs->cidmode)) {
+			atomic_set(&cs->cidmode, ev->parameter);
+			if (ev->parameter) {
+				cs->at_state.pending_commands |= PC_CIDMODE;
+				dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
+			} else {
+				cs->at_state.pending_commands |= PC_UMMODE;
+				dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
+			}
+			atomic_set(&cs->commands_pending, 1);
+		}
+		cs->waiting = 0;
+		wake_up(&cs->waitqueue);
+		break;
+
+	/* events from the hardware drivers */
+	case ACT_NOTIFY_BC_DOWN:
+		bchannel_down(bcs);
+		break;
+	case ACT_NOTIFY_BC_UP:
+		bchannel_up(bcs);
+		break;
+	case ACT_SHUTDOWN:
+		do_shutdown(cs);
+		break;
+
+
+	default:
+		if (action >= ACT_CMD && action < ACT_CMD + AT_NUM) {
+			*pp_command = at_state->bcs->commands[action - ACT_CMD];
+			if (!*pp_command) {
+				*p_genresp = 1;
+				*p_resp_code = RSP_NULL;
+			}
+		} else
+			err("%s: action==%d!", __func__, action);
+	}
+}
+
+/* State machine to do the calling and hangup procedure */
+static void process_event(struct cardstate *cs, struct event_t *ev)
+{
+	struct bc_state *bcs;
+	char *p_command = NULL;
+	struct reply_t *rep;
+	int rcode;
+	int genresp = 0;
+	int resp_code = RSP_ERROR;
+	int sendcid;
+	struct at_state_t *at_state;
+	int index;
+	int curact;
+	unsigned long flags;
+
+	IFNULLRET(cs);
+	IFNULLRET(ev);
+
+	if (ev->cid >= 0) {
+		at_state = at_state_from_cid(cs, ev->cid);
+		if (!at_state) {
+			gigaset_add_event(cs, &cs->at_state, RSP_WRONG_CID,
+			                  NULL, 0, NULL);
+			return;
+		}
+	} else {
+		at_state = ev->at_state;
+		if (at_state_invalid(cs, at_state)) {
+			dbg(DEBUG_ANY,
+			    "event for invalid at_state %p", at_state);
+			return;
+		}
+	}
+
+	dbg(DEBUG_CMD,
+	    "connection state %d, event %d", at_state->ConState, ev->type);
+
+	bcs = at_state->bcs;
+	sendcid = at_state->cid;
+
+	/* Setting the pointer to the dial array */
+	rep = at_state->replystruct;
+	IFNULLRET(rep);
+
+	if (ev->type == EV_TIMEOUT) {
+		if (ev->parameter != atomic_read(&at_state->timer_index)
+		    || !at_state->timer_active) {
+			ev->type = RSP_NONE; /* old timeout */
+			dbg(DEBUG_ANY, "old timeout");
+		} else if (!at_state->waiting)
+			dbg(DEBUG_ANY, "timeout occured");
+		else
+			dbg(DEBUG_ANY, "stopped waiting");
+	}
+
+	/* if the response belongs to a variable in at_state->int_var[VAR_XXXX] or at_state->str_var[STR_XXXX], set it */
+	if (ev->type >= RSP_VAR && ev->type < RSP_VAR + VAR_NUM) {
+		index = ev->type - RSP_VAR;
+		at_state->int_var[index] = ev->parameter;
+	} else if (ev->type >= RSP_STR && ev->type < RSP_STR + STR_NUM) {
+		index = ev->type - RSP_STR;
+		kfree(at_state->str_var[index]);
+		at_state->str_var[index] = ev->ptr;
+		ev->ptr = NULL; /* prevent process_events() from deallocating ptr */
+	}
+
+	if (ev->type == EV_TIMEOUT || ev->type == RSP_STRING)
+		at_state->getstring = 0;
+
+	/* Search row in dial array which matches modem response and current constate */
+	for (;; rep++) {
+		rcode = rep->resp_code;
+		/* dbg (DEBUG_ANY, "rcode %d", rcode); */
+		if (rcode == RSP_LAST) {
+			/* found nothing...*/
+			warn("%s: rcode=RSP_LAST: resp_code %d in ConState %d!",
+				__func__, ev->type, at_state->ConState);
+			return;
+		}
+		if ((rcode == RSP_ANY || rcode == ev->type)
+		  && ((int) at_state->ConState >= rep->min_ConState)
+		  && (rep->max_ConState < 0
+		      || (int) at_state->ConState <= rep->max_ConState)
+		  && (rep->parameter < 0 || rep->parameter == ev->parameter))
+			break;
+	}
+
+	p_command = rep->command;
+
+	at_state->waiting = 0;
+	for (curact = 0; curact < MAXACT; ++curact) {
+		/* The row tells us what we should do  ..
+		 */
+		do_action(rep->action[curact], cs, bcs, &at_state, &p_command, &genresp, &resp_code, ev);
+		if (!at_state)
+			break; /* may be freed after disconnect */
+	}
+
+	if (at_state) {
+		/* Jump to the next con-state regarding the array */
+		if (rep->new_ConState >= 0)
+			at_state->ConState = rep->new_ConState;
+
+		if (genresp) {
+			spin_lock_irqsave(&cs->lock, flags);
+			at_state->timer_expires = 0; //FIXME
+			at_state->timer_active = 0; //FIXME
+			spin_unlock_irqrestore(&cs->lock, flags);
+			gigaset_add_event(cs, at_state, resp_code, NULL, 0, NULL);
+		} else {
+			/* Send command to modem if not NULL... */
+			if (p_command/*rep->command*/) {
+				if (atomic_read(&cs->connected))
+					send_command(cs, p_command,
+					             sendcid, cs->dle,
+					             GFP_ATOMIC);
+				else
+					gigaset_add_event(cs, at_state,
+					                  RSP_NODEV,
+					                  NULL, 0, NULL);
+			}
+
+			spin_lock_irqsave(&cs->lock, flags);
+			if (!rep->timeout) {
+				at_state->timer_expires = 0;
+				at_state->timer_active = 0;
+			} else if (rep->timeout > 0) { /* new timeout */
+				at_state->timer_expires = rep->timeout * 10;
+				at_state->timer_active = 1;
+				new_index(&at_state->timer_index,
+				          MAX_TIMER_INDEX);
+			}
+			spin_unlock_irqrestore(&cs->lock, flags);
+		}
+	}
+}
+
+static void schedule_sequence(struct cardstate *cs,
+			      struct at_state_t *at_state, int sequence)
+{
+	cs->cur_at_seq = sequence;
+	gigaset_add_event(cs, at_state, RSP_INIT, NULL, sequence, NULL);
+}
+
+static void process_command_flags(struct cardstate *cs)
+{
+	struct at_state_t *at_state = NULL;
+	struct bc_state *bcs;
+	int i;
+	int sequence;
+
+	IFNULLRET(cs);
+
+	atomic_set(&cs->commands_pending, 0);
+
+	if (cs->cur_at_seq) {
+		dbg(DEBUG_CMD, "not searching scheduled commands: busy");
+		return;
+	}
+
+	dbg(DEBUG_CMD, "searching scheduled commands");
+
+	sequence = SEQ_NONE;
+
+	/* clear pending_commands and hangup channels on shutdown */
+	if (cs->at_state.pending_commands & PC_SHUTDOWN) {
+		cs->at_state.pending_commands &= ~PC_CIDMODE;
+		for (i = 0; i < cs->channels; ++i) {
+			bcs = cs->bcs + i;
+			at_state = &bcs->at_state;
+			at_state->pending_commands &=
+				~(PC_DLE1 | PC_ACCEPT | PC_DIAL);
+			if (at_state->cid > 0)
+				at_state->pending_commands |= PC_HUP;
+			if (at_state->pending_commands & PC_CID) {
+				at_state->pending_commands |= PC_NOCID;
+				at_state->pending_commands &= ~PC_CID;
+			}
+		}
+	}
+
+	/* clear pending_commands and hangup channels on reset */
+	if (cs->at_state.pending_commands & PC_INIT) {
+		cs->at_state.pending_commands &= ~PC_CIDMODE;
+		for (i = 0; i < cs->channels; ++i) {
+			bcs = cs->bcs + i;
+			at_state = &bcs->at_state;
+			at_state->pending_commands &=
+				~(PC_DLE1 | PC_ACCEPT | PC_DIAL);
+			if (at_state->cid > 0)
+				at_state->pending_commands |= PC_HUP;
+			if (atomic_read(&cs->mstate) == MS_RECOVER) {
+				if (at_state->pending_commands & PC_CID) {
+					at_state->pending_commands |= PC_NOCID;
+					at_state->pending_commands &= ~PC_CID;
+				}
+			}
+		}
+	}
+
+	/* only switch back to unimodem mode, if no commands are pending and no channels are up */
+	if (cs->at_state.pending_commands == PC_UMMODE
+	    && !atomic_read(&cs->cidmode)
+	    && list_empty(&cs->temp_at_states)
+	    && atomic_read(&cs->mode) == M_CID) {
+		sequence = SEQ_UMMODE;
+		at_state = &cs->at_state;
+		for (i = 0; i < cs->channels; ++i) {
+			bcs = cs->bcs + i;
+			if (bcs->at_state.pending_commands ||
+			    bcs->at_state.cid > 0) {
+				sequence = SEQ_NONE;
+				break;
+			}
+		}
+	}
+	cs->at_state.pending_commands &= ~PC_UMMODE;
+	if (sequence != SEQ_NONE) {
+		schedule_sequence(cs, at_state, sequence);
+		return;
+	}
+
+	for (i = 0; i < cs->channels; ++i) {
+		bcs = cs->bcs + i;
+		if (bcs->at_state.pending_commands & PC_HUP) {
+			bcs->at_state.pending_commands &= ~PC_HUP;
+			if (bcs->at_state.pending_commands & PC_CID) {
+				/* not yet dialing: PC_NOCID is sufficient */
+				bcs->at_state.pending_commands |= PC_NOCID;
+				bcs->at_state.pending_commands &= ~PC_CID;
+			} else {
+				schedule_sequence(cs, &bcs->at_state, SEQ_HUP);
+				return;
+			}
+		}
+		if (bcs->at_state.pending_commands & PC_NOCID) {
+			bcs->at_state.pending_commands &= ~PC_NOCID;
+			cs->curchannel = bcs->channel;
+			schedule_sequence(cs, &cs->at_state, SEQ_NOCID);
+			return;
+		} else if (bcs->at_state.pending_commands & PC_DLE0) {
+			bcs->at_state.pending_commands &= ~PC_DLE0;
+			cs->curchannel = bcs->channel;
+			schedule_sequence(cs, &cs->at_state, SEQ_DLE0);
+			return;
+		}
+	}
+
+	list_for_each_entry(at_state, &cs->temp_at_states, list)
+		if (at_state->pending_commands & PC_HUP) {
+			at_state->pending_commands &= ~PC_HUP;
+			schedule_sequence(cs, at_state, SEQ_HUP);
+			return;
+		}
+
+	if (cs->at_state.pending_commands & PC_INIT) {
+		cs->at_state.pending_commands &= ~PC_INIT;
+		cs->dle = 0; //FIXME
+		cs->inbuf->inputstate = INS_command;
+		//FIXME reset card state (or -> LOCK0)?
+		schedule_sequence(cs, &cs->at_state, SEQ_INIT);
+		return;
+	}
+	if (cs->at_state.pending_commands & PC_SHUTDOWN) {
+		cs->at_state.pending_commands &= ~PC_SHUTDOWN;
+		schedule_sequence(cs, &cs->at_state, SEQ_SHUTDOWN);
+		return;
+	}
+	if (cs->at_state.pending_commands & PC_CIDMODE) {
+		cs->at_state.pending_commands &= ~PC_CIDMODE;
+		if (atomic_read(&cs->mode) == M_UNIMODEM) {
+#if 0
+			cs->retry_count = 2;
+#else
+			cs->retry_count = 1;
+#endif
+			schedule_sequence(cs, &cs->at_state, SEQ_CIDMODE);
+			return;
+		}
+	}
+
+	for (i = 0; i < cs->channels; ++i) {
+		bcs = cs->bcs + i;
+		if (bcs->at_state.pending_commands & PC_DLE1) {
+			bcs->at_state.pending_commands &= ~PC_DLE1;
+			cs->curchannel = bcs->channel;
+			schedule_sequence(cs, &cs->at_state, SEQ_DLE1);
+			return;
+		}
+		if (bcs->at_state.pending_commands & PC_ACCEPT) {
+			bcs->at_state.pending_commands &= ~PC_ACCEPT;
+			schedule_sequence(cs, &bcs->at_state, SEQ_ACCEPT);
+			return;
+		}
+		if (bcs->at_state.pending_commands & PC_DIAL) {
+			bcs->at_state.pending_commands &= ~PC_DIAL;
+			schedule_sequence(cs, &bcs->at_state, SEQ_DIAL);
+			return;
+		}
+		if (bcs->at_state.pending_commands & PC_CID) {
+			switch (atomic_read(&cs->mode)) {
+			case M_UNIMODEM:
+				cs->at_state.pending_commands |= PC_CIDMODE;
+				dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
+				atomic_set(&cs->commands_pending, 1);
+				return;
+#ifdef GIG_MAYINITONDIAL
+			case M_UNKNOWN:
+				schedule_init(cs, MS_INIT);
+				return;
+#endif
+			}
+			bcs->at_state.pending_commands &= ~PC_CID;
+			cs->curchannel = bcs->channel;
+#ifdef GIG_RETRYCID
+			cs->retry_count = 2;
+#else
+			cs->retry_count = 1;
+#endif
+			schedule_sequence(cs, &cs->at_state, SEQ_CID);
+			return;
+		}
+	}
+}
+
+static void process_events(struct cardstate *cs)
+{
+	struct event_t *ev;
+	unsigned head, tail;
+	int i;
+	int check_flags = 0;
+	int was_busy;
+
+	/* no locking needed (only one reader) */
+	head = atomic_read(&cs->ev_head);
+
+	for (i = 0; i < 2 * MAX_EVENTS; ++i) {
+		tail = atomic_read(&cs->ev_tail);
+		if (tail == head) {
+			if (!check_flags && !atomic_read(&cs->commands_pending))
+				break;
+			check_flags = 0;
+			process_command_flags(cs);
+			tail = atomic_read(&cs->ev_tail);
+			if (tail == head) {
+				if (!atomic_read(&cs->commands_pending))
+					break;
+				continue;
+			}
+		}
+
+		ev = cs->events + head;
+		was_busy = cs->cur_at_seq != SEQ_NONE;
+		process_event(cs, ev);
+		kfree(ev->ptr);
+		ev->ptr = NULL;
+		if (was_busy && cs->cur_at_seq == SEQ_NONE)
+			check_flags = 1;
+
+		head = (head + 1) % MAX_EVENTS;
+		atomic_set(&cs->ev_head, head);
+	}
+
+	if (i == 2 * MAX_EVENTS) {
+		err("infinite loop in process_events; aborting.");
+	}
+}
+
+/* tasklet scheduled on any event received from the Gigaset device
+ * parameter:
+ *	data	ISDN controller state structure
+ */
+void gigaset_handle_event(unsigned long data)
+{
+	struct cardstate *cs = (struct cardstate *) data;
+
+	IFNULLRET(cs);
+	IFNULLRET(cs->inbuf);
+
+	/* handle incoming data on control/common channel */
+	if (atomic_read(&cs->inbuf->head) != atomic_read(&cs->inbuf->tail)) {
+		dbg(DEBUG_INTR, "processing new data");
+		cs->ops->handle_input(cs->inbuf);
+	}
+
+	process_events(cs);
+}
diff -urN oldtree/drivers/isdn/gigaset/gigaset.h newtree/drivers/isdn/gigaset/gigaset.h
--- oldtree/drivers/isdn/gigaset/gigaset.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/isdn/gigaset/gigaset.h	2006-02-21 15:58:32.867149992 +0000
@@ -0,0 +1,938 @@
+/* Siemens Gigaset 307x driver
+ * Common header file for all connection variants
+ *
+ * Written by Stefan Eilers <Eilers.Stefan@epost.de>
+ *        and Hansjoerg Lipp <hjlipp@web.de>
+ *
+ * Version: $Id: gigaset.h,v 1.97.4.26 2006/02/04 18:28:16 hjlipp Exp $
+ * ===========================================================================
+ */
+
+#ifndef GIGASET_H
+#define GIGASET_H
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <asm/atomic.h>
+#include <linux/spinlock.h>
+#include <linux/isdnif.h>
+#include <linux/usb.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/ppp_defs.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/list.h>
+
+#define GIG_VERSION {0,5,0,0}
+#define GIG_COMPAT  {0,4,0,0}
+
+#define MAX_REC_PARAMS 10                         /* Max. number of params in response string */
+#define MAX_RESP_SIZE 512                         /* Max. size of a response string */
+#define HW_HDR_LEN 2                              /* Header size used to store ack info */
+
+#define MAX_EVENTS 64                          /* size of event queue */
+
+#define RBUFSIZE 8192
+#define SBUFSIZE 4096				/* sk_buff payload size */
+
+#define MAX_BUF_SIZE (SBUFSIZE - 2)		/* Max. size of a data packet from LL */
+#define TRANSBUFSIZE 768			/* bytes per skb for transparent receive */
+
+/* compile time options */
+#define GIG_MAJOR 0
+
+#define GIG_MAYINITONDIAL
+#define GIG_RETRYCID
+#define GIG_X75
+
+#define MAX_TIMER_INDEX 1000
+#define MAX_SEQ_INDEX   1000
+
+#define GIG_TICK (HZ / 10)
+
+/* timeout values (unit: 1 sec) */
+#define INIT_TIMEOUT 1
+
+/* timeout values (unit: 0.1 sec) */
+#define RING_TIMEOUT 3		/* for additional parameters to RING */
+#define BAS_TIMEOUT 20		/* for response to Base USB ops */
+#define ATRDY_TIMEOUT 3		/* for HD_READY_SEND_ATDATA */
+
+#define BAS_RETRY 3		/* max. retries for base USB ops */
+
+#define MAXACT 3
+
+#define IFNULL(a)         if (unlikely(!(a)))
+#define IFNULLRET(a)      if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); return; }
+#define IFNULLRETVAL(a,b) if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); return (b); }
+#define IFNULLCONT(a)     if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); continue; }
+#define IFNULLGOTO(a,b)   if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); goto b; }
+
+extern int gigaset_debuglevel;	/* "needs" cast to (enum debuglevel) */
+
+/* any combination of these can be given with the 'debug=' parameter to insmod, e.g.
+ * 'insmod usb_gigaset.o debug=0x2c' will set DEBUG_OPEN, DEBUG_CMD and DEBUG_INTR. */
+enum debuglevel { /* up to 24 bits (atomic_t) */
+	DEBUG_REG	  = 0x0002, /* serial port I/O register operations */
+	DEBUG_OPEN	  = 0x0004, /* open/close serial port */
+	DEBUG_INTR	  = 0x0008, /* interrupt processing */
+	DEBUG_INTR_DUMP   = 0x0010, /* Activating hexdump debug output on interrupt
+				      requests, not available as run-time option */
+	DEBUG_CMD	  = 0x00020, /* sent/received LL commands */
+	DEBUG_STREAM	  = 0x00040, /* application data stream I/O events */
+	DEBUG_STREAM_DUMP = 0x00080, /* application data stream content */
+	DEBUG_LLDATA	  = 0x00100, /* sent/received LL data */
+	DEBUG_INTR_0	  = 0x00200, /* serial port output interrupt processing */
+	DEBUG_DRIVER	  = 0x00400, /* driver structure */
+	DEBUG_HDLC	  = 0x00800, /* M10x HDLC processing */
+	DEBUG_WRITE	  = 0x01000, /* M105 data write */
+	DEBUG_TRANSCMD    = 0x02000, /*AT-COMMANDS+RESPONSES*/
+	DEBUG_MCMD        = 0x04000, /*COMMANDS THAT ARE SENT VERY OFTEN*/
+	DEBUG_INIT	  = 0x08000, /* (de)allocation+initialization of data structures */
+	DEBUG_LOCK	  = 0x10000, /* semaphore operations */
+	DEBUG_OUTPUT	  = 0x20000, /* output to device */
+	DEBUG_ISO         = 0x40000, /* isochronous transfers */
+	DEBUG_IF	  = 0x80000, /* character device operations */
+	DEBUG_USBREQ	  = 0x100000, /* USB communication (except payload data) */
+	DEBUG_LOCKCMD     = 0x200000, /* AT commands and responses when MS_LOCKED */
+
+	DEBUG_ANY	  = 0x3fffff, /* print message if any of the others is activated */
+};
+
+#ifdef CONFIG_GIGASET_DEBUG
+#define DEBUG_DEFAULT (DEBUG_INIT | DEBUG_TRANSCMD | DEBUG_CMD | DEBUG_USBREQ)
+//#define DEBUG_DEFAULT (DEBUG_LOCK | DEBUG_INIT | DEBUG_TRANSCMD | DEBUG_CMD | DEBUF_IF | DEBUG_DRIVER | DEBUG_OUTPUT | DEBUG_INTR)
+#else
+#define DEBUG_DEFAULT 0
+#endif
+
+/* redefine syslog macros to prepend module name instead of entire source path */
+/* The space before the comma in ", ##" is needed by gcc 2.95 */
+#undef info
+#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg)
+
+#undef notice
+#define notice(format, arg...) printk(KERN_NOTICE "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg)
+
+#undef warn
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg)
+
+#undef err
+#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg)
+
+#undef dbg
+#ifdef CONFIG_GIGASET_DEBUG
+#define dbg(level, format, arg...) do { if (unlikely(((enum debuglevel)gigaset_debuglevel) & (level))) \
+	printk(KERN_DEBUG "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg); } while (0)
+#else
+#define dbg(level, format, arg...) do {} while (0)
+#endif
+
+void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
+                        size_t len, const unsigned char *buf, int from_user);
+
+/* connection state */
+#define ZSAU_NONE			0
+#define ZSAU_DISCONNECT_IND		4
+#define ZSAU_OUTGOING_CALL_PROCEEDING	1
+#define ZSAU_PROCEEDING			1
+#define ZSAU_CALL_DELIVERED		2
+#define ZSAU_ACTIVE			3
+#define ZSAU_NULL			5
+#define ZSAU_DISCONNECT_REQ		6
+#define ZSAU_UNKNOWN			-1
+
+/* USB control transfer requests */
+#define OUT_VENDOR_REQ			(USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT)
+#define IN_VENDOR_REQ			(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT)
+
+/* int-in-events 3070 */
+#define HD_B1_FLOW_CONTROL		0x80
+#define HD_B2_FLOW_CONTROL		0x81
+#define HD_RECEIVEATDATA_ACK		(0x35)		// 3070		// att: HD_RECEIVE>>AT<<DATA_ACK
+#define HD_READY_SEND_ATDATA		(0x36)		// 3070
+#define HD_OPEN_ATCHANNEL_ACK		(0x37)		// 3070
+#define HD_CLOSE_ATCHANNEL_ACK		(0x38)		// 3070
+#define HD_DEVICE_INIT_OK		(0x11)		// ISurf USB + 3070
+#define HD_OPEN_B1CHANNEL_ACK		(0x51)		// ISurf USB + 3070
+#define HD_OPEN_B2CHANNEL_ACK		(0x52)		// ISurf USB + 3070
+#define HD_CLOSE_B1CHANNEL_ACK		(0x53)		// ISurf USB + 3070
+#define HD_CLOSE_B2CHANNEL_ACK		(0x54)		// ISurf USB + 3070
+// 	 Powermangment
+#define HD_SUSPEND_END			(0x61)		// ISurf USB
+//   Configuration
+#define HD_RESET_INTERRUPT_PIPE_ACK	(0xFF)		// ISurf USB + 3070
+
+/* control requests 3070 */
+#define	HD_OPEN_B1CHANNEL		(0x23)		// ISurf USB + 3070
+#define	HD_CLOSE_B1CHANNEL		(0x24)		// ISurf USB + 3070
+#define	HD_OPEN_B2CHANNEL		(0x25)		// ISurf USB + 3070
+#define	HD_CLOSE_B2CHANNEL		(0x26)		// ISurf USB + 3070
+#define HD_RESET_INTERRUPT_PIPE		(0x27)		// ISurf USB + 3070
+#define	HD_DEVICE_INIT_ACK		(0x34)		// ISurf USB + 3070
+#define	HD_WRITE_ATMESSAGE		(0x12)		// 3070
+#define	HD_READ_ATMESSAGE		(0x13)		// 3070
+#define	HD_OPEN_ATCHANNEL		(0x28)		// 3070
+#define	HD_CLOSE_ATCHANNEL		(0x29)		// 3070
+
+/* USB frames for isochronous transfer */
+#define BAS_FRAMETIME	1		/* number of milliseconds between frames */
+#define BAS_NUMFRAMES	8		/* number of frames per URB */
+#define BAS_MAXFRAME	16		/* allocated bytes per frame */
+#define BAS_NORMFRAME	8		/* send size without flow control */
+#define BAS_HIGHFRAME	10		/* "    "    with positive flow control */
+#define BAS_LOWFRAME	5		/* "    "    with negative flow control */
+#define BAS_CORRFRAMES	4		/* flow control multiplicator */
+
+#define BAS_INBUFSIZE	(BAS_MAXFRAME * BAS_NUMFRAMES) /* size of isochronous input buffer per URB */
+#define BAS_OUTBUFSIZE	4096		/* size of common isochronous output buffer */
+#define BAS_OUTBUFPAD	BAS_MAXFRAME	/* size of pad area for isochronous output buffer */
+
+#define BAS_INURBS	3
+#define BAS_OUTURBS	3
+
+/* variable commands in struct bc_state */
+#define AT_ISO		0
+#define AT_DIAL		1
+#define AT_MSN		2
+#define AT_BC		3
+#define AT_PROTO	4
+#define AT_TYPE		5
+#define AT_HLC		6
+#define AT_NUM		7
+
+/* variables in struct at_state_t */
+#define VAR_ZSAU   0
+#define VAR_ZDLE   1
+#define VAR_ZVLS   2
+#define VAR_ZCTP   3
+#define VAR_NUM    4
+
+#define STR_NMBR   0
+#define STR_ZCPN   1
+#define STR_ZCON   2
+#define STR_ZBC    3
+#define STR_ZHLC   4
+#define STR_NUM    5
+
+#define EV_TIMEOUT      -105
+#define EV_IF_VER       -106
+#define EV_PROC_CIDMODE -107
+#define EV_SHUTDOWN     -108
+#define EV_START        -110
+#define EV_STOP         -111
+#define EV_IF_LOCK      -112
+#define EV_PROTO_L2     -113
+#define EV_ACCEPT       -114
+#define EV_DIAL         -115
+#define EV_HUP          -116
+#define EV_BC_OPEN      -117
+#define EV_BC_CLOSED    -118
+
+/* input state */
+#define INS_command     0x0001
+#define INS_DLE_char    0x0002
+#define INS_byte_stuff  0x0004
+#define INS_have_data   0x0008
+#define INS_skip_frame  0x0010
+#define INS_DLE_command 0x0020
+#define INS_flag_hunt	0x0040
+
+/* channel state */
+#define CHS_D_UP	0x01
+#define CHS_B_UP	0x02
+#define CHS_NOTIFY_LL	0x04
+
+#define ICALL_REJECT  0
+#define ICALL_ACCEPT  1
+#define ICALL_IGNORE  2
+
+/* device state */
+#define MS_UNINITIALIZED        0
+#define MS_INIT                 1
+#define MS_LOCKED               2
+#define MS_SHUTDOWN             3
+#define MS_RECOVER              4
+#define MS_READY                5
+
+/* mode */
+#define M_UNKNOWN       0
+#define M_CONFIG        1
+#define M_UNIMODEM      2
+#define M_CID           3
+
+/* start mode */
+#define SM_LOCKED       0
+#define SM_ISDN         1 /* default */
+
+struct gigaset_ops;
+struct gigaset_driver;
+
+struct usb_cardstate;
+struct ser_cardstate;
+struct bas_cardstate;
+
+struct bc_state;
+struct usb_bc_state;
+struct ser_bc_state;
+struct bas_bc_state;
+
+struct reply_t {
+	int	resp_code;      /* RSP_XXXX */
+	int	min_ConState;   /* <0 => ignore */
+	int	max_ConState;   /* <0 => ignore */
+	int	parameter;      /* e.g. ZSAU_XXXX <0: ignore*/
+	int	new_ConState;   /* <0 => ignore */
+	int	timeout;        /* >0 => *HZ; <=0 => TOUT_XXXX*/
+	int	action[MAXACT]; /* ACT_XXXX */
+	char *command;        /* NULL==none */
+};
+
+extern struct reply_t gigaset_tab_cid_m10x[];
+extern struct reply_t gigaset_tab_nocid_m10x[];
+
+struct inbuf_t {
+	unsigned char           *rcvbuf;                /* usb-gigaset receive buffer */
+	struct bc_state		*bcs;
+	struct cardstate *cs;
+	int inputstate;
+
+	atomic_t head, tail;
+	unsigned char data[RBUFSIZE];
+};
+
+/* isochronous write buffer structure
+ * circular buffer with pad area for extraction of complete USB frames
+ * - data[read..nextread-1] is valid data already submitted to the USB subsystem
+ * - data[nextread..write-1] is valid data yet to be sent
+ * - data[write] is the next byte to write to
+ *   - in byte-oriented L2 procotols, it is completely free
+ *   - in bit-oriented L2 procotols, it may contain a partial byte of valid data
+ * - data[write+1..read-1] is free
+ * - wbits is the number of valid data bits in data[write], starting at the LSB
+ * - writesem is the semaphore for writing to the buffer:
+ *   if writesem <= 0, data[write..read-1] is currently being written to
+ * - idle contains the byte value to repeat when the end of valid data is
+ *   reached; if nextread==write (buffer contains no data to send), either the
+ *   BAS_OUTBUFPAD bytes immediately before data[write] (if write>=BAS_OUTBUFPAD)
+ *   or those of the pad area (if write<BAS_OUTBUFPAD) are also filled with that
+ *   value
+ * - optionally, the following statistics on the buffer's usage can be collected:
+ *   maxfill: maximum number of bytes occupied
+ *   idlefills: number of times a frame of idle bytes is prepared
+ *   emptygets: number of times the buffer was empty when a data frame was requested
+ *   backtoback: number of times two data packets were entered into the buffer
+ *    without intervening idle flags
+ *   nakedback: set if no idle flags have been inserted since the last data packet
+ */
+struct isowbuf_t {
+	atomic_t	read;
+	atomic_t	nextread;
+	atomic_t	write;
+	atomic_t	writesem;
+	int		wbits;
+	unsigned char	data[BAS_OUTBUFSIZE + BAS_OUTBUFPAD];
+	unsigned char	idle;
+};
+
+/* isochronous write URB context structure
+ * data to be stored along with the URB and retrieved when it is returned
+ * as completed by the USB subsystem
+ * - urb: pointer to the URB itself
+ * - bcs: pointer to the B Channel control structure
+ * - limit: end of write buffer area covered by this URB
+ */
+struct isow_urbctx_t {
+	struct urb *urb;
+	struct bc_state *bcs;
+	int limit;
+};
+
+/* AT state structure
+ * data associated with the state of an ISDN connection, whether or not
+ * it is currently assigned a B channel
+ */
+struct at_state_t {
+	struct list_head        list;
+	int                     waiting;
+	int                     getstring;
+	atomic_t		timer_index;
+	unsigned long		timer_expires;
+	int			timer_active;
+	unsigned int		ConState;                           /* State of connection */
+	struct reply_t          *replystruct;
+	int                     cid;
+	int                     int_var[VAR_NUM];   /* see VAR_XXXX */
+	char                    *str_var[STR_NUM];  /* see STR_XXXX */
+	unsigned                pending_commands;   /* see PC_XXXX */
+	atomic_t                seq_index;
+
+	struct cardstate    *cs;
+	struct bc_state         *bcs;
+};
+
+struct resp_type_t {
+	unsigned char	*response;
+	int		resp_code;           /* RSP_XXXX */
+	int		type;                /* RT_XXXX */
+};
+
+struct prot_skb {
+	atomic_t		empty;
+	struct semaphore	*sem;
+	struct sk_buff		*skb;
+};
+
+struct event_t {
+	int type;
+	void *ptr, *arg;
+	int parameter;
+	int cid;
+	struct at_state_t *at_state;
+};
+
+/* This buffer holds all information about the used B-Channel */
+struct bc_state {
+	struct sk_buff *tx_skb;                        /* Current transfer buffer to modem */
+	struct sk_buff_head squeue;	               /* B-Channel send Queue */
+
+	/* Variables for debugging .. */
+	int corrupted;                                   /* Counter for corrupted packages */
+	int trans_down;                                  /* Counter of packages (downstream) */
+	int trans_up;                                    /* Counter of packages (upstream) */
+
+	struct at_state_t at_state;
+	unsigned long rcvbytes;
+
+	__u16 fcs;
+	struct sk_buff *skb;
+	int inputstate; /* see INS_XXXX */
+
+	int channel;
+
+	struct cardstate *cs;
+
+	unsigned chstate;			/* bitmap (CHS_*) */
+	int ignore;
+	unsigned	proto2;			/* Layer 2 protocol (ISDN_PROTO_L2_*) */
+	char		*commands[AT_NUM]; /* see AT_XXXX */
+
+#ifdef CONFIG_GIGASET_DEBUG
+	int emptycount;
+#endif
+	int busy;
+	int use_count;
+
+	/* hardware drivers */
+	union {
+		struct ser_bc_state *ser;		 /* private data of serial hardware driver */
+		struct usb_bc_state *usb;		 /* private data of usb hardware driver */
+		struct bas_bc_state *bas;
+	} hw;
+};
+
+struct cardstate {
+	struct gigaset_driver *driver;
+	unsigned minor_index;
+
+	const struct gigaset_ops *ops;
+
+	/* Stuff to handle communication */
+	//wait_queue_head_t initwait;
+	wait_queue_head_t waitqueue;
+	int waiting;
+	atomic_t mode;                       /* see M_XXXX */
+	atomic_t mstate;                     /* Modem state: see MS_XXXX */
+	                                     /* only changed by the event layer */
+	int cmd_result;
+
+	int channels;
+	struct bc_state *bcs;                /* Array of struct bc_state */
+
+	int onechannel;                      /* data and commands transmitted in one stream (M10x) */
+
+	spinlock_t lock;
+	struct at_state_t at_state;          /* at_state_t for cid == 0 */
+	struct list_head temp_at_states;     /* list of temporary "struct at_state_t"s without B channel */
+
+	struct inbuf_t *inbuf;
+
+	struct cmdbuf_t *cmdbuf, *lastcmdbuf;
+	spinlock_t cmdlock;
+	unsigned curlen, cmdbytes;
+
+	unsigned open_count;
+	struct tty_struct *tty;
+	struct tasklet_struct if_wake_tasklet;
+	unsigned control_state;
+
+	unsigned fwver[4];
+	int gotfwver;
+
+	atomic_t running;                    /* !=0 if events are handled */
+	atomic_t connected;                  /* !=0 if hardware is connected */
+
+	atomic_t cidmode;
+
+	int myid;                            /* id for communication with LL */
+	isdn_if iif;
+
+	struct reply_t *tabnocid;
+	struct reply_t *tabcid;
+	int cs_init;
+	int ignoreframes;                    /* frames to ignore after setting up the B channel */
+	struct semaphore sem;                /* locks this structure: */
+	                                     /*   connected is not changed, */
+	                                     /*   hardware_up is not changed, */
+	                                     /*   MState is not changed to or from MS_LOCKED */
+
+	struct timer_list timer;
+	int retry_count;
+	int dle;                             /* !=0 if modem commands/responses are dle encoded */
+	int cur_at_seq;                      /* sequence of AT commands being processed */
+	int curchannel;                      /* channel, those commands are meant for */
+	atomic_t commands_pending;           /* flag(s) in xxx.commands_pending have been set */
+	struct tasklet_struct event_tasklet; /* tasklet for serializing AT commands. Scheduled
+	                                      *   -> for modem reponses (and incomming data for M10x)
+	                                      *   -> on timeout
+	                                      *   -> after setting bits in xxx.at_state.pending_command
+	                                      *      (e.g. command from LL) */
+	struct tasklet_struct write_tasklet; /* tasklet for serial output
+					      * (not used in base driver) */
+
+	/* event queue */
+	struct event_t events[MAX_EVENTS];
+	atomic_t ev_tail, ev_head;
+	spinlock_t ev_lock;
+
+	/* current modem response */
+	unsigned char respdata[MAX_RESP_SIZE];
+	unsigned cbytes;
+
+	/* hardware drivers */
+	union {
+		struct usb_cardstate *usb; /* private data of USB hardware driver */
+		struct ser_cardstate *ser; /* private data of serial hardware driver */
+		struct bas_cardstate *bas; /* private data of base hardware driver */
+	} hw;
+};
+
+struct gigaset_driver {
+	struct list_head list;
+	spinlock_t lock;                       /* locks minor tables and blocked */
+	//struct semaphore sem;                /* locks this structure */
+	struct tty_driver *tty;
+	unsigned have_tty;
+	unsigned minor;
+	unsigned minors;
+	struct cardstate *cs;
+	unsigned *flags;
+	int blocked;
+
+	const struct gigaset_ops *ops;
+	struct module *owner;
+};
+
+struct cmdbuf_t {
+	struct cmdbuf_t *next, *prev;
+	int len, offset;
+	struct tasklet_struct *wake_tasklet;
+	unsigned char buf[0];
+};
+
+struct bas_bc_state {
+	/* isochronous output state */
+	atomic_t	running;
+	atomic_t	corrbytes;
+	spinlock_t	isooutlock;
+	struct isow_urbctx_t	isoouturbs[BAS_OUTURBS];
+	struct isow_urbctx_t	*isooutdone, *isooutfree, *isooutovfl;
+	struct isowbuf_t	*isooutbuf;
+	unsigned numsub;			/* submitted URB counter (for diagnostic messages only) */
+	struct tasklet_struct	sent_tasklet;
+
+	/* isochronous input state */
+	spinlock_t isoinlock;
+	struct urb *isoinurbs[BAS_INURBS];
+	unsigned char isoinbuf[BAS_INBUFSIZE * BAS_INURBS];
+	struct urb *isoindone;	                /* completed isoc read URB */
+	int loststatus;				/* status of dropped URB */
+	unsigned isoinlost;			/* number of bytes lost */
+	/* state of bit unstuffing algorithm (in addition to BC_state.inputstate) */
+	unsigned seqlen;			/* number of '1' bits not yet unstuffed */
+	unsigned inbyte, inbits;		/* collected bits for next byte */
+	/* statistics */
+	unsigned goodbytes;			/* bytes correctly received */
+	unsigned alignerrs;			/* frames with incomplete byte at end */
+	unsigned fcserrs;			/* FCS errors */
+	unsigned frameerrs;			/* framing errors */
+	unsigned giants;			/* long frames */
+	unsigned runts;				/* short frames */
+	unsigned aborts;			/* HDLC aborts */
+	unsigned shared0s;			/* '0' bits shared between flags */
+	unsigned stolen0s;			/* '0' stuff bits also serving as leading flag bits */
+	struct tasklet_struct rcvd_tasklet;
+};
+
+struct gigaset_ops {
+	/* Called from ev-layer.c/interface.c for sending AT commands to the device */
+	int (*write_cmd)(struct cardstate *cs,
+	                 const unsigned char *buf, int len,
+	                 struct tasklet_struct *wake_tasklet);
+
+	/* Called from interface.c for additional device control */
+	int (*write_room)(struct cardstate *cs);
+	int (*chars_in_buffer)(struct cardstate *cs);
+	int (*brkchars)(struct cardstate *cs, const unsigned char buf[6]);
+
+	/* Called from ev-layer.c after setting up connection
+	 * Should call gigaset_bchannel_up(), when finished. */
+	int (*init_bchannel)(struct bc_state *bcs);
+
+	/* Called from ev-layer.c after hanging up
+	 * Should call gigaset_bchannel_down(), when finished. */
+	int (*close_bchannel)(struct bc_state *bcs);
+
+	/* Called by gigaset_initcs() for setting up bcs->hw.xxx */
+	int (*initbcshw)(struct bc_state *bcs);
+
+	/* Called by gigaset_freecs() for freeing bcs->hw.xxx */
+	int (*freebcshw)(struct bc_state *bcs);
+
+	/* Called by gigaset_stop() or gigaset_bchannel_down() for resetting bcs->hw.xxx */
+	void (*reinitbcshw)(struct bc_state *bcs);
+
+	/* Called by gigaset_initcs() for setting up cs->hw.xxx */
+	int (*initcshw)(struct cardstate *cs);
+
+	/* Called by gigaset_freecs() for freeing cs->hw.xxx */
+	void (*freecshw)(struct cardstate *cs);
+
+	///* Called by gigaset_stop() for killing URBs, shutting down the device, ...
+	//   hardwareup: ==0: don't try to shut down the device, hardware is really not accessible
+	//	       !=0: hardware still up */
+	//void (*stophw)(struct cardstate *cs, int hardwareup);
+
+	/* Called from common.c/interface.c for additional serial port control */
+	int (*set_modem_ctrl)(struct cardstate *cs, unsigned old_state, unsigned new_state);
+	int (*baud_rate)(struct cardstate *cs, unsigned cflag);
+	int (*set_line_ctrl)(struct cardstate *cs, unsigned cflag);
+
+	/* Called from i4l.c to put an skb into the send-queue. */
+	int (*send_skb)(struct bc_state *bcs, struct sk_buff *skb);
+
+	/* Called from ev-layer.c to process a block of data
+	 * received through the common/control channel. */
+	void (*handle_input)(struct inbuf_t *inbuf);
+
+};
+
+/* = Common structures and definitions ======================================= */
+
+/* Parser states for DLE-Event:
+ * <DLE-EVENT>: <DLE_FLAG> "X" <EVENT> <DLE_FLAG> "."
+ * <DLE_FLAG>:  0x10
+ * <EVENT>:     ((a-z)* | (A-Z)* | (0-10)*)+
+ */
+#define DLE_FLAG       0x10
+
+/* ===========================================================================
+ *  Functions implemented in asyncdata.c
+ */
+
+/* Called from i4l.c to put an skb into the send-queue.
+ * After sending gigaset_skb_sent() should be called. */
+int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb);
+
+/* Called from ev-layer.c to process a block of data
+ * received through the common/control channel. */
+void gigaset_m10x_input(struct inbuf_t *inbuf);
+
+/* ===========================================================================
+ *  Functions implemented in isocdata.c
+ */
+
+/* Called from i4l.c to put an skb into the send-queue.
+ * After sending gigaset_skb_sent() should be called. */
+int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb);
+
+/* Called from ev-layer.c to process a block of data
+ * received through the common/control channel. */
+void gigaset_isoc_input(struct inbuf_t *inbuf);
+
+/* Called from bas-gigaset.c to process a block of data
+ * received through the isochronous channel */
+void gigaset_isoc_receive(unsigned char *src, unsigned count, struct bc_state *bcs);
+
+/* Called from bas-gigaset.c to put a block of data
+ * into the isochronous output buffer */
+int gigaset_isoc_buildframe(struct bc_state *bcs, unsigned char *in, int len);
+
+/* Called from bas-gigaset.c to initialize the isochronous output buffer */
+void gigaset_isowbuf_init(struct isowbuf_t *iwb, unsigned char idle);
+
+/* Called from bas-gigaset.c to retrieve a block of bytes for sending */
+int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size);
+
+/* ===========================================================================
+ *  Functions implemented in i4l.c/gigaset.h
+ */
+
+/* Called by gigaset_initcs() for setting up with the isdn4linux subsystem */
+int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid);
+
+/* Called from xxx-gigaset.c to indicate completion of sending an skb */
+void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb);
+
+/* Called from common.c/ev-layer.c to indicate events relevant to the LL */
+int gigaset_isdn_icall(struct at_state_t *at_state);
+int gigaset_isdn_setup_accept(struct at_state_t *at_state);
+int gigaset_isdn_setup_dial(struct at_state_t *at_state, void *data);
+
+void gigaset_i4l_cmd(struct cardstate *cs, int cmd);
+void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd);
+
+
+static inline void gigaset_isdn_rcv_err(struct bc_state *bcs)
+{
+	isdn_ctrl response;
+
+	/* error -> LL */
+	dbg(DEBUG_CMD, "sending L1ERR");
+	response.driver = bcs->cs->myid;
+	response.command = ISDN_STAT_L1ERR;
+	response.arg = bcs->channel;
+	response.parm.errcode = ISDN_STAT_L1ERR_RECV;
+	bcs->cs->iif.statcallb(&response);
+}
+
+/* ===========================================================================
+ *  Functions implemented in ev-layer.c
+ */
+
+/* tasklet called from common.c to process queued events */
+void gigaset_handle_event(unsigned long data);
+
+/* called from isocdata.c / asyncdata.c
+ * when a complete modem response line has been received */
+void gigaset_handle_modem_response(struct cardstate *cs);
+
+/* ===========================================================================
+ *  Functions implemented in proc.c
+ */
+
+/* initialize sysfs for device */
+void gigaset_init_dev_sysfs(struct usb_interface *interface);
+void gigaset_free_dev_sysfs(struct usb_interface *interface);
+
+/* ===========================================================================
+ *  Functions implemented in common.c/gigaset.h
+ */
+
+void gigaset_bcs_reinit(struct bc_state *bcs);
+void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs,
+                     struct cardstate *cs, int cid);
+int gigaset_get_channel(struct bc_state *bcs);
+void gigaset_free_channel(struct bc_state *bcs);
+int gigaset_get_channels(struct cardstate *cs);
+void gigaset_free_channels(struct cardstate *cs);
+void gigaset_block_channels(struct cardstate *cs);
+
+/* Allocate and initialize driver structure. */
+struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
+                                          const char *procname,
+                                          const char *devname,
+                                          const char *devfsname,
+                                          const struct gigaset_ops *ops,
+                                          struct module *owner);
+
+/* Deallocate driver structure. */
+void gigaset_freedriver(struct gigaset_driver *drv);
+void gigaset_debugdrivers(void);
+struct cardstate *gigaset_get_cs_by_minor(unsigned minor);
+struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty);
+struct cardstate *gigaset_get_cs_by_id(int id);
+
+/* For drivers without fixed assignment device<->cardstate (usb) */
+struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv);
+void gigaset_unassign(struct cardstate *cs);
+void gigaset_blockdriver(struct gigaset_driver *drv);
+
+/* Allocate and initialize card state. Calls hardware dependent gigaset_init[b]cs(). */
+struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
+				 int onechannel, int ignoreframes,
+				 int cidmode, const char *modulename);
+
+/* Free card state. Calls hardware dependent gigaset_free[b]cs(). */
+void gigaset_freecs(struct cardstate *cs);
+
+/* Tell common.c that hardware and driver are ready. */
+int gigaset_start(struct cardstate *cs);
+
+/* Tell common.c that the device is not present any more. */
+void gigaset_stop(struct cardstate *cs);
+
+/* Tell common.c that the driver is being unloaded. */
+void gigaset_shutdown(struct cardstate *cs);
+
+/* Tell common.c that an skb has been sent. */
+void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb);
+
+/* Append event to the queue.
+ * Returns NULL on failure or a pointer to the event on success.
+ * ptr must be kmalloc()ed (and not be freed by the caller).
+ */
+struct event_t *gigaset_add_event(struct cardstate *cs,
+                                  struct at_state_t *at_state, int type,
+                                  void *ptr, int parameter, void *arg);
+
+/* Called on CONFIG1 command from frontend. */
+int gigaset_enterconfigmode(struct cardstate *cs); //0: success <0: errorcode
+
+/* cs->lock must not be locked */
+static inline void gigaset_schedule_event(struct cardstate *cs)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&cs->lock, flags);
+	if (atomic_read(&cs->running))
+		tasklet_schedule(&cs->event_tasklet);
+	spin_unlock_irqrestore(&cs->lock, flags);
+}
+
+/* Tell common.c that B channel has been closed. */
+/* cs->lock must not be locked */
+static inline void gigaset_bchannel_down(struct bc_state *bcs)
+{
+	gigaset_add_event(bcs->cs, &bcs->at_state, EV_BC_CLOSED, NULL, 0, NULL);
+
+	dbg(DEBUG_CMD, "scheduling BC_CLOSED");
+	gigaset_schedule_event(bcs->cs);
+}
+
+/* Tell common.c that B channel has been opened. */
+/* cs->lock must not be locked */
+static inline void gigaset_bchannel_up(struct bc_state *bcs)
+{
+	gigaset_add_event(bcs->cs, &bcs->at_state, EV_BC_OPEN, NULL, 0, NULL);
+
+	dbg(DEBUG_CMD, "scheduling BC_OPEN");
+	gigaset_schedule_event(bcs->cs);
+}
+
+/* handling routines for sk_buff */
+/* ============================= */
+
+/* private version of __skb_put()
+ * append 'len' bytes to the content of 'skb', already knowing that the
+ * existing buffer can accomodate them
+ * returns a pointer to the location where the new bytes should be copied to
+ * This function does not take any locks so it must be called with the
+ * appropriate locks held only.
+ */
+static inline unsigned char *gigaset_skb_put_quick(struct sk_buff *skb,
+                                                   unsigned int len)
+{
+	unsigned char *tmp = skb->tail;
+	/*SKB_LINEAR_ASSERT(skb);*/		/* not needed here */
+	skb->tail += len;
+	skb->len += len;
+	return tmp;
+}
+
+/* pass received skb to LL
+ * Warning: skb must not be accessed anymore!
+ */
+static inline void gigaset_rcv_skb(struct sk_buff *skb,
+                                   struct cardstate *cs,
+                                   struct bc_state *bcs)
+{
+	cs->iif.rcvcallb_skb(cs->myid, bcs->channel, skb);
+	bcs->trans_down++;
+}
+
+/* handle reception of corrupted skb
+ * Warning: skb must not be accessed anymore!
+ */
+static inline void gigaset_rcv_error(struct sk_buff *procskb,
+                                     struct cardstate *cs,
+                                     struct bc_state *bcs)
+{
+	if (procskb)
+		dev_kfree_skb(procskb);
+
+	if (bcs->ignore)
+		--bcs->ignore;
+	else {
+		++bcs->corrupted;
+		gigaset_isdn_rcv_err(bcs);
+	}
+}
+
+
+/* bitwise byte inversion table */
+extern __u8 gigaset_invtab[];	/* in common.c */
+
+
+/* append received bytes to inbuf */
+static inline int gigaset_fill_inbuf(struct inbuf_t *inbuf,
+                                     const unsigned char *src,
+                                     unsigned numbytes)
+{
+	unsigned n, head, tail, bytesleft;
+
+	dbg(DEBUG_INTR, "received %u bytes", numbytes);
+
+	if (!numbytes)
+		return 0;
+
+	bytesleft = numbytes;
+	tail = atomic_read(&inbuf->tail);
+	head = atomic_read(&inbuf->head);
+	dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
+
+	while (bytesleft) {
+		if (head > tail)
+			n = head - 1 - tail;
+		else if (head == 0)
+			n = (RBUFSIZE-1) - tail;
+		else
+			n = RBUFSIZE - tail;
+		if (!n) {
+			err("buffer overflow (%u bytes lost)", bytesleft);
+			break;
+		}
+		if (n > bytesleft)
+			n = bytesleft;
+		memcpy(inbuf->data + tail, src, n);
+		bytesleft -= n;
+		tail = (tail + n) % RBUFSIZE;
+		src += n;
+	}
+	dbg(DEBUG_INTR, "setting tail to %u", tail);
+	atomic_set(&inbuf->tail, tail);
+	return numbytes != bytesleft;
+}
+
+/* ===========================================================================
+ *  Functions implemented in interface.c
+ */
+
+/* initialize interface */
+void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
+                           const char *devname, const char *devfsname);
+/* release interface */
+void gigaset_if_freedriver(struct gigaset_driver *drv);
+/* add minor */
+void gigaset_if_init(struct cardstate *cs);
+/* remove minor */
+void gigaset_if_free(struct cardstate *cs);
+/* device received data */
+void gigaset_if_receive(struct cardstate *cs,
+                        unsigned char *buffer, size_t len);
+
+#endif
diff -urN oldtree/drivers/isdn/gigaset/i4l.c newtree/drivers/isdn/gigaset/i4l.c
--- oldtree/drivers/isdn/gigaset/i4l.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/isdn/gigaset/i4l.c	2006-02-21 15:58:32.898145280 +0000
@@ -0,0 +1,567 @@
+/*
+ * Stuff used by all variants of the driver
+ *
+ * Copyright (c) 2001 by Stefan Eilers (Eilers.Stefan@epost.de),
+ *                       Hansjoerg Lipp (hjlipp@web.de),
+ *                       Tilman Schmidt (tilman@imap.cc).
+ *
+ * =====================================================================
+ *	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.
+ * =====================================================================
+ * ToDo: ...
+ * =====================================================================
+ * Version: $Id: i4l.c,v 1.3.2.9 2006/02/04 18:28:16 hjlipp Exp $
+ * =====================================================================
+ */
+
+#include "gigaset.h"
+
+/* == Handling of I4L IO ============================================================================*/
+
+/* writebuf_from_LL
+ * called by LL to transmit data on an open channel
+ * inserts the buffer data into the send queue and starts the transmission
+ * Note that this operation must not sleep!
+ * When the buffer is processed completely, gigaset_skb_sent() should be called.
+ * parameters:
+ *	driverID	driver ID as assigned by LL
+ *	channel		channel number
+ *	ack		if != 0 LL wants to be notified on completion via statcallb(ISDN_STAT_BSENT)
+ *	skb		skb containing data to send
+ * return value:
+ *	number of accepted bytes
+ *	0 if temporarily unable to accept data (out of buffer space)
+ *	<0 on error (eg. -EINVAL)
+ */
+static int writebuf_from_LL(int driverID, int channel, int ack, struct sk_buff *skb)
+{
+	struct cardstate *cs;
+	struct bc_state *bcs;
+	unsigned len;
+	unsigned skblen;
+
+	if (!(cs = gigaset_get_cs_by_id(driverID))) {
+		err("%s: invalid driver ID (%d)", __func__, driverID);
+		return -ENODEV;
+	}
+	if (channel < 0 || channel >= cs->channels) {
+		err("%s: invalid channel ID (%d)", __func__, channel);
+		return -ENODEV;
+	}
+	bcs = &cs->bcs[channel];
+	len = skb->len;
+
+	dbg(DEBUG_LLDATA,
+	    "Receiving data from LL (id: %d, channel: %d, ack: %d, size: %d)",
+	    driverID, channel, ack, len);
+
+	if (!len) {
+		if (ack)
+			warn("not ACKing empty packet from LL");
+		return 0;
+	}
+	if (len > MAX_BUF_SIZE) {
+		err("%s: packet too large (%d bytes)", __func__, channel);
+		return -EINVAL;
+	}
+
+	if (!atomic_read(&cs->connected))
+		return -ENODEV;
+
+	skblen = ack ? len : 0;
+	skb->head[0] = skblen & 0xff;
+	skb->head[1] = skblen >> 8;
+	dbg(DEBUG_MCMD, "skb: len=%u, skblen=%u: %02x %02x", len, skblen,
+	     (unsigned) skb->head[0], (unsigned) skb->head[1]);
+
+	/* pass to device-specific module */
+	return cs->ops->send_skb(bcs, skb);
+}
+
+void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
+{
+	unsigned len;
+	isdn_ctrl response;
+
+	++bcs->trans_up;
+
+	if (skb->len)
+		warn("%s: skb->len==%d", __func__, skb->len);
+
+	len = (unsigned char) skb->head[0] |
+	      (unsigned) (unsigned char) skb->head[1] << 8;
+	if (len) {
+		dbg(DEBUG_MCMD,
+		    "Acknowledge sending to LL (id: %d, channel: %d size: %u)",
+		    bcs->cs->myid, bcs->channel, len);
+
+		response.driver = bcs->cs->myid;
+		response.command = ISDN_STAT_BSENT;
+		response.arg = bcs->channel;
+		response.parm.length = len;
+		bcs->cs->iif.statcallb(&response);
+	}
+}
+EXPORT_SYMBOL_GPL(gigaset_skb_sent);
+
+/* This function will be called by LL to send commands
+ * NOTE: LL ignores the returned value, for commands other than ISDN_CMD_IOCTL,
+ * so don't put too much effort into it.
+ */
+static int command_from_LL(isdn_ctrl *cntrl)
+{
+	struct cardstate *cs = gigaset_get_cs_by_id(cntrl->driver);
+	//isdn_ctrl response;
+	//unsigned long flags;
+	struct bc_state *bcs;
+	int retval = 0;
+	struct setup_parm *sp;
+
+	//dbg(DEBUG_ANY, "Gigaset_HW: Receiving command");
+	gigaset_debugdrivers();
+
+	/* Terminate this call if no device is present. Bt if the command is "ISDN_CMD_LOCK" or
+	 * "ISDN_CMD_UNLOCK" then execute it due to the fact that they are device independent !
+	 */
+	//FIXME "remove test for &connected"
+	if ((!cs || !atomic_read(&cs->connected))) {
+		warn("LL tried to access unknown device with nr. %d",
+		     cntrl->driver);
+		return -ENODEV;
+	}
+
+	switch (cntrl->command) {
+	case ISDN_CMD_IOCTL:
+
+		dbg(DEBUG_ANY, "ISDN_CMD_IOCTL (driver:%d,arg: %ld)",
+		    cntrl->driver, cntrl->arg);
+
+		warn("ISDN_CMD_IOCTL is not supported.");
+		return -EINVAL;
+
+	case ISDN_CMD_DIAL:
+		dbg(DEBUG_ANY, "ISDN_CMD_DIAL (driver: %d, channel: %ld, "
+		    "phone: %s,ownmsn: %s, si1: %d, si2: %d)",
+		    cntrl->driver, cntrl->arg,
+		    cntrl->parm.setup.phone, cntrl->parm.setup.eazmsn,
+		    cntrl->parm.setup.si1, cntrl->parm.setup.si2);
+
+		if (cntrl->arg >= cs->channels) {
+			err("invalid channel (%d)", (int) cntrl->arg);
+			return -EINVAL;
+		}
+
+		bcs = cs->bcs + cntrl->arg;
+
+		if (!gigaset_get_channel(bcs)) {
+			err("channel not free");
+			return -EBUSY;
+		}
+
+		sp = kmalloc(sizeof *sp, GFP_ATOMIC);
+		if (!sp) {
+			gigaset_free_channel(bcs);
+			err("ISDN_CMD_DIAL: out of memory");
+			return -ENOMEM;
+		}
+		*sp = cntrl->parm.setup;
+
+		if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp,
+			               atomic_read(&bcs->at_state.seq_index),
+			               NULL)) {
+			//FIXME what should we do?
+			kfree(sp);
+			gigaset_free_channel(bcs);
+			return -ENOMEM;
+		}
+
+		dbg(DEBUG_CMD, "scheduling DIAL");
+		gigaset_schedule_event(cs);
+		break;
+	case ISDN_CMD_ACCEPTD: //FIXME
+		dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTD");
+
+		if (cntrl->arg >= cs->channels) {
+			err("invalid channel (%d)", (int) cntrl->arg);
+			return -EINVAL;
+		}
+
+		if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg].at_state,
+			               EV_ACCEPT, NULL, 0, NULL)) {
+			//FIXME what should we do?
+			return -ENOMEM;
+		}
+
+		dbg(DEBUG_CMD, "scheduling ACCEPT");
+		gigaset_schedule_event(cs);
+
+		break;
+	case ISDN_CMD_ACCEPTB:
+		dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTB");
+		break;
+	case ISDN_CMD_HANGUP:
+		dbg(DEBUG_ANY,
+		    "ISDN_CMD_HANGUP (channel: %d)", (int) cntrl->arg);
+
+		if (cntrl->arg >= cs->channels) {
+			err("ISDN_CMD_HANGUP: invalid channel (%u)",
+			    (unsigned) cntrl->arg);
+			return -EINVAL;
+		}
+
+		if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg].at_state,
+			               EV_HUP, NULL, 0, NULL)) {
+			//FIXME what should we do?
+			return -ENOMEM;
+		}
+
+		dbg(DEBUG_CMD, "scheduling HUP");
+		gigaset_schedule_event(cs);
+
+		break;
+	case ISDN_CMD_CLREAZ:               /* Do not signal incoming signals */ //FIXME
+		dbg(DEBUG_ANY, "ISDN_CMD_CLREAZ");
+		break;
+	case ISDN_CMD_SETEAZ:               /* Signal incoming calls for given MSN */ //FIXME
+		dbg(DEBUG_ANY,
+		    "ISDN_CMD_SETEAZ (id:%d, channel: %ld, number: %s)",
+		    cntrl->driver, cntrl->arg, cntrl->parm.num);
+		break;
+	case ISDN_CMD_SETL2:                /* Set L2 to given protocol */
+		dbg(DEBUG_ANY, "ISDN_CMD_SETL2 (Channel: %ld, Proto: %lx)",
+		     cntrl->arg & 0xff, (cntrl->arg >> 8));
+
+		if ((cntrl->arg & 0xff) >= cs->channels) {
+			err("invalid channel (%u)",
+			    (unsigned) cntrl->arg & 0xff);
+			return -EINVAL;
+		}
+
+		if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg & 0xff].at_state,
+		                       EV_PROTO_L2, NULL, cntrl->arg >> 8,
+		                       NULL)) {
+			//FIXME what should we do?
+			return -ENOMEM;
+		}
+
+		dbg(DEBUG_CMD, "scheduling PROTO_L2");
+		gigaset_schedule_event(cs);
+		break;
+	case ISDN_CMD_SETL3:              /* Set L3 to given protocol */
+		dbg(DEBUG_ANY, "ISDN_CMD_SETL3 (Channel: %ld, Proto: %lx)",
+		     cntrl->arg & 0xff, (cntrl->arg >> 8));
+
+		if ((cntrl->arg & 0xff) >= cs->channels) {
+			err("invalid channel (%u)",
+			    (unsigned) cntrl->arg & 0xff);
+			return -EINVAL;
+		}
+
+		if (cntrl->arg >> 8 != ISDN_PROTO_L3_TRANS) {
+			err("invalid protocol %lu", cntrl->arg >> 8);
+			return -EINVAL;
+		}
+
+		break;
+	case ISDN_CMD_PROCEED:
+		dbg(DEBUG_ANY, "ISDN_CMD_PROCEED"); //FIXME
+		break;
+	case ISDN_CMD_ALERT:
+		dbg(DEBUG_ANY, "ISDN_CMD_ALERT"); //FIXME
+		if (cntrl->arg >= cs->channels) {
+			err("invalid channel (%d)", (int) cntrl->arg);
+			return -EINVAL;
+		}
+		//bcs = cs->bcs + cntrl->arg;
+		//bcs->proto2 = -1;
+		// FIXME
+		break;
+	case ISDN_CMD_REDIR:
+		dbg(DEBUG_ANY, "ISDN_CMD_REDIR"); //FIXME
+		break;
+	case ISDN_CMD_PROT_IO:
+		dbg(DEBUG_ANY, "ISDN_CMD_PROT_IO");
+		break;
+	case ISDN_CMD_FAXCMD:
+		dbg(DEBUG_ANY, "ISDN_CMD_FAXCMD");
+		break;
+	case ISDN_CMD_GETL2:
+		dbg(DEBUG_ANY, "ISDN_CMD_GETL2");
+		break;
+	case ISDN_CMD_GETL3:
+		dbg(DEBUG_ANY, "ISDN_CMD_GETL3");
+		break;
+	case ISDN_CMD_GETEAZ:
+		dbg(DEBUG_ANY, "ISDN_CMD_GETEAZ");
+		break;
+	case ISDN_CMD_SETSIL:
+		dbg(DEBUG_ANY, "ISDN_CMD_SETSIL");
+		break;
+	case ISDN_CMD_GETSIL:
+		dbg(DEBUG_ANY, "ISDN_CMD_GETSIL");
+		break;
+	default:
+		err("unknown command %d from LL",
+		     cntrl->command);
+		return -EINVAL;
+	}
+
+	return retval;
+}
+
+void gigaset_i4l_cmd(struct cardstate *cs, int cmd)
+{
+	isdn_ctrl command;
+
+	command.driver = cs->myid;
+	command.command = cmd;
+	command.arg = 0;
+	cs->iif.statcallb(&command);
+}
+
+void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd)
+{
+	isdn_ctrl command;
+
+	command.driver = bcs->cs->myid;
+	command.command = cmd;
+	command.arg = bcs->channel;
+	bcs->cs->iif.statcallb(&command);
+}
+
+int gigaset_isdn_setup_dial(struct at_state_t *at_state, void *data)
+{
+	struct bc_state *bcs = at_state->bcs;
+	unsigned proto;
+	const char *bc;
+	size_t length[AT_NUM];
+	size_t l;
+	int i;
+	struct setup_parm *sp = data;
+
+	switch (bcs->proto2) {
+	case ISDN_PROTO_L2_HDLC:
+		proto = 1; /* 0: Bitsynchron, 1: HDLC, 2: voice */
+		break;
+	case ISDN_PROTO_L2_TRANS:
+		proto = 2; /* 0: Bitsynchron, 1: HDLC, 2: voice */
+		break;
+	default:
+		err("invalid protocol: %u", bcs->proto2);
+		return -EINVAL;
+	}
+
+	switch (sp->si1) {
+	case 1:		/* audio */
+		bc = "9090A3";	/* 3.1 kHz audio, A-law */
+		break;
+	case 7:		/* data */
+	default:	/* hope the app knows what it is doing */
+		bc = "8890";	/* unrestricted digital information */
+	}
+	//FIXME add missing si1 values from 1TR6, inspect si2, set HLC/LLC
+
+	length[AT_DIAL ] = 1 + strlen(sp->phone) + 1 + 1;
+	l = strlen(sp->eazmsn);
+	length[AT_MSN  ] = l ? 6 + l + 1 + 1 : 0;
+	length[AT_BC   ] = 5 + strlen(bc) + 1 + 1;
+	length[AT_PROTO] = 6 + 1 + 1 + 1; /* proto: 1 character */
+	length[AT_ISO  ] = 6 + 1 + 1 + 1; /* channel: 1 character */
+	length[AT_TYPE ] = 6 + 1 + 1 + 1; /* call type: 1 character */
+	length[AT_HLC  ] = 0;
+
+	for (i = 0; i < AT_NUM; ++i) {
+		kfree(bcs->commands[i]);
+		bcs->commands[i] = NULL;
+		if (length[i] &&
+		    !(bcs->commands[i] = kmalloc(length[i], GFP_ATOMIC))) {
+			err("out of memory");
+			return -ENOMEM;
+		}
+	}
+
+	/* type = 1: extern, 0: intern, 2: recall, 3: door, 4: centrex */
+	if (sp->phone[0] == '*' && sp->phone[1] == '*') {
+		/* internal call: translate ** prefix to CTP value */
+		snprintf(bcs->commands[AT_DIAL], length[AT_DIAL],
+			 "D%s\r", sp->phone+2);
+		strncpy(bcs->commands[AT_TYPE], "^SCTP=0\r", length[AT_TYPE]);
+	} else {
+		snprintf(bcs->commands[AT_DIAL], length[AT_DIAL],
+			 "D%s\r", sp->phone);
+		strncpy(bcs->commands[AT_TYPE], "^SCTP=1\r", length[AT_TYPE]);
+	}
+
+	if (bcs->commands[AT_MSN])
+		snprintf(bcs->commands[AT_MSN], length[AT_MSN], "^SMSN=%s\r", sp->eazmsn);
+	snprintf(bcs->commands[AT_BC   ], length[AT_BC   ], "^SBC=%s\r", bc);
+	snprintf(bcs->commands[AT_PROTO], length[AT_PROTO], "^SBPR=%u\r", proto);
+	snprintf(bcs->commands[AT_ISO  ], length[AT_ISO  ], "^SISO=%u\r", (unsigned)bcs->channel + 1);
+
+	return 0;
+}
+
+int gigaset_isdn_setup_accept(struct at_state_t *at_state)
+{
+	unsigned proto;
+	size_t length[AT_NUM];
+	int i;
+	struct bc_state *bcs = at_state->bcs;
+
+	switch (bcs->proto2) {
+	case ISDN_PROTO_L2_HDLC:
+		proto = 1; /* 0: Bitsynchron, 1: HDLC, 2: voice */
+		break;
+	case ISDN_PROTO_L2_TRANS:
+		proto = 2; /* 0: Bitsynchron, 1: HDLC, 2: voice */
+		break;
+	default:
+		err("invalid protocol: %u", bcs->proto2);
+		return -EINVAL;
+	}
+
+	length[AT_DIAL ] = 0;
+	length[AT_MSN  ] = 0;
+	length[AT_BC   ] = 0;
+	length[AT_PROTO] = 6 + 1 + 1 + 1; /* proto: 1 character */
+	length[AT_ISO  ] = 6 + 1 + 1 + 1; /* channel: 1 character */
+	length[AT_TYPE ] = 0;
+	length[AT_HLC  ] = 0;
+
+	for (i = 0; i < AT_NUM; ++i) {
+		kfree(bcs->commands[i]);
+		bcs->commands[i] = NULL;
+		if (length[i] &&
+		    !(bcs->commands[i] = kmalloc(length[i], GFP_ATOMIC))) {
+			err("out of memory");
+			return -ENOMEM;
+		}
+	}
+
+	snprintf(bcs->commands[AT_PROTO], length[AT_PROTO], "^SBPR=%u\r", proto);
+	snprintf(bcs->commands[AT_ISO  ], length[AT_ISO  ], "^SISO=%u\r", (unsigned) bcs->channel + 1);
+
+	return 0;
+}
+
+int gigaset_isdn_icall(struct at_state_t *at_state)
+{
+	struct cardstate *cs = at_state->cs;
+	struct bc_state *bcs = at_state->bcs;
+	isdn_ctrl response;
+	int retval;
+
+	/* fill ICALL structure */
+	response.parm.setup.si1 = 0;	/* default: unknown */
+	response.parm.setup.si2 = 0;
+	response.parm.setup.screen = 0;	//FIXME how to set these?
+	response.parm.setup.plan = 0;
+	if (!at_state->str_var[STR_ZBC]) {
+		/* no BC (internal call): assume speech, A-law */
+		response.parm.setup.si1 = 1;
+	} else if (!strcmp(at_state->str_var[STR_ZBC], "8890")) {
+		/* unrestricted digital information */
+		response.parm.setup.si1 = 7;
+	} else if (!strcmp(at_state->str_var[STR_ZBC], "8090A3")) {
+		/* speech, A-law */
+		response.parm.setup.si1 = 1;
+	} else if (!strcmp(at_state->str_var[STR_ZBC], "9090A3")) {
+		/* 3,1 kHz audio, A-law */
+		response.parm.setup.si1 = 1;
+		response.parm.setup.si2 = 2;
+	} else {
+		warn("RING ignored - unsupported BC %s",
+		     at_state->str_var[STR_ZBC]);
+		return ICALL_IGNORE;
+	}
+	if (at_state->str_var[STR_NMBR]) {
+		strncpy(response.parm.setup.phone, at_state->str_var[STR_NMBR],
+			sizeof response.parm.setup.phone - 1);
+		response.parm.setup.phone[sizeof response.parm.setup.phone - 1] = 0;
+	} else
+		response.parm.setup.phone[0] = 0;
+	if (at_state->str_var[STR_ZCPN]) {
+		strncpy(response.parm.setup.eazmsn, at_state->str_var[STR_ZCPN],
+			sizeof response.parm.setup.eazmsn - 1);
+		response.parm.setup.eazmsn[sizeof response.parm.setup.eazmsn - 1] = 0;
+	} else
+		response.parm.setup.eazmsn[0] = 0;
+
+	if (!bcs) {
+		notice("no channel for incoming call");
+		dbg(DEBUG_CMD, "Sending ICALLW");
+		response.command = ISDN_STAT_ICALLW;
+		response.arg = 0; //FIXME
+	} else {
+		dbg(DEBUG_CMD, "Sending ICALL");
+		response.command = ISDN_STAT_ICALL;
+		response.arg = bcs->channel; //FIXME
+	}
+	response.driver = cs->myid;
+	retval = cs->iif.statcallb(&response);
+	dbg(DEBUG_CMD, "Response: %d", retval);
+	switch (retval) {
+	case 0:	/* no takers */
+		return ICALL_IGNORE;
+	case 1:	/* alerting */
+		bcs->chstate |= CHS_NOTIFY_LL;
+		return ICALL_ACCEPT;
+	case 2:	/* reject */
+		return ICALL_REJECT;
+	case 3:	/* incomplete */
+		warn("LL requested unsupported feature: Incomplete Number");
+		return ICALL_IGNORE;
+	case 4:	/* proceeding */
+		/* Gigaset will send ALERTING anyway.
+		 * There doesn't seem to be a way to avoid this.
+		 */
+		return ICALL_ACCEPT;
+	case 5:	/* deflect */
+		warn("LL requested unsupported feature: Call Deflection");
+		return ICALL_IGNORE;
+	default:
+		err("LL error %d on ICALL", retval);
+		return ICALL_IGNORE;
+	}
+}
+
+/* Set Callback function pointer */
+int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid)
+{
+	isdn_if *iif = &cs->iif;
+
+	dbg(DEBUG_ANY, "Register driver capabilities to LL");
+
+	//iif->id[sizeof(iif->id) - 1]=0;
+	//strncpy(iif->id, isdnid, sizeof(iif->id) - 1);
+	if (snprintf(iif->id, sizeof iif->id, "%s_%u", isdnid, cs->minor_index)
+	    >= sizeof iif->id)
+		return -ENOMEM; //FIXME EINVAL/...??
+
+	iif->owner = THIS_MODULE;
+	iif->channels = cs->channels;                        /* I am supporting just one channel *//* I was supporting...*/
+	iif->maxbufsize = MAX_BUF_SIZE;
+	iif->features = ISDN_FEATURE_L2_TRANS |   /* Our device is very advanced, therefore */
+		ISDN_FEATURE_L2_HDLC |
+#ifdef GIG_X75
+		ISDN_FEATURE_L2_X75I |
+#endif
+		ISDN_FEATURE_L3_TRANS |
+		ISDN_FEATURE_P_EURO;
+	iif->hl_hdrlen = HW_HDR_LEN;              /* Area for storing ack */
+	iif->command = command_from_LL;
+	iif->writebuf_skb = writebuf_from_LL;
+	iif->writecmd = NULL;                     /* Don't support isdnctrl */
+	iif->readstat = NULL;                     /* Don't support isdnctrl */
+	iif->rcvcallb_skb = NULL;                 /* Will be set by LL */
+	iif->statcallb = NULL;                    /* Will be set by LL */
+
+	if (!register_isdn(iif))
+		return 0;
+
+	cs->myid = iif->channels;                 /* Set my device id */
+	return 1;
+}
diff -urN oldtree/drivers/isdn/gigaset/interface.c newtree/drivers/isdn/gigaset/interface.c
--- oldtree/drivers/isdn/gigaset/interface.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/isdn/gigaset/interface.c	2006-02-21 15:58:32.912143152 +0000
@@ -0,0 +1,718 @@
+/*
+ * interface to user space for the gigaset driver
+ *
+ * Copyright (c) 2004 by Hansjoerg Lipp <hjlipp@web.de>
+ *
+ * =====================================================================
+ *    This program is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU General Public License as
+ *    published by the Free Software Foundation; either version 2 of
+ *    the License, or (at your option) any later version.
+ * =====================================================================
+ * Version: $Id: interface.c,v 1.14.4.15 2006/02/04 18:28:16 hjlipp Exp $
+ * =====================================================================
+ */
+
+#include "gigaset.h"
+#include <linux/gigaset_dev.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+/*** our ioctls ***/
+
+static int if_lock(struct cardstate *cs, int *arg)
+{
+	int cmd = *arg;
+
+	dbg(DEBUG_IF, "%u: if_lock (%d)", cs->minor_index, cmd);
+
+	if (cmd > 1)
+		return -EINVAL;
+
+	if (cmd < 0) {
+		*arg = atomic_read(&cs->mstate) == MS_LOCKED; //FIXME remove?
+		return 0;
+	}
+
+	if (!cmd && atomic_read(&cs->mstate) == MS_LOCKED
+	    && atomic_read(&cs->connected)) {
+		cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
+		cs->ops->baud_rate(cs, B115200);
+		cs->ops->set_line_ctrl(cs, CS8);
+		cs->control_state = TIOCM_DTR|TIOCM_RTS;
+	}
+
+	cs->waiting = 1;
+	if (!gigaset_add_event(cs, &cs->at_state, EV_IF_LOCK,
+		               NULL, cmd, NULL)) {
+		cs->waiting = 0;
+		return -ENOMEM;
+	}
+
+	dbg(DEBUG_CMD, "scheduling IF_LOCK");
+	gigaset_schedule_event(cs);
+
+	wait_event(cs->waitqueue, !cs->waiting);
+
+	if (cs->cmd_result >= 0) {
+		*arg = cs->cmd_result;
+		return 0;
+	}
+
+	return cs->cmd_result;
+}
+
+static int if_version(struct cardstate *cs, unsigned arg[4])
+{
+	static const unsigned version[4] = GIG_VERSION;
+	static const unsigned compat[4] = GIG_COMPAT;
+	unsigned cmd = arg[0];
+
+	dbg(DEBUG_IF, "%u: if_version (%d)", cs->minor_index, cmd);
+
+	switch (cmd) {
+	case GIGVER_DRIVER:
+		memcpy(arg, version, sizeof version);
+		return 0;
+	case GIGVER_COMPAT:
+		memcpy(arg, compat, sizeof compat);
+		return 0;
+	case GIGVER_FWBASE:
+		cs->waiting = 1;
+		if (!gigaset_add_event(cs, &cs->at_state, EV_IF_VER,
+			               NULL, 0, arg)) {
+			cs->waiting = 0;
+			return -ENOMEM;
+		}
+
+		dbg(DEBUG_CMD, "scheduling IF_VER");
+		gigaset_schedule_event(cs);
+
+		wait_event(cs->waitqueue, !cs->waiting);
+
+		if (cs->cmd_result >= 0)
+			return 0;
+
+		return cs->cmd_result;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int if_config(struct cardstate *cs, int *arg)
+{
+	dbg(DEBUG_IF, "%u: if_config (%d)", cs->minor_index, *arg);
+
+	if (*arg != 1)
+		return -EINVAL;
+
+	if (atomic_read(&cs->mstate) != MS_LOCKED)
+		return -EBUSY;
+
+	*arg = 0;
+	return gigaset_enterconfigmode(cs);
+}
+
+/*** the terminal driver ***/
+/* stolen from usbserial and some other tty drivers */
+
+static int  if_open(struct tty_struct *tty, struct file *filp);
+static void if_close(struct tty_struct *tty, struct file *filp);
+static int  if_ioctl(struct tty_struct *tty, struct file *file,
+                     unsigned int cmd, unsigned long arg);
+static int  if_write_room(struct tty_struct *tty);
+static int  if_chars_in_buffer(struct tty_struct *tty);
+static void if_throttle(struct tty_struct *tty);
+static void if_unthrottle(struct tty_struct *tty);
+static void if_set_termios(struct tty_struct *tty, struct termios *old);
+static int  if_tiocmget(struct tty_struct *tty, struct file *file);
+static int  if_tiocmset(struct tty_struct *tty, struct file *file,
+                        unsigned int set, unsigned int clear);
+static int  if_write(struct tty_struct *tty,
+                     const unsigned char *buf, int count);
+
+static struct tty_operations if_ops = {
+	.open =			if_open,
+	.close =		if_close,
+	.ioctl =		if_ioctl,
+	.write =		if_write,
+	.write_room =		if_write_room,
+	.chars_in_buffer =	if_chars_in_buffer,
+	.set_termios =		if_set_termios,
+	.throttle =		if_throttle,
+	.unthrottle =		if_unthrottle,
+#if 0
+	.break_ctl =		serial_break,
+#endif
+	.tiocmget =		if_tiocmget,
+	.tiocmset =		if_tiocmset,
+};
+
+static int if_open(struct tty_struct *tty, struct file *filp)
+{
+	struct cardstate *cs;
+	unsigned long flags;
+
+	dbg(DEBUG_IF, "%d+%d: %s()", tty->driver->minor_start, tty->index,
+	    __FUNCTION__);
+
+	tty->driver_data = NULL;
+
+	cs = gigaset_get_cs_by_tty(tty);
+	if (!cs)
+		return -ENODEV;
+
+	if (down_interruptible(&cs->sem))
+		return -ERESTARTSYS; // FIXME -EINTR?
+	tty->driver_data = cs;
+
+	++cs->open_count;
+
+	if (cs->open_count == 1) {
+		spin_lock_irqsave(&cs->lock, flags);
+		cs->tty = tty;
+		spin_unlock_irqrestore(&cs->lock, flags);
+		tty->low_latency = 1; //FIXME test
+		//FIXME
+	}
+
+	up(&cs->sem);
+	return 0;
+}
+
+static void if_close(struct tty_struct *tty, struct file *filp)
+{
+	struct cardstate *cs;
+	unsigned long flags;
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return;
+	}
+
+	dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+
+	down(&cs->sem);
+
+	if (!cs->open_count)
+		warn("%s: device not opened", __FUNCTION__);
+	else {
+		if (!--cs->open_count) {
+			spin_lock_irqsave(&cs->lock, flags);
+			cs->tty = NULL;
+			spin_unlock_irqrestore(&cs->lock, flags);
+			//FIXME
+		}
+	}
+
+	up(&cs->sem);
+}
+
+static int if_ioctl(struct tty_struct *tty, struct file *file,
+                    unsigned int cmd, unsigned long arg)
+{
+	struct cardstate *cs;
+	int retval = -ENODEV;
+	int int_arg;
+	unsigned char buf[6];
+	unsigned version[4];
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __FUNCTION__, cmd);
+
+	if (down_interruptible(&cs->sem))
+		return -ERESTARTSYS; // FIXME -EINTR?
+
+	if (!cs->open_count)
+		warn("%s: device not opened", __FUNCTION__);
+	else {
+		retval = 0;
+		switch (cmd) {
+		case GIGASET_REDIR:
+			retval = get_user(int_arg, (int __user *) arg);
+			if (retval >= 0)
+				retval = if_lock(cs, &int_arg);
+			if (retval >= 0)
+				retval = put_user(int_arg, (int __user *) arg);
+			break;
+		case GIGASET_CONFIG:
+			retval = get_user(int_arg, (int __user *) arg);
+			if (retval >= 0)
+				retval = if_config(cs, &int_arg);
+			if (retval >= 0)
+				retval = put_user(int_arg, (int __user *) arg);
+			break;
+		case GIGASET_BRKCHARS:
+			//FIXME test if MS_LOCKED
+			gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS",
+			                   6, (const unsigned char *) arg, 1);
+			if (!atomic_read(&cs->connected)) {
+				dbg(DEBUG_ANY, "can't communicate with unplugged device");
+				retval = -ENODEV;
+				break;
+			}
+			retval = copy_from_user(&buf,
+			                        (const unsigned char __user *) arg, 6)
+			         ? -EFAULT : 0;
+			if (retval >= 0)
+				retval = cs->ops->brkchars(cs, buf);
+			break;
+		case GIGASET_VERSION:
+			retval = copy_from_user(version, (unsigned __user *) arg,
+			                        sizeof version) ? -EFAULT : 0;
+			if (retval >= 0)
+				retval = if_version(cs, version);
+			if (retval >= 0)
+				retval = copy_to_user((unsigned __user *) arg, version,
+				                      sizeof version)
+				         ? -EFAULT : 0;
+			break;
+	        default:
+			dbg(DEBUG_ANY, "%s: arg not supported - 0x%04x",
+			    __FUNCTION__, cmd);
+			retval = -ENOIOCTLCMD;
+		}
+	}
+
+	up(&cs->sem);
+
+	return retval;
+}
+
+static int if_tiocmget(struct tty_struct *tty, struct file *file)
+{
+	struct cardstate *cs;
+	int retval;
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+
+	if (down_interruptible(&cs->sem))
+		return -ERESTARTSYS; // FIXME -EINTR?
+
+	// FIXME read from device?
+	retval = cs->control_state & (TIOCM_RTS|TIOCM_DTR);
+
+	up(&cs->sem);
+
+	return retval;
+}
+
+static int if_tiocmset(struct tty_struct *tty, struct file *file,
+                       unsigned int set, unsigned int clear)
+{
+	struct cardstate *cs;
+	int retval;
+	unsigned mc;
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	dbg(DEBUG_IF,
+	    "%u: %s(0x%x, 0x%x)", cs->minor_index, __FUNCTION__, set, clear);
+
+	if (down_interruptible(&cs->sem))
+		return -ERESTARTSYS; // FIXME -EINTR?
+
+	if (!atomic_read(&cs->connected)) {
+		dbg(DEBUG_ANY, "can't communicate with unplugged device");
+		retval = -ENODEV;
+	} else {
+		mc = (cs->control_state | set) & ~clear & (TIOCM_RTS|TIOCM_DTR);
+		retval = cs->ops->set_modem_ctrl(cs, cs->control_state, mc);
+		cs->control_state = mc;
+	}
+
+	up(&cs->sem);
+
+	return retval;
+}
+
+static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+	struct cardstate *cs;
+	int retval = -ENODEV;
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+
+	if (down_interruptible(&cs->sem))
+		return -ERESTARTSYS; // FIXME -EINTR?
+
+	if (!cs->open_count)
+		warn("%s: device not opened", __FUNCTION__);
+	else if (atomic_read(&cs->mstate) != MS_LOCKED) {
+		warn("can't write to unlocked device");
+		retval = -EBUSY;
+	} else if (!atomic_read(&cs->connected)) {
+		dbg(DEBUG_ANY, "can't write to unplugged device");
+		retval = -EBUSY; //FIXME
+	} else {
+		retval = cs->ops->write_cmd(cs, buf, count,
+		                            &cs->if_wake_tasklet);
+	}
+
+	up(&cs->sem);
+
+	return retval;
+}
+
+static int if_write_room(struct tty_struct *tty)
+{
+	struct cardstate *cs;
+	int retval = -ENODEV;
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+
+	if (down_interruptible(&cs->sem))
+		return -ERESTARTSYS; // FIXME -EINTR?
+
+	if (!cs->open_count)
+		warn("%s: device not opened", __FUNCTION__);
+	else if (atomic_read(&cs->mstate) != MS_LOCKED) {
+		warn("can't write to unlocked device");
+		retval = -EBUSY; //FIXME
+	} else if (!atomic_read(&cs->connected)) {
+		dbg(DEBUG_ANY, "can't write to unplugged device");
+		retval = -EBUSY; //FIXME
+	} else
+		retval = cs->ops->write_room(cs);
+
+	up(&cs->sem);
+
+	return retval;
+}
+
+static int if_chars_in_buffer(struct tty_struct *tty)
+{
+	struct cardstate *cs;
+	int retval = -ENODEV;
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+
+	if (down_interruptible(&cs->sem))
+		return -ERESTARTSYS; // FIXME -EINTR?
+
+	if (!cs->open_count)
+		warn("%s: device not opened", __FUNCTION__);
+	else if (atomic_read(&cs->mstate) != MS_LOCKED) {
+		warn("can't write to unlocked device");
+		retval = -EBUSY;
+	} else if (!atomic_read(&cs->connected)) {
+		dbg(DEBUG_ANY, "can't write to unplugged device");
+		retval = -EBUSY; //FIXME
+	} else
+		retval = cs->ops->chars_in_buffer(cs);
+
+	up(&cs->sem);
+
+	return retval;
+}
+
+static void if_throttle(struct tty_struct *tty)
+{
+	struct cardstate *cs;
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return;
+	}
+
+	dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+
+	down(&cs->sem);
+
+	if (!cs->open_count)
+		warn("%s: device not opened", __FUNCTION__);
+	else {
+		//FIXME
+	}
+
+	up(&cs->sem);
+}
+
+static void if_unthrottle(struct tty_struct *tty)
+{
+	struct cardstate *cs;
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return;
+	}
+
+	dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+
+	down(&cs->sem);
+
+	if (!cs->open_count)
+		warn("%s: device not opened", __FUNCTION__);
+	else {
+		//FIXME
+	}
+
+	up(&cs->sem);
+}
+
+static void if_set_termios(struct tty_struct *tty, struct termios *old)
+{
+	struct cardstate *cs;
+	unsigned int iflag;
+	unsigned int cflag;
+	unsigned int old_cflag;
+	unsigned int control_state, new_state;
+
+	cs = (struct cardstate *) tty->driver_data;
+	if (!cs) {
+		err("cs==NULL in %s", __FUNCTION__);
+		return;
+	}
+
+	dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+
+	down(&cs->sem);
+
+	if (!cs->open_count) {
+		warn("%s: device not opened", __FUNCTION__);
+		goto out;
+	}
+
+	if (!atomic_read(&cs->connected)) {
+		dbg(DEBUG_ANY, "can't communicate with unplugged device");
+		goto out;
+	}
+
+	// stolen from mct_u232.c
+	iflag = tty->termios->c_iflag;
+	cflag = tty->termios->c_cflag;
+	old_cflag = old ? old->c_cflag : cflag; //FIXME?
+	dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x", cs->minor_index,
+	    iflag, cflag, old_cflag);
+
+	/* get a local copy of the current port settings */
+	control_state = cs->control_state;
+
+	/*
+	 * Update baud rate.
+	 * Do not attempt to cache old rates and skip settings,
+	 * disconnects screw such tricks up completely.
+	 * Premature optimization is the root of all evil.
+	 */
+
+        /* reassert DTR and (maybe) RTS on transition from B0 */
+	if ((old_cflag & CBAUD) == B0) {
+		new_state = control_state | TIOCM_DTR;
+		/* don't set RTS if using hardware flow control */
+		if (!(old_cflag & CRTSCTS))
+			new_state |= TIOCM_RTS;
+		dbg(DEBUG_IF, "%u: from B0 - set DTR%s", cs->minor_index,
+		    (new_state & TIOCM_RTS) ? " only" : "/RTS");
+		cs->ops->set_modem_ctrl(cs, control_state, new_state);
+		control_state = new_state;
+	}
+
+	cs->ops->baud_rate(cs, cflag & CBAUD);
+
+	if ((cflag & CBAUD) == B0) {
+		/* Drop RTS and DTR */
+		dbg(DEBUG_IF, "%u: to B0 - drop DTR/RTS", cs->minor_index);
+		new_state = control_state & ~(TIOCM_DTR | TIOCM_RTS);
+		cs->ops->set_modem_ctrl(cs, control_state, new_state);
+		control_state = new_state;
+	}
+
+	/*
+	 * Update line control register (LCR)
+	 */
+
+	cs->ops->set_line_ctrl(cs, cflag);
+
+#if 0
+	//FIXME this hangs M101 [ts 2005-03-09]
+	//FIXME do we need this?
+	/*
+	 * Set flow control: well, I do not really now how to handle DTR/RTS.
+	 * Just do what we have seen with SniffUSB on Win98.
+	 */
+	/* Drop DTR/RTS if no flow control otherwise assert */
+	dbg(DEBUG_IF, "%u: control_state %x", cs->minor_index, control_state);
+	new_state = control_state;
+	if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
+		new_state |= TIOCM_DTR | TIOCM_RTS;
+	else
+		new_state &= ~(TIOCM_DTR | TIOCM_RTS);
+	if (new_state != control_state) {
+		dbg(DEBUG_IF, "%u: new_state %x", cs->minor_index, new_state);
+		gigaset_set_modem_ctrl(cs, control_state, new_state); // FIXME: mct_u232.c sets the old state here. is this a bug?
+		control_state = new_state;
+	}
+#endif
+
+	/* save off the modified port settings */
+	cs->control_state = control_state;
+
+out:
+	up(&cs->sem);
+}
+
+
+/* wakeup tasklet for the write operation */
+static void if_wake(unsigned long data)
+{
+	struct cardstate *cs = (struct cardstate *) data;
+	struct tty_struct *tty;
+
+	tty = cs->tty;
+	if (!tty)
+		return;
+
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup) {
+		dbg(DEBUG_IF, "write wakeup call");
+		tty->ldisc.write_wakeup(tty);
+	}
+
+	wake_up_interruptible(&tty->write_wait);
+}
+
+/*** interface to common ***/
+
+void gigaset_if_init(struct cardstate *cs)
+{
+	struct gigaset_driver *drv;
+
+	drv = cs->driver;
+	if (!drv->have_tty)
+		return;
+
+	tasklet_init(&cs->if_wake_tasklet, &if_wake, (unsigned long) cs);
+	tty_register_device(drv->tty, cs->minor_index, NULL);
+}
+
+void gigaset_if_free(struct cardstate *cs)
+{
+	struct gigaset_driver *drv;
+
+	drv = cs->driver;
+	if (!drv->have_tty)
+		return;
+
+	tasklet_disable(&cs->if_wake_tasklet);
+	tasklet_kill(&cs->if_wake_tasklet);
+	tty_unregister_device(drv->tty, cs->minor_index);
+}
+
+void gigaset_if_receive(struct cardstate *cs,
+                        unsigned char *buffer, size_t len)
+{
+	unsigned long flags;
+	struct tty_struct *tty;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	if ((tty = cs->tty) == NULL)
+		dbg(DEBUG_ANY, "receive on closed device");
+	else {
+		tty_buffer_request_room(tty, len);
+		tty_insert_flip_string(tty, buffer, len);
+		tty_flip_buffer_push(tty);
+	}
+	spin_unlock_irqrestore(&cs->lock, flags);
+}
+EXPORT_SYMBOL_GPL(gigaset_if_receive);
+
+/* gigaset_if_initdriver
+ * Initialize tty interface.
+ * parameters:
+ *      drv             Driver
+ *      procname        Name of the driver (e.g. for /proc/tty/drivers)
+ *      devname         Name of the device files (prefix without minor number)
+ *      devfsname       Devfs name of the device files without %d
+ */
+void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
+                           const char *devname, const char *devfsname)
+{
+	unsigned minors = drv->minors;
+	int ret;
+	struct tty_driver *tty;
+
+	drv->have_tty = 0;
+
+	if ((drv->tty = alloc_tty_driver(minors)) == NULL)
+		goto enomem;
+	tty = drv->tty;
+
+	tty->magic =		TTY_DRIVER_MAGIC,
+	tty->major =		GIG_MAJOR,
+	tty->type =		TTY_DRIVER_TYPE_SERIAL,
+	tty->subtype =		SERIAL_TYPE_NORMAL,
+	tty->flags =		TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+
+	tty->driver_name =	procname;
+	tty->name =		devname;
+	tty->minor_start =	drv->minor;
+	tty->num =		drv->minors;
+
+	tty->owner =		THIS_MODULE;
+	tty->devfs_name =	devfsname;
+
+	tty->init_termios          = tty_std_termios; //FIXME
+	tty->init_termios.c_cflag  = B9600 | CS8 | CREAD | HUPCL | CLOCAL; //FIXME
+	tty_set_operations(tty, &if_ops);
+
+	ret = tty_register_driver(tty);
+	if (ret < 0) {
+		warn("failed to register tty driver (error %d)", ret);
+		goto error;
+	}
+	dbg(DEBUG_IF, "tty driver initialized");
+	drv->have_tty = 1;
+	return;
+
+enomem:
+	warn("could not allocate tty structures");
+error:
+	if (drv->tty)
+		put_tty_driver(drv->tty);
+}
+
+void gigaset_if_freedriver(struct gigaset_driver *drv)
+{
+	if (!drv->have_tty)
+		return;
+
+	drv->have_tty = 0;
+	tty_unregister_driver(drv->tty);
+	put_tty_driver(drv->tty);
+}
diff -urN oldtree/drivers/isdn/gigaset/isocdata.c newtree/drivers/isdn/gigaset/isocdata.c
--- oldtree/drivers/isdn/gigaset/isocdata.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/isdn/gigaset/isocdata.c	2006-02-21 15:58:32.972134032 +0000
@@ -0,0 +1,1009 @@
+/*
+ * Common data handling layer for bas_gigaset
+ *
+ * Copyright (c) 2005 by Tilman Schmidt <tilman@imap.cc>,
+ *                       Hansjoerg Lipp <hjlipp@web.de>.
+ *
+ * =====================================================================
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation; either version 2 of
+ *	the License, or (at your option) any later version.
+ * =====================================================================
+ * ToDo: ...
+ * =====================================================================
+ * Version: $Id: isocdata.c,v 1.2.2.5 2005/11/13 23:05:19 hjlipp Exp $
+ * =====================================================================
+ */
+
+#include "gigaset.h"
+#include <linux/crc-ccitt.h>
+
+/* access methods for isowbuf_t */
+/* ============================ */
+
+/* initialize buffer structure
+ */
+void gigaset_isowbuf_init(struct isowbuf_t *iwb, unsigned char idle)
+{
+	atomic_set(&iwb->read, 0);
+	atomic_set(&iwb->nextread, 0);
+	atomic_set(&iwb->write, 0);
+	atomic_set(&iwb->writesem, 1);
+	iwb->wbits = 0;
+	iwb->idle = idle;
+	memset(iwb->data + BAS_OUTBUFSIZE, idle, BAS_OUTBUFPAD);
+}
+
+/* compute number of bytes which can be appended to buffer
+ * so that there is still room to append a maximum frame of flags
+ */
+static inline int isowbuf_freebytes(struct isowbuf_t *iwb)
+{
+	int read, write, freebytes;
+
+	read = atomic_read(&iwb->read);
+	write = atomic_read(&iwb->write);
+	if ((freebytes = read - write) > 0) {
+		/* no wraparound: need padding space within regular area */
+		return freebytes - BAS_OUTBUFPAD;
+	} else if (read < BAS_OUTBUFPAD) {
+		/* wraparound: can use space up to end of regular area */
+		return BAS_OUTBUFSIZE - write;
+	} else {
+		/* following the wraparound yields more space */
+		return freebytes + BAS_OUTBUFSIZE - BAS_OUTBUFPAD;
+	}
+}
+
+/* compare two offsets within the buffer
+ * The buffer is seen as circular, with the read position as start
+ * returns -1/0/1 if position a </=/> position b without crossing 'read'
+ */
+static inline int isowbuf_poscmp(struct isowbuf_t *iwb, int a, int b)
+{
+	int read;
+	if (a == b)
+		return 0;
+	read = atomic_read(&iwb->read);
+	if (a < b) {
+		if (a < read && read <= b)
+			return +1;
+		else
+			return -1;
+	} else {
+		if (b < read && read <= a)
+			return -1;
+		else
+			return +1;
+	}
+}
+
+/* start writing
+ * acquire the write semaphore
+ * return true if acquired, false if busy
+ */
+static inline int isowbuf_startwrite(struct isowbuf_t *iwb)
+{
+	if (!atomic_dec_and_test(&iwb->writesem)) {
+		atomic_inc(&iwb->writesem);
+		dbg(DEBUG_ISO,
+		    "%s: couldn't acquire iso write semaphore", __func__);
+		return 0;
+	}
+#ifdef CONFIG_GIGASET_DEBUG
+	dbg(DEBUG_ISO,
+	    "%s: acquired iso write semaphore, data[write]=%02x, nbits=%d",
+	    __func__, iwb->data[atomic_read(&iwb->write)], iwb->wbits);
+#endif
+	return 1;
+}
+
+/* finish writing
+ * release the write semaphore and update the maximum buffer fill level
+ * returns the current write position
+ */
+static inline int isowbuf_donewrite(struct isowbuf_t *iwb)
+{
+	int write = atomic_read(&iwb->write);
+	atomic_inc(&iwb->writesem);
+	return write;
+}
+
+/* append bits to buffer without any checks
+ * - data contains bits to append, starting at LSB
+ * - nbits is number of bits to append (0..24)
+ * must be called with the write semaphore held
+ * If more than nbits bits are set in data, the extraneous bits are set in the
+ * buffer too, but the write position is only advanced by nbits.
+ */
+static inline void isowbuf_putbits(struct isowbuf_t *iwb, u32 data, int nbits)
+{
+	int write = atomic_read(&iwb->write);
+	data <<= iwb->wbits;
+	data |= iwb->data[write];
+	nbits += iwb->wbits;
+	while (nbits >= 8) {
+		iwb->data[write++] = data & 0xff;
+		write %= BAS_OUTBUFSIZE;
+		data >>= 8;
+		nbits -= 8;
+	}
+	iwb->wbits = nbits;
+	iwb->data[write] = data & 0xff;
+	atomic_set(&iwb->write, write);
+}
+
+/* put final flag on HDLC bitstream
+ * also sets the idle fill byte to the correspondingly shifted flag pattern
+ * must be called with the write semaphore held
+ */
+static inline void isowbuf_putflag(struct isowbuf_t *iwb)
+{
+	int write;
+
+	/* add two flags, thus reliably covering one byte */
+	isowbuf_putbits(iwb, 0x7e7e, 8);
+	/* recover the idle flag byte */
+	write = atomic_read(&iwb->write);
+	iwb->idle = iwb->data[write];
+	dbg(DEBUG_ISO, "idle fill byte %02x", iwb->idle);
+	/* mask extraneous bits in buffer */
+	iwb->data[write] &= (1 << iwb->wbits) - 1;
+}
+
+/* retrieve a block of bytes for sending
+ * The requested number of bytes is provided as a contiguous block.
+ * If necessary, the frame is filled to the requested number of bytes
+ * with the idle value.
+ * returns offset to frame, < 0 on busy or error
+ */
+int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
+{
+	int read, write, limit, src, dst;
+	unsigned char pbyte;
+
+	read = atomic_read(&iwb->nextread);
+	write = atomic_read(&iwb->write);
+	if (likely(read == write)) {
+		//dbg(DEBUG_STREAM, "%s: send buffer empty", __func__);
+		/* return idle frame */
+		return read < BAS_OUTBUFPAD ?
+		        BAS_OUTBUFSIZE : read - BAS_OUTBUFPAD;
+	}
+
+	limit = read + size;
+	dbg(DEBUG_STREAM,
+	    "%s: read=%d write=%d limit=%d", __func__, read, write, limit);
+#ifdef CONFIG_GIGASET_DEBUG
+	if (unlikely(size < 0 || size > BAS_OUTBUFPAD)) {
+		err("invalid size %d", size);
+		return -EINVAL;
+	}
+	src = atomic_read(&iwb->read);
+	if (unlikely(limit > BAS_OUTBUFSIZE + BAS_OUTBUFPAD ||
+		     (read < src && limit >= src))) {
+		err("isoc write buffer frame reservation violated");
+		return -EFAULT;
+	}
+#endif
+
+	if (read < write) {
+		/* no wraparound in valid data */
+		if (limit >= write) {
+			/* append idle frame */
+			if (!isowbuf_startwrite(iwb))
+				return -EBUSY;
+			/* write position could have changed */
+			if (limit >= (write = atomic_read(&iwb->write))) {
+				pbyte = iwb->data[write]; /* save partial byte */
+				limit = write + BAS_OUTBUFPAD;
+				dbg(DEBUG_STREAM,
+				    "%s: filling %d->%d with %02x",
+				    __func__, write, limit, iwb->idle);
+				if (write + BAS_OUTBUFPAD < BAS_OUTBUFSIZE)
+					memset(iwb->data + write, iwb->idle,
+					       BAS_OUTBUFPAD);
+				else {
+					/* wraparound, fill entire pad area */
+					memset(iwb->data + write, iwb->idle,
+					       BAS_OUTBUFSIZE + BAS_OUTBUFPAD
+					       - write);
+					limit = 0;
+				}
+				dbg(DEBUG_STREAM, "%s: restoring %02x at %d",
+				    __func__, pbyte, limit);
+				iwb->data[limit] = pbyte; /* restore partial byte */
+				atomic_set(&iwb->write, limit);
+			}
+			isowbuf_donewrite(iwb);
+		}
+	} else {
+		/* valid data wraparound */
+		if (limit >= BAS_OUTBUFSIZE) {
+			/* copy wrapped part into pad area */
+			src = 0;
+			dst = BAS_OUTBUFSIZE;
+			while (dst < limit && src < write)
+				iwb->data[dst++] = iwb->data[src++];
+			if (dst <= limit) {
+				/* fill pad area with idle byte */
+				memset(iwb->data + dst, iwb->idle,
+				       BAS_OUTBUFSIZE + BAS_OUTBUFPAD - dst);
+			}
+			limit = src;
+		}
+	}
+	atomic_set(&iwb->nextread, limit);
+	return read;
+}
+
+/* dump_bytes
+ * write hex bytes to syslog for debugging
+ */
+static inline void dump_bytes(enum debuglevel level, const char *tag,
+                              unsigned char *bytes, int count)
+{
+#ifdef CONFIG_GIGASET_DEBUG
+	unsigned char c;
+	static char dbgline[3 * 32 + 1];
+	static const char hexdigit[] = "0123456789abcdef";
+	int i = 0;
+	IFNULLRET(tag);
+	IFNULLRET(bytes);
+	while (count-- > 0) {
+		if (i > sizeof(dbgline) - 4) {
+			dbgline[i] = '\0';
+			dbg(level, "%s:%s", tag, dbgline);
+			i = 0;
+		}
+		c = *bytes++;
+		dbgline[i] = (i && !(i % 12)) ? '-' : ' ';
+		i++;
+		dbgline[i++] = hexdigit[(c >> 4) & 0x0f];
+		dbgline[i++] = hexdigit[c & 0x0f];
+	}
+	dbgline[i] = '\0';
+	dbg(level, "%s:%s", tag, dbgline);
+#endif
+}
+
+/*============================================================================*/
+
+/* bytewise HDLC bitstuffing via table lookup
+ * lookup table: 5 subtables for 0..4 preceding consecutive '1' bits
+ * index: 256*(number of preceding '1' bits) + (next byte to stuff)
+ * value: bit  9.. 0 = result bits
+ *        bit 12..10 = number of trailing '1' bits in result
+ *        bit 14..13 = number of bits added by stuffing
+ */
+static u16 stufftab[5 * 256] = {
+// previous 1s = 0:
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x201f,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x205f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x209f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20df,
+ 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x048f,
+ 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x251f,
+ 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x04af,
+ 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x255f,
+ 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x08c7, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x08cf,
+ 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x08d7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x299f,
+ 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x0ce7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x0cef,
+ 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x10f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x2ddf,
+
+// previous 1s = 1:
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x200f,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x202f,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x204f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x206f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x208f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x20af,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x20cf,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20ef,
+ 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x250f,
+ 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x252f,
+ 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x254f,
+ 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x256f,
+ 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x08c7, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x298f,
+ 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x08d7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x29af,
+ 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x0ce7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x2dcf,
+ 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x10f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x31ef,
+
+// previous 1s = 2:
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x2007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x2017,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x2027, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x2037,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x2047, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x2057,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x2067, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x2077,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x2087, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x2097,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x20a7, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x20b7,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x20c7, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x20d7,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x20e7, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20f7,
+ 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x2507, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x2517,
+ 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x2527, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x2537,
+ 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x2547, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x2557,
+ 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x2567, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x2577,
+ 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x2987, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x2997,
+ 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x29a7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x29b7,
+ 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x2dc7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x2dd7,
+ 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x31e7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x41f7,
+
+// previous 1s = 3:
+ 0x0000, 0x0001, 0x0002, 0x2003, 0x0004, 0x0005, 0x0006, 0x200b, 0x0008, 0x0009, 0x000a, 0x2013, 0x000c, 0x000d, 0x000e, 0x201b,
+ 0x0010, 0x0011, 0x0012, 0x2023, 0x0014, 0x0015, 0x0016, 0x202b, 0x0018, 0x0019, 0x001a, 0x2033, 0x001c, 0x001d, 0x001e, 0x203b,
+ 0x0020, 0x0021, 0x0022, 0x2043, 0x0024, 0x0025, 0x0026, 0x204b, 0x0028, 0x0029, 0x002a, 0x2053, 0x002c, 0x002d, 0x002e, 0x205b,
+ 0x0030, 0x0031, 0x0032, 0x2063, 0x0034, 0x0035, 0x0036, 0x206b, 0x0038, 0x0039, 0x003a, 0x2073, 0x003c, 0x003d, 0x203e, 0x207b,
+ 0x0040, 0x0041, 0x0042, 0x2083, 0x0044, 0x0045, 0x0046, 0x208b, 0x0048, 0x0049, 0x004a, 0x2093, 0x004c, 0x004d, 0x004e, 0x209b,
+ 0x0050, 0x0051, 0x0052, 0x20a3, 0x0054, 0x0055, 0x0056, 0x20ab, 0x0058, 0x0059, 0x005a, 0x20b3, 0x005c, 0x005d, 0x005e, 0x20bb,
+ 0x0060, 0x0061, 0x0062, 0x20c3, 0x0064, 0x0065, 0x0066, 0x20cb, 0x0068, 0x0069, 0x006a, 0x20d3, 0x006c, 0x006d, 0x006e, 0x20db,
+ 0x0070, 0x0071, 0x0072, 0x20e3, 0x0074, 0x0075, 0x0076, 0x20eb, 0x0078, 0x0079, 0x007a, 0x20f3, 0x207c, 0x207d, 0x20be, 0x40fb,
+ 0x0480, 0x0481, 0x0482, 0x2503, 0x0484, 0x0485, 0x0486, 0x250b, 0x0488, 0x0489, 0x048a, 0x2513, 0x048c, 0x048d, 0x048e, 0x251b,
+ 0x0490, 0x0491, 0x0492, 0x2523, 0x0494, 0x0495, 0x0496, 0x252b, 0x0498, 0x0499, 0x049a, 0x2533, 0x049c, 0x049d, 0x049e, 0x253b,
+ 0x04a0, 0x04a1, 0x04a2, 0x2543, 0x04a4, 0x04a5, 0x04a6, 0x254b, 0x04a8, 0x04a9, 0x04aa, 0x2553, 0x04ac, 0x04ad, 0x04ae, 0x255b,
+ 0x04b0, 0x04b1, 0x04b2, 0x2563, 0x04b4, 0x04b5, 0x04b6, 0x256b, 0x04b8, 0x04b9, 0x04ba, 0x2573, 0x04bc, 0x04bd, 0x253e, 0x257b,
+ 0x08c0, 0x08c1, 0x08c2, 0x2983, 0x08c4, 0x08c5, 0x08c6, 0x298b, 0x08c8, 0x08c9, 0x08ca, 0x2993, 0x08cc, 0x08cd, 0x08ce, 0x299b,
+ 0x08d0, 0x08d1, 0x08d2, 0x29a3, 0x08d4, 0x08d5, 0x08d6, 0x29ab, 0x08d8, 0x08d9, 0x08da, 0x29b3, 0x08dc, 0x08dd, 0x08de, 0x29bb,
+ 0x0ce0, 0x0ce1, 0x0ce2, 0x2dc3, 0x0ce4, 0x0ce5, 0x0ce6, 0x2dcb, 0x0ce8, 0x0ce9, 0x0cea, 0x2dd3, 0x0cec, 0x0ced, 0x0cee, 0x2ddb,
+ 0x10f0, 0x10f1, 0x10f2, 0x31e3, 0x10f4, 0x10f5, 0x10f6, 0x31eb, 0x20f8, 0x20f9, 0x20fa, 0x41f3, 0x257c, 0x257d, 0x29be, 0x46fb,
+
+// previous 1s = 4:
+ 0x0000, 0x2001, 0x0002, 0x2005, 0x0004, 0x2009, 0x0006, 0x200d, 0x0008, 0x2011, 0x000a, 0x2015, 0x000c, 0x2019, 0x000e, 0x201d,
+ 0x0010, 0x2021, 0x0012, 0x2025, 0x0014, 0x2029, 0x0016, 0x202d, 0x0018, 0x2031, 0x001a, 0x2035, 0x001c, 0x2039, 0x001e, 0x203d,
+ 0x0020, 0x2041, 0x0022, 0x2045, 0x0024, 0x2049, 0x0026, 0x204d, 0x0028, 0x2051, 0x002a, 0x2055, 0x002c, 0x2059, 0x002e, 0x205d,
+ 0x0030, 0x2061, 0x0032, 0x2065, 0x0034, 0x2069, 0x0036, 0x206d, 0x0038, 0x2071, 0x003a, 0x2075, 0x003c, 0x2079, 0x203e, 0x407d,
+ 0x0040, 0x2081, 0x0042, 0x2085, 0x0044, 0x2089, 0x0046, 0x208d, 0x0048, 0x2091, 0x004a, 0x2095, 0x004c, 0x2099, 0x004e, 0x209d,
+ 0x0050, 0x20a1, 0x0052, 0x20a5, 0x0054, 0x20a9, 0x0056, 0x20ad, 0x0058, 0x20b1, 0x005a, 0x20b5, 0x005c, 0x20b9, 0x005e, 0x20bd,
+ 0x0060, 0x20c1, 0x0062, 0x20c5, 0x0064, 0x20c9, 0x0066, 0x20cd, 0x0068, 0x20d1, 0x006a, 0x20d5, 0x006c, 0x20d9, 0x006e, 0x20dd,
+ 0x0070, 0x20e1, 0x0072, 0x20e5, 0x0074, 0x20e9, 0x0076, 0x20ed, 0x0078, 0x20f1, 0x007a, 0x20f5, 0x207c, 0x40f9, 0x20be, 0x417d,
+ 0x0480, 0x2501, 0x0482, 0x2505, 0x0484, 0x2509, 0x0486, 0x250d, 0x0488, 0x2511, 0x048a, 0x2515, 0x048c, 0x2519, 0x048e, 0x251d,
+ 0x0490, 0x2521, 0x0492, 0x2525, 0x0494, 0x2529, 0x0496, 0x252d, 0x0498, 0x2531, 0x049a, 0x2535, 0x049c, 0x2539, 0x049e, 0x253d,
+ 0x04a0, 0x2541, 0x04a2, 0x2545, 0x04a4, 0x2549, 0x04a6, 0x254d, 0x04a8, 0x2551, 0x04aa, 0x2555, 0x04ac, 0x2559, 0x04ae, 0x255d,
+ 0x04b0, 0x2561, 0x04b2, 0x2565, 0x04b4, 0x2569, 0x04b6, 0x256d, 0x04b8, 0x2571, 0x04ba, 0x2575, 0x04bc, 0x2579, 0x253e, 0x467d,
+ 0x08c0, 0x2981, 0x08c2, 0x2985, 0x08c4, 0x2989, 0x08c6, 0x298d, 0x08c8, 0x2991, 0x08ca, 0x2995, 0x08cc, 0x2999, 0x08ce, 0x299d,
+ 0x08d0, 0x29a1, 0x08d2, 0x29a5, 0x08d4, 0x29a9, 0x08d6, 0x29ad, 0x08d8, 0x29b1, 0x08da, 0x29b5, 0x08dc, 0x29b9, 0x08de, 0x29bd,
+ 0x0ce0, 0x2dc1, 0x0ce2, 0x2dc5, 0x0ce4, 0x2dc9, 0x0ce6, 0x2dcd, 0x0ce8, 0x2dd1, 0x0cea, 0x2dd5, 0x0cec, 0x2dd9, 0x0cee, 0x2ddd,
+ 0x10f0, 0x31e1, 0x10f2, 0x31e5, 0x10f4, 0x31e9, 0x10f6, 0x31ed, 0x20f8, 0x41f1, 0x20fa, 0x41f5, 0x257c, 0x46f9, 0x29be, 0x4b7d
+};
+
+/* hdlc_bitstuff_byte
+ * perform HDLC bitstuffing for one input byte (8 bits, LSB first)
+ * parameters:
+ *	cin	input byte
+ *	ones	number of trailing '1' bits in result before this step
+ *	iwb	pointer to output buffer structure (write semaphore must be held)
+ * return value:
+ *	number of trailing '1' bits in result after this step
+ */
+
+static inline int hdlc_bitstuff_byte(struct isowbuf_t *iwb, unsigned char cin,
+                                     int ones)
+{
+	u16 stuff;
+	int shiftinc, newones;
+
+	/* get stuffing information for input byte
+	 * value: bit  9.. 0 = result bits
+	 *        bit 12..10 = number of trailing '1' bits in result
+	 *        bit 14..13 = number of bits added by stuffing
+	 */
+	stuff = stufftab[256 * ones + cin];
+	shiftinc = (stuff >> 13) & 3;
+	newones = (stuff >> 10) & 7;
+	stuff &= 0x3ff;
+
+	/* append stuffed byte to output stream */
+	isowbuf_putbits(iwb, stuff, 8 + shiftinc);
+	return newones;
+}
+
+/* hdlc_buildframe
+ * Perform HDLC framing with bitstuffing on a byte buffer
+ * The input buffer is regarded as a sequence of bits, starting with the least
+ * significant bit of the first byte and ending with the most significant bit
+ * of the last byte. A 16 bit FCS is appended as defined by RFC 1662.
+ * Whenever five consecutive '1' bits appear in the resulting bit sequence, a
+ * '0' bit is inserted after them.
+ * The resulting bit string and a closing flag pattern (PPP_FLAG, '01111110')
+ * are appended to the output buffer starting at the given bit position, which
+ * is assumed to already contain a leading flag.
+ * The output buffer must have sufficient length; count + count/5 + 6 bytes
+ * starting at *out are safe and are verified to be present.
+ * parameters:
+ *	in	input buffer
+ *	count	number of bytes in input buffer
+ *	iwb	pointer to output buffer structure (write semaphore must be held)
+ * return value:
+ *	position of end of packet in output buffer on success,
+ *	-EAGAIN if write semaphore busy or buffer full
+ */
+
+static inline int hdlc_buildframe(struct isowbuf_t *iwb,
+                                  unsigned char *in, int count)
+{
+	int ones;
+	u16 fcs;
+	int end;
+	unsigned char c;
+
+	if (isowbuf_freebytes(iwb) < count + count / 5 + 6 ||
+	    !isowbuf_startwrite(iwb)) {
+		dbg(DEBUG_ISO, "%s: %d bytes free -> -EAGAIN",
+		    __func__, isowbuf_freebytes(iwb));
+		return -EAGAIN;
+	}
+
+	dump_bytes(DEBUG_STREAM, "snd data", in, count);
+
+	/* bitstuff and checksum input data */
+	fcs = PPP_INITFCS;
+	ones = 0;
+	while (count-- > 0) {
+		c = *in++;
+		ones = hdlc_bitstuff_byte(iwb, c, ones);
+		fcs = crc_ccitt_byte(fcs, c);
+	}
+
+	/* bitstuff and append FCS (complemented, least significant byte first) */
+	fcs ^= 0xffff;
+	ones = hdlc_bitstuff_byte(iwb, fcs & 0x00ff, ones);
+	ones = hdlc_bitstuff_byte(iwb, (fcs >> 8) & 0x00ff, ones);
+
+	/* put closing flag and repeat byte for flag idle */
+	isowbuf_putflag(iwb);
+	end = isowbuf_donewrite(iwb);
+	dump_bytes(DEBUG_STREAM_DUMP, "isowbuf", iwb->data, end + 1);
+	return end;
+}
+
+/* trans_buildframe
+ * Append a block of 'transparent' data to the output buffer,
+ * inverting the bytes.
+ * The output buffer must have sufficient length; count bytes
+ * starting at *out are safe and are verified to be present.
+ * parameters:
+ *	in	input buffer
+ *	count	number of bytes in input buffer
+ *	iwb	pointer to output buffer structure (write semaphore must be held)
+ * return value:
+ *	position of end of packet in output buffer on success,
+ *	-EAGAIN if write semaphore busy or buffer full
+ */
+
+static inline int trans_buildframe(struct isowbuf_t *iwb,
+				   unsigned char *in, int count)
+{
+	int write;
+	unsigned char c;
+
+	if (unlikely(count <= 0))
+		return atomic_read(&iwb->write); /* better ideas? */
+
+	if (isowbuf_freebytes(iwb) < count ||
+	    !isowbuf_startwrite(iwb)) {
+		dbg(DEBUG_ISO, "can't put %d bytes", count);
+		return -EAGAIN;
+	}
+
+	dbg(DEBUG_STREAM, "put %d bytes", count);
+	write = atomic_read(&iwb->write);
+	do {
+		c = gigaset_invtab[*in++];
+		iwb->data[write++] = c;
+		write %= BAS_OUTBUFSIZE;
+	} while (--count > 0);
+	atomic_set(&iwb->write, write);
+	iwb->idle = c;
+
+	return isowbuf_donewrite(iwb);
+}
+
+int gigaset_isoc_buildframe(struct bc_state *bcs, unsigned char *in, int len)
+{
+	int result;
+
+	switch (bcs->proto2) {
+	case ISDN_PROTO_L2_HDLC:
+		result = hdlc_buildframe(bcs->hw.bas->isooutbuf, in, len);
+		dbg(DEBUG_ISO, "%s: %d bytes HDLC -> %d", __func__, len, result);
+		break;
+	default:			/* assume transparent */
+		result = trans_buildframe(bcs->hw.bas->isooutbuf, in, len);
+		dbg(DEBUG_ISO, "%s: %d bytes trans -> %d", __func__, len, result);
+	}
+	return result;
+}
+
+/* hdlc_putbyte
+ * append byte c to current skb of B channel structure *bcs, updating fcs
+ */
+static inline void hdlc_putbyte(unsigned char c, struct bc_state *bcs)
+{
+	bcs->fcs = crc_ccitt_byte(bcs->fcs, c);
+	if (unlikely(bcs->skb == NULL)) {
+		/* skipping */
+		return;
+	}
+	if (unlikely(bcs->skb->len == SBUFSIZE)) {
+		warn("received oversized packet discarded");
+		bcs->hw.bas->giants++;
+		dev_kfree_skb_any(bcs->skb);
+		bcs->skb = NULL;
+		return;
+	}
+	*gigaset_skb_put_quick(bcs->skb, 1) = c;
+}
+
+/* hdlc_flush
+ * drop partial HDLC data packet
+ */
+static inline void hdlc_flush(struct bc_state *bcs)
+{
+	/* clear skb or allocate new if not skipping */
+	if (likely(bcs->skb != NULL))
+		skb_trim(bcs->skb, 0);
+	else if (!bcs->ignore) {
+		if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
+			skb_reserve(bcs->skb, HW_HDR_LEN);
+		else
+			err("could not allocate skb");
+	}
+
+	/* reset packet state */
+	bcs->fcs = PPP_INITFCS;
+}
+
+/* hdlc_done
+ * process completed HDLC data packet
+ */
+static inline void hdlc_done(struct bc_state *bcs)
+{
+	struct sk_buff *procskb;
+
+	if (unlikely(bcs->ignore)) {
+		bcs->ignore--;
+		hdlc_flush(bcs);
+		return;
+	}
+
+	if ((procskb = bcs->skb) == NULL) {
+		/* previous error */
+		dbg(DEBUG_ISO, "%s: skb=NULL", __func__);
+		gigaset_rcv_error(NULL, bcs->cs, bcs);
+	} else if (procskb->len < 2) {
+		notice("received short frame (%d octets)", procskb->len);
+		bcs->hw.bas->runts++;
+		gigaset_rcv_error(procskb, bcs->cs, bcs);
+	} else if (bcs->fcs != PPP_GOODFCS) {
+		notice("frame check error (0x%04x)", bcs->fcs);
+		bcs->hw.bas->fcserrs++;
+		gigaset_rcv_error(procskb, bcs->cs, bcs);
+	} else {
+		procskb->len -= 2;		/* subtract FCS */
+		procskb->tail -= 2;
+		dbg(DEBUG_ISO,
+		    "%s: good frame (%d octets)", __func__, procskb->len);
+		dump_bytes(DEBUG_STREAM,
+		           "rcv data", procskb->data, procskb->len);
+		bcs->hw.bas->goodbytes += procskb->len;
+		gigaset_rcv_skb(procskb, bcs->cs, bcs);
+	}
+
+	if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
+		skb_reserve(bcs->skb, HW_HDR_LEN);
+	else
+		err("could not allocate skb");
+	bcs->fcs = PPP_INITFCS;
+}
+
+/* hdlc_frag
+ * drop HDLC data packet with non-integral last byte
+ */
+static inline void hdlc_frag(struct bc_state *bcs, unsigned inbits)
+{
+	if (unlikely(bcs->ignore)) {
+		bcs->ignore--;
+		hdlc_flush(bcs);
+		return;
+	}
+
+	notice("received partial byte (%d bits)", inbits);
+	bcs->hw.bas->alignerrs++;
+	gigaset_rcv_error(bcs->skb, bcs->cs, bcs);
+
+	if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
+		skb_reserve(bcs->skb, HW_HDR_LEN);
+	else
+		err("could not allocate skb");
+	bcs->fcs = PPP_INITFCS;
+}
+
+/* bit counts lookup table for HDLC bit unstuffing
+ * index: input byte
+ * value: bit 0..3 = number of consecutive '1' bits starting from LSB
+ *        bit 4..6 = number of consecutive '1' bits starting from MSB
+ *		     (replacing 8 by 7 to make it fit; the algorithm won't care)
+ *        bit 7 set if there are 5 or more "interior" consecutive '1' bits
+ */
+static unsigned char bitcounts[256] = {
+  0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04,
+  0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05,
+  0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04,
+  0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x80, 0x06,
+  0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04,
+  0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05,
+  0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04,
+  0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x80, 0x81, 0x80, 0x07,
+  0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x14,
+  0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x15,
+  0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x14,
+  0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x90, 0x16,
+  0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x23, 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x24,
+  0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x23, 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x25,
+  0x30, 0x31, 0x30, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x31, 0x30, 0x32, 0x30, 0x31, 0x30, 0x34,
+  0x40, 0x41, 0x40, 0x42, 0x40, 0x41, 0x40, 0x43, 0x50, 0x51, 0x50, 0x52, 0x60, 0x61, 0x70, 0x78
+};
+
+/* hdlc_unpack
+ * perform HDLC frame processing (bit unstuffing, flag detection, FCS calculation)
+ * on a sequence of received data bytes (8 bits each, LSB first)
+ * pass on successfully received, complete frames as SKBs via gigaset_rcv_skb
+ * notify of errors via gigaset_rcv_error
+ * tally frames, errors etc. in BC structure counters
+ * parameters:
+ *	src	received data
+ *	count	number of received bytes
+ *	bcs	receiving B channel structure
+ */
+static inline void hdlc_unpack(unsigned char *src, unsigned count,
+                               struct bc_state *bcs)
+{
+	struct bas_bc_state *ubc;
+	int inputstate;
+	unsigned seqlen, inbyte, inbits;
+
+	IFNULLRET(bcs);
+	ubc = bcs->hw.bas;
+	IFNULLRET(ubc);
+
+	/* load previous state:
+	 * inputstate = set of flag bits:
+	 * - INS_flag_hunt: no complete opening flag received since connection setup or last abort
+	 * - INS_have_data: at least one complete data byte received since last flag
+	 * seqlen = number of consecutive '1' bits in last 7 input stream bits (0..7)
+	 * inbyte = accumulated partial data byte (if !INS_flag_hunt)
+	 * inbits = number of valid bits in inbyte, starting at LSB (0..6)
+	 */
+	inputstate = bcs->inputstate;
+	seqlen = ubc->seqlen;
+	inbyte = ubc->inbyte;
+	inbits = ubc->inbits;
+
+	/* bit unstuffing a byte a time
+	 * Take your time to understand this; it's straightforward but tedious.
+	 * The "bitcounts" lookup table is used to speed up the counting of
+	 * leading and trailing '1' bits.
+	 */
+	while (count--) {
+		unsigned char c = *src++;
+		unsigned char tabentry = bitcounts[c];
+		unsigned lead1 = tabentry & 0x0f;
+		unsigned trail1 = (tabentry >> 4) & 0x0f;
+
+		seqlen += lead1;
+
+		if (unlikely(inputstate & INS_flag_hunt)) {
+			if (c == PPP_FLAG) {
+				/* flag-in-one */
+				inputstate &= ~(INS_flag_hunt | INS_have_data);
+				inbyte = 0;
+				inbits = 0;
+			} else if (seqlen == 6 && trail1 != 7) {
+				/* flag completed & not followed by abort */
+				inputstate &= ~(INS_flag_hunt | INS_have_data);
+				inbyte = c >> (lead1 + 1);
+				inbits = 7 - lead1;
+				if (trail1 >= 8) {
+					/* interior stuffing: omitting the MSB handles most cases */
+					inbits--;
+					/* correct the incorrectly handled cases individually */
+					switch (c) {
+					case 0xbe:
+						inbyte = 0x3f;
+						break;
+					}
+				}
+			}
+			/* else: continue flag-hunting */
+		} else if (likely(seqlen < 5 && trail1 < 7)) {
+			/* streamlined case: 8 data bits, no stuffing */
+			inbyte |= c << inbits;
+			hdlc_putbyte(inbyte & 0xff, bcs);
+			inputstate |= INS_have_data;
+			inbyte >>= 8;
+			/* inbits unchanged */
+		} else if (likely(seqlen == 6 && inbits == 7 - lead1 &&
+				  trail1 + 1 == inbits &&
+				  !(inputstate & INS_have_data))) {
+			/* streamlined case: flag idle - state unchanged */
+		} else if (unlikely(seqlen > 6)) {
+			/* abort sequence */
+			ubc->aborts++;
+			hdlc_flush(bcs);
+			inputstate |= INS_flag_hunt;
+		} else if (seqlen == 6) {
+			/* closing flag, including (6 - lead1) '1's and one '0' from inbits */
+			if (inbits > 7 - lead1) {
+				hdlc_frag(bcs, inbits + lead1 - 7);
+				inputstate &= ~INS_have_data;
+			} else {
+				if (inbits < 7 - lead1)
+					ubc->stolen0s ++;
+				if (inputstate & INS_have_data) {
+					hdlc_done(bcs);
+					inputstate &= ~INS_have_data;
+				}
+			}
+
+			if (c == PPP_FLAG) {
+				/* complete flag, LSB overlaps preceding flag */
+				ubc->shared0s ++;
+				inbits = 0;
+				inbyte = 0;
+			} else if (trail1 != 7) {
+				/* remaining bits */
+				inbyte = c >> (lead1 + 1);
+				inbits = 7 - lead1;
+				if (trail1 >= 8) {
+					/* interior stuffing: omitting the MSB handles most cases */
+					inbits--;
+					/* correct the incorrectly handled cases individually */
+					switch (c) {
+					case 0xbe:
+						inbyte = 0x3f;
+						break;
+					}
+				}
+			} else {
+				/* abort sequence follows, skb already empty anyway */
+				ubc->aborts++;
+				inputstate |= INS_flag_hunt;
+			}
+		} else { /* (seqlen < 6) && (seqlen == 5 || trail1 >= 7) */
+
+			if (c == PPP_FLAG) {
+				/* complete flag */
+				if (seqlen == 5)
+					ubc->stolen0s++;
+				if (inbits) {
+					hdlc_frag(bcs, inbits);
+					inbits = 0;
+					inbyte = 0;
+				} else if (inputstate & INS_have_data)
+					hdlc_done(bcs);
+				inputstate &= ~INS_have_data;
+			} else if (trail1 == 7) {
+				/* abort sequence */
+				ubc->aborts++;
+				hdlc_flush(bcs);
+				inputstate |= INS_flag_hunt;
+			} else {
+				/* stuffed data */
+				if (trail1 < 7) { /* => seqlen == 5 */
+					/* stuff bit at position lead1, no interior stuffing */
+					unsigned char mask = (1 << lead1) - 1;
+					c = (c & mask) | ((c & ~mask) >> 1);
+					inbyte |= c << inbits;
+					inbits += 7;
+				} else if (seqlen < 5) { /* trail1 >= 8 */
+					/* interior stuffing: omitting the MSB handles most cases */
+					/* correct the incorrectly handled cases individually */
+					switch (c) {
+					case 0xbe:
+						c = 0x7e;
+						break;
+					}
+					inbyte |= c << inbits;
+					inbits += 7;
+				} else { /* seqlen == 5 && trail1 >= 8 */
+
+					/* stuff bit at lead1 *and* interior stuffing */
+					switch (c) {	/* unstuff individually */
+					case 0x7d:
+						c = 0x3f;
+						break;
+					case 0xbe:
+						c = 0x3f;
+						break;
+					case 0x3e:
+						c = 0x1f;
+						break;
+					case 0x7c:
+						c = 0x3e;
+						break;
+					}
+					inbyte |= c << inbits;
+					inbits += 6;
+				}
+				if (inbits >= 8) {
+					inbits -= 8;
+					hdlc_putbyte(inbyte & 0xff, bcs);
+					inputstate |= INS_have_data;
+					inbyte >>= 8;
+				}
+			}
+		}
+		seqlen = trail1 & 7;
+	}
+
+	/* save new state */
+	bcs->inputstate = inputstate;
+	ubc->seqlen = seqlen;
+	ubc->inbyte = inbyte;
+	ubc->inbits = inbits;
+}
+
+/* trans_receive
+ * pass on received USB frame transparently as SKB via gigaset_rcv_skb
+ * invert bytes
+ * tally frames, errors etc. in BC structure counters
+ * parameters:
+ *	src	received data
+ *	count	number of received bytes
+ *	bcs	receiving B channel structure
+ */
+static inline void trans_receive(unsigned char *src, unsigned count,
+                                 struct bc_state *bcs)
+{
+	struct sk_buff *skb;
+	int dobytes;
+	unsigned char *dst;
+
+	if (unlikely(bcs->ignore)) {
+		bcs->ignore--;
+		hdlc_flush(bcs);
+		return;
+	}
+	if (unlikely((skb = bcs->skb) == NULL)) {
+		bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN);
+		if (!skb) {
+			err("could not allocate skb");
+			return;
+		}
+		skb_reserve(skb, HW_HDR_LEN);
+	}
+	bcs->hw.bas->goodbytes += skb->len;
+	dobytes = TRANSBUFSIZE - skb->len;
+	while (count > 0) {
+		dst = skb_put(skb, count < dobytes ? count : dobytes);
+		while (count > 0 && dobytes > 0) {
+			*dst++ = gigaset_invtab[*src++];
+			count--;
+			dobytes--;
+		}
+		if (dobytes == 0) {
+			gigaset_rcv_skb(skb, bcs->cs, bcs);
+			bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN);
+			if (!skb) {
+				err("could not allocate skb");
+				return;
+			}
+			skb_reserve(bcs->skb, HW_HDR_LEN);
+			dobytes = TRANSBUFSIZE;
+		}
+	}
+}
+
+void gigaset_isoc_receive(unsigned char *src, unsigned count, struct bc_state *bcs)
+{
+	switch (bcs->proto2) {
+	case ISDN_PROTO_L2_HDLC:
+		hdlc_unpack(src, count, bcs);
+		break;
+	default:		/* assume transparent */
+		trans_receive(src, count, bcs);
+	}
+}
+
+/* == data input =========================================================== */
+
+static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf)
+{
+	struct cardstate *cs = inbuf->cs;
+	unsigned cbytes      = cs->cbytes;
+
+	while (numbytes--) {
+		/* copy next character, check for end of line */
+		switch (cs->respdata[cbytes] = *src++) {
+		case '\r':
+		case '\n':
+			/* end of line */
+			dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)",
+			    __func__, cbytes);
+			cs->cbytes = cbytes;
+			gigaset_handle_modem_response(cs);
+			cbytes = 0;
+			break;
+		default:
+			/* advance in line buffer, checking for overflow */
+			if (cbytes < MAX_RESP_SIZE - 1)
+				cbytes++;
+			else
+				warn("response too large");
+		}
+	}
+
+	/* save state */
+	cs->cbytes = cbytes;
+}
+
+
+/* process a block of data received through the control channel
+ */
+void gigaset_isoc_input(struct inbuf_t *inbuf)
+{
+	struct cardstate *cs = inbuf->cs;
+	unsigned tail, head, numbytes;
+	unsigned char *src;
+
+	head = atomic_read(&inbuf->head);
+	while (head != (tail = atomic_read(&inbuf->tail))) {
+		dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
+		if (head > tail)
+			tail = RBUFSIZE;
+		src = inbuf->data + head;
+		numbytes = tail - head;
+		dbg(DEBUG_INTR, "processing %u bytes", numbytes);
+
+		if (atomic_read(&cs->mstate) == MS_LOCKED) {
+			gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response",
+			                   numbytes, src, 0);
+			gigaset_if_receive(inbuf->cs, src, numbytes);
+		} else {
+			gigaset_dbg_buffer(DEBUG_CMD, "received response",
+			                   numbytes, src, 0);
+			cmd_loop(src, numbytes, inbuf);
+		}
+
+		head += numbytes;
+		if (head == RBUFSIZE)
+			head = 0;
+		dbg(DEBUG_INTR, "setting head to %u", head);
+		atomic_set(&inbuf->head, head);
+	}
+}
+
+
+/* == data output ========================================================== */
+
+/* gigaset_send_skb
+ * called by common.c to queue an skb for sending
+ * and start transmission if necessary
+ * parameters:
+ *	B Channel control structure
+ *	skb
+ * return value:
+ *	number of bytes accepted for sending
+ *	(skb->len if ok, 0 if out of buffer space)
+ *	or error code (< 0, eg. -EINVAL)
+ */
+int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb)
+{
+	int len;
+
+	IFNULLRETVAL(bcs, -EFAULT);
+	IFNULLRETVAL(skb, -EFAULT);
+	len = skb->len;
+
+	skb_queue_tail(&bcs->squeue, skb);
+	dbg(DEBUG_ISO,
+	    "%s: skb queued, qlen=%d", __func__, skb_queue_len(&bcs->squeue));
+
+	/* tasklet submits URB if necessary */
+	tasklet_schedule(&bcs->hw.bas->sent_tasklet);
+
+	return len;	/* ok so far */
+}
diff -urN oldtree/drivers/isdn/gigaset/proc.c newtree/drivers/isdn/gigaset/proc.c
--- oldtree/drivers/isdn/gigaset/proc.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/isdn/gigaset/proc.c	2006-02-21 15:58:32.927140872 +0000
@@ -0,0 +1,81 @@
+/*
+ * Stuff used by all variants of the driver
+ *
+ * Copyright (c) 2001 by Stefan Eilers <Eilers.Stefan@epost.de>,
+ *                       Hansjoerg Lipp <hjlipp@web.de>,
+ *                       Tilman Schmidt <tilman@imap.cc>.
+ *
+ * =====================================================================
+ *	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.
+ * =====================================================================
+ * ToDo: ...
+ * =====================================================================
+ * Version: $Id: proc.c,v 1.5.2.13 2006/02/04 18:28:16 hjlipp Exp $
+ * =====================================================================
+ */
+
+#include "gigaset.h"
+#include <linux/ctype.h>
+
+static ssize_t show_cidmode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct cardstate *cs = usb_get_intfdata(intf);
+	return sprintf(buf, "%d\n", atomic_read(&cs->cidmode)); // FIXME use scnprintf for 13607 bit architectures (if PAGE_SIZE==4096)
+}
+
+static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct cardstate *cs = usb_get_intfdata(intf);
+	long int value;
+	char *end;
+
+	value = simple_strtol(buf, &end, 0);
+	while (*end)
+		if (!isspace(*end++))
+			return -EINVAL;
+	if (value < 0 || value > 1)
+			return -EINVAL;
+
+	if (down_interruptible(&cs->sem))
+		return -ERESTARTSYS; // FIXME -EINTR?
+
+	cs->waiting = 1;
+	if (!gigaset_add_event(cs, &cs->at_state, EV_PROC_CIDMODE,
+		               NULL, value, NULL)) {
+		cs->waiting = 0;
+		up(&cs->sem);
+		return -ENOMEM;
+	}
+
+	dbg(DEBUG_CMD, "scheduling PROC_CIDMODE");
+	gigaset_schedule_event(cs);
+
+	wait_event(cs->waitqueue, !cs->waiting);
+
+	up(&cs->sem);
+
+	return count;
+}
+
+static DEVICE_ATTR(cidmode, S_IRUGO|S_IWUSR, show_cidmode, set_cidmode);
+
+/* free sysfs for device */
+void gigaset_free_dev_sysfs(struct usb_interface *interface)
+{
+	dbg(DEBUG_INIT, "removing sysfs entries");
+	device_remove_file(&interface->dev, &dev_attr_cidmode);
+}
+EXPORT_SYMBOL_GPL(gigaset_free_dev_sysfs);
+
+/* initialize sysfs for device */
+void gigaset_init_dev_sysfs(struct usb_interface *interface)
+{
+	dbg(DEBUG_INIT, "setting up sysfs");
+	device_create_file(&interface->dev, &dev_attr_cidmode);
+}
+EXPORT_SYMBOL_GPL(gigaset_init_dev_sysfs);
diff -urN oldtree/drivers/isdn/gigaset/usb-gigaset.c newtree/drivers/isdn/gigaset/usb-gigaset.c
--- oldtree/drivers/isdn/gigaset/usb-gigaset.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/isdn/gigaset/usb-gigaset.c	2006-02-21 15:58:32.988131600 +0000
@@ -0,0 +1,1008 @@
+/*
+ * USB driver for Gigaset 307x directly or using M105 Data.
+ *
+ * Copyright (c) 2001 by Stefan Eilers <Eilers.Stefan@epost.de>
+ *                   and Hansjoerg Lipp <hjlipp@web.de>.
+ *
+ * This driver was derived from the USB skeleton driver by
+ * Greg Kroah-Hartman <greg@kroah.com>
+ *
+ * =====================================================================
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation; either version 2 of
+ *	the License, or (at your option) any later version.
+ * =====================================================================
+ * ToDo: ...
+ * =====================================================================
+ * Version: $Id: usb-gigaset.c,v 1.85.4.18 2006/02/04 18:28:16 hjlipp Exp $
+ * =====================================================================
+ */
+
+#include "gigaset.h"
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+/* Version Information */
+#define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Stefan Eilers <Eilers.Stefan@epost.de>"
+#define DRIVER_DESC "USB Driver for Gigaset 307x using M105"
+
+/* Module parameters */
+
+static int startmode = SM_ISDN;
+static int cidmode = 1;
+
+module_param(startmode, int, S_IRUGO);
+module_param(cidmode, int, S_IRUGO);
+MODULE_PARM_DESC(startmode, "start in isdn4linux mode");
+MODULE_PARM_DESC(cidmode, "Call-ID mode");
+
+#define GIGASET_MINORS     1
+#define GIGASET_MINOR      8
+#define GIGASET_MODULENAME "usb_gigaset"
+#define GIGASET_DEVFSNAME  "gig/usb/"
+#define GIGASET_DEVNAME    "ttyGU"
+
+#define IF_WRITEBUF 2000 //FIXME  // WAKEUP_CHARS: 256
+
+/* Values for the Gigaset M105 Data */
+#define USB_M105_VENDOR_ID	0x0681
+#define USB_M105_PRODUCT_ID	0x0009
+
+/* table of devices that work with this driver */
+static struct usb_device_id gigaset_table [] = {
+	{ USB_DEVICE(USB_M105_VENDOR_ID, USB_M105_PRODUCT_ID) },
+	{ }					/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, gigaset_table);
+
+/* Get a minor range for your devices from the usb maintainer */
+#define USB_SKEL_MINOR_BASE	200
+
+
+/*
+ * Control requests (empty fields: 00)
+ *
+ *       RT|RQ|VALUE|INDEX|LEN  |DATA
+ * In:
+ *       C1 08             01
+ *            Get flags (1 byte). Bits: 0=dtr,1=rts,3-7:?
+ *       C1 0F             ll ll
+ *            Get device information/status (llll: 0x200 and 0x40 seen).
+ *            Real size: I only saw MIN(llll,0x64).
+ *            Contents: seems to be always the same...
+ *              offset 0x00: Length of this structure (0x64) (len: 1,2,3 bytes)
+ *              offset 0x3c: String (16 bit chars): "MCCI USB Serial V2.0"
+ *              rest:        ?
+ * Out:
+ *       41 11
+ *            Initialize/reset device ?
+ *       41 00 xx 00
+ *            ? (xx=00 or 01; 01 on start, 00 on close)
+ *       41 07 vv mm
+ *            Set/clear flags vv=value, mm=mask (see RQ 08)
+ *       41 12 xx
+ *            Used before the following configuration requests are issued
+ *            (with xx=0x0f). I've seen other values<0xf, though.
+ *       41 01 xx xx
+ *            Set baud rate. xxxx=ceil(0x384000/rate)=trunc(0x383fff/rate)+1.
+ *       41 03 ps bb
+ *            Set byte size and parity. p:  0x20=even,0x10=odd,0x00=no parity
+ *                                     [    0x30: m, 0x40: s           ]
+ *                                     [s:  0: 1 stop bit; 1: 1.5; 2: 2]
+ *                                      bb: bits/byte (seen 7 and 8)
+ *       41 13 -- -- -- -- 10 00 ww 00 00 00 xx 00 00 00 yy 00 00 00 zz 00 00 00
+ *            ??
+ *            Initialization: 01, 40, 00, 00
+ *            Open device:    00  40, 00, 00
+ *            yy and zz seem to be equal, either 0x00 or 0x0a
+ *            (ww,xx) pairs seen: (00,00), (00,40), (01,40), (09,80), (19,80)
+ *       41 19 -- -- -- -- 06 00 00 00 00 xx 11 13
+ *            Used after every "configuration sequence" (RQ 12, RQs 01/03/13).
+ *            xx is usually 0x00 but was 0x7e before starting data transfer
+ *            in unimodem mode. So, this might be an array of characters that need
+ *            special treatment ("commit all bufferd data"?), 11=^Q, 13=^S.
+ *
+ * Unimodem mode: use "modprobe ppp_async flag_time=0" as the device _needs_ two
+ * flags per packet.
+ */
+
+static int gigaset_probe(struct usb_interface *interface,
+                         const struct usb_device_id *id);
+static void gigaset_disconnect(struct usb_interface *interface);
+
+static struct gigaset_driver *driver = NULL;
+static struct cardstate *cardstate = NULL;
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver gigaset_usb_driver = {
+	.name =         GIGASET_MODULENAME,
+	.probe =        gigaset_probe,
+	.disconnect =   gigaset_disconnect,
+	.id_table =     gigaset_table,
+};
+
+struct usb_cardstate {
+	struct usb_device       *udev;                  /* save off the usb device pointer */
+	struct usb_interface    *interface;             /* the interface for this device */
+	atomic_t                busy;                   /* bulk output in progress */
+
+	/* Output buffer for commands (M105: and data)*/
+	unsigned char           *bulk_out_buffer;       /* the buffer to send data */
+	int                     bulk_out_size;          /* the size of the send buffer */
+	__u8                    bulk_out_endpointAddr;  /* the address of the bulk out endpoint */
+	struct urb              *bulk_out_urb;          /* the urb used to transmit data */
+
+	/* Input buffer for command responses (M105: and data)*/
+	int                     rcvbuf_size;            /* the size of the receive buffer */
+	struct urb              *read_urb;              /* the urb used to receive data */
+	__u8                    int_in_endpointAddr;    /* the address of the bulk in endpoint */
+
+	char                    bchars[6];              /* req. 0x19 */
+};
+
+struct usb_bc_state {};
+
+static inline unsigned tiocm_to_gigaset(unsigned state)
+{
+	return ((state & TIOCM_DTR) ? 1 : 0) | ((state & TIOCM_RTS) ? 2 : 0);
+}
+
+#ifdef CONFIG_GIGASET_UNDOCREQ
+/* WARNING: EXPERIMENTAL! */
+static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state,
+                                  unsigned new_state)
+{
+	unsigned mask, val;
+	int r;
+
+	mask = tiocm_to_gigaset(old_state ^ new_state);
+	val = tiocm_to_gigaset(new_state);
+
+	dbg(DEBUG_USBREQ, "set flags 0x%02x with mask 0x%02x", val, mask);
+	r = usb_control_msg(cs->hw.usb->udev,
+	                    usb_sndctrlpipe(cs->hw.usb->udev, 0), 7, 0x41,
+	                    (val & 0xff) | ((mask & 0xff) << 8), 0,
+	                    NULL, 0, 2000 /*timeout??*/); // don't use this in an interrupt/BH
+	if (r < 0)
+		return r;
+	//..
+	return 0;
+}
+
+static int set_value(struct cardstate *cs, u8 req, u16 val)
+{
+	int r, r2;
+
+	dbg(DEBUG_USBREQ, "request %02x (%04x)", (unsigned)req, (unsigned)val);
+	r = usb_control_msg(cs->hw.usb->udev,
+	                    usb_sndctrlpipe(cs->hw.usb->udev, 0), 0x12, 0x41,
+	                    0xf /*?*/, 0,
+	                    NULL, 0, 2000 /*?*/); /* no idea, what this does */
+	if (r < 0) {
+		err("error %d on request 0x12", -r);
+		return r;
+	}
+
+	r = usb_control_msg(cs->hw.usb->udev,
+	                    usb_sndctrlpipe(cs->hw.usb->udev, 0), req, 0x41,
+	                    val, 0,
+	                    NULL, 0, 2000 /*?*/);
+	if (r < 0)
+		err("error %d on request 0x%02x", -r, (unsigned)req);
+
+	r2 = usb_control_msg(cs->hw.usb->udev,
+	                     usb_sndctrlpipe(cs->hw.usb->udev, 0), 0x19, 0x41,
+	                     0, 0, cs->hw.usb->bchars, 6, 2000 /*?*/);
+	if (r2 < 0)
+		err("error %d on request 0x19", -r2);
+
+	return r < 0 ? r : (r2 < 0 ? r2 : 0);
+}
+
+/* WARNING: HIGHLY EXPERIMENTAL! */
+// don't use this in an interrupt/BH
+static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag)
+{
+	u16 val;
+	u32 rate;
+
+	cflag &= CBAUD;
+
+	switch (cflag) {
+	//FIXME more values?
+	case    B300: rate =     300; break;
+	case    B600: rate =     600; break;
+	case   B1200: rate =    1200; break;
+	case   B2400: rate =    2400; break;
+	case   B4800: rate =    4800; break;
+	case   B9600: rate =    9600; break;
+	case  B19200: rate =   19200; break;
+	case  B38400: rate =   38400; break;
+	case  B57600: rate =   57600; break;
+	case B115200: rate =  115200; break;
+	default:
+		rate =  9600;
+		err("unsupported baudrate request 0x%x,"
+		    " using default of B9600", cflag);
+	}
+
+	val = 0x383fff / rate + 1;
+
+	return set_value(cs, 1, val);
+}
+
+/* WARNING: HIGHLY EXPERIMENTAL! */
+// don't use this in an interrupt/BH
+static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
+{
+	u16 val = 0;
+
+	/* set the parity */
+	if (cflag & PARENB)
+		val |= (cflag & PARODD) ? 0x10 : 0x20;
+
+	/* set the number of data bits */
+	switch (cflag & CSIZE) {
+	case CS5:
+		val |= 5 << 8; break;
+	case CS6:
+		val |= 6 << 8; break;
+	case CS7:
+		val |= 7 << 8; break;
+	case CS8:
+		val |= 8 << 8; break;
+	default:
+		err("CSIZE was not CS5-CS8, using default of 8");
+		val |= 8 << 8;
+		break;
+	}
+
+	/* set the number of stop bits */
+	if (cflag & CSTOPB) {
+		if ((cflag & CSIZE) == CS5)
+			val |= 1; /* 1.5 stop bits */ //FIXME is this okay?
+		else
+			val |= 2; /* 2 stop bits */
+	}
+
+	return set_value(cs, 3, val);
+}
+
+#else
+static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state,
+                                  unsigned new_state)
+{
+	return -EINVAL;
+}
+
+static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
+{
+	return -EINVAL;
+}
+
+static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag)
+{
+	return -EINVAL;
+}
+#endif
+
+
+ /*================================================================================================================*/
+static int gigaset_init_bchannel(struct bc_state *bcs)
+{
+	/* nothing to do for M10x */
+	gigaset_bchannel_up(bcs);
+	return 0;
+}
+
+static int gigaset_close_bchannel(struct bc_state *bcs)
+{
+	/* nothing to do for M10x */
+	gigaset_bchannel_down(bcs);
+	return 0;
+}
+
+//void send_ack_to_LL(void *data);
+static int write_modem(struct cardstate *cs);
+static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb);
+
+
+/* Handling of send queue. If there is already a skb opened, put data to
+ * the transfer buffer by calling "write_modem". Otherwise take a new skb out of the queue.
+ * This function will be called by the ISR via "transmit_chars" (USB: B-Channel Bulk callback handler
+ * via immediate task queue) or by writebuf_from_LL if the LL wants to transmit data.
+ */
+static void gigaset_modem_fill(unsigned long data)
+{
+	struct cardstate *cs = (struct cardstate *) data;
+	struct bc_state *bcs = &cs->bcs[0]; /* only one channel */
+	struct cmdbuf_t *cb;
+	unsigned long flags;
+	int again;
+
+	dbg(DEBUG_OUTPUT, "modem_fill");
+
+	if (atomic_read(&cs->hw.usb->busy)) {
+		dbg(DEBUG_OUTPUT, "modem_fill: busy");
+		return;
+	}
+
+	do {
+		again = 0;
+		if (!bcs->tx_skb) { /* no skb is being sent */
+			spin_lock_irqsave(&cs->cmdlock, flags);
+			cb = cs->cmdbuf;
+			spin_unlock_irqrestore(&cs->cmdlock, flags);
+			if (cb) { /* commands to send? */
+				dbg(DEBUG_OUTPUT, "modem_fill: cb");
+				if (send_cb(cs, cb) < 0) {
+					dbg(DEBUG_OUTPUT,
+					    "modem_fill: send_cb failed");
+					again = 1; /* no callback will be called! */
+				}
+			} else { /* skbs to send? */
+				bcs->tx_skb = skb_dequeue(&bcs->squeue);
+				if (bcs->tx_skb)
+					dbg(DEBUG_INTR,
+					    "Dequeued skb (Adr: %lx)!",
+					    (unsigned long) bcs->tx_skb);
+			}
+		}
+
+		if (bcs->tx_skb) {
+			dbg(DEBUG_OUTPUT, "modem_fill: tx_skb");
+			if (write_modem(cs) < 0) {
+				dbg(DEBUG_OUTPUT,
+				    "modem_fill: write_modem failed");
+				// FIXME should we tell the LL?
+				again = 1; /* no callback will be called! */
+			}
+		}
+	} while (again);
+}
+
+/**
+ *	gigaset_read_int_callback
+ *
+ *      It is called if the data was received from the device. This is almost similiar to
+ *      the interrupt service routine in the serial device.
+ */
+static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs)
+{
+	int resubmit = 0;
+	int r;
+	struct cardstate *cs;
+	unsigned numbytes;
+	unsigned char *src;
+	//unsigned long flags;
+	struct inbuf_t *inbuf;
+
+	IFNULLRET(urb);
+	inbuf = (struct inbuf_t *) urb->context;
+	IFNULLRET(inbuf);
+	//spin_lock_irqsave(&inbuf->lock, flags);
+	cs = inbuf->cs;
+	IFNULLGOTO(cs, exit);
+	IFNULLGOTO(cardstate, exit);
+
+	if (!atomic_read(&cs->connected)) {
+		err("%s: disconnected", __func__);
+		goto exit;
+	}
+
+	if (!urb->status) {
+		numbytes = urb->actual_length;
+
+		if (numbytes) {
+			src = inbuf->rcvbuf;
+			if (unlikely(*src))
+				warn("%s: There was no leading 0, but 0x%02x!",
+				     __func__, (unsigned) *src);
+			++src; /* skip leading 0x00 */
+			--numbytes;
+			if (gigaset_fill_inbuf(inbuf, src, numbytes)) {
+				dbg(DEBUG_INTR, "%s-->BH", __func__);
+				gigaset_schedule_event(inbuf->cs);
+			}
+		} else
+			dbg(DEBUG_INTR, "Received zero block length");
+		resubmit = 1;
+	} else {
+		/* The urb might have been killed. */
+		dbg(DEBUG_ANY, "%s - nonzero read bulk status received: %d",
+		    __func__, urb->status);
+		if (urb->status != -ENOENT) /* not killed */
+			resubmit = 1;
+	}
+exit:
+	//spin_unlock_irqrestore(&inbuf->lock, flags);
+	if (resubmit) {
+		r = usb_submit_urb(urb, SLAB_ATOMIC);
+		if (r)
+			err("error %d when resubmitting urb.", -r);
+	}
+}
+
+
+/* This callback routine is called when data was transmitted to a B-Channel.
+ * Therefore it has to check if there is still data to transmit. This
+ * happens by calling modem_fill via task queue.
+ *
+ */
+static void gigaset_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct cardstate *cs = (struct cardstate *) urb->context;
+
+	IFNULLRET(cs);
+#ifdef CONFIG_GIGASET_DEBUG
+	if (!atomic_read(&cs->connected)) {
+		err("%s:not connected", __func__);
+		return;
+	}
+#endif
+	if (urb->status)
+		err("bulk transfer failed (status %d)", -urb->status); /* That's all we can do. Communication problems
+		                                                           are handeled by timeouts or network protocols */
+
+	atomic_set(&cs->hw.usb->busy, 0);
+	tasklet_schedule(&cs->write_tasklet);
+}
+
+static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb)
+{
+	struct cmdbuf_t *tcb;
+	unsigned long flags;
+	int count;
+	int status = -ENOENT; // FIXME
+	struct usb_cardstate *ucs = cs->hw.usb;
+
+	do {
+		if (!cb->len) {
+			tcb = cb;
+
+			spin_lock_irqsave(&cs->cmdlock, flags);
+			cs->cmdbytes -= cs->curlen;
+			dbg(DEBUG_OUTPUT, "send_cb: sent %u bytes, %u left",
+			    cs->curlen, cs->cmdbytes);
+			cs->cmdbuf = cb = cb->next;
+			if (cb) {
+				cb->prev = NULL;
+				cs->curlen = cb->len;
+			} else {
+				cs->lastcmdbuf = NULL;
+				cs->curlen = 0;
+			}
+			spin_unlock_irqrestore(&cs->cmdlock, flags);
+
+			if (tcb->wake_tasklet)
+				tasklet_schedule(tcb->wake_tasklet);
+			kfree(tcb);
+		}
+		if (cb) {
+			count = min(cb->len, ucs->bulk_out_size);
+			usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev,
+			                  usb_sndbulkpipe(ucs->udev,
+			                     ucs->bulk_out_endpointAddr & 0x0f),
+			                  cb->buf + cb->offset, count,
+			                  gigaset_write_bulk_callback, cs);
+
+			cb->offset += count;
+			cb->len -= count;
+			atomic_set(&ucs->busy, 1);
+			dbg(DEBUG_OUTPUT, "send_cb: send %d bytes", count);
+
+			status = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC);
+			if (status) {
+				atomic_set(&ucs->busy, 0);
+				err("could not submit urb (error %d).",
+				    -status);
+				cb->len = 0; /* skip urb => remove cb+wakeup in next loop cycle */
+			}
+		}
+	} while (cb && status); /* bei Fehler naechster Befehl //FIXME: ist das OK? */
+
+	return status;
+}
+
+/* Write string into transbuf and send it to modem.
+ */
+static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
+                             int len, struct tasklet_struct *wake_tasklet)
+{
+	struct cmdbuf_t *cb;
+	unsigned long flags;
+
+	gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
+	                     DEBUG_TRANSCMD : DEBUG_LOCKCMD,
+	                   "CMD Transmit", len, buf, 0);
+
+	if (!atomic_read(&cs->connected)) {
+		err("%s: not connected", __func__);
+		return -ENODEV;
+	}
+
+	if (len <= 0)
+		return 0;
+
+	if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) {
+		err("%s: out of memory", __func__);
+		return -ENOMEM;
+	}
+
+	memcpy(cb->buf, buf, len);
+	cb->len = len;
+	cb->offset = 0;
+	cb->next = NULL;
+	cb->wake_tasklet = wake_tasklet;
+
+	spin_lock_irqsave(&cs->cmdlock, flags);
+	cb->prev = cs->lastcmdbuf;
+	if (cs->lastcmdbuf)
+		cs->lastcmdbuf->next = cb;
+	else {
+		cs->cmdbuf = cb;
+		cs->curlen = len;
+	}
+	cs->cmdbytes += len;
+	cs->lastcmdbuf = cb;
+	spin_unlock_irqrestore(&cs->cmdlock, flags);
+
+	tasklet_schedule(&cs->write_tasklet);
+	return len;
+}
+
+static int gigaset_write_room(struct cardstate *cs)
+{
+	unsigned long flags;
+	unsigned bytes;
+
+	spin_lock_irqsave(&cs->cmdlock, flags);
+	bytes = cs->cmdbytes;
+	spin_unlock_irqrestore(&cs->cmdlock, flags);
+
+	return bytes < IF_WRITEBUF ? IF_WRITEBUF - bytes : 0;
+}
+
+static int gigaset_chars_in_buffer(struct cardstate *cs)
+{
+	return cs->cmdbytes;
+}
+
+static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6])
+{
+#ifdef CONFIG_GIGASET_UNDOCREQ
+	gigaset_dbg_buffer(DEBUG_USBREQ, "brkchars", 6, buf, 0);
+	memcpy(cs->hw.usb->bchars, buf, 6);
+	return usb_control_msg(cs->hw.usb->udev,
+	                       usb_sndctrlpipe(cs->hw.usb->udev, 0), 0x19, 0x41,
+	                       0, 0, &buf, 6, 2000);
+#else
+	return -EINVAL;
+#endif
+}
+
+static int gigaset_freebcshw(struct bc_state *bcs)
+{
+	if (!bcs->hw.usb)
+		return 0;
+	//FIXME
+	kfree(bcs->hw.usb);
+	return 1;
+}
+
+/* Initialize the b-channel structure */
+static int gigaset_initbcshw(struct bc_state *bcs)
+{
+	bcs->hw.usb = kmalloc(sizeof(struct usb_bc_state), GFP_KERNEL);
+	if (!bcs->hw.usb)
+		return 0;
+
+	//bcs->hw.usb->trans_flg = READY_TO_TRNSMIT; /* B-Channel ready to transmit */
+	return 1;
+}
+
+static void gigaset_reinitbcshw(struct bc_state *bcs)
+{
+}
+
+static void gigaset_freecshw(struct cardstate *cs)
+{
+	//FIXME
+	tasklet_kill(&cs->write_tasklet);
+	kfree(cs->hw.usb);
+}
+
+static int gigaset_initcshw(struct cardstate *cs)
+{
+	struct usb_cardstate *ucs;
+
+	cs->hw.usb = ucs =
+		kmalloc(sizeof(struct usb_cardstate), GFP_KERNEL);
+	if (!ucs)
+		return 0;
+
+	ucs->bchars[0] = 0;
+	ucs->bchars[1] = 0;
+	ucs->bchars[2] = 0;
+	ucs->bchars[3] = 0;
+	ucs->bchars[4] = 0x11;
+	ucs->bchars[5] = 0x13;
+	ucs->bulk_out_buffer = NULL;
+	ucs->bulk_out_urb = NULL;
+	//ucs->urb_cmd_out = NULL;
+	ucs->read_urb = NULL;
+	tasklet_init(&cs->write_tasklet,
+	             &gigaset_modem_fill, (unsigned long) cs);
+
+	return 1;
+}
+
+/* Writes the data of the current open skb into the modem.
+ * We have to protect against multiple calls until the
+ * callback handler () is called , due to the fact that we
+ * are just allowed to send data once to an endpoint. Therefore
+ * we using "trans_flg" to synchonize ...
+ */
+static int write_modem(struct cardstate *cs)
+{
+	int ret;
+	int count;
+	struct bc_state *bcs = &cs->bcs[0]; /* only one channel */
+	struct usb_cardstate *ucs = cs->hw.usb;
+	//unsigned long flags;
+
+	IFNULLRETVAL(bcs->tx_skb, -EINVAL);
+
+	dbg(DEBUG_WRITE, "len: %d...", bcs->tx_skb->len);
+
+	ret = -ENODEV;
+	IFNULLGOTO(ucs->bulk_out_buffer, error);
+	IFNULLGOTO(ucs->bulk_out_urb, error);
+	ret = 0;
+
+	if (!bcs->tx_skb->len) {
+		dev_kfree_skb_any(bcs->tx_skb);
+		bcs->tx_skb = NULL;
+		return -EINVAL;
+	}
+
+	/* Copy data to bulk out buffer and  // FIXME copying not necessary
+	 * transmit data
+	 */
+	count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size);
+	memcpy(ucs->bulk_out_buffer, bcs->tx_skb->data, count);
+	skb_pull(bcs->tx_skb, count);
+
+	usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev,
+	                  usb_sndbulkpipe(ucs->udev,
+	                                  ucs->bulk_out_endpointAddr & 0x0f),
+	                  ucs->bulk_out_buffer, count,
+	                  gigaset_write_bulk_callback, cs);
+	atomic_set(&ucs->busy, 1);
+	dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count);
+
+	ret = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC);
+	if (ret) {
+		err("could not submit urb (error %d).", -ret);
+		atomic_set(&ucs->busy, 0);
+	}
+	if (!bcs->tx_skb->len) {
+		/* skb sent completely */
+		gigaset_skb_sent(bcs, bcs->tx_skb); //FIXME also, when ret<0?
+
+		dbg(DEBUG_INTR,
+		    "kfree skb (Adr: %lx)!", (unsigned long) bcs->tx_skb);
+		dev_kfree_skb_any(bcs->tx_skb);
+		bcs->tx_skb = NULL;
+	}
+
+	return ret;
+error:
+	dev_kfree_skb_any(bcs->tx_skb);
+	bcs->tx_skb = NULL;
+	return ret;
+
+}
+
+static int gigaset_probe(struct usb_interface *interface,
+                         const struct usb_device_id *id)
+{
+	int retval;
+	struct usb_device *udev = interface_to_usbdev(interface);
+	unsigned int ifnum;
+	struct usb_host_interface *hostif;
+	struct cardstate *cs = NULL;
+	struct usb_cardstate *ucs = NULL;
+	//struct usb_interface_descriptor *iface_desc;
+	struct usb_endpoint_descriptor *endpoint;
+	//isdn_ctrl command;
+	int buffer_size;
+	int alt;
+	//unsigned long flags;
+
+	info("%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)",
+	    __func__, le16_to_cpu(udev->descriptor.idVendor),
+	    le16_to_cpu(udev->descriptor.idProduct));
+
+	retval = -ENODEV; //FIXME
+
+	/* See if the device offered us matches what we can accept */
+	if ((le16_to_cpu(udev->descriptor.idVendor  != USB_M105_VENDOR_ID)) ||
+	    (le16_to_cpu(udev->descriptor.idProduct != USB_M105_PRODUCT_ID)))
+		return -ENODEV;
+
+	/* this starts to become ascii art... */
+	hostif = interface->cur_altsetting;
+	alt = hostif->desc.bAlternateSetting;
+	ifnum = hostif->desc.bInterfaceNumber; // FIXME ?
+
+	if (alt != 0 || ifnum != 0) {
+		warn("ifnum %d, alt %d", ifnum, alt);
+		return -ENODEV;
+	}
+
+	/* Reject application specific intefaces
+	 *
+	 */
+	if (hostif->desc.bInterfaceClass != 255) {
+		info("%s: Device matched, but iface_desc[%d]->bInterfaceClass==%d !",
+		       __func__, ifnum, hostif->desc.bInterfaceClass);
+		return -ENODEV;
+	}
+
+	info("%s: Device matched ... !", __func__);
+
+	cs = gigaset_getunassignedcs(driver);
+	if (!cs) {
+		warn("No free cardstate!");
+		return -ENODEV;
+	}
+	ucs = cs->hw.usb;
+
+#if 0
+	if (usb_set_configuration(udev, udev->config[0].desc.bConfigurationValue) < 0) {
+		warn("set_configuration failed");
+		goto error;
+	}
+
+
+	if (usb_set_interface(udev, ifnum/*==0*/, alt/*==0*/) < 0) {
+		warn("usb_set_interface failed, device %d interface %d altsetting %d",
+		     udev->devnum, ifnum, alt);
+		goto error;
+	}
+#endif
+
+	/* set up the endpoint information */
+	/* check out the endpoints */
+	/* We will get 2 endpoints: One for sending commands to the device (bulk out) and one to
+	 * poll messages from the device(int in).
+	 * Therefore we will have an almost similiar situation as with our serial port handler.
+	 * If an connection will be established, we will have to create data in/out pipes
+	 * dynamically...
+	 */
+
+	endpoint = &hostif->endpoint[0].desc;
+
+	buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+	ucs->bulk_out_size = buffer_size;
+	ucs->bulk_out_endpointAddr = endpoint->bEndpointAddress;
+	ucs->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
+	if (!ucs->bulk_out_buffer) {
+		err("Couldn't allocate bulk_out_buffer");
+		retval = -ENOMEM;
+		goto error;
+	}
+
+	ucs->bulk_out_urb = usb_alloc_urb(0, SLAB_KERNEL);
+	if (!ucs->bulk_out_urb) {
+		err("Couldn't allocate bulk_out_buffer");
+		retval = -ENOMEM;
+		goto error;
+	}
+
+	endpoint = &hostif->endpoint[1].desc;
+
+	atomic_set(&ucs->busy, 0);
+	ucs->udev = udev;
+	ucs->interface = interface;
+
+	ucs->read_urb = usb_alloc_urb(0, SLAB_KERNEL);
+	if (!ucs->read_urb) {
+		err("No free urbs available");
+		retval = -ENOMEM;
+		goto error;
+	}
+	buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+	ucs->rcvbuf_size = buffer_size;
+	ucs->int_in_endpointAddr = endpoint->bEndpointAddress;
+	cs->inbuf[0].rcvbuf = kmalloc(buffer_size, GFP_KERNEL);
+	if (!cs->inbuf[0].rcvbuf) {
+		err("Couldn't allocate rcvbuf");
+		retval = -ENOMEM;
+		goto error;
+	}
+	/* Fill the interrupt urb and send it to the core */
+	usb_fill_int_urb(ucs->read_urb, udev,
+	                 usb_rcvintpipe(udev,
+	                                endpoint->bEndpointAddress & 0x0f),
+	                 cs->inbuf[0].rcvbuf, buffer_size,
+	                 gigaset_read_int_callback,
+	                 cs->inbuf + 0, endpoint->bInterval);
+
+	retval = usb_submit_urb(ucs->read_urb, SLAB_KERNEL);
+	if (retval) {
+		err("Could not submit URB!");
+		goto error;
+	}
+
+	/* tell common part that the device is ready */
+	if (startmode == SM_LOCKED)
+		atomic_set(&cs->mstate, MS_LOCKED);
+	if (!gigaset_start(cs)) {
+		tasklet_kill(&cs->write_tasklet);
+		retval = -ENODEV; //FIXME
+		goto error;
+	}
+
+	/* save address of controller structure */
+	usb_set_intfdata(interface, cs);
+
+	/* set up device sysfs */
+	gigaset_init_dev_sysfs(interface);
+	return 0;
+
+error:
+	if (ucs->read_urb)
+		usb_kill_urb(ucs->read_urb);
+	kfree(ucs->bulk_out_buffer);
+	if (ucs->bulk_out_urb != NULL)
+		usb_free_urb(ucs->bulk_out_urb);
+	kfree(cs->inbuf[0].rcvbuf);
+	if (ucs->read_urb != NULL)
+		usb_free_urb(ucs->read_urb);
+	ucs->read_urb = ucs->bulk_out_urb = NULL;
+	cs->inbuf[0].rcvbuf = ucs->bulk_out_buffer = NULL;
+	gigaset_unassign(cs);
+	return retval;
+}
+
+/**
+ *	skel_disconnect
+ */
+static void gigaset_disconnect(struct usb_interface *interface)
+{
+	struct cardstate *cs;
+	struct usb_cardstate *ucs;
+
+	cs = usb_get_intfdata(interface);
+
+	/* clear device sysfs */
+	gigaset_free_dev_sysfs(interface);
+
+	usb_set_intfdata(interface, NULL);
+	ucs = cs->hw.usb;
+	usb_kill_urb(ucs->read_urb);
+	//info("GigaSet USB device #%d will be disconnected", minor);
+
+	gigaset_stop(cs);
+
+	tasklet_kill(&cs->write_tasklet);
+
+	usb_kill_urb(ucs->bulk_out_urb);  /* FIXME: nur, wenn noetig */
+	//usb_kill_urb(ucs->urb_cmd_out);  /* FIXME: nur, wenn noetig */
+
+	kfree(ucs->bulk_out_buffer);
+	if (ucs->bulk_out_urb != NULL)
+		usb_free_urb(ucs->bulk_out_urb);
+	//if(ucs->urb_cmd_out != NULL)
+	//	usb_free_urb(ucs->urb_cmd_out);
+	kfree(cs->inbuf[0].rcvbuf);
+	if (ucs->read_urb != NULL)
+		usb_free_urb(ucs->read_urb);
+	ucs->read_urb = ucs->bulk_out_urb/*=ucs->urb_cmd_out*/=NULL;
+	cs->inbuf[0].rcvbuf = ucs->bulk_out_buffer = NULL;
+
+	gigaset_unassign(cs);
+}
+
+static struct gigaset_ops ops = {
+	gigaset_write_cmd,
+	gigaset_write_room,
+	gigaset_chars_in_buffer,
+	gigaset_brkchars,
+	gigaset_init_bchannel,
+	gigaset_close_bchannel,
+	gigaset_initbcshw,
+	gigaset_freebcshw,
+	gigaset_reinitbcshw,
+	gigaset_initcshw,
+	gigaset_freecshw,
+	gigaset_set_modem_ctrl,
+	gigaset_baud_rate,
+	gigaset_set_line_ctrl,
+	gigaset_m10x_send_skb,
+	gigaset_m10x_input,
+};
+
+/**
+ *	usb_gigaset_init
+ * This function is called while kernel-module is loaded
+ */
+static int __init usb_gigaset_init(void)
+{
+	int result;
+
+	/* allocate memory for our driver state and intialize it */
+	if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
+	                               GIGASET_MODULENAME, GIGASET_DEVNAME,
+	                               GIGASET_DEVFSNAME, &ops,
+	                               THIS_MODULE)) == NULL)
+		goto error;
+
+	/* allocate memory for our device state and intialize it */
+	cardstate = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);
+	if (!cardstate)
+		goto error;
+
+	/* register this driver with the USB subsystem */
+	result = usb_register(&gigaset_usb_driver);
+	if (result < 0) {
+		err("usb_gigaset: usb_register failed (error %d)",
+		    -result);
+		goto error;
+	}
+
+	info(DRIVER_AUTHOR);
+	info(DRIVER_DESC);
+	return 0;
+
+error:	if (cardstate)
+		gigaset_freecs(cardstate);
+	cardstate = NULL;
+	if (driver)
+		gigaset_freedriver(driver);
+	driver = NULL;
+	return -1;
+}
+
+
+/**
+ *	usb_gigaset_exit
+ * This function is called while unloading the kernel-module
+ */
+static void __exit usb_gigaset_exit(void)
+{
+	gigaset_blockdriver(driver); /* => probe will fail
+	                              * => no gigaset_start any more
+	                              */
+
+	gigaset_shutdown(cardstate);
+	/* from now on, no isdn callback should be possible */
+
+	/* deregister this driver with the USB subsystem */
+	usb_deregister(&gigaset_usb_driver);
+	/* this will call the disconnect-callback */
+	/* from now on, no disconnect/probe callback should be running */
+
+	gigaset_freecs(cardstate);
+	cardstate = NULL;
+	gigaset_freedriver(driver);
+	driver = NULL;
+}
+
+
+module_init(usb_gigaset_init);
+module_exit(usb_gigaset_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+
+MODULE_LICENSE("GPL");
diff -urN oldtree/drivers/isdn/i4l/Kconfig newtree/drivers/isdn/i4l/Kconfig
--- oldtree/drivers/isdn/i4l/Kconfig	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/isdn/i4l/Kconfig	2006-02-21 15:58:32.798160480 +0000
@@ -139,3 +139,4 @@
 
 endmenu
 
+source "drivers/isdn/gigaset/Kconfig"
diff -urN oldtree/drivers/leds/Kconfig newtree/drivers/leds/Kconfig
--- oldtree/drivers/leds/Kconfig	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/leds/Kconfig	2006-02-21 15:58:31.320385136 +0000
@@ -0,0 +1,70 @@
+
+menu "LED devices"
+
+config NEW_LEDS
+	bool "LED Support"
+	help
+	  Say Y to enable Linux LED support.  This is not related to standard
+	  keyboard LEDs which are controlled via the input system.
+
+config LEDS_CLASS
+	tristate "LED Class Support"
+	depends NEW_LEDS
+	help
+	  This option enables the led sysfs class in /sys/class/leds.  You'll
+	  need this to do anything useful with LEDs.  If unsure, say N.
+
+config LEDS_TRIGGERS
+	bool "LED Trigger support"
+	depends NEW_LEDS
+	help
+	  This option enables trigger support for the leds class.
+	  These triggers allow kernel events to drive the LEDs and can
+	  be configured via sysfs. If unsure, say Y.
+
+config LEDS_CORGI
+	tristate "LED Support for the Sharp SL-C7x0 series"
+	depends LEDS_CLASS && PXA_SHARP_C7xx
+	help
+	  This option enables support for the LEDs on Sharp Zaurus
+	  SL-C7x0 series (C700, C750, C760, C860).
+
+config LEDS_LOCOMO
+	tristate "LED Support for Locomo device"
+	depends LEDS_CLASS && SHARP_LOCOMO
+	help
+	  This option enables support for the LEDs on Sharp Locomo.
+	  Zaurus models SL-5500 and SL-5600.
+
+config LEDS_SPITZ
+	tristate "LED Support for the Sharp SL-Cxx00 series"
+	depends LEDS_CLASS && PXA_SHARP_Cxx00
+	help
+	  This option enables support for the LEDs on Sharp Zaurus
+	  SL-Cxx00 series (C1000, C3000, C3100).
+
+config LEDS_IXP4XX
+	tristate "LED Support for GPIO connected LEDs on IXP4XX processors"
+	depends LEDS_CLASS && ARCH_IXP4XX
+	help
+	  This option enables support for the LEDs connected to GPIO
+	  outputs of the Intel IXP4XX processors.  To be useful the
+	  particular board must have LEDs and they must be connected
+	  to the GPIO lines.  If unsure, say Y.
+
+config LEDS_TOSA
+	tristate "LED Support for the Sharp SL-6000 series"
+	depends LEDS_CLASS && PXA_SHARPSL
+	help
+	  This option enables support for the LEDs on Sharp Zaurus
+	  SL-6000 series.
+
+config LEDS_TRIGGER_TIMER
+	tristate "LED Timer Trigger"
+	depends LEDS_TRIGGERS
+	help
+	  This allows LEDs to be controlled by a programmable timer
+	  via sysfs. If unsure, say Y.
+
+endmenu
+
diff -urN oldtree/drivers/leds/Makefile newtree/drivers/leds/Makefile
--- oldtree/drivers/leds/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/leds/Makefile	2006-02-21 15:58:31.321384984 +0000
@@ -0,0 +1,15 @@
+
+# LED Core
+obj-$(CONFIG_NEW_LEDS)			+= led-core.o
+obj-$(CONFIG_LEDS_CLASS)		+= led-class.o
+obj-$(CONFIG_LEDS_TRIGGERS)		+= led-triggers.o
+
+# LED Platform Drivers
+obj-$(CONFIG_LEDS_CORGI)		+= leds-corgi.o
+obj-$(CONFIG_LEDS_LOCOMO)		+= leds-locomo.o
+obj-$(CONFIG_LEDS_SPITZ)		+= leds-spitz.o
+obj-$(CONFIG_LEDS_IXP4XX)		+= leds-ixp4xx-gpio.o
+obj-$(CONFIG_LEDS_TOSA)			+= leds-tosa.o
+
+# LED Triggers
+obj-$(CONFIG_LEDS_TRIGGER_TIMER)	+= ledtrig-timer.o
diff -urN oldtree/drivers/leds/led-class.c newtree/drivers/leds/led-class.c
--- oldtree/drivers/leds/led-class.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/leds/led-class.c	2006-02-21 15:58:31.164408848 +0000
@@ -0,0 +1,174 @@
+/*
+ * LED Class Core
+ *
+ * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
+ * Copyright (C) 2005-2006 Richard Purdie <rpurdie@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/sysdev.h>
+#include <linux/timer.h>
+#include <linux/err.h>
+#include <linux/leds.h>
+#include "leds.h"
+
+static struct class *leds_class;
+
+static ssize_t led_brightness_show(struct class_device *dev, char *buf)
+{
+	struct led_classdev *led_cdev = class_get_devdata(dev);
+	ssize_t ret = 0;
+
+	/* no lock needed for this */
+	sprintf(buf, "%u\n", led_cdev->brightness);
+	ret = strlen(buf) + 1;
+
+	return ret;
+}
+
+static ssize_t led_brightness_store(struct class_device *dev,
+				const char *buf, size_t size)
+{
+	struct led_classdev *led_cdev = class_get_devdata(dev);
+	ssize_t ret = -EINVAL;
+	char *after;
+	unsigned long state = simple_strtoul(buf, &after, 10);
+
+	if (after - buf > 0) {
+		ret = after - buf;
+		write_lock(&led_cdev->lock);
+		led_set_brightness(led_cdev, state);
+		write_unlock(&led_cdev->lock);
+	}
+
+	return ret;
+}
+
+static CLASS_DEVICE_ATTR(brightness, 0644, led_brightness_show,
+			led_brightness_store);
+#ifdef CONFIG_LEDS_TRIGGERS
+static CLASS_DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
+#endif
+
+/**
+ * led_classdev_suspend - suspend an led_classdev.
+ * @led_cdev: the led_classdev to suspend.
+ */
+void led_classdev_suspend(struct led_classdev *led_cdev)
+{
+	write_lock(&led_cdev->lock);
+	led_cdev->flags |= LED_SUSPENDED;
+	led_cdev->brightness_set(led_cdev, 0);
+	write_unlock(&led_cdev->lock);
+}
+EXPORT_SYMBOL_GPL(led_classdev_suspend);
+
+/**
+ * led_classdev_resume - resume an led_classdev.
+ * @led_cdev: the led_classdev to resume.
+ */
+void led_classdev_resume(struct led_classdev *led_cdev)
+{
+	write_lock(&led_cdev->lock);
+	led_cdev->flags &= ~LED_SUSPENDED;
+	led_cdev->brightness_set(led_cdev, led_cdev->brightness);
+	write_unlock(&led_cdev->lock);
+}
+EXPORT_SYMBOL_GPL(led_classdev_resume);
+
+/**
+ * led_classdev_register - register a new object of led_classdev class.
+ * @dev: The device to register.
+ * @led_cdev: the led_classdev structure for this device.
+ */
+int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
+{
+	led_cdev->class_dev = class_device_create(leds_class, NULL, 0,
+						parent, "%s", led_cdev->name);
+	if (unlikely(IS_ERR(led_cdev->class_dev)))
+		return PTR_ERR(led_cdev->class_dev);
+
+	rwlock_init(&led_cdev->lock);
+	class_set_devdata(led_cdev->class_dev, led_cdev);
+
+	/* register the attributes */
+	class_device_create_file(led_cdev->class_dev,
+				&class_device_attr_brightness);
+
+	/* add to the list of leds */
+	write_lock(&leds_list_lock);
+	list_add_tail(&led_cdev->node, &leds_list);
+	write_unlock(&leds_list_lock);
+
+#ifdef CONFIG_LEDS_TRIGGERS
+	rwlock_init(&led_cdev->trigger_lock);
+
+	led_trigger_set_default(led_cdev);
+
+	class_device_create_file(led_cdev->class_dev,
+				&class_device_attr_trigger);
+#endif
+
+	printk(KERN_INFO "Registered led device: %s\n",
+			led_cdev->class_dev->class_id);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(led_classdev_register);
+
+/**
+ * led_classdev_unregister - unregisters a object of led_properties class.
+ * @led_cdev: the led device to unreigister
+ *
+ * Unregisters a previously registered via led_classdev_register object.
+ */
+void led_classdev_unregister(struct led_classdev *led_cdev)
+{
+	class_device_remove_file(led_cdev->class_dev,
+				&class_device_attr_brightness);
+#ifdef CONFIG_LEDS_TRIGGERS
+	class_device_remove_file(led_cdev->class_dev,
+				&class_device_attr_trigger);
+	write_lock(&led_cdev->trigger_lock);
+	if (led_cdev->trigger)
+		led_trigger_set(led_cdev, NULL);
+	write_unlock(&led_cdev->trigger_lock);
+#endif
+
+	class_device_unregister(led_cdev->class_dev);
+
+	write_lock(&leds_list_lock);
+	list_del(&led_cdev->node);
+	write_unlock(&leds_list_lock);
+}
+EXPORT_SYMBOL_GPL(led_classdev_unregister);
+
+static int __init leds_init(void)
+{
+	leds_class = class_create(THIS_MODULE, "leds");
+	if (IS_ERR(leds_class))
+		return PTR_ERR(leds_class);
+	return 0;
+}
+
+static void __exit leds_exit(void)
+{
+	class_destroy(leds_class);
+}
+
+subsys_initcall(leds_init);
+module_exit(leds_exit);
+
+MODULE_AUTHOR("John Lenz, Richard Purdie");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("LED Class Interface");
diff -urN oldtree/drivers/leds/led-core.c newtree/drivers/leds/led-core.c
--- oldtree/drivers/leds/led-core.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/leds/led-core.c	2006-02-21 15:58:31.149411128 +0000
@@ -0,0 +1,25 @@
+/*
+ * LED Class Core
+ *
+ * Copyright 2005-2006 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <rpurdie@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/leds.h>
+#include "leds.h"
+
+rwlock_t leds_list_lock = RW_LOCK_UNLOCKED;
+LIST_HEAD(leds_list);
+
+EXPORT_SYMBOL_GPL(leds_list);
+EXPORT_SYMBOL_GPL(leds_list_lock);
diff -urN oldtree/drivers/leds/led-triggers.c newtree/drivers/leds/led-triggers.c
--- oldtree/drivers/leds/led-triggers.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/leds/led-triggers.c	2006-02-21 15:58:31.180406416 +0000
@@ -0,0 +1,239 @@
+/*
+ * LED Triggers Core
+ *
+ * Copyright 2005-2006 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <rpurdie@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/sysdev.h>
+#include <linux/timer.h>
+#include <linux/leds.h>
+#include "leds.h"
+
+/*
+ * Nests outside led_cdev->lock and led_cdev->trigger_lock
+ */
+static rwlock_t triggers_list_lock = RW_LOCK_UNLOCKED;
+static LIST_HEAD(trigger_list);
+
+ssize_t led_trigger_store(struct class_device *dev, const char *buf,
+			size_t count)
+{
+	struct led_classdev *led_cdev = class_get_devdata(dev);
+	char trigger_name[TRIG_NAME_MAX];
+	struct led_trigger *trig;
+	size_t len;
+
+	trigger_name[sizeof(trigger_name) - 1] = '\0';
+	strncpy(trigger_name, buf, sizeof(trigger_name) - 1);
+	len = strlen(trigger_name);
+
+	if (len && trigger_name[len - 1] == '\n')
+		trigger_name[len - 1] = '\0';
+
+	if (!strcmp(trigger_name, "none")) {
+		write_lock(&led_cdev->trigger_lock);
+		led_trigger_set(led_cdev, NULL);
+		write_unlock(&led_cdev->trigger_lock);
+		return count;
+	}
+
+	read_lock(&triggers_list_lock);
+	list_for_each_entry(trig, &trigger_list, next_trig) {
+		if (!strcmp(trigger_name, trig->name)) {
+			write_lock(&led_cdev->trigger_lock);
+			led_trigger_set(led_cdev, trig);
+			write_unlock(&led_cdev->trigger_lock);
+
+			read_unlock(&triggers_list_lock);
+			return count;
+		}
+	}
+	read_unlock(&triggers_list_lock);
+
+	return -EINVAL;
+}
+
+
+ssize_t led_trigger_show(struct class_device *dev, char *buf)
+{
+	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct led_trigger *trig;
+	int len = 0;
+
+	read_lock(&triggers_list_lock);
+	read_lock(&led_cdev->trigger_lock);
+
+	if (!led_cdev->trigger)
+		len += sprintf(buf+len, "[none] ");
+	else
+		len += sprintf(buf+len, "none ");
+
+	list_for_each_entry(trig, &trigger_list, next_trig) {
+		if (led_cdev->trigger && !strcmp(led_cdev->trigger->name,
+							trig->name))
+			len += sprintf(buf+len, "[%s] ", trig->name);
+		else
+			len += sprintf(buf+len, "%s ", trig->name);
+	}
+	read_unlock(&led_cdev->trigger_lock);
+	read_unlock(&triggers_list_lock);
+
+	len += sprintf(len+buf, "\n");
+	return len;
+}
+
+void led_trigger_event(struct led_trigger *trigger,
+			enum led_brightness brightness)
+{
+	struct list_head *entry;
+
+	if (!trigger)
+		return;
+
+	read_lock(&trigger->leddev_list_lock);
+	list_for_each(entry, &trigger->led_cdevs) {
+		struct led_classdev *led_cdev;
+
+		led_cdev = list_entry(entry, struct led_classdev, trig_list);
+		write_lock(&led_cdev->lock);
+		led_set_brightness(led_cdev, brightness);
+		write_unlock(&led_cdev->lock);
+	}
+	read_unlock(&trigger->leddev_list_lock);
+}
+
+/* Caller must ensure led_cdev->trigger_lock held */
+void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger)
+{
+	/* Remove any existing trigger */
+	if (led_cdev->trigger) {
+		write_lock(&led_cdev->trigger->leddev_list_lock);
+		list_del(&led_cdev->trig_list);
+		write_unlock(&led_cdev->trigger->leddev_list_lock);
+		if (led_cdev->trigger->deactivate)
+			led_cdev->trigger->deactivate(led_cdev);
+	}
+	if (trigger) {
+		write_lock(&trigger->leddev_list_lock);
+		list_add_tail(&led_cdev->trig_list, &trigger->led_cdevs);
+		write_unlock(&trigger->leddev_list_lock);
+		if (trigger->activate)
+			trigger->activate(led_cdev);
+	}
+	led_cdev->trigger = trigger;
+}
+
+void led_trigger_set_default(struct led_classdev *led_cdev)
+{
+	struct led_trigger *trig;
+
+	if (!led_cdev->default_trigger)
+		return;
+
+	read_lock(&triggers_list_lock);
+	write_lock(&led_cdev->trigger_lock);
+	list_for_each_entry(trig, &trigger_list, next_trig) {
+		if (!strcmp(led_cdev->default_trigger, trig->name))
+			led_trigger_set(led_cdev, trig);
+	}
+	write_unlock(&led_cdev->trigger_lock);
+	read_unlock(&triggers_list_lock);
+}
+
+int led_trigger_register(struct led_trigger *trigger)
+{
+	struct led_classdev *led_cdev;
+
+	rwlock_init(&trigger->leddev_list_lock);
+	INIT_LIST_HEAD(&trigger->led_cdevs);
+
+	/* Add to the list of led triggers */
+	write_lock(&triggers_list_lock);
+	list_add_tail(&trigger->next_trig, &trigger_list);
+	write_unlock(&triggers_list_lock);
+
+	/* Register with any LEDs that have this as a default trigger */
+	read_lock(&leds_list_lock);
+	list_for_each_entry(led_cdev, &leds_list, node) {
+		write_lock(&led_cdev->trigger_lock);
+		if (!led_cdev->trigger && led_cdev->default_trigger &&
+			    !strcmp(led_cdev->default_trigger, trigger->name))
+			led_trigger_set(led_cdev, trigger);
+		write_unlock(&led_cdev->trigger_lock);
+	}
+	read_unlock(&leds_list_lock);
+
+	return 0;
+}
+
+void led_trigger_register_simple(const char *name, struct led_trigger **tp)
+{
+	struct led_trigger *trigger;
+
+	trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
+
+	if (trigger) {
+		trigger->name = name;
+		led_trigger_register(trigger);
+	}
+	*tp = trigger;
+}
+
+void led_trigger_unregister(struct led_trigger *trigger)
+{
+	struct led_classdev *led_cdev;
+
+	/* Remove from the list of led triggers */
+	write_lock(&triggers_list_lock);
+	list_del(&trigger->next_trig);
+	write_unlock(&triggers_list_lock);
+
+	/* Remove anyone actively using this trigger */
+	read_lock(&leds_list_lock);
+	list_for_each_entry(led_cdev, &leds_list, node) {
+		write_lock(&led_cdev->trigger_lock);
+		if (led_cdev->trigger == trigger)
+			led_trigger_set(led_cdev, NULL);
+		write_unlock(&led_cdev->trigger_lock);
+	}
+	read_unlock(&leds_list_lock);
+}
+
+void led_trigger_unregister_simple(struct led_trigger *trigger)
+{
+	led_trigger_unregister(trigger);
+	kfree(trigger);
+}
+
+/* Used by LED Class */
+EXPORT_SYMBOL_GPL(led_trigger_set);
+EXPORT_SYMBOL_GPL(led_trigger_set_default);
+EXPORT_SYMBOL_GPL(led_trigger_show);
+EXPORT_SYMBOL_GPL(led_trigger_store);
+
+/* LED Trigger Interface */
+EXPORT_SYMBOL_GPL(led_trigger_register);
+EXPORT_SYMBOL_GPL(led_trigger_unregister);
+
+/* Simple LED Tigger Interface */
+EXPORT_SYMBOL_GPL(led_trigger_register_simple);
+EXPORT_SYMBOL_GPL(led_trigger_unregister_simple);
+EXPORT_SYMBOL_GPL(led_trigger_event);
+
+MODULE_AUTHOR("Richard Purdie");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("LED Triggers Core");
diff -urN oldtree/drivers/leds/leds-corgi.c newtree/drivers/leds/leds-corgi.c
--- oldtree/drivers/leds/leds-corgi.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/leds/leds-corgi.c	2006-02-21 15:58:31.222400032 +0000
@@ -0,0 +1,121 @@
+/*
+ * LED Triggers Core
+ *
+ * Copyright 2005-2006 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <rpurdie@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <asm/mach-types.h>
+#include <asm/arch/corgi.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/hardware/scoop.h>
+
+static void corgiled_amber_set(struct led_classdev *led_cdev, enum led_brightness value)
+{
+	if (value)
+		GPSR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
+	else
+		GPCR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
+}
+
+static void corgiled_green_set(struct led_classdev *led_cdev, enum led_brightness value)
+{
+	if (value)
+		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN);
+	else
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN);
+}
+
+static struct led_classdev corgi_amber_led = {
+	.name			= "corgi:amber",
+	.default_trigger	= "sharpsl-charge",
+	.brightness_set		= corgiled_amber_set,
+};
+
+static struct led_classdev corgi_green_led = {
+	.name			= "corgi:green",
+	.default_trigger	= "nand-disk",
+	.brightness_set		= corgiled_green_set,
+};
+
+#ifdef CONFIG_PM
+static int corgiled_suspend(struct platform_device *dev, pm_message_t state)
+{
+#ifdef CONFIG_LEDS_TRIGGERS
+	if (corgi_amber_led.trigger && strcmp(corgi_amber_led.trigger->name, "sharpsl-charge"))
+#endif
+		led_classdev_suspend(&corgi_amber_led);
+	led_classdev_suspend(&corgi_green_led);
+	return 0;
+}
+
+static int corgiled_resume(struct platform_device *dev)
+{
+	led_classdev_resume(&corgi_amber_led);
+	led_classdev_resume(&corgi_green_led);
+	return 0;
+}
+#endif
+
+static int corgiled_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = led_classdev_register(&pdev->dev, &corgi_amber_led);
+	if (ret < 0)
+		return ret;
+
+	ret = led_classdev_register(&pdev->dev, &corgi_green_led);
+	if (ret < 0)
+		led_classdev_unregister(&corgi_amber_led);
+
+	return ret;
+}
+
+static int corgiled_remove(struct platform_device *pdev)
+{
+	led_classdev_unregister(&corgi_amber_led);
+	led_classdev_unregister(&corgi_green_led);
+	return 0;
+}
+
+static struct platform_driver corgiled_driver = {
+	.probe		= corgiled_probe,
+	.remove		= corgiled_remove,
+#ifdef CONFIG_PM
+	.suspend	= corgiled_suspend,
+	.resume		= corgiled_resume,
+#endif
+	.driver		= {
+		.name		= "corgi-led",
+	},
+};
+
+static int __init corgiled_init(void)
+{
+	return platform_driver_register(&corgiled_driver);
+}
+
+static void __exit corgiled_exit(void)
+{
+ 	platform_driver_unregister(&corgiled_driver);
+}
+
+module_init(corgiled_init);
+module_exit(corgiled_exit);
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
+MODULE_DESCRIPTION("Corgi LED driver");
+MODULE_LICENSE("GPL");
diff -urN oldtree/drivers/leds/leds-ixp4xx-gpio.c newtree/drivers/leds/leds-ixp4xx-gpio.c
--- oldtree/drivers/leds/leds-ixp4xx-gpio.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/leds/leds-ixp4xx-gpio.c	2006-02-21 15:58:31.306387264 +0000
@@ -0,0 +1,215 @@
+/*
+ * IXP4XX GPIO driver LED driver
+ *
+ * Author: John Bowler <jbowler@acm.org>
+ *
+ * Copyright (c) 2006 John Bowler
+ *
+ * Permission is hereby granted, free of charge, to any
+ * person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the
+ * Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice
+ * shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+ * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+ * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/leds.h>
+#include <asm/arch/hardware.h>
+
+extern spinlock_t gpio_lock;
+
+/* Up to 16 gpio lines are possible. */
+#define GPIO_MAX 16
+static struct ixp4xxgpioled_device {
+	struct led_classdev ancestor;
+	int               flags;
+} ixp4xxgpioled_devices[GPIO_MAX];
+
+void ixp4xxgpioled_brightness_set(struct led_classdev *pled,
+				enum led_brightness value)
+{
+	const struct ixp4xxgpioled_device *const ixp4xx_dev =
+		container_of(pled, struct ixp4xxgpioled_device, ancestor);
+	const u32 gpio_pin = ixp4xx_dev - ixp4xxgpioled_devices;
+
+	if (gpio_pin < GPIO_MAX && ixp4xx_dev->ancestor.name != 0) {
+		/* Set or clear the 'gpio_pin' bit according to the style
+		 * and the required setting (value > 0 == on)
+		 */
+		const int gpio_value =
+			(value > 0) == (ixp4xx_dev->flags != IXP4XX_GPIO_LOW) ?
+				IXP4XX_GPIO_HIGH : IXP4XX_GPIO_LOW;
+
+		{
+			unsigned long flags;
+			spin_lock_irqsave(&gpio_lock, flags);
+			gpio_line_set(gpio_pin, gpio_value);
+			spin_unlock_irqrestore(&gpio_lock, flags);
+		}
+	}
+}
+
+/* LEDs are described in resources, the following iterates over the valid
+ * LED resources.
+ */
+#define for_all_leds(i, pdev) \
+	for (i=0; i<pdev->num_resources; ++i) \
+		if (pdev->resource[i].start < GPIO_MAX && \
+			pdev->resource[i].name != 0)
+
+/* The following applies 'operation' to each LED from the given platform,
+ * the function always returns 0 to allow tail call elimination.
+ */
+static int apply_to_all_leds(struct platform_device *pdev,
+	void (*operation)(struct led_classdev *pled))
+{
+	int i;
+
+	for_all_leds(i, pdev)
+		operation(&ixp4xxgpioled_devices[pdev->resource[i].start].ancestor);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int ixp4xxgpioled_suspend(struct platform_device *pdev,
+				pm_message_t state)
+{
+	return apply_to_all_leds(pdev, led_classdev_suspend);
+}
+
+static int ixp4xxgpioled_resume(struct platform_device *pdev)
+{
+	return apply_to_all_leds(pdev, led_classdev_resume);
+}
+#endif
+
+static void ixp4xxgpioled_remove_one_led(struct led_classdev *pled)
+{
+	led_classdev_unregister(pled);
+	pled->name = 0;
+}
+
+static int ixp4xxgpioled_remove(struct platform_device *pdev)
+{
+	return apply_to_all_leds(pdev, ixp4xxgpioled_remove_one_led);
+}
+
+static int ixp4xxgpioled_probe(struct platform_device *pdev)
+{
+	/* The board level has to tell the driver where the
+	 * LEDs are connected - there is no way to find out
+	 * electrically.  It must also say whether the GPIO
+	 * lines are active high or active low.
+	 *
+	 * To do this read the num_resources (the number of
+	 * LEDs) and the struct resource (the data for each
+	 * LED).  The name comes from the resource, and it
+	 * isn't copied.
+	 */
+	int i;
+
+	for_all_leds(i, pdev) {
+		const u8 gpio_pin = pdev->resource[i].start;
+		int      rc;
+
+		if (ixp4xxgpioled_devices[gpio_pin].ancestor.name == 0) {
+			unsigned long flags;
+
+			spin_lock_irqsave(&gpio_lock, flags);
+			gpio_line_config(gpio_pin, IXP4XX_GPIO_OUT);
+			/* The config can, apparently, reset the state,
+			 * I suspect the gpio line may be an input and
+			 * the config may cause the line to be latched,
+			 * so the setting depends on how the LED is
+			 * connected to the line (which affects how it
+			 * floats if not driven).
+			 */
+			gpio_line_set(gpio_pin, IXP4XX_GPIO_HIGH);
+			spin_unlock_irqrestore(&gpio_lock, flags);
+
+			ixp4xxgpioled_devices[gpio_pin].flags =
+				pdev->resource[i].flags & IORESOURCE_BITS;
+
+			ixp4xxgpioled_devices[gpio_pin].ancestor.name =
+				pdev->resource[i].name;
+
+			/* This is how a board manufacturer makes the LED
+			 * come on on reset - the GPIO line will be high, so
+			 * make the LED light when the line is low...
+			 */
+			if (ixp4xxgpioled_devices[gpio_pin].flags != IXP4XX_GPIO_LOW)
+				ixp4xxgpioled_devices[gpio_pin].ancestor.brightness = 100;
+			else
+				ixp4xxgpioled_devices[gpio_pin].ancestor.brightness = 0;
+
+			ixp4xxgpioled_devices[gpio_pin].ancestor.flags = 0;
+
+			ixp4xxgpioled_devices[gpio_pin].ancestor.brightness_set =
+				ixp4xxgpioled_brightness_set;
+
+			ixp4xxgpioled_devices[gpio_pin].ancestor.default_trigger = 0;
+		}
+
+		rc = led_classdev_register(&pdev->dev,
+				&ixp4xxgpioled_devices[gpio_pin].ancestor);
+		if (rc < 0) {
+			ixp4xxgpioled_devices[gpio_pin].ancestor.name = 0;
+			ixp4xxgpioled_remove(pdev);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static struct platform_driver ixp4xxgpioled_driver = {
+	.probe   = ixp4xxgpioled_probe,
+	.remove  = ixp4xxgpioled_remove,
+#ifdef CONFIG_PM
+	.suspend = ixp4xxgpioled_suspend,
+	.resume  = ixp4xxgpioled_resume,
+#endif
+	.driver  = {
+		.name = "IXP4XX-GPIO-LED",
+	},
+};
+
+static int __init ixp4xxgpioled_init(void)
+{
+	return platform_driver_register(&ixp4xxgpioled_driver);
+}
+
+static void __exit ixp4xxgpioled_exit(void)
+{
+	platform_driver_unregister(&ixp4xxgpioled_driver);
+}
+
+module_init(ixp4xxgpioled_init);
+module_exit(ixp4xxgpioled_exit);
+
+MODULE_AUTHOR("John Bowler <jbowler@acm.org>");
+MODULE_DESCRIPTION("IXP4XX GPIO LED driver");
+MODULE_LICENSE("Dual MIT/GPL");
diff -urN oldtree/drivers/leds/leds-locomo.c newtree/drivers/leds/leds-locomo.c
--- oldtree/drivers/leds/leds-locomo.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/leds/leds-locomo.c	2006-02-21 15:58:31.292389392 +0000
@@ -0,0 +1,95 @@
+/*
+ * linux/drivers/leds/locomo.c
+ *
+ * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/leds.h>
+
+#include <asm/hardware.h>
+#include <asm/hardware/locomo.h>
+
+static void locomoled_brightness_set(struct led_classdev *led_cdev,
+				enum led_brightness value, int offset)
+{
+	struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->class_dev->dev);
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (value)
+		locomo_writel(LOCOMO_LPT_TOFH, locomo_dev->mapbase + offset);
+	else
+		locomo_writel(LOCOMO_LPT_TOFL, locomo_dev->mapbase + offset);
+	local_irq_restore(flags);
+}
+
+static void locomoled_brightness_set0(struct led_classdev *led_cdev,
+				enum led_brightness value)
+{
+	locomoled_brightness_set(led_cdev, value, LOCOMO_LPT0);
+}
+
+static void locomoled_brightness_set1(struct led_classdev *led_cdev,
+				enum led_brightness value)
+{
+	locomoled_brightness_set(led_cdev, value, LOCOMO_LPT1);
+}
+
+static struct led_classdev locomo_led0 = {
+	.name			= "locomo:amber",
+	.brightness_set		= locomoled_brightness_set0,
+};
+
+static struct led_classdev locomo_led1 = {
+	.name			= "locomo:green",
+	.brightness_set		= locomoled_brightness_set1,
+};
+
+static int locomoled_probe(struct locomo_dev *ldev)
+{
+	int ret;
+
+	ret = led_classdev_register(&ldev->dev, &locomo_led0);
+	if (ret < 0)
+		return ret;
+
+	ret = led_classdev_register(&ldev->dev, &locomo_led1);
+	if (ret < 0)
+		led_classdev_unregister(&locomo_led0);
+
+	return ret;
+}
+
+static int locomoled_remove(struct locomo_dev *dev)
+{
+	led_classdev_unregister(&locomo_led0);
+	led_classdev_unregister(&locomo_led1);
+	return 0;
+}
+
+static struct locomo_driver locomoled_driver = {
+	.drv = {
+		.name = "locomoled"
+	},
+	.devid	= LOCOMO_DEVID_LED,
+	.probe	= locomoled_probe,
+	.remove	= locomoled_remove,
+};
+
+static int __init locomoled_init(void)
+{
+	return locomo_driver_register(&locomoled_driver);
+}
+module_init(locomoled_init);
+
+MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
+MODULE_DESCRIPTION("Locomo LED driver");
+MODULE_LICENSE("GPL");
diff -urN oldtree/drivers/leds/leds-spitz.c newtree/drivers/leds/leds-spitz.c
--- oldtree/drivers/leds/leds-spitz.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/leds/leds-spitz.c	2006-02-21 15:58:31.223399880 +0000
@@ -0,0 +1,125 @@
+/*
+ * LED Triggers Core
+ *
+ * Copyright 2005-2006 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <rpurdie@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <asm/hardware/scoop.h>
+#include <asm/mach-types.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/spitz.h>
+
+static void spitzled_amber_set(struct led_classdev *led_cdev, enum led_brightness value)
+{
+	if (value)
+		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE);
+	else
+		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE);
+}
+
+static void spitzled_green_set(struct led_classdev *led_cdev, enum led_brightness value)
+{
+	if (value)
+		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN);
+	else
+		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN);
+}
+
+static struct led_classdev spitz_amber_led = {
+	.name			= "spitz:amber",
+	.default_trigger	= "sharpsl-charge",
+	.brightness_set		= spitzled_amber_set,
+};
+
+static struct led_classdev spitz_green_led = {
+	.name			= "spitz:green",
+	.default_trigger	= "ide-disk",
+	.brightness_set		= spitzled_green_set,
+};
+
+#ifdef CONFIG_PM
+static int spitzled_suspend(struct platform_device *dev, pm_message_t state)
+{
+#ifdef CONFIG_LEDS_TRIGGERS
+	if (spitz_amber_led.trigger && strcmp(spitz_amber_led.trigger->name, "sharpsl-charge"))
+#endif
+		led_classdev_suspend(&spitz_amber_led);
+	led_classdev_suspend(&spitz_green_led);
+	return 0;
+}
+
+static int spitzled_resume(struct platform_device *dev)
+{
+	led_classdev_resume(&spitz_amber_led);
+	led_classdev_resume(&spitz_green_led);
+	return 0;
+}
+#endif
+
+static int spitzled_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	if (machine_is_akita())
+		spitz_green_led.default_trigger = "nand-disk";
+
+	ret = led_classdev_register(&pdev->dev, &spitz_amber_led);
+	if (ret < 0)
+		return ret;
+
+	ret = led_classdev_register(&pdev->dev, &spitz_green_led);
+	if (ret < 0)
+		led_classdev_unregister(&spitz_amber_led);
+
+	return ret;
+}
+
+static int spitzled_remove(struct platform_device *pdev)
+{
+	led_classdev_unregister(&spitz_amber_led);
+	led_classdev_unregister(&spitz_green_led);
+
+	return 0;
+}
+
+static struct platform_driver spitzled_driver = {
+	.probe		= spitzled_probe,
+	.remove		= spitzled_remove,
+#ifdef CONFIG_PM
+	.suspend	= spitzled_suspend,
+	.resume		= spitzled_resume,
+#endif
+	.driver		= {
+		.name		= "spitz-led",
+	},
+};
+
+static int __init spitzled_init(void)
+{
+	return platform_driver_register(&spitzled_driver);
+}
+
+static void __exit spitzled_exit(void)
+{
+ 	platform_driver_unregister(&spitzled_driver);
+}
+
+module_init(spitzled_init);
+module_exit(spitzled_exit);
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
+MODULE_DESCRIPTION("Spitz LED driver");
+MODULE_LICENSE("GPL");
diff -urN oldtree/drivers/leds/leds-tosa.c newtree/drivers/leds/leds-tosa.c
--- oldtree/drivers/leds/leds-tosa.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/leds/leds-tosa.c	2006-02-21 15:58:31.320385136 +0000
@@ -0,0 +1,131 @@
+/*
+ * LED Triggers Core
+ *
+ * Copyright 2005 Dirk Opfer
+ *
+ * Author: Dirk Opfer <Dirk@Opfer-Online.de>
+ *	based on spitz.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <asm/hardware/scoop.h>
+#include <asm/mach-types.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/tosa.h>
+
+static void tosaled_amber_set(struct led_classdev *led_cdev,
+				enum led_brightness value)
+{
+	if (value)
+		set_scoop_gpio(&tosascoop_jc_device.dev,
+				TOSA_SCOOP_JC_CHRG_ERR_LED);
+	else
+		reset_scoop_gpio(&tosascoop_jc_device.dev,
+				TOSA_SCOOP_JC_CHRG_ERR_LED);
+}
+
+static void tosaled_green_set(struct led_classdev *led_cdev,
+				enum led_brightness value)
+{
+	if (value)
+		set_scoop_gpio(&tosascoop_jc_device.dev,
+				TOSA_SCOOP_JC_NOTE_LED);
+	else
+		reset_scoop_gpio(&tosascoop_jc_device.dev,
+				TOSA_SCOOP_JC_NOTE_LED);
+}
+
+static struct led_classdev tosa_amber_led = {
+	.name			= "tosa:amber",
+	.default_trigger	= "sharpsl-charge",
+	.brightness_set		= tosaled_amber_set,
+};
+
+static struct led_classdev tosa_green_led = {
+	.name			= "tosa:green",
+	.default_trigger	= "nand-disk",
+	.brightness_set		= tosaled_green_set,
+};
+
+#ifdef CONFIG_PM
+static int tosaled_suspend(struct platform_device *dev, pm_message_t state)
+{
+#ifdef CONFIG_LEDS_TRIGGERS
+	if (tosa_amber_led.trigger && strcmp(tosa_amber_led.trigger->name,
+						"sharpsl-charge"))
+#endif
+		led_classdev_suspend(&tosa_amber_led);
+	led_classdev_suspend(&tosa_green_led);
+	return 0;
+}
+
+static int tosaled_resume(struct platform_device *dev)
+{
+	led_classdev_resume(&tosa_amber_led);
+	led_classdev_resume(&tosa_green_led);
+	return 0;
+}
+#else
+#define tosaled_suspend NULL
+#define tosaled_resume NULL
+#endif
+
+static int tosaled_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = led_classdev_register(&pdev->dev, &tosa_amber_led);
+	if (ret < 0)
+		return ret;
+
+	ret = led_classdev_register(&pdev->dev, &tosa_green_led);
+	if (ret < 0)
+		led_classdev_unregister(&tosa_amber_led);
+
+	return ret;
+}
+
+static int tosaled_remove(struct platform_device *pdev)
+{
+	led_classdev_unregister(&tosa_amber_led);
+	led_classdev_unregister(&tosa_green_led);
+
+	return 0;
+}
+
+static struct platform_driver tosaled_driver = {
+	.probe		= tosaled_probe,
+	.remove		= tosaled_remove,
+	.suspend	= tosaled_suspend,
+	.resume		= tosaled_resume,
+	.driver		= {
+		.name		= "tosa-led",
+	},
+};
+
+static int __init tosaled_init(void)
+{
+	return platform_driver_register(&tosaled_driver);
+}
+
+static void __exit tosaled_exit(void)
+{
+ 	platform_driver_unregister(&tosaled_driver);
+}
+
+module_init(tosaled_init);
+module_exit(tosaled_exit);
+
+MODULE_AUTHOR("Dirk Opfer <Dirk@Opfer-Online.de>");
+MODULE_DESCRIPTION("Tosa LED driver");
+MODULE_LICENSE("GPL");
diff -urN oldtree/drivers/leds/leds.h newtree/drivers/leds/leds.h
--- oldtree/drivers/leds/leds.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/leds/leds.h	2006-02-21 15:58:31.164408848 +0000
@@ -0,0 +1,45 @@
+/*
+ * LED Core
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <rpurdie@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#ifndef __LEDS_H_INCLUDED
+#define __LEDS_H_INCLUDED
+
+#include <linux/leds.h>
+
+/* led_cdev->lock must be held as write */
+static inline void led_set_brightness(struct led_classdev *led_cdev,
+					enum led_brightness value)
+{
+	if (value > LED_FULL)
+		value = LED_FULL;
+	led_cdev->brightness = value;
+	if (!(led_cdev->flags & LED_SUSPENDED))
+		led_cdev->brightness_set(led_cdev, value);
+}
+
+extern rwlock_t leds_list_lock;
+extern struct list_head leds_list;
+
+#ifdef CONFIG_LEDS_TRIGGERS
+void led_trigger_set_default(struct led_classdev *led_cdev);
+void led_trigger_set(struct led_classdev *led_cdev,
+			struct led_trigger *trigger);
+#else
+#define led_trigger_set_default(x) do {} while(0)
+#define led_trigger_set(x, y) do {} while(0)
+#endif
+
+ssize_t led_trigger_store(struct class_device *dev, const char *buf,
+			size_t count);
+ssize_t led_trigger_show(struct class_device *dev, char *buf);
+
+#endif	/* __LEDS_H_INCLUDED */
diff -urN oldtree/drivers/leds/ledtrig-timer.c newtree/drivers/leds/ledtrig-timer.c
--- oldtree/drivers/leds/ledtrig-timer.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/leds/ledtrig-timer.c	2006-02-21 15:58:31.179406568 +0000
@@ -0,0 +1,174 @@
+/*
+ * LED Kernel Timer Trigger
+ *
+ * Copyright 2005-2006 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <rpurdie@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/sysdev.h>
+#include <linux/timer.h>
+#include <linux/leds.h>
+#include "leds.h"
+
+struct timer_trig_data {
+	unsigned long delay_on;		/* milliseconds on */
+	unsigned long delay_off;	/* milliseconds off */
+	struct timer_list timer;
+};
+
+static void led_timer_function(unsigned long data)
+{
+	struct led_classdev *led_cdev = (struct led_classdev *) data;
+	struct timer_trig_data *timer_data = led_cdev->trigger_data;
+	unsigned long brightness = LED_OFF;
+	unsigned long delay = timer_data->delay_off;
+
+	if (!timer_data->delay_on || !timer_data->delay_off) {
+		write_lock(&led_cdev->lock);
+		led_set_brightness(led_cdev, LED_OFF);
+		write_unlock(&led_cdev->lock);
+		return;
+	}
+
+	if (!led_cdev->brightness) {
+		brightness = LED_FULL;
+		delay = timer_data->delay_on;
+	}
+
+	write_lock(&led_cdev->lock);
+	led_set_brightness(led_cdev, brightness);
+	write_unlock(&led_cdev->lock);
+
+	mod_timer(&timer_data->timer, jiffies + msecs_to_jiffies(delay));
+}
+
+static ssize_t led_delay_on_show(struct class_device *dev, char *buf)
+{
+	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct timer_trig_data *timer_data = led_cdev->trigger_data;
+
+	sprintf(buf, "%lu\n", timer_data->delay_on);
+
+	return strlen(buf) + 1;
+}
+
+static ssize_t led_delay_on_store(struct class_device *dev, const char *buf,
+				size_t size)
+{
+	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct timer_trig_data *timer_data = led_cdev->trigger_data;
+	int ret = -EINVAL;
+	char *after;
+	unsigned long state = simple_strtoul(buf, &after, 10);
+
+	if (after - buf > 0) {
+		timer_data->delay_on = state;
+		mod_timer(&timer_data->timer, jiffies + 1);
+		ret = after - buf;
+	}
+
+	return ret;
+}
+
+static ssize_t led_delay_off_show(struct class_device *dev, char *buf)
+{
+	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct timer_trig_data *timer_data = led_cdev->trigger_data;
+
+	sprintf(buf, "%lu\n", timer_data->delay_off);
+
+	return strlen(buf) + 1;
+}
+
+static ssize_t led_delay_off_store(struct class_device *dev, const char *buf,
+				size_t size)
+{
+	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct timer_trig_data *timer_data = led_cdev->trigger_data;
+	int ret = -EINVAL;
+	char *after;
+	unsigned long state = simple_strtoul(buf, &after, 10);
+
+	if (after - buf > 0) {
+		timer_data->delay_off = state;
+		mod_timer(&timer_data->timer, jiffies + 1);
+		ret = after - buf;
+	}
+
+	return ret;
+}
+
+static CLASS_DEVICE_ATTR(delay_on, 0644, led_delay_on_show,
+			led_delay_on_store);
+static CLASS_DEVICE_ATTR(delay_off, 0644, led_delay_off_show,
+			led_delay_off_store);
+
+static void timer_trig_activate(struct led_classdev *led_cdev)
+{
+	struct timer_trig_data *timer_data;
+
+	timer_data = kzalloc(sizeof(struct timer_trig_data), GFP_KERNEL);
+	if (!timer_data)
+		return;
+
+	led_cdev->trigger_data = timer_data;
+
+	init_timer(&timer_data->timer);
+	timer_data->timer.function = led_timer_function;
+	timer_data->timer.data = (unsigned long) led_cdev;
+
+	class_device_create_file(led_cdev->class_dev,
+				&class_device_attr_delay_on);
+	class_device_create_file(led_cdev->class_dev,
+				&class_device_attr_delay_off);
+}
+
+static void timer_trig_deactivate(struct led_classdev *led_cdev)
+{
+	struct timer_trig_data *timer_data = led_cdev->trigger_data;
+
+	if (timer_data) {
+		class_device_remove_file(led_cdev->class_dev,
+					&class_device_attr_delay_on);
+		class_device_remove_file(led_cdev->class_dev,
+					&class_device_attr_delay_off);
+		del_timer_sync(&timer_data->timer);
+		kfree(timer_data);
+	}
+}
+
+static struct led_trigger timer_led_trigger = {
+	.name     = "timer",
+	.activate = timer_trig_activate,
+	.deactivate = timer_trig_deactivate,
+};
+
+static int __init timer_trig_init(void)
+{
+	return led_trigger_register(&timer_led_trigger);
+}
+
+static void __exit timer_trig_exit(void)
+{
+	led_trigger_unregister(&timer_led_trigger);
+}
+
+module_init(timer_trig_init);
+module_exit(timer_trig_exit);
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
+MODULE_DESCRIPTION("Timer LED trigger");
+MODULE_LICENSE("GPL");
diff -urN oldtree/drivers/macintosh/smu.c newtree/drivers/macintosh/smu.c
--- oldtree/drivers/macintosh/smu.c	2006-02-19 11:41:02.486965024 +0000
+++ newtree/drivers/macintosh/smu.c	2006-02-21 15:58:24.173471632 +0000
@@ -35,6 +35,7 @@
 #include <linux/delay.h>
 #include <linux/sysdev.h>
 #include <linux/poll.h>
+#include <linux/mutex.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -92,7 +93,7 @@
  * for now, just hard code that
  */
 static struct smu_device	*smu;
-static DECLARE_MUTEX(smu_part_access);
+static DEFINE_MUTEX(smu_part_access);
 
 static void smu_i2c_retry(unsigned long data);
 
@@ -978,11 +979,11 @@
 
 	if (interruptible) {
 		int rc;
-		rc = down_interruptible(&smu_part_access);
+		rc = mutex_lock_interruptible(&smu_part_access);
 		if (rc)
 			return ERR_PTR(rc);
 	} else
-		down(&smu_part_access);
+		mutex_lock(&smu_part_access);
 
 	part = (struct smu_sdbp_header *)get_property(smu->of_node,
 						      pname, size);
@@ -992,7 +993,7 @@
 		if (part != NULL && size)
 			*size = part->len << 2;
 	}
-	up(&smu_part_access);
+	mutex_unlock(&smu_part_access);
 	return part;
 }
 
diff -urN oldtree/drivers/macintosh/via-pmu68k.c newtree/drivers/macintosh/via-pmu68k.c
--- oldtree/drivers/macintosh/via-pmu68k.c	2006-02-19 11:41:02.494963808 +0000
+++ newtree/drivers/macintosh/via-pmu68k.c	2006-02-21 15:58:36.283630608 +0000
@@ -112,7 +112,7 @@
 static int pmu_autopoll(int devs);
 void pmu_poll(void);
 static int pmu_reset_bus(void);
-static int pmu_queue_request(struct adb_request *req);
+static int pmu68k_queue_request(struct adb_request *req);
 
 static void pmu_start(void);
 static void send_byte(int x);
@@ -298,7 +298,7 @@
 			req->reply_len = 1;
 		} else
 			req->reply_len = 0;
-		ret = pmu_queue_request(req);
+		ret = pmu68k_queue_request(req);
 		break;
     case CUDA_PACKET:
 		switch (req->data[1]) {
@@ -311,7 +311,7 @@
 			req->reply[0] = CUDA_PACKET;
 			req->reply[1] = 0;
 			req->reply[2] = CUDA_GET_TIME;
-			ret = pmu_queue_request(req);
+			ret = pmu68k_queue_request(req);
 			break;
 		case CUDA_SET_TIME:
 			if (req->nbytes != 6)
@@ -324,7 +324,7 @@
 			req->reply[0] = CUDA_PACKET;
 			req->reply[1] = 0;
 			req->reply[2] = CUDA_SET_TIME;
-			ret = pmu_queue_request(req);
+			ret = pmu68k_queue_request(req);
 			break;
 		case CUDA_GET_PRAM:
 			if (req->nbytes != 4)
@@ -337,7 +337,7 @@
 			req->reply[0] = CUDA_PACKET;
 			req->reply[1] = 0;
 			req->reply[2] = CUDA_GET_PRAM;
-			ret = pmu_queue_request(req);
+			ret = pmu68k_queue_request(req);
 			break;
 		case CUDA_SET_PRAM:
 			if (req->nbytes != 5)
@@ -351,7 +351,7 @@
 			req->reply[0] = CUDA_PACKET;
 			req->reply[1] = 0;
 			req->reply[2] = CUDA_SET_PRAM;
-			ret = pmu_queue_request(req);
+			ret = pmu68k_queue_request(req);
 			break;
 		}
 		break;
@@ -365,7 +365,7 @@
 		req->nbytes += 2;
 		req->reply_expected = 1;
 		req->reply_len = 0;
-		ret = pmu_queue_request(req);
+		ret = pmu68k_queue_request(req);
 		break;
     }
     if (ret)
@@ -426,9 +426,9 @@
 	req.data[4] = 0;
 	req.reply_len = 0;
 	req.reply_expected = 1;
-	if (pmu_queue_request(&req) != 0)
+	if (pmu68k_queue_request(&req) != 0)
 	{
-		printk(KERN_ERR "pmu_adb_reset_bus: pmu_queue_request failed\n");
+		printk(KERN_ERR "pmu_adb_reset_bus: pmu68k_queue_request failed\n");
 		return -EIO;
 	}
 	while (!req.complete)
@@ -474,11 +474,11 @@
 	} else
 		req->reply_len = 0;
 	req->reply_expected = 0;
-	return pmu_queue_request(req);
+	return pmu68k_queue_request(req);
 }
 
 static int 
-pmu_queue_request(struct adb_request *req)
+pmu68k_queue_request(struct adb_request *req)
 {
 	unsigned long flags;
 	int nsend;
diff -urN oldtree/drivers/mca/mca-bus.c newtree/drivers/mca/mca-bus.c
--- oldtree/drivers/mca/mca-bus.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/mca/mca-bus.c	2006-02-21 15:58:16.085701160 +0000
@@ -63,9 +63,36 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int mca_bus_suspend(struct device *dev, pm_message_t state)
+{
+	int ret = 0;
+
+	if (dev->driver && dev->driver->suspend)
+		ret = dev->driver->suspend(dev, state);
+
+	return ret;
+}
+
+static int mca_bus_resume(struct device *dev)
+{
+	int ret = 0;
+
+	if (dev->driver && dev->driver->resume)
+		ret = dev->driver->resume(dev);
+
+	return ret;
+}
+#else
+#define mca_bus_suspend NULL
+#define mca_bus_resume NULL
+#endif
+
 struct bus_type mca_bus_type = {
 	.name  = "MCA",
 	.match = mca_bus_match,
+	.suspend = mca_bus_suspend,
+	.resume = mca_bus_resume,
 };
 EXPORT_SYMBOL (mca_bus_type);
 
diff -urN oldtree/drivers/md/bitmap.c newtree/drivers/md/bitmap.c
--- oldtree/drivers/md/bitmap.c	2006-02-19 11:41:02.503962440 +0000
+++ newtree/drivers/md/bitmap.c	2006-02-21 15:58:30.756470864 +0000
@@ -89,16 +89,6 @@
 }
 
 #define WRITE_POOL_SIZE 256
-/* mempool for queueing pending writes on the bitmap file */
-static void *write_pool_alloc(gfp_t gfp_flags, void *data)
-{
-	return kmalloc(sizeof(struct page_list), gfp_flags);
-}
-
-static void write_pool_free(void *ptr, void *data)
-{
-	kfree(ptr);
-}
 
 /*
  * just a placeholder - calls kmalloc for bitmap pages
@@ -1564,8 +1554,8 @@
 	spin_lock_init(&bitmap->write_lock);
 	INIT_LIST_HEAD(&bitmap->complete_pages);
 	init_waitqueue_head(&bitmap->write_wait);
-	bitmap->write_pool = mempool_create(WRITE_POOL_SIZE, write_pool_alloc,
-				write_pool_free, NULL);
+	bitmap->write_pool = mempool_create_kmalloc_pool(WRITE_POOL_SIZE,
+						sizeof(struct page_list));
 	err = -ENOMEM;
 	if (!bitmap->write_pool)
 		goto error;
diff -urN oldtree/drivers/md/dm-crypt.c newtree/drivers/md/dm-crypt.c
--- oldtree/drivers/md/dm-crypt.c	2006-02-19 11:41:02.504962288 +0000
+++ newtree/drivers/md/dm-crypt.c	2006-02-21 15:58:30.857455512 +0000
@@ -94,20 +94,6 @@
 static kmem_cache_t *_crypt_io_pool;
 
 /*
- * Mempool alloc and free functions for the page
- */
-static void *mempool_alloc_page(gfp_t gfp_mask, void *data)
-{
-	return alloc_page(gfp_mask);
-}
-
-static void mempool_free_page(void *page, void *data)
-{
-	__free_page(page);
-}
-
-
-/*
  * Different IV generation algorithms:
  *
  * plain: the initial vector is the 32-bit low-endian version of the sector
@@ -630,15 +616,13 @@
 		}
 	}
 
-	cc->io_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
-				     mempool_free_slab, _crypt_io_pool);
+	cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool);
 	if (!cc->io_pool) {
 		ti->error = PFX "Cannot allocate crypt io mempool";
 		goto bad3;
 	}
 
-	cc->page_pool = mempool_create(MIN_POOL_PAGES, mempool_alloc_page,
-				       mempool_free_page, NULL);
+	cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0);
 	if (!cc->page_pool) {
 		ti->error = PFX "Cannot allocate page mempool";
 		goto bad4;
diff -urN oldtree/drivers/md/dm-io.c newtree/drivers/md/dm-io.c
--- oldtree/drivers/md/dm-io.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/md/dm-io.c	2006-02-21 15:58:30.757470712 +0000
@@ -32,16 +32,6 @@
 static unsigned _num_ios;
 static mempool_t *_io_pool;
 
-static void *alloc_io(gfp_t gfp_mask, void *pool_data)
-{
-	return kmalloc(sizeof(struct io), gfp_mask);
-}
-
-static void free_io(void *element, void *pool_data)
-{
-	kfree(element);
-}
-
 static unsigned int pages_to_ios(unsigned int pages)
 {
 	return 4 * pages;	/* too many ? */
@@ -65,7 +55,8 @@
 
 	} else {
 		/* create new pool */
-		_io_pool = mempool_create(new_ios, alloc_io, free_io, NULL);
+		_io_pool = mempool_create_kmalloc_pool(new_ios,
+						       sizeof(struct io));
 		if (!_io_pool)
 			return -ENOMEM;
 
diff -urN oldtree/drivers/md/dm-mpath.c newtree/drivers/md/dm-mpath.c
--- oldtree/drivers/md/dm-mpath.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/md/dm-mpath.c	2006-02-21 15:58:30.858455360 +0000
@@ -179,8 +179,7 @@
 		m->queue_io = 1;
 		INIT_WORK(&m->process_queued_ios, process_queued_ios, m);
 		INIT_WORK(&m->trigger_event, trigger_event, m);
-		m->mpio_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
-					      mempool_free_slab, _mpio_cache);
+		m->mpio_pool = mempool_create_slab_pool(MIN_IOS, _mpio_cache);
 		if (!m->mpio_pool) {
 			kfree(m);
 			return NULL;
diff -urN oldtree/drivers/md/dm-raid1.c newtree/drivers/md/dm-raid1.c
--- oldtree/drivers/md/dm-raid1.c	2006-02-19 11:41:02.508961680 +0000
+++ newtree/drivers/md/dm-raid1.c	2006-02-21 15:58:30.758470560 +0000
@@ -122,16 +122,6 @@
 /* FIXME move this */
 static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw);
 
-static void *region_alloc(gfp_t gfp_mask, void *pool_data)
-{
-	return kmalloc(sizeof(struct region), gfp_mask);
-}
-
-static void region_free(void *element, void *pool_data)
-{
-	kfree(element);
-}
-
 #define MIN_REGIONS 64
 #define MAX_RECOVERY 1
 static int rh_init(struct region_hash *rh, struct mirror_set *ms,
@@ -173,8 +163,8 @@
 	INIT_LIST_HEAD(&rh->quiesced_regions);
 	INIT_LIST_HEAD(&rh->recovered_regions);
 
-	rh->region_pool = mempool_create(MIN_REGIONS, region_alloc,
-					 region_free, NULL);
+	rh->region_pool = mempool_create_kmalloc_pool(MIN_REGIONS,
+						      sizeof(struct region));
 	if (!rh->region_pool) {
 		vfree(rh->buckets);
 		rh->buckets = NULL;
diff -urN oldtree/drivers/md/dm-snap.c newtree/drivers/md/dm-snap.c
--- oldtree/drivers/md/dm-snap.c	2006-02-19 11:41:02.509961528 +0000
+++ newtree/drivers/md/dm-snap.c	2006-02-21 15:58:30.859455208 +0000
@@ -1174,8 +1174,7 @@
 		goto bad4;
 	}
 
-	pending_pool = mempool_create(128, mempool_alloc_slab,
-				      mempool_free_slab, pending_cache);
+	pending_pool = mempool_create_slab_pool(128, pending_cache);
 	if (!pending_pool) {
 		DMERR("Couldn't create pending pool.");
 		r = -ENOMEM;
diff -urN oldtree/drivers/md/dm-table.c newtree/drivers/md/dm-table.c
--- oldtree/drivers/md/dm-table.c	2006-02-19 11:41:02.510961376 +0000
+++ newtree/drivers/md/dm-table.c	2006-02-21 15:58:35.719716336 +0000
@@ -14,6 +14,7 @@
 #include <linux/ctype.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
+#include <linux/mutex.h>
 #include <asm/atomic.h>
 
 #define MAX_DEPTH 16
@@ -765,14 +766,14 @@
 	return r;
 }
 
-static DECLARE_MUTEX(_event_lock);
+static DEFINE_MUTEX(_event_lock);
 void dm_table_event_callback(struct dm_table *t,
 			     void (*fn)(void *), void *context)
 {
-	down(&_event_lock);
+	mutex_lock(&_event_lock);
 	t->event_fn = fn;
 	t->event_context = context;
-	up(&_event_lock);
+	mutex_unlock(&_event_lock);
 }
 
 void dm_table_event(struct dm_table *t)
@@ -783,10 +784,10 @@
 	 */
 	BUG_ON(in_interrupt());
 
-	down(&_event_lock);
+	mutex_lock(&_event_lock);
 	if (t->event_fn)
 		t->event_fn(t->event_context);
-	up(&_event_lock);
+	mutex_unlock(&_event_lock);
 }
 
 sector_t dm_table_get_size(struct dm_table *t)
diff -urN oldtree/drivers/md/dm.c newtree/drivers/md/dm.c
--- oldtree/drivers/md/dm.c	2006-02-19 11:41:02.511961224 +0000
+++ newtree/drivers/md/dm.c	2006-02-21 15:58:35.711717552 +0000
@@ -10,6 +10,7 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/moduleparam.h>
 #include <linux/blkpg.h>
 #include <linux/bio.h>
@@ -17,6 +18,7 @@
 #include <linux/mempool.h>
 #include <linux/slab.h>
 #include <linux/idr.h>
+#include <linux/blktrace_api.h>
 
 static const char *_name = DM_NAME;
 
@@ -334,6 +336,8 @@
 			/* nudge anyone waiting on suspend queue */
 			wake_up(&io->md->wait);
 
+		blk_add_trace_bio(io->md->queue, io->bio, BLK_TA_COMPLETE);
+
 		bio_endio(io->bio, io->bio->bi_size, io->error);
 		free_io(io->md, io);
 	}
@@ -392,6 +396,7 @@
 		      struct target_io *tio)
 {
 	int r;
+	sector_t sector;
 
 	/*
 	 * Sanity checks.
@@ -407,10 +412,17 @@
 	 * this io.
 	 */
 	atomic_inc(&tio->io->io_count);
+	sector = clone->bi_sector;
 	r = ti->type->map(ti, clone, &tio->info);
-	if (r > 0)
+	if (r > 0) {
 		/* the bio has been remapped so dispatch it */
+
+		blk_add_trace_remap(bdev_get_queue(clone->bi_bdev), clone, 
+				    tio->io->bio->bi_bdev->bd_dev, sector, 
+				    clone->bi_sector);
+
 		generic_make_request(clone);
+	}
 
 	else if (r < 0) {
 		/* error the io and bail out */
@@ -688,14 +700,14 @@
 /*-----------------------------------------------------------------
  * An IDR is used to keep track of allocated minor numbers.
  *---------------------------------------------------------------*/
-static DECLARE_MUTEX(_minor_lock);
+static DEFINE_MUTEX(_minor_lock);
 static DEFINE_IDR(_minor_idr);
 
 static void free_minor(unsigned int minor)
 {
-	down(&_minor_lock);
+	mutex_lock(&_minor_lock);
 	idr_remove(&_minor_idr, minor);
-	up(&_minor_lock);
+	mutex_unlock(&_minor_lock);
 }
 
 /*
@@ -708,7 +720,7 @@
 	if (minor >= (1 << MINORBITS))
 		return -EINVAL;
 
-	down(&_minor_lock);
+	mutex_lock(&_minor_lock);
 
 	if (idr_find(&_minor_idr, minor)) {
 		r = -EBUSY;
@@ -733,7 +745,7 @@
 	}
 
 out:
-	up(&_minor_lock);
+	mutex_unlock(&_minor_lock);
 	return r;
 }
 
@@ -742,7 +754,7 @@
 	int r;
 	unsigned int m;
 
-	down(&_minor_lock);
+	mutex_lock(&_minor_lock);
 
 	r = idr_pre_get(&_minor_idr, GFP_KERNEL);
 	if (!r) {
@@ -764,7 +776,7 @@
 	*minor = m;
 
 out:
-	up(&_minor_lock);
+	mutex_unlock(&_minor_lock);
 	return r;
 }
 
@@ -807,13 +819,11 @@
 	md->queue->unplug_fn = dm_unplug_all;
 	md->queue->issue_flush_fn = dm_flush_all;
 
-	md->io_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
-				     mempool_free_slab, _io_cache);
+	md->io_pool = mempool_create_slab_pool(MIN_IOS, _io_cache);
  	if (!md->io_pool)
  		goto bad2;
 
-	md->tio_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
-				      mempool_free_slab, _tio_cache);
+	md->tio_pool = mempool_create_slab_pool(MIN_IOS, _tio_cache);
 	if (!md->tio_pool)
 		goto bad3;
 
@@ -947,13 +957,13 @@
 	if (MAJOR(dev) != _major || minor >= (1 << MINORBITS))
 		return NULL;
 
-	down(&_minor_lock);
+	mutex_lock(&_minor_lock);
 
 	md = idr_find(&_minor_idr, minor);
 	if (!md || (dm_disk(md)->first_minor != minor))
 		md = NULL;
 
-	up(&_minor_lock);
+	mutex_unlock(&_minor_lock);
 
 	return md;
 }
diff -urN oldtree/drivers/md/kcopyd.c newtree/drivers/md/kcopyd.c
--- oldtree/drivers/md/kcopyd.c	2006-02-19 11:41:02.512961072 +0000
+++ newtree/drivers/md/kcopyd.c	2006-02-21 15:58:35.720716184 +0000
@@ -22,6 +22,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/workqueue.h>
+#include <linux/mutex.h>
 
 #include "kcopyd.h"
 
@@ -227,8 +228,7 @@
 	if (!_job_cache)
 		return -ENOMEM;
 
-	_job_pool = mempool_create(MIN_JOBS, mempool_alloc_slab,
-				   mempool_free_slab, _job_cache);
+	_job_pool = mempool_create_slab_pool(MIN_JOBS, _job_cache);
 	if (!_job_pool) {
 		kmem_cache_destroy(_job_cache);
 		return -ENOMEM;
@@ -573,68 +573,68 @@
 /*-----------------------------------------------------------------
  * Unit setup
  *---------------------------------------------------------------*/
-static DECLARE_MUTEX(_client_lock);
+static DEFINE_MUTEX(_client_lock);
 static LIST_HEAD(_clients);
 
 static void client_add(struct kcopyd_client *kc)
 {
-	down(&_client_lock);
+	mutex_lock(&_client_lock);
 	list_add(&kc->list, &_clients);
-	up(&_client_lock);
+	mutex_unlock(&_client_lock);
 }
 
 static void client_del(struct kcopyd_client *kc)
 {
-	down(&_client_lock);
+	mutex_lock(&_client_lock);
 	list_del(&kc->list);
-	up(&_client_lock);
+	mutex_unlock(&_client_lock);
 }
 
-static DECLARE_MUTEX(kcopyd_init_lock);
+static DEFINE_MUTEX(kcopyd_init_lock);
 static int kcopyd_clients = 0;
 
 static int kcopyd_init(void)
 {
 	int r;
 
-	down(&kcopyd_init_lock);
+	mutex_lock(&kcopyd_init_lock);
 
 	if (kcopyd_clients) {
 		/* Already initialized. */
 		kcopyd_clients++;
-		up(&kcopyd_init_lock);
+		mutex_unlock(&kcopyd_init_lock);
 		return 0;
 	}
 
 	r = jobs_init();
 	if (r) {
-		up(&kcopyd_init_lock);
+		mutex_unlock(&kcopyd_init_lock);
 		return r;
 	}
 
 	_kcopyd_wq = create_singlethread_workqueue("kcopyd");
 	if (!_kcopyd_wq) {
 		jobs_exit();
-		up(&kcopyd_init_lock);
+		mutex_unlock(&kcopyd_init_lock);
 		return -ENOMEM;
 	}
 
 	kcopyd_clients++;
 	INIT_WORK(&_kcopyd_work, do_work, NULL);
-	up(&kcopyd_init_lock);
+	mutex_unlock(&kcopyd_init_lock);
 	return 0;
 }
 
 static void kcopyd_exit(void)
 {
-	down(&kcopyd_init_lock);
+	mutex_lock(&kcopyd_init_lock);
 	kcopyd_clients--;
 	if (!kcopyd_clients) {
 		jobs_exit();
 		destroy_workqueue(_kcopyd_wq);
 		_kcopyd_wq = NULL;
 	}
-	up(&kcopyd_init_lock);
+	mutex_unlock(&kcopyd_init_lock);
 }
 
 int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result)
diff -urN oldtree/drivers/md/md.c newtree/drivers/md/md.c
--- oldtree/drivers/md/md.c	2006-02-19 11:41:02.516960464 +0000
+++ newtree/drivers/md/md.c	2006-02-21 15:58:35.724715576 +0000
@@ -43,6 +43,7 @@
 #include <linux/buffer_head.h> /* for invalidate_bdev */
 #include <linux/suspend.h>
 #include <linux/poll.h>
+#include <linux/mutex.h>
 
 #include <linux/init.h>
 
@@ -2377,7 +2378,7 @@
 
 static struct kobject *md_probe(dev_t dev, int *part, void *data)
 {
-	static DECLARE_MUTEX(disks_sem);
+	static DEFINE_MUTEX(disks_mutex);
 	mddev_t *mddev = mddev_find(dev);
 	struct gendisk *disk;
 	int partitioned = (MAJOR(dev) != MD_MAJOR);
@@ -2387,15 +2388,15 @@
 	if (!mddev)
 		return NULL;
 
-	down(&disks_sem);
+	mutex_lock(&disks_mutex);
 	if (mddev->gendisk) {
-		up(&disks_sem);
+		mutex_unlock(&disks_mutex);
 		mddev_put(mddev);
 		return NULL;
 	}
 	disk = alloc_disk(1 << shift);
 	if (!disk) {
-		up(&disks_sem);
+		mutex_unlock(&disks_mutex);
 		mddev_put(mddev);
 		return NULL;
 	}
@@ -2413,7 +2414,7 @@
 	disk->queue = mddev->queue;
 	add_disk(disk);
 	mddev->gendisk = disk;
-	up(&disks_sem);
+	mutex_unlock(&disks_mutex);
 	mddev->kobj.parent = &disk->kobj;
 	mddev->kobj.k_name = NULL;
 	snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md");
diff -urN oldtree/drivers/md/multipath.c newtree/drivers/md/multipath.c
--- oldtree/drivers/md/multipath.c	2006-02-19 11:41:02.517960312 +0000
+++ newtree/drivers/md/multipath.c	2006-02-21 15:58:30.798464480 +0000
@@ -35,18 +35,6 @@
 #define	NR_RESERVED_BUFS	32
 
 
-static void *mp_pool_alloc(gfp_t gfp_flags, void *data)
-{
-	struct multipath_bh *mpb;
-	mpb = kzalloc(sizeof(*mpb), gfp_flags);
-	return mpb;
-}
-
-static void mp_pool_free(void *mpb, void *data)
-{
-	kfree(mpb);
-}
-
 static int multipath_map (multipath_conf_t *conf)
 {
 	int i, disks = conf->raid_disks;
@@ -494,9 +482,8 @@
 	}
 	mddev->degraded = conf->raid_disks = conf->working_disks;
 
-	conf->pool = mempool_create(NR_RESERVED_BUFS,
-				    mp_pool_alloc, mp_pool_free,
-				    NULL);
+	conf->pool = mempool_create_kzalloc_pool(NR_RESERVED_BUFS,
+						 sizeof(struct multipath_bh));
 	if (conf->pool == NULL) {
 		printk(KERN_ERR 
 			"multipath: couldn't allocate memory for %s\n",
diff -urN oldtree/drivers/media/common/saa7146_core.c newtree/drivers/media/common/saa7146_core.c
--- oldtree/drivers/media/common/saa7146_core.c	2006-02-19 11:41:02.553954840 +0000
+++ newtree/drivers/media/common/saa7146_core.c	2006-02-21 15:58:13.419106544 +0000
@@ -21,7 +21,7 @@
 #include <media/saa7146.h>
 
 LIST_HEAD(saa7146_devices);
-DECLARE_MUTEX(saa7146_devices_lock);
+DEFINE_MUTEX(saa7146_devices_lock);
 
 static int saa7146_num;
 
@@ -402,11 +402,11 @@
 
 	pci_set_drvdata(pci, dev);
 
-	init_MUTEX(&dev->lock);
+	mutex_init(&dev->lock);
 	spin_lock_init(&dev->int_slock);
 	spin_lock_init(&dev->slock);
 
-	init_MUTEX(&dev->i2c_lock);
+	mutex_init(&dev->i2c_lock);
 
 	dev->module = THIS_MODULE;
 	init_waitqueue_head(&dev->i2c_wq);
diff -urN oldtree/drivers/media/common/saa7146_fops.c newtree/drivers/media/common/saa7146_fops.c
--- oldtree/drivers/media/common/saa7146_fops.c	2006-02-19 11:41:02.553954840 +0000
+++ newtree/drivers/media/common/saa7146_fops.c	2006-02-21 15:58:13.420106392 +0000
@@ -17,18 +17,18 @@
 	}
 
 	/* is it free? */
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	if (vv->resources & bit) {
 		DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit));
 		/* no, someone else uses it */
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		return 0;
 	}
 	/* it's free, grab it */
 	fh->resources  |= bit;
 	vv->resources |= bit;
 	DEB_D(("res: get 0x%02x, cur:0x%02x\n",bit,vv->resources));
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 	return 1;
 }
 
@@ -40,11 +40,11 @@
 	if ((fh->resources & bits) != bits)
 		BUG();
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	fh->resources  &= ~bits;
 	vv->resources &= ~bits;
 	DEB_D(("res: put 0x%02x, cur:0x%02x\n",bits,vv->resources));
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 }
 
 
@@ -204,7 +204,7 @@
 
 	DEB_EE(("inode:%p, file:%p, minor:%d\n",inode,file,minor));
 
-	if (down_interruptible(&saa7146_devices_lock))
+	if (mutex_lock_interruptible(&saa7146_devices_lock))
 		return -ERESTARTSYS;
 
 	list_for_each(list,&saa7146_devices) {
@@ -276,7 +276,7 @@
 		kfree(fh);
 		file->private_data = NULL;
 	}
-	up(&saa7146_devices_lock);
+	mutex_unlock(&saa7146_devices_lock);
 	return result;
 }
 
@@ -287,7 +287,7 @@
 
 	DEB_EE(("inode:%p, file:%p\n",inode,file));
 
-	if (down_interruptible(&saa7146_devices_lock))
+	if (mutex_lock_interruptible(&saa7146_devices_lock))
 		return -ERESTARTSYS;
 
 	if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
@@ -303,7 +303,7 @@
 	file->private_data = NULL;
 	kfree(fh);
 
-	up(&saa7146_devices_lock);
+	mutex_unlock(&saa7146_devices_lock);
 
 	return 0;
 }
diff -urN oldtree/drivers/media/common/saa7146_i2c.c newtree/drivers/media/common/saa7146_i2c.c
--- oldtree/drivers/media/common/saa7146_i2c.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/media/common/saa7146_i2c.c	2006-02-21 15:58:13.421106240 +0000
@@ -279,7 +279,7 @@
 	int address_err = 0;
 	int short_delay = 0;
 
-	if (down_interruptible (&dev->i2c_lock))
+	if (mutex_lock_interruptible(&dev->i2c_lock))
 		return -ERESTARTSYS;
 
 	for(i=0;i<num;i++) {
@@ -366,7 +366,7 @@
 		}
 	}
 
-	up(&dev->i2c_lock);
+	mutex_unlock(&dev->i2c_lock);
 	return err;
 }
 
diff -urN oldtree/drivers/media/common/saa7146_vbi.c newtree/drivers/media/common/saa7146_vbi.c
--- oldtree/drivers/media/common/saa7146_vbi.c	2006-02-19 11:41:02.555954536 +0000
+++ newtree/drivers/media/common/saa7146_vbi.c	2006-02-21 15:58:13.421106240 +0000
@@ -410,7 +410,7 @@
 			    V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
 			    sizeof(struct saa7146_buf),
 			    file);
-	init_MUTEX(&fh->vbi_q.lock);
+	mutex_init(&fh->vbi_q.lock);
 
 	init_timer(&fh->vbi_read_timeout);
 	fh->vbi_read_timeout.function = vbi_read_timeout;
diff -urN oldtree/drivers/media/common/saa7146_video.c newtree/drivers/media/common/saa7146_video.c
--- oldtree/drivers/media/common/saa7146_video.c	2006-02-19 11:41:02.556954384 +0000
+++ newtree/drivers/media/common/saa7146_video.c	2006-02-21 15:58:13.423105936 +0000
@@ -378,20 +378,20 @@
 		err = try_win(dev,&f->fmt.win);
 		if (0 != err)
 			return err;
-		down(&dev->lock);
+		mutex_lock(&dev->lock);
 		fh->ov.win    = f->fmt.win;
 		fh->ov.nclips = f->fmt.win.clipcount;
 		if (fh->ov.nclips > 16)
 			fh->ov.nclips = 16;
 		if (copy_from_user(fh->ov.clips,f->fmt.win.clips,sizeof(struct v4l2_clip)*fh->ov.nclips)) {
-			up(&dev->lock);
+			mutex_unlock(&dev->lock);
 			return -EFAULT;
 		}
 
 		/* fh->ov.fh is used to indicate that we have valid overlay informations, too */
 		fh->ov.fh = fh;
 
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 
 		/* check if our current overlay is active */
 		if (IS_OVERLAY_ACTIVE(fh) != 0) {
@@ -516,7 +516,7 @@
 		return -EINVAL;
 	}
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_BOOLEAN:
@@ -560,7 +560,7 @@
 		/* fixme: we can support changing VFLIP and HFLIP here... */
 		if (IS_CAPTURE_ACTIVE(fh) != 0) {
 			DEB_D(("V4L2_CID_HFLIP while active capture.\n"));
-			up(&dev->lock);
+			mutex_unlock(&dev->lock);
 			return -EINVAL;
 		}
 		vv->hflip = c->value;
@@ -568,7 +568,7 @@
 	case V4L2_CID_VFLIP:
 		if (IS_CAPTURE_ACTIVE(fh) != 0) {
 			DEB_D(("V4L2_CID_VFLIP while active capture.\n"));
-			up(&dev->lock);
+			mutex_unlock(&dev->lock);
 			return -EINVAL;
 		}
 		vv->vflip = c->value;
@@ -577,7 +577,7 @@
 		return -EINVAL;
 	}
 	}
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 
 	if (IS_OVERLAY_ACTIVE(fh) != 0) {
 		saa7146_stop_preview(fh);
@@ -939,7 +939,7 @@
 			}
 		}
 
-		down(&dev->lock);
+		mutex_lock(&dev->lock);
 
 		/* ok, accept it */
 		vv->ov_fb = *fb;
@@ -948,7 +948,7 @@
 			vv->ov_fb.fmt.bytesperline =
 				vv->ov_fb.fmt.width*fmt->depth/8;
 
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 
 		return 0;
 	}
@@ -1086,7 +1086,7 @@
 			}
 		}
 
-		down(&dev->lock);
+		mutex_lock(&dev->lock);
 
 		for(i = 0; i < dev->ext_vv_data->num_stds; i++)
 			if (*id & dev->ext_vv_data->stds[i].id)
@@ -1098,7 +1098,7 @@
 			found = 1;
 		}
 
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 
 		if (vv->ov_suspend != NULL) {
 			saa7146_start_preview(vv->ov_suspend);
@@ -1201,11 +1201,11 @@
 		DEB_D(("VIDIOCGMBUF \n"));
 
 		q = &fh->video_q;
-		down(&q->lock);
+		mutex_lock(&q->lock);
 		err = videobuf_mmap_setup(q,gbuffers,gbufsize,
 					  V4L2_MEMORY_MMAP);
 		if (err < 0) {
-			up(&q->lock);
+			mutex_unlock(&q->lock);
 			return err;
 		}
 		memset(mbuf,0,sizeof(*mbuf));
@@ -1213,7 +1213,7 @@
 		mbuf->size   = gbuffers * gbufsize;
 		for (i = 0; i < gbuffers; i++)
 			mbuf->offsets[i] = i * gbufsize;
-		up(&q->lock);
+		mutex_unlock(&q->lock);
 		return 0;
 	}
 	default:
@@ -1414,7 +1414,7 @@
 			    sizeof(struct saa7146_buf),
 			    file);
 
-	init_MUTEX(&fh->video_q.lock);
+	mutex_init(&fh->video_q.lock);
 
 	return 0;
 }
diff -urN oldtree/drivers/media/dvb/b2c2/flexcop-common.h newtree/drivers/media/dvb/b2c2/flexcop-common.h
--- oldtree/drivers/media/dvb/b2c2/flexcop-common.h	2006-02-19 11:41:02.557954232 +0000
+++ newtree/drivers/media/dvb/b2c2/flexcop-common.h	2006-02-21 15:58:13.423105936 +0000
@@ -10,6 +10,8 @@
 
 #include <linux/config.h>
 #include <linux/pci.h>
+#include <linux/mutex.h>
+
 
 #include "flexcop-reg.h"
 
@@ -73,7 +75,7 @@
 	int (*fe_sleep) (struct dvb_frontend *);
 
 	struct i2c_adapter i2c_adap;
-	struct semaphore i2c_sem;
+	struct mutex i2c_mutex;
 
 	struct module *owner;
 
diff -urN oldtree/drivers/media/dvb/b2c2/flexcop-i2c.c newtree/drivers/media/dvb/b2c2/flexcop-i2c.c
--- oldtree/drivers/media/dvb/b2c2/flexcop-i2c.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/media/dvb/b2c2/flexcop-i2c.c	2006-02-21 15:58:13.424105784 +0000
@@ -135,7 +135,7 @@
 	struct flexcop_device *fc = i2c_get_adapdata(i2c_adap);
 	int i, ret = 0;
 
-	if (down_interruptible(&fc->i2c_sem))
+	if (mutex_lock_interruptible(&fc->i2c_mutex))
 		return -ERESTARTSYS;
 
 	/* reading */
@@ -161,7 +161,7 @@
 	else
 		ret = num;
 
-	up(&fc->i2c_sem);
+	mutex_unlock(&fc->i2c_mutex);
 
 	return ret;
 }
@@ -180,7 +180,7 @@
 {
 	int ret;
 
-	sema_init(&fc->i2c_sem,1);
+	mutex_init(&fc->i2c_mutex);
 
 	memset(&fc->i2c_adap, 0, sizeof(struct i2c_adapter));
 	strncpy(fc->i2c_adap.name, "B2C2 FlexCop device",I2C_NAME_SIZE);
diff -urN oldtree/drivers/media/dvb/bt8xx/bt878.c newtree/drivers/media/dvb/bt8xx/bt878.c
--- oldtree/drivers/media/dvb/bt8xx/bt878.c	2006-02-19 11:41:02.561953624 +0000
+++ newtree/drivers/media/dvb/bt8xx/bt878.c	2006-02-21 15:58:13.426105480 +0000
@@ -344,7 +344,7 @@
 	int retval;
 
 	retval = 0;
-	if (down_interruptible (&bt->gpio_lock))
+	if (mutex_lock_interruptible(&bt->gpio_lock))
 		return -ERESTARTSYS;
 	/* special gpio signal */
 	switch (cmd) {
@@ -375,7 +375,7 @@
 		retval = -EINVAL;
 		break;
 	}
-	up(&bt->gpio_lock);
+	mutex_unlock(&bt->gpio_lock);
 	return retval;
 }
 
diff -urN oldtree/drivers/media/dvb/bt8xx/bt878.h newtree/drivers/media/dvb/bt8xx/bt878.h
--- oldtree/drivers/media/dvb/bt8xx/bt878.h	2006-02-19 11:41:02.562953472 +0000
+++ newtree/drivers/media/dvb/bt8xx/bt878.h	2006-02-21 15:58:13.427105328 +0000
@@ -25,6 +25,8 @@
 #include <linux/pci.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
+
 #include "bt848.h"
 #include "bttv.h"
 
@@ -108,7 +110,7 @@
 extern int bt878_num;
 
 struct bt878 {
-	struct semaphore  gpio_lock;
+	struct mutex gpio_lock;
 	unsigned int nr;
 	unsigned int bttv_nr;
 	struct i2c_adapter *adapter;
diff -urN oldtree/drivers/media/dvb/bt8xx/dst.c newtree/drivers/media/dvb/bt8xx/dst.c
--- oldtree/drivers/media/dvb/bt8xx/dst.c	2006-02-19 11:41:02.563953320 +0000
+++ newtree/drivers/media/dvb/bt8xx/dst.c	2006-02-21 15:58:13.428105176 +0000
@@ -910,7 +910,7 @@
 
 static int dst_probe(struct dst_state *state)
 {
-	sema_init(&state->dst_mutex, 1);
+	mutex_init(&state->dst_mutex);
 	if ((rdc_8820_reset(state)) < 0) {
 		dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
 		return -1;
@@ -962,7 +962,7 @@
 {
 	u8 reply;
 
-	down(&state->dst_mutex);
+	mutex_lock(&state->dst_mutex);
 	if ((dst_comm_init(state)) < 0) {
 		dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed.");
 		goto error;
@@ -1013,11 +1013,11 @@
 		dprintk(verbose, DST_INFO, 1, "checksum failure");
 		goto error;
 	}
-	up(&state->dst_mutex);
+	mutex_unlock(&state->dst_mutex);
 	return 0;
 
 error:
-	up(&state->dst_mutex);
+	mutex_unlock(&state->dst_mutex);
 	return -EIO;
 
 }
@@ -1128,7 +1128,7 @@
 			dst_set_voltage(fe, SEC_VOLTAGE_13);
 	}
 	state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE);
-	down(&state->dst_mutex);
+	mutex_lock(&state->dst_mutex);
 	if ((dst_comm_init(state)) < 0) {
 		dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed.");
 		goto error;
@@ -1160,11 +1160,11 @@
 	state->diseq_flags |= ATTEMPT_TUNE;
 	retval = dst_get_tuna(state);
 werr:
-	up(&state->dst_mutex);
+	mutex_unlock(&state->dst_mutex);
 	return retval;
 
 error:
-	up(&state->dst_mutex);
+	mutex_unlock(&state->dst_mutex);
 	return -EIO;
 }
 
diff -urN oldtree/drivers/media/dvb/bt8xx/dst_ca.c newtree/drivers/media/dvb/bt8xx/dst_ca.c
--- oldtree/drivers/media/dvb/bt8xx/dst_ca.c	2006-02-19 11:41:02.563953320 +0000
+++ newtree/drivers/media/dvb/bt8xx/dst_ca.c	2006-02-21 15:58:13.429105024 +0000
@@ -81,7 +81,7 @@
 {
 	u8 reply;
 
-	down(&state->dst_mutex);
+	mutex_lock(&state->dst_mutex);
 	dst_comm_init(state);
 	msleep(65);
 
@@ -110,11 +110,11 @@
 			goto error;
 		}
 	}
-	up(&state->dst_mutex);
+	mutex_unlock(&state->dst_mutex);
 	return 0;
 
 error:
-	up(&state->dst_mutex);
+	mutex_unlock(&state->dst_mutex);
 	return -EIO;
 }
 
diff -urN oldtree/drivers/media/dvb/bt8xx/dst_common.h newtree/drivers/media/dvb/bt8xx/dst_common.h
--- oldtree/drivers/media/dvb/bt8xx/dst_common.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/media/dvb/bt8xx/dst_common.h	2006-02-21 15:58:13.429105024 +0000
@@ -25,6 +25,8 @@
 #include <linux/smp_lock.h>
 #include <linux/dvb/frontend.h>
 #include <linux/device.h>
+#include <linux/mutex.h>
+
 #include "bt878.h"
 
 #include "dst_ca.h"
@@ -121,7 +123,7 @@
 	u8 vendor[8];
 	u8 board_info[8];
 
-	struct semaphore dst_mutex;
+	struct mutex dst_mutex;
 };
 
 struct dst_types {
diff -urN oldtree/drivers/media/dvb/bt8xx/dvb-bt8xx.c newtree/drivers/media/dvb/bt8xx/dvb-bt8xx.c
--- oldtree/drivers/media/dvb/bt8xx/dvb-bt8xx.c	2006-02-19 11:41:02.564953168 +0000
+++ newtree/drivers/media/dvb/bt8xx/dvb-bt8xx.c	2006-02-21 15:58:13.430104872 +0000
@@ -76,13 +76,13 @@
 	if (!dvbdmx->dmx.frontend)
 		return -EINVAL;
 
-	down(&card->lock);
+	mutex_lock(&card->lock);
 	card->nfeeds++;
 	rc = card->nfeeds;
 	if (card->nfeeds == 1)
 		bt878_start(card->bt, card->gpio_mode,
 			    card->op_sync_orin, card->irq_err_ignore);
-	up(&card->lock);
+	mutex_unlock(&card->lock);
 	return rc;
 }
 
@@ -96,11 +96,11 @@
 	if (!dvbdmx->dmx.frontend)
 		return -EINVAL;
 
-	down(&card->lock);
+	mutex_lock(&card->lock);
 	card->nfeeds--;
 	if (card->nfeeds == 0)
 		bt878_stop(card->bt);
-	up(&card->lock);
+	mutex_unlock(&card->lock);
 
 	return 0;
 }
@@ -788,7 +788,7 @@
 	if (!(card = kzalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL)))
 		return -ENOMEM;
 
-	init_MUTEX(&card->lock);
+	mutex_init(&card->lock);
 	card->bttv_nr = sub->core->nr;
 	strncpy(card->card_name, sub->core->name, sizeof(sub->core->name));
 	card->i2c_adapter = &sub->core->i2c_adap;
@@ -881,7 +881,7 @@
 		return -EFAULT;
 	}
 
-	init_MUTEX(&card->bt->gpio_lock);
+	mutex_init(&card->bt->gpio_lock);
 	card->bt->bttv_nr = sub->core->nr;
 
 	if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) {
diff -urN oldtree/drivers/media/dvb/bt8xx/dvb-bt8xx.h newtree/drivers/media/dvb/bt8xx/dvb-bt8xx.h
--- oldtree/drivers/media/dvb/bt8xx/dvb-bt8xx.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/media/dvb/bt8xx/dvb-bt8xx.h	2006-02-21 15:58:13.430104872 +0000
@@ -26,6 +26,8 @@
 #define DVB_BT8XX_H
 
 #include <linux/i2c.h>
+#include <linux/mutex.h>
+
 #include "dvbdev.h"
 #include "dvb_net.h"
 #include "bttv.h"
@@ -38,7 +40,7 @@
 #include "lgdt330x.h"
 
 struct dvb_bt8xx_card {
-	struct semaphore lock;
+	struct mutex lock;
 	int nfeeds;
 	char card_name[32];
 	struct dvb_adapter dvb_adapter;
diff -urN oldtree/drivers/media/dvb/cinergyT2/cinergyT2.c newtree/drivers/media/dvb/cinergyT2/cinergyT2.c
--- oldtree/drivers/media/dvb/cinergyT2/cinergyT2.c	2006-02-19 11:41:02.566952864 +0000
+++ newtree/drivers/media/dvb/cinergyT2/cinergyT2.c	2006-02-21 15:58:13.432104568 +0000
@@ -30,6 +30,8 @@
 #include <linux/pci.h>
 #include <linux/input.h>
 #include <linux/dvb/frontend.h>
+#include <linux/mutex.h>
+
 
 #include "dmxdev.h"
 #include "dvb_demux.h"
@@ -116,7 +118,7 @@
 struct cinergyt2 {
 	struct dvb_demux demux;
 	struct usb_device *udev;
-	struct semaphore sem;
+	struct mutex sem;
 	struct dvb_adapter adapter;
 	struct dvb_device *fedev;
 	struct dmxdev dmxdev;
@@ -345,14 +347,14 @@
 	struct dvb_demux *demux = dvbdmxfeed->demux;
 	struct cinergyt2 *cinergyt2 = demux->priv;
 
-	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	if (cinergyt2->streaming == 0)
 		cinergyt2_start_stream_xfer(cinergyt2);
 
 	cinergyt2->streaming++;
-	up(&cinergyt2->sem);
+	mutex_unlock(&cinergyt2->sem);
 	return 0;
 }
 
@@ -361,13 +363,13 @@
 	struct dvb_demux *demux = dvbdmxfeed->demux;
 	struct cinergyt2 *cinergyt2 = demux->priv;
 
-	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	if (--cinergyt2->streaming == 0)
 		cinergyt2_stop_stream_xfer(cinergyt2);
 
-	up(&cinergyt2->sem);
+	mutex_unlock(&cinergyt2->sem);
 	return 0;
 }
 
@@ -483,11 +485,11 @@
 	struct cinergyt2 *cinergyt2 = dvbdev->priv;
 	int err = -ERESTARTSYS;
 
-	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	if ((err = dvb_generic_open(inode, file))) {
-		up(&cinergyt2->sem);
+		mutex_unlock(&cinergyt2->sem);
 		return err;
 	}
 
@@ -499,7 +501,7 @@
 
 	atomic_inc(&cinergyt2->inuse);
 
-	up(&cinergyt2->sem);
+	mutex_unlock(&cinergyt2->sem);
 	return 0;
 }
 
@@ -517,7 +519,7 @@
 	struct dvb_device *dvbdev = file->private_data;
 	struct cinergyt2 *cinergyt2 = dvbdev->priv;
 
-	if (down_interruptible(&cinergyt2->sem))
+	if (mutex_lock_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	if (!cinergyt2->disconnect_pending && (file->f_flags & O_ACCMODE) != O_RDONLY) {
@@ -526,7 +528,7 @@
 		cinergyt2_sleep(cinergyt2, 1);
 	}
 
-	up(&cinergyt2->sem);
+	mutex_unlock(&cinergyt2->sem);
 
 	if (atomic_dec_and_test(&cinergyt2->inuse) && cinergyt2->disconnect_pending) {
 		warn("delayed unregister in release");
@@ -541,12 +543,12 @@
 	struct dvb_device *dvbdev = file->private_data;
 	struct cinergyt2 *cinergyt2 = dvbdev->priv;
 
-	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	poll_wait(file, &cinergyt2->poll_wq, wait);
 
-	up(&cinergyt2->sem);
+	mutex_unlock(&cinergyt2->sem);
 
 	return (POLLIN | POLLRDNORM | POLLPRI);
 }
@@ -613,7 +615,7 @@
 		if (copy_from_user(&p, (void  __user*) arg, sizeof(p)))
 			return -EFAULT;
 
-		if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+		if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 			return -ERESTARTSYS;
 
 		param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
@@ -629,7 +631,7 @@
 					(char *) param, sizeof(*param),
 					NULL, 0);
 
-		up(&cinergyt2->sem);
+		mutex_unlock(&cinergyt2->sem);
 
 		return (err < 0) ? err : 0;
 	}
@@ -724,7 +726,7 @@
 	struct cinergyt2_rc_event rc_events[12];
 	int n, len, i;
 
-	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return;
 
 	len = cinergyt2_command(cinergyt2, buf, sizeof(buf),
@@ -784,7 +786,7 @@
 	schedule_delayed_work(&cinergyt2->rc_query_work,
 			      msecs_to_jiffies(RC_QUERY_INTERVAL));
 
-	up(&cinergyt2->sem);
+	mutex_unlock(&cinergyt2->sem);
 }
 
 static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
@@ -849,7 +851,7 @@
 	uint8_t lock_bits;
 	uint32_t unc;
 
-	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return;
 
 	unc = s->uncorrected_block_count;
@@ -868,7 +870,7 @@
 	schedule_delayed_work(&cinergyt2->query_work,
 			      msecs_to_jiffies(QUERY_INTERVAL));
 
-	up(&cinergyt2->sem);
+	mutex_unlock(&cinergyt2->sem);
 }
 
 static int cinergyt2_probe (struct usb_interface *intf,
@@ -885,7 +887,7 @@
 	memset (cinergyt2, 0, sizeof (struct cinergyt2));
 	usb_set_intfdata (intf, (void *) cinergyt2);
 
-	init_MUTEX(&cinergyt2->sem);
+	mutex_init(&cinergyt2->sem);
 	init_waitqueue_head (&cinergyt2->poll_wq);
 	INIT_WORK(&cinergyt2->query_work, cinergyt2_query, cinergyt2);
 
@@ -967,7 +969,7 @@
 {
 	struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
 
-	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	if (state.event > PM_EVENT_ON) {
@@ -981,7 +983,7 @@
 		cinergyt2_sleep(cinergyt2, 1);
 	}
 
-	up(&cinergyt2->sem);
+	mutex_unlock(&cinergyt2->sem);
 	return 0;
 }
 
@@ -990,7 +992,7 @@
 	struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
 	struct dvbt_set_parameters_msg *param = &cinergyt2->param;
 
-	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	if (!cinergyt2->sleeping) {
@@ -1003,7 +1005,7 @@
 
 	cinergyt2_resume_rc(cinergyt2);
 
-	up(&cinergyt2->sem);
+	mutex_unlock(&cinergyt2->sem);
 	return 0;
 }
 
diff -urN oldtree/drivers/media/dvb/dvb-core/dmxdev.c newtree/drivers/media/dvb/dvb-core/dmxdev.c
--- oldtree/drivers/media/dvb/dvb-core/dmxdev.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/media/dvb/dvb-core/dmxdev.c	2006-02-21 15:58:13.433104416 +0000
@@ -175,12 +175,12 @@
 
 	dprintk ("function : %s\n", __FUNCTION__);
 
-	if (down_interruptible (&dmxdev->mutex))
+	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
 
 	if ((file->f_flags&O_ACCMODE)==O_RDWR) {
 		if (!(dmxdev->capabilities&DMXDEV_CAP_DUPLEX)) {
-			up(&dmxdev->mutex);
+			mutex_unlock(&dmxdev->mutex);
 			return -EOPNOTSUPP;
 		}
 	}
@@ -190,7 +190,7 @@
 	      dmxdev->dvr_buffer.size=DVR_BUFFER_SIZE;
 	      dmxdev->dvr_buffer.data=vmalloc(DVR_BUFFER_SIZE);
 	      if (!dmxdev->dvr_buffer.data) {
-		      up(&dmxdev->mutex);
+		      mutex_unlock(&dmxdev->mutex);
 		      return -ENOMEM;
 	      }
 	}
@@ -199,20 +199,20 @@
 		dmxdev->dvr_orig_fe=dmxdev->demux->frontend;
 
 		if (!dmxdev->demux->write) {
-			up(&dmxdev->mutex);
+			mutex_unlock(&dmxdev->mutex);
 			return -EOPNOTSUPP;
 		}
 
 		front=get_fe(dmxdev->demux, DMX_MEMORY_FE);
 
 		if (!front) {
-			up(&dmxdev->mutex);
+			mutex_unlock(&dmxdev->mutex);
 			return -EINVAL;
 		}
 		dmxdev->demux->disconnect_frontend(dmxdev->demux);
 		dmxdev->demux->connect_frontend(dmxdev->demux, front);
 	}
-	up(&dmxdev->mutex);
+	mutex_unlock(&dmxdev->mutex);
 	return 0;
 }
 
@@ -221,7 +221,7 @@
 	struct dvb_device *dvbdev = file->private_data;
 	struct dmxdev *dmxdev = dvbdev->priv;
 
-	if (down_interruptible (&dmxdev->mutex))
+	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
 
 	if ((file->f_flags&O_ACCMODE)==O_WRONLY) {
@@ -239,7 +239,7 @@
 			vfree(mem);
 		}
 	}
-	up(&dmxdev->mutex);
+	mutex_unlock(&dmxdev->mutex);
 	return 0;
 }
 
@@ -254,10 +254,10 @@
 		return -EOPNOTSUPP;
 	if ((file->f_flags&O_ACCMODE)!=O_WRONLY)
 		return -EINVAL;
-	if (down_interruptible (&dmxdev->mutex))
+	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
 	ret=dmxdev->demux->write(dmxdev->demux, buf, count);
-	up(&dmxdev->mutex);
+	mutex_unlock(&dmxdev->mutex);
 	return ret;
 }
 
@@ -268,11 +268,11 @@
 	struct dmxdev *dmxdev = dvbdev->priv;
 	int ret;
 
-	//down(&dmxdev->mutex);
+	//mutex_lock(&dmxdev->mutex);
 	ret= dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
 			      file->f_flags&O_NONBLOCK,
 			      buf, count, ppos);
-	//up(&dmxdev->mutex);
+	//mutex_unlock(&dmxdev->mutex);
 	return ret;
 }
 
@@ -688,7 +688,7 @@
 	if (!dmxdev->filter)
 		return -EINVAL;
 
-	if (down_interruptible(&dmxdev->mutex))
+	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
 
 	for (i=0; i<dmxdev->filternum; i++)
@@ -696,12 +696,12 @@
 			break;
 
 	if (i==dmxdev->filternum) {
-		up(&dmxdev->mutex);
+		mutex_unlock(&dmxdev->mutex);
 		return -EMFILE;
 	}
 
 	dmxdevfilter=&dmxdev->filter[i];
-	sema_init(&dmxdevfilter->mutex, 1);
+	mutex_init(&dmxdevfilter->mutex);
 	dmxdevfilter->dvbdev=dmxdev->dvbdev;
 	file->private_data=dmxdevfilter;
 
@@ -711,18 +711,18 @@
 	dmxdevfilter->feed.ts=NULL;
 	init_timer(&dmxdevfilter->timer);
 
-	up(&dmxdev->mutex);
+	mutex_unlock(&dmxdev->mutex);
 	return 0;
 }
 
 
 static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, struct dmxdev_filter *dmxdevfilter)
 {
-	if (down_interruptible(&dmxdev->mutex))
+	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
 
-	if (down_interruptible(&dmxdevfilter->mutex)) {
-		up(&dmxdev->mutex);
+	if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+		mutex_unlock(&dmxdev->mutex);
 		return -ERESTARTSYS;
 	}
 
@@ -740,8 +740,8 @@
 
 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);
 	wake_up(&dmxdevfilter->buffer.queue);
-	up(&dmxdevfilter->mutex);
-	up(&dmxdev->mutex);
+	mutex_unlock(&dmxdevfilter->mutex);
+	mutex_unlock(&dmxdev->mutex);
 	return 0;
 }
 
@@ -841,7 +841,7 @@
 	struct dmxdev_filter *dmxdevfilter= file->private_data;
 	int ret=0;
 
-	if (down_interruptible(&dmxdevfilter->mutex))
+	if (mutex_lock_interruptible(&dmxdevfilter->mutex))
 		return -ERESTARTSYS;
 
 	if (dmxdevfilter->type==DMXDEV_TYPE_SEC)
@@ -851,7 +851,7 @@
 				     file->f_flags&O_NONBLOCK,
 				     buf, count, ppos);
 
-	up(&dmxdevfilter->mutex);
+	mutex_unlock(&dmxdevfilter->mutex);
 	return ret;
 }
 
@@ -864,58 +864,58 @@
 	unsigned long arg=(unsigned long) parg;
 	int ret=0;
 
-	if (down_interruptible (&dmxdev->mutex))
+	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
 
 	switch (cmd) {
 	case DMX_START:
-		if (down_interruptible(&dmxdevfilter->mutex)) {
-			up(&dmxdev->mutex);
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
 			return -ERESTARTSYS;
 		}
 		if (dmxdevfilter->state<DMXDEV_STATE_SET)
 			ret = -EINVAL;
 		else
 			ret = dvb_dmxdev_filter_start(dmxdevfilter);
-		up(&dmxdevfilter->mutex);
+		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
 	case DMX_STOP:
-		if (down_interruptible(&dmxdevfilter->mutex)) {
-			up(&dmxdev->mutex);
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
 			return -ERESTARTSYS;
 		}
 		ret=dvb_dmxdev_filter_stop(dmxdevfilter);
-		up(&dmxdevfilter->mutex);
+		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
 	case DMX_SET_FILTER:
-		if (down_interruptible(&dmxdevfilter->mutex)) {
-			up(&dmxdev->mutex);
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
 			return -ERESTARTSYS;
 		}
 		ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter,
 				    (struct dmx_sct_filter_params *)parg);
-		up(&dmxdevfilter->mutex);
+		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
 	case DMX_SET_PES_FILTER:
-		if (down_interruptible(&dmxdevfilter->mutex)) {
-			up(&dmxdev->mutex);
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
 			return -ERESTARTSYS;
 		}
 		ret=dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter,
 					       (struct dmx_pes_filter_params *)parg);
-		up(&dmxdevfilter->mutex);
+		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
 	case DMX_SET_BUFFER_SIZE:
-		if (down_interruptible(&dmxdevfilter->mutex)) {
-			up(&dmxdev->mutex);
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
 			return -ERESTARTSYS;
 		}
 		ret=dvb_dmxdev_set_buffer_size(dmxdevfilter, arg);
-		up(&dmxdevfilter->mutex);
+		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
 	case DMX_GET_EVENT:
@@ -959,7 +959,7 @@
 	default:
 		ret=-EINVAL;
 	}
-	up(&dmxdev->mutex);
+	mutex_unlock(&dmxdev->mutex);
 	return ret;
 }
 
@@ -1030,7 +1030,7 @@
 
 	int ret=0;
 
-	if (down_interruptible (&dmxdev->mutex))
+	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
 
 	switch (cmd) {
@@ -1042,7 +1042,7 @@
 	default:
 		ret=-EINVAL;
 	}
-	up(&dmxdev->mutex);
+	mutex_unlock(&dmxdev->mutex);
 	return ret;
 }
 
@@ -1113,7 +1113,7 @@
 		return -ENOMEM;
 	}
 
-	sema_init(&dmxdev->mutex, 1);
+	mutex_init(&dmxdev->mutex);
 	spin_lock_init(&dmxdev->lock);
 	for (i=0; i<dmxdev->filternum; i++) {
 		dmxdev->filter[i].dev=dmxdev;
diff -urN oldtree/drivers/media/dvb/dvb-core/dmxdev.h newtree/drivers/media/dvb/dvb-core/dmxdev.h
--- oldtree/drivers/media/dvb/dvb-core/dmxdev.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/media/dvb/dvb-core/dmxdev.h	2006-02-21 15:58:13.433104416 +0000
@@ -30,7 +30,7 @@
 #include <linux/wait.h>
 #include <linux/fs.h>
 #include <linux/string.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include <linux/dvb/dmx.h>
 
@@ -83,7 +83,7 @@
 	struct dmxdev *dev;
 	struct dmxdev_buffer buffer;
 
-	struct semaphore mutex;
+	struct mutex mutex;
 
 	/* only for sections */
 	struct timer_list timer;
@@ -117,7 +117,7 @@
 	struct dmxdev_buffer dvr_buffer;
 #define DVR_BUFFER_SIZE (10*188*1024)
 
-	struct semaphore mutex;
+	struct mutex mutex;
 	spinlock_t lock;
 };
 
diff -urN oldtree/drivers/media/dvb/dvb-core/dvb_demux.c newtree/drivers/media/dvb/dvb-core/dvb_demux.c
--- oldtree/drivers/media/dvb/dvb-core/dvb_demux.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/media/dvb/dvb-core/dvb_demux.c	2006-02-21 15:58:13.435104112 +0000
@@ -589,18 +589,18 @@
 	if (pid > DMX_MAX_PID)
 		return -EINVAL;
 
-	if (down_interruptible(&demux->mutex))
+	if (mutex_lock_interruptible(&demux->mutex))
 		return -ERESTARTSYS;
 
 	if (ts_type & TS_DECODER) {
 		if (pes_type >= DMX_TS_PES_OTHER) {
-			up(&demux->mutex);
+			mutex_unlock(&demux->mutex);
 			return -EINVAL;
 		}
 
 		if (demux->pesfilter[pes_type] &&
 		    demux->pesfilter[pes_type] != feed) {
-			up(&demux->mutex);
+			mutex_unlock(&demux->mutex);
 			return -EINVAL;
 		}
 
@@ -622,14 +622,14 @@
 #else
 		feed->buffer = vmalloc(feed->buffer_size);
 		if (!feed->buffer) {
-			up(&demux->mutex);
+			mutex_unlock(&demux->mutex);
 			return -ENOMEM;
 		}
 #endif
 	}
 
 	feed->state = DMX_STATE_READY;
-	up(&demux->mutex);
+	mutex_unlock(&demux->mutex);
 
 	return 0;
 }
@@ -640,21 +640,21 @@
 	struct dvb_demux *demux = feed->demux;
 	int ret;
 
-	if (down_interruptible(&demux->mutex))
+	if (mutex_lock_interruptible(&demux->mutex))
 		return -ERESTARTSYS;
 
 	if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) {
-		up(&demux->mutex);
+		mutex_unlock(&demux->mutex);
 		return -EINVAL;
 	}
 
 	if (!demux->start_feed) {
-		up(&demux->mutex);
+		mutex_unlock(&demux->mutex);
 		return -ENODEV;
 	}
 
 	if ((ret = demux->start_feed(feed)) < 0) {
-		up(&demux->mutex);
+		mutex_unlock(&demux->mutex);
 		return ret;
 	}
 
@@ -662,7 +662,7 @@
 	ts_feed->is_filtering = 1;
 	feed->state = DMX_STATE_GO;
 	spin_unlock_irq(&demux->lock);
-	up(&demux->mutex);
+	mutex_unlock(&demux->mutex);
 
 	return 0;
 }
@@ -673,16 +673,16 @@
 	struct dvb_demux *demux = feed->demux;
 	int ret;
 
-	if (down_interruptible(&demux->mutex))
+	if (mutex_lock_interruptible(&demux->mutex))
 		return -ERESTARTSYS;
 
 	if (feed->state < DMX_STATE_GO) {
-		up(&demux->mutex);
+		mutex_unlock(&demux->mutex);
 		return -EINVAL;
 	}
 
 	if (!demux->stop_feed) {
-		up(&demux->mutex);
+		mutex_unlock(&demux->mutex);
 		return -ENODEV;
 	}
 
@@ -692,7 +692,7 @@
 	ts_feed->is_filtering = 0;
 	feed->state = DMX_STATE_ALLOCATED;
 	spin_unlock_irq(&demux->lock);
-	up(&demux->mutex);
+	mutex_unlock(&demux->mutex);
 
 	return ret;
 }
@@ -704,11 +704,11 @@
 	struct dvb_demux *demux = (struct dvb_demux *)dmx;
 	struct dvb_demux_feed *feed;
 
-	if (down_interruptible(&demux->mutex))
+	if (mutex_lock_interruptible(&demux->mutex))
 		return -ERESTARTSYS;
 
 	if (!(feed = dvb_dmx_feed_alloc(demux))) {
-		up(&demux->mutex);
+		mutex_unlock(&demux->mutex);
 		return -EBUSY;
 	}
 
@@ -729,7 +729,7 @@
 
 	if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
 		feed->state = DMX_STATE_FREE;
-		up(&demux->mutex);
+		mutex_unlock(&demux->mutex);
 		return -EBUSY;
 	}
 
@@ -737,7 +737,7 @@
 	feed->filter->feed = feed;
 	feed->filter->state = DMX_STATE_READY;
 
-	up(&demux->mutex);
+	mutex_unlock(&demux->mutex);
 
 	return 0;
 }
@@ -748,11 +748,11 @@
 	struct dvb_demux *demux = (struct dvb_demux *)dmx;
 	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
 
-	if (down_interruptible(&demux->mutex))
+	if (mutex_lock_interruptible(&demux->mutex))
 		return -ERESTARTSYS;
 
 	if (feed->state == DMX_STATE_FREE) {
-		up(&demux->mutex);
+		mutex_unlock(&demux->mutex);
 		return -EINVAL;
 	}
 #ifndef NOBUFS
@@ -770,7 +770,7 @@
 	if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER)
 		demux->pesfilter[feed->pes_type] = NULL;
 
-	up(&demux->mutex);
+	mutex_unlock(&demux->mutex);
 	return 0;
 }
 
@@ -785,12 +785,12 @@
 	struct dvb_demux *dvbdemux = dvbdmxfeed->demux;
 	struct dvb_demux_filter *dvbdmxfilter;
 
-	if (down_interruptible(&dvbdemux->mutex))
+	if (mutex_lock_interruptible(&dvbdemux->mutex))
 		return -ERESTARTSYS;
 
 	dvbdmxfilter = dvb_dmx_filter_alloc(dvbdemux);
 	if (!dvbdmxfilter) {
-		up(&dvbdemux->mutex);
+		mutex_unlock(&dvbdemux->mutex);
 		return -EBUSY;
 	}
 
@@ -805,7 +805,7 @@
 	dvbdmxfeed->filter = dvbdmxfilter;
 	spin_unlock_irq(&dvbdemux->lock);
 
-	up(&dvbdemux->mutex);
+	mutex_unlock(&dvbdemux->mutex);
 	return 0;
 }
 
@@ -819,7 +819,7 @@
 	if (pid > 0x1fff)
 		return -EINVAL;
 
-	if (down_interruptible(&dvbdmx->mutex))
+	if (mutex_lock_interruptible(&dvbdmx->mutex))
 		return -ERESTARTSYS;
 
 	dvb_demux_feed_add(dvbdmxfeed);
@@ -833,13 +833,13 @@
 #else
 	dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size);
 	if (!dvbdmxfeed->buffer) {
-		up(&dvbdmx->mutex);
+		mutex_unlock(&dvbdmx->mutex);
 		return -ENOMEM;
 	}
 #endif
 
 	dvbdmxfeed->state = DMX_STATE_READY;
-	up(&dvbdmx->mutex);
+	mutex_unlock(&dvbdmx->mutex);
 	return 0;
 }
 
@@ -871,16 +871,16 @@
 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
 	int ret;
 
-	if (down_interruptible(&dvbdmx->mutex))
+	if (mutex_lock_interruptible(&dvbdmx->mutex))
 		return -ERESTARTSYS;
 
 	if (feed->is_filtering) {
-		up(&dvbdmx->mutex);
+		mutex_unlock(&dvbdmx->mutex);
 		return -EBUSY;
 	}
 
 	if (!dvbdmxfeed->filter) {
-		up(&dvbdmx->mutex);
+		mutex_unlock(&dvbdmx->mutex);
 		return -EINVAL;
 	}
 
@@ -890,14 +890,14 @@
 	dvbdmxfeed->feed.sec.seclen = 0;
 
 	if (!dvbdmx->start_feed) {
-		up(&dvbdmx->mutex);
+		mutex_unlock(&dvbdmx->mutex);
 		return -ENODEV;
 	}
 
 	prepare_secfilters(dvbdmxfeed);
 
 	if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) {
-		up(&dvbdmx->mutex);
+		mutex_unlock(&dvbdmx->mutex);
 		return ret;
 	}
 
@@ -906,7 +906,7 @@
 	dvbdmxfeed->state = DMX_STATE_GO;
 	spin_unlock_irq(&dvbdmx->lock);
 
-	up(&dvbdmx->mutex);
+	mutex_unlock(&dvbdmx->mutex);
 	return 0;
 }
 
@@ -916,11 +916,11 @@
 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
 	int ret;
 
-	if (down_interruptible(&dvbdmx->mutex))
+	if (mutex_lock_interruptible(&dvbdmx->mutex))
 		return -ERESTARTSYS;
 
 	if (!dvbdmx->stop_feed) {
-		up(&dvbdmx->mutex);
+		mutex_unlock(&dvbdmx->mutex);
 		return -ENODEV;
 	}
 
@@ -931,7 +931,7 @@
 	feed->is_filtering = 0;
 	spin_unlock_irq(&dvbdmx->lock);
 
-	up(&dvbdmx->mutex);
+	mutex_unlock(&dvbdmx->mutex);
 	return ret;
 }
 
@@ -942,11 +942,11 @@
 	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
 
-	if (down_interruptible(&dvbdmx->mutex))
+	if (mutex_lock_interruptible(&dvbdmx->mutex))
 		return -ERESTARTSYS;
 
 	if (dvbdmxfilter->feed != dvbdmxfeed) {
-		up(&dvbdmx->mutex);
+		mutex_unlock(&dvbdmx->mutex);
 		return -EINVAL;
 	}
 
@@ -966,7 +966,7 @@
 
 	dvbdmxfilter->state = DMX_STATE_FREE;
 	spin_unlock_irq(&dvbdmx->lock);
-	up(&dvbdmx->mutex);
+	mutex_unlock(&dvbdmx->mutex);
 	return 0;
 }
 
@@ -977,11 +977,11 @@
 	struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
 	struct dvb_demux_feed *dvbdmxfeed;
 
-	if (down_interruptible(&dvbdmx->mutex))
+	if (mutex_lock_interruptible(&dvbdmx->mutex))
 		return -ERESTARTSYS;
 
 	if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) {
-		up(&dvbdmx->mutex);
+		mutex_unlock(&dvbdmx->mutex);
 		return -EBUSY;
 	}
 
@@ -1006,7 +1006,7 @@
 	(*feed)->stop_filtering = dmx_section_feed_stop_filtering;
 	(*feed)->release_filter = dmx_section_feed_release_filter;
 
-	up(&dvbdmx->mutex);
+	mutex_unlock(&dvbdmx->mutex);
 	return 0;
 }
 
@@ -1016,11 +1016,11 @@
 	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
 	struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
 
-	if (down_interruptible(&dvbdmx->mutex))
+	if (mutex_lock_interruptible(&dvbdmx->mutex))
 		return -ERESTARTSYS;
 
 	if (dvbdmxfeed->state == DMX_STATE_FREE) {
-		up(&dvbdmx->mutex);
+		mutex_unlock(&dvbdmx->mutex);
 		return -EINVAL;
 	}
 #ifndef NOBUFS
@@ -1033,7 +1033,7 @@
 
 	dvbdmxfeed->pid = 0xffff;
 
-	up(&dvbdmx->mutex);
+	mutex_unlock(&dvbdmx->mutex);
 	return 0;
 }
 
@@ -1071,10 +1071,10 @@
 	if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
 		return -EINVAL;
 
-	if (down_interruptible(&dvbdemux->mutex))
+	if (mutex_lock_interruptible(&dvbdemux->mutex))
 		return -ERESTARTSYS;
 	dvb_dmx_swfilter(dvbdemux, buf, count);
-	up(&dvbdemux->mutex);
+	mutex_unlock(&dvbdemux->mutex);
 
 	if (signal_pending(current))
 		return -EINTR;
@@ -1126,11 +1126,11 @@
 	if (demux->frontend)
 		return -EINVAL;
 
-	if (down_interruptible(&dvbdemux->mutex))
+	if (mutex_lock_interruptible(&dvbdemux->mutex))
 		return -ERESTARTSYS;
 
 	demux->frontend = frontend;
-	up(&dvbdemux->mutex);
+	mutex_unlock(&dvbdemux->mutex);
 	return 0;
 }
 
@@ -1138,11 +1138,11 @@
 {
 	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
 
-	if (down_interruptible(&dvbdemux->mutex))
+	if (mutex_lock_interruptible(&dvbdemux->mutex))
 		return -ERESTARTSYS;
 
 	demux->frontend = NULL;
-	up(&dvbdemux->mutex);
+	mutex_unlock(&dvbdemux->mutex);
 	return 0;
 }
 
@@ -1215,7 +1215,7 @@
 	dmx->disconnect_frontend = dvbdmx_disconnect_frontend;
 	dmx->get_pes_pids = dvbdmx_get_pes_pids;
 
-	sema_init(&dvbdemux->mutex, 1);
+	mutex_init(&dvbdemux->mutex);
 	spin_lock_init(&dvbdemux->lock);
 
 	return 0;
diff -urN oldtree/drivers/media/dvb/dvb-core/dvb_demux.h newtree/drivers/media/dvb/dvb-core/dvb_demux.h
--- oldtree/drivers/media/dvb/dvb-core/dvb_demux.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/media/dvb/dvb-core/dvb_demux.h	2006-02-21 15:58:13.435104112 +0000
@@ -26,7 +26,7 @@
 #include <linux/time.h>
 #include <linux/timer.h>
 #include <linux/spinlock.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include "demux.h"
 
@@ -125,7 +125,7 @@
 	u8 tsbuf[204];
 	int tsbufp;
 
-	struct semaphore mutex;
+	struct mutex mutex;
 	spinlock_t lock;
 };
 
diff -urN oldtree/drivers/media/dvb/dvb-core/dvb_frontend.c newtree/drivers/media/dvb/dvb-core/dvb_frontend.c
--- oldtree/drivers/media/dvb/dvb-core/dvb_frontend.c	2006-02-19 11:41:02.569952408 +0000
+++ newtree/drivers/media/dvb/dvb-core/dvb_frontend.c	2006-02-21 15:58:13.436103960 +0000
@@ -37,7 +37,7 @@
 #include <linux/suspend.h>
 #include <linux/jiffies.h>
 #include <asm/processor.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include "dvb_frontend.h"
 #include "dvbdev.h"
@@ -88,7 +88,7 @@
  * FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
  */
 
-static DECLARE_MUTEX(frontend_mutex);
+static DEFINE_MUTEX(frontend_mutex);
 
 struct dvb_frontend_private {
 
@@ -1021,12 +1021,12 @@
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	if (down_interruptible (&frontend_mutex))
+	if (mutex_lock_interruptible(&frontend_mutex))
 		return -ERESTARTSYS;
 
 	fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL);
 	if (fe->frontend_priv == NULL) {
-		up(&frontend_mutex);
+		mutex_unlock(&frontend_mutex);
 		return -ENOMEM;
 	}
 	fepriv = fe->frontend_priv;
@@ -1045,7 +1045,7 @@
 	dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
 			     fe, DVB_DEVICE_FRONTEND);
 
-	up (&frontend_mutex);
+	mutex_unlock(&frontend_mutex);
 	return 0;
 }
 EXPORT_SYMBOL(dvb_register_frontend);
@@ -1055,7 +1055,7 @@
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 	dprintk ("%s\n", __FUNCTION__);
 
-	down (&frontend_mutex);
+	mutex_lock(&frontend_mutex);
 	dvb_unregister_device (fepriv->dvbdev);
 	dvb_frontend_stop (fe);
 	if (fe->ops->release)
@@ -1064,7 +1064,7 @@
 		printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops->info.name);
 	/* fe is invalid now */
 	kfree(fepriv);
-	up (&frontend_mutex);
+	mutex_unlock(&frontend_mutex);
 	return 0;
 }
 EXPORT_SYMBOL(dvb_unregister_frontend);
diff -urN oldtree/drivers/media/dvb/dvb-core/dvb_net.c newtree/drivers/media/dvb/dvb-core/dvb_net.c
--- oldtree/drivers/media/dvb/dvb-core/dvb_net.c	2006-02-19 11:41:02.571952104 +0000
+++ newtree/drivers/media/dvb/dvb-core/dvb_net.c	2006-02-21 15:58:13.437103808 +0000
@@ -62,6 +62,8 @@
 #include <linux/uio.h>
 #include <asm/uaccess.h>
 #include <linux/crc32.h>
+#include <linux/mutex.h>
+
 
 #include "dvb_demux.h"
 #include "dvb_net.h"
@@ -152,7 +154,7 @@
 	int ule_sndu_remain;			/* Nr. of bytes still required for current ULE SNDU. */
 	unsigned long ts_count;			/* Current ts cell counter. */
 
-	struct semaphore mutex;
+	struct mutex mutex;
 };
 
 
@@ -889,7 +891,7 @@
 	unsigned char *mac = (unsigned char *) dev->dev_addr;
 
 	dprintk("%s: rx_mode %i\n", __FUNCTION__, priv->rx_mode);
-	down(&priv->mutex);
+	mutex_lock(&priv->mutex);
 	if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0])
 		printk("%s: BUG %d\n", __FUNCTION__, __LINE__);
 
@@ -974,7 +976,7 @@
 		ret = -EINVAL;
 
 error:
-	up(&priv->mutex);
+	mutex_unlock(&priv->mutex);
 	return ret;
 }
 
@@ -984,7 +986,7 @@
 	int i, ret = 0;
 
 	dprintk("%s\n", __FUNCTION__);
-	down(&priv->mutex);
+	mutex_lock(&priv->mutex);
 	if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
 		if (priv->secfeed) {
 			if (priv->secfeed->is_filtering) {
@@ -1026,7 +1028,7 @@
 			printk("%s: no ts feed to stop\n", dev->name);
 	} else
 		ret = -EINVAL;
-	up(&priv->mutex);
+	mutex_unlock(&priv->mutex);
 	return ret;
 }
 
@@ -1208,7 +1210,7 @@
 
 	INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list, net);
 	INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed, net);
-	init_MUTEX(&priv->mutex);
+	mutex_init(&priv->mutex);
 
 	net->base_addr = pid;
 
diff -urN oldtree/drivers/media/dvb/dvb-usb/cxusb.c newtree/drivers/media/dvb/dvb-usb/cxusb.c
--- oldtree/drivers/media/dvb/dvb-usb/cxusb.c	2006-02-19 11:41:02.574951648 +0000
+++ newtree/drivers/media/dvb/dvb-usb/cxusb.c	2006-02-21 15:58:13.438103656 +0000
@@ -77,7 +77,7 @@
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	int i;
 
-	if (down_interruptible(&d->i2c_sem) < 0)
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 		return -EAGAIN;
 
 	if (num > 2)
@@ -126,7 +126,7 @@
 		}
 	}
 
-	up(&d->i2c_sem);
+	mutex_unlock(&d->i2c_mutex);
 	return i;
 }
 
diff -urN oldtree/drivers/media/dvb/dvb-usb/dibusb-common.c newtree/drivers/media/dvb/dvb-usb/dibusb-common.c
--- oldtree/drivers/media/dvb/dvb-usb/dibusb-common.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/media/dvb/dvb-usb/dibusb-common.c	2006-02-21 15:58:13.439103504 +0000
@@ -128,7 +128,7 @@
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	int i;
 
-	if (down_interruptible(&d->i2c_sem) < 0)
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 		return -EAGAIN;
 
 	if (num > 2)
@@ -146,7 +146,7 @@
 				break;
 	}
 
-	up(&d->i2c_sem);
+	mutex_unlock(&d->i2c_mutex);
 	return i;
 }
 
diff -urN oldtree/drivers/media/dvb/dvb-usb/digitv.c newtree/drivers/media/dvb/dvb-usb/digitv.c
--- oldtree/drivers/media/dvb/dvb-usb/digitv.c	2006-02-19 11:41:02.576951344 +0000
+++ newtree/drivers/media/dvb/dvb-usb/digitv.c	2006-02-21 15:58:13.440103352 +0000
@@ -48,7 +48,7 @@
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	int i;
 
-	if (down_interruptible(&d->i2c_sem) < 0)
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 		return -EAGAIN;
 
 	if (num > 2)
@@ -67,7 +67,7 @@
 				break;
 	}
 
-	up(&d->i2c_sem);
+	mutex_unlock(&d->i2c_mutex);
 	return i;
 }
 
diff -urN oldtree/drivers/media/dvb/dvb-usb/dvb-usb-init.c newtree/drivers/media/dvb/dvb-usb/dvb-usb-init.c
--- oldtree/drivers/media/dvb/dvb-usb/dvb-usb-init.c	2006-02-19 11:41:02.580950736 +0000
+++ newtree/drivers/media/dvb/dvb-usb/dvb-usb-init.c	2006-02-21 15:58:13.441103200 +0000
@@ -42,8 +42,8 @@
 {
 	int ret = 0;
 
-	sema_init(&d->usb_sem, 1);
-	sema_init(&d->i2c_sem, 1);
+	mutex_init(&d->usb_mutex);
+	mutex_init(&d->i2c_mutex);
 
 	d->state = DVB_USB_STATE_INIT;
 
diff -urN oldtree/drivers/media/dvb/dvb-usb/dvb-usb-urb.c newtree/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
--- oldtree/drivers/media/dvb/dvb-usb/dvb-usb-urb.c	2006-02-19 11:41:02.580950736 +0000
+++ newtree/drivers/media/dvb/dvb-usb/dvb-usb-urb.c	2006-02-21 15:58:13.442103048 +0000
@@ -21,7 +21,7 @@
 	if (wbuf == NULL || wlen == 0)
 		return -EINVAL;
 
-	if ((ret = down_interruptible(&d->usb_sem)))
+	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
 		return ret;
 
 	deb_xfer(">>> ");
@@ -53,7 +53,7 @@
 		}
 	}
 
-	up(&d->usb_sem);
+	mutex_unlock(&d->usb_mutex);
 	return ret;
 }
 EXPORT_SYMBOL(dvb_usb_generic_rw);
diff -urN oldtree/drivers/media/dvb/dvb-usb/dvb-usb.h newtree/drivers/media/dvb/dvb-usb/dvb-usb.h
--- oldtree/drivers/media/dvb/dvb-usb/dvb-usb.h	2006-02-19 11:41:02.581950584 +0000
+++ newtree/drivers/media/dvb/dvb-usb/dvb-usb.h	2006-02-21 15:58:13.441103200 +0000
@@ -12,6 +12,7 @@
 #include <linux/input.h>
 #include <linux/usb.h>
 #include <linux/firmware.h>
+#include <linux/mutex.h>
 
 #include "dvb_frontend.h"
 #include "dvb_demux.h"
@@ -227,8 +228,8 @@
  * @feedcount: number of reqested feeds (used for streaming-activation)
  * @pid_filtering: is hardware pid_filtering used or not.
  *
- * @usb_sem: semaphore of USB control messages (reading needs two messages)
- * @i2c_sem: semaphore for i2c-transfers
+ * @usb_mutex: semaphore of USB control messages (reading needs two messages)
+ * @i2c_mutex: semaphore for i2c-transfers
  *
  * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
  * @pll_addr: I2C address of the tuner for programming
@@ -283,10 +284,10 @@
 	int pid_filtering;
 
 	/* locking */
-	struct semaphore usb_sem;
+	struct mutex usb_mutex;
 
 	/* i2c */
-	struct semaphore i2c_sem;
+	struct mutex i2c_mutex;
 	struct i2c_adapter i2c_adap;
 
 	/* tuner programming information */
diff -urN oldtree/drivers/media/dvb/dvb-usb/vp702x.c newtree/drivers/media/dvb/dvb-usb/vp702x.c
--- oldtree/drivers/media/dvb/dvb-usb/vp702x.c	2006-02-19 11:41:02.621944504 +0000
+++ newtree/drivers/media/dvb/dvb-usb/vp702x.c	2006-02-21 15:58:13.442103048 +0000
@@ -75,7 +75,7 @@
 {
 	int ret;
 
-	if ((ret = down_interruptible(&d->usb_sem)))
+	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
 		return ret;
 
 	if ((ret = vp702x_usb_out_op(d,REQUEST_OUT,0,0,o,olen)) < 0)
@@ -84,7 +84,7 @@
 	ret = vp702x_usb_in_op(d,REQUEST_IN,0,0,i,ilen);
 
 unlock:
-	up(&d->usb_sem);
+	mutex_unlock(&d->usb_mutex);
 
 	return ret;
 }
diff -urN oldtree/drivers/media/dvb/dvb-usb/vp7045.c newtree/drivers/media/dvb/dvb-usb/vp7045.c
--- oldtree/drivers/media/dvb/dvb-usb/vp7045.c	2006-02-19 11:41:02.622944352 +0000
+++ newtree/drivers/media/dvb/dvb-usb/vp7045.c	2006-02-21 15:58:13.443102896 +0000
@@ -38,7 +38,7 @@
 	deb_xfer("out buffer: ");
 	debug_dump(outbuf,outlen+1,deb_xfer);
 
-	if ((ret = down_interruptible(&d->usb_sem)))
+	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
 		return ret;
 
 	if (usb_control_msg(d->udev,
@@ -68,7 +68,7 @@
 		memcpy(in,&inbuf[1],inlen);
 
 unlock:
-	up(&d->usb_sem);
+	mutex_unlock(&d->usb_mutex);
 
 	return ret;
 }
diff -urN oldtree/drivers/media/dvb/frontends/Kconfig newtree/drivers/media/dvb/frontends/Kconfig
--- oldtree/drivers/media/dvb/frontends/Kconfig	2006-02-19 11:41:02.623944200 +0000
+++ newtree/drivers/media/dvb/frontends/Kconfig	2006-02-21 15:58:36.284630456 +0000
@@ -75,7 +75,7 @@
 
 config DVB_CX22700
 	tristate "Conexant CX22700 based"
-	depends on DVB_CORE
+	depends on DVB_CORE && (BROKEN || !ARM)  # ICE on arm
 	help
 	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
diff -urN oldtree/drivers/media/dvb/frontends/bcm3510.c newtree/drivers/media/dvb/frontends/bcm3510.c
--- oldtree/drivers/media/dvb/frontends/bcm3510.c	2006-02-19 11:41:02.625943896 +0000
+++ newtree/drivers/media/dvb/frontends/bcm3510.c	2006-02-21 15:58:13.444102744 +0000
@@ -39,6 +39,8 @@
 #include <linux/jiffies.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 
 #include "dvb_frontend.h"
 #include "bcm3510.h"
@@ -52,7 +54,7 @@
 	struct dvb_frontend frontend;
 
 	/* demodulator private data */
-	struct semaphore hab_sem;
+	struct mutex hab_mutex;
 	u8 firmware_loaded:1;
 
 	unsigned long next_status_check;
@@ -213,7 +215,7 @@
 	dbufout(ob,olen+2,deb_hab);
 	deb_hab("\n");
 
-	if (down_interruptible(&st->hab_sem) < 0)
+	if (mutex_lock_interruptible(&st->hab_mutex) < 0)
 		return -EAGAIN;
 
 	if ((ret = bcm3510_hab_send_request(st, ob, olen+2)) < 0 ||
@@ -226,7 +228,7 @@
 
 	memcpy(ibuf,&ib[2],ilen);
 error:
-	up(&st->hab_sem);
+	mutex_unlock(&st->hab_mutex);
 	return ret;
 }
 
@@ -796,7 +798,7 @@
 	state->frontend.ops = &state->ops;
 	state->frontend.demodulator_priv = state;
 
-	sema_init(&state->hab_sem, 1);
+	mutex_init(&state->hab_mutex);
 
 	if ((ret = bcm3510_readB(state,0xe0,&v)) < 0)
 		goto error;
diff -urN oldtree/drivers/media/dvb/ttpci/Kconfig newtree/drivers/media/dvb/ttpci/Kconfig
--- oldtree/drivers/media/dvb/ttpci/Kconfig	2006-02-19 11:41:02.644941008 +0000
+++ newtree/drivers/media/dvb/ttpci/Kconfig	2006-02-21 15:58:36.294628936 +0000
@@ -1,6 +1,6 @@
 config DVB_AV7110
 	tristate "AV7110 cards"
-	depends on DVB_CORE && PCI
+	depends on DVB_CORE && PCI && (BROKEN || !ARM) # ICE on arm
 	select FW_LOADER
 	select VIDEO_DEV
 	select VIDEO_SAA7146_VV
@@ -119,7 +119,7 @@
 
 config DVB_BUDGET_PATCH
 	tristate "AV7110 cards with Budget Patch"
-	depends on DVB_CORE && DVB_BUDGET
+	depends on DVB_CORE && DVB_BUDGET && (BROKEN || !ARM) # ICE
 	select DVB_AV7110
 	select DVB_STV0299
 	select DVB_VES1X93
diff -urN oldtree/drivers/media/dvb/ttpci/av7110.c newtree/drivers/media/dvb/ttpci/av7110.c
--- oldtree/drivers/media/dvb/ttpci/av7110.c	2006-02-19 11:41:02.646940704 +0000
+++ newtree/drivers/media/dvb/ttpci/av7110.c	2006-02-21 15:58:13.452101528 +0000
@@ -54,7 +54,7 @@
 #include <linux/i2c.h>
 
 #include <asm/system.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include <linux/dvb/frontend.h>
 
@@ -242,10 +242,10 @@
 		if (!av7110->arm_ready)
 			continue;
 
-		if (down_interruptible(&av7110->dcomlock))
+		if (mutex_lock_interruptible(&av7110->dcomlock))
 			break;
 		newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
-		up(&av7110->dcomlock);
+		mutex_unlock(&av7110->dcomlock);
 
 		if (newloops == av7110->arm_loops || av7110->arm_errors > 3) {
 			printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n",
@@ -253,10 +253,10 @@
 
 			recover_arm(av7110);
 
-			if (down_interruptible(&av7110->dcomlock))
+			if (mutex_lock_interruptible(&av7110->dcomlock))
 				break;
 			newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1;
-			up(&av7110->dcomlock);
+			mutex_unlock(&av7110->dcomlock);
 		}
 		av7110->arm_loops = newloops;
 		av7110->arm_errors = 0;
@@ -741,7 +741,7 @@
 	int ret = 0;
 	dprintk(4, "%p\n", av7110);
 
-	if (down_interruptible(&av7110->pid_mutex))
+	if (mutex_lock_interruptible(&av7110->pid_mutex))
 		return -ERESTARTSYS;
 
 	if (!(vpid & 0x8000))
@@ -760,7 +760,7 @@
 		ret = SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid);
 	}
 
-	up(&av7110->pid_mutex);
+	mutex_unlock(&av7110->pid_mutex);
 	return ret;
 }
 
@@ -2096,7 +2096,7 @@
 	if (av7110->playing)
 		return 0;
 
-	if (down_interruptible(&av7110->pid_mutex))
+	if (mutex_lock_interruptible(&av7110->pid_mutex))
 		return -ERESTARTSYS;
 
 	if (synced) {
@@ -2118,7 +2118,7 @@
 	if (!ret)
 		av7110->fe_synced = synced;
 
-	up(&av7110->pid_mutex);
+	mutex_unlock(&av7110->pid_mutex);
 	return ret;
 }
 
@@ -2713,16 +2713,16 @@
 	tasklet_init (&av7110->debi_tasklet, debiirq, (unsigned long) av7110);
 	tasklet_init (&av7110->gpio_tasklet, gpioirq, (unsigned long) av7110);
 
-	sema_init(&av7110->pid_mutex, 1);
+	mutex_init(&av7110->pid_mutex);
 
 	/* locks for data transfers from/to AV7110 */
 	spin_lock_init(&av7110->debilock);
-	sema_init(&av7110->dcomlock, 1);
+	mutex_init(&av7110->dcomlock);
 	av7110->debitype = -1;
 
 	/* default OSD window */
 	av7110->osdwin = 1;
-	sema_init(&av7110->osd_sema, 1);
+	mutex_init(&av7110->osd_mutex);
 
 	/* ARM "watchdog" */
 	init_waitqueue_head(&av7110->arm_wait);
diff -urN oldtree/drivers/media/dvb/ttpci/av7110.h newtree/drivers/media/dvb/ttpci/av7110.h
--- oldtree/drivers/media/dvb/ttpci/av7110.h	2006-02-19 11:41:02.647940552 +0000
+++ newtree/drivers/media/dvb/ttpci/av7110.h	2006-02-21 15:58:13.452101528 +0000
@@ -16,6 +16,7 @@
 #include <linux/dvb/ca.h>
 #include <linux/dvb/osd.h>
 #include <linux/dvb/net.h>
+#include <linux/mutex.h>
 
 #include "dvbdev.h"
 #include "demux.h"
@@ -127,7 +128,7 @@
 	/* DEBI and polled command interface */
 
 	spinlock_t		debilock;
-	struct semaphore	dcomlock;
+	struct mutex		dcomlock;
 	volatile int		debitype;
 	volatile int		debilen;
 
@@ -146,7 +147,7 @@
 
 	int			osdwin;      /* currently active window */
 	u16			osdbpp[8];
-	struct semaphore	osd_sema;
+	struct mutex		osd_mutex;
 
 	/* CA */
 
@@ -172,7 +173,7 @@
 	struct tasklet_struct   vpe_tasklet;
 
 	int			fe_synced;
-	struct semaphore	pid_mutex;
+	struct mutex		pid_mutex;
 
 	int			video_blank;
 	struct video_status	videostate;
diff -urN oldtree/drivers/media/dvb/ttpci/av7110_hw.c newtree/drivers/media/dvb/ttpci/av7110_hw.c
--- oldtree/drivers/media/dvb/ttpci/av7110_hw.c	2006-02-19 11:41:02.648940400 +0000
+++ newtree/drivers/media/dvb/ttpci/av7110_hw.c	2006-02-21 15:58:13.463099856 +0000
@@ -324,10 +324,10 @@
 	start = jiffies;
 	for (;;) {
 		err = time_after(jiffies, start + ARM_WAIT_FREE);
-		if (down_interruptible(&av7110->dcomlock))
+		if (mutex_lock_interruptible(&av7110->dcomlock))
 			return -ERESTARTSYS;
 		stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
-		up(&av7110->dcomlock);
+		mutex_unlock(&av7110->dcomlock);
 		if ((stat & flags) == 0)
 			break;
 		if (err) {
@@ -484,11 +484,11 @@
 		dprintk(1, "arm not ready.\n");
 		return -1;
 	}
-	if (down_interruptible(&av7110->dcomlock))
+	if (mutex_lock_interruptible(&av7110->dcomlock))
 		return -ERESTARTSYS;
 
 	ret = __av7110_send_fw_cmd(av7110, buf, length);
-	up(&av7110->dcomlock);
+	mutex_unlock(&av7110->dcomlock);
 	if (ret && ret!=-ERESTARTSYS)
 		printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
 		       __FUNCTION__, ret);
@@ -560,11 +560,11 @@
 		return -1;
 	}
 
-	if (down_interruptible(&av7110->dcomlock))
+	if (mutex_lock_interruptible(&av7110->dcomlock))
 		return -ERESTARTSYS;
 
 	if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
-		up(&av7110->dcomlock);
+		mutex_unlock(&av7110->dcomlock);
 		printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
 		return err;
 	}
@@ -576,7 +576,7 @@
 			break;
 		if (err) {
 			printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
-			up(&av7110->dcomlock);
+			mutex_unlock(&av7110->dcomlock);
 			return -ETIMEDOUT;
 		}
 #ifdef _NOHANDSHAKE
@@ -592,7 +592,7 @@
 			break;
 		if (err) {
 			printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
-			up(&av7110->dcomlock);
+			mutex_unlock(&av7110->dcomlock);
 			return -ETIMEDOUT;
 		}
 		msleep(1);
@@ -603,12 +603,12 @@
 	stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
 	if (stat & GPMQOver) {
 		printk(KERN_ERR "%s: GPMQOver\n", __FUNCTION__);
-		up(&av7110->dcomlock);
+		mutex_unlock(&av7110->dcomlock);
 		return -1;
 	}
 	else if (stat & OSDQOver) {
 		printk(KERN_ERR "%s: OSDQOver\n", __FUNCTION__);
-		up(&av7110->dcomlock);
+		mutex_unlock(&av7110->dcomlock);
 		return -1;
 	}
 #endif
@@ -616,7 +616,7 @@
 	for (i = 0; i < reply_buf_len; i++)
 		reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
 
-	up(&av7110->dcomlock);
+	mutex_unlock(&av7110->dcomlock);
 	return 0;
 }
 
@@ -732,7 +732,7 @@
 	unsigned long start;
 	int err;
 
-	if (down_interruptible(&av7110->dcomlock))
+	if (mutex_lock_interruptible(&av7110->dcomlock))
 		return -ERESTARTSYS;
 	start = jiffies;
 	while (1) {
@@ -742,12 +742,12 @@
 		if (err) {
 			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
 			       __FUNCTION__);
-			up(&av7110->dcomlock);
+			mutex_unlock(&av7110->dcomlock);
 			return -ETIMEDOUT;
 		}
 		msleep(1);
 	}
-	up(&av7110->dcomlock);
+	mutex_unlock(&av7110->dcomlock);
 	return 0;
 }
 
@@ -758,7 +758,7 @@
 	int length = strlen(buf) + 1;
 	u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y };
 
-	if (down_interruptible(&av7110->dcomlock))
+	if (mutex_lock_interruptible(&av7110->dcomlock))
 		return -ERESTARTSYS;
 
 	start = jiffies;
@@ -769,7 +769,7 @@
 		if (ret) {
 			printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
 			       __FUNCTION__);
-			up(&av7110->dcomlock);
+			mutex_unlock(&av7110->dcomlock);
 			return -ETIMEDOUT;
 		}
 		msleep(1);
@@ -783,7 +783,7 @@
 		if (ret) {
 			printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
 			       __FUNCTION__);
-			up(&av7110->dcomlock);
+			mutex_unlock(&av7110->dcomlock);
 			return -ETIMEDOUT;
 		}
 		msleep(1);
@@ -795,7 +795,7 @@
 	if (length & 1)
 		wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
 	ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
-	up(&av7110->dcomlock);
+	mutex_unlock(&av7110->dcomlock);
 	if (ret && ret!=-ERESTARTSYS)
 		printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
 	return ret;
@@ -1059,7 +1059,7 @@
 {
 	int ret;
 
-	if (down_interruptible(&av7110->osd_sema))
+	if (mutex_lock_interruptible(&av7110->osd_mutex))
 		return -ERESTARTSYS;
 
 	switch (dc->cmd) {
@@ -1195,7 +1195,7 @@
 		break;
 	}
 
-	up(&av7110->osd_sema);
+	mutex_unlock(&av7110->osd_mutex);
 	if (ret==-ERESTARTSYS)
 		dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd);
 	else if (ret)
diff -urN oldtree/drivers/media/dvb/ttpci/budget.h newtree/drivers/media/dvb/ttpci/budget.h
--- oldtree/drivers/media/dvb/ttpci/budget.h	2006-02-19 11:41:02.653939640 +0000
+++ newtree/drivers/media/dvb/ttpci/budget.h	2006-02-21 15:58:13.465099552 +0000
@@ -10,6 +10,8 @@
 #include "dvb_net.h"
 
 #include <linux/module.h>
+#include <linux/mutex.h>
+
 #include <media/saa7146.h>
 
 extern int budget_debug;
@@ -51,7 +53,7 @@
 	struct dmx_frontend mem_frontend;
 
 	int fe_synced;
-	struct semaphore pid_mutex;
+	struct mutex pid_mutex;
 
 	int ci_present;
 	int video_port;
diff -urN oldtree/drivers/media/dvb/ttusb-budget/Kconfig newtree/drivers/media/dvb/ttusb-budget/Kconfig
--- oldtree/drivers/media/dvb/ttusb-budget/Kconfig	2006-02-19 11:41:02.654939488 +0000
+++ newtree/drivers/media/dvb/ttusb-budget/Kconfig	2006-02-21 15:58:36.294628936 +0000
@@ -1,6 +1,6 @@
 config DVB_TTUSB_BUDGET
 	tristate "Technotrend/Hauppauge Nova-USB devices"
-	depends on DVB_CORE && USB
+	depends on DVB_CORE && USB && (BROKEN || !ARM)  # ICE on arm
 	select DVB_CX22700
 	select DVB_TDA1004X
 	select DVB_VES1820
diff -urN oldtree/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c newtree/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
--- oldtree/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c	2006-02-19 11:41:02.655939336 +0000
+++ newtree/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c	2006-02-21 15:58:13.467099248 +0000
@@ -19,7 +19,7 @@
 #include <linux/time.h>
 #include <linux/errno.h>
 #include <linux/jiffies.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include "dvb_frontend.h"
 #include "dmxdev.h"
@@ -35,7 +35,6 @@
 #include <linux/dvb/dmx.h>
 #include <linux/pci.h>
 
-
 /*
   TTUSB_HWSECTIONS:
     the DSP supports filtering in hardware, however, since the "muxstream"
@@ -83,8 +82,8 @@
 	struct dvb_net dvbnet;
 
 	/* and one for USB access. */
-	struct semaphore semi2c;
-	struct semaphore semusb;
+	struct mutex semi2c;
+	struct mutex semusb;
 
 	struct dvb_adapter adapter;
 	struct usb_device *dev;
@@ -150,7 +149,7 @@
 	printk("\n");
 #endif
 
-	if (down_interruptible(&ttusb->semusb) < 0)
+	if (mutex_lock_interruptible(&ttusb->semusb) < 0)
 		return -EAGAIN;
 
 	err = usb_bulk_msg(ttusb->dev, ttusb->bulk_out_pipe,
@@ -158,13 +157,13 @@
 	if (err != 0) {
 		dprintk("%s: usb_bulk_msg(send) failed, err == %i!\n",
 			__FUNCTION__, err);
-		up(&ttusb->semusb);
+		mutex_unlock(&ttusb->semusb);
 		return err;
 	}
 	if (actual_len != len) {
 		dprintk("%s: only wrote %d of %d bytes\n", __FUNCTION__,
 			actual_len, len);
-		up(&ttusb->semusb);
+		mutex_unlock(&ttusb->semusb);
 		return -1;
 	}
 
@@ -174,7 +173,7 @@
 	if (err != 0) {
 		printk("%s: failed, receive error %d\n", __FUNCTION__,
 		       err);
-		up(&ttusb->semusb);
+		mutex_unlock(&ttusb->semusb);
 		return err;
 	}
 #if DEBUG >= 3
@@ -185,14 +184,14 @@
 	printk("\n");
 #endif
 	if (!needresult)
-		up(&ttusb->semusb);
+		mutex_unlock(&ttusb->semusb);
 	return 0;
 }
 
 static int ttusb_result(struct ttusb *ttusb, u8 * data, int len)
 {
 	memcpy(data, ttusb->last_result, len);
-	up(&ttusb->semusb);
+	mutex_unlock(&ttusb->semusb);
 	return 0;
 }
 
@@ -250,7 +249,7 @@
 	int i = 0;
 	int inc;
 
-	if (down_interruptible(&ttusb->semi2c) < 0)
+	if (mutex_lock_interruptible(&ttusb->semi2c) < 0)
 		return -EAGAIN;
 
 	while (i < num) {
@@ -284,7 +283,7 @@
 		i += inc;
 	}
 
-	up(&ttusb->semi2c);
+	mutex_unlock(&ttusb->semi2c);
 	return i;
 }
 
@@ -1495,8 +1494,11 @@
 	ttusb->dev = udev;
 	ttusb->c = 0;
 	ttusb->mux_state = 0;
-	sema_init(&ttusb->semi2c, 0);
-	sema_init(&ttusb->semusb, 1);
+	mutex_init(&ttusb->semi2c);
+
+	mutex_lock(&ttusb->semi2c);
+
+	mutex_init(&ttusb->semusb);
 
 	ttusb_setup_interfaces(ttusb);
 
@@ -1504,7 +1506,7 @@
 	if (ttusb_init_controller(ttusb))
 		printk("ttusb_init_controller: error\n");
 
-	up(&ttusb->semi2c);
+	mutex_unlock(&ttusb->semi2c);
 
 	dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE);
 	ttusb->adapter.priv = ttusb;
diff -urN oldtree/drivers/media/dvb/ttusb-dec/ttusb_dec.c newtree/drivers/media/dvb/ttusb-dec/ttusb_dec.c
--- oldtree/drivers/media/dvb/ttusb-dec/ttusb_dec.c	2006-02-19 11:41:02.656939184 +0000
+++ newtree/drivers/media/dvb/ttusb-dec/ttusb_dec.c	2006-02-21 15:58:13.471098640 +0000
@@ -20,7 +20,8 @@
  *
  */
 
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -115,7 +116,7 @@
 	unsigned int			out_pipe;
 	unsigned int			irq_pipe;
 	enum ttusb_dec_interface	interface;
-	struct semaphore		usb_sem;
+	struct mutex			usb_mutex;
 
 	void			*irq_buffer;
 	struct urb		*irq_urb;
@@ -124,7 +125,7 @@
 	dma_addr_t		iso_dma_handle;
 	struct urb		*iso_urb[ISO_BUF_COUNT];
 	int			iso_stream_count;
-	struct semaphore	iso_sem;
+	struct mutex		iso_mutex;
 
 	u8				packet[MAX_PVA_LENGTH + 4];
 	enum ttusb_dec_packet_type	packet_type;
@@ -273,9 +274,9 @@
 	if (!b)
 		return -ENOMEM;
 
-	if ((result = down_interruptible(&dec->usb_sem))) {
+	if ((result = mutex_lock_interruptible(&dec->usb_mutex))) {
 		kfree(b);
-		printk("%s: Failed to down usb semaphore.\n", __FUNCTION__);
+		printk("%s: Failed to lock usb mutex.\n", __FUNCTION__);
 		return result;
 	}
 
@@ -300,7 +301,7 @@
 	if (result) {
 		printk("%s: command bulk message failed: error %d\n",
 		       __FUNCTION__, result);
-		up(&dec->usb_sem);
+		mutex_unlock(&dec->usb_mutex);
 		kfree(b);
 		return result;
 	}
@@ -311,7 +312,7 @@
 	if (result) {
 		printk("%s: result bulk message failed: error %d\n",
 		       __FUNCTION__, result);
-		up(&dec->usb_sem);
+		mutex_unlock(&dec->usb_mutex);
 		kfree(b);
 		return result;
 	} else {
@@ -327,7 +328,7 @@
 		if (cmd_result && b[3] > 0)
 			memcpy(cmd_result, &b[4], b[3]);
 
-		up(&dec->usb_sem);
+		mutex_unlock(&dec->usb_mutex);
 
 		kfree(b);
 		return 0;
@@ -835,7 +836,7 @@
 
 	dprintk("%s\n", __FUNCTION__);
 
-	if (down_interruptible(&dec->iso_sem))
+	if (mutex_lock_interruptible(&dec->iso_mutex))
 		return;
 
 	dec->iso_stream_count--;
@@ -845,7 +846,7 @@
 			usb_kill_urb(dec->iso_urb[i]);
 	}
 
-	up(&dec->iso_sem);
+	mutex_unlock(&dec->iso_mutex);
 }
 
 /* Setting the interface of the DEC tends to take down the USB communications
@@ -890,7 +891,7 @@
 
 	dprintk("%s\n", __FUNCTION__);
 
-	if (down_interruptible(&dec->iso_sem))
+	if (mutex_lock_interruptible(&dec->iso_mutex))
 		return -EAGAIN;
 
 	if (!dec->iso_stream_count) {
@@ -911,7 +912,7 @@
 					i--;
 				}
 
-				up(&dec->iso_sem);
+				mutex_unlock(&dec->iso_mutex);
 				return result;
 			}
 		}
@@ -919,7 +920,7 @@
 
 	dec->iso_stream_count++;
 
-	up(&dec->iso_sem);
+	mutex_unlock(&dec->iso_mutex);
 
 	return 0;
 }
@@ -1229,8 +1230,8 @@
 {
 	dprintk("%s\n", __FUNCTION__);
 
-	sema_init(&dec->usb_sem, 1);
-	sema_init(&dec->iso_sem, 1);
+	mutex_init(&dec->usb_mutex);
+	mutex_init(&dec->iso_mutex);
 
 	dec->command_pipe = usb_sndbulkpipe(dec->udev, COMMAND_PIPE);
 	dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE);
diff -urN oldtree/drivers/media/radio/miropcm20-rds-core.c newtree/drivers/media/radio/miropcm20-rds-core.c
--- oldtree/drivers/media/radio/miropcm20-rds-core.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/media/radio/miropcm20-rds-core.c	2006-02-21 15:58:13.471098640 +0000
@@ -18,14 +18,15 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
 #include <asm/io.h>
 #include "../../../sound/oss/aci.h"
 #include "miropcm20-rds-core.h"
 
 #define DEBUG 0
 
-static struct semaphore aci_rds_sem;
+static struct mutex aci_rds_mutex;
 
 #define RDS_DATASHIFT          2   /* Bit 2 */
 #define RDS_DATAMASK        (1 << RDS_DATASHIFT)
@@ -181,7 +182,7 @@
 {
 	int ret;
 
-	if (down_interruptible(&aci_rds_sem))
+	if (mutex_lock_interruptible(&aci_rds_mutex))
 		return -EINTR;
 
 	rds_write(cmd);
@@ -192,7 +193,7 @@
 	else
 		ret = 0;
 
-	up(&aci_rds_sem);
+	mutex_unlock(&aci_rds_mutex);
 	
 	return ret;
 }
@@ -200,7 +201,7 @@
 
 int __init attach_aci_rds(void)
 {
-	init_MUTEX(&aci_rds_sem);
+	mutex_init(&aci_rds_mutex);
 	return 0;
 }
 
diff -urN oldtree/drivers/media/radio/radio-aimslab.c newtree/drivers/media/radio/radio-aimslab.c
--- oldtree/drivers/media/radio/radio-aimslab.c	2006-02-19 11:41:02.658938880 +0000
+++ newtree/drivers/media/radio/radio-aimslab.c	2006-02-21 15:58:13.472098488 +0000
@@ -43,7 +43,7 @@
 
 static int io = CONFIG_RADIO_RTRACK_PORT; 
 static int radio_nr = -1;
-static struct semaphore lock;
+static struct mutex lock;
 
 struct rt_device
 {
@@ -83,23 +83,23 @@
 static void rt_mute(struct rt_device *dev)
 {
 	dev->muted = 1;
-	down(&lock);
+	mutex_lock(&lock);
 	outb(0xd0, io);			/* volume steady, off		*/
-	up(&lock);
+	mutex_unlock(&lock);
 }
 
 static int rt_setvol(struct rt_device *dev, int vol)
 {
 	int i;
 
-	down(&lock);
+	mutex_lock(&lock);
 	
 	if(vol == dev->curvol) {	/* requested volume = current */
 		if (dev->muted) {	/* user is unmuting the card  */
 			dev->muted = 0;
 			outb (0xd8, io);	/* enable card */
 		}	
-		up(&lock);
+		mutex_unlock(&lock);
 		return 0;
 	}
 
@@ -108,7 +108,7 @@
 		sleep_delay(2000000);	/* make sure it's totally down	*/
 		outb(0xd0, io);		/* volume steady, off		*/
 		dev->curvol = 0;	/* track the volume state!	*/
-		up(&lock);
+		mutex_unlock(&lock);
 		return 0;
 	}
 
@@ -121,7 +121,7 @@
 			rt_decvol();
 
 	dev->curvol = vol;
-	up(&lock);
+	mutex_unlock(&lock);
 	return 0;
 }
 
@@ -168,7 +168,7 @@
 	freq += 171200;			/* Add 10.7 MHz IF 		*/
 	freq /= 800;			/* Convert to 50 kHz units	*/
 	
-	down(&lock);			/* Stop other ops interfering */
+	mutex_lock(&lock);			/* Stop other ops interfering */
 	 
 	send_0_byte (io, dev);		/*  0: LSB of frequency		*/
 
@@ -196,7 +196,7 @@
 	else
 		outb (0xd8, io);	/* volume steady + sigstr + on */
 		
-	up(&lock);
+	mutex_unlock(&lock);
 
 	return 0;
 }
@@ -337,7 +337,7 @@
 
 	/* Set up the I/O locking */
 	
-	init_MUTEX(&lock);
+	mutex_init(&lock);
 	
  	/* mute card - prevents noisy bootups */
 
diff -urN oldtree/drivers/media/radio/radio-aztech.c newtree/drivers/media/radio/radio-aztech.c
--- oldtree/drivers/media/radio/radio-aztech.c	2006-02-19 11:41:02.658938880 +0000
+++ newtree/drivers/media/radio/radio-aztech.c	2006-02-21 15:58:13.473098336 +0000
@@ -42,7 +42,7 @@
 static int io = CONFIG_RADIO_AZTECH_PORT; 
 static int radio_nr = -1;
 static int radio_wait_time = 1000;
-static struct semaphore lock;
+static struct mutex lock;
 
 struct az_device
 {
@@ -87,9 +87,9 @@
 
 static int az_setvol(struct az_device *dev, int vol)
 {
-	down(&lock);
+	mutex_lock(&lock);
 	outb (volconvert(vol), io);
-	up(&lock);
+	mutex_unlock(&lock);
 	return 0;
 }
 
@@ -122,7 +122,7 @@
 	frequency += 171200;		/* Add 10.7 MHz IF		*/
 	frequency /= 800;		/* Convert to 50 kHz units	*/
 					
-	down(&lock);
+	mutex_lock(&lock);
 	
 	send_0_byte (dev);		/*  0: LSB of frequency       */
 
@@ -152,7 +152,7 @@
 	udelay (radio_wait_time);
 	outb_p(128+64+volconvert(dev->curvol), io);
 	
-	up(&lock);
+	mutex_unlock(&lock);
 
 	return 0;
 }
@@ -283,7 +283,7 @@
 		return -EBUSY;
 	}
 
-	init_MUTEX(&lock);
+	mutex_init(&lock);
 	aztech_radio.priv=&aztech_unit;
 	
 	if(video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr)==-1)
diff -urN oldtree/drivers/media/radio/radio-maestro.c newtree/drivers/media/radio/radio-maestro.c
--- oldtree/drivers/media/radio/radio-maestro.c	2006-02-19 11:41:02.661938424 +0000
+++ newtree/drivers/media/radio/radio-maestro.c	2006-02-21 15:58:13.474098184 +0000
@@ -23,10 +23,11 @@
 #include <linux/sched.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <linux/pci.h>
 #include <linux/videodev.h>
 
+
 #define DRIVER_VERSION	"0.05"
 
 #define GPIO_DATA	0x60   /* port offset from ESS_IO_BASE */
@@ -104,7 +105,7 @@
 		muted,	/* VIDEO_AUDIO_MUTE */
 		stereo,	/* VIDEO_TUNER_STEREO_ON */	
 		tuned;	/* signal strength (0 or 0xffff) */
-	struct	semaphore lock;
+	struct mutex lock;
 };
 
 static u32 radio_bits_get(struct radio_device *dev)
@@ -258,9 +259,9 @@
 	struct radio_device *card = video_get_drvdata(dev);
 	int ret;
 
-	down(&card->lock);
+	mutex_lock(&card->lock);
 	ret = video_usercopy(inode, file, cmd, arg, radio_function);
-	up(&card->lock);
+	mutex_unlock(&card->lock);
 
 	return ret;
 }
@@ -311,7 +312,7 @@
 	}
 
 	radio_unit->io = pci_resource_start(pdev, 0) + GPIO_DATA;
-	init_MUTEX(&radio_unit->lock);
+	mutex_init(&radio_unit->lock);
 
 	maestro_radio_inst = video_device_alloc();
 	if (maestro_radio_inst == NULL) {
diff -urN oldtree/drivers/media/radio/radio-maxiradio.c newtree/drivers/media/radio/radio-maxiradio.c
--- oldtree/drivers/media/radio/radio-maxiradio.c	2006-02-19 11:41:02.686934624 +0000
+++ newtree/drivers/media/radio/radio-maxiradio.c	2006-02-21 15:58:13.474098184 +0000
@@ -37,7 +37,8 @@
 #include <linux/sched.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
 #include <linux/pci.h>
 #include <linux/videodev.h>
 
@@ -101,7 +102,7 @@
 		
 	unsigned long freq;
 	
-	struct  semaphore lock;
+	struct mutex lock;
 } radio_unit = {0, 0, 0, 0, };
 
 
@@ -267,9 +268,9 @@
 	struct radio_device *card=dev->priv;
 	int ret;
 	
-	down(&card->lock);
+	mutex_lock(&card->lock);
 	ret = video_usercopy(inode, file, cmd, arg, radio_function);
-	up(&card->lock);
+	mutex_unlock(&card->lock);
 	return ret;
 }
 
@@ -290,7 +291,7 @@
 	        goto err_out_free_region;
 
 	radio_unit.io = pci_resource_start(pdev, 0);
-	init_MUTEX(&radio_unit.lock);
+	mutex_init(&radio_unit.lock);
 	maxiradio_radio.priv = &radio_unit;
 
 	if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
diff -urN oldtree/drivers/media/radio/radio-sf16fmi.c newtree/drivers/media/radio/radio-sf16fmi.c
--- oldtree/drivers/media/radio/radio-sf16fmi.c	2006-02-19 11:41:02.687934472 +0000
+++ newtree/drivers/media/radio/radio-sf16fmi.c	2006-02-21 15:58:13.475098032 +0000
@@ -24,7 +24,7 @@
 #include <linux/isapnp.h>
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 struct fmi_device
 {
@@ -37,7 +37,7 @@
 static int io = -1; 
 static int radio_nr = -1;
 static struct pnp_dev *dev = NULL;
-static struct semaphore lock;
+static struct mutex lock;
 
 /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
 /* It is only useful to give freq in intervall of 800 (=0.05Mhz),
@@ -68,16 +68,16 @@
 
 static inline void fmi_mute(int port)
 {
-	down(&lock);
+	mutex_lock(&lock);
 	outb(0x00, port);
-	up(&lock);
+	mutex_unlock(&lock);
 }
 
 static inline void fmi_unmute(int port)
 {
-	down(&lock);
+	mutex_lock(&lock);
 	outb(0x08, port);
-	up(&lock);
+	mutex_unlock(&lock);
 }
 
 static inline int fmi_setfreq(struct fmi_device *dev)
@@ -85,12 +85,12 @@
 	int myport = dev->port;
 	unsigned long freq = dev->curfreq;
 
-	down(&lock);
+	mutex_lock(&lock);
 
 	outbits(16, RSF16_ENCODE(freq), myport);
 	outbits(8, 0xC0, myport);
 	msleep(143);		/* was schedule_timeout(HZ/7) */
-	up(&lock);
+	mutex_unlock(&lock);
 	if (dev->curvol) fmi_unmute(myport);
 	return 0;
 }
@@ -102,7 +102,7 @@
 	int myport = dev->port;
 
 	
-	down(&lock);
+	mutex_lock(&lock);
 	val = dev->curvol ? 0x08 : 0x00;	/* unmute/mute */
 	outb(val, myport);
 	outb(val | 0x10, myport);
@@ -110,7 +110,7 @@
 	res = (int)inb(myport+1);
 	outb(val, myport);
 	
-	up(&lock);
+	mutex_unlock(&lock);
 	return (res & 2) ? 0 : 0xFFFF;
 }
 
@@ -296,7 +296,7 @@
 	fmi_unit.flags = VIDEO_TUNER_LOW;
 	fmi_radio.priv = &fmi_unit;
 	
-	init_MUTEX(&lock);
+	mutex_init(&lock);
 	
 	if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) == -1) {
 		release_region(io, 2);
diff -urN oldtree/drivers/media/radio/radio-sf16fmr2.c newtree/drivers/media/radio/radio-sf16fmr2.c
--- oldtree/drivers/media/radio/radio-sf16fmr2.c	2006-02-19 11:41:02.687934472 +0000
+++ newtree/drivers/media/radio/radio-sf16fmr2.c	2006-02-21 15:58:13.475098032 +0000
@@ -19,9 +19,9 @@
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
 #include <linux/videodev.h>	/* kernel radio structs		*/
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
-static struct semaphore lock;
+static struct mutex lock;
 
 #undef DEBUG
 //#define DEBUG 1
@@ -238,9 +238,9 @@
 			if (fmr2->mute)
 				v->flags |= VIDEO_AUDIO_MUTE;
 			v->mode=VIDEO_MODE_AUTO;
-			down(&lock);
+			mutex_lock(&lock);
 			v->signal = fmr2_getsigstr(fmr2);
-			up(&lock);
+			mutex_unlock(&lock);
 			return 0;
 		}
 		case VIDIOCSTUNER:
@@ -274,9 +274,9 @@
 			/* set card freq (if not muted) */
 			if (fmr2->curvol && !fmr2->mute)
 			{
-				down(&lock);
+				mutex_lock(&lock);
 				fmr2_setfreq(fmr2);
-				up(&lock);
+				mutex_unlock(&lock);
 			}
 			return 0;
 		}
@@ -318,14 +318,14 @@
 			else
 				printk(KERN_DEBUG "mute\n");
 #endif
-			down(&lock);
+			mutex_lock(&lock);
 			if (fmr2->curvol && !fmr2->mute)
 			{
 				fmr2_setvolume(fmr2);
 				fmr2_setfreq(fmr2);
 			}
 			else fmr2_mute(fmr2->port);
-			up(&lock);
+			mutex_unlock(&lock);
 			return 0;
 		}
 		case VIDIOCGUNIT:
@@ -380,7 +380,7 @@
 	fmr2_unit.card_type = 0;
 	fmr2_radio.priv = &fmr2_unit;
 
-	init_MUTEX(&lock);
+	mutex_init(&lock);
 
 	if (request_region(io, 2, "sf16fmr2"))
 	{
@@ -397,10 +397,10 @@
 	printk(KERN_INFO "SF16FMR2 radio card driver at 0x%x.\n", io);
 	debug_print((KERN_DEBUG "Mute %d Low %d\n",VIDEO_AUDIO_MUTE,VIDEO_TUNER_LOW));
 	/* mute card - prevents noisy bootups */
-	down(&lock);
+	mutex_lock(&lock);
 	fmr2_mute(io);
 	fmr2_product_info(&fmr2_unit);
-	up(&lock);
+	mutex_unlock(&lock);
 	debug_print((KERN_DEBUG "card_type %d\n", fmr2_unit.card_type));
 	return 0;
 }
diff -urN oldtree/drivers/media/radio/radio-typhoon.c newtree/drivers/media/radio/radio-typhoon.c
--- oldtree/drivers/media/radio/radio-typhoon.c	2006-02-19 11:41:02.689934168 +0000
+++ newtree/drivers/media/radio/radio-typhoon.c	2006-02-21 15:58:13.476097880 +0000
@@ -59,7 +59,7 @@
 	int muted;
 	unsigned long curfreq;
 	unsigned long mutefreq;
-	struct semaphore lock;
+	struct mutex lock;
 };
 
 static void typhoon_setvol_generic(struct typhoon_device *dev, int vol);
@@ -77,12 +77,12 @@
 
 static void typhoon_setvol_generic(struct typhoon_device *dev, int vol)
 {
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	vol >>= 14;				/* Map 16 bit to 2 bit */
 	vol &= 3;
 	outb_p(vol / 2, dev->iobase);		/* Set the volume, high bit. */
 	outb_p(vol % 2, dev->iobase + 2);	/* Set the volume, low bit. */
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 }
 
 static int typhoon_setfreq_generic(struct typhoon_device *dev,
@@ -102,7 +102,7 @@
 	 *
 	 */
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	x = frequency / 160;
 	outval = (x * x + 2500) / 5000;
 	outval = (outval * x + 5000) / 10000;
@@ -112,7 +112,7 @@
 	outb_p((outval >> 8) & 0x01, dev->iobase + 4);
 	outb_p(outval >> 9, dev->iobase + 6);
 	outb_p(outval & 0xff, dev->iobase + 8);
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 
 	return 0;
 }
@@ -337,7 +337,7 @@
 #endif /* MODULE */
 
 	printk(KERN_INFO BANNER);
-	init_MUTEX(&typhoon_unit.lock);
+	mutex_init(&typhoon_unit.lock);
 	io = typhoon_unit.iobase;
 	if (!request_region(io, 8, "typhoon")) {
 		printk(KERN_ERR "radio-typhoon: port 0x%x already in use\n",
diff -urN oldtree/drivers/media/radio/radio-zoltrix.c newtree/drivers/media/radio/radio-zoltrix.c
--- oldtree/drivers/media/radio/radio-zoltrix.c	2006-02-19 11:41:02.689934168 +0000
+++ newtree/drivers/media/radio/radio-zoltrix.c	2006-02-21 15:58:13.477097728 +0000
@@ -48,7 +48,7 @@
 	unsigned long curfreq;
 	int muted;
 	unsigned int stereo;
-	struct semaphore lock;
+	struct mutex lock;
 };
 
 static int zol_setvol(struct zol_device *dev, int vol)
@@ -57,30 +57,30 @@
 	if (dev->muted)
 		return 0;
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	if (vol == 0) {
 		outb(0, io);
 		outb(0, io);
 		inb(io + 3);    /* Zoltrix needs to be read to confirm */
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		return 0;
 	}
 
 	outb(dev->curvol-1, io);
 	msleep(10);
 	inb(io + 2);
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 	return 0;
 }
 
 static void zol_mute(struct zol_device *dev)
 {
 	dev->muted = 1;
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	outb(0, io);
 	outb(0, io);
 	inb(io + 3);            /* Zoltrix needs to be read to confirm */
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 }
 
 static void zol_unmute(struct zol_device *dev)
@@ -104,7 +104,7 @@
 	bitmask = 0xc480402c10080000ull;
 	i = 45;
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	
 	outb(0, io);
 	outb(0, io);
@@ -149,7 +149,7 @@
 		udelay(1000);
 	}
 	
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 	
 	if(!dev->muted)
 	{
@@ -164,7 +164,7 @@
 {
 	int a, b;
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	outb(0x00, io);         /* This stuff I found to do nothing */
 	outb(dev->curvol, io);
 	msleep(20);
@@ -173,7 +173,7 @@
 	msleep(10);
 	b = inb(io);
 
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 	
 	if (a != b)
 		return (0);
@@ -188,7 +188,7 @@
 {
 	int x1, x2;
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	
 	outb(0x00, io);
 	outb(dev->curvol, io);
@@ -198,7 +198,7 @@
 	msleep(10);
 	x2 = inb(io);
 
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 	
 	if ((x1 == x2) && (x1 == 0xcf))
 		return 1;
@@ -350,7 +350,7 @@
 	}
 	printk(KERN_INFO "Zoltrix Radio Plus card driver.\n");
 
-	init_MUTEX(&zoltrix_unit.lock);
+	mutex_init(&zoltrix_unit.lock);
 	
 	/* mute card - prevents noisy bootups */
 
diff -urN oldtree/drivers/media/video/arv.c newtree/drivers/media/video/arv.c
--- oldtree/drivers/media/video/arv.c	2006-02-19 11:41:02.692933712 +0000
+++ newtree/drivers/media/video/arv.c	2006-02-21 15:58:13.477097728 +0000
@@ -31,8 +31,8 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
+#include <linux/mutex.h>
 
-#include <asm/semaphore.h>
 #include <asm/uaccess.h>
 #include <asm/m32r.h>
 #include <asm/io.h>
@@ -117,7 +117,7 @@
 	int width, height;
 	int frame_bytes, line_bytes;
 	wait_queue_head_t wait;
-	struct semaphore lock;
+	struct mutex lock;
 };
 
 static int video_nr = -1;	/* video device number (first free) */
@@ -288,7 +288,7 @@
 	if (ar->mode == AR_MODE_NORMAL)
 		arvcr1 |= ARVCR1_NORMAL;
 
-	down(&ar->lock);
+	mutex_lock(&ar->lock);
 
 #if USE_INT
 	local_irq_save(flags);
@@ -392,7 +392,7 @@
 	}
 	DEBUG(1, "ret = %d\n", ret);
 out_up:
-	up(&ar->lock);
+	mutex_unlock(&ar->lock);
 	return ret;
 }
 
@@ -456,7 +456,7 @@
 		    (w->width != AR_WIDTH_QVGA || w->height != AR_HEIGHT_QVGA))
 				return -EINVAL;
 
-		down(&ar->lock);
+		mutex_lock(&ar->lock);
 		ar->width = w->width;
 		ar->height = w->height;
 		if (ar->width == AR_WIDTH_VGA) {
@@ -473,7 +473,7 @@
 			ar->line_bytes = AR_LINE_BYTES_QVGA;
 			ar->mode = AR_MODE_INTERLACE;
 		}
-		up(&ar->lock);
+		mutex_unlock(&ar->lock);
 		return 0;
 	}
 	case VIDIOCGFBUF:
@@ -734,7 +734,7 @@
 void ar_release(struct video_device *vfd)
 {
 	struct ar_device *ar = vfd->priv;
-	down(&ar->lock);
+	mutex_lock(&ar->lock);
 	video_device_release(vfd);
 }
 
@@ -824,7 +824,7 @@
 		ar->line_bytes	= AR_LINE_BYTES_QVGA;
 		ar->mode	= AR_MODE_INTERLACE;
 	}
-	init_MUTEX(&ar->lock);
+	mutex_init(&ar->lock);
 	init_waitqueue_head(&ar->wait);
 
 #if USE_INT
diff -urN oldtree/drivers/media/video/bttv-driver.c newtree/drivers/media/video/bttv-driver.c
--- oldtree/drivers/media/video/bttv-driver.c	2006-02-19 11:41:02.700932496 +0000
+++ newtree/drivers/media/video/bttv-driver.c	2006-02-21 15:58:13.482096968 +0000
@@ -1965,7 +1965,7 @@
 		BUG();
 	}
 
-	down(&fh->cap.lock);
+	mutex_lock(&fh->cap.lock);
 		kfree(fh->ov.clips);
 	fh->ov.clips    = clips;
 	fh->ov.nclips   = n;
@@ -1986,7 +1986,7 @@
 		bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
 		retval = bttv_switch_overlay(btv,fh,new);
 	}
-	up(&fh->cap.lock);
+	mutex_unlock(&fh->cap.lock);
 	return retval;
 }
 
@@ -2166,7 +2166,7 @@
 		fmt = format_by_fourcc(f->fmt.pix.pixelformat);
 
 		/* update our state informations */
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		fh->fmt              = fmt;
 		fh->cap.field        = f->fmt.pix.field;
 		fh->cap.last         = V4L2_FIELD_NONE;
@@ -2175,7 +2175,7 @@
 		btv->init.fmt        = fmt;
 		btv->init.width      = f->fmt.pix.width;
 		btv->init.height     = f->fmt.pix.height;
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 
 		return 0;
 	}
@@ -2282,7 +2282,7 @@
 		fmt = format_by_palette(pic->palette);
 		if (NULL == fmt)
 			return -EINVAL;
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		if (fmt->depth != pic->depth) {
 			retval = -EINVAL;
 			goto fh_unlock_and_return;
@@ -2313,7 +2313,7 @@
 		bt848_contrast(btv,pic->contrast);
 		bt848_hue(btv,pic->hue);
 		bt848_sat(btv,pic->colour);
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 		return 0;
 	}
 
@@ -2379,7 +2379,7 @@
 			return -EPERM;
 		end = (unsigned long)fbuf->base +
 			fbuf->height * fbuf->bytesperline;
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		retval = -EINVAL;
 
 		switch (fbuf->depth) {
@@ -2417,7 +2417,7 @@
 			btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
 		else
 			btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 		return 0;
 	}
 
@@ -2440,7 +2440,7 @@
 		if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
 			return -EBUSY;
 
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		if (*on) {
 			fh->ov.tvnorm = btv->tvnorm;
 			new = videobuf_alloc(sizeof(*new));
@@ -2451,7 +2451,7 @@
 
 		/* switch over */
 		retval = bttv_switch_overlay(btv,fh,new);
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 		return retval;
 	}
 
@@ -2460,7 +2460,7 @@
 		struct video_mbuf *mbuf = arg;
 		unsigned int i;
 
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
 					     V4L2_MEMORY_MMAP);
 		if (retval < 0)
@@ -2470,7 +2470,7 @@
 		mbuf->size   = gbuffers * gbufsize;
 		for (i = 0; i < gbuffers; i++)
 			mbuf->offsets[i] = i * gbufsize;
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 		return 0;
 	}
 	case VIDIOCMCAPTURE:
@@ -2482,7 +2482,7 @@
 		if (vm->frame >= VIDEO_MAX_FRAME)
 			return -EINVAL;
 
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		retval = -EINVAL;
 		buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
 		if (NULL == buf)
@@ -2504,7 +2504,7 @@
 		spin_lock_irqsave(&btv->s_lock,flags);
 		buffer_queue(&fh->cap,&buf->vb);
 		spin_unlock_irqrestore(&btv->s_lock,flags);
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 		return 0;
 	}
 	case VIDIOCSYNC:
@@ -2515,7 +2515,7 @@
 		if (*frame >= VIDEO_MAX_FRAME)
 			return -EINVAL;
 
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		retval = -EINVAL;
 		buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
 		if (NULL == buf)
@@ -2535,7 +2535,7 @@
 			retval = -EINVAL;
 			break;
 		}
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 		return retval;
 	}
 
@@ -2719,7 +2719,7 @@
 		if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
 			return -EINVAL;
 
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		retval = -EINVAL;
 		if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
 			if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth)
@@ -2759,7 +2759,7 @@
 				retval = bttv_switch_overlay(btv,fh,new);
 			}
 		}
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 		return retval;
 	}
 
@@ -2890,7 +2890,7 @@
 	return 0;
 
  fh_unlock_and_return:
-	up(&fh->cap.lock);
+	mutex_unlock(&fh->cap.lock);
 	return retval;
 }
 
@@ -2957,16 +2957,16 @@
 		buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
 	} else {
 		/* read() capture */
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		if (NULL == fh->cap.read_buf) {
 			/* need to capture a new frame */
 			if (locked_btres(fh->btv,RESOURCE_VIDEO)) {
-				up(&fh->cap.lock);
+				mutex_unlock(&fh->cap.lock);
 				return POLLERR;
 			}
 			fh->cap.read_buf = videobuf_alloc(fh->cap.msize);
 			if (NULL == fh->cap.read_buf) {
-				up(&fh->cap.lock);
+				mutex_unlock(&fh->cap.lock);
 				return POLLERR;
 			}
 			fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
@@ -2974,13 +2974,13 @@
 			if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
 				kfree (fh->cap.read_buf);
 				fh->cap.read_buf = NULL;
-				up(&fh->cap.lock);
+				mutex_unlock(&fh->cap.lock);
 				return POLLERR;
 			}
 			fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
 			fh->cap.read_off = 0;
 		}
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 		buf = (struct bttv_buffer*)fh->cap.read_buf;
 	}
 
diff -urN oldtree/drivers/media/video/bw-qcam.c newtree/drivers/media/video/bw-qcam.c
--- oldtree/drivers/media/video/bw-qcam.c	2006-02-19 11:41:02.705931736 +0000
+++ newtree/drivers/media/video/bw-qcam.c	2006-02-21 15:58:13.483096816 +0000
@@ -73,7 +73,7 @@
 #include <linux/parport.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include "bw-qcam.h"
@@ -168,7 +168,7 @@
 	
 	memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
 	
-	init_MUTEX(&q->lock);
+	mutex_init(&q->lock);
 
 	q->port_mode = (QC_ANY | QC_NOTSET);
 	q->width = 320;
@@ -772,9 +772,9 @@
 			qcam->whitebal = p->whiteness>>8;
 			qcam->bpp = p->depth;
 
-			down(&qcam->lock);			
+			mutex_lock(&qcam->lock);
 			qc_setscanmode(qcam);
-			up(&qcam->lock);
+			mutex_unlock(&qcam->lock);
 			qcam->status |= QC_PARAM_CHANGE;
 
 			return 0;
@@ -805,9 +805,9 @@
 				qcam->height = 240;
 				qcam->transfer_scale = 1;
 			}
-			down(&qcam->lock);
+			mutex_lock(&qcam->lock);
 			qc_setscanmode(qcam);
-			up(&qcam->lock);
+			mutex_unlock(&qcam->lock);
 			
 			/* We must update the camera before we grab. We could
 			   just have changed the grab size */
@@ -854,7 +854,7 @@
 	int len;
 	parport_claim_or_block(qcam->pdev);
 	
-	down(&qcam->lock);
+	mutex_lock(&qcam->lock);
 	
 	qc_reset(qcam);
 
@@ -864,7 +864,7 @@
 
 	len=qc_capture(qcam, buf,count);
 	
-	up(&qcam->lock);
+	mutex_unlock(&qcam->lock);
 	
 	parport_release(qcam->pdev);
 	return len;
diff -urN oldtree/drivers/media/video/bw-qcam.h newtree/drivers/media/video/bw-qcam.h
--- oldtree/drivers/media/video/bw-qcam.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/media/video/bw-qcam.h	2006-02-21 15:58:13.487096208 +0000
@@ -55,7 +55,7 @@
 	struct video_device vdev;
 	struct pardevice *pdev;
 	struct parport *pport;
-	struct semaphore lock;
+	struct mutex lock;
 	int width, height;
 	int bpp;
 	int mode;
diff -urN oldtree/drivers/media/video/c-qcam.c newtree/drivers/media/video/c-qcam.c
--- oldtree/drivers/media/video/c-qcam.c	2006-02-19 11:41:02.706931584 +0000
+++ newtree/drivers/media/video/c-qcam.c	2006-02-21 15:58:13.506093320 +0000
@@ -34,7 +34,8 @@
 #include <linux/parport.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
 #include <asm/uaccess.h>
 
 struct qcam_device {
@@ -47,7 +48,7 @@
 	int contrast, brightness, whitebal;
 	int top, left;
 	unsigned int bidirectional;
-	struct semaphore lock;
+	struct mutex lock;
 };
 
 /* cameras maximum */
@@ -581,11 +582,11 @@
 			qcam->contrast = p->contrast>>8;
 			qcam->whitebal = p->whiteness>>8;
 
-			down(&qcam->lock);			
+			mutex_lock(&qcam->lock);
 			parport_claim_or_block(qcam->pdev);
 			qc_setup(qcam); 
 			parport_release(qcam->pdev);
-			up(&qcam->lock);
+			mutex_unlock(&qcam->lock);
 			return 0;
 		}
 		case VIDIOCSWIN:
@@ -628,11 +629,11 @@
 #endif
 			/* Ok we figured out what to use from our 
 			   wide choice */
-			down(&qcam->lock);
+			mutex_lock(&qcam->lock);
 			parport_claim_or_block(qcam->pdev);
 			qc_setup(qcam);
 			parport_release(qcam->pdev);
-			up(&qcam->lock);
+			mutex_unlock(&qcam->lock);
 			return 0;
 		}
 		case VIDIOCGWIN:
@@ -672,12 +673,12 @@
 	struct qcam_device *qcam=(struct qcam_device *)v;
 	int len;
 
-	down(&qcam->lock);
+	mutex_lock(&qcam->lock);
 	parport_claim_or_block(qcam->pdev);
 	/* Probably should have a semaphore against multiple users */
 	len = qc_capture(qcam, buf,count); 
 	parport_release(qcam->pdev);
-	up(&qcam->lock);
+	mutex_unlock(&qcam->lock);
 	return len;
 }
 
@@ -727,7 +728,7 @@
 	
 	memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
 
-	init_MUTEX(&q->lock);
+	mutex_init(&q->lock);
 	q->width = q->ccd_width = 320;
 	q->height = q->ccd_height = 240;
 	q->mode = QC_MILLIONS | QC_DECIMATION_1;
diff -urN oldtree/drivers/media/video/cpia.c newtree/drivers/media/video/cpia.c
--- oldtree/drivers/media/video/cpia.c	2006-02-19 11:41:02.709931128 +0000
+++ newtree/drivers/media/video/cpia.c	2006-02-21 15:58:13.504093624 +0000
@@ -39,7 +39,7 @@
 #include <linux/pagemap.h>
 #include <linux/delay.h>
 #include <asm/io.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
@@ -622,7 +622,7 @@
 	
 	buffer = page;
 	
-	if (down_interruptible(&cam->param_lock))
+	if (mutex_lock_interruptible(&cam->param_lock))
 		return -ERESTARTSYS;
 	
 	/*
@@ -1350,7 +1350,7 @@
 	} else
 		DBG("error: %d\n", retval);
 	
-	up(&cam->param_lock);
+	mutex_unlock(&cam->param_lock);
 	
 out:
 	free_page((unsigned long)page);
@@ -1664,7 +1664,7 @@
 	case CPIA_COMMAND_GetColourParams:
 	case CPIA_COMMAND_GetColourBalance:
 	case CPIA_COMMAND_GetExposure:
-		down(&cam->param_lock);
+		mutex_lock(&cam->param_lock);
 		datasize=8;
 		break;
 	case CPIA_COMMAND_ReadMCPorts: 
@@ -1691,7 +1691,7 @@
 		if (command == CPIA_COMMAND_GetColourParams ||
 		    command == CPIA_COMMAND_GetColourBalance ||
 		    command == CPIA_COMMAND_GetExposure)
-			up(&cam->param_lock);
+			mutex_unlock(&cam->param_lock);
 	} else {
 		switch(command) {
 		case CPIA_COMMAND_GetCPIAVersion:
@@ -1726,13 +1726,13 @@
 			cam->params.colourParams.brightness = data[0];
 			cam->params.colourParams.contrast = data[1];
 			cam->params.colourParams.saturation = data[2];
-			up(&cam->param_lock);
+			mutex_unlock(&cam->param_lock);
 			break;
 		case CPIA_COMMAND_GetColourBalance:
 			cam->params.colourBalance.redGain = data[0];
 			cam->params.colourBalance.greenGain = data[1];
 			cam->params.colourBalance.blueGain = data[2];
-			up(&cam->param_lock);
+			mutex_unlock(&cam->param_lock);
 			break;
 		case CPIA_COMMAND_GetExposure:
 			cam->params.exposure.gain = data[0];
@@ -1743,7 +1743,7 @@
 			cam->params.exposure.green1Comp = data[5];
 			cam->params.exposure.green2Comp = data[6];
 			cam->params.exposure.blueComp = data[7];
-			up(&cam->param_lock);
+			mutex_unlock(&cam->param_lock);
 			break;
 
 		case CPIA_COMMAND_ReadMCPorts: 
@@ -2059,7 +2059,7 @@
 	int rows, cols, linesize, subsample_422;
 
 	/* make sure params don't change while we are decoding */
-	down(&cam->param_lock);
+	mutex_lock(&cam->param_lock);
 
 	obuf = cam->decompressed_frame.data;
 	end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
@@ -2069,26 +2069,26 @@
 
 	if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
 		LOG("header not found\n");
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		return -1;
 	}
 
 	if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
 		LOG("wrong video size\n");
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		return -1;
 	}
 	
 	if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) {
 		LOG("illegal subtype %d\n",ibuf[17]);
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		return -1;
 	}
 	subsample_422 = ibuf[17] == SUBSAMPLE_422;
 	
 	if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
 		LOG("illegal yuvorder %d\n",ibuf[18]);
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		return -1;
 	}
 	in_uyvy = ibuf[18] == YUVORDER_UYVY;
@@ -2098,7 +2098,7 @@
 	    (ibuf[26] != cam->params.roi.rowStart) ||
 	    (ibuf[27] != cam->params.roi.rowEnd)) {
 		LOG("ROI mismatch\n");
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		return -1;
 	}
 	cols = 8*(ibuf[25] - ibuf[24]);
@@ -2107,14 +2107,14 @@
 	
 	if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
 		LOG("illegal compression %d\n",ibuf[28]);
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		return -1;
 	}
 	compressed = (ibuf[28] == COMPRESSED);
 	
 	if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) {
 		LOG("illegal decimation %d\n",ibuf[29]);
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		return -1;
 	}
 	decimation = (ibuf[29] == DECIMATION_ENAB);	
@@ -2130,7 +2130,7 @@
 	cam->params.status.vpStatus = ibuf[38];
 	cam->params.status.errorCode = ibuf[39];
 	cam->fps = ibuf[41];
-	up(&cam->param_lock);
+	mutex_unlock(&cam->param_lock);
 	
 	linesize = skipcount(cols, out_fmt);
 	ibuf += FRAME_HEADER_SIZE;
@@ -2271,9 +2271,9 @@
 /* update various camera modes and settings */
 static void dispatch_commands(struct cam_data *cam)
 {
-	down(&cam->param_lock);
+	mutex_lock(&cam->param_lock);
 	if (cam->cmd_queue==COMMAND_NONE) {
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		return;
 	}
 	DEB_BYTE(cam->cmd_queue);
@@ -2415,7 +2415,7 @@
 	  }
 
 	cam->cmd_queue = COMMAND_NONE;
-	up(&cam->param_lock);
+	mutex_unlock(&cam->param_lock);
 	return;
 }
 
@@ -2562,7 +2562,7 @@
 	gain = data[2];
 	coarseL = data[3];
 
-	down(&cam->param_lock);
+	mutex_lock(&cam->param_lock);
 	light_exp = cam->params.colourParams.brightness +
 	            TC - 50 + EXP_ACC_LIGHT;
 	if(light_exp > 255)
@@ -2762,7 +2762,7 @@
 			LOG("Automatically increasing sensor_fps\n");
 		}
 	}
-	up(&cam->param_lock);
+	mutex_unlock(&cam->param_lock);
 }
 
 /*-----------------------------------------------------------------*/
@@ -2778,10 +2778,10 @@
 	int cam_exposure, old_exp;
 	if(!FIRMWARE_VERSION(1,2))
 		return;
-	down(&cam->param_lock);
+	mutex_lock(&cam->param_lock);
 	if(cam->params.flickerControl.flickerMode == 0 ||
 	   cam->raw_image[39] == 0) {
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		return;
 	}
 	cam_exposure = cam->raw_image[39]*2;
@@ -2810,7 +2810,7 @@
 			cam->exposure_status = EXPOSURE_NORMAL;
 
 	}
-	up(&cam->param_lock);
+	mutex_unlock(&cam->param_lock);
 }
 #undef FIRMWARE_VERSION
 
@@ -3186,7 +3186,7 @@
 	if (!try_module_get(cam->ops->owner))
 		return -ENODEV;
 
-	down(&cam->busy_lock);
+	mutex_lock(&cam->busy_lock);
 	err = -ENOMEM;
 	if (!cam->raw_image) {
 		cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
@@ -3227,7 +3227,7 @@
 	
 	++cam->open_count;
 	file->private_data = dev;
-	up(&cam->busy_lock);
+	mutex_unlock(&cam->busy_lock);
 	return 0;
 
  oops:
@@ -3239,7 +3239,7 @@
 		rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
 		cam->raw_image = NULL;
 	}
-	up(&cam->busy_lock);
+	mutex_unlock(&cam->busy_lock);
 	put_cam(cam->ops);
 	return err;
 }
@@ -3303,24 +3303,24 @@
 	int err;
 
 	/* make this _really_ smp and multithread-safe */
-	if (down_interruptible(&cam->busy_lock))
+	if (mutex_lock_interruptible(&cam->busy_lock))
 		return -EINTR;
 
 	if (!buf) {
 		DBG("buf NULL\n");
-		up(&cam->busy_lock);
+		mutex_unlock(&cam->busy_lock);
 		return -EINVAL;
 	}
 
 	if (!count) {
 		DBG("count 0\n");
-		up(&cam->busy_lock);
+		mutex_unlock(&cam->busy_lock);
 		return 0;
 	}
 
 	if (!cam->ops) {
 		DBG("ops NULL\n");
-		up(&cam->busy_lock);
+		mutex_unlock(&cam->busy_lock);
 		return -ENODEV;
 	}
 
@@ -3329,7 +3329,7 @@
 	cam->mmap_kludge=0;
 	if((err = fetch_frame(cam)) != 0) {
 		DBG("ERROR from fetch_frame: %d\n", err);
-		up(&cam->busy_lock);
+		mutex_unlock(&cam->busy_lock);
 		return err;
 	}
 	cam->decompressed_frame.state = FRAME_UNUSED;
@@ -3338,17 +3338,17 @@
 	if (cam->decompressed_frame.count > count) {
 		DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
 		    (unsigned long) count);
-		up(&cam->busy_lock);
+		mutex_unlock(&cam->busy_lock);
 		return -EFAULT;
 	}
 	if (copy_to_user(buf, cam->decompressed_frame.data,
 	                cam->decompressed_frame.count)) {
 		DBG("copy_to_user failed\n");
-		up(&cam->busy_lock);
+		mutex_unlock(&cam->busy_lock);
 		return -EFAULT;
 	}
 
-	up(&cam->busy_lock);
+	mutex_unlock(&cam->busy_lock);
 	return cam->decompressed_frame.count;
 }
 
@@ -3363,7 +3363,7 @@
 		return -ENODEV;
 	
 	/* make this _really_ smp-safe */
-	if (down_interruptible(&cam->busy_lock))
+	if (mutex_lock_interruptible(&cam->busy_lock))
 		return -EINTR;
 
 	//DBG("cpia_ioctl: %u\n", ioctlnr);
@@ -3439,7 +3439,7 @@
 			break;
 		}
 
-		down(&cam->param_lock);
+		mutex_lock(&cam->param_lock);
 		/* brightness, colour, contrast need no check 0-65535 */
 		cam->vp = *vp;
 		/* update cam->params.colourParams */
@@ -3466,7 +3466,7 @@
 
 		/* queue command to update camera */
 		cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
 		    vp->depth, vp->palette, vp->brightness, vp->hue, vp->colour,
 		    vp->contrast);
@@ -3501,13 +3501,13 @@
 		/* we set the video window to something smaller or equal to what
 		* is requested by the user???
 		*/
-		down(&cam->param_lock);
+		mutex_lock(&cam->param_lock);
 		if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
 			int video_size = match_videosize(vw->width, vw->height);
 
 			if (video_size < 0) {
 				retval = -EINVAL;
-				up(&cam->param_lock);
+				mutex_unlock(&cam->param_lock);
 				break;
 			}
 			cam->video_size = video_size;
@@ -3520,7 +3520,7 @@
 			cam->cmd_queue |= COMMAND_SETFORMAT;
 		}
 
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 
 		/* setformat ignored by camera during streaming,
 		 * so stop/dispatch/start */
@@ -3682,7 +3682,7 @@
 
 		DBG("%d,%d/%dx%d\n", vc->x,vc->y,vc->width, vc->height);
 		
-		down(&cam->param_lock);
+		mutex_lock(&cam->param_lock);
 		
 		cam->vc.x      = vc->x;
 		cam->vc.y      = vc->y;
@@ -3692,7 +3692,7 @@
 		set_vw_size(cam);
 		cam->cmd_queue |= COMMAND_SETFORMAT;
 
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 
 		/* setformat ignored by camera during streaming,
 		 * so stop/dispatch/start */
@@ -3736,7 +3736,7 @@
 		break;
 	}
 
-	up(&cam->busy_lock);
+	mutex_unlock(&cam->busy_lock);
 	return retval;
 } 
 
@@ -3769,12 +3769,12 @@
 		return -ENODEV;
 	
 	/* make this _really_ smp-safe */
-	if (down_interruptible(&cam->busy_lock))
+	if (mutex_lock_interruptible(&cam->busy_lock))
 		return -EINTR;
 
 	if (!cam->frame_buf) {	/* we do lazy allocation */
 		if ((retval = allocate_frame_buf(cam))) {
-			up(&cam->busy_lock);
+			mutex_unlock(&cam->busy_lock);
 			return retval;
 		}
 	}
@@ -3783,7 +3783,7 @@
 	while (size > 0) {
 		page = vmalloc_to_pfn((void *)pos);
 		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-			up(&cam->busy_lock);
+			mutex_unlock(&cam->busy_lock);
 			return -EAGAIN;
 		}
 		start += PAGE_SIZE;
@@ -3795,7 +3795,7 @@
 	}
 
 	DBG("cpia_mmap: %ld\n", size);
-	up(&cam->busy_lock);
+	mutex_unlock(&cam->busy_lock);
 
 	return 0;
 }
@@ -3936,8 +3936,8 @@
 	memset(cam, 0, sizeof(struct cam_data));
 
 	cam->ops = ops;
-	init_MUTEX(&cam->param_lock);
-	init_MUTEX(&cam->busy_lock);
+	mutex_init(&cam->param_lock);
+	mutex_init(&cam->busy_lock);
 
 	reset_camera_struct(cam);
 
diff -urN oldtree/drivers/media/video/cpia.h newtree/drivers/media/video/cpia.h
--- oldtree/drivers/media/video/cpia.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/media/video/cpia.h	2006-02-21 15:58:13.505093472 +0000
@@ -47,6 +47,7 @@
 #include <linux/videodev.h>
 #include <linux/list.h>
 #include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 struct cpia_camera_ops
 {
@@ -246,7 +247,7 @@
 struct cam_data {
 	struct list_head cam_data_list;
 
-        struct semaphore busy_lock;     /* guard against SMP multithreading */
+        struct mutex busy_lock;     /* guard against SMP multithreading */
 	struct cpia_camera_ops *ops;	/* lowlevel driver operations */
 	void *lowlevel_data;		/* private data for lowlevel driver */
 	u8 *raw_image;			/* buffer for raw image data */
@@ -261,7 +262,7 @@
 	u8 mainsFreq;			/* for flicker control */
 
 				/* proc interface */
-	struct semaphore param_lock;	/* params lock for this camera */
+	struct mutex param_lock;	/* params lock for this camera */
 	struct cam_params params;	/* camera settings */
 	struct proc_dir_entry *proc_entry;	/* /proc/cpia/videoX */
 	
diff -urN oldtree/drivers/media/video/cx88/cx88-alsa.c newtree/drivers/media/video/cx88/cx88-alsa.c
--- oldtree/drivers/media/video/cx88/cx88-alsa.c	2006-02-19 11:41:02.753924440 +0000
+++ newtree/drivers/media/video/cx88/cx88-alsa.c	2006-02-21 15:58:11.156450520 +0000
@@ -63,7 +63,7 @@
 	/* audio controls */
 	int                        irq;
 
-	snd_card_t                 *card;
+	struct snd_card            *card;
 
 	spinlock_t                 reg_lock;
 
@@ -82,7 +82,7 @@
 	struct cx88_buffer   *buf;
 
 	long opened;
-	snd_pcm_substream_t *substream;
+	struct snd_pcm_substream *substream;
 
 };
 typedef struct cx88_audio_dev snd_cx88_card_t;
@@ -96,7 +96,7 @@
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
-static snd_card_t *snd_cx88_cards[SNDRV_CARDS];
+static struct snd_card *snd_cx88_cards[SNDRV_CARDS];
 
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled.");
@@ -320,7 +320,7 @@
 /*
  * Digital hardware definition
  */
-static snd_pcm_hardware_t snd_cx88_digital_hw = {
+static struct snd_pcm_hardware snd_cx88_digital_hw = {
 	.info = SNDRV_PCM_INFO_MMAP |
 		SNDRV_PCM_INFO_INTERLEAVED |
 		SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -342,16 +342,16 @@
 /*
  * audio pcm capture runtime free
  */
-static void snd_card_cx88_runtime_free(snd_pcm_runtime_t *runtime)
+static void snd_card_cx88_runtime_free(struct snd_pcm_runtime *runtime)
 {
 }
 /*
  * audio pcm capture open callback
  */
-static int snd_cx88_pcm_open(snd_pcm_substream_t *substream)
+static int snd_cx88_pcm_open(struct snd_pcm_substream *substream)
 {
 	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	int err;
 
 	if (test_and_set_bit(0, &chip->opened))
@@ -380,7 +380,7 @@
 /*
  * audio close callback
  */
-static int snd_cx88_close(snd_pcm_substream_t *substream)
+static int snd_cx88_close(struct snd_pcm_substream *substream)
 {
 	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
 
@@ -393,8 +393,8 @@
 /*
  * hw_params callback
  */
-static int snd_cx88_hw_params(snd_pcm_substream_t * substream,
-				 snd_pcm_hw_params_t * hw_params)
+static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
+			      struct snd_pcm_hw_params * hw_params)
 {
 	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
 	struct cx88_buffer *buf;
@@ -453,7 +453,7 @@
 /*
  * hw free callback
  */
-static int snd_cx88_hw_free(snd_pcm_substream_t * substream)
+static int snd_cx88_hw_free(struct snd_pcm_substream * substream)
 {
 
 	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
@@ -469,7 +469,7 @@
 /*
  * prepare callback
  */
-static int snd_cx88_prepare(snd_pcm_substream_t *substream)
+static int snd_cx88_prepare(struct snd_pcm_substream *substream)
 {
 	return 0;
 }
@@ -478,7 +478,7 @@
 /*
  * trigger callback
  */
-static int snd_cx88_card_trigger(snd_pcm_substream_t *substream, int cmd)
+static int snd_cx88_card_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
 	int err;
@@ -505,10 +505,10 @@
 /*
  * pointer callback
  */
-static snd_pcm_uframes_t snd_cx88_pointer(snd_pcm_substream_t *substream)
+static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream)
 {
 	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
+	struct snd_pcm_runtime *runtime = substream->runtime;
 
 	if (chip->read_count) {
 		chip->read_count -= snd_pcm_lib_period_bytes(substream);
@@ -525,7 +525,7 @@
 /*
  * operators
  */
-static snd_pcm_ops_t snd_cx88_pcm_ops = {
+static struct snd_pcm_ops snd_cx88_pcm_ops = {
 	.open = snd_cx88_pcm_open,
 	.close = snd_cx88_close,
 	.ioctl = snd_pcm_lib_ioctl,
@@ -542,7 +542,7 @@
 static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, char *name)
 {
 	int err;
-	snd_pcm_t *pcm;
+	struct snd_pcm *pcm;
 
 	err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
 	if (err < 0)
@@ -557,7 +557,8 @@
 /****************************************************************************
 				CONTROL INTERFACE
  ****************************************************************************/
-static int snd_cx88_capture_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *info)
+static int snd_cx88_capture_volume_info(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_info *info)
 {
 	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	info->count = 1;
@@ -568,7 +569,8 @@
 }
 
 /* OK - TODO: test it */
-static int snd_cx88_capture_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+static int snd_cx88_capture_volume_get(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *value)
 {
 	snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
 	struct cx88_core *core=chip->core;
@@ -579,7 +581,8 @@
 }
 
 /* OK - TODO: test it */
-static int snd_cx88_capture_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+static int snd_cx88_capture_volume_put(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *value)
 {
 	snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
 	struct cx88_core *core=chip->core;
@@ -595,7 +598,7 @@
 	return v != old_control;
 }
 
-static snd_kcontrol_new_t snd_cx88_capture_volume = {
+static struct snd_kcontrol_new snd_cx88_capture_volume = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Capture Volume",
 	.info = snd_cx88_capture_volume_info,
@@ -641,7 +644,7 @@
 /*
  * Component Destructor
  */
-static void snd_cx88_dev_free(snd_card_t * card)
+static void snd_cx88_dev_free(struct snd_card * card)
 {
 	snd_cx88_card_t *chip = card->private_data;
 
@@ -654,8 +657,9 @@
  */
 
 static int devno;
-static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci,
-				    snd_cx88_card_t **rchip)
+static int __devinit snd_cx88_create(struct snd_card *card,
+				     struct pci_dev *pci,
+				     snd_cx88_card_t **rchip)
 {
 	snd_cx88_card_t   *chip;
 	struct cx88_core  *core;
@@ -726,7 +730,7 @@
 static int __devinit cx88_audio_initdev(struct pci_dev *pci,
 				    const struct pci_device_id *pci_id)
 {
-	snd_card_t       *card;
+	struct snd_card  *card;
 	snd_cx88_card_t  *chip;
 	int              err;
 
diff -urN oldtree/drivers/media/video/cx88/cx88-core.c newtree/drivers/media/video/cx88/cx88-core.c
--- oldtree/drivers/media/video/cx88/cx88-core.c	2006-02-19 11:41:02.757923832 +0000
+++ newtree/drivers/media/video/cx88/cx88-core.c	2006-02-21 15:58:13.613077056 +0000
@@ -1061,7 +1061,7 @@
 	core->pci_bus  = pci->bus->number;
 	core->pci_slot = PCI_SLOT(pci->devfn);
 	core->pci_irqmask = 0x00fc00;
-	init_MUTEX(&core->lock);
+	mutex_init(&core->lock);
 
 	core->nr = cx88_devcount++;
 	sprintf(core->name,"cx88[%d]",core->nr);
diff -urN oldtree/drivers/media/video/cx88/cx88-video.c newtree/drivers/media/video/cx88/cx88-video.c
--- oldtree/drivers/media/video/cx88/cx88-video.c	2006-02-19 11:41:02.762923072 +0000
+++ newtree/drivers/media/video/cx88/cx88-video.c	2006-02-21 15:58:13.616076600 +0000
@@ -336,17 +336,17 @@
 		return 1;
 
 	/* is it free? */
-	down(&core->lock);
+	mutex_lock(&core->lock);
 	if (dev->resources & bit) {
 		/* no, someone else uses it */
-		up(&core->lock);
+		mutex_unlock(&core->lock);
 		return 0;
 	}
 	/* it's free, grab it */
 	fh->resources  |= bit;
 	dev->resources |= bit;
 	dprintk(1,"res: get %d\n",bit);
-	up(&core->lock);
+	mutex_unlock(&core->lock);
 	return 1;
 }
 
@@ -369,11 +369,11 @@
 	if ((fh->resources & bits) != bits)
 		BUG();
 
-	down(&core->lock);
+	mutex_lock(&core->lock);
 	fh->resources  &= ~bits;
 	dev->resources &= ~bits;
 	dprintk(1,"res: put %d\n",bits);
-	up(&core->lock);
+	mutex_unlock(&core->lock);
 }
 
 /* ------------------------------------------------------------------ */
@@ -1291,9 +1291,9 @@
 		if (i == ARRAY_SIZE(tvnorms))
 			return -EINVAL;
 
-		down(&core->lock);
+		mutex_lock(&core->lock);
 		cx88_set_tvnorm(core,&tvnorms[i]);
-		up(&core->lock);
+		mutex_unlock(&core->lock);
 		return 0;
 	}
 
@@ -1343,10 +1343,10 @@
 
 		if (*i >= 4)
 			return -EINVAL;
-		down(&core->lock);
+		mutex_lock(&core->lock);
 		cx88_newstation(core);
 		video_mux(core,*i);
-		up(&core->lock);
+		mutex_unlock(&core->lock);
 		return 0;
 	}
 
@@ -1438,7 +1438,7 @@
 			return -EINVAL;
 		if (1 == radio && f->type != V4L2_TUNER_RADIO)
 			return -EINVAL;
-		down(&core->lock);
+		mutex_lock(&core->lock);
 		core->freq = f->frequency;
 		cx88_newstation(core);
 		cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f);
@@ -1447,7 +1447,7 @@
 		msleep (10);
 		cx88_set_tvaudio(core);
 
-		up(&core->lock);
+		mutex_unlock(&core->lock);
 		return 0;
 	}
 
@@ -1921,11 +1921,11 @@
 	pci_set_drvdata(pci_dev,dev);
 
 	/* initial device configuration */
-	down(&core->lock);
+	mutex_lock(&core->lock);
 	cx88_set_tvnorm(core,tvnorms);
 	init_controls(core);
 	video_mux(core,0);
-	up(&core->lock);
+	mutex_unlock(&core->lock);
 
 	/* start tvaudio thread */
 	if (core->tuner_type != TUNER_ABSENT)
diff -urN oldtree/drivers/media/video/cx88/cx88.h newtree/drivers/media/video/cx88/cx88.h
--- oldtree/drivers/media/video/cx88/cx88.h	2006-02-19 11:41:02.764922768 +0000
+++ newtree/drivers/media/video/cx88/cx88.h	2006-02-21 15:58:13.614076904 +0000
@@ -35,6 +35,8 @@
 #include "cx88-reg.h"
 
 #include <linux/version.h>
+#include <linux/mutex.h>
+
 #define CX88_VERSION_CODE KERNEL_VERSION(0,0,5)
 
 #ifndef TRUE
@@ -308,7 +310,7 @@
 	/* IR remote control state */
 	struct cx88_IR             *ir;
 
-	struct semaphore           lock;
+	struct mutex               lock;
 
 	/* various v4l controls */
 	u32                        freq;
diff -urN oldtree/drivers/media/video/em28xx/em28xx-video.c newtree/drivers/media/video/em28xx/em28xx-video.c
--- oldtree/drivers/media/video/em28xx/em28xx-video.c	2006-02-19 11:41:02.768922160 +0000
+++ newtree/drivers/media/video/em28xx/em28xx-video.c	2006-02-21 15:58:13.618076296 +0000
@@ -347,12 +347,12 @@
 		dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	}
 
-	init_MUTEX(&dev->fileop_lock);	/* to 1 == available */
+	mutex_init(&dev->fileop_lock);	/* to 1 == available */
 	spin_lock_init(&dev->queue_lock);
 	init_waitqueue_head(&dev->wait_frame);
 	init_waitqueue_head(&dev->wait_stream);
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 
 	em28xx_set_alternate(dev);
 
@@ -386,7 +386,7 @@
 	video_mux(dev, 0);
 
       err:
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 	up_read(&em28xx_disconnect);
 	return errCode;
 }
@@ -421,7 +421,7 @@
 
 	em28xx_videodbg("users=%d\n", dev->users);
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 
 	em28xx_uninit_isoc(dev);
 
@@ -430,7 +430,7 @@
 	/* the device is already disconnect, free the remaining resources */
 	if (dev->state & DEV_DISCONNECTED) {
 		em28xx_release_resources(dev);
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		kfree(dev);
 		return 0;
 	}
@@ -446,7 +446,7 @@
 
 	dev->users--;
 	wake_up_interruptible_nr(&dev->open, 1);
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 	return 0;
 }
 
@@ -463,32 +463,32 @@
 	int ret = 0;
 	struct em28xx *dev = filp->private_data;
 
-	if (down_interruptible(&dev->fileop_lock))
+	if (mutex_lock_interruptible(&dev->fileop_lock))
 		return -ERESTARTSYS;
 
 	if (dev->state & DEV_DISCONNECTED) {
 		em28xx_videodbg("device not present\n");
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -ENODEV;
 	}
 
 	if (dev->state & DEV_MISCONFIGURED) {
 		em28xx_videodbg("device misconfigured; close and open it again\n");
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -EIO;
 	}
 
 	if (dev->io == IO_MMAP) {
 		em28xx_videodbg ("IO method is set to mmap; close and open"
 				" the device again to choose the read method\n");
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -EINVAL;
 	}
 
 	if (dev->io == IO_NONE) {
 		if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) {
 			em28xx_errdev("read failed, not enough memory\n");
-			up(&dev->fileop_lock);
+			mutex_unlock(&dev->fileop_lock);
 			return -ENOMEM;
 		}
 		dev->io = IO_READ;
@@ -497,13 +497,13 @@
 	}
 
 	if (!count) {
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return 0;
 	}
 
 	if (list_empty(&dev->outqueue)) {
 		if (filp->f_flags & O_NONBLOCK) {
-			up(&dev->fileop_lock);
+			mutex_unlock(&dev->fileop_lock);
 			return -EAGAIN;
 		}
 		ret = wait_event_interruptible
@@ -511,11 +511,11 @@
 		     (!list_empty(&dev->outqueue)) ||
 		     (dev->state & DEV_DISCONNECTED));
 		if (ret) {
-			up(&dev->fileop_lock);
+			mutex_unlock(&dev->fileop_lock);
 			return ret;
 		}
 		if (dev->state & DEV_DISCONNECTED) {
-			up(&dev->fileop_lock);
+			mutex_unlock(&dev->fileop_lock);
 			return -ENODEV;
 		}
 	}
@@ -534,12 +534,12 @@
 		count = f->buf.length;
 
 	if (copy_to_user(buf, f->bufmem, count)) {
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -EFAULT;
 	}
 	*f_pos += count;
 
-	up(&dev->fileop_lock);
+	mutex_unlock(&dev->fileop_lock);
 
 	return count;
 }
@@ -553,7 +553,7 @@
 	unsigned int mask = 0;
 	struct em28xx *dev = filp->private_data;
 
-	if (down_interruptible(&dev->fileop_lock))
+	if (mutex_lock_interruptible(&dev->fileop_lock))
 		return POLLERR;
 
 	if (dev->state & DEV_DISCONNECTED) {
@@ -579,13 +579,13 @@
 			if (!list_empty(&dev->outqueue))
 				mask |= POLLIN | POLLRDNORM;
 
-			up(&dev->fileop_lock);
+			mutex_unlock(&dev->fileop_lock);
 
 			return mask;
 		}
 	}
 
-	up(&dev->fileop_lock);
+	mutex_unlock(&dev->fileop_lock);
 	return POLLERR;
 }
 
@@ -625,25 +625,25 @@
 
 	struct em28xx *dev = filp->private_data;
 
-	if (down_interruptible(&dev->fileop_lock))
+	if (mutex_lock_interruptible(&dev->fileop_lock))
 		return -ERESTARTSYS;
 
 	if (dev->state & DEV_DISCONNECTED) {
 		em28xx_videodbg("mmap: device not present\n");
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -ENODEV;
 	}
 
 	if (dev->state & DEV_MISCONFIGURED) {
 		em28xx_videodbg ("mmap: Device is misconfigured; close and "
 						"open it again\n");
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -EIO;
 	}
 
 	if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
 	    size != PAGE_ALIGN(dev->frame[0].buf.length)) {
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -EINVAL;
 	}
 
@@ -653,7 +653,7 @@
 	}
 	if (i == dev->num_frames) {
 		em28xx_videodbg("mmap: user supplied mapping address is out of range\n");
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -EINVAL;
 	}
 
@@ -665,7 +665,7 @@
 	while (size > 0) {	/* size is page-aligned */
 		if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
 			em28xx_videodbg("mmap: vm_insert_page failed\n");
-			up(&dev->fileop_lock);
+			mutex_unlock(&dev->fileop_lock);
 			return -EAGAIN;
 		}
 		start += PAGE_SIZE;
@@ -677,7 +677,7 @@
 	vma->vm_private_data = &dev->frame[i];
 
 	em28xx_vm_open(vma);
-	up(&dev->fileop_lock);
+	mutex_unlock(&dev->fileop_lock);
 	return 0;
 }
 
@@ -901,7 +901,7 @@
 			if (i == TVNORMS)
 				return -EINVAL;
 
-			down(&dev->lock);
+			mutex_lock(&dev->lock);
 			dev->tvnorm = &tvnorms[i];
 
 			em28xx_set_norm(dev, dev->width, dev->height);
@@ -929,7 +929,7 @@
 			em28xx_i2c_call_clients(dev, VIDIOC_S_STD,
 						&dev->tvnorm->id);
 
-			up(&dev->lock);
+			mutex_unlock(&dev->lock);
 
 			return 0;
 		}
@@ -985,9 +985,9 @@
 			if (0 == INPUT(*index)->type)
 				return -EINVAL;
 
-			down(&dev->lock);
+			mutex_lock(&dev->lock);
 			video_mux(dev, *index);
-			up(&dev->lock);
+			mutex_unlock(&dev->lock);
 
 			return 0;
 		}
@@ -1138,10 +1138,10 @@
 /*		t->signal = 0xffff;*/
 /*		em28xx_i2c_call_clients(dev,VIDIOC_G_TUNER,t);*/
 			/* No way to get signal strength? */
-			down(&dev->lock);
+			mutex_lock(&dev->lock);
 			em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
 						&status);
-			up(&dev->lock);
+			mutex_unlock(&dev->lock);
 			t->signal =
 			    (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
 
@@ -1163,10 +1163,10 @@
 			t->rangehigh = 0xffffffffUL;	/* FIXME: set correct range */
 /*		t->signal = 0xffff; */
 			/* No way to get signal strength? */
-			down(&dev->lock);
+			mutex_lock(&dev->lock);
 			em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
 						&status);
-			up(&dev->lock);
+			mutex_unlock(&dev->lock);
 			t->signal =
 			    (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
 
@@ -1194,10 +1194,10 @@
 			if (V4L2_TUNER_ANALOG_TV != f->type)
 				return -EINVAL;
 
-			down(&dev->lock);
+			mutex_lock(&dev->lock);
 			dev->ctl_freq = f->frequency;
 			em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
-			up(&dev->lock);
+			mutex_unlock(&dev->lock);
 			return 0;
 		}
 
@@ -1618,25 +1618,25 @@
 	int ret = 0;
 	struct em28xx *dev = filp->private_data;
 
-	if (down_interruptible(&dev->fileop_lock))
+	if (mutex_lock_interruptible(&dev->fileop_lock))
 		return -ERESTARTSYS;
 
 	if (dev->state & DEV_DISCONNECTED) {
 		em28xx_errdev("v4l2 ioctl: device not present\n");
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -ENODEV;
 	}
 
 	if (dev->state & DEV_MISCONFIGURED) {
 		em28xx_errdev
 		    ("v4l2 ioctl: device is misconfigured; close and open it again\n");
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -EIO;
 	}
 
 	ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl);
 
-	up(&dev->fileop_lock);
+	mutex_unlock(&dev->fileop_lock);
 
 	return ret;
 }
@@ -1670,7 +1670,7 @@
 
 	dev->udev = udev;
 	dev->model = model;
-	init_MUTEX(&dev->lock);
+	mutex_init(&dev->lock);
 	init_waitqueue_head(&dev->open);
 
 	dev->em28xx_write_regs = em28xx_write_regs;
@@ -1744,7 +1744,7 @@
 		return -ENOMEM;
 	}
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	/* register i2c bus */
 	em28xx_i2c_register(dev);
 
@@ -1754,7 +1754,7 @@
 	/* configure the device */
 	em28xx_config_i2c(dev);
 
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 
 	errCode = em28xx_config(dev);
 
@@ -1783,11 +1783,11 @@
 	list_add_tail(&dev->devlist,&em28xx_devlist);
 
 	/* register v4l2 device */
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1))) {
 		em28xx_errdev("unable to register video device (error=%i).\n",
 			      retval);
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		list_del(&dev->devlist);
 		video_device_release(dev->vdev);
 		kfree(dev);
@@ -1803,7 +1803,7 @@
 	}
 	video_mux(dev, 0);
 
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 
 	em28xx_info("V4L2 device registered as /dev/video%d\n",
 		    dev->vdev->minor);
@@ -1943,7 +1943,7 @@
 
 	down_write(&em28xx_disconnect);
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 
 	em28xx_info("disconnecting %s\n", dev->vdev->name);
 
@@ -1963,7 +1963,7 @@
 		em28xx_release_resources(dev);
 	}
 
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 
 	if (!dev->users) {
 		kfree(dev->alt_max_pkt_size);
diff -urN oldtree/drivers/media/video/em28xx/em28xx.h newtree/drivers/media/video/em28xx/em28xx.h
--- oldtree/drivers/media/video/em28xx/em28xx.h	2006-02-19 11:41:02.769922008 +0000
+++ newtree/drivers/media/video/em28xx/em28xx.h	2006-02-21 15:58:13.616076600 +0000
@@ -27,6 +27,7 @@
 
 #include <linux/videodev.h>
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 #include <media/ir-kbd-i2c.h>
 
 /* Boards supported by driver */
@@ -256,7 +257,7 @@
 	enum em28xx_stream_state stream;
 	enum em28xx_io_method io;
 	/* locks */
-	struct semaphore lock, fileop_lock;
+	struct mutex lock, fileop_lock;
 	spinlock_t queue_lock;
 	struct list_head inqueue, outqueue;
 	wait_queue_head_t open, wait_frame, wait_stream;
diff -urN oldtree/drivers/media/video/meye.c newtree/drivers/media/video/meye.c
--- oldtree/drivers/media/video/meye.c	2006-02-19 11:41:02.930897536 +0000
+++ newtree/drivers/media/video/meye.c	2006-02-21 15:58:13.621075840 +0000
@@ -925,7 +925,7 @@
 			return -EINVAL;
 		if (p->palette != VIDEO_PALETTE_YUV422)
 			return -EINVAL;
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS,
 				      p->brightness >> 10);
 		sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE,
@@ -935,7 +935,7 @@
 		sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST,
 				      p->contrast >> 10);
 		meye.picture = *p;
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -946,21 +946,21 @@
 		if (*i < 0 || *i >= gbuffers)
 			return -EINVAL;
 
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 
 		switch (meye.grab_buffer[*i].state) {
 
 		case MEYE_BUF_UNUSED:
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EINVAL;
 		case MEYE_BUF_USING:
 			if (file->f_flags & O_NONBLOCK) {
-				up(&meye.lock);
+				mutex_unlock(&meye.lock);
 				return -EAGAIN;
 			}
 			if (wait_event_interruptible(meye.proc_list,
 						     (meye.grab_buffer[*i].state != MEYE_BUF_USING))) {
-				up(&meye.lock);
+				mutex_unlock(&meye.lock);
 				return -EINTR;
 			}
 			/* fall through */
@@ -968,7 +968,7 @@
 			meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
 			kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int));
 		}
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -987,7 +987,7 @@
 		if (meye.grab_buffer[vm->frame].state != MEYE_BUF_UNUSED)
 			return -EBUSY;
 
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		if (vm->width == 640 && vm->height == 480) {
 			if (meye.params.subsample) {
 				meye.params.subsample = 0;
@@ -999,7 +999,7 @@
 				restart = 1;
 			}
 		} else {
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EINVAL;
 		}
 
@@ -1007,7 +1007,7 @@
 			mchip_continuous_start();
 		meye.grab_buffer[vm->frame].state = MEYE_BUF_USING;
 		kfifo_put(meye.grabq, (unsigned char *)&vm->frame, sizeof(int));
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1039,7 +1039,7 @@
 			return -EINVAL;
 		if (jp->framerate > 31)
 			return -EINVAL;
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		if (meye.params.subsample != jp->subsample ||
 		    meye.params.quality != jp->quality)
 			mchip_hic_stop();	/* need restart */
@@ -1050,7 +1050,7 @@
 				      meye.params.agc);
 		sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE,
 				      meye.params.picture);
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1068,12 +1068,12 @@
 		}
 		if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED)
 			return -EBUSY;
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP)
 			mchip_cont_compression_start();
 		meye.grab_buffer[*nb].state = MEYE_BUF_USING;
 		kfifo_put(meye.grabq, (unsigned char *)nb, sizeof(int));
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1084,20 +1084,20 @@
 		if (*i < 0 || *i >= gbuffers)
 			return -EINVAL;
 
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		switch (meye.grab_buffer[*i].state) {
 
 		case MEYE_BUF_UNUSED:
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EINVAL;
 		case MEYE_BUF_USING:
 			if (file->f_flags & O_NONBLOCK) {
-				up(&meye.lock);
+				mutex_unlock(&meye.lock);
 				return -EAGAIN;
 			}
 			if (wait_event_interruptible(meye.proc_list,
 						     (meye.grab_buffer[*i].state != MEYE_BUF_USING))) {
-				up(&meye.lock);
+				mutex_unlock(&meye.lock);
 				return -EINTR;
 			}
 			/* fall through */
@@ -1106,7 +1106,7 @@
 			kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int));
 		}
 		*i = meye.grab_buffer[*i].size;
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1116,14 +1116,14 @@
 			return -EINVAL;
 		if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
 			return -EBUSY;
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		meye.grab_buffer[0].state = MEYE_BUF_USING;
 		mchip_take_picture();
 		mchip_get_picture(
 			meye.grab_fbuffer,
 			mchip_hsize() * mchip_vsize() * 2);
 		meye.grab_buffer[0].state = MEYE_BUF_DONE;
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1134,7 +1134,7 @@
 			return -EINVAL;
 		if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
 			return -EBUSY;
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		meye.grab_buffer[0].state = MEYE_BUF_USING;
 		*len = -1;
 		while (*len == -1) {
@@ -1142,7 +1142,7 @@
 			*len = mchip_compress_frame(meye.grab_fbuffer, gbufsize);
 		}
 		meye.grab_buffer[0].state = MEYE_BUF_DONE;
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1285,7 +1285,7 @@
 	case VIDIOC_S_CTRL: {
 		struct v4l2_control *c = arg;
 
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		switch (c->id) {
 		case V4L2_CID_BRIGHTNESS:
 			sonypi_camera_command(
@@ -1329,17 +1329,17 @@
 			meye.params.framerate = c->value;
 			break;
 		default:
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EINVAL;
 		}
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
 	case VIDIOC_G_CTRL: {
 		struct v4l2_control *c = arg;
 
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		switch (c->id) {
 		case V4L2_CID_BRIGHTNESS:
 			c->value = meye.picture.brightness >> 10;
@@ -1369,10 +1369,10 @@
 			c->value = meye.params.framerate;
 			break;
 		default:
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EINVAL;
 		}
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1469,7 +1469,7 @@
 		    f->fmt.pix.field != V4L2_FIELD_NONE)
 			return -EINVAL;
 		f->fmt.pix.field = V4L2_FIELD_NONE;
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		if (f->fmt.pix.width <= 320) {
 			f->fmt.pix.width = 320;
 			f->fmt.pix.height = 240;
@@ -1487,7 +1487,7 @@
 			meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP;
 			break;
 		}
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
 		f->fmt.pix.sizeimage = f->fmt.pix.height *
 				       f->fmt.pix.bytesperline;
@@ -1509,11 +1509,11 @@
 			/* already allocated, no modifications */
 			break;
 		}
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		if (meye.grab_fbuffer) {
 			for (i = 0; i < gbuffers; i++)
 				if (meye.vma_use_count[i]) {
-					up(&meye.lock);
+					mutex_unlock(&meye.lock);
 					return -EINVAL;
 				}
 			rvfree(meye.grab_fbuffer, gbuffers * gbufsize);
@@ -1525,12 +1525,12 @@
 		if (!meye.grab_fbuffer) {
 			printk(KERN_ERR "meye: v4l framebuffer allocation"
 					" failed\n");
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -ENOMEM;
 		}
 		for (i = 0; i < gbuffers; i++)
 			meye.vma_use_count[i] = 0;
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1569,12 +1569,12 @@
 			return -EINVAL;
 		if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED)
 			return -EINVAL;
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		buf->flags |= V4L2_BUF_FLAG_QUEUED;
 		buf->flags &= ~V4L2_BUF_FLAG_DONE;
 		meye.grab_buffer[buf->index].state = MEYE_BUF_USING;
 		kfifo_put(meye.grabq, (unsigned char *)&buf->index, sizeof(int));
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1587,23 +1587,23 @@
 		if (buf->memory != V4L2_MEMORY_MMAP)
 			return -EINVAL;
 
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) {
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EAGAIN;
 		}
 		if (wait_event_interruptible(meye.proc_list,
 					     kfifo_len(meye.doneq) != 0) < 0) {
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EINTR;
 		}
 		if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr,
 			       sizeof(int))) {
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EBUSY;
 		}
 		if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) {
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EINVAL;
 		}
 		buf->index = reqnr;
@@ -1616,12 +1616,12 @@
 		buf->m.offset = reqnr * gbufsize;
 		buf->length = gbufsize;
 		meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED;
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
 	case VIDIOC_STREAMON: {
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		switch (meye.mchip_mode) {
 		case MCHIP_HIC_MODE_CONT_OUT:
 			mchip_continuous_start();
@@ -1630,23 +1630,23 @@
 			mchip_cont_compression_start();
 			break;
 		default:
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EINVAL;
 		}
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
 	case VIDIOC_STREAMOFF: {
 		int i;
 
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		mchip_hic_stop();
 		kfifo_reset(meye.grabq);
 		kfifo_reset(meye.doneq);
 		for (i = 0; i < MEYE_MAX_BUFNBRS; i++)
 			meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1672,11 +1672,11 @@
 {
 	unsigned int res = 0;
 
-	down(&meye.lock);
+	mutex_lock(&meye.lock);
 	poll_wait(file, &meye.proc_list, wait);
 	if (kfifo_len(meye.doneq))
 		res = POLLIN | POLLRDNORM;
-	up(&meye.lock);
+	mutex_unlock(&meye.lock);
 	return res;
 }
 
@@ -1704,9 +1704,9 @@
 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
 	unsigned long page, pos;
 
-	down(&meye.lock);
+	mutex_lock(&meye.lock);
 	if (size > gbuffers * gbufsize) {
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		return -EINVAL;
 	}
 	if (!meye.grab_fbuffer) {
@@ -1716,7 +1716,7 @@
 		meye.grab_fbuffer = rvmalloc(gbuffers*gbufsize);
 		if (!meye.grab_fbuffer) {
 			printk(KERN_ERR "meye: v4l framebuffer allocation failed\n");
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -ENOMEM;
 		}
 		for (i = 0; i < gbuffers; i++)
@@ -1727,7 +1727,7 @@
 	while (size > 0) {
 		page = vmalloc_to_pfn((void *)pos);
 		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EAGAIN;
 		}
 		start += PAGE_SIZE;
@@ -1744,7 +1744,7 @@
 	vma->vm_private_data = (void *) (offset / gbufsize);
 	meye_vm_open(vma);
 
-	up(&meye.lock);
+	mutex_unlock(&meye.lock);
 	return 0;
 }
 
@@ -1913,7 +1913,7 @@
 		goto outvideoreg;
 	}
 
-	init_MUTEX(&meye.lock);
+	mutex_init(&meye.lock);
 	init_waitqueue_head(&meye.proc_list);
 	meye.picture.depth = 16;
 	meye.picture.palette = VIDEO_PALETTE_YUV422;
diff -urN oldtree/drivers/media/video/meye.h newtree/drivers/media/video/meye.h
--- oldtree/drivers/media/video/meye.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/media/video/meye.h	2006-02-21 15:58:13.622075688 +0000
@@ -260,6 +260,8 @@
 
 /* private API definitions */
 #include <linux/meye.h>
+#include <linux/mutex.h>
+
 
 /* Enable jpg software correction */
 #define MEYE_JPEG_CORRECTION	1
@@ -301,7 +303,7 @@
 					/* list of buffers */
 	struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS];
 	int vma_use_count[MEYE_MAX_BUFNBRS]; /* mmap count */
-	struct semaphore lock;		/* semaphore for open/mmap... */
+	struct mutex lock;		/* mutex for open/mmap... */
 	struct kfifo *grabq;		/* queue for buffers to be grabbed */
 	spinlock_t grabq_lock;		/* lock protecting the queue */
 	struct kfifo *doneq;		/* queue for grabbed buffers */
diff -urN oldtree/drivers/media/video/mxb.c newtree/drivers/media/video/mxb.c
--- oldtree/drivers/media/video/mxb.c	2006-02-19 11:41:02.939896168 +0000
+++ newtree/drivers/media/video/mxb.c	2006-02-21 15:58:13.623075536 +0000
@@ -625,9 +625,9 @@
 		}
 		
 		/* fixme: locke das setzen des inputs mit hilfe des mutexes
-		down(&dev->lock);
+		mutex_lock(&dev->lock);
 		video_mux(dev,*i);
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		*/
 				
 		/* fixme: check if streaming capture
diff -urN oldtree/drivers/media/video/planb.c newtree/drivers/media/video/planb.c
--- oldtree/drivers/media/video/planb.c	2006-02-19 11:41:02.942895712 +0000
+++ newtree/drivers/media/video/planb.c	2006-02-21 15:58:13.624075384 +0000
@@ -48,7 +48,7 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/irq.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include "planb.h"
 #include "saa7196.h"
@@ -329,12 +329,12 @@
 
 static inline void planb_lock(struct planb *pb)
 {
-	down(&pb->lock);
+	mutex_lock(&pb->lock);
 }
 
 static inline void planb_unlock(struct planb *pb)
 {
-	up(&pb->lock);
+	mutex_unlock(&pb->lock);
 }
 
 /***************/
@@ -2067,7 +2067,7 @@
 #endif
 	pb->tab_size = PLANB_MAXLINES + 40;
 	pb->suspend = 0;
-	init_MUTEX(&pb->lock);
+	mutex_init(&pb->lock);
 	pb->ch1_cmd = 0;
 	pb->ch2_cmd = 0;
 	pb->mask = 0;
diff -urN oldtree/drivers/media/video/planb.h newtree/drivers/media/video/planb.h
--- oldtree/drivers/media/video/planb.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/media/video/planb.h	2006-02-21 15:58:13.625075232 +0000
@@ -174,7 +174,7 @@
 	int	user;
 	unsigned int tab_size;
 	int     maxlines;
-	struct semaphore lock;
+	struct mutex lock;
 	unsigned int	irq;			/* interrupt number */
 	volatile unsigned int intr_mask;
 
diff -urN oldtree/drivers/media/video/pms.c newtree/drivers/media/video/pms.c
--- oldtree/drivers/media/video/pms.c	2006-02-19 11:41:02.943895560 +0000
+++ newtree/drivers/media/video/pms.c	2006-02-21 15:58:13.626075080 +0000
@@ -30,6 +30,8 @@
 #include <asm/io.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
+#include <linux/mutex.h>
+
 #include <asm/uaccess.h>
 
 
@@ -44,7 +46,7 @@
 	struct video_picture picture;
 	int height;
 	int width;
-	struct semaphore lock;
+	struct mutex lock;
 };
 
 struct i2c_info
@@ -724,10 +726,10 @@
 			struct video_channel *v = arg;
 			if(v->channel<0 || v->channel>3)
 				return -EINVAL;
-			down(&pd->lock);
+			mutex_lock(&pd->lock);
 			pms_videosource(v->channel&1);
 			pms_vcrinput(v->channel>>1);
-			up(&pd->lock);
+			mutex_unlock(&pd->lock);
 			return 0;
 		}
 		case VIDIOCGTUNER:
@@ -761,7 +763,7 @@
 			struct video_tuner *v = arg;
 			if(v->tuner)
 				return -EINVAL;
-			down(&pd->lock);
+			mutex_lock(&pd->lock);
 			switch(v->mode)
 			{
 				case VIDEO_MODE_AUTO:
@@ -785,10 +787,10 @@
 					pms_format(2);
 					break;
 				default:
-					up(&pd->lock);
+					mutex_unlock(&pd->lock);
 					return -EINVAL;
 			}
-			up(&pd->lock);
+			mutex_unlock(&pd->lock);
 			return 0;
 		}
 		case VIDIOCGPICT:
@@ -809,12 +811,12 @@
 			 *	Now load the card.
 			 */
 
-			down(&pd->lock);
+			mutex_lock(&pd->lock);
 			pms_brightness(p->brightness>>8);
 			pms_hue(p->hue>>8);
 			pms_colour(p->colour>>8);
 			pms_contrast(p->contrast>>8);	
-			up(&pd->lock);
+			mutex_unlock(&pd->lock);
 			return 0;
 		}
 		case VIDIOCSWIN:
@@ -830,9 +832,9 @@
 				return -EINVAL;
 			pd->width=vw->width;
 			pd->height=vw->height;
-			down(&pd->lock);
+			mutex_lock(&pd->lock);
 			pms_resolution(pd->width, pd->height);
-			up(&pd->lock);			/* Ok we figured out what to use from our wide choice */
+			mutex_unlock(&pd->lock);			/* Ok we figured out what to use from our wide choice */
 			return 0;
 		}
 		case VIDIOCGWIN:
@@ -872,9 +874,9 @@
 	struct pms_device *pd=(struct pms_device *)v;
 	int len;
 	
-	down(&pd->lock);
+	mutex_lock(&pd->lock);
 	len=pms_capture(pd, buf, (pd->picture.depth==16)?0:1,count);
-	up(&pd->lock);
+	mutex_unlock(&pd->lock);
 	return len;
 }
 
@@ -1029,7 +1031,7 @@
 		return -ENODEV;
 	}
 	memcpy(&pms_device, &pms_template, sizeof(pms_template));
-	init_MUTEX(&pms_device.lock);
+	mutex_init(&pms_device.lock);
 	pms_device.height=240;
 	pms_device.width=320;
 	pms_swsense(75);
diff -urN oldtree/drivers/media/video/saa5246a.c newtree/drivers/media/video/saa5246a.c
--- oldtree/drivers/media/video/saa5246a.c	2006-02-19 11:41:02.944895408 +0000
+++ newtree/drivers/media/video/saa5246a.c	2006-02-21 15:58:13.627074928 +0000
@@ -46,6 +46,8 @@
 #include <linux/i2c.h>
 #include <linux/videotext.h>
 #include <linux/videodev.h>
+#include <linux/mutex.h>
+
 #include "saa5246a.h"
 
 MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
@@ -57,7 +59,7 @@
 	u8     pgbuf[NUM_DAUS][VTX_VIRTUALSIZE];
 	int    is_searching[NUM_DAUS];
 	struct i2c_client *client;
-	struct semaphore lock;
+	struct mutex lock;
 };
 
 static struct video_device saa_template;	/* Declared near bottom */
@@ -90,7 +92,7 @@
 		return -ENOMEM;
 	}
 	strlcpy(client->name, IF_NAME, I2C_NAME_SIZE);
-	init_MUTEX(&t->lock);
+	mutex_init(&t->lock);
 
 	/*
 	 *	Now create a video4linux device
@@ -719,9 +721,9 @@
 	int err;
 
 	cmd = vtx_fix_command(cmd);
-	down(&t->lock);
+	mutex_lock(&t->lock);
 	err = video_usercopy(inode, file, cmd, arg, do_saa5246a_ioctl);
-	up(&t->lock);
+	mutex_unlock(&t->lock);
 	return err;
 }
 
diff -urN oldtree/drivers/media/video/saa5249.c newtree/drivers/media/video/saa5249.c
--- oldtree/drivers/media/video/saa5249.c	2006-02-19 11:41:02.944895408 +0000
+++ newtree/drivers/media/video/saa5249.c	2006-02-21 15:58:13.627074928 +0000
@@ -56,6 +56,8 @@
 #include <linux/i2c.h>
 #include <linux/videotext.h>
 #include <linux/videodev.h>
+#include <linux/mutex.h>
+
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -105,7 +107,7 @@
 	int disp_mode;
 	int virtual_mode;
 	struct i2c_client *client;
-	struct semaphore lock;
+	struct mutex lock;
 };
 
 
@@ -158,7 +160,7 @@
 		return -ENOMEM;
 	}
 	strlcpy(client->name, IF_NAME, I2C_NAME_SIZE);
-	init_MUTEX(&t->lock);
+	mutex_init(&t->lock);
 	
 	/*
 	 *	Now create a video4linux device
@@ -619,9 +621,9 @@
 	int err;
 	
 	cmd = vtx_fix_command(cmd);
-	down(&t->lock);
+	mutex_lock(&t->lock);
 	err = video_usercopy(inode,file,cmd,arg,do_saa5249_ioctl);
-	up(&t->lock);
+	mutex_unlock(&t->lock);
 	return err;
 }
 
diff -urN oldtree/drivers/media/video/saa7134/saa7134-alsa.c newtree/drivers/media/video/saa7134/saa7134-alsa.c
--- oldtree/drivers/media/video/saa7134/saa7134-alsa.c	2006-02-19 11:41:02.962892672 +0000
+++ newtree/drivers/media/video/saa7134/saa7134-alsa.c	2006-02-21 15:58:13.628074776 +0000
@@ -69,7 +69,7 @@
  */
 
 typedef struct snd_card_saa7134 {
-	snd_card_t *card;
+	struct snd_card *card;
 	spinlock_t mixer_lock;
 	int mixer_volume[MIXER_ADDR_LAST+1][2];
 	int capture_source[MIXER_ADDR_LAST+1][2];
@@ -93,10 +93,10 @@
 
 	spinlock_t lock;
 
-	snd_pcm_substream_t *substream;
+	struct snd_pcm_substream *substream;
 } snd_card_saa7134_pcm_t;
 
-static snd_card_t *snd_saa7134_cards[SNDRV_CARDS];
+static struct snd_card *snd_saa7134_cards[SNDRV_CARDS];
 
 
 /*
@@ -249,10 +249,10 @@
  *
  */
 
-static int snd_card_saa7134_capture_trigger(snd_pcm_substream_t * substream,
+static int snd_card_saa7134_capture_trigger(struct snd_pcm_substream * substream,
 					  int cmd)
 {
-	snd_pcm_runtime_t *runtime = substream->runtime;
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_card_saa7134_pcm_t *pcm = runtime->private_data;
 	struct saa7134_dev *dev=pcm->dev;
 	int err = 0;
@@ -331,9 +331,9 @@
  *
  */
 
-static int snd_card_saa7134_capture_prepare(snd_pcm_substream_t * substream)
+static int snd_card_saa7134_capture_prepare(struct snd_pcm_substream * substream)
 {
-	snd_pcm_runtime_t *runtime = substream->runtime;
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	int bswap, sign;
 	u32 fmt, control;
 	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
@@ -420,9 +420,10 @@
  *
  */
 
-static snd_pcm_uframes_t snd_card_saa7134_capture_pointer(snd_pcm_substream_t * substream)
+static snd_pcm_uframes_t
+snd_card_saa7134_capture_pointer(struct snd_pcm_substream * substream)
 {
-	snd_pcm_runtime_t *runtime = substream->runtime;
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_card_saa7134_pcm_t *pcm = runtime->private_data;
 	struct saa7134_dev *dev=pcm->dev;
 
@@ -440,7 +441,7 @@
  * ALSA hardware capabilities definition
  */
 
-static snd_pcm_hardware_t snd_card_saa7134_capture =
+static struct snd_pcm_hardware snd_card_saa7134_capture =
 {
 	.info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -463,7 +464,7 @@
 	.periods_max =		1024,
 };
 
-static void snd_card_saa7134_runtime_free(snd_pcm_runtime_t *runtime)
+static void snd_card_saa7134_runtime_free(struct snd_pcm_runtime *runtime)
 {
 	snd_card_saa7134_pcm_t *pcm = runtime->private_data;
 
@@ -480,8 +481,8 @@
  *
  */
 
-static int snd_card_saa7134_hw_params(snd_pcm_substream_t * substream,
-				    snd_pcm_hw_params_t * hw_params)
+static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
+				      struct snd_pcm_hw_params * hw_params)
 {
 	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
 	struct saa7134_dev *dev;
@@ -560,7 +561,7 @@
  *
  */
 
-static int snd_card_saa7134_hw_free(snd_pcm_substream_t * substream)
+static int snd_card_saa7134_hw_free(struct snd_pcm_substream * substream)
 {
 	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
 	struct saa7134_dev *dev;
@@ -586,7 +587,7 @@
  *
  */
 
-static int snd_card_saa7134_capture_close(snd_pcm_substream_t * substream)
+static int snd_card_saa7134_capture_close(struct snd_pcm_substream * substream)
 {
 	return 0;
 }
@@ -601,20 +602,20 @@
  *
  */
 
-static int snd_card_saa7134_capture_open(snd_pcm_substream_t * substream)
+static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream)
 {
-	snd_pcm_runtime_t *runtime = substream->runtime;
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_card_saa7134_pcm_t *pcm;
 	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
 	struct saa7134_dev *dev = saa7134->dev;
 	int err;
 
-	down(&dev->dmasound.lock);
+	mutex_lock(&dev->dmasound.lock);
 
 	dev->dmasound.read_count  = 0;
 	dev->dmasound.read_offset = 0;
 
-	up(&dev->dmasound.lock);
+	mutex_unlock(&dev->dmasound.lock);
 
 	pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
 	if (pcm == NULL)
@@ -639,7 +640,7 @@
  * ALSA capture callbacks definition
  */
 
-static snd_pcm_ops_t snd_card_saa7134_capture_ops = {
+static struct snd_pcm_ops snd_card_saa7134_capture_ops = {
 	.open =			snd_card_saa7134_capture_open,
 	.close =		snd_card_saa7134_capture_close,
 	.ioctl =		snd_pcm_lib_ioctl,
@@ -660,7 +661,7 @@
 
 static int snd_card_saa7134_pcm(snd_card_saa7134_t *saa7134, int device)
 {
-	snd_pcm_t *pcm;
+	struct snd_pcm *pcm;
 	int err;
 
 	if ((err = snd_pcm_new(saa7134->card, "SAA7134 PCM", device, 0, 1, &pcm)) < 0)
@@ -678,7 +679,8 @@
   .get = snd_saa7134_volume_get, .put = snd_saa7134_volume_put, \
   .private_value = addr }
 
-static int snd_saa7134_volume_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
+static int snd_saa7134_volume_info(struct snd_kcontrol * kcontrol,
+				   struct snd_ctl_elem_info * uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	uinfo->count = 2;
@@ -687,7 +689,8 @@
 	return 0;
 }
 
-static int snd_saa7134_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int snd_saa7134_volume_get(struct snd_kcontrol * kcontrol,
+				  struct snd_ctl_elem_value * ucontrol)
 {
 	snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
 	int addr = kcontrol->private_value;
@@ -697,7 +700,8 @@
 	return 0;
 }
 
-static int snd_saa7134_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int snd_saa7134_volume_put(struct snd_kcontrol * kcontrol,
+				  struct snd_ctl_elem_value * ucontrol)
 {
 	snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
 	int change, addr = kcontrol->private_value;
@@ -728,7 +732,8 @@
   .get = snd_saa7134_capsrc_get, .put = snd_saa7134_capsrc_put, \
   .private_value = addr }
 
-static int snd_saa7134_capsrc_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
+static int snd_saa7134_capsrc_info(struct snd_kcontrol * kcontrol,
+				   struct snd_ctl_elem_info * uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 	uinfo->count = 2;
@@ -737,7 +742,8 @@
 	return 0;
 }
 
-static int snd_saa7134_capsrc_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int snd_saa7134_capsrc_get(struct snd_kcontrol * kcontrol,
+				  struct snd_ctl_elem_value * ucontrol)
 {
 	snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
 	int addr = kcontrol->private_value;
@@ -750,7 +756,8 @@
 	return 0;
 }
 
-static int snd_saa7134_capsrc_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int snd_saa7134_capsrc_put(struct snd_kcontrol * kcontrol,
+				  struct snd_ctl_elem_value * ucontrol)
 {
 	snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
 	int change, addr = kcontrol->private_value;
@@ -827,7 +834,7 @@
 	return change;
 }
 
-static snd_kcontrol_new_t snd_saa7134_controls[] = {
+static struct snd_kcontrol_new snd_saa7134_controls[] = {
 SAA713x_VOLUME("Video Volume", 0, MIXER_ADDR_TVTUNER),
 SAA713x_CAPSRC("Video Capture Switch", 0, MIXER_ADDR_TVTUNER),
 SAA713x_VOLUME("Line Volume", 1, MIXER_ADDR_LINE1),
@@ -846,7 +853,7 @@
 
 static int snd_card_saa7134_new_mixer(snd_card_saa7134_t * chip)
 {
-	snd_card_t *card = chip->card;
+	struct snd_card *card = chip->card;
 	unsigned int idx;
 	int err;
 
@@ -860,7 +867,7 @@
 	return 0;
 }
 
-static void snd_saa7134_free(snd_card_t * card)
+static void snd_saa7134_free(struct snd_card * card)
 {
 	snd_card_saa7134_t *chip = card->private_data;
 
@@ -887,7 +894,7 @@
 static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
 {
 
-	snd_card_t *card;
+	struct snd_card *card;
 	snd_card_saa7134_t *chip;
 	int err;
 
@@ -932,7 +939,7 @@
 
 	chip->irq = dev->pci->irq;
 
-	init_MUTEX(&dev->dmasound.lock);
+	mutex_init(&dev->dmasound.lock);
 
 	if ((err = snd_card_saa7134_new_mixer(chip)) < 0)
 		goto __nodev;
diff -urN oldtree/drivers/media/video/saa7134/saa7134-core.c newtree/drivers/media/video/saa7134/saa7134-core.c
--- oldtree/drivers/media/video/saa7134/saa7134-core.c	2006-02-19 11:41:02.965892216 +0000
+++ newtree/drivers/media/video/saa7134/saa7134-core.c	2006-02-21 15:58:13.629074624 +0000
@@ -613,7 +613,7 @@
 
 	saa_writel(SAA7134_IRQ1, 0);
 	saa_writel(SAA7134_IRQ2, 0);
-	init_MUTEX(&dev->lock);
+	mutex_init(&dev->lock);
 	spin_lock_init(&dev->slock);
 
 	saa7134_track_gpio(dev,"pre-init");
diff -urN oldtree/drivers/media/video/saa7134/saa7134-empress.c newtree/drivers/media/video/saa7134/saa7134-empress.c
--- oldtree/drivers/media/video/saa7134/saa7134-empress.c	2006-02-19 11:41:02.966892064 +0000
+++ newtree/drivers/media/video/saa7134/saa7134-empress.c	2006-02-21 15:58:13.630074472 +0000
@@ -89,7 +89,7 @@
 
 	dprintk("open minor=%d\n",minor);
 	err = -EBUSY;
-	if (down_trylock(&dev->empress_tsq.lock))
+	if (!mutex_trylock(&dev->empress_tsq.lock))
 		goto done;
 	if (dev->empress_users)
 		goto done_up;
@@ -99,7 +99,7 @@
 	err = 0;
 
 done_up:
-	up(&dev->empress_tsq.lock);
+	mutex_unlock(&dev->empress_tsq.lock);
 done:
 	return err;
 }
@@ -110,7 +110,7 @@
 
 	if (dev->empress_tsq.streaming)
 		videobuf_streamoff(&dev->empress_tsq);
-	down(&dev->empress_tsq.lock);
+	mutex_lock(&dev->empress_tsq.lock);
 	if (dev->empress_tsq.reading)
 		videobuf_read_stop(&dev->empress_tsq);
 	videobuf_mmap_free(&dev->empress_tsq);
@@ -119,7 +119,7 @@
 	/* stop the encoder */
 	ts_reset_encoder(dev);
 
-	up(&dev->empress_tsq.lock);
+	mutex_unlock(&dev->empress_tsq.lock);
 	return 0;
 }
 
diff -urN oldtree/drivers/media/video/saa7134/saa7134-oss.c newtree/drivers/media/video/saa7134/saa7134-oss.c
--- oldtree/drivers/media/video/saa7134/saa7134-oss.c	2006-02-19 11:41:02.968891760 +0000
+++ newtree/drivers/media/video/saa7134/saa7134-oss.c	2006-02-21 15:58:13.632074168 +0000
@@ -254,7 +254,7 @@
 	if (NULL == dev)
 		return -ENODEV;
 
-	down(&dev->dmasound.lock);
+	mutex_lock(&dev->dmasound.lock);
 	err = -EBUSY;
 	if (dev->dmasound.users_dsp)
 		goto fail1;
@@ -270,13 +270,13 @@
 	if (0 != err)
 		goto fail2;
 
-	up(&dev->dmasound.lock);
+	mutex_unlock(&dev->dmasound.lock);
 	return 0;
 
  fail2:
 	dev->dmasound.users_dsp--;
  fail1:
-	up(&dev->dmasound.lock);
+	mutex_unlock(&dev->dmasound.lock);
 	return err;
 }
 
@@ -284,13 +284,13 @@
 {
 	struct saa7134_dev *dev = file->private_data;
 
-	down(&dev->dmasound.lock);
+	mutex_lock(&dev->dmasound.lock);
 	if (dev->dmasound.recording_on)
 		dsp_rec_stop(dev);
 	dsp_buffer_free(dev);
 	dev->dmasound.users_dsp--;
 	file->private_data = NULL;
-	up(&dev->dmasound.lock);
+	mutex_unlock(&dev->dmasound.lock);
 	return 0;
 }
 
@@ -304,7 +304,7 @@
 	int err,ret = 0;
 
 	add_wait_queue(&dev->dmasound.wq, &wait);
-	down(&dev->dmasound.lock);
+	mutex_lock(&dev->dmasound.lock);
 	while (count > 0) {
 		/* wait for data if needed */
 		if (0 == dev->dmasound.read_count) {
@@ -328,12 +328,12 @@
 					ret = -EAGAIN;
 				break;
 			}
-			up(&dev->dmasound.lock);
+			mutex_unlock(&dev->dmasound.lock);
 			set_current_state(TASK_INTERRUPTIBLE);
 			if (0 == dev->dmasound.read_count)
 				schedule();
 			set_current_state(TASK_RUNNING);
-			down(&dev->dmasound.lock);
+			mutex_lock(&dev->dmasound.lock);
 			if (signal_pending(current)) {
 				if (0 == ret)
 					ret = -EINTR;
@@ -362,7 +362,7 @@
 		if (dev->dmasound.read_offset == dev->dmasound.bufsize)
 			dev->dmasound.read_offset = 0;
 	}
-	up(&dev->dmasound.lock);
+	mutex_unlock(&dev->dmasound.lock);
 	remove_wait_queue(&dev->dmasound.wq, &wait);
 	return ret;
 }
@@ -435,13 +435,13 @@
 	case SNDCTL_DSP_STEREO:
 		if (get_user(val, p))
 			return -EFAULT;
-		down(&dev->dmasound.lock);
+		mutex_lock(&dev->dmasound.lock);
 		dev->dmasound.channels = val ? 2 : 1;
 		if (dev->dmasound.recording_on) {
 			dsp_rec_stop(dev);
 			dsp_rec_start(dev);
 		}
-		up(&dev->dmasound.lock);
+		mutex_unlock(&dev->dmasound.lock);
 		return put_user(dev->dmasound.channels-1, p);
 
 	case SNDCTL_DSP_CHANNELS:
@@ -449,13 +449,13 @@
 			return -EFAULT;
 		if (val != 1 && val != 2)
 			return -EINVAL;
-		down(&dev->dmasound.lock);
+		mutex_lock(&dev->dmasound.lock);
 		dev->dmasound.channels = val;
 		if (dev->dmasound.recording_on) {
 			dsp_rec_stop(dev);
 			dsp_rec_start(dev);
 		}
-		up(&dev->dmasound.lock);
+		mutex_unlock(&dev->dmasound.lock);
 		/* fall through */
 	case SOUND_PCM_READ_CHANNELS:
 		return put_user(dev->dmasound.channels, p);
@@ -478,13 +478,13 @@
 		case AFMT_U16_BE:
 		case AFMT_S16_LE:
 		case AFMT_S16_BE:
-			down(&dev->dmasound.lock);
+			mutex_lock(&dev->dmasound.lock);
 			dev->dmasound.afmt = val;
 			if (dev->dmasound.recording_on) {
 				dsp_rec_stop(dev);
 				dsp_rec_start(dev);
 			}
-			up(&dev->dmasound.lock);
+			mutex_unlock(&dev->dmasound.lock);
 			return put_user(dev->dmasound.afmt, p);
 		default:
 			return -EINVAL;
@@ -509,10 +509,10 @@
 		return 0;
 
 	case SNDCTL_DSP_RESET:
-		down(&dev->dmasound.lock);
+		mutex_lock(&dev->dmasound.lock);
 		if (dev->dmasound.recording_on)
 			dsp_rec_stop(dev);
-		up(&dev->dmasound.lock);
+		mutex_unlock(&dev->dmasound.lock);
 		return 0;
 	case SNDCTL_DSP_GETBLKSIZE:
 		return put_user(dev->dmasound.blksize, p);
@@ -556,10 +556,10 @@
 	poll_wait(file, &dev->dmasound.wq, wait);
 
 	if (0 == dev->dmasound.read_count) {
-		down(&dev->dmasound.lock);
+		mutex_lock(&dev->dmasound.lock);
 		if (!dev->dmasound.recording_on)
 			dsp_rec_start(dev);
-		up(&dev->dmasound.lock);
+		mutex_unlock(&dev->dmasound.lock);
 	} else
 		mask |= (POLLIN | POLLRDNORM);
 	return mask;
@@ -852,7 +852,7 @@
 		return -1;
 
 	/* general */
-	init_MUTEX(&dev->dmasound.lock);
+	mutex_init(&dev->dmasound.lock);
 	init_waitqueue_head(&dev->dmasound.wq);
 
 	switch (dev->pci->device) {
diff -urN oldtree/drivers/media/video/saa7134/saa7134-video.c newtree/drivers/media/video/saa7134/saa7134-video.c
--- oldtree/drivers/media/video/saa7134/saa7134-video.c	2006-02-19 11:41:02.971891304 +0000
+++ newtree/drivers/media/video/saa7134/saa7134-video.c	2006-02-21 15:58:13.634073864 +0000
@@ -460,17 +460,17 @@
 		return 1;
 
 	/* is it free? */
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	if (dev->resources & bit) {
 		/* no, someone else uses it */
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		return 0;
 	}
 	/* it's free, grab it */
 	fh->resources  |= bit;
 	dev->resources |= bit;
 	dprintk("res: get %d\n",bit);
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 	return 1;
 }
 
@@ -492,11 +492,11 @@
 	if ((fh->resources & bits) != bits)
 		BUG();
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	fh->resources  &= ~bits;
 	dev->resources &= ~bits;
 	dprintk("res: put %d\n",bits);
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 }
 
 /* ------------------------------------------------------------------ */
@@ -1340,21 +1340,21 @@
 		if (!list_empty(&fh->cap.stream))
 			buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream);
 	} else {
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		if (UNSET == fh->cap.read_off) {
 			/* need to capture a new frame */
 			if (res_locked(fh->dev,RESOURCE_VIDEO)) {
-				up(&fh->cap.lock);
+				mutex_unlock(&fh->cap.lock);
 				return POLLERR;
 			}
 			if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) {
-				up(&fh->cap.lock);
+				mutex_unlock(&fh->cap.lock);
 				return POLLERR;
 			}
 			fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
 			fh->cap.read_off = 0;
 		}
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 		buf = fh->cap.read_buf;
 	}
 
@@ -1561,14 +1561,14 @@
 		if (0 != err)
 			return err;
 
-		down(&dev->lock);
+		mutex_lock(&dev->lock);
 		fh->win    = f->fmt.win;
 		fh->nclips = f->fmt.win.clipcount;
 		if (fh->nclips > 8)
 			fh->nclips = 8;
 		if (copy_from_user(fh->clips,f->fmt.win.clips,
 				   sizeof(struct v4l2_clip)*fh->nclips)) {
-			up(&dev->lock);
+			mutex_unlock(&dev->lock);
 			return -EFAULT;
 		}
 
@@ -1578,7 +1578,7 @@
 			start_preview(dev,fh);
 			spin_unlock_irqrestore(&dev->slock,flags);
 		}
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		return 0;
 	case V4L2_BUF_TYPE_VBI_CAPTURE:
 		saa7134_vbi_fmt(dev,f);
@@ -1612,9 +1612,9 @@
 		return get_control(dev,arg);
 	case VIDIOC_S_CTRL:
 	{
-		down(&dev->lock);
+		mutex_lock(&dev->lock);
 		err = set_control(dev,NULL,arg);
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		return err;
 	}
 	/* --- input switching --------------------------------------- */
@@ -1664,9 +1664,9 @@
 			return -EINVAL;
 		if (NULL == card_in(dev,*i).name)
 			return -EINVAL;
-		down(&dev->lock);
+		mutex_lock(&dev->lock);
 		video_mux(dev,*i);
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		return 0;
 	}
 
@@ -1766,7 +1766,7 @@
 		if (i == TVNORMS)
 			return -EINVAL;
 
-		down(&dev->lock);
+		mutex_lock(&dev->lock);
 		if (res_check(fh, RESOURCE_OVERLAY)) {
 			spin_lock_irqsave(&dev->slock,flags);
 			stop_preview(dev,fh);
@@ -1776,7 +1776,7 @@
 		} else
 			set_tvnorm(dev,&tvnorms[i]);
 		saa7134_tvaudio_do_scan(dev);
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		return 0;
 	}
 
@@ -1909,13 +1909,13 @@
 			return -EINVAL;
 		if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
 			return -EINVAL;
-		down(&dev->lock);
+		mutex_lock(&dev->lock);
 		dev->ctl_freq = f->frequency;
 
 		saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f);
 
 		saa7134_tvaudio_do_scan(dev);
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		return 0;
 	}
 
diff -urN oldtree/drivers/media/video/saa7134/saa7134.h newtree/drivers/media/video/saa7134/saa7134.h
--- oldtree/drivers/media/video/saa7134/saa7134.h	2006-02-19 11:41:02.972891152 +0000
+++ newtree/drivers/media/video/saa7134/saa7134.h	2006-02-21 15:58:13.631074320 +0000
@@ -29,6 +29,7 @@
 #include <linux/input.h>
 #include <linux/notifier.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
 
 #include <asm/io.h>
 
@@ -359,7 +360,7 @@
 
 /* dmasound dsp status */
 struct saa7134_dmasound {
-	struct semaphore           lock;
+	struct mutex               lock;
 	int                        minor_mixer;
 	int                        minor_dsp;
 	unsigned int               users_dsp;
@@ -386,7 +387,7 @@
 	unsigned int               read_offset;
 	unsigned int               read_count;
 	void *			   priv_data;
-	snd_pcm_substream_t 	   *substream;
+	struct snd_pcm_substream   *substream;
 };
 
 /* IR input */
@@ -423,7 +424,7 @@
 /* global device status */
 struct saa7134_dev {
 	struct list_head           devlist;
-	struct semaphore           lock;
+	struct mutex               lock;
 	spinlock_t                 slock;
 #ifdef VIDIOC_G_PRIORITY
 	struct v4l2_prio_state     prio;
diff -urN oldtree/drivers/media/video/video-buf-dvb.c newtree/drivers/media/video/video-buf-dvb.c
--- oldtree/drivers/media/video/video-buf-dvb.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/media/video/video-buf-dvb.c	2006-02-21 15:58:13.647071888 +0000
@@ -96,7 +96,7 @@
 	if (!demux->dmx.frontend)
 		return -EINVAL;
 
-	down(&dvb->lock);
+	mutex_lock(&dvb->lock);
 	dvb->nfeeds++;
 	rc = dvb->nfeeds;
 
@@ -110,7 +110,7 @@
 	}
 
 out:
-	up(&dvb->lock);
+	mutex_unlock(&dvb->lock);
 	return rc;
 }
 
@@ -120,14 +120,14 @@
 	struct videobuf_dvb *dvb = demux->priv;
 	int err = 0;
 
-	down(&dvb->lock);
+	mutex_lock(&dvb->lock);
 	dvb->nfeeds--;
 	if (0 == dvb->nfeeds  &&  NULL != dvb->thread) {
 		// FIXME: cx8802_cancel_buffers(dev);
 		err = kthread_stop(dvb->thread);
 		dvb->thread = NULL;
 	}
-	up(&dvb->lock);
+	mutex_unlock(&dvb->lock);
 	return err;
 }
 
@@ -139,7 +139,7 @@
 {
 	int result;
 
-	init_MUTEX(&dvb->lock);
+	mutex_init(&dvb->lock);
 
 	/* register adapter */
 	result = dvb_register_adapter(&dvb->adapter, dvb->name, module);
diff -urN oldtree/drivers/media/video/video-buf.c newtree/drivers/media/video/video-buf.c
--- oldtree/drivers/media/video/video-buf.c	2006-02-19 11:41:03.016884464 +0000
+++ newtree/drivers/media/video/video-buf.c	2006-02-21 15:58:13.640072952 +0000
@@ -385,7 +385,7 @@
 	q->ops     = ops;
 	q->priv_data = priv;
 
-	init_MUTEX(&q->lock);
+	mutex_init(&q->lock);
 	INIT_LIST_HEAD(&q->stream);
 }
 
@@ -549,7 +549,7 @@
 	if (!list_empty(&q->stream))
 		return -EBUSY;
 
-	down(&q->lock);
+	mutex_lock(&q->lock);
 	count = req->count;
 	if (count > VIDEO_MAX_FRAME)
 		count = VIDEO_MAX_FRAME;
@@ -566,7 +566,7 @@
 	req->count = count;
 
  done:
-	up(&q->lock);
+	mutex_unlock(&q->lock);
 	return retval;
 }
 
@@ -592,7 +592,7 @@
 	unsigned long flags;
 	int retval;
 
-	down(&q->lock);
+	mutex_lock(&q->lock);
 	retval = -EBUSY;
 	if (q->reading)
 		goto done;
@@ -652,7 +652,7 @@
 	retval = 0;
 
  done:
-	up(&q->lock);
+	mutex_unlock(&q->lock);
 	return retval;
 }
 
@@ -663,7 +663,7 @@
 	struct videobuf_buffer *buf;
 	int retval;
 
-	down(&q->lock);
+	mutex_lock(&q->lock);
 	retval = -EBUSY;
 	if (q->reading)
 		goto done;
@@ -693,7 +693,7 @@
 	videobuf_status(b,buf,q->type);
 
  done:
-	up(&q->lock);
+	mutex_unlock(&q->lock);
 	return retval;
 }
 
@@ -704,7 +704,7 @@
 	unsigned long flags;
 	int retval;
 
-	down(&q->lock);
+	mutex_lock(&q->lock);
 	retval = -EBUSY;
 	if (q->reading)
 		goto done;
@@ -721,7 +721,7 @@
 	spin_unlock_irqrestore(q->irqlock,flags);
 
  done:
-	up(&q->lock);
+	mutex_unlock(&q->lock);
 	return retval;
 }
 
@@ -729,7 +729,7 @@
 {
 	int retval = -EINVAL;
 
-	down(&q->lock);
+	mutex_lock(&q->lock);
 	if (!q->streaming)
 		goto done;
 	videobuf_queue_cancel(q);
@@ -737,7 +737,7 @@
 	retval = 0;
 
  done:
-	up(&q->lock);
+	mutex_unlock(&q->lock);
 	return retval;
 }
 
@@ -792,7 +792,7 @@
 	unsigned size, nbufs, bytes;
 	int retval;
 
-	down(&q->lock);
+	mutex_lock(&q->lock);
 
 	nbufs = 1; size = 0;
 	q->ops->buf_setup(q,&nbufs,&size);
@@ -860,7 +860,7 @@
 	}
 
  done:
-	up(&q->lock);
+	mutex_unlock(&q->lock);
 	return retval;
 }
 
@@ -922,7 +922,7 @@
 	unsigned long flags;
 
 	dprintk(2,"%s\n",__FUNCTION__);
-	down(&q->lock);
+	mutex_lock(&q->lock);
 	retval = -EBUSY;
 	if (q->streaming)
 		goto done;
@@ -996,7 +996,7 @@
 	}
 
  done:
-	up(&q->lock);
+	mutex_unlock(&q->lock);
 	return retval;
 }
 
@@ -1007,7 +1007,7 @@
 	struct videobuf_buffer *buf = NULL;
 	unsigned int rc = 0;
 
-	down(&q->lock);
+	mutex_lock(&q->lock);
 	if (q->streaming) {
 		if (!list_empty(&q->stream))
 			buf = list_entry(q->stream.next,
@@ -1035,7 +1035,7 @@
 		    buf->state == STATE_ERROR)
 			rc = POLLIN|POLLRDNORM;
 	}
-	up(&q->lock);
+	mutex_unlock(&q->lock);
 	return rc;
 }
 
@@ -1064,7 +1064,7 @@
 	map->count--;
 	if (0 == map->count) {
 		dprintk(1,"munmap %p q=%p\n",map,q);
-		down(&q->lock);
+		mutex_lock(&q->lock);
 		for (i = 0; i < VIDEO_MAX_FRAME; i++) {
 			if (NULL == q->bufs[i])
 				continue;
@@ -1076,7 +1076,7 @@
 			q->bufs[i]->baddr = 0;
 			q->ops->buf_release(q,q->bufs[i]);
 		}
-		up(&q->lock);
+		mutex_unlock(&q->lock);
 		kfree(map);
 	}
 	return;
@@ -1170,7 +1170,7 @@
 	unsigned int first,last,size,i;
 	int retval;
 
-	down(&q->lock);
+	mutex_lock(&q->lock);
 	retval = -EINVAL;
 	if (!(vma->vm_flags & VM_WRITE)) {
 		dprintk(1,"mmap app bug: PROT_WRITE please\n");
@@ -1238,7 +1238,7 @@
 	retval = 0;
 
  done:
-	up(&q->lock);
+	mutex_unlock(&q->lock);
 	return retval;
 }
 
diff -urN oldtree/drivers/media/video/videodev.c newtree/drivers/media/video/videodev.c
--- oldtree/drivers/media/video/videodev.c	2006-02-19 11:41:03.018884160 +0000
+++ newtree/drivers/media/video/videodev.c	2006-02-21 15:58:13.648071736 +0000
@@ -224,13 +224,13 @@
 	struct  video_device *vfl = video_devdata(file);
 	int retval = 0;
 
-	down(&vfl->lock);
+	mutex_lock(&vfl->lock);
 	if (vfl->users) {
 		retval = -EBUSY;
 	} else {
 		vfl->users++;
 	}
-	up(&vfl->lock);
+	mutex_unlock(&vfl->lock);
 	return retval;
 }
 
@@ -328,7 +328,7 @@
 	sprintf(vfd->devfs_name, "v4l/%s%d", name_base, i - base);
 	devfs_mk_cdev(MKDEV(VIDEO_MAJOR, vfd->minor),
 			S_IFCHR | S_IRUSR | S_IWUSR, vfd->devfs_name);
-	init_MUTEX(&vfd->lock);
+	mutex_init(&vfd->lock);
 
 	/* sysfs class */
 	memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev));
diff -urN oldtree/drivers/media/video/vino.c newtree/drivers/media/video/vino.c
--- oldtree/drivers/media/video/vino.c	2006-02-19 11:41:03.019884008 +0000
+++ newtree/drivers/media/video/vino.c	2006-02-21 15:58:13.650071432 +0000
@@ -42,6 +42,7 @@
 #include <linux/videodev.h>
 #include <linux/videodev2.h>
 #include <linux/video_decoder.h>
+#include <linux/mutex.h>
 
 #include <asm/paccess.h>
 #include <asm/io.h>
@@ -245,7 +246,7 @@
 	struct vino_framebuffer *buffer[VINO_FRAMEBUFFER_COUNT_MAX];
 
 	spinlock_t queue_lock;
-	struct semaphore queue_sem;
+	struct mutex queue_mutex;
 	wait_queue_head_t frame_wait_queue;
 };
 
@@ -283,7 +284,7 @@
 	/* the driver is currently processing the queue */
 	int capturing;
 
-	struct semaphore sem;
+	struct mutex mutex;
 	spinlock_t capture_lock;
 
 	unsigned int users;
@@ -1131,11 +1132,11 @@
 	if (q->type != VINO_MEMORY_MMAP)
 		return;
 
-	down(&q->queue_sem);
+	mutex_lock(&q->queue_mutex);
 
 	vino_queue_free_with_count(q, q->length);
 
-	up(&q->queue_sem);
+	mutex_unlock(&q->queue_mutex);
 }
 
 static int vino_queue_init(struct vino_framebuffer_queue *q,
@@ -1159,7 +1160,7 @@
 	if (*length < 1)
 		return -EINVAL;
 
-	down(&q->queue_sem);
+	mutex_lock(&q->queue_mutex);
 
 	if (*length > VINO_FRAMEBUFFER_COUNT_MAX)
 		*length = VINO_FRAMEBUFFER_COUNT_MAX;
@@ -1211,7 +1212,7 @@
 		q->magic = VINO_QUEUE_MAGIC;
 	}
 
-	up(&q->queue_sem);
+	mutex_unlock(&q->queue_mutex);
 
 	return ret;
 }
@@ -4045,7 +4046,7 @@
 	dprintk("open(): channel = %c\n",
 	       (vcs->channel == VINO_CHANNEL_A) ? 'A' : 'B');
 
-	down(&vcs->sem);
+	mutex_lock(&vcs->mutex);
 
 	if (vcs->users) {
 		dprintk("open(): driver busy\n");
@@ -4062,7 +4063,7 @@
 	vcs->users++;
 
  out:
-	up(&vcs->sem);
+	mutex_unlock(&vcs->mutex);
 
 	dprintk("open(): %s!\n", ret ? "failed" : "complete");
 
@@ -4075,7 +4076,7 @@
 	struct vino_channel_settings *vcs = video_get_drvdata(dev);
 	dprintk("close():\n");
 
-	down(&vcs->sem);
+	mutex_lock(&vcs->mutex);
 
 	vcs->users--;
 
@@ -4087,7 +4088,7 @@
 		vino_queue_free(&vcs->fb_queue);
 	}
 
-	up(&vcs->sem);
+	mutex_unlock(&vcs->mutex);
 
 	return 0;
 }
@@ -4130,7 +4131,7 @@
 
 	// TODO: reject mmap if already mapped
 
-	if (down_interruptible(&vcs->sem))
+	if (mutex_lock_interruptible(&vcs->mutex))
 		return -EINTR;
 
 	if (vcs->reading) {
@@ -4214,7 +4215,7 @@
 	vma->vm_ops = &vino_vm_ops;
 
 out:
-	up(&vcs->sem);
+	mutex_unlock(&vcs->mutex);
 
 	return ret;
 }
@@ -4374,12 +4375,12 @@
 	struct vino_channel_settings *vcs = video_get_drvdata(dev);
 	int ret;
 
-	if (down_interruptible(&vcs->sem))
+	if (mutex_lock_interruptible(&vcs->mutex))
 		return -EINTR;
 
 	ret = video_usercopy(inode, file, cmd, arg, vino_do_ioctl);
 
-	up(&vcs->sem);
+	mutex_unlock(&vcs->mutex);
 
 	return ret;
 }
@@ -4564,10 +4565,10 @@
 
 	vcs->capturing = 0;
 
-	init_MUTEX(&vcs->sem);
+	mutex_init(&vcs->mutex);
 	spin_lock_init(&vcs->capture_lock);
 
-	init_MUTEX(&vcs->fb_queue.queue_sem);
+	mutex_init(&vcs->fb_queue.queue_mutex);
 	spin_lock_init(&vcs->fb_queue.queue_lock);
 	init_waitqueue_head(&vcs->fb_queue.frame_wait_queue);
 
diff -urN oldtree/drivers/media/video/zoran.h newtree/drivers/media/video/zoran.h
--- oldtree/drivers/media/video/zoran.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/media/video/zoran.h	2006-02-21 15:58:16.734602512 +0000
@@ -395,7 +395,7 @@
 	struct videocodec *codec;	/* video codec */
 	struct videocodec *vfe;	/* video front end */
 
-	struct semaphore resource_lock;	/* prevent evil stuff */
+	struct mutex resource_lock;	/* prevent evil stuff */
 
 	u8 initialized;		/* flag if zoran has been correctly initalized */
 	int user;		/* number of current users */
diff -urN oldtree/drivers/media/video/zoran_card.c newtree/drivers/media/video/zoran_card.c
--- oldtree/drivers/media/video/zoran_card.c	2006-02-19 11:41:03.023883400 +0000
+++ newtree/drivers/media/video/zoran_card.c	2006-02-21 15:58:16.715605400 +0000
@@ -47,6 +47,7 @@
 #include <linux/interrupt.h>
 #include <linux/video_decoder.h>
 #include <linux/video_encoder.h>
+#include <linux/mutex.h>
 
 #include <asm/io.h>
 
@@ -673,7 +674,7 @@
 		KERN_DEBUG "%s: i2c_client_register() - driver id = %d\n",
 		ZR_DEVNAME(zr), client->driver->id);
 
-	down(&zr->resource_lock);
+	mutex_lock(&zr->resource_lock);
 
 	if (zr->user > 0) {
 		/* we're already busy, so we keep a reference to
@@ -694,7 +695,7 @@
 	}
 
 clientreg_unlock_and_return:
-	up(&zr->resource_lock);
+	mutex_unlock(&zr->resource_lock);
 
 	return res;
 }
@@ -707,7 +708,7 @@
 
 	dprintk(2, KERN_DEBUG "%s: i2c_client_unregister()\n", ZR_DEVNAME(zr));
 
-	down(&zr->resource_lock);
+	mutex_lock(&zr->resource_lock);
 
 	if (zr->user > 0) {
 		res = -EBUSY;
@@ -722,7 +723,7 @@
 		snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%d]", zr->id);
 	}
 clientunreg_unlock_and_return:
-	up(&zr->resource_lock);
+	mutex_unlock(&zr->resource_lock);
 	return res;
 }
 
@@ -1206,7 +1207,7 @@
 		zr->id = zoran_num;
 		snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%u]", zr->id);
 		spin_lock_init(&zr->spinlock);
-		init_MUTEX(&zr->resource_lock);
+		mutex_init(&zr->resource_lock);
 		if (pci_enable_device(dev))
 			continue;
 		zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0);
diff -urN oldtree/drivers/media/video/zoran_driver.c newtree/drivers/media/video/zoran_driver.c
--- oldtree/drivers/media/video/zoran_driver.c	2006-02-19 11:41:03.025883096 +0000
+++ newtree/drivers/media/video/zoran_driver.c	2006-02-21 15:58:16.731602968 +0000
@@ -81,6 +81,7 @@
 
 #include <linux/video_decoder.h>
 #include <linux/video_encoder.h>
+#include <linux/mutex.h>
 #include "zoran.h"
 #include "zoran_device.h"
 #include "zoran_card.h"
@@ -1292,7 +1293,7 @@
 
 	/* see fs/device.c - the kernel already locks during open(),
 	 * so locking ourselves only causes deadlocks */
-	/*down(&zr->resource_lock);*/
+	/*mutex_lock(&zr->resource_lock);*/
 
 	if (!zr->decoder) {
 		dprintk(1,
@@ -1371,7 +1372,7 @@
 	if (zr->user++ == 0)
 		first_open = 1;
 
-	/*up(&zr->resource_lock);*/
+	/*mutex_unlock(&zr->resource_lock);*/
 
 	/* default setup - TODO: look at flags */
 	if (first_open) {	/* First device open */
@@ -1401,7 +1402,7 @@
 
 	/* if there's no device found, we didn't obtain the lock either */
 	if (zr) {
-		/*up(&zr->resource_lock);*/
+		/*mutex_unlock(&zr->resource_lock);*/
 	}
 
 	return res;
@@ -1419,7 +1420,7 @@
 
 	/* kernel locks (fs/device.c), so don't do that ourselves
 	 * (prevents deadlocks) */
-	/*down(&zr->resource_lock);*/
+	/*mutex_lock(&zr->resource_lock);*/
 
 	zoran_close_end_session(file);
 
@@ -1466,7 +1467,7 @@
 	}
 	module_put(THIS_MODULE);
 
-	/*up(&zr->resource_lock);*/
+	/*mutex_unlock(&zr->resource_lock);*/
 
 	dprintk(4, KERN_INFO "%s: zoran_close() done\n", ZR_DEVNAME(zr));
 
@@ -2027,14 +2028,14 @@
 	 * but moving the free code outside the munmap() handler fixes
 	 * all this... If someone knows why, please explain me (Ronald)
 	 */
-	if (!down_trylock(&zr->resource_lock)) {
+	if (!!mutex_trylock(&zr->resource_lock)) {
 		/* we obtained it! Let's try to free some things */
 		if (fh->jpg_buffers.ready_to_be_freed)
 			jpg_fbuffer_free(file);
 		if (fh->v4l_buffers.ready_to_be_freed)
 			v4l_fbuffer_free(file);
 
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 	}
 
 	switch (cmd) {
@@ -2051,12 +2052,12 @@
 
 		vcap->channels = zr->card.inputs;
 		vcap->audios = 0;
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		vcap->maxwidth = BUZ_MAX_WIDTH;
 		vcap->maxheight = BUZ_MAX_HEIGHT;
 		vcap->minwidth = BUZ_MIN_WIDTH;
 		vcap->minheight = BUZ_MIN_HEIGHT;
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return 0;
 	}
@@ -2084,9 +2085,9 @@
 		vchan->tuners = 0;
 		vchan->flags = 0;
 		vchan->type = VIDEO_TYPE_CAMERA;
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		vchan->norm = zr->norm;
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 		vchan->channel = channel;
 
 		return 0;
@@ -2113,7 +2114,7 @@
 			"%s: VIDIOCSCHAN - channel=%d, norm=%d\n",
 			ZR_DEVNAME(zr), vchan->channel, vchan->norm);
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		if ((res = zoran_set_input(zr, vchan->channel)))
 			goto schan_unlock_and_return;
 		if ((res = zoran_set_norm(zr, vchan->norm)))
@@ -2122,7 +2123,7 @@
 		/* Make sure the changes come into effect */
 		res = wait_grab_pending(zr);
 	schan_unlock_and_return:
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 		return res;
 	}
 		break;
@@ -2134,7 +2135,7 @@
 		dprintk(3, KERN_DEBUG "%s: VIDIOCGPICT\n", ZR_DEVNAME(zr));
 
 		memset(vpict, 0, sizeof(struct video_picture));
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		vpict->hue = zr->hue;
 		vpict->brightness = zr->brightness;
 		vpict->contrast = zr->contrast;
@@ -2145,7 +2146,7 @@
 		} else {
 			vpict->depth = 0;
 		}
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return 0;
 	}
@@ -2180,7 +2181,7 @@
 			return -EINVAL;
 		}
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 
 		decoder_command(zr, DECODER_SET_PICTURE, vpict);
 
@@ -2191,7 +2192,7 @@
 
 		fh->overlay_settings.format = &zoran_formats[i];
 
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return 0;
 	}
@@ -2204,9 +2205,9 @@
 		dprintk(3, KERN_DEBUG "%s: VIDIOCCAPTURE - on=%d\n",
 			ZR_DEVNAME(zr), *on);
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		res = setup_overlay(file, *on);
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return res;
 	}
@@ -2219,12 +2220,12 @@
 		dprintk(3, KERN_DEBUG "%s: VIDIOCGWIN\n", ZR_DEVNAME(zr));
 
 		memset(vwin, 0, sizeof(struct video_window));
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		vwin->x = fh->overlay_settings.x;
 		vwin->y = fh->overlay_settings.y;
 		vwin->width = fh->overlay_settings.width;
 		vwin->height = fh->overlay_settings.height;
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 		vwin->clipcount = 0;
 		return 0;
 	}
@@ -2241,12 +2242,12 @@
 			ZR_DEVNAME(zr), vwin->x, vwin->y, vwin->width,
 			vwin->height, vwin->clipcount);
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		res =
 		    setup_window(file, vwin->x, vwin->y, vwin->width,
 				 vwin->height, vwin->clips,
 				 vwin->clipcount, NULL);
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return res;
 	}
@@ -2258,9 +2259,9 @@
 
 		dprintk(3, KERN_DEBUG "%s: VIDIOCGFBUF\n", ZR_DEVNAME(zr));
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		*vbuf = zr->buffer;
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 		return 0;
 	}
 		break;
@@ -2287,12 +2288,12 @@
 			return -EINVAL;
 		}
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		res =
 		    setup_fbuffer(file, vbuf->base, &zoran_formats[i],
 				  vbuf->width, vbuf->height,
 				  vbuf->bytesperline);
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return res;
 	}
@@ -2305,9 +2306,9 @@
 		dprintk(3, KERN_DEBUG "%s: VIDIOCSYNC - frame=%d\n",
 			ZR_DEVNAME(zr), *frame);
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		res = v4l_sync(file, *frame);
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 		if (!res)
 			zr->v4l_sync_tail++;
 		return res;
@@ -2325,9 +2326,9 @@
 			ZR_DEVNAME(zr), vmap->frame, vmap->width, vmap->height,
 			vmap->format);
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		res = v4l_grab(file, vmap);
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 		return res;
 	}
 		break;
@@ -2348,7 +2349,7 @@
 			    i * fh->v4l_buffers.buffer_size;
 		}
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 
 		if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
 			dprintk(1,
@@ -2367,7 +2368,7 @@
 		/* The next mmap will map the V4L buffers */
 		fh->map_mode = ZORAN_MAP_MODE_RAW;
 	v4l1reqbuf_unlock_and_return:
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return res;
 	}
@@ -2421,7 +2422,7 @@
 		bparams->major_version = MAJOR_VERSION;
 		bparams->minor_version = MINOR_VERSION;
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 
 		bparams->norm = zr->norm;
 		bparams->input = zr->input;
@@ -2450,7 +2451,7 @@
 		bparams->jpeg_markers =
 		    fh->jpg_settings.jpg_comp.jpeg_markers;
 
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		bparams->VFIFO_FB = 0;
 
@@ -2486,7 +2487,7 @@
 		       sizeof(bparams->COM_data));
 		settings.jpg_comp.jpeg_markers = bparams->jpeg_markers;
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 
 		if (zr->codec_mode != BUZ_MODE_IDLE) {
 			dprintk(1,
@@ -2506,7 +2507,7 @@
 
 		fh->jpg_settings = settings;
 	sparams_unlock_and_return:
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return res;
 	}
@@ -2538,7 +2539,7 @@
 		    breq->size > MAX_KMALLOC_MEM)
 			breq->size = MAX_KMALLOC_MEM;
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 
 		if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
 			dprintk(1,
@@ -2561,7 +2562,7 @@
 		 * also be *_PLAY, but it doesn't matter here */
 		fh->map_mode = ZORAN_MAP_MODE_JPG_REC;
 	jpgreqbuf_unlock_and_return:
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return res;
 	}
@@ -2574,9 +2575,9 @@
 		dprintk(3, KERN_DEBUG "%s: BUZIOC_QBUF_CAPT - frame=%d\n",
 			ZR_DEVNAME(zr), *frame);
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_COMPRESS);
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return res;
 	}
@@ -2589,9 +2590,9 @@
 		dprintk(3, KERN_DEBUG "%s: BUZIOC_QBUF_PLAY - frame=%d\n",
 			ZR_DEVNAME(zr), *frame);
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_DECOMPRESS);
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return res;
 	}
@@ -2604,9 +2605,9 @@
 
 		dprintk(3, KERN_DEBUG "%s: BUZIOC_SYNC\n", ZR_DEVNAME(zr));
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		res = jpg_sync(file, bsync);
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return res;
 	}
@@ -2630,7 +2631,7 @@
 		input = zr->card.input[bstat->input].muxsel;
 		norm = VIDEO_MODE_AUTO;
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 
 		if (zr->codec_mode != BUZ_MODE_IDLE) {
 			dprintk(1,
@@ -2655,7 +2656,7 @@
 		decoder_command(zr, DECODER_SET_INPUT, &input);
 		decoder_command(zr, DECODER_SET_NORM, &zr->norm);
 	gstat_unlock_and_return:
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		if (!res) {
 			bstat->signal =
@@ -2763,7 +2764,7 @@
 		switch (fmt->type) {
 		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 
-			down(&zr->resource_lock);
+			mutex_lock(&zr->resource_lock);
 
 			fmt->fmt.win.w.left = fh->overlay_settings.x;
 			fmt->fmt.win.w.top = fh->overlay_settings.y;
@@ -2776,14 +2777,14 @@
 			else
 				fmt->fmt.win.field = V4L2_FIELD_TOP;
 
-			up(&zr->resource_lock);
+			mutex_unlock(&zr->resource_lock);
 
 			break;
 
 		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 
-			down(&zr->resource_lock);
+			mutex_lock(&zr->resource_lock);
 
 			if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
 			    fh->map_mode == ZORAN_MAP_MODE_RAW) {
@@ -2837,7 +2838,7 @@
 				    V4L2_COLORSPACE_SMPTE170M;
 			}
 
-			up(&zr->resource_lock);
+			mutex_unlock(&zr->resource_lock);
 
 			break;
 
@@ -2870,7 +2871,7 @@
 				fmt->fmt.win.w.height,
 				fmt->fmt.win.clipcount,
 				fmt->fmt.win.bitmap);
-			down(&zr->resource_lock);
+			mutex_lock(&zr->resource_lock);
 			res =
 			    setup_window(file, fmt->fmt.win.w.left,
 					 fmt->fmt.win.w.top,
@@ -2880,7 +2881,7 @@
 					   fmt->fmt.win.clips,
 					 fmt->fmt.win.clipcount,
 					 fmt->fmt.win.bitmap);
-			up(&zr->resource_lock);
+			mutex_unlock(&zr->resource_lock);
 			return res;
 			break;
 
@@ -2917,7 +2918,7 @@
 			}
 
 			if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) {
-				down(&zr->resource_lock);
+				mutex_lock(&zr->resource_lock);
 
 				settings = fh->jpg_settings;
 
@@ -2995,7 +2996,7 @@
 				    ZORAN_MAP_MODE_JPG_REC :
 				    ZORAN_MAP_MODE_JPG_PLAY;
 			sfmtjpg_unlock_and_return:
-				up(&zr->resource_lock);
+				mutex_unlock(&zr->resource_lock);
 			} else {
 				for (i = 0; i < zoran_num_formats; i++)
 					if (fmt->fmt.pix.pixelformat ==
@@ -3010,7 +3011,7 @@
 						(char *) &printformat);
 					return -EINVAL;
 				}
-				down(&zr->resource_lock);
+				mutex_lock(&zr->resource_lock);
 				if (fh->jpg_buffers.allocated ||
 				    (fh->v4l_buffers.allocated &&
 				     fh->v4l_buffers.active !=
@@ -3052,7 +3053,7 @@
 
 				fh->map_mode = ZORAN_MAP_MODE_RAW;
 			sfmtv4l_unlock_and_return:
-				up(&zr->resource_lock);
+				mutex_unlock(&zr->resource_lock);
 			}
 
 			break;
@@ -3077,7 +3078,7 @@
 		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_FBUF\n", ZR_DEVNAME(zr));
 
 		memset(fb, 0, sizeof(*fb));
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		fb->base = zr->buffer.base;
 		fb->fmt.width = zr->buffer.width;
 		fb->fmt.height = zr->buffer.height;
@@ -3086,7 +3087,7 @@
 				fh->overlay_settings.format->fourcc;
 		}
 		fb->fmt.bytesperline = zr->buffer.bytesperline;
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 		fb->fmt.colorspace = V4L2_COLORSPACE_SRGB;
 		fb->fmt.field = V4L2_FIELD_INTERLACED;
 		fb->flags = V4L2_FBUF_FLAG_OVERLAY;
@@ -3121,12 +3122,12 @@
 			return -EINVAL;
 		}
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		res =
 		    setup_fbuffer(file, fb->base, &zoran_formats[i],
 				  fb->fmt.width, fb->fmt.height,
 				  fb->fmt.bytesperline);
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return res;
 	}
@@ -3139,9 +3140,9 @@
 		dprintk(3, KERN_DEBUG "%s: VIDIOC_PREVIEW - on=%d\n",
 			ZR_DEVNAME(zr), *on);
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		res = setup_overlay(file, *on);
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return res;
 	}
@@ -3163,7 +3164,7 @@
 			return -EINVAL;
 		}
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 
 		if (fh->v4l_buffers.allocated || fh->jpg_buffers.allocated) {
 			dprintk(1,
@@ -3224,7 +3225,7 @@
 			goto v4l2reqbuf_unlock_and_return;
 		}
 	v4l2reqbuf_unlock_and_return:
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return 0;
 	}
@@ -3245,9 +3246,9 @@
 		buf->type = type;
 		buf->index = index;
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		res = zoran_v4l2_buffer_status(file, buf, buf->index);
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return res;
 	}
@@ -3262,7 +3263,7 @@
 			KERN_DEBUG "%s: VIDIOC_QBUF - type=%d, index=%d\n",
 			ZR_DEVNAME(zr), buf->type, buf->index);
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 
 		switch (fh->map_mode) {
 		case ZORAN_MAP_MODE_RAW:
@@ -3322,7 +3323,7 @@
 			goto qbuf_unlock_and_return;
 		}
 	qbuf_unlock_and_return:
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return res;
 	}
@@ -3336,7 +3337,7 @@
 		dprintk(3, KERN_DEBUG "%s: VIDIOC_DQBUF - type=%d\n",
 			ZR_DEVNAME(zr), buf->type);
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 
 		switch (fh->map_mode) {
 		case ZORAN_MAP_MODE_RAW:
@@ -3410,7 +3411,7 @@
 			goto dqbuf_unlock_and_return;
 		}
 	dqbuf_unlock_and_return:
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return res;
 	}
@@ -3422,7 +3423,7 @@
 
 		dprintk(3, KERN_DEBUG "%s: VIDIOC_STREAMON\n", ZR_DEVNAME(zr));
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 
 		switch (fh->map_mode) {
 		case ZORAN_MAP_MODE_RAW:	/* raw capture */
@@ -3470,7 +3471,7 @@
 			goto strmon_unlock_and_return;
 		}
 	strmon_unlock_and_return:
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return res;
 	}
@@ -3482,7 +3483,7 @@
 
 		dprintk(3, KERN_DEBUG "%s: VIDIOC_STREAMOFF\n", ZR_DEVNAME(zr));
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 
 		switch (fh->map_mode) {
 		case ZORAN_MAP_MODE_RAW:	/* raw capture */
@@ -3540,7 +3541,7 @@
 			goto strmoff_unlock_and_return;
 		}
 	strmoff_unlock_and_return:
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return res;
 	}
@@ -3600,7 +3601,7 @@
 		    ctrl->id > V4L2_CID_HUE)
 			return -EINVAL;
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		switch (ctrl->id) {
 		case V4L2_CID_BRIGHTNESS:
 			ctrl->value = zr->brightness;
@@ -3615,7 +3616,7 @@
 			ctrl->value = zr->hue;
 			break;
 		}
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return 0;
 	}
@@ -3642,7 +3643,7 @@
 			return -EINVAL;
 		}
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		switch (ctrl->id) {
 		case V4L2_CID_BRIGHTNESS:
 			zr->brightness = ctrl->value;
@@ -3664,7 +3665,7 @@
 
 		decoder_command(zr, DECODER_SET_PICTURE, &pict);
 
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return 0;
 	}
@@ -3732,9 +3733,9 @@
 
 		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_STD\n", ZR_DEVNAME(zr));
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		norm = zr->norm;
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		switch (norm) {
 		case VIDEO_MODE_PAL:
@@ -3776,13 +3777,13 @@
 			return -EINVAL;
 		}
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		if ((res = zoran_set_norm(zr, norm)))
 			goto sstd_unlock_and_return;
 
 		res = wait_grab_pending(zr);
 	sstd_unlock_and_return:
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 		return res;
 	}
 		break;
@@ -3809,9 +3810,9 @@
 		inp->std = V4L2_STD_ALL;
 
 		/* Get status of video decoder */
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		decoder_command(zr, DECODER_GET_STATUS, &status);
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		if (!(status & DECODER_STATUS_GOOD)) {
 			inp->status |= V4L2_IN_ST_NO_POWER;
@@ -3830,9 +3831,9 @@
 
 		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_INPUT\n", ZR_DEVNAME(zr));
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		*input = zr->input;
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return 0;
 	}
@@ -3845,14 +3846,14 @@
 		dprintk(3, KERN_DEBUG "%s: VIDIOC_S_INPUT - input=%d\n",
 			ZR_DEVNAME(zr), *input);
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 		if ((res = zoran_set_input(zr, *input)))
 			goto sinput_unlock_and_return;
 
 		/* Make sure the changes come into effect */
 		res = wait_grab_pending(zr);
 	sinput_unlock_and_return:
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 		return res;
 	}
 		break;
@@ -3914,7 +3915,7 @@
 		memset(cropcap, 0, sizeof(*cropcap));
 		cropcap->type = type;
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 
 		if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
 		    (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
@@ -3934,7 +3935,7 @@
 		cropcap->defrect.width = BUZ_MIN_WIDTH;
 		cropcap->defrect.height = BUZ_MIN_HEIGHT;
 	cropcap_unlock_and_return:
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 		return res;
 	}
 		break;
@@ -3950,7 +3951,7 @@
 		memset(crop, 0, sizeof(*crop));
 		crop->type = type;
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 
 		if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
 		    (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
@@ -3969,7 +3970,7 @@
 		crop->c.height = fh->jpg_settings.img_height;
 
 	gcrop_unlock_and_return:
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return res;
 	}
@@ -3988,7 +3989,7 @@
 			ZR_DEVNAME(zr), crop->type, crop->c.left, crop->c.top,
 			crop->c.width, crop->c.height);
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 
 		if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
 			dprintk(1,
@@ -4024,7 +4025,7 @@
 		fh->jpg_settings = settings;
 
 	scrop_unlock_and_return:
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 		return res;
 	}
 		break;
@@ -4038,7 +4039,7 @@
 
 		memset(params, 0, sizeof(*params));
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 
 		params->quality = fh->jpg_settings.jpg_comp.quality;
 		params->APPn = fh->jpg_settings.jpg_comp.APPn;
@@ -4053,7 +4054,7 @@
 		params->jpeg_markers =
 		    fh->jpg_settings.jpg_comp.jpeg_markers;
 
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return 0;
 	}
@@ -4074,7 +4075,7 @@
 
 		settings.jpg_comp = *params;
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 
 		if (fh->v4l_buffers.active != ZORAN_FREE ||
 		    fh->jpg_buffers.active != ZORAN_FREE) {
@@ -4093,7 +4094,7 @@
 			    zoran_v4l2_calc_bufsize(&fh->jpg_settings);
 		fh->jpg_settings.jpg_comp = *params = settings.jpg_comp;
 	sjpegc_unlock_and_return:
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		return 0;
 	}
@@ -4127,7 +4128,7 @@
 
 		switch (fmt->type) {
 		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-			down(&zr->resource_lock);
+			mutex_lock(&zr->resource_lock);
 
 			if (fmt->fmt.win.w.width > BUZ_MAX_WIDTH)
 				fmt->fmt.win.w.width = BUZ_MAX_WIDTH;
@@ -4138,7 +4139,7 @@
 			if (fmt->fmt.win.w.height < BUZ_MIN_HEIGHT)
 				fmt->fmt.win.w.height = BUZ_MIN_HEIGHT;
 
-			up(&zr->resource_lock);
+			mutex_unlock(&zr->resource_lock);
 			break;
 
 		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
@@ -4146,7 +4147,7 @@
 			if (fmt->fmt.pix.bytesperline > 0)
 				return -EINVAL;
 
-			down(&zr->resource_lock);
+			mutex_lock(&zr->resource_lock);
 
 			if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) {
 				settings = fh->jpg_settings;
@@ -4229,7 +4230,7 @@
 				goto tryfmt_unlock_and_return;
 			}
 		tryfmt_unlock_and_return:
-			up(&zr->resource_lock);
+			mutex_unlock(&zr->resource_lock);
 
 			return res;
 			break;
@@ -4280,7 +4281,7 @@
 	 * if no buffers queued or so, return POLLNVAL
 	 */
 
-	down(&zr->resource_lock);
+	mutex_lock(&zr->resource_lock);
 
 	switch (fh->map_mode) {
 	case ZORAN_MAP_MODE_RAW:
@@ -4329,7 +4330,7 @@
 	}
 
 poll_unlock_and_return:
-	up(&zr->resource_lock);
+	mutex_unlock(&zr->resource_lock);
 
 	return res;
 }
@@ -4385,7 +4386,7 @@
 				if (fh->jpg_buffers.buffer[i].map)
 					break;
 			if (i == fh->jpg_buffers.num_buffers) {
-				down(&zr->resource_lock);
+				mutex_lock(&zr->resource_lock);
 
 				if (fh->jpg_buffers.active != ZORAN_FREE) {
 					jpg_qbuf(file, -1, zr->codec_mode);
@@ -4398,7 +4399,7 @@
 				fh->jpg_buffers.allocated = 0;
 				fh->jpg_buffers.ready_to_be_freed = 1;
 
-				up(&zr->resource_lock);
+				mutex_unlock(&zr->resource_lock);
 			}
 
 			break;
@@ -4421,7 +4422,7 @@
 				if (fh->v4l_buffers.buffer[i].map)
 					break;
 			if (i == fh->v4l_buffers.num_buffers) {
-				down(&zr->resource_lock);
+				mutex_lock(&zr->resource_lock);
 
 				if (fh->v4l_buffers.active != ZORAN_FREE) {
 					zr36057_set_memgrab(zr, 0);
@@ -4434,7 +4435,7 @@
 				fh->v4l_buffers.allocated = 0;
 				fh->v4l_buffers.ready_to_be_freed = 1;
 
-				up(&zr->resource_lock);
+				mutex_unlock(&zr->resource_lock);
 			}
 
 			break;
@@ -4489,7 +4490,7 @@
 	case ZORAN_MAP_MODE_JPG_PLAY:
 
 		/* lock */
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 
 		/* Map the MJPEG buffers */
 		if (!fh->jpg_buffers.allocated) {
@@ -4579,13 +4580,13 @@
 
 		}
 	jpg_mmap_unlock_and_return:
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		break;
 
 	case ZORAN_MAP_MODE_RAW:
 
-		down(&zr->resource_lock);
+		mutex_lock(&zr->resource_lock);
 
 		/* Map the V4L buffers */
 		if (!fh->v4l_buffers.allocated) {
@@ -4657,7 +4658,7 @@
 				break;
 		}
 	v4l_mmap_unlock_and_return:
-		up(&zr->resource_lock);
+		mutex_unlock(&zr->resource_lock);
 
 		break;
 
diff -urN oldtree/drivers/message/fusion/mptfc.c newtree/drivers/message/fusion/mptfc.c
--- oldtree/drivers/message/fusion/mptfc.c	2006-02-19 11:41:03.047879752 +0000
+++ newtree/drivers/message/fusion/mptfc.c	2006-02-21 15:58:18.748296384 +0000
@@ -154,7 +154,7 @@
 
 static struct scsi_transport_template *mptfc_transport_template = NULL;
 
-struct fc_function_template mptfc_transport_functions = {
+static struct fc_function_template mptfc_transport_functions = {
 	.dd_fcrport_size = 8,
 	.show_host_node_name = 1,
 	.show_host_port_name = 1,
@@ -514,7 +514,7 @@
  *	Return non-zero if allocation fails.
  *	Init memory once per LUN.
  */
-int
+static int
 mptfc_slave_alloc(struct scsi_device *sdev)
 {
 	MPT_SCSI_HOST		*hd;
diff -urN oldtree/drivers/message/fusion/mptlan.c newtree/drivers/message/fusion/mptlan.c
--- oldtree/drivers/message/fusion/mptlan.c	2006-02-19 11:41:03.049879448 +0000
+++ newtree/drivers/message/fusion/mptlan.c	2006-02-21 15:58:18.749296232 +0000
@@ -1152,10 +1152,7 @@
 				priv->mpt_rxfidx_tail,
 				MPT_LAN_MAX_BUCKETS_OUT);
 
-		panic("Damn it Jim! I'm a doctor, not a programmer! "
-				"Oh, wait a sec, I am a programmer. "
-				"And, who's Jim?!?!\n"
-				"Arrgghh! We've done it again!\n");
+		return -1;
 	}
 
 	if (remaining == 0)
diff -urN oldtree/drivers/message/fusion/mptsas.c newtree/drivers/message/fusion/mptsas.c
--- oldtree/drivers/message/fusion/mptsas.c	2006-02-19 11:41:03.051879144 +0000
+++ newtree/drivers/message/fusion/mptsas.c	2006-02-21 15:58:18.752295776 +0000
@@ -117,6 +117,8 @@
 struct mptsas_devinfo {
 	u16	handle;		/* unique id to address this device */
 	u16	handle_parent;	/* unique id to address parent device */
+	u16	handle_enclosure; /* enclosure identifier of the enclosure */
+	u16	slot;		/* physical slot in enclosure */
 	u8	phy_id;		/* phy number of parent device */
 	u8	port_id;	/* sas physical port this device
 				   is assoc'd with */
@@ -146,6 +148,18 @@
 	struct mptsas_phyinfo *phy_info;
 };
 
+struct mptsas_enclosure {
+	u64	enclosure_logical_id;	/* The WWN for the enclosure */
+	u16	enclosure_handle;	/* unique id to address this */
+	u16	flags;			/* details enclosure management */
+	u16	num_slot;		/* num slots */
+	u16	start_slot;		/* first slot */
+	u8	start_id;		/* starting logical target id */
+	u8	start_channel;		/* starting logical channel id */
+	u8	sep_id;			/* SEP device logical target id */
+	u8	sep_channel;		/* SEP channel logical channel id */
+};
+
 
 #ifdef SASDEBUG
 static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
@@ -205,6 +219,7 @@
 
 	printk("---- SAS DEVICE PAGE 0 ---------\n");
 	printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle));
+	printk("Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle));
 	printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle));
 	printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot));
 	printk("SAS Address=0x%llX\n", le64_to_cpu(sas_address));
@@ -243,6 +258,82 @@
 #define mptsas_print_expander_pg1(pg1)		do { } while (0)
 #endif
 
+static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
+{
+	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+	return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
+}
+
+static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
+{
+	struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
+	return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
+}
+
+static int
+mptsas_sas_exclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
+		u32 form, u32 form_specific)
+{
+	ConfigExtendedPageHeader_t hdr;
+	CONFIGPARMS cfg;
+	SasEnclosurePage0_t *buffer;
+	dma_addr_t dma_handle;
+	int error;
+	__le64 le_identifier;
+
+	memset(&hdr, 0, sizeof(hdr));
+	hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
+	hdr.PageNumber = 0;
+	hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+	hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
+
+	cfg.cfghdr.ehdr = &hdr;
+	cfg.physAddr = -1;
+	cfg.pageAddr = form + form_specific;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.dir = 0;	/* read */
+	cfg.timeout = 10;
+
+	error = mpt_config(ioc, &cfg);
+	if (error)
+		goto out;
+	if (!hdr.ExtPageLength) {
+		error = -ENXIO;
+		goto out;
+	}
+
+	buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+			&dma_handle);
+	if (!buffer) {
+		error = -ENOMEM;
+		goto out;
+	}
+
+	cfg.physAddr = dma_handle;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+	error = mpt_config(ioc, &cfg);
+	if (error)
+		goto out_free_consistent;
+
+	/* save config data */
+	memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
+	enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
+	enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
+	enclosure->flags = le16_to_cpu(buffer->Flags);
+	enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
+	enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
+	enclosure->start_id = buffer->StartTargetID;
+	enclosure->start_channel = buffer->StartBus;
+	enclosure->sep_id = buffer->SEPTargetID;
+	enclosure->sep_channel = buffer->SEPBus;
+
+ out_free_consistent:
+	pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+			    buffer, dma_handle);
+ out:
+	return error;
+}
 
 /*
  * This is pretty ugly.  We will be able to seriously clean it up
@@ -399,12 +490,6 @@
 	.use_clustering			= ENABLE_CLUSTERING,
 };
 
-static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
-{
-	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
-	return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
-}
-
 static int mptsas_get_linkerrors(struct sas_phy *phy)
 {
 	MPT_ADAPTER *ioc = phy_to_ioc(phy);
@@ -546,8 +631,67 @@
 	return error;
 }
 
+static int
+mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
+{
+	MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
+	int i, error;
+	struct mptsas_portinfo *p;
+	struct mptsas_enclosure enclosure_info;
+	u64 enclosure_handle;
+
+	mutex_lock(&ioc->sas_topology_mutex);
+	list_for_each_entry(p, &ioc->sas_topology, list) {
+		for (i = 0; i < p->num_phys; i++) {
+			if (p->phy_info[i].attached.sas_address ==
+			    rphy->identify.sas_address) {
+				enclosure_handle = p->phy_info[i].
+					attached.handle_enclosure;
+				goto found_info;
+			}
+		}
+	}
+	mutex_unlock(&ioc->sas_topology_mutex);
+	return -ENXIO;
+
+ found_info:
+	mutex_unlock(&ioc->sas_topology_mutex);
+	memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
+	error = mptsas_sas_exclosure_pg0(ioc, &enclosure_info,
+			(MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
+			 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
+	if (!error)
+		*identifier = enclosure_info.enclosure_logical_id;
+	return error;
+}
+
+static int
+mptsas_get_bay_identifier(struct sas_rphy *rphy)
+{
+	MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
+	struct mptsas_portinfo *p;
+	int i, rc;
+
+	mutex_lock(&ioc->sas_topology_mutex);
+	list_for_each_entry(p, &ioc->sas_topology, list) {
+		for (i = 0; i < p->num_phys; i++) {
+			if (p->phy_info[i].attached.sas_address ==
+			    rphy->identify.sas_address) {
+				rc = p->phy_info[i].attached.slot;
+				goto out;
+			}
+		}
+	}
+	rc = -ENXIO;
+ out:
+	mutex_unlock(&ioc->sas_topology_mutex);
+	return rc;
+}
+
 static struct sas_function_template mptsas_transport_functions = {
 	.get_linkerrors		= mptsas_get_linkerrors,
+	.get_enclosure_identifier = mptsas_get_enclosure_identifier,
+	.get_bay_identifier	= mptsas_get_bay_identifier,
 	.phy_reset		= mptsas_phy_reset,
 };
 
@@ -739,6 +883,9 @@
 
 	device_info->handle = le16_to_cpu(buffer->DevHandle);
 	device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
+	device_info->handle_enclosure =
+	    le16_to_cpu(buffer->EnclosureHandle);
+	device_info->slot = le16_to_cpu(buffer->Slot);
 	device_info->phy_id = buffer->PhyNum;
 	device_info->port_id = buffer->PhysicalPort;
 	device_info->id = buffer->TargetID;
@@ -1335,29 +1482,15 @@
 	case MPTSAS_ADD_DEVICE:
 
 		/*
-		 * When there is no sas address,
-		 * RAID volumes are being deleted,
-		 * and hidden phy disk are being added.
-		 * We don't know the SAS data yet,
-		 * so lookup sas device page to get
-		 * pertaining info
+		 * Refresh sas device pg0 data
 		 */
-		if (!ev->sas_address) {
-			if (mptsas_sas_device_pg0(ioc,
-			    &sas_device, ev->id,
-			    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
-			     MPI_SAS_DEVICE_PGAD_FORM_SHIFT)))
-				break;
-			ev->handle = sas_device.handle;
-			ev->parent_handle = sas_device.handle_parent;
-			ev->channel = sas_device.channel;
-			ev->phy_id = sas_device.phy_id;
-			ev->sas_address = sas_device.sas_address;
-			ev->device_info = sas_device.device_info;
-		}
+		if (mptsas_sas_device_pg0(ioc, &sas_device,
+		    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+		     MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id))
+			break;
 
 		phy_info = mptsas_find_phyinfo_by_parent(ioc,
-				ev->parent_handle, ev->phy_id);
+				sas_device.handle_parent, sas_device.phy_id);
 		if (!phy_info) {
 			printk("mptsas: add event for non-existant PHY.\n");
 			break;
@@ -1368,14 +1501,8 @@
 			break;
 		}
 
-		/* fill attached info */
-		phy_info->attached.handle = ev->handle;
-		phy_info->attached.phy_id = ev->phy_id;
-		phy_info->attached.port_id = phy_info->identify.port_id;
-		phy_info->attached.id = ev->id;
-		phy_info->attached.channel = ev->channel;
-		phy_info->attached.sas_address = ev->sas_address;
-		phy_info->attached.device_info = ev->device_info;
+		memcpy(&phy_info->attached, &sas_device,
+		    sizeof(struct mptsas_devinfo));
 
 		if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
 			ds = "ssp";
@@ -1393,7 +1520,6 @@
 		if (!rphy)
 			break; /* non-fatal: an rphy can be added later */
 
-		rphy->scsi_target_id = phy_info->attached.id;
 		mptsas_parse_device_info(&rphy->identify, &phy_info->attached);
 		if (sas_rphy_add(rphy)) {
 			sas_rphy_free(rphy);
diff -urN oldtree/drivers/message/i2o/i2o_block.c newtree/drivers/message/i2o/i2o_block.c
--- oldtree/drivers/message/i2o/i2o_block.c	2006-02-19 11:41:03.088873520 +0000
+++ newtree/drivers/message/i2o/i2o_block.c	2006-02-21 15:58:30.881451864 +0000
@@ -1179,10 +1179,9 @@
 		goto exit;
 	}
 
-	i2o_blk_req_pool.pool = mempool_create(I2O_BLOCK_REQ_MEMPOOL_SIZE,
-					       mempool_alloc_slab,
-					       mempool_free_slab,
-					       i2o_blk_req_pool.slab);
+	i2o_blk_req_pool.pool =
+		mempool_create_slab_pool(I2O_BLOCK_REQ_MEMPOOL_SIZE,
+					 i2o_blk_req_pool.slab);
 	if (!i2o_blk_req_pool.pool) {
 		osm_err("can't init request mempool\n");
 		rc = -ENOMEM;
diff -urN oldtree/drivers/mmc/Kconfig newtree/drivers/mmc/Kconfig
--- oldtree/drivers/mmc/Kconfig	2006-02-19 11:41:03.098872000 +0000
+++ newtree/drivers/mmc/Kconfig	2006-02-21 15:58:32.123263080 +0000
@@ -29,6 +29,15 @@
 	  mount the filesystem. Almost everyone wishing MMC support
 	  should say Y or M here.
 
+config MMC_BULKTRANSFER
+	bool "Multi-block writes (EXPERIMENTAL)"
+	depends on MMC_BLOCK != n && EXPERIMENTAL
+	default n
+	help
+	  By default all writes are done one sector at a time. Enable
+	  this option to transfer as large blocks as the host supports.
+	  The transfer speed is in most cases doubled.
+
 config MMC_ARMMMCI
 	tristate "ARM AMBA Multimedia Card Interface support"
 	depends on ARM_AMBA && MMC
@@ -49,6 +58,17 @@
 
 	  If unsure, say N.
 
+config MMC_SDHCI
+	tristate "Secure Digital Host Controller Interface support  (EXPERIMENTAL)"
+	depends on PCI && MMC && EXPERIMENTAL
+	help
+	  This select the generic Secure Digital Host Controller Interface.
+	  It is used by manufacturers such as Texas Instruments(R), Ricoh(R)
+	  and Toshiba(R). Most controllers found in laptops are of this type.
+	  If you have a controller with this interface, say Y or M here.
+
+	  If unsure, say N.
+
 config MMC_WBSD
 	tristate "Winbond W83L51xD SD/MMC Card Interface support"
 	depends on MMC && ISA_DMA_API
diff -urN oldtree/drivers/mmc/Makefile newtree/drivers/mmc/Makefile
--- oldtree/drivers/mmc/Makefile	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/mmc/Makefile	2006-02-21 15:58:30.011584104 +0000
@@ -17,6 +17,7 @@
 #
 obj-$(CONFIG_MMC_ARMMMCI)	+= mmci.o
 obj-$(CONFIG_MMC_PXA)		+= pxamci.o
+obj-$(CONFIG_MMC_SDHCI)		+= sdhci.o
 obj-$(CONFIG_MMC_WBSD)		+= wbsd.o
 obj-$(CONFIG_MMC_AU1X)		+= au1xmmc.o
 
diff -urN oldtree/drivers/mmc/mmc_block.c newtree/drivers/mmc/mmc_block.c
--- oldtree/drivers/mmc/mmc_block.c	2006-02-19 11:41:03.101871544 +0000
+++ newtree/drivers/mmc/mmc_block.c	2006-02-21 15:58:32.137260952 +0000
@@ -159,9 +159,25 @@
 	struct mmc_card *card = md->queue.card;
 	int ret;
 
+#ifdef CONFIG_MMC_BULKTRANSFER
+	int failsafe;
+#endif
+
 	if (mmc_card_claim_host(card))
 		goto cmd_err;
 
+#ifdef CONFIG_MMC_BULKTRANSFER
+	/*
+	 * We first try transfering multiple blocks. If this fails
+	 * we fall back to single block transfers.
+	 *
+	 * This gives us good performance when all is well and the
+	 * possibility to determine which sector fails when all
+	 * is not well.
+	 */
+	failsafe = 0;
+#endif
+
 	do {
 		struct mmc_blk_request brq;
 		struct mmc_command cmd;
@@ -180,13 +196,31 @@
 		brq.stop.arg = 0;
 		brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
 
+#ifdef CONFIG_MMC_BULKTRANSFER
+		/*
+		 * A multi-block transfer failed. Falling back to single
+		 * blocks.
+		 */
+		if (failsafe)
+			brq.data.blocks = 1;
+
+#else
+		/*
+		 * Writes are done one sector at a time.
+		 */
+		if (rq_data_dir(req) != READ)
+			brq.data.blocks = 1;
+#endif
+
+		ret = 1;
+
 		if (rq_data_dir(req) == READ) {
 			brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK;
 			brq.data.flags |= MMC_DATA_READ;
 		} else {
-			brq.cmd.opcode = MMC_WRITE_BLOCK;
+			brq.cmd.opcode = brq.data.blocks > 1 ?
+				MMC_WRITE_MULTIPLE_BLOCK : MMC_WRITE_BLOCK;
 			brq.data.flags |= MMC_DATA_WRITE;
-			brq.data.blocks = 1;
 		}
 
 		if (brq.data.blocks > 1) {
@@ -203,19 +237,19 @@
 		if (brq.cmd.error) {
 			printk(KERN_ERR "%s: error %d sending read/write command\n",
 			       req->rq_disk->disk_name, brq.cmd.error);
-			goto cmd_err;
+			goto cmd_fail;
 		}
 
 		if (brq.data.error) {
 			printk(KERN_ERR "%s: error %d transferring data\n",
 			       req->rq_disk->disk_name, brq.data.error);
-			goto cmd_err;
+			goto cmd_fail;
 		}
 
 		if (brq.stop.error) {
 			printk(KERN_ERR "%s: error %d sending stop command\n",
 			       req->rq_disk->disk_name, brq.stop.error);
-			goto cmd_err;
+			goto cmd_fail;
 		}
 
 		do {
@@ -228,7 +262,7 @@
 			if (err) {
 				printk(KERN_ERR "%s: error %d requesting status\n",
 				       req->rq_disk->disk_name, err);
-				goto cmd_err;
+				goto cmd_fail;
 			}
 		} while (!(cmd.resp[0] & R1_READY_FOR_DATA));
 
@@ -254,6 +288,27 @@
 			end_that_request_last(req, 1);
 		}
 		spin_unlock_irq(&md->lock);
+
+#ifdef CONFIG_MMC_BULKTRANSFER
+		/*
+		 * Go back to bulk mode if in failsafe mode.
+		 */
+		failsafe = 0;
+#endif
+
+		continue;
+
+ cmd_fail:
+
+#ifdef CONFIG_MMC_BULKTRANSFER
+		if (failsafe)
+	 		goto cmd_err;
+	 	else
+	 		failsafe = 1;
+#else
+ 		goto cmd_err;
+#endif
+
 	} while (ret);
 
 	mmc_card_release_host(card);
diff -urN oldtree/drivers/mmc/pxamci.c newtree/drivers/mmc/pxamci.c
--- oldtree/drivers/mmc/pxamci.c	2006-02-19 11:41:03.104871088 +0000
+++ newtree/drivers/mmc/pxamci.c	2006-02-21 15:58:12.470250792 +0000
@@ -438,7 +438,7 @@
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	irq = platform_get_irq(pdev, 0);
-	if (!r || irq == NO_IRQ)
+	if (!r || irq < 0)
 		return -ENXIO;
 
 	r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
diff -urN oldtree/drivers/mmc/sdhci.c newtree/drivers/mmc/sdhci.c
--- oldtree/drivers/mmc/sdhci.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/mmc/sdhci.c	2006-02-21 15:58:30.082573312 +0000
@@ -0,0 +1,1264 @@
+/*
+ *  linux/drivers/mmc/sdhci.c - Secure Digital Host Controller Interface driver
+ *
+ *  Copyright (C) 2005-2006 Pierre Ossman, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+ /*
+  * Note that PIO transfer is rather crappy atm. The buffer full/empty
+  * interrupts aren't reliable so we currently transfer the entire buffer
+  * directly. Patches to solve the problem are welcome.
+  */
+
+#include <linux/delay.h>
+#include <linux/highmem.h>
+#include <linux/pci.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/protocol.h>
+
+#include <asm/scatterlist.h>
+
+#include "sdhci.h"
+
+#define DRIVER_NAME "sdhci"
+#define DRIVER_VERSION "0.11"
+
+#define BUGMAIL "<sdhci-devel@list.drzeus.cx>"
+
+#ifdef CONFIG_MMC_DEBUG
+#define DBG(f, x...) \
+	printk(KERN_DEBUG DRIVER_NAME " [%s()]: " f, __func__,## x)
+#else
+#define DBG(f, x...) do { } while (0)
+#endif
+
+static const struct pci_device_id pci_ids[] __devinitdata = {
+	/* handle any SD host controller */
+	{PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)},
+	{ /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+static void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *);
+static void sdhci_finish_data(struct sdhci_host *);
+
+static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
+static void sdhci_finish_command(struct sdhci_host *);
+
+static void sdhci_dumpregs(struct sdhci_host *host)
+{
+	printk(KERN_DEBUG DRIVER_NAME ": ============== REGISTER DUMP ==============\n");
+
+	printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n",
+		readl(host->ioaddr + SDHCI_DMA_ADDRESS),
+		readw(host->ioaddr + SDHCI_HOST_VERSION));
+	printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt:  0x%08x\n",
+		readw(host->ioaddr + SDHCI_BLOCK_SIZE),
+		readw(host->ioaddr + SDHCI_BLOCK_COUNT));
+	printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
+		readl(host->ioaddr + SDHCI_ARGUMENT),
+		readw(host->ioaddr + SDHCI_TRANSFER_MODE));
+	printk(KERN_DEBUG DRIVER_NAME ": Present:  0x%08x | Host ctl: 0x%08x\n",
+		readl(host->ioaddr + SDHCI_PRESENT_STATE),
+		readb(host->ioaddr + SDHCI_HOST_CONTROL));
+	printk(KERN_DEBUG DRIVER_NAME ": Power:    0x%08x | Blk gap:  0x%08x\n",
+		readb(host->ioaddr + SDHCI_POWER_CONTROL),
+		readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL));
+	printk(KERN_DEBUG DRIVER_NAME ": Wake-up:  0x%08x | Clock:    0x%08x\n",
+		readb(host->ioaddr + SDHCI_WALK_UP_CONTROL),
+		readw(host->ioaddr + SDHCI_CLOCK_CONTROL));
+	printk(KERN_DEBUG DRIVER_NAME ": Timeout:  0x%08x | Int stat: 0x%08x\n",
+		readb(host->ioaddr + SDHCI_TIMEOUT_CONTROL),
+		readl(host->ioaddr + SDHCI_INT_STATUS));
+	printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
+		readl(host->ioaddr + SDHCI_INT_ENABLE),
+		readl(host->ioaddr + SDHCI_SIGNAL_ENABLE));
+	printk(KERN_DEBUG DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
+		readw(host->ioaddr + SDHCI_ACMD12_ERR),
+		readw(host->ioaddr + SDHCI_SLOT_INT_STATUS));
+	printk(KERN_DEBUG DRIVER_NAME ": Caps:     0x%08x | Max curr: 0x%08x\n",
+		readl(host->ioaddr + SDHCI_CAPABILITIES),
+		readl(host->ioaddr + SDHCI_MAX_CURRENT));
+
+	printk(KERN_DEBUG DRIVER_NAME ": ===========================================\n");
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * Low level functions                                                       *
+ *                                                                           *
+\*****************************************************************************/
+
+static void sdhci_reset(struct sdhci_host *host, u8 mask)
+{
+	writeb(mask, host->ioaddr + SDHCI_SOFTWARE_RESET);
+
+	if (mask & SDHCI_RESET_ALL) {
+		host->clock = 0;
+
+		mdelay(50);
+	}
+}
+
+static void sdhci_init(struct sdhci_host *host)
+{
+	u32 intmask;
+
+	sdhci_reset(host, SDHCI_RESET_ALL);
+
+	intmask = ~(SDHCI_INT_CARD_INT | SDHCI_INT_BUF_EMPTY | SDHCI_INT_BUF_FULL);
+
+	writel(intmask, host->ioaddr + SDHCI_INT_ENABLE);
+	writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
+
+	/* This is unknown magic. */
+	writeb(0xE, host->ioaddr + SDHCI_TIMEOUT_CONTROL);
+}
+
+static void sdhci_activate_led(struct sdhci_host *host)
+{
+	u8 ctrl;
+
+	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
+	ctrl |= SDHCI_CTRL_LED;
+	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
+}
+
+static void sdhci_deactivate_led(struct sdhci_host *host)
+{
+	u8 ctrl;
+
+	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
+	ctrl &= ~SDHCI_CTRL_LED;
+	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * Core functions                                                            *
+ *                                                                           *
+\*****************************************************************************/
+
+static inline char* sdhci_kmap_sg(struct sdhci_host* host)
+{
+	host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ);
+	return host->mapped_sg + host->cur_sg->offset;
+}
+
+static inline void sdhci_kunmap_sg(struct sdhci_host* host)
+{
+	kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
+}
+
+static inline int sdhci_next_sg(struct sdhci_host* host)
+{
+	/*
+	 * Skip to next SG entry.
+	 */
+	host->cur_sg++;
+	host->num_sg--;
+
+	/*
+	 * Any entries left?
+	 */
+	if (host->num_sg > 0) {
+		host->offset = 0;
+		host->remain = host->cur_sg->length;
+	}
+
+	return host->num_sg;
+}
+
+static void sdhci_transfer_pio(struct sdhci_host *host)
+{
+	char *buffer;
+	u32 mask;
+	int bytes, size;
+	unsigned long max_jiffies;
+
+	BUG_ON(!host->data);
+
+	if (host->num_sg == 0)
+		return;
+
+	bytes = 0;
+	if (host->data->flags & MMC_DATA_READ)
+		mask = SDHCI_DATA_AVAILABLE;
+	else
+		mask = SDHCI_SPACE_AVAILABLE;
+
+	buffer = sdhci_kmap_sg(host) + host->offset;
+
+	/* Transfer shouldn't take more than 5 s */
+	max_jiffies = jiffies + HZ * 5;
+
+	while (host->size > 0) {
+		if (time_after(jiffies, max_jiffies)) {
+			printk(KERN_ERR "%s: PIO transfer stalled. "
+				"Please report this to "
+				BUGMAIL ".\n", mmc_hostname(host->mmc));
+			sdhci_dumpregs(host);
+
+			sdhci_kunmap_sg(host);
+
+			host->data->error = MMC_ERR_FAILED;
+			sdhci_finish_data(host);
+			return;
+		}
+
+		if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask))
+			continue;
+
+		size = min(host->size, host->remain);
+
+		if (size >= 4) {
+			if (host->data->flags & MMC_DATA_READ)
+				*(u32*)buffer = readl(host->ioaddr + SDHCI_BUFFER);
+			else
+				writel(*(u32*)buffer, host->ioaddr + SDHCI_BUFFER);
+			size = 4;
+		} else if (size >= 2) {
+			if (host->data->flags & MMC_DATA_READ)
+				*(u16*)buffer = readw(host->ioaddr + SDHCI_BUFFER);
+			else
+				writew(*(u16*)buffer, host->ioaddr + SDHCI_BUFFER);
+			size = 2;
+		} else {
+			if (host->data->flags & MMC_DATA_READ)
+				*(u8*)buffer = readb(host->ioaddr + SDHCI_BUFFER);
+			else
+				writeb(*(u8*)buffer, host->ioaddr + SDHCI_BUFFER);
+			size = 1;
+		}
+
+		buffer += size;
+		host->offset += size;
+		host->remain -= size;
+
+		bytes += size;
+		host->size -= size;
+
+		if (host->remain == 0) {
+			sdhci_kunmap_sg(host);
+			if (sdhci_next_sg(host) == 0) {
+				DBG("PIO transfer: %d bytes\n", bytes);
+				return;
+			}
+			buffer = sdhci_kmap_sg(host);
+		}
+	}
+
+	sdhci_kunmap_sg(host);
+
+	DBG("PIO transfer: %d bytes\n", bytes);
+}
+
+static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
+{
+	u16 mode;
+
+	WARN_ON(host->data);
+
+	if (data == NULL) {
+		writew(0, host->ioaddr + SDHCI_TRANSFER_MODE);
+		return;
+	}
+
+	DBG("blksz %04x blks %04x flags %08x\n",
+		1 << data->blksz_bits, data->blocks, data->flags);
+	DBG("tsac %d ms nsac %d clk\n",
+		data->timeout_ns / 1000000, data->timeout_clks);
+
+	mode = SDHCI_TRNS_BLK_CNT_EN;
+	if (data->blocks > 1)
+		mode |= SDHCI_TRNS_MULTI;
+	if (data->flags & MMC_DATA_READ)
+		mode |= SDHCI_TRNS_READ;
+	if (host->flags & SDHCI_USE_DMA)
+		mode |= SDHCI_TRNS_DMA;
+
+	writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE);
+
+	writew(1 << data->blksz_bits, host->ioaddr + SDHCI_BLOCK_SIZE);
+	writew(data->blocks, host->ioaddr + SDHCI_BLOCK_COUNT);
+
+	if (host->flags & SDHCI_USE_DMA) {
+		int count;
+
+		count = pci_map_sg(host->chip->pdev, data->sg, data->sg_len,
+			(data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
+		BUG_ON(count != 1);
+
+		writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS);
+	} else {
+		host->size = (1 << data->blksz_bits) * data->blocks;
+
+		host->cur_sg = data->sg;
+		host->num_sg = data->sg_len;
+
+		host->offset = 0;
+		host->remain = host->cur_sg->length;
+	}
+}
+
+static void sdhci_finish_data(struct sdhci_host *host)
+{
+	struct mmc_data *data;
+	u32 intmask;
+	u16 blocks;
+
+	BUG_ON(!host->data);
+
+	data = host->data;
+	host->data = NULL;
+
+	if (host->flags & SDHCI_USE_DMA) {
+		pci_unmap_sg(host->chip->pdev, data->sg, data->sg_len,
+			(data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
+	} else {
+		intmask = readl(host->ioaddr + SDHCI_SIGNAL_ENABLE);
+		intmask &= ~(SDHCI_INT_BUF_EMPTY | SDHCI_INT_BUF_FULL);
+		writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
+
+		intmask = readl(host->ioaddr + SDHCI_INT_ENABLE);
+		intmask &= ~(SDHCI_INT_BUF_EMPTY | SDHCI_INT_BUF_FULL);
+		writel(intmask, host->ioaddr + SDHCI_INT_ENABLE);
+	}
+
+	/*
+	 * Controller doesn't count down when in single block mode.
+	 */
+	if ((data->blocks == 1) && (data->error == MMC_ERR_NONE))
+		blocks = 0;
+	else
+		blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT);
+	data->bytes_xfered = (1 << data->blksz_bits) * (data->blocks - blocks);
+
+	if ((data->error == MMC_ERR_NONE) && blocks) {
+		printk(KERN_ERR "%s: Controller signalled completion even "
+			"though there were blocks left. Please report this "
+			"to " BUGMAIL ".\n", mmc_hostname(host->mmc));
+		data->error = MMC_ERR_FAILED;
+	}
+
+	if (host->size != 0) {
+		printk(KERN_ERR "%s: %d bytes were left untransferred. "
+			"Please report this to " BUGMAIL ".\n",
+			mmc_hostname(host->mmc), host->size);
+		data->error = MMC_ERR_FAILED;
+	}
+
+	DBG("Ending data transfer (%d bytes)\n", data->bytes_xfered);
+
+	if (data->stop) {
+		/*
+		 * The controller needs a reset of internal state machines
+		 * upon error conditions.
+		 */
+		if (data->error != MMC_ERR_NONE) {
+			sdhci_reset(host, SDHCI_RESET_CMD);
+			sdhci_reset(host, SDHCI_RESET_DATA);
+		}
+
+		sdhci_send_command(host, data->stop);
+	} else
+		tasklet_schedule(&host->finish_tasklet);
+}
+
+static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
+{
+	int flags;
+	u32 present;
+	unsigned long max_jiffies;
+
+	WARN_ON(host->cmd);
+
+	DBG("Sending cmd (%x)\n", cmd->opcode);
+
+	/* Wait max 10 ms */
+	max_jiffies = jiffies + (HZ + 99)/100;
+	do {
+		if (time_after(jiffies, max_jiffies)) {
+			printk(KERN_ERR "%s: Controller never released "
+				"inhibit bits. Please report this to "
+				BUGMAIL ".\n", mmc_hostname(host->mmc));
+			sdhci_dumpregs(host);
+			cmd->error = MMC_ERR_FAILED;
+			tasklet_schedule(&host->finish_tasklet);
+			return;
+		}
+		present = readl(host->ioaddr + SDHCI_PRESENT_STATE);
+	} while (present & (SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT));
+
+	mod_timer(&host->timer, jiffies + 10 * HZ);
+
+	host->cmd = cmd;
+
+	sdhci_prepare_data(host, cmd->data);
+
+	writel(cmd->arg, host->ioaddr + SDHCI_ARGUMENT);
+
+	if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
+		printk(KERN_ERR "%s: Unsupported response type! "
+			"Please report this to " BUGMAIL ".\n",
+			mmc_hostname(host->mmc));
+		cmd->error = MMC_ERR_INVALID;
+		tasklet_schedule(&host->finish_tasklet);
+		return;
+	}
+
+	if (!(cmd->flags & MMC_RSP_PRESENT))
+		flags = SDHCI_CMD_RESP_NONE;
+	else if (cmd->flags & MMC_RSP_136)
+		flags = SDHCI_CMD_RESP_LONG;
+	else if (cmd->flags & MMC_RSP_BUSY)
+		flags = SDHCI_CMD_RESP_SHORT_BUSY;
+	else
+		flags = SDHCI_CMD_RESP_SHORT;
+
+	if (cmd->flags & MMC_RSP_CRC)
+		flags |= SDHCI_CMD_CRC;
+	if (cmd->flags & MMC_RSP_OPCODE)
+		flags |= SDHCI_CMD_INDEX;
+	if (cmd->data)
+		flags |= SDHCI_CMD_DATA;
+
+	writel(SDHCI_MAKE_CMD(cmd->opcode, flags),
+		host->ioaddr + SDHCI_COMMAND);
+}
+
+static void sdhci_finish_command(struct sdhci_host *host)
+{
+	int i;
+
+	BUG_ON(host->cmd == NULL);
+
+	if (host->cmd->flags & MMC_RSP_PRESENT) {
+		if (host->cmd->flags & MMC_RSP_136) {
+			/* CRC is stripped so we need to do some shifting. */
+			for (i = 0;i < 4;i++) {
+				host->cmd->resp[i] = readl(host->ioaddr +
+					SDHCI_RESPONSE + (3-i)*4) << 8;
+				if (i != 3)
+					host->cmd->resp[i] |=
+						readb(host->ioaddr +
+						SDHCI_RESPONSE + (3-i)*4-1);
+			}
+		} else {
+			host->cmd->resp[0] = readl(host->ioaddr + SDHCI_RESPONSE);
+		}
+	}
+
+	host->cmd->error = MMC_ERR_NONE;
+
+	DBG("Ending cmd (%x)\n", host->cmd->opcode);
+
+	if (host->cmd->data) {
+		u32 intmask;
+
+		host->data = host->cmd->data;
+
+		if (!(host->flags & SDHCI_USE_DMA)) {
+			/*
+			 * Don't enable the interrupts until now to make sure we
+			 * get stable handling of the FIFO.
+			 */
+			intmask = readl(host->ioaddr + SDHCI_INT_ENABLE);
+			intmask |= SDHCI_INT_BUF_EMPTY | SDHCI_INT_BUF_FULL;
+			writel(intmask, host->ioaddr + SDHCI_INT_ENABLE);
+
+			intmask = readl(host->ioaddr + SDHCI_SIGNAL_ENABLE);
+			intmask |= SDHCI_INT_BUF_EMPTY | SDHCI_INT_BUF_FULL;
+			writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
+
+			/*
+			 * The buffer interrupts are to unreliable so we
+			 * start the transfer immediatly.
+			 */
+			sdhci_transfer_pio(host);
+		}
+	} else
+		tasklet_schedule(&host->finish_tasklet);
+
+	host->cmd = NULL;
+}
+
+static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+	int div;
+	u16 clk;
+	unsigned long max_jiffies;
+
+	if (clock == host->clock)
+		return;
+
+	writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
+
+	if (clock == 0)
+		goto out;
+
+	for (div = 1;div < 256;div *= 2) {
+		if ((host->max_clk / div) <= clock)
+			break;
+	}
+	div >>= 1;
+
+	clk = div << SDHCI_DIVIDER_SHIFT;
+	clk |= SDHCI_CLOCK_INT_EN;
+	writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
+
+	/* Wait max 10 ms */
+	max_jiffies = jiffies + (HZ + 99)/100;
+	do {
+		if (time_after(jiffies, max_jiffies)) {
+			printk(KERN_ERR "%s: Internal clock never stabilised. "
+				"Please report this to " BUGMAIL ".\n",
+				mmc_hostname(host->mmc));
+			sdhci_dumpregs(host);
+			return;
+		}
+		clk = readw(host->ioaddr + SDHCI_CLOCK_CONTROL);
+	} while (!(clk & SDHCI_CLOCK_INT_STABLE));
+
+	clk |= SDHCI_CLOCK_CARD_EN;
+	writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
+
+out:
+	host->clock = clock;
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * MMC callbacks                                                             *
+ *                                                                           *
+\*****************************************************************************/
+
+static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct sdhci_host *host;
+	unsigned long flags;
+
+	host = mmc_priv(mmc);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	WARN_ON(host->mrq != NULL);
+
+	sdhci_activate_led(host);
+
+	host->mrq = mrq;
+
+	if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
+		host->mrq->cmd->error = MMC_ERR_TIMEOUT;
+		tasklet_schedule(&host->finish_tasklet);
+	} else
+		sdhci_send_command(host, mrq->cmd);
+
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct sdhci_host *host;
+	unsigned long flags;
+	u8 ctrl;
+
+	host = mmc_priv(mmc);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	DBG("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n",
+	     ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select,
+	     ios->vdd, ios->bus_width);
+
+	/*
+	 * Reset the chip on each power off.
+	 * Should clear out any weird states.
+	 */
+	if (ios->power_mode == MMC_POWER_OFF) {
+		writel(0, host->ioaddr + SDHCI_SIGNAL_ENABLE);
+		spin_unlock_irqrestore(&host->lock, flags);
+		sdhci_init(host);
+		spin_lock_irqsave(&host->lock, flags);
+	}
+
+	sdhci_set_clock(host, ios->clock);
+
+	if (ios->power_mode == MMC_POWER_OFF)
+		writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
+	else
+		writeb(0xFF, host->ioaddr + SDHCI_POWER_CONTROL);
+
+	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
+	if (ios->bus_width == MMC_BUS_WIDTH_4)
+		ctrl |= SDHCI_CTRL_4BITBUS;
+	else
+		ctrl &= ~SDHCI_CTRL_4BITBUS;
+	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
+
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static int sdhci_get_ro(struct mmc_host *mmc)
+{
+	struct sdhci_host *host;
+	unsigned long flags;
+	int present;
+
+	host = mmc_priv(mmc);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	present = readl(host->ioaddr + SDHCI_PRESENT_STATE);
+
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	return !(present & SDHCI_WRITE_PROTECT);
+}
+
+static struct mmc_host_ops sdhci_ops = {
+	.request	= sdhci_request,
+	.set_ios	= sdhci_set_ios,
+	.get_ro		= sdhci_get_ro,
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Tasklets                                                                  *
+ *                                                                           *
+\*****************************************************************************/
+
+static void sdhci_tasklet_card(unsigned long param)
+{
+	struct sdhci_host *host;
+	unsigned long flags;
+
+	host = (struct sdhci_host*)param;
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
+		if (host->mrq) {
+			printk(KERN_ERR "%s: Card removed during transfer!\n",
+				mmc_hostname(host->mmc));
+			printk(KERN_ERR "%s: Resetting controller.\n",
+				mmc_hostname(host->mmc));
+
+			sdhci_reset(host, SDHCI_RESET_CMD);
+			sdhci_reset(host, SDHCI_RESET_DATA);
+
+			host->mrq->cmd->error = MMC_ERR_FAILED;
+			tasklet_schedule(&host->finish_tasklet);
+		}
+	}
+
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	mmc_detect_change(host->mmc, msecs_to_jiffies(500));
+}
+
+static void sdhci_tasklet_finish(unsigned long param)
+{
+	struct sdhci_host *host;
+	unsigned long flags;
+	struct mmc_request *mrq;
+
+	host = (struct sdhci_host*)param;
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	del_timer(&host->timer);
+
+	mrq = host->mrq;
+
+	DBG("Ending request, cmd (%x)\n", mrq->cmd->opcode);
+
+	/*
+	 * The controller needs a reset of internal state machines
+	 * upon error conditions.
+	 */
+	if ((mrq->cmd->error != MMC_ERR_NONE) ||
+		(mrq->data && ((mrq->data->error != MMC_ERR_NONE) ||
+		(mrq->data->stop && (mrq->data->stop->error != MMC_ERR_NONE))))) {
+		sdhci_reset(host, SDHCI_RESET_CMD);
+		sdhci_reset(host, SDHCI_RESET_DATA);
+	}
+
+	host->mrq = NULL;
+	host->cmd = NULL;
+	host->data = NULL;
+
+	sdhci_deactivate_led(host);
+
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	mmc_request_done(host->mmc, mrq);
+}
+
+static void sdhci_timeout_timer(unsigned long data)
+{
+	struct sdhci_host *host;
+	unsigned long flags;
+
+	host = (struct sdhci_host*)data;
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	if (host->mrq) {
+		printk(KERN_ERR "%s: Timeout waiting for hardware interrupt. "
+			"Please report this to " BUGMAIL ".\n",
+			mmc_hostname(host->mmc));
+		sdhci_dumpregs(host);
+
+		if (host->data) {
+			host->data->error = MMC_ERR_TIMEOUT;
+			sdhci_finish_data(host);
+		} else {
+			if (host->cmd)
+				host->cmd->error = MMC_ERR_TIMEOUT;
+			else
+				host->mrq->cmd->error = MMC_ERR_TIMEOUT;
+
+			tasklet_schedule(&host->finish_tasklet);
+		}
+	}
+
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * Interrupt handling                                                        *
+ *                                                                           *
+\*****************************************************************************/
+
+static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
+{
+	BUG_ON(intmask == 0);
+
+	if (!host->cmd) {
+		printk(KERN_ERR "%s: Got command interrupt even though no "
+			"command operation was in progress.\n",
+			mmc_hostname(host->mmc));
+		printk(KERN_ERR "%s: Please report this to " BUGMAIL ".\n",
+			mmc_hostname(host->mmc));
+		sdhci_dumpregs(host);
+		return;
+	}
+
+	if (intmask & SDHCI_INT_RESPONSE)
+		sdhci_finish_command(host);
+	else {
+		if (intmask & SDHCI_INT_TIMEOUT)
+			host->cmd->error = MMC_ERR_TIMEOUT;
+		else if (intmask & SDHCI_INT_CRC)
+			host->cmd->error = MMC_ERR_BADCRC;
+		else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX))
+			host->cmd->error = MMC_ERR_FAILED;
+		else
+			host->cmd->error = MMC_ERR_INVALID;
+
+		tasklet_schedule(&host->finish_tasklet);
+	}
+}
+
+static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
+{
+	BUG_ON(intmask == 0);
+
+	if (!host->data) {
+		/*
+		 * A data end interrupt is sent together with the response
+		 * for the stop command.
+		 */
+		if (intmask & SDHCI_INT_DATA_END)
+			return;
+
+		printk(KERN_ERR "%s: Got data interrupt even though no "
+			"data operation was in progress.\n",
+			mmc_hostname(host->mmc));
+		printk(KERN_ERR "%s: Please report this to " BUGMAIL ".\n",
+			mmc_hostname(host->mmc));
+		sdhci_dumpregs(host);
+
+		return;
+	}
+
+	if (intmask & SDHCI_INT_DATA_TIMEOUT)
+		host->data->error = MMC_ERR_TIMEOUT;
+	else if (intmask & SDHCI_INT_DATA_CRC)
+		host->data->error = MMC_ERR_BADCRC;
+	else if (intmask & SDHCI_INT_DATA_END_BIT)
+		host->data->error = MMC_ERR_FAILED;
+
+	if (host->data->error != MMC_ERR_NONE)
+		sdhci_finish_data(host);
+	else {
+		if (intmask & (SDHCI_INT_BUF_FULL | SDHCI_INT_BUF_EMPTY))
+			sdhci_transfer_pio(host);
+
+		if (intmask & SDHCI_INT_DATA_END)
+			sdhci_finish_data(host);
+	}
+}
+
+static irqreturn_t sdhci_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	irqreturn_t result;
+	struct sdhci_host* host = dev_id;
+	u32 intmask;
+
+	spin_lock(&host->lock);
+
+	intmask = readl(host->ioaddr + SDHCI_INT_STATUS);
+
+	if (!intmask) {
+		result = IRQ_NONE;
+		goto out;
+	}
+
+	DBG("*** %s got interrupt: 0x%08x\n", host->slot_descr, intmask);
+
+	if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE))
+		tasklet_schedule(&host->card_tasklet);
+
+	if (intmask & SDHCI_INT_CMD_MASK) {
+		sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
+
+		writel(intmask & SDHCI_INT_CMD_MASK,
+			host->ioaddr + SDHCI_INT_STATUS);
+	}
+
+	if (intmask & SDHCI_INT_DATA_MASK) {
+		sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
+
+		writel(intmask & SDHCI_INT_DATA_MASK,
+			host->ioaddr + SDHCI_INT_STATUS);
+	}
+
+	intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
+
+	if (intmask & SDHCI_INT_CARD_INT) {
+		printk(KERN_ERR "%s: Unexpected card interrupt. Please "
+			"report this to " BUGMAIL ".\n",
+			mmc_hostname(host->mmc));
+		sdhci_dumpregs(host);
+	}
+
+	if (intmask & SDHCI_INT_BUS_POWER) {
+		printk(KERN_ERR "%s: Unexpected bus power interrupt. Please "
+			"report this to " BUGMAIL ".\n",
+			mmc_hostname(host->mmc));
+		sdhci_dumpregs(host);
+	}
+
+	if (intmask & SDHCI_INT_ACMD12ERR) {
+		printk(KERN_ERR "%s: Unexpected auto CMD12 error. Please "
+			"report this to " BUGMAIL ".\n",
+			mmc_hostname(host->mmc));
+		sdhci_dumpregs(host);
+
+		writew(~0, host->ioaddr + SDHCI_ACMD12_ERR);
+	}
+
+	if (intmask)
+		writel(intmask, host->ioaddr + SDHCI_INT_STATUS);
+
+	result = IRQ_HANDLED;
+
+out:
+	spin_unlock(&host->lock);
+
+	return result;
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * Suspend/resume                                                            *
+ *                                                                           *
+\*****************************************************************************/
+
+#ifdef CONFIG_PM
+
+static int sdhci_suspend (struct pci_dev *pdev, pm_message_t state)
+{
+	struct sdhci_chip *chip;
+	int i, ret;
+
+	chip = pci_get_drvdata(pdev);
+	if (!chip)
+		return 0;
+
+	DBG("Suspending...\n");
+
+	for (i = 0;i < chip->num_slots;i++) {
+		if (!chip->hosts[i])
+			continue;
+		ret = mmc_suspend_host(chip->hosts[i]->mmc, state);
+		if (ret) {
+			for (i--;i >= 0;i--)
+				mmc_resume_host(chip->hosts[i]->mmc);
+			return ret;
+		}
+	}
+
+	pci_save_state(pdev);
+	pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+	return 0;
+}
+
+static int sdhci_resume (struct pci_dev *pdev)
+{
+	struct sdhci_chip *chip;
+	int i, ret;
+
+	chip = pci_get_drvdata(pdev);
+	if (!chip)
+		return 0;
+
+	DBG("Resuming...\n");
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	pci_enable_device(pdev);
+
+	for (i = 0;i < chip->num_slots;i++) {
+		if (!chip->hosts[i])
+			continue;
+		if (chip->hosts[i]->flags & SDHCI_USE_DMA)
+			pci_set_master(pdev);
+		sdhci_init(chip->hosts[i]);
+		ret = mmc_resume_host(chip->hosts[i]->mmc);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+#else /* CONFIG_PM */
+
+#define sdhci_suspend NULL
+#define sdhci_resume NULL
+
+#endif /* CONFIG_PM */
+
+/*****************************************************************************\
+ *                                                                           *
+ * Device probing/removal                                                    *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
+{
+	int ret;
+	struct sdhci_chip *chip;
+	struct mmc_host *mmc;
+	struct sdhci_host *host;
+
+	u8 first_bar;
+	unsigned int caps;
+
+	chip = pci_get_drvdata(pdev);
+	BUG_ON(!chip);
+
+	ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar);
+	if (ret)
+		return ret;
+
+	first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK;
+
+	if (first_bar > 5) {
+		printk(KERN_ERR DRIVER_NAME ": Invalid first BAR. Aborting.\n");
+		return -ENODEV;
+	}
+
+	if (!(pci_resource_flags(pdev, first_bar + slot) & IORESOURCE_MEM)) {
+		printk(KERN_ERR DRIVER_NAME ": BAR is not iomem. Aborting.\n");
+		return -ENODEV;
+	}
+
+	if (pci_resource_len(pdev, first_bar + slot) != 0x100) {
+		printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. Aborting.\n");
+		return -ENODEV;
+	}
+
+	mmc = mmc_alloc_host(sizeof(struct sdhci_host), &pdev->dev);
+	if (!mmc)
+		return -ENOMEM;
+
+	host = mmc_priv(mmc);
+	host->mmc = mmc;
+
+	host->bar = first_bar + slot;
+
+	host->addr = pci_resource_start(pdev, host->bar);
+	host->irq = pdev->irq;
+
+	DBG("slot %d at 0x%08lx, irq %d\n", slot, host->addr, host->irq);
+
+	snprintf(host->slot_descr, 20, "sdhci:slot%d", slot);
+
+	ret = pci_request_region(pdev, host->bar, host->slot_descr);
+	if (ret)
+		goto free;
+
+	host->ioaddr = ioremap_nocache(host->addr,
+		pci_resource_len(pdev, host->bar));
+	if (!host->ioaddr) {
+		ret = -ENOMEM;
+		goto release;
+	}
+
+	caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
+
+	if ((caps & SDHCI_CAN_DO_DMA) && ((pdev->class & 0x0000FF) == 0x01))
+		host->flags |= SDHCI_USE_DMA;
+
+	if (host->flags & SDHCI_USE_DMA) {
+		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
+			printk(KERN_WARNING "%s: No suitable DMA available. "
+				"Falling back to PIO.\n", host->slot_descr);
+			host->flags &= ~SDHCI_USE_DMA;
+		}
+	}
+
+	if (host->flags & SDHCI_USE_DMA)
+		pci_set_master(pdev);
+	else /* XXX: Hack to get MMC layer to avoid highmem */
+		pdev->dma_mask = 0;
+
+	host->max_clk = (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
+	host->max_clk *= 1000000;
+
+	/*
+	 * Set host parameters.
+	 */
+	mmc->ops = &sdhci_ops;
+	mmc->f_min = host->max_clk / 256;
+	mmc->f_max = host->max_clk;
+	mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+	mmc->caps = MMC_CAP_4_BIT_DATA;
+
+	spin_lock_init(&host->lock);
+
+	/*
+	 * Maximum number of segments. Hardware cannot do scatter lists.
+	 */
+	if (host->flags & SDHCI_USE_DMA)
+		mmc->max_hw_segs = 1;
+	else
+		mmc->max_hw_segs = 16;
+	mmc->max_phys_segs = 16;
+
+	/*
+	 * Maximum number of sectors in one transfer. Limited by sector
+	 * count register.
+	 */
+	mmc->max_sectors = 0x3FFF;
+
+	/*
+	 * Maximum segment size. Could be one segment with the maximum number
+	 * of sectors.
+	 */
+	mmc->max_seg_size = mmc->max_sectors * 512;
+
+	/*
+	 * Init tasklets.
+	 */
+	tasklet_init(&host->card_tasklet,
+		sdhci_tasklet_card, (unsigned long)host);
+	tasklet_init(&host->finish_tasklet,
+		sdhci_tasklet_finish, (unsigned long)host);
+
+	setup_timer(&host->timer, sdhci_timeout_timer, (int)host);
+
+	ret = request_irq(host->irq, sdhci_irq, SA_SHIRQ,
+		host->slot_descr, host);
+	if (ret)
+		goto unmap;
+
+	sdhci_init(host);
+
+#ifdef CONFIG_MMC_DEBUG
+	sdhci_dumpregs(host);
+#endif
+
+	host->chip = chip;
+	chip->hosts[slot] = host;
+
+	mmc_add_host(mmc);
+
+	printk(KERN_INFO "%s: SDHCI at 0x%08lx irq %d %s\n", mmc_hostname(mmc),
+		host->addr, host->irq,
+		(host->flags & SDHCI_USE_DMA)?"DMA":"PIO");
+
+	return 0;
+
+unmap:
+	tasklet_kill(&host->card_tasklet);
+	tasklet_kill(&host->finish_tasklet);
+
+	iounmap(host->ioaddr);
+release:
+	pci_release_region(pdev, host->bar);
+free:
+	mmc_free_host(mmc);
+
+	return ret;
+}
+
+static void sdhci_remove_slot(struct pci_dev *pdev, int slot)
+{
+	struct sdhci_chip *chip;
+	struct mmc_host *mmc;
+	struct sdhci_host *host;
+
+	chip = pci_get_drvdata(pdev);
+	host = chip->hosts[slot];
+	mmc = host->mmc;
+
+	chip->hosts[slot] = NULL;
+
+	mmc_remove_host(mmc);
+
+	sdhci_reset(host, SDHCI_RESET_ALL);
+
+	free_irq(host->irq, host);
+
+	del_timer_sync(&host->timer);
+
+	tasklet_kill(&host->card_tasklet);
+	tasklet_kill(&host->finish_tasklet);
+
+	iounmap(host->ioaddr);
+
+	pci_release_region(pdev, host->bar);
+
+	mmc_free_host(mmc);
+}
+
+static int __devinit sdhci_probe(struct pci_dev *pdev,
+	const struct pci_device_id *ent)
+{
+	int ret, i;
+	u8 slots;
+	struct sdhci_chip *chip;
+
+	BUG_ON(pdev == NULL);
+	BUG_ON(ent == NULL);
+
+	DBG("found at %s\n", pci_name(pdev));
+
+	ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots);
+	if (ret)
+		return ret;
+
+	slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
+	DBG("found %d slot(s)\n", slots);
+	if (slots == 0)
+		return -ENODEV;
+
+	ret = pci_enable_device(pdev);
+	if (ret)
+		return ret;
+
+	chip = kzalloc(sizeof(struct sdhci_chip) +
+		sizeof(struct sdhci_host*) * slots, GFP_KERNEL);
+	if (!chip) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	chip->pdev = pdev;
+
+	chip->num_slots = slots;
+	pci_set_drvdata(pdev, chip);
+
+	for (i = 0;i < slots;i++) {
+		ret = sdhci_probe_slot(pdev, i);
+		if (ret) {
+			for (i--;i >= 0;i--)
+				sdhci_remove_slot(pdev, i);
+			goto free;
+		}
+	}
+
+	return 0;
+
+free:
+	pci_set_drvdata(pdev, NULL);
+	kfree(chip);
+
+err:
+	pci_disable_device(pdev);
+	return ret;
+}
+
+static void __devexit sdhci_remove(struct pci_dev *pdev)
+{
+	int i;
+	struct sdhci_chip *chip;
+
+	chip = pci_get_drvdata(pdev);
+
+	if (chip) {
+		for (i = 0;i < chip->num_slots;i++)
+			sdhci_remove_slot(pdev, i);
+
+		pci_set_drvdata(pdev, NULL);
+
+		kfree(chip);
+	}
+
+	pci_disable_device(pdev);
+}
+
+static struct pci_driver sdhci_driver = {
+	.name = 	DRIVER_NAME,
+	.id_table =	pci_ids,
+	.probe = 	sdhci_probe,
+	.remove =	__devexit_p(sdhci_remove),
+	.suspend =	sdhci_suspend,
+	.resume	=	sdhci_resume,
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Driver init/exit                                                          *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __init sdhci_drv_init(void)
+{
+	printk(KERN_INFO DRIVER_NAME
+		": Secure Digital Host Controller Interface driver, "
+		DRIVER_VERSION "\n");
+	printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
+
+	return pci_register_driver(&sdhci_driver);
+}
+
+static void __exit sdhci_drv_exit(void)
+{
+	DBG("Exiting\n");
+
+	pci_unregister_driver(&sdhci_driver);
+}
+
+module_init(sdhci_drv_init);
+module_exit(sdhci_drv_exit);
+
+MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
+MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff -urN oldtree/drivers/mmc/sdhci.h newtree/drivers/mmc/sdhci.h
--- oldtree/drivers/mmc/sdhci.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/mmc/sdhci.h	2006-02-21 15:58:30.082573312 +0000
@@ -0,0 +1,185 @@
+/*
+ *  linux/drivers/mmc/sdhci.h - Secure Digital Host Controller Interface driver
+ *
+ *  Copyright (C) 2005 Pierre Ossman, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * PCI registers
+ */
+
+#define PCI_SLOT_INFO			0x40	/* 8 bits */
+#define  PCI_SLOT_INFO_SLOTS(x)		((x >> 4) & 7)
+#define  PCI_SLOT_INFO_FIRST_BAR_MASK	0x07
+
+/*
+ * Controller registers
+ */
+
+#define SDHCI_DMA_ADDRESS	0x00
+
+#define SDHCI_BLOCK_SIZE	0x04
+
+#define SDHCI_BLOCK_COUNT	0x06
+
+#define SDHCI_ARGUMENT		0x08
+
+#define SDHCI_TRANSFER_MODE	0x0C
+#define  SDHCI_TRNS_DMA		0x01
+#define  SDHCI_TRNS_BLK_CNT_EN	0x02
+#define  SDHCI_TRNS_ACMD12	0x04
+#define  SDHCI_TRNS_READ	0x10
+#define  SDHCI_TRNS_MULTI	0x20
+
+#define SDHCI_COMMAND		0x0E
+#define  SDHCI_CMD_RESP_MASK	0x03
+#define  SDHCI_CMD_CRC		0x08
+#define  SDHCI_CMD_INDEX	0x10
+#define  SDHCI_CMD_DATA		0x20
+
+#define  SDHCI_CMD_RESP_NONE	0x00
+#define  SDHCI_CMD_RESP_LONG	0x01
+#define  SDHCI_CMD_RESP_SHORT	0x02
+#define  SDHCI_CMD_RESP_SHORT_BUSY 0x03
+
+#define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff))
+
+#define SDHCI_RESPONSE		0x10
+
+#define SDHCI_BUFFER		0x20
+
+#define SDHCI_PRESENT_STATE	0x24
+#define  SDHCI_CMD_INHIBIT	0x00000001
+#define  SDHCI_DATA_INHIBIT	0x00000002
+#define  SDHCI_DOING_WRITE	0x00000100
+#define  SDHCI_DOING_READ	0x00000200
+#define  SDHCI_SPACE_AVAILABLE	0x00000400
+#define  SDHCI_DATA_AVAILABLE	0x00000800
+#define  SDHCI_CARD_PRESENT	0x00010000
+#define  SDHCI_WRITE_PROTECT	0x00080000
+
+#define SDHCI_HOST_CONTROL 	0x28
+#define  SDHCI_CTRL_LED		0x01
+#define  SDHCI_CTRL_4BITBUS	0x02
+
+#define SDHCI_POWER_CONTROL	0x29
+
+#define SDHCI_BLOCK_GAP_CONTROL	0x2A
+
+#define SDHCI_WALK_UP_CONTROL	0x2B
+
+#define SDHCI_CLOCK_CONTROL	0x2C
+#define  SDHCI_DIVIDER_SHIFT	8
+#define  SDHCI_CLOCK_CARD_EN	0x0004
+#define  SDHCI_CLOCK_INT_STABLE	0x0002
+#define  SDHCI_CLOCK_INT_EN	0x0001
+
+#define SDHCI_TIMEOUT_CONTROL	0x2E
+
+#define SDHCI_SOFTWARE_RESET	0x2F
+#define  SDHCI_RESET_ALL	0x01
+#define  SDHCI_RESET_CMD	0x02
+#define  SDHCI_RESET_DATA	0x04
+
+#define SDHCI_INT_STATUS	0x30
+#define SDHCI_INT_ENABLE	0x34
+#define SDHCI_SIGNAL_ENABLE	0x38
+#define  SDHCI_INT_RESPONSE	0x00000001
+#define  SDHCI_INT_DATA_END	0x00000002
+#define  SDHCI_INT_DMA_END	0x00000008
+#define  SDHCI_INT_BUF_EMPTY	0x00000010
+#define  SDHCI_INT_BUF_FULL	0x00000020
+#define  SDHCI_INT_CARD_INSERT	0x00000040
+#define  SDHCI_INT_CARD_REMOVE	0x00000080
+#define  SDHCI_INT_CARD_INT	0x00000100
+#define  SDHCI_INT_TIMEOUT	0x00010000
+#define  SDHCI_INT_CRC		0x00020000
+#define  SDHCI_INT_END_BIT	0x00040000
+#define  SDHCI_INT_INDEX	0x00080000
+#define  SDHCI_INT_DATA_TIMEOUT	0x00100000
+#define  SDHCI_INT_DATA_CRC	0x00200000
+#define  SDHCI_INT_DATA_END_BIT	0x00400000
+#define  SDHCI_INT_BUS_POWER	0x00800000
+#define  SDHCI_INT_ACMD12ERR	0x01000000
+
+#define  SDHCI_INT_NORMAL_MASK	0x00007FFF
+#define  SDHCI_INT_ERROR_MASK	0xFFFF8000
+
+#define  SDHCI_INT_CMD_MASK	(SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \
+		SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)
+#define  SDHCI_INT_DATA_MASK	(SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
+		SDHCI_INT_BUF_EMPTY | SDHCI_INT_BUF_FULL | \
+		SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
+		SDHCI_INT_DATA_END_BIT)
+
+#define SDHCI_ACMD12_ERR	0x3C
+
+/* 3E-3F reserved */
+
+#define SDHCI_CAPABILITIES	0x40
+#define  SDHCI_CAN_DO_DMA	0x00400000
+#define  SDHCI_CLOCK_BASE_MASK	0x00003F00
+#define  SDHCI_CLOCK_BASE_SHIFT	8
+
+/* 44-47 reserved for more caps */
+
+#define SDHCI_MAX_CURRENT	0x48
+
+/* 4C-4F reserved for more max current */
+
+/* 50-FB reserved */
+
+#define SDHCI_SLOT_INT_STATUS	0xFC
+
+#define SDHCI_HOST_VERSION	0xFE
+
+struct sdhci_chip;
+
+struct sdhci_host {
+	struct sdhci_chip	*chip;
+	struct mmc_host		*mmc;		/* MMC structure */
+
+	spinlock_t		lock;		/* Mutex */
+
+	int			flags;		/* Host attributes */
+#define SDHCI_USE_DMA		(1<<0)
+
+	unsigned int		max_clk;	/* Max possible freq (MHz) */
+
+	unsigned int		clock;		/* Current clock (MHz) */
+
+	struct mmc_request	*mrq;		/* Current request */
+	struct mmc_command	*cmd;		/* Current command */
+	struct mmc_data		*data;		/* Current data request */
+
+	struct scatterlist	*cur_sg;	/* We're working on this */
+	char			*mapped_sg;	/* This is where it's mapped */
+	int			num_sg;		/* Entries left */
+	int			offset;		/* Offset into current sg */
+	int			remain;		/* Bytes left in current */
+
+	int			size;		/* Remaining bytes in transfer */
+
+	char			slot_descr[20];	/* Name for reservations */
+
+	int			irq;		/* Device IRQ */
+	int			bar;		/* PCI BAR index */
+	unsigned long		addr;		/* Bus address */
+	void __iomem *		ioaddr;		/* Mapped address */
+
+	struct tasklet_struct	card_tasklet;	/* Tasklet structures */
+	struct tasklet_struct	finish_tasklet;
+
+	struct timer_list	timer;		/* Timer for timeouts */
+};
+
+struct sdhci_chip {
+	struct pci_dev		*pdev;
+
+	int			num_slots;	/* Slots on controller */
+	struct sdhci_host	*hosts[0];	/* Pointers to hosts */
+};
diff -urN oldtree/drivers/mtd/chips/cfi_cmdset_0001.c newtree/drivers/mtd/chips/cfi_cmdset_0001.c
--- oldtree/drivers/mtd/chips/cfi_cmdset_0001.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/mtd/chips/cfi_cmdset_0001.c	2006-02-21 15:58:08.631834320 +0000
@@ -1019,8 +1019,8 @@
 #define XIP_INVAL_CACHED_RANGE(map, from, size)  \
 	INVALIDATE_CACHED_RANGE(map, from, size)
 
-#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec)  \
-	UDELAY(map, chip, adr, usec)
+#define INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr, adr, len, usec)  \
+	UDELAY(map, chip, cmd_adr, usec)
 
 /*
  * Extra notes:
@@ -1052,7 +1052,7 @@
 	spin_lock(chip->mutex);  \
 } while (0)
 
-#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec)  \
+#define INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr, adr, len, usec)  \
 do {  \
 	spin_unlock(chip->mutex);  \
 	INVALIDATE_CACHED_RANGE(map, adr, len);  \
@@ -1284,7 +1284,7 @@
 	map_write(map, datum, adr);
 	chip->state = mode;
 
-	INVALIDATE_CACHE_UDELAY(map, chip,
+	INVALIDATE_CACHE_UDELAY(map, chip, adr,
 				adr, map_bankwidth(map),
 				chip->word_write_time);
 
@@ -1572,8 +1572,8 @@
 	map_write(map, CMD(0xd0), cmd_adr);
 	chip->state = FL_WRITING;
 
-	INVALIDATE_CACHE_UDELAY(map, chip,
-				cmd_adr, len,
+	INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr,
+				adr, len,
 				chip->buffer_write_time);
 
 	timeo = jiffies + (HZ/2);
@@ -1744,7 +1744,7 @@
 	chip->state = FL_ERASING;
 	chip->erase_suspended = 0;
 
-	INVALIDATE_CACHE_UDELAY(map, chip,
+	INVALIDATE_CACHE_UDELAY(map, chip, adr,
 				adr, len,
 				chip->erase_time*1000/2);
 
diff -urN oldtree/drivers/mtd/chips/sharp.c newtree/drivers/mtd/chips/sharp.c
--- oldtree/drivers/mtd/chips/sharp.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/mtd/chips/sharp.c	2006-02-21 15:58:15.226831728 +0000
@@ -64,7 +64,7 @@
 
 #undef AUTOUNLOCK  /* automatically unlocks blocks before erasing */
 
-struct mtd_info *sharp_probe(struct map_info *);
+static struct mtd_info *sharp_probe(struct map_info *);
 
 static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd);
 
@@ -96,7 +96,6 @@
 	struct flchip chips[1];
 };
 
-struct mtd_info *sharp_probe(struct map_info *map);
 static void sharp_destroy(struct mtd_info *mtd);
 
 static struct mtd_chip_driver sharp_chipdrv = {
@@ -107,7 +106,7 @@
 };
 
 
-struct mtd_info *sharp_probe(struct map_info *map)
+static struct mtd_info *sharp_probe(struct map_info *map)
 {
 	struct mtd_info *mtd = NULL;
 	struct sharp_info *sharp = NULL;
@@ -581,7 +580,7 @@
 
 }
 
-int __init sharp_probe_init(void)
+static int __init sharp_probe_init(void)
 {
 	printk("MTD Sharp chip driver <ds@lineo.com>\n");
 
diff -urN oldtree/drivers/mtd/devices/blkmtd.c newtree/drivers/mtd/devices/blkmtd.c
--- oldtree/drivers/mtd/devices/blkmtd.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/mtd/devices/blkmtd.c	2006-02-21 15:58:15.036860608 +0000
@@ -29,7 +29,7 @@
 #include <linux/list.h>
 #include <linux/init.h>
 #include <linux/mtd/mtd.h>
-
+#include <linux/mutex.h>
 
 #define err(format, arg...) printk(KERN_ERR "blkmtd: " format "\n" , ## arg)
 #define info(format, arg...) printk(KERN_INFO "blkmtd: " format "\n" , ## arg)
@@ -46,7 +46,7 @@
 	struct list_head list;
 	struct block_device *blkdev;
 	struct mtd_info mtd_info;
-	struct semaphore wrbuf_mutex;
+	struct mutex wrbuf_mutex;
 };
 
 
@@ -268,7 +268,7 @@
 	if(end_len)
 		pagecnt++;
 
-	down(&dev->wrbuf_mutex);
+	mutex_lock(&dev->wrbuf_mutex);
 
 	DEBUG(3, "blkmtd: write: start_len = %zd len = %zd end_len = %zd pagecnt = %d\n",
 	      start_len, len, end_len, pagecnt);
@@ -376,7 +376,7 @@
 		blkmtd_write_out(bio);
 
 	DEBUG(2, "blkmtd: write: end, retlen = %zd, err = %d\n", *retlen, err);
-	up(&dev->wrbuf_mutex);
+	mutex_unlock(&dev->wrbuf_mutex);
 
 	if(retlen)
 		*retlen = thislen;
@@ -659,7 +659,7 @@
 	memset(dev, 0, sizeof(struct blkmtd_dev));
 	dev->blkdev = bdev;
 	if(!readonly) {
-		init_MUTEX(&dev->wrbuf_mutex);
+		mutex_init(&dev->wrbuf_mutex);
 	}
 
 	dev->mtd_info.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
diff -urN oldtree/drivers/mtd/devices/block2mtd.c newtree/drivers/mtd/devices/block2mtd.c
--- oldtree/drivers/mtd/devices/block2mtd.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/mtd/devices/block2mtd.c	2006-02-21 15:58:15.037860456 +0000
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/mtd/mtd.h>
 #include <linux/buffer_head.h>
+#include <linux/mutex.h>
 
 #define VERSION "$Revision: 1.30 $"
 
@@ -31,7 +32,7 @@
 	struct list_head list;
 	struct block_device *blkdev;
 	struct mtd_info mtd;
-	struct semaphore write_mutex;
+	struct mutex write_mutex;
 };
 
 
@@ -134,9 +135,9 @@
 	int err;
 
 	instr->state = MTD_ERASING;
-	down(&dev->write_mutex);
+	mutex_lock(&dev->write_mutex);
 	err = _block2mtd_erase(dev, from, len);
-	up(&dev->write_mutex);
+	mutex_unlock(&dev->write_mutex);
 	if (err) {
 		ERROR("erase failed err = %d", err);
 		instr->state = MTD_ERASE_FAILED;
@@ -249,9 +250,9 @@
 	if (to + len > mtd->size)
 		len = mtd->size - to;
 
-	down(&dev->write_mutex);
+	mutex_lock(&dev->write_mutex);
 	err = _block2mtd_write(dev, buf, to, len, retlen);
-	up(&dev->write_mutex);
+	mutex_unlock(&dev->write_mutex);
 	if (err > 0)
 		err = 0;
 	return err;
@@ -310,7 +311,7 @@
 		goto devinit_err;
 	}
 
-	init_MUTEX(&dev->write_mutex);
+	mutex_init(&dev->write_mutex);
 
 	/* Setup the MTD structure */
 	/* make the name contain the block device in */
diff -urN oldtree/drivers/mtd/devices/doc2000.c newtree/drivers/mtd/devices/doc2000.c
--- oldtree/drivers/mtd/devices/doc2000.c	2006-02-19 11:41:03.109870328 +0000
+++ newtree/drivers/mtd/devices/doc2000.c	2006-02-21 15:58:15.038860304 +0000
@@ -20,6 +20,7 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/bitops.h>
+#include <linux/mutex.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -605,7 +606,7 @@
 
 	this->curfloor = -1;
 	this->curchip = -1;
-	init_MUTEX(&this->lock);
+	mutex_init(&this->lock);
 
 	/* Ident all the chips present. */
 	DoC_ScanChips(this, maxchips);
@@ -645,7 +646,7 @@
 	if (from >= this->totlen)
 		return -EINVAL;
 
-	down(&this->lock);
+	mutex_lock(&this->lock);
 
 	*retlen = 0;
 	while (left) {
@@ -774,7 +775,7 @@
 		buf += len;
 	}
 
-	up(&this->lock);
+	mutex_unlock(&this->lock);
 
 	return ret;
 }
@@ -803,7 +804,7 @@
 	if (to >= this->totlen)
 		return -EINVAL;
 
-	down(&this->lock);
+	mutex_lock(&this->lock);
 
 	*retlen = 0;
 	while (left) {
@@ -873,7 +874,7 @@
 				printk(KERN_ERR "Error programming flash\n");
 				/* Error in programming */
 				*retlen = 0;
-				up(&this->lock);
+				mutex_unlock(&this->lock);
 				return -EIO;
 			}
 
@@ -935,7 +936,7 @@
 			printk(KERN_ERR "Error programming flash\n");
 			/* Error in programming */
 			*retlen = 0;
-			up(&this->lock);
+			mutex_unlock(&this->lock);
 			return -EIO;
 		}
 
@@ -956,7 +957,7 @@
 
 			ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x);
 			if (ret) {
-				up(&this->lock);
+				mutex_unlock(&this->lock);
 				return ret;
 			}
 		}
@@ -966,7 +967,7 @@
 		buf += len;
 	}
 
-	up(&this->lock);
+	mutex_unlock(&this->lock);
 	return 0;
 }
 
@@ -975,13 +976,13 @@
 			  u_char *eccbuf, struct nand_oobinfo *oobsel)
 {
 	static char static_buf[512];
-	static DECLARE_MUTEX(writev_buf_sem);
+	static DEFINE_MUTEX(writev_buf_mutex);
 
 	size_t totretlen = 0;
 	size_t thisvecofs = 0;
 	int ret= 0;
 
-	down(&writev_buf_sem);
+	mutex_lock(&writev_buf_mutex);
 
 	while(count) {
 		size_t thislen, thisretlen;
@@ -1024,7 +1025,7 @@
 		to += thislen;
 	}
 
-	up(&writev_buf_sem);
+	mutex_unlock(&writev_buf_mutex);
 	*retlen = totretlen;
 	return ret;
 }
@@ -1037,7 +1038,7 @@
 	int len256 = 0, ret;
 	struct Nand *mychip;
 
-	down(&this->lock);
+	mutex_lock(&this->lock);
 
 	mychip = &this->chips[ofs >> this->chipshift];
 
@@ -1083,7 +1084,7 @@
 
 	ret = DoC_WaitReady(this);
 
-	up(&this->lock);
+	mutex_unlock(&this->lock);
 	return ret;
 
 }
@@ -1197,10 +1198,10 @@
  	struct DiskOnChip *this = mtd->priv;
  	int ret;
 
- 	down(&this->lock);
+ 	mutex_lock(&this->lock);
  	ret = doc_write_oob_nolock(mtd, ofs, len, retlen, buf);
 
- 	up(&this->lock);
+ 	mutex_unlock(&this->lock);
  	return ret;
 }
 
@@ -1214,10 +1215,10 @@
 	struct Nand *mychip;
 	int status;
 
- 	down(&this->lock);
+ 	mutex_lock(&this->lock);
 
 	if (ofs & (mtd->erasesize-1) || len & (mtd->erasesize-1)) {
-		up(&this->lock);
+		mutex_unlock(&this->lock);
 		return -EINVAL;
 	}
 
@@ -1265,7 +1266,7 @@
  callback:
 	mtd_erase_callback(instr);
 
-	up(&this->lock);
+	mutex_unlock(&this->lock);
 	return 0;
 }
 
diff -urN oldtree/drivers/mtd/inftlcore.c newtree/drivers/mtd/inftlcore.c
--- oldtree/drivers/mtd/inftlcore.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/mtd/inftlcore.c	2006-02-21 15:58:15.234830512 +0000
@@ -47,9 +47,6 @@
  */
 #define MAX_LOOPS 10000
 
-extern void INFTL_dumptables(struct INFTLrecord *inftl);
-extern void INFTL_dumpVUchains(struct INFTLrecord *inftl);
-
 static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
 {
 	struct INFTLrecord *inftl;
@@ -885,8 +882,6 @@
 	.owner		= THIS_MODULE,
 };
 
-extern char inftlmountrev[];
-
 static int __init init_inftl(void)
 {
 	printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.19 $, "
diff -urN oldtree/drivers/mtd/mtd_blkdevs.c newtree/drivers/mtd/mtd_blkdevs.c
--- oldtree/drivers/mtd/mtd_blkdevs.c	2006-02-19 11:41:03.117869112 +0000
+++ newtree/drivers/mtd/mtd_blkdevs.c	2006-02-21 15:58:15.043859544 +0000
@@ -19,12 +19,12 @@
 #include <linux/spinlock.h>
 #include <linux/hdreg.h>
 #include <linux/init.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 static LIST_HEAD(blktrans_majors);
 
-extern struct semaphore mtd_table_mutex;
+extern struct mutex mtd_table_mutex;
 extern struct mtd_info *mtd_table[];
 
 struct mtd_blkcore_priv {
@@ -122,9 +122,9 @@
 
 		spin_unlock_irq(rq->queue_lock);
 
-		down(&dev->sem);
+		mutex_lock(&dev->lock);
 		res = do_blktrans_request(tr, dev, req);
-		up(&dev->sem);
+		mutex_unlock(&dev->lock);
 
 		spin_lock_irq(rq->queue_lock);
 
@@ -235,8 +235,8 @@
 	int last_devnum = -1;
 	struct gendisk *gd;
 
-	if (!down_trylock(&mtd_table_mutex)) {
-		up(&mtd_table_mutex);
+	if (!!mutex_trylock(&mtd_table_mutex)) {
+		mutex_unlock(&mtd_table_mutex);
 		BUG();
 	}
 
@@ -267,7 +267,7 @@
 		return -EBUSY;
 	}
 
-	init_MUTEX(&new->sem);
+	mutex_init(&new->lock);
 	list_add_tail(&new->list, &tr->devs);
  added:
 	if (!tr->writesect)
@@ -313,8 +313,8 @@
 
 int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
 {
-	if (!down_trylock(&mtd_table_mutex)) {
-		up(&mtd_table_mutex);
+	if (!!mutex_trylock(&mtd_table_mutex)) {
+		mutex_unlock(&mtd_table_mutex);
 		BUG();
 	}
 
@@ -378,14 +378,14 @@
 
 	memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv));
 
-	down(&mtd_table_mutex);
+	mutex_lock(&mtd_table_mutex);
 
 	ret = register_blkdev(tr->major, tr->name);
 	if (ret) {
 		printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n",
 		       tr->name, tr->major, ret);
 		kfree(tr->blkcore_priv);
-		up(&mtd_table_mutex);
+		mutex_unlock(&mtd_table_mutex);
 		return ret;
 	}
 	spin_lock_init(&tr->blkcore_priv->queue_lock);
@@ -396,7 +396,7 @@
 	if (!tr->blkcore_priv->rq) {
 		unregister_blkdev(tr->major, tr->name);
 		kfree(tr->blkcore_priv);
-		up(&mtd_table_mutex);
+		mutex_unlock(&mtd_table_mutex);
 		return -ENOMEM;
 	}
 
@@ -407,7 +407,7 @@
 		blk_cleanup_queue(tr->blkcore_priv->rq);
 		unregister_blkdev(tr->major, tr->name);
 		kfree(tr->blkcore_priv);
-		up(&mtd_table_mutex);
+		mutex_unlock(&mtd_table_mutex);
 		return ret;
 	}
 
@@ -419,7 +419,7 @@
 			tr->add_mtd(tr, mtd_table[i]);
 	}
 
-	up(&mtd_table_mutex);
+	mutex_unlock(&mtd_table_mutex);
 
 	return 0;
 }
@@ -428,7 +428,7 @@
 {
 	struct list_head *this, *next;
 
-	down(&mtd_table_mutex);
+	mutex_lock(&mtd_table_mutex);
 
 	/* Clean up the kernel thread */
 	tr->blkcore_priv->exiting = 1;
@@ -446,7 +446,7 @@
 	blk_cleanup_queue(tr->blkcore_priv->rq);
 	unregister_blkdev(tr->major, tr->name);
 
-	up(&mtd_table_mutex);
+	mutex_unlock(&mtd_table_mutex);
 
 	kfree(tr->blkcore_priv);
 
diff -urN oldtree/drivers/mtd/mtdblock.c newtree/drivers/mtd/mtdblock.c
--- oldtree/drivers/mtd/mtdblock.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/mtd/mtdblock.c	2006-02-21 15:58:15.044859392 +0000
@@ -19,11 +19,13 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/blktrans.h>
+#include <linux/mutex.h>
+
 
 static struct mtdblk_dev {
 	struct mtd_info *mtd;
 	int count;
-	struct semaphore cache_sem;
+	struct mutex cache_mutex;
 	unsigned char *cache_data;
 	unsigned long cache_offset;
 	unsigned int cache_size;
@@ -284,7 +286,7 @@
 	mtdblk->count = 1;
 	mtdblk->mtd = mtd;
 
-	init_MUTEX (&mtdblk->cache_sem);
+	mutex_init(&mtdblk->cache_mutex);
 	mtdblk->cache_state = STATE_EMPTY;
 	if ((mtdblk->mtd->flags & MTD_CAP_RAM) != MTD_CAP_RAM &&
 	    mtdblk->mtd->erasesize) {
@@ -306,9 +308,9 @@
 
    	DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
 
-	down(&mtdblk->cache_sem);
+	mutex_lock(&mtdblk->cache_mutex);
 	write_cached_data(mtdblk);
-	up(&mtdblk->cache_sem);
+	mutex_unlock(&mtdblk->cache_mutex);
 
 	if (!--mtdblk->count) {
 		/* It was the last usage. Free the device */
@@ -327,9 +329,9 @@
 {
 	struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
 
-	down(&mtdblk->cache_sem);
+	mutex_lock(&mtdblk->cache_mutex);
 	write_cached_data(mtdblk);
-	up(&mtdblk->cache_sem);
+	mutex_unlock(&mtdblk->cache_mutex);
 
 	if (mtdblk->mtd->sync)
 		mtdblk->mtd->sync(mtdblk->mtd);
diff -urN oldtree/drivers/mtd/mtdcore.c newtree/drivers/mtd/mtdcore.c
--- oldtree/drivers/mtd/mtdcore.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/mtd/mtdcore.c	2006-02-21 15:58:15.044859392 +0000
@@ -27,7 +27,7 @@
 
 /* These are exported solely for the purpose of mtd_blkdevs.c. You
    should not use them for _anything_ else */
-DECLARE_MUTEX(mtd_table_mutex);
+DEFINE_MUTEX(mtd_table_mutex);
 struct mtd_info *mtd_table[MAX_MTD_DEVICES];
 
 EXPORT_SYMBOL_GPL(mtd_table_mutex);
@@ -49,7 +49,7 @@
 {
 	int i;
 
-	down(&mtd_table_mutex);
+	mutex_lock(&mtd_table_mutex);
 
 	for (i=0; i < MAX_MTD_DEVICES; i++)
 		if (!mtd_table[i]) {
@@ -67,7 +67,7 @@
 				not->add(mtd);
 			}
 
-			up(&mtd_table_mutex);
+			mutex_unlock(&mtd_table_mutex);
 			/* We _know_ we aren't being removed, because
 			   our caller is still holding us here. So none
 			   of this try_ nonsense, and no bitching about it
@@ -76,7 +76,7 @@
 			return 0;
 		}
 
-	up(&mtd_table_mutex);
+	mutex_unlock(&mtd_table_mutex);
 	return 1;
 }
 
@@ -94,7 +94,7 @@
 {
 	int ret;
 
-	down(&mtd_table_mutex);
+	mutex_lock(&mtd_table_mutex);
 
 	if (mtd_table[mtd->index] != mtd) {
 		ret = -ENODEV;
@@ -118,7 +118,7 @@
 		ret = 0;
 	}
 
-	up(&mtd_table_mutex);
+	mutex_unlock(&mtd_table_mutex);
 	return ret;
 }
 
@@ -135,7 +135,7 @@
 {
 	int i;
 
-	down(&mtd_table_mutex);
+	mutex_lock(&mtd_table_mutex);
 
 	list_add(&new->list, &mtd_notifiers);
 
@@ -145,7 +145,7 @@
 		if (mtd_table[i])
 			new->add(mtd_table[i]);
 
-	up(&mtd_table_mutex);
+	mutex_unlock(&mtd_table_mutex);
 }
 
 /**
@@ -162,7 +162,7 @@
 {
 	int i;
 
-	down(&mtd_table_mutex);
+	mutex_lock(&mtd_table_mutex);
 
 	module_put(THIS_MODULE);
 
@@ -171,7 +171,7 @@
 			old->remove(mtd_table[i]);
 
 	list_del(&old->list);
-	up(&mtd_table_mutex);
+	mutex_unlock(&mtd_table_mutex);
 	return 0;
 }
 
@@ -193,7 +193,7 @@
 	struct mtd_info *ret = NULL;
 	int i;
 
-	down(&mtd_table_mutex);
+	mutex_lock(&mtd_table_mutex);
 
 	if (num == -1) {
 		for (i=0; i< MAX_MTD_DEVICES; i++)
@@ -211,7 +211,7 @@
 	if (ret)
 		ret->usecount++;
 
-	up(&mtd_table_mutex);
+	mutex_unlock(&mtd_table_mutex);
 	return ret;
 }
 
@@ -219,9 +219,9 @@
 {
 	int c;
 
-	down(&mtd_table_mutex);
+	mutex_lock(&mtd_table_mutex);
 	c = --mtd->usecount;
-	up(&mtd_table_mutex);
+	mutex_unlock(&mtd_table_mutex);
 	BUG_ON(c < 0);
 
 	module_put(mtd->owner);
@@ -319,7 +319,7 @@
 	int len, l, i;
         off_t   begin = 0;
 
-	down(&mtd_table_mutex);
+	mutex_lock(&mtd_table_mutex);
 
 	len = sprintf(page, "dev:    size   erasesize  name\n");
         for (i=0; i< MAX_MTD_DEVICES; i++) {
@@ -337,7 +337,7 @@
         *eof = 1;
 
 done:
-	up(&mtd_table_mutex);
+	mutex_unlock(&mtd_table_mutex);
         if (off >= len+begin)
                 return 0;
         *start = page + (off-begin);
diff -urN oldtree/drivers/mtd/nand/nand_base.c newtree/drivers/mtd/nand/nand_base.c
--- oldtree/drivers/mtd/nand/nand_base.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/mtd/nand/nand_base.c	2006-02-21 15:58:31.346381184 +0000
@@ -80,6 +80,7 @@
 #include <linux/mtd/compatmac.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
+#include <linux/leds.h>
 #include <asm/io.h>
 
 #ifdef CONFIG_MTD_PARTITIONS
@@ -515,6 +516,8 @@
 	return nand_isbad_bbt (mtd, ofs, allowbbt);
 }
 
+DEFINE_LED_TRIGGER(nand_led_trigger);
+
 /*
  * Wait for the ready pin, after a command
  * The timeout is catched later.
@@ -524,12 +527,14 @@
 	struct nand_chip *this = mtd->priv;
 	unsigned long	timeo = jiffies + 2;
 
+	led_trigger_event(nand_led_trigger, LED_FULL);
 	/* wait until command is processed or timeout occures */
 	do {
 		if (this->dev_ready(mtd))
-			return;
+			break;
 		touch_softlockup_watchdog();
 	} while (time_before(jiffies, timeo));
+	led_trigger_event(nand_led_trigger, LED_OFF);
 }
 
 /**
@@ -817,6 +822,8 @@
 	else
 		 timeo += (HZ * 20) / 1000;
 
+	led_trigger_event(nand_led_trigger, LED_FULL);
+
 	/* Apply this short delay always to ensure that we do wait tWB in
 	 * any case on any machine. */
 	ndelay (100);
@@ -840,6 +847,8 @@
 		}
 		cond_resched();
 	}
+	led_trigger_event(nand_led_trigger, LED_OFF);
+
 	status = (int) this->read_byte(mtd);
 	return status;
 }
@@ -2724,6 +2733,21 @@
 EXPORT_SYMBOL_GPL (nand_scan);
 EXPORT_SYMBOL_GPL (nand_release);
 
+
+static int __init nand_base_init(void)
+{
+	led_trigger_register_simple("nand-disk", &nand_led_trigger);
+	return 0;
+}
+
+static void __exit nand_base_exit(void)
+{
+	led_trigger_unregister_simple(nand_led_trigger);
+}
+
+module_init(nand_base_init);
+module_exit(nand_base_exit);
+
 MODULE_LICENSE ("GPL");
 MODULE_AUTHOR ("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
 MODULE_DESCRIPTION ("Generic NAND flash driver code");
diff -urN oldtree/drivers/net/3c523.c newtree/drivers/net/3c523.c
--- oldtree/drivers/net/3c523.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/3c523.c	2006-02-21 15:58:15.283823064 +0000
@@ -105,6 +105,7 @@
 #include <linux/mca-legacy.h>
 #include <linux/ethtool.h>
 #include <linux/bitops.h>
+#include <linux/jiffies.h>
 
 #include <asm/uaccess.h>
 #include <asm/processor.h>
@@ -658,7 +659,7 @@
 
 	s = jiffies;		/* warning: only active with interrupts on !! */
 	while (!(cfg_cmd->cmd_status & STAT_COMPL)) {
-		if (jiffies - s > 30*HZ/100)
+		if (time_after(jiffies, s + 30*HZ/100))
 			break;
 	}
 
@@ -684,7 +685,7 @@
 
 	s = jiffies;
 	while (!(ias_cmd->cmd_status & STAT_COMPL)) {
-		if (jiffies - s > 30*HZ/100)
+		if (time_after(jiffies, s + 30*HZ/100))
 			break;
 	}
 
@@ -709,7 +710,7 @@
 
 	s = jiffies;
 	while (!(tdr_cmd->cmd_status & STAT_COMPL)) {
-		if (jiffies - s > 30*HZ/100) {
+		if (time_after(jiffies, s + 30*HZ/100)) {
 			printk(KERN_WARNING "%s: %d Problems while running the TDR.\n", dev->name, __LINE__);
 			result = 1;
 			break;
@@ -798,7 +799,7 @@
 			elmc_id_attn586();
 			s = jiffies;
 			while (!(mc_cmd->cmd_status & STAT_COMPL)) {
-				if (jiffies - s > 30*HZ/100)
+				if (time_after(jiffies, s + 30*HZ/100))
 					break;
 			}
 			if (!(mc_cmd->cmd_status & STAT_COMPL)) {
diff -urN oldtree/drivers/net/3c59x.c newtree/drivers/net/3c59x.c
--- oldtree/drivers/net/3c59x.c	2006-02-19 11:41:03.125867896 +0000
+++ newtree/drivers/net/3c59x.c	2006-02-21 15:58:15.308819264 +0000
@@ -258,6 +258,7 @@
 #include <linux/highmem.h>
 #include <linux/eisa.h>
 #include <linux/bitops.h>
+#include <linux/jiffies.h>
 #include <asm/irq.h>			/* For NR_IRQS only. */
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -2724,7 +2725,7 @@
 			skb = dev_alloc_skb(PKT_BUF_SZ);
 			if (skb == NULL) {
 				static unsigned long last_jif;
-				if ((jiffies - last_jif) > 10 * HZ) {
+				if (time_after(jiffies, last_jif + 10 * HZ)) {
 					printk(KERN_WARNING "%s: memory shortage\n", dev->name);
 					last_jif = jiffies;
 				}
diff -urN oldtree/drivers/net/7990.c newtree/drivers/net/7990.c
--- oldtree/drivers/net/7990.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/7990.c	2006-02-21 15:58:15.309819112 +0000
@@ -29,7 +29,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/skbuff.h>
-#include <linux/irq.h>
+#include <asm/irq.h>
 /* Used for the temporal inet entries and routing */
 #include <linux/socket.h>
 #include <linux/bitops.h>
diff -urN oldtree/drivers/net/8139cp.c newtree/drivers/net/8139cp.c
--- oldtree/drivers/net/8139cp.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/8139cp.c	2006-02-21 15:58:15.791745848 +0000
@@ -1196,20 +1196,11 @@
 
 	cp_init_hw(cp);
 
-	rc = request_irq(dev->irq, cp_interrupt, SA_SHIRQ, dev->name, dev);
-	if (rc)
-		goto err_out_hw;
-
 	netif_carrier_off(dev);
 	mii_check_media(&cp->mii_if, netif_msg_link(cp), TRUE);
 	netif_start_queue(dev);
 
 	return 0;
-
-err_out_hw:
-	cp_stop_hw(cp);
-	cp_free_rings(cp);
-	return rc;
 }
 
 static int cp_close (struct net_device *dev)
@@ -1230,7 +1221,6 @@
 	spin_unlock_irqrestore(&cp->lock, flags);
 
 	synchronize_irq(dev->irq);
-	free_irq(dev->irq, dev);
 
 	cp_free_rings(cp);
 	return 0;
@@ -1814,6 +1804,10 @@
 	if (rc)
 		goto err_out_iomap;
 
+	rc = request_irq(dev->irq, cp_interrupt, SA_SHIRQ, dev->name, dev);
+	if (rc)
+		goto err_out_unreg;
+
 	printk (KERN_INFO "%s: RTL-8139C+ at 0x%lx, "
 		"%02x:%02x:%02x:%02x:%02x:%02x, "
 		"IRQ %d\n",
@@ -1833,6 +1827,8 @@
 
 	return 0;
 
+err_out_unreg:
+	unregister_netdev(dev);
 err_out_iomap:
 	iounmap(regs);
 err_out_res:
@@ -1853,6 +1849,7 @@
 
 	if (!dev)
 		BUG();
+	free_irq(dev->irq, dev);
 	unregister_netdev(dev);
 	iounmap(cp->regs);
 	if (cp->wol_enabled) pci_set_power_state (pdev, PCI_D0);
diff -urN oldtree/drivers/net/8139too.c newtree/drivers/net/8139too.c
--- oldtree/drivers/net/8139too.c	2006-02-19 11:41:03.128867440 +0000
+++ newtree/drivers/net/8139too.c	2006-02-21 15:58:16.574626832 +0000
@@ -1605,7 +1605,7 @@
 	if (tp->watchdog_fired) {
 		tp->watchdog_fired = 0;
 		rtl8139_tx_timeout_task(_data);
-	} else if (rtnl_shlock_nowait() == 0) {
+	} else if (rtnl_trylock()) {
 		rtl8139_thread_iter (dev, tp, tp->mmio_addr);
 		rtnl_unlock ();
 	} else {
diff -urN oldtree/drivers/net/82596.c newtree/drivers/net/82596.c
--- oldtree/drivers/net/82596.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/82596.c	2006-02-21 15:58:15.310818960 +0000
@@ -614,7 +614,7 @@
 static int init_i596_mem(struct net_device *dev)
 {
 	struct i596_private *lp = dev->priv;
-#if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET)
+#if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET) || defined(ENABLE_APRICOT)
 	short ioaddr = dev->base_addr;
 #endif
 	unsigned long flags;
diff -urN oldtree/drivers/net/8390.c newtree/drivers/net/8390.c
--- oldtree/drivers/net/8390.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/8390.c	2006-02-21 15:58:36.302627720 +0000
@@ -1,1109 +1,40 @@
-/* 8390.c: A general NS8390 ethernet driver core for linux. */
-/*
-	Written 1992-94 by Donald Becker.
-  
-	Copyright 1993 United States Government as represented by the
-	Director, National Security Agency.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-  
-  This is the chip-specific code for many 8390-based ethernet adaptors.
-  This is not a complete driver, it must be combined with board-specific
-  code such as ne.c, wd.c, 3c503.c, etc.
-
-  Seeing how at least eight drivers use this code, (not counting the
-  PCMCIA ones either) it is easy to break some card by what seems like
-  a simple innocent change. Please contact me or Donald if you think
-  you have found something that needs changing. -- PG
-
-
-  Changelog:
-
-  Paul Gortmaker	: remove set_bit lock, other cleanups.
-  Paul Gortmaker	: add ei_get_8390_hdr() so we can pass skb's to 
-			  ei_block_input() for eth_io_copy_and_sum().
-  Paul Gortmaker	: exchange static int ei_pingpong for a #define,
-			  also add better Tx error handling.
-  Paul Gortmaker	: rewrite Rx overrun handling as per NS specs.
-  Alexey Kuznetsov	: use the 8390's six bit hash multicast filter.
-  Paul Gortmaker	: tweak ANK's above multicast changes a bit.
-  Paul Gortmaker	: update packet statistics for v2.1.x
-  Alan Cox		: support arbitary stupid port mappings on the
-  			  68K Macintosh. Support >16bit I/O spaces
-  Paul Gortmaker	: add kmod support for auto-loading of the 8390
-			  module by all drivers that require it.
-  Alan Cox		: Spinlocking work, added 'BUG_83C690'
-  Paul Gortmaker	: Separate out Tx timeout code from Tx path.
-  Paul Gortmaker	: Remove old unused single Tx buffer code.
-  Hayato Fujiwara	: Add m32r support.
-  Paul Gortmaker	: use skb_padto() instead of stack scratch area
-
-  Sources:
-  The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
-
-  */
+/* 8390 core for usual drivers */
 
 static const char version[] =
     "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/fs.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/bitops.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fcntl.h>
-#include <linux/in.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/crc32.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-
-#define NS8390_CORE
-#include "8390.h"
-
-#define BUG_83C690
-
-/* These are the operational function interfaces to board-specific
-   routines.
-	void reset_8390(struct net_device *dev)
-		Resets the board associated with DEV, including a hardware reset of
-		the 8390.  This is only called when there is a transmit timeout, and
-		it is always followed by 8390_init().
-	void block_output(struct net_device *dev, int count, const unsigned char *buf,
-					  int start_page)
-		Write the COUNT bytes of BUF to the packet buffer at START_PAGE.  The
-		"page" value uses the 8390's 256-byte pages.
-	void get_8390_hdr(struct net_device *dev, struct e8390_hdr *hdr, int ring_page)
-		Read the 4 byte, page aligned 8390 header. *If* there is a
-		subsequent read, it will be of the rest of the packet.
-	void block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-		Read COUNT bytes from the packet buffer into the skb data area. Start 
-		reading from RING_OFFSET, the address as the 8390 sees it.  This will always
-		follow the read of the 8390 header. 
-*/
-#define ei_reset_8390 (ei_local->reset_8390)
-#define ei_block_output (ei_local->block_output)
-#define ei_block_input (ei_local->block_input)
-#define ei_get_8390_hdr (ei_local->get_8390_hdr)
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef ei_debug
-int ei_debug = 1;
-#endif
+#include "lib8390.c"
 
-/* Index to functions. */
-static void ei_tx_intr(struct net_device *dev);
-static void ei_tx_err(struct net_device *dev);
-static void ei_tx_timeout(struct net_device *dev);
-static void ei_receive(struct net_device *dev);
-static void ei_rx_overrun(struct net_device *dev);
-
-/* Routines generic to NS8390-based boards. */
-static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
-								int start_page);
-static void set_multicast_list(struct net_device *dev);
-static void do_set_multicast_list(struct net_device *dev);
-
-/*
- *	SMP and the 8390 setup.
- *
- *	The 8390 isnt exactly designed to be multithreaded on RX/TX. There is
- *	a page register that controls bank and packet buffer access. We guard
- *	this with ei_local->page_lock. Nobody should assume or set the page other
- *	than zero when the lock is not held. Lock holders must restore page 0
- *	before unlocking. Even pure readers must take the lock to protect in 
- *	page 0.
- *
- *	To make life difficult the chip can also be very slow. We therefore can't
- *	just use spinlocks. For the longer lockups we disable the irq the device
- *	sits on and hold the lock. We must hold the lock because there is a dual
- *	processor case other than interrupts (get stats/set multicast list in
- *	parallel with each other and transmit).
- *
- *	Note: in theory we can just disable the irq on the card _but_ there is
- *	a latency on SMP irq delivery. So we can easily go "disable irq" "sync irqs"
- *	enter lock, take the queued irq. So we waddle instead of flying.
- *
- *	Finally by special arrangement for the purpose of being generally 
- *	annoying the transmit function is called bh atomic. That places
- *	restrictions on the user context callers as disable_irq won't save
- *	them.
- */
- 
-
-
-/**
- * ei_open - Open/initialize the board.
- * @dev: network device to initialize
- *
- * This routine goes all-out, setting everything
- * up anew at each open, even though many of these registers should only
- * need to be set once at boot.
- */
 int ei_open(struct net_device *dev)
 {
-	unsigned long flags;
-	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
-
-	/* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout
-	    wrapper that does e.g. media check & then calls ei_tx_timeout. */
-	if (dev->tx_timeout == NULL)
-		 dev->tx_timeout = ei_tx_timeout;
-	if (dev->watchdog_timeo <= 0)
-		 dev->watchdog_timeo = TX_TIMEOUT;
-    
-	/*
-	 *	Grab the page lock so we own the register set, then call
-	 *	the init function.
-	 */
-      
-      	spin_lock_irqsave(&ei_local->page_lock, flags);
-	NS8390_init(dev, 1);
-	/* Set the flag before we drop the lock, That way the IRQ arrives
-	   after its set and we get no silly warnings */
-	netif_start_queue(dev);
-      	spin_unlock_irqrestore(&ei_local->page_lock, flags);
-	ei_local->irqlock = 0;
-	return 0;
+	return __ei_open(dev);
 }
 
-/**
- * ei_close - shut down network device
- * @dev: network device to close
- *
- * Opposite of ei_open(). Only used when "ifconfig <devname> down" is done.
- */
 int ei_close(struct net_device *dev)
 {
-	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
-	unsigned long flags;
-
-	/*
-	 *	Hold the page lock during close
-	 */
-	 	
-      	spin_lock_irqsave(&ei_local->page_lock, flags);
-	NS8390_init(dev, 0);
-      	spin_unlock_irqrestore(&ei_local->page_lock, flags);
-	netif_stop_queue(dev);
-	return 0;
+	return __ei_close(dev);
 }
 
-/**
- * ei_tx_timeout - handle transmit time out condition
- * @dev: network device which has apparently fallen asleep
- *
- * Called by kernel when device never acknowledges a transmit has
- * completed (or failed) - i.e. never posted a Tx related interrupt.
- */
-
-void ei_tx_timeout(struct net_device *dev)
-{
-	long e8390_base = dev->base_addr;
-	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
-	int txsr, isr, tickssofar = jiffies - dev->trans_start;
-	unsigned long flags;
-
-#if defined(CONFIG_M32R) && defined(CONFIG_SMP)
-	unsigned long icucr;
-
-	local_irq_save(flags);
-	icucr = inl(M32R_ICU_CR1_PORTL);
-	icucr |= M32R_ICUCR_ISMOD11;
-	outl(icucr, M32R_ICU_CR1_PORTL);
-	local_irq_restore(flags);
-#endif
-	ei_local->stat.tx_errors++;
-
-	spin_lock_irqsave(&ei_local->page_lock, flags);
-	txsr = inb(e8390_base+EN0_TSR);
-	isr = inb(e8390_base+EN0_ISR);
-	spin_unlock_irqrestore(&ei_local->page_lock, flags);
-
-	printk(KERN_DEBUG "%s: Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n",
-		dev->name, (txsr & ENTSR_ABT) ? "excess collisions." :
-		(isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar);
-
-	if (!isr && !ei_local->stat.tx_packets) 
-	{
-		/* The 8390 probably hasn't gotten on the cable yet. */
-		ei_local->interface_num ^= 1;   /* Try a different xcvr.  */
-	}
-
-	/* Ugly but a reset can be slow, yet must be protected */
-		
-	disable_irq_nosync(dev->irq);
-	spin_lock(&ei_local->page_lock);
-		
-	/* Try to restart the card.  Perhaps the user has fixed something. */
-	ei_reset_8390(dev);
-	NS8390_init(dev, 1);
-		
-	spin_unlock(&ei_local->page_lock);
-	enable_irq(dev->irq);
-	netif_wake_queue(dev);
-}
-    
-/**
- * ei_start_xmit - begin packet transmission
- * @skb: packet to be sent
- * @dev: network device to which packet is sent
- *
- * Sends a packet to an 8390 network device.
- */
- 
-static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	long e8390_base = dev->base_addr;
-	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
-	int send_length = skb->len, output_page;
-	unsigned long flags;
-
-	if (skb->len < ETH_ZLEN) {
-		skb = skb_padto(skb, ETH_ZLEN);
-		if (skb == NULL)
-			return 0;
-		send_length = ETH_ZLEN;
-	}
-
-	/* Mask interrupts from the ethercard. 
-	   SMP: We have to grab the lock here otherwise the IRQ handler
-	   on another CPU can flip window and race the IRQ mask set. We end
-	   up trashing the mcast filter not disabling irqs if we don't lock */
-	   
-	spin_lock_irqsave(&ei_local->page_lock, flags);
-	outb_p(0x00, e8390_base + EN0_IMR);
-	spin_unlock_irqrestore(&ei_local->page_lock, flags);
-	
-	
-	/*
-	 *	Slow phase with lock held.
-	 */
-	 
-	disable_irq_nosync(dev->irq);
-	
-	spin_lock(&ei_local->page_lock);
-	
-	ei_local->irqlock = 1;
-
-	/*
-	 * We have two Tx slots available for use. Find the first free
-	 * slot, and then perform some sanity checks. With two Tx bufs,
-	 * you get very close to transmitting back-to-back packets. With
-	 * only one Tx buf, the transmitter sits idle while you reload the
-	 * card, leaving a substantial gap between each transmitted packet.
-	 */
-
-	if (ei_local->tx1 == 0) 
-	{
-		output_page = ei_local->tx_start_page;
-		ei_local->tx1 = send_length;
-		if (ei_debug  &&  ei_local->tx2 > 0)
-			printk(KERN_DEBUG "%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
-				dev->name, ei_local->tx2, ei_local->lasttx, ei_local->txing);
-	}
-	else if (ei_local->tx2 == 0) 
-	{
-		output_page = ei_local->tx_start_page + TX_PAGES/2;
-		ei_local->tx2 = send_length;
-		if (ei_debug  &&  ei_local->tx1 > 0)
-			printk(KERN_DEBUG "%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
-				dev->name, ei_local->tx1, ei_local->lasttx, ei_local->txing);
-	}
-	else
-	{	/* We should never get here. */
-		if (ei_debug)
-			printk(KERN_DEBUG "%s: No Tx buffers free! tx1=%d tx2=%d last=%d\n",
-				dev->name, ei_local->tx1, ei_local->tx2, ei_local->lasttx);
-		ei_local->irqlock = 0;
-		netif_stop_queue(dev);
-		outb_p(ENISR_ALL, e8390_base + EN0_IMR);
-		spin_unlock(&ei_local->page_lock);
-		enable_irq(dev->irq);
-		ei_local->stat.tx_errors++;
-		return 1;
-	}
-
-	/*
-	 * Okay, now upload the packet and trigger a send if the transmitter
-	 * isn't already sending. If it is busy, the interrupt handler will
-	 * trigger the send later, upon receiving a Tx done interrupt.
-	 */
-	 
-	ei_block_output(dev, send_length, skb->data, output_page);
-		
-	if (! ei_local->txing) 
-	{
-		ei_local->txing = 1;
-		NS8390_trigger_send(dev, send_length, output_page);
-		dev->trans_start = jiffies;
-		if (output_page == ei_local->tx_start_page) 
-		{
-			ei_local->tx1 = -1;
-			ei_local->lasttx = -1;
-		}
-		else 
-		{
-			ei_local->tx2 = -1;
-			ei_local->lasttx = -2;
-		}
-	}
-	else ei_local->txqueue++;
-
-	if (ei_local->tx1  &&  ei_local->tx2)
-		netif_stop_queue(dev);
-	else
-		netif_start_queue(dev);
-
-	/* Turn 8390 interrupts back on. */
-	ei_local->irqlock = 0;
-	outb_p(ENISR_ALL, e8390_base + EN0_IMR);
-	
-	spin_unlock(&ei_local->page_lock);
-	enable_irq(dev->irq);
-
-	dev_kfree_skb (skb);
-	ei_local->stat.tx_bytes += send_length;
-    
-	return 0;
-}
-
-/**
- * ei_interrupt - handle the interrupts from an 8390
- * @irq: interrupt number
- * @dev_id: a pointer to the net_device
- * @regs: unused
- *
- * Handle the ether interface interrupts. We pull packets from
- * the 8390 via the card specific functions and fire them at the networking
- * stack. We also handle transmit completions and wake the transmit path if
- * necessary. We also update the counters and do other housekeeping as
- * needed.
- */
-
 irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
-	struct net_device *dev = dev_id;
-	long e8390_base;
-	int interrupts, nr_serviced = 0;
-	struct ei_device *ei_local;
-    
-	if (dev == NULL) 
-	{
-		printk ("net_interrupt(): irq %d for unknown device.\n", irq);
-		return IRQ_NONE;
-	}
-    
-	e8390_base = dev->base_addr;
-	ei_local = (struct ei_device *) netdev_priv(dev);
-
-	/*
-	 *	Protect the irq test too.
-	 */
-	 
-	spin_lock(&ei_local->page_lock);
-
-	if (ei_local->irqlock) 
-	{
-#if 1 /* This might just be an interrupt for a PCI device sharing this line */
-		/* The "irqlock" check is only for testing. */
-		printk(ei_local->irqlock
-			   ? "%s: Interrupted while interrupts are masked! isr=%#2x imr=%#2x.\n"
-			   : "%s: Reentering the interrupt handler! isr=%#2x imr=%#2x.\n",
-			   dev->name, inb_p(e8390_base + EN0_ISR),
-			   inb_p(e8390_base + EN0_IMR));
-#endif
-		spin_unlock(&ei_local->page_lock);
-		return IRQ_NONE;
-	}
-    
-	/* Change to page 0 and read the intr status reg. */
-	outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
-	if (ei_debug > 3)
-		printk(KERN_DEBUG "%s: interrupt(isr=%#2.2x).\n", dev->name,
-			   inb_p(e8390_base + EN0_ISR));
-    
-	/* !!Assumption!! -- we stay in page 0.	 Don't break this. */
-	while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0
-		   && ++nr_serviced < MAX_SERVICE) 
-	{
-		if (!netif_running(dev)) {
-			printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name);
-			/* rmk - acknowledge the interrupts */
-			outb_p(interrupts, e8390_base + EN0_ISR);
-			interrupts = 0;
-			break;
-		}
-		if (interrupts & ENISR_OVER) 
-			ei_rx_overrun(dev);
-		else if (interrupts & (ENISR_RX+ENISR_RX_ERR)) 
-		{
-			/* Got a good (?) packet. */
-			ei_receive(dev);
-		}
-		/* Push the next to-transmit packet through. */
-		if (interrupts & ENISR_TX)
-			ei_tx_intr(dev);
-		else if (interrupts & ENISR_TX_ERR)
-			ei_tx_err(dev);
-
-		if (interrupts & ENISR_COUNTERS) 
-		{
-			ei_local->stat.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0);
-			ei_local->stat.rx_crc_errors   += inb_p(e8390_base + EN0_COUNTER1);
-			ei_local->stat.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2);
-			outb_p(ENISR_COUNTERS, e8390_base + EN0_ISR); /* Ack intr. */
-		}
-		
-		/* Ignore any RDC interrupts that make it back to here. */
-		if (interrupts & ENISR_RDC) 
-		{
-			outb_p(ENISR_RDC, e8390_base + EN0_ISR);
-		}
-
-		outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
-	}
-    
-	if (interrupts && ei_debug) 
-	{
-		outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
-		if (nr_serviced >= MAX_SERVICE) 
-		{
-			/* 0xFF is valid for a card removal */
-			if(interrupts!=0xFF)
-				printk(KERN_WARNING "%s: Too much work at interrupt, status %#2.2x\n",
-				   dev->name, interrupts);
-			outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */
-		} else {
-			printk(KERN_WARNING "%s: unknown interrupt %#2x\n", dev->name, interrupts);
-			outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
-		}
-	}
-	spin_unlock(&ei_local->page_lock);
-	return IRQ_RETVAL(nr_serviced > 0);
+	return __ei_interrupt(irq, dev_id, regs);
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 void ei_poll(struct net_device *dev)
 {
-	disable_irq(dev->irq);
-	ei_interrupt(dev->irq, dev, NULL);
-	enable_irq(dev->irq);
-}
-#endif
-
-/**
- * ei_tx_err - handle transmitter error
- * @dev: network device which threw the exception
- *
- * A transmitter error has happened. Most likely excess collisions (which
- * is a fairly normal condition). If the error is one where the Tx will
- * have been aborted, we try and send another one right away, instead of
- * letting the failed packet sit and collect dust in the Tx buffer. This
- * is a much better solution as it avoids kernel based Tx timeouts, and
- * an unnecessary card reset.
- *
- * Called with lock held.
- */
-
-static void ei_tx_err(struct net_device *dev)
-{
-	long e8390_base = dev->base_addr;
-	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
-	unsigned char txsr = inb_p(e8390_base+EN0_TSR);
-	unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
-
-#ifdef VERBOSE_ERROR_DUMP
-	printk(KERN_DEBUG "%s: transmitter error (%#2x): ", dev->name, txsr);
-	if (txsr & ENTSR_ABT)
-		printk("excess-collisions ");
-	if (txsr & ENTSR_ND)
-		printk("non-deferral ");
-	if (txsr & ENTSR_CRS)
-		printk("lost-carrier ");
-	if (txsr & ENTSR_FU)
-		printk("FIFO-underrun ");
-	if (txsr & ENTSR_CDH)
-		printk("lost-heartbeat ");
-	printk("\n");
-#endif
-
-	outb_p(ENISR_TX_ERR, e8390_base + EN0_ISR); /* Ack intr. */
-
-	if (tx_was_aborted)
-		ei_tx_intr(dev);
-	else 
-	{
-		ei_local->stat.tx_errors++;
-		if (txsr & ENTSR_CRS) ei_local->stat.tx_carrier_errors++;
-		if (txsr & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++;
-		if (txsr & ENTSR_OWC) ei_local->stat.tx_window_errors++;
-	}
-}
-
-/**
- * ei_tx_intr - transmit interrupt handler
- * @dev: network device for which tx intr is handled
- *
- * We have finished a transmit: check for errors and then trigger the next
- * packet to be sent. Called with lock held.
- */
-
-static void ei_tx_intr(struct net_device *dev)
-{
-	long e8390_base = dev->base_addr;
-	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
-	int status = inb(e8390_base + EN0_TSR);
-    
-	outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */
-
-	/*
-	 * There are two Tx buffers, see which one finished, and trigger
-	 * the send of another one if it exists.
-	 */
-	ei_local->txqueue--;
-
-	if (ei_local->tx1 < 0) 
-	{
-		if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
-			printk(KERN_ERR "%s: bogus last_tx_buffer %d, tx1=%d.\n",
-				ei_local->name, ei_local->lasttx, ei_local->tx1);
-		ei_local->tx1 = 0;
-		if (ei_local->tx2 > 0) 
-		{
-			ei_local->txing = 1;
-			NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
-			dev->trans_start = jiffies;
-			ei_local->tx2 = -1,
-			ei_local->lasttx = 2;
-		}
-		else ei_local->lasttx = 20, ei_local->txing = 0;	
-	}
-	else if (ei_local->tx2 < 0) 
-	{
-		if (ei_local->lasttx != 2  &&  ei_local->lasttx != -2)
-			printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
-				ei_local->name, ei_local->lasttx, ei_local->tx2);
-		ei_local->tx2 = 0;
-		if (ei_local->tx1 > 0) 
-		{
-			ei_local->txing = 1;
-			NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
-			dev->trans_start = jiffies;
-			ei_local->tx1 = -1;
-			ei_local->lasttx = 1;
-		}
-		else
-			ei_local->lasttx = 10, ei_local->txing = 0;
-	}
-//	else printk(KERN_WARNING "%s: unexpected TX-done interrupt, lasttx=%d.\n",
-//			dev->name, ei_local->lasttx);
-
-	/* Minimize Tx latency: update the statistics after we restart TXing. */
-	if (status & ENTSR_COL)
-		ei_local->stat.collisions++;
-	if (status & ENTSR_PTX)
-		ei_local->stat.tx_packets++;
-	else 
-	{
-		ei_local->stat.tx_errors++;
-		if (status & ENTSR_ABT) 
-		{
-			ei_local->stat.tx_aborted_errors++;
-			ei_local->stat.collisions += 16;
-		}
-		if (status & ENTSR_CRS) 
-			ei_local->stat.tx_carrier_errors++;
-		if (status & ENTSR_FU) 
-			ei_local->stat.tx_fifo_errors++;
-		if (status & ENTSR_CDH)
-			ei_local->stat.tx_heartbeat_errors++;
-		if (status & ENTSR_OWC)
-			ei_local->stat.tx_window_errors++;
-	}
-	netif_wake_queue(dev);
-}
-
-/**
- * ei_receive - receive some packets
- * @dev: network device with which receive will be run
- *
- * We have a good packet(s), get it/them out of the buffers. 
- * Called with lock held.
- */
-
-static void ei_receive(struct net_device *dev)
-{
-	long e8390_base = dev->base_addr;
-	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
-	unsigned char rxing_page, this_frame, next_frame;
-	unsigned short current_offset;
-	int rx_pkt_count = 0;
-	struct e8390_pkt_hdr rx_frame;
-	int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page;
-    
-	while (++rx_pkt_count < 10) 
-	{
-		int pkt_len, pkt_stat;
-		
-		/* Get the rx page (incoming packet pointer). */
-		outb_p(E8390_NODMA+E8390_PAGE1, e8390_base + E8390_CMD);
-		rxing_page = inb_p(e8390_base + EN1_CURPAG);
-		outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
-		
-		/* Remove one frame from the ring.  Boundary is always a page behind. */
-		this_frame = inb_p(e8390_base + EN0_BOUNDARY) + 1;
-		if (this_frame >= ei_local->stop_page)
-			this_frame = ei_local->rx_start_page;
-		
-		/* Someday we'll omit the previous, iff we never get this message.
-		   (There is at least one clone claimed to have a problem.)  
-		   
-		   Keep quiet if it looks like a card removal. One problem here
-		   is that some clones crash in roughly the same way.
-		 */
-		if (ei_debug > 0  &&  this_frame != ei_local->current_page && (this_frame!=0x0 || rxing_page!=0xFF))
-			printk(KERN_ERR "%s: mismatched read page pointers %2x vs %2x.\n",
-				   dev->name, this_frame, ei_local->current_page);
-		
-		if (this_frame == rxing_page)	/* Read all the frames? */
-			break;				/* Done for now */
-		
-		current_offset = this_frame << 8;
-		ei_get_8390_hdr(dev, &rx_frame, this_frame);
-		
-		pkt_len = rx_frame.count - sizeof(struct e8390_pkt_hdr);
-		pkt_stat = rx_frame.status;
-		
-		next_frame = this_frame + 1 + ((pkt_len+4)>>8);
-		
-		/* Check for bogosity warned by 3c503 book: the status byte is never
-		   written.  This happened a lot during testing! This code should be
-		   cleaned up someday. */
-		if (rx_frame.next != next_frame
-			&& rx_frame.next != next_frame + 1
-			&& rx_frame.next != next_frame - num_rx_pages
-			&& rx_frame.next != next_frame + 1 - num_rx_pages) {
-			ei_local->current_page = rxing_page;
-			outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY);
-			ei_local->stat.rx_errors++;
-			continue;
-		}
-
-		if (pkt_len < 60  ||  pkt_len > 1518) 
-		{
-			if (ei_debug)
-				printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n",
-					   dev->name, rx_frame.count, rx_frame.status,
-					   rx_frame.next);
-			ei_local->stat.rx_errors++;
-			ei_local->stat.rx_length_errors++;
-		}
-		 else if ((pkt_stat & 0x0F) == ENRSR_RXOK) 
-		{
-			struct sk_buff *skb;
-			
-			skb = dev_alloc_skb(pkt_len+2);
-			if (skb == NULL) 
-			{
-				if (ei_debug > 1)
-					printk(KERN_DEBUG "%s: Couldn't allocate a sk_buff of size %d.\n",
-						   dev->name, pkt_len);
-				ei_local->stat.rx_dropped++;
-				break;
-			}
-			else
-			{
-				skb_reserve(skb,2);	/* IP headers on 16 byte boundaries */
-				skb->dev = dev;
-				skb_put(skb, pkt_len);	/* Make room */
-				ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame));
-				skb->protocol=eth_type_trans(skb,dev);
-				netif_rx(skb);
-				dev->last_rx = jiffies;
-				ei_local->stat.rx_packets++;
-				ei_local->stat.rx_bytes += pkt_len;
-				if (pkt_stat & ENRSR_PHY)
-					ei_local->stat.multicast++;
-			}
-		} 
-		else 
-		{
-			if (ei_debug)
-				printk(KERN_DEBUG "%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n",
-					   dev->name, rx_frame.status, rx_frame.next,
-					   rx_frame.count);
-			ei_local->stat.rx_errors++;
-			/* NB: The NIC counts CRC, frame and missed errors. */
-			if (pkt_stat & ENRSR_FO)
-				ei_local->stat.rx_fifo_errors++;
-		}
-		next_frame = rx_frame.next;
-		
-		/* This _should_ never happen: it's here for avoiding bad clones. */
-		if (next_frame >= ei_local->stop_page) {
-			printk("%s: next frame inconsistency, %#2x\n", dev->name,
-				   next_frame);
-			next_frame = ei_local->rx_start_page;
-		}
-		ei_local->current_page = next_frame;
-		outb_p(next_frame-1, e8390_base+EN0_BOUNDARY);
-	}
-
-	/* We used to also ack ENISR_OVER here, but that would sometimes mask
-	   a real overrun, leaving the 8390 in a stopped state with rec'vr off. */
-	outb_p(ENISR_RX+ENISR_RX_ERR, e8390_base+EN0_ISR);
-	return;
-}
-
-/**
- * ei_rx_overrun - handle receiver overrun
- * @dev: network device which threw exception
- *
- * We have a receiver overrun: we have to kick the 8390 to get it started
- * again. Problem is that you have to kick it exactly as NS prescribes in
- * the updated datasheets, or "the NIC may act in an unpredictable manner."
- * This includes causing "the NIC to defer indefinitely when it is stopped
- * on a busy network."  Ugh.
- * Called with lock held. Don't call this with the interrupts off or your
- * computer will hate you - it takes 10ms or so. 
- */
-
-static void ei_rx_overrun(struct net_device *dev)
-{
-	long e8390_base = dev->base_addr;
-	unsigned char was_txing, must_resend = 0;
-	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
-    
-	/*
-	 * Record whether a Tx was in progress and then issue the
-	 * stop command.
-	 */
-	was_txing = inb_p(e8390_base+E8390_CMD) & E8390_TRANS;
-	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
-    
-	if (ei_debug > 1)
-		printk(KERN_DEBUG "%s: Receiver overrun.\n", dev->name);
-	ei_local->stat.rx_over_errors++;
-    
-	/* 
-	 * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
-	 * Early datasheets said to poll the reset bit, but now they say that
-	 * it "is not a reliable indicator and subsequently should be ignored."
-	 * We wait at least 10ms.
-	 */
-
-	mdelay(10);
-
-	/*
-	 * Reset RBCR[01] back to zero as per magic incantation.
-	 */
-	outb_p(0x00, e8390_base+EN0_RCNTLO);
-	outb_p(0x00, e8390_base+EN0_RCNTHI);
-
-	/*
-	 * See if any Tx was interrupted or not. According to NS, this
-	 * step is vital, and skipping it will cause no end of havoc.
-	 */
-
-	if (was_txing)
-	{ 
-		unsigned char tx_completed = inb_p(e8390_base+EN0_ISR) & (ENISR_TX+ENISR_TX_ERR);
-		if (!tx_completed)
-			must_resend = 1;
-	}
-
-	/*
-	 * Have to enter loopback mode and then restart the NIC before
-	 * you are allowed to slurp packets up off the ring.
-	 */
-	outb_p(E8390_TXOFF, e8390_base + EN0_TXCR);
-	outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
-
-	/*
-	 * Clear the Rx ring of all the debris, and ack the interrupt.
-	 */
-	ei_receive(dev);
-	outb_p(ENISR_OVER, e8390_base+EN0_ISR);
-
-	/*
-	 * Leave loopback mode, and resend any packet that got stopped.
-	 */
-	outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); 
-	if (must_resend)
-    		outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD);
-}
-
-/*
- *	Collect the stats. This is called unlocked and from several contexts.
- */
- 
-static struct net_device_stats *get_stats(struct net_device *dev)
-{
-	long ioaddr = dev->base_addr;
-	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
-	unsigned long flags;
-    
-	/* If the card is stopped, just return the present stats. */
-	if (!netif_running(dev))
-		return &ei_local->stat;
-
-	spin_lock_irqsave(&ei_local->page_lock,flags);
-	/* Read the counter registers, assuming we are in page 0. */
-	ei_local->stat.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0);
-	ei_local->stat.rx_crc_errors   += inb_p(ioaddr + EN0_COUNTER1);
-	ei_local->stat.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2);
-	spin_unlock_irqrestore(&ei_local->page_lock, flags);
-    
-	return &ei_local->stat;
+	__ei_poll(dev);
 }
-
-/*
- * Form the 64 bit 8390 multicast table from the linked list of addresses
- * associated with this dev structure.
- */
- 
-static inline void make_mc_bits(u8 *bits, struct net_device *dev)
-{
-	struct dev_mc_list *dmi;
-
-	for (dmi=dev->mc_list; dmi; dmi=dmi->next) 
-	{
-		u32 crc;
-		if (dmi->dmi_addrlen != ETH_ALEN) 
-		{
-			printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name);
-			continue;
-		}
-		crc = ether_crc(ETH_ALEN, dmi->dmi_addr);
-		/* 
-		 * The 8390 uses the 6 most significant bits of the
-		 * CRC to index the multicast table.
-		 */
-		bits[crc>>29] |= (1<<((crc>>26)&7));
-	}
-}
-
-/**
- * do_set_multicast_list - set/clear multicast filter
- * @dev: net device for which multicast filter is adjusted
- *
- *	Set or clear the multicast filter for this adaptor. May be called
- *	from a BH in 2.1.x. Must be called with lock held. 
- */
- 
-static void do_set_multicast_list(struct net_device *dev)
-{
-	long e8390_base = dev->base_addr;
-	int i;
-	struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
-
-	if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) 
-	{
-		memset(ei_local->mcfilter, 0, 8);
-		if (dev->mc_list)
-			make_mc_bits(ei_local->mcfilter, dev);
-	}
-	else
-		memset(ei_local->mcfilter, 0xFF, 8);	/* mcast set to accept-all */
-
-	/* 
-	 * DP8390 manuals don't specify any magic sequence for altering
-	 * the multicast regs on an already running card. To be safe, we
-	 * ensure multicast mode is off prior to loading up the new hash
-	 * table. If this proves to be not enough, we can always resort
-	 * to stopping the NIC, loading the table and then restarting.
-	 *
-	 * Bug Alert!  The MC regs on the SMC 83C690 (SMC Elite and SMC 
-	 * Elite16) appear to be write-only. The NS 8390 data sheet lists
-	 * them as r/w so this is a bug.  The SMC 83C790 (SMC Ultra and
-	 * Ultra32 EISA) appears to have this bug fixed.
-	 */
-	 
-	if (netif_running(dev))
-		outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
-	outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
-	for(i = 0; i < 8; i++) 
-	{
-		outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i));
-#ifndef BUG_83C690
-		if(inb_p(e8390_base + EN1_MULT_SHIFT(i))!=ei_local->mcfilter[i])
-			printk(KERN_ERR "Multicast filter read/write mismap %d\n",i);
 #endif
-	}
-	outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD);
-
-  	if(dev->flags&IFF_PROMISC)
-  		outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR);
-	else if(dev->flags&IFF_ALLMULTI || dev->mc_list)
-  		outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR);
-  	else
-  		outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
- }
-
-/*
- *	Called without lock held. This is invoked from user context and may
- *	be parallel to just about everything else. Its also fairly quick and
- *	not called too often. Must protect against both bh and irq users
- */
- 
-static void set_multicast_list(struct net_device *dev)
-{
-	unsigned long flags;
-	struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
-	
-	spin_lock_irqsave(&ei_local->page_lock, flags);
-	do_set_multicast_list(dev);
-	spin_unlock_irqrestore(&ei_local->page_lock, flags);
-}	
-
-/**
- * ethdev_setup - init rest of 8390 device struct
- * @dev: network device structure to init
- *
- * Initialize the rest of the 8390 device structure.  Do NOT __init
- * this, as it is used by 8390 based modular drivers too.
- */
-
-static void ethdev_setup(struct net_device *dev)
-{
-	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
-	if (ei_debug > 1)
-		printk(version);
-    
-	dev->hard_start_xmit = &ei_start_xmit;
-	dev->get_stats	= get_stats;
-	dev->set_multicast_list = &set_multicast_list;
 
-	ether_setup(dev);
-
-	spin_lock_init(&ei_local->page_lock);
-}
-
-/**
- * alloc_ei_netdev - alloc_etherdev counterpart for 8390
- * @size: extra bytes to allocate
- *
- * Allocate 8390-specific net_device.
- */
 struct net_device *__alloc_ei_netdev(int size)
 {
-	return alloc_netdev(sizeof(struct ei_device) + size, "eth%d",
-				ethdev_setup);
+	return ____alloc_ei_netdev(size);
 }
 
-
-
-
-/* This page of functions should be 8390 generic */
-/* Follow National Semi's recommendations for initializing the "NIC". */
-
-/**
- * NS8390_init - initialize 8390 hardware
- * @dev: network device to initialize
- * @startp: boolean.  non-zero value to initiate chip processing
- *
- *	Must be called with lock held.
- */
-
 void NS8390_init(struct net_device *dev, int startp)
 {
-	long e8390_base = dev->base_addr;
-	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
-	int i;
-	int endcfg = ei_local->word16
-	    ? (0x48 | ENDCFG_WTS | (ei_local->bigendian ? ENDCFG_BOS : 0))
-	    : 0x48;
-    
-	if(sizeof(struct e8390_pkt_hdr)!=4)
-    		panic("8390.c: header struct mispacked\n");    
-	/* Follow National Semi's recommendations for initing the DP83902. */
-	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); /* 0x21 */
-	outb_p(endcfg, e8390_base + EN0_DCFG);	/* 0x48 or 0x49 */
-	/* Clear the remote byte count registers. */
-	outb_p(0x00,  e8390_base + EN0_RCNTLO);
-	outb_p(0x00,  e8390_base + EN0_RCNTHI);
-	/* Set to monitor and loopback mode -- this is vital!. */
-	outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */
-	outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */
-	/* Set the transmit page and receive ring. */
-	outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR);
-	ei_local->tx1 = ei_local->tx2 = 0;
-	outb_p(ei_local->rx_start_page, e8390_base + EN0_STARTPG);
-	outb_p(ei_local->stop_page-1, e8390_base + EN0_BOUNDARY);	/* 3c503 says 0x3f,NS0x26*/
-	ei_local->current_page = ei_local->rx_start_page;		/* assert boundary+1 */
-	outb_p(ei_local->stop_page, e8390_base + EN0_STOPPG);
-	/* Clear the pending interrupts and mask. */
-	outb_p(0xFF, e8390_base + EN0_ISR);
-	outb_p(0x00,  e8390_base + EN0_IMR);
-    
-	/* Copy the station address into the DS8390 registers. */
-
-	outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* 0x61 */
-	for(i = 0; i < 6; i++) 
-	{
-		outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i));
-		if (ei_debug > 1 && inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
-			printk(KERN_ERR "Hw. address read/write mismap %d\n",i);
-	}
-
-	outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
-	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
-
-	netif_start_queue(dev);
-	ei_local->tx1 = ei_local->tx2 = 0;
-	ei_local->txing = 0;
-
-	if (startp) 
-	{
-		outb_p(0xff,  e8390_base + EN0_ISR);
-		outb_p(ENISR_ALL,  e8390_base + EN0_IMR);
-		outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD);
-		outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
-		/* 3c503 TechMan says rxconfig only after the NIC is started. */
-		outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on,  */
-		do_set_multicast_list(dev);	/* (re)load the mcast table */
-	}
-}
-
-/* Trigger a transmit start, assuming the length is valid. 
-   Always called with the page lock held */
-   
-static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
-								int start_page)
-{
-	long e8390_base = dev->base_addr;
- 	struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) netdev_priv(dev);
-   
-	outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD);
-    
-	if (inb_p(e8390_base + E8390_CMD) & E8390_TRANS) 
-	{
-		printk(KERN_WARNING "%s: trigger_send() called with the transmitter busy.\n",
-			dev->name);
-		return;
-	}
-	outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
-	outb_p(length >> 8, e8390_base + EN0_TCNTHI);
-	outb_p(start_page, e8390_base + EN0_TPSR);
-	outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base+E8390_CMD);
+	return __NS8390_init(dev, startp);
 }
 
 EXPORT_SYMBOL(ei_open);
diff -urN oldtree/drivers/net/Kconfig newtree/drivers/net/Kconfig
--- oldtree/drivers/net/Kconfig	2006-02-19 11:41:03.130867136 +0000
+++ newtree/drivers/net/Kconfig	2006-02-21 15:58:36.353619968 +0000
@@ -823,7 +823,7 @@
 	tristate "SMC 91C9x/91C1xxx support"
 	select CRC32
 	select MII
-	depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || SOC_AU1X00)
+	depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6 || (M32R && (BROKEN || !ISA)) || SUPERH || SOC_AU1X00)
 	help
 	  This is a driver for SMC's 91x series of Ethernet chipsets,
 	  including the SMC91C94 and the SMC91C111. Say Y if you want it
@@ -2314,13 +2314,11 @@
 
 endmenu
 
-if !UML
 source "drivers/net/tokenring/Kconfig"
 
 source "drivers/net/wireless/Kconfig"
 
 source "drivers/net/pcmcia/Kconfig"
-endif
 
 source "drivers/net/wan/Kconfig"
 
diff -urN oldtree/drivers/net/Makefile newtree/drivers/net/Makefile
--- oldtree/drivers/net/Makefile	2006-02-19 11:41:03.130867136 +0000
+++ newtree/drivers/net/Makefile	2006-02-21 15:58:36.363618448 +0000
@@ -82,7 +82,7 @@
 obj-$(CONFIG_NET) += Space.o loopback.o
 obj-$(CONFIG_SEEQ8005) += seeq8005.o
 obj-$(CONFIG_NET_SB1000) += sb1000.o
-obj-$(CONFIG_MAC8390) += mac8390.o 8390.o
+obj-$(CONFIG_MAC8390) += mac8390.o
 obj-$(CONFIG_APNE) += apne.o 8390.o
 obj-$(CONFIG_PCMCIA_PCNET) += 8390.o
 obj-$(CONFIG_SHAPER) += shaper.o
@@ -90,7 +90,6 @@
 obj-$(CONFIG_SMC9194) += smc9194.o
 obj-$(CONFIG_FEC) += fec.o
 obj-$(CONFIG_68360_ENET) += 68360enet.o
-obj-$(CONFIG_ARM_ETHERH) += 8390.o
 obj-$(CONFIG_WD80x3) += wd.o 8390.o
 obj-$(CONFIG_EL2) += 3c503.o 8390.o
 obj-$(CONFIG_NE2000) += ne.o 8390.o
@@ -166,7 +165,7 @@
 obj-$(CONFIG_LP486E) += lp486e.o
 
 obj-$(CONFIG_ETH16I) += eth16i.o
-obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o
+obj-$(CONFIG_ZORRO8390) += zorro8390.o
 obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
 obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
 obj-$(CONFIG_EQUALIZER) += eql.o
@@ -180,7 +179,7 @@
 obj-$(CONFIG_ATARI_BIONET) += atari_bionet.o
 obj-$(CONFIG_ATARI_PAMSNET) += atari_pamsnet.o
 obj-$(CONFIG_A2065) += a2065.o
-obj-$(CONFIG_HYDRA) += hydra.o 8390.o
+obj-$(CONFIG_HYDRA) += hydra.o
 obj-$(CONFIG_ARIADNE) += ariadne.o
 obj-$(CONFIG_CS89x0) += cs89x0.o
 obj-$(CONFIG_MACSONIC) += macsonic.o
diff -urN oldtree/drivers/net/apne.c newtree/drivers/net/apne.c
--- oldtree/drivers/net/apne.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/apne.c	2006-02-21 15:58:15.314818352 +0000
@@ -36,6 +36,7 @@
 #include <linux/delay.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/jiffies.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -216,7 +217,7 @@
 	outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);
 
 	while ((inb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0)
-		if (jiffies - reset_start_time > 2*HZ/100) {
+		if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
 			printk(" not found (no reset ack).\n");
 			return -ENODEV;
 		}
@@ -382,7 +383,7 @@
 
     /* This check _should_not_ be necessary, omit eventually. */
     while ((inb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0)
-	if (jiffies - reset_start_time > 2*HZ/100) {
+	if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
 	    printk("%s: ne_reset_8390() did not complete.\n", dev->name);
 	    break;
 	}
@@ -530,7 +531,7 @@
     dma_start = jiffies;
 
     while ((inb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0)
-	if (jiffies - dma_start > 2*HZ/100) {		/* 20ms */
+	if (time_after(jiffies, dma_start + 2*HZ/100)) {	/* 20ms */
 		printk("%s: timeout waiting for Tx RDC.\n", dev->name);
 		apne_reset_8390(dev);
 		NS8390_init(dev,1);
diff -urN oldtree/drivers/net/appletalk/ipddp.c newtree/drivers/net/appletalk/ipddp.c
--- oldtree/drivers/net/appletalk/ipddp.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/appletalk/ipddp.c	2006-02-21 15:58:36.311626352 +0000
@@ -146,9 +146,7 @@
 
 	/* Create the Extended DDP header */
 	ddp = (struct ddpehdr *)skb->data;
-        ddp->deh_len = skb->len;
-        ddp->deh_hops = 1;
-        ddp->deh_pad = 0;
+        ddp->deh_len_hops = htons(skb->len + (1<<10));
         ddp->deh_sum = 0;
 
 	/*
@@ -171,7 +169,6 @@
         ddp->deh_sport = 72;
 
         *((__u8 *)(ddp+1)) = 22;        	/* ddp type = IP */
-        *((__u16 *)ddp)=ntohs(*((__u16 *)ddp));	/* fix up length field */
 
         skb->protocol = htons(ETH_P_ATALK);     /* Protocol has changed */
 
diff -urN oldtree/drivers/net/arcnet/arc-rawmode.c newtree/drivers/net/arcnet/arc-rawmode.c
--- oldtree/drivers/net/arcnet/arc-rawmode.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/arcnet/arc-rawmode.c	2006-02-21 15:58:15.323816984 +0000
@@ -42,7 +42,7 @@
 static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
 		      int bufnum);
 
-struct ArcProto rawmode_proto =
+static struct ArcProto rawmode_proto =
 {
 	.suffix		= 'r',
 	.mtu		= XMTU,
diff -urN oldtree/drivers/net/arcnet/arc-rimi.c newtree/drivers/net/arcnet/arc-rimi.c
--- oldtree/drivers/net/arcnet/arc-rimi.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/arcnet/arc-rimi.c	2006-02-21 15:58:15.324816832 +0000
@@ -97,25 +97,44 @@
 		       "must specify the shmem and irq!\n");
 		return -ENODEV;
 	}
+	if (dev->dev_addr[0] == 0) {
+		BUGMSG(D_NORMAL, "You need to specify your card's station "
+		       "ID!\n");
+		return -ENODEV;
+	}
 	/*
-	 * Grab the memory region at mem_start for BUFFER_SIZE bytes.
+	 * Grab the memory region at mem_start for MIRROR_SIZE bytes.
 	 * Later in arcrimi_found() the real size will be determined
 	 * and this reserve will be released and the correct size
 	 * will be taken.
 	 */
-	if (!request_mem_region(dev->mem_start, BUFFER_SIZE, "arcnet (90xx)")) {
+	if (!request_mem_region(dev->mem_start, MIRROR_SIZE, "arcnet (90xx)")) {
 		BUGMSG(D_NORMAL, "Card memory already allocated\n");
 		return -ENODEV;
 	}
-	if (dev->dev_addr[0] == 0) {
-		release_mem_region(dev->mem_start, BUFFER_SIZE);
-		BUGMSG(D_NORMAL, "You need to specify your card's station "
-		       "ID!\n");
-		return -ENODEV;
-	}
 	return arcrimi_found(dev);
 }
 
+static int check_mirror(unsigned long addr, size_t size)
+{
+	void __iomem *p;
+	int res = -1;
+
+	if (!request_mem_region(addr, size, "arcnet (90xx)"))
+		return -1;
+
+	p = ioremap(addr, size);
+	if (p) {
+		if (readb(p) == TESTvalue)
+			res = 1;
+		else
+			res = 0;
+		iounmap(p);
+	}
+
+	release_mem_region(addr, size);
+	return res;
+}
 
 /*
  * Set up the struct net_device associated with this card.  Called after
@@ -125,19 +144,28 @@
 {
 	struct arcnet_local *lp;
 	unsigned long first_mirror, last_mirror, shmem;
+	void __iomem *p;
 	int mirror_size;
 	int err;
 
+	p = ioremap(dev->mem_start, MIRROR_SIZE);
+	if (!p) {
+		release_mem_region(dev->mem_start, MIRROR_SIZE);
+		BUGMSG(D_NORMAL, "Can't ioremap\n");
+		return -ENODEV;
+	}
+
 	/* reserve the irq */
 	if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet (RIM I)", dev)) {
-		release_mem_region(dev->mem_start, BUFFER_SIZE);
+		iounmap(p);
+		release_mem_region(dev->mem_start, MIRROR_SIZE);
 		BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq);
 		return -ENODEV;
 	}
 
 	shmem = dev->mem_start;
-	isa_writeb(TESTvalue, shmem);
-	isa_writeb(dev->dev_addr[0], shmem + 1);	/* actually the node ID */
+	writeb(TESTvalue, p);
+	writeb(dev->dev_addr[0], p + 1);	/* actually the node ID */
 
 	/* find the real shared memory start/end points, including mirrors */
 
@@ -146,17 +174,18 @@
 	 * 2k (or there are no mirrors at all) but on some, it's 4k.
 	 */
 	mirror_size = MIRROR_SIZE;
-	if (isa_readb(shmem) == TESTvalue
-	    && isa_readb(shmem - mirror_size) != TESTvalue
-	    && isa_readb(shmem - 2 * mirror_size) == TESTvalue)
-		mirror_size *= 2;
+	if (readb(p) == TESTvalue
+	    && check_mirror(shmem - MIRROR_SIZE, MIRROR_SIZE) == 0
+	    && check_mirror(shmem - 2 * MIRROR_SIZE, MIRROR_SIZE) == 1)
+		mirror_size = 2 * MIRROR_SIZE;
 
-	first_mirror = last_mirror = shmem;
-	while (isa_readb(first_mirror) == TESTvalue)
+	first_mirror = shmem - mirror_size;
+	while (check_mirror(first_mirror, mirror_size) == 1)
 		first_mirror -= mirror_size;
 	first_mirror += mirror_size;
 
-	while (isa_readb(last_mirror) == TESTvalue)
+	last_mirror = shmem + mirror_size;
+	while (check_mirror(last_mirror, mirror_size) == 1)
 		last_mirror += mirror_size;
 	last_mirror -= mirror_size;
 
@@ -181,7 +210,8 @@
 	 * with the correct size.  There is a VERY slim chance this could
 	 * fail.
 	 */
-	release_mem_region(shmem, BUFFER_SIZE);
+	iounmap(p);
+	release_mem_region(shmem, MIRROR_SIZE);
 	if (!request_mem_region(dev->mem_start,
 				dev->mem_end - dev->mem_start + 1,
 				"arcnet (90xx)")) {
diff -urN oldtree/drivers/net/arcnet/arcnet.c newtree/drivers/net/arcnet/arcnet.c
--- oldtree/drivers/net/arcnet/arcnet.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/arcnet/arcnet.c	2006-02-21 15:58:15.325816680 +0000
@@ -52,6 +52,7 @@
 #include <net/arp.h>
 #include <linux/init.h>
 #include <linux/arcdevice.h>
+#include <linux/jiffies.h>
 
 /* "do nothing" functions for protocol drivers */
 static void null_rx(struct net_device *dev, int bufnum,
@@ -61,6 +62,7 @@
 static int null_prepare_tx(struct net_device *dev, struct archdr *pkt,
 			   int length, int bufnum);
 
+static void arcnet_rx(struct net_device *dev, int bufnum);
 
 /*
  * one ArcProto per possible proto ID.  None of the elements of
@@ -71,7 +73,7 @@
  struct ArcProto *arc_proto_map[256], *arc_proto_default,
    *arc_bcast_proto, *arc_raw_proto;
 
-struct ArcProto arc_proto_null =
+static struct ArcProto arc_proto_null =
 {
 	.suffix		= '?',
 	.mtu		= XMTU,
@@ -90,7 +92,6 @@
 EXPORT_SYMBOL(arc_proto_default);
 EXPORT_SYMBOL(arc_bcast_proto);
 EXPORT_SYMBOL(arc_raw_proto);
-EXPORT_SYMBOL(arc_proto_null);
 EXPORT_SYMBOL(arcnet_unregister_proto);
 EXPORT_SYMBOL(arcnet_debug);
 EXPORT_SYMBOL(alloc_arcdev);
@@ -118,7 +119,7 @@
 
 	arcnet_debug = debug;
 
-	printk(VERSION);
+	printk("arcnet loaded.\n");
 
 #ifdef ALPHA_WARNING
 	BUGLVL(D_EXTRA) {
@@ -178,8 +179,8 @@
  * Dump the contents of an ARCnet buffer
  */
 #if (ARCNET_DEBUG_MAX & (D_RX | D_TX))
-void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc,
-			int take_arcnet_lock)
+static void arcnet_dump_packet(struct net_device *dev, int bufnum,
+			       char *desc, int take_arcnet_lock)
 {
 	struct arcnet_local *lp = dev->priv;
 	int i, length;
@@ -208,7 +209,10 @@
 
 }
 
-EXPORT_SYMBOL(arcnet_dump_packet);
+#else
+
+#define arcnet_dump_packet(dev, bufnum, desc,take_arcnet_lock) do { } while (0)
+
 #endif
 
 
@@ -733,7 +737,7 @@
 	
 	spin_unlock_irqrestore(&lp->lock, flags);
 
-	if (jiffies - lp->last_timeout > 10*HZ) {
+	if (time_after(jiffies, lp->last_timeout + 10*HZ)) {
 		BUGMSG(D_EXTRA, "tx timed out%s (status=%Xh, intmask=%Xh, dest=%02Xh)\n",
 		       msg, status, lp->intmask, lp->lasttrans_dest);
 		lp->last_timeout = jiffies;
@@ -996,7 +1000,7 @@
  * This is a generic packet receiver that calls arcnet??_rx depending on the
  * protocol ID found.
  */
-void arcnet_rx(struct net_device *dev, int bufnum)
+static void arcnet_rx(struct net_device *dev, int bufnum)
 {
 	struct arcnet_local *lp = dev->priv;
 	struct archdr pkt;
diff -urN oldtree/drivers/net/arcnet/com90xx.c newtree/drivers/net/arcnet/com90xx.c
--- oldtree/drivers/net/arcnet/com90xx.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/arcnet/com90xx.c	2006-02-21 15:58:15.329816072 +0000
@@ -53,7 +53,7 @@
 
 
 /* Internal function declarations */
-static int com90xx_found(int ioaddr, int airq, u_long shmem);
+static int com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem *);
 static void com90xx_command(struct net_device *dev, int command);
 static int com90xx_status(struct net_device *dev);
 static void com90xx_setmask(struct net_device *dev, int mask);
@@ -116,14 +116,26 @@
 	unsigned long airqmask;
 	int ports[(0x3f0 - 0x200) / 16 + 1] =
 	{0};
-	u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] =
-	{0};
+	unsigned long *shmems;
+	void __iomem **iomem;
 	int numports, numshmems, *port;
 	u_long *p;
+	int index;
 
 	if (!io && !irq && !shmem && !*device && com90xx_skip_probe)
 		return;
 
+	shmems = kzalloc(((0x10000-0xa0000) / 0x800) * sizeof(unsigned long),
+			 GFP_KERNEL);
+	if (!shmems)
+		return;
+	iomem = kzalloc(((0x10000-0xa0000) / 0x800) * sizeof(void __iomem *),
+			 GFP_KERNEL);
+	if (!iomem) {
+		kfree(shmems);
+		return;
+	}
+
 	BUGLVL(D_NORMAL) printk(VERSION);
 
 	/* set up the arrays where we'll store the possible probe addresses */
@@ -179,6 +191,8 @@
 
 	if (!numports) {
 		BUGMSG2(D_NORMAL, "S1: No ARCnet cards found.\n");
+		kfree(shmems);
+		kfree(iomem);
 		return;
 	}
 	/* Stage 2: we have now reset any possible ARCnet cards, so we can't
@@ -202,8 +216,8 @@
 	 * 0xD1 byte in the right place, or are read-only.
 	 */
 	numprint = -1;
-	for (p = &shmems[0]; p < shmems + numshmems; p++) {
-		u_long ptr = *p;
+	for (index = 0, p = &shmems[0]; index < numshmems; p++, index++) {
+		void __iomem *base;
 
 		numprint++;
 		numprint %= 8;
@@ -213,38 +227,49 @@
 		}
 		BUGMSG2(D_INIT, "%lXh ", *p);
 
-		if (!request_mem_region(*p, BUFFER_SIZE, "arcnet (90xx)")) {
+		if (!request_mem_region(*p, MIRROR_SIZE, "arcnet (90xx)")) {
 			BUGMSG2(D_INIT_REASONS, "(request_mem_region)\n");
 			BUGMSG2(D_INIT_REASONS, "Stage 3: ");
 			BUGLVL(D_INIT_REASONS) numprint = 0;
-			*p-- = shmems[--numshmems];
-			continue;
+			goto out;
+		}
+		base = ioremap(*p, MIRROR_SIZE);
+		if (!base) {
+			BUGMSG2(D_INIT_REASONS, "(ioremap)\n");
+			BUGMSG2(D_INIT_REASONS, "Stage 3: ");
+			BUGLVL(D_INIT_REASONS) numprint = 0;
+			goto out1;
 		}
-		if (isa_readb(ptr) != TESTvalue) {
+		if (readb(base) != TESTvalue) {
 			BUGMSG2(D_INIT_REASONS, "(%02Xh != %02Xh)\n",
-				isa_readb(ptr), TESTvalue);
+				readb(base), TESTvalue);
 			BUGMSG2(D_INIT_REASONS, "S3: ");
 			BUGLVL(D_INIT_REASONS) numprint = 0;
-			release_mem_region(*p, BUFFER_SIZE);
-			*p-- = shmems[--numshmems];
-			continue;
+			goto out2;
 		}
 		/* By writing 0x42 to the TESTvalue location, we also make
 		 * sure no "mirror" shmem areas show up - if they occur
 		 * in another pass through this loop, they will be discarded
 		 * because *cptr != TESTvalue.
 		 */
-		isa_writeb(0x42, ptr);
-		if (isa_readb(ptr) != 0x42) {
+		writeb(0x42, base);
+		if (readb(base) != 0x42) {
 			BUGMSG2(D_INIT_REASONS, "(read only)\n");
 			BUGMSG2(D_INIT_REASONS, "S3: ");
-			release_mem_region(*p, BUFFER_SIZE);
-			*p-- = shmems[--numshmems];
-			continue;
+			goto out2;
 		}
 		BUGMSG2(D_INIT_REASONS, "\n");
 		BUGMSG2(D_INIT_REASONS, "S3: ");
 		BUGLVL(D_INIT_REASONS) numprint = 0;
+		iomem[index] = base;
+		continue;
+	out2:
+		iounmap(base);
+	out1:
+		release_mem_region(*p, MIRROR_SIZE);
+	out:
+		*p-- = shmems[--numshmems];
+		index--;
 	}
 	BUGMSG2(D_INIT, "\n");
 
@@ -252,6 +277,8 @@
 		BUGMSG2(D_NORMAL, "S3: No ARCnet cards found.\n");
 		for (port = &ports[0]; port < ports + numports; port++)
 			release_region(*port, ARCNET_TOTAL_SIZE);
+		kfree(shmems);
+		kfree(iomem);
 		return;
 	}
 	/* Stage 4: something of a dummy, to report the shmems that are
@@ -351,30 +378,32 @@
 			mdelay(RESETtime);
 		} else {
 			/* just one shmem and port, assume they match */
-			isa_writeb(TESTvalue, shmems[0]);
+			writeb(TESTvalue, iomem[0]);
 		}
 #else
 		inb(_RESET);
 		mdelay(RESETtime);
 #endif
 
-		for (p = &shmems[0]; p < shmems + numshmems; p++) {
-			u_long ptr = *p;
+		for (index = 0; index < numshmems; index++) {
+			u_long ptr = shmems[index];
+			void __iomem *base = iomem[index];
 
-			if (isa_readb(ptr) == TESTvalue) {	/* found one */
+			if (readb(base) == TESTvalue) {	/* found one */
 				BUGMSG2(D_INIT, "%lXh)\n", *p);
 				openparen = 0;
 
 				/* register the card */
-				if (com90xx_found(*port, airq, *p) == 0)
+				if (com90xx_found(*port, airq, ptr, base) == 0)
 					found = 1;
 				numprint = -1;
 
 				/* remove shmem from the list */
-				*p = shmems[--numshmems];
+				shmems[index] = shmems[--numshmems];
+				iomem[index] = iomem[numshmems];
 				break;	/* go to the next I/O port */
 			} else {
-				BUGMSG2(D_INIT_REASONS, "%Xh-", isa_readb(ptr));
+				BUGMSG2(D_INIT_REASONS, "%Xh-", readb(base));
 			}
 		}
 
@@ -391,17 +420,40 @@
 	BUGLVL(D_INIT_REASONS) printk("\n");
 
 	/* Now put back TESTvalue on all leftover shmems. */
-	for (p = &shmems[0]; p < shmems + numshmems; p++) {
-		isa_writeb(TESTvalue, *p);
-		release_mem_region(*p, BUFFER_SIZE);
+	for (index = 0; index < numshmems; index++) {
+		writeb(TESTvalue, iomem[index]);
+		iounmap(iomem[index]);
+		release_mem_region(shmems[index], MIRROR_SIZE);
 	}
+	kfree(shmems);
+	kfree(iomem);
 }
 
+static int check_mirror(unsigned long addr, size_t size)
+{
+	void __iomem *p;
+	int res = -1;
+
+	if (!request_mem_region(addr, size, "arcnet (90xx)"))
+		return -1;
+
+	p = ioremap(addr, size);
+	if (p) {
+		if (readb(p) == TESTvalue)
+			res = 1;
+		else
+			res = 0;
+		iounmap(p);
+	}
+
+	release_mem_region(addr, size);
+	return res;
+}
 
 /* Set up the struct net_device associated with this card.  Called after
  * probing succeeds.
  */
-static int __init com90xx_found(int ioaddr, int airq, u_long shmem)
+static int __init com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem *p)
 {
 	struct net_device *dev = NULL;
 	struct arcnet_local *lp;
@@ -412,7 +464,8 @@
 	dev = alloc_arcdev(device);
 	if (!dev) {
 		BUGMSG2(D_NORMAL, "com90xx: Can't allocate device!\n");
-		release_mem_region(shmem, BUFFER_SIZE);
+		iounmap(p);
+		release_mem_region(shmem, MIRROR_SIZE);
 		return -ENOMEM;
 	}
 	lp = dev->priv;
@@ -423,24 +476,27 @@
 	 * 2k (or there are no mirrors at all) but on some, it's 4k.
 	 */
 	mirror_size = MIRROR_SIZE;
-	if (isa_readb(shmem) == TESTvalue
-	    && isa_readb(shmem - mirror_size) != TESTvalue
-	    && isa_readb(shmem - 2 * mirror_size) == TESTvalue)
-		mirror_size *= 2;
+	if (readb(p) == TESTvalue &&
+	    check_mirror(shmem - MIRROR_SIZE, MIRROR_SIZE) == 0 &&
+	    check_mirror(shmem - 2 * MIRROR_SIZE, MIRROR_SIZE) == 1)
+		mirror_size = 2 * MIRROR_SIZE;
 
-	first_mirror = last_mirror = shmem;
-	while (isa_readb(first_mirror) == TESTvalue)
+	first_mirror = shmem - mirror_size;
+	while (check_mirror(first_mirror, mirror_size) == 1)
 		first_mirror -= mirror_size;
 	first_mirror += mirror_size;
 
-	while (isa_readb(last_mirror) == TESTvalue)
+	last_mirror = shmem + mirror_size;
+	while (check_mirror(last_mirror, mirror_size) == 1)
 		last_mirror += mirror_size;
 	last_mirror -= mirror_size;
 
 	dev->mem_start = first_mirror;
 	dev->mem_end = last_mirror + MIRROR_SIZE - 1;
 
-	release_mem_region(shmem, BUFFER_SIZE);
+	iounmap(p);
+	release_mem_region(shmem, MIRROR_SIZE);
+
 	if (!request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)"))
 		goto err_free_dev;
 
diff -urN oldtree/drivers/net/arcnet/rfc1051.c newtree/drivers/net/arcnet/rfc1051.c
--- oldtree/drivers/net/arcnet/rfc1051.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/arcnet/rfc1051.c	2006-02-21 15:58:15.329816072 +0000
@@ -43,7 +43,7 @@
 		      int bufnum);
 
 
-struct ArcProto rfc1051_proto =
+static struct ArcProto rfc1051_proto =
 {
 	.suffix		= 's',
 	.mtu		= XMTU - RFC1051_HDR_SIZE,
diff -urN oldtree/drivers/net/arcnet/rfc1201.c newtree/drivers/net/arcnet/rfc1201.c
--- oldtree/drivers/net/arcnet/rfc1201.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/arcnet/rfc1201.c	2006-02-21 15:58:15.330815920 +0000
@@ -43,7 +43,7 @@
 		      int bufnum);
 static int continue_tx(struct net_device *dev, int bufnum);
 
-struct ArcProto rfc1201_proto =
+static struct ArcProto rfc1201_proto =
 {
 	.suffix		= 'a',
 	.mtu		= 1500,	/* could be more, but some receivers can't handle it... */
diff -urN oldtree/drivers/net/arm/am79c961a.c newtree/drivers/net/arm/am79c961a.c
--- oldtree/drivers/net/arm/am79c961a.c	2006-02-19 11:41:03.135866376 +0000
+++ newtree/drivers/net/arm/am79c961a.c	2006-02-21 15:58:12.476249880 +0000
@@ -696,7 +696,9 @@
 	dev->base_addr = res->start;
 	dev->irq = platform_get_irq(pdev, 0);
 
-    	ret = -ENODEV;
+	ret = -ENODEV;
+	if (dev->irq < 0)
+		goto nodev;
 	if (!request_region(dev->base_addr, 0x18, dev->name))
 		goto nodev;
 
diff -urN oldtree/drivers/net/arm/etherh.c newtree/drivers/net/arm/etherh.c
--- oldtree/drivers/net/arm/etherh.c	2006-02-19 11:41:03.138865920 +0000
+++ newtree/drivers/net/arm/etherh.c	2006-02-21 15:58:36.324624376 +0000
@@ -46,12 +46,18 @@
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
+#include <linux/jiffies.h>
 
 #include <asm/system.h>
 #include <asm/ecard.h>
 #include <asm/io.h>
 
-#include "../8390.h"
+#define EI_SHIFT(x)	(ei_local->reg_offset[x])
+
+#define ei_inb(_p)	 readb((void __iomem *)_p)
+#define ei_outb(_v,_p)	 writeb(_v,(void __iomem *)_p)
+#define ei_inb_p(_p)	 readb((void __iomem *)_p)
+#define ei_outb_p(_v,_p) writeb(_v,(void __iomem *)_p)
 
 #define NET_DEBUG  0
 #define DEBUG_INIT 2
@@ -59,6 +65,11 @@
 #define DRV_NAME	"etherh"
 #define DRV_VERSION	"1.11"
 
+static char version[] __initdata =
+	"EtherH/EtherM Driver (c) 2002-2004 Russell King " DRV_VERSION "\n";
+
+#include "../lib8390.c"
+
 static unsigned int net_debug = NET_DEBUG;
 
 struct etherh_priv {
@@ -86,9 +97,6 @@
 MODULE_DESCRIPTION("EtherH/EtherM driver");
 MODULE_LICENSE("GPL");
 
-static char version[] __initdata =
-	"EtherH/EtherM Driver (c) 2002-2004 Russell King " DRV_VERSION "\n";
-
 #define ETHERH500_DATAPORT	0x800	/* MEMC */
 #define ETHERH500_NS8390	0x000	/* MEMC */
 #define ETHERH500_CTRLPORT	0x800	/* IOC  */
@@ -176,7 +184,7 @@
 	switch (etherh_priv(dev)->id) {
 	case PROD_I3_ETHERLAN600:
 	case PROD_I3_ETHERLAN600A:
-		addr = (void *)dev->base_addr + EN0_RCNTHI;
+		addr = (void __iomem *)dev->base_addr + EN0_RCNTHI;
 
 		switch (dev->if_port) {
 		case IF_PORT_10BASE2:
@@ -217,7 +225,7 @@
 	switch (etherh_priv(dev)->id) {
 	case PROD_I3_ETHERLAN600:
 	case PROD_I3_ETHERLAN600A:
-		addr = (void *)dev->base_addr + EN0_RCNTHI;
+		addr = (void __iomem *)dev->base_addr + EN0_RCNTHI;
 		switch (dev->if_port) {
 		case IF_PORT_10BASE2:
 			stat = 1;
@@ -280,7 +288,7 @@
 etherh_reset(struct net_device *dev)
 {
 	struct ei_device *ei_local = netdev_priv(dev);
-	void __iomem *addr = (void *)dev->base_addr;
+	void __iomem *addr = (void __iomem *)dev->base_addr;
 
 	writeb(E8390_NODMA+E8390_PAGE0+E8390_STOP, addr);
 
@@ -326,7 +334,7 @@
 
 	ei_local->dmaing = 1;
 
-	addr = (void *)dev->base_addr;
+	addr = (void __iomem *)dev->base_addr;
 	dma_base = etherh_priv(dev)->dma_base;
 
 	count = (count + 1) & ~1;
@@ -355,11 +363,11 @@
 	dma_start = jiffies;
 
 	while ((readb (addr + EN0_ISR) & ENISR_RDC) == 0)
-		if (jiffies - dma_start > 2*HZ/100) { /* 20ms */
+		if (time_after(jiffies, dma_start + 2*HZ/100)) { /* 20ms */
 			printk(KERN_ERR "%s: timeout waiting for TX RDC\n",
 				dev->name);
 			etherh_reset (dev);
-			NS8390_init (dev, 1);
+			__NS8390_init (dev, 1);
 			break;
 		}
 
@@ -386,7 +394,7 @@
 
 	ei_local->dmaing = 1;
 
-	addr = (void *)dev->base_addr;
+	addr = (void __iomem *)dev->base_addr;
 	dma_base = etherh_priv(dev)->dma_base;
 
 	buf = skb->data;
@@ -426,7 +434,7 @@
 
 	ei_local->dmaing = 1;
 
-	addr = (void *)dev->base_addr;
+	addr = (void __iomem *)dev->base_addr;
 	dma_base = etherh_priv(dev)->dma_base;
 
 	writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD);
@@ -464,7 +472,7 @@
 		return -EINVAL;
 	}
 
-	if (request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))
+	if (request_irq(dev->irq, __ei_interrupt, 0, dev->name, dev))
 		return -EAGAIN;
 
 	/*
@@ -490,7 +498,7 @@
 		etherh_setif(dev);
 
 	etherh_reset(dev);
-	ei_open(dev);
+	__ei_open(dev);
 
 	return 0;
 }
@@ -501,7 +509,7 @@
 static int
 etherh_close(struct net_device *dev)
 {
-	ei_close (dev);
+	__ei_close (dev);
 	free_irq (dev->irq, dev);
 	return 0;
 }
@@ -649,7 +657,7 @@
 	if (ret)
 		goto out;
 
-	dev = __alloc_ei_netdev(sizeof(struct etherh_priv));
+	dev = ____alloc_ei_netdev(sizeof(struct etherh_priv));
 	if (!dev) {
 		ret = -ENOMEM;
 		goto release;
@@ -735,7 +743,7 @@
 	ei_local->interface_num = 0;
 
 	etherh_reset(dev);
-	NS8390_init(dev, 0);
+	__NS8390_init(dev, 0);
 
 	ret = register_netdev(dev);
 	if (ret)
diff -urN oldtree/drivers/net/bnx2.c newtree/drivers/net/bnx2.c
--- oldtree/drivers/net/bnx2.c	2006-02-19 11:41:03.143865160 +0000
+++ newtree/drivers/net/bnx2.c	2006-02-21 15:58:16.113696904 +0000
@@ -14,8 +14,8 @@
 
 #define DRV_MODULE_NAME		"bnx2"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"1.4.31"
-#define DRV_MODULE_RELDATE	"January 19, 2006"
+#define DRV_MODULE_VERSION	"1.4.38"
+#define DRV_MODULE_RELDATE	"February 10, 2006"
 
 #define RUN_AT(x) (jiffies + (x))
 
@@ -360,6 +360,8 @@
 static void
 bnx2_free_mem(struct bnx2 *bp)
 {
+	int i;
+
 	if (bp->stats_blk) {
 		pci_free_consistent(bp->pdev, sizeof(struct statistics_block),
 				    bp->stats_blk, bp->stats_blk_mapping);
@@ -378,19 +380,23 @@
 	}
 	kfree(bp->tx_buf_ring);
 	bp->tx_buf_ring = NULL;
-	if (bp->rx_desc_ring) {
-		pci_free_consistent(bp->pdev,
-				    sizeof(struct rx_bd) * RX_DESC_CNT,
-				    bp->rx_desc_ring, bp->rx_desc_mapping);
-		bp->rx_desc_ring = NULL;
+	for (i = 0; i < bp->rx_max_ring; i++) {
+		if (bp->rx_desc_ring[i])
+			pci_free_consistent(bp->pdev,
+					    sizeof(struct rx_bd) * RX_DESC_CNT,
+					    bp->rx_desc_ring[i],
+					    bp->rx_desc_mapping[i]);
+		bp->rx_desc_ring[i] = NULL;
 	}
-	kfree(bp->rx_buf_ring);
+	vfree(bp->rx_buf_ring);
 	bp->rx_buf_ring = NULL;
 }
 
 static int
 bnx2_alloc_mem(struct bnx2 *bp)
 {
+	int i;
+
 	bp->tx_buf_ring = kmalloc(sizeof(struct sw_bd) * TX_DESC_CNT,
 				     GFP_KERNEL);
 	if (bp->tx_buf_ring == NULL)
@@ -404,18 +410,23 @@
 	if (bp->tx_desc_ring == NULL)
 		goto alloc_mem_err;
 
-	bp->rx_buf_ring = kmalloc(sizeof(struct sw_bd) * RX_DESC_CNT,
-				     GFP_KERNEL);
+	bp->rx_buf_ring = vmalloc(sizeof(struct sw_bd) * RX_DESC_CNT *
+				  bp->rx_max_ring);
 	if (bp->rx_buf_ring == NULL)
 		goto alloc_mem_err;
 
-	memset(bp->rx_buf_ring, 0, sizeof(struct sw_bd) * RX_DESC_CNT);
-	bp->rx_desc_ring = pci_alloc_consistent(bp->pdev,
-					        sizeof(struct rx_bd) *
-						RX_DESC_CNT,
-						&bp->rx_desc_mapping);
-	if (bp->rx_desc_ring == NULL)
-		goto alloc_mem_err;
+	memset(bp->rx_buf_ring, 0, sizeof(struct sw_bd) * RX_DESC_CNT *
+				   bp->rx_max_ring);
+
+	for (i = 0; i < bp->rx_max_ring; i++) {
+		bp->rx_desc_ring[i] =
+			pci_alloc_consistent(bp->pdev,
+					     sizeof(struct rx_bd) * RX_DESC_CNT,
+					     &bp->rx_desc_mapping[i]);
+		if (bp->rx_desc_ring[i] == NULL)
+			goto alloc_mem_err;
+
+	}
 
 	bp->status_blk = pci_alloc_consistent(bp->pdev,
 					      sizeof(struct status_block),
@@ -1520,7 +1531,7 @@
 	struct sk_buff *skb;
 	struct sw_bd *rx_buf = &bp->rx_buf_ring[index];
 	dma_addr_t mapping;
-	struct rx_bd *rxbd = &bp->rx_desc_ring[index];
+	struct rx_bd *rxbd = &bp->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
 	unsigned long align;
 
 	skb = dev_alloc_skb(bp->rx_buf_size);
@@ -1656,23 +1667,30 @@
 bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb,
 	u16 cons, u16 prod)
 {
-	struct sw_bd *cons_rx_buf = &bp->rx_buf_ring[cons];
-	struct sw_bd *prod_rx_buf = &bp->rx_buf_ring[prod];
-	struct rx_bd *cons_bd = &bp->rx_desc_ring[cons];
-	struct rx_bd *prod_bd = &bp->rx_desc_ring[prod];
+	struct sw_bd *cons_rx_buf, *prod_rx_buf;
+	struct rx_bd *cons_bd, *prod_bd;
+
+	cons_rx_buf = &bp->rx_buf_ring[cons];
+	prod_rx_buf = &bp->rx_buf_ring[prod];
 
 	pci_dma_sync_single_for_device(bp->pdev,
 		pci_unmap_addr(cons_rx_buf, mapping),
 		bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
 
-	prod_rx_buf->skb = cons_rx_buf->skb;
-	pci_unmap_addr_set(prod_rx_buf, mapping,
-			pci_unmap_addr(cons_rx_buf, mapping));
+	bp->rx_prod_bseq += bp->rx_buf_use_size;
 
-	memcpy(prod_bd, cons_bd, 8);
+	prod_rx_buf->skb = skb;
 
-	bp->rx_prod_bseq += bp->rx_buf_use_size;
+	if (cons == prod)
+		return;
+
+	pci_unmap_addr_set(prod_rx_buf, mapping,
+			pci_unmap_addr(cons_rx_buf, mapping));
 
+	cons_bd = &bp->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)];
+	prod_bd = &bp->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)];
+	prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
+	prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
 }
 
 static int
@@ -1699,14 +1717,19 @@
 		u32 status;
 		struct sw_bd *rx_buf;
 		struct sk_buff *skb;
+		dma_addr_t dma_addr;
 
 		sw_ring_cons = RX_RING_IDX(sw_cons);
 		sw_ring_prod = RX_RING_IDX(sw_prod);
 
 		rx_buf = &bp->rx_buf_ring[sw_ring_cons];
 		skb = rx_buf->skb;
-		pci_dma_sync_single_for_cpu(bp->pdev,
-			pci_unmap_addr(rx_buf, mapping),
+
+		rx_buf->skb = NULL;
+
+		dma_addr = pci_unmap_addr(rx_buf, mapping);
+
+		pci_dma_sync_single_for_cpu(bp->pdev, dma_addr,
 			bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
 
 		rx_hdr = (struct l2_fhdr *) skb->data;
@@ -1747,8 +1770,7 @@
 			skb = new_skb;
 		}
 		else if (bnx2_alloc_rx_skb(bp, sw_ring_prod) == 0) {
-			pci_unmap_single(bp->pdev,
-				pci_unmap_addr(rx_buf, mapping),
+			pci_unmap_single(bp->pdev, dma_addr,
 				bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
 
 			skb_reserve(skb, bp->rx_offset);
@@ -1794,8 +1816,6 @@
 		rx_pkt++;
 
 next_rx:
-		rx_buf->skb = NULL;
-
 		sw_cons = NEXT_RX_BD(sw_cons);
 		sw_prod = NEXT_RX_BD(sw_prod);
 
@@ -3340,27 +3360,35 @@
 	bp->hw_rx_cons = 0;
 	bp->rx_prod_bseq = 0;
 		
-	rxbd = &bp->rx_desc_ring[0];
-	for (i = 0; i < MAX_RX_DESC_CNT; i++, rxbd++) {
-		rxbd->rx_bd_len = bp->rx_buf_use_size;
-		rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
-	}
+	for (i = 0; i < bp->rx_max_ring; i++) {
+		int j;
 
-	rxbd->rx_bd_haddr_hi = (u64) bp->rx_desc_mapping >> 32;
-	rxbd->rx_bd_haddr_lo = (u64) bp->rx_desc_mapping & 0xffffffff;
+		rxbd = &bp->rx_desc_ring[i][0];
+		for (j = 0; j < MAX_RX_DESC_CNT; j++, rxbd++) {
+			rxbd->rx_bd_len = bp->rx_buf_use_size;
+			rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
+		}
+		if (i == (bp->rx_max_ring - 1))
+			j = 0;
+		else
+			j = i + 1;
+		rxbd->rx_bd_haddr_hi = (u64) bp->rx_desc_mapping[j] >> 32;
+		rxbd->rx_bd_haddr_lo = (u64) bp->rx_desc_mapping[j] &
+				       0xffffffff;
+	}
 
 	val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
 	val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
 	val |= 0x02 << 8;
 	CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_CTX_TYPE, val);
 
-	val = (u64) bp->rx_desc_mapping >> 32;
+	val = (u64) bp->rx_desc_mapping[0] >> 32;
 	CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_HI, val);
 
-	val = (u64) bp->rx_desc_mapping & 0xffffffff;
+	val = (u64) bp->rx_desc_mapping[0] & 0xffffffff;
 	CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_LO, val);
 
-	for ( ;ring_prod < bp->rx_ring_size; ) {
+	for (i = 0; i < bp->rx_ring_size; i++) {
 		if (bnx2_alloc_rx_skb(bp, ring_prod) < 0) {
 			break;
 		}
@@ -3375,6 +3403,29 @@
 }
 
 static void
+bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
+{
+	u32 num_rings, max;
+
+	bp->rx_ring_size = size;
+	num_rings = 1;
+	while (size > MAX_RX_DESC_CNT) {
+		size -= MAX_RX_DESC_CNT;
+		num_rings++;
+	}
+	/* round to next power of 2 */
+	max = MAX_RX_RINGS;
+	while ((max & num_rings) == 0)
+		max >>= 1;
+
+	if (num_rings != max)
+		max <<= 1;
+
+	bp->rx_max_ring = max;
+	bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1;
+}
+
+static void
 bnx2_free_tx_skbs(struct bnx2 *bp)
 {
 	int i;
@@ -3419,7 +3470,7 @@
 	if (bp->rx_buf_ring == NULL)
 		return;
 
-	for (i = 0; i < RX_DESC_CNT; i++) {
+	for (i = 0; i < bp->rx_max_ring_idx; i++) {
 		struct sw_bd *rx_buf = &bp->rx_buf_ring[i];
 		struct sk_buff *skb = rx_buf->skb;
 
@@ -3506,74 +3557,9 @@
 		{ 0x0c00, 0, 0x00000000, 0x00000001 },
 		{ 0x0c04, 0, 0x00000000, 0x03ff0001 },
 		{ 0x0c08, 0, 0x0f0ff073, 0x00000000 },
-		{ 0x0c0c, 0, 0x00ffffff, 0x00000000 },
-		{ 0x0c30, 0, 0x00000000, 0xffffffff },
-		{ 0x0c34, 0, 0x00000000, 0xffffffff },
-		{ 0x0c38, 0, 0x00000000, 0xffffffff },
-		{ 0x0c3c, 0, 0x00000000, 0xffffffff },
-		{ 0x0c40, 0, 0x00000000, 0xffffffff },
-		{ 0x0c44, 0, 0x00000000, 0xffffffff },
-		{ 0x0c48, 0, 0x00000000, 0x0007ffff },
-		{ 0x0c4c, 0, 0x00000000, 0xffffffff },
-		{ 0x0c50, 0, 0x00000000, 0xffffffff },
-		{ 0x0c54, 0, 0x00000000, 0xffffffff },
-		{ 0x0c58, 0, 0x00000000, 0xffffffff },
-		{ 0x0c5c, 0, 0x00000000, 0xffffffff },
-		{ 0x0c60, 0, 0x00000000, 0xffffffff },
-		{ 0x0c64, 0, 0x00000000, 0xffffffff },
-		{ 0x0c68, 0, 0x00000000, 0xffffffff },
-		{ 0x0c6c, 0, 0x00000000, 0xffffffff },
-		{ 0x0c70, 0, 0x00000000, 0xffffffff },
-		{ 0x0c74, 0, 0x00000000, 0xffffffff },
-		{ 0x0c78, 0, 0x00000000, 0xffffffff },
-		{ 0x0c7c, 0, 0x00000000, 0xffffffff },
-		{ 0x0c80, 0, 0x00000000, 0xffffffff },
-		{ 0x0c84, 0, 0x00000000, 0xffffffff },
-		{ 0x0c88, 0, 0x00000000, 0xffffffff },
-		{ 0x0c8c, 0, 0x00000000, 0xffffffff },
-		{ 0x0c90, 0, 0x00000000, 0xffffffff },
-		{ 0x0c94, 0, 0x00000000, 0xffffffff },
-		{ 0x0c98, 0, 0x00000000, 0xffffffff },
-		{ 0x0c9c, 0, 0x00000000, 0xffffffff },
-		{ 0x0ca0, 0, 0x00000000, 0xffffffff },
-		{ 0x0ca4, 0, 0x00000000, 0xffffffff },
-		{ 0x0ca8, 0, 0x00000000, 0x0007ffff },
-		{ 0x0cac, 0, 0x00000000, 0xffffffff },
-		{ 0x0cb0, 0, 0x00000000, 0xffffffff },
-		{ 0x0cb4, 0, 0x00000000, 0xffffffff },
-		{ 0x0cb8, 0, 0x00000000, 0xffffffff },
-		{ 0x0cbc, 0, 0x00000000, 0xffffffff },
-		{ 0x0cc0, 0, 0x00000000, 0xffffffff },
-		{ 0x0cc4, 0, 0x00000000, 0xffffffff },
-		{ 0x0cc8, 0, 0x00000000, 0xffffffff },
-		{ 0x0ccc, 0, 0x00000000, 0xffffffff },
-		{ 0x0cd0, 0, 0x00000000, 0xffffffff },
-		{ 0x0cd4, 0, 0x00000000, 0xffffffff },
-		{ 0x0cd8, 0, 0x00000000, 0xffffffff },
-		{ 0x0cdc, 0, 0x00000000, 0xffffffff },
-		{ 0x0ce0, 0, 0x00000000, 0xffffffff },
-		{ 0x0ce4, 0, 0x00000000, 0xffffffff },
-		{ 0x0ce8, 0, 0x00000000, 0xffffffff },
-		{ 0x0cec, 0, 0x00000000, 0xffffffff },
-		{ 0x0cf0, 0, 0x00000000, 0xffffffff },
-		{ 0x0cf4, 0, 0x00000000, 0xffffffff },
-		{ 0x0cf8, 0, 0x00000000, 0xffffffff },
-		{ 0x0cfc, 0, 0x00000000, 0xffffffff },
-		{ 0x0d00, 0, 0x00000000, 0xffffffff },
-		{ 0x0d04, 0, 0x00000000, 0xffffffff },
 
 		{ 0x1000, 0, 0x00000000, 0x00000001 },
 		{ 0x1004, 0, 0x00000000, 0x000f0001 },
-		{ 0x1044, 0, 0x00000000, 0xffc003ff },
-		{ 0x1080, 0, 0x00000000, 0x0001ffff },
-		{ 0x1084, 0, 0x00000000, 0xffffffff },
-		{ 0x1088, 0, 0x00000000, 0xffffffff },
-		{ 0x108c, 0, 0x00000000, 0xffffffff },
-		{ 0x1090, 0, 0x00000000, 0xffffffff },
-		{ 0x1094, 0, 0x00000000, 0xffffffff },
-		{ 0x1098, 0, 0x00000000, 0xffffffff },
-		{ 0x109c, 0, 0x00000000, 0xffffffff },
-		{ 0x10a0, 0, 0x00000000, 0xffffffff },
 
 		{ 0x1408, 0, 0x01c00800, 0x00000000 },
 		{ 0x149c, 0, 0x8000ffff, 0x00000000 },
@@ -3585,111 +3571,9 @@
 		{ 0x14c4, 0, 0x00003fff, 0x00000000 },
 		{ 0x14cc, 0, 0x00000000, 0x00000001 },
 		{ 0x14d0, 0, 0xffffffff, 0x00000000 },
-		{ 0x1500, 0, 0x00000000, 0xffffffff },
-		{ 0x1504, 0, 0x00000000, 0xffffffff },
-		{ 0x1508, 0, 0x00000000, 0xffffffff },
-		{ 0x150c, 0, 0x00000000, 0xffffffff },
-		{ 0x1510, 0, 0x00000000, 0xffffffff },
-		{ 0x1514, 0, 0x00000000, 0xffffffff },
-		{ 0x1518, 0, 0x00000000, 0xffffffff },
-		{ 0x151c, 0, 0x00000000, 0xffffffff },
-		{ 0x1520, 0, 0x00000000, 0xffffffff },
-		{ 0x1524, 0, 0x00000000, 0xffffffff },
-		{ 0x1528, 0, 0x00000000, 0xffffffff },
-		{ 0x152c, 0, 0x00000000, 0xffffffff },
-		{ 0x1530, 0, 0x00000000, 0xffffffff },
-		{ 0x1534, 0, 0x00000000, 0xffffffff },
-		{ 0x1538, 0, 0x00000000, 0xffffffff },
-		{ 0x153c, 0, 0x00000000, 0xffffffff },
-		{ 0x1540, 0, 0x00000000, 0xffffffff },
-		{ 0x1544, 0, 0x00000000, 0xffffffff },
-		{ 0x1548, 0, 0x00000000, 0xffffffff },
-		{ 0x154c, 0, 0x00000000, 0xffffffff },
-		{ 0x1550, 0, 0x00000000, 0xffffffff },
-		{ 0x1554, 0, 0x00000000, 0xffffffff },
-		{ 0x1558, 0, 0x00000000, 0xffffffff },
-		{ 0x1600, 0, 0x00000000, 0xffffffff },
-		{ 0x1604, 0, 0x00000000, 0xffffffff },
-		{ 0x1608, 0, 0x00000000, 0xffffffff },
-		{ 0x160c, 0, 0x00000000, 0xffffffff },
-		{ 0x1610, 0, 0x00000000, 0xffffffff },
-		{ 0x1614, 0, 0x00000000, 0xffffffff },
-		{ 0x1618, 0, 0x00000000, 0xffffffff },
-		{ 0x161c, 0, 0x00000000, 0xffffffff },
-		{ 0x1620, 0, 0x00000000, 0xffffffff },
-		{ 0x1624, 0, 0x00000000, 0xffffffff },
-		{ 0x1628, 0, 0x00000000, 0xffffffff },
-		{ 0x162c, 0, 0x00000000, 0xffffffff },
-		{ 0x1630, 0, 0x00000000, 0xffffffff },
-		{ 0x1634, 0, 0x00000000, 0xffffffff },
-		{ 0x1638, 0, 0x00000000, 0xffffffff },
-		{ 0x163c, 0, 0x00000000, 0xffffffff },
-		{ 0x1640, 0, 0x00000000, 0xffffffff },
-		{ 0x1644, 0, 0x00000000, 0xffffffff },
-		{ 0x1648, 0, 0x00000000, 0xffffffff },
-		{ 0x164c, 0, 0x00000000, 0xffffffff },
-		{ 0x1650, 0, 0x00000000, 0xffffffff },
-		{ 0x1654, 0, 0x00000000, 0xffffffff },
 
 		{ 0x1800, 0, 0x00000000, 0x00000001 },
 		{ 0x1804, 0, 0x00000000, 0x00000003 },
-		{ 0x1840, 0, 0x00000000, 0xffffffff },
-		{ 0x1844, 0, 0x00000000, 0xffffffff },
-		{ 0x1848, 0, 0x00000000, 0xffffffff },
-		{ 0x184c, 0, 0x00000000, 0xffffffff },
-		{ 0x1850, 0, 0x00000000, 0xffffffff },
-		{ 0x1900, 0, 0x7ffbffff, 0x00000000 },
-		{ 0x1904, 0, 0xffffffff, 0x00000000 },
-		{ 0x190c, 0, 0xffffffff, 0x00000000 },
-		{ 0x1914, 0, 0xffffffff, 0x00000000 },
-		{ 0x191c, 0, 0xffffffff, 0x00000000 },
-		{ 0x1924, 0, 0xffffffff, 0x00000000 },
-		{ 0x192c, 0, 0xffffffff, 0x00000000 },
-		{ 0x1934, 0, 0xffffffff, 0x00000000 },
-		{ 0x193c, 0, 0xffffffff, 0x00000000 },
-		{ 0x1944, 0, 0xffffffff, 0x00000000 },
-		{ 0x194c, 0, 0xffffffff, 0x00000000 },
-		{ 0x1954, 0, 0xffffffff, 0x00000000 },
-		{ 0x195c, 0, 0xffffffff, 0x00000000 },
-		{ 0x1964, 0, 0xffffffff, 0x00000000 },
-		{ 0x196c, 0, 0xffffffff, 0x00000000 },
-		{ 0x1974, 0, 0xffffffff, 0x00000000 },
-		{ 0x197c, 0, 0xffffffff, 0x00000000 },
-		{ 0x1980, 0, 0x0700ffff, 0x00000000 },
-
-		{ 0x1c00, 0, 0x00000000, 0x00000001 },
-		{ 0x1c04, 0, 0x00000000, 0x00000003 },
-		{ 0x1c08, 0, 0x0000000f, 0x00000000 },
-		{ 0x1c40, 0, 0x00000000, 0xffffffff },
-		{ 0x1c44, 0, 0x00000000, 0xffffffff },
-		{ 0x1c48, 0, 0x00000000, 0xffffffff },
-		{ 0x1c4c, 0, 0x00000000, 0xffffffff },
-		{ 0x1c50, 0, 0x00000000, 0xffffffff },
-		{ 0x1d00, 0, 0x7ffbffff, 0x00000000 },
-		{ 0x1d04, 0, 0xffffffff, 0x00000000 },
-		{ 0x1d0c, 0, 0xffffffff, 0x00000000 },
-		{ 0x1d14, 0, 0xffffffff, 0x00000000 },
-		{ 0x1d1c, 0, 0xffffffff, 0x00000000 },
-		{ 0x1d24, 0, 0xffffffff, 0x00000000 },
-		{ 0x1d2c, 0, 0xffffffff, 0x00000000 },
-		{ 0x1d34, 0, 0xffffffff, 0x00000000 },
-		{ 0x1d3c, 0, 0xffffffff, 0x00000000 },
-		{ 0x1d44, 0, 0xffffffff, 0x00000000 },
-		{ 0x1d4c, 0, 0xffffffff, 0x00000000 },
-		{ 0x1d54, 0, 0xffffffff, 0x00000000 },
-		{ 0x1d5c, 0, 0xffffffff, 0x00000000 },
-		{ 0x1d64, 0, 0xffffffff, 0x00000000 },
-		{ 0x1d6c, 0, 0xffffffff, 0x00000000 },
-		{ 0x1d74, 0, 0xffffffff, 0x00000000 },
-		{ 0x1d7c, 0, 0xffffffff, 0x00000000 },
-		{ 0x1d80, 0, 0x0700ffff, 0x00000000 },
-
-		{ 0x2004, 0, 0x00000000, 0x0337000f },
-		{ 0x2008, 0, 0xffffffff, 0x00000000 },
-		{ 0x200c, 0, 0xffffffff, 0x00000000 },
-		{ 0x2010, 0, 0xffffffff, 0x00000000 },
-		{ 0x2014, 0, 0x801fff80, 0x00000000 },
-		{ 0x2018, 0, 0x000003ff, 0x00000000 },
 
 		{ 0x2800, 0, 0x00000000, 0x00000001 },
 		{ 0x2804, 0, 0x00000000, 0x00003f01 },
@@ -3707,16 +3591,6 @@
 		{ 0x2c00, 0, 0x00000000, 0x00000011 },
 		{ 0x2c04, 0, 0x00000000, 0x00030007 },
 
-		{ 0x3000, 0, 0x00000000, 0x00000001 },
-		{ 0x3004, 0, 0x00000000, 0x007007ff },
-		{ 0x3008, 0, 0x00000003, 0x00000000 },
-		{ 0x300c, 0, 0xffffffff, 0x00000000 },
-		{ 0x3010, 0, 0xffffffff, 0x00000000 },
-		{ 0x3014, 0, 0xffffffff, 0x00000000 },
-		{ 0x3034, 0, 0xffffffff, 0x00000000 },
-		{ 0x3038, 0, 0xffffffff, 0x00000000 },
-		{ 0x3050, 0, 0x00000001, 0x00000000 },
-
 		{ 0x3c00, 0, 0x00000000, 0x00000001 },
 		{ 0x3c04, 0, 0x00000000, 0x00070000 },
 		{ 0x3c08, 0, 0x00007f71, 0x07f00000 },
@@ -3726,88 +3600,11 @@
 		{ 0x3c18, 0, 0x00000000, 0xffffffff },
 		{ 0x3c1c, 0, 0xfffff000, 0x00000000 },
 		{ 0x3c20, 0, 0xffffff00, 0x00000000 },
-		{ 0x3c24, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c28, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c2c, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c30, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c34, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c38, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c3c, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c40, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c44, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c48, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c4c, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c50, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c54, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c58, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c5c, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c60, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c64, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c68, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c6c, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c70, 0, 0xffffffff, 0x00000000 },
-		{ 0x3c74, 0, 0x0000003f, 0x00000000 },
-		{ 0x3c78, 0, 0x00000000, 0x00000000 },
-		{ 0x3c7c, 0, 0x00000000, 0x00000000 },
-		{ 0x3c80, 0, 0x3fffffff, 0x00000000 },
-		{ 0x3c84, 0, 0x0000003f, 0x00000000 },
-		{ 0x3c88, 0, 0x00000000, 0xffffffff },
-		{ 0x3c8c, 0, 0x00000000, 0xffffffff },
-
-		{ 0x4000, 0, 0x00000000, 0x00000001 },
-		{ 0x4004, 0, 0x00000000, 0x00030000 },
-		{ 0x4008, 0, 0x00000ff0, 0x00000000 },
-		{ 0x400c, 0, 0xffffffff, 0x00000000 },
-		{ 0x4088, 0, 0x00000000, 0x00070303 },
-
-		{ 0x4400, 0, 0x00000000, 0x00000001 },
-		{ 0x4404, 0, 0x00000000, 0x00003f01 },
-		{ 0x4408, 0, 0x7fff00ff, 0x00000000 },
-		{ 0x440c, 0, 0xffffffff, 0x00000000 },
-		{ 0x4410, 0, 0xffff,     0x0000 },
-		{ 0x4414, 0, 0xffff,     0x0000 },
-		{ 0x4418, 0, 0xffff,     0x0000 },
-		{ 0x441c, 0, 0xffff,     0x0000 },
-		{ 0x4428, 0, 0xffffffff, 0x00000000 },
-		{ 0x442c, 0, 0xffffffff, 0x00000000 },
-		{ 0x4430, 0, 0xffffffff, 0x00000000 },
-		{ 0x4434, 0, 0xffffffff, 0x00000000 },
-		{ 0x4438, 0, 0xffffffff, 0x00000000 },
-		{ 0x443c, 0, 0xffffffff, 0x00000000 },
-		{ 0x4440, 0, 0xffffffff, 0x00000000 },
-		{ 0x4444, 0, 0xffffffff, 0x00000000 },
-
-		{ 0x4c00, 0, 0x00000000, 0x00000001 },
-		{ 0x4c04, 0, 0x00000000, 0x0000003f },
-		{ 0x4c08, 0, 0xffffffff, 0x00000000 },
-		{ 0x4c0c, 0, 0x0007fc00, 0x00000000 },
-		{ 0x4c10, 0, 0x80003fe0, 0x00000000 },
-		{ 0x4c14, 0, 0xffffffff, 0x00000000 },
-		{ 0x4c44, 0, 0x00000000, 0x9fff9fff },
-		{ 0x4c48, 0, 0x00000000, 0xb3009fff },
-		{ 0x4c4c, 0, 0x00000000, 0x77f33b30 },
-		{ 0x4c50, 0, 0x00000000, 0xffffffff },
 
 		{ 0x5004, 0, 0x00000000, 0x0000007f },
 		{ 0x5008, 0, 0x0f0007ff, 0x00000000 },
 		{ 0x500c, 0, 0xf800f800, 0x07ff07ff },
 
-		{ 0x5400, 0, 0x00000008, 0x00000001 },
-		{ 0x5404, 0, 0x00000000, 0x0000003f },
-		{ 0x5408, 0, 0x0000001f, 0x00000000 },
-		{ 0x540c, 0, 0xffffffff, 0x00000000 },
-		{ 0x5410, 0, 0xffffffff, 0x00000000 },
-		{ 0x5414, 0, 0x0000ffff, 0x00000000 },
-		{ 0x5418, 0, 0x0000ffff, 0x00000000 },
-		{ 0x541c, 0, 0x0000ffff, 0x00000000 },
-		{ 0x5420, 0, 0x0000ffff, 0x00000000 },
-		{ 0x5428, 0, 0x000000ff, 0x00000000 },
-		{ 0x542c, 0, 0xff00ffff, 0x00000000 },
-		{ 0x5430, 0, 0x001fff80, 0x00000000 },
-		{ 0x5438, 0, 0xffffffff, 0x00000000 },
-		{ 0x543c, 0, 0xffffffff, 0x00000000 },
-		{ 0x5440, 0, 0xf800f800, 0x07ff07ff },
-
 		{ 0x5c00, 0, 0x00000000, 0x00000001 },
 		{ 0x5c04, 0, 0x00000000, 0x0003000f },
 		{ 0x5c08, 0, 0x00000003, 0x00000000 },
@@ -4794,6 +4591,64 @@
 	info->fw_version[5] = 0;
 }
 
+#define BNX2_REGDUMP_LEN		(32 * 1024)
+
+static int
+bnx2_get_regs_len(struct net_device *dev)
+{
+	return BNX2_REGDUMP_LEN;
+}
+
+static void
+bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
+{
+	u32 *p = _p, i, offset;
+	u8 *orig_p = _p;
+	struct bnx2 *bp = netdev_priv(dev);
+	u32 reg_boundaries[] = { 0x0000, 0x0098, 0x0400, 0x045c,
+				 0x0800, 0x0880, 0x0c00, 0x0c10,
+				 0x0c30, 0x0d08, 0x1000, 0x101c,
+				 0x1040, 0x1048, 0x1080, 0x10a4,
+				 0x1400, 0x1490, 0x1498, 0x14f0,
+				 0x1500, 0x155c, 0x1580, 0x15dc,
+				 0x1600, 0x1658, 0x1680, 0x16d8,
+				 0x1800, 0x1820, 0x1840, 0x1854,
+				 0x1880, 0x1894, 0x1900, 0x1984,
+				 0x1c00, 0x1c0c, 0x1c40, 0x1c54,
+				 0x1c80, 0x1c94, 0x1d00, 0x1d84,
+				 0x2000, 0x2030, 0x23c0, 0x2400,
+				 0x2800, 0x2820, 0x2830, 0x2850,
+				 0x2b40, 0x2c10, 0x2fc0, 0x3058,
+				 0x3c00, 0x3c94, 0x4000, 0x4010,
+				 0x4080, 0x4090, 0x43c0, 0x4458,
+				 0x4c00, 0x4c18, 0x4c40, 0x4c54,
+				 0x4fc0, 0x5010, 0x53c0, 0x5444,
+				 0x5c00, 0x5c18, 0x5c80, 0x5c90,
+				 0x5fc0, 0x6000, 0x6400, 0x6428,
+				 0x6800, 0x6848, 0x684c, 0x6860,
+				 0x6888, 0x6910, 0x8000 };
+
+	regs->version = 0;
+
+	memset(p, 0, BNX2_REGDUMP_LEN);
+
+	if (!netif_running(bp->dev))
+		return;
+
+	i = 0;
+	offset = reg_boundaries[0];
+	p += offset;
+	while (offset < BNX2_REGDUMP_LEN) {
+		*p++ = REG_RD(bp, offset);
+		offset += 4;
+		if (offset == reg_boundaries[i + 1]) {
+			offset = reg_boundaries[i + 2];
+			p = (u32 *) (orig_p + offset);
+			i += 2;
+		}
+	}
+}
+
 static void
 bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
@@ -4979,7 +4834,7 @@
 {
 	struct bnx2 *bp = netdev_priv(dev);
 
-	ering->rx_max_pending = MAX_RX_DESC_CNT;
+	ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT;
 	ering->rx_mini_max_pending = 0;
 	ering->rx_jumbo_max_pending = 0;
 
@@ -4996,17 +4851,28 @@
 {
 	struct bnx2 *bp = netdev_priv(dev);
 
-	if ((ering->rx_pending > MAX_RX_DESC_CNT) ||
+	if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) ||
 		(ering->tx_pending > MAX_TX_DESC_CNT) ||
 		(ering->tx_pending <= MAX_SKB_FRAGS)) {
 
 		return -EINVAL;
 	}
-	bp->rx_ring_size = ering->rx_pending;
+	if (netif_running(bp->dev)) {
+		bnx2_netif_stop(bp);
+		bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
+		bnx2_free_skbs(bp);
+		bnx2_free_mem(bp);
+	}
+
+	bnx2_set_rx_ring_size(bp, ering->rx_pending);
 	bp->tx_ring_size = ering->tx_pending;
 
 	if (netif_running(bp->dev)) {
-		bnx2_netif_stop(bp);
+		int rc;
+
+		rc = bnx2_alloc_mem(bp);
+		if (rc)
+			return rc;
 		bnx2_init_nic(bp);
 		bnx2_netif_start(bp);
 	}
@@ -5360,6 +5226,8 @@
 	.get_settings		= bnx2_get_settings,
 	.set_settings		= bnx2_set_settings,
 	.get_drvinfo		= bnx2_get_drvinfo,
+	.get_regs_len		= bnx2_get_regs_len,
+	.get_regs		= bnx2_get_regs,
 	.get_wol		= bnx2_get_wol,
 	.set_wol		= bnx2_set_wol,
 	.nway_reset		= bnx2_nway_reset,
@@ -5678,7 +5546,7 @@
 	bp->mac_addr[5] = (u8) reg;
 
 	bp->tx_ring_size = MAX_TX_DESC_CNT;
-	bp->rx_ring_size = 100;
+	bnx2_set_rx_ring_size(bp, 100);
 
 	bp->rx_csum = 1;
 
@@ -5897,6 +5765,7 @@
 	if (!netif_running(dev))
 		return 0;
 
+	flush_scheduled_work();
 	bnx2_netif_stop(bp);
 	netif_device_detach(dev);
 	del_timer_sync(&bp->timer);
diff -urN oldtree/drivers/net/bnx2.h newtree/drivers/net/bnx2.h
--- oldtree/drivers/net/bnx2.h	2006-02-19 11:41:03.146864704 +0000
+++ newtree/drivers/net/bnx2.h	2006-02-21 15:58:16.125695080 +0000
@@ -23,6 +23,7 @@
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
@@ -3792,8 +3793,10 @@
 #define TX_DESC_CNT  (BCM_PAGE_SIZE / sizeof(struct tx_bd))
 #define MAX_TX_DESC_CNT (TX_DESC_CNT - 1)
 
+#define MAX_RX_RINGS	4
 #define RX_DESC_CNT  (BCM_PAGE_SIZE / sizeof(struct rx_bd))
 #define MAX_RX_DESC_CNT (RX_DESC_CNT - 1)
+#define MAX_TOTAL_RX_DESC_CNT (MAX_RX_DESC_CNT * MAX_RX_RINGS)
 
 #define NEXT_TX_BD(x) (((x) & (MAX_TX_DESC_CNT - 1)) ==			\
 		(MAX_TX_DESC_CNT - 1)) ?				\
@@ -3805,8 +3808,10 @@
 		(MAX_RX_DESC_CNT - 1)) ?				\
 	(x) + 2 : (x) + 1
 
-#define RX_RING_IDX(x) ((x) & MAX_RX_DESC_CNT)
+#define RX_RING_IDX(x) ((x) & bp->rx_max_ring_idx)
 
+#define RX_RING(x) (((x) & ~MAX_RX_DESC_CNT) >> 8)
+#define RX_IDX(x) ((x) & MAX_RX_DESC_CNT)
 
 /* Context size. */
 #define CTX_SHIFT                   7
@@ -3903,6 +3908,15 @@
 	struct status_block	*status_blk;
 	u32 			last_status_idx;
 
+	u32			flags;
+#define PCIX_FLAG			1
+#define PCI_32BIT_FLAG			2
+#define ONE_TDMA_FLAG			4	/* no longer used */
+#define NO_WOL_FLAG			8
+#define USING_DAC_FLAG			0x10
+#define USING_MSI_FLAG			0x20
+#define ASF_ENABLE_FLAG			0x40
+
 	struct tx_bd		*tx_desc_ring;
 	struct sw_bd		*tx_buf_ring;
 	u32			tx_prod_bseq;
@@ -3920,19 +3934,22 @@
 	u32			rx_offset;
 	u32			rx_buf_use_size;	/* useable size */
 	u32			rx_buf_size;		/* with alignment */
-	struct rx_bd		*rx_desc_ring;
-	struct sw_bd		*rx_buf_ring;
+	u32			rx_max_ring_idx;
+
 	u32			rx_prod_bseq;
 	u16			rx_prod;
 	u16			rx_cons;
 
 	u32			rx_csum;
 
+	struct sw_bd		*rx_buf_ring;
+	struct rx_bd		*rx_desc_ring[MAX_RX_RINGS];
+
 	/* Only used to synchronize netif_stop_queue/wake_queue when tx */
 	/* ring is full */
 	spinlock_t		tx_lock;
 
-	/* End of fileds used in the performance code paths. */
+	/* End of fields used in the performance code paths. */
 
 	char			*name;
 
@@ -3945,15 +3962,6 @@
 	/* Used to synchronize phy accesses. */
 	spinlock_t		phy_lock;
 
-	u32			flags;
-#define PCIX_FLAG			1
-#define PCI_32BIT_FLAG			2
-#define ONE_TDMA_FLAG			4	/* no longer used */
-#define NO_WOL_FLAG			8
-#define USING_DAC_FLAG			0x10
-#define USING_MSI_FLAG			0x20
-#define ASF_ENABLE_FLAG			0x40
-
 	u32			phy_flags;
 #define PHY_SERDES_FLAG			1
 #define PHY_CRC_FIX_FLAG		2
@@ -4004,8 +4012,9 @@
 	dma_addr_t		tx_desc_mapping;
 
 
+	int			rx_max_ring;
 	int			rx_ring_size;
-	dma_addr_t		rx_desc_mapping;
+	dma_addr_t		rx_desc_mapping[MAX_RX_RINGS];
 
 	u16			tx_quick_cons_trip;
 	u16			tx_quick_cons_trip_int;
diff -urN oldtree/drivers/net/cassini.c newtree/drivers/net/cassini.c
--- oldtree/drivers/net/cassini.c	2006-02-19 11:41:03.173860600 +0000
+++ newtree/drivers/net/cassini.c	2006-02-21 15:58:16.770597040 +0000
@@ -91,6 +91,7 @@
 #include <linux/mii.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
+#include <linux/mutex.h>
 
 #include <net/checksum.h>
 
@@ -3892,7 +3893,7 @@
 	spin_unlock(&cp->stat_lock[N_TX_RINGS]);
 }
 
-/* Shut down the chip, must be called with pm_sem held.  */
+/* Shut down the chip, must be called with pm_mutex held.  */
 static void cas_shutdown(struct cas *cp)
 {
 	unsigned long flags;
@@ -4311,11 +4312,11 @@
 	int hw_was_up, err;
 	unsigned long flags;
 
-	down(&cp->pm_sem);
+	mutex_lock(&cp->pm_mutex);
 
 	hw_was_up = cp->hw_running;
 
-	/* The power-management semaphore protects the hw_running
+	/* The power-management mutex protects the hw_running
 	 * etc. state so it is safe to do this bit without cp->lock
 	 */
 	if (!cp->hw_running) {
@@ -4364,7 +4365,7 @@
 	cas_unlock_all_restore(cp, flags);
 
 	netif_start_queue(dev);
-	up(&cp->pm_sem);
+	mutex_unlock(&cp->pm_mutex);
 	return 0;
 
 err_spare:
@@ -4372,7 +4373,7 @@
 	cas_free_rxds(cp);
 err_tx_tiny:
 	cas_tx_tiny_free(cp);
-	up(&cp->pm_sem);
+	mutex_unlock(&cp->pm_mutex);
 	return err;
 }
 
@@ -4382,7 +4383,7 @@
 	struct cas *cp = netdev_priv(dev);
 
 	/* Make sure we don't get distracted by suspend/resume */
-	down(&cp->pm_sem);
+	mutex_lock(&cp->pm_mutex);
 
 	netif_stop_queue(dev);
 
@@ -4399,7 +4400,7 @@
 	cas_spare_free(cp);
 	cas_free_rxds(cp);
 	cas_tx_tiny_free(cp);
-	up(&cp->pm_sem);
+	mutex_unlock(&cp->pm_mutex);
 	return 0;
 }
 
@@ -4834,10 +4835,10 @@
 	unsigned long flags;
 	int rc = -EOPNOTSUPP;
 	
-	/* Hold the PM semaphore while doing ioctl's or we may collide
+	/* Hold the PM mutex while doing ioctl's or we may collide
 	 * with open/close and power management and oops.
 	 */
-	down(&cp->pm_sem);
+	mutex_lock(&cp->pm_mutex);
 	switch (cmd) {
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
 		data->phy_id = cp->phy_addr;
@@ -4867,7 +4868,7 @@
 		break;
 	};
 
-	up(&cp->pm_sem);
+	mutex_unlock(&cp->pm_mutex);
 	return rc;
 }
 
@@ -4994,7 +4995,7 @@
 		spin_lock_init(&cp->tx_lock[i]);
 	}
 	spin_lock_init(&cp->stat_lock[N_TX_RINGS]);
-	init_MUTEX(&cp->pm_sem);
+	mutex_init(&cp->pm_mutex);
 
 	init_timer(&cp->link_timer);
 	cp->link_timer.function = cas_link_timer;
@@ -5116,10 +5117,10 @@
 			    cp->init_block, cp->block_dvma);
 
 err_out_iounmap:
-	down(&cp->pm_sem);
+	mutex_lock(&cp->pm_mutex);
 	if (cp->hw_running)
 		cas_shutdown(cp);
-	up(&cp->pm_sem);
+	mutex_unlock(&cp->pm_mutex);
 
 	iounmap(cp->regs);
 
@@ -5152,11 +5153,11 @@
 	cp = netdev_priv(dev);
 	unregister_netdev(dev);
 
-	down(&cp->pm_sem);
+	mutex_lock(&cp->pm_mutex);
 	flush_scheduled_work();
 	if (cp->hw_running)
 		cas_shutdown(cp);
-	up(&cp->pm_sem);
+	mutex_unlock(&cp->pm_mutex);
 
 #if 1
 	if (cp->orig_cacheline_size) {
@@ -5183,10 +5184,7 @@
 	struct cas *cp = netdev_priv(dev);
 	unsigned long flags;
 
-	/* We hold the PM semaphore during entire driver
-	 * sleep time
-	 */
-	down(&cp->pm_sem);
+	mutex_lock(&cp->pm_mutex);
 	
 	/* If the driver is opened, we stop the DMA */
 	if (cp->opened) {
@@ -5206,6 +5204,7 @@
 
 	if (cp->hw_running)
 		cas_shutdown(cp);
+	mutex_unlock(&cp->pm_mutex);
 
 	return 0;
 }
@@ -5217,6 +5216,7 @@
 
 	printk(KERN_INFO "%s: resuming\n", dev->name);
 
+	mutex_lock(&cp->pm_mutex);
 	cas_hard_reset(cp);
 	if (cp->opened) {
 		unsigned long flags;
@@ -5229,7 +5229,7 @@
 
 		netif_device_attach(dev);
 	}
-	up(&cp->pm_sem);
+	mutex_unlock(&cp->pm_mutex);
 	return 0;
 }
 #endif /* CONFIG_PM */
diff -urN oldtree/drivers/net/cassini.h newtree/drivers/net/cassini.h
--- oldtree/drivers/net/cassini.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/cassini.h	2006-02-21 15:58:16.781595368 +0000
@@ -4284,7 +4284,7 @@
 	 * (ie. not power managed) */
 	int hw_running;
 	int opened;
-	struct semaphore pm_sem; /* open/close/suspend/resume */
+	struct mutex pm_mutex; /* open/close/suspend/resume */
 
 	struct cas_init_block *init_block;
 	struct cas_tx_desc *init_txds[MAX_TX_RINGS];
diff -urN oldtree/drivers/net/chelsio/cpl5_cmd.h newtree/drivers/net/chelsio/cpl5_cmd.h
--- oldtree/drivers/net/chelsio/cpl5_cmd.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/chelsio/cpl5_cmd.h	2006-02-21 15:58:36.331623312 +0000
@@ -108,7 +108,7 @@
 	u8 iff:4;
 #endif
 	u16 vlan;
-	u32 len;
+	__be32 len;
 
 	u32 rsvd2;
 	u8 rsvd3;
@@ -119,7 +119,7 @@
 	u8 ip_hdr_words:4;
 	u8 tcp_hdr_words:4;
 #endif
-	u16 eth_type_mss;
+	__be16 eth_type_mss;
 };
 
 struct cpl_rx_pkt {
@@ -138,7 +138,7 @@
 	u8 iff:4;
 #endif
 	u16 csum;
-	u16 vlan;
+	__be16 vlan;
 	u16 len;
 };
 
diff -urN oldtree/drivers/net/e100.c newtree/drivers/net/e100.c
--- oldtree/drivers/net/e100.c	2006-02-19 11:41:03.180859536 +0000
+++ newtree/drivers/net/e100.c	2006-02-21 15:58:15.340814400 +0000
@@ -280,12 +280,6 @@
 	rus_mask         = 0x3C,
 };
 
-enum ru_state  {
-	RU_SUSPENDED = 0,
-	RU_RUNNING	 = 1,
-	RU_UNINITIALIZED = -1,
-};
-
 enum scb_stat_ack {
 	stat_ack_not_ours    = 0x00,
 	stat_ack_sw_gen      = 0x04,
@@ -527,7 +521,6 @@
 	struct rx *rx_to_use;
 	struct rx *rx_to_clean;
 	struct rfd blank_rfd;
-	enum ru_state ru_running;
 
 	spinlock_t cb_lock			____cacheline_aligned;
 	spinlock_t cmd_lock;
@@ -948,7 +941,7 @@
 		((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i));
 
 	/* Template for a freshly allocated RFD */
-	nic->blank_rfd.command = cpu_to_le16(cb_el);
+	nic->blank_rfd.command = cpu_to_le16(cb_el & cb_s);
 	nic->blank_rfd.rbd = 0xFFFFFFFF;
 	nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN);
 
@@ -1746,19 +1739,11 @@
 	return 0;
 }
 
-static inline void e100_start_receiver(struct nic *nic, struct rx *rx)
+static inline void e100_start_receiver(struct nic *nic)
 {
-	if(!nic->rxs) return;
-	if(RU_SUSPENDED != nic->ru_running) return;
-
-	/* handle init time starts */
-	if(!rx) rx = nic->rxs;
-
-	/* (Re)start RU if suspended or idle and RFA is non-NULL */
-	if(rx->skb) {
-		e100_exec_cmd(nic, ruc_start, rx->dma_addr);
-		nic->ru_running = RU_RUNNING;
-	}
+	/* Start if RFA is non-NULL */
+	if(nic->rx_to_clean->skb)
+		e100_exec_cmd(nic, ruc_start, nic->rx_to_clean->dma_addr);
 }
 
 #define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN)
@@ -1788,7 +1773,7 @@
 		put_unaligned(cpu_to_le32(rx->dma_addr),
 			(u32 *)&prev_rfd->link);
 		wmb();
-		prev_rfd->command &= ~cpu_to_le16(cb_el);
+		prev_rfd->command &= ~cpu_to_le16(cb_el & cb_s);
 		pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,
 			sizeof(struct rfd), PCI_DMA_TODEVICE);
 	}
@@ -1826,10 +1811,6 @@
 	pci_unmap_single(nic->pdev, rx->dma_addr,
 		RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
 
-	/* this allows for a fast restart without re-enabling interrupts */
-	if(le16_to_cpu(rfd->command) & cb_el)
-		nic->ru_running = RU_SUSPENDED;
-
 	/* Pull off the RFD and put the actual data (minus eth hdr) */
 	skb_reserve(skb, sizeof(struct rfd));
 	skb_put(skb, actual_size);
@@ -1860,45 +1841,18 @@
 	unsigned int work_to_do)
 {
 	struct rx *rx;
-	int restart_required = 0;
-	struct rx *rx_to_start = NULL;
-
-	/* are we already rnr? then pay attention!!! this ensures that
-	 * the state machine progression never allows a start with a
-	 * partially cleaned list, avoiding a race between hardware
-	 * and rx_to_clean when in NAPI mode */
-	if(RU_SUSPENDED == nic->ru_running)
-		restart_required = 1;
 
 	/* Indicate newly arrived packets */
 	for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {
-		int err = e100_rx_indicate(nic, rx, work_done, work_to_do);
-		if(-EAGAIN == err) {
-			/* hit quota so have more work to do, restart once
-			 * cleanup is complete */
-			restart_required = 0;
-			break;
-		} else if(-ENODATA == err)
+		if(e100_rx_indicate(nic, rx, work_done, work_to_do))
 			break; /* No more to clean */
 	}
 
-	/* save our starting point as the place we'll restart the receiver */
-	if(restart_required)
-		rx_to_start = nic->rx_to_clean;
-
 	/* Alloc new skbs to refill list */
 	for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {
 		if(unlikely(e100_rx_alloc_skb(nic, rx)))
 			break; /* Better luck next time (see watchdog) */
 	}
-
-	if(restart_required) {
-		// ack the rnr?
-		writeb(stat_ack_rnr, &nic->csr->scb.stat_ack);
-		e100_start_receiver(nic, rx_to_start);
-		if(work_done)
-			(*work_done)++;
-	}
 }
 
 static void e100_rx_clean_list(struct nic *nic)
@@ -1906,8 +1860,6 @@
 	struct rx *rx;
 	unsigned int i, count = nic->params.rfds.count;
 
-	nic->ru_running = RU_UNINITIALIZED;
-
 	if(nic->rxs) {
 		for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
 			if(rx->skb) {
@@ -1929,7 +1881,6 @@
 	unsigned int i, count = nic->params.rfds.count;
 
 	nic->rx_to_use = nic->rx_to_clean = NULL;
-	nic->ru_running = RU_UNINITIALIZED;
 
 	if(!(nic->rxs = kmalloc(sizeof(struct rx) * count, GFP_ATOMIC)))
 		return -ENOMEM;
@@ -1945,7 +1896,6 @@
 	}
 
 	nic->rx_to_use = nic->rx_to_clean = nic->rxs;
-	nic->ru_running = RU_SUSPENDED;
 
 	return 0;
 }
@@ -1965,10 +1915,6 @@
 	/* Ack interrupt(s) */
 	writeb(stat_ack, &nic->csr->scb.stat_ack);
 
-	/* We hit Receive No Resource (RNR); restart RU after cleaning */
-	if(stat_ack & stat_ack_rnr)
-		nic->ru_running = RU_SUSPENDED;
-
 	if(likely(netif_rx_schedule_prep(netdev))) {
 		e100_disable_irq(nic);
 		__netif_rx_schedule(netdev);
@@ -2062,7 +2008,7 @@
 	if((err = e100_hw_init(nic)))
 		goto err_clean_cbs;
 	e100_set_multicast_list(nic->netdev);
-	e100_start_receiver(nic, NULL);
+	e100_start_receiver(nic);
 	mod_timer(&nic->watchdog, jiffies);
 	if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ,
 		nic->netdev->name, nic->netdev)))
@@ -2142,7 +2088,7 @@
 		mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR,
 			BMCR_LOOPBACK);
 
-	e100_start_receiver(nic, NULL);
+	e100_start_receiver(nic);
 
 	if(!(skb = dev_alloc_skb(ETH_DATA_LEN))) {
 		err = -ENOMEM;
diff -urN oldtree/drivers/net/eth16i.c newtree/drivers/net/eth16i.c
--- oldtree/drivers/net/eth16i.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/eth16i.c	2006-02-21 15:58:15.344813792 +0000
@@ -161,6 +161,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/bitops.h>
+#include <linux/jiffies.h>
 
 #include <asm/system.h>		  
 #include <asm/io.h>		  
@@ -754,7 +755,7 @@
 
 static int eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l)
 {
-	int starttime;
+	unsigned long starttime;
 
 	outb(0xff, ioaddr + TX_STATUS_REG);
 
@@ -765,7 +766,7 @@
 	outb(TX_START | 1, ioaddr + TRANSMIT_START_REG); 
 
 	while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0) {
-		if( (jiffies - starttime) > TX_TIMEOUT) {
+		if( time_after(jiffies, starttime + TX_TIMEOUT)) {
 			return -1;
 		}
 	}
@@ -775,18 +776,18 @@
 
 static int eth16i_receive_probe_packet(int ioaddr)
 {
-	int starttime;
+	unsigned long starttime;
 
 	starttime = jiffies;
 
 	while((inb(ioaddr + TX_STATUS_REG) & 0x20) == 0) {
-		if( (jiffies - starttime) > TX_TIMEOUT) {
+		if( time_after(jiffies, starttime + TX_TIMEOUT)) {
 
 			if(eth16i_debug > 1)
 				printk(KERN_DEBUG "Timeout occurred waiting transmit packet received\n");
 			starttime = jiffies;
 			while((inb(ioaddr + RX_STATUS_REG) & 0x80) == 0) {
-				if( (jiffies - starttime) > TX_TIMEOUT) {
+				if( time_after(jiffies, starttime + TX_TIMEOUT)) {
 					if(eth16i_debug > 1)
 						printk(KERN_DEBUG "Timeout occurred waiting receive packet\n");
 					return -1;
diff -urN oldtree/drivers/net/fs_enet/mac-fcc.c newtree/drivers/net/fs_enet/mac-fcc.c
--- oldtree/drivers/net/fs_enet/mac-fcc.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/fs_enet/mac-fcc.c	2006-02-21 15:58:12.481249120 +0000
@@ -118,6 +118,8 @@
 
 	/* Fill out IRQ field */
 	fep->interrupt = platform_get_irq(pdev, 0);
+	if (fep->interrupt < 0)
+		return -EINVAL;
 
 	/* Attach the memory for the FCC Parameter RAM */
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram");
diff -urN oldtree/drivers/net/fs_enet/mac-fec.c newtree/drivers/net/fs_enet/mac-fec.c
--- oldtree/drivers/net/fs_enet/mac-fec.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/fs_enet/mac-fec.c	2006-02-21 15:58:12.482248968 +0000
@@ -144,6 +144,8 @@
 	
 	/* Fill out IRQ field */
 	fep->interrupt = platform_get_irq_byname(pdev,"interrupt");
+	if (fep->interrupt < 0)
+		return -EINVAL;
 	
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
 	fep->fec.fecp =(void*)r->start;
diff -urN oldtree/drivers/net/fs_enet/mac-scc.c newtree/drivers/net/fs_enet/mac-scc.c
--- oldtree/drivers/net/fs_enet/mac-scc.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/fs_enet/mac-scc.c	2006-02-21 15:58:12.483248816 +0000
@@ -118,6 +118,8 @@
 
 	/* Fill out IRQ field */
 	fep->interrupt = platform_get_irq_byname(pdev, "interrupt");
+	if (fep->interrupt < 0)
+		return -EINVAL;
 
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
 	fep->scc.sccp = (void *)r->start;
diff -urN oldtree/drivers/net/gianfar.c newtree/drivers/net/gianfar.c
--- oldtree/drivers/net/gianfar.c	2006-02-19 11:41:03.261847224 +0000
+++ newtree/drivers/net/gianfar.c	2006-02-21 15:58:12.490247752 +0000
@@ -193,8 +193,12 @@
 		priv->interruptTransmit = platform_get_irq_byname(pdev, "tx");
 		priv->interruptReceive = platform_get_irq_byname(pdev, "rx");
 		priv->interruptError = platform_get_irq_byname(pdev, "error");
+		if (priv->interruptTransmit < 0 || priv->interruptReceive < 0 || priv->interruptError < 0)
+			goto regs_fail;
 	} else {
 		priv->interruptTransmit = platform_get_irq(pdev, 0);
+		if (priv->interruptTransmit < 0)
+			goto regs_fail;
 	}
 
 	/* get a pointer to the register memory */
diff -urN oldtree/drivers/net/hamradio/baycom_epp.c newtree/drivers/net/hamradio/baycom_epp.c
--- oldtree/drivers/net/hamradio/baycom_epp.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/hamradio/baycom_epp.c	2006-02-21 15:58:15.353812424 +0000
@@ -905,7 +905,7 @@
 	/* autoprobe baud rate */
 	tstart = jiffies;
 	i = 0;
-	while ((signed)(jiffies-tstart-HZ/3) < 0) {
+	while (time_before(jiffies, tstart + HZ/3)) {
 		if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1)
 			goto epptimeout;
 		if ((stat & (EPP_NRAEF|EPP_NRHF)) == EPP_NRHF) {
diff -urN oldtree/drivers/net/hp100.c newtree/drivers/net/hp100.c
--- oldtree/drivers/net/hp100.c	2006-02-19 11:41:03.270845856 +0000
+++ newtree/drivers/net/hp100.c	2006-02-21 15:58:15.359811512 +0000
@@ -115,6 +115,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
+#include <linux/jiffies.h>
 
 #include <asm/io.h>
 
@@ -1499,7 +1500,7 @@
 		printk("hp100: %s: start_xmit_bm: No TX PDL available.\n", dev->name);
 #endif
 		/* not waited long enough since last tx? */
-		if (jiffies - dev->trans_start < HZ)
+		if (time_before(jiffies, dev->trans_start + HZ))
 			return -EAGAIN;
 
 		if (hp100_check_lan(dev))
@@ -1652,7 +1653,7 @@
 		printk("hp100: %s: start_xmit: tx free mem = 0x%x\n", dev->name, i);
 #endif
 		/* not waited long enough since last failed tx try? */
-		if (jiffies - dev->trans_start < HZ) {
+		if (time_before(jiffies, dev->trans_start + HZ)) {
 #ifdef HP100_DEBUG
 			printk("hp100: %s: trans_start timing problem\n",
 			       dev->name);
@@ -1718,17 +1719,10 @@
 	hp100_outw(i, FRAGMENT_LEN);	/* and first/only fragment length    */
 
 	if (lp->mode == 2) {	/* memory mapped */
-		if (lp->mem_ptr_virt) {	/* high pci memory was remapped */
-			/* Note: The J2585B needs alignment to 32bits here!  */
-			memcpy_toio(lp->mem_ptr_virt, skb->data, (skb->len + 3) & ~3);
-			if (!ok_flag)
-				memset_io(lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len);
-		} else {
-			/* Note: The J2585B needs alignment to 32bits here!  */
-			isa_memcpy_toio(lp->mem_ptr_phys, skb->data, (skb->len + 3) & ~3);
-			if (!ok_flag)
-				isa_memset_io(lp->mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb->len);
-		}
+		/* Note: The J2585B needs alignment to 32bits here!  */
+		memcpy_toio(lp->mem_ptr_virt, skb->data, (skb->len + 3) & ~3);
+		if (!ok_flag)
+			memset_io(lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len);
 	} else {		/* programmed i/o */
 		outsl(ioaddr + HP100_REG_DATA32, skb->data,
 		      (skb->len + 3) >> 2);
@@ -1798,10 +1792,7 @@
 		/* First we get the header, which contains information about the */
 		/* actual length of the received packet. */
 		if (lp->mode == 2) {	/* memory mapped mode */
-			if (lp->mem_ptr_virt)	/* if memory was remapped */
-				header = readl(lp->mem_ptr_virt);
-			else
-				header = isa_readl(lp->mem_ptr_phys);
+			header = readl(lp->mem_ptr_virt);
 		} else		/* programmed i/o */
 			header = hp100_inl(DATA32);
 
@@ -1833,13 +1824,9 @@
 			ptr = skb->data;
 
 			/* Now transfer the data from the card into that area */
-			if (lp->mode == 2) {
-				if (lp->mem_ptr_virt)
-					memcpy_fromio(ptr, lp->mem_ptr_virt,pkt_len);
-				/* Note alignment to 32bit transfers */
-				else
-					isa_memcpy_fromio(ptr, lp->mem_ptr_phys, pkt_len);
-			} else	/* io mapped */
+			if (lp->mode == 2)
+				memcpy_fromio(ptr, lp->mem_ptr_virt,pkt_len);
+			else	/* io mapped */
 				insl(ioaddr + HP100_REG_DATA32, ptr, pkt_len >> 2);
 
 			skb->protocol = eth_type_trans(skb, dev);
diff -urN oldtree/drivers/net/hydra.c newtree/drivers/net/hydra.c
--- oldtree/drivers/net/hydra.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/hydra.c	2006-02-21 15:58:36.340621944 +0000
@@ -31,7 +31,16 @@
 #include <asm/amigahw.h>
 #include <linux/zorro.h>
 
-#include "8390.h"
+#define EI_SHIFT(x)	(ei_local->reg_offset[x])
+#define ei_inb(port)   in_8(port)
+#define ei_outb(val,port)  out_8(port,val)
+#define ei_inb_p(port)   in_8(port)
+#define ei_outb_p(val,port)  out_8(port,val)
+
+static const char version[] =
+    "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+
+#include "lib8390.c"
 
 #define NE_EN0_DCFG     (0x0e*2)
 
@@ -100,7 +109,7 @@
 	0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
     };
 
-    dev = alloc_ei_netdev();
+    dev = ____alloc_ei_netdev(0);
     if (!dev)
 	return -ENOMEM;
     SET_MODULE_OWNER(dev);
@@ -117,7 +126,7 @@
     dev->irq = IRQ_AMIGA_PORTS;
 
     /* Install the Interrupt handler */
-    if (request_irq(IRQ_AMIGA_PORTS, ei_interrupt, SA_SHIRQ, "Hydra Ethernet",
+    if (request_irq(IRQ_AMIGA_PORTS, __ei_interrupt, SA_SHIRQ, "Hydra Ethernet",
 		    dev)) {
 	free_netdev(dev);
 	return -EAGAIN;
@@ -139,10 +148,10 @@
     dev->open = &hydra_open;
     dev->stop = &hydra_close;
 #ifdef CONFIG_NET_POLL_CONTROLLER
-    dev->poll_controller = ei_poll;
+    dev->poll_controller = __ei_poll;
 #endif
 
-    NS8390_init(dev, 0);
+    __NS8390_init(dev, 0);
 
     err = register_netdev(dev);
     if (err) {
@@ -164,7 +173,7 @@
 
 static int hydra_open(struct net_device *dev)
 {
-    ei_open(dev);
+    __ei_open(dev);
     return 0;
 }
 
@@ -172,7 +181,7 @@
 {
     if (ei_debug > 1)
 	printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
-    ei_close(dev);
+    __ei_close(dev);
     return 0;
 }
 
diff -urN oldtree/drivers/net/ibm_emac/ibm_emac_core.c newtree/drivers/net/ibm_emac/ibm_emac_core.c
--- oldtree/drivers/net/ibm_emac/ibm_emac_core.c	2006-02-19 11:41:03.273845400 +0000
+++ newtree/drivers/net/ibm_emac/ibm_emac_core.c	2006-02-21 15:58:15.369809992 +0000
@@ -204,7 +204,7 @@
 
 static inline void emac_tx_enable(struct ocp_enet_private *dev)
 {
-	struct emac_regs *p = dev->emacp;
+	struct emac_regs __iomem *p = dev->emacp;
 	unsigned long flags;
 	u32 r;
 
@@ -220,7 +220,7 @@
 
 static void emac_tx_disable(struct ocp_enet_private *dev)
 {
-	struct emac_regs *p = dev->emacp;
+	struct emac_regs __iomem *p = dev->emacp;
 	unsigned long flags;
 	u32 r;
 
@@ -244,7 +244,7 @@
 
 static void emac_rx_enable(struct ocp_enet_private *dev)
 {
-	struct emac_regs *p = dev->emacp;
+	struct emac_regs __iomem *p = dev->emacp;
 	unsigned long flags;
 	u32 r;
 
@@ -275,7 +275,7 @@
 
 static void emac_rx_disable(struct ocp_enet_private *dev)
 {
-	struct emac_regs *p = dev->emacp;
+	struct emac_regs __iomem *p = dev->emacp;
 	unsigned long flags;
 	u32 r;
 
@@ -299,7 +299,7 @@
 
 static inline void emac_rx_disable_async(struct ocp_enet_private *dev)
 {
-	struct emac_regs *p = dev->emacp;
+	struct emac_regs __iomem *p = dev->emacp;
 	unsigned long flags;
 	u32 r;
 
@@ -315,7 +315,7 @@
 
 static int emac_reset(struct ocp_enet_private *dev)
 {
-	struct emac_regs *p = dev->emacp;
+	struct emac_regs __iomem *p = dev->emacp;
 	unsigned long flags;
 	int n = 20;
 
@@ -348,7 +348,7 @@
 
 static void emac_hash_mc(struct ocp_enet_private *dev)
 {
-	struct emac_regs *p = dev->emacp;
+	struct emac_regs __iomem *p = dev->emacp;
 	u16 gaht[4] = { 0 };
 	struct dev_mc_list *dmi;
 
@@ -393,7 +393,7 @@
 /* BHs disabled */
 static int emac_configure(struct ocp_enet_private *dev)
 {
-	struct emac_regs *p = dev->emacp;
+	struct emac_regs __iomem *p = dev->emacp;
 	struct net_device *ndev = dev->ndev;
 	int gige;
 	u32 r;
@@ -555,7 +555,7 @@
 
 static int __emac_mdio_read(struct ocp_enet_private *dev, u8 id, u8 reg)
 {
-	struct emac_regs *p = dev->emacp;
+	struct emac_regs __iomem *p = dev->emacp;
 	u32 r;
 	int n;
 
@@ -604,7 +604,7 @@
 static void __emac_mdio_write(struct ocp_enet_private *dev, u8 id, u8 reg,
 			      u16 val)
 {
-	struct emac_regs *p = dev->emacp;
+	struct emac_regs __iomem *p = dev->emacp;
 	int n;
 
 	DBG2("%d: mdio_write(%02x,%02x,%04x)" NL, dev->def->index, id, reg,
@@ -666,7 +666,7 @@
 static void emac_set_multicast_list(struct net_device *ndev)
 {
 	struct ocp_enet_private *dev = ndev->priv;
-	struct emac_regs *p = dev->emacp;
+	struct emac_regs __iomem *p = dev->emacp;
 	u32 rmr = emac_iff2rmr(ndev);
 
 	DBG("%d: multicast %08x" NL, dev->def->index, rmr);
@@ -825,7 +825,7 @@
 }
 
 static inline int emac_alloc_rx_skb(struct ocp_enet_private *dev, int slot,
-				    int flags)
+				    gfp_t flags)
 {
 	struct sk_buff *skb = alloc_skb(dev->rx_skb_size, flags);
 	if (unlikely(!skb))
@@ -1047,7 +1047,7 @@
 
 static inline int emac_xmit_finish(struct ocp_enet_private *dev, int len)
 {
-	struct emac_regs *p = dev->emacp;
+	struct emac_regs __iomem *p = dev->emacp;
 	struct net_device *ndev = dev->ndev;
 
 	/* Send the packet out */
@@ -1519,7 +1519,7 @@
 static irqreturn_t emac_irq(int irq, void *dev_instance, struct pt_regs *regs)
 {
 	struct ocp_enet_private *dev = dev_instance;
-	struct emac_regs *p = dev->emacp;
+	struct emac_regs __iomem *p = dev->emacp;
 	struct ibm_emac_error_stats *st = &dev->estats;
 
 	u32 isr = in_be32(&p->isr);
@@ -1619,17 +1619,17 @@
 
 	DBG("%d: remove" NL, dev->def->index);
 
-	ocp_set_drvdata(ocpdev, 0);
+	ocp_set_drvdata(ocpdev, NULL);
 	unregister_netdev(dev->ndev);
 
 	tah_fini(dev->tah_dev);
 	rgmii_fini(dev->rgmii_dev, dev->rgmii_input);
 	zmii_fini(dev->zmii_dev, dev->zmii_input);
 
-	emac_dbg_register(dev->def->index, 0);
+	emac_dbg_register(dev->def->index, NULL);
 
 	mal_unregister_commac(dev->mal, &dev->commac);
-	iounmap((void *)dev->emacp);
+	iounmap(dev->emacp);
 	kfree(dev->ndev);
 }
 
@@ -2048,9 +2048,7 @@
 		goto out4;
 
 	/* Map EMAC regs */
-	dev->emacp =
-	    (struct emac_regs *)ioremap(dev->def->paddr,
-					sizeof(struct emac_regs));
+	dev->emacp = ioremap(dev->def->paddr, sizeof(struct emac_regs));
 	if (!dev->emacp) {
 		printk(KERN_ERR "emac%d: could not ioremap device registers!\n",
 		       dev->def->index);
@@ -2210,7 +2208,7 @@
 
 	return 0;
       out6:
-	iounmap((void *)dev->emacp);
+	iounmap(dev->emacp);
       out5:
 	tah_fini(dev->tah_dev);
       out4:
diff -urN oldtree/drivers/net/ibm_emac/ibm_emac_core.h newtree/drivers/net/ibm_emac/ibm_emac_core.h
--- oldtree/drivers/net/ibm_emac/ibm_emac_core.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/ibm_emac/ibm_emac_core.h	2006-02-21 15:58:15.370809840 +0000
@@ -155,7 +155,7 @@
 
 struct ocp_enet_private {
 	struct net_device		*ndev;		/* 0 */
-	struct emac_regs		*emacp;
+	struct emac_regs		__iomem *emacp;
 	
 	struct mal_descriptor		*tx_desc;
 	int				tx_cnt;
diff -urN oldtree/drivers/net/ibm_emac/ibm_emac_debug.c newtree/drivers/net/ibm_emac/ibm_emac_debug.c
--- oldtree/drivers/net/ibm_emac/ibm_emac_debug.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/ibm_emac/ibm_emac_debug.c	2006-02-21 15:58:15.371809688 +0000
@@ -58,7 +58,7 @@
 
 static void emac_mac_dump(int idx, struct ocp_enet_private *dev)
 {
-	struct emac_regs *p = dev->emacp;
+	struct emac_regs __iomem *p = dev->emacp;
 
 	printk("** EMAC%d registers **\n"
 	       "MR0 = 0x%08x MR1 = 0x%08x TMR0 = 0x%08x TMR1 = 0x%08x\n"
diff -urN oldtree/drivers/net/ibm_emac/ibm_emac_rgmii.h newtree/drivers/net/ibm_emac/ibm_emac_rgmii.h
--- oldtree/drivers/net/ibm_emac/ibm_emac_rgmii.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/ibm_emac/ibm_emac_rgmii.h	2006-02-21 15:58:15.371809688 +0000
@@ -31,7 +31,7 @@
 
 /* RGMII device */
 struct ibm_ocp_rgmii {
-	struct rgmii_regs *base;
+	struct rgmii_regs __iomem *base;
 	int users;		/* number of EMACs using this RGMII bridge */
 };
 
diff -urN oldtree/drivers/net/ibm_emac/ibm_emac_zmii.c newtree/drivers/net/ibm_emac/ibm_emac_zmii.c
--- oldtree/drivers/net/ibm_emac/ibm_emac_zmii.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/ibm_emac/ibm_emac_zmii.c	2006-02-21 15:58:15.372809536 +0000
@@ -80,7 +80,7 @@
 static int __init zmii_init(struct ocp_device *ocpdev, int input, int *mode)
 {
 	struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev);
-	struct zmii_regs *p;
+	struct zmii_regs __iomem *p;
 
 	ZMII_DBG("%d: init(%d, %d)" NL, ocpdev->def->index, input, *mode);
 
@@ -94,8 +94,7 @@
 		}
 		dev->mode = PHY_MODE_NA;
 
-		p = (struct zmii_regs *)ioremap(ocpdev->def->paddr,
-						sizeof(struct zmii_regs));
+		p = ioremap(ocpdev->def->paddr, sizeof(struct zmii_regs));
 		if (!p) {
 			printk(KERN_ERR
 			       "zmii%d: could not ioremap device registers!\n",
@@ -231,7 +230,7 @@
 	if (!--dev->users) {
 		/* Free everything if this is the last user */
 		ocp_set_drvdata(ocpdev, NULL);
-		iounmap((void *)dev->base);
+		iounmap(dev->base);
 		kfree(dev);
 	}
 }
diff -urN oldtree/drivers/net/ibm_emac/ibm_emac_zmii.h newtree/drivers/net/ibm_emac/ibm_emac_zmii.h
--- oldtree/drivers/net/ibm_emac/ibm_emac_zmii.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/ibm_emac/ibm_emac_zmii.h	2006-02-21 15:58:15.372809536 +0000
@@ -32,7 +32,7 @@
 
 /* ZMII device */
 struct ibm_ocp_zmii {
-	struct zmii_regs *base;
+	struct zmii_regs __iomem *base;
 	int mode;		/* subset of PHY_MODE_XXXX */
 	int users;		/* number of EMACs using this ZMII bridge */
 	u32 fer_save;		/* FER value left by firmware */
diff -urN oldtree/drivers/net/irda/donauboe.c newtree/drivers/net/irda/donauboe.c
--- oldtree/drivers/net/irda/donauboe.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/irda/donauboe.c	2006-02-21 15:58:16.132694016 +0000
@@ -1778,7 +1778,7 @@
 static int __init
 donauboe_init (void)
 {
-  return pci_module_init(&donauboe_pci_driver);
+  return pci_register_driver(&donauboe_pci_driver);
 }
 
 static void __exit
diff -urN oldtree/drivers/net/irda/ep7211_ir.c newtree/drivers/net/irda/ep7211_ir.c
--- oldtree/drivers/net/irda/ep7211_ir.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/irda/ep7211_ir.c	2006-02-21 15:58:16.133693864 +0000
@@ -8,6 +8,7 @@
 #include <linux/delay.h>
 #include <linux/tty.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irda_device.h>
@@ -23,6 +24,8 @@
 static int  ep7211_ir_change_speed(struct irda_task *task);
 static int  ep7211_ir_reset(struct irda_task *task);
 
+static DEFINE_SPINLOCK(ep7211_lock);
+
 static struct dongle_reg dongle = {
 	.type = IRDA_EP7211_IR,
 	.open = ep7211_ir_open,
@@ -36,7 +39,7 @@
 {
 	unsigned int syscon1, flags;
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&ep7211_lock, flags);
 
 	/* Turn on the SIR encoder. */
 	syscon1 = clps_readl(SYSCON1);
@@ -46,14 +49,14 @@
 	/* XXX: We should disable modem status interrupts on the first
 		UART (interrupt #14). */
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&ep7211_lock, flags);
 }
 
 static void ep7211_ir_close(dongle_t *self)
 {
 	unsigned int syscon1, flags;
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&ep7211_lock, flags);
 
 	/* Turn off the SIR encoder. */
 	syscon1 = clps_readl(SYSCON1);
@@ -63,7 +66,7 @@
 	/* XXX: If we've disabled the modem status interrupts, we should
 		reset them back to their original state. */
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&ep7211_lock, flags);
 }
 
 /*
diff -urN oldtree/drivers/net/irda/irtty-sir.c newtree/drivers/net/irda/irtty-sir.c
--- oldtree/drivers/net/irda/irtty-sir.c	2006-02-19 11:41:03.277844792 +0000
+++ newtree/drivers/net/irda/irtty-sir.c	2006-02-21 15:58:16.551630328 +0000
@@ -33,6 +33,7 @@
 #include <asm/uaccess.h>
 #include <linux/smp_lock.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irda_device.h>
@@ -338,7 +339,7 @@
 /*****************************************************************/
 
 /* serialize ldisc open/close with sir_dev */
-static DECLARE_MUTEX(irtty_sem);
+static DEFINE_MUTEX(irtty_mutex);
 
 /* notifier from sir_dev when irda% device gets opened (ifup) */
 
@@ -348,11 +349,11 @@
 	struct tty_struct *tty;
 
 	/* serialize with ldisc open/close */
-	down(&irtty_sem);
+	mutex_lock(&irtty_mutex);
 
 	priv = dev->priv;
 	if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) {
-		up(&irtty_sem);
+		mutex_unlock(&irtty_mutex);
 		return -ESTALE;
 	}
 
@@ -363,7 +364,7 @@
 	/* Make sure we can receive more data */
 	irtty_stop_receiver(tty, FALSE);
 
-	up(&irtty_sem);
+	mutex_unlock(&irtty_mutex);
 	return 0;
 }
 
@@ -375,11 +376,11 @@
 	struct tty_struct *tty;
 
 	/* serialize with ldisc open/close */
-	down(&irtty_sem);
+	mutex_lock(&irtty_mutex);
 
 	priv = dev->priv;
 	if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) {
-		up(&irtty_sem);
+		mutex_unlock(&irtty_mutex);
 		return -ESTALE;
 	}
 
@@ -390,7 +391,7 @@
 	if (tty->driver->stop)
 		tty->driver->stop(tty);
 
-	up(&irtty_sem);
+	mutex_unlock(&irtty_mutex);
 
 	return 0;
 }
@@ -514,13 +515,13 @@
 	priv->dev = dev;
 
 	/* serialize with start_dev - in case we were racing with ifup */
-	down(&irtty_sem);
+	mutex_lock(&irtty_mutex);
 
 	dev->priv = priv;
 	tty->disc_data = priv;
 	tty->receive_room = 65536;
 
-	up(&irtty_sem);
+	mutex_unlock(&irtty_mutex);
 
 	IRDA_DEBUG(0, "%s - %s: irda line discipline opened\n", __FUNCTION__, tty->name);
 
diff -urN oldtree/drivers/net/irda/nsc-ircc.c newtree/drivers/net/irda/nsc-ircc.c
--- oldtree/drivers/net/irda/nsc-ircc.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/irda/nsc-ircc.c	2006-02-21 15:58:16.137693256 +0000
@@ -12,6 +12,7 @@
  *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>
  *     Copyright (c) 1998 Lichen Wang, <lwang@actisys.com>
  *     Copyright (c) 1998 Actisys Corp., www.actisys.com
+ *     Copyright (c) 2000-2004 Jean Tourrilhes <jt@hpl.hp.com>
  *     All Rights Reserved
  *      
  *     This program is free software; you can redistribute it and/or 
@@ -53,14 +54,13 @@
 #include <linux/init.h>
 #include <linux/rtnetlink.h>
 #include <linux/dma-mapping.h>
+#include <linux/pnp.h>
+#include <linux/platform_device.h>
 
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/byteorder.h>
 
-#include <linux/pm.h>
-#include <linux/pm_legacy.h>
-
 #include <net/irda/wrapper.h>
 #include <net/irda/irda.h>
 #include <net/irda/irda_device.h>
@@ -72,14 +72,27 @@
 
 static char *driver_name = "nsc-ircc";
 
+/* Power Management */
+#define NSC_IRCC_DRIVER_NAME                  "nsc-ircc"
+static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state);
+static int nsc_ircc_resume(struct platform_device *dev);
+
+static struct platform_driver nsc_ircc_driver = {
+	.suspend	= nsc_ircc_suspend,
+	.resume		= nsc_ircc_resume,
+	.driver		= {
+		.name	= NSC_IRCC_DRIVER_NAME,
+	},
+};
+
 /* Module parameters */
 static int qos_mtt_bits = 0x07;  /* 1 ms or more */
 static int dongle_id;
 
 /* Use BIOS settions by default, but user may supply module parameters */
-static unsigned int io[]  = { ~0, ~0, ~0, ~0 };
-static unsigned int irq[] = { 0, 0, 0, 0, 0 };
-static unsigned int dma[] = { 0, 0, 0, 0, 0 };
+static unsigned int io[]  = { ~0, ~0, ~0, ~0, ~0 };
+static unsigned int irq[] = {  0,  0,  0,  0,  0 };
+static unsigned int dma[] = {  0,  0,  0,  0,  0 };
 
 static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info);
 static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info);
@@ -87,6 +100,7 @@
 static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info);
 static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info);
 static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info);
+static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id);
 
 /* These are the known NSC chips */
 static nsc_chip_t chips[] = {
@@ -101,11 +115,12 @@
 	/* Contributed by Jan Frey - IBM A30/A31 */
 	{ "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff, 
 	  nsc_ircc_probe_39x, nsc_ircc_init_39x },
+	{ "IBM", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff,
+ 	  nsc_ircc_probe_39x, nsc_ircc_init_39x },
 	{ NULL }
 };
 
-/* Max 4 instances for now */
-static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL };
+static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL, NULL };
 
 static char *dongle_types[] = {
 	"Differential serial interface",
@@ -126,8 +141,24 @@
 	"No dongle connected",
 };
 
+/* PNP probing */
+static chipio_t pnp_info;
+static const struct pnp_device_id nsc_ircc_pnp_table[] = {
+	{ .id = "NSC6001", .driver_data = 0 },
+	{ .id = "IBM0071", .driver_data = 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(pnp, nsc_ircc_pnp_table);
+
+static struct pnp_driver nsc_ircc_pnp_driver = {
+	.name = "nsc-ircc",
+	.id_table = nsc_ircc_pnp_table,
+	.probe = nsc_ircc_pnp_probe,
+};
+
 /* Some prototypes */
-static int  nsc_ircc_open(int i, chipio_t *info);
+static int  nsc_ircc_open(chipio_t *info);
 static int  nsc_ircc_close(struct nsc_ircc_cb *self);
 static int  nsc_ircc_setup(chipio_t *info);
 static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self);
@@ -146,7 +177,10 @@
 static int  nsc_ircc_net_close(struct net_device *dev);
 static int  nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev);
-static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
+
+/* Globals */
+static int pnp_registered;
+static int pnp_succeeded;
 
 /*
  * Function nsc_ircc_init ()
@@ -158,28 +192,36 @@
 {
 	chipio_t info;
 	nsc_chip_t *chip;
-	int ret = -ENODEV;
+	int ret;
 	int cfg_base;
 	int cfg, id;
 	int reg;
 	int i = 0;
 
+	ret = platform_driver_register(&nsc_ircc_driver); 
+        if (ret) {
+                IRDA_ERROR("%s, Can't register driver!\n", driver_name);       
+                return ret;                                                                       
+        }	
+
+ 	/* Register with PnP subsystem to detect disable ports */
+	ret = pnp_register_driver(&nsc_ircc_pnp_driver);
+
+ 	if (ret >= 0)
+ 		pnp_registered = 1;
+
+	ret = -ENODEV;
+
 	/* Probe for all the NSC chipsets we know about */
-	for (chip=chips; chip->name ; chip++) {
+	for (chip = chips; chip->name ; chip++) {
 		IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __FUNCTION__,
 			   chip->name);
 		
 		/* Try all config registers for this chip */
-		for (cfg=0; cfg<3; cfg++) {
+		for (cfg = 0; cfg < ARRAY_SIZE(chip->cfg); cfg++) {
 			cfg_base = chip->cfg[cfg];
 			if (!cfg_base)
 				continue;
-			
-			memset(&info, 0, sizeof(chipio_t));
-			info.cfg_base = cfg_base;
-			info.fir_base = io[i];
-			info.dma = dma[i];
-			info.irq = irq[i];
 
 			/* Read index register */
 			reg = inb(cfg_base);
@@ -194,26 +236,67 @@
 			if ((id & chip->cid_mask) == chip->cid_value) {
 				IRDA_DEBUG(2, "%s() Found %s chip, revision=%d\n",
 					   __FUNCTION__, chip->name, id & ~chip->cid_mask);
-				/* 
-				 * If the user supplies the base address, then
-				 * we init the chip, if not we probe the values
-				 * set by the BIOS
-				 */				
-				if (io[i] < 0x2000) {
-					chip->init(chip, &info);
-				} else
-					chip->probe(chip, &info);
-
-				if (nsc_ircc_open(i, &info) == 0)
-					ret = 0;
+				
+				/*
+				 * If we found a correct PnP setting, 
+				 * we first try it.
+				 */
+				if (pnp_succeeded) {
+					memset(&info, 0, sizeof(chipio_t));
+					info.cfg_base = cfg_base;
+					info.fir_base = pnp_info.fir_base;
+					info.dma = pnp_info.dma;
+					info.irq = pnp_info.irq;
+					
+					if (info.fir_base < 0x2000) {
+						IRDA_MESSAGE("%s, chip->init\n", driver_name);
+						chip->init(chip, &info);
+					} else
+						chip->probe(chip, &info);
+					
+					if (nsc_ircc_open(&info) >= 0)
+						ret = 0;
+				}
+				
+				/*
+				 * Opening based on PnP values failed.
+				 * Let's fallback to user values, or probe
+				 * the chip.
+				 */
+				if (ret) {
+					IRDA_DEBUG(2, "%s, PnP init failed\n", driver_name);
+					memset(&info, 0, sizeof(chipio_t));
+					info.cfg_base = cfg_base;
+					info.fir_base = io[i];
+					info.dma = dma[i];
+					info.irq = irq[i];
+		
+					/* 
+					 * If the user supplies the base address, then
+					 * we init the chip, if not we probe the values
+					 * set by the BIOS
+					 */				
+					if (io[i] < 0x2000) {
+						chip->init(chip, &info);
+					} else
+						chip->probe(chip, &info);
+					
+					if (nsc_ircc_open(&info) >= 0)
+						ret = 0;
+				}				
 				i++;
 			} else {
 				IRDA_DEBUG(2, "%s(), Wrong chip id=0x%02x\n", __FUNCTION__, id);
 			}
 		} 
-		
 	}
 
+	if (ret) {
+		platform_driver_unregister(&nsc_ircc_driver);
+		pnp_unregister_driver(&nsc_ircc_pnp_driver);
+		pnp_registered = 0;
+	}
+		
 	return ret;
 }
 
@@ -227,12 +310,17 @@
 {
 	int i;
 
-	pm_unregister_all(nsc_ircc_pmproc);
-
-	for (i=0; i < 4; i++) {
+	for (i = 0; i < ARRAY_SIZE(dev_self); i++) {
 		if (dev_self[i])
 			nsc_ircc_close(dev_self[i]);
 	}
+
+	platform_driver_unregister(&nsc_ircc_driver);
+
+	if (pnp_registered)
+ 		pnp_unregister_driver(&nsc_ircc_pnp_driver);
+	
+	pnp_registered = 0;
 }
 
 /*
@@ -241,16 +329,26 @@
  *    Open driver instance
  *
  */
-static int __init nsc_ircc_open(int i, chipio_t *info)
+static int __init nsc_ircc_open(chipio_t *info)
 {
 	struct net_device *dev;
 	struct nsc_ircc_cb *self;
-        struct pm_dev *pmdev;
 	void *ret;
-	int err;
+	int err, chip_index;
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
+
+ 	for (chip_index = 0; chip_index < ARRAY_SIZE(dev_self); chip_index++) {
+		if (!dev_self[chip_index])
+			break;
+	}
+	
+	if (chip_index == ARRAY_SIZE(dev_self)) {
+		IRDA_ERROR("%s(), maximum number of supported chips reached!\n", __FUNCTION__);
+		return -ENOMEM;
+	}
+
 	IRDA_MESSAGE("%s, Found chip at base=0x%03x\n", driver_name,
 		     info->cfg_base);
 
@@ -271,8 +369,8 @@
 	spin_lock_init(&self->lock);
    
 	/* Need to store self somewhere */
-	dev_self[i] = self;
-	self->index = i;
+	dev_self[chip_index] = self;
+	self->index = chip_index;
 
 	/* Initialize IO */
 	self->io.cfg_base  = info->cfg_base;
@@ -351,7 +449,7 @@
 
 	/* Check if user has supplied a valid dongle id or not */
 	if ((dongle_id <= 0) ||
-	    (dongle_id >= (sizeof(dongle_types) / sizeof(dongle_types[0]))) ) {
+	    (dongle_id >= ARRAY_SIZE(dongle_types))) {
 		dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base);
 		
 		IRDA_MESSAGE("%s, Found dongle: %s\n", driver_name,
@@ -364,11 +462,18 @@
 	self->io.dongle_id = dongle_id;
 	nsc_ircc_init_dongle_interface(self->io.fir_base, dongle_id);
 
-        pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, nsc_ircc_pmproc);
-        if (pmdev)
-                pmdev->data = self;
+ 	self->pldev = platform_device_register_simple(NSC_IRCC_DRIVER_NAME,
+ 						      self->index, NULL, 0);
+ 	if (IS_ERR(self->pldev)) {
+ 		err = PTR_ERR(self->pldev);
+ 		goto out5;
+ 	}
+ 	platform_set_drvdata(self->pldev, self);
 
-	return 0;
+	return chip_index;
+
+ out5: 
+ 	unregister_netdev(dev);
  out4:
 	dma_free_coherent(NULL, self->tx_buff.truesize,
 			  self->tx_buff.head, self->tx_buff_dma);
@@ -379,7 +484,7 @@
 	release_region(self->io.fir_base, self->io.fir_ext);
  out1:
 	free_netdev(dev);
-	dev_self[i] = NULL;
+	dev_self[chip_index] = NULL;
 	return err;
 }
 
@@ -399,6 +504,8 @@
 
         iobase = self->io.fir_base;
 
+	platform_device_unregister(self->pldev);
+
 	/* Remove netdevice */
 	unregister_netdev(self->netdev);
 
@@ -806,6 +913,43 @@
 	return 0;
 }
 
+/* PNP probing */
+static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id)
+{
+	memset(&pnp_info, 0, sizeof(chipio_t));
+	pnp_info.irq = -1;
+	pnp_info.dma = -1;
+	pnp_succeeded = 1;
+
+	/* There don't seem to be any way to get the cfg_base.
+	 * On my box, cfg_base is in the PnP descriptor of the
+	 * motherboard. Oh well... Jean II */
+
+	if (pnp_port_valid(dev, 0) &&
+		!(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED))
+		pnp_info.fir_base = pnp_port_start(dev, 0);
+
+	if (pnp_irq_valid(dev, 0) &&
+		!(pnp_irq_flags(dev, 0) & IORESOURCE_DISABLED))
+		pnp_info.irq = pnp_irq(dev, 0);
+
+	if (pnp_dma_valid(dev, 0) &&
+		!(pnp_dma_flags(dev, 0) & IORESOURCE_DISABLED))
+		pnp_info.dma = pnp_dma(dev, 0);
+
+	IRDA_DEBUG(0, "%s() : From PnP, found firbase 0x%03X ; irq %d ; dma %d.\n",
+		   __FUNCTION__, pnp_info.fir_base, pnp_info.irq, pnp_info.dma);
+	
+	if((pnp_info.fir_base == 0) ||
+	   (pnp_info.irq == -1) || (pnp_info.dma == -1)) {
+		/* Returning an error will disable the device. Yuck ! */
+		//return -EINVAL;
+		pnp_succeeded = 0;
+	}
+
+	return 0;
+}
+
 /*
  * Function nsc_ircc_setup (info)
  *
@@ -2161,45 +2305,83 @@
 	return &self->stats;
 }
 
-static void nsc_ircc_suspend(struct nsc_ircc_cb *self)
+static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state)
 {
-	IRDA_MESSAGE("%s, Suspending\n", driver_name);
-
+     	struct nsc_ircc_cb *self = platform_get_drvdata(dev);
+ 	int bank;
+	unsigned long flags;
+ 	int iobase = self->io.fir_base;
+	
 	if (self->io.suspended)
-		return;
-
-	nsc_ircc_net_close(self->netdev);
+		return 0;
 
+	IRDA_DEBUG(1, "%s, Suspending\n", driver_name);
+		
+	rtnl_lock();
+	if (netif_running(self->netdev)) {
+		netif_device_detach(self->netdev);
+		spin_lock_irqsave(&self->lock, flags);
+		/* Save current bank */
+		bank = inb(iobase+BSR);
+		
+		/* Disable interrupts */
+		switch_bank(iobase, BANK0);
+		outb(0, iobase+IER);
+		
+		/* Restore bank register */
+		outb(bank, iobase+BSR);
+		
+		spin_unlock_irqrestore(&self->lock, flags);
+		free_irq(self->io.irq, self->netdev);
+		disable_dma(self->io.dma);
+	}
 	self->io.suspended = 1;
+	rtnl_unlock();
+ 	
+	return 0;
 }
-
-static void nsc_ircc_wakeup(struct nsc_ircc_cb *self)
+ 
+static int nsc_ircc_resume(struct platform_device *dev)
 {
+ 	struct nsc_ircc_cb *self = platform_get_drvdata(dev);
+ 	unsigned long flags;
+ 
 	if (!self->io.suspended)
-		return;
+		return 0;
 
+	IRDA_DEBUG(1, "%s, Waking up\n", driver_name);
+
+	rtnl_lock();
 	nsc_ircc_setup(&self->io);
-	nsc_ircc_net_open(self->netdev);
-	
-	IRDA_MESSAGE("%s, Waking up\n", driver_name);
+	nsc_ircc_init_dongle_interface(self->io.fir_base, self->io.dongle_id);
 
+	if (netif_running(self->netdev)) {
+		if (request_irq(self->io.irq, nsc_ircc_interrupt, 0,                     				
+				self->netdev->name, self->netdev)) {
+ 		    	IRDA_WARNING("%s, unable to allocate irq=%d\n",
+				     driver_name, self->io.irq);
+			
+			/*
+			 * Don't fail resume process, just kill this
+			 * network interface
+			 */
+			unregister_netdevice(self->netdev);
+		} else {
+			spin_lock_irqsave(&self->lock, flags);
+			nsc_ircc_change_speed(self, self->io.speed);
+			spin_unlock_irqrestore(&self->lock, flags);
+			netif_device_attach(self->netdev);
+		}
+		
+	} else {
+		spin_lock_irqsave(&self->lock, flags);
+		nsc_ircc_change_speed(self, 9600);
+		spin_unlock_irqrestore(&self->lock, flags);
+	}
 	self->io.suspended = 0;
-}
+	rtnl_unlock();
 
-static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data)
-{
-        struct nsc_ircc_cb *self = (struct nsc_ircc_cb*) dev->data;
-        if (self) {
-                switch (rqst) {
-                case PM_SUSPEND:
-                        nsc_ircc_suspend(self);
-                        break;
-                case PM_RESUME:
-                        nsc_ircc_wakeup(self);
-                        break;
-                }
-        }
-	return 0;
+ 	return 0;
 }
 
 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
diff -urN oldtree/drivers/net/irda/nsc-ircc.h newtree/drivers/net/irda/nsc-ircc.h
--- oldtree/drivers/net/irda/nsc-ircc.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/irda/nsc-ircc.h	2006-02-21 15:58:16.144692192 +0000
@@ -269,7 +269,7 @@
 	__u32 new_speed;
 	int index;                 /* Instance index */
 
-        struct pm_dev *dev;
+	struct platform_device *pldev;
 };
 
 static inline void switch_bank(int iobase, int bank)
diff -urN oldtree/drivers/net/irda/sir_dongle.c newtree/drivers/net/irda/sir_dongle.c
--- oldtree/drivers/net/irda/sir_dongle.c	2006-02-19 11:41:03.279844488 +0000
+++ newtree/drivers/net/irda/sir_dongle.c	2006-02-21 15:58:16.553630024 +0000
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 #include <linux/kmod.h>
+#include <linux/mutex.h>
 
 #include <net/irda/irda.h>
 
@@ -28,7 +29,7 @@
  */
 
 static LIST_HEAD(dongle_list);			/* list of registered dongle drivers */
-static DECLARE_MUTEX(dongle_list_lock);		/* protects the list */
+static DEFINE_MUTEX(dongle_list_lock);		/* protects the list */
 
 int irda_register_dongle(struct dongle_driver *new)
 {
@@ -38,25 +39,25 @@
 	IRDA_DEBUG(0, "%s : registering dongle \"%s\" (%d).\n",
 		   __FUNCTION__, new->driver_name, new->type);
 
-	down(&dongle_list_lock);
+	mutex_lock(&dongle_list_lock);
 	list_for_each(entry, &dongle_list) {
 		drv = list_entry(entry, struct dongle_driver, dongle_list);
 		if (new->type == drv->type) {
-			up(&dongle_list_lock);
+			mutex_unlock(&dongle_list_lock);
 			return -EEXIST;
 		}
 	}
 	list_add(&new->dongle_list, &dongle_list);
-	up(&dongle_list_lock);
+	mutex_unlock(&dongle_list_lock);
 	return 0;
 }
 EXPORT_SYMBOL(irda_register_dongle);
 
 int irda_unregister_dongle(struct dongle_driver *drv)
 {
-	down(&dongle_list_lock);
+	mutex_lock(&dongle_list_lock);
 	list_del(&drv->dongle_list);
-	up(&dongle_list_lock);
+	mutex_unlock(&dongle_list_lock);
 	return 0;
 }
 EXPORT_SYMBOL(irda_unregister_dongle);
@@ -75,7 +76,7 @@
 		return -EBUSY;
 	
 	/* serialize access to the list of registered dongles */
-	down(&dongle_list_lock);
+	mutex_lock(&dongle_list_lock);
 
 	list_for_each(entry, &dongle_list) {
 		drv = list_entry(entry, struct dongle_driver, dongle_list);
@@ -109,14 +110,14 @@
 	if (!drv->open  ||  (err=drv->open(dev))!=0)
 		goto out_reject;		/* failed to open driver */
 
-	up(&dongle_list_lock);
+	mutex_unlock(&dongle_list_lock);
 	return 0;
 
 out_reject:
 	dev->dongle_drv = NULL;
 	module_put(drv->owner);
 out_unlock:
-	up(&dongle_list_lock);
+	mutex_unlock(&dongle_list_lock);
 	return err;
 }
 
diff -urN oldtree/drivers/net/irda/vlsi_ir.c newtree/drivers/net/irda/vlsi_ir.c
--- oldtree/drivers/net/irda/vlsi_ir.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/irda/vlsi_ir.c	2006-02-21 15:58:16.146691888 +0000
@@ -1887,7 +1887,7 @@
 		vlsi_proc_root->owner = THIS_MODULE;
 	}
 
-	ret = pci_module_init(&vlsi_irda_driver);
+	ret = pci_register_driver(&vlsi_irda_driver);
 
 	if (ret && vlsi_proc_root)
 		remove_proc_entry(PROC_DIR, NULL);
diff -urN oldtree/drivers/net/lib8390.c newtree/drivers/net/lib8390.c
--- oldtree/drivers/net/lib8390.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/net/lib8390.c	2006-02-21 15:58:37.465450944 +0000
@@ -0,0 +1,1109 @@
+/* 8390.c: A general NS8390 ethernet driver core for linux. */
+/*
+	Written 1992-94 by Donald Becker.
+
+	Copyright 1993 United States Government as represented by the
+	Director, National Security Agency.
+
+	This software may be used and distributed according to the terms
+	of the GNU General Public License, incorporated herein by reference.
+
+	The author may be reached as becker@scyld.com, or C/O
+	Scyld Computing Corporation
+	410 Severn Ave., Suite 210
+	Annapolis MD 21403
+
+
+  This is the chip-specific code for many 8390-based ethernet adaptors.
+  This is not a complete driver, it must be combined with board-specific
+  code such as ne.c, wd.c, 3c503.c, etc.
+
+  Seeing how at least eight drivers use this code, (not counting the
+  PCMCIA ones either) it is easy to break some card by what seems like
+  a simple innocent change. Please contact me or Donald if you think
+  you have found something that needs changing. -- PG
+
+
+  Changelog:
+
+  Paul Gortmaker	: remove set_bit lock, other cleanups.
+  Paul Gortmaker	: add ei_get_8390_hdr() so we can pass skb's to
+			  ei_block_input() for eth_io_copy_and_sum().
+  Paul Gortmaker	: exchange static int ei_pingpong for a #define,
+			  also add better Tx error handling.
+  Paul Gortmaker	: rewrite Rx overrun handling as per NS specs.
+  Alexey Kuznetsov	: use the 8390's six bit hash multicast filter.
+  Paul Gortmaker	: tweak ANK's above multicast changes a bit.
+  Paul Gortmaker	: update packet statistics for v2.1.x
+  Alan Cox		: support arbitary stupid port mappings on the
+  			  68K Macintosh. Support >16bit I/O spaces
+  Paul Gortmaker	: add kmod support for auto-loading of the 8390
+			  module by all drivers that require it.
+  Alan Cox		: Spinlocking work, added 'BUG_83C690'
+  Paul Gortmaker	: Separate out Tx timeout code from Tx path.
+  Paul Gortmaker	: Remove old unused single Tx buffer code.
+  Hayato Fujiwara	: Add m32r support.
+  Paul Gortmaker	: use skb_padto() instead of stack scratch area
+
+  Sources:
+  The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
+
+  */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/bitops.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/in.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#define NS8390_CORE
+#include "8390.h"
+
+#define ei_inb(_p)	 readb((void __iomem *)_p)
+#define ei_outb(_v,_p)	 writeb(_v,(void __iomem *)_p)
+#define ei_inb_p(_p)	 readb((void __iomem *)_p)
+#define ei_outb_p(_v,_p) writeb(_v,(void __iomem *)_p)
+
+#define BUG_83C690
+
+/* These are the operational function interfaces to board-specific
+   routines.
+	void reset_8390(struct net_device *dev)
+		Resets the board associated with DEV, including a hardware reset of
+		the 8390.  This is only called when there is a transmit timeout, and
+		it is always followed by 8390_init().
+	void block_output(struct net_device *dev, int count, const unsigned char *buf,
+					  int start_page)
+		Write the COUNT bytes of BUF to the packet buffer at START_PAGE.  The
+		"page" value uses the 8390's 256-byte pages.
+	void get_8390_hdr(struct net_device *dev, struct e8390_hdr *hdr, int ring_page)
+		Read the 4 byte, page aligned 8390 header. *If* there is a
+		subsequent read, it will be of the rest of the packet.
+	void block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
+		Read COUNT bytes from the packet buffer into the skb data area. Start
+		reading from RING_OFFSET, the address as the 8390 sees it.  This will always
+		follow the read of the 8390 header.
+*/
+#define ei_reset_8390 (ei_local->reset_8390)
+#define ei_block_output (ei_local->block_output)
+#define ei_block_input (ei_local->block_input)
+#define ei_get_8390_hdr (ei_local->get_8390_hdr)
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef ei_debug
+int ei_debug = 1;
+#endif
+
+/* Index to functions. */
+static void ei_tx_intr(struct net_device *dev);
+static void ei_tx_err(struct net_device *dev);
+static void ei_tx_timeout(struct net_device *dev);
+static void ei_receive(struct net_device *dev);
+static void ei_rx_overrun(struct net_device *dev);
+
+/* Routines generic to NS8390-based boards. */
+static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
+								int start_page);
+static void set_multicast_list(struct net_device *dev);
+static void do_set_multicast_list(struct net_device *dev);
+static void __NS8390_init(struct net_device *dev, int startp);
+
+/*
+ *	SMP and the 8390 setup.
+ *
+ *	The 8390 isnt exactly designed to be multithreaded on RX/TX. There is
+ *	a page register that controls bank and packet buffer access. We guard
+ *	this with ei_local->page_lock. Nobody should assume or set the page other
+ *	than zero when the lock is not held. Lock holders must restore page 0
+ *	before unlocking. Even pure readers must take the lock to protect in
+ *	page 0.
+ *
+ *	To make life difficult the chip can also be very slow. We therefore can't
+ *	just use spinlocks. For the longer lockups we disable the irq the device
+ *	sits on and hold the lock. We must hold the lock because there is a dual
+ *	processor case other than interrupts (get stats/set multicast list in
+ *	parallel with each other and transmit).
+ *
+ *	Note: in theory we can just disable the irq on the card _but_ there is
+ *	a latency on SMP irq delivery. So we can easily go "disable irq" "sync irqs"
+ *	enter lock, take the queued irq. So we waddle instead of flying.
+ *
+ *	Finally by special arrangement for the purpose of being generally
+ *	annoying the transmit function is called bh atomic. That places
+ *	restrictions on the user context callers as disable_irq won't save
+ *	them.
+ */
+
+
+/**
+ * ei_open - Open/initialize the board.
+ * @dev: network device to initialize
+ *
+ * This routine goes all-out, setting everything
+ * up anew at each open, even though many of these registers should only
+ * need to be set once at boot.
+ */
+static int __ei_open(struct net_device *dev)
+{
+	unsigned long flags;
+	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+
+	/* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout
+	    wrapper that does e.g. media check & then calls ei_tx_timeout. */
+	if (dev->tx_timeout == NULL)
+		 dev->tx_timeout = ei_tx_timeout;
+	if (dev->watchdog_timeo <= 0)
+		 dev->watchdog_timeo = TX_TIMEOUT;
+
+	/*
+	 *	Grab the page lock so we own the register set, then call
+	 *	the init function.
+	 */
+
+      	spin_lock_irqsave(&ei_local->page_lock, flags);
+	__NS8390_init(dev, 1);
+	/* Set the flag before we drop the lock, That way the IRQ arrives
+	   after its set and we get no silly warnings */
+	netif_start_queue(dev);
+      	spin_unlock_irqrestore(&ei_local->page_lock, flags);
+	ei_local->irqlock = 0;
+	return 0;
+}
+
+/**
+ * ei_close - shut down network device
+ * @dev: network device to close
+ *
+ * Opposite of ei_open(). Only used when "ifconfig <devname> down" is done.
+ */
+static int __ei_close(struct net_device *dev)
+{
+	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+	unsigned long flags;
+
+	/*
+	 *	Hold the page lock during close
+	 */
+
+      	spin_lock_irqsave(&ei_local->page_lock, flags);
+	__NS8390_init(dev, 0);
+      	spin_unlock_irqrestore(&ei_local->page_lock, flags);
+	netif_stop_queue(dev);
+	return 0;
+}
+
+/**
+ * ei_tx_timeout - handle transmit time out condition
+ * @dev: network device which has apparently fallen asleep
+ *
+ * Called by kernel when device never acknowledges a transmit has
+ * completed (or failed) - i.e. never posted a Tx related interrupt.
+ */
+
+static void ei_tx_timeout(struct net_device *dev)
+{
+	unsigned long e8390_base = dev->base_addr;
+	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+	int txsr, isr, tickssofar = jiffies - dev->trans_start;
+	unsigned long flags;
+
+#if defined(CONFIG_M32R) && defined(CONFIG_SMP)
+	unsigned long icucr;
+
+	local_irq_save(flags);
+	icucr = inl(M32R_ICU_CR1_PORTL);
+	icucr |= M32R_ICUCR_ISMOD11;
+	outl(icucr, M32R_ICU_CR1_PORTL);
+	local_irq_restore(flags);
+#endif
+	ei_local->stat.tx_errors++;
+
+	spin_lock_irqsave(&ei_local->page_lock, flags);
+	txsr = ei_inb(e8390_base+EN0_TSR);
+	isr = ei_inb(e8390_base+EN0_ISR);
+	spin_unlock_irqrestore(&ei_local->page_lock, flags);
+
+	printk(KERN_DEBUG "%s: Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n",
+		dev->name, (txsr & ENTSR_ABT) ? "excess collisions." :
+		(isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar);
+
+	if (!isr && !ei_local->stat.tx_packets)
+	{
+		/* The 8390 probably hasn't gotten on the cable yet. */
+		ei_local->interface_num ^= 1;   /* Try a different xcvr.  */
+	}
+
+	/* Ugly but a reset can be slow, yet must be protected */
+
+	disable_irq_nosync(dev->irq);
+	spin_lock(&ei_local->page_lock);
+
+	/* Try to restart the card.  Perhaps the user has fixed something. */
+	ei_reset_8390(dev);
+	__NS8390_init(dev, 1);
+
+	spin_unlock(&ei_local->page_lock);
+	enable_irq(dev->irq);
+	netif_wake_queue(dev);
+}
+
+/**
+ * ei_start_xmit - begin packet transmission
+ * @skb: packet to be sent
+ * @dev: network device to which packet is sent
+ *
+ * Sends a packet to an 8390 network device.
+ */
+
+static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	unsigned long e8390_base = dev->base_addr;
+	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+	int send_length = skb->len, output_page;
+	unsigned long flags;
+
+	if (skb->len < ETH_ZLEN) {
+		skb = skb_padto(skb, ETH_ZLEN);
+		if (skb == NULL)
+			return 0;
+		send_length = ETH_ZLEN;
+	}
+
+	/* Mask interrupts from the ethercard.
+	   SMP: We have to grab the lock here otherwise the IRQ handler
+	   on another CPU can flip window and race the IRQ mask set. We end
+	   up trashing the mcast filter not disabling irqs if we don't lock */
+
+	spin_lock_irqsave(&ei_local->page_lock, flags);
+	ei_outb_p(0x00, e8390_base + EN0_IMR);
+	spin_unlock_irqrestore(&ei_local->page_lock, flags);
+
+
+	/*
+	 *	Slow phase with lock held.
+	 */
+
+	disable_irq_nosync(dev->irq);
+
+	spin_lock(&ei_local->page_lock);
+
+	ei_local->irqlock = 1;
+
+	/*
+	 * We have two Tx slots available for use. Find the first free
+	 * slot, and then perform some sanity checks. With two Tx bufs,
+	 * you get very close to transmitting back-to-back packets. With
+	 * only one Tx buf, the transmitter sits idle while you reload the
+	 * card, leaving a substantial gap between each transmitted packet.
+	 */
+
+	if (ei_local->tx1 == 0)
+	{
+		output_page = ei_local->tx_start_page;
+		ei_local->tx1 = send_length;
+		if (ei_debug  &&  ei_local->tx2 > 0)
+			printk(KERN_DEBUG "%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
+				dev->name, ei_local->tx2, ei_local->lasttx, ei_local->txing);
+	}
+	else if (ei_local->tx2 == 0)
+	{
+		output_page = ei_local->tx_start_page + TX_PAGES/2;
+		ei_local->tx2 = send_length;
+		if (ei_debug  &&  ei_local->tx1 > 0)
+			printk(KERN_DEBUG "%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
+				dev->name, ei_local->tx1, ei_local->lasttx, ei_local->txing);
+	}
+	else
+	{	/* We should never get here. */
+		if (ei_debug)
+			printk(KERN_DEBUG "%s: No Tx buffers free! tx1=%d tx2=%d last=%d\n",
+				dev->name, ei_local->tx1, ei_local->tx2, ei_local->lasttx);
+		ei_local->irqlock = 0;
+		netif_stop_queue(dev);
+		ei_outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+		spin_unlock(&ei_local->page_lock);
+		enable_irq(dev->irq);
+		ei_local->stat.tx_errors++;
+		return 1;
+	}
+
+	/*
+	 * Okay, now upload the packet and trigger a send if the transmitter
+	 * isn't already sending. If it is busy, the interrupt handler will
+	 * trigger the send later, upon receiving a Tx done interrupt.
+	 */
+
+	ei_block_output(dev, send_length, skb->data, output_page);
+
+	if (! ei_local->txing)
+	{
+		ei_local->txing = 1;
+		NS8390_trigger_send(dev, send_length, output_page);
+		dev->trans_start = jiffies;
+		if (output_page == ei_local->tx_start_page)
+		{
+			ei_local->tx1 = -1;
+			ei_local->lasttx = -1;
+		}
+		else
+		{
+			ei_local->tx2 = -1;
+			ei_local->lasttx = -2;
+		}
+	}
+	else ei_local->txqueue++;
+
+	if (ei_local->tx1  &&  ei_local->tx2)
+		netif_stop_queue(dev);
+	else
+		netif_start_queue(dev);
+
+	/* Turn 8390 interrupts back on. */
+	ei_local->irqlock = 0;
+	ei_outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+
+	spin_unlock(&ei_local->page_lock);
+	enable_irq(dev->irq);
+
+	dev_kfree_skb (skb);
+	ei_local->stat.tx_bytes += send_length;
+
+	return 0;
+}
+
+/**
+ * ei_interrupt - handle the interrupts from an 8390
+ * @irq: interrupt number
+ * @dev_id: a pointer to the net_device
+ * @regs: unused
+ *
+ * Handle the ether interface interrupts. We pull packets from
+ * the 8390 via the card specific functions and fire them at the networking
+ * stack. We also handle transmit completions and wake the transmit path if
+ * necessary. We also update the counters and do other housekeeping as
+ * needed.
+ */
+
+static irqreturn_t __ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct net_device *dev = dev_id;
+	unsigned long e8390_base;
+	int interrupts, nr_serviced = 0;
+	struct ei_device *ei_local;
+
+	if (dev == NULL)
+	{
+		printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+		return IRQ_NONE;
+	}
+
+	e8390_base = dev->base_addr;
+	ei_local = (struct ei_device *) netdev_priv(dev);
+
+	/*
+	 *	Protect the irq test too.
+	 */
+
+	spin_lock(&ei_local->page_lock);
+
+	if (ei_local->irqlock)
+	{
+#if 1 /* This might just be an interrupt for a PCI device sharing this line */
+		/* The "irqlock" check is only for testing. */
+		printk(ei_local->irqlock
+			   ? "%s: Interrupted while interrupts are masked! isr=%#2x imr=%#2x.\n"
+			   : "%s: Reentering the interrupt handler! isr=%#2x imr=%#2x.\n",
+			   dev->name, ei_inb_p(e8390_base + EN0_ISR),
+			   ei_inb_p(e8390_base + EN0_IMR));
+#endif
+		spin_unlock(&ei_local->page_lock);
+		return IRQ_NONE;
+	}
+
+	/* Change to page 0 and read the intr status reg. */
+	ei_outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
+	if (ei_debug > 3)
+		printk(KERN_DEBUG "%s: interrupt(isr=%#2.2x).\n", dev->name,
+			   ei_inb_p(e8390_base + EN0_ISR));
+
+	/* !!Assumption!! -- we stay in page 0.	 Don't break this. */
+	while ((interrupts = ei_inb_p(e8390_base + EN0_ISR)) != 0
+		   && ++nr_serviced < MAX_SERVICE)
+	{
+		if (!netif_running(dev)) {
+			printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name);
+			/* rmk - acknowledge the interrupts */
+			ei_outb_p(interrupts, e8390_base + EN0_ISR);
+			interrupts = 0;
+			break;
+		}
+		if (interrupts & ENISR_OVER)
+			ei_rx_overrun(dev);
+		else if (interrupts & (ENISR_RX+ENISR_RX_ERR))
+		{
+			/* Got a good (?) packet. */
+			ei_receive(dev);
+		}
+		/* Push the next to-transmit packet through. */
+		if (interrupts & ENISR_TX)
+			ei_tx_intr(dev);
+		else if (interrupts & ENISR_TX_ERR)
+			ei_tx_err(dev);
+
+		if (interrupts & ENISR_COUNTERS)
+		{
+			ei_local->stat.rx_frame_errors += ei_inb_p(e8390_base + EN0_COUNTER0);
+			ei_local->stat.rx_crc_errors   += ei_inb_p(e8390_base + EN0_COUNTER1);
+			ei_local->stat.rx_missed_errors+= ei_inb_p(e8390_base + EN0_COUNTER2);
+			ei_outb_p(ENISR_COUNTERS, e8390_base + EN0_ISR); /* Ack intr. */
+		}
+
+		/* Ignore any RDC interrupts that make it back to here. */
+		if (interrupts & ENISR_RDC)
+		{
+			ei_outb_p(ENISR_RDC, e8390_base + EN0_ISR);
+		}
+
+		ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
+	}
+
+	if (interrupts && ei_debug)
+	{
+		ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
+		if (nr_serviced >= MAX_SERVICE)
+		{
+			/* 0xFF is valid for a card removal */
+			if(interrupts!=0xFF)
+				printk(KERN_WARNING "%s: Too much work at interrupt, status %#2.2x\n",
+				   dev->name, interrupts);
+			ei_outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */
+		} else {
+			printk(KERN_WARNING "%s: unknown interrupt %#2x\n", dev->name, interrupts);
+			ei_outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
+		}
+	}
+	spin_unlock(&ei_local->page_lock);
+	return IRQ_RETVAL(nr_serviced > 0);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void __ei_poll(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	__ei_interrupt(dev->irq, dev, NULL);
+	enable_irq(dev->irq);
+}
+#endif
+
+/**
+ * ei_tx_err - handle transmitter error
+ * @dev: network device which threw the exception
+ *
+ * A transmitter error has happened. Most likely excess collisions (which
+ * is a fairly normal condition). If the error is one where the Tx will
+ * have been aborted, we try and send another one right away, instead of
+ * letting the failed packet sit and collect dust in the Tx buffer. This
+ * is a much better solution as it avoids kernel based Tx timeouts, and
+ * an unnecessary card reset.
+ *
+ * Called with lock held.
+ */
+
+static void ei_tx_err(struct net_device *dev)
+{
+	unsigned long e8390_base = dev->base_addr;
+	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+	unsigned char txsr = ei_inb_p(e8390_base+EN0_TSR);
+	unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
+
+#ifdef VERBOSE_ERROR_DUMP
+	printk(KERN_DEBUG "%s: transmitter error (%#2x): ", dev->name, txsr);
+	if (txsr & ENTSR_ABT)
+		printk("excess-collisions ");
+	if (txsr & ENTSR_ND)
+		printk("non-deferral ");
+	if (txsr & ENTSR_CRS)
+		printk("lost-carrier ");
+	if (txsr & ENTSR_FU)
+		printk("FIFO-underrun ");
+	if (txsr & ENTSR_CDH)
+		printk("lost-heartbeat ");
+	printk("\n");
+#endif
+
+	ei_outb_p(ENISR_TX_ERR, e8390_base + EN0_ISR); /* Ack intr. */
+
+	if (tx_was_aborted)
+		ei_tx_intr(dev);
+	else
+	{
+		ei_local->stat.tx_errors++;
+		if (txsr & ENTSR_CRS) ei_local->stat.tx_carrier_errors++;
+		if (txsr & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++;
+		if (txsr & ENTSR_OWC) ei_local->stat.tx_window_errors++;
+	}
+}
+
+/**
+ * ei_tx_intr - transmit interrupt handler
+ * @dev: network device for which tx intr is handled
+ *
+ * We have finished a transmit: check for errors and then trigger the next
+ * packet to be sent. Called with lock held.
+ */
+
+static void ei_tx_intr(struct net_device *dev)
+{
+	unsigned long e8390_base = dev->base_addr;
+	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+	int status = ei_inb(e8390_base + EN0_TSR);
+
+	ei_outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */
+
+	/*
+	 * There are two Tx buffers, see which one finished, and trigger
+	 * the send of another one if it exists.
+	 */
+	ei_local->txqueue--;
+
+	if (ei_local->tx1 < 0)
+	{
+		if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
+			printk(KERN_ERR "%s: bogus last_tx_buffer %d, tx1=%d.\n",
+				ei_local->name, ei_local->lasttx, ei_local->tx1);
+		ei_local->tx1 = 0;
+		if (ei_local->tx2 > 0)
+		{
+			ei_local->txing = 1;
+			NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
+			dev->trans_start = jiffies;
+			ei_local->tx2 = -1,
+			ei_local->lasttx = 2;
+		}
+		else ei_local->lasttx = 20, ei_local->txing = 0;
+	}
+	else if (ei_local->tx2 < 0)
+	{
+		if (ei_local->lasttx != 2  &&  ei_local->lasttx != -2)
+			printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
+				ei_local->name, ei_local->lasttx, ei_local->tx2);
+		ei_local->tx2 = 0;
+		if (ei_local->tx1 > 0)
+		{
+			ei_local->txing = 1;
+			NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
+			dev->trans_start = jiffies;
+			ei_local->tx1 = -1;
+			ei_local->lasttx = 1;
+		}
+		else
+			ei_local->lasttx = 10, ei_local->txing = 0;
+	}
+//	else printk(KERN_WARNING "%s: unexpected TX-done interrupt, lasttx=%d.\n",
+//			dev->name, ei_local->lasttx);
+
+	/* Minimize Tx latency: update the statistics after we restart TXing. */
+	if (status & ENTSR_COL)
+		ei_local->stat.collisions++;
+	if (status & ENTSR_PTX)
+		ei_local->stat.tx_packets++;
+	else
+	{
+		ei_local->stat.tx_errors++;
+		if (status & ENTSR_ABT)
+		{
+			ei_local->stat.tx_aborted_errors++;
+			ei_local->stat.collisions += 16;
+		}
+		if (status & ENTSR_CRS)
+			ei_local->stat.tx_carrier_errors++;
+		if (status & ENTSR_FU)
+			ei_local->stat.tx_fifo_errors++;
+		if (status & ENTSR_CDH)
+			ei_local->stat.tx_heartbeat_errors++;
+		if (status & ENTSR_OWC)
+			ei_local->stat.tx_window_errors++;
+	}
+	netif_wake_queue(dev);
+}
+
+/**
+ * ei_receive - receive some packets
+ * @dev: network device with which receive will be run
+ *
+ * We have a good packet(s), get it/them out of the buffers.
+ * Called with lock held.
+ */
+
+static void ei_receive(struct net_device *dev)
+{
+	unsigned long e8390_base = dev->base_addr;
+	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+	unsigned char rxing_page, this_frame, next_frame;
+	unsigned short current_offset;
+	int rx_pkt_count = 0;
+	struct e8390_pkt_hdr rx_frame;
+	int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page;
+
+	while (++rx_pkt_count < 10)
+	{
+		int pkt_len, pkt_stat;
+
+		/* Get the rx page (incoming packet pointer). */
+		ei_outb_p(E8390_NODMA+E8390_PAGE1, e8390_base + E8390_CMD);
+		rxing_page = ei_inb_p(e8390_base + EN1_CURPAG);
+		ei_outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
+
+		/* Remove one frame from the ring.  Boundary is always a page behind. */
+		this_frame = ei_inb_p(e8390_base + EN0_BOUNDARY) + 1;
+		if (this_frame >= ei_local->stop_page)
+			this_frame = ei_local->rx_start_page;
+
+		/* Someday we'll omit the previous, iff we never get this message.
+		   (There is at least one clone claimed to have a problem.)
+
+		   Keep quiet if it looks like a card removal. One problem here
+		   is that some clones crash in roughly the same way.
+		 */
+		if (ei_debug > 0  &&  this_frame != ei_local->current_page && (this_frame!=0x0 || rxing_page!=0xFF))
+			printk(KERN_ERR "%s: mismatched read page pointers %2x vs %2x.\n",
+				   dev->name, this_frame, ei_local->current_page);
+
+		if (this_frame == rxing_page)	/* Read all the frames? */
+			break;				/* Done for now */
+
+		current_offset = this_frame << 8;
+		ei_get_8390_hdr(dev, &rx_frame, this_frame);
+
+		pkt_len = rx_frame.count - sizeof(struct e8390_pkt_hdr);
+		pkt_stat = rx_frame.status;
+
+		next_frame = this_frame + 1 + ((pkt_len+4)>>8);
+
+		/* Check for bogosity warned by 3c503 book: the status byte is never
+		   written.  This happened a lot during testing! This code should be
+		   cleaned up someday. */
+		if (rx_frame.next != next_frame
+			&& rx_frame.next != next_frame + 1
+			&& rx_frame.next != next_frame - num_rx_pages
+			&& rx_frame.next != next_frame + 1 - num_rx_pages) {
+			ei_local->current_page = rxing_page;
+			ei_outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY);
+			ei_local->stat.rx_errors++;
+			continue;
+		}
+
+		if (pkt_len < 60  ||  pkt_len > 1518)
+		{
+			if (ei_debug)
+				printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n",
+					   dev->name, rx_frame.count, rx_frame.status,
+					   rx_frame.next);
+			ei_local->stat.rx_errors++;
+			ei_local->stat.rx_length_errors++;
+		}
+		 else if ((pkt_stat & 0x0F) == ENRSR_RXOK)
+		{
+			struct sk_buff *skb;
+
+			skb = dev_alloc_skb(pkt_len+2);
+			if (skb == NULL)
+			{
+				if (ei_debug > 1)
+					printk(KERN_DEBUG "%s: Couldn't allocate a sk_buff of size %d.\n",
+						   dev->name, pkt_len);
+				ei_local->stat.rx_dropped++;
+				break;
+			}
+			else
+			{
+				skb_reserve(skb,2);	/* IP headers on 16 byte boundaries */
+				skb->dev = dev;
+				skb_put(skb, pkt_len);	/* Make room */
+				ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame));
+				skb->protocol=eth_type_trans(skb,dev);
+				netif_rx(skb);
+				dev->last_rx = jiffies;
+				ei_local->stat.rx_packets++;
+				ei_local->stat.rx_bytes += pkt_len;
+				if (pkt_stat & ENRSR_PHY)
+					ei_local->stat.multicast++;
+			}
+		}
+		else
+		{
+			if (ei_debug)
+				printk(KERN_DEBUG "%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n",
+					   dev->name, rx_frame.status, rx_frame.next,
+					   rx_frame.count);
+			ei_local->stat.rx_errors++;
+			/* NB: The NIC counts CRC, frame and missed errors. */
+			if (pkt_stat & ENRSR_FO)
+				ei_local->stat.rx_fifo_errors++;
+		}
+		next_frame = rx_frame.next;
+
+		/* This _should_ never happen: it's here for avoiding bad clones. */
+		if (next_frame >= ei_local->stop_page) {
+			printk("%s: next frame inconsistency, %#2x\n", dev->name,
+				   next_frame);
+			next_frame = ei_local->rx_start_page;
+		}
+		ei_local->current_page = next_frame;
+		ei_outb_p(next_frame-1, e8390_base+EN0_BOUNDARY);
+	}
+
+	/* We used to also ack ENISR_OVER here, but that would sometimes mask
+	   a real overrun, leaving the 8390 in a stopped state with rec'vr off. */
+	ei_outb_p(ENISR_RX+ENISR_RX_ERR, e8390_base+EN0_ISR);
+	return;
+}
+
+/**
+ * ei_rx_overrun - handle receiver overrun
+ * @dev: network device which threw exception
+ *
+ * We have a receiver overrun: we have to kick the 8390 to get it started
+ * again. Problem is that you have to kick it exactly as NS prescribes in
+ * the updated datasheets, or "the NIC may act in an unpredictable manner."
+ * This includes causing "the NIC to defer indefinitely when it is stopped
+ * on a busy network."  Ugh.
+ * Called with lock held. Don't call this with the interrupts off or your
+ * computer will hate you - it takes 10ms or so.
+ */
+
+static void ei_rx_overrun(struct net_device *dev)
+{
+	unsigned long e8390_base = dev->base_addr;
+	unsigned char was_txing, must_resend = 0;
+	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+
+	/*
+	 * Record whether a Tx was in progress and then issue the
+	 * stop command.
+	 */
+	was_txing = ei_inb_p(e8390_base+E8390_CMD) & E8390_TRANS;
+	ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
+
+	if (ei_debug > 1)
+		printk(KERN_DEBUG "%s: Receiver overrun.\n", dev->name);
+	ei_local->stat.rx_over_errors++;
+
+	/*
+	 * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
+	 * Early datasheets said to poll the reset bit, but now they say that
+	 * it "is not a reliable indicator and subsequently should be ignored."
+	 * We wait at least 10ms.
+	 */
+
+	mdelay(10);
+
+	/*
+	 * Reset RBCR[01] back to zero as per magic incantation.
+	 */
+	ei_outb_p(0x00, e8390_base+EN0_RCNTLO);
+	ei_outb_p(0x00, e8390_base+EN0_RCNTHI);
+
+	/*
+	 * See if any Tx was interrupted or not. According to NS, this
+	 * step is vital, and skipping it will cause no end of havoc.
+	 */
+
+	if (was_txing)
+	{
+		unsigned char tx_completed = ei_inb_p(e8390_base+EN0_ISR) & (ENISR_TX+ENISR_TX_ERR);
+		if (!tx_completed)
+			must_resend = 1;
+	}
+
+	/*
+	 * Have to enter loopback mode and then restart the NIC before
+	 * you are allowed to slurp packets up off the ring.
+	 */
+	ei_outb_p(E8390_TXOFF, e8390_base + EN0_TXCR);
+	ei_outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
+
+	/*
+	 * Clear the Rx ring of all the debris, and ack the interrupt.
+	 */
+	ei_receive(dev);
+	ei_outb_p(ENISR_OVER, e8390_base+EN0_ISR);
+
+	/*
+	 * Leave loopback mode, and resend any packet that got stopped.
+	 */
+	ei_outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR);
+	if (must_resend)
+    		ei_outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD);
+}
+
+/*
+ *	Collect the stats. This is called unlocked and from several contexts.
+ */
+
+static struct net_device_stats *get_stats(struct net_device *dev)
+{
+	unsigned long ioaddr = dev->base_addr;
+	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+	unsigned long flags;
+
+	/* If the card is stopped, just return the present stats. */
+	if (!netif_running(dev))
+		return &ei_local->stat;
+
+	spin_lock_irqsave(&ei_local->page_lock,flags);
+	/* Read the counter registers, assuming we are in page 0. */
+	ei_local->stat.rx_frame_errors += ei_inb_p(ioaddr + EN0_COUNTER0);
+	ei_local->stat.rx_crc_errors   += ei_inb_p(ioaddr + EN0_COUNTER1);
+	ei_local->stat.rx_missed_errors+= ei_inb_p(ioaddr + EN0_COUNTER2);
+	spin_unlock_irqrestore(&ei_local->page_lock, flags);
+
+	return &ei_local->stat;
+}
+
+/*
+ * Form the 64 bit 8390 multicast table from the linked list of addresses
+ * associated with this dev structure.
+ */
+
+static inline void make_mc_bits(u8 *bits, struct net_device *dev)
+{
+	struct dev_mc_list *dmi;
+
+	for (dmi=dev->mc_list; dmi; dmi=dmi->next)
+	{
+		u32 crc;
+		if (dmi->dmi_addrlen != ETH_ALEN)
+		{
+			printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name);
+			continue;
+		}
+		crc = ether_crc(ETH_ALEN, dmi->dmi_addr);
+		/*
+		 * The 8390 uses the 6 most significant bits of the
+		 * CRC to index the multicast table.
+		 */
+		bits[crc>>29] |= (1<<((crc>>26)&7));
+	}
+}
+
+/**
+ * do_set_multicast_list - set/clear multicast filter
+ * @dev: net device for which multicast filter is adjusted
+ *
+ *	Set or clear the multicast filter for this adaptor. May be called
+ *	from a BH in 2.1.x. Must be called with lock held.
+ */
+
+static void do_set_multicast_list(struct net_device *dev)
+{
+	unsigned long e8390_base = dev->base_addr;
+	int i;
+	struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
+
+	if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI)))
+	{
+		memset(ei_local->mcfilter, 0, 8);
+		if (dev->mc_list)
+			make_mc_bits(ei_local->mcfilter, dev);
+	}
+	else
+		memset(ei_local->mcfilter, 0xFF, 8);	/* mcast set to accept-all */
+
+	/*
+	 * DP8390 manuals don't specify any magic sequence for altering
+	 * the multicast regs on an already running card. To be safe, we
+	 * ensure multicast mode is off prior to loading up the new hash
+	 * table. If this proves to be not enough, we can always resort
+	 * to stopping the NIC, loading the table and then restarting.
+	 *
+	 * Bug Alert!  The MC regs on the SMC 83C690 (SMC Elite and SMC
+	 * Elite16) appear to be write-only. The NS 8390 data sheet lists
+	 * them as r/w so this is a bug.  The SMC 83C790 (SMC Ultra and
+	 * Ultra32 EISA) appears to have this bug fixed.
+	 */
+
+	if (netif_running(dev))
+		ei_outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
+	ei_outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
+	for(i = 0; i < 8; i++)
+	{
+		ei_outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i));
+#ifndef BUG_83C690
+		if(ei_inb_p(e8390_base + EN1_MULT_SHIFT(i))!=ei_local->mcfilter[i])
+			printk(KERN_ERR "Multicast filter read/write mismap %d\n",i);
+#endif
+	}
+	ei_outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD);
+
+  	if(dev->flags&IFF_PROMISC)
+  		ei_outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR);
+	else if(dev->flags&IFF_ALLMULTI || dev->mc_list)
+  		ei_outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR);
+  	else
+  		ei_outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
+ }
+
+/*
+ *	Called without lock held. This is invoked from user context and may
+ *	be parallel to just about everything else. Its also fairly quick and
+ *	not called too often. Must protect against both bh and irq users
+ */
+
+static void set_multicast_list(struct net_device *dev)
+{
+	unsigned long flags;
+	struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
+
+	spin_lock_irqsave(&ei_local->page_lock, flags);
+	do_set_multicast_list(dev);
+	spin_unlock_irqrestore(&ei_local->page_lock, flags);
+}
+
+/**
+ * ethdev_setup - init rest of 8390 device struct
+ * @dev: network device structure to init
+ *
+ * Initialize the rest of the 8390 device structure.  Do NOT __init
+ * this, as it is used by 8390 based modular drivers too.
+ */
+
+static void ethdev_setup(struct net_device *dev)
+{
+	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+	if (ei_debug > 1)
+		printk(version);
+
+	dev->hard_start_xmit = &ei_start_xmit;
+	dev->get_stats	= get_stats;
+	dev->set_multicast_list = &set_multicast_list;
+
+	ether_setup(dev);
+
+	spin_lock_init(&ei_local->page_lock);
+}
+
+/**
+ * alloc_ei_netdev - alloc_etherdev counterpart for 8390
+ * @size: extra bytes to allocate
+ *
+ * Allocate 8390-specific net_device.
+ */
+static struct net_device *____alloc_ei_netdev(int size)
+{
+	return alloc_netdev(sizeof(struct ei_device) + size, "eth%d",
+				ethdev_setup);
+}
+
+
+
+
+/* This page of functions should be 8390 generic */
+/* Follow National Semi's recommendations for initializing the "NIC". */
+
+/**
+ * NS8390_init - initialize 8390 hardware
+ * @dev: network device to initialize
+ * @startp: boolean.  non-zero value to initiate chip processing
+ *
+ *	Must be called with lock held.
+ */
+
+static void __NS8390_init(struct net_device *dev, int startp)
+{
+	unsigned long e8390_base = dev->base_addr;
+	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+	int i;
+	int endcfg = ei_local->word16
+	    ? (0x48 | ENDCFG_WTS | (ei_local->bigendian ? ENDCFG_BOS : 0))
+	    : 0x48;
+
+	if(sizeof(struct e8390_pkt_hdr)!=4)
+    		panic("8390.c: header struct mispacked\n");
+	/* Follow National Semi's recommendations for initing the DP83902. */
+	ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); /* 0x21 */
+	ei_outb_p(endcfg, e8390_base + EN0_DCFG);	/* 0x48 or 0x49 */
+	/* Clear the remote byte count registers. */
+	ei_outb_p(0x00,  e8390_base + EN0_RCNTLO);
+	ei_outb_p(0x00,  e8390_base + EN0_RCNTHI);
+	/* Set to monitor and loopback mode -- this is vital!. */
+	ei_outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */
+	ei_outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */
+	/* Set the transmit page and receive ring. */
+	ei_outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR);
+	ei_local->tx1 = ei_local->tx2 = 0;
+	ei_outb_p(ei_local->rx_start_page, e8390_base + EN0_STARTPG);
+	ei_outb_p(ei_local->stop_page-1, e8390_base + EN0_BOUNDARY);	/* 3c503 says 0x3f,NS0x26*/
+	ei_local->current_page = ei_local->rx_start_page;		/* assert boundary+1 */
+	ei_outb_p(ei_local->stop_page, e8390_base + EN0_STOPPG);
+	/* Clear the pending interrupts and mask. */
+	ei_outb_p(0xFF, e8390_base + EN0_ISR);
+	ei_outb_p(0x00,  e8390_base + EN0_IMR);
+
+	/* Copy the station address into the DS8390 registers. */
+
+	ei_outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* 0x61 */
+	for(i = 0; i < 6; i++)
+	{
+		ei_outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i));
+		if (ei_debug > 1 && ei_inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
+			printk(KERN_ERR "Hw. address read/write mismap %d\n",i);
+	}
+
+	ei_outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
+	ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
+
+	netif_start_queue(dev);
+	ei_local->tx1 = ei_local->tx2 = 0;
+	ei_local->txing = 0;
+
+	if (startp)
+	{
+		ei_outb_p(0xff,  e8390_base + EN0_ISR);
+		ei_outb_p(ENISR_ALL,  e8390_base + EN0_IMR);
+		ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD);
+		ei_outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
+		/* 3c503 TechMan says rxconfig only after the NIC is started. */
+		ei_outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on,  */
+		do_set_multicast_list(dev);	/* (re)load the mcast table */
+	}
+}
+
+/* Trigger a transmit start, assuming the length is valid.
+   Always called with the page lock held */
+
+static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
+								int start_page)
+{
+	unsigned long e8390_base = dev->base_addr;
+ 	struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) netdev_priv(dev);
+
+	ei_outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD);
+
+	if (ei_inb_p(e8390_base + E8390_CMD) & E8390_TRANS)
+	{
+		printk(KERN_WARNING "%s: trigger_send() called with the transmitter busy.\n",
+			dev->name);
+		return;
+	}
+	ei_outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
+	ei_outb_p(length >> 8, e8390_base + EN0_TCNTHI);
+	ei_outb_p(start_page, e8390_base + EN0_TPSR);
+	ei_outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base+E8390_CMD);
+}
diff -urN oldtree/drivers/net/mac8390.c newtree/drivers/net/mac8390.c
--- oldtree/drivers/net/mac8390.c	2006-02-19 11:41:03.294842208 +0000
+++ newtree/drivers/net/mac8390.c	2006-02-21 15:58:36.363618448 +0000
@@ -39,7 +39,16 @@
 #include <asm/hwtest.h>
 #include <asm/macints.h>
 
-#include "8390.h"
+static char version[] =
+	"mac8390.c: v0.4 2001-05-15 David Huggins-Daines <dhd@debian.org> and others\n";
+
+#define EI_SHIFT(x)	(ei_local->reg_offset[x])
+#define ei_inb(port)   in_8(port)
+#define ei_outb(val,port)  out_8(port,val)
+#define ei_inb_p(port)   in_8(port)
+#define ei_outb_p(val,port)  out_8(port,val)
+
+#include "lib8390.c"
 
 #define WD_START_PG			0x00	/* First page of TX buffer */
 #define CABLETRON_RX_START_PG		0x00    /* First page of RX buffer */
@@ -116,9 +125,6 @@
 	1, /* dayna-lc */
 };
 
-static char version[] __initdata =
-	"mac8390.c: v0.4 2001-05-15 David Huggins-Daines <dhd@debian.org> and others\n";
-		
 extern enum mac8390_type mac8390_ident(struct nubus_dev * dev);
 extern int mac8390_memsize(unsigned long membase);
 extern int mac8390_memtest(struct net_device * dev);
@@ -237,7 +243,7 @@
 	if (!MACH_IS_MAC)
 		return ERR_PTR(-ENODEV);
 
-	dev = alloc_ei_netdev();
+	dev = ____alloc_ei_netdev(0);
 	if (!dev)
 		return ERR_PTR(-ENOMEM);
 
@@ -438,7 +444,7 @@
 	dev->open = &mac8390_open;
 	dev->stop = &mac8390_close;
 #ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = ei_poll;
+	dev->poll_controller = __ei_poll;
 #endif
 
 	/* GAR, ei_status is actually a macro even though it looks global */
@@ -510,7 +516,7 @@
 		return -ENODEV;
 	}
 		
-	NS8390_init(dev, 0);
+	__NS8390_init(dev, 0);
 
 	/* Good, done, now spit out some messages */
 	printk(KERN_INFO "%s: %s in slot %X (type %s)\n",
@@ -532,8 +538,8 @@
 
 static int mac8390_open(struct net_device *dev)
 {
-	ei_open(dev);
-	if (request_irq(dev->irq, ei_interrupt, 0, "8390 Ethernet", dev)) {
+	__ei_open(dev);
+	if (request_irq(dev->irq, __ei_interrupt, 0, "8390 Ethernet", dev)) {
 		printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
 		return -EAGAIN;
 	}	
@@ -543,7 +549,7 @@
 static int mac8390_close(struct net_device *dev)
 {
 	free_irq(dev->irq, dev);
-	ei_close(dev);
+	__ei_close(dev);
 	return 0;
 }
 
diff -urN oldtree/drivers/net/macsonic.c newtree/drivers/net/macsonic.c
--- oldtree/drivers/net/macsonic.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/macsonic.c	2006-02-21 15:58:15.376808928 +0000
@@ -622,7 +622,7 @@
 	return 0;
 
 out_unregister:
-	driver_unregister(&mac_sonic_driver);
+	platform_driver_unregister(&mac_sonic_driver);
 
 	return -ENOMEM;
 }
diff -urN oldtree/drivers/net/mv643xx_eth.c newtree/drivers/net/mv643xx_eth.c
--- oldtree/drivers/net/mv643xx_eth.c	2006-02-19 11:41:03.297841752 +0000
+++ newtree/drivers/net/mv643xx_eth.c	2006-02-21 15:58:15.381808168 +0000
@@ -81,10 +81,15 @@
 #define PHY_WAIT_MICRO_SECONDS	10
 
 /* Static function declarations */
-static int eth_port_link_is_up(unsigned int eth_port_num);
 static void eth_port_uc_addr_get(struct net_device *dev,
 						unsigned char *MacAddr);
 static void eth_port_set_multicast_list(struct net_device *);
+static void mv643xx_eth_port_enable_tx(unsigned int port_num,
+						unsigned int channels);
+static void mv643xx_eth_port_enable_rx(unsigned int port_num,
+						unsigned int channels);
+static unsigned int mv643xx_eth_port_disable_tx(unsigned int port_num);
+static unsigned int mv643xx_eth_port_disable_rx(unsigned int port_num);
 static int mv643xx_eth_open(struct net_device *);
 static int mv643xx_eth_stop(struct net_device *);
 static int mv643xx_eth_change_mtu(struct net_device *, int);
@@ -93,8 +98,12 @@
 #ifdef MV643XX_NAPI
 static int mv643xx_poll(struct net_device *dev, int *budget);
 #endif
+static int ethernet_phy_get(unsigned int eth_port_num);
 static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr);
 static int ethernet_phy_detect(unsigned int eth_port_num);
+static int mv643xx_mdio_read(struct net_device *dev, int phy_id, int location);
+static void mv643xx_mdio_write(struct net_device *dev, int phy_id, int location, int val);
+static int mv643xx_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
 static struct ethtool_ops mv643xx_ethtool_ops;
 
 static char mv643xx_driver_name[] = "mv643xx_eth";
@@ -171,11 +180,11 @@
 	if (test_and_set_bit(0, &mp->rx_task_busy))
 		panic("%s: Error in test_set_bit / clear_bit", dev->name);
 
-	while (mp->rx_ring_skbs < (mp->rx_ring_size - 5)) {
+	while (mp->rx_desc_count < (mp->rx_ring_size - 5)) {
 		skb = dev_alloc_skb(RX_SKB_SIZE + DMA_ALIGN);
 		if (!skb)
 			break;
-		mp->rx_ring_skbs++;
+		mp->rx_desc_count++;
 		unaligned = (u32)skb->data & (DMA_ALIGN - 1);
 		if (unaligned)
 			skb_reserve(skb, DMA_ALIGN - unaligned);
@@ -196,7 +205,7 @@
 	 * If RX ring is empty of SKB, set a timer to try allocating
 	 * again in a later time .
 	 */
-	if ((mp->rx_ring_skbs == 0) && (mp->rx_timer_flag == 0)) {
+	if ((mp->rx_desc_count == 0) && (mp->rx_timer_flag == 0)) {
 		printk(KERN_INFO "%s: Rx ring is empty\n", dev->name);
 		/* After 100mSec */
 		mp->timeout.expires = jiffies + (HZ / 10);
@@ -245,8 +254,7 @@
 	unsigned int port_num = mp->port_num;
 
 	eth_port_init_mac_tables(port_num);
-	memcpy(mp->port_mac_addr, dev->dev_addr, 6);
-	eth_port_uc_addr_set(port_num, mp->port_mac_addr);
+	eth_port_uc_addr_set(port_num, dev->dev_addr);
 }
 
 /*
@@ -260,13 +268,14 @@
 static void mv643xx_eth_set_rx_mode(struct net_device *dev)
 {
 	struct mv643xx_private *mp = netdev_priv(dev);
+	u32 config_reg;
 
+	config_reg = mv_read(MV643XX_ETH_PORT_CONFIG_REG(mp->port_num));
 	if (dev->flags & IFF_PROMISC)
-		mp->port_config |= (u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
+		config_reg |= (u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
 	else
-		mp->port_config &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
-
-	mv_write(MV643XX_ETH_PORT_CONFIG_REG(mp->port_num), mp->port_config);
+		config_reg &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
+	mv_write(MV643XX_ETH_PORT_CONFIG_REG(mp->port_num), config_reg);
 
 	eth_port_set_multicast_list(dev);
 }
@@ -322,7 +331,7 @@
 
 	netif_device_detach(dev);
 	eth_port_reset(mp->port_num);
-	eth_port_start(mp);
+	eth_port_start(dev);
 	netif_device_attach(dev);
 }
 
@@ -397,7 +406,7 @@
 #else
 	while (eth_port_receive(mp, &pkt_info) == ETH_OK) {
 #endif
-		mp->rx_ring_skbs--;
+		mp->rx_desc_count--;
 		received_packets++;
 
 		/* Update statistics. Note byte count includes 4 byte CRC count */
@@ -452,6 +461,56 @@
 	return received_packets;
 }
 
+/* Set the mv643xx port configuration register for the speed/duplex mode. */
+static void mv643xx_eth_update_pscr(struct net_device *dev,
+				    struct ethtool_cmd *ecmd)
+{
+	struct mv643xx_private *mp = netdev_priv(dev);
+	int port_num = mp->port_num;
+	u32 o_pscr, n_pscr;
+	unsigned int channels;
+
+	o_pscr = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num));
+	n_pscr = o_pscr;
+
+	/* clear speed, duplex and rx buffer size fields */
+	n_pscr &= ~(MV643XX_ETH_SET_MII_SPEED_TO_100  |
+		   MV643XX_ETH_SET_GMII_SPEED_TO_1000 |
+		   MV643XX_ETH_SET_FULL_DUPLEX_MODE   |
+		   MV643XX_ETH_MAX_RX_PACKET_MASK);
+
+	if (ecmd->duplex == DUPLEX_FULL)
+		n_pscr |= MV643XX_ETH_SET_FULL_DUPLEX_MODE;
+
+	if (ecmd->speed == SPEED_1000)
+		n_pscr |= MV643XX_ETH_SET_GMII_SPEED_TO_1000 |
+			  MV643XX_ETH_MAX_RX_PACKET_9700BYTE;
+	else {
+		if (ecmd->speed == SPEED_100)
+			n_pscr |= MV643XX_ETH_SET_MII_SPEED_TO_100;
+		n_pscr |= MV643XX_ETH_MAX_RX_PACKET_1522BYTE;
+	}
+
+	if (n_pscr != o_pscr) {
+		if ((o_pscr & MV643XX_ETH_SERIAL_PORT_ENABLE) == 0)
+			mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
+								n_pscr);
+		else {
+			channels = mv643xx_eth_port_disable_tx(port_num);
+
+			o_pscr &= ~MV643XX_ETH_SERIAL_PORT_ENABLE;
+			mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
+								o_pscr);
+			mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
+								n_pscr);
+			mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
+								n_pscr);
+			if (channels)
+				mv643xx_eth_port_enable_tx(port_num, channels);
+		}
+	}
+}
+
 /*
  * mv643xx_eth_int_handler
  *
@@ -497,7 +556,7 @@
 		/* UDP change : We may need this */
 		if ((eth_int_cause_ext & 0x0000ffff) &&
 		    (mv643xx_eth_free_tx_queue(dev, eth_int_cause_ext) == 0) &&
-		    (mp->tx_ring_size > mp->tx_ring_skbs + MAX_DESCS_PER_SKB))
+		    (mp->tx_ring_size > mp->tx_desc_count + MAX_DESCS_PER_SKB))
 			netif_wake_queue(dev);
 #ifdef MV643XX_NAPI
 	} else {
@@ -534,15 +593,23 @@
 	}
 	/* PHY status changed */
 	if (eth_int_cause_ext & (BIT16 | BIT20)) {
-		if (eth_port_link_is_up(port_num)) {
-			netif_carrier_on(dev);
-			netif_wake_queue(dev);
-			/* Start TX queue */
-			mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG
-								(port_num), 1);
-		} else {
-			netif_carrier_off(dev);
+		struct ethtool_cmd cmd;
+
+		if (mii_link_ok(&mp->mii)) {
+			mii_ethtool_gset(&mp->mii, &cmd);
+			mv643xx_eth_update_pscr(dev, &cmd);
+			if (!netif_carrier_ok(dev)) {
+				netif_carrier_on(dev);
+				if (mp->tx_ring_size > mp->tx_desc_count +
+							MAX_DESCS_PER_SKB) {
+					netif_wake_queue(dev);
+					/* Start TX queue */
+					mv643xx_eth_port_enable_tx(port_num, mp->port_tx_queue_command);
+				}
+			}
+		} else if (netif_carrier_ok(dev)) {
 			netif_stop_queue(dev);
+			netif_carrier_off(dev);
 		}
 	}
 
@@ -671,8 +738,8 @@
 
 	mp->rx_desc_area_size = rx_desc_num * sizeof(struct eth_rx_desc);
 
-	/* Add the queue to the list of RX queues of this port */
-	mp->port_rx_queue_command |= 1;
+	/* Enable queue 0 for this port */
+	mp->port_rx_queue_command = 1;
 }
 
 /*
@@ -718,8 +785,36 @@
 
 	mp->tx_desc_area_size = tx_desc_num * sizeof(struct eth_tx_desc);
 
-	/* Add the queue to the list of Tx queues of this port */
-	mp->port_tx_queue_command |= 1;
+	/* Enable queue 0 for this port */
+	mp->port_tx_queue_command = 1;
+}
+
+static int mv643xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct mv643xx_private *mp = netdev_priv(dev);
+	int err;
+
+	spin_lock_irq(&mp->lock);
+	err = mii_ethtool_sset(&mp->mii, cmd);
+	spin_unlock_irq(&mp->lock);
+
+	return err;
+}
+
+static int mv643xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct mv643xx_private *mp = netdev_priv(dev);
+	int err;
+
+	spin_lock_irq(&mp->lock);
+	err = mii_ethtool_gset(&mp->mii, cmd);
+	spin_unlock_irq(&mp->lock);
+
+	/* The PHY may support 1000baseT_Half, but the mv643xx does not */
+	cmd->supported &= ~SUPPORTED_1000baseT_Half;
+	cmd->advertising &= ~ADVERTISED_1000baseT_Half;
+
+	return err;
 }
 
 /*
@@ -750,12 +845,6 @@
 		return -EAGAIN;
 	}
 
-	/* Stop RX Queues */
-	mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), 0x0000ff00);
-
-	/* Set the MAC Address */
-	memcpy(mp->port_mac_addr, dev->dev_addr, 6);
-
 	eth_port_init(mp);
 
 	INIT_WORK(&mp->rx_task, (void (*)(void *))mv643xx_eth_rx_task, dev);
@@ -784,7 +873,7 @@
 	}
 
 	/* Allocate TX ring */
-	mp->tx_ring_skbs = 0;
+	mp->tx_desc_count = 0;
 	size = mp->tx_ring_size * sizeof(struct eth_tx_desc);
 	mp->tx_desc_area_size = size;
 
@@ -809,7 +898,7 @@
 	ether_init_tx_desc_ring(mp);
 
 	/* Allocate RX ring */
-	mp->rx_ring_skbs = 0;
+	mp->rx_desc_count = 0;
 	size = mp->rx_ring_size * sizeof(struct eth_rx_desc);
 	mp->rx_desc_area_size = size;
 
@@ -841,7 +930,11 @@
 
 	mv643xx_eth_rx_task(dev);	/* Fill RX ring with skb's */
 
-	eth_port_start(mp);
+	/* Clear any pending ethernet port interrupts */
+	mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
+	mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0);
+
+	eth_port_start(dev);
 
 	/* Interrupt Coalescing */
 
@@ -853,16 +946,13 @@
 	mp->tx_int_coal =
 		eth_port_set_tx_coal(port_num, 133000000, MV643XX_TX_COAL);
 
-	/* Clear any pending ethernet port interrupts */
-	mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
-	mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0);
-
 	/* Unmask phy and link status changes interrupts */
 	mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num),
 						INT_UNMASK_ALL_EXT);
 
 	/* Unmask RX buffer and TX end interrupt */
 	mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_UNMASK_ALL);
+
 	return 0;
 
 out_free_tx_skb:
@@ -883,20 +973,20 @@
 	struct sk_buff *skb;
 
 	/* Stop Tx Queues */
-	mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), 0x0000ff00);
+	mv643xx_eth_port_disable_tx(port_num);
 
 	/* Free outstanding skb's on TX rings */
-	for (curr = 0; mp->tx_ring_skbs && curr < mp->tx_ring_size; curr++) {
+	for (curr = 0; mp->tx_desc_count && curr < mp->tx_ring_size; curr++) {
 		skb = mp->tx_skb[curr];
 		if (skb) {
-			mp->tx_ring_skbs -= skb_shinfo(skb)->nr_frags;
+			mp->tx_desc_count -= skb_shinfo(skb)->nr_frags;
 			dev_kfree_skb(skb);
-			mp->tx_ring_skbs--;
+			mp->tx_desc_count--;
 		}
 	}
-	if (mp->tx_ring_skbs)
+	if (mp->tx_desc_count)
 		printk("%s: Error on Tx descriptor free - could not free %d"
-				" descriptors\n", dev->name, mp->tx_ring_skbs);
+				" descriptors\n", dev->name, mp->tx_desc_count);
 
 	/* Free TX ring */
 	if (mp->tx_sram_size)
@@ -913,21 +1003,21 @@
 	int curr;
 
 	/* Stop RX Queues */
-	mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), 0x0000ff00);
+	mv643xx_eth_port_disable_rx(port_num);
 
 	/* Free preallocated skb's on RX rings */
-	for (curr = 0; mp->rx_ring_skbs && curr < mp->rx_ring_size; curr++) {
+	for (curr = 0; mp->rx_desc_count && curr < mp->rx_ring_size; curr++) {
 		if (mp->rx_skb[curr]) {
 			dev_kfree_skb(mp->rx_skb[curr]);
-			mp->rx_ring_skbs--;
+			mp->rx_desc_count--;
 		}
 	}
 
-	if (mp->rx_ring_skbs)
+	if (mp->rx_desc_count)
 		printk(KERN_ERR
 			"%s: Error in freeing Rx Ring. %d skb's still"
 			" stuck in RX Ring - ignoring them\n", dev->name,
-			mp->rx_ring_skbs);
+			mp->rx_desc_count);
 	/* Free RX ring */
 	if (mp->rx_sram_size)
 		iounmap(mp->p_rx_desc_area);
@@ -997,7 +1087,8 @@
 	}
 
 	if (netif_queue_stopped(dev) &&
-			mp->tx_ring_size > mp->tx_ring_skbs + MAX_DESCS_PER_SKB)
+			mp->tx_ring_size >
+					mp->tx_desc_count + MAX_DESCS_PER_SKB)
 		netif_wake_queue(dev);
 }
 
@@ -1089,7 +1180,7 @@
 	}
 
 	/* This is a hard error, log it. */
-	if ((mp->tx_ring_size - mp->tx_ring_skbs) <=
+	if ((mp->tx_ring_size - mp->tx_desc_count) <=
 					(skb_shinfo(skb)->nr_frags + 1)) {
 		netif_stop_queue(dev);
 		printk(KERN_ERR
@@ -1266,7 +1357,7 @@
 	/* Check if TX queue can handle another skb. If not, then
 	 * signal higher layers to stop requesting TX
 	 */
-	if (mp->tx_ring_size <= (mp->tx_ring_skbs + MAX_DESCS_PER_SKB))
+	if (mp->tx_ring_size <= (mp->tx_desc_count + MAX_DESCS_PER_SKB))
 		/*
 		 * Stop getting skb's from upper layers.
 		 * Getting skb's from upper layers will be enabled again after
@@ -1316,6 +1407,35 @@
 }
 #endif
 
+static void mv643xx_init_ethtool_cmd(struct net_device *dev, int phy_address,
+				     int speed, int duplex,
+				     struct ethtool_cmd *cmd)
+{
+	struct mv643xx_private *mp = netdev_priv(dev);
+
+	memset(cmd, 0, sizeof(*cmd));
+
+	cmd->port = PORT_MII;
+	cmd->transceiver = XCVR_INTERNAL;
+	cmd->phy_address = phy_address;
+
+	if (speed == 0) {
+		cmd->autoneg = AUTONEG_ENABLE;
+		/* mii lib checks, but doesn't use speed on AUTONEG_ENABLE */
+		cmd->speed = SPEED_100;
+		cmd->advertising = ADVERTISED_10baseT_Half  |
+				   ADVERTISED_10baseT_Full  |
+				   ADVERTISED_100baseT_Half |
+				   ADVERTISED_100baseT_Full;
+		if (mp->mii.supports_gmii)
+			cmd->advertising |= ADVERTISED_1000baseT_Full;
+	} else {
+		cmd->autoneg = AUTONEG_DISABLE;
+		cmd->speed = speed;
+		cmd->duplex = duplex;
+	}
+}
+
 /*/
  * mv643xx_eth_probe
  *
@@ -1336,6 +1456,9 @@
 	u8 *p;
 	struct resource *res;
 	int err;
+	struct ethtool_cmd cmd;
+	int duplex = DUPLEX_HALF;
+	int speed = 0;			/* default to auto-negotiation */
 
 	dev = alloc_etherdev(sizeof(struct mv643xx_private));
 	if (!dev)
@@ -1373,6 +1496,7 @@
 	dev->tx_queue_len = mp->tx_ring_size;
 	dev->base_addr = 0;
 	dev->change_mtu = mv643xx_eth_change_mtu;
+	dev->do_ioctl = mv643xx_eth_do_ioctl;
 	SET_ETHTOOL_OPS(dev, &mv643xx_ethtool_ops);
 
 #ifdef MV643XX_CHECKSUM_OFFLOAD_TX
@@ -1393,33 +1517,17 @@
 
 	/* set default config values */
 	eth_port_uc_addr_get(dev, dev->dev_addr);
-	mp->port_config = MV643XX_ETH_PORT_CONFIG_DEFAULT_VALUE;
-	mp->port_config_extend = MV643XX_ETH_PORT_CONFIG_EXTEND_DEFAULT_VALUE;
-	mp->port_sdma_config = MV643XX_ETH_PORT_SDMA_CONFIG_DEFAULT_VALUE;
-	mp->port_serial_control = MV643XX_ETH_PORT_SERIAL_CONTROL_DEFAULT_VALUE;
 	mp->rx_ring_size = MV643XX_ETH_PORT_DEFAULT_RECEIVE_QUEUE_SIZE;
 	mp->tx_ring_size = MV643XX_ETH_PORT_DEFAULT_TRANSMIT_QUEUE_SIZE;
 
 	pd = pdev->dev.platform_data;
 	if (pd) {
-		if (pd->mac_addr != NULL)
+		if (pd->mac_addr)
 			memcpy(dev->dev_addr, pd->mac_addr, 6);
 
 		if (pd->phy_addr || pd->force_phy_addr)
 			ethernet_phy_set(port_num, pd->phy_addr);
 
-		if (pd->port_config || pd->force_port_config)
-			mp->port_config = pd->port_config;
-
-		if (pd->port_config_extend || pd->force_port_config_extend)
-			mp->port_config_extend = pd->port_config_extend;
-
-		if (pd->port_sdma_config || pd->force_port_sdma_config)
-			mp->port_sdma_config = pd->port_sdma_config;
-
-		if (pd->port_serial_control || pd->force_port_serial_control)
-			mp->port_serial_control = pd->port_serial_control;
-
 		if (pd->rx_queue_size)
 			mp->rx_ring_size = pd->rx_queue_size;
 
@@ -1435,16 +1543,33 @@
 			mp->rx_sram_size = pd->rx_sram_size;
 			mp->rx_sram_addr = pd->rx_sram_addr;
 		}
+
+		duplex = pd->duplex;
+		speed = pd->speed;
 	}
 
+	/* Hook up MII support for ethtool */
+	mp->mii.dev = dev;
+	mp->mii.mdio_read = mv643xx_mdio_read;
+	mp->mii.mdio_write = mv643xx_mdio_write;
+	mp->mii.phy_id = ethernet_phy_get(port_num);
+	mp->mii.phy_id_mask = 0x3f;
+	mp->mii.reg_num_mask = 0x1f;
+
 	err = ethernet_phy_detect(port_num);
 	if (err) {
 		pr_debug("MV643xx ethernet port %d: "
 					"No PHY detected at addr %d\n",
 					port_num, ethernet_phy_get(port_num));
-		return err;
+		goto out;
 	}
 
+	ethernet_phy_reset(port_num);
+	mp->mii.supports_gmii = mii_check_gmii_support(&mp->mii);
+	mv643xx_init_ethtool_cmd(dev, mp->mii.phy_id, speed, duplex, &cmd);
+	mv643xx_eth_update_pscr(dev, &cmd);
+	mv643xx_set_settings(dev, &cmd);
+
 	err = register_netdev(dev);
 	if (err)
 		goto out;
@@ -1708,7 +1833,6 @@
  *	Prior to calling the initialization routine eth_port_init() the user
  *	must set the following fields under mv643xx_private struct:
  *	port_num		User Ethernet port number.
- *	port_mac_addr[6]	User defined port MAC address.
  *	port_config		User port configuration value.
  *	port_config_extend	User port config extend value.
  *	port_sdma_config	User port SDMA config value.
@@ -1725,20 +1849,12 @@
  *		return_info	Tx/Rx user resource return information.
  */
 
-/* defines */
-/* SDMA command macros */
-#define ETH_ENABLE_TX_QUEUE(eth_port) \
-	mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port), 1)
-
-/* locals */
-
 /* PHY routines */
 static int ethernet_phy_get(unsigned int eth_port_num);
 static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr);
 
 /* Ethernet Port routines */
-static int eth_port_uc_addr(unsigned int eth_port_num, unsigned char uc_nibble,
-								int option);
+static void eth_port_set_filter_table_entry(int table, unsigned char entry);
 
 /*
  * eth_port_init - Initialize the Ethernet port driver
@@ -1766,17 +1882,12 @@
  */
 static void eth_port_init(struct mv643xx_private *mp)
 {
-	mp->port_rx_queue_command = 0;
-	mp->port_tx_queue_command = 0;
-
 	mp->rx_resource_err = 0;
 	mp->tx_resource_err = 0;
 
 	eth_port_reset(mp->port_num);
 
 	eth_port_init_mac_tables(mp->port_num);
-
-	ethernet_phy_reset(mp->port_num);
 }
 
 /*
@@ -1798,7 +1909,7 @@
  *	and ether_init_rx_desc_ring for Rx queues).
  *
  * INPUT:
- *	struct mv643xx_private *mp	Ethernet port control struct
+ *	dev - a pointer to the required interface
  *
  * OUTPUT:
  *	Ethernet port is ready to receive and transmit.
@@ -1806,10 +1917,13 @@
  * RETURN:
  *	None.
  */
-static void eth_port_start(struct mv643xx_private *mp)
+static void eth_port_start(struct net_device *dev)
 {
+	struct mv643xx_private *mp = netdev_priv(dev);
 	unsigned int port_num = mp->port_num;
 	int tx_curr_desc, rx_curr_desc;
+	u32 pscr;
+	struct ethtool_cmd ethtool_cmd;
 
 	/* Assignment of Tx CTRP of given queue */
 	tx_curr_desc = mp->tx_curr_desc_q;
@@ -1822,37 +1936,45 @@
 		(u32)((struct eth_rx_desc *)mp->rx_desc_dma + rx_curr_desc));
 
 	/* Add the assigned Ethernet address to the port's address table */
-	eth_port_uc_addr_set(port_num, mp->port_mac_addr);
+	eth_port_uc_addr_set(port_num, dev->dev_addr);
 
 	/* Assign port configuration and command. */
-	mv_write(MV643XX_ETH_PORT_CONFIG_REG(port_num), mp->port_config);
+	mv_write(MV643XX_ETH_PORT_CONFIG_REG(port_num),
+			  MV643XX_ETH_PORT_CONFIG_DEFAULT_VALUE);
 
 	mv_write(MV643XX_ETH_PORT_CONFIG_EXTEND_REG(port_num),
-						mp->port_config_extend);
+			  MV643XX_ETH_PORT_CONFIG_EXTEND_DEFAULT_VALUE);
 
+	pscr = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num));
 
-	/* Increase the Rx side buffer size if supporting GigE */
-	if (mp->port_serial_control & MV643XX_ETH_SET_GMII_SPEED_TO_1000)
-		mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
-			(mp->port_serial_control & 0xfff1ffff) | (0x5 << 17));
-	else
-		mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
-						mp->port_serial_control);
+	pscr &= ~(MV643XX_ETH_SERIAL_PORT_ENABLE | MV643XX_ETH_FORCE_LINK_PASS);
+	mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr);
 
-	mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
-		mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)) |
-						MV643XX_ETH_SERIAL_PORT_ENABLE);
+	pscr |= MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL |
+		MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII    |
+		MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLX     |
+		MV643XX_ETH_DO_NOT_FORCE_LINK_FAIL	   |
+		MV643XX_ETH_SERIAL_PORT_CONTROL_RESERVED;
+
+	mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr);
+
+	pscr |= MV643XX_ETH_SERIAL_PORT_ENABLE;
+	mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr);
 
 	/* Assign port SDMA configuration */
 	mv_write(MV643XX_ETH_SDMA_CONFIG_REG(port_num),
-							mp->port_sdma_config);
+			  MV643XX_ETH_PORT_SDMA_CONFIG_DEFAULT_VALUE);
 
 	/* Enable port Rx. */
-	mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num),
-						mp->port_rx_queue_command);
+	mv643xx_eth_port_enable_rx(port_num, mp->port_rx_queue_command);
 
 	/* Disable port bandwidth limits by clearing MTU register */
 	mv_write(MV643XX_ETH_MAXIMUM_TRANSMIT_UNIT(port_num), 0);
+
+	/* save phy settings across reset */
+	mv643xx_get_settings(dev, &ethtool_cmd);
+	ethernet_phy_reset(mp->port_num);
+	mv643xx_set_settings(dev, &ethtool_cmd);
 }
 
 /*
@@ -1866,8 +1988,9 @@
  *	char *		p_addr		Address to be set
  *
  * OUTPUT:
- *	Set MAC address low and high registers. also calls eth_port_uc_addr()
- *	To set the unicast table with the proper information.
+ *	Set MAC address low and high registers. also calls
+ *	eth_port_set_filter_table_entry() to set the unicast
+ *	table with the proper information.
  *
  * RETURN:
  *	N/A.
@@ -1878,6 +2001,7 @@
 {
 	unsigned int mac_h;
 	unsigned int mac_l;
+	int table;
 
 	mac_l = (p_addr[4] << 8) | (p_addr[5]);
 	mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | (p_addr[2] << 8) |
@@ -1887,9 +2011,8 @@
 	mv_write(MV643XX_ETH_MAC_ADDR_HIGH(eth_port_num), mac_h);
 
 	/* Accept frames of this address */
-	eth_port_uc_addr(eth_port_num, p_addr[5], ACCEPT_MAC_ADDR);
-
-	return;
+	table = MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE(eth_port_num);
+	eth_port_set_filter_table_entry(table, p_addr[5] & 0x0f);
 }
 
 /*
@@ -1928,72 +2051,6 @@
 }
 
 /*
- * eth_port_uc_addr - This function Set the port unicast address table
- *
- * DESCRIPTION:
- *	This function locates the proper entry in the Unicast table for the
- *	specified MAC nibble and sets its properties according to function
- *	parameters.
- *
- * INPUT:
- *	unsigned int	eth_port_num	Port number.
- *	unsigned char	uc_nibble	Unicast MAC Address last nibble.
- *	int 		option		0 = Add, 1 = remove address.
- *
- * OUTPUT:
- *	This function add/removes MAC addresses from the port unicast address
- *	table.
- *
- * RETURN:
- *	true is output succeeded.
- *	false if option parameter is invalid.
- *
- */
-static int eth_port_uc_addr(unsigned int eth_port_num, unsigned char uc_nibble,
-								int option)
-{
-	unsigned int unicast_reg;
-	unsigned int tbl_offset;
-	unsigned int reg_offset;
-
-	/* Locate the Unicast table entry */
-	uc_nibble = (0xf & uc_nibble);
-	tbl_offset = (uc_nibble / 4) * 4;	/* Register offset from unicast table base */
-	reg_offset = uc_nibble % 4;	/* Entry offset within the above register */
-
-	switch (option) {
-	case REJECT_MAC_ADDR:
-		/* Clear accepts frame bit at given unicast DA table entry */
-		unicast_reg = mv_read((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE
-						(eth_port_num) + tbl_offset));
-
-		unicast_reg &= (0x0E << (8 * reg_offset));
-
-		mv_write((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE
-				(eth_port_num) + tbl_offset), unicast_reg);
-		break;
-
-	case ACCEPT_MAC_ADDR:
-		/* Set accepts frame bit at unicast DA filter table entry */
-		unicast_reg =
-			mv_read((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE
-						(eth_port_num) + tbl_offset));
-
-		unicast_reg |= (0x01 << (8 * reg_offset));
-
-		mv_write((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE
-				(eth_port_num) + tbl_offset), unicast_reg);
-
-		break;
-
-	default:
-		return 0;
-	}
-
-	return 1;
-}
-
-/*
  * The entries in each table are indexed by a hash of a packet's MAC
  * address.  One bit in each entry determines whether the packet is
  * accepted.  There are 4 entries (each 8 bits wide) in each register
@@ -2205,8 +2262,8 @@
 
 	/* Clear DA filter unicast table (Ex_dFUT) */
 	for (table_index = 0; table_index <= 0xC; table_index += 4)
-		mv_write((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE
-					(eth_port_num) + table_index), 0);
+		mv_write(MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE
+					(eth_port_num) + table_index, 0);
 
 	for (table_index = 0; table_index <= 0xFC; table_index += 4) {
 		/* Clear DA filter special multicast table (Ex_dFSMT) */
@@ -2389,6 +2446,73 @@
 	eth_port_read_smi_reg(eth_port_num, 0, &phy_reg_data);
 	phy_reg_data |= 0x8000;	/* Set bit 15 to reset the PHY */
 	eth_port_write_smi_reg(eth_port_num, 0, phy_reg_data);
+
+	/* wait for PHY to come out of reset */
+	do {
+		udelay(1);
+		eth_port_read_smi_reg(eth_port_num, 0, &phy_reg_data);
+	} while (phy_reg_data & 0x8000);
+}
+
+static void mv643xx_eth_port_enable_tx(unsigned int port_num,
+					unsigned int channels)
+{
+	mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), channels);
+}
+
+static void mv643xx_eth_port_enable_rx(unsigned int port_num,
+					unsigned int channels)
+{
+	mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), channels);
+}
+
+static unsigned int mv643xx_eth_port_disable_tx(unsigned int port_num)
+{
+	u32 channels;
+
+	/* Stop Tx port activity. Check port Tx activity. */
+	channels = mv_read(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num))
+							& 0xFF;
+	if (channels) {
+		/* Issue stop command for active channels only */
+		mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num),
+							(channels << 8));
+
+		/* Wait for all Tx activity to terminate. */
+		/* Check port cause register that all Tx queues are stopped */
+		while (mv_read(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num))
+							& 0xFF)
+			udelay(PHY_WAIT_MICRO_SECONDS);
+
+		/* Wait for Tx FIFO to empty */
+		while (mv_read(MV643XX_ETH_PORT_STATUS_REG(port_num)) &
+							ETH_PORT_TX_FIFO_EMPTY)
+			udelay(PHY_WAIT_MICRO_SECONDS);
+	}
+
+	return channels;
+}
+
+static unsigned int mv643xx_eth_port_disable_rx(unsigned int port_num)
+{
+	u32 channels;
+
+	/* Stop Rx port activity. Check port Rx activity. */
+	channels = mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num)
+							& 0xFF);
+	if (channels) {
+		/* Issue stop command for active channels only */
+		mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num),
+							(channels << 8));
+
+		/* Wait for all Rx activity to terminate. */
+		/* Check port cause register that all Rx queues are stopped */
+		while (mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num))
+							& 0xFF)
+			udelay(PHY_WAIT_MICRO_SECONDS);
+	}
+
+	return channels;
 }
 
 /*
@@ -2413,70 +2537,21 @@
 {
 	unsigned int reg_data;
 
-	/* Stop Tx port activity. Check port Tx activity. */
-	reg_data = mv_read(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num));
-
-	if (reg_data & 0xFF) {
-		/* Issue stop command for active channels only */
-		mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num),
-							(reg_data << 8));
-
-		/* Wait for all Tx activity to terminate. */
-		/* Check port cause register that all Tx queues are stopped */
-		while (mv_read(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num))
-									& 0xFF)
-			udelay(10);
-	}
-
-	/* Stop Rx port activity. Check port Rx activity. */
-	reg_data = mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num));
-
-	if (reg_data & 0xFF) {
-		/* Issue stop command for active channels only */
-		mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num),
-							(reg_data << 8));
-
-		/* Wait for all Rx activity to terminate. */
-		/* Check port cause register that all Rx queues are stopped */
-		while (mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num))
-									& 0xFF)
-			udelay(10);
-	}
+	mv643xx_eth_port_disable_tx(port_num);
+	mv643xx_eth_port_disable_rx(port_num);
 
 	/* Clear all MIB counters */
 	eth_clear_mib_counters(port_num);
 
 	/* Reset the Enable bit in the Configuration Register */
 	reg_data = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num));
-	reg_data &= ~MV643XX_ETH_SERIAL_PORT_ENABLE;
+	reg_data &= ~(MV643XX_ETH_SERIAL_PORT_ENABLE		|
+			MV643XX_ETH_DO_NOT_FORCE_LINK_FAIL	|
+			MV643XX_ETH_FORCE_LINK_PASS);
 	mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), reg_data);
 }
 
 
-static int eth_port_autoneg_supported(unsigned int eth_port_num)
-{
-	unsigned int phy_reg_data0;
-
-	eth_port_read_smi_reg(eth_port_num, 0, &phy_reg_data0);
-
-	return phy_reg_data0 & 0x1000;
-}
-
-static int eth_port_link_is_up(unsigned int eth_port_num)
-{
-	unsigned int phy_reg_data1;
-
-	eth_port_read_smi_reg(eth_port_num, 1, &phy_reg_data1);
-
-	if (eth_port_autoneg_supported(eth_port_num)) {
-		if (phy_reg_data1 & 0x20)	/* auto-neg complete */
-			return 1;
-	} else if (phy_reg_data1 & 0x4)		/* link up */
-		return 1;
-
-	return 0;
-}
-
 /*
  * eth_port_read_smi_reg - Read PHY registers
  *
@@ -2582,6 +2657,24 @@
 }
 
 /*
+ * Wrappers for MII support library.
+ */
+static int mv643xx_mdio_read(struct net_device *dev, int phy_id, int location)
+{
+	int val;
+	struct mv643xx_private *mp = netdev_priv(dev);
+
+	eth_port_read_smi_reg(mp->port_num, location, &val);
+	return val;
+}
+
+static void mv643xx_mdio_write(struct net_device *dev, int phy_id, int location, int val)
+{
+	struct mv643xx_private *mp = netdev_priv(dev);
+	eth_port_write_smi_reg(mp->port_num, location, val);
+}
+
+/*
  * eth_port_send - Send an Ethernet packet
  *
  * DESCRIPTION:
@@ -2635,8 +2728,8 @@
 		return ETH_ERROR;
 	}
 
-	mp->tx_ring_skbs++;
-	BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size);
+	mp->tx_desc_count++;
+	BUG_ON(mp->tx_desc_count > mp->tx_ring_size);
 
 	/* Get the Tx Desc ring indexes */
 	tx_desc_curr = mp->tx_curr_desc_q;
@@ -2670,7 +2763,7 @@
 		first_descriptor->cmd_sts = mp->tx_first_command;
 
 		wmb();
-		ETH_ENABLE_TX_QUEUE(mp->port_num);
+		mv643xx_eth_port_enable_tx(mp->port_num, mp->port_tx_queue_command);
 
 		/*
 		 * Finish Tx packet. Update first desc in case of Tx resource
@@ -2704,8 +2797,8 @@
 	if (mp->tx_resource_err)
 		return ETH_QUEUE_FULL;
 
-	mp->tx_ring_skbs++;
-	BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size);
+	mp->tx_desc_count++;
+	BUG_ON(mp->tx_desc_count > mp->tx_ring_size);
 
 	/* Get the Tx Desc ring indexes */
 	tx_desc_curr = mp->tx_curr_desc_q;
@@ -2723,7 +2816,7 @@
 			ETH_BUFFER_OWNED_BY_DMA | ETH_TX_ENABLE_INTERRUPT;
 
 	wmb();
-	ETH_ENABLE_TX_QUEUE(mp->port_num);
+	mv643xx_eth_port_enable_tx(mp->port_num, mp->port_tx_queue_command);
 
 	/* Finish Tx packet. Update first desc in case of Tx resource error */
 	tx_desc_curr = (tx_desc_curr + 1) % mp->tx_ring_size;
@@ -2819,8 +2912,8 @@
 	/* Any Tx return cancels the Tx resource error status */
 	mp->tx_resource_err = 0;
 
-	BUG_ON(mp->tx_ring_skbs == 0);
-	mp->tx_ring_skbs--;
+	BUG_ON(mp->tx_desc_count == 0);
+	mp->tx_desc_count--;
 
 out:
 	spin_unlock_irqrestore(&mp->lock, flags);
@@ -3017,111 +3110,6 @@
 #define MV643XX_STATS_LEN	\
 	sizeof(mv643xx_gstrings_stats) / sizeof(struct mv643xx_stats)
 
-static int
-mv643xx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
-{
-	struct mv643xx_private *mp = netdev->priv;
-	int port_num = mp->port_num;
-	int autoneg = eth_port_autoneg_supported(port_num);
-	int mode_10_bit;
-	int auto_duplex;
-	int half_duplex = 0;
-	int full_duplex = 0;
-	int auto_speed;
-	int speed_10 = 0;
-	int speed_100 = 0;
-	int speed_1000 = 0;
-
-	u32 pcs = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num));
-	u32 psr = mv_read(MV643XX_ETH_PORT_STATUS_REG(port_num));
-
-	mode_10_bit = psr & MV643XX_ETH_PORT_STATUS_MODE_10_BIT;
-
-	if (mode_10_bit) {
-		ecmd->supported = SUPPORTED_10baseT_Half;
-	} else {
-		ecmd->supported = (SUPPORTED_10baseT_Half		|
-				   SUPPORTED_10baseT_Full		|
-				   SUPPORTED_100baseT_Half		|
-				   SUPPORTED_100baseT_Full		|
-				   SUPPORTED_1000baseT_Full		|
-				   (autoneg ? SUPPORTED_Autoneg : 0)	|
-				   SUPPORTED_TP);
-
-		auto_duplex = !(pcs & MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLX);
-		auto_speed = !(pcs & MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII);
-
-		ecmd->advertising = ADVERTISED_TP;
-
-		if (autoneg) {
-			ecmd->advertising |= ADVERTISED_Autoneg;
-
-			if (auto_duplex) {
-				half_duplex = 1;
-				full_duplex = 1;
-			} else {
-				if (pcs & MV643XX_ETH_SET_FULL_DUPLEX_MODE)
-					full_duplex = 1;
-				else
-					half_duplex = 1;
-			}
-
-			if (auto_speed) {
-				speed_10 = 1;
-				speed_100 = 1;
-				speed_1000 = 1;
-			} else {
-				if (pcs & MV643XX_ETH_SET_GMII_SPEED_TO_1000)
-					speed_1000 = 1;
-				else if (pcs & MV643XX_ETH_SET_MII_SPEED_TO_100)
-					speed_100 = 1;
-				else
-					speed_10 = 1;
-			}
-
-			if (speed_10 & half_duplex)
-				ecmd->advertising |= ADVERTISED_10baseT_Half;
-			if (speed_10 & full_duplex)
-				ecmd->advertising |= ADVERTISED_10baseT_Full;
-			if (speed_100 & half_duplex)
-				ecmd->advertising |= ADVERTISED_100baseT_Half;
-			if (speed_100 & full_duplex)
-				ecmd->advertising |= ADVERTISED_100baseT_Full;
-			if (speed_1000)
-				ecmd->advertising |= ADVERTISED_1000baseT_Full;
-		}
-	}
-
-	ecmd->port = PORT_TP;
-	ecmd->phy_address = ethernet_phy_get(port_num);
-
-	ecmd->transceiver = XCVR_EXTERNAL;
-
-	if (netif_carrier_ok(netdev)) {
-		if (mode_10_bit)
-			ecmd->speed = SPEED_10;
-		else {
-			if (psr & MV643XX_ETH_PORT_STATUS_GMII_1000)
-				ecmd->speed = SPEED_1000;
-			else if (psr & MV643XX_ETH_PORT_STATUS_MII_100)
-				ecmd->speed = SPEED_100;
-			else
-				ecmd->speed = SPEED_10;
-		}
-
-		if (psr & MV643XX_ETH_PORT_STATUS_FULL_DUPLEX)
-			ecmd->duplex = DUPLEX_FULL;
-		else
-			ecmd->duplex = DUPLEX_HALF;
-	} else {
-		ecmd->speed = -1;
-		ecmd->duplex = -1;
-	}
-
-	ecmd->autoneg = autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;
-	return 0;
-}
-
 static void mv643xx_get_drvinfo(struct net_device *netdev,
 				struct ethtool_drvinfo *drvinfo)
 {
@@ -3168,15 +3156,41 @@
 	}
 }
 
+static u32 mv643xx_eth_get_link(struct net_device *dev)
+{
+	struct mv643xx_private *mp = netdev_priv(dev);
+
+	return mii_link_ok(&mp->mii);
+}
+
+static int mv643xx_eth_nway_restart(struct net_device *dev)
+{
+	struct mv643xx_private *mp = netdev_priv(dev);
+
+	return mii_nway_restart(&mp->mii);
+}
+
+static int mv643xx_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct mv643xx_private *mp = netdev_priv(dev);
+
+	return generic_mii_ioctl(&mp->mii, if_mii(ifr), cmd, NULL);
+}
+
 static struct ethtool_ops mv643xx_ethtool_ops = {
 	.get_settings           = mv643xx_get_settings,
+	.set_settings           = mv643xx_set_settings,
 	.get_drvinfo            = mv643xx_get_drvinfo,
-	.get_link               = ethtool_op_get_link,
+	.get_link               = mv643xx_eth_get_link,
 	.get_sg			= ethtool_op_get_sg,
 	.set_sg			= ethtool_op_set_sg,
 	.get_strings            = mv643xx_get_strings,
 	.get_stats_count        = mv643xx_get_stats_count,
 	.get_ethtool_stats      = mv643xx_get_ethtool_stats,
+	.get_strings            = mv643xx_get_strings,
+	.get_stats_count        = mv643xx_get_stats_count,
+	.get_ethtool_stats      = mv643xx_get_ethtool_stats,
+	.nway_reset		= mv643xx_eth_nway_restart,
 };
 
 /************* End ethtool support *************************/
diff -urN oldtree/drivers/net/mv643xx_eth.h newtree/drivers/net/mv643xx_eth.h
--- oldtree/drivers/net/mv643xx_eth.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/mv643xx_eth.h	2006-02-21 15:58:15.389806952 +0000
@@ -5,6 +5,7 @@
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
+#include <linux/mii.h>
 
 #include <linux/mv643xx.h>
 
@@ -89,10 +90,6 @@
  *
  */
 
-/* MAC accepet/reject macros */
-#define ACCEPT_MAC_ADDR				0
-#define REJECT_MAC_ADDR				1
-
 /* Buffer offset from buffer pointer */
 #define RX_BUF_OFFSET				0x2
 
@@ -324,11 +321,6 @@
 
 struct mv643xx_private {
 	int port_num;			/* User Ethernet port number	*/
-	u8 port_mac_addr[6];		/* User defined port MAC address.*/
-	u32 port_config;		/* User port configuration value*/
-	u32 port_config_extend;		/* User port config extend value*/
-	u32 port_sdma_config;		/* User port SDMA config value	*/
-	u32 port_serial_control;	/* User port serial control value */
 	u32 port_tx_queue_command;	/* Port active Tx queues summary*/
 	u32 port_rx_queue_command;	/* Port active Rx queues summary*/
 
@@ -376,12 +368,12 @@
 	spinlock_t lock;
 	/* Size of Tx Ring per queue */
 	unsigned int tx_ring_size;
-	/* Ammont of SKBs outstanding on Tx queue */
-	unsigned int tx_ring_skbs;
+	/* Number of tx descriptors in use */
+	unsigned int tx_desc_count;
 	/* Size of Rx Ring per queue */
 	unsigned int rx_ring_size;
-	/* Ammount of SKBs allocated to Rx Ring per queue */
-	unsigned int rx_ring_skbs;
+	/* Number of rx descriptors in use */
+	unsigned int rx_desc_count;
 
 	/*
 	 * rx_task used to fill RX ring out of bottom half context
@@ -398,6 +390,7 @@
 
 	u32 rx_int_coal;
 	u32 tx_int_coal;
+	struct mii_if_info mii;
 };
 
 /* ethernet.h API list */
@@ -405,7 +398,7 @@
 /* Port operation control routines */
 static void eth_port_init(struct mv643xx_private *mp);
 static void eth_port_reset(unsigned int eth_port_num);
-static void eth_port_start(struct mv643xx_private *mp);
+static void eth_port_start(struct net_device *dev);
 
 /* Port MAC address routines */
 static void eth_port_uc_addr_set(unsigned int eth_port_num,
diff -urN oldtree/drivers/net/ne-h8300.c newtree/drivers/net/ne-h8300.c
--- oldtree/drivers/net/ne-h8300.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/ne-h8300.c	2006-02-21 15:58:15.390806800 +0000
@@ -27,6 +27,7 @@
 #include <linux/delay.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/jiffies.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -365,7 +366,7 @@
 
 	/* This check _should_not_ be necessary, omit eventually. */
 	while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
-		if (jiffies - reset_start_time > 2*HZ/100) {
+		if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
 			printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n", dev->name);
 			break;
 		}
@@ -580,7 +581,7 @@
 #endif
 
 	while ((inb_p(NE_BASE + EN0_ISR) & ENISR_RDC) == 0)
-		if (jiffies - dma_start > 2*HZ/100) {		/* 20ms */
+		if (time_after(jiffies, dma_start + 2*HZ/100)) {		/* 20ms */
 			printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name);
 			ne_reset_8390(dev);
 			NS8390_init(dev,1);
diff -urN oldtree/drivers/net/ne.c newtree/drivers/net/ne.c
--- oldtree/drivers/net/ne.c	2006-02-19 11:41:03.298841600 +0000
+++ newtree/drivers/net/ne.c	2006-02-21 15:58:15.391806648 +0000
@@ -50,6 +50,7 @@
 #include <linux/delay.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/jiffies.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -341,7 +342,7 @@
 		outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);
 
 		while ((inb_p(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
-		if (jiffies - reset_start_time > 2*HZ/100) {
+		if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
 			if (bad_card) {
 				printk(" (warning: no reset ack)");
 				break;
@@ -580,7 +581,7 @@
 
 	/* This check _should_not_ be necessary, omit eventually. */
 	while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
-		if (jiffies - reset_start_time > 2*HZ/100) {
+		if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
 			printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n", dev->name);
 			break;
 		}
@@ -787,7 +788,7 @@
 #endif
 
 	while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
-		if (jiffies - dma_start > 2*HZ/100) {		/* 20ms */
+		if (time_after(jiffies, dma_start + 2*HZ/100)) {		/* 20ms */
 			printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name);
 			ne_reset_8390(dev);
 			NS8390_init(dev,1);
diff -urN oldtree/drivers/net/ne2.c newtree/drivers/net/ne2.c
--- oldtree/drivers/net/ne2.c	2006-02-19 11:41:03.299841448 +0000
+++ newtree/drivers/net/ne2.c	2006-02-21 15:58:15.392806496 +0000
@@ -75,6 +75,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/bitops.h>
+#include <linux/jiffies.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -395,7 +396,7 @@
 		outb(inb(base_addr + NE_RESET), base_addr + NE_RESET);
 
 		while ((inb_p(base_addr + EN0_ISR) & ENISR_RESET) == 0)
-			if (jiffies - reset_start_time > 2*HZ/100) {
+			if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
 				printk(" not found (no reset ack).\n");
 				retval = -ENODEV;
 				goto out;
@@ -548,7 +549,7 @@
 
 	/* This check _should_not_ be necessary, omit eventually. */
 	while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
-		if (jiffies - reset_start_time > 2*HZ/100) {
+		if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
 			printk("%s: ne_reset_8390() did not complete.\n", 
 					dev->name);
 			break;
@@ -749,7 +750,7 @@
 #endif
 
 	while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
-		if (jiffies - dma_start > 2*HZ/100) {		/* 20ms */
+		if (time_after(jiffies, dma_start + 2*HZ/100)) {		/* 20ms */
 			printk("%s: timeout waiting for Tx RDC.\n", dev->name);
 			ne_reset_8390(dev);
 			NS8390_init(dev,1);
diff -urN oldtree/drivers/net/ns83820.c newtree/drivers/net/ns83820.c
--- oldtree/drivers/net/ns83820.c	2006-02-19 11:41:03.300841296 +0000
+++ newtree/drivers/net/ns83820.c	2006-02-21 15:58:15.404804672 +0000
@@ -116,6 +116,7 @@
 #include <linux/timer.h>
 #include <linux/if_vlan.h>
 #include <linux/rtnetlink.h>
+#include <linux/jiffies.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -1607,7 +1608,7 @@
 {
 	struct ns83820 *dev = PRIV(ndev);
 	int timed_out = 0;
-	long start;
+	unsigned long start;
 	u32 status;
 	int loops = 0;
 
@@ -1625,7 +1626,7 @@
 			break;
 		if (status & fail)
 			break;
-		if ((jiffies - start) >= HZ) {
+		if (time_after_eq(jiffies, start + HZ)) {
 			timed_out = 1;
 			break;
 		}
diff -urN oldtree/drivers/net/oaknet.c newtree/drivers/net/oaknet.c
--- oldtree/drivers/net/oaknet.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/oaknet.c	2006-02-21 15:58:15.405804520 +0000
@@ -20,6 +20,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
+#include <linux/jiffies.h>
 
 #include <asm/board.h>
 #include <asm/io.h>
@@ -606,7 +607,7 @@
 #endif
 
 	while ((ei_ibp(base + EN0_ISR) & ENISR_RDC) == 0) {
-		if (jiffies - start > OAKNET_WAIT) {
+		if (time_after(jiffies, start + OAKNET_WAIT)) {
 			printk("%s: timeout waiting for Tx RDC.\n", dev->name);
 			oaknet_reset_8390(dev);
 			NS8390_init(dev, TRUE);
diff -urN oldtree/drivers/net/pcmcia/3c589_cs.c newtree/drivers/net/pcmcia/3c589_cs.c
--- oldtree/drivers/net/pcmcia/3c589_cs.c	2006-02-19 11:41:03.305840536 +0000
+++ newtree/drivers/net/pcmcia/3c589_cs.c	2006-02-21 15:58:15.413803304 +0000
@@ -39,6 +39,7 @@
 #include <linux/if_arp.h>
 #include <linux/ioport.h>
 #include <linux/bitops.h>
+#include <linux/jiffies.h>
 
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
@@ -796,7 +797,7 @@
     media = inw(ioaddr+WN4_MEDIA) & 0xc810;
 
     /* Ignore collisions unless we've had no irq's recently */
-    if (jiffies - lp->last_irq < HZ) {
+    if (time_before(jiffies, lp->last_irq + HZ)) {
 	media &= ~0x0010;
     } else {
 	/* Try harder to detect carrier errors */
diff -urN oldtree/drivers/net/ppp_async.c newtree/drivers/net/ppp_async.c
--- oldtree/drivers/net/ppp_async.c	2006-02-19 11:41:03.319838408 +0000
+++ newtree/drivers/net/ppp_async.c	2006-02-21 15:58:15.414803152 +0000
@@ -30,6 +30,7 @@
 #include <linux/ppp_channel.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
+#include <linux/jiffies.h>
 #include <asm/uaccess.h>
 #include <asm/string.h>
 
@@ -570,7 +571,7 @@
 		 * character if necessary.
 		 */
 		if (islcp || flag_time == 0
-		    || jiffies - ap->last_xmit >= flag_time)
+		    || time_after_eq(jiffies, ap->last_xmit + flag_time))
 			*buf++ = PPP_FLAG;
 		ap->last_xmit = jiffies;
 		fcs = PPP_INITFCS;
diff -urN oldtree/drivers/net/ppp_generic.c newtree/drivers/net/ppp_generic.c
--- oldtree/drivers/net/ppp_generic.c	2006-02-19 11:41:03.321838104 +0000
+++ newtree/drivers/net/ppp_generic.c	2006-02-21 15:58:23.805527568 +0000
@@ -46,6 +46,7 @@
 #include <linux/rwsem.h>
 #include <linux/stddef.h>
 #include <linux/device.h>
+#include <linux/mutex.h>
 #include <net/slhc_vj.h>
 #include <asm/atomic.h>
 
@@ -198,11 +199,11 @@
 static void cardmap_destroy(struct cardmap **map);
 
 /*
- * all_ppp_sem protects the all_ppp_units mapping.
+ * all_ppp_mutex protects the all_ppp_units mapping.
  * It also ensures that finding a ppp unit in the all_ppp_units map
  * and updating its file.refcnt field is atomic.
  */
-static DECLARE_MUTEX(all_ppp_sem);
+static DEFINE_MUTEX(all_ppp_mutex);
 static struct cardmap *all_ppp_units;
 static atomic_t ppp_unit_count = ATOMIC_INIT(0);
 
@@ -804,7 +805,7 @@
 		/* Attach to an existing ppp unit */
 		if (get_user(unit, p))
 			break;
-		down(&all_ppp_sem);
+		mutex_lock(&all_ppp_mutex);
 		err = -ENXIO;
 		ppp = ppp_find_unit(unit);
 		if (ppp != 0) {
@@ -812,7 +813,7 @@
 			file->private_data = &ppp->file;
 			err = 0;
 		}
-		up(&all_ppp_sem);
+		mutex_unlock(&all_ppp_mutex);
 		break;
 
 	case PPPIOCATTCHAN:
@@ -2446,7 +2447,7 @@
 	dev->do_ioctl = ppp_net_ioctl;
 
 	ret = -EEXIST;
-	down(&all_ppp_sem);
+	mutex_lock(&all_ppp_mutex);
 	if (unit < 0)
 		unit = cardmap_find_first_free(all_ppp_units);
 	else if (cardmap_get(all_ppp_units, unit) != NULL)
@@ -2465,12 +2466,12 @@
 
 	atomic_inc(&ppp_unit_count);
 	cardmap_set(&all_ppp_units, unit, ppp);
-	up(&all_ppp_sem);
+	mutex_unlock(&all_ppp_mutex);
 	*retp = 0;
 	return ppp;
 
 out2:
-	up(&all_ppp_sem);
+	mutex_unlock(&all_ppp_mutex);
 	free_netdev(dev);
 out1:
 	kfree(ppp);
@@ -2500,7 +2501,7 @@
 {
 	struct net_device *dev;
 
-	down(&all_ppp_sem);
+	mutex_lock(&all_ppp_mutex);
 	ppp_lock(ppp);
 	dev = ppp->dev;
 	ppp->dev = NULL;
@@ -2514,7 +2515,7 @@
 	ppp->file.dead = 1;
 	ppp->owner = NULL;
 	wake_up_interruptible(&ppp->file.rwait);
-	up(&all_ppp_sem);
+	mutex_unlock(&all_ppp_mutex);
 }
 
 /*
@@ -2556,7 +2557,7 @@
 
 /*
  * Locate an existing ppp unit.
- * The caller should have locked the all_ppp_sem.
+ * The caller should have locked the all_ppp_mutex.
  */
 static struct ppp *
 ppp_find_unit(int unit)
@@ -2601,7 +2602,7 @@
 	int ret = -ENXIO;
 	int hdrlen;
 
-	down(&all_ppp_sem);
+	mutex_lock(&all_ppp_mutex);
 	ppp = ppp_find_unit(unit);
 	if (ppp == 0)
 		goto out;
@@ -2626,7 +2627,7 @@
  outl:
 	write_unlock_bh(&pch->upl);
  out:
-	up(&all_ppp_sem);
+	mutex_unlock(&all_ppp_mutex);
 	return ret;
 }
 
diff -urN oldtree/drivers/net/s2io.c newtree/drivers/net/s2io.c
--- oldtree/drivers/net/s2io.c	2006-02-19 11:41:03.328837040 +0000
+++ newtree/drivers/net/s2io.c	2006-02-21 15:58:15.431800568 +0000
@@ -57,23 +57,27 @@
 #include <linux/ethtool.h>
 #include <linux/workqueue.h>
 #include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <net/tcp.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
+#include <asm/div64.h>
 
 /* local include */
 #include "s2io.h"
 #include "s2io-regs.h"
 
-#define DRV_VERSION "Version 2.0.9.4"
+#define DRV_VERSION "2.0.11.2"
 
 /* S2io Driver name & version. */
 static char s2io_driver_name[] = "Neterion";
 static char s2io_driver_version[] = DRV_VERSION;
 
-int rxd_size[4] = {32,48,48,64};
-int rxd_count[4] = {127,85,85,63};
+static int rxd_size[4] = {32,48,48,64};
+static int rxd_count[4] = {127,85,85,63};
 
 static inline int RXD_IS_UP2DT(RxD_t *rxdp)
 {
@@ -168,6 +172,11 @@
 	{"\n DRIVER STATISTICS"},
 	{"single_bit_ecc_errs"},
 	{"double_bit_ecc_errs"},
+	("lro_aggregated_pkts"),
+	("lro_flush_both_count"),
+	("lro_out_of_sequence_pkts"),
+	("lro_flush_due_to_max_pkts"),
+	("lro_avg_aggr_pkts"),
 };
 
 #define S2IO_STAT_LEN sizeof(ethtool_stats_keys)/ ETH_GSTRING_LEN
@@ -317,6 +326,12 @@
 static unsigned int rxsync_frequency = 3;
 /* Interrupt type. Values can be 0(INTA), 1(MSI), 2(MSI_X) */
 static unsigned int intr_type = 0;
+/* Large receive offload feature */
+static unsigned int lro = 0;
+/* Max pkts to be aggregated by LRO at one time. If not specified,
+ * aggregation happens until we hit max IP pkt size(64K)
+ */
+static unsigned int lro_max_pkts = 0xFFFF;
 
 /*
  * S2IO device table.
@@ -1476,6 +1491,19 @@
 	writel((u32) (val64 >> 32), (add + 4));
 	val64 = readq(&bar0->mac_cfg);
 
+	/* Enable FCS stripping by adapter */
+	add = &bar0->mac_cfg;
+	val64 = readq(&bar0->mac_cfg);
+	val64 |= MAC_CFG_RMAC_STRIP_FCS;
+	if (nic->device_type == XFRAME_II_DEVICE)
+		writeq(val64, &bar0->mac_cfg);
+	else {
+		writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
+		writel((u32) (val64), add);
+		writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
+		writel((u32) (val64 >> 32), (add + 4));
+	}
+
 	/*
 	 * Set the time value to be inserted in the pause frame
 	 * generated by xena.
@@ -2127,7 +2155,7 @@
 	}
 }
 
-int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb)
+static int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb)
 {
 	struct net_device *dev = nic->dev;
 	struct sk_buff *frag_list;
@@ -2569,6 +2597,8 @@
 #ifndef CONFIG_S2IO_NAPI
 	int pkt_cnt = 0;
 #endif
+	int i;
+
 	spin_lock(&nic->rx_lock);
 	if (atomic_read(&nic->card_state) == CARD_DOWN) {
 		DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n",
@@ -2661,6 +2691,18 @@
 			break;
 #endif
 	}
+	if (nic->lro) {
+		/* Clear all LRO sessions before exiting */
+		for (i=0; i<MAX_LRO_SESSIONS; i++) {
+			lro_t *lro = &nic->lro0_n[i];
+			if (lro->in_use) {
+				update_L3L4_header(nic, lro);
+				queue_rx_frame(lro->parent);
+				clear_lro_session(lro);
+			}
+		}
+	}
+
 	spin_unlock(&nic->rx_lock);
 }
 
@@ -2852,7 +2894,7 @@
  *  void.
  */
 
-void s2io_reset(nic_t * sp)
+static void s2io_reset(nic_t * sp)
 {
 	XENA_dev_config_t __iomem *bar0 = sp->bar0;
 	u64 val64;
@@ -2940,7 +2982,7 @@
  *  SUCCESS on success and FAILURE on failure.
  */
 
-int s2io_set_swapper(nic_t * sp)
+static int s2io_set_swapper(nic_t * sp)
 {
 	struct net_device *dev = sp->dev;
 	XENA_dev_config_t __iomem *bar0 = sp->bar0;
@@ -3089,7 +3131,7 @@
 	return ret;
 }
 
-void restore_xmsi_data(nic_t *nic)
+static void restore_xmsi_data(nic_t *nic)
 {
 	XENA_dev_config_t __iomem *bar0 = nic->bar0;
 	u64 val64;
@@ -3180,7 +3222,7 @@
 	return 0;
 }
 
-int s2io_enable_msi_x(nic_t *nic)
+static int s2io_enable_msi_x(nic_t *nic)
 {
 	XENA_dev_config_t __iomem *bar0 = nic->bar0;
 	u64 tx_mat, rx_mat;
@@ -3668,23 +3710,32 @@
 	 * else schedule a tasklet to reallocate the buffers.
 	 */
 	for (i = 0; i < config->rx_ring_num; i++) {
-		int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
-		int level = rx_buffer_level(sp, rxb_size, i);
-
-		if ((level == PANIC) && (!TASKLET_IN_USE)) {
-			DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", dev->name);
-			DBG_PRINT(INTR_DBG, "PANIC levels\n");
-			if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
-				DBG_PRINT(ERR_DBG, "%s:Out of memory",
-					  dev->name);
-				DBG_PRINT(ERR_DBG, " in ISR!!\n");
+		if (!sp->lro) {
+			int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
+			int level = rx_buffer_level(sp, rxb_size, i);
+
+			if ((level == PANIC) && (!TASKLET_IN_USE)) {
+				DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", 
+							dev->name);
+				DBG_PRINT(INTR_DBG, "PANIC levels\n");
+				if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
+					DBG_PRINT(ERR_DBG, "%s:Out of memory",
+						  dev->name);
+					DBG_PRINT(ERR_DBG, " in ISR!!\n");
+					clear_bit(0, (&sp->tasklet_status));
+					atomic_dec(&sp->isr_cnt);
+					return IRQ_HANDLED;
+				}
 				clear_bit(0, (&sp->tasklet_status));
-				atomic_dec(&sp->isr_cnt);
-				return IRQ_HANDLED;
+			} else if (level == LOW) {
+				tasklet_schedule(&sp->task);
 			}
-			clear_bit(0, (&sp->tasklet_status));
-		} else if (level == LOW) {
-			tasklet_schedule(&sp->task);
+		}
+		else if (fill_rx_buffers(sp, i) == -ENOMEM) {
+				DBG_PRINT(ERR_DBG, "%s:Out of memory",
+							dev->name);
+				DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
+				break;
 		}
 	}
 
@@ -3697,29 +3748,37 @@
 {
 	ring_info_t *ring = (ring_info_t *)dev_id;
 	nic_t *sp = ring->nic;
+	struct net_device *dev = (struct net_device *) dev_id;
 	int rxb_size, level, rng_n;
 
 	atomic_inc(&sp->isr_cnt);
 	rx_intr_handler(ring);
 
 	rng_n = ring->ring_no;
-	rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]);
-	level = rx_buffer_level(sp, rxb_size, rng_n);
+	if (!sp->lro) {
+		rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]);
+		level = rx_buffer_level(sp, rxb_size, rng_n);
 
-	if ((level == PANIC) && (!TASKLET_IN_USE)) {
-		int ret;
-		DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
-		DBG_PRINT(INTR_DBG, "PANIC levels\n");
-		if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
-			DBG_PRINT(ERR_DBG, "Out of memory in %s",
-				  __FUNCTION__);
+		if ((level == PANIC) && (!TASKLET_IN_USE)) {
+			int ret;
+			DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
+			DBG_PRINT(INTR_DBG, "PANIC levels\n");
+			if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
+				DBG_PRINT(ERR_DBG, "Out of memory in %s",
+					  __FUNCTION__);
+				clear_bit(0, (&sp->tasklet_status));
+				return IRQ_HANDLED;
+			}
 			clear_bit(0, (&sp->tasklet_status));
-			return IRQ_HANDLED;
+		} else if (level == LOW) {
+			tasklet_schedule(&sp->task);
 		}
-		clear_bit(0, (&sp->tasklet_status));
-	} else if (level == LOW) {
-		tasklet_schedule(&sp->task);
 	}
+	else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
+			DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
+			DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
+	}
+
 	atomic_dec(&sp->isr_cnt);
 
 	return IRQ_HANDLED;
@@ -3875,24 +3934,33 @@
 	 */
 #ifndef CONFIG_S2IO_NAPI
 	for (i = 0; i < config->rx_ring_num; i++) {
-		int ret;
-		int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
-		int level = rx_buffer_level(sp, rxb_size, i);
-
-		if ((level == PANIC) && (!TASKLET_IN_USE)) {
-			DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", dev->name);
-			DBG_PRINT(INTR_DBG, "PANIC levels\n");
-			if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
-				DBG_PRINT(ERR_DBG, "%s:Out of memory",
-					  dev->name);
-				DBG_PRINT(ERR_DBG, " in ISR!!\n");
+		if (!sp->lro) {
+			int ret;
+			int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
+			int level = rx_buffer_level(sp, rxb_size, i);
+
+			if ((level == PANIC) && (!TASKLET_IN_USE)) {
+				DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", 
+							dev->name);
+				DBG_PRINT(INTR_DBG, "PANIC levels\n");
+				if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
+					DBG_PRINT(ERR_DBG, "%s:Out of memory",
+						  dev->name);
+					DBG_PRINT(ERR_DBG, " in ISR!!\n");
+					clear_bit(0, (&sp->tasklet_status));
+					atomic_dec(&sp->isr_cnt);
+					return IRQ_HANDLED;
+				}
 				clear_bit(0, (&sp->tasklet_status));
-				atomic_dec(&sp->isr_cnt);
-				return IRQ_HANDLED;
+			} else if (level == LOW) {
+				tasklet_schedule(&sp->task);
 			}
-			clear_bit(0, (&sp->tasklet_status));
-		} else if (level == LOW) {
-			tasklet_schedule(&sp->task);
+		}
+		else if (fill_rx_buffers(sp, i) == -ENOMEM) {
+				DBG_PRINT(ERR_DBG, "%s:Out of memory",
+							dev->name);
+				DBG_PRINT(ERR_DBG, " in Rx intr!!\n");
+				break;
 		}
 	}
 #endif
@@ -4128,7 +4196,7 @@
  *  as defined in errno.h file on failure.
  */
 
-int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
+static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
 {
 	nic_t *sp = dev->priv;
 	XENA_dev_config_t __iomem *bar0 = sp->bar0;
@@ -5043,6 +5111,7 @@
 	int i = 0;
 	nic_t *sp = dev->priv;
 	StatInfo_t *stat_info = sp->mac_control.stats_info;
+	u64 tmp;
 
 	s2io_updt_stats(sp);
 	tmp_stats[i++] =
@@ -5134,6 +5203,16 @@
 	tmp_stats[i++] = 0;
 	tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs;
 	tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs;
+	tmp_stats[i++] = stat_info->sw_stat.clubbed_frms_cnt;
+	tmp_stats[i++] = stat_info->sw_stat.sending_both;
+	tmp_stats[i++] = stat_info->sw_stat.outof_sequence_pkts;
+	tmp_stats[i++] = stat_info->sw_stat.flush_max_pkts;
+	tmp = 0;
+	if (stat_info->sw_stat.num_aggregations) {
+		tmp = stat_info->sw_stat.sum_avg_pkts_aggregated;
+		do_div(tmp, stat_info->sw_stat.num_aggregations);
+	}
+	tmp_stats[i++] = tmp;
 }
 
 static int s2io_ethtool_get_regs_len(struct net_device *dev)
@@ -5515,6 +5594,14 @@
 	/* Setting its receive mode */
 	s2io_set_multicast(dev);
 
+	if (sp->lro) {
+		/* Initialize max aggregatable pkts based on MTU */
+		sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu;
+		/* Check if we can use(if specified) user provided value */
+		if (lro_max_pkts < sp->lro_max_aggr_per_sess)
+			sp->lro_max_aggr_per_sess = lro_max_pkts;
+	}
+
 	/* Enable tasklet for the device */
 	tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
 
@@ -5607,6 +5694,7 @@
 		((unsigned long) rxdp->Host_Control);
 	int ring_no = ring_data->ring_no;
 	u16 l3_csum, l4_csum;
+	lro_t *lro;
 
 	skb->dev = dev;
 	if (rxdp->Control_1 & RXD_T_CODE) {
@@ -5655,7 +5743,8 @@
 			skb_put(skb, buf2_len);
 	}
 
-	if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) &&
+	if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!sp->lro) ||
+	    (sp->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
 	    (sp->rx_csum)) {
 		l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
 		l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1);
@@ -5666,6 +5755,54 @@
 			 * a flag in the RxD.
 			 */
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
+			if (sp->lro) {
+				u32 tcp_len;
+				u8 *tcp;
+				int ret = 0;
+
+				ret = s2io_club_tcp_session(skb->data, &tcp,
+						&tcp_len, &lro, rxdp, sp);
+				switch (ret) {
+					case 3: /* Begin anew */
+						lro->parent = skb;
+						goto aggregate;
+					case 1: /* Aggregate */
+					{
+						lro_append_pkt(sp, lro,
+							skb, tcp_len);
+						goto aggregate;
+					}
+					case 4: /* Flush session */
+					{
+						lro_append_pkt(sp, lro,
+							skb, tcp_len);
+						queue_rx_frame(lro->parent);
+						clear_lro_session(lro);
+						sp->mac_control.stats_info->
+						    sw_stat.flush_max_pkts++;
+						goto aggregate;
+					}
+					case 2: /* Flush both */
+						lro->parent->data_len =
+							lro->frags_len;
+						sp->mac_control.stats_info->
+						     sw_stat.sending_both++;
+						queue_rx_frame(lro->parent);
+						clear_lro_session(lro);
+						goto send_up;
+					case 0: /* sessions exceeded */
+					case 5: /*
+						 * First pkt in session not
+						 * L3/L4 aggregatable
+						 */
+						break;
+					default:
+						DBG_PRINT(ERR_DBG,
+							"%s: Samadhana!!\n",
+							 __FUNCTION__);
+						BUG();
+				}
+			}
 		} else {
 			/*
 			 * Packet with erroneous checksum, let the
@@ -5677,25 +5814,31 @@
 		skb->ip_summed = CHECKSUM_NONE;
 	}
 
-	skb->protocol = eth_type_trans(skb, dev);
+	if (!sp->lro) {
+		skb->protocol = eth_type_trans(skb, dev);
 #ifdef CONFIG_S2IO_NAPI
-	if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
-		/* Queueing the vlan frame to the upper layer */
-		vlan_hwaccel_receive_skb(skb, sp->vlgrp,
-			RXD_GET_VLAN_TAG(rxdp->Control_2));
-	} else {
-		netif_receive_skb(skb);
-	}
+		if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
+			/* Queueing the vlan frame to the upper layer */
+			vlan_hwaccel_receive_skb(skb, sp->vlgrp,
+				RXD_GET_VLAN_TAG(rxdp->Control_2));
+		} else {
+			netif_receive_skb(skb);
+		}
 #else
-	if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
-		/* Queueing the vlan frame to the upper layer */
-		vlan_hwaccel_rx(skb, sp->vlgrp,
-			RXD_GET_VLAN_TAG(rxdp->Control_2));
-	} else {
-		netif_rx(skb);
-	}
+		if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
+			/* Queueing the vlan frame to the upper layer */
+			vlan_hwaccel_rx(skb, sp->vlgrp,
+				RXD_GET_VLAN_TAG(rxdp->Control_2));
+		} else {
+			netif_rx(skb);
+		}
 #endif
+	} else {
+send_up:
+		queue_rx_frame(skb);
+	}		
 	dev->last_rx = jiffies;
+aggregate:
 	atomic_dec(&sp->rx_bufs_left[ring_no]);
 	return SUCCESS;
 }
@@ -5713,7 +5856,7 @@
  *  void.
  */
 
-void s2io_link(nic_t * sp, int link)
+static void s2io_link(nic_t * sp, int link)
 {
 	struct net_device *dev = (struct net_device *) sp->dev;
 
@@ -5738,7 +5881,7 @@
  *  returns the revision ID of the device.
  */
 
-int get_xena_rev_id(struct pci_dev *pdev)
+static int get_xena_rev_id(struct pci_dev *pdev)
 {
 	u8 id = 0;
 	int ret;
@@ -5807,6 +5950,8 @@
 #endif
 module_param(rxsync_frequency, int, 0);
 module_param(intr_type, int, 0);
+module_param(lro, int, 0);
+module_param(lro_max_pkts, int, 0);
 
 /**
  *  s2io_init_nic - Initialization of the adapter .
@@ -5938,6 +6083,7 @@
 	else
 		sp->device_type = XFRAME_I_DEVICE;
 
+	sp->lro = lro;
 		
 	/* Initialize some PCI/PCI-X fields of the NIC. */
 	s2io_init_pci(sp);
@@ -6241,6 +6387,10 @@
 		DBG_PRINT(ERR_DBG, "%s: 3-Buffer mode support has been "
 			  "enabled\n",dev->name);
 
+	if (sp->lro)
+		DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
+			dev->name);
+
 	/* Initialize device name */
 	strcpy(sp->name, dev->name);
 	if (sp->device_type & XFRAME_II_DEVICE)
@@ -6343,7 +6493,7 @@
  * Description: This function is the cleanup routine for the driver. It unregist * ers the driver.
  */
 
-void s2io_closer(void)
+static void s2io_closer(void)
 {
 	pci_unregister_driver(&s2io_driver);
 	DBG_PRINT(INIT_DBG, "cleanup done\n");
@@ -6351,3 +6501,318 @@
 
 module_init(s2io_starter);
 module_exit(s2io_closer);
+
+static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip, 
+		struct tcphdr **tcp, RxD_t *rxdp)
+{
+	int ip_off;
+	u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len;
+
+	if (!(rxdp->Control_1 & RXD_FRAME_PROTO_TCP)) {
+		DBG_PRINT(INIT_DBG,"%s: Non-TCP frames not supported for LRO\n",
+			  __FUNCTION__);
+		return -1;
+	}
+
+	/* TODO:
+	 * By default the VLAN field in the MAC is stripped by the card, if this
+	 * feature is turned off in rx_pa_cfg register, then the ip_off field
+	 * has to be shifted by a further 2 bytes
+	 */
+	switch (l2_type) {
+		case 0: /* DIX type */
+		case 4: /* DIX type with VLAN */
+			ip_off = HEADER_ETHERNET_II_802_3_SIZE;
+			break;
+		/* LLC, SNAP etc are considered non-mergeable */
+		default:
+			return -1;
+	}
+
+	*ip = (struct iphdr *)((u8 *)buffer + ip_off);
+	ip_len = (u8)((*ip)->ihl);
+	ip_len <<= 2;
+	*tcp = (struct tcphdr *)((unsigned long)*ip + ip_len);
+
+	return 0;
+}
+
+static int check_for_socket_match(lro_t *lro, struct iphdr *ip,
+				  struct tcphdr *tcp)
+{
+	DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
+	if ((lro->iph->saddr != ip->saddr) || (lro->iph->daddr != ip->daddr) ||
+	   (lro->tcph->source != tcp->source) || (lro->tcph->dest != tcp->dest))
+		return -1;
+	return 0;
+}
+
+static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp)
+{
+	return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2));
+}
+
+static void initiate_new_session(lro_t *lro, u8 *l2h,
+		     struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len)
+{
+	DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
+	lro->l2h = l2h;
+	lro->iph = ip;
+	lro->tcph = tcp;
+	lro->tcp_next_seq = tcp_pyld_len + ntohl(tcp->seq);
+	lro->tcp_ack = ntohl(tcp->ack_seq);
+	lro->sg_num = 1;
+	lro->total_len = ntohs(ip->tot_len);
+	lro->frags_len = 0;
+	/* 
+	 * check if we saw TCP timestamp. Other consistency checks have
+	 * already been done.
+ 	 */
+	if (tcp->doff == 8) {
+		u32 *ptr;
+		ptr = (u32 *)(tcp+1);
+		lro->saw_ts = 1;
+		lro->cur_tsval = *(ptr+1);
+		lro->cur_tsecr = *(ptr+2);
+	}
+	lro->in_use = 1;
+}
+
+static void update_L3L4_header(nic_t *sp, lro_t *lro)
+{
+	struct iphdr *ip = lro->iph;
+	struct tcphdr *tcp = lro->tcph;
+	u16 nchk;
+	StatInfo_t *statinfo = sp->mac_control.stats_info;
+	DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
+
+	/* Update L3 header */
+	ip->tot_len = htons(lro->total_len);
+	ip->check = 0;
+	nchk = ip_fast_csum((u8 *)lro->iph, ip->ihl);
+	ip->check = nchk;
+
+	/* Update L4 header */
+	tcp->ack_seq = lro->tcp_ack;
+	tcp->window = lro->window;
+
+	/* Update tsecr field if this session has timestamps enabled */
+	if (lro->saw_ts) {
+		u32 *ptr = (u32 *)(tcp + 1);
+		*(ptr+2) = lro->cur_tsecr;
+	}
+
+	/* Update counters required for calculation of
+	 * average no. of packets aggregated.
+	 */
+	statinfo->sw_stat.sum_avg_pkts_aggregated += lro->sg_num;
+	statinfo->sw_stat.num_aggregations++;
+}
+
+static void aggregate_new_rx(lro_t *lro, struct iphdr *ip,
+		struct tcphdr *tcp, u32 l4_pyld)
+{
+	DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
+	lro->total_len += l4_pyld;
+	lro->frags_len += l4_pyld;
+	lro->tcp_next_seq += l4_pyld;
+	lro->sg_num++;
+
+	/* Update ack seq no. and window ad(from this pkt) in LRO object */
+	lro->tcp_ack = tcp->ack_seq;
+	lro->window = tcp->window;
+	
+	if (lro->saw_ts) {
+		u32 *ptr;
+		/* Update tsecr and tsval from this packet */
+		ptr = (u32 *) (tcp + 1);
+		lro->cur_tsval = *(ptr + 1); 
+		lro->cur_tsecr = *(ptr + 2);
+	}
+}
+
+static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
+				    struct tcphdr *tcp, u32 tcp_pyld_len)
+{
+	u8 *ptr;
+
+	DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
+
+	if (!tcp_pyld_len) {
+		/* Runt frame or a pure ack */
+		return -1;
+	}
+
+	if (ip->ihl != 5) /* IP has options */
+		return -1;
+
+	if (tcp->urg || tcp->psh || tcp->rst || tcp->syn || tcp->fin ||
+								!tcp->ack) {
+		/*
+		 * Currently recognize only the ack control word and
+		 * any other control field being set would result in
+		 * flushing the LRO session
+		 */
+		return -1;
+	}
+
+	/* 
+	 * Allow only one TCP timestamp option. Don't aggregate if
+	 * any other options are detected.
+	 */
+	if (tcp->doff != 5 && tcp->doff != 8)
+		return -1;
+
+	if (tcp->doff == 8) {
+		ptr = (u8 *)(tcp + 1);	
+		while (*ptr == TCPOPT_NOP)
+			ptr++;
+		if (*ptr != TCPOPT_TIMESTAMP || *(ptr+1) != TCPOLEN_TIMESTAMP)
+			return -1;
+
+		/* Ensure timestamp value increases monotonically */
+		if (l_lro)
+			if (l_lro->cur_tsval > *((u32 *)(ptr+2)))
+				return -1;
+
+		/* timestamp echo reply should be non-zero */
+		if (*((u32 *)(ptr+6)) == 0) 
+			return -1;
+	}
+
+	return 0;
+}
+
+static int
+s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
+		      RxD_t *rxdp, nic_t *sp)
+{
+	struct iphdr *ip;
+	struct tcphdr *tcph;
+	int ret = 0, i;
+
+	if (!(ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp,
+					 rxdp))) {
+		DBG_PRINT(INFO_DBG,"IP Saddr: %x Daddr: %x\n",
+			  ip->saddr, ip->daddr);
+	} else {
+		return ret;
+	}
+
+	tcph = (struct tcphdr *)*tcp;
+	*tcp_len = get_l4_pyld_length(ip, tcph);
+	for (i=0; i<MAX_LRO_SESSIONS; i++) {
+		lro_t *l_lro = &sp->lro0_n[i];
+		if (l_lro->in_use) {
+			if (check_for_socket_match(l_lro, ip, tcph))
+				continue;
+			/* Sock pair matched */
+			*lro = l_lro;
+
+			if ((*lro)->tcp_next_seq != ntohl(tcph->seq)) {
+				DBG_PRINT(INFO_DBG, "%s:Out of order. expected "
+					  "0x%x, actual 0x%x\n", __FUNCTION__,
+					  (*lro)->tcp_next_seq,
+					  ntohl(tcph->seq));
+
+				sp->mac_control.stats_info->
+				   sw_stat.outof_sequence_pkts++;
+				ret = 2;
+				break;
+			}
+
+			if (!verify_l3_l4_lro_capable(l_lro, ip, tcph,*tcp_len))
+				ret = 1; /* Aggregate */
+			else
+				ret = 2; /* Flush both */
+			break;
+		}
+	}
+
+	if (ret == 0) {
+		/* Before searching for available LRO objects,
+		 * check if the pkt is L3/L4 aggregatable. If not
+		 * don't create new LRO session. Just send this
+		 * packet up.
+		 */
+		if (verify_l3_l4_lro_capable(NULL, ip, tcph, *tcp_len)) {
+			return 5;
+		}
+
+		for (i=0; i<MAX_LRO_SESSIONS; i++) {
+			lro_t *l_lro = &sp->lro0_n[i];
+			if (!(l_lro->in_use)) {
+				*lro = l_lro;
+				ret = 3; /* Begin anew */
+				break;
+			}
+		}
+	}
+
+	if (ret == 0) { /* sessions exceeded */
+		DBG_PRINT(INFO_DBG,"%s:All LRO sessions already in use\n",
+			  __FUNCTION__);
+		*lro = NULL;
+		return ret;
+	}
+
+	switch (ret) {
+		case 3:
+			initiate_new_session(*lro, buffer, ip, tcph, *tcp_len);
+			break;
+		case 2:
+			update_L3L4_header(sp, *lro);
+			break;
+		case 1:
+			aggregate_new_rx(*lro, ip, tcph, *tcp_len);
+			if ((*lro)->sg_num == sp->lro_max_aggr_per_sess) {
+				update_L3L4_header(sp, *lro);
+				ret = 4; /* Flush the LRO */
+			}
+			break;
+		default:
+			DBG_PRINT(ERR_DBG,"%s:Dont know, can't say!!\n",
+				__FUNCTION__);
+			break;
+	}
+
+	return ret;
+}
+
+static void clear_lro_session(lro_t *lro)
+{
+	static u16 lro_struct_size = sizeof(lro_t);
+
+	memset(lro, 0, lro_struct_size);
+}
+
+static void queue_rx_frame(struct sk_buff *skb)
+{
+	struct net_device *dev = skb->dev;
+
+	skb->protocol = eth_type_trans(skb, dev);
+#ifdef CONFIG_S2IO_NAPI
+	netif_receive_skb(skb);
+#else
+	netif_rx(skb);
+#endif
+}
+
+static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb,
+			   u32 tcp_len)
+{
+	struct sk_buff *tmp, *first = lro->parent;
+
+	first->len += tcp_len;
+	first->data_len = lro->frags_len;
+	skb_pull(skb, (skb->len - tcp_len));
+	if ((tmp = skb_shinfo(first)->frag_list)) {
+		while (tmp->next)
+			tmp = tmp->next;
+		tmp->next = skb;
+	}
+	else
+		skb_shinfo(first)->frag_list = skb;
+	sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++;
+	return;
+}
diff -urN oldtree/drivers/net/s2io.h newtree/drivers/net/s2io.h
--- oldtree/drivers/net/s2io.h	2006-02-19 11:41:03.329836888 +0000
+++ newtree/drivers/net/s2io.h	2006-02-21 15:58:15.434800112 +0000
@@ -64,7 +64,7 @@
 #define	INTR_DBG	4
 
 /* Global variable that defines the present debug level of the driver. */
-int debug_level = ERR_DBG;	/* Default level. */
+static int debug_level = ERR_DBG;
 
 /* DEBUG message print. */
 #define DBG_PRINT(dbg_level, args...)  if(!(debug_level<dbg_level)) printk(args)
@@ -78,6 +78,13 @@
 typedef struct {
 	unsigned long long single_ecc_errs;
 	unsigned long long double_ecc_errs;
+	/* LRO statistics */
+	unsigned long long clubbed_frms_cnt;
+	unsigned long long sending_both;
+	unsigned long long outof_sequence_pkts;
+	unsigned long long flush_max_pkts;
+	unsigned long long sum_avg_pkts_aggregated;
+	unsigned long long num_aggregations;
 } swStat_t;
 
 /* The statistics block of Xena */
@@ -268,7 +275,7 @@
 #define MAX_RX_RINGS 8
 
 /* FIFO mappings for all possible number of fifos configured */
-int fifo_map[][MAX_TX_FIFOS] = {
+static int fifo_map[][MAX_TX_FIFOS] = {
 	{0, 0, 0, 0, 0, 0, 0, 0},
 	{0, 0, 0, 0, 1, 1, 1, 1},
 	{0, 0, 0, 1, 1, 1, 2, 2},
@@ -680,6 +687,24 @@
 	u64 data;
 };
 
+/* Data structure to represent a LRO session */
+typedef struct lro {
+	struct sk_buff	*parent;
+	u8		*l2h;
+	struct iphdr	*iph;
+	struct tcphdr	*tcph;
+	u32		tcp_next_seq;
+	u32		tcp_ack;
+	int		total_len;
+	int		frags_len;
+	int		sg_num;
+	int		in_use;
+	u16		window;
+	u32		cur_tsval;
+	u32		cur_tsecr;
+	u8		saw_ts;
+}lro_t;
+
 /* Structure representing one instance of the NIC */
 struct s2io_nic {
 	int rxd_mode;
@@ -784,6 +809,13 @@
 #define XFRAME_II_DEVICE	2
 	u8 device_type;
 
+#define MAX_LRO_SESSIONS	32
+	lro_t lro0_n[MAX_LRO_SESSIONS];
+	unsigned long	clubbed_frms_cnt;
+	unsigned long	sending_both;
+	u8		lro;
+	u16		lro_max_aggr_per_sess;
+
 #define INTA	0
 #define MSI	1
 #define MSI_X	2
@@ -911,18 +943,16 @@
 static void alarm_intr_handler(struct s2io_nic *sp);
 
 static int s2io_starter(void);
-void s2io_closer(void);
 static void s2io_tx_watchdog(struct net_device *dev);
 static void s2io_tasklet(unsigned long dev_addr);
 static void s2io_set_multicast(struct net_device *dev);
 static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp);
-void s2io_link(nic_t * sp, int link);
-void s2io_reset(nic_t * sp);
+static void s2io_link(nic_t * sp, int link);
 #if defined(CONFIG_S2IO_NAPI)
 static int s2io_poll(struct net_device *dev, int *budget);
 #endif
 static void s2io_init_pci(nic_t * sp);
-int s2io_set_mac_addr(struct net_device *dev, u8 * addr);
+static int s2io_set_mac_addr(struct net_device *dev, u8 * addr);
 static void s2io_alarm_handle(unsigned long data);
 static int s2io_enable_msi(nic_t *nic);
 static irqreturn_t s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs);
@@ -930,14 +960,18 @@
 s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs);
 static irqreturn_t
 s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs);
-int s2io_enable_msi_x(nic_t *nic);
 static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs);
 static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag);
 static struct ethtool_ops netdev_ethtool_ops;
 static void s2io_set_link(unsigned long data);
-int s2io_set_swapper(nic_t * sp);
+static int s2io_set_swapper(nic_t * sp);
 static void s2io_card_down(nic_t *nic);
 static int s2io_card_up(nic_t *nic);
-int get_xena_rev_id(struct pci_dev *pdev);
-void restore_xmsi_data(nic_t *nic);
+static int get_xena_rev_id(struct pci_dev *pdev);
+static void restore_xmsi_data(nic_t *nic);
+static int s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro, RxD_t *rxdp, nic_t *sp);
+static void clear_lro_session(lro_t *lro);
+static void queue_rx_frame(struct sk_buff *skb);
+static void update_L3L4_header(nic_t *sp, lro_t *lro);
+static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb, u32 tcp_len);
 #endif				/* _S2IO_H */
diff -urN oldtree/drivers/net/seeq8005.c newtree/drivers/net/seeq8005.c
--- oldtree/drivers/net/seeq8005.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/seeq8005.c	2006-02-21 15:58:15.435799960 +0000
@@ -46,6 +46,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/bitops.h>
+#include <linux/jiffies.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -699,7 +700,7 @@
 	int ioaddr = dev->base_addr;
 	int status = inw(SEEQ_STATUS);
 	int transmit_ptr = 0;
-	int tmp;
+	unsigned long tmp;
 
 	if (net_debug>4) {
 		printk("%s: send 0x%04x\n",dev->name,length);
@@ -724,7 +725,7 @@
 	
 	/* drain FIFO */
 	tmp = jiffies;
-	while ( (((status=inw(SEEQ_STATUS)) & SEEQSTAT_FIFO_EMPTY) == 0) && (jiffies - tmp < HZ))
+	while ( (((status=inw(SEEQ_STATUS)) & SEEQSTAT_FIFO_EMPTY) == 0) && time_before(jiffies, tmp + HZ))
 		mb();
 	
 	/* doit ! */
diff -urN oldtree/drivers/net/shaper.c newtree/drivers/net/shaper.c
--- oldtree/drivers/net/shaper.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/shaper.c	2006-02-21 15:58:15.436799808 +0000
@@ -83,6 +83,7 @@
 #include <linux/if_arp.h>
 #include <linux/init.h>
 #include <linux/if_shaper.h>
+#include <linux/jiffies.h>
 
 #include <net/dst.h>
 #include <net/arp.h>
@@ -168,7 +169,7 @@
 		/*
 		 *	Queue over time. Spill packet.
 		 */
-		if(SHAPERCB(skb)->shapeclock-jiffies > SHAPER_LATENCY) {
+		if(time_after(SHAPERCB(skb)->shapeclock,jiffies + SHAPER_LATENCY)) {
 			dev_kfree_skb(skb);
 			shaper->stats.tx_dropped++;
 		} else
diff -urN oldtree/drivers/net/sk98lin/h/skaddr.h newtree/drivers/net/sk98lin/h/skaddr.h
--- oldtree/drivers/net/sk98lin/h/skaddr.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/sk98lin/h/skaddr.h	2006-02-21 15:58:15.443798744 +0000
@@ -236,18 +236,6 @@
 	SK_U32	PortNumber,
 	int	Flags);
 
-extern	int	SkAddrXmacMcClear(
-	SK_AC	*pAC,
-	SK_IOC	IoC,
-	SK_U32	PortNumber,
-	int	Flags);
-
-extern	int	SkAddrGmacMcClear(
-	SK_AC	*pAC,
-	SK_IOC	IoC,
-	SK_U32	PortNumber,
-	int	Flags);
-
 extern	int	SkAddrMcAdd(
 	SK_AC		*pAC,
 	SK_IOC		IoC,
@@ -255,35 +243,11 @@
 	SK_MAC_ADDR	*pMc,
 	int		Flags);
 
-extern	int	SkAddrXmacMcAdd(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
-	SK_U32		PortNumber,
-	SK_MAC_ADDR	*pMc,
-	int		Flags);
-
-extern	int	SkAddrGmacMcAdd(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
-	SK_U32		PortNumber,
-	SK_MAC_ADDR	*pMc,
-	int		Flags);
-
 extern	int	SkAddrMcUpdate(
 	SK_AC	*pAC,
 	SK_IOC	IoC,
 	SK_U32	PortNumber);
 
-extern	int	SkAddrXmacMcUpdate(
-	SK_AC	*pAC,
-	SK_IOC	IoC,
-	SK_U32	PortNumber);
-
-extern	int	SkAddrGmacMcUpdate(
-	SK_AC	*pAC,
-	SK_IOC	IoC,
-	SK_U32	PortNumber);
-
 extern	int	SkAddrOverride(
 	SK_AC		*pAC,
 	SK_IOC		IoC,
@@ -297,18 +261,6 @@
 	SK_U32	PortNumber,
 	int	NewPromMode);
 
-extern	int	SkAddrXmacPromiscuousChange(
-	SK_AC	*pAC,
-	SK_IOC	IoC,
-	SK_U32	PortNumber,
-	int	NewPromMode);
-
-extern	int	SkAddrGmacPromiscuousChange(
-	SK_AC	*pAC,
-	SK_IOC	IoC,
-	SK_U32	PortNumber,
-	int	NewPromMode);	
-
 #ifndef SK_SLIM
 extern	int	SkAddrSwap(
 	SK_AC	*pAC,
diff -urN oldtree/drivers/net/sk98lin/h/skcsum.h newtree/drivers/net/sk98lin/h/skcsum.h
--- oldtree/drivers/net/sk98lin/h/skcsum.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/sk98lin/h/skcsum.h	2006-02-21 15:58:15.443798744 +0000
@@ -203,12 +203,6 @@
 	unsigned	Checksum2,
 	int			NetNumber);
 
-extern void SkCsGetSendInfo(
-	SK_AC				*pAc,
-	void				*pIpHeader,
-	SKCS_PACKET_INFO	*pPacketInfo,
-	int					NetNumber);
-
 extern void SkCsSetReceiveFlags(
 	SK_AC		*pAc,
 	unsigned	ReceiveFlags,
diff -urN oldtree/drivers/net/sk98lin/h/skgeinit.h newtree/drivers/net/sk98lin/h/skgeinit.h
--- oldtree/drivers/net/sk98lin/h/skgeinit.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/sk98lin/h/skgeinit.h	2006-02-21 15:58:15.447798136 +0000
@@ -464,12 +464,6 @@
 /*
  * public functions in skgeinit.c
  */
-extern void	SkGePollRxD(
-	SK_AC	*pAC,
-	SK_IOC	IoC,
-	int		Port,
-	SK_BOOL	PollRxD);
-
 extern void	SkGePollTxD(
 	SK_AC	*pAC,
 	SK_IOC	IoC,
@@ -522,10 +516,6 @@
 	int		Led,
 	int		Mode);
 
-extern void	SkGeInitRamIface(
-	SK_AC	*pAC,
-	SK_IOC	IoC);
-
 extern int	SkGeInitAssignRamToQueues(
 	SK_AC	*pAC,
 	int		ActivePort,
@@ -549,11 +539,6 @@
 	SK_IOC	IoC,
 	int		Port);
 
-extern void	SkMacClearRst(
-	SK_AC	*pAC,
-	SK_IOC	IoC,
-	int		Port);
-
 extern void	SkXmInitMac(
 	SK_AC	*pAC,
 	SK_IOC	IoC,
@@ -580,11 +565,6 @@
 	SK_IOC	IoC,
 	int		Port);
 
-extern void	SkMacFlushRxFifo(
-	SK_AC	*pAC,
-	SK_IOC	IoC,
-	int		Port);
-
 extern void	SkMacIrq(
 	SK_AC	*pAC,
 	SK_IOC	IoC,
@@ -601,12 +581,6 @@
 	int		Port,
 	SK_U16	IStatus);
 
-extern void  SkMacSetRxTxEn(
-	SK_AC	*pAC,
-	SK_IOC	IoC,
-	int		Port,
-	int		Para);
-
 extern int  SkMacRxTxEnable(
 	SK_AC	*pAC,
 	SK_IOC	IoC,
@@ -659,16 +633,6 @@
 	int		StartNum,
 	int		StopNum);
 
-extern void	SkXmInitDupMd(
-	SK_AC	*pAC,
-	SK_IOC	IoC,
-	int		Port);
-
-extern void	SkXmInitPauseMd(
-	SK_AC	*pAC,
-	SK_IOC	IoC,
-	int		Port);
-
 extern void	SkXmAutoNegLipaXmac(
 	SK_AC	*pAC,
 	SK_IOC	IoC,
@@ -729,17 +693,6 @@
 	int		Port,
 	SK_BOOL	StartTest);
 
-extern int SkGmEnterLowPowerMode(
-	SK_AC	*pAC,
-	SK_IOC	IoC,
-	int		Port,
-	SK_U8	Mode);
-
-extern int SkGmLeaveLowPowerMode(
-	SK_AC	*pAC,
-	SK_IOC	IoC,
-	int		Port);
-
 #ifdef SK_DIAG
 extern void	SkGePhyRead(
 	SK_AC	*pAC,
@@ -782,7 +735,6 @@
 /*
  * public functions in skgeinit.c
  */
-extern void	SkGePollRxD();
 extern void	SkGePollTxD();
 extern void	SkGeYellowLED();
 extern int	SkGeCfgSync();
@@ -792,7 +744,6 @@
 extern void	SkGeDeInit();
 extern int	SkGeInitPort();
 extern void	SkGeXmitLED();
-extern void	SkGeInitRamIface();
 extern int	SkGeInitAssignRamToQueues();
 
 /*
@@ -801,18 +752,15 @@
 extern void SkMacRxTxDisable();
 extern void	SkMacSoftRst();
 extern void	SkMacHardRst();
-extern void	SkMacClearRst();
 extern void SkMacInitPhy();
 extern int  SkMacRxTxEnable();
 extern void SkMacPromiscMode();
 extern void SkMacHashing();
 extern void SkMacIrqDisable();
 extern void	SkMacFlushTxFifo();
-extern void	SkMacFlushRxFifo();
 extern void	SkMacIrq();
 extern int	SkMacAutoNegDone();
 extern void	SkMacAutoNegLipaPhy();
-extern void SkMacSetRxTxEn();
 extern void	SkXmInitMac();
 extern void	SkXmPhyRead();
 extern void	SkXmPhyWrite();
@@ -820,8 +768,6 @@
 extern void	SkGmPhyRead();
 extern void	SkGmPhyWrite();
 extern void	SkXmClrExactAddr();
-extern void	SkXmInitDupMd();
-extern void	SkXmInitPauseMd();
 extern void	SkXmAutoNegLipaXmac();
 extern int	SkXmUpdateStats();
 extern int	SkGmUpdateStats();
@@ -832,8 +778,6 @@
 extern int	SkXmOverflowStatus();
 extern int	SkGmOverflowStatus();
 extern int	SkGmCableDiagStatus();
-extern int	SkGmEnterLowPowerMode();
-extern int	SkGmLeaveLowPowerMode();
 
 #ifdef SK_DIAG
 extern void	SkGePhyRead();
diff -urN oldtree/drivers/net/sk98lin/h/skgepnmi.h newtree/drivers/net/sk98lin/h/skgepnmi.h
--- oldtree/drivers/net/sk98lin/h/skgepnmi.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/sk98lin/h/skgepnmi.h	2006-02-21 15:58:15.448797984 +0000
@@ -946,10 +946,6 @@
  * Function prototypes
  */
 extern int SkPnmiInit(SK_AC *pAC, SK_IOC IoC, int Level);
-extern int SkPnmiGetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void* pBuf,
-	unsigned int* pLen, SK_U32 Instance, SK_U32 NetIndex);
-extern int SkPnmiPreSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id,
-	void* pBuf, unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
 extern int SkPnmiSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void* pBuf,
 	unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
 extern int SkPnmiGetStruct(SK_AC *pAC, SK_IOC IoC, void* pBuf,
diff -urN oldtree/drivers/net/sk98lin/h/skgesirq.h newtree/drivers/net/sk98lin/h/skgesirq.h
--- oldtree/drivers/net/sk98lin/h/skgesirq.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/sk98lin/h/skgesirq.h	2006-02-21 15:58:15.449797832 +0000
@@ -105,7 +105,6 @@
 
 extern void SkGeSirqIsr(SK_AC *pAC, SK_IOC IoC, SK_U32 Istatus);
 extern int  SkGeSirqEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Para);
-extern void SkHWLinkUp(SK_AC *pAC, SK_IOC IoC, int Port);
 extern void SkHWLinkDown(SK_AC *pAC, SK_IOC IoC, int Port);
 
 #endif	/* _INC_SKGESIRQ_H_ */
diff -urN oldtree/drivers/net/sk98lin/h/ski2c.h newtree/drivers/net/sk98lin/h/ski2c.h
--- oldtree/drivers/net/sk98lin/h/ski2c.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/sk98lin/h/ski2c.h	2006-02-21 15:58:15.449797832 +0000
@@ -162,9 +162,6 @@
 } SK_I2C;
 
 extern int SkI2cInit(SK_AC *pAC, SK_IOC IoC, int Level);
-extern int SkI2cWrite(SK_AC *pAC, SK_IOC IoC, SK_U32 Data, int Dev, int Size,
-					   int Reg, int Burst);
-extern int SkI2cReadSensor(SK_AC *pAC, SK_IOC IoC, SK_SENSOR *pSen);
 #ifdef SK_DIAG
 extern	SK_U32 SkI2cRead(SK_AC *pAC, SK_IOC IoC, int Dev, int Size, int Reg,
 						 int Burst);
diff -urN oldtree/drivers/net/sk98lin/h/skvpd.h newtree/drivers/net/sk98lin/h/skvpd.h
--- oldtree/drivers/net/sk98lin/h/skvpd.h	2006-02-19 11:41:03.335835976 +0000
+++ newtree/drivers/net/sk98lin/h/skvpd.h	2006-02-21 15:58:15.450797680 +0000
@@ -183,14 +183,6 @@
 	int			addr);
 #endif	/* SKDIAG */
 
-extern int	VpdSetupPara(
-	SK_AC		*pAC,
-	const char	*key,
-	const char	*buf,
-	int			len,
-	int			type,
-	int			op);
-
 extern SK_VPD_STATUS	*VpdStat(
 	SK_AC		*pAC,
 	SK_IOC		IoC);
@@ -227,11 +219,6 @@
 	SK_AC		*pAC,
 	SK_IOC		IoC);
 
-extern void	VpdErrLog(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
-	char		*msg);
-
 #ifdef	SKDIAG
 extern int	VpdReadBlock(
 	SK_AC		*pAC,
@@ -249,7 +236,6 @@
 #endif	/* SKDIAG */
 #else	/* SK_KR_PROTO */
 extern SK_U32	VpdReadDWord();
-extern int	VpdSetupPara();
 extern SK_VPD_STATUS	*VpdStat();
 extern int	VpdKeys();
 extern int	VpdRead();
@@ -257,7 +243,6 @@
 extern int	VpdWrite();
 extern int	VpdDelete();
 extern int	VpdUpdate();
-extern void	VpdErrLog();
 #endif	/* SK_KR_PROTO */
 
 #endif	/* __INC_SKVPD_H_ */
diff -urN oldtree/drivers/net/sk98lin/skaddr.c newtree/drivers/net/sk98lin/skaddr.c
--- oldtree/drivers/net/sk98lin/skaddr.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/sk98lin/skaddr.c	2006-02-21 15:58:15.457796616 +0000
@@ -87,6 +87,21 @@
 static int	Next0[SK_MAX_MACS] = {0};
 #endif	/* DEBUG */
 
+static int SkAddrGmacMcAdd(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
+			   SK_MAC_ADDR *pMc, int Flags);
+static int SkAddrGmacMcClear(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
+			     int Flags);
+static int SkAddrGmacMcUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber);
+static int SkAddrGmacPromiscuousChange(SK_AC *pAC, SK_IOC IoC,
+				       SK_U32 PortNumber, int NewPromMode);
+static int SkAddrXmacMcAdd(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
+			   SK_MAC_ADDR *pMc, int Flags);
+static int SkAddrXmacMcClear(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
+			     int Flags);
+static int SkAddrXmacMcUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber);
+static int SkAddrXmacPromiscuousChange(SK_AC *pAC, SK_IOC IoC,
+				       SK_U32 PortNumber, int NewPromMode);
+
 /* functions ******************************************************************/
 
 /******************************************************************************
@@ -372,7 +387,7 @@
  *	SK_ADDR_SUCCESS
  *	SK_ADDR_ILLEGAL_PORT
  */
-int	SkAddrXmacMcClear(
+static int	SkAddrXmacMcClear(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* I/O context */
 SK_U32	PortNumber,	/* Index of affected port */
@@ -429,7 +444,7 @@
  *	SK_ADDR_SUCCESS
  *	SK_ADDR_ILLEGAL_PORT
  */
-int	SkAddrGmacMcClear(
+static int	SkAddrGmacMcClear(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* I/O context */
 SK_U32	PortNumber,	/* Index of affected port */
@@ -519,7 +534,7 @@
  * Returns:
  *	Hash value of multicast address.
  */
-SK_U32 SkXmacMcHash(
+static SK_U32 SkXmacMcHash(
 unsigned char *pMc)	/* Multicast address */
 {
 	SK_U32 Idx;
@@ -557,7 +572,7 @@
  * Returns:
  *	Hash value of multicast address.
  */
-SK_U32 SkGmacMcHash(
+static SK_U32 SkGmacMcHash(
 unsigned char *pMc)	/* Multicast address */
 {
 	SK_U32 Data;
@@ -672,7 +687,7 @@
  *	SK_MC_ILLEGAL_ADDRESS
  *	SK_MC_RLMT_OVERFLOW
  */
-int	SkAddrXmacMcAdd(
+static int	SkAddrXmacMcAdd(
 SK_AC		*pAC,		/* adapter context */
 SK_IOC		IoC,		/* I/O context */
 SK_U32		PortNumber,	/* Port Number */
@@ -778,7 +793,7 @@
  *	SK_MC_FILTERING_INEXACT
  *	SK_MC_ILLEGAL_ADDRESS
  */
-int	SkAddrGmacMcAdd(
+static int	SkAddrGmacMcAdd(
 SK_AC		*pAC,		/* adapter context */
 SK_IOC		IoC,		/* I/O context */
 SK_U32		PortNumber,	/* Port Number */
@@ -937,7 +952,7 @@
  *	SK_MC_FILTERING_INEXACT
  *	SK_ADDR_ILLEGAL_PORT
  */
-int	SkAddrXmacMcUpdate(
+static int	SkAddrXmacMcUpdate(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* I/O context */
 SK_U32	PortNumber)	/* Port Number */
@@ -1082,7 +1097,7 @@
  *	SK_MC_FILTERING_INEXACT
  *	SK_ADDR_ILLEGAL_PORT
  */
-int	SkAddrGmacMcUpdate(
+static int	SkAddrGmacMcUpdate(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* I/O context */
 SK_U32	PortNumber)	/* Port Number */
@@ -1468,7 +1483,7 @@
  *	SK_ADDR_SUCCESS
  *	SK_ADDR_ILLEGAL_PORT
  */
-int	SkAddrXmacPromiscuousChange(
+static int	SkAddrXmacPromiscuousChange(
 SK_AC	*pAC,			/* adapter context */
 SK_IOC	IoC,			/* I/O context */
 SK_U32	PortNumber,		/* port whose promiscuous mode changes */
@@ -1585,7 +1600,7 @@
  *	SK_ADDR_SUCCESS
  *	SK_ADDR_ILLEGAL_PORT
  */
-int	SkAddrGmacPromiscuousChange(
+static int	SkAddrGmacPromiscuousChange(
 SK_AC	*pAC,			/* adapter context */
 SK_IOC	IoC,			/* I/O context */
 SK_U32	PortNumber,		/* port whose promiscuous mode changes */
diff -urN oldtree/drivers/net/sk98lin/skgeinit.c newtree/drivers/net/sk98lin/skgeinit.c
--- oldtree/drivers/net/sk98lin/skgeinit.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/sk98lin/skgeinit.c	2006-02-21 15:58:15.463795704 +0000
@@ -59,34 +59,6 @@
 
 /******************************************************************************
  *
- *	SkGePollRxD() - Enable / Disable Descriptor Polling of RxD Ring
- *
- * Description:
- *	Enable or disable the descriptor polling of the receive descriptor
- *	ring (RxD) for port 'Port'.
- *	The new configuration is *not* saved over any SkGeStopPort() and
- *	SkGeInitPort() calls.
- *
- * Returns:
- *	nothing
- */
-void SkGePollRxD(
-SK_AC	*pAC,		/* adapter context */
-SK_IOC	IoC,		/* IO context */
-int		Port,		/* Port Index (MAC_1 + n) */
-SK_BOOL PollRxD)	/* SK_TRUE (enable pol.), SK_FALSE (disable pol.) */
-{
-	SK_GEPORT *pPrt;
-
-	pPrt = &pAC->GIni.GP[Port];
-
-	SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), (PollRxD) ?
-		CSR_ENA_POL : CSR_DIS_POL);
-}	/* SkGePollRxD */
-
-
-/******************************************************************************
- *
  *	SkGePollTxD() - Enable / Disable Descriptor Polling of TxD Rings
  *
  * Description:
@@ -952,7 +924,7 @@
  * Returns:
  *	nothing
  */
-void SkGeInitRamIface(
+static void SkGeInitRamIface(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC)		/* IO context */
 {
@@ -1409,83 +1381,6 @@
 
 }	/* SkGeInit0*/
 
-#ifdef SK_PCI_RESET
-
-/******************************************************************************
- *
- *	SkGePciReset() - Reset PCI interface
- *
- * Description:
- *	o Read PCI configuration.
- *	o Change power state to 3.
- *	o Change power state to 0.
- *	o Restore PCI configuration.
- *
- * Returns:
- *	0:	Success.
- *	1:	Power state could not be changed to 3.
- */
-static int SkGePciReset(
-SK_AC	*pAC,		/* adapter context */
-SK_IOC	IoC)		/* IO context */
-{
-	int		i;
-	SK_U16	PmCtlSts;
-	SK_U32	Bp1;
-	SK_U32	Bp2;
-	SK_U16	PciCmd;
-	SK_U8	Cls;
-	SK_U8	Lat;
-	SK_U8	ConfigSpace[PCI_CFG_SIZE];
-
-	/*
-	 * Note: Switching to D3 state is like a software reset.
-	 *		 Switching from D3 to D0 is a hardware reset.
-	 *		 We have to save and restore the configuration space.
-	 */
-	for (i = 0; i < PCI_CFG_SIZE; i++) {
-		SkPciReadCfgDWord(pAC, i*4, &ConfigSpace[i]);
-	}
-
-	/* We know the RAM Interface Arbiter is enabled. */
-	SkPciWriteCfgWord(pAC, PCI_PM_CTL_STS, PCI_PM_STATE_D3);
-	SkPciReadCfgWord(pAC, PCI_PM_CTL_STS, &PmCtlSts);
-	
-	if ((PmCtlSts & PCI_PM_STATE_MSK) != PCI_PM_STATE_D3) {
-		return(1);
-	}
-
-	/* Return to D0 state. */
-	SkPciWriteCfgWord(pAC, PCI_PM_CTL_STS, PCI_PM_STATE_D0);
-
-	/* Check for D0 state. */
-	SkPciReadCfgWord(pAC, PCI_PM_CTL_STS, &PmCtlSts);
-	
-	if ((PmCtlSts & PCI_PM_STATE_MSK) != PCI_PM_STATE_D0) {
-		return(1);
-	}
-
-	/* Check PCI Config Registers. */
-	SkPciReadCfgWord(pAC, PCI_COMMAND, &PciCmd);
-	SkPciReadCfgByte(pAC, PCI_CACHE_LSZ, &Cls);
-	SkPciReadCfgDWord(pAC, PCI_BASE_1ST, &Bp1);
-	SkPciReadCfgDWord(pAC, PCI_BASE_2ND, &Bp2);
-	SkPciReadCfgByte(pAC, PCI_LAT_TIM, &Lat);
-	
-	if (PciCmd != 0 || Cls != (SK_U8)0 || Lat != (SK_U8)0 ||
-		(Bp1 & 0xfffffff0L) != 0 || Bp2 != 1) {
-		return(1);
-	}
-
-	/* Restore PCI Config Space. */
-	for (i = 0; i < PCI_CFG_SIZE; i++) {
-		SkPciWriteCfgDWord(pAC, i*4, ConfigSpace[i]);
-	}
-
-	return(0);
-}	/* SkGePciReset */
-
-#endif /* SK_PCI_RESET */
 
 /******************************************************************************
  *
@@ -1524,10 +1419,6 @@
 	/* save CLK_RUN bits (YUKON-Lite) */
 	SK_IN16(IoC, B0_CTST, &CtrlStat);
 
-#ifdef SK_PCI_RESET
-	(void)SkGePciReset(pAC, IoC);
-#endif /* SK_PCI_RESET */
-
 	/* do the SW-reset */
 	SK_OUT8(IoC, B0_CTST, CS_RST_SET);
 
@@ -1991,11 +1882,6 @@
 	int	i;
 	SK_U16	Word;
 
-#ifdef SK_PHY_LP_MODE
-	SK_U8	Byte;
-	SK_U16	PmCtlSts;
-#endif /* SK_PHY_LP_MODE */
-
 #if (!defined(SK_SLIM) && !defined(VCPU))
 	/* ensure I2C is ready */
 	SkI2cWaitIrq(pAC, IoC);
@@ -2010,38 +1896,6 @@
 		}
 	}
 
-#ifdef SK_PHY_LP_MODE
-    /*
-	 * for power saving purposes within mobile environments
-	 * we set the PHY to coma mode and switch to D3 power state.
-	 */
-	if (pAC->GIni.GIYukonLite &&
-		pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3) {
-
-		/* for all ports switch PHY to coma mode */
-		for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
-			
-			SkGmEnterLowPowerMode(pAC, IoC, i, PHY_PM_DEEP_SLEEP);
-		}
-
-		if (pAC->GIni.GIVauxAvail) {
-			/* switch power to VAUX */
-			Byte = PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF;
-
-			SK_OUT8(IoC, B0_POWER_CTRL, Byte);
-		}
-		
-		/* switch to D3 state */
-		SK_IN16(IoC, PCI_C(PCI_PM_CTL_STS), &PmCtlSts);
-
-		PmCtlSts |= PCI_PM_STATE_D3;
-
-		SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
-
-		SK_OUT16(IoC, PCI_C(PCI_PM_CTL_STS), PmCtlSts);
-	}
-#endif /* SK_PHY_LP_MODE */
-
 	/* Reset all bits in the PCI STATUS register */
 	/*
 	 * Note: PCI Cfg cycles cannot be used, because they are not
diff -urN oldtree/drivers/net/sk98lin/skgemib.c newtree/drivers/net/sk98lin/skgemib.c
--- oldtree/drivers/net/sk98lin/skgemib.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/sk98lin/skgemib.c	2006-02-21 15:58:15.464795552 +0000
@@ -871,13 +871,6 @@
 		sizeof(SK_PNMI_CONF),
 		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyType),
 		SK_PNMI_RO, MacPrivateConf, 0},
-#ifdef SK_PHY_LP_MODE
-		{OID_SKGE_PHY_LP_MODE,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_CONF),
-		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyMode),
-		SK_PNMI_RW, MacPrivateConf, 0},
-#endif	
 	{OID_SKGE_LINK_CAP,
 		SK_PNMI_MAC_ENTRIES,
 		sizeof(SK_PNMI_CONF),
diff -urN oldtree/drivers/net/sk98lin/skgepnmi.c newtree/drivers/net/sk98lin/skgepnmi.c
--- oldtree/drivers/net/sk98lin/skgepnmi.c	2006-02-19 11:41:03.342834912 +0000
+++ newtree/drivers/net/sk98lin/skgepnmi.c	2006-02-21 15:58:15.470794640 +0000
@@ -56,10 +56,6 @@
  * Public Function prototypes
  */
 int SkPnmiInit(SK_AC *pAC, SK_IOC IoC, int level);
-int SkPnmiGetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf,
-	unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
-int SkPnmiPreSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf,
-	unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
 int SkPnmiSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf,
 	unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
 int SkPnmiGetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf,
@@ -587,7 +583,7 @@
  *                           exist (e.g. port instance 3 on a two port
  *	                         adapter.
  */
-int SkPnmiGetVar(
+static int SkPnmiGetVar(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 SK_U32 Id,		/* Object ID that is to be processed */
@@ -629,7 +625,7 @@
  *                           exist (e.g. port instance 3 on a two port
  *	                         adapter.
  */
-int SkPnmiPreSetVar(
+static int SkPnmiPreSetVar(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 SK_U32 Id,		/* Object ID that is to be processed */
@@ -5062,9 +5058,6 @@
 		case OID_SKGE_SPEED_CAP:
 		case OID_SKGE_SPEED_MODE:
 		case OID_SKGE_SPEED_STATUS:
-#ifdef SK_PHY_LP_MODE
-		case OID_SKGE_PHY_LP_MODE:
-#endif
 			if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U8)) {
 
 				*pLen = (Limit - LogPortIndex) * sizeof(SK_U8);
@@ -5140,28 +5133,6 @@
 				Offset += sizeof(SK_U32);
 				break;
 
-#ifdef SK_PHY_LP_MODE
-			case OID_SKGE_PHY_LP_MODE:
-				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
-					if (LogPortIndex == 0) {
-						continue;
-					}
-					else {
-						/* Get value for physical ports */
-						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex);
-						Val8 = (SK_U8) pAC->GIni.GP[PhysPortIndex].PPhyPowerState;
-						*pBufPtr = Val8;
-					}
-				}
-				else { /* DualNetMode */
-					
-					Val8 = (SK_U8) pAC->GIni.GP[PhysPortIndex].PPhyPowerState;
-					*pBufPtr = Val8;
-				}
-				Offset += sizeof(SK_U8);
-				break;
-#endif
-
 			case OID_SKGE_LINK_CAP:
 				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
 					if (LogPortIndex == 0) {
@@ -5478,16 +5449,6 @@
 		}
 		break;
 
-#ifdef SK_PHY_LP_MODE
-	case OID_SKGE_PHY_LP_MODE:
-		if (*pLen < Limit - LogPortIndex) {
-
-			*pLen = Limit - LogPortIndex;
-			return (SK_PNMI_ERR_TOO_SHORT);
-		}
-		break;
-#endif
-
 	case OID_SKGE_MTU:
 		if (*pLen < sizeof(SK_U32)) {
 
@@ -5845,116 +5806,6 @@
 			Offset += sizeof(SK_U32);
 			break;
 		
-#ifdef SK_PHY_LP_MODE
-		case OID_SKGE_PHY_LP_MODE:
-			/* The preset ends here */
-			if (Action == SK_PNMI_PRESET) {
-
-				return (SK_PNMI_ERR_OK);
-			}
-
-			if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
-				if (LogPortIndex == 0) {
-					Offset = 0;
-					continue;
-				}
-				else {
-					/* Set value for physical ports */
-					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex);
-
-					switch (*(pBuf + Offset)) {
-						case 0:
-							/* If LowPowerMode is active, we can leave it. */
-							if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState) {
-
-								Val32 = SkGmLeaveLowPowerMode(pAC, IoC, PhysPortIndex);
-								
-								if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState < 3)	{
-									
-									SkDrvInitAdapter(pAC);
-								}
-								break;
-							}
-							else {
-								*pLen = 0;
-								return (SK_PNMI_ERR_GENERAL);
-							}
-						case 1:
-						case 2:
-						case 3:
-						case 4:
-							/* If no LowPowerMode is active, we can enter it. */
-							if (!pAC->GIni.GP[PhysPortIndex].PPhyPowerState) {
-
-								if ((*(pBuf + Offset)) < 3)	{
-								
-									SkDrvDeInitAdapter(pAC);
-								}
-
-								Val32 = SkGmEnterLowPowerMode(pAC, IoC, PhysPortIndex, *pBuf);
-								break;
-							}
-							else {
-								*pLen = 0;
-								return (SK_PNMI_ERR_GENERAL);
-							}
-						default:
-							*pLen = 0;
-							return (SK_PNMI_ERR_BAD_VALUE);
-					}
-				}
-			}
-			else { /* DualNetMode */
-				
-				switch (*(pBuf + Offset)) {
-					case 0:
-						/* If we are in a LowPowerMode, we can leave it. */
-						if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState) {
-
-							Val32 = SkGmLeaveLowPowerMode(pAC, IoC, PhysPortIndex);
-							
-							if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState < 3)	{
-
-								SkDrvInitAdapter(pAC);
-							}
-							break;
-						}
-						else {
-							*pLen = 0;
-							return (SK_PNMI_ERR_GENERAL);
-						}
-					
-					case 1:
-					case 2:
-					case 3:
-					case 4:
-						/* If we are not already in LowPowerMode, we can enter it. */
-						if (!pAC->GIni.GP[PhysPortIndex].PPhyPowerState) {
-
-							if ((*(pBuf + Offset)) < 3)	{
-
-								SkDrvDeInitAdapter(pAC);
-							}
-							else {
-
-								Val32 = SkGmEnterLowPowerMode(pAC, IoC, PhysPortIndex, *pBuf);
-							}
-							break;
-						}
-						else {
-							*pLen = 0;
-							return (SK_PNMI_ERR_GENERAL);
-						}
-					
-					default:
-						*pLen = 0;
-						return (SK_PNMI_ERR_BAD_VALUE);
-				}
-			}
-			Offset += sizeof(SK_U8);
-			break;
-#endif
-
 		default:
             SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
                 ("MacPrivateConf: Unknown OID should be handled before set"));
diff -urN oldtree/drivers/net/sk98lin/skgesirq.c newtree/drivers/net/sk98lin/skgesirq.c
--- oldtree/drivers/net/sk98lin/skgesirq.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/sk98lin/skgesirq.c	2006-02-21 15:58:15.472794336 +0000
@@ -265,7 +265,7 @@
  *
  * Returns: N/A
  */
-void SkHWLinkUp(
+static void SkHWLinkUp(
 SK_AC	*pAC,	/* adapter context */
 SK_IOC	IoC,	/* IO context */
 int		Port)	/* Port Index (MAC_1 + n) */
@@ -612,14 +612,6 @@
 				 * we ignore those
 				 */
 				pPrt->HalfDupTimerActive = SK_TRUE;
-#ifdef XXX
-				Len = sizeof(SK_U64);
-				SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *)&Octets,
-					&Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, 0),
-					pAC->Rlmt.Port[0].Net->NetNumber);
-				
-				pPrt->LastOctets = Octets;
-#endif /* XXX */
 				/* Snap statistic counters */
 				(void)SkXmUpdateStats(pAC, IoC, 0);
 
@@ -653,14 +645,6 @@
 				 pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) &&
 				!pPrt->HalfDupTimerActive) {
 				pPrt->HalfDupTimerActive = SK_TRUE;
-#ifdef XXX
-				Len = sizeof(SK_U64);
-				SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *)&Octets,
-					&Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, 1),
-					pAC->Rlmt.Port[1].Net->NetNumber);
-				
-				pPrt->LastOctets = Octets;
-#endif /* XXX */
 				/* Snap statistic counters */
 				(void)SkXmUpdateStats(pAC, IoC, 1);
 
@@ -2085,12 +2069,6 @@
 			pPrt->HalfDupTimerActive = SK_FALSE;
 			if (pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF ||
 				pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) {
-#ifdef XXX
-				Len = sizeof(SK_U64);
-				SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *)&Octets,
-					&Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, Port),
-					pAC->Rlmt.Port[Port].Net->NetNumber);
-#endif /* XXX */
 				/* Snap statistic counters */
 				(void)SkXmUpdateStats(pAC, IoC, Port);
 
diff -urN oldtree/drivers/net/sk98lin/ski2c.c newtree/drivers/net/sk98lin/ski2c.c
--- oldtree/drivers/net/sk98lin/ski2c.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/sk98lin/ski2c.c	2006-02-21 15:58:15.474794032 +0000
@@ -396,7 +396,7 @@
  *			1:	error,	 transfer does not complete, I2C transfer
  *						 killed, wait loop terminated.
  */
-int	SkI2cWait(
+static int	SkI2cWait(
 SK_AC	*pAC,	/* Adapter Context */
 SK_IOC	IoC,	/* I/O Context */
 int		Event)	/* complete event to wait for (I2C_READ or I2C_WRITE) */
@@ -481,7 +481,7 @@
  * returns	0:	success
  *			1:	error
  */
-int SkI2cWrite(
+static int SkI2cWrite(
 SK_AC	*pAC,		/* Adapter Context */
 SK_IOC	IoC,		/* I/O Context */
 SK_U32	I2cData,	/* I2C Data to write */
@@ -538,7 +538,7 @@
  *		1 if the read is completed
  *		0 if the read must be continued (I2C Bus still allocated)
  */
-int	SkI2cReadSensor(
+static int	SkI2cReadSensor(
 SK_AC		*pAC,	/* Adapter Context */
 SK_IOC		IoC,	/* I/O Context */
 SK_SENSOR	*pSen)	/* Sensor to be read */
diff -urN oldtree/drivers/net/sk98lin/sklm80.c newtree/drivers/net/sk98lin/sklm80.c
--- oldtree/drivers/net/sk98lin/sklm80.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/sk98lin/sklm80.c	2006-02-21 15:58:15.474794032 +0000
@@ -34,79 +34,7 @@
 #include "h/lm80.h"
 #include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
 
-#ifdef	SK_DIAG
-#define	BREAK_OR_WAIT(pAC,IoC,Event)	SkI2cWait(pAC,IoC,Event)
-#else	/* nSK_DIAG */
 #define	BREAK_OR_WAIT(pAC,IoC,Event)	break
-#endif	/* nSK_DIAG */
-
-#ifdef	SK_DIAG
-/*
- * read the register 'Reg' from the device 'Dev'
- *
- * return 	read error	-1
- *		success		the read value
- */
-int	SkLm80RcvReg(
-SK_IOC	IoC,		/* Adapter Context */
-int		Dev,		/* I2C device address */
-int		Reg)		/* register to read */
-{
-	int	Val = 0;
-	int	TempExt;
-
-	/* Signal device number */
-	if (SkI2cSndDev(IoC, Dev, I2C_WRITE)) {
-		return(-1);
-	}
-
-	if (SkI2cSndByte(IoC, Reg)) {
-		return(-1);
-	}
-
-	/* repeat start */
-	if (SkI2cSndDev(IoC, Dev, I2C_READ)) {
-		return(-1);
-	}
-
-	switch (Reg) {
-	case LM80_TEMP_IN:
-		Val = (int)SkI2cRcvByte(IoC, 1);
-
-		/* First: correct the value: it might be negative */
-		if ((Val & 0x80) != 0) {
-			/* Value is negative */
-			Val = Val - 256;
-		}
-		Val = Val * SK_LM80_TEMP_LSB;
-		SkI2cStop(IoC);
-		
-		TempExt = (int)SkLm80RcvReg(IoC, LM80_ADDR, LM80_TEMP_CTRL);
-		
-		if (Val > 0) {
-			Val += ((TempExt >> 7) * SK_LM80_TEMPEXT_LSB);
-		}
-		else {
-			Val -= ((TempExt >> 7) * SK_LM80_TEMPEXT_LSB);
-		}
-		return(Val);
-		break;
-	case LM80_VT0_IN:
-	case LM80_VT1_IN:
-	case LM80_VT2_IN:
-	case LM80_VT3_IN:
-		Val = (int)SkI2cRcvByte(IoC, 1) * SK_LM80_VT_LSB;
-		break;
-	
-	default:
-		Val = (int)SkI2cRcvByte(IoC, 1);
-		break;
-	}
-
-	SkI2cStop(IoC);
-	return(Val);
-}
-#endif	/* SK_DIAG */
 
 /*
  * read a sensors value (LM80 specific)
diff -urN oldtree/drivers/net/sk98lin/skrlmt.c newtree/drivers/net/sk98lin/skrlmt.c
--- oldtree/drivers/net/sk98lin/skrlmt.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/sk98lin/skrlmt.c	2006-02-21 15:58:15.476793728 +0000
@@ -282,7 +282,6 @@
 
 SK_MAC_ADDR	SkRlmtMcAddr =	{{0x01,  0x00,  0x5A,  0x52,  0x4C,  0x4D}};
 SK_MAC_ADDR	BridgeMcAddr =	{{0x01,  0x80,  0xC2,  0x00,  0x00,  0x00}};
-SK_MAC_ADDR	BcAddr = 		{{0xFF,  0xFF,  0xFF,  0xFF,  0xFF,  0xFF}};
 
 /* local variables ************************************************************/
 
diff -urN oldtree/drivers/net/sk98lin/skvpd.c newtree/drivers/net/sk98lin/skvpd.c
--- oldtree/drivers/net/sk98lin/skvpd.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/sk98lin/skvpd.c	2006-02-21 15:58:15.478793424 +0000
@@ -132,65 +132,6 @@
 
 #endif	/* SKDIAG */
 
-#if 0
-
-/*
-	Write the dword 'data' at address 'addr' into the VPD EEPROM, and
-	verify that the data is written.
-
- Needed Time:
-
-.				MIN		MAX
-. -------------------------------------------------------------------
-. write				1.8 ms		3.6 ms
-. internal write cyles		0.7 ms		7.0 ms
-. -------------------------------------------------------------------
-. over all program time	 	2.5 ms		10.6 ms
-. read				1.3 ms		2.6 ms
-. -------------------------------------------------------------------
-. over all 			3.8 ms		13.2 ms
-.
-
-
- Returns	0:	success
-			1:	error,	I2C transfer does not terminate
-			2:	error,	data verify error
-
- */
-static int VpdWriteDWord(
-SK_AC	*pAC,	/* pAC pointer */
-SK_IOC	IoC,	/* IO Context */
-int		addr,	/* VPD address */
-SK_U32	data)	/* VPD data to write */
-{
-	/* start VPD write */
-	/* Don't swap here, it's a data stream of bytes */
-	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
-		("VPD write dword at addr 0x%x, data = 0x%x\n",addr,data));
-	VPD_OUT32(pAC, IoC, PCI_VPD_DAT_REG, (SK_U32)data);
-	/* But do it here */
-	addr |= VPD_WRITE;
-
-	VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, (SK_U16)(addr | VPD_WRITE));
-
-	/* this may take up to 10,6 ms */
-	if (VpdWait(pAC, IoC, VPD_WRITE)) {
-		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
-			("Write Timed Out\n"));
-		return(1);
-	};
-
-	/* verify data */
-	if (VpdReadDWord(pAC, IoC, addr) != data) {
-		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
-			("Data Verify Error\n"));
-		return(2);
-	}
-	return(0);
-}	/* VpdWriteDWord */
-
-#endif	/* 0 */
-
 /*
  *	Read one Stream of 'len' bytes of VPD data, starting at 'addr' from
  *	or to the I2C EEPROM.
@@ -728,7 +669,7 @@
  *		6:	fatal VPD error
  *
  */
-int	VpdSetupPara(
+static int	VpdSetupPara(
 SK_AC	*pAC,		/* common data base */
 const char	*key,	/* keyword to insert */
 const char	*buf,	/* buffer with the keyword value */
@@ -1148,50 +1089,3 @@
 	return(0);
 }
 
-
-
-/*
- *	Read the contents of the VPD EEPROM and copy it to the VPD buffer
- *	if not already done. If the keyword "VF" is not present it will be
- *	created and the error log message will be stored to this keyword.
- *	If "VF" is not present the error log message will be stored to the
- *	keyword "VL". "VL" will created or overwritten if "VF" is present.
- *	The VPD read/write area is saved to the VPD EEPROM.
- *
- * returns nothing, errors will be ignored.
- */
-void VpdErrLog(
-SK_AC	*pAC,	/* common data base */
-SK_IOC	IoC,	/* IO Context */
-char	*msg)	/* error log message */
-{
-	SK_VPD_PARA *v, vf;	/* VF */
-	int len;
-
-	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX,
-		("VPD error log msg %s\n", msg));
-	if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
-		if (VpdInit(pAC, IoC) != 0) {
-			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
-				("VPD init error\n"));
-			return;
-		}
-	}
-
-	len = strlen(msg);
-	if (len > VPD_MAX_LEN) {
-		/* cut it */
-		len = VPD_MAX_LEN;
-	}
-	if ((v = vpd_find_para(pAC, VPD_VF, &vf)) != NULL) {
-		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("overwrite VL\n"));
-		(void)VpdSetupPara(pAC, VPD_VL, msg, len, VPD_RW_KEY, OWR_KEY);
-	}
-	else {
-		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("write VF\n"));
-		(void)VpdSetupPara(pAC, VPD_VF, msg, len, VPD_RW_KEY, ADD_KEY);
-	}
-
-	(void)VpdUpdate(pAC, IoC);
-}
-
diff -urN oldtree/drivers/net/sk98lin/skxmac2.c newtree/drivers/net/sk98lin/skxmac2.c
--- oldtree/drivers/net/sk98lin/skxmac2.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/sk98lin/skxmac2.c	2006-02-21 15:58:15.481792968 +0000
@@ -41,13 +41,13 @@
 #endif
 
 #ifdef GENESIS
-BCOM_HACK BcomRegA1Hack[] = {
+static BCOM_HACK BcomRegA1Hack[] = {
  { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1104 }, { 0x17, 0x0013 },
  { 0x15, 0x0404 }, { 0x17, 0x8006 }, { 0x15, 0x0132 }, { 0x17, 0x8006 },
  { 0x15, 0x0232 }, { 0x17, 0x800D }, { 0x15, 0x000F }, { 0x18, 0x0420 },
  { 0, 0 }
 };
-BCOM_HACK BcomRegC0Hack[] = {
+static BCOM_HACK BcomRegC0Hack[] = {
  { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1204 }, { 0x17, 0x0013 },
  { 0x15, 0x0A04 }, { 0x18, 0x0420 },
  { 0, 0 }
@@ -790,7 +790,7 @@
  * Returns:
  *	nothing
  */
-void SkMacFlushRxFifo(
+static void SkMacFlushRxFifo(
 SK_AC	*pAC,	/* adapter context */
 SK_IOC	IoC,	/* IO context */
 int		Port)	/* Port Index (MAC_1 + n) */
@@ -1231,38 +1231,6 @@
 }	/* SkMacHardRst */
 
 
-/******************************************************************************
- *
- *	SkMacClearRst() - Clear the MAC reset
- *
- * Description:	calls a clear MAC reset routine dep. on board type
- *
- * Returns:
- *	nothing
- */
-void SkMacClearRst(
-SK_AC	*pAC,	/* adapter context */
-SK_IOC	IoC,	/* IO context */
-int		Port)	/* Port Index (MAC_1 + n) */
-{
-	
-#ifdef GENESIS
-	if (pAC->GIni.GIGenesis) {
-		
-		SkXmClearRst(pAC, IoC, Port);
-	}
-#endif /* GENESIS */
-	
-#ifdef YUKON
-	if (pAC->GIni.GIYukon) {
-		
-		SkGmClearRst(pAC, IoC, Port);
-	}
-#endif /* YUKON */
-
-}	/* SkMacClearRst */
-
-
 #ifdef GENESIS
 /******************************************************************************
  *
@@ -1713,7 +1681,7 @@
  * Returns:
  *	nothing
  */
-void SkXmInitDupMd(
+static void SkXmInitDupMd(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		Port)		/* Port Index (MAC_1 + n) */
@@ -1761,7 +1729,7 @@
  * Returns:
  *	nothing
  */
-void SkXmInitPauseMd(
+static void SkXmInitPauseMd(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		Port)		/* Port Index (MAC_1 + n) */
@@ -2076,283 +2044,7 @@
 }	/* SkXmInitPhyBcom */
 #endif /* GENESIS */
 
-
 #ifdef YUKON
-#ifndef SK_SLIM
-/******************************************************************************
- *
- *	SkGmEnterLowPowerMode()
- *
- * Description:	
- *	This function sets the Marvell Alaska PHY to the low power mode
- *	given by parameter mode.
- *	The following low power modes are available:
- *		
- *		- Coma Mode (Deep Sleep):
- *			Power consumption: ~15 - 30 mW
- *			The PHY cannot wake up on its own.
- *
- *		- IEEE 22.2.4.1.5 compatible power down mode
- *			Power consumption: ~240 mW
- *			The PHY cannot wake up on its own.
- *
- *		- energy detect mode
- *			Power consumption: ~160 mW
- *			The PHY can wake up on its own by detecting activity
- *			on the CAT 5 cable.
- *
- *		- energy detect plus mode
- *			Power consumption: ~150 mW
- *			The PHY can wake up on its own by detecting activity
- *			on the CAT 5 cable.
- *			Connected devices can be woken up by sending normal link
- *			pulses every one second.
- *
- * Note:
- *
- * Returns:
- *		0: ok
- *		1: error
- */
-int SkGmEnterLowPowerMode(
-SK_AC	*pAC,		/* adapter context */
-SK_IOC	IoC,		/* IO context */
-int		Port,		/* Port Index (e.g. MAC_1) */
-SK_U8	Mode)		/* low power mode */
-{
-	SK_U16	Word;
-	SK_U32	DWord;
-	SK_U8	LastMode;
-	int		Ret = 0;
-
-	if (pAC->GIni.GIYukonLite &&
-	    pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3) {
-
-		/* save current power mode */
-		LastMode = pAC->GIni.GP[Port].PPhyPowerState;
-		pAC->GIni.GP[Port].PPhyPowerState = Mode;
-
-		switch (Mode) {
-			/* coma mode (deep sleep) */
-			case PHY_PM_DEEP_SLEEP:
-				/* setup General Purpose Control Register */
-				GM_OUT16(IoC, 0, GM_GP_CTRL, GM_GPCR_FL_PASS |
-					GM_GPCR_SPEED_100 | GM_GPCR_AU_ALL_DIS);
-
-				/* apply COMA mode workaround */
-				SkGmPhyWrite(pAC, IoC, Port, 29, 0x001f);
-				SkGmPhyWrite(pAC, IoC, Port, 30, 0xfff3);
-
-				SK_IN32(IoC, PCI_C(PCI_OUR_REG_1), &DWord);
-
-				SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
-				
-				/* Set PHY to Coma Mode */
-				SK_OUT32(IoC, PCI_C(PCI_OUR_REG_1), DWord | PCI_PHY_COMA);
-				
-				SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
-
-			break;
-			
-			/* IEEE 22.2.4.1.5 compatible power down mode */
-			case PHY_PM_IEEE_POWER_DOWN:
-				/*
-				 * - disable MAC 125 MHz clock
-				 * - allow MAC power down
-				 */
-				SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word);
-				Word |= PHY_M_PC_DIS_125CLK;
-				Word &=	~PHY_M_PC_MAC_POW_UP;
-				SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word);
-
-				/*
-				 * register changes must be followed by a software
-				 * reset to take effect
-				 */
-				SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word);
-				Word |= PHY_CT_RESET;
-				SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word);
-
-				/* switch IEEE compatible power down mode on */
-				SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word);
-				Word |= PHY_CT_PDOWN;
-				SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word);
-			break;
-
-			/* energy detect and energy detect plus mode */
-			case PHY_PM_ENERGY_DETECT:
-			case PHY_PM_ENERGY_DETECT_PLUS:
-				/*
-				 * - disable MAC 125 MHz clock
-				 */
-				SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word);
-				Word |= PHY_M_PC_DIS_125CLK;
-				SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word);
-				
-				/* activate energy detect mode 1 */
-				SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word);
-
-				/* energy detect mode */
-				if (Mode == PHY_PM_ENERGY_DETECT) {
-					Word |= PHY_M_PC_EN_DET;
-				}
-				/* energy detect plus mode */
-				else {
-					Word |= PHY_M_PC_EN_DET_PLUS;
-				}
-
-				SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word);
-
-				/*
-				 * reinitialize the PHY to force a software reset
-				 * which is necessary after the register settings
-				 * for the energy detect modes.
-				 * Furthermore reinitialisation prevents that the
-				 * PHY is running out of a stable state.
-				 */
-				SkGmInitPhyMarv(pAC, IoC, Port, SK_FALSE);
-			break;
-
-			/* don't change current power mode */
-			default:
-				pAC->GIni.GP[Port].PPhyPowerState = LastMode;
-				Ret = 1;
-			break;
-		}
-	}
-	/* low power modes are not supported by this chip */
-	else {
-		Ret = 1;
-	}
-
-	return(Ret);
-
-}	/* SkGmEnterLowPowerMode */
-
-/******************************************************************************
- *
- *	SkGmLeaveLowPowerMode()
- *
- * Description:	
- *	Leave the current low power mode and switch to normal mode
- *
- * Note:
- *
- * Returns:
- *		0:	ok
- *		1:	error
- */
-int SkGmLeaveLowPowerMode(
-SK_AC	*pAC,		/* adapter context */
-SK_IOC	IoC,		/* IO context */
-int		Port)		/* Port Index (e.g. MAC_1) */
-{
-	SK_U32	DWord;
-	SK_U16	Word;
-	SK_U8	LastMode;
-	int		Ret = 0;
-
-	if (pAC->GIni.GIYukonLite &&
-		pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3) {
-
-		/* save current power mode */
-		LastMode = pAC->GIni.GP[Port].PPhyPowerState;
-		pAC->GIni.GP[Port].PPhyPowerState = PHY_PM_OPERATIONAL_MODE;
-
-		switch (LastMode) {
-			/* coma mode (deep sleep) */
-			case PHY_PM_DEEP_SLEEP:
-				SK_IN32(IoC, PCI_C(PCI_OUR_REG_1), &DWord);
-
-				SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
-				
-				/* Release PHY from Coma Mode */
-				SK_OUT32(IoC, PCI_C(PCI_OUR_REG_1), DWord & ~PCI_PHY_COMA);
-				
-				SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
-				
-				SK_IN32(IoC, B2_GP_IO, &DWord);
-
-				/* set to output */
-				DWord |= (GP_DIR_9 | GP_IO_9);
-
-				/* set PHY reset */
-				SK_OUT32(IoC, B2_GP_IO, DWord);
-
-				DWord &= ~GP_IO_9; /* clear PHY reset (active high) */
-
-				/* clear PHY reset */
-				SK_OUT32(IoC, B2_GP_IO, DWord);
-			break;
-			
-			/* IEEE 22.2.4.1.5 compatible power down mode */
-			case PHY_PM_IEEE_POWER_DOWN:
-				/*
-				 * - enable MAC 125 MHz clock
-				 * - set MAC power up
-				 */
-				SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word);
-				Word &= ~PHY_M_PC_DIS_125CLK;
-				Word |=	PHY_M_PC_MAC_POW_UP;
-				SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word);
-
-				/*
-				 * register changes must be followed by a software
-				 * reset to take effect
-				 */
-				SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word);
-				Word |= PHY_CT_RESET;
-				SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word);
-
-				/* switch IEEE compatible power down mode off */
-				SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word);
-				Word &= ~PHY_CT_PDOWN;
-				SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word);
-			break;
-
-			/* energy detect and energy detect plus mode */
-			case PHY_PM_ENERGY_DETECT:
-			case PHY_PM_ENERGY_DETECT_PLUS:
-				/*
-				 * - enable MAC 125 MHz clock
-				 */
-				SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word);
-				Word &= ~PHY_M_PC_DIS_125CLK;
-				SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word);
-				
-				/* disable energy detect mode */
-				SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word);
-				Word &= ~PHY_M_PC_EN_DET_MSK;
-				SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word);
-
-				/*
-				 * reinitialize the PHY to force a software reset
-				 * which is necessary after the register settings
-				 * for the energy detect modes.
-				 * Furthermore reinitialisation prevents that the
-				 * PHY is running out of a stable state.
-				 */
-				SkGmInitPhyMarv(pAC, IoC, Port, SK_FALSE);
-			break;
-
-			/* don't change current power mode */
-			default:
-				pAC->GIni.GP[Port].PPhyPowerState = LastMode;
-				Ret = 1;
-			break;
-		}
-	}
-	/* low power modes are not supported by this chip */
-	else {
-		Ret = 1;
-	}
-
-	return(Ret);
-
-}	/* SkGmLeaveLowPowerMode */
-#endif /* !SK_SLIM */
-
-
 /******************************************************************************
  *
  *	SkGmInitPhyMarv() - Initialize the Marvell Phy registers
@@ -3420,145 +3112,6 @@
 }	/* SkMacAutoNegDone */
 
 
-#ifdef GENESIS
-/******************************************************************************
- *
- *	SkXmSetRxTxEn() - Special Set Rx/Tx Enable and some features in XMAC
- *
- * Description:
- *  sets MAC or PHY LoopBack and Duplex Mode in the MMU Command Reg.
- *  enables Rx/Tx
- *
- * Returns: N/A
- */
-static void SkXmSetRxTxEn(
-SK_AC	*pAC,		/* Adapter Context */
-SK_IOC	IoC,		/* IO context */
-int		Port,		/* Port Index (MAC_1 + n) */
-int		Para)		/* Parameter to set: MAC or PHY LoopBack, Duplex Mode */
-{
-	SK_U16	Word;
-
-	XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
-
-	switch (Para & (SK_MAC_LOOPB_ON | SK_MAC_LOOPB_OFF)) {
-	case SK_MAC_LOOPB_ON:
-		Word |= XM_MMU_MAC_LB;
-		break;
-	case SK_MAC_LOOPB_OFF:
-		Word &= ~XM_MMU_MAC_LB;
-		break;
-	}
-
-	switch (Para & (SK_PHY_LOOPB_ON | SK_PHY_LOOPB_OFF)) {
-	case SK_PHY_LOOPB_ON:
-		Word |= XM_MMU_GMII_LOOP;
-		break;
-	case SK_PHY_LOOPB_OFF:
-		Word &= ~XM_MMU_GMII_LOOP;
-		break;
-	}
-	
-	switch (Para & (SK_PHY_FULLD_ON | SK_PHY_FULLD_OFF)) {
-	case SK_PHY_FULLD_ON:
-		Word |= XM_MMU_GMII_FD;
-		break;
-	case SK_PHY_FULLD_OFF:
-		Word &= ~XM_MMU_GMII_FD;
-		break;
-	}
-	
-	XM_OUT16(IoC, Port, XM_MMU_CMD, Word | XM_MMU_ENA_RX | XM_MMU_ENA_TX);
-
-	/* dummy read to ensure writing */
-	XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
-
-}	/* SkXmSetRxTxEn */
-#endif /* GENESIS */
-
-
-#ifdef YUKON
-/******************************************************************************
- *
- *	SkGmSetRxTxEn() - Special Set Rx/Tx Enable and some features in GMAC
- *
- * Description:
- *  sets MAC LoopBack and Duplex Mode in the General Purpose Control Reg.
- *  enables Rx/Tx
- *
- * Returns: N/A
- */
-static void SkGmSetRxTxEn(
-SK_AC	*pAC,		/* Adapter Context */
-SK_IOC	IoC,		/* IO context */
-int		Port,		/* Port Index (MAC_1 + n) */
-int		Para)		/* Parameter to set: MAC LoopBack, Duplex Mode */
-{
-	SK_U16	Ctrl;
-	
-	GM_IN16(IoC, Port, GM_GP_CTRL, &Ctrl);
-
-	switch (Para & (SK_MAC_LOOPB_ON | SK_MAC_LOOPB_OFF)) {
-	case SK_MAC_LOOPB_ON:
-		Ctrl |= GM_GPCR_LOOP_ENA;
-		break;
-	case SK_MAC_LOOPB_OFF:
-		Ctrl &= ~GM_GPCR_LOOP_ENA;
-		break;
-	}
-
-	switch (Para & (SK_PHY_FULLD_ON | SK_PHY_FULLD_OFF)) {
-	case SK_PHY_FULLD_ON:
-		Ctrl |= GM_GPCR_DUP_FULL;
-		break;
-	case SK_PHY_FULLD_OFF:
-		Ctrl &= ~GM_GPCR_DUP_FULL;
-		break;
-	}
-	
-    GM_OUT16(IoC, Port, GM_GP_CTRL, (SK_U16)(Ctrl | GM_GPCR_RX_ENA |
-		GM_GPCR_TX_ENA));
-
-	/* dummy read to ensure writing */
-	GM_IN16(IoC, Port, GM_GP_CTRL, &Ctrl);
-
-}	/* SkGmSetRxTxEn */
-#endif /* YUKON */
-
-
-#ifndef SK_SLIM
-/******************************************************************************
- *
- *	SkMacSetRxTxEn() - Special Set Rx/Tx Enable and parameters
- *
- * Description:	calls the Special Set Rx/Tx Enable routines dep. on board type
- *
- * Returns: N/A
- */
-void SkMacSetRxTxEn(
-SK_AC	*pAC,		/* Adapter Context */
-SK_IOC	IoC,		/* IO context */
-int		Port,		/* Port Index (MAC_1 + n) */
-int		Para)
-{
-#ifdef GENESIS
-	if (pAC->GIni.GIGenesis) {
-		
-		SkXmSetRxTxEn(pAC, IoC, Port, Para);
-	}
-#endif /* GENESIS */
-	
-#ifdef YUKON
-	if (pAC->GIni.GIYukon) {
-		
-		SkGmSetRxTxEn(pAC, IoC, Port, Para);
-	}
-#endif /* YUKON */
-
-}	/* SkMacSetRxTxEn */
-#endif /* !SK_SLIM */
-
-
 /******************************************************************************
  *
  *	SkMacRxTxEnable() - Enable Rx/Tx activity if port is up
@@ -3976,7 +3529,7 @@
  * Returns:
  *	nothing
  */
-void SkXmIrq(
+static void SkXmIrq(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		Port)		/* Port Index (MAC_1 + n) */
@@ -4112,7 +3665,7 @@
  * Returns:
  *	nothing
  */
-void SkGmIrq(
+static void SkGmIrq(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		Port)		/* Port Index (MAC_1 + n) */
diff -urN oldtree/drivers/net/sky2.c newtree/drivers/net/sky2.c
--- oldtree/drivers/net/sky2.c	2006-02-19 11:41:03.353833240 +0000
+++ newtree/drivers/net/sky2.c	2006-02-21 15:58:15.994714992 +0000
@@ -28,6 +28,7 @@
 #include <linux/kernel.h>
 #include <linux/version.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/netdevice.h>
 #include <linux/dma-mapping.h>
 #include <linux/etherdevice.h>
@@ -483,9 +484,9 @@
 /* Force a renegotiation */
 static void sky2_phy_reinit(struct sky2_port *sky2)
 {
-	down(&sky2->phy_sema);
+	mutex_lock(&sky2->phy_mutex);
 	sky2_phy_init(sky2->hw, sky2->port);
-	up(&sky2->phy_sema);
+	mutex_unlock(&sky2->phy_mutex);
 }
 
 static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
@@ -550,9 +551,9 @@
 
 	sky2_read16(hw, SK_REG(port, GMAC_IRQ_SRC));
 
-	down(&sky2->phy_sema);
+	mutex_lock(&sky2->phy_mutex);
 	sky2_phy_init(hw, port);
-	up(&sky2->phy_sema);
+	mutex_unlock(&sky2->phy_mutex);
 
 	/* MIB clear */
 	reg = gma_read16(hw, port, GM_PHY_ADDR);
@@ -865,9 +866,9 @@
 	case SIOCGMIIREG: {
 		u16 val = 0;
 
-		down(&sky2->phy_sema);
+		mutex_lock(&sky2->phy_mutex);
 		err = __gm_phy_read(hw, sky2->port, data->reg_num & 0x1f, &val);
-		up(&sky2->phy_sema);
+		mutex_unlock(&sky2->phy_mutex);
 
 		data->val_out = val;
 		break;
@@ -877,10 +878,10 @@
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 
-		down(&sky2->phy_sema);
+		mutex_lock(&sky2->phy_mutex);
 		err = gm_phy_write(hw, sky2->port, data->reg_num & 0x1f,
 				   data->val_in);
-		up(&sky2->phy_sema);
+		mutex_unlock(&sky2->phy_mutex);
 		break;
 	}
 	return err;
@@ -1603,7 +1604,7 @@
 	struct sky2_hw *hw = sky2->hw;
 	u16 istatus, phystat;
 
-	down(&sky2->phy_sema);
+	mutex_lock(&sky2->phy_mutex);
 	istatus = gm_phy_read(hw, sky2->port, PHY_MARV_INT_STAT);
 	phystat = gm_phy_read(hw, sky2->port, PHY_MARV_PHY_STAT);
 
@@ -1631,7 +1632,7 @@
 			sky2_link_down(sky2);
 	}
 out:
-	up(&sky2->phy_sema);
+	mutex_unlock(&sky2->phy_mutex);
 
 	local_irq_disable();
 	hw->intr_mask |= (sky2->port == 0) ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2;
@@ -1860,6 +1861,7 @@
 	unsigned int work_done = 0;
 	u16 hwidx;
 	u16 tx_done[2] = { TX_NO_STATUS, TX_NO_STATUS };
+	int done;
 
 	sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
 
@@ -1942,25 +1944,35 @@
 	}
 
 exit_loop:
+
+	*budget -= work_done;
+	dev0->quota -= work_done;
+
 	sky2_tx_check(hw, 0, tx_done[0]);
 	sky2_tx_check(hw, 1, tx_done[1]);
 
-	if (likely(work_done < to_do)) {
+	done = sky2_read16(hw, STAT_PUT_IDX) == hw->st_idx;
+	if (done) {
 		/* need to restart TX timer */
 		if (is_ec_a1(hw)) {
 			sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP);
 			sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
 		}
 
+		/* Kick status timer, it seems that status timer is not
+		 * reset on clear??
+		 */
+		if (sky2_read8(hw, STAT_LEV_TIMER_CTRL) == TIM_START) {
+			sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_STOP);
+			sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_START);
+		}
+
 		netif_rx_complete(dev0);
 		hw->intr_mask |= Y2_IS_STAT_BMU;
 		sky2_write32(hw, B0_IMSK, hw->intr_mask);
-		return 0;
-	} else {
-		*budget -= work_done;
-		dev0->quota -= work_done;
-		return 1;
 	}
+
+	return !done;
 }
 
 static void sky2_hw_error(struct sky2_hw *hw, unsigned port, u32 status)
@@ -2702,7 +2714,7 @@
 		ms = data * 1000;
 
 	/* save initial values */
-	down(&sky2->phy_sema);
+	mutex_lock(&sky2->phy_mutex);
 	if (hw->chip_id == CHIP_ID_YUKON_XL) {
 		u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
 		gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
@@ -2718,9 +2730,9 @@
 		sky2_led(hw, port, onoff);
 		onoff = !onoff;
 
-		up(&sky2->phy_sema);
+		mutex_unlock(&sky2->phy_mutex);
 		interrupted = msleep_interruptible(250);
-		down(&sky2->phy_sema);
+		mutex_lock(&sky2->phy_mutex);
 
 		ms -= 250;
 	}
@@ -2735,7 +2747,7 @@
 		gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
 		gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
 	}
-	up(&sky2->phy_sema);
+	mutex_unlock(&sky2->phy_mutex);
 
 	return 0;
 }
@@ -3048,7 +3060,7 @@
 	sky2->rx_csum = (hw->chip_id != CHIP_ID_YUKON_XL);
 
 	INIT_WORK(&sky2->phy_task, sky2_phy_task, sky2);
-	init_MUTEX(&sky2->phy_sema);
+	mutex_init(&sky2->phy_mutex);
 	sky2->tx_pending = TX_DEF_PENDING;
 	sky2->rx_pending = is_ec_a1(hw) ? 8 : RX_DEF_PENDING;
 	sky2->rx_bufsize = sky2_buf_size(ETH_DATA_LEN);
diff -urN oldtree/drivers/net/sky2.h newtree/drivers/net/sky2.h
--- oldtree/drivers/net/sky2.h	2006-02-19 11:41:03.356832784 +0000
+++ newtree/drivers/net/sky2.h	2006-02-21 15:58:16.006713168 +0000
@@ -1831,7 +1831,7 @@
 	struct net_device_stats net_stats;
 
 	struct work_struct   phy_task;
-	struct semaphore     phy_sema;
+	struct mutex	     phy_mutex;
 };
 
 struct sky2_hw {
diff -urN oldtree/drivers/net/smc91x.c newtree/drivers/net/smc91x.c
--- oldtree/drivers/net/smc91x.c	2006-02-19 11:41:03.361832024 +0000
+++ newtree/drivers/net/smc91x.c	2006-02-21 15:58:12.496246840 +0000
@@ -2221,6 +2221,10 @@
 
 	ndev->dma = (unsigned char)-1;
 	ndev->irq = platform_get_irq(pdev, 0);
+	if (ndev->irq < 0) {
+		ret = -ENODEV;
+		goto out_free_netdev;
+	}
 
 	ret = smc_request_attrib(pdev);
 	if (ret)
diff -urN oldtree/drivers/net/starfire.c newtree/drivers/net/starfire.c
--- oldtree/drivers/net/starfire.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/starfire.c	2006-02-21 15:58:15.486792208 +0000
@@ -2084,6 +2084,38 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int starfire_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+
+	if (netif_running(dev)) {
+		netif_device_detach(dev);
+		netdev_close(dev);
+	}
+
+	pci_save_state(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev,state));
+
+	return 0;
+}
+
+static int starfire_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+
+	if (netif_running(dev)) {
+		netdev_open(dev);
+		netif_device_attach(dev);
+	}
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
 
 static void __devexit starfire_remove_one (struct pci_dev *pdev)
 {
@@ -2115,6 +2147,10 @@
 	.name		= DRV_NAME,
 	.probe		= starfire_init_one,
 	.remove		= __devexit_p(starfire_remove_one),
+#ifdef CONFIG_PM
+	.suspend	= starfire_suspend,
+	.resume		= starfire_resume,
+#endif /* CONFIG_PM */
 	.id_table	= starfire_pci_tbl,
 };
 
diff -urN oldtree/drivers/net/sundance.c newtree/drivers/net/sundance.c
--- oldtree/drivers/net/sundance.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/sundance.c	2006-02-21 15:58:15.490791600 +0000
@@ -633,9 +633,13 @@
 
 	np->phys[0] = 1;		/* Default setting */
 	np->mii_preamble_required++;
+	/*
+	 * It seems some phys doesn't deal well with address 0 being accessed
+	 * first, so leave address zero to the end of the loop (32 & 31).
+	 */
 	for (phy = 1; phy <= 32 && phy_idx < MII_CNT; phy++) {
-		int mii_status = mdio_read(dev, phy, MII_BMSR);
 		int phyx = phy & 0x1f;
+		int mii_status = mdio_read(dev, phyx, MII_BMSR);
 		if (mii_status != 0xffff  &&  mii_status != 0x0000) {
 			np->phys[phy_idx++] = phyx;
 			np->mii_if.advertising = mdio_read(dev, phyx, MII_ADVERTISE);
diff -urN oldtree/drivers/net/sungem.c newtree/drivers/net/sungem.c
--- oldtree/drivers/net/sungem.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/sungem.c	2006-02-21 15:58:16.680610720 +0000
@@ -55,6 +55,7 @@
 #include <linux/workqueue.h>
 #include <linux/if_vlan.h>
 #include <linux/bitops.h>
+#include <linux/mutex.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -2284,7 +2285,7 @@
 {
 	struct gem *gp = (struct gem *) data;
 
-	down(&gp->pm_sem);
+	mutex_lock(&gp->pm_mutex);
 
 	netif_poll_disable(gp->dev);
 
@@ -2311,7 +2312,7 @@
 
 	netif_poll_enable(gp->dev);
 
-	up(&gp->pm_sem);
+	mutex_unlock(&gp->pm_mutex);
 }
 
 
@@ -2320,14 +2321,14 @@
 	struct gem *gp = dev->priv;
 	int rc = 0;
 
-	down(&gp->pm_sem);
+	mutex_lock(&gp->pm_mutex);
 
 	/* We need the cell enabled */
 	if (!gp->asleep)
 		rc = gem_do_start(dev);
 	gp->opened = (rc == 0);
 
-	up(&gp->pm_sem);
+	mutex_unlock(&gp->pm_mutex);
 
 	return rc;
 }
@@ -2340,13 +2341,13 @@
 	 * our caller (dev_close) already did it for us
 	 */
 
-	down(&gp->pm_sem);
+	mutex_lock(&gp->pm_mutex);
 
 	gp->opened = 0;	
 	if (!gp->asleep)
 		gem_do_stop(dev, 0);
 
-	up(&gp->pm_sem);
+	mutex_unlock(&gp->pm_mutex);
 	
 	return 0;
 }
@@ -2358,7 +2359,7 @@
 	struct gem *gp = dev->priv;
 	unsigned long flags;
 
-	down(&gp->pm_sem);
+	mutex_lock(&gp->pm_mutex);
 
 	netif_poll_disable(dev);
 
@@ -2391,11 +2392,11 @@
 	/* Stop the link timer */
 	del_timer_sync(&gp->link_timer);
 
-	/* Now we release the semaphore to not block the reset task who
+	/* Now we release the mutex to not block the reset task who
 	 * can take it too. We are marked asleep, so there will be no
 	 * conflict here
 	 */
-	up(&gp->pm_sem);
+	mutex_unlock(&gp->pm_mutex);
 
 	/* Wait for a pending reset task to complete */
 	while (gp->reset_task_pending)
@@ -2424,7 +2425,7 @@
 
 	printk(KERN_INFO "%s: resuming\n", dev->name);
 
-	down(&gp->pm_sem);
+	mutex_lock(&gp->pm_mutex);
 
 	/* Keep the cell enabled during the entire operation, no need to
 	 * take a lock here tho since nothing else can happen while we are
@@ -2440,7 +2441,7 @@
 		 * still asleep, a new sleep cycle may bring it back
 		 */
 		gem_put_cell(gp);
-		up(&gp->pm_sem);
+		mutex_unlock(&gp->pm_mutex);
 		return 0;
 	}
 	pci_set_master(gp->pdev);
@@ -2486,7 +2487,7 @@
 
 	netif_poll_enable(dev);
 	
-	up(&gp->pm_sem);
+	mutex_unlock(&gp->pm_mutex);
 
 	return 0;
 }
@@ -2591,7 +2592,7 @@
 		return 0;
 	}
 
-	down(&gp->pm_sem);
+	mutex_lock(&gp->pm_mutex);
 	spin_lock_irq(&gp->lock);
 	spin_lock(&gp->tx_lock);
 	dev->mtu = new_mtu;
@@ -2602,7 +2603,7 @@
 	}
 	spin_unlock(&gp->tx_lock);
 	spin_unlock_irq(&gp->lock);
-	up(&gp->pm_sem);
+	mutex_unlock(&gp->pm_mutex);
 
 	return 0;
 }
@@ -2771,10 +2772,10 @@
 	int rc = -EOPNOTSUPP;
 	unsigned long flags;
 
-	/* Hold the PM semaphore while doing ioctl's or we may collide
+	/* Hold the PM mutex while doing ioctl's or we may collide
 	 * with power management.
 	 */
-	down(&gp->pm_sem);
+	mutex_lock(&gp->pm_mutex);
 		
 	spin_lock_irqsave(&gp->lock, flags);
 	gem_get_cell(gp);
@@ -2812,7 +2813,7 @@
 	gem_put_cell(gp);
 	spin_unlock_irqrestore(&gp->lock, flags);
 
-	up(&gp->pm_sem);
+	mutex_unlock(&gp->pm_mutex);
 	
 	return rc;
 }
@@ -3033,7 +3034,7 @@
 
 	spin_lock_init(&gp->lock);
 	spin_lock_init(&gp->tx_lock);
-	init_MUTEX(&gp->pm_sem);
+	mutex_init(&gp->pm_mutex);
 
 	init_timer(&gp->link_timer);
 	gp->link_timer.function = gem_link_timer;
diff -urN oldtree/drivers/net/sungem.h newtree/drivers/net/sungem.h
--- oldtree/drivers/net/sungem.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/sungem.h	2006-02-21 15:58:16.691609048 +0000
@@ -980,15 +980,15 @@
 	int			tx_new, tx_old;
 
 	unsigned int has_wol : 1;	/* chip supports wake-on-lan */
-	unsigned int asleep : 1;	/* chip asleep, protected by pm_sem */
+	unsigned int asleep : 1;	/* chip asleep, protected by pm_mutex */
 	unsigned int asleep_wol : 1;	/* was asleep with WOL enabled */
-	unsigned int opened : 1;	/* driver opened, protected by pm_sem */
+	unsigned int opened : 1;	/* driver opened, protected by pm_mutex */
 	unsigned int running : 1;	/* chip running, protected by lock */
 	
 	/* cell enable count, protected by lock */
 	int			cell_enabled;  
 	
-	struct semaphore	pm_sem;
+	struct mutex		pm_mutex;
 
 	u32			msg_enable;
 	u32			status;
diff -urN oldtree/drivers/net/sunhme.c newtree/drivers/net/sunhme.c
--- oldtree/drivers/net/sunhme.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/sunhme.c	2006-02-21 15:58:16.837586856 +0000
@@ -3013,7 +3013,7 @@
 }
 #endif /* !(__sparc__) */
 
-static int __init happy_meal_pci_init(struct pci_dev *pdev)
+static int __devinit happy_meal_pci_init(struct pci_dev *pdev)
 {
 	struct quattro *qp = NULL;
 #ifdef __sparc__
@@ -3073,6 +3073,7 @@
 	memset(hp, 0, sizeof(*hp));
 
 	hp->happy_dev = pdev;
+	pci_dev_get(pdev);
 
 	spin_lock_init(&hp->happy_lock);
 
@@ -3260,6 +3261,7 @@
 	pci_release_regions(pdev);
 
 err_out_clear_quattro:
+	pci_dev_put(pdev);
 	if (qp != NULL)
 		qp->happy_meals[qfe_slot] = NULL;
 
@@ -3304,21 +3306,58 @@
 #endif
 
 #ifdef CONFIG_PCI
-static int __init happy_meal_pci_probe(void)
+static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
+	const struct pci_device_id *id)
 {
-	struct pci_dev *pdev = NULL;
-	int cards = 0;
+	int retval;
+
+	retval = pci_enable_device(pdev);
+	if (retval < 0)
+		goto err;
+
+	pci_set_master(pdev);
+	happy_meal_pci_init(pdev);
+
+	return 0;
+err:
+	return retval;
+}
 
-	while ((pdev = pci_find_device(PCI_VENDOR_ID_SUN,
-				       PCI_DEVICE_ID_SUN_HAPPYMEAL, pdev)) != NULL) {
-		if (pci_enable_device(pdev))
-			continue;
-		pci_set_master(pdev);
-		cards++;
-		happy_meal_pci_init(pdev);
+static void __devexit happy_meal_pci_remove(struct pci_dev *pdev)
+{
+	struct quattro *tmp, *qp = qfe_pci_list;
+	struct pci_dev *bdev = pdev->bus->self;
+
+	if (qp->quattro_dev == bdev) { /* is it the 1st one? */
+		qfe_pci_list = qp->next;
+		kfree(qp);
+		goto end;
 	}
-	return cards;
+
+	for (; qp->next != NULL; qp = qp->next) /* some further? */
+		if (qp->next->quattro_dev == bdev)
+			break;
+
+	tmp = qp->next; /* kill it, but preserve list */
+	qp->next = qp->next->next;
+	kfree(tmp);
+end:
+	pci_dev_put(pdev);
 }
+
+static struct pci_device_id happy_meal_pci_tbl[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_HAPPYMEAL) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, happy_meal_pci_tbl);
+
+static struct pci_driver happy_meal_pci_driver = {
+	.name		= "happy_meal_pci",
+	.id_table	= happy_meal_pci_tbl,
+	.probe		= happy_meal_pci_probe,
+	.remove		= __devexit_p(happy_meal_pci_remove)
+};
+
 #endif
 
 static int __init happy_meal_probe(void)
@@ -3337,11 +3376,10 @@
 	cards += happy_meal_sbus_probe();
 #endif
 #ifdef CONFIG_PCI
-	cards += happy_meal_pci_probe();
+	return pci_register_driver(&happy_meal_pci_driver);
+#else
+	return cards ? 0 : -ENODEV;
 #endif
-	if (!cards)
-		return -ENODEV;
-	return 0;
 }
 
 
@@ -3408,14 +3446,7 @@
 	}
 #endif
 #ifdef CONFIG_PCI
-	while (qfe_pci_list) {
-		struct quattro *qfe = qfe_pci_list;
-		struct quattro *next = qfe->next;
-
-		kfree(qfe);
-
-		qfe_pci_list = next;
-	}
+	pci_unregister_driver(&happy_meal_pci_driver);
 #endif
 }
 
diff -urN oldtree/drivers/net/tg3.c newtree/drivers/net/tg3.c
--- oldtree/drivers/net/tg3.c	2006-02-19 11:41:03.371830504 +0000
+++ newtree/drivers/net/tg3.c	2006-02-21 15:58:16.164689152 +0000
@@ -69,8 +69,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"3.49"
-#define DRV_MODULE_RELDATE	"Feb 2, 2006"
+#define DRV_MODULE_VERSION	"3.50"
+#define DRV_MODULE_RELDATE	"Feb 4, 2006"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -223,8 +223,12 @@
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714S,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715S,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780S,
@@ -1038,9 +1042,11 @@
 		struct net_device *dev_peer;
 
 		dev_peer = pci_get_drvdata(tp->pdev_peer);
+		/* remove_one() may have been run on the peer. */
 		if (!dev_peer)
-			BUG();
-		tp_peer = netdev_priv(dev_peer);
+			tp_peer = tp;
+		else
+			tp_peer = netdev_priv(dev_peer);
 	}
 
 	if ((tp->tg3_flags & TG3_FLAG_WOL_ENABLE) != 0 ||
@@ -1131,7 +1137,7 @@
 static int tg3_nvram_lock(struct tg3 *);
 static void tg3_nvram_unlock(struct tg3 *);
 
-static int tg3_set_power_state(struct tg3 *tp, int state)
+static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
 {
 	u32 misc_host_ctrl;
 	u16 power_control, power_caps;
@@ -1150,7 +1156,7 @@
 	power_control |= PCI_PM_CTRL_PME_STATUS;
 	power_control &= ~(PCI_PM_CTRL_STATE_MASK);
 	switch (state) {
-	case 0:
+	case PCI_D0:
 		power_control |= 0;
 		pci_write_config_word(tp->pdev,
 				      pm + PCI_PM_CTRL,
@@ -1163,15 +1169,15 @@
 
 		return 0;
 
-	case 1:
+	case PCI_D1:
 		power_control |= 1;
 		break;
 
-	case 2:
+	case PCI_D2:
 		power_control |= 2;
 		break;
 
-	case 3:
+	case PCI_D3hot:
 		power_control |= 3;
 		break;
 
@@ -2680,6 +2686,12 @@
 
 	err |= tg3_readphy(tp, MII_BMSR, &bmsr);
 	err |= tg3_readphy(tp, MII_BMSR, &bmsr);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) {
+		if (tr32(MAC_TX_STATUS) & TX_STATUS_LINK_UP)
+			bmsr |= BMSR_LSTATUS;
+		else
+			bmsr &= ~BMSR_LSTATUS;
+	}
 
 	err |= tg3_readphy(tp, MII_BMCR, &bmcr);
 
@@ -2748,6 +2760,13 @@
 			bmcr = new_bmcr;
 			err |= tg3_readphy(tp, MII_BMSR, &bmsr);
 			err |= tg3_readphy(tp, MII_BMSR, &bmsr);
+			if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
+			    ASIC_REV_5714) {
+				if (tr32(MAC_TX_STATUS) & TX_STATUS_LINK_UP)
+					bmsr |= BMSR_LSTATUS;
+				else
+					bmsr &= ~BMSR_LSTATUS;
+			}
 			tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
 		}
 	}
@@ -5568,6 +5587,9 @@
 		tg3_abort_hw(tp, 1);
 	}
 
+	if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
+		tg3_phy_reset(tp);
+
 	err = tg3_chip_reset(tp);
 	if (err)
 		return err;
@@ -6080,6 +6102,17 @@
 		tp->tg3_flags2 |= TG3_FLG2_HW_AUTONEG;
 	}
 
+	if ((tp->tg3_flags2 & TG3_FLG2_MII_SERDES) &&
+	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)) {
+		u32 tmp;
+
+		tmp = tr32(SERDES_RX_CTRL);
+		tw32(SERDES_RX_CTRL, tmp | SERDES_RX_SIG_DETECT);
+		tp->grc_local_ctrl &= ~GRC_LCLCTRL_USE_EXT_SIG_DETECT;
+		tp->grc_local_ctrl |= GRC_LCLCTRL_USE_SIG_DETECT;
+		tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
+	}
+
 	err = tg3_setup_phy(tp, 1);
 	if (err)
 		return err;
@@ -6158,7 +6191,7 @@
 	int err;
 
 	/* Force the chip into D0. */
-	err = tg3_set_power_state(tp, 0);
+	err = tg3_set_power_state(tp, PCI_D0);
 	if (err)
 		goto out;
 
@@ -6445,6 +6478,10 @@
 
 	tg3_full_lock(tp, 0);
 
+	err = tg3_set_power_state(tp, PCI_D0);
+	if (err)
+		return err;
+
 	tg3_disable_ints(tp);
 	tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
 
@@ -6459,7 +6496,9 @@
 
 	if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
 	    (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_AX) &&
-	    (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_BX)) {
+	    (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_BX) &&
+	    !((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) &&
+	      (tp->pdev_peer == tp->pdev))) {
 		/* All MSI supporting chips should support tagged
 		 * status.  Assert that this is the case.
 		 */
@@ -6822,7 +6861,6 @@
 	tp->tg3_flags &=
 		~(TG3_FLAG_INIT_COMPLETE |
 		  TG3_FLAG_GOT_SERDES_FLOWCTL);
-	netif_carrier_off(tp->dev);
 
 	tg3_full_unlock(tp);
 
@@ -6839,6 +6877,10 @@
 
 	tg3_free_consistent(tp);
 
+	tg3_set_power_state(tp, PCI_D3hot);
+
+	netif_carrier_off(tp->dev);
+
 	return 0;
 }
 
@@ -7157,6 +7199,9 @@
 
 	memset(p, 0, TG3_REGDUMP_LEN);
 
+	if (tp->link_config.phy_is_low_power)
+		return;
+
 	tg3_full_lock(tp, 0);
 
 #define __GET_REG32(reg)	(*(p)++ = tr32(reg))
@@ -7231,6 +7276,9 @@
 	u8  *pd;
 	u32 i, offset, len, val, b_offset, b_count;
 
+	if (tp->link_config.phy_is_low_power)
+		return -EAGAIN;
+
 	offset = eeprom->offset;
 	len = eeprom->len;
 	eeprom->len = 0;
@@ -7292,6 +7340,9 @@
 	u32 offset, len, b_offset, odd_len, start, end;
 	u8 *buf;
 
+	if (tp->link_config.phy_is_low_power)
+		return -EAGAIN;
+
 	if (eeprom->magic != TG3_EEPROM_MAGIC)
 		return -EINVAL;
 
@@ -8212,6 +8263,9 @@
 {
 	struct tg3 *tp = netdev_priv(dev);
 
+	if (tp->link_config.phy_is_low_power)
+		tg3_set_power_state(tp, PCI_D0);
+
 	memset(data, 0, sizeof(u64) * TG3_NUM_TEST);
 
 	if (tg3_test_nvram(tp) != 0) {
@@ -8269,6 +8323,9 @@
 
 		tg3_full_unlock(tp);
 	}
+	if (tp->link_config.phy_is_low_power)
+		tg3_set_power_state(tp, PCI_D3hot);
+
 }
 
 static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -8288,6 +8345,9 @@
 		if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
 			break;			/* We have no PHY */
 
+		if (tp->link_config.phy_is_low_power)
+			return -EAGAIN;
+
 		spin_lock_bh(&tp->lock);
 		err = tg3_readphy(tp, data->reg_num & 0x1f, &mii_regval);
 		spin_unlock_bh(&tp->lock);
@@ -8304,6 +8364,9 @@
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 
+		if (tp->link_config.phy_is_low_power)
+			return -EAGAIN;
+
 		spin_lock_bh(&tp->lock);
 		err = tg3_writephy(tp, data->reg_num & 0x1f, data->val_in);
 		spin_unlock_bh(&tp->lock);
@@ -9718,7 +9781,7 @@
 		tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3;
 
 	/* Force the chip into D0. */
-	err = tg3_set_power_state(tp, 0);
+	err = tg3_set_power_state(tp, PCI_D0);
 	if (err) {
 		printk(KERN_ERR PFX "(%s) transition to D0 failed\n",
 		       pci_name(tp->pdev));
@@ -10771,11 +10834,12 @@
 		tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
 	}
 
-	/* TSO is off by default, user can enable using ethtool.  */
-#if 0
-	if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)
+	/* TSO is on by default on chips that support hardware TSO.
+	 * Firmware TSO on older chips gives lower performance, so it
+	 * is off by default, but can be enabled using ethtool.
+	 */
+	if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
 		dev->features |= NETIF_F_TSO;
-#endif
 
 #endif
 
@@ -10968,7 +11032,7 @@
 
 	pci_restore_state(tp->pdev);
 
-	err = tg3_set_power_state(tp, 0);
+	err = tg3_set_power_state(tp, PCI_D0);
 	if (err)
 		return err;
 
diff -urN oldtree/drivers/net/tokenring/Kconfig newtree/drivers/net/tokenring/Kconfig
--- oldtree/drivers/net/tokenring/Kconfig	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/tokenring/Kconfig	2006-02-21 15:58:36.364618296 +0000
@@ -3,7 +3,7 @@
 #
 
 menu "Token Ring devices"
-	depends on NETDEVICES
+	depends on NETDEVICES && !UML
 
 # So far, we only have PCI, ISA, and MCA token ring devices
 config TR
@@ -84,7 +84,7 @@
 
 config TMS380TR
 	tristate "Generic TMS380 Token Ring ISA/PCI adapter support"
-	depends on TR && (PCI || ISA && ISA_DMA_API || MCA)
+	depends on TR && (PCI || ISA && ISA_DMA_API || MCA) && (BROKEN || !FRV)
 	select FW_LOADER
 	---help---
 	  This driver provides generic support for token ring adapters
diff -urN oldtree/drivers/net/tokenring/lanstreamer.c newtree/drivers/net/tokenring/lanstreamer.c
--- oldtree/drivers/net/tokenring/lanstreamer.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/tokenring/lanstreamer.c	2006-02-21 15:58:15.501789928 +0000
@@ -122,6 +122,7 @@
 #include <linux/spinlock.h>
 #include <linux/version.h>
 #include <linux/bitops.h>
+#include <linux/jiffies.h>
 
 #include <net/checksum.h>
 
@@ -512,7 +513,7 @@
 
 	while (!((readw(streamer_mmio + SISR)) & SISR_SRB_REPLY)) {
 		msleep_interruptible(100);
-		if (jiffies - t > 40 * HZ) {
+		if (time_after(jiffies, t + 40 * HZ)) {
 			printk(KERN_ERR
 			       "IBM PCI tokenring card not responding\n");
 			release_region(dev->base_addr, STREAMER_IO_SPACE);
diff -urN oldtree/drivers/net/tokenring/olympic.c newtree/drivers/net/tokenring/olympic.c
--- oldtree/drivers/net/tokenring/olympic.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/tokenring/olympic.c	2006-02-21 15:58:15.503789624 +0000
@@ -100,6 +100,7 @@
 #include <linux/pci.h>
 #include <linux/spinlock.h>
 #include <linux/bitops.h>
+#include <linux/jiffies.h>
 
 #include <net/checksum.h>
 
@@ -307,7 +308,7 @@
 	t=jiffies;
 	while((readl(olympic_mmio+BCTL)) & BCTL_SOFTRESET) {
 		schedule();		
-		if(jiffies-t > 40*HZ) {
+		if(time_after(jiffies, t + 40*HZ)) {
 			printk(KERN_ERR "IBM PCI tokenring card not responding.\n");
 			return -ENODEV;
 		}
@@ -359,7 +360,7 @@
 		t=jiffies;
 		while (!readl(olympic_mmio+CLKCTL) & CLKCTL_PAUSE) { 
 			schedule() ; 
-			if(jiffies-t > 2*HZ) { 
+			if(time_after(jiffies, t + 2*HZ)) {
 				printk(KERN_ERR "IBM Cardbus tokenring adapter not responsing.\n") ; 
 				return -ENODEV;
 			}
@@ -373,7 +374,7 @@
 	t=jiffies;
 	while(!((readl(olympic_mmio+SISR_RR)) & SISR_SRB_REPLY)) {
 		schedule();		
-		if(jiffies-t > 15*HZ) {
+		if(time_after(jiffies, t + 15*HZ)) {
 			printk(KERN_ERR "IBM PCI tokenring card not responding.\n");
 			return -ENODEV;
 		}
@@ -519,7 +520,7 @@
             			olympic_priv->srb_queued=0;
             			break;
         		}
-			if ((jiffies-t) > 10*HZ) { 
+			if (time_after(jiffies, t + 10*HZ)) {
 				printk(KERN_WARNING "%s: SRB timed out. \n",dev->name) ; 
 				olympic_priv->srb_queued=0;
 				break ; 
diff -urN oldtree/drivers/net/tulip/de2104x.c newtree/drivers/net/tulip/de2104x.c
--- oldtree/drivers/net/tulip/de2104x.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/tulip/de2104x.c	2006-02-21 15:58:15.518787344 +0000
@@ -402,8 +402,7 @@
 		unsigned copying_skb, buflen;
 
 		skb = de->rx_skb[rx_tail].skb;
-		if (!skb)
-			BUG();
+		BUG_ON(!skb);
 		rmb();
 		status = le32_to_cpu(de->rx_ring[rx_tail].opts1);
 		if (status & DescOwn)
@@ -545,8 +544,7 @@
 			break;
 
 		skb = de->tx_skb[tx_tail].skb;
-		if (!skb)
-			BUG();
+		BUG_ON(!skb);
 		if (unlikely(skb == DE_DUMMY_SKB))
 			goto next;
 
@@ -789,8 +787,7 @@
 
 	de->tx_head = NEXT_TX(entry);
 
-	if (TX_BUFFS_AVAIL(de) < 0)
-		BUG();
+	BUG_ON(TX_BUFFS_AVAIL(de) < 0);
 	if (TX_BUFFS_AVAIL(de) == 0)
 		netif_stop_queue(dev);
 
@@ -916,8 +913,7 @@
 	unsigned media = de->media_type;
 	u32 macmode = dr32(MacMode);
 
-	if (de_is_running(de))
-		BUG();
+	BUG_ON(de_is_running(de));
 
 	if (de->de21040)
 		dw32(CSR11, FULL_DUPLEX_MAGIC);
@@ -1153,8 +1149,7 @@
 		return;
 	}
 	
-	if (!(status & LinkFail))
-		BUG();
+	BUG_ON(!(status & LinkFail));
 
 	if (netif_carrier_ok(de->dev)) {
 		de_link_down(de);
@@ -2092,8 +2087,7 @@
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct de_private *de = dev->priv;
 
-	if (!dev)
-		BUG();
+	BUG_ON(!dev);
 	unregister_netdev(dev);
 	kfree(de->ee_data);
 	iounmap(de->regs);
diff -urN oldtree/drivers/net/tulip/media.c newtree/drivers/net/tulip/media.c
--- oldtree/drivers/net/tulip/media.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/tulip/media.c	2006-02-21 15:58:15.771748888 +0000
@@ -44,8 +44,10 @@
 
 /* MII transceiver control section.
    Read and write the MII registers using software-generated serial
-   MDIO protocol.  See the MII specifications or DP83840A data sheet
-   for details. */
+   MDIO protocol.
+   See IEEE 802.3-2002.pdf (Section 2, Chapter "22.2.4 Management functions")
+   or DP83840A data sheet for more details.
+   */
 
 int tulip_mdio_read(struct net_device *dev, int phy_id, int location)
 {
@@ -261,24 +263,56 @@
 				u16 *reset_sequence = &((u16*)(p+3))[init_length];
 				int reset_length = p[2 + init_length*2];
 				misc_info = reset_sequence + reset_length;
-				if (startup)
+				if (startup) {
+					int timeout = 10;	/* max 1 ms */
 					for (i = 0; i < reset_length; i++)
 						iowrite32(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15);
+
+					/* flush posted writes */
+					ioread32(ioaddr + CSR15);
+
+					/* Sect 3.10.3 in DP83840A.pdf (p39) */
+					udelay(500);
+
+					/* Section 4.2 in DP83840A.pdf (p43) */
+					/* and IEEE 802.3 "22.2.4.1.1 Reset" */
+					while (timeout-- &&
+						(tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET))
+						udelay(100);
+				}
 				for (i = 0; i < init_length; i++)
 					iowrite32(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15);
+
+				ioread32(ioaddr + CSR15);	/* flush posted writes */
 			} else {
 				u8 *init_sequence = p + 2;
 				u8 *reset_sequence = p + 3 + init_length;
 				int reset_length = p[2 + init_length];
 				misc_info = (u16*)(reset_sequence + reset_length);
 				if (startup) {
+					int timeout = 10;	/* max 1 ms */
 					iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12);
 					for (i = 0; i < reset_length; i++)
 						iowrite32(reset_sequence[i], ioaddr + CSR12);
+
+					/* flush posted writes */
+					ioread32(ioaddr + CSR12);
+
+					/* Sect 3.10.3 in DP83840A.pdf (p39) */
+					udelay(500);
+
+					/* Section 4.2 in DP83840A.pdf (p43) */
+					/* and IEEE 802.3 "22.2.4.1.1 Reset" */
+					while (timeout-- &&
+						(tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET))
+						udelay(100);
 				}
 				for (i = 0; i < init_length; i++)
 					iowrite32(init_sequence[i], ioaddr + CSR12);
+
+				ioread32(ioaddr + CSR12);	/* flush posted writes */
 			}
+
 			tmp_info = get_u16(&misc_info[1]);
 			if (tmp_info)
 				tp->advertising[phy_num] = tmp_info | 1;
diff -urN oldtree/drivers/net/tulip/pnic.c newtree/drivers/net/tulip/pnic.c
--- oldtree/drivers/net/tulip/pnic.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/tulip/pnic.c	2006-02-21 15:58:15.527785976 +0000
@@ -16,6 +16,7 @@
 
 #include <linux/kernel.h>
 #include <linux/pci.h>
+#include <linux/jiffies.h>
 #include "tulip.h"
 
 
@@ -68,7 +69,7 @@
 		 */
 		if (tulip_media_cap[dev->if_port] & MediaIsMII)
 			return;
-		if (! tp->nwayset  ||  jiffies - dev->trans_start > 1*HZ) {
+		if (! tp->nwayset  ||  time_after(jiffies, dev->trans_start + 1*HZ)) {
 			tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff);
 			iowrite32(tp->csr6, ioaddr + CSR6);
 			iowrite32(0x30, ioaddr + CSR12);
diff -urN oldtree/drivers/net/tulip/tulip.h newtree/drivers/net/tulip/tulip.h
--- oldtree/drivers/net/tulip/tulip.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/tulip/tulip.h	2006-02-21 15:58:15.759750712 +0000
@@ -474,8 +474,11 @@
 			udelay(10);
 
 		if (!i)
-			printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed\n",
-					pci_name(tp->pdev));
+			printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed"
+					" (CSR5 0x%x CSR6 0x%x)\n",
+					pci_name(tp->pdev),
+					ioread32(ioaddr + CSR5),
+					ioread32(ioaddr + CSR6));
 	}
 }
 
diff -urN oldtree/drivers/net/tulip/tulip_core.c newtree/drivers/net/tulip/tulip_core.c
--- oldtree/drivers/net/tulip/tulip_core.c	2006-02-19 11:41:03.378829440 +0000
+++ newtree/drivers/net/tulip/tulip_core.c	2006-02-21 15:58:15.758750864 +0000
@@ -22,7 +22,7 @@
 #else
 #define DRV_VERSION	"1.1.13"
 #endif
-#define DRV_RELDATE	"May 11, 2002"
+#define DRV_RELDATE	"December 15, 2004"
 
 
 #include <linux/module.h>
diff -urN oldtree/drivers/net/tulip/winbond-840.c newtree/drivers/net/tulip/winbond-840.c
--- oldtree/drivers/net/tulip/winbond-840.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/tulip/winbond-840.c	2006-02-21 15:58:15.531785368 +0000
@@ -1645,7 +1645,7 @@
 
 		/* no more hardware accesses behind this line. */
 
-		if (np->csr6) BUG();
+		BUG_ON(np->csr6);
 		if (ioread32(ioaddr + IntrEnable)) BUG();
 
 		/* pci_power_off(pdev, -1); */
diff -urN oldtree/drivers/net/tulip/xircom_cb.c newtree/drivers/net/tulip/xircom_cb.c
--- oldtree/drivers/net/tulip/xircom_cb.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/tulip/xircom_cb.c	2006-02-21 15:58:15.533785064 +0000
@@ -32,6 +32,9 @@
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
+#ifdef CONFIG_NET_POLL_CONTROLLER
+#include <asm/irq.h>
+#endif
 
 #ifdef DEBUG
 #define enter(x)   printk("Enter: %s, %s line %i\n",x,__FILE__,__LINE__)
@@ -598,10 +601,8 @@
 	enter("setup_descriptors");
 
 
-	if (card->rx_buffer == NULL)
-		BUG();
-	if (card->tx_buffer == NULL)
-		BUG();
+	BUG_ON(card->rx_buffer == NULL);
+	BUG_ON(card->tx_buffer == NULL);
 
 	/* Receive descriptors */
 	memset(card->rx_buffer, 0, 128);	/* clear the descriptors */
diff -urN oldtree/drivers/net/wan/dscc4.c newtree/drivers/net/wan/dscc4.c
--- oldtree/drivers/net/wan/dscc4.c	2006-02-19 11:41:03.382828832 +0000
+++ newtree/drivers/net/wan/dscc4.c	2006-02-21 15:58:24.194468440 +0000
@@ -105,6 +105,7 @@
 #include <linux/delay.h>
 #include <net/syncppp.h>
 #include <linux/hdlc.h>
+#include <linux/mutex.h>
 
 /* Version */
 static const char version[] = "$Id: dscc4.c,v 1.173 2003/09/20 23:55:34 romieu Exp $ for Linux\n";
@@ -112,7 +113,7 @@
 static int quartz;
 
 #ifdef CONFIG_DSCC4_PCI_RST
-static DECLARE_MUTEX(dscc4_sem);
+static DEFINE_MUTEX(dscc4_mutex);
 static u32 dscc4_pci_config_store[16];
 #endif
 
@@ -1018,7 +1019,7 @@
 {
 	int i;
 
-	down(&dscc4_sem);
+	mutex_lock(&dscc4_mutex);
 	for (i = 0; i < 16; i++)
 		pci_read_config_dword(pdev, i << 2, dscc4_pci_config_store + i);
 
@@ -1039,7 +1040,7 @@
 
 	for (i = 0; i < 16; i++)
 		pci_write_config_dword(pdev, i << 2, dscc4_pci_config_store[i]);
-	up(&dscc4_sem);
+	mutex_unlock(&dscc4_mutex);
 }
 #else
 #define dscc4_pci_reset(pdev,ioaddr)	do {} while (0)
diff -urN oldtree/drivers/net/wan/hostess_sv11.c newtree/drivers/net/wan/hostess_sv11.c
--- oldtree/drivers/net/wan/hostess_sv11.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/wan/hostess_sv11.c	2006-02-21 15:58:15.545783240 +0000
@@ -29,6 +29,7 @@
 #include <linux/ioport.h>
 #include <net/arp.h>
 
+#include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/byteorder.h>
diff -urN oldtree/drivers/net/wan/sealevel.c newtree/drivers/net/wan/sealevel.c
--- oldtree/drivers/net/wan/sealevel.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/wan/sealevel.c	2006-02-21 15:58:15.550782480 +0000
@@ -23,6 +23,7 @@
 #include <linux/init.h>
 #include <net/arp.h>
 
+#include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/byteorder.h>
diff -urN oldtree/drivers/net/wireless/Kconfig newtree/drivers/net/wireless/Kconfig
--- oldtree/drivers/net/wireless/Kconfig	2006-02-19 11:41:03.391827464 +0000
+++ newtree/drivers/net/wireless/Kconfig	2006-02-21 15:58:36.364618296 +0000
@@ -6,7 +6,8 @@
 	depends on NETDEVICES
 
 config NET_RADIO
-	bool "Wireless LAN drivers (non-hamradio) & Wireless Extensions"
+	bool "Wireless LAN drivers (non-hamradio)"
+	select WIRELESS_EXT
 	---help---
 	  Support for wireless LANs and everything having to do with radio,
 	  but not with amateur radio or FM broadcasting.
@@ -135,8 +136,9 @@
 
 config IPW2100
 	tristate "Intel PRO/Wireless 2100 Network Connection"
-	depends on NET_RADIO && PCI && IEEE80211
+	depends on NET_RADIO && PCI
 	select FW_LOADER
+	select IEEE80211
 	---help---
           A driver for the Intel PRO/Wireless 2100 Network 
 	  Connection 802.11b wireless network adapter.
@@ -188,8 +190,9 @@
 
 config IPW2200
 	tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
-	depends on NET_RADIO && IEEE80211 && PCI
+	depends on NET_RADIO && PCI
 	select FW_LOADER
+	select IEEE80211
 	---help---
           A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network
 	  Connection adapters. 
@@ -239,7 +242,8 @@
 
 config AIRO
 	tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
-	depends on NET_RADIO && ISA_DMA_API && CRYPTO && (PCI || BROKEN)
+ 	depends on NET_RADIO && ISA_DMA_API && (PCI || BROKEN)
+	select CRYPTO
 	---help---
 	  This is the standard Linux driver to support Cisco/Aironet ISA and
 	  PCI 802.11 wireless cards.
@@ -326,7 +330,7 @@
 
 config ATMEL
       tristate "Atmel at76c50x chipset  802.11b support"
-      depends on NET_RADIO
+      depends on NET_RADIO && (PCI || PCMCIA)
       select FW_LOADER
       select CRC32
        ---help---
@@ -387,6 +391,7 @@
 config AIRO_CS
 	tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards"
 	depends on NET_RADIO && PCMCIA && (BROKEN || !M32R)
+	select CRYPTO
 	---help---
 	  This is the standard Linux driver to support Cisco/Aironet PCMCIA
 	  802.11 wireless cards.  This driver is the same as the Aironet
@@ -473,6 +478,8 @@
 
 source "drivers/net/wireless/hostap/Kconfig"
 
+source "drivers/net/wireless/tiacx/Kconfig"
+
 # yes, this works even when no drivers are selected
 config NET_WIRELESS
 	bool
diff -urN oldtree/drivers/net/wireless/Makefile newtree/drivers/net/wireless/Makefile
--- oldtree/drivers/net/wireless/Makefile	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/wireless/Makefile	2006-02-21 15:58:22.552718024 +0000
@@ -33,7 +33,7 @@
 obj-$(CONFIG_PCMCIA_ATMEL)      += atmel_cs.o
 
 obj-$(CONFIG_PRISM54)		+= prism54/
-
+obj-$(CONFIG_ACX)		+= tiacx/
 obj-$(CONFIG_HOSTAP)		+= hostap/
 
 # 16-bit wireless PCMCIA client drivers
diff -urN oldtree/drivers/net/wireless/airo.c newtree/drivers/net/wireless/airo.c
--- oldtree/drivers/net/wireless/airo.c	2006-02-19 11:41:03.394827008 +0000
+++ newtree/drivers/net/wireless/airo.c	2006-02-21 15:58:15.565780200 +0000
@@ -36,6 +36,7 @@
 #include <linux/in.h>
 #include <linux/bitops.h>
 #include <linux/scatterlist.h>
+#include <linux/crypto.h>
 #include <asm/io.h>
 #include <asm/system.h>
 
@@ -87,14 +88,6 @@
 #include <linux/delay.h>
 #endif
 
-/* Support Cisco MIC feature */
-#define MICSUPPORT
-
-#if defined(MICSUPPORT) && !defined(CONFIG_CRYPTO)
-#warning MIC support requires Crypto API
-#undef MICSUPPORT
-#endif
-
 /* Hack to do some power saving */
 #define POWER_ON_DOWN
 
@@ -1118,7 +1111,6 @@
 static int writerids(struct net_device *dev, aironet_ioctl *comp);
 static int flashcard(struct net_device *dev, aironet_ioctl *comp);
 #endif /* CISCO_EXT */
-#ifdef MICSUPPORT
 static void micinit(struct airo_info *ai);
 static int micsetup(struct airo_info *ai);
 static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len);
@@ -1127,9 +1119,6 @@
 static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi);
 static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm);
 
-#include <linux/crypto.h>
-#endif
-
 struct airo_info {
 	struct net_device_stats	stats;
 	struct net_device             *dev;
@@ -1190,12 +1179,10 @@
 	unsigned long		scan_timestamp;	/* Time started to scan */
 	struct iw_spy_data	spy_data;
 	struct iw_public_data	wireless_data;
-#ifdef MICSUPPORT
 	/* MIC stuff */
 	struct crypto_tfm	*tfm;
 	mic_module		mod[2];
 	mic_statistics		micstats;
-#endif
 	HostRxDesc rxfids[MPI_MAX_FIDS]; // rx/tx/config MPI350 descriptors
 	HostTxDesc txfids[MPI_MAX_FIDS];
 	HostRidDesc config_desc;
@@ -1229,7 +1216,6 @@
 static int flashputbuf(struct airo_info *ai);
 static int flashrestart(struct airo_info *ai,struct net_device *dev);
 
-#ifdef MICSUPPORT
 /***********************************************************************
  *                              MIC ROUTINES                           *
  ***********************************************************************
@@ -1686,7 +1672,6 @@
 	digest[2] = (val>>8) & 0xFF;
 	digest[3] = val & 0xFF;
 }
-#endif
 
 static int readBSSListRid(struct airo_info *ai, int first,
 		      BSSListRid *list) {
@@ -2005,7 +1990,6 @@
 	 * Firmware automaticly puts 802 header on so
 	 * we don't need to account for it in the length
 	 */
-#ifdef MICSUPPORT
 	if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
 		(ntohs(((u16 *)buffer)[6]) != 0x888E)) {
 		MICBuffer pMic;
@@ -2022,9 +2006,7 @@
 		memcpy (sendbuf, &pMic, sizeof(pMic));
 		sendbuf += sizeof(pMic);
 		memcpy (sendbuf, buffer, len - sizeof(etherHead));
-	} else
-#endif
-	{
+	} else {
 		*payloadLen = cpu_to_le16(len - sizeof(etherHead));
 
 		dev->trans_start = jiffies;
@@ -2400,9 +2382,7 @@
 				ai->shared, ai->shared_dma);
 		}
         }
-#ifdef MICSUPPORT
 	crypto_free_tfm(ai->tfm);
-#endif
 	del_airo_dev( dev );
 	free_netdev( dev );
 }
@@ -2726,9 +2706,7 @@
 	ai->thr_pid = kernel_thread(airo_thread, dev, CLONE_FS | CLONE_FILES);
 	if (ai->thr_pid < 0)
 		goto err_out_free;
-#ifdef MICSUPPORT
 	ai->tfm = NULL;
-#endif
 	rc = add_airo_dev( dev );
 	if (rc)
 		goto err_out_thr;
@@ -2969,10 +2947,8 @@
 			airo_read_wireless_stats(ai);
 		else if (test_bit(JOB_PROMISC, &ai->flags))
 			airo_set_promisc(ai);
-#ifdef MICSUPPORT
 		else if (test_bit(JOB_MIC, &ai->flags))
 			micinit(ai);
-#endif
 		else if (test_bit(JOB_EVENT, &ai->flags))
 			airo_send_event(dev);
 		else if (test_bit(JOB_AUTOWEP, &ai->flags))
@@ -3010,12 +2986,10 @@
 
 		if ( status & EV_MIC ) {
 			OUT4500( apriv, EVACK, EV_MIC );
-#ifdef MICSUPPORT
 			if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) {
 				set_bit(JOB_MIC, &apriv->flags);
 				wake_up_interruptible(&apriv->thr_wait);
 			}
-#endif
 		}
 		if ( status & EV_LINK ) {
 			union iwreq_data	wrqu;
@@ -3194,11 +3168,8 @@
 				}
 				bap_read (apriv, buffer + hdrlen/2, len, BAP0);
 			} else {
-#ifdef MICSUPPORT
 				MICBuffer micbuf;
-#endif
 				bap_read (apriv, buffer, ETH_ALEN*2, BAP0);
-#ifdef MICSUPPORT
 				if (apriv->micstats.enabled) {
 					bap_read (apriv,(u16*)&micbuf,sizeof(micbuf),BAP0);
 					if (ntohs(micbuf.typelen) > 0x05DC)
@@ -3211,15 +3182,10 @@
 						skb_trim (skb, len + hdrlen);
 					}
 				}
-#endif
 				bap_read(apriv,buffer+ETH_ALEN,len,BAP0);
-#ifdef MICSUPPORT
 				if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) {
 badmic:
 					dev_kfree_skb_irq (skb);
-#else
-				if (0) {
-#endif
 badrx:
 					OUT4500( apriv, EVACK, EV_RX);
 					goto exitrx;
@@ -3430,10 +3396,8 @@
 	int len = 0;
 	struct sk_buff *skb;
 	char *buffer;
-#ifdef MICSUPPORT
 	int off = 0;
 	MICBuffer micbuf;
-#endif
 
 	memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd));
 	/* Make sure we got something */
@@ -3448,7 +3412,6 @@
 			goto badrx;
 		}
 		buffer = skb_put(skb,len);
-#ifdef MICSUPPORT
 		memcpy(buffer, ai->rxfids[0].virtual_host_addr, ETH_ALEN * 2);
 		if (ai->micstats.enabled) {
 			memcpy(&micbuf,
@@ -3470,9 +3433,6 @@
 			dev_kfree_skb_irq (skb);
 			goto badrx;
 		}
-#else
-		memcpy(buffer, ai->rxfids[0].virtual_host_addr, len);
-#endif
 #ifdef WIRELESS_SPY
 		if (ai->spy_data.spy_number > 0) {
 			char *sa;
@@ -3689,13 +3649,11 @@
 		ai->config.authType = AUTH_OPEN;
 		ai->config.modulation = MOD_CCK;
 
-#ifdef MICSUPPORT
 		if ((cap_rid.len>=sizeof(cap_rid)) && (cap_rid.extSoftCap&1) &&
 		    (micsetup(ai) == SUCCESS)) {
 			ai->config.opmode |= MODE_MIC;
 			set_bit(FLAG_MIC_CAPABLE, &ai->flags);
 		}
-#endif
 
 		/* Save off the MAC */
 		for( i = 0; i < ETH_ALEN; i++ ) {
@@ -4170,15 +4128,12 @@
 	}
 	len -= ETH_ALEN * 2;
 
-#ifdef MICSUPPORT
 	if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && 
 	    (ntohs(((u16 *)pPacket)[6]) != 0x888E)) {
 		if (encapsulate(ai,(etherHead *)pPacket,&pMic,len) != SUCCESS)
 			return ERROR;
 		miclen = sizeof(pMic);
 	}
-#endif
-
 	// packet is destination[6], source[6], payload[len-12]
 	// write the payload length and dst/src/payload
 	if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR;
@@ -5801,11 +5756,13 @@
 	Cmd cmd;
 	Resp rsp;
 	APListRid APList_rid;
-	static const unsigned char bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 };
+	static const u8 any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+	static const u8 off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
 	if (awrq->sa_family != ARPHRD_ETHER)
 		return -EINVAL;
-	else if (!memcmp(bcast, awrq->sa_data, ETH_ALEN)) {
+	else if (!memcmp(any, awrq->sa_data, ETH_ALEN) ||
+	         !memcmp(off, awrq->sa_data, ETH_ALEN)) {
 		memset(&cmd, 0, sizeof(cmd));
 		cmd.cmd=CMD_LOSE_SYNC;
 		if (down_interruptible(&local->sem))
@@ -6296,6 +6253,267 @@
 
 /*------------------------------------------------------------------*/
 /*
+ * Wireless Handler : set extended Encryption parameters
+ */
+static int airo_set_encodeext(struct net_device *dev,
+			   struct iw_request_info *info,
+			    union iwreq_data *wrqu,
+			    char *extra)
+{
+	struct airo_info *local = dev->priv;
+	struct iw_point *encoding = &wrqu->encoding;
+	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+	CapabilityRid cap_rid;		/* Card capability info */
+	int perm = ( encoding->flags & IW_ENCODE_TEMP ? 0 : 1 );
+	u16 currentAuthType = local->config.authType;
+	int idx, key_len, alg = ext->alg;	/* Check encryption mode */
+	wep_key_t key;
+
+	/* Is WEP supported ? */
+	readCapabilityRid(local, &cap_rid, 1);
+	/* Older firmware doesn't support this...
+	if(!(cap_rid.softCap & 2)) {
+		return -EOPNOTSUPP;
+	} */
+	readConfigRid(local, 1);
+
+	/* Determine and validate the key index */
+	idx = encoding->flags & IW_ENCODE_INDEX;
+	if (idx) {
+		if (idx < 1 || idx > ((cap_rid.softCap & 0x80) ? 4:1))
+			return -EINVAL;
+		idx--;
+	} else
+		idx = get_wep_key(local, 0xffff);
+
+	if (encoding->flags & IW_ENCODE_DISABLED)
+		alg = IW_ENCODE_ALG_NONE;
+
+	/* Just setting the transmit key? */
+	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+		set_wep_key(local, idx, NULL, 0, perm, 1);
+	} else {
+		/* Set the requested key first */
+		memset(key.key, 0, MAX_KEY_SIZE);
+		switch (alg) {
+		case IW_ENCODE_ALG_NONE:
+			key.len = 0;
+			break;
+		case IW_ENCODE_ALG_WEP:
+			if (ext->key_len > MIN_KEY_SIZE) {
+				key.len = MAX_KEY_SIZE;
+			} else if (ext->key_len > 0) {
+				key.len = MIN_KEY_SIZE;
+			} else {
+				return -EINVAL;
+			}
+			key_len = min (ext->key_len, key.len);
+			memcpy(key.key, ext->key, key_len);
+			break;
+		default:
+			return -EINVAL;
+		}
+		/* Send the key to the card */
+		set_wep_key(local, idx, key.key, key.len, perm, 1);
+	}
+
+	/* Read the flags */
+	if(encoding->flags & IW_ENCODE_DISABLED)
+		local->config.authType = AUTH_OPEN;	// disable encryption
+	if(encoding->flags & IW_ENCODE_RESTRICTED)
+		local->config.authType = AUTH_SHAREDKEY;	// Only Both
+	if(encoding->flags & IW_ENCODE_OPEN)
+		local->config.authType = AUTH_ENCRYPT;	// Only Wep
+	/* Commit the changes to flags if needed */
+	if (local->config.authType != currentAuthType)
+		set_bit (FLAG_COMMIT, &local->flags);
+
+	return -EINPROGRESS;
+}
+
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get extended Encryption parameters
+ */
+static int airo_get_encodeext(struct net_device *dev,
+			    struct iw_request_info *info,
+			    union iwreq_data *wrqu,
+			    char *extra)
+{
+	struct airo_info *local = dev->priv;
+	struct iw_point *encoding = &wrqu->encoding;
+	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+	CapabilityRid cap_rid;		/* Card capability info */
+	int idx, max_key_len;
+
+	/* Is it supported ? */
+	readCapabilityRid(local, &cap_rid, 1);
+	if(!(cap_rid.softCap & 2)) {
+		return -EOPNOTSUPP;
+	}
+	readConfigRid(local, 1);
+
+	max_key_len = encoding->length - sizeof(*ext);
+	if (max_key_len < 0)
+		return -EINVAL;
+
+	idx = encoding->flags & IW_ENCODE_INDEX;
+	if (idx) {
+		if (idx < 1 || idx > ((cap_rid.softCap & 0x80) ? 4:1))
+			return -EINVAL;
+		idx--;
+	} else
+		idx = get_wep_key(local, 0xffff);
+
+	encoding->flags = idx + 1;
+	memset(ext, 0, sizeof(*ext));
+
+	/* Check encryption mode */
+	switch(local->config.authType) {
+		case AUTH_ENCRYPT:
+			encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED;
+			break;
+		case AUTH_SHAREDKEY:
+			encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED;
+			break;
+		default:
+		case AUTH_OPEN:
+			encoding->flags = IW_ENCODE_ALG_NONE | IW_ENCODE_DISABLED;
+			break;
+	}
+	/* We can't return the key, so set the proper flag and return zero */
+	encoding->flags |= IW_ENCODE_NOKEY;
+	memset(extra, 0, 16);
+	
+	/* Copy the key to the user buffer */
+	ext->key_len = get_wep_key(local, idx);
+	if (ext->key_len > 16) {
+		ext->key_len=0;
+	}
+
+	return 0;
+}
+
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set extended authentication parameters
+ */
+static int airo_set_auth(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	struct airo_info *local = dev->priv;
+	struct iw_param *param = &wrqu->param;
+	u16 currentAuthType = local->config.authType;
+
+	switch (param->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_WPA_VERSION:
+	case IW_AUTH_CIPHER_PAIRWISE:
+	case IW_AUTH_CIPHER_GROUP:
+	case IW_AUTH_KEY_MGMT:
+	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+	case IW_AUTH_PRIVACY_INVOKED:
+		/*
+		 * airo does not use these parameters
+		 */
+		break;
+
+	case IW_AUTH_DROP_UNENCRYPTED:
+		if (param->value) {
+			/* Only change auth type if unencrypted */
+			if (currentAuthType == AUTH_OPEN)
+				local->config.authType = AUTH_ENCRYPT;
+		} else {
+			local->config.authType = AUTH_OPEN;
+		}
+
+		/* Commit the changes to flags if needed */
+		if (local->config.authType != currentAuthType)
+			set_bit (FLAG_COMMIT, &local->flags);
+		break;
+
+	case IW_AUTH_80211_AUTH_ALG: {
+			/* FIXME: What about AUTH_OPEN?  This API seems to
+			 * disallow setting our auth to AUTH_OPEN.
+			 */
+			if (param->value & IW_AUTH_ALG_SHARED_KEY) {
+				local->config.authType = AUTH_SHAREDKEY;
+			} else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
+				local->config.authType = AUTH_ENCRYPT;
+			} else
+				return -EINVAL;
+			break;
+
+			/* Commit the changes to flags if needed */
+			if (local->config.authType != currentAuthType)
+				set_bit (FLAG_COMMIT, &local->flags);
+		}
+
+	case IW_AUTH_WPA_ENABLED:
+		/* Silently accept disable of WPA */
+		if (param->value > 0)
+			return -EOPNOTSUPP;
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+	return -EINPROGRESS;
+}
+
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get extended authentication parameters
+ */
+static int airo_get_auth(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	struct airo_info *local = dev->priv;
+	struct iw_param *param = &wrqu->param;
+	u16 currentAuthType = local->config.authType;
+
+	switch (param->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_DROP_UNENCRYPTED:
+		switch (currentAuthType) {
+		case AUTH_SHAREDKEY:
+		case AUTH_ENCRYPT:
+			param->value = 1;
+			break;
+		default:
+			param->value = 0;
+			break;
+		}
+		break;
+
+	case IW_AUTH_80211_AUTH_ALG:
+		switch (currentAuthType) {
+		case AUTH_SHAREDKEY:
+			param->value = IW_AUTH_ALG_SHARED_KEY;
+			break;
+		case AUTH_ENCRYPT:
+		default:
+			param->value = IW_AUTH_ALG_OPEN_SYSTEM;
+			break;
+		}
+		break;
+
+	case IW_AUTH_WPA_ENABLED:
+		param->value = 0;
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+
+/*------------------------------------------------------------------*/
+/*
  * Wireless Handler : set Tx-Power
  */
 static int airo_set_txpow(struct net_device *dev,
@@ -7050,6 +7268,15 @@
 	(iw_handler) airo_get_encode,		/* SIOCGIWENCODE */
 	(iw_handler) airo_set_power,		/* SIOCSIWPOWER */
 	(iw_handler) airo_get_power,		/* SIOCGIWPOWER */
+	(iw_handler) NULL,			/* -- hole -- */
+	(iw_handler) NULL,			/* -- hole -- */
+	(iw_handler) NULL,			/* SIOCSIWGENIE */
+	(iw_handler) NULL,			/* SIOCGIWGENIE */
+	(iw_handler) airo_set_auth,		/* SIOCSIWAUTH */
+	(iw_handler) airo_get_auth,		/* SIOCGIWAUTH */
+	(iw_handler) airo_set_encodeext,	/* SIOCSIWENCODEEXT */
+	(iw_handler) airo_get_encodeext,	/* SIOCGIWENCODEEXT */
+	(iw_handler) NULL,			/* SIOCSIWPMKSA */
 };
 
 /* Note : don't describe AIROIDIFC and AIROOLDIDIFC in here.
@@ -7270,13 +7497,11 @@
 	case AIROGSTAT:     ridcode = RID_STATUS;       break;
 	case AIROGSTATSD32: ridcode = RID_STATSDELTA;   break;
 	case AIROGSTATSC32: ridcode = RID_STATS;        break;
-#ifdef MICSUPPORT
 	case AIROGMICSTATS:
 		if (copy_to_user(comp->data, &ai->micstats,
 				 min((int)comp->len,(int)sizeof(ai->micstats))))
 			return -EFAULT;
 		return 0;
-#endif
 	case AIRORRID:      ridcode = comp->ridnum;     break;
 	default:
 		return -EINVAL;
@@ -7308,9 +7533,7 @@
 static int writerids(struct net_device *dev, aironet_ioctl *comp) {
 	struct airo_info *ai = dev->priv;
 	int  ridcode;
-#ifdef MICSUPPORT
         int  enabled;
-#endif
 	Resp      rsp;
 	static int (* writer)(struct airo_info *, u16 rid, const void *, int, int);
 	unsigned char *iobuf;
@@ -7367,11 +7590,9 @@
 
 		PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDSIZE, 1);
 
-#ifdef MICSUPPORT
 		enabled = ai->micstats.enabled;
 		memset(&ai->micstats,0,sizeof(ai->micstats));
 		ai->micstats.enabled = enabled;
-#endif
 
 		if (copy_to_user(comp->data, iobuf,
 				 min((int)comp->len, (int)RIDSIZE))) {
diff -urN oldtree/drivers/net/wireless/ipw2100.c newtree/drivers/net/wireless/ipw2100.c
--- oldtree/drivers/net/wireless/ipw2100.c	2006-02-19 11:41:03.429821688 +0000
+++ newtree/drivers/net/wireless/ipw2100.c	2006-02-21 15:58:15.578778224 +0000
@@ -167,7 +167,7 @@
 
 #include "ipw2100.h"
 
-#define IPW2100_VERSION "1.1.3"
+#define IPW2100_VERSION "git-1.1.4"
 
 #define DRV_NAME	"ipw2100"
 #define DRV_VERSION	IPW2100_VERSION
@@ -1672,6 +1672,18 @@
 	return err;
 }
 
+static const struct ieee80211_geo ipw_geos[] = {
+	{			/* Restricted */
+	 "---",
+	 .bg_channels = 14,
+	 .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+		{2427, 4}, {2432, 5}, {2437, 6},
+		{2442, 7}, {2447, 8}, {2452, 9},
+		{2457, 10}, {2462, 11}, {2467, 12},
+		{2472, 13}, {2484, 14}},
+	 },
+};
+
 static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
 {
 	unsigned long flags;
@@ -1727,6 +1739,13 @@
 		goto exit;
 	}
 
+	/* Initialize the geo */
+	if (ieee80211_set_geo(priv->ieee, &ipw_geos[0])) {
+		printk(KERN_WARNING DRV_NAME "Could not set geo\n");
+		return 0;
+	}
+	priv->ieee->freq_band = IEEE80211_24GHZ_BAND;
+
 	lock = LOCK_NONE;
 	if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) {
 		printk(KERN_ERR DRV_NAME
@@ -3750,7 +3769,7 @@
 	struct net_device *dev = priv->net_dev;
 	const char *p = buf;
 
-	(void) dev; /* kill unused-var warning for debug-only code */
+	(void)dev;		/* kill unused-var warning for debug-only code */
 
 	if (count < 1)
 		return count;
@@ -4070,7 +4089,7 @@
 	unsigned long val;
 	char *p = buffer;
 
-	(void) dev; /* kill unused-var warning for debug-only code */
+	(void)dev;		/* kill unused-var warning for debug-only code */
 
 	IPW_DEBUG_INFO("enter\n");
 
@@ -5107,12 +5126,13 @@
 		.host_command_length = 4
 	};
 	int err = 0;
+	u32 tmp = tx_power;
 
 	if (tx_power != IPW_TX_POWER_DEFAULT)
-		tx_power = (tx_power - IPW_TX_POWER_MIN_DBM) * 16 /
-		    (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM);
+		tmp = (tx_power - IPW_TX_POWER_MIN_DBM) * 16 /
+		      (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM);
 
-	cmd.host_command_parameters[0] = tx_power;
+	cmd.host_command_parameters[0] = tmp;
 
 	if (priv->ieee->iw_mode == IW_MODE_ADHOC)
 		err = ipw2100_hw_send_command(priv, &cmd);
@@ -5365,9 +5385,12 @@
 						     SEC_LEVEL_0, 0, 1);
 	} else {
 		auth_mode = IPW_AUTH_OPEN;
-		if ((priv->ieee->sec.flags & SEC_AUTH_MODE) &&
-		    (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY))
-			auth_mode = IPW_AUTH_SHARED;
+		if (priv->ieee->sec.flags & SEC_AUTH_MODE) {
+			if (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY)
+				auth_mode = IPW_AUTH_SHARED;
+			else if (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP)
+				auth_mode = IPW_AUTH_LEAP_CISCO_ID;
+		}
 
 		sec_level = SEC_LEVEL_0;
 		if (priv->ieee->sec.flags & SEC_LEVEL)
@@ -5760,6 +5783,9 @@
 	} else if (value & IW_AUTH_ALG_OPEN_SYSTEM) {
 		sec.auth_mode = WLAN_AUTH_OPEN;
 		ieee->open_wep = 1;
+	} else if (value & IW_AUTH_ALG_LEAP) {
+		sec.auth_mode = WLAN_AUTH_LEAP;
+		ieee->open_wep = 1;
 	} else
 		return -EINVAL;
 
@@ -5771,8 +5797,8 @@
 	return ret;
 }
 
-void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv,
-			     char *wpa_ie, int wpa_ie_len)
+static void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv,
+				    char *wpa_ie, int wpa_ie_len)
 {
 
 	struct ipw2100_wpa_assoc_frame frame;
diff -urN oldtree/drivers/net/wireless/ipw2100.h newtree/drivers/net/wireless/ipw2100.h
--- oldtree/drivers/net/wireless/ipw2100.h	2006-02-19 11:41:03.430821536 +0000
+++ newtree/drivers/net/wireless/ipw2100.h	2006-02-21 15:58:15.587776856 +0000
@@ -392,8 +392,10 @@
 #define IPW_WEP104_CIPHER (1<<5)
 #define IPW_CKIP_CIPHER   (1<<6)
 
-#define	IPW_AUTH_OPEN     0
-#define	IPW_AUTH_SHARED   1
+#define	IPW_AUTH_OPEN     	0
+#define	IPW_AUTH_SHARED   	1
+#define IPW_AUTH_LEAP	  	2
+#define IPW_AUTH_LEAP_CISCO_ID	0x80
 
 struct statistic {
 	int value;
diff -urN oldtree/drivers/net/wireless/ipw2200.c newtree/drivers/net/wireless/ipw2200.c
--- oldtree/drivers/net/wireless/ipw2200.c	2006-02-19 11:41:03.434820928 +0000
+++ newtree/drivers/net/wireless/ipw2200.c	2006-02-21 15:58:16.034708912 +0000
@@ -33,7 +33,7 @@
 #include "ipw2200.h"
 #include <linux/version.h>
 
-#define IPW2200_VERSION "git-1.0.8"
+#define IPW2200_VERSION "git-1.0.10"
 #define DRV_DESCRIPTION	"Intel(R) PRO/Wireless 2200/2915 Network Driver"
 #define DRV_COPYRIGHT	"Copyright(c) 2003-2005 Intel Corporation"
 #define DRV_VERSION     IPW2200_VERSION
@@ -55,7 +55,9 @@
 static int auto_create = 1;
 static int led = 0;
 static int disable = 0;
-static int hwcrypto = 1;
+static int bt_coexist = 0;
+static int hwcrypto = 0;
+static int roaming = 1;
 static const char ipw_modes[] = {
 	'a', 'b', 'g', '?'
 };
@@ -227,12 +229,15 @@
 	return total;
 }
 
+/* alias for 32-bit indirect read (for SRAM/reg above 4K), with debug wrapper */
 static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg);
 #define ipw_read_reg32(a, b) _ipw_read_reg32(a, b)
 
+/* alias for 8-bit indirect read (for SRAM/reg above 4K), with debug wrapper */
 static u8 _ipw_read_reg8(struct ipw_priv *ipw, u32 reg);
 #define ipw_read_reg8(a, b) _ipw_read_reg8(a, b)
 
+/* 8-bit indirect write (for SRAM/reg above 4K), with debug wrapper */
 static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value);
 static inline void ipw_write_reg8(struct ipw_priv *a, u32 b, u8 c)
 {
@@ -241,6 +246,7 @@
 	_ipw_write_reg8(a, b, c);
 }
 
+/* 16-bit indirect write (for SRAM/reg above 4K), with debug wrapper */
 static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value);
 static inline void ipw_write_reg16(struct ipw_priv *a, u32 b, u16 c)
 {
@@ -249,6 +255,7 @@
 	_ipw_write_reg16(a, b, c);
 }
 
+/* 32-bit indirect write (for SRAM/reg above 4K), with debug wrapper */
 static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value);
 static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c)
 {
@@ -257,48 +264,70 @@
 	_ipw_write_reg32(a, b, c);
 }
 
+/* 8-bit direct write (low 4K) */
 #define _ipw_write8(ipw, ofs, val) writeb((val), (ipw)->hw_base + (ofs))
+
+/* 8-bit direct write (for low 4K of SRAM/regs), with debug wrapper */
 #define ipw_write8(ipw, ofs, val) \
  IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \
  _ipw_write8(ipw, ofs, val)
 
+/* 16-bit direct write (low 4K) */
 #define _ipw_write16(ipw, ofs, val) writew((val), (ipw)->hw_base + (ofs))
+
+/* 16-bit direct write (for low 4K of SRAM/regs), with debug wrapper */
 #define ipw_write16(ipw, ofs, val) \
  IPW_DEBUG_IO("%s %d: write_direct16(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \
  _ipw_write16(ipw, ofs, val)
 
+/* 32-bit direct write (low 4K) */
 #define _ipw_write32(ipw, ofs, val) writel((val), (ipw)->hw_base + (ofs))
+
+/* 32-bit direct write (for low 4K of SRAM/regs), with debug wrapper */
 #define ipw_write32(ipw, ofs, val) \
  IPW_DEBUG_IO("%s %d: write_direct32(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \
  _ipw_write32(ipw, ofs, val)
 
+/* 8-bit direct read (low 4K) */
 #define _ipw_read8(ipw, ofs) readb((ipw)->hw_base + (ofs))
+
+/* 8-bit direct read (low 4K), with debug wrapper */
 static inline u8 __ipw_read8(char *f, u32 l, struct ipw_priv *ipw, u32 ofs)
 {
 	IPW_DEBUG_IO("%s %d: read_direct8(0x%08X)\n", f, l, (u32) (ofs));
 	return _ipw_read8(ipw, ofs);
 }
 
+/* alias to 8-bit direct read (low 4K of SRAM/regs), with debug wrapper */
 #define ipw_read8(ipw, ofs) __ipw_read8(__FILE__, __LINE__, ipw, ofs)
 
+/* 16-bit direct read (low 4K) */
 #define _ipw_read16(ipw, ofs) readw((ipw)->hw_base + (ofs))
+
+/* 16-bit direct read (low 4K), with debug wrapper */
 static inline u16 __ipw_read16(char *f, u32 l, struct ipw_priv *ipw, u32 ofs)
 {
 	IPW_DEBUG_IO("%s %d: read_direct16(0x%08X)\n", f, l, (u32) (ofs));
 	return _ipw_read16(ipw, ofs);
 }
 
+/* alias to 16-bit direct read (low 4K of SRAM/regs), with debug wrapper */
 #define ipw_read16(ipw, ofs) __ipw_read16(__FILE__, __LINE__, ipw, ofs)
 
+/* 32-bit direct read (low 4K) */
 #define _ipw_read32(ipw, ofs) readl((ipw)->hw_base + (ofs))
+
+/* 32-bit direct read (low 4K), with debug wrapper */
 static inline u32 __ipw_read32(char *f, u32 l, struct ipw_priv *ipw, u32 ofs)
 {
 	IPW_DEBUG_IO("%s %d: read_direct32(0x%08X)\n", f, l, (u32) (ofs));
 	return _ipw_read32(ipw, ofs);
 }
 
+/* alias to 32-bit direct read (low 4K of SRAM/regs), with debug wrapper */
 #define ipw_read32(ipw, ofs) __ipw_read32(__FILE__, __LINE__, ipw, ofs)
 
+/* multi-byte read (above 4K), with debug wrapper */
 static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int);
 static inline void __ipw_read_indirect(const char *f, int l,
 				       struct ipw_priv *a, u32 b, u8 * c, int d)
@@ -308,15 +337,17 @@
 	_ipw_read_indirect(a, b, c, d);
 }
 
+/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */
 #define ipw_read_indirect(a, b, c, d) __ipw_read_indirect(__FILE__, __LINE__, a, b, c, d)
 
+/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */
 static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data,
 				int num);
 #define ipw_write_indirect(a, b, c, d) \
 	IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \
 	_ipw_write_indirect(a, b, c, d)
 
-/* indirect write s */
+/* 32-bit indirect write (above 4K) */
 static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value)
 {
 	IPW_DEBUG_IO(" %p : reg = 0x%8X : value = 0x%8X\n", priv, reg, value);
@@ -324,22 +355,29 @@
 	_ipw_write32(priv, IPW_INDIRECT_DATA, value);
 }
 
+/* 8-bit indirect write (above 4K) */
 static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value)
 {
+	u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK;	/* dword align */
+	u32 dif_len = reg - aligned_addr;
+
 	IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value);
-	_ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK);
-	_ipw_write8(priv, IPW_INDIRECT_DATA, value);
+	_ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
+	_ipw_write8(priv, IPW_INDIRECT_DATA + dif_len, value);
 }
 
+/* 16-bit indirect write (above 4K) */
 static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value)
 {
+	u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK;	/* dword align */
+	u32 dif_len = (reg - aligned_addr) & (~0x1ul);
+
 	IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value);
-	_ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK);
-	_ipw_write16(priv, IPW_INDIRECT_DATA, value);
+	_ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
+	_ipw_write16(priv, IPW_INDIRECT_DATA + dif_len, value);
 }
 
-/* indirect read s */
-
+/* 8-bit indirect read (above 4K) */
 static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg)
 {
 	u32 word;
@@ -349,6 +387,7 @@
 	return (word >> ((reg & 0x3) * 8)) & 0xff;
 }
 
+/* 32-bit indirect read (above 4K) */
 static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg)
 {
 	u32 value;
@@ -361,11 +400,12 @@
 	return value;
 }
 
-/* iterative/auto-increment 32 bit reads and writes */
+/* General purpose, no alignment requirement, iterative (multi-byte) read, */
+/*    for area above 1st 4K of SRAM/reg space */
 static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf,
 			       int num)
 {
-	u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK;
+	u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK;	/* dword align */
 	u32 dif_len = addr - aligned_addr;
 	u32 i;
 
@@ -375,7 +415,7 @@
 		return;
 	}
 
-	/* Read the first nibble byte by byte */
+	/* Read the first dword (or portion) byte by byte */
 	if (unlikely(dif_len)) {
 		_ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
 		/* Start reading at aligned_addr + dif_len */
@@ -384,11 +424,12 @@
 		aligned_addr += 4;
 	}
 
+	/* Read all of the middle dwords as dwords, with auto-increment */
 	_ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr);
 	for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4)
 		*(u32 *) buf = _ipw_read32(priv, IPW_AUTOINC_DATA);
 
-	/* Copy the last nibble */
+	/* Read the last dword (or portion) byte by byte */
 	if (unlikely(num)) {
 		_ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
 		for (i = 0; num > 0; i++, num--)
@@ -396,10 +437,12 @@
 	}
 }
 
+/* General purpose, no alignment requirement, iterative (multi-byte) write, */
+/*    for area above 1st 4K of SRAM/reg space */
 static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf,
 				int num)
 {
-	u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK;
+	u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK;	/* dword align */
 	u32 dif_len = addr - aligned_addr;
 	u32 i;
 
@@ -409,20 +452,21 @@
 		return;
 	}
 
-	/* Write the first nibble byte by byte */
+	/* Write the first dword (or portion) byte by byte */
 	if (unlikely(dif_len)) {
 		_ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
-		/* Start reading at aligned_addr + dif_len */
+		/* Start writing at aligned_addr + dif_len */
 		for (i = dif_len; ((i < 4) && (num > 0)); i++, num--, buf++)
 			_ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf);
 		aligned_addr += 4;
 	}
 
+	/* Write all of the middle dwords as dwords, with auto-increment */
 	_ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr);
 	for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4)
 		_ipw_write32(priv, IPW_AUTOINC_DATA, *(u32 *) buf);
 
-	/* Copy the last nibble */
+	/* Write the last dword (or portion) byte by byte */
 	if (unlikely(num)) {
 		_ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
 		for (i = 0; num > 0; i++, num--, buf++)
@@ -430,17 +474,21 @@
 	}
 }
 
+/* General purpose, no alignment requirement, iterative (multi-byte) write, */
+/*    for 1st 4K of SRAM/regs space */
 static void ipw_write_direct(struct ipw_priv *priv, u32 addr, void *buf,
 			     int num)
 {
 	memcpy_toio((priv->hw_base + addr), buf, num);
 }
 
+/* Set bit(s) in low 4K of SRAM/regs */
 static inline void ipw_set_bit(struct ipw_priv *priv, u32 reg, u32 mask)
 {
 	ipw_write32(priv, reg, ipw_read32(priv, reg) | mask);
 }
 
+/* Clear bit(s) in low 4K of SRAM/regs */
 static inline void ipw_clear_bit(struct ipw_priv *priv, u32 reg, u32 mask)
 {
 	ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask);
@@ -701,7 +749,7 @@
 
 }
 
-u32 ipw_register_toggle(u32 reg)
+static u32 ipw_register_toggle(u32 reg)
 {
 	reg &= ~IPW_START_STANDBY;
 	if (reg & IPW_GATE_ODMA)
@@ -722,11 +770,11 @@
  * - On radio OFF, turn off any LEDs started during radio on
  *
  */
-#define LD_TIME_LINK_ON 300
-#define LD_TIME_LINK_OFF 2700
-#define LD_TIME_ACT_ON 250
+#define LD_TIME_LINK_ON msecs_to_jiffies(300)
+#define LD_TIME_LINK_OFF msecs_to_jiffies(2700)
+#define LD_TIME_ACT_ON msecs_to_jiffies(250)
 
-void ipw_led_link_on(struct ipw_priv *priv)
+static void ipw_led_link_on(struct ipw_priv *priv)
 {
 	unsigned long flags;
 	u32 led;
@@ -764,12 +812,12 @@
 static void ipw_bg_led_link_on(void *data)
 {
 	struct ipw_priv *priv = data;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	ipw_led_link_on(data);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 }
 
-void ipw_led_link_off(struct ipw_priv *priv)
+static void ipw_led_link_off(struct ipw_priv *priv)
 {
 	unsigned long flags;
 	u32 led;
@@ -808,9 +856,9 @@
 static void ipw_bg_led_link_off(void *data)
 {
 	struct ipw_priv *priv = data;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	ipw_led_link_off(data);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 }
 
 static void __ipw_led_activity_on(struct ipw_priv *priv)
@@ -847,6 +895,7 @@
 	}
 }
 
+#if 0
 void ipw_led_activity_on(struct ipw_priv *priv)
 {
 	unsigned long flags;
@@ -854,8 +903,9 @@
 	__ipw_led_activity_on(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
+#endif  /*  0  */
 
-void ipw_led_activity_off(struct ipw_priv *priv)
+static void ipw_led_activity_off(struct ipw_priv *priv)
 {
 	unsigned long flags;
 	u32 led;
@@ -885,12 +935,12 @@
 static void ipw_bg_led_activity_off(void *data)
 {
 	struct ipw_priv *priv = data;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	ipw_led_activity_off(data);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 }
 
-void ipw_led_band_on(struct ipw_priv *priv)
+static void ipw_led_band_on(struct ipw_priv *priv)
 {
 	unsigned long flags;
 	u32 led;
@@ -925,7 +975,7 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-void ipw_led_band_off(struct ipw_priv *priv)
+static void ipw_led_band_off(struct ipw_priv *priv)
 {
 	unsigned long flags;
 	u32 led;
@@ -948,24 +998,24 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-void ipw_led_radio_on(struct ipw_priv *priv)
+static void ipw_led_radio_on(struct ipw_priv *priv)
 {
 	ipw_led_link_on(priv);
 }
 
-void ipw_led_radio_off(struct ipw_priv *priv)
+static void ipw_led_radio_off(struct ipw_priv *priv)
 {
 	ipw_led_activity_off(priv);
 	ipw_led_link_off(priv);
 }
 
-void ipw_led_link_up(struct ipw_priv *priv)
+static void ipw_led_link_up(struct ipw_priv *priv)
 {
 	/* Set the Link Led on for all nic types */
 	ipw_led_link_on(priv);
 }
 
-void ipw_led_link_down(struct ipw_priv *priv)
+static void ipw_led_link_down(struct ipw_priv *priv)
 {
 	ipw_led_activity_off(priv);
 	ipw_led_link_off(priv);
@@ -974,7 +1024,7 @@
 		ipw_led_radio_off(priv);
 }
 
-void ipw_led_init(struct ipw_priv *priv)
+static void ipw_led_init(struct ipw_priv *priv)
 {
 	priv->nic_type = priv->eeprom[EEPROM_NIC_TYPE];
 
@@ -1025,7 +1075,7 @@
 	}
 }
 
-void ipw_led_shutdown(struct ipw_priv *priv)
+static void ipw_led_shutdown(struct ipw_priv *priv)
 {
 	ipw_led_activity_off(priv);
 	ipw_led_link_off(priv);
@@ -1074,6 +1124,7 @@
 
 static inline u32 ipw_get_event_log_len(struct ipw_priv *priv)
 {
+	/* length = 1st dword in log */
 	return ipw_read_reg32(priv, ipw_read32(priv, IPW_EVENT_LOG));
 }
 
@@ -1870,7 +1921,8 @@
 }
 
 #define HOST_COMPLETE_TIMEOUT HZ
-static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd)
+
+static int __ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd)
 {
 	int rc = 0;
 	unsigned long flags;
@@ -1897,9 +1949,15 @@
 	IPW_DEBUG_HC("%s command (#%d) %d bytes: 0x%08X\n",
 		     get_cmd_string(cmd->cmd), cmd->cmd, cmd->len,
 		     priv->status);
-	printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len);
 
-	rc = ipw_queue_tx_hcmd(priv, cmd->cmd, &cmd->param, cmd->len, 0);
+#ifndef DEBUG_CMD_WEP_KEY
+	if (cmd->cmd == IPW_CMD_WEP_KEY)
+		IPW_DEBUG_HC("WEP_KEY command masked out for secure.\n");
+	else
+#endif
+		printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len);
+
+	rc = ipw_queue_tx_hcmd(priv, cmd->cmd, cmd->param, cmd->len, 0);
 	if (rc) {
 		priv->status &= ~STATUS_HCMD_ACTIVE;
 		IPW_ERROR("Failed to send %s: Reason %d\n",
@@ -1942,61 +2000,62 @@
 	return rc;
 }
 
-static int ipw_send_host_complete(struct ipw_priv *priv)
+static int ipw_send_cmd_simple(struct ipw_priv *priv, u8 command)
+{
+	struct host_cmd cmd = {
+		.cmd = command,
+	};
+
+	return __ipw_send_cmd(priv, &cmd);
+}
+
+static int ipw_send_cmd_pdu(struct ipw_priv *priv, u8 command, u8 len,
+			    void *data)
 {
 	struct host_cmd cmd = {
-		.cmd = IPW_CMD_HOST_COMPLETE,
-		.len = 0
+		.cmd = command,
+		.len = len,
+		.param = data,
 	};
 
+	return __ipw_send_cmd(priv, &cmd);
+}
+
+static int ipw_send_host_complete(struct ipw_priv *priv)
+{
 	if (!priv) {
 		IPW_ERROR("Invalid args\n");
 		return -1;
 	}
 
-	return ipw_send_cmd(priv, &cmd);
+	return ipw_send_cmd_simple(priv, IPW_CMD_HOST_COMPLETE);
 }
 
 static int ipw_send_system_config(struct ipw_priv *priv,
 				  struct ipw_sys_config *config)
 {
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_SYSTEM_CONFIG,
-		.len = sizeof(*config)
-	};
-
 	if (!priv || !config) {
 		IPW_ERROR("Invalid args\n");
 		return -1;
 	}
 
-	memcpy(cmd.param, config, sizeof(*config));
-	return ipw_send_cmd(priv, &cmd);
+	return ipw_send_cmd_pdu(priv, IPW_CMD_SYSTEM_CONFIG, sizeof(*config),
+				config);
 }
 
 static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len)
 {
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_SSID,
-		.len = min(len, IW_ESSID_MAX_SIZE)
-	};
-
 	if (!priv || !ssid) {
 		IPW_ERROR("Invalid args\n");
 		return -1;
 	}
 
-	memcpy(cmd.param, ssid, cmd.len);
-	return ipw_send_cmd(priv, &cmd);
+	return ipw_send_cmd_pdu(priv, IPW_CMD_SSID, min(len, IW_ESSID_MAX_SIZE),
+				ssid);
 }
 
 static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac)
 {
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_ADAPTER_ADDRESS,
-		.len = ETH_ALEN
-	};
-
 	if (!priv || !mac) {
 		IPW_ERROR("Invalid args\n");
 		return -1;
@@ -2005,8 +2064,7 @@
 	IPW_DEBUG_INFO("%s: Setting MAC to " MAC_FMT "\n",
 		       priv->net_dev->name, MAC_ARG(mac));
 
-	memcpy(cmd.param, mac, ETH_ALEN);
-	return ipw_send_cmd(priv, &cmd);
+	return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac);
 }
 
 /*
@@ -2036,9 +2094,9 @@
 static void ipw_bg_adapter_restart(void *data)
 {
 	struct ipw_priv *priv = data;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	ipw_adapter_restart(data);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 }
 
 #define IPW_SCAN_CHECK_WATCHDOG (5 * HZ)
@@ -2048,8 +2106,8 @@
 	struct ipw_priv *priv = data;
 	if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) {
 		IPW_DEBUG_SCAN("Scan completion watchdog resetting "
-			       "adapter (%dms).\n",
-			       IPW_SCAN_CHECK_WATCHDOG / 100);
+			       "adapter after (%dms).\n",
+			       jiffies_to_msecs(IPW_SCAN_CHECK_WATCHDOG));
 		queue_work(priv->workqueue, &priv->adapter_restart);
 	}
 }
@@ -2057,59 +2115,48 @@
 static void ipw_bg_scan_check(void *data)
 {
 	struct ipw_priv *priv = data;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	ipw_scan_check(data);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 }
 
 static int ipw_send_scan_request_ext(struct ipw_priv *priv,
 				     struct ipw_scan_request_ext *request)
 {
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_SCAN_REQUEST_EXT,
-		.len = sizeof(*request)
-	};
-
-	memcpy(cmd.param, request, sizeof(*request));
-	return ipw_send_cmd(priv, &cmd);
+	return ipw_send_cmd_pdu(priv, IPW_CMD_SCAN_REQUEST_EXT,
+				sizeof(*request), request);
 }
 
 static int ipw_send_scan_abort(struct ipw_priv *priv)
 {
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_SCAN_ABORT,
-		.len = 0
-	};
-
 	if (!priv) {
 		IPW_ERROR("Invalid args\n");
 		return -1;
 	}
 
-	return ipw_send_cmd(priv, &cmd);
+	return ipw_send_cmd_simple(priv, IPW_CMD_SCAN_ABORT);
 }
 
 static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens)
 {
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_SENSITIVITY_CALIB,
-		.len = sizeof(struct ipw_sensitivity_calib)
+	struct ipw_sensitivity_calib calib = {
+		.beacon_rssi_raw = sens,
 	};
-	struct ipw_sensitivity_calib *calib = (struct ipw_sensitivity_calib *)
-	    &cmd.param;
-	calib->beacon_rssi_raw = sens;
-	return ipw_send_cmd(priv, &cmd);
+
+	return ipw_send_cmd_pdu(priv, IPW_CMD_SENSITIVITY_CALIB, sizeof(calib),
+				&calib);
 }
 
 static int ipw_send_associate(struct ipw_priv *priv,
 			      struct ipw_associate *associate)
 {
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_ASSOCIATE,
-		.len = sizeof(*associate)
-	};
-
 	struct ipw_associate tmp_associate;
+
+	if (!priv || !associate) {
+		IPW_ERROR("Invalid args\n");
+		return -1;
+	}
+
 	memcpy(&tmp_associate, associate, sizeof(*associate));
 	tmp_associate.policy_support =
 	    cpu_to_le16(tmp_associate.policy_support);
@@ -2122,80 +2169,55 @@
 	    cpu_to_le16(tmp_associate.beacon_interval);
 	tmp_associate.atim_window = cpu_to_le16(tmp_associate.atim_window);
 
-	if (!priv || !associate) {
-		IPW_ERROR("Invalid args\n");
-		return -1;
-	}
-
-	memcpy(cmd.param, &tmp_associate, sizeof(*associate));
-	return ipw_send_cmd(priv, &cmd);
+	return ipw_send_cmd_pdu(priv, IPW_CMD_ASSOCIATE, sizeof(tmp_associate),
+				&tmp_associate);
 }
 
 static int ipw_send_supported_rates(struct ipw_priv *priv,
 				    struct ipw_supported_rates *rates)
 {
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_SUPPORTED_RATES,
-		.len = sizeof(*rates)
-	};
-
 	if (!priv || !rates) {
 		IPW_ERROR("Invalid args\n");
 		return -1;
 	}
 
-	memcpy(cmd.param, rates, sizeof(*rates));
-	return ipw_send_cmd(priv, &cmd);
+	return ipw_send_cmd_pdu(priv, IPW_CMD_SUPPORTED_RATES, sizeof(*rates),
+				rates);
 }
 
 static int ipw_set_random_seed(struct ipw_priv *priv)
 {
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_SEED_NUMBER,
-		.len = sizeof(u32)
-	};
+	u32 val;
 
 	if (!priv) {
 		IPW_ERROR("Invalid args\n");
 		return -1;
 	}
 
-	get_random_bytes(&cmd.param, sizeof(u32));
+	get_random_bytes(&val, sizeof(val));
 
-	return ipw_send_cmd(priv, &cmd);
+	return ipw_send_cmd_pdu(priv, IPW_CMD_SEED_NUMBER, sizeof(val), &val);
 }
 
 static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off)
 {
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_CARD_DISABLE,
-		.len = sizeof(u32)
-	};
-
 	if (!priv) {
 		IPW_ERROR("Invalid args\n");
 		return -1;
 	}
 
-	*((u32 *) & cmd.param) = phy_off;
-
-	return ipw_send_cmd(priv, &cmd);
+	return ipw_send_cmd_pdu(priv, IPW_CMD_CARD_DISABLE, sizeof(phy_off),
+				&phy_off);
 }
 
 static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power)
 {
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_TX_POWER,
-		.len = sizeof(*power)
-	};
-
 	if (!priv || !power) {
 		IPW_ERROR("Invalid args\n");
 		return -1;
 	}
 
-	memcpy(cmd.param, power, sizeof(*power));
-	return ipw_send_cmd(priv, &cmd);
+	return ipw_send_cmd_pdu(priv, IPW_CMD_TX_POWER, sizeof(*power), power);
 }
 
 static int ipw_set_tx_power(struct ipw_priv *priv)
@@ -2247,18 +2269,14 @@
 	struct ipw_rts_threshold rts_threshold = {
 		.rts_threshold = rts,
 	};
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_RTS_THRESHOLD,
-		.len = sizeof(rts_threshold)
-	};
 
 	if (!priv) {
 		IPW_ERROR("Invalid args\n");
 		return -1;
 	}
 
-	memcpy(cmd.param, &rts_threshold, sizeof(rts_threshold));
-	return ipw_send_cmd(priv, &cmd);
+	return ipw_send_cmd_pdu(priv, IPW_CMD_RTS_THRESHOLD,
+				sizeof(rts_threshold), &rts_threshold);
 }
 
 static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag)
@@ -2266,27 +2284,19 @@
 	struct ipw_frag_threshold frag_threshold = {
 		.frag_threshold = frag,
 	};
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_FRAG_THRESHOLD,
-		.len = sizeof(frag_threshold)
-	};
 
 	if (!priv) {
 		IPW_ERROR("Invalid args\n");
 		return -1;
 	}
 
-	memcpy(cmd.param, &frag_threshold, sizeof(frag_threshold));
-	return ipw_send_cmd(priv, &cmd);
+	return ipw_send_cmd_pdu(priv, IPW_CMD_FRAG_THRESHOLD,
+				sizeof(frag_threshold), &frag_threshold);
 }
 
 static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode)
 {
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_POWER_MODE,
-		.len = sizeof(u32)
-	};
-	u32 *param = (u32 *) (&cmd.param);
+	u32 param;
 
 	if (!priv) {
 		IPW_ERROR("Invalid args\n");
@@ -2297,17 +2307,18 @@
 	 * level */
 	switch (mode) {
 	case IPW_POWER_BATTERY:
-		*param = IPW_POWER_INDEX_3;
+		param = IPW_POWER_INDEX_3;
 		break;
 	case IPW_POWER_AC:
-		*param = IPW_POWER_MODE_CAM;
+		param = IPW_POWER_MODE_CAM;
 		break;
 	default:
-		*param = mode;
+		param = mode;
 		break;
 	}
 
-	return ipw_send_cmd(priv, &cmd);
+	return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param),
+				&param);
 }
 
 static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit)
@@ -2316,18 +2327,14 @@
 		.short_retry_limit = slimit,
 		.long_retry_limit = llimit
 	};
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_RETRY_LIMIT,
-		.len = sizeof(retry_limit)
-	};
 
 	if (!priv) {
 		IPW_ERROR("Invalid args\n");
 		return -1;
 	}
 
-	memcpy(cmd.param, &retry_limit, sizeof(retry_limit));
-	return ipw_send_cmd(priv, &cmd);
+	return ipw_send_cmd_pdu(priv, IPW_CMD_RETRY_LIMIT, sizeof(retry_limit),
+				&retry_limit);
 }
 
 /*
@@ -2454,7 +2461,7 @@
 	/*
 	   If the data looks correct, then copy it to our private
 	   copy.  Otherwise let the firmware know to perform the operation
-	   on it's own
+	   on its own.
 	 */
 	if (priv->eeprom[EEPROM_VERSION] != 0) {
 		IPW_DEBUG_INFO("Writing EEPROM data into SRAM\n");
@@ -2707,22 +2714,25 @@
 
 static int ipw_fw_dma_wait(struct ipw_priv *priv)
 {
-	u32 current_index = 0;
+	u32 current_index = 0, previous_index;
 	u32 watchdog = 0;
 
 	IPW_DEBUG_FW(">> : \n");
 
 	current_index = ipw_fw_dma_command_block_index(priv);
-	IPW_DEBUG_FW_INFO("sram_desc.last_cb_index:0x%8X\n",
+	IPW_DEBUG_FW_INFO("sram_desc.last_cb_index:0x%08X\n",
 			  (int)priv->sram_desc.last_cb_index);
 
 	while (current_index < priv->sram_desc.last_cb_index) {
 		udelay(50);
+		previous_index = current_index;
 		current_index = ipw_fw_dma_command_block_index(priv);
 
-		watchdog++;
-
-		if (watchdog > 400) {
+		if (previous_index < current_index) {
+			watchdog = 0;
+			continue;
+		}
+		if (++watchdog > 400) {
 			IPW_DEBUG_FW_INFO("Timeout\n");
 			ipw_fw_dma_dump_command_block(priv);
 			ipw_fw_dma_abort(priv);
@@ -2772,6 +2782,7 @@
 	return ipw_read32(priv, 0x90) == 0xd55555d5;
 }
 
+/* timeout in msec, attempted in 10-msec quanta */
 static int ipw_poll_bit(struct ipw_priv *priv, u32 addr, u32 mask,
 			       int timeout)
 {
@@ -2800,10 +2811,11 @@
 	/* stop master. typical delay - 0 */
 	ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER);
 
+	/* timeout is in msec, polled in 10-msec quanta */
 	rc = ipw_poll_bit(priv, IPW_RESET_REG,
 			  IPW_RESET_REG_MASTER_DISABLED, 100);
 	if (rc < 0) {
-		IPW_ERROR("stop master failed in 10ms\n");
+		IPW_ERROR("wait for stop master failed after 100ms\n");
 		return -1;
 	}
 
@@ -2890,8 +2902,8 @@
 	mdelay(1);
 
 	/* enable ucode store */
-	ipw_write_reg8(priv, DINO_CONTROL_REG, 0x0);
-	ipw_write_reg8(priv, DINO_CONTROL_REG, DINO_ENABLE_CS);
+	ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0x0);
+	ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, DINO_ENABLE_CS);
 	mdelay(1);
 
 	/* write ucode */
@@ -3036,7 +3048,7 @@
 	rc = ipw_poll_bit(priv, IPW_RESET_REG,
 			  IPW_RESET_REG_MASTER_DISABLED, 500);
 	if (rc < 0) {
-		IPW_ERROR("wait for reg master disabled failed\n");
+		IPW_ERROR("wait for reg master disabled failed after 500ms\n");
 		return rc;
 	}
 
@@ -3209,55 +3221,29 @@
 	const struct firmware *firmware = NULL;
 	const struct firmware *ucode = NULL;
 #endif
+	char *ucode_name;
+	char *fw_name;
 	int rc = 0, retries = 3;
 
-#ifdef CONFIG_PM
-	if (!fw_loaded) {
-#endif
-		rc = ipw_get_fw(priv, &bootfw, IPW_FW_NAME("boot"));
-		if (rc)
-			goto error;
-
-		switch (priv->ieee->iw_mode) {
-		case IW_MODE_ADHOC:
-			rc = ipw_get_fw(priv, &ucode,
-					IPW_FW_NAME("ibss_ucode"));
-			if (rc)
-				goto error;
-
-			rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("ibss"));
-			break;
-
+	switch (priv->ieee->iw_mode) {
+	case IW_MODE_ADHOC:
+		ucode_name = IPW_FW_NAME("ibss_ucode");
+		fw_name = IPW_FW_NAME("ibss");
+		break;
 #ifdef CONFIG_IPW2200_MONITOR
-		case IW_MODE_MONITOR:
-			rc = ipw_get_fw(priv, &ucode,
-					IPW_FW_NAME("sniffer_ucode"));
-			if (rc)
-				goto error;
-
-			rc = ipw_get_fw(priv, &firmware,
-					IPW_FW_NAME("sniffer"));
-			break;
+	case IW_MODE_MONITOR:
+		ucode_name = IPW_FW_NAME("sniffer_ucode");
+		fw_name = IPW_FW_NAME("sniffer");
+		break;
 #endif
-		case IW_MODE_INFRA:
-			rc = ipw_get_fw(priv, &ucode, IPW_FW_NAME("bss_ucode"));
-			if (rc)
-				goto error;
-
-			rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("bss"));
-			break;
-
-		default:
-			rc = -EINVAL;
-		}
-
-		if (rc)
-			goto error;
-
-#ifdef CONFIG_PM
-		fw_loaded = 1;
+	case IW_MODE_INFRA:
+		ucode_name = IPW_FW_NAME("bss_ucode");
+		fw_name = IPW_FW_NAME("bss");
+		break;
+	default:
+		rc = -EINVAL;
+		goto error;
 	}
-#endif
 
 	if (!priv->rxq)
 		priv->rxq = ipw_rx_queue_alloc(priv);
@@ -3279,7 +3265,7 @@
 	ipw_stop_nic(priv);
 
 	rc = ipw_reset_nic(priv);
-	if (rc) {
+	if (rc < 0) {
 		IPW_ERROR("Unable to reset NIC\n");
 		goto error;
 	}
@@ -3287,6 +3273,15 @@
 	ipw_zero_memory(priv, IPW_NIC_SRAM_LOWER_BOUND,
 			IPW_NIC_SRAM_UPPER_BOUND - IPW_NIC_SRAM_LOWER_BOUND);
 
+#ifdef CONFIG_PM
+	if (!fw_loaded) {
+#endif
+		rc = ipw_get_fw(priv, &bootfw, IPW_FW_NAME("boot"));
+		if (rc < 0)
+			goto error;
+#ifdef CONFIG_PM
+	}
+#endif
 	/* DMA the initial boot firmware into the device */
 	rc = ipw_load_firmware(priv, bootfw->data + sizeof(struct fw_header),
 			       bootfw->size - sizeof(struct fw_header));
@@ -3298,7 +3293,7 @@
 	/* kick start the device */
 	ipw_start_nic(priv);
 
-	/* wait for the device to finish it's initial startup sequence */
+	/* wait for the device to finish its initial startup sequence */
 	rc = ipw_poll_bit(priv, IPW_INTA_RW,
 			  IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500);
 	if (rc < 0) {
@@ -3310,6 +3305,16 @@
 	/* ack fw init done interrupt */
 	ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE);
 
+#ifdef CONFIG_PM
+	if (!fw_loaded) {
+#endif
+		rc = ipw_get_fw(priv, &ucode, ucode_name);
+		if (rc < 0)
+			goto error;
+#ifdef CONFIG_PM
+	}
+#endif
+
 	/* DMA the ucode into the device */
 	rc = ipw_load_ucode(priv, ucode->data + sizeof(struct fw_header),
 			    ucode->size - sizeof(struct fw_header));
@@ -3321,6 +3326,16 @@
 	/* stop nic */
 	ipw_stop_nic(priv);
 
+#ifdef CONFIG_PM
+	if (!fw_loaded) {
+#endif
+		rc = ipw_get_fw(priv, &firmware, fw_name);
+		if (rc < 0)
+			goto error;
+#ifdef CONFIG_PM
+	}
+#endif
+
 	/* DMA bss firmware into the device */
 	rc = ipw_load_firmware(priv, firmware->data +
 			       sizeof(struct fw_header),
@@ -3329,11 +3344,14 @@
 		IPW_ERROR("Unable to load firmware: %d\n", rc);
 		goto error;
 	}
+#ifdef CONFIG_PM
+	fw_loaded = 1;
+#endif
 
 	ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0);
 
 	rc = ipw_queue_reset(priv);
-	if (rc) {
+	if (rc < 0) {
 		IPW_ERROR("Unable to initialize queues\n");
 		goto error;
 	}
@@ -3362,7 +3380,7 @@
 	rc = ipw_poll_bit(priv, IPW_INTA_RW,
 			  IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500);
 	if (rc < 0) {
-		IPW_ERROR("device failed to start after 500ms\n");
+		IPW_ERROR("device failed to start within 500ms\n");
 		goto error;
 	}
 	IPW_DEBUG_INFO("device response after %dms\n", rc);
@@ -3715,9 +3733,9 @@
 static void ipw_bg_disassociate(void *data)
 {
 	struct ipw_priv *priv = data;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	ipw_disassociate(data);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 }
 
 static void ipw_system_config(void *data)
@@ -4077,9 +4095,9 @@
 static void ipw_bg_gather_stats(void *data)
 {
 	struct ipw_priv *priv = data;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	ipw_gather_stats(data);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 }
 
 /* Missed beacon behavior:
@@ -4121,8 +4139,9 @@
 		return;
 	}
 
-	if (missed_count > priv->roaming_threshold &&
-	    missed_count <= priv->disassociate_threshold) {
+	if (roaming &&
+	    (missed_count > priv->roaming_threshold &&
+	     missed_count <= priv->disassociate_threshold)) {
 		/* If we are not already roaming, set the ROAM
 		 * bit in the status and kick off a scan.
 		 * This can happen several times before we reach
@@ -4150,7 +4169,6 @@
 	}
 
 	IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count);
-
 }
 
 /**
@@ -4616,9 +4634,9 @@
 		}
 
 	default:
-		IPW_ERROR("Unknown notification: "
-			  "subtype=%d,flags=0x%2x,size=%d\n",
-			  notif->subtype, notif->flags, notif->size);
+		IPW_DEBUG_NOTIF("Unknown notification: "
+				"subtype=%d,flags=0x%2x,size=%d\n",
+				notif->subtype, notif->flags, notif->size);
 	}
 }
 
@@ -4911,13 +4929,13 @@
 static void ipw_bg_rx_queue_replenish(void *data)
 {
 	struct ipw_priv *priv = data;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	ipw_rx_queue_replenish(data);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 }
 
 /* Assumes that the skb field of the buffers in 'pool' is kept accurate.
- * If an SKB has been detached, the POOL needs to have it's SKB set to NULL
+ * If an SKB has been detached, the POOL needs to have its SKB set to NULL
  * This free routine walks the list of POOL entries and if SKB is set to
  * non NULL it is unmapped and freed
  */
@@ -5257,10 +5275,11 @@
 	if (priv->ieee->scan_age != 0 &&
 	    time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
 		IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
-				"because of age: %lums.\n",
+				"because of age: %ums.\n",
 				escape_essid(network->ssid, network->ssid_len),
 				MAC_ARG(network->bssid),
-				1000 * (jiffies - network->last_scanned) / HZ);
+				jiffies_to_msecs(jiffies -
+						 network->last_scanned));
 		return 0;
 	}
 
@@ -5369,7 +5388,7 @@
 			return;
 		}
 
-		down(&priv->sem);
+		mutex_lock(&priv->mutex);
 		if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) {
 			IPW_DEBUG_MERGE("remove network %s\n",
 					escape_essid(priv->essid,
@@ -5379,7 +5398,7 @@
 
 		ipw_disassociate(priv);
 		priv->assoc_network = match.network;
-		up(&priv->sem);
+		mutex_unlock(&priv->mutex);
 		return;
 	}
 }
@@ -5467,11 +5486,12 @@
 	if (network->last_associate &&
 	    time_after(network->last_associate + (HZ * 3UL), jiffies)) {
 		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
-				"because of storming (%lus since last "
+				"because of storming (%ums since last "
 				"assoc attempt).\n",
 				escape_essid(network->ssid, network->ssid_len),
 				MAC_ARG(network->bssid),
-				(jiffies - network->last_associate) / HZ);
+				jiffies_to_msecs(jiffies -
+						 network->last_associate));
 		return 0;
 	}
 
@@ -5479,10 +5499,11 @@
 	if (priv->ieee->scan_age != 0 &&
 	    time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
 		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
-				"because of age: %lums.\n",
+				"because of age: %ums.\n",
 				escape_essid(network->ssid, network->ssid_len),
 				MAC_ARG(network->bssid),
-				1000 * (jiffies - network->last_scanned) / HZ);
+				jiffies_to_msecs(jiffies -
+						 network->last_scanned));
 		return 0;
 	}
 
@@ -5671,54 +5692,44 @@
 
 static void ipw_send_tgi_tx_key(struct ipw_priv *priv, int type, int index)
 {
-	struct ipw_tgi_tx_key *key;
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_TGI_TX_KEY,
-		.len = sizeof(*key)
-	};
+	struct ipw_tgi_tx_key key;
 
 	if (!(priv->ieee->sec.flags & (1 << index)))
 		return;
 
-	key = (struct ipw_tgi_tx_key *)&cmd.param;
-	key->key_id = index;
-	memcpy(key->key, priv->ieee->sec.keys[index], SCM_TEMPORAL_KEY_LENGTH);
-	key->security_type = type;
-	key->station_index = 0;	/* always 0 for BSS */
-	key->flags = 0;
+	key.key_id = index;
+	memcpy(key.key, priv->ieee->sec.keys[index], SCM_TEMPORAL_KEY_LENGTH);
+	key.security_type = type;
+	key.station_index = 0;	/* always 0 for BSS */
+	key.flags = 0;
 	/* 0 for new key; previous value of counter (after fatal error) */
-	key->tx_counter[0] = 0;
-	key->tx_counter[1] = 0;
+	key.tx_counter[0] = 0;
+	key.tx_counter[1] = 0;
 
-	ipw_send_cmd(priv, &cmd);
+	ipw_send_cmd_pdu(priv, IPW_CMD_TGI_TX_KEY, sizeof(key), &key);
 }
 
 static void ipw_send_wep_keys(struct ipw_priv *priv, int type)
 {
-	struct ipw_wep_key *key;
+	struct ipw_wep_key key;
 	int i;
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_WEP_KEY,
-		.len = sizeof(*key)
-	};
 
-	key = (struct ipw_wep_key *)&cmd.param;
-	key->cmd_id = DINO_CMD_WEP_KEY;
-	key->seq_num = 0;
+	key.cmd_id = DINO_CMD_WEP_KEY;
+	key.seq_num = 0;
 
 	/* Note: AES keys cannot be set for multiple times.
 	 * Only set it at the first time. */
 	for (i = 0; i < 4; i++) {
-		key->key_index = i | type;
+		key.key_index = i | type;
 		if (!(priv->ieee->sec.flags & (1 << i))) {
-			key->key_size = 0;
+			key.key_size = 0;
 			continue;
 		}
 
-		key->key_size = priv->ieee->sec.key_sizes[i];
-		memcpy(key->key, priv->ieee->sec.keys[i], key->key_size);
+		key.key_size = priv->ieee->sec.key_sizes[i];
+		memcpy(key.key, priv->ieee->sec.keys[i], key.key_size);
 
-		ipw_send_cmd(priv, &cmd);
+		ipw_send_cmd_pdu(priv, IPW_CMD_WEP_KEY, sizeof(key), &key);
 	}
 }
 
@@ -5822,9 +5833,9 @@
 static void ipw_bg_adhoc_check(void *data)
 {
 	struct ipw_priv *priv = data;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	ipw_adhoc_check(data);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 }
 
 #ifdef CONFIG_IPW2200_DEBUG
@@ -6051,7 +6062,7 @@
 	    (priv->status & STATUS_EXIT_PENDING))
 		return 0;
 
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 
 	if (priv->status & STATUS_SCANNING) {
 		IPW_DEBUG_HC("Concurrent scan requested.  Ignoring.\n");
@@ -6159,16 +6170,16 @@
 	queue_delayed_work(priv->workqueue, &priv->scan_check,
 			   IPW_SCAN_CHECK_WATCHDOG);
       done:
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return err;
 }
 
 static void ipw_bg_abort_scan(void *data)
 {
 	struct ipw_priv *priv = data;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	ipw_abort_scan(data);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 }
 
 static int ipw_wpa_enable(struct ipw_priv *priv, int value)
@@ -6193,6 +6204,9 @@
 	} else if (value & IW_AUTH_ALG_OPEN_SYSTEM) {
 		sec.auth_mode = WLAN_AUTH_OPEN;
 		ieee->open_wep = 1;
+	} else if (value & IW_AUTH_ALG_LEAP) {
+		sec.auth_mode = WLAN_AUTH_LEAP;
+		ieee->open_wep = 1;
 	} else
 		return -EINVAL;
 
@@ -6204,7 +6218,8 @@
 	return ret;
 }
 
-void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie, int wpa_ie_len)
+static void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie,
+				int wpa_ie_len)
 {
 	/* make sure WPA is enabled */
 	ipw_wpa_enable(priv, 1);
@@ -6215,15 +6230,10 @@
 static int ipw_set_rsn_capa(struct ipw_priv *priv,
 			    char *capabilities, int length)
 {
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_RSN_CAPABILITIES,
-		.len = length,
-	};
-
 	IPW_DEBUG_HC("HOST_CMD_RSN_CAPABILITIES\n");
 
-	memcpy(cmd.param, capabilities, length);
-	return ipw_send_cmd(priv, &cmd);
+	return ipw_send_cmd_pdu(priv, IPW_CMD_RSN_CAPABILITIES, length,
+				capabilities);
 }
 
 /*
@@ -6244,7 +6254,7 @@
 	    (wrqu->data.length && extra == NULL))
 		return -EINVAL;
 
-	//down(&priv->sem);
+	//mutex_lock(&priv->mutex);
 
 	//if (!ieee->wpa_enabled) {
 	//      err = -EOPNOTSUPP;
@@ -6270,7 +6280,7 @@
 
 	ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
       out:
-	//up(&priv->sem);
+	//mutex_unlock(&priv->mutex);
 	return err;
 }
 
@@ -6283,7 +6293,7 @@
 	struct ieee80211_device *ieee = priv->ieee;
 	int err = 0;
 
-	//down(&priv->sem);
+	//mutex_lock(&priv->mutex);
 
 	//if (!ieee->wpa_enabled) {
 	//      err = -EOPNOTSUPP;
@@ -6304,7 +6314,7 @@
 	memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
 
       out:
-	//up(&priv->sem);
+	//mutex_unlock(&priv->mutex);
 	return err;
 }
 
@@ -6964,12 +6974,12 @@
 	if (priv == NULL)
 		return;
 
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 
 	if (priv->status & STATUS_ASSOCIATED)
 		ipw_qos_activate(priv, &(priv->assoc_network->qos_data));
 
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 }
 
 static int ipw_handle_probe_response(struct net_device *dev,
@@ -7010,25 +7020,15 @@
 static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters
 				       *qos_param)
 {
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_QOS_PARAMETERS,
-		.len = (sizeof(struct ieee80211_qos_parameters) * 3)
-	};
-
-	memcpy(cmd.param, qos_param, sizeof(*qos_param) * 3);
-	return ipw_send_cmd(priv, &cmd);
+	return ipw_send_cmd_pdu(priv, IPW_CMD_QOS_PARAMETERS,
+				sizeof(*qos_param) * 3, qos_param);
 }
 
 static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element
 				     *qos_param)
 {
-	struct host_cmd cmd = {
-		.cmd = IPW_CMD_WME_INFO,
-		.len = sizeof(*qos_param)
-	};
-
-	memcpy(cmd.param, qos_param, sizeof(*qos_param));
-	return ipw_send_cmd(priv, &cmd);
+	return ipw_send_cmd_pdu(priv, IPW_CMD_WME_INFO, sizeof(*qos_param),
+				qos_param);
 }
 
 #endif				/* CONFIG_IPW_QOS */
@@ -7052,19 +7052,21 @@
 
 	memset(&priv->assoc_request, 0, sizeof(priv->assoc_request));
 	priv->assoc_request.channel = network->channel;
+	priv->assoc_request.auth_key = 0;
+
 	if ((priv->capability & CAP_PRIVACY_ON) &&
-	    (priv->capability & CAP_SHARED_KEY)) {
+	    (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY)) {
 		priv->assoc_request.auth_type = AUTH_SHARED_KEY;
 		priv->assoc_request.auth_key = priv->ieee->sec.active_key;
 
-		if ((priv->capability & CAP_PRIVACY_ON) &&
-		    (priv->ieee->sec.level == SEC_LEVEL_1) &&
-		    !(priv->ieee->host_encrypt || priv->ieee->host_decrypt))
+		if (priv->ieee->sec.level == SEC_LEVEL_1)
 			ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP);
-	} else {
+
+	} else if ((priv->capability & CAP_PRIVACY_ON) &&
+		   (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP))
+		priv->assoc_request.auth_type = AUTH_LEAP;
+	else
 		priv->assoc_request.auth_type = AUTH_OPEN;
-		priv->assoc_request.auth_key = 0;
-	}
 
 	if (priv->ieee->wpa_ie_len) {
 		priv->assoc_request.policy_support = 0x02;	/* RSN active */
@@ -7278,9 +7280,9 @@
 static void ipw_bg_roam(void *data)
 {
 	struct ipw_priv *priv = data;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	ipw_roam(data);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 }
 
 static int ipw_associate(void *data)
@@ -7375,9 +7377,9 @@
 static void ipw_bg_associate(void *data)
 {
 	struct ipw_priv *priv = data;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	ipw_associate(data);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 }
 
 static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv,
@@ -8126,7 +8128,7 @@
 			   union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	if (priv->status & STATUS_RF_KILL_MASK)
 		strcpy(wrqu->name, "radio off");
 	else if (!(priv->status & STATUS_ASSOCIATED))
@@ -8135,7 +8137,7 @@
 		snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c",
 			 ipw_modes[priv->assoc_request.ieee_mode]);
 	IPW_DEBUG_WX("Name: %s\n", wrqu->name);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return 0;
 }
 
@@ -8204,9 +8206,9 @@
 
 	if (fwrq->m == 0) {
 		IPW_DEBUG_WX("SET Freq/Channel -> any\n");
-		down(&priv->sem);
+		mutex_lock(&priv->mutex);
 		ret = ipw_set_channel(priv, 0);
-		up(&priv->sem);
+		mutex_unlock(&priv->mutex);
 		return ret;
 	}
 	/* if setting by freq convert to channel */
@@ -8234,9 +8236,9 @@
 	}
 
 	IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m);
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	ret = ipw_set_channel(priv, channel);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return ret;
 }
 
@@ -8250,14 +8252,14 @@
 
 	/* If we are associated, trying to associate, or have a statically
 	 * configured CHANNEL then return that; otherwise return ANY */
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	if (priv->config & CFG_STATIC_CHANNEL ||
 	    priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED))
 		wrqu->freq.m = priv->channel;
 	else
 		wrqu->freq.m = 0;
 
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel);
 	return 0;
 }
@@ -8287,7 +8289,7 @@
 	if (wrqu->mode == priv->ieee->iw_mode)
 		return 0;
 
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 
 	ipw_sw_reset(priv, 0);
 
@@ -8310,7 +8312,7 @@
 	priv->ieee->iw_mode = wrqu->mode;
 
 	queue_work(priv->workqueue, &priv->adapter_restart);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return err;
 }
 
@@ -8319,10 +8321,10 @@
 			   union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	wrqu->mode = priv->ieee->iw_mode;
 	IPW_DEBUG_WX("Get MODE -> %d\n", wrqu->mode);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return 0;
 }
 
@@ -8369,7 +8371,7 @@
 	range->avg_qual.level = 0;	/* FIXME to real average level */
 	range->avg_qual.noise = 0;
 	range->avg_qual.updated = 7;	/* Updated all three */
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	range->num_bitrates = min(priv->rates.num_rates, (u8) IW_MAX_BITRATES);
 
 	for (i = 0; i < range->num_bitrates; i++)
@@ -8387,7 +8389,7 @@
 
 	/* Set the Wireless Extension versions */
 	range->we_version_compiled = WIRELESS_EXT;
-	range->we_version_source = 16;
+	range->we_version_source = 18;
 
 	i = 0;
 	if (priv->ieee->mode & (IEEE_B | IEEE_G)) {
@@ -8411,7 +8413,7 @@
 	range->num_channels = i;
 	range->num_frequency = i;
 
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 
 	/* Event capability (kernel + driver) */
 	range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
@@ -8419,6 +8421,9 @@
 				IW_EVENT_CAPA_MASK(SIOCGIWAP));
 	range->event_capa[1] = IW_EVENT_CAPA_K_1;
 
+	range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+		IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+
 	IPW_DEBUG_WX("GET Range\n");
 	return 0;
 }
@@ -8438,7 +8443,7 @@
 
 	if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
 		return -EINVAL;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) ||
 	    !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) {
 		/* we disable mandatory BSSID association */
@@ -8447,14 +8452,14 @@
 		IPW_DEBUG_ASSOC("Attempting to associate with new "
 				"parameters.\n");
 		ipw_associate(priv);
-		up(&priv->sem);
+		mutex_unlock(&priv->mutex);
 		return 0;
 	}
 
 	priv->config |= CFG_STATIC_BSSID;
 	if (!memcmp(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN)) {
 		IPW_DEBUG_WX("BSSID set to current BSSID.\n");
-		up(&priv->sem);
+		mutex_unlock(&priv->mutex);
 		return 0;
 	}
 
@@ -8468,7 +8473,7 @@
 	if (!ipw_disassociate(priv))
 		ipw_associate(priv);
 
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return 0;
 }
 
@@ -8479,7 +8484,7 @@
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	/* If we are associated, trying to associate, or have a statically
 	 * configured BSSID then return that; otherwise return ANY */
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	if (priv->config & CFG_STATIC_BSSID ||
 	    priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
 		wrqu->ap_addr.sa_family = ARPHRD_ETHER;
@@ -8489,7 +8494,7 @@
 
 	IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n",
 		     MAC_ARG(wrqu->ap_addr.sa_data));
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return 0;
 }
 
@@ -8500,7 +8505,7 @@
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	char *essid = "";	/* ANY */
 	int length = 0;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	if (wrqu->essid.flags && wrqu->essid.length) {
 		length = wrqu->essid.length - 1;
 		essid = extra;
@@ -8515,7 +8520,7 @@
 			priv->config &= ~CFG_STATIC_ESSID;
 			ipw_associate(priv);
 		}
-		up(&priv->sem);
+		mutex_unlock(&priv->mutex);
 		return 0;
 	}
 
@@ -8525,7 +8530,7 @@
 
 	if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) {
 		IPW_DEBUG_WX("ESSID set to current ESSID.\n");
-		up(&priv->sem);
+		mutex_unlock(&priv->mutex);
 		return 0;
 	}
 
@@ -8540,7 +8545,7 @@
 	if (!ipw_disassociate(priv))
 		ipw_associate(priv);
 
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return 0;
 }
 
@@ -8552,7 +8557,7 @@
 
 	/* If we are associated, trying to associate, or have a statically
 	 * configured ESSID then return that; otherwise return ANY */
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	if (priv->config & CFG_STATIC_ESSID ||
 	    priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
 		IPW_DEBUG_WX("Getting essid: '%s'\n",
@@ -8565,7 +8570,7 @@
 		wrqu->essid.length = 0;
 		wrqu->essid.flags = 0;	/* active */
 	}
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return 0;
 }
 
@@ -8578,12 +8583,12 @@
 	IPW_DEBUG_WX("Setting nick to '%s'\n", extra);
 	if (wrqu->data.length > IW_ESSID_MAX_SIZE)
 		return -E2BIG;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
 	memset(priv->nick, 0, sizeof(priv->nick));
 	memcpy(priv->nick, extra, wrqu->data.length);
 	IPW_DEBUG_TRACE("<<\n");
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return 0;
 
 }
@@ -8594,11 +8599,11 @@
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	IPW_DEBUG_WX("Getting nick\n");
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	wrqu->data.length = strlen(priv->nick) + 1;
 	memcpy(extra, priv->nick, wrqu->data.length);
 	wrqu->data.flags = 1;	/* active */
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return 0;
 }
 
@@ -8691,7 +8696,7 @@
       apply:
 	IPW_DEBUG_WX("Setting rate mask to 0x%08X [%s]\n",
 		     mask, fixed ? "fixed" : "sub-rates");
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	if (mask == IEEE80211_DEFAULT_RATES_MASK) {
 		priv->config &= ~CFG_FIXED_RATE;
 		ipw_set_fixed_rate(priv, priv->ieee->mode);
@@ -8700,7 +8705,7 @@
 
 	if (priv->rates_mask == mask) {
 		IPW_DEBUG_WX("Mask set to current mask.\n");
-		up(&priv->sem);
+		mutex_unlock(&priv->mutex);
 		return 0;
 	}
 
@@ -8711,7 +8716,7 @@
 	if (!ipw_disassociate(priv))
 		ipw_associate(priv);
 
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return 0;
 }
 
@@ -8720,9 +8725,9 @@
 			   union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	wrqu->bitrate.value = priv->last_rate;
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value);
 	return 0;
 }
@@ -8732,20 +8737,20 @@
 			  union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	if (wrqu->rts.disabled)
 		priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
 	else {
 		if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
 		    wrqu->rts.value > MAX_RTS_THRESHOLD) {
-			up(&priv->sem);
+			mutex_unlock(&priv->mutex);
 			return -EINVAL;
 		}
 		priv->rts_threshold = wrqu->rts.value;
 	}
 
 	ipw_send_rts_threshold(priv, priv->rts_threshold);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	IPW_DEBUG_WX("SET RTS Threshold -> %d \n", priv->rts_threshold);
 	return 0;
 }
@@ -8755,11 +8760,11 @@
 			  union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	wrqu->rts.value = priv->rts_threshold;
 	wrqu->rts.fixed = 0;	/* no auto select */
 	wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	IPW_DEBUG_WX("GET RTS Threshold -> %d \n", wrqu->rts.value);
 	return 0;
 }
@@ -8771,7 +8776,7 @@
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	int err = 0;
 
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	if (ipw_radio_kill_sw(priv, wrqu->power.disabled)) {
 		err = -EINPROGRESS;
 		goto out;
@@ -8794,7 +8799,7 @@
 	priv->tx_power = wrqu->power.value;
 	err = ipw_set_tx_power(priv);
       out:
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return err;
 }
 
@@ -8803,12 +8808,12 @@
 			    union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	wrqu->power.value = priv->tx_power;
 	wrqu->power.fixed = 1;
 	wrqu->power.flags = IW_TXPOW_DBM;
 	wrqu->power.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 
 	IPW_DEBUG_WX("GET TX Power -> %s %d \n",
 		     wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value);
@@ -8821,13 +8826,13 @@
 			   union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	if (wrqu->frag.disabled)
 		priv->ieee->fts = DEFAULT_FTS;
 	else {
 		if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
 		    wrqu->frag.value > MAX_FRAG_THRESHOLD) {
-			up(&priv->sem);
+			mutex_unlock(&priv->mutex);
 			return -EINVAL;
 		}
 
@@ -8835,7 +8840,7 @@
 	}
 
 	ipw_send_frag_threshold(priv, wrqu->frag.value);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	IPW_DEBUG_WX("SET Frag Threshold -> %d \n", wrqu->frag.value);
 	return 0;
 }
@@ -8845,11 +8850,11 @@
 			   union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	wrqu->frag.value = priv->ieee->fts;
 	wrqu->frag.fixed = 0;	/* no auto select */
 	wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FTS);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value);
 
 	return 0;
@@ -8870,7 +8875,7 @@
 	if (wrqu->retry.value < 0 || wrqu->retry.value > 255)
 		return -EINVAL;
 
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	if (wrqu->retry.flags & IW_RETRY_MIN)
 		priv->short_retry_limit = (u8) wrqu->retry.value;
 	else if (wrqu->retry.flags & IW_RETRY_MAX)
@@ -8882,7 +8887,7 @@
 
 	ipw_send_retry_limit(priv, priv->short_retry_limit,
 			     priv->long_retry_limit);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	IPW_DEBUG_WX("SET retry limit -> short:%d long:%d\n",
 		     priv->short_retry_limit, priv->long_retry_limit);
 	return 0;
@@ -8894,11 +8899,11 @@
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	wrqu->retry.disabled = 0;
 
 	if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
-		up(&priv->sem);
+		mutex_unlock(&priv->mutex);
 		return -EINVAL;
 	}
 
@@ -8912,7 +8917,7 @@
 		wrqu->retry.flags = IW_RETRY_LIMIT;
 		wrqu->retry.value = priv->short_retry_limit;
 	}
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 
 	IPW_DEBUG_WX("GET retry -> %d \n", wrqu->retry.value);
 
@@ -8929,7 +8934,7 @@
 	    (priv->status & STATUS_EXIT_PENDING))
 		return 0;
 
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 
 	if (priv->status & STATUS_RF_KILL_MASK) {
 		IPW_DEBUG_HC("Aborting scan due to RF kill activation\n");
@@ -8981,7 +8986,7 @@
 	priv->status |= STATUS_SCANNING;
 
       done:
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return err;
 }
 
@@ -9024,7 +9029,7 @@
 	int ret;
 	u32 cap = priv->capability;
 
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	ret = ieee80211_wx_set_encode(priv->ieee, info, wrqu, key);
 
 	/* In IBSS mode, we need to notify the firmware to update
@@ -9034,7 +9039,7 @@
 	    priv->status & STATUS_ASSOCIATED)
 		ipw_disassociate(priv);
 
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return ret;
 }
 
@@ -9052,17 +9057,17 @@
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	int err;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	if (wrqu->power.disabled) {
 		priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
 		err = ipw_send_power_mode(priv, IPW_POWER_MODE_CAM);
 		if (err) {
 			IPW_DEBUG_WX("failed setting power mode.\n");
-			up(&priv->sem);
+			mutex_unlock(&priv->mutex);
 			return err;
 		}
 		IPW_DEBUG_WX("SET Power Management Mode -> off\n");
-		up(&priv->sem);
+		mutex_unlock(&priv->mutex);
 		return 0;
 	}
 
@@ -9074,7 +9079,7 @@
 	default:		/* Otherwise we don't support it */
 		IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
 			     wrqu->power.flags);
-		up(&priv->sem);
+		mutex_unlock(&priv->mutex);
 		return -EOPNOTSUPP;
 	}
 
@@ -9087,12 +9092,12 @@
 	err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
 	if (err) {
 		IPW_DEBUG_WX("failed setting power mode.\n");
-		up(&priv->sem);
+		mutex_unlock(&priv->mutex);
 		return err;
 	}
 
 	IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return 0;
 }
 
@@ -9101,13 +9106,13 @@
 			    union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	if (!(priv->power_mode & IPW_POWER_ENABLED))
 		wrqu->power.disabled = 1;
 	else
 		wrqu->power.disabled = 0;
 
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode);
 
 	return 0;
@@ -9120,7 +9125,7 @@
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	int mode = *(int *)extra;
 	int err;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	if ((mode < 1) || (mode > IPW_POWER_LIMIT)) {
 		mode = IPW_POWER_AC;
 		priv->power_mode = mode;
@@ -9133,11 +9138,11 @@
 
 		if (err) {
 			IPW_DEBUG_WX("failed setting power mode.\n");
-			up(&priv->sem);
+			mutex_unlock(&priv->mutex);
 			return err;
 		}
 	}
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return 0;
 }
 
@@ -9186,7 +9191,7 @@
 		IPW_WARNING("Attempt to set invalid wireless mode: %d\n", mode);
 		return -EINVAL;
 	}
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	if (priv->adapter == IPW_2915ABG) {
 		priv->ieee->abg_true = 1;
 		if (mode & IEEE_A) {
@@ -9198,7 +9203,7 @@
 		if (mode & IEEE_A) {
 			IPW_WARNING("Attempt to set 2200BG into "
 				    "802.11a mode\n");
-			up(&priv->sem);
+			mutex_unlock(&priv->mutex);
 			return -EINVAL;
 		}
 
@@ -9235,7 +9240,7 @@
 	IPW_DEBUG_WX("PRIV SET MODE: %c%c%c\n",
 		     mode & IEEE_A ? 'a' : '.',
 		     mode & IEEE_B ? 'b' : '.', mode & IEEE_G ? 'g' : '.');
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return 0;
 }
 
@@ -9244,7 +9249,7 @@
 				    union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	switch (priv->ieee->mode) {
 	case IEEE_A:
 		strncpy(extra, "802.11a (1)", MAX_WX_STRING);
@@ -9275,7 +9280,7 @@
 	IPW_DEBUG_WX("PRIV GET MODE: %s\n", extra);
 
 	wrqu->data.length = strlen(extra) + 1;
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 
 	return 0;
 }
@@ -9286,7 +9291,7 @@
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	int mode = *(int *)extra;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	/* Switching from SHORT -> LONG requires a disassociation */
 	if (mode == 1) {
 		if (!(priv->config & CFG_PREAMBLE_LONG)) {
@@ -9305,11 +9310,11 @@
 		priv->config &= ~CFG_PREAMBLE_LONG;
 		goto done;
 	}
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return -EINVAL;
 
       done:
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return 0;
 }
 
@@ -9318,12 +9323,12 @@
 			       union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	if (priv->config & CFG_PREAMBLE_LONG)
 		snprintf(wrqu->name, IFNAMSIZ, "long (1)");
 	else
 		snprintf(wrqu->name, IFNAMSIZ, "auto (0)");
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return 0;
 }
 
@@ -9335,7 +9340,7 @@
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	int *parms = (int *)extra;
 	int enable = (parms[0] > 0);
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]);
 	if (enable) {
 		if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
@@ -9350,13 +9355,13 @@
 		ipw_set_channel(priv, parms[1]);
 	} else {
 		if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
-			up(&priv->sem);
+			mutex_unlock(&priv->mutex);
 			return 0;
 		}
 		priv->net_dev->type = ARPHRD_ETHER;
 		queue_work(priv->workqueue, &priv->adapter_restart);
 	}
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return 0;
 }
 
@@ -9386,7 +9391,7 @@
 
 	IPW_DEBUG_WX("SW_RESET\n");
 
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 
 	ret = ipw_sw_reset(priv, 0);
 	if (!ret) {
@@ -9398,9 +9403,9 @@
 	 * module parameter, so take appropriate action */
 	ipw_radio_kill_sw(priv, priv->status & STATUS_RF_KILL_SW);
 
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	ieee80211_wx_set_encode(priv->ieee, info, &wrqu_sec, NULL);
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 
 	if (!(priv->status & STATUS_RF_KILL_MASK)) {
 		/* Configuration likely changed -- force [re]association */
@@ -9410,7 +9415,7 @@
 			ipw_associate(priv);
 	}
 
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 
 	return 0;
 }
@@ -9586,7 +9591,7 @@
 static  void init_sys_config(struct ipw_sys_config *sys_config)
 {
 	memset(sys_config, 0, sizeof(struct ipw_sys_config));
-	sys_config->bt_coexistence = 1;	/* We may need to look into prvStaBtConfig */
+	sys_config->bt_coexistence = 0;
 	sys_config->answer_broadcast_ssid_probe = 0;
 	sys_config->accept_all_data_frames = 0;
 	sys_config->accept_non_directed_frames = 1;
@@ -9607,11 +9612,11 @@
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	IPW_DEBUG_INFO("dev->open\n");
 	/* we should be verifying the device is ready to be opened */
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	if (!(priv->status & STATUS_RF_KILL_MASK) &&
 	    (priv->status & STATUS_ASSOCIATED))
 		netif_start_queue(dev);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return 0;
 }
 
@@ -9647,11 +9652,6 @@
 	u16 remaining_bytes;
 	int fc;
 
-	/* If there isn't room in the queue, we return busy and let the
-	 * network stack requeue the packet for us */
-	if (ipw_queue_space(q) < q->high_mark)
-		return NETDEV_TX_BUSY;
-
 	switch (priv->ieee->iw_mode) {
 	case IW_MODE_ADHOC:
 		hdr_len = IEEE80211_3ADDR_LEN;
@@ -9867,7 +9867,7 @@
 
       fail_unlock:
 	spin_unlock_irqrestore(&priv->lock, flags);
-	return 1;
+	return -1;
 }
 
 static struct net_device_stats *ipw_net_get_stats(struct net_device *dev)
@@ -9890,13 +9890,13 @@
 	struct sockaddr *addr = p;
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EADDRNOTAVAIL;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	priv->config |= CFG_CUSTOM_MAC;
 	memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
 	printk(KERN_INFO "%s: Setting MAC to " MAC_FMT "\n",
 	       priv->net_dev->name, MAC_ARG(priv->mac_addr));
 	queue_work(priv->workqueue, &priv->adapter_restart);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return 0;
 }
 
@@ -9940,9 +9940,9 @@
 
 	if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE)
 		return -EINVAL;
-	down(&p->sem);
+	mutex_lock(&p->mutex);
 	memcpy(bytes, &p->eeprom[eeprom->offset], eeprom->len);
-	up(&p->sem);
+	mutex_unlock(&p->mutex);
 	return 0;
 }
 
@@ -9954,12 +9954,12 @@
 
 	if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE)
 		return -EINVAL;
-	down(&p->sem);
+	mutex_lock(&p->mutex);
 	memcpy(&p->eeprom[eeprom->offset], bytes, eeprom->len);
 	for (i = IPW_EEPROM_DATA;
 	     i < IPW_EEPROM_DATA + IPW_EEPROM_IMAGE_SIZE; i++)
 		ipw_write8(p, i, p->eeprom[i]);
-	up(&p->sem);
+	mutex_unlock(&p->mutex);
 	return 0;
 }
 
@@ -10054,12 +10054,12 @@
 static void ipw_bg_rf_kill(void *data)
 {
 	struct ipw_priv *priv = data;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	ipw_rf_kill(data);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 }
 
-void ipw_link_up(struct ipw_priv *priv)
+static void ipw_link_up(struct ipw_priv *priv)
 {
 	priv->last_seq_num = -1;
 	priv->last_frag_num = -1;
@@ -10089,12 +10089,12 @@
 static void ipw_bg_link_up(void *data)
 {
 	struct ipw_priv *priv = data;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	ipw_link_up(data);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 }
 
-void ipw_link_down(struct ipw_priv *priv)
+static void ipw_link_down(struct ipw_priv *priv)
 {
 	ipw_led_link_down(priv);
 	netif_carrier_off(priv->net_dev);
@@ -10117,9 +10117,9 @@
 static void ipw_bg_link_down(void *data)
 {
 	struct ipw_priv *priv = data;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	ipw_link_down(data);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 }
 
 static int ipw_setup_deferred_work(struct ipw_priv *priv)
@@ -10292,6 +10292,20 @@
 
 	/* set basic system config settings */
 	init_sys_config(&priv->sys_config);
+
+	/* Support Bluetooth if we have BT h/w on board, and user wants to.
+	 * Does not support BT priority yet (don't abort or defer our Tx) */
+	if (bt_coexist) {
+		unsigned char bt_caps = priv->eeprom[EEPROM_SKU_CAPABILITY];
+
+		if (bt_caps & EEPROM_SKU_CAP_BT_CHANNEL_SIG)
+			priv->sys_config.bt_coexistence
+			    |= CFG_BT_COEXISTENCE_SIGNAL_CHNL;
+		if (bt_caps & EEPROM_SKU_CAP_BT_OOB)
+			priv->sys_config.bt_coexistence
+			    |= CFG_BT_COEXISTENCE_OOB;
+	}
+
 	if (priv->ieee->iw_mode == IW_MODE_ADHOC)
 		priv->sys_config.answer_broadcast_ssid_probe = 1;
 	else
@@ -10782,9 +10796,9 @@
 static void ipw_bg_up(void *data)
 {
 	struct ipw_priv *priv = data;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	ipw_up(data);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 }
 
 static void ipw_deinit(struct ipw_priv *priv)
@@ -10853,23 +10867,23 @@
 static void ipw_bg_down(void *data)
 {
 	struct ipw_priv *priv = data;
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 	ipw_down(data);
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 }
 
 /* Called by register_netdev() */
 static int ipw_net_init(struct net_device *dev)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 
 	if (ipw_up(priv)) {
-		up(&priv->sem);
+		mutex_unlock(&priv->mutex);
 		return -EIO;
 	}
 
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	return 0;
 }
 
@@ -10959,7 +10973,7 @@
 	for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++)
 		INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
 
-	init_MUTEX(&priv->sem);
+	mutex_init(&priv->mutex);
 	if (pci_enable_device(pdev)) {
 		err = -ENODEV;
 		goto out_free_ieee80211;
@@ -11017,7 +11031,7 @@
 	SET_MODULE_OWNER(net_dev);
 	SET_NETDEV_DEV(net_dev, &pdev->dev);
 
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 
 	priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit;
 	priv->ieee->set_security = shim__set_security;
@@ -11050,11 +11064,11 @@
 	err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group);
 	if (err) {
 		IPW_ERROR("failed to create sysfs device attributes\n");
-		up(&priv->sem);
+		mutex_unlock(&priv->mutex);
 		goto out_release_irq;
 	}
 
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 	err = register_netdev(net_dev);
 	if (err) {
 		IPW_ERROR("failed to register network device\n");
@@ -11091,13 +11105,13 @@
 	if (!priv)
 		return;
 
-	down(&priv->sem);
+	mutex_lock(&priv->mutex);
 
 	priv->status |= STATUS_EXIT_PENDING;
 	ipw_down(priv);
 	sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);
 
-	up(&priv->sem);
+	mutex_unlock(&priv->mutex);
 
 	unregister_netdev(priv->net_dev);
 
@@ -11281,12 +11295,18 @@
 MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)");
 #endif
 
+module_param(bt_coexist, int, 0444);
+MODULE_PARM_DESC(bt_coexist, "enable bluetooth coexistence (default off)");
+
 module_param(hwcrypto, int, 0444);
-MODULE_PARM_DESC(hwcrypto, "enable hardware crypto (default on)");
+MODULE_PARM_DESC(hwcrypto, "enable hardware crypto (default off)");
 
 module_param(cmdlog, int, 0444);
 MODULE_PARM_DESC(cmdlog,
 		 "allocate a ring buffer for logging firmware commands");
 
+module_param(roaming, int, 0444);
+MODULE_PARM_DESC(roaming, "enable roaming support (default on)");
+
 module_exit(ipw_exit);
 module_init(ipw_init);
diff -urN oldtree/drivers/net/wireless/ipw2200.h newtree/drivers/net/wireless/ipw2200.h
--- oldtree/drivers/net/wireless/ipw2200.h	2006-02-19 11:41:03.436820624 +0000
+++ newtree/drivers/net/wireless/ipw2200.h	2006-02-21 15:58:15.596775488 +0000
@@ -33,6 +33,7 @@
 #include <linux/moduleparam.h>
 #include <linux/config.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
 
 #include <linux/pci.h>
 #include <linux/netdevice.h>
@@ -46,6 +47,7 @@
 #include <linux/firmware.h>
 #include <linux/wireless.h>
 #include <linux/dma-mapping.h>
+#include <linux/jiffies.h>
 #include <asm/io.h>
 
 #include <net/ieee80211.h>
@@ -852,7 +854,7 @@
 	u16 dwell_time[IPW_SCAN_TYPES];
 } __attribute__ ((packed));
 
-extern inline u8 ipw_get_scan_type(struct ipw_scan_request_ext *scan, u8 index)
+static inline u8 ipw_get_scan_type(struct ipw_scan_request_ext *scan, u8 index)
 {
 	if (index % 2)
 		return scan->scan_type[index / 2] & 0x0F;
@@ -860,7 +862,7 @@
 		return (scan->scan_type[index / 2] & 0xF0) >> 4;
 }
 
-extern inline void ipw_set_scan_type(struct ipw_scan_request_ext *scan,
+static inline void ipw_set_scan_type(struct ipw_scan_request_ext *scan,
 				     u8 index, u8 scan_type)
 {
 	if (index % 2)
@@ -1120,7 +1122,7 @@
 	struct ieee80211_device *ieee;
 
 	spinlock_t lock;
-	struct semaphore sem;
+	struct mutex mutex;
 
 	/* basic pci-network driver stuff */
 	struct pci_dev *pci_dev;
@@ -1406,13 +1408,6 @@
 * Register bit definitions
 */
 
-/* Dino control registers bits */
-
-#define DINO_ENABLE_SYSTEM 0x80
-#define DINO_ENABLE_CS     0x40
-#define DINO_RXFIFO_DATA   0x01
-#define DINO_CONTROL_REG   0x00200000
-
 #define IPW_INTA_RW       0x00000008
 #define IPW_INTA_MASK_R   0x0000000C
 #define IPW_INDIRECT_ADDR 0x00000010
@@ -1459,6 +1454,11 @@
 #define IPW_DOMAIN_0_END 0x1000
 #define CLX_MEM_BAR_SIZE 0x1000
 
+/* Dino/baseband control registers bits */
+
+#define DINO_ENABLE_SYSTEM 0x80	/* 1 = baseband processor on, 0 = reset */
+#define DINO_ENABLE_CS     0x40	/* 1 = enable ucode load */
+#define DINO_RXFIFO_DATA   0x01	/* 1 = data available */
 #define IPW_BASEBAND_CONTROL_STATUS	0X00200000
 #define IPW_BASEBAND_TX_FIFO_WRITE	0X00200004
 #define IPW_BASEBAND_RX_FIFO_READ	0X00200004
@@ -1567,13 +1567,18 @@
 #define EEPROM_BSS_CHANNELS_BG  (GET_EEPROM_ADDR(0x2c,LSB))	/* 2 bytes  */
 #define EEPROM_HW_VERSION       (GET_EEPROM_ADDR(0x72,LSB))	/* 2 bytes  */
 
-/* NIC type as found in the one byte EEPROM_NIC_TYPE  offset*/
+/* NIC type as found in the one byte EEPROM_NIC_TYPE offset */
 #define EEPROM_NIC_TYPE_0 0
 #define EEPROM_NIC_TYPE_1 1
 #define EEPROM_NIC_TYPE_2 2
 #define EEPROM_NIC_TYPE_3 3
 #define EEPROM_NIC_TYPE_4 4
 
+/* Bluetooth Coexistence capabilities as found in EEPROM_SKU_CAPABILITY */
+#define EEPROM_SKU_CAP_BT_CHANNEL_SIG  0x01	/* we can tell BT our channel # */
+#define EEPROM_SKU_CAP_BT_PRIORITY     0x02	/* BT can take priority over us */
+#define EEPROM_SKU_CAP_BT_OOB          0x04	/* we can signal BT out-of-band */
+
 #define FW_MEM_REG_LOWER_BOUND          0x00300000
 #define FW_MEM_REG_EEPROM_ACCESS        (FW_MEM_REG_LOWER_BOUND + 0x40)
 #define IPW_EVENT_REG                   (FW_MEM_REG_LOWER_BOUND + 0x04)
@@ -1658,9 +1663,10 @@
 	IPW_FW_ERROR_FATAL_ERROR
 };
 
-#define AUTH_OPEN       0
-#define AUTH_SHARED_KEY 1
-#define AUTH_IGNORE     3
+#define AUTH_OPEN	0
+#define AUTH_SHARED_KEY	1
+#define AUTH_LEAP	2
+#define AUTH_IGNORE	3
 
 #define HC_ASSOCIATE      0
 #define HC_REASSOCIATE    1
@@ -1860,7 +1866,7 @@
 	u8 cmd;
 	u8 len;
 	u16 reserved;
-	u32 param[TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH];
+	u32 *param;
 } __attribute__ ((packed));
 
 struct ipw_cmd_log {
@@ -1869,21 +1875,23 @@
 	struct host_cmd cmd;
 };
 
-#define CFG_BT_COEXISTENCE_MIN                  0x00
-#define CFG_BT_COEXISTENCE_DEFER                0x02
-#define CFG_BT_COEXISTENCE_KILL                 0x04
-#define CFG_BT_COEXISTENCE_WME_OVER_BT          0x08
-#define CFG_BT_COEXISTENCE_OOB                  0x10
-#define CFG_BT_COEXISTENCE_MAX                  0xFF
-#define CFG_BT_COEXISTENCE_DEF                  0x80	/* read Bt from EEPROM */
-
-#define CFG_CTS_TO_ITSELF_ENABLED_MIN	0x0
-#define CFG_CTS_TO_ITSELF_ENABLED_MAX	0x1
+/* SysConfig command parameters ... */
+/* bt_coexistence param */
+#define CFG_BT_COEXISTENCE_SIGNAL_CHNL  0x01	/* tell BT our chnl # */
+#define CFG_BT_COEXISTENCE_DEFER        0x02	/* defer our Tx if BT traffic */
+#define CFG_BT_COEXISTENCE_KILL         0x04	/* kill our Tx if BT traffic */
+#define CFG_BT_COEXISTENCE_WME_OVER_BT  0x08	/* multimedia extensions */
+#define CFG_BT_COEXISTENCE_OOB          0x10	/* signal BT via out-of-band */
+
+/* clear-to-send to self param */
+#define CFG_CTS_TO_ITSELF_ENABLED_MIN	0x00
+#define CFG_CTS_TO_ITSELF_ENABLED_MAX	0x01
 #define CFG_CTS_TO_ITSELF_ENABLED_DEF	CFG_CTS_TO_ITSELF_ENABLED_MIN
 
-#define CFG_SYS_ANTENNA_BOTH                      0x000
-#define CFG_SYS_ANTENNA_A                         0x001
-#define CFG_SYS_ANTENNA_B                         0x003
+/* Antenna diversity param (h/w can select best antenna, based on signal) */
+#define CFG_SYS_ANTENNA_BOTH            0x00	/* NIC selects best antenna */
+#define CFG_SYS_ANTENNA_A               0x01	/* force antenna A */
+#define CFG_SYS_ANTENNA_B               0x03	/* force antenna B */
 
 /*
  * The definitions below were lifted off the ipw2100 driver, which only
diff -urN oldtree/drivers/net/wireless/netwave_cs.c newtree/drivers/net/wireless/netwave_cs.c
--- oldtree/drivers/net/wireless/netwave_cs.c	2006-02-19 11:41:03.437820472 +0000
+++ newtree/drivers/net/wireless/netwave_cs.c	2006-02-21 15:58:15.615772600 +0000
@@ -55,10 +55,8 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/bitops.h>
-#ifdef CONFIG_NET_RADIO
 #include <linux/wireless.h>
 #include <net/iw_handler.h>
-#endif
 
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
diff -urN oldtree/drivers/net/wireless/strip.c newtree/drivers/net/wireless/strip.c
--- oldtree/drivers/net/wireless/strip.c	2006-02-19 11:41:03.445819256 +0000
+++ newtree/drivers/net/wireless/strip.c	2006-02-21 15:58:15.624771232 +0000
@@ -112,7 +112,7 @@
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/time.h>
-
+#include <linux/jiffies.h>
 
 /************************************************************************/
 /* Useful structures and definitions					*/
@@ -1569,7 +1569,7 @@
 	del_timer(&strip_info->idle_timer);
 
 
-	if (jiffies - strip_info->pps_timer > HZ) {
+	if (time_after(jiffies, strip_info->pps_timer + HZ)) {
 		unsigned long t = jiffies - strip_info->pps_timer;
 		unsigned long rx_pps_count = (strip_info->rx_pps_count * HZ * 8 + t / 2) / t;
 		unsigned long tx_pps_count = (strip_info->tx_pps_count * HZ * 8 + t / 2) / t;
diff -urN oldtree/drivers/net/wireless/tiacx/Changelog newtree/drivers/net/wireless/tiacx/Changelog
--- oldtree/drivers/net/wireless/tiacx/Changelog	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/net/wireless/tiacx/Changelog	2006-02-21 15:58:22.562716504 +0000
@@ -0,0 +1,502 @@
+TODO:
+e100.c: pci_dma_sync_single_for_cpu(nic->pdev, rx->dma_addr, sizeof(struct rfd), PCI_DMA_FROMDEVICE);
+do we need to do something like above for rxhostdescs/rxbufs?
+
+TODO: from Efthym <efthym@gmx.net>:
+13:12:42 wlan0: rx: 31 DUPs in 551 packets received in 10 sec
+13:12:48 wlan0: tx error 0x20, buf 20! (excessive Tx retries
+13:12:48 wlan0: tx error 0x20, buf 21! (excessive Tx retries
+13:12:48 wlan0: several excessive Tx retry errors occurred, a
+13:12:48 wlan0: tx error 0x20, buf 22! (excessive Tx retries
+13:12:48 wlan0: tx error 0x20, buf 23! (excessive Tx retries
+13:12:48 wlan0: tx error 0x20, buf 24! (excessive Tx retries
+13:12:48 wlan0: recalibrating radio
+13:12:48 wlan0: successfully recalibrated radio
+13:12:52 wlan0: tx error 0x20, buf 25! (excessive Tx retries
+13:12:52 wlan0: several excessive Tx retry errors occurred, a
+13:12:52 wlan0: tx error 0x20, buf 26! (excessive Tx retries
+13:12:52 wlan0: tx error 0x20, buf 27! (excessive Tx retries
+13:12:52 wlan0: tx error 0x20, buf 28! (excessive Tx retries
+13:12:52 wlan0: tx error 0x20, buf 29! (excessive Tx retries
+13:12:52 wlan0: several excessive Tx retry errors occurred, a
+13:12:52 wlan0: tx error 0x20, buf 30! (excessive Tx retries
+13:12:52 wlan0: tx error 0x20, buf 31! (excessive Tx retries
+13:12:52 wlan0: tx error 0x20, buf 00! (excessive Tx retries
+13:12:52 wlan0: less than 5 minutes since last radio recalibr
+13:12:58 wlan0: tx error 0x20, buf 01! (excessive Tx retries
+13:12:58 wlan0: several excessive Tx retry errors occurred, a
+13:12:58 wlan0: tx error 0x20, buf 02! (excessive Tx retries
+13:12:58 wlan0: tx error 0x20, buf 03! (excessive Tx retries
+13:12:58 wlan0: tx error 0x20, buf 04! (excessive Tx retries
+13:12:58 wlan0: tx error 0x20, buf 05! (excessive Tx retries
+13:12:58 wlan0: several excessive Tx retry errors occurred, a
+13:12:58 disabling above notification message
+13:12:58 wlan0: tx error 0x20, buf 06! (excessive Tx retries
+13:12:58 wlan0: tx error 0x20, buf 07!
+13:12:58 wlan0: tx error 0x20, buf 08!
+13:12:58 wlan0: less than 5 minutes since last radio recalibr
+13:13:06 wlan0: tx error 0x20, buf 09!
+13:13:06 wlan0: tx error 0x20, buf 10!
+13:13:06 wlan0: tx error 0x20, buf 11!
+13:13:06 wlan0: tx error 0x20, buf 12!
+13:13:06 wlan0: tx error 0x20, buf 13!
+13:13:06 wlan0: tx error 0x20, buf 14!
+13:13:06 wlan0: tx error 0x20, buf 15!
+13:13:06 wlan0: tx error 0x20, buf 16!
+13:13:06 wlan0: less than 5 minutes since last radio recalibr
+13:13:18 wlan0: tx error 0x20, buf 17!
+13:13:18 wlan0: tx error 0x20, buf 18!
+13:13:18 wlan0: tx error 0x20, buf 19!
+13:13:18 wlan0: tx error 0x20, buf 20!
+13:13:18 wlan0: tx error 0x20, buf 21!
+13:13:18 wlan0: tx error 0x20, buf 22!
+13:13:18 wlan0: tx error 0x20, buf 23!
+13:13:18 wlan0: tx error 0x20, buf 24!
+13:13:18 wlan0: less than 5 minutes since last radio recalibr
+13:13:25 wlan0: tx error 0x20, buf 25!
+13:13:25 wlan0: tx error 0x20, buf 26!
+13:13:25 wlan0: tx error 0x20, buf 27!
+13:13:25 wlan0: tx error 0x20, buf 28!
+13:13:25 wlan0: tx error 0x20, buf 29!
+13:13:25 wlan0: tx error 0x20, buf 30!
+13:13:25 wlan0: tx error 0x20, buf 31!
+13:13:25 wlan0: tx error 0x20, buf 00!
+13:13:25 wlan0: less than 5 minutes since last radio recalibr
+13:13:25 disabling above message
+13:13:32 wlan0: tx error 0x20, buf 01!
+13:13:32 wlan0: tx error 0x20, buf 02!
+13:13:32 wlan0: tx error 0x20, buf 03!
+13:13:32 wlan0: tx error 0x20, buf 04!
+13:13:32 wlan0: tx error 0x20, buf 05!
+13:13:32 wlan0: tx error 0x20, buf 06!
+13:13:32 wlan0: tx error 0x20, buf 07!
+13:13:32 wlan0: tx error 0x20, buf 08!
+13:13:41 wlan0: tx error 0x20, buf 09!
+13:13:41 wlan0: tx error 0x20, buf 10!
+13:13:41 wlan0: tx error 0x20, buf 11!
+13:13:41 wlan0: tx error 0x20, buf 12!
+13:13:41 wlan0: tx error 0x20, buf 13!
+13:13:41 wlan0: tx error 0x20, buf 14!
+13:13:41 wlan0: tx error 0x20, buf 15!
+13:13:41 wlan0: tx error 0x20, buf 16!
+13:13:51 wlan0: tx error 0x20, buf 17!
+13:13:51 wlan0: tx error 0x20, buf 18!
+13:13:51 wlan0: tx error 0x20, buf 19!
+13:13:51 wlan0: tx error 0x20, buf 20!
+13:13:51 wlan0: tx error 0x20, buf 21!
+13:13:51 wlan0: tx error 0x20, buf 22!
+13:13:51 wlan0: tx error 0x20, buf 23!
+13:13:51 wlan0: tx error 0x20, buf 24!
+13:14:02 wlan0: tx error 0x20, buf 25!
+13:14:02 wlan0: tx error 0x20, buf 26!
+13:14:02 wlan0: tx error 0x20, buf 27!
+13:14:02 wlan0: tx error 0x20, buf 28!
+13:14:02 wlan0: tx error 0x20, buf 29!
+13:14:02 wlan0: tx error 0x20, buf 30!
+13:14:02 wlan0: tx error 0x20, buf 31!
+13:14:02 wlan0: tx error 0x20, buf 00!
+13:14:13 wlan0: tx error 0x20, buf 01!
+13:14:13 wlan0: tx error 0x20, buf 02!
+13:14:13 wlan0: tx error 0x20, buf 03!
+13:14:13 wlan0: tx error 0x20, buf 04!
+13:14:13 wlan0: tx error 0x20, buf 05!
+13:14:13 wlan0: tx error 0x20, buf 06!
+13:14:13 wlan0: tx error 0x20, buf 07!
+13:14:13 wlan0: tx error 0x20, buf 08!
+
+[20060126] 0.3.31
+* fix bug uncovered by code added in support for firmware 2.3.1.31
+
+[20060124] 0.3.30
+* fix breakage introduced by vda
+* Bas Vermeulen <bvermeul@blackstar.xs4all.nl>:
+  support for firmware 2.3.1.31
+
+[20060117] 0.3.29
+* Andreas Mohr <andim2@users.sourceforge.net>:
+  - fix OOPS in acx_l_rxmonitor() (wrong ndev->type setting leading to memcpy
+    of negative size) by reworking monitor mode type setup and adding
+    missing sanity checks
+  - rename acx1XX_ie_powermgmt_t to more correct acx1XX_ie_powersave_t
+  - fix format string compile warnings
+  - add <linux/compiler.h> include apparently required for __iomem define
+    around Linux 2.6.8
+  - rework eCPU init by replacing static msleep with faster, more intelligent
+    (hopefully) busy-wait
+* acx_s_set_defaults slightly edited
+* ioctls are changed to have correct prototypes
+
+[20060116] 0.3.28
+* Massive global replaces: priv->adev, netdev_priv->ndev2adev etc.
+  Minimal code changes
+
+[20060113]
+* Andreas Mohr <andim2@users.sourceforge.net>:
+  - add recommended cpu_relax() to busy-wait loops
+  - reorder struct wlandevice_t for better(??) cache use
+  - kill superfluous result variable in conv.c
+  - misc. small cleanup
+* SEPARATE_DRIVER_INSTANCES is a 2.4ism, removed
+
+[20060112] 0.3.27
+* Andreas Mohr <andim2@users.sourceforge.net>:
+  - add support for configopt parsing for ACX100 EEPROM version v5
+  - only start another radio recalibration interval every 5 seconds
+    on ACX111 instead of every second
+
+[20060111]
+* drop compatibility cruft for kernels < 2.6.10
+
+[20060109] 0.3.26
+* From Andreas Mohr <andi@rhlx01.fht-esslingen.de>
+  - revert kzalloc change (too early, only Linux 2.6.14+ has support)
+  - add safe limit checks for probe_delay EEPROM values, log more
+    configopt values
+  - some early parts for packet fragmentation support
+    (I already know how to do it, I think, I just need some time
+    to implement it, and I *really* need this feature here with such
+    a BROKEN 3-wall connection here...)
+  - 802.11 power save mode improvements (not usable by mere mortals yet)
+  - switch fw cmd length structs depending on whether acx100 or acx111
+  - fix log message rate limiting (as a benefit code is now faster, too)
+  - unify acx100/acx111 scanning, saving a couple hundred bytes
+  - set Ctl2_8 to 0 which it most likely should be (please report if
+    this breaks anything - but it shouldn't since it's being initialized
+    to 0 on driver init anyway...)
+
+[20060108] 0.3.25
+* fix scanning breakage
+* fix cmd timeout breakage
+* attempt to fix suspend/resume
+
+[20060104] 0.3.24
+* From Andreas Mohr <andim2@users.sourceforge.net>
+  - activated acx100 configoption readout, unified acx100/acx111 parsing
+  - init NULL data template, required for 802.11 power save mode
+  - return actual, valid txpower levels in range ioctl (from configoption!)
+  fix bugs:
+  - fatal bug in 802.11 powersave structs
+  - some missing endianness conversions
+  - check for sane regulatory domain related settings on both SETting and GETting
+  - random optimizations making this much enhanced code *smaller* than the
+    previous version!
+  - optimized struct layout
+  - merge acx100_s_init_packet_templates and acx111_s_init_packet_templates
+  - use kzalloc instead of kmalloc where useful (yes, this driver is Linux 2.6.x
+    only, with x rather large)
+  - avoid some sprintf() and strlen()
+  - add support for new get_wireless_stats handling (...silence deprecation
+    warning!)
+  - add some unlikely()
+  - lower msleep() value in issue_cmd() in order to speed up card initialization
+    time (almost less than 1 second now, on P3/700!). should this lower msleep()
+    value be made init-only??
+  - disable get sensitivity ioctl for USB (unfortunately not working yet)
+  - make sure to call synchronize_irq(), (semi-)required for SMP
+  - group together some closely related functions
+  - misc cleanups/code maintenance
+  So, configoptions are now working for acx100, too, and unified, and
+  802.11 power save mode actually worked for acx100 when I tested it (large
+  delays during ping which indicate that it must be active, but I guess these
+  delays should be much reduced with a properly tuned implementation), but it's
+  not finished and thus not enabled by default.
+
+[20051228]
+* Global s/acxlog/log/
+
+[20051220] 0.3.23
+* timeout handling fixed for high load case
+  (patch by Andreas Mohr)
+
+[20051219] 0.3.22
+* acx100 active scanning must be working now, thanks to Carlos Martin
+  <carlos@cmartin.tk>.
+
+[20051202]
+* acx_s_update_card_settings cosmetic change
+  (but wasn't run tested)
+
+[20051201] 0.3.21
+* Thanks Carlos Martin
+* Completely serialize USB rx. Tiny speed loss,
+  but even more safe wrt reordering.
+* A few msleeps removed
+
+[20051128] 0.3.20
+* we will use only 2 rx usb buffers now. No apparent speed loss,
+  eliminates usb packet reordering risk.
+* two USB fixes for real bugs and one fix for possible leak
+  of an urb on error path. Thanks Carlos Martin <carlosmn@gmail.com>.
+
+[20051116] 0.3.19
+* a few small fixes accumulated over time, nothing spectacular
+
+[20051031] 0.3.18
+* hopefully a final touch on USB tx autorate
+
+[20051022] 0.3.17
+* PCI command submission made simpler
+
+[20051021] 0.3.16
+* Small changes mostly designed to break USB ;)
+* Auto rate handling for USB is still not confirmed to work.
+  I need USB logs from the users.
+
+[20051020] 0.3.15
+* Auto rate handling for USB is implemented. Untested.
+
+[20051019]
+* first step in proper auto rate handling for USB
+
+[20051018] 0.3.14
+* update for 2.6.14-rc4-mm1
+* Kconfig bug (error if ACX=y, ACX_USB=y, USB=m) fixed
+* PARANOID_LOCKING off by default
+
+[20051016] 0.3.13
+* Revert 20051013 fix, we have one which actually works.
+  Thanks Jacek Jablonski <yacek87@gmail.com> for testing!
+
+[20051013]
+* trying to fix "yet another similar bug"
+* usb fix by Carlos Martin
+
+[20051012] 0.3.12
+* acx_l_clean_tx_desc bug fixed - was stopping tx completely
+  at high load. (It seems there exists yet another similar bug!)
+* "unknown IE" dump was 2 bytes too short - fixed
+* DUP logging made less noisy
+* another usb fix by Carlos Martin <carlosmn@gmail.com>
+
+[20051003]
+* several usb fixes by Carlos Martin <carlosmn@gmail.com> - thanks!
+* unknown IE logging made less noisy
+* few unknown IEs added to the growing collection
+* version bump to 0.3.11
+
+[20050916]
+* fix bogus MTU handling, add ability to change MTU
+* fix WLAN_DATA_MAXLEN: 2312 -> 2304
+* version bump to 0.3.10
+
+[20050915]
+* by popular request default mode is 'managed'
+* empty handler for EID 7 (country info) is added
+* fix 'timer not started - iface is not up'
+* tx[host]desc micro optimizations
+* version bump to 0.3.9
+
+[20050914]
+* tx[host]desc ring workings brought a bit back to two-hostdesc
+  scheme. This is an attempt to fix weird WG311v2 bug.
+  I still fail to understand how same chip with same fw can
+  work for me but do not work for a WG311v2 owner. Mystery.
+* README updated
+* version bump to 0.3.8
+
+[20050913]
+* variable and fields with awful names renamed
+* a few fields dropped (they had constant values)
+* small optimization to acx_l_clean_tx_desc()
+* version bump to 0.3.7
+
+[20050912]
+* stop using 16 byte "private area" in txdesc - fw bug makes it unreliable
+* better logging of DUPs
+* version bump to 0.3.6
+
+[20050911]
+* use alloc_netdev/free_netdev/netdev_priv
+* acx_inline.h incorporated into pci.c
+* helper.c + helper2.c = common.c
+* marking static functions
+* enable IE_DOT11_CURRENT_ANTENNA for acx111
+* version bump to 0.3.5
+
+[20050910]
+* minor fixes, 2.6.13-mm2 integration
+
+[20050905]
+* TIWLAN_DC is dead, ui32ACX[TR]xQueueStart is dead
+* massive mucking with PCI and USB resulting in:
+  acx_pci.o + acx_usb.o = acx.o  ;)
+  Why? Here's why:
+    text    data     bss     dec     hex filename
+  116199     452      40  116691   1c7d3 acx.o
+  103435     244      20  103699   19513 acx_pci.o
+   81732     196      32   81960   14028 acx_usb.o
+* helper.c is PCI/USB independent now. It was the last one.
+* both modular and non-modular builds, PCI, USB, PCI+USB,
+  seem to compile successfully!
+* version bump to 0.3.4
+
+[20050904]
+* acx_stop_queue() locking reviewed and mostly fixed
+* 2.4isms in USB code are officially dead
+* added debug stuff for discovering interrogate/configure IEs
+* version bump to 0.3.3
+
+[20050903]
+* locking bug on error path fixed
+* issue_cmd() logging made more sane
+* issue_cmd() callers may abstain from printing issue_cmd() errors:
+  issue_cmd() itself gives enough info
+* version bump to 0.3.2
+
+[20050902]
+* kill bogus configure() call in acx100_s_create_dma_regions()
+
+[20050901]
+* acx100_s_create_dma_regions: hopefully fixed for USB
+  (problem found with help of Carlos Martin <carlosmn@gmail.com> - thanks!)
+* a load of cleanups:
+* acx_s_create_tx_desc_queue -> acx_create_tx_desc_queue
+  (it doesn't sleep)
+* struct acxp80211_nullframe -> acx_template_nullframe
+* xXBUFFERCOUNT_ACXnn -> xXBUFCNT_ACXnn
+* xXBUFFERCOUNT_USB -> USB_xXBUFCNT: these are _unrelated_ to xXBUFCNT_ACXnn,
+  should have visibly different names
+* TODOs added (we have a few really Pascalish/Windowish names,
+  and some misleading ones)
+* version bump to 0.3.1
+
+[20050830]
+* finally kill warning about acx_s_activate_power_save_mode()
+* struct acx100_ie_memconfigoption: convert pRxHostDesc to acx_ptr type
+* massive move of device-independent code from helper.c to helper2.c
+
+[20050829]
+* dummy handler for NONERP EID (47) added
+
+[20050823]
+* driver submitted for kernel inclusion
+* #defines renamed: CONFIG_ACX_{PCI,USB} -> ACX_{PCI,USB}
+  (needed for correct compilation of two modules from the same source)
+* version bump to 0.3.0
+* sizes:
+   text    data     bss     dec     hex filename
+  78242     264       8   78514   132b2 drivers/net/wireless/acx/acx_pci.o
+  60622     208      20   60850    edb2 drivers/net/wireless/acx/acx_usb.o
+
+[20050822]
+* idma.c is incorporated into helper.c
+* lots of cosmetic work: comments, struct member shuffling,
+  etc. TIWLAN_DC and other PCI data structs are #ifdef'ed
+  to be PCI-only. A few todos added. Extra #include's removed.
+* added sem locking debug printout code (for amd64 debug)
+* beacon tx rate and beacon ratevector is updated according to
+  "iwconfig rate" command immediately (required mode change before).
+
+[20050821]
+* Switch to wrapper functions for dealing with "tx buffers"
+  (memory areas where we create packets for tx. For USB, it's just
+  a part of wlandevice_t, for PCI it's a DMAable buffer pointed to
+  by txhostdesc).
+* Completely hide nature of PCI txdescs under opaque pointer type tx_t*
+* acx_l_ether_to_txdesc -> acx_l_ether_to_txbuf, not using knowledge
+  of PCI txdesc anymore.
+* Massive surgery on usb.c, cutting all paths into PCI code.
+* PCI code moved to pci.c - USB don't need these pieces anymore
+* acx111 and acx100 txhostdesc creation unified into single function
+
+[20050816]
+* PCI code switched to single-txdesc scheme
+* version bump to 0.2.5
+
+[20050815]
+* dev_kfree_skb -> dev_kfree_skb_any
+
+[20050814]
+* Auto rate was reset to lowest rate by scanning code
+  (AP beacons did it every tenth of a second!). Fixed.
+* USB rx no longer uses PCI-style rx descriptor ring.
+  tx ring elimination needs 'single-descriptor' setup
+  to be developed for acx100 (patch exists for acx111).
+* Very strange sem locking problems are reported on amd64.
+  Code which misbehaves looks fine. I do not know what's going on.
+  Workaround: turn off preemption.
+
+[20050812]
+* acx100 was failing to find out radio module #,
+  and wanted to load radio module 00. Must be fixed now.
+* USB: more simplifications
+
+[20050810]
+* USB: simplified command submission code, removed some
+  wlandevice_t fields (now unused)
+
+[20050808]
+* USB changes: nuked global statics, simplified issue_cmd,
+  shortened wlandevice_t. Added some TODOs :)
+
+[20050807]
+* restart scan if AP is not found
+* remove use_eth_name parameter. It was deprecated
+* disable legacy firmware loader for 2.6. Driver printed a warning
+  about need to switch to hotplug.
+* WARNING: new names for firmware images!
+  Driver will try to load the following images:
+  PCI driver:
+    'tiacxNNNcMM' (NNN=100/111, MM=radio module ID (in uppercase hex)):
+    combined firmware for specified chipset and radio.
+    failing that, it will try to load images named
+    'tiacxNNN' (NNN=100/111): main firmware for specified chipset
+    and 'tiacxNNNrMM': corresponding radio module.
+    For example, my firmware is in file named 'tiacx111c16'.
+    Alternatively, I may remove it and use pair of files
+    'tiacx111' and 'tiacx111r16' instead.
+  USB driver: loads image named 'tiacx100usb'
+  Hint: you can keep both old and new image names (via symlinks
+  or just by copying files) if you need to run older driver.
+* fix "Debug: sleeping function called from invalid context..." for USB
+* ACX_{PCI,USB} -> CONFIG_ACX_{PCI,USB} in preparation to 2.6 merge
+* version bump to 0.2.4
+
+[20050804]
+* 'Fixed' deadlock on flush_scheduled_work (need a better fix eventually)
+* We didn't completely disable IRQs on ifdown -> "Disabling IRQ#NN"
+  on second modprobe. Fixed.
+
+[20050802]
+* removed some // comments in order to please Andreas
+* moved a field to PCI-only part of wlandevice_t
+* Random Version Bump (tm) to 0.2.3
+* no code changes
+
+[20050730]
+* Basically just incorporating acx-20050722.acx100fixed.patch
+  This is a bit of a backward step, because instead of figuring out
+  why active scanning doesn't work for acx100, we just disable it.
+  acx100 owners encouraged to try to make it work
+
+[20050729]
+* Added some IE IDs
+
+[20050726]
+* added probe request config to acx100_s_init_packet_templates,
+  maybe acx100 is working now
+
+[20050721]
+* del_timer_sync() sem lockup on SMP maybe fixed
+
+[20050720]
+* lots of amd64 warnings fixed, thanks to Matan Peled <chaosite@gmail.com>
+
+[20050710]
+* {tx,rx}hostdesc->desc_phy removed (was not used)
+* netdev->type of ARPHRD_IEEE80211_PRISM was sticking forever
+  after monitor mode. Fixed
+* monitor mode tx is working again
+* rate reporting added in monitor mode packet header
+
+[20050709]
+* moved PCI specific ioctls to pci.c
+* ioctl.c is PCI/USB independent now
+
+[20050708]
+* Fixed one apparent bug (wlandevice_t had different
+  layout for PCI and USB - conv.c would die horribly)
+* Massive code shuffling with only trivial code changes.
+  Mostly sorting out PCI/USB stuff into relevant files.
+* ihw.c eliminated
+* helper2.c is PCI/USB independent now
diff -urN oldtree/drivers/net/wireless/tiacx/Kconfig newtree/drivers/net/wireless/tiacx/Kconfig
--- oldtree/drivers/net/wireless/tiacx/Kconfig	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/net/wireless/tiacx/Kconfig	2006-02-21 15:58:22.567715744 +0000
@@ -0,0 +1,63 @@
+config ACX
+	tristate "TI acx100/acx111 802.11b/g wireless chipsets"
+	depends on NET_RADIO && EXPERIMENTAL && (USB || PCI)
+	select FW_LOADER
+	---help---
+	A driver for 802.11b/g wireless cards based on
+	Texas Instruments acx100 and acx111 chipsets.
+
+	This driver supports Host AP mode that allows
+	your computer to act as an IEEE 802.11 access point.
+	This driver is new and experimental.
+
+	Texas Instruments did not take part in development of this driver
+	in any way, shape or form.
+
+	The driver can be compiled as a module and will be named "acx".
+
+config ACX_PCI
+	bool "TI acx100/acx111 802.11b/g PCI"
+	depends on ACX && PCI
+	---help---
+	Include PCI and CardBus support in acx.
+
+	acx chipsets need their firmware loaded at startup.
+	You will need to provide a firmware image via hotplug.
+
+	Firmware may be in a form of single image 40-100kb in size
+	(a 'combined' firmware) or two images - main image
+	(again 40-100kb) and radio image (~10kb or less).
+
+	Firmware images are requested from hotplug using following names:
+
+	tiacx100 - main firmware image for acx100 chipset
+	tiacx100rNN - radio acx100 firmware for radio type NN
+	tiacx100cNN - combined acx100 firmware for radio type NN
+	tiacx111 - main acx111 firmware
+	tiacx111rNN - radio acx111 firmware for radio type NN
+	tiacx111cNN - combined acx111 firmware for radio type NN
+
+	Driver will attempt to load combined image first.
+	If no such image is found, it will try to load main image
+	and radio image instead.
+
+	Firmware files are not covered by GPL and are not distributed
+	with this driver for legal reasons.
+
+config ACX_USB
+	bool "TI acx100/acx111 802.11b/g USB"
+	depends on ACX && (USB=y || USB=ACX)
+	---help---
+	Include USB support in acx.
+
+	There is only one currently known device in this category,
+	D-Link DWL-120+, but newer devices seem to be on the horizon.
+
+	acx chipsets need their firmware loaded at startup.
+	You will need to provide a firmware image via hotplug.
+
+	Firmware for USB device is requested from hotplug
+	by the 'tiacx100usb' name.
+
+	Firmware files are not covered by GPL and are not distributed
+	with this driver for legal reasons.
diff -urN oldtree/drivers/net/wireless/tiacx/Makefile newtree/drivers/net/wireless/tiacx/Makefile
--- oldtree/drivers/net/wireless/tiacx/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/net/wireless/tiacx/Makefile	2006-02-21 15:58:22.567715744 +0000
@@ -0,0 +1,6 @@
+obj-$(CONFIG_ACX) += acx.o
+
+acx-obj-$(CONFIG_ACX_PCI) += pci.o
+acx-obj-$(CONFIG_ACX_USB) += usb.o
+
+acx-objs := wlan.o conv.o ioctl.o common.o $(acx-obj-y)
diff -urN oldtree/drivers/net/wireless/tiacx/README newtree/drivers/net/wireless/tiacx/README
--- oldtree/drivers/net/wireless/tiacx/README	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/net/wireless/tiacx/README	2006-02-21 15:58:22.588712552 +0000
@@ -0,0 +1,34 @@
+Contact:
+netdev@vger.kernel.org
+acx100-devel@lists.sourceforge.net
+acx100-users@lists.sourceforge.net
+
+Bug reports:
+
+Visit http://www.catb.org/~esr/faqs/smart-questions.html
+
+Please describe your wireless setup, manufacturer and type
+(acx100/acx100usb/acx111?) of your hardware. Which firmware image(s)
+are you using? If problem is reproducible, #define ACX_DEBUG 2
+in acx_config.h and modprobe driver with debug=0xffff.
+Post resulting kernel log (bzipped). It is large but very useful
+for bug hunting. Try older versions of the driver.
+
+Firmware images:
+
+You should not supply firmware_dir= parameter anymore. Driver will try
+to load the following images via hotplug (not from /usr/share/acx
+directory as older driver did, hotplug firmware directory location
+varies for different distros, try /lib/firmware or
+/usr/lib/hotplug/firmware):
+
+PCI driver:
+'tiacxNNNcMM' (NNN=100/111, MM=radio module ID (in uppercase hex)):
+combined firmware for specified chipset and radio.
+Failing that, it will try to load images named 'tiacxNNN'
+(main firmware for specified chipset) and 'tiacxNNNrMM' (corresponding
+radio module). For example, my firmware is in file named 'tiacx111c16'.
+Alternatively, I may remove it and use pair of files 'tiacx111' and
+'tiacx111r16' instead.
+USB driver:
+image is named 'tiacx100usb'
diff -urN oldtree/drivers/net/wireless/tiacx/acx.h newtree/drivers/net/wireless/tiacx/acx.h
--- oldtree/drivers/net/wireless/tiacx/acx.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/net/wireless/tiacx/acx.h	2006-02-21 15:58:22.559716960 +0000
@@ -0,0 +1,6 @@
+#include "acx_config.h"
+#include "wlan_compat.h"
+#include "wlan_hdr.h"
+#include "wlan_mgmt.h"
+#include "acx_struct.h"
+#include "acx_func.h"
diff -urN oldtree/drivers/net/wireless/tiacx/acx_config.h newtree/drivers/net/wireless/tiacx/acx_config.h
--- oldtree/drivers/net/wireless/tiacx/acx_config.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/net/wireless/tiacx/acx_config.h	2006-02-21 15:58:22.558717112 +0000
@@ -0,0 +1,40 @@
+#define ACX_RELEASE "v0.3.31"
+
+/* set to 0 if you don't want any debugging code to be compiled in */
+/* set to 1 if you want some debugging */
+/* set to 2 if you want extensive debug log */
+#define ACX_DEBUG 1
+#define ACX_DEFAULT_MSG 0
+
+/* assume 32bit I/O width
+ * (16bit is also compatible with Compact Flash) */
+#define ACX_IO_WIDTH 32
+
+/* Set this to 1 if you want monitor mode to use
+ * phy header. Currently it is not useful anyway since we
+ * don't know what useful info (if any) is in phy header.
+ * If you want faster/smaller code, say 0 here */
+#define WANT_PHY_HDR 0
+
+/* whether to do Tx descriptor cleanup in softirq (i.e. not in IRQ
+ * handler) or not. Note that doing it later does slightly increase
+ * system load, so still do that stuff in the IRQ handler for now,
+ * even if that probably means worse latency */
+#define TX_CLEANUP_IN_SOFTIRQ 0
+
+/* if you want very experimental 802.11 power save mode features */
+#define POWER_SAVE_80211 0
+
+/* if you want very early packet fragmentation bits and pieces */
+#define ACX_FRAGMENTATION 0
+
+/* Locking: */
+/* very talkative */
+/* #define PARANOID_LOCKING 1 */
+/* normal (use when bug-free) */
+#define DO_LOCKING 1
+/* else locking is disabled! */
+
+/* 0 - normal mode */
+/* 1 - development/debug: probe for IEs on modprobe */
+#define CMD_DISCOVERY 0
diff -urN oldtree/drivers/net/wireless/tiacx/acx_func.h newtree/drivers/net/wireless/tiacx/acx_func.h
--- oldtree/drivers/net/wireless/tiacx/acx_func.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/net/wireless/tiacx/acx_func.h	2006-02-21 15:58:22.559716960 +0000
@@ -0,0 +1,644 @@
+/***********************************************************************
+** Copyright (C) 2003  ACX100 Open Source Project
+**
+** The contents of this file are subject to the Mozilla Public
+** License Version 1.1 (the "License"); you may not use this file
+** except in compliance with the License. You may obtain a copy of
+** the License at http://www.mozilla.org/MPL/
+**
+** Software distributed under the License is distributed on an "AS
+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+** implied. See the License for the specific language governing
+** rights and limitations under the License.
+**
+** Alternatively, the contents of this file may be used under the
+** terms of the GNU Public License version 2 (the "GPL"), in which
+** case the provisions of the GPL are applicable instead of the
+** above.  If you wish to allow the use of your version of this file
+** only under the terms of the GPL and not to allow others to use
+** your version of this file under the MPL, indicate your decision
+** by deleting the provisions above and replace them with the notice
+** and other provisions required by the GPL.  If you do not delete
+** the provisions above, a recipient may use your version of this
+** file under either the MPL or the GPL.
+** ---------------------------------------------------------------------
+** Inquiries regarding the ACX100 Open Source Project can be
+** made directly to:
+**
+** acx100-users@lists.sf.net
+** http://acx100.sf.net
+** ---------------------------------------------------------------------
+*/
+
+
+/***********************************************************************
+** LOGGING
+**
+** - Avoid SHOUTING needlessly. Avoid excessive verbosity.
+**   Gradually remove messages which are old debugging aids.
+**
+** - Use printk() for messages which are to be always logged.
+**   Supply either 'acx:' or '<devname>:' prefix so that user
+**   can figure out who's speaking among other kernel chatter.
+**   acx: is for general issues (e.g. "acx: no firmware image!")
+**   while <devname>: is related to a particular device
+**   (think about multi-card setup). Double check that message
+**   is not confusing to the average user.
+**
+** - use printk KERN_xxx level only if message is not a WARNING
+**   but is INFO, ERR etc.
+**
+** - Use printk_ratelimited() for messages which may flood
+**   (e.g. "rx DUP pkt!").
+**
+** - Use log() for messages which may be omitted (and they
+**   _will_ be omitted in non-debug builds). Note that
+**   message levels may be disabled at compile-time selectively,
+**   thus select them wisely. Example: L_DEBUG is the lowest
+**   (most likely to be compiled out) -> use for less important stuff.
+**
+** - Do not print important stuff with log(), or else people
+**   will never build non-debug driver.
+**
+** Style:
+** hex: capital letters, zero filled (e.g. 0x02AC)
+** str: dont start from capitals, no trailing periods ("tx: queue is stopped")
+*/
+#if ACX_DEBUG > 1
+
+void log_fn_enter(const char *funcname);
+void log_fn_exit(const char *funcname);
+void log_fn_exit_v(const char *funcname, int v);
+
+#define FN_ENTER \
+	do { \
+		if (unlikely(acx_debug & L_FUNC)) { \
+			log_fn_enter(__func__); \
+		} \
+	} while (0)
+
+#define FN_EXIT1(v) \
+	do { \
+		if (unlikely(acx_debug & L_FUNC)) { \
+			log_fn_exit_v(__func__, v); \
+		} \
+	} while (0)
+#define FN_EXIT0 \
+	do { \
+		if (unlikely(acx_debug & L_FUNC)) { \
+			log_fn_exit(__func__); \
+		} \
+	} while (0)
+
+#else
+
+#define FN_ENTER
+#define FN_EXIT1(v)
+#define FN_EXIT0
+
+#endif /* ACX_DEBUG > 1 */
+
+
+#if ACX_DEBUG
+
+#define log(chan, args...) \
+	do { \
+		if (acx_debug & (chan)) \
+			printk(args); \
+	} while (0)
+#define printk_ratelimited(args...) printk(args)
+
+#else /* Non-debug build: */
+
+#define log(chan, args...)
+/* Standard way of log flood prevention */
+#define printk_ratelimited(args...) \
+do { \
+	if (printk_ratelimit()) \
+		printk(args); \
+} while (0)
+
+#endif /* ACX_DEBUG */
+
+void acx_print_mac(const char *head, const u8 *mac, const char *tail);
+
+/* Optimized out to nothing in non-debug build */
+static inline void
+acxlog_mac(int level, const char *head, const u8 *mac, const char *tail)
+{
+	if (acx_debug & level) {
+		acx_print_mac(head, mac, tail);
+	}
+}
+
+
+/***********************************************************************
+** MAC address helpers
+*/
+static inline void
+MAC_COPY(u8 *mac, const u8 *src)
+{
+	*(u32*)mac = *(u32*)src;
+	((u16*)mac)[2] = ((u16*)src)[2];
+	/* kernel's memcpy will do the same: memcpy(dst, src, ETH_ALEN); */
+}
+
+static inline void
+MAC_FILL(u8 *mac, u8 val)
+{
+	memset(mac, val, ETH_ALEN);
+}
+
+static inline void
+MAC_BCAST(u8 *mac)
+{
+	((u16*)mac)[2] = *(u32*)mac = -1;
+}
+
+static inline void
+MAC_ZERO(u8 *mac)
+{
+	((u16*)mac)[2] = *(u32*)mac = 0;
+}
+
+static inline int
+mac_is_equal(const u8 *a, const u8 *b)
+{
+	/* can't beat this */
+	return memcmp(a, b, ETH_ALEN) == 0;
+}
+
+static inline int
+mac_is_bcast(const u8 *mac)
+{
+	/* AND together 4 first bytes with sign-extended 2 last bytes
+	** Only bcast address gives 0xffffffff. +1 gives 0 */
+	return ( *(s32*)mac & ((s16*)mac)[2] ) + 1 == 0;
+}
+
+static inline int
+mac_is_zero(const u8 *mac)
+{
+	return ( *(u32*)mac | ((u16*)mac)[2] ) == 0;
+}
+
+static inline int
+mac_is_directed(const u8 *mac)
+{
+	return (mac[0] & 1)==0;
+}
+
+static inline int
+mac_is_mcast(const u8 *mac)
+{
+	return (mac[0] & 1) && !mac_is_bcast(mac);
+}
+
+#define MACSTR "%02X:%02X:%02X:%02X:%02X:%02X"
+#define MAC(bytevector) \
+	((unsigned char *)bytevector)[0], \
+	((unsigned char *)bytevector)[1], \
+	((unsigned char *)bytevector)[2], \
+	((unsigned char *)bytevector)[3], \
+	((unsigned char *)bytevector)[4], \
+	((unsigned char *)bytevector)[5]
+
+
+/***********************************************************************
+** Random helpers
+*/
+#define TO_STRING(x)	#x
+#define STRING(x)	TO_STRING(x)
+
+#define CLEAR_BIT(val, mask) ((val) &= ~(mask))
+#define SET_BIT(val, mask) ((val) |= (mask))
+
+/* undefined if v==0 */
+static inline unsigned int
+lowest_bit(u16 v)
+{
+	unsigned int n = 0;
+	while (!(v & 0xf)) { v>>=4; n+=4; }
+	while (!(v & 1)) { v>>=1; n++; }
+	return n;
+}
+
+/* undefined if v==0 */
+static inline unsigned int
+highest_bit(u16 v)
+{
+	unsigned int n = 0;
+	while (v>0xf) { v>>=4; n+=4; }
+	while (v>1) { v>>=1; n++; }
+	return n;
+}
+
+/* undefined if v==0 */
+static inline int
+has_only_one_bit(u16 v)
+{
+	return ((v-1) ^ v) >= v;
+}
+
+
+/***********************************************************************
+** LOCKING
+** We have adev->sem and adev->lock.
+**
+** We employ following naming convention in order to get locking right:
+**
+** acx_e_xxxx - external entry points called from process context.
+**	It is okay to sleep. adev->sem is to be taken on entry.
+** acx_i_xxxx - external entry points possibly called from atomic context.
+**	Sleeping is not allowed (and thus down(sem) is not legal!)
+** acx_s_xxxx - potentially sleeping functions. Do not ever call under lock!
+** acx_l_xxxx - functions which expect lock to be already taken.
+** rest       - non-sleeping functions which do not require locking
+**		but may be run under lock
+**
+** A small number of local helpers do not have acx_[eisl]_ prefix.
+** They are always close to caller and are to be revieved locally.
+**
+** Theory of operation:
+**
+** All process-context entry points (_e_ functions) take sem
+** immediately. IRQ handler and other 'atomic-context' entry points
+** (_i_ functions) take lock immediately on entry, but dont take sem
+** because that might sleep.
+**
+** Thus *all* code is either protected by sem or lock, or both.
+**
+** Code which must not run concurrently with IRQ takes lock.
+** Such code is marked with _l_.
+**
+** This results in the following rules of thumb useful in code review:
+**
+** + If a function calls _s_ fn, it must be an _s_ itself.
+** + You can call _l_ fn only (a) from another _l_ fn
+**   or (b) from _s_, _e_ or _i_ fn by taking lock, calling _l_,
+**   and dropping lock.
+** + All IRQ code runs under lock.
+** + Any _s_ fn is running under sem.
+** + Code under sem can race only with IRQ code.
+** + Code under sem+lock cannot race with anything.
+*/
+
+/* These functions *must* be inline or they will break horribly on SPARC, due
+ * to its weird semantics for save/restore flags */
+
+#if defined(PARANOID_LOCKING) /* Lock debugging */
+
+void acx_lock_debug(acx_device_t *adev, const char* where);
+void acx_unlock_debug(acx_device_t *adev, const char* where);
+void acx_down_debug(acx_device_t *adev, const char* where);
+void acx_up_debug(acx_device_t *adev, const char* where);
+void acx_lock_unhold(void);
+void acx_sem_unhold(void);
+
+static inline void
+acx_lock_helper(acx_device_t *adev, unsigned long *fp, const char* where)
+{
+	acx_lock_debug(adev, where);
+	spin_lock_irqsave(&adev->lock, *fp);
+}
+static inline void
+acx_unlock_helper(acx_device_t *adev, unsigned long *fp, const char* where)
+{
+	acx_unlock_debug(adev, where);
+	spin_unlock_irqrestore(&adev->lock, *fp);
+}
+static inline void
+acx_down_helper(acx_device_t *adev, const char* where)
+{
+	acx_down_debug(adev, where);
+}
+static inline void
+acx_up_helper(acx_device_t *adev, const char* where)
+{
+	acx_up_debug(adev, where);
+}
+#define acx_lock(adev, flags)	acx_lock_helper(adev, &(flags), __FILE__ ":" STRING(__LINE__))
+#define acx_unlock(adev, flags)	acx_unlock_helper(adev, &(flags), __FILE__ ":" STRING(__LINE__))
+#define acx_sem_lock(adev)	acx_down_helper(adev, __FILE__ ":" STRING(__LINE__))
+#define acx_sem_unlock(adev)	acx_up_helper(adev, __FILE__ ":" STRING(__LINE__))
+
+#elif defined(DO_LOCKING)
+
+#define acx_lock(adev, flags)	spin_lock_irqsave(&adev->lock, flags)
+#define acx_unlock(adev, flags)	spin_unlock_irqrestore(&adev->lock, flags)
+#define acx_sem_lock(adev)	down(&adev->sem)
+#define acx_sem_unlock(adev)	up(&adev->sem)
+#define acx_lock_unhold()	((void)0)
+#define acx_sem_unhold()	((void)0)
+
+#else /* no locking! :( */
+
+#define acx_lock(adev, flags)	((void)0)
+#define acx_unlock(adev, flags)	((void)0)
+#define acx_sem_lock(adev)	((void)0)
+#define acx_sem_unlock(adev)	((void)0)
+#define acx_lock_unhold()	((void)0)
+#define acx_sem_unhold()	((void)0)
+
+#endif
+
+
+/***********************************************************************
+*/
+
+/* Can race with rx path (which is not protected by sem):
+** rx -> process_[re]assocresp() -> set_status(ASSOCIATED) -> wake_queue()
+** Can race with tx_complete IRQ:
+** IRQ -> acxpci_l_clean_txdesc -> acx_wake_queue
+** Review carefully all callsites */
+static inline void
+acx_stop_queue(struct net_device *ndev, const char *msg)
+{
+	if (netif_queue_stopped(ndev))
+		return;
+
+	netif_stop_queue(ndev);
+	if (msg)
+		log(L_BUFT, "tx: stop queue %s\n", msg);
+}
+
+static inline int
+acx_queue_stopped(struct net_device *ndev)
+{
+	return netif_queue_stopped(ndev);
+}
+
+/*
+static inline void
+acx_start_queue(struct net_device *ndev, const char *msg)
+{
+	netif_start_queue(ndev);
+	if (msg)
+		log(L_BUFT, "tx: start queue %s\n", msg);
+}
+*/
+
+static inline void
+acx_wake_queue(struct net_device *ndev, const char *msg)
+{
+	netif_wake_queue(ndev);
+	if (msg)
+		log(L_BUFT, "tx: wake queue %s\n", msg);
+}
+
+static inline void
+acx_carrier_off(struct net_device *ndev, const char *msg)
+{
+	netif_carrier_off(ndev);
+	if (msg)
+		log(L_BUFT, "tx: carrier off %s\n", msg);
+}
+
+static inline void
+acx_carrier_on(struct net_device *ndev, const char *msg)
+{
+	netif_carrier_on(ndev);
+	if (msg)
+		log(L_BUFT, "tx: carrier on %s\n", msg);
+}
+
+/* This function does not need locking UNLESS you call it
+** as acx_set_status(ACX_STATUS_4_ASSOCIATED), bacause this can
+** wake queue. This can race with stop_queue elsewhere. */
+void acx_set_status(acx_device_t *adev, u16 status);
+
+
+/***********************************************************************
+** Communication with firmware
+*/
+#define CMD_TIMEOUT_MS(n)	(n)
+#define ACX_CMD_TIMEOUT_DEFAULT	CMD_TIMEOUT_MS(50)
+
+#if ACX_DEBUG
+
+/* We want to log cmd names */
+int acxpci_s_issue_cmd_timeo_debug(acx_device_t *adev, unsigned cmd, void *param, unsigned len, unsigned timeout, const char* cmdstr);
+int acxusb_s_issue_cmd_timeo_debug(acx_device_t *adev, unsigned cmd, void *param, unsigned len, unsigned timeout, const char* cmdstr);
+static inline int
+acx_s_issue_cmd_timeo_debug(acx_device_t *adev, unsigned cmd, void *param, unsigned len, unsigned timeout, const char* cmdstr)
+{
+	if (IS_PCI(adev))
+		return acxpci_s_issue_cmd_timeo_debug(adev, cmd, param, len, timeout, cmdstr);
+	return acxusb_s_issue_cmd_timeo_debug(adev, cmd, param, len, timeout, cmdstr);
+}
+#define acx_s_issue_cmd(adev,cmd,param,len) \
+	acx_s_issue_cmd_timeo_debug(adev,cmd,param,len,ACX_CMD_TIMEOUT_DEFAULT,#cmd)
+#define acx_s_issue_cmd_timeo(adev,cmd,param,len,timeo) \
+	acx_s_issue_cmd_timeo_debug(adev,cmd,param,len,timeo,#cmd)
+int acx_s_configure_debug(acx_device_t *adev, void *pdr, int type, const char* str);
+#define acx_s_configure(adev,pdr,type) \
+	acx_s_configure_debug(adev,pdr,type,#type)
+int acx_s_interrogate_debug(acx_device_t *adev, void *pdr, int type, const char* str);
+#define acx_s_interrogate(adev,pdr,type) \
+	acx_s_interrogate_debug(adev,pdr,type,#type)
+
+#else
+
+int acxpci_s_issue_cmd_timeo(acx_device_t *adev, unsigned cmd, void *param, unsigned len, unsigned timeout);
+int acxusb_s_issue_cmd_timeo(acx_device_t *adev, unsigned cmd, void *param, unsigned len, unsigned timeout);
+static inline int
+acx_s_issue_cmd_timeo(acx_device_t *adev, unsigned cmd,	void *param, unsigned len, unsigned timeout)
+{
+	if (IS_PCI(adev))
+		return acxpci_s_issue_cmd_timeo(adev, cmd, param, len, timeout);
+	return acxusb_s_issue_cmd_timeo(adev, cmd, param, len, timeout);
+}
+static inline int
+acx_s_issue_cmd(acx_device_t *adev, unsigned cmd, void *param, unsigned len)
+{
+	if (IS_PCI(adev))
+		return acxpci_s_issue_cmd_timeo(adev, cmd, param, len, ACX_CMD_TIMEOUT_DEFAULT);
+	return acxusb_s_issue_cmd_timeo(adev, cmd, param, len, ACX_CMD_TIMEOUT_DEFAULT);
+}
+int acx_s_configure(acx_device_t *adev, void *pdr, int type);
+int acx_s_interrogate(acx_device_t *adev, void *pdr, int type);
+
+#endif
+
+void acx_s_cmd_start_scan(acx_device_t *adev);
+
+
+/***********************************************************************
+** Ioctls
+*/
+int
+acx111pci_ioctl_info(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	struct iw_param *vwrq,
+	char *extra);
+int
+acx100pci_ioctl_set_phy_amp_bias(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	struct iw_param *vwrq,
+	char *extra);
+
+
+/***********************************************************************
+** /proc
+*/
+#ifdef CONFIG_PROC_FS
+int acx_proc_register_entries(const struct net_device *ndev);
+int acx_proc_unregister_entries(const struct net_device *ndev);
+#else
+static inline int
+acx_proc_register_entries(const struct net_device *ndev) { return OK; }
+static inline int
+acx_proc_unregister_entries(const struct net_device *ndev) { return OK; }
+#endif
+
+
+/***********************************************************************
+*/
+firmware_image_t *acx_s_read_fw(struct device *dev, const char *file, u32 *size);
+int acxpci_s_upload_radio(acx_device_t *adev);
+
+
+/***********************************************************************
+** Unsorted yet :)
+*/
+int acxpci_s_read_phy_reg(acx_device_t *adev, u32 reg, u8 *charbuf);
+int acxusb_s_read_phy_reg(acx_device_t *adev, u32 reg, u8 *charbuf);
+static inline int
+acx_s_read_phy_reg(acx_device_t *adev, u32 reg, u8 *charbuf)
+{
+	if (IS_PCI(adev))
+		return acxpci_s_read_phy_reg(adev, reg, charbuf);
+	return acxusb_s_read_phy_reg(adev, reg, charbuf);
+}
+
+int acxpci_s_write_phy_reg(acx_device_t *adev, u32 reg, u8 value);
+int acxusb_s_write_phy_reg(acx_device_t *adev, u32 reg, u8 value);
+static inline int
+acx_s_write_phy_reg(acx_device_t *adev, u32 reg, u8 value)
+{
+	if (IS_PCI(adev))
+		return acxpci_s_write_phy_reg(adev, reg, value);
+	return acxusb_s_write_phy_reg(adev, reg, value);
+}
+
+tx_t* acxpci_l_alloc_tx(acx_device_t *adev);
+tx_t* acxusb_l_alloc_tx(acx_device_t *adev);
+static inline tx_t*
+acx_l_alloc_tx(acx_device_t *adev)
+{
+	if (IS_PCI(adev))
+		return acxpci_l_alloc_tx(adev);
+	return acxusb_l_alloc_tx(adev);
+}
+
+void acxusb_l_dealloc_tx(tx_t *tx_opaque);
+static inline void
+acx_l_dealloc_tx(acx_device_t *adev, tx_t *tx_opaque)
+{
+	if (IS_USB(adev))
+		acxusb_l_dealloc_tx(tx_opaque);
+}
+
+void* acxpci_l_get_txbuf(acx_device_t *adev, tx_t *tx_opaque);
+void* acxusb_l_get_txbuf(acx_device_t *adev, tx_t *tx_opaque);
+static inline void*
+acx_l_get_txbuf(acx_device_t *adev, tx_t *tx_opaque)
+{
+	if (IS_PCI(adev))
+		return acxpci_l_get_txbuf(adev, tx_opaque);
+	return acxusb_l_get_txbuf(adev, tx_opaque);
+}
+
+void acxpci_l_tx_data(acx_device_t *adev, tx_t *tx_opaque, int len);
+void acxusb_l_tx_data(acx_device_t *adev, tx_t *tx_opaque, int len);
+static inline void
+acx_l_tx_data(acx_device_t *adev, tx_t *tx_opaque, int len)
+{
+	if (IS_PCI(adev))
+		acxpci_l_tx_data(adev, tx_opaque, len);
+	else
+		acxusb_l_tx_data(adev, tx_opaque, len);
+}
+
+static inline wlan_hdr_t*
+acx_get_wlan_hdr(acx_device_t *adev, const rxbuffer_t *rxbuf)
+{
+	return (wlan_hdr_t*)((u8*)&rxbuf->hdr_a3 + adev->phy_header_len);
+}
+
+void acxpci_l_power_led(acx_device_t *adev, int enable);
+int acxpci_read_eeprom_byte(acx_device_t *adev, u32 addr, u8 *charbuf);
+unsigned int acxpci_l_clean_txdesc(acx_device_t *adev);
+void acxpci_l_clean_txdesc_emergency(acx_device_t *adev);
+int acxpci_s_create_hostdesc_queues(acx_device_t *adev);
+void acxpci_create_desc_queues(acx_device_t *adev, u32 tx_queue_start, u32 rx_queue_start);
+void acxpci_free_desc_queues(acx_device_t *adev);
+char* acxpci_s_proc_diag_output(char *p, acx_device_t *adev);
+int acxpci_proc_eeprom_output(char *p, acx_device_t *adev);
+void acxpci_set_interrupt_mask(acx_device_t *adev);
+int acx100pci_s_set_tx_level(acx_device_t *adev, u8 level_dbm);
+
+void acx_s_msleep(int ms);
+int acx_s_init_mac(acx_device_t *adev);
+void acx_set_reg_domain(acx_device_t *adev, unsigned char reg_dom_id);
+void acx_set_timer(acx_device_t *adev, int timeout_us);
+void acx_update_capabilities(acx_device_t *adev);
+void acx_s_start(acx_device_t *adev);
+
+void acx_s_update_card_settings(acx_device_t *adev);
+void acx_s_parse_configoption(acx_device_t *adev, const acx111_ie_configoption_t *pcfg);
+void acx_l_update_ratevector(acx_device_t *adev);
+
+void acx_init_task_scheduler(acx_device_t *adev);
+void acx_schedule_task(acx_device_t *adev, unsigned int set_flag);
+
+int acx_e_ioctl_old(struct net_device *ndev, struct ifreq *ifr, int cmd);
+
+client_t *acx_l_sta_list_get(acx_device_t *adev, const u8 *address);
+void acx_l_sta_list_del(acx_device_t *adev, client_t *clt);
+
+int acx_l_transmit_disassoc(acx_device_t *adev, client_t *clt);
+void acx_i_timer(unsigned long a);
+int acx_s_complete_scan(acx_device_t *adev);
+
+struct sk_buff *acx_rxbuf_to_ether(acx_device_t *adev, rxbuffer_t *rxbuf);
+int acx_ether_to_txbuf(acx_device_t *adev, void *txbuf, const struct sk_buff *skb);
+
+u8 acx_signal_determine_quality(u8 signal, u8 noise);
+
+void acx_l_process_rxbuf(acx_device_t *adev, rxbuffer_t *rxbuf);
+void acx_l_handle_txrate_auto(acx_device_t *adev, struct client *txc,
+			u16 intended_rate, u8 rate100, u16 rate111, u8 error,
+			int pkts_to_ignore);
+
+void acx_dump_bytes(const void *, int);
+void acx_log_bad_eid(wlan_hdr_t* hdr, int len, wlan_ie_t* ie_ptr);
+
+u8 acx_rate111to100(u16);
+
+void acx_s_set_defaults(acx_device_t *adev);
+
+#if !ACX_DEBUG
+static inline const char* acx_get_packet_type_string(u16 fc) { return ""; }
+#else
+const char* acx_get_packet_type_string(u16 fc);
+#endif
+const char* acx_cmd_status_str(unsigned int state);
+
+int acx_i_start_xmit(struct sk_buff *skb, struct net_device *ndev);
+
+void great_inquisitor(acx_device_t *adev);
+
+void acx_s_get_firmware_version(acx_device_t *adev);
+void acx_display_hardware_details(acx_device_t *adev);
+
+int acx_e_change_mtu(struct net_device *ndev, int mtu);
+struct net_device_stats* acx_e_get_stats(struct net_device *ndev);
+struct iw_statistics* acx_e_get_wireless_stats(struct net_device *ndev);
+
+int __init acxpci_e_init_module(void);
+int __init acxusb_e_init_module(void);
+void __exit acxpci_e_cleanup_module(void);
+void __exit acxusb_e_cleanup_module(void);
diff -urN oldtree/drivers/net/wireless/tiacx/acx_struct.h newtree/drivers/net/wireless/tiacx/acx_struct.h
--- oldtree/drivers/net/wireless/tiacx/acx_struct.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/net/wireless/tiacx/acx_struct.h	2006-02-21 15:58:22.561716656 +0000
@@ -0,0 +1,1965 @@
+/***********************************************************************
+** Copyright (C) 2003  ACX100 Open Source Project
+**
+** The contents of this file are subject to the Mozilla Public
+** License Version 1.1 (the "License"); you may not use this file
+** except in compliance with the License. You may obtain a copy of
+** the License at http://www.mozilla.org/MPL/
+**
+** Software distributed under the License is distributed on an "AS
+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+** implied. See the License for the specific language governing
+** rights and limitations under the License.
+**
+** Alternatively, the contents of this file may be used under the
+** terms of the GNU Public License version 2 (the "GPL"), in which
+** case the provisions of the GPL are applicable instead of the
+** above.  If you wish to allow the use of your version of this file
+** only under the terms of the GPL and not to allow others to use
+** your version of this file under the MPL, indicate your decision
+** by deleting the provisions above and replace them with the notice
+** and other provisions required by the GPL.  If you do not delete
+** the provisions above, a recipient may use your version of this
+** file under either the MPL or the GPL.
+** ---------------------------------------------------------------------
+** Inquiries regarding the ACX100 Open Source Project can be
+** made directly to:
+**
+** acx100-users@lists.sf.net
+** http://acx100.sf.net
+** ---------------------------------------------------------------------
+*/
+
+/***********************************************************************
+** Forward declarations of types
+*/
+typedef struct tx tx_t;
+typedef struct acx_device acx_device_t;
+typedef struct client client_t;
+typedef struct rxdesc rxdesc_t;
+typedef struct txdesc txdesc_t;
+typedef struct rxhostdesc rxhostdesc_t;
+typedef struct txhostdesc txhostdesc_t;
+
+
+/***********************************************************************
+** Debug / log functionality
+*/
+enum {
+	L_LOCK		= (ACX_DEBUG>1)*0x0001,	/* locking debug log */
+	L_INIT		= (ACX_DEBUG>0)*0x0002,	/* special card initialization logging */
+	L_IRQ		= (ACX_DEBUG>0)*0x0004,	/* interrupt stuff */
+	L_ASSOC		= (ACX_DEBUG>0)*0x0008,	/* assocation (network join) and station log */
+	L_FUNC		= (ACX_DEBUG>1)*0x0020,	/* logging of function enter / leave */
+	L_XFER		= (ACX_DEBUG>1)*0x0080,	/* logging of transfers and mgmt */
+	L_DATA		= (ACX_DEBUG>1)*0x0100,	/* logging of transfer data */
+	L_DEBUG		= (ACX_DEBUG>1)*0x0200,	/* log of debug info */
+	L_IOCTL		= (ACX_DEBUG>0)*0x0400,	/* log ioctl calls */
+	L_CTL		= (ACX_DEBUG>1)*0x0800,	/* log of low-level ctl commands */
+	L_BUFR		= (ACX_DEBUG>1)*0x1000,	/* debug rx buffer mgmt (ring buffer etc.) */
+	L_XFER_BEACON	= (ACX_DEBUG>1)*0x2000,	/* also log beacon packets */
+	L_BUFT		= (ACX_DEBUG>1)*0x4000,	/* debug tx buffer mgmt (ring buffer etc.) */
+	L_USBRXTX	= (ACX_DEBUG>0)*0x8000,	/* debug USB rx/tx operations */
+	L_BUF		= L_BUFR + L_BUFT,
+	L_ANY		= 0xffff
+};
+
+#if ACX_DEBUG
+extern unsigned int acx_debug;
+#else
+enum { acx_debug = 0 };
+#endif
+
+
+/***********************************************************************
+** Random helpers
+*/
+#define ACX_PACKED __WLAN_ATTRIB_PACK__
+
+#define VEC_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+/* Use worker_queues for 2.5/2.6 kernels and queue tasks for 2.4 kernels
+   (used for the 'bottom half' of the interrupt routine) */
+
+#include <linux/workqueue.h>
+#define USE_WORKER_TASKS
+#define WORK_STRUCT struct work_struct
+#define SCHEDULE_WORK schedule_work
+#define FLUSH_SCHEDULED_WORK flush_scheduled_work
+
+
+/***********************************************************************
+** Constants
+*/
+#define OK	0
+#define NOT_OK	1
+
+/* The supported chip models */
+#define CHIPTYPE_ACX100		1
+#define CHIPTYPE_ACX111		2
+
+#define IS_ACX100(adev)	((adev)->chip_type == CHIPTYPE_ACX100)
+#define IS_ACX111(adev)	((adev)->chip_type == CHIPTYPE_ACX111)
+
+/* Supported interfaces */
+#define DEVTYPE_PCI		0
+#define DEVTYPE_USB		1
+
+#if !defined(CONFIG_ACX_PCI) && !defined(CONFIG_ACX_USB)
+#error Driver must include PCI and/or USB support. You selected neither.
+#endif
+
+#if defined(CONFIG_ACX_PCI)
+ #if !defined(CONFIG_ACX_USB)
+  #define IS_PCI(adev)	1
+ #else
+  #define IS_PCI(adev)	((adev)->dev_type == DEVTYPE_PCI)
+ #endif
+#else
+ #define IS_PCI(adev)	0
+#endif
+
+#if defined(CONFIG_ACX_USB)
+ #if !defined(CONFIG_ACX_PCI)
+  #define IS_USB(adev)	1
+ #else
+  #define IS_USB(adev)	((adev)->dev_type == DEVTYPE_USB)
+ #endif
+#else
+ #define IS_USB(adev)	0
+#endif
+
+/* Driver defaults */
+#define DEFAULT_DTIM_INTERVAL	10
+/* used to be 2048, but FreeBSD driver changed it to 4096 to work properly
+** in noisy wlans */
+#define DEFAULT_MSDU_LIFETIME	4096
+#define DEFAULT_RTS_THRESHOLD	2312	/* max. size: disable RTS mechanism */
+#define DEFAULT_BEACON_INTERVAL	100
+
+#define ACX100_BAP_DATALEN_MAX		4096
+#define ACX100_RID_GUESSING_MAXLEN	2048	/* I'm not really sure */
+#define ACX100_RIDDATA_MAXLEN		ACX100_RID_GUESSING_MAXLEN
+
+/* Support Constants */
+/* Radio type names, found in Win98 driver's TIACXLN.INF */
+#define RADIO_MAXIM_0D		0x0d
+#define RADIO_RFMD_11		0x11
+#define RADIO_RALINK_15		0x15
+/* used in ACX111 cards (WG311v2, WL-121, ...): */
+#define RADIO_RADIA_16		0x16
+/* most likely *sometimes* used in ACX111 cards: */
+#define RADIO_UNKNOWN_17	0x17
+/* FwRad19.bin was found in a Safecom driver; must be an ACX111 radio: */
+#define RADIO_UNKNOWN_19	0x19
+
+/* Controller Commands */
+/* can be found in table cmdTable in firmware "Rev. 1.5.0" (FW150) */
+#define ACX1xx_CMD_RESET		0x00
+#define ACX1xx_CMD_INTERROGATE		0x01
+#define ACX1xx_CMD_CONFIGURE		0x02
+#define ACX1xx_CMD_ENABLE_RX		0x03
+#define ACX1xx_CMD_ENABLE_TX		0x04
+#define ACX1xx_CMD_DISABLE_RX		0x05
+#define ACX1xx_CMD_DISABLE_TX		0x06
+#define ACX1xx_CMD_FLUSH_QUEUE		0x07
+#define ACX1xx_CMD_SCAN			0x08
+#define ACX1xx_CMD_STOP_SCAN		0x09
+#define ACX1xx_CMD_CONFIG_TIM		0x0a
+#define ACX1xx_CMD_JOIN			0x0b
+#define ACX1xx_CMD_WEP_MGMT		0x0c
+#ifdef OLD_FIRMWARE_VERSIONS
+#define ACX100_CMD_HALT			0x0e	/* mapped to unknownCMD in FW150 */
+#else
+#define ACX1xx_CMD_MEM_READ		0x0d
+#define ACX1xx_CMD_MEM_WRITE		0x0e
+#endif
+#define ACX1xx_CMD_SLEEP		0x0f
+#define ACX1xx_CMD_WAKE			0x10
+#define ACX1xx_CMD_UNKNOWN_11		0x11	/* mapped to unknownCMD in FW150 */
+#define ACX100_CMD_INIT_MEMORY		0x12
+#define ACX1xx_CMD_CONFIG_BEACON	0x13
+#define ACX1xx_CMD_CONFIG_PROBE_RESPONSE	0x14
+#define ACX1xx_CMD_CONFIG_NULL_DATA	0x15
+#define ACX1xx_CMD_CONFIG_PROBE_REQUEST	0x16
+#define ACX1xx_CMD_TEST			0x17
+#define ACX1xx_CMD_RADIOINIT		0x18
+#define ACX111_CMD_RADIOCALIB		0x19
+
+/* 'After Interrupt' Commands */
+#define ACX_AFTER_IRQ_CMD_STOP_SCAN	0x01
+#define ACX_AFTER_IRQ_CMD_ASSOCIATE	0x02
+#define ACX_AFTER_IRQ_CMD_RADIO_RECALIB	0x04
+#define ACX_AFTER_IRQ_UPDATE_CARD_CFG	0x08
+#define ACX_AFTER_IRQ_TX_CLEANUP	0x10
+#define ACX_AFTER_IRQ_COMPLETE_SCAN	0x20
+#define ACX_AFTER_IRQ_RESTART_SCAN	0x40
+
+/***********************************************************************
+** Tx/Rx buffer sizes and watermarks
+**
+** This will alloc and use DMAable buffers of
+** WLAN_A4FR_MAXLEN_WEP_FCS * (RX_CNT + TX_CNT) bytes
+** RX/TX_CNT=32 -> ~150k DMA buffers
+** RX/TX_CNT=16 -> ~75k DMA buffers
+**
+** 2005-10-10: reduced memory usage by lowering both to 16
+*/
+#define RX_CNT 16
+#define TX_CNT 16
+
+/* we clean up txdescs when we have N free txdesc: */
+#define TX_CLEAN_BACKLOG (TX_CNT/4)
+#define TX_START_CLEAN (TX_CNT - TX_CLEAN_BACKLOG)
+#define TX_EMERG_CLEAN 2
+/* we stop queue if we have < N free txbufs: */
+#define TX_STOP_QUEUE 3
+/* we start queue if we have >= N free txbufs: */
+#define TX_START_QUEUE 5
+
+/***********************************************************************
+** Interrogate/Configure cmd constants
+**
+** NB: length includes JUST the data part of the IE
+** (does not include size of the (type,len) pair)
+**
+** TODO: seems that acx100, acx100usb, acx111 have some differences,
+** fix code with regard to this!
+*/
+
+#define DEF_IE(name, val, len) enum { ACX##name=val, ACX##name##_LEN=len }
+
+/* Information Elements: Network Parameters, Static Configuration Entities */
+/* these are handled by real_cfgtable in firmware "Rev 1.5.0" (FW150) */
+DEF_IE(1xx_IE_UNKNOWN_00		,0x0000, -1);	/* mapped to cfgInvalid in FW150 */
+DEF_IE(100_IE_ACX_TIMER			,0x0001, 0x10);
+DEF_IE(1xx_IE_POWER_MGMT		,0x0002, 0x06);
+DEF_IE(1xx_IE_QUEUE_CONFIG		,0x0003, 0x1c);
+DEF_IE(100_IE_BLOCK_SIZE		,0x0004, 0x02);
+DEF_IE(1xx_IE_MEMORY_CONFIG_OPTIONS	,0x0005, 0x14);
+DEF_IE(1xx_IE_RATE_FALLBACK		,0x0006, 0x01);
+DEF_IE(100_IE_WEP_OPTIONS		,0x0007, 0x03);
+DEF_IE(111_IE_RADIO_BAND		,0x0007, -1);
+DEF_IE(1xx_IE_MEMORY_MAP		,0x0008, 0x28); /* huh? */
+DEF_IE(100_IE_SSID			,0x0008, 0x20); /* huh? */
+DEF_IE(1xx_IE_SCAN_STATUS		,0x0009, 0x04); /* mapped to cfgInvalid in FW150 */
+DEF_IE(1xx_IE_ASSOC_ID			,0x000a, 0x02);
+DEF_IE(1xx_IE_UNKNOWN_0B		,0x000b, -1);	/* mapped to cfgInvalid in FW150 */
+DEF_IE(100_IE_UNKNOWN_0C		,0x000c, -1);	/* very small implementation in FW150! */
+/* ACX100 has an equivalent struct in the cmd mailbox directly after reset.
+ * 0x14c seems extremely large, will trash stack on failure (memset!)
+ * in case of small input struct --> OOPS! */
+DEF_IE(111_IE_CONFIG_OPTIONS		,0x000c, 0x14c);
+DEF_IE(1xx_IE_FWREV			,0x000d, 0x18);
+DEF_IE(1xx_IE_FCS_ERROR_COUNT		,0x000e, 0x04);
+DEF_IE(1xx_IE_MEDIUM_USAGE		,0x000f, 0x08);
+DEF_IE(1xx_IE_RXCONFIG			,0x0010, 0x04);
+DEF_IE(100_IE_UNKNOWN_11		,0x0011, -1);	/* NONBINARY: large implementation in FW150! link quality readings or so? */
+DEF_IE(111_IE_QUEUE_THRESH		,0x0011, -1);
+DEF_IE(100_IE_UNKNOWN_12		,0x0012, -1);	/* NONBINARY: VERY large implementation in FW150!! */
+DEF_IE(111_IE_BSS_POWER_SAVE		,0x0012, -1);
+DEF_IE(1xx_IE_FIRMWARE_STATISTICS	,0x0013, 0x9c);
+DEF_IE(1xx_IE_FEATURE_CONFIG		,0x0015, 0x08);
+DEF_IE(111_IE_KEY_CHOOSE		,0x0016, 0x04);	/* for rekeying. really len=4?? */
+DEF_IE(1xx_IE_DOT11_STATION_ID		,0x1001, 0x06);
+DEF_IE(100_IE_DOT11_UNKNOWN_1002	,0x1002, -1);	/* mapped to cfgInvalid in FW150 */
+DEF_IE(111_IE_DOT11_FRAG_THRESH		,0x1002, -1);	/* mapped to cfgInvalid in FW150 */
+DEF_IE(100_IE_DOT11_BEACON_PERIOD	,0x1003, 0x02);	/* mapped to cfgInvalid in FW150 */
+DEF_IE(1xx_IE_DOT11_DTIM_PERIOD		,0x1004, -1);	/* mapped to cfgInvalid in FW150 */
+DEF_IE(1xx_IE_DOT11_SHORT_RETRY_LIMIT	,0x1005, 0x01);
+DEF_IE(1xx_IE_DOT11_LONG_RETRY_LIMIT	,0x1006, 0x01);
+DEF_IE(100_IE_DOT11_WEP_DEFAULT_KEY_WRITE	,0x1007, 0x20);	/* configure default keys */
+DEF_IE(1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME	,0x1008, 0x04);
+DEF_IE(1xx_IE_DOT11_GROUP_ADDR		,0x1009, -1);
+DEF_IE(1xx_IE_DOT11_CURRENT_REG_DOMAIN	,0x100a, 0x02);
+//It's harmless to have larger struct. Use USB case always.
+DEF_IE(1xx_IE_DOT11_CURRENT_ANTENNA	,0x100b, 0x02);	/* in fact len=1 for PCI */
+DEF_IE(1xx_IE_DOT11_UNKNOWN_100C	,0x100c, -1);	/* mapped to cfgInvalid in FW150 */
+DEF_IE(1xx_IE_DOT11_TX_POWER_LEVEL	,0x100d, 0x01);
+DEF_IE(1xx_IE_DOT11_CURRENT_CCA_MODE	,0x100e, 0x02);	/* in fact len=1 for PCI */
+//USB doesn't return anything - len==0?!
+DEF_IE(100_IE_DOT11_ED_THRESHOLD	,0x100f, 0x04);
+DEF_IE(1xx_IE_DOT11_WEP_DEFAULT_KEY_SET	,0x1010, 0x01);	/* set default key ID */
+DEF_IE(100_IE_DOT11_UNKNOWN_1011	,0x1011, -1);	/* mapped to cfgInvalid in FW150 */
+DEF_IE(100_IE_DOT11_UNKNOWN_1012	,0x1012, -1);	/* mapped to cfgInvalid in FW150 */
+DEF_IE(100_IE_DOT11_UNKNOWN_1013	,0x1013, -1);	/* mapped to cfgInvalid in FW150 */
+
+#if 0
+/* Experimentally obtained on acx100, fw 1.9.8.b
+** -1 means that fw returned 'invalid IE'
+** 0200 FC00 nnnn... are test read contents: u16 type, u16 len, data
+** (AA are poison bytes marking bytes not written by fw)
+**
+** Looks like acx100 fw does not update len field (thus len=256-4=FC here)
+** A number of IEs seem to trash type,len fields
+** IEs marked 'huge' return gobs of data (no poison bytes remain)
+*/
+DEF_IE(100_IE_INVAL_00,			0x0000, -1);
+DEF_IE(100_IE_INVAL_01,			0x0001, -1);	/* IE_ACX_TIMER, len=16 on older fw */
+DEF_IE(100_IE_POWER_MGMT,		0x0002, 4);	/* 0200FC00 00040000 AAAAAAAA */
+DEF_IE(100_IE_QUEUE_CONFIG,		0x0003, 28);	/* 0300FC00 48060000 9CAD0000 0101AAAA DCB00000 E4B00000 9CAA0000 00AAAAAA */
+DEF_IE(100_IE_BLOCK_SIZE,		0x0004, 2);	/* 0400FC00 0001AAAA AAAAAAAA AAAAAAAA */
+/* write only: */
+DEF_IE(100_IE_MEMORY_CONFIG_OPTIONS,	0x0005, 20);
+DEF_IE(100_IE_RATE_FALLBACK,		0x0006, 1);	/* 0600FC00 00AAAAAA AAAAAAAA AAAAAAAA */
+/* write only: */
+DEF_IE(100_IE_WEP_OPTIONS,		0x0007, 3);
+DEF_IE(100_IE_MEMORY_MAP,		0x0008, 40);	/* huge: 0800FC00 30000000 6CA20000 70A20000... */
+/* gives INVAL on read: */
+DEF_IE(100_IE_SCAN_STATUS,		0x0009, -1);
+DEF_IE(100_IE_ASSOC_ID,			0x000a, 2);	/* huge: 0A00FC00 00000000 01040800 00000000... */
+DEF_IE(100_IE_INVAL_0B,			0x000b, -1);
+/* 'command rejected': */
+DEF_IE(100_IE_CONFIG_OPTIONS,		0x000c, -3);
+DEF_IE(100_IE_FWREV,			0x000d, 24);	/* 0D00FC00 52657620 312E392E 382E6200 AAAAAAAA AAAAAAAA 05050201 AAAAAAAA */
+DEF_IE(100_IE_FCS_ERROR_COUNT,		0x000e, 4);
+DEF_IE(100_IE_MEDIUM_USAGE,		0x000f, 8);	/* E41F0000 2D780300 FCC91300 AAAAAAAA */
+DEF_IE(100_IE_RXCONFIG,			0x0010, 4);	/* 1000FC00 00280000 AAAAAAAA AAAAAAAA */
+DEF_IE(100_IE_QUEUE_THRESH,		0x0011, 12);	/* 1100FC00 AAAAAAAA 00000000 00000000 */
+DEF_IE(100_IE_BSS_POWER_SAVE,		0x0012, 1);	/* 1200FC00 00AAAAAA AAAAAAAA AAAAAAAA */
+/* read only, variable len */
+DEF_IE(100_IE_FIRMWARE_STATISTICS,	0x0013, 256); /* 0000AC00 00000000 ... */
+DEF_IE(100_IE_INT_CONFIG,		0x0014, 20);	/* 00000000 00000000 00000000 00000000 5D74D105 00000000 AAAAAAAA AAAAAAAA */
+DEF_IE(100_IE_FEATURE_CONFIG,		0x0015, 8);	/* 1500FC00 16000000 AAAAAAAA AAAAAAAA */
+/* returns 'invalid MAC': */
+DEF_IE(100_IE_KEY_CHOOSE,		0x0016, -4);
+DEF_IE(100_IE_INVAL_17,			0x0017, -1);
+DEF_IE(100_IE_UNKNOWN_18,		0x0018, 0);	/* null len?! 1800FC00 AAAAAAAA AAAAAAAA AAAAAAAA */
+DEF_IE(100_IE_UNKNOWN_19,		0x0019, 256);	/* huge: 1900FC00 9C1F00EA FEFFFFEA FEFFFFEA... */
+DEF_IE(100_IE_INVAL_1A,			0x001A, -1);
+
+DEF_IE(100_IE_DOT11_INVAL_1000,			0x1000, -1);
+DEF_IE(100_IE_DOT11_STATION_ID,			0x1001, 6);	/* huge: 0110FC00 58B10E2F 03000000 00000000... */
+DEF_IE(100_IE_DOT11_INVAL_1002,			0x1002, -1);
+DEF_IE(100_IE_DOT11_INVAL_1003,			0x1003, -1);
+DEF_IE(100_IE_DOT11_INVAL_1004,			0x1004, -1);
+DEF_IE(100_IE_DOT11_SHORT_RETRY_LIMIT,		0x1005, 1);
+DEF_IE(100_IE_DOT11_LONG_RETRY_LIMIT,		0x1006, 1);
+/* write only: */
+DEF_IE(100_IE_DOT11_WEP_DEFAULT_KEY_WRITE,	0x1007, 32);
+DEF_IE(100_IE_DOT11_MAX_XMIT_MSDU_LIFETIME,	0x1008, 4);	/* huge: 0810FC00 00020000 F4010000 00000000... */
+/* undoc but returns something */
+DEF_IE(100_IE_DOT11_GROUP_ADDR,			0x1009, 12);	/* huge: 0910FC00 00000000 00000000 00000000... */
+DEF_IE(100_IE_DOT11_CURRENT_REG_DOMAIN,		0x100a, 1);	/* 0A10FC00 30AAAAAA AAAAAAAA AAAAAAAA */
+DEF_IE(100_IE_DOT11_CURRENT_ANTENNA,		0x100b, 1);	/* 0B10FC00 8FAAAAAA AAAAAAAA AAAAAAAA */
+DEF_IE(100_IE_DOT11_INVAL_100C,			0x100c, -1);
+DEF_IE(100_IE_DOT11_TX_POWER_LEVEL,		0x100d, 2);	/* 00000000 0100AAAA AAAAAAAA AAAAAAAA */
+DEF_IE(100_IE_DOT11_CURRENT_CCA_MODE,		0x100e, 1);	/* 0E10FC00 0DAAAAAA AAAAAAAA AAAAAAAA */
+DEF_IE(100_IE_DOT11_ED_THRESHOLD,		0x100f, 4);	/* 0F10FC00 70000000 AAAAAAAA AAAAAAAA */
+/* set default key ID  */
+DEF_IE(100_IE_DOT11_WEP_DEFAULT_KEY_SET,	0x1010, 1);	/* 1010FC00 00AAAAAA AAAAAAAA AAAAAAAA */
+DEF_IE(100_IE_DOT11_INVAL_1011,			0x1011, -1);
+DEF_IE(100_IE_DOT11_INVAL_1012,			0x1012, -1);
+DEF_IE(100_IE_DOT11_INVAL_1013,			0x1013, -1);
+DEF_IE(100_IE_DOT11_UNKNOWN_1014,		0x1014, 256);	/* huge */
+DEF_IE(100_IE_DOT11_UNKNOWN_1015,		0x1015, 256);	/* huge */
+DEF_IE(100_IE_DOT11_UNKNOWN_1016,		0x1016, 256);	/* huge */
+DEF_IE(100_IE_DOT11_UNKNOWN_1017,		0x1017, 256);	/* huge */
+DEF_IE(100_IE_DOT11_UNKNOWN_1018,		0x1018, 256);	/* huge */
+DEF_IE(100_IE_DOT11_UNKNOWN_1019,		0x1019, 256);	/* huge */
+#endif
+
+#if 0
+/* Experimentally obtained on PCI acx111 Xterasys XN-2522g, fw 1.2.1.34
+** -1 means that fw returned 'invalid IE'
+** 0400 0800 nnnn... are test read contents: u16 type, u16 len, data
+** (AA are poison bytes marking bytes not written by fw)
+**
+** Looks like acx111 fw reports real len!
+*/
+DEF_IE(111_IE_INVAL_00,			0x0000, -1);
+DEF_IE(111_IE_INVAL_01,			0x0001, -1);
+DEF_IE(111_IE_POWER_MGMT,		0x0002, 12);
+/* write only, variable len: 12 + rxqueue_cnt*8 + txqueue_cnt*4: */
+DEF_IE(111_IE_MEMORY_CONFIG,		0x0003, 24);
+DEF_IE(111_IE_BLOCK_SIZE,		0x0004, 8); /* 04000800 AA00AAAA AAAAAAAA */
+/* variable len: 8 + rxqueue_cnt*8 + txqueue_cnt*8: */
+DEF_IE(111_IE_QUEUE_HEAD,		0x0005, 24);
+DEF_IE(111_IE_RATE_FALLBACK,		0x0006, 1);
+/* acx100 name:WEP_OPTIONS */
+/* said to have len:1 (not true, actually returns 12 bytes): */
+DEF_IE(111_IE_RADIO_BAND,		0x0007, 12); /* 07000C00 AAAA1F00 FF03AAAA AAAAAAAA */
+DEF_IE(111_IE_MEMORY_MAP,		0x0008, 48);
+/* said to have len:4, but gives INVAL on read: */
+DEF_IE(111_IE_SCAN_STATUS,		0x0009, -1);
+DEF_IE(111_IE_ASSOC_ID,			0x000a, 2);
+/* write only, len is not known: */
+DEF_IE(111_IE_UNKNOWN_0B,		0x000b, 0);
+/* read only, variable len. I see 67 byte reads: */
+DEF_IE(111_IE_CONFIG_OPTIONS,		0x000c, 67); /* 0C004300 01160500 ... */
+DEF_IE(111_IE_FWREV,			0x000d, 24);
+DEF_IE(111_IE_FCS_ERROR_COUNT,		0x000e, 4);
+DEF_IE(111_IE_MEDIUM_USAGE,		0x000f, 8);
+DEF_IE(111_IE_RXCONFIG,			0x0010, 4);
+DEF_IE(111_IE_QUEUE_THRESH,		0x0011, 12);
+DEF_IE(111_IE_BSS_POWER_SAVE,		0x0012, 1);
+/* read only, variable len. I see 240 byte reads: */
+DEF_IE(111_IE_FIRMWARE_STATISTICS,	0x0013, 240); /* 1300F000 00000000 ... */
+/* said to have len=17. looks like fw pads it to 20: */
+DEF_IE(111_IE_INT_CONFIG,		0x0014, 20); /* 14001400 00000000 00000000 00000000 00000000 00000000 */
+DEF_IE(111_IE_FEATURE_CONFIG,		0x0015, 8);
+/* said to be name:KEY_INDICATOR, len:4, but gives INVAL on read: */
+DEF_IE(111_IE_KEY_CHOOSE,		0x0016, -1);
+/* said to have len:4, but in fact returns 8: */
+DEF_IE(111_IE_MAX_USB_XFR,		0x0017, 8); /* 17000800 00014000 00000000 */
+DEF_IE(111_IE_INVAL_18,			0x0018, -1);
+DEF_IE(111_IE_INVAL_19,			0x0019, -1);
+/* undoc but returns something: */
+/* huh, fw indicates len=20 but uses 4 more bytes in buffer??? */
+DEF_IE(111_IE_UNKNOWN_1A,		0x001A, 20); /* 1A001400 AA00AAAA 0000020F FF030000 00020000 00000007 04000000 */
+
+DEF_IE(111_IE_DOT11_INVAL_1000,			0x1000, -1);
+DEF_IE(111_IE_DOT11_STATION_ID,			0x1001, 6);
+DEF_IE(111_IE_DOT11_FRAG_THRESH,		0x1002, 2);
+/* acx100 only? gives INVAL on read: */
+DEF_IE(111_IE_DOT11_BEACON_PERIOD,		0x1003, -1);
+/* said to be MAX_RECV_MSDU_LIFETIME: */
+DEF_IE(111_IE_DOT11_DTIM_PERIOD,		0x1004, 4);
+DEF_IE(111_IE_DOT11_SHORT_RETRY_LIMIT,		0x1005, 1);
+DEF_IE(111_IE_DOT11_LONG_RETRY_LIMIT,		0x1006, 1);
+/* acx100 only? gives INVAL on read: */
+DEF_IE(111_IE_DOT11_WEP_DEFAULT_KEY_WRITE,	0x1007, -1);
+DEF_IE(111_IE_DOT11_MAX_XMIT_MSDU_LIFETIME,	0x1008, 4);
+/* undoc but returns something. maybe it's 2 multicast MACs to listen to? */
+DEF_IE(111_IE_DOT11_GROUP_ADDR,			0x1009, 12); /* 09100C00 00000000 00000000 00000000 */
+DEF_IE(111_IE_DOT11_CURRENT_REG_DOMAIN,		0x100a, 1);
+DEF_IE(111_IE_DOT11_CURRENT_ANTENNA,		0x100b, 2);
+DEF_IE(111_IE_DOT11_INVAL_100C,			0x100c, -1);
+DEF_IE(111_IE_DOT11_TX_POWER_LEVEL,		0x100d, 1);
+/* said to have len=1 but gives INVAL on read: */
+DEF_IE(111_IE_DOT11_CURRENT_CCA_MODE,		0x100e, -1);
+/* said to have len=4 but gives INVAL on read: */
+DEF_IE(111_IE_DOT11_ED_THRESHOLD,		0x100f, -1);
+/* set default key ID. write only: */
+DEF_IE(111_IE_DOT11_WEP_DEFAULT_KEY_SET,	0x1010, 1);
+/* undoc but returns something: */
+DEF_IE(111_IE_DOT11_UNKNOWN_1011,		0x1011, 1); /* 11100100 20 */
+DEF_IE(111_IE_DOT11_INVAL_1012,			0x1012, -1);
+DEF_IE(111_IE_DOT11_INVAL_1013,			0x1013, -1);
+#endif
+
+
+/***********************************************************************
+**Information Frames Structures
+*/
+
+/* Used in beacon frames and the like */
+#define DOT11RATEBYTE_1		(1*2)
+#define DOT11RATEBYTE_2		(2*2)
+#define DOT11RATEBYTE_5_5	(5*2+1)
+#define DOT11RATEBYTE_11	(11*2)
+#define DOT11RATEBYTE_22	(22*2)
+#define DOT11RATEBYTE_6_G	(6*2)
+#define DOT11RATEBYTE_9_G	(9*2)
+#define DOT11RATEBYTE_12_G	(12*2)
+#define DOT11RATEBYTE_18_G	(18*2)
+#define DOT11RATEBYTE_24_G	(24*2)
+#define DOT11RATEBYTE_36_G	(36*2)
+#define DOT11RATEBYTE_48_G	(48*2)
+#define DOT11RATEBYTE_54_G	(54*2)
+#define DOT11RATEBYTE_BASIC	0x80	/* flags rates included in basic rate set */
+
+
+/***********************************************************************
+** rxbuffer_t
+**
+** This is the format of rx data returned by acx
+*/
+
+/* I've hoped it's a 802.11 PHY header, but no...
+ * so far, I've seen on acx111:
+ * 0000 3a00 0000 0000 IBBS Beacons
+ * 0000 3c00 0000 0000 ESS Beacons
+ * 0000 2700 0000 0000 Probe requests
+ * --vda
+ */
+typedef struct phy_hdr {
+	u8	unknown[4] ACX_PACKED;
+	u8	acx111_unknown[4] ACX_PACKED;
+} phy_hdr_t;
+
+/* seems to be a bit similar to hfa384x_rx_frame.
+ * These fields are still not quite obvious, though.
+ * Some seem to have different meanings... */
+
+#define RXBUF_HDRSIZE 12
+#define RXBUF_BYTES_RCVD(adev, rxbuf) \
+		((le16_to_cpu((rxbuf)->mac_cnt_rcvd) & 0xfff) - (adev)->phy_header_len)
+#define RXBUF_BYTES_USED(rxbuf) \
+		((le16_to_cpu((rxbuf)->mac_cnt_rcvd) & 0xfff) + RXBUF_HDRSIZE)
+/* USBism */
+#define RXBUF_IS_TXSTAT(rxbuf) (le16_to_cpu((rxbuf)->mac_cnt_rcvd) & 0x8000)
+/*
+mac_cnt_rcvd:
+    12 bits: length of frame from control field to first byte of FCS
+    3 bits: reserved
+    1 bit: 1 = it's a tx status info, not a rx packet (USB only)
+
+mac_cnt_mblks:
+    6 bits: number of memory block used to store frame in adapter memory
+    1 bit: Traffic Indicator bit in TIM of received Beacon was set
+
+mac_status: 1 byte (bitmap):
+    7 Matching BSSID
+    6 Matching SSID
+    5 BDCST	Address 1 field is a broadcast
+    4 VBM	received beacon frame has more than one set bit (?!)
+    3 TIM Set	bit representing this station is set in TIM of received beacon
+    2 GROUP	Address 1 is a multicast
+    1 ADDR1	Address 1 matches our MAC
+    0 FCSGD	FSC is good
+
+phy_stat_baseband: 1 byte (bitmap):
+    7 Preamble		frame had a long preamble
+    6 PLCP Error	CRC16 error in PLCP header
+    5 Unsup_Mod		unsupported modulation
+    4 Selected Antenna	antenna 1 was used to receive this frame
+    3 PBCC/CCK		frame used: 1=PBCC, 0=CCK modulation
+    2 OFDM		frame used OFDM modulation
+    1 TI Protection	protection frame was detected
+    0 Reserved
+
+phy_plcp_signal: 1 byte:
+    Receive PLCP Signal field from the Baseband Processor
+
+phy_level: 1 byte:
+    receive AGC gain level (can be used to measure receive signal strength)
+
+phy_snr: 1 byte:
+    estimated noise power of equalized receive signal
+    at input of FEC decoder (can be used to measure receive signal quality)
+
+time: 4 bytes:
+    timestamp sampled from either the Access Manager TSF counter
+    or free-running microsecond counter when the MAC receives
+    first byte of PLCP header.
+*/
+
+typedef struct rxbuffer {
+	u16	mac_cnt_rcvd ACX_PACKED;	/* only 12 bits are len! (0xfff) */
+	u8	mac_cnt_mblks ACX_PACKED;
+	u8	mac_status ACX_PACKED;
+	u8	phy_stat_baseband ACX_PACKED;	/* bit 0x80: used LNA (Low-Noise Amplifier) */
+	u8	phy_plcp_signal ACX_PACKED;
+	u8	phy_level ACX_PACKED;		/* PHY stat */
+	u8	phy_snr ACX_PACKED;		/* PHY stat */
+	u32	time ACX_PACKED;		/* timestamp upon MAC rcv first byte */
+/* 4-byte (acx100) or 8-byte (acx111) phy header will be here
+** if RX_CFG1_INCLUDE_PHY_HDR is in effect:
+**	phy_hdr_t phy			*/
+	wlan_hdr_a3_t hdr_a3 ACX_PACKED;
+	/* maximally sized data part of wlan packet */
+	u8	data_a3[WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_HDR_A3_LEN] ACX_PACKED;
+	/* can add hdr/data_a4 if needed */
+} rxbuffer_t;
+
+
+/*--- Firmware statistics ----------------------------------------------------*/
+typedef struct fw_stats {
+	u32	val0x0 ACX_PACKED;		/* hdr; */
+	u32	tx_desc_of ACX_PACKED;
+	u32	rx_oom ACX_PACKED;
+	u32	rx_hdr_of ACX_PACKED;
+	u32	rx_hdr_use_next ACX_PACKED;
+	u32	rx_dropped_frame ACX_PACKED;
+	u32	rx_frame_ptr_err ACX_PACKED;
+	u32	rx_xfr_hint_trig ACX_PACKED;
+
+	u32	rx_dma_req ACX_PACKED;
+	u32	rx_dma_err ACX_PACKED;
+	u32	tx_dma_req ACX_PACKED;
+	u32	tx_dma_err ACX_PACKED;
+
+	u32	cmd_cplt ACX_PACKED;
+	u32	fiq ACX_PACKED;
+	u32	rx_hdrs ACX_PACKED;
+	u32	rx_cmplt ACX_PACKED;
+	u32	rx_mem_of ACX_PACKED;
+	u32	rx_rdys ACX_PACKED;
+	u32	irqs ACX_PACKED;
+	u32	acx_trans_procs ACX_PACKED;
+	u32	decrypt_done ACX_PACKED;
+	u32	dma_0_done ACX_PACKED;
+	u32	dma_1_done ACX_PACKED;
+	u32	tx_exch_complet ACX_PACKED;
+	u32	commands ACX_PACKED;
+	u32	acx_rx_procs ACX_PACKED;
+	u32	hw_pm_mode_changes ACX_PACKED;
+	u32	host_acks ACX_PACKED;
+	u32	pci_pm ACX_PACKED;
+	u32	acm_wakeups ACX_PACKED;
+
+	u32	wep_key_count ACX_PACKED;
+	u32	wep_default_key_count ACX_PACKED;
+	u32	dot11_def_key_mib ACX_PACKED;
+	u32	wep_key_not_found ACX_PACKED;
+	u32	wep_decrypt_fail ACX_PACKED;
+} fw_stats_t;
+
+/* Firmware version struct */
+
+typedef struct fw_ver {
+	u16	cmd ACX_PACKED;
+	u16	size ACX_PACKED;
+	char	fw_id[20] ACX_PACKED;
+	u32	hw_id ACX_PACKED;
+} fw_ver_t;
+
+#define FW_ID_SIZE 20
+
+
+/*--- WEP stuff --------------------------------------------------------------*/
+#define DOT11_MAX_DEFAULT_WEP_KEYS	4
+
+/* non-firmware struct, no packing necessary */
+typedef struct wep_key {
+	size_t	size; /* most often used member first */
+	u8	index;
+	u8	key[29];
+	u16	strange_filler;
+} wep_key_t;			/* size = 264 bytes (33*8) */
+/* FIXME: We don't have size 264! Or is there 2 bytes beyond the key
+ * (strange_filler)? */
+
+/* non-firmware struct, no packing necessary */
+typedef struct key_struct {
+	u8	addr[ETH_ALEN];	/* 0x00 */
+	u16	filler1;	/* 0x06 */
+	u32	filler2;	/* 0x08 */
+	u32	index;		/* 0x0c */
+	u16	len;		/* 0x10 */
+	u8	key[29];	/* 0x12; is this long enough??? */
+} key_struct_t;			/* size = 276. FIXME: where is the remaining space?? */
+
+
+/*--- Client (peer) info -----------------------------------------------------*/
+/* adev->sta_list[] is used for:
+** accumulating and processing of scan results
+** keeping client info in AP mode
+** keeping AP info in STA mode (AP is the only one 'client')
+** keeping peer info in ad-hoc mode
+** non-firmware struct --> no packing necessary */
+enum {
+	CLIENT_EMPTY_SLOT_0 = 0,
+	CLIENT_EXIST_1 = 1,
+	CLIENT_AUTHENTICATED_2 = 2,
+	CLIENT_ASSOCIATED_3 = 3,
+	CLIENT_JOIN_CANDIDATE = 4
+};
+struct client {
+	/* most frequent access first */
+	u8	used;			/* misnamed, more like 'status' */
+	struct client*	next;
+	unsigned long	mtime;		/* last time we heard it, in jiffies */
+	size_t	essid_len;		/* length of ESSID (without '\0') */
+	u32	sir;			/* Standard IR */
+	u32	snr;			/* Signal to Noise Ratio */
+	u16	aid;			/* association ID */
+	u16	seq;			/* from client's auth req */
+	u16	auth_alg;		/* from client's auth req */
+	u16	cap_info;		/* from client's assoc req */
+	u16	rate_cap;		/* what client supports (all rates) */
+	u16	rate_bas;		/* what client supports (basic rates) */
+	u16	rate_cfg;		/* what is allowed (by iwconfig etc) */
+	u16	rate_cur;		/* currently used rate mask */
+	u8	rate_100;		/* currently used rate byte (acx100 only) */
+	u8	address[ETH_ALEN];
+	u8	bssid[ETH_ALEN];	/* ad-hoc hosts can have bssid != mac */
+	u8	channel;
+	u8	auth_step;
+	u8	ignore_count;
+	u8	fallback_count;
+	u8	stepup_count;
+	char	essid[IW_ESSID_MAX_SIZE + 1];	/* ESSID and trailing '\0'  */
+/* FIXME: this one is too damn big */
+	char	challenge_text[WLAN_CHALLENGE_LEN];
+};
+
+
+/***********************************************************************
+** Hardware structures
+*/
+
+/* An opaque typesafe helper type
+ *
+ * Some hardware fields are actually pointers,
+ * but they have to remain u32, since using ptr instead
+ * (8 bytes on 64bit systems!) would disrupt the fixed descriptor
+ * format the acx firmware expects in the non-user area.
+ * Since we cannot cram an 8 byte ptr into 4 bytes, we need to
+ * enforce that pointed to data remains in low memory
+ * (address value needs to fit in 4 bytes) on 64bit systems.
+ *
+ * This is easy to get wrong, thus we are using a small struct
+ * and special macros to access it. Macros will check for
+ * attempts to overflow an acx_ptr with value > 0xffffffff.
+ *
+ * Attempts to use acx_ptr without macros result in compile-time errors */
+
+typedef struct {
+	u32	v ACX_PACKED;
+} acx_ptr;
+
+#if ACX_DEBUG
+#define CHECK32(n) BUG_ON(sizeof(n)>4 && (long)(n)>0xffffff00)
+#else
+#define CHECK32(n) ((void)0)
+#endif
+
+/* acx_ptr <-> integer conversion */
+#define cpu2acx(n) ({ CHECK32(n); ((acx_ptr){ .v = cpu_to_le32(n) }); })
+#define acx2cpu(a) (le32_to_cpu(a.v))
+
+/* acx_ptr <-> pointer conversion */
+#define ptr2acx(p) ({ CHECK32(p); ((acx_ptr){ .v = cpu_to_le32((u32)(long)(p)) }); })
+#define acx2ptr(a) ((void*)le32_to_cpu(a.v))
+
+/* Values for rate field (acx100 only) */
+#define RATE100_1		10
+#define RATE100_2		20
+#define RATE100_5		55
+#define RATE100_11		110
+#define RATE100_22		220
+/* This bit denotes use of PBCC:
+** (PBCC encoding is usable with 11 and 22 Mbps speeds only) */
+#define RATE100_PBCC511		0x80
+
+/* Bit values for rate111 field */
+#define RATE111_1		0x0001	/* DBPSK */
+#define RATE111_2		0x0002	/* DQPSK */
+#define RATE111_5		0x0004	/* CCK or PBCC */
+#define RATE111_6		0x0008	/* CCK-OFDM or OFDM */
+#define RATE111_9		0x0010	/* CCK-OFDM or OFDM */
+#define RATE111_11		0x0020	/* CCK or PBCC */
+#define RATE111_12		0x0040	/* CCK-OFDM or OFDM */
+#define RATE111_18		0x0080	/* CCK-OFDM or OFDM */
+#define RATE111_22		0x0100	/* PBCC */
+#define RATE111_24		0x0200	/* CCK-OFDM or OFDM */
+#define RATE111_36		0x0400	/* CCK-OFDM or OFDM */
+#define RATE111_48		0x0800	/* CCK-OFDM or OFDM */
+#define RATE111_54		0x1000	/* CCK-OFDM or OFDM */
+#define RATE111_RESERVED	0x2000
+#define RATE111_PBCC511		0x4000  /* PBCC mod at 5.5 or 11Mbit (else CCK) */
+#define RATE111_SHORTPRE	0x8000  /* short preamble */
+/* Special 'try everything' value */
+#define RATE111_ALL		0x1fff
+/* These bits denote acx100 compatible settings */
+#define RATE111_ACX100_COMPAT	0x0127
+/* These bits denote 802.11b compatible settings */
+#define RATE111_80211B_COMPAT	0x0027
+
+/* Descriptor Ctl field bits
+ * init value is 0x8e, "idle" value is 0x82 (in idle tx descs)
+ */
+#define DESC_CTL_SHORT_PREAMBLE	0x01	/* preamble type: 0 = long; 1 = short */
+#define DESC_CTL_FIRSTFRAG	0x02	/* this is the 1st frag of the frame */
+#define DESC_CTL_AUTODMA	0x04
+#define DESC_CTL_RECLAIM	0x08	/* ready to reuse */
+#define DESC_CTL_HOSTDONE	0x20	/* host has finished processing */
+#define DESC_CTL_ACXDONE	0x40	/* acx has finished processing */
+/* host owns the desc [has to be released last, AFTER modifying all other desc fields!] */
+#define DESC_CTL_HOSTOWN	0x80
+#define	DESC_CTL_ACXDONE_HOSTOWN (DESC_CTL_ACXDONE | DESC_CTL_HOSTOWN)
+
+/* Descriptor Status field
+ */
+#define	DESC_STATUS_FULL	(1 << 31)
+
+/* NB: some bits may be interesting for Monitor mode tx (aka Raw tx): */
+#define DESC_CTL2_SEQ		0x01	/* don't increase sequence field */
+#define DESC_CTL2_FCS		0x02	/* don't add the FCS */
+#define DESC_CTL2_MORE_FRAG	0x04
+#define DESC_CTL2_RETRY		0x08	/* don't increase retry field */
+#define DESC_CTL2_POWER		0x10	/* don't increase power mgmt. field */
+#define DESC_CTL2_RTS		0x20	/* do RTS/CTS magic before sending */
+#define DESC_CTL2_WEP		0x40	/* encrypt this frame */
+#define DESC_CTL2_DUR		0x80	/* don't increase duration field */
+
+/***********************************************************************
+** PCI structures
+*/
+/* IRQ Constants
+** (outside of "#ifdef PCI" because USB (mis)uses HOST_INT_SCAN_COMPLETE) */
+#define HOST_INT_RX_DATA	0x0001
+#define HOST_INT_TX_COMPLETE	0x0002
+#define HOST_INT_TX_XFER	0x0004
+#define HOST_INT_RX_COMPLETE	0x0008
+#define HOST_INT_DTIM		0x0010
+#define HOST_INT_BEACON		0x0020
+#define HOST_INT_TIMER		0x0040
+#define HOST_INT_KEY_NOT_FOUND	0x0080
+#define HOST_INT_IV_ICV_FAILURE	0x0100
+#define HOST_INT_CMD_COMPLETE	0x0200
+#define HOST_INT_INFO		0x0400
+#define HOST_INT_OVERFLOW	0x0800
+#define HOST_INT_PROCESS_ERROR	0x1000
+#define HOST_INT_SCAN_COMPLETE	0x2000
+#define HOST_INT_FCS_THRESHOLD	0x4000
+#define HOST_INT_UNKNOWN	0x8000
+
+/* Outside of "#ifdef PCI" because USB needs to know sizeof()
+** of txdesc and rxdesc: */
+struct txdesc {
+	acx_ptr	pNextDesc ACX_PACKED;	/* pointer to next txdesc */
+	acx_ptr	HostMemPtr ACX_PACKED;			/* 0x04 */
+	acx_ptr	AcxMemPtr ACX_PACKED;			/* 0x08 */
+	u32	tx_time ACX_PACKED;			/* 0x0c */
+	u16	total_length ACX_PACKED;		/* 0x10 */
+	u16	Reserved ACX_PACKED;			/* 0x12 */
+
+/* The following 16 bytes do not change when acx100 owns the descriptor */
+/* BUG: fw clears last byte of this area which is supposedly reserved
+** for driver use. amd64 blew up. We dare not use it now */
+	u32	dummy[4] ACX_PACKED;
+
+	u8	Ctl_8 ACX_PACKED;			/* 0x24, 8bit value */
+	u8	Ctl2_8 ACX_PACKED;			/* 0x25, 8bit value */
+	u8	error ACX_PACKED;			/* 0x26 */
+	u8	ack_failures ACX_PACKED;		/* 0x27 */
+	u8	rts_failures ACX_PACKED;		/* 0x28 */
+	u8	rts_ok ACX_PACKED;			/* 0x29 */
+	union {
+		struct {
+			u8	rate ACX_PACKED;	/* 0x2a */
+			u8	queue_ctrl ACX_PACKED;	/* 0x2b */
+		} r1 ACX_PACKED;
+		struct {
+			u16	rate111 ACX_PACKED;	/* 0x2a */
+		} r2 ACX_PACKED;
+	} u ACX_PACKED;
+	u32	queue_info ACX_PACKED;			/* 0x2c (acx100, reserved on acx111) */
+};		/* size : 48 = 0x30 */
+/* NB: acx111 txdesc structure is 4 byte larger */
+/* All these 4 extra bytes are reserved. tx alloc code takes them into account */
+
+struct rxdesc {
+	acx_ptr	pNextDesc ACX_PACKED;			/* 0x00 */
+	acx_ptr	HostMemPtr ACX_PACKED;			/* 0x04 */
+	acx_ptr	ACXMemPtr ACX_PACKED;			/* 0x08 */
+	u32	rx_time ACX_PACKED;			/* 0x0c */
+	u16	total_length ACX_PACKED;		/* 0x10 */
+	u16	WEP_length ACX_PACKED;			/* 0x12 */
+	u32	WEP_ofs ACX_PACKED;			/* 0x14 */
+
+/* the following 16 bytes do not change when acx100 owns the descriptor */
+	u8	driverWorkspace[16] ACX_PACKED;		/* 0x18 */
+
+	u8	Ctl_8 ACX_PACKED;
+	u8	rate ACX_PACKED;
+	u8	error ACX_PACKED;
+	u8	SNR ACX_PACKED;				/* Signal-to-Noise Ratio */
+	u8	RxLevel ACX_PACKED;
+	u8	queue_ctrl ACX_PACKED;
+	u16	unknown ACX_PACKED;
+	u32	unknown2 ACX_PACKED;
+};		/* size 52 = 0x34 */
+
+#ifdef ACX_PCI
+
+/* Register I/O offsets */
+#define ACX100_EEPROM_ID_OFFSET	0x380
+
+/* please add further ACX hardware register definitions only when
+   it turns out you need them in the driver, and please try to use
+   firmware functionality instead, since using direct I/O access instead
+   of letting the firmware do it might confuse the firmware's state
+   machine */
+
+/* ***** ABSOLUTELY ALWAYS KEEP OFFSETS IN SYNC WITH THE INITIALIZATION
+** OF THE I/O ARRAYS!!!! (grep for '^IO_ACX') ***** */
+enum {
+	IO_ACX_SOFT_RESET = 0,
+
+	IO_ACX_SLV_MEM_ADDR,
+	IO_ACX_SLV_MEM_DATA,
+	IO_ACX_SLV_MEM_CTL,
+	IO_ACX_SLV_END_CTL,
+
+	IO_ACX_FEMR,		/* Function Event Mask */
+
+	IO_ACX_INT_TRIG,
+	IO_ACX_IRQ_MASK,
+	IO_ACX_IRQ_STATUS_NON_DES,
+	IO_ACX_IRQ_STATUS_CLEAR, /* CLEAR = clear on read */
+	IO_ACX_IRQ_ACK,
+	IO_ACX_HINT_TRIG,
+
+	IO_ACX_ENABLE,
+
+	IO_ACX_EEPROM_CTL,
+	IO_ACX_EEPROM_ADDR,
+	IO_ACX_EEPROM_DATA,
+	IO_ACX_EEPROM_CFG,
+
+	IO_ACX_PHY_ADDR,
+	IO_ACX_PHY_DATA,
+	IO_ACX_PHY_CTL,
+
+	IO_ACX_GPIO_OE,
+
+	IO_ACX_GPIO_OUT,
+
+	IO_ACX_CMD_MAILBOX_OFFS,
+	IO_ACX_INFO_MAILBOX_OFFS,
+	IO_ACX_EEPROM_INFORMATION,
+
+	IO_ACX_EE_START,
+	IO_ACX_SOR_CFG,
+	IO_ACX_ECPU_CTRL
+};
+/* ***** ABSOLUTELY ALWAYS KEEP OFFSETS IN SYNC WITH THE INITIALIZATION
+** OF THE I/O ARRAYS!!!! (grep for '^IO_ACX') ***** */
+
+/* Values for IO_ACX_INT_TRIG register: */
+/* inform hw that rxdesc in queue needs processing */
+#define INT_TRIG_RXPRC		0x08
+/* inform hw that txdesc in queue needs processing */
+#define INT_TRIG_TXPRC		0x04
+/* ack that we received info from info mailbox */
+#define INT_TRIG_INFOACK	0x02
+/* inform hw that we have filled command mailbox */
+#define INT_TRIG_CMD		0x01
+
+struct txhostdesc {
+	acx_ptr	data_phy ACX_PACKED;			/* 0x00 [u8 *] */
+	u16	data_offset ACX_PACKED;			/* 0x04 */
+	u16	reserved ACX_PACKED;			/* 0x06 */
+	u16	Ctl_16 ACX_PACKED;	/* 16bit value, endianness!! */
+	u16	length ACX_PACKED;			/* 0x0a */
+	acx_ptr	desc_phy_next ACX_PACKED;		/* 0x0c [txhostdesc *] */
+	acx_ptr	pNext ACX_PACKED;			/* 0x10 [txhostdesc *] */
+	u32	Status ACX_PACKED;			/* 0x14, unused on Tx */
+/* From here on you can use this area as you want (variable length, too!) */
+	u8	*data ACX_PACKED;
+};
+
+struct rxhostdesc {
+	acx_ptr	data_phy ACX_PACKED;			/* 0x00 [rxbuffer_t *] */
+	u16	data_offset ACX_PACKED;			/* 0x04 */
+	u16	reserved ACX_PACKED;			/* 0x06 */
+	u16	Ctl_16 ACX_PACKED;			/* 0x08; 16bit value, endianness!! */
+	u16	length ACX_PACKED;			/* 0x0a */
+	acx_ptr	desc_phy_next ACX_PACKED;		/* 0x0c [rxhostdesc_t *] */
+	acx_ptr	pNext ACX_PACKED;			/* 0x10 [rxhostdesc_t *] */
+	u32	Status ACX_PACKED;			/* 0x14 */
+/* From here on you can use this area as you want (variable length, too!) */
+	rxbuffer_t *data ACX_PACKED;
+};
+
+#endif /* ACX_PCI */
+
+/***********************************************************************
+** USB structures and constants
+*/
+#ifdef ACX_USB
+
+/* Used for usb_txbuffer.desc field */
+#define USB_TXBUF_TXDESC	0xA
+/* Size of header (everything up to data[]) */
+#define USB_TXBUF_HDRSIZE	14
+typedef struct usb_txbuffer {
+	u16	desc ACX_PACKED;
+	u16	mpdu_len ACX_PACKED;
+	u8	queue_index ACX_PACKED;
+	u8	rate ACX_PACKED;
+	u32	hostdata ACX_PACKED;
+	u8	ctrl1 ACX_PACKED;
+	u8	ctrl2 ACX_PACKED;
+	u16	data_len ACX_PACKED;
+	/* wlan packet content is placed here: */
+	u8	data[WLAN_A4FR_MAXLEN_WEP_FCS] ACX_PACKED;
+} usb_txbuffer_t;
+
+/* USB returns either rx packets (see rxbuffer) or
+** these "tx status" structs: */
+typedef struct usb_txstatus {
+	u16	mac_cnt_rcvd ACX_PACKED;	/* only 12 bits are len! (0xfff) */
+	u8	queue_index ACX_PACKED;
+	u8	mac_status ACX_PACKED;		/* seen 0x20 on tx failure */
+	u32	hostdata ACX_PACKED;
+	u8	rate ACX_PACKED;
+	u8	ack_failures ACX_PACKED;
+	u8	rts_failures ACX_PACKED;
+	u8	rts_ok ACX_PACKED;
+} usb_txstatus_t;
+
+typedef struct usb_tx {
+	unsigned	busy:1;
+	struct urb	*urb;
+	acx_device_t	*adev;
+	/* actual USB bulk output data block is here: */
+	usb_txbuffer_t	bulkout;
+} usb_tx_t;
+
+struct usb_rx_plain {
+	unsigned	busy:1;
+	struct urb	*urb;
+	acx_device_t	*adev;
+	rxbuffer_t	bulkin;
+};
+
+typedef struct usb_rx {
+	unsigned	busy:1;
+	struct urb	*urb;
+	acx_device_t	*adev;
+	rxbuffer_t	bulkin;
+ /* Make entire structure 4k. Report if it breaks something. */
+	u8 padding[4*1024 - sizeof(struct usb_rx_plain)];
+} usb_rx_t;
+#endif /* ACX_USB */
+
+
+/* Config Option structs */
+
+typedef struct co_antennas {
+	u8	type ACX_PACKED;
+	u8	len ACX_PACKED;
+	u8	list[2] ACX_PACKED;
+} co_antennas_t;
+
+typedef struct co_powerlevels {
+	u8	type ACX_PACKED;
+	u8	len ACX_PACKED;
+	u16	list[8] ACX_PACKED;
+} co_powerlevels_t;
+
+typedef struct co_datarates {
+	u8	type ACX_PACKED;
+	u8	len ACX_PACKED;
+	u8	list[8] ACX_PACKED;
+} co_datarates_t;
+
+typedef struct co_domains {
+	u8	type ACX_PACKED;
+	u8	len ACX_PACKED;
+	u8	list[6] ACX_PACKED;
+} co_domains_t;
+
+typedef struct co_product_id {
+	u8	type ACX_PACKED;
+	u8	len ACX_PACKED;
+	u8	list[128] ACX_PACKED;
+} co_product_id_t;
+
+typedef struct co_manuf_id {
+	u8	type ACX_PACKED;
+	u8	len ACX_PACKED;
+	u8	list[128] ACX_PACKED;
+} co_manuf_t;
+
+typedef struct co_fixed {
+	char	NVSv[8] ACX_PACKED;
+/*	u16	NVS_vendor_offs;	ACX111-only */
+/*	u16	unknown;		ACX111-only */
+	u8	MAC[6] ACX_PACKED;	/* ACX100-only */
+	u16	probe_delay ACX_PACKED;	/* ACX100-only */
+	u32	eof_memory ACX_PACKED;
+	u8	dot11CCAModes ACX_PACKED;
+	u8	dot11Diversity ACX_PACKED;
+	u8	dot11ShortPreambleOption ACX_PACKED;
+	u8	dot11PBCCOption ACX_PACKED;
+	u8	dot11ChannelAgility ACX_PACKED;
+	u8	dot11PhyType ACX_PACKED; /* FIXME: does 802.11 call it "dot11PHYType"? */
+	u8	dot11TempType ACX_PACKED;
+	u8	table_count ACX_PACKED;
+} co_fixed_t;
+
+typedef struct acx111_ie_configoption {
+	u16			type ACX_PACKED;
+	u16			len ACX_PACKED;
+/* Do not access below members directly, they are in fact variable length */
+	co_fixed_t		fixed ACX_PACKED;
+	co_antennas_t		antennas ACX_PACKED;
+	co_powerlevels_t	power_levels ACX_PACKED;
+	co_datarates_t		data_rates ACX_PACKED;
+	co_domains_t		domains ACX_PACKED;
+	co_product_id_t		product_id ACX_PACKED;
+	co_manuf_t		manufacturer ACX_PACKED;
+	u8			_padding[4];
+} acx111_ie_configoption_t;
+
+
+/***********************************************************************
+** Main acx per-device data structure
+*/
+#define ACX_STATE_FW_LOADED	0x01
+#define ACX_STATE_IFACE_UP	0x02
+
+/* MAC mode (BSS type) defines
+ * Note that they shouldn't be redefined, since they are also used
+ * during communication with firmware */
+#define ACX_MODE_0_ADHOC	0
+#define ACX_MODE_1_UNUSED	1
+#define ACX_MODE_2_STA		2
+#define ACX_MODE_3_AP		3
+/* These are our own inventions. Sending these to firmware
+** makes it stop emitting beacons, which is exactly what we want
+** for these modes */
+#define ACX_MODE_MONITOR	0xfe
+#define ACX_MODE_OFF		0xff
+/* 'Submode': identifies exact status of ADHOC/STA host */
+#define ACX_STATUS_0_STOPPED		0
+#define ACX_STATUS_1_SCANNING		1
+#define ACX_STATUS_2_WAIT_AUTH		2
+#define ACX_STATUS_3_AUTHENTICATED	3
+#define ACX_STATUS_4_ASSOCIATED		4
+
+/* FIXME: this should be named something like struct acx_priv (typedef'd to
+ * acx_priv_t) */
+
+/* non-firmware struct, no packing necessary */
+struct acx_device {
+	/* most frequent accesses first (dereferencing and cache line!) */
+
+	/*** Locking ***/
+	struct semaphore	sem;
+	spinlock_t		lock;
+#if defined(PARANOID_LOCKING) /* Lock debugging */
+	const char		*last_sem;
+	const char		*last_lock;
+	unsigned long		sem_time;
+	unsigned long		lock_time;
+#endif
+
+	/*** Device chain ***/
+	struct acx_device	*next;		/* link for list of devices */
+
+	/*** Linux network device ***/
+	struct net_device	*ndev;		/* pointer to linux netdevice */
+	struct net_device	*prev_nd;	/* FIXME: We should not chain via our
+						 * private struct acx_device _and_
+						 * the struct net_device */
+	/*** Device statistics ***/
+	struct net_device_stats	stats;		/* net device statistics */
+#ifdef WIRELESS_EXT
+	struct iw_statistics	wstats;		/* wireless statistics */
+#endif
+	/*** Power managment ***/
+	struct pm_dev		*pm;		/* PM crap */
+
+	/*** Management timer ***/
+	struct timer_list	mgmt_timer;
+
+	/*** Hardware identification ***/
+	const char		*chip_name;
+	u8			dev_type;
+	u8			chip_type;
+	u8			form_factor;
+	u8			radio_type;
+	u8			eeprom_version;
+
+	/*** Config retrieved from EEPROM ***/
+	char			cfgopt_NVSv[8];
+	u16			cfgopt_NVS_vendor_offs;
+	u8			cfgopt_MAC[6];
+	u16			cfgopt_probe_delay;
+	u32			cfgopt_eof_memory;
+	u8			cfgopt_dot11CCAModes;
+	u8			cfgopt_dot11Diversity;
+	u8			cfgopt_dot11ShortPreambleOption;
+	u8			cfgopt_dot11PBCCOption;
+	u8			cfgopt_dot11ChannelAgility;
+	u8			cfgopt_dot11PhyType;
+	u8			cfgopt_dot11TempType;
+	co_antennas_t		cfgopt_antennas;
+	co_powerlevels_t	cfgopt_power_levels;
+	co_datarates_t		cfgopt_data_rates;
+	co_domains_t		cfgopt_domains;
+	co_product_id_t		cfgopt_product_id;
+	co_manuf_t		cfgopt_manufacturer;
+
+	/*** Firmware identification ***/
+	char		firmware_version[FW_ID_SIZE+1];
+	u32		firmware_numver;
+	u32		firmware_id;
+	const u16	*ie_len;
+	const u16	*ie_len_dot11;
+
+	/*** Device state ***/
+	u16		dev_state_mask;
+	u8		led_power;		/* power LED status */
+	u32		get_mask;		/* mask of settings to fetch from the card */
+	u32		set_mask;		/* mask of settings to write to the card */
+
+	/* Barely used in USB case */
+	u16		irq_status;
+
+	u8		after_interrupt_jobs;	/* mini job list for doing actions after an interrupt occurred */
+	WORK_STRUCT	after_interrupt_task;	/* our task for after interrupt actions */
+
+	/*** scanning ***/
+	u16		scan_count;		/* number of times to do channel scan */
+	u8		scan_mode;		/* 0 == active, 1 == passive, 2 == background */
+	u8		scan_rate;
+	u16		scan_duration;
+	u16		scan_probe_delay;
+#if WIRELESS_EXT > 15
+	struct iw_spy_data	spy_data;	/* FIXME: needs to be implemented! */
+#endif
+
+	/*** Wireless network settings ***/
+	/* copy of the device address (ifconfig hw ether) that we actually use
+	** for 802.11; copied over from the network device's MAC address
+	** (ifconfig) when it makes sense only */
+	u8		dev_addr[MAX_ADDR_LEN];
+	u8		bssid[ETH_ALEN];	/* the BSSID after having joined */
+	u8		ap[ETH_ALEN];		/* The AP we want, FF:FF:FF:FF:FF:FF is any */
+	u16		aid;			/* The Association ID sent from the AP / last used AID if we're an AP */
+	u16		mode;			/* mode from iwconfig */
+	int		monitor_type;		/* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_PRISM */
+	u16		status;			/* 802.11 association status */
+	u8		essid_active;		/* specific ESSID active, or select any? */
+	u8		essid_len;		/* to avoid dozens of strlen() */
+	/* INCLUDES \0 termination for easy printf - but many places
+	** simply want the string data memcpy'd plus a length indicator!
+	** Keep that in mind... */
+	char		essid[IW_ESSID_MAX_SIZE+1];
+	/* essid we are going to use for association, in case of "essid 'any'"
+	** and in case of hidden ESSID (use configured ESSID then) */
+	char		essid_for_assoc[IW_ESSID_MAX_SIZE+1];
+	char		nick[IW_ESSID_MAX_SIZE+1]; /* see essid! */
+	u8		channel;
+	u8		reg_dom_id;		/* reg domain setting */
+	u16		reg_dom_chanmask;
+	u16		auth_or_assoc_retries;
+	u16		scan_retries;
+	unsigned long	scan_start;		/* YES, jiffies is defined as "unsigned long" */
+
+	/* stations known to us (if we're an ap) */
+	client_t	sta_list[32];		/* tab is larger than list, so that */
+	client_t	*sta_hash_tab[64];	/* hash collisions are not likely */
+	client_t	*ap_client;		/* this one is our AP (STA mode only) */
+
+	int		dup_count;
+	int		nondup_count;
+	unsigned long	dup_msg_expiry;
+	u16		last_seq_ctrl;		/* duplicate packet detection */
+
+	/* 802.11 power save mode */
+	u8		ps_wakeup_cfg;
+	u8		ps_listen_interval;
+	u8		ps_options;
+	u8		ps_hangover_period;
+	u32		ps_enhanced_transition_time;
+	u32		ps_beacon_rx_time;
+
+	/*** PHY settings ***/
+	u8		fallback_threshold;
+	u8		stepup_threshold;
+	u16		rate_basic;
+	u16		rate_oper;
+	u16		rate_bcast;
+	u16		rate_bcast100;
+	u8		rate_auto;		/* false if "iwconfig rate N" (WITHOUT 'auto'!) */
+	u8		preamble_mode;		/* 0 == Long Preamble, 1 == Short, 2 == Auto */
+	u8		preamble_cur;
+
+	u8		tx_disabled;
+	u8		tx_level_dbm;
+	/* u8		tx_level_val; */
+	/* u8		tx_level_auto;		whether to do automatic power adjustment */
+
+	unsigned long	recalib_time_last_success;
+	unsigned long	recalib_time_last_attempt;
+	int		recalib_failure_count;
+	int		recalib_msg_ratelimit;
+	int		retry_errors_msg_ratelimit;
+
+	unsigned long	brange_time_last_state_change;	/* time the power LED was last changed */
+	u8		brange_last_state;	/* last state of the LED */
+	u8		brange_max_quality;	/* maximum quality that equates to full speed */
+
+	u8		sensitivity;
+	u8		antenna;		/* antenna settings */
+	u8		ed_threshold;		/* energy detect threshold */
+	u8		cca;			/* clear channel assessment */
+
+	u16		rts_threshold;
+	u16		frag_threshold;
+	u32		short_retry;
+	u32		long_retry;
+	u16		msdu_lifetime;
+	u16		listen_interval;	/* given in units of beacon interval */
+	u32		beacon_interval;
+
+	u16		capabilities;
+	u8		rate_supported_len;
+	u8		rate_supported[13];
+
+	/*** Encryption settings (WEP) ***/
+	u32		auth_alg;		/* used in transmit_authen1 */
+	u8		wep_enabled;
+	u8		wep_restricted;
+	u8		wep_current_index;
+	wep_key_t	wep_keys[DOT11_MAX_DEFAULT_WEP_KEYS];	/* the default WEP keys */
+	key_struct_t	wep_key_struct[10];
+
+	/*** Unknown ***/
+	u8		dtim_interval;
+
+	/*** Card Rx/Tx management ***/
+	u16		rx_config_1;
+	u16		rx_config_2;
+	u16		memblocksize;
+	unsigned int	tx_free;
+	unsigned int	tx_head; /* keep as close as possible to Tx stuff below (cache line) */
+	u16		phy_header_len;
+
+/*************************************************************************
+ *** PCI/USB/... must be last or else hw agnostic code breaks horribly ***
+ *************************************************************************/
+
+	/* hack to let common code compile. FIXME */
+	dma_addr_t	rxhostdesc_startphy;
+
+	/*** PCI stuff ***/
+#ifdef ACX_PCI
+	/* pointers to tx buffers, tx host descriptors (in host memory)
+	** and tx descs in device memory */
+	unsigned int	tx_tail;
+	u8		*txbuf_start;
+	txhostdesc_t	*txhostdesc_start;
+	txdesc_t	*txdesc_start;	/* points to PCI-mapped memory */
+	dma_addr_t	txbuf_startphy;
+	dma_addr_t	txhostdesc_startphy;
+	/* sizes of above host memory areas */
+	unsigned int	txbuf_area_size;
+	unsigned int	txhostdesc_area_size;
+
+	unsigned int	txdesc_size;	/* size of txdesc; ACX111 = ACX100 + 4 */
+	client_t	*txc[TX_CNT];
+	u16		txr[TX_CNT];
+
+	/* same for rx */
+	unsigned int	rx_tail;
+	rxbuffer_t	*rxbuf_start;
+	rxhostdesc_t	*rxhostdesc_start;
+	rxdesc_t	*rxdesc_start;
+	/* physical addresses of above host memory areas */
+	dma_addr_t	rxbuf_startphy;
+	/* dma_addr_t	rxhostdesc_startphy; */
+	unsigned int	rxbuf_area_size;
+	unsigned int	rxhostdesc_area_size;
+
+	u8		need_radio_fw;
+	u8		irqs_active;	/* whether irq sending is activated */
+
+	const u16	*io;		/* points to ACX100 or ACX111 PCI I/O register address set */
+
+	struct pci_dev	*pdev;
+
+	unsigned long	membase;
+	unsigned long	membase2;
+	void __iomem	*iobase;
+	void __iomem	*iobase2;
+	/* command interface */
+	u8 __iomem	*cmd_area;
+	u8 __iomem	*info_area;
+
+	u16		irq_mask;		/* interrupt types to mask out (not wanted) with many IRQs activated */
+	u16		irq_mask_off;		/* interrupt types to mask out (not wanted) with IRQs off */
+	unsigned int	irq_loops_this_jiffy;
+	unsigned long	irq_last_jiffies;
+#endif
+
+	/*** USB stuff ***/
+#ifdef ACX_USB
+	struct usb_device	*usbdev;
+
+	rxbuffer_t	rxtruncbuf;
+
+	usb_tx_t	*usb_tx;
+	usb_rx_t	*usb_rx;
+
+	int		bulkinep;	/* bulk-in endpoint */
+	int		bulkoutep;	/* bulk-out endpoint */
+	int		rxtruncsize;
+#endif
+
+};
+
+static inline acx_device_t*
+ndev2adev(struct net_device *ndev)
+{
+	return netdev_priv(ndev);
+}
+
+
+/* For use with ACX1xx_IE_RXCONFIG */
+/*  bit     description
+ *    13   include additional header (length etc.) *required*
+ *		struct is defined in 'struct rxbuffer'
+ *		is this bit acx100 only? does acx111 always put the header,
+ *		and bit setting is irrelevant? --vda
+ *    10   receive frames only with SSID used in last join cmd
+ *     9   discard broadcast
+ *     8   receive packets for multicast address 1
+ *     7   receive packets for multicast address 0
+ *     6   discard all multicast packets
+ *     5   discard frames from foreign BSSID
+ *     4   discard frames with foreign destination MAC address
+ *     3   promiscuous mode (receive ALL frames, disable filter)
+ *     2   include FCS
+ *     1   include phy header
+ *     0   ???
+ */
+#define RX_CFG1_INCLUDE_RXBUF_HDR	0x2000 /* ACX100 only */
+#define RX_CFG1_FILTER_SSID		0x0400
+#define RX_CFG1_FILTER_BCAST		0x0200
+#define RX_CFG1_RCV_MC_ADDR1		0x0100
+#define RX_CFG1_RCV_MC_ADDR0		0x0080
+#define RX_CFG1_FILTER_ALL_MULTI	0x0040
+#define RX_CFG1_FILTER_BSSID		0x0020
+#define RX_CFG1_FILTER_MAC		0x0010
+#define RX_CFG1_RCV_PROMISCUOUS		0x0008
+#define RX_CFG1_INCLUDE_FCS		0x0004
+#define RX_CFG1_INCLUDE_PHY_HDR		(WANT_PHY_HDR ? 0x0002 : 0)
+/*  bit     description
+ *    11   receive association requests etc.
+ *    10   receive authentication frames
+ *     9   receive beacon frames
+ *     8   receive contention free packets
+ *     7   receive control frames
+ *     6   receive data frames
+ *     5   receive broken frames
+ *     4   receive management frames
+ *     3   receive probe requests
+ *     2   receive probe responses
+ *     1   receive RTS/CTS/ACK frames
+ *     0   receive other
+ */
+#define RX_CFG2_RCV_ASSOC_REQ		0x0800
+#define RX_CFG2_RCV_AUTH_FRAMES		0x0400
+#define RX_CFG2_RCV_BEACON_FRAMES	0x0200
+#define RX_CFG2_RCV_CONTENTION_FREE	0x0100
+#define RX_CFG2_RCV_CTRL_FRAMES		0x0080
+#define RX_CFG2_RCV_DATA_FRAMES		0x0040
+#define RX_CFG2_RCV_BROKEN_FRAMES	0x0020
+#define RX_CFG2_RCV_MGMT_FRAMES		0x0010
+#define RX_CFG2_RCV_PROBE_REQ		0x0008
+#define RX_CFG2_RCV_PROBE_RESP		0x0004
+#define RX_CFG2_RCV_ACK_FRAMES		0x0002
+#define RX_CFG2_RCV_OTHER		0x0001
+
+/* For use with ACX1xx_IE_FEATURE_CONFIG */
+#define FEATURE1_80MHZ_CLOCK	0x00000040L
+#define FEATURE1_4X		0x00000020L
+#define FEATURE1_LOW_RX		0x00000008L
+#define FEATURE1_EXTRA_LOW_RX	0x00000001L
+
+#define FEATURE2_SNIFFER	0x00000080L
+#define FEATURE2_NO_TXCRYPT	0x00000001L
+
+/*-- get and set mask values --*/
+#define GETSET_LED_POWER	0x00000001L
+#define GETSET_STATION_ID	0x00000002L
+#define SET_TEMPLATES		0x00000004L
+#define SET_STA_LIST		0x00000008L
+#define GETSET_TX		0x00000010L
+#define GETSET_RX		0x00000020L
+#define SET_RXCONFIG		0x00000040L
+#define GETSET_ANTENNA		0x00000080L
+#define GETSET_SENSITIVITY	0x00000100L
+#define GETSET_TXPOWER		0x00000200L
+#define GETSET_ED_THRESH	0x00000400L
+#define GETSET_CCA		0x00000800L
+#define GETSET_POWER_80211	0x00001000L
+#define GETSET_RETRY		0x00002000L
+#define GETSET_REG_DOMAIN	0x00004000L
+#define GETSET_CHANNEL		0x00008000L
+/* Used when ESSID changes etc and we need to scan for AP anew */
+#define GETSET_RESCAN		0x00010000L
+#define GETSET_MODE		0x00020000L
+#define GETSET_WEP		0x00040000L
+#define SET_WEP_OPTIONS		0x00080000L
+#define SET_MSDU_LIFETIME	0x00100000L
+#define SET_RATE_FALLBACK	0x00200000L
+
+/* keep in sync with the above */
+#define GETSET_ALL	(0 \
+/* GETSET_LED_POWER */	| 0x00000001L \
+/* GETSET_STATION_ID */	| 0x00000002L \
+/* SET_TEMPLATES */	| 0x00000004L \
+/* SET_STA_LIST */	| 0x00000008L \
+/* GETSET_TX */		| 0x00000010L \
+/* GETSET_RX */		| 0x00000020L \
+/* SET_RXCONFIG */	| 0x00000040L \
+/* GETSET_ANTENNA */	| 0x00000080L \
+/* GETSET_SENSITIVITY */| 0x00000100L \
+/* GETSET_TXPOWER */	| 0x00000200L \
+/* GETSET_ED_THRESH */	| 0x00000400L \
+/* GETSET_CCA */	| 0x00000800L \
+/* GETSET_POWER_80211 */| 0x00001000L \
+/* GETSET_RETRY */	| 0x00002000L \
+/* GETSET_REG_DOMAIN */	| 0x00004000L \
+/* GETSET_CHANNEL */	| 0x00008000L \
+/* GETSET_RESCAN */	| 0x00010000L \
+/* GETSET_MODE */	| 0x00020000L \
+/* GETSET_WEP */	| 0x00040000L \
+/* SET_WEP_OPTIONS */	| 0x00080000L \
+/* SET_MSDU_LIFETIME */	| 0x00100000L \
+/* SET_RATE_FALLBACK */	| 0x00200000L \
+			)
+
+
+/***********************************************************************
+** Firmware loading
+*/
+#include <linux/firmware.h>	/* request_firmware() */
+#include <linux/pci.h>		/* struct pci_device */
+
+
+/***********************************************************************
+*/
+typedef struct acx100_ie_memblocksize {
+	u16	type ACX_PACKED;
+	u16	len ACX_PACKED;
+	u16	size ACX_PACKED;
+} acx100_ie_memblocksize_t;
+
+typedef struct acx100_ie_queueconfig {
+	u16	type ACX_PACKED;
+	u16	len ACX_PACKED;
+	u32	AreaSize ACX_PACKED;
+	u32	RxQueueStart ACX_PACKED;
+	u8	QueueOptions ACX_PACKED;
+	u8	NumTxQueues ACX_PACKED;
+	u8	NumRxDesc ACX_PACKED;	 /* for USB only */
+	u8	pad1 ACX_PACKED;
+	u32	QueueEnd ACX_PACKED;
+	u32	HostQueueEnd ACX_PACKED; /* QueueEnd2 */
+	u32	TxQueueStart ACX_PACKED;
+	u8	TxQueuePri ACX_PACKED;
+	u8	NumTxDesc ACX_PACKED;
+	u16	pad2 ACX_PACKED;
+} acx100_ie_queueconfig_t;
+
+typedef struct acx111_ie_queueconfig {
+	u16	type ACX_PACKED;
+	u16	len ACX_PACKED;
+	u32	tx_memory_block_address ACX_PACKED;
+	u32	rx_memory_block_address ACX_PACKED;
+	u32	rx1_queue_address ACX_PACKED;
+	u32	reserved1 ACX_PACKED;
+	u32	tx1_queue_address ACX_PACKED;
+	u8	tx1_attributes ACX_PACKED;
+	u16	reserved2 ACX_PACKED;
+	u8	reserved3 ACX_PACKED;
+} acx111_ie_queueconfig_t;
+
+typedef struct acx100_ie_memconfigoption {
+	u16	type ACX_PACKED;
+	u16	len ACX_PACKED;
+	u32	DMA_config ACX_PACKED;
+	acx_ptr	pRxHostDesc ACX_PACKED;
+	u32	rx_mem ACX_PACKED;
+	u32	tx_mem ACX_PACKED;
+	u16	RxBlockNum ACX_PACKED;
+	u16	TxBlockNum ACX_PACKED;
+} acx100_ie_memconfigoption_t;
+
+typedef struct acx111_ie_memoryconfig {
+	u16	type ACX_PACKED;
+	u16	len ACX_PACKED;
+	u16	no_of_stations ACX_PACKED;
+	u16	memory_block_size ACX_PACKED;
+	u8	tx_rx_memory_block_allocation ACX_PACKED;
+	u8	count_rx_queues ACX_PACKED;
+	u8	count_tx_queues ACX_PACKED;
+	u8	options ACX_PACKED;
+	u8	fragmentation ACX_PACKED;
+	u16	reserved1 ACX_PACKED;
+	u8	reserved2 ACX_PACKED;
+
+	/* start of rx1 block */
+	u8	rx_queue1_count_descs ACX_PACKED;
+	u8	rx_queue1_reserved1 ACX_PACKED;
+	u8	rx_queue1_type ACX_PACKED; /* must be set to 7 */
+	u8	rx_queue1_prio ACX_PACKED; /* must be set to 0 */
+	acx_ptr	rx_queue1_host_rx_start ACX_PACKED;
+	/* end of rx1 block */
+
+	/* start of tx1 block */
+	u8	tx_queue1_count_descs ACX_PACKED;
+	u8	tx_queue1_reserved1 ACX_PACKED;
+	u8	tx_queue1_reserved2 ACX_PACKED;
+	u8	tx_queue1_attributes ACX_PACKED;
+	/* end of tx1 block */
+} acx111_ie_memoryconfig_t;
+
+typedef struct acx_ie_memmap {
+	u16	type ACX_PACKED;
+	u16	len ACX_PACKED;
+	u32	CodeStart ACX_PACKED;
+	u32	CodeEnd ACX_PACKED;
+	u32	WEPCacheStart ACX_PACKED;
+	u32	WEPCacheEnd ACX_PACKED;
+	u32	PacketTemplateStart ACX_PACKED;
+	u32	PacketTemplateEnd ACX_PACKED;
+	u32	QueueStart ACX_PACKED;
+	u32	QueueEnd ACX_PACKED;
+	u32	PoolStart ACX_PACKED;
+	u32	PoolEnd ACX_PACKED;
+} acx_ie_memmap_t;
+
+typedef struct acx111_ie_feature_config {
+	u16	type ACX_PACKED;
+	u16	len ACX_PACKED;
+	u32	feature_options ACX_PACKED;
+	u32	data_flow_options ACX_PACKED;
+} acx111_ie_feature_config_t;
+
+typedef struct acx111_ie_tx_level {
+	u16	type ACX_PACKED;
+	u16	len ACX_PACKED;
+	u8	level ACX_PACKED;
+} acx111_ie_tx_level_t;
+
+#define PS_CFG_ENABLE		0x80
+#define PS_CFG_PENDING		0x40 /* status flag when entering PS */
+#define PS_CFG_WAKEUP_MODE_MASK	0x07
+#define PS_CFG_WAKEUP_BY_HOST	0x03
+#define PS_CFG_WAKEUP_EACH_ITVL	0x02
+#define PS_CFG_WAKEUP_ON_DTIM	0x01
+#define PS_CFG_WAKEUP_ALL_BEAC	0x00
+
+/* Enhanced PS mode: sleep until Rx Beacon w/ the STA's AID bit set
+** in the TIM; newer firmwares only(?) */
+#define PS_OPT_ENA_ENHANCED_PS	0x04
+#define PS_OPT_TX_PSPOLL	0x02 /* send PSPoll frame to fetch waiting frames from AP (on frame with matching AID) */
+#define PS_OPT_STILL_RCV_BCASTS	0x01
+
+typedef struct acx100_ie_powersave {
+	u16	type ACX_PACKED;
+	u16	len ACX_PACKED;
+	u8	wakeup_cfg ACX_PACKED;
+	u8	listen_interval ACX_PACKED; /* for EACH_ITVL: wake up every "beacon units" interval */
+	u8	options ACX_PACKED;
+	u8	hangover_period ACX_PACKED; /* remaining wake time after Tx MPDU w/ PS bit, in values of 1/1024 seconds */
+	u16	enhanced_ps_transition_time ACX_PACKED; /* rem. wake time for Enh. PS */
+} acx100_ie_powersave_t;
+
+typedef struct acx111_ie_powersave {
+	u16	type ACX_PACKED;
+	u16	len ACX_PACKED;
+	u8	wakeup_cfg ACX_PACKED;
+	u8	listen_interval ACX_PACKED; /* for EACH_ITVL: wake up every "beacon units" interval */
+	u8	options ACX_PACKED;
+	u8	hangover_period ACX_PACKED; /* remaining wake time after Tx MPDU w/ PS bit, in values of 1/1024 seconds */
+	u32	beacon_rx_time ACX_PACKED;
+	u32	enhanced_ps_transition_time ACX_PACKED; /* rem. wake time for Enh. PS */
+} acx111_ie_powersave_t;
+
+
+/***********************************************************************
+** Commands and template structures
+*/
+
+/*
+** SCAN command structure
+**
+** even though acx100 scan rates match RATE100 constants,
+** acx111 ones do not match! Therefore we do not use RATE100 #defines */
+#define ACX_SCAN_RATE_1		10
+#define ACX_SCAN_RATE_2		20
+#define ACX_SCAN_RATE_5		55
+#define ACX_SCAN_RATE_11	110
+#define ACX_SCAN_RATE_22	220
+#define ACX_SCAN_RATE_PBCC	0x80	/* OR with this if needed */
+#define ACX_SCAN_OPT_ACTIVE	0x00	/* a bit mask */
+#define ACX_SCAN_OPT_PASSIVE	0x01
+/* Background scan: we go into Power Save mode (by transmitting
+** NULL data frame to AP with the power mgmt bit set), do the scan,
+** and then exit Power Save mode. A plus is that AP buffers frames
+** for us while we do background scan. Thus we avoid frame losses.
+** Background scan can be active or passive, just like normal one */
+#define ACX_SCAN_OPT_BACKGROUND	0x02
+typedef struct acx100_scan {
+	u16	count ACX_PACKED;	/* number of scans to do, 0xffff == continuous */
+	u16	start_chan ACX_PACKED;
+	u16	flags ACX_PACKED;	/* channel list mask; 0x8000 == all channels? */
+	u8	max_rate ACX_PACKED;	/* max. probe rate */
+	u8	options ACX_PACKED;	/* bit mask, see defines above */
+	u16	chan_duration ACX_PACKED;
+	u16	max_probe_delay ACX_PACKED;
+} acx100_scan_t;			/* length 0xc */
+
+#define ACX111_SCAN_RATE_6	0x0B
+#define ACX111_SCAN_RATE_9	0x0F
+#define ACX111_SCAN_RATE_12	0x0A
+#define ACX111_SCAN_RATE_18	0x0E
+#define ACX111_SCAN_RATE_24	0x09
+#define ACX111_SCAN_RATE_36	0x0D
+#define ACX111_SCAN_RATE_48	0x08
+#define ACX111_SCAN_RATE_54	0x0C
+#define ACX111_SCAN_OPT_5GHZ    0x04	/* else 2.4GHZ */
+#define ACX111_SCAN_MOD_SHORTPRE 0x01	/* you can combine SHORTPRE and PBCC */
+#define ACX111_SCAN_MOD_PBCC	0x80
+#define ACX111_SCAN_MOD_OFDM	0x40
+typedef struct acx111_scan {
+	u16	count ACX_PACKED;		/* number of scans to do */
+	u8	channel_list_select ACX_PACKED; /* 0: scan all channels, 1: from chan_list only */
+	u16	reserved1 ACX_PACKED;
+	u8	reserved2 ACX_PACKED;
+	u8	rate ACX_PACKED;		/* rate for probe requests (if active scan) */
+	u8	options ACX_PACKED;		/* bit mask, see defines above */
+	u16	chan_duration ACX_PACKED;	/* min time to wait for reply on one channel (in TU) */
+						/* (active scan only) (802.11 section 11.1.3.2.2) */
+	u16	max_probe_delay ACX_PACKED;	/* max time to wait for reply on one channel (active scan) */
+						/* time to listen on a channel (passive scan) */
+	u8	modulation ACX_PACKED;
+	u8	channel_list[26] ACX_PACKED;	/* bits 7:0 first byte: channels 8:1 */
+						/* bits 7:0 second byte: channels 16:9 */
+						/* 26 bytes is enough to cover 802.11a */
+} acx111_scan_t;
+
+
+/*
+** Radio calibration command structure
+*/
+typedef struct acx111_cmd_radiocalib {
+/* 0x80000000 == automatic calibration by firmware, according to interval;
+ * bits 0..3: select calibration methods to go through:
+ * calib based on DC, AfeDC, Tx mismatch, Tx equilization */
+	u32	methods ACX_PACKED;
+	u32	interval ACX_PACKED;
+} acx111_cmd_radiocalib_t;
+
+
+/*
+** Packet template structures
+**
+** Packet templates store contents of Beacon, Probe response, Probe request,
+** Null data frame, and TIM data frame. Firmware automatically transmits
+** contents of template at appropriate time:
+** - Beacon: when configured as AP or Ad-hoc
+** - Probe response: when configured as AP or Ad-hoc, whenever
+**   a Probe request frame is received
+** - Probe request: when host issues SCAN command (active)
+** - Null data frame: when entering 802.11 power save mode
+** - TIM data: at the end of Beacon frames (if no TIM template
+**   is configured, then transmits default TIM)
+** NB:
+** - size field must be set to size of actual template
+**   (NOT sizeof(struct) - templates are variable in length),
+**   size field is not itself counted.
+** - members flagged with an asterisk must be initialized with host,
+**   rest must be zero filled.
+** - variable length fields shown only in comments */
+typedef struct acx_template_tim {
+	u16	size ACX_PACKED;
+	u8	tim_eid ACX_PACKED;	/* 00 1 TIM IE ID * */
+	u8	len ACX_PACKED;		/* 01 1 Length * */
+	u8	dtim_cnt ACX_PACKED;	/* 02 1 DTIM Count */
+	u8	dtim_period ACX_PACKED;	/* 03 1 DTIM Period */
+	u8	bitmap_ctrl ACX_PACKED;	/* 04 1 Bitmap Control * (except bit0) */
+					/* 05 n Partial Virtual Bitmap * */
+	u8	variable[0x100 - 1-1-1-1-1] ACX_PACKED;
+} acx_template_tim_t;
+
+typedef struct acx_template_probereq {
+	u16	size ACX_PACKED;
+	u16	fc ACX_PACKED;		/* 00 2 fc * */
+	u16	dur ACX_PACKED;		/* 02 2 Duration */
+	u8	da[6] ACX_PACKED;	/* 04 6 Destination Address * */
+	u8	sa[6] ACX_PACKED;	/* 0A 6 Source Address * */
+	u8	bssid[6] ACX_PACKED;	/* 10 6 BSSID * */
+	u16	seq ACX_PACKED;		/* 16 2 Sequence Control */
+					/* 18 n SSID * */
+					/* nn n Supported Rates * */
+	u8	variable[0x44 - 2-2-6-6-6-2] ACX_PACKED;
+} acx_template_probereq_t;
+
+typedef struct acx_template_proberesp {
+	u16	size ACX_PACKED;
+	u16	fc ACX_PACKED;		/* 00 2 fc * (bits [15:12] and [10:8] per 802.11 section 7.1.3.1) */
+	u16	dur ACX_PACKED;		/* 02 2 Duration */
+	u8	da[6] ACX_PACKED;	/* 04 6 Destination Address */
+	u8	sa[6] ACX_PACKED;	/* 0A 6 Source Address */
+	u8	bssid[6] ACX_PACKED;	/* 10 6 BSSID */
+	u16	seq ACX_PACKED;		/* 16 2 Sequence Control */
+	u8	timestamp[8] ACX_PACKED;/* 18 8 Timestamp */
+	u16	beacon_interval ACX_PACKED; /* 20 2 Beacon Interval * */
+	u16	cap ACX_PACKED;		/* 22 2 Capability Information * */
+					/* 24 n SSID * */
+					/* nn n Supported Rates * */
+					/* nn 1 DS Parameter Set * */
+	u8	variable[0x54 - 2-2-6-6-6-2-8-2-2] ACX_PACKED;
+} acx_template_proberesp_t;
+#define acx_template_beacon_t acx_template_proberesp_t
+#define acx_template_beacon acx_template_proberesp
+
+typedef struct acx_template_nullframe {
+	u16	size ACX_PACKED;
+	struct wlan_hdr_a3 hdr ACX_PACKED;
+} acx_template_nullframe_t;
+
+
+/*
+** JOIN command structure
+**
+** as opposed to acx100, acx111 dtim interval is AFTER rates_basic111.
+** NOTE: took me about an hour to get !@#$%^& packing right --> struct packing is eeeeevil... */
+typedef struct acx_joinbss {
+	u8	bssid[ETH_ALEN] ACX_PACKED;
+	u16	beacon_interval ACX_PACKED;
+	union {
+		struct {
+			u8	dtim_interval ACX_PACKED;
+			u8	rates_basic ACX_PACKED;
+			u8	rates_supported ACX_PACKED;
+		} acx100 ACX_PACKED;
+		struct {
+			u16	rates_basic ACX_PACKED;
+			u8	dtim_interval ACX_PACKED;
+		} acx111 ACX_PACKED;
+	} u ACX_PACKED;
+	u8	genfrm_txrate ACX_PACKED;	/* generated frame (bcn, proberesp, RTS, PSpoll) tx rate */
+	u8	genfrm_mod_pre ACX_PACKED;	/* generated frame modulation/preamble:
+						** bit7: PBCC, bit6: OFDM (else CCK/DQPSK/DBPSK)
+						** bit5: short pre */
+	u8	macmode ACX_PACKED;	/* BSS Type, must be one of ACX_MODE_xxx */
+	u8	channel ACX_PACKED;
+	u8	essid_len ACX_PACKED;
+	char	essid[IW_ESSID_MAX_SIZE] ACX_PACKED;
+} acx_joinbss_t;
+
+#define JOINBSS_RATES_1		0x01
+#define JOINBSS_RATES_2		0x02
+#define JOINBSS_RATES_5		0x04
+#define JOINBSS_RATES_11	0x08
+#define JOINBSS_RATES_22	0x10
+
+/* Looks like missing bits are used to indicate 11g rates!
+** (it follows from the fact that constants below match 1:1 to RATE111_nn)
+** This was actually seen! Look at that Assoc Request sent by acx111,
+** it _does_ contain 11g rates in basic set:
+01:30:20.070772 Beacon (xxx) [1.0* 2.0* 5.5* 11.0* 6.0* 9.0* 12.0* 18.0* 24.0* 36.0* 48.0* 54.0* Mbit] ESS CH: 1
+01:30:20.074425 Authentication (Open System)-1: Succesful
+01:30:20.076539 Authentication (Open System)-2:
+01:30:20.076620 Acknowledgment
+01:30:20.088546 Assoc Request (xxx) [1.0* 2.0* 5.5* 6.0* 9.0* 11.0* 12.0* 18.0* 24.0* 36.0* 48.0* 54.0* Mbit]
+01:30:20.122413 Assoc Response AID(1) :: Succesful
+01:30:20.122679 Acknowledgment
+01:30:20.173204 Beacon (xxx) [1.0* 2.0* 5.5* 11.0* 6.0* 9.0* 12.0* 18.0* 24.0* 36.0* 48.0* 54.0* Mbit] ESS CH: 1
+*/
+#define JOINBSS_RATES_BASIC111_1	0x0001
+#define JOINBSS_RATES_BASIC111_2	0x0002
+#define JOINBSS_RATES_BASIC111_5	0x0004
+#define JOINBSS_RATES_BASIC111_11	0x0020
+#define JOINBSS_RATES_BASIC111_22	0x0100
+
+
+/***********************************************************************
+*/
+typedef struct mem_read_write {
+	u16	addr ACX_PACKED;
+	u16	type ACX_PACKED; /* 0x0 int. RAM / 0xffff MAC reg. / 0x81 PHY RAM / 0x82 PHY reg. */
+	u32	len ACX_PACKED;
+	u32	data ACX_PACKED;
+} mem_read_write_t;
+
+typedef struct firmware_image {
+	u32	chksum ACX_PACKED;
+	u32	size ACX_PACKED;
+	u8	data[1] ACX_PACKED; /* the byte array of the actual firmware... */
+} firmware_image_t;
+
+typedef struct acx_cmd_radioinit {
+	u32	offset ACX_PACKED;
+	u32	len ACX_PACKED;
+} acx_cmd_radioinit_t;
+
+typedef struct acx100_ie_wep_options {
+	u16	type ACX_PACKED;
+	u16	len ACX_PACKED;
+	u16	NumKeys ACX_PACKED;	/* max # of keys */
+	u8	WEPOption ACX_PACKED;	/* 0 == decrypt default key only, 1 == override decrypt */
+	u8	Pad ACX_PACKED;		/* used only for acx111 */
+} acx100_ie_wep_options_t;
+
+typedef struct ie_dot11WEPDefaultKey {
+	u16	type ACX_PACKED;
+	u16	len ACX_PACKED;
+	u8	action ACX_PACKED;
+	u8	keySize ACX_PACKED;
+	u8	defaultKeyNum ACX_PACKED;
+	u8	key[29] ACX_PACKED;	/* check this! was Key[19] */
+} ie_dot11WEPDefaultKey_t;
+
+typedef struct acx111WEPDefaultKey {
+	u8	MacAddr[ETH_ALEN] ACX_PACKED;
+	u16	action ACX_PACKED;	/* NOTE: this is a u16, NOT a u8!! */
+	u16	reserved ACX_PACKED;
+	u8	keySize ACX_PACKED;
+	u8	type ACX_PACKED;
+	u8	index ACX_PACKED;
+	u8	defaultKeyNum ACX_PACKED;
+	u8	counter[6] ACX_PACKED;
+	u8	key[32] ACX_PACKED;	/* up to 32 bytes (for TKIP!) */
+} acx111WEPDefaultKey_t;
+
+typedef struct ie_dot11WEPDefaultKeyID {
+	u16	type ACX_PACKED;
+	u16	len ACX_PACKED;
+	u8	KeyID ACX_PACKED;
+} ie_dot11WEPDefaultKeyID_t;
+
+typedef struct acx100_cmd_wep_mgmt {
+	u8	MacAddr[ETH_ALEN] ACX_PACKED;
+	u16	Action ACX_PACKED;
+	u16	KeySize ACX_PACKED;
+	u8	Key[29] ACX_PACKED; /* 29*8 == 232bits == WEP256 */
+} acx100_cmd_wep_mgmt_t;
+
+/* UNUSED?
+typedef struct defaultkey {
+	u8	num;
+} defaultkey_t;
+*/
+
+typedef struct acx_ie_generic {
+	u16	type ACX_PACKED;
+	u16	len ACX_PACKED;
+	union {
+		/* struct wep wp ACX_PACKED; */
+		/* Association ID IE: just a 16bit value: */
+		u16	aid;
+		/* UNUSED? struct defaultkey dkey ACX_PACKED; */
+		/* generic member for quick implementation of commands */
+		u8	bytes[32] ACX_PACKED;
+	} m ACX_PACKED;
+} acx_ie_generic_t;
+
+/***********************************************************************
+*/
+#define CHECK_SIZEOF(type,size) { \
+	extern void BUG_bad_size_for_##type(void); \
+	if (sizeof(type)!=(size)) BUG_bad_size_for_##type(); \
+}
+
+static inline void
+acx_struct_size_check(void)
+{
+	CHECK_SIZEOF(txdesc_t, 0x30);
+	CHECK_SIZEOF(acx100_ie_memconfigoption_t, 24);
+	CHECK_SIZEOF(acx100_ie_queueconfig_t, 0x20);
+	CHECK_SIZEOF(acx_joinbss_t, 0x30);
+	/* IEs need 4 bytes for (type,len) tuple */
+	CHECK_SIZEOF(acx111_ie_configoption_t, ACX111_IE_CONFIG_OPTIONS_LEN + 4);
+}
+
+
+/***********************************************************************
+** Global data
+*/
+extern const u8 acx_bitpos2ratebyte[];
+extern const u8 acx_bitpos2rate100[];
+
+extern const u8 acx_reg_domain_ids[];
+extern const char * const acx_reg_domain_strings[];
+enum {
+	acx_reg_domain_ids_len = 8
+};
+
+extern const struct iw_handler_def acx_ioctl_handler_def;
diff -urN oldtree/drivers/net/wireless/tiacx/common.c newtree/drivers/net/wireless/tiacx/common.c
--- oldtree/drivers/net/wireless/tiacx/common.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/net/wireless/tiacx/common.c	2006-02-21 15:58:22.587712704 +0000
@@ -0,0 +1,6884 @@
+/***********************************************************************
+** Copyright (C) 2003  ACX100 Open Source Project
+**
+** The contents of this file are subject to the Mozilla Public
+** License Version 1.1 (the "License"); you may not use this file
+** except in compliance with the License. You may obtain a copy of
+** the License at http://www.mozilla.org/MPL/
+**
+** Software distributed under the License is distributed on an "AS
+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+** implied. See the License for the specific language governing
+** rights and limitations under the License.
+**
+** Alternatively, the contents of this file may be used under the
+** terms of the GNU Public License version 2 (the "GPL"), in which
+** case the provisions of the GPL are applicable instead of the
+** above.  If you wish to allow the use of your version of this file
+** only under the terms of the GPL and not to allow others to use
+** your version of this file under the MPL, indicate your decision
+** by deleting the provisions above and replace them with the notice
+** and other provisions required by the GPL.  If you do not delete
+** the provisions above, a recipient may use your version of this
+** file under either the MPL or the GPL.
+** ---------------------------------------------------------------------
+** Inquiries regarding the ACX100 Open Source Project can be
+** made directly to:
+**
+** acx100-users@lists.sf.net
+** http://acx100.sf.net
+** ---------------------------------------------------------------------
+*/
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/if_arp.h>
+#include <linux/rtnetlink.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/pm.h>
+#include <linux/vmalloc.h>
+#include <net/iw_handler.h>
+
+#include "acx.h"
+
+
+/***********************************************************************
+*/
+static client_t *acx_l_sta_list_alloc(acx_device_t *adev);
+static client_t *acx_l_sta_list_get_from_hash(acx_device_t *adev, const u8 *address);
+
+static int acx_l_process_data_frame_master(acx_device_t *adev, rxbuffer_t *rxbuf);
+static int acx_l_process_data_frame_client(acx_device_t *adev, rxbuffer_t *rxbuf);
+/* static int acx_l_process_NULL_frame(acx_device_t *adev, rxbuffer_t *rxbuf, int vala); */
+static int acx_l_process_mgmt_frame(acx_device_t *adev, rxbuffer_t *rxbuf);
+static void acx_l_process_disassoc_from_sta(acx_device_t *adev, const wlan_fr_disassoc_t *req);
+static void acx_l_process_disassoc_from_ap(acx_device_t *adev, const wlan_fr_disassoc_t *req);
+static void acx_l_process_deauth_from_sta(acx_device_t *adev, const wlan_fr_deauthen_t *req);
+static void acx_l_process_deauth_from_ap(acx_device_t *adev, const wlan_fr_deauthen_t *req);
+static int acx_l_process_probe_response(acx_device_t *adev, wlan_fr_proberesp_t *req, const rxbuffer_t *rxbuf);
+static int acx_l_process_assocresp(acx_device_t *adev, const wlan_fr_assocresp_t *req);
+static int acx_l_process_reassocresp(acx_device_t *adev, const wlan_fr_reassocresp_t *req);
+static int acx_l_process_authen(acx_device_t *adev, const wlan_fr_authen_t *req);
+static int acx_l_transmit_assocresp(acx_device_t *adev, const wlan_fr_assocreq_t *req);
+static int acx_l_transmit_reassocresp(acx_device_t *adev, const wlan_fr_reassocreq_t *req);
+static int acx_l_transmit_deauthen(acx_device_t *adev, const u8 *addr, u16 reason);
+static int acx_l_transmit_authen1(acx_device_t *adev);
+static int acx_l_transmit_authen2(acx_device_t *adev, const wlan_fr_authen_t *req, client_t *clt);
+static int acx_l_transmit_authen3(acx_device_t *adev, const wlan_fr_authen_t *req);
+static int acx_l_transmit_authen4(acx_device_t *adev, const wlan_fr_authen_t *req);
+static int acx_l_transmit_assoc_req(acx_device_t *adev);
+
+
+/***********************************************************************
+*/
+#if ACX_DEBUG
+unsigned int acx_debug /* will add __read_mostly later */ = ACX_DEFAULT_MSG;
+/* parameter is 'debug', corresponding var is acx_debug */
+module_param_named(debug, acx_debug, uint, 0);
+MODULE_PARM_DESC(debug, "Debug level mask (see L_xxx constants)");
+#endif
+
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("Dual MPL/GPL");
+#endif
+/* USB had this: MODULE_AUTHOR("Martin Wawro <martin.wawro AT uni-dortmund.de>"); */
+MODULE_AUTHOR("ACX100 Open Source Driver development team");
+MODULE_DESCRIPTION("Driver for TI ACX1xx based wireless cards (CardBus/PCI/USB)");
+
+
+/***********************************************************************
+*/
+/* Probably a number of acx's intermediate buffers for USB transfers,
+** not to be confused with number of descriptors in tx/rx rings
+** (which are not directly accessible to host in USB devices) */
+#define USB_RX_CNT 10
+#define USB_TX_CNT 10
+
+
+/***********************************************************************
+*/
+
+/* minutes to wait until next radio recalibration: */
+#define RECALIB_PAUSE	5
+
+/* Please keep acx_reg_domain_ids_len in sync... */
+const u8 acx_reg_domain_ids[acx_reg_domain_ids_len] =
+	{ 0x10, 0x20, 0x30, 0x31, 0x32, 0x40, 0x41, 0x51 };
+static const u16 reg_domain_channel_masks[acx_reg_domain_ids_len] =
+	{ 0x07ff, 0x07ff, 0x1fff, 0x0600, 0x1e00, 0x2000, 0x3fff, 0x01fc };
+const char * const
+acx_reg_domain_strings[] = {
+	/* 0 */	" 1-11 FCC (USA)",
+	/* 1 */	" 1-11 DOC/IC (Canada)",
+/* BTW: WLAN use in ETSI is regulated by ETSI standard EN 300 328-2 V1.1.2 */
+	/* 2 */	" 1-13 ETSI (Europe)",
+	/* 3 */	"10-11 Spain",
+	/* 4 */	"10-13 France",
+	/* 5 */	"   14 MKK (Japan)",
+	/* 6 */	" 1-14 MKK1",
+	/* 7 */	"  3-9 Israel (not all firmware versions)",
+	NULL /* needs to remain as last entry */
+};
+
+
+
+/***********************************************************************
+** Debugging support
+*/
+#ifdef PARANOID_LOCKING
+static unsigned max_lock_time;
+static unsigned max_sem_time;
+
+void
+acx_lock_unhold() { max_lock_time = 0; }
+void
+acx_sem_unhold() { max_sem_time = 0; }
+
+static inline const char*
+sanitize_str(const char *s)
+{
+	const char* t = strrchr(s, '/');
+	if (t) return t + 1;
+	return s;
+}
+
+void
+acx_lock_debug(acx_device_t *adev, const char* where)
+{
+	unsigned int count = 100*1000*1000;
+	where = sanitize_str(where);
+	while (--count) {
+		if (!spin_is_locked(&adev->lock)) break;
+		cpu_relax();
+	}
+	if (!count) {
+		printk(KERN_EMERG "LOCKUP: already taken at %s!\n", adev->last_lock);
+		BUG();
+	}
+	adev->last_lock = where;
+	rdtscl(adev->lock_time);
+}
+void
+acx_unlock_debug(acx_device_t *adev, const char* where)
+{
+#ifdef SMP
+	if (!spin_is_locked(&adev->lock)) {
+		where = sanitize_str(where);
+		printk(KERN_EMERG "STRAY UNLOCK at %s!\n", where);
+		BUG();
+	}
+#endif
+	if (acx_debug & L_LOCK) {
+		unsigned long diff;
+		rdtscl(diff);
+		diff -= adev->lock_time;
+		if (diff > max_lock_time) {
+			where = sanitize_str(where);
+			printk("max lock hold time %ld CPU ticks from %s "
+				"to %s\n", diff, adev->last_lock, where);
+			max_lock_time = diff;
+		}
+	}
+}
+void
+acx_down_debug(acx_device_t *adev, const char* where)
+{
+	int sem_count;
+	unsigned long timeout = jiffies + 5*HZ;
+
+	where = sanitize_str(where);
+
+	for (;;) {
+		sem_count = atomic_read(&adev->sem.count);
+		if (sem_count) break;
+		if (time_after(jiffies, timeout))
+			break;
+		msleep(5);
+	}
+	if (!sem_count) {
+		printk(KERN_EMERG "D STATE at %s! last sem at %s\n",
+			where, adev->last_sem);
+		dump_stack();
+	}
+	adev->last_sem = where;
+	adev->sem_time = jiffies;
+	down(&adev->sem);
+	if (acx_debug & L_LOCK) {
+		printk("%s: sem_down %d -> %d\n",
+			where, sem_count, atomic_read(&adev->sem.count));
+	}
+}
+void
+acx_up_debug(acx_device_t *adev, const char* where)
+{
+	int sem_count = atomic_read(&adev->sem.count);
+	if (sem_count) {
+		where = sanitize_str(where);
+		printk(KERN_EMERG "STRAY UP at %s! sem.count=%d\n", where, sem_count);
+		dump_stack();
+	}
+	if (acx_debug & L_LOCK) {
+		unsigned long diff = jiffies - adev->sem_time;
+		if (diff > max_sem_time) {
+			where = sanitize_str(where);
+			printk("max sem hold time %ld jiffies from %s "
+				"to %s\n", diff, adev->last_sem, where);
+			max_sem_time = diff;
+		}
+	}
+	up(&adev->sem);
+	if (acx_debug & L_LOCK) {
+		where = sanitize_str(where);
+		printk("%s: sem_up %d -> %d\n",
+			where, sem_count, atomic_read(&adev->sem.count));
+	}
+}
+#endif /* PARANOID_LOCKING */
+
+
+/***********************************************************************
+*/
+#if ACX_DEBUG > 1
+
+static int acx_debug_func_indent;
+#define DEBUG_TSC 0
+#define FUNC_INDENT_INCREMENT 2
+
+#if DEBUG_TSC
+#define TIMESTAMP(d) unsigned long d; rdtscl(d)
+#else
+#define TIMESTAMP(d) unsigned long d = jiffies
+#endif
+
+static const char
+spaces[] = "          " "          "; /* Nx10 spaces */
+
+void
+log_fn_enter(const char *funcname)
+{
+	int indent;
+	TIMESTAMP(d);
+
+	indent = acx_debug_func_indent;
+	if (indent >= sizeof(spaces))
+		indent = sizeof(spaces)-1;
+
+	printk("%08ld %s==> %s\n",
+		d % 100000000,
+		spaces + (sizeof(spaces)-1) - indent,
+		funcname
+	);
+
+	acx_debug_func_indent += FUNC_INDENT_INCREMENT;
+}
+void
+log_fn_exit(const char *funcname)
+{
+	int indent;
+	TIMESTAMP(d);
+
+	acx_debug_func_indent -= FUNC_INDENT_INCREMENT;
+
+	indent = acx_debug_func_indent;
+	if (indent >= sizeof(spaces))
+		indent = sizeof(spaces)-1;
+
+	printk("%08ld %s<== %s\n",
+		d % 100000000,
+		spaces + (sizeof(spaces)-1) - indent,
+		funcname
+	);
+}
+void
+log_fn_exit_v(const char *funcname, int v)
+{
+	int indent;
+	TIMESTAMP(d);
+
+	acx_debug_func_indent -= FUNC_INDENT_INCREMENT;
+
+	indent = acx_debug_func_indent;
+	if (indent >= sizeof(spaces))
+		indent = sizeof(spaces)-1;
+
+	printk("%08ld %s<== %s: %08X\n",
+		d % 100000000,
+		spaces + (sizeof(spaces)-1) - indent,
+		funcname,
+		v
+	);
+}
+#endif /* ACX_DEBUG > 1 */
+
+
+/***********************************************************************
+** Basically a msleep with logging
+*/
+void
+acx_s_msleep(int ms)
+{
+	FN_ENTER;
+	msleep(ms);
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** Not inlined: it's larger than it seems
+*/
+void
+acx_print_mac(const char *head, const u8 *mac, const char *tail)
+{
+	printk("%s"MACSTR"%s", head, MAC(mac), tail);
+}
+
+
+/***********************************************************************
+** acx_get_status_name
+*/
+static const char*
+acx_get_status_name(u16 status)
+{
+	static const char * const str[] = {
+		"STOPPED", "SCANNING", "WAIT_AUTH",
+		"AUTHENTICATED", "ASSOCIATED", "INVALID??"
+	};
+	if (status > VEC_SIZE(str)-1)
+		status = VEC_SIZE(str)-1;
+
+	return str[status];
+}
+
+
+/***********************************************************************
+** acx_get_packet_type_string
+*/
+#if ACX_DEBUG
+const char*
+acx_get_packet_type_string(u16 fc)
+{
+	static const char * const mgmt_arr[] = {
+		"MGMT/AssocReq", "MGMT/AssocResp", "MGMT/ReassocReq",
+		"MGMT/ReassocResp", "MGMT/ProbeReq", "MGMT/ProbeResp",
+		"MGMT/UNKNOWN", "MGMT/UNKNOWN", "MGMT/Beacon", "MGMT/ATIM",
+		"MGMT/Disassoc", "MGMT/Authen", "MGMT/Deauthen"
+	};
+	static const char * const ctl_arr[] = {
+		"CTL/PSPoll", "CTL/RTS", "CTL/CTS", "CTL/Ack", "CTL/CFEnd",
+		"CTL/CFEndCFAck"
+	};
+	static const char * const data_arr[] = {
+		"DATA/DataOnly", "DATA/Data CFAck", "DATA/Data CFPoll",
+		"DATA/Data CFAck/CFPoll", "DATA/Null", "DATA/CFAck",
+		"DATA/CFPoll", "DATA/CFAck/CFPoll"
+	};
+	const char *str;
+	u8 fstype = (WF_FC_FSTYPE & fc) >> 4;
+	u8 ctl;
+
+	switch (WF_FC_FTYPE & fc) {
+	case WF_FTYPE_MGMT:
+		if (fstype < VEC_SIZE(mgmt_arr))
+			str = mgmt_arr[fstype];
+		else
+			str = "MGMT/UNKNOWN";
+		break;
+	case WF_FTYPE_CTL:
+		ctl = fstype - 0x0a;
+		if (ctl < VEC_SIZE(ctl_arr))
+			str = ctl_arr[ctl];
+		else
+			str = "CTL/UNKNOWN";
+		break;
+	case WF_FTYPE_DATA:
+		if (fstype < VEC_SIZE(data_arr))
+			str = data_arr[fstype];
+		else
+			str = "DATA/UNKNOWN";
+		break;
+	default:
+		str = "UNKNOWN";
+		break;
+	}
+	return str;
+}
+#endif
+
+
+/***********************************************************************
+** acx_wlan_reason_str
+*/
+static inline const char*
+acx_wlan_reason_str(u16 reason)
+{
+	static const char* const reason_str[] = {
+	/*  0 */	"?",
+	/*  1 */	"unspecified",
+	/*  2 */	"prev auth is not valid",
+	/*  3 */	"leaving BBS",
+	/*  4 */	"due to inactivity",
+	/*  5 */	"AP is busy",
+	/*  6 */	"got class 2 frame from non-auth'ed STA",
+	/*  7 */	"got class 3 frame from non-assoc'ed STA",
+	/*  8 */	"STA has left BSS",
+	/*  9 */	"assoc without auth is not allowed",
+	/* 10 */	"bad power setting (802.11h)",
+	/* 11 */	"bad channel (802.11i)",
+	/* 12 */	"?",
+	/* 13 */	"invalid IE",
+	/* 14 */	"MIC failure",
+	/* 15 */	"four-way handshake timeout",
+	/* 16 */	"group key handshake timeout",
+	/* 17 */	"IE is different",
+	/* 18 */	"invalid group cipher",
+	/* 19 */	"invalid pairwise cipher",
+	/* 20 */	"invalid AKMP",
+	/* 21 */	"unsupported RSN version",
+	/* 22 */	"invalid RSN IE cap",
+	/* 23 */	"802.1x failed",
+	/* 24 */	"cipher suite rejected"
+	};
+	return reason < VEC_SIZE(reason_str) ? reason_str[reason] : "?";
+}
+
+
+/***********************************************************************
+** acx_cmd_status_str
+*/
+const char*
+acx_cmd_status_str(unsigned int state)
+{
+	static const char * const cmd_error_strings[] = {
+		"Idle",
+		"Success",
+		"Unknown Command",
+		"Invalid Information Element",
+		"Channel rejected",
+		"Channel invalid in current regulatory domain",
+		"MAC invalid",
+		"Command rejected (read-only information element)",
+		"Command rejected",
+		"Already asleep",
+		"TX in progress",
+		"Already awake",
+		"Write only",
+		"RX in progress",
+		"Invalid parameter",
+		"Scan in progress",
+		"Failed"
+	};
+	return state < VEC_SIZE(cmd_error_strings) ?
+			cmd_error_strings[state] : "?";
+}
+
+
+/***********************************************************************
+** get_status_string
+*/
+static inline const char*
+get_status_string(unsigned int status)
+{
+	/* A bit shortened, but hopefully still understandable */
+	static const char * const status_str[] = {
+	/* 0 */	"Successful",
+	/* 1 */	"Unspecified failure",
+	/* 2 */	"reserved",
+	/* 3 */	"reserved",
+	/* 4 */	"reserved",
+	/* 5 */	"reserved",
+	/* 6 */	"reserved",
+	/* 7 */	"reserved",
+	/* 8 */	"reserved",
+	/* 9 */	"reserved",
+	/*10 */	"Cannot support all requested capabilities in Capability Information field",
+	/*11 */	"Reassoc denied (reason outside of 802.11b scope)",
+	/*12 */	"Assoc denied (reason outside of 802.11b scope), maybe MAC filtering by peer?",
+	/*13 */	"Responding station doesnt support specified auth algorithm",
+	/*14 */	"Auth rejected: wrong transaction sequence number",
+	/*15 */	"Auth rejected: challenge failure",
+	/*16 */	"Auth rejected: timeout for next frame in sequence",
+	/*17 */	"Assoc denied: too many STAs on this AP",
+	/*18 */	"Assoc denied: requesting STA doesnt support all data rates in basic set",
+	/*19 */	"Assoc denied: requesting STA doesnt support Short Preamble",
+	/*20 */	"Assoc denied: requesting STA doesnt support PBCC Modulation",
+	/*21 */	"Assoc denied: requesting STA doesnt support Channel Agility"
+	/*22 */	"reserved",
+	/*23 */	"reserved",
+	/*24 */	"reserved",
+	/*25 */	"Assoc denied: requesting STA doesnt support Short Slot Time",
+	/*26 */	"Assoc denied: requesting STA doesnt support DSSS-OFDM"
+	};
+
+	return status_str[status < VEC_SIZE(status_str) ? status : 2];
+}
+
+
+/***********************************************************************
+*/
+void
+acx_log_bad_eid(wlan_hdr_t* hdr, int len, wlan_ie_t* ie_ptr)
+{
+	if (acx_debug & L_ASSOC) {
+		int offset = (u8*)ie_ptr - (u8*)hdr;
+		printk("acx: unknown EID %d in mgmt frame at offset %d. IE: ",
+				ie_ptr->eid, offset);
+	/* IE len can be bogus, IE can extend past packet end. Oh well... */
+		acx_dump_bytes(ie_ptr, ie_ptr->len + 2);
+		if (acx_debug & L_DATA) {
+			printk("frame (%s): ",
+			acx_get_packet_type_string(le16_to_cpu(hdr->fc)));
+			acx_dump_bytes(hdr, len);
+		}
+	}
+}
+
+
+/***********************************************************************
+*/
+#if ACX_DEBUG
+void
+acx_dump_bytes(const void *data, int num)
+{
+	const u8* ptr = (const u8*)data;
+
+	if (num <= 0) {
+		printk("\n");
+		return;
+	}
+
+	while (num >= 16) {
+		printk( "%02X %02X %02X %02X %02X %02X %02X %02X "
+			"%02X %02X %02X %02X %02X %02X %02X %02X\n",
+			ptr[0], ptr[1], ptr[2], ptr[3],
+			ptr[4], ptr[5], ptr[6], ptr[7],
+			ptr[8], ptr[9], ptr[10], ptr[11],
+			ptr[12], ptr[13], ptr[14], ptr[15]);
+		num -= 16;
+		ptr += 16;
+	}
+	if (num > 0) {
+		while (--num > 0)
+			printk("%02X ", *ptr++);
+		printk("%02X\n", *ptr);
+	}
+}
+#endif
+
+
+/***********************************************************************
+** acx_s_get_firmware_version
+*/
+void
+acx_s_get_firmware_version(acx_device_t *adev)
+{
+	fw_ver_t fw;
+	u8 hexarr[4] = { 0, 0, 0, 0 };
+	int hexidx = 0, val = 0;
+	const char *num;
+	char c;
+
+	FN_ENTER;
+
+	memset(fw.fw_id, 'E', FW_ID_SIZE);
+	acx_s_interrogate(adev, &fw, ACX1xx_IE_FWREV);
+	memcpy(adev->firmware_version, fw.fw_id, FW_ID_SIZE);
+	adev->firmware_version[FW_ID_SIZE] = '\0';
+
+	log(L_DEBUG, "fw_ver: fw_id='%s' hw_id=%08X\n",
+				adev->firmware_version, fw.hw_id);
+
+	if (strncmp(fw.fw_id, "Rev ", 4) != 0) {
+		printk("acx: strange firmware version string "
+			"'%s', please report\n", adev->firmware_version);
+		adev->firmware_numver = 0x01090407; /* assume 1.9.4.7 */
+	} else {
+		num = &fw.fw_id[4];
+		while (1) {
+			c = *num++;
+			if ((c == '.') || (c == '\0')) {
+				hexarr[hexidx++] = val;
+				if ((hexidx > 3) || (c == '\0')) /* end? */
+					break;
+				val = 0;
+				continue;
+			}
+			if ((c >= '0') && (c <= '9'))
+				c -= '0';
+			else
+				c = c - 'a' + (char)10;
+			val = val*16 + c;
+		}
+
+		adev->firmware_numver = (u32)(
+				(hexarr[0] << 24) + (hexarr[1] << 16)
+				+ (hexarr[2] << 8) + hexarr[3]);
+		log(L_DEBUG, "firmware_numver 0x%08X\n", adev->firmware_numver);
+	}
+	if (IS_ACX111(adev)) {
+		if (adev->firmware_numver == 0x00010011) {
+			/* This one does not survive floodpinging */
+			printk("acx: firmware '%s' is known to be buggy, "
+				"please upgrade\n", adev->firmware_version);
+		}
+	}
+
+	adev->firmware_id = le32_to_cpu(fw.hw_id);
+
+	/* we're able to find out more detailed chip names now */
+	switch (adev->firmware_id & 0xffff0000) {
+		case 0x01010000:
+		case 0x01020000:
+			adev->chip_name = "TNETW1100A";
+			break;
+		case 0x01030000:
+			adev->chip_name = "TNETW1100B";
+			break;
+		case 0x03000000:
+		case 0x03010000:
+			adev->chip_name = "TNETW1130";
+			break;
+		default:
+			printk("acx: unknown chip ID 0x%08X, "
+				"please report\n", adev->firmware_id);
+			break;
+	}
+
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acx_display_hardware_details
+**
+** Displays hw/fw version, radio type etc...
+*/
+void
+acx_display_hardware_details(acx_device_t *adev)
+{
+	const char *radio_str, *form_str;
+
+	FN_ENTER;
+
+	switch (adev->radio_type) {
+	case RADIO_MAXIM_0D:
+		/* hmm, the DWL-650+ seems to have two variants,
+		 * according to a windows driver changelog comment:
+		 * RFMD and Maxim. */
+		radio_str = "Maxim";
+		break;
+	case RADIO_RFMD_11:
+		radio_str = "RFMD";
+		break;
+	case RADIO_RALINK_15:
+		radio_str = "Ralink";
+		break;
+	case RADIO_RADIA_16:
+		radio_str = "Radia";
+		break;
+	case RADIO_UNKNOWN_17:
+		/* TI seems to have a radio which is
+		 * additionally 802.11a capable, too */
+		radio_str = "802.11a/b/g radio?! Please report";
+		break;
+	case RADIO_UNKNOWN_19:
+		radio_str = "A radio used by Safecom cards?! Please report";
+		break;
+	default:
+		radio_str = "UNKNOWN, please report the radio type name!";
+		break;
+	}
+
+	switch (adev->form_factor) {
+	case 0x00:
+		form_str = "unspecified";
+		break;
+	case 0x01:
+		form_str = "(mini-)PCI / CardBus";
+		break;
+	case 0x02:
+		form_str = "USB";
+		break;
+	case 0x03:
+		form_str = "Compact Flash";
+		break;
+	default:
+		form_str = "UNKNOWN, please report";
+		break;
+	}
+
+	printk("acx: form factor 0x%02X (%s), "
+		"radio type 0x%02X (%s), EEPROM version 0x%02X, "
+		"uploaded firmware '%s' (0x%08X)\n",
+		adev->form_factor, form_str, adev->radio_type, radio_str,
+		adev->eeprom_version, adev->firmware_version,
+		adev->firmware_id);
+
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+*/
+int
+acx_e_change_mtu(struct net_device *ndev, int mtu)
+{
+	enum {
+		MIN_MTU = 256,
+		MAX_MTU = WLAN_DATA_MAXLEN - (ETH_HLEN)
+	};
+
+	if (mtu < MIN_MTU || mtu > MAX_MTU)
+		return -EINVAL;
+
+	ndev->mtu = mtu;
+	return 0;
+}
+
+
+/***********************************************************************
+** acx_e_get_stats, acx_e_get_wireless_stats
+*/
+struct net_device_stats*
+acx_e_get_stats(struct net_device *ndev)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	return &adev->stats;
+}
+
+struct iw_statistics*
+acx_e_get_wireless_stats(struct net_device *ndev)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	return &adev->wstats;
+}
+
+
+/***********************************************************************
+** maps acx111 tx descr rate field to acx100 one
+*/
+const u8
+acx_bitpos2rate100[] = {
+	RATE100_1	,/* 0 */
+	RATE100_2	,/* 1 */
+	RATE100_5	,/* 2 */
+	RATE100_2	,/* 3, should not happen */
+	RATE100_2	,/* 4, should not happen */
+	RATE100_11	,/* 5 */
+	RATE100_2	,/* 6, should not happen */
+	RATE100_2	,/* 7, should not happen */
+	RATE100_22	,/* 8 */
+	RATE100_2	,/* 9, should not happen */
+	RATE100_2	,/* 10, should not happen */
+	RATE100_2	,/* 11, should not happen */
+	RATE100_2	,/* 12, should not happen */
+	RATE100_2	,/* 13, should not happen */
+	RATE100_2	,/* 14, should not happen */
+	RATE100_2	,/* 15, should not happen */
+};
+
+u8
+acx_rate111to100(u16 r) {
+	return acx_bitpos2rate100[highest_bit(r)];
+}
+
+
+/***********************************************************************
+** Calculate level like the feb 2003 windows driver seems to do
+*/
+static u8
+acx_signal_to_winlevel(u8 rawlevel)
+{
+	/* u8 winlevel = (u8) (0.5 + 0.625 * rawlevel); */
+	u8 winlevel = ((4 + (rawlevel * 5)) / 8);
+
+	if (winlevel > 100)
+		winlevel = 100;
+	return winlevel;
+}
+
+u8
+acx_signal_determine_quality(u8 signal, u8 noise)
+{
+	int qual;
+
+	qual = (((signal - 30) * 100 / 70) + (100 - noise * 4)) / 2;
+
+	if (qual > 100)
+		return 100;
+	if (qual < 0)
+		return 0;
+	return qual;
+}
+
+
+/***********************************************************************
+** Interrogate/configure commands
+*/
+
+/* FIXME: the lengths given here probably aren't always correct.
+ * They should be gradually replaced by proper "sizeof(acx1XX_ie_XXXX)-4",
+ * unless the firmware actually expects a different length than the struct length */
+static const u16
+acx100_ie_len[] = {
+	0,
+	ACX100_IE_ACX_TIMER_LEN,
+	sizeof(acx100_ie_powersave_t)-4, /* is that 6 or 8??? */
+	ACX1xx_IE_QUEUE_CONFIG_LEN,
+	ACX100_IE_BLOCK_SIZE_LEN,
+	ACX1xx_IE_MEMORY_CONFIG_OPTIONS_LEN,
+	ACX1xx_IE_RATE_FALLBACK_LEN,
+	ACX100_IE_WEP_OPTIONS_LEN,
+	ACX1xx_IE_MEMORY_MAP_LEN, /*	ACX1xx_IE_SSID_LEN, */
+	0,
+	ACX1xx_IE_ASSOC_ID_LEN,
+	0,
+	ACX111_IE_CONFIG_OPTIONS_LEN,
+	ACX1xx_IE_FWREV_LEN,
+	ACX1xx_IE_FCS_ERROR_COUNT_LEN,
+	ACX1xx_IE_MEDIUM_USAGE_LEN,
+	ACX1xx_IE_RXCONFIG_LEN,
+	0,
+	0,
+	ACX1xx_IE_FIRMWARE_STATISTICS_LEN,
+	0,
+	ACX1xx_IE_FEATURE_CONFIG_LEN,
+	ACX111_IE_KEY_CHOOSE_LEN,
+};
+
+static const u16
+acx100_ie_len_dot11[] = {
+	0,
+	ACX1xx_IE_DOT11_STATION_ID_LEN,
+	0,
+	ACX100_IE_DOT11_BEACON_PERIOD_LEN,
+	ACX1xx_IE_DOT11_DTIM_PERIOD_LEN,
+	ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT_LEN,
+	ACX1xx_IE_DOT11_LONG_RETRY_LIMIT_LEN,
+	ACX100_IE_DOT11_WEP_DEFAULT_KEY_WRITE_LEN,
+	ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME_LEN,
+	0,
+	ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN_LEN,
+	ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN,
+	0,
+	ACX1xx_IE_DOT11_TX_POWER_LEVEL_LEN,
+	ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN,
+	ACX100_IE_DOT11_ED_THRESHOLD_LEN,
+	ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET_LEN,
+	0,
+	0,
+	0,
+};
+
+static const u16
+acx111_ie_len[] = {
+	0,
+	ACX100_IE_ACX_TIMER_LEN,
+	sizeof(acx111_ie_powersave_t)-4,
+	ACX1xx_IE_QUEUE_CONFIG_LEN,
+	ACX100_IE_BLOCK_SIZE_LEN,
+	ACX1xx_IE_MEMORY_CONFIG_OPTIONS_LEN,
+	ACX1xx_IE_RATE_FALLBACK_LEN,
+	ACX100_IE_WEP_OPTIONS_LEN,
+	ACX1xx_IE_MEMORY_MAP_LEN, /*	ACX1xx_IE_SSID_LEN, */
+	0,
+	ACX1xx_IE_ASSOC_ID_LEN,
+	0,
+	ACX111_IE_CONFIG_OPTIONS_LEN,
+	ACX1xx_IE_FWREV_LEN,
+	ACX1xx_IE_FCS_ERROR_COUNT_LEN,
+	ACX1xx_IE_MEDIUM_USAGE_LEN,
+	ACX1xx_IE_RXCONFIG_LEN,
+	0,
+	0,
+	ACX1xx_IE_FIRMWARE_STATISTICS_LEN,
+	0,
+	ACX1xx_IE_FEATURE_CONFIG_LEN,
+	ACX111_IE_KEY_CHOOSE_LEN,
+};
+
+static const u16
+acx111_ie_len_dot11[] = {
+	0,
+	ACX1xx_IE_DOT11_STATION_ID_LEN,
+	0,
+	ACX100_IE_DOT11_BEACON_PERIOD_LEN,
+	ACX1xx_IE_DOT11_DTIM_PERIOD_LEN,
+	ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT_LEN,
+	ACX1xx_IE_DOT11_LONG_RETRY_LIMIT_LEN,
+	ACX100_IE_DOT11_WEP_DEFAULT_KEY_WRITE_LEN,
+	ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME_LEN,
+	0,
+	ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN_LEN,
+	ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN,
+	0,
+	ACX1xx_IE_DOT11_TX_POWER_LEVEL_LEN,
+	ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN,
+	ACX100_IE_DOT11_ED_THRESHOLD_LEN,
+	ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET_LEN,
+	0,
+	0,
+	0,
+};
+
+
+#undef FUNC
+#define FUNC "configure"
+#if !ACX_DEBUG
+int
+acx_s_configure(acx_device_t *adev, void *pdr, int type)
+{
+#else
+int
+acx_s_configure_debug(acx_device_t *adev, void *pdr, int type, const char* typestr)
+{
+#endif
+	u16 len;
+	int res;
+
+	if (type < 0x1000)
+		len = adev->ie_len[type];
+	else
+		len = adev->ie_len_dot11[type - 0x1000];
+
+	log(L_CTL, FUNC"(type:%s,len:%u)\n", typestr, len);
+	if (unlikely(!len)) {
+		log(L_DEBUG, "zero-length type %s?!\n", typestr);
+	}
+
+	((acx_ie_generic_t *)pdr)->type = cpu_to_le16(type);
+	((acx_ie_generic_t *)pdr)->len = cpu_to_le16(len);
+	res = acx_s_issue_cmd(adev, ACX1xx_CMD_CONFIGURE, pdr, len + 4);
+	if (unlikely(OK != res)) {
+#if ACX_DEBUG
+		printk("%s: "FUNC"(type:%s) FAILED\n", adev->ndev->name, typestr);
+#else
+		printk("%s: "FUNC"(type:0x%X) FAILED\n", adev->ndev->name, type);
+#endif
+		/* dump_stack() is already done in issue_cmd() */
+	}
+	return res;
+}
+
+#undef FUNC
+#define FUNC "interrogate"
+#if !ACX_DEBUG
+int
+acx_s_interrogate(acx_device_t *adev, void *pdr, int type)
+{
+#else
+int
+acx_s_interrogate_debug(acx_device_t *adev, void *pdr, int type,
+		const char* typestr)
+{
+#endif
+	u16 len;
+	int res;
+
+	if (type < 0x1000)
+		len = adev->ie_len[type];
+	else
+		len = adev->ie_len_dot11[type-0x1000];
+
+	log(L_CTL, FUNC"(type:%s,len:%u)\n", typestr, len);
+
+	((acx_ie_generic_t *)pdr)->type = cpu_to_le16(type);
+	((acx_ie_generic_t *)pdr)->len = cpu_to_le16(len);
+	res = acx_s_issue_cmd(adev, ACX1xx_CMD_INTERROGATE, pdr, len + 4);
+	if (unlikely(OK != res)) {
+#if ACX_DEBUG
+		printk("%s: "FUNC"(type:%s) FAILED\n", adev->ndev->name, typestr);
+#else
+		printk("%s: "FUNC"(type:0x%X) FAILED\n", adev->ndev->name, type);
+#endif
+		/* dump_stack() is already done in issue_cmd() */
+	}
+	return res;
+}
+
+#if CMD_DISCOVERY
+void
+great_inquisitor(acx_device_t *adev)
+{
+	static struct {
+		u16	type ACX_PACKED;
+		u16	len ACX_PACKED;
+		/* 0x200 was too large here: */
+		u8	data[0x100 - 4] ACX_PACKED;
+	} ie;
+	u16 type;
+
+	FN_ENTER;
+
+	/* 0..0x20, 0x1000..0x1020 */
+	for (type = 0; type <= 0x1020; type++) {
+		if (type == 0x21)
+			type = 0x1000;
+		ie.type = cpu_to_le16(type);
+		ie.len = cpu_to_le16(sizeof(ie) - 4);
+		acx_s_issue_cmd(adev, ACX1xx_CMD_INTERROGATE, &ie, sizeof(ie));
+	}
+	FN_EXIT0;
+}
+#endif
+
+
+#ifdef CONFIG_PROC_FS
+/***********************************************************************
+** /proc files
+*/
+/***********************************************************************
+** acx_l_proc_output
+** Generate content for our /proc entry
+**
+** Arguments:
+**	buf is a pointer to write output to
+**	adev is the usual pointer to our private struct acx_device
+** Returns:
+**	number of bytes actually written to buf
+** Side effects:
+**	none
+*/
+static int
+acx_l_proc_output(char *buf, acx_device_t *adev)
+{
+	char *p = buf;
+	int i;
+
+	FN_ENTER;
+
+	p += sprintf(p,
+		"acx driver version:\t\t" ACX_RELEASE "\n"
+		"Wireless extension version:\t" STRING(WIRELESS_EXT) "\n"
+		"chip name:\t\t\t%s (0x%08X)\n"
+		"radio type:\t\t\t0x%02X\n"
+		"form factor:\t\t\t0x%02X\n"
+		"EEPROM version:\t\t\t0x%02X\n"
+		"firmware version:\t\t%s (0x%08X)\n",
+		adev->chip_name, adev->firmware_id,
+		adev->radio_type,
+		adev->form_factor,
+		adev->eeprom_version,
+		adev->firmware_version, adev->firmware_numver);
+
+	for (i = 0; i < VEC_SIZE(adev->sta_list); i++) {
+		struct client *bss = &adev->sta_list[i];
+		if (!bss->used) continue;
+		p += sprintf(p, "BSS %u BSSID "MACSTR" ESSID %s channel %u "
+			"Cap 0x%X SIR %u SNR %u\n",
+			i, MAC(bss->bssid), (char*)bss->essid, bss->channel,
+			bss->cap_info, bss->sir, bss->snr);
+	}
+	p += sprintf(p, "status:\t\t\t%u (%s)\n",
+			adev->status, acx_get_status_name(adev->status));
+
+	FN_EXIT1(p - buf);
+	return p - buf;
+}
+
+
+/***********************************************************************
+*/
+static int
+acx_s_proc_diag_output(char *buf, acx_device_t *adev)
+{
+	char *p = buf;
+	fw_stats_t *fw_stats;
+	unsigned long flags;
+
+	FN_ENTER;
+
+	/* TODO: may replace kmalloc/memset with kzalloc once
+	 * Linux 2.6.14 is widespread */
+	fw_stats = kmalloc(sizeof(*fw_stats), GFP_KERNEL);
+	if (!fw_stats) {
+		FN_EXIT1(0);
+		return 0;
+	}
+	memset(fw_stats, 0, sizeof(*fw_stats));
+
+	acx_lock(adev, flags);
+
+	if (IS_PCI(adev))
+		p = acxpci_s_proc_diag_output(p, adev);
+
+	p += sprintf(p,
+		"\n"
+		"** network status **\n"
+		"dev_state_mask 0x%04X\n"
+		"status %u (%s), "
+		"mode %u, channel %u, "
+		"reg_dom_id 0x%02X, reg_dom_chanmask 0x%04X, ",
+		adev->dev_state_mask,
+		adev->status, acx_get_status_name(adev->status),
+		adev->mode, adev->channel,
+		adev->reg_dom_id, adev->reg_dom_chanmask
+		);
+	p += sprintf(p,
+		"ESSID \"%s\", essid_active %d, essid_len %d, "
+		"essid_for_assoc \"%s\", nick \"%s\"\n"
+		"WEP ena %d, restricted %d, idx %d\n",
+		adev->essid, adev->essid_active, (int)adev->essid_len,
+		adev->essid_for_assoc, adev->nick,
+		adev->wep_enabled, adev->wep_restricted,
+		adev->wep_current_index);
+	p += sprintf(p, "dev_addr  "MACSTR"\n", MAC(adev->dev_addr));
+	p += sprintf(p, "bssid     "MACSTR"\n", MAC(adev->bssid));
+	p += sprintf(p, "ap_filter "MACSTR"\n", MAC(adev->ap));
+
+	p += sprintf(p,
+		"\n"
+		"** PHY status **\n"
+		"tx_disabled %d, tx_level_dbm %d\n" /* "tx_level_val %d, tx_level_auto %d\n" */
+		"sensitivity %d, antenna 0x%02X, ed_threshold %d, cca %d, preamble_mode %d\n"
+		"rts_threshold %d, frag_threshold %d, short_retry %d, long_retry %d\n"
+		"msdu_lifetime %d, listen_interval %d, beacon_interval %d\n",
+		adev->tx_disabled, adev->tx_level_dbm, /* adev->tx_level_val, adev->tx_level_auto, */
+		adev->sensitivity, adev->antenna, adev->ed_threshold, adev->cca, adev->preamble_mode,
+		adev->rts_threshold, adev->frag_threshold, adev->short_retry, adev->long_retry,
+		adev->msdu_lifetime, adev->listen_interval, adev->beacon_interval);
+
+	acx_unlock(adev, flags);
+
+	if (OK != acx_s_interrogate(adev, fw_stats, ACX1xx_IE_FIRMWARE_STATISTICS))
+		p += sprintf(p,
+			"\n"
+			"** Firmware **\n"
+			"QUERY FAILED!!\n");
+	else {
+		p += sprintf(p,
+			"\n"
+			"** Firmware **\n"
+			"version \"%s\"\n"
+			"tx_desc_overfl %u, rx_OutOfMem %u, rx_hdr_overfl %u, rx_hdr_use_next %u\n"
+			"rx_dropped_frame %u, rx_frame_ptr_err %u, rx_xfr_hint_trig %u, rx_dma_req %u\n"
+			"rx_dma_err %u, tx_dma_req %u, tx_dma_err %u, cmd_cplt %u, fiq %u\n"
+			"rx_hdrs %u, rx_cmplt %u, rx_mem_overfl %u, rx_rdys %u, irqs %u\n"
+			"acx_trans_procs %u, decrypt_done %u, dma_0_done %u, dma_1_done %u\n",
+			adev->firmware_version,
+			le32_to_cpu(fw_stats->tx_desc_of),
+			le32_to_cpu(fw_stats->rx_oom),
+			le32_to_cpu(fw_stats->rx_hdr_of),
+			le32_to_cpu(fw_stats->rx_hdr_use_next),
+			le32_to_cpu(fw_stats->rx_dropped_frame),
+			le32_to_cpu(fw_stats->rx_frame_ptr_err),
+			le32_to_cpu(fw_stats->rx_xfr_hint_trig),
+			le32_to_cpu(fw_stats->rx_dma_req),
+			le32_to_cpu(fw_stats->rx_dma_err),
+			le32_to_cpu(fw_stats->tx_dma_req),
+			le32_to_cpu(fw_stats->tx_dma_err),
+			le32_to_cpu(fw_stats->cmd_cplt),
+			le32_to_cpu(fw_stats->fiq),
+			le32_to_cpu(fw_stats->rx_hdrs),
+			le32_to_cpu(fw_stats->rx_cmplt),
+			le32_to_cpu(fw_stats->rx_mem_of),
+			le32_to_cpu(fw_stats->rx_rdys),
+			le32_to_cpu(fw_stats->irqs),
+			le32_to_cpu(fw_stats->acx_trans_procs),
+			le32_to_cpu(fw_stats->decrypt_done),
+			le32_to_cpu(fw_stats->dma_0_done),
+			le32_to_cpu(fw_stats->dma_1_done));
+		p += sprintf(p,
+			"tx_exch_complet %u, commands %u, acx_rx_procs %u\n"
+			"hw_pm_mode_changes %u, host_acks %u, pci_pm %u, acm_wakeups %u\n"
+			"wep_key_count %u, wep_default_key_count %u, dot11_def_key_mib %u\n"
+			"wep_key_not_found %u, wep_decrypt_fail %u\n",
+			le32_to_cpu(fw_stats->tx_exch_complet),
+			le32_to_cpu(fw_stats->commands),
+			le32_to_cpu(fw_stats->acx_rx_procs),
+			le32_to_cpu(fw_stats->hw_pm_mode_changes),
+			le32_to_cpu(fw_stats->host_acks),
+			le32_to_cpu(fw_stats->pci_pm),
+			le32_to_cpu(fw_stats->acm_wakeups),
+			le32_to_cpu(fw_stats->wep_key_count),
+			le32_to_cpu(fw_stats->wep_default_key_count),
+			le32_to_cpu(fw_stats->dot11_def_key_mib),
+			le32_to_cpu(fw_stats->wep_key_not_found),
+			le32_to_cpu(fw_stats->wep_decrypt_fail));
+	}
+
+	kfree(fw_stats);
+
+	FN_EXIT1(p - buf);
+	return p - buf;
+}
+
+
+/***********************************************************************
+*/
+static int
+acx_s_proc_phy_output(char *buf, acx_device_t *adev)
+{
+	char *p = buf;
+	int i;
+
+	FN_ENTER;
+
+	/*
+	if (RADIO_RFMD_11 != adev->radio_type) {
+		printk("sorry, not yet adapted for radio types "
+			"other than RFMD, please verify "
+			"PHY size etc. first!\n");
+		goto end;
+	}
+	*/
+
+	/* The PHY area is only 0x80 bytes long; further pages after that
+	 * only have some page number registers with altered value,
+	 * all other registers remain the same. */
+	for (i = 0; i < 0x80; i++) {
+		acx_s_read_phy_reg(adev, i, p++);
+	}
+
+	FN_EXIT1(p - buf);
+	return p - buf;
+}
+
+
+/***********************************************************************
+** acx_e_read_proc_XXXX
+** Handle our /proc entry
+**
+** Arguments:
+**	standard kernel read_proc interface
+** Returns:
+**	number of bytes written to buf
+** Side effects:
+**	none
+*/
+static int
+acx_e_read_proc(char *buf, char **start, off_t offset, int count,
+		     int *eof, void *data)
+{
+	acx_device_t *adev = (acx_device_t*)data;
+	unsigned long flags;
+	int length;
+
+	FN_ENTER;
+
+	acx_sem_lock(adev);
+	acx_lock(adev, flags);
+	/* fill buf */
+	length = acx_l_proc_output(buf, adev);
+	acx_unlock(adev, flags);
+	acx_sem_unlock(adev);
+
+	/* housekeeping */
+	if (length <= offset + count)
+		*eof = 1;
+	*start = buf + offset;
+	length -= offset;
+	if (length > count)
+		length = count;
+	if (length < 0)
+		length = 0;
+	FN_EXIT1(length);
+	return length;
+}
+
+static int
+acx_e_read_proc_diag(char *buf, char **start, off_t offset, int count,
+		     int *eof, void *data)
+{
+	acx_device_t *adev = (acx_device_t*)data;
+	int length;
+
+	FN_ENTER;
+
+	acx_sem_lock(adev);
+	/* fill buf */
+	length = acx_s_proc_diag_output(buf, adev);
+	acx_sem_unlock(adev);
+
+	/* housekeeping */
+	if (length <= offset + count)
+		*eof = 1;
+	*start = buf + offset;
+	length -= offset;
+	if (length > count)
+		length = count;
+	if (length < 0)
+		length = 0;
+	FN_EXIT1(length);
+	return length;
+}
+
+static int
+acx_e_read_proc_eeprom(char *buf, char **start, off_t offset, int count,
+		     int *eof, void *data)
+{
+	acx_device_t *adev = (acx_device_t*)data;
+	int length;
+
+	FN_ENTER;
+
+	/* fill buf */
+	length = 0;
+	if (IS_PCI(adev)) {
+		acx_sem_lock(adev);
+		length = acxpci_proc_eeprom_output(buf, adev);
+		acx_sem_unlock(adev);
+	}
+
+	/* housekeeping */
+	if (length <= offset + count)
+		*eof = 1;
+	*start = buf + offset;
+	length -= offset;
+	if (length > count)
+		length = count;
+	if (length < 0)
+		length = 0;
+	FN_EXIT1(length);
+	return length;
+}
+
+static int
+acx_e_read_proc_phy(char *buf, char **start, off_t offset, int count,
+		     int *eof, void *data)
+{
+	acx_device_t *adev = (acx_device_t*)data;
+	int length;
+
+	FN_ENTER;
+
+	acx_sem_lock(adev);
+	/* fill buf */
+	length = acx_s_proc_phy_output(buf, adev);
+	acx_sem_unlock(adev);
+
+	/* housekeeping */
+	if (length <= offset + count)
+		*eof = 1;
+	*start = buf + offset;
+	length -= offset;
+	if (length > count)
+		length = count;
+	if (length < 0)
+		length = 0;
+	FN_EXIT1(length);
+	return length;
+}
+
+
+/***********************************************************************
+** /proc files registration
+*/
+static const char * const
+proc_files[] = { "", "_diag", "_eeprom", "_phy" };
+
+static read_proc_t * const
+proc_funcs[] = {
+	acx_e_read_proc,
+	acx_e_read_proc_diag,
+	acx_e_read_proc_eeprom,
+	acx_e_read_proc_phy
+};
+
+static int
+manage_proc_entries(const struct net_device *ndev, int remove)
+{
+	acx_device_t *adev = ndev2adev((struct net_device *)ndev);
+	char procbuf[80];
+	int i;
+
+	for (i = 0; i < VEC_SIZE(proc_files); i++)	{
+		snprintf(procbuf, sizeof(procbuf),
+			"driver/acx_%s%s", ndev->name, proc_files[i]);
+		log(L_INIT, "%sing /proc entry %s\n",
+			remove ? "remov" : "creat", procbuf);
+		if (!remove) {
+			if (!create_proc_read_entry(procbuf, 0, 0, proc_funcs[i], adev)) {
+				printk("acx: cannot register /proc entry %s\n", procbuf);
+				return NOT_OK;
+			}
+		} else {
+			remove_proc_entry(procbuf, NULL);
+		}
+	}
+	return OK;
+}
+
+int
+acx_proc_register_entries(const struct net_device *ndev)
+{
+	return manage_proc_entries(ndev, 0);
+}
+
+int
+acx_proc_unregister_entries(const struct net_device *ndev)
+{
+	return manage_proc_entries(ndev, 1);
+}
+#endif /* CONFIG_PROC_FS */
+
+
+/***********************************************************************
+** acx_cmd_join_bssid
+**
+** Common code for both acx100 and acx111.
+*/
+/* NB: does NOT match RATE100_nn but matches ACX[111]_SCAN_RATE_n */
+static const u8
+bitpos2genframe_txrate[] = {
+	10,	/*  0.  1 Mbit/s */
+	20,	/*  1.  2 Mbit/s */
+	55,	/*  2.  5.5 Mbit/s */
+	0x0B,	/*  3.  6 Mbit/s */
+	0x0F,	/*  4.  9 Mbit/s */
+	110,	/*  5. 11 Mbit/s */
+	0x0A,	/*  6. 12 Mbit/s */
+	0x0E,	/*  7. 18 Mbit/s */
+	220,	/*  8. 22 Mbit/s */
+	0x09,	/*  9. 24 Mbit/s */
+	0x0D,	/* 10. 36 Mbit/s */
+	0x08,	/* 11. 48 Mbit/s */
+	0x0C,	/* 12. 54 Mbit/s */
+	10,	/* 13.  1 Mbit/s, should never happen */
+	10,	/* 14.  1 Mbit/s, should never happen */
+	10,	/* 15.  1 Mbit/s, should never happen */
+};
+
+/* Looks scary, eh?
+** Actually, each one compiled into one AND and one SHIFT,
+** 31 bytes in x86 asm (more if uints are replaced by u16/u8) */
+static inline unsigned int
+rate111to5bits(unsigned int rate)
+{
+	return (rate & 0x7)
+	| ( (rate & RATE111_11) / (RATE111_11/JOINBSS_RATES_11) )
+	| ( (rate & RATE111_22) / (RATE111_22/JOINBSS_RATES_22) )
+	;
+}
+
+static void
+acx_s_cmd_join_bssid(acx_device_t *adev, const u8 *bssid)
+{
+	acx_joinbss_t tmp;
+	int dtim_interval;
+	int i;
+
+	if (mac_is_zero(bssid))
+		return;
+
+	FN_ENTER;
+
+	dtim_interval =	(ACX_MODE_0_ADHOC == adev->mode) ?
+			1 : adev->dtim_interval;
+
+	memset(&tmp, 0, sizeof(tmp));
+
+	for (i = 0; i < ETH_ALEN; i++) {
+		tmp.bssid[i] = bssid[ETH_ALEN-1 - i];
+	}
+
+	tmp.beacon_interval = cpu_to_le16(adev->beacon_interval);
+
+	/* Basic rate set. Control frame responses (such as ACK or CTS frames)
+	** are sent with one of these rates */
+	if (IS_ACX111(adev)) {
+		/* It was experimentally determined that rates_basic
+		** can take 11g rates as well, not only rates
+		** defined with JOINBSS_RATES_BASIC111_nnn.
+		** Just use RATE111_nnn constants... */
+		tmp.u.acx111.dtim_interval = dtim_interval;
+		tmp.u.acx111.rates_basic = cpu_to_le16(adev->rate_basic);
+		log(L_ASSOC, "rates_basic:%04X, rates_supported:%04X\n",
+			adev->rate_basic, adev->rate_oper);
+	} else {
+		tmp.u.acx100.dtim_interval = dtim_interval;
+		tmp.u.acx100.rates_basic = rate111to5bits(adev->rate_basic);
+		tmp.u.acx100.rates_supported = rate111to5bits(adev->rate_oper);
+		log(L_ASSOC, "rates_basic:%04X->%02X, "
+			"rates_supported:%04X->%02X\n",
+			adev->rate_basic, tmp.u.acx100.rates_basic,
+			adev->rate_oper, tmp.u.acx100.rates_supported);
+	}
+
+	/* Setting up how Beacon, Probe Response, RTS, and PS-Poll frames
+	** will be sent (rate/modulation/preamble) */
+	tmp.genfrm_txrate = bitpos2genframe_txrate[lowest_bit(adev->rate_basic)];
+	tmp.genfrm_mod_pre = 0; /* FIXME: was = adev->capab_short (which was always 0); */
+	/* we can use short pre *if* all peers can understand it */
+	/* FIXME #2: we need to correctly set PBCC/OFDM bits here too */
+
+	/* we switch fw to STA mode in MONITOR mode, it seems to be
+	** the only mode where fw does not emit beacons by itself
+	** but allows us to send anything (we really want to retain
+	** ability to tx arbitrary frames in MONITOR mode)
+	*/
+	tmp.macmode = (adev->mode != ACX_MODE_MONITOR ? adev->mode : ACX_MODE_2_STA);
+	tmp.channel = adev->channel;
+	tmp.essid_len = adev->essid_len;
+	/* NOTE: the code memcpy'd essid_len + 1 before, which is WRONG! */
+	memcpy(tmp.essid, adev->essid, tmp.essid_len);
+	acx_s_issue_cmd(adev, ACX1xx_CMD_JOIN, &tmp, tmp.essid_len + 0x11);
+
+	log(L_ASSOC|L_DEBUG, "BSS_Type = %u\n", tmp.macmode);
+	acxlog_mac(L_ASSOC|L_DEBUG, "JoinBSSID MAC:", adev->bssid, "\n");
+
+	acx_update_capabilities(adev);
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acx_s_cmd_start_scan
+**
+** Issue scan command to the hardware
+**
+** unified function for both ACX111 and ACX100
+*/
+static void
+acx_s_scan_chan(acx_device_t *adev)
+{
+	union {
+		acx111_scan_t acx111;
+		acx100_scan_t acx100;
+	} s;
+
+	FN_ENTER;
+
+	memset(&s, 0, sizeof(s));
+
+	/* first common positions... */
+
+	s.acx111.count = cpu_to_le16(adev->scan_count);
+	s.acx111.rate = adev->scan_rate;
+	s.acx111.options = adev->scan_mode;
+	s.acx111.chan_duration = cpu_to_le16(adev->scan_duration);
+	s.acx111.max_probe_delay = cpu_to_le16(adev->scan_probe_delay);
+
+	/* ...then differences */
+
+	if (IS_ACX111(adev)) {
+		s.acx111.channel_list_select = 0; /* scan every allowed channel */
+		/*s.acx111.channel_list_select = 1;*/ /* scan given channels */
+		/*s.acx111.modulation = 0x40;*/ /* long preamble? OFDM? -> only for active scan */
+		s.acx111.modulation = 0;
+		/*s.acx111.channel_list[0] = 6;
+		s.acx111.channel_list[1] = 4;*/
+	} else {
+		s.acx100.start_chan = cpu_to_le16(1);
+		s.acx100.flags = cpu_to_le16(0x8000);
+	}
+
+	acx_s_issue_cmd(adev, ACX1xx_CMD_SCAN, &s, sizeof(s));
+	FN_EXIT0;
+}
+
+
+void
+acx_s_cmd_start_scan(acx_device_t *adev)
+{
+	/* time_before check is 'just in case' thing */
+	if (!(adev->irq_status & HOST_INT_SCAN_COMPLETE)
+	 && time_before(jiffies, adev->scan_start + 10*HZ)
+	) {
+		log(L_INIT, "start_scan: seems like previous scan "
+		"is still running. Not starting anew. Please report\n");
+		return;
+	}
+
+	log(L_INIT, "starting radio scan\n");
+	/* remember that fw is commanded to do scan */
+	adev->scan_start = jiffies;
+	CLEAR_BIT(adev->irq_status, HOST_INT_SCAN_COMPLETE);
+	/* issue it */
+	acx_s_scan_chan(adev);
+}
+
+
+/***********************************************************************
+** acx111 feature config
+*/
+static int
+acx111_s_get_feature_config(acx_device_t *adev,
+		u32 *feature_options, u32 *data_flow_options)
+{
+	struct acx111_ie_feature_config feat;
+
+	if (!IS_ACX111(adev)) {
+		return NOT_OK;
+	}
+
+	memset(&feat, 0, sizeof(feat));
+
+	if (OK != acx_s_interrogate(adev, &feat, ACX1xx_IE_FEATURE_CONFIG)) {
+		return NOT_OK;
+	}
+	log(L_DEBUG,
+		"got Feature option:0x%X, DataFlow option: 0x%X\n",
+		feat.feature_options,
+		feat.data_flow_options);
+
+	if (feature_options)
+		*feature_options = le32_to_cpu(feat.feature_options);
+	if (data_flow_options)
+		*data_flow_options = le32_to_cpu(feat.data_flow_options);
+
+	return OK;
+}
+
+static int
+acx111_s_set_feature_config(acx_device_t *adev,
+	u32 feature_options, u32 data_flow_options,
+	unsigned int mode /* 0 == remove, 1 == add, 2 == set */)
+{
+	struct acx111_ie_feature_config feat;
+
+	if (!IS_ACX111(adev)) {
+		return NOT_OK;
+	}
+
+	if ((mode < 0) || (mode > 2))
+		return NOT_OK;
+
+	if (mode != 2)
+		/* need to modify old data */
+		acx111_s_get_feature_config(adev, &feat.feature_options, &feat.data_flow_options);
+	else {
+		/* need to set a completely new value */
+		feat.feature_options = 0;
+		feat.data_flow_options = 0;
+	}
+
+	if (mode == 0) { /* remove */
+		CLEAR_BIT(feat.feature_options, cpu_to_le32(feature_options));
+		CLEAR_BIT(feat.data_flow_options, cpu_to_le32(data_flow_options));
+	} else { /* add or set */
+		SET_BIT(feat.feature_options, cpu_to_le32(feature_options));
+		SET_BIT(feat.data_flow_options, cpu_to_le32(data_flow_options));
+	}
+
+	log(L_DEBUG,
+		"old: feature 0x%08X dataflow 0x%08X. mode: %u\n"
+		"new: feature 0x%08X dataflow 0x%08X\n",
+		feature_options, data_flow_options, mode,
+		le32_to_cpu(feat.feature_options),
+		le32_to_cpu(feat.data_flow_options));
+
+	if (OK != acx_s_configure(adev, &feat, ACX1xx_IE_FEATURE_CONFIG)) {
+		return NOT_OK;
+	}
+
+	return OK;
+}
+
+static inline int
+acx111_s_feature_off(acx_device_t *adev, u32 f, u32 d)
+{
+	return acx111_s_set_feature_config(adev, f, d, 0);
+}
+static inline int
+acx111_s_feature_on(acx_device_t *adev, u32 f, u32 d)
+{
+	return acx111_s_set_feature_config(adev, f, d, 1);
+}
+static inline int
+acx111_s_feature_set(acx_device_t *adev, u32 f, u32 d)
+{
+	return acx111_s_set_feature_config(adev, f, d, 2);
+}
+
+
+/***********************************************************************
+** acx100_s_init_memory_pools
+*/
+static int
+acx100_s_init_memory_pools(acx_device_t *adev, const acx_ie_memmap_t *mmt)
+{
+	acx100_ie_memblocksize_t MemoryBlockSize;
+	acx100_ie_memconfigoption_t MemoryConfigOption;
+	int TotalMemoryBlocks;
+	int RxBlockNum;
+	int TotalRxBlockSize;
+	int TxBlockNum;
+	int TotalTxBlockSize;
+
+	FN_ENTER;
+
+	/* Let's see if we can follow this:
+	   first we select our memory block size (which I think is
+	   completely arbitrary) */
+	MemoryBlockSize.size = cpu_to_le16(adev->memblocksize);
+
+	/* Then we alert the card to our decision of block size */
+	if (OK != acx_s_configure(adev, &MemoryBlockSize, ACX100_IE_BLOCK_SIZE)) {
+		goto bad;
+	}
+
+	/* We figure out how many total blocks we can create, using
+	   the block size we chose, and the beginning and ending
+	   memory pointers, i.e.: end-start/size */
+	TotalMemoryBlocks = (le32_to_cpu(mmt->PoolEnd) - le32_to_cpu(mmt->PoolStart)) / adev->memblocksize;
+
+	log(L_DEBUG, "TotalMemoryBlocks=%u (%u bytes)\n",
+		TotalMemoryBlocks, TotalMemoryBlocks*adev->memblocksize);
+
+	/* MemoryConfigOption.DMA_config bitmask:
+			access to ACX memory is to be done:
+	0x00080000	using PCI conf space?!
+	0x00040000	using IO instructions?
+	0x00000000	using memory access instructions
+	0x00020000	using local memory block linked list (else what?)
+	0x00010000	using host indirect descriptors (else host must access ACX memory?)
+	*/
+	if (IS_PCI(adev)) {
+		MemoryConfigOption.DMA_config = cpu_to_le32(0x30000);
+		/* Declare start of the Rx host pool */
+		MemoryConfigOption.pRxHostDesc = cpu2acx(adev->rxhostdesc_startphy);
+		log(L_DEBUG, "pRxHostDesc 0x%08X, rxhostdesc_startphy 0x%lX\n",
+				acx2cpu(MemoryConfigOption.pRxHostDesc),
+				(long)adev->rxhostdesc_startphy);
+	} else {
+		MemoryConfigOption.DMA_config = cpu_to_le32(0x20000);
+	}
+
+	/* 50% of the allotment of memory blocks go to tx descriptors */
+	TxBlockNum = TotalMemoryBlocks / 2;
+	MemoryConfigOption.TxBlockNum = cpu_to_le16(TxBlockNum);
+
+	/* and 50% go to the rx descriptors */
+	RxBlockNum = TotalMemoryBlocks - TxBlockNum;
+	MemoryConfigOption.RxBlockNum = cpu_to_le16(RxBlockNum);
+
+	/* size of the tx and rx descriptor queues */
+	TotalTxBlockSize = TxBlockNum * adev->memblocksize;
+	TotalRxBlockSize = RxBlockNum * adev->memblocksize;
+	log(L_DEBUG, "TxBlockNum %u RxBlockNum %u TotalTxBlockSize %u "
+		"TotalTxBlockSize %u\n", TxBlockNum, RxBlockNum,
+		TotalTxBlockSize, TotalRxBlockSize);
+
+
+	/* align the tx descriptor queue to an alignment of 0x20 (32 bytes) */
+	MemoryConfigOption.rx_mem =
+		cpu_to_le32((le32_to_cpu(mmt->PoolStart) + 0x1f) & ~0x1f);
+
+	/* align the rx descriptor queue to units of 0x20
+	 * and offset it by the tx descriptor queue */
+	MemoryConfigOption.tx_mem =
+		cpu_to_le32((le32_to_cpu(mmt->PoolStart) + TotalRxBlockSize + 0x1f) & ~0x1f);
+	log(L_DEBUG, "rx_mem %08X rx_mem %08X\n",
+		MemoryConfigOption.tx_mem, MemoryConfigOption.rx_mem);
+
+	/* alert the device to our decision */
+	if (OK != acx_s_configure(adev, &MemoryConfigOption, ACX1xx_IE_MEMORY_CONFIG_OPTIONS)) {
+		goto bad;
+	}
+
+	/* and tell the device to kick it into gear */
+	if (OK != acx_s_issue_cmd(adev, ACX100_CMD_INIT_MEMORY, NULL, 0)) {
+		goto bad;
+	}
+	FN_EXIT1(OK);
+	return OK;
+bad:
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+
+
+/***********************************************************************
+** acx100_s_create_dma_regions
+**
+** Note that this fn messes up heavily with hardware, but we cannot
+** lock it (we need to sleep). Not a problem since IRQs can't happen
+*/
+static int
+acx100_s_create_dma_regions(acx_device_t *adev)
+{
+	acx100_ie_queueconfig_t queueconf;
+	acx_ie_memmap_t memmap;
+	int res = NOT_OK;
+	u32 tx_queue_start, rx_queue_start;
+
+	FN_ENTER;
+
+	/* read out the acx100 physical start address for the queues */
+	if (OK != acx_s_interrogate(adev, &memmap, ACX1xx_IE_MEMORY_MAP)) {
+		goto fail;
+	}
+
+	tx_queue_start = le32_to_cpu(memmap.QueueStart);
+	rx_queue_start = tx_queue_start + TX_CNT * sizeof(txdesc_t);
+
+	log(L_DEBUG, "initializing Queue Indicator\n");
+
+	memset(&queueconf, 0, sizeof(queueconf));
+
+	/* Not needed for PCI, so we can avoid setting them altogether */
+	if (IS_USB(adev)) {
+		queueconf.NumTxDesc = USB_TX_CNT;
+		queueconf.NumRxDesc = USB_RX_CNT;
+	}
+
+	/* calculate size of queues */
+	queueconf.AreaSize = cpu_to_le32(
+			TX_CNT * sizeof(txdesc_t) +
+			RX_CNT * sizeof(rxdesc_t) + 8
+			);
+	queueconf.NumTxQueues = 1;  /* number of tx queues */
+	/* sets the beginning of the tx descriptor queue */
+	queueconf.TxQueueStart = memmap.QueueStart;
+	/* done by memset: queueconf.TxQueuePri = 0; */
+	queueconf.RxQueueStart = cpu_to_le32(rx_queue_start);
+	queueconf.QueueOptions = 1;		/* auto reset descriptor */
+	/* sets the end of the rx descriptor queue */
+	queueconf.QueueEnd = cpu_to_le32(
+			rx_queue_start + RX_CNT * sizeof(rxdesc_t)
+			);
+	/* sets the beginning of the next queue */
+	queueconf.HostQueueEnd = cpu_to_le32(le32_to_cpu(queueconf.QueueEnd) + 8);
+	if (OK != acx_s_configure(adev, &queueconf, ACX1xx_IE_QUEUE_CONFIG)) {
+		goto fail;
+	}
+
+	if (IS_PCI(adev)) {
+	/* sets the beginning of the rx descriptor queue, after the tx descrs */
+		if (OK != acxpci_s_create_hostdesc_queues(adev))
+			goto fail;
+		acxpci_create_desc_queues(adev, tx_queue_start, rx_queue_start);
+	}
+
+	if (OK != acx_s_interrogate(adev, &memmap, ACX1xx_IE_MEMORY_MAP)) {
+		goto fail;
+	}
+
+	memmap.PoolStart = cpu_to_le32(
+			(le32_to_cpu(memmap.QueueEnd) + 4 + 0x1f) & ~0x1f
+			);
+
+	if (OK != acx_s_configure(adev, &memmap, ACX1xx_IE_MEMORY_MAP)) {
+		goto fail;
+	}
+
+	if (OK != acx100_s_init_memory_pools(adev, &memmap)) {
+		goto fail;
+	}
+
+	res = OK;
+	goto end;
+
+fail:
+	acx_s_msleep(1000); /* ? */
+	if (IS_PCI(adev))
+		acxpci_free_desc_queues(adev);
+end:
+	FN_EXIT1(res);
+	return res;
+}
+
+
+/***********************************************************************
+** acx111_s_create_dma_regions
+**
+** Note that this fn messes heavily with hardware, but we cannot
+** lock it (we need to sleep). Not a problem since IRQs can't happen
+*/
+#define ACX111_PERCENT(percent) ((percent)/5)
+
+static int
+acx111_s_create_dma_regions(acx_device_t *adev)
+{
+	struct acx111_ie_memoryconfig memconf;
+	struct acx111_ie_queueconfig queueconf;
+	u32 tx_queue_start, rx_queue_start;
+
+	FN_ENTER;
+
+	/* Calculate memory positions and queue sizes */
+
+	/* Set up our host descriptor pool + data pool */
+	if (IS_PCI(adev)) {
+		if (OK != acxpci_s_create_hostdesc_queues(adev))
+			goto fail;
+	}
+
+	memset(&memconf, 0, sizeof(memconf));
+	/* the number of STAs (STA contexts) to support
+	** NB: was set to 1 and everything seemed to work nevertheless... */
+	memconf.no_of_stations = cpu_to_le16(VEC_SIZE(adev->sta_list));
+	/* specify the memory block size. Default is 256 */
+	memconf.memory_block_size = cpu_to_le16(adev->memblocksize);
+	/* let's use 50%/50% for tx/rx (specify percentage, units of 5%) */
+	memconf.tx_rx_memory_block_allocation = ACX111_PERCENT(50);
+	/* set the count of our queues
+	** NB: struct acx111_ie_memoryconfig shall be modified
+	** if we ever will switch to more than one rx and/or tx queue */
+	memconf.count_rx_queues = 1;
+	memconf.count_tx_queues = 1;
+	/* 0 == Busmaster Indirect Memory Organization, which is what we want
+	 * (using linked host descs with their allocated mem).
+	 * 2 == Generic Bus Slave */
+	/* done by memset: memconf.options = 0; */
+	/* let's use 25% for fragmentations and 75% for frame transfers
+	 * (specified in units of 5%) */
+	memconf.fragmentation = ACX111_PERCENT(75);
+	/* Rx descriptor queue config */
+	memconf.rx_queue1_count_descs = RX_CNT;
+	memconf.rx_queue1_type = 7; /* must be set to 7 */
+	/* done by memset: memconf.rx_queue1_prio = 0; low prio */
+	if (IS_PCI(adev)) {
+		memconf.rx_queue1_host_rx_start = cpu2acx(adev->rxhostdesc_startphy);
+	}
+	/* Tx descriptor queue config */
+	memconf.tx_queue1_count_descs = TX_CNT;
+	/* done by memset: memconf.tx_queue1_attributes = 0; lowest priority */
+
+	/* NB1: this looks wrong: (memconf,ACX1xx_IE_QUEUE_CONFIG),
+	** (queueconf,ACX1xx_IE_MEMORY_CONFIG_OPTIONS) look swapped, eh?
+	** But it is actually correct wrt IE numbers.
+	** NB2: sizeof(memconf) == 28 == 0x1c but configure(ACX1xx_IE_QUEUE_CONFIG)
+	** writes 0x20 bytes (because same IE for acx100 uses struct acx100_ie_queueconfig
+	** which is 4 bytes larger. what a mess. TODO: clean it up) */
+	if (OK != acx_s_configure(adev, &memconf, ACX1xx_IE_QUEUE_CONFIG)) {
+		goto fail;
+	}
+
+	acx_s_interrogate(adev, &queueconf, ACX1xx_IE_MEMORY_CONFIG_OPTIONS);
+
+	tx_queue_start = le32_to_cpu(queueconf.tx1_queue_address);
+	rx_queue_start = le32_to_cpu(queueconf.rx1_queue_address);
+
+	log(L_INIT, "dump queue head (from card):\n"
+		       "len: %u\n"
+		       "tx_memory_block_address: %X\n"
+		       "rx_memory_block_address: %X\n"
+		       "tx1_queue address: %X\n"
+		       "rx1_queue address: %X\n",
+				le16_to_cpu(queueconf.len),
+				le32_to_cpu(queueconf.tx_memory_block_address),
+				le32_to_cpu(queueconf.rx_memory_block_address),
+				tx_queue_start,
+				rx_queue_start);
+
+	if (IS_PCI(adev))
+		acxpci_create_desc_queues(adev, tx_queue_start, rx_queue_start);
+
+	FN_EXIT1(OK);
+	return OK;
+fail:
+	if (IS_PCI(adev))
+		acxpci_free_desc_queues(adev);
+
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+
+
+/***********************************************************************
+*/
+static void
+acx_s_initialize_rx_config(acx_device_t *adev)
+{
+	struct {
+		u16	id ACX_PACKED;
+		u16	len ACX_PACKED;
+		u16	rx_cfg1 ACX_PACKED;
+		u16	rx_cfg2 ACX_PACKED;
+	} cfg;
+
+	switch (adev->mode) {
+	case ACX_MODE_OFF:
+		adev->rx_config_1 = (u16) (0
+			/* | RX_CFG1_INCLUDE_RXBUF_HDR	*/
+			/* | RX_CFG1_FILTER_SSID	*/
+			/* | RX_CFG1_FILTER_BCAST	*/
+			/* | RX_CFG1_RCV_MC_ADDR1	*/
+			/* | RX_CFG1_RCV_MC_ADDR0	*/
+			/* | RX_CFG1_FILTER_ALL_MULTI	*/
+			/* | RX_CFG1_FILTER_BSSID	*/
+			/* | RX_CFG1_FILTER_MAC		*/
+			/* | RX_CFG1_RCV_PROMISCUOUS	*/
+			/* | RX_CFG1_INCLUDE_FCS	*/
+			/* | RX_CFG1_INCLUDE_PHY_HDR	*/
+			);
+		adev->rx_config_2 = (u16) (0
+			/*| RX_CFG2_RCV_ASSOC_REQ	*/
+			/*| RX_CFG2_RCV_AUTH_FRAMES	*/
+			/*| RX_CFG2_RCV_BEACON_FRAMES	*/
+			/*| RX_CFG2_RCV_CONTENTION_FREE	*/
+			/*| RX_CFG2_RCV_CTRL_FRAMES	*/
+			/*| RX_CFG2_RCV_DATA_FRAMES	*/
+			/*| RX_CFG2_RCV_BROKEN_FRAMES	*/
+			/*| RX_CFG2_RCV_MGMT_FRAMES	*/
+			/*| RX_CFG2_RCV_PROBE_REQ	*/
+			/*| RX_CFG2_RCV_PROBE_RESP	*/
+			/*| RX_CFG2_RCV_ACK_FRAMES	*/
+			/*| RX_CFG2_RCV_OTHER		*/
+			);
+		break;
+	case ACX_MODE_MONITOR:
+		adev->rx_config_1 = (u16) (0
+			/* | RX_CFG1_INCLUDE_RXBUF_HDR	*/
+			/* | RX_CFG1_FILTER_SSID	*/
+			/* | RX_CFG1_FILTER_BCAST	*/
+			/* | RX_CFG1_RCV_MC_ADDR1	*/
+			/* | RX_CFG1_RCV_MC_ADDR0	*/
+			/* | RX_CFG1_FILTER_ALL_MULTI	*/
+			/* | RX_CFG1_FILTER_BSSID	*/
+			/* | RX_CFG1_FILTER_MAC		*/
+			| RX_CFG1_RCV_PROMISCUOUS
+			/* | RX_CFG1_INCLUDE_FCS	*/
+			/* | RX_CFG1_INCLUDE_PHY_HDR	*/
+			);
+		adev->rx_config_2 = (u16) (0
+			| RX_CFG2_RCV_ASSOC_REQ
+			| RX_CFG2_RCV_AUTH_FRAMES
+			| RX_CFG2_RCV_BEACON_FRAMES
+			| RX_CFG2_RCV_CONTENTION_FREE
+			| RX_CFG2_RCV_CTRL_FRAMES
+			| RX_CFG2_RCV_DATA_FRAMES
+			| RX_CFG2_RCV_BROKEN_FRAMES
+			| RX_CFG2_RCV_MGMT_FRAMES
+			| RX_CFG2_RCV_PROBE_REQ
+			| RX_CFG2_RCV_PROBE_RESP
+			| RX_CFG2_RCV_ACK_FRAMES
+			| RX_CFG2_RCV_OTHER
+			);
+		break;
+	default:
+		adev->rx_config_1 = (u16) (0
+			/* | RX_CFG1_INCLUDE_RXBUF_HDR	*/
+			/* | RX_CFG1_FILTER_SSID	*/
+			/* | RX_CFG1_FILTER_BCAST	*/
+			/* | RX_CFG1_RCV_MC_ADDR1	*/
+			/* | RX_CFG1_RCV_MC_ADDR0	*/
+			/* | RX_CFG1_FILTER_ALL_MULTI	*/
+			/* | RX_CFG1_FILTER_BSSID	*/
+			| RX_CFG1_FILTER_MAC
+			/* | RX_CFG1_RCV_PROMISCUOUS	*/
+			/* | RX_CFG1_INCLUDE_FCS	*/
+			/* | RX_CFG1_INCLUDE_PHY_HDR	*/
+			);
+		adev->rx_config_2 = (u16) (0
+			| RX_CFG2_RCV_ASSOC_REQ
+			| RX_CFG2_RCV_AUTH_FRAMES
+			| RX_CFG2_RCV_BEACON_FRAMES
+			| RX_CFG2_RCV_CONTENTION_FREE
+			| RX_CFG2_RCV_CTRL_FRAMES
+			| RX_CFG2_RCV_DATA_FRAMES
+			/*| RX_CFG2_RCV_BROKEN_FRAMES	*/
+			| RX_CFG2_RCV_MGMT_FRAMES
+			| RX_CFG2_RCV_PROBE_REQ
+			| RX_CFG2_RCV_PROBE_RESP
+			/*| RX_CFG2_RCV_ACK_FRAMES	*/
+			| RX_CFG2_RCV_OTHER
+			);
+		break;
+	}
+	adev->rx_config_1 |= RX_CFG1_INCLUDE_RXBUF_HDR;
+
+	if ((adev->rx_config_1 & RX_CFG1_INCLUDE_PHY_HDR)
+	 || (adev->firmware_numver >= 0x02000000))
+		adev->phy_header_len = IS_ACX111(adev) ? 8 : 4;
+	else
+		adev->phy_header_len = 0;
+
+	log(L_INIT, "setting RXconfig to %04X:%04X\n",
+			adev->rx_config_1, adev->rx_config_2);
+	cfg.rx_cfg1 = cpu_to_le16(adev->rx_config_1);
+	cfg.rx_cfg2 = cpu_to_le16(adev->rx_config_2);
+	acx_s_configure(adev, &cfg, ACX1xx_IE_RXCONFIG);
+}
+
+
+/***********************************************************************
+** acx_s_set_defaults
+*/
+void
+acx_s_set_defaults(acx_device_t *adev)
+{
+	unsigned long flags;
+
+	FN_ENTER;
+
+	/* do it before getting settings, prevent bogus channel 0 warning */
+	adev->channel = 1;
+
+	/* query some settings from the card.
+	 * NOTE: for some settings, e.g. CCA and ED (ACX100!), an initial
+	 * query is REQUIRED, otherwise the card won't work correctly! */
+	adev->get_mask = GETSET_ANTENNA|GETSET_SENSITIVITY|GETSET_STATION_ID|GETSET_REG_DOMAIN;
+	/* Only ACX100 supports ED and CCA */
+	if (IS_ACX100(adev))
+		adev->get_mask |= GETSET_CCA|GETSET_ED_THRESH;
+
+	acx_s_update_card_settings(adev);
+
+	acx_lock(adev, flags);
+
+	/* set our global interrupt mask */
+	if (IS_PCI(adev))
+		acxpci_set_interrupt_mask(adev);
+
+	adev->led_power = 1; /* LED is active on startup */
+	adev->brange_max_quality = 60; /* LED blink max quality is 60 */
+	adev->brange_time_last_state_change = jiffies;
+
+	/* copy the MAC address we just got from the card
+	 * into our MAC address used during current 802.11 session */
+	MAC_COPY(adev->dev_addr, adev->ndev->dev_addr);
+	MAC_BCAST(adev->ap);
+
+	adev->essid_len =
+		snprintf(adev->essid, sizeof(adev->essid), "STA%02X%02X%02X",
+			adev->dev_addr[3], adev->dev_addr[4], adev->dev_addr[5]);
+	adev->essid_active = 1;
+
+	/* we have a nick field to waste, so why not abuse it
+	 * to announce the driver version? ;-) */
+	strncpy(adev->nick, "acx " ACX_RELEASE, IW_ESSID_MAX_SIZE);
+
+	if (IS_PCI(adev)) { /* FIXME: this should be made to apply to USB, too! */
+		/* first regulatory domain entry in EEPROM == default reg. domain */
+		adev->reg_dom_id = adev->cfgopt_domains.list[0];
+	}
+
+	/* 0xffff would be better, but then we won't get a "scan complete"
+	 * interrupt, so our current infrastructure will fail: */
+	adev->scan_count = 1;
+	adev->scan_mode = ACX_SCAN_OPT_ACTIVE;
+	adev->scan_duration = 100;
+	adev->scan_probe_delay = 200;
+	/* reported to break scanning: adev->scan_probe_delay = adev->cfgopt_probe_delay; */
+	adev->scan_rate = ACX_SCAN_RATE_1;
+
+	adev->mode = ACX_MODE_2_STA;
+	adev->auth_alg = WLAN_AUTH_ALG_OPENSYSTEM;
+	adev->listen_interval = 100;
+	adev->beacon_interval = DEFAULT_BEACON_INTERVAL;
+	adev->dtim_interval = DEFAULT_DTIM_INTERVAL;
+
+	adev->msdu_lifetime = DEFAULT_MSDU_LIFETIME;
+
+	adev->rts_threshold = DEFAULT_RTS_THRESHOLD;
+	adev->frag_threshold = 2346;
+
+	/* use standard default values for retry limits */
+	adev->short_retry = 7; /* max. retries for (short) non-RTS packets */
+	adev->long_retry = 4; /* max. retries for long (RTS) packets */
+
+	adev->preamble_mode = 2; /* auto */
+	adev->fallback_threshold = 3;
+	adev->stepup_threshold = 10;
+	adev->rate_bcast = RATE111_1;
+	adev->rate_bcast100 = RATE100_1;
+	adev->rate_basic = RATE111_1 | RATE111_2;
+	adev->rate_auto = 1;
+	if (IS_ACX111(adev)) {
+		adev->rate_oper = RATE111_ALL;
+	} else {
+		adev->rate_oper = RATE111_ACX100_COMPAT;
+	}
+
+	/* Supported Rates element - the rates here are given in units of
+	 * 500 kbit/s, plus 0x80 added. See 802.11-1999.pdf item 7.3.2.2 */
+	acx_l_update_ratevector(adev);
+
+	/* set some more defaults */
+	if (IS_ACX111(adev)) {
+		/* 30mW (15dBm) is default, at least in my acx111 card: */
+		adev->tx_level_dbm = 15;
+	} else {
+		/* don't use max. level, since it might be dangerous
+		 * (e.g. WRT54G people experience
+		 * excessive Tx power damage!) */
+		adev->tx_level_dbm = 18;
+	}
+	/* adev->tx_level_auto = 1; */
+	if (IS_ACX111(adev)) {
+		/* start with sensitivity level 1 out of 3: */
+		adev->sensitivity = 1;
+	}
+
+/* #define ENABLE_POWER_SAVE */
+#ifdef ENABLE_POWER_SAVE
+	adev->ps_wakeup_cfg = PS_CFG_ENABLE | PS_CFG_WAKEUP_ALL_BEAC;
+	adev->ps_listen_interval = 1;
+	adev->ps_options = PS_OPT_ENA_ENHANCED_PS | PS_OPT_TX_PSPOLL | PS_OPT_STILL_RCV_BCASTS;
+	adev->ps_hangover_period = 30;
+	adev->ps_enhanced_transition_time = 0;
+#else
+	adev->ps_wakeup_cfg = 0;
+	adev->ps_listen_interval = 0;
+	adev->ps_options = 0;
+	adev->ps_hangover_period = 0;
+	adev->ps_enhanced_transition_time = 0;
+#endif
+
+	/* These settings will be set in fw on ifup */
+	adev->set_mask = 0
+		| GETSET_RETRY
+		| SET_MSDU_LIFETIME
+	/* configure card to do rate fallback when in auto rate mode */
+		| SET_RATE_FALLBACK
+		| SET_RXCONFIG
+		| GETSET_TXPOWER
+	/* better re-init the antenna value we got above */
+		| GETSET_ANTENNA
+#if POWER_SAVE_80211
+		| GETSET_POWER_80211
+#endif
+		;
+
+	acx_unlock(adev, flags);
+	acx_lock_unhold(); /* hold time 844814 CPU ticks @2GHz */
+
+	acx_s_initialize_rx_config(adev);
+
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** FIXME: this should be solved in a general way for all radio types
+** by decoding the radio firmware module,
+** since it probably has some standard structure describing how to
+** set the power level of the radio module which it controls.
+** Or maybe not, since the radio module probably has a function interface
+** instead which then manages Tx level programming :-\
+*/
+static int
+acx111_s_set_tx_level(acx_device_t *adev, u8 level_dbm)
+{
+	struct acx111_ie_tx_level tx_level;
+
+	/* my acx111 card has two power levels in its configoptions (== EEPROM):
+	 * 1 (30mW) [15dBm]
+	 * 2 (10mW) [10dBm]
+	 * For now, just assume all other acx111 cards have the same.
+	 * FIXME: Ideally we would query it here, but we first need a
+	 * standard way to query individual configoptions easily.
+	 * Well, now we have proper cfgopt txpower variables, but this still
+	 * hasn't been done yet, since it also requires dBm <-> mW conversion here... */
+	if (level_dbm <= 12) {
+		tx_level.level = 2; /* 10 dBm */
+		adev->tx_level_dbm = 10;
+	} else {
+		tx_level.level = 1; /* 15 dBm */
+		adev->tx_level_dbm = 15;
+	}
+	if (level_dbm != adev->tx_level_dbm)
+		log(L_INIT, "acx111 firmware has specific "
+			"power levels only: adjusted %d dBm to %d dBm!\n",
+			level_dbm, adev->tx_level_dbm);
+
+	return acx_s_configure(adev, &tx_level, ACX1xx_IE_DOT11_TX_POWER_LEVEL);
+}
+
+static int
+acx_s_set_tx_level(acx_device_t *adev, u8 level_dbm)
+{
+	if (IS_ACX111(adev)) {
+		return acx111_s_set_tx_level(adev, level_dbm);
+	}
+	if (IS_PCI(adev)) {
+		return acx100pci_s_set_tx_level(adev, level_dbm);
+	}
+	return OK;
+}
+
+
+/***********************************************************************
+*/
+#ifdef UNUSED
+/* Returns the current tx level (ACX111) */
+static u8
+acx111_s_get_tx_level(acx_device_t *adev)
+{
+	struct acx111_ie_tx_level tx_level;
+
+	tx_level.level = 0;
+	acx_s_interrogate(adev, &tx_level, ACX1xx_IE_DOT11_TX_POWER_LEVEL);
+	return tx_level.level;
+}
+#endif
+
+
+/***********************************************************************
+** acx_l_rxmonitor
+** Called from IRQ context only
+*/
+static void
+acx_l_rxmonitor(acx_device_t *adev, const rxbuffer_t *rxbuf)
+{
+	wlansniffrm_t *msg;
+	struct sk_buff *skb;
+	void *datap;
+	unsigned int skb_len;
+	int payload_offset;
+
+	FN_ENTER;
+
+	/* we are in big luck: the acx100 doesn't modify any of the fields */
+	/* in the 802.11 frame. just pass this packet into the PF_PACKET */
+	/* subsystem. yeah. */
+	payload_offset = ((u8*)acx_get_wlan_hdr(adev, rxbuf) - (u8*)rxbuf);
+	skb_len = RXBUF_BYTES_USED(rxbuf) - payload_offset;
+
+	/* sanity check */
+	if (unlikely(skb_len > WLAN_A4FR_MAXLEN_WEP)) {
+		printk("%s: monitor mode panic: oversized frame!\n",
+				adev->ndev->name);
+		goto end;
+	}
+
+	if (adev->ndev->type == ARPHRD_IEEE80211_PRISM)
+		skb_len += sizeof(*msg);
+
+	/* allocate skb */
+	skb = dev_alloc_skb(skb_len);
+	if (unlikely(!skb)) {
+		printk("%s: no memory for skb (%u bytes)\n",
+				adev->ndev->name, skb_len);
+		goto end;
+	}
+
+	skb_put(skb, skb_len);
+
+	if (adev->ndev->type == ARPHRD_IEEE80211) {
+		/* when in raw 802.11 mode, just copy frame as-is */
+		datap = skb->data;
+	} else if (adev->ndev->type == ARPHRD_IEEE80211_PRISM) {
+		/* emulate prism header */
+		msg = (wlansniffrm_t*)skb->data;
+		datap = msg + 1;
+
+		msg->msgcode = WLANSNIFFFRM;
+		msg->msglen = sizeof(*msg);
+		strncpy(msg->devname, adev->ndev->name, sizeof(msg->devname)-1);
+		msg->devname[sizeof(msg->devname)-1] = '\0';
+
+		msg->hosttime.did = WLANSNIFFFRM_hosttime;
+		msg->hosttime.status = WLANITEM_STATUS_data_ok;
+		msg->hosttime.len = 4;
+		msg->hosttime.data = jiffies;
+
+		msg->mactime.did = WLANSNIFFFRM_mactime;
+		msg->mactime.status = WLANITEM_STATUS_data_ok;
+		msg->mactime.len = 4;
+		msg->mactime.data = rxbuf->time;
+
+		msg->channel.did = WLANSNIFFFRM_channel;
+		msg->channel.status = WLANITEM_STATUS_data_ok;
+		msg->channel.len = 4;
+		msg->channel.data = adev->channel;
+
+		msg->rssi.did = WLANSNIFFFRM_rssi;
+		msg->rssi.status = WLANITEM_STATUS_no_value;
+		msg->rssi.len = 4;
+		msg->rssi.data = 0;
+
+		msg->sq.did = WLANSNIFFFRM_sq;
+		msg->sq.status = WLANITEM_STATUS_no_value;
+		msg->sq.len = 4;
+		msg->sq.data = 0;
+
+		msg->signal.did = WLANSNIFFFRM_signal;
+		msg->signal.status = WLANITEM_STATUS_data_ok;
+		msg->signal.len = 4;
+		msg->signal.data = rxbuf->phy_snr;
+
+		msg->noise.did = WLANSNIFFFRM_noise;
+		msg->noise.status = WLANITEM_STATUS_data_ok;
+		msg->noise.len = 4;
+		msg->noise.data = rxbuf->phy_level;
+
+		msg->rate.did = WLANSNIFFFRM_rate;
+		msg->rate.status = WLANITEM_STATUS_data_ok;
+		msg->rate.len = 4;
+		msg->rate.data = rxbuf->phy_plcp_signal / 5;
+
+		msg->istx.did = WLANSNIFFFRM_istx;
+		msg->istx.status = WLANITEM_STATUS_data_ok;
+		msg->istx.len = 4;
+		msg->istx.data = 0;	/* tx=0: it's not a tx packet */
+
+		skb_len -= sizeof(*msg);
+
+		msg->frmlen.did = WLANSNIFFFRM_signal;
+		msg->frmlen.status = WLANITEM_STATUS_data_ok;
+		msg->frmlen.len = 4;
+		msg->frmlen.data = skb_len;
+	} else {
+		printk("acx: unsupported netdev type %d!\n", adev->ndev->type);
+		dev_kfree_skb(skb);
+		return;
+	}
+
+	/* sanity check (keep it here) */
+	if (unlikely((int)skb_len < 0)) {
+		printk("acx: skb_len=%d. Driver bug, please report\n", (int)skb_len);
+		dev_kfree_skb(skb);
+		return;
+	}
+	memcpy(datap, ((unsigned char*)rxbuf)+payload_offset, skb_len);
+
+	skb->dev = adev->ndev;
+	skb->dev->last_rx = jiffies;
+
+	skb->mac.raw = skb->data;
+	skb->ip_summed = CHECKSUM_NONE;
+	skb->pkt_type = PACKET_OTHERHOST;
+	skb->protocol = htons(ETH_P_80211_RAW);
+	netif_rx(skb);
+
+	adev->stats.rx_packets++;
+	adev->stats.rx_bytes += skb->len;
+
+end:
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acx_l_rx_ieee802_11_frame
+**
+** Called from IRQ context only
+*/
+
+/* All these contortions are for saner dup logging
+**
+** We want: (a) to know about excessive dups
+** (b) to not spam kernel log about occasional dups
+**
+** 1/64 threshold was chosen by running "ping -A"
+** It gave "rx: 59 DUPs in 2878 packets" only with 4 parallel
+** "ping -A" streams running. */
+/* 2005-10-11: bumped up to 1/8
+** subtract a $smallint from dup_count in order to
+** avoid "2 DUPs in 19 packets" messages */
+static inline int
+acx_l_handle_dup(acx_device_t *adev, u16 seq)
+{
+	if (adev->dup_count) {
+		adev->nondup_count++;
+		if (time_after(jiffies, adev->dup_msg_expiry)) {
+			/* Log only if more than 1 dup in 64 packets */
+			if (adev->nondup_count/8 < adev->dup_count-5) {
+				printk(KERN_INFO "%s: rx: %d DUPs in "
+					"%d packets received in 10 secs\n",
+					adev->ndev->name,
+					adev->dup_count,
+					adev->nondup_count);
+			}
+			adev->dup_count = 0;
+			adev->nondup_count = 0;
+		}
+	}
+	if (unlikely(seq == adev->last_seq_ctrl)) {
+		if (!adev->dup_count++)
+			adev->dup_msg_expiry = jiffies + 10*HZ;
+		adev->stats.rx_errors++;
+		return 1; /* a dup */
+	}
+	adev->last_seq_ctrl = seq;
+	return 0;
+}
+
+static int
+acx_l_rx_ieee802_11_frame(acx_device_t *adev, rxbuffer_t *rxbuf)
+{
+	unsigned int ftype, fstype;
+	const wlan_hdr_t *hdr;
+	int result = NOT_OK;
+
+	FN_ENTER;
+
+	hdr = acx_get_wlan_hdr(adev, rxbuf);
+
+	/* see IEEE 802.11-1999.pdf chapter 7 "MAC frame formats" */
+	if (unlikely((hdr->fc & WF_FC_PVERi) != 0)) {
+		printk_ratelimited(KERN_INFO "rx: unsupported 802.11 protocol\n");
+		goto end;
+	}
+
+	ftype = hdr->fc & WF_FC_FTYPEi;
+	fstype = hdr->fc & WF_FC_FSTYPEi;
+
+	switch (ftype) {
+	/* check data frames first, for speed */
+	case WF_FTYPE_DATAi:
+		switch (fstype) {
+		case WF_FSTYPE_DATAONLYi:
+			if (acx_l_handle_dup(adev, hdr->seq))
+				break; /* a dup, simply discard it */
+
+			/* TODO:
+			if (WF_FC_FROMTODSi == (hdr->fc & WF_FC_FROMTODSi)) {
+				result = acx_l_process_data_frame_wds(adev, rxbuf);
+				break;
+			}
+			*/
+
+			switch (adev->mode) {
+			case ACX_MODE_3_AP:
+				result = acx_l_process_data_frame_master(adev, rxbuf);
+				break;
+			case ACX_MODE_0_ADHOC:
+			case ACX_MODE_2_STA:
+				result = acx_l_process_data_frame_client(adev, rxbuf);
+				break;
+			}
+		case WF_FSTYPE_DATA_CFACKi:
+		case WF_FSTYPE_DATA_CFPOLLi:
+		case WF_FSTYPE_DATA_CFACK_CFPOLLi:
+		case WF_FSTYPE_CFPOLLi:
+		case WF_FSTYPE_CFACK_CFPOLLi:
+		/*   see above.
+			acx_process_class_frame(adev, rxbuf, 3); */
+			break;
+		case WF_FSTYPE_NULLi:
+			/* acx_l_process_NULL_frame(adev, rxbuf, 3); */
+			break;
+		/* FIXME: same here, see above */
+		case WF_FSTYPE_CFACKi:
+		default:
+			break;
+		}
+		break;
+	case WF_FTYPE_MGMTi:
+		result = acx_l_process_mgmt_frame(adev, rxbuf);
+		break;
+	case WF_FTYPE_CTLi:
+		if (fstype == WF_FSTYPE_PSPOLLi)
+			result = OK;
+		/*   this call is irrelevant, since
+		 *   acx_process_class_frame is a stub, so return
+		 *   immediately instead.
+		 * return acx_process_class_frame(adev, rxbuf, 3); */
+		break;
+	default:
+		break;
+	}
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_l_process_rxbuf
+**
+** NB: used by USB code also
+*/
+void
+acx_l_process_rxbuf(acx_device_t *adev, rxbuffer_t *rxbuf)
+{
+	struct wlan_hdr *hdr;
+	unsigned int qual;
+	int buf_len;
+	u16 fc;
+
+	hdr = acx_get_wlan_hdr(adev, rxbuf);
+	fc = le16_to_cpu(hdr->fc);
+	/* length of frame from control field to first byte of FCS */
+	buf_len = RXBUF_BYTES_RCVD(adev, rxbuf);
+
+	if ( ((WF_FC_FSTYPE & fc) != WF_FSTYPE_BEACON)
+	  || (acx_debug & L_XFER_BEACON)
+	) {
+		log(L_XFER|L_DATA, "rx: %s "
+			"time:%u len:%u signal:%u SNR:%u macstat:%02X "
+			"phystat:%02X phyrate:%u status:%u\n",
+			acx_get_packet_type_string(fc),
+			le32_to_cpu(rxbuf->time),
+			buf_len,
+			acx_signal_to_winlevel(rxbuf->phy_level),
+			acx_signal_to_winlevel(rxbuf->phy_snr),
+			rxbuf->mac_status,
+			rxbuf->phy_stat_baseband,
+			rxbuf->phy_plcp_signal,
+			adev->status);
+	}
+
+	if (unlikely(acx_debug & L_DATA)) {
+		printk("rx: 802.11 buf[%u]: ", buf_len);
+		acx_dump_bytes(hdr, buf_len);
+	}
+
+	/* FIXME: should check for Rx errors (rxbuf->mac_status?
+	 * discard broken packets - but NOT for monitor!)
+	 * and update Rx packet statistics here */
+
+	if (unlikely(adev->mode == ACX_MODE_MONITOR)) {
+		acx_l_rxmonitor(adev, rxbuf);
+	} else if (likely(buf_len >= WLAN_HDR_A3_LEN)) {
+		acx_l_rx_ieee802_11_frame(adev, rxbuf);
+	} else {
+		log(L_DEBUG|L_XFER|L_DATA,
+		       "rx: NOT receiving packet (%s): "
+		       "size too small (%u)\n",
+		       acx_get_packet_type_string(fc),
+		       buf_len);
+	}
+
+	/* Now check Rx quality level, AFTER processing packet.
+	 * I tried to figure out how to map these levels to dBm
+	 * values, but for the life of me I really didn't
+	 * manage to get it. Either these values are not meant to
+	 * be expressed in dBm, or it's some pretty complicated
+	 * calculation. */
+
+#ifdef FROM_SCAN_SOURCE_ONLY
+	/* only consider packets originating from the MAC
+	 * address of the device that's managing our BSSID.
+	 * Disable it for now, since it removes information (levels
+	 * from different peers) and slows the Rx path. */
+	if (adev->ap_client
+	 && mac_is_equal(hdr->a2, adev->ap_client->address)) {
+#endif
+		adev->wstats.qual.level = acx_signal_to_winlevel(rxbuf->phy_level);
+		adev->wstats.qual.noise = acx_signal_to_winlevel(rxbuf->phy_snr);
+#ifndef OLD_QUALITY
+		qual = acx_signal_determine_quality(adev->wstats.qual.level,
+				adev->wstats.qual.noise);
+#else
+		qual = (adev->wstats.qual.noise <= 100) ?
+				100 - adev->wstats.qual.noise : 0;
+#endif
+		adev->wstats.qual.qual = qual;
+		adev->wstats.qual.updated = 7; /* all 3 indicators updated */
+#ifdef FROM_SCAN_SOURCE_ONLY
+	}
+#endif
+}
+
+
+/***********************************************************************
+** acx_l_handle_txrate_auto
+**
+** Theory of operation:
+** client->rate_cap is a bitmask of rates client is capable of.
+** client->rate_cfg is a bitmask of allowed (configured) rates.
+** It is set as a result of iwconfig rate N [auto]
+** or iwpriv set_rates "N,N,N N,N,N" commands.
+** It can be fixed (e.g. 0x0080 == 18Mbit only),
+** auto (0x00ff == 18Mbit or any lower value),
+** and code handles any bitmask (0x1081 == try 54Mbit,18Mbit,1Mbit _only_).
+**
+** client->rate_cur is a value for rate111 field in tx descriptor.
+** It is always set to txrate_cfg sans zero or more most significant
+** bits. This routine handles selection of new rate_cur value depending on
+** outcome of last tx event.
+**
+** client->rate_100 is a precalculated rate value for acx100
+** (we can do without it, but will need to calculate it on each tx).
+**
+** You cannot configure mixed usage of 5.5 and/or 11Mbit rate
+** with PBCC and CCK modulation. Either both at CCK or both at PBCC.
+** In theory you can implement it, but so far it is considered not worth doing.
+**
+** 22Mbit, of course, is PBCC always. */
+
+/* maps acx100 tx descr rate field to acx111 one */
+static u16
+rate100to111(u8 r)
+{
+	switch (r) {
+	case RATE100_1:	return RATE111_1;
+	case RATE100_2:	return RATE111_2;
+	case RATE100_5:
+	case (RATE100_5 | RATE100_PBCC511):	return RATE111_5;
+	case RATE100_11:
+	case (RATE100_11 | RATE100_PBCC511):	return RATE111_11;
+	case RATE100_22:	return RATE111_22;
+	default:
+		printk("acx: unexpected acx100 txrate: %u! "
+			"Please report\n", r);
+		return RATE111_1;
+	}
+}
+
+
+void
+acx_l_handle_txrate_auto(acx_device_t *adev, struct client *txc,
+			u16 cur, u8 rate100, u16 rate111,
+			u8 error, int pkts_to_ignore)
+{
+	u16 sent_rate;
+	int slower_rate_was_used;
+
+	/* vda: hmm. current code will do this:
+	** 1. send packets at 11 Mbit, stepup++
+	** 2. will try to send at 22Mbit. hardware will see no ACK,
+	**    retries at 11Mbit, success. code notes that used rate
+	**    is lower. stepup = 0, fallback++
+	** 3. repeat step 2 fallback_count times. Fall back to
+	**    11Mbit. go to step 1.
+	** If stepup_count is large (say, 16) and fallback_count
+	** is small (3), this wouldn't be too bad wrt throughput */
+
+	if (unlikely(!cur)) {
+		printk("acx: BUG! ratemask is empty\n");
+		return; /* or else we may lock up the box */
+	}
+
+	/* do some preparations, i.e. calculate the one rate that was
+	 * used to send this packet */
+	if (IS_ACX111(adev)) {
+		sent_rate = 1 << highest_bit(rate111 & RATE111_ALL);
+	} else {
+		sent_rate = rate100to111(rate100);
+	}
+	/* sent_rate has only one bit set now, corresponding to tx rate
+	 * which was used by hardware to tx this particular packet */
+
+	/* now do the actual auto rate management */
+	log(L_XFER, "tx: %sclient=%p/"MACSTR" used=%04X cur=%04X cfg=%04X "
+		"__=%u/%u ^^=%u/%u\n",
+		(txc->ignore_count > 0) ? "[IGN] " : "",
+		txc, MAC(txc->address), sent_rate, cur, txc->rate_cfg,
+		txc->fallback_count, adev->fallback_threshold,
+		txc->stepup_count, adev->stepup_threshold
+	);
+
+	/* we need to ignore old packets already in the tx queue since
+	 * they use older rate bytes configured before our last rate change,
+	 * otherwise our mechanism will get confused by interpreting old data.
+	 * Do it after logging above */
+	if (txc->ignore_count) {
+		txc->ignore_count--;
+		return;
+	}
+
+	/* true only if the only nonzero bit in sent_rate is
+	** less significant than highest nonzero bit in cur */
+	slower_rate_was_used = ( cur > ((sent_rate<<1)-1) );
+
+	if (slower_rate_was_used || error) {
+		txc->stepup_count = 0;
+		if (++txc->fallback_count <= adev->fallback_threshold)
+			return;
+		txc->fallback_count = 0;
+
+		/* clear highest 1 bit in cur */
+		sent_rate = RATE111_54;
+		while (!(cur & sent_rate)) sent_rate >>= 1;
+		CLEAR_BIT(cur, sent_rate);
+		if (!cur) /* we can't disable all rates! */
+			cur = sent_rate;
+		log(L_XFER, "tx: falling back to ratemask %04X\n", cur);
+
+	} else { /* there was neither lower rate nor error */
+		txc->fallback_count = 0;
+		if (++txc->stepup_count <= adev->stepup_threshold)
+			return;
+		txc->stepup_count = 0;
+
+		/* Sanitize. Sort of not needed, but I dont trust hw that much...
+		** what if it can report bogus tx rates sometimes? */
+		while (!(cur & sent_rate)) sent_rate >>= 1;
+
+		/* try to find a higher sent_rate that isn't yet in our
+		 * current set, but is an allowed cfg */
+		while (1) {
+			sent_rate <<= 1;
+			if (sent_rate > txc->rate_cfg)
+				/* no higher rates allowed by config */
+				return;
+			if (!(cur & sent_rate) && (txc->rate_cfg & sent_rate))
+				/* found */
+				break;
+			/* not found, try higher one */
+		}
+		SET_BIT(cur, sent_rate);
+		log(L_XFER, "tx: stepping up to ratemask %04X\n", cur);
+	}
+
+	txc->rate_cur = cur;
+	txc->ignore_count = pkts_to_ignore;
+	/* calculate acx100 style rate byte if needed */
+	if (IS_ACX100(adev)) {
+		txc->rate_100 = acx_bitpos2rate100[highest_bit(cur)];
+	}
+}
+
+
+/***********************************************************************
+** acx_i_start_xmit
+**
+** Called by network core. Can be called outside of process context.
+*/
+int
+acx_i_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	tx_t *tx;
+	void *txbuf;
+	unsigned long flags;
+	int txresult = NOT_OK;
+	int len;
+
+	FN_ENTER;
+
+	if (unlikely(!skb)) {
+		/* indicate success */
+		txresult = OK;
+		goto end_no_unlock;
+	}
+	if (unlikely(!adev)) {
+		goto end_no_unlock;
+	}
+
+	acx_lock(adev, flags);
+
+	if (unlikely(!(adev->dev_state_mask & ACX_STATE_IFACE_UP))) {
+		goto end;
+	}
+	if (unlikely(adev->mode == ACX_MODE_OFF)) {
+		goto end;
+	}
+	if (unlikely(acx_queue_stopped(ndev))) {
+		log(L_DEBUG, "%s: called when queue stopped\n", __func__);
+		goto end;
+	}
+	if (unlikely(ACX_STATUS_4_ASSOCIATED != adev->status)) {
+		log(L_XFER, "trying to xmit, but not associated yet: "
+			"aborting...\n");
+		/* silently drop the packet, since we're not connected yet */
+		txresult = OK;
+		/* ...but indicate an error nevertheless */
+		adev->stats.tx_errors++;
+		goto end;
+	}
+
+	tx = acx_l_alloc_tx(adev);
+	if (unlikely(!tx)) {
+		printk_ratelimited("%s: start_xmit: txdesc ring is full, "
+			"dropping tx\n", ndev->name);
+		txresult = NOT_OK;
+		goto end;
+	}
+
+	txbuf = acx_l_get_txbuf(adev, tx);
+	if (unlikely(!txbuf)) {
+		/* Card was removed */
+		txresult = NOT_OK;
+		acx_l_dealloc_tx(adev, tx);
+		goto end;
+	}
+	len = acx_ether_to_txbuf(adev, txbuf, skb);
+	if (unlikely(len < 0)) {
+		/* Error in packet conversion */
+		txresult = NOT_OK;
+		acx_l_dealloc_tx(adev, tx);
+		goto end;
+	}
+	acx_l_tx_data(adev, tx, len);
+	ndev->trans_start = jiffies;
+
+	txresult = OK;
+	adev->stats.tx_packets++;
+	adev->stats.tx_bytes += skb->len;
+
+end:
+	acx_unlock(adev, flags);
+
+end_no_unlock:
+	if ((txresult == OK) && skb)
+		dev_kfree_skb_any(skb);
+
+	FN_EXIT1(txresult);
+	return txresult;
+}
+
+
+/***********************************************************************
+** acx_l_update_ratevector
+**
+** Updates adev->rate_supported[_len] according to rate_{basic,oper}
+*/
+const u8
+acx_bitpos2ratebyte[] = {
+	DOT11RATEBYTE_1,
+	DOT11RATEBYTE_2,
+	DOT11RATEBYTE_5_5,
+	DOT11RATEBYTE_6_G,
+	DOT11RATEBYTE_9_G,
+	DOT11RATEBYTE_11,
+	DOT11RATEBYTE_12_G,
+	DOT11RATEBYTE_18_G,
+	DOT11RATEBYTE_22,
+	DOT11RATEBYTE_24_G,
+	DOT11RATEBYTE_36_G,
+	DOT11RATEBYTE_48_G,
+	DOT11RATEBYTE_54_G,
+};
+
+void
+acx_l_update_ratevector(acx_device_t *adev)
+{
+	u16 bcfg = adev->rate_basic;
+	u16 ocfg = adev->rate_oper;
+	u8 *supp = adev->rate_supported;
+	const u8 *dot11 = acx_bitpos2ratebyte;
+
+	FN_ENTER;
+
+	while (ocfg) {
+		if (ocfg & 1) {
+			*supp = *dot11;
+			if (bcfg & 1) {
+				*supp |= 0x80;
+			}
+			supp++;
+		}
+		dot11++;
+		ocfg >>= 1;
+		bcfg >>= 1;
+	}
+	adev->rate_supported_len = supp - adev->rate_supported;
+	if (acx_debug & L_ASSOC) {
+		printk("new ratevector: ");
+		acx_dump_bytes(adev->rate_supported, adev->rate_supported_len);
+	}
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acx_l_sta_list_init
+*/
+static void
+acx_l_sta_list_init(acx_device_t *adev)
+{
+	FN_ENTER;
+	memset(adev->sta_hash_tab, 0, sizeof(adev->sta_hash_tab));
+	memset(adev->sta_list, 0, sizeof(adev->sta_list));
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acx_l_sta_list_get_from_hash
+*/
+static inline client_t*
+acx_l_sta_list_get_from_hash(acx_device_t *adev, const u8 *address)
+{
+	return adev->sta_hash_tab[address[5] % VEC_SIZE(adev->sta_hash_tab)];
+}
+
+
+/***********************************************************************
+** acx_l_sta_list_get
+*/
+client_t*
+acx_l_sta_list_get(acx_device_t *adev, const u8 *address)
+{
+	client_t *client;
+	FN_ENTER;
+	client = acx_l_sta_list_get_from_hash(adev, address);
+	while (client) {
+		if (mac_is_equal(address, client->address)) {
+			client->mtime = jiffies;
+			break;
+		}
+		client = client->next;
+	}
+	FN_EXIT0;
+	return client;
+}
+
+
+/***********************************************************************
+** acx_l_sta_list_del
+*/
+void
+acx_l_sta_list_del(acx_device_t *adev, client_t *victim)
+{
+	client_t *client, *next;
+
+	client = acx_l_sta_list_get_from_hash(adev, victim->address);
+	next = client;
+	/* tricky. next = client on first iteration only,
+	** on all other iters next = client->next */
+	while (next) {
+		if (next == victim) {
+			client->next = victim->next;
+			/* Overkill */
+			memset(victim, 0, sizeof(*victim));
+			break;
+		}
+		client = next;
+		next = client->next;
+	}
+}
+
+
+/***********************************************************************
+** acx_l_sta_list_alloc
+**
+** Never fails - will evict oldest client if needed
+*/
+static client_t*
+acx_l_sta_list_alloc(acx_device_t *adev)
+{
+	int i;
+	unsigned long age, oldest_age;
+	client_t *client, *oldest;
+
+	FN_ENTER;
+
+	oldest = &adev->sta_list[0];
+	oldest_age = 0;
+	for (i = 0; i < VEC_SIZE(adev->sta_list); i++) {
+		client = &adev->sta_list[i];
+
+		if (!client->used) {
+			goto found;
+		} else {
+			age = jiffies - client->mtime;
+			if (oldest_age < age) {
+				oldest_age = age;
+				oldest = client;
+			}
+		}
+	}
+	acx_l_sta_list_del(adev, oldest);
+	client = oldest;
+found:
+	memset(client, 0, sizeof(*client));
+	FN_EXIT0;
+	return client;
+}
+
+
+/***********************************************************************
+** acx_l_sta_list_add
+**
+** Never fails - will evict oldest client if needed
+*/
+/* In case we will reimplement it differently... */
+#define STA_LIST_ADD_CAN_FAIL 0
+
+static client_t*
+acx_l_sta_list_add(acx_device_t *adev, const u8 *address)
+{
+	client_t *client;
+	int index;
+
+	FN_ENTER;
+
+	client = acx_l_sta_list_alloc(adev);
+
+	client->mtime = jiffies;
+	MAC_COPY(client->address, address);
+	client->used = CLIENT_EXIST_1;
+	client->auth_alg = WLAN_AUTH_ALG_SHAREDKEY;
+	client->auth_step = 1;
+	/* give some tentative peer rate values
+	** (needed because peer may do auth without probing us first,
+	** thus we'll have no idea of peer's ratevector yet).
+	** Will be overwritten by scanning or assoc code */
+	client->rate_cap = adev->rate_basic;
+	client->rate_cfg = adev->rate_basic;
+	client->rate_cur = 1 << lowest_bit(adev->rate_basic);
+
+	index = address[5] % VEC_SIZE(adev->sta_hash_tab);
+	client->next = adev->sta_hash_tab[index];
+	adev->sta_hash_tab[index] = client;
+
+	acxlog_mac(L_ASSOC, "sta_list_add: sta=", address, "\n");
+
+	FN_EXIT0;
+	return client;
+}
+
+
+/***********************************************************************
+** acx_l_sta_list_get_or_add
+**
+** Never fails - will evict oldest client if needed
+*/
+static client_t*
+acx_l_sta_list_get_or_add(acx_device_t *adev, const u8 *address)
+{
+	client_t *client = acx_l_sta_list_get(adev, address);
+	if (!client)
+		client = acx_l_sta_list_add(adev, address);
+	return client;
+}
+
+
+/***********************************************************************
+** acx_set_status
+**
+** This function is called in many atomic regions, must not sleep
+**
+** This function does not need locking UNLESS you call it
+** as acx_set_status(ACX_STATUS_4_ASSOCIATED), bacause this can
+** wake queue. This can race with stop_queue elsewhere.
+** See acx_stop_queue comment. */
+void
+acx_set_status(acx_device_t *adev, u16 new_status)
+{
+#define QUEUE_OPEN_AFTER_ASSOC 1 /* this really seems to be needed now */
+	u16 old_status = adev->status;
+
+	FN_ENTER;
+
+	log(L_ASSOC, "%s(%d):%s\n",
+	       __func__, new_status, acx_get_status_name(new_status));
+
+	/* wireless_send_event never sleeps */
+	if (ACX_STATUS_4_ASSOCIATED == new_status) {
+		union iwreq_data wrqu;
+
+		wrqu.data.length = 0;
+		wrqu.data.flags = 0;
+		wireless_send_event(adev->ndev, SIOCGIWSCAN, &wrqu, NULL);
+
+		wrqu.data.length = 0;
+		wrqu.data.flags = 0;
+		MAC_COPY(wrqu.ap_addr.sa_data, adev->bssid);
+		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+		wireless_send_event(adev->ndev, SIOCGIWAP, &wrqu, NULL);
+	} else {
+		union iwreq_data wrqu;
+
+		/* send event with empty BSSID to indicate we're not associated */
+		MAC_ZERO(wrqu.ap_addr.sa_data);
+		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+		wireless_send_event(adev->ndev, SIOCGIWAP, &wrqu, NULL);
+	}
+
+	adev->status = new_status;
+
+	switch (new_status) {
+	case ACX_STATUS_1_SCANNING:
+		adev->scan_retries = 0;
+		/* 1.0 s initial scan time */
+		acx_set_timer(adev, 1000000);
+		break;
+	case ACX_STATUS_2_WAIT_AUTH:
+	case ACX_STATUS_3_AUTHENTICATED:
+		adev->auth_or_assoc_retries = 0;
+		acx_set_timer(adev, 1500000); /* 1.5 s */
+		break;
+	}
+
+#if QUEUE_OPEN_AFTER_ASSOC
+	if (new_status == ACX_STATUS_4_ASSOCIATED)	{
+		if (old_status < ACX_STATUS_4_ASSOCIATED) {
+			/* ah, we're newly associated now,
+			 * so let's indicate carrier */
+			acx_carrier_on(adev->ndev, "after association");
+			acx_wake_queue(adev->ndev, "after association");
+		}
+	} else {
+		/* not associated any more, so let's kill carrier */
+		if (old_status >= ACX_STATUS_4_ASSOCIATED) {
+			acx_carrier_off(adev->ndev, "after losing association");
+			acx_stop_queue(adev->ndev, "after losing association");
+		}
+	}
+#endif
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acx_i_timer
+**
+** Fires up periodically. Used to kick scan/auth/assoc if something goes wrong
+*/
+void
+acx_i_timer(unsigned long address)
+{
+	unsigned long flags;
+	acx_device_t *adev = (acx_device_t*)address;
+
+	FN_ENTER;
+
+	acx_lock(adev, flags);
+
+	log(L_DEBUG|L_ASSOC, "%s: adev->status=%d (%s)\n",
+		__func__, adev->status, acx_get_status_name(adev->status));
+
+	switch (adev->status) {
+	case ACX_STATUS_1_SCANNING:
+		/* was set to 0 by set_status() */
+		if (++adev->scan_retries < 7) {
+			acx_set_timer(adev, 1000000);
+			/* used to interrogate for scan status.
+			** We rely on SCAN_COMPLETE IRQ instead */
+			log(L_ASSOC, "continuing scan (%d sec)\n",
+					adev->scan_retries);
+		} else {
+			log(L_ASSOC, "stopping scan\n");
+			/* send stop_scan cmd when we leave the interrupt context,
+			 * and make a decision what to do next (COMPLETE_SCAN) */
+			acx_schedule_task(adev,
+				ACX_AFTER_IRQ_CMD_STOP_SCAN + ACX_AFTER_IRQ_COMPLETE_SCAN);
+		}
+		break;
+	case ACX_STATUS_2_WAIT_AUTH:
+		/* was set to 0 by set_status() */
+		if (++adev->auth_or_assoc_retries < 10) {
+			log(L_ASSOC, "resend authen1 request (attempt %d)\n",
+					adev->auth_or_assoc_retries + 1);
+			acx_l_transmit_authen1(adev);
+		} else {
+			/* time exceeded: fall back to scanning mode */
+			log(L_ASSOC,
+			       "authen1 request reply timeout, giving up\n");
+			/* we are a STA, need to find AP anyhow */
+			acx_set_status(adev, ACX_STATUS_1_SCANNING);
+			acx_schedule_task(adev, ACX_AFTER_IRQ_RESTART_SCAN);
+		}
+		/* used to be 1500000, but some other driver uses 2.5s */
+		acx_set_timer(adev, 2500000);
+		break;
+	case ACX_STATUS_3_AUTHENTICATED:
+		/* was set to 0 by set_status() */
+		if (++adev->auth_or_assoc_retries < 10) {
+			log(L_ASSOC,	"resend assoc request (attempt %d)\n",
+					adev->auth_or_assoc_retries + 1);
+			acx_l_transmit_assoc_req(adev);
+		} else {
+			/* time exceeded: give up */
+			log(L_ASSOC,
+				"association request reply timeout, giving up\n");
+			/* we are a STA, need to find AP anyhow */
+			acx_set_status(adev, ACX_STATUS_1_SCANNING);
+			acx_schedule_task(adev, ACX_AFTER_IRQ_RESTART_SCAN);
+		}
+		acx_set_timer(adev, 2500000); /* see above */
+		break;
+	case ACX_STATUS_4_ASSOCIATED:
+	default:
+		break;
+	}
+
+	acx_unlock(adev, flags);
+
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acx_set_timer
+**
+** Sets the 802.11 state management timer's timeout.
+*/
+void
+acx_set_timer(acx_device_t *adev, int timeout_us)
+{
+	FN_ENTER;
+
+	log(L_DEBUG|L_IRQ, "%s(%u ms)\n", __func__, timeout_us/1000);
+	if (!(adev->dev_state_mask & ACX_STATE_IFACE_UP)) {
+		printk("attempt to set the timer "
+			"when the card interface is not up!\n");
+		goto end;
+	}
+
+	/* first check if the timer was already initialized, THEN modify it */
+	if (adev->mgmt_timer.function) {
+		mod_timer(&adev->mgmt_timer,
+				jiffies + (timeout_us * HZ / 1000000));
+	}
+end:
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acx_l_transmit_assocresp
+**
+** We are an AP here
+*/
+static const u8
+dot11ratebyte[] = {
+	DOT11RATEBYTE_1,
+	DOT11RATEBYTE_2,
+	DOT11RATEBYTE_5_5,
+	DOT11RATEBYTE_6_G,
+	DOT11RATEBYTE_9_G,
+	DOT11RATEBYTE_11,
+	DOT11RATEBYTE_12_G,
+	DOT11RATEBYTE_18_G,
+	DOT11RATEBYTE_22,
+	DOT11RATEBYTE_24_G,
+	DOT11RATEBYTE_36_G,
+	DOT11RATEBYTE_48_G,
+	DOT11RATEBYTE_54_G,
+};
+
+static inline int
+find_pos(const u8 *p, int size, u8 v)
+{
+	int i;
+	for (i = 0; i < size; i++)
+		if (p[i] == v)
+			return i;
+	/* printk a message about strange byte? */
+	return 0;
+}
+
+static void
+add_bits_to_ratemasks(u8* ratevec, int len, u16* brate, u16* orate)
+{
+	while (len--) {
+		int n = 1 << find_pos(dot11ratebyte,
+				sizeof(dot11ratebyte), *ratevec & 0x7f);
+		if (*ratevec & 0x80)
+			*brate |= n;
+		*orate |= n;
+		ratevec++;
+	}
+}
+
+static int
+acx_l_transmit_assocresp(acx_device_t *adev, const wlan_fr_assocreq_t *req)
+{
+	struct tx *tx;
+	struct wlan_hdr_mgmt *head;
+	struct assocresp_frame_body *body;
+	u8 *p;
+	const u8 *da;
+	/* const u8 *sa; */
+	const u8 *bssid;
+	client_t *clt;
+
+	FN_ENTER;
+
+	/* sa = req->hdr->a1; */
+	da = req->hdr->a2;
+	bssid = req->hdr->a3;
+
+	clt = acx_l_sta_list_get(adev, da);
+	if (!clt)
+		goto ok;
+
+	/* Assoc without auth is a big no-no */
+	/* Let's be liberal: if already assoc'ed STA sends assoc req again,
+	** we won't be rude */
+	if (clt->used != CLIENT_AUTHENTICATED_2
+	 && clt->used != CLIENT_ASSOCIATED_3) {
+		acx_l_transmit_deauthen(adev, da, WLAN_MGMT_REASON_CLASS2_NONAUTH);
+		goto bad;
+	}
+
+	clt->used = CLIENT_ASSOCIATED_3;
+
+	if (clt->aid == 0)
+		clt->aid = ++adev->aid;
+	clt->cap_info = ieee2host16(*(req->cap_info));
+
+	/* We cheat here a bit. We don't really care which rates are flagged
+	** as basic by the client, so we stuff them in single ratemask */
+	clt->rate_cap = 0;
+	if (req->supp_rates)
+		add_bits_to_ratemasks(req->supp_rates->rates,
+			req->supp_rates->len, &clt->rate_cap, &clt->rate_cap);
+	if (req->ext_rates)
+		add_bits_to_ratemasks(req->ext_rates->rates,
+			req->ext_rates->len, &clt->rate_cap, &clt->rate_cap);
+	/* We can check that client supports all basic rates,
+	** and deny assoc if not. But let's be liberal, right? ;) */
+	clt->rate_cfg = clt->rate_cap & adev->rate_oper;
+	if (!clt->rate_cfg) clt->rate_cfg = 1 << lowest_bit(adev->rate_oper);
+	clt->rate_cur = 1 << lowest_bit(clt->rate_cfg);
+	if (IS_ACX100(adev))
+		clt->rate_100 = acx_bitpos2rate100[lowest_bit(clt->rate_cfg)];
+	clt->fallback_count = clt->stepup_count = 0;
+	clt->ignore_count = 16;
+
+	tx = acx_l_alloc_tx(adev);
+	if (!tx)
+		goto bad;
+	head = acx_l_get_txbuf(adev, tx);
+	if (!head) {
+		acx_l_dealloc_tx(adev, tx);
+		goto bad;
+	}
+	body = (void*)(head + 1);
+
+	head->fc = WF_FSTYPE_ASSOCRESPi;
+	head->dur = req->hdr->dur;
+	MAC_COPY(head->da, da);
+	MAC_COPY(head->sa, adev->dev_addr);
+	MAC_COPY(head->bssid, bssid);
+	head->seq = req->hdr->seq;
+
+	body->cap_info = host2ieee16(adev->capabilities);
+	body->status = host2ieee16(0);
+	body->aid = host2ieee16(clt->aid);
+	p = wlan_fill_ie_rates((u8*)&body->rates, adev->rate_supported_len,
+							adev->rate_supported);
+	p = wlan_fill_ie_rates_ext(p, adev->rate_supported_len,
+							adev->rate_supported);
+
+	acx_l_tx_data(adev, tx, p - (u8*)head);
+ok:
+	FN_EXIT1(OK);
+	return OK;
+bad:
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+
+
+/***********************************************************************
+* acx_l_transmit_reassocresp
+
+You may be wondering, just like me, what the hell ReAuth is.
+In practice it was seen sent by STA when STA feels like losing connection.
+
+[802.11]
+
+5.4.2.3 Reassociation
+
+Association is sufficient for no-transition message delivery between
+IEEE 802.11 stations. Additional functionality is needed to support
+BSS-transition mobility. The additional required functionality
+is provided by the reassociation service. Reassociation is a DSS.
+The reassociation service is invoked to 'move' a current association
+from one AP to another. This keeps the DS informed of the current
+mapping between AP and STA as the station moves from BSS to BSS within
+an ESS. Reassociation also enables changing association attributes
+of an established association while the STA remains associated with
+the same AP. Reassociation is always initiated by the mobile STA.
+
+5.4.3.1 Authentication
+...
+A STA may be authenticated with many other STAs at any given instant.
+
+5.4.3.1.1 Preauthentication
+
+Because the authentication process could be time-consuming (depending
+on the authentication protocol in use), the authentication service can
+be invoked independently of the association service. Preauthentication
+is typically done by a STA while it is already associated with an AP
+(with which it previously authenticated). IEEE 802.11 does not require
+that STAs preauthenticate with APs. However, authentication is required
+before an association can be established. If the authentication is left
+until reassociation time, this may impact the speed with which a STA can
+reassociate between APs, limiting BSS-transition mobility performance.
+The use of preauthentication takes the authentication service overhead
+out of the time-critical reassociation process.
+
+5.7.3 Reassociation
+
+For a STA to reassociate, the reassociation service causes the following
+message to occur:
+
+  Reassociation request
+
+* Message type: Management
+* Message subtype: Reassociation request
+* Information items:
+  - IEEE address of the STA
+  - IEEE address of the AP with which the STA will reassociate
+  - IEEE address of the AP with which the STA is currently associated
+  - ESSID
+* Direction of message: From STA to 'new' AP
+
+The address of the current AP is included for efficiency. The inclusion
+of the current AP address facilitates MAC reassociation to be independent
+of the DS implementation.
+
+  Reassociation response
+* Message type: Management
+* Message subtype: Reassociation response
+* Information items:
+  - Result of the requested reassociation. (success/failure)
+  - If the reassociation is successful, the response shall include the AID.
+* Direction of message: From AP to STA
+
+7.2.3.6 Reassociation Request frame format
+
+The frame body of a management frame of subtype Reassociation Request
+contains the information shown in Table 9.
+
+Table 9 Reassociation Request frame body
+Order Information
+1 Capability information
+2 Listen interval
+3 Current AP address
+4 SSID
+5 Supported rates
+
+7.2.3.7 Reassociation Response frame format
+
+The frame body of a management frame of subtype Reassociation Response
+contains the information shown in Table 10.
+
+Table 10 Reassociation Response frame body
+Order Information
+1 Capability information
+2 Status code
+3 Association ID (AID)
+4 Supported rates
+
+*/
+static int
+acx_l_transmit_reassocresp(acx_device_t *adev, const wlan_fr_reassocreq_t *req)
+{
+	struct tx *tx;
+	struct wlan_hdr_mgmt *head;
+	struct reassocresp_frame_body *body;
+	u8 *p;
+	const u8 *da;
+	/* const u8 *sa; */
+	const u8 *bssid;
+	client_t *clt;
+
+	FN_ENTER;
+
+	/* sa = req->hdr->a1; */
+	da = req->hdr->a2;
+	bssid = req->hdr->a3;
+
+	/* Must be already authenticated, so it must be in the list */
+	clt = acx_l_sta_list_get(adev, da);
+	if (!clt)
+		goto ok;
+
+	/* Assoc without auth is a big no-no */
+	/* Already assoc'ed STAs sending ReAssoc req are ok per 802.11 */
+	if (clt->used != CLIENT_AUTHENTICATED_2
+	 && clt->used != CLIENT_ASSOCIATED_3) {
+		acx_l_transmit_deauthen(adev, da, WLAN_MGMT_REASON_CLASS2_NONAUTH);
+		goto bad;
+	}
+
+	clt->used = CLIENT_ASSOCIATED_3;
+	if (clt->aid == 0) {
+		clt->aid = ++adev->aid;
+	}
+	if (req->cap_info)
+		clt->cap_info = ieee2host16(*(req->cap_info));
+
+	/* We cheat here a bit. We don't really care which rates are flagged
+	** as basic by the client, so we stuff them in single ratemask */
+	clt->rate_cap = 0;
+	if (req->supp_rates)
+		add_bits_to_ratemasks(req->supp_rates->rates,
+			req->supp_rates->len, &clt->rate_cap, &clt->rate_cap);
+	if (req->ext_rates)
+		add_bits_to_ratemasks(req->ext_rates->rates,
+			req->ext_rates->len, &clt->rate_cap, &clt->rate_cap);
+	/* We can check that client supports all basic rates,
+	** and deny assoc if not. But let's be liberal, right? ;) */
+	clt->rate_cfg = clt->rate_cap & adev->rate_oper;
+	if (!clt->rate_cfg) clt->rate_cfg = 1 << lowest_bit(adev->rate_oper);
+	clt->rate_cur = 1 << lowest_bit(clt->rate_cfg);
+	if (IS_ACX100(adev))
+		clt->rate_100 = acx_bitpos2rate100[lowest_bit(clt->rate_cfg)];
+
+	clt->fallback_count = clt->stepup_count = 0;
+	clt->ignore_count = 16;
+
+	tx = acx_l_alloc_tx(adev);
+	if (!tx)
+		goto ok;
+	head = acx_l_get_txbuf(adev, tx);
+	if (!head) {
+		acx_l_dealloc_tx(adev, tx);
+		goto ok;
+	}
+	body = (void*)(head + 1);
+
+	head->fc = WF_FSTYPE_REASSOCRESPi;
+	head->dur = req->hdr->dur;
+	MAC_COPY(head->da, da);
+	MAC_COPY(head->sa, adev->dev_addr);
+	MAC_COPY(head->bssid, bssid);
+	head->seq = req->hdr->seq;
+
+	/* IEs: 1. caps */
+	body->cap_info = host2ieee16(adev->capabilities);
+	/* 2. status code */
+	body->status = host2ieee16(0);
+	/* 3. AID */
+	body->aid = host2ieee16(clt->aid);
+	/* 4. supp rates */
+	p = wlan_fill_ie_rates((u8*)&body->rates, adev->rate_supported_len,
+							adev->rate_supported);
+	/* 5. ext supp rates */
+	p = wlan_fill_ie_rates_ext(p, adev->rate_supported_len,
+							adev->rate_supported);
+
+	acx_l_tx_data(adev, tx, p - (u8*)head);
+ok:
+	FN_EXIT1(OK);
+	return OK;
+bad:
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+
+
+/***********************************************************************
+** acx_l_process_disassoc_from_sta
+*/
+static void
+acx_l_process_disassoc_from_sta(acx_device_t *adev, const wlan_fr_disassoc_t *req)
+{
+	const u8 *ta;
+	client_t *clt;
+
+	FN_ENTER;
+
+	ta = req->hdr->a2;
+	clt = acx_l_sta_list_get(adev, ta);
+	if (!clt)
+		goto end;
+
+	if (clt->used != CLIENT_ASSOCIATED_3
+	 && clt->used != CLIENT_AUTHENTICATED_2) {
+		/* it's disassociating, but it's
+		** not even authenticated! Let it know that */
+		acxlog_mac(L_ASSOC|L_XFER, "peer ", ta, "has sent disassoc "
+			"req but it is not even auth'ed! sending deauth\n");
+		acx_l_transmit_deauthen(adev, ta,
+			WLAN_MGMT_REASON_CLASS2_NONAUTH);
+		clt->used = CLIENT_EXIST_1;
+	} else {
+		/* mark it as auth'ed only */
+		clt->used = CLIENT_AUTHENTICATED_2;
+	}
+end:
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acx_l_process_deauthen_from_sta
+*/
+static void
+acx_l_process_deauth_from_sta(acx_device_t *adev, const wlan_fr_deauthen_t *req)
+{
+	const wlan_hdr_t *hdr;
+	client_t *client;
+
+	FN_ENTER;
+
+	hdr = req->hdr;
+
+	if (acx_debug & L_ASSOC) {
+		acx_print_mac("got deauth from sta:", hdr->a2, " ");
+		acx_print_mac("a1:", hdr->a1, " ");
+		acx_print_mac("a3:", hdr->a3, " ");
+		acx_print_mac("adev->addr:", adev->dev_addr, " ");
+		acx_print_mac("adev->bssid:", adev->bssid, "\n");
+	}
+
+	if (!mac_is_equal(adev->dev_addr, hdr->a1)) {
+		goto end;
+	}
+
+	client = acx_l_sta_list_get(adev, hdr->a2);
+	if (!client) {
+		goto end;
+	}
+	client->used = CLIENT_EXIST_1;
+end:
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acx_l_process_disassoc_from_ap
+*/
+static void
+acx_l_process_disassoc_from_ap(acx_device_t *adev, const wlan_fr_disassoc_t *req)
+{
+	FN_ENTER;
+
+	if (!adev->ap_client) {
+		/* Hrm, we aren't assoc'ed yet anyhow... */
+		goto end;
+	}
+
+	printk("%s: got disassoc frame with reason %d (%s)\n",
+		adev->ndev->name, *req->reason,
+		acx_wlan_reason_str(*req->reason));
+
+	if (mac_is_equal(adev->dev_addr, req->hdr->a1)) {
+		acx_l_transmit_deauthen(adev, adev->bssid,
+				WLAN_MGMT_REASON_DEAUTH_LEAVING);
+		SET_BIT(adev->set_mask, GETSET_RESCAN);
+		acx_schedule_task(adev, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
+	}
+end:
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acx_l_process_deauth_from_ap
+*/
+static void
+acx_l_process_deauth_from_ap(acx_device_t *adev, const wlan_fr_deauthen_t *req)
+{
+	FN_ENTER;
+
+	if (!adev->ap_client) {
+		/* Hrm, we aren't assoc'ed yet anyhow... */
+		goto end;
+	}
+
+	printk("%s: got deauth frame with reason %d (%s)\n",
+		adev->ndev->name, *req->reason,
+		acx_wlan_reason_str(*req->reason));
+
+	/* Chk: is ta verified to be from our AP? */
+	if (mac_is_equal(adev->dev_addr, req->hdr->a1)) {
+		log(L_DEBUG, "AP sent us deauth packet\n");
+		SET_BIT(adev->set_mask, GETSET_RESCAN);
+		acx_schedule_task(adev, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
+	}
+end:
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acx_l_rx
+**
+** The end of the Rx path. Pulls data from a rxhostdesc into a socket
+** buffer and feeds it to the network stack via netif_rx().
+*/
+static void
+acx_l_rx(acx_device_t *adev, rxbuffer_t *rxbuf)
+{
+	FN_ENTER;
+	if (likely(adev->dev_state_mask & ACX_STATE_IFACE_UP)) {
+		struct sk_buff *skb;
+		skb = acx_rxbuf_to_ether(adev, rxbuf);
+		if (likely(skb)) {
+			netif_rx(skb);
+			adev->ndev->last_rx = jiffies;
+			adev->stats.rx_packets++;
+			adev->stats.rx_bytes += skb->len;
+		}
+	}
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acx_l_process_data_frame_master
+*/
+static int
+acx_l_process_data_frame_master(acx_device_t *adev, rxbuffer_t *rxbuf)
+{
+	struct wlan_hdr *hdr;
+	struct tx *tx;
+	void *txbuf;
+	int len;
+	int result = NOT_OK;
+
+	FN_ENTER;
+
+	hdr = acx_get_wlan_hdr(adev, rxbuf);
+
+	switch (WF_FC_FROMTODSi & hdr->fc) {
+	case 0:
+	case WF_FC_FROMDSi:
+		log(L_DEBUG, "ap->sta or adhoc->adhoc data frame ignored\n");
+		goto done;
+	case WF_FC_TODSi:
+		break;
+	default: /* WF_FC_FROMTODSi */
+		log(L_DEBUG, "wds data frame ignored (TODO)\n");
+		goto done;
+	}
+
+	/* check if it is our BSSID, if not, leave */
+	if (!mac_is_equal(adev->bssid, hdr->a1)) {
+		goto done;
+	}
+
+	if (mac_is_equal(adev->dev_addr, hdr->a3)) {
+		/* this one is for us */
+		acx_l_rx(adev, rxbuf);
+	} else {
+		if (mac_is_bcast(hdr->a3)) {
+			/* this one is bcast, rx it too */
+			acx_l_rx(adev, rxbuf);
+		}
+		tx = acx_l_alloc_tx(adev);
+		if (!tx) {
+			goto fail;
+		}
+		/* repackage, tx, and hope it someday reaches its destination */
+		/* order is important, we do it in-place */
+		MAC_COPY(hdr->a1, hdr->a3);
+		MAC_COPY(hdr->a3, hdr->a2);
+		MAC_COPY(hdr->a2, adev->bssid);
+		/* To_DS = 0, From_DS = 1 */
+		hdr->fc = WF_FC_FROMDSi + WF_FTYPE_DATAi;
+
+		txbuf = acx_l_get_txbuf(adev, tx);
+		if (txbuf) {
+			len = RXBUF_BYTES_RCVD(adev, rxbuf);
+			memcpy(txbuf, hdr, len);
+			acx_l_tx_data(adev, tx, len);
+		} else {
+			acx_l_dealloc_tx(adev, tx);
+		}
+	}
+done:
+	result = OK;
+fail:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_l_process_data_frame_client
+*/
+static int
+acx_l_process_data_frame_client(acx_device_t *adev, rxbuffer_t *rxbuf)
+{
+	const u8 *da, *bssid;
+	const wlan_hdr_t *hdr;
+	struct net_device *ndev = adev->ndev;
+	int result = NOT_OK;
+
+	FN_ENTER;
+
+	if (ACX_STATUS_4_ASSOCIATED != adev->status)
+		goto drop;
+
+	hdr = acx_get_wlan_hdr(adev, rxbuf);
+
+	switch (WF_FC_FROMTODSi & hdr->fc) {
+	case 0:
+		if (adev->mode != ACX_MODE_0_ADHOC) {
+			log(L_DEBUG, "adhoc->adhoc data frame ignored\n");
+			goto drop;
+		}
+		bssid = hdr->a3;
+		break;
+	case WF_FC_FROMDSi:
+		if (adev->mode != ACX_MODE_2_STA) {
+			log(L_DEBUG, "ap->sta data frame ignored\n");
+			goto drop;
+		}
+		bssid = hdr->a2;
+		break;
+	case WF_FC_TODSi:
+		log(L_DEBUG, "sta->ap data frame ignored\n");
+		goto drop;
+	default: /* WF_FC_FROMTODSi: wds->wds */
+		log(L_DEBUG, "wds data frame ignored (todo)\n");
+		goto drop;
+	}
+
+	da = hdr->a1;
+
+	if (unlikely(acx_debug & L_DEBUG)) {
+		acx_print_mac("rx: da=", da, "");
+		acx_print_mac(" bssid=", bssid, "");
+		acx_print_mac(" adev->bssid=", adev->bssid, "");
+		acx_print_mac(" adev->addr=", adev->dev_addr, "\n");
+	}
+
+	/* promiscuous mode --> receive all packets */
+	if (unlikely(ndev->flags & IFF_PROMISC))
+		goto process;
+
+	/* FIRST, check if it is our BSSID */
+	if (!mac_is_equal(adev->bssid, bssid)) {
+		/* is not our BSSID, so bail out */
+		goto drop;
+	}
+
+	/* then, check if it is our address */
+	if (mac_is_equal(adev->dev_addr, da)) {
+		goto process;
+	}
+
+	/* then, check if it is broadcast */
+	if (mac_is_bcast(da)) {
+		goto process;
+	}
+
+	if (mac_is_mcast(da)) {
+		/* unconditionally receive all multicasts */
+		if (ndev->flags & IFF_ALLMULTI)
+			goto process;
+
+		/* FIXME: need to check against the list of
+		 * multicast addresses that are configured
+		 * for the interface (ifconfig) */
+		log(L_XFER, "FIXME: multicast packet, need to check "
+			"against a list of multicast addresses "
+			"(to be created!); accepting packet for now\n");
+		/* for now, just accept it here */
+		goto process;
+	}
+
+	log(L_DEBUG, "rx: foreign packet, dropping\n");
+	goto drop;
+process:
+	/* receive packet */
+	acx_l_rx(adev, rxbuf);
+
+	result = OK;
+drop:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_l_process_mgmt_frame
+**
+** Theory of operation: mgmt packet gets parsed (to make it easy
+** to access variable-sized IEs), results stored in 'parsed'.
+** Then we react to the packet.
+*/
+typedef union parsed_mgmt_req {
+	wlan_fr_mgmt_t mgmt;
+	wlan_fr_assocreq_t assocreq;
+	wlan_fr_reassocreq_t reassocreq;
+	wlan_fr_assocresp_t assocresp;
+	wlan_fr_reassocresp_t reassocresp;
+	wlan_fr_beacon_t beacon;
+	wlan_fr_disassoc_t disassoc;
+	wlan_fr_authen_t authen;
+	wlan_fr_deauthen_t deauthen;
+	wlan_fr_proberesp_t proberesp;
+} parsed_mgmt_req_t;
+
+void BUG_excessive_stack_usage(void);
+
+static int
+acx_l_process_mgmt_frame(acx_device_t *adev, rxbuffer_t *rxbuf)
+{
+	parsed_mgmt_req_t parsed;	/* takes ~100 bytes of stack */
+	wlan_hdr_t *hdr;
+	int adhoc, sta_scan, sta, ap;
+	int len;
+
+	if (sizeof(parsed) > 256)
+		BUG_excessive_stack_usage();
+
+	FN_ENTER;
+
+	hdr = acx_get_wlan_hdr(adev, rxbuf);
+
+	/* Management frames never have these set */
+	if (WF_FC_FROMTODSi & hdr->fc) {
+		FN_EXIT1(NOT_OK);
+		return NOT_OK;
+	}
+
+	len = RXBUF_BYTES_RCVD(adev, rxbuf);
+	if (WF_FC_ISWEPi & hdr->fc)
+		len -= 0x10;
+
+	adhoc = (adev->mode == ACX_MODE_0_ADHOC);
+	sta_scan = ((adev->mode == ACX_MODE_2_STA)
+		 && (adev->status != ACX_STATUS_4_ASSOCIATED));
+	sta = ((adev->mode == ACX_MODE_2_STA)
+	    && (adev->status == ACX_STATUS_4_ASSOCIATED));
+	ap = (adev->mode == ACX_MODE_3_AP);
+
+	switch (WF_FC_FSTYPEi & hdr->fc) {
+	/* beacons first, for speed */
+	case WF_FSTYPE_BEACONi:
+		memset(&parsed.beacon, 0, sizeof(parsed.beacon));
+		parsed.beacon.hdr = hdr;
+		parsed.beacon.len = len;
+		if (acx_debug & L_DATA) {
+			printk("beacon len:%d fc:%04X dur:%04X seq:%04X",
+			       len, hdr->fc, hdr->dur, hdr->seq);
+			acx_print_mac(" a1:", hdr->a1, "");
+			acx_print_mac(" a2:", hdr->a2, "");
+			acx_print_mac(" a3:", hdr->a3, "\n");
+		}
+		wlan_mgmt_decode_beacon(&parsed.beacon);
+		/* beacon and probe response are very similar, so... */
+		acx_l_process_probe_response(adev, &parsed.beacon, rxbuf);
+		break;
+	case WF_FSTYPE_ASSOCREQi:
+		if (!ap)
+			break;
+		memset(&parsed.assocreq, 0, sizeof(parsed.assocreq));
+		parsed.assocreq.hdr = hdr;
+		parsed.assocreq.len = len;
+		wlan_mgmt_decode_assocreq(&parsed.assocreq);
+		if (mac_is_equal(hdr->a1, adev->bssid)
+		 && mac_is_equal(hdr->a3, adev->bssid)) {
+			acx_l_transmit_assocresp(adev, &parsed.assocreq);
+		}
+		break;
+	case WF_FSTYPE_REASSOCREQi:
+		if (!ap)
+			break;
+		memset(&parsed.assocreq, 0, sizeof(parsed.assocreq));
+		parsed.assocreq.hdr = hdr;
+		parsed.assocreq.len = len;
+		wlan_mgmt_decode_assocreq(&parsed.assocreq);
+		/* reassocreq and assocreq are equivalent */
+		acx_l_transmit_reassocresp(adev, &parsed.reassocreq);
+		break;
+	case WF_FSTYPE_ASSOCRESPi:
+		if (!sta_scan)
+			break;
+		memset(&parsed.assocresp, 0, sizeof(parsed.assocresp));
+		parsed.assocresp.hdr = hdr;
+		parsed.assocresp.len = len;
+		wlan_mgmt_decode_assocresp(&parsed.assocresp);
+		acx_l_process_assocresp(adev, &parsed.assocresp);
+		break;
+	case WF_FSTYPE_REASSOCRESPi:
+		if (!sta_scan)
+			break;
+		memset(&parsed.assocresp, 0, sizeof(parsed.assocresp));
+		parsed.assocresp.hdr = hdr;
+		parsed.assocresp.len = len;
+		wlan_mgmt_decode_assocresp(&parsed.assocresp);
+		acx_l_process_reassocresp(adev, &parsed.reassocresp);
+		break;
+	case WF_FSTYPE_PROBEREQi:
+		if (ap || adhoc) {
+			/* FIXME: since we're supposed to be an AP,
+			** we need to return a Probe Response packet.
+			** Currently firmware is doing it for us,
+			** but firmware is buggy! See comment elsewhere --vda */
+		}
+		break;
+	case WF_FSTYPE_PROBERESPi:
+		memset(&parsed.proberesp, 0, sizeof(parsed.proberesp));
+		parsed.proberesp.hdr = hdr;
+		parsed.proberesp.len = len;
+		wlan_mgmt_decode_proberesp(&parsed.proberesp);
+		acx_l_process_probe_response(adev, &parsed.proberesp, rxbuf);
+		break;
+	case 6:
+	case 7:
+		/* exit */
+		break;
+	case WF_FSTYPE_ATIMi:
+		/* exit */
+		break;
+	case WF_FSTYPE_DISASSOCi:
+		if (!sta && !ap)
+			break;
+		memset(&parsed.disassoc, 0, sizeof(parsed.disassoc));
+		parsed.disassoc.hdr = hdr;
+		parsed.disassoc.len = len;
+		wlan_mgmt_decode_disassoc(&parsed.disassoc);
+		if (sta)
+			acx_l_process_disassoc_from_ap(adev, &parsed.disassoc);
+		else
+			acx_l_process_disassoc_from_sta(adev, &parsed.disassoc);
+		break;
+	case WF_FSTYPE_AUTHENi:
+		if (!sta_scan && !ap)
+			break;
+		memset(&parsed.authen, 0, sizeof(parsed.authen));
+		parsed.authen.hdr = hdr;
+		parsed.authen.len = len;
+		wlan_mgmt_decode_authen(&parsed.authen);
+		acx_l_process_authen(adev, &parsed.authen);
+		break;
+	case WF_FSTYPE_DEAUTHENi:
+		if (!sta && !ap)
+			break;
+		memset(&parsed.deauthen, 0, sizeof(parsed.deauthen));
+		parsed.deauthen.hdr = hdr;
+		parsed.deauthen.len = len;
+		wlan_mgmt_decode_deauthen(&parsed.deauthen);
+		if (sta)
+			acx_l_process_deauth_from_ap(adev, &parsed.deauthen);
+		else
+			acx_l_process_deauth_from_sta(adev, &parsed.deauthen);
+		break;
+	}
+
+	FN_EXIT1(OK);
+	return OK;
+}
+
+
+#ifdef UNUSED
+/***********************************************************************
+** acx_process_class_frame
+**
+** Called from IRQ context only
+*/
+static int
+acx_process_class_frame(acx_device_t *adev, rxbuffer_t *rxbuf, int vala)
+{
+	return OK;
+}
+#endif
+
+
+/***********************************************************************
+** acx_l_process_NULL_frame
+*/
+#ifdef BOGUS_ITS_NOT_A_NULL_FRAME_HANDLER_AT_ALL
+static int
+acx_l_process_NULL_frame(acx_device_t *adev, rxbuffer_t *rxbuf, int vala)
+{
+	const signed char *esi;
+	const u8 *ebx;
+	const wlan_hdr_t *hdr;
+	const client_t *client;
+	int result = NOT_OK;
+
+	hdr = acx_get_wlan_hdr(adev, rxbuf);
+
+	switch (WF_FC_FROMTODSi & hdr->fc) {
+	case 0:
+		esi = hdr->a1;
+		ebx = hdr->a2;
+		break;
+	case WF_FC_FROMDSi:
+		esi = hdr->a1;
+		ebx = hdr->a3;
+		break;
+	case WF_FC_TODSi:
+		esi = hdr->a1;
+		ebx = hdr->a2;
+		break;
+	default: /* WF_FC_FROMTODSi */
+		esi = hdr->a1; /* added by me! --vda */
+		ebx = hdr->a2;
+	}
+
+	if (esi[0x0] < 0) {
+		result = OK;
+		goto done;
+	}
+
+	client = acx_l_sta_list_get(adev, ebx);
+	if (client)
+		result = NOT_OK;
+	else {
+#ifdef IS_IT_BROKEN
+		log(L_DEBUG|L_XFER, "<transmit_deauth 7>\n");
+		acx_l_transmit_deauthen(adev, ebx,
+			WLAN_MGMT_REASON_CLASS2_NONAUTH);
+#else
+		log(L_DEBUG, "received NULL frame from unknown client! "
+			"We really shouldn't send deauthen here, right?\n");
+#endif
+		result = OK;
+	}
+done:
+	return result;
+}
+#endif
+
+
+/***********************************************************************
+** acx_l_process_probe_response
+*/
+static int
+acx_l_process_probe_response(acx_device_t *adev, wlan_fr_proberesp_t *req,
+			const rxbuffer_t *rxbuf)
+{
+	struct client *bss;
+	wlan_hdr_t *hdr;
+
+	FN_ENTER;
+
+	hdr = req->hdr;
+
+	if (mac_is_equal(hdr->a3, adev->dev_addr)) {
+		log(L_ASSOC, "huh, scan found our own MAC!?\n");
+		goto ok; /* just skip this one silently */
+	}
+
+	bss = acx_l_sta_list_get_or_add(adev, hdr->a2);
+
+	/* NB: be careful modifying bss data! It may be one
+	** of the already known clients (like our AP if we are a STA)
+	** Thus do not blindly modify e.g. current ratemask! */
+
+	if (STA_LIST_ADD_CAN_FAIL && !bss) {
+		/* uh oh, we found more sites/stations than we can handle with
+		 * our current setup: pull the emergency brake and stop scanning! */
+		acx_schedule_task(adev, ACX_AFTER_IRQ_CMD_STOP_SCAN);
+		/* TODO: a nice comment what below call achieves --vda */
+		acx_set_status(adev, ACX_STATUS_2_WAIT_AUTH);
+		goto ok;
+	}
+	/* NB: get_or_add already filled bss->address = hdr->a2 */
+	MAC_COPY(bss->bssid, hdr->a3);
+
+	/* copy the ESSID element */
+	if (req->ssid && req->ssid->len <= IW_ESSID_MAX_SIZE) {
+		bss->essid_len = req->ssid->len;
+		memcpy(bss->essid, req->ssid->ssid, req->ssid->len);
+		bss->essid[req->ssid->len] = '\0';
+	} else {
+		/* Either no ESSID IE or oversized one */
+		printk("%s: received packet has bogus ESSID\n",
+						    adev->ndev->name);
+	}
+
+	if (req->ds_parms)
+		bss->channel = req->ds_parms->curr_ch;
+	if (req->cap_info)
+		bss->cap_info = ieee2host16(*req->cap_info);
+
+	bss->sir = acx_signal_to_winlevel(rxbuf->phy_level);
+	bss->snr = acx_signal_to_winlevel(rxbuf->phy_snr);
+
+	bss->rate_cap = 0;	/* operational mask */
+	bss->rate_bas = 0;	/* basic mask */
+	if (req->supp_rates)
+		add_bits_to_ratemasks(req->supp_rates->rates,
+			req->supp_rates->len, &bss->rate_bas, &bss->rate_cap);
+	if (req->ext_rates)
+		add_bits_to_ratemasks(req->ext_rates->rates,
+			req->ext_rates->len, &bss->rate_bas, &bss->rate_cap);
+	/* Fix up any possible bogosity - code elsewhere
+	 * is not expecting empty masks */
+	if (!bss->rate_cap)
+		bss->rate_cap = adev->rate_basic;
+	if (!bss->rate_bas)
+		bss->rate_bas = 1 << lowest_bit(bss->rate_cap);
+	if (!bss->rate_cur)
+		bss->rate_cur = 1 << lowest_bit(bss->rate_bas);
+
+	/* People moan about this being too noisy at L_ASSOC */
+	log(L_DEBUG,
+		"found %s: ESSID='%s' ch=%d "
+		"BSSID="MACSTR" caps=0x%04X SIR=%d SNR=%d\n",
+		(bss->cap_info & WF_MGMT_CAP_IBSS) ? "Ad-Hoc peer" : "AP",
+		bss->essid, bss->channel, MAC(bss->bssid), bss->cap_info,
+		bss->sir, bss->snr);
+ok:
+	FN_EXIT0;
+	return OK;
+}
+
+
+/***********************************************************************
+** acx_l_process_assocresp
+*/
+static int
+acx_l_process_assocresp(acx_device_t *adev, const wlan_fr_assocresp_t *req)
+{
+	const wlan_hdr_t *hdr;
+	int res = OK;
+
+	FN_ENTER;
+
+	hdr = req->hdr;
+
+	if ((ACX_MODE_2_STA == adev->mode)
+	 && mac_is_equal(adev->dev_addr, hdr->a1)) {
+		u16 st = ieee2host16(*(req->status));
+		if (WLAN_MGMT_STATUS_SUCCESS == st) {
+			adev->aid = ieee2host16(*(req->aid));
+			/* tell the card we are associated when
+			** we are out of interrupt context */
+			acx_schedule_task(adev, ACX_AFTER_IRQ_CMD_ASSOCIATE);
+		} else {
+
+			/* TODO: we shall delete peer from sta_list, and try
+			** other candidates... */
+
+			printk("%s: association FAILED: peer sent "
+				"response code %d (%s)\n",
+				adev->ndev->name, st, get_status_string(st));
+			res = NOT_OK;
+		}
+	}
+
+	FN_EXIT1(res);
+	return res;
+}
+
+
+/***********************************************************************
+** acx_l_process_reassocresp
+*/
+static int
+acx_l_process_reassocresp(acx_device_t *adev, const wlan_fr_reassocresp_t *req)
+{
+	const wlan_hdr_t *hdr;
+	int result = NOT_OK;
+	u16 st;
+
+	FN_ENTER;
+
+	hdr = req->hdr;
+
+	if (!mac_is_equal(adev->dev_addr, hdr->a1)) {
+		goto end;
+	}
+	st = ieee2host16(*(req->status));
+	if (st == WLAN_MGMT_STATUS_SUCCESS) {
+		acx_set_status(adev, ACX_STATUS_4_ASSOCIATED);
+		result = OK;
+	} else {
+		printk("%s: reassociation FAILED: peer sent "
+			"response code %d (%s)\n",
+			adev->ndev->name, st, get_status_string(st));
+	}
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_l_process_authen
+**
+** Called only in STA_SCAN or AP mode
+*/
+static int
+acx_l_process_authen(acx_device_t *adev, const wlan_fr_authen_t *req)
+{
+	const wlan_hdr_t *hdr;
+	client_t *clt;
+	wlan_ie_challenge_t *chal;
+	u16 alg, seq, status;
+	int ap, result;
+
+	FN_ENTER;
+
+	hdr = req->hdr;
+
+	if (acx_debug & L_ASSOC) {
+		acx_print_mac("AUTHEN adev->addr=", adev->dev_addr, " ");
+		acx_print_mac("a1=", hdr->a1, " ");
+		acx_print_mac("a2=", hdr->a2, " ");
+		acx_print_mac("a3=", hdr->a3, " ");
+		acx_print_mac("adev->bssid=", adev->bssid, "\n");
+	}
+
+	if (!mac_is_equal(adev->dev_addr, hdr->a1)
+	 || !mac_is_equal(adev->bssid, hdr->a3)) {
+		result = OK;
+		goto end;
+	}
+
+	alg = ieee2host16(*(req->auth_alg));
+	seq = ieee2host16(*(req->auth_seq));
+	status = ieee2host16(*(req->status));
+
+	ap = (adev->mode == ACX_MODE_3_AP);
+
+	if (adev->auth_alg <= 1) {
+		if (adev->auth_alg != alg) {
+			log(L_ASSOC, "auth algorithm mismatch: "
+				"our:%d peer:%d\n", adev->auth_alg, alg);
+			result = NOT_OK;
+			goto end;
+		}
+	}
+	log(L_ASSOC, "algorithm is ok\n");
+
+	if (ap) {
+		clt = acx_l_sta_list_get_or_add(adev, hdr->a2);
+		if (STA_LIST_ADD_CAN_FAIL && !clt) {
+			log(L_ASSOC, "could not allocate room for client\n");
+			result = NOT_OK;
+			goto end;
+		}
+	} else {
+		clt = adev->ap_client;
+		if (!mac_is_equal(clt->address, hdr->a2)) {
+			printk("%s: malformed auth frame from AP?!\n",
+					adev->ndev->name);
+			result = NOT_OK;
+			goto end;
+		}
+	}
+
+	/* now check which step in the authentication sequence we are
+	 * currently in, and act accordingly */
+	log(L_ASSOC, "acx_process_authen auth seq step %d\n", seq);
+	switch (seq) {
+	case 1:
+		if (!ap)
+			break;
+		acx_l_transmit_authen2(adev, req, clt);
+		break;
+	case 2:
+		if (ap)
+			break;
+		if (status == WLAN_MGMT_STATUS_SUCCESS) {
+			if (alg == WLAN_AUTH_ALG_OPENSYSTEM) {
+				acx_set_status(adev, ACX_STATUS_3_AUTHENTICATED);
+				acx_l_transmit_assoc_req(adev);
+			} else
+			if (alg == WLAN_AUTH_ALG_SHAREDKEY) {
+				acx_l_transmit_authen3(adev, req);
+			}
+		} else {
+			printk("%s: auth FAILED: peer sent "
+				"response code %d (%s), "
+				"still waiting for authentication\n",
+				adev->ndev->name,
+				status,	get_status_string(status));
+			acx_set_status(adev, ACX_STATUS_2_WAIT_AUTH);
+		}
+		break;
+	case 3:
+		if (!ap)
+			break;
+		if ((clt->auth_alg != WLAN_AUTH_ALG_SHAREDKEY)
+		 || (alg != WLAN_AUTH_ALG_SHAREDKEY)
+		 || (clt->auth_step != 2))
+			break;
+		chal = req->challenge;
+		if (!chal
+		 || memcmp(chal->challenge, clt->challenge_text, WLAN_CHALLENGE_LEN)
+		 || (chal->eid != WLAN_EID_CHALLENGE)
+		 || (chal->len != WLAN_CHALLENGE_LEN)
+		)
+			break;
+		acx_l_transmit_authen4(adev, req);
+		MAC_COPY(clt->address, hdr->a2);
+		clt->used = CLIENT_AUTHENTICATED_2;
+		clt->auth_step = 4;
+		clt->seq = ieee2host16(hdr->seq);
+		break;
+	case 4:
+		if (ap)
+			break;
+		/* ok, we're through: we're authenticated. Woohoo!! */
+		acx_set_status(adev, ACX_STATUS_3_AUTHENTICATED);
+		log(L_ASSOC, "Authenticated!\n");
+		/* now that we're authenticated, request association */
+		acx_l_transmit_assoc_req(adev);
+		break;
+	}
+	result = NOT_OK;
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_gen_challenge
+*/
+static inline void
+acx_gen_challenge(wlan_ie_challenge_t* d)
+{
+	FN_ENTER;
+	d->eid = WLAN_EID_CHALLENGE;
+	d->len = WLAN_CHALLENGE_LEN;
+	get_random_bytes(d->challenge, WLAN_CHALLENGE_LEN);
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acx_l_transmit_deauthen
+*/
+static int
+acx_l_transmit_deauthen(acx_device_t *adev, const u8 *addr, u16 reason)
+{
+	struct tx *tx;
+	struct wlan_hdr_mgmt *head;
+	struct deauthen_frame_body *body;
+
+	FN_ENTER;
+
+	tx = acx_l_alloc_tx(adev);
+	if (!tx)
+		goto bad;
+	head = acx_l_get_txbuf(adev, tx);
+	if (!head) {
+		acx_l_dealloc_tx(adev, tx);
+		goto bad;
+	}
+	body = (void*)(head + 1);
+
+	head->fc = (WF_FTYPE_MGMTi | WF_FSTYPE_DEAUTHENi);
+	head->dur = 0;
+	MAC_COPY(head->da, addr);
+	MAC_COPY(head->sa, adev->dev_addr);
+	MAC_COPY(head->bssid, adev->bssid);
+	head->seq = 0;
+
+	log(L_DEBUG|L_ASSOC|L_XFER,
+		"sending deauthen to "MACSTR" for %d\n",
+		MAC(addr), reason);
+
+	body->reason = host2ieee16(reason);
+
+	/* body is fixed size here, but beware of cutting-and-pasting this -
+	** do not use sizeof(*body) for variable sized mgmt packets! */
+	acx_l_tx_data(adev, tx, WLAN_HDR_A3_LEN + sizeof(*body));
+
+	FN_EXIT1(OK);
+	return OK;
+bad:
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+
+
+/***********************************************************************
+** acx_l_transmit_authen1
+*/
+static int
+acx_l_transmit_authen1(acx_device_t *adev)
+{
+	struct tx *tx;
+	struct wlan_hdr_mgmt *head;
+	struct auth_frame_body *body;
+
+	FN_ENTER;
+
+	log(L_ASSOC, "sending authentication1 request, "
+		"awaiting response\n");
+
+	tx = acx_l_alloc_tx(adev);
+	if (!tx)
+		goto bad;
+	head = acx_l_get_txbuf(adev, tx);
+	if (!head) {
+		acx_l_dealloc_tx(adev, tx);
+		goto bad;
+	}
+	body = (void*)(head + 1);
+
+	head->fc = WF_FSTYPE_AUTHENi;
+	head->dur = host2ieee16(0x8000);
+	MAC_COPY(head->da, adev->bssid);
+	MAC_COPY(head->sa, adev->dev_addr);
+	MAC_COPY(head->bssid, adev->bssid);
+	head->seq = 0;
+
+	body->auth_alg = host2ieee16(adev->auth_alg);
+	body->auth_seq = host2ieee16(1);
+	body->status = host2ieee16(0);
+
+	acx_l_tx_data(adev, tx, WLAN_HDR_A3_LEN + 2 + 2 + 2);
+
+	FN_EXIT1(OK);
+	return OK;
+bad:
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+
+
+/***********************************************************************
+** acx_l_transmit_authen2
+*/
+static int
+acx_l_transmit_authen2(acx_device_t *adev, const wlan_fr_authen_t *req,
+		      client_t *clt)
+{
+	struct tx *tx;
+	struct wlan_hdr_mgmt *head;
+	struct auth_frame_body *body;
+	unsigned int packet_len;
+
+	FN_ENTER;
+
+	if (!clt)
+		goto ok;
+
+	MAC_COPY(clt->address, req->hdr->a2);
+#ifdef UNUSED
+	clt->ps = ((WF_FC_PWRMGTi & req->hdr->fc) != 0);
+#endif
+	clt->auth_alg = ieee2host16(*(req->auth_alg));
+	clt->auth_step = 2;
+	clt->seq = ieee2host16(req->hdr->seq);
+
+	tx = acx_l_alloc_tx(adev);
+	if (!tx)
+		goto bad;
+	head = acx_l_get_txbuf(adev, tx);
+	if (!head) {
+		acx_l_dealloc_tx(adev, tx);
+		goto bad;
+	}
+	body = (void*)(head + 1);
+
+	head->fc = WF_FSTYPE_AUTHENi;
+	head->dur = req->hdr->dur;
+	MAC_COPY(head->da, req->hdr->a2);
+	MAC_COPY(head->sa, adev->dev_addr);
+	MAC_COPY(head->bssid, req->hdr->a3);
+	head->seq = req->hdr->seq;
+
+	/* already in IEEE format, no endianness conversion */
+	body->auth_alg = *(req->auth_alg);
+	body->auth_seq = host2ieee16(2);
+	body->status = host2ieee16(0);
+
+	packet_len = WLAN_HDR_A3_LEN + 2 + 2 + 2;
+	if (ieee2host16(*(req->auth_alg)) == WLAN_AUTH_ALG_OPENSYSTEM) {
+		clt->used = CLIENT_AUTHENTICATED_2;
+	} else {	/* shared key */
+		acx_gen_challenge(&body->challenge);
+		memcpy(&clt->challenge_text, body->challenge.challenge, WLAN_CHALLENGE_LEN);
+		packet_len += 2 + 2 + 2 + 1+1+WLAN_CHALLENGE_LEN;
+	}
+
+	acxlog_mac(L_ASSOC|L_XFER,
+		"transmit_auth2: BSSID=", head->bssid, "\n");
+
+	acx_l_tx_data(adev, tx, packet_len);
+ok:
+	FN_EXIT1(OK);
+	return OK;
+bad:
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+
+
+/***********************************************************************
+** acx_l_transmit_authen3
+*/
+static int
+acx_l_transmit_authen3(acx_device_t *adev, const wlan_fr_authen_t *req)
+{
+	struct tx *tx;
+	struct wlan_hdr_mgmt *head;
+	struct auth_frame_body *body;
+	unsigned int packet_len;
+
+	FN_ENTER;
+
+	tx = acx_l_alloc_tx(adev);
+	if (!tx)
+		goto ok;
+	head = acx_l_get_txbuf(adev, tx);
+	if (!head) {
+		acx_l_dealloc_tx(adev, tx);
+		goto ok;
+	}
+	body = (void*)(head + 1);
+
+	head->fc = WF_FC_ISWEPi + WF_FSTYPE_AUTHENi;
+	/* FIXME: is this needed?? authen4 does it...
+	head->dur = req->hdr->dur;
+	head->seq = req->hdr->seq;
+	*/
+	MAC_COPY(head->da, adev->bssid);
+	MAC_COPY(head->sa, adev->dev_addr);
+	MAC_COPY(head->bssid, adev->bssid);
+
+	/* already in IEEE format, no endianness conversion */
+	body->auth_alg = *(req->auth_alg);
+	body->auth_seq = host2ieee16(3);
+	body->status = host2ieee16(0);
+	memcpy(&body->challenge, req->challenge, req->challenge->len + 2);
+	packet_len = WLAN_HDR_A3_LEN + 8 + req->challenge->len;
+
+	log(L_ASSOC|L_XFER, "transmit_authen3!\n");
+
+	acx_l_tx_data(adev, tx, packet_len);
+ok:
+	FN_EXIT1(OK);
+	return OK;
+}
+
+
+/***********************************************************************
+** acx_l_transmit_authen4
+*/
+static int
+acx_l_transmit_authen4(acx_device_t *adev, const wlan_fr_authen_t *req)
+{
+	struct tx *tx;
+	struct wlan_hdr_mgmt *head;
+	struct auth_frame_body *body;
+
+	FN_ENTER;
+
+	tx = acx_l_alloc_tx(adev);
+	if (!tx)
+		goto ok;
+	head = acx_l_get_txbuf(adev, tx);
+	if (!head) {
+		acx_l_dealloc_tx(adev, tx);
+		goto ok;
+	}
+	body = (void*)(head + 1);
+
+	head->fc = WF_FSTYPE_AUTHENi; /* 0xb0 */
+	head->dur = req->hdr->dur;
+	MAC_COPY(head->da, req->hdr->a2);
+	MAC_COPY(head->sa, adev->dev_addr);
+	MAC_COPY(head->bssid, req->hdr->a3);
+	head->seq = req->hdr->seq;
+
+	/* already in IEEE format, no endianness conversion */
+	body->auth_alg = *(req->auth_alg);
+	body->auth_seq = host2ieee16(4);
+	body->status = host2ieee16(0);
+
+	acx_l_tx_data(adev, tx, WLAN_HDR_A3_LEN + 2 + 2 + 2);
+ok:
+	FN_EXIT1(OK);
+	return OK;
+}
+
+
+/***********************************************************************
+** acx_l_transmit_assoc_req
+**
+** adev->ap_client is a current candidate AP here
+*/
+static int
+acx_l_transmit_assoc_req(acx_device_t *adev)
+{
+	struct tx *tx;
+	struct wlan_hdr_mgmt *head;
+	u8 *body, *p, *prate;
+	unsigned int packet_len;
+	u16 cap;
+
+	FN_ENTER;
+
+	log(L_ASSOC, "sending association request, "
+			"awaiting response. NOT ASSOCIATED YET\n");
+	tx = acx_l_alloc_tx(adev);
+	if (!tx)
+		goto bad;
+	head = acx_l_get_txbuf(adev, tx);
+	if (!head) {
+		acx_l_dealloc_tx(adev, tx);
+		goto bad;
+	}
+	body = (void*)(head + 1);
+
+	head->fc = WF_FSTYPE_ASSOCREQi;
+	head->dur = host2ieee16(0x8000);
+	MAC_COPY(head->da, adev->bssid);
+	MAC_COPY(head->sa, adev->dev_addr);
+	MAC_COPY(head->bssid, adev->bssid);
+	head->seq = 0;
+
+	p = body;
+	/* now start filling the AssocReq frame body */
+
+	/* since this assoc request will most likely only get
+	 * sent in the STA to AP case (and not when Ad-Hoc IBSS),
+	 * the cap combination indicated here will thus be
+	 * WF_MGMT_CAP_ESSi *always* (no IBSS ever)
+	 * The specs are more than non-obvious on all that:
+	 *
+	 * 802.11 7.3.1.4 Capability Information field
+	** APs set the ESS subfield to 1 and the IBSS subfield to 0 within
+	** Beacon or Probe Response management frames. STAs within an IBSS
+	** set the ESS subfield to 0 and the IBSS subfield to 1 in transmitted
+	** Beacon or Probe Response management frames
+	**
+	** APs set the Privacy subfield to 1 within transmitted Beacon,
+	** Probe Response, Association Response, and Reassociation Response
+	** if WEP is required for all data type frames within the BSS.
+	** STAs within an IBSS set the Privacy subfield to 1 in Beacon
+	** or Probe Response management frames if WEP is required
+	** for all data type frames within the IBSS */
+
+	/* note that returning 0 will be refused by several APs...
+	 * (so this indicates that you're probably supposed to
+	 * "confirm" the ESS mode) */
+	cap = WF_MGMT_CAP_ESSi;
+
+	/* this one used to be a check on wep_restricted,
+	 * but more likely it's wep_enabled instead */
+	if (adev->wep_enabled)
+		SET_BIT(cap, WF_MGMT_CAP_PRIVACYi);
+
+	/* Probably we can just set these always, because our hw is
+	** capable of shortpre and PBCC --vda */
+	/* only ask for short preamble if the peer station supports it */
+	if (adev->ap_client->cap_info & WF_MGMT_CAP_SHORT)
+		SET_BIT(cap, WF_MGMT_CAP_SHORTi);
+	/* only ask for PBCC support if the peer station supports it */
+	if (adev->ap_client->cap_info & WF_MGMT_CAP_PBCC)
+		SET_BIT(cap, WF_MGMT_CAP_PBCCi);
+
+	/* IEs: 1. caps */
+	*(u16*)p = cap;	p += 2;
+	/* 2. listen interval */
+	*(u16*)p = host2ieee16(adev->listen_interval); p += 2;
+	/* 3. ESSID */
+	p = wlan_fill_ie_ssid(p,
+			strlen(adev->essid_for_assoc), adev->essid_for_assoc);
+	/* 4. supp rates */
+	prate = p;
+	p = wlan_fill_ie_rates(p,
+			adev->rate_supported_len, adev->rate_supported);
+	/* 5. ext supp rates */
+	p = wlan_fill_ie_rates_ext(p,
+			adev->rate_supported_len, adev->rate_supported);
+
+	if (acx_debug & L_DEBUG) {
+		printk("association: rates element\n");
+		acx_dump_bytes(prate, p - prate);
+	}
+
+	/* calculate lengths */
+	packet_len = WLAN_HDR_A3_LEN + (p - body);
+
+	log(L_ASSOC, "association: requesting caps 0x%04X, ESSID '%s'\n",
+		cap, adev->essid_for_assoc);
+
+	acx_l_tx_data(adev, tx, packet_len);
+	FN_EXIT1(OK);
+	return OK;
+bad:
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+
+
+/***********************************************************************
+** acx_l_transmit_disassoc
+**
+** FIXME: looks like incomplete implementation of a helper:
+** acx_l_transmit_disassoc(adev, clt) - kick this client (we're an AP)
+** acx_l_transmit_disassoc(adev, NULL) - leave BSSID (we're a STA)
+*/
+#ifdef BROKEN
+int
+acx_l_transmit_disassoc(acx_device_t *adev, client_t *clt)
+{
+	struct tx *tx;
+	struct wlan_hdr_mgmt *head;
+	struct disassoc_frame_body *body;
+
+	FN_ENTER;
+/*	if (clt != NULL) { */
+		tx = acx_l_alloc_tx(adev);
+		if (!tx)
+			goto bad;
+		head = acx_l_get_txbuf(adev, tx);
+		if (!head) {
+			acx_l_dealloc_tx(adev, tx);
+			goto bad;
+		}
+		body = (void*)(head + 1);
+
+/*		clt->used = CLIENT_AUTHENTICATED_2; - not (yet?) associated */
+
+		head->fc = WF_FSTYPE_DISASSOCi;
+		head->dur = 0;
+		/* huh? It muchly depends on whether we're STA or AP...
+		** sta->ap: da=bssid, sa=own, bssid=bssid
+		** ap->sta: da=sta, sa=bssid, bssid=bssid. FIXME! */
+		MAC_COPY(head->da, adev->bssid);
+		MAC_COPY(head->sa, adev->dev_addr);
+		MAC_COPY(head->bssid, adev->dev_addr);
+		head->seq = 0;
+
+		/* "Class 3 frame received from nonassociated station." */
+		body->reason = host2ieee16(7);
+
+		/* fixed size struct, ok to sizeof */
+		acx_l_tx_data(adev, tx, WLAN_HDR_A3_LEN + sizeof(*body));
+/*	} */
+	FN_EXIT1(OK);
+	return OK;
+bad:
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+#endif
+
+
+/***********************************************************************
+** acx_s_complete_scan
+**
+** Called either from after_interrupt_task() if:
+** 1) there was Scan_Complete IRQ, or
+** 2) scanning expired in timer()
+** We need to decide which ESS or IBSS to join.
+** Iterates thru adev->sta_list:
+**	if adev->ap is not bcast, will join only specified
+**	ESS or IBSS with this bssid
+**	checks peers' caps for ESS/IBSS bit
+**	checks peers' SSID, allows exact match or hidden SSID
+** If station to join is chosen:
+**	points adev->ap_client to the chosen struct client
+**	sets adev->essid_for_assoc for future assoc attempt
+** Auth/assoc is not yet performed
+** Returns OK if there is no need to restart scan
+*/
+int
+acx_s_complete_scan(acx_device_t *adev)
+{
+	struct client *bss;
+	unsigned long flags;
+	u16 needed_cap;
+	int i;
+	int idx_found = -1;
+	int result = OK;
+
+	FN_ENTER;
+
+	switch (adev->mode) {
+	case ACX_MODE_0_ADHOC:
+		needed_cap = WF_MGMT_CAP_IBSS; /* 2, we require Ad-Hoc */
+		break;
+	case ACX_MODE_2_STA:
+		needed_cap = WF_MGMT_CAP_ESS; /* 1, we require Managed */
+		break;
+	default:
+		printk("acx: driver bug: mode=%d in complete_scan()\n", adev->mode);
+		dump_stack();
+		goto end;
+	}
+
+	acx_lock(adev, flags);
+
+	/* TODO: sta_iterator hiding implementation would be nice here... */
+
+	for (i = 0; i < VEC_SIZE(adev->sta_list); i++) {
+		bss = &adev->sta_list[i];
+		if (!bss->used) continue;
+
+		log(L_ASSOC, "scan table: SSID='%s' CH=%d SIR=%d SNR=%d\n",
+			bss->essid, bss->channel, bss->sir, bss->snr);
+
+		if (!mac_is_bcast(adev->ap))
+			if (!mac_is_equal(bss->bssid, adev->ap))
+				continue; /* keep looking */
+
+		/* broken peer with no mode flags set? */
+		if (unlikely(!(bss->cap_info & (WF_MGMT_CAP_ESS | WF_MGMT_CAP_IBSS)))) {
+			printk("%s: strange peer "MACSTR" found with "
+				"neither ESS (AP) nor IBSS (Ad-Hoc) "
+				"capability - skipped\n",
+				adev->ndev->name, MAC(bss->address));
+			continue;
+		}
+		log(L_ASSOC, "peer_cap 0x%04X, needed_cap 0x%04X\n",
+		       bss->cap_info, needed_cap);
+
+		/* does peer station support what we need? */
+		if ((bss->cap_info & needed_cap) != needed_cap)
+			continue; /* keep looking */
+
+		/* strange peer with NO basic rates?! */
+		if (unlikely(!bss->rate_bas)) {
+			printk("%s: strange peer "MACSTR" with empty rate set "
+				"- skipped\n",
+				adev->ndev->name, MAC(bss->address));
+			continue;
+		}
+
+		/* do we support all basic rates of this peer? */
+		if ((bss->rate_bas & adev->rate_oper) != bss->rate_bas)	{
+/* we probably need to have all rates as operational rates,
+   even in case of an 11M-only configuration */
+#ifdef THIS_IS_TROUBLESOME
+			printk("%s: peer "MACSTR": incompatible basic rates "
+				"(AP requests 0x%04X, we have 0x%04X) "
+				"- skipped\n",
+				adev->ndev->name, MAC(bss->address),
+				bss->rate_bas, adev->rate_oper);
+			continue;
+#else
+			printk("%s: peer "MACSTR": incompatible basic rates "
+				"(AP requests 0x%04X, we have 0x%04X). "
+				"Considering anyway...\n",
+				adev->ndev->name, MAC(bss->address),
+				bss->rate_bas, adev->rate_oper);
+#endif
+		}
+
+		if ( !(adev->reg_dom_chanmask & (1<<(bss->channel-1))) ) {
+			printk("%s: warning: peer "MACSTR" is on channel %d "
+				"outside of channel range of current "
+				"regulatory domain - couldn't join "
+				"even if other settings match. "
+				"You might want to adapt your config\n",
+				adev->ndev->name, MAC(bss->address),
+				bss->channel);
+			continue; /* keep looking */
+		}
+
+		if (!adev->essid_active || !strcmp(bss->essid, adev->essid)) {
+			log(L_ASSOC,
+			       "found station with matching ESSID! ('%s' "
+			       "station, '%s' config)\n",
+			       bss->essid,
+			       (adev->essid_active) ? adev->essid : "[any]");
+			/* TODO: continue looking for peer with better SNR */
+			bss->used = CLIENT_JOIN_CANDIDATE;
+			idx_found = i;
+
+			/* stop searching if this station is
+			 * on the current channel, otherwise
+			 * keep looking for an even better match */
+			if (bss->channel == adev->channel)
+				break;
+		} else
+		if (!bss->essid[0]
+		 || ((' ' == bss->essid[0]) && !bss->essid[1])
+		) {
+			/* hmm, station with empty or single-space SSID:
+			 * using hidden SSID broadcast?
+			 */
+			/* This behaviour is broken: which AP from zillion
+			** of APs with hidden SSID you'd try?
+			** We should use Probe requests to get Probe responses
+			** and check for real SSID (are those never hidden?) */
+			bss->used = CLIENT_JOIN_CANDIDATE;
+			if (idx_found == -1)
+				idx_found = i;
+			log(L_ASSOC, "found station with empty or "
+				"single-space (hidden) SSID, considering "
+				"for assoc attempt\n");
+			/* ...and keep looking for better matches */
+		} else {
+			log(L_ASSOC, "ESSID doesn't match! ('%s' "
+				"station, '%s' config)\n",
+				bss->essid,
+				(adev->essid_active) ? adev->essid : "[any]");
+		}
+	}
+
+	/* TODO: iterate thru join candidates instead */
+	/* TODO: rescan if not associated within some timeout */
+	if (idx_found != -1) {
+		char *essid_src;
+		size_t essid_len;
+
+		bss = &adev->sta_list[idx_found];
+		adev->ap_client = bss;
+
+		if (bss->essid[0] == '\0') {
+			/* if the ESSID of the station we found is empty
+			 * (no broadcast), then use user-configured ESSID
+			 * instead */
+			essid_src = adev->essid;
+			essid_len = adev->essid_len;
+		} else {
+			essid_src = bss->essid;
+			essid_len = strlen(bss->essid);
+		}
+
+		acx_update_capabilities(adev);
+
+		memcpy(adev->essid_for_assoc, essid_src, essid_len);
+		adev->essid_for_assoc[essid_len] = '\0';
+		adev->channel = bss->channel;
+		MAC_COPY(adev->bssid, bss->bssid);
+
+		bss->rate_cfg = (bss->rate_cap & adev->rate_oper);
+		bss->rate_cur = 1 << lowest_bit(bss->rate_cfg);
+		bss->rate_100 = acx_rate111to100(bss->rate_cur);
+
+		acxlog_mac(L_ASSOC,
+			"matching station found: ", adev->bssid, ", joining\n");
+
+		/* TODO: do we need to switch to the peer's channel first? */
+
+		if (ACX_MODE_0_ADHOC == adev->mode) {
+			acx_set_status(adev, ACX_STATUS_4_ASSOCIATED);
+		} else {
+			acx_l_transmit_authen1(adev);
+			acx_set_status(adev, ACX_STATUS_2_WAIT_AUTH);
+		}
+	} else { /* idx_found == -1 */
+		/* uh oh, no station found in range */
+		if (ACX_MODE_0_ADHOC == adev->mode) {
+			printk("%s: no matching station found in range, "
+				"generating our own IBSS instead\n",
+				adev->ndev->name);
+			/* we do it the HostAP way: */
+			MAC_COPY(adev->bssid, adev->dev_addr);
+			adev->bssid[0] |= 0x02; /* 'local assigned addr' bit */
+			/* add IBSS bit to our caps... */
+			acx_update_capabilities(adev);
+			acx_set_status(adev, ACX_STATUS_4_ASSOCIATED);
+			/* In order to cmd_join be called below */
+			idx_found = 0;
+		} else {
+			/* we shall scan again, AP can be
+			** just temporarily powered off */
+			log(L_ASSOC,
+				"no matching station found in range yet\n");
+			acx_set_status(adev, ACX_STATUS_1_SCANNING);
+			result = NOT_OK;
+		}
+	}
+
+	acx_unlock(adev, flags);
+
+	if (idx_found != -1) {
+		if (ACX_MODE_0_ADHOC == adev->mode) {
+			/* need to update channel in beacon template */
+			SET_BIT(adev->set_mask, SET_TEMPLATES);
+			if (ACX_STATE_IFACE_UP & adev->dev_state_mask)
+				acx_s_update_card_settings(adev);
+		}
+		/* Inform firmware on our decision to start or join BSS */
+		acx_s_cmd_join_bssid(adev, adev->bssid);
+	}
+
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_s_read_fw
+**
+** Loads a firmware image
+**
+** Returns:
+**  0				unable to load file
+**  pointer to firmware		success
+*/
+firmware_image_t*
+acx_s_read_fw(struct device *dev, const char *file, u32 *size)
+{
+	firmware_image_t *res;
+	const struct firmware *fw_entry;
+
+	res = NULL;
+	log(L_INIT, "requesting firmware image '%s'\n", file);
+	if (!request_firmware(&fw_entry, file, dev)) {
+		*size = 8;
+		if (fw_entry->size >= 8)
+			*size = 8 + le32_to_cpu(*(u32 *)(fw_entry->data + 4));
+		if (fw_entry->size != *size) {
+			printk("acx: firmware size does not match "
+				"firmware header: %d != %d, "
+				"aborting fw upload\n",
+				(int) fw_entry->size, (int) *size);
+			goto release_ret;
+		}
+		res = vmalloc(*size);
+		if (!res) {
+			printk("acx: no memory for firmware "
+				"(%u bytes)\n", *size);
+			goto release_ret;
+		}
+		memcpy(res, fw_entry->data, fw_entry->size);
+release_ret:
+		release_firmware(fw_entry);
+		return res;
+	}
+	printk("acx: firmware image '%s' was not provided. "
+		"Check your hotplug scripts\n", file);
+
+	/* checksum will be verified in write_fw, so don't bother here */
+	return res;
+}
+
+
+/***********************************************************************
+** acx_s_set_wepkey
+*/
+static void
+acx100_s_set_wepkey(acx_device_t *adev)
+{
+	ie_dot11WEPDefaultKey_t dk;
+	int i;
+
+	for (i = 0; i < DOT11_MAX_DEFAULT_WEP_KEYS; i++) {
+		if (adev->wep_keys[i].size != 0) {
+			log(L_INIT, "setting WEP key: %d with "
+				"total size: %d\n", i, (int) adev->wep_keys[i].size);
+			dk.action = 1;
+			dk.keySize = adev->wep_keys[i].size;
+			dk.defaultKeyNum = i;
+			memcpy(dk.key, adev->wep_keys[i].key, dk.keySize);
+			acx_s_configure(adev, &dk, ACX100_IE_DOT11_WEP_DEFAULT_KEY_WRITE);
+		}
+	}
+}
+
+static void
+acx111_s_set_wepkey(acx_device_t *adev)
+{
+	acx111WEPDefaultKey_t dk;
+	int i;
+
+	for (i = 0; i < DOT11_MAX_DEFAULT_WEP_KEYS; i++) {
+		if (adev->wep_keys[i].size != 0) {
+			log(L_INIT, "setting WEP key: %d with "
+				"total size: %d\n", i, (int) adev->wep_keys[i].size);
+			memset(&dk, 0, sizeof(dk));
+			dk.action = cpu_to_le16(1); /* "add key"; yes, that's a 16bit value */
+			dk.keySize = adev->wep_keys[i].size;
+
+			/* are these two lines necessary? */
+			dk.type = 0;              /* default WEP key */
+			dk.index = 0;             /* ignored when setting default key */
+
+			dk.defaultKeyNum = i;
+			memcpy(dk.key, adev->wep_keys[i].key, dk.keySize);
+			acx_s_issue_cmd(adev, ACX1xx_CMD_WEP_MGMT, &dk, sizeof(dk));
+		}
+	}
+}
+
+static void
+acx_s_set_wepkey(acx_device_t *adev)
+{
+	if (IS_ACX111(adev))
+		acx111_s_set_wepkey(adev);
+	else
+		acx100_s_set_wepkey(adev);
+}
+
+
+/***********************************************************************
+** acx100_s_init_wep
+**
+** FIXME: this should probably be moved into the new card settings
+** management, but since we're also modifying the memory map layout here
+** due to the WEP key space we want, we should take care...
+*/
+static int
+acx100_s_init_wep(acx_device_t *adev)
+{
+	acx100_ie_wep_options_t options;
+	ie_dot11WEPDefaultKeyID_t dk;
+	acx_ie_memmap_t pt;
+	int res = NOT_OK;
+
+	FN_ENTER;
+
+	if (OK != acx_s_interrogate(adev, &pt, ACX1xx_IE_MEMORY_MAP)) {
+		goto fail;
+	}
+
+	log(L_DEBUG, "CodeEnd:%X\n", pt.CodeEnd);
+
+	pt.WEPCacheStart = cpu_to_le32(le32_to_cpu(pt.CodeEnd) + 0x4);
+	pt.WEPCacheEnd   = cpu_to_le32(le32_to_cpu(pt.CodeEnd) + 0x4);
+
+	if (OK != acx_s_configure(adev, &pt, ACX1xx_IE_MEMORY_MAP)) {
+		goto fail;
+	}
+
+	/* let's choose maximum setting: 4 default keys, plus 10 other keys: */
+	options.NumKeys = cpu_to_le16(DOT11_MAX_DEFAULT_WEP_KEYS + 10);
+	options.WEPOption = 0x00;
+
+	log(L_ASSOC, "%s: writing WEP options\n", __func__);
+	acx_s_configure(adev, &options, ACX100_IE_WEP_OPTIONS);
+
+	acx100_s_set_wepkey(adev);
+
+	if (adev->wep_keys[adev->wep_current_index].size != 0) {
+		log(L_ASSOC, "setting active default WEP key number: %d\n",
+				adev->wep_current_index);
+		dk.KeyID = adev->wep_current_index;
+		acx_s_configure(adev, &dk, ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET); /* 0x1010 */
+	}
+	/* FIXME!!! wep_key_struct is filled nowhere! But adev
+	 * is initialized to 0, and we don't REALLY need those keys either */
+/*		for (i = 0; i < 10; i++) {
+		if (adev->wep_key_struct[i].len != 0) {
+			MAC_COPY(wep_mgmt.MacAddr, adev->wep_key_struct[i].addr);
+			wep_mgmt.KeySize = cpu_to_le16(adev->wep_key_struct[i].len);
+			memcpy(&wep_mgmt.Key, adev->wep_key_struct[i].key, le16_to_cpu(wep_mgmt.KeySize));
+			wep_mgmt.Action = cpu_to_le16(1);
+			log(L_ASSOC, "writing WEP key %d (len %d)\n", i, le16_to_cpu(wep_mgmt.KeySize));
+			if (OK == acx_s_issue_cmd(adev, ACX1xx_CMD_WEP_MGMT, &wep_mgmt, sizeof(wep_mgmt))) {
+				adev->wep_key_struct[i].index = i;
+			}
+		}
+	}
+*/
+
+	/* now retrieve the updated WEPCacheEnd pointer... */
+	if (OK != acx_s_interrogate(adev, &pt, ACX1xx_IE_MEMORY_MAP)) {
+		printk("%s: ACX1xx_IE_MEMORY_MAP read #2 FAILED\n",
+				adev->ndev->name);
+		goto fail;
+	}
+	/* ...and tell it to start allocating templates at that location */
+	/* (no endianness conversion needed) */
+	pt.PacketTemplateStart = pt.WEPCacheEnd;
+
+	if (OK != acx_s_configure(adev, &pt, ACX1xx_IE_MEMORY_MAP)) {
+		printk("%s: ACX1xx_IE_MEMORY_MAP write #2 FAILED\n",
+				adev->ndev->name);
+		goto fail;
+	}
+	res = OK;
+
+fail:
+	FN_EXIT1(res);
+	return res;
+}
+
+
+static int
+acx_s_init_max_template_generic(acx_device_t *adev, unsigned int len, unsigned int cmd)
+{
+	int res;
+	union {
+		acx_template_nullframe_t null;
+		acx_template_beacon_t b;
+		acx_template_tim_t tim;
+		acx_template_probereq_t preq;
+		acx_template_proberesp_t presp;
+	} templ;
+
+	memset(&templ, 0, len);
+	templ.null.size = cpu_to_le16(len - 2);
+	res = acx_s_issue_cmd(adev, cmd, &templ, len);
+	return res;
+}
+
+static inline int
+acx_s_init_max_null_data_template(acx_device_t *adev)
+{
+	return acx_s_init_max_template_generic(
+		adev, sizeof(acx_template_nullframe_t), ACX1xx_CMD_CONFIG_NULL_DATA
+	);
+}
+
+static inline int
+acx_s_init_max_beacon_template(acx_device_t *adev)
+{
+	return acx_s_init_max_template_generic(
+		adev, sizeof(acx_template_beacon_t), ACX1xx_CMD_CONFIG_BEACON
+	);
+}
+
+static inline int
+acx_s_init_max_tim_template(acx_device_t *adev)
+{
+	return acx_s_init_max_template_generic(
+		adev, sizeof(acx_template_tim_t), ACX1xx_CMD_CONFIG_TIM
+	);
+}
+
+static inline int
+acx_s_init_max_probe_response_template(acx_device_t *adev)
+{
+	return acx_s_init_max_template_generic(
+		adev, sizeof(acx_template_proberesp_t), ACX1xx_CMD_CONFIG_PROBE_RESPONSE
+	);
+}
+
+static inline int
+acx_s_init_max_probe_request_template(acx_device_t *adev)
+{
+	return acx_s_init_max_template_generic(
+		adev, sizeof(acx_template_probereq_t), ACX1xx_CMD_CONFIG_PROBE_REQUEST
+	);
+}
+
+/***********************************************************************
+** acx_s_set_tim_template
+**
+** FIXME: In full blown driver we will regularly update partial virtual bitmap
+** by calling this function
+** (it can be done by irq handler on each DTIM irq or by timer...)
+
+[802.11 7.3.2.6] TIM information element:
+- 1 EID
+- 1 Length
+1 1 DTIM Count
+    indicates how many beacons (including this) appear before next DTIM
+    (0=this one is a DTIM)
+2 1 DTIM Period
+    number of beacons between successive DTIMs
+    (0=reserved, 1=all TIMs are DTIMs, 2=every other, etc)
+3 1 Bitmap Control
+    bit0: Traffic Indicator bit associated with Assoc ID 0 (Bcast AID?)
+    set to 1 in TIM elements with a value of 0 in the DTIM Count field
+    when one or more broadcast or multicast frames are buffered at the AP.
+    bit1-7: Bitmap Offset (logically Bitmap_Offset = Bitmap_Control & 0xFE).
+4 n Partial Virtual Bitmap
+    Visible part of traffic-indication bitmap.
+    Full bitmap consists of 2008 bits (251 octets) such that bit number N
+    (0<=N<=2007) in the bitmap corresponds to bit number (N mod 8)
+    in octet number N/8 where the low-order bit of each octet is bit0,
+    and the high order bit is bit7.
+    Each set bit in virtual bitmap corresponds to traffic buffered by AP
+    for a specific station (with corresponding AID?).
+    Partial Virtual Bitmap shows a part of bitmap which has non-zero.
+    Bitmap Offset is a number of skipped zero octets (see above).
+    'Missing' octets at the tail are also assumed to be zero.
+    Example: Length=6, Bitmap_Offset=2, Partial_Virtual_Bitmap=55 55 55
+    This means that traffic-indication bitmap is:
+    00000000 00000000 01010101 01010101 01010101 00000000 00000000...
+    (is bit0 in the map is always 0 and real value is in Bitmap Control bit0?)
+*/
+static int
+acx_s_set_tim_template(acx_device_t *adev)
+{
+/* For now, configure smallish test bitmap, all zero ("no pending data") */
+	enum { bitmap_size = 5 };
+
+	acx_template_tim_t t;
+	int result;
+
+	FN_ENTER;
+
+	memset(&t, 0, sizeof(t));
+	t.size = 5 + bitmap_size; /* eid+len+count+period+bmap_ctrl + bmap */
+	t.tim_eid = WLAN_EID_TIM;
+	t.len = 3 + bitmap_size; /* count+period+bmap_ctrl + bmap */
+	result = acx_s_issue_cmd(adev, ACX1xx_CMD_CONFIG_TIM, &t, sizeof(t));
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_fill_beacon_or_proberesp_template
+**
+** For frame format info, please see 802.11-1999.pdf item 7.2.3.9 and below!!
+**
+** NB: we use the fact that
+** struct acx_template_proberesp and struct acx_template_beacon are the same
+** (well, almost...)
+**
+** [802.11] Beacon's body consist of these IEs:
+** 1 Timestamp
+** 2 Beacon interval
+** 3 Capability information
+** 4 SSID
+** 5 Supported rates (up to 8 rates)
+** 6 FH Parameter Set (frequency-hopping PHYs only)
+** 7 DS Parameter Set (direct sequence PHYs only)
+** 8 CF Parameter Set (only if PCF is supported)
+** 9 IBSS Parameter Set (ad-hoc only)
+**
+** Beacon only:
+** 10 TIM (AP only) (see 802.11 7.3.2.6)
+** 11 Country Information (802.11d)
+** 12 FH Parameters (802.11d)
+** 13 FH Pattern Table (802.11d)
+** ... (?!! did not yet find relevant PDF file... --vda)
+** 19 ERP Information (extended rate PHYs)
+** 20 Extended Supported Rates (if more than 8 rates)
+**
+** Proberesp only:
+** 10 Country information (802.11d)
+** 11 FH Parameters (802.11d)
+** 12 FH Pattern Table (802.11d)
+** 13-n Requested information elements (802.11d)
+** ????
+** 18 ERP Information (extended rate PHYs)
+** 19 Extended Supported Rates (if more than 8 rates)
+*/
+static int
+acx_fill_beacon_or_proberesp_template(acx_device_t *adev,
+					struct acx_template_beacon *templ,
+					u16 fc /* in host order! */)
+{
+	int len;
+	u8 *p;
+
+	FN_ENTER;
+
+	memset(templ, 0, sizeof(*templ));
+	MAC_BCAST(templ->da);
+	MAC_COPY(templ->sa, adev->dev_addr);
+	MAC_COPY(templ->bssid, adev->bssid);
+
+	templ->beacon_interval = cpu_to_le16(adev->beacon_interval);
+	acx_update_capabilities(adev);
+	templ->cap = cpu_to_le16(adev->capabilities);
+
+	p = templ->variable;
+	p = wlan_fill_ie_ssid(p, adev->essid_len, adev->essid);
+	p = wlan_fill_ie_rates(p, adev->rate_supported_len, adev->rate_supported);
+	p = wlan_fill_ie_ds_parms(p, adev->channel);
+	/* NB: should go AFTER tim, but acx seem to keep tim last always */
+	p = wlan_fill_ie_rates_ext(p, adev->rate_supported_len, adev->rate_supported);
+
+	switch (adev->mode) {
+	case ACX_MODE_0_ADHOC:
+		/* ATIM window */
+		p = wlan_fill_ie_ibss_parms(p, 0); break;
+	case ACX_MODE_3_AP:
+		/* TIM IE is set up as separate template */
+		break;
+	}
+
+	len = p - (u8*)templ;
+	templ->fc = cpu_to_le16(WF_FTYPE_MGMT | fc);
+	/* - 2: do not count 'u16 size' field */
+	templ->size = cpu_to_le16(len - 2);
+
+	FN_EXIT1(len);
+	return len;
+}
+
+
+#if POWER_SAVE_80211
+/***********************************************************************
+** acx_s_set_null_data_template
+*/
+static int
+acx_s_set_null_data_template(acx_device_t *adev)
+{
+	struct acx_template_nullframe b;
+	int result;
+
+	FN_ENTER;
+
+	/* memset(&b, 0, sizeof(b)); not needed, setting all members */
+
+	b.size = cpu_to_le16(sizeof(b) - 2);
+	b.hdr.fc = WF_FTYPE_MGMTi | WF_FSTYPE_NULLi;
+	b.hdr.dur = 0;
+	MAC_BCAST(b.hdr.a1);
+	MAC_COPY(b.hdr.a2, adev->dev_addr);
+	MAC_COPY(b.hdr.a3, adev->bssid);
+	b.hdr.seq = 0;
+
+	result = acx_s_issue_cmd(adev, ACX1xx_CMD_CONFIG_NULL_DATA, &b, sizeof(b));
+
+	FN_EXIT1(result);
+	return result;
+}
+#endif
+
+
+/***********************************************************************
+** acx_s_set_beacon_template
+*/
+static int
+acx_s_set_beacon_template(acx_device_t *adev)
+{
+	struct acx_template_beacon bcn;
+	int len, result;
+
+	FN_ENTER;
+
+	len = acx_fill_beacon_or_proberesp_template(adev, &bcn, WF_FSTYPE_BEACON);
+	result = acx_s_issue_cmd(adev, ACX1xx_CMD_CONFIG_BEACON, &bcn, len);
+
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_s_set_probe_response_template
+*/
+static int
+acx_s_set_probe_response_template(acx_device_t *adev)
+{
+	struct acx_template_proberesp pr;
+	int len, result;
+
+	FN_ENTER;
+
+	len = acx_fill_beacon_or_proberesp_template(adev, &pr, WF_FSTYPE_PROBERESP);
+	result = acx_s_issue_cmd(adev, ACX1xx_CMD_CONFIG_PROBE_RESPONSE, &pr, len);
+
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_s_init_packet_templates()
+**
+** NOTE: order is very important here, to have a correct memory layout!
+** init templates: max Probe Request (station mode), max NULL data,
+** max Beacon, max TIM, max Probe Response.
+*/
+static int
+acx_s_init_packet_templates(acx_device_t *adev)
+{
+	acx_ie_memmap_t mm; /* ACX100 only */
+	int result = NOT_OK;
+
+	FN_ENTER;
+
+	log(L_DEBUG|L_INIT, "initializing max packet templates\n");
+
+	if (OK != acx_s_init_max_probe_request_template(adev))
+		goto failed;
+
+	if (OK != acx_s_init_max_null_data_template(adev))
+		goto failed;
+
+	if (OK != acx_s_init_max_beacon_template(adev))
+		goto failed;
+
+	if (OK != acx_s_init_max_tim_template(adev))
+		goto failed;
+
+	if (OK != acx_s_init_max_probe_response_template(adev))
+		goto failed;
+
+	if (IS_ACX111(adev)) {
+		/* ACX111 doesn't need the memory map magic below,
+		 * and the other templates will be set later (acx_start) */
+		result = OK;
+		goto success;
+	}
+
+	/* ACX100 will have its TIM template set,
+	 * and we also need to update the memory map */
+
+	if (OK != acx_s_set_tim_template(adev))
+		goto failed_acx100;
+
+	log(L_DEBUG, "sizeof(memmap)=%d bytes\n", (int)sizeof(mm));
+
+	if (OK != acx_s_interrogate(adev, &mm, ACX1xx_IE_MEMORY_MAP))
+		goto failed_acx100;
+
+	mm.QueueStart = cpu_to_le32(le32_to_cpu(mm.PacketTemplateEnd) + 4);
+	if (OK != acx_s_configure(adev, &mm, ACX1xx_IE_MEMORY_MAP))
+		goto failed_acx100;
+
+	result = OK;
+	goto success;
+
+failed_acx100:
+	log(L_DEBUG|L_INIT,
+		/* "cb=0x%X\n" */
+		"ACXMemoryMap:\n"
+		".CodeStart=0x%X\n"
+		".CodeEnd=0x%X\n"
+		".WEPCacheStart=0x%X\n"
+		".WEPCacheEnd=0x%X\n"
+		".PacketTemplateStart=0x%X\n"
+		".PacketTemplateEnd=0x%X\n",
+		/* len, */
+		le32_to_cpu(mm.CodeStart),
+		le32_to_cpu(mm.CodeEnd),
+		le32_to_cpu(mm.WEPCacheStart),
+		le32_to_cpu(mm.WEPCacheEnd),
+		le32_to_cpu(mm.PacketTemplateStart),
+		le32_to_cpu(mm.PacketTemplateEnd));
+
+failed:
+	printk("%s: %s() FAILED\n", adev->ndev->name, __func__);
+
+success:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+*/
+static int
+acx_s_set_probe_request_template(acx_device_t *adev)
+{
+	struct acx_template_probereq probereq;
+	char *p;
+	int res;
+	int frame_len;
+
+	FN_ENTER;
+
+	memset(&probereq, 0, sizeof(probereq));
+
+	probereq.fc = WF_FTYPE_MGMTi | WF_FSTYPE_PROBEREQi;
+	MAC_BCAST(probereq.da);
+	MAC_COPY(probereq.sa, adev->dev_addr);
+	MAC_BCAST(probereq.bssid);
+
+	p = probereq.variable;
+	p = wlan_fill_ie_ssid(p, adev->essid_len, adev->essid);
+	p = wlan_fill_ie_rates(p, adev->rate_supported_len, adev->rate_supported);
+	p = wlan_fill_ie_rates_ext(p, adev->rate_supported_len, adev->rate_supported);
+	frame_len = p - (char*)&probereq;
+	probereq.size = cpu_to_le16(frame_len - 2);
+
+	res = acx_s_issue_cmd(adev, ACX1xx_CMD_CONFIG_PROBE_REQUEST, &probereq, frame_len);
+	FN_EXIT0;
+	return res;
+}
+
+
+/***********************************************************************
+** acx_s_init_mac
+*/
+int
+acx_s_init_mac(acx_device_t *adev)
+{
+	int result = NOT_OK;
+
+	FN_ENTER;
+
+	if (IS_ACX111(adev)) {
+		adev->ie_len = acx111_ie_len;
+		adev->ie_len_dot11 = acx111_ie_len_dot11;
+	} else {
+		adev->ie_len = acx100_ie_len;
+		adev->ie_len_dot11 = acx100_ie_len_dot11;
+	}
+
+	if (IS_PCI(adev)) {
+		adev->memblocksize = 256; /* 256 is default */
+		/* try to load radio for both ACX100 and ACX111, since both
+		 * chips have at least some firmware versions making use of an
+		 * external radio module */
+		acxpci_s_upload_radio(adev);
+	} else {
+		adev->memblocksize = 128;
+	}
+
+	if (IS_ACX111(adev)) {
+		/* for ACX111, the order is different from ACX100
+		   1. init packet templates
+		   2. create station context and create dma regions
+		   3. init wep default keys
+		*/
+		if (OK != acx_s_init_packet_templates(adev))
+			goto fail;
+		if (OK != acx111_s_create_dma_regions(adev)) {
+			printk("%s: acx111_create_dma_regions FAILED\n",
+						adev->ndev->name);
+			goto fail;
+		}
+	} else {
+		if (OK != acx100_s_init_wep(adev))
+			goto fail;
+		if (OK != acx_s_init_packet_templates(adev))
+			goto fail;
+		if (OK != acx100_s_create_dma_regions(adev)) {
+			printk("%s: acx100_create_dma_regions FAILED\n",
+						adev->ndev->name);
+			goto fail;
+		}
+	}
+
+	MAC_COPY(adev->ndev->dev_addr, adev->dev_addr);
+	result = OK;
+
+fail:
+	if (result)
+		printk("acx: init_mac() FAILED\n");
+	FN_EXIT1(result);
+	return result;
+}
+
+
+void
+acx_s_set_sane_reg_domain(acx_device_t *adev, int do_set)
+{
+	unsigned mask;
+
+	unsigned int i;
+
+	for (i = 0; i < sizeof(acx_reg_domain_ids); i++)
+		if (acx_reg_domain_ids[i] == adev->reg_dom_id)
+			break;
+
+	if (sizeof(acx_reg_domain_ids) == i) {
+		log(L_INIT, "Invalid or unsupported regulatory domain"
+			       " 0x%02X specified, falling back to FCC (USA)!"
+			       " Please report if this sounds fishy!\n",
+				adev->reg_dom_id);
+		i = 0;
+		adev->reg_dom_id = acx_reg_domain_ids[i];
+
+		/* since there was a mismatch, we need to force updating */
+		do_set = 1;
+	}
+
+	if (do_set) {
+		acx_ie_generic_t dom;
+		dom.m.bytes[0] = adev->reg_dom_id;
+		acx_s_configure(adev, &dom, ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN);
+	}
+
+	adev->reg_dom_chanmask = reg_domain_channel_masks[i];
+
+	mask = (1 << (adev->channel - 1));
+	if (!(adev->reg_dom_chanmask & mask)) {
+	/* hmm, need to adjust our channel to reside within domain */
+		mask = 1;
+		for (i = 1; i <= 14; i++) {
+			if (adev->reg_dom_chanmask & mask) {
+				printk("%s: adjusting selected channel from %d "
+					"to %d due to new regulatory domain\n",
+					adev->ndev->name, adev->channel, i);
+				adev->channel = i;
+				break;
+			}
+			mask <<= 1;
+		}
+	}
+}
+
+
+#if POWER_SAVE_80211
+static void
+acx_s_update_80211_powersave_mode(acx_device_t *adev)
+{
+	/* merge both structs in a union to be able to have common code */
+	union {
+		acx111_ie_powersave_t acx111;
+		acx100_ie_powersave_t acx100;
+	} pm;
+
+	/* change 802.11 power save mode settings */
+	log(L_INIT, "updating 802.11 power save mode settings: "
+		"wakeup_cfg 0x%02X, listen interval %u, "
+		"options 0x%02X, hangover period %u, "
+		"enhanced_ps_transition_time %u\n",
+		adev->ps_wakeup_cfg, adev->ps_listen_interval,
+		adev->ps_options, adev->ps_hangover_period,
+		adev->ps_enhanced_transition_time);
+	acx_s_interrogate(adev, &pm, ACX1xx_IE_POWER_MGMT);
+	log(L_INIT, "Previous PS mode settings: wakeup_cfg 0x%02X, "
+		"listen interval %u, options 0x%02X, "
+		"hangover period %u, "
+		"enhanced_ps_transition_time %u, beacon_rx_time %u\n",
+		pm.acx111.wakeup_cfg,
+		pm.acx111.listen_interval,
+		pm.acx111.options,
+		pm.acx111.hangover_period,
+		IS_ACX111(adev) ?
+			pm.acx111.enhanced_ps_transition_time
+		      : pm.acx100.enhanced_ps_transition_time,
+		IS_ACX111(adev) ?
+			pm.acx111.beacon_rx_time
+		      : (u32)-1
+		);
+	pm.acx111.wakeup_cfg = adev->ps_wakeup_cfg;
+	pm.acx111.listen_interval = adev->ps_listen_interval;
+	pm.acx111.options = adev->ps_options;
+	pm.acx111.hangover_period = adev->ps_hangover_period;
+	if (IS_ACX111(adev)) {
+		pm.acx111.beacon_rx_time = cpu_to_le32(adev->ps_beacon_rx_time);
+		pm.acx111.enhanced_ps_transition_time = cpu_to_le32(adev->ps_enhanced_transition_time);
+	} else {
+		pm.acx100.enhanced_ps_transition_time = cpu_to_le16(adev->ps_enhanced_transition_time);
+	}
+	acx_s_configure(adev, &pm, ACX1xx_IE_POWER_MGMT);
+	acx_s_interrogate(adev, &pm, ACX1xx_IE_POWER_MGMT);
+	log(L_INIT, "wakeup_cfg: 0x%02X\n", pm.acx111.wakeup_cfg);
+	acx_s_msleep(40);
+	acx_s_interrogate(adev, &pm, ACX1xx_IE_POWER_MGMT);
+	log(L_INIT, "wakeup_cfg: 0x%02X\n", pm.acx111.wakeup_cfg);
+	log(L_INIT, "power save mode change %s\n",
+		(pm.acx111.wakeup_cfg & PS_CFG_PENDING) ? "FAILED" : "was successful");
+	/* FIXME: maybe verify via PS_CFG_PENDING bit here
+	 * that power save mode change was successful. */
+	/* FIXME: we shouldn't trigger a scan immediately after
+	 * fiddling with power save mode (since the firmware is sending
+	 * a NULL frame then). */
+}
+#endif
+
+
+/***********************************************************************
+** acx_s_update_card_settings
+**
+** Applies accumulated changes in various adev->xxxx members
+** Called by ioctl commit handler, acx_start, acx_set_defaults,
+** acx_s_after_interrupt_task (if IRQ_CMD_UPDATE_CARD_CFG),
+*/
+static void
+acx111_s_sens_radio_16_17(acx_device_t *adev)
+{
+	u32 feature1, feature2;
+
+	if ((adev->sensitivity < 1) || (adev->sensitivity > 3)) {
+		printk("%s: invalid sensitivity setting (1..3), "
+			"setting to 1\n", adev->ndev->name);
+		adev->sensitivity = 1;
+	}
+	acx111_s_get_feature_config(adev, &feature1, &feature2);
+	CLEAR_BIT(feature1, FEATURE1_LOW_RX|FEATURE1_EXTRA_LOW_RX);
+	if (adev->sensitivity > 1)
+		SET_BIT(feature1, FEATURE1_LOW_RX);
+	if (adev->sensitivity > 2)
+		SET_BIT(feature1, FEATURE1_EXTRA_LOW_RX);
+	acx111_s_feature_set(adev, feature1, feature2);
+}
+
+
+void
+acx_s_update_card_settings(acx_device_t *adev)
+{
+	unsigned long flags;
+	unsigned int start_scan = 0;
+	int i;
+
+	FN_ENTER;
+
+	log(L_INIT, "get_mask 0x%08X, set_mask 0x%08X\n",
+			adev->get_mask, adev->set_mask);
+
+	/* Track dependencies betweed various settings */
+
+	if (adev->set_mask & (GETSET_MODE|GETSET_RESCAN|GETSET_WEP)) {
+		log(L_INIT, "important setting has been changed. "
+			"Need to update packet templates, too\n");
+		SET_BIT(adev->set_mask, SET_TEMPLATES);
+	}
+	if (adev->set_mask & GETSET_CHANNEL) {
+		/* This will actually tune RX/TX to the channel */
+		SET_BIT(adev->set_mask, GETSET_RX|GETSET_TX);
+		switch (adev->mode) {
+		case ACX_MODE_0_ADHOC:
+		case ACX_MODE_3_AP:
+			/* Beacons contain channel# - update them */
+			SET_BIT(adev->set_mask, SET_TEMPLATES);
+		}
+		switch (adev->mode) {
+		case ACX_MODE_0_ADHOC:
+		case ACX_MODE_2_STA:
+			start_scan = 1;
+		}
+	}
+
+	/* Apply settings */
+
+#ifdef WHY_SHOULD_WE_BOTHER /* imagine we were just powered off */
+	/* send a disassoc request in case it's required */
+	if (adev->set_mask & (GETSET_MODE|GETSET_RESCAN|GETSET_CHANNEL|GETSET_WEP)) {
+		if (ACX_MODE_2_STA == adev->mode) {
+			if (ACX_STATUS_4_ASSOCIATED == adev->status) {
+				log(L_ASSOC, "we were ASSOCIATED - "
+					"sending disassoc request\n");
+				acx_lock(adev, flags);
+				acx_l_transmit_disassoc(adev, NULL);
+				/* FIXME: deauth? */
+				acx_unlock(adev, flags);
+			}
+			/* need to reset some other stuff as well */
+			log(L_DEBUG, "resetting bssid\n");
+			MAC_ZERO(adev->bssid);
+			SET_BIT(adev->set_mask, SET_TEMPLATES|SET_STA_LIST);
+			start_scan = 1;
+		}
+	}
+#endif
+
+	if (adev->get_mask & GETSET_STATION_ID) {
+		u8 stationID[4 + ACX1xx_IE_DOT11_STATION_ID_LEN];
+		const u8 *paddr;
+
+		acx_s_interrogate(adev, &stationID, ACX1xx_IE_DOT11_STATION_ID);
+		paddr = &stationID[4];
+		for (i = 0; i < ETH_ALEN; i++) {
+			/* we copy the MAC address (reversed in
+			 * the card) to the netdevice's MAC
+			 * address, and on ifup it will be
+			 * copied into iwadev->dev_addr */
+			adev->ndev->dev_addr[ETH_ALEN - 1 - i] = paddr[i];
+		}
+		CLEAR_BIT(adev->get_mask, GETSET_STATION_ID);
+	}
+
+	if (adev->get_mask & GETSET_SENSITIVITY) {
+		if ((RADIO_RFMD_11 == adev->radio_type)
+		|| (RADIO_MAXIM_0D == adev->radio_type)
+		|| (RADIO_RALINK_15 == adev->radio_type)) {
+			acx_s_read_phy_reg(adev, 0x30, &adev->sensitivity);
+		} else {
+			log(L_INIT, "don't know how to get sensitivity "
+				"for radio type 0x%02X\n", adev->radio_type);
+			adev->sensitivity = 0;
+		}
+		log(L_INIT, "got sensitivity value %u\n", adev->sensitivity);
+
+		CLEAR_BIT(adev->get_mask, GETSET_SENSITIVITY);
+	}
+
+	if (adev->get_mask & GETSET_ANTENNA) {
+		u8 antenna[4 + ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN];
+
+		memset(antenna, 0, sizeof(antenna));
+		acx_s_interrogate(adev, antenna, ACX1xx_IE_DOT11_CURRENT_ANTENNA);
+		adev->antenna = antenna[4];
+		log(L_INIT, "got antenna value 0x%02X\n", adev->antenna);
+		CLEAR_BIT(adev->get_mask, GETSET_ANTENNA);
+	}
+
+	if (adev->get_mask & GETSET_ED_THRESH) {
+		if (IS_ACX100(adev))	{
+			u8 ed_threshold[4 + ACX100_IE_DOT11_ED_THRESHOLD_LEN];
+
+			memset(ed_threshold, 0, sizeof(ed_threshold));
+			acx_s_interrogate(adev, ed_threshold, ACX100_IE_DOT11_ED_THRESHOLD);
+			adev->ed_threshold = ed_threshold[4];
+		} else {
+			log(L_INIT, "acx111 doesn't support ED\n");
+			adev->ed_threshold = 0;
+		}
+		log(L_INIT, "got Energy Detect (ED) threshold %u\n", adev->ed_threshold);
+		CLEAR_BIT(adev->get_mask, GETSET_ED_THRESH);
+	}
+
+	if (adev->get_mask & GETSET_CCA) {
+		if (IS_ACX100(adev))	{
+			u8 cca[4 + ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN];
+
+			memset(cca, 0, sizeof(adev->cca));
+			acx_s_interrogate(adev, cca, ACX1xx_IE_DOT11_CURRENT_CCA_MODE);
+			adev->cca = cca[4];
+		} else {
+			log(L_INIT, "acx111 doesn't support CCA\n");
+			adev->cca = 0;
+		}
+		log(L_INIT, "got Channel Clear Assessment (CCA) value %u\n", adev->cca);
+		CLEAR_BIT(adev->get_mask, GETSET_CCA);
+	}
+
+	if (adev->get_mask & GETSET_REG_DOMAIN) {
+		acx_ie_generic_t dom;
+
+		acx_s_interrogate(adev, &dom, ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN);
+		adev->reg_dom_id = dom.m.bytes[0];
+		acx_s_set_sane_reg_domain(adev, 0);
+		log(L_INIT, "got regulatory domain 0x%02X\n", adev->reg_dom_id);
+		CLEAR_BIT(adev->get_mask, GETSET_REG_DOMAIN);
+	}
+
+	if (adev->set_mask & GETSET_STATION_ID) {
+		u8 stationID[4 + ACX1xx_IE_DOT11_STATION_ID_LEN];
+		u8 *paddr;
+
+		paddr = &stationID[4];
+		for (i = 0; i < ETH_ALEN; i++) {
+			/* copy the MAC address we obtained when we noticed
+			 * that the ethernet iface's MAC changed
+			 * to the card (reversed in
+			 * the card!) */
+			paddr[i] = adev->dev_addr[ETH_ALEN - 1 - i];
+		}
+		acx_s_configure(adev, &stationID, ACX1xx_IE_DOT11_STATION_ID);
+		CLEAR_BIT(adev->set_mask, GETSET_STATION_ID);
+	}
+
+	if (adev->set_mask & SET_TEMPLATES) {
+		log(L_INIT, "updating packet templates\n");
+		switch (adev->mode) {
+		case ACX_MODE_2_STA:
+			acx_s_set_probe_request_template(adev);
+#if POWER_SAVE_80211
+			acx_s_set_null_data_template(adev);
+#endif
+			break;
+		case ACX_MODE_0_ADHOC:
+			acx_s_set_probe_request_template(adev);
+#if POWER_SAVE_80211
+			/* maybe power save functionality is somehow possible
+			 * for Ad-Hoc mode, too... FIXME: verify it somehow? firmware debug fields? */
+			acx_s_set_null_data_template(adev);
+#endif
+			/* fall through */
+		case ACX_MODE_3_AP:
+			acx_s_set_beacon_template(adev);
+			acx_s_set_tim_template(adev);
+			/* BTW acx111 firmware would not send probe responses
+			** if probe request does not have all basic rates flagged
+			** by 0x80! Thus firmware does not conform to 802.11,
+			** it should ignore 0x80 bit in ratevector from STA.
+			** We can 'fix' it by not using this template and
+			** sending probe responses by hand. TODO --vda */
+			acx_s_set_probe_response_template(adev);
+		}
+		/* Needed if generated frames are to be emitted at different tx rate now */
+		log(L_IRQ, "redoing cmd_join_bssid() after template cfg\n");
+		acx_s_cmd_join_bssid(adev, adev->bssid);
+		CLEAR_BIT(adev->set_mask, SET_TEMPLATES);
+	}
+	if (adev->set_mask & SET_STA_LIST) {
+		acx_lock(adev, flags);
+		acx_l_sta_list_init(adev);
+		CLEAR_BIT(adev->set_mask, SET_STA_LIST);
+		acx_unlock(adev, flags);
+	}
+	if (adev->set_mask & SET_RATE_FALLBACK) {
+		u8 rate[4 + ACX1xx_IE_RATE_FALLBACK_LEN];
+
+		/* configure to not do fallbacks when not in auto rate mode */
+		rate[4] = (adev->rate_auto) ? /* adev->txrate_fallback_retries */ 1 : 0;
+		log(L_INIT, "updating Tx fallback to %u retries\n", rate[4]);
+		acx_s_configure(adev, &rate, ACX1xx_IE_RATE_FALLBACK);
+		CLEAR_BIT(adev->set_mask, SET_RATE_FALLBACK);
+	}
+	if (adev->set_mask & GETSET_TXPOWER) {
+		log(L_INIT, "updating transmit power: %u dBm\n",
+					adev->tx_level_dbm);
+		acx_s_set_tx_level(adev, adev->tx_level_dbm);
+		CLEAR_BIT(adev->set_mask, GETSET_TXPOWER);
+	}
+
+	if (adev->set_mask & GETSET_SENSITIVITY) {
+		log(L_INIT, "updating sensitivity value: %u\n",
+					adev->sensitivity);
+		switch (adev->radio_type) {
+		case RADIO_RFMD_11:
+		case RADIO_MAXIM_0D:
+		case RADIO_RALINK_15:
+			acx_s_write_phy_reg(adev, 0x30, adev->sensitivity);
+			break;
+		case RADIO_RADIA_16:
+		case RADIO_UNKNOWN_17:
+			acx111_s_sens_radio_16_17(adev);
+			break;
+		default:
+			log(L_INIT, "don't know how to modify sensitivity "
+				"for radio type 0x%02X\n", adev->radio_type);
+		}
+		CLEAR_BIT(adev->set_mask, GETSET_SENSITIVITY);
+	}
+
+	if (adev->set_mask & GETSET_ANTENNA) {
+		/* antenna */
+		u8 antenna[4 + ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN];
+
+		memset(antenna, 0, sizeof(antenna));
+		antenna[4] = adev->antenna;
+		log(L_INIT, "updating antenna value: 0x%02X\n",
+					adev->antenna);
+		acx_s_configure(adev, &antenna, ACX1xx_IE_DOT11_CURRENT_ANTENNA);
+		CLEAR_BIT(adev->set_mask, GETSET_ANTENNA);
+	}
+
+	if (adev->set_mask & GETSET_ED_THRESH) {
+		/* ed_threshold */
+		log(L_INIT, "updating Energy Detect (ED) threshold: %u\n",
+					adev->ed_threshold);
+		if (IS_ACX100(adev)) {
+			u8 ed_threshold[4 + ACX100_IE_DOT11_ED_THRESHOLD_LEN];
+
+			memset(ed_threshold, 0, sizeof(ed_threshold));
+			ed_threshold[4] = adev->ed_threshold;
+			acx_s_configure(adev, &ed_threshold, ACX100_IE_DOT11_ED_THRESHOLD);
+		}
+		else
+			log(L_INIT, "acx111 doesn't support ED!\n");
+		CLEAR_BIT(adev->set_mask, GETSET_ED_THRESH);
+	}
+
+	if (adev->set_mask & GETSET_CCA) {
+		/* CCA value */
+		log(L_INIT, "updating Channel Clear Assessment "
+				"(CCA) value: 0x%02X\n", adev->cca);
+		if (IS_ACX100(adev))	{
+			u8 cca[4 + ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN];
+
+			memset(cca, 0, sizeof(cca));
+			cca[4] = adev->cca;
+			acx_s_configure(adev, &cca, ACX1xx_IE_DOT11_CURRENT_CCA_MODE);
+		}
+		else
+			log(L_INIT, "acx111 doesn't support CCA!\n");
+		CLEAR_BIT(adev->set_mask, GETSET_CCA);
+	}
+
+	if (adev->set_mask & GETSET_LED_POWER) {
+		/* Enable Tx */
+		log(L_INIT, "updating power LED status: %u\n", adev->led_power);
+
+		acx_lock(adev, flags);
+		if (IS_PCI(adev))
+			acxpci_l_power_led(adev, adev->led_power);
+		CLEAR_BIT(adev->set_mask, GETSET_LED_POWER);
+		acx_unlock(adev, flags);
+	}
+
+	if (adev->set_mask & GETSET_POWER_80211) {
+#if POWER_SAVE_80211
+		acx_s_update_80211_powersave_mode(adev);
+#endif
+		CLEAR_BIT(adev->set_mask, GETSET_POWER_80211);
+	}
+
+	if (adev->set_mask & GETSET_CHANNEL) {
+		/* channel */
+		log(L_INIT, "updating channel to: %u\n", adev->channel);
+		CLEAR_BIT(adev->set_mask, GETSET_CHANNEL);
+	}
+
+	if (adev->set_mask & GETSET_TX) {
+		/* set Tx */
+		log(L_INIT, "updating: %s Tx\n",
+				adev->tx_disabled ? "disable" : "enable");
+		if (adev->tx_disabled)
+			acx_s_issue_cmd(adev, ACX1xx_CMD_DISABLE_TX, NULL, 0);
+		else
+			acx_s_issue_cmd(adev, ACX1xx_CMD_ENABLE_TX, &adev->channel, 1);
+		CLEAR_BIT(adev->set_mask, GETSET_TX);
+	}
+
+	if (adev->set_mask & GETSET_RX) {
+		/* Enable Rx */
+		log(L_INIT, "updating: enable Rx on channel: %u\n",
+				adev->channel);
+		acx_s_issue_cmd(adev, ACX1xx_CMD_ENABLE_RX, &adev->channel, 1);
+		CLEAR_BIT(adev->set_mask, GETSET_RX);
+	}
+
+	if (adev->set_mask & GETSET_RETRY) {
+		u8 short_retry[4 + ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT_LEN];
+		u8 long_retry[4 + ACX1xx_IE_DOT11_LONG_RETRY_LIMIT_LEN];
+
+		log(L_INIT, "updating short retry limit: %u, long retry limit: %u\n",
+					adev->short_retry, adev->long_retry);
+		short_retry[0x4] = adev->short_retry;
+		long_retry[0x4] = adev->long_retry;
+		acx_s_configure(adev, &short_retry, ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT);
+		acx_s_configure(adev, &long_retry, ACX1xx_IE_DOT11_LONG_RETRY_LIMIT);
+		CLEAR_BIT(adev->set_mask, GETSET_RETRY);
+	}
+
+	if (adev->set_mask & SET_MSDU_LIFETIME) {
+		u8 xmt_msdu_lifetime[4 + ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME_LEN];
+
+		log(L_INIT, "updating tx MSDU lifetime: %u\n",
+					adev->msdu_lifetime);
+		*(u32 *)&xmt_msdu_lifetime[4] = cpu_to_le32((u32)adev->msdu_lifetime);
+		acx_s_configure(adev, &xmt_msdu_lifetime, ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME);
+		CLEAR_BIT(adev->set_mask, SET_MSDU_LIFETIME);
+	}
+
+	if (adev->set_mask & GETSET_REG_DOMAIN) {
+		log(L_INIT, "updating regulatory domain: 0x%02X\n",
+					adev->reg_dom_id);
+		acx_s_set_sane_reg_domain(adev, 1);
+		CLEAR_BIT(adev->set_mask, GETSET_REG_DOMAIN);
+	}
+
+	if (adev->set_mask & GETSET_MODE) {
+		adev->ndev->type = (adev->mode == ACX_MODE_MONITOR) ?
+			adev->monitor_type : ARPHRD_ETHER;
+
+		switch (adev->mode) {
+		case ACX_MODE_3_AP:
+
+			acx_lock(adev, flags);
+			acx_l_sta_list_init(adev);
+			adev->aid = 0;
+			adev->ap_client = NULL;
+			MAC_COPY(adev->bssid, adev->dev_addr);
+			/* this basically says "we're connected" */
+			acx_set_status(adev, ACX_STATUS_4_ASSOCIATED);
+			acx_unlock(adev, flags);
+
+			acx111_s_feature_off(adev, 0, FEATURE2_NO_TXCRYPT|FEATURE2_SNIFFER);
+			/* start sending beacons */
+			acx_s_cmd_join_bssid(adev, adev->bssid);
+			break;
+		case ACX_MODE_MONITOR:
+			acx111_s_feature_on(adev, 0, FEATURE2_NO_TXCRYPT|FEATURE2_SNIFFER);
+			/* this stops beacons */
+			acx_s_cmd_join_bssid(adev, adev->bssid);
+			/* this basically says "we're connected" */
+			acx_set_status(adev, ACX_STATUS_4_ASSOCIATED);
+			SET_BIT(adev->set_mask, SET_RXCONFIG|SET_WEP_OPTIONS);
+			break;
+		case ACX_MODE_0_ADHOC:
+		case ACX_MODE_2_STA:
+			acx111_s_feature_off(adev, 0, FEATURE2_NO_TXCRYPT|FEATURE2_SNIFFER);
+
+			acx_lock(adev, flags);
+			adev->aid = 0;
+			adev->ap_client = NULL;
+			acx_unlock(adev, flags);
+
+			/* we want to start looking for peer or AP */
+			start_scan = 1;
+			break;
+		case ACX_MODE_OFF:
+			/* TODO: disable RX/TX, stop any scanning activity etc: */
+			/* adev->tx_disabled = 1; */
+			/* SET_BIT(adev->set_mask, GETSET_RX|GETSET_TX); */
+
+			/* This stops beacons (invalid macmode...) */
+			acx_s_cmd_join_bssid(adev, adev->bssid);
+			acx_set_status(adev, ACX_STATUS_0_STOPPED);
+			break;
+		}
+		CLEAR_BIT(adev->set_mask, GETSET_MODE);
+	}
+
+	if (adev->set_mask & SET_RXCONFIG) {
+		acx_s_initialize_rx_config(adev);
+		CLEAR_BIT(adev->set_mask, SET_RXCONFIG);
+	}
+
+	if (adev->set_mask & GETSET_RESCAN) {
+		switch (adev->mode) {
+		case ACX_MODE_0_ADHOC:
+		case ACX_MODE_2_STA:
+			start_scan = 1;
+			break;
+		}
+		CLEAR_BIT(adev->set_mask, GETSET_RESCAN);
+	}
+
+	if (adev->set_mask & GETSET_WEP) {
+		/* encode */
+
+		ie_dot11WEPDefaultKeyID_t dkey;
+#ifdef DEBUG_WEP
+		struct {
+			u16 type ACX_PACKED;
+			u16 len ACX_PACKED;
+			u8  val ACX_PACKED;
+		} keyindic;
+#endif
+		log(L_INIT, "updating WEP key settings\n");
+
+		acx_s_set_wepkey(adev);
+
+		dkey.KeyID = adev->wep_current_index;
+		log(L_INIT, "setting WEP key %u as default\n", dkey.KeyID);
+		acx_s_configure(adev, &dkey, ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET);
+#ifdef DEBUG_WEP
+		keyindic.val = 3;
+		acx_s_configure(adev, &keyindic, ACX111_IE_KEY_CHOOSE);
+#endif
+		start_scan = 1;
+		CLEAR_BIT(adev->set_mask, GETSET_WEP);
+	}
+
+	if (adev->set_mask & SET_WEP_OPTIONS) {
+		acx100_ie_wep_options_t options;
+
+		if (IS_ACX111(adev)) {
+			log(L_DEBUG, "setting WEP Options for acx111 is not supported\n");
+		} else {
+			log(L_INIT, "setting WEP Options\n");
+
+			/* let's choose maximum setting: 4 default keys,
+			 * plus 10 other keys: */
+			options.NumKeys = cpu_to_le16(DOT11_MAX_DEFAULT_WEP_KEYS + 10);
+			/* don't decrypt default key only,
+			 * don't override decryption: */
+			options.WEPOption = 0;
+			if (adev->mode == ACX_MODE_MONITOR) {
+				/* don't decrypt default key only,
+				 * override decryption mechanism: */
+				options.WEPOption = 2;
+			}
+
+			acx_s_configure(adev, &options, ACX100_IE_WEP_OPTIONS);
+		}
+		CLEAR_BIT(adev->set_mask, SET_WEP_OPTIONS);
+	}
+
+	/* Rescan was requested */
+	if (start_scan) {
+		switch (adev->mode) {
+		case ACX_MODE_0_ADHOC:
+		case ACX_MODE_2_STA:
+			/* We can avoid clearing list if join code
+			** will be a bit more clever about not picking
+			** 'bad' AP over and over again */
+			acx_lock(adev, flags);
+			adev->ap_client = NULL;
+			acx_l_sta_list_init(adev);
+			acx_set_status(adev, ACX_STATUS_1_SCANNING);
+			acx_unlock(adev, flags);
+
+			acx_s_cmd_start_scan(adev);
+		}
+	}
+
+	/* debug, rate, and nick don't need any handling */
+	/* what about sniffing mode?? */
+
+	log(L_INIT, "get_mask 0x%08X, set_mask 0x%08X - after update\n",
+			adev->get_mask, adev->set_mask);
+
+/* end: */
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acx_e_after_interrupt_task
+*/
+static int
+acx_s_recalib_radio(acx_device_t *adev)
+{
+	if (IS_ACX111(adev)) {
+		acx111_cmd_radiocalib_t cal;
+
+		printk("%s: recalibrating radio\n", adev->ndev->name);
+		/* automatic recalibration, choose all methods: */
+		cal.methods = cpu_to_le32(0x8000000f);
+		/* automatic recalibration every 60 seconds (value in TUs)
+		 * I wonder what the firmware default here is? */
+		cal.interval = cpu_to_le32(58594);
+		return acx_s_issue_cmd_timeo(adev, ACX111_CMD_RADIOCALIB,
+			&cal, sizeof(cal), CMD_TIMEOUT_MS(100));
+	} else {
+		/* On ACX100, we need to recalibrate the radio
+		 * by issuing a GETSET_TX|GETSET_RX */
+		if (/* (OK == acx_s_issue_cmd(adev, ACX1xx_CMD_DISABLE_TX, NULL, 0)) &&
+		    (OK == acx_s_issue_cmd(adev, ACX1xx_CMD_DISABLE_RX, NULL, 0)) && */
+		    (OK == acx_s_issue_cmd(adev, ACX1xx_CMD_ENABLE_TX, &adev->channel, 1)) &&
+		    (OK == acx_s_issue_cmd(adev, ACX1xx_CMD_ENABLE_RX, &adev->channel, 1)) )
+			return OK;
+		return NOT_OK;
+	}
+}
+
+static void
+acx_s_after_interrupt_recalib(acx_device_t *adev)
+{
+	int res;
+
+	/* this helps with ACX100 at least;
+	 * hopefully ACX111 also does a
+	 * recalibration here */
+
+	/* clear flag beforehand, since we want to make sure
+	 * it's cleared; then only set it again on specific circumstances */
+	CLEAR_BIT(adev->after_interrupt_jobs, ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
+
+	/* better wait a bit between recalibrations to
+	 * prevent overheating due to torturing the card
+	 * into working too long despite high temperature
+	 * (just a safety measure) */
+	if (adev->recalib_time_last_success
+	 && time_before(jiffies, adev->recalib_time_last_success
+					+ RECALIB_PAUSE * 60 * HZ)) {
+		if (adev->recalib_msg_ratelimit <= 4) {
+			printk("%s: less than " STRING(RECALIB_PAUSE)
+				" minutes since last radio recalibration, "
+				"not recalibrating (maybe card is too hot?)\n",
+				adev->ndev->name);
+			adev->recalib_msg_ratelimit++;
+			if (adev->recalib_msg_ratelimit == 5)
+				printk("disabling above message\n");
+		}
+		return;
+	}
+
+	adev->recalib_msg_ratelimit = 0;
+
+	/* note that commands sometimes fail (card busy),
+	 * so only clear flag if we were fully successful */
+	res = acx_s_recalib_radio(adev);
+	if (res == OK) {
+		printk("%s: successfully recalibrated radio\n",
+						adev->ndev->name);
+		adev->recalib_time_last_success = jiffies;
+		adev->recalib_failure_count = 0;
+	} else {
+		/* failed: resubmit, but only limited
+		 * amount of times within some time range
+		 * to prevent endless loop */
+
+		adev->recalib_time_last_success = 0; /* we failed */
+
+		/* if some time passed between last
+		 * attempts, then reset failure retry counter
+		 * to be able to do next recalib attempt */
+		if (time_after(jiffies, adev->recalib_time_last_attempt + 5*HZ))
+			adev->recalib_failure_count = 0;
+
+		if (adev->recalib_failure_count < 5) {
+			/* increment inside only, for speedup of outside path */
+			adev->recalib_failure_count++;
+			adev->recalib_time_last_attempt = jiffies;
+			acx_schedule_task(adev, ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
+		}
+	}
+}
+
+static void
+acx_e_after_interrupt_task(void *data)
+{
+	struct net_device *ndev = (struct net_device*)data;
+	acx_device_t *adev = ndev2adev(ndev);
+
+	FN_ENTER;
+
+	acx_sem_lock(adev);
+
+	if (!adev->after_interrupt_jobs)
+		goto end; /* no jobs to do */
+
+#if TX_CLEANUP_IN_SOFTIRQ
+	/* can happen only on PCI */
+	if (adev->after_interrupt_jobs & ACX_AFTER_IRQ_TX_CLEANUP) {
+		acx_lock(adev, flags);
+		acxpci_l_clean_txdesc(adev);
+		CLEAR_BIT(adev->after_interrupt_jobs, ACX_AFTER_IRQ_TX_CLEANUP);
+		acx_unlock(adev, flags);
+	}
+#endif
+	/* we see lotsa tx errors */
+	if (adev->after_interrupt_jobs & ACX_AFTER_IRQ_CMD_RADIO_RECALIB) {
+		acx_s_after_interrupt_recalib(adev);
+	}
+
+	/* a poor interrupt code wanted to do update_card_settings() */
+	if (adev->after_interrupt_jobs & ACX_AFTER_IRQ_UPDATE_CARD_CFG) {
+		if (ACX_STATE_IFACE_UP & adev->dev_state_mask)
+			acx_s_update_card_settings(adev);
+		CLEAR_BIT(adev->after_interrupt_jobs, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
+	}
+
+	/* 1) we detected that no Scan_Complete IRQ came from fw, or
+	** 2) we found too many STAs */
+	if (adev->after_interrupt_jobs & ACX_AFTER_IRQ_CMD_STOP_SCAN) {
+		log(L_IRQ, "sending a stop scan cmd...\n");
+		acx_s_issue_cmd(adev, ACX1xx_CMD_STOP_SCAN, NULL, 0);
+		/* HACK: set the IRQ bit, since we won't get a
+		 * scan complete IRQ any more on ACX111 (works on ACX100!),
+		 * since _we_, not a fw, have stopped the scan */
+		SET_BIT(adev->irq_status, HOST_INT_SCAN_COMPLETE);
+		CLEAR_BIT(adev->after_interrupt_jobs, ACX_AFTER_IRQ_CMD_STOP_SCAN);
+	}
+
+	/* either fw sent Scan_Complete or we detected that
+	** no Scan_Complete IRQ came from fw. Finish scanning,
+	** pick join partner if any */
+	if (adev->after_interrupt_jobs & ACX_AFTER_IRQ_COMPLETE_SCAN) {
+		if (adev->status == ACX_STATUS_1_SCANNING) {
+			if (OK != acx_s_complete_scan(adev)) {
+				SET_BIT(adev->after_interrupt_jobs,
+					ACX_AFTER_IRQ_RESTART_SCAN);
+			}
+		} else {
+			/* + scan kills current join status - restore it
+			**   (do we need it for STA?) */
+			/* + does it happen only with active scans?
+			**   active and passive scans? ALL scans including
+			**   background one? */
+			/* + was not verified that everything is restored
+			**   (but at least we start to emit beacons again) */
+			switch (adev->mode) {
+			case ACX_MODE_0_ADHOC:
+			case ACX_MODE_3_AP:
+				log(L_IRQ, "redoing cmd_join_bssid() after scan\n");
+				acx_s_cmd_join_bssid(adev, adev->bssid);
+			}
+		}
+		CLEAR_BIT(adev->after_interrupt_jobs, ACX_AFTER_IRQ_COMPLETE_SCAN);
+	}
+
+	/* STA auth or assoc timed out, start over again */
+	if (adev->after_interrupt_jobs & ACX_AFTER_IRQ_RESTART_SCAN) {
+		log(L_IRQ, "sending a start_scan cmd...\n");
+		acx_s_cmd_start_scan(adev);
+		CLEAR_BIT(adev->after_interrupt_jobs, ACX_AFTER_IRQ_RESTART_SCAN);
+	}
+
+	/* whee, we got positive assoc response! 8) */
+	if (adev->after_interrupt_jobs & ACX_AFTER_IRQ_CMD_ASSOCIATE) {
+		acx_ie_generic_t pdr;
+		/* tiny race window exists, checking that we still a STA */
+		switch (adev->mode) {
+		case ACX_MODE_2_STA:
+			pdr.m.aid = cpu_to_le16(adev->aid);
+			acx_s_configure(adev, &pdr, ACX1xx_IE_ASSOC_ID);
+			acx_set_status(adev, ACX_STATUS_4_ASSOCIATED);
+			log(L_ASSOC|L_DEBUG, "ASSOCIATED!\n");
+			CLEAR_BIT(adev->after_interrupt_jobs, ACX_AFTER_IRQ_CMD_ASSOCIATE);
+		}
+	}
+end:
+	acx_sem_unlock(adev);
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acx_schedule_task
+**
+** Schedule the call of the after_interrupt method after leaving
+** the interrupt context.
+*/
+void
+acx_schedule_task(acx_device_t *adev, unsigned int set_flag)
+{
+	SET_BIT(adev->after_interrupt_jobs, set_flag);
+	SCHEDULE_WORK(&adev->after_interrupt_task);
+}
+
+
+/***********************************************************************
+*/
+void
+acx_init_task_scheduler(acx_device_t *adev)
+{
+	/* configure task scheduler */
+	INIT_WORK(&adev->after_interrupt_task, acx_e_after_interrupt_task,
+			adev->ndev);
+}
+
+
+/***********************************************************************
+** acx_s_start
+*/
+void
+acx_s_start(acx_device_t *adev)
+{
+	FN_ENTER;
+
+	/*
+	 * Ok, now we do everything that can possibly be done with ioctl
+	 * calls to make sure that when it was called before the card
+	 * was up we get the changes asked for
+	 */
+
+	SET_BIT(adev->set_mask, SET_TEMPLATES|SET_STA_LIST|GETSET_WEP
+		|GETSET_TXPOWER|GETSET_ANTENNA|GETSET_ED_THRESH|GETSET_CCA
+		|GETSET_REG_DOMAIN|GETSET_MODE|GETSET_CHANNEL
+		|GETSET_TX|GETSET_RX);
+
+	log(L_INIT, "updating initial settings on iface activation\n");
+	acx_s_update_card_settings(adev);
+
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acx_update_capabilities
+*/
+void
+acx_update_capabilities(acx_device_t *adev)
+{
+	u16 cap = 0;
+
+	switch (adev->mode) {
+	case ACX_MODE_3_AP:
+		SET_BIT(cap, WF_MGMT_CAP_ESS); break;
+	case ACX_MODE_0_ADHOC:
+		SET_BIT(cap, WF_MGMT_CAP_IBSS); break;
+	/* other types of stations do not emit beacons */
+	}
+
+	if (adev->wep_restricted) {
+		SET_BIT(cap, WF_MGMT_CAP_PRIVACY);
+	}
+	if (adev->cfgopt_dot11ShortPreambleOption) {
+		SET_BIT(cap, WF_MGMT_CAP_SHORT);
+	}
+	if (adev->cfgopt_dot11PBCCOption) {
+		SET_BIT(cap, WF_MGMT_CAP_PBCC);
+	}
+	if (adev->cfgopt_dot11ChannelAgility) {
+		SET_BIT(cap, WF_MGMT_CAP_AGILITY);
+	}
+	log(L_DEBUG, "caps updated from 0x%04X to 0x%04X\n",
+				adev->capabilities, cap);
+	adev->capabilities = cap;
+}
+
+/***********************************************************************
+** Common function to parse ALL configoption struct formats
+** (ACX100 and ACX111; FIXME: how to make it work with ACX100 USB!?!?).
+** FIXME: logging should be removed here and added to a /proc file instead
+*/
+void
+acx_s_parse_configoption(acx_device_t *adev, const acx111_ie_configoption_t *pcfg)
+{
+	const u8 *pEle;
+	int i;
+	int is_acx111 = IS_ACX111(adev);
+
+	if (acx_debug & L_DEBUG) {
+		printk("configoption struct content:\n");
+		acx_dump_bytes(pcfg, sizeof(*pcfg));
+	}
+
+	if (( is_acx111 && (adev->eeprom_version == 5))
+	||  (!is_acx111 && (adev->eeprom_version == 4))
+	||  (!is_acx111 && (adev->eeprom_version == 5))) {
+		/* these versions are known to be supported */
+	} else {
+		printk("unknown chip and EEPROM version combination (%s, v%d), "
+			"don't know how to parse config options yet. "
+			"Please report\n", is_acx111 ? "ACX111" : "ACX100",
+			adev->eeprom_version);
+		return;
+	}
+
+	/* first custom-parse the first part which has chip-specific layout */
+
+	pEle = (const u8 *) pcfg;
+
+	pEle += 4; /* skip (type,len) header */
+
+	memcpy(adev->cfgopt_NVSv, pEle, sizeof(adev->cfgopt_NVSv));
+	pEle += sizeof(adev->cfgopt_NVSv);
+
+	if (is_acx111) {
+		adev->cfgopt_NVS_vendor_offs = le16_to_cpu(*(u16 *)pEle);
+		pEle += sizeof(adev->cfgopt_NVS_vendor_offs);
+
+		adev->cfgopt_probe_delay = 200; /* good default value? */
+		pEle += 2; /* FIXME: unknown, value 0x0001 */
+	} else {
+		memcpy(adev->cfgopt_MAC, pEle, sizeof(adev->cfgopt_MAC));
+		pEle += sizeof(adev->cfgopt_MAC);
+
+		adev->cfgopt_probe_delay = le16_to_cpu(*(u16 *)pEle);
+		pEle += sizeof(adev->cfgopt_probe_delay);
+		if ((adev->cfgopt_probe_delay < 100) || (adev->cfgopt_probe_delay > 500)) {
+			printk("strange probe_delay value %d, "
+				"tweaking to 200\n", adev->cfgopt_probe_delay);
+			adev->cfgopt_probe_delay = 200;
+		}
+	}
+
+	adev->cfgopt_eof_memory = le32_to_cpu(*(u32 *)pEle);
+	pEle += sizeof(adev->cfgopt_eof_memory);
+
+	printk("NVS_vendor_offs:%04X probe_delay:%d eof_memory:%d\n",
+		adev->cfgopt_NVS_vendor_offs,
+		adev->cfgopt_probe_delay,
+		adev->cfgopt_eof_memory);
+
+	adev->cfgopt_dot11CCAModes = *pEle++;
+	adev->cfgopt_dot11Diversity = *pEle++;
+	adev->cfgopt_dot11ShortPreambleOption = *pEle++;
+	adev->cfgopt_dot11PBCCOption = *pEle++;
+	adev->cfgopt_dot11ChannelAgility = *pEle++;
+	adev->cfgopt_dot11PhyType = *pEle++;
+	adev->cfgopt_dot11TempType = *pEle++;
+	printk("CCAModes:%02X Diversity:%02X ShortPreOpt:%02X "
+		"PBCC:%02X ChanAgil:%02X PHY:%02X Temp:%02X\n",
+		adev->cfgopt_dot11CCAModes,
+		adev->cfgopt_dot11Diversity,
+		adev->cfgopt_dot11ShortPreambleOption,
+		adev->cfgopt_dot11PBCCOption,
+		adev->cfgopt_dot11ChannelAgility,
+		adev->cfgopt_dot11PhyType,
+		adev->cfgopt_dot11TempType);
+
+	/* then use common parsing for next part which has common layout */
+
+	pEle++; /* skip table_count (6) */
+
+	adev->cfgopt_antennas.type = pEle[0];
+	adev->cfgopt_antennas.len = pEle[1];
+	printk("AntennaID:%02X Len:%02X Data:",
+			adev->cfgopt_antennas.type, adev->cfgopt_antennas.len);
+	for (i = 0; i < pEle[1]; i++) {
+		adev->cfgopt_antennas.list[i] = pEle[i+2];
+		printk("%02X ", pEle[i+2]);
+	}
+	printk("\n");
+
+	pEle += pEle[1] + 2;
+	adev->cfgopt_power_levels.type = pEle[0];
+	adev->cfgopt_power_levels.len = pEle[1];
+	printk("PowerLevelID:%02X Len:%02X Data:",
+		adev->cfgopt_power_levels.type, adev->cfgopt_power_levels.len);
+	for (i = 0; i < pEle[1]; i++) {
+		adev->cfgopt_power_levels.list[i] = le16_to_cpu(*(u16 *)&pEle[i*2+2]);
+		printk("%04X ", adev->cfgopt_power_levels.list[i]);
+	}
+	printk("\n");
+
+	pEle += pEle[1]*2 + 2;
+	adev->cfgopt_data_rates.type = pEle[0];
+	adev->cfgopt_data_rates.len = pEle[1];
+	printk("DataRatesID:%02X Len:%02X Data:",
+		adev->cfgopt_data_rates.type, adev->cfgopt_data_rates.len);
+	for (i = 0; i < pEle[1]; i++) {
+		adev->cfgopt_data_rates.list[i] = pEle[i+2];
+		printk("%02X ", pEle[i+2]);
+	}
+	printk("\n");
+
+	pEle += pEle[1] + 2;
+	adev->cfgopt_domains.type = pEle[0];
+	adev->cfgopt_domains.len = pEle[1];
+	printk("DomainID:%02X Len:%02X Data:",
+			adev->cfgopt_domains.type, adev->cfgopt_domains.len);
+	for (i = 0; i < pEle[1]; i++) {
+		adev->cfgopt_domains.list[i] = pEle[i+2];
+		printk("%02X ", pEle[i+2]);
+	}
+	printk("\n");
+
+	pEle += pEle[1] + 2;
+	adev->cfgopt_product_id.type = pEle[0];
+	adev->cfgopt_product_id.len = pEle[1];
+	for (i = 0; i < pEle[1]; i++) {
+		adev->cfgopt_product_id.list[i] = pEle[i+2];
+	}
+	printk("ProductID:%02X Len:%02X Data:%.*s\n",
+		adev->cfgopt_product_id.type, adev->cfgopt_product_id.len,
+		adev->cfgopt_product_id.len, (char *)adev->cfgopt_product_id.list);
+
+	pEle += pEle[1] + 2;
+	adev->cfgopt_manufacturer.type = pEle[0];
+	adev->cfgopt_manufacturer.len = pEle[1];
+	for (i = 0; i < pEle[1]; i++) {
+		adev->cfgopt_manufacturer.list[i] = pEle[i+2];
+	}
+	printk("ManufacturerID:%02X Len:%02X Data:%.*s\n",
+		adev->cfgopt_manufacturer.type, adev->cfgopt_manufacturer.len,
+		adev->cfgopt_manufacturer.len, (char *)adev->cfgopt_manufacturer.list);
+/*
+	printk("EEPROM part:\n");
+	for (i=0; i<58; i++) {
+		printk("%02X =======>  0x%02X\n",
+			i, (u8 *)adev->cfgopt_NVSv[i-2]);
+	}
+*/
+}
+
+
+/***********************************************************************
+*/
+static int __init
+acx_e_init_module(void)
+{
+	int r1,r2;
+
+	acx_struct_size_check();
+
+	printk("acx: this driver is still EXPERIMENTAL\n"
+		"acx: reading README file and/or Craig's HOWTO is "
+		"recommended, visit http://acx100.sf.net in case "
+		"of further questions/discussion\n");
+
+#if defined(CONFIG_ACX_PCI)
+	r1 = acxpci_e_init_module();
+#else
+	r1 = -EINVAL;
+#endif
+#if defined(CONFIG_ACX_USB)
+	r2 = acxusb_e_init_module();
+#else
+	r2 = -EINVAL;
+#endif
+	if (r2 && r1) /* both failed! */
+		return r2 ? r2 : r1;
+	/* return success if at least one succeeded */
+	return 0;
+}
+
+static void __exit
+acx_e_cleanup_module(void)
+{
+#if defined(CONFIG_ACX_PCI)
+	acxpci_e_cleanup_module();
+#endif
+#if defined(CONFIG_ACX_USB)
+	acxusb_e_cleanup_module();
+#endif
+}
+
+module_init(acx_e_init_module)
+module_exit(acx_e_cleanup_module)
diff -urN oldtree/drivers/net/wireless/tiacx/conv.c newtree/drivers/net/wireless/tiacx/conv.c
--- oldtree/drivers/net/wireless/tiacx/conv.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/net/wireless/tiacx/conv.c	2006-02-21 15:58:22.563716352 +0000
@@ -0,0 +1,502 @@
+/***********************************************************************
+** Copyright (C) 2003  ACX100 Open Source Project
+**
+** The contents of this file are subject to the Mozilla Public
+** License Version 1.1 (the "License"); you may not use this file
+** except in compliance with the License. You may obtain a copy of
+** the License at http://www.mozilla.org/MPL/
+**
+** Software distributed under the License is distributed on an "AS
+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+** implied. See the License for the specific language governing
+** rights and limitations under the License.
+**
+** Alternatively, the contents of this file may be used under the
+** terms of the GNU Public License version 2 (the "GPL"), in which
+** case the provisions of the GPL are applicable instead of the
+** above.  If you wish to allow the use of your version of this file
+** only under the terms of the GPL and not to allow others to use
+** your version of this file under the MPL, indicate your decision
+** by deleting the provisions above and replace them with the notice
+** and other provisions required by the GPL.  If you do not delete
+** the provisions above, a recipient may use your version of this
+** file under either the MPL or the GPL.
+** ---------------------------------------------------------------------
+** Inquiries regarding the ACX100 Open Source Project can be
+** made directly to:
+**
+** acx100-users@lists.sf.net
+** http://acx100.sf.net
+** ---------------------------------------------------------------------
+*/
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+
+#include "acx.h"
+
+
+/***********************************************************************
+** proto_is_stt
+**
+** Searches the 802.1h Selective Translation Table for a given
+** protocol.
+**
+** prottype - protocol number (in host order) to search for.
+**
+** Returns:
+**	1 - if the table is empty or a match is found.
+**	0 - if the table is non-empty and a match is not found.
+**
+** Based largely on p80211conv.c of the linux-wlan-ng project
+*/
+static inline int
+proto_is_stt(unsigned int proto)
+{
+	/* Always return found for now.  This is the behavior used by the */
+	/* Zoom Win95 driver when 802.1h mode is selected */
+	/* TODO: If necessary, add an actual search we'll probably
+		 need this to match the CMAC's way of doing things.
+		 Need to do some testing to confirm.
+	*/
+
+	if (proto == 0x80f3)  /* APPLETALK */
+		return 1;
+
+	return 0;
+/*	return ((prottype == ETH_P_AARP) || (prottype == ETH_P_IPX)); */
+}
+
+/* Helpers */
+
+static inline void
+store_llc_snap(struct wlan_llc *llc)
+{
+	llc->dsap = 0xaa;	/* SNAP, see IEEE 802 */
+	llc->ssap = 0xaa;
+	llc->ctl = 0x03;
+}
+static inline int
+llc_is_snap(const struct wlan_llc *llc)
+{
+	return (llc->dsap == 0xaa)
+	&& (llc->ssap == 0xaa)
+	&& (llc->ctl == 0x03);
+}
+static inline void
+store_oui_rfc1042(struct wlan_snap *snap)
+{
+	snap->oui[0] = 0;
+	snap->oui[1] = 0;
+	snap->oui[2] = 0;
+}
+static inline int
+oui_is_rfc1042(const struct wlan_snap *snap)
+{
+	return (snap->oui[0] == 0)
+	&& (snap->oui[1] == 0)
+	&& (snap->oui[2] == 0);
+}
+static inline void
+store_oui_8021h(struct wlan_snap *snap)
+{
+	snap->oui[0] = 0;
+	snap->oui[1] = 0;
+	snap->oui[2] = 0xf8;
+}
+static inline int
+oui_is_8021h(const struct wlan_snap *snap)
+{
+	return (snap->oui[0] == 0)
+	&& (snap->oui[1] == 0)
+	&& (snap->oui[2] == 0xf8);
+}
+
+
+/***********************************************************************
+** acx_ether_to_txbuf
+**
+** Uses the contents of the ether frame to build the elements of
+** the 802.11 frame.
+**
+** We don't actually set up the frame header here.  That's the
+** MAC's job.  We're only handling conversion of DIXII or 802.3+LLC
+** frames to something that works with 802.11.
+**
+** Based largely on p80211conv.c of the linux-wlan-ng project
+*/
+int
+acx_ether_to_txbuf(acx_device_t *adev, void *txbuf, const struct sk_buff *skb)
+{
+	struct wlan_hdr_a3 *w_hdr;
+	struct wlan_ethhdr *e_hdr;
+	struct wlan_llc *e_llc;
+	struct wlan_snap *e_snap;
+	const u8 *a1, *a3;
+	int header_len, payload_len = -1;
+	/* protocol type or data length, depending on whether
+	 * DIX or 802.3 ethernet format */
+	u16 proto;
+	u16 fc;
+
+	FN_ENTER;
+
+	if (unlikely(!skb->len)) {
+		log(L_DEBUG, "zero-length skb!\n");
+		goto end;
+	}
+
+	w_hdr = (struct wlan_hdr_a3*)txbuf;
+
+	switch (adev->mode) {
+	case ACX_MODE_MONITOR:
+		/* NB: one day we might want to play with DESC_CTL2_FCS
+		** Will need to stop doing "- WLAN_FCS_LEN" here then */
+		if (unlikely(skb->len >= WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_FCS_LEN)) {
+			printk("%s: can't tx oversized frame (%d bytes)\n",
+				adev->ndev->name, skb->len);
+			goto end;
+		}
+		memcpy(w_hdr, skb->data, skb->len);
+		payload_len = skb->len;
+		goto end;
+	}
+
+	/* step 1: classify ether frame, DIX or 802.3? */
+	e_hdr = (wlan_ethhdr_t *)skb->data;
+	proto = ntohs(e_hdr->type);
+	if (proto <= 1500) {
+		log(L_DEBUG, "tx: 802.3 len: %d\n", skb->len);
+		/* codes <= 1500 reserved for 802.3 lengths */
+		/* it's 802.3, pass ether payload unchanged, */
+		/* trim off ethernet header and copy payload to txdesc */
+		header_len = WLAN_HDR_A3_LEN;
+	} else {
+		/* it's DIXII, time for some conversion */
+		/* Create 802.11 packet. Header also contains llc and snap. */
+
+		log(L_DEBUG, "tx: DIXII len: %d\n", skb->len);
+
+		/* size of header is 802.11 header + llc + snap */
+		header_len = WLAN_HDR_A3_LEN + sizeof(wlan_llc_t) + sizeof(wlan_snap_t);
+		/* llc is located behind the 802.11 header */
+		e_llc = (wlan_llc_t*)(w_hdr + 1);
+		/* snap is located behind the llc */
+		e_snap = (wlan_snap_t*)(e_llc + 1);
+
+		/* setup the LLC header */
+		store_llc_snap(e_llc);
+
+		/* setup the SNAP header */
+		e_snap->type = htons(proto);
+		if (proto_is_stt(proto)) {
+			store_oui_8021h(e_snap);
+		} else {
+			store_oui_rfc1042(e_snap);
+		}
+	}
+	/* trim off ethernet header and copy payload to txbuf */
+	payload_len = skb->len - sizeof(wlan_ethhdr_t);
+	/* TODO: can we just let acx DMA payload from skb instead? */
+	memcpy((u8*)txbuf + header_len, skb->data + sizeof(wlan_ethhdr_t), payload_len);
+	payload_len += header_len;
+
+	/* Set up the 802.11 header */
+	switch (adev->mode) {
+	case ACX_MODE_0_ADHOC:
+		fc = (WF_FTYPE_DATAi | WF_FSTYPE_DATAONLYi);
+		a1 = e_hdr->daddr;
+		a3 = adev->bssid;
+		break;
+	case ACX_MODE_2_STA:
+		fc = (WF_FTYPE_DATAi | WF_FSTYPE_DATAONLYi | WF_FC_TODSi);
+		a1 = adev->bssid;
+		a3 = e_hdr->daddr;
+		break;
+	case ACX_MODE_3_AP:
+		fc = (WF_FTYPE_DATAi | WF_FSTYPE_DATAONLYi | WF_FC_FROMDSi);
+		a1 = e_hdr->daddr;
+		a3 = e_hdr->saddr;
+		break;
+	default:
+		printk("%s: error - converting eth to wlan in unknown mode\n",
+				adev->ndev->name);
+		payload_len = -1;
+		goto end;
+	}
+	if (adev->wep_enabled)
+		SET_BIT(fc, WF_FC_ISWEPi);
+
+	w_hdr->fc = fc;
+	w_hdr->dur = 0;
+	MAC_COPY(w_hdr->a1, a1);
+	MAC_COPY(w_hdr->a2, adev->dev_addr);
+	MAC_COPY(w_hdr->a3, a3);
+	w_hdr->seq = 0;
+
+#ifdef DEBUG_CONVERT
+	if (acx_debug & L_DATA) {
+		printk("original eth frame [%d]: ", skb->len);
+		acx_dump_bytes(skb->data, skb->len);
+		printk("802.11 frame [%d]: ", payload_len);
+		acx_dump_bytes(w_hdr, payload_len);
+	}
+#endif
+
+end:
+	FN_EXIT1(payload_len);
+	return payload_len;
+}
+
+
+/***********************************************************************
+** acx_rxbuf_to_ether
+**
+** Uses the contents of a received 802.11 frame to build an ether
+** frame.
+**
+** This function extracts the src and dest address from the 802.11
+** frame to use in the construction of the eth frame.
+**
+** Based largely on p80211conv.c of the linux-wlan-ng project
+*/
+struct sk_buff*
+acx_rxbuf_to_ether(acx_device_t *adev, rxbuffer_t *rxbuf)
+{
+	struct wlan_hdr *w_hdr;
+	struct wlan_ethhdr *e_hdr;
+	struct wlan_llc *e_llc;
+	struct wlan_snap *e_snap;
+	struct sk_buff *skb;
+	const u8 *daddr;
+	const u8 *saddr;
+	const u8 *e_payload;
+	int buflen, payload_length;
+	unsigned int payload_offset, mtu;
+	u16 fc;
+
+	FN_ENTER;
+
+	/* This looks complex because it must handle possible
+	** phy header in rxbuff */
+	w_hdr = acx_get_wlan_hdr(adev, rxbuf);
+	payload_offset = WLAN_HDR_A3_LEN; /* it is relative to w_hdr */
+	payload_length = RXBUF_BYTES_USED(rxbuf) /* entire rxbuff... */
+		- ((u8*)w_hdr - (u8*)rxbuf) /* minus space before 802.11 frame */
+		- WLAN_HDR_A3_LEN; /* minus 802.11 header */
+
+	/* setup some vars for convenience */
+	fc = w_hdr->fc;
+	switch (WF_FC_FROMTODSi & fc) {
+	case 0:
+		daddr = w_hdr->a1;
+		saddr = w_hdr->a2;
+		break;
+	case WF_FC_FROMDSi:
+		daddr = w_hdr->a1;
+		saddr = w_hdr->a3;
+		break;
+	case WF_FC_TODSi:
+		daddr = w_hdr->a3;
+		saddr = w_hdr->a2;
+		break;
+	default: /* WF_FC_FROMTODSi */
+		payload_offset += (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN);
+		payload_length -= (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN);
+		daddr = w_hdr->a3;
+		saddr = w_hdr->a4;
+	}
+
+	if ((WF_FC_ISWEPi & fc) && IS_ACX100(adev)) {
+		/* chop off the IV+ICV WEP header and footer */
+		log(L_DATA|L_DEBUG, "rx: WEP packet, "
+			"chopping off IV and ICV\n");
+		payload_offset += WLAN_WEP_IV_LEN;
+		payload_length -= WLAN_WEP_IV_LEN + WLAN_WEP_ICV_LEN;
+	}
+
+	if (unlikely(payload_length < 0)) {
+		printk("%s: rx frame too short, ignored\n", adev->ndev->name);
+		goto ret_null;
+	}
+
+	e_hdr = (wlan_ethhdr_t*) ((u8*) w_hdr + payload_offset);
+	e_llc = (wlan_llc_t*) e_hdr;
+	e_snap = (wlan_snap_t*) (e_llc + 1);
+	mtu = adev->ndev->mtu;
+	e_payload = (u8*) (e_snap + 1);
+
+	log(L_DATA, "rx: payload_offset %d, payload_length %d\n",
+		payload_offset, payload_length);
+	log(L_XFER|L_DATA,
+		"rx: frame info: llc=%02X%02X%02X "
+		"snap.oui=%02X%02X%02X snap.type=%04X\n",
+		e_llc->dsap, e_llc->ssap, e_llc->ctl,
+		e_snap->oui[0],	e_snap->oui[1], e_snap->oui[2],
+		ntohs(e_snap->type));
+
+	/* Test for the various encodings */
+	if ((payload_length >= sizeof(wlan_ethhdr_t))
+	 && ((e_llc->dsap != 0xaa) || (e_llc->ssap != 0xaa))
+	 && (   (mac_is_equal(daddr, e_hdr->daddr))
+	     || (mac_is_equal(saddr, e_hdr->saddr))
+	    )
+	) {
+	/* 802.3 Encapsulated: */
+	/* wlan frame body contains complete eth frame (header+body) */
+		log(L_DEBUG|L_DATA, "rx: 802.3 ENCAP len=%d\n", payload_length);
+
+		if (unlikely(payload_length > (mtu + ETH_HLEN))) {
+			printk("%s: rx: ENCAP frame too large (%d > %d)\n",
+				adev->ndev->name,
+				payload_length, mtu + ETH_HLEN);
+			goto ret_null;
+		}
+
+		/* allocate space and setup host buffer */
+		buflen = payload_length;
+		/* Attempt to align IP header (14 bytes eth header + 2 = 16) */
+		skb = dev_alloc_skb(buflen + 2);
+		if (unlikely(!skb))
+			goto no_skb;
+		skb_reserve(skb, 2);
+		skb_put(skb, buflen);		/* make room */
+
+		/* now copy the data from the 80211 frame */
+		memcpy(skb->data, e_hdr, payload_length);
+
+	} else if ( (payload_length >= sizeof(wlan_llc_t)+sizeof(wlan_snap_t))
+		 && llc_is_snap(e_llc) ) {
+	/* wlan frame body contains: AA AA 03 ... (it's a SNAP) */
+
+		if ( !oui_is_rfc1042(e_snap)
+		 || (proto_is_stt(ieee2host16(e_snap->type)) /* && (ethconv == WLAN_ETHCONV_8021h) */)) {
+			log(L_DEBUG|L_DATA, "rx: SNAP+RFC1042 len=%d\n", payload_length);
+	/* wlan frame body contains: AA AA 03 !(00 00 00) ... -or- */
+	/* wlan frame body contains: AA AA 03 00 00 00 0x80f3 ... */
+	/* build eth hdr, type = len, copy AA AA 03... as eth body */
+			/* it's a SNAP + RFC1042 frame && protocol is in STT */
+
+			if (unlikely(payload_length > mtu)) {
+				printk("%s: rx: SNAP frame too large (%d > %d)\n",
+					adev->ndev->name,
+					payload_length, mtu);
+				goto ret_null;
+			}
+
+			/* allocate space and setup host buffer */
+			buflen = payload_length + ETH_HLEN;
+			skb = dev_alloc_skb(buflen + 2);
+			if (unlikely(!skb))
+				goto no_skb;
+			skb_reserve(skb, 2);
+			skb_put(skb, buflen);		/* make room */
+
+			/* create 802.3 header */
+			e_hdr = (wlan_ethhdr_t*) skb->data;
+			MAC_COPY(e_hdr->daddr, daddr);
+			MAC_COPY(e_hdr->saddr, saddr);
+			e_hdr->type = htons(payload_length);
+
+			/* Now copy the data from the 80211 frame.
+			   Make room in front for the eth header, and keep the
+			   llc and snap from the 802.11 payload */
+			memcpy(skb->data + ETH_HLEN,
+					e_llc, payload_length);
+
+		} else {
+	/* wlan frame body contains: AA AA 03 00 00 00 [type] [tail] */
+	/* build eth hdr, type=[type], copy [tail] as eth body */
+			log(L_DEBUG|L_DATA, "rx: 802.1h/RFC1042 len=%d\n",
+				payload_length);
+			/* it's an 802.1h frame (an RFC1042 && protocol is not in STT) */
+			/* build a DIXII + RFC894 */
+
+			payload_length -= sizeof(wlan_llc_t) + sizeof(wlan_snap_t);
+			if (unlikely(payload_length > mtu)) {
+				printk("%s: rx: DIXII frame too large (%d > %d)\n",
+					adev->ndev->name,
+					payload_length,	mtu);
+				goto ret_null;
+			}
+
+			/* allocate space and setup host buffer */
+			buflen = payload_length + ETH_HLEN;
+			skb = dev_alloc_skb(buflen + 2);
+			if (unlikely(!skb))
+				goto no_skb;
+			skb_reserve(skb, 2);
+			skb_put(skb, buflen);		/* make room */
+
+			/* create 802.3 header */
+			e_hdr = (wlan_ethhdr_t *) skb->data;
+			MAC_COPY(e_hdr->daddr, daddr);
+			MAC_COPY(e_hdr->saddr, saddr);
+			e_hdr->type = e_snap->type;
+
+			/* Now copy the data from the 80211 frame.
+			   Make room in front for the eth header, and cut off the
+			   llc and snap from the 802.11 payload */
+			memcpy(skb->data + ETH_HLEN,
+					e_payload, payload_length);
+		}
+
+	} else {
+		log(L_DEBUG|L_DATA, "rx: NON-ENCAP len=%d\n", payload_length);
+	/* build eth hdr, type=len, copy wlan body as eth body */
+		/* any NON-ENCAP */
+		/* it's a generic 80211+LLC or IPX 'Raw 802.3' */
+		/* build an 802.3 frame */
+
+		if (unlikely(payload_length > mtu)) {
+			printk("%s: rx: OTHER frame too large (%d > %d)\n",
+				adev->ndev->name, payload_length, mtu);
+			goto ret_null;
+		}
+
+		/* allocate space and setup host buffer */
+		buflen = payload_length + ETH_HLEN;
+		skb = dev_alloc_skb(buflen + 2);
+		if (unlikely(!skb))
+			goto no_skb;
+		skb_reserve(skb, 2);
+		skb_put(skb, buflen);		/* make room */
+
+		/* set up the 802.3 header */
+		e_hdr = (wlan_ethhdr_t *) skb->data;
+		MAC_COPY(e_hdr->daddr, daddr);
+		MAC_COPY(e_hdr->saddr, saddr);
+		e_hdr->type = htons(payload_length);
+
+		/* now copy the data from the 80211 frame */
+		memcpy(skb->data + ETH_HLEN, e_llc, payload_length);
+	}
+
+	skb->dev = adev->ndev;
+	skb->protocol = eth_type_trans(skb, adev->ndev);
+
+#ifdef DEBUG_CONVERT
+	if (acx_debug & L_DATA) {
+		int len = RXBUF_BYTES_RCVD(adev, rxbuf);
+		printk("p802.11 frame [%d]: ", len);
+		acx_dump_bytes(w_hdr, len);
+		printk("eth frame [%d]: ", skb->len);
+		acx_dump_bytes(skb->data, skb->len);
+	}
+#endif
+
+	FN_EXIT0;
+	return skb;
+
+no_skb:
+	printk("%s: rx: no memory for skb (%d bytes)\n",
+			adev->ndev->name, buflen + 2);
+ret_null:
+	FN_EXIT1((int)NULL);
+	return NULL;
+}
diff -urN oldtree/drivers/net/wireless/tiacx/ioctl.c newtree/drivers/net/wireless/tiacx/ioctl.c
--- oldtree/drivers/net/wireless/tiacx/ioctl.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/net/wireless/tiacx/ioctl.c	2006-02-21 15:58:22.566715896 +0000
@@ -0,0 +1,2733 @@
+/***********************************************************************
+** Copyright (C) 2003  ACX100 Open Source Project
+**
+** The contents of this file are subject to the Mozilla Public
+** License Version 1.1 (the "License"); you may not use this file
+** except in compliance with the License. You may obtain a copy of
+** the License at http://www.mozilla.org/MPL/
+**
+** Software distributed under the License is distributed on an "AS
+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+** implied. See the License for the specific language governing
+** rights and limitations under the License.
+**
+** Alternatively, the contents of this file may be used under the
+** terms of the GNU Public License version 2 (the "GPL"), in which
+** case the provisions of the GPL are applicable instead of the
+** above.  If you wish to allow the use of your version of this file
+** only under the terms of the GPL and not to allow others to use
+** your version of this file under the MPL, indicate your decision
+** by deleting the provisions above and replace them with the notice
+** and other provisions required by the GPL.  If you do not delete
+** the provisions above, a recipient may use your version of this
+** file under either the MPL or the GPL.
+** ---------------------------------------------------------------------
+** Inquiries regarding the ACX100 Open Source Project can be
+** made directly to:
+**
+** acx100-users@lists.sf.net
+** http://acx100.sf.net
+** ---------------------------------------------------------------------
+*/
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+//#include <asm/uaccess.h> /* required for 2.4.x kernels; verify_write() */
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+
+#include "acx.h"
+
+
+/***********************************************************************
+*/
+
+/* channel frequencies
+ * TODO: Currently, every other 802.11 driver keeps its own copy of this. In
+ * the long run this should be integrated into ieee802_11.h or wireless.h or
+ * whatever IEEE802.11x framework evolves */
+static const u16 acx_channel_freq[] = {
+	2412, 2417, 2422, 2427, 2432, 2437, 2442,
+	2447, 2452, 2457, 2462, 2467, 2472, 2484,
+};
+
+
+/***********************************************************************
+** acx_ioctl_commit
+*/
+static int
+acx_ioctl_commit(struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+
+	FN_ENTER;
+
+	acx_sem_lock(adev);
+	if (ACX_STATE_IFACE_UP & adev->dev_state_mask)
+		acx_s_update_card_settings(adev);
+	acx_sem_unlock(adev);
+
+	FN_EXIT0;
+	return OK;
+}
+
+
+/***********************************************************************
+*/
+static int
+acx_ioctl_get_name(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	static const char * const names[] = { "IEEE 802.11b+/g+", "IEEE 802.11b+" };
+
+	strcpy(wrqu->name, names[IS_ACX111(adev) ? 0 : 1]);
+
+	return OK;
+}
+
+
+/***********************************************************************
+** acx_ioctl_set_freq
+*/
+static int
+acx_ioctl_set_freq(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	int channel = -1;
+	unsigned int mult = 1;
+	int result;
+
+	FN_ENTER;
+
+	if (wrqu->freq.e == 0 && wrqu->freq.m <= 1000) {
+		/* Setting by channel number */
+		channel = wrqu->freq.m;
+	} else {
+		/* If setting by frequency, convert to a channel */
+		int i;
+
+		for (i = 0; i < (6 - wrqu->freq.e); i++)
+			mult *= 10;
+
+		for (i = 1; i <= 14; i++)
+			if (wrqu->freq.m == acx_channel_freq[i - 1] * mult)
+				channel = i;
+	}
+
+	if (channel > 14) {
+		result = -EINVAL;
+		goto end;
+	}
+
+	acx_sem_lock(adev);
+
+	adev->channel = channel;
+	/* hmm, the following code part is strange, but this is how
+	 * it was being done before... */
+	log(L_IOCTL, "Changing to channel %d\n", channel);
+	SET_BIT(adev->set_mask, GETSET_CHANNEL);
+
+	result = -EINPROGRESS; /* need to call commit handler */
+
+	acx_sem_unlock(adev);
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+*/
+static inline int
+acx_ioctl_get_freq(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	wrqu->freq.e = 0;
+	wrqu->freq.m = adev->channel;
+	return OK;
+}
+
+
+/***********************************************************************
+** acx_ioctl_set_mode
+*/
+static int
+acx_ioctl_set_mode(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	int result;
+
+	FN_ENTER;
+
+	acx_sem_lock(adev);
+
+	switch (wrqu->mode) {
+	case IW_MODE_AUTO:
+		adev->mode = ACX_MODE_OFF;
+		break;
+	case IW_MODE_MONITOR:
+		adev->mode = ACX_MODE_MONITOR;
+		break;
+	case IW_MODE_ADHOC:
+		adev->mode = ACX_MODE_0_ADHOC;
+		break;
+	case IW_MODE_INFRA:
+		adev->mode = ACX_MODE_2_STA;
+		break;
+	case IW_MODE_MASTER:
+		printk("acx: master mode (HostAP) is very, very "
+			"experimental! It might work partially, but "
+			"better get prepared for nasty surprises "
+			"at any time\n");
+		adev->mode = ACX_MODE_3_AP;
+		break;
+	case IW_MODE_REPEAT:
+	case IW_MODE_SECOND:
+	default:
+		result = -EOPNOTSUPP;
+		goto end_unlock;
+	}
+
+	log(L_ASSOC, "new adev->mode=%d\n", adev->mode);
+	SET_BIT(adev->set_mask, GETSET_MODE);
+	result = -EINPROGRESS;
+
+end_unlock:
+	acx_sem_unlock(adev);
+
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+*/
+static int
+acx_ioctl_get_mode(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	int result = 0;
+
+	switch (adev->mode) {
+	case ACX_MODE_OFF:
+		wrqu->mode = IW_MODE_AUTO; break;
+	case ACX_MODE_MONITOR:
+		wrqu->mode = IW_MODE_MONITOR; break;
+	case ACX_MODE_0_ADHOC:
+		wrqu->mode = IW_MODE_ADHOC; break;
+	case ACX_MODE_2_STA:
+		wrqu->mode = IW_MODE_INFRA; break;
+	case ACX_MODE_3_AP:
+		wrqu->mode = IW_MODE_MASTER; break;
+	default:
+		result = -EOPNOTSUPP;
+	}
+	return result;
+}
+
+
+/***********************************************************************
+*/
+static int
+acx_ioctl_set_sens(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_param *vwrq = &wrqu->sens;
+	acx_device_t *adev = ndev2adev(ndev);
+
+	acx_sem_lock(adev);
+
+	adev->sensitivity = (1 == vwrq->disabled) ? 0 : vwrq->value;
+	SET_BIT(adev->set_mask, GETSET_SENSITIVITY);
+
+	acx_sem_unlock(adev);
+
+	return -EINPROGRESS;
+}
+
+
+/***********************************************************************
+*/
+static int
+acx_ioctl_get_sens(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_param *vwrq = &wrqu->sens;
+	acx_device_t *adev = ndev2adev(ndev);
+
+	if (IS_USB(adev))
+		/* setting the PHY reg via fw cmd doesn't work yet */
+		return -EOPNOTSUPP;
+
+	/* acx_sem_lock(adev); */
+
+	vwrq->value = adev->sensitivity;
+	vwrq->disabled = (vwrq->value == 0);
+	vwrq->fixed = 1;
+
+	/* acx_sem_unlock(adev); */
+
+	return OK;
+}
+
+
+/***********************************************************************
+** acx_ioctl_set_ap
+**
+** Sets the MAC address of the AP to associate with
+*/
+static int
+acx_ioctl_set_ap(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct sockaddr *awrq = &wrqu->ap_addr;
+	acx_device_t *adev = ndev2adev(ndev);
+	int result = 0;
+	const u8 *ap;
+
+	FN_ENTER;
+	if (NULL == awrq) {
+		result = -EFAULT;
+		goto end;
+	}
+	if (ARPHRD_ETHER != awrq->sa_family) {
+		result = -EINVAL;
+		goto end;
+	}
+
+	ap = awrq->sa_data;
+	acxlog_mac(L_IOCTL, "set AP=", ap, "\n");
+
+	MAC_COPY(adev->ap, ap);
+
+	/* We want to start rescan in managed or ad-hoc mode,
+	** otherwise just set adev->ap.
+	** "iwconfig <if> ap <mac> mode managed": we must be able
+	** to set ap _first_ and _then_ set mode */
+	switch (adev->mode) {
+	case ACX_MODE_0_ADHOC:
+	case ACX_MODE_2_STA:
+		/* FIXME: if there is a convention on what zero AP means,
+		** please add a comment about that. I don't know of any --vda */
+		if (mac_is_zero(ap)) {
+			/* "off" == 00:00:00:00:00:00 */
+			MAC_BCAST(adev->ap);
+			log(L_IOCTL, "Not reassociating\n");
+		} else {
+			log(L_IOCTL, "Forcing reassociation\n");
+			SET_BIT(adev->set_mask, GETSET_RESCAN);
+		}
+		break;
+	}
+	result = -EINPROGRESS;
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+*/
+static int
+acx_ioctl_get_ap(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct sockaddr *awrq = &wrqu->ap_addr;
+	acx_device_t *adev = ndev2adev(ndev);
+
+	if (ACX_STATUS_4_ASSOCIATED == adev->status) {
+		/* as seen in Aironet driver, airo.c */
+		MAC_COPY(awrq->sa_data, adev->bssid);
+	} else {
+		MAC_ZERO(awrq->sa_data);
+	}
+	awrq->sa_family = ARPHRD_ETHER;
+	return OK;
+}
+
+
+/***********************************************************************
+** acx_ioctl_get_aplist
+**
+** Deprecated in favor of iwscan.
+** We simply return the list of currently available stations in range,
+** don't do a new scan.
+*/
+static int
+acx_ioctl_get_aplist(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_point *dwrq = &wrqu->data;
+	acx_device_t *adev = ndev2adev(ndev);
+	struct sockaddr *address = (struct sockaddr *) extra;
+	struct iw_quality qual[IW_MAX_AP];
+	int i, cur;
+	int result = OK;
+
+	FN_ENTER;
+
+	/* we have AP list only in STA mode */
+	if (ACX_MODE_2_STA != adev->mode) {
+		result = -EOPNOTSUPP;
+		goto end;
+	}
+
+	cur = 0;
+	for (i = 0; i < VEC_SIZE(adev->sta_list); i++) {
+		struct client *bss = &adev->sta_list[i];
+		if (!bss->used) continue;
+		MAC_COPY(address[cur].sa_data, bss->bssid);
+		address[cur].sa_family = ARPHRD_ETHER;
+		qual[cur].level = bss->sir;
+		qual[cur].noise = bss->snr;
+#ifndef OLD_QUALITY
+		qual[cur].qual = acx_signal_determine_quality(qual[cur].level,
+						    qual[cur].noise);
+#else
+		qual[cur].qual = (qual[cur].noise <= 100) ?
+			       100 - qual[cur].noise : 0;
+#endif
+		/* no scan: level/noise/qual not updated: */
+		qual[cur].updated = 0;
+		cur++;
+	}
+	if (cur) {
+		dwrq->flags = 1;
+		memcpy(extra + sizeof(struct sockaddr)*cur, &qual,
+				sizeof(struct iw_quality)*cur);
+	}
+	dwrq->length = cur;
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+*/
+static int
+acx_ioctl_set_scan(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	int result;
+
+	FN_ENTER;
+
+	acx_sem_lock(adev);
+
+	/* don't start scan if device is not up yet */
+	if (!(adev->dev_state_mask & ACX_STATE_IFACE_UP)) {
+		result = -EAGAIN;
+		goto end_unlock;
+	}
+
+	/* This is NOT a rescan for new AP!
+	** Do not use SET_BIT(GETSET_RESCAN); */
+	acx_s_cmd_start_scan(adev);
+	result = OK;
+
+end_unlock:
+	acx_sem_unlock(adev);
+/* end: */
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_s_scan_add_station
+*/
+/* helper. not sure whether it's really a _s_leeping fn */
+static char*
+acx_s_scan_add_station(
+	acx_device_t *adev,
+	char *ptr,
+	char *end_buf,
+	struct client *bss)
+{
+	struct iw_event iwe;
+	char *ptr_rate;
+
+	FN_ENTER;
+
+	/* MAC address has to be added first */
+	iwe.cmd = SIOCGIWAP;
+	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+	MAC_COPY(iwe.u.ap_addr.sa_data, bss->bssid);
+	acxlog_mac(L_IOCTL, "scan, station address: ", bss->bssid, "\n");
+	ptr = iwe_stream_add_event(ptr, end_buf, &iwe, IW_EV_ADDR_LEN);
+
+	/* Add ESSID */
+	iwe.cmd = SIOCGIWESSID;
+	iwe.u.data.length = bss->essid_len;
+	iwe.u.data.flags = 1;
+	log(L_IOCTL, "scan, essid: %s\n", bss->essid);
+	ptr = iwe_stream_add_point(ptr, end_buf, &iwe, bss->essid);
+
+	/* Add mode */
+	iwe.cmd = SIOCGIWMODE;
+	if (bss->cap_info & (WF_MGMT_CAP_ESS | WF_MGMT_CAP_IBSS)) {
+		if (bss->cap_info & WF_MGMT_CAP_ESS)
+			iwe.u.mode = IW_MODE_MASTER;
+		else
+			iwe.u.mode = IW_MODE_ADHOC;
+		log(L_IOCTL, "scan, mode: %d\n", iwe.u.mode);
+		ptr = iwe_stream_add_event(ptr, end_buf, &iwe, IW_EV_UINT_LEN);
+	}
+
+	/* Add frequency */
+	iwe.cmd = SIOCGIWFREQ;
+	iwe.u.freq.m = acx_channel_freq[bss->channel - 1] * 100000;
+	iwe.u.freq.e = 1;
+	log(L_IOCTL, "scan, frequency: %d\n", iwe.u.freq.m);
+	ptr = iwe_stream_add_event(ptr, end_buf, &iwe, IW_EV_FREQ_LEN);
+
+	/* Add link quality */
+	iwe.cmd = IWEVQUAL;
+	/* FIXME: these values should be expressed in dBm, but we don't know
+	 * how to calibrate it yet */
+	iwe.u.qual.level = bss->sir;
+	iwe.u.qual.noise = bss->snr;
+#ifndef OLD_QUALITY
+	iwe.u.qual.qual = acx_signal_determine_quality(iwe.u.qual.level,
+							iwe.u.qual.noise);
+#else
+	iwe.u.qual.qual = (iwe.u.qual.noise <= 100) ?
+				100 - iwe.u.qual.noise : 0;
+#endif
+	iwe.u.qual.updated = 7;
+	log(L_IOCTL, "scan, link quality: %d/%d/%d\n",
+			iwe.u.qual.level, iwe.u.qual.noise, iwe.u.qual.qual);
+	ptr = iwe_stream_add_event(ptr, end_buf, &iwe, IW_EV_QUAL_LEN);
+
+	/* Add encryption */
+	iwe.cmd = SIOCGIWENCODE;
+	if (bss->cap_info & WF_MGMT_CAP_PRIVACY)
+		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+	else
+		iwe.u.data.flags = IW_ENCODE_DISABLED;
+	iwe.u.data.length = 0;
+	log(L_IOCTL, "scan, encryption flags: %X\n", iwe.u.data.flags);
+	ptr = iwe_stream_add_point(ptr, end_buf, &iwe, bss->essid);
+
+	/* add rates */
+	iwe.cmd = SIOCGIWRATE;
+	iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+	ptr_rate = ptr + IW_EV_LCP_LEN;
+
+	{
+	u16 rate = bss->rate_cap;
+	const u8* p = acx_bitpos2ratebyte;
+	while (rate) {
+		if (rate & 1) {
+			iwe.u.bitrate.value = *p * 500000; /* units of 500kb/s */
+			log(L_IOCTL, "scan, rate: %d\n", iwe.u.bitrate.value);
+			ptr = iwe_stream_add_value(ptr, ptr_rate, end_buf,
+						&iwe, IW_EV_PARAM_LEN);
+		}
+		rate >>= 1;
+		p++;
+	}}
+
+	if ((ptr_rate - ptr) > (ptrdiff_t)IW_EV_LCP_LEN)
+		ptr = ptr_rate;
+
+	/* drop remaining station data items for now */
+
+	FN_EXIT0;
+	return ptr;
+}
+
+
+/***********************************************************************
+ * acx_ioctl_get_scan
+ */
+static int
+acx_ioctl_get_scan(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_point *dwrq = &wrqu->data;
+	acx_device_t *adev = ndev2adev(ndev);
+	char *ptr = extra;
+	int i;
+	int result = OK;
+
+	FN_ENTER;
+
+	acx_sem_lock(adev);
+
+	/* no scan available if device is not up yet */
+	if (!(adev->dev_state_mask & ACX_STATE_IFACE_UP)) {
+		log(L_IOCTL, "iface not up yet\n");
+		result = -EAGAIN;
+		goto end_unlock;
+	}
+
+#ifdef ENODATA_TO_BE_USED_AFTER_SCAN_ERROR_ONLY
+	if (adev->bss_table_count == 0)	{
+		/* no stations found */
+		result = -ENODATA;
+		goto end_unlock;
+	}
+#endif
+
+	for (i = 0; i < VEC_SIZE(adev->sta_list); i++) {
+		struct client *bss = &adev->sta_list[i];
+		if (!bss->used) continue;
+		ptr = acx_s_scan_add_station(adev, ptr,
+			extra + IW_SCAN_MAX_DATA, bss);
+	}
+	dwrq->length = ptr - extra;
+	dwrq->flags = 0;
+
+end_unlock:
+	acx_sem_unlock(adev);
+/* end: */
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_ioctl_set_essid
+*/
+static int
+acx_ioctl_set_essid(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_point *dwrq = &wrqu->essid;
+	acx_device_t *adev = ndev2adev(ndev);
+	int len = dwrq->length;
+	int result;
+
+	FN_ENTER;
+
+	if (len < 0) {
+		result = -EINVAL;
+		goto end;
+	}
+
+	log(L_IOCTL, "set ESSID '%*s', length %d, flags 0x%04X\n",
+					len, extra, len, dwrq->flags);
+
+	acx_sem_lock(adev);
+
+	/* ESSID disabled? */
+	if (0 == dwrq->flags) {
+		adev->essid_active = 0;
+
+	} else {
+		if (dwrq->length > IW_ESSID_MAX_SIZE+1)	{
+			result = -E2BIG;
+			goto end_unlock;
+		}
+
+		if (len > sizeof(adev->essid))
+			len = sizeof(adev->essid);
+		memcpy(adev->essid, extra, len-1);
+		adev->essid[len-1] = '\0';
+		/* Paranoia: just in case there is a '\0'... */
+		adev->essid_len = strlen(adev->essid);
+		adev->essid_active = 1;
+	}
+
+	SET_BIT(adev->set_mask, GETSET_RESCAN);
+
+	result = -EINPROGRESS;
+
+end_unlock:
+	acx_sem_unlock(adev);
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+*/
+static int
+acx_ioctl_get_essid(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_point *dwrq = &wrqu->essid;
+	acx_device_t *adev = ndev2adev(ndev);
+
+	dwrq->flags = adev->essid_active;
+	if (adev->essid_active)	{
+		memcpy(extra, adev->essid, adev->essid_len);
+		extra[adev->essid_len] = '\0';
+		dwrq->length = adev->essid_len + 1;
+		dwrq->flags = 1;
+	}
+	return OK;
+}
+
+
+/***********************************************************************
+** acx_l_update_client_rates
+*/
+static void
+acx_l_update_client_rates(acx_device_t *adev, u16 rate)
+{
+	int i;
+	for (i = 0; i < VEC_SIZE(adev->sta_list); i++) {
+		client_t *clt = &adev->sta_list[i];
+		if (!clt->used)	continue;
+		clt->rate_cfg = (clt->rate_cap & rate);
+		if (!clt->rate_cfg) {
+			/* no compatible rates left: kick client */
+			acxlog_mac(L_ASSOC, "client ",clt->address," kicked: "
+				"rates are not compatible anymore\n");
+			acx_l_sta_list_del(adev, clt);
+			continue;
+		}
+		clt->rate_cur &= clt->rate_cfg;
+		if (!clt->rate_cur) {
+			/* current rate become invalid, choose a valid one */
+			clt->rate_cur = 1 << lowest_bit(clt->rate_cfg);
+		}
+		if (IS_ACX100(adev))
+			clt->rate_100 = acx_bitpos2rate100[highest_bit(clt->rate_cur)];
+		clt->fallback_count = clt->stepup_count = 0;
+		clt->ignore_count = 16;
+	}
+	switch (adev->mode) {
+	case ACX_MODE_2_STA:
+		if (adev->ap_client && !adev->ap_client->used) {
+			/* Owwww... we kicked our AP!! :) */
+			SET_BIT(adev->set_mask, GETSET_RESCAN);
+		}
+	}
+}
+
+
+/***********************************************************************
+*/
+/* maps bits from acx111 rate to rate in Mbits */
+static const unsigned int
+acx111_rate_tbl[] = {
+     1000000, /* 0 */
+     2000000, /* 1 */
+     5500000, /* 2 */
+     6000000, /* 3 */
+     9000000, /* 4 */
+    11000000, /* 5 */
+    12000000, /* 6 */
+    18000000, /* 7 */
+    22000000, /* 8 */
+    24000000, /* 9 */
+    36000000, /* 10 */
+    48000000, /* 11 */
+    54000000, /* 12 */
+      500000, /* 13, should not happen */
+      500000, /* 14, should not happen */
+      500000, /* 15, should not happen */
+};
+
+/***********************************************************************
+ * acx_ioctl_set_rate
+ */
+static int
+acx_ioctl_set_rate(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_param *vwrq = &wrqu->param;
+	acx_device_t *adev = ndev2adev(ndev);
+	u16 txrate_cfg = 1;
+	unsigned long flags;
+	int autorate;
+	int result = -EINVAL;
+
+	FN_ENTER;
+	log(L_IOCTL, "rate %d fixed 0x%X disabled 0x%X flags 0x%X\n",
+		vwrq->value, vwrq->fixed, vwrq->disabled, vwrq->flags);
+
+	if ((0 == vwrq->fixed) || (1 == vwrq->fixed)) {
+		int i = VEC_SIZE(acx111_rate_tbl)-1;
+		if (vwrq->value == -1)
+			/* "iwconfig rate auto" --> choose highest */
+			vwrq->value = IS_ACX100(adev) ?	22000000 : 54000000;
+		while (i >= 0) {
+			if (vwrq->value == acx111_rate_tbl[i]) {
+				txrate_cfg <<= i;
+				i = 0;
+				break;
+			}
+			i--;
+		}
+		if (i == -1) { /* no matching rate */
+			result = -EINVAL;
+			goto end;
+		}
+	} else {	/* rate N, N<1000 (driver specific): we don't use this */
+		result = -EOPNOTSUPP;
+		goto end;
+	}
+	/* now: only one bit is set in txrate_cfg, corresponding to
+	** indicated rate */
+
+	autorate = (vwrq->fixed == 0) && (RATE111_1 != txrate_cfg);
+	if (autorate) {
+		/* convert 00100000 -> 00111111 */
+		txrate_cfg = (txrate_cfg<<1)-1;
+	}
+
+	if (IS_ACX100(adev)) {
+		txrate_cfg &= RATE111_ACX100_COMPAT;
+		if (!txrate_cfg) {
+			result = -ENOTSUPP; /* rate is not supported by acx100 */
+			goto end;
+		}
+	}
+
+	acx_sem_lock(adev);
+	acx_lock(adev, flags);
+
+	adev->rate_auto = autorate;
+	adev->rate_oper = txrate_cfg;
+	adev->rate_basic = txrate_cfg;
+	/* only do that in auto mode, non-auto will be able to use
+	 * one specific Tx rate only anyway */
+	if (autorate) {
+		/* only use 802.11b base rates, for standard 802.11b H/W
+		 * compatibility */
+		adev->rate_basic &= RATE111_80211B_COMPAT;
+	}
+	adev->rate_bcast = 1 << lowest_bit(txrate_cfg);
+	if (IS_ACX100(adev))
+		adev->rate_bcast100 = acx_rate111to100(adev->rate_bcast);
+	acx_l_update_ratevector(adev);
+	acx_l_update_client_rates(adev, txrate_cfg);
+
+	/* Do/don't do tx rate fallback; beacon contents and rate */
+	SET_BIT(adev->set_mask, SET_RATE_FALLBACK|SET_TEMPLATES);
+	result = -EINPROGRESS;
+
+	acx_unlock(adev, flags);
+	acx_sem_unlock(adev);
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_ioctl_get_rate
+*/
+static int
+acx_ioctl_get_rate(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_param *vwrq = &wrqu->param;
+	acx_device_t *adev = ndev2adev(ndev);
+	unsigned long flags;
+	u16 rate;
+
+	acx_lock(adev, flags);
+	rate = adev->rate_oper;
+	if (adev->ap_client)
+		rate = adev->ap_client->rate_cur;
+	vwrq->value = acx111_rate_tbl[highest_bit(rate)];
+	vwrq->fixed = !adev->rate_auto;
+	vwrq->disabled = 0;
+	acx_unlock(adev, flags);
+
+	return OK;
+}
+
+static int
+acx_ioctl_set_rts(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_param *vwrq = &wrqu->rts;
+	acx_device_t *adev = ndev2adev(ndev);
+	int val = vwrq->value;
+
+	if (vwrq->disabled)
+		val = 2312;
+	if ((val < 0) || (val > 2312))
+		return -EINVAL;
+
+	adev->rts_threshold = val;
+	return OK;
+}
+
+static inline int
+acx_ioctl_get_rts(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_param *vwrq = &wrqu->rts;
+	acx_device_t *adev = ndev2adev(ndev);
+
+	vwrq->value = adev->rts_threshold;
+	vwrq->disabled = (vwrq->value >= 2312);
+	vwrq->fixed = 1;
+	return OK;
+}
+
+
+#if ACX_FRAGMENTATION
+static int
+acx_ioctl_set_frag(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	struct iw_param *vwrq,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	int val = vwrq->value;
+
+	if (vwrq->disabled)
+		val = 32767;
+	else
+	if ((val < 256) || (val > 2347))
+		return -EINVAL;
+
+	adev->frag_threshold = val;
+	return OK;
+}
+
+static inline int
+acx_ioctl_get_frag(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_param *vwrq = &wrqu->frag;
+	acx_device_t *adev = ndev2adev(ndev);
+
+	vwrq->value = adev->frag_threshold;
+	vwrq->disabled = (vwrq->value >= 2347);
+	vwrq->fixed = 1;
+	return OK;
+}
+#endif
+
+
+/***********************************************************************
+** acx_ioctl_set_encode
+*/
+static int
+acx_ioctl_set_encode(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_point *dwrq = &wrqu->encoding;
+	acx_device_t *adev = ndev2adev(ndev);
+	int index;
+	int result;
+
+	FN_ENTER;
+
+	log(L_IOCTL, "set encoding flags=0x%04X, size=%d, key: %s\n",
+			dwrq->flags, dwrq->length, extra ? "set" : "No key");
+
+	acx_sem_lock(adev);
+
+	index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+
+	if (dwrq->length > 0) {
+		/* if index is 0 or invalid, use default key */
+		if ((index < 0) || (index > 3))
+			index = (int)adev->wep_current_index;
+
+		if (0 == (dwrq->flags & IW_ENCODE_NOKEY)) {
+			if (dwrq->length > 29)
+				dwrq->length = 29; /* restrict it */
+
+			if (dwrq->length > 13) {
+				/* 29*8 == 232, WEP256 */
+				adev->wep_keys[index].size = 29;
+			} else if (dwrq->length > 5) {
+				/* 13*8 == 104bit, WEP128 */
+				adev->wep_keys[index].size = 13;
+			} else if (dwrq->length > 0) {
+				/* 5*8 == 40bit, WEP64 */
+				adev->wep_keys[index].size = 5;
+			} else {
+				/* disable key */
+				adev->wep_keys[index].size = 0;
+			}
+
+			memset(adev->wep_keys[index].key, 0,
+				sizeof(adev->wep_keys[index].key));
+			memcpy(adev->wep_keys[index].key, extra, dwrq->length);
+		}
+	} else {
+		/* set transmit key */
+		if ((index >= 0) && (index <= 3))
+			adev->wep_current_index = index;
+		else if (0 == (dwrq->flags & IW_ENCODE_MODE)) {
+			/* complain if we were not just setting
+			 * the key mode */
+			result = -EINVAL;
+			goto end_unlock;
+		}
+	}
+
+	adev->wep_enabled = !(dwrq->flags & IW_ENCODE_DISABLED);
+
+	if (dwrq->flags & IW_ENCODE_OPEN) {
+		adev->auth_alg = WLAN_AUTH_ALG_OPENSYSTEM;
+		adev->wep_restricted = 0;
+
+	} else if (dwrq->flags & IW_ENCODE_RESTRICTED) {
+		adev->auth_alg = WLAN_AUTH_ALG_SHAREDKEY;
+		adev->wep_restricted = 1;
+	}
+
+	/* set flag to make sure the card WEP settings get updated */
+	SET_BIT(adev->set_mask, GETSET_WEP);
+
+	log(L_IOCTL, "len=%d, key at 0x%p, flags=0x%X\n",
+		dwrq->length, extra, dwrq->flags);
+
+	for (index = 0; index <= 3; index++) {
+		if (adev->wep_keys[index].size) {
+			log(L_IOCTL,	"index=%d, size=%d, key at 0x%p\n",
+				adev->wep_keys[index].index,
+				(int) adev->wep_keys[index].size,
+				adev->wep_keys[index].key);
+		}
+	}
+	result = -EINPROGRESS;
+
+end_unlock:
+	acx_sem_unlock(adev);
+
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_ioctl_get_encode
+*/
+static int
+acx_ioctl_get_encode(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_point *dwrq = &wrqu->encoding;
+	acx_device_t *adev = ndev2adev(ndev);
+	int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+
+	FN_ENTER;
+
+	if (adev->wep_enabled == 0) {
+		dwrq->flags = IW_ENCODE_DISABLED;
+	} else {
+		if ((index < 0) || (index > 3))
+			index = (int)adev->wep_current_index;
+
+		dwrq->flags = (adev->wep_restricted == 1) ?
+				IW_ENCODE_RESTRICTED : IW_ENCODE_OPEN;
+		dwrq->length = adev->wep_keys[index].size;
+
+		memcpy(extra, adev->wep_keys[index].key,
+			      adev->wep_keys[index].size);
+	}
+
+	/* set the current index */
+	SET_BIT(dwrq->flags, index + 1);
+
+	log(L_IOCTL, "len=%d, key=%p, flags=0x%X\n",
+	       dwrq->length, dwrq->pointer,
+	       dwrq->flags);
+
+	FN_EXIT1(OK);
+	return OK;
+}
+
+
+/***********************************************************************
+*/
+static int
+acx_ioctl_set_power(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_param *vwrq = &wrqu->power;
+	acx_device_t *adev = ndev2adev(ndev);
+	int result = -EINPROGRESS;
+
+	FN_ENTER;
+
+	log(L_IOCTL, "set 802.11 powersave flags=0x%04X\n", vwrq->flags);
+
+	acx_sem_lock(adev);
+
+	if (vwrq->disabled) {
+		CLEAR_BIT(adev->ps_wakeup_cfg, PS_CFG_ENABLE);
+		SET_BIT(adev->set_mask, GETSET_POWER_80211);
+		goto end;
+	}
+	if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+		u16 ps_timeout = (vwrq->value * 1024) / 1000;
+
+		if (ps_timeout > 255)
+			ps_timeout = 255;
+		log(L_IOCTL, "setting PS timeout value to %d time units "
+				"due to %dus\n", ps_timeout, vwrq->value);
+		adev->ps_hangover_period = ps_timeout;
+	} else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
+		u16 ps_periods = vwrq->value / 1000000;
+
+		if (ps_periods > 255)
+			ps_periods = 255;
+		log(L_IOCTL, "setting PS period value to %d periods "
+				"due to %dus\n", ps_periods, vwrq->value);
+		adev->ps_listen_interval = ps_periods;
+		CLEAR_BIT(adev->ps_wakeup_cfg, PS_CFG_WAKEUP_MODE_MASK);
+		SET_BIT(adev->ps_wakeup_cfg, PS_CFG_WAKEUP_EACH_ITVL);
+	}
+
+	switch (vwrq->flags & IW_POWER_MODE) {
+		/* FIXME: are we doing the right thing here? */
+		case IW_POWER_UNICAST_R:
+			CLEAR_BIT(adev->ps_options, PS_OPT_STILL_RCV_BCASTS);
+			break;
+		case IW_POWER_MULTICAST_R:
+			SET_BIT(adev->ps_options, PS_OPT_STILL_RCV_BCASTS);
+			break;
+		case IW_POWER_ALL_R:
+			SET_BIT(adev->ps_options, PS_OPT_STILL_RCV_BCASTS);
+			break;
+		case IW_POWER_ON:
+			break;
+		default:
+			log(L_IOCTL, "unknown PS mode\n");
+			result = -EINVAL;
+			goto end;
+	}
+
+	SET_BIT(adev->ps_wakeup_cfg, PS_CFG_ENABLE);
+	SET_BIT(adev->set_mask, GETSET_POWER_80211);
+end:
+	acx_sem_unlock(adev);
+
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+*/
+static int
+acx_ioctl_get_power(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_param *vwrq = &wrqu->power;
+	acx_device_t *adev = ndev2adev(ndev);
+
+	FN_ENTER;
+
+	log(L_IOCTL, "Get 802.11 Power Save flags = 0x%04X\n", vwrq->flags);
+	vwrq->disabled = ((adev->ps_wakeup_cfg & PS_CFG_ENABLE) == 0);
+	if (vwrq->disabled)
+		goto end;
+
+	if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+		vwrq->value = adev->ps_hangover_period * 1000 / 1024;
+		vwrq->flags = IW_POWER_TIMEOUT;
+	} else {
+		vwrq->value = adev->ps_listen_interval * 1000000;
+		vwrq->flags = IW_POWER_PERIOD|IW_POWER_RELATIVE;
+	}
+	if (adev->ps_options & PS_OPT_STILL_RCV_BCASTS)
+		SET_BIT(vwrq->flags, IW_POWER_ALL_R);
+	else
+		SET_BIT(vwrq->flags, IW_POWER_UNICAST_R);
+end:
+	FN_EXIT1(OK);
+	return OK;
+}
+
+
+/***********************************************************************
+** acx_ioctl_get_txpow
+*/
+static inline int
+acx_ioctl_get_txpow(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_param *vwrq = &wrqu->power;
+	acx_device_t *adev = ndev2adev(ndev);
+
+	FN_ENTER;
+
+	vwrq->flags = IW_TXPOW_DBM;
+	vwrq->disabled = 0;
+	vwrq->fixed = 1;
+	vwrq->value = adev->tx_level_dbm;
+
+	log(L_IOCTL, "get txpower:%d dBm\n", adev->tx_level_dbm);
+
+	FN_EXIT1(OK);
+	return OK;
+}
+
+
+/***********************************************************************
+** acx_ioctl_set_txpow
+*/
+static int
+acx_ioctl_set_txpow(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_param *vwrq = &wrqu->power;
+	acx_device_t *adev = ndev2adev(ndev);
+	int result;
+
+	FN_ENTER;
+
+	log(L_IOCTL, "set txpower:%d, disabled:%d, flags:0x%04X\n",
+			vwrq->value, vwrq->disabled, vwrq->flags);
+
+	acx_sem_lock(adev);
+
+	if (vwrq->disabled != adev->tx_disabled) {
+		SET_BIT(adev->set_mask, GETSET_TX);
+	}
+
+	adev->tx_disabled = vwrq->disabled;
+	if (vwrq->value == -1) {
+		if (vwrq->disabled) {
+			adev->tx_level_dbm = 0;
+			log(L_IOCTL, "disable radio tx\n");
+		} else {
+			/* adev->tx_level_auto = 1; */
+			log(L_IOCTL, "set tx power auto (NIY)\n");
+		}
+	} else {
+		adev->tx_level_dbm = vwrq->value <= 20 ? vwrq->value : 20;
+		/* adev->tx_level_auto = 0; */
+		log(L_IOCTL, "set txpower=%d dBm\n", adev->tx_level_dbm);
+	}
+	SET_BIT(adev->set_mask, GETSET_TXPOWER);
+
+	result = -EINPROGRESS;
+
+	acx_sem_unlock(adev);
+
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_ioctl_get_range
+*/
+static int
+acx_ioctl_get_range(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_point *dwrq = &wrqu->data;
+	struct iw_range *range = (struct iw_range *)extra;
+	acx_device_t *adev = ndev2adev(ndev);
+	int i,n;
+
+	FN_ENTER;
+
+	if (!dwrq->pointer)
+		goto end;
+
+	dwrq->length = sizeof(struct iw_range);
+	memset(range, 0, sizeof(struct iw_range));
+	n = 0;
+	for (i = 1; i <= 14; i++) {
+		if (adev->reg_dom_chanmask & (1 << (i - 1))) {
+			range->freq[n].i = i;
+			range->freq[n].m = acx_channel_freq[i - 1] * 100000;
+			range->freq[n].e = 1; /* units are MHz */
+			n++;
+		}
+	}
+	range->num_channels = n;
+	range->num_frequency = n;
+
+	range->min_rts = 0;
+	range->max_rts = 2312;
+
+#if ACX_FRAGMENTATION
+	range->min_frag = 256;
+	range->max_frag = 2312;
+#endif
+
+	range->encoding_size[0] = 5;
+	range->encoding_size[1] = 13;
+	range->encoding_size[2] = 29;
+	range->num_encoding_sizes = 3;
+	range->max_encoding_tokens = 4;
+
+	range->min_pmp = 0;
+	range->max_pmp = 5000000;
+	range->min_pmt = 0;
+	range->max_pmt = 65535 * 1000;
+	range->pmp_flags = IW_POWER_PERIOD;
+	range->pmt_flags = IW_POWER_TIMEOUT;
+	range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
+
+	if (IS_ACX100(adev)) { /* ACX100 has direct radio programming - arbitrary levels, so offer a lot */
+		for (i = 0; i <= IW_MAX_TXPOWER - 1; i++)
+			range->txpower[i] = 20 * i / (IW_MAX_TXPOWER - 1);
+		range->num_txpower = IW_MAX_TXPOWER;
+		range->txpower_capa = IW_TXPOW_DBM;
+	}
+	else {
+		int count = min(IW_MAX_TXPOWER, (int)adev->cfgopt_power_levels.len);
+		for (i = 0; i <= count; i++)
+			range->txpower[i] = adev->cfgopt_power_levels.list[i];
+		range->num_txpower = count;
+		/* this list is given in mW */
+		range->txpower_capa = IW_TXPOW_MWATT;
+	}
+
+	range->we_version_compiled = WIRELESS_EXT;
+	range->we_version_source = 0x9;
+
+	range->retry_capa = IW_RETRY_LIMIT;
+	range->retry_flags = IW_RETRY_LIMIT;
+	range->min_retry = 1;
+	range->max_retry = 255;
+
+	range->r_time_flags = IW_RETRY_LIFETIME;
+	range->min_r_time = 0;
+	/* FIXME: lifetime ranges and orders of magnitude are strange?? */
+	range->max_r_time = 65535;
+
+	if (IS_USB(adev))
+		range->sensitivity = 0;
+	else if (IS_ACX111(adev))
+		range->sensitivity = 3;
+	else
+		range->sensitivity = 255;
+
+	for (i=0; i < adev->rate_supported_len; i++) {
+		range->bitrate[i] = (adev->rate_supported[i] & ~0x80) * 500000;
+		/* never happens, but keep it, to be safe: */
+		if (range->bitrate[i] == 0)
+			break;
+	}
+	range->num_bitrates = i;
+
+	range->max_qual.qual = 100;
+	range->max_qual.level = 100;
+	range->max_qual.noise = 100;
+	/* TODO: better values */
+	range->avg_qual.qual = 90;
+	range->avg_qual.level = 80;
+	range->avg_qual.noise = 2;
+
+end:
+	FN_EXIT1(OK);
+	return OK;
+}
+
+
+/***********************************************************************
+** Private functions
+*/
+
+/***********************************************************************
+** acx_ioctl_get_nick
+*/
+static inline int
+acx_ioctl_get_nick(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_point *dwrq = &wrqu->data;
+	acx_device_t *adev = ndev2adev(ndev);
+
+	strcpy(extra, adev->nick);
+	dwrq->length = strlen(extra) + 1;
+
+	return OK;
+}
+
+
+/***********************************************************************
+** acx_ioctl_set_nick
+*/
+static int
+acx_ioctl_set_nick(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_point *dwrq = &wrqu->data;
+	acx_device_t *adev = ndev2adev(ndev);
+	int result;
+
+	FN_ENTER;
+
+	acx_sem_lock(adev);
+
+	if (dwrq->length > IW_ESSID_MAX_SIZE + 1) {
+		result = -E2BIG;
+		goto end_unlock;
+	}
+
+	/* extra includes trailing \0, so it's ok */
+	strcpy(adev->nick, extra);
+	result = OK;
+
+end_unlock:
+	acx_sem_unlock(adev);
+
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_ioctl_get_retry
+*/
+static int
+acx_ioctl_get_retry(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_param *vwrq = &wrqu->retry;
+	acx_device_t *adev = ndev2adev(ndev);
+	unsigned int type = vwrq->flags & IW_RETRY_TYPE;
+	unsigned int modifier = vwrq->flags & IW_RETRY_MODIFIER;
+	int result;
+
+	FN_ENTER;
+
+	acx_sem_lock(adev);
+
+	/* return the short retry number by default */
+	if (type == IW_RETRY_LIFETIME) {
+		vwrq->flags = IW_RETRY_LIFETIME;
+		vwrq->value = adev->msdu_lifetime;
+	} else if (modifier == IW_RETRY_MAX) {
+		vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+		vwrq->value = adev->long_retry;
+	} else {
+		vwrq->flags = IW_RETRY_LIMIT;
+		if (adev->long_retry != adev->short_retry)
+			SET_BIT(vwrq->flags, IW_RETRY_MIN);
+		vwrq->value = adev->short_retry;
+	}
+
+	/* can't be disabled */
+	vwrq->disabled = (u8)0;
+	result = OK;
+
+	acx_sem_unlock(adev);
+
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_ioctl_set_retry
+*/
+static int
+acx_ioctl_set_retry(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_param *vwrq = &wrqu->retry;
+	acx_device_t *adev = ndev2adev(ndev);
+	int result;
+
+	FN_ENTER;
+
+	if (!vwrq) {
+		result = -EFAULT;
+		goto end;
+	}
+	if (vwrq->disabled) {
+		result = -EINVAL;
+		goto end;
+	}
+
+	acx_sem_lock(adev);
+
+	result = -EINVAL;
+	if (IW_RETRY_LIMIT == (vwrq->flags & IW_RETRY_TYPE)) {
+		printk("old retry limits: short %d long %d\n",
+				adev->short_retry, adev->long_retry);
+		if (vwrq->flags & IW_RETRY_MAX) {
+			adev->long_retry = vwrq->value;
+		} else if (vwrq->flags & IW_RETRY_MIN) {
+			adev->short_retry = vwrq->value;
+		} else {
+			/* no modifier: set both */
+			adev->long_retry = vwrq->value;
+			adev->short_retry = vwrq->value;
+		}
+		printk("new retry limits: short %d long %d\n",
+				adev->short_retry, adev->long_retry);
+		SET_BIT(adev->set_mask, GETSET_RETRY);
+		result = -EINPROGRESS;
+	}
+	else if (vwrq->flags & IW_RETRY_LIFETIME) {
+		adev->msdu_lifetime = vwrq->value;
+		printk("new MSDU lifetime: %d\n", adev->msdu_lifetime);
+		SET_BIT(adev->set_mask, SET_MSDU_LIFETIME);
+		result = -EINPROGRESS;
+	}
+
+	acx_sem_unlock(adev);
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/************************ private ioctls ******************************/
+
+
+/***********************************************************************
+** acx_ioctl_set_debug
+*/
+#if ACX_DEBUG
+static int
+acx_ioctl_set_debug(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	unsigned int debug_new = *((unsigned int *)extra);
+	int result = -EINVAL;
+
+	log(L_ANY, "setting debug from %04X to %04X\n", acx_debug, debug_new);
+	acx_debug = debug_new;
+
+	result = OK;
+	return result;
+
+}
+#endif
+
+
+/***********************************************************************
+** acx_ioctl_list_reg_domain
+*/
+static int
+acx_ioctl_list_reg_domain(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	int i = 1;
+	const char * const *entry = acx_reg_domain_strings;
+
+	printk("dom# chan# domain/country\n");
+	while (*entry)
+		printk("%4d %s\n", i++, *entry++);
+	return OK;
+}
+
+
+/***********************************************************************
+** acx_ioctl_set_reg_domain
+*/
+static int
+acx_ioctl_set_reg_domain(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	int result;
+
+	FN_ENTER;
+
+	if ((*extra < 1) || ((size_t)*extra > acx_reg_domain_ids_len)) {
+		result = -EINVAL;
+		goto end;
+	}
+
+	acx_sem_lock(adev);
+
+	adev->reg_dom_id = acx_reg_domain_ids[*extra - 1];
+	SET_BIT(adev->set_mask, GETSET_REG_DOMAIN);
+
+	result = -EINPROGRESS;
+
+	acx_sem_unlock(adev);
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_ioctl_get_reg_domain
+*/
+static int
+acx_ioctl_get_reg_domain(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	int dom,i;
+
+	/* no locking */
+	dom = adev->reg_dom_id;
+
+	for (i = 1; i <= acx_reg_domain_ids_len; i++) {
+		if (acx_reg_domain_ids[i-1] == dom) {
+			log(L_IOCTL, "regulatory domain is currently set "
+				"to %d (0x%X): %s\n", i, dom,
+				acx_reg_domain_strings[i-1]);
+			*extra = i;
+			break;
+		}
+	}
+
+	return OK;
+}
+
+
+/***********************************************************************
+** acx_ioctl_set_short_preamble
+*/
+static const char * const
+preamble_modes[] = {
+	"off",
+	"on",
+	"auto (peer capability dependent)",
+	"unknown mode, error"
+};
+
+static int
+acx_ioctl_set_short_preamble(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	int i;
+	int result;
+
+	FN_ENTER;
+
+	if ((unsigned char)*extra > 2) {
+		result = -EINVAL;
+		goto end;
+	}
+
+	acx_sem_lock(adev);
+
+	adev->preamble_mode = (u8)*extra;
+	switch (adev->preamble_mode) {
+	case 0: /* long */
+		adev->preamble_cur = 0;
+		break;
+	case 1:
+		/* short, kick incapable peers */
+		adev->preamble_cur = 1;
+		for (i = 0; i < VEC_SIZE(adev->sta_list); i++) {
+			client_t *clt = &adev->sta_list[i];
+			if (!clt->used) continue;
+			if (!(clt->cap_info & WF_MGMT_CAP_SHORT)) {
+				clt->used = CLIENT_EMPTY_SLOT_0;
+			}
+		}
+		switch (adev->mode) {
+		case ACX_MODE_2_STA:
+			if (adev->ap_client && !adev->ap_client->used) {
+				/* We kicked our AP :) */
+				SET_BIT(adev->set_mask, GETSET_RESCAN);
+			}
+		}
+		break;
+	case 2: /* auto. short only if all peers are short-capable */
+		adev->preamble_cur = 1;
+		for (i = 0; i < VEC_SIZE(adev->sta_list); i++) {
+			client_t *clt = &adev->sta_list[i];
+			if (!clt->used) continue;
+			if (!(clt->cap_info & WF_MGMT_CAP_SHORT)) {
+				adev->preamble_cur = 0;
+				break;
+			}
+		}
+		break;
+	}
+	printk("new short preamble setting: configured %s, active %s\n",
+			preamble_modes[adev->preamble_mode],
+			preamble_modes[adev->preamble_cur]);
+	result = OK;
+
+	acx_sem_unlock(adev);
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_ioctl_get_short_preamble
+*/
+static int
+acx_ioctl_get_short_preamble(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+
+	acx_sem_lock(adev);
+
+	printk("current short preamble setting: configured %s, active %s\n",
+			preamble_modes[adev->preamble_mode],
+			preamble_modes[adev->preamble_cur]);
+
+	*extra = (char)adev->preamble_mode;
+
+	acx_sem_unlock(adev);
+
+	return OK;
+}
+
+
+/***********************************************************************
+** acx_ioctl_set_antenna
+**
+** TX and RX antenna can be set separately but this function good
+** for testing 0-4 bits
+*/
+static int
+acx_ioctl_set_antenna(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+
+	acx_sem_lock(adev);
+
+	printk("old antenna value: 0x%02X (COMBINED bit mask)\n"
+		     "Rx antenna selection:\n"
+		     "0x00 ant. 1\n"
+		     "0x40 ant. 2\n"
+		     "0x80 full diversity\n"
+		     "0xc0 partial diversity\n"
+		     "0x0f dwell time mask (in units of us)\n"
+		     "Tx antenna selection:\n"
+		     "0x00 ant. 2\n" /* yep, those ARE reversed! */
+		     "0x20 ant. 1\n"
+		     "new antenna value: 0x%02X\n",
+		     adev->antenna, (u8)*extra);
+
+	adev->antenna = (u8)*extra;
+	SET_BIT(adev->set_mask, GETSET_ANTENNA);
+
+	acx_sem_unlock(adev);
+
+	return -EINPROGRESS;
+}
+
+
+/***********************************************************************
+** acx_ioctl_get_antenna
+*/
+static int
+acx_ioctl_get_antenna(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+
+	/* no locking. it's pointless to lock a single load */
+	printk("current antenna value: 0x%02X (COMBINED bit mask)\n"
+		     "Rx antenna selection:\n"
+		     "0x00 ant. 1\n"
+		     "0x40 ant. 2\n"
+		     "0x80 full diversity\n"
+		     "0xc0 partial diversity\n"
+		     "Tx antenna selection:\n"
+		     "0x00 ant. 2\n" /* yep, those ARE reversed! */
+		     "0x20 ant. 1\n", adev->antenna);
+
+	return 0;
+}
+
+
+/***********************************************************************
+** acx_ioctl_set_rx_antenna
+**
+** 0 = antenna1; 1 = antenna2; 2 = full diversity; 3 = partial diversity
+** Could anybody test which antenna is the external one?
+*/
+static int
+acx_ioctl_set_rx_antenna(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	int result;
+
+	FN_ENTER;
+
+	if (*extra > 3) {
+		result = -EINVAL;
+		goto end;
+	}
+
+	printk("old antenna value: 0x%02X\n", adev->antenna);
+
+	acx_sem_lock(adev);
+
+	adev->antenna &= 0x3f;
+	SET_BIT(adev->antenna, (*extra << 6));
+	SET_BIT(adev->set_mask, GETSET_ANTENNA);
+	printk("new antenna value: 0x%02X\n", adev->antenna);
+	result = -EINPROGRESS;
+
+	acx_sem_unlock(adev);
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_ioctl_set_tx_antenna
+**
+** Arguments: 0 == antenna2; 1 == antenna1;
+** Could anybody test which antenna is the external one?
+*/
+static int
+acx_ioctl_set_tx_antenna(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	int result;
+
+	FN_ENTER;
+
+	if (*extra > 1) {
+		result = -EINVAL;
+		goto end;
+	}
+
+	printk("old antenna value: 0x%02X\n", adev->antenna);
+
+	acx_sem_lock(adev);
+
+	adev->antenna &= ~0x30;
+	SET_BIT(adev->antenna, ((*extra & 0x01) << 5));
+	SET_BIT(adev->set_mask, GETSET_ANTENNA);
+	printk("new antenna value: 0x%02X\n", adev->antenna);
+	result = -EINPROGRESS;
+
+	acx_sem_unlock(adev);
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_ioctl_wlansniff
+**
+** can we just remove this in favor of monitor mode? --vda
+*/
+static int
+acx_ioctl_wlansniff(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	unsigned int *params = (unsigned int*)extra;
+	unsigned int enable = (unsigned int)(params[0] > 0);
+	int result;
+
+	FN_ENTER;
+
+	acx_sem_lock(adev);
+
+	/* not using printk() here, since it distorts kismet display
+	 * when printk messages activated */
+	log(L_IOCTL, "setting monitor to: 0x%02X\n", params[0]);
+
+	switch (params[0]) {
+	case 0:
+		/* no monitor mode. hmm, should we simply ignore it
+		 * or go back to enabling adev->netdev->type ARPHRD_ETHER? */
+		break;
+	case 1:
+		adev->monitor_type = ARPHRD_IEEE80211_PRISM;
+		break;
+	case 2:
+		adev->monitor_type = ARPHRD_IEEE80211;
+		break;
+	}
+
+	if (params[0]) {
+		adev->mode = ACX_MODE_MONITOR;
+		SET_BIT(adev->set_mask, GETSET_MODE);
+	}
+
+	if (enable) {
+		adev->channel = params[1];
+		SET_BIT(adev->set_mask, GETSET_RX);
+	}
+	result = -EINPROGRESS;
+
+	acx_sem_unlock(adev);
+
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_ioctl_unknown11
+** FIXME: looks like some sort of "iwpriv kick_sta MAC" but it's broken
+*/
+static int
+acx_ioctl_unknown11(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+#ifdef BROKEN
+	struct iw_param *vwrq = &wrqu->param;
+	acx_device_t *adev = ndev2adev(ndev);
+	unsigned long flags;
+	client_t client;
+	int result;
+
+	acx_sem_lock(adev);
+	acx_lock(adev, flags);
+
+	acx_l_transmit_disassoc(adev, &client);
+	result = OK;
+
+	acx_unlock(adev, flags);
+	acx_sem_unlock(adev);
+
+	return result;
+#endif
+	return -EINVAL;
+}
+
+
+/***********************************************************************
+** debug helper function to be able to debug various issues relatively easily
+*/
+static int
+acx_ioctl_dbg_set_masks(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	const unsigned int *params = (unsigned int*)extra;
+	int result;
+
+	acx_sem_lock(adev);
+
+	log(L_IOCTL, "setting flags in settings mask: "
+			"get_mask %08X set_mask %08X\n"
+			"before: get_mask %08X set_mask %08X\n",
+			params[0], params[1],
+			adev->get_mask, adev->set_mask);
+	SET_BIT(adev->get_mask, params[0]);
+	SET_BIT(adev->set_mask, params[1]);
+	log(L_IOCTL, "after: get_mask %08X set_mask %08X\n",
+			adev->get_mask, adev->set_mask);
+	result = -EINPROGRESS; /* immediately call commit handler */
+
+	acx_sem_unlock(adev);
+
+	return result;
+}
+
+
+/***********************************************************************
+* acx_ioctl_set_rates
+*
+* This ioctl takes string parameter. Examples:
+* iwpriv wlan0 SetRates "1,2"
+*	use 1 and 2 Mbit rates, both are in basic rate set
+* iwpriv wlan0 SetRates "1,2 5,11"
+*	use 1,2,5.5,11 Mbit rates. 1 and 2 are basic
+* iwpriv wlan0 SetRates "1,2 5c,11c"
+*	same ('c' means 'CCK modulation' and it is a default for 5 and 11)
+* iwpriv wlan0 SetRates "1,2 5p,11p"
+*	use 1,2,5.5,11 Mbit, 1,2 are basic. 5 and 11 are using PBCC
+* iwpriv wlan0 SetRates "1,2,5,11 22p"
+*	use 1,2,5.5,11,22 Mbit. 1,2,5.5 and 11 are basic. 22 is using PBCC
+*	(this is the maximum acx100 can do (modulo x4 mode))
+* iwpriv wlan0 SetRates "1,2,5,11 22"
+*	same. 802.11 defines only PBCC modulation
+*	for 22 and 33 Mbit rates, so there is no ambiguity
+* iwpriv wlan0 SetRates "1,2,5,11 6o,9o,12o,18o,24o,36o,48o,54o"
+*	1,2,5.5 and 11 are basic. 11g OFDM rates are enabled but
+*	they are not in basic rate set.	22 Mbit is disabled.
+* iwpriv wlan0 SetRates "1,2,5,11 6,9,12,18,24,36,48,54"
+*	same. OFDM is default for 11g rates except 22 and 33 Mbit,
+*	thus 'o' is optional
+* iwpriv wlan0 SetRates "1,2,5,11 6d,9d,12d,18d,24d,36d,48d,54d"
+*	1,2,5.5 and 11 are basic. 11g CCK-OFDM rates are enabled
+*	(acx111 does not support CCK-OFDM, driver will reject this cmd)
+* iwpriv wlan0 SetRates "6,9,12 18,24,36,48,54"
+*	6,9,12 are basic, rest of 11g rates is enabled. Using OFDM
+*/
+#include "setrate.c"
+
+/* disallow: 33Mbit (unsupported by hw) */
+/* disallow: CCKOFDM (unsupported by hw) */
+static int
+acx111_supported(int mbit, int modulation, void *opaque)
+{
+	if (mbit==33) return -ENOTSUPP;
+	if (modulation==DOT11_MOD_CCKOFDM) return -ENOTSUPP;
+	return OK;
+}
+
+static const u16
+acx111mask[] = {
+	[DOT11_RATE_1 ] = RATE111_1 ,
+	[DOT11_RATE_2 ] = RATE111_2 ,
+	[DOT11_RATE_5 ] = RATE111_5 ,
+	[DOT11_RATE_11] = RATE111_11,
+	[DOT11_RATE_22] = RATE111_22,
+	/* [DOT11_RATE_33] = */
+	[DOT11_RATE_6 ] = RATE111_6 ,
+	[DOT11_RATE_9 ] = RATE111_9 ,
+	[DOT11_RATE_12] = RATE111_12,
+	[DOT11_RATE_18] = RATE111_18,
+	[DOT11_RATE_24] = RATE111_24,
+	[DOT11_RATE_36] = RATE111_36,
+	[DOT11_RATE_48] = RATE111_48,
+	[DOT11_RATE_54] = RATE111_54,
+};
+
+static u32
+acx111_gen_mask(int mbit, int modulation, void *opaque)
+{
+	/* lower 16 bits show selected 1, 2, CCK and OFDM rates */
+	/* upper 16 bits show selected PBCC rates */
+	u32 m = acx111mask[rate_mbit2enum(mbit)];
+	if (modulation==DOT11_MOD_PBCC)
+		return m<<16;
+	return m;
+}
+
+static int
+verify_rate(u32 rate, int chip_type)
+{
+	/* never happens. be paranoid */
+	if (!rate) return -EINVAL;
+
+	/* disallow: mixing PBCC and CCK at 5 and 11Mbit
+	** (can be supported, but needs complicated handling in tx code) */
+	if (( rate & ((RATE111_11+RATE111_5)<<16) )
+	&&  ( rate & (RATE111_11+RATE111_5) )
+	) {
+		return -ENOTSUPP;
+	}
+	if (CHIPTYPE_ACX100 == chip_type) {
+		if ( rate & ~(RATE111_ACX100_COMPAT+(RATE111_ACX100_COMPAT<<16)) )
+			return -ENOTSUPP;
+	}
+	return 0;
+}
+
+static int
+acx_ioctl_set_rates(struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	unsigned long flags;
+	int result;
+	u32 brate = 0, orate = 0; /* basic, operational rate set */
+
+	FN_ENTER;
+
+	log(L_IOCTL, "set_rates %s\n", extra);
+	result = fill_ratemasks(extra, &brate, &orate,
+				acx111_supported, acx111_gen_mask, 0);
+	if (result) goto end;
+	SET_BIT(orate, brate);
+	log(L_IOCTL, "brate %08X orate %08X\n", brate, orate);
+
+	result = verify_rate(brate, adev->chip_type);
+	if (result) goto end;
+	result = verify_rate(orate, adev->chip_type);
+	if (result) goto end;
+
+	acx_sem_lock(adev);
+	acx_lock(adev, flags);
+
+	adev->rate_basic = brate;
+	adev->rate_oper = orate;
+	/* TODO: ideally, we shall monitor highest basic rate
+	** which was successfully sent to every peer
+	** (say, last we checked, everybody could hear 5.5 Mbits)
+	** and use that for bcasts when we want to reach all peers.
+	** For beacons, we probably shall use lowest basic rate
+	** because we want to reach all *potential* new peers too */
+	adev->rate_bcast = 1 << lowest_bit(brate);
+	if (IS_ACX100(adev))
+		adev->rate_bcast100 = acx_rate111to100(adev->rate_bcast);
+	adev->rate_auto = !has_only_one_bit(orate);
+	acx_l_update_client_rates(adev, orate);
+	/* TODO: get rid of ratevector, build it only when needed */
+	acx_l_update_ratevector(adev);
+
+	/* Do/don't do tx rate fallback; beacon contents and rate */
+	SET_BIT(adev->set_mask, SET_RATE_FALLBACK|SET_TEMPLATES);
+	result = -EINPROGRESS;
+
+	acx_unlock(adev, flags);
+	acx_sem_unlock(adev);
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acx_ioctl_get_phy_chan_busy_percentage
+*/
+static int
+acx_ioctl_get_phy_chan_busy_percentage(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	struct { /* added ACX_PACKED, not tested --vda */
+		u16 type ACX_PACKED;
+		u16 len ACX_PACKED;
+		u32 busytime ACX_PACKED;
+		u32 totaltime ACX_PACKED;
+	} usage;
+	int result;
+
+	acx_sem_lock(adev);
+
+	if (OK != acx_s_interrogate(adev, &usage, ACX1xx_IE_MEDIUM_USAGE)) {
+		result = NOT_OK;
+		goto end_unlock;
+	}
+
+	usage.busytime = le32_to_cpu(usage.busytime);
+	usage.totaltime = le32_to_cpu(usage.totaltime);
+	printk("%s: average busy percentage since last invocation: %d%% "
+		"(%u of %u microseconds)\n",
+		ndev->name,
+		usage.busytime / ((usage.totaltime / 100) + 1),
+		usage.busytime, usage.totaltime);
+
+	result = OK;
+
+end_unlock:
+	acx_sem_unlock(adev);
+
+	return result;
+}
+
+
+/***********************************************************************
+** acx_ioctl_set_ed_threshold
+*/
+static inline int
+acx_ioctl_set_ed_threshold(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+
+	acx_sem_lock(adev);
+
+	printk("old ED threshold value: %d\n", adev->ed_threshold);
+	adev->ed_threshold = (unsigned char)*extra;
+	printk("new ED threshold value: %d\n", (unsigned char)*extra);
+	SET_BIT(adev->set_mask, GETSET_ED_THRESH);
+
+	acx_sem_unlock(adev);
+
+	return -EINPROGRESS;
+}
+
+
+/***********************************************************************
+** acx_ioctl_set_cca
+*/
+static inline int
+acx_ioctl_set_cca(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	int result;
+
+	acx_sem_lock(adev);
+
+	printk("old CCA value: 0x%02X\n", adev->cca);
+	adev->cca = (unsigned char)*extra;
+	printk("new CCA value: 0x%02X\n", (unsigned char)*extra);
+	SET_BIT(adev->set_mask, GETSET_CCA);
+	result = -EINPROGRESS;
+
+	acx_sem_unlock(adev);
+
+	return result;
+}
+
+
+/***********************************************************************
+*/
+static const char * const
+scan_modes[] = { "active", "passive", "background" };
+
+static void
+acx_print_scan_params(acx_device_t *adev, const char* head)
+{
+	printk("%s: %smode %d (%s), min chan time %dTU, "
+		"max chan time %dTU, max scan rate byte: %d\n",
+		adev->ndev->name, head,
+		adev->scan_mode, scan_modes[adev->scan_mode],
+		adev->scan_probe_delay, adev->scan_duration, adev->scan_rate);
+}
+
+static int
+acx_ioctl_set_scan_params(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	int result;
+	const int *params = (int *)extra;
+
+	acx_sem_lock(adev);
+
+	acx_print_scan_params(adev, "old scan parameters: ");
+	if ((params[0] != -1) && (params[0] >= 0) && (params[0] <= 2))
+		adev->scan_mode = params[0];
+	if (params[1] != -1)
+		adev->scan_probe_delay = params[1];
+	if (params[2] != -1)
+		adev->scan_duration = params[2];
+	if ((params[3] != -1) && (params[3] <= 255))
+		adev->scan_rate = params[3];
+	acx_print_scan_params(adev, "new scan parameters: ");
+	SET_BIT(adev->set_mask, GETSET_RESCAN);
+	result = -EINPROGRESS;
+
+	acx_sem_unlock(adev);
+
+	return result;
+}
+
+static int
+acx_ioctl_get_scan_params(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	int result;
+	int *params = (int *)extra;
+
+	acx_sem_lock(adev);
+
+	acx_print_scan_params(adev, "current scan parameters: ");
+	params[0] = adev->scan_mode;
+	params[1] = adev->scan_probe_delay;
+	params[2] = adev->scan_duration;
+	params[3] = adev->scan_rate;
+	result = OK;
+
+	acx_sem_unlock(adev);
+
+	return result;
+}
+
+
+/***********************************************************************
+*/
+static int
+acx100_ioctl_set_led_power(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	static const char * const led_modes[] = { "off", "on", "LinkQuality" };
+
+	acx_device_t *adev = ndev2adev(ndev);
+	int result;
+
+	acx_sem_lock(adev);
+
+	printk("%s: power LED status: old %d (%s), ",
+			ndev->name,
+			adev->led_power,
+			led_modes[adev->led_power]);
+	adev->led_power = extra[0];
+	if (adev->led_power > 2) adev->led_power = 2;
+	printk("new %d (%s)\n",
+			adev->led_power,
+			led_modes[adev->led_power]);
+
+	if (adev->led_power == 2) {
+		printk("%s: max link quality setting: old %d, ",
+			ndev->name, adev->brange_max_quality);
+		if (extra[1])
+			adev->brange_max_quality = extra[1];
+		printk("new %d\n", adev->brange_max_quality);
+	}
+
+	SET_BIT(adev->set_mask, GETSET_LED_POWER);
+
+	result = -EINPROGRESS;
+
+	acx_sem_unlock(adev);
+
+	return result;
+}
+
+
+/***********************************************************************
+*/
+static inline int
+acx100_ioctl_get_led_power(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+
+	acx_sem_lock(adev);
+
+	extra[0] = adev->led_power;
+	if (adev->led_power == 2)
+		extra[1] = adev->brange_max_quality;
+	else
+		extra[1] = -1;
+
+	acx_sem_unlock(adev);
+
+	return OK;
+}
+
+
+/***********************************************************************
+*/
+static int
+acx111_ioctl_info(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_param *vwrq = &wrqu->param;
+	if (!IS_PCI(ndev2adev(ndev)))
+		return OK;
+	return acx111pci_ioctl_info(ndev, info, vwrq, extra);
+}
+
+
+/***********************************************************************
+*/
+static int
+acx100_ioctl_set_phy_amp_bias(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu,
+	char *extra)
+{
+	struct iw_param *vwrq = &wrqu->param;
+	if (!IS_PCI(ndev2adev(ndev))) {
+		printk("acx: set_phy_amp_bias() is not supported on USB\n");
+		return OK;
+	}
+	return acx100pci_ioctl_set_phy_amp_bias(ndev, info, vwrq, extra);
+}
+
+
+/***********************************************************************
+*/
+static const iw_handler acx_ioctl_handler[] =
+{
+	acx_ioctl_commit,		/* SIOCSIWCOMMIT */
+	acx_ioctl_get_name,		/* SIOCGIWNAME */
+	NULL,				/* SIOCSIWNWID */
+	NULL,				/* SIOCGIWNWID */
+	acx_ioctl_set_freq,		/* SIOCSIWFREQ */
+	acx_ioctl_get_freq,		/* SIOCGIWFREQ */
+	acx_ioctl_set_mode,		/* SIOCSIWMODE */
+	acx_ioctl_get_mode,		/* SIOCGIWMODE */
+	acx_ioctl_set_sens,		/* SIOCSIWSENS */
+	acx_ioctl_get_sens,		/* SIOCGIWSENS */
+	NULL,				/* SIOCSIWRANGE */
+	acx_ioctl_get_range,		/* SIOCGIWRANGE */
+	NULL,				/* SIOCSIWPRIV */
+	NULL,				/* SIOCGIWPRIV */
+	NULL,				/* SIOCSIWSTATS */
+	NULL,				/* SIOCGIWSTATS */
+#if IW_HANDLER_VERSION > 4
+	iw_handler_set_spy,		/* SIOCSIWSPY */
+	iw_handler_get_spy,		/* SIOCGIWSPY */
+	iw_handler_set_thrspy,		/* SIOCSIWTHRSPY */
+	iw_handler_get_thrspy,		/* SIOCGIWTHRSPY */
+#else /* IW_HANDLER_VERSION > 4 */
+#ifdef WIRELESS_SPY
+	NULL /* acx_ioctl_set_spy FIXME */,	/* SIOCSIWSPY */
+	NULL /* acx_ioctl_get_spy */,	/* SIOCGIWSPY */
+#else /* WSPY */
+	NULL,				/* SIOCSIWSPY */
+	NULL,				/* SIOCGIWSPY */
+#endif /* WSPY */
+	NULL,				/* [nothing] */
+	NULL,				/* [nothing] */
+#endif /* IW_HANDLER_VERSION > 4 */
+	acx_ioctl_set_ap,		/* SIOCSIWAP */
+	acx_ioctl_get_ap,		/* SIOCGIWAP */
+	NULL,				/* [nothing] */
+	acx_ioctl_get_aplist,		/* SIOCGIWAPLIST */
+	acx_ioctl_set_scan,		/* SIOCSIWSCAN */
+	acx_ioctl_get_scan,		/* SIOCGIWSCAN */
+	acx_ioctl_set_essid,		/* SIOCSIWESSID */
+	acx_ioctl_get_essid,		/* SIOCGIWESSID */
+	acx_ioctl_set_nick,		/* SIOCSIWNICKN */
+	acx_ioctl_get_nick,		/* SIOCGIWNICKN */
+	NULL,				/* [nothing] */
+	NULL,				/* [nothing] */
+	acx_ioctl_set_rate,		/* SIOCSIWRATE */
+	acx_ioctl_get_rate,		/* SIOCGIWRATE */
+	acx_ioctl_set_rts,		/* SIOCSIWRTS */
+	acx_ioctl_get_rts,		/* SIOCGIWRTS */
+#if ACX_FRAGMENTATION
+	acx_ioctl_set_frag,		/* SIOCSIWFRAG */
+	acx_ioctl_get_frag,		/* SIOCGIWFRAG */
+#else
+	NULL,				/* SIOCSIWFRAG */
+	NULL,				/* SIOCGIWFRAG */
+#endif
+	acx_ioctl_set_txpow,		/* SIOCSIWTXPOW */
+	acx_ioctl_get_txpow,		/* SIOCGIWTXPOW */
+	acx_ioctl_set_retry,		/* SIOCSIWRETRY */
+	acx_ioctl_get_retry,		/* SIOCGIWRETRY */
+	acx_ioctl_set_encode,		/* SIOCSIWENCODE */
+	acx_ioctl_get_encode,		/* SIOCGIWENCODE */
+	acx_ioctl_set_power,		/* SIOCSIWPOWER */
+	acx_ioctl_get_power,		/* SIOCGIWPOWER */
+};
+
+
+/***********************************************************************
+*/
+
+/* if you plan to reorder something, make sure to reorder all other places
+ * accordingly! */
+/* SET/GET convention: SETs must have even position, GETs odd */
+#define ACX100_IOCTL SIOCIWFIRSTPRIV
+enum {
+	ACX100_IOCTL_DEBUG = ACX100_IOCTL,
+	ACX100_IOCTL_GET__________UNUSED1,
+	ACX100_IOCTL_SET_PLED,
+	ACX100_IOCTL_GET_PLED,
+	ACX100_IOCTL_SET_RATES,
+	ACX100_IOCTL_LIST_DOM,
+	ACX100_IOCTL_SET_DOM,
+	ACX100_IOCTL_GET_DOM,
+	ACX100_IOCTL_SET_SCAN_PARAMS,
+	ACX100_IOCTL_GET_SCAN_PARAMS,
+	ACX100_IOCTL_SET_PREAMB,
+	ACX100_IOCTL_GET_PREAMB,
+	ACX100_IOCTL_SET_ANT,
+	ACX100_IOCTL_GET_ANT,
+	ACX100_IOCTL_RX_ANT,
+	ACX100_IOCTL_TX_ANT,
+	ACX100_IOCTL_SET_PHY_AMP_BIAS,
+	ACX100_IOCTL_GET_PHY_CHAN_BUSY,
+	ACX100_IOCTL_SET_ED,
+	ACX100_IOCTL_GET__________UNUSED3,
+	ACX100_IOCTL_SET_CCA,
+	ACX100_IOCTL_GET__________UNUSED4,
+	ACX100_IOCTL_MONITOR,
+	ACX100_IOCTL_TEST,
+	ACX100_IOCTL_DBG_SET_MASKS,
+	ACX111_IOCTL_INFO,
+	ACX100_IOCTL_DBG_SET_IO,
+	ACX100_IOCTL_DBG_GET_IO
+};
+
+
+static const iw_handler acx_ioctl_private_handler[] =
+{
+#if ACX_DEBUG
+[ACX100_IOCTL_DEBUG		- ACX100_IOCTL] = acx_ioctl_set_debug,
+#endif
+[ACX100_IOCTL_SET_PLED		- ACX100_IOCTL] = acx100_ioctl_set_led_power,
+[ACX100_IOCTL_GET_PLED		- ACX100_IOCTL] = acx100_ioctl_get_led_power,
+[ACX100_IOCTL_SET_RATES		- ACX100_IOCTL] = acx_ioctl_set_rates,
+[ACX100_IOCTL_LIST_DOM		- ACX100_IOCTL] = acx_ioctl_list_reg_domain,
+[ACX100_IOCTL_SET_DOM		- ACX100_IOCTL] = acx_ioctl_set_reg_domain,
+[ACX100_IOCTL_GET_DOM		- ACX100_IOCTL] = acx_ioctl_get_reg_domain,
+[ACX100_IOCTL_SET_SCAN_PARAMS	- ACX100_IOCTL] = acx_ioctl_set_scan_params,
+[ACX100_IOCTL_GET_SCAN_PARAMS	- ACX100_IOCTL] = acx_ioctl_get_scan_params,
+[ACX100_IOCTL_SET_PREAMB	- ACX100_IOCTL] = acx_ioctl_set_short_preamble,
+[ACX100_IOCTL_GET_PREAMB	- ACX100_IOCTL] = acx_ioctl_get_short_preamble,
+[ACX100_IOCTL_SET_ANT		- ACX100_IOCTL] = acx_ioctl_set_antenna,
+[ACX100_IOCTL_GET_ANT		- ACX100_IOCTL] = acx_ioctl_get_antenna,
+[ACX100_IOCTL_RX_ANT		- ACX100_IOCTL] = acx_ioctl_set_rx_antenna,
+[ACX100_IOCTL_TX_ANT		- ACX100_IOCTL] = acx_ioctl_set_tx_antenna,
+[ACX100_IOCTL_SET_PHY_AMP_BIAS	- ACX100_IOCTL] = acx100_ioctl_set_phy_amp_bias,
+[ACX100_IOCTL_GET_PHY_CHAN_BUSY	- ACX100_IOCTL] = acx_ioctl_get_phy_chan_busy_percentage,
+[ACX100_IOCTL_SET_ED		- ACX100_IOCTL] = acx_ioctl_set_ed_threshold,
+[ACX100_IOCTL_SET_CCA		- ACX100_IOCTL] = acx_ioctl_set_cca,
+[ACX100_IOCTL_MONITOR		- ACX100_IOCTL] = acx_ioctl_wlansniff,
+[ACX100_IOCTL_TEST		- ACX100_IOCTL] = acx_ioctl_unknown11,
+[ACX100_IOCTL_DBG_SET_MASKS	- ACX100_IOCTL] = acx_ioctl_dbg_set_masks,
+[ACX111_IOCTL_INFO		- ACX100_IOCTL] = acx111_ioctl_info,
+};
+
+
+static const struct iw_priv_args acx_ioctl_private_args[] = {
+#if ACX_DEBUG
+{ cmd : ACX100_IOCTL_DEBUG,
+	set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	get_args : 0,
+	name : "SetDebug" },
+#endif
+{ cmd : ACX100_IOCTL_SET_PLED,
+	set_args : IW_PRIV_TYPE_BYTE | 2,
+	get_args : 0,
+	name : "SetLEDPower" },
+{ cmd : ACX100_IOCTL_GET_PLED,
+	set_args : 0,
+	get_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 2,
+	name : "GetLEDPower" },
+{ cmd : ACX100_IOCTL_SET_RATES,
+	set_args : IW_PRIV_TYPE_CHAR | 256,
+	get_args : 0,
+	name : "SetRates" },
+{ cmd : ACX100_IOCTL_LIST_DOM,
+	set_args : 0,
+	get_args : 0,
+	name : "ListRegDomain" },
+{ cmd : ACX100_IOCTL_SET_DOM,
+	set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+	get_args : 0,
+	name : "SetRegDomain" },
+{ cmd : ACX100_IOCTL_GET_DOM,
+	set_args : 0,
+	get_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+	name : "GetRegDomain" },
+{ cmd : ACX100_IOCTL_SET_SCAN_PARAMS,
+	set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 4,
+	get_args : 0,
+	name : "SetScanParams" },
+{ cmd : ACX100_IOCTL_GET_SCAN_PARAMS,
+	set_args : 0,
+	get_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 4,
+	name : "GetScanParams" },
+{ cmd : ACX100_IOCTL_SET_PREAMB,
+	set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+	get_args : 0,
+	name : "SetSPreamble" },
+{ cmd : ACX100_IOCTL_GET_PREAMB,
+	set_args : 0,
+	get_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+	name : "GetSPreamble" },
+{ cmd : ACX100_IOCTL_SET_ANT,
+	set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+	get_args : 0,
+	name : "SetAntenna" },
+{ cmd : ACX100_IOCTL_GET_ANT,
+	set_args : 0,
+	get_args : 0,
+	name : "GetAntenna" },
+{ cmd : ACX100_IOCTL_RX_ANT,
+	set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+	get_args : 0,
+	name : "SetRxAnt" },
+{ cmd : ACX100_IOCTL_TX_ANT,
+	set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+	get_args : 0,
+	name : "SetTxAnt" },
+{ cmd : ACX100_IOCTL_SET_PHY_AMP_BIAS,
+	set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+	get_args : 0,
+	name : "SetPhyAmpBias"},
+{ cmd : ACX100_IOCTL_GET_PHY_CHAN_BUSY,
+	set_args : 0,
+	get_args : 0,
+	name : "GetPhyChanBusy" },
+{ cmd : ACX100_IOCTL_SET_ED,
+	set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	get_args : 0,
+	name : "SetED" },
+{ cmd : ACX100_IOCTL_SET_CCA,
+	set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+	get_args : 0,
+	name : "SetCCA" },
+{ cmd : ACX100_IOCTL_MONITOR,
+	set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2,
+	get_args : 0,
+	name : "monitor" },
+{ cmd : ACX100_IOCTL_TEST,
+	set_args : 0,
+	get_args : 0,
+	name : "Test" },
+{ cmd : ACX100_IOCTL_DBG_SET_MASKS,
+	set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2,
+	get_args : 0,
+	name : "DbgSetMasks" },
+{ cmd : ACX111_IOCTL_INFO,
+	set_args : 0,
+	get_args : 0,
+	name : "GetAcx111Info" },
+{ cmd : ACX100_IOCTL_DBG_SET_IO,
+	set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 4,
+	get_args : 0,
+	name : "DbgSetIO" },
+{ cmd : ACX100_IOCTL_DBG_GET_IO,
+	set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3,
+	get_args : 0,
+	name : "DbgGetIO" },
+};
+
+
+const struct iw_handler_def acx_ioctl_handler_def =
+{
+	.num_standard = VEC_SIZE(acx_ioctl_handler),
+	.num_private = VEC_SIZE(acx_ioctl_private_handler),
+	.num_private_args = VEC_SIZE(acx_ioctl_private_args),
+	.standard = (iw_handler *) acx_ioctl_handler,
+	.private = (iw_handler *) acx_ioctl_private_handler,
+	.private_args = (struct iw_priv_args *) acx_ioctl_private_args,
+#if IW_HANDLER_VERSION > 5
+	.get_wireless_stats = acx_e_get_wireless_stats
+#endif /* IW > 5 */
+};
diff -urN oldtree/drivers/net/wireless/tiacx/pci.c newtree/drivers/net/wireless/tiacx/pci.c
--- oldtree/drivers/net/wireless/tiacx/pci.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/net/wireless/tiacx/pci.c	2006-02-21 15:58:22.572714984 +0000
@@ -0,0 +1,4276 @@
+/***********************************************************************
+** Copyright (C) 2003  ACX100 Open Source Project
+**
+** The contents of this file are subject to the Mozilla Public
+** License Version 1.1 (the "License"); you may not use this file
+** except in compliance with the License. You may obtain a copy of
+** the License at http://www.mozilla.org/MPL/
+**
+** Software distributed under the License is distributed on an "AS
+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+** implied. See the License for the specific language governing
+** rights and limitations under the License.
+**
+** Alternatively, the contents of this file may be used under the
+** terms of the GNU Public License version 2 (the "GPL"), in which
+** case the provisions of the GPL are applicable instead of the
+** above.  If you wish to allow the use of your version of this file
+** only under the terms of the GPL and not to allow others to use
+** your version of this file under the MPL, indicate your decision
+** by deleting the provisions above and replace them with the notice
+** and other provisions required by the GPL.  If you do not delete
+** the provisions above, a recipient may use your version of this
+** file under either the MPL or the GPL.
+** ---------------------------------------------------------------------
+** Inquiries regarding the ACX100 Open Source Project can be
+** made directly to:
+**
+** acx100-users@lists.sf.net
+** http://acx100.sf.net
+** ---------------------------------------------------------------------
+*/
+#define ACX_PCI 1
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/compiler.h> /* required for Lx 2.6.8 ?? */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/if_arp.h>
+#include <linux/rtnetlink.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <linux/netdevice.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/pm.h>
+#include <linux/vmalloc.h>
+
+#include "acx.h"
+
+
+/***********************************************************************
+*/
+#define PCI_TYPE		(PCI_USES_MEM | PCI_ADDR0 | PCI_NO_ACPI_WAKE)
+#define PCI_ACX100_REGION1		0x01
+#define PCI_ACX100_REGION1_SIZE		0x1000	/* Memory size - 4K bytes */
+#define PCI_ACX100_REGION2		0x02
+#define PCI_ACX100_REGION2_SIZE		0x10000 /* Memory size - 64K bytes */
+
+#define PCI_ACX111_REGION1		0x00
+#define PCI_ACX111_REGION1_SIZE		0x2000	/* Memory size - 8K bytes */
+#define PCI_ACX111_REGION2		0x01
+#define PCI_ACX111_REGION2_SIZE		0x20000 /* Memory size - 128K bytes */
+
+/* Texas Instruments Vendor ID */
+#define PCI_VENDOR_ID_TI		0x104c
+
+/* ACX100 22Mb/s WLAN controller */
+#define PCI_DEVICE_ID_TI_TNETW1100A	0x8400
+#define PCI_DEVICE_ID_TI_TNETW1100B	0x8401
+
+/* ACX111 54Mb/s WLAN controller */
+#define PCI_DEVICE_ID_TI_TNETW1130	0x9066
+
+/* PCI Class & Sub-Class code, Network-'Other controller' */
+#define PCI_CLASS_NETWORK_OTHERS	0x0280
+
+#define CARD_EEPROM_ID_SIZE 6
+
+#ifndef PCI_D0
+/* From include/linux/pci.h */
+#define PCI_D0		0
+#define PCI_D1		1
+#define PCI_D2		2
+#define PCI_D3hot	3
+#define PCI_D3cold	4
+#define PCI_UNKNOWN	5
+#define PCI_POWER_ERROR	-1
+#endif
+
+
+/***********************************************************************
+*/
+static void acxpci_i_tx_timeout(struct net_device *ndev);
+static irqreturn_t acxpci_i_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void acxpci_i_set_multicast_list(struct net_device *ndev);
+
+static int acxpci_e_open(struct net_device *ndev);
+static int acxpci_e_close(struct net_device *ndev);
+static void acxpci_s_up(struct net_device *ndev);
+static void acxpci_s_down(struct net_device *ndev);
+
+
+/***********************************************************************
+** Register access
+*/
+
+/* Pick one */
+/* #define INLINE_IO static */
+#define INLINE_IO static inline
+
+INLINE_IO u32
+read_reg32(acx_device_t *adev, unsigned int offset)
+{
+#if ACX_IO_WIDTH == 32
+	return readl((u8 *)adev->iobase + adev->io[offset]);
+#else
+	return readw((u8 *)adev->iobase + adev->io[offset])
+	    + (readw((u8 *)adev->iobase + adev->io[offset] + 2) << 16);
+#endif
+}
+
+INLINE_IO u16
+read_reg16(acx_device_t *adev, unsigned int offset)
+{
+	return readw((u8 *)adev->iobase + adev->io[offset]);
+}
+
+INLINE_IO u8
+read_reg8(acx_device_t *adev, unsigned int offset)
+{
+	return readb((u8 *)adev->iobase + adev->io[offset]);
+}
+
+INLINE_IO void
+write_reg32(acx_device_t *adev, unsigned int offset, u32 val)
+{
+#if ACX_IO_WIDTH == 32
+	writel(val, (u8 *)adev->iobase + adev->io[offset]);
+#else
+	writew(val & 0xffff, (u8 *)adev->iobase + adev->io[offset]);
+	writew(val >> 16, (u8 *)adev->iobase + adev->io[offset] + 2);
+#endif
+}
+
+INLINE_IO void
+write_reg16(acx_device_t *adev, unsigned int offset, u16 val)
+{
+	writew(val, (u8 *)adev->iobase + adev->io[offset]);
+}
+
+INLINE_IO void
+write_reg8(acx_device_t *adev, unsigned int offset, u8 val)
+{
+	writeb(val, (u8 *)adev->iobase + adev->io[offset]);
+}
+
+/* Handle PCI posting properly:
+ * Make sure that writes reach the adapter in case they require to be executed
+ * *before* the next write, by reading a random (and safely accessible) register.
+ * This call has to be made if there is no read following (which would flush the data
+ * to the adapter), yet the written data has to reach the adapter immediately. */
+INLINE_IO void
+write_flush(acx_device_t *adev)
+{
+	/* readb(adev->iobase + adev->io[IO_ACX_INFO_MAILBOX_OFFS]); */
+	/* faster version (accesses the first register, IO_ACX_SOFT_RESET,
+	 * which should also be safe): */
+	readb(adev->iobase);
+}
+
+
+/***********************************************************************
+*/
+static struct net_device *root_adev_newest = NULL;
+DECLARE_MUTEX(root_adev_sem);
+
+
+/***********************************************************************
+*/
+static inline txdesc_t*
+get_txdesc(acx_device_t *adev, int index)
+{
+	return (txdesc_t*) (((u8*)adev->txdesc_start) + index * adev->txdesc_size);
+}
+
+static inline txdesc_t*
+advance_txdesc(acx_device_t *adev, txdesc_t* txdesc, int inc)
+{
+	return (txdesc_t*) (((u8*)txdesc) + inc * adev->txdesc_size);
+}
+
+static txhostdesc_t*
+get_txhostdesc(acx_device_t *adev, txdesc_t* txdesc)
+{
+	int index = (u8*)txdesc - (u8*)adev->txdesc_start;
+	if (unlikely(ACX_DEBUG && (index % adev->txdesc_size))) {
+		printk("bad txdesc ptr %p\n", txdesc);
+		return NULL;
+	}
+	index /= adev->txdesc_size;
+	if (unlikely(ACX_DEBUG && (index >= TX_CNT))) {
+		printk("bad txdesc ptr %p\n", txdesc);
+		return NULL;
+	}
+	return &adev->txhostdesc_start[index*2];
+}
+
+static inline client_t*
+get_txc(acx_device_t *adev, txdesc_t* txdesc)
+{
+	int index = (u8*)txdesc - (u8*)adev->txdesc_start;
+	if (unlikely(ACX_DEBUG && (index % adev->txdesc_size))) {
+		printk("bad txdesc ptr %p\n", txdesc);
+		return NULL;
+	}
+	index /= adev->txdesc_size;
+	if (unlikely(ACX_DEBUG && (index >= TX_CNT))) {
+		printk("bad txdesc ptr %p\n", txdesc);
+		return NULL;
+	}
+	return adev->txc[index];
+}
+
+static inline u16
+get_txr(acx_device_t *adev, txdesc_t* txdesc)
+{
+	int index = (u8*)txdesc - (u8*)adev->txdesc_start;
+	index /= adev->txdesc_size;
+	return adev->txr[index];
+}
+
+static inline void
+put_txcr(acx_device_t *adev, txdesc_t* txdesc, client_t* c, u16 r111)
+{
+	int index = (u8*)txdesc - (u8*)adev->txdesc_start;
+	if (unlikely(ACX_DEBUG && (index % adev->txdesc_size))) {
+		printk("bad txdesc ptr %p\n", txdesc);
+		return;
+	}
+	index /= adev->txdesc_size;
+	if (unlikely(ACX_DEBUG && (index >= TX_CNT))) {
+		printk("bad txdesc ptr %p\n", txdesc);
+		return;
+	}
+	adev->txc[index] = c;
+	adev->txr[index] = r111;
+}
+
+
+/***********************************************************************
+** EEPROM and PHY read/write helpers
+*/
+/***********************************************************************
+** acxpci_read_eeprom_byte
+**
+** Function called to read an octet in the EEPROM.
+**
+** This function is used by acxpci_e_probe to check if the
+** connected card is a legal one or not.
+**
+** Arguments:
+**	adev		ptr to acx_device structure
+**	addr		address to read in the EEPROM
+**	charbuf		ptr to a char. This is where the read octet
+**			will be stored
+*/
+int
+acxpci_read_eeprom_byte(acx_device_t *adev, u32 addr, u8 *charbuf)
+{
+	int result;
+	int count;
+
+	write_reg32(adev, IO_ACX_EEPROM_CFG, 0);
+	write_reg32(adev, IO_ACX_EEPROM_ADDR, addr);
+	write_flush(adev);
+	write_reg32(adev, IO_ACX_EEPROM_CTL, 2);
+
+	count = 0xffff;
+	while (read_reg16(adev, IO_ACX_EEPROM_CTL)) {
+		/* scheduling away instead of CPU burning loop
+		 * doesn't seem to work here at all:
+		 * awful delay, sometimes also failure.
+		 * Doesn't matter anyway (only small delay). */
+		if (unlikely(!--count)) {
+			printk("%s: timeout waiting for EEPROM read\n",
+							adev->ndev->name);
+			result = NOT_OK;
+			goto fail;
+		}
+		cpu_relax();
+	}
+
+	*charbuf = read_reg8(adev, IO_ACX_EEPROM_DATA);
+	log(L_DEBUG, "EEPROM at 0x%04X = 0x%02X\n", addr, *charbuf);
+	result = OK;
+
+fail:
+	return result;
+}
+
+
+/***********************************************************************
+** We don't lock hw accesses here since we never r/w eeprom in IRQ
+** Note: this function sleeps only because of GFP_KERNEL alloc
+*/
+#ifdef UNUSED
+int
+acxpci_s_write_eeprom(acx_device_t *adev, u32 addr, u32 len, const u8 *charbuf)
+{
+	u8 *data_verify = NULL;
+	unsigned long flags;
+	int count, i;
+	int result = NOT_OK;
+	u16 gpio_orig;
+
+	printk("acx: WARNING! I would write to EEPROM now. "
+		"Since I really DON'T want to unless you know "
+		"what you're doing (THIS CODE WILL PROBABLY "
+		"NOT WORK YET!), I will abort that now. And "
+		"definitely make sure to make a "
+		"/proc/driver/acx_wlan0_eeprom backup copy first!!! "
+		"(the EEPROM content includes the PCI config header!! "
+		"If you kill important stuff, then you WILL "
+		"get in trouble and people DID get in trouble already)\n");
+	return OK;
+
+	FN_ENTER;
+
+	data_verify = kmalloc(len, GFP_KERNEL);
+	if (!data_verify) {
+		goto end;
+	}
+
+	/* first we need to enable the OE (EEPROM Output Enable) GPIO line
+	 * to be able to write to the EEPROM.
+	 * NOTE: an EEPROM writing success has been reported,
+	 * but you probably have to modify GPIO_OUT, too,
+	 * and you probably need to activate a different GPIO
+	 * line instead! */
+	gpio_orig = read_reg16(adev, IO_ACX_GPIO_OE);
+	write_reg16(adev, IO_ACX_GPIO_OE, gpio_orig & ~1);
+	write_flush(adev);
+
+	/* ok, now start writing the data out */
+	for (i = 0; i < len; i++) {
+		write_reg32(adev, IO_ACX_EEPROM_CFG, 0);
+		write_reg32(adev, IO_ACX_EEPROM_ADDR, addr + i);
+		write_reg32(adev, IO_ACX_EEPROM_DATA, *(charbuf + i));
+		write_flush(adev);
+		write_reg32(adev, IO_ACX_EEPROM_CTL, 1);
+
+		count = 0xffff;
+		while (read_reg16(adev, IO_ACX_EEPROM_CTL)) {
+			if (unlikely(!--count)) {
+				printk("WARNING, DANGER!!! "
+					"Timeout waiting for EEPROM write\n");
+				goto end;
+			}
+			cpu_relax();
+		}
+	}
+
+	/* disable EEPROM writing */
+	write_reg16(adev, IO_ACX_GPIO_OE, gpio_orig);
+	write_flush(adev);
+
+	/* now start a verification run */
+	for (i = 0; i < len; i++) {
+		write_reg32(adev, IO_ACX_EEPROM_CFG, 0);
+		write_reg32(adev, IO_ACX_EEPROM_ADDR, addr + i);
+		write_flush(adev);
+		write_reg32(adev, IO_ACX_EEPROM_CTL, 2);
+
+		count = 0xffff;
+		while (read_reg16(adev, IO_ACX_EEPROM_CTL)) {
+			if (unlikely(!--count)) {
+				printk("timeout waiting for EEPROM read\n");
+				goto end;
+			}
+			cpu_relax();
+		}
+
+		data_verify[i] = read_reg16(adev, IO_ACX_EEPROM_DATA);
+	}
+
+	if (0 == memcmp(charbuf, data_verify, len))
+		result = OK; /* read data matches, success */
+
+end:
+	kfree(data_verify);
+	FN_EXIT1(result);
+	return result;
+}
+#endif /* UNUSED */
+
+
+/***********************************************************************
+** acxpci_s_read_phy_reg
+**
+** Messing with rx/tx disabling and enabling here
+** (write_reg32(adev, IO_ACX_ENABLE, 0b000000xx)) kills traffic
+*/
+int
+acxpci_s_read_phy_reg(acx_device_t *adev, u32 reg, u8 *charbuf)
+{
+	int result = NOT_OK;
+	int count;
+
+	FN_ENTER;
+
+	write_reg32(adev, IO_ACX_PHY_ADDR, reg);
+	write_flush(adev);
+	write_reg32(adev, IO_ACX_PHY_CTL, 2);
+
+	count = 0xffff;
+	while (read_reg32(adev, IO_ACX_PHY_CTL)) {
+		/* scheduling away instead of CPU burning loop
+		 * doesn't seem to work here at all:
+		 * awful delay, sometimes also failure.
+		 * Doesn't matter anyway (only small delay). */
+		if (unlikely(!--count)) {
+			printk("%s: timeout waiting for phy read\n",
+							adev->ndev->name);
+			*charbuf = 0;
+			goto fail;
+		}
+		cpu_relax();
+	}
+
+	log(L_DEBUG, "count was %u\n", count);
+	*charbuf = read_reg8(adev, IO_ACX_PHY_DATA);
+
+	log(L_DEBUG, "radio PHY at 0x%04X = 0x%02X\n", *charbuf, reg);
+	result = OK;
+	goto fail; /* silence compiler warning */
+fail:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+*/
+int
+acxpci_s_write_phy_reg(acx_device_t *adev, u32 reg, u8 value)
+{
+	FN_ENTER;
+
+	/* mprusko said that 32bit accesses result in distorted sensitivity
+	 * on his card. Unconfirmed, looks like it's not true (most likely since we
+	 * now properly flush writes). */
+	write_reg32(adev, IO_ACX_PHY_DATA, value);
+	write_reg32(adev, IO_ACX_PHY_ADDR, reg);
+	write_flush(adev);
+	write_reg32(adev, IO_ACX_PHY_CTL, 1);
+	write_flush(adev);
+	log(L_DEBUG, "radio PHY write 0x%02X at 0x%04X\n", value, reg);
+
+	FN_EXIT1(OK);
+	return OK;
+}
+
+
+#define NO_AUTO_INCREMENT	1
+
+/***********************************************************************
+** acxpci_s_write_fw
+**
+** Write the firmware image into the card.
+**
+** Arguments:
+**	adev		wlan device structure
+**	apfw_image	firmware image.
+**
+** Returns:
+**	1	firmware image corrupted
+**	0	success
+*/
+static int
+acxpci_s_write_fw(acx_device_t *adev, const firmware_image_t *apfw_image, u32 offset)
+{
+	int len, size;
+	u32 sum, v32;
+	/* we skip the first four bytes which contain the control sum */
+	const u8 *image = (u8*)apfw_image + 4;
+
+	/* start the image checksum by adding the image size value */
+	sum = image[0]+image[1]+image[2]+image[3];
+	image += 4;
+
+	write_reg32(adev, IO_ACX_SLV_END_CTL, 0);
+
+#if NO_AUTO_INCREMENT
+	write_reg32(adev, IO_ACX_SLV_MEM_CTL, 0); /* use basic mode */
+#else
+	write_reg32(adev, IO_ACX_SLV_MEM_CTL, 1); /* use autoincrement mode */
+	write_reg32(adev, IO_ACX_SLV_MEM_ADDR, offset); /* configure start address */
+	write_flush(adev);
+#endif
+
+	len = 0;
+	size = le32_to_cpu(apfw_image->size) & (~3);
+
+	while (likely(len < size)) {
+		v32 = be32_to_cpu(*(u32*)image);
+		sum += image[0]+image[1]+image[2]+image[3];
+		image += 4;
+		len += 4;
+
+#if NO_AUTO_INCREMENT
+		write_reg32(adev, IO_ACX_SLV_MEM_ADDR, offset + len - 4);
+		write_flush(adev);
+#endif
+		write_reg32(adev, IO_ACX_SLV_MEM_DATA, v32);
+	}
+
+	log(L_DEBUG, "firmware written, size:%d sum1:%x sum2:%x\n",
+			size, sum, le32_to_cpu(apfw_image->chksum));
+
+	/* compare our checksum with the stored image checksum */
+	return (sum != le32_to_cpu(apfw_image->chksum));
+}
+
+
+/***********************************************************************
+** acxpci_s_validate_fw
+**
+** Compare the firmware image given with
+** the firmware image written into the card.
+**
+** Arguments:
+**	adev		wlan device structure
+**   apfw_image  firmware image.
+**
+** Returns:
+**	NOT_OK	firmware image corrupted or not correctly written
+**	OK	success
+*/
+static int
+acxpci_s_validate_fw(acx_device_t *adev, const firmware_image_t *apfw_image,
+				u32 offset)
+{
+	u32 sum, v32, w32;
+	int len, size;
+	int result = OK;
+	/* we skip the first four bytes which contain the control sum */
+	const u8 *image = (u8*)apfw_image + 4;
+
+	/* start the image checksum by adding the image size value */
+	sum = image[0]+image[1]+image[2]+image[3];
+	image += 4;
+
+	write_reg32(adev, IO_ACX_SLV_END_CTL, 0);
+
+#if NO_AUTO_INCREMENT
+	write_reg32(adev, IO_ACX_SLV_MEM_CTL, 0); /* use basic mode */
+#else
+	write_reg32(adev, IO_ACX_SLV_MEM_CTL, 1); /* use autoincrement mode */
+	write_reg32(adev, IO_ACX_SLV_MEM_ADDR, offset); /* configure start address */
+#endif
+
+	len = 0;
+	size = le32_to_cpu(apfw_image->size) & (~3);
+
+	while (likely(len < size)) {
+		v32 = be32_to_cpu(*(u32*)image);
+		image += 4;
+		len += 4;
+
+#if NO_AUTO_INCREMENT
+		write_reg32(adev, IO_ACX_SLV_MEM_ADDR, offset + len - 4);
+#endif
+		w32 = read_reg32(adev, IO_ACX_SLV_MEM_DATA);
+
+		if (unlikely(w32 != v32)) {
+			printk("acx: FATAL: firmware upload: "
+			"data parts at offset %d don't match (0x%08X vs. 0x%08X)! "
+			"I/O timing issues or defective memory, with DWL-xx0+? "
+			"ACX_IO_WIDTH=16 may help. Please report\n",
+				len, v32, w32);
+			result = NOT_OK;
+			break;
+		}
+
+		sum += (u8)w32 + (u8)(w32>>8) + (u8)(w32>>16) + (u8)(w32>>24);
+	}
+
+	/* sum control verification */
+	if (result != NOT_OK) {
+		if (sum != le32_to_cpu(apfw_image->chksum)) {
+			printk("acx: FATAL: firmware upload: "
+				"checksums don't match!\n");
+			result = NOT_OK;
+		}
+	}
+
+	return result;
+}
+
+
+/***********************************************************************
+** acxpci_s_upload_fw
+**
+** Called from acx_reset_dev
+*/
+static int
+acxpci_s_upload_fw(acx_device_t *adev)
+{
+	firmware_image_t *apfw_image = NULL;
+	int res = NOT_OK;
+	int try;
+	u32 size;
+	char filename[sizeof("tiacx1NNcNN")];
+
+	FN_ENTER;
+
+	/* Try combined, then main image */
+	adev->need_radio_fw = 0;
+	snprintf(filename, sizeof(filename), "tiacx1%02dc%02X",
+		IS_ACX111(adev)*11, adev->radio_type);
+
+	apfw_image = acx_s_read_fw(&adev->pdev->dev, filename, &size);
+	if (!apfw_image) {
+		adev->need_radio_fw = 1;
+		filename[sizeof("tiacx1NN")-1] = '\0';
+		apfw_image = acx_s_read_fw(&adev->pdev->dev, filename, &size);
+		if (!apfw_image) {
+			FN_EXIT1(NOT_OK);
+			return NOT_OK;
+		}
+	}
+
+	for (try = 1; try <= 5; try++) {
+		res = acxpci_s_write_fw(adev, apfw_image, 0);
+		log(L_DEBUG|L_INIT, "acx_write_fw (main/combined):%d\n", res);
+		if (OK == res) {
+			res = acxpci_s_validate_fw(adev, apfw_image, 0);
+			log(L_DEBUG|L_INIT, "acx_validate_fw "
+					"(main/combined):%d\n", res);
+		}
+
+		if (OK == res) {
+			SET_BIT(adev->dev_state_mask, ACX_STATE_FW_LOADED);
+			break;
+		}
+		printk("acx: firmware upload attempt #%d FAILED, "
+			"retrying...\n", try);
+		acx_s_msleep(1000); /* better wait for a while... */
+	}
+
+	vfree(apfw_image);
+
+	FN_EXIT1(res);
+	return res;
+}
+
+
+/***********************************************************************
+** acxpci_s_upload_radio
+**
+** Uploads the appropriate radio module firmware into the card.
+*/
+int
+acxpci_s_upload_radio(acx_device_t *adev)
+{
+	acx_ie_memmap_t mm;
+	firmware_image_t *radio_image;
+	acx_cmd_radioinit_t radioinit;
+	int res = NOT_OK;
+	int try;
+	u32 offset;
+	u32 size;
+	char filename[sizeof("tiacx1NNrNN")];
+
+	if (!adev->need_radio_fw) return OK;
+
+	FN_ENTER;
+
+	acx_s_interrogate(adev, &mm, ACX1xx_IE_MEMORY_MAP);
+	offset = le32_to_cpu(mm.CodeEnd);
+
+	snprintf(filename, sizeof(filename), "tiacx1%02dr%02X",
+		IS_ACX111(adev)*11,
+		adev->radio_type);
+	radio_image = acx_s_read_fw(&adev->pdev->dev, filename, &size);
+	if (!radio_image) {
+		printk("acx: can't load radio module '%s'\n", filename);
+		goto fail;
+	}
+
+	acx_s_issue_cmd(adev, ACX1xx_CMD_SLEEP, NULL, 0);
+
+	for (try = 1; try <= 5; try++) {
+		res = acxpci_s_write_fw(adev, radio_image, offset);
+		log(L_DEBUG|L_INIT, "acx_write_fw (radio): %d\n", res);
+		if (OK == res) {
+			res = acxpci_s_validate_fw(adev, radio_image, offset);
+			log(L_DEBUG|L_INIT, "acx_validate_fw (radio): %d\n", res);
+		}
+
+		if (OK == res)
+			break;
+		printk("acx: radio firmware upload attempt #%d FAILED, "
+			"retrying...\n", try);
+		acx_s_msleep(1000); /* better wait for a while... */
+	}
+
+	acx_s_issue_cmd(adev, ACX1xx_CMD_WAKE, NULL, 0);
+	radioinit.offset = cpu_to_le32(offset);
+	/* no endian conversion needed, remains in card CPU area: */
+	radioinit.len = radio_image->size;
+
+	vfree(radio_image);
+
+	if (OK != res)
+		goto fail;
+
+	/* will take a moment so let's have a big timeout */
+	acx_s_issue_cmd_timeo(adev, ACX1xx_CMD_RADIOINIT,
+		&radioinit, sizeof(radioinit), CMD_TIMEOUT_MS(1000));
+
+	res = acx_s_interrogate(adev, &mm, ACX1xx_IE_MEMORY_MAP);
+fail:
+	FN_EXIT1(res);
+	return res;
+}
+
+
+/***********************************************************************
+** acxpci_l_reset_mac
+**
+** MAC will be reset
+** Call context: reset_dev
+*/
+static void
+acxpci_l_reset_mac(acx_device_t *adev)
+{
+	u16 temp;
+
+	FN_ENTER;
+
+	/* halt eCPU */
+	temp = read_reg16(adev, IO_ACX_ECPU_CTRL) | 0x1;
+	write_reg16(adev, IO_ACX_ECPU_CTRL, temp);
+
+	/* now do soft reset of eCPU, set bit */
+	temp = read_reg16(adev, IO_ACX_SOFT_RESET) | 0x1;
+	log(L_DEBUG, "%s: enable soft reset...\n", __func__);
+	write_reg16(adev, IO_ACX_SOFT_RESET, temp);
+	write_flush(adev);
+
+	/* now clear bit again: deassert eCPU reset */
+	log(L_DEBUG, "%s: disable soft reset and go to init mode...\n", __func__);
+	write_reg16(adev, IO_ACX_SOFT_RESET, temp & ~0x1);
+
+	/* now start a burst read from initial EEPROM */
+	temp = read_reg16(adev, IO_ACX_EE_START) | 0x1;
+	write_reg16(adev, IO_ACX_EE_START, temp);
+	write_flush(adev);
+
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acxpci_s_verify_init
+*/
+static int
+acxpci_s_verify_init(acx_device_t *adev)
+{
+	int result = NOT_OK;
+	unsigned long timeout;
+
+	FN_ENTER;
+
+	timeout = jiffies + 2*HZ;
+	for (;;) {
+		u16 irqstat = read_reg16(adev, IO_ACX_IRQ_STATUS_NON_DES);
+		if (irqstat & HOST_INT_FCS_THRESHOLD) {
+			result = OK;
+			write_reg16(adev, IO_ACX_IRQ_ACK, HOST_INT_FCS_THRESHOLD);
+			break;
+		}
+		if (time_after(jiffies, timeout))
+			break;
+		/* Init may take up to ~0.5 sec total */
+		acx_s_msleep(50);
+	}
+
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** A few low-level helpers
+**
+** Note: these functions are not protected by lock
+** and thus are never allowed to be called from IRQ.
+** Also they must not race with fw upload which uses same hw regs
+*/
+
+/***********************************************************************
+** acxpci_write_cmd_type_status
+*/
+
+static inline void
+acxpci_write_cmd_type_status(acx_device_t *adev, u16 type, u16 status)
+{
+	writel(type | (status << 16), adev->cmd_area);
+	write_flush(adev);
+}
+
+
+/***********************************************************************
+** acxpci_read_cmd_type_status
+*/
+static u32
+acxpci_read_cmd_type_status(acx_device_t *adev)
+{
+	u32 cmd_type, cmd_status;
+
+	cmd_type = readl(adev->cmd_area);
+	cmd_status = (cmd_type >> 16);
+	cmd_type = (u16)cmd_type;
+
+	log(L_CTL, "cmd_type:%04X cmd_status:%04X [%s]\n",
+		cmd_type, cmd_status,
+		acx_cmd_status_str(cmd_status));
+
+	return cmd_status;
+}
+
+
+/***********************************************************************
+** acxpci_s_reset_dev
+**
+** Arguments:
+**	netdevice that contains the adev variable
+** Returns:
+**	NOT_OK on fail
+**	OK on success
+** Side effects:
+**	device is hard reset
+** Call context:
+**	acxpci_e_probe
+** Comment:
+**	This resets the device using low level hardware calls
+**	as well as uploads and verifies the firmware to the card
+*/
+
+static inline void
+init_mboxes(acx_device_t *adev)
+{
+	u32 cmd_offs, info_offs;
+
+	cmd_offs = read_reg32(adev, IO_ACX_CMD_MAILBOX_OFFS);
+	info_offs = read_reg32(adev, IO_ACX_INFO_MAILBOX_OFFS);
+	adev->cmd_area = (u8 *)adev->iobase2 + cmd_offs;
+	adev->info_area = (u8 *)adev->iobase2 + info_offs;
+	log(L_DEBUG, "iobase2=%p\n"
+		"cmd_mbox_offset=%X cmd_area=%p\n"
+		"info_mbox_offset=%X info_area=%p\n",
+		adev->iobase2,
+		cmd_offs, adev->cmd_area,
+		info_offs, adev->info_area);
+}
+
+
+static inline void
+read_eeprom_area(acx_device_t *adev)
+{
+#if ACX_DEBUG > 1
+	int offs;
+	u8 tmp;
+
+	for (offs = 0x8c; offs < 0xb9; offs++)
+		acxpci_read_eeprom_byte(adev, offs, &tmp);
+#endif
+}
+
+
+static int
+acxpci_s_reset_dev(acx_device_t *adev)
+{
+	const char* msg = "";
+	unsigned long flags;
+	int result = NOT_OK;
+	u16 hardware_info;
+	u16 ecpu_ctrl;
+	int count;
+
+	FN_ENTER;
+
+	/* reset the device to make sure the eCPU is stopped
+	 * to upload the firmware correctly */
+
+	acx_lock(adev, flags);
+
+	acxpci_l_reset_mac(adev);
+
+	ecpu_ctrl = read_reg16(adev, IO_ACX_ECPU_CTRL) & 1;
+	if (!ecpu_ctrl) {
+		msg = "eCPU is already running. ";
+		goto end_unlock;
+	}
+
+#ifdef WE_DONT_NEED_THAT_DO_WE
+	if (read_reg16(adev, IO_ACX_SOR_CFG) & 2) {
+		/* eCPU most likely means "embedded CPU" */
+		msg = "eCPU did not start after boot from flash. ";
+		goto end_unlock;
+	}
+
+	/* check sense on reset flags */
+	if (read_reg16(adev, IO_ACX_SOR_CFG) & 0x10) {
+		printk("%s: eCPU did not start after boot (SOR), "
+			"is this fatal?\n", adev->ndev->name);
+	}
+#endif
+	/* scan, if any, is stopped now, setting corresponding IRQ bit */
+	adev->irq_status |= HOST_INT_SCAN_COMPLETE;
+
+	acx_unlock(adev, flags);
+
+	/* need to know radio type before fw load */
+	/* Need to wait for arrival of this information in a loop,
+	 * most probably since eCPU runs some init code from EEPROM
+	 * (started burst read in reset_mac()) which also
+	 * sets the radio type ID */
+
+	count = 0xffff;
+	do {
+		hardware_info = read_reg16(adev, IO_ACX_EEPROM_INFORMATION);
+		if (!--count) {
+			msg = "eCPU didn't indicate radio type";
+			goto end_fail;
+		}
+		cpu_relax();
+	} while (!(hardware_info & 0xff00)); /* radio type still zero? */
+
+	/* printk("DEBUG: count %d\n", count); */
+	adev->form_factor = hardware_info & 0xff;
+	adev->radio_type = hardware_info >> 8;
+
+	/* load the firmware */
+	if (OK != acxpci_s_upload_fw(adev))
+		goto end_fail;
+
+	/* acx_s_msleep(10);	this one really shouldn't be required */
+
+	/* now start eCPU by clearing bit */
+	write_reg16(adev, IO_ACX_ECPU_CTRL, ecpu_ctrl & ~0x1);
+	log(L_DEBUG, "booted eCPU up and waiting for completion...\n");
+
+	/* wait for eCPU bootup */
+	if (OK != acxpci_s_verify_init(adev)) {
+		msg = "timeout waiting for eCPU. ";
+		goto end_fail;
+	}
+	log(L_DEBUG, "eCPU has woken up, card is ready to be configured\n");
+
+	init_mboxes(adev);
+	acxpci_write_cmd_type_status(adev, 0, 0);
+
+	/* test that EEPROM is readable */
+	read_eeprom_area(adev);
+
+	result = OK;
+	goto end;
+
+/* Finish error message. Indicate which function failed */
+end_unlock:
+	acx_unlock(adev, flags);
+end_fail:
+	printk("acx: %sreset_dev() FAILED\n", msg);
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acxpci_s_issue_cmd_timeo
+**
+** Sends command to fw, extract result
+**
+** NB: we do _not_ take lock inside, so be sure to not touch anything
+** which may interfere with IRQ handler operation
+**
+** TODO: busy wait is a bit silly, so:
+** 1) stop doing many iters - go to sleep after first
+** 2) go to waitqueue based approach: wait, not poll!
+*/
+#undef FUNC
+#define FUNC "issue_cmd"
+
+#if !ACX_DEBUG
+int
+acxpci_s_issue_cmd_timeo(
+	acx_device_t *adev,
+	unsigned int cmd,
+	void *buffer,
+	unsigned buflen,
+	unsigned cmd_timeout)
+{
+#else
+int
+acxpci_s_issue_cmd_timeo_debug(
+	acx_device_t *adev,
+	unsigned cmd,
+	void *buffer,
+	unsigned buflen,
+	unsigned cmd_timeout,
+	const char* cmdstr)
+{
+	unsigned long start = jiffies;
+#endif
+	const char *devname;
+	unsigned counter;
+	u16 irqtype;
+	u16 cmd_status;
+	unsigned long timeout;
+
+	FN_ENTER;
+
+	devname = adev->ndev->name;
+	if (!devname || !devname[0] || devname[4]=='%')
+		devname = "acx";
+
+	log(L_CTL, FUNC"(cmd:%s,buflen:%u,timeout:%ums,type:0x%04X)\n",
+		cmdstr, buflen, cmd_timeout,
+		buffer ? le16_to_cpu(((acx_ie_generic_t *)buffer)->type) : -1);
+
+	if (!(adev->dev_state_mask & ACX_STATE_FW_LOADED)) {
+		printk("%s: "FUNC"(): firmware is not loaded yet, "
+			"cannot execute commands!\n", devname);
+		goto bad;
+	}
+
+	if ((acx_debug & L_DEBUG) && (cmd != ACX1xx_CMD_INTERROGATE)) {
+		printk("input buffer (len=%u):\n", buflen);
+		acx_dump_bytes(buffer, buflen);
+	}
+
+	/* wait for firmware to become idle for our command submission */
+	timeout = HZ/5;
+	counter = (timeout * 1000 / HZ) - 1; /* in ms */
+	timeout += jiffies;
+	do {
+		cmd_status = acxpci_read_cmd_type_status(adev);
+		/* Test for IDLE state */
+		if (!cmd_status)
+			break;
+		if (counter % 5 == 0) {
+			if (time_after(jiffies, timeout)) {
+				counter = 0;
+				break;
+			}
+			/* we waited 5 iterations, no luck. Sleep 5 ms */
+			acx_s_msleep(5);
+		}
+	} while (likely(--counter));
+
+	if (!counter) {
+		/* the card doesn't get idle, we're in trouble */
+		printk("%s: "FUNC"(): cmd_status is not IDLE: 0x%04X!=0\n",
+			devname, cmd_status);
+		goto bad;
+	} else if (counter < 190) { /* if waited >10ms... */
+		log(L_CTL|L_DEBUG, FUNC"(): waited for IDLE %dms. "
+			"Please report\n", 199 - counter);
+	}
+
+	/* now write the parameters of the command if needed */
+	if (buffer && buflen) {
+		/* if it's an INTERROGATE command, just pass the length
+		 * of parameters to read, as data */
+#if CMD_DISCOVERY
+		if (cmd == ACX1xx_CMD_INTERROGATE)
+			memset_io(adev->cmd_area + 4, 0xAA, buflen);
+#endif
+		/* adev->cmd_area points to PCI device's memory, not to RAM! */
+		memcpy_toio(adev->cmd_area + 4, buffer,
+			(cmd == ACX1xx_CMD_INTERROGATE) ? 4 : buflen);
+	}
+	/* now write the actual command type */
+	acxpci_write_cmd_type_status(adev, cmd, 0);
+	/* execute command */
+	write_reg16(adev, IO_ACX_INT_TRIG, INT_TRIG_CMD);
+	write_flush(adev);
+
+	/* wait for firmware to process command */
+
+	/* Ensure nonzero and not too large timeout.
+	** Also converts e.g. 100->99, 200->199
+	** which is nice but not essential */
+	cmd_timeout = (cmd_timeout-1) | 1;
+	if (unlikely(cmd_timeout > 1199))
+		cmd_timeout = 1199;
+	/* clear CMD_COMPLETE bit. can be set only by IRQ handler: */
+	adev->irq_status &= ~HOST_INT_CMD_COMPLETE;
+
+	/* we schedule away sometimes (timeout can be large) */
+	counter = cmd_timeout;
+	timeout = jiffies + cmd_timeout * HZ / 1000;
+	do {
+		if (!adev->irqs_active) { /* IRQ disabled: poll */
+			irqtype = read_reg16(adev, IO_ACX_IRQ_STATUS_NON_DES);
+			if (irqtype & HOST_INT_CMD_COMPLETE) {
+				write_reg16(adev, IO_ACX_IRQ_ACK,
+						HOST_INT_CMD_COMPLETE);
+				break;
+			}
+		} else { /* Wait when IRQ will set the bit */
+			irqtype = adev->irq_status;
+			if (irqtype & HOST_INT_CMD_COMPLETE)
+				break;
+		}
+
+		if (counter % 5 == 0) {
+			if (time_after(jiffies, timeout)) {
+				counter = 0;
+				break;
+			}
+			/* we waited 5 iterations, no luck. Sleep 5 ms */
+			acx_s_msleep(5);
+		}
+	} while (likely(--counter));
+
+	/* save state for debugging */
+	cmd_status = acxpci_read_cmd_type_status(adev);
+
+	/* put the card in IDLE state */
+	acxpci_write_cmd_type_status(adev, 0, 0);
+
+	if (!counter) {	/* timed out! */
+		printk("%s: "FUNC"(): timed out %s for CMD_COMPLETE. "
+			"irq bits:0x%04X irq_status:0x%04X timeout:%dms "
+			"cmd_status:%d (%s)\n",
+			devname, (adev->irqs_active) ? "waiting" : "polling",
+			irqtype, adev->irq_status, cmd_timeout,
+			cmd_status, acx_cmd_status_str(cmd_status));
+		goto bad;
+	} else if (cmd_timeout - counter > 30) { /* if waited >30ms... */
+		log(L_CTL|L_DEBUG, FUNC"(): %s for CMD_COMPLETE %dms. "
+			"count:%d. Please report\n",
+			(adev->irqs_active) ? "waited" : "polled",
+			cmd_timeout - counter, counter);
+	}
+
+	if (1 != cmd_status) { /* it is not a 'Success' */
+		printk("%s: "FUNC"(): cmd_status is not SUCCESS: %d (%s). "
+			"Took %dms of %d\n",
+			devname, cmd_status, acx_cmd_status_str(cmd_status),
+			cmd_timeout - counter, cmd_timeout);
+		/* zero out result buffer
+		 * WARNING: this will trash stack in case of illegally large input
+		 * length! */
+		if (buffer && buflen)
+			memset(buffer, 0, buflen);
+		goto bad;
+	}
+
+	/* read in result parameters if needed */
+	if (buffer && buflen && (cmd == ACX1xx_CMD_INTERROGATE)) {
+		/* adev->cmd_area points to PCI device's memory, not to RAM! */
+		memcpy_fromio(buffer, adev->cmd_area + 4, buflen);
+		if (acx_debug & L_DEBUG) {
+			printk("output buffer (len=%u): ", buflen);
+			acx_dump_bytes(buffer, buflen);
+		}
+	}
+/* ok: */
+	log(L_CTL, FUNC"(%s): took %ld jiffies to complete\n",
+			 cmdstr, jiffies - start);
+	FN_EXIT1(OK);
+	return OK;
+
+bad:
+	/* Give enough info so that callers can avoid
+	** printing their own diagnostic messages */
+#if ACX_DEBUG
+	printk("%s: "FUNC"(cmd:%s) FAILED\n", devname, cmdstr);
+#else
+	printk("%s: "FUNC"(cmd:0x%04X) FAILED\n", devname, cmd);
+#endif
+	dump_stack();
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+
+
+/***********************************************************************
+*/
+#ifdef NONESSENTIAL_FEATURES
+typedef struct device_id {
+	unsigned char id[6];
+	char *descr;
+	char *type;
+} device_id_t;
+
+static const device_id_t
+device_ids[] =
+{
+	{
+		{'G', 'l', 'o', 'b', 'a', 'l'},
+		NULL,
+		NULL,
+	},
+	{
+		{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+		"uninitialized",
+		"SpeedStream SS1021 or Gigafast WF721-AEX"
+	},
+	{
+		{0x80, 0x81, 0x82, 0x83, 0x84, 0x85},
+		"non-standard",
+		"DrayTek Vigor 520"
+	},
+	{
+		{'?', '?', '?', '?', '?', '?'},
+		"non-standard",
+		"Level One WPC-0200"
+	},
+	{
+		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+		"empty",
+		"DWL-650+ variant"
+	}
+};
+
+static void
+acx_show_card_eeprom_id(acx_device_t *adev)
+{
+	unsigned char buffer[CARD_EEPROM_ID_SIZE];
+	int i;
+
+	memset(&buffer, 0, CARD_EEPROM_ID_SIZE);
+	/* use direct EEPROM access */
+	for (i = 0; i < CARD_EEPROM_ID_SIZE; i++) {
+		if (OK != acxpci_read_eeprom_byte(adev,
+					 ACX100_EEPROM_ID_OFFSET + i,
+					 &buffer[i])) {
+			printk("acx: reading EEPROM FAILED\n");
+			break;
+		}
+	}
+
+	for (i = 0; i < VEC_SIZE(device_ids); i++) {
+		if (!memcmp(&buffer, device_ids[i].id, CARD_EEPROM_ID_SIZE)) {
+			if (device_ids[i].descr) {
+				printk("acx: EEPROM card ID string check "
+					"found %s card ID: is this %s?\n",
+					device_ids[i].descr, device_ids[i].type);
+			}
+			break;
+		}
+	}
+	if (i == VEC_SIZE(device_ids)) {
+		printk("acx: EEPROM card ID string check found "
+			"unknown card: expected 'Global', got '%.*s\'. "
+			"Please report\n", CARD_EEPROM_ID_SIZE, buffer);
+	}
+}
+#endif /* NONESSENTIAL_FEATURES */
+
+
+/***********************************************************************
+*/
+static void
+acxpci_s_device_chain_add(struct net_device *ndev)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+
+	down(&root_adev_sem);
+	adev->prev_nd = root_adev_newest;
+	root_adev_newest = ndev;
+	adev->ndev = ndev;
+	up(&root_adev_sem);
+}
+
+static void
+acxpci_s_device_chain_remove(struct net_device *ndev)
+{
+	struct net_device *querydev;
+	struct net_device *olderdev;
+	struct net_device *newerdev;
+
+	down(&root_adev_sem);
+	querydev = root_adev_newest;
+	newerdev = NULL;
+	while (querydev) {
+		olderdev = ndev2adev(querydev)->prev_nd;
+		if (0 == strcmp(querydev->name, ndev->name)) {
+			if (!newerdev) {
+				/* if we were at the beginning of the
+				 * list, then it's the list head that
+				 * we need to update to point at the
+				 * next older device */
+				root_adev_newest = olderdev;
+			} else {
+				/* it's the device that is newer than us
+				 * that we need to update to point at
+				 * the device older than us */
+				ndev2adev(newerdev)->prev_nd = olderdev;
+			}
+			break;
+		}
+		/* "newerdev" is actually the device of the old iteration,
+		 * but since the list starts (root_adev_newest)
+		 * with the newest devices,
+		 * it's newer than the ones following.
+		 * Oh the joys of iterating from newest to oldest :-\ */
+		newerdev = querydev;
+
+		/* keep checking old devices for matches until we hit the end
+		 * of the list */
+		querydev = olderdev;
+	}
+	up(&root_adev_sem);
+}
+
+
+/***********************************************************************
+** acxpci_free_desc_queues
+**
+** Releases the queues that have been allocated, the
+** others have been initialised to NULL so this
+** function can be used if only part of the queues were allocated.
+*/
+
+static inline void
+free_coherent(struct pci_dev *hwdev, size_t size,
+			void *vaddr, dma_addr_t dma_handle)
+{
+	dma_free_coherent(hwdev == NULL ? NULL : &hwdev->dev,
+			size, vaddr, dma_handle);
+}
+
+void
+acxpci_free_desc_queues(acx_device_t *adev)
+{
+#define ACX_FREE_QUEUE(size, ptr, phyaddr) \
+	if (ptr) { \
+		free_coherent(0, size, ptr, phyaddr); \
+		ptr = NULL; \
+		size = 0; \
+	}
+
+	FN_ENTER;
+
+	ACX_FREE_QUEUE(adev->txhostdesc_area_size, adev->txhostdesc_start, adev->txhostdesc_startphy);
+	ACX_FREE_QUEUE(adev->txbuf_area_size, adev->txbuf_start, adev->txbuf_startphy);
+
+	adev->txdesc_start = NULL;
+
+	ACX_FREE_QUEUE(adev->rxhostdesc_area_size, adev->rxhostdesc_start, adev->rxhostdesc_startphy);
+	ACX_FREE_QUEUE(adev->rxbuf_area_size, adev->rxbuf_start, adev->rxbuf_startphy);
+
+	adev->rxdesc_start = NULL;
+
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acxpci_s_delete_dma_regions
+*/
+static void
+acxpci_s_delete_dma_regions(acx_device_t *adev)
+{
+	unsigned long flags;
+
+	FN_ENTER;
+	/* disable radio Tx/Rx. Shouldn't we use the firmware commands
+	 * here instead? Or are we that much down the road that it's no
+	 * longer possible here? */
+	write_reg16(adev, IO_ACX_ENABLE, 0);
+
+	acx_s_msleep(100);
+
+	acx_lock(adev, flags);
+	acxpci_free_desc_queues(adev);
+	acx_unlock(adev, flags);
+
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acxpci_e_probe
+**
+** Probe routine called when a PCI device w/ matching ID is found.
+** Here's the sequence:
+**   - Allocate the PCI resources.
+**   - Read the PCMCIA attribute memory to make sure we have a WLAN card
+**   - Reset the MAC
+**   - Initialize the dev and wlan data
+**   - Initialize the MAC
+**
+** pdev	- ptr to pci device structure containing info about pci configuration
+** id	- ptr to the device id entry that matched this device
+*/
+static const u16
+IO_ACX100[] =
+{
+	0x0000, /* IO_ACX_SOFT_RESET */
+
+	0x0014, /* IO_ACX_SLV_MEM_ADDR */
+	0x0018, /* IO_ACX_SLV_MEM_DATA */
+	0x001c, /* IO_ACX_SLV_MEM_CTL */
+	0x0020, /* IO_ACX_SLV_END_CTL */
+
+	0x0034, /* IO_ACX_FEMR */
+
+	0x007c, /* IO_ACX_INT_TRIG */
+	0x0098, /* IO_ACX_IRQ_MASK */
+	0x00a4, /* IO_ACX_IRQ_STATUS_NON_DES */
+	0x00a8, /* IO_ACX_IRQ_STATUS_CLEAR */
+	0x00ac, /* IO_ACX_IRQ_ACK */
+	0x00b0, /* IO_ACX_HINT_TRIG */
+
+	0x0104, /* IO_ACX_ENABLE */
+
+	0x0250, /* IO_ACX_EEPROM_CTL */
+	0x0254, /* IO_ACX_EEPROM_ADDR */
+	0x0258, /* IO_ACX_EEPROM_DATA */
+	0x025c, /* IO_ACX_EEPROM_CFG */
+
+	0x0268, /* IO_ACX_PHY_ADDR */
+	0x026c, /* IO_ACX_PHY_DATA */
+	0x0270, /* IO_ACX_PHY_CTL */
+
+	0x0290, /* IO_ACX_GPIO_OE */
+
+	0x0298, /* IO_ACX_GPIO_OUT */
+
+	0x02a4, /* IO_ACX_CMD_MAILBOX_OFFS */
+	0x02a8, /* IO_ACX_INFO_MAILBOX_OFFS */
+	0x02ac, /* IO_ACX_EEPROM_INFORMATION */
+
+	0x02d0, /* IO_ACX_EE_START */
+	0x02d4, /* IO_ACX_SOR_CFG */
+	0x02d8 /* IO_ACX_ECPU_CTRL */
+};
+
+static const u16
+IO_ACX111[] =
+{
+	0x0000, /* IO_ACX_SOFT_RESET */
+
+	0x0014, /* IO_ACX_SLV_MEM_ADDR */
+	0x0018, /* IO_ACX_SLV_MEM_DATA */
+	0x001c, /* IO_ACX_SLV_MEM_CTL */
+	0x0020, /* IO_ACX_SLV_END_CTL */
+
+	0x0034, /* IO_ACX_FEMR */
+
+	0x00b4, /* IO_ACX_INT_TRIG */
+	0x00d4, /* IO_ACX_IRQ_MASK */
+	/* we do mean NON_DES (0xf0), not NON_DES_MASK which is at 0xe0: */
+	0x00f0, /* IO_ACX_IRQ_STATUS_NON_DES */
+	0x00e4, /* IO_ACX_IRQ_STATUS_CLEAR */
+	0x00e8, /* IO_ACX_IRQ_ACK */
+	0x00ec, /* IO_ACX_HINT_TRIG */
+
+	0x01d0, /* IO_ACX_ENABLE */
+
+	0x0338, /* IO_ACX_EEPROM_CTL */
+	0x033c, /* IO_ACX_EEPROM_ADDR */
+	0x0340, /* IO_ACX_EEPROM_DATA */
+	0x0344, /* IO_ACX_EEPROM_CFG */
+
+	0x0350, /* IO_ACX_PHY_ADDR */
+	0x0354, /* IO_ACX_PHY_DATA */
+	0x0358, /* IO_ACX_PHY_CTL */
+
+	0x0374, /* IO_ACX_GPIO_OE */
+
+	0x037c, /* IO_ACX_GPIO_OUT */
+
+	0x0388, /* IO_ACX_CMD_MAILBOX_OFFS */
+	0x038c, /* IO_ACX_INFO_MAILBOX_OFFS */
+	0x0390, /* IO_ACX_EEPROM_INFORMATION */
+
+	0x0100, /* IO_ACX_EE_START */
+	0x0104, /* IO_ACX_SOR_CFG */
+	0x0108, /* IO_ACX_ECPU_CTRL */
+};
+
+static void
+dummy_netdev_init(struct net_device *ndev) {}
+
+static int __devinit
+acxpci_e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	acx111_ie_configoption_t co;
+	unsigned long mem_region1 = 0;
+	unsigned long mem_region2 = 0;
+	unsigned long mem_region1_size;
+	unsigned long mem_region2_size;
+	unsigned long phymem1;
+	unsigned long phymem2;
+	void *mem1 = NULL;
+	void *mem2 = NULL;
+	acx_device_t *adev = NULL;
+	struct net_device *ndev = NULL;
+	const char *chip_name;
+	int result = -EIO;
+	int err;
+	u8 chip_type;
+
+	FN_ENTER;
+
+	/* Enable the PCI device */
+	if (pci_enable_device(pdev)) {
+		printk("acx: pci_enable_device() FAILED\n");
+		result = -ENODEV;
+		goto fail_pci_enable_device;
+	}
+
+	/* enable busmastering (required for CardBus) */
+	pci_set_master(pdev);
+
+	/* FIXME: prism54 calls pci_set_mwi() here,
+	 * should we do/support the same? */
+
+	/* chiptype is u8 but id->driver_data is ulong
+	** Works for now (possible values are 1 and 2) */
+	chip_type = (u8)id->driver_data;
+	/* acx100 and acx111 have different PCI memory regions */
+	if (chip_type == CHIPTYPE_ACX100) {
+		chip_name = "ACX100";
+		mem_region1 = PCI_ACX100_REGION1;
+		mem_region1_size  = PCI_ACX100_REGION1_SIZE;
+
+		mem_region2 = PCI_ACX100_REGION2;
+		mem_region2_size  = PCI_ACX100_REGION2_SIZE;
+	} else if (chip_type == CHIPTYPE_ACX111) {
+		chip_name = "ACX111";
+		mem_region1 = PCI_ACX111_REGION1;
+		mem_region1_size  = PCI_ACX111_REGION1_SIZE;
+
+		mem_region2 = PCI_ACX111_REGION2;
+		mem_region2_size  = PCI_ACX111_REGION2_SIZE;
+	} else {
+		printk("acx: unknown chip type 0x%04X\n", chip_type);
+		goto fail_unknown_chiptype;
+	}
+
+	/* Figure out our resources */
+	phymem1 = pci_resource_start(pdev, mem_region1);
+	phymem2 = pci_resource_start(pdev, mem_region2);
+	if (!request_mem_region(phymem1, pci_resource_len(pdev, mem_region1), "acx_1")) {
+		printk("acx: cannot reserve PCI memory region 1 (are you sure "
+			"you have CardBus support in kernel?)\n");
+		goto fail_request_mem_region1;
+	}
+	if (!request_mem_region(phymem2, pci_resource_len(pdev, mem_region2), "acx_2")) {
+		printk("acx: cannot reserve PCI memory region 2\n");
+		goto fail_request_mem_region2;
+	}
+	mem1 = ioremap(phymem1, mem_region1_size);
+	if (!mem1) {
+		printk("acx: ioremap() FAILED\n");
+		goto fail_ioremap1;
+	}
+	mem2 = ioremap(phymem2, mem_region2_size);
+	if (!mem2) {
+		printk("acx: ioremap() #2 FAILED\n");
+		goto fail_ioremap2;
+	}
+
+	printk("acx: found %s-based wireless network card at %s, irq:%d, "
+		"phymem1:0x%lX, phymem2:0x%lX, mem1:0x%p, mem1_size:%ld, "
+		"mem2:0x%p, mem2_size:%ld\n",
+		chip_name, pci_name(pdev), pdev->irq, phymem1, phymem2,
+		mem1, mem_region1_size,
+		mem2, mem_region2_size);
+	log(L_ANY, "initial debug setting is 0x%04X\n", acx_debug);
+
+	if (0 == pdev->irq) {
+		printk("acx: can't use IRQ 0\n");
+		goto fail_irq;
+	}
+
+	ndev = alloc_netdev(sizeof(*adev), "wlan%d", dummy_netdev_init);
+	/* (NB: memsets to 0 entire area) */
+	if (!ndev) {
+		printk("acx: no memory for netdevice structure\n");
+		goto fail_alloc_netdev;
+	}
+
+	ether_setup(ndev);
+	ndev->open = &acxpci_e_open;
+	ndev->stop = &acxpci_e_close;
+	ndev->hard_start_xmit = &acx_i_start_xmit;
+	ndev->get_stats = &acx_e_get_stats;
+#if IW_HANDLER_VERSION <= 5
+	ndev->get_wireless_stats = &acx_e_get_wireless_stats;
+#endif
+	ndev->wireless_handlers = (struct iw_handler_def *)&acx_ioctl_handler_def;
+	ndev->set_multicast_list = &acxpci_i_set_multicast_list;
+	ndev->tx_timeout = &acxpci_i_tx_timeout;
+	ndev->change_mtu = &acx_e_change_mtu;
+	ndev->watchdog_timeo = 4 * HZ;
+	ndev->irq = pdev->irq;
+	ndev->base_addr = pci_resource_start(pdev, 0);
+
+	adev = ndev2adev(ndev);
+	spin_lock_init(&adev->lock);	/* initial state: unlocked */
+	/* We do not start with downed sem: we want PARANOID_LOCKING to work */
+	sema_init(&adev->sem, 1);	/* initial state: 1 (upped) */
+	/* since nobody can see new netdev yet, we can as well
+	** just _presume_ that we're under sem (instead of actually taking it): */
+	/* acx_sem_lock(adev); */
+	adev->pdev = pdev;
+	adev->dev_type = DEVTYPE_PCI;
+	adev->chip_type = chip_type;
+	adev->chip_name = chip_name;
+	adev->io = (CHIPTYPE_ACX100 == chip_type) ? IO_ACX100 : IO_ACX111;
+	adev->membase = phymem1;
+	adev->iobase = mem1;
+	adev->membase2 = phymem2;
+	adev->iobase2 = mem2;
+	/* to find crashes due to weird driver access
+	 * to unconfigured interface (ifup) */
+	adev->mgmt_timer.function = (void (*)(unsigned long))0x0000dead;
+
+#ifdef NONESSENTIAL_FEATURES
+	acx_show_card_eeprom_id(adev);
+#endif /* NONESSENTIAL_FEATURES */
+
+#ifdef SET_MODULE_OWNER
+	SET_MODULE_OWNER(ndev);
+#endif
+	SET_NETDEV_DEV(ndev, &pdev->dev);
+
+	/* register new dev in linked list */
+	acxpci_s_device_chain_add(ndev);
+
+	log(L_IRQ|L_INIT, "using IRQ %d\n", pdev->irq);
+
+	/* need to be able to restore PCI state after a suspend */
+	pci_save_state(pdev);
+	pci_set_drvdata(pdev, ndev);
+
+	/* ok, pci setup is finished, now start initializing the card */
+
+	/* NB: read_reg() reads may return bogus data before reset_dev(),
+	 * since the firmware which directly controls large parts of the I/O
+	 * registers isn't initialized yet.
+	 * acx100 seems to be more affected than acx111 */
+	if (OK != acxpci_s_reset_dev(adev))
+		goto fail_reset;
+
+	if (OK != acxpci_read_eeprom_byte(adev, 0x05, &adev->eeprom_version))
+		goto fail_read_eeprom_version;
+
+	if (IS_ACX100(adev)) {
+		/* ACX100: configopt struct in cmd mailbox - directly after reset */
+		memcpy_fromio(&co, adev->cmd_area, sizeof(co));
+	}
+
+	if (OK != acx_s_init_mac(adev))
+		goto fail_init_mac;
+
+	if (IS_ACX111(adev)) {
+		/* ACX111: configopt struct needs to be queried after full init */
+		acx_s_interrogate(adev, &co, ACX111_IE_CONFIG_OPTIONS);
+	}
+
+//TODO: merge them into one function, they are called just once and are the same for pci & usb
+	acx_s_parse_configoption(adev, &co);
+	acx_s_set_defaults(adev);
+	acx_s_get_firmware_version(adev); /* needs to be after acx_s_init_mac() */
+	acx_display_hardware_details(adev);
+
+	/* Register the card, AFTER everything else has been set up,
+	 * since otherwise an ioctl could step on our feet due to
+	 * firmware operations happening in parallel or uninitialized data */
+	err = register_netdev(ndev);
+	if (OK != err) {
+		printk("acx: register_netdev() FAILED: %d\n", err);
+		goto fail_register_netdev;
+	}
+
+	acx_proc_register_entries(ndev);
+
+	/* Now we have our device, so make sure the kernel doesn't try
+	 * to send packets even though we're not associated to a network yet */
+	acx_stop_queue(ndev, "on probe");
+	acx_carrier_off(ndev, "on probe");
+
+	/* after register_netdev() userspace may start working with dev
+	 * (in particular, on other CPUs), we only need to up the sem */
+	/* acx_sem_unlock(adev); */
+
+	printk("acx "ACX_RELEASE": net device %s, driver compiled "
+		"against wireless extensions %d and Linux %s\n",
+		ndev->name, WIRELESS_EXT, UTS_RELEASE);
+
+#if CMD_DISCOVERY
+	great_inquisitor(adev);
+#endif
+
+	result = OK;
+	goto done;
+
+	/* error paths: undo everything in reverse order... */
+
+fail_register_netdev:
+
+	acxpci_s_delete_dma_regions(adev);
+	pci_set_drvdata(pdev, NULL);
+
+fail_init_mac:
+fail_read_eeprom_version:
+fail_reset:
+
+	acxpci_s_device_chain_remove(ndev);
+	free_netdev(ndev);
+fail_alloc_netdev:
+fail_irq:
+
+	iounmap(mem2);
+fail_ioremap2:
+
+	iounmap(mem1);
+fail_ioremap1:
+
+	release_mem_region(pci_resource_start(pdev, mem_region2),
+			   pci_resource_len(pdev, mem_region2));
+fail_request_mem_region2:
+
+	release_mem_region(pci_resource_start(pdev, mem_region1),
+			   pci_resource_len(pdev, mem_region1));
+fail_request_mem_region1:
+fail_unknown_chiptype:
+
+	pci_disable_device(pdev);
+fail_pci_enable_device:
+
+	pci_set_power_state(pdev, PCI_D3hot);
+
+done:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acxpci_e_remove
+**
+** Deallocate PCI resources for the acx chip.
+**
+** This should NOT execute any other hardware operations on the card,
+** since the card might already be ejected. Instead, that should be done
+** in cleanup_module, since the card is most likely still available there.
+**
+** pdev - ptr to PCI device structure containing info about pci configuration
+*/
+static void __devexit
+acxpci_e_remove(struct pci_dev *pdev)
+{
+	struct net_device *ndev;
+	acx_device_t *adev;
+	unsigned long mem_region1, mem_region2;
+
+	FN_ENTER;
+
+	ndev = (struct net_device*) pci_get_drvdata(pdev);
+	if (!ndev) {
+		log(L_DEBUG, "%s: card is unused. Skipping any release code\n",
+			__func__);
+		goto end;
+	}
+
+	adev = ndev2adev(ndev);
+
+	/* unregister the device to not let the kernel
+	 * (e.g. ioctls) access a half-deconfigured device
+	 * NB: this will cause acxpci_e_close() to be called,
+	 * thus we shouldn't call it under sem! */
+	log(L_INIT, "removing device %s\n", ndev->name);
+	unregister_netdev(ndev);
+
+	/* unregister_netdev ensures that no references to us left.
+	 * For paranoid reasons we continue to follow the rules */
+	acx_sem_lock(adev);
+
+	if (IS_ACX100(adev)) {
+		mem_region1 = PCI_ACX100_REGION1;
+		mem_region2 = PCI_ACX100_REGION2;
+	} else {
+		mem_region1 = PCI_ACX111_REGION1;
+		mem_region2 = PCI_ACX111_REGION2;
+	}
+
+	acx_proc_unregister_entries(ndev);
+
+	/* find our PCI device in the global acx list and remove it */
+	acxpci_s_device_chain_remove(ndev);
+
+	if (adev->dev_state_mask & ACX_STATE_IFACE_UP)
+		acxpci_s_down(ndev);
+
+	CLEAR_BIT(adev->dev_state_mask, ACX_STATE_IFACE_UP);
+
+	acxpci_s_delete_dma_regions(adev);
+
+	/* finally, clean up PCI bus state */
+	if (adev->iobase) iounmap(adev->iobase);
+	if (adev->iobase2) iounmap(adev->iobase2);
+
+	release_mem_region(pci_resource_start(pdev, mem_region1),
+			   pci_resource_len(pdev, mem_region1));
+
+	release_mem_region(pci_resource_start(pdev, mem_region2),
+			   pci_resource_len(pdev, mem_region2));
+
+	pci_disable_device(pdev);
+
+	/* remove dev registration */
+	pci_set_drvdata(pdev, NULL);
+
+	/* Free netdev (quite late,
+	 * since otherwise we might get caught off-guard
+	 * by a netdev timeout handler execution
+	 * expecting to see a working dev...) */
+	free_netdev(ndev);
+
+	/* put device into ACPI D3 mode (shutdown) */
+	pci_set_power_state(pdev, PCI_D3hot);
+
+end:
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** TODO: PM code needs to be fixed / debugged / tested.
+*/
+#ifdef CONFIG_PM
+static int
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
+acxpci_e_suspend(struct pci_dev *pdev, pm_message_t state)
+#else
+acxpci_e_suspend(struct pci_dev *pdev, u32 state)
+#endif
+{
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	acx_device_t *adev;
+
+	FN_ENTER;
+	printk("acx: suspend handler is experimental!\n");
+	printk("sus: dev %p\n", ndev);
+
+	if (!netif_running(ndev))
+		goto end;
+
+	adev = ndev2adev(ndev);
+	printk("sus: adev %p\n", adev);
+
+	acx_sem_lock(adev);
+
+	netif_device_detach(ndev);	/* this one cannot sleep */
+	acxpci_s_down(ndev);
+	/* down() does not set it to 0xffff, but here we really want that */
+	write_reg16(adev, IO_ACX_IRQ_MASK, 0xffff);
+	write_reg16(adev, IO_ACX_FEMR, 0x0);
+	acxpci_s_delete_dma_regions(adev);
+	pci_save_state(pdev);
+	pci_set_power_state(pdev, PCI_D3hot);
+
+	acx_sem_unlock(adev);
+end:
+	FN_EXIT0;
+	return OK;
+}
+
+
+static int
+acxpci_e_resume(struct pci_dev *pdev)
+{
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	acx_device_t *adev;
+
+	FN_ENTER;
+
+	printk("acx: resume handler is experimental!\n");
+	printk("rsm: got dev %p\n", ndev);
+
+	if (!netif_running(ndev))
+		goto end;
+
+	adev = ndev2adev(ndev);
+	printk("rsm: got adev %p\n", adev);
+
+	acx_sem_lock(adev);
+
+	pci_set_power_state(pdev, PCI_D0);
+	printk("rsm: power state PCI_D0 set\n");
+	pci_restore_state(pdev);
+	printk("rsm: PCI state restored\n");
+
+	if (OK != acxpci_s_reset_dev(adev))
+		goto end_unlock;
+	printk("rsm: device reset done\n");
+	if (OK != acx_s_init_mac(adev))
+		goto end_unlock;
+	printk("rsm: init MAC done\n");
+
+	acxpci_s_up(ndev);
+	printk("rsm: acx up done\n");
+
+	/* now even reload all card parameters as they were before suspend,
+	 * and possibly be back in the network again already :-) */
+	if (ACX_STATE_IFACE_UP & adev->dev_state_mask) {
+		adev->set_mask = GETSET_ALL;
+		acx_s_update_card_settings(adev);
+		printk("rsm: settings updated\n");
+	}
+	netif_device_attach(ndev);
+	printk("rsm: device attached\n");
+
+end_unlock:
+	acx_sem_unlock(adev);
+end:
+	/* we need to return OK here anyway, right? */
+	FN_EXIT0;
+	return OK;
+}
+#endif /* CONFIG_PM */
+
+
+/***********************************************************************
+** acxpci_s_up
+**
+** This function is called by acxpci_e_open (when ifconfig sets the device as up)
+**
+** Side effects:
+** - Enables on-card interrupt requests
+** - calls acx_s_start
+*/
+
+static void
+enable_acx_irq(acx_device_t *adev)
+{
+	FN_ENTER;
+	write_reg16(adev, IO_ACX_IRQ_MASK, adev->irq_mask);
+	write_reg16(adev, IO_ACX_FEMR, 0x8000);
+	adev->irqs_active = 1;
+	FN_EXIT0;
+}
+
+static void
+acxpci_s_up(struct net_device *ndev)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	unsigned long flags;
+
+	FN_ENTER;
+
+	acx_lock(adev, flags);
+	enable_acx_irq(adev);
+	acx_unlock(adev, flags);
+
+	/* acx fw < 1.9.3.e has a hardware timer, and older drivers
+	** used to use it. But we don't do that anymore, our OS
+	** has reliable software timers */
+	init_timer(&adev->mgmt_timer);
+	adev->mgmt_timer.function = acx_i_timer;
+	adev->mgmt_timer.data = (unsigned long)adev;
+
+	/* Need to set ACX_STATE_IFACE_UP first, or else
+	** timer won't be started by acx_set_status() */
+	SET_BIT(adev->dev_state_mask, ACX_STATE_IFACE_UP);
+	switch (adev->mode) {
+	case ACX_MODE_0_ADHOC:
+	case ACX_MODE_2_STA:
+		/* actual scan cmd will happen in start() */
+		acx_set_status(adev, ACX_STATUS_1_SCANNING); break;
+	case ACX_MODE_3_AP:
+	case ACX_MODE_MONITOR:
+		acx_set_status(adev, ACX_STATUS_4_ASSOCIATED); break;
+	}
+
+	acx_s_start(adev);
+
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acxpci_s_down
+**
+** This disables the netdevice
+**
+** Side effects:
+** - disables on-card interrupt request
+*/
+
+static void
+disable_acx_irq(acx_device_t *adev)
+{
+	FN_ENTER;
+
+	/* I guess mask is not 0xffff because acx100 won't signal
+	** cmd completion then (needed for ifup).
+	** Someone with acx100 please confirm */
+	write_reg16(adev, IO_ACX_IRQ_MASK, adev->irq_mask_off);
+	write_reg16(adev, IO_ACX_FEMR, 0x0);
+	adev->irqs_active = 0;
+	FN_EXIT0;
+}
+
+static void
+acxpci_s_down(struct net_device *ndev)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	unsigned long flags;
+
+	FN_ENTER;
+
+	/* Disable IRQs first, so that IRQs cannot race with us */
+	/* then wait until interrupts have finished executing on other CPUs */
+	acx_lock(adev, flags);
+	disable_acx_irq(adev);
+	synchronize_irq(adev->pdev->irq);
+	acx_unlock(adev, flags);
+
+	/* we really don't want to have an asynchronous tasklet disturb us
+	** after something vital for its job has been shut down, so
+	** end all remaining work now.
+	**
+	** NB: carrier_off (done by set_status below) would lead to
+	** not yet fully understood deadlock in FLUSH_SCHEDULED_WORK().
+	** That's why we do FLUSH first.
+	**
+	** NB2: we have a bad locking bug here: FLUSH_SCHEDULED_WORK()
+	** waits for acx_e_after_interrupt_task to complete if it is running
+	** on another CPU, but acx_e_after_interrupt_task
+	** will sleep on sem forever, because it is taken by us!
+	** Work around that by temporary sem unlock.
+	** This will fail miserably if we'll be hit by concurrent
+	** iwconfig or something in between. TODO! */
+	acx_sem_unlock(adev);
+	FLUSH_SCHEDULED_WORK();
+	acx_sem_lock(adev);
+
+	/* This is possible:
+	** FLUSH_SCHEDULED_WORK -> acx_e_after_interrupt_task ->
+	** -> set_status(ASSOCIATED) -> wake_queue()
+	** That's why we stop queue _after_ FLUSH_SCHEDULED_WORK
+	** lock/unlock is just paranoia, maybe not needed */
+	acx_lock(adev, flags);
+	acx_stop_queue(ndev, "on ifdown");
+	acx_set_status(adev, ACX_STATUS_0_STOPPED);
+	acx_unlock(adev, flags);
+
+	/* kernel/timer.c says it's illegal to del_timer_sync()
+	** a timer which restarts itself. We guarantee this cannot
+	** ever happen because acx_i_timer() never does this if
+	** status is ACX_STATUS_0_STOPPED */
+	del_timer_sync(&adev->mgmt_timer);
+
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acxpci_e_open
+**
+** Called as a result of SIOCSIFFLAGS ioctl changing the flags bit IFF_UP
+** from clear to set. In other words: ifconfig up.
+**
+** Returns:
+**	0	success
+**	>0	f/w reported error
+**	<0	driver reported error
+*/
+static int
+acxpci_e_open(struct net_device *ndev)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	int result = OK;
+
+	FN_ENTER;
+
+	acx_sem_lock(adev);
+
+	acx_init_task_scheduler(adev);
+
+//TODO: pci_set_power_state(pdev, PCI_D0); ?
+
+	/* request shared IRQ handler */
+	if (request_irq(ndev->irq, acxpci_i_interrupt, SA_SHIRQ, ndev->name, ndev)) {
+		printk("%s: request_irq FAILED\n", ndev->name);
+		result = -EAGAIN;
+		goto done;
+	}
+	log(L_DEBUG|L_IRQ, "request_irq %d successful\n", ndev->irq);
+
+	/* ifup device */
+	acxpci_s_up(ndev);
+
+	/* We don't currently have to do anything else.
+	 * The setup of the MAC should be subsequently completed via
+	 * the mlme commands.
+	 * Higher layers know we're ready from dev->start==1 and
+	 * dev->tbusy==0.  Our rx path knows to pass up received/
+	 * frames because of dev->flags&IFF_UP is true.
+	 */
+done:
+	acx_sem_unlock(adev);
+
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acxpci_e_close
+**
+** Called as a result of SIOCSIIFFLAGS ioctl changing the flags bit IFF_UP
+** from set to clear. I.e. called by "ifconfig DEV down"
+**
+** Returns:
+**	0	success
+**	>0	f/w reported error
+**	<0	driver reported error
+*/
+static int
+acxpci_e_close(struct net_device *ndev)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+
+	FN_ENTER;
+
+	acx_sem_lock(adev);
+
+	/* ifdown device */
+	CLEAR_BIT(adev->dev_state_mask, ACX_STATE_IFACE_UP);
+	if (netif_device_present(ndev)) {
+		acxpci_s_down(ndev);
+	}
+
+	/* disable all IRQs, release shared IRQ handler */
+	write_reg16(adev, IO_ACX_IRQ_MASK, 0xffff);
+	write_reg16(adev, IO_ACX_FEMR, 0x0);
+	free_irq(ndev->irq, ndev);
+
+//TODO: pci_set_power_state(pdev, PCI_D3hot); ?
+
+	/* We currently don't have to do anything else.
+	 * Higher layers know we're not ready from dev->start==0 and
+	 * dev->tbusy==1.  Our rx path knows to not pass up received
+	 * frames because of dev->flags&IFF_UP is false.
+	 */
+	acx_sem_unlock(adev);
+
+	log(L_INIT, "closed device\n");
+	FN_EXIT0;
+	return OK;
+}
+
+
+/***********************************************************************
+** acxpci_i_tx_timeout
+**
+** Called from network core. Must not sleep!
+*/
+static void
+acxpci_i_tx_timeout(struct net_device *ndev)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	unsigned long flags;
+	unsigned int tx_num_cleaned;
+
+	FN_ENTER;
+
+	acx_lock(adev, flags);
+
+	/* clean processed tx descs, they may have been completely full */
+	tx_num_cleaned = acxpci_l_clean_txdesc(adev);
+
+	/* nothing cleaned, yet (almost) no free buffers available?
+	 * --> clean all tx descs, no matter which status!!
+	 * Note that I strongly suspect that doing emergency cleaning
+	 * may confuse the firmware. This is a last ditch effort to get
+	 * ANYTHING to work again...
+	 *
+	 * TODO: it's best to simply reset & reinit hw from scratch...
+	 */
+	if ((adev->tx_free <= TX_EMERG_CLEAN) && (tx_num_cleaned == 0)) {
+		printk("%s: FAILED to free any of the many full tx buffers. "
+			"Switching to emergency freeing. "
+			"Please report!\n", ndev->name);
+		acxpci_l_clean_txdesc_emergency(adev);
+	}
+
+	if (acx_queue_stopped(ndev) && (ACX_STATUS_4_ASSOCIATED == adev->status))
+		acx_wake_queue(ndev, "after tx timeout");
+
+	/* stall may have happened due to radio drift, so recalib radio */
+	acx_schedule_task(adev, ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
+
+	/* do unimportant work last */
+	printk("%s: tx timeout!\n", ndev->name);
+	adev->stats.tx_errors++;
+
+	acx_unlock(adev, flags);
+
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acxpci_i_set_multicast_list
+** FIXME: most likely needs refinement
+*/
+static void
+acxpci_i_set_multicast_list(struct net_device *ndev)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	unsigned long flags;
+
+	FN_ENTER;
+
+	acx_lock(adev, flags);
+
+	/* firmwares don't have allmulti capability,
+	 * so just use promiscuous mode instead in this case. */
+	if (ndev->flags & (IFF_PROMISC|IFF_ALLMULTI)) {
+		SET_BIT(adev->rx_config_1, RX_CFG1_RCV_PROMISCUOUS);
+		CLEAR_BIT(adev->rx_config_1, RX_CFG1_FILTER_ALL_MULTI);
+		SET_BIT(adev->set_mask, SET_RXCONFIG);
+		/* let kernel know in case *we* needed to set promiscuous */
+		ndev->flags |= (IFF_PROMISC|IFF_ALLMULTI);
+	} else {
+		CLEAR_BIT(adev->rx_config_1, RX_CFG1_RCV_PROMISCUOUS);
+		SET_BIT(adev->rx_config_1, RX_CFG1_FILTER_ALL_MULTI);
+		SET_BIT(adev->set_mask, SET_RXCONFIG);
+		ndev->flags &= ~(IFF_PROMISC|IFF_ALLMULTI);
+	}
+
+	/* cannot update card settings directly here, atomic context */
+	acx_schedule_task(adev, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
+
+	acx_unlock(adev, flags);
+
+	FN_EXIT0;
+}
+
+
+/***************************************************************
+** acxpci_l_process_rxdesc
+**
+** Called directly and only from the IRQ handler
+*/
+
+#if !ACX_DEBUG
+static inline void log_rxbuffer(const acx_device_t *adev) {}
+#else
+static void
+log_rxbuffer(const acx_device_t *adev)
+{
+	register const struct rxhostdesc *rxhostdesc;
+	int i;
+	/* no FN_ENTER here, we don't want that */
+
+	rxhostdesc = adev->rxhostdesc_start;
+	if (unlikely(!rxhostdesc)) return;
+	for (i = 0; i < RX_CNT; i++) {
+		if ((rxhostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
+		 && (rxhostdesc->Status & cpu_to_le32(DESC_STATUS_FULL)))
+			printk("rx: buf %d full\n", i);
+		rxhostdesc++;
+	}
+}
+#endif
+
+static void
+acxpci_l_process_rxdesc(acx_device_t *adev)
+{
+	register rxhostdesc_t *hostdesc;
+	int count, tail;
+
+	FN_ENTER;
+
+	if (unlikely(acx_debug & L_BUFR))
+		log_rxbuffer(adev);
+
+	/* First, have a loop to determine the first descriptor that's
+	 * full, just in case there's a mismatch between our current
+	 * rx_tail and the full descriptor we're supposed to handle. */
+	tail = adev->rx_tail;
+	count = RX_CNT;
+	while (1) {
+		hostdesc = &adev->rxhostdesc_start[tail];
+		/* advance tail regardless of outcome of the below test */
+		tail = (tail + 1) % RX_CNT;
+
+		if ((hostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
+		 && (hostdesc->Status & cpu_to_le32(DESC_STATUS_FULL)))
+			break;		/* found it! */
+
+		if (unlikely(!--count))	/* hmm, no luck: all descs empty, bail out */
+			goto end;
+	}
+
+	/* now process descriptors, starting with the first we figured out */
+	while (1) {
+		log(L_BUFR, "rx: tail=%u Ctl_16=%04X Status=%08X\n",
+			tail, hostdesc->Ctl_16, hostdesc->Status);
+
+		acx_l_process_rxbuf(adev, hostdesc->data);
+
+		hostdesc->Status = 0;
+		/* flush all writes before adapter sees CTL_HOSTOWN change */
+		wmb();
+		/* Host no longer owns this, needs to be LAST */
+		CLEAR_BIT(hostdesc->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
+
+		/* ok, descriptor is handled, now check the next descriptor */
+		hostdesc = &adev->rxhostdesc_start[tail];
+
+		/* if next descriptor is empty, then bail out */
+		if (!(hostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
+		 || !(hostdesc->Status & cpu_to_le32(DESC_STATUS_FULL)))
+			break;
+
+		tail = (tail + 1) % RX_CNT;
+	}
+end:
+	adev->rx_tail = tail;
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acxpci_i_interrupt
+**
+** IRQ handler (atomic context, must not sleep, blah, blah)
+*/
+
+/* scan is complete. all frames now on the receive queue are valid */
+#define INFO_SCAN_COMPLETE      0x0001
+#define INFO_WEP_KEY_NOT_FOUND  0x0002
+/* hw has been reset as the result of a watchdog timer timeout */
+#define INFO_WATCH_DOG_RESET    0x0003
+/* failed to send out NULL frame from PS mode notification to AP */
+/* recommended action: try entering 802.11 PS mode again */
+#define INFO_PS_FAIL            0x0004
+/* encryption/decryption process on a packet failed */
+#define INFO_IV_ICV_FAILURE     0x0005
+
+/* Info mailbox format:
+2 bytes: type
+2 bytes: status
+more bytes may follow
+    rumors say about status:
+	0x0000 info available (set by hw)
+	0x0001 information received (must be set by host)
+	0x1000 info available, mailbox overflowed (messages lost) (set by hw)
+    but in practice we've seen:
+	0x9000 when we did not set status to 0x0001 on prev message
+	0x1001 when we did set it
+	0x0000 was never seen
+    conclusion: this is really a bitfield:
+    0x1000 is 'info available' bit
+    'mailbox overflowed' bit is 0x8000, not 0x1000
+    value of 0x0000 probably means that there are no messages at all
+    P.S. I dunno how in hell hw is supposed to notice that messages are lost -
+    it does NOT clear bit 0x0001, and this bit will probably stay forever set
+    after we set it once. Let's hope this will be fixed in firmware someday
+*/
+
+static void
+handle_info_irq(acx_device_t *adev)
+{
+#if ACX_DEBUG
+	static const char * const info_type_msg[] = {
+		"(unknown)",
+		"scan complete",
+		"WEP key not found",
+		"internal watchdog reset was done",
+		"failed to send powersave (NULL frame) notification to AP",
+		"encrypt/decrypt on a packet has failed",
+		"TKIP tx keys disabled",
+		"TKIP rx keys disabled",
+		"TKIP rx: key ID not found",
+		"???",
+		"???",
+		"???",
+		"???",
+		"???",
+		"???",
+		"???",
+		"TKIP IV value exceeds thresh"
+	};
+#endif
+	u32 info_type, info_status;
+
+	info_type = readl(adev->info_area);
+	info_status = (info_type >> 16);
+	info_type = (u16)info_type;
+
+	/* inform fw that we have read this info message */
+	writel(info_type | 0x00010000, adev->info_area);
+	write_reg16(adev, IO_ACX_INT_TRIG, INT_TRIG_INFOACK);
+	write_flush(adev);
+
+	log(L_CTL, "info_type:%04X info_status:%04X\n",
+			info_type, info_status);
+
+	log(L_IRQ, "got Info IRQ: status %04X type %04X: %s\n",
+		info_status, info_type,
+		info_type_msg[(info_type >= VEC_SIZE(info_type_msg)) ?
+				0 : info_type]
+	);
+}
+
+
+static void
+log_unusual_irq(u16 irqtype) {
+	/*
+	if (!printk_ratelimit())
+		return;
+	*/
+
+	printk("acx: got");
+	if (irqtype & HOST_INT_RX_DATA) {
+		printk(" Rx_Data");
+	}
+		/* HOST_INT_TX_COMPLETE   */
+	if (irqtype & HOST_INT_TX_XFER) {
+		printk(" Tx_Xfer");
+	}
+		/* HOST_INT_RX_COMPLETE   */
+	if (irqtype & HOST_INT_DTIM) {
+		printk(" DTIM");
+	}
+	if (irqtype & HOST_INT_BEACON) {
+		printk(" Beacon");
+	}
+	if (irqtype & HOST_INT_TIMER) {
+		log(L_IRQ, " Timer");
+	}
+	if (irqtype & HOST_INT_KEY_NOT_FOUND) {
+		printk(" Key_Not_Found");
+	}
+	if (irqtype & HOST_INT_IV_ICV_FAILURE) {
+		printk(" IV_ICV_Failure");
+	}
+		/* HOST_INT_CMD_COMPLETE  */
+		/* HOST_INT_INFO          */
+	if (irqtype & HOST_INT_OVERFLOW) {
+		printk(" Overflow");
+	}
+	if (irqtype & HOST_INT_PROCESS_ERROR) {
+		printk(" Process_Error");
+	}
+		/* HOST_INT_SCAN_COMPLETE */
+	if (irqtype & HOST_INT_FCS_THRESHOLD) {
+		printk(" FCS_Threshold");
+	}
+	if (irqtype & HOST_INT_UNKNOWN) {
+		printk(" Unknown");
+	}
+	printk(" IRQ(s)\n");
+}
+
+
+static void
+update_link_quality_led(acx_device_t *adev)
+{
+	int qual;
+
+	qual = acx_signal_determine_quality(adev->wstats.qual.level, adev->wstats.qual.noise);
+	if (qual > adev->brange_max_quality)
+		qual = adev->brange_max_quality;
+
+	if (time_after(jiffies, adev->brange_time_last_state_change +
+				(HZ/2 - HZ/2 * (unsigned long)qual / adev->brange_max_quality ) )) {
+		acxpci_l_power_led(adev, (adev->brange_last_state == 0));
+		adev->brange_last_state ^= 1; /* toggle */
+		adev->brange_time_last_state_change = jiffies;
+	}
+}
+
+
+#define MAX_IRQLOOPS_PER_JIFFY  (20000/HZ) /* a la orinoco.c */
+
+static irqreturn_t
+acxpci_i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	acx_device_t *adev;
+	unsigned long flags;
+	unsigned int irqcount = MAX_IRQLOOPS_PER_JIFFY;
+	register u16 irqtype;
+	u16 unmasked;
+
+	adev = ndev2adev((struct net_device*)dev_id);
+
+	/* LOCKING: can just spin_lock() since IRQs are disabled anyway.
+	 * I am paranoid */
+	acx_lock(adev, flags);
+
+	unmasked = read_reg16(adev, IO_ACX_IRQ_STATUS_CLEAR);
+	if (unlikely(0xffff == unmasked)) {
+		/* 0xffff value hints at missing hardware,
+		 * so don't do anything.
+		 * Not very clean, but other drivers do the same... */
+		log(L_IRQ, "IRQ type:FFFF - device removed? IRQ_NONE\n");
+		goto none;
+	}
+
+	/* We will check only "interesting" IRQ types */
+	irqtype = unmasked & ~adev->irq_mask;
+	if (!irqtype) {
+		/* We are on a shared IRQ line and it wasn't our IRQ */
+		log(L_IRQ, "IRQ type:%04X, mask:%04X - all are masked, IRQ_NONE\n",
+			unmasked, adev->irq_mask);
+		goto none;
+	}
+
+	/* Done here because IRQ_NONEs taking three lines of log
+	** drive me crazy */
+	FN_ENTER;
+
+#define IRQ_ITERATE 1
+#if IRQ_ITERATE
+if (jiffies != adev->irq_last_jiffies) {
+	adev->irq_loops_this_jiffy = 0;
+	adev->irq_last_jiffies = jiffies;
+}
+
+/* safety condition; we'll normally abort loop below
+ * in case no IRQ type occurred */
+while (likely(--irqcount)) {
+#endif
+	/* ACK all IRQs ASAP */
+	write_reg16(adev, IO_ACX_IRQ_ACK, 0xffff);
+
+	log(L_IRQ, "IRQ type:%04X, mask:%04X, type & ~mask:%04X\n",
+				unmasked, adev->irq_mask, irqtype);
+
+	/* Handle most important IRQ types first */
+	if (irqtype & HOST_INT_RX_COMPLETE) {
+		log(L_IRQ, "got Rx_Complete IRQ\n");
+		acxpci_l_process_rxdesc(adev);
+	}
+	if (irqtype & HOST_INT_TX_COMPLETE) {
+		log(L_IRQ, "got Tx_Complete IRQ\n");
+		/* don't clean up on each Tx complete, wait a bit
+		 * unless we're going towards full, in which case
+		 * we do it immediately, too (otherwise we might lockup
+		 * with a full Tx buffer if we go into
+		 * acxpci_l_clean_txdesc() at a time when we won't wakeup
+		 * the net queue in there for some reason...) */
+		if (adev->tx_free <= TX_START_CLEAN) {
+#if TX_CLEANUP_IN_SOFTIRQ
+			acx_schedule_task(adev, ACX_AFTER_IRQ_TX_CLEANUP);
+#else
+			acxpci_l_clean_txdesc(adev);
+#endif
+		}
+	}
+
+	/* Less frequent ones */
+	if (irqtype & (0
+		| HOST_INT_CMD_COMPLETE
+		| HOST_INT_INFO
+		| HOST_INT_SCAN_COMPLETE
+	)) {
+		if (irqtype & HOST_INT_CMD_COMPLETE) {
+			log(L_IRQ, "got Command_Complete IRQ\n");
+			/* save the state for the running issue_cmd() */
+			SET_BIT(adev->irq_status, HOST_INT_CMD_COMPLETE);
+		}
+		if (irqtype & HOST_INT_INFO) {
+			handle_info_irq(adev);
+		}
+		if (irqtype & HOST_INT_SCAN_COMPLETE) {
+			log(L_IRQ, "got Scan_Complete IRQ\n");
+			/* need to do that in process context */
+			acx_schedule_task(adev, ACX_AFTER_IRQ_COMPLETE_SCAN);
+			/* remember that fw is not scanning anymore */
+			SET_BIT(adev->irq_status, HOST_INT_SCAN_COMPLETE);
+		}
+	}
+
+	/* These we just log, but either they happen rarely
+	 * or we keep them masked out */
+	if (irqtype & (0
+		| HOST_INT_RX_DATA
+		/* | HOST_INT_TX_COMPLETE   */
+		| HOST_INT_TX_XFER
+		/* | HOST_INT_RX_COMPLETE   */
+		| HOST_INT_DTIM
+		| HOST_INT_BEACON
+		| HOST_INT_TIMER
+		| HOST_INT_KEY_NOT_FOUND
+		| HOST_INT_IV_ICV_FAILURE
+		/* | HOST_INT_CMD_COMPLETE  */
+		/* | HOST_INT_INFO          */
+		| HOST_INT_OVERFLOW
+		| HOST_INT_PROCESS_ERROR
+		/* | HOST_INT_SCAN_COMPLETE */
+		| HOST_INT_FCS_THRESHOLD
+		| HOST_INT_UNKNOWN
+	)) {
+		log_unusual_irq(irqtype);
+	}
+
+#if IRQ_ITERATE
+	unmasked = read_reg16(adev, IO_ACX_IRQ_STATUS_CLEAR);
+	irqtype = unmasked & ~adev->irq_mask;
+	/* Bail out if no new IRQ bits or if all are masked out */
+	if (!irqtype)
+		break;
+
+	if (unlikely(++adev->irq_loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY)) {
+		printk(KERN_ERR "acx: too many interrupts per jiffy!\n");
+		/* Looks like card floods us with IRQs! Try to stop that */
+		write_reg16(adev, IO_ACX_IRQ_MASK, 0xffff);
+		/* This will short-circuit all future attempts to handle IRQ.
+		 * We cant do much more... */
+		adev->irq_mask = 0;
+		break;
+	}
+}
+#endif
+	/* Routine to perform blink with range */
+	if (unlikely(adev->led_power == 2))
+		update_link_quality_led(adev);
+
+/* handled: */
+	/* write_flush(adev); - not needed, last op was read anyway */
+	acx_unlock(adev, flags);
+	FN_EXIT0;
+	return IRQ_HANDLED;
+
+none:
+	acx_unlock(adev, flags);
+	return IRQ_NONE;
+}
+
+
+/***********************************************************************
+** acxpci_l_power_led
+*/
+void
+acxpci_l_power_led(acx_device_t *adev, int enable)
+{
+	u16 gpio_pled =	IS_ACX111(adev) ? 0x0040 : 0x0800;
+
+	/* A hack. Not moving message rate limiting to adev->xxx
+	 * (it's only a debug message after all) */
+	static int rate_limit = 0;
+
+	if (rate_limit++ < 3)
+		log(L_IOCTL, "Please report in case toggling the power "
+				"LED doesn't work for your card!\n");
+	if (enable)
+		write_reg16(adev, IO_ACX_GPIO_OUT,
+			read_reg16(adev, IO_ACX_GPIO_OUT) & ~gpio_pled);
+	else
+		write_reg16(adev, IO_ACX_GPIO_OUT,
+			read_reg16(adev, IO_ACX_GPIO_OUT) | gpio_pled);
+}
+
+
+/***********************************************************************
+** Ioctls
+*/
+
+/***********************************************************************
+*/
+int
+acx111pci_ioctl_info(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	struct iw_param *vwrq,
+	char *extra)
+{
+#if ACX_DEBUG > 1
+	acx_device_t *adev = ndev2adev(ndev);
+	rxdesc_t *rxdesc;
+	txdesc_t *txdesc;
+	rxhostdesc_t *rxhostdesc;
+	txhostdesc_t *txhostdesc;
+	struct acx111_ie_memoryconfig memconf;
+	struct acx111_ie_queueconfig queueconf;
+	unsigned long flags;
+	int i;
+	char memmap[0x34];
+	char rxconfig[0x8];
+	char fcserror[0x8];
+	char ratefallback[0x5];
+
+	if ( !(acx_debug & (L_IOCTL|L_DEBUG)) )
+		return OK;
+	/* using printk() since we checked debug flag already */
+
+	acx_sem_lock(adev);
+
+	if (!IS_ACX111(adev)) {
+		printk("acx111-specific function called "
+			"with non-acx111 chip, aborting\n");
+		goto end_ok;
+	}
+
+	/* get Acx111 Memory Configuration */
+	memset(&memconf, 0, sizeof(memconf));
+	/* BTW, fails with 12 (Write only) error code.
+	** Retained for easy testing of issue_cmd error handling :) */
+	acx_s_interrogate(adev, &memconf, ACX1xx_IE_QUEUE_CONFIG);
+
+	/* get Acx111 Queue Configuration */
+	memset(&queueconf, 0, sizeof(queueconf));
+	acx_s_interrogate(adev, &queueconf, ACX1xx_IE_MEMORY_CONFIG_OPTIONS);
+
+	/* get Acx111 Memory Map */
+	memset(memmap, 0, sizeof(memmap));
+	acx_s_interrogate(adev, &memmap, ACX1xx_IE_MEMORY_MAP);
+
+	/* get Acx111 Rx Config */
+	memset(rxconfig, 0, sizeof(rxconfig));
+	acx_s_interrogate(adev, &rxconfig, ACX1xx_IE_RXCONFIG);
+
+	/* get Acx111 fcs error count */
+	memset(fcserror, 0, sizeof(fcserror));
+	acx_s_interrogate(adev, &fcserror, ACX1xx_IE_FCS_ERROR_COUNT);
+
+	/* get Acx111 rate fallback */
+	memset(ratefallback, 0, sizeof(ratefallback));
+	acx_s_interrogate(adev, &ratefallback, ACX1xx_IE_RATE_FALLBACK);
+
+	/* force occurrence of a beacon interrupt */
+	/* TODO: comment why is this necessary */
+	write_reg16(adev, IO_ACX_HINT_TRIG, HOST_INT_BEACON);
+
+	/* dump Acx111 Mem Configuration */
+	printk("dump mem config:\n"
+		"data read: %d, struct size: %d\n"
+		"Number of stations: %1X\n"
+		"Memory block size: %1X\n"
+		"tx/rx memory block allocation: %1X\n"
+		"count rx: %X / tx: %X queues\n"
+		"options %1X\n"
+		"fragmentation %1X\n"
+		"Rx Queue 1 Count Descriptors: %X\n"
+		"Rx Queue 1 Host Memory Start: %X\n"
+		"Tx Queue 1 Count Descriptors: %X\n"
+		"Tx Queue 1 Attributes: %X\n",
+		memconf.len, (int) sizeof(memconf),
+		memconf.no_of_stations,
+		memconf.memory_block_size,
+		memconf.tx_rx_memory_block_allocation,
+		memconf.count_rx_queues, memconf.count_tx_queues,
+		memconf.options,
+		memconf.fragmentation,
+		memconf.rx_queue1_count_descs,
+	acx2cpu(memconf.rx_queue1_host_rx_start),
+		memconf.tx_queue1_count_descs,
+		memconf.tx_queue1_attributes);
+
+	/* dump Acx111 Queue Configuration */
+	printk("dump queue head:\n"
+		"data read: %d, struct size: %d\n"
+		"tx_memory_block_address (from card): %X\n"
+		"rx_memory_block_address (from card): %X\n"
+		"rx1_queue address (from card): %X\n"
+		"tx1_queue address (from card): %X\n"
+		"tx1_queue attributes (from card): %X\n",
+		queueconf.len, (int) sizeof(queueconf),
+		queueconf.tx_memory_block_address,
+		queueconf.rx_memory_block_address,
+		queueconf.rx1_queue_address,
+		queueconf.tx1_queue_address,
+		queueconf.tx1_attributes);
+
+	/* dump Acx111 Mem Map */
+	printk("dump mem map:\n"
+		"data read: %d, struct size: %d\n"
+		"Code start: %X\n"
+		"Code end: %X\n"
+		"WEP default key start: %X\n"
+		"WEP default key end: %X\n"
+		"STA table start: %X\n"
+		"STA table end: %X\n"
+		"Packet template start: %X\n"
+		"Packet template end: %X\n"
+		"Queue memory start: %X\n"
+		"Queue memory end: %X\n"
+		"Packet memory pool start: %X\n"
+		"Packet memory pool end: %X\n"
+		"iobase: %p\n"
+		"iobase2: %p\n",
+		*((u16 *)&memmap[0x02]), (int) sizeof(memmap),
+		*((u32 *)&memmap[0x04]),
+		*((u32 *)&memmap[0x08]),
+		*((u32 *)&memmap[0x0C]),
+		*((u32 *)&memmap[0x10]),
+		*((u32 *)&memmap[0x14]),
+		*((u32 *)&memmap[0x18]),
+		*((u32 *)&memmap[0x1C]),
+		*((u32 *)&memmap[0x20]),
+		*((u32 *)&memmap[0x24]),
+		*((u32 *)&memmap[0x28]),
+		*((u32 *)&memmap[0x2C]),
+		*((u32 *)&memmap[0x30]),
+		adev->iobase,
+		adev->iobase2);
+
+	/* dump Acx111 Rx Config */
+	printk("dump rx config:\n"
+		"data read: %d, struct size: %d\n"
+		"rx config: %X\n"
+		"rx filter config: %X\n",
+		*((u16 *)&rxconfig[0x02]), (int) sizeof(rxconfig),
+		*((u16 *)&rxconfig[0x04]),
+		*((u16 *)&rxconfig[0x06]));
+
+	/* dump Acx111 fcs error */
+	printk("dump fcserror:\n"
+		"data read: %d, struct size: %d\n"
+		"fcserrors: %X\n",
+		*((u16 *)&fcserror[0x02]), (int) sizeof(fcserror),
+		*((u32 *)&fcserror[0x04]));
+
+	/* dump Acx111 rate fallback */
+	printk("dump rate fallback:\n"
+		"data read: %d, struct size: %d\n"
+		"ratefallback: %X\n",
+		*((u16 *)&ratefallback[0x02]), (int) sizeof(ratefallback),
+		*((u8 *)&ratefallback[0x04]));
+
+	/* protect against IRQ */
+	acx_lock(adev, flags);
+
+	/* dump acx111 internal rx descriptor ring buffer */
+	rxdesc = adev->rxdesc_start;
+
+	/* loop over complete receive pool */
+	if (rxdesc) for (i = 0; i < RX_CNT; i++) {
+		printk("\ndump internal rxdesc %d:\n"
+			"mem pos %p\n"
+			"next 0x%X\n"
+			"acx mem pointer (dynamic) 0x%X\n"
+			"CTL (dynamic) 0x%X\n"
+			"Rate (dynamic) 0x%X\n"
+			"RxStatus (dynamic) 0x%X\n"
+			"Mod/Pre (dynamic) 0x%X\n",
+			i,
+			rxdesc,
+			acx2cpu(rxdesc->pNextDesc),
+			acx2cpu(rxdesc->ACXMemPtr),
+			rxdesc->Ctl_8,
+			rxdesc->rate,
+			rxdesc->error,
+			rxdesc->SNR);
+		rxdesc++;
+	}
+
+	/* dump host rx descriptor ring buffer */
+
+	rxhostdesc = adev->rxhostdesc_start;
+
+	/* loop over complete receive pool */
+	if (rxhostdesc) for (i = 0; i < RX_CNT; i++) {
+		printk("\ndump host rxdesc %d:\n"
+			"mem pos %p\n"
+			"buffer mem pos 0x%X\n"
+			"buffer mem offset 0x%X\n"
+			"CTL 0x%X\n"
+			"Length 0x%X\n"
+			"next 0x%X\n"
+			"Status 0x%X\n",
+			i,
+			rxhostdesc,
+			acx2cpu(rxhostdesc->data_phy),
+			rxhostdesc->data_offset,
+			le16_to_cpu(rxhostdesc->Ctl_16),
+			le16_to_cpu(rxhostdesc->length),
+			acx2cpu(rxhostdesc->desc_phy_next),
+			rxhostdesc->Status);
+		rxhostdesc++;
+	}
+
+	/* dump acx111 internal tx descriptor ring buffer */
+	txdesc = adev->txdesc_start;
+
+	/* loop over complete transmit pool */
+	if (txdesc) for (i = 0; i < TX_CNT; i++) {
+		printk("\ndump internal txdesc %d:\n"
+			"size 0x%X\n"
+			"mem pos %p\n"
+			"next 0x%X\n"
+			"acx mem pointer (dynamic) 0x%X\n"
+			"host mem pointer (dynamic) 0x%X\n"
+			"length (dynamic) 0x%X\n"
+			"CTL (dynamic) 0x%X\n"
+			"CTL2 (dynamic) 0x%X\n"
+			"Status (dynamic) 0x%X\n"
+			"Rate (dynamic) 0x%X\n",
+			i,
+			(int) sizeof(struct txdesc),
+			txdesc,
+			acx2cpu(txdesc->pNextDesc),
+			acx2cpu(txdesc->AcxMemPtr),
+			acx2cpu(txdesc->HostMemPtr),
+			le16_to_cpu(txdesc->total_length),
+			txdesc->Ctl_8,
+			txdesc->Ctl2_8, txdesc->error,
+			txdesc->u.r1.rate);
+		txdesc = advance_txdesc(adev, txdesc, 1);
+	}
+
+	/* dump host tx descriptor ring buffer */
+
+	txhostdesc = adev->txhostdesc_start;
+
+	/* loop over complete host send pool */
+	if (txhostdesc) for (i = 0; i < TX_CNT * 2; i++) {
+		printk("\ndump host txdesc %d:\n"
+			"mem pos %p\n"
+			"buffer mem pos 0x%X\n"
+			"buffer mem offset 0x%X\n"
+			"CTL 0x%X\n"
+			"Length 0x%X\n"
+			"next 0x%X\n"
+			"Status 0x%X\n",
+			i,
+			txhostdesc,
+			acx2cpu(txhostdesc->data_phy),
+			txhostdesc->data_offset,
+			le16_to_cpu(txhostdesc->Ctl_16),
+			le16_to_cpu(txhostdesc->length),
+			acx2cpu(txhostdesc->desc_phy_next),
+			le32_to_cpu(txhostdesc->Status));
+		txhostdesc++;
+	}
+
+	/* write_reg16(adev, 0xb4, 0x4); */
+
+	acx_unlock(adev, flags);
+end_ok:
+
+	acx_sem_unlock(adev);
+#endif /* ACX_DEBUG */
+	return OK;
+}
+
+
+/***********************************************************************
+*/
+int
+acx100pci_ioctl_set_phy_amp_bias(
+	struct net_device *ndev,
+	struct iw_request_info *info,
+	struct iw_param *vwrq,
+	char *extra)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	unsigned long flags;
+	u16 gpio_old;
+
+	if (!IS_ACX100(adev)) {
+		/* WARNING!!!
+		 * Removing this check *might* damage
+		 * hardware, since we're tweaking GPIOs here after all!!!
+		 * You've been warned...
+		 * WARNING!!! */
+		printk("acx: sorry, setting bias level for non-acx100 "
+			"is not supported yet\n");
+		return OK;
+	}
+
+	if (*extra > 7)	{
+		printk("acx: invalid bias parameter, range is 0-7\n");
+		return -EINVAL;
+	}
+
+	acx_sem_lock(adev);
+
+	/* Need to lock accesses to [IO_ACX_GPIO_OUT]:
+	 * IRQ handler uses it to update LED */
+	acx_lock(adev, flags);
+	gpio_old = read_reg16(adev, IO_ACX_GPIO_OUT);
+	write_reg16(adev, IO_ACX_GPIO_OUT, (gpio_old & 0xf8ff) | ((u16)*extra << 8));
+	acx_unlock(adev, flags);
+
+	log(L_DEBUG, "gpio_old: 0x%04X\n", gpio_old);
+	printk("%s: PHY power amplifier bias: old:%d, new:%d\n",
+		ndev->name,
+		(gpio_old & 0x0700) >> 8, (unsigned char)*extra);
+
+	acx_sem_unlock(adev);
+
+	return OK;
+}
+
+
+/***************************************************************
+** acxpci_l_alloc_tx
+** Actually returns a txdesc_t* ptr
+**
+** FIXME: in case of fragments, should allocate multiple descrs
+** after figuring out how many we need and whether we still have
+** sufficiently many.
+*/
+tx_t*
+acxpci_l_alloc_tx(acx_device_t *adev)
+{
+	struct txdesc *txdesc;
+	int head;
+	u8 ctl8;
+
+	FN_ENTER;
+
+	if (unlikely(!adev->tx_free)) {
+		printk("acx: BUG: no free txdesc left\n");
+		txdesc = NULL;
+		goto end;
+	}
+
+	head = adev->tx_head;
+	txdesc = get_txdesc(adev, head);
+	ctl8 = txdesc->Ctl_8;
+
+	/* 2005-10-11: there were several bug reports on this happening
+	** but now cause seems to be understood & fixed */
+	if (unlikely(DESC_CTL_HOSTOWN != (ctl8 & DESC_CTL_ACXDONE_HOSTOWN))) {
+		/* whoops, descr at current index is not free, so probably
+		 * ring buffer already full */
+		printk("acx: BUG: tx_head:%d Ctl8:0x%02X - failed to find "
+			"free txdesc\n", head, ctl8);
+		txdesc = NULL;
+		goto end;
+	}
+
+	/* Needed in case txdesc won't be eventually submitted for tx */
+	txdesc->Ctl_8 = DESC_CTL_ACXDONE_HOSTOWN;
+
+	adev->tx_free--;
+	log(L_BUFT, "tx: got desc %u, %u remain\n",
+			head, adev->tx_free);
+	/* Keep a few free descs between head and tail of tx ring.
+	** It is not absolutely needed, just feels safer */
+	if (adev->tx_free < TX_STOP_QUEUE) {
+		log(L_BUF, "stop queue (%u tx desc left)\n",
+				adev->tx_free);
+		acx_stop_queue(adev->ndev, NULL);
+	}
+
+	/* returning current descriptor, so advance to next free one */
+	adev->tx_head = (head + 1) % TX_CNT;
+end:
+	FN_EXIT0;
+
+	return (tx_t*)txdesc;
+}
+
+
+/***********************************************************************
+*/
+void*
+acxpci_l_get_txbuf(acx_device_t *adev, tx_t* tx_opaque)
+{
+	return get_txhostdesc(adev, (txdesc_t*)tx_opaque)->data;
+}
+
+
+/***********************************************************************
+** acxpci_l_tx_data
+**
+** Can be called from IRQ (rx -> (AP bridging or mgmt response) -> tx).
+** Can be called from acx_i_start_xmit (data frames from net core).
+**
+** FIXME: in case of fragments, should loop over the number of
+** pre-allocated tx descrs, properly setting up transfer data and
+** CTL_xxx flags according to fragment number.
+*/
+void
+acxpci_l_tx_data(acx_device_t *adev, tx_t* tx_opaque, int len)
+{
+	txdesc_t *txdesc = (txdesc_t*)tx_opaque;
+	txhostdesc_t *hostdesc1, *hostdesc2;
+	client_t *clt;
+	u16 rate_cur;
+	u8 Ctl_8, Ctl2_8;
+
+	FN_ENTER;
+
+	/* fw doesn't tx such packets anyhow */
+	if (unlikely(len < WLAN_HDR_A3_LEN))
+		goto end;
+
+	hostdesc1 = get_txhostdesc(adev, txdesc);
+	/* modify flag status in separate variable to be able to write it back
+	 * in one big swoop later (also in order to have less device memory
+	 * accesses) */
+	Ctl_8 = txdesc->Ctl_8;
+	Ctl2_8 = 0; /* really need to init it to 0, not txdesc->Ctl2_8, it seems */
+
+	hostdesc2 = hostdesc1 + 1;
+
+	/* DON'T simply set Ctl field to 0 here globally,
+	 * it needs to maintain a consistent flag status (those are state flags!!),
+	 * otherwise it may lead to severe disruption. Only set or reset particular
+	 * flags at the exact moment this is needed... */
+
+	/* let chip do RTS/CTS handshaking before sending
+	 * in case packet size exceeds threshold */
+	if (len > adev->rts_threshold)
+		SET_BIT(Ctl2_8, DESC_CTL2_RTS);
+	else
+		CLEAR_BIT(Ctl2_8, DESC_CTL2_RTS);
+
+	switch (adev->mode) {
+	case ACX_MODE_0_ADHOC:
+	case ACX_MODE_3_AP:
+		clt = acx_l_sta_list_get(adev, ((wlan_hdr_t*)hostdesc1->data)->a1);
+		break;
+	case ACX_MODE_2_STA:
+		clt = adev->ap_client;
+		break;
+#if 0
+/* testing was done on acx111: */
+	case ACX_MODE_MONITOR:
+		SET_BIT(Ctl2_8, 0
+/* sends CTS to self before packet */
+			+ DESC_CTL2_SEQ		/* don't increase sequence field */
+/* not working (looks like good fcs is still added) */
+			+ DESC_CTL2_FCS		/* don't add the FCS */
+/* not tested */
+			+ DESC_CTL2_MORE_FRAG
+/* not tested */
+			+ DESC_CTL2_RETRY	/* don't increase retry field */
+/* not tested */
+			+ DESC_CTL2_POWER	/* don't increase power mgmt. field */
+/* no effect */
+			+ DESC_CTL2_WEP		/* encrypt this frame */
+/* not tested */
+			+ DESC_CTL2_DUR		/* don't increase duration field */
+			);
+		/* fallthrough */
+#endif
+	default: /* ACX_MODE_OFF, ACX_MODE_MONITOR */
+		clt = NULL;
+		break;
+	}
+
+	rate_cur = clt ? clt->rate_cur : adev->rate_bcast;
+	if (unlikely(!rate_cur)) {
+		printk("acx: driver bug! bad ratemask\n");
+		goto end;
+	}
+
+	/* used in tx cleanup routine for auto rate and accounting: */
+	put_txcr(adev, txdesc, clt, rate_cur);
+
+	txdesc->total_length = cpu_to_le16(len);
+	hostdesc2->length = cpu_to_le16(len - WLAN_HDR_A3_LEN);
+	if (IS_ACX111(adev)) {
+		/* note that if !txdesc->do_auto, txrate->cur
+		** has only one nonzero bit */
+		txdesc->u.r2.rate111 = cpu_to_le16(
+			rate_cur
+			/* WARNING: I was never able to make it work with prism54 AP.
+			** It was falling down to 1Mbit where shortpre is not applicable,
+			** and not working at all at "5,11 basic rates only" setting.
+			** I even didn't see tx packets in radio packet capture.
+			** Disabled for now --vda */
+			/*| ((clt->shortpre && clt->cur!=RATE111_1) ? RATE111_SHORTPRE : 0) */
+			);
+#ifdef TODO_FIGURE_OUT_WHEN_TO_SET_THIS
+			/* should add this to rate111 above as necessary */
+			| (clt->pbcc511 ? RATE111_PBCC511 : 0)
+#endif
+		hostdesc1->length = cpu_to_le16(len);
+	} else { /* ACX100 */
+		u8 rate_100 = clt ? clt->rate_100 : adev->rate_bcast100;
+		txdesc->u.r1.rate = rate_100;
+#ifdef TODO_FIGURE_OUT_WHEN_TO_SET_THIS
+		if (clt->pbcc511) {
+			if (n == RATE100_5 || n == RATE100_11)
+				n |= RATE100_PBCC511;
+		}
+
+		if (clt->shortpre && (clt->cur != RATE111_1))
+			SET_BIT(Ctl_8, DESC_CTL_SHORT_PREAMBLE); /* set Short Preamble */
+#endif
+		/* set autodma and reclaim and 1st mpdu */
+		SET_BIT(Ctl_8, DESC_CTL_AUTODMA | DESC_CTL_RECLAIM | DESC_CTL_FIRSTFRAG);
+#if ACX_FRAGMENTATION
+		/* SET_BIT(Ctl2_8, DESC_CTL2_MORE_FRAG); cannot set it unconditionally, needs to be set for all non-last fragments */
+#endif
+		hostdesc1->length = cpu_to_le16(WLAN_HDR_A3_LEN);
+	}
+	/* don't need to clean ack/rts statistics here, already
+	 * done on descr cleanup */
+
+	/* clears HOSTOWN and ACXDONE bits, thus telling that the descriptors
+	 * are now owned by the acx100; do this as LAST operation */
+	CLEAR_BIT(Ctl_8, DESC_CTL_ACXDONE_HOSTOWN);
+	/* flush writes before we release hostdesc to the adapter here */
+	wmb();
+	CLEAR_BIT(hostdesc1->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
+	CLEAR_BIT(hostdesc2->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
+
+	/* write back modified flags */
+	txdesc->Ctl2_8 = Ctl2_8;
+	txdesc->Ctl_8 = Ctl_8;
+	/* unused: txdesc->tx_time = cpu_to_le32(jiffies); */
+
+	/* flush writes before we tell the adapter that it's its turn now */
+	mmiowb();
+	write_reg16(adev, IO_ACX_INT_TRIG, INT_TRIG_TXPRC);
+	write_flush(adev);
+
+	/* log the packet content AFTER sending it,
+	 * in order to not delay sending any further than absolutely needed
+	 * Do separate logs for acx100/111 to have human-readable rates */
+	if (unlikely(acx_debug & (L_XFER|L_DATA))) {
+		u16 fc = ((wlan_hdr_t*)hostdesc1->data)->fc;
+		if (IS_ACX111(adev))
+			printk("tx: pkt (%s): len %d "
+				"rate %04X%s status %u\n",
+				acx_get_packet_type_string(le16_to_cpu(fc)), len,
+				le16_to_cpu(txdesc->u.r2.rate111),
+				(le16_to_cpu(txdesc->u.r2.rate111) & RATE111_SHORTPRE) ? "(SPr)" : "",
+				adev->status);
+		else
+			printk("tx: pkt (%s): len %d rate %03u%s status %u\n",
+				acx_get_packet_type_string(fc), len,
+				txdesc->u.r1.rate,
+				(Ctl_8 & DESC_CTL_SHORT_PREAMBLE) ? "(SPr)" : "",
+				adev->status);
+
+		if (acx_debug & L_DATA) {
+			printk("tx: 802.11 [%d]: ", len);
+			acx_dump_bytes(hostdesc1->data, len);
+		}
+	}
+end:
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acxpci_l_clean_txdesc
+**
+** This function resets the txdescs' status when the ACX100
+** signals the TX done IRQ (txdescs have been processed), starting with
+** the pool index of the descriptor which we would use next,
+** in order to make sure that we can be as fast as possible
+** in filling new txdescs.
+** Everytime we get called we know where the next packet to be cleaned is.
+*/
+
+#if !ACX_DEBUG
+static inline void log_txbuffer(const acx_device_t *adev) {}
+#else
+static void
+log_txbuffer(acx_device_t *adev)
+{
+	txdesc_t *txdesc;
+	int i;
+
+	/* no FN_ENTER here, we don't want that */
+	/* no locks here, since it's entirely non-critical code */
+	txdesc = adev->txdesc_start;
+	if (unlikely(!txdesc)) return;
+	printk("tx: desc->Ctl8's:");
+	for (i = 0; i < TX_CNT; i++) {
+		printk(" %02X", txdesc->Ctl_8);
+		txdesc = advance_txdesc(adev, txdesc, 1);
+	}
+	printk("\n");
+}
+#endif
+
+
+static void
+handle_tx_error(acx_device_t *adev, u8 error, unsigned int finger)
+{
+	const char *err = "unknown error";
+
+	/* hmm, should we handle this as a mask
+	 * of *several* bits?
+	 * For now I think only caring about
+	 * individual bits is ok... */
+	switch (error) {
+	case 0x01:
+		err = "no Tx due to error in other fragment";
+		adev->wstats.discard.fragment++;
+		break;
+	case 0x02:
+		err = "Tx aborted";
+		adev->stats.tx_aborted_errors++;
+		break;
+	case 0x04:
+		err = "Tx desc wrong parameters";
+		adev->wstats.discard.misc++;
+		break;
+	case 0x08:
+		err = "WEP key not found";
+		adev->wstats.discard.misc++;
+		break;
+	case 0x10:
+		err = "MSDU lifetime timeout? - try changing "
+				"'iwconfig retry lifetime XXX'";
+		adev->wstats.discard.misc++;
+		break;
+	case 0x20:
+		err = "excessive Tx retries due to either distance "
+			"too high or unable to Tx or Tx frame error - "
+			"try changing 'iwconfig txpower XXX' or "
+			"'sens'itivity or 'retry'";
+		adev->wstats.discard.retries++;
+		/* Tx error 0x20 also seems to occur on
+		 * overheating, so I'm not sure whether we
+		 * actually want to do aggressive radio recalibration,
+		 * since people maybe won't notice then that their hardware
+		 * is slowly getting cooked...
+		 * Or is it still a safe long distance from utter
+		 * radio non-functionality despite many radio recalibs
+		 * to final destructive overheating of the hardware?
+		 * In this case we really should do recalib here...
+		 * I guess the only way to find out is to do a
+		 * potentially fatal self-experiment :-\
+		 * Or maybe only recalib in case we're using Tx
+		 * rate auto (on errors switching to lower speed
+		 * --> less heat?) or 802.11 power save mode?
+		 *
+		 * ok, just do it. */
+		if (++adev->retry_errors_msg_ratelimit % 4 == 0) {
+			if (adev->retry_errors_msg_ratelimit <= 20) {
+				printk("%s: several excessive Tx "
+					"retry errors occurred, attempting "
+					"to recalibrate radio. Radio "
+					"drift might be caused by increasing "
+					"card temperature, please check the card "
+					"before it's too late!\n",
+					adev->ndev->name);
+				if (adev->retry_errors_msg_ratelimit == 20)
+					printk("disabling above message\n");
+			}
+
+			acx_schedule_task(adev,	ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
+		}
+		break;
+	case 0x40:
+		err = "Tx buffer overflow";
+		adev->stats.tx_fifo_errors++;
+		break;
+	case 0x80:
+		err = "DMA error";
+		adev->wstats.discard.misc++;
+		break;
+	}
+	adev->stats.tx_errors++;
+	if (adev->stats.tx_errors <= 20)
+		printk("%s: tx error 0x%02X, buf %02u! (%s)\n",
+				adev->ndev->name, error, finger, err);
+	else
+		printk("%s: tx error 0x%02X, buf %02u!\n",
+				adev->ndev->name, error, finger);
+}
+
+
+unsigned int
+acxpci_l_clean_txdesc(acx_device_t *adev)
+{
+	txdesc_t *txdesc;
+	int finger;
+	int num_cleaned;
+	u16 r111;
+	u8 error, ack_failures, rts_failures, rts_ok, r100;
+
+	FN_ENTER;
+
+	if (unlikely(acx_debug & L_DEBUG))
+		log_txbuffer(adev);
+
+	log(L_BUFT, "tx: cleaning up bufs from %u\n", adev->tx_tail);
+
+	/* We know first descr which is not free yet. We advance it as far
+	** as we see correct bits set in following descs (if next desc
+	** is NOT free, we shouldn't advance at all). We know that in
+	** front of tx_tail may be "holes" with isolated free descs.
+	** We will catch up when all intermediate descs will be freed also */
+
+	finger = adev->tx_tail;
+	num_cleaned = 0;
+	while (likely(finger != adev->tx_head)) {
+		txdesc = get_txdesc(adev, finger);
+
+		/* If we allocated txdesc on tx path but then decided
+		** to NOT use it, then it will be left as a free "bubble"
+		** in the "allocated for tx" part of the ring.
+		** We may meet it on the next ring pass here. */
+
+		/* stop if not marked as "tx finished" and "host owned" */
+		if ((txdesc->Ctl_8 & DESC_CTL_ACXDONE_HOSTOWN)
+					!= DESC_CTL_ACXDONE_HOSTOWN) {
+			if (unlikely(!num_cleaned)) { /* maybe remove completely */
+				log(L_BUFT, "clean_txdesc: tail isn't free. "
+					"tail:%d head:%d\n",
+					adev->tx_tail, adev->tx_head);
+			}
+			break;
+		}
+
+		/* remember desc values... */
+		error = txdesc->error;
+		ack_failures = txdesc->ack_failures;
+		rts_failures = txdesc->rts_failures;
+		rts_ok = txdesc->rts_ok;
+		r100 = txdesc->u.r1.rate;
+		r111 = le16_to_cpu(txdesc->u.r2.rate111);
+
+		/* need to check for certain error conditions before we
+		 * clean the descriptor: we still need valid descr data here */
+		if (unlikely(0x30 & error)) {
+			/* only send IWEVTXDROP in case of retry or lifetime exceeded;
+			 * all other errors mean we screwed up locally */
+			union iwreq_data wrqu;
+			wlan_hdr_t *hdr;
+			txhostdesc_t *hostdesc;
+
+			hostdesc = get_txhostdesc(adev, txdesc);
+			hdr = (wlan_hdr_t *)hostdesc->data;
+			MAC_COPY(wrqu.addr.sa_data, hdr->a1);
+			wireless_send_event(adev->ndev, IWEVTXDROP, &wrqu, NULL);
+		}
+
+		/* ...and free the desc */
+		txdesc->error = 0;
+		txdesc->ack_failures = 0;
+		txdesc->rts_failures = 0;
+		txdesc->rts_ok = 0;
+		/* signal host owning it LAST, since ACX already knows that this
+		** descriptor is finished since it set Ctl_8 accordingly. */
+		txdesc->Ctl_8 = DESC_CTL_HOSTOWN;
+
+		adev->tx_free++;
+		num_cleaned++;
+
+		if ((adev->tx_free >= TX_START_QUEUE)
+		 && (adev->status == ACX_STATUS_4_ASSOCIATED)
+		 && (acx_queue_stopped(adev->ndev))
+		) {
+			log(L_BUF, "tx: wake queue (avail. Tx desc %u)\n",
+					adev->tx_free);
+			acx_wake_queue(adev->ndev, NULL);
+		}
+
+		/* do error checking, rate handling and logging
+		 * AFTER having done the work, it's faster */
+
+		/* do rate handling */
+		if (adev->rate_auto) {
+			struct client *clt = get_txc(adev, txdesc);
+			if (clt) {
+				u16 cur = get_txr(adev, txdesc);
+				if (clt->rate_cur == cur) {
+					acx_l_handle_txrate_auto(adev, clt,
+						cur, /* intended rate */
+						r100, r111, /* actually used rate */
+						(error & 0x30), /* was there an error? */
+						TX_CNT + TX_CLEAN_BACKLOG - adev->tx_free);
+				}
+			}
+		}
+
+		if (unlikely(error))
+			handle_tx_error(adev, error, finger);
+
+		if (IS_ACX111(adev))
+			log(L_BUFT, "tx: cleaned %u: !ACK=%u !RTS=%u RTS=%u r111=%04X\n",
+				finger, ack_failures, rts_failures, rts_ok, r111);
+		else
+			log(L_BUFT, "tx: cleaned %u: !ACK=%u !RTS=%u RTS=%u rate=%u\n",
+				finger, ack_failures, rts_failures, rts_ok, r100);
+
+		/* update pointer for descr to be cleaned next */
+		finger = (finger + 1) % TX_CNT;
+	}
+
+	/* remember last position */
+	adev->tx_tail = finger;
+/* end: */
+	FN_EXIT1(num_cleaned);
+	return num_cleaned;
+}
+
+/* clean *all* Tx descriptors, and regardless of their previous state.
+ * Used for brute-force reset handling. */
+void
+acxpci_l_clean_txdesc_emergency(acx_device_t *adev)
+{
+	txdesc_t *txdesc;
+	int i;
+
+	FN_ENTER;
+
+	for (i = 0; i < TX_CNT; i++) {
+		txdesc = get_txdesc(adev, i);
+
+		/* free it */
+		txdesc->ack_failures = 0;
+		txdesc->rts_failures = 0;
+		txdesc->rts_ok = 0;
+		txdesc->error = 0;
+		txdesc->Ctl_8 = DESC_CTL_HOSTOWN;
+	}
+
+	adev->tx_free = TX_CNT;
+
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acxpci_s_create_tx_host_desc_queue
+*/
+
+static void*
+allocate(acx_device_t *adev, size_t size, dma_addr_t *phy, const char *msg)
+{
+	void *ptr;
+
+	ptr = dma_alloc_coherent(adev->pdev ? &adev->pdev->dev : NULL,
+			size, phy, GFP_KERNEL);
+
+	if (ptr) {
+		log(L_DEBUG, "%s sz=%d adr=0x%p phy=0x%08llx\n",
+				msg, (int)size, ptr, (unsigned long long)*phy);
+		memset(ptr, 0, size);
+		return ptr;
+	}
+	printk(KERN_ERR "acx: %s allocation FAILED (%d bytes)\n",
+					msg, (int)size);
+	return NULL;
+}
+
+
+static int
+acxpci_s_create_tx_host_desc_queue(acx_device_t *adev)
+{
+	txhostdesc_t *hostdesc;
+	u8 *txbuf;
+	dma_addr_t hostdesc_phy;
+	dma_addr_t txbuf_phy;
+	int i;
+
+	FN_ENTER;
+
+	/* allocate TX buffer */
+	adev->txbuf_area_size = TX_CNT * WLAN_A4FR_MAXLEN_WEP_FCS;
+	adev->txbuf_start = allocate(adev, adev->txbuf_area_size,
+			&adev->txbuf_startphy, "txbuf_start");
+	if (!adev->txbuf_start)
+		goto fail;
+
+	/* allocate the TX host descriptor queue pool */
+	adev->txhostdesc_area_size = TX_CNT * 2*sizeof(*hostdesc);
+	adev->txhostdesc_start = allocate(adev, adev->txhostdesc_area_size,
+			&adev->txhostdesc_startphy, "txhostdesc_start");
+	if (!adev->txhostdesc_start)
+		goto fail;
+	/* check for proper alignment of TX host descriptor pool */
+	if ((long) adev->txhostdesc_start & 3) {
+		printk("acx: driver bug: dma alloc returns unaligned address\n");
+		goto fail;
+	}
+
+	hostdesc = adev->txhostdesc_start;
+	hostdesc_phy = adev->txhostdesc_startphy;
+	txbuf = adev->txbuf_start;
+	txbuf_phy = adev->txbuf_startphy;
+
+#if 0
+/* Each tx buffer is accessed by hardware via
+** txdesc -> txhostdesc(s) -> txbuffer(s).
+** We use only one txhostdesc per txdesc, but it looks like
+** acx111 is buggy: it accesses second txhostdesc
+** (via hostdesc.desc_phy_next field) even if
+** txdesc->length == hostdesc->length and thus
+** entire packet was placed into first txhostdesc.
+** Due to this bug acx111 hangs unless second txhostdesc
+** has le16_to_cpu(hostdesc.length) = 3 (or larger)
+** Storing NULL into hostdesc.desc_phy_next
+** doesn't seem to help.
+**
+** Update: although it worked on Xterasys XN-2522g
+** with len=3 trick, WG311v2 is even more bogus, doesn't work.
+** Keeping this code (#ifdef'ed out) for documentational purposes.
+*/
+	for (i = 0; i < TX_CNT*2; i++) {
+		hostdesc_phy += sizeof(*hostdesc);
+		if (!(i & 1)) {
+			hostdesc->data_phy = cpu2acx(txbuf_phy);
+			/* hostdesc->data_offset = ... */
+			/* hostdesc->reserved = ... */
+			hostdesc->Ctl_16 = cpu_to_le16(DESC_CTL_HOSTOWN);
+			/* hostdesc->length = ... */
+			hostdesc->desc_phy_next = cpu2acx(hostdesc_phy);
+			hostdesc->pNext = ptr2acx(NULL);
+			/* hostdesc->Status = ... */
+			/* below: non-hardware fields */
+			hostdesc->data = txbuf;
+
+			txbuf += WLAN_A4FR_MAXLEN_WEP_FCS;
+			txbuf_phy += WLAN_A4FR_MAXLEN_WEP_FCS;
+		} else {
+			/* hostdesc->data_phy = ... */
+			/* hostdesc->data_offset = ... */
+			/* hostdesc->reserved = ... */
+			/* hostdesc->Ctl_16 = ... */
+			hostdesc->length = cpu_to_le16(3); /* bug workaround */
+			/* hostdesc->desc_phy_next = ... */
+			/* hostdesc->pNext = ... */
+			/* hostdesc->Status = ... */
+			/* below: non-hardware fields */
+			/* hostdesc->data = ... */
+		}
+		hostdesc++;
+	}
+#endif
+/* We initialize two hostdescs so that they point to adjacent
+** memory areas. Thus txbuf is really just a contiguous memory area */
+	for (i = 0; i < TX_CNT*2; i++) {
+		hostdesc_phy += sizeof(*hostdesc);
+
+		hostdesc->data_phy = cpu2acx(txbuf_phy);
+		/* done by memset(0): hostdesc->data_offset = 0; */
+		/* hostdesc->reserved = ... */
+		hostdesc->Ctl_16 = cpu_to_le16(DESC_CTL_HOSTOWN);
+		/* hostdesc->length = ... */
+		hostdesc->desc_phy_next = cpu2acx(hostdesc_phy);
+		/* done by memset(0): hostdesc->pNext = ptr2acx(NULL); */
+		/* hostdesc->Status = ... */
+		/* ->data is a non-hardware field: */
+		hostdesc->data = txbuf;
+
+		if (!(i & 1)) {
+			txbuf += WLAN_HDR_A3_LEN;
+			txbuf_phy += WLAN_HDR_A3_LEN;
+		} else {
+			txbuf += WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_HDR_A3_LEN;
+			txbuf_phy += WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_HDR_A3_LEN;
+		}
+		hostdesc++;
+	}
+	hostdesc--;
+	hostdesc->desc_phy_next = cpu2acx(adev->txhostdesc_startphy);
+
+	FN_EXIT1(OK);
+	return OK;
+fail:
+	printk("acx: create_tx_host_desc_queue FAILED\n");
+	/* dealloc will be done by free function on error case */
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+
+
+/***************************************************************
+** acxpci_s_create_rx_host_desc_queue
+*/
+/* the whole size of a data buffer (header plus data body)
+ * plus 32 bytes safety offset at the end */
+#define RX_BUFFER_SIZE (sizeof(rxbuffer_t) + 32)
+
+static int
+acxpci_s_create_rx_host_desc_queue(acx_device_t *adev)
+{
+	rxhostdesc_t *hostdesc;
+	rxbuffer_t *rxbuf;
+	dma_addr_t hostdesc_phy;
+	dma_addr_t rxbuf_phy;
+	int i;
+
+	FN_ENTER;
+
+	/* allocate the RX host descriptor queue pool */
+	adev->rxhostdesc_area_size = RX_CNT * sizeof(*hostdesc);
+	adev->rxhostdesc_start = allocate(adev, adev->rxhostdesc_area_size,
+			&adev->rxhostdesc_startphy, "rxhostdesc_start");
+	if (!adev->rxhostdesc_start)
+		goto fail;
+	/* check for proper alignment of RX host descriptor pool */
+	if ((long) adev->rxhostdesc_start & 3) {
+		printk("acx: driver bug: dma alloc returns unaligned address\n");
+		goto fail;
+	}
+
+	/* allocate Rx buffer pool which will be used by the acx
+	 * to store the whole content of the received frames in it */
+	adev->rxbuf_area_size = RX_CNT * RX_BUFFER_SIZE;
+	adev->rxbuf_start = allocate(adev, adev->rxbuf_area_size,
+			&adev->rxbuf_startphy, "rxbuf_start");
+	if (!adev->rxbuf_start)
+		goto fail;
+
+	rxbuf = adev->rxbuf_start;
+	rxbuf_phy = adev->rxbuf_startphy;
+	hostdesc = adev->rxhostdesc_start;
+	hostdesc_phy = adev->rxhostdesc_startphy;
+
+	/* don't make any popular C programming pointer arithmetic mistakes
+	 * here, otherwise I'll kill you...
+	 * (and don't dare asking me why I'm warning you about that...) */
+	for (i = 0; i < RX_CNT; i++) {
+		hostdesc->data = rxbuf;
+		hostdesc->data_phy = cpu2acx(rxbuf_phy);
+		hostdesc->length = cpu_to_le16(RX_BUFFER_SIZE);
+		CLEAR_BIT(hostdesc->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
+		rxbuf++;
+		rxbuf_phy += sizeof(*rxbuf);
+		hostdesc_phy += sizeof(*hostdesc);
+		hostdesc->desc_phy_next = cpu2acx(hostdesc_phy);
+		hostdesc++;
+	}
+	hostdesc--;
+	hostdesc->desc_phy_next = cpu2acx(adev->rxhostdesc_startphy);
+	FN_EXIT1(OK);
+	return OK;
+fail:
+	printk("acx: create_rx_host_desc_queue FAILED\n");
+	/* dealloc will be done by free function on error case */
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+
+
+/***************************************************************
+** acxpci_s_create_hostdesc_queues
+*/
+int
+acxpci_s_create_hostdesc_queues(acx_device_t *adev)
+{
+	int result;
+	result = acxpci_s_create_tx_host_desc_queue(adev);
+	if (OK != result) return result;
+	result = acxpci_s_create_rx_host_desc_queue(adev);
+	return result;
+}
+
+
+/***************************************************************
+** acxpci_create_tx_desc_queue
+*/
+static void
+acxpci_create_tx_desc_queue(acx_device_t *adev, u32 tx_queue_start)
+{
+	txdesc_t *txdesc;
+	txhostdesc_t *hostdesc;
+	dma_addr_t hostmemptr;
+	u32 mem_offs;
+	int i;
+
+	FN_ENTER;
+
+	if (IS_ACX100(adev))
+		adev->txdesc_size = sizeof(*txdesc);
+	else
+		/* the acx111 txdesc is 4 bytes larger */
+		adev->txdesc_size = sizeof(*txdesc) + 4;
+
+	adev->txdesc_start = (txdesc_t *) (adev->iobase2 + tx_queue_start);
+
+	log(L_DEBUG, "adev->iobase2=%p\n"
+			"tx_queue_start=%08X\n"
+			"adev->txdesc_start=%p\n",
+			adev->iobase2,
+			tx_queue_start,
+			adev->txdesc_start);
+
+	adev->tx_free = TX_CNT;
+	/* done by memset: adev->tx_head = 0; */
+	/* done by memset: adev->tx_tail = 0; */
+	txdesc = adev->txdesc_start;
+	mem_offs = tx_queue_start;
+	hostmemptr = adev->txhostdesc_startphy;
+	hostdesc = adev->txhostdesc_start;
+
+	if (IS_ACX111(adev)) {
+		/* ACX111 has a preinitialized Tx buffer! */
+		/* loop over whole send pool */
+		/* FIXME: do we have to do the hostmemptr stuff here?? */
+		for (i = 0; i < TX_CNT; i++) {
+			txdesc->HostMemPtr = ptr2acx(hostmemptr);
+			txdesc->Ctl_8 = DESC_CTL_HOSTOWN;
+			/* reserve two (hdr desc and payload desc) */
+			hostdesc += 2;
+			hostmemptr += 2 * sizeof(*hostdesc);
+			txdesc = advance_txdesc(adev, txdesc, 1);
+		}
+	} else {
+		/* ACX100 Tx buffer needs to be initialized by us */
+		/* clear whole send pool. sizeof is safe here (we are acx100) */
+		memset(adev->txdesc_start, 0, TX_CNT * sizeof(*txdesc));
+
+		/* loop over whole send pool */
+		for (i = 0; i < TX_CNT; i++) {
+			log(L_DEBUG, "configure card tx descriptor: 0x%p, "
+				"size: 0x%X\n", txdesc, adev->txdesc_size);
+
+			/* pointer to hostdesc memory */
+			txdesc->HostMemPtr = ptr2acx(hostmemptr);
+			/* initialise ctl */
+			txdesc->Ctl_8 = ( DESC_CTL_HOSTOWN | DESC_CTL_RECLAIM
+					| DESC_CTL_AUTODMA | DESC_CTL_FIRSTFRAG);
+			/* done by memset(0): txdesc->Ctl2_8 = 0; */
+			/* point to next txdesc */
+			txdesc->pNextDesc = cpu2acx(mem_offs + adev->txdesc_size);
+			/* reserve two (hdr desc and payload desc) */
+			hostdesc += 2;
+			hostmemptr += 2 * sizeof(*hostdesc);
+			/* go to the next one */
+			mem_offs += adev->txdesc_size;
+			/* ++ is safe here (we are acx100) */
+			txdesc++;
+		}
+		/* go back to the last one */
+		txdesc--;
+		/* and point to the first making it a ring buffer */
+		txdesc->pNextDesc = cpu2acx(tx_queue_start);
+	}
+	FN_EXIT0;
+}
+
+
+/***************************************************************
+** acxpci_create_rx_desc_queue
+*/
+static void
+acxpci_create_rx_desc_queue(acx_device_t *adev, u32 rx_queue_start)
+{
+	rxdesc_t *rxdesc;
+	u32 mem_offs;
+	int i;
+
+	FN_ENTER;
+
+	/* done by memset: adev->rx_tail = 0; */
+
+	/* ACX111 doesn't need any further config: preconfigures itself.
+	 * Simply print ring buffer for debugging */
+	if (IS_ACX111(adev)) {
+		/* rxdesc_start already set here */
+
+		adev->rxdesc_start = (rxdesc_t *) ((u8 *)adev->iobase2 + rx_queue_start);
+
+		rxdesc = adev->rxdesc_start;
+		for (i = 0; i < RX_CNT; i++) {
+			log(L_DEBUG, "rx descriptor %d @ 0x%p\n", i, rxdesc);
+			rxdesc = adev->rxdesc_start = (rxdesc_t *)
+				(adev->iobase2 + acx2cpu(rxdesc->pNextDesc));
+		}
+	} else {
+		/* we didn't pre-calculate rxdesc_start in case of ACX100 */
+		/* rxdesc_start should be right AFTER Tx pool */
+		adev->rxdesc_start = (rxdesc_t *)
+			((u8 *) adev->txdesc_start + (TX_CNT * sizeof(txdesc_t)));
+		/* NB: sizeof(txdesc_t) above is valid because we know
+		** we are in if (acx100) block. Beware of cut-n-pasting elsewhere!
+		** acx111's txdesc is larger! */
+
+		memset(adev->rxdesc_start, 0, RX_CNT * sizeof(*rxdesc));
+
+		/* loop over whole receive pool */
+		rxdesc = adev->rxdesc_start;
+		mem_offs = rx_queue_start;
+		for (i = 0; i < RX_CNT; i++) {
+			log(L_DEBUG, "rx descriptor @ 0x%p\n", rxdesc);
+			rxdesc->Ctl_8 = DESC_CTL_RECLAIM | DESC_CTL_AUTODMA;
+			/* point to next rxdesc */
+			rxdesc->pNextDesc = cpu2acx(mem_offs + sizeof(*rxdesc));
+			/* go to the next one */
+			mem_offs += sizeof(*rxdesc);
+			rxdesc++;
+		}
+		/* go to the last one */
+		rxdesc--;
+
+		/* and point to the first making it a ring buffer */
+		rxdesc->pNextDesc = cpu2acx(rx_queue_start);
+	}
+	FN_EXIT0;
+}
+
+
+/***************************************************************
+** acxpci_create_desc_queues
+*/
+void
+acxpci_create_desc_queues(acx_device_t *adev, u32 tx_queue_start, u32 rx_queue_start)
+{
+	acxpci_create_tx_desc_queue(adev, tx_queue_start);
+	acxpci_create_rx_desc_queue(adev, rx_queue_start);
+}
+
+
+/***************************************************************
+** acxpci_s_proc_diag_output
+*/
+char*
+acxpci_s_proc_diag_output(char *p, acx_device_t *adev)
+{
+	const char *rtl, *thd, *ttl;
+	rxhostdesc_t *rxhostdesc;
+	txdesc_t *txdesc;
+	int i;
+
+	FN_ENTER;
+
+	p += sprintf(p, "** Rx buf **\n");
+	rxhostdesc = adev->rxhostdesc_start;
+	if (rxhostdesc) for (i = 0; i < RX_CNT; i++) {
+		rtl = (i == adev->rx_tail) ? " [tail]" : "";
+		if ((rxhostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
+		 && (rxhostdesc->Status & cpu_to_le32(DESC_STATUS_FULL)) )
+			p += sprintf(p, "%02u FULL%s\n", i, rtl);
+		else
+			p += sprintf(p, "%02u empty%s\n", i, rtl);
+		rxhostdesc++;
+	}
+	p += sprintf(p, "** Tx buf (free %d, Linux netqueue %s) **\n", adev->tx_free,
+				acx_queue_stopped(adev->ndev) ? "STOPPED" : "running");
+	txdesc = adev->txdesc_start;
+	if (txdesc) for (i = 0; i < TX_CNT; i++) {
+		thd = (i == adev->tx_head) ? " [head]" : "";
+		ttl = (i == adev->tx_tail) ? " [tail]" : "";
+		if (txdesc->Ctl_8 & DESC_CTL_ACXDONE)
+			p += sprintf(p, "%02u free (%02X)%s%s\n", i, txdesc->Ctl_8, thd, ttl);
+		else
+			p += sprintf(p, "%02u tx   (%02X)%s%s\n", i, txdesc->Ctl_8, thd, ttl);
+		txdesc = advance_txdesc(adev, txdesc, 1);
+	}
+	p += sprintf(p,
+		"\n"
+		"** PCI data **\n"
+		"txbuf_start %p, txbuf_area_size %u, txbuf_startphy %08llx\n"
+		"txdesc_size %u, txdesc_start %p\n"
+		"txhostdesc_start %p, txhostdesc_area_size %u, txhostdesc_startphy %08llx\n"
+		"rxdesc_start %p\n"
+		"rxhostdesc_start %p, rxhostdesc_area_size %u, rxhostdesc_startphy %08llx\n"
+		"rxbuf_start %p, rxbuf_area_size %u, rxbuf_startphy %08llx\n",
+		adev->txbuf_start, adev->txbuf_area_size, (u64)adev->txbuf_startphy,
+		adev->txdesc_size, adev->txdesc_start,
+		adev->txhostdesc_start, adev->txhostdesc_area_size, (u64)adev->txhostdesc_startphy,
+		adev->rxdesc_start,
+		adev->rxhostdesc_start, adev->rxhostdesc_area_size, (u64)adev->rxhostdesc_startphy,
+		adev->rxbuf_start, adev->rxbuf_area_size, (u64)adev->rxbuf_startphy);
+
+	FN_EXIT0;
+	return p;
+}
+
+
+/***********************************************************************
+*/
+int
+acxpci_proc_eeprom_output(char *buf, acx_device_t *adev)
+{
+	char *p = buf;
+	int i;
+
+	FN_ENTER;
+
+	for (i = 0; i < 0x400; i++) {
+		acxpci_read_eeprom_byte(adev, i, p++);
+	}
+
+	FN_EXIT1(p - buf);
+	return p - buf;
+}
+
+
+/***********************************************************************
+*/
+void
+acxpci_set_interrupt_mask(acx_device_t *adev)
+{
+	if (IS_ACX111(adev)) {
+		adev->irq_mask = (u16) ~(0
+				/* | HOST_INT_RX_DATA        */
+				| HOST_INT_TX_COMPLETE
+				/* | HOST_INT_TX_XFER        */
+				| HOST_INT_RX_COMPLETE
+				/* | HOST_INT_DTIM           */
+				/* | HOST_INT_BEACON         */
+				/* | HOST_INT_TIMER          */
+				/* | HOST_INT_KEY_NOT_FOUND  */
+				| HOST_INT_IV_ICV_FAILURE
+				| HOST_INT_CMD_COMPLETE
+				| HOST_INT_INFO
+				/* | HOST_INT_OVERFLOW       */
+				/* | HOST_INT_PROCESS_ERROR  */
+				| HOST_INT_SCAN_COMPLETE
+				| HOST_INT_FCS_THRESHOLD
+				/* | HOST_INT_UNKNOWN        */
+				);
+		/* Or else acx100 won't signal cmd completion, right? */
+		adev->irq_mask_off = (u16)~( HOST_INT_CMD_COMPLETE ); /* 0xfdff */
+	} else {
+		adev->irq_mask = (u16) ~(0
+				/* | HOST_INT_RX_DATA        */
+				| HOST_INT_TX_COMPLETE
+				/* | HOST_INT_TX_XFER        */
+				| HOST_INT_RX_COMPLETE
+				/* | HOST_INT_DTIM           */
+				/* | HOST_INT_BEACON         */
+				/* | HOST_INT_TIMER          */
+				/* | HOST_INT_KEY_NOT_FOUND  */
+				/* | HOST_INT_IV_ICV_FAILURE */
+				| HOST_INT_CMD_COMPLETE
+				| HOST_INT_INFO
+				/* | HOST_INT_OVERFLOW       */
+				/* | HOST_INT_PROCESS_ERROR  */
+				| HOST_INT_SCAN_COMPLETE
+				/* | HOST_INT_FCS_THRESHOLD  */
+				/* | HOST_INT_UNKNOWN        */
+				);
+		adev->irq_mask_off = (u16)~( HOST_INT_UNKNOWN ); /* 0x7fff */
+	}
+}
+
+
+/***********************************************************************
+*/
+int
+acx100pci_s_set_tx_level(acx_device_t *adev, u8 level_dbm)
+{
+	/* since it can be assumed that at least the Maxim radio has a
+	 * maximum power output of 20dBm and since it also can be
+	 * assumed that these values drive the DAC responsible for
+	 * setting the linear Tx level, I'd guess that these values
+	 * should be the corresponding linear values for a dBm value,
+	 * in other words: calculate the values from that formula:
+	 * Y [dBm] = 10 * log (X [mW])
+	 * then scale the 0..63 value range onto the 1..100mW range (0..20 dBm)
+	 * and you're done...
+	 * Hopefully that's ok, but you never know if we're actually
+	 * right... (especially since Windows XP doesn't seem to show
+	 * actual Tx dBm values :-P) */
+
+	/* NOTE: on Maxim, value 30 IS 30mW, and value 10 IS 10mW - so the
+	 * values are EXACTLY mW!!! Not sure about RFMD and others,
+	 * though... */
+	static const u8 dbm2val_maxim[21] = {
+		63, 63, 63, 62,
+		61, 61, 60, 60,
+		59, 58, 57, 55,
+		53, 50, 47, 43,
+		38, 31, 23, 13,
+		0
+	};
+	static const u8 dbm2val_rfmd[21] = {
+		 0,  0,  0,  1,
+		 2,  2,  3,  3,
+		 4,  5,  6,  8,
+		10, 13, 16, 20,
+		25, 32, 41, 50,
+		63
+	};
+	const u8 *table;
+
+	switch (adev->radio_type) {
+	case RADIO_MAXIM_0D:
+		table = &dbm2val_maxim[0];
+		break;
+	case RADIO_RFMD_11:
+	case RADIO_RALINK_15:
+		table = &dbm2val_rfmd[0];
+		break;
+	default:
+		printk("%s: unknown/unsupported radio type, "
+			"cannot modify tx power level yet!\n",
+				adev->ndev->name);
+		return NOT_OK;
+	}
+	printk("%s: changing radio power level to %u dBm (%u)\n",
+			adev->ndev->name, level_dbm, table[level_dbm]);
+	acxpci_s_write_phy_reg(adev, 0x11, table[level_dbm]);
+	return OK;
+}
+
+
+/***********************************************************************
+** Data for init_module/cleanup_module
+*/
+static const struct pci_device_id
+acxpci_id_tbl[] __devinitdata = {
+	{
+		.vendor = PCI_VENDOR_ID_TI,
+		.device = PCI_DEVICE_ID_TI_TNETW1100A,
+		.subvendor = PCI_ANY_ID,
+		.subdevice = PCI_ANY_ID,
+		.driver_data = CHIPTYPE_ACX100,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_TI,
+		.device = PCI_DEVICE_ID_TI_TNETW1100B,
+		.subvendor = PCI_ANY_ID,
+		.subdevice = PCI_ANY_ID,
+		.driver_data = CHIPTYPE_ACX100,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_TI,
+		.device = PCI_DEVICE_ID_TI_TNETW1130,
+		.subvendor = PCI_ANY_ID,
+		.subdevice = PCI_ANY_ID,
+		.driver_data = CHIPTYPE_ACX111,
+	},
+	{
+		.vendor = 0,
+		.device = 0,
+		.subvendor = 0,
+		.subdevice = 0,
+		.driver_data = 0,
+	}
+};
+
+MODULE_DEVICE_TABLE(pci, acxpci_id_tbl);
+
+/* FIXME: checks should be removed once driver is included in the kernel */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)
+/* pci_name() got introduced at start of 2.6.x,
+ * got mandatory (slot_name member removed) in 2.6.11-bk1 */
+#define pci_name(x) x->slot_name
+#endif
+
+static struct pci_driver
+acxpci_drv_id = {
+	.name        = "acx_pci",
+	.id_table    = acxpci_id_tbl,
+	.probe       = acxpci_e_probe,
+	.remove      = __devexit_p(acxpci_e_remove),
+#ifdef CONFIG_PM
+	.suspend     = acxpci_e_suspend,
+	.resume      = acxpci_e_resume
+#endif /* CONFIG_PM */
+};
+
+
+/***********************************************************************
+** acxpci_e_init_module
+**
+** Module initialization routine, called once at module load time
+*/
+int __init
+acxpci_e_init_module(void)
+{
+	int res;
+
+	FN_ENTER;
+
+#if (ACX_IO_WIDTH==32)
+	printk("acx: compiled to use 32bit I/O access. "
+		"I/O timing issues might occur, such as "
+		"non-working firmware upload. Report them\n");
+#else
+	printk("acx: compiled to use 16bit I/O access only "
+		"(compatibility mode)\n");
+#endif
+
+#ifdef __LITTLE_ENDIAN
+#define ENDIANNESS_STRING "running on a little-endian CPU\n"
+#else
+#define ENDIANNESS_STRING "running on a BIG-ENDIAN CPU\n"
+#endif
+	log(L_INIT,
+		ENDIANNESS_STRING
+		"PCI module " ACX_RELEASE " initialized, "
+		"waiting for cards to probe...\n"
+	);
+
+	res = pci_register_driver(&acxpci_drv_id);
+	FN_EXIT1(res);
+	return res;
+}
+
+
+/***********************************************************************
+** acxpci_e_cleanup_module
+**
+** Called at module unload time. This is our last chance to
+** clean up after ourselves.
+*/
+void __exit
+acxpci_e_cleanup_module(void)
+{
+	struct net_device *ndev;
+	unsigned long flags;
+
+	FN_ENTER;
+
+	/* Since the whole module is about to be unloaded,
+	 * we recursively shutdown all cards we handled instead
+	 * of doing it in acxpci_e_remove() (which will be activated by us
+	 * via pci_unregister_driver at the end).
+	 * acxpci_e_remove() might just get called after a card eject,
+	 * that's why hardware operations have to be done here instead
+	 * when the hardware is available. */
+
+	down(&root_adev_sem);
+
+	ndev = root_adev_newest;
+	while (ndev) {
+		acx_device_t *adev = ndev2adev(ndev);
+
+		acx_sem_lock(adev);
+
+		/* disable both Tx and Rx to shut radio down properly */
+		acx_s_issue_cmd(adev, ACX1xx_CMD_DISABLE_TX, NULL, 0);
+		acx_s_issue_cmd(adev, ACX1xx_CMD_DISABLE_RX, NULL, 0);
+
+#ifdef REDUNDANT
+		/* put the eCPU to sleep to save power
+		 * Halting is not possible currently,
+		 * since not supported by all firmware versions */
+		acx_s_issue_cmd(adev, ACX100_CMD_SLEEP, NULL, 0);
+#endif
+		acx_lock(adev, flags);
+
+		/* disable power LED to save power :-) */
+		log(L_INIT, "switching off power LED to save power\n");
+		acxpci_l_power_led(adev, 0);
+
+		/* stop our eCPU */
+		if (IS_ACX111(adev)) {
+			/* FIXME: does this actually keep halting the eCPU?
+			 * I don't think so...
+			 */
+			acxpci_l_reset_mac(adev);
+		} else {
+			u16 temp;
+
+			/* halt eCPU */
+			temp = read_reg16(adev, IO_ACX_ECPU_CTRL) | 0x1;
+			write_reg16(adev, IO_ACX_ECPU_CTRL, temp);
+			write_flush(adev);
+		}
+
+		acx_unlock(adev, flags);
+
+		acx_sem_unlock(adev);
+
+		ndev = adev->prev_nd;
+	}
+
+	up(&root_adev_sem);
+
+	/* now let the PCI layer recursively remove
+	 * all PCI related things (acxpci_e_remove()) */
+	pci_unregister_driver(&acxpci_drv_id);
+
+	FN_EXIT0;
+}
diff -urN oldtree/drivers/net/wireless/tiacx/setrate.c newtree/drivers/net/wireless/tiacx/setrate.c
--- oldtree/drivers/net/wireless/tiacx/setrate.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/net/wireless/tiacx/setrate.c	2006-02-21 15:58:22.572714984 +0000
@@ -0,0 +1,213 @@
+/* TODO: stop #including, move into wireless.c
+ * until then, keep in sync copies in prism54/ and acx/ dirs
+ * code+data size: less than 1k */
+
+enum {
+	DOT11_RATE_1,
+	DOT11_RATE_2,
+	DOT11_RATE_5,
+	DOT11_RATE_11,
+	DOT11_RATE_22,
+	DOT11_RATE_33,
+	DOT11_RATE_6,
+	DOT11_RATE_9,
+	DOT11_RATE_12,
+	DOT11_RATE_18,
+	DOT11_RATE_24,
+	DOT11_RATE_36,
+	DOT11_RATE_48,
+	DOT11_RATE_54
+};
+enum {
+	DOT11_MOD_DBPSK,
+	DOT11_MOD_DQPSK,
+	DOT11_MOD_CCK,
+	DOT11_MOD_OFDM,
+	DOT11_MOD_CCKOFDM,
+	DOT11_MOD_PBCC
+};
+static const u8 ratelist[] = { 1,2,5,11,22,33,6,9,12,18,24,36,48,54 };
+static const u8 dot11ratebyte[] = { 1*2,2*2,11,11*2,22*2,33*2,6*2,9*2,12*2,18*2,24*2,36*2,48*2,54*2 };
+static const u8 default_modulation[] = {
+	DOT11_MOD_DBPSK,
+	DOT11_MOD_DQPSK,
+	DOT11_MOD_CCK,
+	DOT11_MOD_CCK,
+	DOT11_MOD_PBCC,
+	DOT11_MOD_PBCC,
+	DOT11_MOD_OFDM,
+	DOT11_MOD_OFDM,
+	DOT11_MOD_OFDM,
+	DOT11_MOD_OFDM,
+	DOT11_MOD_OFDM,
+	DOT11_MOD_OFDM,
+	DOT11_MOD_OFDM,
+	DOT11_MOD_OFDM
+};
+
+static /* TODO: remove 'static' when moved to wireless.c */
+int
+rate_mbit2enum(int n) {
+	int i=0;
+	while(i<sizeof(ratelist)) {
+		if(n==ratelist[i]) return i;
+		i++;
+	}
+	return -EINVAL;
+}
+
+static int
+get_modulation(int r_enum, char suffix) {
+	if(suffix==',' || suffix==' ' || suffix=='\0') {
+		/* could shorten default_mod by 8 bytes:
+		if(r_enum>=DOT11_RATE_6) return DOT11_MOD_OFDM; */
+		return default_modulation[r_enum];
+	}
+	if(suffix=='c') {
+		if(r_enum<DOT11_RATE_5 || r_enum>DOT11_RATE_11) return -EINVAL;
+		return DOT11_MOD_CCK;
+	}
+	if(suffix=='p') {
+		if(r_enum<DOT11_RATE_5 || r_enum>DOT11_RATE_33) return -EINVAL;
+		return DOT11_MOD_PBCC;
+	}
+	if(suffix=='o') {
+		if(r_enum<DOT11_RATE_6) return -EINVAL;
+		return DOT11_MOD_OFDM;
+	}
+	if(suffix=='d') {
+		if(r_enum<DOT11_RATE_6) return -EINVAL;
+		return DOT11_MOD_CCKOFDM;
+	}
+	return -EINVAL;
+}
+
+#ifdef UNUSED
+static int
+fill_ratevector(const char **pstr, u8 *vector, int size,
+		int (*supported)(int mbit, int mod, void *opaque), void *opaque, int or_mask)
+{
+	unsigned long rate_mbit;
+	int rate_enum,mod;
+	const char *str = *pstr;
+	char c;
+
+	do {
+		rate_mbit = simple_strtoul(str, (char**)&str, 10);
+		if(rate_mbit>INT_MAX) return -EINVAL;
+
+		rate_enum = rate_mbit2enum(rate_mbit);
+		if(rate_enum<0) return rate_enum;
+
+		c = *str;
+		mod = get_modulation(rate_enum, c);
+		if(mod<0) return mod;
+
+		if(c>='a' && c<='z') c = *++str;
+		if(c!=',' && c!=' ' && c!='\0') return -EINVAL;
+
+		if(supported) {
+			int r = supported(rate_mbit, mod, opaque);
+			if(r) return r;
+		}
+
+		*vector++ = dot11ratebyte[rate_enum] | or_mask;
+
+		size--;
+		str++;
+	} while(size>0 && c==',');
+
+	if(size<1) return -E2BIG;
+	*vector=0; /* TODO: sort, remove dups? */
+
+	*pstr = str-1;
+	return 0;
+}
+
+static /* TODO: remove 'static' when moved to wireless.c */
+int
+fill_ratevectors(const char *str, u8 *brate, u8 *orate, int size,
+		int (*supported)(int mbit, int mod, void *opaque), void *opaque)
+{
+	int r;
+
+	r = fill_ratevector(&str, brate, size, supported, opaque, 0x80);
+	if(r) return r;
+
+	orate[0] = 0;
+	if(*str==' ') {
+		str++;
+		r = fill_ratevector(&str, orate, size, supported, opaque, 0);
+		if(r) return r;
+		/* TODO: sanitize, e.g. remove/error on rates already in basic rate set? */
+	}
+	if(*str)
+		return -EINVAL;
+
+	return 0;
+}
+#endif
+
+/* TODO: use u64 masks? */
+
+static int
+fill_ratemask(const char **pstr, u32* mask,
+		int (*supported)(int mbit, int mod,void *opaque),
+		u32 (*gen_mask)(int mbit, int mod,void *opaque),
+		void *opaque)
+{
+	unsigned long rate_mbit;
+	int rate_enum,mod;
+	u32 m = 0;
+	const char *str = *pstr;
+	char c;
+
+	do {
+		rate_mbit = simple_strtoul(str, (char**)&str, 10);
+		if(rate_mbit>INT_MAX) return -EINVAL;
+
+		rate_enum = rate_mbit2enum(rate_mbit);
+		if(rate_enum<0) return rate_enum;
+
+		c = *str;
+		mod = get_modulation(rate_enum, c);
+		if(mod<0) return mod;
+
+		if(c>='a' && c<='z') c = *++str;
+		if(c!=',' && c!=' ' && c!='\0') return -EINVAL;
+
+		if(supported) {
+			int r = supported(rate_mbit, mod, opaque);
+			if(r) return r;
+		}
+
+		m |= gen_mask(rate_mbit, mod, opaque);
+		str++;
+	} while(c==',');
+
+	*pstr = str-1;
+	*mask |= m;
+	return 0;
+}
+
+static /* TODO: remove 'static' when moved to wireless.c */
+int
+fill_ratemasks(const char *str, u32 *bmask, u32 *omask,
+		int (*supported)(int mbit, int mod,void *opaque),
+		u32 (*gen_mask)(int mbit, int mod,void *opaque),
+		void *opaque)
+{
+	int r;
+
+	r = fill_ratemask(&str, bmask, supported, gen_mask, opaque);
+	if(r) return r;
+
+	if(*str==' ') {
+		str++;
+		r = fill_ratemask(&str, omask, supported, gen_mask, opaque);
+		if(r) return r;
+	}
+	if(*str)
+		return -EINVAL;
+	return 0;
+}
diff -urN oldtree/drivers/net/wireless/tiacx/usb.c newtree/drivers/net/wireless/tiacx/usb.c
--- oldtree/drivers/net/wireless/tiacx/usb.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/net/wireless/tiacx/usb.c	2006-02-21 15:58:22.574714680 +0000
@@ -0,0 +1,1695 @@
+/***********************************************************************
+** Copyright (C) 2003  ACX100 Open Source Project
+**
+** The contents of this file are subject to the Mozilla Public
+** License Version 1.1 (the "License"); you may not use this file
+** except in compliance with the License. You may obtain a copy of
+** the License at http://www.mozilla.org/MPL/
+**
+** Software distributed under the License is distributed on an "AS
+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+** implied. See the License for the specific language governing
+** rights and limitations under the License.
+**
+** Alternatively, the contents of this file may be used under the
+** terms of the GNU Public License version 2 (the "GPL"), in which
+** case the provisions of the GPL are applicable instead of the
+** above.  If you wish to allow the use of your version of this file
+** only under the terms of the GPL and not to allow others to use
+** your version of this file under the MPL, indicate your decision
+** by deleting the provisions above and replace them with the notice
+** and other provisions required by the GPL.  If you do not delete
+** the provisions above, a recipient may use your version of this
+** file under either the MPL or the GPL.
+** ---------------------------------------------------------------------
+** Inquiries regarding the ACX100 Open Source Project can be
+** made directly to:
+**
+** acx100-users@lists.sf.net
+** http://acx100.sf.net
+** ---------------------------------------------------------------------
+*/
+
+/***********************************************************************
+** USB support for TI ACX100 based devices. Many parts are taken from
+** the PCI driver.
+**
+** Authors:
+**  Martin Wawro <martin.wawro AT uni-dortmund.de>
+**  Andreas Mohr <andi AT lisas.de>
+**
+** LOCKING
+** callback functions called by USB core are running in interrupt context
+** and thus have names with _i_.
+*/
+#define ACX_USB 1
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <linux/vmalloc.h>
+
+#include "acx.h"
+
+
+/***********************************************************************
+*/
+/* number of endpoints of an interface */
+#define NUM_EP(intf) (intf)->altsetting[0].desc.bNumEndpoints
+#define EP(intf, nr) (intf)->altsetting[0].endpoint[(nr)].desc
+#define GET_DEV(udev) usb_get_dev((udev))
+#define PUT_DEV(udev) usb_put_dev((udev))
+#define SET_NETDEV_OWNER(ndev, owner) /* not needed anymore ??? */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+/* removed in 2.6.14. We will use fake value for now */
+#define URB_ASYNC_UNLINK 0
+#endif
+
+
+/***********************************************************************
+*/
+#define ACX100_VENDOR_ID 0x2001
+#define ACX100_PRODUCT_ID_UNBOOTED 0x3B01
+#define ACX100_PRODUCT_ID_BOOTED 0x3B00
+
+#define ACX_USB_CTRL_TIMEOUT	5500   /* steps in ms */
+
+/* Buffer size for fw upload */
+#define ACX_USB_RWMEM_MAXLEN	2048
+
+/* The number of bulk URBs to use */
+#define ACX_TX_URB_CNT		8
+#define ACX_RX_URB_CNT		2
+
+/* Should be sent to the bulkout endpoint */
+#define ACX_USB_REQ_UPLOAD_FW	0x10
+#define ACX_USB_REQ_ACK_CS	0x11
+#define ACX_USB_REQ_CMD		0x12
+
+/***********************************************************************
+** Prototypes
+*/
+static int acxusb_e_probe(struct usb_interface *, const struct usb_device_id *);
+static void acxusb_e_disconnect(struct usb_interface *);
+static void acxusb_i_complete_tx(struct urb *, struct pt_regs *);
+static void acxusb_i_complete_rx(struct urb *, struct pt_regs *);
+static int acxusb_e_open(struct net_device *);
+static int acxusb_e_close(struct net_device *);
+static void acxusb_i_set_rx_mode(struct net_device *);
+static int acxusb_boot(struct usb_device *);
+
+static void acxusb_l_poll_rx(acx_device_t *adev, usb_rx_t* rx);
+
+static void acxusb_i_tx_timeout(struct net_device *);
+
+/* static void dump_device(struct usb_device *); */
+/* static void dump_device_descriptor(struct usb_device_descriptor *); */
+/* static void dump_config_descriptor(struct usb_config_descriptor *); */
+
+/***********************************************************************
+** Module Data
+*/
+#define TXBUFSIZE sizeof(usb_txbuffer_t)
+/*
+ * Now, this is just plain lying, but the device insists in giving us
+ * huge packets. We supply extra space after rxbuffer. Need to understand
+ * it better...
+ */
+#define RXBUFSIZE (sizeof(rxbuffer_t) + \
+		   (sizeof(usb_rx_t) - sizeof(struct usb_rx_plain)))
+
+static const struct usb_device_id
+acxusb_ids[] = {
+	{ USB_DEVICE(ACX100_VENDOR_ID, ACX100_PRODUCT_ID_BOOTED) },
+	{ USB_DEVICE(ACX100_VENDOR_ID, ACX100_PRODUCT_ID_UNBOOTED) },
+	{}
+};
+
+
+/* USB driver data structure as required by the kernel's USB core */
+static struct usb_driver
+acxusb_driver = {
+	.name = "acx_usb",
+	.probe = acxusb_e_probe,
+	.disconnect = acxusb_e_disconnect,
+	.id_table = acxusb_ids
+};
+
+
+/***********************************************************************
+** USB helper
+**
+** ldd3 ch13 says:
+** When the function is usb_kill_urb, the urb lifecycle is stopped. This
+** function is usually used when the device is disconnected from the system,
+** in the disconnect callback. For some drivers, the usb_unlink_urb function
+** should be used to tell the USB core to stop an urb. This function does not
+** wait for the urb to be fully stopped before returning to the caller.
+** This is useful for stoppingthe urb while in an interrupt handler or when
+** a spinlock is held, as waiting for a urb to fully stop requires the ability
+** for the USB core to put the calling process to sleep. This function requires
+** that the URB_ASYNC_UNLINK flag value be set in the urb that is being asked
+** to be stopped in order to work properly.
+**
+** (URB_ASYNC_UNLINK is obsolete, usb_unlink_urb will always be
+** asynchronous while usb_kill_urb is synchronous and should be called
+** directly (drivers/usb/core/urb.c))
+**
+** In light of this, timeout is just for paranoid reasons...
+*
+* Actually, it's useful for debugging. If we reach timeout, we're doing
+* something wrong with the urbs.
+*/
+static void
+acxusb_unlink_urb(struct urb* urb)
+{
+	if (!urb)
+		return;
+
+	if (urb->status == -EINPROGRESS) {
+		int timeout = 10;
+
+		usb_unlink_urb(urb);
+		while (--timeout && urb->status == -EINPROGRESS) {
+			mdelay(1);
+		}
+		if (!timeout) {
+			printk("acx_usb: urb unlink timeout!\n");
+		}
+	}
+}
+
+
+/***********************************************************************
+** EEPROM and PHY read/write helpers
+*/
+/***********************************************************************
+** acxusb_s_read_phy_reg
+*/
+int
+acxusb_s_read_phy_reg(acx_device_t *adev, u32 reg, u8 *charbuf)
+{
+	/* mem_read_write_t mem; */
+
+	FN_ENTER;
+
+	printk("%s doesn't seem to work yet, disabled.\n", __func__);
+
+	/*
+	mem.addr = cpu_to_le16(reg);
+	mem.type = cpu_to_le16(0x82);
+	mem.len = cpu_to_le32(4);
+	acx_s_issue_cmd(adev, ACX1xx_CMD_MEM_READ, &mem, sizeof(mem));
+	*charbuf = mem.data;
+	log(L_DEBUG, "read radio PHY[0x%04X]=0x%02X\n", reg, *charbuf);
+	*/
+
+	FN_EXIT1(OK);
+	return OK;
+}
+
+
+/***********************************************************************
+*/
+int
+acxusb_s_write_phy_reg(acx_device_t *adev, u32 reg, u8 value)
+{
+	mem_read_write_t mem;
+
+	FN_ENTER;
+
+	mem.addr = cpu_to_le16(reg);
+	mem.type = cpu_to_le16(0x82);
+	mem.len = cpu_to_le32(4);
+	mem.data = value;
+	acx_s_issue_cmd(adev, ACX1xx_CMD_MEM_WRITE, &mem, sizeof(mem));
+	log(L_DEBUG, "write radio PHY[0x%04X]=0x%02X\n", reg, value);
+
+	FN_EXIT1(OK);
+	return OK;
+}
+
+
+/***********************************************************************
+** acxusb_s_issue_cmd_timeo
+** Excecutes a command in the command mailbox
+**
+** buffer = a pointer to the data.
+** The data must not include 4 byte command header
+*/
+
+/* TODO: ideally we shall always know how much we need
+** and this shall be 0 */
+#define BOGUS_SAFETY_PADDING 0x40
+
+#undef FUNC
+#define FUNC "issue_cmd"
+
+#if !ACX_DEBUG
+int
+acxusb_s_issue_cmd_timeo(
+	acx_device_t *adev,
+	unsigned cmd,
+	void *buffer,
+	unsigned buflen,
+	unsigned timeout)
+{
+#else
+int
+acxusb_s_issue_cmd_timeo_debug(
+	acx_device_t *adev,
+	unsigned cmd,
+	void *buffer,
+	unsigned buflen,
+	unsigned timeout,
+	const char* cmdstr)
+{
+#endif
+	/* USB ignores timeout param */
+
+	struct usb_device *usbdev;
+	struct {
+		u16	cmd ACX_PACKED;
+		u16	status ACX_PACKED;
+		u8	data[1] ACX_PACKED;
+	} *loc;
+	const char *devname;
+	int acklen, blocklen, inpipe, outpipe;
+	int cmd_status;
+	int result;
+
+	FN_ENTER;
+
+	devname = adev->ndev->name;
+	/* no "wlan%%d: ..." please */
+	if (!devname || !devname[0] || devname[4]=='%')
+		devname = "acx";
+
+	log(L_CTL, FUNC"(cmd:%s,buflen:%u,type:0x%04X)\n",
+		cmdstr, buflen,
+		buffer ? le16_to_cpu(((acx_ie_generic_t *)buffer)->type) : -1);
+
+	loc = kmalloc(buflen + 4 + BOGUS_SAFETY_PADDING, GFP_KERNEL);
+	if (!loc) {
+		printk("%s: "FUNC"(): no memory for data buffer\n", devname);
+		goto bad;
+	}
+
+	/* get context from acx_device */
+	usbdev = adev->usbdev;
+
+	/* check which kind of command was issued */
+	loc->cmd = cpu_to_le16(cmd);
+	loc->status = 0;
+
+/* NB: buflen == frmlen + 4
+**
+** Interrogate: write 8 bytes: (cmd,status,rid,frmlen), then
+**		read (cmd,status,rid,frmlen,data[frmlen]) back
+**
+** Configure: write (cmd,status,rid,frmlen,data[frmlen])
+**
+** Possibly bogus special handling of ACX1xx_IE_SCAN_STATUS removed
+*/
+
+	/* now write the parameters of the command if needed */
+	acklen = buflen + 4 + BOGUS_SAFETY_PADDING;
+	blocklen = buflen;
+	if (buffer && buflen) {
+		/* if it's an INTERROGATE command, just pass the length
+		 * of parameters to read, as data */
+		if (cmd == ACX1xx_CMD_INTERROGATE) {
+			blocklen = 4;
+			acklen = buflen + 4;
+		}
+		memcpy(loc->data, buffer, blocklen);
+	}
+	blocklen += 4; /* account for cmd,status */
+
+	/* obtain the I/O pipes */
+	outpipe = usb_sndctrlpipe(usbdev, 0);
+	inpipe = usb_rcvctrlpipe(usbdev, 0);
+	log(L_CTL, "ctrl inpipe=0x%X outpipe=0x%X\n", inpipe, outpipe);
+	log(L_CTL, "sending USB control msg (out) (blocklen=%d)\n", blocklen);
+	if (acx_debug & L_DATA)
+		acx_dump_bytes(loc, blocklen);
+
+	result = usb_control_msg(usbdev, outpipe,
+		ACX_USB_REQ_CMD, /* request */
+		USB_TYPE_VENDOR|USB_DIR_OUT, /* requesttype */
+		0, /* value */
+		0, /* index */
+		loc, /* dataptr */
+		blocklen, /* size */
+		ACX_USB_CTRL_TIMEOUT /* timeout in ms */
+	);
+
+	if (result == -ENODEV) {
+		log(L_CTL, "no device present (unplug?)\n");
+		goto good;
+	}
+
+	log(L_CTL, "wrote %d bytes\n", result);
+	if (result < 0) {
+		goto bad;
+	}
+
+	/* check for device acknowledge */
+	log(L_CTL, "sending USB control msg (in) (acklen=%d)\n", acklen);
+	loc->status = 0; /* delete old status flag -> set to IDLE */
+	/* shall we zero out the rest? */
+	result = usb_control_msg(usbdev, inpipe,
+		ACX_USB_REQ_CMD, /* request */
+		USB_TYPE_VENDOR|USB_DIR_IN, /* requesttype */
+		0, /* value */
+		0, /* index */
+		loc, /* dataptr */
+		acklen, /* size */
+		ACX_USB_CTRL_TIMEOUT /* timeout in ms */
+	);
+	if (result < 0) {
+		printk("%s: "FUNC"(): USB read error %d\n", devname, result);
+		goto bad;
+	}
+	if (acx_debug & L_CTL) {
+		printk("read %d bytes: ", result);
+		acx_dump_bytes(loc, result);
+	}
+
+/*
+   check for result==buflen+4? Was seen:
+
+interrogate(type:ACX100_IE_DOT11_ED_THRESHOLD,len:4)
+issue_cmd(cmd:ACX1xx_CMD_INTERROGATE,buflen:8,type:4111)
+ctrl inpipe=0x80000280 outpipe=0x80000200
+sending USB control msg (out) (blocklen=8)
+01 00 00 00 0F 10 04 00
+wrote 8 bytes
+sending USB control msg (in) (acklen=12) sizeof(loc->data
+read 4 bytes <==== MUST BE 12!!
+*/
+
+	cmd_status = le16_to_cpu(loc->status);
+	if (cmd_status != 1) {
+		printk("%s: "FUNC"(): cmd_status is not SUCCESS: %d (%s)\n",
+			devname, cmd_status, acx_cmd_status_str(cmd_status));
+		/* TODO: goto bad; ? */
+	}
+	if ((cmd == ACX1xx_CMD_INTERROGATE) && buffer && buflen) {
+		memcpy(buffer, loc->data, buflen);
+		log(L_CTL, "response frame: cmd=0x%04X status=%d\n",
+			le16_to_cpu(loc->cmd),
+			cmd_status);
+	}
+good:
+	kfree(loc);
+	FN_EXIT1(OK);
+	return OK;
+bad:
+	/* Give enough info so that callers can avoid
+	** printing their own diagnostic messages */
+#if ACX_DEBUG
+	printk("%s: "FUNC"(cmd:%s) FAILED\n", devname, cmdstr);
+#else
+	printk("%s: "FUNC"(cmd:0x%04X) FAILED\n", devname, cmd);
+#endif
+	dump_stack();
+	kfree(loc);
+	FN_EXIT1(NOT_OK);
+	return NOT_OK;
+}
+
+
+/***********************************************************************
+** acxusb_boot()
+** Inputs:
+**    usbdev -> Pointer to kernel's usb_device structure
+**
+** Returns:
+**  (int) Errorcode or 0 on success
+**
+** This function triggers the loading of the firmware image from harddisk
+** and then uploads the firmware to the USB device. After uploading the
+** firmware and transmitting the checksum, the device resets and appears
+** as a new device on the USB bus (the device we can finally deal with)
+*/
+static int
+acxusb_boot(struct usb_device *usbdev)
+{
+	static const char filename[] = "tiacx100usb";
+
+	char *firmware = NULL;
+	char *usbbuf;
+	unsigned int offset;
+	unsigned int len, inpipe, outpipe;
+	u32 checksum;
+	u32 size;
+	int result;
+
+	FN_ENTER;
+
+	usbbuf = kmalloc(ACX_USB_RWMEM_MAXLEN, GFP_KERNEL);
+	if (!usbbuf) {
+		printk(KERN_ERR "acx: no memory for USB transfer buffer ("
+			STRING(ACX_USB_RWMEM_MAXLEN)" bytes)\n");
+		result = -ENOMEM;
+		goto end;
+	}
+	firmware = (char *)acx_s_read_fw(&usbdev->dev, filename, &size);
+	if (!firmware) {
+		result = -EIO;
+		goto end;
+	}
+	log(L_INIT, "firmware size: %d bytes\n", size);
+
+	/* Obtain the I/O pipes */
+	outpipe = usb_sndctrlpipe(usbdev, 0);
+	inpipe = usb_rcvctrlpipe(usbdev, 0);
+
+	/* now upload the firmware, slice the data into blocks */
+	offset = 8;
+	while (offset < size) {
+		len = size - offset;
+		if (len >= ACX_USB_RWMEM_MAXLEN) {
+			len = ACX_USB_RWMEM_MAXLEN;
+		}
+		log(L_INIT, "uploading firmware (%d bytes, offset=%d)\n",
+						len, offset);
+		result = 0;
+		memcpy(usbbuf, firmware + offset, len);
+		result = usb_control_msg(usbdev, outpipe,
+			ACX_USB_REQ_UPLOAD_FW,
+			USB_TYPE_VENDOR|USB_DIR_OUT,
+			size - 8, /* value */
+			0, /* index */
+			usbbuf, /* dataptr */
+			len, /* size */
+			3000 /* timeout in ms */
+		);
+		offset += len;
+		if (result < 0) {
+			printk(KERN_ERR "acx: error %d during upload "
+				"of firmware, aborting\n", result);
+			goto end;
+		}
+	}
+
+	/* finally, send the checksum and reboot the device */
+	checksum = le32_to_cpu(*(u32 *)firmware);
+	/* is this triggers the reboot? */
+	result = usb_control_msg(usbdev, outpipe,
+		ACX_USB_REQ_UPLOAD_FW,
+		USB_TYPE_VENDOR|USB_DIR_OUT,
+		checksum & 0xffff, /* value */
+		checksum >> 16, /* index */
+		NULL, /* dataptr */
+		0, /* size */
+		3000 /* timeout in ms */
+	);
+	if (result < 0) {
+		printk(KERN_ERR "acx: error %d during tx of checksum, "
+				"aborting\n", result);
+		goto end;
+	}
+	result = usb_control_msg(usbdev, inpipe,
+		ACX_USB_REQ_ACK_CS,
+		USB_TYPE_VENDOR|USB_DIR_IN,
+		checksum & 0xffff, /* value */
+		checksum >> 16, /* index */
+		usbbuf, /* dataptr */
+		8, /* size */
+		3000 /* timeout in ms */
+	);
+	if (result < 0) {
+		printk(KERN_ERR "acx: error %d during ACK of checksum, "
+				"aborting\n", result);
+		goto end;
+	}
+	if (*usbbuf != 0x10) {
+		kfree(usbbuf);
+		printk(KERN_ERR "acx: invalid checksum?\n");
+		result = -EINVAL;
+		goto end;
+	}
+	result = 0;
+end:
+	vfree(firmware);
+	kfree(usbbuf);
+
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/*
+ * temporary helper function to at least fill important cfgopt members with
+ * useful replacement values until we figure out how one manages to fetch
+ * the configoption struct in the USB device case...
+ */
+int
+acxusb_s_fill_configoption(acx_device_t *adev)
+{
+	printk("FIXME: haven't figured out how to fetch configoption struct "
+		"from USB device, passing hardcoded values instead\n");
+	adev->cfgopt_probe_delay = 200;
+	adev->cfgopt_dot11CCAModes = 4;
+	adev->cfgopt_dot11Diversity = 1;
+	adev->cfgopt_dot11ShortPreambleOption = 1;
+	adev->cfgopt_dot11PBCCOption = 1;
+	adev->cfgopt_dot11ChannelAgility = 0;
+	adev->cfgopt_dot11PhyType = 5;
+	adev->cfgopt_dot11TempType = 1;
+	return OK;
+}
+
+/***********************************************************************
+** acxusb_e_probe()
+**
+** This function is invoked by the kernel's USB core whenever a new device is
+** attached to the system or the module is loaded. It is presented a usb_device
+** structure from which information regarding the device is obtained and evaluated.
+** In case this driver is able to handle one of the offered devices, it returns
+** a non-null pointer to a driver context and thereby claims the device.
+*/
+
+static void
+dummy_netdev_init(struct net_device *ndev) {}
+
+static int
+acxusb_e_probe(struct usb_interface *intf, const struct usb_device_id *devID)
+{
+	struct usb_device *usbdev = interface_to_usbdev(intf);
+	acx_device_t *adev = NULL;
+	struct net_device *ndev = NULL;
+	struct usb_config_descriptor *config;
+	struct usb_endpoint_descriptor *epdesc;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
+	struct usb_host_endpoint *ep;
+#endif
+	struct usb_interface_descriptor *ifdesc;
+	const char* msg;
+	int numconfigs, numfaces, numep;
+	int result = OK;
+	int i;
+
+	FN_ENTER;
+
+	/* First check if this is the "unbooted" hardware */
+	if ((usbdev->descriptor.idVendor == ACX100_VENDOR_ID)
+	 && (usbdev->descriptor.idProduct == ACX100_PRODUCT_ID_UNBOOTED)) {
+		/* Boot the device (i.e. upload the firmware) */
+		acxusb_boot(usbdev);
+
+		/* OK, we are done with booting. Normally, the
+		** ID for the unbooted device should disappear
+		** and it will not need a driver anyway...so
+		** return a NULL
+		*/
+		log(L_INIT, "finished booting, returning from probe()\n");
+		result = OK; /* success */
+		goto end;
+	}
+
+	if ((usbdev->descriptor.idVendor != ACX100_VENDOR_ID)
+	 || (usbdev->descriptor.idProduct != ACX100_PRODUCT_ID_BOOTED)) {
+		goto end_nodev;
+	}
+
+/* Ok, so it's our device and it has already booted */
+
+	/* Allocate memory for a network device */
+
+	ndev = alloc_netdev(sizeof(*adev), "wlan%d", dummy_netdev_init);
+	/* (NB: memsets to 0 entire area) */
+	if (!ndev) {
+		msg = "acx: no memory for netdev\n";
+		goto end_nomem;
+	}
+
+	/* Register the callbacks for the network device functions */
+
+	ether_setup(ndev);
+	ndev->open = &acxusb_e_open;
+	ndev->stop = &acxusb_e_close;
+	ndev->hard_start_xmit = (void *)&acx_i_start_xmit;
+	ndev->get_stats = (void *)&acx_e_get_stats;
+#if IW_HANDLER_VERSION <= 5
+	ndev->get_wireless_stats = (void *)&acx_e_get_wireless_stats;
+#endif
+	ndev->wireless_handlers = (struct iw_handler_def *)&acx_ioctl_handler_def;
+	ndev->set_multicast_list = (void *)&acxusb_i_set_rx_mode;
+#ifdef HAVE_TX_TIMEOUT
+	ndev->tx_timeout = &acxusb_i_tx_timeout;
+	ndev->watchdog_timeo = 4 * HZ;
+#endif
+	ndev->change_mtu = &acx_e_change_mtu;
+	SET_MODULE_OWNER(ndev);
+
+	/* Setup private driver context */
+
+	adev = ndev2adev(ndev);
+	adev->ndev = ndev;
+
+	adev->dev_type = DEVTYPE_USB;
+	adev->chip_type = CHIPTYPE_ACX100;
+
+	/* FIXME: should be read from register (via firmware) using standard ACX code */
+	adev->radio_type = RADIO_MAXIM_0D;
+
+	adev->usbdev = usbdev;
+	spin_lock_init(&adev->lock);    /* initial state: unlocked */
+	sema_init(&adev->sem, 1);       /* initial state: 1 (upped) */
+
+	/* Check that this is really the hardware we know about.
+	** If not sure, at least notify the user that he
+	** may be in trouble...
+	*/
+	numconfigs = (int)usbdev->descriptor.bNumConfigurations;
+	if (numconfigs != 1)
+		printk("acx: number of configurations is %d, "
+			"this driver only knows how to handle 1, "
+			"be prepared for surprises\n", numconfigs);
+
+	config = &usbdev->config->desc;
+	numfaces = config->bNumInterfaces;
+	if (numfaces != 1)
+		printk("acx: number of interfaces is %d, "
+			"this driver only knows how to handle 1, "
+			"be prepared for surprises\n", numfaces);
+
+	ifdesc = &intf->altsetting->desc;
+	numep = ifdesc->bNumEndpoints;
+	log(L_DEBUG, "# of endpoints: %d\n", numep);
+
+	/* obtain information about the endpoint
+	** addresses, begin with some default values
+	*/
+	adev->bulkoutep = 1;
+	adev->bulkinep = 1;
+	for (i = 0; i < numep; i++) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
+		ep = usbdev->ep_in[i];
+		if (!ep)
+			continue;
+		epdesc = &ep->desc;
+#else
+		epdesc = usb_epnum_to_ep_desc(usbdev, i);
+		if (!epdesc)
+			continue;
+#endif
+		if (epdesc->bmAttributes & USB_ENDPOINT_XFER_BULK) {
+			if (epdesc->bEndpointAddress & 0x80)
+				adev->bulkinep = epdesc->bEndpointAddress & 0xF;
+			else
+				adev->bulkoutep = epdesc->bEndpointAddress & 0xF;
+		}
+	}
+	log(L_DEBUG, "bulkout ep: 0x%X\n", adev->bulkoutep);
+	log(L_DEBUG, "bulkin ep: 0x%X\n", adev->bulkinep);
+
+	/* already done by memset: adev->rxtruncsize = 0; */
+	log(L_DEBUG, "TXBUFSIZE=%d RXBUFSIZE=%d\n",
+				(int) TXBUFSIZE, (int) RXBUFSIZE);
+
+	/* Allocate the RX/TX containers. */
+	adev->usb_tx = kmalloc(sizeof(usb_tx_t) * ACX_TX_URB_CNT, GFP_KERNEL);
+	if (!adev->usb_tx) {
+		msg = "acx: no memory for tx container";
+		goto end_nomem;
+	}
+	adev->usb_rx = kmalloc(sizeof(usb_rx_t) * ACX_RX_URB_CNT, GFP_KERNEL);
+	if (!adev->usb_rx) {
+		msg = "acx: no memory for rx container";
+		goto end_nomem;
+	}
+
+	/* Setup URBs for bulk-in/out messages */
+	for (i = 0; i < ACX_RX_URB_CNT; i++) {
+		adev->usb_rx[i].urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!adev->usb_rx[i].urb) {
+			msg = "acx: no memory for input URB\n";
+			goto end_nomem;
+		}
+		adev->usb_rx[i].urb->status = 0;
+		adev->usb_rx[i].adev = adev;
+		adev->usb_rx[i].busy = 0;
+	}
+
+	for (i = 0; i< ACX_TX_URB_CNT; i++) {
+		adev->usb_tx[i].urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!adev->usb_tx[i].urb) {
+			msg = "acx: no memory for output URB\n";
+			goto end_nomem;
+		}
+		adev->usb_tx[i].urb->status = 0;
+		adev->usb_tx[i].adev = adev;
+		adev->usb_tx[i].busy = 0;
+	}
+	adev->tx_free = ACX_TX_URB_CNT;
+
+	usb_set_intfdata(intf, adev);
+	SET_NETDEV_DEV(ndev, &intf->dev);
+
+	/* TODO: move all of fw cmds to open()? But then we won't know our MAC addr
+	   until ifup (it's available via reading ACX1xx_IE_DOT11_STATION_ID)... */
+
+	/* put acx out of sleep mode and initialize it */
+	acx_s_issue_cmd(adev, ACX1xx_CMD_WAKE, NULL, 0);
+
+	acxusb_s_fill_configoption(adev);
+
+	result = acx_s_init_mac(adev);
+	if (result)
+		goto end;
+
+	acx_s_set_defaults(adev);
+	acx_s_get_firmware_version(adev);
+	acx_display_hardware_details(adev);
+
+	/* Register the network device */
+	log(L_INIT, "registering network device\n");
+	result = register_netdev(ndev);
+	if (result) {
+		msg = "acx: failed to register USB network device "
+			"(error %d)\n";
+		goto end_nomem;
+	}
+
+	acx_proc_register_entries(ndev);
+
+	acx_stop_queue(ndev, "on probe");
+	acx_carrier_off(ndev, "on probe");
+
+	printk("acx: USB module " ACX_RELEASE " loaded successfully\n");
+
+#if CMD_DISCOVERY
+	great_inquisitor(adev);
+#endif
+
+	/* Everything went OK, we are happy now	*/
+	result = OK;
+	goto end;
+
+end_nomem:
+	printk(msg, result);
+
+	if (ndev) {
+		if (adev->usb_rx) {
+			for (i = 0; i < ACX_RX_URB_CNT; i++)
+				usb_free_urb(adev->usb_rx[i].urb);
+			kfree(adev->usb_rx);
+		}
+		if (adev->usb_tx) {
+			for (i = 0; i < ACX_TX_URB_CNT; i++)
+				usb_free_urb(adev->usb_tx[i].urb);
+			kfree(adev->usb_tx);
+		}
+		free_netdev(ndev);
+	}
+
+	result = -ENOMEM;
+	goto end;
+
+end_nodev:
+	/* no device we could handle, return error. */
+	result = -EIO;
+
+end:
+	FN_EXIT1(result);
+	return result;
+}
+
+
+/***********************************************************************
+** acxusb_e_disconnect()
+**
+** This function is invoked whenever the user pulls the plug from the USB
+** device or the module is removed from the kernel. In these cases, the
+** network devices have to be taken down and all allocated memory has
+** to be freed.
+*/
+static void
+acxusb_e_disconnect(struct usb_interface *intf)
+{
+	acx_device_t *adev = usb_get_intfdata(intf);
+	unsigned long flags;
+	int i;
+
+	FN_ENTER;
+
+	/* No WLAN device... no sense */
+	if (!adev)
+		goto end;
+
+	/* Unregister network device
+	 *
+	 * If the interface is up, unregister_netdev() will take
+	 * care of calling our close() function, which takes
+	 * care of unlinking the urbs, sending the device to
+	 * sleep, etc...
+	 * This can't be called with sem or lock held because
+	 * _close() will try to grab it as well if it's called,
+	 * deadlocking the machine.
+	 */
+	unregister_netdev(adev->ndev);
+
+	acx_sem_lock(adev);
+	acx_lock(adev, flags);
+	/* This device exists no more */
+	usb_set_intfdata(intf, NULL);
+	acx_proc_unregister_entries(adev->ndev);
+
+	/*
+	 * Here we only free them. _close() took care of
+	 * unlinking them.
+	 */
+	for (i = 0; i < ACX_RX_URB_CNT; ++i) {
+		usb_free_urb(adev->usb_rx[i].urb);
+	}
+	for (i = 0; i< ACX_TX_URB_CNT; ++i) {
+		usb_free_urb(adev->usb_tx[i].urb);
+	}
+
+	/* Freeing containers */
+	kfree(adev->usb_rx);
+	kfree(adev->usb_tx);
+
+	acx_unlock(adev, flags);
+	acx_sem_unlock(adev);
+
+	free_netdev(adev->ndev);
+end:
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acxusb_e_open()
+** This function is called when the user sets up the network interface.
+** It initializes a management timer, sets up the USB card and starts
+** the network tx queue and USB receive.
+*/
+static int
+acxusb_e_open(struct net_device *ndev)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	unsigned long flags;
+	int i;
+
+	FN_ENTER;
+
+	acx_sem_lock(adev);
+
+	/* put the ACX100 out of sleep mode */
+	acx_s_issue_cmd(adev, ACX1xx_CMD_WAKE, NULL, 0);
+
+	acx_init_task_scheduler(adev);
+
+	init_timer(&adev->mgmt_timer);
+	adev->mgmt_timer.function = acx_i_timer;
+	adev->mgmt_timer.data = (unsigned long)adev;
+
+	/* acx_s_start needs it */
+	SET_BIT(adev->dev_state_mask, ACX_STATE_IFACE_UP);
+	acx_s_start(adev);
+
+	/* don't acx_start_queue() here, we need to associate first */
+
+	acx_lock(adev, flags);
+	for (i = 0; i < ACX_RX_URB_CNT; i++) {
+		adev->usb_rx[i].urb->status = 0;
+	}
+
+	acxusb_l_poll_rx(adev, &adev->usb_rx[0]);
+
+	acx_unlock(adev, flags);
+
+	acx_sem_unlock(adev);
+
+	FN_EXIT0;
+	return 0;
+}
+
+
+/***********************************************************************
+** acxusb_e_close()
+**
+** This function stops the network functionality of the interface (invoked
+** when the user calls ifconfig <wlan> down). The tx queue is halted and
+** the device is marked as down. In case there were any pending USB bulk
+** transfers, these are unlinked (asynchronously). The module in-use count
+** is also decreased in this function.
+*/
+static int
+acxusb_e_close(struct net_device *ndev)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	unsigned long flags;
+	int i;
+
+	FN_ENTER;
+
+#ifdef WE_STILL_DONT_CARE_ABOUT_IT
+	/* Transmit a disassociate frame */
+	lock
+	acx_l_transmit_disassoc(adev, &client);
+	unlock
+#endif
+
+	acx_sem_lock(adev);
+
+	CLEAR_BIT(adev->dev_state_mask, ACX_STATE_IFACE_UP);
+
+/* Code below is remarkably similar to acxpci_s_down(). Maybe we can merge them? */
+
+	/* Make sure we don't get any more rx requests */
+	acx_s_issue_cmd(adev, ACX1xx_CMD_DISABLE_RX, NULL, 0);
+	acx_s_issue_cmd(adev, ACX1xx_CMD_DISABLE_TX, NULL, 0);
+
+	/*
+	 * We must do FLUSH *without* holding sem to avoid a deadlock.
+	 * See pci.c:acxpci_s_down() for deails.
+	 */
+	acx_sem_unlock(adev);
+	FLUSH_SCHEDULED_WORK();
+	acx_sem_lock(adev);
+
+	/* Power down the device */
+	acx_s_issue_cmd(adev, ACX1xx_CMD_SLEEP, NULL, 0);
+
+	/* Stop the transmit queue, mark the device as DOWN */
+	acx_lock(adev, flags);
+	acx_stop_queue(ndev, "on ifdown");
+	acx_set_status(adev, ACX_STATUS_0_STOPPED);
+	/* stop pending rx/tx urb transfers */
+	for (i = 0; i < ACX_TX_URB_CNT; i++) {
+		acxusb_unlink_urb(adev->usb_tx[i].urb);
+		adev->usb_tx[i].busy = 0;
+	}
+	for (i = 0; i < ACX_RX_URB_CNT; i++) {
+		acxusb_unlink_urb(adev->usb_rx[i].urb);
+		adev->usb_rx[i].busy = 0;
+	}
+	adev->tx_free = ACX_TX_URB_CNT;
+	acx_unlock(adev, flags);
+
+	/* Must do this outside of lock */
+	del_timer_sync(&adev->mgmt_timer);
+
+	acx_sem_unlock(adev);
+
+	FN_EXIT0;
+	return 0;
+}
+
+
+/***********************************************************************
+** acxusb_l_poll_rx
+** This function (re)initiates a bulk-in USB transfer on a given urb
+*/
+static void
+acxusb_l_poll_rx(acx_device_t *adev, usb_rx_t* rx)
+{
+	struct usb_device *usbdev;
+	struct urb *rxurb;
+	int errcode, rxnum;
+	unsigned int inpipe;
+
+	FN_ENTER;
+
+	rxurb = rx->urb;
+	usbdev = adev->usbdev;
+
+	rxnum = rx - adev->usb_rx;
+
+	inpipe = usb_rcvbulkpipe(usbdev, adev->bulkinep);
+	if (unlikely(rxurb->status == -EINPROGRESS)) {
+		printk(KERN_ERR "acx: error, rx triggered while rx urb in progress\n");
+		/* FIXME: this is nasty, receive is being cancelled by this code
+		 * on the other hand, this should not happen anyway...
+		 */
+		usb_unlink_urb(rxurb);
+	} else
+	if (unlikely(rxurb->status == -ECONNRESET)) {
+		log(L_USBRXTX, "acx_usb: _poll_rx: connection reset\n");
+		goto end;
+	}
+	rxurb->actual_length = 0;
+	usb_fill_bulk_urb(rxurb, usbdev, inpipe,
+		&rx->bulkin, /* dataptr */
+		RXBUFSIZE, /* size */
+		acxusb_i_complete_rx, /* handler */
+		rx /* handler param */
+	);
+	rxurb->transfer_flags = URB_ASYNC_UNLINK;
+
+	/* ATOMIC: we may be called from complete_rx() usb callback */
+	errcode = usb_submit_urb(rxurb, GFP_ATOMIC);
+	/* FIXME: evaluate the error code! */
+	log(L_USBRXTX, "SUBMIT RX (%d) inpipe=0x%X size=%d errcode=%d\n",
+			rxnum, inpipe, (int) RXBUFSIZE, errcode);
+end:
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acxusb_i_complete_rx()
+** Inputs:
+**     urb -> pointer to USB request block
+**    regs -> pointer to register-buffer for syscalls (see asm/ptrace.h)
+**
+** This function is invoked by USB subsystem whenever a bulk receive
+** request returns.
+** The received data is then committed to the network stack and the next
+** USB receive is triggered.
+*/
+static void
+acxusb_i_complete_rx(struct urb *urb, struct pt_regs *regs)
+{
+	acx_device_t *adev;
+	rxbuffer_t *ptr;
+	rxbuffer_t *inbuf;
+	usb_rx_t *rx;
+	unsigned long flags;
+	int size, remsize, packetsize, rxnum;
+
+	FN_ENTER;
+
+	BUG_ON(!urb->context);
+
+	rx = (usb_rx_t *)urb->context;
+	adev = rx->adev;
+
+	acx_lock(adev, flags);
+
+	/*
+	 * Happens on disconnect or close. Don't play with the urb.
+	 * Don't resubmit it. It will get unlinked by close()
+	 */
+	if (unlikely(!(adev->dev_state_mask & ACX_STATE_IFACE_UP))) {
+		log(L_USBRXTX, "rx: device is down, not doing anything\n");
+		goto end_unlock;
+	}
+
+	inbuf = &rx->bulkin;
+	size = urb->actual_length;
+	remsize = size;
+	rxnum = rx - adev->usb_rx;
+
+	log(L_USBRXTX, "RETURN RX (%d) status=%d size=%d\n",
+				rxnum, urb->status, size);
+
+	/* Send the URB that's waiting. */
+	log(L_USBRXTX, "rxnum=%d, sending=%d\n", rxnum, rxnum^1);
+	acxusb_l_poll_rx(adev, &adev->usb_rx[rxnum^1]);
+
+	if (unlikely(size > sizeof(rxbuffer_t)))
+		printk("acx_usb: rx too large: %d, please report\n", size);
+
+	/* check if the transfer was aborted */
+	switch (urb->status) {
+	case 0: /* No error */
+		break;
+	case -EOVERFLOW:
+		printk(KERN_ERR "acx: rx data overrun\n");
+		adev->rxtruncsize = 0; /* Not valid anymore. */
+		goto end_unlock;
+	case -ECONNRESET:
+		adev->rxtruncsize = 0;
+		goto end_unlock;
+	case -ESHUTDOWN: /* rmmod */
+		adev->rxtruncsize = 0;
+		goto end_unlock;
+	default:
+		adev->rxtruncsize = 0;
+		adev->stats.rx_errors++;
+		printk("acx: rx error (urb status=%d)\n", urb->status);
+		goto end_unlock;
+	}
+
+	if (unlikely(!size))
+		printk("acx: warning, encountered zerolength rx packet\n");
+
+	if (urb->transfer_buffer != inbuf)
+		goto end_unlock;
+
+	/* check if previous frame was truncated
+	** FIXME: this code can only handle truncation
+	** of consecutive packets!
+	*/
+	ptr = inbuf;
+	if (adev->rxtruncsize) {
+		int tail_size;
+
+		ptr = &adev->rxtruncbuf;
+		packetsize = RXBUF_BYTES_USED(ptr);
+		if (acx_debug & L_USBRXTX) {
+			printk("handling truncated frame (truncsize=%d size=%d "
+					"packetsize(from trunc)=%d)\n",
+					adev->rxtruncsize, size, packetsize);
+			acx_dump_bytes(ptr, RXBUF_HDRSIZE);
+			acx_dump_bytes(inbuf, RXBUF_HDRSIZE);
+		}
+
+		/* bytes needed for rxtruncbuf completion: */
+		tail_size = packetsize - adev->rxtruncsize;
+
+		if (size < tail_size) {
+			/* there is not enough data to complete this packet,
+			** simply append the stuff to the truncation buffer
+			*/
+			memcpy(((char *)ptr) + adev->rxtruncsize, inbuf, size);
+			adev->rxtruncsize += size;
+			remsize = 0;
+		} else {
+			/* ok, this data completes the previously
+			** truncated packet. copy it into a descriptor
+			** and give it to the rest of the stack	*/
+
+			/* append tail to previously truncated part
+			** NB: adev->rxtruncbuf (pointed to by ptr) can't
+			** overflow because this is already checked before
+			** truncation buffer was filled. See below,
+			** "if (packetsize > sizeof(rxbuffer_t))..." code */
+			memcpy(((char *)ptr) + adev->rxtruncsize, inbuf, tail_size);
+
+			if (acx_debug & L_USBRXTX) {
+				printk("full trailing packet + 12 bytes:\n");
+				acx_dump_bytes(inbuf, tail_size + RXBUF_HDRSIZE);
+			}
+			acx_l_process_rxbuf(adev, ptr);
+			adev->rxtruncsize = 0;
+			ptr = (rxbuffer_t *) (((char *)inbuf) + tail_size);
+			remsize -= tail_size;
+		}
+		log(L_USBRXTX, "post-merge size=%d remsize=%d\n",
+						size, remsize);
+	}
+
+	/* size = USB data block size
+	** remsize = unprocessed USB bytes left
+	** ptr = current pos in USB data block
+	*/
+	while (remsize) {
+		if (remsize < RXBUF_HDRSIZE) {
+			printk("acx: truncated rx header (%d bytes)!\n",
+				remsize);
+			if (ACX_DEBUG)
+				acx_dump_bytes(ptr, remsize);
+			break;
+		}
+
+		packetsize = RXBUF_BYTES_USED(ptr);
+		log(L_USBRXTX, "packet with packetsize=%d\n", packetsize);
+
+		if (RXBUF_IS_TXSTAT(ptr)) {
+			/* do rate handling */
+			usb_txstatus_t *stat = (void*)ptr;
+			u16 client_no = (u16)stat->hostdata;
+
+			log(L_USBRXTX, "tx: stat: mac_cnt_rcvd:%04X "
+			"queue_index:%02X mac_status:%02X hostdata:%08X "
+			"rate:%u ack_failures:%02X rts_failures:%02X "
+			"rts_ok:%02X\n",
+			stat->mac_cnt_rcvd,
+			stat->queue_index, stat->mac_status, stat->hostdata,
+			stat->rate, stat->ack_failures, stat->rts_failures,
+			stat->rts_ok);
+
+			if (adev->rate_auto && client_no < VEC_SIZE(adev->sta_list)) {
+				client_t *clt = &adev->sta_list[client_no];
+				u16 cur = stat->hostdata >> 16;
+
+				if (clt && clt->rate_cur == cur) {
+					acx_l_handle_txrate_auto(adev, clt,
+						cur, /* intended rate */
+						stat->rate, 0, /* actually used rate */
+						stat->mac_status, /* error? */
+						ACX_TX_URB_CNT - adev->tx_free);
+				}
+			}
+			goto next;
+		}
+
+		if (packetsize > sizeof(rxbuffer_t)) {
+			printk("acx: packet exceeds max wlan "
+				"frame size (%d > %d). size=%d\n",
+				packetsize, (int) sizeof(rxbuffer_t), size);
+			if (ACX_DEBUG)
+				acx_dump_bytes(ptr, 16);
+			/* FIXME: put some real error-handling in here! */
+			break;
+		}
+
+		if (packetsize > remsize) {
+			/* frame truncation handling */
+			if (acx_debug & L_USBRXTX) {
+				printk("need to truncate packet, "
+					"packetsize=%d remsize=%d "
+					"size=%d bytes:",
+					packetsize, remsize, size);
+				acx_dump_bytes(ptr, RXBUF_HDRSIZE);
+			}
+			memcpy(&adev->rxtruncbuf, ptr, remsize);
+			adev->rxtruncsize = remsize;
+			break;
+		}
+
+		/* packetsize <= remsize */
+		/* now handle the received data */
+		acx_l_process_rxbuf(adev, ptr);
+next:
+		ptr = (rxbuffer_t *)(((char *)ptr) + packetsize);
+		remsize -= packetsize;
+		if ((acx_debug & L_USBRXTX) && remsize) {
+			printk("more than one packet in buffer, "
+						"second packet hdr:");
+			acx_dump_bytes(ptr, RXBUF_HDRSIZE);
+		}
+	}
+
+end_unlock:
+	acx_unlock(adev, flags);
+/* end: */
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+** acxusb_i_complete_tx()
+** Inputs:
+**     urb -> pointer to USB request block
+**    regs -> pointer to register-buffer for syscalls (see asm/ptrace.h)
+**
+** This function is invoked upon termination of a USB transfer.
+*/
+static void
+acxusb_i_complete_tx(struct urb *urb, struct pt_regs *regs)
+{
+	acx_device_t *adev;
+	usb_tx_t *tx;
+	unsigned long flags;
+	int txnum;
+
+	FN_ENTER;
+
+	BUG_ON(!urb->context);
+
+	tx = (usb_tx_t *)urb->context;
+	adev = tx->adev;
+
+	txnum = tx - adev->usb_tx;
+
+	acx_lock(adev, flags);
+
+	/*
+	 * If the iface isn't up, we don't have any right
+	 * to play with them. The urb may get unlinked.
+	 */
+	if (unlikely(!(adev->dev_state_mask & ACX_STATE_IFACE_UP))) {
+		log(L_USBRXTX, "tx: device is down, not doing anything\n");
+		goto end_unlock;
+	}
+
+	log(L_USBRXTX, "RETURN TX (%d): status=%d size=%d\n",
+				txnum, urb->status, urb->actual_length);
+
+	/* handle USB transfer errors */
+	switch (urb->status) {
+	case 0:	/* No error */
+		break;
+	case -ESHUTDOWN:
+		goto end_unlock;
+		break;
+	case -ECONNRESET:
+		goto end_unlock;
+		break;
+		/* FIXME: real error-handling code here please */
+	default:
+		printk(KERN_ERR "acx: tx error, urb status=%d\n", urb->status);
+		/* FIXME: real error-handling code here please */
+	}
+
+	/* free the URB and check for more data	*/
+	tx->busy = 0;
+	adev->tx_free++;
+	if ((adev->tx_free >= TX_START_QUEUE)
+	 && (adev->status == ACX_STATUS_4_ASSOCIATED)
+	 && (acx_queue_stopped(adev->ndev))
+	) {
+		log(L_BUF, "tx: wake queue (%u free txbufs)\n",
+				adev->tx_free);
+		acx_wake_queue(adev->ndev, NULL);
+	}
+
+end_unlock:
+	acx_unlock(adev, flags);
+/* end: */
+	FN_EXIT0;
+}
+
+
+/***************************************************************
+** acxusb_l_alloc_tx
+** Actually returns a usb_tx_t* ptr
+*/
+tx_t*
+acxusb_l_alloc_tx(acx_device_t *adev)
+{
+	usb_tx_t *tx;
+	int head;
+
+	FN_ENTER;
+
+	head = adev->tx_head;
+	do {
+		head = (head + 1) % ACX_TX_URB_CNT;
+		if (!adev->usb_tx[head].busy) {
+			log(L_USBRXTX, "allocated tx %d\n", head);
+			tx = &adev->usb_tx[head];
+			tx->busy = 1;
+			adev->tx_free--;
+			/* Keep a few free descs between head and tail of tx ring.
+			** It is not absolutely needed, just feels safer */
+			if (adev->tx_free < TX_STOP_QUEUE) {
+				log(L_BUF, "tx: stop queue "
+					"(%u free txbufs)\n", adev->tx_free);
+				acx_stop_queue(adev->ndev, NULL);
+			}
+			goto end;
+		}
+	} while (likely(head!=adev->tx_head));
+	tx = NULL;
+	printk_ratelimited("acx: tx buffers full\n");
+end:
+	adev->tx_head = head;
+	FN_EXIT0;
+	return (tx_t*)tx;
+}
+
+
+/***************************************************************
+** Used if alloc_tx()'ed buffer needs to be cancelled without doing tx
+*/
+void
+acxusb_l_dealloc_tx(tx_t *tx_opaque)
+{
+	usb_tx_t* tx = (usb_tx_t*)tx_opaque;
+	tx->busy = 0;
+}
+
+
+/***************************************************************
+*/
+void*
+acxusb_l_get_txbuf(acx_device_t *adev, tx_t* tx_opaque)
+{
+	usb_tx_t* tx = (usb_tx_t*)tx_opaque;
+	return &tx->bulkout.data;
+}
+
+
+/***************************************************************
+** acxusb_l_tx_data
+**
+** Can be called from IRQ (rx -> (AP bridging or mgmt response) -> tx).
+** Can be called from acx_i_start_xmit (data frames from net core).
+*/
+void
+acxusb_l_tx_data(acx_device_t *adev, tx_t* tx_opaque, int wlanpkt_len)
+{
+	struct usb_device *usbdev;
+	struct urb* txurb;
+	usb_tx_t* tx;
+	usb_txbuffer_t* txbuf;
+	client_t *clt;
+	wlan_hdr_t* whdr;
+	unsigned int outpipe;
+	int ucode, txnum;
+
+	FN_ENTER;
+
+	tx = ((usb_tx_t *)tx_opaque);
+	txurb = tx->urb;
+	txbuf = &tx->bulkout;
+	whdr = (wlan_hdr_t *)txbuf->data;
+	txnum = tx - adev->usb_tx;
+
+	log(L_DEBUG, "using buf#%d free=%d len=%d\n",
+			txnum, adev->tx_free, wlanpkt_len);
+
+	switch (adev->mode) {
+	case ACX_MODE_0_ADHOC:
+	case ACX_MODE_3_AP:
+		clt = acx_l_sta_list_get(adev, whdr->a1);
+		break;
+	case ACX_MODE_2_STA:
+		clt = adev->ap_client;
+		break;
+	default: /* ACX_MODE_OFF, ACX_MODE_MONITOR */
+		clt = NULL;
+		break;
+	}
+
+	if (unlikely(clt && !clt->rate_cur)) {
+		printk("acx: driver bug! bad ratemask\n");
+		goto end;
+	}
+
+	/* fill the USB transfer header */
+	txbuf->desc = cpu_to_le16(USB_TXBUF_TXDESC);
+	txbuf->mpdu_len = cpu_to_le16(wlanpkt_len);
+	txbuf->queue_index = 1;
+	if (clt) {
+		txbuf->rate = clt->rate_100;
+		txbuf->hostdata = (clt - adev->sta_list) | (clt->rate_cur << 16);
+	} else {
+		txbuf->rate = adev->rate_bcast100;
+		txbuf->hostdata = ((u16)-1) | (adev->rate_bcast << 16);
+	}
+	txbuf->ctrl1 = DESC_CTL_FIRSTFRAG;
+	if (1 == adev->preamble_cur)
+		SET_BIT(txbuf->ctrl1, DESC_CTL_SHORT_PREAMBLE);
+	txbuf->ctrl2 = 0;
+	txbuf->data_len = cpu_to_le16(wlanpkt_len);
+
+	if (unlikely(acx_debug & L_DATA)) {
+		printk("dump of bulk out urb:\n");
+		acx_dump_bytes(txbuf, wlanpkt_len + USB_TXBUF_HDRSIZE);
+	}
+
+	if (unlikely(txurb->status == -EINPROGRESS)) {
+		printk("acx: trying to submit tx urb while already in progress\n");
+	}
+
+	/* now schedule the USB transfer */
+	usbdev = adev->usbdev;
+	outpipe = usb_sndbulkpipe(usbdev, adev->bulkoutep);
+
+	usb_fill_bulk_urb(txurb, usbdev, outpipe,
+		txbuf, /* dataptr */
+		wlanpkt_len + USB_TXBUF_HDRSIZE, /* size */
+		acxusb_i_complete_tx, /* handler */
+		tx /* handler param */
+	);
+
+	txurb->transfer_flags = URB_ASYNC_UNLINK|URB_ZERO_PACKET;
+	ucode = usb_submit_urb(txurb, GFP_ATOMIC);
+	log(L_USBRXTX, "SUBMIT TX (%d): outpipe=0x%X buf=%p txsize=%d "
+		"rate=%u errcode=%d\n", txnum, outpipe, txbuf,
+		wlanpkt_len + USB_TXBUF_HDRSIZE, txbuf->rate, ucode);
+
+	if (unlikely(ucode)) {
+		printk(KERN_ERR "acx: submit_urb() error=%d txsize=%d\n",
+			ucode, wlanpkt_len + USB_TXBUF_HDRSIZE);
+
+		/* on error, just mark the frame as done and update
+		** the statistics
+		*/
+		adev->stats.tx_errors++;
+		tx->busy = 0;
+		adev->tx_free++;
+		/* needed? if (adev->tx_free > TX_START_QUEUE) acx_wake_queue(...) */
+	}
+end:
+	FN_EXIT0;
+}
+
+
+/***********************************************************************
+*/
+static void
+acxusb_i_set_rx_mode(struct net_device *ndev)
+{
+}
+
+
+/***********************************************************************
+*/
+#ifdef HAVE_TX_TIMEOUT
+static void
+acxusb_i_tx_timeout(struct net_device *ndev)
+{
+	acx_device_t *adev = ndev2adev(ndev);
+	unsigned long flags;
+	int i;
+
+	FN_ENTER;
+
+	acx_lock(adev, flags);
+	/* unlink the URBs */
+	for (i = 0; i < ACX_TX_URB_CNT; i++) {
+		acxusb_unlink_urb(adev->usb_tx[i].urb);
+		adev->usb_tx[i].busy = 0;
+	}
+	adev->tx_free = ACX_TX_URB_CNT;
+	/* TODO: stats update */
+	acx_unlock(adev, flags);
+
+	FN_EXIT0;
+}
+#endif
+
+
+/***********************************************************************
+** init_module()
+**
+** This function is invoked upon loading of the kernel module.
+** It registers itself at the kernel's USB subsystem.
+**
+** Returns: Errorcode on failure, 0 on success
+*/
+int __init
+acxusb_e_init_module(void)
+{
+	log(L_INIT, "USB module " ACX_RELEASE " initialized, "
+		"probing for devices...\n");
+	return usb_register(&acxusb_driver);
+}
+
+
+
+/***********************************************************************
+** cleanup_module()
+**
+** This function is invoked as last step of the module unloading. It simply
+** deregisters this module at the kernel's USB subsystem.
+*/
+void __exit
+acxusb_e_cleanup_module()
+{
+	usb_deregister(&acxusb_driver);
+}
+
+
+/***********************************************************************
+** DEBUG STUFF
+*/
+#if ACX_DEBUG
+
+#ifdef UNUSED
+static void
+dump_device(struct usb_device *usbdev)
+{
+	int i;
+	struct usb_config_descriptor *cd;
+
+	printk("acx device dump:\n");
+	printk("  devnum: %d\n", usbdev->devnum);
+	printk("  speed: %d\n", usbdev->speed);
+	printk("  tt: 0x%X\n", (unsigned int)(usbdev->tt));
+	printk("  ttport: %d\n", (unsigned int)(usbdev->ttport));
+	printk("  toggle[0]: 0x%X  toggle[1]: 0x%X\n", (unsigned int)(usbdev->toggle[0]), (unsigned int)(usbdev->toggle[1]));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
+	/* This saw a change after 2.6.10 */
+	printk("  ep_in wMaxPacketSize: ");
+	for (i = 0; i < 16; ++i)
+		printk("%d ", usbdev->ep_in[i]->desc.wMaxPacketSize);
+	printk("\n");
+	printk("  ep_out wMaxPacketSize: ");
+	for (i = 0; i < VEC_SIZE(usbdev->ep_out); ++i)
+		printk("%d ", usbdev->ep_out[i]->desc.wMaxPacketSize);
+	printk("\n");
+#else
+	printk("  epmaxpacketin: ");
+	for (i = 0; i < 16; i++)
+		printk("%d ", usbdev->epmaxpacketin[i]);
+	printk("\n");
+	printk("  epmaxpacketout: ");
+	for (i = 0; i < 16; i++)
+		printk("%d ", usbdev->epmaxpacketout[i]);
+	printk("\n");
+#endif
+	printk("  parent: 0x%X\n", (unsigned int)usbdev->parent);
+	printk("  bus: 0x%X\n", (unsigned int)usbdev->bus);
+#ifdef NO_DATATYPE
+	printk("  configs: ");
+	for (i = 0; i < usbdev->descriptor.bNumConfigurations; i++)
+		printk("0x%X ", usbdev->config[i]);
+	printk("\n");
+#endif
+	printk("  actconfig: %p\n", usbdev->actconfig);
+	dump_device_descriptor(&usbdev->descriptor);
+
+	cd = &usbdev->config->desc;
+	dump_config_descriptor(cd);
+}
+
+
+/***********************************************************************
+*/
+static void
+dump_config_descriptor(struct usb_config_descriptor *cd)
+{
+	printk("Configuration Descriptor:\n");
+	if (!cd) {
+		printk("NULL\n");
+		return;
+	}
+	printk("  bLength: %d (0x%X)\n", cd->bLength, cd->bLength);
+	printk("  bDescriptorType: %d (0x%X)\n", cd->bDescriptorType, cd->bDescriptorType);
+	printk("  bNumInterfaces: %d (0x%X)\n", cd->bNumInterfaces, cd->bNumInterfaces);
+	printk("  bConfigurationValue: %d (0x%X)\n", cd->bConfigurationValue, cd->bConfigurationValue);
+	printk("  iConfiguration: %d (0x%X)\n", cd->iConfiguration, cd->iConfiguration);
+	printk("  bmAttributes: %d (0x%X)\n", cd->bmAttributes, cd->bmAttributes);
+	/* printk("  MaxPower: %d (0x%X)\n", cd->bMaxPower, cd->bMaxPower); */
+}
+
+
+static void
+dump_device_descriptor(struct usb_device_descriptor *dd)
+{
+	printk("Device Descriptor:\n");
+	if (!dd) {
+		printk("NULL\n");
+		return;
+	}
+	printk("  bLength: %d (0x%X)\n", dd->bLength, dd->bLength);
+	printk("  bDescriptortype: %d (0x%X)\n", dd->bDescriptorType, dd->bDescriptorType);
+	printk("  bcdUSB: %d (0x%X)\n", dd->bcdUSB, dd->bcdUSB);
+	printk("  bDeviceClass: %d (0x%X)\n", dd->bDeviceClass, dd->bDeviceClass);
+	printk("  bDeviceSubClass: %d (0x%X)\n", dd->bDeviceSubClass, dd->bDeviceSubClass);
+	printk("  bDeviceProtocol: %d (0x%X)\n", dd->bDeviceProtocol, dd->bDeviceProtocol);
+	printk("  bMaxPacketSize0: %d (0x%X)\n", dd->bMaxPacketSize0, dd->bMaxPacketSize0);
+	printk("  idVendor: %d (0x%X)\n", dd->idVendor, dd->idVendor);
+	printk("  idProduct: %d (0x%X)\n", dd->idProduct, dd->idProduct);
+	printk("  bcdDevice: %d (0x%X)\n", dd->bcdDevice, dd->bcdDevice);
+	printk("  iManufacturer: %d (0x%X)\n", dd->iManufacturer, dd->iManufacturer);
+	printk("  iProduct: %d (0x%X)\n", dd->iProduct, dd->iProduct);
+	printk("  iSerialNumber: %d (0x%X)\n", dd->iSerialNumber, dd->iSerialNumber);
+	printk("  bNumConfigurations: %d (0x%X)\n", dd->bNumConfigurations, dd->bNumConfigurations);
+}
+#endif /* UNUSED */
+
+#endif /* ACX_DEBUG */
diff -urN oldtree/drivers/net/wireless/tiacx/wlan.c newtree/drivers/net/wireless/tiacx/wlan.c
--- oldtree/drivers/net/wireless/tiacx/wlan.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/net/wireless/tiacx/wlan.c	2006-02-21 15:58:22.575714528 +0000
@@ -0,0 +1,422 @@
+/***********************************************************************
+** Copyright (C) 2003  ACX100 Open Source Project
+**
+** The contents of this file are subject to the Mozilla Public
+** License Version 1.1 (the "License"); you may not use this file
+** except in compliance with the License. You may obtain a copy of
+** the License at http://www.mozilla.org/MPL/
+**
+** Software distributed under the License is distributed on an "AS
+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+** implied. See the License for the specific language governing
+** rights and limitations under the License.
+**
+** Alternatively, the contents of this file may be used under the
+** terms of the GNU Public License version 2 (the "GPL"), in which
+** case the provisions of the GPL are applicable instead of the
+** above.  If you wish to allow the use of your version of this file
+** only under the terms of the GPL and not to allow others to use
+** your version of this file under the MPL, indicate your decision
+** by deleting the provisions above and replace them with the notice
+** and other provisions required by the GPL.  If you do not delete
+** the provisions above, a recipient may use your version of this
+** file under either the MPL or the GPL.
+** ---------------------------------------------------------------------
+** Inquiries regarding the ACX100 Open Source Project can be
+** made directly to:
+**
+** acx100-users@lists.sf.net
+** http://acx100.sf.net
+** ---------------------------------------------------------------------
+*/
+
+/***********************************************************************
+** This code is based on elements which are
+** Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
+** info@linux-wlan.com
+** http://www.linux-wlan.com
+*/
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+
+#include "acx.h"
+
+
+/***********************************************************************
+*/
+#define LOG_BAD_EID(hdr,len,ie_ptr) acx_log_bad_eid(hdr, len, ((wlan_ie_t*)ie_ptr))
+
+#define IE_EID(ie_ptr) (((wlan_ie_t*)(ie_ptr))->eid)
+#define IE_LEN(ie_ptr) (((wlan_ie_t*)(ie_ptr))->len)
+#define OFFSET(hdr,off) (WLAN_HDR_A3_DATAP(hdr) + (off))
+
+
+/***********************************************************************
+** wlan_mgmt_decode_XXX
+**
+** Given a complete frame in f->hdr, sets the pointers in f to
+** the areas that correspond to the parts of the frame.
+**
+** Assumptions:
+**	1) f->len and f->hdr are already set
+**	2) f->len is the length of the MAC header + data, the FCS
+**	   is NOT included
+**	3) all members except len and hdr are zero
+** Arguments:
+**	f	frame structure
+**
+** Returns:
+**	nothing
+**
+** Side effects:
+**	frame structure members are pointing at their
+**	respective portions of the frame buffer.
+*/
+void
+wlan_mgmt_decode_beacon(wlan_fr_beacon_t * f)
+{
+	u8 *ie_ptr;
+	u8 *end = (u8*)f->hdr + f->len;
+
+	f->type = WLAN_FSTYPE_BEACON;
+
+	/*-- Fixed Fields ----*/
+	f->ts = (u64 *) OFFSET(f->hdr, WLAN_BEACON_OFF_TS);
+	f->bcn_int = (u16 *) OFFSET(f->hdr, WLAN_BEACON_OFF_BCN_INT);
+	f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_BEACON_OFF_CAPINFO);
+
+	/*-- Information elements */
+	ie_ptr = OFFSET(f->hdr, WLAN_BEACON_OFF_SSID);
+	while (ie_ptr < end) {
+		switch (IE_EID(ie_ptr)) {
+		case WLAN_EID_SSID:
+			f->ssid = (wlan_ie_ssid_t *) ie_ptr;
+			break;
+		case WLAN_EID_SUPP_RATES:
+			f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr;
+			break;
+		case WLAN_EID_EXT_RATES:
+			f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr;
+			break;
+		case WLAN_EID_FH_PARMS:
+			f->fh_parms = (wlan_ie_fh_parms_t *) ie_ptr;
+			break;
+		case WLAN_EID_DS_PARMS:
+			f->ds_parms = (wlan_ie_ds_parms_t *) ie_ptr;
+			break;
+		case WLAN_EID_CF_PARMS:
+			f->cf_parms = (wlan_ie_cf_parms_t *) ie_ptr;
+			break;
+		case WLAN_EID_IBSS_PARMS:
+			f->ibss_parms = (wlan_ie_ibss_parms_t *) ie_ptr;
+			break;
+		case WLAN_EID_TIM:
+			f->tim = (wlan_ie_tim_t *) ie_ptr;
+			break;
+		case WLAN_EID_ERP_INFO:
+			f->erp = (wlan_ie_erp_t *) ie_ptr;
+			break;
+
+		case WLAN_EID_COUNTRY:
+		/* was seen: 07 06 47 42 20 01 0D 14 */
+		case WLAN_EID_PWR_CONSTRAINT:
+		/* was seen by Ashwin Mansinghka <ashwin_man@yahoo.com> from
+		Atheros-based PCI card in AP mode using madwifi drivers: */
+		/* 20 01 00 */
+		case WLAN_EID_NONERP:
+		/* was seen from WRT54GS with OpenWrt: 2F 01 07 */
+		case WLAN_EID_UNKNOWN128:
+		/* was seen by Jacek Jablonski <conexion2000@gmail.com> from Orinoco AP */
+		/* 80 06 00 60 1D 2C 3B 00 */
+		case WLAN_EID_UNKNOWN133:
+		/* was seen by David Bronaugh <dbronaugh@linuxboxen.org> from ???? */
+		/* 85 1E 00 00 84 12 07 00 FF 00 11 00 61 70 63 31 */
+		/* 63 73 72 30 34 32 00 00 00 00 00 00 00 00 00 25 */
+		case WLAN_EID_UNKNOWN223:
+		/* was seen by Carlos Martin <carlosmn@gmail.com> from ???? */
+		/* DF 20 01 1E 04 00 00 00 06 63 09 02 FF 0F 30 30 */
+		/* 30 42 36 42 33 34 30 39 46 31 00 00 00 00 00 00 00 00 */
+		case WLAN_EID_GENERIC:
+		/* WPA: hostap code:
+			if (pos[1] >= 4 &&
+				pos[2] == 0x00 && pos[3] == 0x50 &&
+				pos[4] == 0xf2 && pos[5] == 1) {
+				wpa = pos;
+				wpa_len = pos[1] + 2;
+			}
+		TI x4 mode: seen DD 04 08 00 28 00
+		(08 00 28 is TI's OUI)
+		last byte is probably 0/1 - disabled/enabled
+		*/
+		case WLAN_EID_RSN:
+		/* hostap does something with it:
+			rsn = pos;
+			rsn_len = pos[1] + 2;
+		*/
+			break;
+
+		default:
+			LOG_BAD_EID(f->hdr, f->len, ie_ptr);
+			break;
+		}
+		ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr);
+	}
+}
+
+
+#ifdef UNUSED
+void wlan_mgmt_decode_ibssatim(wlan_fr_ibssatim_t * f)
+{
+	f->type = WLAN_FSTYPE_ATIM;
+	/*-- Fixed Fields ----*/
+	/*-- Information elements */
+}
+#endif /* UNUSED */
+
+void
+wlan_mgmt_decode_disassoc(wlan_fr_disassoc_t * f)
+{
+	f->type = WLAN_FSTYPE_DISASSOC;
+
+	/*-- Fixed Fields ----*/
+	f->reason = (u16 *) OFFSET(f->hdr, WLAN_DISASSOC_OFF_REASON);
+
+	/*-- Information elements */
+}
+
+
+void
+wlan_mgmt_decode_assocreq(wlan_fr_assocreq_t * f)
+{
+	u8 *ie_ptr;
+	u8 *end = (u8*)f->hdr + f->len;
+
+
+	f->type = WLAN_FSTYPE_ASSOCREQ;
+
+	/*-- Fixed Fields ----*/
+	f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_ASSOCREQ_OFF_CAP_INFO);
+	f->listen_int = (u16 *) OFFSET(f->hdr, WLAN_ASSOCREQ_OFF_LISTEN_INT);
+
+	/*-- Information elements */
+	ie_ptr = OFFSET(f->hdr, WLAN_ASSOCREQ_OFF_SSID);
+	while (ie_ptr < end) {
+		switch (IE_EID(ie_ptr)) {
+		case WLAN_EID_SSID:
+			f->ssid = (wlan_ie_ssid_t *) ie_ptr;
+			break;
+		case WLAN_EID_SUPP_RATES:
+			f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr;
+			break;
+		case WLAN_EID_EXT_RATES:
+			f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr;
+			break;
+		default:
+			LOG_BAD_EID(f->hdr, f->len, ie_ptr);
+			break;
+		}
+		ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr);
+	}
+}
+
+
+void
+wlan_mgmt_decode_assocresp(wlan_fr_assocresp_t * f)
+{
+	f->type = WLAN_FSTYPE_ASSOCRESP;
+
+	/*-- Fixed Fields ----*/
+	f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_ASSOCRESP_OFF_CAP_INFO);
+	f->status = (u16 *) OFFSET(f->hdr, WLAN_ASSOCRESP_OFF_STATUS);
+	f->aid = (u16 *) OFFSET(f->hdr, WLAN_ASSOCRESP_OFF_AID);
+
+	/*-- Information elements */
+	f->supp_rates = (wlan_ie_supp_rates_t *)
+			OFFSET(f->hdr, WLAN_ASSOCRESP_OFF_SUPP_RATES);
+}
+
+
+#ifdef UNUSED
+void
+wlan_mgmt_decode_reassocreq(wlan_fr_reassocreq_t * f)
+{
+	u8 *ie_ptr;
+	u8 *end = (u8*)f->hdr + f->len;
+
+	f->type = WLAN_FSTYPE_REASSOCREQ;
+
+	/*-- Fixed Fields ----*/
+	f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_REASSOCREQ_OFF_CAP_INFO);
+	f->listen_int = (u16 *) OFFSET(f->hdr, WLAN_REASSOCREQ_OFF_LISTEN_INT);
+	f->curr_ap = (u8 *) OFFSET(f->hdr, WLAN_REASSOCREQ_OFF_CURR_AP);
+
+	/*-- Information elements */
+	ie_ptr = OFFSET(f->hdr, WLAN_REASSOCREQ_OFF_SSID);
+	while (ie_ptr < end) {
+		switch (IE_EID(ie_ptr)) {
+		case WLAN_EID_SSID:
+			f->ssid = (wlan_ie_ssid_t *) ie_ptr;
+			break;
+		case WLAN_EID_SUPP_RATES:
+			f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr;
+			break;
+		case WLAN_EID_EXT_RATES:
+			f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr;
+			break;
+		default:
+			LOG_BAD_EID(f->hdr, f->len, ie_ptr);
+			break;
+		}
+		ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr);
+	}
+}
+
+
+void
+wlan_mgmt_decode_reassocresp(wlan_fr_reassocresp_t * f)
+{
+	f->type = WLAN_FSTYPE_REASSOCRESP;
+
+	/*-- Fixed Fields ----*/
+	f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_REASSOCRESP_OFF_CAP_INFO);
+	f->status = (u16 *) OFFSET(f->hdr, WLAN_REASSOCRESP_OFF_STATUS);
+	f->aid = (u16 *) OFFSET(f->hdr, WLAN_REASSOCRESP_OFF_AID);
+
+	/*-- Information elements */
+	f->supp_rates = (wlan_ie_supp_rates_t *)
+			OFFSET(f->hdr, WLAN_REASSOCRESP_OFF_SUPP_RATES);
+}
+
+
+void
+wlan_mgmt_decode_probereq(wlan_fr_probereq_t * f)
+{
+	u8 *ie_ptr;
+	u8 *end = (u8*)f->hdr + f->len;
+
+	f->type = WLAN_FSTYPE_PROBEREQ;
+
+	/*-- Fixed Fields ----*/
+
+	/*-- Information elements */
+	ie_ptr = OFFSET(f->hdr, WLAN_PROBEREQ_OFF_SSID);
+	while (ie_ptr < end) {
+		switch (IE_EID(ie_ptr)) {
+		case WLAN_EID_SSID:
+			f->ssid = (wlan_ie_ssid_t *) ie_ptr;
+			break;
+		case WLAN_EID_SUPP_RATES:
+			f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr;
+			break;
+		case WLAN_EID_EXT_RATES:
+			f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr;
+			break;
+		default:
+			LOG_BAD_EID(f->hdr, f->len, ie_ptr);
+			break;
+		}
+		ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr);
+	}
+}
+#endif /* UNUSED */
+
+
+/* TODO: decoding of beacon and proberesp can be merged (similar structure) */
+void
+wlan_mgmt_decode_proberesp(wlan_fr_proberesp_t * f)
+{
+	u8 *ie_ptr;
+	u8 *end = (u8*)f->hdr + f->len;
+
+	f->type = WLAN_FSTYPE_PROBERESP;
+
+	/*-- Fixed Fields ----*/
+	f->ts = (u64 *) OFFSET(f->hdr, WLAN_PROBERESP_OFF_TS);
+	f->bcn_int = (u16 *) OFFSET(f->hdr, WLAN_PROBERESP_OFF_BCN_INT);
+	f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_PROBERESP_OFF_CAP_INFO);
+
+	/*-- Information elements */
+	ie_ptr = OFFSET(f->hdr, WLAN_PROBERESP_OFF_SSID);
+	while (ie_ptr < end) {
+		switch (IE_EID(ie_ptr)) {
+		case WLAN_EID_SSID:
+			f->ssid = (wlan_ie_ssid_t *) ie_ptr;
+			break;
+		case WLAN_EID_SUPP_RATES:
+			f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr;
+			break;
+		case WLAN_EID_EXT_RATES:
+			f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr;
+			break;
+		case WLAN_EID_FH_PARMS:
+			f->fh_parms = (wlan_ie_fh_parms_t *) ie_ptr;
+			break;
+		case WLAN_EID_DS_PARMS:
+			f->ds_parms = (wlan_ie_ds_parms_t *) ie_ptr;
+			break;
+		case WLAN_EID_CF_PARMS:
+			f->cf_parms = (wlan_ie_cf_parms_t *) ie_ptr;
+			break;
+		case WLAN_EID_IBSS_PARMS:
+			f->ibss_parms = (wlan_ie_ibss_parms_t *) ie_ptr;
+			break;
+#ifdef DONT_DO_IT_ADD_REAL_HANDLING_INSTEAD
+		case WLAN_EID_COUNTRY:
+			break;
+		...
+#endif
+#ifdef SENT_HERE_BY_OPENWRT
+		/* should those be trapped or handled?? */
+		case WLAN_EID_ERP_INFO:
+			break;
+		case WLAN_EID_NONERP:
+			break;
+		case WLAN_EID_GENERIC:
+			break;
+#endif
+		default:
+			LOG_BAD_EID(f->hdr, f->len, ie_ptr);
+			break;
+		}
+
+		ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr);
+	}
+}
+
+
+void
+wlan_mgmt_decode_authen(wlan_fr_authen_t * f)
+{
+	u8 *ie_ptr;
+	u8 *end = (u8*)f->hdr + f->len;
+
+	f->type = WLAN_FSTYPE_AUTHEN;
+
+	/*-- Fixed Fields ----*/
+	f->auth_alg = (u16 *) OFFSET(f->hdr, WLAN_AUTHEN_OFF_AUTH_ALG);
+	f->auth_seq = (u16 *) OFFSET(f->hdr, WLAN_AUTHEN_OFF_AUTH_SEQ);
+	f->status = (u16 *) OFFSET(f->hdr, WLAN_AUTHEN_OFF_STATUS);
+
+	/*-- Information elements */
+	ie_ptr = OFFSET(f->hdr, WLAN_AUTHEN_OFF_CHALLENGE);
+	if ((ie_ptr < end) && (IE_EID(ie_ptr) == WLAN_EID_CHALLENGE)) {
+		f->challenge = (wlan_ie_challenge_t *) ie_ptr;
+	}
+}
+
+
+void
+wlan_mgmt_decode_deauthen(wlan_fr_deauthen_t * f)
+{
+	f->type = WLAN_FSTYPE_DEAUTHEN;
+
+	/*-- Fixed Fields ----*/
+	f->reason = (u16 *) OFFSET(f->hdr, WLAN_DEAUTHEN_OFF_REASON);
+
+	/*-- Information elements */
+}
diff -urN oldtree/drivers/net/wireless/tiacx/wlan_compat.h newtree/drivers/net/wireless/tiacx/wlan_compat.h
--- oldtree/drivers/net/wireless/tiacx/wlan_compat.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/net/wireless/tiacx/wlan_compat.h	2006-02-21 15:58:22.576714376 +0000
@@ -0,0 +1,262 @@
+/***********************************************************************
+** Copyright (C) 2003  ACX100 Open Source Project
+**
+** The contents of this file are subject to the Mozilla Public
+** License Version 1.1 (the "License"); you may not use this file
+** except in compliance with the License. You may obtain a copy of
+** the License at http://www.mozilla.org/MPL/
+**
+** Software distributed under the License is distributed on an "AS
+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+** implied. See the License for the specific language governing
+** rights and limitations under the License.
+**
+** Alternatively, the contents of this file may be used under the
+** terms of the GNU Public License version 2 (the "GPL"), in which
+** case the provisions of the GPL are applicable instead of the
+** above.  If you wish to allow the use of your version of this file
+** only under the terms of the GPL and not to allow others to use
+** your version of this file under the MPL, indicate your decision
+** by deleting the provisions above and replace them with the notice
+** and other provisions required by the GPL.  If you do not delete
+** the provisions above, a recipient may use your version of this
+** file under either the MPL or the GPL.
+** ---------------------------------------------------------------------
+** Inquiries regarding the ACX100 Open Source Project can be
+** made directly to:
+**
+** acx100-users@lists.sf.net
+** http://acx100.sf.net
+** ---------------------------------------------------------------------
+*/
+
+/***********************************************************************
+** This code is based on elements which are
+** Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
+** info@linux-wlan.com
+** http://www.linux-wlan.com
+*/
+
+/*=============================================================*/
+/*------ Establish Platform Identity --------------------------*/
+/*=============================================================*/
+/* Key macros: */
+/* WLAN_CPU_FAMILY */
+#define WLAN_Ix86			1
+#define WLAN_PPC			2
+#define WLAN_Ix96			3
+#define WLAN_ARM			4
+#define WLAN_ALPHA			5
+#define WLAN_MIPS			6
+#define WLAN_HPPA			7
+#define WLAN_SPARC			8
+#define WLAN_SH				9
+#define WLAN_x86_64			10
+/* WLAN_CPU_CORE */
+#define WLAN_I386CORE			1
+#define WLAN_PPCCORE			2
+#define WLAN_I296			3
+#define WLAN_ARMCORE			4
+#define WLAN_ALPHACORE			5
+#define WLAN_MIPSCORE			6
+#define WLAN_HPPACORE			7
+/* WLAN_CPU_PART */
+#define WLAN_I386PART			1
+#define WLAN_MPC860			2
+#define WLAN_MPC823			3
+#define WLAN_I296SA			4
+#define WLAN_PPCPART			5
+#define WLAN_ARMPART			6
+#define WLAN_ALPHAPART			7
+#define WLAN_MIPSPART			8
+#define WLAN_HPPAPART			9
+/* WLAN_SYSARCH */
+#define WLAN_PCAT			1
+#define WLAN_MBX			2
+#define WLAN_RPX			3
+#define WLAN_LWARCH			4
+#define WLAN_PMAC			5
+#define WLAN_SKIFF			6
+#define WLAN_BITSY			7
+#define WLAN_ALPHAARCH			7
+#define WLAN_MIPSARCH			9
+#define WLAN_HPPAARCH			10
+/* WLAN_HOSTIF (generally set on the command line, not detected) */
+#define WLAN_PCMCIA			1
+#define WLAN_ISA			2
+#define WLAN_PCI			3
+#define WLAN_USB			4
+#define WLAN_PLX			5
+
+/* Note: the PLX HOSTIF above refers to some vendors implementations for */
+/*       PCI.  It's a PLX chip that is a PCI to PCMCIA adapter, but it   */
+/*       isn't a real PCMCIA host interface adapter providing all the    */
+/*       card&socket services.                                           */
+
+#ifdef __powerpc__
+#ifndef __ppc__
+#define __ppc__
+#endif
+#endif
+
+#if (defined(CONFIG_PPC) || defined(CONFIG_8xx))
+#ifndef __ppc__
+#define __ppc__
+#endif
+#endif
+
+#if defined(__x86_64__)
+ #define WLAN_CPU_FAMILY	WLAN_x86_64
+ #define WLAN_SYSARCH		WLAN_PCAT
+#elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)
+ #define WLAN_CPU_FAMILY	WLAN_Ix86
+ #define WLAN_CPU_CORE		WLAN_I386CORE
+ #define WLAN_CPU_PART		WLAN_I386PART
+ #define WLAN_SYSARCH		WLAN_PCAT
+#elif defined(__ppc__)
+ #define WLAN_CPU_FAMILY	WLAN_PPC
+ #define WLAN_CPU_CORE		WLAN_PPCCORE
+ #if defined(CONFIG_MBX)
+  #define WLAN_CPU_PART		WLAN_MPC860
+  #define WLAN_SYSARCH		WLAN_MBX
+ #elif defined(CONFIG_RPXLITE)
+  #define WLAN_CPU_PART		WLAN_MPC823
+  #define WLAN_SYSARCH		WLAN_RPX
+ #elif defined(CONFIG_RPXCLASSIC)
+  #define WLAN_CPU_PART		WLAN_MPC860
+  #define WLAN_SYSARCH		WLAN_RPX
+ #else
+  #define WLAN_CPU_PART		WLAN_PPCPART
+  #define WLAN_SYSARCH		WLAN_PMAC
+ #endif
+#elif defined(__arm__)
+ #define WLAN_CPU_FAMILY	WLAN_ARM
+ #define WLAN_CPU_CORE		WLAN_ARMCORE
+ #define WLAN_CPU_PART		WLAN_ARM_PART
+ #define WLAN_SYSARCH		WLAN_SKIFF
+#elif defined(__alpha__)
+ #define WLAN_CPU_FAMILY	WLAN_ALPHA
+ #define WLAN_CPU_CORE		WLAN_ALPHACORE
+ #define WLAN_CPU_PART		WLAN_ALPHAPART
+ #define WLAN_SYSARCH		WLAN_ALPHAARCH
+#elif defined(__mips__)
+ #define WLAN_CPU_FAMILY	WLAN_MIPS
+ #define WLAN_CPU_CORE		WLAN_MIPSCORE
+ #define WLAN_CPU_PART		WLAN_MIPSPART
+ #define WLAN_SYSARCH		WLAN_MIPSARCH
+#elif defined(__hppa__)
+ #define WLAN_CPU_FAMILY	WLAN_HPPA
+ #define WLAN_CPU_CORE		WLAN_HPPACORE
+ #define WLAN_CPU_PART		WLAN_HPPAPART
+ #define WLAN_SYSARCH		WLAN_HPPAARCH
+#elif defined(__sparc__)
+ #define WLAN_CPU_FAMILY	WLAN_SPARC
+ #define WLAN_SYSARCH		WLAN_SPARC
+#elif defined(__sh__)
+ #define WLAN_CPU_FAMILY	WLAN_SH
+ #define WLAN_SYSARCH		WLAN_SHARCH
+ #ifndef __LITTLE_ENDIAN__
+  #define __LITTLE_ENDIAN__
+ #endif
+#else
+ #error "No CPU identified!"
+#endif
+
+/*
+   Some big endian machines implicitly do all I/O in little endian mode.
+
+   In particular:
+	  Linux/PPC on PowerMacs (PCI)
+	  Arm/Intel Xscale (PCI)
+
+   This may also affect PLX boards and other BE &| PPC platforms;
+   as new ones are discovered, add them below.
+*/
+
+#if ((WLAN_SYSARCH == WLAN_SKIFF) || (WLAN_SYSARCH == WLAN_PMAC))
+#define REVERSE_ENDIAN
+#endif
+
+/*=============================================================*/
+/*------ Hardware Portability Macros --------------------------*/
+/*=============================================================*/
+#if (WLAN_CPU_FAMILY == WLAN_PPC)
+#define wlan_inw(a)                     in_be16((unsigned short *)((a)+_IO_BASE))
+#define wlan_inw_le16_to_cpu(a)         inw((a))
+#define wlan_outw(v,a)                  out_be16((unsigned short *)((a)+_IO_BASE), (v))
+#define wlan_outw_cpu_to_le16(v,a)      outw((v),(a))
+#else
+#define wlan_inw(a)                     inw((a))
+#define wlan_inw_le16_to_cpu(a)         __cpu_to_le16(inw((a)))
+#define wlan_outw(v,a)                  outw((v),(a))
+#define wlan_outw_cpu_to_le16(v,a)      outw(__cpu_to_le16((v)),(a))
+#endif
+
+/*=============================================================*/
+/*------ Bit settings -----------------------------------------*/
+/*=============================================================*/
+#define ieee2host16(n)	__le16_to_cpu(n)
+#define ieee2host32(n)	__le32_to_cpu(n)
+#define host2ieee16(n)	__cpu_to_le16(n)
+#define host2ieee32(n)	__cpu_to_le32(n)
+
+/* for constants */
+#ifdef __LITTLE_ENDIAN
+ #define IEEE16(a,n)     a = n, a##i = n,
+#else
+ #ifdef __BIG_ENDIAN
+  /* shifts would produce gcc warnings. Oh well... */
+  #define IEEE16(a,n)     a = n, a##i = ((n&0xff)*256 + ((n&0xff00)/256)),
+ #else
+  #error give me endianness or give me death
+ #endif
+#endif
+
+/*=============================================================*/
+/*------ Compiler Portability Macros --------------------------*/
+/*=============================================================*/
+#define __WLAN_ATTRIB_PACK__		__attribute__ ((packed))
+#define __WLAN_PRAGMA_PACK1__
+#define __WLAN_PRAGMA_PACKDFLT__
+
+/* Interrupt handler backwards compatibility stuff */
+#ifndef IRQ_NONE
+#define IRQ_NONE
+#define IRQ_HANDLED
+typedef void irqreturn_t;
+#endif
+
+#ifndef ARPHRD_IEEE80211_PRISM
+#define ARPHRD_IEEE80211_PRISM 802
+#endif
+
+#define ETH_P_80211_RAW		(ETH_P_ECONET + 1)
+
+/*============================================================================*
+ * Constants                                                                  *
+ *============================================================================*/
+#define WLAN_IEEE_OUI_LEN	3
+
+/*============================================================================*
+ * Types                                                                      *
+ *============================================================================*/
+
+/* local ether header type */
+typedef struct wlan_ethhdr {
+	u8	daddr[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	saddr[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u16	type __WLAN_ATTRIB_PACK__;
+} wlan_ethhdr_t;
+
+/* local llc header type */
+typedef struct wlan_llc {
+	u8	dsap __WLAN_ATTRIB_PACK__;
+	u8	ssap __WLAN_ATTRIB_PACK__;
+	u8	ctl __WLAN_ATTRIB_PACK__;
+} wlan_llc_t;
+
+/* local snap header type */
+typedef struct wlan_snap {
+	u8	oui[WLAN_IEEE_OUI_LEN] __WLAN_ATTRIB_PACK__;
+	u16	type __WLAN_ATTRIB_PACK__;
+} wlan_snap_t;
diff -urN oldtree/drivers/net/wireless/tiacx/wlan_hdr.h newtree/drivers/net/wireless/tiacx/wlan_hdr.h
--- oldtree/drivers/net/wireless/tiacx/wlan_hdr.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/net/wireless/tiacx/wlan_hdr.h	2006-02-21 15:58:22.576714376 +0000
@@ -0,0 +1,497 @@
+/***********************************************************************
+** Copyright (C) 2003  ACX100 Open Source Project
+**
+** The contents of this file are subject to the Mozilla Public
+** License Version 1.1 (the "License"); you may not use this file
+** except in compliance with the License. You may obtain a copy of
+** the License at http://www.mozilla.org/MPL/
+**
+** Software distributed under the License is distributed on an "AS
+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+** implied. See the License for the specific language governing
+** rights and limitations under the License.
+**
+** Alternatively, the contents of this file may be used under the
+** terms of the GNU Public License version 2 (the "GPL"), in which
+** case the provisions of the GPL are applicable instead of the
+** above.  If you wish to allow the use of your version of this file
+** only under the terms of the GPL and not to allow others to use
+** your version of this file under the MPL, indicate your decision
+** by deleting the provisions above and replace them with the notice
+** and other provisions required by the GPL.  If you do not delete
+** the provisions above, a recipient may use your version of this
+** file under either the MPL or the GPL.
+** ---------------------------------------------------------------------
+** Inquiries regarding the ACX100 Open Source Project can be
+** made directly to:
+**
+** acx100-users@lists.sf.net
+** http://acx100.sf.net
+** ---------------------------------------------------------------------
+*/
+
+/***********************************************************************
+** This code is based on elements which are
+** Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
+** info@linux-wlan.com
+** http://www.linux-wlan.com
+*/
+
+/* mini-doc
+
+Here are all 11b/11g/11a rates and modulations:
+
+     11b 11g 11a
+     --- --- ---
+ 1  |B  |B  |
+ 2  |Q  |Q  |
+ 5.5|Cp |C p|
+ 6  |   |Od |O
+ 9  |   |od |o
+11  |Cp |C p|
+12  |   |Od |O
+18  |   |od |o
+22  |   |  p|
+24  |   |Od |O
+33  |   |  p|
+36  |   |od |o
+48  |   |od |o
+54  |   |od |o
+
+Mandatory:
+ B - DBPSK (Differential Binary Phase Shift Keying)
+ Q - DQPSK (Differential Quaternary Phase Shift Keying)
+ C - CCK (Complementary Code Keying, a form of DSSS
+		(Direct Sequence Spread Spectrum) modulation)
+ O - OFDM (Orthogonal Frequency Division Multiplexing)
+Optional:
+ o - OFDM
+ d - CCK-OFDM (also known as DSSS-OFDM)
+ p - PBCC (Packet Binary Convolutional Coding)
+
+The term CCK-OFDM may be used interchangeably with DSSS-OFDM
+(the IEEE 802.11g-2003 standard uses the latter terminology).
+In the CCK-OFDM, the PLCP header of the frame uses the CCK form of DSSS,
+while the PLCP payload (the MAC frame) is modulated using OFDM.
+
+Basically, you must use CCK-OFDM if you have mixed 11b/11g environment,
+or else (pure OFDM) 11b equipment may not realize that AP
+is sending a packet and start sending its own one.
+Sadly, looks like acx111 does not support CCK-OFDM, only pure OFDM.
+
+Re PBCC: avoid using it. It makes sense only if you have
+TI "11b+" hardware. You _must_ use PBCC in order to reach 22Mbps on it.
+
+Preambles:
+
+Long preamble (at 1Mbit rate, takes 144 us):
+    16 bytes	ones
+     2 bytes	0xF3A0 (lsb sent first)
+PLCP header follows (at 1Mbit also):
+     1 byte	Signal: speed, in 0.1Mbit units, except for:
+		33Mbit: 33 (instead of 330 - doesn't fit in octet)
+		all CCK-OFDM rates: 30
+     1 byte	Service
+	0,1,4:	reserved
+	2:	1=locked clock
+	3:	1=PBCC
+	5:	Length Extension (PBCC 22,33Mbit (11g only))  <-
+	6:	Length Extension (PBCC 22,33Mbit (11g only))  <- BLACK MAGIC HERE
+	7:	Length Extension                              <-
+     2 bytes	Length (time needed to tx this frame)
+		a) 5.5 Mbit/s CCK
+		   Length = octets*8/5.5, rounded up to integer
+		b) 11 Mbit/s CCK
+		   Length = octets*8/11, rounded up to integer
+		   Service bit 7:
+			0 = rounding took less than 8/11
+			1 = rounding took more than or equal to 8/11
+		c) 5.5 Mbit/s PBCC
+		   Length = (octets+1)*8/5.5, rounded up to integer
+		d) 11 Mbit/s PBCC
+		   Length = (octets+1)*8/11, rounded up to integer
+		   Service bit 7:
+			0 = rounding took less than 8/11
+			1 = rounding took more than or equal to 8/11
+		e) 22 Mbit/s PBCC
+		   Length = (octets+1)*8/22, rounded up to integer
+		   Service bits 6,7:
+			00 = rounding took less than 8/22ths
+			01 = rounding took 8/22...15/22ths
+			10 = rounding took 16/22ths or more.
+		f) 33 Mbit/s PBCC
+		   Length = (octets+1)*8/33, rounded up to integer
+		   Service bits 5,6,7:
+			000 rounding took less than 8/33
+			001 rounding took 8/33...15/33
+			010 rounding took 16/33...23/33
+			011 rounding took 24/33...31/33
+			100 rounding took 32/33 or more
+     2 bytes	CRC
+
+PSDU follows (up to 2346 bytes at selected rate)
+
+While Signal value alone is not enough to determine rate and modulation,
+Signal+Service is always sufficient.
+
+Short preamble (at 1Mbit rate, takes 72 us):
+     7 bytes	zeroes
+     2 bytes	0x05CF (lsb sent first)
+PLCP header follows *at 2Mbit/s*. Format is the same as in long preamble.
+PSDU follows (up to 2346 bytes at selected rate)
+
+OFDM preamble is completely different, uses OFDM
+modulation from the start and thus easily identifiable.
+Not shown here.
+*/
+
+
+/***********************************************************************
+** Constants
+*/
+
+#define WLAN_HDR_A3_LEN			24
+#define WLAN_HDR_A4_LEN			30
+/* IV structure:
+** 3 bytes: Initialization Vector (24 bits)
+** 1 byte: 0..5: padding, must be 0; 6..7: key selector (0-3)
+*/
+#define WLAN_WEP_IV_LEN			4
+/* 802.11 says 2312 but looks like 2312 is a max size of _WEPed data_ */
+#define WLAN_DATA_MAXLEN		2304
+#define WLAN_WEP_ICV_LEN		4
+#define WLAN_FCS_LEN			4
+#define WLAN_A3FR_MAXLEN		(WLAN_HDR_A3_LEN + WLAN_DATA_MAXLEN)
+#define WLAN_A4FR_MAXLEN		(WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN)
+#define WLAN_A3FR_MAXLEN_FCS		(WLAN_HDR_A3_LEN + WLAN_DATA_MAXLEN + 4)
+#define WLAN_A4FR_MAXLEN_FCS		(WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + 4)
+#define WLAN_A3FR_MAXLEN_WEP		(WLAN_A3FR_MAXLEN + 8)
+#define WLAN_A4FR_MAXLEN_WEP		(WLAN_A4FR_MAXLEN + 8)
+#define WLAN_A3FR_MAXLEN_WEP_FCS	(WLAN_A3FR_MAXLEN_FCS + 8)
+#define WLAN_A4FR_MAXLEN_WEP_FCS	(WLAN_A4FR_MAXLEN_FCS + 8)
+
+#define WLAN_BSS_TS_LEN			8
+#define WLAN_SSID_MAXLEN		32
+#define WLAN_BEACON_FR_MAXLEN		(WLAN_HDR_A3_LEN + 334)
+#define WLAN_ATIM_FR_MAXLEN		(WLAN_HDR_A3_LEN + 0)
+#define WLAN_DISASSOC_FR_MAXLEN		(WLAN_HDR_A3_LEN + 2)
+#define WLAN_ASSOCREQ_FR_MAXLEN		(WLAN_HDR_A3_LEN + 48)
+#define WLAN_ASSOCRESP_FR_MAXLEN	(WLAN_HDR_A3_LEN + 16)
+#define WLAN_REASSOCREQ_FR_MAXLEN	(WLAN_HDR_A3_LEN + 54)
+#define WLAN_REASSOCRESP_FR_MAXLEN	(WLAN_HDR_A3_LEN + 16)
+#define WLAN_PROBEREQ_FR_MAXLEN		(WLAN_HDR_A3_LEN + 44)
+#define WLAN_PROBERESP_FR_MAXLEN	(WLAN_HDR_A3_LEN + 78)
+#define WLAN_AUTHEN_FR_MAXLEN		(WLAN_HDR_A3_LEN + 261)
+#define WLAN_DEAUTHEN_FR_MAXLEN		(WLAN_HDR_A3_LEN + 2)
+#define WLAN_CHALLENGE_IE_LEN		130
+#define WLAN_CHALLENGE_LEN		128
+#define WLAN_WEP_MAXKEYLEN		13
+#define WLAN_WEP_NKEYS			4
+
+/*--- Frame Control Field -------------------------------------*/
+/* Frame Types */
+#define WLAN_FTYPE_MGMT			0x00
+#define WLAN_FTYPE_CTL			0x01
+#define WLAN_FTYPE_DATA			0x02
+
+/* Frame subtypes */
+/* Management */
+#define WLAN_FSTYPE_ASSOCREQ		0x00
+#define WLAN_FSTYPE_ASSOCRESP		0x01
+#define WLAN_FSTYPE_REASSOCREQ		0x02
+#define WLAN_FSTYPE_REASSOCRESP		0x03
+#define WLAN_FSTYPE_PROBEREQ		0x04
+#define WLAN_FSTYPE_PROBERESP		0x05
+#define WLAN_FSTYPE_BEACON		0x08
+#define WLAN_FSTYPE_ATIM		0x09
+#define WLAN_FSTYPE_DISASSOC		0x0a
+#define WLAN_FSTYPE_AUTHEN		0x0b
+#define WLAN_FSTYPE_DEAUTHEN		0x0c
+
+/* Control */
+#define WLAN_FSTYPE_PSPOLL		0x0a
+#define WLAN_FSTYPE_RTS			0x0b
+#define WLAN_FSTYPE_CTS			0x0c
+#define WLAN_FSTYPE_ACK			0x0d
+#define WLAN_FSTYPE_CFEND		0x0e
+#define WLAN_FSTYPE_CFENDCFACK		0x0f
+
+/* Data */
+#define WLAN_FSTYPE_DATAONLY		0x00
+#define WLAN_FSTYPE_DATA_CFACK		0x01
+#define WLAN_FSTYPE_DATA_CFPOLL		0x02
+#define WLAN_FSTYPE_DATA_CFACK_CFPOLL	0x03
+#define WLAN_FSTYPE_NULL		0x04
+#define WLAN_FSTYPE_CFACK		0x05
+#define WLAN_FSTYPE_CFPOLL		0x06
+#define WLAN_FSTYPE_CFACK_CFPOLL	0x07
+
+/*--- FC Constants v. 2.0 ------------------------------------*/
+/* Each constant is defined twice: WF_CONST is in host        */
+/* byteorder, WF_CONSTi is in ieee byteorder.                 */
+/* Usage:                                                     */
+/* printf("the frame subtype is %X", WF_FC_FTYPEi & rx.fc);   */
+/* tx.fc = WF_FTYPE_CTLi | WF_FSTYPE_RTSi;                    */
+/*------------------------------------------------------------*/
+
+enum {
+/*--- Frame Control Field -------------------------------------*/
+/* Protocol version: always 0 for current 802.11 standards */
+IEEE16(WF_FC_PVER,			0x0003)
+IEEE16(WF_FC_FTYPE,			0x000c)
+IEEE16(WF_FC_FSTYPE,			0x00f0)
+IEEE16(WF_FC_TODS,			0x0100)
+IEEE16(WF_FC_FROMDS,			0x0200)
+IEEE16(WF_FC_FROMTODS,			0x0300)
+IEEE16(WF_FC_MOREFRAG,			0x0400)
+IEEE16(WF_FC_RETRY,			0x0800)
+/* Indicates PS mode in which STA will be after successful completion
+** of current frame exchange sequence. Always 0 for AP frames */
+IEEE16(WF_FC_PWRMGT,			0x1000)
+/* What MoreData=1 means:
+** From AP to STA in PS mode: don't sleep yet, I have more frames for you
+** From Contention-Free (CF) Pollable STA in response to a CF-Poll:
+**   STA has buffered frames for transmission in response to next CF-Poll
+** Bcast/mcast frames transmitted from AP:
+**   when additional bcast/mcast frames remain to be transmitted by AP
+**   during this beacon interval
+** In all other cases MoreData=0 */
+IEEE16(WF_FC_MOREDATA,			0x2000)
+IEEE16(WF_FC_ISWEP,			0x4000)
+IEEE16(WF_FC_ORDER,			0x8000)
+
+/* Frame Types */
+IEEE16(WF_FTYPE_MGMT,			0x00)
+IEEE16(WF_FTYPE_CTL,			0x04)
+IEEE16(WF_FTYPE_DATA,			0x08)
+
+/* Frame subtypes */
+/* Management */
+IEEE16(WF_FSTYPE_ASSOCREQ,		0x00)
+IEEE16(WF_FSTYPE_ASSOCRESP,		0x10)
+IEEE16(WF_FSTYPE_REASSOCREQ,		0x20)
+IEEE16(WF_FSTYPE_REASSOCRESP,		0x30)
+IEEE16(WF_FSTYPE_PROBEREQ,		0x40)
+IEEE16(WF_FSTYPE_PROBERESP,		0x50)
+IEEE16(WF_FSTYPE_BEACON,		0x80)
+IEEE16(WF_FSTYPE_ATIM,			0x90)
+IEEE16(WF_FSTYPE_DISASSOC,		0xa0)
+IEEE16(WF_FSTYPE_AUTHEN,		0xb0)
+IEEE16(WF_FSTYPE_DEAUTHEN,		0xc0)
+
+/* Control */
+IEEE16(WF_FSTYPE_PSPOLL,		0xa0)
+IEEE16(WF_FSTYPE_RTS,			0xb0)
+IEEE16(WF_FSTYPE_CTS,			0xc0)
+IEEE16(WF_FSTYPE_ACK,			0xd0)
+IEEE16(WF_FSTYPE_CFEND,			0xe0)
+IEEE16(WF_FSTYPE_CFENDCFACK,		0xf0)
+
+/* Data */
+IEEE16(WF_FSTYPE_DATAONLY,		0x00)
+IEEE16(WF_FSTYPE_DATA_CFACK,		0x10)
+IEEE16(WF_FSTYPE_DATA_CFPOLL,		0x20)
+IEEE16(WF_FSTYPE_DATA_CFACK_CFPOLL,	0x30)
+IEEE16(WF_FSTYPE_NULL,			0x40)
+IEEE16(WF_FSTYPE_CFACK,			0x50)
+IEEE16(WF_FSTYPE_CFPOLL,		0x60)
+IEEE16(WF_FSTYPE_CFACK_CFPOLL,		0x70)
+};
+
+
+/***********************************************************************
+** Macros
+*/
+
+/*--- Duration Macros ----------------------------------------*/
+/* Macros to get/set the bitfields of the Duration Field      */
+/*  - the duration value is only valid when bit15 is zero     */
+/*  - the firmware handles these values, so I'm not going     */
+/*    these macros right now.                                 */
+/*------------------------------------------------------------*/
+
+/*--- Sequence Control  Macros -------------------------------*/
+/* Macros to get/set the bitfields of the Sequence Control    */
+/* Field.                                                     */
+/*------------------------------------------------------------*/
+#define WLAN_GET_SEQ_FRGNUM(n) ((u16)(n) & 0x000f)
+#define WLAN_GET_SEQ_SEQNUM(n) (((u16)(n) & 0xfff0) >> 4)
+
+/*--- Data ptr macro -----------------------------------------*/
+/* Creates a u8* to the data portion of a frame               */
+/* Assumes you're passing in a ptr to the beginning of the hdr*/
+/*------------------------------------------------------------*/
+#define WLAN_HDR_A3_DATAP(p) (((u8*)(p)) + WLAN_HDR_A3_LEN)
+#define WLAN_HDR_A4_DATAP(p) (((u8*)(p)) + WLAN_HDR_A4_LEN)
+
+
+/***********************************************************************
+** Types
+*/
+
+/* 802.11 header type
+**
+** Note the following:
+** a1 *always* is receiver's mac or bcast/mcast
+** a2 *always* is transmitter's mac, if a2 exists
+** seq: [0:3] frag#, [4:15] seq# - used for dup detection
+** (dups from retries have same seq#) */
+typedef struct wlan_hdr {
+	u16	fc __WLAN_ATTRIB_PACK__;
+	u16	dur __WLAN_ATTRIB_PACK__;
+	u8	a1[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	a2[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	a3[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u16	seq __WLAN_ATTRIB_PACK__;
+	u8	a4[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+} wlan_hdr_t;
+
+/* Separate structs for use if frame type is known */
+typedef struct wlan_hdr_a3 {
+	u16	fc __WLAN_ATTRIB_PACK__;
+	u16	dur __WLAN_ATTRIB_PACK__;
+	u8	a1[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	a2[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	a3[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u16	seq __WLAN_ATTRIB_PACK__;
+} wlan_hdr_a3_t;
+
+typedef struct wlan_hdr_mgmt {
+	u16	fc __WLAN_ATTRIB_PACK__;
+	u16	dur __WLAN_ATTRIB_PACK__;
+	u8	da[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	sa[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u16	seq __WLAN_ATTRIB_PACK__;
+} wlan_hdr_mgmt_t;
+
+#ifdef NOT_NEEDED_YET
+typedef struct { /* ad-hoc peer->peer (to/from DS = 0/0) */
+	u16	fc __WLAN_ATTRIB_PACK__;
+	u16	dur __WLAN_ATTRIB_PACK__;
+	u8	da[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	sa[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u16	seq __WLAN_ATTRIB_PACK__;
+} ibss;
+typedef struct { /* ap->sta (to/from DS = 0/1) */
+	u16	fc __WLAN_ATTRIB_PACK__;
+	u16	dur __WLAN_ATTRIB_PACK__;
+	u8	da[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	sa[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u16	seq __WLAN_ATTRIB_PACK__;
+} fromap;
+typedef struct { /* sta->ap (to/from DS = 1/0) */
+	u16	fc __WLAN_ATTRIB_PACK__;
+	u16	dur __WLAN_ATTRIB_PACK__;
+	u8	bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	sa[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	da[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u16	seq __WLAN_ATTRIB_PACK__;
+} toap;
+typedef struct { /* wds->wds (to/from DS = 1/1), the only 4addr pkt */
+	u16	fc __WLAN_ATTRIB_PACK__;
+	u16	dur __WLAN_ATTRIB_PACK__;
+	u8	ra[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	ta[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	da[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u16	seq __WLAN_ATTRIB_PACK__;
+	u8	sa[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+} wds;
+typedef struct { /* all management packets */
+	u16	fc __WLAN_ATTRIB_PACK__;
+	u16	dur __WLAN_ATTRIB_PACK__;
+	u8	da[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	sa[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u16	seq __WLAN_ATTRIB_PACK__;
+} mgmt;
+typedef struct { /* has no body, just a FCS */
+	u16	fc __WLAN_ATTRIB_PACK__;
+	u16	dur __WLAN_ATTRIB_PACK__;
+	u8	ra[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	ta[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+} rts;
+typedef struct { /* has no body, just a FCS */
+	u16	fc __WLAN_ATTRIB_PACK__;
+	u16	dur __WLAN_ATTRIB_PACK__;
+	u8	ra[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+} cts;
+typedef struct { /* has no body, just a FCS */
+	u16	fc __WLAN_ATTRIB_PACK__;
+	u16	dur __WLAN_ATTRIB_PACK__;
+	u8	ra[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+} ack;
+typedef struct { /* has no body, just a FCS */
+	u16	fc __WLAN_ATTRIB_PACK__;
+	/* NB: this one holds Assoc ID in dur field: */
+	u16	aid __WLAN_ATTRIB_PACK__;
+	u8	bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	ta[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+} pspoll;
+typedef struct { /* has no body, just a FCS */
+	u16	fc __WLAN_ATTRIB_PACK__;
+	u16	dur __WLAN_ATTRIB_PACK__;
+	u8	ra[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+} cfend;
+typedef struct { /* has no body, just a FCS */
+	u16	fc __WLAN_ATTRIB_PACK__;
+	u16	dur __WLAN_ATTRIB_PACK__;
+	u8	ra[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	u8	bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+} cfendcfack;
+#endif
+
+/* Prism header emulation (monitor mode) */
+typedef struct wlanitem_u32 {
+	u32	did __WLAN_ATTRIB_PACK__;
+	u16	status __WLAN_ATTRIB_PACK__;
+	u16	len __WLAN_ATTRIB_PACK__;
+	u32	data __WLAN_ATTRIB_PACK__;
+} wlanitem_u32_t;
+#define WLANITEM_STATUS_data_ok			0
+#define WLANITEM_STATUS_no_value		1
+#define WLANITEM_STATUS_invalid_itemname	2
+#define WLANITEM_STATUS_invalid_itemdata	3
+#define WLANITEM_STATUS_missing_itemdata	4
+#define WLANITEM_STATUS_incomplete_itemdata	5
+#define WLANITEM_STATUS_invalid_msg_did		6
+#define WLANITEM_STATUS_invalid_mib_did		7
+#define WLANITEM_STATUS_missing_conv_func	8
+#define WLANITEM_STATUS_string_too_long		9
+#define WLANITEM_STATUS_data_out_of_range	10
+#define WLANITEM_STATUS_string_too_short	11
+#define WLANITEM_STATUS_missing_valid_func	12
+#define WLANITEM_STATUS_unknown			13
+#define WLANITEM_STATUS_invalid_did		14
+#define WLANITEM_STATUS_missing_print_func	15
+
+#define WLAN_DEVNAMELEN_MAX	16
+typedef struct wlansniffrm {
+	u32		msgcode __WLAN_ATTRIB_PACK__;
+	u32		msglen __WLAN_ATTRIB_PACK__;
+	u8		devname[WLAN_DEVNAMELEN_MAX] __WLAN_ATTRIB_PACK__;
+	wlanitem_u32_t	hosttime __WLAN_ATTRIB_PACK__;
+	wlanitem_u32_t	mactime __WLAN_ATTRIB_PACK__;
+	wlanitem_u32_t	channel __WLAN_ATTRIB_PACK__;
+	wlanitem_u32_t	rssi __WLAN_ATTRIB_PACK__;
+	wlanitem_u32_t	sq __WLAN_ATTRIB_PACK__;
+	wlanitem_u32_t	signal __WLAN_ATTRIB_PACK__;
+	wlanitem_u32_t	noise __WLAN_ATTRIB_PACK__;
+	wlanitem_u32_t	rate __WLAN_ATTRIB_PACK__;
+	wlanitem_u32_t	istx __WLAN_ATTRIB_PACK__;	/* tx? 0:no 1:yes */
+	wlanitem_u32_t	frmlen __WLAN_ATTRIB_PACK__;
+} wlansniffrm_t;
+#define WLANSNIFFFRM		0x0041
+#define WLANSNIFFFRM_hosttime	0x1041
+#define WLANSNIFFFRM_mactime	0x2041
+#define WLANSNIFFFRM_channel	0x3041
+#define WLANSNIFFFRM_rssi	0x4041
+#define WLANSNIFFFRM_sq		0x5041
+#define WLANSNIFFFRM_signal	0x6041
+#define WLANSNIFFFRM_noise	0x7041
+#define WLANSNIFFFRM_rate	0x8041
+#define WLANSNIFFFRM_istx	0x9041
+#define WLANSNIFFFRM_frmlen	0xA041
diff -urN oldtree/drivers/net/wireless/tiacx/wlan_mgmt.h newtree/drivers/net/wireless/tiacx/wlan_mgmt.h
--- oldtree/drivers/net/wireless/tiacx/wlan_mgmt.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/net/wireless/tiacx/wlan_mgmt.h	2006-02-21 15:58:22.577714224 +0000
@@ -0,0 +1,582 @@
+/***********************************************************************
+** Copyright (C) 2003  ACX100 Open Source Project
+**
+** The contents of this file are subject to the Mozilla Public
+** License Version 1.1 (the "License"); you may not use this file
+** except in compliance with the License. You may obtain a copy of
+** the License at http://www.mozilla.org/MPL/
+**
+** Software distributed under the License is distributed on an "AS
+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+** implied. See the License for the specific language governing
+** rights and limitations under the License.
+**
+** Alternatively, the contents of this file may be used under the
+** terms of the GNU Public License version 2 (the "GPL"), in which
+** case the provisions of the GPL are applicable instead of the
+** above.  If you wish to allow the use of your version of this file
+** only under the terms of the GPL and not to allow others to use
+** your version of this file under the MPL, indicate your decision
+** by deleting the provisions above and replace them with the notice
+** and other provisions required by the GPL.  If you do not delete
+** the provisions above, a recipient may use your version of this
+** file under either the MPL or the GPL.
+** ---------------------------------------------------------------------
+** Inquiries regarding the ACX100 Open Source Project can be
+** made directly to:
+**
+** acx100-users@lists.sf.net
+** http://acx100.sf.net
+** ---------------------------------------------------------------------
+*/
+
+/***********************************************************************
+** This code is based on elements which are
+** Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
+** info@linux-wlan.com
+** http://www.linux-wlan.com
+*/
+
+/***********************************************************************
+** Constants
+*/
+
+/*-- Information Element IDs --------------------*/
+#define WLAN_EID_SSID		0
+#define WLAN_EID_SUPP_RATES	1
+#define WLAN_EID_FH_PARMS	2
+#define WLAN_EID_DS_PARMS	3
+#define WLAN_EID_CF_PARMS	4
+#define WLAN_EID_TIM		5
+#define WLAN_EID_IBSS_PARMS	6
+#define WLAN_EID_COUNTRY	7 /* 802.11d */
+#define WLAN_EID_FH_HOP_PARMS	8 /* 802.11d */
+#define WLAN_EID_FH_TABLE	9 /* 802.11d */
+#define WLAN_EID_REQUEST	10 /* 802.11d */
+/*-- values 11-15 reserved --*/
+#define WLAN_EID_CHALLENGE	16
+/*-- values 17-31 reserved for challenge text extension --*/
+#define WLAN_EID_PWR_CONSTRAINT	32	/* 11h PowerConstraint */
+#define WLAN_EID_ERP_INFO	42	/* was seen from WRT54GS with OpenWrt */
+#define WLAN_EID_NONERP		47	/* was seen from WRT54GS with OpenWrt */
+#define WLAN_EID_RSN		48
+#define WLAN_EID_EXT_RATES	50
+#define WLAN_EID_UNKNOWN128	128
+#define WLAN_EID_UNKNOWN133	133
+#define WLAN_EID_GENERIC	221	/* was seen from WRT54GS with OpenWrt */
+#define WLAN_EID_UNKNOWN223	223
+
+#if 0
+#define WLAN_EID_PWR_CAP		33	/* 11h PowerCapability */
+#define WLAN_EID_TPC_REQUEST		34	/* 11h TPC Request */
+#define WLAN_EID_TPC_REPORT		35	/* 11h TPC Report */
+#define WLAN_EID_SUPP_CHANNELS		36	/* 11h Supported Channels */
+#define WLAN_EID_CHANNEL_SWITCH		37	/* 11h ChannelSwitch */
+#define WLAN_EID_MEASURE_REQUEST	38	/* 11h MeasurementRequest */
+#define WLAN_EID_MEASURE_REPORT		39	/* 11h MeasurementReport */
+#define WLAN_EID_QUIET_ID		40	/* 11h Quiet */
+#define WLAN_EID_IBSS_DFS_ID		41	/* 11h IBSS_DFS */
+#endif
+
+/*-- Reason Codes -------------------------------*/
+#define WLAN_MGMT_REASON_RSVD			0
+#define WLAN_MGMT_REASON_UNSPEC			1
+#define WLAN_MGMT_REASON_PRIOR_AUTH_INVALID	2
+#define WLAN_MGMT_REASON_DEAUTH_LEAVING		3
+#define WLAN_MGMT_REASON_DISASSOC_INACTIVE	4
+#define WLAN_MGMT_REASON_DISASSOC_AP_BUSY	5
+#define WLAN_MGMT_REASON_CLASS2_NONAUTH		6
+#define WLAN_MGMT_REASON_CLASS3_NONASSOC	7
+#define WLAN_MGMT_REASON_DISASSOC_STA_HASLEFT	8
+#define WLAN_MGMT_REASON_CANT_ASSOC_NONAUTH	9
+
+/*-- Status Codes -------------------------------*/
+#define WLAN_MGMT_STATUS_SUCCESS		0
+#define WLAN_MGMT_STATUS_UNSPEC_FAILURE		1
+#define WLAN_MGMT_STATUS_CAPS_UNSUPPORTED	10
+#define WLAN_MGMT_STATUS_REASSOC_NO_ASSOC	11
+#define WLAN_MGMT_STATUS_ASSOC_DENIED_UNSPEC	12
+#define WLAN_MGMT_STATUS_UNSUPPORTED_AUTHALG	13
+#define WLAN_MGMT_STATUS_RX_AUTH_NOSEQ		14
+#define WLAN_MGMT_STATUS_CHALLENGE_FAIL		15
+#define WLAN_MGMT_STATUS_AUTH_TIMEOUT		16
+#define WLAN_MGMT_STATUS_ASSOC_DENIED_BUSY	17
+#define WLAN_MGMT_STATUS_ASSOC_DENIED_RATES	18
+/* p80211b additions */
+#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOSHORT	19
+#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOPBCC	20
+#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOAGILITY	21
+
+/*-- Auth Algorithm Field ---------------------------*/
+#define WLAN_AUTH_ALG_OPENSYSTEM		0
+#define WLAN_AUTH_ALG_SHAREDKEY			1
+
+/*-- Management Frame Field Offsets -------------*/
+/* Note: Not all fields are listed because of variable lengths */
+/* Note: These offsets are from the start of the frame data */
+
+#define WLAN_BEACON_OFF_TS			0
+#define WLAN_BEACON_OFF_BCN_INT			8
+#define WLAN_BEACON_OFF_CAPINFO			10
+#define WLAN_BEACON_OFF_SSID			12
+
+#define WLAN_DISASSOC_OFF_REASON		0
+
+#define WLAN_ASSOCREQ_OFF_CAP_INFO		0
+#define WLAN_ASSOCREQ_OFF_LISTEN_INT		2
+#define WLAN_ASSOCREQ_OFF_SSID			4
+
+#define WLAN_ASSOCRESP_OFF_CAP_INFO		0
+#define WLAN_ASSOCRESP_OFF_STATUS		2
+#define WLAN_ASSOCRESP_OFF_AID			4
+#define WLAN_ASSOCRESP_OFF_SUPP_RATES		6
+
+#define WLAN_REASSOCREQ_OFF_CAP_INFO		0
+#define WLAN_REASSOCREQ_OFF_LISTEN_INT		2
+#define WLAN_REASSOCREQ_OFF_CURR_AP		4
+#define WLAN_REASSOCREQ_OFF_SSID		10
+
+#define WLAN_REASSOCRESP_OFF_CAP_INFO		0
+#define WLAN_REASSOCRESP_OFF_STATUS		2
+#define WLAN_REASSOCRESP_OFF_AID		4
+#define WLAN_REASSOCRESP_OFF_SUPP_RATES		6
+
+#define WLAN_PROBEREQ_OFF_SSID			0
+
+#define WLAN_PROBERESP_OFF_TS			0
+#define WLAN_PROBERESP_OFF_BCN_INT		8
+#define WLAN_PROBERESP_OFF_CAP_INFO		10
+#define WLAN_PROBERESP_OFF_SSID			12
+
+#define WLAN_AUTHEN_OFF_AUTH_ALG		0
+#define WLAN_AUTHEN_OFF_AUTH_SEQ		2
+#define WLAN_AUTHEN_OFF_STATUS			4
+#define WLAN_AUTHEN_OFF_CHALLENGE		6
+
+#define WLAN_DEAUTHEN_OFF_REASON		0
+
+enum {
+IEEE16(WF_MGMT_CAP_ESS,		0x0001)
+IEEE16(WF_MGMT_CAP_IBSS,	0x0002)
+/* In (re)assoc request frames by STA:
+** Pollable=0, PollReq=0: STA is not CF-Pollable
+** 0 1: STA is CF-Pollable, not requesting to be placed on the CF-Polling list
+** 1 0: STA is CF-Pollable, requesting to be placed on the CF-Polling list
+** 1 1: STA is CF-Pollable, requesting never to be polled
+** In beacon, proberesp, (re)assoc resp frames by AP:
+** 0 0: No point coordinator at AP
+** 0 1: Point coordinator at AP for delivery only (no polling)
+** 1 0: Point coordinator at AP for delivery and polling
+** 1 1: Reserved  */
+IEEE16(WF_MGMT_CAP_CFPOLLABLE,	0x0004)
+IEEE16(WF_MGMT_CAP_CFPOLLREQ,	0x0008)
+/* 1=non-WEP data frames are disallowed */
+IEEE16(WF_MGMT_CAP_PRIVACY,	0x0010)
+/* In beacon,  proberesp, (re)assocresp by AP/AdHoc:
+** 1=use of shortpre is allowed ("I can receive shortpre") */
+IEEE16(WF_MGMT_CAP_SHORT,	0x0020)
+IEEE16(WF_MGMT_CAP_PBCC,	0x0040)
+IEEE16(WF_MGMT_CAP_AGILITY,	0x0080)
+/* In (re)assoc request frames by STA:
+** 1=short slot time implemented and enabled
+**   NB: AP shall use long slot time beginning at the next Beacon after assoc
+**   of STA with this bit set to 0
+** In beacon, proberesp, (re)assoc resp frames by AP:
+** currently used slot time value: 0/1 - long/short */
+IEEE16(WF_MGMT_CAP_SHORTSLOT,	0x0400)
+/* In (re)assoc request frames by STA: 1=CCK-OFDM is implemented and enabled
+** In beacon, proberesp, (re)assoc resp frames by AP/AdHoc:
+** 1=CCK-OFDM is allowed */
+IEEE16(WF_MGMT_CAP_CCKOFDM,	0x2000)
+};
+
+
+/***********************************************************************
+** Types
+*/
+
+/* Information Element types */
+
+/* prototype structure, all IEs start with these members */
+typedef struct wlan_ie {
+	u8 eid __WLAN_ATTRIB_PACK__;
+	u8 len __WLAN_ATTRIB_PACK__;
+} wlan_ie_t;
+
+/*-- Service Set Identity (SSID)  -----------------*/
+typedef struct wlan_ie_ssid {
+	u8 eid __WLAN_ATTRIB_PACK__;
+	u8 len __WLAN_ATTRIB_PACK__;
+	u8 ssid[1] __WLAN_ATTRIB_PACK__;	/* may be zero */
+} wlan_ie_ssid_t;
+
+/*-- Supported Rates  -----------------------------*/
+typedef struct wlan_ie_supp_rates {
+	u8 eid __WLAN_ATTRIB_PACK__;
+	u8 len __WLAN_ATTRIB_PACK__;
+	u8 rates[1] __WLAN_ATTRIB_PACK__;	/* had better be at LEAST one! */
+} wlan_ie_supp_rates_t;
+
+/*-- FH Parameter Set  ----------------------------*/
+typedef struct wlan_ie_fh_parms {
+	u8 eid __WLAN_ATTRIB_PACK__;
+	u8 len __WLAN_ATTRIB_PACK__;
+	u16 dwell __WLAN_ATTRIB_PACK__;
+	u8 hopset __WLAN_ATTRIB_PACK__;
+	u8 hoppattern __WLAN_ATTRIB_PACK__;
+	u8 hopindex __WLAN_ATTRIB_PACK__;
+} wlan_ie_fh_parms_t;
+
+/*-- DS Parameter Set  ----------------------------*/
+typedef struct wlan_ie_ds_parms {
+	u8 eid __WLAN_ATTRIB_PACK__;
+	u8 len __WLAN_ATTRIB_PACK__;
+	u8 curr_ch __WLAN_ATTRIB_PACK__;
+} wlan_ie_ds_parms_t;
+
+/*-- CF Parameter Set  ----------------------------*/
+typedef struct wlan_ie_cf_parms {
+	u8 eid __WLAN_ATTRIB_PACK__;
+	u8 len __WLAN_ATTRIB_PACK__;
+	u8 cfp_cnt __WLAN_ATTRIB_PACK__;
+	u8 cfp_period __WLAN_ATTRIB_PACK__;
+	u16 cfp_maxdur __WLAN_ATTRIB_PACK__;
+	u16 cfp_durremaining __WLAN_ATTRIB_PACK__;
+} wlan_ie_cf_parms_t;
+
+/*-- TIM ------------------------------------------*/
+typedef struct wlan_ie_tim {
+	u8 eid __WLAN_ATTRIB_PACK__;
+	u8 len __WLAN_ATTRIB_PACK__;
+	u8 dtim_cnt __WLAN_ATTRIB_PACK__;
+	u8 dtim_period __WLAN_ATTRIB_PACK__;
+	u8 bitmap_ctl __WLAN_ATTRIB_PACK__;
+	u8 virt_bm[1] __WLAN_ATTRIB_PACK__;
+} wlan_ie_tim_t;
+
+/*-- IBSS Parameter Set ---------------------------*/
+typedef struct wlan_ie_ibss_parms {
+	u8 eid __WLAN_ATTRIB_PACK__;
+	u8 len __WLAN_ATTRIB_PACK__;
+	u16 atim_win __WLAN_ATTRIB_PACK__;
+} wlan_ie_ibss_parms_t;
+
+/*-- Challenge Text  ------------------------------*/
+typedef struct wlan_ie_challenge {
+	u8 eid __WLAN_ATTRIB_PACK__;
+	u8 len __WLAN_ATTRIB_PACK__;
+	u8 challenge[1] __WLAN_ATTRIB_PACK__;
+} wlan_ie_challenge_t;
+
+/*-- ERP (42) -------------------------------------*/
+typedef struct wlan_ie_erp {
+	u8 eid __WLAN_ATTRIB_PACK__;
+	u8 len __WLAN_ATTRIB_PACK__;
+	/* bit 0:Non ERP present
+	**     1:Use Protection
+	**     2:Barker Preamble mode
+	**     3-7:reserved */
+	u8 erp __WLAN_ATTRIB_PACK__;
+} wlan_ie_erp_t;
+
+/* Types for parsing mgmt frames */
+
+/* prototype structure, all mgmt frame types will start with these members */
+typedef struct wlan_fr_mgmt {
+	u16 type;
+	u16 len;		/* DOES NOT include FCS */
+	wlan_hdr_t *hdr;
+	/* used for target specific data, skb in Linux */
+	/*-- fixed fields -----------*/
+	/*-- info elements ----------*/
+} wlan_fr_mgmt_t;
+
+/*-- Beacon ---------------------------------------*/
+typedef struct wlan_fr_beacon {
+	u16 type;
+	u16 len;
+	wlan_hdr_t *hdr;
+	/*-- fixed fields -----------*/
+	u64 *ts;
+	u16 *bcn_int;
+	u16 *cap_info;
+	/*-- info elements ----------*/
+	wlan_ie_ssid_t *ssid;
+	wlan_ie_supp_rates_t *supp_rates;
+	wlan_ie_supp_rates_t *ext_rates;
+	wlan_ie_fh_parms_t *fh_parms;
+	wlan_ie_ds_parms_t *ds_parms;
+	wlan_ie_cf_parms_t *cf_parms;
+	wlan_ie_ibss_parms_t *ibss_parms;
+	wlan_ie_tim_t *tim;	/* in beacon only, not proberesp */
+	wlan_ie_erp_t *erp;	/* in beacon only, not proberesp */
+} wlan_fr_beacon_t;
+#define wlan_fr_proberesp wlan_fr_beacon
+#define wlan_fr_proberesp_t wlan_fr_beacon_t
+
+/*-- IBSS ATIM ------------------------------------*/
+typedef struct wlan_fr_ibssatim {
+	u16 type;
+	u16 len;
+	wlan_hdr_t *hdr;
+	/*-- fixed fields -----------*/
+	/*-- info elements ----------*/
+	/* this frame type has a null body */
+} wlan_fr_ibssatim_t;
+
+/*-- Disassociation -------------------------------*/
+typedef struct wlan_fr_disassoc {
+	u16 type;
+	u16 len;
+	wlan_hdr_t *hdr;
+	/*-- fixed fields -----------*/
+	u16 *reason;
+	/*-- info elements ----------*/
+} wlan_fr_disassoc_t;
+
+/*-- Association Request --------------------------*/
+typedef struct wlan_fr_assocreq {
+	u16 type;
+	u16 len;
+	wlan_hdr_t *hdr;
+	/*-- fixed fields -----------*/
+	u16 *cap_info;
+	u16 *listen_int;
+	/*-- info elements ----------*/
+	wlan_ie_ssid_t *ssid;
+	wlan_ie_supp_rates_t *supp_rates;
+	wlan_ie_supp_rates_t *ext_rates;
+} wlan_fr_assocreq_t;
+
+/*-- Association Response -------------------------*/
+typedef struct wlan_fr_assocresp {
+	u16 type;
+	u16 len;
+	wlan_hdr_t *hdr;
+	/*-- fixed fields -----------*/
+	u16 *cap_info;
+	u16 *status;
+	u16 *aid;
+	/*-- info elements ----------*/
+	wlan_ie_supp_rates_t *supp_rates;
+	wlan_ie_supp_rates_t *ext_rates;
+} wlan_fr_assocresp_t;
+
+/*-- Reassociation Request ------------------------*/
+typedef struct wlan_fr_reassocreq {
+	u16 type;
+	u16 len;
+	wlan_hdr_t *hdr;
+	/*-- fixed fields -----------*/
+	u16 *cap_info;
+	u16 *listen_int;
+	u8 *curr_ap;
+	/*-- info elements ----------*/
+	wlan_ie_ssid_t *ssid;
+	wlan_ie_supp_rates_t *supp_rates;
+	wlan_ie_supp_rates_t *ext_rates;
+} wlan_fr_reassocreq_t;
+
+/*-- Reassociation Response -----------------------*/
+typedef struct wlan_fr_reassocresp {
+	u16 type;
+	u16 len;
+	wlan_hdr_t *hdr;
+	/*-- fixed fields -----------*/
+	u16 *cap_info;
+	u16 *status;
+	u16 *aid;
+	/*-- info elements ----------*/
+	wlan_ie_supp_rates_t *supp_rates;
+	wlan_ie_supp_rates_t *ext_rates;
+} wlan_fr_reassocresp_t;
+
+/*-- Probe Request --------------------------------*/
+typedef struct wlan_fr_probereq {
+	u16 type;
+	u16 len;
+	wlan_hdr_t *hdr;
+	/*-- fixed fields -----------*/
+	/*-- info elements ----------*/
+	wlan_ie_ssid_t *ssid;
+	wlan_ie_supp_rates_t *supp_rates;
+	wlan_ie_supp_rates_t *ext_rates;
+} wlan_fr_probereq_t;
+
+/*-- Authentication -------------------------------*/
+typedef struct wlan_fr_authen {
+	u16 type;
+	u16 len;
+	wlan_hdr_t *hdr;
+	/*-- fixed fields -----------*/
+	u16 *auth_alg;
+	u16 *auth_seq;
+	u16 *status;
+	/*-- info elements ----------*/
+	wlan_ie_challenge_t *challenge;
+} wlan_fr_authen_t;
+
+/*-- Deauthenication -----------------------------*/
+typedef struct wlan_fr_deauthen {
+	u16 type;
+	u16 len;
+	wlan_hdr_t *hdr;
+	/*-- fixed fields -----------*/
+	u16 *reason;
+	/*-- info elements ----------*/
+} wlan_fr_deauthen_t;
+
+/* Types for building mgmt frames */
+
+/* Warning. Several types used in below structs are
+** in fact variable length. Use structs with such fields with caution */
+typedef struct auth_frame_body {
+	u16	auth_alg __WLAN_ATTRIB_PACK__;
+	u16	auth_seq __WLAN_ATTRIB_PACK__;
+	u16	status __WLAN_ATTRIB_PACK__;
+	wlan_ie_challenge_t challenge __WLAN_ATTRIB_PACK__;
+} auth_frame_body_t;
+
+typedef struct assocresp_frame_body {
+	u16	cap_info __WLAN_ATTRIB_PACK__;
+	u16	status __WLAN_ATTRIB_PACK__;
+	u16	aid __WLAN_ATTRIB_PACK__;
+	wlan_ie_supp_rates_t rates __WLAN_ATTRIB_PACK__;
+} assocresp_frame_body_t;
+
+typedef struct reassocreq_frame_body {
+	u16	cap_info __WLAN_ATTRIB_PACK__;
+	u16	listen_int __WLAN_ATTRIB_PACK__;
+	u8	current_ap[ETH_ALEN] __WLAN_ATTRIB_PACK__;
+	wlan_ie_ssid_t ssid __WLAN_ATTRIB_PACK__;
+/* access to this one is disabled since ssid_t is variable length: */
+     /* wlan_ie_supp_rates_t rates __WLAN_ATTRIB_PACK__; */
+} reassocreq_frame_body_t;
+
+typedef struct reassocresp_frame_body {
+	u16	cap_info __WLAN_ATTRIB_PACK__;
+	u16	status __WLAN_ATTRIB_PACK__;
+	u16	aid __WLAN_ATTRIB_PACK__;
+	wlan_ie_supp_rates_t rates __WLAN_ATTRIB_PACK__;
+} reassocresp_frame_body_t;
+
+typedef struct deauthen_frame_body {
+	u16	reason __WLAN_ATTRIB_PACK__;
+} deauthen_frame_body_t;
+
+typedef struct disassoc_frame_body {
+	u16	reason __WLAN_ATTRIB_PACK__;
+} disassoc_frame_body_t;
+
+typedef struct probereq_frame_body {
+	wlan_ie_ssid_t ssid __WLAN_ATTRIB_PACK__;
+	wlan_ie_supp_rates_t rates __WLAN_ATTRIB_PACK__;
+} probereq_frame_body_t;
+
+typedef struct proberesp_frame_body {
+	u8	timestamp[8] __WLAN_ATTRIB_PACK__;
+	u16	beacon_int __WLAN_ATTRIB_PACK__;
+	u16	cap_info __WLAN_ATTRIB_PACK__;
+	wlan_ie_ssid_t ssid __WLAN_ATTRIB_PACK__;
+/* access to these is disabled since ssid_t is variable length: */
+     /* wlan_ie_supp_rates_t rates __WLAN_ATTRIB_PACK__; */
+     /* fhps_t	fhps __WLAN_ATTRIB_PACK__; */
+     /* dsps_t	dsps __WLAN_ATTRIB_PACK__; */
+     /* cfps_t	cfps __WLAN_ATTRIB_PACK__; */
+} proberesp_frame_body_t;
+
+
+/***********************************************************************
+** Functions
+*/
+
+/* Helpers for parsing mgmt frames */
+void wlan_mgmt_decode_ibssatim(wlan_fr_ibssatim_t *f);
+void wlan_mgmt_decode_assocreq(wlan_fr_assocreq_t *f);
+void wlan_mgmt_decode_assocresp(wlan_fr_assocresp_t *f);
+void wlan_mgmt_decode_authen(wlan_fr_authen_t *f);
+void wlan_mgmt_decode_beacon(wlan_fr_beacon_t *f);
+void wlan_mgmt_decode_deauthen(wlan_fr_deauthen_t *f);
+void wlan_mgmt_decode_disassoc(wlan_fr_disassoc_t *f);
+void wlan_mgmt_decode_probereq(wlan_fr_probereq_t *f);
+void wlan_mgmt_decode_proberesp(wlan_fr_proberesp_t *f);
+void wlan_mgmt_decode_reassocreq(wlan_fr_reassocreq_t *f);
+void wlan_mgmt_decode_reassocresp(wlan_fr_reassocresp_t *f);
+
+/* Helpers for building mgmt frames */
+static inline u8*
+wlan_fill_ie_ssid(u8 *p, int len, const char *ssid)
+{
+	struct wlan_ie_ssid *ie = (void*)p;
+	ie->eid = WLAN_EID_SSID;
+	ie->len = len;
+	memcpy(ie->ssid, ssid, len);
+	return p + len + 2;
+}
+/* This controls whether we create 802.11g 'ext supported rates' IEs
+** or just create overlong 'supported rates' IEs instead
+** (non-11g compliant) */
+#define WE_OBEY_802_11G 1
+static inline u8*
+wlan_fill_ie_rates(u8 *p, int len, const u8 *rates)
+{
+	struct wlan_ie_supp_rates *ie = (void*)p;
+#if WE_OBEY_802_11G
+	if (len > 8 ) len = 8;
+#endif
+	/* supported rates (1 to 8 octets) */
+	ie->eid = WLAN_EID_SUPP_RATES;
+	ie->len = len;
+	memcpy(ie->rates, rates, len);
+	return p + len + 2;
+}
+/* This one wouldn't create an IE at all if not needed */
+static inline u8*
+wlan_fill_ie_rates_ext(u8 *p, int len, const u8 *rates)
+{
+	struct wlan_ie_supp_rates *ie = (void*)p;
+#if !WE_OBEY_802_11G
+	return p;
+#endif
+	len -= 8;
+	if (len < 0) return p;
+	/* ext supported rates */
+	ie->eid = WLAN_EID_EXT_RATES;
+	ie->len = len;
+	memcpy(ie->rates, rates+8, len);
+	return p + len + 2;
+}
+static inline u8*
+wlan_fill_ie_ds_parms(u8 *p, int channel)
+{
+	struct wlan_ie_ds_parms *ie = (void*)p;
+	ie->eid = WLAN_EID_DS_PARMS;
+	ie->len = 1;
+	ie->curr_ch = channel;
+	return p + sizeof(*ie);
+}
+static inline u8*
+wlan_fill_ie_ibss_parms(u8 *p, int atim_win)
+{
+	struct wlan_ie_ibss_parms *ie = (void*)p;
+	ie->eid = WLAN_EID_IBSS_PARMS;
+	ie->len = 2;
+	ie->atim_win = atim_win;
+	return p + sizeof(*ie);
+}
+static inline u8*
+wlan_fill_ie_tim(u8 *p,	int rem, int period, int bcast,
+		int ofs, int len, const u8 *vbm)
+{
+	struct wlan_ie_tim *ie = (void*)p;
+	ie->eid = WLAN_EID_TIM;
+	ie->len = len + 3;
+	ie->dtim_cnt = rem;
+	ie->dtim_period = period;
+	ie->bitmap_ctl = ofs | (bcast!=0);
+	if (vbm)
+		memcpy(ie->virt_bm, vbm, len); /* min 1 byte */
+	else
+		ie->virt_bm[0] = 0;
+	return p + len + 3 + 2;
+}
diff -urN oldtree/drivers/net/wireless/wavelan.p.h newtree/drivers/net/wireless/wavelan.p.h
--- oldtree/drivers/net/wireless/wavelan.p.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/wireless/wavelan.p.h	2006-02-21 15:58:15.625771080 +0000
@@ -98,11 +98,7 @@
  * characteristics of the hardware.  Applications such as mobile IP may
  * take advantage of it.
  *
- * You will need to enable the CONFIG_NET_RADIO define in the kernel
- * configuration to enable the wireless extensions (this is the one
- * giving access to the radio network device choice).
- *
- * It might also be a good idea as well to fetch the wireless tools to
+ * It might be a good idea as well to fetch the wireless tools to
  * configure the device and play a bit.
  */
 
diff -urN oldtree/drivers/net/wireless/wavelan_cs.p.h newtree/drivers/net/wireless/wavelan_cs.p.h
--- oldtree/drivers/net/wireless/wavelan_cs.p.h	2006-02-19 11:41:03.451818344 +0000
+++ newtree/drivers/net/wireless/wavelan_cs.p.h	2006-02-21 15:58:15.678763024 +0000
@@ -99,11 +99,7 @@
  * caracteristics of the hardware in a standard way and support for
  * applications for taking advantage of it (like Mobile IP).
  *
- * You will need to enable the CONFIG_NET_RADIO define in the kernel
- * configuration to enable the wireless extensions (this is the one
- * giving access to the radio network device choice).
- *
- * It might also be a good idea as well to fetch the wireless tools to
+ * It might be a good idea as well to fetch the wireless tools to
  * configure the device and play a bit.
  */
 
@@ -440,11 +436,8 @@
 #include <linux/ioport.h>
 #include <linux/fcntl.h>
 #include <linux/ethtool.h>
-
-#ifdef CONFIG_NET_RADIO
 #include <linux/wireless.h>		/* Wireless extensions */
 #include <net/iw_handler.h>		/* New driver API */
-#endif
 
 /* Pcmcia headers that we need */
 #include <pcmcia/cs_types.h>
diff -urN oldtree/drivers/net/zorro8390.c newtree/drivers/net/zorro8390.c
--- oldtree/drivers/net/zorro8390.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/net/zorro8390.c	2006-02-21 15:58:36.365618144 +0000
@@ -27,14 +27,23 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/zorro.h>
+#include <linux/jiffies.h>
 
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
 
-#include "8390.h"
+#define EI_SHIFT(x)	(ei_local->reg_offset[x])
+#define ei_inb(port)   in_8(port)
+#define ei_outb(val,port)  out_8(port,val)
+#define ei_inb_p(port)   in_8(port)
+#define ei_outb_p(val,port)  out_8(port,val)
 
+static const char version[] =
+    "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+
+#include "lib8390.c"
 
 #define DRV_NAME	"zorro8390"
 
@@ -113,7 +122,7 @@
 	    break;
     board = z->resource.start;
     ioaddr = board+cards[i].offset;
-    dev = alloc_ei_netdev();
+    dev = ____alloc_ei_netdev(0);
     if (!dev)
 	return -ENOMEM;
     SET_MODULE_OWNER(dev);
@@ -151,7 +160,7 @@
 	z_writeb(z_readb(ioaddr + NE_RESET), ioaddr + NE_RESET);
 
 	while ((z_readb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0)
-	    if (jiffies - reset_start_time > 2*HZ/100) {
+	    if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
 		printk(KERN_WARNING " not found (no reset ack).\n");
 		return -ENODEV;
 	    }
@@ -200,7 +209,7 @@
     dev->irq = IRQ_AMIGA_PORTS;
 
     /* Install the Interrupt handler */
-    i = request_irq(IRQ_AMIGA_PORTS, ei_interrupt, SA_SHIRQ, DRV_NAME, dev);
+    i = request_irq(IRQ_AMIGA_PORTS, __ei_interrupt, SA_SHIRQ, DRV_NAME, dev);
     if (i) return i;
 
     for(i = 0; i < ETHER_ADDR_LEN; i++) {
@@ -225,10 +234,10 @@
     dev->open = &zorro8390_open;
     dev->stop = &zorro8390_close;
 #ifdef CONFIG_NET_POLL_CONTROLLER
-    dev->poll_controller = ei_poll;
+    dev->poll_controller = __ei_poll;
 #endif
 
-    NS8390_init(dev, 0);
+    __NS8390_init(dev, 0);
     err = register_netdev(dev);
     if (err) {
 	free_irq(IRQ_AMIGA_PORTS, dev);
@@ -245,7 +254,7 @@
 
 static int zorro8390_open(struct net_device *dev)
 {
-    ei_open(dev);
+    __ei_open(dev);
     return 0;
 }
 
@@ -253,7 +262,7 @@
 {
     if (ei_debug > 1)
 	printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
-    ei_close(dev);
+    __ei_close(dev);
     return 0;
 }
 
@@ -273,7 +282,7 @@
 
     /* This check _should_not_ be necessary, omit eventually. */
     while ((z_readb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0)
-	if (jiffies - reset_start_time > 2*HZ/100) {
+	if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
 	    printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n",
 		   dev->name);
 	    break;
@@ -400,11 +409,11 @@
     dma_start = jiffies;
 
     while ((z_readb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0)
-	if (jiffies - dma_start > 2*HZ/100) {		/* 20ms */
+	if (time_after(jiffies, dma_start + 2*HZ/100)) {	/* 20ms */
 		printk(KERN_ERR "%s: timeout waiting for Tx RDC.\n",
 		       dev->name);
 		zorro8390_reset_8390(dev);
-		NS8390_init(dev,1);
+		__NS8390_init(dev,1);
 		break;
 	}
 
diff -urN oldtree/drivers/parport/share.c newtree/drivers/parport/share.c
--- oldtree/drivers/parport/share.c	2006-02-19 11:41:03.530806336 +0000
+++ newtree/drivers/parport/share.c	2006-02-21 15:58:24.205466768 +0000
@@ -32,6 +32,7 @@
 #include <linux/kmod.h>
 
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <asm/irq.h>
 
 #undef PARPORT_PARANOID
@@ -50,7 +51,7 @@
 
 static LIST_HEAD(drivers);
 
-static DECLARE_MUTEX(registration_lock);
+static DEFINE_MUTEX(registration_lock);
 
 /* What you can do to a port that's gone away.. */
 static void dead_write_lines (struct parport *p, unsigned char b){}
@@ -158,11 +159,11 @@
 	if (list_empty(&portlist))
 		get_lowlevel_driver ();
 
-	down(&registration_lock);
+	mutex_lock(&registration_lock);
 	list_for_each_entry(port, &portlist, list)
 		drv->attach(port);
 	list_add(&drv->list, &drivers);
-	up(&registration_lock);
+	mutex_unlock(&registration_lock);
 
 	return 0;
 }
@@ -188,11 +189,11 @@
 {
 	struct parport *port;
 
-	down(&registration_lock);
+	mutex_lock(&registration_lock);
 	list_del_init(&drv->list);
 	list_for_each_entry(port, &portlist, list)
 		drv->detach(port);
-	up(&registration_lock);
+	mutex_unlock(&registration_lock);
 }
 
 static void free_port (struct parport *port)
@@ -366,7 +367,7 @@
 #endif
 
 	parport_proc_register(port);
-	down(&registration_lock);
+	mutex_lock(&registration_lock);
 	spin_lock_irq(&parportlist_lock);
 	list_add_tail(&port->list, &portlist);
 	for (i = 1; i < 3; i++) {
@@ -383,7 +384,7 @@
 		if (slave)
 			attach_driver_chain(slave);
 	}
-	up(&registration_lock);
+	mutex_unlock(&registration_lock);
 }
 
 /**
@@ -409,7 +410,7 @@
 {
 	int i;
 
-	down(&registration_lock);
+	mutex_lock(&registration_lock);
 
 	/* Spread the word. */
 	detach_driver_chain (port);
@@ -436,7 +437,7 @@
 	}
 	spin_unlock(&parportlist_lock);
 
-	up(&registration_lock);
+	mutex_unlock(&registration_lock);
 
 	parport_proc_unregister(port);
 
diff -urN oldtree/drivers/pci/hotplug/acpiphp.h newtree/drivers/pci/hotplug/acpiphp.h
--- oldtree/drivers/pci/hotplug/acpiphp.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/pci/hotplug/acpiphp.h	2006-02-21 15:58:18.213377704 +0000
@@ -37,6 +37,7 @@
 
 #include <linux/acpi.h>
 #include <linux/kobject.h>	/* for KOBJ_NAME_LEN */
+#include <linux/mutex.h>
 #include "pci_hotplug.h"
 
 #define dbg(format, arg...)					\
@@ -118,7 +119,7 @@
 	struct acpiphp_bridge *bridge;	/* parent */
 	struct list_head funcs;		/* one slot may have different
 					   objects (i.e. for each function) */
-	struct semaphore crit_sect;
+	struct mutex crit_sect;
 
 	u32		id;		/* slot id (serial #) for hotplug core */
 	u8		device;		/* pci device# */
diff -urN oldtree/drivers/pci/hotplug/acpiphp_glue.c newtree/drivers/pci/hotplug/acpiphp_glue.c
--- oldtree/drivers/pci/hotplug/acpiphp_glue.c	2006-02-19 11:41:03.532806032 +0000
+++ newtree/drivers/pci/hotplug/acpiphp_glue.c	2006-02-21 15:58:18.214377552 +0000
@@ -46,7 +46,7 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/smp_lock.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include "../pci.h"
 #include "pci_hotplug.h"
@@ -188,7 +188,7 @@
 		slot->device = device;
 		slot->sun = sun;
 		INIT_LIST_HEAD(&slot->funcs);
-		init_MUTEX(&slot->crit_sect);
+		mutex_init(&slot->crit_sect);
 
 		slot->next = bridge->slots;
 		bridge->slots = slot;
@@ -751,6 +751,101 @@
 }
 
 
+
+/**
+ * acpiphp_max_busnr - return the highest reserved bus number under
+ * the given bus.
+ * @bus: bus to start search with
+ *
+ */
+static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
+{
+	struct list_head *tmp;
+	unsigned char max, n;
+
+	/*
+	 * pci_bus_max_busnr will return the highest
+	 * reserved busnr for all these children.
+	 * that is equivalent to the bus->subordinate
+	 * value.  We don't want to use the parent's
+	 * bus->subordinate value because it could have
+	 * padding in it.
+	 */
+	max = bus->secondary;
+
+	list_for_each(tmp, &bus->children) {
+		n = pci_bus_max_busnr(pci_bus_b(tmp));
+		if (n > max)
+			max = n;
+	}
+	return max;
+}
+
+
+
+/**
+ *  get_func - get a pointer to acpiphp_func given a slot, device
+ *  @slot: slot to search
+ *  @dev:  pci_dev struct to match.
+ *
+ *  This function will increase the reference count of pci_dev,
+ *  so callers should call pci_dev_put when complete.
+ *
+ */
+static struct acpiphp_func *
+get_func(struct acpiphp_slot *slot, struct pci_dev *dev)
+{
+	struct acpiphp_func *func = NULL;
+	struct pci_bus *bus = slot->bridge->pci_bus;
+	struct pci_dev *pdev;
+
+	list_for_each_entry(func, &slot->funcs, sibling) {
+		pdev = pci_get_slot(bus, PCI_DEVFN(slot->device,
+					func->function));
+		if (pdev) {
+			if (pdev == dev)
+				break;
+			pci_dev_put(pdev);
+		}
+	}
+	return func;
+}
+
+
+/**
+ * acpiphp_bus_add - add a new bus to acpi subsystem
+ * @func: acpiphp_func of the bridge
+ *
+ */
+static int acpiphp_bus_add(struct acpiphp_func *func)
+{
+	acpi_handle phandle;
+	struct acpi_device *device, *pdevice;
+	int ret_val;
+
+	acpi_get_parent(func->handle, &phandle);
+	if (acpi_bus_get_device(phandle, &pdevice)) {
+		dbg("no parent device, assuming NULL\n");
+		pdevice = NULL;
+	}
+	ret_val = acpi_bus_add(&device, pdevice, func->handle,
+			ACPI_BUS_TYPE_DEVICE);
+	if (ret_val)
+		dbg("cannot add bridge to acpi list\n");
+
+	/*
+	 * try to start anyway.  We could have failed to add
+	 * simply because this bus had previously been added
+	 * on another add.  Don't bother with the return value
+	 * we just keep going.
+	 */
+	ret_val = acpi_bus_start(device);
+
+	return ret_val;
+}
+
+
+
 /**
  * enable_device - enable, configure a slot
  * @slot: slot to be enabled
@@ -788,7 +883,7 @@
 		goto err_exit;
 	}
 
-	max = bus->secondary;
+	max = acpiphp_max_busnr(bus);
 	for (pass = 0; pass < 2; pass++) {
 		list_for_each_entry(dev, &bus->devices, bus_list) {
 			if (PCI_SLOT(dev->devfn) != slot->device)
@@ -796,8 +891,15 @@
 			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
 			    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
 				max = pci_scan_bridge(bus, dev, max, pass);
-				if (pass && dev->subordinate)
+				if (pass && dev->subordinate) {
 					pci_bus_size_bridges(dev->subordinate);
+					func = get_func(slot, dev);
+					if (func) {
+						acpiphp_bus_add(func);
+						/* side effect of get_func */
+						pci_dev_put(dev);
+					}
+				}
 			}
 		}
 	}
@@ -1401,7 +1503,7 @@
 {
 	int retval;
 
-	down(&slot->crit_sect);
+	mutex_lock(&slot->crit_sect);
 
 	/* wake up all functions */
 	retval = power_on_slot(slot);
@@ -1413,7 +1515,7 @@
 		retval = enable_device(slot);
 
  err_exit:
-	up(&slot->crit_sect);
+	mutex_unlock(&slot->crit_sect);
 	return retval;
 }
 
@@ -1424,7 +1526,7 @@
 {
 	int retval = 0;
 
-	down(&slot->crit_sect);
+	mutex_lock(&slot->crit_sect);
 
 	/* unconfigure all functions */
 	retval = disable_device(slot);
@@ -1437,7 +1539,7 @@
 		goto err_exit;
 
  err_exit:
-	up(&slot->crit_sect);
+	mutex_unlock(&slot->crit_sect);
 	return retval;
 }
 
diff -urN oldtree/drivers/pci/hotplug/cpqphp.h newtree/drivers/pci/hotplug/cpqphp.h
--- oldtree/drivers/pci/hotplug/cpqphp.h	2006-02-19 11:41:03.533805880 +0000
+++ newtree/drivers/pci/hotplug/cpqphp.h	2006-02-21 15:58:18.225375880 +0000
@@ -32,6 +32,7 @@
 #include <linux/interrupt.h>
 #include <asm/io.h>		/* for read? and write? functions */
 #include <linux/delay.h>	/* for delays */
+#include <linux/mutex.h>
 
 #define MY_NAME	"cpqphp"
 
@@ -286,7 +287,7 @@
 struct controller {
 	struct controller *next;
 	u32 ctrl_int_comp;
-	struct semaphore crit_sect;	/* critical section semaphore */
+	struct mutex crit_sect;		/* critical section mutex */
 	void __iomem *hpc_reg;		/* cookie for our pci controller location */
 	struct pci_resource *mem_head;
 	struct pci_resource *p_mem_head;
diff -urN oldtree/drivers/pci/hotplug/cpqphp_core.c newtree/drivers/pci/hotplug/cpqphp_core.c
--- oldtree/drivers/pci/hotplug/cpqphp_core.c	2006-02-19 11:41:03.534805728 +0000
+++ newtree/drivers/pci/hotplug/cpqphp_core.c	2006-02-21 15:58:18.263370104 +0000
@@ -599,7 +599,7 @@
 	hp_slot = func->device - ctrl->slot_device_offset;
 
 	// Wait for exclusive access to hardware
-	down(&ctrl->crit_sect);
+	mutex_lock(&ctrl->crit_sect);
 
 	if (status == 1) {
 		amber_LED_on (ctrl, hp_slot);
@@ -607,7 +607,7 @@
 		amber_LED_off (ctrl, hp_slot);
 	} else {
 		// Done with exclusive hardware access
-		up(&ctrl->crit_sect);
+		mutex_unlock(&ctrl->crit_sect);
 		return(1);
 	}
 
@@ -617,7 +617,7 @@
 	wait_for_ctrl_irq (ctrl);
 
 	// Done with exclusive hardware access
-	up(&ctrl->crit_sect);
+	mutex_unlock(&ctrl->crit_sect);
 
 	return(0);
 }
@@ -1084,7 +1084,7 @@
 	dbg("bus device function rev: %d %d %d %d\n", ctrl->bus,
 		PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), ctrl->rev);
 
-	init_MUTEX(&ctrl->crit_sect);
+	mutex_init(&ctrl->crit_sect);
 	init_waitqueue_head(&ctrl->queue);
 
 	/* initialize our threads if they haven't already been started up */
@@ -1223,7 +1223,7 @@
 
 	// turn off empty slots here unless command line option "ON" set
 	// Wait for exclusive access to hardware
-	down(&ctrl->crit_sect);
+	mutex_lock(&ctrl->crit_sect);
 
 	num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F;
 
@@ -1270,12 +1270,12 @@
 	rc = init_SERR(ctrl);
 	if (rc) {
 		err("init_SERR failed\n");
-		up(&ctrl->crit_sect);
+		mutex_unlock(&ctrl->crit_sect);
 		goto err_free_irq;
 	}
 
 	// Done with exclusive hardware access
-	up(&ctrl->crit_sect);
+	mutex_unlock(&ctrl->crit_sect);
 
 	cpqhp_create_debugfs_files(ctrl);
 
diff -urN oldtree/drivers/pci/hotplug/cpqphp_ctrl.c newtree/drivers/pci/hotplug/cpqphp_ctrl.c
--- oldtree/drivers/pci/hotplug/cpqphp_ctrl.c	2006-02-19 11:41:03.537805272 +0000
+++ newtree/drivers/pci/hotplug/cpqphp_ctrl.c	2006-02-21 15:58:18.289366152 +0000
@@ -1299,7 +1299,7 @@
 		 **********************************/
 		rc = CARD_FUNCTIONING;
 	} else {
-		down(&ctrl->crit_sect);
+		mutex_lock(&ctrl->crit_sect);
 
 		/* turn on board without attaching to the bus */
 		enable_slot_power (ctrl, hp_slot);
@@ -1333,12 +1333,12 @@
 		/* Wait for SOBS to be unset */
 		wait_for_ctrl_irq (ctrl);
 
-		up(&ctrl->crit_sect);
+		mutex_unlock(&ctrl->crit_sect);
 
 		if (rc)
 			return rc;
 
-		down(&ctrl->crit_sect);
+		mutex_lock(&ctrl->crit_sect);
 
 		slot_enable (ctrl, hp_slot);
 		green_LED_blink (ctrl, hp_slot);
@@ -1350,7 +1350,7 @@
 		/* Wait for SOBS to be unset */
 		wait_for_ctrl_irq (ctrl);
 
-		up(&ctrl->crit_sect);
+		mutex_unlock(&ctrl->crit_sect);
 
 		/* Wait for ~1 second because of hot plug spec */
 		long_delay(1*HZ);
@@ -1375,7 +1375,7 @@
 				 * called for the "base" bus/dev/func of an
 				 * adapter. */
 
-				down(&ctrl->crit_sect);
+				mutex_lock(&ctrl->crit_sect);
 
 				amber_LED_on (ctrl, hp_slot);
 				green_LED_off (ctrl, hp_slot);
@@ -1386,7 +1386,7 @@
 				/* Wait for SOBS to be unset */
 				wait_for_ctrl_irq (ctrl);
 
-				up(&ctrl->crit_sect);
+				mutex_unlock(&ctrl->crit_sect);
 
 				if (rc)
 					return rc;
@@ -1410,7 +1410,7 @@
 				 * called for the "base" bus/dev/func of an
 				 * adapter. */
 
-				down(&ctrl->crit_sect);
+				mutex_lock(&ctrl->crit_sect);
 
 				amber_LED_on (ctrl, hp_slot);
 				green_LED_off (ctrl, hp_slot);
@@ -1421,13 +1421,13 @@
 				/* Wait for SOBS to be unset */
 				wait_for_ctrl_irq (ctrl);
 
-				up(&ctrl->crit_sect);
+				mutex_unlock(&ctrl->crit_sect);
 
 				return rc;
 			}
 			/* Done configuring so turn LED on full time */
 
-			down(&ctrl->crit_sect);
+			mutex_lock(&ctrl->crit_sect);
 
 			green_LED_on (ctrl, hp_slot);
 
@@ -1436,7 +1436,7 @@
 			/* Wait for SOBS to be unset */
 			wait_for_ctrl_irq (ctrl);
 
-			up(&ctrl->crit_sect);
+			mutex_unlock(&ctrl->crit_sect);
 			rc = 0;
 		} else {
 			/* Something is wrong
@@ -1445,7 +1445,7 @@
 			 * in this case it will always be called for the "base"
 			 * bus/dev/func of an adapter. */
 
-			down(&ctrl->crit_sect);
+			mutex_lock(&ctrl->crit_sect);
 
 			amber_LED_on (ctrl, hp_slot);
 			green_LED_off (ctrl, hp_slot);
@@ -1456,7 +1456,7 @@
 			/* Wait for SOBS to be unset */
 			wait_for_ctrl_irq (ctrl);
 
-			up(&ctrl->crit_sect);
+			mutex_unlock(&ctrl->crit_sect);
 		}
 
 	}
@@ -1488,7 +1488,7 @@
 	dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n",
 	    __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot);
 
-	down(&ctrl->crit_sect);
+	mutex_lock(&ctrl->crit_sect);
 
 	/* turn on board without attaching to the bus */
 	enable_slot_power(ctrl, hp_slot);
@@ -1522,7 +1522,7 @@
 	/* Wait for SOBS to be unset */
 	wait_for_ctrl_irq(ctrl);
 
-	up(&ctrl->crit_sect);
+	mutex_unlock(&ctrl->crit_sect);
 
 	if (rc)
 		return rc;
@@ -1532,7 +1532,7 @@
 	/* turn on board and blink green LED */
 
 	dbg("%s: before down\n", __FUNCTION__);
-	down(&ctrl->crit_sect);
+	mutex_lock(&ctrl->crit_sect);
 	dbg("%s: after down\n", __FUNCTION__);
 
 	dbg("%s: before slot_enable\n", __FUNCTION__);
@@ -1553,7 +1553,7 @@
 	dbg("%s: after wait_for_ctrl_irq\n", __FUNCTION__);
 
 	dbg("%s: before up\n", __FUNCTION__);
-	up(&ctrl->crit_sect);
+	mutex_unlock(&ctrl->crit_sect);
 	dbg("%s: after up\n", __FUNCTION__);
 
 	/* Wait for ~1 second because of hot plug spec */
@@ -1607,7 +1607,7 @@
 		cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
 
 		if (rc) {
-			down(&ctrl->crit_sect);
+			mutex_lock(&ctrl->crit_sect);
 
 			amber_LED_on (ctrl, hp_slot);
 			green_LED_off (ctrl, hp_slot);
@@ -1618,7 +1618,7 @@
 			/* Wait for SOBS to be unset */
 			wait_for_ctrl_irq (ctrl);
 
-			up(&ctrl->crit_sect);
+			mutex_unlock(&ctrl->crit_sect);
 			return rc;
 		} else {
 			cpqhp_save_slot_config(ctrl, func);
@@ -1640,7 +1640,7 @@
 			}
 		} while (new_slot);
 
-		down(&ctrl->crit_sect);
+		mutex_lock(&ctrl->crit_sect);
 
 		green_LED_on (ctrl, hp_slot);
 
@@ -1649,9 +1649,9 @@
 		/* Wait for SOBS to be unset */
 		wait_for_ctrl_irq (ctrl);
 
-		up(&ctrl->crit_sect);
+		mutex_unlock(&ctrl->crit_sect);
 	} else {
-		down(&ctrl->crit_sect);
+		mutex_lock(&ctrl->crit_sect);
 
 		amber_LED_on (ctrl, hp_slot);
 		green_LED_off (ctrl, hp_slot);
@@ -1662,7 +1662,7 @@
 		/* Wait for SOBS to be unset */
 		wait_for_ctrl_irq (ctrl);
 
-		up(&ctrl->crit_sect);
+		mutex_unlock(&ctrl->crit_sect);
 
 		return rc;
 	}
@@ -1721,7 +1721,7 @@
 		func->status = 0x01;
 	func->configured = 0;
 
-	down(&ctrl->crit_sect);
+	mutex_lock(&ctrl->crit_sect);
 
 	green_LED_off (ctrl, hp_slot);
 	slot_disable (ctrl, hp_slot);
@@ -1736,7 +1736,7 @@
 	/* Wait for SOBS to be unset */
 	wait_for_ctrl_irq (ctrl);
 
-	up(&ctrl->crit_sect);
+	mutex_unlock(&ctrl->crit_sect);
 
 	if (!replace_flag && ctrl->add_support) {
 		while (func) {
@@ -1899,7 +1899,7 @@
 					dbg("button cancel\n");
 					del_timer(&p_slot->task_event);
 
-					down(&ctrl->crit_sect);
+					mutex_lock(&ctrl->crit_sect);
 
 					if (p_slot->state == BLINKINGOFF_STATE) {
 						/* slot is on */
@@ -1922,7 +1922,7 @@
 					/* Wait for SOBS to be unset */
 					wait_for_ctrl_irq (ctrl);
 
-					up(&ctrl->crit_sect);
+					mutex_unlock(&ctrl->crit_sect);
 				}
 				/*** button Released (No action on press...) */
 				else if (ctrl->event_queue[loop].event_type == INT_BUTTON_RELEASE) {
@@ -1937,7 +1937,7 @@
 						p_slot->state = BLINKINGON_STATE;
 						info(msg_button_on, p_slot->number);
 					}
-					down(&ctrl->crit_sect);
+					mutex_lock(&ctrl->crit_sect);
 					
 					dbg("blink green LED and turn off amber\n");
 					
@@ -1949,7 +1949,7 @@
 					/* Wait for SOBS to be unset */
 					wait_for_ctrl_irq (ctrl);
 
-					up(&ctrl->crit_sect);
+					mutex_unlock(&ctrl->crit_sect);
 					init_timer(&p_slot->task_event);
 					p_slot->hp_slot = hp_slot;
 					p_slot->ctrl = ctrl;
diff -urN oldtree/drivers/pci/hotplug/ibmphp_hpc.c newtree/drivers/pci/hotplug/ibmphp_hpc.c
--- oldtree/drivers/pci/hotplug/ibmphp_hpc.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/pci/hotplug/ibmphp_hpc.c	2006-02-21 15:58:18.296365088 +0000
@@ -34,6 +34,8 @@
 #include <linux/pci.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
+
 #include "ibmphp.h"
 
 static int to_debug = FALSE;
@@ -101,7 +103,7 @@
 //----------------------------------------------------------------------------
 static int ibmphp_shutdown;
 static int tid_poll;
-static struct semaphore sem_hpcaccess;	// lock access to HPC
+static struct mutex 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
@@ -131,7 +133,7 @@
 {
 	debug ("%s - Entry\n", __FUNCTION__);
 
-	init_MUTEX (&sem_hpcaccess);
+	mutex_init(&sem_hpcaccess);
 	init_MUTEX (&semOperations);
 	init_MUTEX_LOCKED (&sem_exit);
 	to_debug = FALSE;
@@ -778,7 +780,7 @@
 *---------------------------------------------------------------------*/
 static void get_hpc_access (void)
 {
-	down (&sem_hpcaccess);
+	mutex_lock(&sem_hpcaccess);
 }
 
 /*----------------------------------------------------------------------
@@ -786,7 +788,7 @@
 *---------------------------------------------------------------------*/
 void free_hpc_access (void)
 {
-	up (&sem_hpcaccess);
+	mutex_unlock(&sem_hpcaccess);
 }
 
 /*----------------------------------------------------------------------
diff -urN oldtree/drivers/pci/hotplug/pciehp.h newtree/drivers/pci/hotplug/pciehp.h
--- oldtree/drivers/pci/hotplug/pciehp.h	2006-02-19 11:41:03.540804816 +0000
+++ newtree/drivers/pci/hotplug/pciehp.h	2006-02-21 15:58:18.297364936 +0000
@@ -34,6 +34,7 @@
 #include <linux/delay.h>
 #include <linux/sched.h>		/* signal_pending() */
 #include <linux/pcieport_if.h>
+#include <linux/mutex.h>
 #include "pci_hotplug.h"
 
 #define MY_NAME	"pciehp"
@@ -96,7 +97,7 @@
 #define MAX_EVENTS		10
 struct controller {
 	struct controller *next;
-	struct semaphore crit_sect;	/* critical section semaphore */
+	struct mutex crit_sect;		/* critical section mutex */
 	struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */
 	int num_slots;			/* Number of slots on ctlr */
 	int slot_num_inc;		/* 1 or -1 */
diff -urN oldtree/drivers/pci/hotplug/pciehp_core.c newtree/drivers/pci/hotplug/pciehp_core.c
--- oldtree/drivers/pci/hotplug/pciehp_core.c	2006-02-19 11:41:03.541804664 +0000
+++ newtree/drivers/pci/hotplug/pciehp_core.c	2006-02-21 15:58:18.304363872 +0000
@@ -439,7 +439,7 @@
 	}
 
 	/* Wait for exclusive access to hardware */
-	down(&ctrl->crit_sect);
+	mutex_lock(&ctrl->crit_sect);
 
 	t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
 	
@@ -447,7 +447,7 @@
 		rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
 		if (rc) {
 			/* Done with exclusive hardware access */
-			up(&ctrl->crit_sect);
+			mutex_unlock(&ctrl->crit_sect);
 			goto err_out_free_ctrl_slot;
 		} else
 			/* Wait for the command to complete */
@@ -455,7 +455,7 @@
 	}
 
 	/* Done with exclusive hardware access */
-	up(&ctrl->crit_sect);
+	mutex_unlock(&ctrl->crit_sect);
 
 	return 0;
 
diff -urN oldtree/drivers/pci/hotplug/pciehp_ctrl.c newtree/drivers/pci/hotplug/pciehp_ctrl.c
--- oldtree/drivers/pci/hotplug/pciehp_ctrl.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/pci/hotplug/pciehp_ctrl.c	2006-02-21 15:58:18.308363264 +0000
@@ -229,13 +229,13 @@
 static void set_slot_off(struct controller *ctrl, struct slot * pslot)
 {
 	/* Wait for exclusive access to hardware */
-	down(&ctrl->crit_sect);
+	mutex_lock(&ctrl->crit_sect);
 
 	/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
 	if (POWER_CTRL(ctrl->ctrlcap)) {
 		if (pslot->hpc_ops->power_off_slot(pslot)) {   
 			err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
-			up(&ctrl->crit_sect);
+			mutex_unlock(&ctrl->crit_sect);
 			return;
 		}
 		wait_for_ctrl_irq (ctrl);
@@ -249,14 +249,14 @@
 	if (ATTN_LED(ctrl->ctrlcap)) { 
 		if (pslot->hpc_ops->set_attention_status(pslot, 1)) {   
 			err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
-			up(&ctrl->crit_sect);
+			mutex_unlock(&ctrl->crit_sect);
 			return;
 		}
 		wait_for_ctrl_irq (ctrl);
 	}
 
 	/* Done with exclusive hardware access */
-	up(&ctrl->crit_sect);
+	mutex_unlock(&ctrl->crit_sect);
 }
 
 /**
@@ -279,13 +279,13 @@
 			ctrl->slot_device_offset, hp_slot);
 
 	/* Wait for exclusive access to hardware */
-	down(&ctrl->crit_sect);
+	mutex_lock(&ctrl->crit_sect);
 
 	if (POWER_CTRL(ctrl->ctrlcap)) {
 		/* Power on slot */
 		rc = p_slot->hpc_ops->power_on_slot(p_slot);
 		if (rc) {
-			up(&ctrl->crit_sect);
+			mutex_unlock(&ctrl->crit_sect);
 			return -1;
 		}
 
@@ -301,7 +301,7 @@
 	}
 
 	/* Done with exclusive hardware access */
-	up(&ctrl->crit_sect);
+	mutex_unlock(&ctrl->crit_sect);
 
 	/* Wait for ~1 second */
 	wait_for_ctrl_irq (ctrl);
@@ -335,7 +335,7 @@
 		pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
 	if (PWR_LED(ctrl->ctrlcap)) {
 		/* Wait for exclusive access to hardware */
-  		down(&ctrl->crit_sect);
+  		mutex_lock(&ctrl->crit_sect);
 
   		p_slot->hpc_ops->green_led_on(p_slot);
   
@@ -343,7 +343,7 @@
   		wait_for_ctrl_irq (ctrl);
   	
   		/* Done with exclusive hardware access */
-  		up(&ctrl->crit_sect);
+  		mutex_unlock(&ctrl->crit_sect);
   	}
 	return 0;
 
@@ -375,14 +375,14 @@
 	dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
 
 	/* Wait for exclusive access to hardware */
-	down(&ctrl->crit_sect);
+	mutex_lock(&ctrl->crit_sect);
 
 	if (POWER_CTRL(ctrl->ctrlcap)) {
 		/* power off slot */
 		rc = p_slot->hpc_ops->power_off_slot(p_slot);
 		if (rc) {
 			err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
-			up(&ctrl->crit_sect);
+			mutex_unlock(&ctrl->crit_sect);
 			return rc;
 		}
 		/* Wait for the command to complete */
@@ -398,7 +398,7 @@
 	}
 
 	/* Done with exclusive hardware access */
-	up(&ctrl->crit_sect);
+	mutex_unlock(&ctrl->crit_sect);
 
 	return 0;
 }
@@ -445,7 +445,7 @@
 
 		if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
 			/* Wait for exclusive access to hardware */
-			down(&p_slot->ctrl->crit_sect);
+			mutex_lock(&p_slot->ctrl->crit_sect);
 
 			p_slot->hpc_ops->green_led_off(p_slot);
 
@@ -453,7 +453,7 @@
 			wait_for_ctrl_irq (p_slot->ctrl);
 
 			/* Done with exclusive hardware access */
-			up(&p_slot->ctrl->crit_sect);
+			mutex_unlock(&p_slot->ctrl->crit_sect);
 		}
 		p_slot->state = STATIC_STATE;
 	}
@@ -495,7 +495,7 @@
 
 		if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
 			/* Wait for exclusive access to hardware */
-			down(&p_slot->ctrl->crit_sect);
+			mutex_lock(&p_slot->ctrl->crit_sect);
 
 			p_slot->hpc_ops->green_led_off(p_slot);
 
@@ -503,7 +503,7 @@
 			wait_for_ctrl_irq (p_slot->ctrl);
 
 			/* Done with exclusive hardware access */
-			up(&p_slot->ctrl->crit_sect);
+			mutex_unlock(&p_slot->ctrl->crit_sect);
 		}
 		p_slot->state = STATIC_STATE;
 	}
@@ -616,7 +616,7 @@
 					switch (p_slot->state) {
 					case BLINKINGOFF_STATE:
 						/* Wait for exclusive access to hardware */
-						down(&ctrl->crit_sect);
+						mutex_lock(&ctrl->crit_sect);
 						
 						if (PWR_LED(ctrl->ctrlcap)) {
 							p_slot->hpc_ops->green_led_on(p_slot);
@@ -630,11 +630,11 @@
 							wait_for_ctrl_irq (ctrl);
 						}
 						/* Done with exclusive hardware access */
-						up(&ctrl->crit_sect);
+						mutex_unlock(&ctrl->crit_sect);
 						break;
 					case BLINKINGON_STATE:
 						/* Wait for exclusive access to hardware */
-						down(&ctrl->crit_sect);
+						mutex_lock(&ctrl->crit_sect);
 
 						if (PWR_LED(ctrl->ctrlcap)) {
 							p_slot->hpc_ops->green_led_off(p_slot);
@@ -647,7 +647,7 @@
 							wait_for_ctrl_irq (ctrl);
 						}
 						/* Done with exclusive hardware access */
-						up(&ctrl->crit_sect);
+						mutex_unlock(&ctrl->crit_sect);
 
 						break;
 					default:
@@ -676,7 +676,7 @@
 						}
 
 						/* Wait for exclusive access to hardware */
-						down(&ctrl->crit_sect);
+						mutex_lock(&ctrl->crit_sect);
 
 						/* blink green LED and turn off amber */
 						if (PWR_LED(ctrl->ctrlcap)) {
@@ -693,7 +693,7 @@
 						}
 
 						/* Done with exclusive hardware access */
-						up(&ctrl->crit_sect);
+						mutex_unlock(&ctrl->crit_sect);
 
 						init_timer(&p_slot->task_event);
 						p_slot->task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
@@ -708,7 +708,7 @@
 					if (POWER_CTRL(ctrl->ctrlcap)) {
 						dbg("power fault\n");
 						/* Wait for exclusive access to hardware */
-						down(&ctrl->crit_sect);
+						mutex_lock(&ctrl->crit_sect);
 
 						if (ATTN_LED(ctrl->ctrlcap)) {
 							p_slot->hpc_ops->set_attention_status(p_slot, 1);
@@ -721,7 +721,7 @@
 						}
 
 						/* Done with exclusive hardware access */
-						up(&ctrl->crit_sect);
+						mutex_unlock(&ctrl->crit_sect);
 					}
 				}
 				/***********SURPRISE REMOVAL********************/
@@ -756,19 +756,19 @@
 	int rc;
 
 	/* Check to see if (latch closed, card present, power off) */
-	down(&p_slot->ctrl->crit_sect);
+	mutex_lock(&p_slot->ctrl->crit_sect);
 
 	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
 	if (rc || !getstatus) {
 		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
-		up(&p_slot->ctrl->crit_sect);
+		mutex_unlock(&p_slot->ctrl->crit_sect);
 		return 1;
 	}
 	if (MRL_SENS(p_slot->ctrl->ctrlcap)) {	
 		rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 		if (rc || getstatus) {
 			info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
-			up(&p_slot->ctrl->crit_sect);
+			mutex_unlock(&p_slot->ctrl->crit_sect);
 			return 1;
 		}
 	}
@@ -777,11 +777,11 @@
 		rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
 		if (rc || getstatus) {
 			info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
-			up(&p_slot->ctrl->crit_sect);
+			mutex_unlock(&p_slot->ctrl->crit_sect);
 			return 1;
 		}
 	}
-	up(&p_slot->ctrl->crit_sect);
+	mutex_unlock(&p_slot->ctrl->crit_sect);
 
 	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 
@@ -806,13 +806,13 @@
 		return 1;
 
 	/* Check to see if (latch closed, card present, power on) */
-	down(&p_slot->ctrl->crit_sect);
+	mutex_lock(&p_slot->ctrl->crit_sect);
 
 	if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {	
 		ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
 		if (ret || !getstatus) {
 			info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
-			up(&p_slot->ctrl->crit_sect);
+			mutex_unlock(&p_slot->ctrl->crit_sect);
 			return 1;
 		}
 	}
@@ -821,7 +821,7 @@
 		ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 		if (ret || getstatus) {
 			info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
-			up(&p_slot->ctrl->crit_sect);
+			mutex_unlock(&p_slot->ctrl->crit_sect);
 			return 1;
 		}
 	}
@@ -830,12 +830,12 @@
 		ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
 		if (ret || !getstatus) {
 			info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
-			up(&p_slot->ctrl->crit_sect);
+			mutex_unlock(&p_slot->ctrl->crit_sect);
 			return 1;
 		}
 	}
 
-	up(&p_slot->ctrl->crit_sect);
+	mutex_unlock(&p_slot->ctrl->crit_sect);
 
 	ret = remove_board(p_slot);
 	update_slot_info(p_slot);
diff -urN oldtree/drivers/pci/hotplug/pciehp_hpc.c newtree/drivers/pci/hotplug/pciehp_hpc.c
--- oldtree/drivers/pci/hotplug/pciehp_hpc.c	2006-02-19 11:41:03.542804512 +0000
+++ newtree/drivers/pci/hotplug/pciehp_hpc.c	2006-02-21 15:58:18.319361592 +0000
@@ -1334,7 +1334,7 @@
 	if (pci_enable_device(pdev))
 		goto abort_free_ctlr;
 	
-	init_MUTEX(&ctrl->crit_sect);
+	mutex_init(&ctrl->crit_sect);
 	/* setup wait queue */
 	init_waitqueue_head(&ctrl->queue);
 
diff -urN oldtree/drivers/pci/hotplug/pcihp_skeleton.c newtree/drivers/pci/hotplug/pcihp_skeleton.c
--- oldtree/drivers/pci/hotplug/pcihp_skeleton.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/pci/hotplug/pcihp_skeleton.c	2006-02-21 15:58:18.526330128 +0000
@@ -37,10 +37,12 @@
 #include <linux/init.h>
 #include "pci_hotplug.h"
 
+#define SLOT_NAME_SIZE	10
 struct slot {
 	u8 number;
 	struct hotplug_slot *hotplug_slot;
 	struct list_head slot_list;
+	char name[SLOT_NAME_SIZE];
 };
 
 static LIST_HEAD(slot_list);
@@ -233,12 +235,10 @@
 
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 	kfree(slot->hotplug_slot->info);
-	kfree(slot->hotplug_slot->name);
 	kfree(slot->hotplug_slot);
 	kfree(slot);
 }
 
-#define SLOT_NAME_SIZE	10
 static void make_slot_name(struct slot *slot)
 {
 	/*
@@ -257,7 +257,6 @@
 	struct slot *slot;
 	struct hotplug_slot *hotplug_slot;
 	struct hotplug_slot_info *info;
-	char *name;
 	int retval = -ENOMEM;
 	int i;
 
@@ -266,31 +265,23 @@
 	 * with the pci_hotplug subsystem.
 	 */
 	for (i = 0; i < num_slots; ++i) {
-		slot = kmalloc(sizeof(struct slot), GFP_KERNEL);
+		slot = kzalloc(sizeof(*slot), GFP_KERNEL);
 		if (!slot)
 			goto error;
-		memset(slot, 0, sizeof(struct slot));
 
-		hotplug_slot = kmalloc(sizeof(struct hotplug_slot),
-					GFP_KERNEL);
+		hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL);
 		if (!hotplug_slot)
 			goto error_slot;
-		memset(hotplug_slot, 0, sizeof (struct hotplug_slot));
 		slot->hotplug_slot = hotplug_slot;
 
-		info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
+		info = kzalloc(sizeof(*info), GFP_KERNEL);
 		if (!info)
 			goto error_hpslot;
-		memset(info, 0, sizeof (struct hotplug_slot_info));
 		hotplug_slot->info = info;
 
-		name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
-		if (!name)
-			goto error_info;
-		hotplug_slot->name = name;
-
 		slot->number = i;
 
+		hotplug_slot->name = slot->name;
 		hotplug_slot->private = slot;
 		hotplug_slot->release = &release_slot;
 		make_slot_name(slot);
@@ -300,16 +291,16 @@
 		 * Initialize the slot info structure with some known
 		 * good values.
 		 */
-		info->power_status = get_power_status(slot);
-		info->attention_status = get_attention_status(slot);
-		info->latch_status = get_latch_status(slot);
-		info->adapter_status = get_adapter_status(slot);
+		get_power_status(hotplug_slot, &info->power_status);
+		get_attention_status(hotplug_slot, &info->attention_status);
+		get_latch_status(hotplug_slot, &info->latch_status);
+		get_adapter_status(hotplug_slot, &info->adapter_status);
 		
 		dbg("registering slot %d\n", i);
 		retval = pci_hp_register(slot->hotplug_slot);
 		if (retval) {
 			err("pci_hp_register failed with error %d\n", retval);
-			goto error_name;
+			goto error_info;
 		}
 
 		/* add slot to our internal list */
@@ -317,8 +308,6 @@
 	}
 
 	return 0;
-error_name:
-	kfree(name);
 error_info:
 	kfree(info);
 error_hpslot:
diff -urN oldtree/drivers/pci/hotplug/rpadlpar_core.c newtree/drivers/pci/hotplug/rpadlpar_core.c
--- oldtree/drivers/pci/hotplug/rpadlpar_core.c	2006-02-19 11:41:03.544804208 +0000
+++ newtree/drivers/pci/hotplug/rpadlpar_core.c	2006-02-21 15:58:24.217464944 +0000
@@ -19,7 +19,7 @@
 #include <linux/string.h>
 
 #include <asm/pci-bridge.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/rtas.h>
 #include <asm/vio.h>
 
@@ -27,7 +27,7 @@
 #include "rpaphp.h"
 #include "rpadlpar.h"
 
-static DECLARE_MUTEX(rpadlpar_sem);
+static DEFINE_MUTEX(rpadlpar_mutex);
 
 #define DLPAR_MODULE_NAME "rpadlpar_io"
 
@@ -300,7 +300,7 @@
 	int node_type;
 	int rc = -EIO;
 
-	if (down_interruptible(&rpadlpar_sem))
+	if (mutex_lock_interruptible(&rpadlpar_mutex))
 		return -ERESTARTSYS;
 
 	/* Find newly added node */
@@ -324,7 +324,7 @@
 
 	printk(KERN_INFO "%s: slot %s added\n", DLPAR_MODULE_NAME, drc_name);
 exit:
-	up(&rpadlpar_sem);
+	mutex_unlock(&rpadlpar_mutex);
 	return rc;
 }
 
@@ -417,7 +417,7 @@
 	int node_type;
 	int rc = 0;
 
-	if (down_interruptible(&rpadlpar_sem))
+	if (mutex_lock_interruptible(&rpadlpar_mutex))
 		return -ERESTARTSYS;
 
 	dn = find_dlpar_node(drc_name, &node_type);
@@ -439,7 +439,7 @@
 	}
 	printk(KERN_INFO "%s: slot %s removed\n", DLPAR_MODULE_NAME, drc_name);
 exit:
-	up(&rpadlpar_sem);
+	mutex_unlock(&rpadlpar_mutex);
 	return rc;
 }
 
diff -urN oldtree/drivers/pci/hotplug/sgi_hotplug.c newtree/drivers/pci/hotplug/sgi_hotplug.c
--- oldtree/drivers/pci/hotplug/sgi_hotplug.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/pci/hotplug/sgi_hotplug.c	2006-02-21 15:58:24.240461448 +0000
@@ -15,6 +15,7 @@
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/types.h>
+#include <linux/mutex.h>
 
 #include <asm/sn/addrs.h>
 #include <asm/sn/l1.h>
@@ -81,7 +82,7 @@
 	.get_power_status       = get_power_status,
 };
 
-static DECLARE_MUTEX(sn_hotplug_sem);
+static DEFINE_MUTEX(sn_hotplug_mutex);
 
 static ssize_t path_show (struct hotplug_slot *bss_hotplug_slot,
 	       		  char *buf)
@@ -339,7 +340,7 @@
 	int rc;
 
 	/* Serialize the Linux PCI infrastructure */
-	down(&sn_hotplug_sem);
+	mutex_lock(&sn_hotplug_mutex);
 
 	/*
 	 * Power-on and initialize the slot in the SN
@@ -347,7 +348,7 @@
 	 */
 	rc = sn_slot_enable(bss_hotplug_slot, slot->device_num);
 	if (rc) {
-		up(&sn_hotplug_sem);
+		mutex_unlock(&sn_hotplug_mutex);
 		return rc;
 	}
 
@@ -355,7 +356,7 @@
 				  PCI_DEVFN(slot->device_num + 1, 0));
 	if (!num_funcs) {
 		dev_dbg(slot->pci_bus->self, "no device in slot\n");
-		up(&sn_hotplug_sem);
+		mutex_unlock(&sn_hotplug_mutex);
 		return -ENODEV;
 	}
 
@@ -395,7 +396,7 @@
 	if (new_ppb)
 		pci_bus_add_devices(new_bus);
 
-	up(&sn_hotplug_sem);
+	mutex_unlock(&sn_hotplug_mutex);
 
 	if (rc == 0)
 		dev_dbg(slot->pci_bus->self,
@@ -415,7 +416,7 @@
 	int rc;
 
 	/* Acquire update access to the bus */
-	down(&sn_hotplug_sem);
+	mutex_lock(&sn_hotplug_mutex);
 
 	/* is it okay to bring this slot down? */
 	rc = sn_slot_disable(bss_hotplug_slot, slot->device_num,
@@ -450,7 +451,7 @@
 			     PCI_REQ_SLOT_DISABLE);
  leaving:
 	/* Release the bus lock */
-	up(&sn_hotplug_sem);
+	mutex_unlock(&sn_hotplug_mutex);
 
 	return rc;
 }
@@ -462,9 +463,9 @@
 	struct pcibus_info *pcibus_info;
 
 	pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
-	down(&sn_hotplug_sem);
+	mutex_lock(&sn_hotplug_mutex);
 	*value = pcibus_info->pbi_enabled_devices & (1 << slot->device_num);
-	up(&sn_hotplug_sem);
+	mutex_unlock(&sn_hotplug_mutex);
 	return 0;
 }
 
diff -urN oldtree/drivers/pci/hotplug/shpchp.h newtree/drivers/pci/hotplug/shpchp.h
--- oldtree/drivers/pci/hotplug/shpchp.h	2006-02-19 11:41:03.548803600 +0000
+++ newtree/drivers/pci/hotplug/shpchp.h	2006-02-21 15:58:18.641312648 +0000
@@ -33,6 +33,7 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/sched.h>	/* signal_pending(), struct timer_list */
+#include <linux/mutex.h>
 
 #include "pci_hotplug.h"
 
@@ -52,10 +53,8 @@
 #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
 #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
 
-#define SLOT_MAGIC	0x67267321
+#define SLOT_NAME_SIZE 10
 struct slot {
-	u32 magic;
-	struct slot *next;
 	u8 bus;
 	u8 device;
 	u16 status;
@@ -70,6 +69,7 @@
 	struct hpc_ops *hpc_ops;
 	struct hotplug_slot *hotplug_slot;
 	struct list_head	slot_list;
+	char name[SLOT_NAME_SIZE];
 };
 
 struct event_info {
@@ -78,15 +78,16 @@
 };
 
 struct controller {
-	struct controller *next;
-	struct semaphore crit_sect;	/* critical section semaphore */
+	struct list_head ctrl_list;
+	struct mutex crit_sect;		/* critical section mutex */
+	struct mutex cmd_lock;		/* command lock */
 	struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */
 	int num_slots;			/* Number of slots on ctlr */
 	int slot_num_inc;		/* 1 or -1 */
 	struct pci_dev *pci_dev;
 	struct pci_bus *pci_bus;
 	struct event_info event_queue[10];
-	struct slot *slot;
+	struct list_head slot_list;
 	struct hpc_ops *hpc_ops;
 	wait_queue_head_t queue;	/* sleep & wake process */
 	u8 next_event;
@@ -204,7 +205,7 @@
 
 
 /* Global variables */
-extern struct controller *shpchp_ctrl_list;
+extern struct list_head shpchp_ctrl_list;
 
 struct ctrl_reg {
 	volatile u32 base_offset;
@@ -286,10 +287,6 @@
 		dbg("%s - slot == NULL", function);
 		return -1;
 	}
-	if (slot->magic != SLOT_MAGIC) {
-		dbg("%s - bad magic number for slot", function);
-		return -1;
-	}
 	if (!slot->hotplug_slot) {
 		dbg("%s - slot->hotplug_slot == NULL!", function);
 		return -1;
@@ -314,23 +311,19 @@
 
 static inline struct slot *shpchp_find_slot (struct controller *ctrl, u8 device)
 {
-	struct slot *p_slot, *tmp_slot = NULL;
+	struct slot *slot;
 
 	if (!ctrl)
 		return NULL;
 
-	p_slot = ctrl->slot;
-
-	while (p_slot && (p_slot->device != device)) {
-		tmp_slot = p_slot;
-		p_slot = p_slot->next;
-	}
-	if (p_slot == NULL) {
-		err("ERROR: shpchp_find_slot device=0x%x\n", device);
-		p_slot = tmp_slot;
+	list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
+		if (slot->device == device)
+			return slot;
 	}
 
-	return (p_slot);
+	err("%s: slot (device=0x%x) not found\n", __FUNCTION__, device);
+
+	return NULL;
 }
 
 static inline int wait_for_ctrl_irq (struct controller *ctrl)
@@ -427,13 +420,6 @@
 	pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, pcix_misc2_temp);
 }
 
-#define SLOT_NAME_SIZE 10
-
-static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
-{
-	snprintf(buffer, buffer_size, "%04d_%04d", slot->bus, slot->number);
-}
-
 enum php_ctlr_type {
 	PCI,
 	ISA,
diff -urN oldtree/drivers/pci/hotplug/shpchp_core.c newtree/drivers/pci/hotplug/shpchp_core.c
--- oldtree/drivers/pci/hotplug/shpchp_core.c	2006-02-19 11:41:03.548803600 +0000
+++ newtree/drivers/pci/hotplug/shpchp_core.c	2006-02-21 15:58:18.642312496 +0000
@@ -38,7 +38,7 @@
 int shpchp_debug;
 int shpchp_poll_mode;
 int shpchp_poll_time;
-struct controller *shpchp_ctrl_list;	/* = NULL */
+LIST_HEAD(shpchp_ctrl_list);
 
 #define DRIVER_VERSION	"0.4"
 #define DRIVER_AUTHOR	"Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
@@ -94,107 +94,98 @@
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	kfree(slot->hotplug_slot->info);
-	kfree(slot->hotplug_slot->name);
 	kfree(slot->hotplug_slot);
 	kfree(slot);
 }
 
+static void make_slot_name(struct slot *slot)
+{
+	snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d",
+		 slot->bus, slot->number);
+}
+
 static int init_slots(struct controller *ctrl)
 {
-	struct slot *new_slot;
-	u8 number_of_slots;
-	u8 slot_device;
-	u32 slot_number, sun;
-	int result = -ENOMEM;
-
-	number_of_slots = ctrl->num_slots;
-	slot_device = ctrl->slot_device_offset;
-	slot_number = ctrl->first_slot;
-
-	while (number_of_slots) {
-		new_slot = (struct slot *) kmalloc(sizeof(struct slot), GFP_KERNEL);
-		if (!new_slot)
+	struct slot *slot;
+	struct hotplug_slot *hotplug_slot;
+	struct hotplug_slot_info *info;
+	int retval = -ENOMEM;
+	int i;
+	u32 sun;
+
+	for (i = 0; i < ctrl->num_slots; i++) {
+		slot = kzalloc(sizeof(*slot), GFP_KERNEL);
+		if (!slot)
 			goto error;
 
-		memset(new_slot, 0, sizeof(struct slot));
-		new_slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
-		if (!new_slot->hotplug_slot)
+		hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL);
+		if (!hotplug_slot)
 			goto error_slot;
-		memset(new_slot->hotplug_slot, 0, sizeof (struct hotplug_slot));
+		slot->hotplug_slot = hotplug_slot;
 
-		new_slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
-		if (!new_slot->hotplug_slot->info)
+		info = kzalloc(sizeof(*info), GFP_KERNEL);
+		if (!info)
 			goto error_hpslot;
-		memset(new_slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info));
-		new_slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL);
-		if (!new_slot->hotplug_slot->name)
-			goto error_info;
+		hotplug_slot->info = info;
+
+		hotplug_slot->name = slot->name;
 
-		new_slot->magic = SLOT_MAGIC;
-		new_slot->ctrl = ctrl;
-		new_slot->bus = ctrl->slot_bus;
-		new_slot->device = slot_device;
-		new_slot->hpc_ops = ctrl->hpc_ops;
+		slot->hp_slot = i;
+		slot->ctrl = ctrl;
+		slot->bus = ctrl->slot_bus;
+		slot->device = ctrl->slot_device_offset + i;
+		slot->hpc_ops = ctrl->hpc_ops;
 
 		if (shpchprm_get_physical_slot_number(ctrl, &sun,
-					new_slot->bus, new_slot->device))
-			goto error_name;
+						      slot->bus, slot->device))
+			goto error_info;
 
-		new_slot->number = sun;
-		new_slot->hp_slot = slot_device - ctrl->slot_device_offset;
+		slot->number = sun;
 
 		/* register this slot with the hotplug pci core */
-		new_slot->hotplug_slot->private = new_slot;
-		new_slot->hotplug_slot->release = &release_slot;
-		make_slot_name(new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot);
-		new_slot->hotplug_slot->ops = &shpchp_hotplug_slot_ops;
-
-		new_slot->hpc_ops->get_power_status(new_slot, &(new_slot->hotplug_slot->info->power_status));
-		new_slot->hpc_ops->get_attention_status(new_slot, &(new_slot->hotplug_slot->info->attention_status));
-		new_slot->hpc_ops->get_latch_status(new_slot, &(new_slot->hotplug_slot->info->latch_status));
-		new_slot->hpc_ops->get_adapter_status(new_slot, &(new_slot->hotplug_slot->info->adapter_status));
-
-		dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x slot_device_offset=%x\n", new_slot->bus, 
-			new_slot->device, new_slot->hp_slot, new_slot->number, ctrl->slot_device_offset);
-		result = pci_hp_register (new_slot->hotplug_slot);
-		if (result) {
-			err ("pci_hp_register failed with error %d\n", result);
-			goto error_name;
+		hotplug_slot->private = slot;
+		hotplug_slot->release = &release_slot;
+		make_slot_name(slot);
+		hotplug_slot->ops = &shpchp_hotplug_slot_ops;
+
+		get_power_status(hotplug_slot, &info->power_status);
+		get_attention_status(hotplug_slot, &info->attention_status);
+		get_latch_status(hotplug_slot, &info->latch_status);
+		get_adapter_status(hotplug_slot, &info->adapter_status);
+
+		dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
+		    "slot_device_offset=%x\n", slot->bus, slot->device,
+		    slot->hp_slot, slot->number, ctrl->slot_device_offset);
+		retval = pci_hp_register(slot->hotplug_slot);
+		if (retval) {
+			err("pci_hp_register failed with error %d\n", retval);
+			goto error_info;
 		}
 
-		new_slot->next = ctrl->slot;
-		ctrl->slot = new_slot;
-
-		number_of_slots--;
-		slot_device++;
-		slot_number += ctrl->slot_num_inc;
+		list_add(&slot->slot_list, &ctrl->slot_list);
 	}
 
 	return 0;
-
-error_name:
-	kfree(new_slot->hotplug_slot->name);
 error_info:
-	kfree(new_slot->hotplug_slot->info);
+	kfree(info);
 error_hpslot:
-	kfree(new_slot->hotplug_slot);
+	kfree(hotplug_slot);
 error_slot:
-	kfree(new_slot);
+	kfree(slot);
 error:
-	return result;
+	return retval;
 }
 
 static void cleanup_slots(struct controller *ctrl)
 {
-	struct slot *old_slot, *next_slot;
-
-	old_slot = ctrl->slot;
-	ctrl->slot = NULL;
-
-	while (old_slot) {
-		next_slot = old_slot->next;
-		pci_hp_deregister(old_slot->hotplug_slot);
-		old_slot = next_slot;
+	struct list_head *tmp;
+	struct list_head *next;
+	struct slot *slot;
+
+	list_for_each_safe(tmp, next, &ctrl->slot_list) {
+		slot = list_entry(tmp, struct slot, slot_list);
+		list_del(&slot->slot_list);
+		pci_hp_deregister(slot->hotplug_slot);
 	}
 }
 
@@ -207,9 +198,12 @@
 	int rc;
 	int flags;
 
-	rc = shpc_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &updown, &flags);
+	rc = shpc_get_ctlr_slot_config(ctrl, &num_ctlr_slots,
+				       &first_device_num, &physical_slot_num,
+				       &updown, &flags);
 	if (rc) {
-		err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device);
+		err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n",
+		    __FUNCTION__, ctrl->bus, ctrl->device);
 		return -1;
 	}
 
@@ -218,19 +212,19 @@
 	ctrl->first_slot = physical_slot_num;
 	ctrl->slot_num_inc = updown;		/* either -1 or 1 */
 
-	dbg("%s: num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) updown(%d) for b:d (%x:%x)\n",
-		__FUNCTION__, num_ctlr_slots, first_device_num, physical_slot_num, updown, ctrl->bus, ctrl->device);
+	dbg("%s: num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) updown(%d) for b:d "
+	    "(%x:%x)\n", __FUNCTION__, num_ctlr_slots, first_device_num,
+	    physical_slot_num, updown, ctrl->bus, ctrl->device);
 
 	return 0;
 }
 
-
 /*
  * set_attention_status - Turns the Amber LED for a slot on, off or blink
  */
 static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
@@ -240,20 +234,18 @@
 	return 0;
 }
 
-
 static int enable_slot (struct hotplug_slot *hotplug_slot)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	return shpchp_enable_slot(slot);
 }
 
-
 static int disable_slot (struct hotplug_slot *hotplug_slot)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
@@ -262,7 +254,7 @@
 
 static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval;
 
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -276,7 +268,7 @@
 
 static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval;
 
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -290,7 +282,7 @@
 
 static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval;
 
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -304,7 +296,7 @@
 
 static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval;
 
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -318,7 +310,7 @@
 
 static int get_address (struct hotplug_slot *hotplug_slot, u32 *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	struct pci_bus *bus = slot->ctrl->pci_dev->subordinate;
 
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -330,11 +322,11 @@
 
 static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval;
 
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
-	
+
 	retval = slot->hpc_ops->get_max_bus_speed(slot, value);
 	if (retval < 0)
 		*value = PCI_SPEED_UNKNOWN;
@@ -344,11 +336,11 @@
 
 static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval;
 
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
-	
+
 	retval = slot->hpc_ops->get_cur_bus_speed(slot, value);
 	if (retval < 0)
 		*value = PCI_SPEED_UNKNOWN;
@@ -372,46 +364,47 @@
 	int rc;
 	struct controller *ctrl;
 	struct slot *t_slot;
-	int first_device_num;	/* first PCI device number supported by this SHPC */
-	int num_ctlr_slots;	/* number of slots supported by this SHPC */
+	int first_device_num;	/* first PCI device number */
+	int num_ctlr_slots;	/* number of slots implemented */
 
 	if (!is_shpc_capable(pdev))
 		return -ENODEV;
 
-	ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL);
+	ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
 	if (!ctrl) {
 		err("%s : out of memory\n", __FUNCTION__);
 		goto err_out_none;
 	}
-	memset(ctrl, 0, sizeof(struct controller));
+	INIT_LIST_HEAD(&ctrl->slot_list);
 
 	rc = shpc_init(ctrl, pdev);
 	if (rc) {
-		dbg("%s: controller initialization failed\n", SHPC_MODULE_NAME);
+		dbg("%s: controller initialization failed\n",
+		    SHPC_MODULE_NAME);
 		goto err_out_free_ctrl;
 	}
 
 	pci_set_drvdata(pdev, ctrl);
 
-	ctrl->pci_bus = kmalloc (sizeof (*ctrl->pci_bus), GFP_KERNEL);
+	ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL);
 	if (!ctrl->pci_bus) {
 		err("out of memory\n");
 		rc = -ENOMEM;
 		goto err_out_unmap_mmio_region;
 	}
-	
+
 	memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus));
 	ctrl->bus = pdev->bus->number;
 	ctrl->slot_bus = pdev->subordinate->number;
-
 	ctrl->device = PCI_SLOT(pdev->devfn);
 	ctrl->function = PCI_FUNC(pdev->devfn);
-	dbg("ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", ctrl->bus, ctrl->device, ctrl->function, pdev->irq);
+
+	dbg("ctrl bus=0x%x, device=%x, function=%x, irq=%x\n",
+	    ctrl->bus, ctrl->device, ctrl->function, pdev->irq);
 
 	/*
-	 *	Save configuration headers for this and subordinate PCI buses
+	 * Save configuration headers for this and subordinate PCI buses
 	 */
-
 	rc = get_ctlr_slot_config(ctrl);
 	if (rc) {
 		err(msg_initialization_err, rc);
@@ -421,7 +414,7 @@
 	num_ctlr_slots = ctrl->num_slots;
 
 	ctrl->add_support = 1;
-	
+
 	/* Setup the slot information structures */
 	rc = init_slots(ctrl);
 	if (rc) {
@@ -437,20 +430,15 @@
 	dbg("%s: t_slot->hp_slot %x\n", __FUNCTION__,t_slot->hp_slot);
 
 	if (rc || ctrl->speed == PCI_SPEED_UNKNOWN) {
-		err(SHPC_MODULE_NAME ": Can't get current bus speed. Set to 33MHz PCI.\n");
+		err(SHPC_MODULE_NAME ": Can't get current bus speed. "
+		    "Set to 33MHz PCI.\n");
 		ctrl->speed = PCI_SPEED_33MHz;
 	}
 
 	/* Finish setting up the hot plug ctrl device */
 	ctrl->next_event = 0;
 
-	if (!shpchp_ctrl_list) {
-		shpchp_ctrl_list = ctrl;
-		ctrl->next = NULL;
-	} else {
-		ctrl->next = shpchp_ctrl_list;
-		shpchp_ctrl_list = ctrl;
-	}
+	list_add(&ctrl->ctrl_list, &shpchp_ctrl_list);
 
 	shpchp_create_ctrl_files(ctrl);
 
@@ -468,11 +456,10 @@
 	return -ENODEV;
 }
 
-
 static int shpc_start_thread(void)
 {
 	int retval = 0;
-	
+
 	dbg("Initialize + Start the notification/polling mechanism \n");
 
 	retval = shpchp_event_start_thread();
@@ -486,22 +473,17 @@
 
 static void __exit unload_shpchpd(void)
 {
+	struct list_head *tmp;
+	struct list_head *next;
 	struct controller *ctrl;
-	struct controller *tctrl;
-
-	ctrl = shpchp_ctrl_list;
 
-	while (ctrl) {
+	list_for_each_safe(tmp, next, &shpchp_ctrl_list) {
+		ctrl = list_entry(tmp, struct controller, ctrl_list);
 		shpchp_remove_ctrl_files(ctrl);
 		cleanup_slots(ctrl);
-
 		kfree (ctrl->pci_bus);
 		ctrl->hpc_ops->release_ctlr(ctrl);
-
-		tctrl = ctrl;
-		ctrl = ctrl->next;
-
-		kfree(tctrl);
+		kfree(ctrl);
 	}
 
 	/* Stop the notification mechanism */
@@ -509,24 +491,12 @@
 
 }
 
-
 static struct pci_device_id shpcd_pci_tbl[] = {
-	{
-	.class =        ((PCI_CLASS_BRIDGE_PCI << 8) | 0x00),
-	.class_mask =	~0,
-	.vendor =       PCI_ANY_ID,
-	.device =       PCI_ANY_ID,
-	.subvendor =    PCI_ANY_ID,
-	.subdevice =    PCI_ANY_ID,
-	},
-	
+	{PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0)},
 	{ /* end: all zeroes */ }
 };
-
 MODULE_DEVICE_TABLE(pci, shpcd_pci_tbl);
 
-
-
 static struct pci_driver shpc_driver = {
 	.name =		SHPC_MODULE_NAME,
 	.id_table =	shpcd_pci_tbl,
@@ -534,8 +504,6 @@
 	/* remove:	shpc_remove_one, */
 };
 
-
-
 static int __init shpcd_init(void)
 {
 	int retval = 0;
diff -urN oldtree/drivers/pci/hotplug/shpchp_ctrl.c newtree/drivers/pci/hotplug/shpchp_ctrl.c
--- oldtree/drivers/pci/hotplug/shpchp_ctrl.c	2006-02-19 11:41:03.549803448 +0000
+++ newtree/drivers/pci/hotplug/shpchp_ctrl.c	2006-02-21 15:58:18.452341376 +0000
@@ -242,21 +242,10 @@
 	int rc = 0;
 
 	dbg("%s: change to speed %d\n", __FUNCTION__, speed);
-	down(&ctrl->crit_sect);
 	if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed))) {
 		err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
-		up(&ctrl->crit_sect);
 		return WRONG_BUS_FREQUENCY;
 	}
-		
-	if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
-		err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
-			  __FUNCTION__);
-		err("%s: Error code (%d)\n", __FUNCTION__, rc);
-		up(&ctrl->crit_sect);
-		return WRONG_BUS_FREQUENCY;
-	}
-	up(&ctrl->crit_sect);
 	return rc;
 }
 
@@ -318,56 +307,27 @@
 			__FUNCTION__, p_slot->device,
 			ctrl->slot_device_offset, hp_slot);
 
-	/* Wait for exclusive access to hardware */
-	down(&ctrl->crit_sect);
-
 	/* Power on slot without connecting to bus */
 	rc = p_slot->hpc_ops->power_on_slot(p_slot);
 	if (rc) {
 		err("%s: Failed to power on slot\n", __FUNCTION__);
-		/* Done with exclusive hardware access */
-		up(&ctrl->crit_sect);
 		return -1;
 	}
 	
-	rc = p_slot->hpc_ops->check_cmd_status(ctrl);
-	if (rc) {
-		err("%s: Failed to power on slot, error code(%d)\n", __FUNCTION__, rc);
-		/* Done with exclusive hardware access */
-		up(&ctrl->crit_sect);
-		return -1;
-	}
-
-	
 	if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) {
 		if (slots_not_empty)
 			return WRONG_BUS_FREQUENCY;
 		
 		if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) {
 			err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
-			up(&ctrl->crit_sect);
 			return WRONG_BUS_FREQUENCY;
 		}
 		
-		if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
-			err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
-				  __FUNCTION__);
-			err("%s: Error code (%d)\n", __FUNCTION__, rc);
-			up(&ctrl->crit_sect);
-			return WRONG_BUS_FREQUENCY;
-		}
 		/* turn on board, blink green LED, turn off Amber LED */
 		if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
 			err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
-			up(&ctrl->crit_sect);
 			return rc;
 		}
-
-		if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
-			err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
-			up(&ctrl->crit_sect);
-			return rc;  
-		}
 	}
  
 	rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &adapter_speed);
@@ -379,16 +339,12 @@
 
 	if (rc  || adapter_speed == PCI_SPEED_UNKNOWN) {
 		err("%s: Can't get adapter speed or bus mode mismatch\n", __FUNCTION__);
-		/* Done with exclusive hardware access */
-		up(&ctrl->crit_sect);
 		return WRONG_BUS_FREQUENCY;
 	}
 
 	rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bus_speed);
 	if (rc || bus_speed == PCI_SPEED_UNKNOWN) {
 		err("%s: Can't get bus operation speed\n", __FUNCTION__);
-		/* Done with exclusive hardware access */
-		up(&ctrl->crit_sect);
 		return WRONG_BUS_FREQUENCY;
 	}
 
@@ -398,9 +354,6 @@
 		max_bus_speed = bus_speed;
 	}
 
-	/* Done with exclusive hardware access */
-	up(&ctrl->crit_sect);
-
 	if ((rc  = p_slot->hpc_ops->get_prog_int(p_slot, &pi))) {
 		err("%s: Can't get controller programming interface, set it to 1\n", __FUNCTION__);
 		pi = 1;
@@ -481,22 +434,12 @@
 				return rc;
 	}
 
-	down(&ctrl->crit_sect);
 	/* turn on board, blink green LED, turn off Amber LED */
 	if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
 		err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
-		up(&ctrl->crit_sect);
 		return rc;
 	}
 
-	if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
-		err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
-		up(&ctrl->crit_sect);
-		return rc;  
-	}
-
-	up(&ctrl->crit_sect);
-
 	/* Wait for ~1 second */
 	wait_for_ctrl_irq (ctrl);
 
@@ -520,40 +463,18 @@
 	p_slot->is_a_board = 0x01;
 	p_slot->pwr_save = 1;
 
-	/* Wait for exclusive access to hardware */
-	down(&ctrl->crit_sect);
-
 	p_slot->hpc_ops->green_led_on(p_slot);
 
-	/* Done with exclusive hardware access */
-	up(&ctrl->crit_sect);
-
 	return 0;
 
 err_exit:
-	/* Wait for exclusive access to hardware */
-	down(&ctrl->crit_sect);
-
 	/* turn off slot, turn on Amber LED, turn off Green LED */
 	rc = p_slot->hpc_ops->slot_disable(p_slot);
 	if (rc) {
 		err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
-		/* Done with exclusive hardware access */
-		up(&ctrl->crit_sect);
-		return rc;
-	}
-
-	rc = p_slot->hpc_ops->check_cmd_status(ctrl);
-	if (rc) {
-		err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
-		/* Done with exclusive hardware access */
-		up(&ctrl->crit_sect);
 		return rc;
 	}
 
-	/* Done with exclusive hardware access */
-	up(&ctrl->crit_sect);
-
 	return(rc);
 }
 
@@ -580,37 +501,19 @@
 	if (p_slot->is_a_board)
 		p_slot->status = 0x01;
 
-	/* Wait for exclusive access to hardware */
-	down(&ctrl->crit_sect);
-
 	/* turn off slot, turn on Amber LED, turn off Green LED */
 	rc = p_slot->hpc_ops->slot_disable(p_slot);
 	if (rc) {
 		err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
-		/* Done with exclusive hardware access */
-		up(&ctrl->crit_sect);
 		return rc;
 	}
-
-	rc = p_slot->hpc_ops->check_cmd_status(ctrl);
-	if (rc) {
-		err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
-		/* Done with exclusive hardware access */
-		up(&ctrl->crit_sect);
-		return rc;  
-	}
 	
 	rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
 	if (rc) {
 		err("%s: Issue of Set Attention command failed\n", __FUNCTION__);
-		/* Done with exclusive hardware access */
-		up(&ctrl->crit_sect);
 		return rc;
 	}
 
-	/* Done with exclusive hardware access */
-	up(&ctrl->crit_sect);
-
 	p_slot->pwr_save = 0;
 	p_slot->is_a_board = 0;
 
@@ -654,15 +557,9 @@
 	} else {
 		p_slot->state = POWERON_STATE;
 
-		if (shpchp_enable_slot(p_slot)) {
-			/* Wait for exclusive access to hardware */
-			down(&p_slot->ctrl->crit_sect);
-
+		if (shpchp_enable_slot(p_slot))
 			p_slot->hpc_ops->green_led_off(p_slot);
 
-			/* Done with exclusive hardware access */
-			up(&p_slot->ctrl->crit_sect);
-		}
 		p_slot->state = STATIC_STATE;
 	}
 
@@ -688,7 +585,7 @@
 		if (pushbutton_pending)
 			shpchp_pushbutton_thread(pushbutton_pending);
 		else
-			for (ctrl = shpchp_ctrl_list; ctrl; ctrl=ctrl->next)
+			list_for_each_entry(ctrl, &shpchp_ctrl_list, ctrl_list)
 				interrupt_event_handler(ctrl);
 	}
 	dbg("event_thread signals exit\n");
@@ -767,27 +664,12 @@
 
 					switch (p_slot->state) {
 					case BLINKINGOFF_STATE:
-						/* Wait for exclusive access to hardware */
-						down(&ctrl->crit_sect);
-
 						p_slot->hpc_ops->green_led_on(p_slot);
-
 						p_slot->hpc_ops->set_attention_status(p_slot, 0);
-
-						/* Done with exclusive hardware access */
-						up(&ctrl->crit_sect);
 						break;
 					case BLINKINGON_STATE:
-						/* Wait for exclusive access to hardware */
-						down(&ctrl->crit_sect);
-
 						p_slot->hpc_ops->green_led_off(p_slot);
-
 						p_slot->hpc_ops->set_attention_status(p_slot, 0);
-
-						/* Done with exclusive hardware access */
-						up(&ctrl->crit_sect);
-
 						break;
 					default:
 						warn("Not a valid state\n");
@@ -812,17 +694,10 @@
 						info(msg_button_on, p_slot->number);
 					}
 
-					/* Wait for exclusive access to hardware */
-					down(&ctrl->crit_sect);
-
 					/* blink green LED and turn off amber */
 					p_slot->hpc_ops->green_led_blink(p_slot);
-					
 					p_slot->hpc_ops->set_attention_status(p_slot, 0);
 
-					/* Done with exclusive hardware access */
-					up(&ctrl->crit_sect);
-
 					init_timer(&p_slot->task_event);
 					p_slot->task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
 					p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
@@ -833,15 +708,8 @@
 				} else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
 					/***********POWER FAULT********************/
 					dbg("%s: power fault\n", __FUNCTION__);
-					/* Wait for exclusive access to hardware */
-					down(&ctrl->crit_sect);
-
 					p_slot->hpc_ops->set_attention_status(p_slot, 1);
-					
 					p_slot->hpc_ops->green_led_off(p_slot);
-
-					/* Done with exclusive hardware access */
-					up(&ctrl->crit_sect);
 				} else {
 					/* refresh notification */
 					if (p_slot)
@@ -862,29 +730,25 @@
 int shpchp_enable_slot (struct slot *p_slot)
 {
 	u8 getstatus = 0;
-	int rc;
+	int rc, retval = -ENODEV;
 
 	/* Check to see if (latch closed, card present, power off) */
-	down(&p_slot->ctrl->crit_sect);
+	mutex_lock(&p_slot->ctrl->crit_sect);
 	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
 	if (rc || !getstatus) {
 		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
-		up(&p_slot->ctrl->crit_sect);
-		return -ENODEV;
+		goto out;
 	}
 	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 	if (rc || getstatus) {
 		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
-		up(&p_slot->ctrl->crit_sect);
-		return -ENODEV;
+		goto out;
 	}
 	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
 	if (rc || getstatus) {
 		info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
-		up(&p_slot->ctrl->crit_sect);
-		return -ENODEV;
+		goto out;
 	}
-	up(&p_slot->ctrl->crit_sect);
 
 	p_slot->is_a_board = 1;
 
@@ -899,56 +763,56 @@
 	     && p_slot->ctrl->num_slots == 1) {
 		/* handle amd pogo errata; this must be done before enable  */
 		amd_pogo_errata_save_misc_reg(p_slot);
-		rc = board_added(p_slot);
+		retval = board_added(p_slot);
 		/* handle amd pogo errata; this must be done after enable  */
 		amd_pogo_errata_restore_misc_reg(p_slot);
 	} else
-		rc = board_added(p_slot);
+		retval = board_added(p_slot);
 
-	if (rc) {
+	if (retval) {
 		p_slot->hpc_ops->get_adapter_status(p_slot,
 				&(p_slot->presence_save));
 		p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 	}
 
 	update_slot_info(p_slot);
-	return rc;
+ out:
+	mutex_unlock(&p_slot->ctrl->crit_sect);
+	return retval;
 }
 
 
 int shpchp_disable_slot (struct slot *p_slot)
 {
 	u8 getstatus = 0;
-	int ret = 0;
+	int rc, retval = -ENODEV;
 
 	if (!p_slot->ctrl)
 		return -ENODEV;
 
 	/* Check to see if (latch closed, card present, power on) */
-	down(&p_slot->ctrl->crit_sect);
+	mutex_lock(&p_slot->ctrl->crit_sect);
 
-	ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
-	if (ret || !getstatus) {
+	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
+	if (rc || !getstatus) {
 		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
-		up(&p_slot->ctrl->crit_sect);
-		return -ENODEV;
+		goto out;
 	}
-	ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
-	if (ret || getstatus) {
+	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+	if (rc || getstatus) {
 		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
-		up(&p_slot->ctrl->crit_sect);
-		return -ENODEV;
+		goto out;
 	}
-	ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
-	if (ret || !getstatus) {
+	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+	if (rc || !getstatus) {
 		info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
-		up(&p_slot->ctrl->crit_sect);
-		return -ENODEV;
+		goto out;
 	}
-	up(&p_slot->ctrl->crit_sect);
 
-	ret = remove_board(p_slot);
+	retval = remove_board(p_slot);
 	update_slot_info(p_slot);
-	return ret;
+ out:
+	mutex_unlock(&p_slot->ctrl->crit_sect);
+	return retval;
 }
 
diff -urN oldtree/drivers/pci/hotplug/shpchp_hpc.c newtree/drivers/pci/hotplug/shpchp_hpc.c
--- oldtree/drivers/pci/hotplug/shpchp_hpc.c	2006-02-19 11:41:03.551803144 +0000
+++ newtree/drivers/pci/hotplug/shpchp_hpc.c	2006-02-21 15:58:18.654310672 +0000
@@ -231,6 +231,7 @@
 static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs);
 
 static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
+static int hpc_check_cmd_status(struct controller *ctrl);
 
 /* This is the interrupt polling timeout function. */
 static void int_poll_timeout(unsigned long lphp_ctlr)
@@ -303,10 +304,13 @@
 	int i;
 
 	DBG_ENTER_ROUTINE 
-	
+
+	mutex_lock(&slot->ctrl->cmd_lock);
+
 	if (!php_ctlr) {
 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return -1;
+		retval = -EINVAL;
+		goto out;
 	}
 
 	for (i = 0; i < 10; i++) {
@@ -323,7 +327,8 @@
 	if (cmd_status & 0x1) { 
 		/* After 1 sec and and the controller is still busy */
 		err("%s : Controller is still busy after 1 sec.\n", __FUNCTION__);
-		return -1;
+		retval = -EBUSY;
+		goto out;
 	}
 
 	++t_slot;
@@ -340,6 +345,17 @@
 	 * Wait for command completion.
 	 */
 	retval = shpc_wait_cmd(slot->ctrl);
+	if (retval)
+		goto out;
+
+	cmd_status = hpc_check_cmd_status(slot->ctrl);
+	if (cmd_status) {
+		err("%s: Failed to issued command 0x%x (error code = %d)\n",
+		    __FUNCTION__, cmd, cmd_status);
+		retval = -EIO;
+	}
+ out:
+	mutex_unlock(&slot->ctrl->cmd_lock);
 
 	DBG_LEAVE_ROUTINE 
 	return retval;
@@ -1093,14 +1109,8 @@
 		wake_up_interruptible(&ctrl->queue);
 	}
 
-	if ((intr_loc = (intr_loc >> 1)) == 0) {
-		/* Unmask Global Interrupt Mask */
-		temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
-		temp_dword &= 0xfffffffe;
-		writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
-
-		return IRQ_NONE;
-	}
+	if ((intr_loc = (intr_loc >> 1)) == 0)
+		goto out;
 
 	for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { 
 	/* To find out which slot has interrupt pending */
@@ -1130,6 +1140,7 @@
 			dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); 
 		}
 	}
+ out:
 	if (!shpchp_poll_mode) {
 		/* Unmask Global Interrupt Mask */
 		temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
@@ -1343,7 +1354,6 @@
 	.green_led_blink		= hpc_set_green_led_blink,
 	
 	.release_ctlr			= hpc_release_ctlr,
-	.check_cmd_status		= hpc_check_cmd_status,
 };
 
 inline static int shpc_indirect_creg_read(struct controller *ctrl, int index,
@@ -1375,15 +1385,13 @@
 	ctrl->pci_dev = pdev;  /* pci_dev of the P2P bridge */
 
 	spin_lock_init(&list_lock);
-	php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL);
+	php_ctlr = kzalloc(sizeof(*php_ctlr), GFP_KERNEL);
 
 	if (!php_ctlr) {	/* allocate controller state data */
 		err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
 		goto abort;
 	}
 
-	memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s));
-
 	php_ctlr->pci_dev = pdev;	/* save pci_dev in context */
 
 	if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device ==
@@ -1454,7 +1462,9 @@
 	}
 	dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg);
 
-	init_MUTEX(&ctrl->crit_sect);
+	mutex_init(&ctrl->crit_sect);
+	mutex_init(&ctrl->cmd_lock);
+
 	/* Setup wait queue */
 	init_waitqueue_head(&ctrl->queue);
 
diff -urN oldtree/drivers/pci/msi.c newtree/drivers/pci/msi.c
--- oldtree/drivers/pci/msi.c	2006-02-19 11:41:03.553802840 +0000
+++ newtree/drivers/pci/msi.c	2006-02-21 15:58:17.824436832 +0000
@@ -37,7 +37,7 @@
 
 #ifndef CONFIG_X86_IO_APIC
 int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
-u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
+u8 irq_vector[NR_IRQ_VECTORS];
 #endif
 
 static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
@@ -374,6 +374,11 @@
 		printk(KERN_WARNING "PCI: MSI cache init failed\n");
 		return status;
 	}
+
+#ifndef CONFIG_X86_IO_APIC
+	irq_vector[0] = FIRST_DEVICE_VECTOR;
+#endif
+
 	last_alloc_vector = assign_irq_vector(AUTO_ASSIGN);
 	if (last_alloc_vector < 0) {
 		pci_msi_enable = 0;
diff -urN oldtree/drivers/pci/pci.c newtree/drivers/pci/pci.c
--- oldtree/drivers/pci/pci.c	2006-02-19 11:41:03.557802232 +0000
+++ newtree/drivers/pci/pci.c	2006-02-21 15:58:23.262610104 +0000
@@ -19,7 +19,6 @@
 #include <asm/dma.h>	/* isa_dma_bridge_buggy */
 #include "pci.h"
 
-#if 0
 
 /**
  * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
@@ -34,7 +33,7 @@
 	struct list_head *tmp;
 	unsigned char max, n;
 
-	max = bus->number;
+	max = bus->subordinate;
 	list_for_each(tmp, &bus->children) {
 		n = pci_bus_max_busnr(pci_bus_b(tmp));
 		if(n > max)
@@ -42,7 +41,9 @@
 	}
 	return max;
 }
+EXPORT_SYMBOL_GPL(pci_bus_max_busnr);
 
+#if 0
 /**
  * pci_max_busnr - returns maximum PCI bus number
  *
@@ -404,30 +405,39 @@
  * message.
  */
 
-pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
+pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t msg)
 {
+	pci_power_t state = PCI_D3hot;
 	int ret;
 
 	if (!pci_find_capability(dev, PCI_CAP_ID_PM))
 		return PCI_D0;
 
 	if (platform_pci_choose_state) {
-		ret = platform_pci_choose_state(dev, state);
+		ret = platform_pci_choose_state(dev, msg);
 		if (ret >= 0)
-			state.event = ret;
+			msg.state = ret;
 	}
 
-	switch (state.event) {
+	switch (msg.event) {
 	case PM_EVENT_ON:
-		return PCI_D0;
+		state = PCI_D0;
+		break;
 	case PM_EVENT_FREEZE:
 	case PM_EVENT_SUSPEND:
-		return PCI_D3hot;
+		if (msg.state && msg.state <= PCI_D3hot)
+			state = msg.state;
+		break;
 	default:
-		printk("They asked me for state %d\n", state.event);
-		BUG();
+		dev_err(&dev->dev, "PCI: Invalid PM Event [Event %d] [State %u]\n",
+			msg.event, msg.state);
+		WARN_ON(1);
+		state = PCI_D0;
+		break;
 	}
-	return PCI_D0;
+	dev_dbg(&dev->dev, "PCI: Translated Power Message %d/%u -> %u\n",
+		msg.event, msg.state, state);
+	return state;
 }
 
 EXPORT_SYMBOL(pci_choose_state);
diff -urN oldtree/drivers/pci/probe.c newtree/drivers/pci/probe.c
--- oldtree/drivers/pci/probe.c	2006-02-19 11:41:03.559801928 +0000
+++ newtree/drivers/pci/probe.c	2006-02-21 15:58:18.035404760 +0000
@@ -537,6 +537,11 @@
 			pci_fixup_parent_subordinate_busnr(child, max);
 			/* Now we can scan all subordinate buses... */
 			max = pci_scan_child_bus(child);
+			/*
+			 * now fix it up again since we have found
+			 * the real value of max.
+			 */
+			pci_fixup_parent_subordinate_busnr(child, max);
 		} else {
 			/*
 			 * For CardBus bridges, we leave 4 bus numbers
diff -urN oldtree/drivers/pci/quirks.c newtree/drivers/pci/quirks.c
--- oldtree/drivers/pci/quirks.c	2006-02-19 11:41:03.561801624 +0000
+++ newtree/drivers/pci/quirks.c	2006-02-21 15:58:18.698303984 +0000
@@ -1074,6 +1074,42 @@
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_963,		quirk_sis_96x_smbus );
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_LPC,		quirk_sis_96x_smbus );
 
+/*
+ * On ASUS A8V and A8V Deluxe boards, the onboard AC97 audio controller
+ * and MC97 modem controller are disabled when a second PCI soundcard is
+ * present. This patch, tweaking the VT8237 ISA bridge, enables them.
+ * -- bjd
+ */
+static int __initdata asus_hides_ac97 = 0;
+
+static void __init asus_hides_ac97_device(struct pci_dev *dev)
+{
+	if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_ASUSTEK)) {
+		if (dev->device == PCI_DEVICE_ID_VIA_8237)
+				asus_hides_ac97 = 1;
+			}
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_device );
+
+static void __init asus_hides_ac97_lpc(struct pci_dev *dev)
+{
+	u8 val;
+
+	if (likely(!asus_hides_ac97))
+		return;
+
+	pci_read_config_byte(dev, 0x50, &val);
+	if (val & 0xc0) {
+		pci_write_config_byte(dev, 0x50, val & (~0xc0));
+		pci_read_config_byte(dev, 0x50, &val);
+		if (val & 0xc0)
+			printk(KERN_INFO "PCI: onboard AC97/MC97 devices continue to play 'hide and seek'! 0x%x\n", val);
+		else
+			printk(KERN_INFO "PCI: enabled onboard AC97/MC97 devices\n");
+	}
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8237,	asus_hides_ac97_lpc );
+
 #ifdef CONFIG_X86_IO_APIC
 static void __init quirk_alder_ioapic(struct pci_dev *pdev)
 {
@@ -1242,6 +1278,33 @@
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_PXHV,	quirk_pcie_pxh);
 
 
+/*
+ * Fixup the cardbus bridges on the IBM Dock II docking station
+ */
+static void __devinit quirk_ibm_dock2_cardbus(struct pci_dev *dev)
+{
+	u32 val;
+
+	/*
+	 * tie the 2 interrupt pins to INTA, and configure the
+	 * multifunction routing register to handle this.
+	 */
+	if ((dev->subsystem_vendor == PCI_VENDOR_ID_IBM) &&
+		(dev->subsystem_device == 0x0148)) {
+		printk(KERN_INFO "PCI: Found IBM Dock II Cardbus Bridge "
+			"applying quirk\n");
+		pci_read_config_dword(dev, 0x8c, &val);
+		val = ((val & 0xffffff00) | 0x1002);
+		pci_write_config_dword(dev, 0x8c, val);
+		pci_read_config_dword(dev, 0x80, &val);
+		val = ((val & 0x00ffff00) | 0x2864c077);
+		pci_write_config_dword(dev, 0x80, val);
+	}
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1420,
+				quirk_ibm_dock2_cardbus);
+
 static void __devinit quirk_netmos(struct pci_dev *dev)
 {
 	unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4;
diff -urN oldtree/drivers/pcmcia/omap_cf.c newtree/drivers/pcmcia/omap_cf.c
--- oldtree/drivers/pcmcia/omap_cf.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/pcmcia/omap_cf.c	2006-02-21 15:58:12.500246232 +0000
@@ -218,7 +218,7 @@
 
 	/* either CFLASH.IREQ (INT_1610_CF) or some GPIO */
 	irq = platform_get_irq(pdev, 0);
-	if (!irq)
+	if (irq < 0)
 		return -EINVAL;
 
 	cf = kcalloc(1, sizeof *cf, GFP_KERNEL);
diff -urN oldtree/drivers/pnp/isapnp/core.c newtree/drivers/pnp/isapnp/core.c
--- oldtree/drivers/pnp/isapnp/core.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/pnp/isapnp/core.c	2006-02-21 15:58:24.249460080 +0000
@@ -42,6 +42,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/isapnp.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 
 #if 0
@@ -92,7 +93,7 @@
 #define _LTAG_FIXEDMEM32RANGE	0x86
 
 static unsigned char isapnp_checksum_value;
-static DECLARE_MUTEX(isapnp_cfg_mutex);
+static DEFINE_MUTEX(isapnp_cfg_mutex);
 static int isapnp_detected;
 static int isapnp_csn_count;
 
@@ -901,7 +902,7 @@
 {
 	if (csn < 1 || csn > isapnp_csn_count || logdev > 10)
 		return -EINVAL;
-	down(&isapnp_cfg_mutex);
+	mutex_lock(&isapnp_cfg_mutex);
 	isapnp_wait();
 	isapnp_key();
 	isapnp_wake(csn);
@@ -927,7 +928,7 @@
 int isapnp_cfg_end(void)
 {
 	isapnp_wait();
-	up(&isapnp_cfg_mutex);
+	mutex_unlock(&isapnp_cfg_mutex);
 	return 0;
 }
 
diff -urN oldtree/drivers/s390/block/dasd_devmap.c newtree/drivers/s390/block/dasd_devmap.c
--- oldtree/drivers/s390/block/dasd_devmap.c	2006-02-19 11:41:03.602795392 +0000
+++ newtree/drivers/s390/block/dasd_devmap.c	2006-02-21 15:58:36.370617384 +0000
@@ -368,7 +368,7 @@
 	if (!new)
 		return ERR_PTR(-ENOMEM);
 	spin_lock(&dasd_devmap_lock);
-	devmap = 0;
+	devmap = NULL;
 	hash = dasd_hash_busid(bus_id);
 	list_for_each_entry(tmp, &dasd_hashlists[hash], list)
 		if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) {
@@ -380,10 +380,10 @@
 		new->devindex = dasd_max_devindex++;
 		strncpy(new->bus_id, bus_id, BUS_ID_SIZE);
 		new->features = features;
-		new->device = 0;
+		new->device = NULL;
 		list_add(&new->list, &dasd_hashlists[hash]);
 		devmap = new;
-		new = 0;
+		new = NULL;
 	}
 	spin_unlock(&dasd_devmap_lock);
 	kfree(new);
@@ -454,7 +454,7 @@
 	int i;
 
 	spin_lock(&dasd_devmap_lock);
-	devmap = 0;
+	devmap = NULL;
 	for (i = 0; (i < 256) && !devmap; i++)
 		list_for_each_entry(tmp, &dasd_hashlists[i], list)
 			if (tmp->devindex == devindex) {
diff -urN oldtree/drivers/s390/block/dasd_eckd.c newtree/drivers/s390/block/dasd_eckd.c
--- oldtree/drivers/s390/block/dasd_eckd.c	2006-02-19 11:41:03.604795088 +0000
+++ newtree/drivers/s390/block/dasd_eckd.c	2006-02-21 15:58:36.372617080 +0000
@@ -65,16 +65,16 @@
 /* The ccw bus type uses this table to find devices that it sends to
  * dasd_eckd_probe */
 static struct ccw_device_id dasd_eckd_ids[] = {
-	{ CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3390, 0), driver_info: 0x1},
-	{ CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3390, 0), driver_info: 0x2},
-	{ CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3390, 0), driver_info: 0x3},
-	{ CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3380, 0), driver_info: 0x4},
-	{ CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3380, 0), driver_info: 0x5},
-	{ CCW_DEVICE_DEVTYPE (0x9343, 0, 0x9345, 0), driver_info: 0x6},
-	{ CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3390, 0), driver_info: 0x7},
-	{ CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3380, 0), driver_info: 0x8},
-	{ CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3390, 0), driver_info: 0x9},
-	{ CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3380, 0), driver_info: 0xa},
+	{ CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3390, 0), .driver_info = 0x1},
+	{ CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3390, 0), .driver_info = 0x2},
+	{ CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3390, 0), .driver_info = 0x3},
+	{ CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3380, 0), .driver_info = 0x4},
+	{ CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3380, 0), .driver_info = 0x5},
+	{ CCW_DEVICE_DEVTYPE (0x9343, 0, 0x9345, 0), .driver_info = 0x6},
+	{ CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3390, 0), .driver_info = 0x7},
+	{ CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3380, 0), .driver_info = 0x8},
+	{ CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3390, 0), .driver_info = 0x9},
+	{ CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3380, 0), .driver_info = 0xa},
 	{ /* end of list */ },
 };
 
diff -urN oldtree/drivers/s390/block/dasd_fba.c newtree/drivers/s390/block/dasd_fba.c
--- oldtree/drivers/s390/block/dasd_fba.c	2006-02-19 11:41:03.607794632 +0000
+++ newtree/drivers/s390/block/dasd_fba.c	2006-02-21 15:58:36.373616928 +0000
@@ -45,8 +45,8 @@
 };
 
 static struct ccw_device_id dasd_fba_ids[] = {
-	{ CCW_DEVICE_DEVTYPE (0x6310, 0, 0x9336, 0), driver_info: 0x1},
-	{ CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3370, 0), driver_info: 0x2},
+	{ CCW_DEVICE_DEVTYPE (0x6310, 0, 0x9336, 0), .driver_info = 0x1},
+	{ CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3370, 0), .driver_info = 0x2},
 	{ /* end of list */ },
 };
 
diff -urN oldtree/drivers/s390/block/dasd_genhd.c newtree/drivers/s390/block/dasd_genhd.c
--- oldtree/drivers/s390/block/dasd_genhd.c	2006-02-19 11:41:03.608794480 +0000
+++ newtree/drivers/s390/block/dasd_genhd.c	2006-02-21 15:58:36.373616928 +0000
@@ -87,9 +87,9 @@
 dasd_gendisk_free(struct dasd_device *device)
 {
 	del_gendisk(device->gdp);
-	device->gdp->queue = 0;
+	device->gdp->queue = NULL;
 	put_disk(device->gdp);
-	device->gdp = 0;
+	device->gdp = NULL;
 }
 
 /*
@@ -141,7 +141,7 @@
 	 * device->bdev to lower the offline open_count limit again.
 	 */
 	bdev = device->bdev;
-	device->bdev = 0;
+	device->bdev = NULL;
 
 	/*
 	 * See fs/partition/check.c:delete_partition
diff -urN oldtree/drivers/s390/block/dasd_ioctl.c newtree/drivers/s390/block/dasd_ioctl.c
--- oldtree/drivers/s390/block/dasd_ioctl.c	2006-02-19 11:41:03.610794176 +0000
+++ newtree/drivers/s390/block/dasd_ioctl.c	2006-02-21 15:58:24.410435608 +0000
@@ -151,9 +151,9 @@
 		return -ENODEV;
 	dasd_enable_device(device);
 	/* Formatting the dasd device can change the capacity. */
-	down(&bdev->bd_sem);
+	mutex_lock(&bdev->bd_mutex);
 	i_size_write(bdev->bd_inode, (loff_t)get_capacity(device->gdp) << 9);
-	up(&bdev->bd_sem);
+	mutex_unlock(&bdev->bd_mutex);
 	return 0;
 }
 
@@ -184,9 +184,9 @@
 	 * Set i_size to zero, since read, write, etc. check against this
 	 * value.
 	 */
-	down(&bdev->bd_sem);
+	mutex_lock(&bdev->bd_mutex);
 	i_size_write(bdev->bd_inode, 0);
-	up(&bdev->bd_sem);
+	mutex_unlock(&bdev->bd_mutex);
 	return 0;
 }
 
diff -urN oldtree/drivers/s390/char/con3215.c newtree/drivers/s390/char/con3215.c
--- oldtree/drivers/s390/char/con3215.c	2006-02-19 11:41:03.612793872 +0000
+++ newtree/drivers/s390/char/con3215.c	2006-02-21 15:58:36.375616624 +0000
@@ -694,7 +694,7 @@
 				       GFP_KERNEL|GFP_DMA);
 	if (raw->buffer == NULL) {
 		spin_lock(&raw3215_device_lock);
-		raw3215[line] = 0;
+		raw3215[line] = NULL;
 		spin_unlock(&raw3215_device_lock);
 		kfree(raw);
 		return -ENOMEM;
diff -urN oldtree/drivers/s390/char/ctrlchar.c newtree/drivers/s390/char/ctrlchar.c
--- oldtree/drivers/s390/char/ctrlchar.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/s390/char/ctrlchar.c	2006-02-21 15:58:36.376616472 +0000
@@ -24,7 +24,7 @@
 	handle_sysrq(ctrlchar_sysrq_key, NULL, (struct tty_struct *) tty);
 }
 
-static DECLARE_WORK(ctrlchar_work, ctrlchar_handle_sysrq, 0);
+static DECLARE_WORK(ctrlchar_work, ctrlchar_handle_sysrq, NULL);
 #endif
 
 
diff -urN oldtree/drivers/s390/char/defkeymap.c newtree/drivers/s390/char/defkeymap.c
--- oldtree/drivers/s390/char/defkeymap.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/s390/char/defkeymap.c	2006-02-21 15:58:36.376616472 +0000
@@ -83,8 +83,8 @@
 };
 
 ushort *key_maps[MAX_NR_KEYMAPS] = {
-	plain_map, shift_map, 0, 0,
-	ctrl_map, shift_ctrl_map,	0
+	plain_map, shift_map, NULL, NULL,
+	ctrl_map, shift_ctrl_map,	NULL
 };
 
 unsigned int keymap_count = 4;
@@ -145,7 +145,7 @@
 	func_buf + 97,
 	func_buf + 103,
 	func_buf + 109,
-	0,
+	NULL,
 };
 
 struct kbdiacr accent_table[MAX_DIACR] = {
diff -urN oldtree/drivers/s390/char/fs3270.c newtree/drivers/s390/char/fs3270.c
--- oldtree/drivers/s390/char/fs3270.c	2006-02-19 11:41:03.613793720 +0000
+++ newtree/drivers/s390/char/fs3270.c	2006-02-21 15:58:36.377616320 +0000
@@ -237,7 +237,7 @@
  * Process reads from fullscreen 3270.
  */
 static ssize_t
-fs3270_read(struct file *filp, char *data, size_t count, loff_t *off)
+fs3270_read(struct file *filp, char __user *data, size_t count, loff_t *off)
 {
 	struct fs3270 *fp;
 	struct raw3270_request *rq;
@@ -282,7 +282,7 @@
  * Process writes to fullscreen 3270.
  */
 static ssize_t
-fs3270_write(struct file *filp, const char *data, size_t count, loff_t *off)
+fs3270_write(struct file *filp, const char __user *data, size_t count, loff_t *off)
 {
 	struct fs3270 *fp;
 	struct raw3270_request *rq;
@@ -339,10 +339,10 @@
 		fp->write_command = arg;
 		break;
 	case TUBGETI:
-		rc = put_user(fp->read_command, (char *) arg);
+		rc = put_user(fp->read_command, (char __user *) arg);
 		break;
 	case TUBGETO:
-		rc = put_user(fp->write_command,(char *) arg);
+		rc = put_user(fp->write_command,(char __user *) arg);
 		break;
 	case TUBGETMOD:
 		iocb.model = fp->view.model;
@@ -351,7 +351,7 @@
 		iocb.pf_cnt = 24;
 		iocb.re_cnt = 20;
 		iocb.map = 0;
-		if (copy_to_user((char *) arg, &iocb,
+		if (copy_to_user((char __user *) arg, &iocb,
 				 sizeof(struct raw3270_iocb)))
 			rc = -EFAULT;
 		break;
@@ -481,7 +481,7 @@
 	struct fs3270 *fp;
 
 	fp = filp->private_data;
-	filp->private_data = 0;
+	filp->private_data = NULL;
 	if (fp) {
 		fp->fs_pid = 0;
 		raw3270_reset(&fp->view);
diff -urN oldtree/drivers/s390/char/keyboard.c newtree/drivers/s390/char/keyboard.c
--- oldtree/drivers/s390/char/keyboard.c	2006-02-19 11:41:03.614793568 +0000
+++ newtree/drivers/s390/char/keyboard.c	2006-02-21 15:58:36.378616168 +0000
@@ -108,7 +108,7 @@
 out_kbd:
 	kfree(kbd);
 out:
-	return 0;
+	return NULL;
 }
 
 void
@@ -309,7 +309,7 @@
 		if (kbd->sysrq) {
 			if (kbd->sysrq == K(KT_LATIN, '-')) {
 				kbd->sysrq = 0;
-				handle_sysrq(value, 0, kbd->tty);
+				handle_sysrq(value, NULL, kbd->tty);
 				return;
 			}
 			if (value == '-') {
@@ -368,7 +368,7 @@
 			/* disallocate map */
 			key_map = kbd->key_maps[tmp.kb_table];
 			if (key_map) {
-			    kbd->key_maps[tmp.kb_table] = 0;
+			    kbd->key_maps[tmp.kb_table] = NULL;
 			    kfree(key_map);
 			}
 			break;
diff -urN oldtree/drivers/s390/char/raw3270.c newtree/drivers/s390/char/raw3270.c
--- oldtree/drivers/s390/char/raw3270.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/s390/char/raw3270.c	2006-02-21 15:58:36.379616016 +0000
@@ -28,6 +28,7 @@
 #include <linux/major.h>
 #include <linux/kdev_t.h>
 #include <linux/device.h>
+#include <linux/mutex.h>
 
 struct class *class3270;
 
@@ -59,7 +60,7 @@
 #define RAW3270_FLAGS_CONSOLE	8	/* Device is the console. */
 
 /* Semaphore to protect global data of raw3270 (devices, views, etc). */
-static DECLARE_MUTEX(raw3270_sem);
+static DEFINE_MUTEX(raw3270_mutex);
 
 /* List of 3270 devices. */
 static struct list_head raw3270_devices = LIST_HEAD_INIT(raw3270_devices);
@@ -719,8 +720,8 @@
 		rc = __raw3270_size_device_vm(rp);
 	else
 		rc = __raw3270_size_device(rp);
-	raw3270_init_view.dev = 0;
-	rp->view = 0;
+	raw3270_init_view.dev = NULL;
+	rp->view = NULL;
 	up(&raw3270_init_sem);
 	if (rc == 0) {	/* Found something. */
 		/* Try to find a model. */
@@ -761,8 +762,8 @@
 	rp->view = &raw3270_init_view;
 	raw3270_init_view.dev = rp;
 	rc = raw3270_start_init(rp, &raw3270_init_view, &raw3270_init_request);
-	raw3270_init_view.dev = 0;
-	rp->view = 0;
+	raw3270_init_view.dev = NULL;
+	rp->view = NULL;
 	up(&raw3270_init_sem);
 	return rc;
 }
@@ -816,7 +817,7 @@
 	 * number for it. Note: there is no device with minor 0,
 	 * see special case for fs3270.c:fs3270_open().
 	 */
-	down(&raw3270_sem);
+	mutex_lock(&raw3270_mutex);
 	/* Keep the list sorted. */
 	minor = RAW3270_FIRSTMINOR;
 	rp->minor = -1;
@@ -833,7 +834,7 @@
 		rp->minor = minor;
 		list_add_tail(&rp->list, &raw3270_devices);
 	}
-	up(&raw3270_sem);
+	mutex_unlock(&raw3270_mutex);
 	/* No free minor number? Then give up. */
 	if (rp->minor == -1)
 		return -EUSERS;
@@ -934,7 +935,7 @@
 	else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
 		rc = -ENODEV;
 	else {
-		oldview = 0;
+		oldview = NULL;
 		if (rp->view) {
 			oldview = rp->view;
 			oldview->fn->deactivate(oldview);
@@ -951,7 +952,7 @@
 						rp->view = nv;
 						if (nv->fn->activate(nv) == 0)
 							break;
-						rp->view = 0;
+						rp->view = NULL;
 					}
 			}
 		}
@@ -975,7 +976,7 @@
 	spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
 	if (rp->view == view) {
 		view->fn->deactivate(view);
-		rp->view = 0;
+		rp->view = NULL;
 		/* Move deactivated view to end of list. */
 		list_del_init(&view->list);
 		list_add_tail(&view->list, &rp->view_list);
@@ -985,7 +986,7 @@
 				rp->view = view;
 				if (view->fn->activate(view) == 0)
 					break;
-				rp->view = 0;
+				rp->view = NULL;
 			}
 		}
 	}
@@ -1004,7 +1005,7 @@
 
 	if (minor <= 0)
 		return -ENODEV;
-	down(&raw3270_sem);
+	mutex_lock(&raw3270_mutex);
 	rc = -ENODEV;
 	list_for_each_entry(rp, &raw3270_devices, list) {
 		if (rp->minor != minor)
@@ -1025,7 +1026,7 @@
 		spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
 		break;
 	}
-	up(&raw3270_sem);
+	mutex_unlock(&raw3270_mutex);
 	return rc;
 }
 
@@ -1039,7 +1040,7 @@
 	struct raw3270_view *view, *tmp;
 	unsigned long flags;
 
-	down(&raw3270_sem);
+	mutex_lock(&raw3270_mutex);
 	view = ERR_PTR(-ENODEV);
 	list_for_each_entry(rp, &raw3270_devices, list) {
 		if (rp->minor != minor)
@@ -1058,7 +1059,7 @@
 		spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
 		break;
 	}
-	up(&raw3270_sem);
+	mutex_unlock(&raw3270_mutex);
 	return view;
 }
 
@@ -1076,7 +1077,7 @@
 	spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
 	if (rp->view == view) {
 		view->fn->deactivate(view);
-		rp->view = 0;
+		rp->view = NULL;
 	}
 	list_del_init(&view->list);
 	if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
@@ -1105,7 +1106,7 @@
 	struct ccw_device *cdev;
 
 	/* Remove from device chain. */
-	down(&raw3270_sem);
+	mutex_lock(&raw3270_mutex);
 	if (rp->clttydev)
 		class_device_destroy(class3270,
 				     MKDEV(IBM_TTY3270_MAJOR, rp->minor));
@@ -1113,13 +1114,13 @@
 		class_device_destroy(class3270,
 				     MKDEV(IBM_FS3270_MAJOR, rp->minor));
 	list_del_init(&rp->list);
-	up(&raw3270_sem);
+	mutex_unlock(&raw3270_mutex);
 
 	/* Disconnect from ccw_device. */
 	cdev = rp->cdev;
-	rp->cdev = 0;
-	cdev->dev.driver_data = 0;
-	cdev->handler = 0;
+	rp->cdev = NULL;
+	cdev->dev.driver_data = NULL;
+	cdev->handler = NULL;
 
 	/* Put ccw_device structure. */
 	put_device(&cdev->dev);
@@ -1144,7 +1145,7 @@
 	return snprintf(buf, PAGE_SIZE, "%i\n",
 			((struct raw3270 *) dev->driver_data)->model);
 }
-static DEVICE_ATTR(model, 0444, raw3270_model_show, 0);
+static DEVICE_ATTR(model, 0444, raw3270_model_show, NULL);
 
 static ssize_t
 raw3270_rows_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -1152,7 +1153,7 @@
 	return snprintf(buf, PAGE_SIZE, "%i\n",
 			((struct raw3270 *) dev->driver_data)->rows);
 }
-static DEVICE_ATTR(rows, 0444, raw3270_rows_show, 0);
+static DEVICE_ATTR(rows, 0444, raw3270_rows_show, NULL);
 
 static ssize_t
 raw3270_columns_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -1160,7 +1161,7 @@
 	return snprintf(buf, PAGE_SIZE, "%i\n",
 			((struct raw3270 *) dev->driver_data)->cols);
 }
-static DEVICE_ATTR(columns, 0444, raw3270_columns_show, 0);
+static DEVICE_ATTR(columns, 0444, raw3270_columns_show, NULL);
 
 static struct attribute * raw3270_attrs[] = {
 	&dev_attr_model.attr,
@@ -1209,13 +1210,13 @@
 	if (!np)
 		return -ENOMEM;
 	np->notifier = notifier;
-	down(&raw3270_sem);
+	mutex_lock(&raw3270_mutex);
 	list_add_tail(&np->list, &raw3270_notifier);
 	list_for_each_entry(rp, &raw3270_devices, list) {
 		get_device(&rp->cdev->dev);
 		notifier(rp->minor, 1);
 	}
-	up(&raw3270_sem);
+	mutex_unlock(&raw3270_mutex);
 	return 0;
 }
 
@@ -1223,14 +1224,14 @@
 {
 	struct raw3270_notifier *np;
 
-	down(&raw3270_sem);
+	mutex_lock(&raw3270_mutex);
 	list_for_each_entry(np, &raw3270_notifier, list)
 		if (np->notifier == notifier) {
 			list_del(&np->list);
 			kfree(np);
 			break;
 		}
-	up(&raw3270_sem);
+	mutex_unlock(&raw3270_mutex);
 }
 
 /*
@@ -1257,10 +1258,10 @@
 		goto failure;
 	raw3270_create_attributes(rp);
 	set_bit(RAW3270_FLAGS_READY, &rp->flags);
-	down(&raw3270_sem);
+	mutex_lock(&raw3270_mutex);
 	list_for_each_entry(np, &raw3270_notifier, list)
 		np->notifier(rp->minor, 1);
-	up(&raw3270_sem);
+	mutex_unlock(&raw3270_mutex);
 	return 0;
 
 failure:
@@ -1296,7 +1297,7 @@
 	spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
 	if (rp->view) {
 		rp->view->fn->deactivate(rp->view);
-		rp->view = 0;
+		rp->view = NULL;
 	}
 	while (!list_empty(&rp->view_list)) {
 		v = list_entry(rp->view_list.next, struct raw3270_view, list);
@@ -1308,10 +1309,10 @@
 	}
 	spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
 
-	down(&raw3270_sem);
+	mutex_lock(&raw3270_mutex);
 	list_for_each_entry(np, &raw3270_notifier, list)
 		np->notifier(rp->minor, 0);
-	up(&raw3270_sem);
+	mutex_unlock(&raw3270_mutex);
 
 	/* Reset 3270 device. */
 	raw3270_reset_device(rp);
@@ -1371,13 +1372,13 @@
 	rc = ccw_driver_register(&raw3270_ccw_driver);
 	if (rc == 0) {
 		/* Create attributes for early (= console) device. */
-		down(&raw3270_sem);
+		mutex_lock(&raw3270_mutex);
 		class3270 = class_create(THIS_MODULE, "3270");
 		list_for_each_entry(rp, &raw3270_devices, list) {
 			get_device(&rp->cdev->dev);
 			raw3270_create_attributes(rp);
 		}
-		up(&raw3270_sem);
+		mutex_unlock(&raw3270_mutex);
 	}
 	return rc;
 }
diff -urN oldtree/drivers/s390/char/raw3270.h newtree/drivers/s390/char/raw3270.h
--- oldtree/drivers/s390/char/raw3270.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/s390/char/raw3270.h	2006-02-21 15:58:36.386614952 +0000
@@ -231,7 +231,7 @@
 		INIT_LIST_HEAD(&cs->update);
 		return cs;
 	}
-	return 0;
+	return NULL;
 }
 
 static inline unsigned long
diff -urN oldtree/drivers/s390/char/tape_34xx.c newtree/drivers/s390/char/tape_34xx.c
--- oldtree/drivers/s390/char/tape_34xx.c	2006-02-19 11:41:03.618792960 +0000
+++ newtree/drivers/s390/char/tape_34xx.c	2006-02-21 15:58:36.393613888 +0000
@@ -1316,8 +1316,8 @@
 };
 
 static struct ccw_device_id tape_34xx_ids[] = {
-	{ CCW_DEVICE_DEVTYPE(0x3480, 0, 0x3480, 0), driver_info: tape_3480},
-	{ CCW_DEVICE_DEVTYPE(0x3490, 0, 0x3490, 0), driver_info: tape_3490},
+	{ CCW_DEVICE_DEVTYPE(0x3480, 0, 0x3480, 0), .driver_info = tape_3480},
+	{ CCW_DEVICE_DEVTYPE(0x3490, 0, 0x3490, 0), .driver_info = tape_3490},
 	{ /* end of list */ }
 };
 
diff -urN oldtree/drivers/s390/char/tty3270.c newtree/drivers/s390/char/tty3270.c
--- oldtree/drivers/s390/char/tty3270.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/s390/char/tty3270.c	2006-02-21 15:58:36.397613280 +0000
@@ -438,7 +438,7 @@
 {
 	struct string *s;
 
-	tp->rcl_walk = 0;
+	tp->rcl_walk = NULL;
 	if (len <= 0)
 		return;
 	if (tp->rcl_nr >= tp->rcl_max) {
@@ -467,12 +467,12 @@
 		else if (!list_empty(&tp->rcl_lines))
 			tp->rcl_walk = tp->rcl_lines.prev;
 		s = tp->rcl_walk ? 
-			list_entry(tp->rcl_walk, struct string, list) : 0;
+			list_entry(tp->rcl_walk, struct string, list) : NULL;
 		if (tp->rcl_walk) {
 			s = list_entry(tp->rcl_walk, struct string, list);
 			tty3270_update_prompt(tp, s->string, s->len);
 		} else
-			tty3270_update_prompt(tp, 0, 0);
+			tty3270_update_prompt(tp, NULL, 0);
 		tty3270_set_timer(tp, 1);
 	}
 	spin_unlock_bh(&tp->view.lock);
@@ -554,7 +554,7 @@
 	 * has to be emitted to the tty and for 0x6d the screen
 	 * needs to be redrawn.
 	 */
-	input = 0;
+	input = NULL;
 	len = 0;
 	if (tp->input->string[0] == 0x7d) {
 		/* Enter: write input to tty. */
@@ -568,7 +568,7 @@
 			tty3270_update_status(tp);
 		}
 		/* Clear input area. */
-		tty3270_update_prompt(tp, 0, 0);
+		tty3270_update_prompt(tp, NULL, 0);
 		tty3270_set_timer(tp, 1);
 	} else if (tp->input->string[0] == 0x6d) {
 		/* Display has been cleared. Redraw. */
@@ -812,8 +812,8 @@
 	tp = (struct tty3270 *) view;
 	tty = tp->tty;
 	if (tty) {
-		tty->driver_data = 0;
-		tp->tty = tp->kbd->tty = 0;
+		tty->driver_data = NULL;
+		tp->tty = tp->kbd->tty = NULL;
 		tty_hangup(tty);
 		raw3270_put_view(&tp->view);
 	}
@@ -952,8 +952,8 @@
 		return;
 	tp = (struct tty3270 *) tty->driver_data;
 	if (tp) {
-		tty->driver_data = 0;
-		tp->tty = tp->kbd->tty = 0;
+		tty->driver_data = NULL;
+		tp->tty = tp->kbd->tty = NULL;
 		raw3270_put_view(&tp->view);
 	}
 }
@@ -1677,7 +1677,7 @@
 		new = L_ECHO(tty) ? TF_INPUT: TF_INPUTN;
 		if (new != tp->inattr) {
 			tp->inattr = new;
-			tty3270_update_prompt(tp, 0, 0);
+			tty3270_update_prompt(tp, NULL, 0);
 			tty3270_set_timer(tp, 1);
 		}
 	}
@@ -1763,7 +1763,7 @@
 tty3270_notifier(int index, int active)
 {
 	if (active)
-		tty_register_device(tty3270_driver, index, 0);
+		tty_register_device(tty3270_driver, index, NULL);
 	else
 		tty_unregister_device(tty3270_driver, index);
 }
@@ -1823,7 +1823,7 @@
 
 	raw3270_unregister_notifier(tty3270_notifier);
 	driver = tty3270_driver;
-	tty3270_driver = 0;
+	tty3270_driver = NULL;
 	tty_unregister_driver(driver);
 	tty3270_del_views();
 }
diff -urN oldtree/drivers/s390/char/vmlogrdr.c newtree/drivers/s390/char/vmlogrdr.c
--- oldtree/drivers/s390/char/vmlogrdr.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/s390/char/vmlogrdr.c	2006-02-21 15:58:36.398613128 +0000
@@ -86,7 +86,7 @@
  */
 static int vmlogrdr_open(struct inode *, struct file *);
 static int vmlogrdr_release(struct inode *, struct file *);
-static ssize_t vmlogrdr_read (struct file *filp, char *data, size_t count,
+static ssize_t vmlogrdr_read (struct file *filp, char __user *data, size_t count,
 			       loff_t * ppos);
 
 static struct file_operations vmlogrdr_fops = {
@@ -515,7 +515,7 @@
 
 
 static ssize_t
-vmlogrdr_read (struct file *filp, char *data, size_t count, loff_t * ppos)
+vmlogrdr_read (struct file *filp, char __user *data, size_t count, loff_t * ppos)
 {
 	int rc;
 	struct vmlogrdr_priv_t * priv = filp->private_data;
diff -urN oldtree/drivers/s390/char/vmwatchdog.c newtree/drivers/s390/char/vmwatchdog.c
--- oldtree/drivers/s390/char/vmwatchdog.c	2006-02-19 11:41:03.621792504 +0000
+++ newtree/drivers/s390/char/vmwatchdog.c	2006-02-21 15:58:36.398613128 +0000
@@ -193,7 +193,7 @@
 		return 0;
 	case WDIOC_GETSTATUS:
 	case WDIOC_GETBOOTSTATUS:
-		return put_user(0, (int *)arg);
+		return put_user(0, (int __user *)arg);
 	case WDIOC_GETTEMP:
 		return -EINVAL;
 	case WDIOC_SETOPTIONS:
diff -urN oldtree/drivers/s390/cio/ccwgroup.c newtree/drivers/s390/cio/ccwgroup.c
--- oldtree/drivers/s390/cio/ccwgroup.c	2006-02-19 11:41:03.623792200 +0000
+++ newtree/drivers/s390/cio/ccwgroup.c	2006-02-21 15:58:36.399612976 +0000
@@ -320,7 +320,7 @@
 	if (!try_module_get(gdrv->owner))
 		return -EINVAL;
 
-	value = simple_strtoul(buf, 0, 0);
+	value = simple_strtoul(buf, NULL, 0);
 	ret = count;
 	if (value == 1)
 		ccwgroup_set_online(gdev);
diff -urN oldtree/drivers/s390/cio/cio.c newtree/drivers/s390/cio/cio.c
--- oldtree/drivers/s390/cio/cio.c	2006-02-19 11:41:03.626791744 +0000
+++ newtree/drivers/s390/cio/cio.c	2006-02-21 15:58:36.406611912 +0000
@@ -798,7 +798,7 @@
 cio_get_console_subchannel(void)
 {
 	if (!console_subchannel_in_use)
-		return 0;
+		return NULL;
 	return &console_subchannel;
 }
 
diff -urN oldtree/drivers/s390/cio/cmf.c newtree/drivers/s390/cio/cmf.c
--- oldtree/drivers/s390/cio/cmf.c	2006-02-19 11:41:03.628791440 +0000
+++ newtree/drivers/s390/cio/cmf.c	2006-02-21 15:58:36.407611760 +0000
@@ -258,7 +258,7 @@
 		spin_lock_irq(cdev->ccwlock);
 		if (s.ret == 1) {
 			s.ret = -ERESTARTSYS;
-			cdev->private->cmb_wait = 0;
+			cdev->private->cmb_wait = NULL;
 			if (cdev->private->state == DEV_STATE_CMFCHANGE)
 				cdev->private->state = DEV_STATE_ONLINE;
 		}
@@ -276,7 +276,7 @@
 	struct set_schib_struct *s;
 
 	s = cdev->private->cmb_wait;
-	cdev->private->cmb_wait = 0;
+	cdev->private->cmb_wait = NULL;
 	if (!s) {
 		WARN_ON(1);
 		return;
@@ -876,7 +876,7 @@
 	&dev_attr_avg_device_disconnect_time.attr,
 	&dev_attr_avg_control_unit_queuing_time.attr,
 	&dev_attr_avg_device_active_only_time.attr,
-	0,
+	NULL,
 };
 
 static struct attribute_group cmf_attr_group = {
@@ -896,7 +896,7 @@
 	&dev_attr_avg_device_active_only_time.attr,
 	&dev_attr_avg_device_busy_time.attr,
 	&dev_attr_avg_initial_command_response_time.attr,
-	0,
+	NULL,
 };
 
 static struct attribute_group cmf_attr_group_ext = {
diff -urN oldtree/drivers/s390/cio/device.c newtree/drivers/s390/cio/device.c
--- oldtree/drivers/s390/cio/device.c	2006-02-19 11:41:03.630791136 +0000
+++ newtree/drivers/s390/cio/device.c	2006-02-21 15:58:36.408611608 +0000
@@ -101,7 +101,7 @@
 	if ((buffer_size - length <= 0) || (i >= num_envp))
 		return -ENOMEM;
 
-	envp[i] = 0;
+	envp[i] = NULL;
 
 	return 0;
 }
@@ -1060,7 +1060,7 @@
 				 __ccwdev_check_busid);
 	put_driver(drv);
 
-	return dev ? to_ccwdev(dev) : 0;
+	return dev ? to_ccwdev(dev) : NULL;
 }
 
 /************************** device driver handling ************************/
@@ -1085,7 +1085,7 @@
 	ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV;
 
 	if (ret) {
-		cdev->drv = 0;
+		cdev->drv = NULL;
 		return ret;
 	}
 
@@ -1116,7 +1116,7 @@
 				 ret, cdev->dev.bus_id);
 	}
 	ccw_device_set_timeout(cdev, 0);
-	cdev->drv = 0;
+	cdev->drv = NULL;
 	return 0;
 }
 
diff -urN oldtree/drivers/s390/cio/qdio.c newtree/drivers/s390/cio/qdio.c
--- oldtree/drivers/s390/cio/qdio.c	2006-02-19 11:41:03.639789768 +0000
+++ newtree/drivers/s390/cio/qdio.c	2006-02-21 15:58:36.415610544 +0000
@@ -2728,7 +2728,7 @@
 	QDIO_DBF_TEXT1(0,trace,dbf_text);
 	QDIO_DBF_TEXT0(0,setup,dbf_text);
 
-	cdev->private->qdio_data = 0;
+	cdev->private->qdio_data = NULL;
 
 	up(&irq_ptr->setting_up_sema);
 
diff -urN oldtree/drivers/s390/crypto/z90hardware.c newtree/drivers/s390/crypto/z90hardware.c
--- oldtree/drivers/s390/crypto/z90hardware.c	2006-02-19 11:41:03.643789160 +0000
+++ newtree/drivers/s390/crypto/z90hardware.c	2006-02-21 15:58:36.417610240 +0000
@@ -2374,7 +2374,7 @@
 	struct CPRB *cprb_p;
 	struct CPRBX *cprbx_p;
 
-	src_p = 0;
+	src_p = NULL;
 	reply_code = 0;
 	service_rc = 0;
 	service_rs = 0;
diff -urN oldtree/drivers/s390/crypto/z90main.c newtree/drivers/s390/crypto/z90main.c
--- oldtree/drivers/s390/crypto/z90main.c	2006-02-19 11:41:03.645788856 +0000
+++ newtree/drivers/s390/crypto/z90main.c	2006-02-21 15:58:36.426608872 +0000
@@ -613,10 +613,10 @@
 	add_timer(&cleanup_timer);
 
 	/* Set up the proc file system */
-	entry = create_proc_entry("driver/z90crypt", 0644, 0);
+	entry = create_proc_entry("driver/z90crypt", 0644, NULL);
 	if (entry) {
 		entry->nlink = 1;
-		entry->data = 0;
+		entry->data = NULL;
 		entry->read_proc = z90crypt_status;
 		entry->write_proc = z90crypt_status_write;
 	}
@@ -660,7 +660,7 @@
 
 	PDEBUG("PID %d\n", PID());
 
-	remove_proc_entry("driver/z90crypt", 0);
+	remove_proc_entry("driver/z90crypt", NULL);
 
 	if ((nresult = misc_deregister(&z90crypt_misc_device)))
 		PRINTK("misc_deregister failed with %d.\n", nresult);
@@ -1913,7 +1913,7 @@
 		}
 
 		tempstat = get_status_PCIXCCcount();
-		if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0)
+		if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
 			ret = -EFAULT;
 		break;
 
@@ -2222,7 +2222,7 @@
 	if (z90crypt.terminating)
 		return REC_FATAL_ERROR;
 
-	caller_p = 0;
+	caller_p = NULL;
 	dev_ptr = z90crypt.device_p[index];
 	rv = 0;
 	do {
@@ -2286,7 +2286,7 @@
 					break;
 				}
 			}
-			caller_p = 0;
+			caller_p = NULL;
 		}
 		if (!caller_p) {
 			PRINTKW("Unable to locate PSMID %02X%02X%02X%02X%02X"
@@ -2406,7 +2406,7 @@
 	struct work_element *pq_p;
 	struct list_head *lptr, *tptr;
 
-	pq_p = 0;
+	pq_p = NULL;
 	list_for_each_safe(lptr, tptr, &pending_list) {
 		pq_p = list_entry(lptr, struct work_element, liste);
 		if (!memcmp(pq_p->caller_id, psmid, sizeof(pq_p->caller_id))) {
@@ -2415,7 +2415,7 @@
 			pq_p->audit[1] |= FP_NOTPENDING;
 			break;
 		}
-		pq_p = 0;
+		pq_p = NULL;
 	}
 
 	if (!pq_p) {
@@ -2519,7 +2519,7 @@
 	 * exiting the loop. If (pendingq_count+requestq_count) == 0 after the
 	 * loop, there is no work remaining on the queues.
 	 */
-	resp_addr = 0;
+	resp_addr = NULL;
 	workavail = 2;
 	buff_len = 0;
 	while (workavail) {
@@ -3085,7 +3085,7 @@
 		disabledFlag = 0;
 		t = -1;
 	}
-	z90crypt.device_p[index] = 0;
+	z90crypt.device_p[index] = NULL;
 
 	/* if the type is valid, remove the device from the type_mask */
 	if ((t != -1) && z90crypt.hdware_info->type_mask[t].st_mask[index]) {
diff -urN oldtree/drivers/s390/net/ctctty.c newtree/drivers/s390/net/ctctty.c
--- oldtree/drivers/s390/net/ctctty.c	2006-02-19 11:41:03.653787640 +0000
+++ newtree/drivers/s390/net/ctctty.c	2006-02-21 15:58:36.431608112 +0000
@@ -1037,7 +1037,7 @@
 		info->lsr |= UART_LSR_TEMT;
 	}
 	tty_ldisc_flush(tty);
-	info->tty = 0;
+	info->tty = NULL;
 	tty->closing = 0;
 	if (info->blocked_open) {
 		msleep_interruptible(500);
@@ -1066,7 +1066,7 @@
 	info->count = 0;
 	info->flags &= ~CTC_ASYNC_NORMAL_ACTIVE;
 	spin_lock_irqsave(&ctc_tty_lock, saveflags);
-	info->tty = 0;
+	info->tty = NULL;
 	spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
 	wake_up_interruptible(&info->open_wait);
 }
@@ -1160,7 +1160,7 @@
 				(unsigned long) info);
 		info->magic = CTC_ASYNC_MAGIC;
 		info->line = i;
-		info->tty = 0;
+		info->tty = NULL;
 		info->count = 0;
 		info->blocked_open = 0;
 		init_waitqueue_head(&info->open_wait);
diff -urN oldtree/drivers/s390/net/iucv.c newtree/drivers/s390/net/iucv.c
--- oldtree/drivers/s390/net/iucv.c	2006-02-19 11:41:03.656787184 +0000
+++ newtree/drivers/s390/net/iucv.c	2006-02-21 15:58:36.434607656 +0000
@@ -695,7 +695,7 @@
 	iucv_debug(1, "entering");
 	if (iucv_cpuid != -1) {
 		smp_call_function_on(iucv_retrieve_buffer_cpuid,
-				     0, 0, 1, iucv_cpuid);
+				     NULL, 0, 1, iucv_cpuid);
 		/* Release the cpu reserved by iucv_declare_buffer. */
 		smp_put_cpu(iucv_cpuid);
 		iucv_cpuid = -1;
diff -urN oldtree/drivers/s390/net/qeth_main.c newtree/drivers/s390/net/qeth_main.c
--- oldtree/drivers/s390/net/qeth_main.c	2006-02-19 11:41:03.666785664 +0000
+++ newtree/drivers/s390/net/qeth_main.c	2006-02-21 15:58:36.442606440 +0000
@@ -4826,7 +4826,7 @@
 qeth_get_setassparms_cmd(struct qeth_card *, enum qeth_ipa_funcs,
 			 __u16, __u16, enum qeth_prot_versions);
 static int
-qeth_arp_query(struct qeth_card *card, char *udata)
+qeth_arp_query(struct qeth_card *card, char __user *udata)
 {
 	struct qeth_cmd_buffer *iob;
 	struct qeth_arp_query_info qinfo = {0, };
@@ -4960,7 +4960,7 @@
  * function to send SNMP commands to OSA-E card
  */
 static int
-qeth_snmp_command(struct qeth_card *card, char *udata)
+qeth_snmp_command(struct qeth_card *card, char __user *udata)
 {
 	struct qeth_cmd_buffer *iob;
 	struct qeth_ipa_cmd *cmd;
@@ -7952,9 +7952,9 @@
 }
 
 static struct ccw_device_id qeth_ids[] = {
-	{CCW_DEVICE(0x1731, 0x01), driver_info:QETH_CARD_TYPE_OSAE},
-	{CCW_DEVICE(0x1731, 0x05), driver_info:QETH_CARD_TYPE_IQD},
-	{CCW_DEVICE(0x1731, 0x06), driver_info:QETH_CARD_TYPE_OSN},
+	{CCW_DEVICE(0x1731, 0x01), .driver_info = QETH_CARD_TYPE_OSAE},
+	{CCW_DEVICE(0x1731, 0x05), .driver_info = QETH_CARD_TYPE_IQD},
+	{CCW_DEVICE(0x1731, 0x06), .driver_info = QETH_CARD_TYPE_OSN},
 	{},
 };
 MODULE_DEVICE_TABLE(ccw, qeth_ids);
@@ -8424,7 +8424,7 @@
 
 static struct notifier_block qeth_ip_notifier = {
 	qeth_ip_event,
-	0
+	NULL
 };
 
 #ifdef CONFIG_QETH_IPV6
@@ -8477,7 +8477,7 @@
 
 static struct notifier_block qeth_ip6_notifier = {
 	qeth_ip6_event,
-	0
+	NULL
 };
 #endif
 
@@ -8504,7 +8504,7 @@
 
 static struct notifier_block qeth_reboot_notifier = {
 	qeth_reboot_event,
-	0
+	NULL
 };
 
 static int
diff -urN oldtree/drivers/s390/net/qeth_sys.c newtree/drivers/s390/net/qeth_sys.c
--- oldtree/drivers/s390/net/qeth_sys.c	2006-02-19 11:41:03.669785208 +0000
+++ newtree/drivers/s390/net/qeth_sys.c	2006-02-21 15:58:36.444606136 +0000
@@ -1756,7 +1756,7 @@
 }
 
 
-static DRIVER_ATTR(group, 0200, 0, qeth_driver_group_store);
+static DRIVER_ATTR(group, 0200, NULL, qeth_driver_group_store);
 
 static ssize_t
 qeth_driver_notifier_register_store(struct device_driver *ddrv, const char *buf,
@@ -1784,7 +1784,7 @@
 	return count;
 }
 
-static DRIVER_ATTR(notifier_register, 0200, 0,
+static DRIVER_ATTR(notifier_register, 0200, NULL,
 		   qeth_driver_notifier_register_store);
 
 int
diff -urN oldtree/drivers/s390/net/smsgiucv.c newtree/drivers/s390/net/smsgiucv.c
--- oldtree/drivers/s390/net/smsgiucv.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/s390/net/smsgiucv.c	2006-02-21 15:58:36.445605984 +0000
@@ -66,7 +66,7 @@
 		return;
 	}
 	rc = iucv_receive(eib->ippathid, eib->ipmsgid, eib->iptrgcls,
-			  msg, len, 0, 0, 0);
+			  msg, len, NULL, NULL, NULL);
 	if (rc == 0) {
 		msg[len] = 0;
 		EBCASC(msg, len);
@@ -122,7 +122,7 @@
 	struct smsg_callback *cb, *tmp;
 
 	spin_lock(&smsg_list_lock);
-	cb = 0;
+	cb = NULL;
 	list_for_each_entry(tmp, &smsg_list, list)
 		if (tmp->callback == callback &&
 		    strcmp(tmp->prefix, prefix) == 0) {
@@ -139,7 +139,7 @@
 {
 	if (smsg_handle > 0) {
 		cpcmd("SET SMSG OFF", NULL, 0, NULL);
-		iucv_sever(smsg_pathid, 0);
+		iucv_sever(smsg_pathid, NULL);
 		iucv_unregister_program(smsg_handle);
 		driver_unregister(&smsg_driver);
 	}
@@ -162,19 +162,19 @@
 		return rc;
 	}
 	smsg_handle = iucv_register_program("SMSGIUCV        ", "*MSG    ",
-					    pgmmask, &smsg_ops, 0);
+					    pgmmask, &smsg_ops, NULL);
 	if (!smsg_handle) {
 		printk(KERN_ERR "SMSGIUCV: failed to register to iucv");
 		driver_unregister(&smsg_driver);
 		return -EIO;	/* better errno ? */
 	}
-	rc = iucv_connect (&smsg_pathid, 1, 0, "*MSG    ", 0, 0, 0, 0,
-			   smsg_handle, 0);
+	rc = iucv_connect (&smsg_pathid, 1, NULL, "*MSG    ", NULL, 0, NULL,
+			   NULL, smsg_handle, NULL);
 	if (rc) {
 		printk(KERN_ERR "SMSGIUCV: failed to connect to *MSG");
 		iucv_unregister_program(smsg_handle);
 		driver_unregister(&smsg_driver);
-		smsg_handle = 0;
+		smsg_handle = NULL;
 		return -EIO;
 	}
 	cpcmd("SET SMSG IUCV", NULL, 0, NULL);
diff -urN oldtree/drivers/s390/scsi/zfcp_aux.c newtree/drivers/s390/scsi/zfcp_aux.c
--- oldtree/drivers/s390/scsi/zfcp_aux.c	2006-02-19 11:41:03.672784752 +0000
+++ newtree/drivers/s390/scsi/zfcp_aux.c	2006-02-21 15:58:30.764469648 +0000
@@ -829,18 +829,6 @@
 	device_unregister(&unit->sysfs_device);
 }
 
-static void *
-zfcp_mempool_alloc(gfp_t gfp_mask, void *size)
-{
-	return kmalloc((size_t) size, gfp_mask);
-}
-
-static void
-zfcp_mempool_free(void *element, void *size)
-{
-	kfree(element);
-}
-
 /*
  * Allocates a combined QTCB/fsf_req buffer for erp actions and fcp/SCSI
  * commands.
@@ -853,51 +841,39 @@
 zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
 {
 	adapter->pool.fsf_req_erp =
-		mempool_create(ZFCP_POOL_FSF_REQ_ERP_NR,
-			       zfcp_mempool_alloc, zfcp_mempool_free, (void *)
-			       sizeof(struct zfcp_fsf_req_pool_element));
-
-	if (NULL == adapter->pool.fsf_req_erp)
+		mempool_create_kmalloc_pool(ZFCP_POOL_FSF_REQ_ERP_NR,
+				sizeof(struct zfcp_fsf_req_pool_element));
+	if (!adapter->pool.fsf_req_erp)
 		return -ENOMEM;
 
 	adapter->pool.fsf_req_scsi =
-		mempool_create(ZFCP_POOL_FSF_REQ_SCSI_NR,
-			       zfcp_mempool_alloc, zfcp_mempool_free, (void *)
-			       sizeof(struct zfcp_fsf_req_pool_element));
-
-	if (NULL == adapter->pool.fsf_req_scsi)
+		mempool_create_kmalloc_pool(ZFCP_POOL_FSF_REQ_SCSI_NR,
+				sizeof(struct zfcp_fsf_req_pool_element));
+	if (!adapter->pool.fsf_req_scsi)
 		return -ENOMEM;
 
 	adapter->pool.fsf_req_abort =
-		mempool_create(ZFCP_POOL_FSF_REQ_ABORT_NR,
-			       zfcp_mempool_alloc, zfcp_mempool_free, (void *)
-			       sizeof(struct zfcp_fsf_req_pool_element));
-
-	if (NULL == adapter->pool.fsf_req_abort)
+		mempool_create_kmalloc_pool(ZFCP_POOL_FSF_REQ_ABORT_NR,
+				sizeof(struct zfcp_fsf_req_pool_element));
+	if (!adapter->pool.fsf_req_abort)
 		return -ENOMEM;
 
 	adapter->pool.fsf_req_status_read =
-		mempool_create(ZFCP_POOL_STATUS_READ_NR,
-			       zfcp_mempool_alloc, zfcp_mempool_free,
-			       (void *) sizeof(struct zfcp_fsf_req));
-
-	if (NULL == adapter->pool.fsf_req_status_read)
+		mempool_create_kmalloc_pool(ZFCP_POOL_STATUS_READ_NR,
+					    sizeof(struct zfcp_fsf_req));
+	if (!adapter->pool.fsf_req_status_read)
 		return -ENOMEM;
 
 	adapter->pool.data_status_read =
-		mempool_create(ZFCP_POOL_STATUS_READ_NR,
-			       zfcp_mempool_alloc, zfcp_mempool_free,
-			       (void *) sizeof(struct fsf_status_read_buffer));
-
-	if (NULL == adapter->pool.data_status_read)
+		mempool_create_kmalloc_pool(ZFCP_POOL_STATUS_READ_NR,
+					sizeof(struct fsf_status_read_buffer));
+	if (!adapter->pool.data_status_read)
 		return -ENOMEM;
 
 	adapter->pool.data_gid_pn =
-		mempool_create(ZFCP_POOL_DATA_GID_PN_NR,
-			       zfcp_mempool_alloc, zfcp_mempool_free, (void *)
-			       sizeof(struct zfcp_gid_pn_data));
-
-	if (NULL == adapter->pool.data_gid_pn)
+		mempool_create_kmalloc_pool(ZFCP_POOL_DATA_GID_PN_NR,
+					    sizeof(struct zfcp_gid_pn_data));
+	if (!adapter->pool.data_gid_pn)
 		return -ENOMEM;
 
 	return 0;
diff -urN oldtree/drivers/s390/scsi/zfcp_erp.c newtree/drivers/s390/scsi/zfcp_erp.c
--- oldtree/drivers/s390/scsi/zfcp_erp.c	2006-02-19 11:41:03.676784144 +0000
+++ newtree/drivers/s390/scsi/zfcp_erp.c	2006-02-21 15:58:36.457604160 +0000
@@ -2124,7 +2124,7 @@
 		sbale = &(adapter->response_queue.buffer[i]->element[0]);
 		sbale->length = 0;
 		sbale->flags = SBAL_FLAGS_LAST_ENTRY;
-		sbale->addr = 0;
+		sbale->addr = NULL;
 	}
 
 	ZFCP_LOG_TRACE("calling do_QDIO on adapter %s (flags=0x%x, "
diff -urN oldtree/drivers/s390/scsi/zfcp_fsf.c newtree/drivers/s390/scsi/zfcp_fsf.c
--- oldtree/drivers/s390/scsi/zfcp_fsf.c	2006-02-19 11:41:03.679783688 +0000
+++ newtree/drivers/s390/scsi/zfcp_fsf.c	2006-02-21 15:58:36.462603400 +0000
@@ -2232,7 +2232,7 @@
 	/* setup new FSF request */
 	retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
 				     erp_action ? ZFCP_REQ_AUTO_CLEANUP : 0,
-				     0, &lock_flags, &fsf_req);
+				     NULL, &lock_flags, &fsf_req);
 	if (retval < 0) {
 		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
                               "exchange port data request for"
diff -urN oldtree/drivers/s390/scsi/zfcp_scsi.c newtree/drivers/s390/scsi/zfcp_scsi.c
--- oldtree/drivers/s390/scsi/zfcp_scsi.c	2006-02-19 11:41:03.684782928 +0000
+++ newtree/drivers/s390/scsi/zfcp_scsi.c	2006-02-21 15:58:36.463603248 +0000
@@ -54,30 +54,30 @@
 
 struct zfcp_data zfcp_data = {
 	.scsi_host_template = {
-	      name:	               ZFCP_NAME,
-	      proc_name:               "zfcp",
-	      proc_info:               NULL,
-	      detect:	               NULL,
-	      slave_alloc:             zfcp_scsi_slave_alloc,
-	      slave_configure:         zfcp_scsi_slave_configure,
-	      slave_destroy:           zfcp_scsi_slave_destroy,
-	      queuecommand:            zfcp_scsi_queuecommand,
-	      eh_abort_handler:        zfcp_scsi_eh_abort_handler,
-	      eh_device_reset_handler: zfcp_scsi_eh_device_reset_handler,
-	      eh_bus_reset_handler:    zfcp_scsi_eh_bus_reset_handler,
-	      eh_host_reset_handler:   zfcp_scsi_eh_host_reset_handler,
+	      .name =	               ZFCP_NAME,
+	      .proc_name =             "zfcp",
+	      .proc_info =             NULL,
+	      .detect =	               NULL,
+	      .slave_alloc =           zfcp_scsi_slave_alloc,
+	      .slave_configure =       zfcp_scsi_slave_configure,
+	      .slave_destroy =         zfcp_scsi_slave_destroy,
+	      .queuecommand =          zfcp_scsi_queuecommand,
+	      .eh_abort_handler =      zfcp_scsi_eh_abort_handler,
+	      .eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler,
+	      .eh_bus_reset_handler =  zfcp_scsi_eh_bus_reset_handler,
+	      .eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler,
 			               /* FIXME(openfcp): Tune */
-	      can_queue:               4096,
-	      this_id:	               0,
+	      .can_queue =             4096,
+	      .this_id =               0,
 	      /*
 	       * FIXME:
 	       * one less? can zfcp_create_sbale cope with it?
 	       */
-	      sg_tablesize:            ZFCP_MAX_SBALES_PER_REQ,
-	      cmd_per_lun:             1,
-	      unchecked_isa_dma:       0,
-	      use_clustering:          1,
-	      sdev_attrs:              zfcp_sysfs_sdev_attrs,
+	      .sg_tablesize =          ZFCP_MAX_SBALES_PER_REQ,
+	      .cmd_per_lun =           1,
+	      .unchecked_isa_dma =     0,
+	      .use_clustering =        1,
+	      .sdev_attrs =            zfcp_sysfs_sdev_attrs,
 	},
 	.driver_version = ZFCP_VERSION,
 	/* rest initialised with zeros */
diff -urN oldtree/drivers/scsi/53c700.c newtree/drivers/scsi/53c700.c
--- oldtree/drivers/scsi/53c700.c	2006-02-19 11:41:03.694781408 +0000
+++ newtree/drivers/scsi/53c700.c	2006-02-21 15:58:18.762294256 +0000
@@ -238,14 +238,6 @@
 	"MSG IN",
 };
 
-static __u8 NCR_700_SDTR_msg[] = {
-	0x01,			/* Extended message */
-	0x03,			/* Extended message Length */
-	0x01,			/* SDTR Extended message */
-	NCR_700_MIN_PERIOD,
-	NCR_700_MAX_OFFSET
-};
-
 /* This translates the SDTR message offset and period to a value
  * which can be loaded into the SXFER_REG.
  *
@@ -266,7 +258,7 @@
 		return 0;
 
 	if(period < hostdata->min_period) {
-		printk(KERN_WARNING "53c700: Period %dns is less than this chip's minimum, setting to %d\n", period*4, NCR_700_SDTR_msg[3]*4);
+		printk(KERN_WARNING "53c700: Period %dns is less than this chip's minimum, setting to %d\n", period*4, NCR_700_MIN_PERIOD*4);
 		period = hostdata->min_period;
 	}
 	XFERP = (period*4 * hostdata->sync_clock)/1000 - 4;
@@ -1434,11 +1426,9 @@
 
 	if(hostdata->fast &&
 	   NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC)) {
-		memcpy(&hostdata->msgout[count], NCR_700_SDTR_msg,
-		       sizeof(NCR_700_SDTR_msg));
-		hostdata->msgout[count+3] = spi_period(SCp->device->sdev_target);
-		hostdata->msgout[count+4] = spi_offset(SCp->device->sdev_target);
-		count += sizeof(NCR_700_SDTR_msg);
+		count += spi_populate_sync_msg(&hostdata->msgout[count],
+				spi_period(SCp->device->sdev_target),
+				spi_offset(SCp->device->sdev_target));
 		NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
 	}
 
diff -urN oldtree/drivers/scsi/BusLogic.c newtree/drivers/scsi/BusLogic.c
--- oldtree/drivers/scsi/BusLogic.c	2006-02-19 11:41:03.700780496 +0000
+++ newtree/drivers/scsi/BusLogic.c	2006-02-21 15:58:36.058664808 +0000
@@ -41,6 +41,7 @@
 #include <linux/stat.h>
 #include <linux/pci.h>
 #include <linux/spinlock.h>
+#include <linux/jiffies.h>
 #include <scsi/scsicam.h>
 
 #include <asm/dma.h>
@@ -2896,7 +2897,7 @@
 		 */
 		if (HostAdapter->ActiveCommands[TargetID] == 0)
 			HostAdapter->LastSequencePoint[TargetID] = jiffies;
-		else if (jiffies - HostAdapter->LastSequencePoint[TargetID] > 4 * HZ) {
+		else if (time_after(jiffies, HostAdapter->LastSequencePoint[TargetID] + 4 * HZ)) {
 			HostAdapter->LastSequencePoint[TargetID] = jiffies;
 			QueueTag = BusLogic_OrderedQueueTag;
 		}
diff -urN oldtree/drivers/scsi/Kconfig newtree/drivers/scsi/Kconfig
--- oldtree/drivers/scsi/Kconfig	2006-02-19 11:41:03.705779736 +0000
+++ newtree/drivers/scsi/Kconfig	2006-02-21 15:58:20.130086320 +0000
@@ -459,6 +459,31 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called in2000.
 
+config SCSI_ARCMSR
+	tristate "ARECA ARC11X0[PCI-X]/ARC12X0[PCI-EXPRESS] SATA-RAID support"
+	depends on PCI && SCSI
+	help
+	  This driver supports all of ARECA's SATA RAID controller cards.
+	  This is an ARECA-maintained driver by Erich Chen.
+	  If you have any problems, please mail to: < erich@areca.com.tw >
+	  Areca supports Linux RAID config tools.
+
+	  < http://www.areca.com.tw >
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called arcmsr (modprobe arcmsr).
+
+config SCSI_ARCMSR_MSI
+	bool "Use PCI message signal interrupt"
+	depends on PCI_MSI && SCSI_ARCMSR
+	default n
+	help
+	  If you say Y here.  You will enable PCI Message signaled Interrupts
+	  function, but some machines may have problems.  If you get
+	  abort command on driver initialize, you have to answer Y here.
+	  If the IRQ problem even worse,
+	  please report the problem to the maintainer.
+
 source "drivers/scsi/megaraid/Kconfig.megaraid"
 
 config SCSI_SATA
@@ -1071,7 +1096,7 @@
 	  memory using PCI DAC cycles.
 
 config SCSI_SYM53C8XX_DEFAULT_TAGS
-	int "default tagged command queue depth"
+	int "Default tagged command queue depth"
 	depends on SCSI_SYM53C8XX_2
 	default "16"
 	help
@@ -1082,7 +1107,7 @@
 	  exceed CONFIG_SCSI_SYM53C8XX_MAX_TAGS.
 
 config SCSI_SYM53C8XX_MAX_TAGS
-	int "maximum number of queued commands"
+	int "Maximum number of queued commands"
 	depends on SCSI_SYM53C8XX_2
 	default "64"
 	help
@@ -1091,13 +1116,14 @@
 	  possible. The driver supports up to 256 queued commands per device.
 	  This value is used as a compiled-in hard limit.
 
-config SCSI_SYM53C8XX_IOMAPPED
-	bool "use port IO"
+config SCSI_SYM53C8XX_MMIO
+	bool "Use memory mapped IO"
 	depends on SCSI_SYM53C8XX_2
+	default y
 	help
-	  If you say Y here, the driver will use port IO to access
-	  the card.  This is significantly slower then using memory
-	  mapped IO.  Most people should answer N.
+	  Memory mapped IO is faster than Port IO.  Most people should
+	  answer Y here, but some machines may have problems.  If you have
+	  to answer N here, please report the problem to the maintainer.
 
 config SCSI_IPR
 	tristate "IBM Power Linux RAID adapter support"
diff -urN oldtree/drivers/scsi/Makefile newtree/drivers/scsi/Makefile
--- oldtree/drivers/scsi/Makefile	2006-02-19 11:41:03.705779736 +0000
+++ newtree/drivers/scsi/Makefile	2006-02-21 15:58:20.130086320 +0000
@@ -58,6 +58,7 @@
 obj-$(CONFIG_SCSI_BUSLOGIC)	+= BusLogic.o
 obj-$(CONFIG_SCSI_DPT_I2O)	+= dpt_i2o.o
 obj-$(CONFIG_SCSI_U14_34F)	+= u14-34f.o
+obj-$(CONFIG_SCSI_ARCMSR)	+= arcmsr/
 obj-$(CONFIG_SCSI_ULTRASTOR)	+= ultrastor.o
 obj-$(CONFIG_SCSI_AHA152X)	+= aha152x.o
 obj-$(CONFIG_SCSI_AHA1542)	+= aha1542.o
diff -urN oldtree/drivers/scsi/aacraid/aachba.c newtree/drivers/scsi/aacraid/aachba.c
--- oldtree/drivers/scsi/aacraid/aachba.c	2006-02-19 11:41:03.712778672 +0000
+++ newtree/drivers/scsi/aacraid/aachba.c	2006-02-21 15:58:20.110089360 +0000
@@ -1597,13 +1597,13 @@
 		cp[11] = 0;
 		cp[12] = 0;
 		aac_internal_transfer(scsicmd, cp, 0,
-		  min((unsigned int)scsicmd->cmnd[13], sizeof(cp)));
+		  min((size_t)scsicmd->cmnd[13], sizeof(cp)));
 		if (sizeof(cp) < scsicmd->cmnd[13]) {
 			unsigned int len, offset = sizeof(cp);
 
 			memset(cp, 0, offset);
 			do {
-				len = min(scsicmd->cmnd[13]-offset, sizeof(cp));
+				len = min((size_t)(scsicmd->cmnd[13]-offset), sizeof(cp));
 				aac_internal_transfer(scsicmd, cp, offset, len);
 			} while ((offset += len) < scsicmd->cmnd[13]);
 		}
diff -urN oldtree/drivers/scsi/aacraid/aacraid.h newtree/drivers/scsi/aacraid/aacraid.h
--- oldtree/drivers/scsi/aacraid/aacraid.h	2006-02-19 11:41:03.713778520 +0000
+++ newtree/drivers/scsi/aacraid/aacraid.h	2006-02-21 15:58:18.767293496 +0000
@@ -997,7 +997,7 @@
 	int			maximum_num_physicals;
 	int			maximum_num_channels;
 	struct fsa_dev_info	*fsa_dev;
-	pid_t			thread_pid;
+	struct task_struct	*thread;
 	int			cardtype;
 	
 	/*
@@ -1017,7 +1017,6 @@
 	 *	AIF thread states
 	 */
 	u32			aif_thread;
-	struct completion	aif_completion;
 	struct aac_adapter_info adapter_info;
 	struct aac_supplement_adapter_info supplement_adapter_info;
 	/* These are in adapter info but they are in the io flow so
@@ -1797,7 +1796,7 @@
 unsigned int aac_response_normal(struct aac_queue * q);
 unsigned int aac_command_normal(struct aac_queue * q);
 unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index);
-int aac_command_thread(struct aac_dev * dev);
+int aac_command_thread(void *data);
 int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx);
 int aac_fib_adapter_complete(struct fib * fibptr, unsigned short size);
 struct aac_driver_ident* aac_get_driver_ident(int devtype);
diff -urN oldtree/drivers/scsi/aacraid/comminit.c newtree/drivers/scsi/aacraid/comminit.c
--- oldtree/drivers/scsi/aacraid/comminit.c	2006-02-19 11:41:03.714778368 +0000
+++ newtree/drivers/scsi/aacraid/comminit.c	2006-02-21 15:58:18.779291672 +0000
@@ -433,7 +433,6 @@
 	}
 		
 	INIT_LIST_HEAD(&dev->fib_list);
-	init_completion(&dev->aif_completion);
 
 	return dev;
 }
diff -urN oldtree/drivers/scsi/aacraid/commsup.c newtree/drivers/scsi/aacraid/commsup.c
--- oldtree/drivers/scsi/aacraid/commsup.c	2006-02-19 11:41:03.715778216 +0000
+++ newtree/drivers/scsi/aacraid/commsup.c	2006-02-21 15:58:18.780291520 +0000
@@ -39,6 +39,7 @@
 #include <linux/completion.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
+#include <linux/kthread.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
 #include <asm/semaphore.h>
@@ -1045,8 +1046,9 @@
  *	more FIBs.
  */
  
-int aac_command_thread(struct aac_dev * dev)
+int aac_command_thread(void *data)
 {
+	struct aac_dev *dev = data;
 	struct hw_fib *hw_fib, *hw_newfib;
 	struct fib *fib, *newfib;
 	struct aac_fib_context *fibctx;
@@ -1058,12 +1060,7 @@
 	 */
 	if (dev->aif_thread)
 		return -EINVAL;
-	/*
-	 *	Set up the name that will appear in 'ps'
-	 *	stored in  task_struct.comm[16].
-	 */
-	daemonize("aacraid");
-	allow_signal(SIGKILL);
+
 	/*
 	 *	Let the DPC know it has a place to send the AIF's to.
 	 */
@@ -1266,13 +1263,12 @@
 		spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags);
 		schedule();
 
-		if(signal_pending(current))
+		if (kthread_should_stop())
 			break;
 		set_current_state(TASK_INTERRUPTIBLE);
 	}
 	if (dev->queues)
 		remove_wait_queue(&dev->queues->queue[HostNormCmdQueue].cmdready, &wait);
 	dev->aif_thread = 0;
-	complete_and_exit(&dev->aif_completion, 0);
 	return 0;
 }
diff -urN oldtree/drivers/scsi/aacraid/linit.c newtree/drivers/scsi/aacraid/linit.c
--- oldtree/drivers/scsi/aacraid/linit.c	2006-02-19 11:41:03.717777912 +0000
+++ newtree/drivers/scsi/aacraid/linit.c	2006-02-21 15:58:18.781291368 +0000
@@ -48,6 +48,7 @@
 #include <linux/syscalls.h>
 #include <linux/delay.h>
 #include <linux/smp_lock.h>
+#include <linux/kthread.h>
 #include <asm/semaphore.h>
 
 #include <scsi/scsi.h>
@@ -850,10 +851,10 @@
 	/*
 	 *	Start any kernel threads needed
 	 */
-	aac->thread_pid = kernel_thread((int (*)(void *))aac_command_thread,
-	  aac, 0);
-	if (aac->thread_pid < 0) {
+	aac->thread = kthread_run(aac_command_thread, aac, AAC_DRIVERNAME);
+	if (IS_ERR(aac->thread)) {
 		printk(KERN_ERR "aacraid: Unable to create command thread.\n");
+		error = PTR_ERR(aac->thread);
 		goto out_deinit;
 	}
 
@@ -934,9 +935,7 @@
 	return 0;
 
  out_deinit:
-	kill_proc(aac->thread_pid, SIGKILL, 0);
-	wait_for_completion(&aac->aif_completion);
-
+	kthread_stop(aac->thread);
 	aac_send_shutdown(aac);
 	aac_adapter_disable_int(aac);
 	free_irq(pdev->irq, aac);
@@ -970,8 +969,7 @@
 
 	scsi_remove_host(shost);
 
-	kill_proc(aac->thread_pid, SIGKILL, 0);
-	wait_for_completion(&aac->aif_completion);
+	kthread_stop(aac->thread);
 
 	aac_send_shutdown(aac);
 	aac_adapter_disable_int(aac);
diff -urN oldtree/drivers/scsi/aha152x.c newtree/drivers/scsi/aha152x.c
--- oldtree/drivers/scsi/aha152x.c	2006-02-19 11:41:03.719777608 +0000
+++ newtree/drivers/scsi/aha152x.c	2006-02-21 15:58:18.783291064 +0000
@@ -1260,16 +1260,15 @@
  * Reset the bus
  *
  */
-static int aha152x_bus_reset(Scsi_Cmnd *SCpnt)
+static int aha152x_bus_reset_host(struct Scsi_Host *shpnt)
 {
-	struct Scsi_Host *shpnt = SCpnt->device->host;
 	unsigned long flags;
 
 	DO_LOCK(flags);
 
 #if defined(AHA152X_DEBUG)
 	if(HOSTDATA(shpnt)->debug & debug_eh) {
-		printk(DEBUG_LEAD "aha152x_bus_reset(%p)", CMDINFO(SCpnt), SCpnt);
+		printk(KERN_DEBUG "scsi%d: bus reset", shpnt->host_no);
 		show_queues(shpnt);
 	}
 #endif
@@ -1277,14 +1276,14 @@
 	free_hard_reset_SCs(shpnt, &ISSUE_SC);
 	free_hard_reset_SCs(shpnt, &DISCONNECTED_SC);
 
-	DPRINTK(debug_eh, DEBUG_LEAD "resetting bus\n", CMDINFO(SCpnt));
+	DPRINTK(debug_eh, KERN_DEBUG "scsi%d: resetting bus\n", shpnt->host_no);
 
 	SETPORT(SCSISEQ, SCSIRSTO);
 	mdelay(256);
 	SETPORT(SCSISEQ, 0);
 	mdelay(DELAY);
 
-	DPRINTK(debug_eh, DEBUG_LEAD "bus resetted\n", CMDINFO(SCpnt));
+	DPRINTK(debug_eh, KERN_DEBUG "scsi%d: bus resetted\n", shpnt->host_no);
 
 	setup_expected_interrupts(shpnt);
 	if(HOSTDATA(shpnt)->commands==0)
@@ -1295,6 +1294,14 @@
 	return SUCCESS;
 }
 
+/*
+ * Reset the bus
+ *
+ */
+static int aha152x_bus_reset(Scsi_Cmnd *SCpnt)
+{
+	return aha152x_bus_reset_host(SCpnt->device->host);
+}
 
 /*
  *  Restore default values to the AIC-6260 registers and reset the fifos
@@ -1337,23 +1344,28 @@
  * Reset the host (bus and controller)
  *
  */
-int aha152x_host_reset(Scsi_Cmnd * SCpnt)
+int aha152x_host_reset_host(struct Scsi_Host *shpnt)
 {
-#if defined(AHA152X_DEBUG)
-	struct Scsi_Host *shpnt = SCpnt->device->host;
-#endif
+	DPRINTK(debug_eh, KERN_DEBUG "scsi%d: host reset\n", shpnt->host_no);
 
-	DPRINTK(debug_eh, DEBUG_LEAD "aha152x_host_reset(%p)\n", CMDINFO(SCpnt), SCpnt);
+	aha152x_bus_reset_host(shpnt);
 
-	aha152x_bus_reset(SCpnt);
-
-	DPRINTK(debug_eh, DEBUG_LEAD "resetting ports\n", CMDINFO(SCpnt));
-	reset_ports(SCpnt->device->host);
+	DPRINTK(debug_eh, KERN_DEBUG "scsi%d: resetting ports\n", shpnt->host_no);
+	reset_ports(shpnt);
 
 	return SUCCESS;
 }
 
 /*
+ * Reset the host (bus and controller)
+ *
+ */
+static int aha152x_host_reset(Scsi_Cmnd *SCpnt)
+{
+	return aha152x_host_reset_host(SCpnt->device->host);
+}
+
+/*
  * Return the "logical geometry"
  *
  */
@@ -1431,22 +1443,18 @@
 {
 	int i;
 	for (i = 0; i<ARRAY_SIZE(aha152x_host); i++) {
-		struct Scsi_Host *shpnt = aha152x_host[i];
-		if (shpnt && HOSTDATA(shpnt)->service) {
-			HOSTDATA(shpnt)->service=0;
-			is_complete(shpnt);
-		}
+		is_complete(aha152x_host[i]);
 	}
 }
 
 /*
- *    Interrupts handler
+ * Interrupt handler
  *
  */
-
 static irqreturn_t intr(int irqno, void *dev_id, struct pt_regs *regs)
 {
 	struct Scsi_Host *shpnt = lookup_irq(irqno);
+	unsigned long flags;
 	unsigned char rev, dmacntrl0;
 
 	if (!shpnt) {
@@ -1472,23 +1480,23 @@
 	if ((rev == 0xFF) && (dmacntrl0 == 0xFF))
 		return IRQ_NONE;
 
+	if (TESTLO(DMASTAT, INTSTAT))
+		return IRQ_NONE;
+
 	/* no more interrupts from the controller, while we're busy.
 	   INTEN is restored by the BH handler */
 	CLRBITS(DMACNTRL0, INTEN);
 
-#if 0
-	/* check if there is already something to be
-           serviced; should not happen */
-	if(HOSTDATA(shpnt)->service) {
-		printk(KERN_ERR "aha152x%d: lost interrupt (%d)\n", HOSTNO, HOSTDATA(shpnt)->service);
-	        show_queues(shpnt);
+	DO_LOCK(flags);
+	if (HOSTDATA(shpnt)->service == 0) {
+		HOSTDATA(shpnt)->service=1;
+
+		/* Poke the BH handler */
+		INIT_WORK(&aha152x_tq, (void *) run, NULL);
+		schedule_work(&aha152x_tq);
 	}
-#endif
-	
-	/* Poke the BH handler */
-	HOSTDATA(shpnt)->service++;
-	INIT_WORK(&aha152x_tq, (void *) run, NULL);
-	schedule_work(&aha152x_tq);
+	DO_UNLOCK(flags);
+
 	return IRQ_HANDLED;
 }
 
@@ -1708,12 +1716,7 @@
 		ADDMSGO(BUS_DEVICE_RESET);
 	} else if (SYNCNEG==0 && SYNCHRONOUS) {
     		CURRENT_SC->SCp.phase |= syncneg;
-		ADDMSGO(EXTENDED_MESSAGE);
-		ADDMSGO(3);
-		ADDMSGO(EXTENDED_SDTR);
-		ADDMSGO(50);		/* 200ns */
-		ADDMSGO(8);		/* 8 byte req/ack offset */
-
+		MSGOLEN += spi_populate_sync_msg(&MSGO(MSGOLEN), 50, 8);
 		SYNCNEG=1;		/* negotiation in progress */
 	}
 
@@ -2527,7 +2530,11 @@
 	unsigned long flags;
 	int pending;
 
+	if (!shpnt)
+		return;
+
 	DO_LOCK(flags);
+
 	if(HOSTDATA(shpnt)->in_intr) {
 		DO_UNLOCK(flags);
 		/* aha152x_error never returns.. */
@@ -2535,6 +2542,14 @@
 	}
 	HOSTDATA(shpnt)->in_intr++;
 
+	if (HOSTDATA(shpnt)->service == 0) {
+		DO_UNLOCK(flags);
+		return;
+	}
+
+	HOSTDATA(shpnt)->service = 0;
+
+
 	/*
 	 * loop while there are interrupt conditions pending
 	 *
@@ -3925,7 +3940,8 @@
 {
 	int i;
 
-	for(i=0; i<ARRAY_SIZE(setup); i++) {
+	flush_scheduled_work();
+	for (i=0; i<ARRAY_SIZE(setup); i++) {
 		aha152x_release(aha152x_host[i]);
 		aha152x_host[i]=NULL;
 	}
diff -urN oldtree/drivers/scsi/aha152x.h newtree/drivers/scsi/aha152x.h
--- oldtree/drivers/scsi/aha152x.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/scsi/aha152x.h	2006-02-21 15:58:08.882796168 +0000
@@ -332,6 +332,6 @@
 
 struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *);
 void aha152x_release(struct Scsi_Host *);
-int aha152x_host_reset(Scsi_Cmnd *);
+int aha152x_host_reset_host(struct Scsi_Host *);
 
 #endif /* _AHA152X_H */
diff -urN oldtree/drivers/scsi/aic7xxx/aic79xx.h newtree/drivers/scsi/aic7xxx/aic79xx.h
--- oldtree/drivers/scsi/aic7xxx/aic79xx.h	2006-02-19 11:41:03.722777152 +0000
+++ newtree/drivers/scsi/aic7xxx/aic79xx.h	2006-02-21 15:58:19.278215824 +0000
@@ -974,8 +974,6 @@
 
 int		ahd_write_seeprom(struct ahd_softc *ahd, uint16_t *buf,
 				  u_int start_addr, u_int count);
-int		ahd_wait_seeprom(struct ahd_softc *ahd);
-int		ahd_verify_vpd_cksum(struct vpd_config *vpd);
 int		ahd_verify_cksum(struct seeprom_config *sc);
 int		ahd_acquire_seeprom(struct ahd_softc *ahd);
 void		ahd_release_seeprom(struct ahd_softc *ahd);
@@ -1322,8 +1320,6 @@
 	char			*name;
 	ahd_device_setup_t	*setup;
 };
-extern struct ahd_pci_identity ahd_pci_ident_table [];
-extern const u_int ahd_num_pci_devs;
 
 /***************************** VL/EISA Declarations ***************************/
 struct aic7770_identity {
@@ -1341,15 +1337,6 @@
 /*************************** Function Declarations ****************************/
 /******************************************************************************/
 void			ahd_reset_cmds_pending(struct ahd_softc *ahd);
-u_int			ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl);
-void			ahd_busy_tcl(struct ahd_softc *ahd,
-				     u_int tcl, u_int busyid);
-static __inline void	ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl);
-static __inline void
-ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl)
-{
-	ahd_busy_tcl(ahd, tcl, SCB_LIST_NULL);
-}
 
 /***************************** PCI Front End *********************************/
 struct	ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t);
@@ -1358,7 +1345,6 @@
 int	ahd_pci_test_register_access(struct ahd_softc *);
 
 /************************** SCB and SCB queue management **********************/
-int		ahd_probe_scbs(struct ahd_softc *);
 void		ahd_qinfifo_requeue_tail(struct ahd_softc *ahd,
 					 struct scb *scb);
 int		ahd_match_scb(struct ahd_softc *ahd, struct scb *scb,
@@ -1376,33 +1362,20 @@
 int			 ahd_parse_cfgdata(struct ahd_softc *ahd,
 					   struct seeprom_config *sc);
 void			 ahd_intr_enable(struct ahd_softc *ahd, int enable);
-void			 ahd_update_coalescing_values(struct ahd_softc *ahd,
-						      u_int timer,
-						      u_int maxcmds,
-						      u_int mincmds);
-void			 ahd_enable_coalescing(struct ahd_softc *ahd,
-					       int enable);
 void			 ahd_pause_and_flushwork(struct ahd_softc *ahd);
 int			 ahd_suspend(struct ahd_softc *ahd); 
-int			 ahd_resume(struct ahd_softc *ahd);
 void			 ahd_set_unit(struct ahd_softc *, int);
 void			 ahd_set_name(struct ahd_softc *, char *);
 struct scb		*ahd_get_scb(struct ahd_softc *ahd, u_int col_idx);
 void			 ahd_free_scb(struct ahd_softc *ahd, struct scb *scb);
-void			 ahd_alloc_scbs(struct ahd_softc *ahd);
 void			 ahd_free(struct ahd_softc *ahd);
 int			 ahd_reset(struct ahd_softc *ahd, int reinit);
-void			 ahd_shutdown(void *arg);
 int			 ahd_write_flexport(struct ahd_softc *ahd,
 					    u_int addr, u_int value);
 int			 ahd_read_flexport(struct ahd_softc *ahd, u_int addr,
 					   uint8_t *value);
-int			 ahd_wait_flexport(struct ahd_softc *ahd);
 
 /*************************** Interrupt Services *******************************/
-void			ahd_pci_intr(struct ahd_softc *ahd);
-void			ahd_clear_intstat(struct ahd_softc *ahd);
-void			ahd_flush_qoutfifo(struct ahd_softc *ahd);
 void			ahd_run_qoutfifo(struct ahd_softc *ahd);
 #ifdef AHD_TARGET_MODE
 void			ahd_run_tqinfifo(struct ahd_softc *ahd, int paused);
@@ -1411,7 +1384,6 @@
 void			ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat);
 void			ahd_handle_scsiint(struct ahd_softc *ahd,
 					   u_int intstat);
-void			ahd_clear_critical_section(struct ahd_softc *ahd);
 
 /***************************** Error Recovery *********************************/
 typedef enum {
@@ -1428,23 +1400,9 @@
 					     char channel, int lun, u_int tag,
 					     int stop_on_first, int remove,
 					     int save_state);
-void			ahd_freeze_devq(struct ahd_softc *ahd, struct scb *scb);
 int			ahd_reset_channel(struct ahd_softc *ahd, char channel,
 					  int initiate_reset);
-int			ahd_abort_scbs(struct ahd_softc *ahd, int target,
-				       char channel, int lun, u_int tag,
-				       role_t role, uint32_t status);
-void			ahd_restart(struct ahd_softc *ahd);
-void			ahd_clear_fifo(struct ahd_softc *ahd, u_int fifo);
-void			ahd_handle_scb_status(struct ahd_softc *ahd,
-					      struct scb *scb);
-void			ahd_handle_scsi_status(struct ahd_softc *ahd,
-					       struct scb *scb);
-void			ahd_calc_residual(struct ahd_softc *ahd,
-					  struct scb *scb);
 /*************************** Utility Functions ********************************/
-struct ahd_phase_table_entry*
-			ahd_lookup_phase_entry(int phase);
 void			ahd_compile_devinfo(struct ahd_devinfo *devinfo,
 					    u_int our_id, u_int target,
 					    u_int lun, char channel,
@@ -1452,14 +1410,6 @@
 /************************** Transfer Negotiation ******************************/
 void			ahd_find_syncrate(struct ahd_softc *ahd, u_int *period,
 					  u_int *ppr_options, u_int maxsync);
-void			ahd_validate_offset(struct ahd_softc *ahd,
-					    struct ahd_initiator_tinfo *tinfo,
-					    u_int period, u_int *offset,
-					    int wide, role_t role);
-void			ahd_validate_width(struct ahd_softc *ahd,
-					   struct ahd_initiator_tinfo *tinfo,
-					   u_int *bus_width,
-					   role_t role);
 /*
  * Negotiation types.  These are used to qualify if we should renegotiate
  * even if our goal and current transport parameters are identical.
@@ -1529,10 +1479,8 @@
 #define AHD_SHOW_INT_COALESCING	0x10000
 #define AHD_DEBUG_SEQUENCER	0x20000
 #endif
-void			ahd_print_scb(struct scb *scb);
 void			ahd_print_devinfo(struct ahd_softc *ahd,
 					  struct ahd_devinfo *devinfo);
-void			ahd_dump_sglist(struct scb *scb);
 void			ahd_dump_card_state(struct ahd_softc *ahd);
 int			ahd_print_register(ahd_reg_parse_entry_t *table,
 					   u_int num_entries,
@@ -1541,5 +1489,4 @@
 					   u_int value,
 					   u_int *cur_column,
 					   u_int wrap_point);
-void			ahd_dump_scbs(struct ahd_softc *ahd);
 #endif /* _AIC79XX_H_ */
diff -urN oldtree/drivers/scsi/aic7xxx/aic79xx_core.c newtree/drivers/scsi/aic7xxx/aic79xx_core.c
--- oldtree/drivers/scsi/aic7xxx/aic79xx_core.c	2006-02-19 11:41:03.733775480 +0000
+++ newtree/drivers/scsi/aic7xxx/aic79xx_core.c	2006-02-21 15:58:20.092092096 +0000
@@ -52,7 +52,7 @@
 
 
 /***************************** Lookup Tables **********************************/
-char *ahd_chip_names[] =
+static char *ahd_chip_names[] =
 {
 	"NONE",
 	"aic7901",
@@ -155,7 +155,7 @@
 	AHDMSG_1B,
 	AHDMSG_2B,
 	AHDMSG_EXT
-} ahd_msgtype;
+	} ahd_msgtype;
 static int		ahd_sent_msg(struct ahd_softc *ahd, ahd_msgtype type,
 				     u_int msgval, int full);
 static int		ahd_parse_msg(struct ahd_softc *ahd,
@@ -238,10 +238,33 @@
 					      struct target_cmd *cmd);
 #endif
 
+static int		ahd_abort_scbs(struct ahd_softc *ahd, int target,
+				       char channel, int lun, u_int tag,
+				       role_t role, uint32_t status);
+static void		ahd_alloc_scbs(struct ahd_softc *ahd);
+static void		ahd_busy_tcl(struct ahd_softc *ahd, u_int tcl,
+				     u_int scbid);
+static void		ahd_calc_residual(struct ahd_softc *ahd,
+					  struct scb *scb);
+static void		ahd_clear_critical_section(struct ahd_softc *ahd);
+static void		ahd_clear_intstat(struct ahd_softc *ahd);
+static void		ahd_enable_coalescing(struct ahd_softc *ahd,
+					      int enable);
+static u_int		ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl);
+static void		ahd_freeze_devq(struct ahd_softc *ahd,
+					struct scb *scb);
+static void		ahd_handle_scb_status(struct ahd_softc *ahd,
+					      struct scb *scb);
+static struct ahd_phase_table_entry* ahd_lookup_phase_entry(int phase);
+static void		ahd_shutdown(void *arg);
+static void		ahd_update_coalescing_values(struct ahd_softc *ahd,
+						     u_int timer,
+						     u_int maxcmds,
+						     u_int mincmds);
+static int		ahd_verify_vpd_cksum(struct vpd_config *vpd);
+static int		ahd_wait_seeprom(struct ahd_softc *ahd);
+
 /******************************** Private Inlines *****************************/
-static __inline void	ahd_assert_atn(struct ahd_softc *ahd);
-static __inline int	ahd_currently_packetized(struct ahd_softc *ahd);
-static __inline int	ahd_set_active_fifo(struct ahd_softc *ahd);
 
 static __inline void
 ahd_assert_atn(struct ahd_softc *ahd)
@@ -295,11 +318,44 @@
 	}
 }
 
+static __inline void
+ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl)
+{
+	ahd_busy_tcl(ahd, tcl, SCB_LIST_NULL);
+}
+
+/*
+ * Determine whether the sequencer reported a residual
+ * for this SCB/transaction.
+ */
+static __inline void
+ahd_update_residual(struct ahd_softc *ahd, struct scb *scb)
+{
+	uint32_t sgptr;
+
+	sgptr = ahd_le32toh(scb->hscb->sgptr);
+	if ((sgptr & SG_STATUS_VALID) != 0)
+		ahd_calc_residual(ahd, scb);
+}
+
+static __inline void
+ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb)
+{
+	uint32_t sgptr;
+
+	sgptr = ahd_le32toh(scb->hscb->sgptr);
+	if ((sgptr & SG_STATUS_VALID) != 0)
+		ahd_handle_scb_status(ahd, scb);
+	else
+		ahd_done(ahd, scb);
+}
+
+
 /************************* Sequencer Execution Control ************************/
 /*
  * Restart the sequencer program from address zero
  */
-void
+static void
 ahd_restart(struct ahd_softc *ahd)
 {
 
@@ -343,7 +399,7 @@
 	ahd_unpause(ahd);
 }
 
-void
+static void
 ahd_clear_fifo(struct ahd_softc *ahd, u_int fifo)
 {
 	ahd_mode_state	 saved_modes;
@@ -367,7 +423,7 @@
  * Flush and completed commands that are sitting in the command
  * complete queues down on the chip but have yet to be dma'ed back up.
  */
-void
+static void
 ahd_flush_qoutfifo(struct ahd_softc *ahd)
 {
 	struct		scb *scb;
@@ -906,6 +962,51 @@
 	ahd_free(ahd);
 }
 
+#ifdef AHD_DEBUG
+static void
+ahd_dump_sglist(struct scb *scb)
+{
+	int i;
+
+	if (scb->sg_count > 0) {
+		if ((scb->ahd_softc->flags & AHD_64BIT_ADDRESSING) != 0) {
+			struct ahd_dma64_seg *sg_list;
+
+			sg_list = (struct ahd_dma64_seg*)scb->sg_list;
+			for (i = 0; i < scb->sg_count; i++) {
+				uint64_t addr;
+				uint32_t len;
+
+				addr = ahd_le64toh(sg_list[i].addr);
+				len = ahd_le32toh(sg_list[i].len);
+				printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
+				       i,
+				       (uint32_t)((addr >> 32) & 0xFFFFFFFF),
+				       (uint32_t)(addr & 0xFFFFFFFF),
+				       sg_list[i].len & AHD_SG_LEN_MASK,
+				       (sg_list[i].len & AHD_DMA_LAST_SEG)
+				     ? " Last" : "");
+			}
+		} else {
+			struct ahd_dma_seg *sg_list;
+
+			sg_list = (struct ahd_dma_seg*)scb->sg_list;
+			for (i = 0; i < scb->sg_count; i++) {
+				uint32_t len;
+
+				len = ahd_le32toh(sg_list[i].len);
+				printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
+				       i,
+				       (len & AHD_SG_HIGH_ADDR_MASK) >> 24,
+				       ahd_le32toh(sg_list[i].addr),
+				       len & AHD_SG_LEN_MASK,
+				       len & AHD_DMA_LAST_SEG ? " Last" : "");
+			}
+		}
+	}
+}
+#endif  /*  AHD_DEBUG  */
+
 void
 ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
 {
@@ -2542,7 +2643,7 @@
 }
 
 #define AHD_MAX_STEPS 2000
-void
+static void
 ahd_clear_critical_section(struct ahd_softc *ahd)
 {
 	ahd_mode_state	saved_modes;
@@ -2665,7 +2766,7 @@
 /*
  * Clear any pending interrupt status.
  */
-void
+static void
 ahd_clear_intstat(struct ahd_softc *ahd)
 {
 	AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
@@ -2696,6 +2797,8 @@
 #ifdef AHD_DEBUG
 uint32_t ahd_debug = AHD_DEBUG_OPTS;
 #endif
+
+#if 0
 void
 ahd_print_scb(struct scb *scb)
 {
@@ -2720,49 +2823,7 @@
 	       SCB_GET_TAG(scb));
 	ahd_dump_sglist(scb);
 }
-
-void
-ahd_dump_sglist(struct scb *scb)
-{
-	int i;
-
-	if (scb->sg_count > 0) {
-		if ((scb->ahd_softc->flags & AHD_64BIT_ADDRESSING) != 0) {
-			struct ahd_dma64_seg *sg_list;
-
-			sg_list = (struct ahd_dma64_seg*)scb->sg_list;
-			for (i = 0; i < scb->sg_count; i++) {
-				uint64_t addr;
-				uint32_t len;
-
-				addr = ahd_le64toh(sg_list[i].addr);
-				len = ahd_le32toh(sg_list[i].len);
-				printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
-				       i,
-				       (uint32_t)((addr >> 32) & 0xFFFFFFFF),
-				       (uint32_t)(addr & 0xFFFFFFFF),
-				       sg_list[i].len & AHD_SG_LEN_MASK,
-				       (sg_list[i].len & AHD_DMA_LAST_SEG)
-				     ? " Last" : "");
-			}
-		} else {
-			struct ahd_dma_seg *sg_list;
-
-			sg_list = (struct ahd_dma_seg*)scb->sg_list;
-			for (i = 0; i < scb->sg_count; i++) {
-				uint32_t len;
-
-				len = ahd_le32toh(sg_list[i].len);
-				printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
-				       i,
-				       (len & AHD_SG_HIGH_ADDR_MASK) >> 24,
-				       ahd_le32toh(sg_list[i].addr),
-				       len & AHD_SG_LEN_MASK,
-				       len & AHD_DMA_LAST_SEG ? " Last" : "");
-			}
-		}
-	}
-}
+#endif  /*  0  */
 
 /************************* Transfer Negotiation *******************************/
 /*
@@ -2925,7 +2986,7 @@
  * Truncate the given synchronous offset to a value the
  * current adapter type and syncrate are capable of.
  */
-void
+static void
 ahd_validate_offset(struct ahd_softc *ahd,
 		    struct ahd_initiator_tinfo *tinfo,
 		    u_int period, u_int *offset, int wide,
@@ -2956,7 +3017,7 @@
  * Truncate the given transfer width parameter to a value the
  * current adapter type is capable of.
  */
-void
+static void
 ahd_validate_width(struct ahd_softc *ahd, struct ahd_initiator_tinfo *tinfo,
 		   u_int *bus_width, role_t role)
 {
@@ -3483,7 +3544,7 @@
 	       devinfo->target, devinfo->lun);
 }
 
-struct ahd_phase_table_entry*
+static struct ahd_phase_table_entry*
 ahd_lookup_phase_entry(int phase)
 {
 	struct ahd_phase_table_entry *entry;
@@ -3762,11 +3823,8 @@
 {
 	if (offset == 0)
 		period = AHD_ASYNC_XFER_PERIOD;
-	ahd->msgout_buf[ahd->msgout_index++] = MSG_EXTENDED;
-	ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_SDTR_LEN;
-	ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_SDTR;
-	ahd->msgout_buf[ahd->msgout_index++] = period;
-	ahd->msgout_buf[ahd->msgout_index++] = offset;
+	ahd->msgout_index += spi_populate_sync_msg(
+			ahd->msgout_buf + ahd->msgout_index, period, offset);
 	ahd->msgout_len += 5;
 	if (bootverbose) {
 		printf("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n",
@@ -3783,10 +3841,8 @@
 ahd_construct_wdtr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
 		   u_int bus_width)
 {
-	ahd->msgout_buf[ahd->msgout_index++] = MSG_EXTENDED;
-	ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_WDTR_LEN;
-	ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_WDTR;
-	ahd->msgout_buf[ahd->msgout_index++] = bus_width;
+	ahd->msgout_index += spi_populate_width_msg(
+			ahd->msgout_buf + ahd->msgout_index, bus_width);
 	ahd->msgout_len += 4;
 	if (bootverbose) {
 		printf("(%s:%c:%d:%d): Sending WDTR %x\n",
@@ -3813,14 +3869,9 @@
 		ppr_options |= MSG_EXT_PPR_PCOMP_EN;
 	if (offset == 0)
 		period = AHD_ASYNC_XFER_PERIOD;
-	ahd->msgout_buf[ahd->msgout_index++] = MSG_EXTENDED;
-	ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_PPR_LEN;
-	ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_PPR;
-	ahd->msgout_buf[ahd->msgout_index++] = period;
-	ahd->msgout_buf[ahd->msgout_index++] = 0;
-	ahd->msgout_buf[ahd->msgout_index++] = offset;
-	ahd->msgout_buf[ahd->msgout_index++] = bus_width;
-	ahd->msgout_buf[ahd->msgout_index++] = ppr_options;
+	ahd->msgout_index += spi_populate_ppr_msg(
+			ahd->msgout_buf + ahd->msgout_index, period, offset,
+			bus_width, ppr_options);
 	ahd->msgout_len += 8;
 	if (bootverbose) {
 		printf("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, "
@@ -5378,7 +5429,7 @@
 	return;
 }
 
-void
+static void
 ahd_shutdown(void *arg)
 {
 	struct	ahd_softc *ahd;
@@ -5507,7 +5558,7 @@
 /*
  * Determine the number of SCBs available on the controller
  */
-int
+static int
 ahd_probe_scbs(struct ahd_softc *ahd) {
 	int i;
 
@@ -5956,7 +6007,7 @@
 	ahd_platform_scb_free(ahd, scb);
 }
 
-void
+static void
 ahd_alloc_scbs(struct ahd_softc *ahd)
 {
 	struct scb_data *scb_data;
@@ -7009,7 +7060,7 @@
 	ahd_outb(ahd, HCNTRL, hcntrl);
 }
 
-void
+static void
 ahd_update_coalescing_values(struct ahd_softc *ahd, u_int timer, u_int maxcmds,
 			     u_int mincmds)
 {
@@ -7027,7 +7078,7 @@
 	ahd_outb(ahd, INT_COALESCING_MINCMDS, -mincmds);
 }
 
-void
+static void
 ahd_enable_coalescing(struct ahd_softc *ahd, int enable)
 {
 
@@ -7098,6 +7149,7 @@
 	ahd->flags &= ~AHD_ALL_INTERRUPTS;
 }
 
+#if 0
 int
 ahd_suspend(struct ahd_softc *ahd)
 {
@@ -7111,7 +7163,9 @@
 	ahd_shutdown(ahd);
 	return (0);
 }
+#endif  /*  0  */
 
+#if 0
 int
 ahd_resume(struct ahd_softc *ahd)
 {
@@ -7121,6 +7175,7 @@
 	ahd_restart(ahd);
 	return (0);
 }
+#endif  /*  0  */
 
 /************************** Busy Target Table *********************************/
 /*
@@ -7153,7 +7208,7 @@
 /*
  * Return the untagged transaction id for a given target/channel lun.
  */
-u_int
+static u_int
 ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl)
 {
 	u_int scbid;
@@ -7166,7 +7221,7 @@
 	return (scbid);
 }
 
-void
+static void
 ahd_busy_tcl(struct ahd_softc *ahd, u_int tcl, u_int scbid)
 {
 	u_int scb_offset;
@@ -7214,7 +7269,7 @@
 	return match;
 }
 
-void
+static void
 ahd_freeze_devq(struct ahd_softc *ahd, struct scb *scb)
 {
 	int	target;
@@ -7317,7 +7372,7 @@
 	ahd->flags &= ~AHD_UPDATE_PEND_CMDS;
 }
 
-void
+static void
 ahd_done_with_status(struct ahd_softc *ahd, struct scb *scb, uint32_t status)
 {
 	cam_status ostat;
@@ -7718,7 +7773,7 @@
  * been modified from CAM_REQ_INPROG.  This routine assumes that the sequencer
  * is paused before it is called.
  */
-int
+static int
 ahd_abort_scbs(struct ahd_softc *ahd, int target, char channel,
 	       int lun, u_int tag, role_t role, uint32_t status)
 {
@@ -8066,18 +8121,8 @@
 }
 
 /****************************** Status Processing *****************************/
-void
-ahd_handle_scb_status(struct ahd_softc *ahd, struct scb *scb)
-{
-	if (scb->hscb->shared_data.istatus.scsi_status != 0) {
-		ahd_handle_scsi_status(ahd, scb);
-	} else {
-		ahd_calc_residual(ahd, scb);
-		ahd_done(ahd, scb);
-	}
-}
 
-void
+static void
 ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
 {
 	struct	hardware_scb *hscb;
@@ -8285,10 +8330,21 @@
 	}
 }
 
+static void
+ahd_handle_scb_status(struct ahd_softc *ahd, struct scb *scb)
+{
+	if (scb->hscb->shared_data.istatus.scsi_status != 0) {
+		ahd_handle_scsi_status(ahd, scb);
+	} else {
+		ahd_calc_residual(ahd, scb);
+		ahd_done(ahd, scb);
+	}
+}
+
 /*
  * Calculate the residual for a just completed SCB.
  */
-void
+static void
 ahd_calc_residual(struct ahd_softc *ahd, struct scb *scb)
 {
 	struct hardware_scb *hscb;
@@ -9139,6 +9195,7 @@
 		ahd_unpause(ahd);
 }
 
+#if 0
 void
 ahd_dump_scbs(struct ahd_softc *ahd)
 {
@@ -9164,6 +9221,7 @@
 	ahd_set_scbptr(ahd, saved_scb_index);
 	ahd_restore_modes(ahd, saved_modes);
 }
+#endif  /*  0  */
 
 /**************************** Flexport Logic **********************************/
 /*
@@ -9266,7 +9324,7 @@
 /*
  * Wait ~100us for the serial eeprom to satisfy our request.
  */
-int
+static int
 ahd_wait_seeprom(struct ahd_softc *ahd)
 {
 	int cnt;
@@ -9284,7 +9342,7 @@
  * Validate the two checksums in the per_channel
  * vital product data struct.
  */
-int
+static int
 ahd_verify_vpd_cksum(struct vpd_config *vpd)
 {
 	int i;
@@ -9363,6 +9421,24 @@
 	/* Currently a no-op */
 }
 
+/*
+ * Wait at most 2 seconds for flexport arbitration to succeed.
+ */
+static int
+ahd_wait_flexport(struct ahd_softc *ahd)
+{
+	int cnt;
+
+	AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
+	cnt = 1000000 * 2 / 5;
+	while ((ahd_inb(ahd, BRDCTL) & FLXARBACK) == 0 && --cnt)
+		ahd_delay(5);
+
+	if (cnt == 0)
+		return (ETIMEDOUT);
+	return (0);
+}
+
 int
 ahd_write_flexport(struct ahd_softc *ahd, u_int addr, u_int value)
 {
@@ -9404,24 +9480,6 @@
 	return (0);
 }
 
-/*
- * Wait at most 2 seconds for flexport arbitration to succeed.
- */
-int
-ahd_wait_flexport(struct ahd_softc *ahd)
-{
-	int cnt;
-
-	AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
-	cnt = 1000000 * 2 / 5;
-	while ((ahd_inb(ahd, BRDCTL) & FLXARBACK) == 0 && --cnt)
-		ahd_delay(5);
-
-	if (cnt == 0)
-		return (ETIMEDOUT);
-	return (0);
-}
-
 /************************* Target Mode ****************************************/
 #ifdef AHD_TARGET_MODE
 cam_status
diff -urN oldtree/drivers/scsi/aic7xxx/aic79xx_inline.h newtree/drivers/scsi/aic7xxx/aic79xx_inline.h
--- oldtree/drivers/scsi/aic7xxx/aic79xx_inline.h	2006-02-19 11:41:03.734775328 +0000
+++ newtree/drivers/scsi/aic7xxx/aic79xx_inline.h	2006-02-21 15:58:19.286214608 +0000
@@ -418,10 +418,6 @@
 }
 
 /*********************** Miscelaneous Support Functions ***********************/
-static __inline void	ahd_complete_scb(struct ahd_softc *ahd,
-					 struct scb *scb);
-static __inline void	ahd_update_residual(struct ahd_softc *ahd,
-					    struct scb *scb);
 static __inline struct ahd_initiator_tinfo *
 			ahd_fetch_transinfo(struct ahd_softc *ahd,
 					    char channel, u_int our_id,
@@ -467,32 +463,6 @@
 			ahd_get_sense_bufaddr(struct ahd_softc *ahd,
 					      struct scb *scb);
 
-static __inline void
-ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb)
-{
-	uint32_t sgptr;
-
-	sgptr = ahd_le32toh(scb->hscb->sgptr);
-	if ((sgptr & SG_STATUS_VALID) != 0)
-		ahd_handle_scb_status(ahd, scb);
-	else
-		ahd_done(ahd, scb);
-}
-
-/*
- * Determine whether the sequencer reported a residual
- * for this SCB/transaction.
- */
-static __inline void
-ahd_update_residual(struct ahd_softc *ahd, struct scb *scb)
-{
-	uint32_t sgptr;
-
-	sgptr = ahd_le32toh(scb->hscb->sgptr);
-	if ((sgptr & SG_STATUS_VALID) != 0)
-		ahd_calc_residual(ahd, scb);
-}
-
 /*
  * Return pointers to the transfer negotiation information
  * for the specified our_id/remote_id pair.
diff -urN oldtree/drivers/scsi/aic7xxx/aic79xx_osm.c newtree/drivers/scsi/aic7xxx/aic79xx_osm.c
--- oldtree/drivers/scsi/aic7xxx/aic79xx_osm.c	2006-02-19 11:41:03.736775024 +0000
+++ newtree/drivers/scsi/aic7xxx/aic79xx_osm.c	2006-02-21 15:58:19.383199864 +0000
@@ -312,7 +312,7 @@
  * force all outstanding transactions to be serviced prior to a new
  * transaction.
  */
-uint32_t aic79xx_periodic_otag;
+static uint32_t aic79xx_periodic_otag;
 
 /* Some storage boxes are using an LSI chip which has a bug making it
  * impossible to use aic79xx Rev B chip in 320 speeds.  The following
@@ -810,6 +810,7 @@
 	return (0);
 }
 
+#if 0
 /********************* Platform Dependent Functions ***************************/
 /*
  * Compare "left hand" softc with "right hand" softc, returning:
@@ -863,6 +864,7 @@
 	value = rahd->channel - lahd->channel;
 	return (value);
 }
+#endif  /*  0  */
 
 static void
 ahd_linux_setup_iocell_info(u_long index, int instance, int targ, int32_t value)
diff -urN oldtree/drivers/scsi/aic7xxx/aic79xx_osm.h newtree/drivers/scsi/aic7xxx/aic79xx_osm.h
--- oldtree/drivers/scsi/aic7xxx/aic79xx_osm.h	2006-02-19 11:41:03.737774872 +0000
+++ newtree/drivers/scsi/aic7xxx/aic79xx_osm.h	2006-02-21 15:58:19.384199712 +0000
@@ -518,9 +518,6 @@
 	int pos;
 };
 
-void	ahd_format_transinfo(struct info_str *info,
-			     struct ahd_transinfo *tinfo);
-
 /******************************** Locking *************************************/
 static __inline void
 ahd_lockinit(struct ahd_softc *ahd)
@@ -594,8 +591,6 @@
 #define PCIXM_STATUS_MAXCRDS	0x1C00	/* Maximum Cumulative Read Size */
 #define PCIXM_STATUS_RCVDSCEM	0x2000	/* Received a Split Comp w/Error msg */
 
-extern struct pci_driver aic79xx_pci_driver;
-
 typedef enum
 {
 	AHD_POWER_STATE_D0,
@@ -876,7 +871,6 @@
 irqreturn_t
 	ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs);
 void	ahd_platform_flushwork(struct ahd_softc *ahd);
-int	ahd_softc_comp(struct ahd_softc *, struct ahd_softc *);
 void	ahd_done(struct ahd_softc*, struct scb*);
 void	ahd_send_async(struct ahd_softc *, char channel,
 		       u_int target, u_int lun, ac_code, void *);
diff -urN oldtree/drivers/scsi/aic7xxx/aic79xx_osm_pci.c newtree/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
--- oldtree/drivers/scsi/aic7xxx/aic79xx_osm_pci.c	2006-02-19 11:41:03.737774872 +0000
+++ newtree/drivers/scsi/aic7xxx/aic79xx_osm_pci.c	2006-02-21 15:58:19.386199408 +0000
@@ -82,7 +82,7 @@
 
 MODULE_DEVICE_TABLE(pci, ahd_linux_pci_id_table);
 
-struct pci_driver aic79xx_pci_driver = {
+static struct pci_driver aic79xx_pci_driver = {
 	.name		= "aic79xx",
 	.probe		= ahd_linux_pci_dev_probe,
 	.remove		= ahd_linux_pci_dev_remove,
diff -urN oldtree/drivers/scsi/aic7xxx/aic79xx_pci.c newtree/drivers/scsi/aic7xxx/aic79xx_pci.c
--- oldtree/drivers/scsi/aic7xxx/aic79xx_pci.c	2006-02-19 11:41:03.738774720 +0000
+++ newtree/drivers/scsi/aic7xxx/aic79xx_pci.c	2006-02-21 15:58:19.398197584 +0000
@@ -97,7 +97,7 @@
 static ahd_device_setup_t ahd_aic7902_setup;
 static ahd_device_setup_t ahd_aic790X_setup;
 
-struct ahd_pci_identity ahd_pci_ident_table [] =
+static struct ahd_pci_identity ahd_pci_ident_table [] =
 {
 	/* aic7901 based controllers */
 	{
@@ -201,7 +201,7 @@
 	}
 };
 
-const u_int ahd_num_pci_devs = NUM_ELEMENTS(ahd_pci_ident_table);
+static const u_int ahd_num_pci_devs = NUM_ELEMENTS(ahd_pci_ident_table);
 		
 #define	DEVCONFIG		0x40
 #define		PCIXINITPAT	0x0000E000ul
@@ -245,6 +245,7 @@
 static void	ahd_configure_termination(struct ahd_softc *ahd,
 					  u_int adapter_control);
 static void	ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat);
+static void	ahd_pci_intr(struct ahd_softc *ahd);
 
 struct ahd_pci_identity *
 ahd_find_pci_device(ahd_dev_softc_t pci)
@@ -757,7 +758,7 @@
 	"%s: Address or Write Phase Parity Error Detected in %s.\n"
 };
 
-void
+static void
 ahd_pci_intr(struct ahd_softc *ahd)
 {
 	uint8_t		pci_status[8];
diff -urN oldtree/drivers/scsi/aic7xxx/aic79xx_proc.c newtree/drivers/scsi/aic7xxx/aic79xx_proc.c
--- oldtree/drivers/scsi/aic7xxx/aic79xx_proc.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/scsi/aic7xxx/aic79xx_proc.c	2006-02-21 15:58:19.401197128 +0000
@@ -138,7 +138,7 @@
 	return (len);
 }
 
-void
+static void
 ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo)
 {
 	u_int speed;
diff -urN oldtree/drivers/scsi/aic7xxx/aic7xxx.h newtree/drivers/scsi/aic7xxx/aic7xxx.h
--- oldtree/drivers/scsi/aic7xxx/aic7xxx.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/scsi/aic7xxx/aic7xxx.h	2006-02-21 15:58:19.403196824 +0000
@@ -1136,8 +1136,6 @@
 	char			*name;
 	ahc_device_setup_t	*setup;
 };
-extern struct ahc_pci_identity ahc_pci_ident_table[];
-extern const u_int ahc_num_pci_devs;
 
 /***************************** VL/EISA Declarations ***************************/
 struct aic7770_identity {
diff -urN oldtree/drivers/scsi/aic7xxx/aic7xxx_core.c newtree/drivers/scsi/aic7xxx/aic7xxx_core.c
--- oldtree/drivers/scsi/aic7xxx/aic7xxx_core.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/scsi/aic7xxx/aic7xxx_core.c	2006-02-21 15:58:18.811286808 +0000
@@ -2461,11 +2461,8 @@
 {
 	if (offset == 0)
 		period = AHC_ASYNC_XFER_PERIOD;
-	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED;
-	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR_LEN;
-	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR;
-	ahc->msgout_buf[ahc->msgout_index++] = period;
-	ahc->msgout_buf[ahc->msgout_index++] = offset;
+	ahc->msgout_index += spi_populate_sync_msg(
+			ahc->msgout_buf + ahc->msgout_index, period, offset);
 	ahc->msgout_len += 5;
 	if (bootverbose) {
 		printf("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n",
@@ -2482,10 +2479,8 @@
 ahc_construct_wdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
 		   u_int bus_width)
 {
-	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED;
-	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_WDTR_LEN;
-	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_WDTR;
-	ahc->msgout_buf[ahc->msgout_index++] = bus_width;
+	ahc->msgout_index += spi_populate_width_msg(
+			ahc->msgout_buf + ahc->msgout_index, bus_width);
 	ahc->msgout_len += 4;
 	if (bootverbose) {
 		printf("(%s:%c:%d:%d): Sending WDTR %x\n",
@@ -2505,14 +2500,9 @@
 {
 	if (offset == 0)
 		period = AHC_ASYNC_XFER_PERIOD;
-	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED;
-	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR_LEN;
-	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR;
-	ahc->msgout_buf[ahc->msgout_index++] = period;
-	ahc->msgout_buf[ahc->msgout_index++] = 0;
-	ahc->msgout_buf[ahc->msgout_index++] = offset;
-	ahc->msgout_buf[ahc->msgout_index++] = bus_width;
-	ahc->msgout_buf[ahc->msgout_index++] = ppr_options;
+	ahc->msgout_index += spi_populate_ppr_msg(
+			ahc->msgout_buf + ahc->msgout_index, period, offset,
+			bus_width, ppr_options);
 	ahc->msgout_len += 8;
 	if (bootverbose) {
 		printf("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, "
diff -urN oldtree/drivers/scsi/aic7xxx/aic7xxx_osm.c newtree/drivers/scsi/aic7xxx/aic7xxx_osm.c
--- oldtree/drivers/scsi/aic7xxx/aic7xxx_osm.c	2006-02-19 11:41:03.759771528 +0000
+++ newtree/drivers/scsi/aic7xxx/aic7xxx_osm.c	2006-02-21 15:58:19.416194848 +0000
@@ -328,7 +328,7 @@
  * force all outstanding transactions to be serviced prior to a new
  * transaction.
  */
-uint32_t aic7xxx_periodic_otag;
+static uint32_t aic7xxx_periodic_otag;
 
 /*
  * Module information and settable options.
diff -urN oldtree/drivers/scsi/aic7xxx/aic7xxx_osm.h newtree/drivers/scsi/aic7xxx/aic7xxx_osm.h
--- oldtree/drivers/scsi/aic7xxx/aic7xxx_osm.h	2006-02-19 11:41:03.759771528 +0000
+++ newtree/drivers/scsi/aic7xxx/aic7xxx_osm.h	2006-02-21 15:58:19.417194696 +0000
@@ -537,8 +537,6 @@
 #define PCIR_SUBVEND_0	0x2c
 #define PCIR_SUBDEV_0	0x2e
 
-extern struct pci_driver aic7xxx_pci_driver;
-
 typedef enum
 {
 	AHC_POWER_STATE_D0,
diff -urN oldtree/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c newtree/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
--- oldtree/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c	2006-02-21 15:58:19.418194544 +0000
@@ -130,7 +130,7 @@
 
 MODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table);
 
-struct pci_driver aic7xxx_pci_driver = {
+static struct pci_driver aic7xxx_pci_driver = {
 	.name		= "aic7xxx",
 	.probe		= ahc_linux_pci_dev_probe,
 	.remove		= ahc_linux_pci_dev_remove,
diff -urN oldtree/drivers/scsi/aic7xxx/aic7xxx_pci.c newtree/drivers/scsi/aic7xxx/aic7xxx_pci.c
--- oldtree/drivers/scsi/aic7xxx/aic7xxx_pci.c	2006-02-19 11:41:03.761771224 +0000
+++ newtree/drivers/scsi/aic7xxx/aic7xxx_pci.c	2006-02-21 15:58:19.421194088 +0000
@@ -162,7 +162,7 @@
 static ahc_device_setup_t ahc_aha494XX_setup;
 static ahc_device_setup_t ahc_aha398XX_setup;
 
-struct ahc_pci_identity ahc_pci_ident_table [] =
+static struct ahc_pci_identity ahc_pci_ident_table [] =
 {
 	/* aic7850 based controllers */
 	{
@@ -553,7 +553,7 @@
 	}
 };
 
-const u_int ahc_num_pci_devs = NUM_ELEMENTS(ahc_pci_ident_table);
+static const u_int ahc_num_pci_devs = NUM_ELEMENTS(ahc_pci_ident_table);
 		
 #define AHC_394X_SLOT_CHANNEL_A	4
 #define AHC_394X_SLOT_CHANNEL_B	5
diff -urN oldtree/drivers/scsi/arcmsr/Makefile newtree/drivers/scsi/arcmsr/Makefile
--- oldtree/drivers/scsi/arcmsr/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/scsi/arcmsr/Makefile	2006-02-21 15:58:20.129086472 +0000
@@ -0,0 +1,4 @@
+# File: drivers/arcmsr/Makefile
+# Makefile for the ARECA PCI-X PCI-EXPRESS SATA RAID controllers SCSI driver.
+
+obj-$(CONFIG_SCSI_ARCMSR) := arcmsr.o
diff -urN oldtree/drivers/scsi/arcmsr/arcmsr.c newtree/drivers/scsi/arcmsr/arcmsr.c
--- oldtree/drivers/scsi/arcmsr/arcmsr.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/scsi/arcmsr/arcmsr.c	2006-02-21 15:58:20.126086928 +0000
@@ -0,0 +1,2125 @@
+/*
+*******************************************************************************
+**        O.S   : Linux
+**   FILE NAME  : arcmsr.c
+**        BY    : Erich Chen
+**   Description: SCSI RAID Device Driver for
+**                ARECA RAID Host adapter
+*******************************************************************************
+** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
+**
+**     Web site: www.areca.com.tw
+**       E-mail: erich@areca.com.tw
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License version 2 as
+** published by the Free Software Foundation.
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+*******************************************************************************
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+**    derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING,BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************
+** For history of changes, see Documentation/scsi/ChangeLog.arcmsr
+*******************************************************************************
+*/
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsicam.h>
+#include "arcmsr.h"
+
+MODULE_AUTHOR("Erich Chen <erich@areca.com.tw>");
+MODULE_DESCRIPTION("ARECA (ARC11xx/12xx) SATA RAID HOST Adapter");
+MODULE_LICENSE("Dual BSD/GPL");
+
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static uint8_t arcmsr_adapterCnt;
+static struct HCBARC arcmsr_host_control_block;
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static int arcmsr_fops_close(struct inode *inode, struct file *filep);
+static int arcmsr_fops_open(struct inode *inode, struct file *filep);
+static int arcmsr_initialize(struct ACB *pACB, struct pci_dev *pci_device);
+static int arcmsr_iop_ioctlcmd(struct ACB *pACB, int ioctl_cmd, void __user * arg);
+static int arcmsr_release(struct Scsi_Host *);
+static int arcmsr_cmd_abort(struct scsi_cmnd *);
+static int arcmsr_bus_reset(struct scsi_cmnd *);
+static int arcmsr_ioctl(struct scsi_device * dev, int ioctl_cmd, void __user * arg);
+static int arcmsr_fops_ioctl(struct inode *inode, struct file *filep,
+				unsigned int ioctl_cmd, unsigned long arg);
+static int arcmsr_halt_notify(struct notifier_block *nb,
+				unsigned long event, void *buf);
+static int arcmsr_proc_info(struct Scsi_Host *host, char *buffer, char **start,
+				off_t offset, int length, int inout);
+static int arcmsr_bios_param(struct scsi_device *sdev,
+				struct block_device *bdev, sector_t capacity, int *info);
+static int arcmsr_queue_command(struct scsi_cmnd * cmd,
+				void (*done) (struct scsi_cmnd *));
+static int arcmsr_device_probe(struct pci_dev *pci_device,
+				const struct pci_device_id *id);
+static void arcmsr_device_remove(struct pci_dev *pci_device);
+static void arcmsr_pcidev_disattach(struct ACB *pACB);
+static void arcmsr_iop_init(struct ACB *pACB);
+static void arcmsr_free_ccb_pool(struct ACB *pACB);
+static irqreturn_t arcmsr_interrupt(struct ACB *pACB);
+static uint8_t arcmsr_wait_msgint_ready(struct ACB *pACB);
+static const char *arcmsr_info(struct Scsi_Host *);
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static ssize_t arcmsr_show_firmware_info(struct class_device *dev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(dev);
+	struct ACB *pACB = (struct ACB *) host->hostdata;
+	unsigned long flags = 0;
+	ssize_t len;
+
+	spin_lock_irqsave(pACB->host->host_lock, flags);
+	len = snprintf(buf, PAGE_SIZE,
+			"=================================\n"
+		        "Firmware Version:  %s\n"
+			"Adapter Model:           %s\n"
+			"Reguest Lenth:               %4d\n"
+			"Numbers of Queue:            %4d\n"
+			"SDRAM Size:                  %4d\n"
+			"IDE Channels:                %4d\n"
+			"=================================\n",
+				pACB->firm_version,
+				pACB->firm_model,
+				pACB->firm_request_len,
+				pACB->firm_numbers_queue,
+				pACB->firm_sdram_size,
+				pACB->firm_ide_channels);
+	spin_unlock_irqrestore(pACB->host->host_lock, flags);
+	return len;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static ssize_t arcmsr_show_driver_state(struct class_device *dev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(dev);
+	struct ACB *pACB = (struct ACB *)host->hostdata;
+	unsigned long flags = 0;
+	ssize_t len;
+
+	spin_lock_irqsave(pACB->host->host_lock, flags);
+	len = snprintf(buf, PAGE_SIZE,
+				"=================================\n"
+				"ARCMSR: %s\n"
+				"Current commands posted:     %4d\n"
+				"Max commands posted:         %4d\n"
+				"Current pending commands:    %4d\n"
+				"Max pending commands:        %4d\n"
+				"Max sgl length:              %4d\n"
+				"Max sector count:            %4d\n"
+				"SCSI Host Resets:            %4d\n"
+				"SCSI Aborts/Timeouts:        %4d\n"
+				"=================================\n",
+				ARCMSR_DRIVER_VERSION,
+				atomic_read(&pACB->ccboutstandingcount),
+				ARCMSR_MAX_OUTSTANDING_CMD,
+				atomic_read(&pACB->ccbpendingcount),
+				ARCMSR_MAX_PENDING_CMD,
+				ARCMSR_MAX_SG_ENTRIES,
+				ARCMSR_MAX_XFER_SECTORS,
+				pACB->num_resets,
+				pACB->num_aborts);
+	spin_unlock_irqrestore(pACB->host->host_lock, flags);
+	return len;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static struct class_device_attribute arcmsr_firmware_info_attr = {
+	.attr = {
+		.name = "firmware_info",
+		.mode = S_IRUGO,
+	},
+	.show = arcmsr_show_firmware_info,
+};
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static struct class_device_attribute arcmsr_driver_state_attr = {
+	.attr = {
+		.name = "driver_state",
+		.mode = S_IRUGO,
+	},
+	.show = arcmsr_show_driver_state
+};
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static struct class_device_attribute *arcmsr_scsi_host_attr[] = {
+	&arcmsr_firmware_info_attr,
+	&arcmsr_driver_state_attr,
+	NULL
+};
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth)
+{
+	if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
+		queue_depth = ARCMSR_MAX_CMD_PERLUN;
+	scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
+	return queue_depth;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static struct scsi_host_template arcmsr_scsi_host_template = {
+	.module			= THIS_MODULE,
+	.proc_name		= "arcmsr",
+	.proc_info		= arcmsr_proc_info,
+	.name			= "ARCMSR ARECA SATA RAID HOST Adapter" ARCMSR_DRIVER_VERSION,
+	.release		= arcmsr_release,
+	.info			= arcmsr_info,
+	.ioctl			= arcmsr_ioctl,
+	.queuecommand		= arcmsr_queue_command,
+	.eh_abort_handler	= arcmsr_cmd_abort,
+	.eh_bus_reset_handler	= arcmsr_bus_reset,
+	.bios_param		= arcmsr_bios_param,
+	.change_queue_depth	= arcmsr_adjust_disk_queue_depth,
+	.can_queue		= ARCMSR_MAX_OUTSTANDING_CMD,
+	.this_id		= ARCMSR_SCSI_INITIATOR_ID,
+	.sg_tablesize		= ARCMSR_MAX_SG_ENTRIES,
+	.max_sectors    	= ARCMSR_MAX_XFER_SECTORS,
+	.cmd_per_lun		= ARCMSR_MAX_CMD_PERLUN,
+	.unchecked_isa_dma	= 0,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.shost_attrs		= arcmsr_scsi_host_attr,
+};
+/*
+*******************************************************************************
+** notifier block to get a notify on system shutdown/halt/reboot
+*******************************************************************************
+*/
+static struct notifier_block arcmsr_event_notifier = {
+	.notifier_call		= arcmsr_halt_notify
+};
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static struct file_operations arcmsr_file_operations = {
+	.owner			= THIS_MODULE,
+	.ioctl			= arcmsr_fops_ioctl,
+	.open			= arcmsr_fops_open,
+	.release		= arcmsr_fops_close,
+};
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static struct pci_device_id arcmsr_device_id_table[] = {
+	{PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1110)},
+	{PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1120)},
+	{PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1130)},
+	{PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1160)},
+	{PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1170)},
+	{PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1210)},
+	{PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1220)},
+	{PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1230)},
+	{PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1260)},
+	{PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1270)},
+	{PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1280)},
+	{0, 0}, /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table);
+static struct pci_driver arcmsr_pci_driver = {
+	.name			= "arcmsr",
+	.id_table		= arcmsr_device_id_table,
+	.probe			= arcmsr_device_probe,
+	.remove			= arcmsr_device_remove,
+};
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id,
+	struct pt_regs *regs)
+{
+	irqreturn_t handle_state;
+	struct HCBARC *pHCBARC = &arcmsr_host_control_block;
+	struct ACB *pACB;
+	struct ACB *pACBtmp;
+	unsigned long flags;
+	int i = 0;
+
+	pACB = (struct ACB *)dev_id;
+	pACBtmp = pHCBARC->pACB[i];
+	while ((pACB != pACBtmp) && pACBtmp && (i < ARCMSR_MAX_ADAPTER) ) {
+		i++;
+		pACBtmp = pHCBARC->pACB[i];
+	}
+	if (!pACBtmp)
+		return IRQ_NONE;
+	spin_lock_irqsave(pACB->host->host_lock, flags);
+	handle_state = arcmsr_interrupt(pACB);
+	spin_unlock_irqrestore(pACB->host->host_lock, flags);
+	return handle_state;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static int arcmsr_bios_param(struct scsi_device *sdev,
+	struct block_device *bdev, sector_t capacity, int *geom)
+{
+	int ret, heads, sectors, cylinders, total_capacity;
+	unsigned char *buffer;/* return copy of block device's partition table */
+
+	buffer = scsi_bios_ptable(bdev);
+	if (buffer) {
+		ret = scsi_partsize(buffer, capacity, &geom[2], &geom[0], &geom[1]);
+		kfree(buffer);
+		if (ret != -1)
+			return ret;
+	}
+	total_capacity = capacity;
+	heads = 64;
+	sectors = 32;
+	cylinders = total_capacity / (heads * sectors);
+	if (cylinders > 1024) {
+		heads = 255;
+		sectors = 63;
+		cylinders = total_capacity / (heads * sectors);
+	}
+	geom[0] = heads;
+	geom[1] = sectors;
+	geom[2] = cylinders;
+	return 0;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static int arcmsr_device_probe(struct pci_dev *pci_device,
+	const struct pci_device_id *id)
+{
+	struct Scsi_Host *host;
+	struct HCBARC *pHCBARC = &arcmsr_host_control_block;
+	struct ACB *pACB;
+	uint8_t bus, dev_fun;
+
+	if (pci_enable_device(pci_device)) {
+		printk(KERN_NOTICE
+			"arcmsr%d: adapter probe: pci_enable_device error \n"
+			, arcmsr_adapterCnt);
+		return -ENODEV;
+	}
+	host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof (struct ACB));
+	if (!host) {
+		printk(KERN_NOTICE
+			"arcmsr%d: adapter probe: scsi_host_alloc error \n"
+			, arcmsr_adapterCnt);
+		return -ENODEV;
+	}
+	if (!pci_set_dma_mask(pci_device, DMA_64BIT_MASK))
+		printk(KERN_INFO
+		"ARECA RAID ADAPTER%d: 64BITS PCI BUS DMA ADDRESSING SUPPORTED\n"
+		, arcmsr_adapterCnt);
+	else if (!pci_set_dma_mask(pci_device, DMA_32BIT_MASK))
+		printk(KERN_INFO
+		"ARECA RAID ADAPTER%d: 32BITS PCI BUS DMA ADDRESSING SUPPORTED\n"
+		, arcmsr_adapterCnt);
+	else {
+		printk(KERN_NOTICE
+			"ARECA RAID ADAPTER%d: No suitable DMA available.\n"
+			, arcmsr_adapterCnt);
+		return -ENOMEM;
+	}
+	if (pci_set_consistent_dma_mask(pci_device, DMA_32BIT_MASK)) {
+		printk(KERN_NOTICE
+			"ARECA RAID ADAPTER%d:"
+			" No 32BIT coherent DMA adressing available\n"
+			, arcmsr_adapterCnt);
+		return -ENOMEM;
+	}
+	bus = pci_device->bus->number;
+	dev_fun = pci_device->devfn;
+	pACB = (struct ACB *) host->hostdata;
+	memset(pACB, 0, sizeof (struct ACB));
+	spin_lock_init(&pACB->qbuffer_lock);
+	spin_lock_init(&pACB->pending_list_lock);
+	spin_lock_init(&pACB->working_list_lock);
+	spin_lock_init(&pACB->done_list_lock);
+	pACB->pci_device = pci_device;
+	pACB->host = host;
+	host->max_sectors = ARCMSR_MAX_XFER_SECTORS;
+	host->max_lun = ARCMSR_MAX_TARGETLUN;
+	host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/
+	host->max_cmd_len = 16;    /*this is issue of 64bit LBA, over 2T byte*/
+	host->sg_tablesize = ARCMSR_MAX_SG_ENTRIES;
+	host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */
+	host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN;
+	host->this_id = ARCMSR_SCSI_INITIATOR_ID;
+	host->unique_id = (bus << 8) | dev_fun;
+	host->io_port = 0;
+	host->n_io_port = 0;
+	host->irq = pci_device->irq;
+	pci_set_master(pci_device);
+	if (arcmsr_initialize(pACB, pci_device)) {
+		printk(KERN_NOTICE
+			"arcmsr%d: initialize got error \n"
+			, arcmsr_adapterCnt);
+		pHCBARC->adapterCnt = arcmsr_adapterCnt;
+		pHCBARC->pACB[arcmsr_adapterCnt] = NULL;
+		scsi_remove_host(host);
+		scsi_host_put(host);
+		return -ENODEV;
+	}
+	if (pci_request_regions(pci_device, "arcmsr")) {
+		printk(KERN_NOTICE
+			"arcmsr%d: adapter probe: pci_request_regions failed \n"
+			, arcmsr_adapterCnt--);
+		pHCBARC->adapterCnt = arcmsr_adapterCnt;
+		arcmsr_pcidev_disattach(pACB);
+		return -ENODEV;
+	}
+#ifdef CONFIG_SCSI_ARCMSR_MSI
+	if (!pci_enable_msi(pci_device))
+		pACB->acb_flags |= ACB_F_HAVE_MSI;
+#endif
+	if (request_irq(pci_device->irq, arcmsr_do_interrupt, SA_INTERRUPT | SA_SHIRQ,
+		"arcmsr", pACB)) {
+		printk(KERN_NOTICE
+			"arcmsr%d: request IRQ=%d failed !\n"
+			, arcmsr_adapterCnt--, pci_device->irq);
+		pHCBARC->adapterCnt = arcmsr_adapterCnt;
+		arcmsr_pcidev_disattach(pACB);
+		return -ENODEV;
+	}
+	arcmsr_iop_init(pACB);
+	if (scsi_add_host(host, &pci_device->dev)) {
+		printk(KERN_NOTICE
+			"arcmsr%d: scsi_add_host got error \n"
+			, arcmsr_adapterCnt--);
+		pHCBARC->adapterCnt = arcmsr_adapterCnt;
+		arcmsr_pcidev_disattach(pACB);
+		return -ENODEV;
+	}
+	pHCBARC->adapterCnt = arcmsr_adapterCnt;
+	pci_set_drvdata(pci_device, host);
+	scsi_scan_host(host);
+	return 0;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_device_remove(struct pci_dev *pci_device)
+{
+	struct Scsi_Host * host = pci_get_drvdata(pci_device);
+	struct ACB *pACB = (struct ACB *) host->hostdata;
+	struct HCBARC *pHCBARC = &arcmsr_host_control_block;
+	int i;
+
+	arcmsr_pcidev_disattach(pACB);
+	/*if this is last pACB */
+	for(i = 0; i < ARCMSR_MAX_ADAPTER; i++) {
+		if (pHCBARC->pACB[i])
+			return;/* this is not last adapter's release */
+	}
+	unregister_chrdev(pHCBARC->arcmsr_major_number, "arcmsr");
+	unregister_reboot_notifier(&arcmsr_event_notifier);
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static int arcmsr_scsi_host_template_init(
+	struct scsi_host_template * host_template)
+{
+	int error;
+	struct HCBARC *pHCBARC = &arcmsr_host_control_block;
+
+	/*
+	** register as a PCI hot-plug driver module+
+	*/
+	memset(pHCBARC, 0, sizeof (struct HCBARC));
+	error = pci_module_init(&arcmsr_pci_driver);
+	if (pHCBARC->pACB[0]) {
+		host_template->proc_name = "arcmsr";
+		register_reboot_notifier(&arcmsr_event_notifier);
+		pHCBARC->arcmsr_major_number = register_chrdev(0, "arcmsr"
+			, &arcmsr_file_operations);
+		printk(KERN_INFO
+			"arcmsr device major number %d \n"
+			, pHCBARC->arcmsr_major_number);
+	}
+	return error;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static int arcmsr_module_init(void)
+{
+	return(arcmsr_scsi_host_template_init(&arcmsr_scsi_host_template));
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_module_exit(void)
+{
+	pci_unregister_driver(&arcmsr_pci_driver);
+}
+module_init(arcmsr_module_init);
+module_exit(arcmsr_module_exit);
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_pci_unmap_dma(struct CCB *pCCB)
+{
+	struct ACB *pACB = pCCB->pACB;
+	struct scsi_cmnd *pcmd = pCCB->pcmd;
+
+	if (pcmd->use_sg != 0) {
+		struct scatterlist *sl;
+
+		sl = (struct scatterlist *)pcmd->request_buffer;
+		pci_unmap_sg(pACB->pci_device, sl, pcmd->use_sg, pcmd->sc_data_direction);
+	}
+	else if (pcmd->request_bufflen != 0)
+		pci_unmap_single(pACB->pci_device,
+			(dma_addr_t)(unsigned long)pcmd->SCp.ptr,
+			pcmd->request_bufflen, pcmd->sc_data_direction);
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static int arcmsr_fops_open(struct inode *inode, struct file *filep)
+{
+	int i, minor;
+	struct HCBARC *pHCBARC = &arcmsr_host_control_block;
+	struct ACB *pACB;
+
+	minor = MINOR(inode->i_rdev);
+	if (minor >= pHCBARC->adapterCnt)
+		return -ENODEV;
+	for(i = 0; i < ARCMSR_MAX_ADAPTER; i++) {
+		pACB = pHCBARC->pACB[i];
+		if (pACB) {
+			if (pACB->adapter_index == minor)
+				break;
+		}
+	}
+	if (i >= ARCMSR_MAX_ADAPTER)
+		return -ENODEV;
+	return 0;/* success */
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static int arcmsr_fops_close(struct inode *inode, struct file *filep)
+{
+	int i, minor;
+	struct HCBARC *pHCBARC = &arcmsr_host_control_block;
+	struct ACB *pACB;
+
+	minor = MINOR(inode->i_rdev);
+	if (minor >= pHCBARC->adapterCnt)
+		return -ENODEV;
+	for(i = 0; i < ARCMSR_MAX_ADAPTER; i++) {
+		pACB = pHCBARC->pACB[i];
+		if (pACB) {
+			if (pACB->adapter_index == minor)
+				break;
+		}
+	}
+	if (i >= ARCMSR_MAX_ADAPTER)
+		return -ENODEV;
+	return 0;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static int arcmsr_fops_ioctl(struct inode *inode, struct file *filep,
+	unsigned int ioctl_cmd, unsigned long arg)
+{
+	int i, minor;
+	struct HCBARC *pHCBARC = &arcmsr_host_control_block;
+	struct ACB *pACB;
+
+	minor = MINOR(inode->i_rdev);
+	if (minor >= pHCBARC->adapterCnt)
+		return -ENODEV;
+	for(i = 0; i < ARCMSR_MAX_ADAPTER; i++) {
+		pACB = pHCBARC->pACB[i];
+		if (pACB) {
+			if (pACB->adapter_index == minor)
+				break;
+		}
+	}
+	if (i >= ARCMSR_MAX_ADAPTER)
+		return -ENODEV;
+	return arcmsr_iop_ioctlcmd(pACB, ioctl_cmd, (void __user *) arg);
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_flush_adapter_cache(struct ACB *pACB)
+{
+	struct MU __iomem *reg=pACB->pmu;
+
+	writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
+	if (arcmsr_wait_msgint_ready(pACB))
+		printk(KERN_NOTICE
+			"arcmsr%d: wait 'flush adapter cache' timeout \n"
+			, pACB->adapter_index);
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_ccb_complete(struct CCB *pCCB, int stand_flag)
+{
+	unsigned long flags;
+	struct ACB *pACB = pCCB->pACB;
+	struct scsi_cmnd *pcmd = pCCB->pcmd;
+
+	arcmsr_pci_unmap_dma(pCCB);
+	spin_lock_irqsave(&pACB->done_list_lock, flags);
+	if (stand_flag == 1)
+		atomic_dec(&pACB->ccboutstandingcount);
+	pCCB->startdone = ARCMSR_CCB_DONE;
+	pCCB->ccb_flags = 0;
+	list_add_tail(&pCCB->list, &pACB->ccb_free_list);
+	spin_unlock_irqrestore(&pACB->done_list_lock, flags);
+	pcmd->scsi_done(pcmd);
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_report_sense_info(struct CCB *pCCB)
+{
+	struct scsi_cmnd *pcmd = pCCB->pcmd;
+	struct SENSE_DATA *psenseBuffer = (struct SENSE_DATA *)pcmd->sense_buffer;
+
+	pcmd->result = DID_OK << 16;
+	if (psenseBuffer) {
+		int sense_data_length =
+			sizeof (struct SENSE_DATA) < sizeof (pcmd->sense_buffer)
+			? sizeof (struct SENSE_DATA) : sizeof (pcmd->sense_buffer);
+		memset(psenseBuffer, 0, sizeof (pcmd->sense_buffer));
+		memcpy(psenseBuffer, pCCB->arcmsr_cdb.SenseData, sense_data_length);
+		psenseBuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
+		psenseBuffer->Valid = 1;
+	}
+}
+/*
+*******************************************************************************
+** to insert pCCB into tail of pACB wait exec ccbQ
+*******************************************************************************
+*/
+static void arcmsr_queue_pendingccb(struct ACB *pACB, struct CCB *pCCB)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&pACB->pending_list_lock, flags);
+	list_add_tail(&pCCB->list, &pACB->ccb_pending_list);
+	atomic_inc(&pACB->ccbpendingcount);
+	spin_unlock_irqrestore(&pACB->pending_list_lock, flags);
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_abort_allcmd(struct ACB *pACB)
+{
+	struct MU __iomem *reg = pACB->pmu;
+
+	writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &reg->inbound_msgaddr0);
+	if (arcmsr_wait_msgint_ready(pACB))
+		printk(KERN_NOTICE
+			"arcmsr%d: wait 'abort all outstanding command' timeout \n"
+			, pACB->adapter_index);
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static uint8_t arcmsr_wait_msgint_ready(struct ACB *pACB)
+{
+	struct MU __iomem *reg = pACB->pmu;
+	uint32_t Index;
+	uint8_t Retries = 0x00;
+
+	do {
+		for(Index = 0; Index < 100; Index++) {
+			if (readl(&reg->outbound_intstatus)
+				& ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
+				writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT
+					, &reg->outbound_intstatus);
+				return 0x00;
+			}
+			msleep_interruptible(10);
+		}/*max 1 seconds*/
+	} while (Retries++ < 20);/*max 20 sec*/
+	return 0xff;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static struct CCB *arcmsr_get_pendingccb(struct ACB *pACB)
+{
+	unsigned long flags;
+	struct list_head *head = &pACB->ccb_pending_list;
+	struct CCB *pCCB = NULL;
+
+	if (spin_trylock_irqsave(&pACB->pending_list_lock, flags)) {
+		if (!list_empty(head)) {
+			pCCB = list_entry(head->next, struct CCB, list);
+			atomic_dec(&pACB->ccbpendingcount);
+			list_del(head->next);
+		}
+		spin_unlock_irqrestore(&pACB->pending_list_lock, flags);
+	}
+	return pCCB;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_iop_reset(struct ACB *pACB)
+{
+	struct MU __iomem *reg = pACB->pmu;
+	struct CCB *pCCB;
+	uint32_t intmask_org, mask;
+	int i = 0;
+
+	if (atomic_read(&pACB->ccboutstandingcount) != 0) {
+		/* talk to iop 331 outstanding command aborted */
+		arcmsr_abort_allcmd(pACB);
+		/* wait for 3 sec for all command aborted*/
+		msleep_interruptible(3000);
+		/* disable all outbound interrupt */
+		intmask_org = readl(&reg->outbound_intmask);
+		writel(intmask_org | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
+			&reg->outbound_intmask);
+		/* clear all outbound posted Q */
+		for(i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++)
+			readl(&reg->outbound_queueport);
+		for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+			pCCB = pACB->pccb_pool[i];
+			if (pCCB->startdone == ARCMSR_CCB_START) {
+				pCCB->startdone = ARCMSR_CCB_ABORTED;
+				pCCB->pcmd->result = DID_ABORT << 16;
+				arcmsr_ccb_complete(pCCB, 1);
+			}
+		}
+		/* enable all outbound interrupt */
+		mask =~ (ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE
+			| ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
+		writel(intmask_org & mask, &reg->outbound_intmask);
+	}
+	while (atomic_read(&pACB->ccbpendingcount) != 0) {
+		pCCB = arcmsr_get_pendingccb(pACB);
+		if (pCCB) {
+			printk(KERN_NOTICE
+				"arcmsr%d:iop reset abort command ccbpendingcount=%d \n"
+				, pACB->adapter_index, atomic_read(&pACB->ccbpendingcount));
+			pCCB->startdone = ARCMSR_CCB_ABORTED;
+			pCCB->pcmd->result = DID_ABORT << 16;
+			arcmsr_ccb_complete(pCCB, 0);
+			atomic_dec(&pACB->ccbpendingcount);
+		}
+		else
+			break;
+	}
+	atomic_set(&pACB->ccboutstandingcount, 0);
+	atomic_set(&pACB->ccbpendingcount, 0);
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_build_ccb(struct ACB *pACB, struct CCB *pCCB,
+	struct scsi_cmnd *pcmd)
+{
+	struct ARCMSR_CDB *pARCMSR_CDB = (struct ARCMSR_CDB *)&pCCB->arcmsr_cdb;
+	int8_t *psge = (int8_t *)&pARCMSR_CDB->u;
+	uint32_t address_lo, address_hi;
+	int arccdbsize = 0x30;
+
+	pCCB->pcmd = pcmd;
+	memset(pARCMSR_CDB, 0, sizeof (struct ARCMSR_CDB));
+	pARCMSR_CDB->Bus = 0;
+	pARCMSR_CDB->TargetID = pcmd->device->id;
+	pARCMSR_CDB->LUN = pcmd->device->lun;
+	pARCMSR_CDB->Function = 1;
+	pARCMSR_CDB->CdbLength = (uint8_t)pcmd->cmd_len;
+	pARCMSR_CDB->Context = (unsigned long)pARCMSR_CDB;
+	memcpy(pARCMSR_CDB->Cdb, pcmd->cmnd, pcmd->cmd_len);
+	if (pcmd->use_sg) {
+		int length, sgcount, i, cdb_sgcount = 0;
+		struct scatterlist *sl;
+
+		/* Get Scatter Gather List from scsiport. */
+		sl = (struct scatterlist *) pcmd->request_buffer;
+		sgcount = pci_map_sg(pACB->pci_device, sl, pcmd->use_sg,
+				pcmd->sc_data_direction);
+		/* map stor port SG list to our iop SG List. */
+		for(i = 0; i < sgcount; i++) {
+			/* Get the physical address of the current data pointer */
+			length = cpu_to_le32(sg_dma_len(sl));
+			address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sl)));
+			address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sl)));
+			if (address_hi == 0) {
+				struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge;
+
+				pdma_sg->address = address_lo;
+				pdma_sg->length = length;
+				psge += sizeof (struct SG32ENTRY);
+				arccdbsize += sizeof (struct SG32ENTRY);
+			} else {
+				struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge;
+
+				pdma_sg->addresshigh = address_hi;
+				pdma_sg->address = address_lo;
+				pdma_sg->length = length|IS_SG64_ADDR;
+				psge += sizeof (struct SG64ENTRY);
+				arccdbsize += sizeof (struct SG64ENTRY);
+			}
+			sl++;
+			cdb_sgcount++;
+		}
+		pARCMSR_CDB->sgcount = (uint8_t)cdb_sgcount;
+		pARCMSR_CDB->DataLength = pcmd->request_bufflen;
+		if ( arccdbsize > 256)
+			pARCMSR_CDB->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
+	} else if (pcmd->request_bufflen) {
+		dma_addr_t dma_addr;
+		dma_addr = pci_map_single(pACB->pci_device, pcmd->request_buffer,
+				pcmd->request_bufflen, pcmd->sc_data_direction);
+		pcmd->SCp.ptr = (char *)(unsigned long) dma_addr;
+		address_lo = cpu_to_le32(dma_addr_lo32(dma_addr));
+		address_hi = cpu_to_le32(dma_addr_hi32(dma_addr));
+		if (address_hi == 0) {
+			struct  SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge;
+			pdma_sg->address = address_lo;
+			pdma_sg->length = pcmd->request_bufflen;
+		} else {
+			struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge;
+			pdma_sg->addresshigh = address_hi;
+			pdma_sg->address = address_lo;
+			pdma_sg->length = pcmd->request_bufflen|IS_SG64_ADDR;
+		}
+		pARCMSR_CDB->sgcount = 1;
+		pARCMSR_CDB->DataLength = pcmd->request_bufflen;
+	}
+	if (pcmd->cmnd[0] | WRITE_6 || pcmd->cmnd[0] | WRITE_10) {
+		pARCMSR_CDB->Flags |= ARCMSR_CDB_FLAG_WRITE;
+		pCCB->ccb_flags |= CCB_FLAG_WRITE;
+	}
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_post_ccb(struct ACB *pACB, struct CCB *pCCB)
+{
+	struct MU __iomem *reg = pACB->pmu;
+	uint32_t cdb_shifted_phyaddr = pCCB->cdb_shifted_phyaddr;
+	struct ARCMSR_CDB *pARCMSR_CDB = (struct ARCMSR_CDB *)&pCCB->arcmsr_cdb;
+
+	atomic_inc(&pACB->ccboutstandingcount);
+	pCCB->startdone = ARCMSR_CCB_START;
+	if (pARCMSR_CDB->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
+		writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
+			&reg->inbound_queueport);
+	else
+		writel(cdb_shifted_phyaddr, &reg->inbound_queueport);
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_post_pendingccb(struct ACB *pACB)
+{
+	struct CCB *pCCB;
+
+	while ((atomic_read(&pACB->ccbpendingcount) > 0)
+		&& (atomic_read(&pACB->ccboutstandingcount) < ARCMSR_MAX_OUTSTANDING_CMD)) {
+		pCCB = arcmsr_get_pendingccb(pACB);
+		if (!pCCB)
+			break;
+		arcmsr_post_ccb(pACB, pCCB);
+	}
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_post_Qbuffer(struct ACB *pACB)
+{
+	struct MU __iomem *reg = pACB->pmu;
+	struct QBUFFER __iomem *pwbuffer = (struct QBUFFER __iomem *) &reg->ioctl_wbuffer;
+	uint8_t __iomem *iop_data = (uint8_t __iomem *) pwbuffer->data;
+	int32_t allxfer_len = 0;
+
+	if (pACB->acb_flags & ACB_F_IOCTL_WQBUFFER_READED) {
+		pACB->acb_flags &= (~ACB_F_IOCTL_WQBUFFER_READED);
+		while ((pACB->wqbuf_firstindex != pACB->wqbuf_lastindex)
+			&& (allxfer_len < 124)) {
+			writeb(pACB->wqbuffer[pACB->wqbuf_firstindex], iop_data);
+			pACB->wqbuf_firstindex++;
+			pACB->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+			iop_data++;
+			allxfer_len++;
+		}
+		writel(allxfer_len, &pwbuffer->data_len);
+		writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK
+			, &reg->inbound_doorbell);
+	}
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_stop_adapter_bgrb(struct ACB *pACB)
+{
+	struct MU __iomem *reg = pACB->pmu;
+
+	pACB->acb_flags &= ~ACB_F_MSG_START_BGRB;
+	writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, &reg->inbound_msgaddr0);
+	if (arcmsr_wait_msgint_ready(pACB))
+		printk(KERN_NOTICE
+			"arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
+			, pACB->adapter_index);
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_free_ccb_pool(struct ACB *pACB)
+{
+	dma_free_coherent(&pACB->pci_device->dev
+		, ARCMSR_MAX_FREECCB_NUM * sizeof (struct CCB) + 0x20,
+		pACB->dma_coherent,
+		pACB->dma_coherent_handle);
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static irqreturn_t arcmsr_interrupt(struct ACB *pACB)
+{
+	struct MU __iomem *reg = pACB->pmu;
+	struct CCB *pCCB;
+	uint32_t flag_ccb, outbound_intstatus, outbound_doorbell;
+
+	outbound_intstatus = readl(&reg->outbound_intstatus)
+		& pACB->outbound_int_enable;
+	writel(outbound_intstatus, &reg->outbound_intstatus);
+	if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) {
+		outbound_doorbell = readl(&reg->outbound_doorbell);
+		writel(outbound_doorbell, &reg->outbound_doorbell);
+		if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) {
+			struct QBUFFER __iomem * prbuffer =
+				(struct QBUFFER __iomem *) &reg->ioctl_rbuffer;
+			uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
+			int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex;
+
+			rqbuf_lastindex = pACB->rqbuf_lastindex;
+			rqbuf_firstindex = pACB->rqbuf_firstindex;
+			iop_len = readl(&prbuffer->data_len);
+			my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1)
+					&(ARCMSR_MAX_QBUFFER - 1);
+			if (my_empty_len >= iop_len) {
+				while (iop_len > 0) {
+					pACB->rqbuffer[pACB->rqbuf_lastindex] = readb(iop_data);
+					pACB->rqbuf_lastindex++;
+					pACB->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+					iop_data++;
+					iop_len--;
+				}
+				writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
+					&reg->inbound_doorbell);
+			} else
+				pACB->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
+		}
+		if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) {
+			pACB->acb_flags |= ACB_F_IOCTL_WQBUFFER_READED;
+			if (pACB->wqbuf_firstindex != pACB->wqbuf_lastindex) {
+				struct QBUFFER __iomem * pwbuffer =
+						(struct QBUFFER __iomem *) &reg->ioctl_wbuffer;
+				uint8_t __iomem * iop_data = (uint8_t __iomem *) pwbuffer->data;
+				int32_t allxfer_len = 0;
+
+				pACB->acb_flags &= (~ACB_F_IOCTL_WQBUFFER_READED);
+				while ((pACB->wqbuf_firstindex != pACB->wqbuf_lastindex)
+					&& (allxfer_len < 124)) {
+					writeb(pACB->wqbuffer[pACB->wqbuf_firstindex], iop_data);
+					pACB->wqbuf_firstindex++;
+					pACB->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+					iop_data++;
+					allxfer_len++;
+				}
+				writel(allxfer_len, &pwbuffer->data_len);
+				writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK,
+					&reg->inbound_doorbell);
+			}
+			if (pACB->wqbuf_firstindex == pACB->wqbuf_lastindex)
+				pACB->acb_flags |= ACB_F_IOCTL_WQBUFFER_CLEARED;
+		}
+	}
+	if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) {
+		int id, lun;
+		/*
+		****************************************************************
+		**               areca cdb command done
+		****************************************************************
+		*/
+		while (1) {
+			if ((flag_ccb = readl(&reg->outbound_queueport)) == 0xFFFFFFFF)
+				break;/*chip FIFO no ccb for completion already*/
+			/* check if command done with no error*/
+			pCCB = (struct CCB *)(pACB->vir2phy_offset + (flag_ccb << 5));
+			if ((pCCB->pACB != pACB) || (pCCB->startdone != ARCMSR_CCB_START)) {
+				if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
+					printk(KERN_NOTICE
+						"arcmsr%d: ccb='0x%p' isr got aborted command \n"
+						, pACB->adapter_index, pCCB);
+					continue;
+				}
+				printk(KERN_NOTICE
+					"arcmsr%d: isr get an illegal ccb command done acb='0x%p'"
+					"ccb='0x%p' ccbacb='0x%p' startdone = 0x%x"
+					" ccboutstandingcount=%d \n"
+					, pACB->adapter_index
+					, pACB
+					, pCCB
+					, pCCB->pACB
+					, pCCB->startdone
+					, atomic_read(&pACB->ccboutstandingcount));
+				continue;
+			}
+			id = pCCB->pcmd->device->id;
+			lun = pCCB->pcmd->device->lun;
+			if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
+				if (pACB->devstate[id][lun] == ARECA_RAID_GONE)
+					pACB->devstate[id][lun] = ARECA_RAID_GOOD;
+				pCCB->pcmd->result = DID_OK << 16;
+				arcmsr_ccb_complete(pCCB, 1);
+			} else {
+				switch(pCCB->arcmsr_cdb.DeviceStatus) {
+				case ARCMSR_DEV_SELECT_TIMEOUT: {
+						pACB->devstate[id][lun] = ARECA_RAID_GONE;
+						pCCB->pcmd->result = DID_TIME_OUT << 16;
+						arcmsr_ccb_complete(pCCB, 1);
+					}
+					break;
+				case ARCMSR_DEV_ABORTED:
+				case ARCMSR_DEV_INIT_FAIL: {
+						pACB->devstate[id][lun] = ARECA_RAID_GONE;
+						pCCB->pcmd->result = DID_BAD_TARGET << 16;
+						arcmsr_ccb_complete(pCCB, 1);
+					}
+					break;
+				case SCSISTAT_CHECK_CONDITION: {
+						pACB->devstate[id][lun] = ARECA_RAID_GOOD;
+						arcmsr_report_sense_info(pCCB);
+						arcmsr_ccb_complete(pCCB, 1);
+					}
+					break;
+				default:
+ 					printk(KERN_NOTICE
+						"arcmsr%d: scsi id=%d lun=%d"
+						" isr get command error done,"
+						"but got unknown DeviceStatus = 0x%x \n"
+						, pACB->adapter_index
+						, id
+						, lun
+						, pCCB->arcmsr_cdb.DeviceStatus);
+						pACB->devstate[id][lun] = ARECA_RAID_GONE;
+						pCCB->pcmd->result = DID_NO_CONNECT << 16;
+						arcmsr_ccb_complete(pCCB, 1);
+					break;
+				}
+			}
+		}/*drain reply FIFO*/
+	}
+	if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))
+		return IRQ_NONE;
+	arcmsr_post_pendingccb(pACB);/*try to post all pending ccb*/
+	return IRQ_HANDLED;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_iop_parking(struct ACB *pACB)
+{
+	if (pACB) {
+		/* stop adapter background rebuild */
+		if (pACB->acb_flags & ACB_F_MSG_START_BGRB) {
+			pACB->acb_flags &= ~ACB_F_MSG_START_BGRB;
+			arcmsr_stop_adapter_bgrb(pACB);
+			arcmsr_flush_adapter_cache(pACB);
+		}
+	}
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static int arcmsr_iop_ioctlcmd(struct ACB *pACB, int ioctl_cmd, void __user * arg)
+{
+	struct MU __iomem *reg = pACB->pmu;
+	struct CMD_IOCTL_FIELD *pcmdioctlfld;
+	dma_addr_t cmd_handle;
+	unsigned long flags;
+	int retvalue = 0;
+
+	spin_lock_irqsave(&pACB->qbuffer_lock, flags);
+	pcmdioctlfld = pci_alloc_consistent(pACB->pci_device,
+		sizeof (struct CMD_IOCTL_FIELD), &cmd_handle);
+	if (!pcmdioctlfld) {
+		spin_unlock_irqrestore(&pACB->qbuffer_lock, flags);
+		return -ENOMEM;
+	}
+	if (copy_from_user(pcmdioctlfld, arg, sizeof (struct CMD_IOCTL_FIELD)) != 0) {
+		retvalue = -EFAULT;
+		goto ioctl_out;
+	}
+	if (memcmp(pcmdioctlfld->cmdioctl.Signature, "ARCMSR", 6) !=0 ) {
+		retvalue = -EINVAL;
+		goto ioctl_out;
+	}
+	switch(ioctl_cmd) {
+	case ARCMSR_IOCTL_READ_RQBUFFER: {
+			unsigned long *ver_addr;
+			dma_addr_t buf_handle;
+			uint8_t *pQbuffer,*ptmpQbuffer;
+			int32_t allxfer_len = 0;
+
+			ver_addr = pci_alloc_consistent(pACB->pci_device, 1032, &buf_handle);
+			if (!ver_addr) {
+				retvalue = -ENOMEM;
+				goto ioctl_out;
+			}
+			ptmpQbuffer = (uint8_t *)ver_addr;
+			while ((pACB->rqbuf_firstindex != pACB->rqbuf_lastindex)
+				&& (allxfer_len < 1031)) {
+				pQbuffer = &pACB->rqbuffer[pACB->rqbuf_firstindex];
+				memcpy(ptmpQbuffer, pQbuffer, 1);
+				pACB->rqbuf_firstindex++;
+				pACB->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+				ptmpQbuffer++;
+				allxfer_len++;
+			}
+			if (pACB->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+				struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *)
+							&reg->ioctl_rbuffer;
+				uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
+				int32_t iop_len;
+
+				pACB->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+				iop_len = readl(&prbuffer->data_len);
+				while (iop_len > 0) {
+					pACB->rqbuffer[pACB->rqbuf_lastindex] = readb(iop_data);
+					pACB->rqbuf_lastindex++;
+					pACB->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+					iop_data++;
+					iop_len--;
+				}
+				writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
+						&reg->inbound_doorbell);
+			}
+			memcpy(pcmdioctlfld->ioctldatabuffer, (uint8_t *)ver_addr, allxfer_len);
+			pcmdioctlfld->cmdioctl.Length = allxfer_len;
+			pcmdioctlfld->cmdioctl.ReturnCode = ARCMSR_IOCTL_RETURNCODE_OK;
+			if (copy_to_user(arg, pcmdioctlfld, sizeof (struct CMD_IOCTL_FIELD)) != 0)
+				retvalue = -EFAULT;
+			pci_free_consistent(pACB->pci_device, 1032, ver_addr, buf_handle);
+		}
+		break;
+	case ARCMSR_IOCTL_WRITE_WQBUFFER: {
+			unsigned long *ver_addr;
+			dma_addr_t buf_handle;
+			int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
+			uint8_t *pQbuffer, *ptmpuserbuffer;
+
+			ver_addr = pci_alloc_consistent(pACB->pci_device, 1032, &buf_handle);
+			if (!ver_addr) {
+				retvalue = -ENOMEM;
+				goto ioctl_out;
+			}
+			ptmpuserbuffer = (uint8_t *)ver_addr;
+			user_len = pcmdioctlfld->cmdioctl.Length;
+			memcpy(ptmpuserbuffer, pcmdioctlfld->ioctldatabuffer, user_len);
+			wqbuf_lastindex = pACB->wqbuf_lastindex;
+			wqbuf_firstindex = pACB->wqbuf_firstindex;
+			if (wqbuf_lastindex != wqbuf_firstindex) {
+				arcmsr_post_Qbuffer(pACB);
+				pcmdioctlfld->cmdioctl.ReturnCode =
+							ARCMSR_IOCTL_RETURNCODE_ERROR;
+			} else {
+				my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
+						&(ARCMSR_MAX_QBUFFER - 1);
+				if (my_empty_len >= user_len) {
+					while (user_len > 0) {
+						pQbuffer =
+						&pACB->wqbuffer[pACB->wqbuf_lastindex];
+						memcpy(pQbuffer, ptmpuserbuffer, 1);
+						pACB->wqbuf_lastindex++;
+						pACB->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+						ptmpuserbuffer++;
+						user_len--;
+					}
+					if (pACB->acb_flags & ACB_F_IOCTL_WQBUFFER_CLEARED) {
+						pACB->acb_flags &=
+							~ACB_F_IOCTL_WQBUFFER_CLEARED;
+						arcmsr_post_Qbuffer(pACB);
+					}
+					pcmdioctlfld->cmdioctl.ReturnCode =
+							ARCMSR_IOCTL_RETURNCODE_OK;
+				}
+				else
+					pcmdioctlfld->cmdioctl.ReturnCode =
+							ARCMSR_IOCTL_RETURNCODE_ERROR;
+			}
+			if (copy_to_user(arg, pcmdioctlfld,
+				sizeof (struct CMD_IOCTL_FIELD)) != 0)
+				retvalue = -EFAULT;
+			pci_free_consistent(pACB->pci_device, 1032, ver_addr, buf_handle);
+		}
+		break;
+	case ARCMSR_IOCTL_CLEAR_RQBUFFER: {
+			uint8_t *pQbuffer = pACB->rqbuffer;
+
+			if (pACB->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+				pACB->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+				writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
+					&reg->inbound_doorbell);
+			}
+			pACB->acb_flags |= ACB_F_IOCTL_RQBUFFER_CLEARED;
+			pACB->rqbuf_firstindex = 0;
+			pACB->rqbuf_lastindex = 0;
+			memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
+			pcmdioctlfld->cmdioctl.ReturnCode = ARCMSR_IOCTL_RETURNCODE_OK;
+			if (copy_to_user(arg, pcmdioctlfld,
+				sizeof (struct CMD_IOCTL_FIELD)) != 0)
+				retvalue = -EFAULT;
+		}
+		break;
+	case ARCMSR_IOCTL_CLEAR_WQBUFFER: {
+			uint8_t *pQbuffer = pACB->wqbuffer;
+
+			if (pACB->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+				pACB->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+				writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
+						, &reg->inbound_doorbell);
+			}
+			pACB->acb_flags |=
+				(ACB_F_IOCTL_WQBUFFER_CLEARED | ACB_F_IOCTL_WQBUFFER_READED);
+			pACB->wqbuf_firstindex = 0;
+			pACB->wqbuf_lastindex = 0;
+			memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
+			pcmdioctlfld->cmdioctl.ReturnCode = ARCMSR_IOCTL_RETURNCODE_OK;
+			if (copy_to_user(arg, pcmdioctlfld,
+				sizeof (struct CMD_IOCTL_FIELD)) != 0)
+				retvalue = -EFAULT;
+		}
+		break;
+	case ARCMSR_IOCTL_CLEAR_ALLQBUFFER: {
+			uint8_t *pQbuffer;
+
+			if (pACB->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+				pACB->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+				writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
+						, &reg->inbound_doorbell);
+			}
+			pACB->acb_flags |=
+				(ACB_F_IOCTL_WQBUFFER_CLEARED
+				| ACB_F_IOCTL_RQBUFFER_CLEARED
+				| ACB_F_IOCTL_WQBUFFER_READED);
+			pACB->rqbuf_firstindex = 0;
+			pACB->rqbuf_lastindex = 0;
+			pACB->wqbuf_firstindex = 0;
+			pACB->wqbuf_lastindex = 0;
+			pQbuffer = pACB->rqbuffer;
+			memset(pQbuffer, 0, sizeof (struct QBUFFER));
+			pQbuffer = pACB->wqbuffer;
+			memset(pQbuffer, 0, sizeof (struct QBUFFER));
+			pcmdioctlfld->cmdioctl.ReturnCode = ARCMSR_IOCTL_RETURNCODE_OK;
+			if (copy_to_user(arg, pcmdioctlfld,
+				sizeof (struct CMD_IOCTL_FIELD)) != 0)
+				retvalue = -EFAULT;
+		}
+		break;
+	case ARCMSR_IOCTL_RETURN_CODE_3F: {
+			pcmdioctlfld->cmdioctl.ReturnCode = ARCMSR_IOCTL_RETURNCODE_3F;
+			if (copy_to_user(arg, pcmdioctlfld,
+				sizeof (struct CMD_IOCTL_FIELD)) != 0)
+				retvalue = -EFAULT;
+		}
+		break;
+	case ARCMSR_IOCTL_SAY_HELLO: {
+			int8_t * hello_string = "Hello! I am ARCMSR";
+
+			memcpy(pcmdioctlfld->ioctldatabuffer, hello_string
+				, (int16_t)strlen(hello_string));
+			pcmdioctlfld->cmdioctl.ReturnCode = ARCMSR_IOCTL_RETURNCODE_OK;
+			if (copy_to_user(arg, pcmdioctlfld,
+				sizeof (struct CMD_IOCTL_FIELD)) != 0)
+				retvalue = -EFAULT;
+		}
+		break;
+	case ARCMSR_IOCTL_SAY_GOODBYE:
+		arcmsr_iop_parking(pACB);
+		break;
+	case ARCMSR_IOCTL_FLUSH_ADAPTER_CACHE:
+		arcmsr_flush_adapter_cache(pACB);
+		break;
+	default:
+		retvalue = -EFAULT;
+	}
+ioctl_out:
+	pci_free_consistent(pACB->pci_device, sizeof (struct CMD_IOCTL_FIELD),
+			pcmdioctlfld, cmd_handle);
+	spin_unlock_irqrestore(&pACB->qbuffer_lock, flags);
+	return retvalue;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static int arcmsr_ioctl(struct scsi_device *dev, int ioctl_cmd, void __user * arg)
+{
+	struct ACB *pACB;
+	struct HCBARC *pHCBARC = &arcmsr_host_control_block;
+	int32_t match = 0x55AA, i;
+
+	for(i = 0; i < ARCMSR_MAX_ADAPTER; i++) {
+		pACB = pHCBARC->pACB[i];
+		if (pACB) {
+			if (pACB->host == dev->host) {
+				match = i;
+				break;
+			}
+		}
+	}
+	if (match == 0x55AA)
+		return -ENXIO;
+	if (!arg)
+		return -EINVAL;
+	return(arcmsr_iop_ioctlcmd(pACB, ioctl_cmd, arg));
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static struct CCB *arcmsr_get_freeccb(struct ACB *pACB)
+{
+	unsigned long flags;
+	struct list_head *head = &pACB->ccb_free_list;
+	struct CCB *pCCB = NULL;
+
+	spin_lock_irqsave(&pACB->working_list_lock, flags);
+	if (!list_empty(head)) {
+		pCCB = list_entry(head->next, struct CCB, list);
+		list_del(head->next);
+	}
+	spin_unlock_irqrestore(&pACB->working_list_lock, flags);
+	return pCCB;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static int arcmsr_queue_command(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
+{
+	struct Scsi_Host *host = cmd->device->host;
+	struct ACB *pACB = (struct ACB *) host->hostdata;
+	struct CCB *pCCB;
+	int target = cmd->device->id;
+	int lun = cmd->device->lun;
+
+	cmd->scsi_done = done;
+	cmd->host_scribble = NULL;
+	cmd->result = 0;
+	if (cmd->cmnd[0] == SYNCHRONIZE_CACHE) {
+		/*
+		** 0x35 avoid synchronizing disk cache cmd after
+		** .remove : arcmsr_device_remove (linux bug)
+		*/
+		if (pACB->devstate[target][lun] == ARECA_RAID_GONE)
+			cmd->result = (DID_NO_CONNECT << 16);
+		cmd->scsi_done(cmd);
+		return 0;
+	}
+	if (pACB->acb_flags & ACB_F_BUS_RESET) {
+		printk(KERN_NOTICE "arcmsr%d: bus reset"
+			" and return busy \n"
+			, pACB->adapter_index);
+		cmd->result = (DID_BUS_BUSY << 16);
+		cmd->scsi_done(cmd);
+		return 0;
+	}
+	if (pACB->devstate[target][lun] == ARECA_RAID_GONE) {
+		uint8_t block_cmd;
+
+		block_cmd = cmd->cmnd[0] & 0x0f;
+		if (block_cmd == 0x08 || block_cmd == 0x0a) {
+			printk(KERN_NOTICE
+				"arcmsr%d: block 'read/write'"
+				"command with gone raid volume"
+				" Cmd=%2x, TargetId=%d, Lun=%d \n"
+				, pACB->adapter_index
+				, cmd->cmnd[0]
+				, target
+				, lun);
+			cmd->result = (DID_NO_CONNECT << 16);
+			cmd->scsi_done(cmd);
+			return 0;
+		}
+	}
+	arcmsr_post_pendingccb(pACB);
+	pCCB = arcmsr_get_freeccb(pACB);
+	if (pCCB) {
+		arcmsr_build_ccb(pACB, pCCB, cmd);
+		if (atomic_read(&pACB->ccboutstandingcount) < ARCMSR_MAX_OUTSTANDING_CMD) {
+			arcmsr_post_ccb(pACB, pCCB);
+			return 0;
+		}
+		arcmsr_queue_pendingccb(pACB, pCCB);
+		return 0;
+	}
+	printk(KERN_NOTICE
+		"arcmsr%d: 'out of ccbs resource' ccb outstanding=%d pending=%d \n"
+		, pACB->adapter_index
+		, atomic_read(&pACB->ccboutstandingcount)
+		, atomic_read(&pACB->ccbpendingcount));
+	cmd->result = (DID_BUS_BUSY << 16);
+	cmd->scsi_done(cmd);
+	return 0;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_get_firmware_spec(struct ACB *pACB)
+{
+	struct MU __iomem *reg = pACB->pmu;
+	char *acb_firm_model = pACB->firm_model;
+	char *acb_firm_version = pACB->firm_version;
+	char __iomem *iop_firm_model = (char __iomem *) &reg->message_rwbuffer[15];
+	char __iomem *iop_firm_version = (char __iomem *) &reg->message_rwbuffer[17];
+	int count;
+
+	writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
+	if (arcmsr_wait_msgint_ready(pACB))
+		printk(KERN_NOTICE
+			"arcmsr%d: wait "
+			"'get adapter firmware miscellaneous data' timeout \n"
+			, pACB->adapter_index);
+	count = 8;
+	while (count) {
+		*acb_firm_model = readb(iop_firm_model);
+		acb_firm_model++;
+		iop_firm_model++;
+		count--;
+	}
+	count = 16;
+	while (count) {
+		*acb_firm_version = readb(iop_firm_version);
+		acb_firm_version++;
+		iop_firm_version++;
+		count--;
+	}
+	printk(KERN_INFO
+		"ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n"
+		, pACB->adapter_index
+		, pACB->firm_version);
+	pACB->firm_request_len = readl(&reg->message_rwbuffer[1]);
+	pACB->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);
+	pACB->firm_sdram_size = readl(&reg->message_rwbuffer[3]);
+	pACB->firm_ide_channels = readl(&reg->message_rwbuffer[4]);
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_start_adapter_bgrb(struct ACB *pACB)
+{
+	struct MU __iomem *reg = pACB->pmu;
+	pACB->acb_flags |= ACB_F_MSG_START_BGRB;
+	writel(ARCMSR_INBOUND_MESG0_START_BGRB, &reg->inbound_msgaddr0);
+	if (arcmsr_wait_msgint_ready(pACB))
+		printk(KERN_NOTICE
+			"arcmsr%d: wait 'start adapter background rebulid' timeout \n"
+			, pACB->adapter_index);
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_polling_ccbdone(struct ACB *pACB, struct CCB *poll_ccb)
+{
+	struct MU __iomem *reg = pACB->pmu;
+	struct CCB *pCCB;
+	uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0;
+	int id, lun;
+
+polling_ccb_retry:
+	poll_count++;
+	outbound_intstatus = readl(&reg->outbound_intstatus)
+					& pACB->outbound_int_enable;
+	writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
+	while (1) {
+		if ((flag_ccb = readl(&reg->outbound_queueport)) == 0xFFFFFFFF) {
+			if (poll_ccb_done)
+				break;
+			else {
+				msleep(25);
+				if (poll_count > 100)
+					break;
+				goto polling_ccb_retry;
+			}
+		}
+		pCCB = (struct CCB *)(pACB->vir2phy_offset + (flag_ccb << 5));
+		if ((pCCB->pACB != pACB) || (pCCB->startdone != ARCMSR_CCB_START)) {
+			if ((pCCB->startdone == ARCMSR_CCB_ABORTED) && (pCCB == poll_ccb)) {
+				printk(KERN_NOTICE
+					"arcmsr%d: scsi id=%d lun=%d ccb='0x%p'"
+					" poll command abort successfully \n"
+					, pACB->adapter_index
+					, pCCB->pcmd->device->id
+					, pCCB->pcmd->device->lun
+					, pCCB);
+				pCCB->pcmd->result = DID_ABORT << 16;
+				arcmsr_ccb_complete(pCCB, 1);
+				poll_ccb_done = 1;
+				continue;
+			}
+			printk(KERN_NOTICE
+				"arcmsr%d: polling get an illegal ccb"
+				" command done ccb='0x%p'"
+				"ccboutstandingcount=%d \n"
+				, pACB->adapter_index
+				, pCCB
+				, atomic_read(&pACB->ccboutstandingcount));
+			continue;
+		}
+		id = pCCB->pcmd->device->id;
+		lun = pCCB->pcmd->device->lun;
+		if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
+			if (pACB->devstate[id][lun] == ARECA_RAID_GONE)
+				pACB->devstate[id][lun] = ARECA_RAID_GOOD;
+			pCCB->pcmd->result = DID_OK << 16;
+			arcmsr_ccb_complete(pCCB, 1);
+		} else {
+			switch(pCCB->arcmsr_cdb.DeviceStatus) {
+			case ARCMSR_DEV_SELECT_TIMEOUT: {
+					pACB->devstate[id][lun] = ARECA_RAID_GONE;
+					pCCB->pcmd->result = DID_TIME_OUT << 16;
+					arcmsr_ccb_complete(pCCB, 1);
+				}
+				break;
+			case ARCMSR_DEV_ABORTED:
+			case ARCMSR_DEV_INIT_FAIL: {
+					pACB->devstate[id][lun] = ARECA_RAID_GONE;
+					pCCB->pcmd->result = DID_BAD_TARGET << 16;
+					arcmsr_ccb_complete(pCCB, 1);
+				}
+				break;
+			case SCSISTAT_CHECK_CONDITION: {
+					pACB->devstate[id][lun] = ARECA_RAID_GOOD;
+					arcmsr_report_sense_info(pCCB);
+					arcmsr_ccb_complete(pCCB, 1);
+				}
+				break;
+			default:
+				printk(KERN_NOTICE
+					"arcmsr%d: scsi id=%d lun=%d"
+					" polling and getting command error done"
+					"but got unknown DeviceStatus = 0x%x \n"
+					, pACB->adapter_index
+					, id
+					, lun
+					, pCCB->arcmsr_cdb.DeviceStatus);
+				pACB->devstate[id][lun] = ARECA_RAID_GONE;
+				pCCB->pcmd->result = DID_BAD_TARGET << 16;
+				arcmsr_ccb_complete(pCCB, 1);
+				break;
+			}
+		}
+	}
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_iop_init(struct ACB *pACB)
+{
+	struct MU __iomem *reg = pACB->pmu;
+	uint32_t intmask_org, mask, outbound_doorbell, firmware_state = 0;
+
+	do {
+		firmware_state = readl(&reg->outbound_msgaddr1);
+	} while (!(firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK));
+	intmask_org = readl(&reg->outbound_intmask)
+			| ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE;
+	arcmsr_get_firmware_spec(pACB);
+	arcmsr_start_adapter_bgrb(pACB);
+	outbound_doorbell = readl(&reg->outbound_doorbell);
+	writel(outbound_doorbell, &reg->outbound_doorbell);
+	writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
+	mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE
+			| ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
+	writel(intmask_org & mask, &reg->outbound_intmask);
+	pACB->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff;
+	pACB->acb_flags |= ACB_F_IOP_INITED;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
+{
+	struct ACB *pACB;
+	int retry = 0;
+
+	pACB = (struct ACB *) cmd->device->host->hostdata;
+	printk(KERN_NOTICE "arcmsr%d: bus reset ..... \n", pACB->adapter_index);
+	pACB->num_resets++;
+	pACB->acb_flags |= ACB_F_BUS_RESET;
+	while (atomic_read(&pACB->ccboutstandingcount) != 0 && retry < 400) {
+		arcmsr_interrupt(pACB);
+		msleep(25);
+		retry++;
+	}
+	arcmsr_iop_reset(pACB);
+	pACB->acb_flags &= ~ACB_F_BUS_RESET;
+	return SUCCESS;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static int arcmsr_seek_cmd2abort(struct scsi_cmnd *abortcmd)
+{
+	struct ACB *pACB = (struct ACB *) abortcmd->device->host->hostdata;
+	struct MU __iomem *reg = pACB->pmu;
+	struct CCB *pCCB;
+	uint32_t intmask_org, mask;
+	int i = 0, pendingcount;
+
+	pACB->num_aborts++;
+	/*
+	*****************************************************************
+	** It is the upper layer do abort command this lock just prior
+	** to calling us.
+	** First determine if we currently own this command.
+	** Start by searching the device queue. If not found
+	** at all, and the system wanted us to just abort the
+	** command return success.
+	*****************************************************************
+	*/
+	if (atomic_read(&pACB->ccboutstandingcount) != 0) {
+		for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+			pCCB = pACB->pccb_pool[i];
+			if (pCCB->startdone == ARCMSR_CCB_START) {
+				if (pCCB->pcmd == abortcmd) {
+					pCCB->startdone = ARCMSR_CCB_ABORTED;
+					printk(KERN_NOTICE
+					"arcmsr%d: scsi id=%d lun=%d"
+					" abort ccb '0x%p' outstanding command\n"
+					, pACB->adapter_index
+					, abortcmd->device->id
+					, abortcmd->device->lun
+					, pCCB);
+					goto abort_outstanding_cmd;
+				}
+			}
+		}
+	}
+	/*
+	**********************************************************
+	** seek this command at our command list
+	** if command found then remove, abort it and free this CCB
+	**********************************************************
+	*/
+	pendingcount = atomic_read(&pACB->ccbpendingcount);
+	if (pendingcount > 0) {
+		do {
+			pCCB = arcmsr_get_pendingccb(pACB);
+			if (!pCCB)
+				break;
+			if (pCCB->pcmd == abortcmd) {
+				printk(KERN_NOTICE
+					"arcmsr%d: scsi id=%d lun=%d"
+					" abort ccb '0x%p' pending command \n"
+					, pACB->adapter_index
+					, abortcmd->device->id
+					, abortcmd->device->lun
+					, pCCB);
+				pCCB->startdone = ARCMSR_CCB_ABORTED;
+				pCCB->pcmd->result = DID_ABORT << 16;
+				arcmsr_ccb_complete(pCCB, 0);
+				return SUCCESS;
+			} else
+				arcmsr_queue_pendingccb(pACB, pCCB);
+		} while (pendingcount--);
+	}
+	return SUCCESS;
+abort_outstanding_cmd:
+	/*wait for 3 sec for all command done*/
+	msleep_interruptible(3000);
+	/* disable all outbound interrupt */
+	intmask_org = readl(&reg->outbound_intmask);
+	writel(intmask_org | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE
+		, &reg->outbound_intmask);
+	arcmsr_polling_ccbdone(pACB, pCCB);
+	/* enable all outbound interrupt */
+	mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE
+			| ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
+	writel(intmask_org & mask, &reg->outbound_intmask);
+	return SUCCESS;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static int arcmsr_cmd_abort(struct scsi_cmnd *cmd)
+{
+	struct ACB *pACB = (struct ACB *) cmd->device->host->hostdata;
+	int error;
+
+	printk(KERN_NOTICE
+		"arcmsr%d: abort device command of scsi id=%d lun=%d \n"
+		, pACB->adapter_index
+		, cmd->device->id
+		, cmd->device->lun);
+	/*
+	************************************************
+	** the all interrupt service routine is locked
+	** we need to handle it as soon as possible and exit
+	************************************************
+	*/
+	error = arcmsr_seek_cmd2abort(cmd);
+	if (error != SUCCESS)
+		printk(KERN_NOTICE
+		"arcmsr%d: abort command failed scsi id=%d lun=%d \n"
+		, pACB->adapter_index
+		, cmd->device->id
+		, cmd->device->lun);
+	return error;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static const char *arcmsr_info(struct Scsi_Host *host)
+{
+	static char buf[256];
+	struct ACB *pACB;
+	uint16_t device_id;
+
+	pACB = (struct ACB *) host->hostdata;
+	device_id = pACB->pci_device->device;
+	switch(device_id) {
+	case PCIDeviceIDARC1110: {
+			sprintf(buf,
+			"ARECA ARC1110 PCI-X 4 PORTS SATA RAID CONTROLLER "
+			"\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCIDeviceIDARC1120: {
+			sprintf(buf,
+			"ARECA ARC1120 PCI-X 8 PORTS SATA RAID CONTROLLER "
+			"(RAID6-ENGINE Inside)\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCIDeviceIDARC1130: {
+			sprintf(buf,
+			"ARECA ARC1130 PCI-X 12 PORTS SATA RAID CONTROLLER "
+			"(RAID6-ENGINE Inside)\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCIDeviceIDARC1160: {
+			sprintf(buf,
+			"ARECA ARC1160 PCI-X 16 PORTS SATA RAID CONTROLLER "
+			"(RAID6-ENGINE Inside)\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCIDeviceIDARC1170: {
+			sprintf(buf,
+			"ARECA ARC1170 PCI-X 24 PORTS SATA RAID CONTROLLER "
+			"(RAID6-ENGINE Inside)\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCIDeviceIDARC1210: {
+			sprintf(buf,
+			"ARECA ARC1210 PCI-EXPRESS 4 PORTS SATA RAID CONTROLLER "
+			"\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCIDeviceIDARC1220: {
+			sprintf(buf,
+			"ARECA ARC1220 PCI-EXPRESS 8 PORTS SATA RAID CONTROLLER "
+			"(RAID6-ENGINE Inside)\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCIDeviceIDARC1230: {
+			sprintf(buf,
+			"ARECA ARC1230 PCI-EXPRESS 12 PORTS SATA RAID CONTROLLER "
+			"(RAID6-ENGINE Inside)\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCIDeviceIDARC1260: {
+			sprintf(buf,
+			"ARECA ARC1260 PCI-EXPRESS 16 PORTS SATA RAID CONTROLLER "
+			"(RAID6-ENGINE Inside)\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCIDeviceIDARC1270: {
+			sprintf(buf,
+			"ARECA ARC1270 PCI-EXPRESS 24 PORTS SATA RAID CONTROLLER "
+			"(RAID6-ENGINE Inside)\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCIDeviceIDARC1280:
+	default: {
+			sprintf(buf,
+			"ARECA X-TYPE SATA RAID CONTROLLER "
+			"(RAID6-ENGINE Inside)\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	}
+	return buf;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static int arcmsr_initialize(struct ACB *pACB, struct pci_dev *pci_device)
+{
+	struct MU __iomem *reg;
+	uint32_t intmask_org, ccb_phyaddr_hi32;
+	dma_addr_t dma_coherent_handle, dma_addr;
+	struct HCBARC *pHCBARC = &arcmsr_host_control_block;
+	uint8_t pcicmd;
+	void *dma_coherent;
+	void __iomem *page_remapped;
+	int i, j;
+	struct CCB *pccb_tmp;
+
+	pci_read_config_byte(pci_device, PCI_COMMAND, &pcicmd);
+	pci_write_config_byte(pci_device, PCI_COMMAND,
+		pcicmd | PCI_COMMAND_INVALIDATE | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+	page_remapped = ioremap(pci_resource_start(pci_device, 0),
+		pci_resource_len(pci_device, 0));
+	if ( !page_remapped ) {
+		printk(KERN_NOTICE "arcmsr%d: memory"
+			" mapping region fail \n", arcmsr_adapterCnt);
+		return -ENXIO;
+	}
+	pACB->pmu = (struct MU __iomem *)(page_remapped);
+	pACB->acb_flags |=
+		(ACB_F_IOCTL_WQBUFFER_CLEARED
+		| ACB_F_IOCTL_RQBUFFER_CLEARED
+		| ACB_F_IOCTL_WQBUFFER_READED);
+	pACB->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
+	pACB->irq = pci_device->irq;
+	INIT_LIST_HEAD(&pACB->ccb_free_list);
+	INIT_LIST_HEAD(&pACB->ccb_pending_list);
+	dma_coherent = dma_alloc_coherent(&pci_device->dev
+		, ARCMSR_MAX_FREECCB_NUM * sizeof (struct CCB) + 0x20
+		, &dma_coherent_handle, GFP_KERNEL);
+	if (!dma_coherent) {
+		printk(KERN_NOTICE
+			"arcmsr%d: dma_alloc_coherent got error \n"
+			, arcmsr_adapterCnt);
+		return -ENOMEM;
+	}
+	pACB->dma_coherent = dma_coherent;
+	pACB->dma_coherent_handle = dma_coherent_handle;
+	memset(dma_coherent, 0, ARCMSR_MAX_FREECCB_NUM * sizeof (struct CCB) + 0x20);
+	if (((unsigned long)dma_coherent & 0x1F) != 0) {
+		dma_coherent = dma_coherent + (0x20 - ((unsigned long)dma_coherent & 0x1F));
+		dma_coherent_handle = dma_coherent_handle
+			+ (0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
+	}
+	dma_addr = dma_coherent_handle;
+	pccb_tmp = (struct CCB *)dma_coherent;
+	for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+		pccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
+		pccb_tmp->pACB = pACB;
+		pACB->pccb_pool[i] = pccb_tmp;
+		list_add_tail(&pccb_tmp->list, &pACB->ccb_free_list);
+		dma_addr = dma_addr + sizeof (struct CCB);
+		pccb_tmp++;
+	}
+	pACB->vir2phy_offset = (unsigned long)pccb_tmp - (unsigned long)dma_addr;
+	for(i = 0; i < ARCMSR_MAX_TARGETID; i++) {
+		for(j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
+			pACB->devstate[i][j] = ARECA_RAID_GOOD;
+	}
+	reg = pACB->pmu;
+	/*
+	*************************************************************
+	** here we need to tell iop 331 our pccb_tmp.HighPart
+	** if pccb_tmp.HighPart is not zero
+	*************************************************************
+	*/
+	ccb_phyaddr_hi32 = (uint32_t) ((dma_coherent_handle >> 16) >> 16);
+	if (ccb_phyaddr_hi32 != 0) {
+		writel(ARCMSR_SIGNATURE_SET_CONFIG, &reg->message_rwbuffer[0]);
+		writel(ccb_phyaddr_hi32, &reg->message_rwbuffer[1]);
+		writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, &reg->inbound_msgaddr0);
+		if (arcmsr_wait_msgint_ready(pACB))
+			printk(KERN_NOTICE
+				"arcmsr%d: 'set ccb high part physical address' timeout \n"
+				, arcmsr_adapterCnt);
+	}
+	pACB->adapter_index = arcmsr_adapterCnt;
+	pHCBARC->pACB[arcmsr_adapterCnt] = pACB;
+	intmask_org = readl(&reg->outbound_intmask);
+	writel(intmask_org | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE
+			, &reg->outbound_intmask);
+	arcmsr_adapterCnt++;
+	return 0;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static int arcmsr_set_info(char *buffer, int length)
+{
+	return 0;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static void arcmsr_pcidev_disattach(struct ACB *pACB)
+{
+	struct MU __iomem *reg = pACB->pmu;
+	struct pci_dev *pci_device;
+	struct CCB *pCCB;
+	struct HCBARC *pHCBARC = &arcmsr_host_control_block;
+	struct Scsi_Host *host;
+	uint32_t intmask_org;
+	int i = 0, poll_count = 0, have_msi = 0;
+
+	arcmsr_stop_adapter_bgrb(pACB);
+	arcmsr_flush_adapter_cache(pACB);
+	intmask_org = readl(&reg->outbound_intmask);
+	writel(intmask_org | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE
+			, &reg->outbound_intmask);
+	pACB->acb_flags |= ACB_F_SCSISTOPADAPTER;
+	pACB->acb_flags &= ~ACB_F_IOP_INITED;
+	if (atomic_read(&pACB->ccboutstandingcount) != 0) {
+		while (atomic_read(&pACB->ccboutstandingcount) != 0 && (poll_count < 256)) {
+			arcmsr_interrupt(pACB);
+			msleep(25);
+			poll_count++;
+		}
+		if (atomic_read(&pACB->ccboutstandingcount) != 0) {
+			arcmsr_abort_allcmd(pACB);
+			for(i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++)
+				readl(&reg->outbound_queueport);
+			for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+				pCCB = pACB->pccb_pool[i];
+				if (pCCB->startdone == ARCMSR_CCB_START) {
+					pCCB->startdone = ARCMSR_CCB_ABORTED;
+					pCCB->pcmd->result = DID_ABORT << 16;
+					arcmsr_ccb_complete(pCCB, 1);
+				}
+			}
+		}
+	}
+	while (atomic_read(&pACB->ccbpendingcount) != 0) {
+		pCCB = arcmsr_get_pendingccb(pACB);
+		if (pCCB) {
+			pCCB->startdone = ARCMSR_CCB_ABORTED;
+			pCCB->pcmd->result = DID_ABORT << 16;
+			arcmsr_ccb_complete(pCCB, 0);
+			atomic_dec(&pACB->ccbpendingcount);
+		} else
+			break;
+	}
+	if ((pACB->acb_flags & ACB_F_HAVE_MSI) != 0) {
+		have_msi = 1;
+	}
+	host = pACB->host;
+	pci_device = pACB->pci_device;
+	iounmap(pACB->pmu);
+	arcmsr_free_ccb_pool(pACB);
+	pHCBARC->pACB[pACB->adapter_index] = NULL;
+	scsi_remove_host(host);
+	scsi_host_put(host);
+	free_irq(pci_device->irq, pACB);
+#ifdef CONFIG_SCSI_ARCMSR_MSI
+	if (have_msi == 1)
+	    pci_disable_msi(pci_device);
+#endif
+	pci_release_regions(pci_device);
+	pci_disable_device(pci_device);
+	pci_set_drvdata(pci_device, NULL);
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static int arcmsr_halt_notify(struct notifier_block *nb, unsigned long event, void *buf)
+{
+	struct ACB *pACB;
+	struct HCBARC *pHCBARC = &arcmsr_host_control_block;
+	int i;
+
+	if ((event != SYS_RESTART) && (event != SYS_HALT) && (event != SYS_POWER_OFF))
+		return NOTIFY_DONE;
+	for(i = 0; i < ARCMSR_MAX_ADAPTER; i++) {
+		pACB = pHCBARC->pACB[i];
+		if (!pACB)
+			continue;
+		arcmsr_pcidev_disattach(pACB);
+	}
+	unregister_chrdev(pHCBARC->arcmsr_major_number, "arcmsr");
+	unregister_reboot_notifier(&arcmsr_event_notifier);
+	return NOTIFY_OK;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+#undef SPRINTF
+#define SPRINTF(args...) pos +=sprintf(pos,## args)
+#define YESNO(YN)\
+if (YN) SPRINTF(" Yes ");\
+else SPRINTF(" No ")
+
+static int arcmsr_proc_info(struct Scsi_Host *host, char *buffer,
+	char **start, off_t offset, int length, int inout)
+{
+	uint8_t  i;
+	struct HCBARC *pHCBARC = &arcmsr_host_control_block;
+	char * pos = buffer;
+	struct ACB *pACB;
+
+	if (inout)
+		return(arcmsr_set_info(buffer, length));
+	for(i = 0; i < ARCMSR_MAX_ADAPTER; i++) {
+		pACB = pHCBARC->pACB[i];
+		if (!pACB)
+			continue;
+		SPRINTF("ARECA SATA RAID Mass Storage Host Adadpter \n");
+		SPRINTF("Driver Version %s ", ARCMSR_DRIVER_VERSION);
+		SPRINTF("IRQ%d \n", pACB->pci_device->irq);
+		SPRINTF("===========================\n");
+	}
+	*start = buffer + offset;
+	if (pos - buffer < offset)
+		return 0;
+	else if (pos - buffer - offset < length)
+		return pos - buffer - offset;
+	return length;
+}
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+static int arcmsr_release(struct Scsi_Host *host)
+{
+	struct ACB *pACB;
+	struct HCBARC *pHCBARC = &arcmsr_host_control_block;
+	uint8_t match = 0xff, i;
+
+	if (!host)
+		return -ENXIO;
+	pACB = (struct ACB *)host->hostdata;
+	if (!pACB)
+		return -ENXIO;
+	for(i = 0; i < ARCMSR_MAX_ADAPTER; i++) {
+		if (pHCBARC->pACB[i] == pACB)
+			match = i;
+	}
+	if (match == 0xff)
+		return -ENXIO;
+	arcmsr_pcidev_disattach(pACB);
+	for(i = 0; i < ARCMSR_MAX_ADAPTER; i++) {
+		if (pHCBARC->pACB[i])
+			return 0;
+	}
+	unregister_chrdev(pHCBARC->arcmsr_major_number, "arcmsr");
+	unregister_reboot_notifier(&arcmsr_event_notifier);
+	return 0;
+}
+
diff -urN oldtree/drivers/scsi/arcmsr/arcmsr.h newtree/drivers/scsi/arcmsr/arcmsr.h
--- oldtree/drivers/scsi/arcmsr/arcmsr.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/scsi/arcmsr/arcmsr.h	2006-02-21 15:58:20.128086624 +0000
@@ -0,0 +1,1242 @@
+/*
+*******************************************************************************
+**        O.S   : Linux
+**   FILE NAME  : arcmsr.h
+**        BY    : Erich Chen
+**   Description: SCSI RAID Device Driver for
+**                ARECA RAID Host adapter
+*******************************************************************************
+** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved.
+**
+**     Web site: www.areca.com.tw
+**       E-mail: erich@areca.com.tw
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License version 2 as
+** published by the Free Software Foundation.
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+*******************************************************************************
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+**    derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+**(INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************
+*/
+#define ARCMSR_MAX_OUTSTANDING_CMD 						256
+#define ARCMSR_MAX_PENDING_CMD							 64
+#define ARCMSR_MAX_FREECCB_NUM							320
+#define ARCMSR_DRIVER_VERSION				"Driver Version 1.20.00.13"
+#define ARCMSR_SCSI_INITIATOR_ID						255
+#define ARCMSR_DEV_SECTOR_SIZE							512
+#define ARCMSR_MAX_XFER_SECTORS							256
+#define ARCMSR_MAX_XFER_LEN	   ARCMSR_MAX_XFER_SECTORS * ARCMSR_DEV_SECTOR_SIZE
+#define ARCMSR_MAX_TARGETID							 16
+#define ARCMSR_MAX_TARGETLUN							  8
+#define ARCMSR_MAX_CMD_PERLUN				 ARCMSR_MAX_OUTSTANDING_CMD
+#define ARCMSR_MAX_QBUFFER						       4096
+#define ARCMSR_MAX_SG_ENTRIES							 38
+#define ARCMSR_MAX_ADAPTER							  4
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+#define PCIVendorIDARECA       0x17D3 /* Vendor ID */
+#define PCIDeviceIDARC1110     0x1110 /* Device ID */
+#define PCIDeviceIDARC1120     0x1120 /* Device ID */
+#define PCIDeviceIDARC1130     0x1130 /* Device ID */
+#define PCIDeviceIDARC1160     0x1160 /* Device ID */
+#define PCIDeviceIDARC1170     0x1170 /* Device ID */
+#define PCIDeviceIDARC1210     0x1210 /* Device ID */
+#define PCIDeviceIDARC1220     0x1220 /* Device ID */
+#define PCIDeviceIDARC1230     0x1230 /* Device ID */
+#define PCIDeviceIDARC1260     0x1260 /* Device ID */
+#define PCIDeviceIDARC1270     0x1270 /* Device ID */
+#define PCIDeviceIDARC1280     0x1280 /* Device ID */
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+#define dma_addr_hi32(addr)               (uint32_t) ((addr>>16)>>16)
+#define dma_addr_lo32(addr)               (uint32_t) (addr & 0xffffffff)
+/*
+*******************************************************************************
+**        IOCTL CONTROL CODE
+*******************************************************************************
+*/
+struct CMD_IO_CONTROL
+{
+      uint32_t HeaderLength;
+      uint8_t  Signature[8];
+      uint32_t Timeout;
+      uint32_t ControlCode;
+      uint32_t ReturnCode;
+      uint32_t Length;
+};
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+struct CMD_IOCTL_FIELD
+{
+    struct CMD_IO_CONTROL			cmdioctl;
+    uint8_t					ioctldatabuffer[1032];
+};
+
+#define ARCMSR_IOP_ERROR_ILLEGALPCI		0x0001
+#define ARCMSR_IOP_ERROR_VENDORID		0x0002
+#define ARCMSR_IOP_ERROR_DEVICEID		0x0002
+#define ARCMSR_IOP_ERROR_ILLEGALCDB		0x0003
+#define ARCMSR_IOP_ERROR_UNKNOW_CDBERR		0x0004
+#define ARCMSR_SYS_ERROR_MEMORY_ALLOCATE	0x0005
+#define ARCMSR_SYS_ERROR_MEMORY_CROSS4G		0x0006
+#define ARCMSR_SYS_ERROR_MEMORY_LACK		0x0007
+#define ARCMSR_SYS_ERROR_MEMORY_RANGE		0x0008
+#define ARCMSR_SYS_ERROR_DEVICE_BASE		0x0009
+#define ARCMSR_SYS_ERROR_PORT_VALIDATE		0x000A
+/*DeviceType*/
+#define ARECA_SATA_RAID				0x90000000
+/*FunctionCode*/
+#define FUNCTION_READ_RQBUFFER			0x0801
+#define FUNCTION_WRITE_WQBUFFER			0x0802
+#define FUNCTION_CLEAR_RQBUFFER			0x0803
+#define FUNCTION_CLEAR_WQBUFFER			0x0804
+#define FUNCTION_CLEAR_ALLQBUFFER		0x0805
+#define FUNCTION_RETURN_CODE_3F			0x0806
+#define FUNCTION_SAY_HELLO			0x0807
+#define FUNCTION_SAY_GOODBYE			0x0808
+#define FUNCTION_FLUSH_ADAPTER_CACHE		0x0809
+/* ARECA IO CONTROL CODE*/
+#define ARCMSR_IOCTL_READ_RQBUFFER       \
+	ARECA_SATA_RAID | FUNCTION_READ_RQBUFFER
+#define ARCMSR_IOCTL_WRITE_WQBUFFER      \
+	ARECA_SATA_RAID | FUNCTION_WRITE_WQBUFFER
+#define ARCMSR_IOCTL_CLEAR_RQBUFFER      \
+	ARECA_SATA_RAID | FUNCTION_CLEAR_RQBUFFER
+#define ARCMSR_IOCTL_CLEAR_WQBUFFER      \
+	ARECA_SATA_RAID | FUNCTION_CLEAR_WQBUFFER
+#define ARCMSR_IOCTL_CLEAR_ALLQBUFFER    \
+	ARECA_SATA_RAID | FUNCTION_CLEAR_ALLQBUFFER
+#define ARCMSR_IOCTL_RETURN_CODE_3F      \
+	ARECA_SATA_RAID | FUNCTION_RETURN_CODE_3F
+#define ARCMSR_IOCTL_SAY_HELLO           \
+	ARECA_SATA_RAID | FUNCTION_SAY_HELLO
+#define ARCMSR_IOCTL_SAY_GOODBYE         \
+	ARECA_SATA_RAID | FUNCTION_SAY_GOODBYE
+#define ARCMSR_IOCTL_FLUSH_ADAPTER_CACHE \
+	ARECA_SATA_RAID | FUNCTION_FLUSH_ADAPTER_CACHE
+/* ARECA IOCTL ReturnCode */
+#define ARCMSR_IOCTL_RETURNCODE_OK              0x00000001
+#define ARCMSR_IOCTL_RETURNCODE_ERROR           0x00000006
+#define ARCMSR_IOCTL_RETURNCODE_3F              0x0000003F
+/*
+*************************************************************
+**   structure for holding DMA address data
+*************************************************************
+*/
+#define IS_SG64_ADDR                0x01000000 /* bit24 */
+struct  SG32ENTRY
+{
+	uint32_t					length;
+	uint32_t					address;
+};
+struct  SG64ENTRY
+{
+ 	uint32_t					length;
+ 	uint32_t					address;
+ 	uint32_t					addresshigh;
+};
+struct SGENTRY_UNION
+{
+	union
+	{
+		struct SG32ENTRY            sg32entry;
+		struct SG64ENTRY            sg64entry;
+	}u;
+};
+/*
+**********************************
+**********************************
+*/
+struct QBUFFER
+{
+	uint32_t      data_len;
+	uint8_t       data[124];
+};
+/*
+*******************************************************************************
+**      FIRMWARE INFO
+*******************************************************************************
+*/
+struct FIRMWARE_INFO
+{
+	uint32_t      signature;                /*0, 00-03*/
+	uint32_t      request_len;              /*1, 04-07*/
+	uint32_t      numbers_queue;            /*2, 08-11*/
+	uint32_t      sdram_size;               /*3, 12-15*/
+	uint32_t      ide_channels;             /*4, 16-19*/
+	char          vendor[40];               /*5, 20-59*/
+	char          model[8];                 /*15, 60-67*/
+	char          firmware_ver[16];         /*17, 68-83*/
+	char          device_map[16];           /*21, 84-99*/
+};
+/*
+*******************************************************************************
+**                            ARECA FIRMWARE SPEC
+*******************************************************************************
+**		Usage of IOP331 adapter
+**		(All In/Out is in IOP331's view)
+**		1. Message 0 --> InitThread message and retrun code
+**		2. Doorbell is used for RS-232 emulation
+**				inDoorBell :    bit0 -- data in ready
+**					(DRIVER DATA WRITE OK)
+**							bit1 -- data out has been read
+**					(DRIVER DATA READ OK)
+**				outDooeBell:    bit0 -- data out ready
+**					(IOP331 DATA WRITE OK)
+**							bit1 -- data in has been read
+**					(IOP331 DATA READ OK)
+**		3. Index Memory Usage
+**			offset 0xf00 : for RS232 out (request buffer)
+**			offset 0xe00 : for RS232 in  (scratch buffer)
+**			offset 0xa00 : for inbound message code message_rwbuffer
+**					(driver send to IOP331)
+**			offset 0xa00 : for outbound message code message_rwbuffer
+**					(IOP331 send to driver)
+**		4. RS-232 emulation
+**			Currently 128 byte buffer is used
+**				1st uint32_t : Data length (1--124)
+**				Byte 4--127  : Max 124 bytes of data
+**		5. PostQ
+**		All SCSI Command must be sent through postQ:
+**		(inbound queue port)	Request frame must be 32 bytes aligned
+**		#bit27--bit31 => flag for post ccb
+**		#bit0--bit26  => real address (bit27--bit31) of post arcmsr_cdb
+**				bit31 :
+**					0 : 256 bytes frame
+**					1 : 512 bytes frame
+**				bit30 :
+**					0 : normal request
+**					1 : BIOS request
+**				bit29 : reserved
+**				bit28 : reserved
+**				bit27 : reserved
+**  ---------------------------------------------------------------------------
+**		(outbount queue port)	Request reply
+**		#bit27--bit31
+**			=> flag for reply
+**		#bit0--bit26
+**			=> real address (bit27--bit31) of reply arcmsr_cdb
+**				bit31 : must be 0 (for this type of reply)
+**				bit30 : reserved for BIOS handshake
+**				bit29 : reserved
+**				bit28 :
+**				0 : no error, ignore AdapStatus/DevStatus/SenseData
+**				1 : Error, error code in AdapStatus/DevStatus/SenseData
+**				bit27 : reserved
+**		6. BIOS request
+**			All BIOS request is the same with request from PostQ
+**			Except :
+**				Request frame is sent from configuration space
+**			offset: 0x78 : Request Frame (bit30 == 1)
+**			offset: 0x18 : writeonly to generate
+**						IRQ to IOP331
+**			Completion of request:
+**			(bit30 == 0, bit28==err flag)
+**		7. Definition of SGL entry (structure)
+**		8. Message1 Out - Diag Status Code (????)
+**		9. Message0 message code :
+**			0x00 : NOP
+**			0x01 : Get Config
+**			->offset 0xa00 :for outbound message code message_rwbuffer
+**			(IOP331 send to driver)
+**			Signature             0x87974060(4)
+**			Request len           0x00000200(4)
+**			numbers of queue      0x00000100(4)
+**			SDRAM Size            0x00000100(4)-->256 MB
+**			IDE Channels          0x00000008(4)
+**			vendor                40 bytes char
+**			model                  8 bytes char
+**			FirmVer               16 bytes char
+**			Device Map            16 bytes char
+**			FirmwareVersion DWORD <== Added for checking of
+**							new firmware capability
+**			0x02 : Set Config
+**			->offset 0xa00 :for inbound message code message_rwbuffer
+**			(driver send to IOP331)
+**			Signature             0x87974063(4)
+**			UPPER32 of Request Frame  (4)-->Driver Only
+**			0x03 : Reset (Abort all queued Command)
+**			0x04 : Stop Background Activity
+**			0x05 : Flush Cache
+**			0x06 : Start Background Activity
+**				(re-start if background is halted)
+**			0x07 : Check If Host Command Pending
+**				(Novell May Need This Function)
+**			0x08 : Set controller time
+**			->offset 0xa00 : for inbound message code message_rwbuffer
+**			(driver to IOP331)
+**			byte 0 : 0xaa <-- signature
+**			byte 1 : 0x55 <-- signature
+**			byte 2 : year (04)
+**			byte 3 : month (1..12)
+**			byte 4 : date (1..31)
+**			byte 5 : hour (0..23)
+**			byte 6 : minute (0..59)
+**			byte 7 : second (0..59)
+*******************************************************************************
+*/
+/* signature of set and get firmware config */
+#define ARCMSR_SIGNATURE_GET_CONFIG                   0x87974060
+#define ARCMSR_SIGNATURE_SET_CONFIG                   0x87974063
+/* message code of inbound message register */
+#define ARCMSR_INBOUND_MESG0_NOP                      0x00000000
+#define ARCMSR_INBOUND_MESG0_GET_CONFIG               0x00000001
+#define ARCMSR_INBOUND_MESG0_SET_CONFIG               0x00000002
+#define ARCMSR_INBOUND_MESG0_ABORT_CMD                0x00000003
+#define ARCMSR_INBOUND_MESG0_STOP_BGRB                0x00000004
+#define ARCMSR_INBOUND_MESG0_FLUSH_CACHE              0x00000005
+#define ARCMSR_INBOUND_MESG0_START_BGRB               0x00000006
+#define ARCMSR_INBOUND_MESG0_CHK331PENDING            0x00000007
+#define ARCMSR_INBOUND_MESG0_SYNC_TIMER               0x00000008
+/* doorbell interrupt generator */
+#define ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK           0x00000001
+#define ARCMSR_INBOUND_DRIVER_DATA_READ_OK            0x00000002
+#define ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK          0x00000001
+#define ARCMSR_OUTBOUND_IOP331_DATA_READ_OK           0x00000002
+/* ccb areca cdb flag */
+#define ARCMSR_CCBPOST_FLAG_SGL_BSIZE                 0x80000000
+#define ARCMSR_CCBPOST_FLAG_IAM_BIOS                  0x40000000
+#define ARCMSR_CCBREPLY_FLAG_IAM_BIOS                 0x40000000
+#define ARCMSR_CCBREPLY_FLAG_ERROR                    0x10000000
+/* outbound firmware ok */
+#define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK             0x80000000
+/*
+*******************************************************************************
+**    size 0x1F8 (504)
+*******************************************************************************
+*/
+struct ARCMSR_CDB
+{
+	uint8_t							Bus;
+	uint8_t							TargetID;
+	uint8_t							LUN;
+	uint8_t							Function;
+
+	uint8_t							CdbLength;
+	uint8_t							sgcount;
+	uint8_t							Flags;
+#define ARCMSR_CDB_FLAG_SGL_BSIZE          0x01
+#define ARCMSR_CDB_FLAG_BIOS               0x02
+#define ARCMSR_CDB_FLAG_WRITE              0x04
+#define ARCMSR_CDB_FLAG_SIMPLEQ            0x00
+#define ARCMSR_CDB_FLAG_HEADQ              0x08
+#define ARCMSR_CDB_FLAG_ORDEREDQ           0x10
+	uint8_t							Reserved1;
+
+	uint32_t						Context;
+	uint32_t						DataLength;
+
+	uint8_t							Cdb[16];
+
+	uint8_t							DeviceStatus;
+#define SCSISTAT_GOOD					0x00
+#define SCSISTAT_CHECK_CONDITION			0x02
+#define SCSISTAT_CONDITION_MET				0x04
+#define SCSISTAT_BUSY					0x08
+#define SCSISTAT_INTERMEDIATE				0x10
+#define SCSISTAT_INTERMEDIATE_COND_MET			0x14
+#define SCSISTAT_RESERVATION_CONFLICT			0x18
+#define SCSISTAT_COMMAND_TERMINATED			0x22
+#define SCSISTAT_QUEUE_FULL				0x28
+#define ARCMSR_DEV_SELECT_TIMEOUT			0xF0
+#define ARCMSR_DEV_ABORTED				0xF1
+#define ARCMSR_DEV_INIT_FAIL				0xF2
+	uint8_t							SenseData[15];
+
+	union
+	{
+		struct SG32ENTRY                sg32entry[ARCMSR_MAX_SG_ENTRIES];
+		struct SG64ENTRY                sg64entry[ARCMSR_MAX_SG_ENTRIES];
+	} u;
+};
+/*
+*******************************************************************************
+**     Messaging Unit (MU) of the Intel R 80331 I/O processor (80331)
+*******************************************************************************
+*/
+struct MU
+{
+	uint32_t	resrved0[4];			/*0000 000F*/
+	uint32_t	inbound_msgaddr0;		/*0010 0013*/
+	uint32_t	inbound_msgaddr1;		/*0014 0017*/
+	uint32_t	outbound_msgaddr0;		/*0018 001B*/
+	uint32_t	outbound_msgaddr1;		/*001C 001F*/
+	uint32_t	inbound_doorbell;		/*0020 0023*/
+	uint32_t	inbound_intstatus;		/*0024 0027*/
+	uint32_t	inbound_intmask;		/*0028 002B*/
+	uint32_t	outbound_doorbell;		/*002C 002F*/
+	uint32_t	outbound_intstatus;		/*0030 0033*/
+	uint32_t	outbound_intmask;		/*0034 0037*/
+	uint32_t	reserved1[2];			/*0038 003F*/
+	uint32_t	inbound_queueport;		/*0040 0043*/
+	uint32_t	outbound_queueport;     	/*0044 0047*/
+	uint32_t	reserved2[2];			/*0048 004F*/
+	uint32_t	reserved3[492];			/*0050 07FF 492*/
+	uint32_t	reserved4[128];			/*0800 09FF 128*/
+	uint32_t	message_rwbuffer[256];		/*0a00 0DFF 256*/
+	uint32_t	ioctl_wbuffer[32];		/*0E00 0E7F  32*/
+	uint32_t	reserved5[32];			/*0E80 0EFF  32*/
+	uint32_t	ioctl_rbuffer[32];		/*0F00 0F7F  32*/
+	uint32_t	reserved6[32];			/*0F80 0FFF  32*/
+};
+/*
+*******************************************************************************
+**                 Adapter Control Block
+*******************************************************************************
+*/
+struct ACB
+{
+	struct pci_dev *		pci_device;
+	struct Scsi_Host *		host;
+	unsigned long			vir2phy_offset;
+	/* Offset is used in making arc cdb physical to virtual calculations */
+	uint32_t			outbound_int_enable;
+
+	struct MU __iomem *		pmu;
+	/* message unit ATU inbound base address0 */
+
+	uint8_t				adapter_index;
+	uint8_t				irq;
+	uint16_t			acb_flags;
+#define ACB_F_SCSISTOPADAPTER         0x0001
+#define ACB_F_MSG_STOP_BGRB           0x0002
+	/* stop RAID background rebuild */
+#define ACB_F_MSG_START_BGRB          0x0004
+	/* stop RAID background rebuild */
+#define ACB_F_IOPDATA_OVERFLOW        0x0008
+	/* iop ioctl data rqbuffer overflow */
+#define ACB_F_IOCTL_WQBUFFER_CLEARED  0x0010
+	/* ioctl clear wqbuffer */
+#define ACB_F_IOCTL_RQBUFFER_CLEARED  0x0020
+	/* ioctl clear rqbuffer */
+#define ACB_F_IOCTL_WQBUFFER_READED   0x0040
+#define ACB_F_BUS_RESET               0x0080
+#define ACB_F_IOP_INITED              0x0100
+	/* iop init */
+#define ACB_F_HAVE_MSI                0x0200
+	/* pci message signal interrupt */
+
+	struct CCB *			pccb_pool[ARCMSR_MAX_FREECCB_NUM];
+	/* used for memory free */
+	struct list_head		ccb_free_list;
+	/* head of free ccb list */
+	struct list_head		ccb_pending_list;
+	/* head of pending ccb list */
+	atomic_t			ccboutstandingcount;
+	atomic_t			ccbpendingcount;
+
+	void *				dma_coherent;
+	/* dma_coherent used for memory free */
+	dma_addr_t			dma_coherent_handle;
+	/* dma_coherent_handle used for memory free */
+
+	uint8_t				rqbuffer[ARCMSR_MAX_QBUFFER];
+	/* data collection buffer for read from 80331 */
+	int32_t				rqbuf_firstindex;
+	/* first of read buffer  */
+	int32_t				rqbuf_lastindex;
+	/* last of read buffer   */
+	uint8_t				wqbuffer[ARCMSR_MAX_QBUFFER];
+	/* data collection buffer for write to 80331  */
+	int32_t				wqbuf_firstindex;
+	/* first of write buffer */
+	int32_t				wqbuf_lastindex;
+	/* last of write buffer  */
+	spinlock_t			qbuffer_lock;
+	spinlock_t			pending_list_lock;
+	spinlock_t			working_list_lock;
+	spinlock_t			done_list_lock;
+
+	uint8_t				devstate[ARCMSR_MAX_TARGETID][ARCMSR_MAX_TARGETLUN];
+	/* id0 ..... id15, lun0...lun7 */
+#define ARECA_RAID_GONE               0x55
+#define ARECA_RAID_GOOD               0xaa
+	uint32_t			num_resets;
+	uint32_t			num_aborts;
+	uint32_t			firm_request_len;
+	uint32_t			firm_numbers_queue;
+	uint32_t			firm_sdram_size;
+	uint32_t			firm_ide_channels;
+	char				firm_model[12];
+	char				firm_version[20];
+};/* HW_DEVICE_EXTENSION */
+/*
+*******************************************************************************
+**                   Command Control Block
+**             this CCB length must be 32 bytes boundary
+*******************************************************************************
+*/
+struct CCB
+{
+	struct ARCMSR_CDB		arcmsr_cdb;
+	/*
+	** 0-503 (size of CDB=504):
+	** arcmsr messenger scsi command descriptor size 504 bytes
+	*/
+	uint32_t			cdb_shifted_phyaddr;
+	/* 504-507 */
+	uint32_t			reserved1;
+	/* 508-511 */
+#if BITS_PER_LONG == 64
+	/*  ======================512+64 bytes========================  */
+	struct list_head		list;
+	/* 512-527 16 bytes next/prev ptrs for ccb lists */
+	struct scsi_cmnd *		pcmd;
+	/* 528-535 8 bytes pointer of linux scsi command */
+	struct ACB *			pACB;
+	/* 536-543 8 bytes pointer of acb */
+
+	uint16_t			ccb_flags;
+	/* 544-545 */
+	#define		CCB_FLAG_READ			0x0000
+	#define		CCB_FLAG_WRITE			0x0001
+	#define		CCB_FLAG_ERROR			0x0002
+	#define		CCB_FLAG_FLUSHCACHE		0x0004
+	#define		CCB_FLAG_MASTER_ABORTED		0x0008
+	uint16_t			startdone;
+	/* 546-547 */
+	#define		ARCMSR_CCB_DONE			0x0000
+	#define		ARCMSR_CCB_START		0x55AA
+	#define		ARCMSR_CCB_ABORTED		0xAA55
+	#define		ARCMSR_CCB_ILLEGAL		0xFFFF
+	uint32_t			reserved2[7];
+	/* 548-551 552-555 556-559 560-563 564-567 568-571 572-575 */
+#else
+	/*  ======================512+32 bytes========================  */
+	struct list_head		list;
+	/* 512-519 8 bytes next/prev ptrs for ccb lists */
+	struct scsi_cmnd *		pcmd;
+	/* 520-523 4 bytes pointer of linux scsi command */
+	struct ACB *			pACB;
+	/* 524-527 4 bytes pointer of acb */
+
+	uint16_t			ccb_flags;
+	/* 528-529 */
+	#define		CCB_FLAG_READ			0x0000
+	#define		CCB_FLAG_WRITE			0x0001
+	#define		CCB_FLAG_ERROR			0x0002
+	#define		CCB_FLAG_FLUSHCACHE		0x0004
+	#define		CCB_FLAG_MASTER_ABORTED		0x0008
+	uint16_t			startdone;
+	/* 530-531 */
+	#define		ARCMSR_CCB_DONE			0x0000
+	#define		ARCMSR_CCB_START		0x55AA
+	#define		ARCMSR_CCB_ABORTED		0xAA55
+	#define		ARCMSR_CCB_ILLEGAL		0xFFFF
+	uint32_t			reserved2[3];
+	/* 532-535 536-539 540-543 */
+#endif
+	/*  ==========================================================  */
+};
+/*
+*********************************************************************
+*********************************************************************
+*/
+struct HCBARC
+{
+	struct ACB *			pACB[ARCMSR_MAX_ADAPTER];
+
+	int32_t				arcmsr_major_number;
+
+	uint8_t				adapterCnt;
+	uint8_t				reserved[3];
+};
+/*
+*******************************************************************************
+*******************************************************************************
+*/
+struct SENSE_DATA
+{
+	uint8_t				ErrorCode:7;
+#define SCSI_SENSE_CURRENT_ERRORS	0x70
+#define SCSI_SENSE_DEFERRED_ERRORS	0x71
+	uint8_t				Valid:1;
+	uint8_t				SegmentNumber;
+	uint8_t				SenseKey:4;
+	uint8_t				Reserved:1;
+	uint8_t				IncorrectLength:1;
+	uint8_t				EndOfMedia:1;
+	uint8_t				FileMark:1;
+	uint8_t				Information[4];
+	uint8_t				AdditionalSenseLength;
+	uint8_t				CommandSpecificInformation[4];
+	uint8_t				AdditionalSenseCode;
+	uint8_t				AdditionalSenseCodeQualifier;
+	uint8_t				FieldReplaceableUnitCode;
+	uint8_t				SenseKeySpecific[3];
+};
+/*
+*******************************************************************************
+**  Peripheral Device Type definitions
+*******************************************************************************
+*/
+#define SCSI_DASD			0x00   /* Direct-access Device     */
+#define SCSI_SEQACESS			0x01   /* Sequential-access device */
+#define SCSI_PRINTER			0x02   /* Printer device           */
+#define SCSI_PROCESSOR			0x03   /* Processor device         */
+#define SCSI_WRITEONCE			0x04   /* Write-once device        */
+#define SCSI_CDROM			0x05   /* CD-ROM device            */
+#define SCSI_SCANNER			0x06   /* Scanner device           */
+#define SCSI_OPTICAL			0x07   /* Optical memory device    */
+#define SCSI_MEDCHGR			0x08   /* Medium changer device    */
+#define SCSI_COMM			0x09   /* Communications device    */
+#define SCSI_NODEV			0x1F   /* Unknown or no device type*/
+/*
+*******************************************************************************
+**             80331 PCI-to-PCI Bridge
+**             PCI Configuration Space
+*******************************************************************************
+*/
+#define     ARCMSR_PCI2PCI_VENDORID_REG                             0x00    /*word*/
+#define     ARCMSR_PCI2PCI_DEVICEID_REG                             0x02    /*word*/
+/*
+*******************************************************************************
+**  0x05-0x04 : command register
+*******************************************************************************
+*/
+#define     ARCMSR_PCI2PCI_PRIMARY_COMMAND_REG                      0x04    /*word*/
+#define     PCI_DISABLE_INTERRUPT          0x0400
+/*
+*******************************************************************************
+**  0x07-0x06 : status register
+*******************************************************************************
+*/
+#define     ARCMSR_PCI2PCI_PRIMARY_STATUS_REG                       0x06    /*word: 06, 07 */
+#define     ARCMSR_ADAP_66MHZ         0x20
+/*
+*******************************************************************************
+**  0x08 : revision ID
+*******************************************************************************
+*/
+#define     ARCMSR_PCI2PCI_REVISIONID_REG                           0x08    /*byte*/
+/*
+*******************************************************************************
+**  0x0b-0x09 : 0180_00 (class code 1, native pci mode )
+*******************************************************************************
+*/
+#define     ARCMSR_PCI2PCI_CLASSCODE_REG                            0x09    /*3 bytes*/
+/*
+*******************************************************************************
+**  0x0c : cache line size
+*******************************************************************************
+*/
+#define     ARCMSR_PCI2PCI_PRIMARY_CACHELINESIZE_REG                0x0C    /*byte*/
+/*
+*******************************************************************************
+**  0x0d : latency timer (number of pci clock 00-ff )
+*******************************************************************************
+*/
+#define     ARCMSR_PCI2PCI_PRIMARY_LATENCYTIMER_REG                 0x0D    /*byte*/
+/*
+*******************************************************************************
+**  0x0e : (header type, single function )
+*******************************************************************************
+*/
+#define     ARCMSR_PCI2PCI_HEADERTYPE_REG                           0x0E    /*byte*/
+/*
+*******************************************************************************
+**  0x13-0x10
+**  PCI CFG Base Address #0 (0x10)
+*******************************************************************************
+*/
+/*
+*******************************************************************************
+**  0x17-0x14 :
+**  PCI CFG Base Address #1 (0x14)
+*******************************************************************************
+*/
+/*
+*******************************************************************************
+**  0x1b-0x18 :
+**  PCI CFG Base Address #2 (0x18)
+*******************************************************************************
+*/
+#define     ARCMSR_PCI2PCI_PRIMARY_BUSNUMBER_REG                    0x18
+#define     ARCMSR_PCI2PCI_SECONDARY_BUSNUMBER_REG                  0x19
+#define     ARCMSR_PCI2PCI_SUBORDINATE_BUSNUMBER_REG                0x1A
+#define     ARCMSR_PCI2PCI_SECONDARY_LATENCYTIMER_REG               0x1B
+/*
+*******************************************************************************
+**  0x1f-0x1c :
+**  PCI CFG Base Address #3 (0x1C)
+*******************************************************************************
+*/
+#define     ARCMSR_PCI2PCI_IO_BASE_REG                              0x1C
+#define     ARCMSR_PCI2PCI_IO_LIMIT_REG                             0x1D
+#define     ARCMSR_PCI2PCI_SECONDARY_STATUS_REG                     0x1E
+/*
+*******************************************************************************
+**  0x23-0x20 :
+**  PCI CFG Base Address #4 (0x20)
+*******************************************************************************
+*/
+#define     ARCMSR_PCI2PCI_NONPREFETCHABLE_MEMORY_BASE_REG          0x20
+#define     ARCMSR_PCI2PCI_NONPREFETCHABLE_MEMORY_LIMIT_REG         0x22
+/*
+*******************************************************************************
+**  0x27-0x24 :
+**  PCI CFG Base Address #5 (0x24)
+*******************************************************************************
+*/
+#define     ARCMSR_PCI2PCI_PREFETCHABLE_MEMORY_BASE_REG             0x24
+#define     ARCMSR_PCI2PCI_PREFETCHABLE_MEMORY_LIMIT_REG            0x26
+/*
+*******************************************************************************
+**  0x2b-0x28 :
+*******************************************************************************
+*/
+#define     ARCMSR_PCI2PCI_PREFETCHABLE_MEMORY_BASE_UPPER32_REG     0x28
+/*
+*******************************************************************************
+**  0x2f-0x2c :
+*******************************************************************************
+*/
+#define     ARCMSR_PCI2PCI_PREFETCHABLE_MEMORY_LIMIT_UPPER32_REG    0x2C
+/*
+*******************************************************************************
+**  0x33-0x30 :
+*******************************************************************************
+*/
+#define     ARCMSR_PCI2PCI_CAPABILITIES_POINTER_REG	            0x34
+/*
+*******************************************************************************
+**  0x3b-0x35 : reserved
+*******************************************************************************
+*/
+/*
+*******************************************************************************
+**  0x3d-0x3c :
+*******************************************************************************
+*/
+#define     ARCMSR_PCI2PCI_PRIMARY_INTERRUPT_LINE_REG               0x3C
+#define     ARCMSR_PCI2PCI_PRIMARY_INTERRUPT_PIN_REG                0x3D
+/*
+*******************************************************************************
+**  0x3f-0x3e :
+*******************************************************************************
+*/
+#define     ARCMSR_PCI2PCI_BRIDGE_CONTROL_REG                       0x3E
+/*
+*******************************************************************************
+**
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_VENDOR_ID_REG                                0x00
+/*
+*******************************************************************************
+**  ATU Device ID Register - ATUDID
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_DEVICE_ID_REG                                0x02
+/*
+*******************************************************************************
+**  ATU Command Register - ATUCMD
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_COMMAND_REG                                  0x04
+/*
+*******************************************************************************
+**  ATU Status Register - ATUSR (Sheet 1 of 2)
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_STATUS_REG                                   0x06
+/*
+*******************************************************************************
+**  ATU Revision ID Register - ATURID
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_REVISION_REG                                 0x08
+/*
+*******************************************************************************
+**  ATU Class Code Register - ATUCCR
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_CLASS_CODE_REG                               0x09
+/*
+*******************************************************************************
+**  ATU Cacheline Size Register - ATUCLSR
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_CACHELINE_SIZE_REG                           0x0C
+/*
+*******************************************************************************
+**  ATU Latency Timer Register - ATULT
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_LATENCY_TIMER_REG                            0x0D
+/*
+*******************************************************************************
+**  ATU Header Type Register - ATUHTR
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_HEADER_TYPE_REG                              0x0E
+/*
+*******************************************************************************
+**  ATU BIST Register - ATUBISTR
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_BIST_REG                                     0x0F
+/*
+*******************************************************************************
+**  Inbound ATU Base Address Register 0 - IABAR0
+*******************************************************************************
+*/
+#define     ARCMSR_INBOUND_ATU_BASE_ADDRESS0_REG                    0x10
+#define     ARCMSR_INBOUND_ATU_MEMORY_PREFETCHABLE                  0x08
+#define     ARCMSR_INBOUND_ATU_MEMORY_WINDOW64                      0x04
+/*
+*******************************************************************************
+**
+*******************************************************************************
+*/
+#define     ARCMSR_INBOUND_ATU_UPPER_BASE_ADDRESS0_REG              0x14
+/*
+*******************************************************************************
+**  Inbound ATU Base Address Register 1 - IABAR1
+*******************************************************************************
+*/
+#define     ARCMSR_INBOUND_ATU_BASE_ADDRESS1_REG                    0x18
+/*
+*******************************************************************************
+**  Inbound ATU Upper Base Address Register 1 - IAUBAR1
+*******************************************************************************
+*/
+#define     ARCMSR_INBOUND_ATU_UPPER_BASE_ADDRESS1_REG              0x1C
+/*
+*******************************************************************************
+**  Inbound ATU Base Address Register 2 - IABAR2
+*******************************************************************************
+*/
+#define     ARCMSR_INBOUND_ATU_BASE_ADDRESS2_REG                    0x20
+/*
+*******************************************************************************
+**  Inbound ATU Upper Base Address Register 2 - IAUBAR2
+*******************************************************************************
+*/
+#define     ARCMSR_INBOUND_ATU_UPPER_BASE_ADDRESS2_REG              0x24
+/*
+*******************************************************************************
+**  ATU Subsystem Vendor ID Register - ASVIR
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_SUBSYSTEM_VENDOR_ID_REG                      0x2C
+/*
+*******************************************************************************
+**  ATU Subsystem ID Register - ASIR
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_SUBSYSTEM_ID_REG                             0x2E
+/*
+*******************************************************************************
+**  Expansion ROM Base Address Register -ERBAR
+*******************************************************************************
+*/
+#define     ARCMSR_EXPANSION_ROM_BASE_ADDRESS_REG                   0x30
+#define     ARCMSR_EXPANSION_ROM_ADDRESS_DECODE_ENABLE    0x01
+/*
+*******************************************************************************
+**  ATU Capabilities Pointer Register - ATU_CAP_PTR
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_CAPABILITY_PTR_REG                           0x34
+/*
+*******************************************************************************
+**  ATU Interrupt Line Register - ATUILR
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_INTERRUPT_LINE_REG                           0x3C
+/*
+*******************************************************************************
+**  ATU Interrupt Pin Register - ATUIPR
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_INTERRUPT_PIN_REG                            0x3D
+/*
+*******************************************************************************
+**  ATU Minimum Grant Register - ATUMGNT
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_MINIMUM_GRANT_REG                            0x3E
+/*
+*******************************************************************************
+**  ATU Maximum Latency Register - ATUMLAT
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_MAXIMUM_LATENCY_REG                          0x3F
+/*
+*******************************************************************************
+**  Inbound ATU Limit Register 0 - IALR0
+*******************************************************************************
+*/
+#define     ARCMSR_INBOUND_ATU_LIMIT0_REG                           0x40
+/*
+*******************************************************************************
+**  Inbound ATU Translate Value Register 0 - IATVR0
+*******************************************************************************
+*/
+#define     ARCMSR_INBOUND_ATU_TRANSLATE_VALUE0_REG                 0x44
+/*
+*******************************************************************************
+**  Expansion ROM Limit Register - ERLR
+*******************************************************************************
+*/
+#define     ARCMSR_EXPANSION_ROM_LIMIT_REG                          0x48
+/*
+*******************************************************************************
+**  Expansion ROM Translate Value Register - ERTVR
+*******************************************************************************
+*/
+#define     ARCMSR_EXPANSION_ROM_TRANSLATE_VALUE_REG                0x4C
+/*
+*******************************************************************************
+**  Inbound ATU Limit Register 1 - IALR1
+*******************************************************************************
+*/
+#define     ARCMSR_INBOUND_ATU_LIMIT1_REG                           0x50
+/*
+*******************************************************************************
+**  Inbound ATU Limit Register 2 - IALR2
+*******************************************************************************
+*/
+#define     ARCMSR_INBOUND_ATU_LIMIT2_REG                           0x54
+/*
+*******************************************************************************
+**  Inbound ATU Translate Value Register 2 - IATVR2
+*******************************************************************************
+*/
+#define     ARCMSR_INBOUND_ATU_TRANSLATE_VALUE2_REG                 0x58
+/*
+*******************************************************************************
+**  Outbound I/O Window Translate Value Register - OIOWTVR
+*******************************************************************************
+*/
+#define     ARCMSR_OUTBOUND_IO_WINDOW_TRANSLATE_VALUE_REG           0x5C
+/*
+*******************************************************************************
+**  Outbound Memory Window Translate Value Register 0 -OMWTVR0
+*******************************************************************************
+*/
+#define     ARCMSR_OUTBOUND_MEMORY_WINDOW_TRANSLATE_VALUE0_REG      0x60
+/*
+*******************************************************************************
+**  Outbound Upper 32-bit Memory Window Translate Value Register 0 - OUMWTVR0
+*******************************************************************************
+*/
+#define     ARCMSR_OUTBOUND_UPPER32_MEMORY_WINDOW_TRANSLATE_VALUE0_REG    0x64
+/*
+*******************************************************************************
+**  Outbound Memory Window Translate Value Register 1 -OMWTVR1
+*******************************************************************************
+*/
+#define     ARCMSR_OUTBOUND_MEMORY_WINDOW_TRANSLATE_VALUE1_REG      0x68
+/*
+*******************************************************************************
+**  Outbound Upper 32-bit Memory Window Translate Value Register 1 - OUMWTVR1
+*******************************************************************************
+*/
+#define     ARCMSR_OUTBOUND_UPPER32_MEMORY_WINDOW_TRANSLATE_VALUE1_REG    0x6C
+/*
+*******************************************************************************
+**  Outbound Upper 32-bit Direct Window Translate Value Register - OUDWTVR
+*******************************************************************************
+*/
+#define     ARCMSR_OUTBOUND_UPPER32_DIRECT_WINDOW_TRANSLATE_VALUE_REG     0x78
+/*
+*******************************************************************************
+**  ATU Configuration Register - ATUCR
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_CONFIGURATION_REG                            0x80
+/*
+*******************************************************************************
+**  PCI Configuration and Status Register - PCSR
+*******************************************************************************
+*/
+#define     ARCMSR_PCI_CONFIGURATION_STATUS_REG                     0x84
+/*
+*******************************************************************************
+**  ATU Interrupt Status Register - ATUISR
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_INTERRUPT_STATUS_REG                         0x88
+/*
+*******************************************************************************
+**  ATU Interrupt Mask Register - ATUIMR
+*******************************************************************************
+*/
+#define     ARCMSR_ATU_INTERRUPT_MASK_REG                           0x8C
+/*
+*******************************************************************************
+**  Inbound ATU Base Address Register 3 - IABAR3
+*******************************************************************************
+*/
+#define     ARCMSR_INBOUND_ATU_BASE_ADDRESS3_REG                    0x90
+/*
+*******************************************************************************
+**  Inbound ATU Upper Base Address Register 3 - IAUBAR3
+*******************************************************************************
+*/
+#define     ARCMSR_INBOUND_ATU_UPPER_BASE_ADDRESS3_REG              0x94
+/*
+*******************************************************************************
+**  Inbound ATU Limit Register 3 - IALR3
+*******************************************************************************
+*/
+#define     ARCMSR_INBOUND_ATU_LIMIT3_REG                           0x98
+/*
+*******************************************************************************
+**  Inbound ATU Translate Value Register 3 - IATVR3
+*******************************************************************************
+*/
+#define     ARCMSR_INBOUND_ATU_TRANSLATE_VALUE3_REG                 0x9C
+/*
+*******************************************************************************
+**  Outbound Configuration Cycle Address Register - OCCAR
+*******************************************************************************
+*/
+#define     ARCMSR_OUTBOUND_CONFIGURATION_CYCLE_ADDRESS_REG         0xA4
+/*
+*******************************************************************************
+**  Outbound Configuration Cycle Data Register - OCCDR
+*******************************************************************************
+*/
+#define     ARCMSR_OUTBOUND_CONFIGURATION_CYCLE_DATA_REG            0xAC
+/*
+*******************************************************************************
+**  VPD Capability Identifier Register - VPD_CAPID
+*******************************************************************************
+*/
+#define     ARCMSR_VPD_CAPABILITY_IDENTIFIER_REG                    0xB8
+/*
+*******************************************************************************
+**  VPD Next Item Pointer Register - VPD_NXTP
+*******************************************************************************
+*/
+#define     ARCMSR_VPD_NEXT_ITEM_PTR_REG                            0xB9
+/*
+*******************************************************************************
+**  VPD Address Register - VPD_AR
+*******************************************************************************
+*/
+#define     ARCMSR_VPD_ADDRESS_REG                                  0xBA
+/*
+*******************************************************************************
+**  VPD Data Register - VPD_DR
+*******************************************************************************
+*/
+#define     ARCMSR_VPD_DATA_REG                                     0xBC
+/*
+*******************************************************************************
+**  Power Management Capability Identifier Register -PM_CAPID
+*******************************************************************************
+*/
+#define     ARCMSR_POWER_MANAGEMENT_CAPABILITY_IDENTIFIER_REG       0xC0
+/*
+*******************************************************************************
+**  Power Management Next Item Pointer Register - PM_NXTP
+*******************************************************************************
+*/
+#define     ARCMSR_POWER_NEXT_ITEM_PTR_REG                          0xC1
+/*
+*******************************************************************************
+**  Power Management Capabilities Register - PM_CAP
+*******************************************************************************
+*/
+#define     ARCMSR_POWER_MANAGEMENT_CAPABILITY_REG                  0xC2
+/*
+*******************************************************************************
+**  Power Management Control/Status Register - PM_CSR
+*******************************************************************************
+*/
+#define     ARCMSR_POWER_MANAGEMENT_CONTROL_STATUS_REG              0xC4
+/*
+*******************************************************************************
+**  PCI-X Capability Identifier Register - PX_CAPID
+*******************************************************************************
+*/
+#define     ARCMSR_PCIX_CAPABILITY_IDENTIFIER_REG                   0xE0
+/*
+*******************************************************************************
+**  PCI-X Next Item Pointer Register - PX_NXTP
+*******************************************************************************
+*/
+#define     ARCMSR_PCIX_NEXT_ITEM_PTR_REG                           0xE1
+/*
+*******************************************************************************
+**  PCI-X Command Register - PX_CMD
+*******************************************************************************
+*/
+#define     ARCMSR_PCIX_COMMAND_REG                                 0xE2
+/*
+*******************************************************************************
+**  PCI-X Status Register - PX_SR
+*******************************************************************************
+*/
+#define     ARCMSR_PCIX_STATUS_REG                                  0xE4
+/*
+*******************************************************************************
+**  Message Registers
+*******************************************************************************
+*/
+#define     ARCMSR_MU_INBOUND_MESSAGE_REG0                          0x10
+#define     ARCMSR_MU_INBOUND_MESSAGE_REG1                          0x14
+/*
+*******************************************************************************
+**  Outbound Message Register - OMRx
+*******************************************************************************
+*/
+#define     ARCMSR_MU_OUTBOUND_MESSAGE_REG0                         0x18
+#define     ARCMSR_MU_OUTBOUND_MESSAGE_REG1                         0x1C
+/*
+*******************************************************************************
+**        Doorbell Registers
+*******************************************************************************
+*/
+#define     ARCMSR_MU_INBOUND_DOORBELL_REG                          0x20
+/*
+*******************************************************************************
+**  Inbound Interrupt Status Register - IISR
+*******************************************************************************
+*/
+#define     ARCMSR_MU_INBOUND_INTERRUPT_STATUS_REG0                 0x24
+#define     ARCMSR_MU_INBOUND_INDEX_INT                             0x40
+#define     ARCMSR_MU_INBOUND_QUEUEFULL_INT                         0x20
+#define     ARCMSR_MU_INBOUND_POSTQUEUE_INT                         0x10
+#define     ARCMSR_MU_INBOUND_ERROR_DOORBELL_INT                    0x08
+#define     ARCMSR_MU_INBOUND_DOORBELL_INT                          0x04
+#define     ARCMSR_MU_INBOUND_MESSAGE1_INT                          0x02
+#define     ARCMSR_MU_INBOUND_MESSAGE0_INT                          0x01
+/*
+*******************************************************************************
+**  Inbound Interrupt Mask Register - IIMR
+*******************************************************************************
+*/
+#define     ARCMSR_MU_INBOUND_INTERRUPT_MASK_REG	            0x28
+#define     ARCMSR_MU_INBOUND_INDEX_INTMASKENABLE                   0x40
+#define     ARCMSR_MU_INBOUND_QUEUEFULL_INTMASKENABLE               0x20
+#define     ARCMSR_MU_INBOUND_POSTQUEUE_INTMASKENABLE               0x10
+#define     ARCMSR_MU_INBOUND_DOORBELL_ERROR_INTMASKENABLE          0x08
+#define     ARCMSR_MU_INBOUND_DOORBELL_INTMASKENABLE                0x04
+#define     ARCMSR_MU_INBOUND_MESSAGE1_INTMASKENABLE                0x02
+#define     ARCMSR_MU_INBOUND_MESSAGE0_INTMASKENABLE                0x01
+/*
+*******************************************************************************
+**  Outbound Doorbell Register - ODR
+*******************************************************************************
+*/
+#define     ARCMSR_MU_OUTBOUND_DOORBELL_REG                         0x2C
+/*
+*******************************************************************************
+**  Outbound Interrupt Status Register - OISR
+*******************************************************************************
+*/
+#define     ARCMSR_MU_OUTBOUND_INTERRUPT_STATUS_REG                 0x30
+#define     ARCMSR_MU_OUTBOUND_PCI_INT                              0x10
+#define     ARCMSR_MU_OUTBOUND_POSTQUEUE_INT                        0x08
+#define     ARCMSR_MU_OUTBOUND_DOORBELL_INT                         0x04
+#define     ARCMSR_MU_OUTBOUND_MESSAGE1_INT                         0x02
+#define     ARCMSR_MU_OUTBOUND_MESSAGE0_INT                         0x01
+#define     ARCMSR_MU_OUTBOUND_HANDLE_INT                 \
+                    (ARCMSR_MU_OUTBOUND_MESSAGE0_INT      \
+                     |ARCMSR_MU_OUTBOUND_MESSAGE1_INT     \
+                     |ARCMSR_MU_OUTBOUND_DOORBELL_INT     \
+                     |ARCMSR_MU_OUTBOUND_POSTQUEUE_INT    \
+                     |ARCMSR_MU_OUTBOUND_PCI_INT)
+/*
+*******************************************************************************
+**  Outbound Interrupt Mask Register - OIMR
+*******************************************************************************
+*/
+#define     ARCMSR_MU_OUTBOUND_INTERRUPT_MASK_REG                   0x34
+#define     ARCMSR_MU_OUTBOUND_PCI_INTMASKENABLE                    0x10
+#define     ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE              0x08
+#define     ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE               0x04
+#define     ARCMSR_MU_OUTBOUND_MESSAGE1_INTMASKENABLE               0x02
+#define     ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE               0x01
+#define     ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE                    0x1F
+/*
+*******************************************************************************
+**
+*******************************************************************************
+*/
+#define     ARCMSR_MU_INBOUND_QUEUE_PORT_REG                        0x40
+#define     ARCMSR_MU_OUTBOUND_QUEUE_PORT_REG                       0x44
+
+/*
+*******************************************************************************
+**  MU Configuration Register - MUCR  FFFF.E350H
+*******************************************************************************
+*/
+#define     ARCMSR_MU_CONFIGURATION_REG                       0xFFFFE350
+#define     ARCMSR_MU_CIRCULAR_QUEUE_SIZE64K                      0x0020
+#define     ARCMSR_MU_CIRCULAR_QUEUE_SIZE32K                      0x0010
+#define     ARCMSR_MU_CIRCULAR_QUEUE_SIZE16K                      0x0008
+#define     ARCMSR_MU_CIRCULAR_QUEUE_SIZE8K                       0x0004
+#define     ARCMSR_MU_CIRCULAR_QUEUE_SIZE4K                       0x0002
+#define     ARCMSR_MU_CIRCULAR_QUEUE_ENABLE                       0x0001
+/*
+*******************************************************************************
+**  Queue Base Address Register - QBAR
+*******************************************************************************
+*/
+#define     ARCMSR_MU_QUEUE_BASE_ADDRESS_REG                  0xFFFFE354
+/*
+*******************************************************************************
+**  Inbound Free Head Pointer Register - IFHPR
+*******************************************************************************
+*/
+#define     ARCMSR_MU_INBOUND_FREE_HEAD_PTR_REG               0xFFFFE360
+/*
+*******************************************************************************
+**  Inbound Free Tail Pointer Register - IFTPR
+*******************************************************************************
+*/
+#define     ARCMSR_MU_INBOUND_FREE_TAIL_PTR_REG               0xFFFFE364
+/*
+*******************************************************************************
+**  Inbound Post Head Pointer Register - IPHPR
+*******************************************************************************
+*/
+#define     ARCMSR_MU_INBOUND_POST_HEAD_PTR_REG               0xFFFFE368
+/*
+*******************************************************************************
+**  Inbound Post Tail Pointer Register - IPTPR
+*******************************************************************************
+*/
+#define     ARCMSR_MU_INBOUND_POST_TAIL_PTR_REG               0xFFFFE36C
+/*
+*******************************************************************************
+**  Index Address Register - IAR
+*******************************************************************************
+*/
+#define     ARCMSR_MU_LOCAL_MEMORY_INDEX_REG                  0xFFFFE380
diff -urN oldtree/drivers/scsi/ch.c newtree/drivers/scsi/ch.c
--- oldtree/drivers/scsi/ch.c	2006-02-19 11:41:03.778768640 +0000
+++ newtree/drivers/scsi/ch.c	2006-02-21 15:58:19.842130096 +0000
@@ -39,6 +39,7 @@
 MODULE_DESCRIPTION("device driver for scsi media changer devices");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(SCSI_CHANGER_MAJOR);
 
 static int init = 1;
 module_param(init, int, 0444);
diff -urN oldtree/drivers/scsi/constants.c newtree/drivers/scsi/constants.c
--- oldtree/drivers/scsi/constants.c	2006-02-19 11:41:03.779768488 +0000
+++ newtree/drivers/scsi/constants.c	2006-02-21 15:58:17.645464040 +0000
@@ -114,8 +114,6 @@
 	{0xd, "Report supported task management functions"},
 	{0xe, "Report priority"},
 };
-#define MAINT_IN_SZ \
-        (int)(sizeof(maint_in_arr) / sizeof(maint_in_arr[0]))
 
 static const struct value_name_pair maint_out_arr[] = {
 	{0x6, "Set device identifier"},
@@ -123,34 +121,24 @@
 	{0xb, "Change aliases"},
 	{0xe, "Set priority"},
 };
-#define MAINT_OUT_SZ \
-        (int)(sizeof(maint_out_arr) / sizeof(maint_out_arr[0]))
 
 static const struct value_name_pair serv_in12_arr[] = {
 	{0x1, "Read media serial number"},
 };
-#define SERV_IN12_SZ  \
-        (int)(sizeof(serv_in12_arr) / sizeof(serv_in12_arr[0]))
 
 static const struct value_name_pair serv_out12_arr[] = {
 	{-1, "dummy entry"},
 };
-#define SERV_OUT12_SZ \
-        (int)(sizeof(serv_out12_arr) / sizeof(serv_in12_arr[0]))
 
 static const struct value_name_pair serv_in16_arr[] = {
 	{0x10, "Read capacity(16)"},
 	{0x11, "Read long(16)"},
 };
-#define SERV_IN16_SZ  \
-        (int)(sizeof(serv_in16_arr) / sizeof(serv_in16_arr[0]))
 
 static const struct value_name_pair serv_out16_arr[] = {
 	{0x11, "Write long(16)"},
 	{0x1f, "Notify data transfer device(16)"},
 };
-#define SERV_OUT16_SZ \
-        (int)(sizeof(serv_out16_arr) / sizeof(serv_in16_arr[0]))
 
 static const struct value_name_pair variable_length_arr[] = {
 	{0x1, "Rebuild(32)"},
@@ -190,8 +178,6 @@
 	{0x8f7e, "Perform SCSI command (osd)"},
 	{0x8f7f, "Perform task management function (osd)"},
 };
-#define VARIABLE_LENGTH_SZ \
-        (int)(sizeof(variable_length_arr) / sizeof(variable_length_arr[0]))
 
 static const char * get_sa_name(const struct value_name_pair * arr,
 			        int arr_sz, int service_action)
@@ -223,7 +209,7 @@
 			break;
 		}
 		sa = (cdbp[8] << 8) + cdbp[9];
-		name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa);
+		name = get_sa_name(maint_in_arr, ARRAY_SIZE(maint_in_arr), sa);
 		if (name) {
 			printk("%s%s", leadin, name);
 			if ((cdb_len > 0) && (len != cdb_len))
@@ -238,7 +224,7 @@
 		break;
 	case MAINTENANCE_IN:
 		sa = cdbp[1] & 0x1f;
-		name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa);
+		name = get_sa_name(maint_in_arr, ARRAY_SIZE(maint_in_arr), sa);
 		if (name)
 			printk("%s%s", leadin, name);
 		else
@@ -246,7 +232,8 @@
 		break;
 	case MAINTENANCE_OUT:
 		sa = cdbp[1] & 0x1f;
-		name = get_sa_name(maint_out_arr, MAINT_OUT_SZ, sa);
+		name = get_sa_name(maint_out_arr, ARRAY_SIZE(maint_out_arr),
+					sa);
 		if (name)
 			printk("%s%s", leadin, name);
 		else
@@ -254,7 +241,8 @@
 		break;
 	case SERVICE_ACTION_IN_12:
 		sa = cdbp[1] & 0x1f;
-		name = get_sa_name(serv_in12_arr, SERV_IN12_SZ, sa);
+		name = get_sa_name(serv_in12_arr, ARRAY_SIZE(serv_in12_arr),
+					sa);
 		if (name)
 			printk("%s%s", leadin, name);
 		else
@@ -262,7 +250,8 @@
 		break;
 	case SERVICE_ACTION_OUT_12:
 		sa = cdbp[1] & 0x1f;
-		name = get_sa_name(serv_out12_arr, SERV_OUT12_SZ, sa);
+		name = get_sa_name(serv_out12_arr, ARRAY_SIZE(serv_out12_arr),
+					sa);
 		if (name)
 			printk("%s%s", leadin, name);
 		else
@@ -270,7 +259,8 @@
 		break;
 	case SERVICE_ACTION_IN_16:
 		sa = cdbp[1] & 0x1f;
-		name = get_sa_name(serv_in16_arr, SERV_IN16_SZ, sa);
+		name = get_sa_name(serv_in16_arr, ARRAY_SIZE(serv_in16_arr),
+					sa);
 		if (name)
 			printk("%s%s", leadin, name);
 		else
@@ -278,7 +268,8 @@
 		break;
 	case SERVICE_ACTION_OUT_16:
 		sa = cdbp[1] & 0x1f;
-		name = get_sa_name(serv_out16_arr, SERV_OUT16_SZ, sa);
+		name = get_sa_name(serv_out16_arr, ARRAY_SIZE(serv_out16_arr),
+					sa);
 		if (name)
 			printk("%s%s", leadin, name);
 		else
@@ -1293,14 +1284,13 @@
 "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", 
 "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",
 "DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY"};
-#define NUM_HOSTBYTE_STRS (sizeof(hostbyte_table) / sizeof(const char *))
 
 void scsi_print_hostbyte(int scsiresult)
 {
 	int hb = host_byte(scsiresult);
 
 	printk("Hostbyte=0x%02x", hb);
-	if (hb < NUM_HOSTBYTE_STRS)
+	if (hb < ARRAY_SIZE(hostbyte_table))
 		printk("(%s) ", hostbyte_table[hb]);
 	else
 		printk("is invalid "); 
@@ -1317,12 +1307,10 @@
 static const char * const driverbyte_table[]={
 "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT",  "DRIVER_MEDIA", "DRIVER_ERROR", 
 "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE"};
-#define NUM_DRIVERBYTE_STRS (sizeof(driverbyte_table) / sizeof(const char *))
 
 static const char * const driversuggest_table[]={"SUGGEST_OK",
 "SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP", "SUGGEST_DIE",
 "SUGGEST_5", "SUGGEST_6", "SUGGEST_7", "SUGGEST_SENSE"};
-#define NUM_SUGGEST_STRS (sizeof(driversuggest_table) / sizeof(const char *))
 
 void scsi_print_driverbyte(int scsiresult)
 {
@@ -1331,8 +1319,10 @@
 
 	printk("Driverbyte=0x%02x ", driver_byte(scsiresult));
 	printk("(%s,%s) ",
-	       (dr < NUM_DRIVERBYTE_STRS ? driverbyte_table[dr] : "invalid"),
-	       (su < NUM_SUGGEST_STRS ? driversuggest_table[su] : "invalid"));
+	       (dr < ARRAY_SIZE(driverbyte_table) ?
+					driverbyte_table[dr] : "invalid"),
+	       (su < ARRAY_SIZE(driversuggest_table) ?
+					driversuggest_table[su] : "invalid"));
 }
 #else
 void scsi_print_driverbyte(int scsiresult)
diff -urN oldtree/drivers/scsi/hosts.c newtree/drivers/scsi/hosts.c
--- oldtree/drivers/scsi/hosts.c	2006-02-19 11:41:03.788767120 +0000
+++ newtree/drivers/scsi/hosts.c	2006-02-21 15:58:18.854280272 +0000
@@ -306,10 +306,9 @@
 		dump_stack();
         }
 
-	shost = kmalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask);
+	shost = kzalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask);
 	if (!shost)
 		return NULL;
-	memset(shost, 0, sizeof(struct Scsi_Host) + privsize);
 
 	spin_lock_init(&shost->default_lock);
 	scsi_assign_lock(shost, &shost->default_lock);
diff -urN oldtree/drivers/scsi/ide-scsi.c newtree/drivers/scsi/ide-scsi.c
--- oldtree/drivers/scsi/ide-scsi.c	2006-02-19 11:41:03.792766512 +0000
+++ newtree/drivers/scsi/ide-scsi.c	2006-02-21 15:58:23.823524832 +0000
@@ -47,6 +47,7 @@
 #include <linux/ide.h>
 #include <linux/scatterlist.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
 
 #include <asm/io.h>
 #include <asm/bitops.h>
@@ -109,7 +110,7 @@
 	unsigned long log;			/* log flags */
 } idescsi_scsi_t;
 
-static DECLARE_MUTEX(idescsi_ref_sem);
+static DEFINE_MUTEX(idescsi_ref_mutex);
 
 #define ide_scsi_g(disk) \
 	container_of((disk)->private_data, struct ide_scsi_obj, driver)
@@ -118,19 +119,19 @@
 {
 	struct ide_scsi_obj *scsi = NULL;
 
-	down(&idescsi_ref_sem);
+	mutex_lock(&idescsi_ref_mutex);
 	scsi = ide_scsi_g(disk);
 	if (scsi)
 		scsi_host_get(scsi->host);
-	up(&idescsi_ref_sem);
+	mutex_unlock(&idescsi_ref_mutex);
 	return scsi;
 }
 
 static void ide_scsi_put(struct ide_scsi_obj *scsi)
 {
-	down(&idescsi_ref_sem);
+	mutex_lock(&idescsi_ref_mutex);
 	scsi_host_put(scsi->host);
-	up(&idescsi_ref_sem);
+	mutex_unlock(&idescsi_ref_mutex);
 }
 
 static inline idescsi_scsi_t *scsihost_to_idescsi(struct Scsi_Host *host)
diff -urN oldtree/drivers/scsi/ipr.c newtree/drivers/scsi/ipr.c
--- oldtree/drivers/scsi/ipr.c	2006-02-19 11:41:03.795766056 +0000
+++ newtree/drivers/scsi/ipr.c	2006-02-21 15:58:18.923269784 +0000
@@ -5831,6 +5831,109 @@
 }
 
 /**
+ * ipr_reset_freeze - Hold off all I/O activity
+ * @ipr_cmd:	ipr command struct
+ *
+ * Description: If the PCI slot is frozen, hold off all I/O
+ * activity; then, as soon as the slot is available again,
+ * initiate an adapter reset.
+ */
+static int ipr_reset_freeze(struct ipr_cmnd *ipr_cmd)
+{
+	/* Disallow new interrupts, avoid loop */
+	ipr_cmd->ioa_cfg->allow_interrupts = 0;
+	list_add_tail(&ipr_cmd->queue, &ipr_cmd->ioa_cfg->pending_q);
+	ipr_cmd->done = ipr_reset_ioa_job;
+	return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_pci_frozen - Called when slot has experienced a PCI bus error.
+ * @pdev:	PCI device struct
+ *
+ * Description: This routine is called to tell us that the PCI bus
+ * is down. Can't do anything here, except put the device driver
+ * into a holding pattern, waiting for the PCI bus to come back.
+ */
+static void ipr_pci_frozen(struct pci_dev *pdev)
+{
+	unsigned long flags = 0;
+	struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+	_ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_freeze, IPR_SHUTDOWN_NONE);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+}
+
+/**
+ * ipr_pci_slot_reset - Called when PCI slot has been reset.
+ * @pdev:	PCI device struct
+ *
+ * Description: This routine is called by the pci error recovery
+ * code after the PCI slot has been reset, just before we
+ * should resume normal operations.
+ */
+static pci_ers_result_t ipr_pci_slot_reset(struct pci_dev *pdev)
+{
+	unsigned long flags = 0;
+	struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+	_ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space,
+	                                 IPR_SHUTDOWN_NONE);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * ipr_pci_perm_failure - Called when PCI slot is dead for good.
+ * @pdev:	PCI device struct
+ *
+ * Description: This routine is called when the PCI bus has
+ * permanently failed.
+ */
+static void ipr_pci_perm_failure(struct pci_dev *pdev)
+{
+	unsigned long flags = 0;
+	struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+	if (ioa_cfg->sdt_state == WAIT_FOR_DUMP)
+		ioa_cfg->sdt_state = ABORT_DUMP;
+	ioa_cfg->reset_retries = IPR_NUM_RESET_RELOAD_RETRIES;
+	ioa_cfg->in_ioa_bringdown = 1;
+	ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+}
+
+/**
+ * ipr_pci_error_detected - Called when a PCI error is detected.
+ * @pdev:	PCI device struct
+ * @state:	PCI channel state
+ *
+ * Description: Called when a PCI error is detected.
+ *
+ * Return value:
+ * 	PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT
+ */
+static pci_ers_result_t ipr_pci_error_detected(struct pci_dev *pdev,
+					       pci_channel_state_t state)
+{
+	switch (state) {
+	case pci_channel_io_frozen:
+		ipr_pci_frozen(pdev);
+		return PCI_ERS_RESULT_NEED_RESET;
+	case pci_channel_io_perm_failure:
+		ipr_pci_perm_failure(pdev);
+		return PCI_ERS_RESULT_DISCONNECT;
+		break;
+	default:
+		break;
+	}
+	return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
  * ipr_probe_ioa_part2 - Initializes IOAs found in ipr_probe_ioa(..)
  * @ioa_cfg:	ioa cfg struct
  *
@@ -6601,12 +6704,18 @@
 };
 MODULE_DEVICE_TABLE(pci, ipr_pci_table);
 
+static struct pci_error_handlers ipr_err_handler = {
+	.error_detected = ipr_pci_error_detected,
+	.slot_reset = ipr_pci_slot_reset,
+};
+
 static struct pci_driver ipr_driver = {
 	.name = IPR_NAME,
 	.id_table = ipr_pci_table,
 	.probe = ipr_probe,
 	.remove = ipr_remove,
 	.shutdown = ipr_shutdown,
+	.err_handler = &ipr_err_handler,
 };
 
 /**
diff -urN oldtree/drivers/scsi/iscsi_tcp.c newtree/drivers/scsi/iscsi_tcp.c
--- oldtree/drivers/scsi/iscsi_tcp.c	2006-02-19 11:41:03.803764840 +0000
+++ newtree/drivers/scsi/iscsi_tcp.c	2006-02-21 15:58:30.893450040 +0000
@@ -3200,8 +3200,8 @@
 		 * Data-Out PDU's within R2T-sequence can be quite big;
 		 * using mempool
 		 */
-		ctask->datapool = mempool_create(ISCSI_DTASK_DEFAULT_MAX,
-			 mempool_alloc_slab, mempool_free_slab, taskcache);
+		ctask->datapool = mempool_create_slab_pool(ISCSI_DTASK_DEFAULT_MAX,
+							   taskcache);
 		if (ctask->datapool == NULL) {
 			kfifo_free(ctask->r2tqueue);
 			iscsi_pool_free(&ctask->r2tpool, (void**)ctask->r2ts);
diff -urN oldtree/drivers/scsi/jazz_esp.c newtree/drivers/scsi/jazz_esp.c
--- oldtree/drivers/scsi/jazz_esp.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/scsi/jazz_esp.c	2006-02-21 15:58:18.946266288 +0000
@@ -52,7 +52,6 @@
 				 * via PIO.
 				 */
 
-int jazz_esp_detect(struct scsi_host_template *tpnt);
 static int jazz_esp_release(struct Scsi_Host *shost)
 {
 	if (shost->irq)
@@ -65,27 +64,6 @@
 	return 0;
 }
 
-static struct scsi_host_template driver_template = {
-	.proc_name		= "jazz_esp",
-	.proc_info		= &esp_proc_info,
-	.name			= "ESP 100/100a/200",
-	.detect			= jazz_esp_detect,
-	.slave_alloc		= esp_slave_alloc,
-	.slave_destroy		= esp_slave_destroy,
-	.release		= jazz_esp_release,
-	.info			= esp_info,
-	.queuecommand		= esp_queue,
-	.eh_abort_handler	= esp_abort,
-	.eh_bus_reset_handler	= esp_reset,
-	.can_queue		= 7,
-	.this_id		= 7,
-	.sg_tablesize		= SG_ALL,
-	.cmd_per_lun		= 1,
-	.use_clustering		= DISABLE_CLUSTERING,
-};
-
-#include "scsi_module.c"
-
 /***************************************************************** Detection */
 static int jazz_esp_detect(struct scsi_host_template *tpnt)
 {
@@ -96,7 +74,7 @@
      * first assumption it is there:-)
      */
     if (1) {
-	esp_dev = 0;
+	esp_dev = NULL;
 	esp = esp_allocate(tpnt, (void *) esp_dev);
 	
 	/* Do command transfer with programmed I/O */
@@ -115,13 +93,13 @@
 	esp->dma_setup = &dma_setup;
 
 	/* Optional functions */
-	esp->dma_barrier = 0;
-	esp->dma_drain = 0;
-	esp->dma_invalidate = 0;
-	esp->dma_irq_entry = 0;
-	esp->dma_irq_exit = 0;
-	esp->dma_poll = 0;
-	esp->dma_reset = 0;
+	esp->dma_barrier = NULL;
+	esp->dma_drain = NULL;
+	esp->dma_invalidate = NULL;
+	esp->dma_irq_entry = NULL;
+	esp->dma_irq_exit = NULL;
+	esp->dma_poll = NULL;
+	esp->dma_reset = NULL;
 	esp->dma_led_off = &dma_led_off;
 	esp->dma_led_on = &dma_led_on;
 	
@@ -141,7 +119,7 @@
 	 * of DMA channel, so we can use the jazz DMA functions
 	 * 
 	 */
-	esp->dregs = JAZZ_SCSI_DMA;
+	esp->dregs = (void *) JAZZ_SCSI_DMA;
 	
 	/* ESP register base */
 	esp->eregs = (struct ESP_regs *)(JAZZ_SCSI_BASE);
diff -urN oldtree/drivers/scsi/lpfc/lpfc_mem.c newtree/drivers/scsi/lpfc/lpfc_mem.c
--- oldtree/drivers/scsi/lpfc/lpfc_mem.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/scsi/lpfc/lpfc_mem.c	2006-02-21 15:58:30.768469040 +0000
@@ -38,18 +38,6 @@
 #define LPFC_MBUF_POOL_SIZE     64      /* max elements in MBUF safety pool */
 #define LPFC_MEM_POOL_SIZE      64      /* max elem in non-DMA safety pool */
 
-static void *
-lpfc_pool_kmalloc(gfp_t gfp_flags, void *data)
-{
-	return kmalloc((unsigned long)data, gfp_flags);
-}
-
-static void
-lpfc_pool_kfree(void *obj, void *data)
-{
-	kfree(obj);
-}
-
 int
 lpfc_mem_alloc(struct lpfc_hba * phba)
 {
@@ -79,15 +67,13 @@
 		pool->current_count++;
 	}
 
-	phba->mbox_mem_pool = mempool_create(LPFC_MEM_POOL_SIZE,
-				lpfc_pool_kmalloc, lpfc_pool_kfree,
-				(void *)(unsigned long)sizeof(LPFC_MBOXQ_t));
+	phba->mbox_mem_pool = mempool_create_kmalloc_pool(LPFC_MEM_POOL_SIZE,
+							 sizeof(LPFC_MBOXQ_t));
 	if (!phba->mbox_mem_pool)
 		goto fail_free_mbuf_pool;
 
-	phba->nlp_mem_pool = mempool_create(LPFC_MEM_POOL_SIZE,
-			lpfc_pool_kmalloc, lpfc_pool_kfree,
-			(void *)(unsigned long)sizeof(struct lpfc_nodelist));
+	phba->nlp_mem_pool = mempool_create_kmalloc_pool(LPFC_MEM_POOL_SIZE,
+						sizeof(struct lpfc_nodelist));
 	if (!phba->nlp_mem_pool)
 		goto fail_free_mbox_pool;
 
diff -urN oldtree/drivers/scsi/megaraid.c newtree/drivers/scsi/megaraid.c
--- oldtree/drivers/scsi/megaraid.c	2006-02-19 11:41:03.907749032 +0000
+++ newtree/drivers/scsi/megaraid.c	2006-02-21 15:58:19.097243336 +0000
@@ -4470,7 +4470,6 @@
 {
 	Scsi_Cmnd	*scmd;
 	struct	scsi_device *sdev;
-	unsigned long	flags = 0;
 	scb_t	*scb;
 	int	rval;
 
diff -urN oldtree/drivers/scsi/ncr53c8xx.c newtree/drivers/scsi/ncr53c8xx.c
--- oldtree/drivers/scsi/ncr53c8xx.c	2006-02-19 11:41:03.913748120 +0000
+++ newtree/drivers/scsi/ncr53c8xx.c	2006-02-21 15:58:18.997258536 +0000
@@ -69,6 +69,10 @@
 **     Low PCI traffic for command handling when on-chip RAM is present.
 **     Aggressive SCSI SCRIPTS optimizations.
 **
+**  2005 by Matthew Wilcox and James Bottomley
+**     PCI-ectomy.  This driver now supports only the 720 chip (see the
+**     NCR_Q720 and zalon drivers for the bus probe logic).
+**
 *******************************************************************************
 */
 
@@ -90,13 +94,6 @@
 
 #define SCSI_NCR_DEBUG_FLAGS	(0)
 
-/*==========================================================
-**
-**      Include files
-**
-**==========================================================
-*/
-
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
@@ -121,6 +118,7 @@
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsi_transport.h>
@@ -128,10 +126,8 @@
 
 #include "ncr53c8xx.h"
 
-#define NAME53C			"ncr53c"
 #define NAME53C8XX		"ncr53c8xx"
 
-
 /*==========================================================
 **
 **	Debugging tags
@@ -2111,7 +2107,7 @@
 	*/
 
 	/*
-	**	The M_REJECT problem seems to be due to a selection 
+	**	The MESSAGE_REJECT problem seems to be due to a selection 
 	**	timing problem.
 	**	Wait immediately for the selection to complete. 
 	**	(2.5x behaves so)
@@ -2162,7 +2158,7 @@
 	/*
 	**	Selection complete.
 	**	Send the IDENTIFY and SIMPLE_TAG messages
-	**	(and the M_X_SYNC_REQ message)
+	**	(and the EXTENDED_SDTR message)
 	*/
 	SCR_MOVE_TBL ^ SCR_MSG_OUT,
 		offsetof (struct dsb, smsg),
@@ -2191,7 +2187,7 @@
 	/*
 	**	Initialize the msgout buffer with a NOOP message.
 	*/
-	SCR_LOAD_REG (scratcha, M_NOOP),
+	SCR_LOAD_REG (scratcha, NOP),
 		0,
 	SCR_COPY (1),
 		RADDR (scratcha),
@@ -2343,21 +2339,21 @@
 	/*
 	**	Handle this message.
 	*/
-	SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)),
+	SCR_JUMP ^ IFTRUE (DATA (COMMAND_COMPLETE)),
 		PADDR (complete),
-	SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)),
+	SCR_JUMP ^ IFTRUE (DATA (DISCONNECT)),
 		PADDR (disconnect),
-	SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)),
+	SCR_JUMP ^ IFTRUE (DATA (SAVE_POINTERS)),
 		PADDR (save_dp),
-	SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)),
+	SCR_JUMP ^ IFTRUE (DATA (RESTORE_POINTERS)),
 		PADDR (restore_dp),
-	SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
+	SCR_JUMP ^ IFTRUE (DATA (EXTENDED_MESSAGE)),
 		PADDRH (msg_extended),
-	SCR_JUMP ^ IFTRUE (DATA (M_NOOP)),
+	SCR_JUMP ^ IFTRUE (DATA (NOP)),
 		PADDR (clrack),
-	SCR_JUMP ^ IFTRUE (DATA (M_REJECT)),
+	SCR_JUMP ^ IFTRUE (DATA (MESSAGE_REJECT)),
 		PADDRH (msg_reject),
-	SCR_JUMP ^ IFTRUE (DATA (M_IGN_RESIDUE)),
+	SCR_JUMP ^ IFTRUE (DATA (IGNORE_WIDE_RESIDUE)),
 		PADDRH (msg_ign_residue),
 	/*
 	**	Rest of the messages left as
@@ -2372,7 +2368,7 @@
 	*/
 	SCR_INT,
 		SIR_REJECT_SENT,
-	SCR_LOAD_REG (scratcha, M_REJECT),
+	SCR_LOAD_REG (scratcha, MESSAGE_REJECT),
 		0,
 }/*-------------------------< SETMSG >----------------------*/,{
 	SCR_COPY (1),
@@ -2564,7 +2560,7 @@
 	/*
 	**	If it was no ABORT message ...
 	*/
-	SCR_JUMP ^ IFTRUE (DATA (M_ABORT)),
+	SCR_JUMP ^ IFTRUE (DATA (ABORT_TASK_SET)),
 		PADDRH (msg_out_abort),
 	/*
 	**	... wait for the next phase
@@ -2576,7 +2572,7 @@
 	/*
 	**	... else clear the message ...
 	*/
-	SCR_LOAD_REG (scratcha, M_NOOP),
+	SCR_LOAD_REG (scratcha, NOP),
 		0,
 	SCR_COPY (4),
 		RADDR (scratcha),
@@ -3035,7 +3031,7 @@
 	*/
 	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
 		NADDR (msgin[2]),
-	SCR_JUMP ^ IFTRUE (DATA (M_X_WIDE_REQ)),
+	SCR_JUMP ^ IFTRUE (DATA (EXTENDED_WDTR)),
 		PADDRH (msg_wdtr),
 	/*
 	**	unknown extended message
@@ -3069,7 +3065,7 @@
 
 }/*-------------------------< SEND_WDTR >----------------*/,{
 	/*
-	**	Send the M_X_WIDE_REQ
+	**	Send the EXTENDED_WDTR
 	*/
 	SCR_MOVE_ABS (4) ^ SCR_MSG_OUT,
 		NADDR (msgout),
@@ -3089,7 +3085,7 @@
 	*/
 	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
 		NADDR (msgin[2]),
-	SCR_JUMP ^ IFTRUE (DATA (M_X_SYNC_REQ)),
+	SCR_JUMP ^ IFTRUE (DATA (EXTENDED_SDTR)),
 		PADDRH (msg_sdtr),
 	/*
 	**	unknown extended message
@@ -3124,7 +3120,7 @@
 
 }/*-------------------------< SEND_SDTR >-------------*/,{
 	/*
-	**	Send the M_X_SYNC_REQ
+	**	Send the EXTENDED_SDTR
 	*/
 	SCR_MOVE_ABS (5) ^ SCR_MSG_OUT,
 		NADDR (msgout),
@@ -3202,10 +3198,10 @@
 
 }/*-------------------------< RESET >----------------------*/,{
 	/*
-	**      Send a M_RESET message if bad IDENTIFY 
+	**      Send a TARGET_RESET message if bad IDENTIFY 
 	**	received on reselection.
 	*/
-	SCR_LOAD_REG (scratcha, M_ABORT_TAG),
+	SCR_LOAD_REG (scratcha, ABORT_TASK),
 		0,
 	SCR_JUMP,
 		PADDRH (abort_resel),
@@ -3213,7 +3209,7 @@
 	/*
 	**      Abort a wrong tag received on reselection.
 	*/
-	SCR_LOAD_REG (scratcha, M_ABORT_TAG),
+	SCR_LOAD_REG (scratcha, ABORT_TASK),
 		0,
 	SCR_JUMP,
 		PADDRH (abort_resel),
@@ -3221,7 +3217,7 @@
 	/*
 	**      Abort a reselection when no active CCB.
 	*/
-	SCR_LOAD_REG (scratcha, M_ABORT),
+	SCR_LOAD_REG (scratcha, ABORT_TASK_SET),
 		0,
 }/*-------------------------< ABORT_RESEL >----------------*/,{
 	SCR_COPY (1),
@@ -3333,7 +3329,7 @@
 	**	Read the message, since we got it directly 
 	**	from the SCSI BUS data lines.
 	**	Signal problem to C code for logging the event.
-	**	Send a M_ABORT to clear all pending tasks.
+	**	Send an ABORT_TASK_SET to clear all pending tasks.
 	*/
 	SCR_INT,
 		SIR_RESEL_BAD_LUN,
@@ -3345,7 +3341,7 @@
 	/*
 	**	We donnot have a task for that I_T_L.
 	**	Signal problem to C code for logging the event.
-	**	Send a M_ABORT message.
+	**	Send an ABORT_TASK_SET message.
 	*/
 	SCR_INT,
 		SIR_RESEL_BAD_I_T_L,
@@ -3355,7 +3351,7 @@
 	/*
 	**	We donnot have a task that matches the tag.
 	**	Signal problem to C code for logging the event.
-	**	Send a M_ABORTTAG message.
+	**	Send an ABORT_TASK message.
 	*/
 	SCR_INT,
 		SIR_RESEL_BAD_I_T_L_Q,
@@ -3366,7 +3362,7 @@
 	**	We donnot know the target that reselected us.
 	**	Grab the first message if any (IDENTIFY).
 	**	Signal problem to C code for logging the event.
-	**	M_RESET message.
+	**	TARGET_RESET message.
 	*/
 	SCR_INT,
 		SIR_RESEL_BAD_TARGET,
@@ -4109,17 +4105,11 @@
 
 	switch (nego) {
 	case NS_SYNC:
-		msgptr[msglen++] = M_EXTENDED;
-		msgptr[msglen++] = 3;
-		msgptr[msglen++] = M_X_SYNC_REQ;
-		msgptr[msglen++] = tp->maxoffs ? tp->minsync : 0;
-		msgptr[msglen++] = tp->maxoffs;
+		msglen += spi_populate_sync_msg(msgptr + msglen,
+				tp->maxoffs ? tp->minsync : 0, tp->maxoffs);
 		break;
 	case NS_WIDE:
-		msgptr[msglen++] = M_EXTENDED;
-		msgptr[msglen++] = 2;
-		msgptr[msglen++] = M_X_WIDE_REQ;
-		msgptr[msglen++] = tp->usrwide;
+		msglen += spi_populate_width_msg(msgptr + msglen, tp->usrwide);
 		break;
 	}
 
@@ -4220,7 +4210,7 @@
 	**----------------------------------------------------
 	*/
 
-	idmsg = M_IDENTIFY | sdev->lun;
+	idmsg = IDENTIFY(0, sdev->lun);
 
 	if (cp ->tag != NO_TAG ||
 		(cp != np->ccb && np->disc && !(tp->usrflag & UF_NODISC)))
@@ -4239,7 +4229,7 @@
 		*/
 		if (lp && time_after(jiffies, lp->tags_stime)) {
 			if (lp->tags_smap) {
-				order = M_ORDERED_TAG;
+				order = ORDERED_QUEUE_TAG;
 				if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>2){ 
 					PRINT_ADDR(cmd,
 						"ordered tag forced.\n");
@@ -4257,10 +4247,10 @@
 			case 0x08:  /* READ_SMALL (6) */
 			case 0x28:  /* READ_BIG  (10) */
 			case 0xa8:  /* READ_HUGE (12) */
-				order = M_SIMPLE_TAG;
+				order = SIMPLE_QUEUE_TAG;
 				break;
 			default:
-				order = M_ORDERED_TAG;
+				order = ORDERED_QUEUE_TAG;
 			}
 		}
 		msgptr[msglen++] = order;
@@ -6229,9 +6219,9 @@
 	if (!(dbc & 0xc0000000))
 		phase = (dbc >> 24) & 7;
 	if (phase == 7)
-		msg = M_PARITY;
+		msg = MSG_PARITY_ERROR;
 	else
-		msg = M_ID_ERROR;
+		msg = INITIATOR_ERROR;
 
 
 	/*
@@ -6795,6 +6785,8 @@
 /*-----------------------------------------------------------------------------
 **
 **	Was Sie schon immer ueber transfermode negotiation wissen wollten ...
+**	("Everything you've always wanted to know about transfer mode
+**	  negotiation")
 **
 **	We try to negotiate sync and wide transfer only after
 **	a successful inquire command. We look at byte 7 of the
@@ -6896,8 +6888,8 @@
 			break;
 
 		}
-		np->msgin [0] = M_NOOP;
-		np->msgout[0] = M_NOOP;
+		np->msgin [0] = NOP;
+		np->msgout[0] = NOP;
 		cp->nego_status = 0;
 		break;
 
@@ -6991,12 +6983,7 @@
 		spi_offset(starget) = ofs;
 		ncr_setsync(np, cp, scntl3, (fak<<5)|ofs);
 
-		np->msgout[0] = M_EXTENDED;
-		np->msgout[1] = 3;
-		np->msgout[2] = M_X_SYNC_REQ;
-		np->msgout[3] = per;
-		np->msgout[4] = ofs;
-
+		spi_populate_sync_msg(np->msgout, per, ofs);
 		cp->nego_status = NS_SYNC;
 
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
@@ -7007,7 +6994,7 @@
 			OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad));
 			return;
 		}
-		np->msgin [0] = M_NOOP;
+		np->msgin [0] = NOP;
 
 		break;
 
@@ -7082,13 +7069,9 @@
 
 		spi_width(starget) = wide;
 		ncr_setwide(np, cp, wide, 1);
+		spi_populate_width_msg(np->msgout, wide);
 
-		np->msgout[0] = M_EXTENDED;
-		np->msgout[1] = 2;
-		np->msgout[2] = M_X_WIDE_REQ;
-		np->msgout[3] = wide;
-
-		np->msgin [0] = M_NOOP;
+		np->msgin [0] = NOP;
 
 		cp->nego_status = NS_WIDE;
 
@@ -7107,12 +7090,12 @@
 	case SIR_REJECT_RECEIVED:
 		/*-----------------------------------------------
 		**
-		**	We received a M_REJECT message.
+		**	We received a MESSAGE_REJECT.
 		**
 		**-----------------------------------------------
 		*/
 
-		PRINT_ADDR(cp->cmd, "M_REJECT received (%x:%x).\n",
+		PRINT_ADDR(cp->cmd, "MESSAGE_REJECT received (%x:%x).\n",
 			(unsigned)scr_to_cpu(np->lastmsg), np->msgout[0]);
 		break;
 
@@ -7124,7 +7107,7 @@
 		**-----------------------------------------------
 		*/
 
-		ncr_print_msg(cp, "M_REJECT sent for", np->msgin);
+		ncr_print_msg(cp, "MESSAGE_REJECT sent for", np->msgin);
 		break;
 
 /*--------------------------------------------------------------------
@@ -7143,7 +7126,7 @@
 		**-----------------------------------------------
 		*/
 
-		PRINT_ADDR(cp->cmd, "M_IGN_RESIDUE received, but not yet "
+		PRINT_ADDR(cp->cmd, "IGNORE_WIDE_RESIDUE received, but not yet "
 				"implemented.\n");
 		break;
 #if 0
@@ -7156,7 +7139,7 @@
 		**-----------------------------------------------
 		*/
 
-		PRINT_ADDR(cp->cmd, "M_DISCONNECT received, but datapointer "
+		PRINT_ADDR(cp->cmd, "DISCONNECT received, but datapointer "
 				"not saved: data=%x save=%x goal=%x.\n",
 			(unsigned) INL (nc_temp),
 			(unsigned) scr_to_cpu(np->header.savep),
@@ -7862,7 +7845,7 @@
 **==========================================================
 **
 **	Note: we have to return the correct value.
-**	THERE IS NO SAVE DEFAULT VALUE.
+**	THERE IS NO SAFE DEFAULT VALUE.
 **
 **	Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock.
 **	53C860 and 53C875 rev. 1 support fast20 transfers but 
@@ -8562,7 +8545,7 @@
 
 	/* use SIMPLE TAG messages by default */
 #ifdef SCSI_NCR_ALWAYS_SIMPLE_TAG
-	np->order = M_SIMPLE_TAG;
+	np->order = SIMPLE_QUEUE_TAG;
 #endif
 
 	spin_unlock_irqrestore(&np->smp_lock, flags);
diff -urN oldtree/drivers/scsi/ncr53c8xx.h newtree/drivers/scsi/ncr53c8xx.h
--- oldtree/drivers/scsi/ncr53c8xx.h	2006-02-19 11:41:03.915747816 +0000
+++ newtree/drivers/scsi/ncr53c8xx.h	2006-02-21 15:58:19.003257624 +0000
@@ -56,8 +56,10 @@
 #include <linux/config.h>
 #include <scsi/scsi_host.h>
 
+#include <linux/config.h>
+
 /*
-**	If you want a driver as small as possible, do not define the 
+**	If you want a driver as small as possible, donnot define the 
 **	following options.
 */
 #define SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
@@ -1255,39 +1257,6 @@
 */
 
 /*
-**	Messages
-*/
-
-#define	M_COMPLETE	COMMAND_COMPLETE
-#define	M_EXTENDED	EXTENDED_MESSAGE
-#define	M_SAVE_DP	SAVE_POINTERS
-#define	M_RESTORE_DP	RESTORE_POINTERS
-#define	M_DISCONNECT	DISCONNECT
-#define	M_ID_ERROR	INITIATOR_ERROR
-#define	M_ABORT		ABORT_TASK_SET
-#define	M_REJECT	MESSAGE_REJECT
-#define	M_NOOP		NOP
-#define	M_PARITY	MSG_PARITY_ERROR
-#define	M_LCOMPLETE	LINKED_CMD_COMPLETE
-#define	M_FCOMPLETE	LINKED_FLG_CMD_COMPLETE
-#define	M_RESET		TARGET_RESET
-#define	M_ABORT_TAG	ABORT_TASK
-#define	M_CLEAR_QUEUE	CLEAR_TASK_SET
-#define	M_INIT_REC	INITIATE_RECOVERY
-#define	M_REL_REC	RELEASE_RECOVERY
-#define	M_TERMINATE	(0x11)
-#define	M_SIMPLE_TAG	SIMPLE_QUEUE_TAG
-#define	M_HEAD_TAG	HEAD_OF_QUEUE_TAG
-#define	M_ORDERED_TAG	ORDERED_QUEUE_TAG
-#define	M_IGN_RESIDUE	IGNORE_WIDE_RESIDUE
-#define	M_IDENTIFY   	(0x80)
-
-#define	M_X_MODIFY_DP	EXTENDED_MODIFY_DATA_POINTER
-#define	M_X_SYNC_REQ	EXTENDED_SDTR
-#define	M_X_WIDE_REQ	EXTENDED_WDTR
-#define	M_X_PPR_REQ	EXTENDED_PPR
-
-/*
 **	Status
 */
 
diff -urN oldtree/drivers/scsi/osst.c newtree/drivers/scsi/osst.c
--- oldtree/drivers/scsi/osst.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/scsi/osst.c	2006-02-21 15:58:36.061664352 +0000
@@ -48,8 +48,8 @@
 #include <linux/vmalloc.h>
 #include <linux/blkdev.h>
 #include <linux/moduleparam.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/delay.h>
+#include <linux/jiffies.h>
 #include <asm/uaccess.h>
 #include <asm/dma.h>
 #include <asm/system.h>
@@ -87,6 +87,7 @@
 MODULE_AUTHOR("Willem Riede");
 MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(OSST_MAJOR);
 
 module_param(max_dev, int, 0444);
 MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)");
@@ -107,8 +108,6 @@
 };
 #endif
 
-static char *osst_formats[ST_NBR_MODES] ={"", "l", "m", "a"};
-
 /* Some default definitions have been moved to osst_options.h */
 #define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE)
 #define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE)
@@ -803,7 +802,7 @@
 		    ) && result >= 0)
 		{
 #if DEBUG			
-			if (debugging || jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC)
+			if (debugging || time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC))
 				printk (OSST_DEB_MSG
 					"%s:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n",
 					name, curr, curr+minlast, STp->first_frame_position,
@@ -814,7 +813,7 @@
 			return 0;
 		}
 #if DEBUG
-		if (jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC && notyetprinted)
+		if (time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC) && notyetprinted)
 		{
 			printk (OSST_DEB_MSG "%s:D: Wait for frame %i (>%i): %i-%i %i (%i)\n",
 				name, curr, curr+minlast, STp->first_frame_position,
@@ -5667,7 +5666,7 @@
 	struct st_partstat * STps;
 	struct osst_buffer * buffer;
 	struct gendisk	   * drive;
-	int		     i, mode, dev_num;
+	int		     i, dev_num;
 
 	if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
 		return -ENODEV;
@@ -5803,18 +5802,6 @@
 		snprintf(name, 8, "%s%s", "n", tape_name(tpnt));
 		osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name);
 	}
-	for (mode = 0; mode < ST_NBR_MODES; ++mode) {
-		/*  Rewind entry  */
-		devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5)),
-				S_IFCHR | S_IRUGO | S_IWUGO,
-				"%s/ot%s", SDp->devfs_name, osst_formats[mode]);
-
-		/*  No-rewind entry  */
-		devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5) + 128),
-				S_IFCHR | S_IRUGO | S_IWUGO,
-				"%s/ot%sn", SDp->devfs_name, osst_formats[mode]);
-	}
-	drive->number = devfs_register_tape(SDp->devfs_name);
 
 	sdev_printk(KERN_INFO, SDp,
 		"osst :I: Attached OnStream %.5s tape as %s\n",
@@ -5831,7 +5818,7 @@
 {
 	struct scsi_device * SDp = to_scsi_device(dev);
 	struct osst_tape * tpnt;
-	int i, mode;
+	int i;
 
 	if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0))
 		return 0;
@@ -5842,11 +5829,6 @@
 			osst_sysfs_destroy(MKDEV(OSST_MAJOR, i));
 			osst_sysfs_destroy(MKDEV(OSST_MAJOR, i+128));
 			tpnt->device = NULL;
-			for (mode = 0; mode < ST_NBR_MODES; ++mode) {
-				devfs_remove("%s/ot%s", SDp->devfs_name, osst_formats[mode]);
-				devfs_remove("%s/ot%sn", SDp->devfs_name, osst_formats[mode]);
-			}
-			devfs_unregister_tape(tpnt->drive->number);
 			put_disk(tpnt->drive);
 			os_scsi_tapes[i] = NULL;
 			osst_nr_dev--;
diff -urN oldtree/drivers/scsi/pcmcia/aha152x_stub.c newtree/drivers/scsi/pcmcia/aha152x_stub.c
--- oldtree/drivers/scsi/pcmcia/aha152x_stub.c	2006-02-19 11:41:03.916747664 +0000
+++ newtree/drivers/scsi/pcmcia/aha152x_stub.c	2006-02-21 15:58:08.890794952 +0000
@@ -275,10 +275,8 @@
 
 	link->state &= ~DEV_SUSPEND;
 	if (link->state & DEV_CONFIG) {
-		Scsi_Cmnd tmp;
 		pcmcia_request_configuration(link->handle, &link->conf);
-		tmp.device->host = info->host;
-		aha152x_host_reset(&tmp);
+	    aha152x_host_reset_host(info->host);
 	}
 
 	return 0;
diff -urN oldtree/drivers/scsi/ppa.c newtree/drivers/scsi/ppa.c
--- oldtree/drivers/scsi/ppa.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/scsi/ppa.c	2006-02-21 15:58:36.067663440 +0000
@@ -18,6 +18,7 @@
 #include <linux/parport.h>
 #include <linux/workqueue.h>
 #include <linux/delay.h>
+#include <linux/jiffies.h>
 #include <asm/io.h>
 
 #include <scsi/scsi.h>
@@ -726,7 +727,7 @@
 				retv--;
 
 			if (retv) {
-				if ((jiffies - dev->jstart) > (1 * HZ)) {
+				if (time_after(jiffies, dev->jstart + (1 * HZ))) {
 					printk
 					    ("ppa: Parallel port cable is unplugged!!\n");
 					ppa_fail(dev, DID_BUS_BUSY);
diff -urN oldtree/drivers/scsi/qla2xxx/qla_os.c newtree/drivers/scsi/qla2xxx/qla_os.c
--- oldtree/drivers/scsi/qla2xxx/qla_os.c	2006-02-19 11:41:04.059725928 +0000
+++ newtree/drivers/scsi/qla2xxx/qla_os.c	2006-02-21 15:58:30.918446240 +0000
@@ -2118,8 +2118,7 @@
 	int      rval;
 
 	rval = QLA_SUCCESS;
-	ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab,
-	    mempool_free_slab, srb_cachep);
+	ha->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep);
 	if (ha->srb_mempool == NULL) {
 		qla_printk(KERN_INFO, ha, "Unable to allocate SRB mempool.\n");
 		rval = QLA_FUNCTION_FAILED;
diff -urN oldtree/drivers/scsi/qlogicfc.c newtree/drivers/scsi/qlogicfc.c
--- oldtree/drivers/scsi/qlogicfc.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/scsi/qlogicfc.c	2006-02-21 15:58:36.072662680 +0000
@@ -61,6 +61,7 @@
 #include <linux/unistd.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
+#include <linux/jiffies.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include "scsi.h"
@@ -1325,7 +1326,7 @@
 		cmd->control_flags = cpu_to_le16(CFLAG_READ);
 
 	if (Cmnd->device->tagged_supported) {
-		if ((jiffies - hostdata->tag_ages[Cmnd->device->id]) > (2 * ISP_TIMEOUT)) {
+		if (time_after(jiffies, hostdata->tag_ages[Cmnd->device->id] + (2 * ISP_TIMEOUT))) {
 			cmd->control_flags |= cpu_to_le16(CFLAG_ORDERED_TAG);
 			hostdata->tag_ages[Cmnd->device->id] = jiffies;
 		} else
diff -urN oldtree/drivers/scsi/qlogicpti.c newtree/drivers/scsi/qlogicpti.c
--- oldtree/drivers/scsi/qlogicpti.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/scsi/qlogicpti.c	2006-02-21 15:58:36.076662072 +0000
@@ -24,6 +24,7 @@
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/jiffies.h>
 
 #include <asm/byteorder.h>
 
@@ -1017,7 +1018,7 @@
 	if (Cmnd->device->tagged_supported) {
 		if (qpti->cmd_count[Cmnd->device->id] == 0)
 			qpti->tag_ages[Cmnd->device->id] = jiffies;
-		if ((jiffies - qpti->tag_ages[Cmnd->device->id]) > (5*HZ)) {
+		if (time_after(jiffies, qpti->tag_ages[Cmnd->device->id] + (5*HZ))) {
 			cmd->control_flags = CFLAG_ORDERED_TAG;
 			qpti->tag_ages[Cmnd->device->id] = jiffies;
 		} else
diff -urN oldtree/drivers/scsi/scsi.c newtree/drivers/scsi/scsi.c
--- oldtree/drivers/scsi/scsi.c	2006-02-19 11:41:04.072723952 +0000
+++ newtree/drivers/scsi/scsi.c	2006-02-21 15:58:19.026254128 +0000
@@ -48,7 +48,6 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/completion.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/unistd.h>
 #include <linux/spinlock.h>
 #include <linux/kmod.h>
@@ -136,9 +135,8 @@
 	const int size = offset + sizeof(struct request);
 	struct scsi_request *sreq;
   
-	sreq = kmalloc(size, gfp_mask);
+	sreq = kzalloc(size, gfp_mask);
 	if (likely(sreq != NULL)) {
-		memset(sreq, 0, size);
 		sreq->sr_request = (struct request *)(((char *)sreq) + offset);
 		sreq->sr_device = sdev;
 		sreq->sr_host = sdev->host;
@@ -1248,7 +1246,6 @@
 	for_each_cpu(i)
 		INIT_LIST_HEAD(&per_cpu(scsi_done_q, i));
 
-	devfs_mk_dir("scsi");
 	printk(KERN_NOTICE "SCSI subsystem initialized\n");
 	return 0;
 
@@ -1273,7 +1270,6 @@
 	scsi_exit_sysctl();
 	scsi_exit_hosts();
 	scsi_exit_devinfo();
-	devfs_remove("scsi");
 	scsi_exit_procfs();
 	scsi_exit_queue();
 }
diff -urN oldtree/drivers/scsi/scsi_debug.c newtree/drivers/scsi/scsi_debug.c
--- oldtree/drivers/scsi/scsi_debug.c	2006-02-19 11:41:04.073723800 +0000
+++ newtree/drivers/scsi/scsi_debug.c	2006-02-21 15:58:19.028253824 +0000
@@ -1061,13 +1061,12 @@
 		}
 	}
 	if (NULL == open_devip) { /* try and make a new one */
-		open_devip = kmalloc(sizeof(*open_devip),GFP_KERNEL);
+		open_devip = kzalloc(sizeof(*open_devip),GFP_KERNEL);
 		if (NULL == open_devip) {
 			printk(KERN_ERR "%s: out of memory at line %d\n",
 				__FUNCTION__, __LINE__);
 			return NULL;
 		}
-		memset(open_devip, 0, sizeof(*open_devip));
 		open_devip->sdbg_host = sdbg_host;
 		list_add_tail(&open_devip->dev_list,
 		&sdbg_host->dev_info_list);
@@ -1814,7 +1813,7 @@
         struct sdebug_dev_info *sdbg_devinfo;
         struct list_head *lh, *lh_sf;
 
-        sdbg_host = kmalloc(sizeof(*sdbg_host),GFP_KERNEL);
+        sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
 
         if (NULL == sdbg_host) {
                 printk(KERN_ERR "%s: out of memory at line %d\n",
@@ -1822,19 +1821,17 @@
                 return -ENOMEM;
         }
 
-        memset(sdbg_host, 0, sizeof(*sdbg_host));
         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
 
 	devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
         for (k = 0; k < devs_per_host; k++) {
-                sdbg_devinfo = kmalloc(sizeof(*sdbg_devinfo),GFP_KERNEL);
+                sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo), GFP_KERNEL);
                 if (NULL == sdbg_devinfo) {
                         printk(KERN_ERR "%s: out of memory at line %d\n",
                                __FUNCTION__, __LINE__);
                         error = -ENOMEM;
 			goto clean;
                 }
-                memset(sdbg_devinfo, 0, sizeof(*sdbg_devinfo));
                 sdbg_devinfo->sdbg_host = sdbg_host;
                 list_add_tail(&sdbg_devinfo->dev_list,
                               &sdbg_host->dev_info_list);
diff -urN oldtree/drivers/scsi/scsi_ioctl.c newtree/drivers/scsi/scsi_ioctl.c
--- oldtree/drivers/scsi/scsi_ioctl.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/scsi/scsi_ioctl.c	2006-02-21 15:58:19.029253672 +0000
@@ -241,10 +241,9 @@
 		buf_needed = (buf_needed + 511) & ~511;
 		if (buf_needed > MAX_BUF)
 			buf_needed = MAX_BUF;
-		buf = kmalloc(buf_needed, gfp_mask);
+		buf = kzalloc(buf_needed, gfp_mask);
 		if (!buf)
 			return -ENOMEM;
-		memset(buf, 0, buf_needed);
 		if (inlen == 0) {
 			data_direction = DMA_FROM_DEVICE;
 		} else if (outlen == 0 ) {
diff -urN oldtree/drivers/scsi/scsi_lib.c newtree/drivers/scsi/scsi_lib.c
--- oldtree/drivers/scsi/scsi_lib.c	2006-02-19 11:41:04.076723344 +0000
+++ newtree/drivers/scsi/scsi_lib.c	2006-02-21 15:58:30.919446088 +0000
@@ -286,13 +286,12 @@
 	int result;
 	
 	if (sshdr) {
-		sense = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_NOIO);
+		sense = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_NOIO);
 		if (!sense)
 			return DRIVER_ERROR << 24;
-		memset(sense, 0, SCSI_SENSE_BUFFERSIZE);
 	}
 	result = scsi_execute(sdev, cmd, data_direction, buffer, bufflen,
-				  sense, timeout, retries, 0);
+			      sense, timeout, retries, 0);
 	if (sshdr)
 		scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, sshdr);
 
@@ -1788,9 +1787,8 @@
 					sgp->name);
 		}
 
-		sgp->pool = mempool_create(SG_MEMPOOL_SIZE,
-				mempool_alloc_slab, mempool_free_slab,
-				sgp->slab);
+		sgp->pool = mempool_create_slab_pool(SG_MEMPOOL_SIZE,
+						     sgp->slab);
 		if (!sgp->pool) {
 			printk(KERN_ERR "SCSI: can't init sg mempool %s\n",
 					sgp->name);
diff -urN oldtree/drivers/scsi/scsi_scan.c newtree/drivers/scsi/scsi_scan.c
--- oldtree/drivers/scsi/scsi_scan.c	2006-02-19 11:41:04.079722888 +0000
+++ newtree/drivers/scsi/scsi_scan.c	2006-02-21 15:58:19.032253216 +0000
@@ -205,12 +205,11 @@
 	int display_failure_msg = 1, ret;
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 
-	sdev = kmalloc(sizeof(*sdev) + shost->transportt->device_size,
+	sdev = kzalloc(sizeof(*sdev) + shost->transportt->device_size,
 		       GFP_ATOMIC);
 	if (!sdev)
 		goto out;
 
-	memset(sdev, 0, sizeof(*sdev));
 	sdev->vendor = scsi_null_device_strs;
 	sdev->model = scsi_null_device_strs;
 	sdev->rev = scsi_null_device_strs;
@@ -334,12 +333,11 @@
 	struct scsi_target *starget;
 	struct scsi_target *found_target;
 
-	starget = kmalloc(size, GFP_KERNEL);
+	starget = kzalloc(size, GFP_KERNEL);
 	if (!starget) {
 		printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
 		return NULL;
 	}
-	memset(starget, 0, size);
 	dev = &starget->dev;
 	device_initialize(dev);
 	starget->reap_ref = 1;
@@ -689,12 +687,8 @@
 	if (inq_result[7] & 0x10)
 		sdev->sdtr = 1;
 
-	sprintf(sdev->devfs_name, "scsi/host%d/bus%d/target%d/lun%d",
-				sdev->host->host_no, sdev->channel,
-				sdev->id, sdev->lun);
-
 	/*
-	 * End driverfs/devfs code.
+	 * End sysfs code.
 	 */
 
 	if ((sdev->scsi_level >= SCSI_2) && (inq_result[7] & 2) &&
@@ -752,8 +746,20 @@
 
 	transport_configure_device(&sdev->sdev_gendev);
 
-	if (sdev->host->hostt->slave_configure)
-		sdev->host->hostt->slave_configure(sdev);
+	if (sdev->host->hostt->slave_configure) {
+		int ret = sdev->host->hostt->slave_configure(sdev);
+		if (ret) {
+			/*
+			 * if LLDD reports slave not present, don't clutter
+			 * console with alloc failure messages
+			 */
+			if (ret != -ENXIO) {
+				sdev_printk(KERN_ERR, sdev,
+					"failed to configure device\n");
+			}
+			return SCSI_SCAN_NO_RESPONSE;
+		}
+	}
 
 	/*
 	 * Ok, the device is now all set up, we can
@@ -1249,9 +1255,8 @@
 struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
 				      uint id, uint lun, void *hostdata)
 {
-	struct scsi_device *sdev;
+	struct scsi_device *sdev = ERR_PTR(-ENODEV);
 	struct device *parent = &shost->shost_gendev;
-	int res;
 	struct scsi_target *starget;
 
 	starget = scsi_alloc_target(parent, channel, id);
@@ -1260,12 +1265,8 @@
 
 	get_device(&starget->dev);
 	mutex_lock(&shost->scan_mutex);
-	if (scsi_host_scan_allowed(shost)) {
-		res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1,
-					     hostdata);
-		if (res != SCSI_SCAN_LUN_PRESENT)
-			sdev = ERR_PTR(-ENODEV);
-	}
+	if (scsi_host_scan_allowed(shost))
+		scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
 	mutex_unlock(&shost->scan_mutex);
 	scsi_target_reap(starget);
 	put_device(&starget->dev);
diff -urN oldtree/drivers/scsi/scsi_sysctl.c newtree/drivers/scsi/scsi_sysctl.c
--- oldtree/drivers/scsi/scsi_sysctl.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/scsi/scsi_sysctl.c	2006-02-21 15:58:19.434192112 +0000
@@ -9,6 +9,7 @@
 #include <linux/sysctl.h>
 
 #include "scsi_logging.h"
+#include "scsi_priv.h"
 
 
 static ctl_table scsi_table[] = {
diff -urN oldtree/drivers/scsi/scsi_sysfs.c newtree/drivers/scsi/scsi_sysfs.c
--- oldtree/drivers/scsi/scsi_sysfs.c	2006-02-19 11:41:04.079722888 +0000
+++ newtree/drivers/scsi/scsi_sysfs.c	2006-02-21 15:58:19.723148184 +0000
@@ -17,6 +17,7 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsi_transport.h>
+#include <scsi/scsi_driver.h>
 
 #include "scsi_priv.h"
 #include "scsi_logging.h"
@@ -761,7 +762,7 @@
 }
 EXPORT_SYMBOL(scsi_remove_device);
 
-void __scsi_remove_target(struct scsi_target *starget)
+static void __scsi_remove_target(struct scsi_target *starget)
 {
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 	unsigned long flags;
diff -urN oldtree/drivers/scsi/scsi_transport_fc.c newtree/drivers/scsi/scsi_transport_fc.c
--- oldtree/drivers/scsi/scsi_transport_fc.c	2006-02-19 11:41:04.080722736 +0000
+++ newtree/drivers/scsi/scsi_transport_fc.c	2006-02-21 15:58:20.143084344 +0000
@@ -1115,15 +1115,13 @@
 struct scsi_transport_template *
 fc_attach_transport(struct fc_function_template *ft)
 {
-	struct fc_internal *i = kmalloc(sizeof(struct fc_internal),
-					GFP_KERNEL);
 	int count;
+	struct fc_internal *i = kzalloc(sizeof(struct fc_internal),
+					GFP_KERNEL);
 
 	if (unlikely(!i))
 		return NULL;
 
-	memset(i, 0, sizeof(struct fc_internal));
-
 	i->t.target_attrs.ac.attrs = &i->starget_attrs[0];
 	i->t.target_attrs.ac.class = &fc_transport_class.class;
 	i->t.target_attrs.ac.match = fc_target_match;
@@ -1291,7 +1289,7 @@
  * Notes:
  *	This routine assumes no locks are held on entry.
  **/
-struct fc_rport *
+static struct fc_rport *
 fc_rport_create(struct Scsi_Host *shost, int channel,
 	struct fc_rport_identifiers  *ids)
 {
@@ -1305,12 +1303,11 @@
 	size_t size;
 
 	size = (sizeof(struct fc_rport) + fci->f->dd_fcrport_size);
-	rport = kmalloc(size, GFP_KERNEL);
+	rport = kzalloc(size, GFP_KERNEL);
 	if (unlikely(!rport)) {
 		printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
 		return NULL;
 	}
-	memset(rport, 0, size);
 
 	rport->maxframe_size = -1;
 	rport->supported_classes = FC_COS_UNSPECIFIED;
@@ -1498,8 +1495,7 @@
 	}
 
 	/* Search the bindings array */
-	if (likely((ids->roles & FC_RPORT_ROLE_FCP_TARGET) &&
-		(fc_host_tgtid_bind_type(shost) != FC_TGTID_BIND_NONE))) {
+	if (fc_host_tgtid_bind_type(shost) != FC_TGTID_BIND_NONE) {
 
 		/* search for a matching consistent binding */
 
diff -urN oldtree/drivers/scsi/scsi_transport_iscsi.c newtree/drivers/scsi/scsi_transport_iscsi.c
--- oldtree/drivers/scsi/scsi_transport_iscsi.c	2006-02-19 11:41:04.083722280 +0000
+++ newtree/drivers/scsi/scsi_transport_iscsi.c	2006-02-21 15:58:19.035252760 +0000
@@ -1117,10 +1117,9 @@
 	if (priv)
 		return NULL;
 
-	priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return NULL;
-	memset(priv, 0, sizeof(*priv));
 	INIT_LIST_HEAD(&priv->list);
 	priv->iscsi_transport = tt;
 
diff -urN oldtree/drivers/scsi/scsi_transport_sas.c newtree/drivers/scsi/scsi_transport_sas.c
--- oldtree/drivers/scsi/scsi_transport_sas.c	2006-02-19 11:41:04.084722128 +0000
+++ newtree/drivers/scsi/scsi_transport_sas.c	2006-02-21 15:58:19.036252608 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005 Dell Inc.
+ * Copyright (C) 2005-2006 Dell Inc.
  *	Released under GPL v2.
  *
  * Serial Attached SCSI (SAS) transport class.
@@ -38,7 +38,7 @@
 
 #define SAS_HOST_ATTRS		0
 #define SAS_PORT_ATTRS		17
-#define SAS_RPORT_ATTRS		5
+#define SAS_RPORT_ATTRS		7
 
 struct sas_internal {
 	struct scsi_transport_template t;
@@ -391,10 +391,9 @@
 	struct Scsi_Host *shost = dev_to_shost(parent);
 	struct sas_phy *phy;
 
-	phy = kmalloc(sizeof(*phy), GFP_KERNEL);
+	phy = kzalloc(sizeof(*phy), GFP_KERNEL);
 	if (!phy)
 		return NULL;
-	memset(phy, 0, sizeof(*phy));
 
 	get_device(parent);
 
@@ -534,6 +533,53 @@
 static SAS_CLASS_DEVICE_ATTR(rphy, device_type, S_IRUGO,
 		show_sas_rphy_device_type, NULL);
 
+static ssize_t
+show_sas_rphy_enclosure_identifier(struct class_device *cdev, char *buf)
+{
+	struct sas_rphy *rphy = transport_class_to_rphy(cdev);
+	struct sas_phy *phy = dev_to_phy(rphy->dev.parent);
+	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+	struct sas_internal *i = to_sas_internal(shost->transportt);
+	u64 identifier;
+	int error;
+
+	/*
+	 * Only devices behind an expander are supported, because the
+	 * enclosure identifier is a SMP feature.
+	 */
+	if (phy->local_attached)
+		return -EINVAL;
+
+	error = i->f->get_enclosure_identifier(rphy, &identifier);
+	if (error)
+		return error;
+	return sprintf(buf, "0x%llx\n", (unsigned long long)identifier);
+}
+
+static SAS_CLASS_DEVICE_ATTR(rphy, enclosure_identifier, S_IRUGO,
+		show_sas_rphy_enclosure_identifier, NULL);
+
+static ssize_t
+show_sas_rphy_bay_identifier(struct class_device *cdev, char *buf)
+{
+	struct sas_rphy *rphy = transport_class_to_rphy(cdev);
+	struct sas_phy *phy = dev_to_phy(rphy->dev.parent);
+	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+	struct sas_internal *i = to_sas_internal(shost->transportt);
+	int val;
+
+	if (phy->local_attached)
+		return -EINVAL;
+
+	val = i->f->get_bay_identifier(rphy);
+	if (val < 0)
+		return val;
+	return sprintf(buf, "%d\n", val);
+}
+
+static SAS_CLASS_DEVICE_ATTR(rphy, bay_identifier, S_IRUGO,
+		show_sas_rphy_bay_identifier, NULL);
+
 sas_rphy_protocol_attr(identify.initiator_port_protocols,
 		initiator_port_protocols);
 sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols);
@@ -585,12 +631,11 @@
 	struct Scsi_Host *shost = dev_to_shost(&parent->dev);
 	struct sas_rphy *rphy;
 
-	rphy = kmalloc(sizeof(*rphy), GFP_KERNEL);
+	rphy = kzalloc(sizeof(*rphy), GFP_KERNEL);
 	if (!rphy) {
 		put_device(&parent->dev);
 		return NULL;
 	}
-	memset(rphy, 0, sizeof(*rphy));
 
 	device_initialize(&rphy->dev);
 	rphy->dev.parent = get_device(&parent->dev);
@@ -793,10 +838,9 @@
 	struct sas_internal *i;
 	int count;
 
-	i = kmalloc(sizeof(struct sas_internal), GFP_KERNEL);
+	i = kzalloc(sizeof(struct sas_internal), GFP_KERNEL);
 	if (!i)
 		return NULL;
-	memset(i, 0, sizeof(struct sas_internal));
 
 	i->t.user_scan = sas_user_scan;
 
@@ -848,6 +892,8 @@
 	SETUP_RPORT_ATTRIBUTE(rphy_device_type);
 	SETUP_RPORT_ATTRIBUTE(rphy_sas_address);
 	SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier);
+	SETUP_RPORT_ATTRIBUTE(rphy_enclosure_identifier);
+	SETUP_RPORT_ATTRIBUTE(rphy_bay_identifier);
 	i->rphy_attrs[count] = NULL;
 
 	return &i->t;
diff -urN oldtree/drivers/scsi/scsi_transport_spi.c newtree/drivers/scsi/scsi_transport_spi.c
--- oldtree/drivers/scsi/scsi_transport_spi.c	2006-02-19 11:41:04.085721976 +0000
+++ newtree/drivers/scsi/scsi_transport_spi.c	2006-02-21 15:58:19.037252456 +0000
@@ -401,8 +401,7 @@
 }
 
 static ssize_t
-show_spi_transport_period_helper(struct class_device *cdev, char *buf,
-				 int period)
+show_spi_transport_period_helper(char *buf, int period)
 {
 	int len = period_to_str(buf, period);
 	buf[len++] = '\n';
@@ -459,7 +458,7 @@
 	if (i->f->get_period)
 		i->f->get_period(starget);
 
-	return show_spi_transport_period_helper(cdev, buf, tp->period);
+	return show_spi_transport_period_helper(buf, tp->period);
 }
 
 static ssize_t
@@ -494,7 +493,7 @@
 	struct spi_transport_attrs *tp =
 		(struct spi_transport_attrs *)&starget->starget_data;
 
-	return show_spi_transport_period_helper(cdev, buf, tp->min_period);
+	return show_spi_transport_period_helper(buf, tp->min_period);
 }
 
 static ssize_t
@@ -900,13 +899,11 @@
 	if (unlikely(scsi_device_get(sdev)))
 		return;
 
-	buffer = kmalloc(len, GFP_KERNEL);
+	buffer = kzalloc(len, GFP_KERNEL);
 
 	if (unlikely(!buffer))
 		goto out_put;
 
-	memset(buffer, 0, len);
-
 	/* We need to verify that the actual device will quiesce; the
 	 * later target quiesce is just a nice to have */
 	if (unlikely(scsi_device_quiesce(sdev)))
@@ -1054,6 +1051,42 @@
 }
 EXPORT_SYMBOL(spi_display_xfer_agreement);
 
+int spi_populate_width_msg(unsigned char *msg, int width)
+{
+	msg[0] = EXTENDED_MESSAGE;
+	msg[1] = 2;
+	msg[2] = EXTENDED_WDTR;
+	msg[3] = width;
+	return 4;
+}
+EXPORT_SYMBOL_GPL(spi_populate_width_msg);
+
+int spi_populate_sync_msg(unsigned char *msg, int period, int offset)
+{
+	msg[0] = EXTENDED_MESSAGE;
+	msg[1] = 3;
+	msg[2] = EXTENDED_SDTR;
+	msg[3] = period;
+	msg[4] = offset;
+	return 5;
+}
+EXPORT_SYMBOL_GPL(spi_populate_sync_msg);
+
+int spi_populate_ppr_msg(unsigned char *msg, int period, int offset,
+		int width, int options)
+{
+	msg[0] = EXTENDED_MESSAGE;
+	msg[1] = 6;
+	msg[2] = EXTENDED_PPR;
+	msg[3] = period;
+	msg[4] = 0;
+	msg[5] = offset;
+	msg[6] = width;
+	msg[7] = options;
+	return 8;
+}
+EXPORT_SYMBOL_GPL(spi_populate_ppr_msg);
+
 #ifdef CONFIG_SCSI_CONSTANTS
 static const char * const one_byte_msgs[] = {
 /* 0x00 */ "Command Complete", NULL, "Save Pointers",
@@ -1101,7 +1134,7 @@
 				(int) msg[2]);
 		switch (msg[2]) {
 		case EXTENDED_MODIFY_DATA_POINTER:
-			printk("pointer = %d", (int) (msg[3] << 24) |
+			printk("pointer = %d ", (msg[3] << 24) |
 				(msg[4] << 16) | (msg[5] << 8) | msg[6]);
 			break;
 		case EXTENDED_SDTR:
@@ -1127,7 +1160,7 @@
 	/* Normal One byte */
 	} else if (msg[0] < 0x1f) {
 		if (msg[0] < ARRAY_SIZE(one_byte_msgs))
-			printk(one_byte_msgs[msg[0]]);
+			printk("%s ", one_byte_msgs[msg[0]]);
 		else
 			printk("reserved (%02x) ", msg[0]);
 		len = 1;
@@ -1141,7 +1174,7 @@
 				msg[0], msg[1]);
 		len = 2;
 	} else 
-		printk("reserved");
+		printk("reserved ");
 	return len;
 }
 EXPORT_SYMBOL(spi_print_msg);
@@ -1265,15 +1298,13 @@
 struct scsi_transport_template *
 spi_attach_transport(struct spi_function_template *ft)
 {
-	struct spi_internal *i = kmalloc(sizeof(struct spi_internal),
-					 GFP_KERNEL);
 	int count = 0;
+	struct spi_internal *i = kzalloc(sizeof(struct spi_internal),
+					 GFP_KERNEL);
+
 	if (unlikely(!i))
 		return NULL;
 
-	memset(i, 0, sizeof(struct spi_internal));
-
-
 	i->t.target_attrs.ac.class = &spi_transport_class.class;
 	i->t.target_attrs.ac.attrs = &i->attrs[0];
 	i->t.target_attrs.ac.match = spi_target_match;
diff -urN oldtree/drivers/scsi/sd.c newtree/drivers/scsi/sd.c
--- oldtree/drivers/scsi/sd.c	2006-02-19 11:41:04.087721672 +0000
+++ newtree/drivers/scsi/sd.c	2006-02-21 15:58:19.846129488 +0000
@@ -71,6 +71,27 @@
  */
 #define SD_MAJORS	16
 
+MODULE_AUTHOR("Eric Youngdale");
+MODULE_DESCRIPTION("SCSI disk (sd) driver");
+MODULE_LICENSE("GPL");
+
+MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK0_MAJOR);
+MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK1_MAJOR);
+MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK2_MAJOR);
+MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK3_MAJOR);
+MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK4_MAJOR);
+MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK5_MAJOR);
+MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK6_MAJOR);
+MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK7_MAJOR);
+MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK8_MAJOR);
+MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK9_MAJOR);
+MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK10_MAJOR);
+MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK11_MAJOR);
+MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK12_MAJOR);
+MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK13_MAJOR);
+MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK14_MAJOR);
+MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK15_MAJOR);
+
 /*
  * This is limited by the naming scheme enforced in sd_probe,
  * add another character to it if you really need more disks.
@@ -1503,11 +1524,10 @@
 					"sd_attach\n"));
 
 	error = -ENOMEM;
-	sdkp = kmalloc(sizeof(*sdkp), GFP_KERNEL);
+	sdkp = kzalloc(sizeof(*sdkp), GFP_KERNEL);
 	if (!sdkp)
 		goto out;
 
-	memset (sdkp, 0, sizeof(*sdkp));
 	kref_init(&sdkp->kref);
 
 	gd = alloc_disk(16);
@@ -1558,8 +1578,6 @@
 			'a' + m1, 'a' + m2, 'a' + m3);
 	}
 
-	strcpy(gd->devfs_name, sdp->devfs_name);
-
 	gd->private_data = &sdkp->driver;
 	gd->queue = sdkp->device->request_queue;
 
@@ -1696,9 +1714,5 @@
 		unregister_blkdev(sd_major(i), "sd");
 }
 
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Eric Youngdale");
-MODULE_DESCRIPTION("SCSI disk (sd) driver");
-
 module_init(init_sd);
 module_exit(exit_sd);
diff -urN oldtree/drivers/scsi/sg.c newtree/drivers/scsi/sg.c
--- oldtree/drivers/scsi/sg.c	2006-02-19 11:41:04.091721064 +0000
+++ newtree/drivers/scsi/sg.c	2006-02-21 15:58:22.352748424 +0000
@@ -44,7 +44,6 @@
 #include <linux/poll.h>
 #include <linux/smp_lock.h>
 #include <linux/moduleparam.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/cdev.h>
 #include <linux/seq_file.h>
 #include <linux/blkdev.h>
@@ -1140,32 +1139,6 @@
 	return (retval < 0) ? retval : 0;
 }
 
-/* When startFinish==1 increments page counts for pages other than the 
-   first of scatter gather elements obtained from alloc_pages().
-   When startFinish==0 decrements ... */
-static void
-sg_rb_correct4mmap(Sg_scatter_hold * rsv_schp, int startFinish)
-{
-	struct scatterlist *sg = rsv_schp->buffer;
-	struct page *page;
-	int k, m;
-
-	SCSI_LOG_TIMEOUT(3, printk("sg_rb_correct4mmap: startFinish=%d, scatg=%d\n", 
-				   startFinish, rsv_schp->k_use_sg));
-	/* N.B. correction _not_ applied to base page of each allocation */
-	for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sg) {
-		for (m = PAGE_SIZE; m < sg->length; m += PAGE_SIZE) {
-			page = sg->page;
-			if (startFinish)
-				get_page(page);
-			else {
-				if (page_count(page) > 0)
-					__put_page(page);
-			}
-		}
-	}
-}
-
 static struct page *
 sg_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int *type)
 {
@@ -1237,10 +1210,7 @@
 		sa += len;
 	}
 
-	if (0 == sfp->mmap_called) {
-		sg_rb_correct4mmap(rsv_schp, 1);	/* do only once per fd lifetime */
-		sfp->mmap_called = 1;
-	}
+	sfp->mmap_called = 1;
 	vma->vm_flags |= VM_RESERVED;
 	vma->vm_private_data = sfp;
 	vma->vm_ops = &sg_mmap_vm_ops;
@@ -1361,7 +1331,7 @@
 	void *old_sg_dev_arr = NULL;
 	int k, error;
 
-	sdp = kmalloc(sizeof(Sg_device), GFP_KERNEL);
+	sdp = kzalloc(sizeof(Sg_device), GFP_KERNEL);
 	if (!sdp) {
 		printk(KERN_WARNING "kmalloc Sg_device failure\n");
 		return -ENOMEM;
@@ -1373,12 +1343,11 @@
 		int tmp_dev_max = sg_nr_dev + SG_DEV_ARR_LUMP;
 		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
 
-		tmp_da = kmalloc(tmp_dev_max * sizeof(Sg_device *), GFP_KERNEL);
+		tmp_da = kzalloc(tmp_dev_max * sizeof(Sg_device *), GFP_KERNEL);
 		if (unlikely(!tmp_da))
 			goto expand_failed;
 
 		write_lock_irqsave(&sg_dev_arr_lock, iflags);
-		memset(tmp_da, 0, tmp_dev_max * sizeof(Sg_device *));
 		memcpy(tmp_da, sg_dev_arr, sg_dev_max * sizeof(Sg_device *));
 		old_sg_dev_arr = sg_dev_arr;
 		sg_dev_arr = tmp_da;
@@ -1391,7 +1360,6 @@
 	if (unlikely(k >= SG_MAX_DEVS))
 		goto overflow;
 
-	memset(sdp, 0, sizeof(*sdp));
 	SCSI_LOG_TIMEOUT(3, printk("sg_alloc: dev=%d \n", k));
 	sprintf(disk->disk_name, "sg%d", k);
 	disk->first_minor = k;
@@ -1458,14 +1426,10 @@
 	k = error;
 	sdp = sg_dev_arr[k];
 
-	devfs_mk_cdev(MKDEV(SCSI_GENERIC_MAJOR, k),
-			S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
-			"%s/generic", scsidp->devfs_name);
 	error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, k), 1);
-	if (error) {
-		devfs_remove("%s/generic", scsidp->devfs_name);
+	if (error)
 		goto out;
-	}
+
 	sdp->cdev = cdev;
 	if (sg_sysfs_valid) {
 		struct class_device * sg_class_member;
@@ -1555,7 +1519,6 @@
 		class_device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, k));
 		cdev_del(sdp->cdev);
 		sdp->cdev = NULL;
-		devfs_remove("%s/generic", scsidp->devfs_name);
 		put_disk(sdp->disk);
 		sdp->disk = NULL;
 		if (NULL == sdp->headfp)
@@ -1577,6 +1540,7 @@
 MODULE_DESCRIPTION("SCSI generic (sg) driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(SG_VERSION_STR);
+MODULE_ALIAS_CHARDEV_MAJOR(SCSI_GENERIC_MAJOR);
 
 MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
 MODULE_PARM_DESC(allow_dio, "allow direct I/O (default: 0 (disallow))");
@@ -2162,7 +2126,7 @@
 
 	srp->res_used = 1;
 	SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size));
-	rem = size = (size + 1) & (~1);	/* round to even for aha1542 */
+	rem = size;
 
 	for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sg) {
 		num = sg->length;
@@ -2395,8 +2359,6 @@
 		SCSI_LOG_TIMEOUT(6, 
 			printk("__sg_remove_sfp:    bufflen=%d, k_use_sg=%d\n",
 			(int) sfp->reserve.bufflen, (int) sfp->reserve.k_use_sg));
-		if (sfp->mmap_called)
-			sg_rb_correct4mmap(&sfp->reserve, 0);	/* undo correction */
 		sg_remove_scat(&sfp->reserve);
 	}
 	sfp->parentdp = NULL;
@@ -2478,9 +2440,9 @@
 		return resp;
 
 	if (lowDma)
-		page_mask = GFP_ATOMIC | GFP_DMA | __GFP_NOWARN;
+		page_mask = GFP_ATOMIC | GFP_DMA | __GFP_COMP | __GFP_NOWARN;
 	else
-		page_mask = GFP_ATOMIC | __GFP_NOWARN;
+		page_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN;
 
 	for (order = 0, a_size = PAGE_SIZE; a_size < rqSz;
 	     order++, a_size <<= 1) ;
@@ -2974,4 +2936,3 @@
 
 module_init(init_sg);
 module_exit(exit_sg);
-MODULE_ALIAS_CHARDEV_MAJOR(SCSI_GENERIC_MAJOR);
diff -urN oldtree/drivers/scsi/sr.c newtree/drivers/scsi/sr.c
--- oldtree/drivers/scsi/sr.c	2006-02-19 11:41:04.092720912 +0000
+++ newtree/drivers/scsi/sr.c	2006-02-21 15:58:19.848129184 +0000
@@ -60,6 +60,10 @@
 #include "sr.h"
 
 
+MODULE_DESCRIPTION("SCSI cdrom (sr) driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_CDROM_MAJOR);
+
 #define SR_DISKS	256
 
 #define MAX_RETRIES	3
@@ -171,7 +175,7 @@
  * an inode for that to work, and we do not always have one.
  */
 
-int sr_media_change(struct cdrom_device_info *cdi, int slot)
+static int sr_media_change(struct cdrom_device_info *cdi, int slot)
 {
 	struct scsi_cd *cd = cdi->handle;
 	int retval;
@@ -525,10 +529,9 @@
 		goto fail;
 
 	error = -ENOMEM;
-	cd = kmalloc(sizeof(*cd), GFP_KERNEL);
+	cd = kzalloc(sizeof(*cd), GFP_KERNEL);
 	if (!cd)
 		goto fail;
-	memset(cd, 0, sizeof(*cd));
 
 	kref_init(&cd->kref);
 
@@ -574,8 +577,6 @@
 	get_capabilities(cd);
 	sr_vendor_init(cd);
 
-	snprintf(disk->devfs_name, sizeof(disk->devfs_name),
-			"%s/cd", sdev->devfs_name);
 	disk->driverfs_dev = &sdev->sdev_gendev;
 	set_capacity(disk, cd->capacity);
 	disk->private_data = &cd->driver;
diff -urN oldtree/drivers/scsi/sr_ioctl.c newtree/drivers/scsi/sr_ioctl.c
--- oldtree/drivers/scsi/sr_ioctl.c	2006-02-19 11:41:04.136714224 +0000
+++ newtree/drivers/scsi/sr_ioctl.c	2006-02-21 15:58:19.075246680 +0000
@@ -44,7 +44,7 @@
 	int result;
 	unsigned char *buffer;
 
-	buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd));
+	buffer = kzalloc(32, GFP_KERNEL | SR_GFP_DMA(cd));
 	if (!buffer)
 		return -ENOMEM;
 
@@ -74,7 +74,7 @@
 	int result;
 	unsigned char *buffer;
 
-	buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd));
+	buffer = kzalloc(32, GFP_KERNEL | SR_GFP_DMA(cd));
 	if (!buffer)
 		return -ENOMEM;
 
diff -urN oldtree/drivers/scsi/st.c newtree/drivers/scsi/st.c
--- oldtree/drivers/scsi/st.c	2006-02-19 11:41:04.140713616 +0000
+++ newtree/drivers/scsi/st.c	2006-02-21 15:58:19.849129032 +0000
@@ -35,7 +35,6 @@
 #include <linux/spinlock.h>
 #include <linux/blkdev.h>
 #include <linux/moduleparam.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/cdev.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
@@ -87,8 +86,9 @@
 static struct class *st_sysfs_class;
 
 MODULE_AUTHOR("Kai Makisara");
-MODULE_DESCRIPTION("SCSI Tape Driver");
+MODULE_DESCRIPTION("SCSI tape (st) driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(SCSI_TAPE_MAJOR);
 
 /* Set 'perm' (4th argument) to 0 to disable module_param's definition
  * of sysfs parameters (which module_param doesn't yet support).
@@ -3590,12 +3590,11 @@
 
 	i = sizeof(struct st_buffer) + (max_sg - 1) * sizeof(struct scatterlist) +
 		max_sg * sizeof(struct st_buf_fragment);
-	tb = kmalloc(i, priority);
+	tb = kzalloc(i, priority);
 	if (!tb) {
 		printk(KERN_NOTICE "st: Can't allocate new tape buffer.\n");
 		return NULL;
 	}
-	memset(tb, 0, i);
 	tb->frp_segs = tb->orig_frp_segs = 0;
 	tb->use_sg = max_sg;
 	tb->frp = (struct st_buf_fragment *)(&(tb->sg[0]) + max_sg);
@@ -3924,14 +3923,13 @@
 			goto out_put_disk;
 		}
 
-		tmp_da = kmalloc(tmp_dev_max * sizeof(struct scsi_tape *), GFP_ATOMIC);
+		tmp_da = kzalloc(tmp_dev_max * sizeof(struct scsi_tape *), GFP_ATOMIC);
 		if (tmp_da == NULL) {
 			write_unlock(&st_dev_arr_lock);
 			printk(KERN_ERR "st: Can't extend device array.\n");
 			goto out_put_disk;
 		}
 
-		memset(tmp_da, 0, tmp_dev_max * sizeof(struct scsi_tape *));
 		if (scsi_tapes != NULL) {
 			memcpy(tmp_da, scsi_tapes,
 			       st_dev_max * sizeof(struct scsi_tape *));
@@ -3948,13 +3946,12 @@
 	if (i >= st_dev_max)
 		panic("scsi_devices corrupt (st)");
 
-	tpnt = kmalloc(sizeof(struct scsi_tape), GFP_ATOMIC);
+	tpnt = kzalloc(sizeof(struct scsi_tape), GFP_ATOMIC);
 	if (tpnt == NULL) {
 		write_unlock(&st_dev_arr_lock);
 		printk(KERN_ERR "st: Can't allocate device descriptor.\n");
 		goto out_put_disk;
 	}
-	memset(tpnt, 0, sizeof(struct scsi_tape));
 	kref_init(&tpnt->kref);
 	tpnt->disk = disk;
 	sprintf(disk->disk_name, "st%d", i);
@@ -4056,21 +4053,6 @@
 		do_create_class_files(tpnt, dev_num, mode);
 	}
 
-	for (mode = 0; mode < ST_NBR_MODES; ++mode) {
-		/* Make sure that the minor numbers corresponding to the four
-		   first modes always get the same names */
-		i = mode << (4 - ST_NBR_MODE_BITS);
-		/*  Rewind entry  */
-		devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, 0)),
-			      S_IFCHR | S_IRUGO | S_IWUGO,
-			      "%s/mt%s", SDp->devfs_name, st_formats[i]);
-		/*  No-rewind entry  */
-		devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, 1)),
-			      S_IFCHR | S_IRUGO | S_IWUGO,
-			      "%s/mt%sn", SDp->devfs_name, st_formats[i]);
-	}
-	disk->number = devfs_register_tape(SDp->devfs_name);
-
 	sdev_printk(KERN_WARNING, SDp,
 		    "Attached scsi tape %s", tape_name(tpnt));
 	printk(KERN_WARNING "%s: try direct i/o: %s (alignment %d B)\n",
@@ -4124,13 +4106,9 @@
 			scsi_tapes[i] = NULL;
 			st_nr_dev--;
 			write_unlock(&st_dev_arr_lock);
-			devfs_unregister_tape(tpnt->disk->number);
 			sysfs_remove_link(&tpnt->device->sdev_gendev.kobj,
 					  "tape");
 			for (mode = 0; mode < ST_NBR_MODES; ++mode) {
-				j = mode << (4 - ST_NBR_MODE_BITS);
-				devfs_remove("%s/mt%s", SDp->devfs_name, st_formats[j]);
-				devfs_remove("%s/mt%sn", SDp->devfs_name, st_formats[j]);
 				for (j=0; j < 2; j++) {
 					class_device_destroy(st_sysfs_class,
 							     MKDEV(SCSI_TAPE_MAJOR,
diff -urN oldtree/drivers/scsi/sym53c8xx_2/sym_glue.c newtree/drivers/scsi/sym53c8xx_2/sym_glue.c
--- oldtree/drivers/scsi/sym53c8xx_2/sym_glue.c	2006-02-19 11:41:04.147712552 +0000
+++ newtree/drivers/scsi/sym53c8xx_2/sym_glue.c	2006-02-21 15:58:17.655462520 +0000
@@ -134,45 +134,6 @@
 	}
 }
 
-/*
- * We used to try to deal with 64-bit BARs here, but don't any more.
- * There are many parts of this driver which would need to be modified
- * to handle a 64-bit base address, including scripts.  I'm uncomfortable
- * with making those changes when I have no way of testing it, so I'm
- * just going to disable it.
- *
- * Note that some machines (eg HP rx8620 and Superdome) have bus addresses
- * below 4GB and physical addresses above 4GB.  These will continue to work.
- */
-static int __devinit
-pci_get_base_address(struct pci_dev *pdev, int index, unsigned long *basep)
-{
-	u32 tmp;
-	unsigned long base;
-#define PCI_BAR_OFFSET(index) (PCI_BASE_ADDRESS_0 + (index<<2))
-
-	pci_read_config_dword(pdev, PCI_BAR_OFFSET(index++), &tmp);
-	base = tmp;
-	if ((tmp & 0x7) == PCI_BASE_ADDRESS_MEM_TYPE_64) {
-		pci_read_config_dword(pdev, PCI_BAR_OFFSET(index++), &tmp);
-		if (tmp > 0) {
-			dev_err(&pdev->dev,
-				"BAR %d is 64-bit, disabling\n", index - 1);
-			base = 0;
-		}
-	}
-
-	if ((base & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
-		base &= PCI_BASE_ADDRESS_IO_MASK;
-	} else {
-		base &= PCI_BASE_ADDRESS_MEM_MASK;
-	}
-
-	*basep = base;
-	return index;
-#undef PCI_BAR_OFFSET
-}
-
 static struct scsi_transport_template *sym2_transport_template = NULL;
 
 /*
@@ -514,8 +475,6 @@
  */
 int sym_setup_data_and_start(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp)
 {
-	struct sym_tcb *tp = &np->target[cp->target];
-	struct sym_lcb *lp = sym_lp(tp, cp->lun);
 	u32 lastp, goalp;
 	int dir;
 
@@ -596,7 +555,7 @@
 	/*
 	 *	activate this job.
 	 */
-	sym_start_next_ccbs(np, lp, 2);
+	sym_put_start_queue(np, cp);
 	return 0;
 
 out_abort:
@@ -751,7 +710,6 @@
  *  What we will do regarding the involved SCSI command.
  */
 #define SYM_EH_DO_IGNORE	0
-#define SYM_EH_DO_COMPLETE	1
 #define SYM_EH_DO_WAIT		2
 
 /*
@@ -803,25 +761,18 @@
 
 	dev_warn(&cmd->device->sdev_gendev, "%s operation started.\n", opname);
 
+	spin_lock_irq(cmd->device->host->host_lock);
 	/* This one is queued in some place -> to wait for completion */
 	FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
 		struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
 		if (cp->cmd == cmd) {
 			to_do = SYM_EH_DO_WAIT;
-			goto prepare;
+			break;
 		}
 	}
 
-prepare:
-	/* Prepare stuff to either ignore, complete or wait for completion */
-	switch(to_do) {
-	default:
-	case SYM_EH_DO_IGNORE:
-		break;
-	case SYM_EH_DO_WAIT:
+	if (to_do == SYM_EH_DO_WAIT) {
 		init_completion(&ep->done);
-		/* fall through */
-	case SYM_EH_DO_COMPLETE:
 		ep->old_done = cmd->scsi_done;
 		cmd->scsi_done = sym_eh_done;
 		SYM_UCMD_PTR(cmd)->eh_wait = ep;
@@ -857,9 +808,6 @@
 	}
 
 	ep->to_do = to_do;
-	/* Complete the command with locks held as required by the driver */
-	if (to_do == SYM_EH_DO_COMPLETE)
-		sym_xpt_done2(np, cmd, DID_ABORT);
 
 	/* Wait for completion with locks released, as required by kernel */
 	if (to_do == SYM_EH_DO_WAIT) {
@@ -875,6 +823,7 @@
 		if (ep->timed_out)
 			sts = -2;
 	}
+	spin_unlock_irq(cmd->device->host->host_lock);
 	dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname,
 			sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed");
 	return sts ? SCSI_FAILED : SCSI_SUCCESS;
@@ -886,46 +835,22 @@
  */
 static int sym53c8xx_eh_abort_handler(struct scsi_cmnd *cmd)
 {
-	int rc;
-
-	spin_lock_irq(cmd->device->host->host_lock);
-	rc = sym_eh_handler(SYM_EH_ABORT, "ABORT", cmd);
-	spin_unlock_irq(cmd->device->host->host_lock);
-
-	return rc;
+	return sym_eh_handler(SYM_EH_ABORT, "ABORT", cmd);
 }
 
 static int sym53c8xx_eh_device_reset_handler(struct scsi_cmnd *cmd)
 {
-	int rc;
-
-	spin_lock_irq(cmd->device->host->host_lock);
-	rc = sym_eh_handler(SYM_EH_DEVICE_RESET, "DEVICE RESET", cmd);
-	spin_unlock_irq(cmd->device->host->host_lock);
-
-	return rc;
+	return sym_eh_handler(SYM_EH_DEVICE_RESET, "DEVICE RESET", cmd);
 }
 
 static int sym53c8xx_eh_bus_reset_handler(struct scsi_cmnd *cmd)
 {
-	int rc;
-
-	spin_lock_irq(cmd->device->host->host_lock);
-	rc = sym_eh_handler(SYM_EH_BUS_RESET, "BUS RESET", cmd);
-	spin_unlock_irq(cmd->device->host->host_lock);
-
-	return rc;
+	return sym_eh_handler(SYM_EH_BUS_RESET, "BUS RESET", cmd);
 }
 
 static int sym53c8xx_eh_host_reset_handler(struct scsi_cmnd *cmd)
 {
-	int rc;
-
-	spin_lock_irq(cmd->device->host->host_lock);
-	rc = sym_eh_handler(SYM_EH_HOST_RESET, "HOST RESET", cmd);
-	spin_unlock_irq(cmd->device->host->host_lock);
-
-	return rc;
+	return sym_eh_handler(SYM_EH_HOST_RESET, "HOST RESET", cmd);
 }
 
 /*
@@ -944,15 +869,12 @@
 	if (reqtags > lp->s.scdev_depth)
 		reqtags = lp->s.scdev_depth;
 
-	lp->started_limit = reqtags ? reqtags : 2;
-	lp->started_max   = 1;
 	lp->s.reqtags     = reqtags;
 
 	if (reqtags != oldtags) {
 		dev_info(&tp->starget->dev,
 		         "tagged command queuing %s, command queue depth %d.\n",
-		          lp->s.reqtags ? "enabled" : "disabled",
- 		          lp->started_limit);
+		          lp->s.reqtags ? "enabled" : "disabled", reqtags);
 	}
 }
 
@@ -1866,15 +1788,25 @@
 static void __devinit
 sym_init_device(struct pci_dev *pdev, struct sym_device *device)
 {
-	int i;
+	int i = 2;
+	struct pci_bus_region bus_addr;
 
 	device->host_id = SYM_SETUP_HOST_ID;
 	device->pdev = pdev;
 
-	i = pci_get_base_address(pdev, 1, &device->mmio_base);
-	pci_get_base_address(pdev, i, &device->ram_base);
+	pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[1]);
+	device->mmio_base = bus_addr.start;
+
+	/*
+	 * If the BAR is 64-bit, resource 2 will be occupied by the
+	 * upper 32 bits
+	 */
+	if (!pdev->resource[i].flags)
+		i++;
+	pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[i]);
+	device->ram_base = bus_addr.start;
 
-#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED
+#ifdef CONFIG_SCSI_SYM53C8XX_MMIO
 	if (device->mmio_base)
 		device->s.ioaddr = pci_iomap(pdev, 1,
 						pci_resource_len(pdev, 1));
diff -urN oldtree/drivers/scsi/sym53c8xx_2/sym_glue.h newtree/drivers/scsi/sym53c8xx_2/sym_glue.h
--- oldtree/drivers/scsi/sym53c8xx_2/sym_glue.h	2006-02-19 11:41:04.148712400 +0000
+++ newtree/drivers/scsi/sym53c8xx_2/sym_glue.h	2006-02-21 15:58:17.664461152 +0000
@@ -68,7 +68,7 @@
  */
 #define	SYM_CONF_TIMER_INTERVAL		((HZ+1)/2)
 
-#define SYM_OPT_HANDLE_DEVICE_QUEUEING
+#undef SYM_OPT_HANDLE_DEVICE_QUEUEING
 #define SYM_OPT_LIMIT_COMMAND_REORDERING
 
 /*
diff -urN oldtree/drivers/scsi/sym53c8xx_2/sym_hipd.c newtree/drivers/scsi/sym53c8xx_2/sym_hipd.c
--- oldtree/drivers/scsi/sym53c8xx_2/sym_hipd.c	2006-02-19 11:41:04.151711944 +0000
+++ newtree/drivers/scsi/sym53c8xx_2/sym_hipd.c	2006-02-21 15:58:19.048250784 +0000
@@ -40,7 +40,6 @@
 
 #include <linux/slab.h>
 #include <asm/param.h>		/* for timeouts in units of HZ */
-#include <scsi/scsi_dbg.h>
 
 #include "sym_glue.h"
 #include "sym_nvram.h"
@@ -473,7 +472,7 @@
  *  calculations more simple.
  */
 #define _5M 5000000
-static u32 div_10M[] = {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M};
+static const u32 div_10M[] = {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M};
 
 /*
  *  Get clock factor and sync divisor for a given 
@@ -972,8 +971,8 @@
  *
  *  Has to be called with interrupts disabled.
  */
-#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED
-static int sym_regtest (struct sym_hcb *np)
+#ifdef CONFIG_SCSI_SYM53C8XX_MMIO
+static int sym_regtest(struct sym_hcb *np)
 {
 	register volatile u32 data;
 	/*
@@ -991,20 +990,25 @@
 #endif
 		printf ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n",
 			(unsigned) data);
-		return (0x10);
+		return 0x10;
 	}
-	return (0);
+	return 0;
+}
+#else
+static inline int sym_regtest(struct sym_hcb *np)
+{
+	return 0;
 }
 #endif
 
-static int sym_snooptest (struct sym_hcb *np)
+static int sym_snooptest(struct sym_hcb *np)
 {
-	u32	sym_rd, sym_wr, sym_bk, host_rd, host_wr, pc, dstat;
-	int	i, err=0;
-#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED
-	err |= sym_regtest (np);
-	if (err) return (err);
-#endif
+	u32 sym_rd, sym_wr, sym_bk, host_rd, host_wr, pc, dstat;
+	int i, err;
+
+	err = sym_regtest(np);
+	if (err)
+		return err;
 restart_test:
 	/*
 	 *  Enable Master Parity Checking as we intend 
@@ -1093,7 +1097,7 @@
 		err |= 4;
 	}
 
-	return (err);
+	return err;
 }
 
 /*
@@ -1430,29 +1434,18 @@
 
 	switch (nego) {
 	case NS_SYNC:
-		msgptr[msglen++] = M_EXTENDED;
-		msgptr[msglen++] = 3;
-		msgptr[msglen++] = M_X_SYNC_REQ;
-		msgptr[msglen++] = goal->period;
-		msgptr[msglen++] = goal->offset;
+		msglen += spi_populate_sync_msg(msgptr + msglen, goal->period,
+				goal->offset);
 		break;
 	case NS_WIDE:
-		msgptr[msglen++] = M_EXTENDED;
-		msgptr[msglen++] = 2;
-		msgptr[msglen++] = M_X_WIDE_REQ;
-		msgptr[msglen++] = goal->width;
+		msglen += spi_populate_width_msg(msgptr + msglen, goal->width);
 		break;
 	case NS_PPR:
-		msgptr[msglen++] = M_EXTENDED;
-		msgptr[msglen++] = 6;
-		msgptr[msglen++] = M_X_PPR_REQ;
-		msgptr[msglen++] = goal->period;
-		msgptr[msglen++] = 0;
-		msgptr[msglen++] = goal->offset;
-		msgptr[msglen++] = goal->width;
-		msgptr[msglen++] = (goal->iu ? PPR_OPT_IU : 0) |
+		msglen += spi_populate_ppr_msg(msgptr + msglen, goal->period,
+				goal->offset, goal->width,
+				(goal->iu ? PPR_OPT_IU : 0) |
 					(goal->dt ? PPR_OPT_DT : 0) |
-					(goal->qas ? PPR_OPT_QAS : 0);
+					(goal->qas ? PPR_OPT_QAS : 0));
 		break;
 	}
 
@@ -1474,7 +1467,7 @@
 /*
  *  Insert a job into the start queue.
  */
-static void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp)
+void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp)
 {
 	u_short	qidx;
 
@@ -3948,11 +3941,7 @@
 	/*
 	 *  It was a request. Prepare an answer message.
 	 */
-	np->msgout[0] = M_EXTENDED;
-	np->msgout[1] = 3;
-	np->msgout[2] = M_X_SYNC_REQ;
-	np->msgout[3] = per;
-	np->msgout[4] = ofs;
+	spi_populate_sync_msg(np->msgout, per, ofs);
 
 	if (DEBUG_FLAGS & DEBUG_NEGO) {
 		sym_print_nego_msg(np, target, "sync msgout", np->msgout);
@@ -4078,14 +4067,7 @@
 	/*
 	 *  It was a request. Prepare an answer message.
 	 */
-	np->msgout[0] = M_EXTENDED;
-	np->msgout[1] = 6;
-	np->msgout[2] = M_X_PPR_REQ;
-	np->msgout[3] = per;
-	np->msgout[4] = 0;
-	np->msgout[5] = ofs;
-	np->msgout[6] = wide;
-	np->msgout[7] = opts;
+	spi_populate_ppr_msg(np->msgout, per, ofs, wide, opts);
 
 	if (DEBUG_FLAGS & DEBUG_NEGO) {
 		sym_print_nego_msg(np, target, "ppr msgout", np->msgout);
@@ -4197,10 +4179,7 @@
 	/*
 	 *  It was a request. Prepare an answer message.
 	 */
-	np->msgout[0] = M_EXTENDED;
-	np->msgout[1] = 2;
-	np->msgout[2] = M_X_WIDE_REQ;
-	np->msgout[3] = wide;
+	spi_populate_width_msg(np->msgout, wide);
 
 	np->msgin [0] = M_NOOP;
 
@@ -4245,11 +4224,8 @@
 		 * a single SCSI command (Suggested by Justin Gibbs).
 		 */
 		if (tp->tgoal.offset) {
-			np->msgout[0] = M_EXTENDED;
-			np->msgout[1] = 3;
-			np->msgout[2] = M_X_SYNC_REQ;
-			np->msgout[3] = tp->tgoal.period;
-			np->msgout[4] = tp->tgoal.offset;
+			spi_populate_sync_msg(np->msgout, tp->tgoal.period,
+					tp->tgoal.offset);
 
 			if (DEBUG_FLAGS & DEBUG_NEGO) {
 				sym_print_nego_msg(np, cp->target,
@@ -4624,7 +4600,8 @@
 			 *  Debugging purpose.
 			 */
 #ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING
-			assert(lp->busy_itl == 0);
+			if (lp->busy_itl != 0)
+				goto out_free;
 #endif
 			/*
 			 *  Allocate resources for tags if not yet.
@@ -4669,7 +4646,8 @@
 			 *  Debugging purpose.
 			 */
 #ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING
-			assert(lp->busy_itl == 0 && lp->busy_itlq == 0);
+			if (lp->busy_itl != 0 || lp->busy_itlq != 0)
+				goto out_free;
 #endif
 			/*
 			 *  Count this nexus for this LUN.
diff -urN oldtree/drivers/scsi/sym53c8xx_2/sym_hipd.h newtree/drivers/scsi/sym53c8xx_2/sym_hipd.h
--- oldtree/drivers/scsi/sym53c8xx_2/sym_hipd.h	2006-02-19 11:41:04.152711792 +0000
+++ newtree/drivers/scsi/sym53c8xx_2/sym_hipd.h	2006-02-21 15:58:17.678459024 +0000
@@ -1049,6 +1049,8 @@
 struct sym_chip *sym_lookup_chip_table(u_short device_id, u_char revision);
 #ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
 void sym_start_next_ccbs(struct sym_hcb *np, struct sym_lcb *lp, int maxn);
+#else
+void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp);
 #endif
 void sym_start_up(struct sym_hcb *np, int reason);
 void sym_interrupt(struct sym_hcb *np);
diff -urN oldtree/drivers/serial/8250.h newtree/drivers/serial/8250.h
--- oldtree/drivers/serial/8250.h	2006-02-19 11:41:04.164709968 +0000
+++ newtree/drivers/serial/8250.h	2006-02-21 15:58:36.471602032 +0000
@@ -23,7 +23,7 @@
 	unsigned int baud_base;
 	unsigned int port;
 	unsigned int irq;
-	unsigned int flags;
+	upf_t flags;
 	unsigned char hub6;
 	unsigned char io_type;
 	unsigned char *iomem_base;
diff -urN oldtree/drivers/serial/Kconfig newtree/drivers/serial/Kconfig
--- oldtree/drivers/serial/Kconfig	2006-02-19 11:41:04.167709512 +0000
+++ newtree/drivers/serial/Kconfig	2006-02-21 15:58:20.476033728 +0000
@@ -582,6 +582,13 @@
 	  on your Sparc system as the console, you can do so by answering
 	  Y to this option.
 
+config SERIAL_SUNHV
+	bool "Sun4v Hypervisor Console support"
+	depends on SPARC64
+	help
+	  This driver supports the console device found on SUN4V Sparc
+	  systems.  Say Y if you want to be able to use this device.
+
 config SERIAL_IP22_ZILOG
 	tristate "IP22 Zilog8530 serial support"
 	depends on SGI_IP22
diff -urN oldtree/drivers/serial/Makefile newtree/drivers/serial/Makefile
--- oldtree/drivers/serial/Makefile	2006-02-19 11:41:04.168709360 +0000
+++ newtree/drivers/serial/Makefile	2006-02-21 15:58:31.856303664 +0000
@@ -8,7 +8,7 @@
 serial-8250-$(CONFIG_SERIAL_8250_ACPI) += 8250_acpi.o
 serial-8250-$(CONFIG_PNP) += 8250_pnp.o
 serial-8250-$(CONFIG_GSC) += 8250_gsc.o
-serial-8250-$(CONFIG_PCI) += 8250_pci.o
+serial-8250-$(CONFIG_SERIAL_PCI) += 8250_pci.o
 serial-8250-$(CONFIG_HP300) += 8250_hp300.o
 
 obj-$(CONFIG_SERIAL_CORE) += serial_core.o
@@ -30,6 +30,7 @@
 obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
 obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
 obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
+obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
 obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
 obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
 obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
diff -urN oldtree/drivers/serial/jsm/jsm_tty.c newtree/drivers/serial/jsm/jsm_tty.c
--- oldtree/drivers/serial/jsm/jsm_tty.c	2006-02-19 11:41:04.187706472 +0000
+++ newtree/drivers/serial/jsm/jsm_tty.c	2006-02-21 15:58:37.524441976 +0000
@@ -142,12 +142,14 @@
 {
 	unsigned long lock_flags;
 	struct jsm_channel *channel = (struct jsm_channel *)port;
+	struct termios *termios;
 
 	spin_lock_irqsave(&port->lock, lock_flags);
-	if (ch == port->info->tty->termios->c_cc[VSTART])
+	termios = port->info->tty->termios;
+	if (ch == termios->c_cc[VSTART])
 		channel->ch_bd->bd_ops->send_start_character(channel);
 
-	if (ch == port->info->tty->termios->c_cc[VSTOP])
+	if (ch == termios->c_cc[VSTOP])
 		channel->ch_bd->bd_ops->send_stop_character(channel);
 	spin_unlock_irqrestore(&port->lock, lock_flags);
 }
@@ -178,6 +180,7 @@
 	struct jsm_board *brd;
 	int rc = 0;
 	struct jsm_channel *channel = (struct jsm_channel *)port;
+	struct termios *termios;
 
 	/* Get board pointer from our array of majors we have allocated */
 	brd = channel->ch_bd;
@@ -239,12 +242,13 @@
 	channel->ch_cached_lsr = 0;
 	channel->ch_stops_sent = 0;
 
-	channel->ch_c_cflag	= port->info->tty->termios->c_cflag;
-	channel->ch_c_iflag	= port->info->tty->termios->c_iflag;
-	channel->ch_c_oflag	= port->info->tty->termios->c_oflag;
-	channel->ch_c_lflag	= port->info->tty->termios->c_lflag;
-	channel->ch_startc = port->info->tty->termios->c_cc[VSTART];
-	channel->ch_stopc = port->info->tty->termios->c_cc[VSTOP];
+	termios = port->info->tty->termios;
+	channel->ch_c_cflag	= termios->c_cflag;
+	channel->ch_c_iflag	= termios->c_iflag;
+	channel->ch_c_oflag	= termios->c_oflag;
+	channel->ch_c_lflag	= termios->c_lflag;
+	channel->ch_startc	= termios->c_cc[VSTART];
+	channel->ch_stopc	= termios->c_cc[VSTOP];
 
 	/* Tell UART to init itself */
 	brd->bd_ops->uart_init(channel);
@@ -784,6 +788,7 @@
 
 void jsm_check_queue_flow_control(struct jsm_channel *ch)
 {
+	struct board_ops *bd_ops = ch->ch_bd->bd_ops;
 	int qleft = 0;
 
 	/* Store how much space we have left in the queue */
@@ -809,7 +814,7 @@
 		/* HWFLOW */
 		if (ch->ch_c_cflag & CRTSCTS) {
 			if(!(ch->ch_flags & CH_RECEIVER_OFF)) {
-				ch->ch_bd->bd_ops->disable_receiver(ch);
+				bd_ops->disable_receiver(ch);
 				ch->ch_flags |= (CH_RECEIVER_OFF);
 				jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
 					"Internal queue hit hilevel mark (%d)! Turning off interrupts.\n",
@@ -819,7 +824,7 @@
 		/* SWFLOW */
 		else if (ch->ch_c_iflag & IXOFF) {
 			if (ch->ch_stops_sent <= MAX_STOPS_SENT) {
-				ch->ch_bd->bd_ops->send_stop_character(ch);
+				bd_ops->send_stop_character(ch);
 				ch->ch_stops_sent++;
 				jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
 					"Sending stop char! Times sent: %x\n", ch->ch_stops_sent);
@@ -846,7 +851,7 @@
 		/* HWFLOW */
 		if (ch->ch_c_cflag & CRTSCTS) {
 			if (ch->ch_flags & CH_RECEIVER_OFF) {
-				ch->ch_bd->bd_ops->enable_receiver(ch);
+				bd_ops->enable_receiver(ch);
 				ch->ch_flags &= ~(CH_RECEIVER_OFF);
 				jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
 					"Internal queue hit lowlevel mark (%d)! Turning on interrupts.\n",
@@ -856,7 +861,7 @@
 		/* SWFLOW */
 		else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) {
 			ch->ch_stops_sent = 0;
-			ch->ch_bd->bd_ops->send_start_character(ch);
+			bd_ops->send_start_character(ch);
 			jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Sending start char!\n");
 		}
 	}
diff -urN oldtree/drivers/serial/m32r_sio.h newtree/drivers/serial/m32r_sio.h
--- oldtree/drivers/serial/m32r_sio.h	2006-02-19 11:41:04.188706320 +0000
+++ newtree/drivers/serial/m32r_sio.h	2006-02-21 15:58:36.479600816 +0000
@@ -35,7 +35,7 @@
 	unsigned int baud_base;
 	unsigned int port;
 	unsigned int irq;
-	unsigned int flags;
+	upf_t flags;
 	unsigned char io_type;
 	unsigned char __iomem *iomem_base;
 	unsigned short iomem_reg_shift;
diff -urN oldtree/drivers/serial/s3c2410.c newtree/drivers/serial/s3c2410.c
--- oldtree/drivers/serial/s3c2410.c	2006-02-19 11:41:04.195705256 +0000
+++ newtree/drivers/serial/s3c2410.c	2006-02-21 15:58:12.511244560 +0000
@@ -1066,6 +1066,8 @@
 	port->mapbase	= res->start;
 	port->membase	= S3C24XX_VA_UART + (res->start - S3C24XX_PA_UART);
 	port->irq	= platform_get_irq(platdev, 0);
+	if (port->irq < 0)
+		port->irq = 0;
 
 	ourport->clk	= clk_get(&platdev->dev, "uart");
 
diff -urN oldtree/drivers/serial/sunhv.c newtree/drivers/serial/sunhv.c
--- oldtree/drivers/serial/sunhv.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/serial/sunhv.c	2006-02-21 15:58:20.477033576 +0000
@@ -0,0 +1,549 @@
+/* sunhv.c: Serial driver for SUN4V hypervisor console.
+ *
+ * Copyright (C) 2006 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/hypervisor.h>
+#include <asm/spitfire.h>
+#include <asm/vdev.h>
+#include <asm/oplib.h>
+#include <asm/irq.h>
+
+#if defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#include "suncore.h"
+
+#define CON_BREAK	((long)-1)
+#define CON_HUP		((long)-2)
+
+static inline long hypervisor_con_getchar(long *status)
+{
+	register unsigned long func asm("%o5");
+	register unsigned long arg0 asm("%o0");
+	register unsigned long arg1 asm("%o1");
+
+	func = HV_FAST_CONS_GETCHAR;
+	arg0 = 0;
+	arg1 = 0;
+	__asm__ __volatile__("ta	%6"
+			     : "=&r" (func), "=&r" (arg0), "=&r" (arg1)
+			     : "0" (func), "1" (arg0), "2" (arg1),
+			       "i" (HV_FAST_TRAP));
+
+	*status = arg0;
+
+	return (long) arg1;
+}
+
+static inline long hypervisor_con_putchar(long ch)
+{
+	register unsigned long func asm("%o5");
+	register unsigned long arg0 asm("%o0");
+
+	func = HV_FAST_CONS_PUTCHAR;
+	arg0 = ch;
+	__asm__ __volatile__("ta	%4"
+			     : "=&r" (func), "=&r" (arg0)
+			     : "0" (func), "1" (arg0), "i" (HV_FAST_TRAP));
+
+	return (long) arg0;
+}
+
+#define IGNORE_BREAK	0x1
+#define IGNORE_ALL	0x2
+
+static int hung_up = 0;
+
+static struct tty_struct *receive_chars(struct uart_port *port, struct pt_regs *regs)
+{
+	struct tty_struct *tty = NULL;
+	int saw_console_brk = 0;
+	int limit = 10000;
+
+	if (port->info != NULL)		/* Unopened serial console */
+		tty = port->info->tty;
+
+	while (limit-- > 0) {
+		long status;
+		long c = hypervisor_con_getchar(&status);
+		unsigned char flag;
+
+		if (status == HV_EWOULDBLOCK)
+			break;
+
+		if (c == CON_BREAK) {
+			if (uart_handle_break(port))
+				continue;
+			saw_console_brk = 1;
+			c = 0;
+		}
+
+		if (c == CON_HUP) {
+			hung_up = 1;
+			uart_handle_dcd_change(port, 0);
+		} else if (hung_up) {
+			hung_up = 0;
+			uart_handle_dcd_change(port, 1);
+		}
+
+		if (tty == NULL) {
+			uart_handle_sysrq_char(port, c, regs);
+			continue;
+		}
+
+		flag = TTY_NORMAL;
+		port->icount.rx++;
+		if (c == CON_BREAK) {
+			port->icount.brk++;
+			if (uart_handle_break(port))
+				continue;
+			flag = TTY_BREAK;
+		}
+
+		if (uart_handle_sysrq_char(port, c, regs))
+			continue;
+
+		if ((port->ignore_status_mask & IGNORE_ALL) ||
+		    ((port->ignore_status_mask & IGNORE_BREAK) &&
+		     (c == CON_BREAK)))
+			continue;
+
+		tty_insert_flip_char(tty, c, flag);
+	}
+
+	if (saw_console_brk)
+		sun_do_break();
+
+	return tty;
+}
+
+static void transmit_chars(struct uart_port *port)
+{
+	struct circ_buf *xmit;
+
+	if (!port->info)
+		return;
+
+	xmit = &port->info->xmit;
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+		return;
+
+	while (!uart_circ_empty(xmit)) {
+		long status = hypervisor_con_putchar(xmit->buf[xmit->tail]);
+
+		if (status != HV_EOK)
+			break;
+
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+	}
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+}
+
+static irqreturn_t sunhv_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uart_port *port = dev_id;
+	struct tty_struct *tty;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+	tty = receive_chars(port, regs);
+	transmit_chars(port);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	if (tty)
+		tty_flip_buffer_push(tty);
+
+	return IRQ_HANDLED;
+}
+
+/* port->lock is not held.  */
+static unsigned int sunhv_tx_empty(struct uart_port *port)
+{
+	/* Transmitter is always empty for us.  If the circ buffer
+	 * is non-empty or there is an x_char pending, our caller
+	 * will do the right thing and ignore what we return here.
+	 */
+	return TIOCSER_TEMT;
+}
+
+/* port->lock held by caller.  */
+static void sunhv_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	return;
+}
+
+/* port->lock is held by caller and interrupts are disabled.  */
+static unsigned int sunhv_get_mctrl(struct uart_port *port)
+{
+	return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS;
+}
+
+/* port->lock held by caller.  */
+static void sunhv_stop_tx(struct uart_port *port)
+{
+	return;
+}
+
+/* port->lock held by caller.  */
+static void sunhv_start_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->info->xmit;
+
+	while (!uart_circ_empty(xmit)) {
+		long status = hypervisor_con_putchar(xmit->buf[xmit->tail]);
+
+		if (status != HV_EOK)
+			break;
+
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+	}
+}
+
+/* port->lock is not held.  */
+static void sunhv_send_xchar(struct uart_port *port, char ch)
+{
+	unsigned long flags;
+	int limit = 10000;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	while (limit-- > 0) {
+		long status = hypervisor_con_putchar(ch);
+		if (status == HV_EOK)
+			break;
+	}
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* port->lock held by caller.  */
+static void sunhv_stop_rx(struct uart_port *port)
+{
+}
+
+/* port->lock held by caller.  */
+static void sunhv_enable_ms(struct uart_port *port)
+{
+}
+
+/* port->lock is not held.  */
+static void sunhv_break_ctl(struct uart_port *port, int break_state)
+{
+	if (break_state) {
+		unsigned long flags;
+		int limit = 1000000;
+
+		spin_lock_irqsave(&port->lock, flags);
+
+		while (limit-- > 0) {
+			long status = hypervisor_con_putchar(CON_BREAK);
+			if (status == HV_EOK)
+				break;
+			udelay(2);
+		}
+
+		spin_unlock_irqrestore(&port->lock, flags);
+	}
+}
+
+/* port->lock is not held.  */
+static int sunhv_startup(struct uart_port *port)
+{
+	return 0;
+}
+
+/* port->lock is not held.  */
+static void sunhv_shutdown(struct uart_port *port)
+{
+}
+
+/* port->lock is not held.  */
+static void sunhv_set_termios(struct uart_port *port, struct termios *termios,
+			      struct termios *old)
+{
+	unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
+	unsigned int quot = uart_get_divisor(port, baud);
+	unsigned int iflag, cflag;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	iflag = termios->c_iflag;
+	cflag = termios->c_cflag;
+
+	port->ignore_status_mask = 0;
+	if (iflag & IGNBRK)
+		port->ignore_status_mask |= IGNORE_BREAK;
+	if ((cflag & CREAD) == 0)
+		port->ignore_status_mask |= IGNORE_ALL;
+
+	/* XXX */
+	uart_update_timeout(port, cflag,
+			    (port->uartclk / (16 * quot)));
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *sunhv_type(struct uart_port *port)
+{
+	return "SUN4V HCONS";
+}
+
+static void sunhv_release_port(struct uart_port *port)
+{
+}
+
+static int sunhv_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+static void sunhv_config_port(struct uart_port *port, int flags)
+{
+}
+
+static int sunhv_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	return -EINVAL;
+}
+
+static struct uart_ops sunhv_pops = {
+	.tx_empty	= sunhv_tx_empty,
+	.set_mctrl	= sunhv_set_mctrl,
+	.get_mctrl	= sunhv_get_mctrl,
+	.stop_tx	= sunhv_stop_tx,
+	.start_tx	= sunhv_start_tx,
+	.send_xchar	= sunhv_send_xchar,
+	.stop_rx	= sunhv_stop_rx,
+	.enable_ms	= sunhv_enable_ms,
+	.break_ctl	= sunhv_break_ctl,
+	.startup	= sunhv_startup,
+	.shutdown	= sunhv_shutdown,
+	.set_termios	= sunhv_set_termios,
+	.type		= sunhv_type,
+	.release_port	= sunhv_release_port,
+	.request_port	= sunhv_request_port,
+	.config_port	= sunhv_config_port,
+	.verify_port	= sunhv_verify_port,
+};
+
+static struct uart_driver sunhv_reg = {
+	.owner			= THIS_MODULE,
+	.driver_name		= "serial",
+	.devfs_name		= "tts/",
+	.dev_name		= "ttyS",
+	.major			= TTY_MAJOR,
+};
+
+static struct uart_port *sunhv_port;
+
+static inline void sunhv_console_putchar(struct uart_port *port, char c)
+{
+	unsigned long flags;
+	int limit = 1000000;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	while (limit-- > 0) {
+		long status = hypervisor_con_putchar(c);
+		if (status == HV_EOK)
+			break;
+		udelay(2);
+	}
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void sunhv_console_write(struct console *con, const char *s, unsigned n)
+{
+	struct uart_port *port = sunhv_port;
+	int i;
+
+	for (i = 0; i < n; i++) {
+		if (*s == '\n')
+			sunhv_console_putchar(port, '\r');
+		sunhv_console_putchar(port, *s++);
+	}
+}
+
+static struct console sunhv_console = {
+	.name	=	"ttyHV",
+	.write	=	sunhv_console_write,
+	.device	=	uart_console_device,
+	.flags	=	CON_PRINTBUFFER,
+	.index	=	-1,
+	.data	=	&sunhv_reg,
+};
+
+static inline struct console *SUNHV_CONSOLE(void)
+{
+	if (con_is_present())
+		return NULL;
+
+	sunhv_console.index = 0;
+
+	return &sunhv_console;
+}
+
+static int __init hv_console_compatible(char *buf, int len)
+{
+	while (len) {
+		int this_len;
+
+		if (!strcmp(buf, "qcn"))
+			return 1;
+
+		this_len = strlen(buf) + 1;
+
+		buf += this_len;
+		len -= this_len;
+	}
+
+	return 0;
+}
+
+static unsigned int __init get_interrupt(void)
+{
+	const char *cons_str = "console";
+	const char *compat_str = "compatible";
+	int node = prom_getchild(sun4v_vdev_root);
+	char buf[64];
+	int err, len;
+
+	node = prom_searchsiblings(node, cons_str);
+	if (!node)
+		return 0;
+
+	len = prom_getproplen(node, compat_str);
+	if (len == 0 || len == -1)
+		return 0;
+
+	err = prom_getproperty(node, compat_str, buf, 64);
+	if (err == -1)
+		return 0;
+
+	if (!hv_console_compatible(buf, len))
+		return 0;
+
+	/* Ok, the this is the OBP node for the sun4v hypervisor
+	 * console device.  Decode the interrupt.
+	 */
+	return sun4v_vdev_device_interrupt(node);
+}
+
+static int __init sunhv_init(void)
+{
+	struct uart_port *port;
+	int ret;
+
+	if (tlb_type != hypervisor)
+		return -ENODEV;
+
+	port = kmalloc(sizeof(struct uart_port), GFP_KERNEL);
+	if (unlikely(!port))
+		return -ENOMEM;
+
+	memset(port, 0, sizeof(struct uart_port));
+
+	port->line = 0;
+	port->ops = &sunhv_pops;
+	port->type = PORT_SUNHV;
+	port->uartclk = ( 29491200 / 16 ); /* arbitrary */
+
+	/* Set this just to make uart_configure_port() happy.  */
+	port->membase = (unsigned char __iomem *) __pa(port);
+
+	port->irq = get_interrupt();
+	if (!port->irq) {
+		kfree(port);
+		return -ENODEV;
+	}
+
+	sunhv_reg.minor = sunserial_current_minor;
+	sunhv_reg.nr = 1;
+
+	ret = uart_register_driver(&sunhv_reg);
+	if (ret < 0) {
+		printk(KERN_ERR "SUNHV: uart_register_driver() failed %d\n",
+		       ret);
+		kfree(port);
+
+		return ret;
+	}
+
+	sunserial_current_minor += 1;
+
+	sunhv_reg.cons = SUNHV_CONSOLE();
+
+	sunhv_port = port;
+
+	ret = uart_add_one_port(&sunhv_reg, port);
+	if (ret < 0) {
+		printk(KERN_ERR "SUNHV: uart_add_one_port() failed %d\n", ret);
+		sunserial_current_minor -= 1;
+		uart_unregister_driver(&sunhv_reg);
+		kfree(port);
+		sunhv_port = NULL;
+		return -ENODEV;
+	}
+
+	if (request_irq(port->irq, sunhv_interrupt,
+			SA_SHIRQ, "serial(sunhv)", port)) {
+		printk(KERN_ERR "sunhv: Cannot register IRQ\n");
+		uart_remove_one_port(&sunhv_reg, port);
+		sunserial_current_minor -= 1;
+		uart_unregister_driver(&sunhv_reg);
+		kfree(port);
+		sunhv_port = NULL;
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void __exit sunhv_exit(void)
+{
+	struct uart_port *port = sunhv_port;
+
+	BUG_ON(!port);
+
+	free_irq(port->irq, port);
+
+	uart_remove_one_port(&sunhv_reg, port);
+	sunserial_current_minor -= 1;
+
+	uart_unregister_driver(&sunhv_reg);
+
+	kfree(sunhv_port);
+	sunhv_port = NULL;
+}
+
+module_init(sunhv_init);
+module_exit(sunhv_exit);
+
+MODULE_AUTHOR("David S. Miller");
+MODULE_DESCRIPTION("SUN4V Hypervisor console driver")
+MODULE_LICENSE("GPL");
diff -urN oldtree/drivers/serial/sunsab.c newtree/drivers/serial/sunsab.c
--- oldtree/drivers/serial/sunsab.c	2006-02-19 11:41:04.205703736 +0000
+++ newtree/drivers/serial/sunsab.c	2006-02-21 15:58:20.487032056 +0000
@@ -955,14 +955,13 @@
 	.index	=	-1,
 	.data	=	&sunsab_reg,
 };
-#define SUNSAB_CONSOLE	(&sunsab_console)
 
-static void __init sunsab_console_init(void)
+static inline struct console *SUNSAB_CONSOLE(void)
 {
 	int i;
 
 	if (con_is_present())
-		return;
+		return NULL;
 
 	for (i = 0; i < num_channels; i++) {
 		int this_minor = sunsab_reg.minor + i;
@@ -971,13 +970,14 @@
 			break;
 	}
 	if (i == num_channels)
-		return;
+		return NULL;
 
 	sunsab_console.index = i;
-	register_console(&sunsab_console);
+
+	return &sunsab_console;
 }
 #else
-#define SUNSAB_CONSOLE		(NULL)
+#define SUNSAB_CONSOLE()	(NULL)
 #define sunsab_console_init()	do { } while (0)
 #endif
 
@@ -1124,7 +1124,6 @@
 
 	sunsab_reg.minor = sunserial_current_minor;
 	sunsab_reg.nr = num_channels;
-	sunsab_reg.cons = SUNSAB_CONSOLE;
 
 	ret = uart_register_driver(&sunsab_reg);
 	if (ret < 0) {
@@ -1143,10 +1142,10 @@
 		return ret;
 	}
 
+	sunsab_reg.cons = SUNSAB_CONSOLE();
+
 	sunserial_current_minor += num_channels;
 	
-	sunsab_console_init();
-
 	for (i = 0; i < num_channels; i++) {
 		struct uart_sunsab_port *up = &sunsab_ports[i];
 
diff -urN oldtree/drivers/serial/sunsu.c newtree/drivers/serial/sunsu.c
--- oldtree/drivers/serial/sunsu.c	2006-02-19 11:41:04.206703584 +0000
+++ newtree/drivers/serial/sunsu.c	2006-02-21 15:58:20.498030384 +0000
@@ -1467,18 +1467,17 @@
 	.index	=	-1,
 	.data	=	&sunsu_reg,
 };
-#define SUNSU_CONSOLE	(&sunsu_cons)
 
 /*
  *	Register console.
  */
 
-static int __init sunsu_serial_console_init(void)
+static inline struct console *SUNSU_CONSOLE(void)
 {
 	int i;
 
 	if (con_is_present())
-		return 0;
+		return NULL;
 
 	for (i = 0; i < UART_NR; i++) {
 		int this_minor = sunsu_reg.minor + i;
@@ -1487,16 +1486,16 @@
 			break;
 	}
 	if (i == UART_NR)
-		return 0;
+		return NULL;
 	if (sunsu_ports[i].port_node == 0)
-		return 0;
+		return NULL;
 
 	sunsu_cons.index = i;
-	register_console(&sunsu_cons);
-	return 0;
+
+	return &sunsu_cons;
 }
 #else
-#define SUNSU_CONSOLE			(NULL)
+#define SUNSU_CONSOLE()			(NULL)
 #define sunsu_serial_console_init()	do { } while (0)
 #endif
 
@@ -1526,16 +1525,17 @@
 	}
 
 	sunsu_reg.minor = sunserial_current_minor;
-	sunserial_current_minor += instance;
 
 	sunsu_reg.nr = instance;
-	sunsu_reg.cons = SUNSU_CONSOLE;
 
 	ret = uart_register_driver(&sunsu_reg);
 	if (ret < 0)
 		return ret;
 
-	sunsu_serial_console_init();
+	sunserial_current_minor += instance;
+
+	sunsu_reg.cons = SUNSU_CONSOLE();
+
 	for (i = 0; i < UART_NR; i++) {
 		struct uart_sunsu_port *up = &sunsu_ports[i];
 
diff -urN oldtree/drivers/serial/sunzilog.c newtree/drivers/serial/sunzilog.c
--- oldtree/drivers/serial/sunzilog.c	2006-02-19 11:41:04.207703432 +0000
+++ newtree/drivers/serial/sunzilog.c	2006-02-21 15:58:20.500030080 +0000
@@ -1390,7 +1390,6 @@
 	.index	=	-1,
 	.data   =	&sunzilog_reg,
 };
-#define SUNZILOG_CONSOLE	(&sunzilog_console)
 
 static int __init sunzilog_console_init(void)
 {
@@ -1413,8 +1412,31 @@
 	register_console(&sunzilog_console);
 	return 0;
 }
+
+static inline struct console *SUNZILOG_CONSOLE(void)
+{
+	int i;
+
+	if (con_is_present())
+		return NULL;
+
+	for (i = 0; i < NUM_CHANNELS; i++) {
+		int this_minor = sunzilog_reg.minor + i;
+
+		if ((this_minor - 64) == (serial_console - 1))
+			break;
+	}
+	if (i == NUM_CHANNELS)
+		return NULL;
+
+	sunzilog_console.index = i;
+	sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS;
+
+	return &sunzilog_console;
+}
+
 #else
-#define SUNZILOG_CONSOLE	(NULL)
+#define SUNZILOG_CONSOLE()	(NULL)
 #define sunzilog_console_init() do { } while (0)
 #endif
 
@@ -1666,14 +1688,14 @@
 	}
 		
 	sunzilog_reg.nr = uart_count;
-	sunzilog_reg.cons = SUNZILOG_CONSOLE;
-
 	sunzilog_reg.minor = sunserial_current_minor;
-	sunserial_current_minor += uart_count;
 
 	ret = uart_register_driver(&sunzilog_reg);
 	if (ret == 0) {
-		sunzilog_console_init();
+		sunzilog_reg.cons = SUNZILOG_CONSOLE();
+
+		sunserial_current_minor += uart_count;
+
 		for (i = 0; i < NUM_CHANNELS; i++) {
 			struct uart_sunzilog_port *up = &sunzilog_port_table[i];
 
diff -urN oldtree/drivers/sn/ioc3.c newtree/drivers/sn/ioc3.c
--- oldtree/drivers/sn/ioc3.c	2006-02-19 11:41:04.277692792 +0000
+++ newtree/drivers/sn/ioc3.c	2006-02-21 15:58:29.963591400 +0000
@@ -62,7 +62,7 @@
         return presence;
 }
 
-static inline int nic_read_bit(struct ioc3_driver_data *idd)
+static int nic_read_bit(struct ioc3_driver_data *idd)
 {
 	int result;
 	unsigned long flags;
@@ -77,7 +77,7 @@
 	return result;
 }
 
-static inline void nic_write_bit(struct ioc3_driver_data *idd, int bit)
+static void nic_write_bit(struct ioc3_driver_data *idd, int bit)
 {
 	if (bit)
 		writel(mcr_pack(6, 110), &idd->vma->mcr);
@@ -371,8 +371,7 @@
 
 /* Interrupts */
 
-static inline void
-write_ireg(struct ioc3_driver_data *idd, uint32_t val, int which)
+static void write_ireg(struct ioc3_driver_data *idd, uint32_t val, int which)
 {
 	unsigned long flags;
 
@@ -735,14 +734,12 @@
 	}
 
 	/* Add this IOC3 to all submodules */
-	read_lock(&ioc3_submodules_lock);
 	for(id=0;id<IOC3_MAX_SUBMODULES;id++)
 		if(ioc3_submodules[id] && ioc3_submodules[id]->probe) {
 			idd->active[id] = 1;
 			idd->active[id] = !ioc3_submodules[id]->probe
 						(ioc3_submodules[id], idd);
 		}
-	read_unlock(&ioc3_submodules_lock);
 
 	printk(KERN_INFO "IOC3 Master Driver loaded for %s\n", pci_name(pdev));
 
@@ -767,7 +764,6 @@
 	idd = pci_get_drvdata(pdev);
 
 	/* Remove this IOC3 from all submodules */
-	read_lock(&ioc3_submodules_lock);
 	for(id=0;id<IOC3_MAX_SUBMODULES;id++)
 		if(idd->active[id]) {
 			if(ioc3_submodules[id] && ioc3_submodules[id]->remove)
@@ -781,7 +777,6 @@
 					        pci_name(pdev));
 			idd->active[id] = 0;
 		}
-	read_unlock(&ioc3_submodules_lock);
 
 	/* Clear and disable all IRQs */
 	write_ireg(idd, ~0, IOC3_W_IEC);
diff -urN oldtree/drivers/telephony/phonedev.c newtree/drivers/telephony/phonedev.c
--- oldtree/drivers/telephony/phonedev.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/telephony/phonedev.c	2006-02-21 15:58:24.259458560 +0000
@@ -29,6 +29,7 @@
 #include <linux/kmod.h>
 #include <linux/sem.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/mutex.h>
 
 #define PHONE_NUM_DEVICES	256
 
@@ -37,7 +38,7 @@
  */
 
 static struct phone_device *phone_device[PHONE_NUM_DEVICES];
-static DECLARE_MUTEX(phone_lock);
+static DEFINE_MUTEX(phone_lock);
 
 /*
  *    Open a phone device.
@@ -53,14 +54,14 @@
 	if (minor >= PHONE_NUM_DEVICES)
 		return -ENODEV;
 
-	down(&phone_lock);
+	mutex_lock(&phone_lock);
 	p = phone_device[minor];
 	if (p)
 		new_fops = fops_get(p->f_op);
 	if (!new_fops) {
-		up(&phone_lock);
+		mutex_unlock(&phone_lock);
 		request_module("char-major-%d-%d", PHONE_MAJOR, minor);
-		down(&phone_lock);
+		mutex_lock(&phone_lock);
 		p = phone_device[minor];
 		if (p == NULL || (new_fops = fops_get(p->f_op)) == NULL)
 		{
@@ -78,7 +79,7 @@
 	}
 	fops_put(old_fops);
 end:
-	up(&phone_lock);
+	mutex_unlock(&phone_lock);
 	return err;
 }
 
@@ -100,18 +101,18 @@
 		end = unit + 1;  /* enter the loop at least one time */
 	}
 	
-	down(&phone_lock);
+	mutex_lock(&phone_lock);
 	for (i = base; i < end; i++) {
 		if (phone_device[i] == NULL) {
 			phone_device[i] = p;
 			p->minor = i;
 			devfs_mk_cdev(MKDEV(PHONE_MAJOR,i),
 				S_IFCHR|S_IRUSR|S_IWUSR, "phone/%d", i);
-			up(&phone_lock);
+			mutex_unlock(&phone_lock);
 			return 0;
 		}
 	}
-	up(&phone_lock);
+	mutex_unlock(&phone_lock);
 	return -ENFILE;
 }
 
@@ -121,12 +122,12 @@
 
 void phone_unregister_device(struct phone_device *pfd)
 {
-	down(&phone_lock);
+	mutex_lock(&phone_lock);
 	if (phone_device[pfd->minor] != pfd)
 		panic("phone: bad unregister");
 	devfs_remove("phone/%d", pfd->minor);
 	phone_device[pfd->minor] = NULL;
-	up(&phone_lock);
+	mutex_unlock(&phone_lock);
 }
 
 
diff -urN oldtree/drivers/usb/core/driver.c newtree/drivers/usb/core/driver.c
--- oldtree/drivers/usb/core/driver.c	2006-02-19 11:41:04.304688688 +0000
+++ newtree/drivers/usb/core/driver.c	2006-02-21 15:58:12.740209752 +0000
@@ -378,7 +378,7 @@
 
 	return NULL;
 }
-EXPORT_SYMBOL(usb_match_id);
+EXPORT_SYMBOL_GPL_FUTURE(usb_match_id);
 
 int usb_device_match(struct device *dev, struct device_driver *drv)
 {
@@ -446,7 +446,7 @@
 
 	return retval;
 }
-EXPORT_SYMBOL(usb_register_driver);
+EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver);
 
 /**
  * usb_deregister - unregister a USB driver
@@ -469,4 +469,4 @@
 
 	usbfs_update_special();
 }
-EXPORT_SYMBOL(usb_deregister);
+EXPORT_SYMBOL_GPL_FUTURE(usb_deregister);
diff -urN oldtree/drivers/usb/host/ohci-omap.c newtree/drivers/usb/host/ohci-omap.c
--- oldtree/drivers/usb/host/ohci-omap.c	2006-02-19 11:41:04.343682760 +0000
+++ newtree/drivers/usb/host/ohci-omap.c	2006-02-21 15:58:12.522242888 +0000
@@ -286,7 +286,7 @@
 int usb_hcd_omap_probe (const struct hc_driver *driver,
 			  struct platform_device *pdev)
 {
-	int retval;
+	int retval, irq;
 	struct usb_hcd *hcd = 0;
 	struct ohci_hcd *ohci;
 
@@ -329,7 +329,12 @@
 	if (retval < 0)
 		goto err2;
 
-	retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), SA_INTERRUPT);
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		retval = -ENXIO;
+		goto err2;
+	}
+	retval = usb_add_hcd(hcd, irq, SA_INTERRUPT);
 	if (retval == 0)
 		return retval;
 
diff -urN oldtree/drivers/usb/misc/sisusbvga/sisusb.c newtree/drivers/usb/misc/sisusbvga/sisusb.c
--- oldtree/drivers/usb/misc/sisusbvga/sisusb.c	2006-02-19 11:41:04.415671816 +0000
+++ newtree/drivers/usb/misc/sisusbvga/sisusb.c	2006-02-21 15:58:27.642944192 +0000
@@ -37,6 +37,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/mutex.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
@@ -102,7 +103,7 @@
 
 static struct usb_driver sisusb_driver;
 
-DECLARE_MUTEX(disconnect_sem);
+DEFINE_MUTEX(disconnect_mutex);
 
 static void
 sisusb_free_buffers(struct sisusb_usb_data *sisusb)
@@ -2552,39 +2553,39 @@
 	struct usb_interface *interface;
 	int subminor = iminor(inode);
 
-	down(&disconnect_sem);
+	mutex_lock(&disconnect_mutex);
 
 	if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
 		printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
 				subminor);
-		up(&disconnect_sem);
+		mutex_unlock(&disconnect_mutex);
 		return -ENODEV;
 	}
 
 	if (!(sisusb = usb_get_intfdata(interface))) {
-		up(&disconnect_sem);
+		mutex_unlock(&disconnect_mutex);
 		return -ENODEV;
 	}
 
-	down(&sisusb->lock);
+	mutex_lock(&sisusb->lock);
 
 	if (!sisusb->present || !sisusb->ready) {
-		up(&sisusb->lock);
-		up(&disconnect_sem);
+		mutex_unlock(&sisusb->lock);
+		mutex_unlock(&disconnect_mutex);
 		return -ENODEV;
 	}
 
 	if (sisusb->isopen) {
-		up(&sisusb->lock);
-		up(&disconnect_sem);
+		mutex_unlock(&sisusb->lock);
+		mutex_unlock(&disconnect_mutex);
 		return -EBUSY;
 	}
 
 	if (!sisusb->devinit) {
 		if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
 			if (sisusb_init_gfxdevice(sisusb, 0)) {
-				up(&sisusb->lock);
-				up(&disconnect_sem);
+				mutex_unlock(&sisusb->lock);
+				mutex_unlock(&disconnect_mutex);
 				printk(KERN_ERR
 					"sisusbvga[%d]: Failed to initialize "
 					"device\n",
@@ -2592,8 +2593,8 @@
 				return -EIO;
 			}
 		} else {
-			up(&sisusb->lock);
-			up(&disconnect_sem);
+			mutex_unlock(&sisusb->lock);
+			mutex_unlock(&disconnect_mutex);
 			printk(KERN_ERR
 				"sisusbvga[%d]: Device not attached to "
 				"USB 2.0 hub\n",
@@ -2609,9 +2610,9 @@
 
 	file->private_data = sisusb;
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 
-	up(&disconnect_sem);
+	mutex_unlock(&disconnect_mutex);
 
 	return 0;
 }
@@ -2642,14 +2643,14 @@
 	struct sisusb_usb_data *sisusb;
 	int myminor;
 
-	down(&disconnect_sem);
+	mutex_lock(&disconnect_mutex);
 
 	if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) {
-		up(&disconnect_sem);
+		mutex_unlock(&disconnect_mutex);
 		return -ENODEV;
 	}
 
-	down(&sisusb->lock);
+	mutex_lock(&sisusb->lock);
 
 	if (sisusb->present) {
 		/* Wait for all URBs to finish if device still present */
@@ -2662,12 +2663,12 @@
 	sisusb->isopen = 0;
 	file->private_data = NULL;
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 
 	/* decrement the usage count on our device */
 	kref_put(&sisusb->kref, sisusb_delete);
 
-	up(&disconnect_sem);
+	mutex_unlock(&disconnect_mutex);
 
 	return 0;
 }
@@ -2685,11 +2686,11 @@
 	if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
 		return -ENODEV;
 
-	down(&sisusb->lock);
+	mutex_lock(&sisusb->lock);
 
 	/* Sanity check */
 	if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		return -ENODEV;
 	}
 
@@ -2784,7 +2785,7 @@
 		    (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
 
 		if (count != 4) {
-			up(&sisusb->lock);
+			mutex_unlock(&sisusb->lock);
 			return -EINVAL;
 		}
 
@@ -2808,7 +2809,7 @@
 
 	(*ppos) += bytes_read;
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 
 	return errno ? errno : bytes_read;
 }
@@ -2827,11 +2828,11 @@
 	if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
 		return -ENODEV;
 
-	down(&sisusb->lock);
+	mutex_lock(&sisusb->lock);
 
 	/* Sanity check */
 	if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		return -ENODEV;
 	}
 
@@ -2930,7 +2931,7 @@
 		    (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) {
 
 		if (count != 4) {
-			up(&sisusb->lock);
+			mutex_unlock(&sisusb->lock);
 			return -EINVAL;
 		}
 
@@ -2956,7 +2957,7 @@
 
 	(*ppos) += bytes_written;
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 
 	return errno ? errno : bytes_written;
 }
@@ -2970,11 +2971,11 @@
 	if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
 		return -ENODEV;
 
-	down(&sisusb->lock);
+	mutex_lock(&sisusb->lock);
 
 	/* Sanity check */
 	if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		return -ENODEV;
 	}
 
@@ -2994,7 +2995,7 @@
 			ret = -EINVAL;
 	}
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 	return ret;
 }
 
@@ -3136,7 +3137,7 @@
 	if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
 		return -ENODEV;
 
-	down(&sisusb->lock);
+	mutex_lock(&sisusb->lock);
 
 	/* Sanity check */
 	if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
@@ -3193,7 +3194,7 @@
 	}
 
 err_out:
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 	return retval;
 }
 
@@ -3259,7 +3260,7 @@
 	memset(sisusb, 0, sizeof(*sisusb));
 	kref_init(&sisusb->kref);
 
-	init_MUTEX(&(sisusb->lock));
+	mutex_init(&(sisusb->lock));
 
 	/* Register device */
 	if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
@@ -3430,9 +3431,9 @@
 	 * protect all other routines from the disconnect
 	 * case, not the other way round.
 	 */
-	down(&disconnect_sem);
+	mutex_lock(&disconnect_mutex);
 
-	down(&sisusb->lock);
+	mutex_lock(&sisusb->lock);
 
 	/* Wait for all URBs to complete and kill them in case (MUST do) */
 	if (!sisusb_wait_all_out_complete(sisusb))
@@ -3463,12 +3464,12 @@
 	sisusb->present = 0;
 	sisusb->ready = 0;
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 
 	/* decrement our usage count */
 	kref_put(&sisusb->kref, sisusb_delete);
 
-	up(&disconnect_sem);
+	mutex_unlock(&disconnect_mutex);
 
 	printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
 }
diff -urN oldtree/drivers/usb/misc/sisusbvga/sisusb.h newtree/drivers/usb/misc/sisusbvga/sisusb.h
--- oldtree/drivers/usb/misc/sisusbvga/sisusb.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/usb/misc/sisusbvga/sisusb.h	2006-02-21 15:58:27.843913640 +0000
@@ -47,6 +47,8 @@
 #endif
 #endif
 
+#include <linux/mutex.h>
+
 /* For older kernels, support for text consoles is by default
  * off. To ensable text console support, change the following:
  */
@@ -124,7 +126,7 @@
 	struct usb_interface *interface;
 	struct kref kref;
 	wait_queue_head_t wait_q;	/* for syncind and timeouts */
-	struct semaphore lock;		/* general race avoidance */
+	struct mutex lock;		/* general race avoidance */
 	unsigned int ifnum;		/* interface number of the USB device */
 	int minor;			/* minor (for logging clarity) */
 	int isopen;			/* !=0 if open */
diff -urN oldtree/drivers/usb/misc/sisusbvga/sisusb_con.c newtree/drivers/usb/misc/sisusbvga/sisusb_con.c
--- oldtree/drivers/usb/misc/sisusbvga/sisusb_con.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/usb/misc/sisusbvga/sisusb_con.c	2006-02-21 15:58:27.813918200 +0000
@@ -48,6 +48,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/mutex.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
@@ -102,7 +103,7 @@
 /* Forward declaration */
 static const struct consw sisusb_con;
 
-extern struct semaphore disconnect_sem;
+extern struct mutex disconnect_mutex;
 
 static inline void
 sisusbcon_memsetw(u16 *s, u16 c, unsigned int count)
@@ -194,11 +195,11 @@
 	if (!(sisusb = sisusb_get_sisusb(console)))
 		return NULL;
 
-	down(&sisusb->lock);
+	mutex_lock(&sisusb->lock);
 
 	if (!sisusb_sisusb_valid(sisusb) ||
 	    !sisusb->havethisconsole[console]) {
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		return NULL;
 	}
 
@@ -236,18 +237,18 @@
 	 * are set up/restored.
 	 */
 
-	down(&disconnect_sem);
+	mutex_lock(&disconnect_mutex);
 
 	if (!(sisusb = sisusb_get_sisusb(c->vc_num))) {
-		up(&disconnect_sem);
+		mutex_unlock(&disconnect_mutex);
 		return;
 	}
 
-	down(&sisusb->lock);
+	mutex_lock(&sisusb->lock);
 
 	if (!sisusb_sisusb_valid(sisusb)) {
-		up(&sisusb->lock);
-		up(&disconnect_sem);
+		mutex_unlock(&sisusb->lock);
+		mutex_unlock(&disconnect_mutex);
 		return;
 	}
 
@@ -284,9 +285,9 @@
 	if (!*c->vc_uni_pagedir_loc)
 		con_set_default_unimap(c);
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 
-	up(&disconnect_sem);
+	mutex_unlock(&disconnect_mutex);
 
 	if (init) {
 		c->vc_cols = cols;
@@ -306,14 +307,14 @@
 	 * and others, ie not under our control.
 	 */
 
-	down(&disconnect_sem);
+	mutex_lock(&disconnect_mutex);
 
 	if (!(sisusb = sisusb_get_sisusb(c->vc_num))) {
-		up(&disconnect_sem);
+		mutex_unlock(&disconnect_mutex);
 		return;
 	}
 
-	down(&sisusb->lock);
+	mutex_lock(&sisusb->lock);
 
 	/* Clear ourselves in mysisusbs */
 	mysisusbs[c->vc_num] = NULL;
@@ -332,12 +333,12 @@
 		}
 	}
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 
 	/* decrement the usage count on our sisusb */
 	kref_put(&sisusb->kref, sisusb_delete);
 
-	up(&disconnect_sem);
+	mutex_unlock(&disconnect_mutex);
 }
 
 /* interface routine */
@@ -417,7 +418,7 @@
 #endif
 
 	if (sisusb_is_inactive(c, sisusb)) {
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		return;
 	}
 
@@ -425,7 +426,7 @@
 	sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y),
 				(u32)SISUSB_HADDR(x, y), 2, &written);
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 }
 
 /* Interface routine */
@@ -453,14 +454,14 @@
 		sisusbcon_writew(sisusbcon_readw(s++), dest++);
 
 	if (sisusb_is_inactive(c, sisusb)) {
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		return;
 	}
 
 	sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y),
 				(u32)SISUSB_HADDR(x, y), count * 2, &written);
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 }
 
 /* Interface routine */
@@ -504,7 +505,7 @@
 	}
 
 	if (sisusb_is_inactive(c, sisusb)) {
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		return;
 	}
 
@@ -514,7 +515,7 @@
 	sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y),
 				(u32)SISUSB_HADDR(x, y), length, &written);
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 }
 
 /* Interface routine */
@@ -576,7 +577,7 @@
 #endif
 
 	if (sisusb_is_inactive(c, sisusb)) {
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		return;
 	}
 
@@ -586,7 +587,7 @@
 	sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(dx, dy),
 				(u32)SISUSB_HADDR(dx, dy), length, &written);
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 }
 
 /* interface routine */
@@ -609,7 +610,7 @@
 
 	/* Don't write to screen if in gfx mode */
 	if (sisusb_is_inactive(c, sisusb)) {
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		return 0;
 	}
 
@@ -618,7 +619,7 @@
 	 * as origin.
 	 */
 	if (c->vc_origin == (unsigned long)c->vc_screenbuf) {
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n");
 		return 0;
 	}
@@ -635,7 +636,7 @@
 				(u32)SISUSB_HADDR(0, 0),
 				length, &written);
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 
 	return 0;
 }
@@ -657,7 +658,7 @@
 	/* sisusb->lock is down */
 
 	if (sisusb_is_inactive(c, sisusb)) {
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		return;
 	}
 
@@ -669,7 +670,7 @@
 	sisusbcon_memcpyw((u16 *)c->vc_screenbuf, (u16 *)c->vc_origin,
 								length);
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 }
 
 /* interface routine */
@@ -690,7 +691,7 @@
 	/* sisusb->lock is down */
 
 	if (sisusb_is_inactive(c, sisusb)) {
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		return -EINVAL;
 	}
 
@@ -705,7 +706,7 @@
 			break;
 	}
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 
 	return 0;
 }
@@ -728,7 +729,7 @@
 		sisusb->is_gfx = blank ? 1 : 0;
 
 	if (sisusb_is_inactive(c, sisusb)) {
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		return 0;
 	}
 
@@ -777,7 +778,7 @@
 			cr63  = 0x40;
 			break;
 		default:
-			up(&sisusb->lock);
+			mutex_unlock(&sisusb->lock);
 			return -EINVAL;
 		}
 
@@ -788,7 +789,7 @@
 
 	}
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 
 	return ret;
 }
@@ -809,7 +810,7 @@
 	/* sisusb->lock is down */
 
 	if (sisusb_is_inactive(c, sisusb)) {
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		return 0;
 	}
 
@@ -849,7 +850,7 @@
 
 	sisusbcon_set_start_address(sisusb, c);
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 
 	return 1;
 }
@@ -867,7 +868,7 @@
 	/* sisusb->lock is down */
 
 	if (sisusb_is_inactive(c, sisusb)) {
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		return;
 	}
 
@@ -879,7 +880,7 @@
 	if (mode == CM_ERASE) {
 		sisusb_setidxregor(sisusb, SISCR, 0x0a, 0x20);
 		sisusb->sisusb_cursor_size_to = -1;
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		return;
 	}
 
@@ -919,7 +920,7 @@
 		sisusb->sisusb_cursor_size_to   = to;
 	}
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 }
 
 static int
@@ -961,7 +962,7 @@
 	sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t),
 				(u32)SISUSB_HADDR(0, t), length, &written);
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 
 	return 1;
 }
@@ -994,7 +995,7 @@
 	/* sisusb->lock is down */
 
 	if (sisusb_is_inactive(c, sisusb)) {
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		return 0;
 	}
 
@@ -1084,7 +1085,7 @@
 
 	c->vc_pos = c->vc_pos - oldorigin + c->vc_origin;
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 
 	return 1;
 }
@@ -1106,7 +1107,7 @@
 	/* sisusb->lock is down */
 
 	if (sisusb_is_inactive(c, sisusb) || sisusb->con_blanked) {
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		return 0;
 	}
 
@@ -1116,7 +1117,7 @@
 
 	sisusb->con_rolled_over = 0;
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 
 	return 1;
 }
@@ -1133,7 +1134,7 @@
 
 	fh = sisusb->current_font_height;
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 
 	/* We are quite unflexible as regards resizing. The vt code
 	 * handles sizes where the line length isn't equal the pitch
@@ -1167,7 +1168,7 @@
 
 	if ((slot != 0 && slot != 2) || !fh) {
 		if (uplock)
-			up(&sisusb->lock);
+			mutex_unlock(&sisusb->lock);
 		return -EINVAL;
 	}
 
@@ -1327,7 +1328,7 @@
 	}
 
 	if (uplock)
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 
 	if (dorecalc && c) {
 		int i, rows = c->vc_scan_lines / fh;
@@ -1351,7 +1352,7 @@
 
 font_op_error:
 	if (uplock)
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 
 	return -EIO;
 }
@@ -1417,19 +1418,19 @@
 	font->charcount = 256;
 
 	if (!font->data) {
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		return 0;
 	}
 
 	if (!sisusb->font_backup) {
-		up(&sisusb->lock);
+		mutex_unlock(&sisusb->lock);
 		return -ENODEV;
 	}
 
 	/* Copy 256 chars only, like vgacon */
 	memcpy(font->data, sisusb->font_backup, 256 * 32);
 
-	up(&sisusb->lock);
+	mutex_unlock(&sisusb->lock);
 
 	return 0;
 }
@@ -1512,14 +1513,14 @@
 {
 	int i, ret, minor = sisusb->minor;
 
-	down(&disconnect_sem);
+	mutex_lock(&disconnect_mutex);
 
-	down(&sisusb->lock);
+	mutex_lock(&sisusb->lock);
 
 	/* Erm.. that should not happen */
 	if (sisusb->haveconsole || !sisusb->SiS_Pr) {
-		up(&sisusb->lock);
-		up(&disconnect_sem);
+		mutex_unlock(&sisusb->lock);
+		mutex_unlock(&disconnect_mutex);
 		return 1;
 	}
 
@@ -1529,15 +1530,15 @@
 	if (first > last ||
 	    first > MAX_NR_CONSOLES ||
 	    last > MAX_NR_CONSOLES) {
-		up(&sisusb->lock);
-		up(&disconnect_sem);
+		mutex_unlock(&sisusb->lock);
+		mutex_unlock(&disconnect_mutex);
 		return 1;
 	}
 
 	/* If gfxcore not initialized or no consoles given, quit graciously */
 	if (!sisusb->gfxinit || first < 1 || last < 1) {
-		up(&sisusb->lock);
-		up(&disconnect_sem);
+		mutex_unlock(&sisusb->lock);
+		mutex_unlock(&disconnect_mutex);
 		return 0;
 	}
 
@@ -1547,8 +1548,8 @@
 
 	/* Set up text mode (and upload  default font) */
 	if (sisusb_reset_text_mode(sisusb, 1)) {
-		up(&sisusb->lock);
-		up(&disconnect_sem);
+		mutex_unlock(&sisusb->lock);
+		mutex_unlock(&disconnect_mutex);
 		printk(KERN_ERR
 			"sisusbvga[%d]: Failed to set up text mode\n",
 			minor);
@@ -1571,16 +1572,16 @@
 
 	/* Allocate screen buffer */
 	if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
-		up(&sisusb->lock);
-		up(&disconnect_sem);
+		mutex_unlock(&sisusb->lock);
+		mutex_unlock(&disconnect_mutex);
 		printk(KERN_ERR
 			"sisusbvga[%d]: Failed to allocate screen buffer\n",
 			minor);
 		return 1;
 	}
 
-	up(&sisusb->lock);
-	up(&disconnect_sem);
+	mutex_unlock(&sisusb->lock);
+	mutex_unlock(&disconnect_mutex);
 
 	/* Now grab the desired console(s) */
 	ret = take_over_console(&sisusb_con, first - 1, last - 1, 0);
diff -urN oldtree/drivers/video/Kconfig newtree/drivers/video/Kconfig
--- oldtree/drivers/video/Kconfig	2006-02-19 11:41:04.469663608 +0000
+++ newtree/drivers/video/Kconfig	2006-02-21 15:58:36.508596408 +0000
@@ -101,7 +101,7 @@
 
 config FB_CIRRUS
 	tristate "Cirrus Logic support"
-	depends on FB && (ZORRO || PCI)
+	depends on FB && (ZORRO || PCI) && (BROKEN || !SPARC32)
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
@@ -608,7 +608,7 @@
 
 config FB_NVIDIA
 	tristate "nVidia Framebuffer Support"
-	depends on FB && PCI
+	depends on FB && PCI && (BROKEN || !SPARC32)
 	select I2C_ALGOBIT if FB_NVIDIA_I2C
 	select I2C if FB_NVIDIA_I2C
 	select FB_MODE_HELPERS
@@ -638,7 +638,7 @@
 
 config FB_RIVA
 	tristate "nVidia Riva support"
-	depends on FB && PCI
+	depends on FB && PCI && (BROKEN || !SPARC32)
 	select I2C_ALGOBIT if FB_RIVA_I2C
 	select I2C if FB_RIVA_I2C
 	select FB_MODE_HELPERS
@@ -1074,7 +1074,7 @@
 
 config FB_NEOMAGIC
 	tristate "NeoMagic display support"
-	depends on FB && PCI
+	depends on FB && PCI && (BROKEN || !SPARC32)
 	select FB_MODE_HELPERS
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
diff -urN oldtree/drivers/video/aty/atyfb_base.c newtree/drivers/video/aty/atyfb_base.c
--- oldtree/drivers/video/aty/atyfb_base.c	2006-02-19 11:41:04.479662088 +0000
+++ newtree/drivers/video/aty/atyfb_base.c	2006-02-21 15:58:36.497598080 +0000
@@ -78,7 +78,7 @@
 #include <asm/prom.h>
 #include "../macmodes.h"
 #endif
-#ifdef __sparc__
+#ifdef __sparc_v9__
 #include <asm/pbm.h>
 #include <asm/fbio.h>
 #endif
@@ -242,7 +242,7 @@
 extern void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
 extern void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
 extern void atyfb_imageblit(struct fb_info *info, const struct fb_image *image);
-#ifdef __sparc__
+#ifdef __sparc_v9__
 static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma);
 #endif
 static int atyfb_sync(struct fb_info *info);
@@ -300,7 +300,7 @@
 	.fb_fillrect	= atyfb_fillrect,
 	.fb_copyarea	= atyfb_copyarea,
 	.fb_imageblit	= atyfb_imageblit,
-#ifdef __sparc__
+#ifdef __sparc_v9__
 	.fb_mmap	= atyfb_mmap,
 #endif
 	.fb_sync	= atyfb_sync,
@@ -1519,7 +1519,7 @@
 
 	if (user) {
 		par->open++;
-#ifdef __sparc__
+#ifdef __sparc_v9__
 		par->mmaped = 0;
 #endif
 	}
@@ -1611,7 +1611,7 @@
 		mdelay(1);
 		wait_for_idle(par);
 		if (!par->open) {
-#ifdef __sparc__
+#ifdef __sparc_v9__
 			int was_mmaped = par->mmaped;
 
 			par->mmaped = 0;
@@ -1741,12 +1741,12 @@
 static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
 {
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
-#ifdef __sparc__
+#ifdef __sparc_v9__
 	struct fbtype fbtyp;
 #endif
 
 	switch (cmd) {
-#ifdef __sparc__
+#ifdef __sparc_v9__
 	case FBIOGTYPE:
 		fbtyp.fb_type = FBTYPE_PCI_GENERIC;
 		fbtyp.fb_width = par->crtc.vxres;
@@ -1757,7 +1757,7 @@
 		if (copy_to_user((struct fbtype __user *) arg, &fbtyp, sizeof(fbtyp)))
 			return -EFAULT;
 		break;
-#endif /* __sparc__ */
+#endif /* __sparc_v9__ */
 
 	case FBIO_WAITFORVSYNC:
 		{
@@ -1842,7 +1842,7 @@
 	return 0;
 }
 
-#ifdef __sparc__
+#ifdef __sparc_v9__
 static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
@@ -1970,7 +1970,7 @@
 		}
 	}
 }
-#endif /* __sparc__ */
+#endif /* __sparc_v9__ */
 
 
 
@@ -2588,7 +2588,7 @@
 		goto aty_init_exit;
 	}
 
-#ifdef __sparc__
+#ifdef __sparc_v9__
 	atyfb_save_palette(par, 0);
 #endif
 
@@ -2814,7 +2814,7 @@
 
 #ifdef CONFIG_PCI
 
-#ifdef __sparc__
+#ifdef __sparc_v9__
 
 extern void (*prom_palette) (int);
 
@@ -3035,7 +3035,7 @@
 	return 0;
 }
 
-#else /* __sparc__ */
+#else /* __sparc_v9__ */
 
 #ifdef __i386__
 #ifdef CONFIG_FB_ATY_GENERIC_LCD
@@ -3387,7 +3387,7 @@
 	return ret;
 }
 
-#endif /* !__sparc__ */
+#endif /* !__sparc_v9__ */
 
 static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
@@ -3439,7 +3439,7 @@
 	par->irq = pdev->irq;
 
 	/* Setup "info" structure */
-#ifdef __sparc__
+#ifdef __sparc_v9__
 	rc = atyfb_setup_sparc(pdev, info, addr);
 #else
 	rc = atyfb_setup_generic(pdev, info, addr);
@@ -3453,7 +3453,7 @@
 	if (aty_init(info, "PCI"))
 		goto err_release_io;
 
-#ifdef __sparc__
+#ifdef __sparc_v9__
 	if (!prom_palette)
 		prom_palette = atyfb_palette;
 
@@ -3470,12 +3470,12 @@
 	par->mmap_map[1].size = PAGE_SIZE;
 	par->mmap_map[1].prot_mask = _PAGE_CACHE;
 	par->mmap_map[1].prot_flag = _PAGE_E;
-#endif /* __sparc__ */
+#endif /* __sparc_v9__ */
 
 	return 0;
 
 err_release_io:
-#ifdef __sparc__
+#ifdef __sparc_v9__
 	kfree(par->mmap_map);
 #else
 	if (par->ati_regbase)
@@ -3580,7 +3580,7 @@
 	    par->mtrr_aper = -1;
 	}
 #endif
-#ifndef __sparc__
+#ifndef __sparc_v9__
 	if (par->ati_regbase)
 		iounmap(par->ati_regbase);
 	if (info->screen_base)
@@ -3590,7 +3590,7 @@
 		iounmap(info->sprite.addr);
 #endif
 #endif
-#ifdef __sparc__
+#ifdef __sparc_v9__
 	kfree(par->mmap_map);
 #endif
 	if (par->aux_start)
@@ -3719,7 +3719,9 @@
     atyfb_setup(option);
 #endif
 
+#ifdef CONFIG_PCI
     pci_register_driver(&atyfb_driver);
+#endif
 #ifdef CONFIG_ATARI
     atyfb_atari_probe();
 #endif
@@ -3728,7 +3730,9 @@
 
 static void __exit atyfb_exit(void)
 {
+#ifdef CONFIG_PCI
 	pci_unregister_driver(&atyfb_driver);
+#endif
 }
 
 module_init(atyfb_init);
diff -urN oldtree/drivers/video/epson1355fb.c newtree/drivers/video/epson1355fb.c
--- oldtree/drivers/video/epson1355fb.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/video/epson1355fb.c	2006-02-21 15:58:12.165297152 +0000
@@ -607,6 +607,7 @@
 
 static void epson1355fb_platform_release(struct device *device)
 {
+	dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n");
 }
 
 static int epson1355fb_remove(struct platform_device *dev)
diff -urN oldtree/drivers/video/sa1100fb.c newtree/drivers/video/sa1100fb.c
--- oldtree/drivers/video/sa1100fb.c	2006-02-19 11:41:04.863603720 +0000
+++ newtree/drivers/video/sa1100fb.c	2006-02-21 15:58:12.536240760 +0000
@@ -1457,7 +1457,7 @@
 	int ret, irq;
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq <= 0)
+	if (irq < 0)
 		return -EINVAL;
 
 	if (!request_mem_region(0xb0100000, 0x10000, "LCD"))
diff -urN oldtree/drivers/video/vfb.c newtree/drivers/video/vfb.c
--- oldtree/drivers/video/vfb.c	2006-02-19 11:41:04.881600984 +0000
+++ newtree/drivers/video/vfb.c	2006-02-21 15:58:12.174295784 +0000
@@ -401,6 +401,7 @@
 static void vfb_platform_release(struct device *device)
 {
 	// This is called when the reference count goes to zero.
+	dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n");
 }
 
 static int __init vfb_probe(struct platform_device *dev)
diff -urN oldtree/drivers/w1/Kconfig newtree/drivers/w1/Kconfig
--- oldtree/drivers/w1/Kconfig	2006-02-19 11:41:04.883600680 +0000
+++ newtree/drivers/w1/Kconfig	2006-02-21 15:58:14.567931896 +0000
@@ -11,63 +11,7 @@
 	  This W1 support can also be built as a module.  If so, the module
 	  will be called wire.ko.
 
-config W1_MATROX
-	tristate "Matrox G400 transport layer for 1-wire"
-	depends on W1 && PCI
-	help
-	  Say Y here if you want to communicate with your 1-wire devices
-	  using Matrox's G400 GPIO pins.
-
-	  This support is also available as a module.  If so, the module
-	  will be called matrox_w1.ko.
-
-config W1_DS9490
-	tristate "DS9490R transport layer driver"
-	depends on W1 && USB
-	help
-	  Say Y here if you want to have a driver for DS9490R UWB <-> W1 bridge.
-
-	  This support is also available as a module.  If so, the module
-	  will be called ds9490r.ko.
-
-config W1_DS9490_BRIDGE
-	tristate "DS9490R USB <-> W1 transport layer for 1-wire"
-	depends on W1_DS9490
-	help
-	  Say Y here if you want to communicate with your 1-wire devices
-	  using DS9490R USB bridge.
-
-	  This support is also available as a module.  If so, the module
-	  will be called ds_w1_bridge.ko.
-
-config W1_THERM
-	tristate "Thermal family implementation"
-	depends on W1
-	help
-	  Say Y here if you want to connect 1-wire thermal sensors to you
-	  wire.
-
-config W1_SMEM
-	tristate "Simple 64bit memory family implementation"
-	depends on W1
-	help
-	  Say Y here if you want to connect 1-wire
-	  simple 64bit memory rom(ds2401/ds2411/ds1990*) to you wire.
-
-config W1_DS2433
-	tristate "4kb EEPROM family support (DS2433)"
-	depends on W1
-	help
-	  Say Y here if you want to use a 1-wire
-	  4kb EEPROM family device (DS2433).
-
-config W1_DS2433_CRC
-	bool "Protect DS2433 data with a CRC16"
-	depends on W1_DS2433
-	select CRC16
-	help
-	  Say Y here to protect DS2433 data with a CRC16.
-	  Each block has 30 bytes of data and a two byte CRC16.
-	  Full block writes are only allowed if the CRC is valid.
+source drivers/w1/masters/Kconfig
+source drivers/w1/slaves/Kconfig
 
 endmenu
diff -urN oldtree/drivers/w1/Makefile newtree/drivers/w1/Makefile
--- oldtree/drivers/w1/Makefile	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/w1/Makefile	2006-02-21 15:58:14.568931744 +0000
@@ -13,13 +13,5 @@
 obj-$(CONFIG_W1)	+= wire.o
 wire-objs		:= w1.o w1_int.o w1_family.o w1_netlink.o w1_io.o
 
-obj-$(CONFIG_W1_MATROX)		+= matrox_w1.o
-obj-$(CONFIG_W1_THERM)		+= w1_therm.o
-obj-$(CONFIG_W1_SMEM)		+= w1_smem.o
+obj-y			+= masters/ slaves/
 
-obj-$(CONFIG_W1_DS9490)		+= ds9490r.o
-ds9490r-objs    := dscore.o
-
-obj-$(CONFIG_W1_DS9490_BRIDGE)	+= ds_w1_bridge.o
-
-obj-$(CONFIG_W1_DS2433)		+= w1_ds2433.o
diff -urN oldtree/drivers/w1/ds_w1_bridge.c newtree/drivers/w1/ds_w1_bridge.c
--- oldtree/drivers/w1/ds_w1_bridge.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/w1/ds_w1_bridge.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,174 +0,0 @@
-/*
- *	ds_w1_bridge.c
- *
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
- *
- * 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/module.h>
-#include <linux/types.h>
-
-#include "../w1/w1.h"
-#include "../w1/w1_int.h"
-#include "dscore.h"
-
-static struct ds_device *ds_dev;
-static struct w1_bus_master *ds_bus_master;
-
-static u8 ds9490r_touch_bit(unsigned long data, u8 bit)
-{
-	u8 ret;
-	struct ds_device *dev = (struct ds_device *)data;
-
-	if (ds_touch_bit(dev, bit, &ret))
-		return 0;
-
-	return ret;
-}
-
-static void ds9490r_write_bit(unsigned long data, u8 bit)
-{
-	struct ds_device *dev = (struct ds_device *)data;
-
-	ds_write_bit(dev, bit);
-}
-
-static void ds9490r_write_byte(unsigned long data, u8 byte)
-{
-	struct ds_device *dev = (struct ds_device *)data;
-
-	ds_write_byte(dev, byte);
-}
-
-static u8 ds9490r_read_bit(unsigned long data)
-{
-	struct ds_device *dev = (struct ds_device *)data;
-	int err;
-	u8 bit = 0;
-
-	err = ds_touch_bit(dev, 1, &bit);
-	if (err)
-		return 0;
-	//err = ds_read_bit(dev, &bit);
-	//if (err)
-	//	return 0;
-
-	return bit & 1;
-}
-
-static u8 ds9490r_read_byte(unsigned long data)
-{
-	struct ds_device *dev = (struct ds_device *)data;
-	int err;
-	u8 byte = 0;
-
-	err = ds_read_byte(dev, &byte);
-	if (err)
-		return 0;
-
-	return byte;
-}
-
-static void ds9490r_write_block(unsigned long data, const u8 *buf, int len)
-{
-	struct ds_device *dev = (struct ds_device *)data;
-
-	ds_write_block(dev, (u8 *)buf, len);
-}
-
-static u8 ds9490r_read_block(unsigned long data, u8 *buf, int len)
-{
-	struct ds_device *dev = (struct ds_device *)data;
-	int err;
-
-	err = ds_read_block(dev, buf, len);
-	if (err < 0)
-		return 0;
-
-	return len;
-}
-
-static u8 ds9490r_reset(unsigned long data)
-{
-	struct ds_device *dev = (struct ds_device *)data;
-	struct ds_status st;
-	int err;
-
-	memset(&st, 0, sizeof(st));
-
-	err = ds_reset(dev, &st);
-	if (err)
-		return 1;
-
-	return 0;
-}
-
-static int __devinit ds_w1_init(void)
-{
-	int err;
-
-	ds_bus_master = kmalloc(sizeof(*ds_bus_master), GFP_KERNEL);
-	if (!ds_bus_master) {
-		printk(KERN_ERR "Failed to allocate DS9490R USB<->W1 bus_master structure.\n");
-		return -ENOMEM;
-	}
-
-	ds_dev = ds_get_device();
-	if (!ds_dev) {
-		printk(KERN_ERR "DS9490R is not registered.\n");
-		err =  -ENODEV;
-		goto err_out_free_bus_master;
-	}
-
-	memset(ds_bus_master, 0, sizeof(*ds_bus_master));
-
-	ds_bus_master->data		= (unsigned long)ds_dev;
-	ds_bus_master->touch_bit	= &ds9490r_touch_bit;
-	ds_bus_master->read_bit		= &ds9490r_read_bit;
-	ds_bus_master->write_bit	= &ds9490r_write_bit;
-	ds_bus_master->read_byte	= &ds9490r_read_byte;
-	ds_bus_master->write_byte	= &ds9490r_write_byte;
-	ds_bus_master->read_block	= &ds9490r_read_block;
-	ds_bus_master->write_block	= &ds9490r_write_block;
-	ds_bus_master->reset_bus	= &ds9490r_reset;
-
-	err = w1_add_master_device(ds_bus_master);
-	if (err)
-		goto err_out_put_device;
-
-	return 0;
-
-err_out_put_device:
-	ds_put_device(ds_dev);
-err_out_free_bus_master:
-	kfree(ds_bus_master);
-
-	return err;
-}
-
-static void __devexit ds_w1_fini(void)
-{
-	w1_remove_master_device(ds_bus_master);
-	ds_put_device(ds_dev);
-	kfree(ds_bus_master);
-}
-
-module_init(ds_w1_init);
-module_exit(ds_w1_fini);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
diff -urN oldtree/drivers/w1/dscore.c newtree/drivers/w1/dscore.c
--- oldtree/drivers/w1/dscore.c	2006-02-19 11:41:04.884600528 +0000
+++ newtree/drivers/w1/dscore.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,795 +0,0 @@
-/*
- *	dscore.c
- *
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
- *
- * 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/module.h>
-#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
-#include <linux/usb.h>
-
-#include "dscore.h"
-
-static struct usb_device_id ds_id_table [] = {
-	{ USB_DEVICE(0x04fa, 0x2490) },
-	{ },
-};
-MODULE_DEVICE_TABLE(usb, ds_id_table);
-
-static int ds_probe(struct usb_interface *, const struct usb_device_id *);
-static void ds_disconnect(struct usb_interface *);
-
-int ds_touch_bit(struct ds_device *, u8, u8 *);
-int ds_read_byte(struct ds_device *, u8 *);
-int ds_read_bit(struct ds_device *, u8 *);
-int ds_write_byte(struct ds_device *, u8);
-int ds_write_bit(struct ds_device *, u8);
-static int ds_start_pulse(struct ds_device *, int);
-int ds_reset(struct ds_device *, struct ds_status *);
-struct ds_device * ds_get_device(void);
-void ds_put_device(struct ds_device *);
-
-static inline void ds_dump_status(unsigned char *, unsigned char *, int);
-static int ds_send_control(struct ds_device *, u16, u16);
-static int ds_send_control_mode(struct ds_device *, u16, u16);
-static int ds_send_control_cmd(struct ds_device *, u16, u16);
-
-
-static struct usb_driver ds_driver = {
-	.name =		"DS9490R",
-	.probe =	ds_probe,
-	.disconnect =	ds_disconnect,
-	.id_table =	ds_id_table,
-};
-
-static struct ds_device *ds_dev;
-
-struct ds_device * ds_get_device(void)
-{
-	if (ds_dev)
-		atomic_inc(&ds_dev->refcnt);
-	return ds_dev;
-}
-
-void ds_put_device(struct ds_device *dev)
-{
-	atomic_dec(&dev->refcnt);
-}
-
-static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index)
-{
-	int err;
-
-	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
-			CONTROL_CMD, 0x40, value, index, NULL, 0, 1000);
-	if (err < 0) {
-		printk(KERN_ERR "Failed to send command control message %x.%x: err=%d.\n",
-				value, index, err);
-		return err;
-	}
-
-	return err;
-}
-
-static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
-{
-	int err;
-
-	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
-			MODE_CMD, 0x40, value, index, NULL, 0, 1000);
-	if (err < 0) {
-		printk(KERN_ERR "Failed to send mode control message %x.%x: err=%d.\n",
-				value, index, err);
-		return err;
-	}
-
-	return err;
-}
-
-static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
-{
-	int err;
-
-	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
-			COMM_CMD, 0x40, value, index, NULL, 0, 1000);
-	if (err < 0) {
-		printk(KERN_ERR "Failed to send control message %x.%x: err=%d.\n",
-				value, index, err);
-		return err;
-	}
-
-	return err;
-}
-
-static inline void ds_dump_status(unsigned char *buf, unsigned char *str, int off)
-{
-	printk("%45s: %8x\n", str, buf[off]);
-}
-
-static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st,
-				 unsigned char *buf, int size)
-{
-	int count, err;
-
-	memset(st, 0, sizeof(st));
-
-	count = 0;
-	err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_STATUS]), buf, size, &count, 100);
-	if (err < 0) {
-		printk(KERN_ERR "Failed to read 1-wire data from 0x%x: err=%d.\n", dev->ep[EP_STATUS], err);
-		return err;
-	}
-
-	if (count >= sizeof(*st))
-		memcpy(st, buf, sizeof(*st));
-
-	return count;
-}
-
-static int ds_recv_status(struct ds_device *dev, struct ds_status *st)
-{
-	unsigned char buf[64];
-	int count, err = 0, i;
-
-	memcpy(st, buf, sizeof(*st));
-
-	count = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
-	if (count < 0)
-		return err;
-
-	printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], count);
-	for (i=0; i<count; ++i)
-		printk("%02x ", buf[i]);
-	printk("\n");
-
-	if (count >= 16) {
-		ds_dump_status(buf, "enable flag", 0);
-		ds_dump_status(buf, "1-wire speed", 1);
-		ds_dump_status(buf, "strong pullup duration", 2);
-		ds_dump_status(buf, "programming pulse duration", 3);
-		ds_dump_status(buf, "pulldown slew rate control", 4);
-		ds_dump_status(buf, "write-1 low time", 5);
-		ds_dump_status(buf, "data sample offset/write-0 recovery time", 6);
-		ds_dump_status(buf, "reserved (test register)", 7);
-		ds_dump_status(buf, "device status flags", 8);
-		ds_dump_status(buf, "communication command byte 1", 9);
-		ds_dump_status(buf, "communication command byte 2", 10);
-		ds_dump_status(buf, "communication command buffer status", 11);
-		ds_dump_status(buf, "1-wire data output buffer status", 12);
-		ds_dump_status(buf, "1-wire data input buffer status", 13);
-		ds_dump_status(buf, "reserved", 14);
-		ds_dump_status(buf, "reserved", 15);
-	}
-
-	memcpy(st, buf, sizeof(*st));
-
-	if (st->status & ST_EPOF) {
-		printk(KERN_INFO "Resetting device after ST_EPOF.\n");
-		err = ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
-		if (err)
-			return err;
-		count = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
-		if (count < 0)
-			return err;
-	}
-#if 0
-	if (st->status & ST_IDLE) {
-		printk(KERN_INFO "Resetting pulse after ST_IDLE.\n");
-		err = ds_start_pulse(dev, PULLUP_PULSE_DURATION);
-		if (err)
-			return err;
-	}
-#endif
-
-	return err;
-}
-
-static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
-{
-	int count, err;
-	struct ds_status st;
-
-	count = 0;
-	err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]),
-				buf, size, &count, 1000);
-	if (err < 0) {
-		printk(KERN_INFO "Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]);
-		usb_clear_halt(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]));
-		ds_recv_status(dev, &st);
-		return err;
-	}
-
-#if 0
-	{
-		int i;
-
-		printk("%s: count=%d: ", __func__, count);
-		for (i=0; i<count; ++i)
-			printk("%02x ", buf[i]);
-		printk("\n");
-	}
-#endif
-	return count;
-}
-
-static int ds_send_data(struct ds_device *dev, unsigned char *buf, int len)
-{
-	int count, err;
-
-	count = 0;
-	err = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, dev->ep[EP_DATA_OUT]), buf, len, &count, 1000);
-	if (err < 0) {
-		printk(KERN_ERR "Failed to read 1-wire data from 0x02: err=%d.\n", err);
-		return err;
-	}
-
-	return err;
-}
-
-#if 0
-
-int ds_stop_pulse(struct ds_device *dev, int limit)
-{
-	struct ds_status st;
-	int count = 0, err = 0;
-	u8 buf[0x20];
-
-	do {
-		err = ds_send_control(dev, CTL_HALT_EXE_IDLE, 0);
-		if (err)
-			break;
-		err = ds_send_control(dev, CTL_RESUME_EXE, 0);
-		if (err)
-			break;
-		err = ds_recv_status_nodump(dev, &st, buf, sizeof(buf));
-		if (err)
-			break;
-
-		if ((st.status & ST_SPUA) == 0) {
-			err = ds_send_control_mode(dev, MOD_PULSE_EN, 0);
-			if (err)
-				break;
-		}
-	} while(++count < limit);
-
-	return err;
-}
-
-int ds_detect(struct ds_device *dev, struct ds_status *st)
-{
-	int err;
-
-	err = ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
-	if (err)
-		return err;
-
-	err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, 0);
-	if (err)
-		return err;
-
-	err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM | COMM_TYPE, 0x40);
-	if (err)
-		return err;
-
-	err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_PROG);
-	if (err)
-		return err;
-
-	err = ds_recv_status(dev, st);
-
-	return err;
-}
-
-#endif  /*  0  */
-
-static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
-{
-	u8 buf[0x20];
-	int err, count = 0;
-
-	do {
-		err = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
-#if 0
-		if (err >= 0) {
-			int i;
-			printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], err);
-			for (i=0; i<err; ++i)
-				printk("%02x ", buf[i]);
-			printk("\n");
-		}
-#endif
-	} while(!(buf[0x08] & 0x20) && !(err < 0) && ++count < 100);
-
-
-	if (((err > 16) && (buf[0x10] & 0x01)) || count >= 100 || err < 0) {
-		ds_recv_status(dev, st);
-		return -1;
-	} else
-		return 0;
-}
-
-int ds_reset(struct ds_device *dev, struct ds_status *st)
-{
-	int err;
-
-	//err = ds_send_control(dev, COMM_1_WIRE_RESET | COMM_F | COMM_IM | COMM_SE, SPEED_FLEXIBLE);
-	err = ds_send_control(dev, 0x43, SPEED_NORMAL);
-	if (err)
-		return err;
-
-	ds_wait_status(dev, st);
-#if 0
-	if (st->command_buffer_status) {
-		printk(KERN_INFO "Short circuit.\n");
-		return -EIO;
-	}
-#endif
-	
-	return 0;
-}
-
-#if 0
-int ds_set_speed(struct ds_device *dev, int speed)
-{
-	int err;
-	
-	if (speed != SPEED_NORMAL && speed != SPEED_FLEXIBLE && speed != SPEED_OVERDRIVE)
-		return -EINVAL;
-
-	if (speed != SPEED_OVERDRIVE)
-		speed = SPEED_FLEXIBLE;
-
-	speed &= 0xff;
-
-	err = ds_send_control_mode(dev, MOD_1WIRE_SPEED, speed);
-	if (err)
-		return err;
-
-	return err;
-}
-#endif  /*  0  */
-
-static int ds_start_pulse(struct ds_device *dev, int delay)
-{
-	int err;
-	u8 del = 1 + (u8)(delay >> 4);
-	struct ds_status st;
-
-#if 0
-	err = ds_stop_pulse(dev, 10);
-	if (err)
-		return err;
-
-	err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE);
-	if (err)
-		return err;
-#endif
-	err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, del);
-	if (err)
-		return err;
-
-	err = ds_send_control(dev, COMM_PULSE | COMM_IM | COMM_F, 0);
-	if (err)
-		return err;
-
-	mdelay(delay);
-
-	ds_wait_status(dev, &st);
-
-	return err;
-}
-
-int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit)
-{
-	int err, count;
-	struct ds_status st;
-	u16 value = (COMM_BIT_IO | COMM_IM) | ((bit) ? COMM_D : 0);
-	u16 cmd;
-
-	err = ds_send_control(dev, value, 0);
-	if (err)
-		return err;
-
-	count = 0;
-	do {
-		err = ds_wait_status(dev, &st);
-		if (err)
-			return err;
-
-		cmd = st.command0 | (st.command1 << 8);
-	} while (cmd != value && ++count < 10);
-
-	if (err < 0 || count >= 10) {
-		printk(KERN_ERR "Failed to obtain status.\n");
-		return -EINVAL;
-	}
-
-	err = ds_recv_data(dev, tbit, sizeof(*tbit));
-	if (err < 0)
-		return err;
-
-	return 0;
-}
-
-int ds_write_bit(struct ds_device *dev, u8 bit)
-{
-	int err;
-	struct ds_status st;
-
-	err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | (bit) ? COMM_D : 0, 0);
-	if (err)
-		return err;
-
-	ds_wait_status(dev, &st);
-
-	return 0;
-}
-
-int ds_write_byte(struct ds_device *dev, u8 byte)
-{
-	int err;
-	struct ds_status st;
-	u8 rbyte;
-
-	err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | COMM_SPU, byte);
-	if (err)
-		return err;
-
-	err = ds_wait_status(dev, &st);
-	if (err)
-		return err;
-
-	err = ds_recv_data(dev, &rbyte, sizeof(rbyte));
-	if (err < 0)
-		return err;
-
-	ds_start_pulse(dev, PULLUP_PULSE_DURATION);
-
-	return !(byte == rbyte);
-}
-
-int ds_read_bit(struct ds_device *dev, u8 *bit)
-{
-	int err;
-
-	err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE);
-	if (err)
-		return err;
-
-	err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | COMM_SPU | COMM_D, 0);
-	if (err)
-		return err;
-
-	err = ds_recv_data(dev, bit, sizeof(*bit));
-	if (err < 0)
-		return err;
-
-	return 0;
-}
-
-int ds_read_byte(struct ds_device *dev, u8 *byte)
-{
-	int err;
-	struct ds_status st;
-
-	err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM , 0xff);
-	if (err)
-		return err;
-
-	ds_wait_status(dev, &st);
-
-	err = ds_recv_data(dev, byte, sizeof(*byte));
-	if (err < 0)
-		return err;
-
-	return 0;
-}
-
-int ds_read_block(struct ds_device *dev, u8 *buf, int len)
-{
-	struct ds_status st;
-	int err;
-
-	if (len > 64*1024)
-		return -E2BIG;
-
-	memset(buf, 0xFF, len);
-
-	err = ds_send_data(dev, buf, len);
-	if (err < 0)
-		return err;
-
-	err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
-	if (err)
-		return err;
-
-	ds_wait_status(dev, &st);
-
-	memset(buf, 0x00, len);
-	err = ds_recv_data(dev, buf, len);
-
-	return err;
-}
-
-int ds_write_block(struct ds_device *dev, u8 *buf, int len)
-{
-	int err;
-	struct ds_status st;
-
-	err = ds_send_data(dev, buf, len);
-	if (err < 0)
-		return err;
-
-	ds_wait_status(dev, &st);
-
-	err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
-	if (err)
-		return err;
-
-	ds_wait_status(dev, &st);
-
-	err = ds_recv_data(dev, buf, len);
-	if (err < 0)
-		return err;
-
-	ds_start_pulse(dev, PULLUP_PULSE_DURATION);
-
-	return !(err == len);
-}
-
-#if 0
-
-int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search)
-{
-	int err;
-	u16 value, index;
-	struct ds_status st;
-
-	memset(buf, 0, sizeof(buf));
-
-	err = ds_send_data(ds_dev, (unsigned char *)&init, 8);
-	if (err)
-		return err;
-
-	ds_wait_status(ds_dev, &st);
-
-	value = COMM_SEARCH_ACCESS | COMM_IM | COMM_SM | COMM_F | COMM_RTS;
-	index = (conditional_search ? 0xEC : 0xF0) | (id_number << 8);
-	err = ds_send_control(ds_dev, value, index);
-	if (err)
-		return err;
-
-	ds_wait_status(ds_dev, &st);
-
-	err = ds_recv_data(ds_dev, (unsigned char *)buf, 8*id_number);
-	if (err < 0)
-		return err;
-
-	return err/8;
-}
-
-int ds_match_access(struct ds_device *dev, u64 init)
-{
-	int err;
-	struct ds_status st;
-
-	err = ds_send_data(dev, (unsigned char *)&init, sizeof(init));
-	if (err)
-		return err;
-
-	ds_wait_status(dev, &st);
-
-	err = ds_send_control(dev, COMM_MATCH_ACCESS | COMM_IM | COMM_RST, 0x0055);
-	if (err)
-		return err;
-
-	ds_wait_status(dev, &st);
-
-	return 0;
-}
-
-int ds_set_path(struct ds_device *dev, u64 init)
-{
-	int err;
-	struct ds_status st;
-	u8 buf[9];
-
-	memcpy(buf, &init, 8);
-	buf[8] = BRANCH_MAIN;
-
-	err = ds_send_data(dev, buf, sizeof(buf));
-	if (err)
-		return err;
-
-	ds_wait_status(dev, &st);
-
-	err = ds_send_control(dev, COMM_SET_PATH | COMM_IM | COMM_RST, 0);
-	if (err)
-		return err;
-
-	ds_wait_status(dev, &st);
-
-	return 0;
-}
-
-#endif  /*  0  */
-
-static int ds_probe(struct usb_interface *intf,
-		    const struct usb_device_id *udev_id)
-{
-	struct usb_device *udev = interface_to_usbdev(intf);
-	struct usb_endpoint_descriptor *endpoint;
-	struct usb_host_interface *iface_desc;
-	int i, err;
-
-	ds_dev = kmalloc(sizeof(struct ds_device), GFP_KERNEL);
-	if (!ds_dev) {
-		printk(KERN_INFO "Failed to allocate new DS9490R structure.\n");
-		return -ENOMEM;
-	}
-
-	ds_dev->udev = usb_get_dev(udev);
-	usb_set_intfdata(intf, ds_dev);
-
-	err = usb_set_interface(ds_dev->udev, intf->altsetting[0].desc.bInterfaceNumber, 3);
-	if (err) {
-		printk(KERN_ERR "Failed to set alternative setting 3 for %d interface: err=%d.\n",
-				intf->altsetting[0].desc.bInterfaceNumber, err);
-		return err;
-	}
-
-	err = usb_reset_configuration(ds_dev->udev);
-	if (err) {
-		printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err);
-		return err;
-	}
-
-	iface_desc = &intf->altsetting[0];
-	if (iface_desc->desc.bNumEndpoints != NUM_EP-1) {
-		printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints);
-		return -ENODEV;
-	}
-
-	atomic_set(&ds_dev->refcnt, 0);
-	memset(ds_dev->ep, 0, sizeof(ds_dev->ep));
-
-	/*
-	 * This loop doesn'd show control 0 endpoint,
-	 * so we will fill only 1-3 endpoints entry.
-	 */
-	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
-		endpoint = &iface_desc->endpoint[i].desc;
-
-		ds_dev->ep[i+1] = endpoint->bEndpointAddress;
-
-		printk("%d: addr=%x, size=%d, dir=%s, type=%x\n",
-			i, endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize),
-			(endpoint->bEndpointAddress & USB_DIR_IN)?"IN":"OUT",
-			endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
-	}
-
-#if 0
-	{
-		int err, i;
-		u64 buf[3];
-		u64 init=0xb30000002078ee81ull;
-		struct ds_status st;
-
-		ds_reset(ds_dev, &st);
-		err = ds_search(ds_dev, init, buf, 3, 0);
-		if (err < 0)
-			return err;
-		for (i=0; i<err; ++i)
-			printk("%d: %llx\n", i, buf[i]);
-
-		printk("Resetting...\n");
-		ds_reset(ds_dev, &st);
-		printk("Setting path for %llx.\n", init);
-		err = ds_set_path(ds_dev, init);
-		if (err)
-			return err;
-		printk("Calling MATCH_ACCESS.\n");
-		err = ds_match_access(ds_dev, init);
-		if (err)
-			return err;
-
-		printk("Searching the bus...\n");
-		err = ds_search(ds_dev, init, buf, 3, 0);
-
-		printk("ds_search() returned %d\n", err);
-
-		if (err < 0)
-			return err;
-		for (i=0; i<err; ++i)
-			printk("%d: %llx\n", i, buf[i]);
-
-		return 0;
-	}
-#endif
-
-	return 0;
-}
-
-static void ds_disconnect(struct usb_interface *intf)
-{
-	struct ds_device *dev;
-
-	dev = usb_get_intfdata(intf);
-	usb_set_intfdata(intf, NULL);
-
-	while (atomic_read(&dev->refcnt)) {
-		printk(KERN_INFO "Waiting for DS to become free: refcnt=%d.\n",
-				atomic_read(&dev->refcnt));
-
-		if (msleep_interruptible(1000))
-			flush_signals(current);
-	}
-
-	usb_put_dev(dev->udev);
-	kfree(dev);
-	ds_dev = NULL;
-}
-
-static int ds_init(void)
-{
-	int err;
-
-	err = usb_register(&ds_driver);
-	if (err) {
-		printk(KERN_INFO "Failed to register DS9490R USB device: err=%d.\n", err);
-		return err;
-	}
-
-	return 0;
-}
-
-static void ds_fini(void)
-{
-	usb_deregister(&ds_driver);
-}
-
-module_init(ds_init);
-module_exit(ds_fini);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
-
-EXPORT_SYMBOL(ds_touch_bit);
-EXPORT_SYMBOL(ds_read_byte);
-EXPORT_SYMBOL(ds_read_bit);
-EXPORT_SYMBOL(ds_read_block);
-EXPORT_SYMBOL(ds_write_byte);
-EXPORT_SYMBOL(ds_write_bit);
-EXPORT_SYMBOL(ds_write_block);
-EXPORT_SYMBOL(ds_reset);
-EXPORT_SYMBOL(ds_get_device);
-EXPORT_SYMBOL(ds_put_device);
-
-/*
- * This functions can be used for EEPROM programming,
- * when driver will be included into mainline this will
- * require uncommenting.
- */
-#if 0
-EXPORT_SYMBOL(ds_start_pulse);
-EXPORT_SYMBOL(ds_set_speed);
-EXPORT_SYMBOL(ds_detect);
-EXPORT_SYMBOL(ds_stop_pulse);
-EXPORT_SYMBOL(ds_search);
-#endif
diff -urN oldtree/drivers/w1/dscore.h newtree/drivers/w1/dscore.h
--- oldtree/drivers/w1/dscore.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/w1/dscore.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,166 +0,0 @@
-/*
- *	dscore.h
- *
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
- *
- * 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 __DSCORE_H
-#define __DSCORE_H
-
-#include <linux/usb.h>
-#include <asm/atomic.h>
-
-/* COMMAND TYPE CODES */
-#define CONTROL_CMD			0x00
-#define COMM_CMD			0x01
-#define MODE_CMD			0x02
-
-/* CONTROL COMMAND CODES */
-#define CTL_RESET_DEVICE		0x0000
-#define CTL_START_EXE			0x0001
-#define CTL_RESUME_EXE			0x0002
-#define CTL_HALT_EXE_IDLE		0x0003
-#define CTL_HALT_EXE_DONE		0x0004
-#define CTL_FLUSH_COMM_CMDS		0x0007
-#define CTL_FLUSH_RCV_BUFFER		0x0008
-#define CTL_FLUSH_XMT_BUFFER		0x0009
-#define CTL_GET_COMM_CMDS		0x000A
-
-/* MODE COMMAND CODES */
-#define MOD_PULSE_EN			0x0000
-#define MOD_SPEED_CHANGE_EN		0x0001
-#define MOD_1WIRE_SPEED			0x0002
-#define MOD_STRONG_PU_DURATION		0x0003
-#define MOD_PULLDOWN_SLEWRATE		0x0004
-#define MOD_PROG_PULSE_DURATION		0x0005
-#define MOD_WRITE1_LOWTIME		0x0006
-#define MOD_DSOW0_TREC			0x0007
-
-/* COMMUNICATION COMMAND CODES */
-#define COMM_ERROR_ESCAPE		0x0601
-#define COMM_SET_DURATION		0x0012
-#define COMM_BIT_IO			0x0020
-#define COMM_PULSE			0x0030
-#define COMM_1_WIRE_RESET		0x0042
-#define COMM_BYTE_IO			0x0052
-#define COMM_MATCH_ACCESS		0x0064
-#define COMM_BLOCK_IO			0x0074
-#define COMM_READ_STRAIGHT		0x0080
-#define COMM_DO_RELEASE			0x6092
-#define COMM_SET_PATH			0x00A2
-#define COMM_WRITE_SRAM_PAGE		0x00B2
-#define COMM_WRITE_EPROM		0x00C4
-#define COMM_READ_CRC_PROT_PAGE		0x00D4
-#define COMM_READ_REDIRECT_PAGE_CRC	0x21E4
-#define COMM_SEARCH_ACCESS		0x00F4
-
-/* Communication command bits */
-#define COMM_TYPE			0x0008
-#define COMM_SE				0x0008
-#define COMM_D				0x0008
-#define COMM_Z				0x0008
-#define COMM_CH				0x0008
-#define COMM_SM				0x0008
-#define COMM_R				0x0008
-#define COMM_IM				0x0001
-
-#define COMM_PS				0x4000
-#define COMM_PST			0x4000
-#define COMM_CIB			0x4000
-#define COMM_RTS			0x4000
-#define COMM_DT				0x2000
-#define COMM_SPU			0x1000
-#define COMM_F				0x0800
-#define COMM_NTP			0x0400
-#define COMM_ICP			0x0200
-#define COMM_RST			0x0100
-
-#define PULSE_PROG			0x01
-#define PULSE_SPUE			0x02
-
-#define BRANCH_MAIN			0xCC
-#define BRANCH_AUX			0x33
-
-/*
- * Duration of the strong pull-up pulse in milliseconds.
- */
-#define PULLUP_PULSE_DURATION		750
-
-/* Status flags */
-#define ST_SPUA				0x01  /* Strong Pull-up is active */
-#define ST_PRGA				0x02  /* 12V programming pulse is being generated */
-#define ST_12VP				0x04  /* external 12V programming voltage is present */
-#define ST_PMOD				0x08  /* DS2490 powered from USB and external sources */
-#define ST_HALT				0x10  /* DS2490 is currently halted */
-#define ST_IDLE				0x20  /* DS2490 is currently idle */
-#define ST_EPOF				0x80
-
-#define SPEED_NORMAL			0x00
-#define SPEED_FLEXIBLE			0x01
-#define SPEED_OVERDRIVE			0x02
-
-#define NUM_EP				4
-#define EP_CONTROL			0
-#define EP_STATUS			1
-#define EP_DATA_OUT			2
-#define EP_DATA_IN			3
-
-struct ds_device
-{
-	struct usb_device	*udev;
-	struct usb_interface	*intf;
-
-	int			ep[NUM_EP];
-
-	atomic_t		refcnt;
-};
-
-struct ds_status
-{
-	u8			enable;
-	u8			speed;
-	u8			pullup_dur;
-	u8			ppuls_dur;
-	u8			pulldown_slew;
-	u8			write1_time;
-	u8			write0_time;
-	u8			reserved0;
-	u8			status;
-	u8			command0;
-	u8			command1;
-	u8			command_buffer_status;
-	u8			data_out_buffer_status;
-	u8			data_in_buffer_status;
-	u8			reserved1;
-	u8			reserved2;
-
-};
-
-int ds_touch_bit(struct ds_device *, u8, u8 *);
-int ds_read_byte(struct ds_device *, u8 *);
-int ds_read_bit(struct ds_device *, u8 *);
-int ds_write_byte(struct ds_device *, u8);
-int ds_write_bit(struct ds_device *, u8);
-int ds_reset(struct ds_device *, struct ds_status *);
-struct ds_device * ds_get_device(void);
-void ds_put_device(struct ds_device *);
-int ds_write_block(struct ds_device *, u8 *, int);
-int ds_read_block(struct ds_device *, u8 *, int);
-
-#endif /* __DSCORE_H */
-
diff -urN oldtree/drivers/w1/masters/Kconfig newtree/drivers/w1/masters/Kconfig
--- oldtree/drivers/w1/masters/Kconfig	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/w1/masters/Kconfig	2006-02-21 15:58:14.626922928 +0000
@@ -0,0 +1,48 @@
+#
+# 1-wire bus master configuration
+#
+
+menu "1-wire Bus Masters"
+	depends on W1
+
+config W1_MASTER_MATROX
+	tristate "Matrox G400 transport layer for 1-wire"
+	depends on W1 && PCI
+	help
+	  Say Y here if you want to communicate with your 1-wire devices
+	  using Matrox's G400 GPIO pins.
+
+	  This support is also available as a module.  If so, the module
+	  will be called matrox_w1.ko.
+
+config W1_MASTER_DS9490
+	tristate "DS9490R transport layer driver"
+	depends on W1 && USB
+	help
+	  Say Y here if you want to have a driver for DS9490R UWB <-> W1 bridge.
+
+	  This support is also available as a module.  If so, the module
+	  will be called ds9490r.ko.
+
+config W1_MASTER_DS9490_BRIDGE
+	tristate "DS9490R USB <-> W1 transport layer for 1-wire"
+	depends on W1_MASTER_DS9490
+	help
+	  Say Y here if you want to communicate with your 1-wire devices
+	  using DS9490R USB bridge.
+
+	  This support is also available as a module.  If so, the module
+	  will be called ds_w1_bridge.ko.
+
+config W1_MASTER_DS2482
+	tristate "Maxim DS2482 I2C to 1-Wire bridge"
+	depends on I2C && W1 && EXPERIMENTAL
+	help
+	  If you say yes here you get support for the Maxim DS2482
+	  I2C to 1-Wire bridge.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called ds2482.
+
+endmenu
+
diff -urN oldtree/drivers/w1/masters/Makefile newtree/drivers/w1/masters/Makefile
--- oldtree/drivers/w1/masters/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/w1/masters/Makefile	2006-02-21 15:58:14.599927032 +0000
@@ -0,0 +1,13 @@
+#
+# Makefile for 1-wire bus master drivers.
+#
+
+obj-$(CONFIG_W1_MASTER_MATROX)		+= matrox_w1.o
+
+obj-$(CONFIG_W1_MASTER_DS9490)		+= ds9490r.o
+ds9490r-objs    := dscore.o
+
+obj-$(CONFIG_W1_MASTER_DS9490_BRIDGE)	+= ds_w1_bridge.o
+
+obj-$(CONFIG_W1_MASTER_DS2482)		+= ds2482.o
+
diff -urN oldtree/drivers/w1/masters/ds2482.c newtree/drivers/w1/masters/ds2482.c
--- oldtree/drivers/w1/masters/ds2482.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/w1/masters/ds2482.c	2006-02-21 15:58:14.600926880 +0000
@@ -0,0 +1,564 @@
+/**
+ * ds2482.c - provides i2c to w1-master bridge(s)
+ * Copyright (C) 2005  Ben Gardner <bgardner@wabtec.com>
+ *
+ * The DS2482 is a sensor chip made by Dallas Semiconductor (Maxim).
+ * It is a I2C to 1-wire bridge.
+ * There are two variations: -100 and -800, which have 1 or 8 1-wire ports.
+ * The complete datasheet can be obtained from MAXIM's website at:
+ *   http://www.maxim-ic.com/quick_view2.cfm/qv_pk/4382
+ *
+ * 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; version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <asm/delay.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+
+/**
+ * Address is selected using 2 pins, resulting in 4 possible addresses.
+ *  0x18, 0x19, 0x1a, 0x1b
+ * However, the chip cannot be detected without doing an i2c write,
+ * so use the force module parameter.
+ */
+static unsigned short normal_i2c[] = {I2C_CLIENT_END};
+
+/**
+ * Insmod parameters
+ */
+I2C_CLIENT_INSMOD_1(ds2482);
+
+/**
+ * The DS2482 registers - there are 3 registers that are addressed by a read
+ * pointer. The read pointer is set by the last command executed.
+ *
+ * To read the data, issue a register read for any address
+ */
+#define DS2482_CMD_RESET		0xF0	/* No param */
+#define DS2482_CMD_SET_READ_PTR		0xE1	/* Param: DS2482_PTR_CODE_xxx */
+#define DS2482_CMD_CHANNEL_SELECT	0xC3	/* Param: Channel byte - DS2482-800 only */
+#define DS2482_CMD_WRITE_CONFIG		0xD2	/* Param: Config byte */
+#define DS2482_CMD_1WIRE_RESET		0xB4	/* Param: None */
+#define DS2482_CMD_1WIRE_SINGLE_BIT	0x87	/* Param: Bit byte (bit7) */
+#define DS2482_CMD_1WIRE_WRITE_BYTE	0xA5	/* Param: Data byte */
+#define DS2482_CMD_1WIRE_READ_BYTE	0x96	/* Param: None */
+/* Note to read the byte, Set the ReadPtr to Data then read (any addr) */
+#define DS2482_CMD_1WIRE_TRIPLET	0x78	/* Param: Dir byte (bit7) */
+
+/* Values for DS2482_CMD_SET_READ_PTR */
+#define DS2482_PTR_CODE_STATUS		0xF0
+#define DS2482_PTR_CODE_DATA		0xE1
+#define DS2482_PTR_CODE_CHANNEL		0xD2	/* DS2482-800 only */
+#define DS2482_PTR_CODE_CONFIG		0xC3
+
+/**
+ * Configure Register bit definitions
+ * The top 4 bits always read 0.
+ * To write, the top nibble must be the 1's compl. of the low nibble.
+ */
+#define DS2482_REG_CFG_1WS		0x08
+#define DS2482_REG_CFG_SPU		0x04
+#define DS2482_REG_CFG_PPM		0x02
+#define DS2482_REG_CFG_APU		0x01
+
+
+/**
+ * Write and verify codes for the CHANNEL_SELECT command (DS2482-800 only).
+ * To set the channel, write the value at the index of the channel.
+ * Read and compare against the corresponding value to verify the change.
+ */
+static const u8 ds2482_chan_wr[8] =
+	{ 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87 };
+static const u8 ds2482_chan_rd[8] =
+	{ 0xB8, 0xB1, 0xAA, 0xA3, 0x9C, 0x95, 0x8E, 0x87 };
+
+
+/**
+ * Status Register bit definitions (read only)
+ */
+#define DS2482_REG_STS_DIR		0x80
+#define DS2482_REG_STS_TSB		0x40
+#define DS2482_REG_STS_SBR		0x20
+#define DS2482_REG_STS_RST		0x10
+#define DS2482_REG_STS_LL		0x08
+#define DS2482_REG_STS_SD		0x04
+#define DS2482_REG_STS_PPD		0x02
+#define DS2482_REG_STS_1WB		0x01
+
+
+static int ds2482_attach_adapter(struct i2c_adapter *adapter);
+static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind);
+static int ds2482_detach_client(struct i2c_client *client);
+
+
+/**
+ * Driver data (common to all clients)
+ */
+static struct i2c_driver ds2482_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "ds2482",
+	},
+	.attach_adapter	= ds2482_attach_adapter,
+	.detach_client	= ds2482_detach_client,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct ds2482_data;
+
+struct ds2482_w1_chan {
+	struct ds2482_data	*pdev;
+	u8			channel;
+	struct w1_bus_master	w1_bm;
+};
+
+struct ds2482_data {
+	struct i2c_client	client;
+	struct semaphore	access_lock;
+
+	/* 1-wire interface(s) */
+	int			w1_count;	/* 1 or 8 */
+	struct ds2482_w1_chan	w1_ch[8];
+
+	/* per-device values */
+	u8			channel;
+	u8			read_prt;	/* see DS2482_PTR_CODE_xxx */
+	u8			reg_config;
+};
+
+
+/**
+ * Sets the read pointer.
+ * @param pdev		The ds2482 client pointer
+ * @param read_ptr	see DS2482_PTR_CODE_xxx above
+ * @return -1 on failure, 0 on success
+ */
+static inline int ds2482_select_register(struct ds2482_data *pdev, u8 read_ptr)
+{
+	if (pdev->read_prt != read_ptr) {
+		if (i2c_smbus_write_byte_data(&pdev->client,
+					      DS2482_CMD_SET_READ_PTR,
+					      read_ptr) < 0)
+			return -1;
+
+		pdev->read_prt = read_ptr;
+	}
+	return 0;
+}
+
+/**
+ * Sends a command without a parameter
+ * @param pdev	The ds2482 client pointer
+ * @param cmd	DS2482_CMD_RESET,
+ *		DS2482_CMD_1WIRE_RESET,
+ *		DS2482_CMD_1WIRE_READ_BYTE
+ * @return -1 on failure, 0 on success
+ */
+static inline int ds2482_send_cmd(struct ds2482_data *pdev, u8 cmd)
+{
+	if (i2c_smbus_write_byte(&pdev->client, cmd) < 0)
+		return -1;
+
+	pdev->read_prt = DS2482_PTR_CODE_STATUS;
+	return 0;
+}
+
+/**
+ * Sends a command with a parameter
+ * @param pdev	The ds2482 client pointer
+ * @param cmd	DS2482_CMD_WRITE_CONFIG,
+ *		DS2482_CMD_1WIRE_SINGLE_BIT,
+ *		DS2482_CMD_1WIRE_WRITE_BYTE,
+ *		DS2482_CMD_1WIRE_TRIPLET
+ * @param byte	The data to send
+ * @return -1 on failure, 0 on success
+ */
+static inline int ds2482_send_cmd_data(struct ds2482_data *pdev,
+				       u8 cmd, u8 byte)
+{
+	if (i2c_smbus_write_byte_data(&pdev->client, cmd, byte) < 0)
+		return -1;
+
+	/* all cmds leave in STATUS, except CONFIG */
+	pdev->read_prt = (cmd != DS2482_CMD_WRITE_CONFIG) ?
+			 DS2482_PTR_CODE_STATUS : DS2482_PTR_CODE_CONFIG;
+	return 0;
+}
+
+
+/*
+ * 1-Wire interface code
+ */
+
+#define DS2482_WAIT_IDLE_TIMEOUT	100
+
+/**
+ * Waits until the 1-wire interface is idle (not busy)
+ *
+ * @param pdev Pointer to the device structure
+ * @return the last value read from status or -1 (failure)
+ */
+static int ds2482_wait_1wire_idle(struct ds2482_data *pdev)
+{
+	int temp = -1;
+	int retries = 0;
+
+	if (!ds2482_select_register(pdev, DS2482_PTR_CODE_STATUS)) {
+		do {
+			temp = i2c_smbus_read_byte(&pdev->client);
+		} while ((temp >= 0) && (temp & DS2482_REG_STS_1WB) &&
+			 (++retries > DS2482_WAIT_IDLE_TIMEOUT));
+	}
+
+	if (retries > DS2482_WAIT_IDLE_TIMEOUT)
+		printk(KERN_ERR "%s: timeout on channel %d\n",
+		       __func__, pdev->channel);
+
+	return temp;
+}
+
+/**
+ * Selects a w1 channel.
+ * The 1-wire interface must be idle before calling this function.
+ *
+ * @param pdev		The ds2482 client pointer
+ * @param channel	0-7
+ * @return		-1 (failure) or 0 (success)
+ */
+static int ds2482_set_channel(struct ds2482_data *pdev, u8 channel)
+{
+	if (i2c_smbus_write_byte_data(&pdev->client, DS2482_CMD_CHANNEL_SELECT,
+				      ds2482_chan_wr[channel]) < 0)
+		return -1;
+
+	pdev->read_prt = DS2482_PTR_CODE_CHANNEL;
+	pdev->channel = -1;
+	if (i2c_smbus_read_byte(&pdev->client) == ds2482_chan_rd[channel]) {
+		pdev->channel = channel;
+		return 0;
+	}
+	return -1;
+}
+
+
+/**
+ * Performs the touch-bit function, which writes a 0 or 1 and reads the level.
+ *
+ * @param data	The ds2482 channel pointer
+ * @param bit	The level to write: 0 or non-zero
+ * @return	The level read: 0 or 1
+ */
+static u8 ds2482_w1_touch_bit(void *data, u8 bit)
+{
+	struct ds2482_w1_chan *pchan = data;
+	struct ds2482_data    *pdev = pchan->pdev;
+	int status = -1;
+
+	down(&pdev->access_lock);
+
+	/* Select the channel */
+	ds2482_wait_1wire_idle(pdev);
+	if (pdev->w1_count > 1)
+		ds2482_set_channel(pdev, pchan->channel);
+
+	/* Send the touch command, wait until 1WB == 0, return the status */
+	if (!ds2482_send_cmd_data(pdev, DS2482_CMD_1WIRE_SINGLE_BIT,
+				  bit ? 0xFF : 0))
+		status = ds2482_wait_1wire_idle(pdev);
+
+	up(&pdev->access_lock);
+
+	return (status & DS2482_REG_STS_SBR) ? 1 : 0;
+}
+
+/**
+ * Performs the triplet function, which reads two bits and writes a bit.
+ * The bit written is determined by the two reads:
+ *   00 => dbit, 01 => 0, 10 => 1
+ *
+ * @param data	The ds2482 channel pointer
+ * @param dbit	The direction to choose if both branches are valid
+ * @return	b0=read1 b1=read2 b3=bit written
+ */
+static u8 ds2482_w1_triplet(void *data, u8 dbit)
+{
+	struct ds2482_w1_chan *pchan = data;
+	struct ds2482_data    *pdev = pchan->pdev;
+	int status = (3 << 5);
+
+	down(&pdev->access_lock);
+
+	/* Select the channel */
+	ds2482_wait_1wire_idle(pdev);
+	if (pdev->w1_count > 1)
+		ds2482_set_channel(pdev, pchan->channel);
+
+	/* Send the triplet command, wait until 1WB == 0, return the status */
+	if (!ds2482_send_cmd_data(pdev, DS2482_CMD_1WIRE_TRIPLET,
+				  dbit ? 0xFF : 0))
+		status = ds2482_wait_1wire_idle(pdev);
+
+	up(&pdev->access_lock);
+
+	/* Decode the status */
+	return (status >> 5);
+}
+
+/**
+ * Performs the write byte function.
+ *
+ * @param data	The ds2482 channel pointer
+ * @param byte	The value to write
+ */
+static void ds2482_w1_write_byte(void *data, u8 byte)
+{
+	struct ds2482_w1_chan *pchan = data;
+	struct ds2482_data    *pdev = pchan->pdev;
+
+	down(&pdev->access_lock);
+
+	/* Select the channel */
+	ds2482_wait_1wire_idle(pdev);
+	if (pdev->w1_count > 1)
+		ds2482_set_channel(pdev, pchan->channel);
+
+	/* Send the write byte command */
+	ds2482_send_cmd_data(pdev, DS2482_CMD_1WIRE_WRITE_BYTE, byte);
+
+	up(&pdev->access_lock);
+}
+
+/**
+ * Performs the read byte function.
+ *
+ * @param data	The ds2482 channel pointer
+ * @return	The value read
+ */
+static u8 ds2482_w1_read_byte(void *data)
+{
+	struct ds2482_w1_chan *pchan = data;
+	struct ds2482_data    *pdev = pchan->pdev;
+	int result;
+
+	down(&pdev->access_lock);
+
+	/* Select the channel */
+	ds2482_wait_1wire_idle(pdev);
+	if (pdev->w1_count > 1)
+		ds2482_set_channel(pdev, pchan->channel);
+
+	/* Send the read byte command */
+	ds2482_send_cmd(pdev, DS2482_CMD_1WIRE_READ_BYTE);
+
+	/* Wait until 1WB == 0 */
+	ds2482_wait_1wire_idle(pdev);
+
+	/* Select the data register */
+	ds2482_select_register(pdev, DS2482_PTR_CODE_DATA);
+
+	/* Read the data byte */
+	result = i2c_smbus_read_byte(&pdev->client);
+
+	up(&pdev->access_lock);
+
+	return result;
+}
+
+
+/**
+ * Sends a reset on the 1-wire interface
+ *
+ * @param data	The ds2482 channel pointer
+ * @return	0=Device present, 1=No device present or error
+ */
+static u8 ds2482_w1_reset_bus(void *data)
+{
+	struct ds2482_w1_chan *pchan = data;
+	struct ds2482_data    *pdev = pchan->pdev;
+	int err;
+	u8 retval = 1;
+
+	down(&pdev->access_lock);
+
+	/* Select the channel */
+	ds2482_wait_1wire_idle(pdev);
+	if (pdev->w1_count > 1)
+		ds2482_set_channel(pdev, pchan->channel);
+
+	/* Send the reset command */
+	err = ds2482_send_cmd(pdev, DS2482_CMD_1WIRE_RESET);
+	if (err >= 0) {
+		/* Wait until the reset is complete */
+		err = ds2482_wait_1wire_idle(pdev);
+		retval = !(err & DS2482_REG_STS_PPD);
+
+		/* If the chip did reset since detect, re-config it */
+		if (err & DS2482_REG_STS_RST)
+			ds2482_send_cmd_data(pdev, DS2482_CMD_WRITE_CONFIG,
+					     0xF0);
+	}
+
+	up(&pdev->access_lock);
+
+	return retval;
+}
+
+
+/**
+ * Called to see if the device exists on an i2c bus.
+ */
+static int ds2482_attach_adapter(struct i2c_adapter *adapter)
+{
+	return i2c_probe(adapter, &addr_data, ds2482_detect);
+}
+
+
+/*
+ * The following function does more than just detection. If detection
+ * succeeds, it also registers the new chip.
+ */
+static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct ds2482_data *data;
+	struct i2c_client  *new_client;
+	int err = 0;
+	int temp1;
+	int idx;
+
+	if (!i2c_check_functionality(adapter,
+				     I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+				     I2C_FUNC_SMBUS_BYTE))
+		goto exit;
+
+	if (!(data = kzalloc(sizeof(struct ds2482_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	new_client = &data->client;
+	i2c_set_clientdata(new_client, data);
+	new_client->addr = address;
+	new_client->driver = &ds2482_driver;
+	new_client->adapter = adapter;
+
+	/* Reset the device (sets the read_ptr to status) */
+	if (ds2482_send_cmd(data, DS2482_CMD_RESET) < 0) {
+		dev_dbg(&adapter->dev, "DS2482 reset failed at 0x%02x.\n",
+			address);
+		goto exit_free;
+	}
+
+	/* Sleep at least 525ns to allow the reset to complete */
+	ndelay(525);
+
+	/* Read the status byte - only reset bit and line should be set */
+	temp1 = i2c_smbus_read_byte(new_client);
+	if (temp1 != (DS2482_REG_STS_LL | DS2482_REG_STS_RST)) {
+		dev_dbg(&adapter->dev, "DS2482 (0x%02x) reset status "
+			"0x%02X - not a DS2482\n", address, temp1);
+		goto exit_free;
+	}
+
+	/* Detect the 8-port version */
+	data->w1_count = 1;
+	if (ds2482_set_channel(data, 7) == 0)
+		data->w1_count = 8;
+
+	/* Set all config items to 0 (off) */
+	ds2482_send_cmd_data(data, DS2482_CMD_WRITE_CONFIG, 0xF0);
+
+	/* We can fill in the remaining client fields */
+	snprintf(new_client->name, sizeof(new_client->name), "ds2482-%d00",
+		 data->w1_count);
+
+	init_MUTEX(&data->access_lock);
+
+	/* Tell the I2C layer a new client has arrived */
+	if ((err = i2c_attach_client(new_client)))
+		goto exit_free;
+
+	/* Register 1-wire interface(s) */
+	for (idx = 0; idx < data->w1_count; idx++) {
+		data->w1_ch[idx].pdev = data;
+		data->w1_ch[idx].channel = idx;
+
+		/* Populate all the w1 bus master stuff */
+		data->w1_ch[idx].w1_bm.data       = &data->w1_ch[idx];
+		data->w1_ch[idx].w1_bm.read_byte  = ds2482_w1_read_byte;
+		data->w1_ch[idx].w1_bm.write_byte = ds2482_w1_write_byte;
+		data->w1_ch[idx].w1_bm.touch_bit  = ds2482_w1_touch_bit;
+		data->w1_ch[idx].w1_bm.triplet    = ds2482_w1_triplet;
+		data->w1_ch[idx].w1_bm.reset_bus  = ds2482_w1_reset_bus;
+
+		err = w1_add_master_device(&data->w1_ch[idx].w1_bm);
+		if (err) {
+			data->w1_ch[idx].pdev = NULL;
+			goto exit_w1_remove;
+		}
+	}
+
+	return 0;
+
+exit_w1_remove:
+	i2c_detach_client(new_client);
+
+	for (idx = 0; idx < data->w1_count; idx++) {
+		if (data->w1_ch[idx].pdev != NULL)
+			w1_remove_master_device(&data->w1_ch[idx].w1_bm);
+	}
+exit_free:
+	kfree(data);
+exit:
+	return err;
+}
+
+static int ds2482_detach_client(struct i2c_client *client)
+{
+	struct ds2482_data   *data = i2c_get_clientdata(client);
+	int err, idx;
+
+	/* Unregister the 1-wire bridge(s) */
+	for (idx = 0; idx < data->w1_count; idx++) {
+		if (data->w1_ch[idx].pdev != NULL)
+			w1_remove_master_device(&data->w1_ch[idx].w1_bm);
+	}
+
+	/* Detach the i2c device */
+	if ((err = i2c_detach_client(client))) {
+		dev_err(&client->dev,
+			"Deregistration failed, client not detached.\n");
+		return err;
+	}
+
+	/* Free the memory */
+	kfree(data);
+	return 0;
+}
+
+static int __init sensors_ds2482_init(void)
+{
+	return i2c_add_driver(&ds2482_driver);
+}
+
+static void __exit sensors_ds2482_exit(void)
+{
+	i2c_del_driver(&ds2482_driver);
+}
+
+MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
+MODULE_DESCRIPTION("DS2482 driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_ds2482_init);
+module_exit(sensors_ds2482_exit);
diff -urN oldtree/drivers/w1/masters/ds_w1_bridge.c newtree/drivers/w1/masters/ds_w1_bridge.c
--- oldtree/drivers/w1/masters/ds_w1_bridge.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/w1/masters/ds_w1_bridge.c	2006-02-21 15:58:14.577930376 +0000
@@ -0,0 +1,174 @@
+/*
+ *	ds_w1_bridge.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ *
+ *
+ * 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/module.h>
+#include <linux/types.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+#include "dscore.h"
+
+static struct ds_device *ds_dev;
+static struct w1_bus_master *ds_bus_master;
+
+static u8 ds9490r_touch_bit(void *data, u8 bit)
+{
+	u8 ret;
+	struct ds_device *dev = data;
+
+	if (ds_touch_bit(dev, bit, &ret))
+		return 0;
+
+	return ret;
+}
+
+static void ds9490r_write_bit(void *data, u8 bit)
+{
+	struct ds_device *dev = data;
+
+	ds_write_bit(dev, bit);
+}
+
+static void ds9490r_write_byte(void *data, u8 byte)
+{
+	struct ds_device *dev = data;
+
+	ds_write_byte(dev, byte);
+}
+
+static u8 ds9490r_read_bit(void *data)
+{
+	struct ds_device *dev = data;
+	int err;
+	u8 bit = 0;
+
+	err = ds_touch_bit(dev, 1, &bit);
+	if (err)
+		return 0;
+	//err = ds_read_bit(dev, &bit);
+	//if (err)
+	//	return 0;
+
+	return bit & 1;
+}
+
+static u8 ds9490r_read_byte(void *data)
+{
+	struct ds_device *dev = data;
+	int err;
+	u8 byte = 0;
+
+	err = ds_read_byte(dev, &byte);
+	if (err)
+		return 0;
+
+	return byte;
+}
+
+static void ds9490r_write_block(void *data, const u8 *buf, int len)
+{
+	struct ds_device *dev = data;
+
+	ds_write_block(dev, (u8 *)buf, len);
+}
+
+static u8 ds9490r_read_block(void *data, u8 *buf, int len)
+{
+	struct ds_device *dev = data;
+	int err;
+
+	err = ds_read_block(dev, buf, len);
+	if (err < 0)
+		return 0;
+
+	return len;
+}
+
+static u8 ds9490r_reset(void *data)
+{
+	struct ds_device *dev = data;
+	struct ds_status st;
+	int err;
+
+	memset(&st, 0, sizeof(st));
+
+	err = ds_reset(dev, &st);
+	if (err)
+		return 1;
+
+	return 0;
+}
+
+static int __devinit ds_w1_init(void)
+{
+	int err;
+
+	ds_bus_master = kmalloc(sizeof(*ds_bus_master), GFP_KERNEL);
+	if (!ds_bus_master) {
+		printk(KERN_ERR "Failed to allocate DS9490R USB<->W1 bus_master structure.\n");
+		return -ENOMEM;
+	}
+
+	ds_dev = ds_get_device();
+	if (!ds_dev) {
+		printk(KERN_ERR "DS9490R is not registered.\n");
+		err =  -ENODEV;
+		goto err_out_free_bus_master;
+	}
+
+	memset(ds_bus_master, 0, sizeof(*ds_bus_master));
+
+	ds_bus_master->data		= ds_dev;
+	ds_bus_master->touch_bit	= &ds9490r_touch_bit;
+	ds_bus_master->read_bit		= &ds9490r_read_bit;
+	ds_bus_master->write_bit	= &ds9490r_write_bit;
+	ds_bus_master->read_byte	= &ds9490r_read_byte;
+	ds_bus_master->write_byte	= &ds9490r_write_byte;
+	ds_bus_master->read_block	= &ds9490r_read_block;
+	ds_bus_master->write_block	= &ds9490r_write_block;
+	ds_bus_master->reset_bus	= &ds9490r_reset;
+
+	err = w1_add_master_device(ds_bus_master);
+	if (err)
+		goto err_out_put_device;
+
+	return 0;
+
+err_out_put_device:
+	ds_put_device(ds_dev);
+err_out_free_bus_master:
+	kfree(ds_bus_master);
+
+	return err;
+}
+
+static void __devexit ds_w1_fini(void)
+{
+	w1_remove_master_device(ds_bus_master);
+	ds_put_device(ds_dev);
+	kfree(ds_bus_master);
+}
+
+module_init(ds_w1_init);
+module_exit(ds_w1_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
diff -urN oldtree/drivers/w1/masters/dscore.c newtree/drivers/w1/masters/dscore.c
--- oldtree/drivers/w1/masters/dscore.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/w1/masters/dscore.c	2006-02-21 15:58:14.579930072 +0000
@@ -0,0 +1,795 @@
+/*
+ *	dscore.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ *
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/usb.h>
+
+#include "dscore.h"
+
+static struct usb_device_id ds_id_table [] = {
+	{ USB_DEVICE(0x04fa, 0x2490) },
+	{ },
+};
+MODULE_DEVICE_TABLE(usb, ds_id_table);
+
+static int ds_probe(struct usb_interface *, const struct usb_device_id *);
+static void ds_disconnect(struct usb_interface *);
+
+int ds_touch_bit(struct ds_device *, u8, u8 *);
+int ds_read_byte(struct ds_device *, u8 *);
+int ds_read_bit(struct ds_device *, u8 *);
+int ds_write_byte(struct ds_device *, u8);
+int ds_write_bit(struct ds_device *, u8);
+static int ds_start_pulse(struct ds_device *, int);
+int ds_reset(struct ds_device *, struct ds_status *);
+struct ds_device * ds_get_device(void);
+void ds_put_device(struct ds_device *);
+
+static inline void ds_dump_status(unsigned char *, unsigned char *, int);
+static int ds_send_control(struct ds_device *, u16, u16);
+static int ds_send_control_mode(struct ds_device *, u16, u16);
+static int ds_send_control_cmd(struct ds_device *, u16, u16);
+
+
+static struct usb_driver ds_driver = {
+	.name =		"DS9490R",
+	.probe =	ds_probe,
+	.disconnect =	ds_disconnect,
+	.id_table =	ds_id_table,
+};
+
+static struct ds_device *ds_dev;
+
+struct ds_device * ds_get_device(void)
+{
+	if (ds_dev)
+		atomic_inc(&ds_dev->refcnt);
+	return ds_dev;
+}
+
+void ds_put_device(struct ds_device *dev)
+{
+	atomic_dec(&dev->refcnt);
+}
+
+static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index)
+{
+	int err;
+
+	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
+			CONTROL_CMD, 0x40, value, index, NULL, 0, 1000);
+	if (err < 0) {
+		printk(KERN_ERR "Failed to send command control message %x.%x: err=%d.\n",
+				value, index, err);
+		return err;
+	}
+
+	return err;
+}
+
+static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
+{
+	int err;
+
+	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
+			MODE_CMD, 0x40, value, index, NULL, 0, 1000);
+	if (err < 0) {
+		printk(KERN_ERR "Failed to send mode control message %x.%x: err=%d.\n",
+				value, index, err);
+		return err;
+	}
+
+	return err;
+}
+
+static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
+{
+	int err;
+
+	err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
+			COMM_CMD, 0x40, value, index, NULL, 0, 1000);
+	if (err < 0) {
+		printk(KERN_ERR "Failed to send control message %x.%x: err=%d.\n",
+				value, index, err);
+		return err;
+	}
+
+	return err;
+}
+
+static inline void ds_dump_status(unsigned char *buf, unsigned char *str, int off)
+{
+	printk("%45s: %8x\n", str, buf[off]);
+}
+
+static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st,
+				 unsigned char *buf, int size)
+{
+	int count, err;
+
+	memset(st, 0, sizeof(st));
+
+	count = 0;
+	err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_STATUS]), buf, size, &count, 100);
+	if (err < 0) {
+		printk(KERN_ERR "Failed to read 1-wire data from 0x%x: err=%d.\n", dev->ep[EP_STATUS], err);
+		return err;
+	}
+
+	if (count >= sizeof(*st))
+		memcpy(st, buf, sizeof(*st));
+
+	return count;
+}
+
+static int ds_recv_status(struct ds_device *dev, struct ds_status *st)
+{
+	unsigned char buf[64];
+	int count, err = 0, i;
+
+	memcpy(st, buf, sizeof(*st));
+
+	count = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
+	if (count < 0)
+		return err;
+
+	printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], count);
+	for (i=0; i<count; ++i)
+		printk("%02x ", buf[i]);
+	printk("\n");
+
+	if (count >= 16) {
+		ds_dump_status(buf, "enable flag", 0);
+		ds_dump_status(buf, "1-wire speed", 1);
+		ds_dump_status(buf, "strong pullup duration", 2);
+		ds_dump_status(buf, "programming pulse duration", 3);
+		ds_dump_status(buf, "pulldown slew rate control", 4);
+		ds_dump_status(buf, "write-1 low time", 5);
+		ds_dump_status(buf, "data sample offset/write-0 recovery time", 6);
+		ds_dump_status(buf, "reserved (test register)", 7);
+		ds_dump_status(buf, "device status flags", 8);
+		ds_dump_status(buf, "communication command byte 1", 9);
+		ds_dump_status(buf, "communication command byte 2", 10);
+		ds_dump_status(buf, "communication command buffer status", 11);
+		ds_dump_status(buf, "1-wire data output buffer status", 12);
+		ds_dump_status(buf, "1-wire data input buffer status", 13);
+		ds_dump_status(buf, "reserved", 14);
+		ds_dump_status(buf, "reserved", 15);
+	}
+
+	memcpy(st, buf, sizeof(*st));
+
+	if (st->status & ST_EPOF) {
+		printk(KERN_INFO "Resetting device after ST_EPOF.\n");
+		err = ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
+		if (err)
+			return err;
+		count = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
+		if (count < 0)
+			return err;
+	}
+#if 0
+	if (st->status & ST_IDLE) {
+		printk(KERN_INFO "Resetting pulse after ST_IDLE.\n");
+		err = ds_start_pulse(dev, PULLUP_PULSE_DURATION);
+		if (err)
+			return err;
+	}
+#endif
+
+	return err;
+}
+
+static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
+{
+	int count, err;
+	struct ds_status st;
+
+	count = 0;
+	err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]),
+				buf, size, &count, 1000);
+	if (err < 0) {
+		printk(KERN_INFO "Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]);
+		usb_clear_halt(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]));
+		ds_recv_status(dev, &st);
+		return err;
+	}
+
+#if 0
+	{
+		int i;
+
+		printk("%s: count=%d: ", __func__, count);
+		for (i=0; i<count; ++i)
+			printk("%02x ", buf[i]);
+		printk("\n");
+	}
+#endif
+	return count;
+}
+
+static int ds_send_data(struct ds_device *dev, unsigned char *buf, int len)
+{
+	int count, err;
+
+	count = 0;
+	err = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, dev->ep[EP_DATA_OUT]), buf, len, &count, 1000);
+	if (err < 0) {
+		printk(KERN_ERR "Failed to read 1-wire data from 0x02: err=%d.\n", err);
+		return err;
+	}
+
+	return err;
+}
+
+#if 0
+
+int ds_stop_pulse(struct ds_device *dev, int limit)
+{
+	struct ds_status st;
+	int count = 0, err = 0;
+	u8 buf[0x20];
+
+	do {
+		err = ds_send_control(dev, CTL_HALT_EXE_IDLE, 0);
+		if (err)
+			break;
+		err = ds_send_control(dev, CTL_RESUME_EXE, 0);
+		if (err)
+			break;
+		err = ds_recv_status_nodump(dev, &st, buf, sizeof(buf));
+		if (err)
+			break;
+
+		if ((st.status & ST_SPUA) == 0) {
+			err = ds_send_control_mode(dev, MOD_PULSE_EN, 0);
+			if (err)
+				break;
+		}
+	} while(++count < limit);
+
+	return err;
+}
+
+int ds_detect(struct ds_device *dev, struct ds_status *st)
+{
+	int err;
+
+	err = ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
+	if (err)
+		return err;
+
+	err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, 0);
+	if (err)
+		return err;
+
+	err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM | COMM_TYPE, 0x40);
+	if (err)
+		return err;
+
+	err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_PROG);
+	if (err)
+		return err;
+
+	err = ds_recv_status(dev, st);
+
+	return err;
+}
+
+#endif  /*  0  */
+
+static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
+{
+	u8 buf[0x20];
+	int err, count = 0;
+
+	do {
+		err = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
+#if 0
+		if (err >= 0) {
+			int i;
+			printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], err);
+			for (i=0; i<err; ++i)
+				printk("%02x ", buf[i]);
+			printk("\n");
+		}
+#endif
+	} while(!(buf[0x08] & 0x20) && !(err < 0) && ++count < 100);
+
+
+	if (((err > 16) && (buf[0x10] & 0x01)) || count >= 100 || err < 0) {
+		ds_recv_status(dev, st);
+		return -1;
+	} else
+		return 0;
+}
+
+int ds_reset(struct ds_device *dev, struct ds_status *st)
+{
+	int err;
+
+	//err = ds_send_control(dev, COMM_1_WIRE_RESET | COMM_F | COMM_IM | COMM_SE, SPEED_FLEXIBLE);
+	err = ds_send_control(dev, 0x43, SPEED_NORMAL);
+	if (err)
+		return err;
+
+	ds_wait_status(dev, st);
+#if 0
+	if (st->command_buffer_status) {
+		printk(KERN_INFO "Short circuit.\n");
+		return -EIO;
+	}
+#endif
+
+	return 0;
+}
+
+#if 0
+int ds_set_speed(struct ds_device *dev, int speed)
+{
+	int err;
+
+	if (speed != SPEED_NORMAL && speed != SPEED_FLEXIBLE && speed != SPEED_OVERDRIVE)
+		return -EINVAL;
+
+	if (speed != SPEED_OVERDRIVE)
+		speed = SPEED_FLEXIBLE;
+
+	speed &= 0xff;
+
+	err = ds_send_control_mode(dev, MOD_1WIRE_SPEED, speed);
+	if (err)
+		return err;
+
+	return err;
+}
+#endif  /*  0  */
+
+static int ds_start_pulse(struct ds_device *dev, int delay)
+{
+	int err;
+	u8 del = 1 + (u8)(delay >> 4);
+	struct ds_status st;
+
+#if 0
+	err = ds_stop_pulse(dev, 10);
+	if (err)
+		return err;
+
+	err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE);
+	if (err)
+		return err;
+#endif
+	err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, del);
+	if (err)
+		return err;
+
+	err = ds_send_control(dev, COMM_PULSE | COMM_IM | COMM_F, 0);
+	if (err)
+		return err;
+
+	mdelay(delay);
+
+	ds_wait_status(dev, &st);
+
+	return err;
+}
+
+int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit)
+{
+	int err, count;
+	struct ds_status st;
+	u16 value = (COMM_BIT_IO | COMM_IM) | ((bit) ? COMM_D : 0);
+	u16 cmd;
+
+	err = ds_send_control(dev, value, 0);
+	if (err)
+		return err;
+
+	count = 0;
+	do {
+		err = ds_wait_status(dev, &st);
+		if (err)
+			return err;
+
+		cmd = st.command0 | (st.command1 << 8);
+	} while (cmd != value && ++count < 10);
+
+	if (err < 0 || count >= 10) {
+		printk(KERN_ERR "Failed to obtain status.\n");
+		return -EINVAL;
+	}
+
+	err = ds_recv_data(dev, tbit, sizeof(*tbit));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+int ds_write_bit(struct ds_device *dev, u8 bit)
+{
+	int err;
+	struct ds_status st;
+
+	err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | (bit) ? COMM_D : 0, 0);
+	if (err)
+		return err;
+
+	ds_wait_status(dev, &st);
+
+	return 0;
+}
+
+int ds_write_byte(struct ds_device *dev, u8 byte)
+{
+	int err;
+	struct ds_status st;
+	u8 rbyte;
+
+	err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | COMM_SPU, byte);
+	if (err)
+		return err;
+
+	err = ds_wait_status(dev, &st);
+	if (err)
+		return err;
+
+	err = ds_recv_data(dev, &rbyte, sizeof(rbyte));
+	if (err < 0)
+		return err;
+
+	ds_start_pulse(dev, PULLUP_PULSE_DURATION);
+
+	return !(byte == rbyte);
+}
+
+int ds_read_bit(struct ds_device *dev, u8 *bit)
+{
+	int err;
+
+	err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE);
+	if (err)
+		return err;
+
+	err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | COMM_SPU | COMM_D, 0);
+	if (err)
+		return err;
+
+	err = ds_recv_data(dev, bit, sizeof(*bit));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+int ds_read_byte(struct ds_device *dev, u8 *byte)
+{
+	int err;
+	struct ds_status st;
+
+	err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM , 0xff);
+	if (err)
+		return err;
+
+	ds_wait_status(dev, &st);
+
+	err = ds_recv_data(dev, byte, sizeof(*byte));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+int ds_read_block(struct ds_device *dev, u8 *buf, int len)
+{
+	struct ds_status st;
+	int err;
+
+	if (len > 64*1024)
+		return -E2BIG;
+
+	memset(buf, 0xFF, len);
+
+	err = ds_send_data(dev, buf, len);
+	if (err < 0)
+		return err;
+
+	err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
+	if (err)
+		return err;
+
+	ds_wait_status(dev, &st);
+
+	memset(buf, 0x00, len);
+	err = ds_recv_data(dev, buf, len);
+
+	return err;
+}
+
+int ds_write_block(struct ds_device *dev, u8 *buf, int len)
+{
+	int err;
+	struct ds_status st;
+
+	err = ds_send_data(dev, buf, len);
+	if (err < 0)
+		return err;
+
+	ds_wait_status(dev, &st);
+
+	err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
+	if (err)
+		return err;
+
+	ds_wait_status(dev, &st);
+
+	err = ds_recv_data(dev, buf, len);
+	if (err < 0)
+		return err;
+
+	ds_start_pulse(dev, PULLUP_PULSE_DURATION);
+
+	return !(err == len);
+}
+
+#if 0
+
+int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search)
+{
+	int err;
+	u16 value, index;
+	struct ds_status st;
+
+	memset(buf, 0, sizeof(buf));
+
+	err = ds_send_data(ds_dev, (unsigned char *)&init, 8);
+	if (err)
+		return err;
+
+	ds_wait_status(ds_dev, &st);
+
+	value = COMM_SEARCH_ACCESS | COMM_IM | COMM_SM | COMM_F | COMM_RTS;
+	index = (conditional_search ? 0xEC : 0xF0) | (id_number << 8);
+	err = ds_send_control(ds_dev, value, index);
+	if (err)
+		return err;
+
+	ds_wait_status(ds_dev, &st);
+
+	err = ds_recv_data(ds_dev, (unsigned char *)buf, 8*id_number);
+	if (err < 0)
+		return err;
+
+	return err/8;
+}
+
+int ds_match_access(struct ds_device *dev, u64 init)
+{
+	int err;
+	struct ds_status st;
+
+	err = ds_send_data(dev, (unsigned char *)&init, sizeof(init));
+	if (err)
+		return err;
+
+	ds_wait_status(dev, &st);
+
+	err = ds_send_control(dev, COMM_MATCH_ACCESS | COMM_IM | COMM_RST, 0x0055);
+	if (err)
+		return err;
+
+	ds_wait_status(dev, &st);
+
+	return 0;
+}
+
+int ds_set_path(struct ds_device *dev, u64 init)
+{
+	int err;
+	struct ds_status st;
+	u8 buf[9];
+
+	memcpy(buf, &init, 8);
+	buf[8] = BRANCH_MAIN;
+
+	err = ds_send_data(dev, buf, sizeof(buf));
+	if (err)
+		return err;
+
+	ds_wait_status(dev, &st);
+
+	err = ds_send_control(dev, COMM_SET_PATH | COMM_IM | COMM_RST, 0);
+	if (err)
+		return err;
+
+	ds_wait_status(dev, &st);
+
+	return 0;
+}
+
+#endif  /*  0  */
+
+static int ds_probe(struct usb_interface *intf,
+		    const struct usb_device_id *udev_id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_host_interface *iface_desc;
+	int i, err;
+
+	ds_dev = kmalloc(sizeof(struct ds_device), GFP_KERNEL);
+	if (!ds_dev) {
+		printk(KERN_INFO "Failed to allocate new DS9490R structure.\n");
+		return -ENOMEM;
+	}
+
+	ds_dev->udev = usb_get_dev(udev);
+	usb_set_intfdata(intf, ds_dev);
+
+	err = usb_set_interface(ds_dev->udev, intf->altsetting[0].desc.bInterfaceNumber, 3);
+	if (err) {
+		printk(KERN_ERR "Failed to set alternative setting 3 for %d interface: err=%d.\n",
+				intf->altsetting[0].desc.bInterfaceNumber, err);
+		return err;
+	}
+
+	err = usb_reset_configuration(ds_dev->udev);
+	if (err) {
+		printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err);
+		return err;
+	}
+
+	iface_desc = &intf->altsetting[0];
+	if (iface_desc->desc.bNumEndpoints != NUM_EP-1) {
+		printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints);
+		return -ENODEV;
+	}
+
+	atomic_set(&ds_dev->refcnt, 0);
+	memset(ds_dev->ep, 0, sizeof(ds_dev->ep));
+
+	/*
+	 * This loop doesn'd show control 0 endpoint,
+	 * so we will fill only 1-3 endpoints entry.
+	 */
+	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+		endpoint = &iface_desc->endpoint[i].desc;
+
+		ds_dev->ep[i+1] = endpoint->bEndpointAddress;
+
+		printk("%d: addr=%x, size=%d, dir=%s, type=%x\n",
+			i, endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize),
+			(endpoint->bEndpointAddress & USB_DIR_IN)?"IN":"OUT",
+			endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+	}
+
+#if 0
+	{
+		int err, i;
+		u64 buf[3];
+		u64 init=0xb30000002078ee81ull;
+		struct ds_status st;
+
+		ds_reset(ds_dev, &st);
+		err = ds_search(ds_dev, init, buf, 3, 0);
+		if (err < 0)
+			return err;
+		for (i=0; i<err; ++i)
+			printk("%d: %llx\n", i, buf[i]);
+
+		printk("Resetting...\n");
+		ds_reset(ds_dev, &st);
+		printk("Setting path for %llx.\n", init);
+		err = ds_set_path(ds_dev, init);
+		if (err)
+			return err;
+		printk("Calling MATCH_ACCESS.\n");
+		err = ds_match_access(ds_dev, init);
+		if (err)
+			return err;
+
+		printk("Searching the bus...\n");
+		err = ds_search(ds_dev, init, buf, 3, 0);
+
+		printk("ds_search() returned %d\n", err);
+
+		if (err < 0)
+			return err;
+		for (i=0; i<err; ++i)
+			printk("%d: %llx\n", i, buf[i]);
+
+		return 0;
+	}
+#endif
+
+	return 0;
+}
+
+static void ds_disconnect(struct usb_interface *intf)
+{
+	struct ds_device *dev;
+
+	dev = usb_get_intfdata(intf);
+	usb_set_intfdata(intf, NULL);
+
+	while (atomic_read(&dev->refcnt)) {
+		printk(KERN_INFO "Waiting for DS to become free: refcnt=%d.\n",
+				atomic_read(&dev->refcnt));
+
+		if (msleep_interruptible(1000))
+			flush_signals(current);
+	}
+
+	usb_put_dev(dev->udev);
+	kfree(dev);
+	ds_dev = NULL;
+}
+
+static int ds_init(void)
+{
+	int err;
+
+	err = usb_register(&ds_driver);
+	if (err) {
+		printk(KERN_INFO "Failed to register DS9490R USB device: err=%d.\n", err);
+		return err;
+	}
+
+	return 0;
+}
+
+static void ds_fini(void)
+{
+	usb_deregister(&ds_driver);
+}
+
+module_init(ds_init);
+module_exit(ds_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+
+EXPORT_SYMBOL(ds_touch_bit);
+EXPORT_SYMBOL(ds_read_byte);
+EXPORT_SYMBOL(ds_read_bit);
+EXPORT_SYMBOL(ds_read_block);
+EXPORT_SYMBOL(ds_write_byte);
+EXPORT_SYMBOL(ds_write_bit);
+EXPORT_SYMBOL(ds_write_block);
+EXPORT_SYMBOL(ds_reset);
+EXPORT_SYMBOL(ds_get_device);
+EXPORT_SYMBOL(ds_put_device);
+
+/*
+ * This functions can be used for EEPROM programming,
+ * when driver will be included into mainline this will
+ * require uncommenting.
+ */
+#if 0
+EXPORT_SYMBOL(ds_start_pulse);
+EXPORT_SYMBOL(ds_set_speed);
+EXPORT_SYMBOL(ds_detect);
+EXPORT_SYMBOL(ds_stop_pulse);
+EXPORT_SYMBOL(ds_search);
+#endif
diff -urN oldtree/drivers/w1/masters/dscore.h newtree/drivers/w1/masters/dscore.h
--- oldtree/drivers/w1/masters/dscore.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/w1/masters/dscore.h	2006-02-21 15:58:14.579930072 +0000
@@ -0,0 +1,166 @@
+/*
+ *	dscore.h
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ *
+ *
+ * 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 __DSCORE_H
+#define __DSCORE_H
+
+#include <linux/usb.h>
+#include <asm/atomic.h>
+
+/* COMMAND TYPE CODES */
+#define CONTROL_CMD			0x00
+#define COMM_CMD			0x01
+#define MODE_CMD			0x02
+
+/* CONTROL COMMAND CODES */
+#define CTL_RESET_DEVICE		0x0000
+#define CTL_START_EXE			0x0001
+#define CTL_RESUME_EXE			0x0002
+#define CTL_HALT_EXE_IDLE		0x0003
+#define CTL_HALT_EXE_DONE		0x0004
+#define CTL_FLUSH_COMM_CMDS		0x0007
+#define CTL_FLUSH_RCV_BUFFER		0x0008
+#define CTL_FLUSH_XMT_BUFFER		0x0009
+#define CTL_GET_COMM_CMDS		0x000A
+
+/* MODE COMMAND CODES */
+#define MOD_PULSE_EN			0x0000
+#define MOD_SPEED_CHANGE_EN		0x0001
+#define MOD_1WIRE_SPEED			0x0002
+#define MOD_STRONG_PU_DURATION		0x0003
+#define MOD_PULLDOWN_SLEWRATE		0x0004
+#define MOD_PROG_PULSE_DURATION		0x0005
+#define MOD_WRITE1_LOWTIME		0x0006
+#define MOD_DSOW0_TREC			0x0007
+
+/* COMMUNICATION COMMAND CODES */
+#define COMM_ERROR_ESCAPE		0x0601
+#define COMM_SET_DURATION		0x0012
+#define COMM_BIT_IO			0x0020
+#define COMM_PULSE			0x0030
+#define COMM_1_WIRE_RESET		0x0042
+#define COMM_BYTE_IO			0x0052
+#define COMM_MATCH_ACCESS		0x0064
+#define COMM_BLOCK_IO			0x0074
+#define COMM_READ_STRAIGHT		0x0080
+#define COMM_DO_RELEASE			0x6092
+#define COMM_SET_PATH			0x00A2
+#define COMM_WRITE_SRAM_PAGE		0x00B2
+#define COMM_WRITE_EPROM		0x00C4
+#define COMM_READ_CRC_PROT_PAGE		0x00D4
+#define COMM_READ_REDIRECT_PAGE_CRC	0x21E4
+#define COMM_SEARCH_ACCESS		0x00F4
+
+/* Communication command bits */
+#define COMM_TYPE			0x0008
+#define COMM_SE				0x0008
+#define COMM_D				0x0008
+#define COMM_Z				0x0008
+#define COMM_CH				0x0008
+#define COMM_SM				0x0008
+#define COMM_R				0x0008
+#define COMM_IM				0x0001
+
+#define COMM_PS				0x4000
+#define COMM_PST			0x4000
+#define COMM_CIB			0x4000
+#define COMM_RTS			0x4000
+#define COMM_DT				0x2000
+#define COMM_SPU			0x1000
+#define COMM_F				0x0800
+#define COMM_NTP			0x0400
+#define COMM_ICP			0x0200
+#define COMM_RST			0x0100
+
+#define PULSE_PROG			0x01
+#define PULSE_SPUE			0x02
+
+#define BRANCH_MAIN			0xCC
+#define BRANCH_AUX			0x33
+
+/*
+ * Duration of the strong pull-up pulse in milliseconds.
+ */
+#define PULLUP_PULSE_DURATION		750
+
+/* Status flags */
+#define ST_SPUA				0x01  /* Strong Pull-up is active */
+#define ST_PRGA				0x02  /* 12V programming pulse is being generated */
+#define ST_12VP				0x04  /* external 12V programming voltage is present */
+#define ST_PMOD				0x08  /* DS2490 powered from USB and external sources */
+#define ST_HALT				0x10  /* DS2490 is currently halted */
+#define ST_IDLE				0x20  /* DS2490 is currently idle */
+#define ST_EPOF				0x80
+
+#define SPEED_NORMAL			0x00
+#define SPEED_FLEXIBLE			0x01
+#define SPEED_OVERDRIVE			0x02
+
+#define NUM_EP				4
+#define EP_CONTROL			0
+#define EP_STATUS			1
+#define EP_DATA_OUT			2
+#define EP_DATA_IN			3
+
+struct ds_device
+{
+	struct usb_device	*udev;
+	struct usb_interface	*intf;
+
+	int			ep[NUM_EP];
+
+	atomic_t		refcnt;
+};
+
+struct ds_status
+{
+	u8			enable;
+	u8			speed;
+	u8			pullup_dur;
+	u8			ppuls_dur;
+	u8			pulldown_slew;
+	u8			write1_time;
+	u8			write0_time;
+	u8			reserved0;
+	u8			status;
+	u8			command0;
+	u8			command1;
+	u8			command_buffer_status;
+	u8			data_out_buffer_status;
+	u8			data_in_buffer_status;
+	u8			reserved1;
+	u8			reserved2;
+
+};
+
+int ds_touch_bit(struct ds_device *, u8, u8 *);
+int ds_read_byte(struct ds_device *, u8 *);
+int ds_read_bit(struct ds_device *, u8 *);
+int ds_write_byte(struct ds_device *, u8);
+int ds_write_bit(struct ds_device *, u8);
+int ds_reset(struct ds_device *, struct ds_status *);
+struct ds_device * ds_get_device(void);
+void ds_put_device(struct ds_device *);
+int ds_write_block(struct ds_device *, u8 *, int);
+int ds_read_block(struct ds_device *, u8 *, int);
+
+#endif /* __DSCORE_H */
+
diff -urN oldtree/drivers/w1/masters/matrox_w1.c newtree/drivers/w1/masters/matrox_w1.c
--- oldtree/drivers/w1/masters/matrox_w1.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/w1/masters/matrox_w1.c	2006-02-21 15:58:14.579930072 +0000
@@ -0,0 +1,247 @@
+/*
+ *	matrox_w1.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ *
+ *
+ * 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/types.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/pci_ids.h>
+#include <linux/pci.h>
+#include <linux/timer.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+#include "../w1_log.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Driver for transport(Dallas 1-wire prtocol) over VGA DDC(matrox gpio).");
+
+static struct pci_device_id matrox_w1_tbl[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400) },
+	{ },
+};
+MODULE_DEVICE_TABLE(pci, matrox_w1_tbl);
+
+static int __devinit matrox_w1_probe(struct pci_dev *, const struct pci_device_id *);
+static void __devexit matrox_w1_remove(struct pci_dev *);
+
+static struct pci_driver matrox_w1_pci_driver = {
+	.name = "matrox_w1",
+	.id_table = matrox_w1_tbl,
+	.probe = matrox_w1_probe,
+	.remove = __devexit_p(matrox_w1_remove),
+};
+
+/*
+ * Matrox G400 DDC registers.
+ */
+
+#define MATROX_G400_DDC_CLK		(1<<4)
+#define MATROX_G400_DDC_DATA		(1<<1)
+
+#define MATROX_BASE			0x3C00
+#define MATROX_STATUS			0x1e14
+
+#define MATROX_PORT_INDEX_OFFSET	0x00
+#define MATROX_PORT_DATA_OFFSET		0x0A
+
+#define MATROX_GET_CONTROL		0x2A
+#define MATROX_GET_DATA			0x2B
+#define MATROX_CURSOR_CTL		0x06
+
+struct matrox_device
+{
+	void __iomem *base_addr;
+	void __iomem *port_index;
+	void __iomem *port_data;
+	u8 data_mask;
+
+	unsigned long phys_addr;
+	void __iomem *virt_addr;
+	unsigned long found;
+
+	struct w1_bus_master *bus_master;
+};
+
+static u8 matrox_w1_read_ddc_bit(void *);
+static void matrox_w1_write_ddc_bit(void *, u8);
+
+/*
+ * These functions read and write DDC Data bit.
+ *
+ * Using tristate pins, since i can't find any open-drain pin in whole motherboard.
+ * Unfortunately we can't connect to Intel's 82801xx IO controller
+ * since we don't know motherboard schema, wich has pretty unused(may be not) GPIO.
+ *
+ * I've heard that PIIX also has open drain pin.
+ *
+ * Port mapping.
+ */
+static __inline__ u8 matrox_w1_read_reg(struct matrox_device *dev, u8 reg)
+{
+	u8 ret;
+
+	writeb(reg, dev->port_index);
+	ret = readb(dev->port_data);
+	barrier();
+
+	return ret;
+}
+
+static __inline__ void matrox_w1_write_reg(struct matrox_device *dev, u8 reg, u8 val)
+{
+	writeb(reg, dev->port_index);
+	writeb(val, dev->port_data);
+	wmb();
+}
+
+static void matrox_w1_write_ddc_bit(void *data, u8 bit)
+{
+	u8 ret;
+	struct matrox_device *dev = data;
+
+	if (bit)
+		bit = 0;
+	else
+		bit = dev->data_mask;
+
+	ret = matrox_w1_read_reg(dev, MATROX_GET_CONTROL);
+	matrox_w1_write_reg(dev, MATROX_GET_CONTROL, ((ret & ~dev->data_mask) | bit));
+	matrox_w1_write_reg(dev, MATROX_GET_DATA, 0x00);
+}
+
+static u8 matrox_w1_read_ddc_bit(void *data)
+{
+	u8 ret;
+	struct matrox_device *dev = data;
+
+	ret = matrox_w1_read_reg(dev, MATROX_GET_DATA);
+
+	return ret;
+}
+
+static void matrox_w1_hw_init(struct matrox_device *dev)
+{
+	matrox_w1_write_reg(dev, MATROX_GET_DATA, 0xFF);
+	matrox_w1_write_reg(dev, MATROX_GET_CONTROL, 0x00);
+}
+
+static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct matrox_device *dev;
+	int err;
+
+	assert(pdev != NULL);
+	assert(ent != NULL);
+
+	if (pdev->vendor != PCI_VENDOR_ID_MATROX || pdev->device != PCI_DEVICE_ID_MATROX_G400)
+		return -ENODEV;
+
+	dev = kmalloc(sizeof(struct matrox_device) +
+		       sizeof(struct w1_bus_master), GFP_KERNEL);
+	if (!dev) {
+		dev_err(&pdev->dev,
+			"%s: Failed to create new matrox_device object.\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	memset(dev, 0, sizeof(struct matrox_device) + sizeof(struct w1_bus_master));
+
+	dev->bus_master = (struct w1_bus_master *)(dev + 1);
+
+	/*
+	 * True for G400, for some other we need resource 0, see drivers/video/matrox/matroxfb_base.c
+	 */
+
+	dev->phys_addr = pci_resource_start(pdev, 1);
+
+	dev->virt_addr = ioremap_nocache(dev->phys_addr, 16384);
+	if (!dev->virt_addr) {
+		dev_err(&pdev->dev, "%s: failed to ioremap(0x%lx, %d).\n",
+			__func__, dev->phys_addr, 16384);
+		err = -EIO;
+		goto err_out_free_device;
+	}
+
+	dev->base_addr = dev->virt_addr + MATROX_BASE;
+	dev->port_index = dev->base_addr + MATROX_PORT_INDEX_OFFSET;
+	dev->port_data = dev->base_addr + MATROX_PORT_DATA_OFFSET;
+	dev->data_mask = (MATROX_G400_DDC_DATA);
+
+	matrox_w1_hw_init(dev);
+
+	dev->bus_master->data = dev;
+	dev->bus_master->read_bit = &matrox_w1_read_ddc_bit;
+	dev->bus_master->write_bit = &matrox_w1_write_ddc_bit;
+
+	err = w1_add_master_device(dev->bus_master);
+	if (err)
+		goto err_out_free_device;
+
+	pci_set_drvdata(pdev, dev);
+
+	dev->found = 1;
+
+	dev_info(&pdev->dev, "Matrox G400 GPIO transport layer for 1-wire.\n");
+
+	return 0;
+
+err_out_free_device:
+	kfree(dev);
+
+	return err;
+}
+
+static void __devexit matrox_w1_remove(struct pci_dev *pdev)
+{
+	struct matrox_device *dev = pci_get_drvdata(pdev);
+
+	assert(dev != NULL);
+
+	if (dev->found) {
+		w1_remove_master_device(dev->bus_master);
+		iounmap(dev->virt_addr);
+	}
+	kfree(dev);
+}
+
+static int __init matrox_w1_init(void)
+{
+	return pci_register_driver(&matrox_w1_pci_driver);
+}
+
+static void __exit matrox_w1_fini(void)
+{
+	pci_unregister_driver(&matrox_w1_pci_driver);
+}
+
+module_init(matrox_w1_init);
+module_exit(matrox_w1_fini);
diff -urN oldtree/drivers/w1/matrox_w1.c newtree/drivers/w1/matrox_w1.c
--- oldtree/drivers/w1/matrox_w1.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/w1/matrox_w1.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,247 +0,0 @@
-/*
- *	matrox_w1.c
- *
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
- *
- * 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/atomic.h>
-#include <asm/types.h>
-#include <asm/io.h>
-
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/timer.h>
-#include <linux/slab.h>
-#include <linux/pci_ids.h>
-#include <linux/pci.h>
-#include <linux/timer.h>
-
-#include "w1.h"
-#include "w1_int.h"
-#include "w1_log.h"
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
-MODULE_DESCRIPTION("Driver for transport(Dallas 1-wire prtocol) over VGA DDC(matrox gpio).");
-
-static struct pci_device_id matrox_w1_tbl[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400) },
-	{ },
-};
-MODULE_DEVICE_TABLE(pci, matrox_w1_tbl);
-
-static int __devinit matrox_w1_probe(struct pci_dev *, const struct pci_device_id *);
-static void __devexit matrox_w1_remove(struct pci_dev *);
-
-static struct pci_driver matrox_w1_pci_driver = {
-	.name = "matrox_w1",
-	.id_table = matrox_w1_tbl,
-	.probe = matrox_w1_probe,
-	.remove = __devexit_p(matrox_w1_remove),
-};
-
-/*
- * Matrox G400 DDC registers.
- */
-
-#define MATROX_G400_DDC_CLK		(1<<4)
-#define MATROX_G400_DDC_DATA		(1<<1)
-
-#define MATROX_BASE			0x3C00
-#define MATROX_STATUS			0x1e14
-
-#define MATROX_PORT_INDEX_OFFSET	0x00
-#define MATROX_PORT_DATA_OFFSET		0x0A
-
-#define MATROX_GET_CONTROL		0x2A
-#define MATROX_GET_DATA			0x2B
-#define MATROX_CURSOR_CTL		0x06
-
-struct matrox_device
-{
-	void __iomem *base_addr;
-	void __iomem *port_index;
-	void __iomem *port_data;
-	u8 data_mask;
-
-	unsigned long phys_addr;
-	void __iomem *virt_addr;
-	unsigned long found;
-
-	struct w1_bus_master *bus_master;
-};
-
-static u8 matrox_w1_read_ddc_bit(unsigned long);
-static void matrox_w1_write_ddc_bit(unsigned long, u8);
-
-/*
- * These functions read and write DDC Data bit.
- *
- * Using tristate pins, since i can't find any open-drain pin in whole motherboard.
- * Unfortunately we can't connect to Intel's 82801xx IO controller
- * since we don't know motherboard schema, wich has pretty unused(may be not) GPIO.
- *
- * I've heard that PIIX also has open drain pin.
- *
- * Port mapping.
- */
-static __inline__ u8 matrox_w1_read_reg(struct matrox_device *dev, u8 reg)
-{
-	u8 ret;
-
-	writeb(reg, dev->port_index);
-	ret = readb(dev->port_data);
-	barrier();
-
-	return ret;
-}
-
-static __inline__ void matrox_w1_write_reg(struct matrox_device *dev, u8 reg, u8 val)
-{
-	writeb(reg, dev->port_index);
-	writeb(val, dev->port_data);
-	wmb();
-}
-
-static void matrox_w1_write_ddc_bit(unsigned long data, u8 bit)
-{
-	u8 ret;
-	struct matrox_device *dev = (struct matrox_device *) data;
-
-	if (bit)
-		bit = 0;
-	else
-		bit = dev->data_mask;
-
-	ret = matrox_w1_read_reg(dev, MATROX_GET_CONTROL);
-	matrox_w1_write_reg(dev, MATROX_GET_CONTROL, ((ret & ~dev->data_mask) | bit));
-	matrox_w1_write_reg(dev, MATROX_GET_DATA, 0x00);
-}
-
-static u8 matrox_w1_read_ddc_bit(unsigned long data)
-{
-	u8 ret;
-	struct matrox_device *dev = (struct matrox_device *) data;
-
-	ret = matrox_w1_read_reg(dev, MATROX_GET_DATA);
-
-	return ret;
-}
-
-static void matrox_w1_hw_init(struct matrox_device *dev)
-{
-	matrox_w1_write_reg(dev, MATROX_GET_DATA, 0xFF);
-	matrox_w1_write_reg(dev, MATROX_GET_CONTROL, 0x00);
-}
-
-static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-	struct matrox_device *dev;
-	int err;
-
-	assert(pdev != NULL);
-	assert(ent != NULL);
-
-	if (pdev->vendor != PCI_VENDOR_ID_MATROX || pdev->device != PCI_DEVICE_ID_MATROX_G400)
-		return -ENODEV;
-
-	dev = kmalloc(sizeof(struct matrox_device) +
-		       sizeof(struct w1_bus_master), GFP_KERNEL);
-	if (!dev) {
-		dev_err(&pdev->dev,
-			"%s: Failed to create new matrox_device object.\n",
-			__func__);
-		return -ENOMEM;
-	}
-
-	memset(dev, 0, sizeof(struct matrox_device) + sizeof(struct w1_bus_master));
-
-	dev->bus_master = (struct w1_bus_master *)(dev + 1);
-
-	/*
-	 * True for G400, for some other we need resource 0, see drivers/video/matrox/matroxfb_base.c
-	 */
-
-	dev->phys_addr = pci_resource_start(pdev, 1);
-
-	dev->virt_addr = ioremap_nocache(dev->phys_addr, 16384);
-	if (!dev->virt_addr) {
-		dev_err(&pdev->dev, "%s: failed to ioremap(0x%lx, %d).\n",
-			__func__, dev->phys_addr, 16384);
-		err = -EIO;
-		goto err_out_free_device;
-	}
-
-	dev->base_addr = dev->virt_addr + MATROX_BASE;
-	dev->port_index = dev->base_addr + MATROX_PORT_INDEX_OFFSET;
-	dev->port_data = dev->base_addr + MATROX_PORT_DATA_OFFSET;
-	dev->data_mask = (MATROX_G400_DDC_DATA);
-
-	matrox_w1_hw_init(dev);
-
-	dev->bus_master->data = (unsigned long) dev;
-	dev->bus_master->read_bit = &matrox_w1_read_ddc_bit;
-	dev->bus_master->write_bit = &matrox_w1_write_ddc_bit;
-
-	err = w1_add_master_device(dev->bus_master);
-	if (err)
-		goto err_out_free_device;
-
-	pci_set_drvdata(pdev, dev);
-
-	dev->found = 1;
-
-	dev_info(&pdev->dev, "Matrox G400 GPIO transport layer for 1-wire.\n");
-
-	return 0;
-
-err_out_free_device:
-	kfree(dev);
-
-	return err;
-}
-
-static void __devexit matrox_w1_remove(struct pci_dev *pdev)
-{
-	struct matrox_device *dev = pci_get_drvdata(pdev);
-
-	assert(dev != NULL);
-
-	if (dev->found) {
-		w1_remove_master_device(dev->bus_master);
-		iounmap(dev->virt_addr);
-	}
-	kfree(dev);
-}
-
-static int __init matrox_w1_init(void)
-{
-	return pci_register_driver(&matrox_w1_pci_driver);
-}
-
-static void __exit matrox_w1_fini(void)
-{
-	pci_unregister_driver(&matrox_w1_pci_driver);
-}
-
-module_init(matrox_w1_init);
-module_exit(matrox_w1_fini);
diff -urN oldtree/drivers/w1/slaves/Kconfig newtree/drivers/w1/slaves/Kconfig
--- oldtree/drivers/w1/slaves/Kconfig	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/w1/slaves/Kconfig	2006-02-21 15:58:14.580929920 +0000
@@ -0,0 +1,38 @@
+#
+# 1-wire slaves configuration
+#
+
+menu "1-wire Slaves"
+	depends on W1
+
+config W1_SLAVE_THERM
+	tristate "Thermal family implementation"
+	depends on W1
+	help
+	  Say Y here if you want to connect 1-wire thermal sensors to you
+	  wire.
+
+config W1_SLAVE_SMEM
+	tristate "Simple 64bit memory family implementation"
+	depends on W1
+	help
+	  Say Y here if you want to connect 1-wire
+	  simple 64bit memory rom(ds2401/ds2411/ds1990*) to you wire.
+
+config W1_SLAVE_DS2433
+	tristate "4kb EEPROM family support (DS2433)"
+	depends on W1
+	help
+	  Say Y here if you want to use a 1-wire
+	  4kb EEPROM family device (DS2433).
+
+config W1_SLAVE_DS2433_CRC
+	bool "Protect DS2433 data with a CRC16"
+	depends on W1_DS2433
+	select CRC16
+	help
+	  Say Y here to protect DS2433 data with a CRC16.
+	  Each block has 30 bytes of data and a two byte CRC16.
+	  Full block writes are only allowed if the CRC is valid.
+
+endmenu
diff -urN oldtree/drivers/w1/slaves/Makefile newtree/drivers/w1/slaves/Makefile
--- oldtree/drivers/w1/slaves/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/w1/slaves/Makefile	2006-02-21 15:58:14.580929920 +0000
@@ -0,0 +1,12 @@
+#
+# Makefile for the Dallas's 1-wire slaves.
+#
+
+ifeq ($(CONFIG_W1_SLAVE_DS2433_CRC), y)
+EXTRA_CFLAGS += -DCONFIG_W1_F23_CRC
+endif
+
+obj-$(CONFIG_W1_SLAVE_THERM)	+= w1_therm.o
+obj-$(CONFIG_W1_SLAVE_SMEM)	+= w1_smem.o
+obj-$(CONFIG_W1_SLAVE_DS2433)	+= w1_ds2433.o
+
diff -urN oldtree/drivers/w1/slaves/w1_ds2433.c newtree/drivers/w1/slaves/w1_ds2433.c
--- oldtree/drivers/w1/slaves/w1_ds2433.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/w1/slaves/w1_ds2433.c	2006-02-21 15:58:14.581929768 +0000
@@ -0,0 +1,329 @@
+/*
+ *	w1_ds2433.c - w1 family 23 (DS2433) driver
+ *
+ * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#ifdef CONFIG_W1_F23_CRC
+#include <linux/crc16.h>
+
+#define CRC16_INIT		0
+#define CRC16_VALID		0xb001
+
+#endif
+
+#include "../w1.h"
+#include "../w1_io.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
+MODULE_DESCRIPTION("w1 family 23 driver for DS2433, 4kb EEPROM");
+
+#define W1_EEPROM_SIZE		512
+#define W1_PAGE_COUNT		16
+#define W1_PAGE_SIZE		32
+#define W1_PAGE_BITS		5
+#define W1_PAGE_MASK		0x1F
+
+#define W1_F23_TIME		300
+
+#define W1_F23_READ_EEPROM	0xF0
+#define W1_F23_WRITE_SCRATCH	0x0F
+#define W1_F23_READ_SCRATCH	0xAA
+#define W1_F23_COPY_SCRATCH	0x55
+
+struct w1_f23_data {
+	u8	memory[W1_EEPROM_SIZE];
+	u32	validcrc;
+};
+
+/**
+ * Check the file size bounds and adjusts count as needed.
+ * This would not be needed if the file size didn't reset to 0 after a write.
+ */
+static inline size_t w1_f23_fix_count(loff_t off, size_t count, size_t size)
+{
+	if (off > size)
+		return 0;
+
+	if ((off + count) > size)
+		return (size - off);
+
+	return count;
+}
+
+#ifdef CONFIG_W1_F23_CRC
+static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data,
+				int block)
+{
+	u8	wrbuf[3];
+	int	off = block * W1_PAGE_SIZE;
+
+	if (data->validcrc & (1 << block))
+		return 0;
+
+	if (w1_reset_select_slave(sl)) {
+		data->validcrc = 0;
+		return -EIO;
+	}
+
+	wrbuf[0] = W1_F23_READ_EEPROM;
+	wrbuf[1] = off & 0xff;
+	wrbuf[2] = off >> 8;
+	w1_write_block(sl->master, wrbuf, 3);
+	w1_read_block(sl->master, &data->memory[off], W1_PAGE_SIZE);
+
+	/* cache the block if the CRC is valid */
+	if (crc16(CRC16_INIT, &data->memory[off], W1_PAGE_SIZE) == CRC16_VALID)
+		data->validcrc |= (1 << block);
+
+	return 0;
+}
+#endif	/* CONFIG_W1_F23_CRC */
+
+static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off,
+			       size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+#ifdef CONFIG_W1_F23_CRC
+	struct w1_f23_data *data = sl->family_data;
+	int i, min_page, max_page;
+#else
+	u8 wrbuf[3];
+#endif
+
+	if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0)
+		return 0;
+
+	atomic_inc(&sl->refcnt);
+	if (down_interruptible(&sl->master->mutex)) {
+		count = 0;
+		goto out_dec;
+	}
+
+#ifdef CONFIG_W1_F23_CRC
+
+	min_page = (off >> W1_PAGE_BITS);
+	max_page = (off + count - 1) >> W1_PAGE_BITS;
+	for (i = min_page; i <= max_page; i++) {
+		if (w1_f23_refresh_block(sl, data, i)) {
+			count = -EIO;
+			goto out_up;
+		}
+	}
+	memcpy(buf, &data->memory[off], count);
+
+#else 	/* CONFIG_W1_F23_CRC */
+
+	/* read directly from the EEPROM */
+	if (w1_reset_select_slave(sl)) {
+		count = -EIO;
+		goto out_up;
+	}
+
+	wrbuf[0] = W1_F23_READ_EEPROM;
+	wrbuf[1] = off & 0xff;
+	wrbuf[2] = off >> 8;
+	w1_write_block(sl->master, wrbuf, 3);
+	w1_read_block(sl->master, buf, count);
+
+#endif	/* CONFIG_W1_F23_CRC */
+
+out_up:
+	up(&sl->master->mutex);
+out_dec:
+	atomic_dec(&sl->refcnt);
+
+	return count;
+}
+
+/**
+ * Writes to the scratchpad and reads it back for verification.
+ * Then copies the scratchpad to EEPROM.
+ * The data must be on one page.
+ * The master must be locked.
+ *
+ * @param sl	The slave structure
+ * @param addr	Address for the write
+ * @param len   length must be <= (W1_PAGE_SIZE - (addr & W1_PAGE_MASK))
+ * @param data	The data to write
+ * @return	0=Success -1=failure
+ */
+static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data)
+{
+	u8 wrbuf[4];
+	u8 rdbuf[W1_PAGE_SIZE + 3];
+	u8 es = (addr + len - 1) & 0x1f;
+
+	/* Write the data to the scratchpad */
+	if (w1_reset_select_slave(sl))
+		return -1;
+
+	wrbuf[0] = W1_F23_WRITE_SCRATCH;
+	wrbuf[1] = addr & 0xff;
+	wrbuf[2] = addr >> 8;
+
+	w1_write_block(sl->master, wrbuf, 3);
+	w1_write_block(sl->master, data, len);
+
+	/* Read the scratchpad and verify */
+	if (w1_reset_select_slave(sl))
+		return -1;
+
+	w1_write_8(sl->master, W1_F23_READ_SCRATCH);
+	w1_read_block(sl->master, rdbuf, len + 3);
+
+	/* Compare what was read against the data written */
+	if ((rdbuf[0] != wrbuf[1]) || (rdbuf[1] != wrbuf[2]) ||
+	    (rdbuf[2] != es) || (memcmp(data, &rdbuf[3], len) != 0))
+		return -1;
+
+	/* Copy the scratchpad to EEPROM */
+	if (w1_reset_select_slave(sl))
+		return -1;
+
+	wrbuf[0] = W1_F23_COPY_SCRATCH;
+	wrbuf[3] = es;
+	w1_write_block(sl->master, wrbuf, 4);
+
+	/* Sleep for 5 ms to wait for the write to complete */
+	msleep(5);
+
+	/* Reset the bus to wake up the EEPROM (this may not be needed) */
+	w1_reset_bus(sl->master);
+
+	return 0;
+}
+
+static ssize_t w1_f23_write_bin(struct kobject *kobj, char *buf, loff_t off,
+				size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	int addr, len, idx;
+
+	if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0)
+		return 0;
+
+#ifdef CONFIG_W1_F23_CRC
+	/* can only write full blocks in cached mode */
+	if ((off & W1_PAGE_MASK) || (count & W1_PAGE_MASK)) {
+		dev_err(&sl->dev, "invalid offset/count off=%d cnt=%zd\n",
+			(int)off, count);
+		return -EINVAL;
+	}
+
+	/* make sure the block CRCs are valid */
+	for (idx = 0; idx < count; idx += W1_PAGE_SIZE) {
+		if (crc16(CRC16_INIT, &buf[idx], W1_PAGE_SIZE) != CRC16_VALID) {
+			dev_err(&sl->dev, "bad CRC at offset %d\n", (int)off);
+			return -EINVAL;
+		}
+	}
+#endif	/* CONFIG_W1_F23_CRC */
+
+	atomic_inc(&sl->refcnt);
+	if (down_interruptible(&sl->master->mutex)) {
+		count = 0;
+		goto out_dec;
+	}
+
+	/* Can only write data to one page at a time */
+	idx = 0;
+	while (idx < count) {
+		addr = off + idx;
+		len = W1_PAGE_SIZE - (addr & W1_PAGE_MASK);
+		if (len > (count - idx))
+			len = count - idx;
+
+		if (w1_f23_write(sl, addr, len, &buf[idx]) < 0) {
+			count = -EIO;
+			goto out_up;
+		}
+		idx += len;
+	}
+
+out_up:
+	up(&sl->master->mutex);
+out_dec:
+	atomic_dec(&sl->refcnt);
+
+	return count;
+}
+
+static struct bin_attribute w1_f23_bin_attr = {
+	.attr = {
+		.name = "eeprom",
+		.mode = S_IRUGO | S_IWUSR,
+		.owner = THIS_MODULE,
+	},
+	.size = W1_EEPROM_SIZE,
+	.read = w1_f23_read_bin,
+	.write = w1_f23_write_bin,
+};
+
+static int w1_f23_add_slave(struct w1_slave *sl)
+{
+	int err;
+#ifdef CONFIG_W1_F23_CRC
+	struct w1_f23_data *data;
+
+	data = kmalloc(sizeof(struct w1_f23_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+	memset(data, 0, sizeof(struct w1_f23_data));
+	sl->family_data = data;
+
+#endif	/* CONFIG_W1_F23_CRC */
+
+	err = sysfs_create_bin_file(&sl->dev.kobj, &w1_f23_bin_attr);
+
+#ifdef CONFIG_W1_F23_CRC
+	if (err)
+		kfree(data);
+#endif	/* CONFIG_W1_F23_CRC */
+
+	return err;
+}
+
+static void w1_f23_remove_slave(struct w1_slave *sl)
+{
+#ifdef CONFIG_W1_F23_CRC
+	kfree(sl->family_data);
+	sl->family_data = NULL;
+#endif	/* CONFIG_W1_F23_CRC */
+	sysfs_remove_bin_file(&sl->dev.kobj, &w1_f23_bin_attr);
+}
+
+static struct w1_family_ops w1_f23_fops = {
+	.add_slave      = w1_f23_add_slave,
+	.remove_slave   = w1_f23_remove_slave,
+};
+
+static struct w1_family w1_family_23 = {
+	.fid = W1_EEPROM_DS2433,
+	.fops = &w1_f23_fops,
+};
+
+static int __init w1_f23_init(void)
+{
+	return w1_register_family(&w1_family_23);
+}
+
+static void __exit w1_f23_fini(void)
+{
+	w1_unregister_family(&w1_family_23);
+}
+
+module_init(w1_f23_init);
+module_exit(w1_f23_fini);
diff -urN oldtree/drivers/w1/slaves/w1_smem.c newtree/drivers/w1/slaves/w1_smem.c
--- oldtree/drivers/w1/slaves/w1_smem.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/w1/slaves/w1_smem.c	2006-02-21 15:58:14.581929768 +0000
@@ -0,0 +1,71 @@
+/*
+ *	w1_smem.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems 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/types.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+
+#include "../w1.h"
+#include "../w1_io.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, 64bit memory family.");
+
+static struct w1_family w1_smem_family_01 = {
+	.fid = W1_FAMILY_SMEM_01,
+};
+
+static struct w1_family w1_smem_family_81 = {
+	.fid = W1_FAMILY_SMEM_81,
+};
+
+static int __init w1_smem_init(void)
+{
+	int err;
+
+	err = w1_register_family(&w1_smem_family_01);
+	if (err)
+		return err;
+
+	err = w1_register_family(&w1_smem_family_81);
+	if (err) {
+		w1_unregister_family(&w1_smem_family_01);
+		return err;
+	}
+
+	return 0;
+}
+
+static void __exit w1_smem_fini(void)
+{
+	w1_unregister_family(&w1_smem_family_01);
+	w1_unregister_family(&w1_smem_family_81);
+}
+
+module_init(w1_smem_init);
+module_exit(w1_smem_fini);
diff -urN oldtree/drivers/w1/slaves/w1_therm.c newtree/drivers/w1/slaves/w1_therm.c
--- oldtree/drivers/w1/slaves/w1_therm.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/drivers/w1/slaves/w1_therm.c	2006-02-21 15:58:14.582929616 +0000
@@ -0,0 +1,268 @@
+/*
+ *	w1_therm.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the therms 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/types.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+
+#include "../w1.h"
+#include "../w1_io.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family.");
+
+static u8 bad_roms[][9] = {
+				{0xaa, 0x00, 0x4b, 0x46, 0xff, 0xff, 0x0c, 0x10, 0x87},
+				{}
+			};
+
+static ssize_t w1_therm_read_bin(struct kobject *, char *, loff_t, size_t);
+
+static struct bin_attribute w1_therm_bin_attr = {
+	.attr = {
+		.name = "w1_slave",
+		.mode = S_IRUGO,
+		.owner = THIS_MODULE,
+	},
+	.size = W1_SLAVE_DATA_SIZE,
+	.read = w1_therm_read_bin,
+};
+
+static int w1_therm_add_slave(struct w1_slave *sl)
+{
+	return sysfs_create_bin_file(&sl->dev.kobj, &w1_therm_bin_attr);
+}
+
+static void w1_therm_remove_slave(struct w1_slave *sl)
+{
+	sysfs_remove_bin_file(&sl->dev.kobj, &w1_therm_bin_attr);
+}
+
+static struct w1_family_ops w1_therm_fops = {
+	.add_slave	= w1_therm_add_slave,
+	.remove_slave	= w1_therm_remove_slave,
+};
+
+static struct w1_family w1_therm_family_DS18S20 = {
+	.fid = W1_THERM_DS18S20,
+	.fops = &w1_therm_fops,
+};
+
+static struct w1_family w1_therm_family_DS18B20 = {
+	.fid = W1_THERM_DS18B20,
+	.fops = &w1_therm_fops,
+};
+
+static struct w1_family w1_therm_family_DS1822 = {
+	.fid = W1_THERM_DS1822,
+	.fops = &w1_therm_fops,
+};
+
+struct w1_therm_family_converter
+{
+	u8			broken;
+	u16			reserved;
+	struct w1_family	*f;
+	int			(*convert)(u8 rom[9]);
+};
+
+static inline int w1_DS18B20_convert_temp(u8 rom[9]);
+static inline int w1_DS18S20_convert_temp(u8 rom[9]);
+
+static struct w1_therm_family_converter w1_therm_families[] = {
+	{
+		.f		= &w1_therm_family_DS18S20,
+		.convert 	= w1_DS18S20_convert_temp
+	},
+	{
+		.f		= &w1_therm_family_DS1822,
+		.convert 	= w1_DS18B20_convert_temp
+	},
+	{
+		.f		= &w1_therm_family_DS18B20,
+		.convert 	= w1_DS18B20_convert_temp
+	},
+};
+
+static inline int w1_DS18B20_convert_temp(u8 rom[9])
+{
+	int t = (rom[1] << 8) | rom[0];
+	t /= 16;
+	return t;
+}
+
+static inline int w1_DS18S20_convert_temp(u8 rom[9])
+{
+	int t, h;
+
+	if (!rom[7])
+		return 0;
+
+	if (rom[1] == 0)
+		t = ((s32)rom[0] >> 1)*1000;
+	else
+		t = 1000*(-1*(s32)(0x100-rom[0]) >> 1);
+
+	t -= 250;
+	h = 1000*((s32)rom[7] - (s32)rom[6]);
+	h /= (s32)rom[7];
+	t += h;
+
+	return t;
+}
+
+static inline int w1_convert_temp(u8 rom[9], u8 fid)
+{
+	int i;
+
+	for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i)
+		if (w1_therm_families[i].f->fid == fid)
+			return w1_therm_families[i].convert(rom);
+
+	return 0;
+}
+
+static int w1_therm_check_rom(u8 rom[9])
+{
+	int i;
+
+	for (i=0; i<sizeof(bad_roms)/9; ++i)
+		if (!memcmp(bad_roms[i], rom, 9))
+			return 1;
+
+	return 0;
+}
+
+static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+	struct w1_slave *sl = kobj_to_w1_slave(kobj);
+	struct w1_master *dev = sl->master;
+	u8 rom[9], crc, verdict;
+	int i, max_trying = 10;
+
+	atomic_inc(&sl->refcnt);
+	smp_mb__after_atomic_inc();
+	if (down_interruptible(&sl->master->mutex)) {
+		count = 0;
+		goto out_dec;
+	}
+
+	if (off > W1_SLAVE_DATA_SIZE) {
+		count = 0;
+		goto out;
+	}
+	if (off + count > W1_SLAVE_DATA_SIZE) {
+		count = 0;
+		goto out;
+	}
+
+	memset(buf, 0, count);
+	memset(rom, 0, sizeof(rom));
+
+	count = 0;
+	verdict = 0;
+	crc = 0;
+
+	while (max_trying--) {
+		if (!w1_reset_select_slave(sl)) {
+			int count = 0;
+			unsigned int tm = 750;
+
+			w1_write_8(dev, W1_CONVERT_TEMP);
+
+			while (tm) {
+				tm = msleep_interruptible(tm);
+				if (signal_pending(current))
+					flush_signals(current);
+			}
+
+			if (!w1_reset_select_slave(sl)) {
+
+				w1_write_8(dev, W1_READ_SCRATCHPAD);
+				if ((count = w1_read_block(dev, rom, 9)) != 9) {
+					dev_warn(&dev->dev, "w1_read_block() returned %d instead of 9.\n", count);
+				}
+
+				crc = w1_calc_crc8(rom, 8);
+
+				if (rom[8] == crc && rom[0])
+					verdict = 1;
+			}
+		}
+
+		if (!w1_therm_check_rom(rom))
+			break;
+	}
+
+	for (i = 0; i < 9; ++i)
+		count += sprintf(buf + count, "%02x ", rom[i]);
+	count += sprintf(buf + count, ": crc=%02x %s\n",
+			   crc, (verdict) ? "YES" : "NO");
+	if (verdict)
+		memcpy(sl->rom, rom, sizeof(sl->rom));
+	else
+		dev_warn(&dev->dev, "18S20 doesn't respond to CONVERT_TEMP.\n");
+
+	for (i = 0; i < 9; ++i)
+		count += sprintf(buf + count, "%02x ", sl->rom[i]);
+
+	count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom, sl->family->fid));
+out:
+	up(&dev->mutex);
+out_dec:
+	smp_mb__before_atomic_inc();
+	atomic_dec(&sl->refcnt);
+
+	return count;
+}
+
+static int __init w1_therm_init(void)
+{
+	int err, i;
+
+	for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i) {
+		err = w1_register_family(w1_therm_families[i].f);
+		if (err)
+			w1_therm_families[i].broken = 1;
+	}
+
+	return 0;
+}
+
+static void __exit w1_therm_fini(void)
+{
+	int i;
+
+	for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i)
+		if (!w1_therm_families[i].broken)
+			w1_unregister_family(w1_therm_families[i].f);
+}
+
+module_init(w1_therm_init);
+module_exit(w1_therm_fini);
diff -urN oldtree/drivers/w1/w1.c newtree/drivers/w1/w1.c
--- oldtree/drivers/w1/w1.c	2006-02-19 11:41:04.885600376 +0000
+++ newtree/drivers/w1/w1.c	2006-02-21 15:58:14.650919280 +0000
@@ -164,11 +164,12 @@
 	.release = &w1_master_release
 };
 
-struct device_driver w1_slave_driver = {
+static struct device_driver w1_slave_driver = {
 	.name = "w1_slave_driver",
 	.bus = &w1_bus_type,
 };
 
+#if 0
 struct device w1_slave_device = {
 	.parent = NULL,
 	.bus = &w1_bus_type,
@@ -176,6 +177,7 @@
 	.driver = &w1_slave_driver,
 	.release = &w1_slave_release
 };
+#endif  /*  0  */
 
 static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -355,7 +357,7 @@
 	return sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group);
 }
 
-void w1_destroy_master_attributes(struct w1_master *master)
+static void w1_destroy_master_attributes(struct w1_master *master)
 {
 	sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
 }
@@ -386,11 +388,14 @@
 	if (dev->driver != &w1_slave_driver || !sl)
 		return 0;
 
-	err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, &cur_len, "W1_FID=%02X", sl->reg_num.family);
+	err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size,
+			&cur_len, "W1_FID=%02X", sl->reg_num.family);
 	if (err)
 		return err;
 
-	err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, &cur_len, "W1_SLAVE_ID=%024LX", (u64)sl->reg_num.id);
+	err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size,
+			&cur_len, "W1_SLAVE_ID=%024LX",
+			(unsigned long long)sl->reg_num.id);
 	if (err)
 		return err;
 
@@ -552,7 +557,7 @@
 	kfree(sl);
 }
 
-static struct w1_master *w1_search_master(unsigned long data)
+static struct w1_master *w1_search_master(void *data)
 {
 	struct w1_master *dev;
 	int found = 0;
@@ -583,7 +588,7 @@
 	spin_unlock_bh(&w1_mlock);
 }
 
-static void w1_slave_found(unsigned long data, u64 rn)
+static void w1_slave_found(void *data, u64 rn)
 {
 	int slave_count;
 	struct w1_slave *sl;
@@ -595,8 +600,8 @@
 
 	dev = w1_search_master(data);
 	if (!dev) {
-		printk(KERN_ERR "Failed to find w1 master device for data %08lx, it is impossible.\n",
-				data);
+		printk(KERN_ERR "Failed to find w1 master device for data %p, "
+		       "it is impossible.\n", data);
 		return;
 	}
 
diff -urN oldtree/drivers/w1/w1.h newtree/drivers/w1/w1.h
--- oldtree/drivers/w1/w1.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/w1/w1.h	2006-02-21 15:58:14.613924904 +0000
@@ -80,7 +80,7 @@
 	struct completion	released;
 };
 
-typedef void (* w1_slave_found_callback)(unsigned long, u64);
+typedef void (* w1_slave_found_callback)(void *, u64);
 
 
 /**
@@ -93,16 +93,16 @@
 struct w1_bus_master
 {
 	/** the first parameter in all the functions below */
-	unsigned long	data;
+	void		*data;
 
 	/**
 	 * Sample the line level
 	 * @return the level read (0 or 1)
 	 */
-	u8		(*read_bit)(unsigned long);
+	u8		(*read_bit)(void *);
 
 	/** Sets the line level */
-	void		(*write_bit)(unsigned long, u8);
+	void		(*write_bit)(void *, u8);
 
 	/**
 	 * touch_bit is the lowest-level function for devices that really
@@ -111,42 +111,42 @@
 	 * touch_bit(1) = write-1 / read cycle
 	 * @return the bit read (0 or 1)
 	 */
-	u8		(*touch_bit)(unsigned long, u8);
+	u8		(*touch_bit)(void *, u8);
 
 	/**
 	 * Reads a bytes. Same as 8 touch_bit(1) calls.
 	 * @return the byte read
 	 */
-	u8		(*read_byte)(unsigned long);
+	u8		(*read_byte)(void *);
 
 	/**
 	 * Writes a byte. Same as 8 touch_bit(x) calls.
 	 */
-	void		(*write_byte)(unsigned long, u8);
+	void		(*write_byte)(void *, u8);
 
 	/**
 	 * Same as a series of read_byte() calls
 	 * @return the number of bytes read
 	 */
-	u8		(*read_block)(unsigned long, u8 *, int);
+	u8		(*read_block)(void *, u8 *, int);
 
 	/** Same as a series of write_byte() calls */
-	void		(*write_block)(unsigned long, const u8 *, int);
+	void		(*write_block)(void *, const u8 *, int);
 
 	/**
 	 * Combines two reads and a smart write for ROM searches
 	 * @return bit0=Id bit1=comp_id bit2=dir_taken
 	 */
-	u8		(*triplet)(unsigned long, u8);
+	u8		(*triplet)(void *, u8);
 
 	/**
 	 * long write-0 with a read for the presence pulse detection
 	 * @return -1=Error, 0=Device present, 1=No device present
 	 */
-	u8		(*reset_bus)(unsigned long);
+	u8		(*reset_bus)(void *);
 
 	/** Really nice hardware can handles the ROM searches */
-	void		(*search)(unsigned long, w1_slave_found_callback);
+	void		(*search)(void *, w1_slave_found_callback);
 };
 
 #define W1_MASTER_NEED_EXIT		0
@@ -203,6 +203,16 @@
 	return container_of(dev, struct w1_master, dev);
 }
 
+extern int w1_max_slave_count;
+extern int w1_max_slave_ttl;
+extern spinlock_t w1_mlock;
+extern struct list_head w1_masters;
+extern struct device_driver w1_master_driver;
+extern struct device w1_master_device;
+
+int w1_process(void *data);
+void w1_reconnect_slaves(struct w1_family *f);
+
 #endif /* __KERNEL__ */
 
 #endif /* __W1_H */
diff -urN oldtree/drivers/w1/w1_ds2433.c newtree/drivers/w1/w1_ds2433.c
--- oldtree/drivers/w1/w1_ds2433.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/w1/w1_ds2433.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,329 +0,0 @@
-/*
- *	w1_ds2433.c - w1 family 23 (DS2433) driver
- *
- * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
- *
- * This source code is licensed under the GNU General Public License,
- * Version 2. See the file COPYING for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#ifdef CONFIG_W1_F23_CRC
-#include <linux/crc16.h>
-
-#define CRC16_INIT		0
-#define CRC16_VALID		0xb001
-
-#endif
-
-#include "w1.h"
-#include "w1_io.h"
-#include "w1_int.h"
-#include "w1_family.h"
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
-MODULE_DESCRIPTION("w1 family 23 driver for DS2433, 4kb EEPROM");
-
-#define W1_EEPROM_SIZE		512
-#define W1_PAGE_COUNT		16
-#define W1_PAGE_SIZE		32
-#define W1_PAGE_BITS		5
-#define W1_PAGE_MASK		0x1F
-
-#define W1_F23_TIME		300
-
-#define W1_F23_READ_EEPROM	0xF0
-#define W1_F23_WRITE_SCRATCH	0x0F
-#define W1_F23_READ_SCRATCH	0xAA
-#define W1_F23_COPY_SCRATCH	0x55
-
-struct w1_f23_data {
-	u8	memory[W1_EEPROM_SIZE];
-	u32	validcrc;
-};
-
-/**
- * Check the file size bounds and adjusts count as needed.
- * This would not be needed if the file size didn't reset to 0 after a write.
- */
-static inline size_t w1_f23_fix_count(loff_t off, size_t count, size_t size)
-{
-	if (off > size)
-		return 0;
-
-	if ((off + count) > size)
-		return (size - off);
-
-	return count;
-}
-
-#ifdef CONFIG_W1_F23_CRC
-static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data,
-				int block)
-{
-	u8	wrbuf[3];
-	int	off = block * W1_PAGE_SIZE;
-
-	if (data->validcrc & (1 << block))
-		return 0;
-
-	if (w1_reset_select_slave(sl)) {
-		data->validcrc = 0;
-		return -EIO;
-	}
-
-	wrbuf[0] = W1_F23_READ_EEPROM;
-	wrbuf[1] = off & 0xff;
-	wrbuf[2] = off >> 8;
-	w1_write_block(sl->master, wrbuf, 3);
-	w1_read_block(sl->master, &data->memory[off], W1_PAGE_SIZE);
-
-	/* cache the block if the CRC is valid */
-	if (crc16(CRC16_INIT, &data->memory[off], W1_PAGE_SIZE) == CRC16_VALID)
-		data->validcrc |= (1 << block);
-
-	return 0;
-}
-#endif	/* CONFIG_W1_F23_CRC */
-
-static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off,
-			       size_t count)
-{
-	struct w1_slave *sl = kobj_to_w1_slave(kobj);
-#ifdef CONFIG_W1_F23_CRC
-	struct w1_f23_data *data = sl->family_data;
-	int i, min_page, max_page;
-#else
-	u8 wrbuf[3];
-#endif
-
-	if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0)
-		return 0;
-
-	atomic_inc(&sl->refcnt);
-	if (down_interruptible(&sl->master->mutex)) {
-		count = 0;
-		goto out_dec;
-	}
-
-#ifdef CONFIG_W1_F23_CRC
-
-	min_page = (off >> W1_PAGE_BITS);
-	max_page = (off + count - 1) >> W1_PAGE_BITS;
-	for (i = min_page; i <= max_page; i++) {
-		if (w1_f23_refresh_block(sl, data, i)) {
-			count = -EIO;
-			goto out_up;
-		}
-	}
-	memcpy(buf, &data->memory[off], count);
-
-#else 	/* CONFIG_W1_F23_CRC */
-
-	/* read directly from the EEPROM */
-	if (w1_reset_select_slave(sl)) {
-		count = -EIO;
-		goto out_up;
-	}
-
-	wrbuf[0] = W1_F23_READ_EEPROM;
-	wrbuf[1] = off & 0xff;
-	wrbuf[2] = off >> 8;
-	w1_write_block(sl->master, wrbuf, 3);
-	w1_read_block(sl->master, buf, count);
-
-#endif	/* CONFIG_W1_F23_CRC */
-
-out_up:
-	up(&sl->master->mutex);
-out_dec:
-	atomic_dec(&sl->refcnt);
-
-	return count;
-}
-
-/**
- * Writes to the scratchpad and reads it back for verification.
- * Then copies the scratchpad to EEPROM.
- * The data must be on one page.
- * The master must be locked.
- *
- * @param sl	The slave structure
- * @param addr	Address for the write
- * @param len   length must be <= (W1_PAGE_SIZE - (addr & W1_PAGE_MASK))
- * @param data	The data to write
- * @return	0=Success -1=failure
- */
-static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data)
-{
-	u8 wrbuf[4];
-	u8 rdbuf[W1_PAGE_SIZE + 3];
-	u8 es = (addr + len - 1) & 0x1f;
-
-	/* Write the data to the scratchpad */
-	if (w1_reset_select_slave(sl))
-		return -1;
-
-	wrbuf[0] = W1_F23_WRITE_SCRATCH;
-	wrbuf[1] = addr & 0xff;
-	wrbuf[2] = addr >> 8;
-
-	w1_write_block(sl->master, wrbuf, 3);
-	w1_write_block(sl->master, data, len);
-
-	/* Read the scratchpad and verify */
-	if (w1_reset_select_slave(sl))
-		return -1;
-
-	w1_write_8(sl->master, W1_F23_READ_SCRATCH);
-	w1_read_block(sl->master, rdbuf, len + 3);
-
-	/* Compare what was read against the data written */
-	if ((rdbuf[0] != wrbuf[1]) || (rdbuf[1] != wrbuf[2]) ||
-	    (rdbuf[2] != es) || (memcmp(data, &rdbuf[3], len) != 0))
-		return -1;
-
-	/* Copy the scratchpad to EEPROM */
-	if (w1_reset_select_slave(sl))
-		return -1;
-
-	wrbuf[0] = W1_F23_COPY_SCRATCH;
-	wrbuf[3] = es;
-	w1_write_block(sl->master, wrbuf, 4);
-
-	/* Sleep for 5 ms to wait for the write to complete */
-	msleep(5);
-
-	/* Reset the bus to wake up the EEPROM (this may not be needed) */
-	w1_reset_bus(sl->master);
-
-	return 0;
-}
-
-static ssize_t w1_f23_write_bin(struct kobject *kobj, char *buf, loff_t off,
-				size_t count)
-{
-	struct w1_slave *sl = kobj_to_w1_slave(kobj);
-	int addr, len, idx;
-
-	if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0)
-		return 0;
-
-#ifdef CONFIG_W1_F23_CRC
-	/* can only write full blocks in cached mode */
-	if ((off & W1_PAGE_MASK) || (count & W1_PAGE_MASK)) {
-		dev_err(&sl->dev, "invalid offset/count off=%d cnt=%zd\n",
-			(int)off, count);
-		return -EINVAL;
-	}
-
-	/* make sure the block CRCs are valid */
-	for (idx = 0; idx < count; idx += W1_PAGE_SIZE) {
-		if (crc16(CRC16_INIT, &buf[idx], W1_PAGE_SIZE) != CRC16_VALID) {
-			dev_err(&sl->dev, "bad CRC at offset %d\n", (int)off);
-			return -EINVAL;
-		}
-	}
-#endif	/* CONFIG_W1_F23_CRC */
-
-	atomic_inc(&sl->refcnt);
-	if (down_interruptible(&sl->master->mutex)) {
-		count = 0;
-		goto out_dec;
-	}
-
-	/* Can only write data to one page at a time */
-	idx = 0;
-	while (idx < count) {
-		addr = off + idx;
-		len = W1_PAGE_SIZE - (addr & W1_PAGE_MASK);
-		if (len > (count - idx))
-			len = count - idx;
-
-		if (w1_f23_write(sl, addr, len, &buf[idx]) < 0) {
-			count = -EIO;
-			goto out_up;
-		}
-		idx += len;
-	}
-
-out_up:
-	up(&sl->master->mutex);
-out_dec:
-	atomic_dec(&sl->refcnt);
-
-	return count;
-}
-
-static struct bin_attribute w1_f23_bin_attr = {
-	.attr = {
-		.name = "eeprom",
-		.mode = S_IRUGO | S_IWUSR,
-		.owner = THIS_MODULE,
-	},
-	.size = W1_EEPROM_SIZE,
-	.read = w1_f23_read_bin,
-	.write = w1_f23_write_bin,
-};
-
-static int w1_f23_add_slave(struct w1_slave *sl)
-{
-	int err;
-#ifdef CONFIG_W1_F23_CRC
-	struct w1_f23_data *data;
-
-	data = kmalloc(sizeof(struct w1_f23_data), GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-	memset(data, 0, sizeof(struct w1_f23_data));
-	sl->family_data = data;
-
-#endif	/* CONFIG_W1_F23_CRC */
-
-	err = sysfs_create_bin_file(&sl->dev.kobj, &w1_f23_bin_attr);
-
-#ifdef CONFIG_W1_F23_CRC
-	if (err)
-		kfree(data);
-#endif	/* CONFIG_W1_F23_CRC */
-
-	return err;
-}
-
-static void w1_f23_remove_slave(struct w1_slave *sl)
-{
-#ifdef CONFIG_W1_F23_CRC
-	kfree(sl->family_data);
-	sl->family_data = NULL;
-#endif	/* CONFIG_W1_F23_CRC */
-	sysfs_remove_bin_file(&sl->dev.kobj, &w1_f23_bin_attr);
-}
-
-static struct w1_family_ops w1_f23_fops = {
-	.add_slave      = w1_f23_add_slave,
-	.remove_slave   = w1_f23_remove_slave,
-};
-
-static struct w1_family w1_family_23 = {
-	.fid = W1_EEPROM_DS2433,
-	.fops = &w1_f23_fops,
-};
-
-static int __init w1_f23_init(void)
-{
-	return w1_register_family(&w1_family_23);
-}
-
-static void __exit w1_f23_fini(void)
-{
-	w1_unregister_family(&w1_family_23);
-}
-
-module_init(w1_f23_init);
-module_exit(w1_f23_fini);
diff -urN oldtree/drivers/w1/w1_family.c newtree/drivers/w1/w1_family.c
--- oldtree/drivers/w1/w1_family.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/w1/w1_family.c	2006-02-21 15:58:14.613924904 +0000
@@ -25,10 +25,10 @@
 #include <linux/delay.h>
 
 #include "w1_family.h"
+#include "w1.h"
 
 DEFINE_SPINLOCK(w1_flock);
 static LIST_HEAD(w1_families);
-extern void w1_reconnect_slaves(struct w1_family *f);
 
 int w1_register_family(struct w1_family *newf)
 {
diff -urN oldtree/drivers/w1/w1_int.c newtree/drivers/w1/w1_int.c
--- oldtree/drivers/w1/w1_int.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/w1/w1_int.c	2006-02-21 15:58:14.638921104 +0000
@@ -26,19 +26,10 @@
 #include "w1.h"
 #include "w1_log.h"
 #include "w1_netlink.h"
+#include "w1_int.h"
 
 static u32 w1_ids = 1;
 
-extern struct device_driver w1_master_driver;
-extern struct bus_type w1_bus_type;
-extern struct device w1_master_device;
-extern int w1_max_slave_count;
-extern int w1_max_slave_ttl;
-extern struct list_head w1_masters;
-extern spinlock_t w1_mlock;
-
-extern int w1_process(void *);
-
 static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
 				       struct device_driver *driver,
 				       struct device *device)
@@ -103,7 +94,7 @@
 	return dev;
 }
 
-void w1_free_dev(struct w1_master *dev)
+static void w1_free_dev(struct w1_master *dev)
 {
 	device_unregister(&dev->dev);
 }
@@ -217,5 +208,3 @@
 
 EXPORT_SYMBOL(w1_add_master_device);
 EXPORT_SYMBOL(w1_remove_master_device);
-
-MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_W1);
diff -urN oldtree/drivers/w1/w1_io.c newtree/drivers/w1/w1_io.c
--- oldtree/drivers/w1/w1_io.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/w1/w1_io.c	2006-02-21 15:58:14.614924752 +0000
@@ -28,7 +28,7 @@
 #include "w1_log.h"
 #include "w1_io.h"
 
-int w1_delay_parm = 1;
+static int w1_delay_parm = 1;
 module_param_named(delay_coef, w1_delay_parm, int, 0);
 
 static u8 w1_crc8_table[] = {
diff -urN oldtree/drivers/w1/w1_smem.c newtree/drivers/w1/w1_smem.c
--- oldtree/drivers/w1/w1_smem.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/w1/w1_smem.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,71 +0,0 @@
-/*
- *	w1_smem.c
- *
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the smems 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/types.h>
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/types.h>
-
-#include "w1.h"
-#include "w1_io.h"
-#include "w1_int.h"
-#include "w1_family.h"
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
-MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, 64bit memory family.");
-
-static struct w1_family w1_smem_family_01 = {
-	.fid = W1_FAMILY_SMEM_01,
-};
-
-static struct w1_family w1_smem_family_81 = {
-	.fid = W1_FAMILY_SMEM_81,
-};
-
-static int __init w1_smem_init(void)
-{
-	int err;
-
-	err = w1_register_family(&w1_smem_family_01);
-	if (err)
-		return err;
-	
-	err = w1_register_family(&w1_smem_family_81);
-	if (err) {
-		w1_unregister_family(&w1_smem_family_01);
-		return err;
-	}
-
-	return 0;
-}
-
-static void __exit w1_smem_fini(void)
-{
-	w1_unregister_family(&w1_smem_family_01);
-	w1_unregister_family(&w1_smem_family_81);
-}
-
-module_init(w1_smem_init);
-module_exit(w1_smem_fini);
diff -urN oldtree/drivers/w1/w1_therm.c newtree/drivers/w1/w1_therm.c
--- oldtree/drivers/w1/w1_therm.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/drivers/w1/w1_therm.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,268 +0,0 @@
-/*
- *	w1_therm.c
- *
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the therms 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/types.h>
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-
-#include "w1.h"
-#include "w1_io.h"
-#include "w1_int.h"
-#include "w1_family.h"
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
-MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family.");
-
-static u8 bad_roms[][9] = {
-				{0xaa, 0x00, 0x4b, 0x46, 0xff, 0xff, 0x0c, 0x10, 0x87},
-				{}
-			};
-
-static ssize_t w1_therm_read_bin(struct kobject *, char *, loff_t, size_t);
-
-static struct bin_attribute w1_therm_bin_attr = {
-	.attr = {
-		.name = "w1_slave",
-		.mode = S_IRUGO,
-		.owner = THIS_MODULE,
-	},
-	.size = W1_SLAVE_DATA_SIZE,
-	.read = w1_therm_read_bin,
-};
-
-static int w1_therm_add_slave(struct w1_slave *sl)
-{
-	return sysfs_create_bin_file(&sl->dev.kobj, &w1_therm_bin_attr);
-}
-
-static void w1_therm_remove_slave(struct w1_slave *sl)
-{
-	sysfs_remove_bin_file(&sl->dev.kobj, &w1_therm_bin_attr);
-}
-
-static struct w1_family_ops w1_therm_fops = {
-	.add_slave	= w1_therm_add_slave,
-	.remove_slave	= w1_therm_remove_slave,
-};
-
-static struct w1_family w1_therm_family_DS18S20 = {
-	.fid = W1_THERM_DS18S20,
-	.fops = &w1_therm_fops,
-};
-
-static struct w1_family w1_therm_family_DS18B20 = {
-	.fid = W1_THERM_DS18B20,
-	.fops = &w1_therm_fops,
-};
-
-static struct w1_family w1_therm_family_DS1822 = {
-	.fid = W1_THERM_DS1822,
-	.fops = &w1_therm_fops,
-};
-
-struct w1_therm_family_converter
-{
-	u8			broken;
-	u16			reserved;
-	struct w1_family	*f;
-	int			(*convert)(u8 rom[9]);
-};
-
-static inline int w1_DS18B20_convert_temp(u8 rom[9]);
-static inline int w1_DS18S20_convert_temp(u8 rom[9]);
-
-static struct w1_therm_family_converter w1_therm_families[] = {
-	{
-		.f		= &w1_therm_family_DS18S20,
-		.convert 	= w1_DS18S20_convert_temp
-	},
-	{
-		.f		= &w1_therm_family_DS1822,
-		.convert 	= w1_DS18B20_convert_temp
-	},
-	{
-		.f		= &w1_therm_family_DS18B20,
-		.convert 	= w1_DS18B20_convert_temp
-	},
-};
-
-static inline int w1_DS18B20_convert_temp(u8 rom[9])
-{
-	int t = (rom[1] << 8) | rom[0];
-	t /= 16;
-	return t;
-}
-
-static inline int w1_DS18S20_convert_temp(u8 rom[9])
-{
-	int t, h;
-
-	if (!rom[7])
-		return 0;
-	
-	if (rom[1] == 0)
-		t = ((s32)rom[0] >> 1)*1000;
-	else
-		t = 1000*(-1*(s32)(0x100-rom[0]) >> 1);
-	
-	t -= 250;
-	h = 1000*((s32)rom[7] - (s32)rom[6]);
-	h /= (s32)rom[7];
-	t += h;
-
-	return t;
-}
-
-static inline int w1_convert_temp(u8 rom[9], u8 fid)
-{
-	int i;
-
-	for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i)
-		if (w1_therm_families[i].f->fid == fid)
-			return w1_therm_families[i].convert(rom);
-
-	return 0;
-}
-
-static int w1_therm_check_rom(u8 rom[9])
-{
-	int i;
-
-	for (i=0; i<sizeof(bad_roms)/9; ++i)
-		if (!memcmp(bad_roms[i], rom, 9))
-			return 1;
-
-	return 0;
-}
-
-static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count)
-{
-	struct w1_slave *sl = kobj_to_w1_slave(kobj);
-	struct w1_master *dev = sl->master;
-	u8 rom[9], crc, verdict;
-	int i, max_trying = 10;
-
-	atomic_inc(&sl->refcnt);
-	smp_mb__after_atomic_inc();
-	if (down_interruptible(&sl->master->mutex)) {
-		count = 0;
-		goto out_dec;
-	}
-
-	if (off > W1_SLAVE_DATA_SIZE) {
-		count = 0;
-		goto out;
-	}
-	if (off + count > W1_SLAVE_DATA_SIZE) {
-		count = 0;
-		goto out;
-	}
-
-	memset(buf, 0, count);
-	memset(rom, 0, sizeof(rom));
-
-	count = 0;
-	verdict = 0;
-	crc = 0;
-
-	while (max_trying--) {
-		if (!w1_reset_select_slave(sl)) {
-			int count = 0;
-			unsigned int tm = 750;
-
-			w1_write_8(dev, W1_CONVERT_TEMP);
-
-			while (tm) {
-				tm = msleep_interruptible(tm);
-				if (signal_pending(current))
-					flush_signals(current);
-			}
-
-			if (!w1_reset_select_slave(sl)) {
-
-				w1_write_8(dev, W1_READ_SCRATCHPAD);
-				if ((count = w1_read_block(dev, rom, 9)) != 9) {
-					dev_warn(&dev->dev, "w1_read_block() returned %d instead of 9.\n", count);
-				}
-
-				crc = w1_calc_crc8(rom, 8);
-
-				if (rom[8] == crc && rom[0])
-					verdict = 1;
-			}
-		}
-
-		if (!w1_therm_check_rom(rom))
-			break;
-	}
-
-	for (i = 0; i < 9; ++i)
-		count += sprintf(buf + count, "%02x ", rom[i]);
-	count += sprintf(buf + count, ": crc=%02x %s\n",
-			   crc, (verdict) ? "YES" : "NO");
-	if (verdict)
-		memcpy(sl->rom, rom, sizeof(sl->rom));
-	else
-		dev_warn(&dev->dev, "18S20 doesn't respond to CONVERT_TEMP.\n");
-
-	for (i = 0; i < 9; ++i)
-		count += sprintf(buf + count, "%02x ", sl->rom[i]);
-	
-	count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom, sl->family->fid));
-out:
-	up(&dev->mutex);
-out_dec:
-	smp_mb__before_atomic_inc();
-	atomic_dec(&sl->refcnt);
-
-	return count;
-}
-
-static int __init w1_therm_init(void)
-{
-	int err, i;
-
-	for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i) {
-		err = w1_register_family(w1_therm_families[i].f);
-		if (err)
-			w1_therm_families[i].broken = 1;
-	}
-
-	return 0;
-}
-
-static void __exit w1_therm_fini(void)
-{
-	int i;
-
-	for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i)
-		if (!w1_therm_families[i].broken)
-			w1_unregister_family(w1_therm_families[i].f);
-}
-
-module_init(w1_therm_init);
-module_exit(w1_therm_fini);
diff -urN oldtree/fs/9p/mux.c newtree/fs/9p/mux.c
--- oldtree/fs/9p/mux.c	2006-02-19 11:41:04.893599160 +0000
+++ newtree/fs/9p/mux.c	2006-02-21 15:58:23.744536840 +0000
@@ -31,6 +31,7 @@
 #include <linux/poll.h>
 #include <linux/kthread.h>
 #include <linux/idr.h>
+#include <linux/mutex.h>
 
 #include "debug.h"
 #include "v9fs.h"
@@ -110,7 +111,7 @@
 static u16 v9fs_mux_get_tag(struct v9fs_mux_data *);
 static void v9fs_mux_put_tag(struct v9fs_mux_data *, u16);
 
-static DECLARE_MUTEX(v9fs_mux_task_lock);
+static DEFINE_MUTEX(v9fs_mux_task_lock);
 static struct workqueue_struct *v9fs_mux_wq;
 
 static int v9fs_mux_num;
@@ -166,7 +167,7 @@
 
 	dprintk(DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, v9fs_mux_num,
 		v9fs_mux_poll_task_num);
-	up(&v9fs_mux_task_lock);
+	mutex_lock(&v9fs_mux_task_lock);
 
 	n = v9fs_mux_calc_poll_procs(v9fs_mux_num + 1);
 	if (n > v9fs_mux_poll_task_num) {
@@ -225,7 +226,7 @@
 	}
 
 	v9fs_mux_num++;
-	down(&v9fs_mux_task_lock);
+	mutex_unlock(&v9fs_mux_task_lock);
 
 	return 0;
 }
@@ -235,7 +236,7 @@
 	int i;
 	struct v9fs_mux_poll_task *vpt;
 
-	up(&v9fs_mux_task_lock);
+	mutex_lock(&v9fs_mux_task_lock);
 	vpt = m->poll_task;
 	list_del(&m->mux_list);
 	for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
@@ -252,7 +253,7 @@
 		v9fs_mux_poll_task_num--;
 	}
 	v9fs_mux_num--;
-	down(&v9fs_mux_task_lock);
+	mutex_unlock(&v9fs_mux_task_lock);
 }
 
 /**
diff -urN oldtree/fs/Kconfig newtree/fs/Kconfig
--- oldtree/fs/Kconfig	2006-02-19 11:41:04.915595816 +0000
+++ newtree/fs/Kconfig	2006-02-21 15:58:33.898993128 +0000
@@ -177,6 +177,8 @@
 	default y if EXT2_FS=y || EXT3_FS=y
 	default m if EXT2_FS=m || EXT3_FS=m
 
+source "fs/reiser4/Kconfig"
+
 config REISERFS_FS
 	tristate "Reiserfs support"
 	help
@@ -937,6 +939,53 @@
 	  To compile this file system support as a module, choose M here: the
 	  module will be called affs.  If unsure, say N.
 
+config ASFS_FS
+	tristate "Amiga SFS file system support (EXPERIMENTAL)"
+	select NLS
+	depends on EXPERIMENTAL
+	help
+
+	  The Amiga Smart FileSystem (SFS) is the file system used on hard
+	  disks by Amiga(tm) and MorphOS(tm) systems.  Say Y if you want
+	  to be able to read files from an Amiga SFS partition on your hard
+	  drive.
+
+	  For more information read <file:Documentation/filesystems/asfs.txt>
+
+	  To compile this file system support as a module, choose M here: the
+	  module will be called asfs.
+
+	  If unsure, say N.
+
+config ASFS_DEFAULT_CODEPAGE
+	string "Default codepage for SFS"
+	depends on ASFS_FS
+	default ""
+	help
+	  This option should be set to the codepage of your SFS filesystems.
+	  It can be overridden with the 'codepage' mount option. Leave it blank
+	  or enter 'none' to disable filename converting.
+
+	  Use full codepage name (for example 'cp1251' instead of '1251') here,
+	  this allows to specify any character set, not only numbered one (like
+	  'iso8859-2').
+
+	  If unsure, leave it blank.
+
+config ASFS_RW
+	bool "Amiga SFS write support (DANGEROUS)"
+	depends on ASFS_FS
+	help
+
+	  If you say Y here, you will be able to write to ASFS file
+	  systems as well as read from them. The read-write support in ASFS
+	  is in beta stage. This means that useing it to write files to SFS
+	  partitions is DANGEROUS and COULD corrupt the filesystem.
+
+	  For more information read <file:Documentation/filesystems/asfs.txt>
+
+	  If unsure, say N.
+
 config HFS_FS
 	tristate "Apple Macintosh file system support (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
diff -urN oldtree/fs/Makefile newtree/fs/Makefile
--- oldtree/fs/Makefile	2006-02-19 11:41:04.916595664 +0000
+++ newtree/fs/Makefile	2006-02-21 15:58:33.899992976 +0000
@@ -51,6 +51,7 @@
  
 # Do not add any filesystems before this line
 obj-$(CONFIG_REISERFS_FS)	+= reiserfs/
+obj-$(CONFIG_REISER4_FS)	+= reiser4/
 obj-$(CONFIG_EXT3_FS)		+= ext3/ # Before ext2 so root fs can be ext3
 obj-$(CONFIG_JBD)		+= jbd/
 obj-$(CONFIG_EXT2_FS)		+= ext2/
@@ -84,6 +85,7 @@
 obj-$(CONFIG_JFFS_FS)		+= jffs/
 obj-$(CONFIG_JFFS2_FS)		+= jffs2/
 obj-$(CONFIG_AFFS_FS)		+= affs/
+obj-$(CONFIG_ASFS_FS)		+= asfs/
 obj-$(CONFIG_ROMFS_FS)		+= romfs/
 obj-$(CONFIG_QNX4FS_FS)		+= qnx4/
 obj-$(CONFIG_AUTOFS_FS)		+= autofs/
diff -urN oldtree/fs/affs/super.c newtree/fs/affs/super.c
--- oldtree/fs/affs/super.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/affs/super.c	2006-02-21 15:58:36.513595648 +0000
@@ -270,6 +270,7 @@
 	int			 reserved;
 	unsigned long		 mount_flags;
 	int			 tmp_flags;	/* fix remount prototype... */
+	u8			 sig[4];
 
 	pr_debug("AFFS: read_super(%s)\n",data ? (const char *)data : "no options");
 
@@ -369,8 +370,9 @@
 		printk(KERN_ERR "AFFS: Cannot read boot block\n");
 		goto out_error;
 	}
-	chksum = be32_to_cpu(*(__be32 *)boot_bh->b_data);
+	memcpy(sig, boot_bh->b_data, 4);
 	brelse(boot_bh);
+	chksum = be32_to_cpu(*(__be32 *)sig);
 
 	/* Dircache filesystems are compatible with non-dircache ones
 	 * when reading. As long as they aren't supported, writing is
@@ -419,11 +421,17 @@
 	}
 
 	if (mount_flags & SF_VERBOSE) {
-		chksum = cpu_to_be32(chksum);
-		printk(KERN_NOTICE "AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n",
-			AFFS_ROOT_TAIL(sb, root_bh)->disk_name[0],
-			AFFS_ROOT_TAIL(sb, root_bh)->disk_name + 1,
-			(char *)&chksum,((char *)&chksum)[3] + '0',blocksize);
+		int len = AFFS_ROOT_TAIL(sb, root_bh)->disk_name[0];
+		char name[32];
+
+		if (len > 31)
+			len = 31;
+		memcpy(name, AFFS_ROOT_TAIL(sb, root_bh)->disk_name + 1, len);
+		name[len] = '\0';
+
+		printk(KERN_NOTICE "AFFS: Mounting volume \"%*s\": "
+			"Type=%c%c%c\\%c, Blocksize=%d\n",
+			len, name, sig[0], sig[1], sig[2], sig[3], blocksize);
 	}
 
 	sb->s_flags |= MS_NODEV | MS_NOSUID;
diff -urN oldtree/fs/asfs/Changes newtree/fs/asfs/Changes
--- oldtree/fs/asfs/Changes	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/asfs/Changes	2006-02-21 15:58:33.134109408 +0000
@@ -0,0 +1,112 @@
+
+Amiga Smart File System, Linux implementation
+
+Please direct bug reports to: marek@amiga.pl
+
+History:
+
+v1.0beta10 (13.06.2005)
+- fixed ugly bug introduced in beta9 that caused kernel crash on x86
+  (thanks to Emiliano for reporting it!)
+
+v1.0beta9 (17.03.2005)
+- added NLS support (thanks to Pavel Fedin!)
+
+v1.0beta8 (07.01.2005)
+- adapted to 2.6.10 kernel VFS changes
+- added workaround for buggy Mandrake kernel headers
+
+v1.0beta7 (25.06.2004)
+- small changes in documentation
+- code clean up: bitfuncs.c, super.c, inode.c, *.h, Makefile, added
+  asfs_ prefix to function names, made some functions static
+  (big thanks to Christoph Hellwig for advice!)
+- fixed minor bugs (inode leak in super.c, not-realesed buffer during
+  object renaming in inode.c)
+- now files/dirs are created with global ownership/permission bits
+
+v1.0beta6 (04.06.2004)
+- fixed: ASFS_SB(sb)->flags was always zero in 2.6.x code
+
+v1.0beta5 (07.05.2004)
+- finally fixed a problem with file size attrib. not being written
+  to disk
+- fixed some problems with GCC 3.x and debug enabled
+
+v1.0beta4 (12.04.2004)
+- removed dummy asfs_notify_change (this fixes major bug introduced
+  in 1.0beta3 - file size wasn't written to disk) until it will
+  be implemented completely
+
+v1.0beta3 (22.03.2004) - still beta
+- updated for 2.6.x kernels VFS changes
+- code clean-up
+- added dummy asfs_notify_change (chmod now returns no errors)
+- added symlinks write support
+- fixed: ASFS_SB(sb)->flags was always zero
+
+v1.0beta2 (11.01.2004) - special version for Pegasos][ kernel
+- separated read and write functions, can be compiled also
+  as read-only fs
+
+v1.0beta1 (02.12.2003) - first public beta with write support
+- added dentry hashing/comparing routines
+- code clean-up
+
+v1.0aplha4 (30.11.2003) - preparing for first public beta
+- fixed some problems with renaming/moving files
+- fixed two major bugs, which didn't occur when fs was mounted
+  on loopback device (newly allocated blocks were not written to
+  disk and state bits were not set correctly on newly mapped file
+  blocks)
+- fixed many small bugs in io code (some buffers were not freed)
+- added/modified sb locks in asfs_lookup and asfs_getblock
+- fixed serious bug in file block allocation routines
+
+v1.0aplha3 (23.11.2003)
+- added (hopefully) all byteswap code, should now work again on
+  little-endian systems (also with write support!)
+- updated documentation
+
+v1.0alpha2 (13.11.2003)
+- now alocates file blocks in chunks during one request
+- fixed some dead-locks, other fixes
+
+v1.0alpha (02.11.2003) - first working version with full write support
+- too much to list it here ;)
+
+... (working on write support)
+
+v0.7 (12.10.2003) - internal realase
+- added asfs_breadcheck, modified asfs_get_node, asfs_search_BTree,
+  no more from_be32/16 macros, other...
+- code splitted into several files
+
+v0.6 (04.09.2003) - final read-only version
+- added support for HashTables, directory scaning should be
+  MUCH faster now
+- added checking of block IDs before reading any data from block
+
+v0.5 (19.07.2003)
+- added simple but effective extent cache - real speed-up
+  in reading large files
+- added read support for symlinks - based on AFFS symlinks
+
+v0.4 (10.07.2003)
+- third code clean-up (thanks to Roman Zippel for advice)
+- now uses generic readpage and readinode routines
+
+v0.3beta (17.06.2003)
+- second code clean-up
+
+v0.2beta2 (15.06.2003)
+- fixed yet another stupid bug - driver can't read root block on little-endian systems
+v0.2beta (15.06.2003)
+- fixed stupid bug - now files have 'file' flag (S_IFREG) set...
+- added mount options to set uid, gid and mode of files and dirs
+- made hidden files & dirs really hidden (= not listed in directories)
+- code clean-up
+
+v0.1beta (11.06.2003)
+- after many kernel crashes, finally got it!
+- first working read-only filesystem driver
diff -urN oldtree/fs/asfs/Makefile newtree/fs/asfs/Makefile
--- oldtree/fs/asfs/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/asfs/Makefile	2006-02-21 15:58:33.137108952 +0000
@@ -0,0 +1,8 @@
+#
+# Makefile for the linux asfs filesystem routines.
+#
+
+obj-$(CONFIG_ASFS_FS) += asfs.o
+
+asfs-y += dir.o extents.o file.o inode.o namei.o nodes.o objects.o super.o symlink.o
+asfs-$(CONFIG_ASFS_RW) += adminspace.o bitfuncs.o
diff -urN oldtree/fs/asfs/adminspace.c newtree/fs/asfs/adminspace.c
--- oldtree/fs/asfs/adminspace.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/asfs/adminspace.c	2006-02-21 15:58:33.132109712 +0000
@@ -0,0 +1,446 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta7
+ *
+ * This file contains some parts of the original amiga version of
+ * SmartFilesystem source code.
+ *
+ * SmartFilesystem is copyrighted (C) 2003 by: John Hendrikx,
+ * Ralph Schmidt, Emmanuel Lesueur, David Gerber, and Marcin Kurek
+ *
+ * Adapted and modified by Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include "asfs_fs.h"
+#include "bitfuncs.h"
+
+#include <asm/byteorder.h>
+
+#ifdef CONFIG_ASFS_RW
+
+static int setfreeblocks(struct super_block *sb, u32 freeblocks)
+{
+	struct buffer_head *bh;
+	if ((bh = asfs_breadcheck(sb, ASFS_SB(sb)->rootobjectcontainer, ASFS_OBJECTCONTAINER_ID))) {
+		struct fsRootInfo *ri = (struct fsRootInfo *) ((u8 *) bh->b_data + sb->s_blocksize - sizeof(struct fsRootInfo));
+		ASFS_SB(sb)->freeblocks = freeblocks;
+		ri->freeblocks = cpu_to_be32(freeblocks);
+		asfs_bstore(sb, bh);
+		asfs_brelse(bh);
+		return 0;
+	}
+	return -EIO;
+}
+
+static inline int enoughspace(struct super_block *sb, u32 blocks)
+{
+	if (ASFS_SB(sb)->freeblocks - ASFS_ALWAYSFREE < blocks)
+		return FALSE;
+
+	return TRUE;
+}
+
+	/* Determines the amount of free blocks starting from block /block/.
+	   If there are no blocks found or if there was an error -1 is returned,
+	   otherwise this function will count the number of free blocks until
+	   an allocated block is encountered or until maxneeded has been
+	   exceeded. */
+
+static int availablespace(struct super_block *sb, u32 block, u32 maxneeded)
+{
+	struct buffer_head *bh = NULL;
+	struct fsBitmap *b;
+	u32 longs = ASFS_SB(sb)->blocks_inbitmap >> 5;
+	u32 maxbitmapblock = ASFS_SB(sb)->bitmapbase + ASFS_SB(sb)->blocks_bitmap;
+	int blocksfound = 0;
+	u32 bitstart;
+	int bitend;
+	u32 nextblock = ASFS_SB(sb)->bitmapbase + block / ASFS_SB(sb)->blocks_inbitmap;
+
+	bitstart = block % ASFS_SB(sb)->blocks_inbitmap;
+
+	while (nextblock < maxbitmapblock && (bh = asfs_breadcheck(sb, nextblock++, ASFS_BITMAP_ID))) {
+		b = (void *) bh->b_data;
+
+		if ((bitend = bmffz(b->bitmap, longs, bitstart)) >= 0) {
+			blocksfound += bitend - bitstart;
+			asfs_brelse(bh);
+			return blocksfound;
+		}
+		blocksfound += ASFS_SB(sb)->blocks_inbitmap - bitstart;
+		if (blocksfound >= maxneeded) {
+			asfs_brelse(bh);
+			return blocksfound;
+		}
+		bitstart = 0;
+		asfs_brelse(bh);
+	}
+
+	if (bh == NULL)
+		return (-1);
+
+	return (blocksfound);
+}
+
+int asfs_findspace(struct super_block *sb, u32 maxneeded, u32 start, u32 end, u32 * returned_block, u32 * returned_blocks)
+{
+	struct buffer_head *bh;
+	u32 longs = ASFS_SB(sb)->blocks_inbitmap >> 5;
+	u32 space = 0;
+	u32 block;
+	u32 bitmapblock = ASFS_SB(sb)->bitmapbase + start / ASFS_SB(sb)->blocks_inbitmap;
+	u32 break_point;
+	int bitstart, bitend;
+	int reads;
+
+	if (enoughspace(sb, maxneeded) == FALSE) {
+		*returned_block = 0;
+		*returned_blocks = 0;
+		return -ENOSPC;
+	}
+
+	if (start >= ASFS_SB(sb)->totalblocks)
+		start -= ASFS_SB(sb)->totalblocks;
+
+	if (end == 0)
+		end = ASFS_SB(sb)->totalblocks;
+
+	reads = ((end - 1) / ASFS_SB(sb)->blocks_inbitmap) + 1 - start / ASFS_SB(sb)->blocks_inbitmap;
+
+	if (start >= end)
+		reads += (ASFS_SB(sb)->totalblocks - 1) / ASFS_SB(sb)->blocks_inbitmap + 1;
+
+	break_point = (start < end ? end : ASFS_SB(sb)->totalblocks);
+
+	*returned_block = 0;
+	*returned_blocks = 0;
+
+	bitend = start % ASFS_SB(sb)->blocks_inbitmap;
+	block = start - bitend;
+
+	while ((bh = asfs_breadcheck(sb, bitmapblock++, ASFS_BITMAP_ID))) {
+		struct fsBitmap *b = (void *) bh->b_data;
+		u32 localbreak_point = break_point - block;
+
+		if (localbreak_point > ASFS_SB(sb)->blocks_inbitmap)
+			localbreak_point = ASFS_SB(sb)->blocks_inbitmap;
+
+		/* At this point space contains the amount of free blocks at
+		   the end of the previous bitmap block.  If there are no
+		   free blocks at the start of this bitmap block, space will
+		   be set to zero, since in that case the space isn't adjacent. */
+
+		while ((bitstart = bmffo(b->bitmap, longs, bitend)) < ASFS_SB(sb)->blocks_inbitmap) {
+			/* found the start of an empty space, now find out how large it is */
+
+			if (bitstart >= localbreak_point)
+				break;
+
+			if (bitstart != 0)
+				space = 0;
+
+			bitend = bmffz(b->bitmap, longs, bitstart);
+
+			if (bitend > localbreak_point)
+				bitend = localbreak_point;
+
+			space += bitend - bitstart;
+
+			if (*returned_blocks < space) {
+				*returned_block = block + bitend - space;
+				if (space >= maxneeded) {
+					*returned_blocks = maxneeded;
+					asfs_brelse(bh);
+					return 0;
+				}
+				*returned_blocks = space;
+			}
+
+			if (bitend >= localbreak_point)
+				break;
+		}
+
+		if (--reads == 0)
+			break;
+
+		/* no (more) empty spaces found in this block */
+
+		if (bitend != ASFS_SB(sb)->blocks_inbitmap)
+			space = 0;
+
+		bitend = 0;
+		block += ASFS_SB(sb)->blocks_inbitmap;
+
+		if (block >= ASFS_SB(sb)->totalblocks) {
+			block = 0;
+			space = 0;
+			break_point = end;
+			bitmapblock = ASFS_SB(sb)->bitmapbase;
+		}
+		asfs_brelse(bh);
+	}
+
+	if (bh == NULL)
+		return -EIO;
+
+	asfs_brelse(bh);
+
+	if (*returned_blocks == 0)
+		return -ENOSPC;
+	else
+		return 0;
+}
+
+int asfs_markspace(struct super_block *sb, u32 block, u32 blocks)
+{
+	int errorcode;
+
+	asfs_debug("markspace: Marking %d blocks from block %d\n", blocks, block);
+
+	if ((availablespace(sb, block, blocks)) < blocks) {
+		printk("ASFS: Attempted to mark %d blocks from block %d, but some of them were already full!\n", blocks, block);
+		return -EIO;
+	}
+
+	if ((errorcode = setfreeblocks(sb, ASFS_SB(sb)->freeblocks - blocks)) == 0) {
+		struct buffer_head *bh;
+		u32 skipblocks = block / ASFS_SB(sb)->blocks_inbitmap;
+		u32 longs = (sb->s_blocksize - sizeof(struct fsBitmap)) >> 2;
+		u32 bitmapblock;
+
+		block -= skipblocks * ASFS_SB(sb)->blocks_inbitmap;
+		bitmapblock = ASFS_SB(sb)->bitmapbase + skipblocks;
+
+		while (blocks > 0) {
+			if ((bh = asfs_breadcheck(sb, bitmapblock++, ASFS_BITMAP_ID))) {
+				struct fsBitmap *b = (void *) bh->b_data;
+
+				blocks -= bmclr(b->bitmap, longs, block, blocks);
+				block = 0;
+
+				asfs_bstore(sb, bh);
+				asfs_brelse(bh);
+			} else
+				return -EIO;
+		}
+	}
+
+	return (errorcode);
+}
+
+	/* This function checks the bitmap and tries to locate at least /blocksneeded/
+	   adjacent unused blocks.  If found it sets returned_block to the start block
+	   and returns no error.  If not found, ERROR_DISK_IS_FULL is returned and
+	   returned_block is set to zero.  Any other errors are returned as well. */
+
+static inline int internalfindspace(struct super_block *sb, u32 blocksneeded, u32 startblock, u32 endblock, u32 * returned_block)
+{
+	u32 blocks;
+	int errorcode;
+
+	if ((errorcode = asfs_findspace(sb, blocksneeded, startblock, endblock, returned_block, &blocks)) == 0)
+		if (blocks != blocksneeded)
+			return -ENOSPC;
+
+	return errorcode;
+}
+
+static int findandmarkspace(struct super_block *sb, u32 blocksneeded, u32 * returned_block)
+{
+	int errorcode;
+
+	if (enoughspace(sb, blocksneeded) != FALSE) {
+		if ((errorcode = internalfindspace(sb, blocksneeded, 0, ASFS_SB(sb)->totalblocks, returned_block)) == 0)
+			errorcode = asfs_markspace(sb, *returned_block, blocksneeded);
+	} else
+		errorcode = -ENOSPC;
+
+	return (errorcode);
+}
+
+/* ************************** */
+
+int asfs_freespace(struct super_block *sb, u32 block, u32 blocks)
+{
+	int errorcode;
+
+	asfs_debug("freespace: Freeing %d blocks from block %d\n", blocks, block);
+
+	if ((errorcode = setfreeblocks(sb, ASFS_SB(sb)->freeblocks + blocks)) == 0) {
+		struct buffer_head *bh;
+		u32 skipblocks = block / ASFS_SB(sb)->blocks_inbitmap;
+		u32 longs = (sb->s_blocksize - sizeof(struct fsBitmap)) >> 2;
+		u32 bitmapblock;
+
+		block -= skipblocks * ASFS_SB(sb)->blocks_inbitmap;
+		bitmapblock = ASFS_SB(sb)->bitmapbase + skipblocks;
+
+		while (blocks > 0) {
+			if ((bh = asfs_breadcheck(sb, bitmapblock++, ASFS_BITMAP_ID))) {
+				struct fsBitmap *b = (void *) bh->b_data;
+
+				blocks -= bmset(b->bitmap, longs, block, blocks);
+				block = 0;
+
+				asfs_bstore(sb, bh);
+				asfs_brelse(bh);
+			} else
+				return -EIO;
+		}
+	}
+
+	return (errorcode);
+}
+
+/*************** admin space containers ****************/
+
+int asfs_allocadminspace(struct super_block *sb, u32 *returned_block)
+{
+	struct buffer_head *bh;
+	u32 adminspaceblock = ASFS_SB(sb)->adminspacecontainer;
+	int errorcode = -EIO;
+
+	asfs_debug("allocadminspace: allocating new block\n");
+
+	while ((bh = asfs_breadcheck(sb, adminspaceblock, ASFS_ADMINSPACECONTAINER_ID))) {
+		struct fsAdminSpaceContainer *asc1 = (void *) bh->b_data;
+		struct fsAdminSpace *as1 = asc1->adminspace;
+		int adminspaces1 = (sb->s_blocksize - sizeof(struct fsAdminSpaceContainer)) / sizeof(struct fsAdminSpace);
+
+		while (adminspaces1-- > 0) {
+			s16 bitoffset;
+
+			if (as1->space != 0 && (bitoffset = bfffz(be32_to_cpu(as1->bits), 0)) >= 0) {
+				u32 emptyadminblock = be32_to_cpu(as1->space) + bitoffset;
+				as1->bits |= cpu_to_be32(1 << (31 - bitoffset));
+				asfs_bstore(sb, bh);
+				*returned_block = emptyadminblock;
+				asfs_brelse(bh);
+				asfs_debug("allocadminspace: found block %d\n", *returned_block);
+				return 0;
+			}
+			as1++;
+		}
+
+		adminspaceblock = be32_to_cpu(asc1->next);
+		asfs_brelse(bh);
+
+		if (adminspaceblock == 0) {
+			u32 startblock;
+
+			asfs_debug("allocadminspace: allocating new adminspace area\n");
+
+			/* If we get here it means current adminspace areas are all filled.
+			   We would now need to find a new area and create a fsAdminSpace
+			   structure in one of the AdminSpaceContainer blocks.  If these
+			   don't have any room left for new adminspace areas a new
+			   AdminSpaceContainer would have to be created first which is
+			   placed as the first block in the newly found admin area. */
+
+			adminspaceblock = ASFS_SB(sb)->adminspacecontainer;
+
+			if ((errorcode = findandmarkspace(sb, 32, &startblock)))
+				return errorcode;
+
+			while ((bh = asfs_breadcheck(sb, adminspaceblock, ASFS_ADMINSPACECONTAINER_ID))) {
+				struct fsAdminSpaceContainer *asc2 = (void *) bh->b_data;
+				struct fsAdminSpace *as2 = asc2->adminspace;
+				int adminspaces2 = (sb->s_blocksize - sizeof(struct fsAdminSpaceContainer)) / sizeof(struct fsAdminSpace);
+
+				while (adminspaces2-- > 0 && as2->space != 0)
+					as2++;
+
+				if (adminspaces2 >= 0) {	/* Found a unused AdminSpace in this AdminSpaceContainer! */
+					as2->space = cpu_to_be32(startblock);
+					as2->bits = 0;
+					asfs_bstore(sb, bh);
+					asfs_brelse(bh);
+					break;
+				}
+
+				if (asc2->next == 0) {
+					/* Oh-oh... we marked our new adminspace area in use, but we couldn't
+					   find space to store a fsAdminSpace structure in the existing
+					   fsAdminSpaceContainer blocks.  This means we need to create and
+					   link a new fsAdminSpaceContainer as the first block in our newly
+					   marked adminspace. */
+
+					asc2->next = cpu_to_be32(startblock);
+					asfs_bstore(sb, bh);
+					asfs_brelse(bh);
+
+					/* Now preparing new AdminSpaceContainer */
+
+					if ((bh = asfs_getzeroblk(sb, startblock)) == NULL)
+						return -EIO;
+
+					asc2 = (void *) bh->b_data;
+					asc2->bheader.id = cpu_to_be32(ASFS_ADMINSPACECONTAINER_ID);
+					asc2->bheader.ownblock = cpu_to_be32(startblock);
+					asc2->previous = cpu_to_be32(adminspaceblock);
+					asc2->adminspace[0].space = cpu_to_be32(startblock);
+					asc2->adminspace[0].bits = cpu_to_be32(0x80000000);
+					asc2->bits = 32;
+
+					asfs_bstore(sb, bh);
+					asfs_brelse(bh);
+
+					adminspaceblock = startblock;
+					break;	/* Breaks through to outer loop! */
+				}
+				adminspaceblock = be32_to_cpu(asc2->next);
+				asfs_brelse(bh);
+			}
+		}
+	}
+	return errorcode;
+}
+
+int asfs_freeadminspace(struct super_block *sb, u32 block)
+{
+	struct buffer_head *bh;
+	u32 adminspaceblock = ASFS_SB(sb)->adminspacecontainer;
+
+	asfs_debug("freeadminspace: Entry -- freeing block %d\n", block);
+
+	while ((bh = asfs_breadcheck(sb, adminspaceblock, ASFS_ADMINSPACECONTAINER_ID))) {
+		struct fsAdminSpaceContainer *asc = (void *) bh->b_data;
+		struct fsAdminSpace *as = asc->adminspace;
+		int adminspaces = (sb->s_blocksize - sizeof(struct fsAdminSpaceContainer)) / sizeof(struct fsAdminSpace);
+
+		while (adminspaces-- > 0) {
+			if (block >= be32_to_cpu(as->space) && block < be32_to_cpu(as->space) + 32) {
+				s16 bitoffset = block - be32_to_cpu(as->space);
+				asfs_debug("freeadminspace: Block to be freed is located in AdminSpaceContainer block at %d\n", adminspaceblock);
+				as->bits &= cpu_to_be32(~(1 << (31 - bitoffset)));
+				asfs_bstore(sb, bh);
+				asfs_brelse(bh);
+				return 0;
+			}
+			as++;
+		}
+
+		if ((adminspaceblock = be32_to_cpu(asc->next)) == 0)
+			break;
+
+		asfs_brelse(bh);
+	}
+
+	if (bh != NULL) {
+		asfs_brelse(bh);
+		printk("ASFS: Unable to free an administration block. The block cannot be found.");
+		return -ENOENT;
+	}
+
+	return -EIO;
+}
+
+#endif
diff -urN oldtree/fs/asfs/asfs_fs.h newtree/fs/asfs/asfs_fs.h
--- oldtree/fs/asfs/asfs_fs.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/asfs/asfs_fs.h	2006-02-21 15:58:33.133109560 +0000
@@ -0,0 +1,234 @@
+#ifndef __LINUX_ASFS_FS_H
+#define __LINUX_ASFS_FS_H
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <asm/byteorder.h>
+#include <linux/amigasfs.h>
+
+#define asfs_debug(fmt,arg...) /* no debug at all */
+//#define asfs_debug(fmt,arg...) printk(fmt,##arg)  /* general debug infos */
+
+#if !defined (__BIG_ENDIAN) && !defined (__LITTLE_ENDIAN)
+#error Endianes must be known for ASFS to work. Sorry.
+#endif
+
+#define ASFS_MAXFN_BUF (ASFS_MAXFN + 4)
+#define ASFS_DEFAULT_UID 0
+#define ASFS_DEFAULT_GID 0
+#define ASFS_DEFAULT_MODE 0644	/* default permission bits for files, dirs have same permission, but with "x" set */
+
+/* Extent structure located in RAM (e.g. inside inode structure),
+   currently used to store last used extent */
+
+struct inramExtent {
+	u32 startblock;	/* Block from begginig of the file */
+	u32 key;
+	u32 next;
+	u16 blocks;
+};
+
+/* inode in-kernel data */
+
+struct asfs_inode_info {
+	u32 firstblock;
+	u32 hashtable;
+	int modified;
+	loff_t mmu_private;
+	struct inramExtent ext_cache;
+	struct inode vfs_inode;
+};
+
+/* short cut to get to the asfs specific inode data */
+static inline struct asfs_inode_info *ASFS_I(struct inode *inode)
+{
+   return list_entry(inode, struct asfs_inode_info, vfs_inode);
+}
+
+/* Amiga SFS superblock in-core data */
+
+struct asfs_sb_info {
+	u32 totalblocks;
+	u32 rootobjectcontainer;
+	u32 extentbnoderoot;
+	u32 objectnoderoot;
+
+	u32 adminspacecontainer;
+	u32 bitmapbase;
+	u32 freeblocks;
+	u32 blocks_inbitmap;
+	u32 blocks_bitmap;
+	u32 block_rovingblockptr;
+
+	uid_t uid;
+	gid_t gid;
+	umode_t mode;
+	u16 flags;
+	char *prefix;
+	char *root_volume;		/* Volume prefix for absolute symlinks. */
+	char *iocharset;
+	char *codepage;
+	struct nls_table *nls_io;
+	struct nls_table *nls_disk;
+};
+
+/* short cut to get to the asfs specific sb data */
+static inline struct asfs_sb_info *ASFS_SB(struct super_block *sb)
+{
+	return sb->s_fs_info;
+}
+
+/* io inline code */
+
+u32 asfs_calcchecksum(void *block, u32 blocksize);
+
+static inline int
+asfs_check_block(struct fsBlockHeader *block, u32 blocksize, u32 n, u32 id)
+{
+	if (asfs_calcchecksum(block, blocksize) ==
+	    be32_to_cpu(((struct fsBlockHeader *) block)->checksum) &&
+	    n == be32_to_cpu(((struct fsBlockHeader *) block)->ownblock) &&
+	    id == be32_to_cpu(((struct fsBlockHeader *) block)->id))
+		return TRUE;
+	return FALSE;
+}
+
+/* get fs structure from block and do some checks... */
+static inline struct buffer_head *
+asfs_breadcheck(struct super_block *sb, u32 n, u32 type)
+{
+	struct buffer_head *bh;
+	if ((bh = sb_bread(sb, n))) {
+		if (asfs_check_block ((void *)bh->b_data, sb->s_blocksize, n, type)) {
+			return bh;	/* all okay */
+		}
+		brelse(bh);
+	}
+	return NULL;		/* error */
+}
+
+static inline struct buffer_head *
+asfs_getzeroblk(struct super_block *sb, int block)
+{
+	struct buffer_head *bh;
+	bh = sb_getblk(sb, block);
+	lock_buffer(bh);
+	memset(bh->b_data, 0, sb->s_blocksize);
+	set_buffer_uptodate(bh);
+	unlock_buffer(bh);
+	return bh;
+}
+
+static inline void
+asfs_bstore(struct super_block *sb, struct buffer_head *bh)
+{
+	((struct fsBlockHeader *) (bh->b_data))->checksum =
+	    cpu_to_be32(asfs_calcchecksum(bh->b_data, sb->s_blocksize));
+	mark_buffer_dirty(bh);
+}
+
+static inline void asfs_brelse(struct buffer_head *bh)
+{
+	brelse(bh);
+}
+
+static inline void dec_count(struct inode *inode)
+{
+	inode->i_nlink--;
+	mark_inode_dirty(inode);
+}
+
+/* all prototypes */
+
+/* adminspace.c */
+int asfs_allocadminspace(struct super_block *sb, u32 * block);
+int asfs_freeadminspace(struct super_block *sb, u32 block);
+int asfs_markspace(struct super_block *sb, u32 block, u32 blocks);
+int asfs_freespace(struct super_block *sb, u32 block, u32 blocks);
+int asfs_findspace(struct super_block *sb, u32 maxneeded, u32 start, u32 end,
+	      u32 * returned_block, u32 * returned_blocks);
+
+/* dir.c */
+int asfs_readdir(struct file *filp, void *dirent, filldir_t filldir);
+struct dentry *asfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd);
+
+/* extents.c */
+int asfs_getextent(struct super_block *sb, u32 key, struct buffer_head **ret_bh,
+	      struct fsExtentBNode **ret_ebn);
+int asfs_deletebnode(struct super_block *sb, struct buffer_head *cb, u32 key);
+int asfs_deleteextents(struct super_block *sb, u32 key);
+int asfs_addblocks(struct super_block *sb, u16 blocks, u32 newspace,
+	      u32 objectnode, u32 * io_lastextentbnode);
+
+/* file.c */
+int asfs_readpage(struct file *file, struct page *page);
+sector_t asfs_bmap(struct address_space *mapping, sector_t block);
+int asfs_writepage(struct page *page, struct writeback_control *wbc);
+int asfs_prepare_write(struct file *file, struct page *page, unsigned from,
+		       unsigned to);
+void asfs_truncate(struct inode *inode);
+int asfs_file_open(struct inode *inode, struct file *filp);
+int asfs_file_release(struct inode *inode, struct file *filp);
+
+/* inode.c */
+struct inode *asfs_get_root_inode(struct super_block *sb);
+void asfs_read_locked_inode(struct inode *inode, void *arg);
+int asfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd);
+int asfs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
+int asfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname);
+int asfs_rmdir(struct inode *dir, struct dentry *dentry);
+int asfs_unlink(struct inode *dir, struct dentry *dentry);
+int asfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+		struct inode *new_dir, struct dentry *new_dentry);
+int asfs_notify_change(struct dentry *dentry, struct iattr *attr);
+
+/* namei */
+u8 asfs_lowerchar(u8 c);
+int asfs_check_name(const u8 *name, int len);
+int asfs_namecmp(u8 *s, u8 *ct, int casesensitive, struct nls_table *t);
+u16 asfs_hash(u8 *name, int casesensitive);
+void asfs_translate(u8 *to, u8 *from, struct nls_table *nls_to, struct nls_table *nls_from, int limit);
+
+/* nodes */
+int asfs_getnode(struct super_block *sb, u32 nodeno,
+	    struct buffer_head **ret_bh, struct fsObjectNode **ret_node);
+int asfs_createnode(struct super_block *sb, struct buffer_head **returned_cb,
+	       struct fsNode **returned_node, u32 * returned_nodeno);
+int asfs_deletenode(struct super_block *sb, u32 objectnode);
+
+/* objects */
+struct fsObject *asfs_nextobject(struct fsObject *obj);
+struct fsObject *asfs_find_obj_by_name(struct super_block *sb,
+		struct fsObjectContainer *objcont, u8 * name);
+int asfs_readobject(struct super_block *sb, u32 objectnode,
+	       struct buffer_head **cb, struct fsObject **returned_object);
+int asfs_createobject(struct super_block *sb, struct buffer_head **io_cb,
+		 struct fsObject **io_o, struct fsObject *src_o,
+		 u8 * objname, int force);
+int asfs_deleteobject(struct super_block *sb, struct buffer_head *cb,
+		 struct fsObject *o);
+int asfs_renameobject(struct super_block *sb, struct buffer_head *cb1,
+		 struct fsObject *o1, struct buffer_head *cbparent,
+		 struct fsObject *oparent, u8 * newname);
+
+int asfs_addblockstofile(struct super_block *sb, struct buffer_head *objcb,
+		    struct fsObject *o, u32 blocks, u32 * newspace,
+		    u32 * addedblocks);
+int asfs_truncateblocksinfile(struct super_block *sb, struct buffer_head *bh,
+			 struct fsObject *o, u32 newsize);
+
+/* super.c */
+struct super_block *asfs_read_super(struct super_block *sb, void *data,
+				    int silent);
+void asfs_put_super(struct super_block *sb);
+int asfs_statfs(struct super_block *sb, struct kstatfs *buf);
+int asfs_remount(struct super_block *sb, int *flags, char *data);
+struct inode *asfs_alloc_inode(struct super_block *sb);
+void asfs_destroy_inode(struct inode *inode);
+
+/* symlink.c */
+int asfs_symlink_readpage(struct file *file, struct page *page);
+int asfs_write_symlink(struct inode *symfile, const char *symname);
+
+#endif
diff -urN oldtree/fs/asfs/bitfuncs.c newtree/fs/asfs/bitfuncs.c
--- oldtree/fs/asfs/bitfuncs.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/asfs/bitfuncs.c	2006-02-21 15:58:33.133109560 +0000
@@ -0,0 +1,171 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include "bitfuncs.h"
+
+/* Bitmap (bm) functions:
+   These functions perform bit-operations on regions of memory which
+   are a multiple of 4 bytes in length. Bitmap is in bigendian byte order.
+*/
+
+/* This function finds the first set bit in a region of memory starting
+   with /bitoffset/.  The region of memory is /longs/ longs long.  It
+   returns the bitoffset of the first set bit it finds. */
+
+int bmffo(u32 *bitmap, int longs, int bitoffset)
+{
+	u32 *scan = bitmap;
+	int longoffset, bit;
+
+	longoffset = bitoffset >> 5;
+	longs -= longoffset;
+	scan += longoffset;
+
+	bitoffset = bitoffset & 0x1F;
+
+	if (bitoffset != 0) {
+		if ((bit = bfffo(be32_to_cpu(*scan), bitoffset)) >= 0) {
+			return (bit + ((scan - bitmap) << 5));
+		}
+		scan++;
+		longs--;
+	}
+
+	while (longs-- > 0) {
+		if (*scan++ != 0) {
+			return (bfffo(be32_to_cpu(*--scan), 0) + ((scan - bitmap) << 5));
+		}
+	}
+
+	return (-1);
+}
+
+/* This function finds the first unset bit in a region of memory starting
+   with /bitoffset/.  The region of memory is /longs/ longs long.  It
+   returns the bitoffset of the first unset bit it finds. */
+
+int bmffz(u32 *bitmap, int longs, int bitoffset)
+{
+	u32 *scan = bitmap;
+	int longoffset, bit;
+
+	longoffset = bitoffset >> 5;
+	longs -= longoffset;
+	scan += longoffset;
+
+	bitoffset = bitoffset & 0x1F;
+
+	if (bitoffset != 0) {
+		if ((bit = bfffz(be32_to_cpu(*scan), bitoffset)) >= 0) {
+			return (bit + ((scan - bitmap) << 5));
+		}
+		scan++;
+		longs--;
+	}
+
+	while (longs-- > 0) {
+		if (*scan++ != 0xFFFFFFFF) {
+			return (bfffz(be32_to_cpu(*--scan), 0) + ((scan - bitmap) << 5));
+		}
+	}
+
+	return (-1);
+}
+
+/* This function clears /bits/ bits in a region of memory starting
+   with /bitoffset/.  The region of memory is /longs/ longs long.  If
+   the region of memory is too small to clear /bits/ bits then this
+   function exits after having cleared all bits till the end of the
+   memory region.  In any case it returns the number of bits which
+   were actually cleared. */
+
+int bmclr(u32 *bitmap, int longs, int bitoffset, int bits)
+{
+	u32 *scan = bitmap;
+	int longoffset;
+	int orgbits = bits;
+
+	longoffset = bitoffset >> 5;
+	longs -= longoffset;
+	scan += longoffset;
+
+	bitoffset = bitoffset & 0x1F;
+
+	if (bitoffset != 0) {
+		if (bits < 32) {
+			*scan = cpu_to_be32(bfclr(be32_to_cpu(*scan), bitoffset, bits));
+		} else {
+			*scan = cpu_to_be32(bfclr(be32_to_cpu(*scan), bitoffset, 32));
+		}
+		scan++;
+		longs--;
+		bits -= 32 - bitoffset;
+	}
+
+	while (bits > 0 && longs-- > 0) {
+		if (bits > 31) {
+			*scan++ = 0;
+		} else {
+			*scan = cpu_to_be32(bfclr(be32_to_cpu(*scan), 0, bits));
+		}
+		bits -= 32;
+	}
+
+	if (bits <= 0) {
+		return (orgbits);
+	}
+	return (orgbits - bits);
+}
+
+/* This function sets /bits/ bits in a region of memory starting
+   with /bitoffset/.  The region of memory is /longs/ longs long.  If
+   the region of memory is too small to set /bits/ bits then this
+   function exits after having set all bits till the end of the
+   memory region.  In any case it returns the number of bits which
+   were actually set. */
+
+int bmset(u32 *bitmap, int longs, int bitoffset, int bits)
+{
+	u32 *scan = bitmap;
+	int longoffset;
+	int orgbits = bits;
+
+	longoffset = bitoffset >> 5;
+	longs -= longoffset;
+	scan += longoffset;
+
+	bitoffset = bitoffset & 0x1F;
+
+	if (bitoffset != 0) {
+		if (bits < 32) {
+			*scan = cpu_to_be32(bfset(be32_to_cpu(*scan), bitoffset, bits));
+		} else {
+			*scan = cpu_to_be32(bfset(be32_to_cpu(*scan), bitoffset, 32));
+		}
+		scan++;
+		longs--;
+		bits -= 32 - bitoffset;
+	}
+
+	while (bits > 0 && longs-- > 0) {
+		if (bits > 31) {
+			*scan++ = 0xFFFFFFFF;
+		} else {
+			*scan = cpu_to_be32(bfset(be32_to_cpu(*scan), 0, bits));
+		}
+		bits -= 32;
+	}
+
+	if (bits <= 0) {
+		return (orgbits);
+	}
+	return (orgbits - bits);
+}
diff -urN oldtree/fs/asfs/bitfuncs.h newtree/fs/asfs/bitfuncs.h
--- oldtree/fs/asfs/bitfuncs.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/asfs/bitfuncs.h	2006-02-21 15:58:33.134109408 +0000
@@ -0,0 +1,59 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#ifndef __BITFUNCS_H
+#define __BITFUNCS_H
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#include <asm/bitops.h>
+#include <linux/bitops.h>
+
+/* Finds first set bit in /data/ starting at /bitoffset/.  This function
+   considers the MSB to be the first bit. */
+static inline int bfffo(u32 data, int bitoffset)
+{
+	u32 mask = 0xffffffff >> bitoffset;
+	data &= mask;
+	return data == 0 ? -1 : 32-fls(data);
+}
+
+/* Finds first zero bit in /data/ starting at /bitoffset/.  This function
+   considers the MSB to be the first bit. */
+static inline int bfffz(u32 data, int bitoffset)
+{
+	return bfffo(~data, bitoffset);
+}
+
+/* Sets /bits/ bits starting from /bitoffset/ in /data/.
+   /bits/ must be between 1 and 32. */
+static inline u32 bfset(u32 data, int bitoffset, int bits)
+{
+	u32 mask = ~((1 << (32 - bits)) - 1);
+	mask >>= bitoffset;
+	return data | mask;
+}
+
+/* Clears /bits/ bits starting from /bitoffset/ in /data/.
+   /bits/ must be between 1 and 32. */
+static inline u32 bfclr(u32 data, int bitoffset, int bits)
+{
+	u32 mask = ~((1 << (32 - bits)) - 1);
+	mask >>= bitoffset;
+	return data & ~mask;
+}
+
+/* bm??? functions assumes that in-memory bitmap is in bigendian byte order */
+int bmffo(u32 *, int, int);
+int bmffz(u32 *, int, int);
+int bmclr(u32 *, int, int, int);
+int bmset(u32 *, int, int, int);
+
+#endif
diff -urN oldtree/fs/asfs/dir.c newtree/fs/asfs/dir.c
--- oldtree/fs/asfs/dir.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/asfs/dir.c	2006-02-21 15:58:33.134109408 +0000
@@ -0,0 +1,240 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta7
+ *
+ * Copyright (C) 2003,2004  Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include "asfs_fs.h"
+
+#include <asm/byteorder.h>
+
+extern struct dentry_operations asfs_dentry_operations;
+
+int asfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+	struct inode *dir = filp->f_dentry->d_inode;
+	struct super_block *sb = dir->i_sb;
+	struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
+	struct nls_table *nls_disk = ASFS_SB(sb)->nls_disk;
+	u8 buf[512];
+	unsigned long f_pos;
+	int stored = 0;
+
+	struct buffer_head *bh;
+	struct fsObjectContainer *objcont;
+	struct fsObject *obj;
+	u32 block;
+	int startnode;
+	int add;
+
+	asfs_debug("asfs_readdir:\n");
+
+	if (filp->f_pos == ASFS_SB(sb)->totalblocks)
+		return stored;
+
+	f_pos = filp->f_pos;
+
+	if (f_pos == 0) {
+		filp->private_data = (void *)0;
+		if (filldir(dirent, ".", 1, f_pos, dir->i_ino, DT_DIR) < 0)
+			return 0;
+		filp->f_pos = f_pos = 1;
+		stored++;
+	}
+	if (f_pos == 1) {
+		if (filldir(dirent, "..", 2, f_pos, parent_ino(filp->f_dentry), DT_DIR) < 0)
+			return stored;
+		filp->f_pos = f_pos = 2;
+		stored++;
+	}
+
+	if (ASFS_I(dir)->firstblock == 0) {	/* empty directory */
+		filp->f_pos = ASFS_SB(sb)->totalblocks;
+		ASFS_I(dir)->modified = 0;
+		return stored;
+	}
+
+	if (f_pos == 2) {	/* reading directory from its beginning */
+		block = ASFS_I(dir)->firstblock;
+		add = 1;
+		startnode = 0;
+	} else {
+		startnode = (int)filp->private_data;
+		add = 0;
+		if (ASFS_I(dir)->modified == 0)
+			block = f_pos;
+		else
+			block = ASFS_I(dir)->firstblock;
+	}
+
+	do {
+		if (!(bh = asfs_breadcheck(sb, block, ASFS_OBJECTCONTAINER_ID)))
+			return stored;
+		objcont = (struct fsObjectContainer *) bh->b_data;
+		obj = &(objcont->object[0]);
+
+		while (be32_to_cpu(obj->objectnode) > 0 &&
+		      ((char *)obj - (char *)objcont) + sizeof(struct fsObject) + 2 < sb->s_blocksize) {
+
+			if (!add && be32_to_cpu(obj->objectnode) == startnode)
+				add++;
+
+			if (add && !(obj->bits & OTYPE_HIDDEN)) {
+				unsigned int type;
+				asfs_translate(buf, obj->name, nls_io, nls_disk, 512);
+				asfs_debug("ASFS: DirFilling: entry #%d \"%s\" (node %u offset %u), type %x\n", \
+				           stored, buf, be32_to_cpu(obj->objectnode), block, obj->bits);
+				filp->f_pos = block;
+
+				if (obj->bits & OTYPE_DIR)
+					type = DT_DIR;
+				else if (obj->bits & OTYPE_LINK && !(obj->bits & OTYPE_HARDLINK))
+					type = DT_LNK;
+				else
+					type = DT_REG;
+
+				if (filldir(dirent, buf, strlen(buf), block, be32_to_cpu(obj->objectnode), type) < 0) {
+					filp->private_data = (void *)be32_to_cpu(obj->objectnode);
+					ASFS_I(dir)->modified = 0;
+					asfs_debug("ASFS: DirFilling: to be continued...\n");
+					asfs_brelse(bh);
+					return stored;
+				}
+				stored++;
+			}
+			obj = asfs_nextobject(obj);
+		}
+		block = be32_to_cpu(objcont->next);
+		asfs_brelse(bh);
+
+	} while (block != 0);
+
+	filp->f_pos = ASFS_SB(sb)->totalblocks;
+	ASFS_I(dir)->modified = 0;
+
+	return stored;
+}
+
+static struct fsObject *asfs_find_obj_by_name_nls(struct super_block *sb, struct fsObjectContainer *objcont, u8 * name)
+{
+	struct fsObject *obj;
+	u8 buf[512];
+
+	obj = &(objcont->object[0]);
+	while (be32_to_cpu(obj->objectnode) > 0 && ((char *) obj - (char *) objcont) + sizeof(struct fsObject) + 2 < sb->s_blocksize) {
+		asfs_translate(buf, obj->name, ASFS_SB(sb)->nls_io, ASFS_SB(sb)->nls_disk, 512);
+		if (asfs_namecmp(buf, name, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE, ASFS_SB(sb)->nls_io) == 0) {
+			asfs_debug("Object found! Node %u, Name %s, Type %x, inCont %u\n", be32_to_cpu(obj->objectnode), obj->name, obj->bits, be32_to_cpu(objcont->bheader.ownblock));
+			return obj;
+		}
+		obj = asfs_nextobject(obj);
+	}
+	return NULL;
+}
+
+struct dentry *asfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+{
+	int res = -EACCES;       /* placeholder for "no data here" */
+	struct inode *inode;
+	struct super_block *sb = dir->i_sb;
+	u8 *name = (u8 *) dentry->d_name.name;
+	struct buffer_head *bh;
+	struct fsObject *obj;
+	u8 bufname[ASFS_MAXFN_BUF];
+
+	asfs_translate(bufname, name, ASFS_SB(sb)->nls_disk, ASFS_SB(sb)->nls_io, ASFS_MAXFN_BUF);
+
+	asfs_debug("asfs_lookup: (searching \"%s\"...) ", name);
+
+	lock_super(sb);
+
+	if ((!strchr(name, '?')) && (ASFS_I(dir)->hashtable != 0)) {	/* hashtable block is available and name can be reverse translated, quick search */
+		struct fsObjectNode *node_p;
+		struct buffer_head *node_bh;
+		u32 node;
+		u16 hash16;
+
+		asfs_debug("(quick search) ");
+
+		if (!(bh = asfs_breadcheck(sb, ASFS_I(dir)->hashtable, ASFS_HASHTABLE_ID))) {
+			unlock_super(sb);
+			return ERR_PTR(res);
+		}
+		hash16 = asfs_hash(bufname, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE);
+		node = be32_to_cpu(((struct fsHashTable *) bh->b_data)->hashentry[HASHCHAIN(hash16)]);
+		asfs_brelse(bh);
+
+		while (node != 0) {
+			if (asfs_getnode(sb, node, &node_bh, &node_p) != 0)
+				goto not_found;
+			if (be16_to_cpu(node_p->hash16) == hash16) {
+				if (!(bh = asfs_breadcheck(sb, be32_to_cpu(node_p->node.data), ASFS_OBJECTCONTAINER_ID))) {
+					asfs_brelse(node_bh);
+					unlock_super(sb);
+					return ERR_PTR(res);
+				}
+				if ((obj = asfs_find_obj_by_name(sb, (struct fsObjectContainer *) bh->b_data, bufname)) != NULL) {
+					asfs_brelse(node_bh);
+					goto found_inode;
+				}
+				asfs_brelse(bh);
+			}
+			node = be32_to_cpu(node_p->next);
+			asfs_brelse(node_bh);
+		}
+	} else { /* hashtable not available or name can't be reverse-translated, long search */
+		struct fsObjectContainer *objcont;
+		u32 block;
+
+		asfs_debug("(long search) ");
+		block = ASFS_I(dir)->firstblock;
+		while (block != 0) {
+			if (!(bh = asfs_breadcheck(sb, block, ASFS_OBJECTCONTAINER_ID))) {
+				unlock_super(sb);
+				return ERR_PTR(res);
+			}
+			objcont = (struct fsObjectContainer *) bh->b_data;
+			if ((obj = asfs_find_obj_by_name_nls(sb, objcont, name)) != NULL)
+				goto found_inode;
+			block = be32_to_cpu(objcont->next);
+			asfs_brelse(bh);
+		}
+	}
+
+not_found:
+	unlock_super(sb);
+	inode = NULL;
+	asfs_debug("object not found.\n");
+	if (0) {
+found_inode:
+		unlock_super(sb);
+		if (!(inode = iget_locked(sb, be32_to_cpu(obj->objectnode)))) {
+			asfs_debug("ASFS: Strange - no inode allocated.\n");
+			return ERR_PTR(res);
+		}
+		if (inode->i_state & I_NEW) {
+			asfs_read_locked_inode(inode, obj);
+			unlock_new_inode(inode);
+		}
+		asfs_brelse(bh);
+	}
+	res = 0;
+	dentry->d_op = &asfs_dentry_operations;
+	d_add(dentry, inode);
+	return ERR_PTR(res);
+}
diff -urN oldtree/fs/asfs/extents.c newtree/fs/asfs/extents.c
--- oldtree/fs/asfs/extents.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/asfs/extents.c	2006-02-21 15:58:33.135109256 +0000
@@ -0,0 +1,586 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta7
+ *
+ * This file contains some parts of the original amiga version of
+ * SmartFilesystem source code.
+ *
+ * SmartFilesystem is copyrighted (C) 2003 by: John Hendrikx,
+ * Ralph Schmidt, Emmanuel Lesueur, David Gerber and Marcin Kurek
+ *
+ * Adapted and modified by Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include "asfs_fs.h"
+
+#include <asm/byteorder.h>
+
+	/* This function looks for the BNode equal to the key.  If no
+	   exact match is available then the BNode which is slightly
+	   lower than key will be returned.  If no such BNode exists
+	   either, then the first BNode in this block is returned.
+
+	   This function will return the first BNode even if there
+	   are no BNode's at all in this block (this can only happen
+	   for the Root of the tree).  Be sure to check if the Root
+	   is not empty before calling this function. */
+
+static struct BNode *searchforbnode(u32 key, struct BTreeContainer *tc)
+{
+	struct BNode *tn;
+	s16 n = be16_to_cpu(tc->nodecount) - 1;
+
+	tn = (struct BNode *) ((u8 *) tc->bnode + n * tc->nodesize);
+	for (;;) {
+		if (n <= 0 || key >= be32_to_cpu(tn->key))
+			return tn;
+
+		tn = (struct BNode *) ((u8 *) tn - tc->nodesize);
+		n--;
+	}
+}
+
+/* This function finds the BNode with the given key.  If no exact match can be
+   found then this function will return either the next or previous closest
+   match (don't rely on this).
+
+   If there were no BNode's at all, then *returned_bh will be NULL. */
+
+static int findbnode(struct super_block *sb, u32 key, struct buffer_head **returned_bh, struct BNode **returned_bnode)
+{
+	u32 rootblock = ASFS_SB(sb)->extentbnoderoot;
+
+	asfs_debug("findbnode: Looking for BNode with key %d\n", key);
+
+	while ((*returned_bh = asfs_breadcheck(sb, rootblock, ASFS_BNODECONTAINER_ID))) {
+		struct fsBNodeContainer *bnc = (void *) (*returned_bh)->b_data;
+		struct BTreeContainer *btc = &bnc->btc;
+
+		if (btc->nodecount == 0) {
+			*returned_bnode = NULL;
+			break;
+		}
+
+		*returned_bnode = searchforbnode(key, btc);
+		if (btc->isleaf == TRUE)
+			break;
+
+		rootblock = be32_to_cpu((*returned_bnode)->data);
+		asfs_brelse(*returned_bh);
+	}
+
+	if (*returned_bh == NULL)
+		return -EIO;
+
+	return 0;
+}
+
+int asfs_getextent(struct super_block *sb, u32 key, struct buffer_head **ret_bh, struct fsExtentBNode **ret_ebn)
+{
+	int result;
+	if ((result = findbnode(sb, key, ret_bh, (struct BNode **)ret_ebn)) == 0)
+		if (be32_to_cpu((*ret_ebn)->key) != key) {
+			brelse(*ret_bh);
+			*ret_bh = NULL;
+			return -ENOENT;
+		}
+
+	return result;
+}
+
+#ifdef CONFIG_ASFS_RW
+
+	/* This routine inserts a node sorted into a BTreeContainer.  It does
+	   this by starting at the end, and moving the nodes one by one to
+	   a higher slot until the empty slot has the correct position for
+	   this key.  Donot use this function on completely filled
+	   BTreeContainers! */
+
+static struct BNode *insertbnode(u32 key, struct BTreeContainer *btc)
+{
+	struct BNode *bn;
+	bn = (struct BNode *) ((u8 *) btc->bnode + btc->nodesize * (be16_to_cpu(btc->nodecount) - 1));
+
+	for (;;) {
+		if (bn < btc->bnode || key > be32_to_cpu(bn->key)) {
+			bn = (struct BNode *) ((u8 *) bn + btc->nodesize);
+			bn->key = cpu_to_be32(key);
+			btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) + 1);
+			break;
+		} else
+			memmove((u8 *)bn + btc->nodesize, bn, btc->nodesize);
+
+		bn = (struct BNode *) ((u8 *) bn - btc->nodesize);
+	}
+
+	return bn;
+}
+
+static int getparentbtreecontainer(struct super_block *sb, struct buffer_head *bh, struct buffer_head **parent_bh)
+{
+	u32 rootblock = ASFS_SB(sb)->extentbnoderoot;
+	u32 childkey = be32_to_cpu(((struct fsBNodeContainer *) bh->b_data)->btc.bnode[0].key);
+	u32 childblock = be32_to_cpu(((struct fsBNodeContainer *) bh->b_data)->bheader.ownblock);
+
+	asfs_debug("getparentbtreecontainer: Getting parent of block %d\n", childblock);
+
+	/* This function gets the BTreeContainer parent of the passed in buffer_head. If
+	   there is no parent this function sets dest_cont io_bh to NULL */
+
+	if (rootblock != childblock) {
+		while ((*parent_bh = asfs_breadcheck(sb, rootblock, ASFS_BNODECONTAINER_ID))) {
+			struct fsBNodeContainer *bnc = (void *) (*parent_bh)->b_data;
+			struct BTreeContainer *btc = &bnc->btc;
+			struct BNode *bn;
+			s16 n = be16_to_cpu(btc->nodecount);
+
+			if (btc->isleaf == TRUE) {
+				asfs_brelse(*parent_bh);
+				break;
+			}
+
+			while (n-- > 0)
+				if (be32_to_cpu(btc->bnode[n].data) == childblock)
+					return 0;	/* Found parent!! */
+
+			bn = searchforbnode(childkey, btc);	/* This searchforbnode() doesn't have to get EXACT key matches. */
+			rootblock = be32_to_cpu(bn->data);
+			asfs_brelse(*parent_bh);
+		}
+		if (*parent_bh == NULL)
+			return -EIO;
+	}
+
+	*parent_bh = NULL;
+	return 0;
+}
+
+/* Spits a btreecontainer. It realses passed in bh! */
+
+static int splitbtreecontainer(struct super_block *sb, struct buffer_head *bh)
+{
+	struct buffer_head *bhparent;
+	struct BNode *bn;
+	int errorcode;
+
+	asfs_debug("splitbtreecontainer: splitting block %u\n", be32_to_cpu(((struct fsBlockHeader *) bh->b_data)->ownblock));
+
+	if ((errorcode = getparentbtreecontainer(sb, bh, &bhparent)) == 0) {
+		if (bhparent == NULL) {
+			u32 newbcontblock;
+			u32 bcontblock;
+			/* We need to create Root tree-container - adding new level to extent tree */
+
+			asfs_debug("splitbtreecontainer: creating root tree-container.\n");
+
+			bhparent = bh;
+			if ((errorcode = asfs_allocadminspace(sb, &newbcontblock)) == 0 && (bh = asfs_getzeroblk(sb, newbcontblock))) {
+				struct fsBNodeContainer *bnc = (void *) bh->b_data;
+				struct fsBNodeContainer *bncparent = (void *) bhparent->b_data;
+				struct BTreeContainer *btcparent = &bncparent->btc;
+
+				bcontblock = be32_to_cpu(bncparent->bheader.ownblock);
+				memcpy(bh->b_data, bhparent->b_data, sb->s_blocksize);
+				bnc->bheader.ownblock = cpu_to_be32(newbcontblock);
+				asfs_bstore(sb, bh);
+
+				memset(bhparent->b_data, '\0', sb->s_blocksize);	/* Not strictly needed, but makes things more clear. */
+				bncparent->bheader.id = cpu_to_be32(ASFS_BNODECONTAINER_ID);
+				bncparent->bheader.ownblock = cpu_to_be32(bcontblock);
+				btcparent->isleaf = FALSE;
+				btcparent->nodesize = sizeof(struct BNode);
+				btcparent->nodecount = 0;
+
+				bn = insertbnode(0, btcparent);
+				bn->data = cpu_to_be32(newbcontblock);
+
+				asfs_bstore(sb, bhparent);
+			}
+			if (bh == NULL)
+				errorcode = -EIO;
+		}
+
+		if (errorcode == 0) {
+			struct fsBNodeContainer *bncparent = (void *) bhparent->b_data;
+			struct BTreeContainer *btcparent = &bncparent->btc;
+			int branches1 = (sb->s_blocksize - sizeof(struct fsBNodeContainer)) / btcparent->nodesize;
+
+			if (be16_to_cpu(btcparent->nodecount) == branches1) {
+				/* We need to split the parent tree-container first! */
+				if ((errorcode = splitbtreecontainer(sb, bhparent)) == 0) {
+					/* bhparent might have changed after the split and has been released */
+					if ((errorcode = getparentbtreecontainer(sb, bh, &bhparent)) == 0) {
+						bncparent = (void *) bhparent->b_data;
+						btcparent = &bncparent->btc;
+					}
+				}
+			}
+
+			if (errorcode == 0) {
+				u32 newbcontblock;
+				struct buffer_head *bhnew;
+
+				/* We can split this container and add it to the parent
+				   because the parent has enough room. */
+
+				if ((errorcode = asfs_allocadminspace(sb, &newbcontblock)) == 0 && (bhnew = asfs_getzeroblk(sb, newbcontblock))) {
+					struct fsBNodeContainer *bncnew = (void *) bhnew->b_data;
+					struct BTreeContainer *btcnew = &bncnew->btc;
+					struct fsBNodeContainer *bnc = (void *) bh->b_data;
+					struct BTreeContainer *btc = &bnc->btc;
+					int branches2 = (sb->s_blocksize - sizeof(struct fsBNodeContainer)) / btc->nodesize;
+					u32 newkey;
+
+					bncnew->bheader.id = cpu_to_be32(ASFS_BNODECONTAINER_ID);
+					bncnew->bheader.ownblock = cpu_to_be32(newbcontblock);
+
+					btcnew->isleaf = btc->isleaf;
+					btcnew->nodesize = btc->nodesize;
+
+					btcnew->nodecount = cpu_to_be16(branches2 - branches2 / 2);
+
+					memcpy(btcnew->bnode, (u8 *) btc->bnode + branches2 / 2 * btc->nodesize, (branches2 - branches2 / 2) * btc->nodesize);
+					newkey = be32_to_cpu(btcnew->bnode[0].key);
+
+					asfs_bstore(sb, bhnew);
+					asfs_brelse(bhnew);
+
+					btc->nodecount = cpu_to_be16(branches2 / 2);
+					asfs_bstore(sb, bh);
+
+					bn = insertbnode(newkey, btcparent);
+					bn->data = cpu_to_be32(newbcontblock);
+					asfs_bstore(sb, bhparent);
+				}
+			}
+		}
+		asfs_brelse(bhparent);
+	}
+	asfs_brelse(bh);
+
+	return errorcode;
+}
+
+/* Returns created extentbnode - returned_bh need to saved and realesed in caller funkction! */
+
+int createextentbnode(struct super_block *sb, u32 key, struct buffer_head **returned_bh, struct BNode **returned_bnode)
+{
+	int errorcode;
+
+	asfs_debug("createbnode: Creating BNode with key %d\n", key);
+
+	while ((errorcode = findbnode(sb, key, returned_bh, returned_bnode)) == 0) {
+		struct fsBNodeContainer *bnc = (void *) (*returned_bh)->b_data;
+		struct BTreeContainer *btc = &bnc->btc;
+		int extbranches = (sb->s_blocksize - sizeof(struct fsBNodeContainer)) / btc->nodesize;
+
+		asfs_debug("createbnode: findbnode found block %d\n", be32_to_cpu(((struct fsBlockHeader *) (*returned_bh)->b_data)->ownblock));
+
+		if (be16_to_cpu(btc->nodecount) < extbranches) {
+			/* Simply insert new node in this BTreeContainer */
+			asfs_debug("createbnode: Simple insert\n");
+			*returned_bnode = insertbnode(key, btc);
+			break;
+		} else if ((errorcode = splitbtreecontainer(sb, *returned_bh)) != 0)
+			break;
+
+		/* Loop and try insert it the normal way again :-) */
+	}
+
+	return (errorcode);
+}
+
+
+/* This routine removes a node from a BTreeContainer indentified
+   by its key.  If no such key exists this routine does nothing.
+   It correctly handles empty BTreeContainers. */
+
+static void removebnode(u32 key, struct BTreeContainer *btc)
+{
+	struct BNode *bn = btc->bnode;
+	int n = 0;
+
+	asfs_debug("removebnode: key %d\n", key);
+
+	while (n < be16_to_cpu(btc->nodecount)) {
+		if (be32_to_cpu(bn->key) == key) {
+			btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) - 1);
+			memmove(bn, (u8 *) bn + btc->nodesize, (be16_to_cpu(btc->nodecount) - n) * btc->nodesize);
+			break;
+		}
+		bn = (struct BNode *) ((u8 *) bn + btc->nodesize);
+		n++;
+	}
+}
+
+int asfs_deletebnode(struct super_block *sb, struct buffer_head *bh, u32 key)
+{
+	struct fsBNodeContainer *bnc1 = (void *) bh->b_data;
+	struct BTreeContainer *btc = &bnc1->btc;
+	u16 branches = (sb->s_blocksize - sizeof(struct fsBNodeContainer)) / btc->nodesize;
+	int errorcode = 0;
+
+	/* Deletes specified internal node. */
+
+	removebnode(key, btc);
+	asfs_bstore(sb, bh);
+
+	/* Now checks if the container still contains enough nodes,
+	   and takes action accordingly. */
+
+	asfs_debug("deletebnode: branches = %d, btc->nodecount = %d\n", branches, be16_to_cpu(btc->nodecount));
+
+	if (be16_to_cpu(btc->nodecount) < (branches + 1) / 2) {
+		struct buffer_head *bhparent;
+		struct buffer_head *bhsec;
+
+		/* nodecount has become to low.  We need to merge this Container
+		   with a neighbouring Container, or we need to steal a few nodes
+		   from a neighbouring Container. */
+
+		/* We get the parent of the container here, so we can find out what
+		   containers neighbour the container which currently hasn't got enough nodes. */
+
+		if ((errorcode = getparentbtreecontainer(sb, bh, &bhparent)) == 0) {
+			if (bhparent != NULL) {
+				struct fsBNodeContainer *bncparent = (void *) bhparent->b_data;
+				struct BTreeContainer *btcparent = &bncparent->btc;
+				s16 n;
+
+				asfs_debug("deletebnode: get parent returned block %d.\n", be32_to_cpu(((struct fsBlockHeader *) bhparent->b_data)->ownblock));
+
+				for (n = 0; n < be16_to_cpu(btcparent->nodecount); n++)
+					if (btcparent->bnode[n].data == bnc1->bheader.ownblock)
+						break;
+				/* n is now the offset of our own bnode. */
+
+				if (n < be16_to_cpu(btcparent->nodecount) - 1) {	/* Check if we have a next neighbour. */
+					asfs_debug("deletebnode: using next container - merging blocks %d and %d\n", be32_to_cpu(bnc1->bheader.ownblock), be32_to_cpu(btcparent->bnode[n+1].data));
+
+					if ((bhsec = asfs_breadcheck(sb, be32_to_cpu(btcparent->bnode[n + 1].data), ASFS_BNODECONTAINER_ID))) {
+						struct fsBNodeContainer *bnc_next = (void *) bhsec->b_data;
+						struct BTreeContainer *btc_next = &bnc_next->btc;
+
+						if (be16_to_cpu(btc_next->nodecount) + be16_to_cpu(btc->nodecount) > branches) {	/* Check if we need to steal nodes. */
+							s16 nodestosteal = (be16_to_cpu(btc_next->nodecount) + be16_to_cpu(btc->nodecount)) / 2 - be16_to_cpu(btc->nodecount);
+
+							/* Merging them is not possible.  Steal a few nodes then. */
+							memcpy((u8 *) btc->bnode + be16_to_cpu(btc->nodecount) * btc->nodesize, btc_next->bnode, nodestosteal * btc->nodesize);
+							btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) + nodestosteal);
+							asfs_bstore(sb, bh);
+
+							memcpy(btc_next->bnode, (u8 *) btc_next->bnode + btc_next->nodesize * nodestosteal,
+							       btc->nodesize * (be16_to_cpu(btc_next->nodecount) - nodestosteal));
+							btc_next->nodecount = cpu_to_be16(be16_to_cpu(btc_next->nodecount) - nodestosteal);
+							asfs_bstore(sb, bhsec);
+
+							btcparent->bnode[n + 1].key = btc_next->bnode[0].key;
+							asfs_bstore(sb, bhparent);
+						} else {	/* Merging is possible. */
+							memcpy((u8 *) btc->bnode + btc->nodesize * be16_to_cpu(btc->nodecount), btc_next->bnode, btc->nodesize * be16_to_cpu(btc_next->nodecount));
+							btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) + be16_to_cpu(btc_next->nodecount));
+							asfs_bstore(sb, bh);
+
+							if ((errorcode = asfs_freeadminspace(sb, be32_to_cpu(((struct fsBlockHeader *) bhsec->b_data)->ownblock))) == 0)
+								errorcode = asfs_deletebnode(sb, bhparent, be32_to_cpu(btcparent->bnode[n + 1].key));
+						}
+						asfs_brelse(bhsec);
+					}
+				} else if (n > 0) {	/* Check if we have a previous neighbour. */
+					asfs_debug("deletebnode: using prev container.\n");
+
+					if ((bhsec = asfs_breadcheck(sb, be32_to_cpu(btcparent->bnode[n - 1].data), ASFS_BNODECONTAINER_ID)) == 0) {
+						struct fsBNodeContainer *bnc2 = (void *) bhsec->b_data;
+						struct BTreeContainer *btc2 = &bnc2->btc;
+
+						if (be16_to_cpu(btc2->nodecount) + be16_to_cpu(btc->nodecount) > branches) {
+							/* Merging them is not possible.  Steal a few nodes then. */
+							s16 nodestosteal = (be16_to_cpu(btc2->nodecount) + be16_to_cpu(btc->nodecount)) / 2 - be16_to_cpu(btc->nodecount);
+
+							memmove((u8 *) btc->bnode + nodestosteal * btc->nodesize, btc->bnode, be16_to_cpu(btc->nodecount) * btc->nodesize);
+							btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) + nodestosteal);
+							memcpy(btc->bnode, (u8 *) btc2->bnode + (be16_to_cpu(btc2->nodecount) - nodestosteal) * btc2->nodesize, nodestosteal * btc->nodesize);
+
+							asfs_bstore(sb, bh);
+
+							btc2->nodecount = cpu_to_be16(be16_to_cpu(btc2->nodecount) - nodestosteal);
+							asfs_bstore(sb, bhsec);
+
+							btcparent->bnode[n].key = btc->bnode[0].key;
+							asfs_bstore(sb, bhparent);
+						} else {	/* Merging is possible. */
+							memcpy((u8 *) btc2->bnode + be16_to_cpu(btc2->nodecount) * btc2->nodesize, btc->bnode, be16_to_cpu(btc->nodecount) * btc->nodesize);
+							btc2->nodecount = cpu_to_be16(be16_to_cpu(btc2->nodecount) + be16_to_cpu(btc->nodecount));
+							asfs_bstore(sb, bhsec);
+
+							if ((errorcode = asfs_freeadminspace(sb, be32_to_cpu(((struct fsBlockHeader *) bhsec->b_data)->ownblock))) == 0)
+								errorcode = asfs_deletebnode(sb, bhparent, be32_to_cpu(btcparent->bnode[n].key));
+						}
+						asfs_brelse(bhsec);
+					}
+				}
+				/*      else
+				   {
+				   // Never happens, except for root and then we don't care.
+				   } */
+			} else if (btc->nodecount == 1) {
+				/* No parent, so must be root. */
+
+				asfs_debug("deletebnode: no parent so must be root\n");
+
+				if (btc->isleaf == FALSE) {
+					struct fsBNodeContainer *bnc3 = (void *) bh->b_data;
+
+					/* The current root has only 1 node.  We now copy the data of this node into the
+					   root and promote that data to be the new root.  The rootblock number stays the
+					   same that way. */
+
+					if ((bhsec = asfs_breadcheck(sb, be32_to_cpu(btc->bnode[0].data), ASFS_BNODECONTAINER_ID))) {
+						u32 blockno = be32_to_cpu(((struct fsBlockHeader *) bh->b_data)->ownblock);
+						memcpy(bh->b_data, bhsec->b_data, sb->s_blocksize);
+						bnc3->bheader.ownblock = cpu_to_be32(blockno);
+
+						asfs_bstore(sb, bh);
+						errorcode = asfs_freeadminspace(sb, be32_to_cpu(((struct fsBlockHeader *) bhsec->b_data)->ownblock));
+						asfs_brelse(bhsec);
+					} else
+						errorcode = -EIO;
+				}
+				/* If not, then root contains leafs. */
+			}
+
+			asfs_debug("deletebnode: almost done\n");
+			/* otherwise, it must be the root, and the root is allowed
+			   to contain less than the minimum amount of nodes. */
+
+		}
+		if (bhparent != NULL)
+			asfs_brelse(bhparent);
+	}
+
+	return errorcode;
+}
+
+   /* Deletes an fsExtentBNode structure by key and any fsExtentBNodes linked to it.
+      This function DOES NOT fix the next pointer in a possible fsExtentBNode which
+      might have been pointing to the first BNode we are deleting.  Make sure you check
+      this yourself, if needed.
+
+      If key is zero, than this function does nothing. */
+
+int asfs_deleteextents(struct super_block *sb, u32 key)
+{
+	struct buffer_head *bh;
+	struct fsExtentBNode *ebn;
+	int errorcode = 0;
+
+	asfs_debug("deleteextents: Entry -- deleting extents from key %d\n", key);
+
+	while (key != 0 && (errorcode = findbnode(sb, key, &bh, (struct BNode **) &ebn)) == 0) {
+		/* node to be deleted located. */
+		key = be32_to_cpu(ebn->next);
+		if ((errorcode = asfs_freespace(sb, be32_to_cpu(ebn->key), be16_to_cpu(ebn->blocks))) != 0)
+			break;
+
+		if ((errorcode = asfs_deletebnode(sb, bh, be32_to_cpu(ebn->key))) != 0)
+			break;
+
+		asfs_brelse(bh);
+	}
+
+	return (errorcode);
+}
+
+   /* This function adds /blocks/ blocks starting at block /newspace/ to a file
+      identified by /objectnode/ and /lastextentbnode/.  /io_lastextentbnode/ can
+      be zero if there is no ExtentBNode chain attached to this file yet.
+      /blocks/ ranges from 1 to 8192.  To be able to extend Extents which are
+      almost full, it is wise to make this value no higher than 8192 blocks.
+      /io_lastextentbnode/ will contain the new lastextentbnode value when this
+      function completes.
+      If there was no chain yet, then this function will create a new one.  */
+
+int asfs_addblocks(struct super_block *sb, u16 blocks, u32 newspace, u32 objectnode, u32 *io_lastextentbnode)
+{
+	struct buffer_head *bh;
+	struct fsExtentBNode *ebn;
+	int errorcode = 0;
+
+	if (*io_lastextentbnode != 0) {
+		/* There was already a ExtentBNode chain for this file.  Extending it. */
+
+		asfs_debug("  addblocks: Extending existing ExtentBNode chain.\n");
+
+		if ((errorcode = asfs_getextent(sb, *io_lastextentbnode, &bh, &ebn)) == 0) {
+			if (be32_to_cpu(ebn->key) + be16_to_cpu(ebn->blocks) == newspace && be16_to_cpu(ebn->blocks) + blocks < 65536) {
+				/* It is possible to extent the last ExtentBNode! */
+				asfs_debug("  addblocks: Extending last ExtentBNode.\n");
+
+				ebn->blocks = cpu_to_be16(be16_to_cpu(ebn->blocks) + blocks);
+
+				asfs_bstore(sb, bh);
+				asfs_brelse(bh);
+			} else {
+				/* It isn't possible to extent the last ExtentBNode so we create
+				   a new one and link it to the last ExtentBNode. */
+
+				ebn->next = cpu_to_be32(newspace);
+				asfs_bstore(sb, bh);
+				asfs_brelse(bh);
+
+				if ((errorcode = createextentbnode(sb, newspace, &bh, (struct BNode **) &ebn)) == 0) {
+					asfs_debug("  addblocks: Created new ExtentBNode.\n");
+
+					ebn->key = cpu_to_be32(newspace);
+					ebn->prev = cpu_to_be32(*io_lastextentbnode);
+					ebn->next = 0;
+					ebn->blocks = cpu_to_be16(blocks);
+
+					*io_lastextentbnode = newspace;
+
+					asfs_bstore(sb, bh);
+					asfs_brelse(bh);
+
+					ASFS_SB(sb)->block_rovingblockptr = newspace + blocks;
+
+	/* to be changed in the future */
+/*					if (ASFS_SB(sb)->block_rovingblockptr >= ASFS_SB(sb)->totalblocks)
+						ASFS_SB(sb)->block_rovingblockptr = 0;*/
+				}
+			}
+		}
+	} else {
+		/* There is no ExtentBNode chain yet for this file.  Attaching one! */
+		if ((errorcode = createextentbnode(sb, newspace, &bh, (struct BNode **) &ebn)) == 0) {
+			asfs_debug("  addblocks: Created new ExtentBNode chain.\n");
+
+			ebn->key = cpu_to_be32(newspace);
+			ebn->prev = cpu_to_be32(objectnode + 0x80000000);
+			ebn->next = 0;
+			ebn->blocks = cpu_to_be16(blocks);
+
+			*io_lastextentbnode = newspace;
+
+			asfs_bstore(sb, bh);
+			asfs_brelse(bh);
+
+			ASFS_SB(sb)->block_rovingblockptr = newspace + blocks;
+
+/*			if (ASFS_SB(sb)->block_rovingblockptr >= ASFS_SB(sb)->totalblocks)
+				ASFS_SB(sb)->block_rovingblockptr = 0;*/
+		}
+	}
+
+	asfs_debug("  addblocks: done.\n");
+
+	return errorcode;
+}
+#endif
diff -urN oldtree/fs/asfs/file.c newtree/fs/asfs/file.c
--- oldtree/fs/asfs/file.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/asfs/file.c	2006-02-21 15:58:33.136109104 +0000
@@ -0,0 +1,251 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta7
+ *
+ * Copyright (C) 2003,2004  Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include "asfs_fs.h"
+
+#include <asm/byteorder.h>
+
+static int
+asfs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_result, int create)
+{
+	struct buffer_head *ebn_bh;
+	struct fsExtentBNode extent, *ebn_p;
+	u32 filedata;
+	unsigned long pos;
+	struct super_block *sb = inode->i_sb;
+#ifdef CONFIG_ASFS_RW
+	int error;
+	struct buffer_head *bh;
+	struct fsObject *obj;
+#endif
+
+	asfs_debug("ASFS: get_block(%lu, %ld, %d)\n", inode->i_ino, block, create);
+
+	if (block < 0) {
+		printk(KERN_ERR "ASFS: asfsget_block: requested block (%lld) < 0!\n", (unsigned long long)block);
+		return -EIO;
+	} else if (block >= inode->i_blocks && !create) {
+		printk(KERN_ERR "ASFS: asfsget_block: strange block request %lld!\n", (unsigned long long)block);
+		return -EIO;
+	}
+
+	if (create)
+#ifdef CONFIG_ASFS_RW
+		ASFS_I(inode)->modified = TRUE;
+#else
+		return -EROFS;
+#endif
+
+	if (block < inode->i_blocks)
+		create = 0;
+
+	lock_super(sb);
+
+#ifdef CONFIG_ASFS_RW
+	if (create) {
+		int blockstoadd;
+		u32 newspace, addedblocks;
+
+		blockstoadd = block - inode->i_blocks + 1;
+
+		if (blockstoadd < ASFS_BLOCKCHUNKS)
+			blockstoadd = ASFS_BLOCKCHUNKS;
+
+		asfs_debug("ASFS get_block: Trying to add %d blocks to file\n", blockstoadd);
+
+		if ((error = asfs_readobject(sb, inode->i_ino, &bh, &obj)) != 0) {
+			unlock_super(sb);
+			return error;
+		}
+
+		if ((error = asfs_addblockstofile(sb, bh, obj, blockstoadd, &newspace, &addedblocks)) != 0) {
+			asfs_brelse(bh);
+			unlock_super(sb);
+			return error;
+		}
+		ASFS_I(inode)->mmu_private += addedblocks * sb->s_blocksize;
+		inode->i_blocks += addedblocks;
+		ASFS_I(inode)->ext_cache.key = 0;
+		ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data);
+		asfs_brelse(bh);
+	}
+#endif
+
+	if (ASFS_I(inode)->ext_cache.key > 0 && ASFS_I(inode)->ext_cache.startblock <= block) {
+		extent.key = ASFS_I(inode)->ext_cache.key;
+		extent.next = ASFS_I(inode)->ext_cache.next;
+		extent.blocks = ASFS_I(inode)->ext_cache.blocks;
+		pos = ASFS_I(inode)->ext_cache.startblock;
+	} else {
+		if (asfs_getextent(inode->i_sb, ASFS_I(inode)->firstblock, &ebn_bh, &ebn_p) != 0) {
+			unlock_super(sb);
+			return -EIO;
+		}
+		extent.key = be32_to_cpu(ebn_p->key);
+		extent.next = be32_to_cpu(ebn_p->next);
+		extent.blocks = be16_to_cpu(ebn_p->blocks);
+		pos = 0;
+		asfs_brelse(ebn_bh);
+	}
+	ebn_p = &extent;
+	filedata = ebn_p->next;
+
+	while (pos + ebn_p->blocks <= block && ebn_p->next != 0 && pos < inode->i_blocks) {
+		pos += ebn_p->blocks;
+		if (asfs_getextent(inode->i_sb, filedata, &ebn_bh, &ebn_p) != 0) {
+			unlock_super(sb);
+			return -EIO;
+		}
+		extent.key = be32_to_cpu(ebn_p->key);
+		extent.next = be32_to_cpu(ebn_p->next);
+		extent.blocks = be16_to_cpu(ebn_p->blocks);
+		ebn_p = &extent;
+		filedata = ebn_p->next;
+		asfs_brelse(ebn_bh);
+	}
+
+	unlock_super(sb);
+
+	map_bh(bh_result, inode->i_sb, (sector_t) (ebn_p->key + block - pos));
+
+	if (create)
+		set_buffer_new(bh_result);
+
+	asfs_debug("ASFS: get_block - mapped block %lu\n", ebn_p->key + block - pos);
+
+	ASFS_I(inode)->ext_cache.startblock = pos;
+	ASFS_I(inode)->ext_cache.key = ebn_p->key;
+	ASFS_I(inode)->ext_cache.next = ebn_p->next;
+	ASFS_I(inode)->ext_cache.blocks = ebn_p->blocks;
+
+	return 0;
+}
+
+int asfs_readpage(struct file *file, struct page *page)
+{
+	asfs_debug("ASFS: %s\n", __FUNCTION__);
+	return block_read_full_page(page, asfs_get_block);
+}
+
+sector_t asfs_bmap(struct address_space *mapping, sector_t block)
+{
+	asfs_debug("ASFS: %s\n", __FUNCTION__);
+	return generic_block_bmap(mapping,block,asfs_get_block);
+}
+
+#ifdef CONFIG_ASFS_RW
+
+int asfs_writepage(struct page *page, struct writeback_control *wbc)
+{
+	asfs_debug("ASFS: %s\n", __FUNCTION__);
+	return block_write_full_page(page, asfs_get_block, wbc);
+}
+
+int asfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
+{
+	asfs_debug("ASFS: %s\n", __FUNCTION__);
+	return cont_prepare_write(page, from, to, asfs_get_block, &ASFS_I(page->mapping->host)->mmu_private);
+}
+
+void asfs_truncate(struct inode *inode)
+{
+	struct super_block *sb = inode->i_sb;
+	struct buffer_head *bh;
+	struct fsObject *obj;
+
+	asfs_debug("AFFS: truncate(inode=%d, oldsize=%u, newsize=%u)\n",
+		 (u32)inode->i_ino, (u32)ASFS_I(inode)->mmu_private, (u32)inode->i_size);
+
+	if (inode->i_size > ASFS_I(inode)->mmu_private) {
+		printk("ASFS: enlarging file is not supported yet\n");
+		return;
+	}
+
+	lock_super(sb);
+
+	if ((asfs_readobject(sb, inode->i_ino, &bh, &obj)) != 0) {
+		unlock_super(sb);
+		return;
+	}
+
+	if (asfs_truncateblocksinfile(sb, bh, obj, inode->i_size) != 0) {
+		asfs_brelse(bh);
+		unlock_super(sb);
+		return;
+	}
+
+	obj->object.file.size = cpu_to_be32(inode->i_size);
+	ASFS_I(inode)->mmu_private = inode->i_size;
+	ASFS_I(inode)->modified = TRUE;
+	inode->i_blocks = (be32_to_cpu(obj->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+	asfs_bstore(sb, bh);
+	asfs_brelse(bh);
+
+	unlock_super(sb);
+}
+
+int asfs_file_open(struct inode *inode, struct file *filp)
+{
+	if (atomic_read(&filp->f_count) != 1)
+		return 0;
+	asfs_debug("ASFS: file open (node %d)\n", (int)inode->i_ino);
+	return 0;
+}
+
+int asfs_file_release(struct inode *inode, struct file *filp)
+{
+	int error = 0;
+
+	asfs_debug("ASFS: file release (node %d oc %d)\n", (int)inode->i_ino, atomic_read(&filp->f_count));
+
+	if (atomic_read(&filp->f_count) != 0)
+		return 0;
+
+	if (ASFS_I(inode)->modified == TRUE) {
+		struct buffer_head *bh;
+		struct fsObject *obj;
+		lock_super(inode->i_sb);
+
+		if ((error = asfs_readobject(inode->i_sb, inode->i_ino, &bh, &obj)) != 0) {
+			unlock_super(inode->i_sb);
+			return error;
+		}
+
+		obj->datemodified = cpu_to_be32(inode->i_mtime.tv_sec - (365*8+2)*24*60*60);
+		if (inode->i_mode & S_IFREG) {
+			error = asfs_truncateblocksinfile(inode->i_sb, bh, obj, (u32)inode->i_size);
+			obj->object.file.size = cpu_to_be32(inode->i_size);
+			ASFS_I(inode)->mmu_private = inode->i_size;
+			inode->i_blocks = (be32_to_cpu(obj->object.file.size) + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
+		}
+		asfs_bstore(inode->i_sb, bh);
+
+		unlock_super(inode->i_sb);
+
+		asfs_brelse(bh);
+	}
+	ASFS_I(inode)->modified = FALSE;
+
+	return error;
+}
+
+#endif
diff -urN oldtree/fs/asfs/inode.c newtree/fs/asfs/inode.c
--- oldtree/fs/asfs/inode.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/asfs/inode.c	2006-02-21 15:58:33.136109104 +0000
@@ -0,0 +1,426 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta8
+ *
+ * Copyright (C) 2003,2004,2005  Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/smp_lock.h>
+#include <linux/time.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include <linux/dirent.h>
+#include "asfs_fs.h"
+
+#include <asm/byteorder.h>
+
+/* Mapping from our types to the kernel */
+
+static struct address_space_operations asfs_aops = {
+	.readpage	= asfs_readpage,
+	.sync_page	= block_sync_page,
+	.bmap		= asfs_bmap,
+#ifdef CONFIG_ASFS_RW
+	.writepage	= asfs_writepage,
+	.prepare_write = asfs_prepare_write,
+	.commit_write = generic_commit_write,
+#endif
+};
+
+static struct file_operations asfs_file_operations = {
+	.llseek		= generic_file_llseek,
+	.read		= generic_file_read,
+	.mmap		= generic_file_mmap,
+#ifdef CONFIG_ASFS_RW
+	.write		= generic_file_write,
+	.open		= asfs_file_open,
+	.release	= asfs_file_release,
+	.fsync		= file_fsync,
+#endif
+};
+
+static struct file_operations asfs_dir_operations = {
+	.read		= generic_read_dir,
+	.readdir	= asfs_readdir,
+};
+
+static struct inode_operations asfs_dir_inode_operations = {
+	.lookup		= asfs_lookup,
+#ifdef CONFIG_ASFS_RW
+	.create		= asfs_create,
+	.unlink		= asfs_unlink,
+	.symlink	= asfs_symlink,
+	.mkdir		= asfs_mkdir,
+	.rmdir		= asfs_rmdir,
+	.rename		= asfs_rename,
+/*	.setattr	= asfs_notify_change,*/
+#endif
+};
+
+static struct inode_operations asfs_file_inode_operations = {
+#ifdef CONFIG_ASFS_RW
+	.truncate	= asfs_truncate,
+/*	.setattr		= asfs_notify_change,*/
+#endif
+};
+
+static struct address_space_operations asfs_symlink_aops = {
+	.readpage	= asfs_symlink_readpage,
+};
+
+static struct inode_operations asfs_symlink_inode_operations = {
+	.readlink	= page_readlink,
+	.follow_link	= page_follow_link_light,
+	.put_link	= page_put_link,
+#ifdef CONFIG_ASFS_RW
+/*	.setattr	= asfs_notify_change,*/
+#endif
+};
+
+void asfs_read_locked_inode(struct inode *inode, void *arg)
+{
+	struct super_block *sb = inode->i_sb;
+	struct fsObject *obj = arg;
+
+	inode->i_mode = ASFS_SB(sb)->mode;
+	inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = be32_to_cpu(obj->datemodified) + (365*8+2)*24*60*60;
+	/* Linux: seconds since 01-01-1970, AmigaSFS: seconds since 01-01-1978 */
+	inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_atime.tv_nsec = 0;
+	inode->i_uid = ASFS_SB(sb)->uid;
+	inode->i_gid = ASFS_SB(sb)->gid;
+
+	asfs_debug("asfs_read_inode2: Setting-up node %lu... ", inode->i_ino);
+
+	if (obj->bits & OTYPE_DIR) {
+		asfs_debug("dir (FirstdirBlock: %u, HashTable %u)\n", \
+		           be32_to_cpu(obj->object.dir.firstdirblock), be32_to_cpu(obj->object.dir.hashtable));
+
+		inode->i_size = 0;
+		inode->i_op = &asfs_dir_inode_operations;
+		inode->i_fop = &asfs_dir_operations;
+		inode->i_mode |= S_IFDIR | ((inode->i_mode & 0400) ? 0100 : 0) |
+		              ((inode->i_mode & 0040) ? 0010 : 0) | ((inode->i_mode & 0004) ? 0001 : 0);
+		ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.dir.firstdirblock);
+		ASFS_I(inode)->hashtable = be32_to_cpu(obj->object.dir.hashtable);
+		ASFS_I(inode)->modified = 0;
+	} else if (obj->bits & OTYPE_LINK && !(obj->bits & OTYPE_HARDLINK)) {
+		asfs_debug("symlink\n");
+		inode->i_size = 0;
+		inode->i_op = &asfs_symlink_inode_operations;
+		inode->i_mapping->a_ops = &asfs_symlink_aops;
+		inode->i_mode |= S_IFLNK | S_IRWXUGO;
+		ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data);
+	} else {
+		asfs_debug("file (Size: %u, FirstBlock: %u)\n", be32_to_cpu(obj->object.file.size), be32_to_cpu(obj->object.file.data));
+		inode->i_size = be32_to_cpu(obj->object.file.size);
+		inode->i_blocks = (be32_to_cpu(obj->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+		inode->i_op = &asfs_file_inode_operations;
+		inode->i_fop = &asfs_file_operations;
+		inode->i_mapping->a_ops = &asfs_aops;
+		inode->i_mode |= S_IFREG;
+		ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data);
+		ASFS_I(inode)->ext_cache.startblock = 0;
+		ASFS_I(inode)->ext_cache.key = 0;
+		ASFS_I(inode)->mmu_private = inode->i_size;
+	}
+	return;
+}
+
+struct inode *asfs_get_root_inode(struct super_block *sb)
+{
+	struct inode *result = NULL;
+	struct fsObject *obj;
+	struct buffer_head *bh;
+
+	asfs_debug("asfs_get_root_inode\n");
+
+	if ((bh = asfs_breadcheck(sb, ASFS_SB(sb)->rootobjectcontainer, ASFS_OBJECTCONTAINER_ID))) {
+		obj = &(((struct fsObjectContainer *)bh->b_data)->object[0]);
+		if (be32_to_cpu(obj->objectnode) > 0)
+			result = iget_locked(sb, be32_to_cpu(obj->objectnode));
+
+		if (result != NULL && result->i_state & I_NEW) {
+			asfs_read_locked_inode(result, obj);
+			unlock_new_inode(result);
+		}
+		asfs_brelse(bh);
+	}
+	return result;
+}
+
+#ifdef CONFIG_ASFS_RW
+
+static void asfs_sync_dir_inode(struct inode *dir, struct fsObject *obj)
+{
+	ASFS_I(dir)->firstblock = be32_to_cpu(obj->object.dir.firstdirblock);
+	ASFS_I(dir)->modified = 1;
+	dir->i_mtime = dir->i_atime = dir->i_ctime = CURRENT_TIME;
+	obj->datemodified = cpu_to_be32(dir->i_mtime.tv_sec - (365*8+2)*24*60*60);
+}
+
+enum { it_file, it_dir, it_link };
+
+static int asfs_create_object(struct inode *dir, struct dentry *dentry, int mode, int type, const char *symname)
+{
+	int error;
+	struct super_block *sb = dir->i_sb;
+	struct inode *inode;
+	struct buffer_head *bh, *dir_bh;
+	struct fsObject obj_data, *dir_obj, *obj;
+	u8 *name = (u8 *) dentry->d_name.name;
+	u8 bufname[ASFS_MAXFN_BUF];
+
+	asfs_debug("asfs_create_obj %s in dir node %d\n", name, (int)dir->i_ino);
+
+	asfs_translate(bufname, name, ASFS_SB(sb)->nls_disk, ASFS_SB(sb)->nls_io, ASFS_MAXFN_BUF);
+	if ((error = asfs_check_name(bufname, strlen(bufname))) != 0)
+		return error;
+
+	sb = dir->i_sb;
+	inode = new_inode(sb);
+	if (!inode)
+		return -ENOMEM;
+
+	memset(&obj_data, 0, sizeof(struct fsObject));
+
+	obj_data.protection = cpu_to_be32(FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE);
+	obj_data.datemodified = cpu_to_be32(inode->i_mtime.tv_sec - (365*8+2)*24*60*60);
+	switch (type) {
+	case it_dir:
+		obj_data.bits = OTYPE_DIR;
+		break;
+	case it_link:
+		obj_data.bits = OTYPE_LINK;
+		break;
+	default:
+		break;
+	}
+
+	lock_super(sb);
+
+	if ((error = asfs_readobject(sb, dir->i_ino, &dir_bh, &dir_obj)) != 0) {
+		dec_count(inode);
+		unlock_super(sb);
+		return error;
+	}
+
+	bh = dir_bh;
+	obj = dir_obj;
+
+	if ((error = asfs_createobject(sb, &bh, &obj, &obj_data, bufname, FALSE)) != 0) {
+		asfs_brelse(dir_bh);
+		dec_count(inode);
+		unlock_super(sb);
+		return error;
+	}
+
+	inode->i_ino = be32_to_cpu(obj->objectnode);
+	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+	inode->i_size = inode->i_blocks = inode->i_blksize = 0;
+	inode->i_uid = dir->i_uid;
+	inode->i_gid = dir->i_gid;
+	inode->i_mode = mode | ASFS_SB(sb)->mode;
+
+	switch (type) {
+	case it_dir:
+		inode->i_mode |= S_IFDIR;
+		inode->i_op = &asfs_dir_inode_operations;
+		inode->i_fop = &asfs_dir_operations;
+		ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.dir.firstdirblock);
+		ASFS_I(inode)->hashtable = be32_to_cpu(obj->object.dir.hashtable);
+		ASFS_I(inode)->modified = 0;
+		break;
+	case it_file:
+		inode->i_mode |= S_IFREG;
+		inode->i_op = &asfs_file_inode_operations;
+		inode->i_fop = &asfs_file_operations;
+		inode->i_mapping->a_ops = &asfs_aops;
+		ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data);
+		ASFS_I(inode)->ext_cache.startblock = 0;
+		ASFS_I(inode)->ext_cache.key = 0;
+		ASFS_I(inode)->mmu_private = inode->i_size;
+		break;
+	case it_link:
+		inode->i_mode = S_IFLNK | S_IRWXUGO;
+		inode->i_op = &page_symlink_inode_operations;
+		inode->i_mapping->a_ops = &asfs_symlink_aops;
+		ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data);
+		error = asfs_write_symlink(inode, symname);
+		break;
+	default:
+		break;
+	}
+
+	asfs_bstore(sb, bh);
+	insert_inode_hash(inode);
+	mark_inode_dirty(inode);
+	d_instantiate(dentry, inode);
+	asfs_sync_dir_inode(dir, dir_obj);
+	asfs_bstore(sb, dir_bh);
+
+	unlock_super(sb);
+	asfs_brelse(bh);
+	asfs_brelse(dir_bh);
+
+	return error;
+}
+
+int asfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd)
+{
+	return asfs_create_object(dir, dentry, mode, it_file, NULL);
+}
+
+int asfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+	return asfs_create_object(dir, dentry, mode, it_dir, NULL);
+}
+
+int asfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
+{
+	return asfs_create_object(dir, dentry, 0, it_link, symname);
+}
+
+int asfs_rmdir(struct inode *dir, struct dentry *dentry)
+{
+	asfs_debug("ASFS: %s\n", __FUNCTION__);
+
+	if (ASFS_I(dentry->d_inode)->firstblock != 0)
+		return -ENOTEMPTY;
+
+	return asfs_unlink(dir, dentry);
+}
+
+int asfs_unlink(struct inode *dir, struct dentry *dentry)
+{
+	struct inode *inode = dentry->d_inode;
+	int error;
+	struct super_block *sb = dir->i_sb;
+	struct buffer_head *bh, *dir_bh;
+	struct fsObject *dir_obj, *obj;
+
+	asfs_debug("ASFS: %s\n", __FUNCTION__);
+
+	lock_super(sb);
+
+	if ((error = asfs_readobject(sb, inode->i_ino, &bh, &obj)) != 0) {
+		unlock_super(sb);
+		return error;
+	}
+	if ((error = asfs_deleteobject(sb, bh, obj)) != 0) {
+		asfs_brelse(bh);
+		unlock_super(sb);
+		return error;
+	}
+	asfs_brelse(bh);
+
+	/* directory data could change after removing the object */
+	if ((error = asfs_readobject(sb, dir->i_ino, &dir_bh, &dir_obj)) != 0) {
+		unlock_super(sb);
+		return error;
+	}
+
+	asfs_sync_dir_inode(dir, dir_obj);
+	asfs_bstore(sb, dir_bh);
+
+	dec_count(inode);
+	unlock_super(sb);
+	asfs_brelse(dir_bh);
+
+	return 0;
+}
+
+int asfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry)
+{
+	struct super_block *sb = old_dir->i_sb;
+	struct buffer_head *src_bh, *old_bh, *new_bh;
+	int error;
+	struct fsObject *src_obj, *old_obj, *new_obj;
+	u8 bufname[ASFS_MAXFN_BUF];
+
+	asfs_debug("ASFS: rename (old=%u,\"%*s\" to new=%u,\"%*s\")\n",
+		 (u32)old_dir->i_ino, (int)old_dentry->d_name.len, old_dentry->d_name.name,
+		 (u32)new_dir->i_ino, (int)new_dentry->d_name.len, new_dentry->d_name.name);
+
+	asfs_translate(bufname, (u8 *) new_dentry->d_name.name, ASFS_SB(sb)->nls_disk, ASFS_SB(sb)->nls_io, ASFS_MAXFN_BUF);
+	if ((error = asfs_check_name(bufname, strlen(bufname))) != 0)
+		return error;
+
+
+	/* Unlink destination if it already exists */
+	if (new_dentry->d_inode)
+		if ((error = asfs_unlink(new_dir, new_dentry)) != 0)
+			return error;
+
+	lock_super(sb);
+
+	if ((error = asfs_readobject(sb, old_dentry->d_inode->i_ino, &src_bh, &src_obj)) != 0) {
+		unlock_super(sb);
+		return error;
+	}
+	if ((error = asfs_readobject(sb, new_dir->i_ino, &new_bh, &new_obj)) != 0) {
+		asfs_brelse(src_bh);
+		unlock_super(sb);
+		return error;
+	}
+
+	if ((error = asfs_renameobject(sb, src_bh, src_obj, new_bh, new_obj, bufname)) != 0) {
+		asfs_brelse(src_bh);
+		asfs_brelse(new_bh);
+		unlock_super(sb);
+		return error;
+	}
+	asfs_brelse(src_bh);
+	asfs_brelse(new_bh);
+
+	if ((error = asfs_readobject(sb, old_dir->i_ino, &old_bh, &old_obj)) != 0) {
+		unlock_super(sb);
+		return error;
+	}
+	if ((error = asfs_readobject(sb, new_dir->i_ino, &new_bh, &new_obj)) != 0) {
+		asfs_brelse(old_bh);
+		unlock_super(sb);
+		return error;
+	}
+
+	asfs_sync_dir_inode(old_dir, old_obj);
+	asfs_sync_dir_inode(new_dir, new_obj);
+
+	asfs_bstore(sb, new_bh);
+	asfs_bstore(sb, old_bh);
+
+	unlock_super(sb);
+	asfs_brelse(old_bh);
+	asfs_brelse(new_bh);
+
+	mark_inode_dirty(old_dir);
+	mark_inode_dirty(new_dir);
+
+	return 0;
+}
+
+/*
+int asfs_notify_change(struct dentry *dentry, struct iattr *attr)
+{
+	struct inode *inode = dentry->d_inode;
+	int error = 0;
+
+	asfs_debug("ASFS: notify_change(%lu,0x%x)\n",inode->i_ino,attr->ia_valid);
+
+	error = inode_change_ok(inode,attr);
+
+	return error;
+}
+*/
+#endif
diff -urN oldtree/fs/asfs/namei.c newtree/fs/asfs/namei.c
--- oldtree/fs/asfs/namei.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/asfs/namei.c	2006-02-21 15:58:33.145107736 +0000
@@ -0,0 +1,197 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta10
+ *
+ * Copyright (C) 2003,2004,2005  Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+#include "asfs_fs.h"
+
+static inline u8 asfs_upperchar(u8 c)
+{
+	if ((c >= 224 && c <= 254 && c != 247) || (c >= 'a' && c <= 'z'))
+		c -= 32;
+	return (c);
+}
+
+u8 asfs_lowerchar(u8 c)
+{
+	if ((c >= 192 && c <= 222 && c != 215) || (c >= 'A' && c <= 'Z'))
+		c += 32;
+	return (c);
+}
+
+static inline u8 asfs_nls_upperchar(u8 c, struct nls_table *t)
+{
+	if (t) {
+		u8 nc = t->charset2upper[c];
+		return nc ? nc : c;
+	} else
+		return asfs_upperchar(c);
+}
+
+/* Check if the name is valid for a asfs object. */
+
+inline int asfs_check_name(const u8 *name, int len)
+{
+	int i;
+
+	if (len > ASFS_MAXFN)
+		return -ENAMETOOLONG;
+
+	for (i = 0; i < len; i++)
+		if (name[i] < ' ' || name[i] == ':' || (name[i] > 0x7e && name[i] < 0xa0))
+			return -EINVAL;
+
+	return 0;
+}
+
+/* Note: the dentry argument is the parent dentry. */
+
+static int asfs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
+{
+	struct super_block *sb = dentry->d_inode->i_sb;
+	const u8 *name = qstr->name;
+	unsigned long hash;
+	int i;
+	struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
+
+	i = asfs_check_name(qstr->name,qstr->len);
+	if (i)
+		return i;
+
+	hash = init_name_hash();
+
+	if (ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE)
+		for (i=qstr->len; i > 0; name++, i--)
+			hash = partial_name_hash(*name, hash);
+	else
+		for (i=qstr->len; i > 0; name++, i--)
+			hash = partial_name_hash(asfs_nls_upperchar(*name, nls_io), hash);
+
+	qstr->hash = end_name_hash(hash);
+
+	return 0;
+}
+
+static int asfs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
+{
+	struct super_block *sb = dentry->d_inode->i_sb;
+	const u8 *aname = a->name;
+	const u8 *bname = b->name;
+	int len;
+	struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
+
+	/* 'a' is the qstr of an already existing dentry, so the name
+	 * must be valid. 'b' must be validated first.
+	 */
+
+	if (asfs_check_name(b->name,b->len))
+		return 1;
+
+	if (a->len != b->len)
+		return 1;
+
+	if (ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE) {
+		for (len=a->len; len > 0; len--)
+			if (*aname++ != *bname++)
+				return 1;
+	} else {
+		for (len=a->len; len > 0; len--)
+			if (asfs_nls_upperchar(*aname++, nls_io) != asfs_nls_upperchar(*bname++, nls_io))
+				return 1;
+	}
+
+	return 0;
+}
+
+struct dentry_operations asfs_dentry_operations = {
+	d_hash:		asfs_hash_dentry,
+	d_compare:	asfs_compare_dentry,
+};
+
+int asfs_namecmp(u8 *s, u8 *ct, int casesensitive, struct nls_table *t)
+{
+	if (casesensitive) {
+		while (*s == *ct && *ct != '\0' && *ct != '/') {
+			s++;
+			ct++;
+		}
+	} else {
+		while (asfs_nls_upperchar(*s, t) == asfs_nls_upperchar(*ct, t) && *ct != '\0'
+		       && *ct != '/') {
+			s++;
+			ct++;
+		}
+	}
+	return (*s == '\0' && (*ct == '\0' || *ct == '/')) ? 0 : *ct - *s;
+}
+
+u16 asfs_hash(u8 *name, int casesensitive)
+{
+	u16 hashval = 0;
+	while (name[hashval] != 0 && name[hashval] != '/')
+		hashval++;
+	if (casesensitive) {
+		u8 c = *name;
+		while (c != 0 && c != '/') {
+			hashval = hashval * 13 + c;
+			c = *++name;
+		}
+	} else {
+		u8 c = *name;
+		while (c != 0 && c != '/') {
+			hashval = hashval * 13 + asfs_upperchar(c);
+			c = *++name;
+		}
+	}
+	return hashval;
+}
+
+void asfs_translate(u8 *to, u8 *from, struct nls_table *nls_to, struct nls_table *nls_from, int limit)
+{
+	wchar_t uni;
+	int i, len;
+	int from_len, to_len = limit;
+
+	if (nls_to) {
+		from_len = strlen(from);
+		for (i=0; i < from_len && to_len > 1; ) {
+			len = nls_from->char2uni(&from[i], from_len-i, &uni);
+			if (len > 0) {
+				i += len;
+				len = nls_to->uni2char(uni, to, to_len);
+				if (len > 0) {
+					to += len;
+					to_len -= len;
+				}
+			} else
+				i++;
+			if (len < 0) {
+				*to++ = '?';
+				to_len--;
+			}
+		}
+		*to = '\0';
+	} else {
+		strncpy (to, from, limit);
+		to[limit-1] = '\0';
+	}
+}
diff -urN oldtree/fs/asfs/nodes.c newtree/fs/asfs/nodes.c
--- oldtree/fs/asfs/nodes.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/asfs/nodes.c	2006-02-21 15:58:33.146107584 +0000
@@ -0,0 +1,455 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta7
+ *
+ * This file contains some parts of the original amiga version of
+ * SmartFilesystem source code.
+ *
+ * SmartFilesystem is copyrighted (C) 2003 by: John Hendrikx,
+ * Ralph Schmidt, Emmanuel Lesueur, David Gerber and Marcin Kurek
+ *
+ * Adapted and modified by Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include "asfs_fs.h"
+
+#include <asm/byteorder.h>
+
+/* Finds a specific node by number. */
+int asfs_getnode(struct super_block *sb, u32 nodeno, struct buffer_head **ret_bh, struct fsObjectNode **ret_node)
+{
+	struct buffer_head *bh;
+	struct fsNodeContainer *nodecont;
+	u32 nodeindex = ASFS_SB(sb)->objectnoderoot;
+
+	while ((bh = asfs_breadcheck(sb, nodeindex, ASFS_NODECONTAINER_ID))) {
+		nodecont = (struct fsNodeContainer *) bh->b_data;
+
+		if (be32_to_cpu(nodecont->nodes) == 1) {
+			*ret_node = (struct fsObjectNode *) ((u8 *) nodecont->node + NODE_STRUCT_SIZE * (nodeno - be32_to_cpu(nodecont->nodenumber)));
+			*ret_bh = bh;
+			return 0;
+		} else {
+			u16 containerentry = (nodeno - be32_to_cpu(nodecont->nodenumber)) / be32_to_cpu(nodecont->nodes);
+			nodeindex = be32_to_cpu(nodecont->node[containerentry]) >> (sb->s_blocksize_bits - ASFS_BLCKFACCURACY);
+		}
+		asfs_brelse(bh);
+	}
+	if (bh == NULL)
+		return -EIO;
+	return -ENOENT;
+}
+
+#ifdef CONFIG_ASFS_RW
+
+	/* Looks for the parent of the passed-in buffer_head (fsNodeContainer)
+	   starting from the root.  It returns an error if any error occured.
+	   If error is 0 and io_bh is NULL as well, then there was no parent (ie,
+	   you asked parent of the root).  Otherwise io_bh should contain the
+	   parent of the passed-in NodeContainer. */
+
+static int parentnodecontainer(struct super_block *sb, struct buffer_head **io_bh)
+{
+	u32 noderoot = ASFS_SB(sb)->objectnoderoot;
+	u32 childblock = be32_to_cpu(((struct fsBlockHeader *) (*io_bh)->b_data)->ownblock);
+	u32 nodenumber = be32_to_cpu(((struct fsNodeContainer *) (*io_bh)->b_data)->nodenumber);
+	int errorcode = 0;
+
+	if (noderoot == childblock) {
+		*io_bh = NULL;
+		return 0;
+	}
+
+	while ((*io_bh = asfs_breadcheck(sb, noderoot, ASFS_NODECONTAINER_ID))) {
+		struct fsNodeContainer *nc = (void *) (*io_bh)->b_data;
+
+		if (be32_to_cpu(nc->nodes) == 1) {
+			/* We've descended the tree to a leaf NodeContainer, something
+			   which should never happen if the passed-in io_bh had
+			   contained a valid fsNodeContainer. */
+			printk("ASFS: Failed to locate the parent NodeContainer - node tree is corrupted!\n");
+			*io_bh = NULL;
+			return -EIO;
+		} else {
+			u16 containerentry = (nodenumber - be32_to_cpu(nc->nodenumber)) / be32_to_cpu(nc->nodes);
+			noderoot = be32_to_cpu(nc->node[containerentry]) >> (sb->s_blocksize_bits - ASFS_BLCKFACCURACY);
+		}
+
+		if (noderoot == childblock)
+			break;
+
+		asfs_brelse(*io_bh);
+	}
+
+	if (*io_bh == NULL)
+		return -EIO;
+
+	return errorcode;
+}
+
+
+static int isfull(struct super_block *sb, struct fsNodeContainer *nc)
+{
+	u32 *p = nc->node;
+	s16 n = NODECONT_BLOCK_COUNT;
+
+	while (--n >= 0) {
+		if (*p == 0 || (be32_to_cpu(*p) & 0x00000001) == 0) {
+			break;
+		}
+		p++;
+	}
+
+	return n < 0;
+}
+
+static int markparentfull(struct super_block *sb, struct buffer_head *bh)
+{
+	u32 nodenumber = be32_to_cpu(((struct fsNodeContainer *) (bh->b_data))->nodenumber);
+	int errorcode;
+
+	if ((errorcode = parentnodecontainer(sb, &bh)) == 0 && bh != 0) {
+		struct fsNodeContainer *nc = (void *) bh->b_data;
+		u16 containerentry = (nodenumber - be32_to_cpu(nc->nodenumber)) / be32_to_cpu(nc->nodes);
+
+		nc->node[containerentry] = cpu_to_be32(be32_to_cpu(nc->node[containerentry]) | 0x00000001);
+
+		asfs_bstore(sb, bh);
+
+		if (isfull(sb, nc)) {	/* This container now is full as well!  Mark the next higher up container too then! */
+			return markparentfull(sb, bh);
+		}
+		asfs_brelse(bh);
+	}
+
+	return errorcode;
+}
+
+static int addnewnodelevel(struct super_block *sb, u16 nodesize)
+{
+	struct buffer_head *bh;
+	u32 noderoot = ASFS_SB(sb)->objectnoderoot;
+	int errorcode;
+
+	/* Adds a new level to the Node tree. */
+
+	asfs_debug("addnewnodelevel: Entry\n");
+
+	if ((bh = asfs_breadcheck(sb, noderoot, ASFS_NODECONTAINER_ID))) {
+		struct buffer_head *newbh;
+		u32 newblock;
+
+		if ((errorcode = asfs_allocadminspace(sb, &newblock)) == 0 && (newbh = asfs_getzeroblk(sb, newblock))) {
+			struct fsNodeContainer *nc = (void *) bh->b_data;
+			struct fsNodeContainer *newnc = (void *) newbh->b_data;
+
+			/* The newly allocated block will become a copy of the current root. */
+
+			newnc->bheader.id = cpu_to_be32(ASFS_NODECONTAINER_ID);
+			newnc->bheader.ownblock = cpu_to_be32(newblock);
+			newnc->nodenumber = nc->nodenumber;
+			newnc->nodes = nc->nodes;
+			memcpy(newnc->node, nc->node, sb->s_blocksize - sizeof(struct fsNodeContainer));
+
+			asfs_bstore(sb, newbh);
+			asfs_brelse(newbh);
+
+			/* The current root will now be transformed into a new root. */
+
+			if (be32_to_cpu(nc->nodes) == 1)
+				nc->nodes = cpu_to_be32((sb->s_blocksize - sizeof(struct fsNodeContainer)) / nodesize);
+			else
+				nc->nodes = cpu_to_be32(be32_to_cpu(nc->nodes) * NODECONT_BLOCK_COUNT);
+
+			nc->node[0] = cpu_to_be32((newblock << (sb->s_blocksize_bits - ASFS_BLCKFACCURACY)) + 1);	/* Tree is full from that point! */
+			memset(&nc->node[1], 0, sb->s_blocksize - sizeof(struct fsNodeContainer) - 4);
+
+			asfs_bstore(sb, bh);
+		}
+		asfs_brelse(bh);
+	} else
+		errorcode = -EIO;
+
+	return errorcode;
+}
+
+static int createnodecontainer(struct super_block *sb, u32 nodenumber, u32 nodes, u32 * returned_block)
+{
+	struct buffer_head *bh;
+	int errorcode;
+	u32 newblock;
+
+	asfs_debug("createnodecontainer: nodenumber = %u, nodes = %u\n", nodenumber, nodes);
+
+	if ((errorcode = asfs_allocadminspace(sb, &newblock)) == 0 && (bh = asfs_getzeroblk(sb, newblock))) {
+		struct fsNodeContainer *nc = (void *) bh->b_data;
+
+		nc->bheader.id = cpu_to_be32(ASFS_NODECONTAINER_ID);
+		nc->bheader.ownblock = cpu_to_be32(newblock);
+
+		nc->nodenumber = cpu_to_be32(nodenumber);
+		nc->nodes = cpu_to_be32(nodes);
+
+		asfs_bstore(sb, bh);
+		asfs_brelse(bh);
+		*returned_block = newblock;
+	}
+
+	return errorcode;
+}
+
+	/* This function creates a new fsNode structure in a fsNodeContainer.  If needed
+	   it will create a new fsNodeContainers and a new fsNodeIndexContainer. */
+
+int asfs_createnode(struct super_block *sb, struct buffer_head **returned_bh, struct fsNode **returned_node, u32 * returned_nodeno)
+{
+	u16 nodecount = (sb->s_blocksize - sizeof(struct fsNodeContainer)) / NODE_STRUCT_SIZE;
+	u32 noderoot = ASFS_SB(sb)->objectnoderoot;
+	u32 nodeindex = noderoot;
+	int errorcode = 0;
+
+	while ((*returned_bh = asfs_breadcheck(sb, nodeindex, ASFS_NODECONTAINER_ID))) {
+		struct fsNodeContainer *nc = (void *) (*returned_bh)->b_data;
+
+		if (be32_to_cpu(nc->nodes) == 1) {	/* Is it a leaf-container? */
+			struct fsNode *n;
+			s16 i = nodecount;
+
+			n = (struct fsNode *) nc->node;
+
+			while (i-- > 0) {
+				if (n->data == 0)
+					break;
+
+				n = (struct fsNode *) ((u8 *) n + NODE_STRUCT_SIZE);
+			}
+
+			if (i >= 0) {
+				/* Found an empty fsNode structure! */
+				*returned_node = n;
+				*returned_nodeno = be32_to_cpu(nc->nodenumber) + ((u8 *) n - (u8 *) nc->node) / NODE_STRUCT_SIZE;
+
+				asfs_debug("createnode: Created Node %d\n", *returned_nodeno);
+
+				/* Below we continue to look through the NodeContainer block.  We skip the entry
+				   we found to be unused, and see if there are any more unused entries.  If we
+				   do not find any more unused entries then this container is now full. */
+
+				n = (struct fsNode *) ((u8 *) n + NODE_STRUCT_SIZE);
+
+				while (i-- > 0) {
+					if (n->data == 0)
+						break;
+
+					n = (struct fsNode *) ((u8 *) n + NODE_STRUCT_SIZE);
+				}
+
+				if (i < 0) {
+					/* No more empty fsNode structures in this block.  Mark parent full. */
+					errorcode = markparentfull(sb, *returned_bh);
+				}
+
+				return errorcode;
+			} else {
+				/* What happened now is that we found a leaf-container which was
+				   completely filled.  In practice this should only happen when there
+				   is only a single NodeContainer (only this container), or when there
+				   was an error in one of the full-bits in a higher level container. */
+
+				if (noderoot != nodeindex) {
+					/*** Hmmm... it looks like there was a damaged full-bit or something.
+					     In this case we'd probably better call markcontainerfull. */
+
+					printk("ASFS: Couldn't find empty Node in NodeContainer while NodeIndexContainer indicated there should be one!\n");
+
+					errorcode = -ENOSPC;
+					break;
+				} else {
+					/* Container is completely filled. */
+
+					if ((errorcode = addnewnodelevel(sb, NODE_STRUCT_SIZE)) != 0)
+						return errorcode;
+
+					nodeindex = noderoot;
+				}
+			}
+		} else {	/* This isn't a leaf container */
+			u32 *p = nc->node;
+			s16 i = NODECONT_BLOCK_COUNT;
+
+			/* We've read a normal container */
+
+			while (i-- > 0) {
+				if (*p != 0 && (be32_to_cpu(*p) & 0x00000001) == 0)
+					break;
+
+				p++;
+			}
+
+			if (i >= 0) {
+				/* Found a not completely filled Container */
+
+				nodeindex = be32_to_cpu(*p) >> (sb->s_blocksize_bits - ASFS_BLCKFACCURACY);
+			} else {
+				/* Everything in the NodeIndexContainer was completely filled.  There possibly
+				   are some unused pointers in this block however.  */
+
+				asfs_debug("createnode: NodeContainer at block has no empty Nodes.\n");
+
+				p = nc->node;
+				i = NODECONT_BLOCK_COUNT;
+
+				while (i-- > 0) {
+					if (*p == 0)
+						break;
+
+					p++;
+				}
+
+				if (i >= 0) {
+					u32 newblock;
+					u32 nodes;
+
+					/* Found an unused Container pointer */
+
+					if (be32_to_cpu(nc->nodes) == (sb->s_blocksize - sizeof(struct fsNodeContainer)) / NODE_STRUCT_SIZE) {
+						nodes = 1;
+					} else {
+						nodes = be32_to_cpu(nc->nodes) / NODECONT_BLOCK_COUNT;
+					}
+
+					if ((errorcode = createnodecontainer(sb, be32_to_cpu(nc->nodenumber) + (p - nc->node) * be32_to_cpu(nc->nodes), nodes, &newblock)) != 0) {
+						break;
+					}
+
+					*p = cpu_to_be32(newblock << (sb->s_blocksize_bits - ASFS_BLCKFACCURACY));
+
+					asfs_bstore(sb, *returned_bh);
+				} else {
+					/* Container is completely filled.  This must be the top-level NodeIndex container
+					   as otherwise the full-bit would have been wrong! */
+
+					if ((errorcode = addnewnodelevel(sb, NODE_STRUCT_SIZE)) != 0)
+						break;
+
+					nodeindex = noderoot;
+				}
+			}
+		}
+		asfs_brelse(*returned_bh);
+	}
+
+	if (*returned_bh == NULL)
+		return -EIO;
+
+	return (errorcode);
+}
+
+static int markparentempty(struct super_block *sb, struct buffer_head *bh)
+{
+	u32 nodenumber = be32_to_cpu(((struct fsNodeContainer *) bh->b_data)->nodenumber);
+	int errorcode;
+
+	if ((errorcode = parentnodecontainer(sb, &bh)) == 0 && bh != 0) {
+		struct fsNodeContainer *nc = (void *) bh->b_data;
+		int wasfull;
+		u16 containerentry = (nodenumber - be32_to_cpu(nc->nodenumber)) / be32_to_cpu(nc->nodes);
+
+		wasfull = isfull(sb, nc);
+
+		nc->node[containerentry] = cpu_to_be32(be32_to_cpu(nc->node[containerentry]) & ~0x00000001);
+
+		asfs_bstore(sb, bh);
+
+		if (wasfull) {
+			/* This container was completely full before!  Mark the next higher up container too then! */
+			return markparentempty(sb, bh);
+		}
+		asfs_brelse(bh);
+	}
+
+	return errorcode;
+}
+
+static int freecontainer(struct super_block *sb, struct buffer_head *bh)
+{
+	u32 nodenumber = be32_to_cpu(((struct fsNodeContainer *) bh->b_data)->nodenumber);
+	int errorcode;
+
+	if ((errorcode = parentnodecontainer(sb, &bh)) == 0 && bh != NULL) {	/* This line also prevents the freeing of the noderoot. */
+		struct fsNodeContainer *nc = (void *) bh->b_data;
+		u16 containerindex = (nodenumber - be32_to_cpu(nc->nodenumber)) / be32_to_cpu(nc->nodes);
+
+		if ((errorcode = asfs_freeadminspace(sb, be32_to_cpu(nc->node[containerindex]) >> (sb->s_blocksize_bits - ASFS_BLCKFACCURACY))) == 0) {
+			u32 *p = nc->node;
+			s16 n = NODECONT_BLOCK_COUNT;
+
+			nc->node[containerindex] = 0;
+			asfs_bstore(sb, bh);
+
+			while (n-- > 0)
+				if (*p++ != 0)
+					break;
+
+			if (n < 0) {	/* This container is now completely empty!  Free this NodeIndexContainer too then! */
+				return freecontainer(sb, bh);
+			}
+		}
+		asfs_brelse(bh);
+	}
+
+	return errorcode;
+}
+
+static int internaldeletenode(struct super_block *sb, struct buffer_head *bh, struct fsNode *n)
+{
+	struct fsNodeContainer *nc = (void *) bh->b_data;
+	u16 nodecount = (sb->s_blocksize - sizeof(struct fsNodeContainer)) / NODE_STRUCT_SIZE;
+	s16 i = nodecount;
+	s16 empty = 0;
+	int errorcode = 0;
+
+	n->data = 0;
+	n = (struct fsNode *) nc->node;
+
+	while (i-- > 0) {
+		if (n->data == 0)
+			empty++;
+
+		n = (struct fsNode *) ((u8 *) n + NODE_STRUCT_SIZE);
+	}
+
+	asfs_bstore(sb, bh);
+
+	if (empty == 1)		/* NodeContainer was completely full before, so we need to mark it empty now. */
+		errorcode = markparentempty(sb, bh);
+	else if (empty == nodecount)	/* NodeContainer is now completely empty!  Free it! */
+		errorcode = freecontainer(sb, bh);
+
+	return (errorcode);
+}
+
+int asfs_deletenode(struct super_block *sb, u32 objectnode)
+{
+	struct buffer_head *bh;
+	struct fsObjectNode *on;
+	int errorcode;
+
+	asfs_debug("deletenode: Deleting Node %d\n", objectnode);
+
+	if ((errorcode = asfs_getnode(sb, objectnode, &bh, &on)) == 0)
+		errorcode = internaldeletenode(sb, bh, (struct fsNode *) on);
+
+	asfs_brelse(bh);
+	return (errorcode);
+}
+
+#endif
diff -urN oldtree/fs/asfs/objects.c newtree/fs/asfs/objects.c
--- oldtree/fs/asfs/objects.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/asfs/objects.c	2006-02-21 15:58:33.147107432 +0000
@@ -0,0 +1,765 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta7
+ *
+ * This file contains some parts of the original amiga version of
+ * SmartFilesystem source code.
+ *
+ * SmartFilesystem is copyrighted (C) 2003 by: John Hendrikx,
+ * Ralph Schmidt, Emmanuel Lesueur, David Gerber, and Marcin Kurek
+ *
+ * Adapted and modified by Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include "asfs_fs.h"
+
+#include <asm/byteorder.h>
+
+struct fsObject *asfs_nextobject(struct fsObject *obj)
+{
+	int i;
+	u8 *p = obj->name;
+
+	for (i = 2; i > 0; p++)
+		if (*p == '\0')
+			i--;
+	if ((p - (u8 *) obj) & 0x01)
+		p++;
+
+	return ((struct fsObject *) p);
+}
+
+struct fsObject *asfs_find_obj_by_name(struct super_block *sb, struct fsObjectContainer *objcont, u8 * name)
+{
+	struct fsObject *obj;
+
+	obj = &(objcont->object[0]);
+	while (be32_to_cpu(obj->objectnode) > 0 && ((char *) obj - (char *) objcont) + sizeof(struct fsObject) + 2 < sb->s_blocksize) {
+		if (asfs_namecmp(obj->name, name, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE, NULL) == 0) {
+			asfs_debug("Object found! Node %u, Name %s, Type %x, inCont %u\n", be32_to_cpu(obj->objectnode), obj->name, obj->bits, be32_to_cpu(objcont->bheader.ownblock));
+			return obj;
+		}
+		obj = asfs_nextobject(obj);
+	}
+	return NULL;
+}
+
+#ifdef CONFIG_ASFS_RW
+
+struct fsObject *find_obj_by_node(struct super_block *sb, struct fsObjectContainer *objcont, u32 objnode)
+{
+	struct fsObject *obj;
+
+	obj = &(objcont->object[0]);
+	while (be32_to_cpu(obj->objectnode) > 0 && ((char *) obj - (char *) objcont) + sizeof(struct fsObject) + 2 < sb->s_blocksize) {
+		if (be32_to_cpu(obj->objectnode) == objnode) {
+			return obj;
+		}
+		obj = asfs_nextobject(obj);
+	}
+	return NULL;
+}
+
+int asfs_readobject(struct super_block *sb, u32 objectnode, struct buffer_head **bh, struct fsObject **returned_object)
+{
+	struct fsObjectNode *on;
+	int errorcode;
+	u32 contblock;
+
+	asfs_debug("Seaching object - node %d\n", objectnode);
+
+	if ((errorcode = asfs_getnode(sb, objectnode, bh, &on)) != 0)
+		return errorcode;
+	contblock = be32_to_cpu(on->node.data);
+	asfs_brelse(*bh);
+
+	if (contblock > 0 && (*bh = asfs_breadcheck(sb, contblock, ASFS_OBJECTCONTAINER_ID))) {
+		*returned_object = find_obj_by_node(sb, (void *) (*bh)->b_data, objectnode);
+		if (*returned_object == NULL) {
+			brelse(*bh);
+			*bh = NULL;
+			return -ENOENT;
+		}
+		return 0;
+	} else
+		return -EIO;
+}
+
+static int removeobjectcontainer(struct super_block *sb, struct buffer_head *bh)
+{
+	struct fsObjectContainer *oc = (void *) bh->b_data;
+	int errorcode;
+	struct buffer_head *block;
+
+	asfs_debug("removeobjectcontainer: block %u\n", be32_to_cpu(oc->bheader.ownblock));
+
+	if (oc->next != 0 && oc->next != oc->bheader.ownblock) {
+		struct fsObjectContainer *next_oc;
+
+		if ((block = asfs_breadcheck(sb, be32_to_cpu(oc->next), ASFS_OBJECTCONTAINER_ID)) == NULL)
+			return -EIO;
+
+		next_oc = (void *) block->b_data;
+		next_oc->previous = oc->previous;
+
+		asfs_bstore(sb, block);
+		asfs_brelse(block);
+	}
+
+	if (oc->previous != 0 && oc->previous != oc->bheader.ownblock) {
+		struct fsObjectContainer *previous_oc;
+
+		if ((block = asfs_breadcheck(sb, be32_to_cpu(oc->previous), ASFS_OBJECTCONTAINER_ID)) == NULL)
+			return -EIO;
+
+		previous_oc = (void *) block->b_data;
+		previous_oc->next = oc->next;
+
+		asfs_bstore(sb, block);
+		asfs_brelse(block);
+	} else {
+		struct fsObject *parent_o;
+
+		if ((errorcode = asfs_readobject(sb, be32_to_cpu(oc->parent), &block, &parent_o)) != 0)
+			return (errorcode);
+
+		parent_o->object.dir.firstdirblock = oc->next;
+
+		asfs_bstore(sb, block);
+		asfs_brelse(block);
+	}
+
+	if ((errorcode = asfs_freeadminspace(sb, be32_to_cpu(oc->bheader.ownblock))) != 0)
+		return (errorcode);
+
+	return (0);
+}
+
+static int setrecycledinfodiff(struct super_block *sb, s32 deletedfiles, s32 deletedblocks)
+{
+	struct buffer_head *bh;
+
+	if ((bh = asfs_breadcheck(sb, ASFS_SB(sb)->rootobjectcontainer, ASFS_OBJECTCONTAINER_ID))) {
+		struct fsRootInfo *ri = (struct fsRootInfo *) ((u8 *) bh->b_data + sb->s_blocksize - sizeof(struct fsRootInfo));
+
+		ri->deletedfiles = cpu_to_be32(be32_to_cpu(ri->deletedfiles) + deletedfiles);
+		ri->deletedblocks = cpu_to_be32(be32_to_cpu(ri->deletedblocks) + deletedblocks);
+
+		asfs_bstore(sb, bh);
+		asfs_brelse(bh);
+	} else
+		return -EIO;
+	return 0;
+}
+
+	/* This function removes the fsObject structure passed in from the passed
+	   buffer_head.  If the ObjectContainer becomes completely empty it will be
+	   delinked from the ObjectContainer chain and marked free for reuse.
+	   This function doesn't delink the object from the hashchain! */
+
+static int simpleremoveobject(struct super_block *sb, struct buffer_head *bh, struct fsObject *o)
+{
+	struct fsObjectContainer *oc = (void *) bh->b_data;
+	int errorcode = 0;
+
+	asfs_debug("simpleremoveobject:\n");
+
+	if (be32_to_cpu(oc->parent) == ASFS_RECYCLEDNODE) {
+		/* This object is removed from the Recycled directory. */
+		if ((errorcode = setrecycledinfodiff(sb, -1, -((be32_to_cpu(o->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits))) != 0)
+			return errorcode;
+	}
+
+	if ((asfs_nextobject(oc->object))->name[0] == '\0')
+		errorcode = removeobjectcontainer(sb, bh);
+	else {
+		struct fsObject *nexto;
+		int objlen;
+
+		nexto = asfs_nextobject(o);
+		objlen = (u8 *) nexto - (u8 *) o;
+
+		memmove(o, nexto, sb->s_blocksize - ((u8 *) nexto - (u8 *) oc));
+		memset((u8 *) oc + sb->s_blocksize - objlen, 0, objlen);
+
+		asfs_bstore(sb, bh);
+	}
+	return errorcode;
+}
+
+/* This function delinks the passed in ObjectNode from its hash-chain.  Handy when deleting
+   the object, or when renaming/moving it. */
+
+static int dehashobjectquick(struct super_block *sb, u32 objectnode, u8 *name, u32 parentobjectnode)
+{
+	struct fsObject *o;
+	int errorcode = 0;
+	struct buffer_head *block;
+
+	asfs_debug("dehashobject: Delinking object %d (=ObjectNode) from hashchain. Parentnode = %d\n", objectnode, parentobjectnode);
+
+	if ((errorcode = asfs_readobject(sb, parentobjectnode, &block, &o)) == 0 && o->object.dir.hashtable != 0) {
+		u32 hashtable = be32_to_cpu(o->object.dir.hashtable);
+		asfs_brelse(block);
+
+		if ((block = asfs_breadcheck(sb, hashtable, ASFS_HASHTABLE_ID))) {
+			struct buffer_head *node_bh;
+			struct fsObjectNode *onptr, on;
+			struct fsHashTable *ht = (void *) block->b_data;
+			u32 nexthash;
+
+			if ((errorcode = asfs_getnode(sb, objectnode, &node_bh, &onptr)) == 0) {
+				u16 hashchain;
+
+				asfs_debug("dehashobject: Read HashTable block of parent object of object to be delinked\n");
+
+				hashchain = HASHCHAIN(asfs_hash(name, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE));
+				nexthash = be32_to_cpu(ht->hashentry[hashchain]);
+
+				if (nexthash == objectnode) {
+					/* The hashtable directly points to the fsObject to be delinked.  We simply
+					   modify the Hashtable to point to the new nexthash entry. */
+
+					asfs_debug("dehashobject: The hashtable points directly to the to be delinked object\n");
+
+					ht->hashentry[hashchain] = onptr->next;
+					asfs_bstore(sb, block);
+				} else {
+					struct fsObjectNode *onsearch = 0;
+
+					on = *onptr;
+
+					asfs_debug("dehashobject: Walking through hashchain\n");
+
+					while (nexthash != 0 && nexthash != objectnode) {
+						asfs_brelse(node_bh);
+						if ((errorcode = asfs_getnode(sb, nexthash, &node_bh, &onsearch)) != 0)
+							break;
+						nexthash = be32_to_cpu(onsearch->next);
+					}
+
+					if (errorcode == 0) {
+						if (nexthash != 0) {
+							/* Previous fsObjectNode found in hash chain.  Modify the fsObjectNode to 'skip' the
+							   ObjectNode which is being delinked from the hash chain. */
+
+							onsearch->next = on.next;
+							asfs_bstore(sb, node_bh);
+						} else {
+							printk("ASFS: Hashchain of object %d is corrupt or incorrectly linked.", objectnode);
+
+							/*** This is strange.  We have been looking for the fsObjectNode which is located before the
+							     passed in fsObjectNode in the hash-chain.  However, we never found the
+							     fsObjectNode reffered to in the hash-chain!  Has to be somekind
+							     of internal error... */
+
+							errorcode = -ENOENT;
+						}
+					}
+				}
+				asfs_brelse(node_bh);
+			}
+			asfs_brelse(block);
+		}
+	}
+	return errorcode;
+}
+
+
+	/* This function removes an object from any directory.  It takes care
+	   of delinking the object from the hashchain and also frees the
+	   objectnode number. */
+
+static int removeobject(struct super_block *sb, struct buffer_head *bh, struct fsObject *o)
+{
+	struct fsObjectContainer *oc = (void *) bh->b_data;
+	int errorcode;
+
+	asfs_debug("removeobject\n");
+
+	if ((errorcode = dehashobjectquick(sb, be32_to_cpu(o->objectnode), o->name, be32_to_cpu(oc->parent))) == 0) {
+		u32 objectnode = be32_to_cpu(o->objectnode);
+
+		if ((errorcode = simpleremoveobject(sb, bh, o)) == 0)
+			errorcode = asfs_deletenode(sb, objectnode);
+	}
+
+	return (errorcode);
+}
+
+	/* This function deletes the specified object. */
+int asfs_deleteobject(struct super_block *sb, struct buffer_head *bh, struct fsObject *o)
+{
+	int errorcode = 0;
+
+	asfs_debug("deleteobject: Entry -- deleting object %d (%s)\n", be32_to_cpu(o->objectnode), o->name);
+
+	if ((o->bits & OTYPE_DIR) == 0 || o->object.dir.firstdirblock == 0) {
+		u8 bits = o->bits;
+		u32 hashblckno = be32_to_cpu(o->object.dir.hashtable);
+		u32 extentbnode = be32_to_cpu(o->object.file.data);
+
+		if ((errorcode = removeobject(sb, bh, o)) == 0) {
+			if ((bits & OTYPE_LINK) != 0) {
+				asfs_debug("deleteobject: Object is soft link!\n");
+				errorcode = asfs_freeadminspace(sb, extentbnode);
+			} else if ((bits & OTYPE_DIR) != 0) {
+				asfs_debug("deleteobject: Object is a directory!\n");
+				errorcode = asfs_freeadminspace(sb, hashblckno);
+			} else {
+				asfs_debug("deleteobject: Object is a file\n");
+				if (extentbnode != 0)
+					errorcode = asfs_deleteextents(sb, extentbnode);
+			}
+		}
+	}
+
+	return (errorcode);
+}
+
+	/* This function takes a HashBlock pointer, an ObjectNode and an ObjectName.
+	   If there is a hashblock, then this function will correctly link the object
+	   into the hashchain.  If there isn't a hashblock (=0) then this function
+	   does nothing.  */
+
+static int hashobject(struct super_block *sb, u32 hashblock, struct fsObjectNode *on, u32 nodeno, u8 *objectname)
+{
+	struct buffer_head *hash_bh;
+
+	asfs_debug("hashobject, using hashblock %d\n", hashblock);
+	if (hashblock == 0)
+		return 0;
+
+	if ((hash_bh = asfs_breadcheck(sb, hashblock, ASFS_HASHTABLE_ID))) {
+		struct fsHashTable *ht = (void *) hash_bh->b_data;
+		u32 nexthash;
+		u16 hashvalue, hashchain;
+
+		hashvalue = asfs_hash(objectname, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE);
+		hashchain = HASHCHAIN(hashvalue);
+		nexthash = be32_to_cpu(ht->hashentry[hashchain]);
+
+		ht->hashentry[hashchain] = cpu_to_be32(nodeno);
+
+		asfs_bstore(sb, hash_bh);
+		asfs_brelse(hash_bh);
+
+		on->next = cpu_to_be32(nexthash);
+		on->hash16 = cpu_to_be16(hashvalue);
+	} else
+		return -EIO;
+
+	return 0;
+}
+
+	/* This function returns a pointer to the first unused byte in
+	   an ObjectContainer. */
+
+static u8 *emptyspaceinobjectcontainer(struct super_block *sb, struct fsObjectContainer *oc)
+{
+	struct fsObject *o = oc->object;
+	u8 *endadr;
+
+	endadr = (u8 *) oc + sb->s_blocksize - sizeof(struct fsObject) - 2;
+
+	while ((u8 *) o < endadr && o->name[0] != 0)
+		o = asfs_nextobject(o);
+
+	return (u8 *) o;
+}
+
+	/* This function will look in the directory indicated by io_o
+	   for an ObjectContainer block which contains bytesneeded free
+	   bytes.  If none is found then this function simply creates a
+	   new ObjectContainer and adds that to the indicated directory. */
+
+static int findobjectspace(struct super_block *sb, struct buffer_head **io_bh, struct fsObject **io_o, u32 bytesneeded)
+{
+	struct buffer_head *bhparent = *io_bh;
+	struct fsObject *oparent = *io_o;
+	struct buffer_head *bh;
+	u32 nextblock = be32_to_cpu(oparent->object.dir.firstdirblock);
+	int errorcode = 0;
+
+	asfs_debug("findobjectspace: Looking for %u bytes in directory with ObjectNode number %d (in block %d)\n", bytesneeded, be32_to_cpu((*io_o)->objectnode),
+		   be32_to_cpu(((struct fsBlockHeader *) (*io_bh)->b_data)->ownblock));
+
+	while (nextblock != 0 && (bh = asfs_breadcheck(sb, nextblock, ASFS_OBJECTCONTAINER_ID))) {
+		struct fsObjectContainer *oc = (void *) bh->b_data;
+		u8 *emptyspace;
+
+		/* We need to find out how much free space this ObjectContainer has */
+
+		emptyspace = emptyspaceinobjectcontainer(sb, oc);
+
+		if ((u8 *) oc + sb->s_blocksize - emptyspace >= bytesneeded) {
+			/* We found enough space in one of the ObjectContainer blocks!!
+			   We return a struct fsObject *. */
+			*io_bh = bh;
+			*io_o = (struct fsObject *) emptyspace;
+			break;
+		}
+		nextblock = be32_to_cpu(oc->next);
+		asfs_brelse(bh);
+	}
+
+	if (nextblock == 0) {
+		u32 newcontblock;
+		/* If we get here, we traversed the *entire* directory (ough!) and found no empty
+		   space large enough for our entry.  We allocate new space and add it to this
+		   directory. */
+
+		if ((errorcode = asfs_allocadminspace(sb, &newcontblock)) == 0 && (bh = asfs_getzeroblk(sb, newcontblock))) {
+			struct fsObjectContainer *oc = (void *) bh->b_data;
+			struct buffer_head *bhnext;
+
+			asfs_debug("findobjectspace: No room was found, allocated new block at %u\n", newcontblock);
+
+			/* Allocated new block.  We will now link it to the START of the directory chain
+			   so the new free space can be found quickly when more entries need to be added. */
+
+			oc->bheader.id = cpu_to_be32(ASFS_OBJECTCONTAINER_ID);
+			oc->bheader.ownblock = cpu_to_be32(newcontblock);
+			oc->parent = oparent->objectnode;
+			oc->next = oparent->object.dir.firstdirblock;
+			oc->previous = 0;
+
+			oparent->object.dir.firstdirblock = cpu_to_be32(newcontblock);
+
+			asfs_bstore(sb, bhparent);
+
+			if (oc->next != 0 && (bhnext = asfs_breadcheck(sb, be32_to_cpu(oc->next), ASFS_OBJECTCONTAINER_ID))) {
+				struct fsObjectContainer *ocnext = (void *) bhnext->b_data;
+				ocnext->previous = cpu_to_be32(newcontblock);
+				asfs_bstore(sb, bhnext);
+				asfs_brelse(bhnext);
+			}
+
+			*io_bh = bh;
+			*io_o = oc->object;
+		}
+	}
+
+	asfs_debug("findobjectspace: new object will be in container block %u\n", be32_to_cpu(((struct fsBlockHeader *) (*io_bh)->b_data)->ownblock));
+
+	return (errorcode);
+}
+
+/* io_bh & io_o refer to the direct parent of the new object.  Objectname is the
+	name of the new object (name only). Does not realese io_bh !!! */
+
+int asfs_createobject(struct super_block *sb, struct buffer_head **io_bh, struct fsObject **io_o, struct fsObject *src_o, u8 *objectname, int force)
+{
+	int errorcode;
+	u32 object_size;
+	u32 hashblock = be32_to_cpu((*io_o)->object.dir.hashtable);
+
+	asfs_debug("createobject: Creating object '%s' in dir '%s'.\n", objectname, (*io_o)->name);
+
+	if (!force && ASFS_SB(sb)->freeblocks < ASFS_ALWAYSFREE)
+		return -ENOSPC;
+
+	if (!force && be32_to_cpu((*io_o)->objectnode) == ASFS_RECYCLEDNODE)
+		return -EINVAL;
+
+	object_size = sizeof(struct fsObject) + strlen(objectname) + 2;
+
+	if ((errorcode = findobjectspace(sb, io_bh, io_o, object_size)) == 0) {
+		struct fsObject *o2 = *io_o;
+		u8 *name = o2->name;
+		u8 *objname = objectname;
+		struct buffer_head *node_bh;
+		struct fsObjectNode *on;
+		u32 nodeno;
+
+		**io_o = *src_o;	/* Copying whole object data... */
+
+		while (*objname != 0)	/* Copying name */
+			*name++ = *objname++;
+
+		*name++ = 0;
+		*name = 0;	/* zero byte for comment */
+
+		if (o2->objectnode != 0)	/* ObjectNode reuse or creation */
+			errorcode = asfs_getnode(sb, o2->objectnode, &node_bh, &on);
+		else {
+			if ((errorcode = asfs_createnode(sb, &node_bh, (struct fsNode **) &on, &nodeno)) == 0) {
+				on->hash16 = cpu_to_be16(asfs_hash(o2->name, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE));
+				o2->objectnode = cpu_to_be32(nodeno);
+			}
+			asfs_debug("createnode returned with errorcode: %d\n", errorcode);
+		}
+
+		if (errorcode == 0) {	/* in io_bh there is a container with created object */
+			on->node.data = ((struct fsBlockHeader *) (*io_bh)->b_data)->ownblock;
+			if ((errorcode = hashobject(sb, hashblock, on, be32_to_cpu(o2->objectnode), objectname)) == 0) {
+				asfs_bstore(sb, node_bh);
+				asfs_brelse(node_bh);
+			} else
+				errorcode = -EIO;
+		}
+
+		if (errorcode == 0) {	/* HashBlock reuse or creation:*/
+
+			if ((o2->bits & OTYPE_DIR) != 0 && o2->object.dir.hashtable == 0) {
+				struct buffer_head *hashbh;
+				u32 hashblock;
+
+				asfs_debug("creating Hashblock\n");
+
+				if ((errorcode = asfs_allocadminspace(sb, &hashblock)) == 0 && (hashbh = asfs_getzeroblk(sb, hashblock))) {
+					struct fsHashTable *ht = (void *) hashbh->b_data;
+
+					o2->object.dir.hashtable = cpu_to_be32(hashblock);
+
+					ht->bheader.id = cpu_to_be32(ASFS_HASHTABLE_ID);
+					ht->bheader.ownblock = cpu_to_be32(hashblock);
+					ht->parent = o2->objectnode;
+
+					asfs_bstore(sb, hashbh);
+					asfs_brelse(hashbh);
+				}
+			}
+		}
+
+		if (errorcode == 0) {	/* SoftLink creation: */
+			if ((o2->bits & (OTYPE_LINK | OTYPE_HARDLINK)) == OTYPE_LINK && o2->object.file.data == 0) {
+				struct buffer_head *bh2;
+				u32 slinkblock;
+
+				if ((errorcode = asfs_allocadminspace(sb, &slinkblock)) == 0 && (bh2 = asfs_getzeroblk(sb, slinkblock))) {
+					struct fsSoftLink *sl = (void *) bh2->b_data;
+					o2->object.file.data = cpu_to_be32(slinkblock);
+					sl->bheader.id = cpu_to_be32(ASFS_SOFTLINK_ID);
+					sl->bheader.ownblock = cpu_to_be32(slinkblock);
+					sl->parent = o2->objectnode;
+					sl->next = 0;
+					sl->previous = 0;
+					asfs_bstore(sb, bh2);
+					asfs_brelse(bh2);
+				}
+			}
+		}
+	}
+	asfs_debug("createobject: done.\n");
+
+	return (errorcode);
+}
+
+	/* This function extends the file object 'o' with a number  of blocks
+		(hopefully, if any blocks has been found!). Only new Extents will
+      be created -- the size of the file will not be altered, and changing
+		it is left up to the caller.  If the file did not have any blocks
+		yet, then the o->object.file.data will be set to the first (new)
+		ExtentBNode. It returns the number of added blocks through
+		addedblocks pointer */
+
+int asfs_addblockstofile(struct super_block *sb, struct buffer_head *objbh, struct fsObject *o, u32 blocks, u32 * newspace, u32 * addedblocks)
+{
+	u32 lastextentbnode;
+	int errorcode = 0;
+	struct fsExtentBNode *ebnp;
+	struct buffer_head *block = NULL;
+
+
+	asfs_debug("extendblocksinfile: Trying to increasing number of blocks by %d.\n", blocks);
+
+	lastextentbnode = be32_to_cpu(o->object.file.data);
+
+	if (lastextentbnode != 0) {
+		while (lastextentbnode != 0 && errorcode == 0) {
+			if (block != NULL)
+				asfs_brelse(block);
+			errorcode = asfs_getextent(sb, lastextentbnode, &block, &ebnp);
+			lastextentbnode = be32_to_cpu(ebnp->next);
+		}
+		lastextentbnode = be32_to_cpu(ebnp->key);
+	}
+
+	if (errorcode == 0) {
+		u32 searchstart;
+
+		u32 found_block;
+		u32 found_blocks;
+
+		*addedblocks = 0;
+		*newspace = 0;
+
+		if (lastextentbnode != 0)
+			searchstart = be32_to_cpu(ebnp->key) + be16_to_cpu(ebnp->blocks);
+		else
+			searchstart = 0; //ASFS_SB(sb)->block_rovingblockptr;
+
+		if ((errorcode = asfs_findspace(sb, blocks, searchstart, searchstart, &found_block, &found_blocks)) != 0) {
+			asfs_brelse(block);
+			asfs_debug("extendblocksinfile: findspace returned %s\n", errorcode == -ENOSPC ? "ENOSPC" : "error");
+			return errorcode;
+		}
+
+		blocks = found_blocks;
+		errorcode = asfs_markspace(sb, found_block, found_blocks);
+		*addedblocks = found_blocks;
+		*newspace = found_block;
+
+		asfs_debug("extendblocksinfile: block = %u, lastextentbnode = %u, extentblocks = %d\n", found_block, lastextentbnode, blocks);
+
+		if ((errorcode = asfs_addblocks(sb, blocks, found_block, be32_to_cpu(o->objectnode), &lastextentbnode)) != 0) {
+			asfs_debug("extendblocksinfile: addblocks returned errorcode %d\n", errorcode);
+			return errorcode;
+		}
+
+		if (o->object.file.data == 0)
+			o->object.file.data = cpu_to_be32(lastextentbnode);
+	}
+
+	if (block)
+		asfs_brelse(block);
+	asfs_bstore(sb, objbh);
+
+	asfs_debug("addblockstofile: done. added %d blocks\n", *addedblocks);
+
+	return errorcode;
+}
+
+	/* The Object indicated by bh1 & o1, gets renamed to newname and placed
+	   in the directory indicated by bhparent & oparent. */
+
+int asfs_renameobject(struct super_block *sb, struct buffer_head *bh1, struct fsObject *o1, struct buffer_head *bhparent, struct fsObject *oparent, u8 * newname)
+{
+	struct fsObject object;
+	u32 oldparentnode = be32_to_cpu(((struct fsObjectContainer *) bh1->b_data)->parent);
+	u8 oldname[107];
+	int errorcode;
+
+	asfs_debug("renameobject: Renaming '%s' to '%s' in dir '%s'\n", o1->name, newname, oparent->name);
+
+	object = *o1;
+	strcpy(oldname, o1->name);
+
+	if ((errorcode = dehashobjectquick(sb, be32_to_cpu(o1->objectnode), o1->name, oldparentnode)) == 0) {
+		u32 parentobjectnode = be32_to_cpu(oparent->objectnode);
+
+		if ((errorcode = simpleremoveobject(sb, bh1, o1)) == 0) {
+			struct buffer_head *bh2 = bhparent;
+			struct fsObject *o2;
+
+			/* oparent might changed after simpleremoveobject */
+			oparent = o2 = find_obj_by_node(sb, (struct fsObjectContainer *) bhparent->b_data, parentobjectnode);
+
+			/* In goes the Parent bh & o, out comes the New object's bh & o :-) */
+			if ((errorcode = asfs_createobject(sb, &bh2, &o2, &object, newname, TRUE)) == 0) {
+				asfs_bstore(sb, bh2);
+				if (be32_to_cpu(oparent->objectnode) == ASFS_RECYCLEDNODE) {
+					asfs_debug("renameobject: Updating recycled dir info\n");
+					if ((errorcode = setrecycledinfodiff(sb, 1, (be32_to_cpu(o2->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits)) != 0) {
+						brelse(bh2);
+						return errorcode;
+					}
+				}
+				brelse(bh2);
+				asfs_debug("renameobject: Succesfully created & stored new object.\n");
+			} else { /* recreate object in old place, maybe this will not fail, but who knows... */
+				asfs_debug("renameobject: Creating new object failed. Trying to recreate it in source directory.\n");
+				if (asfs_readobject(sb, oldparentnode, &bh1, &o1) == 0) {
+					struct buffer_head *bh2 = bh1;
+					if (asfs_createobject(sb, &bh2, &o1, &object, oldname, TRUE) == 0) {
+						asfs_bstore(sb, bh2);
+						if (oldparentnode == ASFS_RECYCLEDNODE) {
+							asfs_debug("renameobject: Updating recycled dir info\n");
+							setrecycledinfodiff(sb, 1, (be32_to_cpu(o1->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits);
+						}
+						brelse(bh2);
+					}
+					brelse(bh1);
+				}
+			}
+		}
+	}
+	return errorcode;
+}
+
+		/* Truncates the specified file to /newsize/ bytes */
+
+int asfs_truncateblocksinfile(struct super_block *sb, struct buffer_head *bh, struct fsObject *o, u32 newsize)
+{
+	struct buffer_head *ebh;
+	struct fsExtentBNode *ebn;
+	int errorcode;
+	u32 pos = 0;
+	u32 newblocks = (newsize + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+	u32 filedata = be32_to_cpu(o->object.file.data);
+	u32 eprev, ekey;
+	u16 eblocks;
+
+	asfs_debug("trucateblocksinfile: newsize %u\n", newsize);
+
+	if (filedata == 0)
+		return 0;
+
+	for (;;) {
+		if ((errorcode = asfs_getextent(sb, filedata, &ebh, &ebn)) != 0)
+			return errorcode;
+		if (pos + be16_to_cpu(ebn->blocks) >= newblocks)
+			break;
+		pos += be16_to_cpu(ebn->blocks);
+		if ((filedata = be32_to_cpu(ebn->next)) == 0)
+			break;
+		asfs_brelse(ebh);
+	};
+
+	eblocks = newblocks - pos;
+	ekey = be32_to_cpu(ebn->key);
+	eprev = be32_to_cpu(ebn->prev);
+
+	if (be16_to_cpu(ebn->blocks) < eblocks) {
+		printk("ASFS: Extent chain is too short or damaged!\n");
+		asfs_brelse(ebh);
+		return -ENOENT;
+	}
+	if (be16_to_cpu(ebn->blocks) - eblocks > 0 && (errorcode = asfs_freespace(sb, be32_to_cpu(ebn->key) + eblocks, be16_to_cpu(ebn->blocks) - eblocks)) != 0) {
+		asfs_brelse(ebh);
+		return errorcode;
+	}
+	if (be32_to_cpu(ebn->next) > 0 && (errorcode = asfs_deleteextents(sb, be32_to_cpu(ebn->next))) != 0) {
+		asfs_brelse(ebh);
+		return errorcode;
+	}
+	ebn->blocks = cpu_to_be16(eblocks);
+	ebn->next = 0;
+	asfs_bstore(sb, ebh);
+
+	if (eblocks == 0) {
+		if (eprev & MSB_MASK) {
+			o->object.file.data = 0;
+			asfs_bstore(sb, bh);
+		} else {
+			struct buffer_head *ebhp;
+			struct fsExtentBNode *ebnp;
+
+			if ((errorcode = asfs_getextent(sb, eprev & !MSB_MASK, &ebhp, &ebnp)) != 0) {
+				asfs_brelse(ebh);
+				return errorcode;
+			}
+
+			ebnp->next = 0;
+			asfs_bstore(sb, ebhp);
+			asfs_brelse(ebhp);
+		}
+		if ((errorcode = asfs_deletebnode(sb, ebh, ekey)) != 0) {
+			asfs_brelse(ebh);
+			return errorcode;
+		}
+	}
+	asfs_brelse(ebh);
+
+	return 0;
+}
+#endif
diff -urN oldtree/fs/asfs/super.c newtree/fs/asfs/super.c
--- oldtree/fs/asfs/super.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/asfs/super.c	2006-02-21 15:58:33.148107280 +0000
@@ -0,0 +1,488 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ *
+ * version: 1.0beta10 for 2.6.xx kernel
+ *
+ * Copyright (C) 2003,2004,2005  Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ * NLS support by Pavel Fedin (C) 2005
+ *
+ *
+ * Thanks to Marcin Kurek (Morgoth/Dreamolers-CAPS) for help and parts
+ * of original amiga version of SmartFilesystem source code.
+ *
+ * SmartFilesystem is copyrighted (C) 2003 by: John Hendrikx,
+ * Ralph Schmidt, Emmanuel Lesueur, David Gerber and Marcin Kurek
+ *
+ *
+ * ASFS is based on the Amiga FFS filesystem for Linux
+ * Copyright (C) 1993  Ray Burr
+ * Copyright (C) 1996  Hans-Joachim Widmaier
+ *
+ * Earlier versions were based on the Linux implementation of
+ * the ROMFS file system
+ * Copyright (C) 1997-1999  Janos Farkas <chexum@shadow.banki.hu>
+ *
+ * ASFS used some parts of the smbfs filesystem:
+ * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
+ * Copyright (C) 1997 by Volker Lendecke
+ *
+ * and parts of the Minix filesystem additionally
+ * Copyright (C) 1991, 1992  Linus Torvalds
+ * Copyright (C) 1996  Gertjan van Wingerde
+ *
+ *
+ * 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.
+ *
+ */
+
+/* todo:
+ * - remove bugs
+ * - add missing features (maybe safe-delete, other...)
+ * - create other fs tools like mkfs.asfs and fsck.asfs, some data-recovery tools
+ */
+
+#define ASFS_VERSION "1.0beta10 (13.06.2005)"
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include <linux/parser.h>
+#include <linux/nls.h>
+#include "asfs_fs.h"
+
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+static char asfs_default_codepage[] = CONFIG_ASFS_DEFAULT_CODEPAGE;
+static char asfs_default_iocharset[] = CONFIG_NLS_DEFAULT;
+
+u32 asfs_calcchecksum(void *block, u32 blocksize)
+{
+	u32 *data = block, checksum = 1;
+	while (blocksize > 0) {
+		checksum += be32_to_cpu(*data++);
+		blocksize -= 4;
+	}
+	checksum -= be32_to_cpu(((struct fsBlockHeader *)block)->checksum);
+	return -checksum;
+}
+
+static struct super_operations asfs_ops = {
+	.alloc_inode	= asfs_alloc_inode,
+	.destroy_inode	= asfs_destroy_inode,
+	.put_super		= asfs_put_super,
+	.statfs			= asfs_statfs,
+#ifdef CONFIG_ASFS_RW
+	.remount_fs		= asfs_remount,
+#endif
+};
+
+extern struct dentry_operations asfs_dentry_operations;
+
+enum {
+	Opt_mode, Opt_setgid, Opt_setuid, Opt_prefix, Opt_volume,
+	Opt_lcvol, Opt_iocharset, Opt_codepage, Opt_ignore, Opt_err
+};
+
+static match_table_t tokens = {
+	{Opt_mode, "mode=%o"},
+	{Opt_setgid, "setgid=%u"},
+	{Opt_setuid, "setuid=%u"},
+	{Opt_prefix, "prefix=%s"},
+	{Opt_volume, "volume=%s"},
+	{Opt_lcvol, "lowercasevol"},
+	{Opt_iocharset, "iocharset=%s"},
+	{Opt_codepage, "codepage=%s"},
+	{Opt_ignore, "grpquota"},
+	{Opt_ignore, "noquota"},
+	{Opt_ignore, "quota"},
+	{Opt_ignore, "usrquota"},
+	{Opt_err, NULL},
+};
+
+static int asfs_parse_options(char *options, struct super_block *sb)
+{
+	char *p;
+	substring_t args[MAX_OPT_ARGS];
+
+	if (!options)
+		return 1;
+	while ((p = strsep(&options, ",")) != NULL) {
+		int token, option;
+		if (!*p)
+			continue;
+		token = match_token(p, tokens, args);
+
+		switch (token) {
+		case Opt_mode:
+			if (match_octal(&args[0], &option))
+				goto no_arg;
+			ASFS_SB(sb)->mode = option & 0777;
+			break;
+		case Opt_setgid:
+			if (match_int(&args[0], &option))
+				goto no_arg;
+			ASFS_SB(sb)->gid = option;
+			break;
+		case Opt_setuid:
+			if (match_int(&args[0], &option))
+				goto no_arg;
+			ASFS_SB(sb)->uid = option;
+			break;
+		case Opt_prefix:
+			if (ASFS_SB(sb)->prefix) {
+				kfree(ASFS_SB(sb)->prefix);
+				ASFS_SB(sb)->prefix = NULL;
+			}
+			ASFS_SB(sb)->prefix = match_strdup(&args[0]);
+			if (! ASFS_SB(sb)->prefix)
+				return 0;
+			break;
+		case Opt_volume:
+			if (ASFS_SB(sb)->root_volume) {
+				kfree(ASFS_SB(sb)->root_volume);
+				ASFS_SB(sb)->root_volume = NULL;
+			}
+			ASFS_SB(sb)->root_volume = match_strdup(&args[0]);
+			if (! ASFS_SB(sb)->root_volume)
+				return 0;
+			break;
+		case Opt_lcvol:
+			ASFS_SB(sb)->flags |= ASFS_VOL_LOWERCASE;
+			break;
+		case Opt_iocharset:
+			if (ASFS_SB(sb)->iocharset != asfs_default_iocharset)
+				kfree(ASFS_SB(sb)->iocharset);
+			ASFS_SB(sb)->iocharset = match_strdup(&args[0]);
+			if (!ASFS_SB(sb)->iocharset)
+				return 0;
+			break;
+		case Opt_codepage:
+			if (ASFS_SB(sb)->codepage != asfs_default_codepage)
+				kfree(ASFS_SB(sb)->codepage);
+			ASFS_SB(sb)->codepage = match_strdup(&args[0]);
+			if (!ASFS_SB(sb)->codepage)
+				return 0;
+		case Opt_ignore:
+		 	/* Silently ignore the quota options */
+			break;
+		default:
+no_arg:
+			printk("ASFS: Unrecognized mount option \"%s\" "
+					"or missing value\n", p);
+			return 0;
+		}
+	}
+	return 1;
+}
+
+static int asfs_fill_super(struct super_block *sb, void *data, int silent)
+{
+	struct asfs_sb_info *sbi;
+	struct buffer_head *bh;
+	struct fsRootBlock *rootblock;
+	struct inode *rootinode;
+
+	sbi = kmalloc(sizeof(struct asfs_sb_info), GFP_KERNEL);
+	if (!sbi)
+		return -ENOMEM;
+	sb->s_fs_info = sbi;
+
+	/* Fill in defaults */
+	ASFS_SB(sb)->uid = ASFS_DEFAULT_UID;
+	ASFS_SB(sb)->gid = ASFS_DEFAULT_GID;
+	ASFS_SB(sb)->mode = ASFS_DEFAULT_MODE;
+	ASFS_SB(sb)->prefix = NULL;
+	ASFS_SB(sb)->root_volume = NULL;
+	ASFS_SB(sb)->flags = 0;
+	ASFS_SB(sb)->iocharset = asfs_default_iocharset;
+	ASFS_SB(sb)->codepage = asfs_default_codepage;
+
+	if (!asfs_parse_options(data, sb)) {
+		printk(KERN_ERR "ASFS: Error parsing options\n");
+		return -EINVAL;
+	}
+
+	if (!sb_set_blocksize(sb, 512))
+		return -EINVAL;
+	sb->s_maxbytes = ASFS_MAXFILESIZE;
+
+	bh = sb_bread(sb, 0);
+	if (!bh) {
+		printk(KERN_ERR "ASFS: unable to read superblock\n");
+		return -EINVAL;
+	}
+
+	rootblock = (struct fsRootBlock *)bh->b_data;
+
+	if (be32_to_cpu(rootblock->bheader.id) == ASFS_ROOTID &&
+		be16_to_cpu(rootblock->version) == ASFS_STRUCTURE_VERISON) {
+
+		sb->s_blocksize = be32_to_cpu(rootblock->blocksize);
+		ASFS_SB(sb)->totalblocks = be32_to_cpu(rootblock->totalblocks);
+		ASFS_SB(sb)->rootobjectcontainer = be32_to_cpu(rootblock->rootobjectcontainer);
+		ASFS_SB(sb)->extentbnoderoot = be32_to_cpu(rootblock->extentbnoderoot);
+		ASFS_SB(sb)->objectnoderoot = be32_to_cpu(rootblock->objectnoderoot);
+		ASFS_SB(sb)->flags |= 0xff & rootblock->bits;
+		ASFS_SB(sb)->adminspacecontainer = be32_to_cpu(rootblock->adminspacecontainer);
+		ASFS_SB(sb)->bitmapbase = be32_to_cpu(rootblock->bitmapbase);
+		ASFS_SB(sb)->blocks_inbitmap = (sb->s_blocksize - sizeof(struct fsBitmap))<<3;  /* must be a multiple of 32 !! */
+		ASFS_SB(sb)->blocks_bitmap = (ASFS_SB(sb)->totalblocks + ASFS_SB(sb)->blocks_inbitmap - 1) / ASFS_SB(sb)->blocks_inbitmap;
+		ASFS_SB(sb)->block_rovingblockptr = 0;
+		asfs_brelse(bh);
+
+		if (!sb_set_blocksize(sb, sb->s_blocksize)) {
+			printk(KERN_ERR "ASFS: Found Amiga SFS RootBlock on dev %s, but blocksize %ld is not supported!\n", \
+			       sb->s_id, sb->s_blocksize);
+			return -EINVAL;
+		}
+
+		bh = sb_bread(sb, 0);
+		if (!bh) {
+			printk(KERN_ERR "ASFS: unable to read superblock\n");
+			goto out;
+		}
+		rootblock = (struct fsRootBlock *)bh->b_data;
+
+		if (asfs_check_block((void *)rootblock, sb->s_blocksize, 0, ASFS_ROOTID)) {
+#ifdef CONFIG_ASFS_RW
+			struct buffer_head *tmpbh;
+			if ((tmpbh = asfs_breadcheck(sb, ASFS_SB(sb)->rootobjectcontainer, ASFS_OBJECTCONTAINER_ID))) {
+				struct fsRootInfo *ri = (struct fsRootInfo *)((u8 *)tmpbh->b_data + sb->s_blocksize - sizeof(struct fsRootInfo));
+				ASFS_SB(sb)->freeblocks = be32_to_cpu(ri->freeblocks);
+				asfs_brelse(tmpbh);
+			} else
+				ASFS_SB(sb)->freeblocks = 0;
+
+			if ((tmpbh = asfs_breadcheck(sb, ASFS_SB(sb)->rootobjectcontainer+2, ASFS_TRANSACTIONFAILURE_ID))) {
+				printk(KERN_NOTICE "VFS: Found Amiga SFS RootBlock on dev %s, but it has unfinished transaction. Mounting read-only.\n", sb->s_id);
+				ASFS_SB(sb)->flags |= ASFS_READONLY;
+				asfs_brelse(tmpbh);
+			}
+
+			if ((tmpbh = asfs_breadcheck(sb, ASFS_SB(sb)->totalblocks-1, ASFS_ROOTID)) == NULL) {
+				printk(KERN_NOTICE "VFS: Found Amiga SFS RootBlock on dev %s, but there is no second RootBlock! Mounting read-only.\n", sb->s_id);
+				ASFS_SB(sb)->flags |= ASFS_READONLY;
+				asfs_brelse(tmpbh);
+			}
+			if (!(ASFS_SB(sb)->flags & ASFS_READONLY))
+				printk(KERN_NOTICE "VFS: Found Amiga SFS RootBlock on dev %s.\n", sb->s_id);
+#else
+			ASFS_SB(sb)->freeblocks = 0;
+			ASFS_SB(sb)->flags |= ASFS_READONLY;
+			printk(KERN_NOTICE "VFS: Found Amiga SFS RootBlock on dev %s.\n", sb->s_id);
+#endif
+		} else {
+			if (!silent)
+				printk(KERN_ERR "VFS: Found Amiga SFS RootBlock on dev %s, but it has checksum error!\n", \
+				       sb->s_id);
+			goto out;
+		}
+	} else {
+		if (!silent)
+			printk(KERN_ERR "VFS: Can't find a valid Amiga SFS filesystem on dev %s.\n", \
+			       sb->s_id);
+		goto out;
+	}
+
+	asfs_brelse(bh);
+
+	sb->s_magic = ASFS_MAGIC;
+	sb->s_flags |= MS_NODEV | MS_NOSUID;
+	if (ASFS_SB(sb)->flags & ASFS_READONLY)
+		sb->s_flags |= MS_RDONLY;
+	sb->s_op = &asfs_ops;
+	asfs_debug("Case sensitive: %s\n", (ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE) ? "yes" : "no");
+
+	if (ASFS_SB(sb)->codepage[0] != '\0' && strcmp(ASFS_SB(sb)->codepage, "none") != 0) {
+		ASFS_SB(sb)->nls_disk = load_nls(ASFS_SB(sb)->codepage);
+		if (!ASFS_SB(sb)->nls_disk) {
+			printk(KERN_ERR "ASFS: codepage %s not found\n", ASFS_SB(sb)->codepage);
+			return -EINVAL;
+		}
+		ASFS_SB(sb)->nls_io = load_nls(ASFS_SB(sb)->iocharset);
+		if (!ASFS_SB(sb)->nls_io) {
+			printk(KERN_ERR "ASFS: IO charset %s not found\n", ASFS_SB(sb)->iocharset);
+			goto out2;
+		}
+	} else {
+		ASFS_SB(sb)->nls_io = NULL;
+		ASFS_SB(sb)->nls_disk = NULL;
+	}
+
+	if ((rootinode = asfs_get_root_inode(sb))) {
+		if ((sb->s_root = d_alloc_root(rootinode))) {
+			sb->s_root->d_op = &asfs_dentry_operations;
+			return 0;
+		}
+		iput(rootinode);
+	}
+	unload_nls(ASFS_SB(sb)->nls_io);
+out2:
+	unload_nls(ASFS_SB(sb)->nls_disk);
+	return -EINVAL;
+
+out:
+	asfs_brelse(bh);
+	return -EINVAL;
+
+}
+
+#ifdef CONFIG_ASFS_RW
+int asfs_remount(struct super_block *sb, int *flags, char *data)
+{
+	asfs_debug("ASFS: remount (flags=0x%x, opts=\"%s\")\n",*flags,data);
+
+	if (!asfs_parse_options(data,sb))
+		return -EINVAL;
+
+	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+		return 0;
+
+	if (*flags & MS_RDONLY) {
+		sb->s_flags |= MS_RDONLY;
+	} else if (!(ASFS_SB(sb)->flags & ASFS_READONLY)) {
+		sb->s_flags &= ~MS_RDONLY;
+	} else {
+		printk("VFS: Can't remount Amiga SFS on dev %s read/write because of errors.", sb->s_id);
+		return -EINVAL;
+	}
+	return 0;
+}
+#endif
+
+void asfs_put_super(struct super_block *sb)
+{
+	struct asfs_sb_info *sbi = ASFS_SB(sb);
+
+	if (ASFS_SB(sb)->prefix)
+		kfree(ASFS_SB(sb)->prefix);
+	if (ASFS_SB(sb)->root_volume)
+		kfree(ASFS_SB(sb)->root_volume);
+	if (ASFS_SB(sb)->nls_disk)
+		unload_nls(ASFS_SB(sb)->nls_disk);
+	if (ASFS_SB(sb)->nls_io)
+		unload_nls(ASFS_SB(sb)->nls_io);
+	if (ASFS_SB(sb)->iocharset != asfs_default_iocharset)
+		kfree(ASFS_SB(sb)->iocharset);
+	if (ASFS_SB(sb)->codepage != asfs_default_codepage)
+		kfree(ASFS_SB(sb)->codepage);
+
+	kfree(sbi);
+	sb->s_fs_info = NULL;
+	return;
+}
+
+/* That's simple too. */
+int asfs_statfs(struct super_block *sb, struct kstatfs *buf)
+{
+	buf->f_type = ASFS_MAGIC;
+	buf->f_bsize = sb->s_blocksize;
+	buf->f_bfree = buf->f_bavail = ASFS_SB(sb)->freeblocks;
+	buf->f_blocks = ASFS_SB(sb)->totalblocks;
+	buf->f_namelen = ASFS_MAXFN;
+	return 0;
+}
+
+/* --- new in 2.6.x --- */
+static kmem_cache_t * asfs_inode_cachep;
+
+struct inode *asfs_alloc_inode(struct super_block *sb)
+{
+	struct asfs_inode_info *ei;
+	ei = (struct asfs_inode_info *)kmem_cache_alloc(asfs_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+void asfs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(asfs_inode_cachep, ASFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct asfs_inode_info *ei = (struct asfs_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		inode_init_once(&ei->vfs_inode);
+	}
+}
+
+static int init_inodecache(void)
+{
+	asfs_inode_cachep = kmem_cache_create("asfs_inode_cache",
+					     sizeof(struct asfs_inode_info),
+					     0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+					     init_once, NULL);
+	if (asfs_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(asfs_inode_cachep))
+		printk(KERN_INFO "asfs_inode_cache: not all structures were freed\n");
+}
+
+static struct super_block *asfs_get_sb(struct file_system_type *fs_type,
+	int flags, const char *dev_name, void *data)
+{
+	return get_sb_bdev(fs_type, flags, dev_name, data, asfs_fill_super);
+}
+
+static struct file_system_type asfs_fs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "asfs",
+	.get_sb		= asfs_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
+};
+
+static int __init init_asfs_fs(void)
+{
+	int err = init_inodecache();
+	if (err)
+		goto out1;
+	err = register_filesystem(&asfs_fs_type);
+	if (err)
+		goto out;
+	return 0;
+out:
+	destroy_inodecache();
+out1:
+	return err;
+}
+
+static void __exit exit_asfs_fs(void)
+{
+	unregister_filesystem(&asfs_fs_type);
+	destroy_inodecache();
+}
+
+/* Yes, works even as a module... :) */
+
+#ifdef CONFIG_ASFS_RW
+MODULE_DESCRIPTION("Amiga Smart File System (read/write) support for Linux kernel 2.6.x v" ASFS_VERSION);
+#else
+MODULE_DESCRIPTION("Amiga Smart File System (read-only) support for Linux kernel 2.6.x v" ASFS_VERSION);
+#endif
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marek Szyprowski <marek@amiga.pl>");
+
+module_init(init_asfs_fs)
+module_exit(exit_asfs_fs)
diff -urN oldtree/fs/asfs/symlink.c newtree/fs/asfs/symlink.c
--- oldtree/fs/asfs/symlink.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/asfs/symlink.c	2006-02-21 15:58:33.148107280 +0000
@@ -0,0 +1,235 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta9
+ *
+ * Copyright (C) 2003,2004,2005  Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include <linux/pagemap.h>
+#include <linux/nls.h>
+#include "asfs_fs.h"
+
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+int asfs_symlink_readpage(struct file *file, struct page *page)
+{
+	struct buffer_head *bh;
+	struct fsSoftLink *slinkcont;
+	struct inode *inode = page->mapping->host;
+	struct super_block *sb = inode->i_sb;
+	struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
+	struct nls_table *nls_disk = ASFS_SB(sb)->nls_disk;
+	char *link = kmap(page);
+	int i = 0, j = 0;
+	char c, lc = 0, *prefix, *lf, *p;
+	wchar_t uni;
+	int clen;
+
+	if (!(bh = asfs_breadcheck(sb, ASFS_I(inode)->firstblock, ASFS_SOFTLINK_ID))) {
+		SetPageError(page);
+		kunmap(page);
+		unlock_page(page);
+		return -EIO;
+	}
+	slinkcont = (struct fsSoftLink *) bh->b_data;
+
+	lf = slinkcont->string;
+	prefix = ASFS_SB(sb)->prefix ? ASFS_SB(sb)->prefix : "/";
+
+	if ((p = strchr(lf,':'))) {	/* Handle assign or volume name */
+		if (ASFS_SB(sb)->root_volume &&
+		    strncmp(lf, ASFS_SB(sb)->root_volume, strlen(ASFS_SB(sb)->root_volume)) == 0) {
+			/* global root volume name found */
+			link[i++] = '/';
+			lf = p+1;
+		} else {
+			/* adding volume prefix */
+			while (i < 1023 && (c = prefix[i]))
+				link[i++] = c;
+			while (i < 1023 && lf[j] != ':')
+			{
+				c = lf[j++];
+				if (ASFS_SB(sb)->flags & ASFS_VOL_LOWERCASE)
+					c = asfs_lowerchar(c);
+				if (nls_io)
+				{
+					clen = nls_disk->char2uni(&c, 1, &uni);
+					if (clen>0) {
+						clen = nls_io->uni2char(uni, &link[i], NLS_MAX_CHARSET_SIZE);
+						if (clen>0)
+							i += clen;
+					}
+					if (clen<0)
+						link[i++] = '?';
+				} else
+					link[i++] = c;
+			}
+			if (i < 1023)
+				link[i++] = '/';
+			j++;
+		}
+		lc = '/';
+	}
+
+	while (i < 1023 && (c = lf[j])) {
+		if (c == '/' && lc == '/' && i < 1020) {	/* parent dir */
+			link[i++] = '.';
+			link[i++] = '.';
+		}
+		lc = c;
+		if (nls_io)
+		{
+			clen = nls_disk->char2uni(&c, 1, &uni);
+			if (clen>0) {
+				clen = nls_io->uni2char(uni, &link[i], NLS_MAX_CHARSET_SIZE);
+				if (clen>0)
+					i += clen;
+			}
+			if (clen<0)
+				link[i++] = '?';
+		} else
+			link[i++] = c;
+		j++;
+	}
+	link[i] = '\0';
+	SetPageUptodate(page);
+	kunmap(page);
+	unlock_page(page);
+	asfs_brelse(bh);
+	return 0;
+}
+
+#ifdef CONFIG_ASFS_RW
+
+int asfs_write_symlink(struct inode *symfile, const char *symname)
+{
+	struct super_block *sb = symfile->i_sb;
+	struct buffer_head *bh;
+	struct fsSoftLink *slinkcont;
+	struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
+	struct nls_table *nls_disk = ASFS_SB(sb)->nls_disk;
+	char *p, c, lc;
+	int i, maxlen, pflen;
+	wchar_t uni;
+	int clen, blen;
+
+	asfs_debug("asfs_write_symlink %s to node %d\n", symname, (int)symfile->i_ino);
+
+	if (!(bh = asfs_breadcheck(sb, ASFS_I(symfile)->firstblock, ASFS_SOFTLINK_ID))) {
+		unlock_super(sb);
+		return -EIO;
+	}
+	slinkcont = (struct fsSoftLink *) bh->b_data;
+
+	/* translating symlink target path */
+
+	maxlen = sb->s_blocksize - sizeof(struct fsSoftLink) - 2;
+	i  = 0;
+	p  = slinkcont->string;
+	lc = '/';
+
+	if (*symname == '/') {
+		while (*symname == '/')
+			symname++;
+		if (ASFS_SB(sb)->prefix &&
+		    strncmp(symname-1, ASFS_SB(sb)->prefix, (pflen = strlen(ASFS_SB(sb)->prefix))) == 0) {
+			/* found volume prefix, ommiting it */
+			symname += pflen;
+			blen = strlen(symname);
+			while (*symname != '/' && *symname != '\0') {
+				clen = nls_io->char2uni(symname, blen, &uni);
+				if (clen>0) {
+					symname += clen;
+					blen -= clen;
+					clen = nls_disk->uni2char(uni, p, NLS_MAX_CHARSET_SIZE);
+					if (clen>0)
+						p += clen;
+				}
+				else
+				{
+					symname++;
+					blen--;
+				}
+				if (clen<0)
+					*p++ = '?';
+				i++;
+			}
+			symname++;
+			*p++ = ':';
+		} else if (ASFS_SB(sb)->root_volume) {	/* adding root volume name */
+			while (ASFS_SB(sb)->root_volume[i])
+				*p++ = ASFS_SB(sb)->root_volume[i++];
+			*p++ = ':';
+		} else {	/* do nothing */
+			*p++ = '/';
+		}
+		i++;
+	}
+
+	blen = strlen(symname);
+	while (i < maxlen && (c = *symname)) {
+		if (c == '.' && lc == '/' && symname[1] == '.' && symname[2] == '/') {
+			*p++ = '/';
+			i++;
+			symname += 3;
+			blen -= 3;
+			lc = '/';
+		} else if (c == '.' && lc == '/' && symname[1] == '/') {
+			symname += 2;
+			blen -= 2;
+			lc = '/';
+		} else {
+			clen = nls_io->char2uni(symname, blen, &uni);
+			if (clen>0) {
+				symname += clen;
+				blen -= clen;
+				clen = nls_disk->uni2char(uni, p, NLS_MAX_CHARSET_SIZE);
+				if (clen>0)
+					lc = *p;
+					p += clen;
+			}
+			else
+			{
+				symname++;
+				blen--;
+			}
+			if (clen<0)
+			{
+				*p++ = '?';
+				lc = '?';
+			}
+			i++;
+		}
+		if (lc == '/')
+			while (*symname == '/')
+			{
+				symname++;
+				blen--;
+			}
+	}
+	*p = 0;
+
+	asfs_bstore(sb, bh);
+	asfs_brelse(bh);
+
+	unlock_super(sb);
+
+	return 0;
+}
+
+#endif
diff -urN oldtree/fs/autofs4/autofs_i.h newtree/fs/autofs4/autofs_i.h
--- oldtree/fs/autofs4/autofs_i.h	2006-02-19 11:41:04.921594904 +0000
+++ newtree/fs/autofs4/autofs_i.h	2006-02-21 15:58:27.388982800 +0000
@@ -13,6 +13,7 @@
 /* Internal header file for autofs */
 
 #include <linux/auto_fs4.h>
+#include <linux/mutex.h>
 #include <linux/list.h>
 
 /* This is the range of ioctl() numbers we claim as ours */
@@ -102,7 +103,7 @@
 	int reghost_enabled;
 	int needs_reghost;
 	struct super_block *sb;
-	struct semaphore wq_sem;
+	struct mutex wq_mutex;
 	spinlock_t fs_lock;
 	struct autofs_wait_queue *queues; /* Wait queue pointer */
 };
diff -urN oldtree/fs/autofs4/inode.c newtree/fs/autofs4/inode.c
--- oldtree/fs/autofs4/inode.c	2006-02-19 11:41:04.922594752 +0000
+++ newtree/fs/autofs4/inode.c	2006-02-21 15:58:27.396981584 +0000
@@ -269,7 +269,7 @@
 	sbi->sb = s;
 	sbi->version = 0;
 	sbi->sub_version = 0;
-	init_MUTEX(&sbi->wq_sem);
+	mutex_init(&sbi->wq_mutex);
 	spin_lock_init(&sbi->fs_lock);
 	sbi->queues = NULL;
 	s->s_blocksize = 1024;
diff -urN oldtree/fs/autofs4/waitq.c newtree/fs/autofs4/waitq.c
--- oldtree/fs/autofs4/waitq.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/autofs4/waitq.c	2006-02-21 15:58:27.396981584 +0000
@@ -178,7 +178,7 @@
 		return -ENOENT;
 	}
 
-	if (down_interruptible(&sbi->wq_sem)) {
+	if (mutex_lock_interruptible(&sbi->wq_mutex)) {
 		kfree(name);
 		return -EINTR;
 	}
@@ -194,7 +194,7 @@
 		/* Can't wait for an expire if there's no mount */
 		if (notify == NFY_NONE && !d_mountpoint(dentry)) {
 			kfree(name);
-			up(&sbi->wq_sem);
+			mutex_unlock(&sbi->wq_mutex);
 			return -ENOENT;
 		}
 
@@ -202,7 +202,7 @@
 		wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL);
 		if ( !wq ) {
 			kfree(name);
-			up(&sbi->wq_sem);
+			mutex_unlock(&sbi->wq_mutex);
 			return -ENOMEM;
 		}
 
@@ -218,10 +218,10 @@
 		wq->status = -EINTR; /* Status return if interrupted */
 		atomic_set(&wq->wait_ctr, 2);
 		atomic_set(&wq->notified, 1);
-		up(&sbi->wq_sem);
+		mutex_unlock(&sbi->wq_mutex);
 	} else {
 		atomic_inc(&wq->wait_ctr);
-		up(&sbi->wq_sem);
+		mutex_unlock(&sbi->wq_mutex);
 		kfree(name);
 		DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d",
 			(unsigned long) wq->wait_queue_token, wq->len, wq->name, notify);
@@ -282,19 +282,19 @@
 {
 	struct autofs_wait_queue *wq, **wql;
 
-	down(&sbi->wq_sem);
+	mutex_lock(&sbi->wq_mutex);
 	for ( wql = &sbi->queues ; (wq = *wql) != 0 ; wql = &wq->next ) {
 		if ( wq->wait_queue_token == wait_queue_token )
 			break;
 	}
 
 	if ( !wq ) {
-		up(&sbi->wq_sem);
+		mutex_unlock(&sbi->wq_mutex);
 		return -EINVAL;
 	}
 
 	*wql = wq->next;	/* Unlink from chain */
-	up(&sbi->wq_sem);
+	mutex_unlock(&sbi->wq_mutex);
 	kfree(wq->name);
 	wq->name = NULL;	/* Do not wait on this queue */
 
diff -urN oldtree/fs/befs/befs.h newtree/fs/befs/befs.h
--- oldtree/fs/befs/befs.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/befs/befs.h	2006-02-21 15:58:36.528593368 +0000
@@ -94,7 +94,7 @@
 
 void befs_dump_super_block(const struct super_block *sb, befs_super_block *);
 void befs_dump_inode(const struct super_block *sb, befs_inode *);
-void befs_dump_index_entry(const struct super_block *sb, befs_btree_super *);
+void befs_dump_index_entry(const struct super_block *sb, befs_disk_btree_super *);
 void befs_dump_index_node(const struct super_block *sb, befs_btree_nodehead *);
 /****************************/
 
@@ -136,7 +136,7 @@
 static inline unsigned int
 befs_iaddrs_per_block(struct super_block *sb)
 {
-	return BEFS_SB(sb)->block_size / sizeof (befs_inode_addr);
+	return BEFS_SB(sb)->block_size / sizeof (befs_disk_inode_addr);
 }
 
 static inline int
@@ -151,4 +151,6 @@
 	return BEFS_SB(sb)->block_size * run.len;
 }
 
+#include "endian.h"
+
 #endif				/* _LINUX_BEFS_H */
diff -urN oldtree/fs/befs/befs_fs_types.h newtree/fs/befs/befs_fs_types.h
--- oldtree/fs/befs/befs_fs_types.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/befs/befs_fs_types.h	2006-02-21 15:58:36.527593520 +0000
@@ -79,17 +79,27 @@
  * On-Disk datastructures of BeFS
  */
 
+typedef u64 __bitwise fs64;
+typedef u32 __bitwise fs32;
+typedef u16 __bitwise fs16;
+
 typedef u64 befs_off_t;
-typedef u64 befs_time_t;
-typedef void befs_binode_etc;
+typedef fs64 befs_time_t;
 
 /* Block runs */
 typedef struct {
+	fs32 allocation_group;
+	fs16 start;
+	fs16 len;
+} PACKED befs_disk_block_run;
+
+typedef struct {
 	u32 allocation_group;
 	u16 start;
 	u16 len;
 } PACKED befs_block_run;
 
+typedef befs_disk_block_run befs_disk_inode_addr;
 typedef befs_block_run befs_inode_addr;
 
 /*
@@ -97,31 +107,31 @@
  */
 typedef struct {
 	char name[B_OS_NAME_LENGTH];
-	u32 magic1;
-	u32 fs_byte_order;
+	fs32 magic1;
+	fs32 fs_byte_order;
 
-	u32 block_size;
-	u32 block_shift;
+	fs32 block_size;
+	fs32 block_shift;
 
-	befs_off_t num_blocks;
-	befs_off_t used_blocks;
+	fs64 num_blocks;
+	fs64 used_blocks;
 
-	u32 inode_size;
+	fs32 inode_size;
 
-	u32 magic2;
-	u32 blocks_per_ag;
-	u32 ag_shift;
-	u32 num_ags;
+	fs32 magic2;
+	fs32 blocks_per_ag;
+	fs32 ag_shift;
+	fs32 num_ags;
 
-	u32 flags;
+	fs32 flags;
 
-	befs_block_run log_blocks;
-	befs_off_t log_start;
-	befs_off_t log_end;
+	befs_disk_block_run log_blocks;
+	fs64 log_start;
+	fs64 log_end;
 
-	u32 magic3;
-	befs_inode_addr root_dir;
-	befs_inode_addr indices;
+	fs32 magic3;
+	befs_disk_inode_addr root_dir;
+	befs_disk_inode_addr indices;
 
 } PACKED befs_super_block;
 
@@ -130,6 +140,16 @@
  * be longer than one block!
  */
 typedef struct {
+	befs_disk_block_run direct[BEFS_NUM_DIRECT_BLOCKS];
+	fs64 max_direct_range;
+	befs_disk_block_run indirect;
+	fs64 max_indirect_range;
+	befs_disk_block_run double_indirect;
+	fs64 max_double_indirect_range;
+	fs64 size;
+} PACKED befs_disk_data_stream;
+
+typedef struct {
 	befs_block_run direct[BEFS_NUM_DIRECT_BLOCKS];
 	befs_off_t max_direct_range;
 	befs_block_run indirect;
@@ -141,35 +161,35 @@
 
 /* Attribute */
 typedef struct {
-	u32 type;
-	u16 name_size;
-	u16 data_size;
+	fs32 type;
+	fs16 name_size;
+	fs16 data_size;
 	char name[1];
 } PACKED befs_small_data;
 
 /* Inode structure */
 typedef struct {
-	u32 magic1;
-	befs_inode_addr inode_num;
-	u32 uid;
-	u32 gid;
-	u32 mode;
-	u32 flags;
+	fs32 magic1;
+	befs_disk_inode_addr inode_num;
+	fs32 uid;
+	fs32 gid;
+	fs32 mode;
+	fs32 flags;
 	befs_time_t create_time;
 	befs_time_t last_modified_time;
-	befs_inode_addr parent;
-	befs_inode_addr attributes;
-	u32 type;
+	befs_disk_inode_addr parent;
+	befs_disk_inode_addr attributes;
+	fs32 type;
 
-	u32 inode_size;
-	u32 etc;		/* not use */
+	fs32 inode_size;
+	fs32 etc;		/* not use */
 
 	union {
-		befs_data_stream datastream;
+		befs_disk_data_stream datastream;
 		char symlink[BEFS_SYMLINK_LEN];
 	} data;
 
-	u32 pad[4];		/* not use */
+	fs32 pad[4];		/* not use */
 	befs_small_data small_data[1];
 } PACKED befs_inode;
 
@@ -190,6 +210,16 @@
 };
 
 typedef struct {
+	fs32 magic;
+	fs32 node_size;
+	fs32 max_depth;
+	fs32 data_type;
+	fs64 root_node_ptr;
+	fs64 free_node_ptr;
+	fs64 max_size;
+} PACKED befs_disk_btree_super;
+
+typedef struct {
 	u32 magic;
 	u32 node_size;
 	u32 max_depth;
@@ -203,11 +233,19 @@
  * Header stucture of each btree node
  */
 typedef struct {
+	fs64 left;
+	fs64 right;
+	fs64 overflow;
+	fs16 all_key_count;
+	fs16 all_key_length;
+} PACKED befs_btree_nodehead;
+
+typedef struct {
 	befs_off_t left;
 	befs_off_t right;
 	befs_off_t overflow;
 	u16 all_key_count;
 	u16 all_key_length;
-} PACKED befs_btree_nodehead;
+} PACKED befs_host_btree_nodehead;
 
 #endif				/* _LINUX_BEFS_FS_TYPES */
diff -urN oldtree/fs/befs/btree.c newtree/fs/befs/btree.c
--- oldtree/fs/befs/btree.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/befs/btree.c	2006-02-21 15:58:36.528593368 +0000
@@ -30,7 +30,6 @@
 #include "befs.h"
 #include "btree.h"
 #include "datastream.h"
-#include "endian.h"
 
 /*
  * The btree functions in this file are built on top of the
@@ -80,7 +79,7 @@
  * In memory structure of each btree node
  */
 typedef struct {
-	befs_btree_nodehead head;	/* head of node converted to cpu byteorder */
+	befs_host_btree_nodehead head;	/* head of node converted to cpu byteorder */
 	struct buffer_head *bh;
 	befs_btree_nodehead *od_node;	/* on disk node */
 } befs_btree_node;
@@ -102,9 +101,9 @@
 
 static int befs_leafnode(befs_btree_node * node);
 
-static u16 *befs_bt_keylen_index(befs_btree_node * node);
+static fs16 *befs_bt_keylen_index(befs_btree_node * node);
 
-static befs_off_t *befs_bt_valarray(befs_btree_node * node);
+static fs64 *befs_bt_valarray(befs_btree_node * node);
 
 static char *befs_bt_keydata(befs_btree_node * node);
 
@@ -136,7 +135,7 @@
 		   befs_btree_super * sup)
 {
 	struct buffer_head *bh = NULL;
-	befs_btree_super *od_sup = NULL;
+	befs_disk_btree_super *od_sup = NULL;
 
 	befs_debug(sb, "---> befs_btree_read_super()");
 
@@ -146,7 +145,7 @@
 		befs_error(sb, "Couldn't read index header.");
 		goto error;
 	}
-	od_sup = (befs_btree_super *) bh->b_data;
+	od_sup = (befs_disk_btree_super *) bh->b_data;
 	befs_dump_index_entry(sb, od_sup);
 
 	sup->magic = fs32_to_cpu(sb, od_sup->magic);
@@ -342,7 +341,7 @@
 	u16 keylen;
 	int findkey_len;
 	char *thiskey;
-	befs_off_t *valarray;
+	fs64 *valarray;
 
 	befs_debug(sb, "---> befs_find_key() %s", findkey);
 
@@ -422,7 +421,7 @@
 	befs_btree_super bt_super;
 	befs_off_t node_off = 0;
 	int cur_key;
-	befs_off_t *valarray;
+	fs64 *valarray;
 	char *keystart;
 	u16 keylen;
 	int res;
@@ -572,7 +571,7 @@
 				   this_node->head.overflow);
 			*node_off = this_node->head.overflow;
 		} else {
-			befs_off_t *valarray = befs_bt_valarray(this_node);
+			fs64 *valarray = befs_bt_valarray(this_node);
 			*node_off = fs64_to_cpu(sb, valarray[0]);
 		}
 		if (befs_bt_read_node(sb, ds, this_node, *node_off) != BEFS_OK) {
@@ -622,7 +621,7 @@
  *
  * Except that rounding up to 8 works, and rounding up to 4 doesn't.
  */
-static u16 *
+static fs16 *
 befs_bt_keylen_index(befs_btree_node * node)
 {
 	const int keylen_align = 8;
@@ -633,7 +632,7 @@
 	if (tmp)
 		off += keylen_align - tmp;
 
-	return (u16 *) ((void *) node->od_node + off);
+	return (fs16 *) ((void *) node->od_node + off);
 }
 
 /**
@@ -643,13 +642,13 @@
  * Returns a pointer to the start of the value array
  * of the node pointed to by the node header
  */
-static befs_off_t *
+static fs64 *
 befs_bt_valarray(befs_btree_node * node)
 {
 	void *keylen_index_start = (void *) befs_bt_keylen_index(node);
-	size_t keylen_index_size = node->head.all_key_count * sizeof (u16);
+	size_t keylen_index_size = node->head.all_key_count * sizeof (fs16);
 
-	return (befs_off_t *) (keylen_index_start + keylen_index_size);
+	return (fs64 *) (keylen_index_start + keylen_index_size);
 }
 
 /**
@@ -681,7 +680,7 @@
 {
 	int prev_key_end;
 	char *keystart;
-	u16 *keylen_index;
+	fs16 *keylen_index;
 
 	if (index < 0 || index > node->head.all_key_count) {
 		*keylen = 0;
diff -urN oldtree/fs/befs/datastream.c newtree/fs/befs/datastream.c
--- oldtree/fs/befs/datastream.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/befs/datastream.c	2006-02-21 15:58:36.529593216 +0000
@@ -18,7 +18,6 @@
 #include "befs.h"
 #include "datastream.h"
 #include "io.h"
-#include "endian.h"
 
 const befs_inode_addr BAD_IADDR = { 0, 0, 0 };
 
@@ -312,7 +311,7 @@
 	befs_blocknr_t indir_start_blk;
 	befs_blocknr_t search_blk;
 	struct buffer_head *indirblock;
-	befs_block_run *array;
+	befs_disk_block_run *array;
 
 	befs_block_run indirect = data->indirect;
 	befs_blocknr_t indirblockno = iaddr2blockno(sb, &indirect);
@@ -334,7 +333,7 @@
 			return BEFS_ERR;
 		}
 
-		array = (befs_block_run *) indirblock->b_data;
+		array = (befs_disk_block_run *) indirblock->b_data;
 
 		for (j = 0; j < arraylen; ++j) {
 			int len = fs16_to_cpu(sb, array[j].len);
@@ -427,7 +426,7 @@
 	struct buffer_head *dbl_indir_block;
 	struct buffer_head *indir_block;
 	befs_block_run indir_run;
-	befs_inode_addr *iaddr_array = NULL;
+	befs_disk_inode_addr *iaddr_array = NULL;
 	befs_sb_info *befs_sb = BEFS_SB(sb);
 
 	befs_blocknr_t indir_start_blk =
@@ -482,7 +481,7 @@
 
 	dbl_block_indx =
 	    dblindir_indx - (dbl_which_block * befs_iaddrs_per_block(sb));
-	iaddr_array = (befs_inode_addr *) dbl_indir_block->b_data;
+	iaddr_array = (befs_disk_inode_addr *) dbl_indir_block->b_data;
 	indir_run = fsrun_to_cpu(sb, iaddr_array[dbl_block_indx]);
 	brelse(dbl_indir_block);
 	iaddr_array = NULL;
@@ -507,7 +506,7 @@
 	}
 
 	block_indx = indir_indx - (which_block * befs_iaddrs_per_block(sb));
-	iaddr_array = (befs_inode_addr *) indir_block->b_data;
+	iaddr_array = (befs_disk_inode_addr *) indir_block->b_data;
 	*run = fsrun_to_cpu(sb, iaddr_array[block_indx]);
 	brelse(indir_block);
 	iaddr_array = NULL;
diff -urN oldtree/fs/befs/debug.c newtree/fs/befs/debug.c
--- oldtree/fs/befs/debug.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/befs/debug.c	2006-02-21 15:58:36.530593064 +0000
@@ -21,7 +21,6 @@
 #endif				/* __KERNEL__ */
 
 #include "befs.h"
-#include "endian.h"
 
 #define ERRBUFSIZE 1024
 
@@ -125,7 +124,7 @@
 	befs_debug(sb, "  type %08x", fs32_to_cpu(sb, inode->type));
 	befs_debug(sb, "  inode_size %u", fs32_to_cpu(sb, inode->inode_size));
 
-	if (S_ISLNK(inode->mode)) {
+	if (S_ISLNK(fs32_to_cpu(sb, inode->mode))) {
 		befs_debug(sb, "  Symbolic link [%s]", inode->data.symlink);
 	} else {
 		int i;
@@ -231,21 +230,20 @@
 
 /* unused */
 void
-befs_dump_run(const struct super_block *sb, befs_block_run run)
+befs_dump_run(const struct super_block *sb, befs_disk_block_run run)
 {
 #ifdef CONFIG_BEFS_DEBUG
 
-	run = fsrun_to_cpu(sb, run);
+	befs_block_run n = fsrun_to_cpu(sb, run);
 
-	befs_debug(sb, "[%u, %hu, %hu]",
-		   run.allocation_group, run.start, run.len);
+	befs_debug(sb, "[%u, %hu, %hu]", n.allocation_group, n.start, n.len);
 
 #endif				//CONFIG_BEFS_DEBUG
 }
 #endif  /*  0  */
 
 void
-befs_dump_index_entry(const struct super_block *sb, befs_btree_super * super)
+befs_dump_index_entry(const struct super_block *sb, befs_disk_btree_super * super)
 {
 #ifdef CONFIG_BEFS_DEBUG
 
diff -urN oldtree/fs/befs/endian.h newtree/fs/befs/endian.h
--- oldtree/fs/befs/endian.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/befs/endian.h	2006-02-21 15:58:36.530593064 +0000
@@ -10,85 +10,84 @@
 #define LINUX_BEFS_ENDIAN
 
 #include <linux/byteorder/generic.h>
-#include "befs.h"
 
 static inline u64
-fs64_to_cpu(const struct super_block *sb, u64 n)
+fs64_to_cpu(const struct super_block *sb, fs64 n)
 {
 	if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
-		return le64_to_cpu(n);
+		return le64_to_cpu((__force __le64)n);
 	else
-		return be64_to_cpu(n);
+		return be64_to_cpu((__force __be64)n);
 }
 
-static inline u64
+static inline fs64
 cpu_to_fs64(const struct super_block *sb, u64 n)
 {
 	if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
-		return cpu_to_le64(n);
+		return (__force fs64)cpu_to_le64(n);
 	else
-		return cpu_to_be64(n);
+		return (__force fs64)cpu_to_be64(n);
 }
 
 static inline u32
-fs32_to_cpu(const struct super_block *sb, u32 n)
+fs32_to_cpu(const struct super_block *sb, fs32 n)
 {
 	if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
-		return le32_to_cpu(n);
+		return le32_to_cpu((__force __le32)n);
 	else
-		return be32_to_cpu(n);
+		return be32_to_cpu((__force __be32)n);
 }
 
-static inline u32
+static inline fs32
 cpu_to_fs32(const struct super_block *sb, u32 n)
 {
 	if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
-		return cpu_to_le32(n);
+		return (__force fs32)cpu_to_le32(n);
 	else
-		return cpu_to_be32(n);
+		return (__force fs32)cpu_to_be32(n);
 }
 
 static inline u16
-fs16_to_cpu(const struct super_block *sb, u16 n)
+fs16_to_cpu(const struct super_block *sb, fs16 n)
 {
 	if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
-		return le16_to_cpu(n);
+		return le16_to_cpu((__force __le16)n);
 	else
-		return be16_to_cpu(n);
+		return be16_to_cpu((__force __be16)n);
 }
 
-static inline u16
+static inline fs16
 cpu_to_fs16(const struct super_block *sb, u16 n)
 {
 	if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
-		return cpu_to_le16(n);
+		return (__force fs16)cpu_to_le16(n);
 	else
-		return cpu_to_be16(n);
+		return (__force fs16)cpu_to_be16(n);
 }
 
 /* Composite types below here */
 
 static inline befs_block_run
-fsrun_to_cpu(const struct super_block *sb, befs_block_run n)
+fsrun_to_cpu(const struct super_block *sb, befs_disk_block_run n)
 {
 	befs_block_run run;
 
 	if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) {
-		run.allocation_group = le32_to_cpu(n.allocation_group);
-		run.start = le16_to_cpu(n.start);
-		run.len = le16_to_cpu(n.len);
+		run.allocation_group = le32_to_cpu((__force __le32)n.allocation_group);
+		run.start = le16_to_cpu((__force __le16)n.start);
+		run.len = le16_to_cpu((__force __le16)n.len);
 	} else {
-		run.allocation_group = be32_to_cpu(n.allocation_group);
-		run.start = be16_to_cpu(n.start);
-		run.len = be16_to_cpu(n.len);
+		run.allocation_group = be32_to_cpu((__force __be32)n.allocation_group);
+		run.start = be16_to_cpu((__force __be16)n.start);
+		run.len = be16_to_cpu((__force __be16)n.len);
 	}
 	return run;
 }
 
-static inline befs_block_run
+static inline befs_disk_block_run
 cpu_to_fsrun(const struct super_block *sb, befs_block_run n)
 {
-	befs_block_run run;
+	befs_disk_block_run run;
 
 	if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) {
 		run.allocation_group = cpu_to_le32(n.allocation_group);
@@ -103,7 +102,7 @@
 }
 
 static inline befs_data_stream
-fsds_to_cpu(const struct super_block *sb, befs_data_stream n)
+fsds_to_cpu(const struct super_block *sb, befs_disk_data_stream n)
 {
 	befs_data_stream data;
 	int i;
diff -urN oldtree/fs/befs/inode.c newtree/fs/befs/inode.c
--- oldtree/fs/befs/inode.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/befs/inode.c	2006-02-21 15:58:36.531592912 +0000
@@ -8,7 +8,6 @@
 
 #include "befs.h"
 #include "inode.h"
-#include "endian.h"
 
 /*
 	Validates the correctness of the befs inode
diff -urN oldtree/fs/befs/linuxvfs.c newtree/fs/befs/linuxvfs.c
--- oldtree/fs/befs/linuxvfs.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/befs/linuxvfs.c	2006-02-21 15:58:36.531592912 +0000
@@ -22,7 +22,6 @@
 #include "datastream.h"
 #include "super.h"
 #include "io.h"
-#include "endian.h"
 
 MODULE_DESCRIPTION("BeOS File System (BeFS) driver");
 MODULE_AUTHOR("Will Dyson");
diff -urN oldtree/fs/befs/super.c newtree/fs/befs/super.c
--- oldtree/fs/befs/super.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/befs/super.c	2006-02-21 15:58:36.532592760 +0000
@@ -11,7 +11,6 @@
 
 #include "befs.h"
 #include "super.h"
-#include "endian.h"
 
 /**
  * load_befs_sb -- Read from disk and properly byteswap all the fields
diff -urN oldtree/fs/binfmt_elf_fdpic.c newtree/fs/binfmt_elf_fdpic.c
--- oldtree/fs/binfmt_elf_fdpic.c	2006-02-19 11:41:04.925594296 +0000
+++ newtree/fs/binfmt_elf_fdpic.c	2006-02-21 15:58:36.538591848 +0000
@@ -435,9 +435,10 @@
 				   struct elf_fdpic_params *interp_params)
 {
 	unsigned long sp, csp, nitems;
-	elf_caddr_t *argv, *envp;
+	elf_caddr_t __user *argv, *envp;
 	size_t platform_len = 0, len;
-	char *k_platform, *u_platform, *p;
+	char *k_platform;
+	char __user *u_platform, *p;
 	long hwcap;
 	int loop;
 
@@ -462,12 +463,11 @@
 	if (k_platform) {
 		platform_len = strlen(k_platform) + 1;
 		sp -= platform_len;
+		u_platform = (char __user *) sp;
 		if (__copy_to_user(u_platform, k_platform, platform_len) != 0)
 			return -EFAULT;
 	}
 
-	u_platform = (char *) sp;
-
 #if defined(__i386__) && defined(CONFIG_SMP)
 	/* in some cases (e.g. Hyper-Threading), we want to avoid L1 evictions
 	 * by the processes running on the same package. One thing we can do
@@ -490,7 +490,7 @@
 	sp = (sp - len) & ~7UL;
 	exec_params->map_addr = sp;
 
-	if (copy_to_user((void *) sp, exec_params->loadmap, len) != 0)
+	if (copy_to_user((void __user *) sp, exec_params->loadmap, len) != 0)
 		return -EFAULT;
 
 	current->mm->context.exec_fdpic_loadmap = (unsigned long) sp;
@@ -501,7 +501,7 @@
 		sp = (sp - len) & ~7UL;
 		interp_params->map_addr = sp;
 
-		if (copy_to_user((void *) sp, interp_params->loadmap, len) != 0)
+		if (copy_to_user((void __user *) sp, interp_params->loadmap, len) != 0)
 			return -EFAULT;
 
 		current->mm->context.interp_fdpic_loadmap = (unsigned long) sp;
@@ -527,7 +527,7 @@
 	/* put the ELF interpreter info on the stack */
 #define NEW_AUX_ENT(nr, id, val)						\
 	do {									\
-		struct { unsigned long _id, _val; } *ent = (void *) csp;	\
+		struct { unsigned long _id, _val; } __user *ent = (void __user *) csp;	\
 		__put_user((id), &ent[nr]._id);					\
 		__put_user((val), &ent[nr]._val);				\
 	} while (0)
@@ -564,13 +564,13 @@
 
 	/* allocate room for argv[] and envv[] */
 	csp -= (bprm->envc + 1) * sizeof(elf_caddr_t);
-	envp = (elf_caddr_t *) csp;
+	envp = (elf_caddr_t __user *) csp;
 	csp -= (bprm->argc + 1) * sizeof(elf_caddr_t);
-	argv = (elf_caddr_t *) csp;
+	argv = (elf_caddr_t __user *) csp;
 
 	/* stack argc */
 	csp -= sizeof(unsigned long);
-	__put_user(bprm->argc, (unsigned long *) csp);
+	__put_user(bprm->argc, (unsigned long __user *) csp);
 
 	if (csp != sp)
 		BUG();
@@ -582,7 +582,7 @@
 	current->mm->arg_start = current->mm->start_stack - (MAX_ARG_PAGES * PAGE_SIZE - bprm->p);
 #endif
 
-	p = (char *) current->mm->arg_start;
+	p = (char __user *) current->mm->arg_start;
 	for (loop = bprm->argc; loop > 0; loop--) {
 		__put_user((elf_caddr_t) p, argv++);
 		len = strnlen_user(p, PAGE_SIZE * MAX_ARG_PAGES);
@@ -1026,7 +1026,7 @@
 		/* clear the bit between beginning of mapping and beginning of PT_LOAD */
 		if (prot & PROT_WRITE && disp > 0) {
 			kdebug("clear[%d] ad=%lx sz=%lx", loop, maddr, disp);
-			clear_user((void *) maddr, disp);
+			clear_user((void __user *) maddr, disp);
 			maddr += disp;
 		}
 
@@ -1060,7 +1060,7 @@
 		if (prot & PROT_WRITE && excess1 > 0) {
 			kdebug("clear[%d] ad=%lx sz=%lx",
 			       loop, maddr + phdr->p_filesz, excess1);
-			clear_user((void *) maddr + phdr->p_filesz, excess1);
+			clear_user((void __user *) maddr + phdr->p_filesz, excess1);
 		}
 
 #else
diff -urN oldtree/fs/bio.c newtree/fs/bio.c
--- oldtree/fs/bio.c	2006-02-19 11:41:04.927593992 +0000
+++ newtree/fs/bio.c	2006-02-21 15:58:30.920445936 +0000
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/mempool.h>
 #include <linux/workqueue.h>
+#include <linux/blktrace_api.h>
 #include <scsi/sg.h>		/* for struct sg_iovec */
 
 #define BIO_POOL_SIZE 256
@@ -1095,6 +1096,9 @@
 	if (!bp)
 		return bp;
 
+	blk_add_trace_pdu_int(bdev_get_queue(bi->bi_bdev), BLK_TA_SPLIT, bi,
+				bi->bi_sector + first_sectors);
+
 	BUG_ON(bi->bi_vcnt != 1);
 	BUG_ON(bi->bi_idx != 0);
 	atomic_set(&bp->cnt, 3);
@@ -1123,16 +1127,6 @@
 	return bp;
 }
 
-static void *bio_pair_alloc(gfp_t gfp_flags, void *data)
-{
-	return kmalloc(sizeof(struct bio_pair), gfp_flags);
-}
-
-static void bio_pair_free(void *bp, void *data)
-{
-	kfree(bp);
-}
-
 
 /*
  * create memory pools for biovec's in a bio_set.
@@ -1149,8 +1143,7 @@
 		if (i >= scale)
 			pool_entries >>= 1;
 
-		*bvp = mempool_create(pool_entries, mempool_alloc_slab,
-					mempool_free_slab, bp->slab);
+		*bvp = mempool_create_slab_pool(pool_entries, bp->slab);
 		if (!*bvp)
 			return -ENOMEM;
 	}
@@ -1188,8 +1181,7 @@
 		return NULL;
 
 	memset(bs, 0, sizeof(*bs));
-	bs->bio_pool = mempool_create(bio_pool_size, mempool_alloc_slab,
-			mempool_free_slab, bio_slab);
+	bs->bio_pool = mempool_create_slab_pool(bio_pool_size, bio_slab);
 
 	if (!bs->bio_pool)
 		goto bad;
@@ -1253,8 +1245,8 @@
 	if (!fs_bio_set)
 		panic("bio: can't allocate bios\n");
 
-	bio_split_pool = mempool_create(BIO_SPLIT_ENTRIES,
-				bio_pair_alloc, bio_pair_free, NULL);
+	bio_split_pool = mempool_create_kmalloc_pool(BIO_SPLIT_ENTRIES,
+						     sizeof(struct bio_pair));
 	if (!bio_split_pool)
 		panic("bio: can't create split pool\n");
 
diff -urN oldtree/fs/block_dev.c newtree/fs/block_dev.c
--- oldtree/fs/block_dev.c	2006-02-19 11:41:04.928593840 +0000
+++ newtree/fs/block_dev.c	2006-02-21 15:58:35.880691864 +0000
@@ -23,6 +23,8 @@
 #include <linux/mount.h>
 #include <linux/uio.h>
 #include <linux/namei.h>
+#include <linux/hardirq.h>
+
 #include <asm/uaccess.h>
 
 struct bdev_inode {
@@ -265,8 +267,8 @@
 	    SLAB_CTOR_CONSTRUCTOR)
 	{
 		memset(bdev, 0, sizeof(*bdev));
-		sema_init(&bdev->bd_sem, 1);
-		sema_init(&bdev->bd_mount_sem, 1);
+		mutex_init(&bdev->bd_mutex);
+		mutex_init(&bdev->bd_mount_mutex);
 		INIT_LIST_HEAD(&bdev->bd_inodes);
 		INIT_LIST_HEAD(&bdev->bd_list);
 		inode_init_once(&ei->vfs_inode);
@@ -393,6 +395,9 @@
 {
 	struct list_head *p;
 	long ret = 0;
+
+	WARN_ON(in_interrupt());
+
 	spin_lock(&bdev_lock);
 	list_for_each(p, &all_bdevs) {
 		struct block_device *bdev;
@@ -574,7 +579,7 @@
 	}
 	owner = disk->fops->owner;
 
-	down(&bdev->bd_sem);
+	mutex_lock(&bdev->bd_mutex);
 	if (!bdev->bd_openers) {
 		bdev->bd_disk = disk;
 		bdev->bd_contains = bdev;
@@ -605,21 +610,21 @@
 			if (ret)
 				goto out_first;
 			bdev->bd_contains = whole;
-			down(&whole->bd_sem);
+			mutex_lock(&whole->bd_mutex);
 			whole->bd_part_count++;
 			p = disk->part[part - 1];
 			bdev->bd_inode->i_data.backing_dev_info =
 			   whole->bd_inode->i_data.backing_dev_info;
 			if (!(disk->flags & GENHD_FL_UP) || !p || !p->nr_sects) {
 				whole->bd_part_count--;
-				up(&whole->bd_sem);
+				mutex_unlock(&whole->bd_mutex);
 				ret = -ENXIO;
 				goto out_first;
 			}
 			kobject_get(&p->kobj);
 			bdev->bd_part = p;
 			bd_set_size(bdev, (loff_t) p->nr_sects << 9);
-			up(&whole->bd_sem);
+			mutex_unlock(&whole->bd_mutex);
 		}
 	} else {
 		put_disk(disk);
@@ -633,13 +638,13 @@
 			if (bdev->bd_invalidated)
 				rescan_partitions(bdev->bd_disk, bdev);
 		} else {
-			down(&bdev->bd_contains->bd_sem);
+			mutex_lock(&bdev->bd_contains->bd_mutex);
 			bdev->bd_contains->bd_part_count++;
-			up(&bdev->bd_contains->bd_sem);
+			mutex_unlock(&bdev->bd_contains->bd_mutex);
 		}
 	}
 	bdev->bd_openers++;
-	up(&bdev->bd_sem);
+	mutex_unlock(&bdev->bd_mutex);
 	unlock_kernel();
 	return 0;
 
@@ -652,7 +657,7 @@
 	put_disk(disk);
 	module_put(owner);
 out:
-	up(&bdev->bd_sem);
+	mutex_unlock(&bdev->bd_mutex);
 	unlock_kernel();
 	if (ret)
 		bdput(bdev);
@@ -714,7 +719,7 @@
 	struct inode *bd_inode = bdev->bd_inode;
 	struct gendisk *disk = bdev->bd_disk;
 
-	down(&bdev->bd_sem);
+	mutex_lock(&bdev->bd_mutex);
 	lock_kernel();
 	if (!--bdev->bd_openers) {
 		sync_blockdev(bdev);
@@ -724,9 +729,9 @@
 		if (disk->fops->release)
 			ret = disk->fops->release(bd_inode, NULL);
 	} else {
-		down(&bdev->bd_contains->bd_sem);
+		mutex_lock(&bdev->bd_contains->bd_mutex);
 		bdev->bd_contains->bd_part_count--;
-		up(&bdev->bd_contains->bd_sem);
+		mutex_unlock(&bdev->bd_contains->bd_mutex);
 	}
 	if (!bdev->bd_openers) {
 		struct module *owner = disk->fops->owner;
@@ -746,7 +751,7 @@
 		bdev->bd_contains = NULL;
 	}
 	unlock_kernel();
-	up(&bdev->bd_sem);
+	mutex_unlock(&bdev->bd_mutex);
 	bdput(bdev);
 	return ret;
 }
diff -urN oldtree/fs/buffer.c newtree/fs/buffer.c
--- oldtree/fs/buffer.c	2006-02-19 11:41:04.930593536 +0000
+++ newtree/fs/buffer.c	2006-02-21 15:58:29.907599912 +0000
@@ -201,7 +201,7 @@
  * freeze_bdev  --  lock a filesystem and force it into a consistent state
  * @bdev:	blockdevice to lock
  *
- * This takes the block device bd_mount_sem to make sure no new mounts
+ * This takes the block device bd_mount_mutex to make sure no new mounts
  * happen on bdev until thaw_bdev() is called.
  * If a superblock is found on this device, we take the s_umount semaphore
  * on it to make sure nobody unmounts until the snapshot creation is done.
@@ -210,7 +210,7 @@
 {
 	struct super_block *sb;
 
-	down(&bdev->bd_mount_sem);
+	mutex_lock(&bdev->bd_mount_mutex);
 	sb = get_super(bdev);
 	if (sb && !(sb->s_flags & MS_RDONLY)) {
 		sb->s_frozen = SB_FREEZE_WRITE;
@@ -264,7 +264,7 @@
 		drop_super(sb);
 	}
 
-	up(&bdev->bd_mount_sem);
+	mutex_unlock(&bdev->bd_mount_mutex);
 }
 EXPORT_SYMBOL(thaw_bdev);
 
@@ -865,8 +865,8 @@
 		}
 		write_unlock_irq(&mapping->tree_lock);
 		__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+		return 1;
 	}
-	
 	return 0;
 }
 EXPORT_SYMBOL(__set_page_dirty_buffers);
@@ -3138,7 +3138,7 @@
 	if (__get_cpu_var(bh_accounting).ratelimit++ < 4096)
 		return;
 	__get_cpu_var(bh_accounting).ratelimit = 0;
-	for_each_cpu(i)
+	for_each_online_cpu(i)
 		tot += per_cpu(bh_accounting, i).nr;
 	buffer_heads_over_limit = (tot > max_buffer_heads);
 }
@@ -3187,6 +3187,9 @@
 		brelse(b->bhs[i]);
 		b->bhs[i] = NULL;
 	}
+	get_cpu_var(bh_accounting).nr += per_cpu(bh_accounting, cpu).nr;
+	per_cpu(bh_accounting, cpu).nr = 0;
+	put_cpu_var(bh_accounting);
 }
 
 static int buffer_cpu_notify(struct notifier_block *self,
diff -urN oldtree/fs/char_dev.c newtree/fs/char_dev.c
--- oldtree/fs/char_dev.c	2006-02-19 11:41:04.930593536 +0000
+++ newtree/fs/char_dev.c	2006-02-21 15:58:12.590232552 +0000
@@ -19,6 +19,7 @@
 #include <linux/kobject.h>
 #include <linux/kobj_map.h>
 #include <linux/cdev.h>
+#include <linux/mutex.h>
 
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
@@ -28,7 +29,7 @@
 
 #define MAX_PROBE_HASH 255	/* random */
 
-static DECLARE_MUTEX(chrdevs_lock);
+static DEFINE_MUTEX(chrdevs_lock);
 
 static struct char_device_struct {
 	struct char_device_struct *next;
@@ -88,13 +89,13 @@
 
 void *acquire_chrdev_list(void)
 {
-	down(&chrdevs_lock);
+	mutex_lock(&chrdevs_lock);
 	return get_next_chrdev(NULL);
 }
 
 void release_chrdev_list(void *dev)
 {
-	up(&chrdevs_lock);
+	mutex_unlock(&chrdevs_lock);
 	kfree(dev);
 }
 
@@ -151,7 +152,7 @@
 
 	memset(cd, 0, sizeof(struct char_device_struct));
 
-	down(&chrdevs_lock);
+	mutex_lock(&chrdevs_lock);
 
 	/* temporary */
 	if (major == 0) {
@@ -186,10 +187,10 @@
 	}
 	cd->next = *cp;
 	*cp = cd;
-	up(&chrdevs_lock);
+	mutex_unlock(&chrdevs_lock);
 	return cd;
 out:
-	up(&chrdevs_lock);
+	mutex_unlock(&chrdevs_lock);
 	kfree(cd);
 	return ERR_PTR(ret);
 }
@@ -200,7 +201,7 @@
 	struct char_device_struct *cd = NULL, **cp;
 	int i = major_to_index(major);
 
-	down(&chrdevs_lock);
+	mutex_lock(&chrdevs_lock);
 	for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
 		if ((*cp)->major == major &&
 		    (*cp)->baseminor == baseminor &&
@@ -210,7 +211,7 @@
 		cd = *cp;
 		*cp = cd->next;
 	}
-	up(&chrdevs_lock);
+	mutex_unlock(&chrdevs_lock);
 	return cd;
 }
 
diff -urN oldtree/fs/cifs/CHANGES newtree/fs/cifs/CHANGES
--- oldtree/fs/cifs/CHANGES	2006-02-19 11:41:04.931593384 +0000
+++ newtree/fs/cifs/CHANGES	2006-02-21 15:58:12.053314176 +0000
@@ -1,3 +1,9 @@
+Version 1.41
+------------
+Fix NTLMv2 security (can be enabled in /proc/fs/cifs) so customers can
+configure stronger authentication.  Fix sfu symlinks so they can
+be followed (not just recognized).
+
 Version 1.40
 ------------
 Use fsuid (fsgid) more consistently instead of uid (gid). Improve performance
diff -urN oldtree/fs/cifs/Makefile newtree/fs/cifs/Makefile
--- oldtree/fs/cifs/Makefile	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/cifs/Makefile	2006-02-21 15:58:12.053314176 +0000
@@ -3,4 +3,4 @@
 #
 obj-$(CONFIG_CIFS) += cifs.o
 
-cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o
+cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o ntlmssp.o
diff -urN oldtree/fs/cifs/cifsencrypt.c newtree/fs/cifs/cifsencrypt.c
--- oldtree/fs/cifs/cifsencrypt.c	2006-02-19 11:41:04.934592928 +0000
+++ newtree/fs/cifs/cifsencrypt.c	2006-02-21 15:58:12.054314024 +0000
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsencrypt.c
  *
- *   Copyright (C) International Business Machines  Corp., 2005
+ *   Copyright (C) International Business Machines  Corp., 2005,2006
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -36,7 +36,8 @@
 extern void mdfour(unsigned char *out, unsigned char *in, int n);
 extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
 	
-static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char * key, char * signature)
+static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, 
+				    const char * key, char * signature)
 {
 	struct	MD5Context context;
 
@@ -259,4 +260,5 @@
 /*	hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */
 
 	hmac_md5_final(v2_session_response,&context);
+	cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); /* BB removeme BB */
 }
diff -urN oldtree/fs/cifs/cifsfs.c newtree/fs/cifs/cifsfs.c
--- oldtree/fs/cifs/cifsfs.c	2006-02-19 11:41:04.935592776 +0000
+++ newtree/fs/cifs/cifsfs.c	2006-02-21 15:58:30.931444264 +0000
@@ -737,10 +737,8 @@
 		cERROR(1,("cifs_min_rcv set to maximum (64)"));
 	}
 
-	cifs_req_poolp = mempool_create(cifs_min_rcv,
-					mempool_alloc_slab,
-					mempool_free_slab,
-					cifs_req_cachep);
+	cifs_req_poolp = mempool_create_slab_pool(cifs_min_rcv,
+						  cifs_req_cachep);
 
 	if(cifs_req_poolp == NULL) {
 		kmem_cache_destroy(cifs_req_cachep);
@@ -770,10 +768,8 @@
 		cFYI(1,("cifs_min_small set to maximum (256)"));
 	}
 
-	cifs_sm_req_poolp = mempool_create(cifs_min_small,
-				mempool_alloc_slab,
-				mempool_free_slab,
-				cifs_sm_req_cachep);
+	cifs_sm_req_poolp = mempool_create_slab_pool(cifs_min_small,
+						     cifs_sm_req_cachep);
 
 	if(cifs_sm_req_poolp == NULL) {
 		mempool_destroy(cifs_req_poolp);
@@ -807,10 +803,8 @@
 	if (cifs_mid_cachep == NULL)
 		return -ENOMEM;
 
-	cifs_mid_poolp = mempool_create(3 /* a reasonable min simultan opers */,
-					mempool_alloc_slab,
-					mempool_free_slab,
-					cifs_mid_cachep);
+	/* 3 is a reasonable minimum number of simultaneous operations */
+	cifs_mid_poolp = mempool_create_slab_pool(3, cifs_mid_cachep);
 	if(cifs_mid_poolp == NULL) {
 		kmem_cache_destroy(cifs_mid_cachep);
 		return -ENOMEM;
diff -urN oldtree/fs/cifs/cifsfs.h newtree/fs/cifs/cifsfs.h
--- oldtree/fs/cifs/cifsfs.h	2006-02-19 11:41:04.936592624 +0000
+++ newtree/fs/cifs/cifsfs.h	2006-02-21 15:58:12.067312048 +0000
@@ -99,5 +99,5 @@
 extern ssize_t	cifs_listxattr(struct dentry *, char *, size_t);
 extern int cifs_ioctl (struct inode * inode, struct file * filep,
 		       unsigned int command, unsigned long arg);
-#define CIFS_VERSION   "1.40"
+#define CIFS_VERSION   "1.41"
 #endif				/* _CIFSFS_H */
diff -urN oldtree/fs/cifs/cifsglob.h newtree/fs/cifs/cifsglob.h
--- oldtree/fs/cifs/cifsglob.h	2006-02-19 11:41:04.936592624 +0000
+++ newtree/fs/cifs/cifsglob.h	2006-02-21 15:58:12.068311896 +0000
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsglob.h
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2005
+ *   Copyright (C) International Business Machines  Corp., 2002,2006
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -430,6 +430,15 @@
 #define   CIFS_LARGE_BUFFER     2
 #define   CIFS_IOVEC            4    /* array of response buffers */
 
+/* Type of session setup needed */
+#define   CIFS_PLAINTEXT	0
+#define   CIFS_LANMAN		1
+#define   CIFS_NTLM		2
+#define   CIFS_NTLMSSP_NEG	3
+#define   CIFS_NTLMSSP_AUTH	4
+#define   CIFS_SPNEGO_INIT	5
+#define   CIFS_SPNEGO_TARG	6
+
 /*
  *****************************************************************
  * All constants go here
diff -urN oldtree/fs/cifs/cifsproto.h newtree/fs/cifs/cifsproto.h
--- oldtree/fs/cifs/cifsproto.h	2006-02-19 11:41:04.938592320 +0000
+++ newtree/fs/cifs/cifsproto.h	2006-02-21 15:58:12.070311592 +0000
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsproto.h
  *
- *   Copyright (c) International Business Machines  Corp., 2002,2005
+ *   Copyright (c) International Business Machines  Corp., 2002,2006
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -64,6 +64,14 @@
 extern void header_assemble(struct smb_hdr *, char /* command */ ,
 			    const struct cifsTconInfo *, int /* length of
 			    fixed section (word count) in two byte units */);
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
+				struct cifsSesInfo *ses,
+				void ** request_buf);
+extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
+			     const int stage, int * pNTLMv2_flg,
+			     const struct nls_table *nls_cp);
+#endif
 extern __u16 GetNextMid(struct TCP_Server_Info *server);
 extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, 
 						 struct cifsTconInfo *);
diff -urN oldtree/fs/cifs/cifssmb.c newtree/fs/cifs/cifssmb.c
--- oldtree/fs/cifs/cifssmb.c	2006-02-19 11:41:04.941591864 +0000
+++ newtree/fs/cifs/cifssmb.c	2006-02-21 15:58:12.096307640 +0000
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifssmb.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2005
+ *   Copyright (C) International Business Machines  Corp., 2002,2006
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   Contains the routines for constructing the SMB PDUs themselves
@@ -186,7 +186,35 @@
                 cifs_stats_inc(&tcon->num_smbs_sent);
 
 	return rc;
-}  
+}
+
+#ifdef CONFIG_CIFS_EXPERIMENTAL  
+int
+small_smb_init_no_tc(const int smb_command, const int wct, 
+		     struct cifsSesInfo *ses, void **request_buf)
+{
+	int rc;
+	struct smb_hdr * buffer;
+
+	rc = small_smb_init(smb_command, wct, NULL, request_buf);
+	if(rc)
+		return rc;
+
+	buffer = (struct smb_hdr *)*request_buf;
+	buffer->Mid = GetNextMid(ses->server);
+	if (ses->capabilities & CAP_UNICODE)
+		buffer->Flags2 |= SMBFLG2_UNICODE;
+	if (ses->capabilities & CAP_STATUS32)
+		buffer->Flags2 |= SMBFLG2_ERR_STATUS;
+
+	/* uid, tid can stay at zero as set in header assemble */
+
+	/* BB add support for turning on the signing when 
+	this function is used after 1st of session setup requests */
+
+	return rc;
+}
+#endif  /* CONFIG_CIFS_EXPERIMENTAL */
 
 /* If the return code is zero, this function must fill in request_buf pointer */
 static int
diff -urN oldtree/fs/cifs/connect.c newtree/fs/cifs/connect.c
--- oldtree/fs/cifs/connect.c	2006-02-19 11:41:04.943591560 +0000
+++ newtree/fs/cifs/connect.c	2006-02-21 15:58:12.101306880 +0000
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/connect.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2005
+ *   Copyright (C) International Business Machines  Corp., 2002,2006
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -2525,7 +2525,7 @@
 	__u32 negotiate_flags, capabilities;
 	__u16 count;
 
-	cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
+	cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
 	if(ses == NULL)
 		return -EINVAL;
 	domain = ses->domainName;
@@ -2575,7 +2575,8 @@
 	SecurityBlob->MessageType = NtLmNegotiate;
 	negotiate_flags =
 	    NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
-	    NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
+	    NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
+	    NTLMSSP_NEGOTIATE_56 |
 	    /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
 	if(sign_CIFS_PDUs)
 		negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
@@ -2588,26 +2589,11 @@
 	SecurityBlob->WorkstationName.Length = 0;
 	SecurityBlob->WorkstationName.MaximumLength = 0;
 
-	if (domain == NULL) {
-		SecurityBlob->DomainName.Buffer = 0;
-		SecurityBlob->DomainName.Length = 0;
-		SecurityBlob->DomainName.MaximumLength = 0;
-	} else {
-		__u16 len;
-		negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
-		strncpy(bcc_ptr, domain, 63);
-		len = strnlen(domain, 64);
-		SecurityBlob->DomainName.MaximumLength =
-		    cpu_to_le16(len);
-		SecurityBlob->DomainName.Buffer =
-		    cpu_to_le32((long) &SecurityBlob->
-				DomainString -
-				(long) &SecurityBlob->Signature);
-		bcc_ptr += len;
-		SecurityBlobLength += len;
-		SecurityBlob->DomainName.Length =
-		    cpu_to_le16(len);
-	}
+	/* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
+	along with username on auth request (ie the response to challenge) */
+	SecurityBlob->DomainName.Buffer = 0;
+	SecurityBlob->DomainName.Length = 0;
+	SecurityBlob->DomainName.MaximumLength = 0;
 	if (ses->capabilities & CAP_UNICODE) {
 		if ((long) bcc_ptr % 2) {
 			*bcc_ptr = 0;
@@ -2677,7 +2663,7 @@
 			      SecurityBlob2->MessageType));
 		} else if (ses) {
 			ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ 
-			cFYI(1, ("UID = %d ", ses->Suid));
+			cFYI(1, ("UID = %d", ses->Suid));
 			if ((pSMBr->resp.hdr.WordCount == 3)
 			    || ((pSMBr->resp.hdr.WordCount == 4)
 				&& (blob_len <
@@ -2685,17 +2671,17 @@
 
 				if (pSMBr->resp.hdr.WordCount == 4) {
 					bcc_ptr += blob_len;
-					cFYI(1,
-					     ("Security Blob Length %d ",
+					cFYI(1, ("Security Blob Length %d",
 					      blob_len));
 				}
 
-				cFYI(1, ("NTLMSSP Challenge rcvd "));
+				cFYI(1, ("NTLMSSP Challenge rcvd"));
 
 				memcpy(ses->server->cryptKey,
 				       SecurityBlob2->Challenge,
 				       CIFS_CRYPTO_KEY_SIZE);
-				if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
+				if(SecurityBlob2->NegotiateFlags & 
+					cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
 					*pNTLMv2_flag = TRUE;
 
 				if((SecurityBlob2->NegotiateFlags & 
@@ -2818,7 +2804,7 @@
 						bcc_ptr++;
 					} else
 						cFYI(1,
-						     ("Variable field of length %d extends beyond end of smb ",
+						     ("Variable field of length %d extends beyond end of smb",
 						      len));
 				}
 			} else {
@@ -2830,7 +2816,7 @@
 		}
 	} else {
 		cERROR(1,
-		       (" Invalid Word count %d: ",
+		       (" Invalid Word count %d:",
 			smb_buffer_response->WordCount));
 		rc = -EIO;
 	}
@@ -3447,7 +3433,7 @@
 		if (extended_security
 				&& (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
 				&& (pSesInfo->server->secType == NTLMSSP)) {
-			cFYI(1, ("New style sesssetup "));
+			cFYI(1, ("New style sesssetup"));
 			rc = CIFSSpnegoSessSetup(xid, pSesInfo,
 				NULL /* security blob */, 
 				0 /* blob length */,
@@ -3455,7 +3441,7 @@
 		} else if (extended_security
 			   && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
 			   && (pSesInfo->server->secType == RawNTLMSSP)) {
-			cFYI(1, ("NTLMSSP sesssetup "));
+			cFYI(1, ("NTLMSSP sesssetup"));
 			rc = CIFSNTLMSSPNegotiateSessSetup(xid,
 						pSesInfo,
 						&ntlmv2_flag,
diff -urN oldtree/fs/cifs/inode.c newtree/fs/cifs/inode.c
--- oldtree/fs/cifs/inode.c	2006-02-19 11:41:04.946591104 +0000
+++ newtree/fs/cifs/inode.c	2006-02-21 15:58:31.713325400 +0000
@@ -163,9 +163,9 @@
 
 		if (num_of_bytes < end_of_file)
 			cFYI(1, ("allocation size less than end of file"));
-		cFYI(1,
-		     ("Size %ld and blocks %ld",
-		      (unsigned long) inode->i_size, inode->i_blocks));
+		cFYI(1, ("Size %ld and blocks %llu",
+			(unsigned long) inode->i_size,
+			(unsigned long long)inode->i_blocks));
 		if (S_ISREG(inode->i_mode)) {
 			cFYI(1, ("File inode"));
 			inode->i_op = &cifs_file_inode_ops;
diff -urN oldtree/fs/cifs/ntlmssp.c newtree/fs/cifs/ntlmssp.c
--- oldtree/fs/cifs/ntlmssp.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/cifs/ntlmssp.c	2006-02-21 15:58:12.102306728 +0000
@@ -0,0 +1,130 @@
+/*
+ *   fs/cifs/ntlmssp.h
+ *
+ *   Copyright (c) International Business Machines  Corp., 2006
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_unicode.h"
+#include "cifs_debug.h"
+#include "ntlmssp.h"
+#include "nterr.h"
+
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
+{
+	__u32 capabilities = 0;
+
+	/* init fields common to all four types of SessSetup */
+	/* note that header is initialized to zero in header_assemble */
+	pSMB->req.AndXCommand = 0xFF;
+	pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
+	pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
+
+	/* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
+
+	/* BB verify whether signing required on neg or just on auth frame 
+	   (and NTLM case) */
+
+	capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+			CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
+
+	if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+		pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+	if (ses->capabilities & CAP_UNICODE) {
+		pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE;
+		capabilities |= CAP_UNICODE;
+	}
+	if (ses->capabilities & CAP_STATUS32) {
+		pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS;
+		capabilities |= CAP_STATUS32;
+	}
+	if (ses->capabilities & CAP_DFS) {
+		pSMB->req.hdr.Flags2 |= SMBFLG2_DFS;
+		capabilities |= CAP_DFS;
+	}
+
+	/* BB check whether to init vcnum BB */
+	return capabilities;
+}
+int 
+CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, const int type,
+		  int * pNTLMv2_flg, const struct nls_table *nls_cp)
+{
+	int rc = 0;
+	int wct;
+	struct smb_hdr *smb_buffer;
+	char *bcc_ptr;
+	SESSION_SETUP_ANDX *pSMB;
+	__u32 capabilities;
+
+	if(ses == NULL)
+		return -EINVAL;
+
+	cFYI(1,("SStp type: %d",type));
+	if(type < CIFS_NTLM) {
+#ifndef CONFIG_CIFS_WEAK_PW_HASH
+		/* LANMAN and plaintext are less secure and off by default.
+		So we make this explicitly be turned on in kconfig (in the
+		build) and turned on at runtime (changed from the default)
+		in proc/fs/cifs or via mount parm.  Unfortunately this is
+		needed for old Win (e.g. Win95), some obscure NAS and OS/2 */
+		return -EOPNOTSUPP;
+#endif
+		wct = 10; /* lanman 2 style sessionsetup */
+	} else if(type < CIFS_NTLMSSP_NEG)
+		wct = 13; /* old style NTLM sessionsetup */
+	else /* same size for negotiate or auth, NTLMSSP or extended security */
+		wct = 12;
+
+	rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
+			    (void **)&smb_buffer);
+	if(rc)
+		return rc;
+
+	pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
+
+	capabilities = cifs_ssetup_hdr(ses, pSMB);
+	bcc_ptr = pByteArea(smb_buffer);
+	if(type > CIFS_NTLM) {
+		pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
+		capabilities |= CAP_EXTENDED_SECURITY;
+		pSMB->req.Capabilities = cpu_to_le32(capabilities);
+		/* BB set password lengths */
+	} else if(type < CIFS_NTLM) /* lanman */ {
+		/* no capabilities flags in old lanman negotiation */
+		/* pSMB->old_req.PasswordLength = */ /* BB fixme BB */
+	} else /* type CIFS_NTLM */ {
+		pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
+		pSMB->req_no_secext.CaseInsensitivePasswordLength =
+			cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+		pSMB->req_no_secext.CaseSensitivePasswordLength =
+			cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+	}
+
+
+/*	rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buf_type, 0); */
+
+	cifs_small_buf_release(smb_buffer);
+
+	return rc;
+}
+#endif /* CONFIG_CIFS_EXPERIMENTAL */
diff -urN oldtree/fs/cifs/ntlmssp.h newtree/fs/cifs/ntlmssp.h
--- oldtree/fs/cifs/ntlmssp.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/cifs/ntlmssp.h	2006-02-21 15:58:12.103306576 +0000
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/ntlmssp.h
  *
- *   Copyright (c) International Business Machines  Corp., 2002
+ *   Copyright (c) International Business Machines  Corp., 2002,2006
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
diff -urN oldtree/fs/cifs/readdir.c newtree/fs/cifs/readdir.c
--- oldtree/fs/cifs/readdir.c	2006-02-19 11:41:04.948590800 +0000
+++ newtree/fs/cifs/readdir.c	2006-02-21 15:58:31.783314760 +0000
@@ -197,10 +197,10 @@
 
 	if (allocation_size < end_of_file)
 		cFYI(1, ("May be sparse file, allocation less than file size"));
-	cFYI(1,
-	     ("File Size %ld and blocks %ld and blocksize %ld",
-	      (unsigned long)tmp_inode->i_size, tmp_inode->i_blocks,
-	      tmp_inode->i_blksize));
+	cFYI(1, ("File Size %ld and blocks %llu and blocksize %ld",
+		(unsigned long)tmp_inode->i_size,
+		(unsigned long long)tmp_inode->i_blocks,
+		tmp_inode->i_blksize));
 	if (S_ISREG(tmp_inode->i_mode)) {
 		cFYI(1, ("File inode"));
 		tmp_inode->i_op = &cifs_file_inode_ops;
diff -urN oldtree/fs/coda/coda_int.h newtree/fs/coda/coda_int.h
--- oldtree/fs/coda/coda_int.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/coda/coda_int.h	2006-02-21 15:58:29.387678952 +0000
@@ -0,0 +1,13 @@
+#ifndef _CODA_INT_
+#define _CODA_INT_
+
+extern struct file_system_type coda_fs_type;
+
+void coda_destroy_inodecache(void);
+int coda_init_inodecache(void);
+int coda_fsync(struct file *coda_file, struct dentry *coda_dentry,
+	       int datasync);
+
+#endif  /*  _CODA_INT_  */
+
+
diff -urN oldtree/fs/coda/dir.c newtree/fs/coda/dir.c
--- oldtree/fs/coda/dir.c	2006-02-19 11:41:04.950590496 +0000
+++ newtree/fs/coda/dir.c	2006-02-21 15:58:29.394677888 +0000
@@ -27,6 +27,8 @@
 #include <linux/coda_cache.h>
 #include <linux/coda_proc.h>
 
+#include "coda_int.h"
+
 /* dir inode-ops */
 static int coda_create(struct inode *dir, struct dentry *new, int mode, struct nameidata *nd);
 static struct dentry *coda_lookup(struct inode *dir, struct dentry *target, struct nameidata *nd);
@@ -50,7 +52,6 @@
 /* support routines */
 static int coda_venus_readdir(struct file *filp, filldir_t filldir,
 			      void *dirent, struct dentry *dir);
-int coda_fsync(struct file *, struct dentry *dentry, int datasync);
 
 /* same as fs/bad_inode.c */
 static int coda_return_EIO(void)
diff -urN oldtree/fs/coda/file.c newtree/fs/coda/file.c
--- oldtree/fs/coda/file.c	2006-02-19 11:41:04.951590344 +0000
+++ newtree/fs/coda/file.c	2006-02-21 15:58:29.394677888 +0000
@@ -24,6 +24,8 @@
 #include <linux/coda_psdev.h>
 #include <linux/coda_proc.h>
 
+#include "coda_int.h"
+
 /* if CODA_STORE fails with EOPNOTSUPP, venus clearly doesn't support
  * CODA_STORE/CODA_RELEASE and we fall back on using the CODA_CLOSE upcall */
 static int use_coda_close;
diff -urN oldtree/fs/coda/inode.c newtree/fs/coda/inode.c
--- oldtree/fs/coda/inode.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/coda/inode.c	2006-02-21 15:58:29.395677736 +0000
@@ -31,6 +31,8 @@
 #include <linux/coda_fs_i.h>
 #include <linux/coda_cache.h>
 
+#include "coda_int.h"
+
 /* VFS super_block ops */
 static void coda_clear_inode(struct inode *);
 static void coda_put_super(struct super_block *);
diff -urN oldtree/fs/coda/psdev.c newtree/fs/coda/psdev.c
--- oldtree/fs/coda/psdev.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/coda/psdev.c	2006-02-21 15:58:29.395677736 +0000
@@ -48,12 +48,9 @@
 #include <linux/coda_psdev.h>
 #include <linux/coda_proc.h>
 
-#define upc_free(r) kfree(r)
+#include "coda_int.h"
 
-/* 
- * Coda stuff
- */
-extern struct file_system_type coda_fs_type;
+#define upc_free(r) kfree(r)
 
 /* statistics */
 int           coda_hard;         /* allows signals during upcalls */
@@ -394,8 +391,6 @@
 MODULE_AUTHOR("Peter J. Braam <braam@cs.cmu.edu>");
 MODULE_LICENSE("GPL");
 
-extern int coda_init_inodecache(void);
-extern void coda_destroy_inodecache(void);
 static int __init init_coda(void)
 {
 	int status;
diff -urN oldtree/fs/compat.c newtree/fs/compat.c
--- oldtree/fs/compat.c	2006-02-19 11:41:04.953590040 +0000
+++ newtree/fs/compat.c	2006-02-21 15:58:30.129566168 +0000
@@ -114,6 +114,7 @@
 	return error;
 }
 
+#ifndef __ARCH_WANT_STAT64
 asmlinkage long compat_sys_newfstatat(unsigned int dfd, char __user *filename,
 		struct compat_stat __user *statbuf, int flag)
 {
@@ -134,6 +135,7 @@
 out:
 	return error;
 }
+#endif
 
 asmlinkage long compat_sys_newfstat(unsigned int fd,
 		struct compat_stat __user * statbuf)
diff -urN oldtree/fs/compat_ioctl.c newtree/fs/compat_ioctl.c
--- oldtree/fs/compat_ioctl.c	2006-02-19 11:41:04.956589584 +0000
+++ newtree/fs/compat_ioctl.c	2006-02-21 15:58:11.946330440 +0000
@@ -72,6 +72,7 @@
 #include <linux/i2c-dev.h>
 #include <linux/wireless.h>
 #include <linux/atalk.h>
+#include <linux/blktrace_api.h>
 
 #include <net/sock.h>          /* siocdevprivate_ioctl */
 #include <net/bluetooth/bluetooth.h>
diff -urN oldtree/fs/cramfs/inode.c newtree/fs/cramfs/inode.c
--- oldtree/fs/cramfs/inode.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/cramfs/inode.c	2006-02-21 15:58:23.873517232 +0000
@@ -22,6 +22,7 @@
 #include <linux/cramfs_fs_sb.h>
 #include <linux/buffer_head.h>
 #include <linux/vfs.h>
+#include <linux/mutex.h>
 #include <asm/semaphore.h>
 
 #include <asm/uaccess.h>
@@ -31,7 +32,7 @@
 static struct file_operations cramfs_directory_operations;
 static struct address_space_operations cramfs_aops;
 
-static DECLARE_MUTEX(read_mutex);
+static DEFINE_MUTEX(read_mutex);
 
 
 /* These two macros may change in future, to provide better st_ino
@@ -252,20 +253,20 @@
 	memset(sbi, 0, sizeof(struct cramfs_sb_info));
 
 	/* Invalidate the read buffers on mount: think disk change.. */
-	down(&read_mutex);
+	mutex_lock(&read_mutex);
 	for (i = 0; i < READ_BUFFERS; i++)
 		buffer_blocknr[i] = -1;
 
 	/* Read the first block and get the superblock from it */
 	memcpy(&super, cramfs_read(sb, 0, sizeof(super)), sizeof(super));
-	up(&read_mutex);
+	mutex_unlock(&read_mutex);
 
 	/* Do sanity checks on the superblock */
 	if (super.magic != CRAMFS_MAGIC) {
 		/* check at 512 byte offset */
-		down(&read_mutex);
+		mutex_lock(&read_mutex);
 		memcpy(&super, cramfs_read(sb, 512, sizeof(super)), sizeof(super));
-		up(&read_mutex);
+		mutex_unlock(&read_mutex);
 		if (super.magic != CRAMFS_MAGIC) {
 			if (!silent)
 				printk(KERN_ERR "cramfs: wrong magic\n");
@@ -368,7 +369,7 @@
 		mode_t mode;
 		int namelen, error;
 
-		down(&read_mutex);
+		mutex_lock(&read_mutex);
 		de = cramfs_read(sb, OFFSET(inode) + offset, sizeof(*de)+256);
 		name = (char *)(de+1);
 
@@ -381,7 +382,7 @@
 		memcpy(buf, name, namelen);
 		ino = CRAMINO(de);
 		mode = de->mode;
-		up(&read_mutex);
+		mutex_unlock(&read_mutex);
 		nextoffset = offset + sizeof(*de) + namelen;
 		for (;;) {
 			if (!namelen) {
@@ -412,7 +413,7 @@
 	unsigned int offset = 0;
 	int sorted;
 
-	down(&read_mutex);
+	mutex_lock(&read_mutex);
 	sorted = CRAMFS_SB(dir->i_sb)->flags & CRAMFS_FLAG_SORTED_DIRS;
 	while (offset < dir->i_size) {
 		struct cramfs_inode *de;
@@ -435,7 +436,7 @@
 
 		for (;;) {
 			if (!namelen) {
-				up(&read_mutex);
+				mutex_unlock(&read_mutex);
 				return ERR_PTR(-EIO);
 			}
 			if (name[namelen-1])
@@ -449,7 +450,7 @@
 			continue;
 		if (!retval) {
 			struct cramfs_inode entry = *de;
-			up(&read_mutex);
+			mutex_unlock(&read_mutex);
 			d_add(dentry, get_cramfs_inode(dir->i_sb, &entry));
 			return NULL;
 		}
@@ -457,7 +458,7 @@
 		if (sorted)
 			break;
 	}
-	up(&read_mutex);
+	mutex_unlock(&read_mutex);
 	d_add(dentry, NULL);
 	return NULL;
 }
@@ -476,21 +477,21 @@
 		u32 start_offset, compr_len;
 
 		start_offset = OFFSET(inode) + maxblock*4;
-		down(&read_mutex);
+		mutex_lock(&read_mutex);
 		if (page->index)
 			start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4, 4);
 		compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4) - start_offset);
-		up(&read_mutex);
+		mutex_unlock(&read_mutex);
 		pgdata = kmap(page);
 		if (compr_len == 0)
 			; /* hole */
 		else {
-			down(&read_mutex);
+			mutex_lock(&read_mutex);
 			bytes_filled = cramfs_uncompress_block(pgdata,
 				 PAGE_CACHE_SIZE,
 				 cramfs_read(sb, start_offset, compr_len),
 				 compr_len);
-			up(&read_mutex);
+			mutex_unlock(&read_mutex);
 		}
 	} else
 		pgdata = kmap(page);
diff -urN oldtree/fs/dcookies.c newtree/fs/dcookies.c
--- oldtree/fs/dcookies.c	2006-02-19 11:41:04.962588672 +0000
+++ newtree/fs/dcookies.c	2006-02-21 15:58:23.876516776 +0000
@@ -23,6 +23,7 @@
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/dcookies.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 /* The dcookies are allocated from a kmem_cache and
@@ -36,7 +37,7 @@
 };
 
 static LIST_HEAD(dcookie_users);
-static DECLARE_MUTEX(dcookie_sem);
+static DEFINE_MUTEX(dcookie_mutex);
 static kmem_cache_t * dcookie_cache;
 static struct list_head * dcookie_hashtable;
 static size_t hash_size;
@@ -114,7 +115,7 @@
 	int err = 0;
 	struct dcookie_struct * dcs;
 
-	down(&dcookie_sem);
+	mutex_lock(&dcookie_mutex);
 
 	if (!is_live()) {
 		err = -EINVAL;
@@ -134,7 +135,7 @@
 	*cookie = dcookie_value(dcs);
 
 out:
-	up(&dcookie_sem);
+	mutex_unlock(&dcookie_mutex);
 	return err;
 }
 
@@ -157,7 +158,7 @@
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	down(&dcookie_sem);
+	mutex_lock(&dcookie_mutex);
 
 	if (!is_live()) {
 		err = -EINVAL;
@@ -192,7 +193,7 @@
 out_free:
 	kfree(kbuf);
 out:
-	up(&dcookie_sem);
+	mutex_unlock(&dcookie_mutex);
 	return err;
 }
 
@@ -290,7 +291,7 @@
 {
 	struct dcookie_user * user;
 
-	down(&dcookie_sem);
+	mutex_lock(&dcookie_mutex);
 
 	user = kmalloc(sizeof(struct dcookie_user), GFP_KERNEL);
 	if (!user)
@@ -302,7 +303,7 @@
 	list_add(&user->next, &dcookie_users);
 
 out:
-	up(&dcookie_sem);
+	mutex_unlock(&dcookie_mutex);
 	return user;
 out_free:
 	kfree(user);
@@ -313,7 +314,7 @@
 
 void dcookie_unregister(struct dcookie_user * user)
 {
-	down(&dcookie_sem);
+	mutex_lock(&dcookie_mutex);
 
 	list_del(&user->next);
 	kfree(user);
@@ -321,7 +322,7 @@
 	if (!is_live())
 		dcookie_exit();
 
-	up(&dcookie_sem);
+	mutex_unlock(&dcookie_mutex);
 }
 
 EXPORT_SYMBOL_GPL(dcookie_register);
diff -urN oldtree/fs/devpts/inode.c newtree/fs/devpts/inode.c
--- oldtree/fs/devpts/inode.c	2006-02-19 11:41:04.965588216 +0000
+++ newtree/fs/devpts/inode.c	2006-02-21 15:58:29.112720752 +0000
@@ -18,6 +18,7 @@
 #include <linux/mount.h>
 #include <linux/tty.h>
 #include <linux/devpts_fs.h>
+#include <linux/parser.h>
 
 #define DEVPTS_SUPER_MAGIC 0x1cd1
 
@@ -32,39 +33,60 @@
 	umode_t mode;
 } config = {.mode = 0600};
 
+enum {
+	Opt_uid, Opt_gid, Opt_mode,
+	Opt_err
+};
+
+static match_table_t tokens = {
+	{Opt_uid, "uid=%u"},
+	{Opt_gid, "gid=%u"},
+	{Opt_mode, "mode=%o"},
+	{Opt_err, NULL}
+};
+
 static int devpts_remount(struct super_block *sb, int *flags, char *data)
 {
-	int setuid = 0;
-	int setgid = 0;
-	uid_t uid = 0;
-	gid_t gid = 0;
-	umode_t mode = 0600;
-	char *this_char;
-
-	this_char = NULL;
-	while ((this_char = strsep(&data, ",")) != NULL) {
-		int n;
-		char dummy;
-		if (!*this_char)
+	char *p;
+
+	config.setuid  = 0;
+	config.setgid  = 0;
+	config.uid     = 0;
+	config.gid     = 0;
+	config.mode    = 0600;
+
+	while ((p = strsep(&data, ",")) != NULL) {
+		substring_t args[MAX_OPT_ARGS];
+		int token;
+		int option;
+
+		if (!*p)
 			continue;
-		if (sscanf(this_char, "uid=%i%c", &n, &dummy) == 1) {
-			setuid = 1;
-			uid = n;
-		} else if (sscanf(this_char, "gid=%i%c", &n, &dummy) == 1) {
-			setgid = 1;
-			gid = n;
-		} else if (sscanf(this_char, "mode=%o%c", &n, &dummy) == 1)
-			mode = n & ~S_IFMT;
-		else {
-			printk("devpts: called with bogus options\n");
+
+		token = match_token(p, tokens, args);
+		switch (token) {
+		case Opt_uid:
+			if (match_int(&args[0], &option))
+				return -EINVAL;
+			config.uid = option;
+			config.setuid = 1;
+			break;
+		case Opt_gid:
+			if (match_int(&args[0], &option))
+				return -EINVAL;
+			config.gid = option;
+			config.setgid = 1;
+			break;
+		case Opt_mode:
+			if (match_octal(&args[0], &option))
+				return -EINVAL;
+			config.mode = option & ~S_IFMT;
+			break;
+		default:
+			printk(KERN_ERR "devpts: called with bogus options\n");
 			return -EINVAL;
 		}
 	}
-	config.setuid  = setuid;
-	config.setgid  = setgid;
-	config.uid     = uid;
-	config.gid     = gid;
-	config.mode    = mode;
 
 	return 0;
 }
diff -urN oldtree/fs/eventpoll.c newtree/fs/eventpoll.c
--- oldtree/fs/eventpoll.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/eventpoll.c	2006-02-21 15:58:25.781227216 +0000
@@ -34,6 +34,7 @@
 #include <linux/eventpoll.h>
 #include <linux/mount.h>
 #include <linux/bitops.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/io.h>
@@ -46,7 +47,7 @@
  * LOCKING:
  * There are three level of locking required by epoll :
  *
- * 1) epsem (semaphore)
+ * 1) epmutex (mutex)
  * 2) ep->sem (rw_semaphore)
  * 3) ep->lock (rw_lock)
  *
@@ -67,9 +68,9 @@
  * if a file has been pushed inside an epoll set and it is then
  * close()d without a previous call toepoll_ctl(EPOLL_CTL_DEL).
  * It is possible to drop the "ep->sem" and to use the global
- * semaphore "epsem" (together with "ep->lock") to have it working,
+ * semaphore "epmutex" (together with "ep->lock") to have it working,
  * but having "ep->sem" will make the interface more scalable.
- * Events that require holding "epsem" are very rare, while for
+ * Events that require holding "epmutex" are very rare, while for
  * normal operations the epoll private "ep->sem" will guarantee
  * a greater scalability.
  */
@@ -274,7 +275,7 @@
 /*
  * This semaphore is used to serialize ep_free() and eventpoll_release_file().
  */
-static struct semaphore epsem;
+static struct mutex epmutex;
 
 /* Safe wake up implementation */
 static struct poll_safewake psw;
@@ -477,10 +478,10 @@
 	 * cleanup path, and this means that noone is using this file anymore.
 	 * The only hit might come from ep_free() but by holding the semaphore
 	 * will correctly serialize the operation. We do need to acquire
-	 * "ep->sem" after "epsem" because ep_remove() requires it when called
+	 * "ep->sem" after "epmutex" because ep_remove() requires it when called
 	 * from anywhere but ep_free().
 	 */
-	down(&epsem);
+	mutex_lock(&epmutex);
 
 	while (!list_empty(lsthead)) {
 		epi = list_entry(lsthead->next, struct epitem, fllink);
@@ -492,7 +493,7 @@
 		up_write(&ep->sem);
 	}
 
-	up(&epsem);
+	mutex_unlock(&epmutex);
 }
 
 
@@ -819,9 +820,9 @@
 	 * We do not need to hold "ep->sem" here because the epoll file
 	 * is on the way to be removed and no one has references to it
 	 * anymore. The only hit might come from eventpoll_release_file() but
-	 * holding "epsem" is sufficent here.
+	 * holding "epmutex" is sufficent here.
 	 */
-	down(&epsem);
+	mutex_lock(&epmutex);
 
 	/*
 	 * Walks through the whole tree by unregistering poll callbacks.
@@ -843,7 +844,7 @@
 		ep_remove(ep, epi);
 	}
 
-	up(&epsem);
+	mutex_unlock(&epmutex);
 }
 
 
@@ -1615,7 +1616,7 @@
 {
 	int error;
 
-	init_MUTEX(&epsem);
+	mutex_init(&epmutex);
 
 	/* Initialize the structure used to perform safe poll wait head wake ups */
 	ep_poll_safewake_init(&psw);
diff -urN oldtree/fs/exec.c newtree/fs/exec.c
--- oldtree/fs/exec.c	2006-02-19 11:41:04.969587608 +0000
+++ newtree/fs/exec.c	2006-02-21 15:58:30.465515096 +0000
@@ -660,12 +660,23 @@
 		struct dentry *proc_dentry1, *proc_dentry2;
 		unsigned long ptrace;
 
+		leader = current->group_leader;
+		/*
+		 * If our leader is the child_reaper become
+		 * the child_reaper and resend SIGKILL signal.
+		 */
+		if (unlikely(leader == child_reaper)) {
+			write_lock(&tasklist_lock);
+			child_reaper = current;
+			zap_other_threads(current);
+			write_unlock(&tasklist_lock);
+		}
+
 		/*
 		 * Wait for the thread group leader to be a zombie.
 		 * It should already be zombie at this point, most
 		 * of the time.
 		 */
-		leader = current->group_leader;
 		while (leader->exit_state != EXIT_ZOMBIE)
 			yield();
 
diff -urN oldtree/fs/ext2/ext2.h newtree/fs/ext2/ext2.h
--- oldtree/fs/ext2/ext2.h	2006-02-19 11:41:04.972587152 +0000
+++ newtree/fs/ext2/ext2.h	2006-02-21 15:58:29.365682296 +0000
@@ -138,6 +138,9 @@
 extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
 		       unsigned long);
 
+/* namei.c */
+struct dentry *ext2_get_parent(struct dentry *child);
+
 /* super.c */
 extern void ext2_error (struct super_block *, const char *, const char *, ...)
 	__attribute__ ((format (printf, 3, 4)));
diff -urN oldtree/fs/ext2/super.c newtree/fs/ext2/super.c
--- oldtree/fs/ext2/super.c	2006-02-19 11:41:04.975586696 +0000
+++ newtree/fs/ext2/super.c	2006-02-21 15:58:29.374680928 +0000
@@ -258,7 +258,6 @@
  * systems, but can be improved upon.
  * Currently only get_parent is required.
  */
-struct dentry *ext2_get_parent(struct dentry *child);
 static struct export_operations ext2_export_ops = {
 	.get_parent = ext2_get_parent,
 };
diff -urN oldtree/fs/ext3/file.c newtree/fs/ext3/file.c
--- oldtree/fs/ext3/file.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/ext3/file.c	2006-02-21 15:58:28.185861656 +0000
@@ -37,9 +37,9 @@
 	if ((filp->f_mode & FMODE_WRITE) &&
 			(atomic_read(&inode->i_writecount) == 1))
 	{
-		down(&EXT3_I(inode)->truncate_sem);
+		mutex_lock(&EXT3_I(inode)->truncate_mutex);
 		ext3_discard_reservation(inode);
-		up(&EXT3_I(inode)->truncate_sem);
+		mutex_unlock(&EXT3_I(inode)->truncate_mutex);
 	}
 	if (is_dx(inode) && filp->private_data)
 		ext3_htree_free_dir_info(filp->private_data);
diff -urN oldtree/fs/ext3/inode.c newtree/fs/ext3/inode.c
--- oldtree/fs/ext3/inode.c	2006-02-19 11:41:04.982585632 +0000
+++ newtree/fs/ext3/inode.c	2006-02-21 15:58:28.187861352 +0000
@@ -702,7 +702,7 @@
 	if (!create || err == -EIO)
 		goto cleanup;
 
-	down(&ei->truncate_sem);
+	mutex_lock(&ei->truncate_mutex);
 
 	/*
 	 * If the indirect block is missing while we are reading
@@ -723,7 +723,7 @@
 		}
 		partial = ext3_get_branch(inode, depth, offsets, chain, &err);
 		if (!partial) {
-			up(&ei->truncate_sem);
+			mutex_unlock(&ei->truncate_mutex);
 			if (err)
 				goto cleanup;
 			clear_buffer_new(bh_result);
@@ -759,13 +759,13 @@
 		err = ext3_splice_branch(handle, inode, iblock, chain,
 					 partial, left);
 	/*
-	 * i_disksize growing is protected by truncate_sem.  Don't forget to
+	 * i_disksize growing is protected by truncate_mutex.  Don't forget to
 	 * protect it if you're about to implement concurrent
 	 * ext3_get_block() -bzzz
 	*/
 	if (!err && extend_disksize && inode->i_size > ei->i_disksize)
 		ei->i_disksize = inode->i_size;
-	up(&ei->truncate_sem);
+	mutex_unlock(&ei->truncate_mutex);
 	if (err)
 		goto cleanup;
 
@@ -1227,7 +1227,7 @@
  *	ext3_file_write() -> generic_file_write() -> __alloc_pages() -> ...
  *
  * Same applies to ext3_get_block().  We will deadlock on various things like
- * lock_journal and i_truncate_sem.
+ * lock_journal and i_truncate_mutex.
  *
  * Setting PF_MEMALLOC here doesn't work - too many internal memory
  * allocations fail.
@@ -2162,7 +2162,7 @@
 	 * From here we block out all ext3_get_block() callers who want to
 	 * modify the block allocation tree.
 	 */
-	down(&ei->truncate_sem);
+	mutex_lock(&ei->truncate_mutex);
 
 	if (n == 1) {		/* direct blocks */
 		ext3_free_data(handle, inode, NULL, i_data+offsets[0],
@@ -2229,7 +2229,7 @@
 
 	ext3_discard_reservation(inode);
 
-	up(&ei->truncate_sem);
+	mutex_unlock(&ei->truncate_mutex);
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
 	ext3_mark_inode_dirty(handle, inode);
 
diff -urN oldtree/fs/ext3/ioctl.c newtree/fs/ext3/ioctl.c
--- oldtree/fs/ext3/ioctl.c	2006-02-19 11:41:04.983585480 +0000
+++ newtree/fs/ext3/ioctl.c	2006-02-21 15:58:28.188861200 +0000
@@ -182,7 +182,7 @@
 		 * need to allocate reservation structure for this inode
 		 * before set the window size
 		 */
-		down(&ei->truncate_sem);
+		mutex_lock(&ei->truncate_mutex);
 		if (!ei->i_block_alloc_info)
 			ext3_init_block_alloc_info(inode);
 
@@ -190,7 +190,7 @@
 			struct ext3_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node;
 			rsv->rsv_goal_size = rsv_window_size;
 		}
-		up(&ei->truncate_sem);
+		mutex_unlock(&ei->truncate_mutex);
 		return 0;
 	}
 	case EXT3_IOC_GROUP_EXTEND: {
diff -urN oldtree/fs/ext3/resize.c newtree/fs/ext3/resize.c
--- oldtree/fs/ext3/resize.c	2006-02-19 11:41:04.985585176 +0000
+++ newtree/fs/ext3/resize.c	2006-02-21 15:58:36.548590328 +0000
@@ -334,7 +334,7 @@
 	unsigned five = 5;
 	unsigned seven = 7;
 	unsigned grp;
-	__u32 *p = (__u32 *)primary->b_data;
+	__le32 *p = (__le32 *)primary->b_data;
 	int gdbackups = 0;
 
 	while ((grp = ext3_list_backups(sb, &three, &five, &seven)) < end) {
@@ -377,7 +377,7 @@
 	struct buffer_head *dind;
 	int gdbackups;
 	struct ext3_iloc iloc;
-	__u32 *data;
+	__le32 *data;
 	int err;
 
 	if (test_opt(sb, DEBUG))
@@ -414,7 +414,7 @@
 		goto exit_bh;
 	}
 
-	data = (__u32 *)dind->b_data;
+	data = (__le32 *)dind->b_data;
 	if (le32_to_cpu(data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)]) != gdblock) {
 		ext3_warning(sb, __FUNCTION__,
 			     "new group %u GDT block %lu not reserved",
@@ -516,7 +516,7 @@
 	struct buffer_head *dind;
 	struct ext3_iloc iloc;
 	unsigned long blk;
-	__u32 *data, *end;
+	__le32 *data, *end;
 	int gdbackups = 0;
 	int res, i;
 	int err;
@@ -533,15 +533,15 @@
 	}
 
 	blk = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + EXT3_SB(sb)->s_gdb_count;
-	data = (__u32 *)dind->b_data + EXT3_SB(sb)->s_gdb_count;
-	end = (__u32 *)dind->b_data + EXT3_ADDR_PER_BLOCK(sb);
+	data = (__le32 *)dind->b_data + EXT3_SB(sb)->s_gdb_count;
+	end = (__le32 *)dind->b_data + EXT3_ADDR_PER_BLOCK(sb);
 
 	/* Get each reserved primary GDT block and verify it holds backups */
 	for (res = 0; res < reserved_gdb; res++, blk++) {
 		if (le32_to_cpu(*data) != blk) {
 			ext3_warning(sb, __FUNCTION__,
 				     "reserved block %lu not at offset %ld",
-				     blk, (long)(data - (__u32 *)dind->b_data));
+				     blk, (long)(data - (__le32 *)dind->b_data));
 			err = -EINVAL;
 			goto exit_bh;
 		}
@@ -556,7 +556,7 @@
 			goto exit_bh;
 		}
 		if (++data >= end)
-			data = (__u32 *)dind->b_data;
+			data = (__le32 *)dind->b_data;
 	}
 
 	for (i = 0; i < reserved_gdb; i++) {
@@ -580,7 +580,7 @@
 	blk = input->group * EXT3_BLOCKS_PER_GROUP(sb);
 	for (i = 0; i < reserved_gdb; i++) {
 		int err2;
-		data = (__u32 *)primary[i]->b_data;
+		data = (__le32 *)primary[i]->b_data;
 		/* printk("reserving backup %lu[%u] = %lu\n",
 		       primary[i]->b_blocknr, gdbackups,
 		       blk + primary[i]->b_blocknr); */
@@ -685,7 +685,7 @@
 			     "can't update backup for group %d (err %d), "
 			     "forcing fsck on next reboot", group, err);
 		sbi->s_mount_state &= ~EXT3_VALID_FS;
-		sbi->s_es->s_state &= ~cpu_to_le16(EXT3_VALID_FS);
+		sbi->s_es->s_state &= cpu_to_le16(~EXT3_VALID_FS);
 		mark_buffer_dirty(sbi->s_sbh);
 	}
 }
diff -urN oldtree/fs/ext3/super.c newtree/fs/ext3/super.c
--- oldtree/fs/ext3/super.c	2006-02-19 11:41:04.987584872 +0000
+++ newtree/fs/ext3/super.c	2006-02-21 15:58:36.549590176 +0000
@@ -472,7 +472,7 @@
 #ifdef CONFIG_EXT3_FS_XATTR
 		init_rwsem(&ei->xattr_sem);
 #endif
-		init_MUTEX(&ei->truncate_sem);
+		mutex_init(&ei->truncate_mutex);
 		inode_init_once(&ei->vfs_inode);
 	}
 }
@@ -2289,10 +2289,9 @@
 			 */
 			ext3_clear_journal_err(sb, es);
 			sbi->s_mount_state = le16_to_cpu(es->s_state);
-			if ((ret = ext3_group_extend(sb, es, n_blocks_count))) {
-				err = ret;
+			err = ext3_group_extend(sb, es, n_blocks_count);
+			if (err)
 				goto restore_opts;
-			}
 			if (!ext3_setup_super (sb, es, 0))
 				sb->s_flags &= ~MS_RDONLY;
 		}
diff -urN oldtree/fs/fat/fatent.c newtree/fs/fat/fatent.c
--- oldtree/fs/fat/fatent.c	2006-02-19 11:41:04.991584264 +0000
+++ newtree/fs/fat/fatent.c	2006-02-21 15:58:28.916750544 +0000
@@ -267,19 +267,19 @@
 
 static inline void lock_fat(struct msdos_sb_info *sbi)
 {
-	down(&sbi->fat_lock);
+	mutex_lock(&sbi->fat_lock);
 }
 
 static inline void unlock_fat(struct msdos_sb_info *sbi)
 {
-	up(&sbi->fat_lock);
+	mutex_unlock(&sbi->fat_lock);
 }
 
 void fat_ent_access_init(struct super_block *sb)
 {
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 
-	init_MUTEX(&sbi->fat_lock);
+	mutex_init(&sbi->fat_lock);
 
 	switch (sbi->fat_bits) {
 	case 32:
diff -urN oldtree/fs/fat/inode.c newtree/fs/fat/inode.c
--- oldtree/fs/fat/inode.c	2006-02-19 11:41:04.993583960 +0000
+++ newtree/fs/fat/inode.c	2006-02-21 15:58:36.554589416 +0000
@@ -390,7 +390,7 @@
 				      le16_to_cpu(de->cdate)) + secs;
 		inode->i_ctime.tv_nsec = csecs * 10000000;
 		inode->i_atime.tv_sec =
-			date_dos2unix(le16_to_cpu(0), le16_to_cpu(de->adate));
+			date_dos2unix(0, le16_to_cpu(de->adate));
 		inode->i_atime.tv_nsec = 0;
 	} else
 		inode->i_ctime = inode->i_atime = inode->i_mtime;
diff -urN oldtree/fs/fcntl.c newtree/fs/fcntl.c
--- oldtree/fs/fcntl.c	2006-02-19 11:41:04.994583808 +0000
+++ newtree/fs/fcntl.c	2006-02-21 15:58:23.590560248 +0000
@@ -73,8 +73,8 @@
 	 * orig_start..fdt->next_fd
 	 */
 	start = orig_start;
-	if (start < fdt->next_fd)
-		start = fdt->next_fd;
+	if (start < files->next_fd)
+		start = files->next_fd;
 
 	newfd = start;
 	if (start < fdt->max_fdset) {
@@ -102,9 +102,8 @@
 	 * we reacquire the fdtable pointer and use it while holding
 	 * the lock, no one can free it during that time.
 	 */
-	fdt = files_fdtable(files);
-	if (start <= fdt->next_fd)
-		fdt->next_fd = newfd + 1;
+	if (start <= files->next_fd)
+		files->next_fd = newfd + 1;
 
 	error = newfd;
 	
diff -urN oldtree/fs/file.c newtree/fs/file.c
--- oldtree/fs/file.c	2006-02-19 11:41:04.995583656 +0000
+++ newtree/fs/file.c	2006-02-21 15:58:23.592559944 +0000
@@ -125,7 +125,8 @@
 		kmem_cache_free(files_cachep, fdt->free_files);
 		return;
 	}
-	if (fdt->max_fdset <= __FD_SETSIZE && fdt->max_fds <= NR_OPEN_DEFAULT) {
+	if (fdt->max_fdset <= EMBEDDED_FD_SET_SIZE &&
+		fdt->max_fds <= NR_OPEN_DEFAULT) {
 		/*
 		 * The fdtable was embedded
 		 */
@@ -155,8 +156,9 @@
 
 void free_fdtable(struct fdtable *fdt)
 {
-	if (fdt->free_files || fdt->max_fdset > __FD_SETSIZE ||
-					fdt->max_fds > NR_OPEN_DEFAULT)
+	if (fdt->free_files ||
+		fdt->max_fdset > EMBEDDED_FD_SET_SIZE ||
+		fdt->max_fds > NR_OPEN_DEFAULT)
 		call_rcu(&fdt->rcu, free_fdtable_rcu);
 }
 
@@ -199,7 +201,6 @@
 		       (nfdt->max_fds - fdt->max_fds) *
 					sizeof(struct file *));
 	}
-	nfdt->next_fd = fdt->next_fd;
 }
 
 /*
@@ -220,11 +221,9 @@
 
 void free_fdset(fd_set *array, int num)
 {
-	int size = num / 8;
-
-	if (num <= __FD_SETSIZE) /* Don't free an embedded fdset */
+	if (num <= EMBEDDED_FD_SET_SIZE) /* Don't free an embedded fdset */
 		return;
-	else if (size <= PAGE_SIZE)
+	else if (num <= 8 * PAGE_SIZE)
 		kfree(array);
 	else
 		vfree(array);
@@ -237,22 +236,17 @@
   	fd_set *new_openset = NULL, *new_execset = NULL;
 	struct file **new_fds;
 
-	fdt = kmalloc(sizeof(*fdt), GFP_KERNEL);
+	fdt = kzalloc(sizeof(*fdt), GFP_KERNEL);
 	if (!fdt)
   		goto out;
-	memset(fdt, 0, sizeof(*fdt));
 
-	nfds = __FD_SETSIZE;
+	nfds = 8 * L1_CACHE_BYTES;
   	/* Expand to the max in easy steps */
-  	do {
-		if (nfds < (PAGE_SIZE * 8))
-			nfds = PAGE_SIZE * 8;
-		else {
-			nfds = nfds * 2;
-			if (nfds > NR_OPEN)
-				nfds = NR_OPEN;
-		}
-	} while (nfds <= nr);
+  	while (nfds <= nr) {
+		nfds = nfds * 2;
+		if (nfds > NR_OPEN)
+			nfds = NR_OPEN;
+	}
 
   	new_openset = alloc_fdset(nfds);
   	new_execset = alloc_fdset(nfds);
diff -urN oldtree/fs/fs-writeback.c newtree/fs/fs-writeback.c
--- oldtree/fs/fs-writeback.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/fs-writeback.c	2006-02-21 15:58:33.807007112 +0000
@@ -286,8 +286,6 @@
  * WB_SYNC_HOLD is a hack for sys_sync(): reattach the inode to sb->s_dirty so
  * that it can be located for waiting on in __writeback_single_inode().
  *
- * Called under inode_lock.
- *
  * If `bdi' is non-zero then we're being asked to writeback a specific queue.
  * This function assumes that the blockdev superblock's inodes are backed by
  * a variety of queues, so all inodes are searched.  For other superblocks,
@@ -303,11 +301,13 @@
  * on the writer throttling path, and we get decent balancing between many
  * throttled threads: we don't want them all piling up on __wait_on_inode.
  */
-static void
-sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc)
+void
+generic_sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc)
 {
 	const unsigned long start = jiffies;	/* livelock avoidance */
 
+	spin_lock(&inode_lock);
+
 	if (!wbc->for_kupdate || list_empty(&sb->s_io))
 		list_splice_init(&sb->s_dirty, &sb->s_io);
 
@@ -387,8 +387,19 @@
 		if (wbc->nr_to_write <= 0)
 			break;
 	}
+	spin_unlock(&inode_lock);
 	return;		/* Leave any unwritten inodes on s_io */
 }
+EXPORT_SYMBOL(generic_sync_sb_inodes);
+
+static void
+sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc)
+{
+	if (sb->s_op->sync_inodes)
+		sb->s_op->sync_inodes(sb, wbc);
+	else
+		generic_sync_sb_inodes(sb, wbc);
+}
 
 /*
  * Start writeback of dirty pagecache data against all unlocked inodes.
@@ -429,11 +440,8 @@
 			 * be unmounted by the time it is released.
 			 */
 			if (down_read_trylock(&sb->s_umount)) {
-				if (sb->s_root) {
-					spin_lock(&inode_lock);
+				if (sb->s_root)
 					sync_sb_inodes(sb, wbc);
-					spin_unlock(&inode_lock);
-				}
 				up_read(&sb->s_umount);
 			}
 			spin_lock(&sb_lock);
@@ -469,9 +477,7 @@
 			(inodes_stat.nr_inodes - inodes_stat.nr_unused) +
 			nr_dirty + nr_unstable;
 	wbc.nr_to_write += wbc.nr_to_write / 2;		/* Bit more for luck */
-	spin_lock(&inode_lock);
 	sync_sb_inodes(sb, &wbc);
-	spin_unlock(&inode_lock);
 }
 
 /*
diff -urN oldtree/fs/hpfs/hpfs_fn.h newtree/fs/hpfs/hpfs_fn.h
--- oldtree/fs/hpfs/hpfs_fn.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/hpfs/hpfs_fn.h	2006-02-21 15:58:27.949897528 +0000
@@ -9,6 +9,7 @@
 //#define DBG
 //#define DEBUG_LOCKS
 
+#include <linux/mutex.h>
 #include <linux/pagemap.h>
 #include <linux/buffer_head.h>
 #include <linux/hpfs_fs.h>
@@ -57,8 +58,8 @@
 	unsigned i_ea_uid : 1;	/* file's uid is stored in ea */
 	unsigned i_ea_gid : 1;	/* file's gid is stored in ea */
 	unsigned i_dirty : 1;
-	struct semaphore i_sem;
-	struct semaphore i_parent;
+	struct mutex i_mutex;
+	struct mutex i_parent_mutex;
 	loff_t **i_rddir_off;
 	struct inode vfs_inode;
 };
diff -urN oldtree/fs/hpfs/inode.c newtree/fs/hpfs/inode.c
--- oldtree/fs/hpfs/inode.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/hpfs/inode.c	2006-02-21 15:58:36.556589112 +0000
@@ -61,14 +61,14 @@
 	if (hpfs_sb(i->i_sb)->sb_eas) {
 		if ((ea = hpfs_get_ea(i->i_sb, fnode, "UID", &ea_size))) {
 			if (ea_size == 2) {
-				i->i_uid = le16_to_cpu(*(u16*)ea);
+				i->i_uid = le16_to_cpu(*(__le16*)ea);
 				hpfs_inode->i_ea_uid = 1;
 			}
 			kfree(ea);
 		}
 		if ((ea = hpfs_get_ea(i->i_sb, fnode, "GID", &ea_size))) {
 			if (ea_size == 2) {
-				i->i_gid = le16_to_cpu(*(u16*)ea);
+				i->i_gid = le16_to_cpu(*(__le16*)ea);
 				hpfs_inode->i_ea_gid = 1;
 			}
 			kfree(ea);
@@ -88,7 +88,7 @@
 			int rdev = 0;
 			umode_t mode = hpfs_sb(sb)->sb_mode;
 			if (ea_size == 2) {
-				mode = le16_to_cpu(*(u16*)ea);
+				mode = le16_to_cpu(*(__le16*)ea);
 				hpfs_inode->i_ea_mode = 1;
 			}
 			kfree(ea);
@@ -96,7 +96,7 @@
 			if (S_ISBLK(mode) || S_ISCHR(mode)) {
 				if ((ea = hpfs_get_ea(i->i_sb, fnode, "DEV", &ea_size))) {
 					if (ea_size == 4)
-						rdev = le32_to_cpu(*(u32*)ea);
+						rdev = le32_to_cpu(*(__le32*)ea);
 					kfree(ea);
 				}
 			}
@@ -149,7 +149,7 @@
 		   we'd better not overwrite them
 		hpfs_error(i->i_sb, "fnode %08x has some unknown HPFS386 stuctures", i->i_ino);
 	} else*/ if (hpfs_sb(i->i_sb)->sb_eas >= 2) {
-		u32 ea;
+		__le32 ea;
 		if ((i->i_uid != hpfs_sb(i->i_sb)->sb_uid) || hpfs_inode->i_ea_uid) {
 			ea = cpu_to_le32(i->i_uid);
 			hpfs_set_ea(i, fnode, "UID", (char*)&ea, 2);
@@ -166,6 +166,7 @@
 			  && i->i_mode != ((hpfs_sb(i->i_sb)->sb_mode & ~(S_ISDIR(i->i_mode) ? 0222 : 0333))
 			  | (S_ISDIR(i->i_mode) ? S_IFDIR : S_IFREG))) || hpfs_inode->i_ea_mode) {
 				ea = cpu_to_le32(i->i_mode);
+				/* sick, but legal */
 				hpfs_set_ea(i, fnode, "MODE", (char *)&ea, 2);
 				hpfs_inode->i_ea_mode = 1;
 			}
@@ -186,9 +187,9 @@
 		kfree(hpfs_inode->i_rddir_off);
 		hpfs_inode->i_rddir_off = NULL;
 	}
-	down(&hpfs_inode->i_parent);
+	mutex_lock(&hpfs_inode->i_parent_mutex);
 	if (!i->i_nlink) {
-		up(&hpfs_inode->i_parent);
+		mutex_unlock(&hpfs_inode->i_parent_mutex);
 		return;
 	}
 	parent = iget_locked(i->i_sb, hpfs_inode->i_parent_dir);
@@ -199,14 +200,14 @@
 			hpfs_read_inode(parent);
 			unlock_new_inode(parent);
 		}
-		down(&hpfs_inode->i_sem);
+		mutex_lock(&hpfs_inode->i_mutex);
 		hpfs_write_inode_nolock(i);
-		up(&hpfs_inode->i_sem);
+		mutex_unlock(&hpfs_inode->i_mutex);
 		iput(parent);
 	} else {
 		mark_inode_dirty(i);
 	}
-	up(&hpfs_inode->i_parent);
+	mutex_unlock(&hpfs_inode->i_parent_mutex);
 }
 
 void hpfs_write_inode_nolock(struct inode *i)
diff -urN oldtree/fs/hpfs/namei.c newtree/fs/hpfs/namei.c
--- oldtree/fs/hpfs/namei.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/hpfs/namei.c	2006-02-21 15:58:27.985892056 +0000
@@ -60,7 +60,7 @@
 	if (dee.read_only)
 		result->i_mode &= ~0222;
 
-	down(&hpfs_i(dir)->i_sem);
+	mutex_lock(&hpfs_i(dir)->i_mutex);
 	r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
 	if (r == 1)
 		goto bail3;
@@ -101,11 +101,11 @@
 		hpfs_write_inode_nolock(result);
 	}
 	d_instantiate(dentry, result);
-	up(&hpfs_i(dir)->i_sem);
+	mutex_unlock(&hpfs_i(dir)->i_mutex);
 	unlock_kernel();
 	return 0;
 bail3:
-	up(&hpfs_i(dir)->i_sem);
+	mutex_unlock(&hpfs_i(dir)->i_mutex);
 	iput(result);
 bail2:
 	hpfs_brelse4(&qbh0);
@@ -168,7 +168,7 @@
 	result->i_data.a_ops = &hpfs_aops;
 	hpfs_i(result)->mmu_private = 0;
 
-	down(&hpfs_i(dir)->i_sem);
+	mutex_lock(&hpfs_i(dir)->i_mutex);
 	r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
 	if (r == 1)
 		goto bail2;
@@ -193,12 +193,12 @@
 		hpfs_write_inode_nolock(result);
 	}
 	d_instantiate(dentry, result);
-	up(&hpfs_i(dir)->i_sem);
+	mutex_unlock(&hpfs_i(dir)->i_mutex);
 	unlock_kernel();
 	return 0;
 
 bail2:
-	up(&hpfs_i(dir)->i_sem);
+	mutex_unlock(&hpfs_i(dir)->i_mutex);
 	iput(result);
 bail1:
 	brelse(bh);
@@ -254,7 +254,7 @@
 	result->i_blocks = 1;
 	init_special_inode(result, mode, rdev);
 
-	down(&hpfs_i(dir)->i_sem);
+	mutex_lock(&hpfs_i(dir)->i_mutex);
 	r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
 	if (r == 1)
 		goto bail2;
@@ -271,12 +271,12 @@
 
 	hpfs_write_inode_nolock(result);
 	d_instantiate(dentry, result);
-	up(&hpfs_i(dir)->i_sem);
+	mutex_unlock(&hpfs_i(dir)->i_mutex);
 	brelse(bh);
 	unlock_kernel();
 	return 0;
 bail2:
-	up(&hpfs_i(dir)->i_sem);
+	mutex_unlock(&hpfs_i(dir)->i_mutex);
 	iput(result);
 bail1:
 	brelse(bh);
@@ -333,7 +333,7 @@
 	result->i_op = &page_symlink_inode_operations;
 	result->i_data.a_ops = &hpfs_symlink_aops;
 
-	down(&hpfs_i(dir)->i_sem);
+	mutex_lock(&hpfs_i(dir)->i_mutex);
 	r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
 	if (r == 1)
 		goto bail2;
@@ -352,11 +352,11 @@
 
 	hpfs_write_inode_nolock(result);
 	d_instantiate(dentry, result);
-	up(&hpfs_i(dir)->i_sem);
+	mutex_unlock(&hpfs_i(dir)->i_mutex);
 	unlock_kernel();
 	return 0;
 bail2:
-	up(&hpfs_i(dir)->i_sem);
+	mutex_unlock(&hpfs_i(dir)->i_mutex);
 	iput(result);
 bail1:
 	brelse(bh);
@@ -382,8 +382,8 @@
 	lock_kernel();
 	hpfs_adjust_length((char *)name, &len);
 again:
-	down(&hpfs_i(inode)->i_parent);
-	down(&hpfs_i(dir)->i_sem);
+	mutex_lock(&hpfs_i(inode)->i_parent_mutex);
+	mutex_lock(&hpfs_i(dir)->i_mutex);
 	err = -ENOENT;
 	de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh);
 	if (!de)
@@ -410,8 +410,8 @@
 		if (rep++)
 			break;
 
-		up(&hpfs_i(dir)->i_sem);
-		up(&hpfs_i(inode)->i_parent);
+		mutex_unlock(&hpfs_i(dir)->i_mutex);
+		mutex_unlock(&hpfs_i(inode)->i_parent_mutex);
 		d_drop(dentry);
 		spin_lock(&dentry->d_lock);
 		if (atomic_read(&dentry->d_count) > 1 ||
@@ -442,8 +442,8 @@
 out1:
 	hpfs_brelse4(&qbh);
 out:
-	up(&hpfs_i(dir)->i_sem);
-	up(&hpfs_i(inode)->i_parent);
+	mutex_unlock(&hpfs_i(dir)->i_mutex);
+	mutex_unlock(&hpfs_i(inode)->i_parent_mutex);
 	unlock_kernel();
 	return err;
 }
@@ -463,8 +463,8 @@
 
 	hpfs_adjust_length((char *)name, &len);
 	lock_kernel();
-	down(&hpfs_i(inode)->i_parent);
-	down(&hpfs_i(dir)->i_sem);
+	mutex_lock(&hpfs_i(inode)->i_parent_mutex);
+	mutex_lock(&hpfs_i(dir)->i_mutex);
 	err = -ENOENT;
 	de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh);
 	if (!de)
@@ -502,8 +502,8 @@
 out1:
 	hpfs_brelse4(&qbh);
 out:
-	up(&hpfs_i(dir)->i_sem);
-	up(&hpfs_i(inode)->i_parent);
+	mutex_unlock(&hpfs_i(dir)->i_mutex);
+	mutex_unlock(&hpfs_i(inode)->i_parent_mutex);
 	unlock_kernel();
 	return err;
 }
@@ -565,12 +565,12 @@
 
 	lock_kernel();
 	/* order doesn't matter, due to VFS exclusion */
-	down(&hpfs_i(i)->i_parent);
+	mutex_lock(&hpfs_i(i)->i_parent_mutex);
 	if (new_inode)
-		down(&hpfs_i(new_inode)->i_parent);
-	down(&hpfs_i(old_dir)->i_sem);
+		mutex_lock(&hpfs_i(new_inode)->i_parent_mutex);
+	mutex_lock(&hpfs_i(old_dir)->i_mutex);
 	if (new_dir != old_dir)
-		down(&hpfs_i(new_dir)->i_sem);
+		mutex_lock(&hpfs_i(new_dir)->i_mutex);
 	
 	/* Erm? Moving over the empty non-busy directory is perfectly legal */
 	if (new_inode && S_ISDIR(new_inode->i_mode)) {
@@ -650,11 +650,11 @@
 	hpfs_decide_conv(i, (char *)new_name, new_len);
 end1:
 	if (old_dir != new_dir)
-		up(&hpfs_i(new_dir)->i_sem);
-	up(&hpfs_i(old_dir)->i_sem);
-	up(&hpfs_i(i)->i_parent);
+		mutex_unlock(&hpfs_i(new_dir)->i_mutex);
+	mutex_unlock(&hpfs_i(old_dir)->i_mutex);
+	mutex_unlock(&hpfs_i(i)->i_parent_mutex);
 	if (new_inode)
-		up(&hpfs_i(new_inode)->i_parent);
+		mutex_unlock(&hpfs_i(new_inode)->i_parent_mutex);
 	unlock_kernel();
 	return err;
 }
diff -urN oldtree/fs/hpfs/super.c newtree/fs/hpfs/super.c
--- oldtree/fs/hpfs/super.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/hpfs/super.c	2006-02-21 15:58:27.986891904 +0000
@@ -181,8 +181,8 @@
 
 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
 	    SLAB_CTOR_CONSTRUCTOR) {
-		init_MUTEX(&ei->i_sem);
-		init_MUTEX(&ei->i_parent);
+		mutex_init(&ei->i_mutex);
+		mutex_init(&ei->i_parent_mutex);
 		inode_init_once(&ei->vfs_inode);
 	}
 }
diff -urN oldtree/fs/hppfs/hppfs_kern.c newtree/fs/hppfs/hppfs_kern.c
--- oldtree/fs/hppfs/hppfs_kern.c	2006-02-19 11:41:05.118564960 +0000
+++ newtree/fs/hppfs/hppfs_kern.c	2006-02-21 15:58:36.558588808 +0000
@@ -216,10 +216,10 @@
 static struct inode_operations hppfs_file_iops = {
 };
 
-static ssize_t read_proc(struct file *file, char *buf, ssize_t count,
+static ssize_t read_proc(struct file *file, char __user *buf, ssize_t count,
 			 loff_t *ppos, int is_user)
 {
-	ssize_t (*read)(struct file *, char *, size_t, loff_t *);
+	ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
 	ssize_t n;
 
 	read = file->f_dentry->d_inode->i_fop->read;
@@ -236,7 +236,7 @@
 	return n;
 }
 
-static ssize_t hppfs_read_file(int fd, char *buf, ssize_t count)
+static ssize_t hppfs_read_file(int fd, char __user *buf, ssize_t count)
 {
 	ssize_t n;
 	int cur, err;
@@ -274,7 +274,7 @@
 	return n;
 }
 
-static ssize_t hppfs_read(struct file *file, char *buf, size_t count,
+static ssize_t hppfs_read(struct file *file, char __user *buf, size_t count,
 			  loff_t *ppos)
 {
 	struct hppfs_private *hppfs = file->private_data;
@@ -313,12 +313,12 @@
 	return(count);
 }
 
-static ssize_t hppfs_write(struct file *file, const char *buf, size_t len,
+static ssize_t hppfs_write(struct file *file, const char __user *buf, size_t len,
 			   loff_t *ppos)
 {
 	struct hppfs_private *data = file->private_data;
 	struct file *proc_file = data->proc_file;
-	ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
+	ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
 	int err;
 
 	write = proc_file->f_dentry->d_inode->i_fop->write;
@@ -658,7 +658,7 @@
 	.statfs		= hppfs_statfs,
 };
 
-static int hppfs_readlink(struct dentry *dentry, char *buffer, int buflen)
+static int hppfs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
 {
 	struct file *proc_file;
 	struct dentry *proc_dentry;
diff -urN oldtree/fs/inode.c newtree/fs/inode.c
--- oldtree/fs/inode.c	2006-02-19 11:41:05.120564656 +0000
+++ newtree/fs/inode.c	2006-02-21 15:58:25.866214296 +0000
@@ -84,14 +84,14 @@
 DEFINE_SPINLOCK(inode_lock);
 
 /*
- * iprune_sem provides exclusion between the kswapd or try_to_free_pages
+ * iprune_mutex provides exclusion between the kswapd or try_to_free_pages
  * icache shrinking path, and the umount path.  Without this exclusion,
  * by the time prune_icache calls iput for the inode whose pages it has
  * been invalidating, or by the time it calls clear_inode & destroy_inode
  * from its final dispose_list, the struct super_block they refer to
  * (for inode->i_sb->s_op) may already have been freed and reused.
  */
-DECLARE_MUTEX(iprune_sem);
+DEFINE_MUTEX(iprune_mutex);
 
 /*
  * Statistics gathering..
@@ -206,7 +206,7 @@
 	i_size_ordered_init(inode);
 #ifdef CONFIG_INOTIFY
 	INIT_LIST_HEAD(&inode->inotify_watches);
-	sema_init(&inode->inotify_sem, 1);
+	mutex_init(&inode->inotify_mutex);
 #endif
 }
 
@@ -319,7 +319,7 @@
 		/*
 		 * We can reschedule here without worrying about the list's
 		 * consistency because the per-sb list of inodes must not
-		 * change during umount anymore, and because iprune_sem keeps
+		 * change during umount anymore, and because iprune_mutex keeps
 		 * shrink_icache_memory() away.
 		 */
 		cond_resched_lock(&inode_lock);
@@ -355,14 +355,14 @@
 	int busy;
 	LIST_HEAD(throw_away);
 
-	down(&iprune_sem);
+	mutex_lock(&iprune_mutex);
 	spin_lock(&inode_lock);
 	inotify_unmount_inodes(&sb->s_inodes);
 	busy = invalidate_list(&sb->s_inodes, &throw_away);
 	spin_unlock(&inode_lock);
 
 	dispose_list(&throw_away);
-	up(&iprune_sem);
+	mutex_unlock(&iprune_mutex);
 
 	return busy;
 }
@@ -377,7 +377,7 @@
 	if (sb) {
 		/*
 		 * no need to lock the super, get_super holds the
-		 * read semaphore so the filesystem cannot go away
+		 * read mutex so the filesystem cannot go away
 		 * under us (->put_super runs with the write lock
 		 * hold).
 		 */
@@ -423,7 +423,7 @@
 	int nr_scanned;
 	unsigned long reap = 0;
 
-	down(&iprune_sem);
+	mutex_lock(&iprune_mutex);
 	spin_lock(&inode_lock);
 	for (nr_scanned = 0; nr_scanned < nr_to_scan; nr_scanned++) {
 		struct inode *inode;
@@ -459,7 +459,7 @@
 	spin_unlock(&inode_lock);
 
 	dispose_list(&freeable);
-	up(&iprune_sem);
+	mutex_unlock(&iprune_mutex);
 
 	if (current_is_kswapd())
 		mod_page_state(kswapd_inodesteal, reap);
diff -urN oldtree/fs/inotify.c newtree/fs/inotify.c
--- oldtree/fs/inotify.c	2006-02-19 11:41:05.121564504 +0000
+++ newtree/fs/inotify.c	2006-02-21 15:58:25.867214144 +0000
@@ -54,10 +54,10 @@
  * Lock ordering:
  *
  * dentry->d_lock (used to keep d_move() away from dentry->d_parent)
- * iprune_sem (synchronize shrink_icache_memory())
+ * iprune_mutex (synchronize shrink_icache_memory())
  * 	inode_lock (protects the super_block->s_inodes list)
- * 	inode->inotify_sem (protects inode->inotify_watches and watches->i_list)
- * 		inotify_dev->sem (protects inotify_device and watches->d_list)
+ * 	inode->inotify_mutex (protects inode->inotify_watches and watches->i_list)
+ * 		inotify_dev->mutex (protects inotify_device and watches->d_list)
  */
 
 /*
@@ -79,20 +79,24 @@
 /*
  * struct inotify_device - represents an inotify instance
  *
- * This structure is protected by the semaphore 'sem'.
+ * This structure is protected by the mutex 'mutex'.
  */
 struct inotify_device {
 	wait_queue_head_t 	wq;		/* wait queue for i/o */
 	struct idr		idr;		/* idr mapping wd -> watch */
-	struct semaphore	sem;		/* protects this bad boy */
-	struct list_head 	events;		/* list of queued events */
+	struct mutex		mutex;		/* protects this bad boy */
 	struct list_head	watches;	/* list of watches */
 	atomic_t		count;		/* reference count */
+	u32			last_wd;	/* the last wd allocated */
+	/* userland consumer API */
+	struct list_head 	events;		/* list of queued events */
 	struct user_struct	*user;		/* user who opened this dev */
 	unsigned int		queue_size;	/* size of the queue (bytes) */
 	unsigned int		event_count;	/* number of pending events */
 	unsigned int		max_events;	/* maximum number of events */
-	u32			last_wd;	/* the last wd allocated */
+	/* kernel consumer API */
+	void (*callback)(struct inotify_event *, const char *, struct inode *,
+			 void *);		/* event callback */
 };
 
 /*
@@ -101,7 +105,7 @@
  * device.  In read(), this list is walked and all events that can fit in the
  * buffer are returned.
  *
- * Protected by dev->sem of the device in which we are queued.
+ * Protected by dev->mutex of the device in which we are queued.
  */
 struct inotify_kernel_event {
 	struct inotify_event	event;	/* the user-space event */
@@ -112,8 +116,8 @@
 /*
  * struct inotify_watch - represents a watch request on a specific inode
  *
- * d_list is protected by dev->sem of the associated watch->dev.
- * i_list and mask are protected by inode->inotify_sem of the associated inode.
+ * d_list is protected by dev->mutex of the associated watch->dev.
+ * i_list and mask are protected by inode->inotify_mutex of the associated inode.
  * dev, inode, and wd are never written to once the watch is created.
  */
 struct inotify_watch {
@@ -124,6 +128,7 @@
 	struct inode		*inode;	/* associated inode */
 	s32 			wd;	/* watch descriptor */
 	u32			mask;	/* event mask for this watch */
+	void		*callback_arg;	/* callback argument - kernel API */
 };
 
 #ifdef CONFIG_SYSCTL
@@ -175,8 +180,10 @@
 static inline void put_inotify_dev(struct inotify_device *dev)
 {
 	if (atomic_dec_and_test(&dev->count)) {
-		atomic_dec(&dev->user->inotify_devs);
-		free_uid(dev->user);
+		if (dev->user) {
+			atomic_dec(&dev->user->inotify_devs);
+			free_uid(dev->user);
+		}
 		idr_destroy(&dev->idr);
 		kfree(dev);
 	}
@@ -261,7 +268,7 @@
 /*
  * inotify_dev_get_event - return the next event in the given dev's queue
  *
- * Caller must hold dev->sem.
+ * Caller must hold dev->mutex.
  */
 static inline struct inotify_kernel_event *
 inotify_dev_get_event(struct inotify_device *dev)
@@ -272,7 +279,7 @@
 /*
  * inotify_dev_queue_event - add a new event to the given device
  *
- * Caller must hold dev->sem.  Can sleep (calls kernel_event()).
+ * Caller must hold dev->mutex.  Can sleep (calls kernel_event()).
  */
 static void inotify_dev_queue_event(struct inotify_device *dev,
 				    struct inotify_watch *watch, u32 mask,
@@ -315,7 +322,7 @@
 /*
  * remove_kevent - cleans up and ultimately frees the given kevent
  *
- * Caller must hold dev->sem.
+ * Caller must hold dev->mutex.
  */
 static void remove_kevent(struct inotify_device *dev,
 			  struct inotify_kernel_event *kevent)
@@ -332,7 +339,7 @@
 /*
  * inotify_dev_event_dequeue - destroy an event on the given device
  *
- * Caller must hold dev->sem.
+ * Caller must hold dev->mutex.
  */
 static void inotify_dev_event_dequeue(struct inotify_device *dev)
 {
@@ -344,9 +351,27 @@
 }
 
 /*
+ * inotify_callback_event - notify kernel consumers of events
+ */
+static void inotify_callback_event(struct inotify_device *dev,
+				   struct inotify_watch *watch,
+				   u32 mask, u32 cookie, const char *name,
+				   struct inode *inode)
+{
+	struct inotify_event event;
+
+	event.wd = watch->wd;
+	event.mask = mask;
+	event.cookie = cookie;
+	event.len = 0; /* kernel consumers don't need length */
+
+	dev->callback(&event, name, inode, watch->callback_arg);
+}
+
+/*
  * inotify_dev_get_wd - returns the next WD for use by the given dev
  *
- * Callers must hold dev->sem.  This function can sleep.
+ * Callers must hold dev->mutex.  This function can sleep.
  */
 static int inotify_dev_get_wd(struct inotify_device *dev,
 			      struct inotify_watch *watch)
@@ -383,16 +408,17 @@
 /*
  * create_watch - creates a watch on the given device.
  *
- * Callers must hold dev->sem.  Calls inotify_dev_get_wd() so may sleep.
+ * Callers must hold dev->mutex.  Calls inotify_dev_get_wd() so may sleep.
  * Both 'dev' and 'inode' (by way of nameidata) need to be pinned.
  */
 static struct inotify_watch *create_watch(struct inotify_device *dev,
-					  u32 mask, struct inode *inode)
+					  u32 mask, struct inode *inode,
+					  void *callback_arg)
 {
 	struct inotify_watch *watch;
 	int ret;
 
-	if (atomic_read(&dev->user->inotify_watches) >=
+	if (dev->user && atomic_read(&dev->user->inotify_watches) >=
 			inotify_max_user_watches)
 		return ERR_PTR(-ENOSPC);
 
@@ -408,6 +434,7 @@
 
 	dev->last_wd = watch->wd;
 	watch->mask = mask;
+	watch->callback_arg = callback_arg;
 	atomic_set(&watch->count, 0);
 	INIT_LIST_HEAD(&watch->d_list);
 	INIT_LIST_HEAD(&watch->i_list);
@@ -425,7 +452,8 @@
 	/* bump our own count, corresponding to our entry in dev->watches */
 	get_inotify_watch(watch);
 
-	atomic_inc(&dev->user->inotify_watches);
+	if (dev->user)
+		atomic_inc(&dev->user->inotify_watches);
 	atomic_inc(&inotify_watches);
 
 	return watch;
@@ -434,7 +462,7 @@
 /*
  * inotify_find_dev - find the watch associated with the given inode and dev
  *
- * Callers must hold inode->inotify_sem.
+ * Callers must hold inode->inotify_mutex.
  */
 static struct inotify_watch *inode_find_dev(struct inode *inode,
 					    struct inotify_device *dev)
@@ -458,7 +486,8 @@
 	list_del(&watch->i_list);
 	list_del(&watch->d_list);
 
-	atomic_dec(&dev->user->inotify_watches);
+	if (dev->user)
+		atomic_dec(&dev->user->inotify_watches);
 	atomic_dec(&inotify_watches);
 	idr_remove(&dev->idr, watch->wd);
 	put_inotify_watch(watch);
@@ -469,7 +498,7 @@
  * the IN_IGNORED event to the given device signifying that the inode is no
  * longer watched.
  *
- * Callers must hold both inode->inotify_sem and dev->sem.  We drop a
+ * Callers must hold both inode->inotify_mutex and dev->mutex.  We drop a
  * reference to the inode before returning.
  *
  * The inode is not iput() so as to remain atomic.  If the inode needs to be
@@ -477,7 +506,10 @@
  */
 static void remove_watch(struct inotify_watch *watch,struct inotify_device *dev)
 {
-	inotify_dev_queue_event(dev, watch, IN_IGNORED, 0, NULL);
+	if (dev->callback)
+		inotify_callback_event(dev, watch, IN_IGNORED, 0, NULL, NULL);
+	else
+		inotify_dev_queue_event(dev, watch, IN_IGNORED, 0, NULL);
 	remove_watch_no_event(watch, dev);
 }
 
@@ -490,7 +522,190 @@
 	return !list_empty(&inode->inotify_watches);
 }
 
-/* Kernel API */
+/* Kernel consumer API */
+
+/**
+ * inotify_init - allocates and initializes an inotify device
+ * @callback: kernel consumer's event callback
+ */
+struct inotify_device *inotify_init(void (*callback)(struct inotify_event *,
+						     const char *,
+						     struct inode *, void *))
+{
+	struct inotify_device *dev;
+
+	dev = kmalloc(sizeof(struct inotify_device), GFP_KERNEL);
+	if (unlikely(!dev))
+		return NULL;
+
+	idr_init(&dev->idr);
+	INIT_LIST_HEAD(&dev->events);
+	INIT_LIST_HEAD(&dev->watches);
+	init_waitqueue_head(&dev->wq);
+	mutex_init(&dev->mutex);
+	dev->event_count = 0;
+	dev->queue_size = 0;
+	dev->max_events = inotify_max_queued_events;
+	dev->user = NULL;	/* set in sys_inotify_init */
+	dev->last_wd = 0;
+	dev->callback = callback;
+	atomic_set(&dev->count, 0);
+	get_inotify_dev(dev);
+
+	return dev;
+}
+EXPORT_SYMBOL_GPL(inotify_init);
+
+/**
+ * inotify_free - clean up and free an inotify device
+ * @dev: inotify device to free
+ */
+int inotify_free(struct inotify_device *dev)
+{
+	/*
+	 * Destroy all of the watches on this device.  Unfortunately, not very
+	 * pretty.  We cannot do a simple iteration over the list, because we
+	 * do not know the inode until we iterate to the watch.  But we need to
+	 * hold inode->inotify_mutex before dev->mutex.  The following works.
+	 */
+	while (1) {
+		struct inotify_watch *watch;
+		struct list_head *watches;
+		struct inode *inode;
+
+		mutex_lock(&dev->mutex);
+		watches = &dev->watches;
+		if (list_empty(watches)) {
+			mutex_unlock(&dev->mutex);
+			break;
+		}
+		watch = list_entry(watches->next, struct inotify_watch, d_list);
+		get_inotify_watch(watch);
+		mutex_unlock(&dev->mutex);
+
+		inode = watch->inode;
+		mutex_lock(&inode->inotify_mutex);
+		mutex_lock(&dev->mutex);
+		remove_watch_no_event(watch, dev);
+		mutex_unlock(&dev->mutex);
+		mutex_unlock(&inode->inotify_mutex);
+		put_inotify_watch(watch);
+	}
+
+	/* destroy all of the events on this device */
+	mutex_lock(&dev->mutex);
+	while (!list_empty(&dev->events))
+		inotify_dev_event_dequeue(dev);
+	mutex_unlock(&dev->mutex);
+
+	/* free this device: the put matching the get in inotify_init() */
+	put_inotify_dev(dev);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(inotify_free);
+
+/**
+ * inotify_inotify_add_watch - add a watch to this inotify device
+ * @dev: inotify device
+ * @inode: inode to watch for events
+ * @mask: filesystem event mask
+ * @callback_arg - ptr to data that kernel consumer associates with this watch
+ *
+ * Caller must pin the inode in question, e.g. by calling path_lookup.
+ */
+s32 inotify_add_watch(struct inotify_device *dev, struct inode *inode,
+		      u32 mask, void *callback_arg)
+{
+	int mask_add = 0;
+	struct inotify_watch *watch, *old;
+	int ret;
+
+	mutex_lock(&inode->inotify_mutex);
+	mutex_lock(&dev->mutex);
+
+	if (mask & IN_MASK_ADD)
+		mask_add = 1;
+
+	/* don't let user-space set invalid bits: we don't want flags set */
+	mask &= IN_ALL_EVENTS | IN_ONESHOT;
+	if (unlikely(!mask)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/*
+	 * Handle the case of re-adding a watch on an (inode,dev) pair that we
+	 * are already watching.  We just update the mask and callback_arg and
+	 * return its wd.
+	 */
+	old = inode_find_dev(inode, dev);
+	if (unlikely(old)) {
+		if (mask_add)
+			old->mask |= mask;
+		else
+			old->mask = mask;
+		old->callback_arg = callback_arg;
+		ret = old->wd;
+		goto out;
+	}
+
+	watch = create_watch(dev, mask, inode, callback_arg);
+	if (unlikely(IS_ERR(watch))) {
+		ret = PTR_ERR(watch);
+		goto out;
+	}
+
+	/* Add the watch to the device's and the inode's list */
+	list_add(&watch->d_list, &dev->watches);
+	list_add(&watch->i_list, &inode->inotify_watches);
+	ret = watch->wd;
+
+out:
+	mutex_unlock(&dev->mutex);
+	mutex_unlock(&inode->inotify_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(inotify_add_watch);
+
+/**
+ * inotify_ignore - remove a given wd from this inotify device
+ * @dev: inotify device
+ * @wd: watch descriptor to remove
+ */
+int inotify_ignore(struct inotify_device *dev, s32 wd)
+{
+	struct inotify_watch *watch;
+	struct inode *inode;
+
+	mutex_lock(&dev->mutex);
+	watch = idr_find(&dev->idr, wd);
+	if (unlikely(!watch)) {
+		mutex_unlock(&dev->mutex);
+		return -EINVAL;
+	}
+	get_inotify_watch(watch);
+	inode = watch->inode;
+	mutex_unlock(&dev->mutex);
+
+	mutex_lock(&inode->inotify_mutex);
+	mutex_lock(&dev->mutex);
+
+	/* make sure that we did not race */
+	watch = idr_find(&dev->idr, wd);
+	if (likely(watch))
+		remove_watch(watch, dev);
+
+	mutex_unlock(&dev->mutex);
+	mutex_unlock(&inode->inotify_mutex);
+	put_inotify_watch(watch);
+
+	return 0;
+
+}
+EXPORT_SYMBOL_GPL(inotify_ignore);
+
+/* Kernel producer API */
 
 /**
  * inotify_inode_queue_event - queue an event to all watches on this inode
@@ -498,30 +713,36 @@
  * @mask: event mask describing this event
  * @cookie: cookie for synchronization, or zero
  * @name: filename, if any
+ * @cinode: child inode, used for events on directories
  */
 void inotify_inode_queue_event(struct inode *inode, u32 mask, u32 cookie,
-			       const char *name)
+			       const char *name, struct inode *cinode)
 {
 	struct inotify_watch *watch, *next;
 
 	if (!inotify_inode_watched(inode))
 		return;
 
-	down(&inode->inotify_sem);
+	mutex_lock(&inode->inotify_mutex);
 	list_for_each_entry_safe(watch, next, &inode->inotify_watches, i_list) {
 		u32 watch_mask = watch->mask;
 		if (watch_mask & mask) {
 			struct inotify_device *dev = watch->dev;
 			get_inotify_watch(watch);
-			down(&dev->sem);
-			inotify_dev_queue_event(dev, watch, mask, cookie, name);
+			mutex_lock(&dev->mutex);
+			if (dev->callback)
+				inotify_callback_event(dev, watch, mask,
+						       cookie, name, cinode);
+			else
+				inotify_dev_queue_event(dev, watch, mask,
+							cookie, name);
 			if (watch_mask & IN_ONESHOT)
 				remove_watch_no_event(watch, dev);
-			up(&dev->sem);
+			mutex_unlock(&dev->mutex);
 			put_inotify_watch(watch);
 		}
 	}
-	up(&inode->inotify_sem);
+	mutex_unlock(&inode->inotify_mutex);
 }
 EXPORT_SYMBOL_GPL(inotify_inode_queue_event);
 
@@ -548,7 +769,8 @@
 	if (inotify_inode_watched(inode)) {
 		dget(parent);
 		spin_unlock(&dentry->d_lock);
-		inotify_inode_queue_event(inode, mask, cookie, name);
+		inotify_inode_queue_event(inode, mask, cookie, name,
+					  dentry->d_inode);
 		dput(parent);
 	} else
 		spin_unlock(&dentry->d_lock);
@@ -569,7 +791,7 @@
  * @list: list of inodes being unmounted (sb->s_inodes)
  *
  * Called with inode_lock held, protecting the unmounting super block's list
- * of inodes, and with iprune_sem held, keeping shrink_icache_memory() at bay.
+ * of inodes, and with iprune_mutex held, keeping shrink_icache_memory() at bay.
  * We temporarily drop inode_lock, however, and CAN block.
  */
 void inotify_unmount_inodes(struct list_head *list)
@@ -618,7 +840,7 @@
 		 * We can safely drop inode_lock here because we hold
 		 * references on both inode and next_i.  Also no new inodes
 		 * will be added since the umount has begun.  Finally,
-		 * iprune_sem keeps shrink_icache_memory() away.
+		 * iprune_mutex keeps shrink_icache_memory() away.
 		 */
 		spin_unlock(&inode_lock);
 
@@ -626,16 +848,21 @@
 			iput(need_iput_tmp);
 
 		/* for each watch, send IN_UNMOUNT and then remove it */
-		down(&inode->inotify_sem);
+		mutex_lock(&inode->inotify_mutex);
 		watches = &inode->inotify_watches;
 		list_for_each_entry_safe(watch, next_w, watches, i_list) {
 			struct inotify_device *dev = watch->dev;
-			down(&dev->sem);
-			inotify_dev_queue_event(dev, watch, IN_UNMOUNT,0,NULL);
+			mutex_lock(&dev->mutex);
+			if (dev->callback)
+				inotify_callback_event(dev, watch, IN_UNMOUNT,
+						       0, NULL, NULL);
+			else
+				inotify_dev_queue_event(dev, watch, IN_UNMOUNT,
+							0, NULL);
 			remove_watch(watch, dev);
-			up(&dev->sem);
+			mutex_unlock(&dev->mutex);
 		}
-		up(&inode->inotify_sem);
+		mutex_unlock(&inode->inotify_mutex);
 		iput(inode);		
 
 		spin_lock(&inode_lock);
@@ -651,14 +878,14 @@
 {
 	struct inotify_watch *watch, *next;
 
-	down(&inode->inotify_sem);
+	mutex_lock(&inode->inotify_mutex);
 	list_for_each_entry_safe(watch, next, &inode->inotify_watches, i_list) {
 		struct inotify_device *dev = watch->dev;
-		down(&dev->sem);
+		mutex_lock(&dev->mutex);
 		remove_watch(watch, dev);
-		up(&dev->sem);
+		mutex_unlock(&dev->mutex);
 	}
-	up(&inode->inotify_sem);
+	mutex_unlock(&inode->inotify_mutex);
 }
 EXPORT_SYMBOL_GPL(inotify_inode_is_dead);
 
@@ -670,10 +897,10 @@
 	int ret = 0;
 
 	poll_wait(file, &dev->wq, wait);
-	down(&dev->sem);
+	mutex_lock(&dev->mutex);
 	if (!list_empty(&dev->events))
 		ret = POLLIN | POLLRDNORM;
-	up(&dev->sem);
+	mutex_unlock(&dev->mutex);
 
 	return ret;
 }
@@ -695,9 +922,9 @@
 
 		prepare_to_wait(&dev->wq, &wait, TASK_INTERRUPTIBLE);
 
-		down(&dev->sem);
+		mutex_lock(&dev->mutex);
 		events = !list_empty(&dev->events);
-		up(&dev->sem);
+		mutex_unlock(&dev->mutex);
 		if (events) {
 			ret = 0;
 			break;
@@ -720,7 +947,7 @@
 	if (ret)
 		return ret;
 
-	down(&dev->sem);
+	mutex_lock(&dev->mutex);
 	while (1) {
 		struct inotify_kernel_event *kevent;
 
@@ -750,90 +977,14 @@
 
 		remove_kevent(dev, kevent);
 	}
-	up(&dev->sem);
+	mutex_unlock(&dev->mutex);
 
 	return ret;
 }
 
 static int inotify_release(struct inode *ignored, struct file *file)
 {
-	struct inotify_device *dev = file->private_data;
-
-	/*
-	 * Destroy all of the watches on this device.  Unfortunately, not very
-	 * pretty.  We cannot do a simple iteration over the list, because we
-	 * do not know the inode until we iterate to the watch.  But we need to
-	 * hold inode->inotify_sem before dev->sem.  The following works.
-	 */
-	while (1) {
-		struct inotify_watch *watch;
-		struct list_head *watches;
-		struct inode *inode;
-
-		down(&dev->sem);
-		watches = &dev->watches;
-		if (list_empty(watches)) {
-			up(&dev->sem);
-			break;
-		}
-		watch = list_entry(watches->next, struct inotify_watch, d_list);
-		get_inotify_watch(watch);
-		up(&dev->sem);
-
-		inode = watch->inode;
-		down(&inode->inotify_sem);
-		down(&dev->sem);
-		remove_watch_no_event(watch, dev);
-		up(&dev->sem);
-		up(&inode->inotify_sem);
-		put_inotify_watch(watch);
-	}
-
-	/* destroy all of the events on this device */
-	down(&dev->sem);
-	while (!list_empty(&dev->events))
-		inotify_dev_event_dequeue(dev);
-	up(&dev->sem);
-
-	/* free this device: the put matching the get in inotify_init() */
-	put_inotify_dev(dev);
-
-	return 0;
-}
-
-/*
- * inotify_ignore - remove a given wd from this inotify instance.
- *
- * Can sleep.
- */
-static int inotify_ignore(struct inotify_device *dev, s32 wd)
-{
-	struct inotify_watch *watch;
-	struct inode *inode;
-
-	down(&dev->sem);
-	watch = idr_find(&dev->idr, wd);
-	if (unlikely(!watch)) {
-		up(&dev->sem);
-		return -EINVAL;
-	}
-	get_inotify_watch(watch);
-	inode = watch->inode;
-	up(&dev->sem);
-
-	down(&inode->inotify_sem);
-	down(&dev->sem);
-
-	/* make sure that we did not race */
-	watch = idr_find(&dev->idr, wd);
-	if (likely(watch))
-		remove_watch(watch, dev);
-
-	up(&dev->sem);
-	up(&inode->inotify_sem);
-	put_inotify_watch(watch);
-
-	return 0;
+	return inotify_free(file->private_data);
 }
 
 static long inotify_ioctl(struct file *file, unsigned int cmd,
@@ -887,12 +1038,15 @@
 		goto out_free_uid;
 	}
 
-	dev = kmalloc(sizeof(struct inotify_device), GFP_KERNEL);
+	dev = inotify_init(NULL);
 	if (unlikely(!dev)) {
 		ret = -ENOMEM;
 		goto out_free_uid;
 	}
 
+	dev->user = user;
+	atomic_inc(&user->inotify_devs);
+
 	filp->f_op = &inotify_fops;
 	filp->f_vfsmnt = mntget(inotify_mnt);
 	filp->f_dentry = dget(inotify_mnt->mnt_root);
@@ -901,20 +1055,6 @@
 	filp->f_flags = O_RDONLY;
 	filp->private_data = dev;
 
-	idr_init(&dev->idr);
-	INIT_LIST_HEAD(&dev->events);
-	INIT_LIST_HEAD(&dev->watches);
-	init_waitqueue_head(&dev->wq);
-	sema_init(&dev->sem, 1);
-	dev->event_count = 0;
-	dev->queue_size = 0;
-	dev->max_events = inotify_max_queued_events;
-	dev->user = user;
-	dev->last_wd = 0;
-	atomic_set(&dev->count, 0);
-
-	get_inotify_dev(dev);
-	atomic_inc(&user->inotify_devs);
 	fd_install(fd, filp);
 
 	return fd;
@@ -928,13 +1068,11 @@
 
 asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask)
 {
-	struct inotify_watch *watch, *old;
 	struct inode *inode;
 	struct inotify_device *dev;
 	struct nameidata nd;
 	struct file *filp;
 	int ret, fput_needed;
-	int mask_add = 0;
 	unsigned flags = 0;
 
 	filp = fget_light(fd, &fput_needed);
@@ -960,46 +1098,7 @@
 	inode = nd.dentry->d_inode;
 	dev = filp->private_data;
 
-	down(&inode->inotify_sem);
-	down(&dev->sem);
-
-	if (mask & IN_MASK_ADD)
-		mask_add = 1;
-
-	/* don't let user-space set invalid bits: we don't want flags set */
-	mask &= IN_ALL_EVENTS | IN_ONESHOT;
-	if (unlikely(!mask)) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	/*
-	 * Handle the case of re-adding a watch on an (inode,dev) pair that we
-	 * are already watching.  We just update the mask and return its wd.
-	 */
-	old = inode_find_dev(inode, dev);
-	if (unlikely(old)) {
-		if (mask_add)
-			old->mask |= mask;
-		else
-			old->mask = mask;
-		ret = old->wd;
-		goto out;
-	}
-
-	watch = create_watch(dev, mask, inode);
-	if (unlikely(IS_ERR(watch))) {
-		ret = PTR_ERR(watch);
-		goto out;
-	}
-
-	/* Add the watch to the device's and the inode's list */
-	list_add(&watch->d_list, &dev->watches);
-	list_add(&watch->i_list, &inode->inotify_watches);
-	ret = watch->wd;
-out:
-	up(&dev->sem);
-	up(&inode->inotify_sem);
+	ret = inotify_add_watch(dev, inode, mask, NULL);
 	path_release(&nd);
 fput_and_out:
 	fput_light(filp, fput_needed);
diff -urN oldtree/fs/isofs/joliet.c newtree/fs/isofs/joliet.c
--- oldtree/fs/isofs/joliet.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/isofs/joliet.c	2006-02-21 15:58:36.558588808 +0000
@@ -14,9 +14,9 @@
  * Convert Unicode 16 to UTF8 or ASCII.
  */
 static int
-uni16_to_x8(unsigned char *ascii, u16 *uni, int len, struct nls_table *nls)
+uni16_to_x8(unsigned char *ascii, __be16 *uni, int len, struct nls_table *nls)
 {
-	wchar_t *ip, ch;
+	__be16 *ip, ch;
 	unsigned char *op;
 
 	ip = uni;
@@ -24,8 +24,8 @@
 
 	while ((ch = get_unaligned(ip)) && len) {
 		int llen;
-		ch = be16_to_cpu(ch);
-		if ((llen = nls->uni2char(ch, op, NLS_MAX_CHARSET_SIZE)) > 0)
+		llen = nls->uni2char(be16_to_cpu(ch), op, NLS_MAX_CHARSET_SIZE);
+		if (llen > 0)
 			op += llen;
 		else
 			*op++ = '?';
@@ -82,7 +82,7 @@
 		len = wcsntombs_be(outname, de->name,
 				   de->name_len[0] >> 1, PAGE_SIZE);
 	} else {
-		len = uni16_to_x8(outname, (u16 *) de->name,
+		len = uni16_to_x8(outname, (__be16 *) de->name,
 				  de->name_len[0] >> 1, nls);
 	}
 	if ((len > 2) && (outname[len-2] == ';') && (outname[len-1] == '1')) {
diff -urN oldtree/fs/jbd/checkpoint.c newtree/fs/jbd/checkpoint.c
--- oldtree/fs/jbd/checkpoint.c	2006-02-19 11:41:05.122564352 +0000
+++ newtree/fs/jbd/checkpoint.c	2006-02-21 15:58:25.943202592 +0000
@@ -85,7 +85,7 @@
 		if (journal->j_flags & JFS_ABORT)
 			return;
 		spin_unlock(&journal->j_state_lock);
-		down(&journal->j_checkpoint_sem);
+		mutex_lock(&journal->j_checkpoint_mutex);
 
 		/*
 		 * Test again, another process may have checkpointed while we
@@ -98,7 +98,7 @@
 			log_do_checkpoint(journal);
 			spin_lock(&journal->j_state_lock);
 		}
-		up(&journal->j_checkpoint_sem);
+		mutex_unlock(&journal->j_checkpoint_mutex);
 	}
 }
 
diff -urN oldtree/fs/jbd/journal.c newtree/fs/jbd/journal.c
--- oldtree/fs/jbd/journal.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/jbd/journal.c	2006-02-21 15:58:25.945202288 +0000
@@ -659,8 +659,8 @@
 	init_waitqueue_head(&journal->j_wait_checkpoint);
 	init_waitqueue_head(&journal->j_wait_commit);
 	init_waitqueue_head(&journal->j_wait_updates);
-	init_MUTEX(&journal->j_barrier);
-	init_MUTEX(&journal->j_checkpoint_sem);
+	mutex_init(&journal->j_barrier);
+	mutex_init(&journal->j_checkpoint_mutex);
 	spin_lock_init(&journal->j_revoke_lock);
 	spin_lock_init(&journal->j_list_lock);
 	spin_lock_init(&journal->j_state_lock);
diff -urN oldtree/fs/jbd/transaction.c newtree/fs/jbd/transaction.c
--- oldtree/fs/jbd/transaction.c	2006-02-19 11:41:05.123564200 +0000
+++ newtree/fs/jbd/transaction.c	2006-02-21 15:58:25.947201984 +0000
@@ -455,7 +455,7 @@
 	 * to make sure that we serialise special journal-locked operations
 	 * too.
 	 */
-	down(&journal->j_barrier);
+	mutex_lock(&journal->j_barrier);
 }
 
 /**
@@ -470,7 +470,7 @@
 {
 	J_ASSERT(journal->j_barrier_count != 0);
 
-	up(&journal->j_barrier);
+	mutex_unlock(&journal->j_barrier);
 	spin_lock(&journal->j_state_lock);
 	--journal->j_barrier_count;
 	spin_unlock(&journal->j_state_lock);
diff -urN oldtree/fs/jffs/inode-v23.c newtree/fs/jffs/inode-v23.c
--- oldtree/fs/jffs/inode-v23.c	2006-02-19 11:41:05.124564048 +0000
+++ newtree/fs/jffs/inode-v23.c	2006-02-21 15:58:27.018039192 +0000
@@ -42,7 +42,7 @@
 #include <linux/quotaops.h>
 #include <linux/highmem.h>
 #include <linux/vfs.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
 
@@ -203,7 +203,7 @@
 	fmc = c->fmc;
 
 	D3(printk (KERN_NOTICE "notify_change(): down biglock\n"));
-	down(&fmc->biglock);
+	mutex_lock(&fmc->biglock);
 
 	f = jffs_find_file(c, inode->i_ino);
 
@@ -211,7 +211,7 @@
 		printk("jffs_setattr(): Invalid inode number: %lu\n",
 		       inode->i_ino);
 		D3(printk (KERN_NOTICE "notify_change(): up biglock\n"));
-		up(&fmc->biglock);
+		mutex_unlock(&fmc->biglock);
 		res = -EINVAL;
 		goto out;
 	});
@@ -232,7 +232,7 @@
 	if (!(new_node = jffs_alloc_node())) {
 		D(printk("jffs_setattr(): Allocation failed!\n"));
 		D3(printk (KERN_NOTICE "notify_change(): up biglock\n"));
-		up(&fmc->biglock);
+		mutex_unlock(&fmc->biglock);
 		res = -ENOMEM;
 		goto out;
 	}
@@ -319,7 +319,7 @@
 		D(printk("jffs_notify_change(): The write failed!\n"));
 		jffs_free_node(new_node);
 		D3(printk (KERN_NOTICE "n_c(): up biglock\n"));
-		up(&c->fmc->biglock);
+		mutex_unlock(&c->fmc->biglock);
 		goto out;
 	}
 
@@ -327,7 +327,7 @@
 
 	mark_inode_dirty(inode);
 	D3(printk (KERN_NOTICE "n_c(): up biglock\n"));
-	up(&c->fmc->biglock);
+	mutex_unlock(&c->fmc->biglock);
 out:
 	unlock_kernel();
 	return res;
@@ -461,7 +461,7 @@
 		goto jffs_rename_end;
 	}
 	D3(printk (KERN_NOTICE "rename(): down biglock\n"));
-	down(&c->fmc->biglock);
+	mutex_lock(&c->fmc->biglock);
 	/* Create a node and initialize as much as needed.  */
 	result = -ENOMEM;
 	if (!(node = jffs_alloc_node())) {
@@ -555,7 +555,7 @@
 
 jffs_rename_end:
 	D3(printk (KERN_NOTICE "rename(): up biglock\n"));
-	up(&c->fmc->biglock);
+	mutex_unlock(&c->fmc->biglock);
 	unlock_kernel();
 	return result;
 } /* jffs_rename()  */
@@ -574,14 +574,14 @@
 	int ddino;
 	lock_kernel();
 	D3(printk (KERN_NOTICE "readdir(): down biglock\n"));
-	down(&c->fmc->biglock);
+	mutex_lock(&c->fmc->biglock);
 
 	D2(printk("jffs_readdir(): inode: 0x%p, filp: 0x%p\n", inode, filp));
 	if (filp->f_pos == 0) {
 		D3(printk("jffs_readdir(): \".\" %lu\n", inode->i_ino));
 		if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0) {
 			D3(printk (KERN_NOTICE "readdir(): up biglock\n"));
-			up(&c->fmc->biglock);
+			mutex_unlock(&c->fmc->biglock);
 			unlock_kernel();
 			return 0;
 		}
@@ -598,7 +598,7 @@
 		D3(printk("jffs_readdir(): \"..\" %u\n", ddino));
 		if (filldir(dirent, "..", 2, filp->f_pos, ddino, DT_DIR) < 0) {
 			D3(printk (KERN_NOTICE "readdir(): up biglock\n"));
-			up(&c->fmc->biglock);
+			mutex_unlock(&c->fmc->biglock);
 			unlock_kernel();
 			return 0;
 		}
@@ -617,7 +617,7 @@
 		if (filldir(dirent, f->name, f->nsize,
 			    filp->f_pos , f->ino, DT_UNKNOWN) < 0) {
 		        D3(printk (KERN_NOTICE "readdir(): up biglock\n"));
-			up(&c->fmc->biglock);
+			mutex_unlock(&c->fmc->biglock);
 			unlock_kernel();
 			return 0;
 		}
@@ -627,7 +627,7 @@
 		} while(f && f->deleted);
 	}
 	D3(printk (KERN_NOTICE "readdir(): up biglock\n"));
-	up(&c->fmc->biglock);
+	mutex_unlock(&c->fmc->biglock);
 	unlock_kernel();
 	return filp->f_pos;
 } /* jffs_readdir()  */
@@ -660,7 +660,7 @@
 	});
 
 	D3(printk (KERN_NOTICE "lookup(): down biglock\n"));
-	down(&c->fmc->biglock);
+	mutex_lock(&c->fmc->biglock);
 
 	r = -ENAMETOOLONG;
 	if (len > JFFS_MAX_NAME_LEN) {
@@ -683,31 +683,31 @@
 
 	if ((len == 1) && (name[0] == '.')) {
 		D3(printk (KERN_NOTICE "lookup(): up biglock\n"));
-		up(&c->fmc->biglock);
+		mutex_unlock(&c->fmc->biglock);
 		if (!(inode = iget(dir->i_sb, d->ino))) {
 			D(printk("jffs_lookup(): . iget() ==> NULL\n"));
 			goto jffs_lookup_end_no_biglock;
 		}
 		D3(printk (KERN_NOTICE "lookup(): down biglock\n"));
-		down(&c->fmc->biglock);
+		mutex_lock(&c->fmc->biglock);
 	} else if ((len == 2) && (name[0] == '.') && (name[1] == '.')) {
 	        D3(printk (KERN_NOTICE "lookup(): up biglock\n"));
-		up(&c->fmc->biglock);
+		mutex_unlock(&c->fmc->biglock);
  		if (!(inode = iget(dir->i_sb, d->pino))) {
 			D(printk("jffs_lookup(): .. iget() ==> NULL\n"));
 			goto jffs_lookup_end_no_biglock;
 		}
 		D3(printk (KERN_NOTICE "lookup(): down biglock\n"));
-		down(&c->fmc->biglock);
+		mutex_lock(&c->fmc->biglock);
 	} else if ((f = jffs_find_child(d, name, len))) {
 	        D3(printk (KERN_NOTICE "lookup(): up biglock\n"));
-		up(&c->fmc->biglock);
+		mutex_unlock(&c->fmc->biglock);
 		if (!(inode = iget(dir->i_sb, f->ino))) {
 			D(printk("jffs_lookup(): iget() ==> NULL\n"));
 			goto jffs_lookup_end_no_biglock;
 		}
 		D3(printk (KERN_NOTICE "lookup(): down biglock\n"));
-		down(&c->fmc->biglock);
+		mutex_lock(&c->fmc->biglock);
 	} else {
 		D3(printk("jffs_lookup(): Couldn't find the file. "
 			  "f = 0x%p, name = \"%s\", d = 0x%p, d->ino = %u\n",
@@ -717,13 +717,13 @@
 
 	d_add(dentry, inode);
 	D3(printk (KERN_NOTICE "lookup(): up biglock\n"));
-	up(&c->fmc->biglock);
+	mutex_unlock(&c->fmc->biglock);
 	unlock_kernel();
 	return NULL;
 
 jffs_lookup_end:
 	D3(printk (KERN_NOTICE "lookup(): up biglock\n"));
-	up(&c->fmc->biglock);
+	mutex_unlock(&c->fmc->biglock);
 
 jffs_lookup_end_no_biglock:
 	unlock_kernel();
@@ -753,7 +753,7 @@
 	ClearPageError(page);
 
 	D3(printk (KERN_NOTICE "readpage(): down biglock\n"));
-	down(&c->fmc->biglock);
+	mutex_lock(&c->fmc->biglock);
 
 	read_len = 0;
 	result = 0;
@@ -782,7 +782,7 @@
 	kunmap(page);
 
 	D3(printk (KERN_NOTICE "readpage(): up biglock\n"));
-	up(&c->fmc->biglock);
+	mutex_unlock(&c->fmc->biglock);
 
 	if (result) {
 	        SetPageError(page);
@@ -839,7 +839,7 @@
 
 	c = dir_f->c;
 	D3(printk (KERN_NOTICE "mkdir(): down biglock\n"));
-	down(&c->fmc->biglock);
+	mutex_lock(&c->fmc->biglock);
 
 	dir_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX)
 			      & ~current->fs->umask);
@@ -906,7 +906,7 @@
 	result = 0;
 jffs_mkdir_end:
 	D3(printk (KERN_NOTICE "mkdir(): up biglock\n"));
-	up(&c->fmc->biglock);
+	mutex_unlock(&c->fmc->biglock);
 	unlock_kernel();
 	return result;
 } /* jffs_mkdir()  */
@@ -921,10 +921,10 @@
 	D3(printk("***jffs_rmdir()\n"));
 	D3(printk (KERN_NOTICE "rmdir(): down biglock\n"));
 	lock_kernel();
-	down(&c->fmc->biglock);
+	mutex_lock(&c->fmc->biglock);
 	ret = jffs_remove(dir, dentry, S_IFDIR);
 	D3(printk (KERN_NOTICE "rmdir(): up biglock\n"));
-	up(&c->fmc->biglock);
+	mutex_unlock(&c->fmc->biglock);
 	unlock_kernel();
 	return ret;
 }
@@ -940,10 +940,10 @@
 	lock_kernel();
 	D3(printk("***jffs_unlink()\n"));
 	D3(printk (KERN_NOTICE "unlink(): down biglock\n"));
-	down(&c->fmc->biglock);
+	mutex_lock(&c->fmc->biglock);
 	ret = jffs_remove(dir, dentry, 0);
 	D3(printk (KERN_NOTICE "unlink(): up biglock\n"));
-	up(&c->fmc->biglock);
+	mutex_unlock(&c->fmc->biglock);
 	unlock_kernel();
 	return ret;
 }
@@ -1086,7 +1086,7 @@
 	c = dir_f->c;
 
 	D3(printk (KERN_NOTICE "mknod(): down biglock\n"));
-	down(&c->fmc->biglock);
+	mutex_lock(&c->fmc->biglock);
 
 	/* Create and initialize a new node.  */
 	if (!(node = jffs_alloc_node())) {
@@ -1152,7 +1152,7 @@
 
 jffs_mknod_end:
 	D3(printk (KERN_NOTICE "mknod(): up biglock\n"));
-	up(&c->fmc->biglock);
+	mutex_unlock(&c->fmc->biglock);
 	unlock_kernel();
 	return result;
 } /* jffs_mknod()  */
@@ -1203,7 +1203,7 @@
 		return -ENOMEM;
 	}
 	D3(printk (KERN_NOTICE "symlink(): down biglock\n"));
-	down(&c->fmc->biglock);
+	mutex_lock(&c->fmc->biglock);
 
 	node->data_offset = 0;
 	node->removed_size = 0;
@@ -1253,7 +1253,7 @@
 	d_instantiate(dentry, inode);
  jffs_symlink_end:
 	D3(printk (KERN_NOTICE "symlink(): up biglock\n"));
-	up(&c->fmc->biglock);
+	mutex_unlock(&c->fmc->biglock);
 	unlock_kernel();
 	return err;
 } /* jffs_symlink()  */
@@ -1306,7 +1306,7 @@
 		return -ENOMEM;
 	}
 	D3(printk (KERN_NOTICE "create(): down biglock\n"));
-	down(&c->fmc->biglock);
+	mutex_lock(&c->fmc->biglock);
 
 	node->data_offset = 0;
 	node->removed_size = 0;
@@ -1359,7 +1359,7 @@
 	d_instantiate(dentry, inode);
  jffs_create_end:
 	D3(printk (KERN_NOTICE "create(): up biglock\n"));
-	up(&c->fmc->biglock);
+	mutex_unlock(&c->fmc->biglock);
 	unlock_kernel();
 	return err;
 } /* jffs_create()  */
@@ -1423,7 +1423,7 @@
 	thiscount = min(c->fmc->max_chunk_size - sizeof(struct jffs_raw_inode), count);
 
 	D3(printk (KERN_NOTICE "file_write(): down biglock\n"));
-	down(&c->fmc->biglock);
+	mutex_lock(&c->fmc->biglock);
 
 	/* Urgh. POSIX says we can do short writes if we feel like it. 
 	 * In practice, we can't. Nothing will cope. So we loop until
@@ -1511,7 +1511,7 @@
 	}
  out:
 	D3(printk (KERN_NOTICE "file_write(): up biglock\n"));
-	up(&c->fmc->biglock);
+	mutex_unlock(&c->fmc->biglock);
 
 	/* Fix things in the real inode.  */
 	if (pos > inode->i_size) {
@@ -1567,7 +1567,7 @@
 		return -EIO;
 	}
 	D3(printk (KERN_NOTICE "ioctl(): down biglock\n"));
-	down(&c->fmc->biglock);
+	mutex_lock(&c->fmc->biglock);
 
 	switch (cmd) {
 	case JFFS_PRINT_HASH:
@@ -1609,7 +1609,7 @@
 		ret = -ENOTTY;
 	}
 	D3(printk (KERN_NOTICE "ioctl(): up biglock\n"));
-	up(&c->fmc->biglock);
+	mutex_unlock(&c->fmc->biglock);
 	return ret;
 } /* jffs_ioctl()  */
 
@@ -1685,12 +1685,12 @@
 	}
 	c = (struct jffs_control *)inode->i_sb->s_fs_info;
 	D3(printk (KERN_NOTICE "read_inode(): down biglock\n"));
-	down(&c->fmc->biglock);
+	mutex_lock(&c->fmc->biglock);
 	if (!(f = jffs_find_file(c, inode->i_ino))) {
 		D(printk("jffs_read_inode(): No such inode (%lu).\n",
 			 inode->i_ino));
 		D3(printk (KERN_NOTICE "read_inode(): up biglock\n"));
-		up(&c->fmc->biglock);
+		mutex_unlock(&c->fmc->biglock);
 		return;
 	}
 	inode->u.generic_ip = (void *)f;
@@ -1732,7 +1732,7 @@
 	}
 
 	D3(printk (KERN_NOTICE "read_inode(): up biglock\n"));
-	up(&c->fmc->biglock);
+	mutex_unlock(&c->fmc->biglock);
 }
 
 
diff -urN oldtree/fs/jffs/intrep.c newtree/fs/jffs/intrep.c
--- oldtree/fs/jffs/intrep.c	2006-02-19 11:41:05.126563744 +0000
+++ newtree/fs/jffs/intrep.c	2006-02-21 15:58:27.271000736 +0000
@@ -62,7 +62,7 @@
 #include <linux/fs.h>
 #include <linux/stat.h>
 #include <linux/pagemap.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/byteorder.h>
 #include <linux/smp_lock.h>
 #include <linux/time.h>
@@ -3416,7 +3416,7 @@
 		D1(printk (KERN_NOTICE "jffs_garbage_collect_thread(): collecting.\n"));
 
 		D3(printk (KERN_NOTICE "g_c_thread(): down biglock\n"));
-		down(&fmc->biglock);
+		mutex_lock(&fmc->biglock);
 		
 		D1(printk("***jffs_garbage_collect_thread(): round #%u, "
 			  "fmc->dirty_size = %u\n", i++, fmc->dirty_size));
@@ -3447,6 +3447,6 @@
 		
 	gc_end:
 		D3(printk (KERN_NOTICE "g_c_thread(): up biglock\n"));
-		up(&fmc->biglock);
+		mutex_unlock(&fmc->biglock);
 	} /* for (;;) */
 } /* jffs_garbage_collect_thread() */
diff -urN oldtree/fs/jffs/jffs_fm.c newtree/fs/jffs/jffs_fm.c
--- oldtree/fs/jffs/jffs_fm.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/jffs/jffs_fm.c	2006-02-21 15:58:27.272000584 +0000
@@ -139,7 +139,7 @@
 	fmc->tail = NULL;
 	fmc->head_extra = NULL;
 	fmc->tail_extra = NULL;
-	init_MUTEX(&fmc->biglock);
+	mutex_init(&fmc->biglock);
 	return fmc;
 }
 
diff -urN oldtree/fs/jffs/jffs_fm.h newtree/fs/jffs/jffs_fm.h
--- oldtree/fs/jffs/jffs_fm.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/jffs/jffs_fm.h	2006-02-21 15:58:27.273000432 +0000
@@ -20,10 +20,11 @@
 #ifndef __LINUX_JFFS_FM_H__
 #define __LINUX_JFFS_FM_H__
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/jffs.h>
 #include <linux/mtd/mtd.h>
-#include <linux/config.h>
+#include <linux/mutex.h>
 
 /* The alignment between two nodes in the flash memory.  */
 #define JFFS_ALIGN_SIZE 4
@@ -97,7 +98,7 @@
 	struct jffs_fm *tail;
 	struct jffs_fm *head_extra;
 	struct jffs_fm *tail_extra;
-	struct semaphore biglock;
+	struct mutex biglock;
 };
 
 /* Notice the two members head_extra and tail_extra in the jffs_control
diff -urN oldtree/fs/jffs2/compr_zlib.c newtree/fs/jffs2/compr_zlib.c
--- oldtree/fs/jffs2/compr_zlib.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/jffs2/compr_zlib.c	2006-02-21 15:58:23.886515256 +0000
@@ -33,13 +33,14 @@
 	*/
 #define STREAM_END_SPACE 12
 
-static DECLARE_MUTEX(deflate_sem);
-static DECLARE_MUTEX(inflate_sem);
+static DEFINE_MUTEX(deflate_mutex);
+static DEFINE_MUTEX(inflate_mutex);
 static z_stream inf_strm, def_strm;
 
 #ifdef __KERNEL__ /* Linux-only */
 #include <linux/vmalloc.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
 
 static int __init alloc_workspaces(void)
 {
@@ -79,11 +80,11 @@
 	if (*dstlen <= STREAM_END_SPACE)
 		return -1;
 
-	down(&deflate_sem);
+	mutex_lock(&deflate_mutex);
 
 	if (Z_OK != zlib_deflateInit(&def_strm, 3)) {
 		printk(KERN_WARNING "deflateInit failed\n");
-		up(&deflate_sem);
+		mutex_unlock(&deflate_mutex);
 		return -1;
 	}
 
@@ -104,7 +105,7 @@
 		if (ret != Z_OK) {
 			D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret));
 			zlib_deflateEnd(&def_strm);
-			up(&deflate_sem);
+			mutex_unlock(&deflate_mutex);
 			return -1;
 		}
 	}
@@ -133,7 +134,7 @@
 	*sourcelen = def_strm.total_in;
 	ret = 0;
  out:
-	up(&deflate_sem);
+	mutex_unlock(&deflate_mutex);
 	return ret;
 }
 
@@ -145,7 +146,7 @@
 	int ret;
 	int wbits = MAX_WBITS;
 
-	down(&inflate_sem);
+	mutex_lock(&inflate_mutex);
 
 	inf_strm.next_in = data_in;
 	inf_strm.avail_in = srclen;
@@ -173,7 +174,7 @@
 
 	if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) {
 		printk(KERN_WARNING "inflateInit failed\n");
-		up(&inflate_sem);
+		mutex_unlock(&inflate_mutex);
 		return 1;
 	}
 
@@ -183,7 +184,7 @@
 		printk(KERN_NOTICE "inflate returned %d\n", ret);
 	}
 	zlib_inflateEnd(&inf_strm);
-	up(&inflate_sem);
+	mutex_unlock(&inflate_mutex);
         return 0;
 }
 
diff -urN oldtree/fs/jfs/jfs_logmgr.c newtree/fs/jfs/jfs_logmgr.c
--- oldtree/fs/jfs/jfs_logmgr.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/jfs/jfs_logmgr.c	2006-02-21 15:58:23.896513736 +0000
@@ -68,6 +68,7 @@
 #include <linux/bio.h>
 #include <linux/suspend.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
 #include "jfs_incore.h"
 #include "jfs_filsys.h"
 #include "jfs_metapage.h"
@@ -165,7 +166,7 @@
  */
 static LIST_HEAD(jfs_external_logs);
 static struct jfs_log *dummy_log = NULL;
-static DECLARE_MUTEX(jfs_log_sem);
+static DEFINE_MUTEX(jfs_log_mutex);
 
 /*
  * forward references
@@ -1085,20 +1086,20 @@
 	if (sbi->mntflag & JFS_INLINELOG)
 		return open_inline_log(sb);
 
-	down(&jfs_log_sem);
+	mutex_lock(&jfs_log_mutex);
 	list_for_each_entry(log, &jfs_external_logs, journal_list) {
 		if (log->bdev->bd_dev == sbi->logdev) {
 			if (memcmp(log->uuid, sbi->loguuid,
 				   sizeof(log->uuid))) {
 				jfs_warn("wrong uuid on JFS journal\n");
-				up(&jfs_log_sem);
+				mutex_unlock(&jfs_log_mutex);
 				return -EINVAL;
 			}
 			/*
 			 * add file system to log active file system list
 			 */
 			if ((rc = lmLogFileSystem(log, sbi, 1))) {
-				up(&jfs_log_sem);
+				mutex_unlock(&jfs_log_mutex);
 				return rc;
 			}
 			goto journal_found;
@@ -1106,7 +1107,7 @@
 	}
 
 	if (!(log = kmalloc(sizeof(struct jfs_log), GFP_KERNEL))) {
-		up(&jfs_log_sem);
+		mutex_unlock(&jfs_log_mutex);
 		return -ENOMEM;
 	}
 	memset(log, 0, sizeof(struct jfs_log));
@@ -1152,7 +1153,7 @@
 	sbi->log = log;
 	LOG_UNLOCK(log);
 
-	up(&jfs_log_sem);
+	mutex_unlock(&jfs_log_mutex);
 	return 0;
 
 	/*
@@ -1169,7 +1170,7 @@
 	blkdev_put(bdev);
 
       free:		/* free log descriptor */
-	up(&jfs_log_sem);
+	mutex_unlock(&jfs_log_mutex);
 	kfree(log);
 
 	jfs_warn("lmLogOpen: exit(%d)", rc);
@@ -1214,11 +1215,11 @@
 {
 	int rc;
 
-	down(&jfs_log_sem);
+	mutex_lock(&jfs_log_mutex);
 	if (!dummy_log) {
 		dummy_log = kmalloc(sizeof(struct jfs_log), GFP_KERNEL);
 		if (!dummy_log) {
-			up(&jfs_log_sem);
+			mutex_unlock(&jfs_log_mutex);
 			return -ENOMEM;
 		}
 		memset(dummy_log, 0, sizeof(struct jfs_log));
@@ -1232,7 +1233,7 @@
 		if (rc) {
 			kfree(dummy_log);
 			dummy_log = NULL;
-			up(&jfs_log_sem);
+			mutex_unlock(&jfs_log_mutex);
 			return rc;
 		}
 	}
@@ -1241,7 +1242,7 @@
 	list_add(&JFS_SBI(sb)->log_list, &dummy_log->sb_list);
 	JFS_SBI(sb)->log = dummy_log;
 	LOG_UNLOCK(dummy_log);
-	up(&jfs_log_sem);
+	mutex_unlock(&jfs_log_mutex);
 
 	return 0;
 }
@@ -1469,7 +1470,7 @@
 
 	jfs_info("lmLogClose: log:0x%p", log);
 
-	down(&jfs_log_sem);
+	mutex_lock(&jfs_log_mutex);
 	LOG_LOCK(log);
 	list_del(&sbi->log_list);
 	LOG_UNLOCK(log);
@@ -1519,7 +1520,7 @@
 	kfree(log);
 
       out:
-	up(&jfs_log_sem);
+	mutex_unlock(&jfs_log_mutex);
 	jfs_info("lmLogClose: exit(%d)", rc);
 	return rc;
 }
diff -urN oldtree/fs/jfs/jfs_metapage.c newtree/fs/jfs/jfs_metapage.c
--- oldtree/fs/jfs/jfs_metapage.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/jfs/jfs_metapage.c	2006-02-21 15:58:30.948441680 +0000
@@ -221,8 +221,8 @@
 	if (metapage_cache == NULL)
 		return -ENOMEM;
 
-	metapage_mempool = mempool_create(METAPOOL_MIN_PAGES, mempool_alloc_slab,
-					  mempool_free_slab, metapage_cache);
+	metapage_mempool = mempool_create_slab_pool(METAPOOL_MIN_PAGES,
+						    metapage_cache);
 
 	if (metapage_mempool == NULL) {
 		kmem_cache_destroy(metapage_cache);
diff -urN oldtree/fs/libfs.c newtree/fs/libfs.c
--- oldtree/fs/libfs.c	2006-02-19 11:41:05.137562072 +0000
+++ newtree/fs/libfs.c	2006-02-21 15:58:26.145171888 +0000
@@ -7,6 +7,8 @@
 #include <linux/pagemap.h>
 #include <linux/mount.h>
 #include <linux/vfs.h>
+#include <linux/mutex.h>
+
 #include <asm/uaccess.h>
 
 int simple_getattr(struct vfsmount *mnt, struct dentry *dentry,
@@ -530,7 +532,7 @@
 	char set_buf[24];
 	void *data;
 	const char *fmt;	/* format for read operation */
-	struct semaphore sem;	/* protects access to these buffers */
+	struct mutex mutex;	/* protects access to these buffers */
 };
 
 /* simple_attr_open is called by an actual attribute open file operation
@@ -549,7 +551,7 @@
 	attr->set = set;
 	attr->data = inode->u.generic_ip;
 	attr->fmt = fmt;
-	init_MUTEX(&attr->sem);
+	mutex_init(&attr->mutex);
 
 	file->private_data = attr;
 
@@ -575,7 +577,7 @@
 	if (!attr->get)
 		return -EACCES;
 
-	down(&attr->sem);
+	mutex_lock(&attr->mutex);
 	if (*ppos) /* continued read */
 		size = strlen(attr->get_buf);
 	else	  /* first read */
@@ -584,7 +586,7 @@
 				 (unsigned long long)attr->get(attr->data));
 
 	ret = simple_read_from_buffer(buf, len, ppos, attr->get_buf, size);
-	up(&attr->sem);
+	mutex_unlock(&attr->mutex);
 	return ret;
 }
 
@@ -602,7 +604,7 @@
 	if (!attr->set)
 		return -EACCES;
 
-	down(&attr->sem);
+	mutex_lock(&attr->mutex);
 	ret = -EFAULT;
 	size = min(sizeof(attr->set_buf) - 1, len);
 	if (copy_from_user(attr->set_buf, buf, size))
@@ -613,7 +615,7 @@
 	val = simple_strtol(attr->set_buf, NULL, 0);
 	attr->set(attr->data, val);
 out:
-	up(&attr->sem);
+	mutex_unlock(&attr->mutex);
 	return ret;
 }
 
diff -urN oldtree/fs/lockd/clntlock.c newtree/fs/lockd/clntlock.c
--- oldtree/fs/lockd/clntlock.c	2006-02-19 11:41:05.137562072 +0000
+++ newtree/fs/lockd/clntlock.c	2006-02-21 15:58:36.563588048 +0000
@@ -111,12 +111,12 @@
 /*
  * The server lockd has called us back to tell us the lock was granted
  */
-u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
+__be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
 {
 	const struct file_lock *fl = &lock->fl;
 	const struct nfs_fh *fh = &lock->fh;
 	struct nlm_wait	*block;
-	u32 res = nlm_lck_denied;
+	__be32 res = nlm_lck_denied;
 
 	/*
 	 * Look up blocked request based on arguments. 
diff -urN oldtree/fs/lockd/host.c newtree/fs/lockd/host.c
--- oldtree/fs/lockd/host.c	2006-02-19 11:41:05.139561768 +0000
+++ newtree/fs/lockd/host.c	2006-02-21 15:58:23.903512672 +0000
@@ -16,6 +16,7 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/lockd/lockd.h>
 #include <linux/lockd/sm_inter.h>
+#include <linux/mutex.h>
 
 
 #define NLMDBG_FACILITY		NLMDBG_HOSTCACHE
@@ -30,7 +31,7 @@
 static struct nlm_host *	nlm_hosts[NLM_HOST_NRHASH];
 static unsigned long		next_gc;
 static int			nrhosts;
-static DECLARE_MUTEX(nlm_host_sema);
+static DEFINE_MUTEX(nlm_host_mutex);
 
 
 static void			nlm_gc_hosts(void);
@@ -71,7 +72,7 @@
 	hash = NLM_ADDRHASH(sin->sin_addr.s_addr);
 
 	/* Lock hash table */
-	down(&nlm_host_sema);
+	mutex_lock(&nlm_host_mutex);
 
 	if (time_after_eq(jiffies, next_gc))
 		nlm_gc_hosts();
@@ -91,7 +92,7 @@
 				nlm_hosts[hash] = host;
 			}
 			nlm_get_host(host);
-			up(&nlm_host_sema);
+			mutex_unlock(&nlm_host_mutex);
 			return host;
 		}
 	}
@@ -128,7 +129,7 @@
 		next_gc = 0;
 
 nohost:
-	up(&nlm_host_sema);
+	mutex_unlock(&nlm_host_mutex);
 	return host;
 }
 
@@ -139,19 +140,19 @@
 	 * and return it
 	 */
 	int hash;
-	down(&nlm_host_sema);
+	mutex_lock(&nlm_host_mutex);
 	for (hash = 0 ; hash < NLM_HOST_NRHASH; hash++) {
 		struct nlm_host *host, **hp;
 		for (hp = &nlm_hosts[hash]; (host = *hp) != 0; hp = &host->h_next) {
 			if (host->h_server &&
 			    host->h_killed == 0) {
 				nlm_get_host(host);
-				up(&nlm_host_sema);
+				mutex_unlock(&nlm_host_mutex);
 				return host;
 			}
 		}
 	}
-	up(&nlm_host_sema);
+	mutex_unlock(&nlm_host_mutex);
 	return NULL;
 }
 
@@ -258,7 +259,7 @@
 	int		i;
 
 	dprintk("lockd: shutting down host module\n");
-	down(&nlm_host_sema);
+	mutex_lock(&nlm_host_mutex);
 
 	/* First, make all hosts eligible for gc */
 	dprintk("lockd: nuking all hosts...\n");
@@ -269,7 +270,7 @@
 
 	/* Then, perform a garbage collection pass */
 	nlm_gc_hosts();
-	up(&nlm_host_sema);
+	mutex_unlock(&nlm_host_mutex);
 
 	/* complain if any hosts are left */
 	if (nrhosts) {
diff -urN oldtree/fs/lockd/mon.c newtree/fs/lockd/mon.c
--- oldtree/fs/lockd/mon.c	2006-02-19 11:41:05.139561768 +0000
+++ newtree/fs/lockd/mon.c	2006-02-21 15:58:36.563588048 +0000
@@ -134,8 +134,8 @@
  * XDR functions for NSM.
  */
 
-static u32 *
-xdr_encode_common(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
+static __be32 *
+xdr_encode_common(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp)
 {
 	char	buffer[20];
 
@@ -157,7 +157,7 @@
 }
 
 static int
-xdr_encode_mon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
+xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp)
 {
 	p = xdr_encode_common(rqstp, p, argp);
 	if (IS_ERR(p))
@@ -171,7 +171,7 @@
 }
 
 static int
-xdr_encode_unmon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
+xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp)
 {
 	p = xdr_encode_common(rqstp, p, argp);
 	if (IS_ERR(p))
@@ -181,7 +181,7 @@
 }
 
 static int
-xdr_decode_stat_res(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp)
+xdr_decode_stat_res(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp)
 {
 	resp->status = ntohl(*p++);
 	resp->state = ntohl(*p++);
@@ -191,7 +191,7 @@
 }
 
 static int
-xdr_decode_stat(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp)
+xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp)
 {
 	resp->state = ntohl(*p++);
 	return 0;
diff -urN oldtree/fs/lockd/svc.c newtree/fs/lockd/svc.c
--- oldtree/fs/lockd/svc.c	2006-02-19 11:41:05.139561768 +0000
+++ newtree/fs/lockd/svc.c	2006-02-21 15:58:23.904512520 +0000
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/stats.h>
@@ -43,13 +44,13 @@
 struct nlmsvc_binding *		nlmsvc_ops;
 EXPORT_SYMBOL(nlmsvc_ops);
 
-static DECLARE_MUTEX(nlmsvc_sema);
+static DEFINE_MUTEX(nlmsvc_mutex);
 static unsigned int		nlmsvc_users;
 static pid_t			nlmsvc_pid;
 int				nlmsvc_grace_period;
 unsigned long			nlmsvc_timeout;
 
-static DECLARE_MUTEX_LOCKED(lockd_start);
+static DECLARE_COMPLETION(lockd_start_done);
 static DECLARE_WAIT_QUEUE_HEAD(lockd_exit);
 
 /*
@@ -112,7 +113,7 @@
 	 * Let our maker know we're running.
 	 */
 	nlmsvc_pid = current->pid;
-	up(&lockd_start);
+	complete(&lockd_start_done);
 
 	daemonize("lockd");
 
@@ -215,7 +216,7 @@
 	struct svc_serv *	serv;
 	int			error = 0;
 
-	down(&nlmsvc_sema);
+	mutex_lock(&nlmsvc_mutex);
 	/*
 	 * Unconditionally increment the user count ... this is
 	 * the number of clients who _want_ a lockd process.
@@ -263,7 +264,7 @@
 			"lockd_up: create thread failed, error=%d\n", error);
 		goto destroy_and_out;
 	}
-	down(&lockd_start);
+	wait_for_completion(&lockd_start_done);
 
 	/*
 	 * Note: svc_serv structures have an initial use count of 1,
@@ -272,7 +273,7 @@
 destroy_and_out:
 	svc_destroy(serv);
 out:
-	up(&nlmsvc_sema);
+	mutex_unlock(&nlmsvc_mutex);
 	return error;
 }
 EXPORT_SYMBOL(lockd_up);
@@ -285,7 +286,7 @@
 {
 	static int warned;
 
-	down(&nlmsvc_sema);
+	mutex_lock(&nlmsvc_mutex);
 	if (nlmsvc_users) {
 		if (--nlmsvc_users)
 			goto out;
@@ -315,7 +316,7 @@
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 out:
-	up(&nlmsvc_sema);
+	mutex_unlock(&nlmsvc_mutex);
 }
 EXPORT_SYMBOL(lockd_down);
 
diff -urN oldtree/fs/lockd/svc4proc.c newtree/fs/lockd/svc4proc.c
--- oldtree/fs/lockd/svc4proc.c	2006-02-19 11:41:05.141561464 +0000
+++ newtree/fs/lockd/svc4proc.c	2006-02-21 15:58:36.566587592 +0000
@@ -21,21 +21,21 @@
 
 #define NLMDBG_FACILITY		NLMDBG_CLIENT
 
-static u32	nlm4svc_callback(struct svc_rqst *, u32, struct nlm_res *);
+static __be32	nlm4svc_callback(struct svc_rqst *, u32, struct nlm_res *);
 
 static const struct rpc_call_ops nlm4svc_callback_ops;
 
 /*
  * Obtain client and file from arguments
  */
-static u32
+static __be32
 nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
 			struct nlm_host **hostp, struct nlm_file **filp)
 {
 	struct nlm_host		*host = NULL;
 	struct nlm_file		*file = NULL;
 	struct nlm_lock		*lock = &argp->lock;
-	u32			error = 0;
+	__be32			error = 0;
 
 	/* nfsd callbacks must have been installed for this procedure */
 	if (!nlmsvc_ops)
@@ -72,7 +72,7 @@
 /*
  * NULL: Test for presence of service
  */
-static int
+static __be32
 nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
 {
 	dprintk("lockd: NULL          called\n");
@@ -82,7 +82,7 @@
 /*
  * TEST: Check for conflicting lock
  */
-static int
+static __be32
 nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
 				         struct nlm_res  *resp)
 {
@@ -111,7 +111,7 @@
 	return rpc_success;
 }
 
-static int
+static __be32
 nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
 				         struct nlm_res  *resp)
 {
@@ -154,7 +154,7 @@
 	return rpc_success;
 }
 
-static int
+static __be32
 nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
 				           struct nlm_res  *resp)
 {
@@ -187,7 +187,7 @@
 /*
  * UNLOCK: release a lock
  */
-static int
+static __be32
 nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
 				           struct nlm_res  *resp)
 {
@@ -221,7 +221,7 @@
  * GRANTED: A server calls us to tell that a process' lock request
  * was granted
  */
-static int
+static __be32
 nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
 				            struct nlm_res  *resp)
 {
@@ -238,12 +238,12 @@
  * because we send the callback before the reply proper. I hope this
  * doesn't break any clients.
  */
-static int
+static __be32
 nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
 					     void	     *resp)
 {
 	struct nlm_res	res;
-	u32		stat;
+	__be32		stat;
 
 	dprintk("lockd: TEST_MSG      called\n");
 	memset(&res, 0, sizeof(res));
@@ -253,12 +253,12 @@
 	return stat;
 }
 
-static int
+static __be32
 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
 					     void	     *resp)
 {
 	struct nlm_res	res;
-	u32		stat;
+	__be32		stat;
 
 	dprintk("lockd: LOCK_MSG      called\n");
 	memset(&res, 0, sizeof(res));
@@ -268,12 +268,12 @@
 	return stat;
 }
 
-static int
+static __be32
 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
 					       void	       *resp)
 {
 	struct nlm_res	res;
-	u32		stat;
+	__be32		stat;
 
 	dprintk("lockd: CANCEL_MSG    called\n");
 	memset(&res, 0, sizeof(res));
@@ -283,12 +283,12 @@
 	return stat;
 }
 
-static int
+static __be32
 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
                                                void            *resp)
 {
 	struct nlm_res	res;
-	u32		stat;
+	__be32		stat;
 
 	dprintk("lockd: UNLOCK_MSG    called\n");
 	memset(&res, 0, sizeof(res));
@@ -298,12 +298,12 @@
 	return stat;
 }
 
-static int
+static __be32
 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
                                                 void            *resp)
 {
 	struct nlm_res	res;
-	u32		stat;
+	__be32		stat;
 
 	dprintk("lockd: GRANTED_MSG   called\n");
 	memset(&res, 0, sizeof(res));
@@ -316,7 +316,7 @@
 /*
  * SHARE: create a DOS share or alter existing share.
  */
-static int
+static __be32
 nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
 				          struct nlm_res  *resp)
 {
@@ -349,7 +349,7 @@
 /*
  * UNSHARE: Release a DOS share.
  */
-static int
+static __be32
 nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
 				            struct nlm_res  *resp)
 {
@@ -382,7 +382,7 @@
 /*
  * NM_LOCK: Create an unmonitored lock
  */
-static int
+static __be32
 nlm4svc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
 				            struct nlm_res  *resp)
 {
@@ -395,7 +395,7 @@
 /*
  * FREE_ALL: Release all locks and shares held by client
  */
-static int
+static __be32
 nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
 					     void            *resp)
 {
@@ -413,7 +413,7 @@
 /*
  * SM_NOTIFY: private callback from statd (not part of official NLM proto)
  */
-static int
+static __be32
 nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
 					      void	        *resp)
 {
@@ -457,7 +457,7 @@
 /*
  * client sent a GRANTED_RES, let's remove the associated block
  */
-static int
+static __be32
 nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res  *argp,
                                                 void            *resp)
 {
@@ -474,7 +474,7 @@
 /*
  * This is the generic lockd callback for async RPC calls
  */
-static u32
+static __be32
 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
 {
 	struct nlm_host	*host;
diff -urN oldtree/fs/lockd/svclock.c newtree/fs/lockd/svclock.c
--- oldtree/fs/lockd/svclock.c	2006-02-19 11:41:05.142561312 +0000
+++ newtree/fs/lockd/svclock.c	2006-02-21 15:58:36.567587440 +0000
@@ -293,7 +293,7 @@
  * Attempt to establish a lock, and if it can't be granted, block it
  * if required.
  */
-u32
+__be32
 nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
 			struct nlm_lock *lock, int wait, struct nlm_cookie *cookie)
 {
@@ -378,7 +378,7 @@
 /*
  * Test for presence of a conflicting lock.
  */
-u32
+__be32
 nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
 				       struct nlm_lock *conflock)
 {
@@ -411,7 +411,7 @@
  * afterwards. In this case the block will still be there, and hence
  * must be removed.
  */
-u32
+__be32
 nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
 {
 	int	error;
@@ -439,7 +439,7 @@
  * be in progress.
  * The calling procedure must check whether the file can be closed.
  */
-u32
+__be32
 nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
 {
 	struct nlm_block	*block;
diff -urN oldtree/fs/lockd/svcproc.c newtree/fs/lockd/svcproc.c
--- oldtree/fs/lockd/svcproc.c	2006-02-19 11:41:05.142561312 +0000
+++ newtree/fs/lockd/svcproc.c	2006-02-21 15:58:36.568587288 +0000
@@ -22,13 +22,13 @@
 
 #define NLMDBG_FACILITY		NLMDBG_CLIENT
 
-static u32	nlmsvc_callback(struct svc_rqst *, u32, struct nlm_res *);
+static __be32	nlmsvc_callback(struct svc_rqst *, u32, struct nlm_res *);
 
 static const struct rpc_call_ops nlmsvc_callback_ops;
 
 #ifdef CONFIG_LOCKD_V4
-static u32
-cast_to_nlm(u32 status, u32 vers)
+static __be32
+cast_to_nlm(__be32 status, u32 vers)
 {
 	/* Note: status is assumed to be in network byte order !!! */
 	if (vers != 4){
@@ -57,14 +57,14 @@
 /*
  * Obtain client and file from arguments
  */
-static u32
+static __be32
 nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
 			struct nlm_host **hostp, struct nlm_file **filp)
 {
 	struct nlm_host		*host = NULL;
 	struct nlm_file		*file = NULL;
 	struct nlm_lock		*lock = &argp->lock;
-	u32			error;
+	__be32			error;
 
 	/* nfsd callbacks must have been installed for this procedure */
 	if (!nlmsvc_ops)
@@ -99,7 +99,7 @@
 /*
  * NULL: Test for presence of service
  */
-static int
+static __be32
 nlmsvc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
 {
 	dprintk("lockd: NULL          called\n");
@@ -109,7 +109,7 @@
 /*
  * TEST: Check for conflicting lock
  */
-static int
+static __be32
 nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
 				         struct nlm_res  *resp)
 {
@@ -139,7 +139,7 @@
 	return rpc_success;
 }
 
-static int
+static __be32
 nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
 				         struct nlm_res  *resp)
 {
@@ -182,7 +182,7 @@
 	return rpc_success;
 }
 
-static int
+static __be32
 nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
 				           struct nlm_res  *resp)
 {
@@ -215,7 +215,7 @@
 /*
  * UNLOCK: release a lock
  */
-static int
+static __be32
 nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
 				           struct nlm_res  *resp)
 {
@@ -249,7 +249,7 @@
  * GRANTED: A server calls us to tell that a process' lock request
  * was granted
  */
-static int
+static __be32
 nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
 				            struct nlm_res  *resp)
 {
@@ -266,12 +266,12 @@
  * because we send the callback before the reply proper. I hope this
  * doesn't break any clients.
  */
-static int
+static __be32
 nlmsvc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
 					     void	     *resp)
 {
 	struct nlm_res	res;
-	u32		stat;
+	__be32		stat;
 
 	dprintk("lockd: TEST_MSG      called\n");
 	memset(&res, 0, sizeof(res));
@@ -281,12 +281,12 @@
 	return stat;
 }
 
-static int
+static __be32
 nlmsvc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
 					     void	     *resp)
 {
 	struct nlm_res	res;
-	u32		stat;
+	__be32		stat;
 
 	dprintk("lockd: LOCK_MSG      called\n");
 	memset(&res, 0, sizeof(res));
@@ -296,12 +296,12 @@
 	return stat;
 }
 
-static int
+static __be32
 nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
 					       void	       *resp)
 {
 	struct nlm_res	res;
-	u32		stat;
+	__be32		stat;
 
 	dprintk("lockd: CANCEL_MSG    called\n");
 	memset(&res, 0, sizeof(res));
@@ -311,12 +311,12 @@
 	return stat;
 }
 
-static int
+static __be32
 nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
                                                void            *resp)
 {
 	struct nlm_res	res;
-	u32		stat;
+	__be32		stat;
 
 	dprintk("lockd: UNLOCK_MSG    called\n");
 	memset(&res, 0, sizeof(res));
@@ -326,12 +326,12 @@
 	return stat;
 }
 
-static int
+static __be32
 nlmsvc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
                                                 void            *resp)
 {
 	struct nlm_res	res;
-	u32		stat;
+	__be32		stat;
 
 	dprintk("lockd: GRANTED_MSG   called\n");
 	memset(&res, 0, sizeof(res));
@@ -344,7 +344,7 @@
 /*
  * SHARE: create a DOS share or alter existing share.
  */
-static int
+static __be32
 nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
 				          struct nlm_res  *resp)
 {
@@ -377,7 +377,7 @@
 /*
  * UNSHARE: Release a DOS share.
  */
-static int
+static __be32
 nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
 				            struct nlm_res  *resp)
 {
@@ -410,7 +410,7 @@
 /*
  * NM_LOCK: Create an unmonitored lock
  */
-static int
+static __be32
 nlmsvc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
 				            struct nlm_res  *resp)
 {
@@ -423,7 +423,7 @@
 /*
  * FREE_ALL: Release all locks and shares held by client
  */
-static int
+static __be32
 nlmsvc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
 					     void            *resp)
 {
@@ -441,7 +441,7 @@
 /*
  * SM_NOTIFY: private callback from statd (not part of official NLM proto)
  */
-static int
+static __be32
 nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
 					      void	        *resp)
 {
@@ -483,7 +483,7 @@
 /*
  * client sent a GRANTED_RES, let's remove the associated block
  */
-static int
+static __be32
 nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res  *argp,
                                                 void            *resp)
 {
@@ -499,7 +499,7 @@
 /*
  * This is the generic lockd callback for async RPC calls
  */
-static u32
+static __be32
 nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
 {
 	struct nlm_host	*host;
diff -urN oldtree/fs/lockd/svcshare.c newtree/fs/lockd/svcshare.c
--- oldtree/fs/lockd/svcshare.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/lockd/svcshare.c	2006-02-21 15:58:36.569587136 +0000
@@ -23,7 +23,7 @@
 	    && !memcmp(share->s_owner.data, oh->data, oh->len);
 }
 
-u32
+__be32
 nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file,
 			struct nlm_args *argp)
 {
@@ -64,7 +64,7 @@
 /*
  * Delete a share.
  */
-u32
+__be32
 nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file,
 			struct nlm_args *argp)
 {
diff -urN oldtree/fs/lockd/svcsubs.c newtree/fs/lockd/svcsubs.c
--- oldtree/fs/lockd/svcsubs.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/lockd/svcsubs.c	2006-02-21 15:58:36.569587136 +0000
@@ -11,6 +11,7 @@
 #include <linux/string.h>
 #include <linux/time.h>
 #include <linux/in.h>
+#include <linux/mutex.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfsd/nfsfh.h>
@@ -28,7 +29,7 @@
 #define FILE_HASH_BITS		5
 #define FILE_NRHASH		(1<<FILE_HASH_BITS)
 static struct nlm_file *	nlm_files[FILE_NRHASH];
-static DECLARE_MUTEX(nlm_file_sema);
+static DEFINE_MUTEX(nlm_file_mutex);
 
 #ifdef NFSD_DEBUG
 static inline void nlm_debug_print_fh(char *msg, struct nfs_fh *f)
@@ -78,20 +79,20 @@
  * This is not quite right, but for now, we assume the client performs
  * the proper R/W checking.
  */
-u32
+__be32
 nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
 					struct nfs_fh *f)
 {
 	struct nlm_file	*file;
 	unsigned int	hash;
-	u32		nfserr;
+	__be32		nfserr;
 
 	nlm_debug_print_fh("nlm_file_lookup", f);
 
 	hash = file_hash(f);
 
 	/* Lock file table */
-	down(&nlm_file_sema);
+	mutex_lock(&nlm_file_mutex);
 
 	for (file = nlm_files[hash]; file; file = file->f_next)
 		if (!nfs_compare_fh(&file->f_handle, f))
@@ -130,7 +131,7 @@
 	nfserr = 0;
 
 out_unlock:
-	up(&nlm_file_sema);
+	mutex_unlock(&nlm_file_mutex);
 	return nfserr;
 
 out_free:
@@ -240,14 +241,14 @@
 	struct nlm_file	*file, **fp;
 	int		i;
 
-	down(&nlm_file_sema);
+	mutex_lock(&nlm_file_mutex);
 	for (i = 0; i < FILE_NRHASH; i++) {
 		fp = nlm_files + i;
 		while ((file = *fp) != NULL) {
 			/* Traverse locks, blocks and shares of this file
 			 * and update file->f_locks count */
 			if (nlm_inspect_file(host, file, action)) {
-				up(&nlm_file_sema);
+				mutex_unlock(&nlm_file_mutex);
 				return 1;
 			}
 
@@ -262,7 +263,7 @@
 			}
 		}
 	}
-	up(&nlm_file_sema);
+	mutex_unlock(&nlm_file_mutex);
 	return 0;
 }
 
@@ -282,7 +283,7 @@
 				file, file->f_count);
 
 	/* Lock file table */
-	down(&nlm_file_sema);
+	mutex_lock(&nlm_file_mutex);
 
 	/* If there are no more locks etc, delete the file */
 	if(--file->f_count == 0) {
@@ -290,7 +291,7 @@
 			nlm_delete_file(file);
 	}
 
-	up(&nlm_file_sema);
+	mutex_unlock(&nlm_file_mutex);
 }
 
 /*
diff -urN oldtree/fs/lockd/xdr.c newtree/fs/lockd/xdr.c
--- oldtree/fs/lockd/xdr.c	2006-02-19 11:41:05.143561160 +0000
+++ newtree/fs/lockd/xdr.c	2006-02-21 15:58:36.571586832 +0000
@@ -44,7 +44,7 @@
 /*
  * XDR functions for basic NLM types
  */
-static u32 *nlm_decode_cookie(u32 *p, struct nlm_cookie *c)
+static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c)
 {
 	unsigned int	len;
 
@@ -70,8 +70,8 @@
 	return p;
 }
 
-static inline u32 *
-nlm_encode_cookie(u32 *p, struct nlm_cookie *c)
+static inline __be32 *
+nlm_encode_cookie(__be32 *p, struct nlm_cookie *c)
 {
 	*p++ = htonl(c->len);
 	memcpy(p, c->data, c->len);
@@ -79,8 +79,8 @@
 	return p;
 }
 
-static u32 *
-nlm_decode_fh(u32 *p, struct nfs_fh *f)
+static __be32 *
+nlm_decode_fh(__be32 *p, struct nfs_fh *f)
 {
 	unsigned int	len;
 
@@ -96,8 +96,8 @@
 	return p + XDR_QUADLEN(NFS2_FHSIZE);
 }
 
-static inline u32 *
-nlm_encode_fh(u32 *p, struct nfs_fh *f)
+static inline __be32 *
+nlm_encode_fh(__be32 *p, struct nfs_fh *f)
 {
 	*p++ = htonl(NFS2_FHSIZE);
 	memcpy(p, f->data, NFS2_FHSIZE);
@@ -107,20 +107,20 @@
 /*
  * Encode and decode owner handle
  */
-static inline u32 *
-nlm_decode_oh(u32 *p, struct xdr_netobj *oh)
+static inline __be32 *
+nlm_decode_oh(__be32 *p, struct xdr_netobj *oh)
 {
 	return xdr_decode_netobj(p, oh);
 }
 
-static inline u32 *
-nlm_encode_oh(u32 *p, struct xdr_netobj *oh)
+static inline __be32 *
+nlm_encode_oh(__be32 *p, struct xdr_netobj *oh)
 {
 	return xdr_encode_netobj(p, oh);
 }
 
-static u32 *
-nlm_decode_lock(u32 *p, struct nlm_lock *lock)
+static __be32 *
+nlm_decode_lock(__be32 *p, struct nlm_lock *lock)
 {
 	struct file_lock	*fl = &lock->fl;
 	s32			start, len, end;
@@ -153,8 +153,8 @@
 /*
  * Encode a lock as part of an NLM call
  */
-static u32 *
-nlm_encode_lock(u32 *p, struct nlm_lock *lock)
+static __be32 *
+nlm_encode_lock(__be32 *p, struct nlm_lock *lock)
 {
 	struct file_lock	*fl = &lock->fl;
 	__s32			start, len;
@@ -184,8 +184,8 @@
 /*
  * Encode result of a TEST/TEST_MSG call
  */
-static u32 *
-nlm_encode_testres(u32 *p, struct nlm_res *resp)
+static __be32 *
+nlm_encode_testres(__be32 *p, struct nlm_res *resp)
 {
 	s32		start, len;
 
@@ -221,7 +221,7 @@
  * First, the server side XDR functions
  */
 int
-nlmsvc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 {
 	u32	exclusive;
 
@@ -238,7 +238,7 @@
 }
 
 int
-nlmsvc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
 {
 	if (!(p = nlm_encode_testres(p, resp)))
 		return 0;
@@ -246,7 +246,7 @@
 }
 
 int
-nlmsvc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 {
 	u32	exclusive;
 
@@ -266,7 +266,7 @@
 }
 
 int
-nlmsvc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 {
 	u32	exclusive;
 
@@ -282,7 +282,7 @@
 }
 
 int
-nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 {
 	if (!(p = nlm_decode_cookie(p, &argp->cookie))
 	 || !(p = nlm_decode_lock(p, &argp->lock)))
@@ -292,7 +292,7 @@
 }
 
 int
-nlmsvc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 {
 	struct nlm_lock	*lock = &argp->lock;
 
@@ -312,7 +312,7 @@
 }
 
 int
-nlmsvc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
 {
 	if (!(p = nlm_encode_cookie(p, &resp->cookie)))
 		return 0;
@@ -322,7 +322,7 @@
 }
 
 int
-nlmsvc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
 {
 	if (!(p = nlm_encode_cookie(p, &resp->cookie)))
 		return 0;
@@ -331,7 +331,7 @@
 }
 
 int
-nlmsvc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp)
+nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp)
 {
 	struct nlm_lock	*lock = &argp->lock;
 
@@ -343,7 +343,7 @@
 }
 
 int
-nlmsvc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp)
+nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
 {
 	if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
 		return 0;
@@ -356,7 +356,7 @@
 }
 
 int
-nlmsvc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
 {
 	if (!(p = nlm_decode_cookie(p, &resp->cookie)))
 		return 0;
@@ -365,13 +365,13 @@
 }
 
 int
-nlmsvc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
+nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
 {
 	return xdr_argsize_check(rqstp, p);
 }
 
 int
-nlmsvc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
+nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
 {
 	return xdr_ressize_check(rqstp, p);
 }
@@ -388,7 +388,7 @@
 #endif
 
 static int
-nlmclt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+nlmclt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
 {
 	struct nlm_lock	*lock = &argp->lock;
 
@@ -402,7 +402,7 @@
 }
 
 static int
-nlmclt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+nlmclt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
 {
 	if (!(p = nlm_decode_cookie(p, &resp->cookie)))
 		return -EIO;
@@ -436,7 +436,7 @@
 
 
 static int
-nlmclt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+nlmclt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
 {
 	struct nlm_lock	*lock = &argp->lock;
 
@@ -453,7 +453,7 @@
 }
 
 static int
-nlmclt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+nlmclt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
 {
 	struct nlm_lock	*lock = &argp->lock;
 
@@ -468,7 +468,7 @@
 }
 
 static int
-nlmclt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+nlmclt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
 {
 	struct nlm_lock	*lock = &argp->lock;
 
@@ -481,7 +481,7 @@
 }
 
 static int
-nlmclt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+nlmclt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
 {
 	if (!(p = nlm_encode_cookie(p, &resp->cookie)))
 		return -EIO;
@@ -491,7 +491,7 @@
 }
 
 static int
-nlmclt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+nlmclt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
 {
 	if (!(p = nlm_encode_testres(p, resp)))
 		return -EIO;
@@ -500,7 +500,7 @@
 }
 
 static int
-nlmclt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+nlmclt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
 {
 	if (!(p = nlm_decode_cookie(p, &resp->cookie)))
 		return -EIO;
diff -urN oldtree/fs/lockd/xdr4.c newtree/fs/lockd/xdr4.c
--- oldtree/fs/lockd/xdr4.c	2006-02-19 11:41:05.144561008 +0000
+++ newtree/fs/lockd/xdr4.c	2006-02-21 15:58:36.570586984 +0000
@@ -44,8 +44,8 @@
 /*
  * XDR functions for basic NLM types
  */
-static u32 *
-nlm4_decode_cookie(u32 *p, struct nlm_cookie *c)
+static __be32 *
+nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c)
 {
 	unsigned int	len;
 
@@ -71,8 +71,8 @@
 	return p;
 }
 
-static u32 *
-nlm4_encode_cookie(u32 *p, struct nlm_cookie *c)
+static __be32 *
+nlm4_encode_cookie(__be32 *p, struct nlm_cookie *c)
 {
 	*p++ = htonl(c->len);
 	memcpy(p, c->data, c->len);
@@ -80,8 +80,8 @@
 	return p;
 }
 
-static u32 *
-nlm4_decode_fh(u32 *p, struct nfs_fh *f)
+static __be32 *
+nlm4_decode_fh(__be32 *p, struct nfs_fh *f)
 {
 	memset(f->data, 0, sizeof(f->data));
 	f->size = ntohl(*p++);
@@ -95,8 +95,8 @@
 	return p + XDR_QUADLEN(f->size);
 }
 
-static u32 *
-nlm4_encode_fh(u32 *p, struct nfs_fh *f)
+static __be32 *
+nlm4_encode_fh(__be32 *p, struct nfs_fh *f)
 {
 	*p++ = htonl(f->size);
 	if (f->size) p[XDR_QUADLEN(f->size)-1] = 0; /* don't leak anything */
@@ -107,20 +107,20 @@
 /*
  * Encode and decode owner handle
  */
-static u32 *
-nlm4_decode_oh(u32 *p, struct xdr_netobj *oh)
+static __be32 *
+nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh)
 {
 	return xdr_decode_netobj(p, oh);
 }
 
-static u32 *
-nlm4_encode_oh(u32 *p, struct xdr_netobj *oh)
+static __be32 *
+nlm4_encode_oh(__be32 *p, struct xdr_netobj *oh)
 {
 	return xdr_encode_netobj(p, oh);
 }
 
-static u32 *
-nlm4_decode_lock(u32 *p, struct nlm_lock *lock)
+static __be32 *
+nlm4_decode_lock(__be32 *p, struct nlm_lock *lock)
 {
 	struct file_lock	*fl = &lock->fl;
 	__s64			len, start, end;
@@ -152,8 +152,8 @@
 /*
  * Encode a lock as part of an NLM call
  */
-static u32 *
-nlm4_encode_lock(u32 *p, struct nlm_lock *lock)
+static __be32 *
+nlm4_encode_lock(__be32 *p, struct nlm_lock *lock)
 {
 	struct file_lock	*fl = &lock->fl;
 	__s64			start, len;
@@ -184,8 +184,8 @@
 /*
  * Encode result of a TEST/TEST_MSG call
  */
-static u32 *
-nlm4_encode_testres(u32 *p, struct nlm_res *resp)
+static __be32 *
+nlm4_encode_testres(__be32 *p, struct nlm_res *resp)
 {
 	s64		start, len;
 
@@ -226,7 +226,7 @@
  * First, the server side XDR functions
  */
 int
-nlm4svc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 {
 	u32	exclusive;
 
@@ -243,7 +243,7 @@
 }
 
 int
-nlm4svc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
 {
 	if (!(p = nlm4_encode_testres(p, resp)))
 		return 0;
@@ -251,7 +251,7 @@
 }
 
 int
-nlm4svc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 {
 	u32	exclusive;
 
@@ -271,7 +271,7 @@
 }
 
 int
-nlm4svc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 {
 	u32	exclusive;
 
@@ -287,7 +287,7 @@
 }
 
 int
-nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 {
 	if (!(p = nlm4_decode_cookie(p, &argp->cookie))
 	 || !(p = nlm4_decode_lock(p, &argp->lock)))
@@ -297,7 +297,7 @@
 }
 
 int
-nlm4svc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 {
 	struct nlm_lock	*lock = &argp->lock;
 
@@ -317,7 +317,7 @@
 }
 
 int
-nlm4svc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
 {
 	if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
 		return 0;
@@ -327,7 +327,7 @@
 }
 
 int
-nlm4svc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
 {
 	if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
 		return 0;
@@ -336,7 +336,7 @@
 }
 
 int
-nlm4svc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp)
+nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp)
 {
 	struct nlm_lock	*lock = &argp->lock;
 
@@ -348,7 +348,7 @@
 }
 
 int
-nlm4svc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp)
+nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
 {
 	if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
 		return 0;
@@ -361,7 +361,7 @@
 }
 
 int
-nlm4svc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
 {
 	if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
 		return 0;
@@ -370,13 +370,13 @@
 }
 
 int
-nlm4svc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
+nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
 {
 	return xdr_argsize_check(rqstp, p);
 }
 
 int
-nlm4svc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
+nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
 {
 	return xdr_ressize_check(rqstp, p);
 }
@@ -386,14 +386,14 @@
  */
 #ifdef NLMCLNT_SUPPORT_SHARES
 static int
-nlm4clt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr)
+nlm4clt_decode_void(struct rpc_rqst *req, __be32 *p, void *ptr)
 {
 	return 0;
 }
 #endif
 
 static int
-nlm4clt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+nlm4clt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
 {
 	struct nlm_lock	*lock = &argp->lock;
 
@@ -407,7 +407,7 @@
 }
 
 static int
-nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+nlm4clt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
 {
 	if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
 		return -EIO;
@@ -441,7 +441,7 @@
 
 
 static int
-nlm4clt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+nlm4clt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
 {
 	struct nlm_lock	*lock = &argp->lock;
 
@@ -458,7 +458,7 @@
 }
 
 static int
-nlm4clt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+nlm4clt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
 {
 	struct nlm_lock	*lock = &argp->lock;
 
@@ -473,7 +473,7 @@
 }
 
 static int
-nlm4clt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+nlm4clt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
 {
 	struct nlm_lock	*lock = &argp->lock;
 
@@ -486,7 +486,7 @@
 }
 
 static int
-nlm4clt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+nlm4clt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
 {
 	if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
 		return -EIO;
@@ -496,7 +496,7 @@
 }
 
 static int
-nlm4clt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+nlm4clt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
 {
 	if (!(p = nlm4_encode_testres(p, resp)))
 		return -EIO;
@@ -505,7 +505,7 @@
 }
 
 static int
-nlm4clt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+nlm4clt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
 {
 	if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
 		return -EIO;
diff -urN oldtree/fs/minix/namei.c newtree/fs/minix/namei.c
--- oldtree/fs/minix/namei.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/minix/namei.c	2006-02-21 15:58:29.040731696 +0000
@@ -6,18 +6,6 @@
 
 #include "minix.h"
 
-static inline void inc_count(struct inode *inode)
-{
-	inode->i_nlink++;
-	mark_inode_dirty(inode);
-}
-
-static inline void dec_count(struct inode *inode)
-{
-	inode->i_nlink--;
-	mark_inode_dirty(inode);
-}
-
 static int add_nondir(struct dentry *dentry, struct inode *inode)
 {
 	int err = minix_add_link(dentry, inode);
@@ -25,7 +13,7 @@
 		d_instantiate(dentry, inode);
 		return 0;
 	}
-	dec_count(inode);
+	inode_dec_link_count(inode);
 	iput(inode);
 	return err;
 }
@@ -125,7 +113,7 @@
 	return err;
 
 out_fail:
-	dec_count(inode);
+	inode_dec_link_count(inode);
 	iput(inode);
 	goto out;
 }
@@ -139,7 +127,7 @@
 		return -EMLINK;
 
 	inode->i_ctime = CURRENT_TIME_SEC;
-	inc_count(inode);
+	inode_inc_link_count(inode);
 	atomic_inc(&inode->i_count);
 	return add_nondir(dentry, inode);
 }
@@ -152,7 +140,7 @@
 	if (dir->i_nlink >= minix_sb(dir->i_sb)->s_link_max)
 		goto out;
 
-	inc_count(dir);
+	inode_inc_link_count(dir);
 
 	inode = minix_new_inode(dir, &err);
 	if (!inode)
@@ -163,7 +151,7 @@
 		inode->i_mode |= S_ISGID;
 	minix_set_inode(inode, 0);
 
-	inc_count(inode);
+	inode_inc_link_count(inode);
 
 	err = minix_make_empty(inode, dir);
 	if (err)
@@ -178,11 +166,11 @@
 	return err;
 
 out_fail:
-	dec_count(inode);
-	dec_count(inode);
+	inode_dec_link_count(inode);
+	inode_dec_link_count(inode);
 	iput(inode);
 out_dir:
-	dec_count(dir);
+	inode_dec_link_count(dir);
 	goto out;
 }
 
@@ -202,7 +190,7 @@
 		goto end_unlink;
 
 	inode->i_ctime = dir->i_ctime;
-	dec_count(inode);
+	inode_dec_link_count(inode);
 end_unlink:
 	return err;
 }
@@ -215,8 +203,8 @@
 	if (minix_empty_dir(inode)) {
 		err = minix_unlink(dir, dentry);
 		if (!err) {
-			dec_count(dir);
-			dec_count(inode);
+			inode_dec_link_count(dir);
+			inode_dec_link_count(inode);
 		}
 	}
 	return err;
@@ -257,34 +245,34 @@
 		new_de = minix_find_entry(new_dentry, &new_page);
 		if (!new_de)
 			goto out_dir;
-		inc_count(old_inode);
+		inode_inc_link_count(old_inode);
 		minix_set_link(new_de, new_page, old_inode);
 		new_inode->i_ctime = CURRENT_TIME_SEC;
 		if (dir_de)
 			new_inode->i_nlink--;
-		dec_count(new_inode);
+		inode_dec_link_count(new_inode);
 	} else {
 		if (dir_de) {
 			err = -EMLINK;
 			if (new_dir->i_nlink >= info->s_link_max)
 				goto out_dir;
 		}
-		inc_count(old_inode);
+		inode_inc_link_count(old_inode);
 		err = minix_add_link(new_dentry, old_inode);
 		if (err) {
-			dec_count(old_inode);
+			inode_dec_link_count(old_inode);
 			goto out_dir;
 		}
 		if (dir_de)
-			inc_count(new_dir);
+			inode_inc_link_count(new_dir);
 	}
 
 	minix_delete_entry(old_de, old_page);
-	dec_count(old_inode);
+	inode_dec_link_count(old_inode);
 
 	if (dir_de) {
 		minix_set_link(dir_de, dir_page, new_dir);
-		dec_count(old_dir);
+		inode_dec_link_count(old_dir);
 	}
 	return 0;
 
diff -urN oldtree/fs/namei.c newtree/fs/namei.c
--- oldtree/fs/namei.c	2006-02-19 11:41:05.148560400 +0000
+++ newtree/fs/namei.c	2006-02-21 15:58:11.744361144 +0000
@@ -1353,6 +1353,7 @@
 		return -ENOENT;
 
 	BUG_ON(victim->d_parent->d_inode != dir);
+	audit_inode_child(victim->d_name.name, victim->d_inode, dir->i_ino);
 
 	error = permission(dir,MAY_WRITE | MAY_EXEC, NULL);
 	if (error)
@@ -1472,7 +1473,7 @@
 	DQUOT_INIT(dir);
 	error = dir->i_op->create(dir, dentry, mode, nd);
 	if (!error)
-		fsnotify_create(dir, dentry->d_name.name);
+		fsnotify_create(dir, dentry);
 	return error;
 }
 
@@ -1793,7 +1794,7 @@
 	DQUOT_INIT(dir);
 	error = dir->i_op->mknod(dir, dentry, mode, dev);
 	if (!error)
-		fsnotify_create(dir, dentry->d_name.name);
+		fsnotify_create(dir, dentry);
 	return error;
 }
 
@@ -1870,7 +1871,7 @@
 	DQUOT_INIT(dir);
 	error = dir->i_op->mkdir(dir, dentry, mode);
 	if (!error)
-		fsnotify_mkdir(dir, dentry->d_name.name);
+		fsnotify_mkdir(dir, dentry);
 	return error;
 }
 
@@ -2133,7 +2134,7 @@
 	DQUOT_INIT(dir);
 	error = dir->i_op->symlink(dir, dentry, oldname);
 	if (!error)
-		fsnotify_create(dir, dentry->d_name.name);
+		fsnotify_create(dir, dentry);
 	return error;
 }
 
@@ -2210,7 +2211,7 @@
 	error = dir->i_op->link(old_dentry, dir, new_dentry);
 	mutex_unlock(&old_dentry->d_inode->i_mutex);
 	if (!error)
-		fsnotify_create(dir, new_dentry->d_name.name);
+		fsnotify_create(dir, new_dentry);
 	return error;
 }
 
diff -urN oldtree/fs/ncpfs/file.c newtree/fs/ncpfs/file.c
--- oldtree/fs/ncpfs/file.c	2006-02-19 11:41:05.151559944 +0000
+++ newtree/fs/ncpfs/file.c	2006-02-21 15:58:28.250851776 +0000
@@ -46,7 +46,7 @@
 		NCP_FINFO(inode)->volNumber, 
 		NCP_FINFO(inode)->dirEntNum);
 	error = -EACCES;
-	down(&NCP_FINFO(inode)->open_sem);
+	mutex_lock(&NCP_FINFO(inode)->open_mutex);
 	if (!atomic_read(&NCP_FINFO(inode)->opened)) {
 		struct ncp_entry_info finfo;
 		int result;
@@ -93,7 +93,7 @@
 	}
 
 out_unlock:
-	up(&NCP_FINFO(inode)->open_sem);
+	mutex_unlock(&NCP_FINFO(inode)->open_mutex);
 out:
 	return error;
 }
diff -urN oldtree/fs/ncpfs/inode.c newtree/fs/ncpfs/inode.c
--- oldtree/fs/ncpfs/inode.c	2006-02-19 11:41:05.151559944 +0000
+++ newtree/fs/ncpfs/inode.c	2006-02-21 15:58:28.251851624 +0000
@@ -63,7 +63,7 @@
 
 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
 	    SLAB_CTOR_CONSTRUCTOR) {
-		init_MUTEX(&ei->open_sem);
+		mutex_init(&ei->open_mutex);
 		inode_init_once(&ei->vfs_inode);
 	}
 }
@@ -520,7 +520,7 @@
 	}
 
 /*	server->lock = 0;	*/
-	init_MUTEX(&server->sem);
+	mutex_init(&server->mutex);
 	server->packet = NULL;
 /*	server->buffer_size = 0;	*/
 /*	server->conn_status = 0;	*/
@@ -557,7 +557,7 @@
 	server->dentry_ttl = 0;	/* no caching */
 
 	INIT_LIST_HEAD(&server->tx.requests);
-	init_MUTEX(&server->rcv.creq_sem);
+	mutex_init(&server->rcv.creq_mutex);
 	server->tx.creq		= NULL;
 	server->rcv.creq	= NULL;
 	server->data_ready	= sock->sk->sk_data_ready;
diff -urN oldtree/fs/ncpfs/ncplib_kernel.c newtree/fs/ncpfs/ncplib_kernel.c
--- oldtree/fs/ncpfs/ncplib_kernel.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/ncpfs/ncplib_kernel.c	2006-02-21 15:58:28.253851320 +0000
@@ -291,7 +291,7 @@
 	int err;
 
 	err = 0;
-	down(&NCP_FINFO(inode)->open_sem);	
+	mutex_lock(&NCP_FINFO(inode)->open_mutex);
 	if (atomic_read(&NCP_FINFO(inode)->opened) == 1) {
 		atomic_set(&NCP_FINFO(inode)->opened, 0);
 		err = ncp_close_file(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle);
@@ -301,7 +301,7 @@
 				NCP_FINFO(inode)->volNumber,
 				NCP_FINFO(inode)->dirEntNum, err);
 	}
-	up(&NCP_FINFO(inode)->open_sem);
+	mutex_unlock(&NCP_FINFO(inode)->open_mutex);
 	return err;
 }
 
diff -urN oldtree/fs/ncpfs/sock.c newtree/fs/ncpfs/sock.c
--- oldtree/fs/ncpfs/sock.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/ncpfs/sock.c	2006-02-21 15:58:28.254851168 +0000
@@ -171,9 +171,9 @@
 
 static inline void ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
 {
-	down(&server->rcv.creq_sem);
+	mutex_lock(&server->rcv.creq_mutex);
 	__ncp_abort_request(server, req, err);
-	up(&server->rcv.creq_sem);
+	mutex_unlock(&server->rcv.creq_mutex);
 }
 
 static inline void __ncptcp_abort(struct ncp_server *server)
@@ -303,20 +303,20 @@
 
 static int ncp_add_request(struct ncp_server *server, struct ncp_request_reply *req)
 {
-	down(&server->rcv.creq_sem);
+	mutex_lock(&server->rcv.creq_mutex);
 	if (!ncp_conn_valid(server)) {
-		up(&server->rcv.creq_sem);
+		mutex_unlock(&server->rcv.creq_mutex);
 		printk(KERN_ERR "ncpfs: tcp: Server died\n");
 		return -EIO;
 	}
 	if (server->tx.creq || server->rcv.creq) {
 		req->status = RQ_QUEUED;
 		list_add_tail(&req->req, &server->tx.requests);
-		up(&server->rcv.creq_sem);
+		mutex_unlock(&server->rcv.creq_mutex);
 		return 0;
 	}
 	__ncp_start_request(server, req);
-	up(&server->rcv.creq_sem);
+	mutex_unlock(&server->rcv.creq_mutex);
 	return 0;
 }
 
@@ -400,7 +400,7 @@
 				info_server(server, 0, server->unexpected_packet.data, result);
 				continue;
 			}
-			down(&server->rcv.creq_sem);		
+			mutex_lock(&server->rcv.creq_mutex);
 			req = server->rcv.creq;
 			if (req && (req->tx_type == NCP_ALLOC_SLOT_REQUEST || (server->sequence == reply.sequence && 
 					server->connection == get_conn_number(&reply)))) {
@@ -430,11 +430,11 @@
 				     	server->rcv.creq = NULL;
 					ncp_finish_request(req, result);
 					__ncp_next_request(server);
-					up(&server->rcv.creq_sem);
+					mutex_unlock(&server->rcv.creq_mutex);
 					continue;
 				}
 			}
-			up(&server->rcv.creq_sem);
+			mutex_unlock(&server->rcv.creq_mutex);
 		}
 drop:;		
 		_recv(sock, &reply, sizeof(reply), MSG_DONTWAIT);
@@ -472,9 +472,9 @@
 void ncpdgram_timeout_proc(void *s)
 {
 	struct ncp_server *server = s;
-	down(&server->rcv.creq_sem);
+	mutex_lock(&server->rcv.creq_mutex);
 	__ncpdgram_timeout_proc(server);
-	up(&server->rcv.creq_sem);
+	mutex_unlock(&server->rcv.creq_mutex);
 }
 
 static inline void ncp_init_req(struct ncp_request_reply* req)
@@ -657,18 +657,18 @@
 {
 	struct ncp_server *server = s;
 
-	down(&server->rcv.creq_sem);
+	mutex_lock(&server->rcv.creq_mutex);
 	__ncptcp_rcv_proc(server);
-	up(&server->rcv.creq_sem);
+	mutex_unlock(&server->rcv.creq_mutex);
 }
 
 void ncp_tcp_tx_proc(void *s)
 {
 	struct ncp_server *server = s;
 	
-	down(&server->rcv.creq_sem);
+	mutex_lock(&server->rcv.creq_mutex);
 	__ncptcp_try_send(server);
-	up(&server->rcv.creq_sem);
+	mutex_unlock(&server->rcv.creq_mutex);
 }
 
 static int do_ncp_rpc_call(struct ncp_server *server, int size,
@@ -833,7 +833,7 @@
 
 void ncp_lock_server(struct ncp_server *server)
 {
-	down(&server->sem);
+	mutex_lock(&server->mutex);
 	if (server->lock)
 		printk(KERN_WARNING "ncp_lock_server: was locked!\n");
 	server->lock = 1;
@@ -846,5 +846,5 @@
 		return;
 	}
 	server->lock = 0;
-	up(&server->sem);
+	mutex_unlock(&server->mutex);
 }
diff -urN oldtree/fs/nfs/callback.c newtree/fs/nfs/callback.c
--- oldtree/fs/nfs/callback.c	2006-02-19 11:41:05.153559640 +0000
+++ newtree/fs/nfs/callback.c	2006-02-21 15:58:23.904512520 +0000
@@ -14,6 +14,7 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/svcsock.h>
 #include <linux/nfs_fs.h>
+#include <linux/mutex.h>
 
 #include <net/inet_sock.h>
 
@@ -31,7 +32,7 @@
 };
 
 static struct nfs_callback_data nfs_callback_info;
-static DECLARE_MUTEX(nfs_callback_sema);
+static DEFINE_MUTEX(nfs_callback_mutex);
 static struct svc_program nfs4_callback_program;
 
 unsigned int nfs_callback_set_tcpport;
@@ -89,7 +90,7 @@
 	int ret = 0;
 
 	lock_kernel();
-	down(&nfs_callback_sema);
+	mutex_lock(&nfs_callback_mutex);
 	if (nfs_callback_info.users++ || nfs_callback_info.pid != 0)
 		goto out;
 	init_completion(&nfs_callback_info.started);
@@ -115,7 +116,7 @@
 	nfs_callback_info.serv = serv;
 	wait_for_completion(&nfs_callback_info.started);
 out:
-	up(&nfs_callback_sema);
+	mutex_unlock(&nfs_callback_mutex);
 	unlock_kernel();
 	return ret;
 out_destroy:
@@ -133,13 +134,13 @@
 	int ret = 0;
 
 	lock_kernel();
-	down(&nfs_callback_sema);
+	mutex_lock(&nfs_callback_mutex);
 	if (--nfs_callback_info.users || nfs_callback_info.pid == 0)
 		goto out;
 	kill_proc(nfs_callback_info.pid, SIGKILL, 1);
 	wait_for_completion(&nfs_callback_info.stopped);
 out:
-	up(&nfs_callback_sema);
+	mutex_unlock(&nfs_callback_mutex);
 	unlock_kernel();
 	return ret;
 }
diff -urN oldtree/fs/nfs/callback.h newtree/fs/nfs/callback.h
--- oldtree/fs/nfs/callback.h	2006-02-19 11:41:05.153559640 +0000
+++ newtree/fs/nfs/callback.h	2006-02-21 15:58:36.571586832 +0000
@@ -31,10 +31,10 @@
 };
 
 struct cb_compound_hdr_res {
-	uint32_t *status;
+	__be32 *status;
 	int taglen;
 	const char *tag;
-	uint32_t *nops;
+	__be32 *nops;
 };
 
 struct cb_getattrargs {
@@ -44,7 +44,7 @@
 };
 
 struct cb_getattrres {
-	uint32_t status;
+	__be32 status;
 	uint32_t bitmap[2];
 	uint64_t size;
 	uint64_t change_attr;
@@ -59,8 +59,8 @@
 	uint32_t truncate;
 };
 
-extern unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res);
-extern unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy);
+extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res);
+extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy);
 
 extern int nfs_callback_up(void);
 extern int nfs_callback_down(void);
diff -urN oldtree/fs/nfs/callback_proc.c newtree/fs/nfs/callback_proc.c
--- oldtree/fs/nfs/callback_proc.c	2006-02-19 11:41:05.154559488 +0000
+++ newtree/fs/nfs/callback_proc.c	2006-02-21 15:58:36.573586528 +0000
@@ -14,7 +14,7 @@
 
 #define NFSDBG_FACILITY NFSDBG_CALLBACK
  
-unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res)
+__be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res)
 {
 	struct nfs4_client *clp;
 	struct nfs_delegation *delegation;
@@ -55,11 +55,11 @@
 	return res->status;
 }
 
-unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
+__be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
 {
 	struct nfs4_client *clp;
 	struct inode *inode;
-	unsigned res;
+	__be32 res;
 	
 	res = htonl(NFS4ERR_BADHANDLE);
 	clp = nfs4_find_client(&args->addr->sin_addr);
diff -urN oldtree/fs/nfs/callback_xdr.c newtree/fs/nfs/callback_xdr.c
--- oldtree/fs/nfs/callback_xdr.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/nfs/callback_xdr.c	2006-02-21 15:58:36.575586224 +0000
@@ -23,9 +23,9 @@
 
 #define NFSDBG_FACILITY NFSDBG_CALLBACK
 
-typedef unsigned (*callback_process_op_t)(void *, void *);
-typedef unsigned (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *);
-typedef unsigned (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *);
+typedef __be32 (*callback_process_op_t)(void *, void *);
+typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *);
+typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *);
 
 
 struct callback_op {
@@ -37,24 +37,24 @@
 
 static struct callback_op callback_ops[];
 
-static int nfs4_callback_null(struct svc_rqst *rqstp, void *argp, void *resp)
+static __be32 nfs4_callback_null(struct svc_rqst *rqstp, void *argp, void *resp)
 {
 	return htonl(NFS4_OK);
 }
 
-static int nfs4_decode_void(struct svc_rqst *rqstp, uint32_t *p, void *dummy)
+static int nfs4_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
 {
 	return xdr_argsize_check(rqstp, p);
 }
 
-static int nfs4_encode_void(struct svc_rqst *rqstp, uint32_t *p, void *dummy)
+static int nfs4_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
 {
 	return xdr_ressize_check(rqstp, p);
 }
 
-static uint32_t *read_buf(struct xdr_stream *xdr, int nbytes)
+static __be32 *read_buf(struct xdr_stream *xdr, int nbytes)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	p = xdr_inline_decode(xdr, nbytes);
 	if (unlikely(p == NULL))
@@ -62,9 +62,9 @@
 	return p;
 }
 
-static unsigned decode_string(struct xdr_stream *xdr, unsigned int *len, const char **str)
+static __be32 decode_string(struct xdr_stream *xdr, unsigned int *len, const char **str)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	p = read_buf(xdr, 4);
 	if (unlikely(p == NULL))
@@ -82,9 +82,9 @@
 	return 0;
 }
 
-static unsigned decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh)
+static __be32 decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	p = read_buf(xdr, 4);
 	if (unlikely(p == NULL))
@@ -100,9 +100,9 @@
 	return 0;
 }
 
-static unsigned decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
+static __be32 decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
 {
-	uint32_t *p;
+	__be32 *p;
 	unsigned int attrlen;
 
 	p = read_buf(xdr, 4);
@@ -119,9 +119,9 @@
 	return 0;
 }
 
-static unsigned decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
+static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	p = read_buf(xdr, 16);
 	if (unlikely(p == NULL))
@@ -130,11 +130,11 @@
 	return 0;
 }
 
-static unsigned decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr)
+static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr)
 {
-	uint32_t *p;
+	__be32 *p;
 	unsigned int minor_version;
-	unsigned status;
+	__be32 status;
 
 	status = decode_string(xdr, &hdr->taglen, &hdr->tag);
 	if (unlikely(status != 0))
@@ -160,9 +160,9 @@
 	return 0;
 }
 
-static unsigned decode_op_hdr(struct xdr_stream *xdr, unsigned int *op)
+static __be32 decode_op_hdr(struct xdr_stream *xdr, unsigned int *op)
 {
-	uint32_t *p;
+	__be32 *p;
 	p = read_buf(xdr, 4);
 	if (unlikely(p == NULL))
 		return htonl(NFS4ERR_RESOURCE);
@@ -170,9 +170,9 @@
 	return 0;
 }
 
-static unsigned decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_getattrargs *args)
+static __be32 decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_getattrargs *args)
 {
-	unsigned status;
+	__be32 status;
 
 	status = decode_fh(xdr, &args->fh);
 	if (unlikely(status != 0))
@@ -184,10 +184,10 @@
 	return status;
 }
 
-static unsigned decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_recallargs *args)
+static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_recallargs *args)
 {
-	uint32_t *p;
-	unsigned status;
+	__be32 *p;
+	__be32 status;
 
 	args->addr = &rqstp->rq_addr;
 	status = decode_stateid(xdr, &args->stateid);
@@ -205,9 +205,9 @@
 	return 0;
 }
 
-static unsigned encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
+static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	p = xdr_reserve_space(xdr, 4 + len);
 	if (unlikely(p == NULL))
@@ -218,10 +218,10 @@
 
 #define CB_SUPPORTED_ATTR0 (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE)
 #define CB_SUPPORTED_ATTR1 (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY)
-static unsigned encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitmap, uint32_t **savep)
+static __be32 encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitmap, __be32 **savep)
 {
-	uint32_t bm[2];
-	uint32_t *p;
+	__be32 bm[2];
+	__be32 *p;
 
 	bm[0] = htonl(bitmap[0] & CB_SUPPORTED_ATTR0);
 	bm[1] = htonl(bitmap[1] & CB_SUPPORTED_ATTR1);
@@ -248,9 +248,9 @@
 	return 0;
 }
 
-static unsigned encode_attr_change(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t change)
+static __be32 encode_attr_change(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t change)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	if (!(bitmap[0] & FATTR4_WORD0_CHANGE))
 		return 0;
@@ -261,9 +261,9 @@
 	return 0;
 }
 
-static unsigned encode_attr_size(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t size)
+static __be32 encode_attr_size(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t size)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	if (!(bitmap[0] & FATTR4_WORD0_SIZE))
 		return 0;
@@ -274,9 +274,9 @@
 	return 0;
 }
 
-static unsigned encode_attr_time(struct xdr_stream *xdr, const struct timespec *time)
+static __be32 encode_attr_time(struct xdr_stream *xdr, const struct timespec *time)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	p = xdr_reserve_space(xdr, 12);
 	if (unlikely(p == 0))
@@ -286,23 +286,23 @@
 	return 0;
 }
 
-static unsigned encode_attr_ctime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
+static __be32 encode_attr_ctime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
 {
 	if (!(bitmap[1] & FATTR4_WORD1_TIME_METADATA))
 		return 0;
 	return encode_attr_time(xdr,time);
 }
 
-static unsigned encode_attr_mtime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
+static __be32 encode_attr_mtime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
 {
 	if (!(bitmap[1] & FATTR4_WORD1_TIME_MODIFY))
 		return 0;
 	return encode_attr_time(xdr,time);
 }
 
-static unsigned encode_compound_hdr_res(struct xdr_stream *xdr, struct cb_compound_hdr_res *hdr)
+static __be32 encode_compound_hdr_res(struct xdr_stream *xdr, struct cb_compound_hdr_res *hdr)
 {
-	unsigned status;
+	__be32 status;
 
 	hdr->status = xdr_reserve_space(xdr, 4);
 	if (unlikely(hdr->status == NULL))
@@ -316,9 +316,9 @@
 	return 0;
 }
 
-static unsigned encode_op_hdr(struct xdr_stream *xdr, uint32_t op, uint32_t res)
+static __be32 encode_op_hdr(struct xdr_stream *xdr, uint32_t op, __be32 res)
 {
-	uint32_t *p;
+	__be32 *p;
 	
 	p = xdr_reserve_space(xdr, 8);
 	if (unlikely(p == NULL))
@@ -328,10 +328,10 @@
 	return 0;
 }
 
-static unsigned encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_getattrres *res)
+static __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_getattrres *res)
 {
-	uint32_t *savep;
-	unsigned status = res->status;
+	__be32 *savep;
+	__be32 status = res->status;
 	
 	if (unlikely(status != 0))
 		goto out;
@@ -354,15 +354,15 @@
 	return status;
 }
 
-static unsigned process_op(struct svc_rqst *rqstp,
+static __be32 process_op(struct svc_rqst *rqstp,
 		struct xdr_stream *xdr_in, void *argp,
 		struct xdr_stream *xdr_out, void *resp)
 {
 	struct callback_op *op;
 	unsigned int op_nr;
-	unsigned int status = 0;
+	__be32 status = 0;
 	long maxlen;
-	unsigned res;
+	__be32 res;
 
 	dprintk("%s: start\n", __FUNCTION__);
 	status = decode_op_hdr(xdr_in, &op_nr);
@@ -397,20 +397,20 @@
 /*
  * Decode, process and encode a COMPOUND
  */
-static int nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp)
+static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp)
 {
 	struct cb_compound_hdr_arg hdr_arg;
 	struct cb_compound_hdr_res hdr_res;
 	struct xdr_stream xdr_in, xdr_out;
-	uint32_t *p;
-	unsigned int status;
+	__be32 *p;
+	__be32 status;
 	unsigned int nops = 1;
 
 	dprintk("%s: start\n", __FUNCTION__);
 
 	xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base);
 
-	p = (uint32_t*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len);
+	p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len);
 	xdr_init_encode(&xdr_out, &rqstp->rq_res, p);
 
 	decode_compound_hdr_arg(&xdr_in, &hdr_arg);
diff -urN oldtree/fs/nfs/dir.c newtree/fs/nfs/dir.c
--- oldtree/fs/nfs/dir.c	2006-02-19 11:41:05.156559184 +0000
+++ newtree/fs/nfs/dir.c	2006-02-21 15:58:36.585584704 +0000
@@ -137,12 +137,12 @@
 	return res;
 }
 
-typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int);
+typedef __be32 * (*decode_dirent_t)(__be32 *, struct nfs_entry *, int);
 typedef struct {
 	struct file	*file;
 	struct page	*page;
 	unsigned long	page_index;
-	u32		*ptr;
+	__be32		*ptr;
 	u64		*dir_cookie;
 	loff_t		current_index;
 	struct nfs_entry *entry;
@@ -211,7 +211,7 @@
 static inline
 int dir_decode(nfs_readdir_descriptor_t *desc)
 {
-	u32	*p = desc->ptr;
+	__be32	*p = desc->ptr;
 	p = desc->decode(p, desc->entry, desc->plus);
 	if (IS_ERR(p))
 		return PTR_ERR(p);
diff -urN oldtree/fs/nfs/idmap.c newtree/fs/nfs/idmap.c
--- oldtree/fs/nfs/idmap.c	2006-02-19 11:41:05.157559032 +0000
+++ newtree/fs/nfs/idmap.c	2006-02-21 15:58:27.416978544 +0000
@@ -35,6 +35,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/slab.h>
@@ -74,8 +75,8 @@
 	struct dentry        *idmap_dentry;
 	wait_queue_head_t     idmap_wq;
 	struct idmap_msg      idmap_im;
-	struct semaphore      idmap_lock;    /* Serializes upcalls */
-	struct semaphore      idmap_im_lock; /* Protects the hashtable */
+	struct mutex          idmap_lock;    /* Serializes upcalls */
+	struct mutex          idmap_im_lock; /* Protects the hashtable */
 	struct idmap_hashtable idmap_user_hash;
 	struct idmap_hashtable idmap_group_hash;
 };
@@ -116,8 +117,8 @@
 		return;
 	}
 
-        init_MUTEX(&idmap->idmap_lock);
-        init_MUTEX(&idmap->idmap_im_lock);
+        mutex_init(&idmap->idmap_lock);
+        mutex_init(&idmap->idmap_im_lock);
 	init_waitqueue_head(&idmap->idmap_wq);
 	idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER;
 	idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP;
@@ -232,8 +233,8 @@
 	if (namelen >= IDMAP_NAMESZ)
 		return -EINVAL;
 
-	down(&idmap->idmap_lock);
-	down(&idmap->idmap_im_lock);
+	mutex_lock(&idmap->idmap_lock);
+	mutex_lock(&idmap->idmap_im_lock);
 
 	he = idmap_lookup_name(h, name, namelen);
 	if (he != NULL) {
@@ -259,11 +260,11 @@
 	}
 
 	set_current_state(TASK_UNINTERRUPTIBLE);
-	up(&idmap->idmap_im_lock);
+	mutex_unlock(&idmap->idmap_im_lock);
 	schedule();
 	current->state = TASK_RUNNING;
 	remove_wait_queue(&idmap->idmap_wq, &wq);
-	down(&idmap->idmap_im_lock);
+	mutex_lock(&idmap->idmap_im_lock);
 
 	if (im->im_status & IDMAP_STATUS_SUCCESS) {
 		*id = im->im_id;
@@ -272,8 +273,8 @@
 
  out:
 	memset(im, 0, sizeof(*im));
-	up(&idmap->idmap_im_lock);
-	up(&idmap->idmap_lock);
+	mutex_unlock(&idmap->idmap_im_lock);
+	mutex_unlock(&idmap->idmap_lock);
 	return (ret);
 }
 
@@ -293,8 +294,8 @@
 
 	im = &idmap->idmap_im;
 
-	down(&idmap->idmap_lock);
-	down(&idmap->idmap_im_lock);
+	mutex_lock(&idmap->idmap_lock);
+	mutex_lock(&idmap->idmap_im_lock);
 
 	he = idmap_lookup_id(h, id);
 	if (he != 0) {
@@ -320,11 +321,11 @@
 	}
 
 	set_current_state(TASK_UNINTERRUPTIBLE);
-	up(&idmap->idmap_im_lock);
+	mutex_unlock(&idmap->idmap_im_lock);
 	schedule();
 	current->state = TASK_RUNNING;
 	remove_wait_queue(&idmap->idmap_wq, &wq);
-	down(&idmap->idmap_im_lock);
+	mutex_lock(&idmap->idmap_im_lock);
 
 	if (im->im_status & IDMAP_STATUS_SUCCESS) {
 		if ((len = strnlen(im->im_name, IDMAP_NAMESZ)) == 0)
@@ -335,8 +336,8 @@
 
  out:
 	memset(im, 0, sizeof(*im));
-	up(&idmap->idmap_im_lock);
-	up(&idmap->idmap_lock);
+	mutex_unlock(&idmap->idmap_im_lock);
+	mutex_unlock(&idmap->idmap_lock);
 	return ret;
 }
 
@@ -380,7 +381,7 @@
         if (copy_from_user(&im_in, src, mlen) != 0)
 		return (-EFAULT);
 
-	down(&idmap->idmap_im_lock);
+	mutex_lock(&idmap->idmap_im_lock);
 
 	ret = mlen;
 	im->im_status = im_in.im_status;
@@ -440,7 +441,7 @@
 		idmap_update_entry(he, im_in.im_name, namelen_in, im_in.im_id);
 	ret = mlen;
 out:
-	up(&idmap->idmap_im_lock);
+	mutex_unlock(&idmap->idmap_im_lock);
 	return ret;
 }
 
@@ -452,10 +453,10 @@
 
 	if (msg->errno >= 0)
 		return;
-	down(&idmap->idmap_im_lock);
+	mutex_lock(&idmap->idmap_im_lock);
 	im->im_status = IDMAP_STATUS_LOOKUPFAIL;
 	wake_up(&idmap->idmap_wq);
-	up(&idmap->idmap_im_lock);
+	mutex_unlock(&idmap->idmap_im_lock);
 }
 
 /* 
diff -urN oldtree/fs/nfs/mount_clnt.c newtree/fs/nfs/mount_clnt.c
--- oldtree/fs/nfs/mount_clnt.c	2006-02-19 11:41:05.159558728 +0000
+++ newtree/fs/nfs/mount_clnt.c	2006-02-21 15:58:36.606581512 +0000
@@ -92,7 +92,7 @@
  * XDR encode/decode functions for MOUNT
  */
 static int
-xdr_encode_dirpath(struct rpc_rqst *req, u32 *p, const char *path)
+xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, const char *path)
 {
 	p = xdr_encode_string(p, path);
 
@@ -101,7 +101,7 @@
 }
 
 static int
-xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
+xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res)
 {
 	struct nfs_fh *fh = res->fh;
 
@@ -113,7 +113,7 @@
 }
 
 static int
-xdr_decode_fhstatus3(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
+xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res)
 {
 	struct nfs_fh *fh = res->fh;
 
diff -urN oldtree/fs/nfs/nfs2xdr.c newtree/fs/nfs/nfs2xdr.c
--- oldtree/fs/nfs/nfs2xdr.c	2006-02-19 11:41:05.160558576 +0000
+++ newtree/fs/nfs/nfs2xdr.c	2006-02-21 15:58:36.607581360 +0000
@@ -67,15 +67,15 @@
 /*
  * Common NFS XDR functions as inlines
  */
-static inline u32 *
-xdr_encode_fhandle(u32 *p, struct nfs_fh *fhandle)
+static inline __be32 *
+xdr_encode_fhandle(__be32 *p, struct nfs_fh *fhandle)
 {
 	memcpy(p, fhandle->data, NFS2_FHSIZE);
 	return p + XDR_QUADLEN(NFS2_FHSIZE);
 }
 
-static inline u32 *
-xdr_decode_fhandle(u32 *p, struct nfs_fh *fhandle)
+static inline __be32 *
+xdr_decode_fhandle(__be32 *p, struct nfs_fh *fhandle)
 {
 	/* NFSv2 handles have a fixed length */
 	fhandle->size = NFS2_FHSIZE;
@@ -83,8 +83,8 @@
 	return p + XDR_QUADLEN(NFS2_FHSIZE);
 }
 
-static inline u32*
-xdr_encode_time(u32 *p, struct timespec *timep)
+static inline __be32*
+xdr_encode_time(__be32 *p, struct timespec *timep)
 {
 	*p++ = htonl(timep->tv_sec);
 	/* Convert nanoseconds into microseconds */
@@ -92,8 +92,8 @@
 	return p;
 }
 
-static inline u32*
-xdr_encode_current_server_time(u32 *p, struct timespec *timep)
+static inline __be32*
+xdr_encode_current_server_time(__be32 *p, struct timespec *timep)
 {
 	/*
 	 * Passing the invalid value useconds=1000000 is a
@@ -109,8 +109,8 @@
 	return p;
 }
 
-static inline u32*
-xdr_decode_time(u32 *p, struct timespec *timep)
+static inline __be32*
+xdr_decode_time(__be32 *p, struct timespec *timep)
 {
 	timep->tv_sec = ntohl(*p++);
 	/* Convert microseconds into nanoseconds */
@@ -118,8 +118,8 @@
 	return p;
 }
 
-static u32 *
-xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
+static __be32 *
+xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
 {
 	u32 rdev;
 	fattr->type = (enum nfs_ftype) ntohl(*p++);
@@ -146,8 +146,8 @@
 	return p;
 }
 
-static inline u32 *
-xdr_encode_sattr(u32 *p, struct iattr *attr)
+static inline __be32 *
+xdr_encode_sattr(__be32 *p, struct iattr *attr)
 {
 	const u32 not_set = __constant_htonl(0xFFFFFFFF);
 
@@ -184,7 +184,7 @@
  * GETATTR, READLINK, STATFS
  */
 static int
-nfs_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
+nfs_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
 {
 	p = xdr_encode_fhandle(p, fh);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
@@ -195,7 +195,7 @@
  * Encode SETATTR arguments
  */
 static int
-nfs_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs_sattrargs *args)
+nfs_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs_sattrargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
 	p = xdr_encode_sattr(p, args->sattr);
@@ -208,7 +208,7 @@
  * LOOKUP, REMOVE, RMDIR
  */
 static int
-nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args)
+nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
 	p = xdr_encode_array(p, args->name, args->len);
@@ -222,7 +222,7 @@
  * exactly to the page we want to fetch.
  */
 static int
-nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
+nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
 {
 	struct rpc_auth	*auth = req->rq_task->tk_auth;
 	unsigned int replen;
@@ -246,7 +246,7 @@
  * Decode READ reply
  */
 static int
-nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
+nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
 {
 	struct kvec *iov = req->rq_rcv_buf.head;
 	int	status, count, recvd, hdrlen;
@@ -286,7 +286,7 @@
  * Write arguments. Splice the buffer to be written into the iovec.
  */
 static int
-nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
+nfs_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
 {
 	struct xdr_buf *sndbuf = &req->rq_snd_buf;
 	u32 offset = (u32)args->offset;
@@ -309,7 +309,7 @@
  * CREATE, MKDIR
  */
 static int
-nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args)
+nfs_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs_createargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
 	p = xdr_encode_array(p, args->name, args->len);
@@ -322,7 +322,7 @@
  * Encode RENAME arguments
  */
 static int
-nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args)
+nfs_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fromfh);
 	p = xdr_encode_array(p, args->fromname, args->fromlen);
@@ -336,7 +336,7 @@
  * Encode LINK arguments
  */
 static int
-nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
+nfs_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs_linkargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fromfh);
 	p = xdr_encode_fhandle(p, args->tofh);
@@ -349,7 +349,7 @@
  * Encode SYMLINK arguments
  */
 static int
-nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
+nfs_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_symlinkargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fromfh);
 	p = xdr_encode_array(p, args->fromname, args->fromlen);
@@ -363,7 +363,7 @@
  * Encode arguments to readdir call
  */
 static int
-nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
+nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args)
 {
 	struct rpc_task	*task = req->rq_task;
 	struct rpc_auth	*auth = task->tk_auth;
@@ -389,7 +389,7 @@
  * from nfs_readdir for each entry.
  */
 static int
-nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
+nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
 {
 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 	struct kvec *iov = rcvbuf->head;
@@ -397,7 +397,7 @@
 	int hdrlen, recvd;
 	int status, nr;
 	unsigned int len, pglen;
-	u32 *end, *entry, *kaddr;
+	__be32 *end, *entry, *kaddr;
 
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
@@ -417,8 +417,8 @@
 	if (pglen > recvd)
 		pglen = recvd;
 	page = rcvbuf->pages;
-	kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
-	end = (u32 *)((char *)p + pglen);
+	kaddr = p = kmap_atomic(*page, KM_USER0);
+	end = (__be32 *)((char *)p + pglen);
 	entry = p;
 	for (nr = 0; *p++; nr++) {
 		if (p + 2 > end)
@@ -453,8 +453,8 @@
 	goto out;
 }
 
-u32 *
-nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
+__be32 *
+nfs_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
 {
 	if (!*p++) {
 		if (!*p)
@@ -481,7 +481,7 @@
  * Decode simple status reply
  */
 static int
-nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy)
+nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy)
 {
 	int	status;
 
@@ -495,7 +495,7 @@
  * GETATTR, SETATTR, WRITE
  */
 static int
-nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
+nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
 {
 	int	status;
 
@@ -510,7 +510,7 @@
  * LOOKUP, CREATE, MKDIR
  */
 static int
-nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res)
+nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
 {
 	int	status;
 
@@ -525,7 +525,7 @@
  * Encode READLINK args
  */
 static int
-nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
+nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args)
 {
 	struct rpc_auth *auth = req->rq_task->tk_auth;
 	unsigned int replen;
@@ -543,7 +543,7 @@
  * Decode READLINK reply
  */
 static int
-nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
+nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
 {
 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 	struct kvec *iov = rcvbuf->head;
@@ -586,7 +586,7 @@
  * Decode WRITE reply
  */
 static int
-nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
+nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
 {
 	res->verf->committed = NFS_FILE_SYNC;
 	return nfs_xdr_attrstat(req, p, res->fattr);
@@ -596,7 +596,7 @@
  * Decode STATFS reply
  */
 static int
-nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs2_fsstat *res)
+nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res)
 {
 	int	status;
 
diff -urN oldtree/fs/nfs/nfs3proc.c newtree/fs/nfs/nfs3proc.c
--- oldtree/fs/nfs/nfs3proc.c	2006-02-19 11:41:05.160558576 +0000
+++ newtree/fs/nfs/nfs3proc.c	2006-02-21 15:58:36.608581208 +0000
@@ -616,7 +616,7 @@
 {
 	struct inode		*dir = dentry->d_inode;
 	struct nfs_fattr	dir_attr;
-	u32			*verf = NFS_COOKIEVERF(dir);
+	__be32			*verf = NFS_COOKIEVERF(dir);
 	struct nfs3_readdirargs	arg = {
 		.fh		= NFS_FH(dir),
 		.cookie		= cookie,
@@ -742,7 +742,7 @@
 	return status;
 }
 
-extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
+extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int);
 
 static void nfs3_read_done(struct rpc_task *task, void *calldata)
 {
diff -urN oldtree/fs/nfs/nfs3xdr.c newtree/fs/nfs/nfs3xdr.c
--- oldtree/fs/nfs/nfs3xdr.c	2006-02-19 11:41:05.161558424 +0000
+++ newtree/fs/nfs/nfs3xdr.c	2006-02-21 15:58:36.618579688 +0000
@@ -106,14 +106,14 @@
 /*
  * Common NFS XDR functions as inlines
  */
-static inline u32 *
-xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
+static inline __be32 *
+xdr_encode_fhandle(__be32 *p, struct nfs_fh *fh)
 {
 	return xdr_encode_array(p, fh->data, fh->size);
 }
 
-static inline u32 *
-xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
+static inline __be32 *
+xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
 {
 	if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
 		memcpy(fh->data, p, fh->size);
@@ -125,24 +125,24 @@
 /*
  * Encode/decode time.
  */
-static inline u32 *
-xdr_encode_time3(u32 *p, struct timespec *timep)
+static inline __be32 *
+xdr_encode_time3(__be32 *p, struct timespec *timep)
 {
 	*p++ = htonl(timep->tv_sec);
 	*p++ = htonl(timep->tv_nsec);
 	return p;
 }
 
-static inline u32 *
-xdr_decode_time3(u32 *p, struct timespec *timep)
+static inline __be32 *
+xdr_decode_time3(__be32 *p, struct timespec *timep)
 {
 	timep->tv_sec = ntohl(*p++);
 	timep->tv_nsec = ntohl(*p++);
 	return p;
 }
 
-static u32 *
-xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
+static __be32 *
+xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
 {
 	unsigned int	type, major, minor;
 	int		fmode;
@@ -177,8 +177,8 @@
 	return p;
 }
 
-static inline u32 *
-xdr_encode_sattr(u32 *p, struct iattr *attr)
+static inline __be32 *
+xdr_encode_sattr(__be32 *p, struct iattr *attr)
 {
 	if (attr->ia_valid & ATTR_MODE) {
 		*p++ = xdr_one;
@@ -223,8 +223,8 @@
 	return p;
 }
 
-static inline u32 *
-xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
+static inline __be32 *
+xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
 {
 	p = xdr_decode_hyper(p, &fattr->pre_size);
 	p = xdr_decode_time3(p, &fattr->pre_mtime);
@@ -233,16 +233,16 @@
 	return p;
 }
 
-static inline u32 *
-xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr)
+static inline __be32 *
+xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
 {
 	if (*p++)
 		p = xdr_decode_fattr(p, fattr);
 	return p;
 }
 
-static inline u32 *
-xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
+static inline __be32 *
+xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
 {
 	if (*p++)
 		return xdr_decode_wcc_attr(p, fattr);
@@ -250,8 +250,8 @@
 }
 
 
-static inline u32 *
-xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr)
+static inline __be32 *
+xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
 {
 	p = xdr_decode_pre_op_attr(p, fattr);
 	return xdr_decode_post_op_attr(p, fattr);
@@ -265,7 +265,7 @@
  * Encode file handle argument
  */
 static int
-nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
+nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
 {
 	p = xdr_encode_fhandle(p, fh);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
@@ -276,7 +276,7 @@
  * Encode SETATTR arguments
  */
 static int
-nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args)
+nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
 	p = xdr_encode_sattr(p, args->sattr);
@@ -291,7 +291,7 @@
  * Encode directory ops argument
  */
 static int
-nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args)
+nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
 	p = xdr_encode_array(p, args->name, args->len);
@@ -303,7 +303,7 @@
  * Encode access() argument
  */
 static int
-nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
+nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
 	*p++ = htonl(args->access);
@@ -317,7 +317,7 @@
  * exactly to the page we want to fetch.
  */
 static int
-nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
+nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
 {
 	struct rpc_auth	*auth = req->rq_task->tk_auth;
 	unsigned int replen;
@@ -339,7 +339,7 @@
  * Write arguments. Splice the buffer to be written into the iovec.
  */
 static int
-nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
+nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
 {
 	struct xdr_buf *sndbuf = &req->rq_snd_buf;
 	u32 count = args->count;
@@ -360,7 +360,7 @@
  * Encode CREATE arguments
  */
 static int
-nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args)
+nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
 	p = xdr_encode_array(p, args->name, args->len);
@@ -380,7 +380,7 @@
  * Encode MKDIR arguments
  */
 static int
-nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args)
+nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
 	p = xdr_encode_array(p, args->name, args->len);
@@ -393,7 +393,7 @@
  * Encode SYMLINK arguments
  */
 static int
-nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args)
+nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fromfh);
 	p = xdr_encode_array(p, args->fromname, args->fromlen);
@@ -407,7 +407,7 @@
  * Encode MKNOD arguments
  */
 static int
-nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args)
+nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
 	p = xdr_encode_array(p, args->name, args->len);
@@ -426,7 +426,7 @@
  * Encode RENAME arguments
  */
 static int
-nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args)
+nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs3_renameargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fromfh);
 	p = xdr_encode_array(p, args->fromname, args->fromlen);
@@ -440,7 +440,7 @@
  * Encode LINK arguments
  */
 static int
-nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args)
+nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fromfh);
 	p = xdr_encode_fhandle(p, args->tofh);
@@ -453,7 +453,7 @@
  * Encode arguments to readdir call
  */
 static int
-nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
+nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
 {
 	struct rpc_auth	*auth = req->rq_task->tk_auth;
 	unsigned int replen;
@@ -482,7 +482,7 @@
  * We just check for syntactical correctness.
  */
 static int
-nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
+nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
 {
 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 	struct kvec *iov = rcvbuf->head;
@@ -490,7 +490,7 @@
 	int hdrlen, recvd;
 	int status, nr;
 	unsigned int len, pglen;
-	u32 *entry, *end, *kaddr;
+	__be32 *entry, *end, *kaddr;
 
 	status = ntohl(*p++);
 	/* Decode post_op_attrs */
@@ -520,8 +520,8 @@
 	if (pglen > recvd)
 		pglen = recvd;
 	page = rcvbuf->pages;
-	kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
-	end = (u32 *)((char *)p + pglen);
+	kaddr = p = kmap_atomic(*page, KM_USER0);
+	end = (__be32 *)((char *)p + pglen);
 	entry = p;
 	for (nr = 0; *p++; nr++) {
 		if (p + 3 > end)
@@ -580,8 +580,8 @@
 	goto out;
 }
 
-u32 *
-nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
+__be32 *
+nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
 {
 	struct nfs_entry old = *entry;
 
@@ -623,7 +623,7 @@
  * Encode COMMIT arguments
  */
 static int
-nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
+nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
 	p = xdr_encode_hyper(p, args->offset);
@@ -637,7 +637,7 @@
  * Encode GETACL arguments
  */
 static int
-nfs3_xdr_getaclargs(struct rpc_rqst *req, u32 *p,
+nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
 		    struct nfs3_getaclargs *args)
 {
 	struct rpc_auth *auth = req->rq_task->tk_auth;
@@ -661,7 +661,7 @@
  * Encode SETACL arguments
  */
 static int
-nfs3_xdr_setaclargs(struct rpc_rqst *req, u32 *p,
+nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
                    struct nfs3_setaclargs *args)
 {
 	struct xdr_buf *buf = &req->rq_snd_buf;
@@ -708,7 +708,7 @@
  * Decode attrstat reply.
  */
 static int
-nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
+nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
 {
 	int	status;
 
@@ -723,7 +723,7 @@
  * SATTR, REMOVE, RMDIR
  */
 static int
-nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
+nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
 {
 	int	status;
 
@@ -737,7 +737,7 @@
  * Decode LOOKUP reply
  */
 static int
-nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
+nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
 {
 	int	status;
 
@@ -756,7 +756,7 @@
  * Decode ACCESS reply
  */
 static int
-nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res)
+nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
 {
 	int	status = ntohl(*p++);
 
@@ -768,7 +768,7 @@
 }
 
 static int
-nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
+nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
 {
 	struct rpc_auth *auth = req->rq_task->tk_auth;
 	unsigned int replen;
@@ -786,7 +786,7 @@
  * Decode READLINK reply
  */
 static int
-nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
+nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
 {
 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 	struct kvec *iov = rcvbuf->head;
@@ -834,7 +834,7 @@
  * Decode READ reply
  */
 static int
-nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
+nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
 {
 	struct kvec *iov = req->rq_rcv_buf.head;
 	int	status, count, ocount, recvd, hdrlen;
@@ -885,7 +885,7 @@
  * Decode WRITE response
  */
 static int
-nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
+nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
 {
 	int	status;
 
@@ -907,7 +907,7 @@
  * Decode a CREATE response
  */
 static int
-nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
+nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
 {
 	int	status;
 
@@ -934,7 +934,7 @@
  * Decode RENAME reply
  */
 static int
-nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res)
+nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res)
 {
 	int	status;
 
@@ -949,7 +949,7 @@
  * Decode LINK reply
  */
 static int
-nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
+nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
 {
 	int	status;
 
@@ -964,7 +964,7 @@
  * Decode FSSTAT reply
  */
 static int
-nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsstat *res)
+nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
 {
 	int		status;
 
@@ -989,7 +989,7 @@
  * Decode FSINFO reply
  */
 static int
-nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
 {
 	int		status;
 
@@ -1017,7 +1017,7 @@
  * Decode PATHCONF reply
  */
 static int
-nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_pathconf *res)
+nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
 {
 	int		status;
 
@@ -1037,7 +1037,7 @@
  * Decode COMMIT reply
  */
 static int
-nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
+nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
 {
 	int		status;
 
@@ -1056,7 +1056,7 @@
  * Decode GETACL reply
  */
 static int
-nfs3_xdr_getaclres(struct rpc_rqst *req, u32 *p,
+nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
 		   struct nfs3_getaclres *res)
 {
 	struct xdr_buf *buf = &req->rq_rcv_buf;
@@ -1088,7 +1088,7 @@
  * Decode setacl reply.
  */
 static int
-nfs3_xdr_setaclres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
+nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
 {
 	int status = ntohl(*p++);
 
diff -urN oldtree/fs/nfs/nfs4_fs.h newtree/fs/nfs/nfs4_fs.h
--- oldtree/fs/nfs/nfs4_fs.h	2006-02-19 11:41:05.162558272 +0000
+++ newtree/fs/nfs/nfs4_fs.h	2006-02-21 15:58:36.619579536 +0000
@@ -262,7 +262,7 @@
 extern const nfs4_stateid zero_stateid;
 
 /* nfs4xdr.c */
-extern uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus);
+extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus);
 extern struct rpc_procinfo nfs4_procedures[];
 
 struct nfs4_mount_data;
diff -urN oldtree/fs/nfs/nfs4proc.c newtree/fs/nfs/nfs4proc.c
--- oldtree/fs/nfs/nfs4proc.c	2006-02-19 11:41:05.165557816 +0000
+++ newtree/fs/nfs/nfs4proc.c	2006-02-21 15:58:36.651574672 +0000
@@ -64,7 +64,7 @@
 static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry);
 static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception);
 static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp);
-extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
+extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus);
 extern struct rpc_procinfo nfs4_procedures[];
 
 /* Prevent leaks of NFSv4 errors into userland */
@@ -120,10 +120,10 @@
 			0
 };
 
-static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry,
+static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry,
 		struct nfs4_readdir_arg *readdir)
 {
-	u32 *start, *p;
+	__be32 *start, *p;
 
 	BUG_ON(readdir->count < 80);
 	if (cookie > 2) {
@@ -144,7 +144,7 @@
 	 * when talking to the server, we always send cookie 0
 	 * instead of 1 or 2.
 	 */
-	start = p = (u32 *)kmap_atomic(*readdir->pages, KM_USER0);
+	start = p = kmap_atomic(*readdir->pages, KM_USER0);
 	
 	if (cookie == 0) {
 		*p++ = xdr_one;                                  /* next */
@@ -2859,11 +2859,11 @@
 		.rpc_resp = clp,
 		.rpc_cred = cred,
 	};
-	u32 *p;
+	__be32 *p;
 	int loop = 0;
 	int status;
 
-	p = (u32*)sc_verifier.data;
+	p = (__be32*)sc_verifier.data;
 	*p++ = htonl((u32)clp->cl_boot_time.tv_sec);
 	*p = htonl((u32)clp->cl_boot_time.tv_nsec);
 
diff -urN oldtree/fs/nfs/nfs4xdr.c newtree/fs/nfs/nfs4xdr.c
--- oldtree/fs/nfs/nfs4xdr.c	2006-02-19 11:41:05.169557208 +0000
+++ newtree/fs/nfs/nfs4xdr.c	2006-02-21 15:58:36.657573760 +0000
@@ -462,7 +462,7 @@
 
 static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	p = xdr_reserve_space(xdr, 4 + len);
 	BUG_ON(p == NULL);
@@ -471,7 +471,7 @@
 
 static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag);
 	BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
@@ -485,7 +485,7 @@
 
 static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
 	BUG_ON(p == NULL);
@@ -498,8 +498,8 @@
 	char owner_group[IDMAP_NAMESZ];
 	int owner_namelen = 0;
 	int owner_grouplen = 0;
-	uint32_t *p;
-	uint32_t *q;
+	__be32 *p;
+	__be32 *q;
 	int len;
 	uint32_t bmval0 = 0;
 	uint32_t bmval1 = 0;
@@ -621,7 +621,7 @@
 
 static int encode_access(struct xdr_stream *xdr, u32 access)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(8);
 	WRITE32(OP_ACCESS);
@@ -632,7 +632,7 @@
 
 static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(8+sizeof(arg->stateid->data));
 	WRITE32(OP_CLOSE);
@@ -644,7 +644,7 @@
 
 static int encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args)
 {
-	uint32_t *p;
+	__be32 *p;
         
         RESERVE_SPACE(16);
         WRITE32(OP_COMMIT);
@@ -656,7 +656,7 @@
 
 static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create)
 {
-	uint32_t *p;
+	__be32 *p;
 	
 	RESERVE_SPACE(8);
 	WRITE32(OP_CREATE);
@@ -688,7 +688,7 @@
 
 static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap)
 {
-        uint32_t *p;
+        __be32 *p;
 
         RESERVE_SPACE(12);
         WRITE32(OP_GETATTR);
@@ -699,7 +699,7 @@
 
 static int encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1)
 {
-        uint32_t *p;
+        __be32 *p;
 
         RESERVE_SPACE(16);
         WRITE32(OP_GETATTR);
@@ -724,7 +724,7 @@
 
 static int encode_getfh(struct xdr_stream *xdr)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(4);
 	WRITE32(OP_GETFH);
@@ -734,7 +734,7 @@
 
 static int encode_link(struct xdr_stream *xdr, const struct qstr *name)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(8 + name->len);
 	WRITE32(OP_LINK);
@@ -764,7 +764,7 @@
  */
 static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(32);
 	WRITE32(OP_LOCK);
@@ -793,7 +793,7 @@
 
 static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(40);
 	WRITE32(OP_LOCKT);
@@ -809,7 +809,7 @@
 
 static int encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(44);
 	WRITE32(OP_LOCKU);
@@ -825,7 +825,7 @@
 static int encode_lookup(struct xdr_stream *xdr, const struct qstr *name)
 {
 	int len = name->len;
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(8 + len);
 	WRITE32(OP_LOOKUP);
@@ -837,7 +837,7 @@
 
 static void encode_share_access(struct xdr_stream *xdr, int open_flags)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(8);
 	switch (open_flags & (FMODE_READ|FMODE_WRITE)) {
@@ -858,7 +858,7 @@
 
 static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg)
 {
-	uint32_t *p;
+	__be32 *p;
  /*
  * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
  * owner 4 = 32
@@ -875,7 +875,7 @@
 
 static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(4);
 	switch(arg->open_flags & O_EXCL) {
@@ -891,7 +891,7 @@
 
 static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *arg)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(4);
 	switch (arg->open_flags & O_CREAT) {
@@ -907,7 +907,7 @@
 
 static inline void encode_delegation_type(struct xdr_stream *xdr, int delegation_type)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(4);
 	switch (delegation_type) {
@@ -927,7 +927,7 @@
 
 static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr *name)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(4);
 	WRITE32(NFS4_OPEN_CLAIM_NULL);
@@ -936,7 +936,7 @@
 
 static inline void encode_claim_previous(struct xdr_stream *xdr, int type)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(4);
 	WRITE32(NFS4_OPEN_CLAIM_PREVIOUS);
@@ -945,7 +945,7 @@
 
 static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struct qstr *name, const nfs4_stateid *stateid)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(4+sizeof(stateid->data));
 	WRITE32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
@@ -975,7 +975,7 @@
 
 static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(8+sizeof(arg->stateid->data));
 	WRITE32(OP_OPEN_CONFIRM);
@@ -987,7 +987,7 @@
 
 static int encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(8+sizeof(arg->stateid->data));
 	WRITE32(OP_OPEN_DOWNGRADE);
@@ -1001,7 +1001,7 @@
 encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh)
 {
 	int len = fh->size;
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(8 + len);
 	WRITE32(OP_PUTFH);
@@ -1013,7 +1013,7 @@
 
 static int encode_putrootfh(struct xdr_stream *xdr)
 {
-        uint32_t *p;
+        __be32 *p;
         
         RESERVE_SPACE(4);
         WRITE32(OP_PUTROOTFH);
@@ -1024,7 +1024,7 @@
 static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx)
 {
 	nfs4_stateid stateid;
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(16);
 	if (ctx->state != NULL) {
@@ -1036,7 +1036,7 @@
 
 static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(4);
 	WRITE32(OP_READ);
@@ -1058,7 +1058,7 @@
 		FATTR4_WORD1_MOUNTED_ON_FILEID,
 	};
 	int replen;
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(32+sizeof(nfs4_verifier));
 	WRITE32(OP_READDIR);
@@ -1100,7 +1100,7 @@
 {
 	struct rpc_auth *auth = req->rq_task->tk_auth;
 	unsigned int replen;
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(4);
 	WRITE32(OP_READLINK);
@@ -1118,7 +1118,7 @@
 
 static int encode_remove(struct xdr_stream *xdr, const struct qstr *name)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(8 + name->len);
 	WRITE32(OP_REMOVE);
@@ -1130,7 +1130,7 @@
 
 static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(8 + oldname->len);
 	WRITE32(OP_RENAME);
@@ -1146,7 +1146,7 @@
 
 static int encode_renew(struct xdr_stream *xdr, const struct nfs4_client *client_stateid)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(12);
 	WRITE32(OP_RENEW);
@@ -1158,7 +1158,7 @@
 static int
 encode_restorefh(struct xdr_stream *xdr)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(4);
 	WRITE32(OP_RESTOREFH);
@@ -1169,7 +1169,7 @@
 static int
 encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(4+sizeof(zero_stateid.data));
 	WRITE32(OP_SETATTR);
@@ -1188,7 +1188,7 @@
 static int
 encode_savefh(struct xdr_stream *xdr)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(4);
 	WRITE32(OP_SAVEFH);
@@ -1199,7 +1199,7 @@
 static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server)
 {
 	int status;
-	uint32_t *p;
+	__be32 *p;
 	
         RESERVE_SPACE(4+sizeof(arg->stateid.data));
         WRITE32(OP_SETATTR);
@@ -1213,7 +1213,7 @@
 
 static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(4 + sizeof(setclientid->sc_verifier->data));
 	WRITE32(OP_SETCLIENTID);
@@ -1232,7 +1232,7 @@
 
 static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_client *client_state)
 {
-        uint32_t *p;
+        __be32 *p;
 
         RESERVE_SPACE(12 + sizeof(client_state->cl_confirm.data));
         WRITE32(OP_SETCLIENTID_CONFIRM);
@@ -1244,7 +1244,7 @@
 
 static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(4);
 	WRITE32(OP_WRITE);
@@ -1263,7 +1263,7 @@
 
 static int encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	RESERVE_SPACE(20);
 
@@ -1279,7 +1279,7 @@
 /*
  * Encode an ACCESS request
  */
-static int nfs4_xdr_enc_access(struct rpc_rqst *req, uint32_t *p, const struct nfs4_accessargs *args)
+static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs4_accessargs *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1297,7 +1297,7 @@
 /*
  * Encode LOOKUP request
  */
-static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_arg *args)
+static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_arg *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1321,7 +1321,7 @@
 /*
  * Encode LOOKUP_ROOT request
  */
-static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_root_arg *args)
+static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_root_arg *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1342,7 +1342,7 @@
 /*
  * Encode REMOVE request
  */
-static int nfs4_xdr_enc_remove(struct rpc_rqst *req, uint32_t *p, const struct nfs4_remove_arg *args)
+static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs4_remove_arg *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1364,7 +1364,7 @@
 /*
  * Encode RENAME request
  */
-static int nfs4_xdr_enc_rename(struct rpc_rqst *req, uint32_t *p, const struct nfs4_rename_arg *args)
+static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs4_rename_arg *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1394,7 +1394,7 @@
 /*
  * Encode LINK request
  */
-static int nfs4_xdr_enc_link(struct rpc_rqst *req, uint32_t *p, const struct nfs4_link_arg *args)
+static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_link_arg *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1424,7 +1424,7 @@
 /*
  * Encode CREATE request
  */
-static int nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, const struct nfs4_create_arg *args)
+static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1454,7 +1454,7 @@
 /*
  * Encode SYMLINK request
  */
-static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, uint32_t *p, const struct nfs4_create_arg *args)
+static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
 {
 	return nfs4_xdr_enc_create(req, p, args);
 }
@@ -1462,7 +1462,7 @@
 /*
  * Encode GETATTR request
  */
-static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, uint32_t *p, const struct nfs4_getattr_arg *args)
+static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nfs4_getattr_arg *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1480,7 +1480,7 @@
 /*
  * Encode a CLOSE request
  */
-static int nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
+static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr = {
@@ -1504,7 +1504,7 @@
 /*
  * Encode an OPEN request
  */
-static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args)
+static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1540,7 +1540,7 @@
 /*
  * Encode an OPEN_CONFIRM request
  */
-static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_confirmargs *args)
+static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_open_confirmargs *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1561,7 +1561,7 @@
 /*
  * Encode an OPEN request with no attributes.
  */
-static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args)
+static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1585,7 +1585,7 @@
 /*
  * Encode an OPEN_DOWNGRADE request
  */
-static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
+static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1609,7 +1609,7 @@
 /*
  * Encode a LOCK request
  */
-static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lock_args *args)
+static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_args *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1630,7 +1630,7 @@
 /*
  * Encode a LOCKT request
  */
-static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockt_args *args)
+static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_args *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1651,7 +1651,7 @@
 /*
  * Encode a LOCKU request
  */
-static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_locku_args *args)
+static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_args *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1672,7 +1672,7 @@
 /*
  * Encode a READLINK request
  */
-static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readlink *args)
+static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_readlink *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1693,7 +1693,7 @@
 /*
  * Encode a READDIR request
  */
-static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readdir_arg *args)
+static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nfs4_readdir_arg *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1714,7 +1714,7 @@
 /*
  * Encode a READ request
  */
-static int nfs4_xdr_enc_read(struct rpc_rqst *req, uint32_t *p, struct nfs_readargs *args)
+static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
 {
 	struct rpc_auth	*auth = req->rq_task->tk_auth;
 	struct xdr_stream xdr;
@@ -1746,7 +1746,7 @@
 /*
  * Encode an SETATTR request
  */
-static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs *args)
+static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_setattrargs *args)
 
 {
         struct xdr_stream xdr;
@@ -1772,7 +1772,7 @@
  * Encode a GETACL request
  */
 static int
-nfs4_xdr_enc_getacl(struct rpc_rqst *req, uint32_t *p,
+nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p,
 		struct nfs_getaclargs *args)
 {
 	struct xdr_stream xdr;
@@ -1799,7 +1799,7 @@
 /*
  * Encode a WRITE request
  */
-static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
+static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1823,7 +1823,7 @@
 /*
  *  a COMMIT request
  */
-static int nfs4_xdr_enc_commit(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
+static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1847,7 +1847,7 @@
 /*
  * FSINFO request
  */
-static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs4_fsinfo_arg *args)
+static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsinfo_arg *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1866,7 +1866,7 @@
 /*
  * a PATHCONF request
  */
-static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct nfs4_pathconf_arg *args)
+static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct nfs4_pathconf_arg *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1886,7 +1886,7 @@
 /*
  * a STATFS request
  */
-static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct nfs4_statfs_arg *args)
+static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs4_statfs_arg *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1907,7 +1907,7 @@
 /*
  * GETATTR_BITMAP request
  */
-static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, const struct nfs_fh *fhandle)
+static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, const struct nfs_fh *fhandle)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1929,7 +1929,7 @@
 /*
  * a RENEW request
  */
-static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp)
+static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs4_client *clp)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1944,7 +1944,7 @@
 /*
  * a SETCLIENTID request
  */
-static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, struct nfs4_setclientid *sc)
+static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4_setclientid *sc)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1959,7 +1959,7 @@
 /*
  * a SETCLIENTID_CONFIRM request
  */
-static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp)
+static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs4_client *clp)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1981,7 +1981,7 @@
 /*
  * DELEGRETURN request
  */
-static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, uint32_t *p, const struct nfs4_delegreturnargs *args)
+static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struct nfs4_delegreturnargs *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -2038,7 +2038,7 @@
 
 static int decode_opaque_inline(struct xdr_stream *xdr, uint32_t *len, char **string)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	READ_BUF(4);
 	READ32(*len);
@@ -2049,7 +2049,7 @@
 
 static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	READ_BUF(8);
 	READ32(hdr->status);
@@ -2064,7 +2064,7 @@
 
 static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
 {
-	uint32_t *p;
+	__be32 *p;
 	uint32_t opnum;
 	int32_t nfserr;
 
@@ -2086,7 +2086,7 @@
 /* Dummy routine */
 static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs4_client *clp)
 {
-	uint32_t *p;
+	__be32 *p;
 	uint32_t strlen;
 	char *str;
 
@@ -2096,7 +2096,8 @@
 
 static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
 {
-	uint32_t bmlen, *p;
+	uint32_t bmlen;
+	__be32 *p;
 
 	READ_BUF(4);
 	READ32(bmlen);
@@ -2111,9 +2112,9 @@
 	return 0;
 }
 
-static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, uint32_t **savep)
+static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 **savep)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	READ_BUF(4);
 	READ32(*attrlen);
@@ -2134,7 +2135,7 @@
 
 static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	*type = 0;
 	if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U)))
@@ -2154,7 +2155,7 @@
 
 static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	*change = 0;
 	if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U)))
@@ -2171,7 +2172,7 @@
 
 static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	*size = 0;
 	if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U)))
@@ -2187,7 +2188,7 @@
 
 static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	*res = 0;
 	if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U)))
@@ -2203,7 +2204,7 @@
 
 static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	*res = 0;
 	if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U)))
@@ -2219,7 +2220,7 @@
 
 static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fsid *fsid)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	fsid->major = 0;
 	fsid->minor = 0;
@@ -2239,7 +2240,7 @@
 
 static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	*res = 60;
 	if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U)))
@@ -2255,7 +2256,7 @@
 
 static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	*res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL;
 	if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U)))
@@ -2271,7 +2272,7 @@
 
 static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	*fileid = 0;
 	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
@@ -2287,7 +2288,7 @@
 
 static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
 {
-	uint32_t *p;
+	__be32 *p;
 	int status = 0;
 
 	*res = 0;
@@ -2304,7 +2305,7 @@
 
 static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
 {
-	uint32_t *p;
+	__be32 *p;
 	int status = 0;
 
 	*res = 0;
@@ -2321,7 +2322,7 @@
 
 static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
 {
-	uint32_t *p;
+	__be32 *p;
 	int status = 0;
 
 	*res = 0;
@@ -2338,7 +2339,7 @@
 
 static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
 {
-	uint32_t *p;
+	__be32 *p;
 	int status = 0;
 
 	*res = 0;
@@ -2355,7 +2356,7 @@
 
 static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink)
 {
-	uint32_t *p;
+	__be32 *p;
 	int status = 0;
 
 	*maxlink = 1;
@@ -2372,7 +2373,7 @@
 
 static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname)
 {
-	uint32_t *p;
+	__be32 *p;
 	int status = 0;
 
 	*maxname = 1024;
@@ -2389,7 +2390,7 @@
 
 static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
 {
-	uint32_t *p;
+	__be32 *p;
 	int status = 0;
 
 	*res = 1024;
@@ -2410,7 +2411,7 @@
 
 static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
 {
-	uint32_t *p;
+	__be32 *p;
 	int status = 0;
 
 	*res = 1024;
@@ -2431,7 +2432,7 @@
 
 static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *mode)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	*mode = 0;
 	if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U)))
@@ -2448,7 +2449,7 @@
 
 static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	*nlink = 1;
 	if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U)))
@@ -2464,7 +2465,8 @@
 
 static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *uid)
 {
-	uint32_t len, *p;
+	uint32_t len;
+	__be32 *p;
 
 	*uid = -2;
 	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
@@ -2488,7 +2490,8 @@
 
 static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *gid)
 {
-	uint32_t len, *p;
+	uint32_t len;
+	__be32 *p;
 
 	*gid = -2;
 	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
@@ -2512,7 +2515,8 @@
 
 static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
 {
-	uint32_t major = 0, minor = 0, *p;
+	uint32_t major = 0, minor = 0;
+	__be32 *p;
 
 	*rdev = MKDEV(0,0);
 	if (unlikely(bitmap[1] & (FATTR4_WORD1_RAWDEV - 1U)))
@@ -2534,7 +2538,7 @@
 
 static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
 {
-	uint32_t *p;
+	__be32 *p;
 	int status = 0;
 
 	*res = 0;
@@ -2551,7 +2555,7 @@
 
 static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
 {
-	uint32_t *p;
+	__be32 *p;
 	int status = 0;
 
 	*res = 0;
@@ -2568,7 +2572,7 @@
 
 static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
 {
-	uint32_t *p;
+	__be32 *p;
 	int status = 0;
 
 	*res = 0;
@@ -2585,7 +2589,7 @@
 
 static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	*used = 0;
 	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U)))
@@ -2602,7 +2606,7 @@
 
 static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
 {
-	uint32_t *p;
+	__be32 *p;
 	uint64_t sec;
 	uint32_t nsec;
 
@@ -2662,7 +2666,7 @@
 	return status;
 }
 
-static int verify_attr_len(struct xdr_stream *xdr, uint32_t *savep, uint32_t attrlen)
+static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen)
 {
 	unsigned int attrwords = XDR_QUADLEN(attrlen);
 	unsigned int nwords = xdr->p - savep;
@@ -2680,7 +2684,7 @@
 
 static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
 {
-	uint32_t *p;
+	__be32 *p;
 
 	READ_BUF(20);
 	READ32(cinfo->atomic);
@@ -2691,7 +2695,7 @@
 
 static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
 {
-	uint32_t *p;
+	__be32 *p;
 	uint32_t supp, acc;
 	int status;
 
@@ -2708,7 +2712,7 @@
 
 static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
 {
-	uint32_t *p;
+	__be32 *p;
 	int status;
 
 	status = decode_op_hdr(xdr, OP_CLOSE);
@@ -2721,7 +2725,7 @@
 
 static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
 {
-	uint32_t *p;
+	__be32 *p;
 	int status;
 
 	status = decode_op_hdr(xdr, OP_COMMIT);
@@ -2734,7 +2738,7 @@
 
 static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
 {
-	uint32_t *p;
+	__be32 *p;
 	uint32_t bmlen;
 	int status;
 
@@ -2751,7 +2755,7 @@
 
 static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
 {
-	uint32_t *savep;
+	__be32 *savep;
 	uint32_t attrlen, 
 		 bitmap[2] = {0};
 	int status;
@@ -2778,7 +2782,7 @@
 	
 static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
 {
-	uint32_t *savep;
+	__be32 *savep;
 	uint32_t attrlen, 
 		 bitmap[2] = {0};
 	int status;
@@ -2811,7 +2815,7 @@
 
 static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
 {
-	uint32_t *savep;
+	__be32 *savep;
 	uint32_t attrlen, 
 		 bitmap[2] = {0};
 	int status;
@@ -2836,7 +2840,7 @@
 
 static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, const struct nfs_server *server)
 {
-	uint32_t *savep;
+	__be32 *savep;
 	uint32_t attrlen,
 		 bitmap[2] = {0},
 		 type;
@@ -2896,7 +2900,7 @@
 
 static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
 {
-	uint32_t *savep;
+	__be32 *savep;
 	uint32_t attrlen, bitmap[2];
 	int status;
 
@@ -2928,7 +2932,7 @@
 
 static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
 {
-	uint32_t *p;
+	__be32 *p;
 	uint32_t len;
 	int status;
 
@@ -2964,7 +2968,7 @@
 static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
 {
 	uint64_t offset, length, clientid;
-	uint32_t *p;
+	__be32 *p;
 	uint32_t namelen, type;
 
 	READ_BUF(32);
@@ -2989,7 +2993,7 @@
 
 static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res)
 {
-	uint32_t *p;
+	__be32 *p;
 	int status;
 
 	status = decode_op_hdr(xdr, OP_LOCK);
@@ -3012,7 +3016,7 @@
 
 static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res)
 {
-	uint32_t *p;
+	__be32 *p;
 	int status;
 
 	status = decode_op_hdr(xdr, OP_LOCKU);
@@ -3031,7 +3035,7 @@
 /* This is too sick! */
 static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize)
 {
-        uint32_t *p;
+        __be32 *p;
 	uint32_t limit_type, nblocks, blocksize;
 
 	READ_BUF(12);
@@ -3050,7 +3054,7 @@
 
 static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
 {
-        uint32_t *p;
+        __be32 *p;
         uint32_t delegation_type;
 
 	READ_BUF(4);
@@ -3076,7 +3080,7 @@
 
 static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
 {
-        uint32_t *p;
+        __be32 *p;
         uint32_t bmlen;
         int status;
 
@@ -3104,7 +3108,7 @@
 
 static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res)
 {
-        uint32_t *p;
+        __be32 *p;
 	int status;
 
         status = decode_op_hdr(xdr, OP_OPEN_CONFIRM);
@@ -3117,7 +3121,7 @@
 
 static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res)
 {
-	uint32_t *p;
+	__be32 *p;
 	int status;
 
 	status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE);
@@ -3141,7 +3145,7 @@
 static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res)
 {
 	struct kvec *iov = req->rq_rcv_buf.head;
-	uint32_t *p;
+	__be32 *p;
 	uint32_t count, eof, recvd, hdrlen;
 	int status;
 
@@ -3171,7 +3175,7 @@
 	struct page	*page = *rcvbuf->pages;
 	struct kvec	*iov = rcvbuf->head;
 	unsigned int	nr, pglen = rcvbuf->page_len;
-	uint32_t	*end, *entry, *p, *kaddr;
+	__be32		*end, *entry, *p, *kaddr;
 	uint32_t	len, attrlen;
 	int 		hdrlen, recvd, status;
 
@@ -3193,8 +3197,8 @@
 	xdr_read_pages(xdr, pglen);
 
 	BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE);
-	kaddr = p = (uint32_t *) kmap_atomic(page, KM_USER0);
-	end = (uint32_t *) ((char *)p + pglen + readdir->pgbase);
+	kaddr = p = kmap_atomic(page, KM_USER0);
+	end = (__be32 *) ((char *)p + pglen + readdir->pgbase);
 	entry = p;
 	for (nr = 0; *p++; nr++) {
 		if (p + 3 > end)
@@ -3244,7 +3248,7 @@
 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 	struct kvec *iov = rcvbuf->head;
 	int hdrlen, len, recvd;
-	uint32_t *p;
+	__be32 *p;
 	char *kaddr;
 	int status;
 
@@ -3321,7 +3325,7 @@
 static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
 		size_t *acl_len)
 {
-	uint32_t *savep;
+	__be32 *savep;
 	uint32_t attrlen,
 		 bitmap[2] = {0};
 	struct kvec *iov = req->rq_rcv_buf.head;
@@ -3368,7 +3372,7 @@
 
 static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
 {
-	uint32_t *p;
+	__be32 *p;
 	uint32_t bmlen;
 	int status;
 
@@ -3384,7 +3388,7 @@
 
 static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp)
 {
-	uint32_t *p;
+	__be32 *p;
 	uint32_t opnum;
 	int32_t nfserr;
 
@@ -3427,7 +3431,7 @@
 
 static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
 {
-	uint32_t *p;
+	__be32 *p;
 	int status;
 
 	status = decode_op_hdr(xdr, OP_WRITE);
@@ -3449,7 +3453,7 @@
 /*
  * Decode OPEN_DOWNGRADE response
  */
-static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
+static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr;
@@ -3477,7 +3481,7 @@
 /*
  * Decode ACCESS response
  */
-static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_accessres *res)
+static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_accessres *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -3495,7 +3499,7 @@
 /*
  * Decode LOOKUP response
  */
-static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_lookup_res *res)
+static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -3518,7 +3522,7 @@
 /*
  * Decode LOOKUP_ROOT response
  */
-static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_lookup_res *res)
+static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -3538,7 +3542,7 @@
 /*
  * Decode REMOVE response
  */
-static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_remove_res *res)
+static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_remove_res *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -3559,7 +3563,7 @@
 /*
  * Decode RENAME response
  */
-static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_rename_res *res)
+static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_rename_res *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -3589,7 +3593,7 @@
 /*
  * Decode LINK response
  */
-static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_link_res *res)
+static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link_res *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -3622,7 +3626,7 @@
 /*
  * Decode CREATE response
  */
-static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_create_res *res)
+static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -3651,7 +3655,7 @@
 /*
  * Decode SYMLINK response
  */
-static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_create_res *res)
+static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
 {
 	return nfs4_xdr_dec_create(rqstp, p, res);
 }
@@ -3659,7 +3663,7 @@
 /*
  * Decode GETATTR response
  */
-static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_getattr_res *res)
+static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_getattr_res *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -3682,7 +3686,7 @@
  * Encode an SETACL request
  */
 static int
-nfs4_xdr_enc_setacl(struct rpc_rqst *req, uint32_t *p, struct nfs_setaclargs *args)
+nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr = {
@@ -3703,7 +3707,7 @@
  * Decode SETACL response
  */
 static int
-nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, uint32_t *p, void *res)
+nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -3725,7 +3729,7 @@
  * Decode GETACL response
  */
 static int
-nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, uint32_t *p, size_t *acl_len)
+nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -3747,7 +3751,7 @@
 /*
  * Decode CLOSE response
  */
-static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
+static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr;
@@ -3777,7 +3781,7 @@
 /*
  * Decode OPEN response
  */
-static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
+static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr;
@@ -3811,7 +3815,7 @@
 /*
  * Decode OPEN_CONFIRM response
  */
-static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_open_confirmres *res)
+static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, __be32 *p, struct nfs_open_confirmres *res)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr;
@@ -3832,7 +3836,7 @@
 /*
  * Decode OPEN response
  */
-static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
+static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr;
@@ -3856,7 +3860,7 @@
 /*
  * Decode SETATTR response
  */
-static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres *res)
+static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_setattrres *res)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr;
@@ -3882,7 +3886,7 @@
 /*
  * Decode LOCK response
  */
-static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lock_res *res)
+static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock_res *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -3903,7 +3907,7 @@
 /*
  * Decode LOCKT response
  */
-static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockt_res *res)
+static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lockt_res *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -3924,7 +3928,7 @@
 /*
  * Decode LOCKU response
  */
-static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_locku_res *res)
+static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_locku_res *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -3945,7 +3949,7 @@
 /*
  * Decode READLINK response
  */
-static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, uint32_t *p, void *res)
+static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, void *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -3966,7 +3970,7 @@
 /*
  * Decode READDIR response
  */
-static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_readdir_res *res)
+static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_readdir_res *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -3987,7 +3991,7 @@
 /*
  * Decode Read response
  */
-static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_readres *res)
+static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, __be32 *p, struct nfs_readres *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -4010,7 +4014,7 @@
 /*
  * Decode WRITE response
  */
-static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res)
+static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -4036,7 +4040,7 @@
 /*
  * Decode COMMIT response
  */
-static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res)
+static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -4060,7 +4064,7 @@
 /*
  * FSINFO request
  */
-static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo)
+static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -4080,7 +4084,7 @@
 /*
  * PATHCONF request
  */
-static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, uint32_t *p, struct nfs_pathconf *pathconf)
+static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *pathconf)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -4098,7 +4102,7 @@
 /*
  * STATFS request
  */
-static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, uint32_t *p, struct nfs_fsstat *fsstat)
+static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *fsstat)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -4116,7 +4120,7 @@
 /*
  * GETATTR_BITMAP request
  */
-static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, uint32_t *p, struct nfs4_server_caps_res *res)
+static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4_server_caps_res *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -4135,7 +4139,7 @@
 /*
  * Decode RENEW response
  */
-static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy)
+static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, __be32 *p, void *dummy)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -4151,7 +4155,7 @@
 /*
  * a SETCLIENTID request
  */
-static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p,
+static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p,
 		struct nfs4_client *clp)
 {
 	struct xdr_stream xdr;
@@ -4170,7 +4174,7 @@
 /*
  * a SETCLIENTID_CONFIRM request
  */
-static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo)
+static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -4192,7 +4196,7 @@
 /*
  * DELEGRETURN request
  */
-static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_delegreturnres *res)
+static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_delegreturnres *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -4211,7 +4215,7 @@
 	return status;
 }
 
-uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
+__be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
 {
 	uint32_t bitmap[2] = {0};
 	uint32_t len;
diff -urN oldtree/fs/nfs/proc.c newtree/fs/nfs/proc.c
--- oldtree/fs/nfs/proc.c	2006-02-19 11:41:05.171556904 +0000
+++ newtree/fs/nfs/proc.c	2006-02-21 15:58:36.658573608 +0000
@@ -548,7 +548,7 @@
 	return 0;
 }
 
-extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
+extern __be32 * nfs_decode_dirent(__be32 *, struct nfs_entry *, int);
 
 static void nfs_read_done(struct rpc_task *task, void *calldata)
 {
diff -urN oldtree/fs/nfs/read.c newtree/fs/nfs/read.c
--- oldtree/fs/nfs/read.c	2006-02-19 11:41:05.171556904 +0000
+++ newtree/fs/nfs/read.c	2006-02-21 15:58:30.956440464 +0000
@@ -597,10 +597,8 @@
 	if (nfs_rdata_cachep == NULL)
 		return -ENOMEM;
 
-	nfs_rdata_mempool = mempool_create(MIN_POOL_READ,
-					   mempool_alloc_slab,
-					   mempool_free_slab,
-					   nfs_rdata_cachep);
+	nfs_rdata_mempool = mempool_create_slab_pool(MIN_POOL_READ,
+						     nfs_rdata_cachep);
 	if (nfs_rdata_mempool == NULL)
 		return -ENOMEM;
 
diff -urN oldtree/fs/nfs/write.c newtree/fs/nfs/write.c
--- oldtree/fs/nfs/write.c	2006-02-19 11:41:05.173556600 +0000
+++ newtree/fs/nfs/write.c	2006-02-21 15:58:30.959440008 +0000
@@ -1407,17 +1407,13 @@
 	if (nfs_wdata_cachep == NULL)
 		return -ENOMEM;
 
-	nfs_wdata_mempool = mempool_create(MIN_POOL_WRITE,
-					   mempool_alloc_slab,
-					   mempool_free_slab,
-					   nfs_wdata_cachep);
+	nfs_wdata_mempool = mempool_create_slab_pool(MIN_POOL_WRITE,
+						     nfs_wdata_cachep);
 	if (nfs_wdata_mempool == NULL)
 		return -ENOMEM;
 
-	nfs_commit_mempool = mempool_create(MIN_POOL_COMMIT,
-					   mempool_alloc_slab,
-					   mempool_free_slab,
-					   nfs_wdata_cachep);
+	nfs_commit_mempool = mempool_create_slab_pool(MIN_POOL_COMMIT,
+						      nfs_wdata_cachep);
 	if (nfs_commit_mempool == NULL)
 		return -ENOMEM;
 
diff -urN oldtree/fs/nfs_common/nfsacl.c newtree/fs/nfs_common/nfsacl.c
--- oldtree/fs/nfs_common/nfsacl.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/nfs_common/nfsacl.c	2006-02-21 15:58:36.575586224 +0000
@@ -46,7 +46,7 @@
 {
 	struct nfsacl_encode_desc *nfsacl_desc =
 		(struct nfsacl_encode_desc *) desc;
-	u32 *p = (u32 *) elem;
+	__be32 *p = elem;
 
 	struct posix_acl_entry *entry =
 		&nfsacl_desc->acl->a_entries[nfsacl_desc->count++];
@@ -127,7 +127,7 @@
 {
 	struct nfsacl_decode_desc *nfsacl_desc =
 		(struct nfsacl_decode_desc *) desc;
-	u32 *p = (u32 *) elem;
+	__be32 *p = elem;
 	struct posix_acl_entry *entry;
 
 	if (!nfsacl_desc->acl) {
diff -urN oldtree/fs/nfsd/export.c newtree/fs/nfsd/export.c
--- oldtree/fs/nfsd/export.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/nfsd/export.c	2006-02-21 15:58:36.583585008 +0000
@@ -917,12 +917,12 @@
  * for a given NFSv4 client.   The root is defined to be the
  * export point with fsid==0
  */
-int
+__be32
 exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
 	       struct cache_req *creq)
 {
 	struct svc_expkey *fsid_key;
-	int rv;
+	__be32 rv;
 	u32 fsidv[2];
 
 	mk_fsid_v1(fsidv, 0);
diff -urN oldtree/fs/nfsd/lockd.c newtree/fs/nfsd/lockd.c
--- oldtree/fs/nfsd/lockd.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/nfsd/lockd.c	2006-02-21 15:58:36.585584704 +0000
@@ -25,7 +25,7 @@
 static u32
 nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp)
 {
-	u32		nfserr;
+	__be32		nfserr;
 	struct svc_fh	fh;
 
 	/* must initialize before using! but maxsize doesn't matter */
diff -urN oldtree/fs/nfsd/nfs2acl.c newtree/fs/nfsd/nfs2acl.c
--- oldtree/fs/nfsd/nfs2acl.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/nfsd/nfs2acl.c	2006-02-21 15:58:36.586584552 +0000
@@ -21,7 +21,7 @@
 /*
  * NULL call.
  */
-static int
+static __be32
 nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
 {
 	return nfs_ok;
@@ -30,12 +30,12 @@
 /*
  * Get the Access and/or Default ACL of a file.
  */
-static int nfsacld_proc_getacl(struct svc_rqst * rqstp,
+static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp,
 		struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
 {
 	svc_fh *fh;
 	struct posix_acl *acl;
-	int nfserr = 0;
+	__be32 nfserr = 0;
 
 	dprintk("nfsd: GETACL(2acl)   %s\n", SVCFH_fmt(&argp->fh));
 
@@ -97,12 +97,12 @@
 /*
  * Set the Access and/or Default ACL of a file.
  */
-static int nfsacld_proc_setacl(struct svc_rqst * rqstp,
+static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp,
 		struct nfsd3_setaclargs *argp,
 		struct nfsd_attrstat *resp)
 {
 	svc_fh *fh;
-	int nfserr = 0;
+	__be32 nfserr = 0;
 
 	dprintk("nfsd: SETACL(2acl)   %s\n", SVCFH_fmt(&argp->fh));
 
@@ -128,7 +128,7 @@
 /*
  * Check file attributes
  */
-static int nfsacld_proc_getattr(struct svc_rqst * rqstp,
+static __be32 nfsacld_proc_getattr(struct svc_rqst * rqstp,
 		struct nfsd_fhandle *argp, struct nfsd_attrstat *resp)
 {
 	dprintk("nfsd: GETATTR  %s\n", SVCFH_fmt(&argp->fh));
@@ -140,10 +140,10 @@
 /*
  * Check file access
  */
-static int nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
+static __be32 nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
 		struct nfsd3_accessres *resp)
 {
-	int nfserr;
+	__be32 nfserr;
 
 	dprintk("nfsd: ACCESS(2acl)   %s 0x%x\n",
 			SVCFH_fmt(&argp->fh),
@@ -158,7 +158,7 @@
 /*
  * XDR decode functions
  */
-static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p,
+static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p,
 		struct nfsd3_getaclargs *argp)
 {
 	if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
@@ -169,7 +169,7 @@
 }
 
 
-static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p,
+static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p,
 		struct nfsd3_setaclargs *argp)
 {
 	struct kvec *head = rqstp->rq_arg.head;
@@ -194,7 +194,7 @@
 	return (n > 0);
 }
 
-static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, u32 *p,
+static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p,
 		struct nfsd_fhandle *argp)
 {
 	if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
@@ -202,7 +202,7 @@
 	return xdr_argsize_check(rqstp, p);
 }
 
-static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
+static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p,
 		struct nfsd3_accessargs *argp)
 {
 	if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
@@ -217,7 +217,7 @@
  */
 
 /* GETACL */
-static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,
+static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
 		struct nfsd3_getaclres *resp)
 {
 	struct dentry *dentry = resp->fh.fh_dentry;
@@ -259,7 +259,7 @@
 	return 1;
 }
 
-static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, u32 *p,
+static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p,
 		struct nfsd_attrstat *resp)
 {
 	p = nfs2svc_encode_fattr(rqstp, p, &resp->fh);
@@ -267,7 +267,7 @@
 }
 
 /* ACCESS */
-static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
+static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p,
 		struct nfsd3_accessres *resp)
 {
 	p = nfs2svc_encode_fattr(rqstp, p, &resp->fh);
@@ -278,7 +278,7 @@
 /*
  * XDR release functions
  */
-static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, u32 *p,
+static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, __be32 *p,
 		struct nfsd3_getaclres *resp)
 {
 	fh_put(&resp->fh);
@@ -287,7 +287,7 @@
 	return 1;
 }
 
-static int nfsaclsvc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
+static int nfsaclsvc_release_fhandle(struct svc_rqst *rqstp, __be32 *p,
 		struct nfsd_fhandle *resp)
 {
 	fh_put(&resp->fh);
diff -urN oldtree/fs/nfsd/nfs3acl.c newtree/fs/nfsd/nfs3acl.c
--- oldtree/fs/nfsd/nfs3acl.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/nfsd/nfs3acl.c	2006-02-21 15:58:36.587584400 +0000
@@ -19,7 +19,7 @@
 /*
  * NULL call.
  */
-static int
+static __be32
 nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
 {
 	return nfs_ok;
@@ -28,12 +28,12 @@
 /*
  * Get the Access and/or Default ACL of a file.
  */
-static int nfsd3_proc_getacl(struct svc_rqst * rqstp,
+static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp,
 		struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
 {
 	svc_fh *fh;
 	struct posix_acl *acl;
-	int nfserr = 0;
+	__be32 nfserr = 0;
 
 	fh = fh_copy(&resp->fh, &argp->fh);
 	if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP)))
@@ -93,12 +93,12 @@
 /*
  * Set the Access and/or Default ACL of a file.
  */
-static int nfsd3_proc_setacl(struct svc_rqst * rqstp,
+static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp,
 		struct nfsd3_setaclargs *argp,
 		struct nfsd3_attrstat *resp)
 {
 	svc_fh *fh;
-	int nfserr = 0;
+	__be32 nfserr = 0;
 
 	fh = fh_copy(&resp->fh, &argp->fh);
 	nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_SATTR);
@@ -122,7 +122,7 @@
 /*
  * XDR decode functions
  */
-static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p,
+static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p,
 		struct nfsd3_getaclargs *args)
 {
 	if (!(p = nfs3svc_decode_fh(p, &args->fh)))
@@ -133,7 +133,7 @@
 }
 
 
-static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p,
+static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p,
 		struct nfsd3_setaclargs *args)
 {
 	struct kvec *head = rqstp->rq_arg.head;
@@ -163,7 +163,7 @@
  */
 
 /* GETACL */
-static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,
+static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
 		struct nfsd3_getaclres *resp)
 {
 	struct dentry *dentry = resp->fh.fh_dentry;
@@ -208,7 +208,7 @@
 }
 
 /* SETACL */
-static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, u32 *p,
+static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, __be32 *p,
 		struct nfsd3_attrstat *resp)
 {
 	p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
@@ -219,7 +219,7 @@
 /*
  * XDR release functions
  */
-static int nfs3svc_release_getacl(struct svc_rqst *rqstp, u32 *p,
+static int nfs3svc_release_getacl(struct svc_rqst *rqstp, __be32 *p,
 		struct nfsd3_getaclres *resp)
 {
 	fh_put(&resp->fh);
diff -urN oldtree/fs/nfsd/nfs3proc.c newtree/fs/nfsd/nfs3proc.c
--- oldtree/fs/nfsd/nfs3proc.c	2006-02-19 11:41:05.174556448 +0000
+++ newtree/fs/nfsd/nfs3proc.c	2006-02-21 15:58:36.589584096 +0000
@@ -43,7 +43,7 @@
 /*
  * NULL call.
  */
-static int
+static __be32
 nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
 {
 	return nfs_ok;
@@ -52,11 +52,12 @@
 /*
  * Get a file's attributes
  */
-static int
+static __be32
 nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle  *argp,
 					   struct nfsd3_attrstat *resp)
 {
-	int	err, nfserr;
+	int	err;
+	__be32	nfserr;
 
 	dprintk("nfsd: GETATTR(3)  %s\n",
 		SVCFH_fmt(&argp->fh));
@@ -76,11 +77,11 @@
 /*
  * Set a file's attributes
  */
-static int
+static __be32
 nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp,
 					   struct nfsd3_attrstat  *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: SETATTR(3)  %s\n",
 				SVCFH_fmt(&argp->fh));
@@ -94,11 +95,11 @@
 /*
  * Look up a path name component
  */
-static int
+static __be32
 nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
 					  struct nfsd3_diropres  *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: LOOKUP(3)   %s %.*s\n",
 				SVCFH_fmt(&argp->fh),
@@ -118,11 +119,11 @@
 /*
  * Check file access
  */
-static int
+static __be32
 nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
 					  struct nfsd3_accessres *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: ACCESS(3)   %s 0x%x\n",
 				SVCFH_fmt(&argp->fh),
@@ -137,11 +138,11 @@
 /*
  * Read a symlink.
  */
-static int
+static __be32
 nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp,
 					   struct nfsd3_readlinkres *resp)
 {
-	int nfserr;
+	__be32 nfserr;
 
 	dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
 
@@ -155,11 +156,11 @@
 /*
  * Read a portion of a file.
  */
-static int
+static __be32
 nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
 				        struct nfsd3_readres  *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: READ(3) %s %lu bytes at %lu\n",
 				SVCFH_fmt(&argp->fh),
@@ -194,11 +195,11 @@
 /*
  * Write data to a file
  */
-static int
+static __be32
 nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
 					 struct nfsd3_writeres  *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: WRITE(3)    %s %d bytes at %ld%s\n",
 				SVCFH_fmt(&argp->fh),
@@ -222,13 +223,13 @@
  * At least in theory; we'll see how it fares in practice when the
  * first reports about SunOS compatibility problems start to pour in...
  */
-static int
+static __be32
 nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
 					  struct nfsd3_diropres   *resp)
 {
 	svc_fh		*dirfhp, *newfhp = NULL;
 	struct iattr	*attr;
-	u32		nfserr;
+	__be32		nfserr;
 
 	dprintk("nfsd: CREATE(3)   %s %.*s\n",
 				SVCFH_fmt(&argp->fh),
@@ -264,11 +265,11 @@
 /*
  * Make directory. This operation is not idempotent.
  */
-static int
+static __be32
 nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
 					 struct nfsd3_diropres   *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: MKDIR(3)    %s %.*s\n",
 				SVCFH_fmt(&argp->fh),
@@ -284,11 +285,11 @@
 	RETURN_STATUS(nfserr);
 }
 
-static int
+static __be32
 nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
 					   struct nfsd3_diropres    *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: SYMLINK(3)  %s %.*s -> %.*s\n",
 				SVCFH_fmt(&argp->ffh),
@@ -306,11 +307,12 @@
 /*
  * Make socket/fifo/device.
  */
-static int
+static __be32
 nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp,
 					 struct nfsd3_diropres  *resp)
 {
-	int	nfserr, type;
+	__be32	nfserr;
+	int type;
 	dev_t	rdev = 0;
 
 	dprintk("nfsd: MKNOD(3)    %s %.*s\n",
@@ -342,11 +344,11 @@
 /*
  * Remove file/fifo/socket etc.
  */
-static int
+static __be32
 nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
 					  struct nfsd3_attrstat  *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: REMOVE(3)   %s %.*s\n",
 				SVCFH_fmt(&argp->fh),
@@ -362,11 +364,11 @@
 /*
  * Remove a directory
  */
-static int
+static __be32
 nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
 					 struct nfsd3_attrstat  *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: RMDIR(3)    %s %.*s\n",
 				SVCFH_fmt(&argp->fh),
@@ -378,11 +380,11 @@
 	RETURN_STATUS(nfserr);
 }
 
-static int
+static __be32
 nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp,
 					  struct nfsd3_renameres  *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: RENAME(3)   %s %.*s ->\n",
 				SVCFH_fmt(&argp->ffh),
@@ -400,11 +402,11 @@
 	RETURN_STATUS(nfserr);
 }
 
-static int
+static __be32
 nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp,
 					struct nfsd3_linkres  *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: LINK(3)     %s ->\n",
 				SVCFH_fmt(&argp->ffh));
@@ -423,11 +425,12 @@
 /*
  * Read a portion of a directory.
  */
-static int
+static __be32
 nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
 					   struct nfsd3_readdirres  *resp)
 {
-	int		nfserr, count;
+	__be32		nfserr;
+	int		count;
 
 	dprintk("nfsd: READDIR(3)  %s %d bytes at %d\n",
 				SVCFH_fmt(&argp->fh),
@@ -458,11 +461,12 @@
  * Read a portion of a directory, including file handles and attrs.
  * For now, we choose to ignore the dircount parameter.
  */
-static int
+static __be32
 nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
 					       struct nfsd3_readdirres  *resp)
 {
-	int	nfserr, count = 0;
+	__be32	nfserr;
+	int	count = 0;
 	loff_t	offset;
 	int	i;
 	caddr_t	page_addr = NULL;
@@ -516,11 +520,11 @@
 /*
  * Get file system stats
  */
-static int
+static __be32
 nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle    *argp,
 					   struct nfsd3_fsstatres *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: FSSTAT(3)   %s\n",
 				SVCFH_fmt(&argp->fh));
@@ -533,11 +537,11 @@
 /*
  * Get file system info
  */
-static int
+static __be32
 nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle    *argp,
 					   struct nfsd3_fsinfores *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: FSINFO(3)   %s\n",
 				SVCFH_fmt(&argp->fh));
@@ -574,11 +578,11 @@
 /*
  * Get pathconf info for the specified file
  */
-static int
+static __be32
 nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle      *argp,
 					     struct nfsd3_pathconfres *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: PATHCONF(3) %s\n",
 				SVCFH_fmt(&argp->fh));
@@ -617,11 +621,11 @@
 /*
  * Commit a file (range) to stable storage.
  */
-static int
+static __be32
 nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp,
 					   struct nfsd3_commitres  *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: COMMIT(3)   %s %u@%Lu\n",
 				SVCFH_fmt(&argp->fh),
diff -urN oldtree/fs/nfsd/nfs3xdr.c newtree/fs/nfsd/nfs3xdr.c
--- oldtree/fs/nfsd/nfs3xdr.c	2006-02-19 11:41:05.175556296 +0000
+++ newtree/fs/nfsd/nfs3xdr.c	2006-02-21 15:58:36.591583792 +0000
@@ -42,23 +42,23 @@
 /*
  * XDR functions for basic NFS types
  */
-static inline u32 *
-encode_time3(u32 *p, struct timespec *time)
+static inline __be32 *
+encode_time3(__be32 *p, struct timespec *time)
 {
 	*p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec);
 	return p;
 }
 
-static inline u32 *
-decode_time3(u32 *p, struct timespec *time)
+static inline __be32 *
+decode_time3(__be32 *p, struct timespec *time)
 {
 	time->tv_sec = ntohl(*p++);
 	time->tv_nsec = ntohl(*p++);
 	return p;
 }
 
-static inline u32 *
-decode_fh(u32 *p, struct svc_fh *fhp)
+static inline __be32 *
+decode_fh(__be32 *p, struct svc_fh *fhp)
 {
 	unsigned int size;
 	fh_init(fhp, NFS3_FHSIZE);
@@ -72,13 +72,13 @@
 }
 
 /* Helper function for NFSv3 ACL code */
-u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp)
+__be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp)
 {
 	return decode_fh(p, fhp);
 }
 
-static inline u32 *
-encode_fh(u32 *p, struct svc_fh *fhp)
+static inline __be32 *
+encode_fh(__be32 *p, struct svc_fh *fhp)
 {
 	unsigned int size = fhp->fh_handle.fh_size;
 	*p++ = htonl(size);
@@ -91,8 +91,8 @@
  * Decode a file name and make sure that the path contains
  * no slashes or null bytes.
  */
-static inline u32 *
-decode_filename(u32 *p, char **namp, int *lenp)
+static inline __be32 *
+decode_filename(__be32 *p, char **namp, int *lenp)
 {
 	char		*name;
 	int		i;
@@ -107,8 +107,8 @@
 	return p;
 }
 
-static inline u32 *
-decode_sattr3(u32 *p, struct iattr *iap)
+static inline __be32 *
+decode_sattr3(__be32 *p, struct iattr *iap)
 {
 	u32	tmp;
 
@@ -153,8 +153,8 @@
 	return p;
 }
 
-static inline u32 *
-encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp,
+static inline __be32 *
+encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
 	      struct kstat *stat)
 {
 	struct dentry	*dentry = fhp->fh_dentry;
@@ -186,8 +186,8 @@
 	return p;
 }
 
-static inline u32 *
-encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
+static inline __be32 *
+encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
 {
 	struct inode	*inode = fhp->fh_dentry->d_inode;
 
@@ -224,8 +224,8 @@
  * The inode may be NULL if the call failed because of a stale file
  * handle. In this case, no attributes are returned.
  */
-static u32 *
-encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
+static __be32 *
+encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
 {
 	struct dentry *dentry = fhp->fh_dentry;
 	if (dentry && dentry->d_inode != NULL) {
@@ -243,8 +243,8 @@
 }
 
 /* Helper for NFSv3 ACLs */
-u32 *
-nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
+__be32 *
+nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
 {
 	return encode_post_op_attr(rqstp, p, fhp);
 }
@@ -252,8 +252,8 @@
 /*
  * Enocde weak cache consistency data
  */
-static u32 *
-encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
+static __be32 *
+encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
 {
 	struct dentry	*dentry = fhp->fh_dentry;
 
@@ -278,7 +278,7 @@
  * XDR decode functions
  */
 int
-nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args)
+nfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *args)
 {
 	if (!(p = decode_fh(p, &args->fh)))
 		return 0;
@@ -286,7 +286,7 @@
 }
 
 int
-nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_sattrargs *args)
 {
 	if (!(p = decode_fh(p, &args->fh))
@@ -303,7 +303,7 @@
 }
 
 int
-nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_diropargs *args)
 {
 	if (!(p = decode_fh(p, &args->fh))
@@ -314,7 +314,7 @@
 }
 
 int
-nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_accessargs *args)
 {
 	if (!(p = decode_fh(p, &args->fh)))
@@ -325,7 +325,7 @@
 }
 
 int
-nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_readargs *args)
 {
 	unsigned int len;
@@ -355,7 +355,7 @@
 }
 
 int
-nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_writeargs *args)
 {
 	unsigned int len, v, hdr;
@@ -392,7 +392,7 @@
 }
 
 int
-nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_createargs *args)
 {
 	if (!(p = decode_fh(p, &args->fh))
@@ -416,7 +416,7 @@
 	return xdr_argsize_check(rqstp, p);
 }
 int
-nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_createargs *args)
 {
 	if (!(p = decode_fh(p, &args->fh))
@@ -428,7 +428,7 @@
 }
 
 int
-nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_symlinkargs *args)
 {
 	unsigned int len;
@@ -480,7 +480,7 @@
 }
 
 int
-nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_mknodargs *args)
 {
 	if (!(p = decode_fh(p, &args->fh))
@@ -504,7 +504,7 @@
 }
 
 int
-nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_renameargs *args)
 {
 	if (!(p = decode_fh(p, &args->ffh))
@@ -517,7 +517,7 @@
 }
 
 int
-nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_readlinkargs *args)
 {
 	if (!(p = decode_fh(p, &args->fh)))
@@ -529,7 +529,7 @@
 }
 
 int
-nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_linkargs *args)
 {
 	if (!(p = decode_fh(p, &args->ffh))
@@ -541,7 +541,7 @@
 }
 
 int
-nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_readdirargs *args)
 {
 	if (!(p = decode_fh(p, &args->fh)))
@@ -561,7 +561,7 @@
 }
 
 int
-nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_readdirargs *args)
 {
 	int len, pn;
@@ -589,7 +589,7 @@
 }
 
 int
-nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_commitargs *args)
 {
 	if (!(p = decode_fh(p, &args->fh)))
@@ -608,14 +608,14 @@
  * will work properly.
  */
 int
-nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
+nfs3svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
 {
 	return xdr_ressize_check(rqstp, p);
 }
 
 /* GETATTR */
 int
-nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_attrstat *resp)
 {
 	if (resp->status == 0)
@@ -625,7 +625,7 @@
 
 /* SETATTR, REMOVE, RMDIR */
 int
-nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_attrstat *resp)
 {
 	p = encode_wcc_data(rqstp, p, &resp->fh);
@@ -634,7 +634,7 @@
 
 /* LOOKUP */
 int
-nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_diropres *resp)
 {
 	if (resp->status == 0) {
@@ -647,7 +647,7 @@
 
 /* ACCESS */
 int
-nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_accessres *resp)
 {
 	p = encode_post_op_attr(rqstp, p, &resp->fh);
@@ -658,7 +658,7 @@
 
 /* READLINK */
 int
-nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_readlinkres *resp)
 {
 	p = encode_post_op_attr(rqstp, p, &resp->fh);
@@ -680,7 +680,7 @@
 
 /* READ */
 int
-nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_readres *resp)
 {
 	p = encode_post_op_attr(rqstp, p, &resp->fh);
@@ -705,7 +705,7 @@
 
 /* WRITE */
 int
-nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_writeres *resp)
 {
 	p = encode_wcc_data(rqstp, p, &resp->fh);
@@ -720,7 +720,7 @@
 
 /* CREATE, MKDIR, SYMLINK, MKNOD */
 int
-nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_diropres *resp)
 {
 	if (resp->status == 0) {
@@ -734,7 +734,7 @@
 
 /* RENAME */
 int
-nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_renameres *resp)
 {
 	p = encode_wcc_data(rqstp, p, &resp->ffh);
@@ -744,7 +744,7 @@
 
 /* LINK */
 int
-nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_linkres *resp)
 {
 	p = encode_post_op_attr(rqstp, p, &resp->fh);
@@ -754,7 +754,7 @@
 
 /* READDIR */
 int
-nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_readdirres *resp)
 {
 	p = encode_post_op_attr(rqstp, p, &resp->fh);
@@ -778,8 +778,8 @@
 		return xdr_ressize_check(rqstp, p);
 }
 
-static inline u32 *
-encode_entry_baggage(struct nfsd3_readdirres *cd, u32 *p, const char *name,
+static inline __be32 *
+encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name,
 	     int namlen, ino_t ino)
 {
 	*p++ = xdr_one;				 /* mark entry present */
@@ -792,8 +792,8 @@
 	return p;
 }
 
-static inline u32 *
-encode_entryplus_baggage(struct nfsd3_readdirres *cd, u32 *p,
+static inline __be32 *
+encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p,
 		struct svc_fh *fhp)
 {
 		p = encode_post_op_attr(cd->rqstp, p, fhp);
@@ -855,7 +855,7 @@
 {
 	struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres,
 		       					common);
-	u32		*p = cd->buffer;
+	__be32		*p = cd->buffer;
 	caddr_t		curr_page_addr = NULL;
 	int		pn;		/* current page number */
 	int		slen;		/* string (name) length */
@@ -921,7 +921,7 @@
 	} else if (cd->rqstp->rq_respages[pn+1] != NULL) {
 		/* temporarily encode entry into next page, then move back to
 		 * current and next page in rq_respages[] */
-		u32 *p1, *tmp;
+		__be32 *p1, *tmp;
 		int len1, len2;
 
 		/* grab next page for temporary storage of entry */
@@ -1011,7 +1011,7 @@
 
 /* FSSTAT */
 int
-nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_fsstatres *resp)
 {
 	struct kstatfs	*s = &resp->stats;
@@ -1033,7 +1033,7 @@
 
 /* FSINFO */
 int
-nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_fsinfores *resp)
 {
 	*p++ = xdr_zero;	/* no post_op_attr */
@@ -1057,7 +1057,7 @@
 
 /* PATHCONF */
 int
-nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_pathconfres *resp)
 {
 	*p++ = xdr_zero;	/* no post_op_attr */
@@ -1076,7 +1076,7 @@
 
 /* COMMIT */
 int
-nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_commitres *resp)
 {
 	p = encode_wcc_data(rqstp, p, &resp->fh);
@@ -1092,7 +1092,7 @@
  * XDR release functions
  */
 int
-nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_release_fhandle(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_attrstat *resp)
 {
 	fh_put(&resp->fh);
@@ -1100,7 +1100,7 @@
 }
 
 int
-nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_release_fhandle2(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_fhandle_pair *resp)
 {
 	fh_put(&resp->fh1);
diff -urN oldtree/fs/nfsd/nfs4callback.c newtree/fs/nfsd/nfs4callback.c
--- oldtree/fs/nfsd/nfs4callback.c	2006-02-19 11:41:05.176556144 +0000
+++ newtree/fs/nfsd/nfs4callback.c	2006-02-21 15:58:36.591583792 +0000
@@ -86,8 +86,8 @@
 /*
 * Generic encode routines from fs/nfs/nfs4xdr.c
 */
-static inline u32 *
-xdr_writemem(u32 *p, const void *ptr, int nbytes)
+static inline __be32 *
+xdr_writemem(__be32 *p, const void *ptr, int nbytes)
 {
 	int tmp = XDR_QUADLEN(nbytes);
 	if (!tmp)
@@ -206,7 +206,7 @@
 static int
 encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr)
 {
-	u32 * p;
+	__be32 * p;
 
 	RESERVE_SPACE(16);
 	WRITE32(0);            /* tag length is always 0 */
@@ -219,7 +219,7 @@
 static int
 encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec)
 {
-	u32 *p;
+	__be32 *p;
 	int len = cb_rec->cbr_fhlen;
 
 	RESERVE_SPACE(12+sizeof(cb_rec->cbr_stateid) + len);
@@ -232,7 +232,7 @@
 }
 
 static int
-nfs4_xdr_enc_cb_null(struct rpc_rqst *req, u32 *p)
+nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p)
 {
 	struct xdr_stream xdrs, *xdr = &xdrs;
 
@@ -242,7 +242,7 @@
 }
 
 static int
-nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, u32 *p, struct nfs4_cb_recall *args)
+nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_cb_recall *args)
 {
 	struct xdr_stream xdr;
 	struct nfs4_cb_compound_hdr hdr = {
@@ -258,7 +258,7 @@
 
 static int
 decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){
-        u32 *p;
+        __be32 *p;
 
         READ_BUF(8);
         READ32(hdr->status);
@@ -273,7 +273,7 @@
 static int
 decode_cb_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
 {
-	u32 *p;
+	__be32 *p;
 	u32 op;
 	int32_t nfserr;
 
@@ -292,13 +292,13 @@
 }
 
 static int
-nfs4_xdr_dec_cb_null(struct rpc_rqst *req, u32 *p)
+nfs4_xdr_dec_cb_null(struct rpc_rqst *req, __be32 *p)
 {
 	return 0;
 }
 
 static int
-nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, u32 *p)
+nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p)
 {
 	struct xdr_stream xdr;
 	struct nfs4_cb_compound_hdr hdr;
@@ -472,7 +472,7 @@
 {
 	struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp;
 	struct nfs4_callback *cb = &clp->cl_callback;
-	u32 addr = htonl(cb->cb_addr);
+	__be32 addr = htonl(cb->cb_addr);
 
 	dprintk("NFSD: nfs4_cb_null task->tk_status %d\n", task->tk_status);
 
diff -urN oldtree/fs/nfsd/nfs4proc.c newtree/fs/nfsd/nfs4proc.c
--- oldtree/fs/nfsd/nfs4proc.c	2006-02-19 11:41:05.177555992 +0000
+++ newtree/fs/nfsd/nfs4proc.c	2006-02-21 15:58:36.593583488 +0000
@@ -67,10 +67,11 @@
 	*dst = *src;
 }
 
-static int
+static __be32
 do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
 {
-	int accmode, status;
+	int accmode;
+	__be32 status;
 
 	if (open->op_truncate &&
 		!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
@@ -88,11 +89,11 @@
 	return status;
 }
 
-static int
+static __be32
 do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
 {
 	struct svc_fh resfh;
-	int status;
+	__be32 status;
 
 	fh_init(&resfh, NFS4_FHSIZE);
 	open->op_truncate = 0;
@@ -131,10 +132,10 @@
 	return status;
 }
 
-static int
+static __be32
 do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
 {
-	int status;
+	__be32 status;
 
 	/* Only reclaims from previously confirmed clients are valid */
 	if ((status = nfs4_check_open_reclaim(&open->op_clientid)))
@@ -161,10 +162,10 @@
 }
 
 
-static inline int
+static inline __be32
 nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, struct nfs4_stateowner **replay_owner)
 {
-	int status;
+	__be32 status;
 	dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n",
 		(int)open->op_fname.len, open->op_fname.data,
 		open->op_stateowner);
@@ -177,7 +178,7 @@
 
 	/* check seqid for replay. set nfs4_owner */
 	status = nfsd4_process_open1(open);
-	if (status == NFSERR_REPLAY_ME) {
+	if (status == nfserr_replay_me) {
 		struct nfs4_replay *rp = &open->op_stateowner->so_replay;
 		fh_put(current_fh);
 		current_fh->fh_handle.fh_size = rp->rp_openfh_len;
@@ -188,7 +189,7 @@
 			dprintk("nfsd4_open: replay failed"
 				" restoring previous filehandle\n");
 		else
-			status = NFSERR_REPLAY_ME;
+			status = nfserr_replay_me;
 	}
 	if (status)
 		goto out;
@@ -261,7 +262,7 @@
 /*
  * filehandle-manipulating ops.
  */
-static inline int
+static inline __be32
 nfsd4_getfh(struct svc_fh *current_fh, struct svc_fh **getfh)
 {
 	if (!current_fh->fh_dentry)
@@ -271,7 +272,7 @@
 	return nfs_ok;
 }
 
-static inline int
+static inline __be32
 nfsd4_putfh(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_putfh *putfh)
 {
 	fh_put(current_fh);
@@ -280,10 +281,10 @@
 	return fh_verify(rqstp, current_fh, 0, MAY_NOP);
 }
 
-static inline int
+static inline __be32
 nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh)
 {
-	int status;
+	__be32 status;
 
 	fh_put(current_fh);
 	status = exp_pseudoroot(rqstp->rq_client, current_fh,
@@ -293,7 +294,7 @@
 	return status;
 }
 
-static inline int
+static inline __be32
 nfsd4_restorefh(struct svc_fh *current_fh, struct svc_fh *save_fh)
 {
 	if (!save_fh->fh_dentry)
@@ -303,7 +304,7 @@
 	return nfs_ok;
 }
 
-static inline int
+static inline __be32
 nfsd4_savefh(struct svc_fh *current_fh, struct svc_fh *save_fh)
 {
 	if (!current_fh->fh_dentry)
@@ -316,7 +317,7 @@
 /*
  * misc nfsv4 ops
  */
-static inline int
+static inline __be32
 nfsd4_access(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_access *access)
 {
 	if (access->ac_req_access & ~NFS3_ACCESS_FULL)
@@ -326,10 +327,10 @@
 	return nfsd_access(rqstp, current_fh, &access->ac_resp_access, &access->ac_supported);
 }
 
-static inline int
+static inline __be32
 nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_commit *commit)
 {
-	int status;
+	__be32 status;
 
 	u32 *p = (u32 *)commit->co_verf.data;
 	*p++ = nfssvc_boot.tv_sec;
@@ -341,11 +342,11 @@
 	return status;
 }
 
-static int
+static __be32
 nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_create *create)
 {
 	struct svc_fh resfh;
-	int status;
+	__be32 status;
 	dev_t rdev;
 
 	fh_init(&resfh, NFS4_FHSIZE);
@@ -425,10 +426,10 @@
 	return status;
 }
 
-static inline int
+static inline __be32
 nfsd4_getattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_getattr *getattr)
 {
-	int status;
+	__be32 status;
 
 	status = fh_verify(rqstp, current_fh, 0, MAY_NOP);
 	if (status)
@@ -444,11 +445,11 @@
 	return nfs_ok;
 }
 
-static inline int
+static inline __be32
 nfsd4_link(struct svc_rqst *rqstp, struct svc_fh *current_fh,
 	   struct svc_fh *save_fh, struct nfsd4_link *link)
 {
-	int status = nfserr_nofilehandle;
+	__be32 status = nfserr_nofilehandle;
 
 	if (!save_fh->fh_dentry)
 		return status;
@@ -458,11 +459,11 @@
 	return status;
 }
 
-static int
+static __be32
 nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh)
 {
 	struct svc_fh tmp_fh;
-	int ret;
+	__be32 ret;
 
 	fh_init(&tmp_fh, NFS4_FHSIZE);
 	if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh,
@@ -476,16 +477,16 @@
 	return nfsd_lookup(rqstp, current_fh, "..", 2, current_fh);
 }
 
-static inline int
+static inline __be32
 nfsd4_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lookup *lookup)
 {
 	return nfsd_lookup(rqstp, current_fh, lookup->lo_name, lookup->lo_len, current_fh);
 }
 
-static inline int
+static inline __be32
 nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read)
 {
-	int status;
+	__be32 status;
 
 	/* no need to check permission - this will be done in nfsd_read() */
 
@@ -510,7 +511,7 @@
 	return status;
 }
 
-static inline int
+static inline __be32
 nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readdir *readdir)
 {
 	u64 cookie = readdir->rd_cookie;
@@ -533,7 +534,7 @@
 	return nfs_ok;
 }
 
-static inline int
+static inline __be32
 nfsd4_readlink(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readlink *readlink)
 {
 	readlink->rl_rqstp = rqstp;
@@ -541,10 +542,10 @@
 	return nfs_ok;
 }
 
-static inline int
+static inline __be32
 nfsd4_remove(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_remove *remove)
 {
-	int status;
+	__be32 status;
 
 	if (nfs4_in_grace())
 		return nfserr_grace;
@@ -558,11 +559,11 @@
 	return status;
 }
 
-static inline int
+static inline __be32
 nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh,
 	     struct svc_fh *save_fh, struct nfsd4_rename *rename)
 {
-	int status = nfserr_nofilehandle;
+	__be32 status = nfserr_nofilehandle;
 
 	if (!save_fh->fh_dentry)
 		return status;
@@ -591,10 +592,10 @@
 	return status;
 }
 
-static inline int
+static inline __be32
 nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_setattr *setattr)
 {
-	int status = nfs_ok;
+	__be32 status = nfs_ok;
 
 	if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
 		nfs4_lock_state();
@@ -616,13 +617,13 @@
 	return status;
 }
 
-static inline int
+static inline __be32
 nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_write *write)
 {
 	stateid_t *stateid = &write->wr_stateid;
 	struct file *filp = NULL;
 	u32 *p;
-	int status = nfs_ok;
+	__be32 status = nfs_ok;
 
 	/* no need to check permission - this will be done in nfsd_write() */
 
@@ -663,12 +664,12 @@
  * attributes matched.  VERIFY is implemented by mapping NFSERR_SAME
  * to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK.
  */
-static int
+static __be32
 nfsd4_verify(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_verify *verify)
 {
-	u32 *buf, *p;
+	__be32 *buf, *p;
 	int count;
-	int status;
+	__be32 status;
 
 	status = fh_verify(rqstp, current_fh, 0, MAY_NOP);
 	if (status)
@@ -717,7 +718,7 @@
 /*
  * NULL call.
  */
-static int
+static __be32
 nfsd4_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
 {
 	return nfs_ok;
@@ -727,7 +728,7 @@
 /*
  * COMPOUND call.
  */
-static int
+static __be32
 nfsd4_proc_compound(struct svc_rqst *rqstp,
 		    struct nfsd4_compoundargs *args,
 		    struct nfsd4_compoundres *resp)
@@ -737,7 +738,7 @@
 	struct svc_fh	*save_fh = NULL;
 	struct nfs4_stateowner *replay_owner = NULL;
 	int		slack_space;    /* in words, not bytes! */
-	int		status;
+	__be32		status;
 
 	status = nfserr_resource;
 	current_fh = kmalloc(sizeof(*current_fh), GFP_KERNEL);
@@ -917,7 +918,7 @@
 		}
 
 encode_op:
-		if (op->status == NFSERR_REPLAY_ME) {
+		if (op->status == nfserr_replay_me) {
 			op->replay = &replay_owner->so_replay;
 			nfsd4_encode_replay(resp, op);
 			status = op->status = op->replay->rp_status;
diff -urN oldtree/fs/nfsd/nfs4recover.c newtree/fs/nfsd/nfs4recover.c
--- oldtree/fs/nfsd/nfs4recover.c	2006-02-19 11:41:05.177555992 +0000
+++ newtree/fs/nfsd/nfs4recover.c	2006-02-21 15:58:36.594583336 +0000
@@ -83,13 +83,13 @@
 	*out = '\0';
 }
 
-int
+__be32
 nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
 {
 	struct xdr_netobj cksum;
 	struct crypto_tfm *tfm;
 	struct scatterlist sg[1];
-	int status = nfserr_resource;
+	__be32 status = nfserr_resource;
 
 	dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
 			clname->len, clname->data);
@@ -192,7 +192,7 @@
 	struct dentry_list *child;
 
 	if (name && isdotent(name, namlen))
-		return nfs_ok;
+		return 0;
 	dentry = lookup_one_len(name, parent, namlen);
 	if (IS_ERR(dentry))
 		return PTR_ERR(dentry);
@@ -332,14 +332,14 @@
 	int status;
 
 	if (nfs4_has_reclaimed_state(child->d_name.name))
-		return nfs_ok;
+		return 0;
 
 	status = nfsd4_clear_clid_dir(parent, child);
 	if (status)
 		printk("failed to remove client recovery directory %s\n",
 				child->d_name.name);
 	/* Keep trying, success or failure: */
-	return nfs_ok;
+	return 0;
 }
 
 void
@@ -364,10 +364,10 @@
 		printk("nfsd4: illegal name %s in recovery directory\n",
 				child->d_name.name);
 		/* Keep trying; maybe the others are OK: */
-		return nfs_ok;
+		return 0;
 	}
 	nfs4_client_to_reclaim(child->d_name.name);
-	return nfs_ok;
+	return 0;
 }
 
 int
diff -urN oldtree/fs/nfsd/nfs4state.c newtree/fs/nfsd/nfs4state.c
--- oldtree/fs/nfsd/nfs4state.c	2006-02-19 11:41:05.179555688 +0000
+++ newtree/fs/nfsd/nfs4state.c	2006-02-21 15:58:36.595583184 +0000
@@ -49,6 +49,7 @@
 #include <linux/nfsd/state.h>
 #include <linux/nfsd/xdr4.h>
 #include <linux/namei.h>
+#include <linux/mutex.h>
 
 #define NFSDDBG_FACILITY                NFSDDBG_PROC
 
@@ -77,11 +78,11 @@
 
 /* Locking:
  *
- * client_sema: 
+ * client_mutex:
  * 	protects clientid_hashtbl[], clientstr_hashtbl[],
  * 	unconfstr_hashtbl[], uncofid_hashtbl[].
  */
-static DECLARE_MUTEX(client_sema);
+static DEFINE_MUTEX(client_mutex);
 
 static kmem_cache_t *stateowner_slab = NULL;
 static kmem_cache_t *file_slab = NULL;
@@ -91,13 +92,13 @@
 void
 nfs4_lock_state(void)
 {
-	down(&client_sema);
+	mutex_lock(&client_mutex);
 }
 
 void
 nfs4_unlock_state(void)
 {
-	up(&client_sema);
+	mutex_unlock(&client_mutex);
 }
 
 static inline u32
@@ -664,10 +665,10 @@
  *		as described above.
  *
  */
-int
+__be32
 nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
 {
-	u32 			ip_addr = rqstp->rq_addr.sin_addr.s_addr;
+	__be32 			ip_addr = rqstp->rq_addr.sin_addr.s_addr;
 	struct xdr_netobj 	clname = { 
 		.len = setclid->se_namelen,
 		.data = setclid->se_name,
@@ -675,7 +676,7 @@
 	nfs4_verifier		clverifier = setclid->se_verf;
 	unsigned int 		strhashval;
 	struct nfs4_client	*conf, *unconf, *new;
-	int 			status;
+	__be32 			status;
 	char                    dname[HEXDIR_LEN];
 	
 	if (!check_name(clname))
@@ -829,14 +830,14 @@
  *
  * NOTE: callback information will be processed here in a future patch
  */
-int
+__be32
 nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm)
 {
-	u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
+	__be32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
 	struct nfs4_client *conf, *unconf;
 	nfs4_verifier confirm = setclientid_confirm->sc_confirm; 
 	clientid_t * clid = &setclientid_confirm->sc_clientid;
-	int status;
+	__be32 status;
 
 	if (STALE_CLIENTID(clid))
 		return nfserr_stale_clientid;
@@ -1265,13 +1266,13 @@
  * Called to check deny when READ with all zero stateid or
  * WRITE with all zero or all one stateid
  */
-static int
+static __be32
 nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
 {
 	struct inode *ino = current_fh->fh_dentry->d_inode;
 	struct nfs4_file *fp;
 	struct nfs4_stateid *stp;
-	int ret;
+	__be32 ret;
 
 	dprintk("NFSD: nfs4_share_conflict\n");
 
@@ -1429,7 +1430,7 @@
 };
 
 
-int
+__be32
 nfsd4_process_open1(struct nfsd4_open *open)
 {
 	clientid_t *clientid = &open->op_clientid;
@@ -1462,7 +1463,7 @@
 	}
 	if (open->op_seqid == sop->so_seqid - 1) {
 		if (sop->so_replay.rp_buflen)
-			return NFSERR_REPLAY_ME;
+			return nfserr_replay_me;
 		/* The original OPEN failed so spectacularly
 		 * that we don't even have replay data saved!
 		 * Therefore, we have no choice but to continue
@@ -1486,7 +1487,7 @@
 	return nfs_ok;
 }
 
-static inline int
+static inline __be32
 nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
 {
 	if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
@@ -1507,12 +1508,12 @@
 	return NULL;
 }
 
-static int
+static __be32
 nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
 		struct nfs4_delegation **dp)
 {
 	int flags;
-	int status = nfserr_bad_stateid;
+	__be32 status = nfserr_bad_stateid;
 
 	*dp = find_delegation_file(fp, &open->op_delegate_stateid);
 	if (*dp == NULL)
@@ -1531,11 +1532,11 @@
 	return nfs_ok;
 }
 
-static int
+static __be32
 nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp)
 {
 	struct nfs4_stateid *local;
-	int status = nfserr_share_denied;
+	__be32 status = nfserr_share_denied;
 	struct nfs4_stateowner *sop = open->op_stateowner;
 
 	list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
@@ -1560,7 +1561,7 @@
 	return kmem_cache_alloc(stateid_slab, GFP_KERNEL);
 }
 
-static int
+static __be32
 nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,
 		struct nfs4_delegation *dp,
 		struct svc_fh *cur_fh, int flags)
@@ -1575,7 +1576,7 @@
 		get_file(dp->dl_vfs_file);
 		stp->st_vfs_file = dp->dl_vfs_file;
 	} else {
-		int status;
+		__be32 status;
 		status = nfsd_open(rqstp, cur_fh, S_IFREG, flags,
 				&stp->st_vfs_file);
 		if (status) {
@@ -1589,7 +1590,7 @@
 	return 0;
 }
 
-static inline int
+static inline __be32
 nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
 		struct nfsd4_open *open)
 {
@@ -1604,22 +1605,23 @@
 	return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
 }
 
-static int
+static __be32
 nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open)
 {
 	struct file *filp = stp->st_vfs_file;
 	struct inode *inode = filp->f_dentry->d_inode;
 	unsigned int share_access, new_writer;
-	int status;
+	__be32 status;
+	int err;
 
 	set_access(&share_access, stp->st_access_bmap);
 	new_writer = (~share_access) & open->op_share_access
 			& NFS4_SHARE_ACCESS_WRITE;
 
 	if (new_writer) {
-		status = get_write_access(inode);
-		if (status)
-			return nfserrno(status);
+		err = get_write_access(inode);
+		if (err)
+			return nfserrno(err);
 	}
 	status = nfsd4_truncate(rqstp, cur_fh, open);
 	if (status) {
@@ -1723,14 +1725,14 @@
 /*
  * called with nfs4_lock_state() held.
  */
-int
+__be32
 nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
 {
 	struct nfs4_file *fp = NULL;
 	struct inode *ino = current_fh->fh_dentry->d_inode;
 	struct nfs4_stateid *stp = NULL;
 	struct nfs4_delegation *dp = NULL;
-	int status;
+	__be32 status;
 
 	status = nfserr_inval;
 	if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny))
@@ -1817,11 +1819,11 @@
 static void laundromat_main(void *);
 static DECLARE_WORK(laundromat_work, laundromat_main, NULL);
 
-int 
+__be32 
 nfsd4_renew(clientid_t *clid)
 {
 	struct nfs4_client *clp;
-	int status;
+	__be32 status;
 
 	nfs4_lock_state();
 	dprintk("process_renew(%08x/%08x): starting\n", 
@@ -1981,9 +1983,9 @@
 }
 
 static
-int nfs4_check_openmode(struct nfs4_stateid *stp, int flags)
+__be32 nfs4_check_openmode(struct nfs4_stateid *stp, int flags)
 {
-        int status = nfserr_openmode;
+        __be32 status = nfserr_openmode;
 
 	if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap)))
                 goto out;
@@ -1994,7 +1996,7 @@
 	return status;
 }
 
-static inline int
+static inline __be32
 check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
 {
 	/* Trying to call delegreturn with a special stateid? Yuch: */
@@ -2028,14 +2030,14 @@
 /*
 * Checks for stateid operations
 */
-int
+__be32
 nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags, struct file **filpp)
 {
 	struct nfs4_stateid *stp = NULL;
 	struct nfs4_delegation *dp = NULL;
 	stateid_t *stidp;
 	struct inode *ino = current_fh->fh_dentry->d_inode;
-	int status;
+	__be32 status;
 
 	dprintk("NFSD: preprocess_stateid_op: stateid = (%08x/%08x/%08x/%08x)\n",
 		stateid->si_boot, stateid->si_stateownerid, 
@@ -2114,7 +2116,7 @@
 /* 
  * Checks for sequence id mutating operations. 
  */
-static int
+static __be32
 nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, struct nfsd4_lock *lock)
 {
 	struct nfs4_stateid *stp;
@@ -2158,7 +2160,7 @@
 		clientid_t *lockclid = &lock->v.new.clientid;
 		struct nfs4_client *clp = sop->so_client;
 		int lkflg = 0;
-		int status;
+		__be32 status;
 
 		lkflg = setlkflg(lock->lk_type);
 
@@ -2222,7 +2224,7 @@
 	if (seqid == sop->so_seqid - 1) {
 		dprintk("NFSD: preprocess_seqid_op: retransmission?\n");
 		/* indicate replay to calling function */
-		return NFSERR_REPLAY_ME;
+		return nfserr_replay_me;
 	}
 	printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n",
 			sop->so_seqid, seqid);
@@ -2230,10 +2232,10 @@
 	return nfserr_bad_seqid;
 }
 
-int
+__be32
 nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc, struct nfs4_stateowner **replay_owner)
 {
-	int status;
+	__be32 status;
 	struct nfs4_stateowner *sop;
 	struct nfs4_stateid *stp;
 
@@ -2298,10 +2300,10 @@
 	}
 }
 
-int
+__be32
 nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od, struct nfs4_stateowner **replay_owner)
 {
-	int status;
+	__be32 status;
 	struct nfs4_stateid *stp;
 	unsigned int share_access;
 
@@ -2352,10 +2354,10 @@
 /*
  * nfs4_unlock_state() called after encode
  */
-int
+__be32
 nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close, struct nfs4_stateowner **replay_owner)
 {
-	int status;
+	__be32 status;
 	struct nfs4_stateid *stp;
 
 	dprintk("NFSD: nfsd4_close on file %.*s\n", 
@@ -2391,10 +2393,10 @@
 	return status;
 }
 
-int
+__be32
 nfsd4_delegreturn(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_delegreturn *dr)
 {
-	int status;
+	__be32 status;
 
 	if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0)))
 		goto out;
@@ -2631,7 +2633,7 @@
 /*
  *  LOCK operation 
  */
-int
+__be32
 nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock, struct nfs4_stateowner **replay_owner)
 {
 	struct nfs4_stateowner *open_sop = NULL;
@@ -2640,8 +2642,9 @@
 	struct file *filp;
 	struct file_lock file_lock;
 	struct file_lock *conflock;
-	int status = 0;
+	__be32 status = 0;
 	unsigned int strhashval;
+	int err;
 
 	dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
 		(long long) lock->lk_offset,
@@ -2749,23 +2752,24 @@
 	* Note: locks.c uses the BKL to protect the inode's lock list.
 	*/
 
-	status = posix_lock_file(filp, &file_lock);
-	dprintk("NFSD: nfsd4_lock: posix_lock_file status %d\n",status);
-	switch (-status) {
+	err = posix_lock_file(filp, &file_lock);
+	dprintk("NFSD: nfsd4_lock: posix_lock_file status %d\n",err);
+	switch (-err) {
 	case 0: /* success! */
 		update_stateid(&lock_stp->st_stateid);
 		memcpy(&lock->lk_resp_stateid, &lock_stp->st_stateid, 
 				sizeof(stateid_t));
+		status = 0;
 		goto out;
 	case (EAGAIN):
 		goto conflicting_lock;
 	case (EDEADLK):
 		status = nfserr_deadlock;
-		dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",status);
+		dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",err);
 		goto out;
 	default:        
-		status = nfserrno(status);
-		dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",status);
+		status = nfserrno(err);
+		dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",err);
 		goto out;
 	}
 
@@ -2794,14 +2798,14 @@
 /*
  * LOCKT operation
  */
-int
+__be32
 nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lockt *lockt)
 {
 	struct inode *inode;
 	struct file file;
 	struct file_lock file_lock;
 	struct file_lock *conflicting_lock;
-	int status;
+	__be32 status;
 
 	if (nfs4_in_grace())
 		return nfserr_grace;
@@ -2874,13 +2878,14 @@
 	return status;
 }
 
-int
+__be32
 nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku, struct nfs4_stateowner **replay_owner)
 {
 	struct nfs4_stateid *stp;
 	struct file *filp = NULL;
 	struct file_lock file_lock;
-	int status;
+	__be32 status;
+	int err;
 						        
 	dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n",
 		(long long) locku->lu_offset,
@@ -2917,8 +2922,8 @@
 	/*
 	*  Try to unlock the file in the VFS.
 	*/
-	status = posix_lock_file(filp, &file_lock); 
-	if (status) {
+	err = posix_lock_file(filp, &file_lock); 
+	if (err) {
 		dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n");
 		goto out_nfserr;
 	}
@@ -2937,7 +2942,7 @@
 	return status;
 
 out_nfserr:
-	status = nfserrno(status);
+	status = nfserrno(err);
 	goto out;
 }
 
@@ -2965,7 +2970,7 @@
 	return status;
 }
 
-int
+__be32
 nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner)
 {
 	clientid_t *clid = &rlockowner->rl_clientid;
@@ -2974,7 +2979,7 @@
 	struct xdr_netobj *owner = &rlockowner->rl_owner;
 	struct list_head matches;
 	int i;
-	int status;
+	__be32 status;
 
 	dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
 		clid->cl_boot, clid->cl_id);
@@ -3111,7 +3116,7 @@
 /*
 * Called from OPEN. Look for clientid in reclaim list.
 */
-int
+__be32
 nfs4_check_open_reclaim(clientid_t *clid)
 {
 	return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad;
diff -urN oldtree/fs/nfsd/nfs4xdr.c newtree/fs/nfsd/nfs4xdr.c
--- oldtree/fs/nfsd/nfs4xdr.c	2006-02-19 11:41:05.180555536 +0000
+++ newtree/fs/nfsd/nfs4xdr.c	2006-02-21 15:58:36.598582728 +0000
@@ -60,8 +60,8 @@
 
 #define NFSDDBG_FACILITY		NFSDDBG_XDR
 
-static int
-check_filename(char *str, int len, int err)
+static __be32
+check_filename(char *str, int len, __be32 err)
 {
 	int i;
 
@@ -86,8 +86,8 @@
  * consistent with the style used in NFSv2/v3...
  */
 #define DECODE_HEAD				\
-	u32 *p;					\
-	int status
+	__be32 *p;				\
+	__be32 status
 #define DECODE_TAIL				\
 	status = 0;				\
 out:						\
@@ -136,13 +136,13 @@
 	}					\
 } while (0)
 
-static u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
+static __be32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
 {
 	/* We want more bytes than seem to be available.
 	 * Maybe we need a new page, maybe we have just run out
 	 */
 	int avail = (char*)argp->end - (char*)argp->p;
-	u32 *p;
+	__be32 *p;
 	if (avail + argp->pagelen < nbytes)
 		return NULL;
 	if (avail + PAGE_SIZE < nbytes) /* need more than a page !! */
@@ -189,7 +189,7 @@
 	return 0;
 }
 
-static char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes)
+static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes)
 {
 	void *new = NULL;
 	if (p == argp->tmp) {
@@ -210,7 +210,7 @@
 }
 
 
-static int
+static __be32
 nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
 {
 	u32 bmlen;
@@ -233,13 +233,14 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *iattr,
     struct nfs4_acl **acl)
 {
 	int expected_len, len = 0;
 	u32 dummy32;
 	char *buf;
+	int host_err;
 
 	DECODE_HEAD;
 	iattr->ia_valid = 0;
@@ -273,7 +274,7 @@
 
 		*acl = nfs4_acl_new();
 		if (*acl == NULL) {
-			status = -ENOMEM;
+			host_err = -ENOMEM;
 			goto out_nfserr;
 		}
 		defer_free(argp, (void (*)(const void *))nfs4_acl_free, *acl);
@@ -288,20 +289,20 @@
 			len += XDR_QUADLEN(dummy32) << 2;
 			READMEM(buf, dummy32);
 			ace.whotype = nfs4_acl_get_whotype(buf, dummy32);
-			status = 0;
+			host_err = 0;
 			if (ace.whotype != NFS4_ACL_WHO_NAMED)
 				ace.who = 0;
 			else if (ace.flag & NFS4_ACE_IDENTIFIER_GROUP)
-				status = nfsd_map_name_to_gid(argp->rqstp,
+				host_err = nfsd_map_name_to_gid(argp->rqstp,
 						buf, dummy32, &ace.who);
 			else
-				status = nfsd_map_name_to_uid(argp->rqstp,
+				host_err = nfsd_map_name_to_uid(argp->rqstp,
 						buf, dummy32, &ace.who);
-			if (status)
+			if (host_err)
 				goto out_nfserr;
 			if (nfs4_acl_add_ace(*acl, ace.type, ace.flag,
 				 ace.access_mask, ace.whotype, ace.who) != 0) {
-				status = -ENOMEM;
+				host_err = -ENOMEM;
 				goto out_nfserr;
 			}
 		}
@@ -321,7 +322,7 @@
 		READ_BUF(dummy32);
 		len += (XDR_QUADLEN(dummy32) << 2);
 		READMEM(buf, dummy32);
-		if ((status = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid)))
+		if ((host_err = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid)))
 			goto out_nfserr;
 		iattr->ia_valid |= ATTR_UID;
 	}
@@ -332,7 +333,7 @@
 		READ_BUF(dummy32);
 		len += (XDR_QUADLEN(dummy32) << 2);
 		READMEM(buf, dummy32);
-		if ((status = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid)))
+		if ((host_err = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid)))
 			goto out_nfserr;
 		iattr->ia_valid |= ATTR_GID;
 	}
@@ -408,11 +409,11 @@
 	DECODE_TAIL;
 
 out_nfserr:
-	status = nfserrno(status);
+	status = nfserrno(host_err);
 	goto out;
 }
 
-static int
+static __be32
 nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access)
 {
 	DECODE_HEAD;
@@ -423,7 +424,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
 {
 	DECODE_HEAD;
@@ -438,7 +439,7 @@
 }
 
 
-static int
+static __be32
 nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit)
 {
 	DECODE_HEAD;
@@ -450,7 +451,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create)
 {
 	DECODE_HEAD;
@@ -490,7 +491,7 @@
 	DECODE_TAIL;
 }
 
-static inline int
+static inline __be32
 nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr)
 {
 	DECODE_HEAD;
@@ -502,13 +503,13 @@
 	DECODE_TAIL;
 }
 
-static inline int
+static inline __be32
 nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr)
 {
 	return nfsd4_decode_bitmap(argp, getattr->ga_bmval);
 }
 
-static int
+static __be32
 nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link)
 {
 	DECODE_HEAD;
@@ -523,7 +524,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
 {
 	DECODE_HEAD;
@@ -562,7 +563,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt)
 {
 	DECODE_HEAD;
@@ -581,7 +582,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku)
 {
 	DECODE_HEAD;
@@ -600,7 +601,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup)
 {
 	DECODE_HEAD;
@@ -615,7 +616,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
 {
 	DECODE_HEAD;
@@ -693,7 +694,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf)
 {
 	DECODE_HEAD;
@@ -707,7 +708,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_downgrade *open_down)
 {
 	DECODE_HEAD;
@@ -723,7 +724,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh)
 {
 	DECODE_HEAD;
@@ -738,7 +739,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read)
 {
 	DECODE_HEAD;
@@ -752,7 +753,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *readdir)
 {
 	DECODE_HEAD;
@@ -768,7 +769,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove)
 {
 	DECODE_HEAD;
@@ -783,7 +784,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename)
 {
 	DECODE_HEAD;
@@ -803,7 +804,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid)
 {
 	DECODE_HEAD;
@@ -814,7 +815,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
 {
 	DECODE_HEAD;
@@ -828,7 +829,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid *setclientid)
 {
 	DECODE_HEAD;
@@ -853,7 +854,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid_confirm *scd_c)
 {
 	DECODE_HEAD;
@@ -866,7 +867,7 @@
 }
 
 /* Also used for NVERIFY */
-static int
+static __be32
 nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify)
 {
 #if 0
@@ -902,7 +903,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
 {
 	int avail;
@@ -945,15 +946,15 @@
 			argp->pagelen -= len;
 		}
 	}
-	argp->end = (u32*) (write->wr_vec[v].iov_base + write->wr_vec[v].iov_len);
-	argp->p = (u32*)  (write->wr_vec[v].iov_base + (XDR_QUADLEN(len) << 2));
+	argp->end = (__be32*) (write->wr_vec[v].iov_base + write->wr_vec[v].iov_len);
+	argp->p = (__be32*)  (write->wr_vec[v].iov_base + (XDR_QUADLEN(len) << 2));
 	write->wr_vec[v].iov_len = len;
 	write->wr_vlen = v+1;
 
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner)
 {
 	DECODE_HEAD;
@@ -967,7 +968,7 @@
 	DECODE_TAIL;
 }
 
-static int
+static __be32
 nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
 {
 	DECODE_HEAD;
@@ -1173,7 +1174,7 @@
  * task to translate them into Linux-specific versions which are more
  * consistent with the style used in NFSv2/v3...
  */
-#define ENCODE_HEAD              u32 *p
+#define ENCODE_HEAD              __be32 *p
 
 #define WRITE32(n)               *p++ = htonl(n)
 #define WRITE64(n)               do {				\
@@ -1203,8 +1204,8 @@
  * Header routine to setup seqid operation replay cache
  */
 #define ENCODE_SEQID_OP_HEAD					\
-	u32 *p;							\
-	u32 *save;						\
+	__be32 *p;						\
+	__be32 *save;						\
 								\
 	save = resp->p;
 
@@ -1233,9 +1234,9 @@
         NF4SOCK, NF4BAD,  NF4LNK, NF4BAD,
 };
 
-static int
+static __be32
 nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
-			u32 **p, int *buflen)
+			__be32 **p, int *buflen)
 {
 	int status;
 
@@ -1255,21 +1256,21 @@
 	return 0;
 }
 
-static inline int
-nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, u32 **p, int *buflen)
+static inline __be32
+nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, __be32 **p, int *buflen)
 {
 	return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, uid, 0, p, buflen);
 }
 
-static inline int
-nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, u32 **p, int *buflen)
+static inline __be32
+nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, __be32 **p, int *buflen)
 {
 	return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, gid, 1, p, buflen);
 }
 
-static inline int
+static inline __be32
 nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
-		u32 **p, int *buflen)
+		__be32 **p, int *buflen)
 {
 	return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen);
 }
@@ -1282,9 +1283,9 @@
  * @countp is the buffer size in _words_; upon successful return this becomes
  * replaced with the number of words written.
  */
-int
+__be32
 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
-		struct dentry *dentry, u32 *buffer, int *countp, u32 *bmval,
+		struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval,
 		struct svc_rqst *rqstp)
 {
 	u32 bmval0 = bmval[0];
@@ -1293,11 +1294,12 @@
 	struct svc_fh tempfh;
 	struct kstatfs statfs;
 	int buflen = *countp << 2;
-	u32 *attrlenp;
+	__be32 *attrlenp;
 	u32 dummy;
 	u64 dummy64;
-	u32 *p = buffer;
-	int status;
+	__be32 *p = buffer;
+	__be32 status;
+	int err;
 	int aclsupport = 0;
 	struct nfs4_acl *acl = NULL;
 
@@ -1305,14 +1307,14 @@
 	BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0);
 	BUG_ON(bmval1 & ~NFSD_SUPPORTED_ATTRS_WORD1);
 
-	status = vfs_getattr(exp->ex_mnt, dentry, &stat);
-	if (status)
+	err = vfs_getattr(exp->ex_mnt, dentry, &stat);
+	if (err)
 		goto out_nfserr;
 	if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL)) ||
 	    (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
 		       FATTR4_WORD1_SPACE_TOTAL))) {
-		status = vfs_statfs(dentry->d_inode->i_sb, &statfs);
-		if (status)
+		err = vfs_statfs(dentry->d_inode->i_sb, &statfs);
+		if (err)
 			goto out_nfserr;
 	}
 	if ((bmval0 & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && !fhp) {
@@ -1324,15 +1326,15 @@
 	}
 	if (bmval0 & (FATTR4_WORD0_ACL | FATTR4_WORD0_ACLSUPPORT
 			| FATTR4_WORD0_SUPPORTED_ATTRS)) {
-		status = nfsd4_get_nfs4_acl(rqstp, dentry, &acl);
-		aclsupport = (status == 0);
+		err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl);
+		aclsupport = (err == 0);
 		if (bmval0 & FATTR4_WORD0_ACL) {
-			if (status == -EOPNOTSUPP)
+			if (err == -EOPNOTSUPP)
 				bmval0 &= ~FATTR4_WORD0_ACL;
-			else if (status == -EINVAL) {
+			else if (err == -EINVAL) {
 				status = nfserr_attrnotsupp;
 				goto out;
-			} else if (status != 0)
+			} else if (err != 0)
 				goto out_nfserr;
 		}
 	}
@@ -1654,7 +1656,7 @@
 		fh_put(&tempfh);
 	return status;
 out_nfserr:
-	status = nfserrno(status);
+	status = nfserrno(err);
 	goto out;
 out_resource:
 	*countp = 0;
@@ -1665,13 +1667,13 @@
 	goto out;
 }
 
-static int
+static __be32
 nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
-		const char *name, int namlen, u32 *p, int *buflen)
+		const char *name, int namlen, __be32 *p, int *buflen)
 {
 	struct svc_export *exp = cd->rd_fhp->fh_export;
 	struct dentry *dentry;
-	int nfserr;
+	__be32 nfserr;
 
 	dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen);
 	if (IS_ERR(dentry))
@@ -1700,10 +1702,10 @@
 	return nfserr;
 }
 
-static u32 *
-nfsd4_encode_rdattr_error(u32 *p, int buflen, int nfserr)
+static __be32 *
+nfsd4_encode_rdattr_error(__be32 *p, int buflen, __be32 nfserr)
 {
-	u32 *attrlenp;
+	__be32 *attrlenp;
 
 	if (buflen < 6)
 		return NULL;
@@ -1723,8 +1725,8 @@
 {
 	struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common);
 	int buflen;
-	u32 *p = cd->buffer;
-	int nfserr = nfserr_toosmall;
+	__be32 *p = cd->buffer;
+	__be32 nfserr = nfserr_toosmall;
 
 	/* In nfsv4, "." and ".." never make it onto the wire.. */
 	if (name && isdotent(name, namlen)) {
@@ -1780,7 +1782,7 @@
 }
 
 static void
-nfsd4_encode_access(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_access *access)
+nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
 {
 	ENCODE_HEAD;
 
@@ -1793,7 +1795,7 @@
 }
 
 static void
-nfsd4_encode_close(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_close *close)
+nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close)
 {
 	ENCODE_SEQID_OP_HEAD;
 
@@ -1808,7 +1810,7 @@
 
 
 static void
-nfsd4_encode_commit(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_commit *commit)
+nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit)
 {
 	ENCODE_HEAD;
 
@@ -1820,7 +1822,7 @@
 }
 
 static void
-nfsd4_encode_create(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_create *create)
+nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create)
 {
 	ENCODE_HEAD;
 
@@ -1834,8 +1836,8 @@
 	}
 }
 
-static int
-nfsd4_encode_getattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_getattr *getattr)
+static __be32
+nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr)
 {
 	struct svc_fh *fhp = getattr->ga_fhp;
 	int buflen;
@@ -1854,7 +1856,7 @@
 }
 
 static void
-nfsd4_encode_getfh(struct nfsd4_compoundres *resp, int nfserr, struct svc_fh *fhp)
+nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh *fhp)
 {
 	unsigned int len;
 	ENCODE_HEAD;
@@ -1894,7 +1896,7 @@
 }
 
 static void
-nfsd4_encode_lock(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock *lock)
+nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock)
 {
 	ENCODE_SEQID_OP_HEAD;
 
@@ -1910,14 +1912,14 @@
 }
 
 static void
-nfsd4_encode_lockt(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lockt *lockt)
+nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt)
 {
 	if (nfserr == nfserr_denied)
 		nfsd4_encode_lock_denied(resp, &lockt->lt_denied);
 }
 
 static void
-nfsd4_encode_locku(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_locku *locku)
+nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku)
 {
 	ENCODE_SEQID_OP_HEAD;
 
@@ -1933,7 +1935,7 @@
 
 
 static void
-nfsd4_encode_link(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_link *link)
+nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link)
 {
 	ENCODE_HEAD;
 
@@ -1946,7 +1948,7 @@
 
 
 static void
-nfsd4_encode_open(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open *open)
+nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
 {
 	ENCODE_SEQID_OP_HEAD;
 
@@ -2011,7 +2013,7 @@
 }
 
 static void
-nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open_confirm *oc)
+nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc)
 {
 	ENCODE_SEQID_OP_HEAD;
 				        
@@ -2026,7 +2028,7 @@
 }
 
 static void
-nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open_downgrade *od)
+nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od)
 {
 	ENCODE_SEQID_OP_HEAD;
 				        
@@ -2040,8 +2042,8 @@
 	ENCODE_SEQID_OP_TAIL(od->od_stateowner);
 }
 
-static int
-nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read *read)
+static __be32
+nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_read *read)
 {
 	u32 eof;
 	int v, pn;
@@ -2110,8 +2112,8 @@
 	return 0;
 }
 
-static int
-nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_readlink *readlink)
+static __be32
+nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink)
 {
 	int maxcount;
 	char *page;
@@ -2161,12 +2163,12 @@
 	return 0;
 }
 
-static int
-nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_readdir *readdir)
+static __be32
+nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readdir *readdir)
 {
 	int maxcount;
 	loff_t offset;
-	u32 *page, *savep;
+	__be32 *page, *savep;
 	ENCODE_HEAD;
 
 	if (nfserr)
@@ -2243,7 +2245,7 @@
 }
 
 static void
-nfsd4_encode_remove(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_remove *remove)
+nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove)
 {
 	ENCODE_HEAD;
 
@@ -2255,7 +2257,7 @@
 }
 
 static void
-nfsd4_encode_rename(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_rename *rename)
+nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename)
 {
 	ENCODE_HEAD;
 
@@ -2272,7 +2274,7 @@
  * regardless of the error status.
  */
 static void
-nfsd4_encode_setattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_setattr *setattr)
+nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr)
 {
 	ENCODE_HEAD;
 
@@ -2291,7 +2293,7 @@
 }
 
 static void
-nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_setclientid *scd)
+nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd)
 {
 	ENCODE_HEAD;
 
@@ -2310,7 +2312,7 @@
 }
 
 static void
-nfsd4_encode_write(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_write *write)
+nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write)
 {
 	ENCODE_HEAD;
 
@@ -2326,7 +2328,7 @@
 void
 nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
 {
-	u32 *statp;
+	__be32 *statp;
 	ENCODE_HEAD;
 
 	RESERVE_SPACE(8);
@@ -2464,7 +2466,7 @@
  */
 
 int
-nfs4svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
+nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
 {
         return xdr_ressize_check(rqstp, p);
 }
@@ -2486,9 +2488,9 @@
 }
 
 int
-nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoundargs *args)
+nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args)
 {
-	int status;
+	__be32 status;
 
 	args->p = p;
 	args->end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len;
@@ -2507,7 +2509,7 @@
 }
 
 int
-nfs4svc_encode_compoundres(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoundres *resp)
+nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundres *resp)
 {
 	/*
 	 * All that remains is to write the tag and operation count...
diff -urN oldtree/fs/nfsd/nfscache.c newtree/fs/nfsd/nfscache.c
--- oldtree/fs/nfsd/nfscache.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/nfsd/nfscache.c	2006-02-21 15:58:36.599582576 +0000
@@ -259,7 +259,7 @@
  * In this case, nfsd_cache_update is called with statp == NULL.
  */
 void
-nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, u32 *statp)
+nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp)
 {
 	struct svc_cacherep *rp;
 	struct kvec	*resv = &rqstp->rq_res.head[0], *cachv;
diff -urN oldtree/fs/nfsd/nfsfh.c newtree/fs/nfsd/nfsfh.c
--- oldtree/fs/nfsd/nfsfh.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/nfsd/nfsfh.c	2006-02-21 15:58:36.600582424 +0000
@@ -76,7 +76,7 @@
  * comment in the NFSv3 spec says this is incorrect (implementation notes for
  * the write call).
  */
-static inline int
+static inline __be32
 nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, int type)
 {
 	/* Type can be negative when creating hardlinks - not to a dir */
@@ -110,13 +110,14 @@
  * This is only called at the start of an nfsproc call, so fhp points to
  * a svc_fh which is all 0 except for the over-the-wire file handle.
  */
-u32
+__be32
 fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
 {
 	struct knfsd_fh	*fh = &fhp->fh_handle;
 	struct svc_export *exp = NULL;
 	struct dentry	*dentry;
-	u32		error = 0;
+	__be32		error = 0;
+	int		host_error;
 
 	dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
 
@@ -188,9 +189,9 @@
 		}
 
 		/* Set user creds for this exportpoint */
-		error = nfsd_setuser(rqstp, exp);
-		if (error) {
-			error = nfserrno(error);
+		host_error = nfsd_setuser(rqstp, exp);
+		if (host_error) {
+			error = nfserrno(host_error);
 			goto out;
 		}
 
@@ -308,7 +309,7 @@
 		fh->ofh_dirino = 0;
 }
 
-int
+__be32
 fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, struct svc_fh *ref_fh)
 {
 	/* ref_fh is a reference file handle.
@@ -444,7 +445,7 @@
  * Update file handle information after changing a dentry.
  * This is only called by nfsd_create, nfsd_create_v3 and nfsd_proc_create
  */
-int
+__be32
 fh_update(struct svc_fh *fhp)
 {
 	struct dentry *dentry;
diff -urN oldtree/fs/nfsd/nfsproc.c newtree/fs/nfsd/nfsproc.c
--- oldtree/fs/nfsd/nfsproc.c	2006-02-19 11:41:05.182555232 +0000
+++ newtree/fs/nfsd/nfsproc.c	2006-02-21 15:58:36.601582272 +0000
@@ -30,7 +30,7 @@
 #define NFSDDBG_FACILITY		NFSDDBG_PROC
 
 
-static int
+static __be32
 nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
 {
 	return nfs_ok;
@@ -56,7 +56,7 @@
  * Get a file's attributes
  * N.B. After this call resp->fh needs an fh_put
  */
-static int
+static __be32
 nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle  *argp,
 					  struct nfsd_attrstat *resp)
 {
@@ -72,7 +72,7 @@
  * Set a file's attributes
  * N.B. After this call resp->fh needs an fh_put
  */
-static int
+static __be32
 nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
 					  struct nfsd_attrstat  *resp)
 {
@@ -92,11 +92,11 @@
  * doesn't exist yet.
  * N.B. After this call resp->fh needs an fh_put
  */
-static int
+static __be32
 nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
 					 struct nfsd_diropres  *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: LOOKUP   %s %.*s\n",
 		SVCFH_fmt(&argp->fh), argp->len, argp->name);
@@ -112,11 +112,11 @@
 /*
  * Read a symlink.
  */
-static int
+static __be32
 nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_readlinkargs *argp,
 					   struct nfsd_readlinkres *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
 
@@ -132,11 +132,11 @@
  * Read a portion of a file.
  * N.B. After this call resp->fh needs an fh_put
  */
-static int
+static __be32
 nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
 				       struct nfsd_readres  *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: READ    %s %d bytes at %d\n",
 		SVCFH_fmt(&argp->fh),
@@ -172,11 +172,11 @@
  * Write data to a file
  * N.B. After this call resp->fh needs an fh_put
  */
-static int
+static __be32
 nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
 					struct nfsd_attrstat  *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 	int	stable = 1;
 
 	dprintk("nfsd: WRITE    %s %d bytes at %d\n",
@@ -197,7 +197,7 @@
  * and the actual create() call in compliance with VFS protocols.
  * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
  */
-static int
+static __be32
 nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
 					 struct nfsd_diropres   *resp)
 {
@@ -206,7 +206,8 @@
 	struct iattr	*attr = &argp->attrs;
 	struct inode	*inode;
 	struct dentry	*dchild;
-	int		nfserr, type, mode;
+	int		type, mode;
+	__be32		nfserr;
 	dev_t		rdev = 0, wanted = new_decode_dev(attr->ia_size);
 
 	dprintk("nfsd: CREATE   %s %.*s\n",
@@ -348,11 +349,11 @@
 	return nfsd_return_dirop(nfserr, resp);
 }
 
-static int
+static __be32
 nfsd_proc_remove(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
 					 void		       *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: REMOVE   %s %.*s\n", SVCFH_fmt(&argp->fh),
 		argp->len, argp->name);
@@ -363,11 +364,11 @@
 	return nfserr;
 }
 
-static int
+static __be32
 nfsd_proc_rename(struct svc_rqst *rqstp, struct nfsd_renameargs *argp,
 				  	 void		        *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: RENAME   %s %.*s -> \n",
 		SVCFH_fmt(&argp->ffh), argp->flen, argp->fname);
@@ -381,11 +382,11 @@
 	return nfserr;
 }
 
-static int
+static __be32
 nfsd_proc_link(struct svc_rqst *rqstp, struct nfsd_linkargs *argp,
 				void			    *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: LINK     %s ->\n",
 		SVCFH_fmt(&argp->ffh));
@@ -401,12 +402,12 @@
 	return nfserr;
 }
 
-static int
+static __be32
 nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp,
 				          void			  *resp)
 {
 	struct svc_fh	newfh;
-	int		nfserr;
+	__be32		nfserr;
 
 	dprintk("nfsd: SYMLINK  %s %.*s -> %.*s\n",
 		SVCFH_fmt(&argp->ffh), argp->flen, argp->fname,
@@ -430,11 +431,11 @@
  * Make directory. This operation is not idempotent.
  * N.B. After this call resp->fh needs an fh_put
  */
-static int
+static __be32
 nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
 					struct nfsd_diropres   *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: MKDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
 
@@ -454,11 +455,11 @@
 /*
  * Remove a directory
  */
-static int
+static __be32
 nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
 				 	void		      *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: RMDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
 
@@ -470,11 +471,12 @@
 /*
  * Read a portion of a directory.
  */
-static int
+static __be32
 nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp,
 					  struct nfsd_readdirres  *resp)
 {
-	int		nfserr, count;
+	int		count;
+	__be32		nfserr;
 	loff_t		offset;
 
 	dprintk("nfsd: READDIR  %s %d bytes at %d\n",
@@ -509,11 +511,11 @@
 /*
  * Get file system info
  */
-static int
+static __be32
 nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle   *argp,
 					  struct nfsd_statfsres *resp)
 {
-	int	nfserr;
+	__be32	nfserr;
 
 	dprintk("nfsd: STATFS   %s\n", SVCFH_fmt(&argp->fh));
 
@@ -579,11 +581,11 @@
 /*
  * Map errnos to NFS errnos.
  */
-int
+__be32
 nfserrno (int errno)
 {
 	static struct {
-		int	nfserr;
+		__be32	nfserr;
 		int	syserr;
 	} nfs_errtbl[] = {
 		{ nfs_ok, 0 },
@@ -615,11 +617,10 @@
 		{ nfserr_badname, -ESRCH },
 		{ nfserr_io, -ETXTBSY },
 		{ nfserr_notsupp, -EOPNOTSUPP },
-		{ -1, -EIO }
 	};
 	int	i;
 
-	for (i = 0; nfs_errtbl[i].nfserr != -1; i++) {
+	for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) {
 		if (nfs_errtbl[i].syserr == errno)
 			return nfs_errtbl[i].nfserr;
 	}
diff -urN oldtree/fs/nfsd/nfssvc.c newtree/fs/nfsd/nfssvc.c
--- oldtree/fs/nfsd/nfssvc.c	2006-02-19 11:41:05.183555080 +0000
+++ newtree/fs/nfsd/nfssvc.c	2006-02-21 15:58:36.602582120 +0000
@@ -389,12 +389,12 @@
 }
 
 int
-nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp)
+nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
 {
 	struct svc_procedure	*proc;
 	kxdrproc_t		xdr;
-	u32			nfserr;
-	u32			*nfserrp;
+	__be32			nfserr;
+	__be32			*nfserrp;
 
 	dprintk("nfsd_dispatch: vers %d proc %d\n",
 				rqstp->rq_vers, rqstp->rq_proc);
@@ -413,7 +413,7 @@
 
 	/* Decode arguments */
 	xdr = proc->pc_decode;
-	if (xdr && !xdr(rqstp, (u32*)rqstp->rq_arg.head[0].iov_base,
+	if (xdr && !xdr(rqstp, (__be32*)rqstp->rq_arg.head[0].iov_base,
 			rqstp->rq_argp)) {
 		dprintk("nfsd: failed to decode arguments!\n");
 		nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
diff -urN oldtree/fs/nfsd/nfsxdr.c newtree/fs/nfsd/nfsxdr.c
--- oldtree/fs/nfsd/nfsxdr.c	2006-02-19 11:41:05.184554928 +0000
+++ newtree/fs/nfsd/nfsxdr.c	2006-02-21 15:58:36.603581968 +0000
@@ -37,8 +37,8 @@
 /*
  * XDR functions for basic NFS types
  */
-static u32 *
-decode_fh(u32 *p, struct svc_fh *fhp)
+static __be32 *
+decode_fh(__be32 *p, struct svc_fh *fhp)
 {
 	fh_init(fhp, NFS_FHSIZE);
 	memcpy(&fhp->fh_handle.fh_base, p, NFS_FHSIZE);
@@ -50,13 +50,13 @@
 }
 
 /* Helper function for NFSv2 ACL code */
-u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp)
+__be32 *nfs2svc_decode_fh(__be32 *p, struct svc_fh *fhp)
 {
 	return decode_fh(p, fhp);
 }
 
-static inline u32 *
-encode_fh(u32 *p, struct svc_fh *fhp)
+static inline __be32 *
+encode_fh(__be32 *p, struct svc_fh *fhp)
 {
 	memcpy(p, &fhp->fh_handle.fh_base, NFS_FHSIZE);
 	return p + (NFS_FHSIZE>> 2);
@@ -66,8 +66,8 @@
  * Decode a file name and make sure that the path contains
  * no slashes or null bytes.
  */
-static inline u32 *
-decode_filename(u32 *p, char **namp, int *lenp)
+static inline __be32 *
+decode_filename(__be32 *p, char **namp, int *lenp)
 {
 	char		*name;
 	int		i;
@@ -82,8 +82,8 @@
 	return p;
 }
 
-static inline u32 *
-decode_pathname(u32 *p, char **namp, int *lenp)
+static inline __be32 *
+decode_pathname(__be32 *p, char **namp, int *lenp)
 {
 	char		*name;
 	int		i;
@@ -98,8 +98,8 @@
 	return p;
 }
 
-static inline u32 *
-decode_sattr(u32 *p, struct iattr *iap)
+static inline __be32 *
+decode_sattr(__be32 *p, struct iattr *iap)
 {
 	u32	tmp, tmp1;
 
@@ -151,8 +151,8 @@
 	return p;
 }
 
-static u32 *
-encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp,
+static __be32 *
+encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
 	     struct kstat *stat)
 {
 	struct dentry	*dentry = fhp->fh_dentry;
@@ -195,7 +195,7 @@
 }
 
 /* Helper function for NFSv2 ACL code */
-u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
+__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
 {
 	struct kstat stat;
 	vfs_getattr(fhp->fh_export->ex_mnt, fhp->fh_dentry, &stat);
@@ -206,13 +206,13 @@
  * XDR decode functions
  */
 int
-nfssvc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
+nfssvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
 {
 	return xdr_argsize_check(rqstp, p);
 }
 
 int
-nfssvc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args)
+nfssvc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *args)
 {
 	if (!(p = decode_fh(p, &args->fh)))
 		return 0;
@@ -220,7 +220,7 @@
 }
 
 int
-nfssvc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
+nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_sattrargs *args)
 {
 	if (!(p = decode_fh(p, &args->fh))
@@ -231,7 +231,7 @@
 }
 
 int
-nfssvc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
+nfssvc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_diropargs *args)
 {
 	if (!(p = decode_fh(p, &args->fh))
@@ -242,7 +242,7 @@
 }
 
 int
-nfssvc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
+nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_readargs *args)
 {
 	unsigned int len;
@@ -274,7 +274,7 @@
 }
 
 int
-nfssvc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
+nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_writeargs *args)
 {
 	unsigned int len;
@@ -304,7 +304,7 @@
 }
 
 int
-nfssvc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
+nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_createargs *args)
 {
 	if (!(p = decode_fh(p, &args->fh))
@@ -316,7 +316,7 @@
 }
 
 int
-nfssvc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
+nfssvc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_renameargs *args)
 {
 	if (!(p = decode_fh(p, &args->ffh))
@@ -329,7 +329,7 @@
 }
 
 int
-nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p, struct nfsd_readlinkargs *args)
+nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readlinkargs *args)
 {
 	if (!(p = decode_fh(p, &args->fh)))
 		return 0;
@@ -340,7 +340,7 @@
 }
 
 int
-nfssvc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
+nfssvc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_linkargs *args)
 {
 	if (!(p = decode_fh(p, &args->ffh))
@@ -352,7 +352,7 @@
 }
 
 int
-nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
+nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_symlinkargs *args)
 {
 	if (!(p = decode_fh(p, &args->ffh))
@@ -365,7 +365,7 @@
 }
 
 int
-nfssvc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
+nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_readdirargs *args)
 {
 	if (!(p = decode_fh(p, &args->fh)))
@@ -385,13 +385,13 @@
  * XDR encode functions
  */
 int
-nfssvc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
+nfssvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
 {
 	return xdr_ressize_check(rqstp, p);
 }
 
 int
-nfssvc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
+nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_attrstat *resp)
 {
 	p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
@@ -399,7 +399,7 @@
 }
 
 int
-nfssvc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
+nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_diropres *resp)
 {
 	p = encode_fh(p, &resp->fh);
@@ -408,7 +408,7 @@
 }
 
 int
-nfssvc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
+nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_readlinkres *resp)
 {
 	*p++ = htonl(resp->len);
@@ -425,7 +425,7 @@
 }
 
 int
-nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p,
+nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_readres *resp)
 {
 	p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
@@ -445,7 +445,7 @@
 }
 
 int
-nfssvc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
+nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_readdirres *resp)
 {
 	xdr_ressize_check(rqstp, p);
@@ -458,7 +458,7 @@
 }
 
 int
-nfssvc_encode_statfsres(struct svc_rqst *rqstp, u32 *p,
+nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_statfsres *resp)
 {
 	struct kstatfs	*stat = &resp->stats;
@@ -476,7 +476,7 @@
 		    int namlen, loff_t offset, ino_t ino, unsigned int d_type)
 {
 	struct nfsd_readdirres *cd = container_of(ccd, struct nfsd_readdirres, common);
-	u32	*p = cd->buffer;
+	__be32	*p = cd->buffer;
 	int	buflen, slen;
 
 	/*
@@ -502,7 +502,7 @@
 	*p++ = htonl((u32) ino);		/* file id */
 	p    = xdr_encode_array(p, name, namlen);/* name length & name */
 	cd->offset = p;			/* remember pointer */
-	*p++ = ~(u32) 0;		/* offset of next entry */
+	*p++ = htonl(~0U);		/* offset of next entry */
 
 	cd->buflen = buflen;
 	cd->buffer = p;
@@ -514,7 +514,7 @@
  * XDR release functions
  */
 int
-nfssvc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
+nfssvc_release_fhandle(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_fhandle *resp)
 {
 	fh_put(&resp->fh);
diff -urN oldtree/fs/nfsd/vfs.c newtree/fs/nfsd/vfs.c
--- oldtree/fs/nfsd/vfs.c	2006-02-19 11:41:05.185554776 +0000
+++ newtree/fs/nfsd/vfs.c	2006-02-21 15:58:36.606581512 +0000
@@ -101,7 +101,7 @@
 	struct dentry *dentry = *dpp;
 	struct vfsmount *mnt = mntget(exp->ex_mnt);
 	struct dentry *mounts = dget(dentry);
-	int err = nfs_ok;
+	int err = 0;
 
 	while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts));
 
@@ -139,14 +139,15 @@
  *   clients and is explicitly disallowed for NFSv3
  *      NeilBrown <neilb@cse.unsw.edu.au>
  */
-int
+__be32
 nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
 					int len, struct svc_fh *resfh)
 {
 	struct svc_export	*exp;
 	struct dentry		*dparent;
 	struct dentry		*dentry;
-	int			err;
+	__be32			err;
+	int			host_err;
 
 	dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name);
 
@@ -184,7 +185,7 @@
 			exp2 = exp_parent(exp->ex_client, mnt, dentry,
 					  &rqstp->rq_chandle);
 			if (IS_ERR(exp2)) {
-				err = PTR_ERR(exp2);
+				host_err = PTR_ERR(exp2);
 				dput(dentry);
 				mntput(mnt);
 				goto out_nfserr;
@@ -201,14 +202,14 @@
 	} else {
 		fh_lock(fhp);
 		dentry = lookup_one_len(name, dparent, len);
-		err = PTR_ERR(dentry);
+		host_err = PTR_ERR(dentry);
 		if (IS_ERR(dentry))
 			goto out_nfserr;
 		/*
 		 * check if we have crossed a mount point ...
 		 */
 		if (d_mountpoint(dentry)) {
-			if ((err = nfsd_cross_mnt(rqstp, &dentry, &exp))) {
+			if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) {
 				dput(dentry);
 				goto out_nfserr;
 			}
@@ -227,7 +228,7 @@
 	return err;
 
 out_nfserr:
-	err = nfserrno(err);
+	err = nfserrno(host_err);
 	goto out;
 }
 
@@ -235,7 +236,7 @@
  * Set various file attributes.
  * N.B. After this call fhp needs an fh_put
  */
-int
+__be32
 nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
 	     int check_guard, time_t guardtime)
 {
@@ -244,7 +245,8 @@
 	int		accmode = MAY_SATTR;
 	int		ftype = 0;
 	int		imode;
-	int		err;
+	__be32		err;
+	int		host_err;
 	int		size_change = 0;
 
 	if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
@@ -310,19 +312,19 @@
 		 * If we are changing the size of the file, then
 		 * we need to break all leases.
 		 */
-		err = break_lease(inode, FMODE_WRITE | O_NONBLOCK);
-		if (err == -EWOULDBLOCK)
-			err = -ETIMEDOUT;
-		if (err) /* ENOMEM or EWOULDBLOCK */
+		host_err = break_lease(inode, FMODE_WRITE | O_NONBLOCK);
+		if (host_err == -EWOULDBLOCK)
+			host_err = -ETIMEDOUT;
+		if (host_err) /* ENOMEM or EWOULDBLOCK */
 			goto out_nfserr;
 
-		err = get_write_access(inode);
-		if (err)
+		host_err = get_write_access(inode);
+		if (host_err)
 			goto out_nfserr;
 
 		size_change = 1;
-		err = locks_verify_truncate(inode, NULL, iap->ia_size);
-		if (err) {
+		host_err = locks_verify_truncate(inode, NULL, iap->ia_size);
+		if (host_err) {
 			put_write_access(inode);
 			goto out_nfserr;
 		}
@@ -348,8 +350,8 @@
 	err = nfserr_notsync;
 	if (!check_guard || guardtime == inode->i_ctime.tv_sec) {
 		fh_lock(fhp);
-		err = notify_change(dentry, iap);
-		err = nfserrno(err);
+		host_err = notify_change(dentry, iap);
+		err = nfserrno(host_err);
 		fh_unlock(fhp);
 	}
 	if (size_change)
@@ -361,7 +363,7 @@
 	return err;
 
 out_nfserr:
-	err = nfserrno(err);
+	err = nfserrno(host_err);
 	goto out;
 }
 
@@ -415,11 +417,12 @@
 	return error;
 }
 
-int
+__be32
 nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
     struct nfs4_acl *acl)
 {
-	int error;
+	__be32 error;
+	int host_error;
 	struct dentry *dentry;
 	struct inode *inode;
 	struct posix_acl *pacl = NULL, *dpacl = NULL;
@@ -435,22 +438,22 @@
 	if (S_ISDIR(inode->i_mode))
 		flags = NFS4_ACL_DIR;
 
-	error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
-	if (error == -EINVAL) {
+	host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
+	if (host_error == -EINVAL) {
 		error = nfserr_attrnotsupp;
 		goto out;
-	} else if (error < 0)
+	} else if (host_error < 0)
 		goto out_nfserr;
 
 	if (pacl) {
-		error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
-		if (error < 0)
+		host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
+		if (host_error < 0)
 			goto out_nfserr;
 	}
 
 	if (dpacl) {
-		error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
-		if (error < 0)
+		host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
+		if (host_error < 0)
 			goto out_nfserr;
 	}
 
@@ -461,7 +464,7 @@
 	posix_acl_release(dpacl);
 	return (error);
 out_nfserr:
-	error = nfserrno(error);
+	error = nfserrno(host_error);
 	goto out;
 }
 
@@ -568,14 +571,14 @@
     {	0,			0				}
 };
 
-int
+__be32
 nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *supported)
 {
 	struct accessmap	*map;
 	struct svc_export	*export;
 	struct dentry		*dentry;
 	u32			query, result = 0, sresult = 0;
-	unsigned int		error;
+	__be32			error;
 
 	error = fh_verify(rqstp, fhp, 0, MAY_NOP);
 	if (error)
@@ -595,7 +598,7 @@
 	query = *access;
 	for  (; map->access; map++) {
 		if (map->access & query) {
-			unsigned int err2;
+			__be32 err2;
 
 			sresult |= map->access;
 
@@ -634,13 +637,15 @@
  * The access argument indicates the type of open (read/write/lock)
  * N.B. After this call fhp needs an fh_put
  */
-int
+__be32
 nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
 			int access, struct file **filp)
 {
 	struct dentry	*dentry;
 	struct inode	*inode;
-	int		flags = O_RDONLY|O_LARGEFILE, err;
+	int		flags = O_RDONLY|O_LARGEFILE;
+	__be32		err;
+	int		host_err;
 
 	/*
 	 * If we get here, then the client has already done an "open",
@@ -670,10 +675,10 @@
 	 * Check to see if there are any leases on this file.
 	 * This may block while leases are broken.
 	 */
-	err = break_lease(inode, O_NONBLOCK | ((access & MAY_WRITE) ? FMODE_WRITE : 0));
-	if (err == -EWOULDBLOCK)
-		err = -ETIMEDOUT;
-	if (err) /* NOMEM or WOULDBLOCK */
+	host_err = break_lease(inode, O_NONBLOCK | ((access & MAY_WRITE) ? FMODE_WRITE : 0));
+	if (host_err == -EWOULDBLOCK)
+		host_err = -ETIMEDOUT;
+	if (host_err) /* NOMEM or WOULDBLOCK */
 		goto out_nfserr;
 
 	if (access & MAY_WRITE) {
@@ -683,10 +688,9 @@
 	}
 	*filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_mnt), flags);
 	if (IS_ERR(*filp))
-		err = PTR_ERR(*filp);
+		host_err = PTR_ERR(*filp);
 out_nfserr:
-	if (err)
-		err = nfserrno(err);
+	err = nfserrno(host_err);
 out:
 	return err;
 }
@@ -815,14 +819,15 @@
 	return size;
 }
 
-static int
+static __be32
 nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
               loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
 {
 	struct inode *inode;
 	struct raparms	*ra;
 	mm_segment_t	oldfs;
-	int		err;
+	__be32		err;
+	int		host_err;
 
 	err = nfserr_perm;
 	inode = file->f_dentry->d_inode;
@@ -840,12 +845,12 @@
 
 	if (file->f_op->sendfile) {
 		svc_pushback_unused_pages(rqstp);
-		err = file->f_op->sendfile(file, &offset, *count,
+		host_err = file->f_op->sendfile(file, &offset, *count,
 						 nfsd_read_actor, rqstp);
 	} else {
 		oldfs = get_fs();
 		set_fs(KERNEL_DS);
-		err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset);
+		host_err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset);
 		set_fs(oldfs);
 	}
 
@@ -858,13 +863,13 @@
 		spin_unlock(&ra_lock);
 	}
 
-	if (err >= 0) {
-		nfsdstats.io_read += err;
-		*count = err;
+	if (host_err >= 0) {
+		nfsdstats.io_read += host_err;
+		*count = host_err;
 		err = 0;
 		fsnotify_access(file->f_dentry);
 	} else 
-		err = nfserrno(err);
+		err = nfserrno(host_err);
 out:
 	return err;
 }
@@ -879,7 +884,7 @@
 	mutex_unlock(&dentry->d_inode->i_mutex);
 }
 
-static int
+static __be32
 nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
 				loff_t offset, struct kvec *vec, int vlen,
 	   			unsigned long cnt, int *stablep)
@@ -888,7 +893,8 @@
 	struct dentry		*dentry;
 	struct inode		*inode;
 	mm_segment_t		oldfs;
-	int			err = 0;
+	__be32			err = 0;
+	int			host_err;
 	int			stable = *stablep;
 
 #ifdef MSNFS
@@ -924,18 +930,18 @@
 
 	/* Write the data. */
 	oldfs = get_fs(); set_fs(KERNEL_DS);
-	err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset);
+	host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset);
 	set_fs(oldfs);
-	if (err >= 0) {
+	if (host_err >= 0) {
 		nfsdstats.io_write += cnt;
 		fsnotify_modify(file->f_dentry);
 	}
 
 	/* clear setuid/setgid flag after write */
-	if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID)))
+	if (host_err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID)))
 		kill_suid(dentry);
 
-	if (err >= 0 && stable) {
+	if (host_err >= 0 && stable) {
 		static ino_t	last_ino;
 		static dev_t	last_dev;
 
@@ -971,11 +977,11 @@
 		last_dev = inode->i_sb->s_dev;
 	}
 
-	dprintk("nfsd: write complete err=%d\n", err);
-	if (err >= 0)
+	dprintk("nfsd: write complete host_err=%d\n", host_err);
+	if (host_err >= 0)
 		err = 0;
 	else 
-		err = nfserrno(err);
+		err = nfserrno(host_err);
 out:
 	return err;
 }
@@ -985,12 +991,12 @@
  * on entry. On return, *count contains the number of bytes actually read.
  * N.B. After this call fhp needs an fh_put
  */
-int
+__be32
 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
 		loff_t offset, struct kvec *vec, int vlen,
 		unsigned long *count)
 {
-	int		err;
+	__be32		err;
 
 	if (file) {
 		err = nfsd_permission(fhp->fh_export, fhp->fh_dentry,
@@ -1014,12 +1020,12 @@
  * The stable flag requests synchronous writes.
  * N.B. After this call fhp needs an fh_put
  */
-int
+__be32
 nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
 		loff_t offset, struct kvec *vec, int vlen, unsigned long cnt,
 		int *stablep)
 {
-	int			err = 0;
+	__be32			err = 0;
 
 	if (file) {
 		err = nfsd_permission(fhp->fh_export, fhp->fh_dentry,
@@ -1051,12 +1057,12 @@
  * Unfortunately we cannot lock the file to make sure we return full WCC
  * data to the client, as locking happens lower down in the filesystem.
  */
-int
+__be32
 nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
                loff_t offset, unsigned long count)
 {
 	struct file	*file;
-	int		err;
+	__be32		err;
 
 	if ((u64)count > ~(u64)offset)
 		return nfserr_inval;
@@ -1084,14 +1090,15 @@
  *
  * N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp
  */
-int
+__be32
 nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
 		char *fname, int flen, struct iattr *iap,
 		int type, dev_t rdev, struct svc_fh *resfhp)
 {
 	struct dentry	*dentry, *dchild = NULL;
 	struct inode	*dirp;
-	int		err;
+	__be32		err;
+	int		host_err;
 
 	err = nfserr_perm;
 	if (!flen)
@@ -1118,7 +1125,7 @@
 		/* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
 		fh_lock(fhp);
 		dchild = lookup_one_len(fname, dentry, flen);
-		err = PTR_ERR(dchild);
+		host_err = PTR_ERR(dchild);
 		if (IS_ERR(dchild))
 			goto out_nfserr;
 		err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
@@ -1157,22 +1164,22 @@
 	err = nfserr_perm;
 	switch (type) {
 	case S_IFREG:
-		err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
+		host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
 		break;
 	case S_IFDIR:
-		err = vfs_mkdir(dirp, dchild, iap->ia_mode);
+		host_err = vfs_mkdir(dirp, dchild, iap->ia_mode);
 		break;
 	case S_IFCHR:
 	case S_IFBLK:
 	case S_IFIFO:
 	case S_IFSOCK:
-		err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
+		host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
 		break;
 	default:
 	        printk("nfsd: bad file type %o in nfsd_create\n", type);
-		err = -EINVAL;
+		host_err = -EINVAL;
 	}
-	if (err < 0)
+	if (host_err < 0)
 		goto out_nfserr;
 
 	if (EX_ISSYNC(fhp->fh_export)) {
@@ -1202,7 +1209,7 @@
 	return err;
 
 out_nfserr:
-	err = nfserrno(err);
+	err = nfserrno(host_err);
 	goto out;
 }
 
@@ -1210,7 +1217,7 @@
 /*
  * NFSv3 version of nfsd_create
  */
-int
+__be32
 nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
 		char *fname, int flen, struct iattr *iap,
 		struct svc_fh *resfhp, int createmode, u32 *verifier,
@@ -1218,7 +1225,8 @@
 {
 	struct dentry	*dentry, *dchild = NULL;
 	struct inode	*dirp;
-	int		err;
+	__be32		err;
+	int		host_err;
 	__u32		v_mtime=0, v_atime=0;
 	int		v_mode=0;
 
@@ -1248,7 +1256,7 @@
 	 * Compose the response file handle.
 	 */
 	dchild = lookup_one_len(fname, dentry, flen);
-	err = PTR_ERR(dchild);
+	host_err = PTR_ERR(dchild);
 	if (IS_ERR(dchild))
 		goto out_nfserr;
 
@@ -1304,8 +1312,8 @@
 		goto out;
 	}
 
-	err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
-	if (err < 0)
+	host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
+	if (host_err < 0)
 		goto out_nfserr;
 
 	if (EX_ISSYNC(fhp->fh_export)) {
@@ -1352,7 +1360,7 @@
  	return err;
  
  out_nfserr:
-	err = nfserrno(err);
+	err = nfserrno(host_err);
 	goto out;
 }
 #endif /* CONFIG_NFSD_V3 */
@@ -1362,13 +1370,14 @@
  * fits into the buffer. On return, it contains the true length.
  * N.B. After this call fhp needs an fh_put
  */
-int
+__be32
 nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
 {
 	struct dentry	*dentry;
 	struct inode	*inode;
 	mm_segment_t	oldfs;
-	int		err;
+	__be32		err;
+	int		host_err;
 
 	err = fh_verify(rqstp, fhp, S_IFLNK, MAY_NOP);
 	if (err)
@@ -1387,18 +1396,18 @@
 	 */
 
 	oldfs = get_fs(); set_fs(KERNEL_DS);
-	err = inode->i_op->readlink(dentry, buf, *lenp);
+	host_err = inode->i_op->readlink(dentry, buf, *lenp);
 	set_fs(oldfs);
 
-	if (err < 0)
+	if (host_err < 0)
 		goto out_nfserr;
-	*lenp = err;
+	*lenp = host_err;
 	err = 0;
 out:
 	return err;
 
 out_nfserr:
-	err = nfserrno(err);
+	err = nfserrno(host_err);
 	goto out;
 }
 
@@ -1406,7 +1415,7 @@
  * Create a symlink and look up its inode
  * N.B. After this call _both_ fhp and resfhp need an fh_put
  */
-int
+__be32
 nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
 				char *fname, int flen,
 				char *path,  int plen,
@@ -1414,7 +1423,8 @@
 				struct iattr *iap)
 {
 	struct dentry	*dentry, *dnew;
-	int		err, cerr;
+	__be32		err, cerr;
+	int		host_err;
 	umode_t		mode;
 
 	err = nfserr_noent;
@@ -1430,7 +1440,7 @@
 	fh_lock(fhp);
 	dentry = fhp->fh_dentry;
 	dnew = lookup_one_len(fname, dentry, flen);
-	err = PTR_ERR(dnew);
+	host_err = PTR_ERR(dnew);
 	if (IS_ERR(dnew))
 		goto out_nfserr;
 
@@ -1442,21 +1452,21 @@
 	if (unlikely(path[plen] != 0)) {
 		char *path_alloced = kmalloc(plen+1, GFP_KERNEL);
 		if (path_alloced == NULL)
-			err = -ENOMEM;
+			host_err = -ENOMEM;
 		else {
 			strncpy(path_alloced, path, plen);
 			path_alloced[plen] = 0;
-			err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode);
+			host_err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode);
 			kfree(path_alloced);
 		}
 	} else
-		err = vfs_symlink(dentry->d_inode, dnew, path, mode);
+		host_err = vfs_symlink(dentry->d_inode, dnew, path, mode);
 
-	if (!err)
+	if (!host_err) {
 		if (EX_ISSYNC(fhp->fh_export))
-			err = nfsd_sync_dir(dentry);
-	if (err)
-		err = nfserrno(err);
+			host_err = nfsd_sync_dir(dentry);
+	} 
+	err = nfserrno(host_err);
 	fh_unlock(fhp);
 
 	cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
@@ -1466,7 +1476,7 @@
 	return err;
 
 out_nfserr:
-	err = nfserrno(err);
+	err = nfserrno(host_err);
 	goto out;
 }
 
@@ -1474,13 +1484,14 @@
  * Create a hardlink
  * N.B. After this call _both_ ffhp and tfhp need an fh_put
  */
-int
+__be32
 nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
 				char *name, int len, struct svc_fh *tfhp)
 {
 	struct dentry	*ddir, *dnew, *dold;
 	struct inode	*dirp, *dest;
-	int		err;
+	__be32		err;
+	int		host_err;
 
 	err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE);
 	if (err)
@@ -1501,24 +1512,25 @@
 	dirp = ddir->d_inode;
 
 	dnew = lookup_one_len(name, ddir, len);
-	err = PTR_ERR(dnew);
+	host_err = PTR_ERR(dnew);
 	if (IS_ERR(dnew))
 		goto out_nfserr;
 
 	dold = tfhp->fh_dentry;
 	dest = dold->d_inode;
 
-	err = vfs_link(dold, dirp, dnew);
-	if (!err) {
+	host_err = vfs_link(dold, dirp, dnew);
+	if (!host_err) {
 		if (EX_ISSYNC(ffhp->fh_export)) {
 			err = nfserrno(nfsd_sync_dir(ddir));
 			write_inode_now(dest, 1);
 		}
+		err = 0;
 	} else {
-		if (err == -EXDEV && rqstp->rq_vers == 2)
+		if (host_err == -EXDEV && rqstp->rq_vers == 2)
 			err = nfserr_acces;
 		else
-			err = nfserrno(err);
+			err = nfserrno(host_err);
 	}
 
 	fh_unlock(ffhp);
@@ -1527,7 +1539,7 @@
 	return err;
 
 out_nfserr:
-	err = nfserrno(err);
+	err = nfserrno(host_err);
 	goto out;
 }
 
@@ -1535,13 +1547,14 @@
  * Rename a file
  * N.B. After this call _both_ ffhp and tfhp need an fh_put
  */
-int
+__be32
 nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
 			    struct svc_fh *tfhp, char *tname, int tlen)
 {
 	struct dentry	*fdentry, *tdentry, *odentry, *ndentry, *trap;
 	struct inode	*fdir, *tdir;
-	int		err;
+	__be32		err;
+	int		host_err;
 
 	err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_REMOVE);
 	if (err)
@@ -1572,22 +1585,22 @@
 	fill_pre_wcc(tfhp);
 
 	odentry = lookup_one_len(fname, fdentry, flen);
-	err = PTR_ERR(odentry);
+	host_err = PTR_ERR(odentry);
 	if (IS_ERR(odentry))
 		goto out_nfserr;
 
-	err = -ENOENT;
+	host_err = -ENOENT;
 	if (!odentry->d_inode)
 		goto out_dput_old;
-	err = -EINVAL;
+	host_err = -EINVAL;
 	if (odentry == trap)
 		goto out_dput_old;
 
 	ndentry = lookup_one_len(tname, tdentry, tlen);
-	err = PTR_ERR(ndentry);
+	host_err = PTR_ERR(ndentry);
 	if (IS_ERR(ndentry))
 		goto out_dput_old;
-	err = -ENOTEMPTY;
+	host_err = -ENOTEMPTY;
 	if (ndentry == trap)
 		goto out_dput_new;
 
@@ -1595,14 +1608,14 @@
 	if ((ffhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
 		((atomic_read(&odentry->d_count) > 1)
 		 || (atomic_read(&ndentry->d_count) > 1))) {
-			err = -EPERM;
+			host_err = -EPERM;
 	} else
 #endif
-	err = vfs_rename(fdir, odentry, tdir, ndentry);
-	if (!err && EX_ISSYNC(tfhp->fh_export)) {
-		err = nfsd_sync_dir(tdentry);
-		if (!err)
-			err = nfsd_sync_dir(fdentry);
+	host_err = vfs_rename(fdir, odentry, tdir, ndentry);
+	if (!host_err && EX_ISSYNC(tfhp->fh_export)) {
+		host_err = nfsd_sync_dir(tdentry);
+		if (!host_err)
+			host_err = nfsd_sync_dir(fdentry);
 	}
 
  out_dput_new:
@@ -1610,8 +1623,7 @@
  out_dput_old:
 	dput(odentry);
  out_nfserr:
-	if (err)
-		err = nfserrno(err);
+	err = nfserrno(host_err);
 
 	/* we cannot reply on fh_unlock on the two filehandles,
 	 * as that would do the wrong thing if the two directories
@@ -1630,13 +1642,14 @@
  * Unlink a file or directory
  * N.B. After this call fhp needs an fh_put
  */
-int
+__be32
 nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
 				char *fname, int flen)
 {
 	struct dentry	*dentry, *rdentry;
 	struct inode	*dirp;
-	int		err;
+	__be32		err;
+	int		host_err;
 
 	err = nfserr_acces;
 	if (!flen || isdotent(fname, flen))
@@ -1650,7 +1663,7 @@
 	dirp = dentry->d_inode;
 
 	rdentry = lookup_one_len(fname, dentry, flen);
-	err = PTR_ERR(rdentry);
+	host_err = PTR_ERR(rdentry);
 	if (IS_ERR(rdentry))
 		goto out_nfserr;
 
@@ -1667,22 +1680,23 @@
 #ifdef MSNFS
 		if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
 			(atomic_read(&rdentry->d_count) > 1)) {
-			err = -EPERM;
+			host_err = -EPERM;
 		} else
 #endif
-		err = vfs_unlink(dirp, rdentry);
+		host_err = vfs_unlink(dirp, rdentry);
 	} else { /* It's RMDIR */
-		err = vfs_rmdir(dirp, rdentry);
+		host_err = vfs_rmdir(dirp, rdentry);
 	}
 
 	dput(rdentry);
 
-	if (err == 0 &&
-	    EX_ISSYNC(fhp->fh_export))
-			err = nfsd_sync_dir(dentry);
+	if (host_err)
+		goto out_nfserr;
+	if (EX_ISSYNC(fhp->fh_export)) 
+		host_err = nfsd_sync_dir(dentry);
 
 out_nfserr:
-	err = nfserrno(err);
+	err = nfserrno(host_err);
 out:
 	return err;
 }
@@ -1691,11 +1705,12 @@
  * Read entries from a directory.
  * The  NFSv3/4 verifier we ignore for now.
  */
-int
+__be32
 nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, 
 	     struct readdir_cd *cdp, encode_dent_fn func)
 {
-	int		err;
+	__be32		err;
+	int 		host_err;
 	struct file	*file;
 	loff_t		offset = *offsetp;
 
@@ -1717,10 +1732,10 @@
 
 	do {
 		cdp->err = nfserr_eof; /* will be cleared on successful read */
-		err = vfs_readdir(file, (filldir_t) func, cdp);
-	} while (err >=0 && cdp->err == nfs_ok);
-	if (err)
-		err = nfserrno(err);
+		host_err = vfs_readdir(file, (filldir_t) func, cdp);
+	} while (host_err >=0 && cdp->err == nfs_ok);
+	if (host_err)
+		err = nfserrno(host_err);
 	else
 		err = cdp->err;
 	*offsetp = vfs_llseek(file, 0, 1);
@@ -1737,10 +1752,10 @@
  * Get file system stats
  * N.B. After this call fhp needs an fh_put
  */
-int
+__be32
 nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
 {
-	int err = fh_verify(rqstp, fhp, 0, MAY_NOP);
+	__be32 err = fh_verify(rqstp, fhp, 0, MAY_NOP);
 	if (!err && vfs_statfs(fhp->fh_dentry->d_inode->i_sb,stat))
 		err = nfserr_io;
 	return err;
@@ -1749,7 +1764,7 @@
 /*
  * Check for a user's access permissions to this inode.
  */
-int
+__be32
 nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
 {
 	struct inode	*inode = dentry->d_inode;
diff -urN oldtree/fs/ntfs/aops.c newtree/fs/ntfs/aops.c
--- oldtree/fs/ntfs/aops.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/ntfs/aops.c	2006-02-21 15:58:27.326992224 +0000
@@ -1279,18 +1279,18 @@
 		
 		tni = locked_nis[nr_locked_nis];
 		/* Get the base inode. */
-		down(&tni->extent_lock);
+		mutex_lock(&tni->extent_lock);
 		if (tni->nr_extents >= 0)
 			base_tni = tni;
 		else {
 			base_tni = tni->ext.base_ntfs_ino;
 			BUG_ON(!base_tni);
 		}
-		up(&tni->extent_lock);
+		mutex_unlock(&tni->extent_lock);
 		ntfs_debug("Unlocking %s inode 0x%lx.",
 				tni == base_tni ? "base" : "extent",
 				tni->mft_no);
-		up(&tni->mrec_lock);
+		mutex_unlock(&tni->mrec_lock);
 		atomic_dec(&tni->count);
 		iput(VFS_I(base_tni));
 	}
diff -urN oldtree/fs/ntfs/compress.c newtree/fs/ntfs/compress.c
--- oldtree/fs/ntfs/compress.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/ntfs/compress.c	2006-02-21 15:58:27.328991920 +0000
@@ -67,7 +67,7 @@
 /**
  * allocate_compression_buffers - allocate the decompression buffers
  *
- * Caller has to hold the ntfs_lock semaphore.
+ * Caller has to hold the ntfs_lock mutex.
  *
  * Return 0 on success or -ENOMEM if the allocations failed.
  */
@@ -84,7 +84,7 @@
 /**
  * free_compression_buffers - free the decompression buffers
  *
- * Caller has to hold the ntfs_lock semaphore.
+ * Caller has to hold the ntfs_lock mutex.
  */
 void free_compression_buffers(void)
 {
diff -urN oldtree/fs/ntfs/file.c newtree/fs/ntfs/file.c
--- oldtree/fs/ntfs/file.c	2006-02-19 11:41:05.215550216 +0000
+++ newtree/fs/ntfs/file.c	2006-02-21 15:58:17.085549160 +0000
@@ -248,7 +248,7 @@
 		 * enough to make ntfs_writepage() work.
 		 */
 		write_lock_irqsave(&ni->size_lock, flags);
-		ni->initialized_size = (index + 1) << PAGE_CACHE_SHIFT;
+		ni->initialized_size = (s64)(index + 1) << PAGE_CACHE_SHIFT;
 		if (ni->initialized_size > new_init_size)
 			ni->initialized_size = new_init_size;
 		write_unlock_irqrestore(&ni->size_lock, flags);
diff -urN oldtree/fs/ntfs/inode.c newtree/fs/ntfs/inode.c
--- oldtree/fs/ntfs/inode.c	2006-02-19 11:41:05.218549760 +0000
+++ newtree/fs/ntfs/inode.c	2006-02-21 15:58:27.345989336 +0000
@@ -382,7 +382,7 @@
 	atomic_set(&ni->count, 1);
 	ni->vol = NTFS_SB(sb);
 	ntfs_init_runlist(&ni->runlist);
-	init_MUTEX(&ni->mrec_lock);
+	mutex_init(&ni->mrec_lock);
 	ni->page = NULL;
 	ni->page_ofs = 0;
 	ni->attr_list_size = 0;
@@ -394,7 +394,7 @@
 	ni->itype.index.collation_rule = 0;
 	ni->itype.index.block_size_bits = 0;
 	ni->itype.index.vcn_size_bits = 0;
-	init_MUTEX(&ni->extent_lock);
+	mutex_init(&ni->extent_lock);
 	ni->nr_extents = 0;
 	ni->ext.base_ntfs_ino = NULL;
 }
@@ -3023,7 +3023,7 @@
 	if (NInoDirty(ni))
 		err = write_mft_record(ni, m, sync);
 	/* Write all attached extent mft records. */
-	down(&ni->extent_lock);
+	mutex_lock(&ni->extent_lock);
 	if (ni->nr_extents > 0) {
 		ntfs_inode **extent_nis = ni->ext.extent_ntfs_inos;
 		int i;
@@ -3050,7 +3050,7 @@
 			}
 		}
 	}
-	up(&ni->extent_lock);
+	mutex_unlock(&ni->extent_lock);
 	unmap_mft_record(ni);
 	if (unlikely(err))
 		goto err_out;
diff -urN oldtree/fs/ntfs/inode.h newtree/fs/ntfs/inode.h
--- oldtree/fs/ntfs/inode.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/ntfs/inode.h	2006-02-21 15:58:27.354987968 +0000
@@ -29,7 +29,7 @@
 #include <linux/seq_file.h>
 #include <linux/list.h>
 #include <asm/atomic.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include "layout.h"
 #include "volume.h"
@@ -81,7 +81,7 @@
 	 * The following fields are only valid for real inodes and extent
 	 * inodes.
 	 */
-	struct semaphore mrec_lock; /* Lock for serializing access to the
+	struct mutex mrec_lock; /* Lock for serializing access to the
 				   mft record belonging to this inode. */
 	struct page *page;	/* The page containing the mft record of the
 				   inode. This should only be touched by the
@@ -119,7 +119,7 @@
 			u8 block_clusters;	/* Number of clusters per cb. */
 		} compressed;
 	} itype;
-	struct semaphore extent_lock;	/* Lock for accessing/modifying the
+	struct mutex extent_lock;	/* Lock for accessing/modifying the
 					   below . */
 	s32 nr_extents;	/* For a base mft record, the number of attached extent
 			   inodes (0 if none), for extent records and for fake
diff -urN oldtree/fs/ntfs/mft.c newtree/fs/ntfs/mft.c
--- oldtree/fs/ntfs/mft.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/ntfs/mft.c	2006-02-21 15:58:27.357987512 +0000
@@ -104,8 +104,8 @@
  * map_mft_record - map, pin and lock an mft record
  * @ni:		ntfs inode whose MFT record to map
  *
- * First, take the mrec_lock semaphore. We might now be sleeping, while waiting
- * for the semaphore if it was already locked by someone else.
+ * First, take the mrec_lock mutex. We might now be sleeping, while waiting
+ * for the mutex if it was already locked by someone else.
  *
  * The page of the record is mapped using map_mft_record_page() before being
  * returned to the caller.
@@ -135,7 +135,7 @@
  * So that code will end up having to own the mrec_lock of all mft
  * records/inodes present in the page before I/O can proceed. In that case we
  * wouldn't need to bother with PG_locked and PG_uptodate as nobody will be
- * accessing anything without owning the mrec_lock semaphore. But we do need
+ * accessing anything without owning the mrec_lock mutex. But we do need
  * to use them because of the read_cache_page() invocation and the code becomes
  * so much simpler this way that it is well worth it.
  *
@@ -160,13 +160,13 @@
 	atomic_inc(&ni->count);
 
 	/* Serialize access to this mft record. */
-	down(&ni->mrec_lock);
+	mutex_lock(&ni->mrec_lock);
 
 	m = map_mft_record_page(ni);
 	if (likely(!IS_ERR(m)))
 		return m;
 
-	up(&ni->mrec_lock);
+	mutex_unlock(&ni->mrec_lock);
 	atomic_dec(&ni->count);
 	ntfs_error(ni->vol->sb, "Failed with error code %lu.", -PTR_ERR(m));
 	return m;
@@ -217,7 +217,7 @@
 	ntfs_debug("Entering for mft_no 0x%lx.", ni->mft_no);
 
 	unmap_mft_record_page(ni);
-	up(&ni->mrec_lock);
+	mutex_unlock(&ni->mrec_lock);
 	atomic_dec(&ni->count);
 	/*
 	 * If pure ntfs_inode, i.e. no vfs inode attached, we leave it to
@@ -261,7 +261,7 @@
 	 * in which case just return it. If not found, add it to the base
 	 * inode before returning it.
 	 */
-	down(&base_ni->extent_lock);
+	mutex_lock(&base_ni->extent_lock);
 	if (base_ni->nr_extents > 0) {
 		extent_nis = base_ni->ext.extent_ntfs_inos;
 		for (i = 0; i < base_ni->nr_extents; i++) {
@@ -274,7 +274,7 @@
 		}
 	}
 	if (likely(ni != NULL)) {
-		up(&base_ni->extent_lock);
+		mutex_unlock(&base_ni->extent_lock);
 		atomic_dec(&base_ni->count);
 		/* We found the record; just have to map and return it. */
 		m = map_mft_record(ni);
@@ -301,7 +301,7 @@
 	/* Record wasn't there. Get a new ntfs inode and initialize it. */
 	ni = ntfs_new_extent_inode(base_ni->vol->sb, mft_no);
 	if (unlikely(!ni)) {
-		up(&base_ni->extent_lock);
+		mutex_unlock(&base_ni->extent_lock);
 		atomic_dec(&base_ni->count);
 		return ERR_PTR(-ENOMEM);
 	}
@@ -312,7 +312,7 @@
 	/* Now map the record. */
 	m = map_mft_record(ni);
 	if (IS_ERR(m)) {
-		up(&base_ni->extent_lock);
+		mutex_unlock(&base_ni->extent_lock);
 		atomic_dec(&base_ni->count);
 		ntfs_clear_extent_inode(ni);
 		goto map_err_out;
@@ -347,14 +347,14 @@
 		base_ni->ext.extent_ntfs_inos = tmp;
 	}
 	base_ni->ext.extent_ntfs_inos[base_ni->nr_extents++] = ni;
-	up(&base_ni->extent_lock);
+	mutex_unlock(&base_ni->extent_lock);
 	atomic_dec(&base_ni->count);
 	ntfs_debug("Done 2.");
 	*ntfs_ino = ni;
 	return m;
 unm_err_out:
 	unmap_mft_record(ni);
-	up(&base_ni->extent_lock);
+	mutex_unlock(&base_ni->extent_lock);
 	atomic_dec(&base_ni->count);
 	/*
 	 * If the extent inode was not attached to the base inode we need to
@@ -399,12 +399,12 @@
 	BUG_ON(NInoAttr(ni));
 	mark_ntfs_record_dirty(ni->page, ni->page_ofs);
 	/* Determine the base vfs inode and mark it dirty, too. */
-	down(&ni->extent_lock);
+	mutex_lock(&ni->extent_lock);
 	if (likely(ni->nr_extents >= 0))
 		base_ni = ni;
 	else
 		base_ni = ni->ext.base_ntfs_ino;
-	up(&ni->extent_lock);
+	mutex_unlock(&ni->extent_lock);
 	__mark_inode_dirty(VFS_I(base_ni), I_DIRTY_SYNC | I_DIRTY_DATASYNC);
 }
 
@@ -983,7 +983,7 @@
 		}
 		ntfs_debug("Inode 0x%lx is not dirty.", mft_no);
 		/* The inode is not dirty, try to take the mft record lock. */
-		if (unlikely(down_trylock(&ni->mrec_lock))) {
+		if (unlikely(!mutex_trylock(&ni->mrec_lock))) {
 			ntfs_debug("Mft record 0x%lx is already locked, do "
 					"not write it.", mft_no);
 			atomic_dec(&ni->count);
@@ -1043,13 +1043,13 @@
 	 * corresponding to this extent mft record attached.
 	 */
 	ni = NTFS_I(vi);
-	down(&ni->extent_lock);
+	mutex_lock(&ni->extent_lock);
 	if (ni->nr_extents <= 0) {
 		/*
 		 * The base inode has no attached extent inodes, write this
 		 * extent mft record.
 		 */
-		up(&ni->extent_lock);
+		mutex_unlock(&ni->extent_lock);
 		iput(vi);
 		ntfs_debug("Base inode 0x%lx has no attached extent inodes, "
 				"write the extent record.", na.mft_no);
@@ -1072,7 +1072,7 @@
 	 * extent mft record.
 	 */
 	if (!eni) {
-		up(&ni->extent_lock);
+		mutex_unlock(&ni->extent_lock);
 		iput(vi);
 		ntfs_debug("Extent inode 0x%lx is not attached to its base "
 				"inode 0x%lx, write the extent record.",
@@ -1083,12 +1083,12 @@
 			mft_no, na.mft_no);
 	/* Take a reference to the extent ntfs inode. */
 	atomic_inc(&eni->count);
-	up(&ni->extent_lock);
+	mutex_unlock(&ni->extent_lock);
 	/*
 	 * Found the extent inode coresponding to this extent mft record.
 	 * Try to take the mft record lock.
 	 */
-	if (unlikely(down_trylock(&eni->mrec_lock))) {
+	if (unlikely(!mutex_trylock(&eni->mrec_lock))) {
 		atomic_dec(&eni->count);
 		iput(vi);
 		ntfs_debug("Extent mft record 0x%lx is already locked, do "
@@ -2711,7 +2711,7 @@
 		 * have its page mapped and it is very easy to do.
 		 */
 		atomic_inc(&ni->count);
-		down(&ni->mrec_lock);
+		mutex_lock(&ni->mrec_lock);
 		ni->page = page;
 		ni->page_ofs = ofs;
 		/*
@@ -2798,22 +2798,22 @@
 	BUG_ON(NInoAttr(ni));
 	BUG_ON(ni->nr_extents != -1);
 
-	down(&ni->extent_lock);
+	mutex_lock(&ni->extent_lock);
 	base_ni = ni->ext.base_ntfs_ino;
-	up(&ni->extent_lock);
+	mutex_unlock(&ni->extent_lock);
 
 	BUG_ON(base_ni->nr_extents <= 0);
 
 	ntfs_debug("Entering for extent inode 0x%lx, base inode 0x%lx.\n",
 			mft_no, base_ni->mft_no);
 
-	down(&base_ni->extent_lock);
+	mutex_lock(&base_ni->extent_lock);
 
 	/* Make sure we are holding the only reference to the extent inode. */
 	if (atomic_read(&ni->count) > 2) {
 		ntfs_error(vol->sb, "Tried to free busy extent inode 0x%lx, "
 				"not freeing.", base_ni->mft_no);
-		up(&base_ni->extent_lock);
+		mutex_unlock(&base_ni->extent_lock);
 		return -EBUSY;
 	}
 
@@ -2831,7 +2831,7 @@
 		break;
 	}
 
-	up(&base_ni->extent_lock);
+	mutex_unlock(&base_ni->extent_lock);
 
 	if (unlikely(err)) {
 		ntfs_error(vol->sb, "Extent inode 0x%lx is not attached to "
@@ -2890,7 +2890,7 @@
 	return 0;
 rollback:
 	/* Rollback what we did... */
-	down(&base_ni->extent_lock);
+	mutex_lock(&base_ni->extent_lock);
 	extent_nis = base_ni->ext.extent_ntfs_inos;
 	if (!(base_ni->nr_extents & 3)) {
 		int new_size = (base_ni->nr_extents + 4) * sizeof(ntfs_inode*);
@@ -2899,7 +2899,7 @@
 		if (unlikely(!extent_nis)) {
 			ntfs_error(vol->sb, "Failed to allocate internal "
 					"buffer during rollback.%s", es);
-			up(&base_ni->extent_lock);
+			mutex_unlock(&base_ni->extent_lock);
 			NVolSetErrors(vol);
 			goto rollback_error;
 		}
@@ -2914,7 +2914,7 @@
 	m->flags |= MFT_RECORD_IN_USE;
 	m->sequence_number = old_seq_no;
 	extent_nis[base_ni->nr_extents++] = ni;
-	up(&base_ni->extent_lock);
+	mutex_unlock(&base_ni->extent_lock);
 	mark_mft_record_dirty(ni);
 	return err;
 }
diff -urN oldtree/fs/ntfs/ntfs.h newtree/fs/ntfs/ntfs.h
--- oldtree/fs/ntfs/ntfs.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/ntfs/ntfs.h	2006-02-21 15:58:27.358987360 +0000
@@ -91,7 +91,7 @@
 
 /* From fs/ntfs/super.c */
 #define default_upcase_len 0x10000
-extern struct semaphore ntfs_lock;
+extern struct mutex ntfs_lock;
 
 typedef struct {
 	int val;
diff -urN oldtree/fs/ntfs/super.c newtree/fs/ntfs/super.c
--- oldtree/fs/ntfs/super.c	2006-02-19 11:41:05.220549456 +0000
+++ newtree/fs/ntfs/super.c	2006-02-21 15:58:27.361986904 +0000
@@ -1635,11 +1635,11 @@
 	ntfs_debug("Read %llu bytes from $UpCase (expected %zu bytes).",
 			i_size, 64 * 1024 * sizeof(ntfschar));
 	iput(ino);
-	down(&ntfs_lock);
+	mutex_lock(&ntfs_lock);
 	if (!default_upcase) {
 		ntfs_debug("Using volume specified $UpCase since default is "
 				"not present.");
-		up(&ntfs_lock);
+		mutex_unlock(&ntfs_lock);
 		return TRUE;
 	}
 	max = default_upcase_len;
@@ -1653,12 +1653,12 @@
 		vol->upcase = default_upcase;
 		vol->upcase_len = max;
 		ntfs_nr_upcase_users++;
-		up(&ntfs_lock);
+		mutex_unlock(&ntfs_lock);
 		ntfs_debug("Volume specified $UpCase matches default. Using "
 				"default.");
 		return TRUE;
 	}
-	up(&ntfs_lock);
+	mutex_unlock(&ntfs_lock);
 	ntfs_debug("Using volume specified $UpCase since it does not match "
 			"the default.");
 	return TRUE;
@@ -1667,17 +1667,17 @@
 	ntfs_free(vol->upcase);
 	vol->upcase = NULL;
 upcase_failed:
-	down(&ntfs_lock);
+	mutex_lock(&ntfs_lock);
 	if (default_upcase) {
 		vol->upcase = default_upcase;
 		vol->upcase_len = default_upcase_len;
 		ntfs_nr_upcase_users++;
-		up(&ntfs_lock);
+		mutex_unlock(&ntfs_lock);
 		ntfs_error(sb, "Failed to load $UpCase from the volume. Using "
 				"default.");
 		return TRUE;
 	}
-	up(&ntfs_lock);
+	mutex_unlock(&ntfs_lock);
 	ntfs_error(sb, "Failed to initialize upcase table.");
 	return FALSE;
 }
@@ -2140,12 +2140,12 @@
 iput_upcase_err_out:
 #endif /* NTFS_RW */
 	vol->upcase_len = 0;
-	down(&ntfs_lock);
+	mutex_lock(&ntfs_lock);
 	if (vol->upcase == default_upcase) {
 		ntfs_nr_upcase_users--;
 		vol->upcase = NULL;
 	}
-	up(&ntfs_lock);
+	mutex_unlock(&ntfs_lock);
 	if (vol->upcase) {
 		ntfs_free(vol->upcase);
 		vol->upcase = NULL;
@@ -2350,7 +2350,7 @@
 	 * Destroy the global default upcase table if necessary.  Also decrease
 	 * the number of upcase users if we are a user.
 	 */
-	down(&ntfs_lock);
+	mutex_lock(&ntfs_lock);
 	if (vol->upcase == default_upcase) {
 		ntfs_nr_upcase_users--;
 		vol->upcase = NULL;
@@ -2361,7 +2361,7 @@
 	}
 	if (vol->cluster_size <= 4096 && !--ntfs_nr_compression_users)
 		free_compression_buffers();
-	up(&ntfs_lock);
+	mutex_unlock(&ntfs_lock);
 	if (vol->upcase) {
 		ntfs_free(vol->upcase);
 		vol->upcase = NULL;
@@ -2811,7 +2811,7 @@
 			ntfs_error(sb, "Failed to load essential metadata.");
 		goto iput_tmp_ino_err_out_now;
 	}
-	down(&ntfs_lock);
+	mutex_lock(&ntfs_lock);
 	/*
 	 * The current mount is a compression user if the cluster size is
 	 * less than or equal 4kiB.
@@ -2822,7 +2822,7 @@
 			ntfs_error(NULL, "Failed to allocate buffers "
 					"for compression engine.");
 			ntfs_nr_compression_users--;
-			up(&ntfs_lock);
+			mutex_unlock(&ntfs_lock);
 			goto iput_tmp_ino_err_out_now;
 		}
 	}
@@ -2834,7 +2834,7 @@
 	if (!default_upcase)
 		default_upcase = generate_default_upcase();
 	ntfs_nr_upcase_users++;
-	up(&ntfs_lock);
+	mutex_unlock(&ntfs_lock);
 	/*
 	 * From now on, ignore @silent parameter. If we fail below this line,
 	 * it will be due to a corrupt fs or a system error, so we report it.
@@ -2852,12 +2852,12 @@
 		atomic_inc(&vol->root_ino->i_count);
 		ntfs_debug("Exiting, status successful.");
 		/* Release the default upcase if it has no users. */
-		down(&ntfs_lock);
+		mutex_lock(&ntfs_lock);
 		if (!--ntfs_nr_upcase_users && default_upcase) {
 			ntfs_free(default_upcase);
 			default_upcase = NULL;
 		}
-		up(&ntfs_lock);
+		mutex_unlock(&ntfs_lock);
 		sb->s_export_op = &ntfs_export_ops;
 		lock_kernel();
 		return 0;
@@ -2925,12 +2925,12 @@
 		vol->attrdef = NULL;
 	}
 	vol->upcase_len = 0;
-	down(&ntfs_lock);
+	mutex_lock(&ntfs_lock);
 	if (vol->upcase == default_upcase) {
 		ntfs_nr_upcase_users--;
 		vol->upcase = NULL;
 	}
-	up(&ntfs_lock);
+	mutex_unlock(&ntfs_lock);
 	if (vol->upcase) {
 		ntfs_free(vol->upcase);
 		vol->upcase = NULL;
@@ -2945,14 +2945,14 @@
 	 * Decrease the number of upcase users and destroy the global default
 	 * upcase table if necessary.
 	 */
-	down(&ntfs_lock);
+	mutex_lock(&ntfs_lock);
 	if (!--ntfs_nr_upcase_users && default_upcase) {
 		ntfs_free(default_upcase);
 		default_upcase = NULL;
 	}
 	if (vol->cluster_size <= 4096 && !--ntfs_nr_compression_users)
 		free_compression_buffers();
-	up(&ntfs_lock);
+	mutex_unlock(&ntfs_lock);
 iput_tmp_ino_err_out_now:
 	iput(tmp_ino);
 	if (vol->mft_ino && vol->mft_ino != tmp_ino)
@@ -3012,7 +3012,7 @@
 kmem_cache_t *ntfs_index_ctx_cache;
 
 /* Driver wide semaphore. */
-DECLARE_MUTEX(ntfs_lock);
+DEFINE_MUTEX(ntfs_lock);
 
 static struct super_block *ntfs_get_sb(struct file_system_type *fs_type,
 	int flags, const char *dev_name, void *data)
diff -urN oldtree/fs/ocfs2/journal.c newtree/fs/ocfs2/journal.c
--- oldtree/fs/ocfs2/journal.c	2006-02-19 11:41:05.273541400 +0000
+++ newtree/fs/ocfs2/journal.c	2006-02-21 15:58:31.739321448 +0000
@@ -582,7 +582,8 @@
 	}
 
 	mlog(0, "inode->i_size = %lld\n", inode->i_size);
-	mlog(0, "inode->i_blocks = %lu\n", inode->i_blocks);
+	mlog(0, "inode->i_blocks = %llu\n",
+			(unsigned long long)inode->i_blocks);
 	mlog(0, "inode->ip_clusters = %u\n", OCFS2_I(inode)->ip_clusters);
 
 	/* call the kernels journal init function now */
@@ -849,8 +850,9 @@
 
 	memset(bhs, 0, sizeof(struct buffer_head *) * CONCURRENT_JOURNAL_FILL);
 
-	mlog(0, "Force reading %lu blocks\n",
-	     (inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9)));
+	mlog(0, "Force reading %llu blocks\n",
+		(unsigned long long)(inode->i_blocks >>
+			(inode->i_sb->s_blocksize_bits - 9)));
 
 	v_blkno = 0;
 	while (v_blkno <
diff -urN oldtree/fs/ocfs2/namei.c newtree/fs/ocfs2/namei.c
--- oldtree/fs/ocfs2/namei.c	2006-02-19 11:41:05.279540488 +0000
+++ newtree/fs/ocfs2/namei.c	2006-02-21 15:58:31.780315216 +0000
@@ -1443,8 +1443,9 @@
 	 * write i_size + 1 bytes. */
 	blocks = (bytes_left + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
 
-	mlog_entry("i_blocks = %lu, i_size = %llu, blocks = %d\n",
-		       inode->i_blocks, i_size_read(inode), blocks);
+	mlog_entry("i_blocks = %llu, i_size = %llu, blocks = %d\n",
+			(unsigned long long)inode->i_blocks,
+			i_size_read(inode), blocks);
 
 	/* Sanity check -- make sure we're going to fit. */
 	if (bytes_left >
diff -urN oldtree/fs/open.c newtree/fs/open.c
--- oldtree/fs/open.c	2006-02-19 11:41:05.304536688 +0000
+++ newtree/fs/open.c	2006-02-21 15:58:23.592559944 +0000
@@ -27,6 +27,7 @@
 #include <linux/pagemap.h>
 #include <linux/syscalls.h>
 #include <linux/rcupdate.h>
+#include <linux/audit.h>
 
 #include <asm/unistd.h>
 
@@ -626,6 +627,8 @@
 	dentry = file->f_dentry;
 	inode = dentry->d_inode;
 
+	audit_inode(NULL, inode, 0);
+
 	err = -EROFS;
 	if (IS_RDONLY(inode))
 		goto out_putf;
@@ -775,7 +778,10 @@
 
 	file = fget(fd);
 	if (file) {
-		error = chown_common(file->f_dentry, user, group);
+		struct dentry * dentry;
+		dentry = file->f_dentry;
+		audit_inode(NULL, dentry->d_inode, 0);
+		error = chown_common(dentry, user, group);
 		fput(file);
 	}
 	return error;
@@ -973,7 +979,7 @@
 	fdt = files_fdtable(files);
  	fd = find_next_zero_bit(fdt->open_fds->fds_bits,
 				fdt->max_fdset,
-				fdt->next_fd);
+				files->next_fd);
 
 	/*
 	 * N.B. For clone tasks sharing a files structure, this test
@@ -998,7 +1004,7 @@
 
 	FD_SET(fd, fdt->open_fds);
 	FD_CLR(fd, fdt->close_on_exec);
-	fdt->next_fd = fd + 1;
+	files->next_fd = fd + 1;
 #if 1
 	/* Sanity check */
 	if (fdt->fd[fd] != NULL) {
@@ -1019,8 +1025,8 @@
 {
 	struct fdtable *fdt = files_fdtable(files);
 	__FD_CLR(fd, fdt->open_fds);
-	if (fd < fdt->next_fd)
-		fdt->next_fd = fd;
+	if (fd < files->next_fd)
+		files->next_fd = fd;
 }
 
 void fastcall put_unused_fd(unsigned int fd)
diff -urN oldtree/fs/partitions/devfs.c newtree/fs/partitions/devfs.c
--- oldtree/fs/partitions/devfs.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/partitions/devfs.c	2006-02-21 15:58:23.918510392 +0000
@@ -6,7 +6,7 @@
 #include <linux/vmalloc.h>
 #include <linux/genhd.h>
 #include <linux/bitops.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 
 struct unique_numspace {
@@ -16,7 +16,7 @@
 	struct semaphore  mutex;
 };
 
-static DECLARE_MUTEX(numspace_mutex);
+static DEFINE_MUTEX(numspace_mutex);
 
 static int expand_numspace(struct unique_numspace *s)
 {
@@ -48,7 +48,7 @@
 {
 	int rval = 0;
 
-	down(&numspace_mutex);
+	mutex_lock(&numspace_mutex);
 	if (s->num_free < 1)
 		rval = expand_numspace(s);
 	if (!rval) {
@@ -56,7 +56,7 @@
 		--s->num_free;
 		__set_bit(rval, s->bits);
 	}
-	up(&numspace_mutex);
+	mutex_unlock(&numspace_mutex);
 
 	return rval;
 }
@@ -66,11 +66,11 @@
 	int old_val;
 
 	if (number >= 0) {
-		down(&numspace_mutex);
+		mutex_lock(&numspace_mutex);
 		old_val = __test_and_clear_bit(number, s->bits);
 		if (old_val)
 			++s->num_free;
-		up(&numspace_mutex);
+		mutex_unlock(&numspace_mutex);
 	}
 }
 
diff -urN oldtree/fs/partitions/msdos.c newtree/fs/partitions/msdos.c
--- oldtree/fs/partitions/msdos.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/partitions/msdos.c	2006-02-21 15:58:36.666572392 +0000
@@ -33,13 +33,11 @@
 #include <asm/unaligned.h>
 
 #define SYS_IND(p)	(get_unaligned(&p->sys_ind))
-#define NR_SECTS(p)	({ __typeof__(p->nr_sects) __a =	\
-				get_unaligned(&p->nr_sects);	\
+#define NR_SECTS(p)	({ __le32 __a =	get_unaligned(&p->nr_sects);	\
 				le32_to_cpu(__a); \
 			})
 
-#define START_SECT(p)	({ __typeof__(p->start_sect) __a =	\
-				get_unaligned(&p->start_sect);	\
+#define START_SECT(p)	({ __le32 __a =	get_unaligned(&p->start_sect);	\
 				le32_to_cpu(__a); \
 			})
 
diff -urN oldtree/fs/proc/inode.c newtree/fs/proc/inode.c
--- oldtree/fs/proc/inode.c	2006-02-19 11:41:05.311535624 +0000
+++ newtree/fs/proc/inode.c	2006-02-21 15:58:36.668572088 +0000
@@ -204,10 +204,6 @@
 	root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root);
 	if (!root_inode)
 		goto out_no_root;
-	/*
-	 * Fixup the root inode's nlink value
-	 */
-	root_inode->i_nlink += nr_processes();
 	root_inode->i_uid = 0;
 	root_inode->i_gid = 0;
 	s->s_root = d_alloc_root(root_inode);
diff -urN oldtree/fs/proc/root.c newtree/fs/proc/root.c
--- oldtree/fs/proc/root.c	2006-02-19 11:41:05.313535320 +0000
+++ newtree/fs/proc/root.c	2006-02-21 15:58:36.668572088 +0000
@@ -80,16 +80,16 @@
 	proc_bus = proc_mkdir("bus", NULL);
 }
 
-static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+static int proc_root_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat
+)
 {
-	/*
-	 * nr_threads is actually protected by the tasklist_lock;
-	 * however, it's conventional to do reads, especially for
-	 * reporting, without any locking whatsoever.
-	 */
-	if (dir->i_ino == PROC_ROOT_INO) /* check for safety... */
-		dir->i_nlink = proc_root.nlink + nr_threads;
+	generic_fillattr(dentry->d_inode, stat);
+	stat->nlink = proc_root.nlink + nr_processes();
+	return 0;
+}
 
+static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+{
 	if (!proc_lookup(dir, dentry, nd)) {
 		return NULL;
 	}
@@ -134,6 +134,7 @@
  */
 static struct inode_operations proc_root_inode_operations = {
 	.lookup		= proc_root_lookup,
+	.getattr	= proc_root_getattr,
 };
 
 /*
diff -urN oldtree/fs/reiser4/Kconfig newtree/fs/reiser4/Kconfig
--- oldtree/fs/reiser4/Kconfig	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/Kconfig	2006-02-21 15:58:34.554893416 +0000
@@ -0,0 +1,31 @@
+config REISER4_FS
+	tristate "Reiser4 (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	select ZLIB_INFLATE
+	select ZLIB_DEFLATE
+	help
+	  Reiser4 is a filesystem that performs all filesystem operations
+	  as atomic transactions, which means that it either performs a
+	  write, or it does not, and in the event of a crash it does not
+	  partially perform it or corrupt it.
+
+	  It stores files in dancing trees, which are like balanced trees but
+	  faster.  It packs small files together so that they share blocks
+	  without wasting space.  This means you can use it to store really
+	  small files.  It also means that it saves you disk space.  It avoids
+	  hassling you with anachronisms like having a maximum number of
+	  inodes, and wasting space if you use less than that number.
+
+	  Reiser4 is a distinct filesystem type from reiserfs (V3).
+	  It's therefore not possible to use reiserfs file systems
+	  with reiser4.
+
+	  To learn more about reiser4, go to http://www.namesys.com
+
+config REISER4_DEBUG
+	bool "Enable reiser4 debug mode"
+	depends on REISER4_FS
+	help
+	  Don't use this unless you are debugging reiser4.
+
+	  If unsure, say N.
diff -urN oldtree/fs/reiser4/Makefile newtree/fs/reiser4/Makefile
--- oldtree/fs/reiser4/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/Makefile	2006-02-21 15:58:35.182797960 +0000
@@ -0,0 +1,101 @@
+#
+# reiser4/Makefile
+#
+
+obj-$(CONFIG_REISER4_FS) += reiser4.o
+
+reiser4-y := \
+		   debug.o \
+		   jnode.o \
+		   znode.o \
+		   key.o \
+		   pool.o \
+		   tree_mod.o \
+		   estimate.o \
+		   carry.o \
+		   carry_ops.o \
+		   lock.o \
+		   tree.o \
+		   context.o \
+		   tap.o \
+		   coord.o \
+		   block_alloc.o \
+		   txnmgr.o \
+		   kassign.o \
+		   flush.o \
+		   wander.o \
+		   eottl.o \
+		   search.o \
+		   page_cache.o \
+		   seal.o \
+		   dscale.o \
+		   flush_queue.o \
+		   ktxnmgrd.o \
+		   blocknrset.o \
+		   super.o \
+		   super_ops.o \
+		   fsdata.o \
+		   export_ops.o \
+		   oid.o \
+		   tree_walk.o \
+		   inode.o \
+		   vfs_ops.o \
+		   as_ops.o \
+		   emergency_flush.o \
+		   entd.o\
+		   readahead.o \
+		   status_flags.o \
+		   init_super.o \
+		   safe_link.o \
+           \
+		   plugin/plugin.o \
+		   plugin/plugin_set.o \
+		   plugin/node/node.o \
+		   plugin/object.o \
+		   plugin/cluster.o \
+		   plugin/inode_ops.o \
+		   plugin/inode_ops_rename.o \
+		   plugin/file_ops.o \
+		   plugin/file_ops_readdir.o \
+		   plugin/file_plugin_common.o \
+		   plugin/file/file.o \
+		   plugin/file/tail_conversion.o \
+		   plugin/file/symlink.o \
+		   plugin/file/cryptcompress.o \
+		   plugin/dir_plugin_common.o \
+		   plugin/dir/hashed_dir.o \
+		   plugin/dir/seekable_dir.o \
+		   plugin/node/node40.o \
+           \
+		   plugin/crypto/cipher.o \
+		   plugin/crypto/digest.o \
+           \
+		   plugin/compress/minilzo.o \
+		   plugin/compress/compress.o \
+		   plugin/compress/compress_mode.o \
+           \
+		   plugin/item/static_stat.o \
+		   plugin/item/sde.o \
+		   plugin/item/cde.o \
+		   plugin/item/blackbox.o \
+		   plugin/item/internal.o \
+		   plugin/item/tail.o \
+		   plugin/item/ctail.o \
+		   plugin/item/extent.o \
+		   plugin/item/extent_item_ops.o \
+		   plugin/item/extent_file_ops.o \
+		   plugin/item/extent_flush_ops.o \
+           \
+		   plugin/hash.o \
+		   plugin/fibration.o \
+		   plugin/tail_policy.o \
+		   plugin/item/item.o \
+           \
+		   plugin/security/perm.o \
+		   plugin/space/bitmap.o \
+           \
+		   plugin/disk_format/disk_format40.o \
+		   plugin/disk_format/disk_format.o \
+	   \
+		   plugin/regular.o
+
diff -urN oldtree/fs/reiser4/README newtree/fs/reiser4/README
--- oldtree/fs/reiser4/README	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/README	2006-02-21 15:58:34.103961968 +0000
@@ -0,0 +1,125 @@
+[LICENSING]
+
+Reiser4 is hereby licensed under the GNU General
+Public License version 2.
+
+Source code files that contain the phrase "licensing governed by
+reiser4/README" are "governed files" throughout this file.  Governed
+files are licensed under the GPL.  The portions of them owned by Hans
+Reiser, or authorized to be licensed by him, have been in the past,
+and likely will be in the future, licensed to other parties under
+other licenses.  If you add your code to governed files, and don't
+want it to be owned by Hans Reiser, put your copyright label on that
+code so the poor blight and his customers can keep things straight.
+All portions of governed files not labeled otherwise are owned by Hans
+Reiser, and by adding your code to it, widely distributing it to
+others or sending us a patch, and leaving the sentence in stating that
+licensing is governed by the statement in this file, you accept this.
+It will be a kindness if you identify whether Hans Reiser is allowed
+to license code labeled as owned by you on your behalf other than
+under the GPL, because he wants to know if it is okay to do so and put
+a check in the mail to you (for non-trivial improvements) when he
+makes his next sale.  He makes no guarantees as to the amount if any,
+though he feels motivated to motivate contributors, and you can surely
+discuss this with him before or after contributing.  You have the
+right to decline to allow him to license your code contribution other
+than under the GPL.
+
+Further licensing options are available for commercial and/or other
+interests directly from Hans Reiser: reiser@namesys.com.  If you interpret
+the GPL as not allowing those additional licensing options, you read
+it wrongly, and Richard Stallman agrees with me, when carefully read
+you can see that those restrictions on additional terms do not apply
+to the owner of the copyright, and my interpretation of this shall
+govern for this license.
+
+[END LICENSING]
+
+Reiser4 is a file system based on dancing tree algorithms, and is
+described at http://www.namesys.com
+
+mkfs.reiser4 and other utilities are on our webpage or wherever your
+Linux provider put them.  You really want to be running the latest
+version off the website if you use fsck.
+
+Yes, if you update your reiser4 kernel module you do have to
+recompile your kernel, most of the time.  The errors you get will be
+quite cryptic if your forget to do so.
+
+Hideous Commercial Pitch: Spread your development costs across other OS
+vendors.  Select from the best in the world, not the best in your
+building, by buying from third party OS component suppliers.  Leverage
+the software component development power of the internet.  Be the most
+aggressive in taking advantage of the commercial possibilities of
+decentralized internet development, and add value through your branded
+integration that you sell as an operating system.  Let your competitors
+be the ones to compete against the entire internet by themselves.  Be
+hip, get with the new economic trend, before your competitors do.  Send
+email to reiser@namesys.com
+
+Hans Reiser was the primary architect of Reiser4, but a whole team
+chipped their ideas in.  He invested everything he had into Namesys
+for 5.5 dark years of no money before Reiser3 finally started to work well
+enough to bring in money.  He owns the copyright.
+
+DARPA was the primary sponsor of Reiser4.  DARPA does not endorse
+Reiser4, it merely sponsors it.  DARPA is, in solely Hans's personal
+opinion, unique in its willingness to invest into things more
+theoretical than the VC community can readily understand, and more
+longterm than allows them to be sure that they will be the ones to
+extract the economic benefits from.  DARPA also integrated us into a
+security community that transformed our security worldview.
+
+Vladimir Saveliev is our lead programmer, with us from the beginning,
+and he worked long hours writing the cleanest code.  This is why he is
+now the lead programmer after years of commitment to our work.  He
+always made the effort to be the best he could be, and to make his
+code the best that it could be.  What resulted was quite remarkable. I
+don't think that money can ever motivate someone to work the way he
+did, he is one of the most selfless men I know.
+
+Alexander Lyamin was our sysadmin, and helped to educate us in
+security issues.  Moscow State University and IMT were very generous
+in the internet access they provided us, and in lots of other little
+ways that a generous institution can be.
+
+Alexander Zarochentcev (sometimes known as zam, or sasha), wrote the
+locking code, the block allocator, and finished the flushing code.
+His code is always crystal clean and well structured.
+
+Nikita Danilov wrote the core of the balancing code, the core of the
+plugins code, and the directory code.  He worked a steady pace of long
+hours that produced a whole lot of well abstracted code.  He is our
+senior computer scientist.
+
+Vladimir Demidov wrote the parser.  Writing an in kernel parser is
+something very few persons have the skills for, and it is thanks to
+him that we can say that the parser is really not so big compared to
+various bits of our other code, and making a parser work in the kernel
+was not so complicated as everyone would imagine mainly because it was
+him doing it...
+
+Joshua McDonald wrote the transaction manager, and the flush code.
+The flush code unexpectedly turned out be extremely hairy for reasons
+you can read about on our web page, and he did a great job on an
+extremely difficult task.
+
+Nina Reiser handled our accounting, government relations, and much
+more.
+
+Ramon Reiser developed our website.
+
+Beverly Palmer drew our graphics.
+
+Vitaly Fertman developed librepair, userspace plugins repair code, fsck
+and worked with Umka on developing libreiser4 and userspace plugins.
+
+Yury Umanets (aka Umka) developed libreiser4, userspace plugins and
+userspace tools (reiser4progs).
+
+Oleg Drokin (aka Green) is the release manager who fixes everything.
+It is so nice to have someone like that on the team.  He (plus Chris
+and Jeff) make it possible for the entire rest of the Namesys team to
+focus on Reiser4, and he fixed a whole lot of Reiser4 bugs also.  It
+is just amazing to watch his talent for spotting bugs in action.
+
diff -urN oldtree/fs/reiser4/as_ops.c newtree/fs/reiser4/as_ops.c
--- oldtree/fs/reiser4/as_ops.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/as_ops.c	2006-02-21 15:58:35.426760872 +0000
@@ -0,0 +1,414 @@
+/* Copyright 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Interface to VFS. Reiser4 address_space_operations are defined here. */
+
+#include "forward.h"
+#include "debug.h"
+#include "dformat.h"
+#include "coord.h"
+#include "plugin/item/item.h"
+#include "plugin/file/file.h"
+#include "plugin/security/perm.h"
+#include "plugin/disk_format/disk_format.h"
+#include "plugin/plugin.h"
+#include "plugin/plugin_set.h"
+#include "plugin/object.h"
+#include "txnmgr.h"
+#include "jnode.h"
+#include "znode.h"
+#include "block_alloc.h"
+#include "tree.h"
+#include "vfs_ops.h"
+#include "inode.h"
+#include "page_cache.h"
+#include "ktxnmgrd.h"
+#include "super.h"
+#include "reiser4.h"
+#include "entd.h"
+#include "emergency_flush.h"
+
+#include <linux/profile.h>
+#include <linux/types.h>
+#include <linux/mount.h>
+#include <linux/vfs.h>
+#include <linux/mm.h>
+#include <linux/buffer_head.h>
+#include <linux/dcache.h>
+#include <linux/list.h>
+#include <linux/pagemap.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/writeback.h>
+#include <linux/backing-dev.h>
+#include <linux/quotaops.h>
+#include <linux/security.h>
+
+/* address space operations */
+
+/**
+ * reiser4_set_page_dirty - set dirty bit, tag in page tree, dirty accounting
+ * @page: page to be dirtied
+ *
+ * Operation of struct address_space_operations. This implementation is used by
+ * unix and crc file plugins.
+ *
+ * This is called when reiser4 page gets dirtied outside of reiser4, for
+ * example, when dirty bit is moved from pte to physical page.
+ *
+ * Tags page in the mapping's page tree with special tag so that it is possible
+ * to do all the reiser4 specific work wrt dirty pages (jnode creation,
+ * capturing by an atom) later because it can not be done in the contexts where
+ * set_page_dirty is called.
+ */
+int reiser4_set_page_dirty(struct page *page)
+{
+	/* this page can be unformatted only */
+	assert("vs-1734", (page->mapping &&
+			   page->mapping->host &&
+			   get_super_fake(page->mapping->host->i_sb) !=
+			   page->mapping->host
+			   && get_cc_fake(page->mapping->host->i_sb) !=
+			   page->mapping->host
+			   && get_bitmap_fake(page->mapping->host->i_sb) !=
+			   page->mapping->host));
+
+	if (!TestSetPageDirty(page)) {
+		struct address_space *mapping = page->mapping;
+
+		if (mapping) {
+			write_lock_irq(&mapping->tree_lock);
+
+			/* check for race with truncate */
+			if (page->mapping) {
+				assert("vs-1652", page->mapping == mapping);
+				if (mapping_cap_account_dirty(mapping))
+					inc_page_state(nr_dirty);
+				radix_tree_tag_set(&mapping->page_tree,
+						   page->index,
+						   PAGECACHE_TAG_REISER4_MOVED);
+			}
+			write_unlock_irq(&mapping->tree_lock);
+			__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+		}
+	}
+	return 0;
+}
+
+static int filler(void *vp, struct page *page)
+{
+	return page->mapping->a_ops->readpage(vp, page);
+}
+
+/**
+ * reiser4_readpages - submit read for a set of pages
+ * @file: file to read
+ * @mapping: address space
+ * @pages: list of pages to submit read for
+ * @nr_pages: number of pages no the list
+ *
+ * Operation of struct address_space_operations. This implementation is used by
+ * unix and crc file plugins.
+ *
+ * Calls read_cache_pages or readpages hook if it is set.
+ */
+int
+reiser4_readpages(struct file *file, struct address_space *mapping,
+		  struct list_head *pages, unsigned nr_pages)
+{
+	reiser4_context *ctx;
+	reiser4_file_fsdata *fsdata;
+
+	ctx = init_context(mapping->host->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	fsdata = reiser4_get_file_fsdata(file);
+	if (IS_ERR(fsdata)) {
+		reiser4_exit_context(ctx);
+		return PTR_ERR(fsdata);
+	}
+
+	if (fsdata->ra2.readpages)
+		fsdata->ra2.readpages(mapping, pages, fsdata->ra2.data);
+	else {
+		/*
+		 * filler (reiser4 readpage method) may involve tree search
+		 * which is not allowed when lock stack is not clean. If lock
+		 * stack is not clean - do nothing.
+		 */
+		if (lock_stack_isclean(get_current_lock_stack()))
+			read_cache_pages(mapping, pages, filler, file);
+		else {
+			while (!list_empty(pages)) {
+				struct page *victim;
+
+				victim = list_entry(pages->prev, struct page, lru);
+				list_del(&victim->lru);
+				page_cache_release(victim);
+			}
+		}
+	}
+	reiser4_exit_context(ctx);
+	return 0;
+}
+
+/* ->invalidatepage method for reiser4 */
+
+/*
+ * this is called for each truncated page from
+ * truncate_inode_pages()->truncate_{complete,partial}_page().
+ *
+ * At the moment of call, page is under lock, and outstanding io (if any) has
+ * completed.
+ */
+
+/**
+ * reiser4_invalidatepage
+ * @page: page to invalidate
+ * @offset: starting offset for partial invalidation
+ *
+ */
+int reiser4_invalidatepage(struct page *page, unsigned long offset)
+{
+	int ret = 0;
+	reiser4_context *ctx;
+	struct inode *inode;
+	jnode *node;
+
+	/*
+	 * This is called to truncate file's page.
+	 *
+	 * Originally, reiser4 implemented truncate in a standard way
+	 * (vmtruncate() calls ->invalidatepage() on all truncated pages
+	 * first, then file system ->truncate() call-back is invoked).
+	 *
+	 * This lead to the problem when ->invalidatepage() was called on a
+	 * page with jnode that was captured into atom in ASTAGE_PRE_COMMIT
+	 * process. That is, truncate was bypassing transactions. To avoid
+	 * this, try_capture_page_to_invalidate() call was added here.
+	 *
+	 * After many troubles with vmtruncate() based truncate (including
+	 * races with flush, tail conversion, etc.) it was re-written in the
+	 * top-to-bottom style: items are killed in cut_tree_object() and
+	 * pages belonging to extent are invalidated in kill_hook_extent(). So
+	 * probably now additional call to capture is not needed here.
+	 */
+
+	assert("nikita-3137", PageLocked(page));
+	assert("nikita-3138", !PageWriteback(page));
+	inode = page->mapping->host;
+
+	/*
+	 * ->invalidatepage() should only be called for the unformatted
+	 * jnodes. Destruction of all other types of jnodes is performed
+	 * separately. But, during some corner cases (like handling errors
+	 * during mount) it is simpler to let ->invalidatepage to be called on
+	 * them. Check for this, and do nothing.
+	 */
+	if (get_super_fake(inode->i_sb) == inode)
+		return 0;
+	if (get_cc_fake(inode->i_sb) == inode)
+		return 0;
+	if (get_bitmap_fake(inode->i_sb) == inode)
+		return 0;
+	assert("vs-1426", PagePrivate(page));
+	assert("vs-1427",
+	       page->mapping == jnode_get_mapping(jnode_by_page(page)));
+	assert("", jprivate(page) != NULL);
+	assert("", ergo(inode_file_plugin(inode) !=
+			file_plugin_by_id(CRC_FILE_PLUGIN_ID), offset == 0));
+
+	ctx = init_context(inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	node = jprivate(page);
+	spin_lock_jnode(node);
+	if (!(node->state & ((1 << JNODE_DIRTY) | (1<< JNODE_FLUSH_QUEUED) |
+			  (1 << JNODE_WRITEBACK) | (1 << JNODE_OVRWR)))) {
+		/* there is not need to capture */
+		jref(node);
+		JF_SET(node, JNODE_HEARD_BANSHEE);
+		page_clear_jnode(page, node);
+		uncapture_jnode(node);
+		unhash_unformatted_jnode(node);
+		jput(node);
+		reiser4_exit_context(ctx);
+		return 0;
+	}
+	spin_unlock_jnode(node);
+
+	/* capture page being truncated. */
+	ret = try_capture_page_to_invalidate(page);
+	if (ret != 0)
+		warning("nikita-3141", "Cannot capture: %i", ret);
+
+	if (offset == 0) {
+		/* remove jnode from transaction and detach it from page. */
+		assert("vs-1435", !JF_ISSET(node, JNODE_CC));
+		jref(node);
+		JF_SET(node, JNODE_HEARD_BANSHEE);
+		/* page cannot be detached from jnode concurrently, because it
+		 * is locked */
+		uncapture_page(page);
+
+		/* this detaches page from jnode, so that jdelete will not try
+		 * to lock page which is already locked */
+		spin_lock_jnode(node);
+		page_clear_jnode(page, node);
+		spin_unlock_jnode(node);
+		unhash_unformatted_jnode(node);
+
+		jput(node);
+	}
+
+	reiser4_exit_context(ctx);
+	return ret;
+}
+
+/* help function called from reiser4_releasepage(). It returns true if jnode
+ * can be detached from its page and page released. */
+int jnode_is_releasable(jnode * node /* node to check */ )
+{
+	assert("nikita-2781", node != NULL);
+	assert_spin_locked(&(node->guard));
+	assert_spin_locked(&(node->load));
+
+	/* is some thread is currently using jnode page, later cannot be
+	 * detached */
+	if (atomic_read(&node->d_count) != 0) {
+		return 0;
+	}
+
+	assert("vs-1214", !jnode_is_loaded(node));
+
+	/* this jnode is just a copy. Its page cannot be released, because
+	 * otherwise next jload() would load obsolete data from disk
+	 * (up-to-date version may still be in memory). */
+	if (is_cced(node)) {
+		return 0;
+	}
+
+	/* emergency flushed page can be released. This is what emergency
+	 * flush is all about after all. */
+	if (JF_ISSET(node, JNODE_EFLUSH)) {
+		return 1;	/* yeah! */
+	}
+
+	/* can only release page if real block number is assigned to
+	   it. Simple check for ->atom wouldn't do, because it is possible for
+	   node to be clean, not it atom yet, and still having fake block
+	   number. For example, node just created in jinit_new(). */
+	if (blocknr_is_fake(jnode_get_block(node))) {
+		return 0;
+	}
+	/* dirty jnode cannot be released. It can however be submitted to disk
+	 * as part of early flushing, but only after getting flush-prepped. */
+	if (JF_ISSET(node, JNODE_DIRTY)) {
+		return 0;
+	}
+	/* overwrite set is only written by log writer. */
+	if (JF_ISSET(node, JNODE_OVRWR)) {
+		return 0;
+	}
+	/* jnode is already under writeback */
+	if (JF_ISSET(node, JNODE_WRITEBACK)) {
+		return 0;
+	}
+#if 0
+	/* page was modified through mmap, but its jnode is not yet
+	 * captured. Don't discard modified data. */
+	if (jnode_is_unformatted(node) && JF_ISSET(node, JNODE_KEEPME)) {
+		return 0;
+	}
+#endif
+	BUG_ON(JF_ISSET(node, JNODE_KEEPME));
+	/* don't flush bitmaps or journal records */
+	if (!jnode_is_znode(node) && !jnode_is_unformatted(node)) {
+		return 0;
+	}
+	return 1;
+}
+
+/*
+ * ->releasepage method for reiser4
+ *
+ * This is called by VM scanner when it comes across clean page.  What we have
+ * to do here is to check whether page can really be released (freed that is)
+ * and if so, detach jnode from it and remove page from the page cache.
+ *
+ * Check for releasability is done by releasable() function.
+ */
+int reiser4_releasepage(struct page *page, gfp_t gfp UNUSED_ARG)
+{
+	jnode *node;
+
+	assert("nikita-2257", PagePrivate(page));
+	assert("nikita-2259", PageLocked(page));
+	assert("nikita-2892", !PageWriteback(page));
+	assert("nikita-3019", schedulable());
+
+	/* NOTE-NIKITA: this can be called in the context of reiser4 call. It
+	   is not clear what to do in this case. A lot of deadlocks seems be
+	   possible. */
+
+	node = jnode_by_page(page);
+	assert("nikita-2258", node != NULL);
+	assert("reiser4-4", page->mapping != NULL);
+	assert("reiser4-5", page->mapping->host != NULL);
+
+	/* is_page_cache_freeable() check
+	   (mapping + private + page_cache_get() by shrink_cache()) */
+	if (page_count(page) > 3)
+		return 0;
+
+	if (PageDirty(page))
+		return 0;
+
+	/* releasable() needs jnode lock, because it looks at the jnode fields
+	 * and we need jload_lock here to avoid races with jload(). */
+	spin_lock_jnode(node);
+	spin_lock(&(node->load));
+	if (jnode_is_releasable(node)) {
+		struct address_space *mapping;
+
+		mapping = page->mapping;
+		jref(node);
+		/* there is no need to synchronize against
+		 * jnode_extent_write() here, because pages seen by
+		 * jnode_extent_write() are !releasable(). */
+		page_clear_jnode(page, node);
+		spin_unlock(&(node->load));
+		spin_unlock_jnode(node);
+
+		/* we are under memory pressure so release jnode also. */
+		jput(node);
+
+		write_lock_irq(&mapping->tree_lock);
+		/* shrink_list() + radix-tree */
+		if (page_count(page) == 2) {
+			__remove_from_page_cache(page);
+			atomic_dec(&page->_count);
+		}
+		write_unlock_irq(&mapping->tree_lock);
+
+		return 1;
+	} else {
+		spin_unlock(&(node->load));
+		spin_unlock_jnode(node);
+		assert("nikita-3020", schedulable());
+		return 0;
+	}
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/block_alloc.c newtree/fs/reiser4/block_alloc.c
--- oldtree/fs/reiser4/block_alloc.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/block_alloc.c	2006-02-21 15:58:34.960831704 +0000
@@ -0,0 +1,1111 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#include "debug.h"
+#include "dformat.h"
+#include "plugin/plugin.h"
+#include "txnmgr.h"
+#include "znode.h"
+#include "block_alloc.h"
+#include "tree.h"
+#include "super.h"
+
+#include <linux/types.h>	/* for __u??  */
+#include <linux/fs.h>		/* for struct super_block  */
+#include <linux/spinlock.h>
+
+/* THE REISER4 DISK SPACE RESERVATION SCHEME. */
+
+/* We need to be able to reserve enough disk space to ensure that an atomic
+   operation will have enough disk space to flush (see flush.c and
+   http://namesys.com/v4/v4.html) and commit it once it is started.
+
+   In our design a call for reserving disk space may fail but not an actual
+   block allocation.
+
+   All free blocks, already allocated blocks, and all kinds of reserved blocks
+   are counted in different per-fs block counters.
+
+   A reiser4 super block's set of block counters currently is:
+
+   free -- free blocks,
+   used -- already allocated blocks,
+
+   grabbed -- initially reserved for performing an fs operation, those blocks
+          are taken from free blocks, then grabbed disk space leaks from grabbed
+          blocks counter to other counters like "fake allocated", "flush
+          reserved", "used", the rest of not used grabbed space is returned to
+          free space at the end of fs operation;
+
+   fake allocated -- counts all nodes without real disk block numbers assigned,
+                     we have separate accounting for formatted and unformatted
+                     nodes (for easier debugging);
+
+   flush reserved -- disk space needed for flushing and committing an atom.
+                     Each dirty already allocated block could be written as a
+                     part of atom's overwrite set or as a part of atom's
+                     relocate set.  In both case one additional block is needed,
+                     it is used as a wandered block if we do overwrite or as a
+		     new location for a relocated block.
+
+   In addition, blocks in some states are counted on per-thread and per-atom
+   basis.  A reiser4 context has a counter of blocks grabbed by this transaction
+   and the sb's grabbed blocks counter is a sum of grabbed blocks counter values
+   of each reiser4 context.  Each reiser4 atom has a counter of "flush reserved"
+   blocks, which are reserved for flush processing and atom commit. */
+
+/* AN EXAMPLE: suppose we insert new item to the reiser4 tree.  We estimate
+   number of blocks to grab for most expensive case of balancing when the leaf
+   node we insert new item to gets split and new leaf node is allocated.
+
+   So, we need to grab blocks for
+
+   1) one block for possible dirtying the node we insert an item to. That block
+      would be used for node relocation at flush time or for allocating of a
+      wandered one, it depends what will be a result (what set, relocate or
+      overwrite the node gets assigned to) of the node processing by the flush
+      algorithm.
+
+   2) one block for either allocating a new node, or dirtying of right or left
+      clean neighbor, only one case may happen.
+
+   VS-FIXME-HANS: why can only one case happen? I would expect to see dirtying of left neighbor, right neighbor, current
+   node, and creation of new node.  have I forgotten something?  email me.
+
+   These grabbed blocks are counted in both reiser4 context "grabbed blocks"
+   counter and in the fs-wide one (both ctx->grabbed_blocks and
+   sbinfo->blocks_grabbed get incremented by 2), sb's free blocks counter is
+   decremented by 2.
+
+   Suppose both two blocks were spent for dirtying of an already allocated clean
+   node (one block went from "grabbed" to "flush reserved") and for new block
+   allocating (one block went from "grabbed" to "fake allocated formatted").
+
+   Inserting of a child pointer to the parent node caused parent node to be
+   split, the balancing code takes care about this grabbing necessary space
+   immediately by calling reiser4_grab with BA_RESERVED flag set which means
+   "can use the 5% reserved disk space".
+
+   At this moment insertion completes and grabbed blocks (if they were not used)
+   should be returned to the free space counter.
+
+   However the atom life-cycle is not completed.  The atom had one "flush
+   reserved" block added by our insertion and the new fake allocated node is
+   counted as a "fake allocated formatted" one.  The atom has to be fully
+   processed by flush before commit.  Suppose that the flush moved the first,
+   already allocated node to the atom's overwrite list, the new fake allocated
+   node, obviously, went into the atom relocate set.  The reiser4 flush
+   allocates the new node using one unit from "fake allocated formatted"
+   counter, the log writer uses one from "flush reserved" for wandered block
+   allocation.
+
+   And, it is not the end.  When the wandered block is deallocated after the
+   atom gets fully played (see wander.c for term description), the disk space
+   occupied for it is returned to free blocks. */
+
+/* BLOCK NUMBERS */
+
+/* Any reiser4 node has a block number assigned to it.  We use these numbers for
+   indexing in hash tables, so if a block has not yet been assigned a location
+   on disk we need to give it a temporary fake block number.
+
+   Current implementation of reiser4 uses 64-bit integers for block numbers. We
+   use highest bit in 64-bit block number to distinguish fake and real block
+   numbers. So, only 63 bits may be used to addressing of real device
+   blocks. That "fake" block numbers space is divided into subspaces of fake
+   block numbers for data blocks and for shadow (working) bitmap blocks.
+
+   Fake block numbers for data blocks are generated by a cyclic counter, which
+   gets incremented after each real block allocation. We assume that it is
+   impossible to overload this counter during one transaction life. */
+
+/* Initialize a blocknr hint. */
+void blocknr_hint_init(reiser4_blocknr_hint * hint)
+{
+	memset(hint, 0, sizeof(reiser4_blocknr_hint));
+}
+
+/* Release any resources of a blocknr hint. */
+void blocknr_hint_done(reiser4_blocknr_hint * hint UNUSED_ARG)
+{
+	/* No resources should be freed in current blocknr_hint implementation. */
+}
+
+/* see above for explanation of fake block number.  */
+/* Audited by: green(2002.06.11) */
+int blocknr_is_fake(const reiser4_block_nr * da)
+{
+	/* The reason for not simply returning result of '&' operation is that
+	   while return value is (possibly 32bit) int,  the reiser4_block_nr is
+	   at least 64 bits long, and high bit (which is the only possible
+	   non zero bit after the masking) would be stripped off */
+	return (*da & REISER4_FAKE_BLOCKNR_BIT_MASK) ? 1 : 0;
+}
+
+/* Static functions for <reiser4 super block>/<reiser4 context> block counters
+   arithmetic. Mostly, they are isolated to not to code same assertions in
+   several places. */
+static void sub_from_ctx_grabbed(reiser4_context * ctx, __u64 count)
+{
+	BUG_ON(ctx->grabbed_blocks < count);
+	assert("zam-527", ctx->grabbed_blocks >= count);
+	ctx->grabbed_blocks -= count;
+}
+
+static void add_to_ctx_grabbed(reiser4_context * ctx, __u64 count)
+{
+	ctx->grabbed_blocks += count;
+}
+
+static void sub_from_sb_grabbed(reiser4_super_info_data * sbinfo, __u64 count)
+{
+	assert("zam-525", sbinfo->blocks_grabbed >= count);
+	sbinfo->blocks_grabbed -= count;
+}
+
+/* Decrease the counter of block reserved for flush in super block. */
+static void
+sub_from_sb_flush_reserved(reiser4_super_info_data * sbinfo, __u64 count)
+{
+	assert("vpf-291", sbinfo->blocks_flush_reserved >= count);
+	sbinfo->blocks_flush_reserved -= count;
+}
+
+static void
+sub_from_sb_fake_allocated(reiser4_super_info_data * sbinfo, __u64 count,
+			   reiser4_ba_flags_t flags)
+{
+	if (flags & BA_FORMATTED) {
+		assert("zam-806", sbinfo->blocks_fake_allocated >= count);
+		sbinfo->blocks_fake_allocated -= count;
+	} else {
+		assert("zam-528",
+		       sbinfo->blocks_fake_allocated_unformatted >= count);
+		sbinfo->blocks_fake_allocated_unformatted -= count;
+	}
+}
+
+static void sub_from_sb_used(reiser4_super_info_data * sbinfo, __u64 count)
+{
+	assert("zam-530",
+	       sbinfo->blocks_used >= count + sbinfo->min_blocks_used);
+	sbinfo->blocks_used -= count;
+}
+
+static void
+sub_from_cluster_reserved(reiser4_super_info_data * sbinfo, __u64 count)
+{
+	assert("edward-501", sbinfo->blocks_clustered >= count);
+	sbinfo->blocks_clustered -= count;
+}
+
+/* Increase the counter of block reserved for flush in atom. */
+static void add_to_atom_flush_reserved_nolock(txn_atom * atom, __u32 count)
+{
+	assert("zam-772", atom != NULL);
+	assert_spin_locked(&(atom->alock));
+	atom->flush_reserved += count;
+}
+
+/* Decrease the counter of block reserved for flush in atom. */
+static void sub_from_atom_flush_reserved_nolock(txn_atom * atom, __u32 count)
+{
+	assert("zam-774", atom != NULL);
+	assert_spin_locked(&(atom->alock));
+	assert("nikita-2790", atom->flush_reserved >= count);
+	atom->flush_reserved -= count;
+}
+
+/* super block has 6 counters: free, used, grabbed, fake allocated
+   (formatted and unformatted) and flush reserved. Their sum must be
+   number of blocks on a device. This function checks this */
+int check_block_counters(const struct super_block *super)
+{
+	__u64 sum;
+
+	sum = reiser4_grabbed_blocks(super) + reiser4_free_blocks(super) +
+	    reiser4_data_blocks(super) + reiser4_fake_allocated(super) +
+	    reiser4_fake_allocated_unformatted(super) + flush_reserved(super) +
+	    reiser4_clustered_blocks(super);
+	if (reiser4_block_count(super) != sum) {
+		printk("super block counters: "
+		       "used %llu, free %llu, "
+		       "grabbed %llu, fake allocated (formatetd %llu, unformatted %llu), "
+		       "reserved %llu, clustered %llu, sum %llu, must be (block count) %llu\n",
+		       (unsigned long long)reiser4_data_blocks(super),
+		       (unsigned long long)reiser4_free_blocks(super),
+		       (unsigned long long)reiser4_grabbed_blocks(super),
+		       (unsigned long long)reiser4_fake_allocated(super),
+		       (unsigned long long)
+		       reiser4_fake_allocated_unformatted(super),
+		       (unsigned long long)flush_reserved(super),
+		       (unsigned long long)reiser4_clustered_blocks(super),
+		       (unsigned long long)sum,
+		       (unsigned long long)reiser4_block_count(super));
+		return 0;
+	}
+	return 1;
+}
+
+/* Adjust "working" free blocks counter for number of blocks we are going to
+   allocate.  Record number of grabbed blocks in fs-wide and per-thread
+   counters.  This function should be called before bitmap scanning or
+   allocating fake block numbers
+
+   @super           -- pointer to reiser4 super block;
+   @count           -- number of blocks we reserve;
+
+   @return          -- 0 if success,  -ENOSPC, if all
+                       free blocks are preserved or already allocated.
+*/
+
+static int
+reiser4_grab(reiser4_context * ctx, __u64 count, reiser4_ba_flags_t flags)
+{
+	__u64 free_blocks;
+	int ret = 0, use_reserved = flags & BA_RESERVED;
+	reiser4_super_info_data *sbinfo;
+
+	assert("vs-1276", ctx == get_current_context());
+
+	/* Do not grab anything on ro-mounted fs. */
+	if (rofs_super(ctx->super)) {
+		ctx->grab_enabled = 0;
+		return 0;
+	}
+
+	sbinfo = get_super_private(ctx->super);
+
+	spin_lock_reiser4_super(sbinfo);
+
+	free_blocks = sbinfo->blocks_free;
+
+	if ((use_reserved && free_blocks < count) ||
+	    (!use_reserved && free_blocks < count + sbinfo->blocks_reserved)) {
+		ret = RETERR(-ENOSPC);
+		goto unlock_and_ret;
+	}
+
+	add_to_ctx_grabbed(ctx, count);
+
+	sbinfo->blocks_grabbed += count;
+	sbinfo->blocks_free -= count;
+
+#if REISER4_DEBUG
+	ctx->grabbed_initially = count;
+#endif
+
+	assert("nikita-2986", check_block_counters(ctx->super));
+
+	/* disable grab space in current context */
+	ctx->grab_enabled = 0;
+
+      unlock_and_ret:
+	spin_unlock_reiser4_super(sbinfo);
+
+	return ret;
+}
+
+int reiser4_grab_space(__u64 count, reiser4_ba_flags_t flags)
+{
+	int ret;
+	reiser4_context *ctx;
+
+	assert("nikita-2964", ergo(flags & BA_CAN_COMMIT,
+				   lock_stack_isclean(get_current_lock_stack
+						      ())));
+	ctx = get_current_context();
+	if (!(flags & BA_FORCE) && !is_grab_enabled(ctx)) {
+		return 0;
+	}
+
+	ret = reiser4_grab(ctx, count, flags);
+	if (ret == -ENOSPC) {
+
+		/* Trying to commit the all transactions if BA_CAN_COMMIT flag present */
+		if (flags & BA_CAN_COMMIT) {
+			txnmgr_force_commit_all(ctx->super, 0);
+			ctx->grab_enabled = 1;
+			ret = reiser4_grab(ctx, count, flags);
+		}
+	}
+	/*
+	 * allocation from reserved pool cannot fail. This is severe error.
+	 */
+	assert("nikita-3005", ergo(flags & BA_RESERVED, ret == 0));
+	return ret;
+}
+
+/*
+ * SPACE RESERVED FOR UNLINK/TRUNCATE
+ *
+ * Unlink and truncate require space in transaction (to update stat data, at
+ * least). But we don't want rm(1) to fail with "No space on device" error.
+ *
+ * Solution is to reserve 5% of disk space for truncates and
+ * unlinks. Specifically, normal space grabbing requests don't grab space from
+ * reserved area. Only requests with BA_RESERVED bit in flags are allowed to
+ * drain it. Per super block delete_sema semaphore is used to allow only one
+ * thread at a time to grab from reserved area.
+ *
+ * Grabbing from reserved area should always be performed with BA_CAN_COMMIT
+ * flag.
+ *
+ */
+
+int reiser4_grab_reserved(struct super_block *super,
+			  __u64 count, reiser4_ba_flags_t flags)
+{
+	reiser4_super_info_data *sbinfo = get_super_private(super);
+
+	assert("nikita-3175", flags & BA_CAN_COMMIT);
+
+	/* Check the delete semaphore already taken by us, we assume that
+	 * reading of machine word is atomic. */
+	if (sbinfo->delete_sema_owner == current) {
+		if (reiser4_grab_space
+		    (count, (flags | BA_RESERVED) & ~BA_CAN_COMMIT)) {
+			warning("zam-1003",
+				"nested call of grab_reserved fails count=(%llu)",
+				(unsigned long long)count);
+			reiser4_release_reserved(super);
+			return RETERR(-ENOSPC);
+		}
+		return 0;
+	}
+
+	if (reiser4_grab_space(count, flags)) {
+		down(&sbinfo->delete_sema);
+		assert("nikita-2929", sbinfo->delete_sema_owner == NULL);
+		sbinfo->delete_sema_owner = current;
+
+		if (reiser4_grab_space(count, flags | BA_RESERVED)) {
+			warning("zam-833",
+				"reserved space is not enough (%llu)",
+				(unsigned long long)count);
+			reiser4_release_reserved(super);
+			return RETERR(-ENOSPC);
+		}
+	}
+	return 0;
+}
+
+void reiser4_release_reserved(struct super_block *super)
+{
+	reiser4_super_info_data *info;
+
+	info = get_super_private(super);
+	if (info->delete_sema_owner == current) {
+		info->delete_sema_owner = NULL;
+		up(&info->delete_sema);
+	}
+}
+
+static reiser4_super_info_data *grabbed2fake_allocated_head(void)
+{
+	reiser4_context *ctx;
+	reiser4_super_info_data *sbinfo;
+
+	ctx = get_current_context();
+	sub_from_ctx_grabbed(ctx, 1);
+
+	sbinfo = get_super_private(ctx->super);
+	spin_lock_reiser4_super(sbinfo);
+
+	sub_from_sb_grabbed(sbinfo, 1);
+	/* return sbinfo locked */
+	return sbinfo;
+}
+
+/* is called after @count fake block numbers are allocated and pointer to
+   those blocks are inserted into tree. */
+static void grabbed2fake_allocated_formatted(void)
+{
+	reiser4_super_info_data *sbinfo;
+
+	sbinfo = grabbed2fake_allocated_head();
+	sbinfo->blocks_fake_allocated++;
+
+	assert("vs-922", check_block_counters(reiser4_get_current_sb()));
+
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+static void grabbed2fake_allocated_unformatted(void)
+{
+	reiser4_super_info_data *sbinfo;
+
+	sbinfo = grabbed2fake_allocated_head();
+	sbinfo->blocks_fake_allocated_unformatted++;
+
+	assert("vs-9221", check_block_counters(reiser4_get_current_sb()));
+
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+void grabbed2cluster_reserved(int count)
+{
+	reiser4_context *ctx;
+	reiser4_super_info_data *sbinfo;
+
+	ctx = get_current_context();
+	sub_from_ctx_grabbed(ctx, count);
+
+	sbinfo = get_super_private(ctx->super);
+	spin_lock_reiser4_super(sbinfo);
+
+	sub_from_sb_grabbed(sbinfo, count);
+	sbinfo->blocks_clustered += count;
+
+	assert("edward-504", check_block_counters(ctx->super));
+
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+void cluster_reserved2grabbed(int count)
+{
+	reiser4_context *ctx;
+	reiser4_super_info_data *sbinfo;
+
+	ctx = get_current_context();
+
+	sbinfo = get_super_private(ctx->super);
+	spin_lock_reiser4_super(sbinfo);
+
+	sub_from_cluster_reserved(sbinfo, count);
+	sbinfo->blocks_grabbed += count;
+
+	assert("edward-505", check_block_counters(ctx->super));
+
+	spin_unlock_reiser4_super(sbinfo);
+	add_to_ctx_grabbed(ctx, count);
+}
+
+void cluster_reserved2free(int count)
+{
+	reiser4_context *ctx;
+	reiser4_super_info_data *sbinfo;
+
+	assert("edward-503", get_current_context()->grabbed_blocks == 0);
+
+	ctx = get_current_context();
+	sbinfo = get_super_private(ctx->super);
+	spin_lock_reiser4_super(sbinfo);
+
+	sub_from_cluster_reserved(sbinfo, count);
+	sbinfo->blocks_free += count;
+
+	assert("edward-502", check_block_counters(ctx->super));
+
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+static spinlock_t fake_lock = SPIN_LOCK_UNLOCKED;
+static reiser4_block_nr fake_gen = 0;
+
+/* obtain a block number for new formatted node which will be used to refer
+   to this newly allocated node until real allocation is done */
+static inline void assign_fake_blocknr(reiser4_block_nr * blocknr)
+{
+	spin_lock(&fake_lock);
+	*blocknr = fake_gen++;
+	spin_unlock(&fake_lock);
+
+	*blocknr &= ~REISER4_BLOCKNR_STATUS_BIT_MASK;
+	*blocknr |= REISER4_UNALLOCATED_STATUS_VALUE;
+	assert("zam-394", zlook(current_tree, blocknr) == NULL);
+}
+
+int assign_fake_blocknr_formatted(reiser4_block_nr * blocknr)
+{
+	assign_fake_blocknr(blocknr);
+	grabbed2fake_allocated_formatted();
+
+	return 0;
+}
+
+/* return fake blocknr which will be used for unformatted nodes */
+reiser4_block_nr fake_blocknr_unformatted(void)
+{
+	reiser4_block_nr blocknr;
+
+	assign_fake_blocknr(&blocknr);
+	grabbed2fake_allocated_unformatted();
+
+	inc_unalloc_unfm_ptr();
+	return blocknr;
+}
+
+/* adjust sb block counters, if real (on-disk) block allocation immediately
+   follows grabbing of free disk space. */
+static void
+grabbed2used(reiser4_context * ctx, reiser4_super_info_data * sbinfo,
+	     __u64 count)
+{
+	sub_from_ctx_grabbed(ctx, count);
+
+	spin_lock_reiser4_super(sbinfo);
+
+	sub_from_sb_grabbed(sbinfo, count);
+	sbinfo->blocks_used += count;
+
+	assert("nikita-2679", check_block_counters(ctx->super));
+
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+/* adjust sb block counters when @count unallocated blocks get mapped to disk */
+static void
+fake_allocated2used(reiser4_super_info_data * sbinfo, __u64 count,
+		    reiser4_ba_flags_t flags)
+{
+	spin_lock_reiser4_super(sbinfo);
+
+	sub_from_sb_fake_allocated(sbinfo, count, flags);
+	sbinfo->blocks_used += count;
+
+	assert("nikita-2680", check_block_counters(reiser4_get_current_sb()));
+
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+static void flush_reserved2used(txn_atom * atom, __u64 count)
+{
+	reiser4_super_info_data *sbinfo;
+
+	assert("zam-787", atom != NULL);
+	assert_spin_locked(&(atom->alock));
+
+	sub_from_atom_flush_reserved_nolock(atom, (__u32) count);
+
+	sbinfo = get_current_super_private();
+	spin_lock_reiser4_super(sbinfo);
+
+	sub_from_sb_flush_reserved(sbinfo, count);
+	sbinfo->blocks_used += count;
+
+	assert("zam-789", check_block_counters(reiser4_get_current_sb()));
+
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+/* update the per fs  blocknr hint default value. */
+void
+update_blocknr_hint_default(const struct super_block *s,
+			    const reiser4_block_nr * block)
+{
+	reiser4_super_info_data *sbinfo = get_super_private(s);
+
+	assert("nikita-3342", !blocknr_is_fake(block));
+
+	spin_lock_reiser4_super(sbinfo);
+	if (*block < sbinfo->block_count) {
+		sbinfo->blocknr_hint_default = *block;
+	} else {
+		warning("zam-676",
+			"block number %llu is too large to be used in a blocknr hint\n",
+			(unsigned long long)*block);
+		dump_stack();
+		DEBUGON(1);
+	}
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+/* get current value of the default blocknr hint. */
+void get_blocknr_hint_default(reiser4_block_nr * result)
+{
+	reiser4_super_info_data *sbinfo = get_current_super_private();
+
+	spin_lock_reiser4_super(sbinfo);
+	*result = sbinfo->blocknr_hint_default;
+	assert("zam-677", *result < sbinfo->block_count);
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+/* Allocate "real" disk blocks by calling a proper space allocation plugin
+ * method. Blocks are allocated in one contiguous disk region. The plugin
+ * independent part accounts blocks by subtracting allocated amount from grabbed
+ * or fake block counter and add the same amount to the counter of allocated
+ * blocks.
+ *
+ * @hint -- a reiser4 blocknr hint object which contains further block
+ *          allocation hints and parameters (search start, a stage of block
+ *          which will be mapped to disk, etc.),
+ * @blk  -- an out parameter for the beginning of the allocated region,
+ * @len  -- in/out parameter, it should contain the maximum number of allocated
+ *          blocks, after block allocation completes, it contains the length of
+ *          allocated disk region.
+ * @flags -- see reiser4_ba_flags_t description.
+ *
+ * @return -- 0 if success, error code otherwise.
+ */
+int
+reiser4_alloc_blocks(reiser4_blocknr_hint * hint, reiser4_block_nr * blk,
+		     reiser4_block_nr * len, reiser4_ba_flags_t flags)
+{
+	__u64 needed = *len;
+	reiser4_context *ctx;
+	reiser4_super_info_data *sbinfo;
+	int ret;
+
+	assert("zam-986", hint != NULL);
+
+	ctx = get_current_context();
+	sbinfo = get_super_private(ctx->super);
+
+	/* For write-optimized data we use default search start value, which is
+	 * close to last write location. */
+	if (flags & BA_USE_DEFAULT_SEARCH_START) {
+		get_blocknr_hint_default(&hint->blk);
+	}
+
+	/* VITALY: allocator should grab this for internal/tx-lists/similar only. */
+/* VS-FIXME-HANS: why is this comment above addressed to vitaly (from vitaly)? */
+	if (hint->block_stage == BLOCK_NOT_COUNTED) {
+		ret = reiser4_grab_space_force(*len, flags);
+		if (ret != 0)
+			return ret;
+	}
+
+	ret =
+	    sa_alloc_blocks(get_space_allocator(ctx->super), hint, (int)needed,
+			    blk, len);
+
+	if (!ret) {
+		assert("zam-680", *blk < reiser4_block_count(ctx->super));
+		assert("zam-681",
+		       *blk + *len <= reiser4_block_count(ctx->super));
+
+		if (flags & BA_PERMANENT) {
+			/* we assume that current atom exists at this moment */
+			txn_atom *atom = get_current_atom_locked();
+			atom->nr_blocks_allocated += *len;
+			spin_unlock_atom(atom);
+		}
+
+		switch (hint->block_stage) {
+		case BLOCK_NOT_COUNTED:
+		case BLOCK_GRABBED:
+			grabbed2used(ctx, sbinfo, *len);
+			break;
+		case BLOCK_UNALLOCATED:
+			fake_allocated2used(sbinfo, *len, flags);
+			break;
+		case BLOCK_FLUSH_RESERVED:
+			{
+				txn_atom *atom = get_current_atom_locked();
+				flush_reserved2used(atom, *len);
+				spin_unlock_atom(atom);
+			}
+			break;
+		default:
+			impossible("zam-531", "wrong block stage");
+		}
+	} else {
+		assert("zam-821",
+		       ergo(hint->max_dist == 0
+			    && !hint->backward, ret != -ENOSPC));
+		if (hint->block_stage == BLOCK_NOT_COUNTED)
+			grabbed2free(ctx, sbinfo, needed);
+	}
+
+	return ret;
+}
+
+/* used -> fake_allocated -> grabbed -> free */
+
+/* adjust sb block counters when @count unallocated blocks get unmapped from
+   disk */
+static void
+used2fake_allocated(reiser4_super_info_data * sbinfo, __u64 count,
+		    int formatted)
+{
+	spin_lock_reiser4_super(sbinfo);
+
+	if (formatted)
+		sbinfo->blocks_fake_allocated += count;
+	else
+		sbinfo->blocks_fake_allocated_unformatted += count;
+
+	sub_from_sb_used(sbinfo, count);
+
+	assert("nikita-2681", check_block_counters(reiser4_get_current_sb()));
+
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+static void
+used2flush_reserved(reiser4_super_info_data * sbinfo, txn_atom * atom,
+		    __u64 count, reiser4_ba_flags_t flags UNUSED_ARG)
+{
+	assert("nikita-2791", atom != NULL);
+	assert_spin_locked(&(atom->alock));
+
+	add_to_atom_flush_reserved_nolock(atom, (__u32) count);
+
+	spin_lock_reiser4_super(sbinfo);
+
+	sbinfo->blocks_flush_reserved += count;
+	/*add_to_sb_flush_reserved(sbinfo, count); */
+	sub_from_sb_used(sbinfo, count);
+
+	assert("nikita-2681", check_block_counters(reiser4_get_current_sb()));
+
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+/* disk space, virtually used by fake block numbers is counted as "grabbed" again. */
+static void
+fake_allocated2grabbed(reiser4_context * ctx, reiser4_super_info_data * sbinfo,
+		       __u64 count, reiser4_ba_flags_t flags)
+{
+	add_to_ctx_grabbed(ctx, count);
+
+	spin_lock_reiser4_super(sbinfo);
+
+	assert("nikita-2682", check_block_counters(ctx->super));
+
+	sbinfo->blocks_grabbed += count;
+	sub_from_sb_fake_allocated(sbinfo, count, flags & BA_FORMATTED);
+
+	assert("nikita-2683", check_block_counters(ctx->super));
+
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+void fake_allocated2free(__u64 count, reiser4_ba_flags_t flags)
+{
+	reiser4_context *ctx;
+	reiser4_super_info_data *sbinfo;
+
+	ctx = get_current_context();
+	sbinfo = get_super_private(ctx->super);
+
+	fake_allocated2grabbed(ctx, sbinfo, count, flags);
+	grabbed2free(ctx, sbinfo, count);
+}
+
+void grabbed2free_mark(__u64 mark)
+{
+	reiser4_context *ctx;
+	reiser4_super_info_data *sbinfo;
+
+	ctx = get_current_context();
+	sbinfo = get_super_private(ctx->super);
+
+	assert("nikita-3007", (__s64) mark >= 0);
+	assert("nikita-3006", ctx->grabbed_blocks >= mark);
+	grabbed2free(ctx, sbinfo, ctx->grabbed_blocks - mark);
+}
+
+/* Adjust free blocks count for blocks which were reserved but were not used. */
+void
+grabbed2free(reiser4_context * ctx, reiser4_super_info_data * sbinfo,
+	     __u64 count)
+{
+	sub_from_ctx_grabbed(ctx, count);
+
+	spin_lock_reiser4_super(sbinfo);
+
+	sub_from_sb_grabbed(sbinfo, count);
+	sbinfo->blocks_free += count;
+	assert("nikita-2684", check_block_counters(ctx->super));
+
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+void grabbed2flush_reserved_nolock(txn_atom * atom, __u64 count)
+{
+	reiser4_context *ctx;
+	reiser4_super_info_data *sbinfo;
+
+	assert("vs-1095", atom);
+
+	ctx = get_current_context();
+	sbinfo = get_super_private(ctx->super);
+
+	sub_from_ctx_grabbed(ctx, count);
+
+	add_to_atom_flush_reserved_nolock(atom, count);
+
+	spin_lock_reiser4_super(sbinfo);
+
+	sbinfo->blocks_flush_reserved += count;
+	sub_from_sb_grabbed(sbinfo, count);
+
+	assert("vpf-292", check_block_counters(ctx->super));
+
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+void grabbed2flush_reserved(__u64 count)
+{
+	txn_atom *atom = get_current_atom_locked();
+
+	grabbed2flush_reserved_nolock(atom, count);
+
+	spin_unlock_atom(atom);
+}
+
+void flush_reserved2grabbed(txn_atom * atom, __u64 count)
+{
+	reiser4_context *ctx;
+	reiser4_super_info_data *sbinfo;
+
+	assert("nikita-2788", atom != NULL);
+	assert_spin_locked(&(atom->alock));
+
+	ctx = get_current_context();
+	sbinfo = get_super_private(ctx->super);
+
+	add_to_ctx_grabbed(ctx, count);
+
+	sub_from_atom_flush_reserved_nolock(atom, (__u32) count);
+
+	spin_lock_reiser4_super(sbinfo);
+
+	sbinfo->blocks_grabbed += count;
+	sub_from_sb_flush_reserved(sbinfo, count);
+
+	assert("vpf-292", check_block_counters(ctx->super));
+
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+/* release all blocks grabbed in context which where not used. */
+void all_grabbed2free(void)
+{
+	reiser4_context *ctx = get_current_context();
+
+	grabbed2free(ctx, get_super_private(ctx->super), ctx->grabbed_blocks);
+}
+
+/* adjust sb block counters if real (on-disk) blocks do not become unallocated
+   after freeing, @count blocks become "grabbed". */
+static void
+used2grabbed(reiser4_context * ctx, reiser4_super_info_data * sbinfo,
+	     __u64 count)
+{
+	add_to_ctx_grabbed(ctx, count);
+
+	spin_lock_reiser4_super(sbinfo);
+
+	sbinfo->blocks_grabbed += count;
+	sub_from_sb_used(sbinfo, count);
+
+	assert("nikita-2685", check_block_counters(ctx->super));
+
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+/* this used to be done through used2grabbed and grabbed2free*/
+static void used2free(reiser4_super_info_data * sbinfo, __u64 count)
+{
+	spin_lock_reiser4_super(sbinfo);
+
+	sbinfo->blocks_free += count;
+	sub_from_sb_used(sbinfo, count);
+
+	assert("nikita-2685", check_block_counters(reiser4_get_current_sb()));
+
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+#if REISER4_DEBUG
+
+/* check "allocated" state of given block range */
+static void
+reiser4_check_blocks(const reiser4_block_nr * start,
+		     const reiser4_block_nr * len, int desired)
+{
+	sa_check_blocks(start, len, desired);
+}
+
+/* check "allocated" state of given block */
+void reiser4_check_block(const reiser4_block_nr * block, int desired)
+{
+	const reiser4_block_nr one = 1;
+
+	reiser4_check_blocks(block, &one, desired);
+}
+
+#endif
+
+/* Blocks deallocation function may do an actual deallocation through space
+   plugin allocation or store deleted block numbers in atom's delete_set data
+   structure depend on @defer parameter. */
+
+/* if BA_DEFER bit is not turned on, @target_stage means the stage of blocks which
+   will be deleted from WORKING bitmap. They might be just unmapped from disk, or
+   freed but disk space is still grabbed by current thread, or these blocks must
+   not be counted in any reiser4 sb block counters, see block_stage_t comment */
+
+/* BA_FORMATTED bit is only used when BA_DEFER in not present: it is used to
+   distinguish blocks allocated for unformatted and formatted nodes */
+
+int
+reiser4_dealloc_blocks(const reiser4_block_nr * start,
+		       const reiser4_block_nr * len,
+		       block_stage_t target_stage, reiser4_ba_flags_t flags)
+{
+	txn_atom *atom = NULL;
+	int ret;
+	reiser4_context *ctx;
+	reiser4_super_info_data *sbinfo;
+
+	ctx = get_current_context();
+	sbinfo = get_super_private(ctx->super);
+
+	if (REISER4_DEBUG) {
+		assert("zam-431", *len != 0);
+		assert("zam-432", *start != 0);
+		assert("zam-558", !blocknr_is_fake(start));
+
+		spin_lock_reiser4_super(sbinfo);
+		assert("zam-562", *start < sbinfo->block_count);
+		spin_unlock_reiser4_super(sbinfo);
+	}
+
+	if (flags & BA_DEFER) {
+		blocknr_set_entry *bsep = NULL;
+
+		/* storing deleted block numbers in a blocknr set
+		   datastructure for further actual deletion */
+		do {
+			atom = get_current_atom_locked();
+			assert("zam-430", atom != NULL);
+
+			ret =
+			    blocknr_set_add_extent(atom, &atom->delete_set,
+						   &bsep, start, len);
+
+			if (ret == -ENOMEM)
+				return ret;
+
+			/* This loop might spin at most two times */
+		} while (ret == -E_REPEAT);
+
+		assert("zam-477", ret == 0);
+		assert("zam-433", atom != NULL);
+
+		spin_unlock_atom(atom);
+
+	} else {
+		assert("zam-425", get_current_super_private() != NULL);
+		sa_dealloc_blocks(get_space_allocator(ctx->super), *start,
+				  *len);
+
+		if (flags & BA_PERMANENT) {
+			/* These blocks were counted as allocated, we have to revert it
+			 * back if allocation is discarded. */
+			txn_atom *atom = get_current_atom_locked();
+			atom->nr_blocks_allocated -= *len;
+			spin_unlock_atom(atom);
+		}
+
+		switch (target_stage) {
+		case BLOCK_NOT_COUNTED:
+			assert("vs-960", flags & BA_FORMATTED);
+			/* VITALY: This is what was grabbed for internal/tx-lists/similar only */
+			used2free(sbinfo, *len);
+			break;
+
+		case BLOCK_GRABBED:
+			used2grabbed(ctx, sbinfo, *len);
+			break;
+
+		case BLOCK_UNALLOCATED:
+			used2fake_allocated(sbinfo, *len, flags & BA_FORMATTED);
+			break;
+
+		case BLOCK_FLUSH_RESERVED:{
+				txn_atom *atom;
+
+				atom = get_current_atom_locked();
+				used2flush_reserved(sbinfo, atom, *len,
+						    flags & BA_FORMATTED);
+				spin_unlock_atom(atom);
+				break;
+			}
+		default:
+			impossible("zam-532", "wrong block stage");
+		}
+	}
+
+	return 0;
+}
+
+/* wrappers for block allocator plugin methods */
+int pre_commit_hook(void)
+{
+	assert("zam-502", get_current_super_private() != NULL);
+	sa_pre_commit_hook();
+	return 0;
+}
+
+/* an actor which applies delete set to block allocator data */
+static int
+apply_dset(txn_atom * atom UNUSED_ARG, const reiser4_block_nr * a,
+	   const reiser4_block_nr * b, void *data UNUSED_ARG)
+{
+	reiser4_context *ctx;
+	reiser4_super_info_data *sbinfo;
+
+	__u64 len = 1;
+
+	ctx = get_current_context();
+	sbinfo = get_super_private(ctx->super);
+
+	assert("zam-877", atom->stage >= ASTAGE_PRE_COMMIT);
+	assert("zam-552", sbinfo != NULL);
+
+	if (b != NULL)
+		len = *b;
+
+	if (REISER4_DEBUG) {
+		spin_lock_reiser4_super(sbinfo);
+
+		assert("zam-554", *a < reiser4_block_count(ctx->super));
+		assert("zam-555", *a + len <= reiser4_block_count(ctx->super));
+
+		spin_unlock_reiser4_super(sbinfo);
+	}
+
+	sa_dealloc_blocks(&sbinfo->space_allocator, *a, len);
+	/* adjust sb block counters */
+	used2free(sbinfo, len);
+	return 0;
+}
+
+void post_commit_hook(void)
+{
+	txn_atom *atom;
+
+	atom = get_current_atom_locked();
+	assert("zam-452", atom->stage == ASTAGE_POST_COMMIT);
+	spin_unlock_atom(atom);
+
+	/* do the block deallocation which was deferred
+	   until commit is done */
+	blocknr_set_iterator(atom, &atom->delete_set, apply_dset, NULL, 1);
+
+	assert("zam-504", get_current_super_private() != NULL);
+	sa_post_commit_hook();
+}
+
+void post_write_back_hook(void)
+{
+	assert("zam-504", get_current_super_private() != NULL);
+
+	sa_post_commit_hook();
+}
+
+/*
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/block_alloc.h newtree/fs/reiser4/block_alloc.h
--- oldtree/fs/reiser4/block_alloc.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/block_alloc.h	2006-02-21 15:58:34.514899496 +0000
@@ -0,0 +1,175 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#if !defined (__FS_REISER4_BLOCK_ALLOC_H__)
+#define __FS_REISER4_BLOCK_ALLOC_H__
+
+#include "dformat.h"
+#include "forward.h"
+
+#include <linux/types.h>	/* for __u??  */
+#include <linux/fs.h>
+
+/* Mask when is applied to given block number shows is that block number is a fake one */
+#define REISER4_FAKE_BLOCKNR_BIT_MASK   0x8000000000000000ULL
+/* Mask which isolates a type of object this fake block number was assigned to */
+#define REISER4_BLOCKNR_STATUS_BIT_MASK 0xC000000000000000ULL
+
+/*result after applying the REISER4_BLOCKNR_STATUS_BIT_MASK should be compared
+   against these two values to understand is the object unallocated or bitmap
+   shadow object (WORKING BITMAP block, look at the plugin/space/bitmap.c) */
+#define REISER4_UNALLOCATED_STATUS_VALUE    0xC000000000000000ULL
+#define REISER4_BITMAP_BLOCKS_STATUS_VALUE  0x8000000000000000ULL
+
+/* specification how block allocation was counted in sb block counters */
+typedef enum {
+	BLOCK_NOT_COUNTED = 0,	/* reiser4 has no info about this block yet */
+	BLOCK_GRABBED = 1,	/* free space grabbed for further allocation
+				   of this block */
+	BLOCK_FLUSH_RESERVED = 2,	/* block is reserved for flush needs. */
+	BLOCK_UNALLOCATED = 3,	/* block is used for existing in-memory object
+				   ( unallocated formatted or unformatted
+				   node) */
+	BLOCK_ALLOCATED = 4	/* block is mapped to disk, real on-disk block
+				   number assigned */
+} block_stage_t;
+
+/* a hint for block allocator */
+struct reiser4_blocknr_hint {
+	/* FIXME: I think we want to add a longterm lock on the bitmap block here.  This
+	   is to prevent jnode_flush() calls from interleaving allocations on the same
+	   bitmap, once a hint is established. */
+
+	/* search start hint */
+	reiser4_block_nr blk;
+	/* if not zero, it is a region size we search for free blocks in */
+	reiser4_block_nr max_dist;
+	/* level for allocation, may be useful have branch-level and higher
+	   write-optimized. */
+	tree_level level;
+	/* block allocator assumes that blocks, which will be mapped to disk,
+	   are in this specified block_stage */
+	block_stage_t block_stage;
+	/* If direction = 1 allocate blocks in backward direction from the end
+	 * of disk to the beginning of disk.  */
+	unsigned int backward:1;
+
+};
+
+/* These flags control block allocation/deallocation behavior */
+enum reiser4_ba_flags {
+	/* do allocatations from reserved (5%) area */
+	BA_RESERVED = (1 << 0),
+
+	/* block allocator can do commit trying to recover free space */
+	BA_CAN_COMMIT = (1 << 1),
+
+	/* if operation will be applied to formatted block */
+	BA_FORMATTED = (1 << 2),
+
+	/* defer actual block freeing until transaction commit */
+	BA_DEFER = (1 << 3),
+
+	/* allocate blocks for permanent fs objects (formatted or unformatted), not
+	   wandered of log blocks */
+	BA_PERMANENT = (1 << 4),
+
+	/* grab space even it was disabled */
+	BA_FORCE = (1 << 5),
+
+	/* use default start value for free blocks search. */
+	BA_USE_DEFAULT_SEARCH_START = (1 << 6)
+};
+
+typedef enum reiser4_ba_flags reiser4_ba_flags_t;
+
+extern void blocknr_hint_init(reiser4_blocknr_hint * hint);
+extern void blocknr_hint_done(reiser4_blocknr_hint * hint);
+extern void update_blocknr_hint_default(const struct super_block *,
+					const reiser4_block_nr *);
+extern void get_blocknr_hint_default(reiser4_block_nr *);
+
+extern reiser4_block_nr reiser4_fs_reserved_space(struct super_block *super);
+
+int assign_fake_blocknr_formatted(reiser4_block_nr *);
+reiser4_block_nr fake_blocknr_unformatted(void);
+
+/* free -> grabbed -> fake_allocated -> used */
+
+int reiser4_grab_space(__u64 count, reiser4_ba_flags_t flags);
+void all_grabbed2free(void);
+void grabbed2free(reiser4_context *, reiser4_super_info_data *, __u64 count);
+void fake_allocated2free(__u64 count, reiser4_ba_flags_t flags);
+void grabbed2flush_reserved_nolock(txn_atom * atom, __u64 count);
+void grabbed2flush_reserved(__u64 count);
+int reiser4_alloc_blocks(reiser4_blocknr_hint * hint,
+			 reiser4_block_nr * start,
+			 reiser4_block_nr * len, reiser4_ba_flags_t flags);
+int reiser4_dealloc_blocks(const reiser4_block_nr *,
+			   const reiser4_block_nr *,
+			   block_stage_t, reiser4_ba_flags_t flags);
+
+static inline int reiser4_alloc_block(reiser4_blocknr_hint * hint,
+				      reiser4_block_nr * start,
+				      reiser4_ba_flags_t flags)
+{
+	reiser4_block_nr one = 1;
+	return reiser4_alloc_blocks(hint, start, &one, flags);
+}
+
+static inline int reiser4_dealloc_block(const reiser4_block_nr * block,
+					block_stage_t stage,
+					reiser4_ba_flags_t flags)
+{
+	const reiser4_block_nr one = 1;
+	return reiser4_dealloc_blocks(block, &one, stage, flags);
+}
+
+#define reiser4_grab_space_force(count, flags)		\
+	reiser4_grab_space(count, flags | BA_FORCE)
+
+extern void grabbed2free_mark(__u64 mark);
+extern int reiser4_grab_reserved(struct super_block *,
+				 __u64, reiser4_ba_flags_t);
+extern void reiser4_release_reserved(struct super_block *super);
+
+/* grabbed -> fake_allocated */
+
+/* fake_allocated -> used */
+
+/* used -> fake_allocated -> grabbed -> free */
+
+extern void flush_reserved2grabbed(txn_atom * atom, __u64 count);
+
+extern int blocknr_is_fake(const reiser4_block_nr * da);
+
+extern void grabbed2cluster_reserved(int count);
+extern void cluster_reserved2grabbed(int count);
+extern void cluster_reserved2free(int count);
+
+extern int check_block_counters(const struct super_block *);
+
+#if REISER4_DEBUG
+
+extern void reiser4_check_block(const reiser4_block_nr *, int);
+
+#else
+
+#  define reiser4_check_block(beg, val)        noop
+
+#endif
+
+extern int pre_commit_hook(void);
+extern void post_commit_hook(void);
+extern void post_write_back_hook(void);
+
+#endif				/* __FS_REISER4_BLOCK_ALLOC_H__ */
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/blocknrset.c newtree/fs/reiser4/blocknrset.c
--- oldtree/fs/reiser4/blocknrset.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/blocknrset.c	2006-02-21 15:58:34.961831552 +0000
@@ -0,0 +1,367 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* This file contains code for various block number sets used by the atom to
+   track the deleted set and wandered block mappings. */
+
+#include "debug.h"
+#include "dformat.h"
+#include "txnmgr.h"
+
+#include <linux/slab.h>
+
+/* The proposed data structure for storing unordered block number sets is a
+   list of elements, each of which contains an array of block number or/and
+   array of block number pairs. That element called blocknr_set_entry is used
+   to store block numbers from the beginning and for extents from the end of
+   the data field (char data[...]). The ->nr_blocks and ->nr_pairs fields
+   count numbers of blocks and extents.
+
+   +------------------- blocknr_set_entry->data ------------------+
+   |block1|block2| ... <free space> ... |pair3|pair2|pair1|
+   +------------------------------------------------------------+
+
+   When current blocknr_set_entry is full, allocate a new one. */
+
+/* Usage examples: blocknr sets are used in reiser4 for storing atom's delete
+ * set (single blocks and block extents), in that case blocknr pair represent an
+ * extent; atom's wandered map is also stored as a blocknr set, blocknr pairs
+ * there represent a (real block) -> (wandered block) mapping. */
+
+typedef struct blocknr_pair blocknr_pair;
+
+/* The total size of a blocknr_set_entry. */
+#define BLOCKNR_SET_ENTRY_SIZE 128
+
+/* The number of blocks that can fit the blocknr data area. */
+#define BLOCKNR_SET_ENTRIES_NUMBER		\
+       ((BLOCKNR_SET_ENTRY_SIZE -		\
+         2 * sizeof (unsigned) -		\
+         sizeof(struct list_head)) /		\
+        sizeof(reiser4_block_nr))
+
+/* An entry of the blocknr_set */
+struct blocknr_set_entry {
+	unsigned nr_singles;
+	unsigned nr_pairs;
+	struct list_head link;
+	reiser4_block_nr entries[BLOCKNR_SET_ENTRIES_NUMBER];
+};
+
+/* A pair of blocks as recorded in the blocknr_set_entry data. */
+struct blocknr_pair {
+	reiser4_block_nr a;
+	reiser4_block_nr b;
+};
+
+/* Return the number of blocknr slots available in a blocknr_set_entry. */
+/* Audited by: green(2002.06.11) */
+static unsigned bse_avail(blocknr_set_entry * bse)
+{
+	unsigned used = bse->nr_singles + 2 * bse->nr_pairs;
+
+	assert("jmacd-5088", BLOCKNR_SET_ENTRIES_NUMBER >= used);
+	cassert(sizeof(blocknr_set_entry) == BLOCKNR_SET_ENTRY_SIZE);
+
+	return BLOCKNR_SET_ENTRIES_NUMBER - used;
+}
+
+/* Initialize a blocknr_set_entry. */
+static void bse_init(blocknr_set_entry *bse)
+{
+	bse->nr_singles = 0;
+	bse->nr_pairs = 0;
+	INIT_LIST_HEAD(&bse->link);
+}
+
+/* Allocate and initialize a blocknr_set_entry. */
+/* Audited by: green(2002.06.11) */
+static blocknr_set_entry *bse_alloc(void)
+{
+	blocknr_set_entry *e;
+
+	if ((e = (blocknr_set_entry *) kmalloc(sizeof(blocknr_set_entry),
+					       GFP_KERNEL)) == NULL)
+		return NULL;
+
+	bse_init(e);
+
+	return e;
+}
+
+/* Free a blocknr_set_entry. */
+/* Audited by: green(2002.06.11) */
+static void bse_free(blocknr_set_entry * bse)
+{
+	kfree(bse);
+}
+
+/* Add a block number to a blocknr_set_entry */
+/* Audited by: green(2002.06.11) */
+static void
+bse_put_single(blocknr_set_entry * bse, const reiser4_block_nr * block)
+{
+	assert("jmacd-5099", bse_avail(bse) >= 1);
+
+	bse->entries[bse->nr_singles++] = *block;
+}
+
+/* Get a pair of block numbers */
+/* Audited by: green(2002.06.11) */
+static inline blocknr_pair *bse_get_pair(blocknr_set_entry * bse, unsigned pno)
+{
+	assert("green-1", BLOCKNR_SET_ENTRIES_NUMBER >= 2 * (pno + 1));
+
+	return (blocknr_pair *) (bse->entries + BLOCKNR_SET_ENTRIES_NUMBER -
+				 2 * (pno + 1));
+}
+
+/* Add a pair of block numbers to a blocknr_set_entry */
+/* Audited by: green(2002.06.11) */
+static void
+bse_put_pair(blocknr_set_entry * bse, const reiser4_block_nr * a,
+	     const reiser4_block_nr * b)
+{
+	blocknr_pair *pair;
+
+	assert("jmacd-5100", bse_avail(bse) >= 2 && a != NULL && b != NULL);
+
+	pair = bse_get_pair(bse, bse->nr_pairs++);
+
+	pair->a = *a;
+	pair->b = *b;
+}
+
+/* Add either a block or pair of blocks to the block number set.  The first
+   blocknr (@a) must be non-NULL.  If @b is NULL a single blocknr is added, if
+   @b is non-NULL a pair is added.  The block number set belongs to atom, and
+   the call is made with the atom lock held.  There may not be enough space in
+   the current blocknr_set_entry.  If new_bsep points to a non-NULL
+   blocknr_set_entry then it will be added to the blocknr_set and new_bsep
+   will be set to NULL.  If new_bsep contains NULL then the atom lock will be
+   released and a new bse will be allocated in new_bsep.  E_REPEAT will be
+   returned with the atom unlocked for the operation to be tried again.  If
+   the operation succeeds, 0 is returned.  If new_bsep is non-NULL and not
+   used during the call, it will be freed automatically. */
+static int blocknr_set_add(txn_atom *atom, blocknr_set *bset,
+			   blocknr_set_entry **new_bsep, const reiser4_block_nr *a,
+			   const reiser4_block_nr *b)
+{
+	blocknr_set_entry *bse;
+	unsigned entries_needed;
+
+	assert("jmacd-5101", a != NULL);
+
+	entries_needed = (b == NULL) ? 1 : 2;
+	if (list_empty(&bset->entries) ||
+	    bse_avail(list_entry(bset->entries.next, blocknr_set_entry, link)) < entries_needed) {
+		/* See if a bse was previously allocated. */
+		if (*new_bsep == NULL) {
+			spin_unlock_atom(atom);
+			*new_bsep = bse_alloc();
+			return (*new_bsep != NULL) ? -E_REPEAT :
+				RETERR(-ENOMEM);
+		}
+
+		/* Put it on the head of the list. */
+		list_add(&((*new_bsep)->link), &bset->entries);
+
+		*new_bsep = NULL;
+	}
+
+	/* Add the single or pair. */
+	bse = list_entry(bset->entries.next, blocknr_set_entry, link);
+	if (b == NULL) {
+		bse_put_single(bse, a);
+	} else {
+		bse_put_pair(bse, a, b);
+	}
+
+	/* If new_bsep is non-NULL then there was an allocation race, free this copy. */
+	if (*new_bsep != NULL) {
+		bse_free(*new_bsep);
+		*new_bsep = NULL;
+	}
+
+	return 0;
+}
+
+/* Add an extent to the block set.  If the length is 1, it is treated as a
+   single block (e.g., reiser4_set_add_block). */
+/* Audited by: green(2002.06.11) */
+/* Auditor note: Entire call chain cannot hold any spinlocks, because
+   kmalloc might schedule. The only exception is atom spinlock, which is
+   properly freed. */
+int
+blocknr_set_add_extent(txn_atom * atom,
+		       blocknr_set * bset,
+		       blocknr_set_entry ** new_bsep,
+		       const reiser4_block_nr * start,
+		       const reiser4_block_nr * len)
+{
+	assert("jmacd-5102", start != NULL && len != NULL && *len > 0);
+	return blocknr_set_add(atom, bset, new_bsep, start,
+			       *len == 1 ? NULL : len);
+}
+
+/* Add a block pair to the block set. It adds exactly a pair, which is checked
+ * by an assertion that both arguments are not null.*/
+/* Audited by: green(2002.06.11) */
+/* Auditor note: Entire call chain cannot hold any spinlocks, because
+   kmalloc might schedule. The only exception is atom spinlock, which is
+   properly freed. */
+int
+blocknr_set_add_pair(txn_atom * atom,
+		     blocknr_set * bset,
+		     blocknr_set_entry ** new_bsep, const reiser4_block_nr * a,
+		     const reiser4_block_nr * b)
+{
+	assert("jmacd-5103", a != NULL && b != NULL);
+	return blocknr_set_add(atom, bset, new_bsep, a, b);
+}
+
+/* Initialize a blocknr_set. */
+void blocknr_set_init(blocknr_set *bset)
+{
+	INIT_LIST_HEAD(&bset->entries);
+}
+
+/* Release the entries of a blocknr_set. */
+void blocknr_set_destroy(blocknr_set *bset)
+{
+	blocknr_set_entry *bse;
+
+	while (!list_empty_careful(&bset->entries)) {
+		bse = list_entry(bset->entries.next, blocknr_set_entry, link);
+		list_del_init(&bse->link);
+		bse_free(bse);
+	}
+}
+
+/* Merge blocknr_set entries out of @from into @into. */
+/* Audited by: green(2002.06.11) */
+/* Auditor comments: This merge does not know if merged sets contain
+   blocks pairs (As for wandered sets) or extents, so it cannot really merge
+   overlapping ranges if there is some. So I believe it may lead to
+   some blocks being presented several times in one blocknr_set. To help
+   debugging such problems it might help to check for duplicate entries on
+   actual processing of this set. Testing this kind of stuff right here is
+   also complicated by the fact that these sets are not sorted and going
+   through whole set on each element addition is going to be CPU-heavy task */
+void blocknr_set_merge(blocknr_set * from, blocknr_set * into)
+{
+	blocknr_set_entry *bse_into = NULL;
+
+	/* If @from is empty, no work to perform. */
+	if (list_empty_careful(&from->entries)) {
+		return;
+	}
+
+	/* If @into is not empty, try merging partial-entries. */
+	if (!list_empty_careful(&into->entries)) {
+
+		/* Neither set is empty, pop the front to members and try to combine them. */
+		blocknr_set_entry *bse_from;
+		unsigned into_avail;
+
+		bse_into = list_entry(into->entries.next, blocknr_set_entry, link);
+		list_del_init(&bse_into->link);
+		bse_from = list_entry(from->entries.next, blocknr_set_entry, link);
+		list_del_init(&bse_from->link);
+
+		/* Combine singles. */
+		for (into_avail = bse_avail(bse_into);
+		     into_avail != 0 && bse_from->nr_singles != 0;
+		     into_avail -= 1) {
+			bse_put_single(bse_into,
+				       &bse_from->entries[--bse_from->
+							  nr_singles]);
+		}
+
+		/* Combine pairs. */
+		for (; into_avail > 1 && bse_from->nr_pairs != 0;
+		     into_avail -= 2) {
+			blocknr_pair *pair =
+			    bse_get_pair(bse_from, --bse_from->nr_pairs);
+			bse_put_pair(bse_into, &pair->a, &pair->b);
+		}
+
+		/* If bse_from is empty, delete it now. */
+		if (bse_avail(bse_from) == BLOCKNR_SET_ENTRIES_NUMBER) {
+			bse_free(bse_from);
+		} else {
+			/* Otherwise, bse_into is full or nearly full (e.g.,
+			   it could have one slot avail and bse_from has one
+			   pair left).  Push it back onto the list.  bse_from
+			   becomes bse_into, which will be the new partial. */
+			list_add(&bse_into->link, &into->entries);
+			bse_into = bse_from;
+		}
+	}
+
+	/* Splice lists together. */
+	list_splice_init(&from->entries, into->entries.prev);
+
+	/* Add the partial entry back to the head of the list. */
+	if (bse_into != NULL) {
+		list_add(&bse_into->link, &into->entries);
+	}
+}
+
+/* Iterate over all blocknr set elements. */
+int blocknr_set_iterator(txn_atom *atom, blocknr_set *bset,
+			 blocknr_set_actor_f actor, void *data, int delete)
+{
+
+	blocknr_set_entry *entry;
+
+	assert("zam-429", atom != NULL);
+	assert("zam-430", atom_is_protected(atom));
+	assert("zam-431", bset != 0);
+	assert("zam-432", actor != NULL);
+
+	entry = list_entry(bset->entries.next, blocknr_set_entry, link);
+	while (&bset->entries != &entry->link) {
+		blocknr_set_entry *tmp = list_entry(entry->link.next, blocknr_set_entry, link);
+		unsigned int i;
+		int ret;
+
+		for (i = 0; i < entry->nr_singles; i++) {
+			ret = actor(atom, &entry->entries[i], NULL, data);
+
+			/* We can't break a loop if delete flag is set. */
+			if (ret != 0 && !delete)
+				return ret;
+		}
+
+		for (i = 0; i < entry->nr_pairs; i++) {
+			struct blocknr_pair *ab;
+
+			ab = bse_get_pair(entry, i);
+
+			ret = actor(atom, &ab->a, &ab->b, data);
+
+			if (ret != 0 && !delete)
+				return ret;
+		}
+
+		if (delete) {
+			list_del(&entry->link);
+			bse_free(entry);
+		}
+
+		entry = tmp;
+	}
+
+	return 0;
+}
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * scroll-step: 1
+ * End:
+ */
diff -urN oldtree/fs/reiser4/carry.c newtree/fs/reiser4/carry.c
--- oldtree/fs/reiser4/carry.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/carry.c	2006-02-21 15:58:34.962831400 +0000
@@ -0,0 +1,1423 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+/* Functions to "carry" tree modification(s) upward. */
+/* Tree is modified one level at a time. As we modify a level we accumulate a
+   set of changes that need to be propagated to the next level.  We manage
+   node locking such that any searches that collide with carrying are
+   restarted, from the root if necessary.
+
+   Insertion of a new item may result in items being moved among nodes and
+   this requires the delimiting key to be updated at the least common parent
+   of the nodes modified to preserve search tree invariants. Also, insertion
+   may require allocation of a new node. A pointer to the new node has to be
+   inserted into some node on the parent level, etc.
+
+   Tree carrying is meant to be analogous to arithmetic carrying.
+
+   A carry operation is always associated with some node (&carry_node).
+
+   Carry process starts with some initial set of operations to be performed
+   and an initial set of already locked nodes.  Operations are performed one
+   by one. Performing each single operation has following possible effects:
+
+    - content of carry node associated with operation is modified
+    - new carry nodes are locked and involved into carry process on this level
+    - new carry operations are posted to the next level
+
+   After all carry operations on this level are done, process is repeated for
+   the accumulated sequence on carry operations for the next level. This
+   starts by trying to lock (in left to right order) all carry nodes
+   associated with carry operations on the parent level. After this, we decide
+   whether more nodes are required on the left of already locked set. If so,
+   all locks taken on the parent level are released, new carry nodes are
+   added, and locking process repeats.
+
+   It may happen that balancing process fails owing to unrecoverable error on
+   some of upper levels of a tree (possible causes are io error, failure to
+   allocate new node, etc.). In this case we should unmount the filesystem,
+   rebooting if it is the root, and possibly advise the use of fsck.
+
+   USAGE:
+
+    int some_tree_operation( znode *node, ... )
+    {
+       // Allocate on a stack pool of carry objects: operations and nodes.
+       // Most carry processes will only take objects from here, without
+       // dynamic allocation.
+
+I feel uneasy about this pool.  It adds to code complexity, I understand why it exists, but.... -Hans
+
+       carry_pool  pool;
+       carry_level lowest_level;
+       carry_op   *op;
+
+       init_carry_pool( &pool );
+       init_carry_level( &lowest_level, &pool );
+
+       // operation may be one of:
+       //   COP_INSERT    --- insert new item into node
+       //   COP_CUT       --- remove part of or whole node
+       //   COP_PASTE     --- increase size of item
+       //   COP_DELETE    --- delete pointer from parent node
+       //   COP_UPDATE    --- update delimiting key in least
+       //                     common ancestor of two
+
+       op = post_carry( &lowest_level, operation, node, 0 );
+       if( IS_ERR( op ) || ( op == NULL ) ) {
+           handle error
+       } else {
+           // fill in remaining fields in @op, according to carry.h:carry_op
+           result = carry( &lowest_level, NULL );
+       }
+       done_carry_pool( &pool );
+    }
+
+   When you are implementing node plugin method that participates in carry
+   (shifting, insertion, deletion, etc.), do the following:
+
+   int foo_node_method( znode *node, ..., carry_level *todo )
+   {
+       carry_op   *op;
+
+       ....
+
+       // note, that last argument to post_carry() is non-null
+       // here, because @op is to be applied to the parent of @node, rather
+       // than to the @node itself as in the previous case.
+
+       op = node_post_carry( todo, operation, node, 1 );
+       // fill in remaining fields in @op, according to carry.h:carry_op
+
+       ....
+
+   }
+
+   BATCHING:
+
+   One of the main advantages of level-by-level balancing implemented here is
+   ability to batch updates on a parent level and to peform them more
+   efficiently as a result.
+
+   Description To Be Done (TBD).
+
+   DIFFICULTIES AND SUBTLE POINTS:
+
+   1. complex plumbing is required, because:
+
+       a. effective allocation through pools is needed
+
+       b. target of operation is not exactly known when operation is
+       posted. This is worked around through bitfields in &carry_node and
+       logic in lock_carry_node()
+
+       c. of interaction with locking code: node should be added into sibling
+       list when pointer to it is inserted into its parent, which is some time
+       after node was created. Between these moments, node is somewhat in
+       suspended state and is only registered in the carry lists
+
+    2. whole balancing logic is implemented here, in particular, insertion
+    logic is coded in make_space().
+
+    3. special cases like insertion (add_tree_root()) or deletion
+    (kill_tree_root()) of tree root and morphing of paste into insert
+    (insert_paste()) have to be handled.
+
+    4. there is non-trivial interdependency between allocation of new nodes
+    and almost everything else. This is mainly due to the (1.c) above. I shall
+    write about this later.
+
+*/
+
+#include "forward.h"
+#include "debug.h"
+#include "key.h"
+#include "coord.h"
+#include "plugin/item/item.h"
+#include "plugin/item/extent.h"
+#include "plugin/node/node.h"
+#include "jnode.h"
+#include "znode.h"
+#include "tree_mod.h"
+#include "tree_walk.h"
+#include "block_alloc.h"
+#include "pool.h"
+#include "tree.h"
+#include "carry.h"
+#include "carry_ops.h"
+#include "super.h"
+#include "reiser4.h"
+
+#include <linux/types.h>
+
+/* level locking/unlocking */
+static int lock_carry_level(carry_level * level);
+static void unlock_carry_level(carry_level * level, int failure);
+static void done_carry_level(carry_level * level);
+static void unlock_carry_node(carry_level * level, carry_node * node, int fail);
+
+int lock_carry_node(carry_level * level, carry_node * node);
+int lock_carry_node_tail(carry_node * node);
+
+/* carry processing proper */
+static int carry_on_level(carry_level * doing, carry_level * todo);
+
+static carry_op *add_op(carry_level * level, pool_ordering order,
+			carry_op * reference);
+
+/* handlers for carry operations. */
+
+static void fatal_carry_error(carry_level * doing, int ecode);
+static int add_new_root(carry_level * level, carry_node * node, znode * fake);
+
+static int carry_estimate_reserve(carry_level * level);
+
+static void print_level(const char *prefix, carry_level * level);
+
+#if REISER4_DEBUG
+typedef enum {
+	CARRY_TODO,
+	CARRY_DOING
+} carry_queue_state;
+static int carry_level_invariant(carry_level * level, carry_queue_state state);
+#endif
+
+static int perthread_pages_reserve(int nrpages, int gfp)
+{
+	return 0;
+}
+
+static void perthread_pages_release(int nrpages)
+{
+}
+
+static int perthread_pages_count(void)
+{
+	return 0;
+}
+
+/* main entry point for tree balancing.
+
+   Tree carry performs operations from @doing and while doing so accumulates
+   information about operations to be performed on the next level ("carried"
+   to the parent level). Carried operations are performed, causing possibly
+   more operations to be carried upward etc. carry() takes care about
+   locking and pinning znodes while operating on them.
+
+   For usage, see comment at the top of fs/reiser4/carry.c
+
+*/
+int carry(carry_level * doing /* set of carry operations to be performed */ ,
+	  carry_level * done	/* set of nodes, already performed at the
+				 * previous level. NULL in most cases */ )
+{
+	int result = 0;
+	/* queue of new requests */
+	carry_level *todo;
+	int wasreserved;
+	int reserve;
+	ON_DEBUG(STORE_COUNTERS);
+
+	assert("nikita-888", doing != NULL);
+	BUG_ON(done != NULL);
+
+	todo = doing + 1;
+	init_carry_level(todo, doing->pool);
+
+	/* queue of requests preformed on the previous level */
+	done = todo + 1;
+	init_carry_level(done, doing->pool);
+
+	wasreserved = perthread_pages_count();
+	reserve = carry_estimate_reserve(doing);
+	result = perthread_pages_reserve(reserve, GFP_KERNEL);
+	if (result != 0)
+		return result;
+
+	/* iterate until there is nothing more to do */
+	while (result == 0 && doing->ops_num > 0) {
+		carry_level *tmp;
+
+		/* at this point @done is locked. */
+		/* repeat lock/do/unlock while
+
+		   (1) lock_carry_level() fails due to deadlock avoidance, or
+
+		   (2) carry_on_level() decides that more nodes have to
+		   be involved.
+
+		   (3) some unexpected error occurred while balancing on the
+		   upper levels. In this case all changes are rolled back.
+
+		 */
+		while (1) {
+			result = lock_carry_level(doing);
+			if (result == 0) {
+				/* perform operations from @doing and
+				   accumulate new requests in @todo */
+				result = carry_on_level(doing, todo);
+				if (result == 0)
+					break;
+				else if (result != -E_REPEAT ||
+					 !doing->restartable) {
+					warning("nikita-1043",
+						"Fatal error during carry: %i",
+						result);
+					print_level("done", done);
+					print_level("doing", doing);
+					print_level("todo", todo);
+					/* do some rough stuff like aborting
+					   all pending transcrashes and thus
+					   pushing tree back to the consistent
+					   state. Alternatvely, just panic.
+					 */
+					fatal_carry_error(doing, result);
+					return result;
+				}
+			} else if (result != -E_REPEAT) {
+				fatal_carry_error(doing, result);
+				return result;
+			}
+			unlock_carry_level(doing, 1);
+		}
+		/* at this point @done can be safely unlocked */
+		done_carry_level(done);
+
+		/* cyclically shift queues */
+		tmp = done;
+		done = doing;
+		doing = todo;
+		todo = tmp;
+		init_carry_level(todo, doing->pool);
+
+		/* give other threads chance to run */
+		preempt_point();
+	}
+	done_carry_level(done);
+
+	assert("nikita-3460", perthread_pages_count() - wasreserved >= 0);
+	perthread_pages_release(perthread_pages_count() - wasreserved);
+
+	/* all counters, but x_refs should remain the same. x_refs can change
+	   owing to transaction manager */
+	ON_DEBUG(CHECK_COUNTERS);
+	return result;
+}
+
+/* perform carry operations on given level.
+
+   Optimizations proposed by pooh:
+
+   (1) don't lock all nodes from queue at the same time. Lock nodes lazily as
+   required;
+
+   (2) unlock node if there are no more operations to be performed upon it and
+   node didn't add any operation to @todo. This can be implemented by
+   attaching to each node two counters: counter of operaions working on this
+   node and counter and operations carried upward from this node.
+
+*/
+static int carry_on_level(carry_level * doing	/* queue of carry operations to
+						 * do on this level */ ,
+			  carry_level * todo	/* queue where new carry
+						 * operations to be performed on
+						 * the * parent level are
+						 * accumulated during @doing
+						 * processing. */ )
+{
+	int result;
+	int (*f) (carry_op *, carry_level *, carry_level *);
+	carry_op *op;
+	carry_op *tmp_op;
+
+	assert("nikita-1034", doing != NULL);
+	assert("nikita-1035", todo != NULL);
+
+	/* @doing->nodes are locked. */
+
+	/* This function can be split into two phases: analysis and modification.
+
+	   Analysis calculates precisely what items should be moved between
+	   nodes. This information is gathered in some structures attached to
+	   each carry_node in a @doing queue. Analysis also determines whether
+	   new nodes are to be allocated etc.
+
+	   After analysis is completed, actual modification is performed. Here
+	   we can take advantage of "batch modification": if there are several
+	   operations acting on the same node, modifications can be performed
+	   more efficiently when batched together.
+
+	   Above is an optimization left for the future.
+	 */
+	/* Important, but delayed optimization: it's possible to batch
+	   operations together and perform them more efficiently as a
+	   result. For example, deletion of several neighboring items from a
+	   node can be converted to a single ->cut() operation.
+
+	   Before processing queue, it should be scanned and "mergeable"
+	   operations merged.
+	 */
+	result = 0;
+	for_all_ops(doing, op, tmp_op) {
+		carry_opcode opcode;
+
+		assert("nikita-1041", op != NULL);
+		opcode = op->op;
+		assert("nikita-1042", op->op < COP_LAST_OP);
+		f = op_dispatch_table[op->op].handler;
+		result = f(op, doing, todo);
+		/* locking can fail with -E_REPEAT. Any different error is fatal
+		   and will be handled by fatal_carry_error() sledgehammer.
+		 */
+		if (result != 0)
+			break;
+	}
+	if (result == 0) {
+		carry_plugin_info info;
+		carry_node *scan;
+		carry_node *tmp_scan;
+
+		info.doing = doing;
+		info.todo = todo;
+
+		assert("nikita-3002",
+		       carry_level_invariant(doing, CARRY_DOING));
+		for_all_nodes(doing, scan, tmp_scan) {
+			znode *node;
+
+			node = carry_real(scan);
+			assert("nikita-2547", node != NULL);
+			if (node_is_empty(node)) {
+				result =
+				    node_plugin_by_node(node)->
+				    prepare_removal(node, &info);
+				if (result != 0)
+					break;
+			}
+		}
+	}
+	return result;
+}
+
+/* post carry operation
+
+   This is main function used by external carry clients: node layout plugins
+   and tree operations to create new carry operation to be performed on some
+   level.
+
+   New operation will be included in the @level queue. To actually perform it,
+   call carry( level, ... ). This function takes write lock on @node. Carry
+   manages all its locks by itself, don't worry about this.
+
+   This function adds operation and node at the end of the queue. It is up to
+   caller to guarantee proper ordering of node queue.
+
+*/
+carry_op *post_carry(carry_level * level	/* queue where new operation is to
+						 * be posted at */ ,
+		     carry_opcode op /* opcode of operation */ ,
+		     znode * node	/* node on which this operation
+					 * will operate */ ,
+		     int apply_to_parent_p	/* whether operation will operate
+						 * directly on @node or on it
+						 * parent. */ )
+{
+	carry_op *result;
+	carry_node *child;
+
+	assert("nikita-1046", level != NULL);
+	assert("nikita-1788", znode_is_write_locked(node));
+
+	result = add_op(level, POOLO_LAST, NULL);
+	if (IS_ERR(result))
+		return result;
+	child = add_carry(level, POOLO_LAST, NULL);
+	if (IS_ERR(child)) {
+		reiser4_pool_free(&level->pool->op_pool, &result->header);
+		return (carry_op *) child;
+	}
+	result->node = child;
+	result->op = op;
+	child->parent = apply_to_parent_p;
+	if (ZF_ISSET(node, JNODE_ORPHAN))
+		child->left_before = 1;
+	child->node = node;
+	return result;
+}
+
+/* initialize carry queue */
+void init_carry_level(carry_level * level /* level to initialize */ ,
+		      carry_pool * pool	/* pool @level will allocate objects
+					 * from */ )
+{
+	assert("nikita-1045", level != NULL);
+	assert("nikita-967", pool != NULL);
+
+	memset(level, 0, sizeof *level);
+	level->pool = pool;
+
+	INIT_LIST_HEAD(&level->nodes);
+	INIT_LIST_HEAD(&level->ops);
+}
+
+/* allocate carry pool and initialize pools within queue */
+carry_pool *init_carry_pool(int size)
+{
+	carry_pool *pool;
+
+	assert("", size >= sizeof(carry_pool) + 3 * sizeof(carry_level));
+	pool = kmalloc(size, GFP_KERNEL);
+	if (pool == NULL)
+		return ERR_PTR(RETERR(-ENOMEM));
+
+	reiser4_init_pool(&pool->op_pool, sizeof(carry_op), CARRIES_POOL_SIZE,
+			  (char *)pool->op);
+	reiser4_init_pool(&pool->node_pool, sizeof(carry_node),
+			  NODES_LOCKED_POOL_SIZE, (char *)pool->node);
+	return pool;
+}
+
+/* finish with queue pools */
+void done_carry_pool(carry_pool * pool /* pool to destroy */ )
+{
+	reiser4_done_pool(&pool->op_pool);
+	reiser4_done_pool(&pool->node_pool);
+	kfree(pool);
+}
+
+/* add new carry node to the @level.
+
+   Returns pointer to the new carry node allocated from pool.  It's up to
+   callers to maintain proper order in the @level. Assumption is that if carry
+   nodes on one level are already sorted and modifications are peroformed from
+   left to right, carry nodes added on the parent level will be ordered
+   automatically. To control ordering use @order and @reference parameters.
+
+*/
+carry_node *add_carry_skip(carry_level * level	/* &carry_level to add node
+						 * to */ ,
+			   pool_ordering order	/* where to insert: at the
+						 * beginning of @level,
+						 * before @reference, after
+						 * @reference, at the end
+						 * of @level */ ,
+			   carry_node * reference	/* reference node for
+							 * insertion */ )
+{
+	ON_DEBUG(carry_node * orig_ref = reference);
+
+	if (order == POOLO_BEFORE) {
+		reference = find_left_carry(reference, level);
+		if (reference == NULL)
+			reference = list_entry(level->nodes.next, carry_node,
+					       header.level_linkage);
+		else
+			reference = list_entry(reference->header.level_linkage.next,
+					       carry_node, header.level_linkage);
+	} else if (order == POOLO_AFTER) {
+		reference = find_right_carry(reference, level);
+		if (reference == NULL)
+			reference = list_entry(level->nodes.prev, carry_node,
+					       header.level_linkage);
+		else
+			reference = list_entry(reference->header.level_linkage.prev,
+					       carry_node, header.level_linkage);
+	}
+	assert("nikita-2209",
+	       ergo(orig_ref != NULL,
+		    carry_real(reference) == carry_real(orig_ref)));
+	return add_carry(level, order, reference);
+}
+
+carry_node *add_carry(carry_level * level	/* &carry_level to add node
+						 * to */ ,
+		      pool_ordering order	/* where to insert: at the
+						 * beginning of @level, before
+						 * @reference, after @reference,
+						 * at the end of @level */ ,
+		      carry_node * reference	/* reference node for
+						 * insertion */ )
+{
+	carry_node *result;
+
+	result =
+	    (carry_node *) add_obj(&level->pool->node_pool, &level->nodes,
+				   order, &reference->header);
+	if (!IS_ERR(result) && (result != NULL))
+		++level->nodes_num;
+	return result;
+}
+
+/* add new carry operation to the @level.
+
+   Returns pointer to the new carry operations allocated from pool. It's up to
+   callers to maintain proper order in the @level. To control ordering use
+   @order and @reference parameters.
+
+*/
+static carry_op *add_op(carry_level * level /* &carry_level to add node to */ ,
+			pool_ordering order	/* where to insert: at the beginning of
+						 * @level, before @reference, after
+						 * @reference, at the end of @level */ ,
+			carry_op *
+			reference /* reference node for insertion */ )
+{
+	carry_op *result;
+
+	result =
+	    (carry_op *) add_obj(&level->pool->op_pool, &level->ops, order,
+				 &reference->header);
+	if (!IS_ERR(result) && (result != NULL))
+		++level->ops_num;
+	return result;
+}
+
+/* Return node on the right of which @node was created.
+
+   Each node is created on the right of some existing node (or it is new root,
+   which is special case not handled here).
+
+   @node is new node created on some level, but not yet inserted into its
+   parent, it has corresponding bit (JNODE_ORPHAN) set in zstate.
+
+*/
+static carry_node *find_begetting_brother(carry_node * node	/* node to start search
+								 * from */ ,
+					  carry_level * kin UNUSED_ARG	/* level to
+									 * scan */ )
+{
+	carry_node *scan;
+
+	assert("nikita-1614", node != NULL);
+	assert("nikita-1615", kin != NULL);
+	assert("nikita-1616", LOCK_CNT_GTZ(rw_locked_tree));
+	assert("nikita-1619", ergo(carry_real(node) != NULL,
+				   ZF_ISSET(carry_real(node), JNODE_ORPHAN)));
+
+	for (scan = node;;
+	     scan = list_entry(scan->header.level_linkage.prev, carry_node,
+			       header.level_linkage)) {
+		assert("nikita-1617", &kin->nodes != &scan->header.level_linkage);
+		if ((scan->node != node->node) &&
+		    !ZF_ISSET(scan->node, JNODE_ORPHAN)) {
+			assert("nikita-1618", carry_real(scan) != NULL);
+			break;
+		}
+	}
+	return scan;
+}
+
+static cmp_t
+carry_node_cmp(carry_level * level, carry_node * n1, carry_node * n2)
+{
+	assert("nikita-2199", n1 != NULL);
+	assert("nikita-2200", n2 != NULL);
+
+	if (n1 == n2)
+		return EQUAL_TO;
+	while (1) {
+		n1 = carry_node_next(n1);
+		if (carry_node_end(level, n1))
+			return GREATER_THAN;
+		if (n1 == n2)
+			return LESS_THAN;
+	}
+	impossible("nikita-2201", "End of level reached");
+}
+
+carry_node *find_carry_node(carry_level * level, const znode * node)
+{
+	carry_node *scan;
+	carry_node *tmp_scan;
+
+	assert("nikita-2202", level != NULL);
+	assert("nikita-2203", node != NULL);
+
+	for_all_nodes(level, scan, tmp_scan) {
+		if (carry_real(scan) == node)
+			return scan;
+	}
+	return NULL;
+}
+
+znode *carry_real(const carry_node * node)
+{
+	assert("nikita-3061", node != NULL);
+
+	return node->lock_handle.node;
+}
+
+carry_node *insert_carry_node(carry_level * doing, carry_level * todo,
+			      const znode * node)
+{
+	carry_node *base;
+	carry_node *scan;
+	carry_node *tmp_scan;
+	carry_node *proj;
+
+	base = find_carry_node(doing, node);
+	assert("nikita-2204", base != NULL);
+
+	for_all_nodes(todo, scan, tmp_scan) {
+		proj = find_carry_node(doing, scan->node);
+		assert("nikita-2205", proj != NULL);
+		if (carry_node_cmp(doing, proj, base) != LESS_THAN)
+			break;
+	}
+	return scan;
+}
+
+static carry_node *add_carry_atplace(carry_level * doing, carry_level * todo,
+				     znode * node)
+{
+	carry_node *reference;
+
+	assert("nikita-2994", doing != NULL);
+	assert("nikita-2995", todo != NULL);
+	assert("nikita-2996", node != NULL);
+
+	reference = insert_carry_node(doing, todo, node);
+	assert("nikita-2997", reference != NULL);
+
+	return add_carry(todo, POOLO_BEFORE, reference);
+}
+
+/* like post_carry(), but designed to be called from node plugin methods.
+   This function is different from post_carry() in that it finds proper place
+   to insert node in the queue. */
+carry_op *node_post_carry(carry_plugin_info * info	/* carry parameters
+							 * passed down to node
+							 * plugin */ ,
+			  carry_opcode op /* opcode of operation */ ,
+			  znode * node	/* node on which this
+					 * operation will operate */ ,
+			  int apply_to_parent_p	/* whether operation will
+						 * operate directly on @node
+						 * or on it parent. */ )
+{
+	carry_op *result;
+	carry_node *child;
+
+	assert("nikita-2207", info != NULL);
+	assert("nikita-2208", info->todo != NULL);
+
+	if (info->doing == NULL)
+		return post_carry(info->todo, op, node, apply_to_parent_p);
+
+	result = add_op(info->todo, POOLO_LAST, NULL);
+	if (IS_ERR(result))
+		return result;
+	child = add_carry_atplace(info->doing, info->todo, node);
+	if (IS_ERR(child)) {
+		reiser4_pool_free(&info->todo->pool->op_pool, &result->header);
+		return (carry_op *) child;
+	}
+	result->node = child;
+	result->op = op;
+	child->parent = apply_to_parent_p;
+	if (ZF_ISSET(node, JNODE_ORPHAN))
+		child->left_before = 1;
+	child->node = node;
+	return result;
+}
+
+/* lock all carry nodes in @level */
+static int lock_carry_level(carry_level * level /* level to lock */ )
+{
+	int result;
+	carry_node *node;
+	carry_node *tmp_node;
+
+	assert("nikita-881", level != NULL);
+	assert("nikita-2229", carry_level_invariant(level, CARRY_TODO));
+
+	/* lock nodes from left to right */
+	result = 0;
+	for_all_nodes(level, node, tmp_node) {
+		result = lock_carry_node(level, node);
+		if (result != 0)
+			break;
+	}
+	return result;
+}
+
+/* Synchronize delimiting keys between @node and its left neighbor.
+
+   To reduce contention on dk key and simplify carry code, we synchronize
+   delimiting keys only when carry ultimately leaves tree level (carrying
+   changes upward) and unlocks nodes at this level.
+
+   This function first finds left neighbor of @node and then updates left
+   neighbor's right delimiting key to conincide with least key in @node.
+
+*/
+
+ON_DEBUG(extern atomic_t delim_key_version;
+    )
+
+static void sync_dkeys(znode * spot /* node to update */ )
+{
+	reiser4_key pivot;
+	reiser4_tree *tree;
+
+	assert("nikita-1610", spot != NULL);
+	assert("nikita-1612", LOCK_CNT_NIL(rw_locked_dk));
+
+	tree = znode_get_tree(spot);
+	read_lock_tree(tree);
+	write_lock_dk(tree);
+
+	assert("nikita-2192", znode_is_loaded(spot));
+
+	/* sync left delimiting key of @spot with key in its leftmost item */
+	if (node_is_empty(spot))
+		pivot = *znode_get_rd_key(spot);
+	else
+		leftmost_key_in_node(spot, &pivot);
+
+	znode_set_ld_key(spot, &pivot);
+
+	/* there can be sequence of empty nodes pending removal on the left of
+	   @spot. Scan them and update their left and right delimiting keys to
+	   match left delimiting key of @spot. Also, update right delimiting
+	   key of first non-empty left neighbor.
+	 */
+	while (1) {
+		if (!ZF_ISSET(spot, JNODE_LEFT_CONNECTED))
+			break;
+
+		spot = spot->left;
+		if (spot == NULL)
+			break;
+
+		znode_set_rd_key(spot, &pivot);
+		/* don't sink into the domain of another balancing */
+		if (!znode_is_write_locked(spot))
+			break;
+		if (ZF_ISSET(spot, JNODE_HEARD_BANSHEE))
+			znode_set_ld_key(spot, &pivot);
+		else
+			break;
+	}
+
+	write_unlock_dk(tree);
+	read_unlock_tree(tree);
+}
+
+/* unlock all carry nodes in @level */
+static void unlock_carry_level(carry_level * level /* level to unlock */ ,
+			       int failure	/* true if unlocking owing to
+						 * failure */ )
+{
+	carry_node *node;
+	carry_node *tmp_node;
+
+	assert("nikita-889", level != NULL);
+
+	if (!failure) {
+		znode *spot;
+
+		spot = NULL;
+		/* update delimiting keys */
+		for_all_nodes(level, node, tmp_node) {
+			if (carry_real(node) != spot) {
+				spot = carry_real(node);
+				sync_dkeys(spot);
+			}
+		}
+	}
+
+	/* nodes can be unlocked in arbitrary order.  In preemptible
+	   environment it's better to unlock in reverse order of locking,
+	   though.
+	 */
+	for_all_nodes_back(level, node, tmp_node) {
+		/* all allocated nodes should be already linked to their
+		   parents at this moment. */
+		assert("nikita-1631", ergo(!failure, !ZF_ISSET(carry_real(node),
+							       JNODE_ORPHAN)));
+		ON_DEBUG(check_dkeys(carry_real(node)));
+		unlock_carry_node(level, node, failure);
+	}
+	level->new_root = NULL;
+}
+
+/* finish with @level
+
+   Unlock nodes and release all allocated resources */
+static void done_carry_level(carry_level * level /* level to finish */ )
+{
+	carry_node *node;
+	carry_node *tmp_node;
+	carry_op *op;
+	carry_op *tmp_op;
+
+	assert("nikita-1076", level != NULL);
+
+	unlock_carry_level(level, 0);
+	for_all_nodes(level, node, tmp_node) {
+		assert("nikita-2113", list_empty_careful(&node->lock_handle.locks_link));
+		assert("nikita-2114", list_empty_careful(&node->lock_handle.owners_link));
+		reiser4_pool_free(&level->pool->node_pool, &node->header);
+	}
+	for_all_ops(level, op, tmp_op)
+	    reiser4_pool_free(&level->pool->op_pool, &op->header);
+}
+
+/* helper function to complete locking of carry node
+
+   Finish locking of carry node. There are several ways in which new carry
+   node can be added into carry level and locked. Normal is through
+   lock_carry_node(), but also from find_{left|right}_neighbor(). This
+   function factors out common final part of all locking scenarios. It
+   supposes that @node -> lock_handle is lock handle for lock just taken and
+   fills ->real_node from this lock handle.
+
+*/
+int lock_carry_node_tail(carry_node * node /* node to complete locking of */ )
+{
+	assert("nikita-1052", node != NULL);
+	assert("nikita-1187", carry_real(node) != NULL);
+	assert("nikita-1188", !node->unlock);
+
+	node->unlock = 1;
+	/* Load node content into memory and install node plugin by
+	   looking at the node header.
+
+	   Most of the time this call is cheap because the node is
+	   already in memory.
+
+	   Corresponding zrelse() is in unlock_carry_node()
+	 */
+	return zload(carry_real(node));
+}
+
+/* lock carry node
+
+   "Resolve" node to real znode, lock it and mark as locked.
+   This requires recursive locking of znodes.
+
+   When operation is posted to the parent level, node it will be applied to is
+   not yet known. For example, when shifting data between two nodes,
+   delimiting has to be updated in parent or parents of nodes involved. But
+   their parents is not yet locked and, moreover said nodes can be reparented
+   by concurrent balancing.
+
+   To work around this, carry operation is applied to special "carry node"
+   rather than to the znode itself. Carry node consists of some "base" or
+   "reference" znode and flags indicating how to get to the target of carry
+   operation (->real_node field of carry_node) from base.
+
+*/
+int lock_carry_node(carry_level * level /* level @node is in */ ,
+		    carry_node * node /* node to lock */ )
+{
+	int result;
+	znode *reference_point;
+	lock_handle lh;
+	lock_handle tmp_lh;
+	reiser4_tree *tree;
+
+	assert("nikita-887", level != NULL);
+	assert("nikita-882", node != NULL);
+
+	result = 0;
+	reference_point = node->node;
+	init_lh(&lh);
+	init_lh(&tmp_lh);
+	if (node->left_before) {
+		/* handling of new nodes, allocated on the previous level:
+
+		   some carry ops were propably posted from the new node, but
+		   this node neither has parent pointer set, nor is
+		   connected. This will be done in ->create_hook() for
+		   internal item.
+
+		   No then less, parent of new node has to be locked. To do
+		   this, first go to the "left" in the carry order. This
+		   depends on the decision to always allocate new node on the
+		   right of existing one.
+
+		   Loop handles case when multiple nodes, all orphans, were
+		   inserted.
+
+		   Strictly speaking, taking tree lock is not necessary here,
+		   because all nodes scanned by loop in
+		   find_begetting_brother() are write-locked by this thread,
+		   and thus, their sibling linkage cannot change.
+
+		 */
+		tree = znode_get_tree(reference_point);
+		read_lock_tree(tree);
+		reference_point = find_begetting_brother(node, level)->node;
+		read_unlock_tree(tree);
+		assert("nikita-1186", reference_point != NULL);
+	}
+	if (node->parent && (result == 0)) {
+		result =
+		    reiser4_get_parent(&tmp_lh, reference_point,
+				       ZNODE_WRITE_LOCK);
+		if (result != 0) {
+			;	/* nothing */
+		} else if (znode_get_level(tmp_lh.node) == 0) {
+			assert("nikita-1347", znode_above_root(tmp_lh.node));
+			result = add_new_root(level, node, tmp_lh.node);
+			if (result == 0) {
+				reference_point = level->new_root;
+				move_lh(&lh, &node->lock_handle);
+			}
+		} else if ((level->new_root != NULL)
+			   && (level->new_root !=
+			       znode_parent_nolock(reference_point))) {
+			/* parent of node exists, but this level aready
+			   created different new root, so */
+			warning("nikita-1109",
+				/* it should be "radicis", but tradition is
+				   tradition.  do banshees read latin? */
+				"hodie natus est radici frater");
+			result = -EIO;
+		} else {
+			move_lh(&lh, &tmp_lh);
+			reference_point = lh.node;
+		}
+	}
+	if (node->left && (result == 0)) {
+		assert("nikita-1183", node->parent);
+		assert("nikita-883", reference_point != NULL);
+		result =
+		    reiser4_get_left_neighbor(&tmp_lh, reference_point,
+					      ZNODE_WRITE_LOCK,
+					      GN_CAN_USE_UPPER_LEVELS);
+		if (result == 0) {
+			done_lh(&lh);
+			move_lh(&lh, &tmp_lh);
+			reference_point = lh.node;
+		}
+	}
+	if (!node->parent && !node->left && !node->left_before) {
+		result =
+		    longterm_lock_znode(&lh, reference_point, ZNODE_WRITE_LOCK,
+					ZNODE_LOCK_HIPRI);
+	}
+	if (result == 0) {
+		move_lh(&node->lock_handle, &lh);
+		result = lock_carry_node_tail(node);
+	}
+	done_lh(&tmp_lh);
+	done_lh(&lh);
+	return result;
+}
+
+/* release a lock on &carry_node.
+
+   Release if necessary lock on @node. This opearion is pair of
+   lock_carry_node() and is idempotent: you can call it more than once on the
+   same node.
+
+*/
+static void
+unlock_carry_node(carry_level * level,
+		  carry_node * node /* node to be released */ ,
+		  int failure	/* 0 if node is unlocked due
+				 * to some error */ )
+{
+	znode *real_node;
+
+	assert("nikita-884", node != NULL);
+
+	real_node = carry_real(node);
+	/* pair to zload() in lock_carry_node_tail() */
+	zrelse(real_node);
+	if (node->unlock && (real_node != NULL)) {
+		assert("nikita-899", real_node == node->lock_handle.node);
+		longterm_unlock_znode(&node->lock_handle);
+	}
+	if (failure) {
+		if (node->deallocate && (real_node != NULL)) {
+			/* free node in bitmap
+
+			   Prepare node for removal. Last zput() will finish
+			   with it.
+			 */
+			ZF_SET(real_node, JNODE_HEARD_BANSHEE);
+		}
+		if (node->free) {
+			assert("nikita-2177",
+			       list_empty_careful(&node->lock_handle.locks_link));
+			assert("nikita-2112",
+			       list_empty_careful(&node->lock_handle.owners_link));
+			reiser4_pool_free(&level->pool->node_pool,
+					  &node->header);
+		}
+	}
+}
+
+/* fatal_carry_error() - all-catching error handling function
+
+   It is possible that carry faces unrecoverable error, like unability to
+   insert pointer at the internal level. Our simple solution is just panic in
+   this situation. More sophisticated things like attempt to remount
+   file-system as read-only can be implemented without much difficlties.
+
+   It is believed, that:
+
+   1. in stead of panicking, all current transactions can be aborted rolling
+   system back to the consistent state.
+
+Umm, if you simply panic without doing anything more at all, then all current
+transactions are aborted and the system is rolled back to a consistent state,
+by virtue of the design of the transactional mechanism. Well, wait, let's be
+precise.  If an internal node is corrupted on disk due to hardware failure,
+then there may be no consistent state that can be rolled back to, so instead
+we should say that it will rollback the transactions, which barring other
+factors means rolling back to a consistent state.
+
+# Nikita: there is a subtle difference between panic and aborting
+# transactions: machine doesn't reboot. Processes aren't killed. Processes
+# don't using reiser4 (not that we care about such processes), or using other
+# reiser4 mounts (about them we do care) will simply continue to run. With
+# some luck, even application using aborted file system can survive: it will
+# get some error, like EBADF, from each file descriptor on failed file system,
+# but applications that do care about tolerance will cope with this (squid
+# will).
+
+It would be a nice feature though to support rollback without rebooting
+followed by remount, but this can wait for later versions.
+
+   2. once isolated transactions will be implemented it will be possible to
+   roll back offending transaction.
+
+2. is additional code complexity of inconsistent value (it implies that a broken tree should be kept in operation), so we must think about
+it more before deciding if it should be done.  -Hans
+
+*/
+static void fatal_carry_error(carry_level * doing UNUSED_ARG	/* carry level
+								 * where
+								 * unrecoverable
+								 * error
+								 * occurred */ ,
+			      int ecode /* error code */ )
+{
+	assert("nikita-1230", doing != NULL);
+	assert("nikita-1231", ecode < 0);
+
+	reiser4_panic("nikita-1232", "Carry failed: %i", ecode);
+}
+
+/* add new root to the tree
+
+   This function itself only manages changes in carry structures and delegates
+   all hard work (allocation of znode for new root, changes of parent and
+   sibling pointers to the add_tree_root().
+
+   Locking: old tree root is locked by carry at this point. Fake znode is also
+   locked.
+
+*/
+static int add_new_root(carry_level * level	/* carry level in context of which
+						 * operation is performed */ ,
+			carry_node * node /* carry node for existing root */ ,
+			znode * fake	/* "fake" znode already locked by
+					 * us */ )
+{
+	int result;
+
+	assert("nikita-1104", level != NULL);
+	assert("nikita-1105", node != NULL);
+
+	assert("nikita-1403", znode_is_write_locked(node->node));
+	assert("nikita-1404", znode_is_write_locked(fake));
+
+	/* trying to create new root. */
+	/* @node is root and it's already locked by us. This
+	   means that nobody else can be trying to add/remove
+	   tree root right now.
+	 */
+	if (level->new_root == NULL)
+		level->new_root = add_tree_root(node->node, fake);
+	if (!IS_ERR(level->new_root)) {
+		assert("nikita-1210", znode_is_root(level->new_root));
+		node->deallocate = 1;
+		result =
+		    longterm_lock_znode(&node->lock_handle, level->new_root,
+					ZNODE_WRITE_LOCK, ZNODE_LOCK_LOPRI);
+		if (result == 0)
+			zput(level->new_root);
+	} else {
+		result = PTR_ERR(level->new_root);
+		level->new_root = NULL;
+	}
+	return result;
+}
+
+/* allocate new znode and add the operation that inserts the
+   pointer to it into the parent node into the todo level
+
+   Allocate new znode, add it into carry queue and post into @todo queue
+   request to add pointer to new node into its parent.
+
+   This is carry related routing that calls new_node() to allocate new
+   node.
+*/
+carry_node *add_new_znode(znode * brother	/* existing left neighbor of new
+						 * node */ ,
+			  carry_node * ref	/* carry node after which new
+						 * carry node is to be inserted
+						 * into queue. This affects
+						 * locking. */ ,
+			  carry_level * doing	/* carry queue where new node is
+						 * to be added */ ,
+			  carry_level * todo	/* carry queue where COP_INSERT
+						 * operation to add pointer to
+						 * new node will ne added */ )
+{
+	carry_node *fresh;
+	znode *new_znode;
+	carry_op *add_pointer;
+	carry_plugin_info info;
+
+	assert("nikita-1048", brother != NULL);
+	assert("nikita-1049", todo != NULL);
+
+	/* There is a lot of possible variations here: to what parent
+	   new node will be attached and where. For simplicity, always
+	   do the following:
+
+	   (1) new node and @brother will have the same parent.
+
+	   (2) new node is added on the right of @brother
+
+	 */
+
+	fresh = add_carry_skip(doing, ref ? POOLO_AFTER : POOLO_LAST, ref);
+	if (IS_ERR(fresh))
+		return fresh;
+
+	fresh->deallocate = 1;
+	fresh->free = 1;
+
+	new_znode = new_node(brother, znode_get_level(brother));
+	if (IS_ERR(new_znode))
+		/* @fresh will be deallocated automatically by error
+		   handling code in the caller. */
+		return (carry_node *) new_znode;
+
+	/* new_znode returned znode with x_count 1. Caller has to decrease
+	   it. make_space() does. */
+
+	ZF_SET(new_znode, JNODE_ORPHAN);
+	fresh->node = new_znode;
+
+	while (ZF_ISSET(carry_real(ref), JNODE_ORPHAN)) {
+		ref = carry_node_prev(ref);
+		assert("nikita-1606", !carry_node_end(doing, ref));
+	}
+
+	info.todo = todo;
+	info.doing = doing;
+	add_pointer = node_post_carry(&info, COP_INSERT, carry_real(ref), 1);
+	if (IS_ERR(add_pointer)) {
+		/* no need to deallocate @new_znode here: it will be
+		   deallocated during carry error handling. */
+		return (carry_node *) add_pointer;
+	}
+
+	add_pointer->u.insert.type = COPT_CHILD;
+	add_pointer->u.insert.child = fresh;
+	add_pointer->u.insert.brother = brother;
+	/* initially new node spawns empty key range */
+	write_lock_dk(znode_get_tree(brother));
+	znode_set_ld_key(new_znode,
+			 znode_set_rd_key(new_znode,
+					  znode_get_rd_key(brother)));
+	write_unlock_dk(znode_get_tree(brother));
+	return fresh;
+}
+
+/*
+ * Estimate how many pages of memory have to be reserved to complete execution
+ * of @level.
+ */
+static int carry_estimate_reserve(carry_level * level)
+{
+	carry_op *op;
+	carry_op *tmp_op;
+	int result;
+
+	result = 0;
+	for_all_ops(level, op, tmp_op)
+	    result += op_dispatch_table[op->op].estimate(op, level);
+	return result;
+}
+
+/* DEBUGGING FUNCTIONS.
+
+   Probably we also should leave them on even when
+   debugging is turned off to print dumps at errors.
+*/
+#if REISER4_DEBUG
+static int carry_level_invariant(carry_level * level, carry_queue_state state)
+{
+	carry_node *node;
+	carry_node *tmp_node;
+
+	if (level == NULL)
+		return 0;
+
+	if (level->track_type != 0 &&
+	    level->track_type != CARRY_TRACK_NODE &&
+	    level->track_type != CARRY_TRACK_CHANGE)
+		return 0;
+
+	/* check that nodes are in ascending order */
+	for_all_nodes(level, node, tmp_node) {
+		znode *left;
+		znode *right;
+
+		reiser4_key lkey;
+		reiser4_key rkey;
+
+		if (node != carry_node_front(level)) {
+			if (state == CARRY_TODO) {
+				right = node->node;
+				left = carry_node_prev(node)->node;
+			} else {
+				right = carry_real(node);
+				left = carry_real(carry_node_prev(node));
+			}
+			if (right == NULL || left == NULL)
+				continue;
+			if (node_is_empty(right) || node_is_empty(left))
+				continue;
+			if (!keyle(leftmost_key_in_node(left, &lkey),
+				   leftmost_key_in_node(right, &rkey))) {
+				warning("", "wrong key order");
+				return 0;
+			}
+		}
+	}
+	return 1;
+}
+#endif
+
+/* get symbolic name for boolean */
+static const char *tf(int boolean /* truth value */ )
+{
+	return boolean ? "t" : "f";
+}
+
+/* symbolic name for carry operation */
+static const char *carry_op_name(carry_opcode op /* carry opcode */ )
+{
+	switch (op) {
+	case COP_INSERT:
+		return "COP_INSERT";
+	case COP_DELETE:
+		return "COP_DELETE";
+	case COP_CUT:
+		return "COP_CUT";
+	case COP_PASTE:
+		return "COP_PASTE";
+	case COP_UPDATE:
+		return "COP_UPDATE";
+	case COP_EXTENT:
+		return "COP_EXTENT";
+	case COP_INSERT_FLOW:
+		return "COP_INSERT_FLOW";
+	default:{
+			/* not mt safe, but who cares? */
+			static char buf[20];
+
+			sprintf(buf, "unknown op: %x", op);
+			return buf;
+		}
+	}
+}
+
+/* dump information about carry node */
+static void print_carry(const char *prefix /* prefix to print */ ,
+			carry_node * node /* node to print */ )
+{
+	if (node == NULL) {
+		printk("%s: null\n", prefix);
+		return;
+	}
+	printk
+	    ("%s: %p parent: %s, left: %s, unlock: %s, free: %s, dealloc: %s\n",
+	     prefix, node, tf(node->parent), tf(node->left), tf(node->unlock),
+	     tf(node->free), tf(node->deallocate));
+}
+
+/* dump information about carry operation */
+static void print_op(const char *prefix /* prefix to print */ ,
+		     carry_op * op /* operation to print */ )
+{
+	if (op == NULL) {
+		printk("%s: null\n", prefix);
+		return;
+	}
+	printk("%s: %p carry_opcode: %s\n", prefix, op, carry_op_name(op->op));
+	print_carry("\tnode", op->node);
+	switch (op->op) {
+	case COP_INSERT:
+	case COP_PASTE:
+		print_coord("\tcoord",
+			    op->u.insert.d ? op->u.insert.d->coord : NULL, 0);
+		print_key("\tkey", op->u.insert.d ? op->u.insert.d->key : NULL);
+		print_carry("\tchild", op->u.insert.child);
+		break;
+	case COP_DELETE:
+		print_carry("\tchild", op->u.delete.child);
+		break;
+	case COP_CUT:
+		if (op->u.cut_or_kill.is_cut) {
+			print_coord("\tfrom",
+				    op->u.cut_or_kill.u.kill->params.from, 0);
+			print_coord("\tto", op->u.cut_or_kill.u.kill->params.to,
+				    0);
+		} else {
+			print_coord("\tfrom",
+				    op->u.cut_or_kill.u.cut->params.from, 0);
+			print_coord("\tto", op->u.cut_or_kill.u.cut->params.to,
+				    0);
+		}
+		break;
+	case COP_UPDATE:
+		print_carry("\tleft", op->u.update.left);
+		break;
+	default:
+		/* do nothing */
+		break;
+	}
+}
+
+/* dump information about all nodes and operations in a @level */
+static void print_level(const char *prefix /* prefix to print */ ,
+			carry_level * level /* level to print */ )
+{
+	carry_node *node;
+	carry_node *tmp_node;
+	carry_op *op;
+	carry_op *tmp_op;
+
+	if (level == NULL) {
+		printk("%s: null\n", prefix);
+		return;
+	}
+	printk("%s: %p, restartable: %s\n",
+	       prefix, level, tf(level->restartable));
+
+	for_all_nodes(level, node, tmp_node)
+	    print_carry("\tcarry node", node);
+	for_all_ops(level, op, tmp_op)
+	    print_op("\tcarry op", op);
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/carry.h newtree/fs/reiser4/carry.h
--- oldtree/fs/reiser4/carry.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/carry.h	2006-02-21 15:58:34.517899040 +0000
@@ -0,0 +1,442 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Functions and data types to "carry" tree modification(s) upward.
+   See fs/reiser4/carry.c for details. */
+
+#if !defined( __FS_REISER4_CARRY_H__ )
+#define __FS_REISER4_CARRY_H__
+
+#include "forward.h"
+#include "debug.h"
+#include "pool.h"
+#include "znode.h"
+
+#include <linux/types.h>
+
+/* &carry_node - "location" of carry node.
+
+   "location" of node that is involved or going to be involved into
+   carry process. Node where operation will be carried to on the
+   parent level cannot be recorded explicitly. Operation will be carried
+   usually to the parent of some node (where changes are performed at
+   the current level) or, to the left neighbor of its parent. But while
+   modifications are performed at the current level, parent may
+   change. So, we have to allow some indirection (or, positevly,
+   flexibility) in locating carry nodes.
+
+*/
+typedef struct carry_node {
+	/* pool linkage */
+	reiser4_pool_header header;
+
+	/* base node from which real_node is calculated. See
+	   fs/reiser4/carry.c:lock_carry_node(). */
+	znode *node;
+
+	/* how to get ->real_node */
+	/* to get ->real_node obtain parent of ->node */
+	__u32 parent:1;
+	/* to get ->real_node obtain left neighbor of parent of
+	   ->node */
+	__u32 left:1;
+	__u32 left_before:1;
+
+	/* locking */
+
+	/* this node was locked by carry process and should be
+	   unlocked when carry leaves a level */
+	__u32 unlock:1;
+
+	/* disk block for this node was allocated by carry process and
+	   should be deallocated when carry leaves a level */
+	__u32 deallocate:1;
+	/* this carry node was allocated by carry process and should be
+	   freed when carry leaves a level */
+	__u32 free:1;
+
+	/* type of lock we want to take on this node */
+	lock_handle lock_handle;
+} carry_node;
+
+/* &carry_opcode - elementary operations that can be carried upward
+
+   Operations that carry() can handle. This list is supposed to be
+   expanded.
+
+   Each carry operation (cop) is handled by appropriate function defined
+   in fs/reiser4/carry.c. For example COP_INSERT is handled by
+   fs/reiser4/carry.c:carry_insert() etc. These functions in turn
+   call plugins of nodes affected by operation to modify nodes' content
+   and to gather operations to be performed on the next level.
+
+*/
+typedef enum {
+	/* insert new item into node. */
+	COP_INSERT,
+	/* delete pointer from parent node */
+	COP_DELETE,
+	/* remove part of or whole node. */
+	COP_CUT,
+	/* increase size of item. */
+	COP_PASTE,
+	/* insert extent (that is sequence of unformatted nodes). */
+	COP_EXTENT,
+	/* update delimiting key in least common ancestor of two
+	   nodes. This is performed when items are moved between two
+	   nodes.
+	 */
+	COP_UPDATE,
+	/* insert flow */
+	COP_INSERT_FLOW,
+	COP_LAST_OP,
+} carry_opcode;
+
+#define CARRY_FLOW_NEW_NODES_LIMIT 20
+
+/* mode (or subtype) of COP_{INSERT|PASTE} operation. Specifies how target
+   item is determined. */
+typedef enum {
+	/* target item is one containing pointer to the ->child node */
+	COPT_CHILD,
+	/* target item is given explicitly by @coord */
+	COPT_ITEM_DATA,
+	/* target item is given by key */
+	COPT_KEY,
+	/* see insert_paste_common() for more comments on this. */
+	COPT_PASTE_RESTARTED,
+} cop_insert_pos_type;
+
+/* flags to cut and delete */
+typedef enum {
+	/* don't kill node even if it became completely empty as results of
+	 * cut. This is needed for eottl handling. See carry_extent() for
+	 * details. */
+	DELETE_RETAIN_EMPTY = (1 << 0)
+} cop_delete_flag;
+
+/*
+ * carry() implements "lock handle tracking" feature.
+ *
+ * Callers supply carry with node where to perform initial operation and lock
+ * handle on this node. Trying to optimize node utilization carry may actually
+ * move insertion point to different node. Callers expect that lock handle
+ * will rebe transferred to the new node also.
+ *
+ */
+typedef enum {
+	/* transfer lock handle along with insertion point */
+	CARRY_TRACK_CHANGE = 1,
+	/* acquire new lock handle to the node where insertion point is. This
+	 * is used when carry() client doesn't initially possess lock handle
+	 * on the insertion point node, for example, by extent insertion
+	 * code. See carry_extent(). */
+	CARRY_TRACK_NODE = 2
+} carry_track_type;
+
+/* data supplied to COP_{INSERT|PASTE} by callers */
+typedef struct carry_insert_data {
+	/* position where new item is to be inserted */
+	coord_t *coord;
+	/* new item description */
+	reiser4_item_data *data;
+	/* key of new item */
+	const reiser4_key *key;
+} carry_insert_data;
+
+/* cut and kill are similar, so carry_cut_data and carry_kill_data share the below structure of parameters */
+struct cut_kill_params {
+	/* coord where cut starts (inclusive) */
+	coord_t *from;
+	/* coord where cut stops (inclusive, this item/unit will also be
+	 * cut) */
+	coord_t *to;
+	/* starting key. This is necessary when item and unit pos don't
+	 * uniquely identify what portion or tree to remove. For example, this
+	 * indicates what portion of extent unit will be affected. */
+	const reiser4_key *from_key;
+	/* exclusive stop key */
+	const reiser4_key *to_key;
+	/* if this is not NULL, smallest actually removed key is stored
+	 * here. */
+	reiser4_key *smallest_removed;
+	/* kill_node_content()  is called for file truncate */
+	int truncate;
+};
+
+struct carry_cut_data {
+	struct cut_kill_params params;
+};
+
+struct carry_kill_data {
+	struct cut_kill_params params;
+	/* parameter to be passed to the ->kill_hook() method of item
+	 * plugin */
+	/*void *iplug_params; *//* FIXME: unused currently */
+	/* if not NULL---inode whose items are being removed. This is needed
+	 * for ->kill_hook() of extent item to update VM structures when
+	 * removing pages. */
+	struct inode *inode;
+	/* sibling list maintenance is complicated by existence of eottl. When
+	 * eottl whose left and right neighbors are formatted leaves is
+	 * removed, one has to connect said leaves in the sibling list. This
+	 * cannot be done when extent removal is just started as locking rules
+	 * require sibling list update to happen atomically with removal of
+	 * extent item. Therefore: 1. pointers to left and right neighbors
+	 * have to be passed down to the ->kill_hook() of extent item, and
+	 * 2. said neighbors have to be locked. */
+	lock_handle *left;
+	lock_handle *right;
+	/* flags modifying behavior of kill. Currently, it may have DELETE_RETAIN_EMPTY set. */
+	unsigned flags;
+	char *buf;
+};
+
+/* &carry_tree_op - operation to "carry" upward.
+
+   Description of an operation we want to "carry" to the upper level of
+   a tree: e.g, when we insert something and there is not enough space
+   we allocate a new node and "carry" the operation of inserting a
+   pointer to the new node to the upper level, on removal of empty node,
+   we carry up operation of removing appropriate entry from parent.
+
+   There are two types of carry ops: when adding or deleting node we
+   node at the parent level where appropriate modification has to be
+   performed is known in advance. When shifting items between nodes
+   (split, merge), delimiting key should be changed in the least common
+   parent of the nodes involved that is not known in advance.
+
+   For the operations of the first type we store in &carry_op pointer to
+   the &carry_node at the parent level. For the operation of the second
+   type we store &carry_node or parents of the left and right nodes
+   modified and keep track of them upward until they coincide.
+
+*/
+typedef struct carry_op {
+	/* pool linkage */
+	reiser4_pool_header header;
+	carry_opcode op;
+	/* node on which operation is to be performed:
+
+	   for insert, paste: node where new item is to be inserted
+
+	   for delete: node where pointer is to be deleted
+
+	   for cut: node to cut from
+
+	   for update: node where delimiting key is to be modified
+
+	   for modify: parent of modified node
+
+	 */
+	carry_node *node;
+	union {
+		struct {
+			/* (sub-)type of insertion/paste. Taken from
+			   cop_insert_pos_type. */
+			__u8 type;
+			/* various operation flags. Taken from
+			   cop_insert_flag. */
+			__u8 flags;
+			carry_insert_data *d;
+			carry_node *child;
+			znode *brother;
+		} insert, paste, extent;
+
+		struct {
+			int is_cut;
+			union {
+				carry_kill_data *kill;
+				carry_cut_data *cut;
+			} u;
+		} cut_or_kill;
+
+		struct {
+			carry_node *left;
+		} update;
+		struct {
+			/* changed child */
+			carry_node *child;
+			/* bitmask of changes. See &cop_modify_flag */
+			__u32 flag;
+		} modify;
+		struct {
+			/* flags to deletion operation. Are taken from
+			   cop_delete_flag */
+			__u32 flags;
+			/* child to delete from parent. If this is
+			   NULL, delete op->node.  */
+			carry_node *child;
+		} delete;
+		struct {
+			/* various operation flags. Taken from
+			   cop_insert_flag. */
+			__u32 flags;
+			flow_t *flow;
+			coord_t *insert_point;
+			reiser4_item_data *data;
+			/* flow insertion is limited by number of new blocks
+			   added in that operation which do not get any data
+			   but part of flow. This limit is set by macro
+			   CARRY_FLOW_NEW_NODES_LIMIT. This field stores number
+			   of nodes added already during one carry_flow */
+			int new_nodes;
+		} insert_flow;
+	} u;
+} carry_op;
+
+/* &carry_op_pool - preallocated pool of carry operations, and nodes */
+typedef struct carry_pool {
+	carry_op op[CARRIES_POOL_SIZE];
+	reiser4_pool op_pool;
+	carry_node node[NODES_LOCKED_POOL_SIZE];
+	reiser4_pool node_pool;
+} carry_pool;
+
+/* &carry_tree_level - carry process on given level
+
+   Description of balancing process on the given level.
+
+   No need for locking here, as carry_tree_level is essentially per
+   thread thing (for now).
+
+*/
+struct carry_level {
+	/* this level may be restarted */
+	__u32 restartable:1;
+	/* list of carry nodes on this level, ordered by key order */
+	struct list_head nodes;
+	struct list_head ops;
+	/* pool where new objects are allocated from */
+	carry_pool *pool;
+	int ops_num;
+	int nodes_num;
+	/* new root created on this level, if any */
+	znode *new_root;
+	/* This is set by caller (insert_by_key(), resize_item(), etc.) when
+	   they want ->tracked to automagically wander to the node where
+	   insertion point moved after insert or paste.
+	 */
+	carry_track_type track_type;
+	/* lock handle supplied by user that we are tracking. See
+	   above. */
+	lock_handle *tracked;
+};
+
+/* information carry passes to plugin methods that may add new operations to
+   the @todo queue  */
+struct carry_plugin_info {
+	carry_level *doing;
+	carry_level *todo;
+};
+
+int carry(carry_level * doing, carry_level * done);
+
+carry_node *add_carry(carry_level * level, pool_ordering order,
+		      carry_node * reference);
+carry_node *add_carry_skip(carry_level * level, pool_ordering order,
+			   carry_node * reference);
+
+extern carry_node *insert_carry_node(carry_level * doing,
+				     carry_level * todo, const znode * node);
+
+extern carry_pool *init_carry_pool(int);
+extern void done_carry_pool(carry_pool * pool);
+
+extern void init_carry_level(carry_level * level, carry_pool * pool);
+
+extern carry_op *post_carry(carry_level * level, carry_opcode op, znode * node,
+			    int apply_to_parent);
+extern carry_op *node_post_carry(carry_plugin_info * info, carry_opcode op,
+				 znode * node, int apply_to_parent_p);
+
+carry_node *add_new_znode(znode * brother, carry_node * reference,
+			  carry_level * doing, carry_level * todo);
+
+carry_node *find_carry_node(carry_level * level, const znode * node);
+
+extern znode *carry_real(const carry_node * node);
+
+/* helper macros to iterate over carry queues */
+
+#define carry_node_next( node )					\
+	list_entry((node)->header.level_linkage.next, carry_node,	\
+		   header.level_linkage)
+
+#define carry_node_prev( node )					\
+	list_entry((node)->header.level_linkage.prev, carry_node,	\
+		   header.level_linkage)
+
+#define carry_node_front( level )						\
+	list_entry((level)->nodes.next, carry_node, header.level_linkage)
+
+#define carry_node_back( level )						\
+	list_entry((level)->nodes.prev, carry_node, header.level_linkage)
+
+#define carry_node_end( level, node )				\
+	(&(level)->nodes == &(node)->header.level_linkage)
+
+/* macro to iterate over all operations in a @level */
+#define for_all_ops( level /* carry level (of type carry_level *) */,			\
+		     op    /* pointer to carry operation, modified by loop (of 		\
+			    * type carry_op *) */,					\
+		     tmp   /* pointer to carry operation (of type carry_op *), 		\
+			    * used to make iterator stable in the face of 		\
+			    * deletions from the level */ )				\
+for (op = list_entry(level->ops.next, carry_op, header.level_linkage),			\
+     tmp = list_entry(op->header.level_linkage.next, carry_op, header.level_linkage); 	\
+     &op->header.level_linkage != &level->ops;						\
+     op = tmp,										\
+     tmp = list_entry(op->header.level_linkage.next, carry_op, header.level_linkage))
+
+#if 0
+for( op = ( carry_op * ) pool_level_list_front( &level -> ops ),		\
+     tmp = ( carry_op * ) pool_level_list_next( &op -> header ) ;		\
+     ! pool_level_list_end( &level -> ops, &op -> header ) ;			\
+     op = tmp, tmp = ( carry_op * ) pool_level_list_next( &op -> header ) )
+#endif
+
+/* macro to iterate over all nodes in a @level */						\
+#define for_all_nodes( level /* carry level (of type carry_level *) */,				\
+		       node  /* pointer to carry node, modified by loop (of 			\
+			      * type carry_node *) */,						\
+		       tmp   /* pointer to carry node (of type carry_node *), 			\
+			      * used to make iterator stable in the face of * 			\
+			      * deletions from the level */ )					\
+for (node = list_entry(level->nodes.next, carry_node, header.level_linkage),			\
+     tmp = list_entry(node->header.level_linkage.next, carry_node, header.level_linkage); 	\
+     &node->header.level_linkage != &level->nodes;						\
+     node = tmp, 										\
+     tmp = list_entry(node->header.level_linkage.next, carry_node, header.level_linkage))
+
+#if 0
+for( node = carry_node_front( level ),						\
+     tmp = carry_node_next( node ) ; ! carry_node_end( level, node ) ;		\
+     node = tmp, tmp = carry_node_next( node ) )
+#endif
+
+/* macro to iterate over all nodes in a @level in reverse order
+
+   This is used, because nodes are unlocked in reversed order of locking */
+#define for_all_nodes_back( level /* carry level (of type carry_level *) */,	\
+		            node  /* pointer to carry node, modified by loop	\
+				   * (of type carry_node *) */,			\
+		            tmp   /* pointer to carry node (of type carry_node	\
+				   * *), used to make iterator stable in the	\
+				   * face of deletions from the level */ )	\
+for( node = carry_node_back( level ),		\
+     tmp = carry_node_prev( node ) ; ! carry_node_end( level, node ) ;		\
+     node = tmp, tmp = carry_node_prev( node ) )
+
+/* __FS_REISER4_CARRY_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/carry_ops.c newtree/fs/reiser4/carry_ops.c
--- oldtree/fs/reiser4/carry_ops.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/carry_ops.c	2006-02-21 15:58:34.963831248 +0000
@@ -0,0 +1,2103 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* implementation of carry operations */
+
+#include "forward.h"
+#include "debug.h"
+#include "key.h"
+#include "coord.h"
+#include "plugin/item/item.h"
+#include "plugin/node/node.h"
+#include "jnode.h"
+#include "znode.h"
+#include "block_alloc.h"
+#include "tree_walk.h"
+#include "pool.h"
+#include "tree_mod.h"
+#include "carry.h"
+#include "carry_ops.h"
+#include "tree.h"
+#include "super.h"
+#include "reiser4.h"
+
+#include <linux/types.h>
+#include <linux/err.h>
+
+static int carry_shift_data(sideof side, coord_t * insert_coord, znode * node,
+			    carry_level * doing, carry_level * todo,
+			    unsigned int including_insert_coord_p);
+
+extern int lock_carry_node(carry_level * level, carry_node * node);
+extern int lock_carry_node_tail(carry_node * node);
+
+/* find left neighbor of a carry node
+
+   Look for left neighbor of @node and add it to the @doing queue. See
+   comments in the body.
+
+*/
+static carry_node *find_left_neighbor(carry_op * op	/* node to find left
+							 * neighbor of */ ,
+				      carry_level * doing /* level to scan */ )
+{
+	int result;
+	carry_node *node;
+	carry_node *left;
+	int flags;
+	reiser4_tree *tree;
+
+	node = op->node;
+
+	tree = current_tree;
+	read_lock_tree(tree);
+	/* first, check whether left neighbor is already in a @doing queue */
+	if (carry_real(node)->left != NULL) {
+		/* NOTE: there is locking subtlety here. Look into
+		 * find_right_neighbor() for more info */
+		if (find_carry_node(doing, carry_real(node)->left) != NULL) {
+			read_unlock_tree(tree);
+			left = node;
+			do {
+				left = list_entry(left->header.level_linkage.prev,
+						  carry_node, header.level_linkage);
+				assert("nikita-3408", !carry_node_end(doing,
+								      left));
+			} while (carry_real(left) == carry_real(node));
+			return left;
+		}
+	}
+	read_unlock_tree(tree);
+
+	left = add_carry_skip(doing, POOLO_BEFORE, node);
+	if (IS_ERR(left))
+		return left;
+
+	left->node = node->node;
+	left->free = 1;
+
+	flags = GN_TRY_LOCK;
+	if (!op->u.insert.flags & COPI_LOAD_LEFT)
+		flags |= GN_NO_ALLOC;
+
+	/* then, feeling lucky, peek left neighbor in the cache. */
+	result = reiser4_get_left_neighbor(&left->lock_handle, carry_real(node),
+					   ZNODE_WRITE_LOCK, flags);
+	if (result == 0) {
+		/* ok, node found and locked. */
+		result = lock_carry_node_tail(left);
+		if (result != 0)
+			left = ERR_PTR(result);
+	} else if (result == -E_NO_NEIGHBOR || result == -ENOENT) {
+		/* node is leftmost node in a tree, or neighbor wasn't in
+		   cache, or there is an extent on the left. */
+		reiser4_pool_free(&doing->pool->node_pool, &left->header);
+		left = NULL;
+	} else if (doing->restartable) {
+		/* if left neighbor is locked, and level is restartable, add
+		   new node to @doing and restart. */
+		assert("nikita-913", node->parent != 0);
+		assert("nikita-914", node->node != NULL);
+		left->left = 1;
+		left->free = 0;
+		left = ERR_PTR(-E_REPEAT);
+	} else {
+		/* left neighbor is locked, level cannot be restarted. Just
+		   ignore left neighbor. */
+		reiser4_pool_free(&doing->pool->node_pool, &left->header);
+		left = NULL;
+	}
+	return left;
+}
+
+/* find right neighbor of a carry node
+
+   Look for right neighbor of @node and add it to the @doing queue. See
+   comments in the body.
+
+*/
+static carry_node *find_right_neighbor(carry_op * op	/* node to find right
+							 * neighbor of */ ,
+				       carry_level * doing /* level to scan */ )
+{
+	int result;
+	carry_node *node;
+	carry_node *right;
+	lock_handle lh;
+	int flags;
+	reiser4_tree *tree;
+
+	init_lh(&lh);
+
+	node = op->node;
+
+	tree = current_tree;
+	read_lock_tree(tree);
+	/* first, check whether right neighbor is already in a @doing queue */
+	if (carry_real(node)->right != NULL) {
+		/*
+		 * Tree lock is taken here anyway, because, even if _outcome_
+		 * of (find_carry_node() != NULL) doesn't depends on
+		 * concurrent updates to ->right, find_carry_node() cannot
+		 * work with second argument NULL. Hence, following comment is
+		 * of historic importance only.
+		 *
+		 * Subtle:
+		 *
+		 * Q: why don't we need tree lock here, looking for the right
+		 * neighbor?
+		 *
+		 * A: even if value of node->real_node->right were changed
+		 * during find_carry_node() execution, outcome of execution
+		 * wouldn't change, because (in short) other thread cannot add
+		 * elements to the @doing, and if node->real_node->right
+		 * already was in @doing, value of node->real_node->right
+		 * couldn't change, because node cannot be inserted between
+		 * locked neighbors.
+		 */
+		if (find_carry_node(doing, carry_real(node)->right) != NULL) {
+			read_unlock_tree(tree);
+			/*
+			 * What we are doing here (this is also applicable to
+			 * the find_left_neighbor()).
+			 *
+			 * tree_walk.c code requires that insertion of a
+			 * pointer to a child, modification of parent pointer
+			 * in the child, and insertion of the child into
+			 * sibling list are atomic (see
+			 * plugin/item/internal.c:create_hook_internal()).
+			 *
+			 * carry allocates new node long before pointer to it
+			 * is inserted into parent and, actually, long before
+			 * parent is even known. Such allocated-but-orphaned
+			 * nodes are only trackable through carry level lists.
+			 *
+			 * Situation that is handled here is following: @node
+			 * has valid ->right pointer, but there is
+			 * allocated-but-orphaned node in the carry queue that
+			 * is logically between @node and @node->right. Here
+			 * we are searching for it. Critical point is that
+			 * this is only possible if @node->right is also in
+			 * the carry queue (this is checked above), because
+			 * this is the only way new orphaned node could be
+			 * inserted between them (before inserting new node,
+			 * make_space() first tries to shift to the right, so,
+			 * right neighbor will be locked and queued).
+			 *
+			 */
+			right = node;
+			do {
+				right = list_entry(right->header.level_linkage.next,
+						   carry_node, header.level_linkage);
+				assert("nikita-3408", !carry_node_end(doing,
+								      right));
+			} while (carry_real(right) == carry_real(node));
+			return right;
+		}
+	}
+	read_unlock_tree(tree);
+
+	flags = GN_CAN_USE_UPPER_LEVELS;
+	if (!op->u.insert.flags & COPI_LOAD_RIGHT)
+		flags = GN_NO_ALLOC;
+
+	/* then, try to lock right neighbor */
+	init_lh(&lh);
+	result = reiser4_get_right_neighbor(&lh, carry_real(node),
+					    ZNODE_WRITE_LOCK, flags);
+	if (result == 0) {
+		/* ok, node found and locked. */
+		right = add_carry_skip(doing, POOLO_AFTER, node);
+		if (!IS_ERR(right)) {
+			right->node = lh.node;
+			move_lh(&right->lock_handle, &lh);
+			right->free = 1;
+			result = lock_carry_node_tail(right);
+			if (result != 0)
+				right = ERR_PTR(result);
+		}
+	} else if ((result == -E_NO_NEIGHBOR) || (result == -ENOENT)) {
+		/* node is rightmost node in a tree, or neighbor wasn't in
+		   cache, or there is an extent on the right. */
+		right = NULL;
+	} else
+		right = ERR_PTR(result);
+	done_lh(&lh);
+	return right;
+}
+
+/* how much free space in a @node is needed for @op
+
+   How much space in @node is required for completion of @op, where @op is
+   insert or paste operation.
+*/
+static unsigned int space_needed_for_op(znode * node	/* znode data are
+							 * inserted or
+							 * pasted in */ ,
+					carry_op * op	/* carry
+							   operation */ )
+{
+	assert("nikita-919", op != NULL);
+
+	switch (op->op) {
+	default:
+		impossible("nikita-1701", "Wrong opcode");
+	case COP_INSERT:
+		return space_needed(node, NULL, op->u.insert.d->data, 1);
+	case COP_PASTE:
+		return space_needed(node, op->u.insert.d->coord,
+				    op->u.insert.d->data, 0);
+	}
+}
+
+/* how much space in @node is required to insert or paste @data at
+   @coord. */
+unsigned int space_needed(const znode * node	/* node data are inserted or
+						 * pasted in */ ,
+			  const coord_t * coord	/* coord where data are
+						 * inserted or pasted
+						 * at */ ,
+			  const reiser4_item_data * data	/* data to insert or
+								 * paste */ ,
+			  int insertion /* non-0 is inserting, 0---paste */ )
+{
+	int result;
+	item_plugin *iplug;
+
+	assert("nikita-917", node != NULL);
+	assert("nikita-918", node_plugin_by_node(node) != NULL);
+	assert("vs-230", !insertion || (coord == NULL));
+
+	result = 0;
+	iplug = data->iplug;
+	if (iplug->b.estimate != NULL) {
+		/* ask item plugin how much space is needed to insert this
+		   item */
+		result += iplug->b.estimate(insertion ? NULL : coord, data);
+	} else {
+		/* reasonable default */
+		result += data->length;
+	}
+	if (insertion) {
+		node_plugin *nplug;
+
+		nplug = node->nplug;
+		/* and add node overhead */
+		if (nplug->item_overhead != NULL) {
+			result += nplug->item_overhead(node, NULL);
+		}
+	}
+	return result;
+}
+
+/* find &coord in parent where pointer to new child is to be stored. */
+static int find_new_child_coord(carry_op * op	/* COP_INSERT carry operation to
+						 * insert pointer to new
+						 * child */ )
+{
+	int result;
+	znode *node;
+	znode *child;
+
+	assert("nikita-941", op != NULL);
+	assert("nikita-942", op->op == COP_INSERT);
+
+	node = carry_real(op->node);
+	assert("nikita-943", node != NULL);
+	assert("nikita-944", node_plugin_by_node(node) != NULL);
+
+	child = carry_real(op->u.insert.child);
+	result =
+	    find_new_child_ptr(node, child, op->u.insert.brother,
+			       op->u.insert.d->coord);
+
+	build_child_ptr_data(child, op->u.insert.d->data);
+	return result;
+}
+
+/* additional amount of free space in @node required to complete @op */
+static int free_space_shortage(znode * node /* node to check */ ,
+			       carry_op * op /* operation being performed */ )
+{
+	assert("nikita-1061", node != NULL);
+	assert("nikita-1062", op != NULL);
+
+	switch (op->op) {
+	default:
+		impossible("nikita-1702", "Wrong opcode");
+	case COP_INSERT:
+	case COP_PASTE:
+		return space_needed_for_op(node, op) - znode_free_space(node);
+	case COP_EXTENT:
+		/* when inserting extent shift data around until insertion
+		   point is utmost in the node. */
+		if (coord_wrt(op->u.insert.d->coord) == COORD_INSIDE)
+			return +1;
+		else
+			return -1;
+	}
+}
+
+/* helper function: update node pointer in operation after insertion
+   point was probably shifted into @target. */
+static znode *sync_op(carry_op * op, carry_node * target)
+{
+	znode *insertion_node;
+
+	/* reget node from coord: shift might move insertion coord to
+	   the neighbor */
+	insertion_node = op->u.insert.d->coord->node;
+	/* if insertion point was actually moved into new node,
+	   update carry node pointer in operation. */
+	if (insertion_node != carry_real(op->node)) {
+		op->node = target;
+		assert("nikita-2540", carry_real(target) == insertion_node);
+	}
+	assert("nikita-2541",
+	       carry_real(op->node) == op->u.insert.d->coord->node);
+	return insertion_node;
+}
+
+/*
+ * complete make_space() call: update tracked lock handle if necessary. See
+ * comments for fs/reiser4/carry.h:carry_track_type
+ */
+static int
+make_space_tail(carry_op * op, carry_level * doing, znode * orig_node)
+{
+	int result;
+	carry_track_type tracking;
+	znode *node;
+
+	tracking = doing->track_type;
+	node = op->u.insert.d->coord->node;
+
+	if (tracking == CARRY_TRACK_NODE ||
+	    (tracking == CARRY_TRACK_CHANGE && node != orig_node)) {
+		/* inserting or pasting into node different from
+		   original. Update lock handle supplied by caller. */
+		assert("nikita-1417", doing->tracked != NULL);
+		done_lh(doing->tracked);
+		init_lh(doing->tracked);
+		result = longterm_lock_znode(doing->tracked, node,
+					     ZNODE_WRITE_LOCK,
+					     ZNODE_LOCK_HIPRI);
+	} else
+		result = 0;
+	return result;
+}
+
+/* This is insertion policy function. It shifts data to the left and right
+   neighbors of insertion coord and allocates new nodes until there is enough
+   free space to complete @op.
+
+   See comments in the body.
+
+   Assumes that the node format favors insertions at the right end of the node
+   as node40 does.
+
+   See carry_flow() on detail about flow insertion
+*/
+static int make_space(carry_op * op /* carry operation, insert or paste */ ,
+		      carry_level * doing /* current carry queue */ ,
+		      carry_level * todo /* carry queue on the parent level */ )
+{
+	znode *node;
+	int result;
+	int not_enough_space;
+	int blk_alloc;
+	znode *orig_node;
+	__u32 flags;
+
+	coord_t *coord;
+
+	assert("nikita-890", op != NULL);
+	assert("nikita-891", todo != NULL);
+	assert("nikita-892",
+	       op->op == COP_INSERT ||
+	       op->op == COP_PASTE || op->op == COP_EXTENT);
+	assert("nikita-1607",
+	       carry_real(op->node) == op->u.insert.d->coord->node);
+
+	flags = op->u.insert.flags;
+
+	/* NOTE check that new node can only be allocated after checking left
+	 * and right neighbors. This is necessary for proper work of
+	 * find_{left,right}_neighbor(). */
+	assert("nikita-3410", ergo(flags & COPI_DONT_ALLOCATE,
+				   flags & COPI_DONT_SHIFT_LEFT));
+	assert("nikita-3411", ergo(flags & COPI_DONT_ALLOCATE,
+				   flags & COPI_DONT_SHIFT_RIGHT));
+
+	coord = op->u.insert.d->coord;
+	orig_node = node = coord->node;
+
+	assert("nikita-908", node != NULL);
+	assert("nikita-909", node_plugin_by_node(node) != NULL);
+
+	result = 0;
+	/* If there is not enough space in a node, try to shift something to
+	   the left neighbor. This is a bit tricky, as locking to the left is
+	   low priority. This is handled by restart logic in carry().
+	 */
+	not_enough_space = free_space_shortage(node, op);
+	if (not_enough_space <= 0)
+		/* it is possible that carry was called when there actually
+		   was enough space in the node. For example, when inserting
+		   leftmost item so that delimiting keys have to be updated.
+		 */
+		return make_space_tail(op, doing, orig_node);
+	if (!(flags & COPI_DONT_SHIFT_LEFT)) {
+		carry_node *left;
+		/* make note in statistics of an attempt to move
+		   something into the left neighbor */
+		left = find_left_neighbor(op, doing);
+		if (unlikely(IS_ERR(left))) {
+			if (PTR_ERR(left) == -E_REPEAT)
+				return -E_REPEAT;
+			else {
+				/* some error other than restart request
+				   occurred. This shouldn't happen. Issue a
+				   warning and continue as if left neighbor
+				   weren't existing.
+				 */
+				warning("nikita-924",
+					"Error accessing left neighbor: %li",
+					PTR_ERR(left));
+			}
+		} else if (left != NULL) {
+
+			/* shift everything possible on the left of and
+			   including insertion coord into the left neighbor */
+			result = carry_shift_data(LEFT_SIDE, coord,
+						  carry_real(left), doing, todo,
+						  flags & COPI_GO_LEFT);
+
+			/* reget node from coord: shift_left() might move
+			   insertion coord to the left neighbor */
+			node = sync_op(op, left);
+
+			not_enough_space = free_space_shortage(node, op);
+			/* There is not enough free space in @node, but
+			   may be, there is enough free space in
+			   @left. Various balancing decisions are valid here.
+			   The same for the shifiting to the right.
+			 */
+		}
+	}
+	/* If there still is not enough space, shift to the right */
+	if (not_enough_space > 0 && !(flags & COPI_DONT_SHIFT_RIGHT)) {
+		carry_node *right;
+
+		right = find_right_neighbor(op, doing);
+		if (IS_ERR(right)) {
+			warning("nikita-1065",
+				"Error accessing right neighbor: %li",
+				PTR_ERR(right));
+		} else if (right != NULL) {
+			/* node containing insertion point, and its right
+			   neighbor node are write locked by now.
+
+			   shift everything possible on the right of but
+			   excluding insertion coord into the right neighbor
+			 */
+			result = carry_shift_data(RIGHT_SIDE, coord,
+						  carry_real(right),
+						  doing, todo,
+						  flags & COPI_GO_RIGHT);
+			/* reget node from coord: shift_right() might move
+			   insertion coord to the right neighbor */
+			node = sync_op(op, right);
+			not_enough_space = free_space_shortage(node, op);
+		}
+	}
+	/* If there is still not enough space, allocate new node(s).
+
+	   We try to allocate new blocks if COPI_DONT_ALLOCATE is not set in
+	   the carry operation flags (currently this is needed during flush
+	   only).
+	 */
+	for (blk_alloc = 0;
+	     not_enough_space > 0 && result == 0 && blk_alloc < 2 &&
+	     !(flags & COPI_DONT_ALLOCATE); ++blk_alloc) {
+		carry_node *fresh;	/* new node we are allocating */
+		coord_t coord_shadow;	/* remembered insertion point before
+					 * shifting data into new node */
+		carry_node *node_shadow;	/* remembered insertion node before
+						 * shifting */
+		unsigned int gointo;	/* whether insertion point should move
+					 * into newly allocated node */
+
+		/* allocate new node on the right of @node. Znode and disk
+		   fake block number for new node are allocated.
+
+		   add_new_znode() posts carry operation COP_INSERT with
+		   COPT_CHILD option to the parent level to add
+		   pointer to newly created node to its parent.
+
+		   Subtle point: if several new nodes are required to complete
+		   insertion operation at this level, they will be inserted
+		   into their parents in the order of creation, which means
+		   that @node will be valid "cookie" at the time of insertion.
+
+		 */
+		fresh = add_new_znode(node, op->node, doing, todo);
+		if (IS_ERR(fresh))
+			return PTR_ERR(fresh);
+
+		/* Try to shift into new node. */
+		result = lock_carry_node(doing, fresh);
+		zput(carry_real(fresh));
+		if (result != 0) {
+			warning("nikita-947",
+				"Cannot lock new node: %i", result);
+			return result;
+		}
+
+		/* both nodes are write locked by now.
+
+		   shift everything possible on the right of and
+		   including insertion coord into the right neighbor.
+		 */
+		coord_dup(&coord_shadow, op->u.insert.d->coord);
+		node_shadow = op->node;
+		/* move insertion point into newly created node if:
+
+		   . insertion point is rightmost in the source node, or
+		   . this is not the first node we are allocating in a row.
+		 */
+		gointo =
+		    (blk_alloc > 0) ||
+		    coord_is_after_rightmost(op->u.insert.d->coord);
+
+		result = carry_shift_data(RIGHT_SIDE, coord, carry_real(fresh),
+					  doing, todo, gointo);
+		/* if insertion point was actually moved into new node,
+		   update carry node pointer in operation. */
+		node = sync_op(op, fresh);
+		not_enough_space = free_space_shortage(node, op);
+		if ((not_enough_space > 0) && (node != coord_shadow.node)) {
+			/* there is not enough free in new node. Shift
+			   insertion point back to the @shadow_node so that
+			   next new node would be inserted between
+			   @shadow_node and @fresh.
+			 */
+			coord_normalize(&coord_shadow);
+			coord_dup(coord, &coord_shadow);
+			node = coord->node;
+			op->node = node_shadow;
+			if (1 || (flags & COPI_STEP_BACK)) {
+				/* still not enough space?! Maybe there is
+				   enough space in the source node (i.e., node
+				   data are moved from) now.
+				 */
+				not_enough_space =
+				    free_space_shortage(node, op);
+			}
+		}
+	}
+	if (not_enough_space > 0) {
+		if (!(flags & COPI_DONT_ALLOCATE))
+			warning("nikita-948", "Cannot insert new item");
+		result = -E_NODE_FULL;
+	}
+	assert("nikita-1622", ergo(result == 0,
+				   carry_real(op->node) == coord->node));
+	assert("nikita-2616", coord == op->u.insert.d->coord);
+	if (result == 0)
+		result = make_space_tail(op, doing, orig_node);
+	return result;
+}
+
+/* insert_paste_common() - common part of insert and paste operations
+
+   This function performs common part of COP_INSERT and COP_PASTE.
+
+   There are two ways in which insertion/paste can be requested:
+
+    . by directly supplying reiser4_item_data. In this case, op ->
+    u.insert.type is set to COPT_ITEM_DATA.
+
+    . by supplying child pointer to which is to inserted into parent. In this
+    case op -> u.insert.type == COPT_CHILD.
+
+    . by supplying key of new item/unit. This is currently only used during
+    extent insertion
+
+   This is required, because when new node is allocated we don't know at what
+   position pointer to it is to be stored in the parent. Actually, we don't
+   even know what its parent will be, because parent can be re-balanced
+   concurrently and new node re-parented, and because parent can be full and
+   pointer to the new node will go into some other node.
+
+   insert_paste_common() resolves pointer to child node into position in the
+   parent by calling find_new_child_coord(), that fills
+   reiser4_item_data. After this, insertion/paste proceeds uniformly.
+
+   Another complication is with finding free space during pasting. It may
+   happen that while shifting items to the neighbors and newly allocated
+   nodes, insertion coord can no longer be in the item we wanted to paste
+   into. At this point, paste becomes (morphs) into insert. Moreover free
+   space analysis has to be repeated, because amount of space required for
+   insertion is different from that of paste (item header overhead, etc).
+
+   This function "unifies" different insertion modes (by resolving child
+   pointer or key into insertion coord), and then calls make_space() to free
+   enough space in the node by shifting data to the left and right and by
+   allocating new nodes if necessary. Carry operation knows amount of space
+   required for its completion. After enough free space is obtained, caller of
+   this function (carry_{insert,paste,etc.}) performs actual insertion/paste
+   by calling item plugin method.
+
+*/
+static int insert_paste_common(carry_op * op	/* carry operation being
+						 * performed */ ,
+			       carry_level * doing /* current carry level */ ,
+			       carry_level * todo /* next carry level */ ,
+			       carry_insert_data * cdata	/* pointer to
+								 * cdata */ ,
+			       coord_t * coord /* insertion/paste coord */ ,
+			       reiser4_item_data * data	/* data to be
+							 * inserted/pasted */ )
+{
+	assert("nikita-981", op != NULL);
+	assert("nikita-980", todo != NULL);
+	assert("nikita-979", (op->op == COP_INSERT) || (op->op == COP_PASTE)
+	       || (op->op == COP_EXTENT));
+
+	if (op->u.insert.type == COPT_PASTE_RESTARTED) {
+		/* nothing to do. Fall through to make_space(). */
+		;
+	} else if (op->u.insert.type == COPT_KEY) {
+		node_search_result intra_node;
+		znode *node;
+		/* Problem with doing batching at the lowest level, is that
+		   operations here are given by coords where modification is
+		   to be performed, and one modification can invalidate coords
+		   of all following operations.
+
+		   So, we are implementing yet another type for operation that
+		   will use (the only) "locator" stable across shifting of
+		   data between nodes, etc.: key (COPT_KEY).
+
+		   This clause resolves key to the coord in the node.
+
+		   But node can change also. Probably some pieces have to be
+		   added to the lock_carry_node(), to lock node by its key.
+
+		 */
+		/* NOTE-NIKITA Lookup bias is fixed to FIND_EXACT. Complain
+		   if you need something else. */
+		op->u.insert.d->coord = coord;
+		node = carry_real(op->node);
+		intra_node = node_plugin_by_node(node)->lookup
+		    (node, op->u.insert.d->key, FIND_EXACT,
+		     op->u.insert.d->coord);
+		if ((intra_node != NS_FOUND) && (intra_node != NS_NOT_FOUND)) {
+			warning("nikita-1715", "Intra node lookup failure: %i",
+				intra_node);
+			return intra_node;
+		}
+	} else if (op->u.insert.type == COPT_CHILD) {
+		/* if we are asked to insert pointer to the child into
+		   internal node, first convert pointer to the child into
+		   coord within parent node.
+		 */
+		znode *child;
+		int result;
+
+		op->u.insert.d = cdata;
+		op->u.insert.d->coord = coord;
+		op->u.insert.d->data = data;
+		op->u.insert.d->coord->node = carry_real(op->node);
+		result = find_new_child_coord(op);
+		child = carry_real(op->u.insert.child);
+		if (result != NS_NOT_FOUND) {
+			warning("nikita-993",
+				"Cannot find a place for child pointer: %i",
+				result);
+			return result;
+		}
+		/* This only happens when we did multiple insertions at
+		   the previous level, trying to insert single item and
+		   it so happened, that insertion of pointers to all new
+		   nodes before this one already caused parent node to
+		   split (may be several times).
+
+		   I am going to come up with better solution.
+
+		   You are not expected to understand this.
+		   -- v6root/usr/sys/ken/slp.c
+
+		   Basically, what happens here is the following: carry came
+		   to the parent level and is about to insert internal item
+		   pointing to the child node that it just inserted in the
+		   level below. Position where internal item is to be inserted
+		   was found by find_new_child_coord() above, but node of the
+		   current carry operation (that is, parent node of child
+		   inserted on the previous level), was determined earlier in
+		   the lock_carry_level/lock_carry_node. It could so happen
+		   that other carry operations already performed on the parent
+		   level already split parent node, so that insertion point
+		   moved into another node. Handle this by creating new carry
+		   node for insertion point if necessary.
+		 */
+		if (carry_real(op->node) != op->u.insert.d->coord->node) {
+			pool_ordering direction;
+			znode *z1;
+			znode *z2;
+			reiser4_key k1;
+			reiser4_key k2;
+
+			/*
+			 * determine in what direction insertion point
+			 * moved. Do this by comparing delimiting keys.
+			 */
+			z1 = op->u.insert.d->coord->node;
+			z2 = carry_real(op->node);
+			if (keyle(leftmost_key_in_node(z1, &k1),
+				  leftmost_key_in_node(z2, &k2)))
+				/* insertion point moved to the left */
+				direction = POOLO_BEFORE;
+			else
+				/* insertion point moved to the right */
+				direction = POOLO_AFTER;
+
+			op->node = add_carry_skip(doing, direction, op->node);
+			if (IS_ERR(op->node))
+				return PTR_ERR(op->node);
+			op->node->node = op->u.insert.d->coord->node;
+			op->node->free = 1;
+			result = lock_carry_node(doing, op->node);
+			if (result != 0)
+				return result;
+		}
+
+		/*
+		 * set up key of an item being inserted: we are inserting
+		 * internal item and its key is (by the very definition of
+		 * search tree) is leftmost key in the child node.
+		 */
+		write_lock_dk(znode_get_tree(child));
+		op->u.insert.d->key = leftmost_key_in_node(child,
+							   znode_get_ld_key(child));
+		write_unlock_dk(znode_get_tree(child));
+		op->u.insert.d->data->arg = op->u.insert.brother;
+	} else {
+		assert("vs-243", op->u.insert.d->coord != NULL);
+		op->u.insert.d->coord->node = carry_real(op->node);
+	}
+
+	/* find free space. */
+	return make_space(op, doing, todo);
+}
+
+/* handle carry COP_INSERT operation.
+
+   Insert new item into node. New item can be given in one of two ways:
+
+   - by passing &tree_coord and &reiser4_item_data as part of @op. This is
+   only applicable at the leaf/twig level.
+
+   - by passing a child node pointer to which is to be inserted by this
+   operation.
+
+*/
+static int carry_insert(carry_op * op /* operation to perform */ ,
+			carry_level * doing	/* queue of operations @op
+						 * is part of */ ,
+			carry_level * todo	/* queue where new operations
+						 * are accumulated */ )
+{
+	znode *node;
+	carry_insert_data cdata;
+	coord_t coord;
+	reiser4_item_data data;
+	carry_plugin_info info;
+	int result;
+
+	assert("nikita-1036", op != NULL);
+	assert("nikita-1037", todo != NULL);
+	assert("nikita-1038", op->op == COP_INSERT);
+
+	coord_init_zero(&coord);
+
+	/* perform common functionality of insert and paste. */
+	result = insert_paste_common(op, doing, todo, &cdata, &coord, &data);
+	if (result != 0)
+		return result;
+
+	node = op->u.insert.d->coord->node;
+	assert("nikita-1039", node != NULL);
+	assert("nikita-1040", node_plugin_by_node(node) != NULL);
+
+	assert("nikita-949",
+	       space_needed_for_op(node, op) <= znode_free_space(node));
+
+	/* ask node layout to create new item. */
+	info.doing = doing;
+	info.todo = todo;
+	result = node_plugin_by_node(node)->create_item
+	    (op->u.insert.d->coord, op->u.insert.d->key, op->u.insert.d->data,
+	     &info);
+	doing->restartable = 0;
+	znode_make_dirty(node);
+
+	return result;
+}
+
+/*
+ * Flow insertion code. COP_INSERT_FLOW is special tree operation that is
+ * supplied with a "flow" (that is, a stream of data) and inserts it into tree
+ * by slicing into multiple items.
+ */
+
+#define flow_insert_point(op) ( ( op ) -> u.insert_flow.insert_point )
+#define flow_insert_flow(op) ( ( op ) -> u.insert_flow.flow )
+#define flow_insert_data(op) ( ( op ) -> u.insert_flow.data )
+
+static size_t item_data_overhead(carry_op * op)
+{
+	if (flow_insert_data(op)->iplug->b.estimate == NULL)
+		return 0;
+	return (flow_insert_data(op)->iplug->b.
+		estimate(NULL /* estimate insertion */ , flow_insert_data(op)) -
+		flow_insert_data(op)->length);
+}
+
+/* FIXME-VS: this is called several times during one make_flow_for_insertion
+   and it will always return the same result. Some optimization could be made
+   by calculating this value once at the beginning and passing it around. That
+   would reduce some flexibility in future changes
+*/
+static int can_paste(coord_t *, const reiser4_key *, const reiser4_item_data *);
+static size_t flow_insertion_overhead(carry_op * op)
+{
+	znode *node;
+	size_t insertion_overhead;
+
+	node = flow_insert_point(op)->node;
+	insertion_overhead = 0;
+	if (node->nplug->item_overhead &&
+	    !can_paste(flow_insert_point(op), &flow_insert_flow(op)->key,
+		       flow_insert_data(op)))
+		insertion_overhead =
+		    node->nplug->item_overhead(node, NULL) +
+			item_data_overhead(op);
+	return insertion_overhead;
+}
+
+/* how many bytes of flow does fit to the node */
+static int what_can_fit_into_node(carry_op * op)
+{
+	size_t free, overhead;
+
+	overhead = flow_insertion_overhead(op);
+	free = znode_free_space(flow_insert_point(op)->node);
+	if (free <= overhead)
+		return 0;
+	free -= overhead;
+	/* FIXME: flow->length is loff_t only to not get overflowed in case of expandign truncate */
+	if (free < op->u.insert_flow.flow->length)
+		return free;
+	return (int)op->u.insert_flow.flow->length;
+}
+
+/* in make_space_for_flow_insertion we need to check either whether whole flow
+   fits into a node or whether minimal fraction of flow fits into a node */
+static int enough_space_for_whole_flow(carry_op * op)
+{
+	return (unsigned)what_can_fit_into_node(op) ==
+	    op->u.insert_flow.flow->length;
+}
+
+#define MIN_FLOW_FRACTION 1
+static int enough_space_for_min_flow_fraction(carry_op * op)
+{
+	assert("vs-902", coord_is_after_rightmost(flow_insert_point(op)));
+
+	return what_can_fit_into_node(op) >= MIN_FLOW_FRACTION;
+}
+
+/* this returns 0 if left neighbor was obtained successfully and everything
+   upto insertion point including it were shifted and left neighbor still has
+   some free space to put minimal fraction of flow into it */
+static int
+make_space_by_shift_left(carry_op * op, carry_level * doing, carry_level * todo)
+{
+	carry_node *left;
+	znode *orig;
+
+	left = find_left_neighbor(op, doing);
+	if (unlikely(IS_ERR(left))) {
+		warning("vs-899",
+			"make_space_by_shift_left: "
+			"error accessing left neighbor: %li", PTR_ERR(left));
+		return 1;
+	}
+	if (left == NULL)
+		/* left neighbor either does not exist or is unformatted
+		   node */
+		return 1;
+
+	orig = flow_insert_point(op)->node;
+	/* try to shift content of node @orig from its head upto insert point
+	   including insertion point into the left neighbor */
+	carry_shift_data(LEFT_SIDE, flow_insert_point(op), carry_real(left), doing, todo, 1	/* including insert
+												 * point */ );
+	if (carry_real(left) != flow_insert_point(op)->node) {
+		/* insertion point did not move */
+		return 1;
+	}
+
+	/* insertion point is set after last item in the node */
+	assert("vs-900", coord_is_after_rightmost(flow_insert_point(op)));
+
+	if (!enough_space_for_min_flow_fraction(op)) {
+		/* insertion point node does not have enough free space to put
+		   even minimal portion of flow into it, therefore, move
+		   insertion point back to orig node (before first item) */
+		coord_init_before_first_item(flow_insert_point(op), orig);
+		return 1;
+	}
+
+	/* part of flow is to be written to the end of node */
+	op->node = left;
+	return 0;
+}
+
+/* this returns 0 if right neighbor was obtained successfully and everything to
+   the right of insertion point was shifted to it and node got enough free
+   space to put minimal fraction of flow into it */
+static int
+make_space_by_shift_right(carry_op * op, carry_level * doing,
+			  carry_level * todo)
+{
+	carry_node *right;
+
+	right = find_right_neighbor(op, doing);
+	if (unlikely(IS_ERR(right))) {
+		warning("nikita-1065", "shift_right_excluding_insert_point: "
+			"error accessing right neighbor: %li", PTR_ERR(right));
+		return 1;
+	}
+	if (right) {
+		/* shift everything possible on the right of but excluding
+		   insertion coord into the right neighbor */
+		carry_shift_data(RIGHT_SIDE, flow_insert_point(op), carry_real(right), doing, todo, 0	/* not
+													 * including
+													 * insert
+													 * point */ );
+	} else {
+		/* right neighbor either does not exist or is unformatted
+		   node */
+		;
+	}
+	if (coord_is_after_rightmost(flow_insert_point(op))) {
+		if (enough_space_for_min_flow_fraction(op)) {
+			/* part of flow is to be written to the end of node */
+			return 0;
+		}
+	}
+
+	/* new node is to be added if insert point node did not get enough
+	   space for whole flow */
+	return 1;
+}
+
+/* this returns 0 when insert coord is set at the node end and fraction of flow
+   fits into that node */
+static int
+make_space_by_new_nodes(carry_op * op, carry_level * doing, carry_level * todo)
+{
+	int result;
+	znode *node;
+	carry_node *new;
+
+	node = flow_insert_point(op)->node;
+
+	if (op->u.insert_flow.new_nodes == CARRY_FLOW_NEW_NODES_LIMIT)
+		return RETERR(-E_NODE_FULL);
+	/* add new node after insert point node */
+	new = add_new_znode(node, op->node, doing, todo);
+	if (unlikely(IS_ERR(new))) {
+		return PTR_ERR(new);
+	}
+	result = lock_carry_node(doing, new);
+	zput(carry_real(new));
+	if (unlikely(result)) {
+		return result;
+	}
+	op->u.insert_flow.new_nodes++;
+	if (!coord_is_after_rightmost(flow_insert_point(op))) {
+		carry_shift_data(RIGHT_SIDE, flow_insert_point(op), carry_real(new), doing, todo, 0	/* not
+													 * including
+													 * insert
+													 * point */ );
+
+		assert("vs-901",
+		       coord_is_after_rightmost(flow_insert_point(op)));
+
+		if (enough_space_for_min_flow_fraction(op)) {
+			return 0;
+		}
+		if (op->u.insert_flow.new_nodes == CARRY_FLOW_NEW_NODES_LIMIT)
+			return RETERR(-E_NODE_FULL);
+
+		/* add one more new node */
+		new = add_new_znode(node, op->node, doing, todo);
+		if (unlikely(IS_ERR(new))) {
+			return PTR_ERR(new);
+		}
+		result = lock_carry_node(doing, new);
+		zput(carry_real(new));
+		if (unlikely(result)) {
+			return result;
+		}
+		op->u.insert_flow.new_nodes++;
+	}
+
+	/* move insertion point to new node */
+	coord_init_before_first_item(flow_insert_point(op), carry_real(new));
+	op->node = new;
+	return 0;
+}
+
+static int
+make_space_for_flow_insertion(carry_op * op, carry_level * doing,
+			      carry_level * todo)
+{
+	__u32 flags = op->u.insert_flow.flags;
+
+	if (enough_space_for_whole_flow(op)) {
+		/* whole flow fits into insert point node */
+		return 0;
+	}
+
+	if (!(flags & COPI_DONT_SHIFT_LEFT)
+	    && (make_space_by_shift_left(op, doing, todo) == 0)) {
+		/* insert point is shifted to left neighbor of original insert
+		   point node and is set after last unit in that node. It has
+		   enough space to fit at least minimal fraction of flow. */
+		return 0;
+	}
+
+	if (enough_space_for_whole_flow(op)) {
+		/* whole flow fits into insert point node */
+		return 0;
+	}
+
+	if (!(flags & COPI_DONT_SHIFT_RIGHT)
+	    && (make_space_by_shift_right(op, doing, todo) == 0)) {
+		/* insert point is still set to the same node, but there is
+		   nothing to the right of insert point. */
+		return 0;
+	}
+
+	if (enough_space_for_whole_flow(op)) {
+		/* whole flow fits into insert point node */
+		return 0;
+	}
+
+	return make_space_by_new_nodes(op, doing, todo);
+}
+
+/* implements COP_INSERT_FLOW operation */
+static int
+carry_insert_flow(carry_op * op, carry_level * doing, carry_level * todo)
+{
+	int result;
+	flow_t *f;
+	coord_t *insert_point;
+	node_plugin *nplug;
+	carry_plugin_info info;
+	znode *orig_node;
+	lock_handle *orig_lh;
+
+	f = op->u.insert_flow.flow;
+	result = 0;
+
+	/* carry system needs this to work */
+	info.doing = doing;
+	info.todo = todo;
+
+	orig_node = flow_insert_point(op)->node;
+	orig_lh = doing->tracked;
+
+	while (f->length) {
+		result = make_space_for_flow_insertion(op, doing, todo);
+		if (result)
+			break;
+
+		insert_point = flow_insert_point(op);
+		nplug = node_plugin_by_node(insert_point->node);
+
+		/* compose item data for insertion/pasting */
+		flow_insert_data(op)->data = f->data;
+		flow_insert_data(op)->length = what_can_fit_into_node(op);
+
+		if (can_paste(insert_point, &f->key, flow_insert_data(op))) {
+			/* insert point is set to item of file we are writing to and we have to append to it */
+			assert("vs-903", insert_point->between == AFTER_UNIT);
+			nplug->change_item_size(insert_point,
+						flow_insert_data(op)->length);
+			flow_insert_data(op)->iplug->b.paste(insert_point,
+							     flow_insert_data
+							     (op), &info);
+		} else {
+			/* new item must be inserted */
+			pos_in_node_t new_pos;
+			flow_insert_data(op)->length += item_data_overhead(op);
+
+			/* FIXME-VS: this is because node40_create_item changes
+			   insert_point for obscure reasons */
+			switch (insert_point->between) {
+			case AFTER_ITEM:
+				new_pos = insert_point->item_pos + 1;
+				break;
+			case EMPTY_NODE:
+				new_pos = 0;
+				break;
+			case BEFORE_ITEM:
+				assert("vs-905", insert_point->item_pos == 0);
+				new_pos = 0;
+				break;
+			default:
+				impossible("vs-906",
+					   "carry_insert_flow: invalid coord");
+				new_pos = 0;
+				break;
+			}
+
+			nplug->create_item(insert_point, &f->key,
+					   flow_insert_data(op), &info);
+			coord_set_item_pos(insert_point, new_pos);
+		}
+		coord_init_after_item_end(insert_point);
+		doing->restartable = 0;
+		znode_make_dirty(insert_point->node);
+
+		move_flow_forward(f, (unsigned)flow_insert_data(op)->length);
+	}
+
+	if (orig_node != flow_insert_point(op)->node) {
+		/* move lock to new insert point */
+		done_lh(orig_lh);
+		init_lh(orig_lh);
+		result =
+		    longterm_lock_znode(orig_lh, flow_insert_point(op)->node,
+					ZNODE_WRITE_LOCK, ZNODE_LOCK_HIPRI);
+	}
+
+	return result;
+}
+
+/* implements COP_DELETE operation
+
+   Remove pointer to @op -> u.delete.child from it's parent.
+
+   This function also handles killing of a tree root is last pointer from it
+   was removed. This is complicated by our handling of "twig" level: root on
+   twig level is never killed.
+
+*/
+static int carry_delete(carry_op * op /* operation to be performed */ ,
+			carry_level * doing UNUSED_ARG	/* current carry
+							 * level */ ,
+			carry_level * todo /* next carry level */ )
+{
+	int result;
+	coord_t coord;
+	coord_t coord2;
+	znode *parent;
+	znode *child;
+	carry_plugin_info info;
+	reiser4_tree *tree;
+
+	/*
+	 * This operation is called to delete internal item pointing to the
+	 * child node that was removed by carry from the tree on the previous
+	 * tree level.
+	 */
+
+	assert("nikita-893", op != NULL);
+	assert("nikita-894", todo != NULL);
+	assert("nikita-895", op->op == COP_DELETE);
+
+	coord_init_zero(&coord);
+	coord_init_zero(&coord2);
+
+	parent = carry_real(op->node);
+	child = op->u.delete.child ?
+	    carry_real(op->u.delete.child) : op->node->node;
+	tree = znode_get_tree(child);
+	read_lock_tree(tree);
+
+	/*
+	 * @parent was determined when carry entered parent level
+	 * (lock_carry_level/lock_carry_node). Since then, actual parent of
+	 * @child node could change due to other carry operations performed on
+	 * the parent level. Check for this.
+	 */
+
+	if (znode_parent(child) != parent) {
+		/* NOTE-NIKITA add stat counter for this. */
+		parent = znode_parent(child);
+		assert("nikita-2581", find_carry_node(doing, parent));
+	}
+	read_unlock_tree(tree);
+
+	assert("nikita-1213", znode_get_level(parent) > LEAF_LEVEL);
+
+	/* Twig level horrors: tree should be of height at least 2. So, last
+	   pointer from the root at twig level is preserved even if child is
+	   empty. This is ugly, but so it was architectured.
+	 */
+
+	if (znode_is_root(parent) &&
+	    znode_get_level(parent) <= REISER4_MIN_TREE_HEIGHT &&
+	    node_num_items(parent) == 1) {
+		/* Delimiting key manipulations. */
+		write_lock_dk(tree);
+		znode_set_ld_key(child, znode_set_ld_key(parent, min_key()));
+		znode_set_rd_key(child, znode_set_rd_key(parent, max_key()));
+		ZF_SET(child, JNODE_DKSET);
+		write_unlock_dk(tree);
+
+		/* @child escaped imminent death! */
+		ZF_CLR(child, JNODE_HEARD_BANSHEE);
+		return 0;
+	}
+
+	/* convert child pointer to the coord_t */
+	result = find_child_ptr(parent, child, &coord);
+	if (result != NS_FOUND) {
+		warning("nikita-994", "Cannot find child pointer: %i", result);
+		print_coord_content("coord", &coord);
+		return result;
+	}
+
+	coord_dup(&coord2, &coord);
+	info.doing = doing;
+	info.todo = todo;
+	{
+		/*
+		 * Actually kill internal item: prepare structure with
+		 * arguments for ->cut_and_kill() method...
+		 */
+
+		struct carry_kill_data kdata;
+		kdata.params.from = &coord;
+		kdata.params.to = &coord2;
+		kdata.params.from_key = NULL;
+		kdata.params.to_key = NULL;
+		kdata.params.smallest_removed = NULL;
+		kdata.params.truncate = 1;
+		kdata.flags = op->u.delete.flags;
+		kdata.inode = NULL;
+		kdata.left = NULL;
+		kdata.right = NULL;
+		kdata.buf = NULL;
+		/* ... and call it. */
+		result = node_plugin_by_node(parent)->cut_and_kill(&kdata,
+								   &info);
+	}
+	doing->restartable = 0;
+
+	/* check whether root should be killed violently */
+	if (znode_is_root(parent) &&
+	    /* don't kill roots at and lower than twig level */
+	    znode_get_level(parent) > REISER4_MIN_TREE_HEIGHT &&
+	    node_num_items(parent) == 1) {
+		result = kill_tree_root(coord.node);
+	}
+
+	return result < 0 ? : 0;
+}
+
+/* implements COP_CUT opration
+
+   Cuts part or whole content of node.
+
+*/
+static int carry_cut(carry_op * op /* operation to be performed */ ,
+		     carry_level * doing /* current carry level */ ,
+		     carry_level * todo /* next carry level */ )
+{
+	int result;
+	carry_plugin_info info;
+	node_plugin *nplug;
+
+	assert("nikita-896", op != NULL);
+	assert("nikita-897", todo != NULL);
+	assert("nikita-898", op->op == COP_CUT);
+
+	info.doing = doing;
+	info.todo = todo;
+
+	nplug = node_plugin_by_node(carry_real(op->node));
+	if (op->u.cut_or_kill.is_cut)
+		result = nplug->cut(op->u.cut_or_kill.u.cut, &info);
+	else
+		result = nplug->cut_and_kill(op->u.cut_or_kill.u.kill, &info);
+
+	doing->restartable = 0;
+	return result < 0 ? : 0;
+}
+
+/* helper function for carry_paste(): returns true if @op can be continued as
+   paste  */
+static int
+can_paste(coord_t * icoord, const reiser4_key * key,
+	  const reiser4_item_data * data)
+{
+	coord_t circa;
+	item_plugin *new_iplug;
+	item_plugin *old_iplug;
+	int result = 0;		/* to keep gcc shut */
+
+	assert("", icoord->between != AT_UNIT);
+
+	/* obviously, one cannot paste when node is empty---there is nothing
+	   to paste into. */
+	if (node_is_empty(icoord->node))
+		return 0;
+	/* if insertion point is at the middle of the item, then paste */
+	if (!coord_is_between_items(icoord))
+		return 1;
+	coord_dup(&circa, icoord);
+	circa.between = AT_UNIT;
+
+	old_iplug = item_plugin_by_coord(&circa);
+	new_iplug = data->iplug;
+
+	/* check whether we can paste to the item @icoord is "at" when we
+	   ignore ->between field */
+	if (old_iplug == new_iplug && item_can_contain_key(&circa, key, data)) {
+		result = 1;
+	} else if (icoord->between == BEFORE_UNIT
+		   || icoord->between == BEFORE_ITEM) {
+		/* otherwise, try to glue to the item at the left, if any */
+		coord_dup(&circa, icoord);
+		if (coord_set_to_left(&circa)) {
+			result = 0;
+			coord_init_before_item(icoord);
+		} else {
+			old_iplug = item_plugin_by_coord(&circa);
+			result = (old_iplug == new_iplug)
+			    && item_can_contain_key(icoord, key, data);
+			if (result) {
+				coord_dup(icoord, &circa);
+				icoord->between = AFTER_UNIT;
+			}
+		}
+	} else if (icoord->between == AFTER_UNIT
+		   || icoord->between == AFTER_ITEM) {
+		coord_dup(&circa, icoord);
+		/* otherwise, try to glue to the item at the right, if any */
+		if (coord_set_to_right(&circa)) {
+			result = 0;
+			coord_init_after_item(icoord);
+		} else {
+			int (*cck) (const coord_t *, const reiser4_key *,
+				    const reiser4_item_data *);
+
+			old_iplug = item_plugin_by_coord(&circa);
+
+			cck = old_iplug->b.can_contain_key;
+			if (cck == NULL)
+				/* item doesn't define ->can_contain_key
+				   method? So it is not expandable. */
+				result = 0;
+			else {
+				result = (old_iplug == new_iplug)
+				    && cck(&circa /*icoord */ , key, data);
+				if (result) {
+					coord_dup(icoord, &circa);
+					icoord->between = BEFORE_UNIT;
+				}
+			}
+		}
+	} else
+		impossible("nikita-2513", "Nothing works");
+	if (result) {
+		if (icoord->between == BEFORE_ITEM) {
+			assert("vs-912", icoord->unit_pos == 0);
+			icoord->between = BEFORE_UNIT;
+		} else if (icoord->between == AFTER_ITEM) {
+			coord_init_after_item_end(icoord);
+		}
+	}
+	return result;
+}
+
+/* implements COP_PASTE operation
+
+   Paste data into existing item. This is complicated by the fact that after
+   we shifted something to the left or right neighbors trying to free some
+   space, item we were supposed to paste into can be in different node than
+   insertion coord. If so, we are no longer doing paste, but insert. See
+   comments in insert_paste_common().
+
+*/
+static int carry_paste(carry_op * op /* operation to be performed */ ,
+		       carry_level * doing UNUSED_ARG	/* current carry
+							 * level */ ,
+		       carry_level * todo /* next carry level */ )
+{
+	znode *node;
+	carry_insert_data cdata;
+	coord_t dcoord;
+	reiser4_item_data data;
+	int result;
+	int real_size;
+	item_plugin *iplug;
+	carry_plugin_info info;
+	coord_t *coord;
+
+	assert("nikita-982", op != NULL);
+	assert("nikita-983", todo != NULL);
+	assert("nikita-984", op->op == COP_PASTE);
+
+	coord_init_zero(&dcoord);
+
+	result = insert_paste_common(op, doing, todo, &cdata, &dcoord, &data);
+	if (result != 0)
+		return result;
+
+	coord = op->u.insert.d->coord;
+
+	/* handle case when op -> u.insert.coord doesn't point to the item
+	   of required type. restart as insert. */
+	if (!can_paste(coord, op->u.insert.d->key, op->u.insert.d->data)) {
+		op->op = COP_INSERT;
+		op->u.insert.type = COPT_PASTE_RESTARTED;
+		result = op_dispatch_table[COP_INSERT].handler(op, doing, todo);
+
+		return result;
+	}
+
+	node = coord->node;
+	iplug = item_plugin_by_coord(coord);
+	assert("nikita-992", iplug != NULL);
+
+	assert("nikita-985", node != NULL);
+	assert("nikita-986", node_plugin_by_node(node) != NULL);
+
+	assert("nikita-987",
+	       space_needed_for_op(node, op) <= znode_free_space(node));
+
+	assert("nikita-1286", coord_is_existing_item(coord));
+
+	/*
+	 * if item is expanded as a result of this operation, we should first
+	 * change item size, than call ->b.paste item method. If item is
+	 * shrunk, it should be done other way around: first call ->b.paste
+	 * method, then reduce item size.
+	 */
+
+	real_size = space_needed_for_op(node, op);
+	if (real_size > 0)
+		node->nplug->change_item_size(coord, real_size);
+
+	doing->restartable = 0;
+	info.doing = doing;
+	info.todo = todo;
+
+	result = iplug->b.paste(coord, op->u.insert.d->data, &info);
+
+	if (real_size < 0)
+		node->nplug->change_item_size(coord, real_size);
+
+	/* if we pasted at the beginning of the item, update item's key. */
+	if (coord->unit_pos == 0 && coord->between != AFTER_UNIT)
+		node->nplug->update_item_key(coord, op->u.insert.d->key, &info);
+
+	znode_make_dirty(node);
+	return result;
+}
+
+/* handle carry COP_EXTENT operation. */
+static int carry_extent(carry_op * op /* operation to perform */ ,
+			carry_level * doing	/* queue of operations @op
+						 * is part of */ ,
+			carry_level * todo	/* queue where new operations
+						 * are accumulated */ )
+{
+	znode *node;
+	carry_insert_data cdata;
+	coord_t coord;
+	reiser4_item_data data;
+	carry_op *delete_dummy;
+	carry_op *insert_extent;
+	int result;
+	carry_plugin_info info;
+
+	assert("nikita-1751", op != NULL);
+	assert("nikita-1752", todo != NULL);
+	assert("nikita-1753", op->op == COP_EXTENT);
+
+	/* extent insertion overview:
+
+	   extents live on the TWIG LEVEL, which is level one above the leaf
+	   one. This complicates extent insertion logic somewhat: it may
+	   happen (and going to happen all the time) that in logical key
+	   ordering extent has to be placed between items I1 and I2, located
+	   at the leaf level, but I1 and I2 are in the same formatted leaf
+	   node N1. To insert extent one has to
+
+	   (1) reach node N1 and shift data between N1, its neighbors and
+	   possibly newly allocated nodes until I1 and I2 fall into different
+	   nodes. Since I1 and I2 are still neighboring items in logical key
+	   order, they will be necessary utmost items in their respective
+	   nodes.
+
+	   (2) After this new extent item is inserted into node on the twig
+	   level.
+
+	   Fortunately this process can reuse almost all code from standard
+	   insertion procedure (viz. make_space() and insert_paste_common()),
+	   due to the following observation: make_space() only shifts data up
+	   to and excluding or including insertion point. It never
+	   "over-moves" through insertion point. Thus, one can use
+	   make_space() to perform step (1). All required for this is just to
+	   instruct free_space_shortage() to keep make_space() shifting data
+	   until insertion point is at the node border.
+
+	 */
+
+	/* perform common functionality of insert and paste. */
+	result = insert_paste_common(op, doing, todo, &cdata, &coord, &data);
+	if (result != 0)
+		return result;
+
+	node = op->u.extent.d->coord->node;
+	assert("nikita-1754", node != NULL);
+	assert("nikita-1755", node_plugin_by_node(node) != NULL);
+	assert("nikita-1700", coord_wrt(op->u.extent.d->coord) != COORD_INSIDE);
+
+	/* NOTE-NIKITA add some checks here. Not assertions, -EIO. Check that
+	   extent fits between items. */
+
+	info.doing = doing;
+	info.todo = todo;
+
+	/* there is another complication due to placement of extents on the
+	   twig level: extents are "rigid" in the sense that key-range
+	   occupied by extent cannot grow indefinitely to the right as it is
+	   for the formatted leaf nodes. Because of this when search finds two
+	   adjacent extents on the twig level, it has to "drill" to the leaf
+	   level, creating new node. Here we are removing this node.
+	 */
+	if (node_is_empty(node)) {
+		delete_dummy = node_post_carry(&info, COP_DELETE, node, 1);
+		if (IS_ERR(delete_dummy))
+			return PTR_ERR(delete_dummy);
+		delete_dummy->u.delete.child = NULL;
+		delete_dummy->u.delete.flags = DELETE_RETAIN_EMPTY;
+		ZF_SET(node, JNODE_HEARD_BANSHEE);
+	}
+
+	/* proceed with inserting extent item into parent. We are definitely
+	   inserting rather than pasting if we get that far. */
+	insert_extent = node_post_carry(&info, COP_INSERT, node, 1);
+	if (IS_ERR(insert_extent))
+		/* @delete_dummy will be automatically destroyed on the level
+		   exiting  */
+		return PTR_ERR(insert_extent);
+	/* NOTE-NIKITA insertion by key is simplest option here. Another
+	   possibility is to insert on the left or right of already existing
+	   item.
+	 */
+	insert_extent->u.insert.type = COPT_KEY;
+	insert_extent->u.insert.d = op->u.extent.d;
+	assert("nikita-1719", op->u.extent.d->key != NULL);
+	insert_extent->u.insert.d->data->arg = op->u.extent.d->coord;
+	insert_extent->u.insert.flags =
+	    znode_get_tree(node)->carry.new_extent_flags;
+
+	/*
+	 * if carry was asked to track lock handle we should actually track
+	 * lock handle on the twig node rather than on the leaf where
+	 * operation was started from. Transfer tracked lock handle.
+	 */
+	if (doing->track_type) {
+		assert("nikita-3242", doing->tracked != NULL);
+		assert("nikita-3244", todo->tracked == NULL);
+		todo->tracked = doing->tracked;
+		todo->track_type = CARRY_TRACK_NODE;
+		doing->tracked = NULL;
+		doing->track_type = 0;
+	}
+
+	return 0;
+}
+
+/* update key in @parent between pointers to @left and @right.
+
+   Find coords of @left and @right and update delimiting key between them.
+   This is helper function called by carry_update(). Finds position of
+   internal item involved. Updates item key. Updates delimiting keys of child
+   nodes involved.
+*/
+static int update_delimiting_key(znode * parent	/* node key is updated
+						 * in */ ,
+				 znode * left /* child of @parent */ ,
+				 znode * right /* child of @parent */ ,
+				 carry_level * doing	/* current carry
+							 * level */ ,
+				 carry_level * todo	/* parent carry
+							 * level */ ,
+				 const char **error_msg	/* place to
+							 * store error
+							 * message */ )
+{
+	coord_t left_pos;
+	coord_t right_pos;
+	int result;
+	reiser4_key ldkey;
+	carry_plugin_info info;
+
+	assert("nikita-1177", right != NULL);
+	/* find position of right left child in a parent */
+	result = find_child_ptr(parent, right, &right_pos);
+	if (result != NS_FOUND) {
+		*error_msg = "Cannot find position of right child";
+		return result;
+	}
+
+	if ((left != NULL) && !coord_is_leftmost_unit(&right_pos)) {
+		/* find position of the left child in a parent */
+		result = find_child_ptr(parent, left, &left_pos);
+		if (result != NS_FOUND) {
+			*error_msg = "Cannot find position of left child";
+			return result;
+		}
+		assert("nikita-1355", left_pos.node != NULL);
+	} else
+		left_pos.node = NULL;
+
+	/* check that they are separated by exactly one key and are basically
+	   sane */
+	if (REISER4_DEBUG) {
+		if ((left_pos.node != NULL)
+		    && !coord_is_existing_unit(&left_pos)) {
+			*error_msg = "Left child is bastard";
+			return RETERR(-EIO);
+		}
+		if (!coord_is_existing_unit(&right_pos)) {
+			*error_msg = "Right child is bastard";
+			return RETERR(-EIO);
+		}
+		if (left_pos.node != NULL &&
+		    !coord_are_neighbors(&left_pos, &right_pos)) {
+			*error_msg = "Children are not direct siblings";
+			return RETERR(-EIO);
+		}
+	}
+	*error_msg = NULL;
+
+	info.doing = doing;
+	info.todo = todo;
+
+	/*
+	 * If child node is not empty, new key of internal item is a key of
+	 * leftmost item in the child node. If the child is empty, take its
+	 * right delimiting key as a new key of the internal item. Precise key
+	 * in the latter case is not important per se, because the child (and
+	 * the internal item) are going to be killed shortly anyway, but we
+	 * have to preserve correct order of keys in the parent node.
+	 */
+
+	if (!ZF_ISSET(right, JNODE_HEARD_BANSHEE))
+		leftmost_key_in_node(right, &ldkey);
+	else {
+		read_lock_dk(znode_get_tree(parent));
+		ldkey = *znode_get_rd_key(right);
+		read_unlock_dk(znode_get_tree(parent));
+	}
+	node_plugin_by_node(parent)->update_item_key(&right_pos, &ldkey, &info);
+	doing->restartable = 0;
+	znode_make_dirty(parent);
+	return 0;
+}
+
+/* implements COP_UPDATE opration
+
+   Update delimiting keys.
+
+*/
+static int carry_update(carry_op * op /* operation to be performed */ ,
+			carry_level * doing /* current carry level */ ,
+			carry_level * todo /* next carry level */ )
+{
+	int result;
+	carry_node *missing UNUSED_ARG;
+	znode *left;
+	znode *right;
+	carry_node *lchild;
+	carry_node *rchild;
+	const char *error_msg;
+	reiser4_tree *tree;
+
+	/*
+	 * This operation is called to update key of internal item. This is
+	 * necessary when carry shifted of cut data on the child
+	 * level. Arguments of this operation are:
+	 *
+	 *     @right --- child node. Operation should update key of internal
+	 *     item pointing to @right.
+	 *
+	 *     @left --- left neighbor of @right. This parameter is optional.
+	 */
+
+	assert("nikita-902", op != NULL);
+	assert("nikita-903", todo != NULL);
+	assert("nikita-904", op->op == COP_UPDATE);
+
+	lchild = op->u.update.left;
+	rchild = op->node;
+
+	if (lchild != NULL) {
+		assert("nikita-1001", lchild->parent);
+		assert("nikita-1003", !lchild->left);
+		left = carry_real(lchild);
+	} else
+		left = NULL;
+
+	tree = znode_get_tree(rchild->node);
+	read_lock_tree(tree);
+	right = znode_parent(rchild->node);
+	read_unlock_tree(tree);
+
+	if (right != NULL) {
+		result = update_delimiting_key(right,
+					       lchild ? lchild->node : NULL,
+					       rchild->node,
+					       doing, todo, &error_msg);
+	} else {
+		error_msg = "Cannot find node to update key in";
+		result = RETERR(-EIO);
+	}
+	/* operation will be reposted to the next level by the
+	   ->update_item_key() method of node plugin, if necessary. */
+
+	if (result != 0) {
+		warning("nikita-999", "Error updating delimiting key: %s (%i)",
+			error_msg ? : "", result);
+	}
+	return result;
+}
+
+/* move items from @node during carry */
+static int carry_shift_data(sideof side /* in what direction to move data */ ,
+			    coord_t * insert_coord	/* coord where new item
+							 * is to be inserted */ ,
+			    znode * node /* node which data are moved from */ ,
+			    carry_level * doing /* active carry queue */ ,
+			    carry_level * todo	/* carry queue where new
+						 * operations are to be put
+						 * in */ ,
+			    unsigned int including_insert_coord_p	/* true if
+									 * @insertion_coord
+									 * can be moved */ )
+{
+	int result;
+	znode *source;
+	carry_plugin_info info;
+	node_plugin *nplug;
+
+	source = insert_coord->node;
+
+	info.doing = doing;
+	info.todo = todo;
+
+	nplug = node_plugin_by_node(node);
+	result = nplug->shift(insert_coord, node,
+			      (side == LEFT_SIDE) ? SHIFT_LEFT : SHIFT_RIGHT, 0,
+			      (int)including_insert_coord_p, &info);
+	/* the only error ->shift() method of node plugin can return is
+	   -ENOMEM due to carry node/operation allocation. */
+	assert("nikita-915", result >= 0 || result == -ENOMEM);
+	if (result > 0) {
+		/*
+		 * if some number of bytes was actually shifted, mark nodes
+		 * dirty, and carry level as non-restartable.
+		 */
+		doing->restartable = 0;
+		znode_make_dirty(source);
+		znode_make_dirty(node);
+	}
+
+	assert("nikita-2077", coord_check(insert_coord));
+	return 0;
+}
+
+typedef carry_node *(*carry_iterator) (carry_node * node);
+static carry_node *find_dir_carry(carry_node * node, carry_level * level,
+				  carry_iterator iterator);
+
+static carry_node *pool_level_list_prev(carry_node *node)
+{
+	return list_entry(node->header.level_linkage.prev, carry_node, header.level_linkage);
+}
+
+/* look for the left neighbor of given carry node in a carry queue.
+
+   This is used by find_left_neighbor(), but I am not sure that this
+   really gives any advantage. More statistics required.
+
+*/
+carry_node *find_left_carry(carry_node * node	/* node to find left neighbor
+						 * of */ ,
+			    carry_level * level /* level to scan */ )
+{
+	return find_dir_carry(node, level,
+			      (carry_iterator) pool_level_list_prev);
+}
+
+static carry_node *pool_level_list_next(carry_node *node)
+{
+	return list_entry(node->header.level_linkage.next, carry_node, header.level_linkage);
+}
+
+/* look for the right neighbor of given carry node in a
+   carry queue.
+
+   This is used by find_right_neighbor(), but I am not sure that this
+   really gives any advantage. More statistics required.
+
+*/
+carry_node *find_right_carry(carry_node * node	/* node to find right neighbor
+						 * of */ ,
+			     carry_level * level /* level to scan */ )
+{
+	return find_dir_carry(node, level,
+			      (carry_iterator) pool_level_list_next);
+}
+
+/* look for the left or right neighbor of given carry node in a carry
+   queue.
+
+   Helper function used by find_{left|right}_carry().
+*/
+static carry_node *find_dir_carry(carry_node * node	/* node to start scanning
+							 * from */ ,
+				  carry_level * level /* level to scan */ ,
+				  carry_iterator iterator	/* operation to
+								 * move to the next
+								 * node */ )
+{
+	carry_node *neighbor;
+
+	assert("nikita-1059", node != NULL);
+	assert("nikita-1060", level != NULL);
+
+	/* scan list of carry nodes on this list dir-ward, skipping all
+	   carry nodes referencing the same znode. */
+	neighbor = node;
+	while (1) {
+		neighbor = iterator(neighbor);
+		if (carry_node_end(level, neighbor))
+			/* list head is reached */
+			return NULL;
+		if (carry_real(neighbor) != carry_real(node))
+			return neighbor;
+	}
+}
+
+/*
+ * Memory reservation estimation.
+ *
+ * Carry process proceeds through tree levels upwards. Carry assumes that it
+ * takes tree in consistent state (e.g., that search tree invariants hold),
+ * and leaves tree consistent after it finishes. This means that when some
+ * error occurs carry cannot simply return if there are pending carry
+ * operations. Generic solution for this problem is carry-undo either as
+ * transaction manager feature (requiring checkpoints and isolation), or
+ * through some carry specific mechanism.
+ *
+ * Our current approach is to panic if carry hits an error while tree is
+ * inconsistent. Unfortunately -ENOMEM can easily be triggered. To work around
+ * this "memory reservation" mechanism was added.
+ *
+ * Memory reservation is implemented by perthread-pages.diff patch from
+ * core-patches. Its API is defined in <linux/gfp.h>
+ *
+ *     int  perthread_pages_reserve(int nrpages, int gfp);
+ *     void perthread_pages_release(int nrpages);
+ *     int  perthread_pages_count(void);
+ *
+ * carry estimates its worst case memory requirements at the entry, reserved
+ * enough memory, and released unused pages before returning.
+ *
+ * Code below estimates worst case memory requirements for a given carry
+ * queue. This is dome by summing worst case memory requirements for each
+ * operation in the queue.
+ *
+ */
+
+/*
+ * Memory memory requirements of many operations depends on the tree
+ * height. For example, item insertion requires new node to be inserted at
+ * each tree level in the worst case. What tree height should be used for
+ * estimation? Current tree height is wrong, because tree height can change
+ * between the time when estimation was done and the time when operation is
+ * actually performed. Maximal possible tree height (REISER4_MAX_ZTREE_HEIGHT)
+ * is also not desirable, because it would lead to the huge over-estimation
+ * all the time. Plausible solution is "capped tree height": if current tree
+ * height is less than some TREE_HEIGHT_CAP constant, capped tree height is
+ * TREE_HEIGHT_CAP, otherwise it's current tree height. Idea behind this is
+ * that if tree height is TREE_HEIGHT_CAP or larger, it's extremely unlikely
+ * to be increased even more during short interval of time.
+ */
+#define TREE_HEIGHT_CAP (5)
+
+/* return capped tree height for the @tree. See comment above. */
+static int cap_tree_height(reiser4_tree * tree)
+{
+	return max_t(int, tree->height, TREE_HEIGHT_CAP);
+}
+
+/* return capped tree height for the current tree. */
+static int capped_height(void)
+{
+	return cap_tree_height(current_tree);
+}
+
+/* return number of pages required to store given number of bytes */
+static int bytes_to_pages(int bytes)
+{
+	return (bytes + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+}
+
+/* how many pages are required to allocate znodes during item insertion. */
+static int carry_estimate_znodes(void)
+{
+	/*
+	 * Note, that there we have some problem here: there is no way to
+	 * reserve pages specifically for the given slab. This means that
+	 * these pages can be hijacked for some other end.
+	 */
+
+	/* in the worst case we need 3 new znode on each tree level */
+	return bytes_to_pages(capped_height() * sizeof(znode) * 3);
+}
+
+/*
+ * how many pages are required to load bitmaps. One bitmap per level.
+ */
+static int carry_estimate_bitmaps(void)
+{
+	if (reiser4_is_set(reiser4_get_current_sb(), REISER4_DONT_LOAD_BITMAP)) {
+		int bytes;
+
+		bytes = capped_height() * (0 +	/* bnode should be added, but its is private to
+						 * bitmap.c, skip for now. */
+					   2 * sizeof(jnode));	/* working and commit jnodes */
+		return bytes_to_pages(bytes) + 2;	/* and their contents */
+	} else
+		/* bitmaps were pre-loaded during mount */
+		return 0;
+}
+
+/* worst case item insertion memory requirements */
+static int carry_estimate_insert(carry_op * op, carry_level * level)
+{
+	return carry_estimate_bitmaps() + carry_estimate_znodes() + 1 +	/* new atom */
+	    capped_height() +	/* new block on each level */
+	    1 +			/* and possibly extra new block at the leaf level */
+	    3;			/* loading of leaves into memory */
+}
+
+/* worst case item deletion memory requirements */
+static int carry_estimate_delete(carry_op * op, carry_level * level)
+{
+	return carry_estimate_bitmaps() + carry_estimate_znodes() + 1 +	/* new atom */
+	    3;			/* loading of leaves into memory */
+}
+
+/* worst case tree cut memory requirements */
+static int carry_estimate_cut(carry_op * op, carry_level * level)
+{
+	return carry_estimate_bitmaps() + carry_estimate_znodes() + 1 +	/* new atom */
+	    3;			/* loading of leaves into memory */
+}
+
+/* worst case memory requirements of pasting into item */
+static int carry_estimate_paste(carry_op * op, carry_level * level)
+{
+	return carry_estimate_bitmaps() + carry_estimate_znodes() + 1 +	/* new atom */
+	    capped_height() +	/* new block on each level */
+	    1 +			/* and possibly extra new block at the leaf level */
+	    3;			/* loading of leaves into memory */
+}
+
+/* worst case memory requirements of extent insertion */
+static int carry_estimate_extent(carry_op * op, carry_level * level)
+{
+	return carry_estimate_insert(op, level) +	/* insert extent */
+	    carry_estimate_delete(op, level);	/* kill leaf */
+}
+
+/* worst case memory requirements of key update */
+static int carry_estimate_update(carry_op * op, carry_level * level)
+{
+	return 0;
+}
+
+/* worst case memory requirements of flow insertion */
+static int carry_estimate_insert_flow(carry_op * op, carry_level * level)
+{
+	int newnodes;
+
+	newnodes = min(bytes_to_pages(op->u.insert_flow.flow->length),
+		       CARRY_FLOW_NEW_NODES_LIMIT);
+	/*
+	 * roughly estimate insert_flow as a sequence of insertions.
+	 */
+	return newnodes * carry_estimate_insert(op, level);
+}
+
+/* This is dispatch table for carry operations. It can be trivially
+   abstracted into useful plugin: tunable balancing policy is a good
+   thing. */
+carry_op_handler op_dispatch_table[COP_LAST_OP] = {
+	[COP_INSERT] = {
+			.handler = carry_insert,
+			.estimate = carry_estimate_insert}
+	,
+	[COP_DELETE] = {
+			.handler = carry_delete,
+			.estimate = carry_estimate_delete}
+	,
+	[COP_CUT] = {
+		     .handler = carry_cut,
+		     .estimate = carry_estimate_cut}
+	,
+	[COP_PASTE] = {
+		       .handler = carry_paste,
+		       .estimate = carry_estimate_paste}
+	,
+	[COP_EXTENT] = {
+			.handler = carry_extent,
+			.estimate = carry_estimate_extent}
+	,
+	[COP_UPDATE] = {
+			.handler = carry_update,
+			.estimate = carry_estimate_update}
+	,
+	[COP_INSERT_FLOW] = {
+			     .handler = carry_insert_flow,
+			     .estimate = carry_estimate_insert_flow}
+};
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/carry_ops.h newtree/fs/reiser4/carry_ops.h
--- oldtree/fs/reiser4/carry_ops.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/carry_ops.h	2006-02-21 15:58:34.520898584 +0000
@@ -0,0 +1,42 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* implementation of carry operations. See carry_ops.c for details. */
+
+#if !defined( __CARRY_OPS_H__ )
+#define __CARRY_OPS_H__
+
+#include "forward.h"
+#include "znode.h"
+#include "carry.h"
+
+/* carry operation handlers */
+typedef struct carry_op_handler {
+	/* perform operation */
+	int (*handler) (carry_op * op, carry_level * doing, carry_level * todo);
+	/* estimate memory requirements for @op */
+	int (*estimate) (carry_op * op, carry_level * level);
+} carry_op_handler;
+
+/* This is dispatch table for carry operations. It can be trivially
+   abstracted into useful plugin: tunable balancing policy is a good
+   thing. */
+extern carry_op_handler op_dispatch_table[COP_LAST_OP];
+
+unsigned int space_needed(const znode * node, const coord_t * coord,
+			  const reiser4_item_data * data, int inserting);
+extern carry_node *find_left_carry(carry_node * node, carry_level * level);
+extern carry_node *find_right_carry(carry_node * node, carry_level * level);
+
+/* __CARRY_OPS_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/context.c newtree/fs/reiser4/context.c
--- oldtree/fs/reiser4/context.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/context.c	2006-02-21 15:58:35.472753880 +0000
@@ -0,0 +1,264 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Manipulation of reiser4_context */
+
+/*
+ * global context used during system call. Variable of this type is allocated
+ * on the stack at the beginning of the reiser4 part of the system call and
+ * pointer to it is stored in the current->fs_context. This allows us to avoid
+ * passing pointer to current transaction and current lockstack (both in
+ * one-to-one mapping with threads) all over the call chain.
+ *
+ * It's kind of like those global variables the prof used to tell you not to
+ * use in CS1, except thread specific.;-) Nikita, this was a good idea.
+ *
+ * In some situations it is desirable to have ability to enter reiser4_context
+ * more than once for the same thread (nested contexts). For example, there
+ * are some functions that can be called either directly from VFS/VM or from
+ * already active reiser4 context (->writepage, for example).
+ *
+ * In such situations "child" context acts like dummy: all activity is
+ * actually performed in the top level context, and get_current_context()
+ * always returns top level context. Of course, init_context()/done_context()
+ * have to be properly nested any way.
+ *
+ * Note that there is an important difference between reiser4 uses
+ * ->fs_context and the way other file systems use it. Other file systems
+ * (ext3 and reiserfs) use ->fs_context only for the duration of _transaction_
+ * (this is why ->fs_context was initially called ->journal_info). This means,
+ * that when ext3 or reiserfs finds that ->fs_context is not NULL on the entry
+ * to the file system, they assume that some transaction is already underway,
+ * and usually bail out, because starting nested transaction would most likely
+ * lead to the deadlock. This gives false positives with reiser4, because we
+ * set ->fs_context before starting transaction.
+ */
+
+#include "debug.h"
+#include "super.h"
+#include "context.h"
+
+#include <linux/writeback.h>	/* balance_dirty_pages() */
+#include <linux/hardirq.h>
+
+
+static void _init_context(reiser4_context * context, struct super_block *super)
+{
+	memset(context, 0, sizeof(*context));
+
+	context->super = super;
+	context->magic = context_magic;
+	context->outer = current->journal_info;
+	current->journal_info = (void *)context;
+	context->nr_children = 0;
+
+	init_lock_stack(&context->stack);
+
+	txn_begin(context);
+
+	/* initialize head of tap list */
+	INIT_LIST_HEAD(&context->taps);
+#if REISER4_DEBUG
+	context->task = current;
+#endif
+	grab_space_enable();
+}
+
+/* initialize context and bind it to the current thread
+
+   This function should be called at the beginning of reiser4 part of
+   syscall.
+*/
+reiser4_context *init_context(struct super_block *super	/* super block we are going to
+							 * work with */ )
+{
+	reiser4_context *context;
+
+	assert("nikita-2662", !in_interrupt() && !in_irq());
+	assert("nikita-3357", super != NULL);
+	assert("nikita-3358", super->s_op == NULL || is_reiser4_super(super));
+
+	context = get_current_context_check();
+	if (context && context->super == super) {
+		context = (reiser4_context *) current->journal_info;
+		context->nr_children++;
+		return context;
+	}
+
+	context = kmalloc(sizeof(*context), GFP_KERNEL);
+	if (context == NULL)
+		return ERR_PTR(RETERR(-ENOMEM));
+
+	_init_context(context, super);
+	return context;
+}
+
+/* this is used in scan_mgr which is called with spinlock held and in
+   reiser4_fill_super magic */
+void init_stack_context(reiser4_context *context, struct super_block *super)
+{
+	assert("nikita-2662", !in_interrupt() && !in_irq());
+	assert("nikita-3357", super != NULL);
+	assert("nikita-3358", super->s_op == NULL || is_reiser4_super(super));
+	assert("vs-12", !is_in_reiser4_context());
+
+	_init_context(context, super);
+	context->on_stack = 1;
+	return;
+}
+
+/* cast lock stack embedded into reiser4 context up to its container */
+reiser4_context *get_context_by_lock_stack(lock_stack * owner)
+{
+	return container_of(owner, reiser4_context, stack);
+}
+
+/* true if there is already _any_ reiser4 context for the current thread */
+int is_in_reiser4_context(void)
+{
+	reiser4_context *ctx;
+
+	ctx = current->journal_info;
+	return ctx != NULL && ((unsigned long)ctx->magic) == context_magic;
+}
+
+/*
+ * call balance dirty pages for the current context.
+ *
+ * File system is expected to call balance_dirty_pages_ratelimited() whenever
+ * it dirties a page. reiser4 does this for unformatted nodes (that is, during
+ * write---this covers vast majority of all dirty traffic), but we cannot do
+ * this immediately when formatted node is dirtied, because long term lock is
+ * usually held at that time. To work around this, dirtying of formatted node
+ * simply increases ->nr_marked_dirty counter in the current reiser4
+ * context. When we are about to leave this context,
+ * balance_dirty_pages_ratelimited() is called, if necessary.
+ *
+ * This introduces another problem: sometimes we do not want to run
+ * balance_dirty_pages_ratelimited() when leaving a context, for example
+ * because some important lock (like ->i_mutex on the parent directory) is
+ * held. To achieve this, ->nobalance flag can be set in the current context.
+ */
+static void balance_dirty_pages_at(reiser4_context *context)
+{
+	reiser4_super_info_data *sbinfo = get_super_private(context->super);
+
+	/*
+	 * call balance_dirty_pages_ratelimited() to process formatted nodes
+	 * dirtied during this system call. Do that only if we are not in mount
+	 * and there were nodes dirtied in this context and we are not in
+	 * writepage (to avoid deadlock) and not in pdflush
+	 */
+	if (sbinfo != NULL && sbinfo->fake != NULL &&
+	    context->nr_marked_dirty != 0 &&
+	    !(current->flags & PF_MEMALLOC) &&
+	    !current_is_pdflush())
+		balance_dirty_pages_ratelimited(sbinfo->fake->i_mapping);
+}
+
+/* release resources associated with context.
+
+   This function should be called at the end of "session" with reiser4,
+   typically just before leaving reiser4 driver back to VFS.
+
+   This is good place to put some degugging consistency checks, like that
+   thread released all locks and closed transcrash etc.
+
+*/
+static void done_context(reiser4_context * context /* context being released */ )
+{
+	assert("nikita-860", context != NULL);
+	assert("nikita-859", context->magic == context_magic);
+	assert("vs-646", (reiser4_context *) current->journal_info == context);
+	assert("zam-686", !in_interrupt() && !in_irq());
+
+	/* only do anything when leaving top-level reiser4 context. All nested
+	 * contexts are just dummies. */
+	if (context->nr_children == 0) {
+		assert("jmacd-673", context->trans == NULL);
+		assert("jmacd-1002", lock_stack_isclean(&context->stack));
+		assert("nikita-1936", no_counters_are_held());
+		assert("nikita-2626", list_empty_careful(taps_list()));
+		assert("zam-1004", ergo(get_super_private(context->super),
+					get_super_private(context->super)->delete_sema_owner !=
+					current));
+
+		/* release all grabbed but as yet unused blocks */
+		if (context->grabbed_blocks != 0)
+			all_grabbed2free();
+
+		/*
+		 * synchronize against longterm_unlock_znode():
+		 * wake_up_requestor() wakes up requestors without holding
+		 * zlock (otherwise they will immediately bump into that lock
+		 * after wake up on another CPU). To work around (rare)
+		 * situation where requestor has been woken up asynchronously
+		 * and managed to run until completion (and destroy its
+		 * context and lock stack) before wake_up_requestor() called
+		 * wake_up() on it, wake_up_requestor() synchronize on lock
+		 * stack spin lock. It has actually been observed that spin
+		 * lock _was_ locked at this point, because
+		 * wake_up_requestor() took interrupt.
+		 */
+		spin_lock_stack(&context->stack);
+		spin_unlock_stack(&context->stack);
+
+		assert("zam-684", context->nr_children == 0);
+		/* restore original ->fs_context value */
+		current->journal_info = context->outer;
+		if (context->on_stack == 0)
+			kfree(context);
+	} else {
+		context->nr_children--;
+#if REISER4_DEBUG
+		assert("zam-685", context->nr_children >= 0);
+#endif
+	}
+}
+
+/*
+ * exit reiser4 context. Call balance_dirty_pages_at() if necessary. Close
+ * transaction. Call done_context() to do context related book-keeping.
+ */
+void reiser4_exit_context(reiser4_context * context)
+{
+	assert("nikita-3021", schedulable());
+
+	if (context->nr_children == 0) {
+		if (!context->nobalance) {
+			txn_restart(context);
+			balance_dirty_pages_at(context);
+		}
+
+		/* if filesystem is mounted with -o sync or -o dirsync - commit
+		   transaction.  FIXME: TXNH_DONT_COMMIT is used to avoid
+		   commiting on exit_context when inode semaphore is held and
+		   to have ktxnmgrd to do commit instead to get better
+		   concurrent filesystem accesses. But, when one mounts with -o
+		   sync, he cares more about reliability than about
+		   performance. So, for now we have this simple mount -o sync
+		   support. */
+		if (context->super->s_flags & (MS_SYNCHRONOUS | MS_DIRSYNC)) {
+			txn_atom *atom;
+
+			atom = get_current_atom_locked_nocheck();
+			if (atom) {
+				atom->flags |= ATOM_FORCE_COMMIT;
+				context->trans->flags &= ~TXNH_DONT_COMMIT;
+				spin_unlock_atom(atom);
+			}
+		}
+		txn_end(context);
+	}
+	done_context(context);
+}
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 120
+ * scroll-step: 1
+ * End:
+ */
diff -urN oldtree/fs/reiser4/context.h newtree/fs/reiser4/context.h
--- oldtree/fs/reiser4/context.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/context.h	2006-02-21 15:58:35.473753728 +0000
@@ -0,0 +1,217 @@
+/* Copyright 2001, 2002, 2003, 2004 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Reiser4 context. See context.c for details. */
+
+#if !defined( __REISER4_CONTEXT_H__ )
+#define __REISER4_CONTEXT_H__
+
+#include "forward.h"
+#include "debug.h"
+#include "dformat.h"
+#include "tap.h"
+#include "lock.h"
+
+#include <linux/types.h>	/* for __u??  */
+#include <linux/fs.h>		/* for struct super_block  */
+#include <linux/spinlock.h>
+#include <linux/sched.h>	/* for struct task_struct */
+
+
+/* reiser4 per-thread context */
+struct reiser4_context {
+	/* magic constant. For identification of reiser4 contexts. */
+	__u32 magic;
+
+	/* current lock stack. See lock.[ch]. This is where list of all
+	   locks taken by current thread is kept. This is also used in
+	   deadlock detection. */
+	lock_stack stack;
+
+	/* current transcrash. */
+	txn_handle *trans;
+	/* transaction handle embedded into reiser4_context. ->trans points
+	 * here by default. */
+	txn_handle trans_in_ctx;
+
+	/* super block we are working with.  To get the current tree
+	   use &get_super_private (reiser4_get_current_sb ())->tree. */
+	struct super_block *super;
+
+	/* parent fs activation */
+	struct fs_activation *outer;
+
+	/* per-thread grabbed (for further allocation) blocks counter */
+	reiser4_block_nr grabbed_blocks;
+
+	/* list of taps currently monitored. See tap.c */
+	struct list_head taps;
+
+	/* grabbing space is enabled */
+	unsigned int grab_enabled:1;
+	/* should be set when we are write dirty nodes to disk in jnode_flush or
+	 * reiser4_write_logs() */
+	unsigned int writeout_mode:1;
+	/* true, if current thread is an ent thread */
+	unsigned int entd:1;
+	/* true, if balance_dirty_pages() should not be run when leaving this
+	 * context. This is used to avoid lengthly balance_dirty_pages()
+	 * operation when holding some important resource, like directory
+	 * ->i_mutex */
+	unsigned int nobalance:1;
+
+	/* this bit is used on done_context to decide whether context is
+	   kmalloc-ed and has to be kfree-ed */
+	unsigned int on_stack:1;
+
+	/* count non-trivial jnode_set_dirty() calls */
+	unsigned long nr_marked_dirty;
+
+	/* reiser4_sync_inodes calls (via generic_sync_sb_inodes)
+	 * reiser4_writepages for each of dirty inodes. Reiser4_writepages
+	 * captures pages. When number of pages captured in one
+	 * reiser4_sync_inodes reaches some threshold - some atoms get
+	 * flushed */
+	int nr_captured;
+	int nr_children;	/* number of child contexts */
+#if REISER4_DEBUG
+	/* debugging information about reiser4 locks held by the current
+	 * thread */
+	lock_counters_info locks;
+	struct task_struct *task;	/* so we can easily find owner of the stack */
+
+	/*
+	 * disk space grabbing debugging support
+	 */
+	/* how many disk blocks were grabbed by the first call to
+	 * reiser4_grab_space() in this context */
+	reiser4_block_nr grabbed_initially;
+
+	/* list of all threads doing flush currently */
+	struct list_head flushers_link;
+	/* information about last error encountered by reiser4 */
+	err_site err;
+#endif
+	void *vp;
+};
+
+extern reiser4_context *get_context_by_lock_stack(lock_stack *);
+
+/* Debugging helps. */
+#if REISER4_DEBUG
+extern void print_contexts(void);
+#endif
+
+#define current_tree (&(get_super_private(reiser4_get_current_sb())->tree))
+#define current_blocksize reiser4_get_current_sb()->s_blocksize
+#define current_blocksize_bits reiser4_get_current_sb()->s_blocksize_bits
+
+extern reiser4_context *init_context(struct super_block *);
+extern void init_stack_context(reiser4_context *, struct super_block *);
+extern void reiser4_exit_context(reiser4_context *);
+
+/* magic constant we store in reiser4_context allocated at the stack. Used to
+   catch accesses to staled or uninitialized contexts. */
+#define context_magic ((__u32) 0x4b1b5d0b)
+
+extern int is_in_reiser4_context(void);
+
+/*
+ * return reiser4_context for the thread @tsk
+ */
+static inline reiser4_context *get_context(const struct task_struct *tsk)
+{
+	assert("vs-1682",
+	       ((reiser4_context *) tsk->journal_info)->magic == context_magic);
+	return (reiser4_context *) tsk->journal_info;
+}
+
+/*
+ * return reiser4 context of the current thread, or NULL if there is none.
+ */
+static inline reiser4_context *get_current_context_check(void)
+{
+	if (is_in_reiser4_context())
+		return get_context(current);
+	else
+		return NULL;
+}
+
+static inline reiser4_context *get_current_context(void);	/* __attribute__((const)); */
+
+/* return context associated with current thread */
+static inline reiser4_context *get_current_context(void)
+{
+	return get_context(current);
+}
+
+/*
+ * true if current thread is in the write-out mode. Thread enters write-out
+ * mode during jnode_flush and reiser4_write_logs().
+ */
+static inline int is_writeout_mode(void)
+{
+	return get_current_context()->writeout_mode;
+}
+
+/*
+ * enter write-out mode
+ */
+static inline void writeout_mode_enable(void)
+{
+	assert("zam-941", !get_current_context()->writeout_mode);
+	get_current_context()->writeout_mode = 1;
+}
+
+/*
+ * leave write-out mode
+ */
+static inline void writeout_mode_disable(void)
+{
+	assert("zam-942", get_current_context()->writeout_mode);
+	get_current_context()->writeout_mode = 0;
+}
+
+static inline void grab_space_enable(void)
+{
+	get_current_context()->grab_enabled = 1;
+}
+
+static inline void grab_space_disable(void)
+{
+	get_current_context()->grab_enabled = 0;
+}
+
+static inline void grab_space_set_enabled(int enabled)
+{
+	get_current_context()->grab_enabled = enabled;
+}
+
+static inline int is_grab_enabled(reiser4_context * ctx)
+{
+	return ctx->grab_enabled;
+}
+
+/* mark transaction handle in @ctx as TXNH_DONT_COMMIT, so that no commit or
+ * flush would be performed when it is closed. This is necessary when handle
+ * has to be closed under some coarse semaphore, like i_mutex of
+ * directory. Commit will be performed by ktxnmgrd. */
+static inline void context_set_commit_async(reiser4_context * context)
+{
+	context->nobalance = 1;
+	context->trans->flags |= TXNH_DONT_COMMIT;
+}
+
+/* __REISER4_CONTEXT_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/coord.c newtree/fs/reiser4/coord.c
--- oldtree/fs/reiser4/coord.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/coord.c	2006-02-21 15:58:34.965830944 +0000
@@ -0,0 +1,937 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#include "forward.h"
+#include "debug.h"
+#include "dformat.h"
+#include "tree.h"
+#include "plugin/item/item.h"
+#include "znode.h"
+#include "coord.h"
+
+/* Internal constructor. */
+static inline void
+coord_init_values(coord_t * coord, const znode * node, pos_in_node_t item_pos,
+		  pos_in_node_t unit_pos, between_enum between)
+{
+	coord->node = (znode *) node;
+	coord_set_item_pos(coord, item_pos);
+	coord->unit_pos = unit_pos;
+	coord->between = between;
+	ON_DEBUG(coord->plug_v = 0);
+	ON_DEBUG(coord->body_v = 0);
+
+	/*ON_TRACE (TRACE_COORDS, "init coord %p node %p: %u %u %s\n", coord, node, item_pos, unit_pos, coord_tween_tostring (between)); */
+}
+
+/* after shifting of node content, coord previously set properly may become
+   invalid, try to "normalize" it. */
+void coord_normalize(coord_t * coord)
+{
+	znode *node;
+
+	node = coord->node;
+	assert("vs-683", node);
+
+	coord_clear_iplug(coord);
+
+	if (node_is_empty(node)) {
+		coord_init_first_unit(coord, node);
+	} else if ((coord->between == AFTER_ITEM)
+		   || (coord->between == AFTER_UNIT)) {
+		return;
+	} else if (coord->item_pos == coord_num_items(coord)
+		   && coord->between == BEFORE_ITEM) {
+		coord_dec_item_pos(coord);
+		coord->between = AFTER_ITEM;
+	} else if (coord->unit_pos == coord_num_units(coord)
+		   && coord->between == BEFORE_UNIT) {
+		coord->unit_pos--;
+		coord->between = AFTER_UNIT;
+	} else if (coord->item_pos == coord_num_items(coord)
+		   && coord->unit_pos == 0 && coord->between == BEFORE_UNIT) {
+		coord_dec_item_pos(coord);
+		coord->unit_pos = 0;
+		coord->between = AFTER_ITEM;
+	}
+}
+
+/* Copy a coordinate. */
+void coord_dup(coord_t * coord, const coord_t * old_coord)
+{
+	assert("jmacd-9800", coord_check(old_coord));
+	coord_dup_nocheck(coord, old_coord);
+}
+
+/* Copy a coordinate without check. Useful when old_coord->node is not
+   loaded. As in cbk_tree_lookup -> connect_znode -> connect_one_side */
+void coord_dup_nocheck(coord_t * coord, const coord_t * old_coord)
+{
+	coord->node = old_coord->node;
+	coord_set_item_pos(coord, old_coord->item_pos);
+	coord->unit_pos = old_coord->unit_pos;
+	coord->between = old_coord->between;
+	coord->iplugid = old_coord->iplugid;
+	ON_DEBUG(coord->plug_v = old_coord->plug_v);
+	ON_DEBUG(coord->body_v = old_coord->body_v);
+}
+
+/* Initialize an invalid coordinate. */
+void coord_init_invalid(coord_t * coord, const znode * node)
+{
+	coord_init_values(coord, node, 0, 0, INVALID_COORD);
+}
+
+void coord_init_first_unit_nocheck(coord_t * coord, const znode * node)
+{
+	coord_init_values(coord, node, 0, 0, AT_UNIT);
+}
+
+/* Initialize a coordinate to point at the first unit of the first item.  If the node is
+   empty, it is positioned at the EMPTY_NODE. */
+void coord_init_first_unit(coord_t * coord, const znode * node)
+{
+	int is_empty = node_is_empty(node);
+
+	coord_init_values(coord, node, 0, 0, (is_empty ? EMPTY_NODE : AT_UNIT));
+
+	assert("jmacd-9801", coord_check(coord));
+}
+
+/* Initialize a coordinate to point at the last unit of the last item.  If the node is
+   empty, it is positioned at the EMPTY_NODE. */
+void coord_init_last_unit(coord_t * coord, const znode * node)
+{
+	int is_empty = node_is_empty(node);
+
+	coord_init_values(coord, node,
+			  (is_empty ? 0 : node_num_items(node) - 1), 0,
+			  (is_empty ? EMPTY_NODE : AT_UNIT));
+	if (!is_empty)
+		coord->unit_pos = coord_last_unit_pos(coord);
+	assert("jmacd-9802", coord_check(coord));
+}
+
+/* Initialize a coordinate to before the first item.  If the node is empty, it is
+   positioned at the EMPTY_NODE. */
+void coord_init_before_first_item(coord_t * coord, const znode * node)
+{
+	int is_empty = node_is_empty(node);
+
+	coord_init_values(coord, node, 0, 0,
+			  (is_empty ? EMPTY_NODE : BEFORE_UNIT));
+
+	assert("jmacd-9803", coord_check(coord));
+}
+
+/* Initialize a coordinate to after the last item.  If the node is empty, it is positioned
+   at the EMPTY_NODE. */
+void coord_init_after_last_item(coord_t * coord, const znode * node)
+{
+	int is_empty = node_is_empty(node);
+
+	coord_init_values(coord, node,
+			  (is_empty ? 0 : node_num_items(node) - 1), 0,
+			  (is_empty ? EMPTY_NODE : AFTER_ITEM));
+
+	assert("jmacd-9804", coord_check(coord));
+}
+
+/* Initialize a coordinate to after last unit in the item. Coord must be set
+   already to existing item */
+void coord_init_after_item_end(coord_t * coord)
+{
+	coord->between = AFTER_UNIT;
+	coord->unit_pos = coord_last_unit_pos(coord);
+}
+
+/* Initialize a coordinate to before the item. Coord must be set already to existing item */
+void coord_init_before_item(coord_t * coord)
+{
+	coord->unit_pos = 0;
+	coord->between = BEFORE_ITEM;
+}
+
+/* Initialize a coordinate to after the item. Coord must be set already to existing item */
+void coord_init_after_item(coord_t * coord)
+{
+	coord->unit_pos = 0;
+	coord->between = AFTER_ITEM;
+}
+
+/* Initialize a coordinate by 0s. Used in places where init_coord was used and
+   it was not clear how actually */
+void coord_init_zero(coord_t * coord)
+{
+	memset(coord, 0, sizeof(*coord));
+}
+
+/* Return the number of units at the present item.  Asserts coord_is_existing_item(). */
+unsigned coord_num_units(const coord_t * coord)
+{
+	assert("jmacd-9806", coord_is_existing_item(coord));
+
+	return item_plugin_by_coord(coord)->b.nr_units(coord);
+}
+
+/* Returns true if the coord was initializewd by coord_init_invalid (). */
+/* Audited by: green(2002.06.15) */
+int coord_is_invalid(const coord_t * coord)
+{
+	return coord->between == INVALID_COORD;
+}
+
+/* Returns true if the coordinate is positioned at an existing item, not before or after
+   an item.  It may be placed at, before, or after any unit within the item, whether
+   existing or not. */
+int coord_is_existing_item(const coord_t * coord)
+{
+	switch (coord->between) {
+	case EMPTY_NODE:
+	case BEFORE_ITEM:
+	case AFTER_ITEM:
+	case INVALID_COORD:
+		return 0;
+
+	case BEFORE_UNIT:
+	case AT_UNIT:
+	case AFTER_UNIT:
+		return coord->item_pos < coord_num_items(coord);
+	}
+
+	impossible("jmacd-9900", "unreachable coord: %p", coord);
+	return 0;
+}
+
+/* Returns true if the coordinate is positioned at an existing unit, not before or after a
+   unit. */
+/* Audited by: green(2002.06.15) */
+int coord_is_existing_unit(const coord_t * coord)
+{
+	switch (coord->between) {
+	case EMPTY_NODE:
+	case BEFORE_UNIT:
+	case AFTER_UNIT:
+	case BEFORE_ITEM:
+	case AFTER_ITEM:
+	case INVALID_COORD:
+		return 0;
+
+	case AT_UNIT:
+		return (coord->item_pos < coord_num_items(coord)
+			&& coord->unit_pos < coord_num_units(coord));
+	}
+
+	impossible("jmacd-9902", "unreachable");
+	return 0;
+}
+
+/* Returns true if the coordinate is positioned at the first unit of the first item.  Not
+   true for empty nodes nor coordinates positioned before the first item. */
+/* Audited by: green(2002.06.15) */
+int coord_is_leftmost_unit(const coord_t * coord)
+{
+	return (coord->between == AT_UNIT && coord->item_pos == 0
+		&& coord->unit_pos == 0);
+}
+
+#if REISER4_DEBUG
+/* For assertions only, checks for a valid coordinate. */
+int coord_check(const coord_t * coord)
+{
+	if (coord->node == NULL) {
+		return 0;
+	}
+	if (znode_above_root(coord->node))
+		return 1;
+
+	switch (coord->between) {
+	default:
+	case INVALID_COORD:
+		return 0;
+	case EMPTY_NODE:
+		if (!node_is_empty(coord->node)) {
+			return 0;
+		}
+		return coord->item_pos == 0 && coord->unit_pos == 0;
+
+	case BEFORE_UNIT:
+	case AFTER_UNIT:
+		if (node_is_empty(coord->node) && (coord->item_pos == 0)
+		    && (coord->unit_pos == 0))
+			return 1;
+	case AT_UNIT:
+		break;
+	case AFTER_ITEM:
+	case BEFORE_ITEM:
+		/* before/after item should not set unit_pos. */
+		if (coord->unit_pos != 0) {
+			return 0;
+		}
+		break;
+	}
+
+	if (coord->item_pos >= node_num_items(coord->node)) {
+		return 0;
+	}
+
+	/* FIXME-VS: we are going to check unit_pos. This makes no sense when
+	   between is set either AFTER_ITEM or BEFORE_ITEM */
+	if (coord->between == AFTER_ITEM || coord->between == BEFORE_ITEM)
+		return 1;
+
+	if (coord_is_iplug_set(coord) &&
+	    coord->unit_pos >
+	    item_plugin_by_coord(coord)->b.nr_units(coord) - 1) {
+		return 0;
+	}
+	return 1;
+}
+#endif
+
+/* Adjust coordinate boundaries based on the number of items prior to coord_next/prev.
+   Returns 1 if the new position is does not exist. */
+static int coord_adjust_items(coord_t * coord, unsigned items, int is_next)
+{
+	/* If the node is invalid, leave it. */
+	if (coord->between == INVALID_COORD) {
+		return 1;
+	}
+
+	/* If the node is empty, set it appropriately. */
+	if (items == 0) {
+		coord->between = EMPTY_NODE;
+		coord_set_item_pos(coord, 0);
+		coord->unit_pos = 0;
+		return 1;
+	}
+
+	/* If it was empty and it no longer is, set to BEFORE/AFTER_ITEM. */
+	if (coord->between == EMPTY_NODE) {
+		coord->between = (is_next ? BEFORE_ITEM : AFTER_ITEM);
+		coord_set_item_pos(coord, 0);
+		coord->unit_pos = 0;
+		return 0;
+	}
+
+	/* If the item_pos is out-of-range, set it appropriatly. */
+	if (coord->item_pos >= items) {
+		coord->between = AFTER_ITEM;
+		coord_set_item_pos(coord, items - 1);
+		coord->unit_pos = 0;
+		/* If is_next, return 1 (can't go any further). */
+		return is_next;
+	}
+
+	return 0;
+}
+
+/* Advances the coordinate by one unit to the right.  If empty, no change.  If
+   coord_is_rightmost_unit, advances to AFTER THE LAST ITEM.  Returns 0 if new position is an
+   existing unit. */
+int coord_next_unit(coord_t * coord)
+{
+	unsigned items = coord_num_items(coord);
+
+	if (coord_adjust_items(coord, items, 1) == 1) {
+		return 1;
+	}
+
+	switch (coord->between) {
+	case BEFORE_UNIT:
+		/* Now it is positioned at the same unit. */
+		coord->between = AT_UNIT;
+		return 0;
+
+	case AFTER_UNIT:
+	case AT_UNIT:
+		/* If it was at or after a unit and there are more units in this item,
+		   advance to the next one. */
+		if (coord->unit_pos < coord_last_unit_pos(coord)) {
+			coord->unit_pos += 1;
+			coord->between = AT_UNIT;
+			return 0;
+		}
+
+		/* Otherwise, it is crossing an item boundary and treated as if it was
+		   after the current item. */
+		coord->between = AFTER_ITEM;
+		coord->unit_pos = 0;
+		/* FALLTHROUGH */
+
+	case AFTER_ITEM:
+		/* Check for end-of-node. */
+		if (coord->item_pos == items - 1) {
+			return 1;
+		}
+
+		coord_inc_item_pos(coord);
+		coord->unit_pos = 0;
+		coord->between = AT_UNIT;
+		return 0;
+
+	case BEFORE_ITEM:
+		/* The adjust_items checks ensure that we are valid here. */
+		coord->unit_pos = 0;
+		coord->between = AT_UNIT;
+		return 0;
+
+	case INVALID_COORD:
+	case EMPTY_NODE:
+		/* Handled in coord_adjust_items(). */
+		break;
+	}
+
+	impossible("jmacd-9902", "unreachable");
+	return 0;
+}
+
+/* Advances the coordinate by one item to the right.  If empty, no change.  If
+   coord_is_rightmost_unit, advances to AFTER THE LAST ITEM.  Returns 0 if new position is
+   an existing item. */
+int coord_next_item(coord_t * coord)
+{
+	unsigned items = coord_num_items(coord);
+
+	if (coord_adjust_items(coord, items, 1) == 1) {
+		return 1;
+	}
+
+	switch (coord->between) {
+	case AFTER_UNIT:
+	case AT_UNIT:
+	case BEFORE_UNIT:
+	case AFTER_ITEM:
+		/* Check for end-of-node. */
+		if (coord->item_pos == items - 1) {
+			coord->between = AFTER_ITEM;
+			coord->unit_pos = 0;
+			coord_clear_iplug(coord);
+			return 1;
+		}
+
+		/* Anywhere in an item, go to the next one. */
+		coord->between = AT_UNIT;
+		coord_inc_item_pos(coord);
+		coord->unit_pos = 0;
+		return 0;
+
+	case BEFORE_ITEM:
+		/* The out-of-range check ensures that we are valid here. */
+		coord->unit_pos = 0;
+		coord->between = AT_UNIT;
+		return 0;
+	case INVALID_COORD:
+	case EMPTY_NODE:
+		/* Handled in coord_adjust_items(). */
+		break;
+	}
+
+	impossible("jmacd-9903", "unreachable");
+	return 0;
+}
+
+/* Advances the coordinate by one unit to the left.  If empty, no change.  If
+   coord_is_leftmost_unit, advances to BEFORE THE FIRST ITEM.  Returns 0 if new position
+   is an existing unit. */
+int coord_prev_unit(coord_t * coord)
+{
+	unsigned items = coord_num_items(coord);
+
+	if (coord_adjust_items(coord, items, 0) == 1) {
+		return 1;
+	}
+
+	switch (coord->between) {
+	case AT_UNIT:
+	case BEFORE_UNIT:
+		if (coord->unit_pos > 0) {
+			coord->unit_pos -= 1;
+			coord->between = AT_UNIT;
+			return 0;
+		}
+
+		if (coord->item_pos == 0) {
+			coord->between = BEFORE_ITEM;
+			return 1;
+		}
+
+		coord_dec_item_pos(coord);
+		coord->unit_pos = coord_last_unit_pos(coord);
+		coord->between = AT_UNIT;
+		return 0;
+
+	case AFTER_UNIT:
+		/* What if unit_pos is out-of-range? */
+		assert("jmacd-5442",
+		       coord->unit_pos <= coord_last_unit_pos(coord));
+		coord->between = AT_UNIT;
+		return 0;
+
+	case BEFORE_ITEM:
+		if (coord->item_pos == 0) {
+			return 1;
+		}
+
+		coord_dec_item_pos(coord);
+		/* FALLTHROUGH */
+
+	case AFTER_ITEM:
+		coord->between = AT_UNIT;
+		coord->unit_pos = coord_last_unit_pos(coord);
+		return 0;
+
+	case INVALID_COORD:
+	case EMPTY_NODE:
+		break;
+	}
+
+	impossible("jmacd-9904", "unreachable");
+	return 0;
+}
+
+/* Advances the coordinate by one item to the left.  If empty, no change.  If
+   coord_is_leftmost_unit, advances to BEFORE THE FIRST ITEM.  Returns 0 if new position
+   is an existing item. */
+int coord_prev_item(coord_t * coord)
+{
+	unsigned items = coord_num_items(coord);
+
+	if (coord_adjust_items(coord, items, 0) == 1) {
+		return 1;
+	}
+
+	switch (coord->between) {
+	case AT_UNIT:
+	case AFTER_UNIT:
+	case BEFORE_UNIT:
+	case BEFORE_ITEM:
+
+		if (coord->item_pos == 0) {
+			coord->between = BEFORE_ITEM;
+			coord->unit_pos = 0;
+			return 1;
+		}
+
+		coord_dec_item_pos(coord);
+		coord->unit_pos = 0;
+		coord->between = AT_UNIT;
+		return 0;
+
+	case AFTER_ITEM:
+		coord->between = AT_UNIT;
+		coord->unit_pos = 0;
+		return 0;
+
+	case INVALID_COORD:
+	case EMPTY_NODE:
+		break;
+	}
+
+	impossible("jmacd-9905", "unreachable");
+	return 0;
+}
+
+/* Calls either coord_init_first_unit or coord_init_last_unit depending on sideof argument. */
+void coord_init_sideof_unit(coord_t * coord, const znode * node, sideof dir)
+{
+	assert("jmacd-9821", dir == LEFT_SIDE || dir == RIGHT_SIDE);
+	if (dir == LEFT_SIDE) {
+		coord_init_first_unit(coord, node);
+	} else {
+		coord_init_last_unit(coord, node);
+	}
+}
+
+/* Calls either coord_is_before_leftmost or coord_is_after_rightmost depending on sideof
+   argument. */
+/* Audited by: green(2002.06.15) */
+int coord_is_after_sideof_unit(coord_t * coord, sideof dir)
+{
+	assert("jmacd-9822", dir == LEFT_SIDE || dir == RIGHT_SIDE);
+	if (dir == LEFT_SIDE) {
+		return coord_is_before_leftmost(coord);
+	} else {
+		return coord_is_after_rightmost(coord);
+	}
+}
+
+/* Calls either coord_next_unit or coord_prev_unit depending on sideof argument. */
+/* Audited by: green(2002.06.15) */
+int coord_sideof_unit(coord_t * coord, sideof dir)
+{
+	assert("jmacd-9823", dir == LEFT_SIDE || dir == RIGHT_SIDE);
+	if (dir == LEFT_SIDE) {
+		return coord_prev_unit(coord);
+	} else {
+		return coord_next_unit(coord);
+	}
+}
+
+#if REISER4_DEBUG
+#define DEBUG_COORD_FIELDS (sizeof(c1->plug_v) + sizeof(c1->body_v))
+#else
+#define DEBUG_COORD_FIELDS (0)
+#endif
+
+int coords_equal(const coord_t * c1, const coord_t * c2)
+{
+	assert("nikita-2840", c1 != NULL);
+	assert("nikita-2841", c2 != NULL);
+
+	return
+	    c1->node == c2->node &&
+	    c1->item_pos == c2->item_pos &&
+	    c1->unit_pos == c2->unit_pos && c1->between == c2->between;
+}
+
+/* If coord_is_after_rightmost return NCOORD_ON_THE_RIGHT, if coord_is_after_leftmost
+   return NCOORD_ON_THE_LEFT, otherwise return NCOORD_INSIDE. */
+/* Audited by: green(2002.06.15) */
+coord_wrt_node coord_wrt(const coord_t * coord)
+{
+	if (coord_is_before_leftmost(coord)) {
+		return COORD_ON_THE_LEFT;
+	}
+
+	if (coord_is_after_rightmost(coord)) {
+		return COORD_ON_THE_RIGHT;
+	}
+
+	return COORD_INSIDE;
+}
+
+/* Returns true if the coordinate is positioned after the last item or after the last unit
+   of the last item or it is an empty node. */
+/* Audited by: green(2002.06.15) */
+int coord_is_after_rightmost(const coord_t * coord)
+{
+	assert("jmacd-7313", coord_check(coord));
+
+	switch (coord->between) {
+	case INVALID_COORD:
+	case AT_UNIT:
+	case BEFORE_UNIT:
+	case BEFORE_ITEM:
+		return 0;
+
+	case EMPTY_NODE:
+		return 1;
+
+	case AFTER_ITEM:
+		return (coord->item_pos == node_num_items(coord->node) - 1);
+
+	case AFTER_UNIT:
+		return ((coord->item_pos == node_num_items(coord->node) - 1) &&
+			coord->unit_pos == coord_last_unit_pos(coord));
+	}
+
+	impossible("jmacd-9908", "unreachable");
+	return 0;
+}
+
+/* Returns true if the coordinate is positioned before the first item or it is an empty
+   node. */
+int coord_is_before_leftmost(const coord_t * coord)
+{
+	/* FIXME-VS: coord_check requires node to be loaded whereas it is not
+	   necessary to check if coord is set before leftmost
+	   assert ("jmacd-7313", coord_check (coord)); */
+	switch (coord->between) {
+	case INVALID_COORD:
+	case AT_UNIT:
+	case AFTER_ITEM:
+	case AFTER_UNIT:
+		return 0;
+
+	case EMPTY_NODE:
+		return 1;
+
+	case BEFORE_ITEM:
+	case BEFORE_UNIT:
+		return (coord->item_pos == 0) && (coord->unit_pos == 0);
+	}
+
+	impossible("jmacd-9908", "unreachable");
+	return 0;
+}
+
+/* Returns true if the coordinate is positioned after a item, before a item, after the
+   last unit of an item, before the first unit of an item, or at an empty node. */
+/* Audited by: green(2002.06.15) */
+int coord_is_between_items(const coord_t * coord)
+{
+	assert("jmacd-7313", coord_check(coord));
+
+	switch (coord->between) {
+	case INVALID_COORD:
+	case AT_UNIT:
+		return 0;
+
+	case AFTER_ITEM:
+	case BEFORE_ITEM:
+	case EMPTY_NODE:
+		return 1;
+
+	case BEFORE_UNIT:
+		return coord->unit_pos == 0;
+
+	case AFTER_UNIT:
+		return coord->unit_pos == coord_last_unit_pos(coord);
+	}
+
+	impossible("jmacd-9908", "unreachable");
+	return 0;
+}
+
+/* Returns true if the coordinates are positioned at adjacent units, regardless of
+   before-after or item boundaries. */
+int coord_are_neighbors(coord_t * c1, coord_t * c2)
+{
+	coord_t *left;
+	coord_t *right;
+
+	assert("nikita-1241", c1 != NULL);
+	assert("nikita-1242", c2 != NULL);
+	assert("nikita-1243", c1->node == c2->node);
+	assert("nikita-1244", coord_is_existing_unit(c1));
+	assert("nikita-1245", coord_is_existing_unit(c2));
+
+	left = right = NULL;
+	switch (coord_compare(c1, c2)) {
+	case COORD_CMP_ON_LEFT:
+		left = c1;
+		right = c2;
+		break;
+	case COORD_CMP_ON_RIGHT:
+		left = c2;
+		right = c1;
+		break;
+	case COORD_CMP_SAME:
+		return 0;
+	default:
+		wrong_return_value("nikita-1246", "compare_coords()");
+	}
+	assert("vs-731", left && right);
+	if (left->item_pos == right->item_pos) {
+		return left->unit_pos + 1 == right->unit_pos;
+	} else if (left->item_pos + 1 == right->item_pos) {
+		return (left->unit_pos == coord_last_unit_pos(left))
+		    && (right->unit_pos == 0);
+	} else {
+		return 0;
+	}
+}
+
+/* Assuming two coordinates are positioned in the same node, return COORD_CMP_ON_RIGHT,
+   COORD_CMP_ON_LEFT, or COORD_CMP_SAME depending on c1's position relative to c2.  */
+/* Audited by: green(2002.06.15) */
+coord_cmp coord_compare(coord_t * c1, coord_t * c2)
+{
+	assert("vs-209", c1->node == c2->node);
+	assert("vs-194", coord_is_existing_unit(c1)
+	       && coord_is_existing_unit(c2));
+
+	if (c1->item_pos > c2->item_pos)
+		return COORD_CMP_ON_RIGHT;
+	if (c1->item_pos < c2->item_pos)
+		return COORD_CMP_ON_LEFT;
+	if (c1->unit_pos > c2->unit_pos)
+		return COORD_CMP_ON_RIGHT;
+	if (c1->unit_pos < c2->unit_pos)
+		return COORD_CMP_ON_LEFT;
+	return COORD_CMP_SAME;
+}
+
+/* If the coordinate is between items, shifts it to the right.  Returns 0 on success and
+   non-zero if there is no position to the right. */
+int coord_set_to_right(coord_t * coord)
+{
+	unsigned items = coord_num_items(coord);
+
+	if (coord_adjust_items(coord, items, 1) == 1) {
+		return 1;
+	}
+
+	switch (coord->between) {
+	case AT_UNIT:
+		return 0;
+
+	case BEFORE_ITEM:
+	case BEFORE_UNIT:
+		coord->between = AT_UNIT;
+		return 0;
+
+	case AFTER_UNIT:
+		if (coord->unit_pos < coord_last_unit_pos(coord)) {
+			coord->unit_pos += 1;
+			coord->between = AT_UNIT;
+			return 0;
+		} else {
+
+			coord->unit_pos = 0;
+
+			if (coord->item_pos == items - 1) {
+				coord->between = AFTER_ITEM;
+				return 1;
+			}
+
+			coord_inc_item_pos(coord);
+			coord->between = AT_UNIT;
+			return 0;
+		}
+
+	case AFTER_ITEM:
+		if (coord->item_pos == items - 1) {
+			return 1;
+		}
+
+		coord_inc_item_pos(coord);
+		coord->unit_pos = 0;
+		coord->between = AT_UNIT;
+		return 0;
+
+	case EMPTY_NODE:
+		return 1;
+
+	case INVALID_COORD:
+		break;
+	}
+
+	impossible("jmacd-9920", "unreachable");
+	return 0;
+}
+
+/* If the coordinate is between items, shifts it to the left.  Returns 0 on success and
+   non-zero if there is no position to the left. */
+int coord_set_to_left(coord_t * coord)
+{
+	unsigned items = coord_num_items(coord);
+
+	if (coord_adjust_items(coord, items, 0) == 1) {
+		return 1;
+	}
+
+	switch (coord->between) {
+	case AT_UNIT:
+		return 0;
+
+	case AFTER_UNIT:
+		coord->between = AT_UNIT;
+		return 0;
+
+	case AFTER_ITEM:
+		coord->between = AT_UNIT;
+		coord->unit_pos = coord_last_unit_pos(coord);
+		return 0;
+
+	case BEFORE_UNIT:
+		if (coord->unit_pos > 0) {
+			coord->unit_pos -= 1;
+			coord->between = AT_UNIT;
+			return 0;
+		} else {
+
+			if (coord->item_pos == 0) {
+				coord->between = BEFORE_ITEM;
+				return 1;
+			}
+
+			coord->unit_pos = coord_last_unit_pos(coord);
+			coord_dec_item_pos(coord);
+			coord->between = AT_UNIT;
+			return 0;
+		}
+
+	case BEFORE_ITEM:
+		if (coord->item_pos == 0) {
+			return 1;
+		}
+
+		coord_dec_item_pos(coord);
+		coord->unit_pos = coord_last_unit_pos(coord);
+		coord->between = AT_UNIT;
+		return 0;
+
+	case EMPTY_NODE:
+		return 1;
+
+	case INVALID_COORD:
+		break;
+	}
+
+	impossible("jmacd-9920", "unreachable");
+	return 0;
+}
+
+static const char *coord_tween_tostring(between_enum n)
+{
+	switch (n) {
+	case BEFORE_UNIT:
+		return "before unit";
+	case BEFORE_ITEM:
+		return "before item";
+	case AT_UNIT:
+		return "at unit";
+	case AFTER_UNIT:
+		return "after unit";
+	case AFTER_ITEM:
+		return "after item";
+	case EMPTY_NODE:
+		return "empty node";
+	case INVALID_COORD:
+		return "invalid";
+	default:
+	{
+		static char buf[30];
+
+		sprintf(buf, "unknown: %i", n);
+		return buf;
+	}
+	}
+}
+
+void print_coord(const char *mes, const coord_t * coord, int node)
+{
+	if (coord == NULL) {
+		printk("%s: null\n", mes);
+		return;
+	}
+	printk("%s: item_pos = %d, unit_pos %d, tween=%s, iplug=%d\n",
+	       mes, coord->item_pos, coord->unit_pos,
+	       coord_tween_tostring(coord->between), coord->iplugid);
+}
+
+int
+item_utmost_child_real_block(const coord_t * coord, sideof side,
+			     reiser4_block_nr * blk)
+{
+	return item_plugin_by_coord(coord)->f.utmost_child_real_block(coord,
+								      side,
+								      blk);
+}
+
+int item_utmost_child(const coord_t * coord, sideof side, jnode ** child)
+{
+	return item_plugin_by_coord(coord)->f.utmost_child(coord, side, child);
+}
+
+/* @count bytes of flow @f got written, update correspondingly f->length,
+   f->data and f->key */
+void move_flow_forward(flow_t * f, unsigned count)
+{
+	if (f->data)
+		f->data += count;
+	f->length -= count;
+	set_key_offset(&f->key, get_key_offset(&f->key) + count);
+}
+
+/*
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/coord.h newtree/fs/reiser4/coord.h
--- oldtree/fs/reiser4/coord.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/coord.h	2006-02-21 15:58:34.525897824 +0000
@@ -0,0 +1,389 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Coords */
+
+#if !defined( __REISER4_COORD_H__ )
+#define __REISER4_COORD_H__
+
+#include "forward.h"
+#include "debug.h"
+#include "dformat.h"
+#include "key.h"
+
+/* insertions happen between coords in the tree, so we need some means
+   of specifying the sense of betweenness. */
+typedef enum {
+	BEFORE_UNIT,		/* Note: we/init_coord depends on this value being zero. */
+	AT_UNIT,
+	AFTER_UNIT,
+	BEFORE_ITEM,
+	AFTER_ITEM,
+	INVALID_COORD,
+	EMPTY_NODE,
+} between_enum;
+
+/* location of coord w.r.t. its node */
+typedef enum {
+	COORD_ON_THE_LEFT = -1,
+	COORD_ON_THE_RIGHT = +1,
+	COORD_INSIDE = 0
+} coord_wrt_node;
+
+typedef enum {
+	COORD_CMP_SAME = 0, COORD_CMP_ON_LEFT = -1, COORD_CMP_ON_RIGHT = +1
+} coord_cmp;
+
+struct coord {
+	/* node in a tree */
+	/*  0 */ znode *node;
+
+	/* position of item within node */
+	/*  4 */ pos_in_node_t item_pos;
+	/* position of unit within item */
+	/*  6 */ pos_in_node_t unit_pos;
+	/* optimization: plugin of item is stored in coord_t. Until this was
+	   implemented, item_plugin_by_coord() was major CPU consumer. ->iplugid
+	   is invalidated (set to 0xff) on each modification of ->item_pos,
+	   and all such modifications are funneled through coord_*_item_pos()
+	   functions below.
+	 */
+	/*  8 */ char iplugid;
+	/* position of coord w.r.t. to neighboring items and/or units.
+	   Values are taken from &between_enum above.
+	 */
+	/*  9 */ char between;
+	/* padding. It will be added by the compiler anyway to conform to the
+	 * C language alignment requirements. We keep it here to be on the
+	 * safe side and to have a clear picture of the memory layout of this
+	 * structure. */
+	/* 10 */ __u16 pad;
+	/* 12 */ int offset;
+#if REISER4_DEBUG
+	unsigned long plug_v;
+	unsigned long body_v;
+#endif
+};
+
+#define INVALID_PLUGID  ((char)((1 << 8) - 1))
+#define INVALID_OFFSET -1
+
+static inline void coord_clear_iplug(coord_t * coord)
+{
+	assert("nikita-2835", coord != NULL);
+	coord->iplugid = INVALID_PLUGID;
+	coord->offset = INVALID_OFFSET;
+}
+
+static inline int coord_is_iplug_set(const coord_t * coord)
+{
+	assert("nikita-2836", coord != NULL);
+	return coord->iplugid != INVALID_PLUGID;
+}
+
+static inline void coord_set_item_pos(coord_t * coord, pos_in_node_t pos)
+{
+	assert("nikita-2478", coord != NULL);
+	coord->item_pos = pos;
+	coord_clear_iplug(coord);
+}
+
+static inline void coord_dec_item_pos(coord_t * coord)
+{
+	assert("nikita-2480", coord != NULL);
+	--coord->item_pos;
+	coord_clear_iplug(coord);
+}
+
+static inline void coord_inc_item_pos(coord_t * coord)
+{
+	assert("nikita-2481", coord != NULL);
+	++coord->item_pos;
+	coord_clear_iplug(coord);
+}
+
+static inline void coord_add_item_pos(coord_t * coord, int delta)
+{
+	assert("nikita-2482", coord != NULL);
+	coord->item_pos += delta;
+	coord_clear_iplug(coord);
+}
+
+static inline void coord_invalid_item_pos(coord_t * coord)
+{
+	assert("nikita-2832", coord != NULL);
+	coord->item_pos = (unsigned short)~0;
+	coord_clear_iplug(coord);
+}
+
+/* Reverse a direction. */
+static inline sideof sideof_reverse(sideof side)
+{
+	return side == LEFT_SIDE ? RIGHT_SIDE : LEFT_SIDE;
+}
+
+/* NOTE: There is a somewhat odd mixture of the following opposed terms:
+
+   "first" and "last"
+   "next" and "prev"
+   "before" and "after"
+   "leftmost" and "rightmost"
+
+   But I think the chosen names are decent the way they are.
+*/
+
+/* COORD INITIALIZERS */
+
+/* Initialize an invalid coordinate. */
+extern void coord_init_invalid(coord_t * coord, const znode * node);
+
+extern void coord_init_first_unit_nocheck(coord_t * coord, const znode * node);
+
+/* Initialize a coordinate to point at the first unit of the first item.  If the node is
+   empty, it is positioned at the EMPTY_NODE. */
+extern void coord_init_first_unit(coord_t * coord, const znode * node);
+
+/* Initialize a coordinate to point at the last unit of the last item.  If the node is
+   empty, it is positioned at the EMPTY_NODE. */
+extern void coord_init_last_unit(coord_t * coord, const znode * node);
+
+/* Initialize a coordinate to before the first item.  If the node is empty, it is
+   positioned at the EMPTY_NODE. */
+extern void coord_init_before_first_item(coord_t * coord, const znode * node);
+
+/* Initialize a coordinate to after the last item.  If the node is empty, it is positioned
+   at the EMPTY_NODE. */
+extern void coord_init_after_last_item(coord_t * coord, const znode * node);
+
+/* Initialize a coordinate to after last unit in the item. Coord must be set
+   already to existing item */
+void coord_init_after_item_end(coord_t * coord);
+
+/* Initialize a coordinate to before the item. Coord must be set already to existing item */
+void coord_init_before_item(coord_t *);
+/* Initialize a coordinate to after the item. Coord must be set already to existing item */
+void coord_init_after_item(coord_t *);
+
+/* Calls either coord_init_first_unit or coord_init_last_unit depending on sideof argument. */
+extern void coord_init_sideof_unit(coord_t * coord, const znode * node,
+				   sideof dir);
+
+/* Initialize a coordinate by 0s. Used in places where init_coord was used and
+   it was not clear how actually
+   FIXME-VS: added by vs (2002, june, 8) */
+extern void coord_init_zero(coord_t * coord);
+
+/* COORD METHODS */
+
+/* after shifting of node content, coord previously set properly may become
+   invalid, try to "normalize" it. */
+void coord_normalize(coord_t * coord);
+
+/* Copy a coordinate. */
+extern void coord_dup(coord_t * coord, const coord_t * old_coord);
+
+/* Copy a coordinate without check. */
+void coord_dup_nocheck(coord_t * coord, const coord_t * old_coord);
+
+unsigned coord_num_units(const coord_t * coord);
+
+/* Return the last valid unit number at the present item (i.e.,
+   coord_num_units() - 1). */
+static inline unsigned coord_last_unit_pos(const coord_t * coord)
+{
+	return coord_num_units(coord) - 1;
+}
+
+#if REISER4_DEBUG
+/* For assertions only, checks for a valid coordinate. */
+extern int coord_check(const coord_t * coord);
+
+extern unsigned long znode_times_locked(const znode * z);
+
+static inline void coord_update_v(coord_t * coord)
+{
+	coord->plug_v = coord->body_v = znode_times_locked(coord->node);
+}
+#endif
+
+extern int coords_equal(const coord_t * c1, const coord_t * c2);
+
+extern void print_coord(const char *mes, const coord_t * coord, int print_node);
+
+/* If coord_is_after_rightmost return NCOORD_ON_THE_RIGHT, if coord_is_after_leftmost
+   return NCOORD_ON_THE_LEFT, otherwise return NCOORD_INSIDE. */
+extern coord_wrt_node coord_wrt(const coord_t * coord);
+
+/* Returns true if the coordinates are positioned at adjacent units, regardless of
+   before-after or item boundaries. */
+extern int coord_are_neighbors(coord_t * c1, coord_t * c2);
+
+/* Assuming two coordinates are positioned in the same node, return NCOORD_CMP_ON_RIGHT,
+   NCOORD_CMP_ON_LEFT, or NCOORD_CMP_SAME depending on c1's position relative to c2.  */
+extern coord_cmp coord_compare(coord_t * c1, coord_t * c2);
+
+/* COORD PREDICATES */
+
+/* Returns true if the coord was initializewd by coord_init_invalid (). */
+extern int coord_is_invalid(const coord_t * coord);
+
+/* Returns true if the coordinate is positioned at an existing item, not before or after
+   an item.  It may be placed at, before, or after any unit within the item, whether
+   existing or not.  If this is true you can call methods of the item plugin.  */
+extern int coord_is_existing_item(const coord_t * coord);
+
+/* Returns true if the coordinate is positioned after a item, before a item, after the
+   last unit of an item, before the first unit of an item, or at an empty node. */
+extern int coord_is_between_items(const coord_t * coord);
+
+/* Returns true if the coordinate is positioned at an existing unit, not before or after a
+   unit. */
+extern int coord_is_existing_unit(const coord_t * coord);
+
+/* Returns true if the coordinate is positioned at an empty node. */
+extern int coord_is_empty(const coord_t * coord);
+
+/* Returns true if the coordinate is positioned at the first unit of the first item.  Not
+   true for empty nodes nor coordinates positioned before the first item. */
+extern int coord_is_leftmost_unit(const coord_t * coord);
+
+/* Returns true if the coordinate is positioned after the last item or after the last unit
+   of the last item or it is an empty node. */
+extern int coord_is_after_rightmost(const coord_t * coord);
+
+/* Returns true if the coordinate is positioned before the first item or it is an empty
+   node. */
+extern int coord_is_before_leftmost(const coord_t * coord);
+
+/* Calls either coord_is_before_leftmost or coord_is_after_rightmost depending on sideof
+   argument. */
+extern int coord_is_after_sideof_unit(coord_t * coord, sideof dir);
+
+/* COORD MODIFIERS */
+
+/* Advances the coordinate by one unit to the right.  If empty, no change.  If
+   coord_is_rightmost_unit, advances to AFTER THE LAST ITEM.  Returns 0 if new position is
+   an existing unit. */
+extern int coord_next_unit(coord_t * coord);
+
+/* Advances the coordinate by one item to the right.  If empty, no change.  If
+   coord_is_rightmost_unit, advances to AFTER THE LAST ITEM.  Returns 0 if new position is
+   an existing item. */
+extern int coord_next_item(coord_t * coord);
+
+/* Advances the coordinate by one unit to the left.  If empty, no change.  If
+   coord_is_leftmost_unit, advances to BEFORE THE FIRST ITEM.  Returns 0 if new position
+   is an existing unit. */
+extern int coord_prev_unit(coord_t * coord);
+
+/* Advances the coordinate by one item to the left.  If empty, no change.  If
+   coord_is_leftmost_unit, advances to BEFORE THE FIRST ITEM.  Returns 0 if new position
+   is an existing item. */
+extern int coord_prev_item(coord_t * coord);
+
+/* If the coordinate is between items, shifts it to the right.  Returns 0 on success and
+   non-zero if there is no position to the right. */
+extern int coord_set_to_right(coord_t * coord);
+
+/* If the coordinate is between items, shifts it to the left.  Returns 0 on success and
+   non-zero if there is no position to the left. */
+extern int coord_set_to_left(coord_t * coord);
+
+/* If the coordinate is at an existing unit, set to after that unit.  Returns 0 on success
+   and non-zero if the unit did not exist. */
+extern int coord_set_after_unit(coord_t * coord);
+
+/* Calls either coord_next_unit or coord_prev_unit depending on sideof argument. */
+extern int coord_sideof_unit(coord_t * coord, sideof dir);
+
+/* iterate over all units in @node */
+#define for_all_units( coord, node )					\
+	for( coord_init_before_first_item( ( coord ), ( node ) ) ; 	\
+	     coord_next_unit( coord ) == 0 ; )
+
+/* iterate over all items in @node */
+#define for_all_items( coord, node )					\
+	for( coord_init_before_first_item( ( coord ), ( node ) ) ; 	\
+	     coord_next_item( coord ) == 0 ; )
+
+/* COORD/ITEM METHODS */
+
+extern int item_utmost_child_real_block(const coord_t * coord, sideof side,
+					reiser4_block_nr * blk);
+extern int item_utmost_child(const coord_t * coord, sideof side,
+			     jnode ** child);
+
+/* a flow is a sequence of bytes being written to or read from the tree.  The
+   tree will slice the flow into items while storing it into nodes, but all of
+   that is hidden from anything outside the tree.  */
+
+struct flow {
+	reiser4_key key;	/* key of start of flow's sequence of bytes */
+	loff_t length;		/* length of flow's sequence of bytes */
+	char *data;		/* start of flow's sequence of bytes */
+	int user;		/* if 1 data is user space, 0 - kernel space */
+	rw_op op;		/* NIKITA-FIXME-HANS: comment is where?  */
+};
+
+void move_flow_forward(flow_t * f, unsigned count);
+
+/* &reiser4_item_data - description of data to be inserted or pasted
+
+   Q: articulate the reasons for the difference between this and flow.
+
+   A: Becides flow we insert into tree other things: stat data, directory
+   entry, etc.  To insert them into tree one has to provide this structure. If
+   one is going to insert flow - he can use insert_flow, where this structure
+   does not have to be created
+*/
+struct reiser4_item_data {
+	/* actual data to be inserted. If NULL, ->create_item() will not
+	   do xmemcpy itself, leaving this up to the caller. This can
+	   save some amount of unnecessary memory copying, for example,
+	   during insertion of stat data.
+
+	 */
+	char *data;
+	/* 1 if 'char * data' contains pointer to user space and 0 if it is
+	   kernel space */
+	int user;
+	/* amount of data we are going to insert or paste */
+	int length;
+	/* "Arg" is opaque data that is passed down to the
+	   ->create_item() method of node layout, which in turn
+	   hands it to the ->create_hook() of item being created. This
+	   arg is currently used by:
+
+	   .  ->create_hook() of internal item
+	   (fs/reiser4/plugin/item/internal.c:internal_create_hook()),
+	   . ->paste() method of directory item.
+	   . ->create_hook() of extent item
+
+	   For internal item, this is left "brother" of new node being
+	   inserted and it is used to add new node into sibling list
+	   after parent to it was just inserted into parent.
+
+	   While ->arg does look somewhat of unnecessary compication,
+	   it actually saves a lot of headache in many places, because
+	   all data necessary to insert or paste new data into tree are
+	   collected in one place, and this eliminates a lot of extra
+	   argument passing and storing everywhere.
+
+	 */
+	void *arg;
+	/* plugin of item we are inserting */
+	item_plugin *iplug;
+};
+
+/* __REISER4_COORD_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/debug.c newtree/fs/reiser4/debug.c
--- oldtree/fs/reiser4/debug.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/debug.c	2006-02-21 15:58:35.427760720 +0000
@@ -0,0 +1,303 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Debugging facilities. */
+
+/*
+ * This file contains generic debugging functions used by reiser4. Roughly
+ * following:
+ *
+ *     panicking: reiser4_do_panic(), reiser4_print_prefix().
+ *
+ *     locking: schedulable(), lock_counters(), print_lock_counters(),
+ *     no_counters_are_held(), commit_check_locks()
+ *
+ *     error code monitoring (see comment before RETERR macro): return_err(),
+ *     report_err().
+ *
+ *     stack back-tracing: fill_backtrace()
+ *
+ *     miscellaneous: preempt_point(), call_on_each_assert(), debugtrap().
+ *
+ */
+
+#include "reiser4.h"
+#include "context.h"
+#include "super.h"
+#include "txnmgr.h"
+#include "znode.h"
+
+#include <linux/sysfs.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/spinlock.h>
+#include <linux/kallsyms.h>
+#include <linux/vmalloc.h>
+#include <linux/ctype.h>
+#include <linux/sysctl.h>
+#include <linux/hardirq.h>
+
+#if REISER4_DEBUG
+static void report_err(void);
+#else
+#define report_err() noop
+#endif
+
+/*
+ * global buffer where message given to reiser4_panic is formatted.
+ */
+static char panic_buf[REISER4_PANIC_MSG_BUFFER_SIZE];
+
+/*
+ * lock protecting consistency of panic_buf under concurrent panics
+ */
+static spinlock_t panic_guard = SPIN_LOCK_UNLOCKED;
+
+/* Your best friend. Call it on each occasion.  This is called by
+    fs/reiser4/debug.h:reiser4_panic(). */
+void reiser4_do_panic(const char *format /* format string */ , ... /* rest */ )
+{
+	static int in_panic = 0;
+	va_list args;
+
+	/*
+	 * check for recursive panic.
+	 */
+	if (in_panic == 0) {
+		in_panic = 1;
+
+		spin_lock(&panic_guard);
+		va_start(args, format);
+		vsnprintf(panic_buf, sizeof(panic_buf), format, args);
+		va_end(args);
+		printk(KERN_EMERG "reiser4 panicked cowardly: %s", panic_buf);
+		spin_unlock(&panic_guard);
+
+		/*
+		 * if kernel debugger is configured---drop in. Early dropping
+		 * into kgdb is not always convenient, because panic message
+		 * is not yet printed most of the times. But:
+		 *
+		 *     (1) message can be extracted from printk_buf[]
+		 *     (declared static inside of printk()), and
+		 *
+		 *     (2) sometimes serial/kgdb combo dies while printing
+		 *     long panic message, so it's more prudent to break into
+		 *     debugger earlier.
+		 *
+		 */
+		DEBUGON(1);
+	}
+	/* to make gcc happy about noreturn attribute */
+	panic("%s", panic_buf);
+}
+
+void
+reiser4_print_prefix(const char *level, int reperr, const char *mid,
+		     const char *function, const char *file, int lineno)
+{
+	const char *comm;
+	int pid;
+
+	if (unlikely(in_interrupt() || in_irq())) {
+		comm = "interrupt";
+		pid = 0;
+	} else {
+		comm = current->comm;
+		pid = current->pid;
+	}
+	printk("%sreiser4[%.16s(%i)]: %s (%s:%i)[%s]:\n",
+	       level, comm, pid, function, file, lineno, mid);
+	if (reperr)
+		report_err();
+}
+
+/* Preemption point: this should be called periodically during long running
+   operations (carry, allocate, and squeeze are best examples) */
+int preempt_point(void)
+{
+	assert("nikita-3008", schedulable());
+	cond_resched();
+	return signal_pending(current);
+}
+
+#if REISER4_DEBUG
+
+/* check that no spinlocks are held */
+int schedulable(void)
+{
+	if (get_current_context_check() != NULL) {
+		if (!LOCK_CNT_NIL(spin_locked)) {
+			print_lock_counters("in atomic", lock_counters());
+			return 0;
+		}
+	}
+	might_sleep();
+	return 1;
+}
+#endif
+
+#if REISER4_DEBUG
+/* Debugging aid: return struct where information about locks taken by current
+   thread is accumulated. This can be used to formulate lock ordering
+   constraints and various assertions.
+
+*/
+lock_counters_info *lock_counters(void)
+{
+	reiser4_context *ctx = get_current_context();
+	assert("jmacd-1123", ctx != NULL);
+	return &ctx->locks;
+}
+
+/*
+ * print human readable information about locks held by the reiser4 context.
+ */
+void print_lock_counters(const char *prefix, const lock_counters_info * info)
+{
+	printk("%s: jnode: %i, tree: %i (r:%i,w:%i), dk: %i (r:%i,w:%i)\n"
+	       "jload: %i, "
+	       "txnh: %i, atom: %i, stack: %i, txnmgr: %i, "
+	       "ktxnmgrd: %i, fq: %i\n"
+	       "inode: %i, "
+	       "cbk_cache: %i (r:%i,w%i), "
+	       "eflush: %i, "
+	       "zlock: %i,\n"
+	       "spin: %i, long: %i inode_sem: (r:%i,w:%i)\n"
+	       "d: %i, x: %i, t: %i\n", prefix,
+	       info->spin_locked_jnode,
+	       info->rw_locked_tree, info->read_locked_tree,
+	       info->write_locked_tree,
+	       info->rw_locked_dk, info->read_locked_dk, info->write_locked_dk,
+	       info->spin_locked_jload,
+	       info->spin_locked_txnh,
+	       info->spin_locked_atom, info->spin_locked_stack,
+	       info->spin_locked_txnmgr, info->spin_locked_ktxnmgrd,
+	       info->spin_locked_fq,
+	       info->spin_locked_inode,
+	       info->rw_locked_cbk_cache,
+	       info->read_locked_cbk_cache,
+	       info->write_locked_cbk_cache,
+	       info->spin_locked_super_eflush,
+	       info->spin_locked_zlock,
+	       info->spin_locked,
+	       info->long_term_locked_znode,
+	       info->inode_sem_r, info->inode_sem_w,
+	       info->d_refs, info->x_refs, info->t_refs);
+}
+
+/*
+ * return true, iff no locks are held.
+ */
+int no_counters_are_held(void)
+{
+	lock_counters_info *counters;
+
+	counters = lock_counters();
+	return
+	    (counters->spin_locked_zlock == 0) &&
+	    (counters->spin_locked_jnode == 0) &&
+	    (counters->rw_locked_tree == 0) &&
+	    (counters->read_locked_tree == 0) &&
+	    (counters->write_locked_tree == 0) &&
+	    (counters->rw_locked_dk == 0) &&
+	    (counters->read_locked_dk == 0) &&
+	    (counters->write_locked_dk == 0) &&
+	    (counters->spin_locked_txnh == 0) &&
+	    (counters->spin_locked_atom == 0) &&
+	    (counters->spin_locked_stack == 0) &&
+	    (counters->spin_locked_txnmgr == 0) &&
+	    (counters->spin_locked_inode == 0) &&
+	    (counters->spin_locked == 0) &&
+	    (counters->long_term_locked_znode == 0) &&
+	    (counters->inode_sem_r == 0) &&
+	    (counters->inode_sem_w == 0) && (counters->d_refs == 0);
+}
+
+/*
+ * return true, iff transaction commit can be done under locks held by the
+ * current thread.
+ */
+int commit_check_locks(void)
+{
+	lock_counters_info *counters;
+	int inode_sem_r;
+	int inode_sem_w;
+	int result;
+
+	/*
+	 * inode's read/write semaphore is the only reiser4 lock that can be
+	 * held during commit.
+	 */
+
+	counters = lock_counters();
+	inode_sem_r = counters->inode_sem_r;
+	inode_sem_w = counters->inode_sem_w;
+
+	counters->inode_sem_r = counters->inode_sem_w = 0;
+	result = no_counters_are_held();
+	counters->inode_sem_r = inode_sem_r;
+	counters->inode_sem_w = inode_sem_w;
+	return result;
+}
+
+/*
+ * fill "error site" in the current reiser4 context. See comment before RETERR
+ * macro for more details.
+ */
+void return_err(int code, const char *file, int line)
+{
+	if (code < 0 && is_in_reiser4_context()) {
+		reiser4_context *ctx = get_current_context();
+
+		if (ctx != NULL) {
+			ctx->err.code = code;
+			ctx->err.file = file;
+			ctx->err.line = line;
+		}
+	}
+}
+
+/*
+ * report error information recorder by return_err().
+ */
+static void report_err(void)
+{
+	reiser4_context *ctx = get_current_context_check();
+
+	if (ctx != NULL) {
+		if (ctx->err.code != 0) {
+			printk("code: %i at %s:%i\n",
+			       ctx->err.code, ctx->err.file, ctx->err.line);
+		}
+	}
+}
+
+#endif				/* REISER4_DEBUG */
+
+#if KERNEL_DEBUGGER
+
+/*
+ * this functions just drops into kernel debugger. It is a convenient place to
+ * put breakpoint in.
+ */
+void debugtrap(void)
+{
+	/* do nothing. Put break point here. */
+#if defined(CONFIG_KGDB) && !defined(CONFIG_REISER4_FS_MODULE)
+	extern void breakpoint(void);
+	breakpoint();
+#endif
+}
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/debug.h newtree/fs/reiser4/debug.h
--- oldtree/fs/reiser4/debug.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/debug.h	2006-02-21 15:58:35.427760720 +0000
@@ -0,0 +1,354 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Declarations of debug macros. */
+
+#if !defined( __FS_REISER4_DEBUG_H__ )
+#define __FS_REISER4_DEBUG_H__
+
+#include "forward.h"
+#include "reiser4.h"
+
+/* generic function to produce formatted output, decorating it with
+   whatever standard prefixes/postfixes we want. "Fun" is a function
+   that will be actually called, can be printk, panic etc.
+   This is for use by other debugging macros, not by users. */
+#define DCALL(lev, fun, reperr, label, format, ...)			\
+({									\
+/*	reiser4_print_prefix(lev, reperr, label,*/			\
+/*	__FUNCTION__, __FILE__, __LINE__);*/				\
+	fun(lev "%sreiser4[%.16s(%i)]: %s (%s:%i)[%s]:\n" format "\n" ,	\
+	    lev, current->comm, current->pid, __FUNCTION__,		\
+	    __FILE__, __LINE__, label, ## __VA_ARGS__);			\
+})
+
+/*
+ * cause kernel to crash
+ */
+#define reiser4_panic(mid, format, ...)				\
+	DCALL("", reiser4_do_panic, 1, mid, format , ## __VA_ARGS__)
+
+/* print message with indication of current process, file, line and
+   function */
+#define reiser4_log(label, format, ...) 				\
+	DCALL(KERN_DEBUG, printk, 0, label, format , ## __VA_ARGS__)
+
+/* Assertion checked during compilation.
+    If "cond" is false (0) we get duplicate case label in switch.
+    Use this to check something like famous
+       cassert (sizeof(struct reiserfs_journal_commit) == 4096) ;
+    in 3.x journal.c. If cassertion fails you get compiler error,
+    so no "maintainer-id".
+*/
+#define cassert(cond) ({ switch(-1) { case (cond): case 0: break; } })
+
+#define noop   do {;} while(0)
+
+#if REISER4_DEBUG
+/* version of info that only actually prints anything when _d_ebugging
+    is on */
+#define dinfo(format, ...) printk(format , ## __VA_ARGS__)
+/* macro to catch logical errors. Put it into `default' clause of
+    switch() statement. */
+#define impossible(label, format, ...) 			\
+         reiser4_panic(label, "impossible: " format , ## __VA_ARGS__)
+/* assert assures that @cond is true. If it is not, reiser4_panic() is
+   called. Use this for checking logical consistency and _never_ call
+   this to check correctness of external data: disk blocks and user-input . */
+#define assert(label, cond)							\
+({										\
+	/* call_on_each_assert(); */						\
+	if (cond) {								\
+		/* put negated check to avoid using !(cond) that would lose	\
+		 * warnings for things like assert(a = b); */			\
+		;								\
+	} else {								\
+		DEBUGON(1);							\
+		reiser4_panic(label, "assertion failed: %s", #cond);		\
+	}									\
+})
+
+/* like assertion, but @expr is evaluated even if REISER4_DEBUG is off. */
+#define check_me( label, expr )	assert( label, ( expr ) )
+
+#define ON_DEBUG( exp ) exp
+
+extern int schedulable(void);
+extern void call_on_each_assert(void);
+
+#else
+
+#define dinfo( format, args... ) noop
+#define impossible( label, format, args... ) noop
+#define assert( label, cond ) noop
+#define check_me( label, expr )	( ( void ) ( expr ) )
+#define ON_DEBUG( exp )
+#define schedulable() might_sleep()
+
+/* REISER4_DEBUG */
+#endif
+
+#if REISER4_DEBUG
+/* per-thread information about lock acquired by this thread. Used by lock
+ * ordering checking in spin_macros.h */
+typedef struct lock_counters_info {
+	int rw_locked_tree;
+	int read_locked_tree;
+	int write_locked_tree;
+
+	int rw_locked_dk;
+	int read_locked_dk;
+	int write_locked_dk;
+
+	int rw_locked_cbk_cache;
+	int read_locked_cbk_cache;
+	int write_locked_cbk_cache;
+
+	int spin_locked_zlock;
+	int spin_locked_jnode;
+	int spin_locked_jload;
+	int spin_locked_txnh;
+	int spin_locked_atom;
+	int spin_locked_stack;
+	int spin_locked_txnmgr;
+	int spin_locked_ktxnmgrd;
+	int spin_locked_fq;
+	int spin_locked_inode;
+	int spin_locked_super_eflush;
+	int spin_locked;
+	int long_term_locked_znode;
+
+	int inode_sem_r;
+	int inode_sem_w;
+
+	int d_refs;
+	int x_refs;
+	int t_refs;
+} lock_counters_info;
+
+extern lock_counters_info *lock_counters(void);
+#define IN_CONTEXT(a, b) (is_in_reiser4_context() ? (a) : (b))
+
+/* increment lock-counter @counter, if present */
+#define LOCK_CNT_INC(counter) IN_CONTEXT(++(lock_counters()->counter), 0)
+
+/* decrement lock-counter @counter, if present */
+#define LOCK_CNT_DEC(counter) IN_CONTEXT(--(lock_counters()->counter), 0)
+
+/* check that lock-counter is zero. This is for use in assertions */
+#define LOCK_CNT_NIL(counter) IN_CONTEXT(lock_counters()->counter == 0, 1)
+
+/* check that lock-counter is greater than zero. This is for use in
+ * assertions */
+#define LOCK_CNT_GTZ(counter) IN_CONTEXT(lock_counters()->counter > 0, 1)
+#define LOCK_CNT_LT(counter,n) IN_CONTEXT(lock_counters()->counter < n, 1)
+
+#else				/* REISER4_DEBUG */
+
+/* no-op versions on the above */
+
+typedef struct lock_counters_info {
+} lock_counters_info;
+
+#define lock_counters() ((lock_counters_info *)NULL)
+#define LOCK_CNT_INC(counter) noop
+#define LOCK_CNT_DEC(counter) noop
+#define LOCK_CNT_NIL(counter) (1)
+#define LOCK_CNT_GTZ(counter) (1)
+#define LOCK_CNT_LT(counter,n) (1)
+
+#endif				/* REISER4_DEBUG */
+
+#define assert_spin_not_locked(lock) BUG_ON(0)
+#define assert_rw_write_locked(lock) BUG_ON(0)
+#define assert_rw_read_locked(lock) BUG_ON(0)
+#define assert_rw_locked(lock) BUG_ON(0)
+#define assert_rw_not_write_locked(lock) BUG_ON(0)
+#define assert_rw_not_read_locked(lock) BUG_ON(0)
+#define assert_rw_not_locked(lock) BUG_ON(0)
+
+/* flags controlling debugging behavior. Are set through debug_flags=N mount
+   option. */
+typedef enum {
+	/* print a lot of information during panic. When this is on all jnodes
+	 * are listed. This can be *very* large output. Usually you don't want
+	 * this. Especially over serial line. */
+	REISER4_VERBOSE_PANIC = 0x00000001,
+	/* print a lot of information during umount */
+	REISER4_VERBOSE_UMOUNT = 0x00000002,
+	/* print gathered statistics on umount */
+	REISER4_STATS_ON_UMOUNT = 0x00000004,
+	/* check node consistency */
+	REISER4_CHECK_NODE = 0x00000008
+} reiser4_debug_flags;
+
+extern int is_in_reiser4_context(void);
+
+/*
+ * evaluate expression @e only if with reiser4 context
+ */
+#define ON_CONTEXT(e)	do {			\
+	if(is_in_reiser4_context()) {		\
+		e;				\
+	} } while(0)
+
+/*
+ * evaluate expression @e only when within reiser4_context and debugging is
+ * on.
+ */
+#define ON_DEBUG_CONTEXT( e ) ON_DEBUG( ON_CONTEXT( e ) )
+
+/*
+ * complain about unexpected function result and crash. Used in "default"
+ * branches of switch statements and alike to assert that invalid results are
+ * not silently ignored.
+ */
+#define wrong_return_value( label, function )				\
+	impossible( label, "wrong return value from " function )
+
+/* Issue different types of reiser4 messages to the console */
+#define warning( label, format, ... )					\
+	DCALL( KERN_WARNING, 						\
+	       printk, 1, label, "WARNING: " format , ## __VA_ARGS__ )
+#define notice( label, format, ... )					\
+	DCALL( KERN_NOTICE, 						\
+	       printk, 1, label, "NOTICE: " format , ## __VA_ARGS__ )
+
+/* mark not yet implemented functionality */
+#define not_yet( label, format, ... )				\
+	reiser4_panic( label, "NOT YET IMPLEMENTED: " format , ## __VA_ARGS__ )
+
+extern void reiser4_do_panic(const char *format, ...)
+    __attribute__ ((noreturn, format(printf, 1, 2)));
+
+extern void reiser4_print_prefix(const char *level, int reperr, const char *mid,
+				 const char *function,
+				 const char *file, int lineno);
+
+extern int preempt_point(void);
+extern void reiser4_print_stats(void);
+
+
+#if REISER4_DEBUG
+extern void print_lock_counters(const char *prefix,
+				const lock_counters_info * info);
+extern int no_counters_are_held(void);
+extern int commit_check_locks(void);
+#else
+#define no_counters_are_held() (1)
+#define commit_check_locks() (1)
+#endif
+
+/* true if @i is power-of-two. Useful for rate-limited warnings, etc. */
+#define IS_POW(i) 				\
+({						\
+	typeof(i) __i;				\
+						\
+	__i = (i);				\
+	!(__i & (__i - 1));			\
+})
+
+#define KERNEL_DEBUGGER (1)
+
+#if KERNEL_DEBUGGER
+
+extern void debugtrap(void);
+
+/*
+ * Check condition @cond and drop into kernel debugger (kgdb) if it's true. If
+ * kgdb is not compiled in, do nothing.
+ */
+#define DEBUGON(cond)				\
+({						\
+	if (unlikely(cond))			\
+		debugtrap();			\
+})
+#else
+#define DEBUGON(cond) noop
+#endif
+
+/*
+ * Error code tracing facility. (Idea is borrowed from XFS code.)
+ *
+ * Suppose some strange and/or unexpected code is returned from some function
+ * (for example, write(2) returns -EEXIST). It is possible to place a
+ * breakpoint in the reiser4_write(), but it is too late here. How to find out
+ * in what particular place -EEXIST was generated first?
+ *
+ * In reiser4 all places where actual error codes are produced (that is,
+ * statements of the form
+ *
+ *     return -EFOO;        // (1), or
+ *
+ *     result = -EFOO;      // (2)
+ *
+ * are replaced with
+ *
+ *     return RETERR(-EFOO);        // (1a), and
+ *
+ *     result = RETERR(-EFOO);      // (2a) respectively
+ *
+ * RETERR() macro fills a backtrace in reiser4_context. This back-trace is
+ * printed in error and warning messages. Moreover, it's possible to put a
+ * conditional breakpoint in return_err (low-level function called by RETERR()
+ * to do the actual work) to break into debugger immediately when particular
+ * error happens.
+ *
+ */
+
+#if REISER4_DEBUG
+
+/*
+ * data-type to store information about where error happened ("error site").
+ */
+typedef struct err_site {
+	int code;		/* error code */
+	const char *file;	/* source file, filled by __FILE__ */
+	int line;		/* source file line, filled by __LINE__ */
+} err_site;
+
+extern void return_err(int code, const char *file, int line);
+
+/*
+ * fill &get_current_context()->err_site with error information.
+ */
+#define RETERR(code) 				\
+({						\
+	typeof(code) __code;			\
+						\
+	__code = (code);			\
+	return_err(__code, __FILE__, __LINE__);	\
+	__code;					\
+})
+
+#else
+
+/*
+ * no-op versions of the above
+ */
+
+typedef struct err_site {
+} err_site;
+#define RETERR(code) code
+#endif
+
+#if REISER4_LARGE_KEY
+/*
+ * conditionally compile arguments only if REISER4_LARGE_KEY is on.
+ */
+#define ON_LARGE_KEY(...) __VA_ARGS__
+#else
+#define ON_LARGE_KEY(...)
+#endif
+
+/* __FS_REISER4_DEBUG_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/dformat.h newtree/fs/reiser4/dformat.h
--- oldtree/fs/reiser4/dformat.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/dformat.h	2006-02-21 15:58:34.837850400 +0000
@@ -0,0 +1,71 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Formats of on-disk data and conversion functions. */
+
+/* put all item formats in the files describing the particular items,
+   our model is, everything you need to do to add an item to reiser4,
+   (excepting the changes to the plugin that uses the item which go
+   into the file defining that plugin), you put into one file. */
+/* Data on disk are stored in little-endian format.
+   To declare fields of on-disk structures, use d8, d16, d32 and d64.
+   d??tocpu() and cputod??() to convert. */
+
+#if !defined( __FS_REISER4_DFORMAT_H__ )
+#define __FS_REISER4_DFORMAT_H__
+
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+#include <linux/types.h>
+
+
+typedef __u8 d8;
+typedef __le16 d16;
+typedef __le32 d32;
+typedef __le64 d64;
+
+#define PACKED __attribute__((packed))
+
+/* data-type for block number */
+typedef __u64 reiser4_block_nr;
+
+/* data-type for block number on disk, disk format */
+typedef __le64 reiser4_dblock_nr;
+
+/**
+ * disk_addr_eq - compare disk addresses
+ * @b1: pointer to block number ot compare
+ * @b2: pointer to block number ot compare
+ *
+ * Returns true if if disk addresses are the same
+ */
+static inline int disk_addr_eq(const reiser4_block_nr *b1,
+			       const reiser4_block_nr * b2)
+{
+	assert("nikita-1033", b1 != NULL);
+	assert("nikita-1266", b2 != NULL);
+
+	return !memcmp(b1, b2, sizeof *b1);
+}
+
+/* structure of master reiser4 super block */
+typedef struct reiser4_master_sb {
+	char magic[16];		/* "ReIsEr4" */
+	__le16 disk_plugin_id;	/* id of disk layout plugin */
+	__le16 blocksize;
+	char uuid[16];		/* unique id */
+	char label[16];		/* filesystem label */
+	__le64 diskmap;		/* location of the diskmap. 0 if not present */
+} reiser4_master_sb;
+
+/* __FS_REISER4_DFORMAT_H__ */
+#endif
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * End:
+ */
diff -urN oldtree/fs/reiser4/dscale.c newtree/fs/reiser4/dscale.c
--- oldtree/fs/reiser4/dscale.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/dscale.c	2006-02-21 15:58:34.837850400 +0000
@@ -0,0 +1,174 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Scalable on-disk integers */
+
+/*
+ * Various on-disk structures contain integer-like structures. Stat-data
+ * contain [yes, "data" is plural, check the dictionary] file size, link
+ * count; extent unit contains extent width etc. To accommodate for general
+ * case enough space is reserved to keep largest possible value. 64 bits in
+ * all cases above. But in overwhelming majority of cases numbers actually
+ * stored in these fields will be comparatively small and reserving 8 bytes is
+ * a waste of precious disk bandwidth.
+ *
+ * Scalable integers are one way to solve this problem. dscale_write()
+ * function stores __u64 value in the given area consuming from 1 to 9 bytes,
+ * depending on the magnitude of the value supplied. dscale_read() reads value
+ * previously stored by dscale_write().
+ *
+ * dscale_write() produces format not completely unlike of UTF: two highest
+ * bits of the first byte are used to store "tag". One of 4 possible tag
+ * values is chosen depending on the number being encoded:
+ *
+ *           0 ... 0x3f               => 0           [table 1]
+ *        0x40 ... 0x3fff             => 1
+ *      0x4000 ... 0x3fffffff         => 2
+ *  0x40000000 ... 0xffffffffffffffff => 3
+ *
+ * (see dscale_range() function)
+ *
+ * Values in the range 0x40000000 ... 0xffffffffffffffff require 8 full bytes
+ * to be stored, so in this case there is no place in the first byte to store
+ * tag. For such values tag is stored in an extra 9th byte.
+ *
+ * As _highest_ bits are used for the test (which is natural) scaled integers
+ * are stored in BIG-ENDIAN format in contrast with the rest of reiser4 which
+ * uses LITTLE-ENDIAN.
+ *
+ */
+
+#include "debug.h"
+#include "dscale.h"
+
+/* return tag of scaled integer stored at @address */
+static int gettag(const unsigned char *address)
+{
+	/* tag is stored in two highest bits */
+	return (*address) >> 6;
+}
+
+/* clear tag from value. Clear tag embedded into @value. */
+static void cleartag(__u64 * value, int tag)
+{
+	/*
+	 * W-w-what ?!
+	 *
+	 * Actually, this is rather simple: @value passed here was read by
+	 * dscale_read(), converted from BIG-ENDIAN, and padded to __u64 by
+	 * zeroes. Tag is still stored in the highest (arithmetically)
+	 * non-zero bits of @value, but relative position of tag within __u64
+	 * depends on @tag.
+	 *
+	 * For example if @tag is 0, it's stored 2 highest bits of lowest
+	 * byte, and its offset (counting from lowest bit) is 8 - 2 == 6 bits.
+	 *
+	 * If tag is 1, it's stored in two highest bits of 2nd lowest byte,
+	 * and it's offset if (2 * 8) - 2 == 14 bits.
+	 *
+	 * See table 1 above for details.
+	 *
+	 * All these cases are captured by the formula:
+	 */
+	*value &= ~(3 << (((1 << tag) << 3) - 2));
+	/*
+	 * That is, clear two (3 == 0t11) bits at the offset
+	 *
+	 *                  8 * (2 ^ tag) - 2,
+	 *
+	 * that is, two highest bits of (2 ^ tag)-th byte of @value.
+	 */
+}
+
+/* return tag for @value. See table 1 above for details. */
+static int dscale_range(__u64 value)
+{
+	if (value > 0x3fffffff)
+		return 3;
+	if (value > 0x3fff)
+		return 2;
+	if (value > 0x3f)
+		return 1;
+	return 0;
+}
+
+/* restore value stored at @adderss by dscale_write() and return number of
+ * bytes consumed */
+int dscale_read(unsigned char *address, __u64 * value)
+{
+	int tag;
+
+	/* read tag */
+	tag = gettag(address);
+	switch (tag) {
+	case 3:
+		/* In this case tag is stored in an extra byte, skip this byte
+		 * and decode value stored in the next 8 bytes.*/
+		*value = __be64_to_cpu(get_unaligned((__be64 *)(address + 1)));
+		/* worst case: 8 bytes for value itself plus one byte for
+		 * tag. */
+		return 9;
+	case 0:
+		*value = get_unaligned(address);
+		break;
+	case 1:
+		*value = __be16_to_cpu(get_unaligned((__be16 *)address));
+		break;
+	case 2:
+		*value = __be32_to_cpu(get_unaligned((__be32 *)address));
+		break;
+	default:
+		return RETERR(-EIO);
+	}
+	/* clear tag embedded into @value */
+	cleartag(value, tag);
+	/* number of bytes consumed is (2 ^ tag)---see table 1. */
+	return 1 << tag;
+}
+
+/* store @value at @address and return number of bytes consumed */
+int dscale_write(unsigned char *address, __u64 value)
+{
+	int tag;
+	int shift;
+	__be64 v;
+	unsigned char *valarr;
+
+	tag = dscale_range(value);
+	v = __cpu_to_be64(value);
+	valarr = (unsigned char *)&v;
+	shift = (tag == 3) ? 1 : 0;
+	memcpy(address + shift, valarr + sizeof v - (1 << tag), 1 << tag);
+	*address |= (tag << 6);
+	return shift + (1 << tag);
+}
+
+/* number of bytes required to store @value */
+int dscale_bytes(__u64 value)
+{
+	int bytes;
+
+	bytes = 1 << dscale_range(value);
+	if (bytes == 8)
+		++bytes;
+	return bytes;
+}
+
+/* returns true if @value and @other require the same number of bytes to be
+ * stored. Used by detect when data structure (like stat-data) has to be
+ * expanded or contracted. */
+int dscale_fit(__u64 value, __u64 other)
+{
+	return dscale_range(value) == dscale_range(other);
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/dscale.h newtree/fs/reiser4/dscale.h
--- oldtree/fs/reiser4/dscale.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/dscale.h	2006-02-21 15:58:34.527897520 +0000
@@ -0,0 +1,27 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Scalable on-disk integers. See dscale.h for details. */
+
+#if !defined( __FS_REISER4_DSCALE_H__ )
+#define __FS_REISER4_DSCALE_H__
+
+#include "dformat.h"
+
+extern int dscale_read(unsigned char *address, __u64 * value);
+extern int dscale_write(unsigned char *address, __u64 value);
+extern int dscale_bytes(__u64 value);
+extern int dscale_fit(__u64 value, __u64 other);
+
+/* __FS_REISER4_DSCALE_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/emergency_flush.c newtree/fs/reiser4/emergency_flush.c
--- oldtree/fs/reiser4/emergency_flush.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/emergency_flush.c	2006-02-21 15:58:35.428760568 +0000
@@ -0,0 +1,919 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* This file exists only until VM gets fixed to reserve pages properly, which
+ * might or might not be very political. */
+
+/* Implementation of emergency flush. */
+
+/* OVERVIEW:
+
+     Before writing a node to the disk, some complex process (flush.[ch]) is
+     to be performed. Flush is the main necessary preliminary step before
+     writing pages back to the disk, but it has some characteristics that make
+     it completely different from traditional ->writepage():
+
+        1 It operates on a large number of nodes, possibly far away from the
+        starting node, both in tree and disk order.
+
+        2 it can involve reading of nodes from the disk (during extent
+        allocation, for example).
+
+        3 it can allocate memory (during insertion of allocated extents).
+
+        4 it participates in the locking protocol which reiser4 uses to
+        implement concurrent tree modifications.
+
+        5 it is CPU consuming and long
+
+     As a result, flush reorganizes some part of reiser4 tree and produces
+     large queue of nodes ready to be submitted for io.
+
+     Items (3) and (4) alone make flush unsuitable for being called directly
+     from reiser4 ->writepage() callback, because of OOM and deadlocks
+     against threads waiting for memory.
+
+     So, flush is performed from within balance_dirty_page() path when dirty
+     pages are generated. If balance_dirty_page() fails to throttle writers
+     and page replacement finds dirty page on the inactive list, we resort to
+     "emergency flush" in our ->vm_writeback().
+
+     Emergency flush is relatively dumb algorithm, implemented in this file,
+     that tries to write tree nodes to the disk without taking locks and without
+     thoroughly optimizing tree layout. We only want to call emergency flush in
+     desperate situations, because it is going to produce sub-optimal disk
+     layouts.
+
+  DETAILED DESCRIPTION
+
+     Emergency flush (eflush) is designed to work as low level mechanism with
+     no or little impact on the rest of (already too complex) code.
+
+     eflush is initiated from ->writepage() method called by VM on memory
+     pressure. It is supposed that ->writepage() is rare call path, because
+     balance_dirty_pages() throttles writes and tries to keep memory in
+     balance.
+
+     eflush main entry point (emergency_flush()) checks whether jnode is
+     eligible for emergency flushing. Check is performed by flushable()
+     function which see for details. After successful check, new block number
+     ("emergency block") is allocated and io is initiated to write jnode
+     content to that block.
+
+     After io is finished, jnode will be cleaned and VM will be able to free
+     page through call to ->releasepage().
+
+     emergency_flush() also contains special case invoked when it is possible
+     to avoid allocation of new node.
+
+     Node selected for eflush is marked (by JNODE_EFLUSH bit in ->flags field)
+     and added to the special hash table of all eflushed nodes. This table
+     doesn't have linkage within each jnode, as this would waste memory in
+     assumption that eflush is rare. In stead new small memory object
+     (eflush_node_t) is allocated that contains pointer to jnode, emergency
+     block number, and is inserted into hash table. Per super block counter of
+     eflushed nodes is incremented. See section [INODE HANDLING] below for
+     more on this.
+
+     It should be noted that emergency flush may allocate memory and wait for
+     io completion (bitmap read).
+
+     Basically eflushed node has following distinctive characteristics:
+
+          (1) JNODE_EFLUSH bit is set
+
+          (2) no page
+
+          (3) there is an element in hash table, for this node
+
+          (4) node content is stored on disk in block whose number is stored
+          in the hash table element
+
+  UNFLUSH
+
+      Unflush is reverse of eflush, that is process bringing page of eflushed
+      inode back into memory.
+
+      In accordance with the policy that eflush is low level and low impact
+      mechanism, transparent to the rest of the code, unflushing is performed
+      deeply within jload_gfp() which is main function used to load and pin
+      jnode page into memory.
+
+      Specifically, if jload_gfp() determines that it is called on eflushed
+      node it gets emergency block number to start io against from the hash
+      table rather than from jnode itself. This is done in
+      jnode_get_io_block() function. After io completes, hash table element
+      for this node is removed and JNODE_EFLUSH bit is cleared.
+
+  LOCKING
+
+      The page lock is used to avoid eflush/e-unflush/jnode_get_io_block races.
+      emergency_flush() and jnode_get_io_block are called under the page lock.
+      The eflush_del() function (emergency unflush) may be called for a node w/o
+      page attached.  In that case eflush_del() allocates a page and locks it.
+
+  PROBLEMS
+
+  1. INODE HANDLING
+
+      Usually (i.e., without eflush), jnode has a page attached to it. This
+      page pins corresponding struct address_space, and, hence, inode in
+      memory. Once inode has been eflushed, its page is gone and inode can be
+      wiped out of memory by the memory pressure (prune_icache()). This leads
+      to the number of complications:
+
+           (1) jload_gfp() has to attach jnode tho the address space's radix
+           tree. This requires existence if inode.
+
+           (2) normal flush needs jnode's inode to start slum collection from
+           unformatted jnode.
+
+      (1) is really a problem, because it is too late to load inode (which
+      would lead to loading of stat data, etc.) within jload_gfp().
+
+      We, therefore, need some way to protect inode from being recycled while
+      having accessible eflushed nodes.
+
+      I'll describe old solution here so it can be compared with new one.
+
+      Original solution pinned inode by __iget() when first its node was
+      eflushed and released (through iput()) when last was unflushed. This
+      required maintenance of inode->eflushed counter in inode.
+
+      Problem arise if last name of inode is unlinked when it has eflushed
+      nodes. In this case, last iput() that leads to the removal of file is
+      iput() made by unflushing from within jload_gfp(). Obviously, calling
+      truncate, and tree traversals from jload_gfp() is not a good idea.
+
+      New solution is to pin inode in memory by adding I_EFLUSH bit to its
+      ->i_state field. This protects inode from being evicted by
+      prune_icache().
+
+  DISK SPACE ALLOCATION
+
+      This section will describe how emergency block is allocated and how
+      block counters (allocated, grabbed, etc.) are manipulated. To be done.
+
+   *****HISTORICAL SECTION****************************************************
+
+   DELAYED PARENT UPDATE
+
+     Important point of emergency flush is that update of parent is sometimes
+     delayed: we don't update parent immediately if:
+
+      1 Child was just allocated, but parent is locked. Waiting for parent
+      lock in emergency flush is impossible (deadlockable).
+
+      2 Part of extent was allocated, but parent has not enough space to
+      insert allocated extent unit. Balancing in emergency flush is
+      impossible, because it will possibly wait on locks.
+
+     When we delay update of parent node, we mark it as such (and possibly
+     also mark children to simplify delayed update later). Question: when
+     parent should be really updated?
+
+   WHERE TO WRITE PAGE INTO?
+
+     So, it was decided that flush has to be performed from a separate
+     thread. Reiser4 has a thread used to periodically commit old transactions,
+     and this thread can be used for the flushing. That is, flushing thread
+     does flush and accumulates nodes prepared for the IO on the special
+     queue. reiser4_vm_writeback() submits nodes from this queue, if queue is
+     empty, it only wakes up flushing thread and immediately returns.
+
+     Still there are some problems with integrating this stuff into VM
+     scanning:
+
+        1 As ->vm_writeback() returns immediately without actually submitting
+        pages for IO, throttling on PG_writeback in shrink_list() will not
+        work. This opens a possibility (on a fast CPU), of try_to_free_pages()
+        completing scanning and calling out_of_memory() before flushing thread
+        managed to add anything to the queue.
+
+        2 It is possible, however unlikely, that flushing thread will be
+        unable to flush anything, because there is not enough memory. In this
+        case reiser4 resorts to the "emergency flush": some dumb algorithm,
+        implemented in this file, that tries to write tree nodes to the disk
+        without taking locks and without thoroughly optimizing tree layout. We
+        only want to call emergency flush in desperate situations, because it
+        is going to produce sub-optimal disk layouts.
+
+        3 Nodes prepared for IO can be from the active list, this means that
+        they will not be met/freed by shrink_list() after IO completion. New
+        blk_congestion_wait() should help with throttling but not
+        freeing. This is not fatal though, because inactive list refilling
+        will ultimately get to these pages and reclaim them.
+
+   REQUIREMENTS
+
+     To make this work we need at least some hook inside VM scanning which
+     gets triggered after scanning (or scanning with particular priority)
+     failed to free pages. This is already present in the
+     mm/vmscan.c:set_shrinker() interface.
+
+     Another useful thing that we would like to have is passing scanning
+     priority down to the ->vm_writeback() that will allow file system to
+     switch to the emergency flush more gracefully.
+
+   POSSIBLE ALGORITHMS
+
+     1 Start emergency flush from ->vm_writeback after reaching some priority.
+     This allows to implement simple page based algorithm: look at the page VM
+     supplied us with and decide what to do.
+
+     2 Start emergency flush from shrinker after reaching some priority.
+     This delays emergency flush as far as possible.
+
+   *****END OF HISTORICAL SECTION**********************************************
+
+*/
+
+#include "forward.h"
+#include "debug.h"
+#include "page_cache.h"
+#include "tree.h"
+#include "jnode.h"
+#include "znode.h"
+#include "inode.h"
+#include "super.h"
+#include "block_alloc.h"
+#include "emergency_flush.h"
+
+#include <linux/mm.h>
+#include <linux/writeback.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/swap.h>
+
+#if REISER4_USE_EFLUSH
+
+static int flushable(jnode * node, struct page *page, int);
+static int needs_allocation(const jnode * node);
+static eflush_node_t *ef_alloc(unsigned int flags);
+static reiser4_ba_flags_t ef_block_flags(const jnode * node);
+static int ef_free_block(jnode * node, const reiser4_block_nr * blk,
+			 block_stage_t stage, eflush_node_t * ef);
+static int ef_prepare(jnode * node, reiser4_block_nr * blk,
+		      eflush_node_t ** enode, reiser4_blocknr_hint * hint);
+static int eflush_add(jnode * node, reiser4_block_nr * blocknr,
+		      eflush_node_t * ef);
+
+/* slab for eflush_node_t's */
+static kmem_cache_t *eflush_slab;
+
+#define EFLUSH_START_BLOCK ((reiser4_block_nr)0)
+
+#define INC_STAT(node, counter)						\
+	reiser4_stat_inc_at_level(jnode_get_level(node), counter);
+
+/**
+ * emergency_flush - try to flush page to disk
+ * @page: what to write
+ *
+ * This is called in desperate situation when flush algorithm can not be used to
+ * flush dirty memory due to deadlocking. It writes @page to temporary allocated
+ * block. In some case it avoids temporary block allocation though. Returns 0 if
+ * page was successfully paged out, 1 if it is busy, or error.
+ */
+int emergency_flush(struct page *page)
+{
+	struct super_block *sb;
+	jnode *node;
+	int result;
+	assert("nikita-2721", page != NULL);
+	assert("nikita-2724", PageLocked(page));
+
+	// warning("nikita-3112", "Emergency flush. Notify Reiser@Namesys.COM");
+
+	/*
+	 * Page is locked, hence page<->jnode mapping cannot change.
+	 */
+
+	sb = page->mapping->host->i_sb;
+	node = jprivate(page);
+
+	assert("vs-1452", node != NULL);
+
+	jref(node);
+
+	result = 0;
+	spin_lock_jnode(node);
+	/*
+	 * if page was dirty and under eflush (this is (only?) possible if page
+	 * was re-dirtied through mmap(2) after eflush IO was submitted, but
+	 * before ->releasepage() freed page) cancel previous eflush.
+	 */
+	eflush_del(node, 1);
+
+	spin_lock(&(node->load));
+	if (flushable(node, page, 1)) {
+		if (needs_allocation(node)) {
+			reiser4_block_nr blk;
+			eflush_node_t *efnode;
+			reiser4_blocknr_hint hint;
+
+			blk = 0ull;
+			efnode = NULL;
+
+			/*
+			 * Set JNODE_EFLUSH bit _before_ allocating a block,
+			 * that prevents flush reserved block from using here
+			 * and by a reiser4 flush process
+			 */
+			JF_SET(node, JNODE_EFLUSH);
+
+			blocknr_hint_init(&hint);
+
+			result = ef_prepare(node, &blk, &efnode, &hint);
+			if (flushable(node, page, 0) && result == 0) {
+				assert("nikita-2759", efnode != NULL);
+				eflush_add(node, &blk, efnode);
+
+				result = page_io(page, node, WRITE,
+						 GFP_NOFS | __GFP_HIGH);
+			} else {
+				JF_CLR(node, JNODE_EFLUSH);
+				spin_unlock(&(node->load));
+				spin_unlock_jnode(node);
+				if (blk != 0ull) {
+					ef_free_block(node, &blk,
+						      hint.block_stage, efnode);
+					kmem_cache_free(eflush_slab, efnode);
+				}
+				result = 1;
+			}
+
+			blocknr_hint_done(&hint);
+		} else {
+			/* eflush without allocation temporary location for a node */
+			txn_atom *atom;
+			flush_queue_t *fq;
+
+			/* get flush queue for this node */
+			result = fq_by_jnode_gfp(node, &fq, GFP_ATOMIC);
+			if (result) {
+				jput(node);
+				return result;
+			}
+
+			atom = node->atom;
+
+			if (!flushable(node, page, 1) ||
+			    needs_allocation(node) ||
+			    !JF_ISSET(node, JNODE_DIRTY)) {
+				spin_unlock(&(node->load));
+				spin_unlock_jnode(node);
+				spin_unlock_atom(atom);
+				fq_put(fq);
+				jput(node);
+				return 1;
+			}
+
+			/* ok, now we can flush it */
+			unlock_page(page);
+
+			queue_jnode(fq, node);
+
+			spin_unlock(&(node->load));
+			spin_unlock_jnode(node);
+			spin_unlock_atom(atom);
+
+			result = write_fq(fq, NULL, 0);
+			if (result != 0)
+				lock_page(page);
+
+			/*
+			 * Even if we wrote nothing, We unlocked the page, so
+			 * let know to the caller that page should not be
+			 * unlocked again
+			 */
+			fq_put(fq);
+		}
+
+	} else {
+		spin_unlock(&(node->load));
+		spin_unlock_jnode(node);
+		result = 1;
+	}
+
+	jput(node);
+	return result;
+}
+
+static int flushable(jnode * node, struct page *page, int check_eflush)
+{
+	assert("nikita-2725", node != NULL);
+	assert_spin_locked(&(node->guard));
+	assert_spin_locked(&(node->load));
+
+	if (jnode_is_loaded(node)) {	/* loaded */
+		return 0;
+	}
+	if (JF_ISSET(node, JNODE_FLUSH_QUEUED)) {	/* already pending io */
+		return 0;
+	}
+	if (JF_ISSET(node, JNODE_EPROTECTED)) {	/* protected from e-flush */
+		return 0;
+	}
+	if (JF_ISSET(node, JNODE_HEARD_BANSHEE)) {
+		return 0;
+	}
+	if (page == NULL) {	/* nothing to flush */
+		return 0;
+	}
+	if (PageWriteback(page)) {	/* already under io */
+		return 0;
+	}
+	/* don't flush bitmaps or journal records */
+	if (!jnode_is_znode(node) && !jnode_is_unformatted(node)) {
+		return 0;
+	}
+	/* don't flush cluster pages */
+	if (jnode_of_cluster(node, page)) {
+		return 0;
+	}
+	if (check_eflush && JF_ISSET(node, JNODE_EFLUSH)) {	/* already flushed */
+		return 0;
+	}
+	return 1;
+}
+
+#undef INC_STAT
+
+/* does node need allocation for eflushing? */
+static int needs_allocation(const jnode * node)
+{
+	return !(JF_ISSET(node, JNODE_RELOC)
+		 && !blocknr_is_fake(jnode_get_block(node)));
+}
+
+static inline int jnode_eq(jnode * const *j1, jnode * const *j2)
+{
+	assert("nikita-2733", j1 != NULL);
+	assert("nikita-2734", j2 != NULL);
+
+	return *j1 == *j2;
+}
+
+static ef_hash_table *get_jnode_enhash(const jnode * node)
+{
+	struct super_block *super;
+
+	assert("nikita-2739", node != NULL);
+
+	super = jnode_get_tree(node)->super;
+	return &get_super_private(super)->efhash_table;
+}
+
+static inline __u32 jnode_hfn(ef_hash_table * table, jnode * const *j)
+{
+	__u32 val;
+
+	assert("nikita-2735", j != NULL);
+	assert("nikita-3346", IS_POW(table->_buckets));
+
+	val = (unsigned long)*j;
+	val /= sizeof(**j);
+	return val & (table->_buckets - 1);
+}
+
+/* The hash table definition */
+#define KMALLOC(size) vmalloc(size)
+#define KFREE(ptr, size) vfree(ptr)
+TYPE_SAFE_HASH_DEFINE(ef, eflush_node_t, jnode *, node, linkage, jnode_hfn,
+		      jnode_eq);
+#undef KFREE
+#undef KMALLOC
+
+/**
+ * init_eflush - create eflush node cache
+ *
+ * Initializes slab cache of eflush nodes. It is part of reiser4 module
+ * initialization.
+ */
+int init_eflush(void)
+{
+	eflush_slab = kmem_cache_create("eflush", sizeof(eflush_node_t),
+					0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (eflush_slab == NULL)
+		return RETERR(-ENOMEM);
+	return 0;
+}
+
+/**
+ * done_eflush - delete eflush nodeznode cache
+ *
+ * This is called on reiser4 module unloading or system shutdown.
+ */
+void done_eflush(void)
+{
+	destroy_reiser4_cache(&eflush_slab);
+}
+
+int eflush_init_at(struct super_block *super)
+{
+	return ef_hash_init(&get_super_private(super)->efhash_table, 8192);
+}
+
+void eflush_done_at(struct super_block *super)
+{
+	ef_hash_done(&get_super_private(super)->efhash_table);
+}
+
+static eflush_node_t *ef_alloc(unsigned int flags)
+{
+	return kmem_cache_alloc(eflush_slab, flags);
+}
+
+static void inc_unfm_ef(void)
+{
+	reiser4_super_info_data *sbinfo;
+
+	sbinfo = get_super_private(get_current_context()->super);
+	spin_lock_reiser4_super(sbinfo);
+	sbinfo->eflushed_unformatted++;
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+static void dec_unfm_ef(void)
+{
+	reiser4_super_info_data *sbinfo;
+
+	sbinfo = get_super_private(get_current_context()->super);
+	spin_lock_reiser4_super(sbinfo);
+	BUG_ON(sbinfo->eflushed_unformatted == 0);
+	sbinfo->eflushed_unformatted--;
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+#define EFLUSH_MAGIC 4335203
+
+static int
+eflush_add(jnode * node, reiser4_block_nr * blocknr, eflush_node_t * ef)
+{
+	reiser4_tree *tree;
+
+	assert("nikita-2737", node != NULL);
+	assert("nikita-2738", JF_ISSET(node, JNODE_EFLUSH));
+	assert("nikita-3382", !JF_ISSET(node, JNODE_EPROTECTED));
+	assert_spin_locked(&(node->guard));
+	assert_spin_locked(&(node->load));
+
+	tree = jnode_get_tree(node);
+
+	ef->node = node;
+	ef->blocknr = *blocknr;
+	ef->hadatom = (node->atom != NULL);
+	ef->incatom = 0;
+	jref(node);
+	spin_lock(&(get_super_private(tree->super)->eflush_guard));
+	ef_hash_insert(get_jnode_enhash(node), ef);
+	ON_DEBUG(++get_super_private(tree->super)->eflushed);
+	spin_unlock(&(get_super_private(tree->super)->eflush_guard));
+
+	if (jnode_is_unformatted(node)) {
+		struct inode *inode;
+		reiser4_inode *info;
+
+		inode = mapping_jnode(node)->host;
+		info = reiser4_inode_data(inode);
+
+		if (!ef->hadatom) {
+			write_lock_irq(&inode->i_mapping->tree_lock);
+			radix_tree_tag_set(jnode_tree_by_reiser4_inode(info),
+					   index_jnode(node),
+					   EFLUSH_TAG_ANONYMOUS);
+			write_unlock_irq(&inode->i_mapping->tree_lock);
+		}
+		inc_unfm_ef();
+	}
+
+	/* FIXME: do we need it here, if eflush add/del are protected by page lock? */
+	spin_unlock(&(node->load));
+
+	/*
+	 * jnode_get_atom() can possible release jnode spin lock. This
+	 * means it can only be called _after_ JNODE_EFLUSH is set, because
+	 * otherwise we would have to re-check flushable() once more. No
+	 * thanks.
+	 */
+
+	if (ef->hadatom) {
+		txn_atom *atom;
+
+		atom = jnode_get_atom(node);
+		if (atom != NULL) {
+			++atom->flushed;
+			ef->incatom = 1;
+			spin_unlock_atom(atom);
+		}
+	}
+
+	spin_unlock_jnode(node);
+	return 0;
+}
+
+/* Arrghh... cast to keep hash table code happy. */
+#define C(node) ((jnode *const *)&(node))
+
+reiser4_block_nr *eflush_get(jnode * node)
+{
+	eflush_node_t *ef;
+	reiser4_tree *tree;
+
+	assert("nikita-2740", node != NULL);
+	assert("nikita-2741", JF_ISSET(node, JNODE_EFLUSH));
+	assert_spin_locked(&(node->guard));
+
+	tree = jnode_get_tree(node);
+	spin_lock(&(get_super_private(tree->super)->eflush_guard));
+	ef = ef_hash_find(get_jnode_enhash(node), C(node));
+	spin_unlock(&(get_super_private(tree->super)->eflush_guard));
+
+	assert("nikita-2742", ef != NULL);
+	return &ef->blocknr;
+}
+
+/* free resources taken for emergency flushing of the node */
+void eflush_free(jnode * node)
+{
+	eflush_node_t *ef;
+	ef_hash_table *table;
+	reiser4_tree *tree;
+	txn_atom *atom;
+	struct inode *inode = NULL;
+	reiser4_block_nr blk;
+
+	assert_spin_locked(&(node->guard));
+
+	table = get_jnode_enhash(node);
+	tree = jnode_get_tree(node);
+
+	spin_lock(&(get_super_private(tree->super)->eflush_guard));
+	ef = ef_hash_find(table, C(node));
+	BUG_ON(ef == NULL);
+	assert("nikita-2745", ef != NULL);
+	blk = ef->blocknr;
+	ef_hash_remove(table, ef);
+	ON_DEBUG(--get_super_private(tree->super)->eflushed);
+	spin_unlock(&(get_super_private(tree->super)->eflush_guard));
+
+	if (ef->incatom) {
+		atom = jnode_get_atom(node);
+		assert("nikita-3311", atom != NULL);
+		--atom->flushed;
+		spin_unlock_atom(atom);
+	}
+
+	assert("vs-1215", JF_ISSET(node, JNODE_EFLUSH));
+
+	if (jnode_is_unformatted(node)) {
+		reiser4_inode *info;
+
+		inode = mapping_jnode(node)->host;
+		info = reiser4_inode_data(inode);
+
+		/* clear e-flush specific tags from node's radix tree slot */
+		if (!ef->hadatom) {
+			write_lock_irq(&inode->i_mapping->tree_lock);
+			radix_tree_tag_clear(jnode_tree_by_reiser4_inode(info),
+					     index_jnode(node),
+					     EFLUSH_TAG_ANONYMOUS);
+			write_unlock_irq(&inode->i_mapping->tree_lock);
+		}
+
+		assert("nikita-3355",
+		       jnode_tree_by_reiser4_inode(info)->rnode != NULL);
+		dec_unfm_ef();
+	}
+	spin_unlock_jnode(node);
+
+#if REISER4_DEBUG
+	if (blocknr_is_fake(jnode_get_block(node)))
+		assert("zam-817", ef->initial_stage == BLOCK_UNALLOCATED);
+	else
+		assert("zam-818", ef->initial_stage == BLOCK_GRABBED);
+#endif
+
+	jput(node);
+
+	ef_free_block(node, &blk,
+		      blocknr_is_fake(jnode_get_block(node)) ?
+		      BLOCK_UNALLOCATED : BLOCK_GRABBED, ef);
+
+	kmem_cache_free(eflush_slab, ef);
+
+	spin_lock_jnode(node);
+}
+
+void eflush_del(jnode * node, int page_locked)
+{
+	struct page *page;
+
+	assert("nikita-2743", node != NULL);
+	assert_spin_locked(&(node->guard));
+
+	if (likely(!JF_ISSET(node, JNODE_EFLUSH)))
+		return;
+
+	if (page_locked) {
+		page = jnode_page(node);
+		assert("nikita-2806", page != NULL);
+		assert("nikita-2807", PageLocked(page));
+	} else {
+		spin_unlock_jnode(node);
+		page = jnode_get_page_locked(node, GFP_NOFS);
+		spin_lock_jnode(node);
+		if (page == NULL) {
+			warning("zam-1025",
+				"eflush_del failed to get page back\n");
+			return;
+		}
+		if (unlikely(!JF_ISSET(node, JNODE_EFLUSH)))
+			/* race: some other thread unflushed jnode. */
+			goto out;
+	}
+
+	if (PageWriteback(page)) {
+		spin_unlock_jnode(node);
+		page_cache_get(page);
+		reiser4_wait_page_writeback(page);
+		page_cache_release(page);
+		spin_lock_jnode(node);
+		if (unlikely(!JF_ISSET(node, JNODE_EFLUSH)))
+			/* race: some other thread unflushed jnode. */
+			goto out;
+	}
+
+	/* we have to make page dirty again. Note that we do not have to do here
+	   anything specific to reiser4 but usual dirty page accounting. If */
+	if (!TestSetPageDirty(page)) {
+		BUG_ON(jnode_get_mapping(node) != page->mapping);
+		if (mapping_cap_account_dirty(page->mapping))
+			inc_page_state(nr_dirty);
+	}
+
+	assert("nikita-2766", atomic_read(&node->x_count) > 1);
+	/* release allocated disk block and in-memory structures  */
+	eflush_free(node);
+	assert("vs-1736", PageLocked(page));
+	JF_CLR(node, JNODE_EFLUSH);
+	ON_DEBUG(JF_SET(node, JNODE_UNEFLUSHED));
+      out:
+	if (!page_locked)
+		unlock_page(page);
+}
+
+int emergency_unflush(jnode * node)
+{
+	int result;
+
+	assert("nikita-2778", node != NULL);
+	assert("nikita-3046", schedulable());
+
+	if (JF_ISSET(node, JNODE_EFLUSH)) {
+		result = jload(node);
+		if (result == 0) {
+			struct page *page;
+
+			assert("nikita-2777", !JF_ISSET(node, JNODE_EFLUSH));
+			page = jnode_page(node);
+			assert("nikita-2779", page != NULL);
+			wait_on_page_writeback(page);
+			jrelse(node);
+		}
+	} else
+		result = 0;
+	return result;
+}
+
+static reiser4_ba_flags_t ef_block_flags(const jnode * node)
+{
+	return jnode_is_znode(node) ? BA_FORMATTED : 0;
+}
+
+static int ef_free_block(jnode * node,
+			 const reiser4_block_nr * blk,
+			 block_stage_t stage, eflush_node_t * ef)
+{
+	int result = 0;
+
+	/* We cannot just ask block allocator to return block into flush
+	 * reserved space, because there is no current atom at this point. */
+	result = reiser4_dealloc_block(blk, stage, ef_block_flags(node));
+	if (result == 0 && stage == BLOCK_GRABBED) {
+		txn_atom *atom;
+
+		if (ef->reserve) {
+			/* further, transfer block from grabbed into flush
+			 * reserved space. */
+			spin_lock_jnode(node);
+			atom = jnode_get_atom(node);
+			assert("nikita-2785", atom != NULL);
+			grabbed2flush_reserved_nolock(atom, 1);
+			spin_unlock_atom(atom);
+			JF_SET(node, JNODE_FLUSH_RESERVED);
+			spin_unlock_jnode(node);
+		} else {
+			reiser4_context *ctx = get_current_context();
+			grabbed2free(ctx, get_super_private(ctx->super),
+				     (__u64) 1);
+		}
+	}
+	return result;
+}
+
+static int
+ef_prepare(jnode * node, reiser4_block_nr * blk, eflush_node_t ** efnode,
+	   reiser4_blocknr_hint * hint)
+{
+	int result;
+	int usedreserve;
+
+	assert("nikita-2760", node != NULL);
+	assert("nikita-2761", blk != NULL);
+	assert("nikita-2762", efnode != NULL);
+	assert_spin_locked(&(node->guard));
+	assert_spin_locked(&(node->load));
+
+	hint->blk = EFLUSH_START_BLOCK;
+	hint->max_dist = 0;
+	hint->level = jnode_get_level(node);
+	usedreserve = 0;
+	if (blocknr_is_fake(jnode_get_block(node)))
+		hint->block_stage = BLOCK_UNALLOCATED;
+	else {
+		txn_atom *atom;
+		switch (jnode_is_leaf(node)) {
+		default:
+			/*
+			 * We cannot just ask block allocator to take block from
+			 * flush reserved space, because there is no current
+			 * atom at this point.
+			 */
+			atom = jnode_get_atom(node);
+			if (atom != NULL) {
+				if (JF_ISSET(node, JNODE_FLUSH_RESERVED)) {
+					usedreserve = 1;
+					flush_reserved2grabbed(atom, 1);
+					JF_CLR(node, JNODE_FLUSH_RESERVED);
+					spin_unlock_atom(atom);
+					break;
+				} else
+					spin_unlock_atom(atom);
+			}
+			/*
+			 * fall through.
+			 * node->atom == NULL if page was dirtied through mmap
+			 */
+		case 0:
+			result =
+			    reiser4_grab_space_force((__u64) 1, BA_RESERVED);
+			grab_space_enable();
+			if (result) {
+				warning("nikita-3323",
+					"Cannot allocate eflush block");
+				return result;
+			}
+		}
+
+		hint->block_stage = BLOCK_GRABBED;
+	}
+
+	/*
+	 * XXX protect @node from being concurrently eflushed. Otherwise, there
+	 * is a danger of underflowing block space
+	 */
+	spin_unlock(&(node->load));
+	spin_unlock_jnode(node);
+
+	*efnode = ef_alloc(GFP_NOFS | __GFP_HIGH);
+	if (*efnode == NULL) {
+		result = RETERR(-ENOMEM);
+		goto out;
+	}
+#if REISER4_DEBUG
+	(*efnode)->initial_stage = hint->block_stage;
+#endif
+	(*efnode)->reserve = usedreserve;
+
+	result = reiser4_alloc_block(hint, blk, ef_block_flags(node));
+	if (result)
+		kmem_cache_free(eflush_slab, *efnode);
+      out:
+	spin_lock_jnode(node);
+	spin_lock(&(node->load));
+	return result;
+}
+
+#endif				/* REISER4_USE_EFLUSH */
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 80
+   LocalWords: " unflush eflushed LocalWords eflush writepage VM releasepage unflushing io "
+   End:
+*/
diff -urN oldtree/fs/reiser4/emergency_flush.h newtree/fs/reiser4/emergency_flush.h
--- oldtree/fs/reiser4/emergency_flush.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/emergency_flush.h	2006-02-21 15:58:34.968830488 +0000
@@ -0,0 +1,75 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Emergency flush */
+
+#ifndef __EMERGENCY_FLUSH_H__
+#define __EMERGENCY_FLUSH_H__
+
+#if REISER4_USE_EFLUSH
+
+#include "block_alloc.h"
+
+struct eflush_node;
+typedef struct eflush_node eflush_node_t;
+
+TYPE_SAFE_HASH_DECLARE(ef, eflush_node_t);
+
+struct eflush_node {
+	jnode *node;
+	reiser4_block_nr blocknr;
+	ef_hash_link linkage;
+	struct list_head inode_link;	/* for per inode list of eflush nodes */
+	struct list_head inode_anon_link;
+	unsigned int hadatom:1;
+	unsigned int incatom:1;
+	unsigned int reserve:1;
+#if REISER4_DEBUG
+	block_stage_t initial_stage;
+#endif
+};
+
+extern int init_eflush(void);
+extern void done_eflush(void);
+
+extern int eflush_init_at(struct super_block *super);
+extern void eflush_done_at(struct super_block *super);
+
+extern reiser4_block_nr *eflush_get(jnode * node);
+extern void eflush_del(jnode * node, int page_locked);
+extern void eflush_free(jnode *);
+
+extern int emergency_flush(struct page *page);
+extern int emergency_unflush(jnode * node);
+
+/* tag to tag eflushed anonymous jnodes in reiser4_inode's radix tree of jnodes */
+#define EFLUSH_TAG_ANONYMOUS PAGECACHE_TAG_DIRTY
+
+#else				/* REISER4_USE_EFLUSH */
+
+#define init_eflush()  (0)
+#define done_eflush()  do {} while (0)
+
+#define eflush_init_at(super) (0)
+#define eflush_done_at(super) do {} while (0)
+
+#define eflush_get(node)  NULL
+#define eflush_del(node, flag) do{}while(0)
+#define eflush_free(node) do{}while(0)
+
+#define emergency_unflush(node) (0)
+#define emergency_flush(page) (1)
+
+#endif				/* REISER4_USE_EFLUSH */
+
+/* __EMERGENCY_FLUSH_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/entd.c newtree/fs/reiser4/entd.c
--- oldtree/fs/reiser4/entd.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/entd.c	2006-02-21 15:58:35.428760568 +0000
@@ -0,0 +1,374 @@
+/* Copyright 2003, 2004 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Ent daemon. */
+
+#include "debug.h"
+#include "txnmgr.h"
+#include "tree.h"
+#include "entd.h"
+#include "super.h"
+#include "context.h"
+#include "reiser4.h"
+#include "vfs_ops.h"
+#include "page_cache.h"
+#include "inode.h"
+
+#include <linux/sched.h>	/* struct task_struct */
+#include <linux/suspend.h>
+#include <linux/kernel.h>
+#include <linux/writeback.h>
+#include <linux/time.h>		/* INITIAL_JIFFIES */
+#include <linux/backing-dev.h>	/* bdi_write_congested */
+#include <linux/wait.h>
+#include <linux/kthread.h>
+
+#define DEF_PRIORITY 12
+#define MAX_ENTD_ITERS 10
+
+static void entd_flush(struct super_block *, struct wbq *);
+static int entd(void *arg);
+
+/*
+ * set ->comm field of end thread to make its state visible to the user level
+ */
+#define entd_set_comm(state)					\
+	snprintf(current->comm, sizeof(current->comm),	\
+	         "ent:%s%s", super->s_id, (state))
+
+/**
+ * init_entd - initialize entd context and start kernel daemon
+ * @super: super block to start ent thread for
+ *
+ * Creates entd contexts, starts kernel thread and waits until it
+ * initializes.
+ */
+int init_entd(struct super_block *super)
+{
+	entd_context *ctx;
+
+	assert("nikita-3104", super != NULL);
+
+	ctx = get_entd_context(super);
+
+	memset(ctx, 0, sizeof *ctx);
+	spin_lock_init(&ctx->guard);
+	init_waitqueue_head(&ctx->wait);
+#if REISER4_DEBUG
+	INIT_LIST_HEAD(&ctx->flushers_list);
+#endif
+	/* lists of writepage requests */
+	INIT_LIST_HEAD(&ctx->todo_list);
+	INIT_LIST_HEAD(&ctx->done_list);
+	/* start entd */
+	ctx->tsk = kthread_run(entd, super, "ent:%s", super->s_id);
+	if (IS_ERR(ctx->tsk))
+		return PTR_ERR(ctx->tsk);
+	return 0;
+}
+
+static void __put_wbq(entd_context *ent, struct wbq *rq)
+{
+	up(&rq->sem);
+}
+
+/* ent should be locked */
+static struct wbq *__get_wbq(entd_context * ent)
+{
+	struct wbq *wbq;
+
+	if (list_empty_careful(&ent->todo_list))
+		return NULL;
+
+	ent->nr_todo_reqs --;
+	wbq = list_entry(ent->todo_list.next, struct wbq, link);
+	list_del_init(&wbq->link);
+	return wbq;
+}
+
+struct wbq * get_wbq(struct super_block * super)
+{
+	struct wbq *result;
+	entd_context * ent = get_entd_context(super);
+
+	spin_lock(&ent->guard);
+	result = __get_wbq(ent);
+	spin_unlock(&ent->guard);
+
+	return result;
+}
+
+void put_wbq(struct super_block *super, struct wbq * rq)
+{
+	entd_context * ent = get_entd_context(super);
+
+	spin_lock(&ent->guard);
+	__put_wbq(ent, rq);
+	spin_unlock(&ent->guard);
+}
+
+static void wakeup_all_wbq(entd_context * ent)
+{
+	struct wbq *rq;
+
+	spin_lock(&ent->guard);
+	while ((rq = __get_wbq(ent)) != NULL)
+		__put_wbq(ent, rq);
+	spin_unlock(&ent->guard);
+}
+
+/* ent thread function */
+static int entd(void *arg)
+{
+	struct super_block *super;
+	entd_context *ent;
+	int done = 0;
+
+	super = arg;
+	/* do_fork() just copies task_struct into the new
+	   thread. ->fs_context shouldn't be copied of course. This shouldn't
+	   be a problem for the rest of the code though.
+	 */
+	current->journal_info = NULL;
+
+	ent = get_entd_context(super);
+
+	while (!done) {
+		try_to_freeze();
+
+		spin_lock(&ent->guard);
+		while (ent->nr_todo_reqs != 0) {
+			struct wbq *rq, *next;
+
+			assert("", list_empty_careful(&ent->done_list));
+
+			/* take request from the queue head */
+			rq = __get_wbq(ent);
+			assert("", rq != NULL);
+			ent->cur_request = rq;
+			spin_unlock(&ent->guard);
+
+			entd_set_comm("!");
+			entd_flush(super, rq);
+
+			iput(rq->mapping->host);
+			up(&(rq->sem));
+
+			/*
+			 * wakeup all requestors and iput their inodes
+			 */
+			spin_lock(&ent->guard);
+			list_for_each_entry_safe(rq, next, &ent->done_list, link) {
+				list_del_init(&(rq->link));
+				ent->nr_done_reqs --;
+				spin_unlock(&ent->guard);
+
+				assert("", rq->written == 1);
+				iput(rq->mapping->host);
+				up(&(rq->sem));
+				spin_lock(&ent->guard);
+			}
+		}
+		spin_unlock(&ent->guard);
+
+		entd_set_comm(".");
+
+		{
+			DEFINE_WAIT(__wait);
+
+			do {
+				prepare_to_wait(&ent->wait, &__wait, TASK_INTERRUPTIBLE);
+				if (kthread_should_stop()) {
+					done = 1;
+					break;
+				}
+				if (ent->nr_todo_reqs != 0)
+					break;
+				schedule();
+			} while (0);
+			finish_wait(&ent->wait, &__wait);
+		}
+	}
+	spin_lock(&ent->guard);
+	BUG_ON(ent->nr_todo_reqs != 0);
+	spin_unlock(&ent->guard);
+	wakeup_all_wbq(ent);
+	return 0;
+}
+
+/**
+ * done_entd - stop entd kernel thread
+ * @super: super block to stop ent thread for
+ *
+ * It is called on umount. Sends stop signal to entd and wait until it handles
+ * it.
+ */
+void done_entd(struct super_block *super)
+{
+	entd_context *ent;
+
+	assert("nikita-3103", super != NULL);
+
+	ent = get_entd_context(super);
+	assert("zam-1055", ent->tsk != NULL);
+	kthread_stop(ent->tsk);
+}
+
+/* called at the beginning of jnode_flush to register flusher thread with ent
+ * daemon */
+void enter_flush(struct super_block *super)
+{
+	entd_context *ent;
+
+	assert("zam-1029", super != NULL);
+	ent = get_entd_context(super);
+
+	assert("zam-1030", ent != NULL);
+
+	spin_lock(&ent->guard);
+	ent->flushers++;
+#if REISER4_DEBUG
+	list_add(&get_current_context()->flushers_link, &ent->flushers_list);
+#endif
+	spin_unlock(&ent->guard);
+}
+
+/* called at the end of jnode_flush */
+void leave_flush(struct super_block *super)
+{
+	entd_context *ent;
+	int wake_up_ent;
+
+	assert("zam-1027", super != NULL);
+	ent = get_entd_context(super);
+
+	assert("zam-1028", ent != NULL);
+
+	spin_lock(&ent->guard);
+	ent->flushers--;
+	wake_up_ent = (ent->flushers == 0 && ent->nr_todo_reqs != 0);
+#if REISER4_DEBUG
+	list_del_init(&get_current_context()->flushers_link);
+#endif
+	spin_unlock(&ent->guard);
+	if (wake_up_ent)
+		wake_up(&ent->wait);
+}
+
+#define ENTD_CAPTURE_APAGE_BURST SWAP_CLUSTER_MAX
+
+static void entd_flush(struct super_block *super, struct wbq *rq)
+{
+	reiser4_context ctx;
+	int tmp;
+
+	init_stack_context(&ctx, super);
+	ctx.entd = 1;
+
+	rq->wbc->start = rq->page->index << PAGE_CACHE_SHIFT;
+	rq->wbc->end = (rq->page->index + ENTD_CAPTURE_APAGE_BURST) << PAGE_CACHE_SHIFT;
+	tmp = rq->wbc->nr_to_write;
+	rq->mapping->a_ops->writepages(rq->mapping, rq->wbc);
+
+	if (rq->wbc->nr_to_write > 0) {
+		rq->wbc->start = 0;
+		rq->wbc->end = 0;
+		generic_sync_sb_inodes(super, rq->wbc);
+	}
+	rq->wbc->nr_to_write = ENTD_CAPTURE_APAGE_BURST;
+	writeout(super, rq->wbc);
+
+	context_set_commit_async(&ctx);
+	reiser4_exit_context(&ctx);
+}
+
+/**
+ * write_page_by_ent - ask entd thread to flush this page as part of slum
+ * @page: page to be written
+ * @wbc: writeback control passed to reiser4_writepage
+ *
+ * Creates a request, puts it on entd list of requests, wakeups entd if
+ * necessary, waits until entd completes with the request.
+ */
+int write_page_by_ent(struct page *page, struct writeback_control *wbc)
+{
+	struct super_block *sb;
+	struct inode *inode;
+	entd_context *ent;
+	struct wbq rq;
+
+	assert("", PageLocked(page));
+	assert("", page->mapping != NULL);
+
+	sb = page->mapping->host->i_sb;
+	ent = get_entd_context(sb);
+	assert("", ent && ent->done == 0);
+
+	/*
+	 * we are going to unlock page and ask ent thread to write the
+	 * page. Re-dirty page before unlocking so that if ent thread fails to
+	 * write it - it will remain dirty
+	 */
+	set_page_dirty_internal(page);
+
+	/*
+	 * pin inode in memory, unlock page, entd_flush will iput. We can not
+	 * iput here becasue we can not allow delete_inode to be called here
+	 */
+	inode = igrab(page->mapping->host);
+	unlock_page(page);
+	if (inode == NULL)
+		/* inode is getting freed */
+		return 0;
+
+	/* init wbq */
+	INIT_LIST_HEAD(&rq.link);
+	rq.magic = WBQ_MAGIC;
+	rq.wbc = wbc;
+	rq.page = page;
+	rq.mapping = inode->i_mapping;
+	rq.node = NULL;
+	rq.written = 0;
+	sema_init(&rq.sem, 0);
+
+	/* add request to entd's list of writepage requests */
+	spin_lock(&ent->guard);
+	ent->nr_todo_reqs++;
+	list_add_tail(&rq.link, &ent->todo_list);
+	if (ent->nr_todo_reqs == 1)
+		wake_up(&ent->wait);
+
+	spin_unlock(&ent->guard);
+
+	/* wait until entd finishes */
+	down(&rq.sem);
+
+	/*
+	 * spin until entd thread which did up(&rq.sem) does not need rq
+	 * anymore
+	 */
+	spin_lock(&ent->guard);
+	spin_unlock(&ent->guard);
+
+	if (rq.written)
+		/* Eventually ENTD has written the page to disk. */
+		return 0;
+	return 0;
+}
+
+int wbq_available(void)
+{
+	struct super_block *sb = reiser4_get_current_sb();
+	entd_context *ent = get_entd_context(sb);
+	return ent->nr_todo_reqs;
+}
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * End:
+ */
diff -urN oldtree/fs/reiser4/entd.h newtree/fs/reiser4/entd.h
--- oldtree/fs/reiser4/entd.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/entd.h	2006-02-21 15:58:35.428760568 +0000
@@ -0,0 +1,92 @@
+/* Copyright 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Ent daemon. */
+
+#ifndef __ENTD_H__
+#define __ENTD_H__
+
+#include "context.h"
+
+#include <linux/fs.h>
+#include <linux/completion.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>	/* for struct task_struct */
+
+#define WBQ_MAGIC 0x7876dc76
+
+/* write-back request. */
+struct wbq {
+	int magic;
+	struct list_head link; /* list head of this list is in entd context */
+	struct writeback_control *wbc;
+	struct page *page;
+	struct address_space *mapping;
+	struct semaphore sem;
+	jnode *node; /* set if ent thread captured requested page */
+	int written; /* set if ent thread wrote requested page */
+};
+
+/* ent-thread context. This is used to synchronize starting/stopping ent
+ * threads. */
+typedef struct entd_context {
+	 /* wait queue that ent thread waits on for more work. It's
+	  * signaled by write_page_by_ent(). */
+	wait_queue_head_t wait;
+	/* spinlock protecting other fields */
+	spinlock_t guard;
+	/* ent thread */
+	struct task_struct *tsk;
+	/* set to indicate that ent thread should leave. */
+	int done;
+	/* counter of active flushers */
+	int flushers;
+	/*
+	 * when reiser4_writepage asks entd to write a page - it adds struct
+	 * wbq to this list
+	 */
+	struct list_head todo_list;
+	/* number of elements on the above list */
+	int nr_todo_reqs;
+
+	struct wbq *cur_request;
+	/*
+	 * when entd writes a page it moves write-back request from todo_list
+	 * to done_list. This list is used at the end of entd iteration to
+	 * wakeup requestors and iput inodes.
+	 */
+	struct list_head done_list;
+	/* number of elements on the above list */
+	int nr_done_reqs;
+
+#if REISER4_DEBUG
+	/* list of all active flushers */
+	struct list_head flushers_list;
+#endif
+} entd_context;
+
+extern int  init_entd(struct super_block *);
+extern void done_entd(struct super_block *);
+
+extern void enter_flush(struct super_block *);
+extern void leave_flush(struct super_block *);
+
+extern int write_page_by_ent(struct page *, struct writeback_control *);
+extern int wbq_available(void);
+extern void ent_writes_page(struct super_block *, struct page *);
+
+extern struct wbq *get_wbq(struct super_block *);
+extern void put_wbq(struct super_block *, struct wbq *);
+extern jnode *get_jnode_by_wbq(struct super_block *, struct wbq *);
+/* __ENTD_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/eottl.c newtree/fs/reiser4/eottl.c
--- oldtree/fs/reiser4/eottl.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/eottl.c	2006-02-21 15:58:34.970830184 +0000
@@ -0,0 +1,510 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#include "forward.h"
+#include "debug.h"
+#include "key.h"
+#include "coord.h"
+#include "plugin/item/item.h"
+#include "plugin/node/node.h"
+#include "znode.h"
+#include "block_alloc.h"
+#include "tree_walk.h"
+#include "tree_mod.h"
+#include "carry.h"
+#include "tree.h"
+#include "super.h"
+
+#include <linux/types.h>	/* for __u??  */
+
+/*
+ * Extents on the twig level (EOTTL) handling.
+ *
+ * EOTTL poses some problems to the tree traversal, that are better explained
+ * by example.
+ *
+ * Suppose we have block B1 on the twig level with the following items:
+ *
+ * 0. internal item I0 with key (0:0:0:0) (locality, key-type, object-id,
+ * offset)
+ * 1. extent item E1 with key (1:4:100:0), having 10 blocks of 4k each
+ * 2. internal item I2 with key (10:0:0:0)
+ *
+ * We are trying to insert item with key (5:0:0:0). Lookup finds node B1, and
+ * then intra-node lookup is done. This lookup finished on the E1, because the
+ * key we are looking for is larger than the key of E1 and is smaller than key
+ * the of I2.
+ *
+ * Here search is stuck.
+ *
+ * After some thought it is clear what is wrong here: extents on the twig level
+ * break some basic property of the *search* tree (on the pretext, that they
+ * restore property of balanced tree).
+ *
+ * Said property is the following: if in the internal node of the search tree
+ * we have [ ... Key1 Pointer Key2 ... ] then, all data that are or will be
+ * keyed in the tree with the Key such that Key1 <= Key < Key2 are accessible
+ * through the Pointer.
+ *
+ * This is not true, when Pointer is Extent-Pointer, simply because extent
+ * cannot expand indefinitely to the right to include any item with
+ *
+ *   Key1 <= Key <= Key2.
+ *
+ * For example, our E1 extent is only responsible for the data with keys
+ *
+ *   (1:4:100:0) <= key <= (1:4:100:0xffffffffffffffff), and
+ *
+ * so, key range
+ *
+ *   ( (1:4:100:0xffffffffffffffff), (10:0:0:0) )
+ *
+ * is orphaned: there is no way to get there from the tree root.
+ *
+ * In other words, extent pointers are different than normal child pointers as
+ * far as search tree is concerned, and this creates such problems.
+ *
+ * Possible solution for this problem is to insert our item into node pointed
+ * to by I2. There are some problems through:
+ *
+ * (1) I2 can be in a different node.
+ * (2) E1 can be immediately followed by another extent E2.
+ *
+ * (1) is solved by calling reiser4_get_right_neighbor() and accounting
+ * for locks/coords as necessary.
+ *
+ * (2) is more complex. Solution here is to insert new empty leaf node and
+ * insert internal item between E1 and E2 pointing to said leaf node. This is
+ * further complicated by possibility that E2 is in a different node, etc.
+ *
+ * Problems:
+ *
+ * (1) if there was internal item I2 immediately on the right of an extent E1
+ * we and we decided to insert new item S1 into node N2 pointed to by I2, then
+ * key of S1 will be less than smallest key in the N2. Normally, search key
+ * checks that key we are looking for is in the range of keys covered by the
+ * node key is being looked in. To work around of this situation, while
+ * preserving useful consistency check new flag CBK_TRUST_DK was added to the
+ * cbk falgs bitmask. This flag is automatically set on entrance to the
+ * coord_by_key() and is only cleared when we are about to enter situation
+ * described above.
+ *
+ * (2) If extent E1 is immediately followed by another extent E2 and we are
+ * searching for the key that is between E1 and E2 we only have to insert new
+ * empty leaf node when coord_by_key was called for insertion, rather than just
+ * for lookup. To distinguish these cases, new flag CBK_FOR_INSERT was added to
+ * the cbk falgs bitmask. This flag is automatically set by coord_by_key calls
+ * performed by insert_by_key() and friends.
+ *
+ * (3) Insertion of new empty leaf node (possibly) requires balancing. In any
+ * case it requires modification of node content which is only possible under
+ * write lock. It may well happen that we only have read lock on the node where
+ * new internal pointer is to be inserted (common case: lookup of non-existent
+ * stat-data that fells between two extents). If only read lock is held, tree
+ * traversal is restarted with lock_level modified so that next time we hit
+ * this problem, write lock will be held. Once we have write lock, balancing
+ * will be performed.
+ */
+
+/**
+ * is_next_item_internal - check whether next item is internal
+ * @coord: coordinate of extent item in twig node
+ * @key: search key
+ * @lh: twig node lock handle
+ *
+ * Looks at the unit next to @coord. If it is an internal one - 1 is returned,
+ * @coord is set to that unit. If that unit is in right neighbor, @lh is moved
+ * to that node, @coord is set to its first unit. If next item is not internal
+ * or does not exist then 0 is returned, @coord and @lh are left unchanged. 2
+ * is returned if search restart has to be done.
+ */
+static int
+is_next_item_internal(coord_t *coord, const reiser4_key *key,
+		      lock_handle *lh)
+{
+	coord_t next;
+	lock_handle rn;
+	int result;
+
+	coord_dup(&next, coord);
+	if (coord_next_unit(&next) == 0) {
+		/* next unit is in this node */
+		if (item_is_internal(&next)) {
+			coord_dup(coord, &next);
+			return 1;
+		}
+		assert("vs-3", item_is_extent(&next));
+		return 0;
+	}
+
+	/*
+	 * next unit either does not exist or is in right neighbor. If it is in
+	 * right neighbor we have to check right delimiting key because
+	 * concurrent thread could get their first and insert item with a key
+	 * smaller than @key
+	 */
+	read_lock_dk(current_tree);
+	result = keycmp(key, znode_get_rd_key(coord->node));
+	read_unlock_dk(current_tree);
+	assert("vs-6", result != EQUAL_TO);
+	if (result == GREATER_THAN)
+		return 2;
+
+	/* lock right neighbor */
+	init_lh(&rn);
+	result = reiser4_get_right_neighbor(&rn, coord->node,
+					    znode_is_wlocked(coord->node) ?
+					    ZNODE_WRITE_LOCK : ZNODE_READ_LOCK,
+					    GN_CAN_USE_UPPER_LEVELS);
+	if (result == -E_NO_NEIGHBOR) {
+		/* we are on the rightmost edge of the tree */
+		done_lh(&rn);
+		return 0;
+	}
+
+	if (result) {
+		assert("vs-4", result < 0);
+		done_lh(&rn);
+		return result;
+	}
+
+	/*
+	 * check whether concurrent thread managed to insert item with a key
+	 * smaller than @key
+	 */
+	read_lock_dk(current_tree);
+	result = keycmp(key, znode_get_ld_key(rn.node));
+	read_unlock_dk(current_tree);
+	assert("vs-6", result != EQUAL_TO);
+	if (result == GREATER_THAN) {
+		done_lh(&rn);
+		return 2;
+	}
+
+	result = zload(rn.node);
+	if (result) {
+		assert("vs-5", result < 0);
+		done_lh(&rn);
+		return result;
+	}
+
+	coord_init_first_unit(&next, rn.node);
+	if (item_is_internal(&next)) {
+		/*
+		 * next unit is in right neighbor and it is an unit of internal
+		 * item. Unlock coord->node. Move @lh to right neighbor. @coord
+		 * is set to the first unit of right neighbor.
+		 */
+		coord_dup(coord, &next);
+		zrelse(rn.node);
+		done_lh(lh);
+		move_lh(lh, &rn);
+		return 1;
+	}
+
+	/*
+	 * next unit is unit of extent item. Return without chaning @lh and
+	 * @coord.
+	 */
+	assert("vs-6", item_is_extent(&next));
+	zrelse(rn.node);
+	done_lh(&rn);
+	return 0;
+}
+
+/**
+ * rd_key - calculate key of an item next to the given one
+ * @coord: position in a node
+ * @key: storage for result key
+ *
+ * @coord is set between items or after the last item in a node. Calculate key
+ * of item to the right of @coord.
+ */
+static reiser4_key *rd_key(const coord_t *coord, reiser4_key *key)
+{
+	coord_t dup;
+
+	assert("nikita-2281", coord_is_between_items(coord));
+	coord_dup(&dup, coord);
+
+	if (coord_set_to_right(&dup) == 0)
+		/* next item is in this node. Return its key. */
+		unit_key_by_coord(&dup, key);
+	else {
+		/*
+		 * next item either does not exist or is in right
+		 * neighbor. Return znode's right delimiting key.
+		 */
+		read_lock_dk(current_tree);
+		*key = *znode_get_rd_key(coord->node);
+		read_unlock_dk(current_tree);
+	}
+	return key;
+}
+
+/**
+ * add_empty_leaf - insert empty leaf between two extents
+ * @insert_coord: position in twig node between two extents
+ * @lh: twig node lock handle
+ * @key: left delimiting key of new node
+ * @rdkey: right delimiting key of new node
+ *
+ * Inserts empty leaf node between two extent items. It is necessary when we
+ * have to insert an item on leaf level between two extents (items on the twig
+ * level).
+ */
+static int
+add_empty_leaf(coord_t *insert_coord, lock_handle *lh,
+	       const reiser4_key *key, const reiser4_key *rdkey)
+{
+	int result;
+	carry_pool *pool;
+	carry_level *todo;
+	reiser4_item_data *item;
+	carry_insert_data *cdata;
+	carry_op *op;
+	znode *node;
+	reiser4_tree *tree;
+
+	assert("vs-49827", znode_contains_key_lock(insert_coord->node, key));
+	tree = znode_get_tree(insert_coord->node);
+	node = new_node(insert_coord->node, LEAF_LEVEL);
+	if (IS_ERR(node))
+		return PTR_ERR(node);
+
+	/* setup delimiting keys for node being inserted */
+	write_lock_dk(tree);
+	znode_set_ld_key(node, key);
+	znode_set_rd_key(node, rdkey);
+	ON_DEBUG(node->creator = current);
+	ON_DEBUG(node->first_key = *key);
+	write_unlock_dk(tree);
+
+	ZF_SET(node, JNODE_ORPHAN);
+
+	/*
+	 * allocate carry_pool, 3 carry_level-s, reiser4_item_data and
+	 * carry_insert_data
+	 */
+	pool = init_carry_pool(sizeof(*pool) + 3 * sizeof(*todo) +
+			       sizeof(*item) + sizeof(*cdata));
+	if (IS_ERR(pool))
+		return PTR_ERR(pool);
+	todo = (carry_level *) (pool + 1);
+	init_carry_level(todo, pool);
+
+	item = (reiser4_item_data *) (todo + 3);
+	cdata = (carry_insert_data *) (item + 1);
+
+	op = post_carry(todo, COP_INSERT, insert_coord->node, 0);
+	if (!IS_ERR(op)) {
+		cdata->coord = insert_coord;
+		cdata->key = key;
+		cdata->data = item;
+		op->u.insert.d = cdata;
+		op->u.insert.type = COPT_ITEM_DATA;
+		build_child_ptr_data(node, item);
+		item->arg = NULL;
+		/* have @insert_coord to be set at inserted item after
+		   insertion is done */
+		todo->track_type = CARRY_TRACK_CHANGE;
+		todo->tracked = lh;
+
+		result = carry(todo, NULL);
+		if (result == 0) {
+			/*
+			 * pin node in memory. This is necessary for
+			 * znode_make_dirty() below.
+			 */
+			result = zload(node);
+			if (result == 0) {
+				lock_handle local_lh;
+
+				/*
+				 * if we inserted new child into tree we have
+				 * to mark it dirty so that flush will be able
+				 * to process it.
+				 */
+				init_lh(&local_lh);
+				result = longterm_lock_znode(&local_lh, node,
+							     ZNODE_WRITE_LOCK,
+							     ZNODE_LOCK_LOPRI);
+				if (result == 0) {
+					znode_make_dirty(node);
+
+					/*
+					 * when internal item pointing to @node
+					 * was inserted into twig node
+					 * create_hook_internal did not connect
+					 * it properly because its right
+					 * neighbor was not known. Do it
+					 * here
+					 */
+					write_lock_tree(tree);
+					assert("nikita-3312",
+					       znode_is_right_connected(node));
+					assert("nikita-2984",
+					       node->right == NULL);
+					ZF_CLR(node, JNODE_RIGHT_CONNECTED);
+					write_unlock_tree(tree);
+					result =
+					    connect_znode(insert_coord, node);
+					if (result == 0)
+						ON_DEBUG(check_dkeys(node));
+
+					done_lh(lh);
+					move_lh(lh, &local_lh);
+					assert("vs-1676", node_is_empty(node));
+					coord_init_first_unit(insert_coord,
+							      node);
+				} else {
+					warning("nikita-3136",
+						"Cannot lock child");
+				}
+				done_lh(&local_lh);
+				zrelse(node);
+			}
+		}
+	} else
+		result = PTR_ERR(op);
+	zput(node);
+	done_carry_pool(pool);
+	return result;
+}
+
+/**
+ * handle_eottl - handle extent-on-the-twig-level cases in tree traversal
+ * @h: search handle
+ * @outcome: flag saying whether search has to restart or is done
+ *
+ * Handles search on twig level. If this function completes search itself then
+ * it returns 1. If search has to go one level down then 0 is returned. If
+ * error happens then LOOKUP_DONE is returned via @outcome and error code is saved
+ * in @h->result.
+ */
+int handle_eottl(cbk_handle *h, int *outcome)
+{
+	int result;
+	reiser4_key key;
+	coord_t *coord;
+
+	coord = h->coord;
+
+	if (h->level != TWIG_LEVEL ||
+	    (coord_is_existing_item(coord) && item_is_internal(coord))) {
+		/* Continue to traverse tree downward. */
+		return 0;
+	}
+
+	/*
+	 * make sure that @h->coord is set to twig node and that it is either
+	 * set to extent item or after extent item
+	 */
+	assert("vs-356", h->level == TWIG_LEVEL);
+	assert("vs-357", ( {
+			  coord_t lcoord;
+			  coord_dup(&lcoord, coord);
+			  check_me("vs-733", coord_set_to_left(&lcoord) == 0);
+			  item_is_extent(&lcoord);
+			  }
+	       ));
+
+	if (*outcome == NS_FOUND) {
+		/* we have found desired key on twig level in extent item */
+		h->result = CBK_COORD_FOUND;
+		*outcome = LOOKUP_DONE;
+		return 1;
+	}
+
+	if (!(h->flags & CBK_FOR_INSERT)) {
+		/* tree traversal is not for insertion. Just return
+		   CBK_COORD_NOTFOUND. */
+		h->result = CBK_COORD_NOTFOUND;
+		*outcome = LOOKUP_DONE;
+		return 1;
+	}
+
+	/* take a look at the item to the right of h -> coord */
+	result = is_next_item_internal(coord, h->key, h->active_lh);
+	if (unlikely(result < 0)) {
+		h->error = "get_right_neighbor failed";
+		h->result = result;
+		*outcome = LOOKUP_DONE;
+		return 1;
+	}
+	if (result == 0) {
+		/*
+		 * item to the right is also an extent one. Allocate a new node
+		 * and insert pointer to it after item h -> coord.
+		 *
+		 * This is a result of extents being located at the twig
+		 * level. For explanation, see comment just above
+		 * is_next_item_internal().
+		 */
+		znode *loaded;
+
+		if (cbk_lock_mode(h->level, h) != ZNODE_WRITE_LOCK) {
+			/*
+			 * we got node read locked, restart coord_by_key to
+			 * have write lock on twig level
+			 */
+			h->lock_level = TWIG_LEVEL;
+			h->lock_mode = ZNODE_WRITE_LOCK;
+			*outcome = LOOKUP_REST;
+			return 1;
+		}
+
+		loaded = coord->node;
+		result =
+		    add_empty_leaf(coord, h->active_lh, h->key,
+				   rd_key(coord, &key));
+		if (result) {
+			h->error = "could not add empty leaf";
+			h->result = result;
+			*outcome = LOOKUP_DONE;
+			return 1;
+		}
+		/* added empty leaf is locked (h->active_lh), its parent node
+		   is unlocked, h->coord is set as EMPTY */
+		assert("vs-13", coord->between == EMPTY_NODE);
+		assert("vs-14", znode_is_write_locked(coord->node));
+		assert("vs-15",
+		       WITH_DATA(coord->node, node_is_empty(coord->node)));
+		assert("vs-16", jnode_is_leaf(ZJNODE(coord->node)));
+		assert("vs-17", coord->node == h->active_lh->node);
+		*outcome = LOOKUP_DONE;
+		h->result = CBK_COORD_NOTFOUND;
+		return 1;
+	} else if (result == 1) {
+		/*
+		 * this is special case mentioned in the comment on
+		 * tree.h:cbk_flags. We have found internal item immediately on
+		 * the right of extent, and we are going to insert new item
+		 * there. Key of item we are going to insert is smaller than
+		 * leftmost key in the node pointed to by said internal item
+		 * (otherwise search wouldn't come to the extent in the first
+		 * place).
+		 *
+		 * This is a result of extents being located at the twig
+		 * level. For explanation, see comment just above
+		 * is_next_item_internal().
+		 */
+		h->flags &= ~CBK_TRUST_DK;
+	} else {
+		assert("vs-8", result == 2);
+		*outcome = LOOKUP_REST;
+		return 1;
+	}
+	assert("vs-362", WITH_DATA(coord->node, item_is_internal(coord)));
+	return 0;
+}
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 120
+ * scroll-step: 1
+ * End:
+ */
diff -urN oldtree/fs/reiser4/estimate.c newtree/fs/reiser4/estimate.c
--- oldtree/fs/reiser4/estimate.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/estimate.c	2006-02-21 15:58:35.429760416 +0000
@@ -0,0 +1,111 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#include "debug.h"
+#include "dformat.h"
+#include "tree.h"
+#include "carry.h"
+#include "inode.h"
+#include "plugin/cluster.h"
+#include "plugin/item/ctail.h"
+
+/* this returns how many nodes might get dirty and added nodes if @children nodes are dirtied
+
+   Amount of internals which will get dirty or get allocated we estimate as 5% of the childs + 1 balancing. 1 balancing
+   is 2 neighbours, 2 new blocks and the current block on the leaf level, 2 neighbour nodes + the current (or 1
+   neighbour and 1 new and the current) on twig level, 2 neighbour nodes on upper levels and 1 for a new root. So 5 for
+   leaf level, 3 for twig level, 2 on upper + 1 for root.
+
+   Do not calculate the current node of the lowest level here - this is overhead only.
+
+   children is almost always 1 here. Exception is flow insertion
+*/
+static reiser4_block_nr
+max_balance_overhead(reiser4_block_nr childen, tree_level tree_height)
+{
+	reiser4_block_nr ten_percent;
+
+	ten_percent = ((103 * childen) >> 10);
+
+	/* If we have too many balancings at the time, tree height can raise on more
+	   then 1. Assume that if tree_height is 5, it can raise on 1 only. */
+	return ((tree_height < 5 ? 5 : tree_height) * 2 + (4 + ten_percent));
+}
+
+/* this returns maximal possible number of nodes which can be modified plus number of new nodes which can be required to
+   perform insertion of one item into the tree */
+/* it is only called when tree height changes, or gets initialized */
+reiser4_block_nr calc_estimate_one_insert(tree_level height)
+{
+	return 1 + max_balance_overhead(1, height);
+}
+
+reiser4_block_nr estimate_one_insert_item(reiser4_tree * tree)
+{
+	return tree->estimate_one_insert;
+}
+
+/* this returns maximal possible number of nodes which can be modified plus number of new nodes which can be required to
+   perform insertion of one unit into an item in the tree */
+reiser4_block_nr estimate_one_insert_into_item(reiser4_tree * tree)
+{
+	/* estimate insert into item just like item insertion */
+	return tree->estimate_one_insert;
+}
+
+reiser4_block_nr estimate_one_item_removal(reiser4_tree * tree)
+{
+	/* on item removal reiser4 does not try to pack nodes more complact, so, only one node may be dirtied on leaf
+	   level */
+	return tree->estimate_one_insert;
+}
+
+/* on leaf level insert_flow may add CARRY_FLOW_NEW_NODES_LIMIT new nodes and dirty 3 existing nodes (insert point and
+   both its neighbors). Max_balance_overhead should estimate number of blocks which may change/get added on internal
+   levels */
+reiser4_block_nr estimate_insert_flow(tree_level height)
+{
+	return 3 + CARRY_FLOW_NEW_NODES_LIMIT + max_balance_overhead(3 +
+								     CARRY_FLOW_NEW_NODES_LIMIT,
+								     height);
+}
+
+/* returnes max number of nodes can be occupied by disk cluster */
+reiser4_block_nr estimate_cluster(struct inode * inode, int unprepped)
+{
+	int per_cluster;
+	per_cluster = (unprepped ? 1 : cluster_nrpages(inode));
+	return 3 + per_cluster +
+		max_balance_overhead(3 + per_cluster,
+				     REISER4_MAX_ZTREE_HEIGHT);
+}
+
+/* how many nodes might get dirty and added
+   during insertion of a disk cluster */
+reiser4_block_nr estimate_insert_cluster(struct inode * inode)
+{
+	return estimate_cluster(inode, 1); /* 24 */
+}
+
+/* how many nodes might get dirty and added
+   during update of a (prepped or unprepped) disk cluster */
+reiser4_block_nr estimate_update_cluster(struct inode * inode)
+{
+	return estimate_cluster(inode, 0); /* 44, for 64K-cluster */
+}
+
+/* how many nodes occupied by a disk cluster might get dirty */
+reiser4_block_nr estimate_dirty_cluster(struct inode * inode)
+{
+	return 2 + cluster_nrpages(inode);
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/export_ops.c newtree/fs/reiser4/export_ops.c
--- oldtree/fs/reiser4/export_ops.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/export_ops.c	2006-02-21 15:58:34.532896760 +0000
@@ -0,0 +1,296 @@
+/* Copyright 2005 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+#include "inode.h"
+#include "plugin/plugin.h"
+
+
+/*
+ * Supported file-handle types
+ */
+typedef enum {
+	FH_WITH_PARENT = 0x10,	/* file handle with parent */
+	FH_WITHOUT_PARENT = 0x11	/* file handle without parent */
+} reiser4_fhtype;
+
+#define NFSERROR (255)
+
+/* initialize place-holder for object */
+static void object_on_wire_init(reiser4_object_on_wire *o)
+{
+	o->plugin = NULL;
+}
+
+/* finish with @o */
+static void object_on_wire_done(reiser4_object_on_wire *o)
+{
+	if (o->plugin != NULL)
+		o->plugin->wire.done(o);
+}
+
+/*
+ * read serialized object identity from @addr and store information about
+ * object in @obj. This is dual to encode_inode().
+ */
+static char *decode_inode(struct super_block *s, char *addr,
+			  reiser4_object_on_wire * obj)
+{
+	file_plugin *fplug;
+
+	/* identifier of object plugin is stored in the first two bytes,
+	 * followed by... */
+	fplug = file_plugin_by_disk_id(get_tree(s), (d16 *) addr);
+	if (fplug != NULL) {
+		addr += sizeof(d16);
+		obj->plugin = fplug;
+		assert("nikita-3520", fplug->wire.read != NULL);
+		/* plugin specific encoding of object identity. */
+		addr = fplug->wire.read(addr, obj);
+	} else
+		addr = ERR_PTR(RETERR(-EINVAL));
+	return addr;
+}
+
+/**
+ * reiser4_decode_fh - decode_fh of export operations
+ * @super: super block
+ * @fh: nfsd file handle
+ * @len: length of file handle
+ * @fhtype: type of file handle
+ * @acceptable: acceptability testing function
+ * @context: argument for @acceptable
+ *
+ * Returns dentry referring to the same file as @fh.
+ */
+static struct dentry *reiser4_decode_fh(struct super_block *super, __u32 *fh,
+					int len, int fhtype,
+					int (*acceptable) (void *context,
+							   struct dentry *de),
+					void *context)
+{
+	reiser4_context *ctx;
+	reiser4_object_on_wire object;
+	reiser4_object_on_wire parent;
+	char *addr;
+	int with_parent;
+
+	ctx = init_context(super);
+	if (IS_ERR(ctx))
+		return (struct dentry *)ctx;
+
+	assert("vs-1482",
+	       fhtype == FH_WITH_PARENT || fhtype == FH_WITHOUT_PARENT);
+
+	with_parent = (fhtype == FH_WITH_PARENT);
+
+	addr = (char *)fh;
+
+	object_on_wire_init(&object);
+	object_on_wire_init(&parent);
+
+	addr = decode_inode(super, addr, &object);
+	if (!IS_ERR(addr)) {
+		if (with_parent)
+			addr = decode_inode(super, addr, &parent);
+		if (!IS_ERR(addr)) {
+			struct dentry *d;
+			typeof(super->s_export_op->find_exported_dentry) fn;
+
+			fn = super->s_export_op->find_exported_dentry;
+			assert("nikita-3521", fn != NULL);
+			d = fn(super, &object, with_parent ? &parent : NULL,
+			       acceptable, context);
+			if (d != NULL && !IS_ERR(d))
+				/* FIXME check for -ENOMEM */
+			  	reiser4_get_dentry_fsdata(d)->stateless = 1;
+			addr = (char *)d;
+		}
+	}
+
+	object_on_wire_done(&object);
+	object_on_wire_done(&parent);
+
+	reiser4_exit_context(ctx);
+	return (void *)addr;
+}
+
+/*
+ * Object serialization support.
+ *
+ * To support knfsd file system provides export_operations that are used to
+ * construct and interpret NFS file handles. As a generalization of this,
+ * reiser4 object plugins have serialization support: it provides methods to
+ * create on-wire representation of identity of reiser4 object, and
+ * re-create/locate object given its on-wire identity.
+ *
+ */
+
+/*
+ * return number of bytes that on-wire representation of @inode's identity
+ * consumes.
+ */
+static int encode_inode_size(struct inode *inode)
+{
+	assert("nikita-3514", inode != NULL);
+	assert("nikita-3515", inode_file_plugin(inode) != NULL);
+	assert("nikita-3516", inode_file_plugin(inode)->wire.size != NULL);
+
+	return inode_file_plugin(inode)->wire.size(inode) + sizeof(d16);
+}
+
+/*
+ * store on-wire representation of @inode's identity at the area beginning at
+ * @start.
+ */
+static char *encode_inode(struct inode *inode, char *start)
+{
+	assert("nikita-3517", inode != NULL);
+	assert("nikita-3518", inode_file_plugin(inode) != NULL);
+	assert("nikita-3519", inode_file_plugin(inode)->wire.write != NULL);
+
+	/*
+	 * first, store two-byte identifier of object plugin, then
+	 */
+	save_plugin_id(file_plugin_to_plugin(inode_file_plugin(inode)),
+		       (d16 *) start);
+	start += sizeof(d16);
+	/*
+	 * call plugin to serialize object's identity
+	 */
+	return inode_file_plugin(inode)->wire.write(inode, start);
+}
+
+/* this returns number of 32 bit long numbers encoded in @lenp. 255 is
+ * returned if file handle can not be stored */
+/**
+ * reiser4_encode_fh - encode_fh of export operations
+ * @dentry:
+ * @fh:
+ * @lenp:
+ * @need_parent:
+ *
+ */
+static int
+reiser4_encode_fh(struct dentry *dentry, __u32 *fh, int *lenp,
+		  int need_parent)
+{
+	struct inode *inode;
+	struct inode *parent;
+	char *addr;
+	int need;
+	int delta;
+	int result;
+	reiser4_context *ctx;
+
+	/*
+	 * knfsd asks as to serialize object in @dentry, and, optionally its
+	 * parent (if need_parent != 0).
+	 *
+	 * encode_inode() and encode_inode_size() is used to build
+	 * representation of object and its parent. All hard work is done by
+	 * object plugins.
+	 */
+	inode = dentry->d_inode;
+	parent = dentry->d_parent->d_inode;
+
+	addr = (char *)fh;
+
+	need = encode_inode_size(inode);
+	if (need < 0)
+		return NFSERROR;
+	if (need_parent) {
+		delta = encode_inode_size(parent);
+		if (delta < 0)
+			return NFSERROR;
+		need += delta;
+	}
+
+	ctx = init_context(dentry->d_inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	if (need <= sizeof(__u32) * (*lenp)) {
+		addr = encode_inode(inode, addr);
+		if (need_parent)
+			addr = encode_inode(parent, addr);
+
+		/* store in lenp number of 32bit words required for file
+		 * handle. */
+		*lenp = (need + sizeof(__u32) - 1) >> 2;
+		result = need_parent ? FH_WITH_PARENT : FH_WITHOUT_PARENT;
+	} else
+		/* no enough space in file handle */
+		result = NFSERROR;
+	reiser4_exit_context(ctx);
+	return result;
+}
+
+/**
+ * reiser4_get_dentry_parent - get_parent of export operations
+ * @child:
+ *
+ */
+static struct dentry *reiser4_get_dentry_parent(struct dentry *child)
+{
+	struct inode *dir;
+	dir_plugin *dplug;
+
+	assert("nikita-3527", child != NULL);
+	/* see comment in reiser4_get_dentry() about following assertion */
+	assert("nikita-3528", is_in_reiser4_context());
+
+	dir = child->d_inode;
+	assert("nikita-3529", dir != NULL);
+	dplug = inode_dir_plugin(dir);
+	assert("nikita-3531", ergo(dplug != NULL, dplug->get_parent != NULL));
+	if (dplug != NULL)
+		return dplug->get_parent(dir);
+	else
+		return ERR_PTR(RETERR(-ENOTDIR));
+}
+
+/**
+ * reiser4_get_dentry - get_dentry of export operations
+ * @super:
+ * @data:
+ *
+ *
+ */
+static struct dentry *reiser4_get_dentry(struct super_block *super, void *data)
+{
+	reiser4_object_on_wire *o;
+
+	assert("nikita-3522", super != NULL);
+	assert("nikita-3523", data != NULL);
+	/*
+	 * this is only supposed to be called by
+	 *
+	 *     reiser4_decode_fh->find_exported_dentry
+	 *
+	 * so, reiser4_context should be here already.
+	 */
+	assert("nikita-3526", is_in_reiser4_context());
+
+	o = (reiser4_object_on_wire *)data;
+	assert("nikita-3524", o->plugin != NULL);
+	assert("nikita-3525", o->plugin->wire.get != NULL);
+
+	return o->plugin->wire.get(super, o);
+}
+
+struct export_operations reiser4_export_operations = {
+	.encode_fh = reiser4_encode_fh,
+	.decode_fh = reiser4_decode_fh,
+	.get_parent = reiser4_get_dentry_parent,
+	.get_dentry = reiser4_get_dentry
+};
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * End:
+ */
diff -urN oldtree/fs/reiser4/flush.c newtree/fs/reiser4/flush.c
--- oldtree/fs/reiser4/flush.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/flush.c	2006-02-21 15:58:35.433759808 +0000
@@ -0,0 +1,3640 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* The design document for this file is at http://www.namesys.com/v4/v4.html. */
+
+#include "forward.h"
+#include "debug.h"
+#include "dformat.h"
+#include "key.h"
+#include "coord.h"
+#include "plugin/item/item.h"
+#include "plugin/plugin.h"
+#include "plugin/object.h"
+#include "txnmgr.h"
+#include "jnode.h"
+#include "znode.h"
+#include "block_alloc.h"
+#include "tree_walk.h"
+#include "carry.h"
+#include "tree.h"
+#include "vfs_ops.h"
+#include "inode.h"
+#include "page_cache.h"
+#include "wander.h"
+#include "super.h"
+#include "entd.h"
+#include "reiser4.h"
+#include "flush.h"
+#include "writeout.h"
+
+#include <asm/atomic.h>
+#include <linux/fs.h>		/* for struct super_block  */
+#include <linux/mm.h>		/* for struct page */
+#include <linux/bio.h>		/* for struct bio */
+#include <linux/pagemap.h>
+#include <linux/blkdev.h>
+
+/* IMPLEMENTATION NOTES */
+
+/* PARENT-FIRST: Some terminology: A parent-first traversal is a way of assigning a total
+   order to the nodes of the tree in which the parent is placed before its children, which
+   are ordered (recursively) in left-to-right order.  When we speak of a "parent-first preceder", it
+   describes the node that "came before in forward parent-first order".  When we speak of a
+   "parent-first follower", it describes the node that "comes next in parent-first
+   order" (alternatively the node that "came before in reverse parent-first order").
+
+   The following pseudo-code prints the nodes of a tree in forward parent-first order:
+
+   void parent_first (node)
+   {
+     print_node (node);
+     if (node->level > leaf) {
+       for (i = 0; i < num_children; i += 1) {
+         parent_first (node->child[i]);
+       }
+     }
+   }
+*/
+
+/* JUST WHAT ARE WE TRYING TO OPTIMIZE, HERE?  The idea is to optimize block allocation so
+   that a left-to-right scan of the tree's data (i.e., the leaves in left-to-right order)
+   can be accomplished with sequential reads, which results in reading nodes in their
+   parent-first order.  This is a read-optimization aspect of the flush algorithm, and
+   there is also a write-optimization aspect, which is that we wish to make large
+   sequential writes to the disk by allocating or reallocating blocks so that they can be
+   written in sequence.  Sometimes the read-optimization and write-optimization goals
+   conflict with each other, as we discuss in more detail below.
+*/
+
+/* STATE BITS: The flush code revolves around the state of the jnodes it covers.  Here are
+   the relevant jnode->state bits and their relevence to flush:
+
+     JNODE_DIRTY: If a node is dirty, it must be flushed.  But in order to be written it
+     must be allocated first.  In order to be considered allocated, the jnode must have
+     exactly one of { JNODE_OVRWR, JNODE_RELOC } set.  These two bits are exclusive, and
+     all dirtied jnodes eventually have one of these bits set during each transaction.
+
+     JNODE_CREATED: The node was freshly created in its transaction and has no previous
+     block address, so it is unconditionally assigned to be relocated, although this is
+     mainly for code-convenience.  It is not being 'relocated' from anything, but in
+     almost every regard it is treated as part of the relocate set.  The JNODE_CREATED bit
+     remains set even after JNODE_RELOC is set, so the actual relocate can be
+     distinguished from the created-and-allocated set easily: relocate-set members
+     (belonging to the preserve-set) have (JNODE_RELOC) set and created-set members which
+     have no previous location to preserve have (JNODE_RELOC | JNODE_CREATED) set.
+
+     JNODE_OVRWR: The node belongs to atom's overwrite set. The flush algorithm made the
+     decision to maintain the pre-existing location for this node and it will be written
+     to the wandered-log.
+
+     JNODE_RELOC: The flush algorithm made the decision to relocate this block (if it was
+     not created, see note above).  A block with JNODE_RELOC set is eligible for
+     early-flushing and may be submitted during flush_empty_queues.  When the JNODE_RELOC
+     bit is set on a znode, the parent node's internal item is modified and the znode is
+     rehashed.
+
+     JNODE_SQUEEZABLE: Before shifting everything left, the flush algorithm scans the node
+     and calls plugin->f.squeeze() method for its items. By this technology we update disk
+     clusters of cryptcompress objects. Also if leftmost point that was found by flush scan
+     has this flag (races with write(), rare case) the flush algorythm makes the decision
+     to pass it to squalloc() in spite of its flushprepped status for squeezing, not for
+     repeated allocation.
+
+     JNODE_FLUSH_QUEUED: This bit is set when a call to flush enters the jnode into its
+     flush queue.  This means the jnode is not on any clean or dirty list, instead it is
+     moved to one of the flush queue (see flush_queue.h) object private list. This
+     prevents multiple concurrent flushes from attempting to start flushing from the
+     same node.
+
+     (DEAD STATE BIT) JNODE_FLUSH_BUSY: This bit was set during the bottom-up
+     squeeze-and-allocate on a node while its children are actively being squeezed and
+     allocated.  This flag was created to avoid submitting a write request for a node
+     while its children are still being allocated and squeezed. Then flush queue was
+     re-implemented to allow unlimited number of nodes be queued. This flag support was
+     commented out in source code because we decided that there was no reason to submit
+     queued nodes before jnode_flush() finishes.  However, current code calls fq_write()
+     during a slum traversal and may submit "busy nodes" to disk. Probably we can
+     re-enable the JNODE_FLUSH_BUSY bit support in future.
+
+   With these state bits, we describe a test used frequently in the code below,
+   jnode_is_flushprepped() (and the spin-lock-taking jnode_check_flushprepped()).  The
+   test for "flushprepped" returns true if any of the following are true:
+
+     - The node is not dirty
+     - The node has JNODE_RELOC set
+     - The node has JNODE_OVRWR set
+
+   If either the node is not dirty or it has already been processed by flush (and assigned
+   JNODE_OVRWR or JNODE_RELOC), then it is prepped.  If jnode_is_flushprepped() returns
+   true then flush has work to do on that node.
+*/
+
+/* FLUSH_PREP_ONCE_PER_TRANSACTION: Within a single transaction a node is never
+   flushprepped twice (unless an explicit call to flush_unprep is made as described in
+   detail below).  For example a node is dirtied, allocated, and then early-flushed to
+   disk and set clean.  Before the transaction commits, the page is dirtied again and, due
+   to memory pressure, the node is flushed again.  The flush algorithm will not relocate
+   the node to a new disk location, it will simply write it to the same, previously
+   relocated position again.
+*/
+
+/* THE BOTTOM-UP VS. TOP-DOWN ISSUE: This code implements a bottom-up algorithm where we
+   start at a leaf node and allocate in parent-first order by iterating to the right.  At
+   each step of the iteration, we check for the right neighbor.  Before advancing to the
+   right neighbor, we check if the current position and the right neighbor share the same
+   parent.  If they do not share the same parent, the parent is allocated before the right
+   neighbor.
+
+   This process goes recursively up the tree and squeeze nodes level by level as long as
+   the right neighbor and the current position have different parents, then it allocates
+   the right-neighbors-with-different-parents on the way back down.  This process is
+   described in more detail in flush_squalloc_changed_ancestor and the recursive function
+   squalloc_one_changed_ancestor.  But the purpose here is not to discuss the
+   specifics of the bottom-up approach as it is to contrast the bottom-up and top-down
+   approaches.
+
+   The top-down algorithm was implemented earlier (April-May 2002).  In the top-down
+   approach, we find a starting point by scanning left along each level past dirty nodes,
+   then going up and repeating the process until the left node and the parent node are
+   clean.  We then perform a parent-first traversal from the starting point, which makes
+   allocating in parent-first order trivial.  After one subtree has been allocated in this
+   manner, we move to the right, try moving upward, then repeat the parent-first
+   traversal.
+
+   Both approaches have problems that need to be addressed.  Both are approximately the
+   same amount of code, but the bottom-up approach has advantages in the order it acquires
+   locks which, at the very least, make it the better approach.  At first glance each one
+   makes the other one look simpler, so it is important to remember a few of the problems
+   with each one.
+
+   Main problem with the top-down approach: When you encounter a clean child during the
+   parent-first traversal, what do you do?  You would like to avoid searching through a
+   large tree of nodes just to find a few dirty leaves at the bottom, and there is not an
+   obvious solution.  One of the advantages of the top-down approach is that during the
+   parent-first traversal you check every child of a parent to see if it is dirty.  In
+   this way, the top-down approach easily handles the main problem of the bottom-up
+   approach: unallocated children.
+
+   The unallocated children problem is that before writing a node to disk we must make
+   sure that all of its children are allocated.  Otherwise, the writing the node means
+   extra I/O because the node will have to be written again when the child is finally
+   allocated.
+
+   WE HAVE NOT YET ELIMINATED THE UNALLOCATED CHILDREN PROBLEM.  Except for bugs, this
+   should not cause any file system corruption, it only degrades I/O performance because a
+   node may be written when it is sure to be written at least one more time in the same
+   transaction when the remaining children are allocated.  What follows is a description
+   of how we will solve the problem.
+*/
+
+/* HANDLING UNALLOCATED CHILDREN: During flush we may allocate a parent node then,
+   proceeding in parent first order, allocate some of its left-children, then encounter a
+   clean child in the middle of the parent.  We do not allocate the clean child, but there
+   may remain unallocated (dirty) children to the right of the clean child.  If we were to
+   stop flushing at this moment and write everything to disk, the parent might still
+   contain unallocated children.
+
+   We could try to allocate all the descendents of every node that we allocate, but this
+   is not necessary.  Doing so could result in allocating the entire tree: if the root
+   node is allocated then every unallocated node would have to be allocated before
+   flushing.  Actually, we do not have to write a node just because we allocate it.  It is
+   possible to allocate but not write a node during flush, when it still has unallocated
+   children.  However, this approach is probably not optimal for the following reason.
+
+   The flush algorithm is designed to allocate nodes in parent-first order in an attempt
+   to optimize reads that occur in the same order.  Thus we are read-optimizing for a
+   left-to-right scan through all the leaves in the system, and we are hoping to
+   write-optimize at the same time because those nodes will be written together in batch.
+   What happens, however, if we assign a block number to a node in its read-optimized
+   order but then avoid writing it because it has unallocated children?  In that
+   situation, we lose out on the write-optimization aspect because a node will have to be
+   written again to the its location on the device, later, which likely means seeking back
+   to that location.
+
+   So there are tradeoffs. We can choose either:
+
+   A. Allocate all unallocated children to preserve both write-optimization and
+   read-optimization, but this is not always desirable because it may mean having to
+   allocate and flush very many nodes at once.
+
+   B. Defer writing nodes with unallocated children, keep their read-optimized locations,
+   but sacrifice write-optimization because those nodes will be written again.
+
+   C. Defer writing nodes with unallocated children, but do not keep their read-optimized
+   locations.  Instead, choose to write-optimize them later, when they are written.  To
+   facilitate this, we "undo" the read-optimized allocation that was given to the node so
+   that later it can be write-optimized, thus "unpreparing" the flush decision.  This is a
+   case where we disturb the FLUSH_PREP_ONCE_PER_TRANSACTION rule described above.  By a
+   call to flush_unprep() we will: if the node was wandered, unset the JNODE_OVRWR bit;
+   if the node was relocated, unset the JNODE_RELOC bit, non-deferred-deallocate its block
+   location, and set the JNODE_CREATED bit, effectively setting the node back to an
+   unallocated state.
+
+   We will take the following approach in v4.0: for twig nodes we will always finish
+   allocating unallocated children (A).  For nodes with (level > TWIG) we will defer
+   writing and choose write-optimization (C).
+
+   To summarize, there are several parts to a solution that avoids the problem with
+   unallocated children:
+
+   FIXME-ZAM: Still no one approach is implemented to eliminate the "UNALLOCATED CHILDREN"
+   problem because there was an experiment which was done showed that we have 1-2 nodes
+   with unallocated children for thousands of written nodes.  The experiment was simple
+   like coping / deletion of linux kernel sources.  However the problem can arise in more
+   complex tests.  I think we have jnode_io_hook to insert a check for unallocated
+   children and see what kind of problem we have.
+
+   1. When flush reaches a stopping point (e.g., a clean node), it should continue calling
+   squeeze-and-allocate on any remaining unallocated children.  FIXME: Difficulty to
+   implement: should be simple -- amounts to adding a while loop to jnode_flush, see
+   comments in that function.
+
+   2. When flush reaches flush_empty_queue(), some of the (level > TWIG) nodes may still
+   have unallocated children.  If the twig level has unallocated children it is an
+   assertion failure.  If a higher-level node has unallocated children, then it should be
+   explicitly de-allocated by a call to flush_unprep().  FIXME: Difficulty to implement:
+   should be simple.
+
+   3. (CPU-Optimization) Checking whether a node has unallocated children may consume more
+   CPU cycles than we would like, and it is possible (but medium complexity) to optimize
+   this somewhat in the case where large sub-trees are flushed.  The following observation
+   helps: if both the left- and right-neighbor of a node are processed by the flush
+   algorithm then the node itself is guaranteed to have all of its children allocated.
+   However, the cost of this check may not be so expensive after all: it is not needed for
+   leaves and flush can guarantee this property for twigs.  That leaves only (level >
+   TWIG) nodes that have to be checked, so this optimization only helps if at least three
+   (level > TWIG) nodes are flushed in one pass, and the savings will be very small unless
+   there are many more (level > TWIG) nodes.  But if there are many (level > TWIG) nodes
+   then the number of blocks being written will be very large, so the savings may be
+   insignificant.  That said, the idea is to maintain both the left and right edges of
+   nodes that are processed in flush.  When flush_empty_queue() is called, a relatively
+   simple test will tell whether the (level > TWIG) node is on the edge.  If it is on the
+   edge, the slow check is necessary, but if it is in the interior then it can be assumed
+   to have all of its children allocated.  FIXME: medium complexity to implement, but
+   simple to verify given that we must have a slow check anyway.
+
+   4. (Optional) This part is optional, not for v4.0--flush should work independently of
+   whether this option is used or not.  Called RAPID_SCAN, the idea is to amend the
+   left-scan operation to take unallocated children into account.  Normally, the left-scan
+   operation goes left as long as adjacent nodes are dirty up until some large maximum
+   value (FLUSH_SCAN_MAXNODES) at which point it stops and begins flushing.  But scan-left
+   may stop at a position where there are unallocated children to the left with the same
+   parent.  When RAPID_SCAN is enabled, the ordinary scan-left operation stops after
+   FLUSH_RELOCATE_THRESHOLD, which is much smaller than FLUSH_SCAN_MAXNODES, then procedes
+   with a rapid scan.  The rapid scan skips all the interior children of a node--if the
+   leftmost child of a twig is dirty, check its left neighbor (the rightmost child of the
+   twig to the left).  If the left neighbor of the leftmost child is also dirty, then
+   continue the scan at the left twig and repeat.  This option will cause flush to
+   allocate more twigs in a single pass, but it also has the potential to write many more
+   nodes than would otherwise be written without the RAPID_SCAN option.  RAPID_SCAN
+   was partially implemented, code removed August 12, 2002 by JMACD.
+*/
+
+/* FLUSH CALLED ON NON-LEAF LEVEL.  Most of our design considerations assume that the
+   starting point for flush is a leaf node, but actually the flush code cares very little
+   about whether or not this is true.  It is possible that all the leaf nodes are flushed
+   and dirty parent nodes still remain, in which case jnode_flush() is called on a
+   non-leaf argument.  Flush doesn't care--it treats the argument node as if it were a
+   leaf, even when it is not.  This is a simple approach, and there may be a more optimal
+   policy but until a problem with this approach is discovered, simplest is probably best.
+
+   NOTE: In this case, the ordering produced by flush is parent-first only if you ignore
+   the leaves.  This is done as a matter of simplicity and there is only one (shaky)
+   justification.  When an atom commits, it flushes all leaf level nodes first, followed
+   by twigs, and so on.  With flushing done in this order, if flush is eventually called
+   on a non-leaf node it means that (somehow) we reached a point where all leaves are
+   clean and only internal nodes need to be flushed.  If that it the case, then it means
+   there were no leaves that were the parent-first preceder/follower of the parent.  This
+   is expected to be a rare case, which is why we do nothing special about it.  However,
+   memory pressure may pass an internal node to flush when there are still dirty leaf
+   nodes that need to be flushed, which could prove our original assumptions
+   "inoperative".  If this needs to be fixed, then scan_left/right should have
+   special checks for the non-leaf levels.  For example, instead of passing from a node to
+   the left neighbor, it should pass from the node to the left neighbor's rightmost
+   descendent (if dirty).
+
+*/
+
+/* UNIMPLEMENTED AS YET: REPACKING AND RESIZING.  We walk the tree in 4MB-16MB chunks, dirtying everything and putting
+   it into a transaction.  We tell the allocator to allocate the blocks as far as possible towards one end of the
+   logical device--the left (starting) end of the device if we are walking from left to right, the right end of the
+   device if we are walking from right to left.  We then make passes in alternating directions, and as we do this the
+   device becomes sorted such that tree order and block number order fully correlate.
+
+   Resizing is done by shifting everything either all the way to the left or all the way
+   to the right, and then reporting the last block.
+*/
+
+/* RELOCATE DECISIONS: The code makes a decision to relocate in several places.  This
+   descibes the policy from the highest level:
+
+   The FLUSH_RELOCATE_THRESHOLD parameter: If we count this many consecutive nodes on the
+   leaf level during flush-scan (right, left), then we unconditionally decide to relocate
+   leaf nodes.
+
+   Otherwise, there are two contexts in which we make a decision to relocate:
+
+   1. The REVERSE PARENT-FIRST context: Implemented in reverse_relocate_test().
+   During the initial stages of flush, after scan-right completes, we want to ask the
+   question: should we relocate this leaf node and thus dirty the parent node.  Then if
+   the node is a leftmost child its parent is its own parent-first preceder, thus we repeat
+   the question at the next level up, and so on.  In these cases we are moving in the
+   reverse-parent first direction.
+
+   There is another case which is considered the reverse direction, which comes at the end
+   of a twig in reverse_relocate_end_of_twig().  As we finish processing a twig we may
+   reach a point where there is a clean twig to the right with a dirty leftmost child.  In
+   this case, we may wish to relocate the child by testing if it should be relocated
+   relative to its parent.
+
+   2. The FORWARD PARENT-FIRST context: Testing for forward relocation is done in
+   allocate_znode.  What distinguishes the forward parent-first case from the
+   reverse-parent first case is that the preceder has already been allocated in the
+   forward case, whereas in the reverse case we don't know what the preceder is until we
+   finish "going in reverse".  That simplifies the forward case considerably, and there we
+   actually use the block allocator to determine whether, e.g., a block closer to the
+   preceder is available.
+*/
+
+/* SQUEEZE_LEFT_EDGE: Unimplemented idea for future consideration.  The idea is, once we
+   finish scan-left and find a starting point, if the parent's left neighbor is dirty then
+   squeeze the parent's left neighbor and the parent.  This may change the
+   flush-starting-node's parent.  Repeat until the child's parent is stable.  If the child
+   is a leftmost child, repeat this left-edge squeezing operation at the next level up.
+   Note that we cannot allocate extents during this or they will be out of parent-first
+   order.  There is also some difficult coordinate maintenence issues.  We can't do a tree
+   search to find coordinates again (because we hold locks), we have to determine them
+   from the two nodes being squeezed.  Looks difficult, but has potential to increase
+   space utilization. */
+
+/* Flush-scan helper functions. */
+static void scan_init(flush_scan * scan);
+static void scan_done(flush_scan * scan);
+
+/* Flush-scan algorithm. */
+static int scan_left(flush_scan * scan, flush_scan * right, jnode * node,
+		     unsigned limit);
+static int scan_right(flush_scan * scan, jnode * node, unsigned limit);
+static int scan_common(flush_scan * scan, flush_scan * other);
+static int scan_formatted(flush_scan * scan);
+static int scan_unformatted(flush_scan * scan, flush_scan * other);
+static int scan_by_coord(flush_scan * scan);
+
+/* Initial flush-point ancestor allocation. */
+static int alloc_pos_and_ancestors(flush_pos_t * pos);
+static int alloc_one_ancestor(const coord_t * coord, flush_pos_t * pos);
+static int set_preceder(const coord_t * coord_in, flush_pos_t * pos);
+
+/* Main flush algorithm.  Note on abbreviation: "squeeze and allocate" == "squalloc". */
+static int squalloc(flush_pos_t * pos);
+
+/* Flush squeeze implementation. */
+static int squeeze_right_non_twig(znode * left, znode * right);
+static int shift_one_internal_unit(znode * left, znode * right);
+
+/* Flush reverse parent-first relocation routines. */
+static int reverse_relocate_if_close_enough(const reiser4_block_nr * pblk,
+					    const reiser4_block_nr * nblk);
+static int reverse_relocate_test(jnode * node, const coord_t * parent_coord,
+				 flush_pos_t * pos);
+static int reverse_relocate_check_dirty_parent(jnode * node,
+					       const coord_t * parent_coord,
+					       flush_pos_t * pos);
+
+/* Flush allocate write-queueing functions: */
+static int allocate_znode(znode * node, const coord_t * parent_coord,
+			  flush_pos_t * pos);
+static int allocate_znode_update(znode * node, const coord_t * parent_coord,
+				 flush_pos_t * pos);
+static int lock_parent_and_allocate_znode(znode *, flush_pos_t *);
+
+/* Flush helper functions: */
+static int jnode_lock_parent_coord(jnode * node,
+				   coord_t * coord,
+				   lock_handle * parent_lh,
+				   load_count * parent_zh,
+				   znode_lock_mode mode, int try);
+static int neighbor_in_slum(znode * node, lock_handle * right_lock, sideof side,
+			    znode_lock_mode mode, int check_dirty);
+static int znode_same_parents(znode * a, znode * b);
+
+static int znode_check_flushprepped(znode * node)
+{
+	return jnode_check_flushprepped(ZJNODE(node));
+}
+
+/* Flush position functions */
+static void pos_init(flush_pos_t * pos);
+static int pos_valid(flush_pos_t * pos);
+static void pos_done(flush_pos_t * pos);
+static int pos_stop(flush_pos_t * pos);
+
+/* check that @org is first jnode extent unit, if extent is unallocated,
+ * because all jnodes of unallocated extent are dirty and of the same atom. */
+#define checkchild(scan)						\
+assert("nikita-3435",							\
+       ergo(scan->direction == LEFT_SIDE &&				\
+            (scan->parent_coord.node->level == TWIG_LEVEL) &&           \
+	    jnode_is_unformatted(scan->node) &&				\
+	    extent_is_unallocated(&scan->parent_coord),			\
+	    extent_unit_index(&scan->parent_coord) == index_jnode(scan->node)))
+
+/* This flush_cnt variable is used to track the number of concurrent flush operations,
+   useful for debugging.  It is initialized in txnmgr.c out of laziness (because flush has
+   no static initializer function...) */
+ON_DEBUG(atomic_t flush_cnt;
+    )
+
+/* check fs backing device for write congestion */
+static int check_write_congestion(void)
+{
+	struct super_block *sb;
+	struct backing_dev_info *bdi;
+
+	sb = reiser4_get_current_sb();
+	bdi = get_super_fake(sb)->i_mapping->backing_dev_info;
+	return bdi_write_congested(bdi);
+}
+
+/* conditionally write flush queue */
+static int write_prepped_nodes(flush_pos_t * pos)
+{
+	int ret;
+
+	assert("zam-831", pos);
+	assert("zam-832", pos->fq);
+
+	if (!(pos->flags & JNODE_FLUSH_WRITE_BLOCKS))
+		return 0;
+
+	if (check_write_congestion())
+		return 0;
+
+	ret = write_fq(pos->fq, pos->nr_written,
+		       WRITEOUT_SINGLE_STREAM | WRITEOUT_FOR_PAGE_RECLAIM);
+	return ret;
+}
+
+/* Proper release all flush pos. resources then move flush position to new
+   locked node */
+static void move_flush_pos(flush_pos_t * pos, lock_handle * new_lock,
+			   load_count * new_load, const coord_t * new_coord)
+{
+	assert("zam-857", new_lock->node == new_load->node);
+
+	if (new_coord) {
+		assert("zam-858", new_coord->node == new_lock->node);
+		coord_dup(&pos->coord, new_coord);
+	} else {
+		coord_init_first_unit(&pos->coord, new_lock->node);
+	}
+
+	if (pos->child) {
+		jput(pos->child);
+		pos->child = NULL;
+	}
+
+	move_load_count(&pos->load, new_load);
+	done_lh(&pos->lock);
+	move_lh(&pos->lock, new_lock);
+}
+
+/* delete empty node which link from the parent still exists. */
+static int delete_empty_node(znode * node)
+{
+	reiser4_key smallest_removed;
+
+	assert("zam-1019", node != NULL);
+	assert("zam-1020", node_is_empty(node));
+	assert("zam-1023", znode_is_wlocked(node));
+
+	return delete_node(node, &smallest_removed, NULL, 1);
+}
+
+/* Prepare flush position for alloc_pos_and_ancestors() and squalloc() */
+static int prepare_flush_pos(flush_pos_t * pos, jnode * org)
+{
+	int ret;
+	load_count load;
+	lock_handle lock;
+
+	init_lh(&lock);
+	init_load_count(&load);
+
+	if (jnode_is_znode(org)) {
+		ret = longterm_lock_znode(&lock, JZNODE(org),
+					  ZNODE_WRITE_LOCK, ZNODE_LOCK_HIPRI);
+		if (ret)
+			return ret;
+
+		ret = incr_load_count_znode(&load, JZNODE(org));
+		if (ret)
+			return ret;
+
+		pos->state =
+		    (jnode_get_level(org) ==
+		     LEAF_LEVEL) ? POS_ON_LEAF : POS_ON_INTERNAL;
+		move_flush_pos(pos, &lock, &load, NULL);
+	} else {
+		coord_t parent_coord;
+		ret = jnode_lock_parent_coord(org, &parent_coord, &lock,
+					      &load, ZNODE_WRITE_LOCK, 0);
+		if (ret)
+			goto done;
+		if (!item_is_extent(&parent_coord)) {
+			/* file was converted to tail, org became HB, we found internal
+			   item */
+			ret = -EAGAIN;
+			goto done;
+		}
+
+		pos->state = POS_ON_EPOINT;
+		move_flush_pos(pos, &lock, &load, &parent_coord);
+		pos->child = jref(org);
+		if (extent_is_unallocated(&parent_coord)
+		    && extent_unit_index(&parent_coord) != index_jnode(org)) {
+			/* @org is not first child of its parent unit. This may happen
+			   because longerm lock of its parent node was released between
+			   scan_left and scan_right. For now work around this having flush to repeat */
+			ret = -EAGAIN;
+		}
+	}
+
+      done:
+	done_load_count(&load);
+	done_lh(&lock);
+	return ret;
+}
+
+/* TODO LIST (no particular order): */
+/* I have labelled most of the legitimate FIXME comments in this file with letters to
+   indicate which issue they relate to.  There are a few miscellaneous FIXMEs with
+   specific names mentioned instead that need to be inspected/resolved. */
+/* B. There is an issue described in reverse_relocate_test having to do with an
+   imprecise is_preceder? check having to do with partially-dirty extents.  The code that
+   sets preceder hints and computes the preceder is basically untested.  Careful testing
+   needs to be done that preceder calculations are done correctly, since if it doesn't
+   affect correctness we will not catch this stuff during regular testing. */
+/* C. EINVAL, E_DEADLOCK, E_NO_NEIGHBOR, ENOENT handling.  It is unclear which of these are
+   considered expected but unlikely conditions.  Flush currently returns 0 (i.e., success
+   but no progress, i.e., restart) whenever it receives any of these in jnode_flush().
+   Many of the calls that may produce one of these return values (i.e.,
+   longterm_lock_znode, reiser4_get_parent, reiser4_get_neighbor, ...) check some of these
+   values themselves and, for instance, stop flushing instead of resulting in a restart.
+   If any of these results are true error conditions then flush will go into a busy-loop,
+   as we noticed during testing when a corrupt tree caused find_child_ptr to return
+   ENOENT.  It needs careful thought and testing of corner conditions.
+*/
+/* D. Atomicity of flush_prep against deletion and flush concurrency.  Suppose a created
+   block is assigned a block number then early-flushed to disk.  It is dirtied again and
+   flush is called again.  Concurrently, that block is deleted, and the de-allocation of
+   its block number does not need to be deferred, since it is not part of the preserve set
+   (i.e., it didn't exist before the transaction).  I think there may be a race condition
+   where flush writes the dirty, created block after the non-deferred deallocated block
+   number is re-allocated, making it possible to write deleted data on top of non-deleted
+   data.  Its just a theory, but it needs to be thought out. */
+/* F. bio_alloc() failure is not handled gracefully. */
+/* G. Unallocated children. */
+/* H. Add a WANDERED_LIST to the atom to clarify the placement of wandered blocks. */
+/* I. Rename flush-scan to scan-point, (flush-pos to flush-point?) */
+
+/* JNODE_FLUSH: MAIN ENTRY POINT */
+/* This is the main entry point for flushing a jnode and its dirty neighborhood (dirty
+   neighborhood is named "slum").  Jnode_flush() is called if reiser4 has to write dirty
+   blocks to disk, it happens when Linux VM decides to reduce number of dirty pages or as
+   a part of transaction commit.
+
+   Our objective here is to prep and flush the slum the jnode belongs to. We want to
+   squish the slum together, and allocate the nodes in it as we squish because allocation
+   of children affects squishing of parents.
+
+   The "argument" @node tells flush where to start.  From there, flush finds the left edge
+   of the slum, and calls squalloc (in which nodes are squeezed and allocated).  To find a
+   "better place" to start squalloc first we perform a flush_scan.
+
+   Flush-scanning may be performed in both left and right directions, but for different
+   purposes.  When scanning to the left, we are searching for a node that precedes a
+   sequence of parent-first-ordered nodes which we will then flush in parent-first order.
+   During flush-scanning, we also take the opportunity to count the number of consecutive
+   leaf nodes.  If this number is past some threshold (FLUSH_RELOCATE_THRESHOLD), then we
+   make a decision to reallocate leaf nodes (thus favoring write-optimization).
+
+   Since the flush argument node can be anywhere in a sequence of dirty leaves, there may
+   also be dirty nodes to the right of the argument.  If the scan-left operation does not
+   count at least FLUSH_RELOCATE_THRESHOLD nodes then we follow it with a right-scan
+   operation to see whether there is, in fact, enough nodes to meet the relocate
+   threshold.  Each right- and left-scan operation uses a single flush_scan object.
+
+   After left-scan and possibly right-scan, we prepare a flush_position object with the
+   starting flush point or parent coordinate, which was determined using scan-left.
+
+   Next we call the main flush routine, squalloc, which iterates along the
+   leaf level, squeezing and allocating nodes (and placing them into the flush queue).
+
+   After squalloc returns we take extra steps to ensure that all the children
+   of the final twig node are allocated--this involves repeating squalloc
+   until we finish at a twig with no unallocated children.
+
+   Finally, we call flush_empty_queue to submit write-requests to disk.  If we encounter
+   any above-twig nodes during flush_empty_queue that still have unallocated children, we
+   flush_unprep them.
+
+   Flush treats several "failure" cases as non-failures, essentially causing them to start
+   over.  E_DEADLOCK is one example.  FIXME:(C) EINVAL, E_NO_NEIGHBOR, ENOENT: these should
+   probably be handled properly rather than restarting, but there are a bunch of cases to
+   audit.
+*/
+
+static int
+jnode_flush(jnode * node, long nr_to_write, long *nr_written,
+	    flush_queue_t * fq, int flags)
+{
+	long ret = 0;
+	flush_scan *right_scan;
+	flush_scan *left_scan;
+	flush_pos_t *flush_pos;
+	int todo;
+	struct super_block *sb;
+	reiser4_super_info_data *sbinfo;
+	jnode *leftmost_in_slum = NULL;
+
+	assert("jmacd-76619", lock_stack_isclean(get_current_lock_stack()));
+	assert("nikita-3022", schedulable());
+
+	/* lock ordering: delete_sema and flush_sema are unordered */
+	assert("nikita-3185",
+	       get_current_super_private()->delete_sema_owner != current);
+
+	/* allocate right_scan, left_scan and flush_pos */
+	right_scan =
+	    kmalloc(2 * sizeof(*right_scan) + sizeof(*flush_pos), GFP_KERNEL);
+	if (right_scan == NULL)
+		return RETERR(-ENOMEM);
+	left_scan = right_scan + 1;
+	flush_pos = (flush_pos_t *) (left_scan + 1);
+
+	sb = reiser4_get_current_sb();
+	sbinfo = get_super_private(sb);
+	if (!reiser4_is_set(sb, REISER4_MTFLUSH)) {
+		down(&sbinfo->flush_sema);
+	}
+
+	/* Flush-concurrency debug code */
+#if REISER4_DEBUG
+	atomic_inc(&flush_cnt);
+#endif
+
+	enter_flush(sb);
+
+	/* Initialize a flush position. */
+	pos_init(flush_pos);
+
+	flush_pos->nr_written = nr_written;
+	flush_pos->fq = fq;
+	flush_pos->flags = flags;
+	flush_pos->nr_to_write = nr_to_write;
+
+	scan_init(right_scan);
+	scan_init(left_scan);
+
+	/* First scan left and remember the leftmost scan position.  If the leftmost
+	   position is unformatted we remember its parent_coord.  We scan until counting
+	   FLUSH_SCAN_MAXNODES.
+
+	   If starting @node is unformatted, at the beginning of left scan its
+	   parent (twig level node, containing extent item) will be long term
+	   locked and lock handle will be stored in the
+	   @right_scan->parent_lock. This lock is used to start the rightward
+	   scan without redoing the tree traversal (necessary to find parent)
+	   and, hence, is kept during leftward scan. As a result, we have to
+	   use try-lock when taking long term locks during the leftward scan.
+	 */
+	ret = scan_left(left_scan, right_scan,
+			node, sbinfo->flush.scan_maxnodes);
+	if (ret != 0)
+		goto failed;
+
+	leftmost_in_slum = jref(left_scan->node);
+	scan_done(left_scan);
+
+	/* Then possibly go right to decide if we will use a policy of relocating leaves.
+	   This is only done if we did not scan past (and count) enough nodes during the
+	   leftward scan.  If we do scan right, we only care to go far enough to establish
+	   that at least FLUSH_RELOCATE_THRESHOLD number of nodes are being flushed.  The
+	   scan limit is the difference between left_scan.count and the threshold. */
+
+	todo = sbinfo->flush.relocate_threshold - left_scan->count;
+	/* scan right is inherently deadlock prone, because we are
+	 * (potentially) holding a lock on the twig node at this moment.
+	 * FIXME: this is incorrect comment: lock is not held */
+	if (todo > 0) {
+		ret = scan_right(right_scan, node, (unsigned)todo);
+		if (ret != 0)
+			goto failed;
+	}
+
+	/* Only the right-scan count is needed, release any rightward locks right away. */
+	scan_done(right_scan);
+
+	/* ... and the answer is: we should relocate leaf nodes if at least
+	   FLUSH_RELOCATE_THRESHOLD nodes were found. */
+	flush_pos->leaf_relocate = JF_ISSET(node, JNODE_REPACK) ||
+	    (left_scan->count + right_scan->count >=
+	     sbinfo->flush.relocate_threshold);
+
+	/* Funny business here.  We set the 'point' in the flush_position at prior to
+	   starting squalloc regardless of whether the first point is
+	   formatted or unformatted.  Without this there would be an invariant, in the
+	   rest of the code, that if the flush_position is unformatted then
+	   flush_position->point is NULL and flush_position->parent_{lock,coord} is set,
+	   and if the flush_position is formatted then flush_position->point is non-NULL
+	   and no parent info is set.
+
+	   This seems lazy, but it makes the initial calls to reverse_relocate_test
+	   (which ask "is it the pos->point the leftmost child of its parent") much easier
+	   because we know the first child already.  Nothing is broken by this, but the
+	   reasoning is subtle.  Holding an extra reference on a jnode during flush can
+	   cause us to see nodes with HEARD_BANSHEE during squalloc, because nodes are not
+	   removed from sibling lists until they have zero reference count.  Flush would
+	   never observe a HEARD_BANSHEE node on the left-edge of flush, nodes are only
+	   deleted to the right.  So if nothing is broken, why fix it?
+
+	   NOTE-NIKITA actually, flush can meet HEARD_BANSHEE node at any
+	   point and in any moment, because of the concurrent file system
+	   activity (for example, truncate). */
+
+	/* Check jnode state after flush_scan completed. Having a lock on this
+	   node or its parent (in case of unformatted) helps us in case of
+	   concurrent flushing. */
+	if (jnode_check_flushprepped(leftmost_in_slum)
+	    && !jnode_convertible(leftmost_in_slum)) {
+		ret = 0;
+		goto failed;
+	}
+
+	/* Now setup flush_pos using scan_left's endpoint. */
+	ret = prepare_flush_pos(flush_pos, leftmost_in_slum);
+	if (ret)
+		goto failed;
+
+	if (znode_get_level(flush_pos->coord.node) == LEAF_LEVEL
+	    && node_is_empty(flush_pos->coord.node)) {
+		znode *empty = flush_pos->coord.node;
+
+		assert("zam-1022", !ZF_ISSET(empty, JNODE_HEARD_BANSHEE));
+		ret = delete_empty_node(empty);
+		goto failed;
+	}
+
+	if (jnode_check_flushprepped(leftmost_in_slum)
+	    && !jnode_convertible(leftmost_in_slum)) {
+		ret = 0;
+		goto failed;
+	}
+
+	/* Set pos->preceder and (re)allocate pos and its ancestors if it is needed  */
+	ret = alloc_pos_and_ancestors(flush_pos);
+	if (ret)
+		goto failed;
+
+	/* Do the main rightward-bottom-up squeeze and allocate loop. */
+	ret = squalloc(flush_pos);
+	pos_stop(flush_pos);
+	if (ret)
+		goto failed;
+
+	/* FIXME_NFQUCMPD: Here, handle the twig-special case for unallocated children.
+	   First, the pos_stop() and pos_valid() routines should be modified
+	   so that pos_stop() sets a flush_position->stop flag to 1 without
+	   releasing the current position immediately--instead release it in
+	   pos_done().  This is a better implementation than the current one anyway.
+
+	   It is not clear that all fields of the flush_position should not be released,
+	   but at the very least the parent_lock, parent_coord, and parent_load should
+	   remain held because they are hold the last twig when pos_stop() is
+	   called.
+
+	   When we reach this point in the code, if the parent_coord is set to after the
+	   last item then we know that flush reached the end of a twig (and according to
+	   the new flush queueing design, we will return now).  If parent_coord is not
+	   past the last item, we should check if the current twig has any unallocated
+	   children to the right (we are not concerned with unallocated children to the
+	   left--in that case the twig itself should not have been allocated).  If the
+	   twig has unallocated children to the right, set the parent_coord to that
+	   position and then repeat the call to squalloc.
+
+	   Testing for unallocated children may be defined in two ways: if any internal
+	   item has a fake block number, it is unallocated; if any extent item is
+	   unallocated then all of its children are unallocated.  But there is a more
+	   aggressive approach: if there are any dirty children of the twig to the right
+	   of the current position, we may wish to relocate those nodes now.  Checking for
+	   potential relocation is more expensive as it requires knowing whether there are
+	   any dirty children that are not unallocated.  The extent_needs_allocation
+	   should be used after setting the correct preceder.
+
+	   When we reach the end of a twig at this point in the code, if the flush can
+	   continue (when the queue is ready) it will need some information on the future
+	   starting point.  That should be stored away in the flush_handle using a seal, I
+	   believe.  Holding a jref() on the future starting point may break other code
+	   that deletes that node.
+	 */
+
+	/* FIXME_NFQUCMPD: Also, we don't want to do any flushing when flush is called
+	   above the twig level.  If the VM calls flush above the twig level, do nothing
+	   and return (but figure out why this happens).  The txnmgr should be modified to
+	   only flush its leaf-level dirty list.  This will do all the necessary squeeze
+	   and allocate steps but leave unallocated branches and possibly unallocated
+	   twigs (when the twig's leftmost child is not dirty).  After flushing the leaf
+	   level, the remaining unallocated nodes should be given write-optimized
+	   locations.  (Possibly, the remaining unallocated twigs should be allocated just
+	   before their leftmost child.)
+	 */
+
+	/* Any failure reaches this point. */
+      failed:
+
+	switch (ret) {
+	case -E_REPEAT:
+	case -EINVAL:
+	case -E_DEADLOCK:
+	case -E_NO_NEIGHBOR:
+	case -ENOENT:
+		/* FIXME(C): Except for E_DEADLOCK, these should probably be handled properly
+		   in each case.  They already are handled in many cases. */
+		/* Something bad happened, but difficult to avoid...  Try again! */
+		ret = 0;
+	}
+
+	if (leftmost_in_slum)
+		jput(leftmost_in_slum);
+
+	pos_done(flush_pos);
+	scan_done(left_scan);
+	scan_done(right_scan);
+	kfree(right_scan);
+
+	ON_DEBUG(atomic_dec(&flush_cnt));
+
+	leave_flush(sb);
+
+	if (!reiser4_is_set(sb, REISER4_MTFLUSH))
+		up(&sbinfo->flush_sema);
+
+	return ret;
+}
+
+/* The reiser4 flush subsystem can be turned into "rapid flush mode" means that
+ * flusher should submit all prepped nodes immediately without keeping them in
+ * flush queues for long time.  The reason for rapid flush mode is to free
+ * memory as fast as possible. */
+
+#if REISER4_USE_RAPID_FLUSH
+
+/**
+ * submit all prepped nodes if rapid flush mode is set,
+ * turn rapid flush mode off.
+ */
+
+static int rapid_flush(flush_pos_t * pos)
+{
+	if (!wbq_available())
+		return 0;
+
+	return write_prepped_nodes(pos);
+}
+
+#else
+
+#define rapid_flush(pos) (0)
+
+#endif				/* REISER4_USE_RAPID_FLUSH */
+
+static jnode * find_flush_start_jnode(
+	jnode * start,
+	txn_atom * atom,
+	flush_queue_t * fq,
+	int *nr_queued,
+	int flags)
+{
+	jnode * node;
+
+	if (start != NULL) {
+		spin_lock_jnode(start);
+		if (JF_ISSET(start, JNODE_DIRTY) && !JF_ISSET(start, JNODE_OVRWR)) {
+			assert("zam-1056", start->atom == atom);
+			node = start;
+			goto enter;
+		}
+		spin_unlock_jnode(start);
+	}
+	/*
+	 * In this loop we process all already prepped (RELOC or OVRWR) and dirtied again
+	 * nodes. The atom spin lock is not released until all dirty nodes processed or
+	 * not prepped node found in the atom dirty lists.
+	 */
+	while ((node = find_first_dirty_jnode(atom, flags))) {
+		spin_lock_jnode(node);
+	enter:
+		assert("zam-881", JF_ISSET(node, JNODE_DIRTY));
+		assert("zam-898", !JF_ISSET(node, JNODE_OVRWR));
+
+		if (JF_ISSET(node, JNODE_WRITEBACK)) {
+			/* move node to the end of atom's writeback list */
+			list_del_init(&node->capture_link);
+			list_add_tail(&node->capture_link, ATOM_WB_LIST(atom));
+
+			/*
+			 * jnode is not necessarily on dirty list: if it was dirtied when
+			 * it was on flush queue - it does not get moved to dirty list
+			 */
+			ON_DEBUG(count_jnode(atom, node, NODE_LIST(node),
+					     WB_LIST, 1));
+
+		} else if (jnode_is_znode(node)
+			   && znode_above_root(JZNODE(node))) {
+			/*
+			 * A special case for znode-above-root.  The above-root (fake)
+			 * znode is captured and dirtied when the tree height changes or
+			 * when the root node is relocated.  This causes atoms to fuse so
+			 * that changes at the root are serialized.  However, this node is
+			 * never flushed.  This special case used to be in lock.c to
+			 * prevent the above-root node from ever being captured, but now
+			 * that it is captured we simply prevent it from flushing.  The
+			 * log-writer code relies on this to properly log superblock
+			 * modifications of the tree height.
+			 */
+			jnode_make_wander_nolock(node);
+		} else if (JF_ISSET(node, JNODE_RELOC)) {
+			queue_jnode(fq, node);
+			++(*nr_queued);
+		} else
+			break;
+
+		spin_unlock_jnode(node);
+	}
+	return node;
+}
+
+
+/* Flush some nodes of current atom, usually slum, return -E_REPEAT if there are more nodes
+ * to flush, return 0 if atom's dirty lists empty and keep current atom locked, return
+ * other errors as they are. */
+int
+flush_current_atom(int flags, long nr_to_write, long *nr_submitted,
+		   txn_atom ** atom, jnode *start)
+{
+	reiser4_super_info_data *sinfo = get_current_super_private();
+	flush_queue_t *fq = NULL;
+	jnode *node;
+	int nr_queued;
+	int ret;
+
+	assert("zam-889", atom != NULL && *atom != NULL);
+	assert_spin_locked(&((*atom)->alock));
+	assert("zam-892", get_current_context()->trans->atom == *atom);
+
+	nr_to_write = LONG_MAX;
+	while (1) {
+		ret = fq_by_atom(*atom, &fq);
+		if (ret != -E_REPEAT)
+			break;
+		*atom = get_current_atom_locked();
+	}
+	if (ret)
+		return ret;
+
+	assert_spin_locked(&((*atom)->alock));
+
+	/* parallel flushers limit */
+	if (sinfo->tmgr.atom_max_flushers != 0) {
+		while ((*atom)->nr_flushers >= sinfo->tmgr.atom_max_flushers) {
+			/* An atom_send_event() call is inside fq_put_nolock() which is
+			   called when flush is finished and nr_flushers is
+			   decremented. */
+			atom_wait_event(*atom);
+			*atom = get_current_atom_locked();
+		}
+	}
+
+	/* count ourself as a flusher */
+	(*atom)->nr_flushers++;
+
+	writeout_mode_enable();
+
+	nr_queued = 0;
+	node = find_flush_start_jnode(start, *atom, fq, &nr_queued, flags);
+
+	if (node == NULL) {
+		if (nr_queued == 0) {
+			(*atom)->nr_flushers--;
+			fq_put_nolock(fq);
+			atom_send_event(*atom);
+			/* current atom remains locked */
+			writeout_mode_disable();
+			return 0;
+		}
+		spin_unlock_atom(*atom);
+	} else {
+		jref(node);
+		BUG_ON((*atom)->super != node->tree->super);
+		spin_unlock_atom(*atom);
+		spin_unlock_jnode(node);
+		BUG_ON(nr_to_write == 0);
+		ret = jnode_flush(node, nr_to_write, nr_submitted, fq, flags);
+		jput(node);
+	}
+
+	ret =
+	    write_fq(fq, nr_submitted,
+		     WRITEOUT_SINGLE_STREAM | WRITEOUT_FOR_PAGE_RECLAIM);
+
+	*atom = get_current_atom_locked();
+	(*atom)->nr_flushers--;
+	fq_put_nolock(fq);
+	atom_send_event(*atom);
+	spin_unlock_atom(*atom);
+
+	writeout_mode_disable();
+
+	if (ret == 0)
+		ret = -E_REPEAT;
+
+	return ret;
+}
+
+/* REVERSE PARENT-FIRST RELOCATION POLICIES */
+
+/* This implements the is-it-close-enough-to-its-preceder? test for relocation in the
+   reverse parent-first relocate context.  Here all we know is the preceder and the block
+   number.  Since we are going in reverse, the preceder may still be relocated as well, so
+   we can't ask the block allocator "is there a closer block available to relocate?" here.
+   In the _forward_ parent-first relocate context (not here) we actually call the block
+   allocator to try and find a closer location. */
+static int
+reverse_relocate_if_close_enough(const reiser4_block_nr * pblk,
+				 const reiser4_block_nr * nblk)
+{
+	reiser4_block_nr dist;
+
+	assert("jmacd-7710", *pblk != 0 && *nblk != 0);
+	assert("jmacd-7711", !blocknr_is_fake(pblk));
+	assert("jmacd-7712", !blocknr_is_fake(nblk));
+
+	/* Distance is the absolute value. */
+	dist = (*pblk > *nblk) ? (*pblk - *nblk) : (*nblk - *pblk);
+
+	/* If the block is less than FLUSH_RELOCATE_DISTANCE blocks away from its preceder
+	   block, do not relocate. */
+	if (dist <= get_current_super_private()->flush.relocate_distance) {
+		return 0;
+	}
+
+	return 1;
+}
+
+/* This function is a predicate that tests for relocation.  Always called in the
+   reverse-parent-first context, when we are asking whether the current node should be
+   relocated in order to expand the flush by dirtying the parent level (and thus
+   proceeding to flush that level).  When traversing in the forward parent-first direction
+   (not here), relocation decisions are handled in two places: allocate_znode() and
+   extent_needs_allocation(). */
+static int
+reverse_relocate_test(jnode * node, const coord_t * parent_coord,
+		      flush_pos_t * pos)
+{
+	reiser4_block_nr pblk = 0;
+	reiser4_block_nr nblk = 0;
+
+	assert("jmacd-8989", !jnode_is_root(node));
+
+	/*
+	 * This function is called only from the
+	 * reverse_relocate_check_dirty_parent() and only if the parent
+	 * node is clean. This implies that the parent has the real (i.e., not
+	 * fake) block number, and, so does the child, because otherwise the
+	 * parent would be dirty.
+	 */
+
+	/* New nodes are treated as if they are being relocated. */
+	if (jnode_created(node)
+	    || (pos->leaf_relocate && jnode_get_level(node) == LEAF_LEVEL)) {
+		return 1;
+	}
+
+	/* Find the preceder.  FIXME(B): When the child is an unformatted, previously
+	   existing node, the coord may be leftmost even though the child is not the
+	   parent-first preceder of the parent.  If the first dirty node appears somewhere
+	   in the middle of the first extent unit, this preceder calculation is wrong.
+	   Needs more logic in here. */
+	if (coord_is_leftmost_unit(parent_coord)) {
+		pblk = *znode_get_block(parent_coord->node);
+	} else {
+		pblk = pos->preceder.blk;
+	}
+	check_preceder(pblk);
+
+	/* If (pblk == 0) then the preceder isn't allocated or isn't known: relocate. */
+	if (pblk == 0) {
+		return 1;
+	}
+
+	nblk = *jnode_get_block(node);
+
+	if (blocknr_is_fake(&nblk))
+		/* child is unallocated, mark parent dirty */
+		return 1;
+
+	return reverse_relocate_if_close_enough(&pblk, &nblk);
+}
+
+/* This function calls reverse_relocate_test to make a reverse-parent-first
+   relocation decision and then, if yes, it marks the parent dirty. */
+static int
+reverse_relocate_check_dirty_parent(jnode * node, const coord_t * parent_coord,
+				    flush_pos_t * pos)
+{
+	int ret;
+
+	if (!JF_ISSET(ZJNODE(parent_coord->node), JNODE_DIRTY)) {
+
+		ret = reverse_relocate_test(node, parent_coord, pos);
+		if (ret < 0) {
+			return ret;
+		}
+
+		/* FIXME-ZAM
+		   if parent is already relocated - we do not want to grab space, right? */
+		if (ret == 1) {
+			int grabbed;
+
+			grabbed = get_current_context()->grabbed_blocks;
+			if (reiser4_grab_space_force((__u64) 1, BA_RESERVED) !=
+			    0)
+				reiser4_panic("umka-1250",
+					      "No space left during flush.");
+
+			assert("jmacd-18923",
+			       znode_is_write_locked(parent_coord->node));
+			znode_make_dirty(parent_coord->node);
+			grabbed2free_mark(grabbed);
+		}
+	}
+
+	return 0;
+}
+
+/* INITIAL ALLOCATE ANCESTORS STEP (REVERSE PARENT-FIRST ALLOCATION BEFORE FORWARD
+   PARENT-FIRST LOOP BEGINS) */
+
+/* Get the leftmost child for given coord. */
+static int get_leftmost_child_of_unit(const coord_t * coord, jnode ** child)
+{
+	int ret;
+
+	ret = item_utmost_child(coord, LEFT_SIDE, child);
+
+	if (ret)
+		return ret;
+
+	if (IS_ERR(*child))
+		return PTR_ERR(*child);
+
+	return 0;
+}
+
+/* This step occurs after the left- and right-scans are completed, before starting the
+   forward parent-first traversal.  Here we attempt to allocate ancestors of the starting
+   flush point, which means continuing in the reverse parent-first direction to the
+   parent, grandparent, and so on (as long as the child is a leftmost child).  This
+   routine calls a recursive process, alloc_one_ancestor, which does the real work,
+   except there is special-case handling here for the first ancestor, which may be a twig.
+   At each level (here and alloc_one_ancestor), we check for relocation and then, if
+   the child is a leftmost child, repeat at the next level.  On the way back down (the
+   recursion), we allocate the ancestors in parent-first order. */
+static int alloc_pos_and_ancestors(flush_pos_t * pos)
+{
+	int ret = 0;
+	lock_handle plock;
+	load_count pload;
+	coord_t pcoord;
+
+	if (znode_check_flushprepped(pos->lock.node))
+		return 0;
+
+	coord_init_invalid(&pcoord, NULL);
+	init_lh(&plock);
+	init_load_count(&pload);
+
+	if (pos->state == POS_ON_EPOINT) {
+		/* a special case for pos on twig level, where we already have
+		   a lock on parent node. */
+		/* The parent may not be dirty, in which case we should decide
+		   whether to relocate the child now. If decision is made to
+		   relocate the child, the parent is marked dirty. */
+		ret =
+		    reverse_relocate_check_dirty_parent(pos->child, &pos->coord,
+							pos);
+		if (ret)
+			goto exit;
+
+		/* FIXME_NFQUCMPD: We only need to allocate the twig (if child
+		   is leftmost) and the leaf/child, so recursion is not needed.
+		   Levels above the twig will be allocated for
+		   write-optimization before the transaction commits.  */
+
+		/* Do the recursive step, allocating zero or more of our
+		 * ancestors. */
+		ret = alloc_one_ancestor(&pos->coord, pos);
+
+	} else {
+		if (!znode_is_root(pos->lock.node)) {
+			/* all formatted nodes except tree root */
+			ret =
+			    reiser4_get_parent(&plock, pos->lock.node,
+					       ZNODE_WRITE_LOCK);
+			if (ret)
+				goto exit;
+
+			ret = incr_load_count_znode(&pload, plock.node);
+			if (ret)
+				goto exit;
+
+			ret =
+			    find_child_ptr(plock.node, pos->lock.node, &pcoord);
+			if (ret)
+				goto exit;
+
+			ret =
+			    reverse_relocate_check_dirty_parent(ZJNODE
+								(pos->lock.
+								 node), &pcoord,
+								pos);
+			if (ret)
+				goto exit;
+
+			ret = alloc_one_ancestor(&pcoord, pos);
+			if (ret)
+				goto exit;
+		}
+
+		ret = allocate_znode(pos->lock.node, &pcoord, pos);
+	}
+      exit:
+	done_load_count(&pload);
+	done_lh(&plock);
+	return ret;
+}
+
+/* This is the recursive step described in alloc_pos_and_ancestors, above.  Ignoring the
+   call to set_preceder, which is the next function described, this checks if the
+   child is a leftmost child and returns if it is not.  If the child is a leftmost child
+   it checks for relocation, possibly dirtying the parent.  Then it performs the recursive
+   step. */
+static int alloc_one_ancestor(const coord_t * coord, flush_pos_t * pos)
+{
+	int ret = 0;
+	lock_handle alock;
+	load_count aload;
+	coord_t acoord;
+
+	/* As we ascend at the left-edge of the region to flush, take this opportunity at
+	   the twig level to find our parent-first preceder unless we have already set
+	   it. */
+	if (pos->preceder.blk == 0) {
+		ret = set_preceder(coord, pos);
+		if (ret != 0)
+			return ret;
+	}
+
+	/* If the ancestor is clean or already allocated, or if the child is not a
+	   leftmost child, stop going up, even leaving coord->node not flushprepped. */
+	if (znode_check_flushprepped(coord->node)
+	    || !coord_is_leftmost_unit(coord))
+		return 0;
+
+	init_lh(&alock);
+	init_load_count(&aload);
+	coord_init_invalid(&acoord, NULL);
+
+	/* Only ascend to the next level if it is a leftmost child, but write-lock the
+	   parent in case we will relocate the child. */
+	if (!znode_is_root(coord->node)) {
+
+		ret =
+		    jnode_lock_parent_coord(ZJNODE(coord->node), &acoord,
+					    &alock, &aload, ZNODE_WRITE_LOCK,
+					    0);
+		if (ret != 0) {
+			/* FIXME(C): check EINVAL, E_DEADLOCK */
+			goto exit;
+		}
+
+		ret =
+		    reverse_relocate_check_dirty_parent(ZJNODE(coord->node),
+							&acoord, pos);
+		if (ret != 0) {
+			goto exit;
+		}
+
+		/* Recursive call. */
+		if (!znode_check_flushprepped(acoord.node)) {
+			ret = alloc_one_ancestor(&acoord, pos);
+			if (ret)
+				goto exit;
+		}
+	}
+
+	/* Note: we call allocate with the parent write-locked (except at the root) in
+	   case we relocate the child, in which case it will modify the parent during this
+	   call. */
+	ret = allocate_znode(coord->node, &acoord, pos);
+
+      exit:
+	done_load_count(&aload);
+	done_lh(&alock);
+	return ret;
+}
+
+/* During the reverse parent-first alloc_pos_and_ancestors process described above there is
+   a call to this function at the twig level.  During alloc_pos_and_ancestors we may ask:
+   should this node be relocated (in reverse parent-first context)?  We repeat this
+   process as long as the child is the leftmost child, eventually reaching an ancestor of
+   the flush point that is not a leftmost child.  The preceder of that ancestors, which is
+   not a leftmost child, is actually on the leaf level.  The preceder of that block is the
+   left-neighbor of the flush point.  The preceder of that block is the rightmost child of
+   the twig on the left.  So, when alloc_pos_and_ancestors passes upward through the twig
+   level, it stops momentarily to remember the block of the rightmost child of the twig on
+   the left and sets it to the flush_position's preceder_hint.
+
+   There is one other place where we may set the flush_position's preceder hint, which is
+   during scan-left.
+*/
+static int set_preceder(const coord_t * coord_in, flush_pos_t * pos)
+{
+	int ret;
+	coord_t coord;
+	lock_handle left_lock;
+	load_count left_load;
+
+	coord_dup(&coord, coord_in);
+
+	init_lh(&left_lock);
+	init_load_count(&left_load);
+
+	/* FIXME(B): Same FIXME as in "Find the preceder" in reverse_relocate_test.
+	   coord_is_leftmost_unit is not the right test if the unformatted child is in the
+	   middle of the first extent unit. */
+	if (!coord_is_leftmost_unit(&coord)) {
+		coord_prev_unit(&coord);
+	} else {
+		ret =
+		    reiser4_get_left_neighbor(&left_lock, coord.node,
+					      ZNODE_READ_LOCK, GN_SAME_ATOM);
+		if (ret) {
+			/* If we fail for any reason it doesn't matter because the
+			   preceder is only a hint.  We are low-priority at this point, so
+			   this must be the case. */
+			if (ret == -E_REPEAT || ret == -E_NO_NEIGHBOR ||
+			    ret == -ENOENT || ret == -EINVAL
+			    || ret == -E_DEADLOCK) {
+				ret = 0;
+			}
+			goto exit;
+		}
+
+		ret = incr_load_count_znode(&left_load, left_lock.node);
+		if (ret)
+			goto exit;
+
+		coord_init_last_unit(&coord, left_lock.node);
+	}
+
+	ret =
+	    item_utmost_child_real_block(&coord, RIGHT_SIDE,
+					 &pos->preceder.blk);
+      exit:
+	check_preceder(pos->preceder.blk);
+	done_load_count(&left_load);
+	done_lh(&left_lock);
+	return ret;
+}
+
+/* MAIN SQUEEZE AND ALLOCATE LOOP (THREE BIG FUNCTIONS) */
+
+/* This procedure implements the outer loop of the flush algorithm.  To put this in
+   context, here is the general list of steps taken by the flush routine as a whole:
+
+   1. Scan-left
+   2. Scan-right (maybe)
+   3. Allocate initial flush position and its ancestors
+   4. <handle extents>
+   5. <squeeze and next position and its ancestors to-the-right,
+       then update position to-the-right>
+   6. <repeat from #4 until flush is stopped>
+
+   This procedure implements the loop in steps 4 through 6 in the above listing.
+
+   Step 4: if the current flush position is an extent item (position on the twig level),
+   it allocates the extent (allocate_extent_item_in_place) then shifts to the next
+   coordinate.  If the next coordinate's leftmost child needs flushprep, we will continue.
+   If the next coordinate is an internal item, we descend back to the leaf level,
+   otherwise we repeat a step #4 (labeled ALLOC_EXTENTS below).  If the "next coordinate"
+   brings us past the end of the twig level, then we call
+   reverse_relocate_end_of_twig to possibly dirty the next (right) twig, prior to
+   step #5 which moves to the right.
+
+   Step 5: calls squalloc_changed_ancestors, which initiates a recursive call up the
+   tree to allocate any ancestors of the next-right flush position that are not also
+   ancestors of the current position.  Those ancestors (in top-down order) are the next in
+   parent-first order.  We squeeze adjacent nodes on the way up until the right node and
+   current node share the same parent, then allocate on the way back down.  Finally, this
+   step sets the flush position to the next-right node.  Then repeat steps 4 and 5.
+*/
+
+/* SQUEEZE CODE */
+
+/* squalloc_right_twig helper function, cut a range of extent items from
+   cut node to->node from the beginning up to coord @to. */
+static int squalloc_right_twig_cut(coord_t * to, reiser4_key * to_key,
+				   znode * left)
+{
+	coord_t from;
+	reiser4_key from_key;
+
+	coord_init_first_unit(&from, to->node);
+	item_key_by_coord(&from, &from_key);
+
+	return cut_node_content(&from, to, &from_key, to_key, NULL);
+}
+
+/* Copy as much of the leading extents from @right to @left, allocating
+   unallocated extents as they are copied.  Returns SQUEEZE_TARGET_FULL or
+   SQUEEZE_SOURCE_EMPTY when no more can be shifted.  If the next item is an
+   internal item it calls shift_one_internal_unit and may then return
+   SUBTREE_MOVED. */
+static int squeeze_right_twig(znode * left, znode * right, flush_pos_t * pos)
+{
+	int ret = SUBTREE_MOVED;
+	coord_t coord;		/* used to iterate over items */
+	reiser4_key stop_key;
+
+	assert("jmacd-2008", !node_is_empty(right));
+	coord_init_first_unit(&coord, right);
+
+	/* FIXME: can be optimized to cut once */
+	while (!node_is_empty(coord.node) && item_is_extent(&coord)) {
+		ON_DEBUG(void *vp);
+
+		assert("vs-1468", coord_is_leftmost_unit(&coord));
+		ON_DEBUG(vp = shift_check_prepare(left, coord.node));
+
+		/* stop_key is used to find what was copied and what to cut */
+		stop_key = *min_key();
+		ret = squalloc_extent(left, &coord, pos, &stop_key);
+		if (ret != SQUEEZE_CONTINUE) {
+			ON_DEBUG(kfree(vp));
+			break;
+		}
+		assert("vs-1465", !keyeq(&stop_key, min_key()));
+
+		/* Helper function to do the cutting. */
+		set_key_offset(&stop_key, get_key_offset(&stop_key) - 1);
+		check_me("vs-1466",
+			 squalloc_right_twig_cut(&coord, &stop_key, left) == 0);
+
+		ON_DEBUG(shift_check(vp, left, coord.node));
+	}
+
+	if (node_is_empty(coord.node))
+		ret = SQUEEZE_SOURCE_EMPTY;
+
+	if (ret == SQUEEZE_TARGET_FULL) {
+		goto out;
+	}
+
+	if (node_is_empty(right)) {
+		/* The whole right node was copied into @left. */
+		assert("vs-464", ret == SQUEEZE_SOURCE_EMPTY);
+		goto out;
+	}
+
+	coord_init_first_unit(&coord, right);
+
+	if (!item_is_internal(&coord)) {
+		/* we do not want to squeeze anything else to left neighbor because "slum"
+		   is over */
+		ret = SQUEEZE_TARGET_FULL;
+		goto out;
+	}
+	assert("jmacd-433", item_is_internal(&coord));
+
+	/* Shift an internal unit.  The child must be allocated before shifting any more
+	   extents, so we stop here. */
+	ret = shift_one_internal_unit(left, right);
+
+      out:
+	assert("jmacd-8612", ret < 0 || ret == SQUEEZE_TARGET_FULL
+	       || ret == SUBTREE_MOVED || ret == SQUEEZE_SOURCE_EMPTY);
+
+	if (ret == SQUEEZE_TARGET_FULL) {
+		/* We submit prepped nodes here and expect that this @left twig
+		 * will not be modified again during this jnode_flush() call. */
+		int ret1;
+
+		/* NOTE: seems like io is done under long term locks. */
+		ret1 = write_prepped_nodes(pos);
+		if (ret1 < 0)
+			return ret1;
+	}
+
+	return ret;
+}
+
+#if REISER4_DEBUG
+static void item_convert_invariant(flush_pos_t * pos)
+{
+	assert("edward-1225", coord_is_existing_item(&pos->coord));
+	if (chaining_data_present(pos)) {
+		item_plugin *iplug = item_convert_plug(pos);
+
+		assert("edward-1000",
+		       iplug == item_plugin_by_coord(&pos->coord));
+		assert("edward-1001", iplug->f.convert != NULL);
+	} else
+		assert("edward-1226", pos->child == NULL);
+}
+#else
+
+#define item_convert_invariant(pos) noop
+
+#endif
+
+/* Scan node items starting from the first one and apply for each
+   item its flush ->convert() method (if any). This method may
+   resize/kill the item so the tree will be changed.
+*/
+static int convert_node(flush_pos_t * pos, znode * node)
+{
+	int ret = 0;
+	item_plugin *iplug;
+
+	assert("edward-304", pos != NULL);
+	assert("edward-305", pos->child == NULL);
+	assert("edward-475", znode_convertible(node));
+	assert("edward-669", znode_is_wlocked(node));
+	assert("edward-1210", !node_is_empty(node));
+
+	if (znode_get_level(node) != LEAF_LEVEL)
+		/* unsupported */
+		goto exit;
+
+	coord_init_first_unit(&pos->coord, node);
+
+	while (1) {
+		ret = 0;
+		coord_set_to_left(&pos->coord);
+		item_convert_invariant(pos);
+
+		iplug = item_plugin_by_coord(&pos->coord);
+		assert("edward-844", iplug != NULL);
+
+		if (iplug->f.convert) {
+			ret = iplug->f.convert(pos);
+			if (ret)
+				goto exit;
+		}
+		assert("edward-307", pos->child == NULL);
+
+		if (coord_next_item(&pos->coord)) {
+			/* node is over */
+
+			if (!chaining_data_present(pos))
+				/* finished this node */
+				break;
+			if (should_chain_next_node(pos)) {
+				/* go to next node */
+				move_chaining_data(pos, 0 /* to next node */ );
+				break;
+			}
+			/* repeat this node */
+			move_chaining_data(pos, 1 /* this node */ );
+			continue;
+		}
+		/* Node is not over.
+		   Check if there is attached convert data.
+		   If so roll one item position back and repeat
+		   on this node
+		 */
+		if (chaining_data_present(pos)) {
+
+			if (iplug != item_plugin_by_coord(&pos->coord))
+				set_item_convert_count(pos, 0);
+
+			ret = coord_prev_item(&pos->coord);
+			assert("edward-1003", !ret);
+
+			move_chaining_data(pos, 1 /* this node */ );
+		}
+	}
+	JF_CLR(ZJNODE(node), JNODE_CONVERTIBLE);
+	znode_make_dirty(node);
+      exit:
+	assert("edward-1004", !ret);
+	return ret;
+}
+
+/* Squeeze and allocate the right neighbor.  This is called after @left and
+   its current children have been squeezed and allocated already.  This
+   procedure's job is to squeeze and items from @right to @left.
+
+   If at the leaf level, use the shift_everything_left memcpy-optimized
+   version of shifting (squeeze_right_leaf).
+
+   If at the twig level, extents are allocated as they are shifted from @right
+   to @left (squalloc_right_twig).
+
+   At any other level, shift one internal item and return to the caller
+   (squalloc_parent_first) so that the shifted-subtree can be processed in
+   parent-first order.
+
+   When unit of internal item is moved, squeezing stops and SUBTREE_MOVED is
+   returned.  When all content of @right is squeezed, SQUEEZE_SOURCE_EMPTY is
+   returned.  If nothing can be moved into @left anymore, SQUEEZE_TARGET_FULL
+   is returned.
+*/
+
+static int squeeze_right_neighbor(flush_pos_t * pos, znode * left,
+				  znode * right)
+{
+	int ret;
+
+	/* FIXME it is possible to see empty hasn't-heard-banshee node in a
+	 * tree owing to error (for example, ENOSPC) in write */
+	/* assert("jmacd-9321", !node_is_empty(left)); */
+	assert("jmacd-9322", !node_is_empty(right));
+	assert("jmacd-9323", znode_get_level(left) == znode_get_level(right));
+
+	switch (znode_get_level(left)) {
+	case TWIG_LEVEL:
+		/* Shift with extent allocating until either an internal item
+		   is encountered or everything is shifted or no free space
+		   left in @left */
+		ret = squeeze_right_twig(left, right, pos);
+		break;
+
+	default:
+		/* All other levels can use shift_everything until we implement per-item
+		   flush plugins. */
+		ret = squeeze_right_non_twig(left, right);
+		break;
+	}
+
+	assert("jmacd-2011", (ret < 0 ||
+			      ret == SQUEEZE_SOURCE_EMPTY
+			      || ret == SQUEEZE_TARGET_FULL
+			      || ret == SUBTREE_MOVED));
+	return ret;
+}
+
+static int squeeze_right_twig_and_advance_coord(flush_pos_t * pos,
+						znode * right)
+{
+	int ret;
+
+	ret = squeeze_right_twig(pos->lock.node, right, pos);
+	if (ret < 0)
+		return ret;
+	if (ret > 0) {
+		coord_init_after_last_item(&pos->coord, pos->lock.node);
+		return ret;
+	}
+
+	coord_init_last_unit(&pos->coord, pos->lock.node);
+	return 0;
+}
+
+/* forward declaration */
+static int squalloc_upper_levels(flush_pos_t *, znode *, znode *);
+
+/* do a fast check for "same parents" condition before calling
+ * squalloc_upper_levels() */
+static inline int check_parents_and_squalloc_upper_levels(flush_pos_t * pos,
+							  znode * left,
+							  znode * right)
+{
+	if (znode_same_parents(left, right))
+		return 0;
+
+	return squalloc_upper_levels(pos, left, right);
+}
+
+/* Check whether the parent of given @right node needs to be processes
+   ((re)allocated) prior to processing of the child.  If @left and @right do not
+   share at least the parent of the @right is after the @left but before the
+   @right in parent-first order, we have to (re)allocate it before the @right
+   gets (re)allocated. */
+static int squalloc_upper_levels(flush_pos_t * pos, znode * left, znode * right)
+{
+	int ret;
+
+	lock_handle left_parent_lock;
+	lock_handle right_parent_lock;
+
+	load_count left_parent_load;
+	load_count right_parent_load;
+
+	init_lh(&left_parent_lock);
+	init_lh(&right_parent_lock);
+
+	init_load_count(&left_parent_load);
+	init_load_count(&right_parent_load);
+
+	ret = reiser4_get_parent(&left_parent_lock, left, ZNODE_WRITE_LOCK);
+	if (ret)
+		goto out;
+
+	ret = reiser4_get_parent(&right_parent_lock, right, ZNODE_WRITE_LOCK);
+	if (ret)
+		goto out;
+
+	/* Check for same parents */
+	if (left_parent_lock.node == right_parent_lock.node)
+		goto out;
+
+	if (znode_check_flushprepped(right_parent_lock.node)) {
+		/* Keep parent-first order.  In the order, the right parent node stands
+		   before the @right node.  If it is already allocated, we set the
+		   preceder (next block search start point) to its block number, @right
+		   node should be allocated after it.
+
+		   However, preceder is set only if the right parent is on twig level.
+		   The explanation is the following: new branch nodes are allocated over
+		   already allocated children while the tree grows, it is difficult to
+		   keep tree ordered, we assume that only leaves and twings are correctly
+		   allocated.  So, only twigs are used as a preceder for allocating of the
+		   rest of the slum. */
+		if (znode_get_level(right_parent_lock.node) == TWIG_LEVEL) {
+			pos->preceder.blk =
+			    *znode_get_block(right_parent_lock.node);
+			check_preceder(pos->preceder.blk);
+		}
+		goto out;
+	}
+
+	ret = incr_load_count_znode(&left_parent_load, left_parent_lock.node);
+	if (ret)
+		goto out;
+
+	ret = incr_load_count_znode(&right_parent_load, right_parent_lock.node);
+	if (ret)
+		goto out;
+
+	ret =
+	    squeeze_right_neighbor(pos, left_parent_lock.node,
+				   right_parent_lock.node);
+	/* We stop if error. We stop if some items/units were shifted (ret == 0)
+	 * and thus @right changed its parent. It means we have not process
+	 * right_parent node prior to processing of @right. Positive return
+	 * values say that shifting items was not happen because of "empty
+	 * source" or "target full" conditions. */
+	if (ret <= 0)
+		goto out;
+
+	/* parent(@left) and parent(@right) may have different parents also. We
+	 * do a recursive call for checking that. */
+	ret =
+	    check_parents_and_squalloc_upper_levels(pos, left_parent_lock.node,
+						    right_parent_lock.node);
+	if (ret)
+		goto out;
+
+	/* allocate znode when going down */
+	ret = lock_parent_and_allocate_znode(right_parent_lock.node, pos);
+
+      out:
+	done_load_count(&left_parent_load);
+	done_load_count(&right_parent_load);
+
+	done_lh(&left_parent_lock);
+	done_lh(&right_parent_lock);
+
+	return ret;
+}
+
+/* Check the leftmost child "flushprepped" status, also returns true if child
+ * node was not found in cache.  */
+static int leftmost_child_of_unit_check_flushprepped(const coord_t * coord)
+{
+	int ret;
+	int prepped;
+
+	jnode *child;
+
+	ret = get_leftmost_child_of_unit(coord, &child);
+
+	if (ret)
+		return ret;
+
+	if (child) {
+		prepped = jnode_check_flushprepped(child);
+		jput(child);
+	} else {
+		/* We consider not existing child as a node which slum
+		   processing should not continue to.  Not cached node is clean,
+		   so it is flushprepped. */
+		prepped = 1;
+	}
+
+	return prepped;
+}
+
+/* (re)allocate znode with automated getting parent node */
+static int lock_parent_and_allocate_znode(znode * node, flush_pos_t * pos)
+{
+	int ret;
+	lock_handle parent_lock;
+	load_count parent_load;
+	coord_t pcoord;
+
+	assert("zam-851", znode_is_write_locked(node));
+
+	init_lh(&parent_lock);
+	init_load_count(&parent_load);
+
+	ret = reiser4_get_parent(&parent_lock, node, ZNODE_WRITE_LOCK);
+	if (ret)
+		goto out;
+
+	ret = incr_load_count_znode(&parent_load, parent_lock.node);
+	if (ret)
+		goto out;
+
+	ret = find_child_ptr(parent_lock.node, node, &pcoord);
+	if (ret)
+		goto out;
+
+	ret = allocate_znode(node, &pcoord, pos);
+
+      out:
+	done_load_count(&parent_load);
+	done_lh(&parent_lock);
+	return ret;
+}
+
+/* Process nodes on leaf level until unformatted node or rightmost node in the
+ * slum reached.  */
+static int handle_pos_on_formatted(flush_pos_t * pos)
+{
+	int ret;
+	lock_handle right_lock;
+	load_count right_load;
+
+	init_lh(&right_lock);
+	init_load_count(&right_load);
+
+	if (should_convert_node(pos, pos->lock.node)) {
+		ret = convert_node(pos, pos->lock.node);
+		if (ret)
+			return ret;
+	}
+
+	while (1) {
+		ret =
+		    neighbor_in_slum(pos->lock.node, &right_lock, RIGHT_SIDE,
+				     ZNODE_WRITE_LOCK,
+				     !should_convert_next_node(pos,
+							       right_lock.
+							       node));
+		if (ret)
+			break;
+
+		/* we don't prep(allocate) nodes for flushing twice.  This can be suboptimal, or it
+		 * can be optimal.  For now we choose to live with the risk that it will
+		 * be suboptimal because it would be quite complex to code it to be
+		 * smarter. */
+		if (znode_check_flushprepped(right_lock.node)
+		    && !znode_convertible(right_lock.node)) {
+			assert("edward-1005",
+			       !should_convert_next_node(pos, right_lock.node));
+			pos_stop(pos);
+			break;
+		}
+
+		ret = incr_load_count_znode(&right_load, right_lock.node);
+		if (ret)
+			break;
+
+		if (should_convert_node(pos, right_lock.node)) {
+			ret = convert_node(pos, right_lock.node);
+			if (ret)
+				break;
+			if (node_is_empty(right_lock.node)) {
+				/* node became empty after converting, repeat */
+				done_load_count(&right_load);
+				done_lh(&right_lock);
+				continue;
+			}
+		}
+
+		/* squeeze _before_ going upward. */
+		ret =
+		    squeeze_right_neighbor(pos, pos->lock.node,
+					   right_lock.node);
+		if (ret < 0)
+			break;
+
+		if (znode_check_flushprepped(right_lock.node)) {
+			if (should_convert_next_node(pos, right_lock.node)) {
+				/* in spite of flushprepped status of the node,
+				   its right slum neighbor should be converted */
+				assert("edward-953", convert_data(pos));
+				assert("edward-954", item_convert_data(pos));
+
+				if (node_is_empty(right_lock.node)) {
+					done_load_count(&right_load);
+					done_lh(&right_lock);
+				} else
+					move_flush_pos(pos, &right_lock,
+						       &right_load, NULL);
+				continue;
+			}
+			pos_stop(pos);
+			break;
+		}
+
+		if (node_is_empty(right_lock.node)) {
+			/* repeat if right node was squeezed completely */
+			done_load_count(&right_load);
+			done_lh(&right_lock);
+			continue;
+		}
+
+		/* parent(right_lock.node) has to be processed before
+		 * (right_lock.node) due to "parent-first" allocation order. */
+		ret =
+		    check_parents_and_squalloc_upper_levels(pos, pos->lock.node,
+							    right_lock.node);
+		if (ret)
+			break;
+		/* (re)allocate _after_ going upward */
+		ret = lock_parent_and_allocate_znode(right_lock.node, pos);
+		if (ret)
+			break;
+
+		if (should_terminate_squalloc(pos)) {
+			set_item_convert_count(pos, 0);
+			break;
+		}
+
+		/* advance the flush position to the right neighbor */
+		move_flush_pos(pos, &right_lock, &right_load, NULL);
+
+		ret = rapid_flush(pos);
+		if (ret)
+			break;
+	}
+
+	assert("edward-1006", !convert_data(pos) || !item_convert_data(pos));
+
+	done_load_count(&right_load);
+	done_lh(&right_lock);
+
+	/* This function indicates via pos whether to stop or go to twig or continue on current
+	 * level. */
+	return ret;
+
+}
+
+/* Process nodes on leaf level until unformatted node or rightmost node in the
+ * slum reached.  */
+static int handle_pos_on_leaf(flush_pos_t * pos)
+{
+	int ret;
+
+	assert("zam-845", pos->state == POS_ON_LEAF);
+
+	ret = handle_pos_on_formatted(pos);
+
+	if (ret == -E_NO_NEIGHBOR) {
+		/* cannot get right neighbor, go process extents. */
+		pos->state = POS_TO_TWIG;
+		return 0;
+	}
+
+	return ret;
+}
+
+/* Process slum on level > 1 */
+static int handle_pos_on_internal(flush_pos_t * pos)
+{
+	assert("zam-850", pos->state == POS_ON_INTERNAL);
+	return handle_pos_on_formatted(pos);
+}
+
+/* check whether squalloc should stop before processing given extent */
+static int squalloc_extent_should_stop(flush_pos_t * pos)
+{
+	assert("zam-869", item_is_extent(&pos->coord));
+
+	/* pos->child is a jnode handle_pos_on_extent() should start with in
+	 * stead of the first child of the first extent unit. */
+	if (pos->child) {
+		int prepped;
+
+		assert("vs-1383", jnode_is_unformatted(pos->child));
+		prepped = jnode_check_flushprepped(pos->child);
+		pos->pos_in_unit =
+		    jnode_get_index(pos->child) -
+		    extent_unit_index(&pos->coord);
+		assert("vs-1470",
+		       pos->pos_in_unit < extent_unit_width(&pos->coord));
+		assert("nikita-3434",
+		       ergo(extent_is_unallocated(&pos->coord),
+			    pos->pos_in_unit == 0));
+		jput(pos->child);
+		pos->child = NULL;
+
+		return prepped;
+	}
+
+	pos->pos_in_unit = 0;
+	if (extent_is_unallocated(&pos->coord))
+		return 0;
+
+	return leftmost_child_of_unit_check_flushprepped(&pos->coord);
+}
+
+/* Handle the case when regular reiser4 tree (znodes connected one to its
+ * neighbors by sibling pointers) is interrupted on leaf level by one or more
+ * unformatted nodes.  By having a lock on twig level and use extent code
+ * routines to process unformatted nodes we swim around an irregular part of
+ * reiser4 tree. */
+static int handle_pos_on_twig(flush_pos_t * pos)
+{
+	int ret;
+
+	assert("zam-844", pos->state == POS_ON_EPOINT);
+	assert("zam-843", item_is_extent(&pos->coord));
+
+	/* We decide should we continue slum processing with current extent
+	   unit: if leftmost child of current extent unit is flushprepped
+	   (i.e. clean or already processed by flush) we stop squalloc().  There
+	   is a fast check for unallocated extents which we assume contain all
+	   not flushprepped nodes. */
+	/* FIXME: Here we implement simple check, we are only looking on the
+	   leftmost child. */
+	ret = squalloc_extent_should_stop(pos);
+	if (ret != 0) {
+		pos_stop(pos);
+		return ret;
+	}
+
+	while (pos_valid(pos) && coord_is_existing_unit(&pos->coord)
+	       && item_is_extent(&pos->coord)) {
+		ret = alloc_extent(pos);
+		if (ret) {
+			break;
+		}
+		coord_next_unit(&pos->coord);
+	}
+
+	if (coord_is_after_rightmost(&pos->coord)) {
+		pos->state = POS_END_OF_TWIG;
+		return 0;
+	}
+	if (item_is_internal(&pos->coord)) {
+		pos->state = POS_TO_LEAF;
+		return 0;
+	}
+
+	assert("zam-860", item_is_extent(&pos->coord));
+
+	/* "slum" is over */
+	pos->state = POS_INVALID;
+	return 0;
+}
+
+/* When we about to return flush position from twig to leaf level we can process
+ * the right twig node or move position to the leaf.  This processes right twig
+ * if it is possible and jump to leaf level if not. */
+static int handle_pos_end_of_twig(flush_pos_t * pos)
+{
+	int ret;
+	lock_handle right_lock;
+	load_count right_load;
+	coord_t at_right;
+	jnode *child = NULL;
+
+	assert("zam-848", pos->state == POS_END_OF_TWIG);
+	assert("zam-849", coord_is_after_rightmost(&pos->coord));
+
+	init_lh(&right_lock);
+	init_load_count(&right_load);
+
+	/* We get a lock on the right twig node even it is not dirty because
+	 * slum continues or discontinues on leaf level not on next twig. This
+	 * lock on the right twig is needed for getting its leftmost child. */
+	ret =
+	    reiser4_get_right_neighbor(&right_lock, pos->lock.node,
+				       ZNODE_WRITE_LOCK, GN_SAME_ATOM);
+	if (ret)
+		goto out;
+
+	ret = incr_load_count_znode(&right_load, right_lock.node);
+	if (ret)
+		goto out;
+
+	/* right twig could be not dirty */
+	if (JF_ISSET(ZJNODE(right_lock.node), JNODE_DIRTY)) {
+		/* If right twig node is dirty we always attempt to squeeze it
+		 * content to the left... */
+	      became_dirty:
+		ret =
+		    squeeze_right_twig_and_advance_coord(pos, right_lock.node);
+		if (ret <= 0) {
+			/* pos->coord is on internal item, go to leaf level, or
+			 * we have an error which will be caught in squalloc() */
+			pos->state = POS_TO_LEAF;
+			goto out;
+		}
+
+		/* If right twig was squeezed completely we wave to re-lock
+		 * right twig. now it is done through the top-level squalloc
+		 * routine. */
+		if (node_is_empty(right_lock.node))
+			goto out;
+
+		/* ... and prep it if it is not yet prepped */
+		if (!znode_check_flushprepped(right_lock.node)) {
+			/* As usual, process parent before ... */
+			ret =
+			    check_parents_and_squalloc_upper_levels(pos,
+								    pos->lock.
+								    node,
+								    right_lock.
+								    node);
+			if (ret)
+				goto out;
+
+			/* ... processing the child */
+			ret =
+			    lock_parent_and_allocate_znode(right_lock.node,
+							   pos);
+			if (ret)
+				goto out;
+		}
+	} else {
+		coord_init_first_unit(&at_right, right_lock.node);
+
+		/* check first child of next twig, should we continue there ? */
+		ret = get_leftmost_child_of_unit(&at_right, &child);
+		if (ret || child == NULL || jnode_check_flushprepped(child)) {
+			pos_stop(pos);
+			goto out;
+		}
+
+		/* check clean twig for possible relocation */
+		if (!znode_check_flushprepped(right_lock.node)) {
+			ret =
+			    reverse_relocate_check_dirty_parent(child,
+								&at_right, pos);
+			if (ret)
+				goto out;
+			if (JF_ISSET(ZJNODE(right_lock.node), JNODE_DIRTY))
+				goto became_dirty;
+		}
+	}
+
+	assert("zam-875", znode_check_flushprepped(right_lock.node));
+
+	/* Update the preceder by a block number of just processed right twig
+	 * node. The code above could miss the preceder updating because
+	 * allocate_znode() could not be called for this node. */
+	pos->preceder.blk = *znode_get_block(right_lock.node);
+	check_preceder(pos->preceder.blk);
+
+	coord_init_first_unit(&at_right, right_lock.node);
+	assert("zam-868", coord_is_existing_unit(&at_right));
+
+	pos->state = item_is_extent(&at_right) ? POS_ON_EPOINT : POS_TO_LEAF;
+	move_flush_pos(pos, &right_lock, &right_load, &at_right);
+
+      out:
+	done_load_count(&right_load);
+	done_lh(&right_lock);
+
+	if (child)
+		jput(child);
+
+	return ret;
+}
+
+/* Move the pos->lock to leaf node pointed by pos->coord, check should we
+ * continue there. */
+static int handle_pos_to_leaf(flush_pos_t * pos)
+{
+	int ret;
+	lock_handle child_lock;
+	load_count child_load;
+	jnode *child;
+
+	assert("zam-846", pos->state == POS_TO_LEAF);
+	assert("zam-847", item_is_internal(&pos->coord));
+
+	init_lh(&child_lock);
+	init_load_count(&child_load);
+
+	ret = get_leftmost_child_of_unit(&pos->coord, &child);
+	if (ret)
+		return ret;
+	if (child == NULL) {
+		pos_stop(pos);
+		return 0;
+	}
+
+	if (jnode_check_flushprepped(child)) {
+		pos->state = POS_INVALID;
+		goto out;
+	}
+
+	ret =
+	    longterm_lock_znode(&child_lock, JZNODE(child), ZNODE_WRITE_LOCK,
+				ZNODE_LOCK_LOPRI);
+	if (ret)
+		goto out;
+
+	ret = incr_load_count_znode(&child_load, JZNODE(child));
+	if (ret)
+		goto out;
+
+	ret = allocate_znode(JZNODE(child), &pos->coord, pos);
+	if (ret)
+		goto out;
+
+	/* move flush position to leaf level */
+	pos->state = POS_ON_LEAF;
+	move_flush_pos(pos, &child_lock, &child_load, NULL);
+
+	if (node_is_empty(JZNODE(child))) {
+		ret = delete_empty_node(JZNODE(child));
+		pos->state = POS_INVALID;
+	}
+      out:
+	done_load_count(&child_load);
+	done_lh(&child_lock);
+	jput(child);
+
+	return ret;
+}
+
+/* move pos from leaf to twig, and move lock from leaf to twig. */
+/* Move pos->lock to upper (twig) level */
+static int handle_pos_to_twig(flush_pos_t * pos)
+{
+	int ret;
+
+	lock_handle parent_lock;
+	load_count parent_load;
+	coord_t pcoord;
+
+	assert("zam-852", pos->state == POS_TO_TWIG);
+
+	init_lh(&parent_lock);
+	init_load_count(&parent_load);
+
+	ret =
+	    reiser4_get_parent(&parent_lock, pos->lock.node, ZNODE_WRITE_LOCK);
+	if (ret)
+		goto out;
+
+	ret = incr_load_count_znode(&parent_load, parent_lock.node);
+	if (ret)
+		goto out;
+
+	ret = find_child_ptr(parent_lock.node, pos->lock.node, &pcoord);
+	if (ret)
+		goto out;
+
+	assert("zam-870", item_is_internal(&pcoord));
+	coord_next_item(&pcoord);
+
+	if (coord_is_after_rightmost(&pcoord))
+		pos->state = POS_END_OF_TWIG;
+	else if (item_is_extent(&pcoord))
+		pos->state = POS_ON_EPOINT;
+	else {
+		/* Here we understand that getting -E_NO_NEIGHBOR in
+		 * handle_pos_on_leaf() was because of just a reaching edge of
+		 * slum */
+		pos_stop(pos);
+		goto out;
+	}
+
+	move_flush_pos(pos, &parent_lock, &parent_load, &pcoord);
+
+      out:
+	done_load_count(&parent_load);
+	done_lh(&parent_lock);
+
+	return ret;
+}
+
+typedef int (*pos_state_handle_t) (flush_pos_t *);
+static pos_state_handle_t flush_pos_handlers[] = {
+	/* process formatted nodes on leaf level, keep lock on a leaf node */
+	[POS_ON_LEAF] = handle_pos_on_leaf,
+	/* process unformatted nodes, keep lock on twig node, pos->coord points to extent currently
+	 * being processed */
+	[POS_ON_EPOINT] = handle_pos_on_twig,
+	/* move a lock from leaf node to its parent for further processing of unformatted nodes */
+	[POS_TO_TWIG] = handle_pos_to_twig,
+	/* move a lock from twig to leaf level when a processing of unformatted nodes finishes,
+	 * pos->coord points to the leaf node we jump to */
+	[POS_TO_LEAF] = handle_pos_to_leaf,
+	/* after processing last extent in the twig node, attempting to shift items from the twigs
+	 * right neighbor and process them while shifting */
+	[POS_END_OF_TWIG] = handle_pos_end_of_twig,
+	/* process formatted nodes on internal level, keep lock on an internal node */
+	[POS_ON_INTERNAL] = handle_pos_on_internal
+};
+
+/* Advance flush position horizontally, prepare for flushing ((re)allocate, squeeze,
+ * encrypt) nodes and their ancestors in "parent-first" order */
+static int squalloc(flush_pos_t * pos)
+{
+	int ret = 0;
+
+	/* maybe needs to be made a case statement with handle_pos_on_leaf as first case, for
+	 * greater CPU efficiency? Measure and see.... -Hans */
+	while (pos_valid(pos)) {
+		ret = flush_pos_handlers[pos->state] (pos);
+		if (ret < 0)
+			break;
+
+		ret = rapid_flush(pos);
+		if (ret)
+			break;
+	}
+
+	/* any positive value or -E_NO_NEIGHBOR are legal return codes for handle_pos*
+	   routines, -E_NO_NEIGHBOR means that slum edge was reached */
+	if (ret > 0 || ret == -E_NO_NEIGHBOR)
+		ret = 0;
+
+	return ret;
+}
+
+static void update_ldkey(znode * node)
+{
+	reiser4_key ldkey;
+
+	assert_rw_write_locked(&(znode_get_tree(node)->dk_lock));
+	if (node_is_empty(node))
+		return;
+
+	znode_set_ld_key(node, leftmost_key_in_node(node, &ldkey));
+}
+
+/* this is to be called after calling of shift node's method to shift data from @right to
+   @left. It sets left delimiting keys of @left and @right to keys of first items of @left
+   and @right correspondingly and sets right delimiting key of @left to first key of @right */
+static void update_znode_dkeys(znode * left, znode * right)
+{
+	assert_rw_write_locked(&(znode_get_tree(right)->dk_lock));
+	assert("vs-1629", (znode_is_write_locked(left) &&
+			   znode_is_write_locked(right)));
+
+	/* we need to update left delimiting of left if it was empty before shift */
+	update_ldkey(left);
+	update_ldkey(right);
+	if (node_is_empty(right))
+		znode_set_rd_key(left, znode_get_rd_key(right));
+	else
+		znode_set_rd_key(left, znode_get_ld_key(right));
+}
+
+/* try to shift everything from @right to @left. If everything was shifted -
+   @right is removed from the tree.  Result is the number of bytes shifted. */
+static int
+shift_everything_left(znode * right, znode * left, carry_level * todo)
+{
+	coord_t from;
+	node_plugin *nplug;
+	carry_plugin_info info;
+
+	coord_init_after_last_item(&from, right);
+
+	nplug = node_plugin_by_node(right);
+	info.doing = NULL;
+	info.todo = todo;
+	return nplug->shift(&from, left, SHIFT_LEFT,
+			    1 /* delete @right if it becomes empty */ ,
+			    1
+			    /* move coord @from to node @left if everything will be shifted */
+			    ,
+			    &info);
+}
+
+/* Shift as much as possible from @right to @left using the memcpy-optimized
+   shift_everything_left.  @left and @right are formatted neighboring nodes on
+   leaf level. */
+static int squeeze_right_non_twig(znode * left, znode * right)
+{
+	int ret;
+	carry_pool *pool;
+	carry_level *todo;
+
+	assert("nikita-2246", znode_get_level(left) == znode_get_level(right));
+
+	if (!JF_ISSET(ZJNODE(left), JNODE_DIRTY) ||
+	    !JF_ISSET(ZJNODE(right), JNODE_DIRTY))
+		return SQUEEZE_TARGET_FULL;
+
+	pool = init_carry_pool(sizeof(*pool) + 3 * sizeof(*todo));
+	if (IS_ERR(pool))
+		return PTR_ERR(pool);
+	todo = (carry_level *) (pool + 1);
+	init_carry_level(todo, pool);
+
+	ret = shift_everything_left(right, left, todo);
+	if (ret > 0) {
+		/* something was shifted */
+		reiser4_tree *tree;
+		__u64 grabbed;
+
+		znode_make_dirty(left);
+		znode_make_dirty(right);
+
+		/* update delimiting keys of nodes which participated in
+		   shift. FIXME: it would be better to have this in shift
+		   node's operation. But it can not be done there. Nobody
+		   remembers why, though */
+		tree = znode_get_tree(left);
+		write_lock_dk(tree);
+		update_znode_dkeys(left, right);
+		write_unlock_dk(tree);
+
+		/* Carry is called to update delimiting key and, maybe, to remove empty
+		   node. */
+		grabbed = get_current_context()->grabbed_blocks;
+		ret = reiser4_grab_space_force(tree->height, BA_RESERVED);
+		assert("nikita-3003", ret == 0);	/* reserved space is exhausted. Ask Hans. */
+		ret = carry(todo, NULL /* previous level */ );
+		grabbed2free_mark(grabbed);
+	} else {
+		/* Shifting impossible, we return appropriate result code */
+		ret =
+		    node_is_empty(right) ? SQUEEZE_SOURCE_EMPTY :
+		    SQUEEZE_TARGET_FULL;
+	}
+
+	done_carry_pool(pool);
+
+	return ret;
+}
+
+#if REISER4_DEBUG
+static int sibling_link_is_ok(const znode *left, const znode *right)
+{
+	int result;
+
+	read_lock_tree(znode_get_tree(left));
+	result = (left->right == right && left == right->left);
+	read_unlock_tree(znode_get_tree(left));
+	return result;
+}
+#endif
+
+/* Shift first unit of first item if it is an internal one.  Return
+   SQUEEZE_TARGET_FULL if it fails to shift an item, otherwise return
+   SUBTREE_MOVED. */
+static int shift_one_internal_unit(znode * left, znode * right)
+{
+	int ret;
+	carry_pool *pool;
+	carry_level *todo;
+	coord_t *coord;
+	carry_plugin_info *info;
+	int size, moved;
+
+	assert("nikita-2247", znode_get_level(left) == znode_get_level(right));
+	assert("nikita-2435", znode_is_write_locked(left));
+	assert("nikita-2436", znode_is_write_locked(right));
+	assert("nikita-2434", sibling_link_is_ok(left, right));
+
+	pool = init_carry_pool(sizeof(*pool) + 3 * sizeof(*todo) +
+			       sizeof(*coord) + sizeof(*info)
+#if REISER4_DEBUG
+			       + sizeof(*coord) + 2 * sizeof(reiser4_key)
+#endif
+	    );
+	if (IS_ERR(pool))
+		return PTR_ERR(pool);
+	todo = (carry_level *) (pool + 1);
+	init_carry_level(todo, pool);
+
+	coord = (coord_t *) (todo + 3);
+	coord_init_first_unit(coord, right);
+	info = (carry_plugin_info *) (coord + 1);
+
+#if REISER4_DEBUG
+	if (!node_is_empty(left)) {
+		coord_t *last;
+		reiser4_key *right_key;
+		reiser4_key *left_key;
+
+		last = (coord_t *) (info + 1);
+		right_key = (reiser4_key *) (last + 1);
+		left_key = right_key + 1;
+		coord_init_last_unit(last, left);
+
+		assert("nikita-2463",
+		       keyle(item_key_by_coord(last, left_key),
+			     item_key_by_coord(coord, right_key)));
+	}
+#endif
+
+	assert("jmacd-2007", item_is_internal(coord));
+
+	size = item_length_by_coord(coord);
+	info->todo = todo;
+	info->doing = NULL;
+
+	ret = node_plugin_by_node(left)->shift(coord, left, SHIFT_LEFT,
+					       1
+					       /* delete @right if it becomes empty */
+					       ,
+					       0
+					       /* do not move coord @coord to node @left */
+					       ,
+					       info);
+
+	/* If shift returns positive, then we shifted the item. */
+	assert("vs-423", ret <= 0 || size == ret);
+	moved = (ret > 0);
+
+	if (moved) {
+		/* something was moved */
+		reiser4_tree *tree;
+		int grabbed;
+
+		znode_make_dirty(left);
+		znode_make_dirty(right);
+		tree = znode_get_tree(left);
+		write_lock_dk(tree);
+		update_znode_dkeys(left, right);
+		write_unlock_dk(tree);
+
+		/* reserve space for delimiting keys after shifting */
+		grabbed = get_current_context()->grabbed_blocks;
+		ret = reiser4_grab_space_force(tree->height, BA_RESERVED);
+		assert("nikita-3003", ret == 0);	/* reserved space is exhausted. Ask Hans. */
+
+		ret = carry(todo, NULL /* previous level */ );
+		grabbed2free_mark(grabbed);
+	}
+
+	done_carry_pool(pool);
+
+	if (ret != 0) {
+		/* Shift or carry operation failed. */
+		assert("jmacd-7325", ret < 0);
+		return ret;
+	}
+
+	return moved ? SUBTREE_MOVED : SQUEEZE_TARGET_FULL;
+}
+
+/* ALLOCATE INTERFACE */
+/* Audited by: umka (2002.06.11) */
+void jnode_set_block(jnode * node /* jnode to update */ ,
+		     const reiser4_block_nr * blocknr /* new block nr */ )
+{
+	assert("nikita-2020", node != NULL);
+	assert("umka-055", blocknr != NULL);
+	assert("zam-819",
+	       ergo(JF_ISSET(node, JNODE_EFLUSH), node->blocknr == 0));
+	assert("vs-1453",
+	       ergo(JF_ISSET(node, JNODE_EFLUSH), jnode_is_unformatted(node)));
+	node->blocknr = *blocknr;
+}
+
+/* Make the final relocate/wander decision during forward parent-first squalloc for a
+   znode.  For unformatted nodes this is done in plugin/item/extent.c:extent_needs_allocation(). */
+static int
+allocate_znode_loaded(znode * node,
+		      const coord_t * parent_coord, flush_pos_t * pos)
+{
+	int ret;
+	reiser4_super_info_data *sbinfo = get_current_super_private();
+	/* FIXME(D): We have the node write-locked and should have checked for !
+	   allocated() somewhere before reaching this point, but there can be a race, so
+	   this assertion is bogus. */
+	assert("jmacd-7987", !jnode_check_flushprepped(ZJNODE(node)));
+	assert("jmacd-7988", znode_is_write_locked(node));
+	assert("jmacd-7989", coord_is_invalid(parent_coord)
+	       || znode_is_write_locked(parent_coord->node));
+
+	if (ZF_ISSET(node, JNODE_REPACK) || znode_created(node)
+	    || znode_is_root(node) ||
+	    /* We have enough nodes to relocate no matter what. */
+	    (pos->leaf_relocate != 0 && znode_get_level(node) == LEAF_LEVEL)) {
+		/* No need to decide with new nodes, they are treated the same as
+		   relocate. If the root node is dirty, relocate. */
+		if (pos->preceder.blk == 0) {
+			/* preceder is unknown and we have decided to relocate node --
+			   using of default value for search start is better than search
+			   from block #0. */
+			get_blocknr_hint_default(&pos->preceder.blk);
+			check_preceder(pos->preceder.blk);
+		}
+
+		goto best_reloc;
+
+	} else if (pos->preceder.blk == 0) {
+		/* If we don't know the preceder, leave it where it is. */
+		jnode_make_wander(ZJNODE(node));
+	} else {
+		/* Make a decision based on block distance. */
+		reiser4_block_nr dist;
+		reiser4_block_nr nblk = *znode_get_block(node);
+
+		assert("jmacd-6172", !blocknr_is_fake(&nblk));
+		assert("jmacd-6173", !blocknr_is_fake(&pos->preceder.blk));
+		assert("jmacd-6174", pos->preceder.blk != 0);
+
+		if (pos->preceder.blk == nblk - 1) {
+			/* Ideal. */
+			jnode_make_wander(ZJNODE(node));
+		} else {
+
+			dist =
+			    (nblk <
+			     pos->preceder.blk) ? (pos->preceder.blk -
+						   nblk) : (nblk -
+							    pos->preceder.blk);
+
+			/* See if we can find a closer block (forward direction only). */
+			pos->preceder.max_dist =
+			    min((reiser4_block_nr) sbinfo->flush.
+				relocate_distance, dist);
+			pos->preceder.level = znode_get_level(node);
+
+			ret = allocate_znode_update(node, parent_coord, pos);
+
+			pos->preceder.max_dist = 0;
+
+			if (ret && (ret != -ENOSPC))
+				return ret;
+
+			if (ret == 0) {
+				/* Got a better allocation. */
+				znode_make_reloc(node, pos->fq);
+			} else if (dist < sbinfo->flush.relocate_distance) {
+				/* The present allocation is good enough. */
+				jnode_make_wander(ZJNODE(node));
+			} else {
+				/* Otherwise, try to relocate to the best position. */
+			      best_reloc:
+				ret =
+				    allocate_znode_update(node, parent_coord,
+							  pos);
+				if (ret != 0)
+					return ret;
+
+				/* set JNODE_RELOC bit _after_ node gets allocated */
+				znode_make_reloc(node, pos->fq);
+			}
+		}
+	}
+
+	/* This is the new preceder. */
+	pos->preceder.blk = *znode_get_block(node);
+	check_preceder(pos->preceder.blk);
+	pos->alloc_cnt += 1;
+
+	assert("jmacd-4277", !blocknr_is_fake(&pos->preceder.blk));
+
+	return 0;
+}
+
+static int
+allocate_znode(znode * node, const coord_t * parent_coord, flush_pos_t * pos)
+{
+	/*
+	 * perform znode allocation with znode pinned in memory to avoid races
+	 * with asynchronous emergency flush (which plays with
+	 * JNODE_FLUSH_RESERVED bit).
+	 */
+	return WITH_DATA(node, allocate_znode_loaded(node, parent_coord, pos));
+}
+
+/* A subroutine of allocate_znode, this is called first to see if there is a close
+   position to relocate to.  It may return ENOSPC if there is no close position.  If there
+   is no close position it may not relocate.  This takes care of updating the parent node
+   with the relocated block address. */
+static int
+allocate_znode_update(znode * node, const coord_t * parent_coord,
+		      flush_pos_t * pos)
+{
+	int ret;
+	reiser4_block_nr blk;
+	lock_handle uber_lock;
+	int flush_reserved_used = 0;
+	int grabbed;
+
+	init_lh(&uber_lock);
+
+	grabbed = get_current_context()->grabbed_blocks;
+
+	/* discard e-flush allocation */
+	ret = zload(node);
+	if (ret)
+		return ret;
+
+	if (ZF_ISSET(node, JNODE_CREATED)) {
+		assert("zam-816", blocknr_is_fake(znode_get_block(node)));
+		pos->preceder.block_stage = BLOCK_UNALLOCATED;
+	} else {
+		pos->preceder.block_stage = BLOCK_GRABBED;
+
+		/* The disk space for relocating the @node is already reserved in "flush reserved"
+		 * counter if @node is leaf, otherwise we grab space using BA_RESERVED (means grab
+		 * space from whole disk not from only 95%). */
+		if (znode_get_level(node) == LEAF_LEVEL) {
+			/*
+			 * earlier (during do_jnode_make_dirty()) we decided
+			 * that @node can possibly go into overwrite set and
+			 * reserved block for its wandering location.
+			 */
+			txn_atom *atom = get_current_atom_locked();
+			assert("nikita-3449",
+			       ZF_ISSET(node, JNODE_FLUSH_RESERVED));
+			flush_reserved2grabbed(atom, (__u64) 1);
+			spin_unlock_atom(atom);
+			/*
+			 * we are trying to move node into relocate
+			 * set. Allocation of relocated position "uses"
+			 * reserved block.
+			 */
+			ZF_CLR(node, JNODE_FLUSH_RESERVED);
+			flush_reserved_used = 1;
+		} else {
+			ret = reiser4_grab_space_force((__u64) 1, BA_RESERVED);
+			if (ret != 0)
+				goto exit;
+		}
+	}
+
+	/* We may do not use 5% of reserved disk space here and flush will not pack tightly. */
+	ret =
+	    reiser4_alloc_block(&pos->preceder, &blk,
+				BA_FORMATTED | BA_PERMANENT);
+	if (ret)
+		goto exit;
+
+	if (!ZF_ISSET(node, JNODE_CREATED) &&
+	    (ret =
+	     reiser4_dealloc_block(znode_get_block(node), 0,
+				   BA_DEFER | BA_FORMATTED)))
+		goto exit;
+
+	if (likely(!znode_is_root(node))) {
+		item_plugin *iplug;
+
+		iplug = item_plugin_by_coord(parent_coord);
+		assert("nikita-2954", iplug->f.update != NULL);
+		iplug->f.update(parent_coord, &blk);
+
+		znode_make_dirty(parent_coord->node);
+
+	} else {
+		reiser4_tree *tree = znode_get_tree(node);
+		znode *uber;
+
+		/* We take a longterm lock on the fake node in order to change
+		   the root block number.  This may cause atom fusion. */
+		ret = get_uber_znode(tree, ZNODE_WRITE_LOCK, ZNODE_LOCK_HIPRI,
+				     &uber_lock);
+		/* The fake node cannot be deleted, and we must have priority
+		   here, and may not be confused with ENOSPC. */
+		assert("jmacd-74412",
+		       ret != -EINVAL && ret != -E_DEADLOCK && ret != -ENOSPC);
+
+		if (ret)
+			goto exit;
+
+		uber = uber_lock.node;
+
+		write_lock_tree(tree);
+		tree->root_block = blk;
+		write_unlock_tree(tree);
+
+		znode_make_dirty(uber);
+	}
+
+	ret = znode_rehash(node, &blk);
+      exit:
+	if (ret) {
+		/* Get flush reserved block back if something fails, because
+		 * callers assume that on error block wasn't relocated and its
+		 * flush reserved block wasn't used. */
+		if (flush_reserved_used) {
+			/*
+			 * ok, we failed to move node into relocate
+			 * set. Restore status quo.
+			 */
+			grabbed2flush_reserved((__u64) 1);
+			ZF_SET(node, JNODE_FLUSH_RESERVED);
+		}
+	}
+	zrelse(node);
+	done_lh(&uber_lock);
+	grabbed2free_mark(grabbed);
+	return ret;
+}
+
+/* JNODE INTERFACE */
+
+/* Lock a node (if formatted) and then get its parent locked, set the child's
+   coordinate in the parent.  If the child is the root node, the above_root
+   znode is returned but the coord is not set.  This function may cause atom
+   fusion, but it is only used for read locks (at this point) and therefore
+   fusion only occurs when the parent is already dirty. */
+/* Hans adds this note: remember to ask how expensive this operation is vs. storing parent
+   pointer in jnodes. */
+static int
+jnode_lock_parent_coord(jnode * node,
+			coord_t * coord,
+			lock_handle * parent_lh,
+			load_count * parent_zh,
+			znode_lock_mode parent_mode, int try)
+{
+	int ret;
+
+	assert("edward-53", jnode_is_unformatted(node) || jnode_is_znode(node));
+	assert("edward-54", jnode_is_unformatted(node)
+	       || znode_is_any_locked(JZNODE(node)));
+
+	if (!jnode_is_znode(node)) {
+		reiser4_key key;
+		tree_level stop_level = TWIG_LEVEL;
+		lookup_bias bias = FIND_EXACT;
+
+		assert("edward-168", !(jnode_get_type(node) == JNODE_BITMAP));
+
+		/* The case when node is not znode, but can have parent coord
+		   (unformatted node, node which represents cluster page,
+		   etc..).  Generate a key for the appropriate entry, search
+		   in the tree using coord_by_key, which handles locking for
+		   us. */
+
+		/*
+		 * nothing is locked at this moment, so, nothing prevents
+		 * concurrent truncate from removing jnode from inode. To
+		 * prevent this spin-lock jnode. jnode can be truncated just
+		 * after call to the jnode_build_key(), but this is ok,
+		 * because coord_by_key() will just fail to find appropriate
+		 * extent.
+		 */
+		spin_lock_jnode(node);
+		if (!JF_ISSET(node, JNODE_HEARD_BANSHEE)) {
+			jnode_build_key(node, &key);
+			ret = 0;
+		} else
+			ret = RETERR(-ENOENT);
+		spin_unlock_jnode(node);
+
+		if (ret != 0)
+			return ret;
+
+		if (jnode_is_cluster_page(node))
+			stop_level = LEAF_LEVEL;
+
+		assert("jmacd-1812", coord != NULL);
+
+		ret = coord_by_key(jnode_get_tree(node), &key, coord, parent_lh,
+				   parent_mode, bias, stop_level, stop_level,
+				   CBK_UNIQUE, NULL /*ra_info */ );
+		switch (ret) {
+		case CBK_COORD_NOTFOUND:
+			assert("edward-1038",
+			       ergo(jnode_is_cluster_page(node),
+				    JF_ISSET(node, JNODE_HEARD_BANSHEE)));
+			if (!JF_ISSET(node, JNODE_HEARD_BANSHEE))
+				warning("nikita-3177", "Parent not found");
+			return ret;
+		case CBK_COORD_FOUND:
+			if (coord->between != AT_UNIT) {
+				/* FIXME: comment needed */
+				done_lh(parent_lh);
+				if (!JF_ISSET(node, JNODE_HEARD_BANSHEE)) {
+					warning("nikita-3178",
+						"Found but not happy: %i",
+						coord->between);
+				}
+				return RETERR(-ENOENT);
+			}
+			ret = incr_load_count_znode(parent_zh, parent_lh->node);
+			if (ret != 0)
+				return ret;
+			/* if (jnode_is_cluster_page(node)) {
+			   races with write() are possible
+			   check_child_cluster (parent_lh->node);
+			   }
+			 */
+			break;
+		default:
+			return ret;
+		}
+
+	} else {
+		int flags;
+		znode *z;
+
+		z = JZNODE(node);
+		/* Formatted node case: */
+		assert("jmacd-2061", !znode_is_root(z));
+
+		flags = GN_ALLOW_NOT_CONNECTED;
+		if (try)
+			flags |= GN_TRY_LOCK;
+
+		ret =
+		    reiser4_get_parent_flags(parent_lh, z, parent_mode, flags);
+		if (ret != 0)
+			/* -E_REPEAT is ok here, it is handled by the caller. */
+			return ret;
+
+		/* Make the child's position "hint" up-to-date.  (Unless above
+		   root, which caller must check.) */
+		if (coord != NULL) {
+
+			ret = incr_load_count_znode(parent_zh, parent_lh->node);
+			if (ret != 0) {
+				warning("jmacd-976812386",
+					"incr_load_count_znode failed: %d",
+					ret);
+				return ret;
+			}
+
+			ret = find_child_ptr(parent_lh->node, z, coord);
+			if (ret != 0) {
+				warning("jmacd-976812",
+					"find_child_ptr failed: %d", ret);
+				return ret;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* Get the (locked) next neighbor of a znode which is dirty and a member of the same atom.
+   If there is no next neighbor or the neighbor is not in memory or if there is a
+   neighbor but it is not dirty or not in the same atom, -E_NO_NEIGHBOR is returned.
+   In some cases the slum may include nodes which are not dirty, if so @check_dirty should be 0 */
+static int neighbor_in_slum(znode * node,	/* starting point */
+			    lock_handle * lock,	/* lock on starting point */
+			    sideof side,	/* left or right direction we seek the next node in */
+			    znode_lock_mode mode,	/* kind of lock we want */
+			    int check_dirty)
+{				/* true if the neighbor should be dirty */
+	int ret;
+
+	assert("jmacd-6334", znode_is_connected(node));
+
+	ret =
+	    reiser4_get_neighbor(lock, node, mode,
+				 GN_SAME_ATOM | (side ==
+						 LEFT_SIDE ? GN_GO_LEFT : 0));
+
+	if (ret) {
+		/* May return -ENOENT or -E_NO_NEIGHBOR. */
+		/* FIXME(C): check EINVAL, E_DEADLOCK */
+		if (ret == -ENOENT) {
+			ret = RETERR(-E_NO_NEIGHBOR);
+		}
+
+		return ret;
+	}
+	if (!check_dirty)
+		return 0;
+	/* Check dirty bit of locked znode, no races here */
+	if (JF_ISSET(ZJNODE(lock->node), JNODE_DIRTY))
+		return 0;
+
+	done_lh(lock);
+	return RETERR(-E_NO_NEIGHBOR);
+}
+
+/* Return true if two znodes have the same parent.  This is called with both nodes
+   write-locked (for squeezing) so no tree lock is needed. */
+static int znode_same_parents(znode * a, znode * b)
+{
+	int result;
+
+	assert("jmacd-7011", znode_is_write_locked(a));
+	assert("jmacd-7012", znode_is_write_locked(b));
+
+	/* We lock the whole tree for this check.... I really don't like whole tree
+	 * locks... -Hans */
+	read_lock_tree(znode_get_tree(a));
+	result = (znode_parent(a) == znode_parent(b));
+	read_unlock_tree(znode_get_tree(a));
+	return result;
+}
+
+/* FLUSH SCAN */
+
+/* Initialize the flush_scan data structure. */
+static void scan_init(flush_scan * scan)
+{
+	memset(scan, 0, sizeof(*scan));
+	init_lh(&scan->node_lock);
+	init_lh(&scan->parent_lock);
+	init_load_count(&scan->parent_load);
+	init_load_count(&scan->node_load);
+	coord_init_invalid(&scan->parent_coord, NULL);
+}
+
+/* Release any resources held by the flush scan, e.g., release locks, free memory, etc. */
+static void scan_done(flush_scan * scan)
+{
+	done_load_count(&scan->node_load);
+	if (scan->node != NULL) {
+		jput(scan->node);
+		scan->node = NULL;
+	}
+	done_load_count(&scan->parent_load);
+	done_lh(&scan->parent_lock);
+	done_lh(&scan->node_lock);
+}
+
+/* Returns true if flush scanning is finished. */
+int scan_finished(flush_scan * scan)
+{
+	return scan->stop || (scan->direction == RIGHT_SIDE &&
+			      scan->count >= scan->max_count);
+}
+
+/* Return true if the scan should continue to the @tonode.  True if the node meets the
+   same_slum_check condition.  If not, deref the "left" node and stop the scan. */
+int scan_goto(flush_scan * scan, jnode * tonode)
+{
+	int go = same_slum_check(scan->node, tonode, 1, 0);
+
+	if (!go) {
+		scan->stop = 1;
+		jput(tonode);
+	}
+
+	return go;
+}
+
+/* Set the current scan->node, refcount it, increment count by the @add_count (number to
+   count, e.g., skipped unallocated nodes), deref previous current, and copy the current
+   parent coordinate. */
+int
+scan_set_current(flush_scan * scan, jnode * node, unsigned add_count,
+		 const coord_t * parent)
+{
+	/* Release the old references, take the new reference. */
+	done_load_count(&scan->node_load);
+
+	if (scan->node != NULL) {
+		jput(scan->node);
+	}
+	scan->node = node;
+	scan->count += add_count;
+
+	/* This next stmt is somewhat inefficient.  The scan_extent_coord code could
+	   delay this update step until it finishes and update the parent_coord only once.
+	   It did that before, but there was a bug and this was the easiest way to make it
+	   correct. */
+	if (parent != NULL) {
+		coord_dup(&scan->parent_coord, parent);
+	}
+
+	/* Failure may happen at the incr_load_count call, but the caller can assume the reference
+	   is safely taken. */
+	return incr_load_count_jnode(&scan->node_load, node);
+}
+
+/* Return true if scanning in the leftward direction. */
+int scanning_left(flush_scan * scan)
+{
+	return scan->direction == LEFT_SIDE;
+}
+
+/* Performs leftward scanning starting from either kind of node.  Counts the starting
+   node.  The right-scan object is passed in for the left-scan in order to copy the parent
+   of an unformatted starting position.  This way we avoid searching for the unformatted
+   node's parent when scanning in each direction.  If we search for the parent once it is
+   set in both scan objects.  The limit parameter tells flush-scan when to stop.
+
+   Rapid scanning is used only during scan_left, where we are interested in finding the
+   'leftpoint' where we begin flushing.  We are interested in stopping at the left child
+   of a twig that does not have a dirty left neighbor.  THIS IS A SPECIAL CASE.  The
+   problem is finding a way to flush only those nodes without unallocated children, and it
+   is difficult to solve in the bottom-up flushing algorithm we are currently using.  The
+   problem can be solved by scanning left at every level as we go upward, but this would
+   basically bring us back to using a top-down allocation strategy, which we already tried
+   (see BK history from May 2002), and has a different set of problems.  The top-down
+   strategy makes avoiding unallocated children easier, but makes it difficult to
+   propertly flush dirty children with clean parents that would otherwise stop the
+   top-down flush, only later to dirty the parent once the children are flushed.  So we
+   solve the problem in the bottom-up algorithm with a special case for twigs and leaves
+   only.
+
+   The first step in solving the problem is this rapid leftward scan.  After we determine
+   that there are at least enough nodes counted to qualify for FLUSH_RELOCATE_THRESHOLD we
+   are no longer interested in the exact count, we are only interested in finding a the
+   best place to start the flush.  We could choose one of two possibilities:
+
+   1. Stop at the leftmost child (of a twig) that does not have a dirty left neighbor.
+   This requires checking one leaf per rapid-scan twig
+
+   2. Stop at the leftmost child (of a twig) where there are no dirty children of the twig
+   to the left.  This requires checking possibly all of the in-memory children of each
+   twig during the rapid scan.
+
+   For now we implement the first policy.
+*/
+static int
+scan_left(flush_scan * scan, flush_scan * right, jnode * node, unsigned limit)
+{
+	int ret = 0;
+
+	scan->max_count = limit;
+	scan->direction = LEFT_SIDE;
+
+	ret = scan_set_current(scan, jref(node), 1, NULL);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = scan_common(scan, right);
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* Before rapid scanning, we need a lock on scan->node so that we can get its
+	   parent, only if formatted. */
+	if (jnode_is_znode(scan->node)) {
+		ret = longterm_lock_znode(&scan->node_lock, JZNODE(scan->node),
+					  ZNODE_WRITE_LOCK, ZNODE_LOCK_LOPRI);
+	}
+
+	/* Rapid_scan would go here (with limit set to FLUSH_RELOCATE_THRESHOLD). */
+	return ret;
+}
+
+/* Performs rightward scanning... Does not count the starting node.  The limit parameter
+   is described in scan_left.  If the starting node is unformatted then the
+   parent_coord was already set during scan_left.  The rapid_after parameter is not used
+   during right-scanning.
+
+   scan_right is only called if the scan_left operation does not count at least
+   FLUSH_RELOCATE_THRESHOLD nodes for flushing.  Otherwise, the limit parameter is set to
+   the difference between scan-left's count and FLUSH_RELOCATE_THRESHOLD, meaning
+   scan-right counts as high as FLUSH_RELOCATE_THRESHOLD and then stops. */
+static int scan_right(flush_scan * scan, jnode * node, unsigned limit)
+{
+	int ret;
+
+	scan->max_count = limit;
+	scan->direction = RIGHT_SIDE;
+
+	ret = scan_set_current(scan, jref(node), 0, NULL);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return scan_common(scan, NULL);
+}
+
+/* Common code to perform left or right scanning. */
+static int scan_common(flush_scan * scan, flush_scan * other)
+{
+	int ret;
+
+	assert("nikita-2376", scan->node != NULL);
+	assert("edward-54", jnode_is_unformatted(scan->node)
+	       || jnode_is_znode(scan->node));
+
+	/* Special case for starting at an unformatted node.  Optimization: we only want
+	   to search for the parent (which requires a tree traversal) once.  Obviously, we
+	   shouldn't have to call it once for the left scan and once for the right scan.
+	   For this reason, if we search for the parent during scan-left we then duplicate
+	   the coord/lock/load into the scan-right object. */
+	if (jnode_is_unformatted(scan->node)) {
+		ret = scan_unformatted(scan, other);
+		if (ret != 0)
+			return ret;
+	}
+	/* This loop expects to start at a formatted position and performs chaining of
+	   formatted regions */
+	while (!scan_finished(scan)) {
+
+		ret = scan_formatted(scan);
+		if (ret != 0) {
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int scan_unformatted(flush_scan * scan, flush_scan * other)
+{
+	int ret = 0;
+	int try = 0;
+
+	if (!coord_is_invalid(&scan->parent_coord))
+		goto scan;
+
+	/* set parent coord from */
+	if (!jnode_is_unformatted(scan->node)) {
+		/* formatted position */
+
+		lock_handle lock;
+		assert("edward-301", jnode_is_znode(scan->node));
+		init_lh(&lock);
+
+		/*
+		 * when flush starts from unformatted node, first thing it
+		 * does is tree traversal to find formatted parent of starting
+		 * node. This parent is then kept lock across scans to the
+		 * left and to the right. This means that during scan to the
+		 * left we cannot take left-ward lock, because this is
+		 * dead-lock prone. So, if we are scanning to the left and
+		 * there is already lock held by this thread,
+		 * jnode_lock_parent_coord() should use try-lock.
+		 */
+		try = scanning_left(scan)
+		    && !lock_stack_isclean(get_current_lock_stack());
+		/* Need the node locked to get the parent lock, We have to
+		   take write lock since there is at least one call path
+		   where this znode is already write-locked by us. */
+		ret =
+		    longterm_lock_znode(&lock, JZNODE(scan->node),
+					ZNODE_WRITE_LOCK,
+					scanning_left(scan) ? ZNODE_LOCK_LOPRI :
+					ZNODE_LOCK_HIPRI);
+		if (ret != 0)
+			/* EINVAL or E_DEADLOCK here mean... try again!  At this point we've
+			   scanned too far and can't back out, just start over. */
+			return ret;
+
+		ret = jnode_lock_parent_coord(scan->node,
+					      &scan->parent_coord,
+					      &scan->parent_lock,
+					      &scan->parent_load,
+					      ZNODE_WRITE_LOCK, try);
+
+		/* FIXME(C): check EINVAL, E_DEADLOCK */
+		done_lh(&lock);
+		if (ret == -E_REPEAT) {
+			scan->stop = 1;
+			return 0;
+		}
+		if (ret)
+			return ret;
+
+	} else {
+		/* unformatted position */
+
+		ret =
+		    jnode_lock_parent_coord(scan->node, &scan->parent_coord,
+					    &scan->parent_lock,
+					    &scan->parent_load,
+					    ZNODE_WRITE_LOCK, try);
+
+		if (IS_CBKERR(ret))
+			return ret;
+
+		if (ret == CBK_COORD_NOTFOUND)
+			/* FIXME(C): check EINVAL, E_DEADLOCK */
+			return ret;
+
+		/* parent was found */
+		assert("jmacd-8661", other != NULL);
+		/* Duplicate the reference into the other flush_scan. */
+		coord_dup(&other->parent_coord, &scan->parent_coord);
+		copy_lh(&other->parent_lock, &scan->parent_lock);
+		copy_load_count(&other->parent_load, &scan->parent_load);
+	}
+      scan:
+	return scan_by_coord(scan);
+}
+
+/* Performs left- or rightward scanning starting from a formatted node. Follow left
+   pointers under tree lock as long as:
+
+   - node->left/right is non-NULL
+   - node->left/right is connected, dirty
+   - node->left/right belongs to the same atom
+   - scan has not reached maximum count
+*/
+static int scan_formatted(flush_scan * scan)
+{
+	int ret;
+	znode *neighbor = NULL;
+
+	assert("jmacd-1401", !scan_finished(scan));
+
+	do {
+		znode *node = JZNODE(scan->node);
+
+		/* Node should be connected, but if not stop the scan. */
+		if (!znode_is_connected(node)) {
+			scan->stop = 1;
+			break;
+		}
+
+		/* Lock the tree, check-for and reference the next sibling. */
+		read_lock_tree(znode_get_tree(node));
+
+		/* It may be that a node is inserted or removed between a node and its
+		   left sibling while the tree lock is released, but the flush-scan count
+		   does not need to be precise.  Thus, we release the tree lock as soon as
+		   we get the neighboring node. */
+		neighbor = scanning_left(scan) ? node->left : node->right;
+		if (neighbor != NULL) {
+			zref(neighbor);
+		}
+
+		read_unlock_tree(znode_get_tree(node));
+
+		/* If neighbor is NULL at the leaf level, need to check for an unformatted
+		   sibling using the parent--break in any case. */
+		if (neighbor == NULL) {
+			break;
+		}
+
+		/* Check the condition for going left, break if it is not met.  This also
+		   releases (jputs) the neighbor if false. */
+		if (!scan_goto(scan, ZJNODE(neighbor))) {
+			break;
+		}
+
+		/* Advance the flush_scan state to the left, repeat. */
+		ret = scan_set_current(scan, ZJNODE(neighbor), 1, NULL);
+		if (ret != 0) {
+			return ret;
+		}
+
+	} while (!scan_finished(scan));
+
+	/* If neighbor is NULL then we reached the end of a formatted region, or else the
+	   sibling is out of memory, now check for an extent to the left (as long as
+	   LEAF_LEVEL). */
+	if (neighbor != NULL || jnode_get_level(scan->node) != LEAF_LEVEL
+	    || scan_finished(scan)) {
+		scan->stop = 1;
+		return 0;
+	}
+	/* Otherwise, calls scan_by_coord for the right(left)most item of the
+	   left(right) neighbor on the parent level, then possibly continue. */
+
+	coord_init_invalid(&scan->parent_coord, NULL);
+	return scan_unformatted(scan, NULL);
+}
+
+/* NOTE-EDWARD:
+   This scans adjacent items of the same type and calls scan flush plugin for each one.
+   Performs left(right)ward scanning starting from a (possibly) unformatted node.  If we start
+   from unformatted node, then we continue only if the next neighbor is also unformatted.
+   When called from scan_formatted, we skip first iteration (to make sure that
+   right(left)most item of the left(right) neighbor on the parent level is of the same
+   type and set appropriate coord). */
+static int scan_by_coord(flush_scan * scan)
+{
+	int ret = 0;
+	int scan_this_coord;
+	lock_handle next_lock;
+	load_count next_load;
+	coord_t next_coord;
+	jnode *child;
+	item_plugin *iplug;
+
+	init_lh(&next_lock);
+	init_load_count(&next_load);
+	scan_this_coord = (jnode_is_unformatted(scan->node) ? 1 : 0);
+
+	/* set initial item id */
+	iplug = item_plugin_by_coord(&scan->parent_coord);
+
+	for (; !scan_finished(scan); scan_this_coord = 1) {
+		if (scan_this_coord) {
+			/* Here we expect that unit is scannable. it would not be so due
+			 * to race with extent->tail conversion.  */
+			if (iplug->f.scan == NULL) {
+				scan->stop = 1;
+				ret = -E_REPEAT;
+				/* skip the check at the end. */
+				goto race;
+			}
+
+			ret = iplug->f.scan(scan);
+			if (ret != 0)
+				goto exit;
+
+			if (scan_finished(scan)) {
+				checkchild(scan);
+				break;
+			}
+		} else {
+			/* the same race against truncate as above is possible
+			 * here, it seems */
+
+			/* NOTE-JMACD: In this case, apply the same end-of-node logic but don't scan
+			   the first coordinate. */
+			assert("jmacd-1231",
+			       item_is_internal(&scan->parent_coord));
+		}
+
+		if (iplug->f.utmost_child == NULL
+		    || znode_get_level(scan->parent_coord.node) != TWIG_LEVEL) {
+			/* stop this coord and continue on parrent level */
+			ret =
+			    scan_set_current(scan,
+					     ZJNODE(zref
+						    (scan->parent_coord.node)),
+					     1, NULL);
+			if (ret != 0)
+				goto exit;
+			break;
+		}
+
+		/* Either way, the invariant is that scan->parent_coord is set to the
+		   parent of scan->node. Now get the next unit. */
+		coord_dup(&next_coord, &scan->parent_coord);
+		coord_sideof_unit(&next_coord, scan->direction);
+
+		/* If off-the-end of the twig, try the next twig. */
+		if (coord_is_after_sideof_unit(&next_coord, scan->direction)) {
+			/* We take the write lock because we may start flushing from this
+			 * coordinate. */
+			ret =
+			    neighbor_in_slum(next_coord.node, &next_lock,
+					     scan->direction, ZNODE_WRITE_LOCK,
+					     1 /* check dirty */ );
+			if (ret == -E_NO_NEIGHBOR) {
+				scan->stop = 1;
+				ret = 0;
+				break;
+			}
+
+			if (ret != 0) {
+				goto exit;
+			}
+
+			ret = incr_load_count_znode(&next_load, next_lock.node);
+			if (ret != 0) {
+				goto exit;
+			}
+
+			coord_init_sideof_unit(&next_coord, next_lock.node,
+					       sideof_reverse(scan->direction));
+		}
+
+		iplug = item_plugin_by_coord(&next_coord);
+
+		/* Get the next child. */
+		ret =
+		    iplug->f.utmost_child(&next_coord,
+					  sideof_reverse(scan->direction),
+					  &child);
+		if (ret != 0)
+			goto exit;
+		/* If the next child is not in memory, or, item_utmost_child
+		   failed (due to race with unlink, most probably), stop
+		   here. */
+		if (child == NULL || IS_ERR(child)) {
+			scan->stop = 1;
+			checkchild(scan);
+			break;
+		}
+
+		assert("nikita-2374", jnode_is_unformatted(child)
+		       || jnode_is_znode(child));
+
+		/* See if it is dirty, part of the same atom. */
+		if (!scan_goto(scan, child)) {
+			checkchild(scan);
+			break;
+		}
+
+		/* If so, make this child current. */
+		ret = scan_set_current(scan, child, 1, &next_coord);
+		if (ret != 0)
+			goto exit;
+
+		/* Now continue.  If formatted we release the parent lock and return, then
+		   proceed. */
+		if (jnode_is_znode(child))
+			break;
+
+		/* Otherwise, repeat the above loop with next_coord. */
+		if (next_load.node != NULL) {
+			done_lh(&scan->parent_lock);
+			move_lh(&scan->parent_lock, &next_lock);
+			move_load_count(&scan->parent_load, &next_load);
+		}
+	}
+
+	assert("jmacd-6233", scan_finished(scan) || jnode_is_znode(scan->node));
+      exit:
+	checkchild(scan);
+      race:			/* skip the above check  */
+	if (jnode_is_znode(scan->node)) {
+		done_lh(&scan->parent_lock);
+		done_load_count(&scan->parent_load);
+	}
+
+	done_load_count(&next_load);
+	done_lh(&next_lock);
+	return ret;
+}
+
+/* FLUSH POS HELPERS */
+
+/* Initialize the fields of a flush_position. */
+static void pos_init(flush_pos_t * pos)
+{
+	memset(pos, 0, sizeof *pos);
+
+	pos->state = POS_INVALID;
+	coord_init_invalid(&pos->coord, NULL);
+	init_lh(&pos->lock);
+	init_load_count(&pos->load);
+
+	blocknr_hint_init(&pos->preceder);
+}
+
+/* The flush loop inside squalloc periodically checks pos_valid to
+   determine when "enough flushing" has been performed.  This will return true until one
+   of the following conditions is met:
+
+   1. the number of flush-queued nodes has reached the kernel-supplied "int *nr_to_flush"
+   parameter, meaning we have flushed as many blocks as the kernel requested.  When
+   flushing to commit, this parameter is NULL.
+
+   2. pos_stop() is called because squalloc discovers that the "next" node in the
+   flush order is either non-existant, not dirty, or not in the same atom.
+*/
+
+static int pos_valid(flush_pos_t * pos)
+{
+	return pos->state != POS_INVALID;
+}
+
+/* Release any resources of a flush_position.  Called when jnode_flush finishes. */
+static void pos_done(flush_pos_t * pos)
+{
+	pos_stop(pos);
+	blocknr_hint_done(&pos->preceder);
+	if (convert_data(pos))
+		free_convert_data(pos);
+}
+
+/* Reset the point and parent.  Called during flush subroutines to terminate the
+   squalloc loop. */
+static int pos_stop(flush_pos_t * pos)
+{
+	pos->state = POS_INVALID;
+	done_lh(&pos->lock);
+	done_load_count(&pos->load);
+	coord_init_invalid(&pos->coord, NULL);
+
+	if (pos->child) {
+		jput(pos->child);
+		pos->child = NULL;
+	}
+
+	return 0;
+}
+
+/* Return the flush_position's block allocator hint. */
+reiser4_blocknr_hint *pos_hint(flush_pos_t * pos)
+{
+	return &pos->preceder;
+}
+
+flush_queue_t *pos_fq(flush_pos_t * pos)
+{
+	return pos->fq;
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 90
+   LocalWords:  preceder
+   End:
+*/
diff -urN oldtree/fs/reiser4/flush.h newtree/fs/reiser4/flush.h
--- oldtree/fs/reiser4/flush.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/flush.h	2006-02-21 15:58:35.182797960 +0000
@@ -0,0 +1,274 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* DECLARATIONS: */
+
+#if !defined(__REISER4_FLUSH_H__)
+#define __REISER4_FLUSH_H__
+
+#include "plugin/cluster.h"
+
+/* The flush_scan data structure maintains the state of an in-progress flush-scan on a
+   single level of the tree.  A flush-scan is used for counting the number of adjacent
+   nodes to flush, which is used to determine whether we should relocate, and it is also
+   used to find a starting point for flush.  A flush-scan object can scan in both right
+   and left directions via the scan_left() and scan_right() interfaces.  The
+   right- and left-variations are similar but perform different functions.  When scanning
+   left we (optionally perform rapid scanning and then) longterm-lock the endpoint node.
+   When scanning right we are simply counting the number of adjacent, dirty nodes. */
+struct flush_scan {
+
+	/* The current number of nodes scanned on this level. */
+	unsigned count;
+
+	/* There may be a maximum number of nodes for a scan on any single level.  When
+	   going leftward, max_count is determined by FLUSH_SCAN_MAXNODES (see reiser4.h) */
+	unsigned max_count;
+
+	/* Direction: Set to one of the sideof enumeration: { LEFT_SIDE, RIGHT_SIDE }. */
+	sideof direction;
+
+	/* Initially @stop is set to false then set true once some condition stops the
+	   search (e.g., we found a clean node before reaching max_count or we found a
+	   node belonging to another atom). */
+	int stop;
+
+	/* The current scan position.  If @node is non-NULL then its reference count has
+	   been incremented to reflect this reference. */
+	jnode *node;
+
+	/* A handle for zload/zrelse of current scan position node. */
+	load_count node_load;
+
+	/* During left-scan, if the final position (a.k.a. endpoint node) is formatted the
+	   node is locked using this lock handle.  The endpoint needs to be locked for
+	   transfer to the flush_position object after scanning finishes. */
+	lock_handle node_lock;
+
+	/* When the position is unformatted, its parent, coordinate, and parent
+	   zload/zrelse handle. */
+	lock_handle parent_lock;
+	coord_t parent_coord;
+	load_count parent_load;
+
+	/* The block allocator preceder hint.  Sometimes flush_scan determines what the
+	   preceder is and if so it sets it here, after which it is copied into the
+	   flush_position.  Otherwise, the preceder is computed later. */
+	reiser4_block_nr preceder_blk;
+};
+
+typedef struct convert_item_info {
+	dc_item_stat d_cur;	/* disk cluster state of the current item */
+	dc_item_stat d_next;	/* disk cluster state of the next slum item */
+	struct inode *inode;
+	flow_t flow;
+} convert_item_info_t;
+
+typedef struct convert_info {
+	int count;		/* for squalloc terminating */
+	reiser4_cluster_t clust;	/* transform cluster */
+	item_plugin *iplug;	/* current item plugin */
+	convert_item_info_t *itm;	/* current item info */
+} convert_info_t;
+
+typedef enum flush_position_state {
+	POS_INVALID,		/* Invalid or stopped pos, do not continue slum
+				 * processing */
+	POS_ON_LEAF,		/* pos points to already prepped, locked formatted node at
+				 * leaf level */
+	POS_ON_EPOINT,		/* pos keeps a lock on twig level, "coord" field is used
+				 * to traverse unformatted nodes */
+	POS_TO_LEAF,		/* pos is being moved to leaf level */
+	POS_TO_TWIG,		/* pos is being moved to twig level */
+	POS_END_OF_TWIG,	/* special case of POS_ON_TWIG, when coord is after
+				 * rightmost unit of the current twig */
+	POS_ON_INTERNAL		/* same as POS_ON_LEAF, but points to internal node */
+} flushpos_state_t;
+
+/* An encapsulation of the current flush point and all the parameters that are passed
+   through the entire squeeze-and-allocate stage of the flush routine.  A single
+   flush_position object is constructed after left- and right-scanning finishes. */
+struct flush_position {
+	flushpos_state_t state;
+
+	coord_t coord;		/* coord to traverse unformatted nodes */
+	lock_handle lock;	/* current lock we hold */
+	load_count load;	/* load status for current locked formatted node  */
+
+	jnode *child;		/* for passing a reference to unformatted child
+				 * across pos state changes */
+
+	reiser4_blocknr_hint preceder;	/* The flush 'hint' state. */
+	int leaf_relocate;	/* True if enough leaf-level nodes were
+				 * found to suggest a relocate policy. */
+	int alloc_cnt;		/* The number of nodes allocated during squeeze and allococate. */
+	int prep_or_free_cnt;	/* The number of nodes prepared for write (allocate) or squeezed and freed. */
+	flush_queue_t *fq;
+	long *nr_written;	/* number of nodes submitted to disk */
+	int flags;		/* a copy of jnode_flush flags argument */
+
+	znode *prev_twig;	/* previous parent pointer value, used to catch
+				 * processing of new twig node */
+	convert_info_t *sq;	/* convert info */
+
+	unsigned long pos_in_unit;	/* for extents only. Position
+					   within an extent unit of first
+					   jnode of slum */
+	long nr_to_write;	/* number of unformatted nodes to handle on flush */
+};
+
+static inline int item_convert_count(flush_pos_t * pos)
+{
+	return pos->sq->count;
+}
+static inline void inc_item_convert_count(flush_pos_t * pos)
+{
+	pos->sq->count++;
+}
+static inline void set_item_convert_count(flush_pos_t * pos, int count)
+{
+	pos->sq->count = count;
+}
+static inline item_plugin *item_convert_plug(flush_pos_t * pos)
+{
+	return pos->sq->iplug;
+}
+
+static inline convert_info_t *convert_data(flush_pos_t * pos)
+{
+	return pos->sq;
+}
+
+static inline convert_item_info_t *item_convert_data(flush_pos_t * pos)
+{
+	assert("edward-955", convert_data(pos));
+	return pos->sq->itm;
+}
+
+static inline tfm_cluster_t *tfm_cluster_sq(flush_pos_t * pos)
+{
+	return &pos->sq->clust.tc;
+}
+
+static inline tfm_stream_t *tfm_stream_sq(flush_pos_t * pos, tfm_stream_id id)
+{
+	assert("edward-854", pos->sq != NULL);
+	return tfm_stream(tfm_cluster_sq(pos), id);
+}
+
+static inline int chaining_data_present(flush_pos_t * pos)
+{
+	return convert_data(pos) && item_convert_data(pos);
+}
+
+/* Returns true if next node contains next item of the disk cluster
+   so item convert data should be moved to the right slum neighbor.
+*/
+static inline int should_chain_next_node(flush_pos_t * pos)
+{
+	int result = 0;
+
+	assert("edward-1007", chaining_data_present(pos));
+
+	switch (item_convert_data(pos)->d_next) {
+	case DC_CHAINED_ITEM:
+		result = 1;
+		break;
+	case DC_AFTER_CLUSTER:
+		break;
+	default:
+		impossible("edward-1009", "bad state of next slum item");
+	}
+	return result;
+}
+
+/* update item state in a disk cluster to assign conversion mode */
+static inline void
+move_chaining_data(flush_pos_t * pos, int this_node /* where is next item */ )
+{
+
+	assert("edward-1010", chaining_data_present(pos));
+
+	if (this_node == 0) {
+		/* next item is on the right neighbor */
+		assert("edward-1011",
+		       item_convert_data(pos)->d_cur == DC_FIRST_ITEM ||
+		       item_convert_data(pos)->d_cur == DC_CHAINED_ITEM);
+		assert("edward-1012",
+		       item_convert_data(pos)->d_next == DC_CHAINED_ITEM);
+
+		item_convert_data(pos)->d_cur = DC_CHAINED_ITEM;
+		item_convert_data(pos)->d_next = DC_INVALID_STATE;
+	} else {
+		/* next item is on the same node */
+		assert("edward-1013",
+		       item_convert_data(pos)->d_cur == DC_FIRST_ITEM ||
+		       item_convert_data(pos)->d_cur == DC_CHAINED_ITEM);
+		assert("edward-1227",
+		       item_convert_data(pos)->d_next == DC_AFTER_CLUSTER ||
+		       item_convert_data(pos)->d_next == DC_INVALID_STATE);
+
+		item_convert_data(pos)->d_cur = DC_AFTER_CLUSTER;
+		item_convert_data(pos)->d_next = DC_INVALID_STATE;
+	}
+}
+
+static inline int should_convert_node(flush_pos_t * pos, znode * node)
+{
+	return znode_convertible(node);
+}
+
+/* true if there is attached convert item info */
+static inline int should_convert_next_node(flush_pos_t * pos, znode * node)
+{
+	return convert_data(pos) && item_convert_data(pos);
+}
+
+#define SQUALLOC_THRESHOLD 256
+
+static inline int should_terminate_squalloc(flush_pos_t * pos)
+{
+	return convert_data(pos) &&
+	    !item_convert_data(pos) &&
+	    item_convert_count(pos) >= SQUALLOC_THRESHOLD;
+}
+
+void free_convert_data(flush_pos_t * pos);
+/* used in extent.c */
+int scan_set_current(flush_scan * scan, jnode * node, unsigned add_size,
+		     const coord_t * parent);
+int scan_finished(flush_scan * scan);
+int scanning_left(flush_scan * scan);
+int scan_goto(flush_scan * scan, jnode * tonode);
+txn_atom *atom_locked_by_fq(flush_queue_t * fq);
+int alloc_extent(flush_pos_t *flush_pos);
+squeeze_result squalloc_extent(znode *left, const coord_t *, flush_pos_t *,
+			       reiser4_key *stop_key);
+extern int init_fqs(void);
+extern void done_fqs(void);
+
+#if REISER4_DEBUG
+
+extern void check_fq(const txn_atom *atom);
+extern atomic_t flush_cnt;
+
+#define check_preceder(blk) \
+assert("nikita-2588", blk < reiser4_block_count(reiser4_get_current_sb()));
+extern void check_pos(flush_pos_t * pos);
+#else
+#define check_preceder(b) noop
+#define check_pos(pos) noop
+#endif
+
+/* __REISER4_FLUSH_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 90
+   LocalWords:  preceder
+   End:
+*/
diff -urN oldtree/fs/reiser4/flush_queue.c newtree/fs/reiser4/flush_queue.c
--- oldtree/fs/reiser4/flush_queue.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/flush_queue.c	2006-02-21 15:58:35.399764976 +0000
@@ -0,0 +1,748 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#include "debug.h"
+#include "super.h"
+#include "txnmgr.h"
+#include "jnode.h"
+#include "znode.h"
+#include "page_cache.h"
+#include "wander.h"
+#include "vfs_ops.h"
+#include "writeout.h"
+#include "flush.h"
+
+#include <linux/bio.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/blkdev.h>
+#include <linux/writeback.h>
+
+/* A flush queue object is an accumulator for keeping jnodes prepared
+   by the jnode_flush() function for writing to disk. Those "queued" jnodes are
+   kept on the flush queue until memory pressure or atom commit asks
+   flush queues to write some or all from their jnodes. */
+
+/*
+   LOCKING:
+
+   fq->guard spin lock protects fq->atom pointer and nothing else.  fq->prepped
+   list protected by atom spin lock.  fq->prepped list uses the following
+   locking:
+
+   two ways to protect fq->prepped list for read-only list traversal:
+
+   1. atom spin-lock atom.
+   2. fq is IN_USE, atom->nr_running_queues increased.
+
+   and one for list modification:
+
+   1. atom is spin-locked and one condition is true: fq is IN_USE or
+      atom->nr_running_queues == 0.
+
+   The deadlock-safe order for flush queues and atoms is: first lock atom, then
+   lock flush queue, then lock jnode.
+*/
+
+#define fq_in_use(fq)          ((fq)->state & FQ_IN_USE)
+#define fq_ready(fq)           (!fq_in_use(fq))
+
+#define mark_fq_in_use(fq)     do { (fq)->state |= FQ_IN_USE;    } while (0)
+#define mark_fq_ready(fq)      do { (fq)->state &= ~FQ_IN_USE;   } while (0)
+
+/* get lock on atom from locked flush queue object */
+static txn_atom *atom_locked_by_fq_nolock(flush_queue_t * fq)
+{
+	/* This code is similar to jnode_get_atom(), look at it for the
+	 * explanation. */
+	txn_atom *atom;
+
+	assert_spin_locked(&(fq->guard));
+
+	while (1) {
+		atom = fq->atom;
+		if (atom == NULL)
+			break;
+
+		if (spin_trylock_atom(atom))
+			break;
+
+		atomic_inc(&atom->refcount);
+		spin_unlock(&(fq->guard));
+		spin_lock_atom(atom);
+		spin_lock(&(fq->guard));
+
+		if (fq->atom == atom) {
+			atomic_dec(&atom->refcount);
+			break;
+		}
+
+		spin_unlock(&(fq->guard));
+		atom_dec_and_unlock(atom);
+		spin_lock(&(fq->guard));
+	}
+
+	return atom;
+}
+
+txn_atom *atom_locked_by_fq(flush_queue_t * fq)
+{
+	txn_atom *atom;
+
+	spin_lock(&(fq->guard));
+	atom = atom_locked_by_fq_nolock(fq);
+	spin_unlock(&(fq->guard));
+	return atom;
+}
+
+static void init_fq(flush_queue_t * fq)
+{
+	memset(fq, 0, sizeof *fq);
+
+	atomic_set(&fq->nr_submitted, 0);
+
+	INIT_LIST_HEAD(ATOM_FQ_LIST(fq));
+
+	sema_init(&fq->io_sem, 0);
+	spin_lock_init(&fq->guard);
+}
+
+/* slab for flush queues */
+static kmem_cache_t *fq_slab;
+
+
+/**
+ * init_fqs - create flush queue cache
+ *
+ * Initializes slab cache of flush queues. It is part of reiser4 module
+ * initialization.
+ */
+int init_fqs(void)
+{
+	fq_slab = kmem_cache_create("fq",
+				    sizeof(flush_queue_t),
+				    0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (fq_slab == NULL)
+		return RETERR(-ENOMEM);
+	return 0;
+}
+
+/**
+ * done_fqs - delete flush queue cache
+ *
+ * This is called on reiser4 module unloading or system shutdown.
+ */
+void done_fqs(void)
+{
+	destroy_reiser4_cache(&fq_slab);
+}
+
+/* create new flush queue object */
+static flush_queue_t *create_fq(unsigned int gfp)
+{
+	flush_queue_t *fq;
+
+	fq = kmem_cache_alloc(fq_slab, gfp);
+	if (fq)
+		init_fq(fq);
+
+	return fq;
+}
+
+/* adjust atom's and flush queue's counters of queued nodes */
+static void count_enqueued_node(flush_queue_t * fq)
+{
+	ON_DEBUG(fq->atom->num_queued++);
+}
+
+static void count_dequeued_node(flush_queue_t * fq)
+{
+	assert("zam-993", fq->atom->num_queued > 0);
+	ON_DEBUG(fq->atom->num_queued--);
+}
+
+/* attach flush queue object to the atom */
+static void attach_fq(txn_atom *atom, flush_queue_t *fq)
+{
+	assert_spin_locked(&(atom->alock));
+	list_add(&fq->alink, &atom->flush_queues);
+	fq->atom = atom;
+	ON_DEBUG(atom->nr_flush_queues++);
+}
+
+static void detach_fq(flush_queue_t * fq)
+{
+	assert_spin_locked(&(fq->atom->alock));
+
+	spin_lock(&(fq->guard));
+	list_del_init(&fq->alink);
+	assert("vs-1456", fq->atom->nr_flush_queues > 0);
+	ON_DEBUG(fq->atom->nr_flush_queues--);
+	fq->atom = NULL;
+	spin_unlock(&(fq->guard));
+}
+
+/* destroy flush queue object */
+static void done_fq(flush_queue_t * fq)
+{
+	assert("zam-763", list_empty_careful(ATOM_FQ_LIST(fq)));
+	assert("zam-766", atomic_read(&fq->nr_submitted) == 0);
+
+	kmem_cache_free(fq_slab, fq);
+}
+
+/* */
+void mark_jnode_queued(flush_queue_t * fq, jnode * node)
+{
+	JF_SET(node, JNODE_FLUSH_QUEUED);
+	count_enqueued_node(fq);
+}
+
+/* Putting jnode into the flush queue. Both atom and jnode should be
+   spin-locked. */
+void queue_jnode(flush_queue_t * fq, jnode * node)
+{
+	assert_spin_locked(&(node->guard));
+	assert("zam-713", node->atom != NULL);
+	assert_spin_locked(&(node->atom->alock));
+	assert("zam-716", fq->atom != NULL);
+	assert("zam-717", fq->atom == node->atom);
+	assert("zam-907", fq_in_use(fq));
+
+	assert("zam-714", JF_ISSET(node, JNODE_DIRTY));
+	assert("zam-826", JF_ISSET(node, JNODE_RELOC));
+	assert("vs-1481", !JF_ISSET(node, JNODE_FLUSH_QUEUED));
+	assert("vs-1481", NODE_LIST(node) != FQ_LIST);
+
+	mark_jnode_queued(fq, node);
+	list_del(&node->capture_link);
+	list_add_tail(&node->capture_link, ATOM_FQ_LIST(fq));
+
+	ON_DEBUG(count_jnode(node->atom, node, NODE_LIST(node),
+			     FQ_LIST, 1));
+}
+
+/* repeatable process for waiting io completion on a flush queue object */
+static int wait_io(flush_queue_t * fq, int *nr_io_errors)
+{
+	assert("zam-738", fq->atom != NULL);
+	assert_spin_locked(&(fq->atom->alock));
+	assert("zam-736", fq_in_use(fq));
+	assert("zam-911", list_empty_careful(ATOM_FQ_LIST(fq)));
+
+	if (atomic_read(&fq->nr_submitted) != 0) {
+		struct super_block *super;
+
+		spin_unlock_atom(fq->atom);
+
+		assert("nikita-3013", schedulable());
+
+		super = reiser4_get_current_sb();
+
+		/* FIXME: this is instead of blk_run_queues() */
+		blk_run_address_space(get_super_fake(super)->i_mapping);
+
+		if (!(super->s_flags & MS_RDONLY))
+			down(&fq->io_sem);
+
+		/* Ask the caller to re-acquire the locks and call this
+		   function again. Note: this technique is commonly used in
+		   the txnmgr code. */
+		return -E_REPEAT;
+	}
+
+	*nr_io_errors += atomic_read(&fq->nr_errors);
+	return 0;
+}
+
+/* wait on I/O completion, re-submit dirty nodes to write */
+static int finish_fq(flush_queue_t * fq, int *nr_io_errors)
+{
+	int ret;
+	txn_atom *atom = fq->atom;
+
+	assert("zam-801", atom != NULL);
+	assert_spin_locked(&(atom->alock));
+	assert("zam-762", fq_in_use(fq));
+
+	ret = wait_io(fq, nr_io_errors);
+	if (ret)
+		return ret;
+
+	detach_fq(fq);
+	done_fq(fq);
+
+	atom_send_event(atom);
+
+	return 0;
+}
+
+/* wait for all i/o for given atom to be completed, actually do one iteration
+   on that and return -E_REPEAT if there more iterations needed */
+static int finish_all_fq(txn_atom * atom, int *nr_io_errors)
+{
+	flush_queue_t *fq;
+
+	assert_spin_locked(&(atom->alock));
+
+	if (list_empty_careful(&atom->flush_queues))
+		return 0;
+
+	list_for_each_entry(fq, &atom->flush_queues, alink) {
+		if (fq_ready(fq)) {
+			int ret;
+
+			mark_fq_in_use(fq);
+			assert("vs-1247", fq->owner == NULL);
+			ON_DEBUG(fq->owner = current);
+			ret = finish_fq(fq, nr_io_errors);
+
+			if (*nr_io_errors)
+				reiser4_handle_error();
+
+			if (ret) {
+				fq_put(fq);
+				return ret;
+			}
+
+			spin_unlock_atom(atom);
+
+			return -E_REPEAT;
+		}
+	}
+
+	/* All flush queues are in use; atom remains locked */
+	return -EBUSY;
+}
+
+/* wait all i/o for current atom */
+int current_atom_finish_all_fq(void)
+{
+	txn_atom *atom;
+	int nr_io_errors = 0;
+	int ret = 0;
+
+	do {
+		while (1) {
+			atom = get_current_atom_locked();
+			ret = finish_all_fq(atom, &nr_io_errors);
+			if (ret != -EBUSY)
+				break;
+			atom_wait_event(atom);
+		}
+	} while (ret == -E_REPEAT);
+
+	/* we do not need locked atom after this function finishes, SUCCESS or
+	   -EBUSY are two return codes when atom remains locked after
+	   finish_all_fq */
+	if (!ret)
+		spin_unlock_atom(atom);
+
+	assert_spin_not_locked(&(atom->alock));
+
+	if (ret)
+		return ret;
+
+	if (nr_io_errors)
+		return RETERR(-EIO);
+
+	return 0;
+}
+
+/* change node->atom field for all jnode from given list */
+static void
+scan_fq_and_update_atom_ref(struct list_head *list, txn_atom *atom)
+{
+	jnode *cur;
+
+	list_for_each_entry(cur, list, capture_link) {
+		spin_lock_jnode(cur);
+		cur->atom = atom;
+		spin_unlock_jnode(cur);
+	}
+}
+
+/* support for atom fusion operation */
+void fuse_fq(txn_atom *to, txn_atom *from)
+{
+	flush_queue_t *fq;
+
+	assert_spin_locked(&(to->alock));
+	assert_spin_locked(&(from->alock));
+
+	list_for_each_entry(fq, &from->flush_queues, alink) {
+		scan_fq_and_update_atom_ref(ATOM_FQ_LIST(fq), to);
+		spin_lock(&(fq->guard));
+		fq->atom = to;
+		spin_unlock(&(fq->guard));
+	}
+
+	list_splice_init(&from->flush_queues, to->flush_queues.prev);
+
+#if REISER4_DEBUG
+	to->num_queued += from->num_queued;
+	to->nr_flush_queues += from->nr_flush_queues;
+	from->nr_flush_queues = 0;
+#endif
+}
+
+#if REISER4_DEBUG
+int atom_fq_parts_are_clean(txn_atom * atom)
+{
+	assert("zam-915", atom != NULL);
+	return list_empty_careful(&atom->flush_queues);
+}
+#endif
+/* Bio i/o completion routine for reiser4 write operations. */
+static int
+end_io_handler(struct bio *bio, unsigned int bytes_done UNUSED_ARG,
+	       int err)
+{
+	int i;
+	int nr_errors = 0;
+	flush_queue_t *fq;
+
+	assert("zam-958", bio->bi_rw & WRITE);
+
+	/* i/o op. is not fully completed */
+	if (bio->bi_size != 0)
+		return 1;
+
+	if (err == -EOPNOTSUPP)
+		set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
+
+	/* we expect that bio->private is set to NULL or fq object which is used
+	 * for synchronization and error counting. */
+	fq = bio->bi_private;
+	/* Check all elements of io_vec for correct write completion. */
+	for (i = 0; i < bio->bi_vcnt; i += 1) {
+		struct page *pg = bio->bi_io_vec[i].bv_page;
+
+		if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) {
+			SetPageError(pg);
+			nr_errors++;
+		}
+
+		{
+			/* jnode WRITEBACK ("write is in progress bit") is
+			 * atomically cleared here. */
+			jnode *node;
+
+			assert("zam-736", pg != NULL);
+			assert("zam-736", PagePrivate(pg));
+			node = jprivate(pg);
+
+			JF_CLR(node, JNODE_WRITEBACK);
+		}
+
+		end_page_writeback(pg);
+		page_cache_release(pg);
+	}
+
+	if (fq) {
+		/* count i/o error in fq object */
+		atomic_add(nr_errors, &fq->nr_errors);
+
+		/* If all write requests registered in this "fq" are done we up
+		 * the semaphore. */
+		if (atomic_sub_and_test(bio->bi_vcnt, &fq->nr_submitted))
+			up(&fq->io_sem);
+	}
+
+	bio_put(bio);
+	return 0;
+}
+
+/* Count I/O requests which will be submitted by @bio in given flush queues
+   @fq */
+void add_fq_to_bio(flush_queue_t * fq, struct bio *bio)
+{
+	bio->bi_private = fq;
+	bio->bi_end_io = end_io_handler;
+
+	if (fq)
+		atomic_add(bio->bi_vcnt, &fq->nr_submitted);
+}
+
+/* Move all queued nodes out from @fq->prepped list. */
+static void release_prepped_list(flush_queue_t * fq)
+{
+	txn_atom *atom;
+
+	assert("zam-904", fq_in_use(fq));
+	atom = atom_locked_by_fq(fq);
+
+	while (!list_empty(ATOM_FQ_LIST(fq))) {
+		jnode *cur;
+
+		cur = list_entry(ATOM_FQ_LIST(fq)->next, jnode, capture_link);
+		list_del_init(&cur->capture_link);
+
+		count_dequeued_node(fq);
+		spin_lock_jnode(cur);
+		assert("nikita-3154", !JF_ISSET(cur, JNODE_OVRWR));
+		assert("nikita-3154", JF_ISSET(cur, JNODE_RELOC));
+		assert("nikita-3154", JF_ISSET(cur, JNODE_FLUSH_QUEUED));
+		JF_CLR(cur, JNODE_FLUSH_QUEUED);
+
+		if (JF_ISSET(cur, JNODE_DIRTY)) {
+			list_add_tail(&cur->capture_link,
+				      ATOM_DIRTY_LIST(atom, jnode_get_level(cur)));
+			ON_DEBUG(count_jnode(atom, cur, FQ_LIST,
+					     DIRTY_LIST, 1));
+		} else {
+			list_add_tail(&cur->capture_link, ATOM_CLEAN_LIST(atom));
+			ON_DEBUG(count_jnode(atom, cur, FQ_LIST,
+					     CLEAN_LIST, 1));
+		}
+
+		spin_unlock_jnode(cur);
+	}
+
+	if (--atom->nr_running_queues == 0)
+		atom_send_event(atom);
+
+	spin_unlock_atom(atom);
+}
+
+/* Submit write requests for nodes on the already filled flush queue @fq.
+
+   @fq: flush queue object which contains jnodes we can (and will) write.
+   @return: number of submitted blocks (>=0) if success, otherwise -- an error
+            code (<0). */
+int write_fq(flush_queue_t * fq, long *nr_submitted, int flags)
+{
+	int ret;
+	txn_atom *atom;
+
+	while (1) {
+		atom = atom_locked_by_fq(fq);
+		assert("zam-924", atom);
+		/* do not write fq in parallel. */
+		if (atom->nr_running_queues == 0
+		    || !(flags & WRITEOUT_SINGLE_STREAM))
+			break;
+		atom_wait_event(atom);
+	}
+
+	atom->nr_running_queues++;
+	spin_unlock_atom(atom);
+
+	ret = write_jnode_list(ATOM_FQ_LIST(fq), fq, nr_submitted, flags);
+	release_prepped_list(fq);
+
+	return ret;
+}
+
+/* Getting flush queue object for exclusive use by one thread. May require
+   several iterations which is indicated by -E_REPEAT return code.
+
+   This function does not contain code for obtaining an atom lock because an
+   atom lock is obtained by different ways in different parts of reiser4,
+   usually it is current atom, but we need a possibility for getting fq for the
+   atom of given jnode. */
+static int fq_by_atom_gfp(txn_atom *atom, flush_queue_t **new_fq, int gfp)
+{
+	flush_queue_t *fq;
+
+	assert_spin_locked(&(atom->alock));
+
+	fq = list_entry(atom->flush_queues.next, flush_queue_t, alink);
+	while (&atom->flush_queues != &fq->alink) {
+		spin_lock(&(fq->guard));
+
+		if (fq_ready(fq)) {
+			mark_fq_in_use(fq);
+			assert("vs-1246", fq->owner == NULL);
+			ON_DEBUG(fq->owner = current);
+			spin_unlock(&(fq->guard));
+
+			if (*new_fq)
+				done_fq(*new_fq);
+
+			*new_fq = fq;
+
+			return 0;
+		}
+
+		spin_unlock(&(fq->guard));
+
+		fq = list_entry(fq->alink.next, flush_queue_t, alink);
+	}
+
+	/* Use previously allocated fq object */
+	if (*new_fq) {
+		mark_fq_in_use(*new_fq);
+		assert("vs-1248", (*new_fq)->owner == 0);
+		ON_DEBUG((*new_fq)->owner = current);
+		attach_fq(atom, *new_fq);
+
+		return 0;
+	}
+
+	spin_unlock_atom(atom);
+
+	*new_fq = create_fq(gfp);
+
+	if (*new_fq == NULL)
+		return RETERR(-ENOMEM);
+
+	return RETERR(-E_REPEAT);
+}
+
+int fq_by_atom(txn_atom * atom, flush_queue_t ** new_fq)
+{
+	return fq_by_atom_gfp(atom, new_fq, GFP_KERNEL);
+}
+
+/* A wrapper around fq_by_atom for getting a flush queue object for current
+ * atom, if success fq->atom remains locked. */
+flush_queue_t *get_fq_for_current_atom(void)
+{
+	flush_queue_t *fq = NULL;
+	txn_atom *atom;
+	int ret;
+
+	do {
+		atom = get_current_atom_locked();
+		ret = fq_by_atom(atom, &fq);
+	} while (ret == -E_REPEAT);
+
+	if (ret)
+		return ERR_PTR(ret);
+	return fq;
+}
+
+/* Releasing flush queue object after exclusive use */
+void fq_put_nolock(flush_queue_t *fq)
+{
+	assert("zam-747", fq->atom != NULL);
+	assert("zam-902", list_empty_careful(ATOM_FQ_LIST(fq)));
+	mark_fq_ready(fq);
+	assert("vs-1245", fq->owner == current);
+	ON_DEBUG(fq->owner = NULL);
+}
+
+void fq_put(flush_queue_t * fq)
+{
+	txn_atom *atom;
+
+	spin_lock(&(fq->guard));
+	atom = atom_locked_by_fq_nolock(fq);
+
+	assert("zam-746", atom != NULL);
+
+	fq_put_nolock(fq);
+	atom_send_event(atom);
+
+	spin_unlock(&(fq->guard));
+	spin_unlock_atom(atom);
+}
+
+/* A part of atom object initialization related to the embedded flush queue
+   list head */
+
+void init_atom_fq_parts(txn_atom *atom)
+{
+	INIT_LIST_HEAD(&atom->flush_queues);
+}
+
+#ifdef REISER4_USE_EFLUSH
+/* get a flush queue for an atom pointed by given jnode (spin-locked) ; returns
+ * both atom and jnode locked and found and took exclusive access for flush
+ * queue object.  */
+int fq_by_jnode_gfp(jnode * node, flush_queue_t ** fq, int gfp)
+{
+	txn_atom *atom;
+	int ret;
+
+	assert_spin_locked(&(node->guard));
+
+	*fq = NULL;
+
+	while (1) {
+		/* begin with taking lock on atom */
+		atom = jnode_get_atom(node);
+		spin_unlock_jnode(node);
+
+		if (atom == NULL) {
+			/* jnode does not point to the atom anymore, it is
+			 * possible because jnode lock could be removed for a
+			 * time in atom_get_locked_by_jnode() */
+			if (*fq) {
+				done_fq(*fq);
+				*fq = NULL;
+			}
+			return 0;
+		}
+
+		/* atom lock is required for taking flush queue */
+		ret = fq_by_atom_gfp(atom, fq, gfp);
+
+		if (ret) {
+			if (ret == -E_REPEAT)
+				/* atom lock was released for doing memory
+				 * allocation, start with locked jnode one more
+				 * time */
+				goto lock_again;
+			return ret;
+		}
+
+		/* It is correct to lock atom first, then lock a jnode */
+		spin_lock_jnode(node);
+
+		if (node->atom == atom)
+			break;	/* Yes! it is our jnode. We got all of them:
+				 * flush queue, and both locked atom and
+				 * jnode */
+
+		/* release all locks and allocated objects and restart from
+		 * locked jnode. */
+		spin_unlock_jnode(node);
+
+		fq_put(*fq);
+		fq = NULL;
+
+		spin_unlock_atom(atom);
+
+	      lock_again:
+		spin_lock_jnode(node);
+	}
+
+	return 0;
+}
+#endif  /*  REISER4_USE_EFLUSH  */
+
+#if REISER4_DEBUG
+
+void check_fq(const txn_atom *atom)
+{
+	/* check number of nodes on all atom's flush queues */
+	flush_queue_t *fq;
+	int count;
+	struct list_head *pos;
+
+	count = 0;
+	list_for_each_entry(fq, &atom->flush_queues, alink) {
+		spin_lock(&(fq->guard));
+		/* calculate number of jnodes on fq' list of prepped jnodes */
+		list_for_each(pos, ATOM_FQ_LIST(fq))
+			count++;
+		spin_unlock(&(fq->guard));
+	}
+	if (count != atom->fq)
+		warning("", "fq counter %d, real %d\n", atom->fq, count);
+
+}
+
+#endif
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * scroll-step: 1
+ * End:
+ */
diff -urN oldtree/fs/reiser4/forward.h newtree/fs/reiser4/forward.h
--- oldtree/fs/reiser4/forward.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/forward.h	2006-02-21 15:58:34.839850096 +0000
@@ -0,0 +1,259 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Forward declarations. Thank you Kernighan. */
+
+#if !defined( __REISER4_FORWARD_H__ )
+#define __REISER4_FORWARD_H__
+
+#include <asm/errno.h>
+#include <linux/types.h>
+
+typedef struct zlock zlock;
+typedef struct lock_stack lock_stack;
+typedef struct lock_handle lock_handle;
+typedef struct znode znode;
+typedef struct flow flow_t;
+typedef struct coord coord_t;
+typedef struct tree_access_pointer tap_t;
+typedef struct item_coord item_coord;
+typedef struct shift_params shift_params;
+typedef struct reiser4_object_create_data reiser4_object_create_data;
+typedef union reiser4_plugin reiser4_plugin;
+typedef __u16 reiser4_plugin_id;
+typedef struct item_plugin item_plugin;
+typedef struct jnode_plugin jnode_plugin;
+typedef struct reiser4_item_data reiser4_item_data;
+typedef union reiser4_key reiser4_key;
+typedef struct reiser4_tree reiser4_tree;
+typedef struct carry_cut_data carry_cut_data;
+typedef struct carry_kill_data carry_kill_data;
+typedef struct carry_tree_op carry_tree_op;
+typedef struct carry_tree_node carry_tree_node;
+typedef struct carry_plugin_info carry_plugin_info;
+typedef struct reiser4_journal reiser4_journal;
+typedef struct txn_atom txn_atom;
+typedef struct txn_handle txn_handle;
+typedef struct txn_mgr txn_mgr;
+typedef struct reiser4_dir_entry_desc reiser4_dir_entry_desc;
+typedef struct reiser4_context reiser4_context;
+typedef struct carry_level carry_level;
+typedef struct blocknr_set blocknr_set;
+typedef struct blocknr_set_entry blocknr_set_entry;
+/* super_block->s_fs_info points to this */
+typedef struct reiser4_super_info_data reiser4_super_info_data;
+/* next two objects are fields of reiser4_super_info_data */
+typedef struct reiser4_oid_allocator reiser4_oid_allocator;
+typedef struct reiser4_space_allocator reiser4_space_allocator;
+
+typedef struct flush_scan flush_scan;
+typedef struct flush_position flush_pos_t;
+
+typedef unsigned short pos_in_node_t;
+#define MAX_POS_IN_NODE 65535
+
+typedef struct jnode jnode;
+typedef struct reiser4_blocknr_hint reiser4_blocknr_hint;
+
+typedef struct uf_coord uf_coord_t;
+typedef struct hint hint_t;
+
+typedef struct ktxnmgrd_context ktxnmgrd_context;
+
+typedef struct reiser4_xattr_plugin reiser4_xattr_plugin;
+
+struct inode;
+struct page;
+struct file;
+struct dentry;
+struct super_block;
+
+/* return values of coord_by_key(). cbk == coord_by_key */
+typedef enum {
+	CBK_COORD_FOUND = 0,
+	CBK_COORD_NOTFOUND = -ENOENT,
+} lookup_result;
+
+/* results of lookup with directory file */
+typedef enum {
+	FILE_NAME_FOUND = 0,
+	FILE_NAME_NOTFOUND = -ENOENT,
+	FILE_IO_ERROR = -EIO,	/* FIXME: it seems silly to have special OOM, IO_ERROR return codes for each search. */
+	FILE_OOM = -ENOMEM	/* FIXME: it seems silly to have special OOM, IO_ERROR return codes for each search. */
+} file_lookup_result;
+
+/* behaviors of lookup. If coord we are looking for is actually in a tree,
+    both coincide. */
+typedef enum {
+	/* search exactly for the coord with key given */
+	FIND_EXACT,
+	/* search for coord with the maximal key not greater than one
+	   given */
+	FIND_MAX_NOT_MORE_THAN	/*LEFT_SLANT_BIAS */
+} lookup_bias;
+
+typedef enum {
+	/* number of leaf level of the tree
+	   The fake root has (tree_level=0). */
+	LEAF_LEVEL = 1,
+
+	/* number of level one above leaf level of the tree.
+
+	   It is supposed that internal tree used by reiser4 to store file
+	   system data and meta data will have height 2 initially (when
+	   created by mkfs).
+	 */
+	TWIG_LEVEL = 2,
+} tree_level;
+
+/* The "real" maximum ztree height is the 0-origin size of any per-level
+   array, since the zero'th level is not used. */
+#define REAL_MAX_ZTREE_HEIGHT     (REISER4_MAX_ZTREE_HEIGHT-LEAF_LEVEL)
+
+/* enumeration of possible mutual position of item and coord.  This enum is
+    return type of ->is_in_item() item plugin method which see. */
+typedef enum {
+	/* coord is on the left of an item */
+	IP_ON_THE_LEFT,
+	/* coord is inside item */
+	IP_INSIDE,
+	/* coord is inside item, but to the right of the rightmost unit of
+	   this item */
+	IP_RIGHT_EDGE,
+	/* coord is on the right of an item */
+	IP_ON_THE_RIGHT
+} interposition;
+
+/* type of lock to acquire on znode before returning it to caller */
+typedef enum {
+	ZNODE_NO_LOCK = 0,
+	ZNODE_READ_LOCK = 1,
+	ZNODE_WRITE_LOCK = 2,
+} znode_lock_mode;
+
+/* type of lock request */
+typedef enum {
+	ZNODE_LOCK_LOPRI = 0,
+	ZNODE_LOCK_HIPRI = (1 << 0),
+
+	/* By setting the ZNODE_LOCK_NONBLOCK flag in a lock request the call to longterm_lock_znode will not sleep
+	   waiting for the lock to become available.  If the lock is unavailable, reiser4_znode_lock will immediately
+	   return the value -E_REPEAT. */
+	ZNODE_LOCK_NONBLOCK = (1 << 1),
+	/* An option for longterm_lock_znode which prevents atom fusion */
+	ZNODE_LOCK_DONT_FUSE = (1 << 2)
+} znode_lock_request;
+
+typedef enum { READ_OP = 0, WRITE_OP = 1 } rw_op;
+
+/* used to specify direction of shift. These must be -1 and 1 */
+typedef enum {
+	SHIFT_LEFT = 1,
+	SHIFT_RIGHT = -1
+} shift_direction;
+
+typedef enum {
+	LEFT_SIDE,
+	RIGHT_SIDE
+} sideof;
+
+#define round_up( value, order )						\
+	( ( typeof( value ) )( ( ( long ) ( value ) + ( order ) - 1U ) &	\
+			     ~( ( order ) - 1 ) ) )
+
+/* values returned by squalloc_right_neighbor and its auxiliary functions */
+typedef enum {
+	/* unit of internal item is moved */
+	SUBTREE_MOVED = 0,
+	/* nothing else can be squeezed into left neighbor */
+	SQUEEZE_TARGET_FULL = 1,
+	/* all content of node is squeezed into its left neighbor */
+	SQUEEZE_SOURCE_EMPTY = 2,
+	/* one more item is copied (this is only returned by
+	   allocate_and_copy_extent to squalloc_twig)) */
+	SQUEEZE_CONTINUE = 3
+} squeeze_result;
+
+/* Do not change items ids. If you do - there will be format change */
+typedef enum {
+	STATIC_STAT_DATA_ID = 0x0,
+	SIMPLE_DIR_ENTRY_ID = 0x1,
+	COMPOUND_DIR_ID = 0x2,
+	NODE_POINTER_ID = 0x3,
+	EXTENT_POINTER_ID = 0x5,
+	FORMATTING_ID = 0x6,
+	CTAIL_ID = 0x7,
+	BLACK_BOX_ID = 0x8,
+	LAST_ITEM_ID = 0x9
+} item_id;
+
+/* Flags passed to jnode_flush() to allow it to distinguish default settings based on
+   whether commit() was called or VM memory pressure was applied. */
+typedef enum {
+	/* submit flush queue to disk at jnode_flush completion */
+	JNODE_FLUSH_WRITE_BLOCKS = 1,
+
+	/* flush is called for commit */
+	JNODE_FLUSH_COMMIT = 2,
+	/* not implemented */
+	JNODE_FLUSH_MEMORY_FORMATTED = 4,
+
+	/* not implemented */
+	JNODE_FLUSH_MEMORY_UNFORMATTED = 8,
+} jnode_flush_flags;
+
+/* Flags to insert/paste carry operations. Currently they only used in
+   flushing code, but in future, they can be used to optimize for repetitive
+   accesses.  */
+typedef enum {
+	/* carry is not allowed to shift data to the left when trying to find
+	   free space  */
+	COPI_DONT_SHIFT_LEFT = (1 << 0),
+	/* carry is not allowed to shift data to the right when trying to find
+	   free space  */
+	COPI_DONT_SHIFT_RIGHT = (1 << 1),
+	/* carry is not allowed to allocate new node(s) when trying to find
+	   free space */
+	COPI_DONT_ALLOCATE = (1 << 2),
+	/* try to load left neighbor if its not in a cache */
+	COPI_LOAD_LEFT = (1 << 3),
+	/* try to load right neighbor if its not in a cache */
+	COPI_LOAD_RIGHT = (1 << 4),
+	/* shift insertion point to the left neighbor */
+	COPI_GO_LEFT = (1 << 5),
+	/* shift insertion point to the right neighbor */
+	COPI_GO_RIGHT = (1 << 6),
+	/* try to step back into original node if insertion into new node
+	   fails after shifting data there. */
+	COPI_STEP_BACK = (1 << 7)
+} cop_insert_flag;
+
+typedef enum {
+	SAFE_UNLINK,		/* safe-link for unlink */
+	SAFE_TRUNCATE		/* safe-link for truncate */
+} reiser4_safe_link_t;
+
+/* this is to show on which list of atom jnode is */
+typedef enum {
+	NOT_CAPTURED,
+	DIRTY_LIST,
+	CLEAN_LIST,
+	FQ_LIST,
+	WB_LIST,
+	OVRWR_LIST,
+	PROTECT_LIST
+} atom_list;
+
+
+
+/* __REISER4_FORWARD_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/fsdata.c newtree/fs/reiser4/fsdata.c
--- oldtree/fs/reiser4/fsdata.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/fsdata.c	2006-02-21 15:58:35.473753728 +0000
@@ -0,0 +1,803 @@
+/* Copyright 2001, 2002, 2003, 2004, 2005 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+#include "fsdata.h"
+#include "inode.h"
+
+
+/* cache or dir_cursors */
+static kmem_cache_t *d_cursor_cache;
+static struct shrinker *d_cursor_shrinker;
+
+/* list of unused cursors */
+static LIST_HEAD(cursor_cache);
+
+/* number of cursors in list of ununsed cursors */
+static unsigned long d_cursor_unused = 0;
+
+/* spinlock protecting manipulations with dir_cursor's hash table and lists */
+spinlock_t d_lock = SPIN_LOCK_UNLOCKED;
+
+static reiser4_file_fsdata *create_fsdata(struct file *file);
+static int file_is_stateless(struct file *file);
+static void free_fsdata(reiser4_file_fsdata *fsdata);
+static void kill_cursor(dir_cursor *);
+
+/**
+ * d_cursor_shrink - shrink callback for cache of dir_cursor-s
+ * @nr: number of objects to free
+ * @mask: GFP mask
+ *
+ * Shrinks d_cursor_cache. Scan LRU list of unused cursors, freeing requested
+ * number. Return number of still freeable cursors.
+ */
+static int d_cursor_shrink(int nr, unsigned int mask)
+{
+	if (nr != 0) {
+		dir_cursor *scan;
+		int killed;
+
+		killed = 0;
+		spin_lock(&d_lock);
+		while (!list_empty(&cursor_cache)) {
+			scan = list_entry(cursor_cache.next, dir_cursor, alist);
+			assert("nikita-3567", scan->ref == 0);
+			kill_cursor(scan);
+			++killed;
+			--nr;
+			if (nr == 0)
+				break;
+		}
+		spin_unlock(&d_lock);
+	}
+	return d_cursor_unused;
+}
+
+/**
+ * init_d_cursor - create d_cursor cache
+ *
+ * Initializes slab cache of d_cursors. It is part of reiser4 module
+ * initialization.
+ */
+int init_d_cursor(void)
+{
+	d_cursor_cache = kmem_cache_create("d_cursor", sizeof(dir_cursor), 0,
+					   SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (d_cursor_cache == NULL)
+		return RETERR(-ENOMEM);
+
+	/*
+	 * actually, d_cursors are "priceless", because there is no way to
+	 * recover information stored in them. On the other hand, we don't
+	 * want to consume all kernel memory by them. As a compromise, just
+	 * assign higher "seeks" value to d_cursor cache, so that it will be
+	 * shrunk only if system is really tight on memory.
+	 */
+	d_cursor_shrinker = set_shrinker(DEFAULT_SEEKS << 3,
+					 d_cursor_shrink);
+	if (d_cursor_shrinker == NULL) {
+		destroy_reiser4_cache(&d_cursor_cache);
+		d_cursor_cache = NULL;
+		return RETERR(-ENOMEM);
+	}
+	return 0;
+}
+
+/**
+ * done_d_cursor - delete d_cursor cache and d_cursor shrinker
+ *
+ * This is called on reiser4 module unloading or system shutdown.
+ */
+void done_d_cursor(void)
+{
+	BUG_ON(d_cursor_shrinker == NULL);
+	remove_shrinker(d_cursor_shrinker);
+	d_cursor_shrinker = NULL;
+
+	destroy_reiser4_cache(&d_cursor_cache);
+}
+
+#define D_CURSOR_TABLE_SIZE (256)
+
+static inline unsigned long
+d_cursor_hash(d_cursor_hash_table *table, const d_cursor_key *key)
+{
+	assert("nikita-3555", IS_POW(D_CURSOR_TABLE_SIZE));
+	return (key->oid + key->cid) & (D_CURSOR_TABLE_SIZE - 1);
+}
+
+static inline int d_cursor_eq(const d_cursor_key *k1, const d_cursor_key *k2)
+{
+	return k1->cid == k2->cid && k1->oid == k2->oid;
+}
+
+/*
+ * define functions to manipulate reiser4 super block's hash table of
+ * dir_cursors
+ */
+#define KMALLOC(size) kmalloc((size), GFP_KERNEL)
+#define KFREE(ptr, size) kfree(ptr)
+TYPE_SAFE_HASH_DEFINE(d_cursor,
+		      dir_cursor,
+		      d_cursor_key, key, hash, d_cursor_hash, d_cursor_eq);
+#undef KFREE
+#undef KMALLOC
+
+/**
+ * init_super_d_info - initialize per-super-block d_cursor resources
+ * @super: super block to initialize
+ *
+ * Initializes per-super-block d_cursor's hash table and radix tree. It is part
+ * of mount.
+ */
+int init_super_d_info(struct super_block *super)
+{
+	d_cursor_info *p;
+
+	p = &get_super_private(super)->d_info;
+
+	INIT_RADIX_TREE(&p->tree, GFP_KERNEL);
+	return d_cursor_hash_init(&p->table, D_CURSOR_TABLE_SIZE);
+}
+
+/**
+ * done_super_d_info - release per-super-block d_cursor resources
+ * @super: super block being umounted
+ *
+ * It is called on umount. Kills all directory cursors attached to suoer block.
+ */
+void done_super_d_info(struct super_block *super)
+{
+	d_cursor_info *d_info;
+	dir_cursor *cursor, *next;
+
+	d_info = &get_super_private(super)->d_info;
+	for_all_in_htable(&d_info->table, d_cursor, cursor, next)
+		kill_cursor(cursor);
+
+	BUG_ON(d_info->tree.rnode != NULL);
+	d_cursor_hash_done(&d_info->table);
+}
+
+/**
+ * kill_cursor - free dir_cursor and reiser4_file_fsdata attached to it
+ * @cursor: cursor to free
+ *
+ * Removes reiser4_file_fsdata attached to @cursor from readdir list of
+ * reiser4_inode, frees that reiser4_file_fsdata. Removes @cursor from from
+ * indices, hash table, list of unused cursors and frees it.
+ */
+static void kill_cursor(dir_cursor *cursor)
+{
+	unsigned long index;
+
+	assert("nikita-3566", cursor->ref == 0);
+	assert("nikita-3572", cursor->fsdata != NULL);
+
+	index = (unsigned long)cursor->key.oid;
+	list_del_init(&cursor->fsdata->dir.linkage);
+	free_fsdata(cursor->fsdata);
+	cursor->fsdata = NULL;
+
+	if (list_empty_careful(&cursor->list))
+		/* this is last cursor for a file. Kill radix-tree entry */
+		radix_tree_delete(&cursor->info->tree, index);
+	else {
+		void **slot;
+
+		/*
+		 * there are other cursors for the same oid.
+		 */
+
+		/*
+		 * if radix tree point to the cursor being removed, re-target
+		 * radix tree slot to the next cursor in the (non-empty as was
+		 * checked above) element of the circular list of all cursors
+		 * for this oid.
+		 */
+		slot = radix_tree_lookup_slot(&cursor->info->tree, index);
+		assert("nikita-3571", *slot != NULL);
+		if (*slot == cursor)
+			*slot = list_entry(cursor->list.next, dir_cursor, list);
+		/* remove cursor from circular list */
+		list_del_init(&cursor->list);
+	}
+	/* remove cursor from the list of unused cursors */
+	list_del_init(&cursor->alist);
+	/* remove cursor from the hash table */
+	d_cursor_hash_remove(&cursor->info->table, cursor);
+	/* and free it */
+	kmem_cache_free(d_cursor_cache, cursor);
+	--d_cursor_unused;
+}
+
+/* possible actions that can be performed on all cursors for the given file */
+enum cursor_action {
+	/*
+	 * load all detached state: this is called when stat-data is loaded
+	 * from the disk to recover information about all pending readdirs
+	 */
+	CURSOR_LOAD,
+	/*
+	 * detach all state from inode, leaving it in the cache. This is called
+	 * when inode is removed form the memory by memory pressure
+	 */
+	CURSOR_DISPOSE,
+	/*
+	 * detach cursors from the inode, and free them. This is called when
+	 * inode is destroyed
+	 */
+	CURSOR_KILL
+};
+
+/*
+ * return d_cursor data for the file system @inode is in.
+ */
+static inline d_cursor_info *d_info(struct inode *inode)
+{
+	return &get_super_private(inode->i_sb)->d_info;
+}
+
+/*
+ * lookup d_cursor in the per-super-block radix tree.
+ */
+static inline dir_cursor *lookup(d_cursor_info * info, unsigned long index)
+{
+	return (dir_cursor *) radix_tree_lookup(&info->tree, index);
+}
+
+/*
+ * attach @cursor to the radix tree. There may be multiple cursors for the
+ * same oid, they are chained into circular list.
+ */
+static void bind_cursor(dir_cursor * cursor, unsigned long index)
+{
+	dir_cursor *head;
+
+	head = lookup(cursor->info, index);
+	if (head == NULL) {
+		/* this is the first cursor for this index */
+		INIT_LIST_HEAD(&cursor->list);
+		radix_tree_insert(&cursor->info->tree, index, cursor);
+	} else {
+		/* some cursor already exists. Chain ours */
+		list_add(&cursor->list, &head->list);
+	}
+}
+
+/*
+ * detach fsdata (if detachable) from file descriptor, and put cursor on the
+ * "unused" list. Called when file descriptor is not longer in active use.
+ */
+static void clean_fsdata(struct file *file)
+{
+	dir_cursor *cursor;
+	reiser4_file_fsdata *fsdata;
+
+	assert("nikita-3570", file_is_stateless(file));
+
+	fsdata = (reiser4_file_fsdata *) file->private_data;
+	if (fsdata != NULL) {
+		cursor = fsdata->cursor;
+		if (cursor != NULL) {
+			spin_lock(&d_lock);
+			--cursor->ref;
+			if (cursor->ref == 0) {
+				list_add_tail(&cursor->alist, &cursor_cache);
+				++d_cursor_unused;
+			}
+			spin_unlock(&d_lock);
+			file->private_data = NULL;
+		}
+	}
+}
+
+/*
+ * global counter used to generate "client ids". These ids are encoded into
+ * high bits of fpos.
+ */
+static __u32 cid_counter = 0;
+#define CID_SHIFT (20)
+#define CID_MASK  (0xfffffull)
+
+static void free_file_fsdata_nolock(struct file *);
+
+/**
+ * insert_cursor - allocate file_fsdata, insert cursor to tree and hash table
+ * @cursor:
+ * @file:
+ * @inode:
+ *
+ * Allocates reiser4_file_fsdata, attaches it to @cursor, inserts cursor to
+ * reiser4 super block's hash table and radix tree.
+ add detachable readdir
+ * state to the @f
+ */
+static int insert_cursor(dir_cursor *cursor, struct file *file,
+			 struct inode *inode)
+{
+	int result;
+	reiser4_file_fsdata *fsdata;
+
+	memset(cursor, 0, sizeof *cursor);
+
+	/* this is either first call to readdir, or rewind. Anyway, create new
+	 * cursor. */
+	fsdata = create_fsdata(NULL);
+	if (fsdata != NULL) {
+		result = radix_tree_preload(GFP_KERNEL);
+		if (result == 0) {
+			d_cursor_info *info;
+			oid_t oid;
+
+			info = d_info(inode);
+			oid = get_inode_oid(inode);
+			/* cid occupies higher 12 bits of f->f_pos. Don't
+			 * allow it to become negative: this confuses
+			 * nfsd_readdir() */
+			cursor->key.cid = (++cid_counter) & 0x7ff;
+			cursor->key.oid = oid;
+			cursor->fsdata = fsdata;
+			cursor->info = info;
+			cursor->ref = 1;
+
+			spin_lock_inode(inode);
+			/* install cursor as @f's private_data, discarding old
+			 * one if necessary */
+#if REISER4_DEBUG
+			if (file->private_data)
+				warning("", "file has fsdata already");
+#endif
+			clean_fsdata(file);
+			free_file_fsdata_nolock(file);
+			file->private_data = fsdata;
+			fsdata->cursor = cursor;
+			spin_unlock_inode(inode);
+			spin_lock(&d_lock);
+			/* insert cursor into hash table */
+			d_cursor_hash_insert(&info->table, cursor);
+			/* and chain it into radix-tree */
+			bind_cursor(cursor, (unsigned long)oid);
+			spin_unlock(&d_lock);
+			radix_tree_preload_end();
+			file->f_pos = ((__u64) cursor->key.cid) << CID_SHIFT;
+		}
+	} else
+		result = RETERR(-ENOMEM);
+	return result;
+}
+
+/**
+ * process_cursors - do action on each cursor attached to inode
+ * @inode:
+ * @act: action to do
+ *
+ * Finds all cursors of @inode in reiser4's super block radix tree of cursors
+ * and performs action specified by @act on each of cursors.
+ */
+static void process_cursors(struct inode *inode, enum cursor_action act)
+{
+	oid_t oid;
+	dir_cursor *start;
+	struct list_head *head;
+	reiser4_context *ctx;
+	d_cursor_info *info;
+
+	/* this can be called by
+	 *
+	 * kswapd->...->prune_icache->..reiser4_destroy_inode
+	 *
+	 * without reiser4_context
+	 */
+	ctx = init_context(inode->i_sb);
+	if (IS_ERR(ctx)) {
+		warning("vs-23", "failed to init context");
+		return;
+	}
+
+	assert("nikita-3558", inode != NULL);
+
+	info = d_info(inode);
+	oid = get_inode_oid(inode);
+	spin_lock_inode(inode);
+	head = get_readdir_list(inode);
+	spin_lock(&d_lock);
+	/* find any cursor for this oid: reference to it is hanging of radix
+	 * tree */
+	start = lookup(info, (unsigned long)oid);
+	if (start != NULL) {
+		dir_cursor *scan;
+		reiser4_file_fsdata *fsdata;
+
+		/* process circular list of cursors for this oid */
+		scan = start;
+		do {
+			dir_cursor *next;
+
+			next = list_entry(scan->list.next, dir_cursor, list);
+			fsdata = scan->fsdata;
+			assert("nikita-3557", fsdata != NULL);
+			if (scan->key.oid == oid) {
+				switch (act) {
+				case CURSOR_DISPOSE:
+					list_del_init(&fsdata->dir.linkage);
+					break;
+				case CURSOR_LOAD:
+					list_add(&fsdata->dir.linkage, head);
+					break;
+				case CURSOR_KILL:
+					kill_cursor(scan);
+					break;
+				}
+			}
+			if (scan == next)
+				/* last cursor was just killed */
+				break;
+			scan = next;
+		} while (scan != start);
+	}
+	spin_unlock(&d_lock);
+	/* check that we killed 'em all */
+	assert("nikita-3568",
+	       ergo(act == CURSOR_KILL,
+		    list_empty_careful(get_readdir_list(inode))));
+	assert("nikita-3569",
+	       ergo(act == CURSOR_KILL, lookup(info, oid) == NULL));
+	spin_unlock_inode(inode);
+	reiser4_exit_context(ctx);
+}
+
+/**
+ * dispose_cursors - removes cursors from inode's list
+ * @inode: inode to dispose cursors of
+ *
+ * For each of cursors corresponding to @inode - removes reiser4_file_fsdata
+ * attached to cursor from inode's readdir list. This is called when inode is
+ * removed from the memory by memory pressure.
+ */
+void dispose_cursors(struct inode *inode)
+{
+	process_cursors(inode, CURSOR_DISPOSE);
+}
+
+/**
+ * load_cursors - attach cursors to inode
+ * @inode: inode to load cursors to
+ *
+ * For each of cursors corresponding to @inode - attaches reiser4_file_fsdata
+ * attached to cursor to inode's readdir list. This is done when inode is
+ * loaded into memory.
+ */
+void load_cursors(struct inode *inode)
+{
+	process_cursors(inode, CURSOR_LOAD);
+}
+
+/**
+ * kill_cursors - kill all inode cursors
+ * @inode: inode to kill cursors of
+ *
+ * Frees all cursors for this inode. This is called when inode is destroyed.
+ */
+void kill_cursors(struct inode *inode)
+{
+	process_cursors(inode, CURSOR_KILL);
+}
+
+/**
+ * file_is_stateless -
+ * @file:
+ *
+ * true, if file descriptor @f is created by NFS server by "demand" to serve
+ * one file system operation. This means that there may be "detached state"
+ * for underlying inode.
+ */
+static int file_is_stateless(struct file *file)
+{
+	return reiser4_get_dentry_fsdata(file->f_dentry)->stateless;
+}
+
+/**
+ * get_dir_fpos -
+ * @dir:
+ *
+ * Calculates ->fpos from user-supplied cookie. Normally it is dir->f_pos, but
+ * in the case of stateless directory operation (readdir-over-nfs), client id
+ * was encoded in the high bits of cookie and should me masked off.
+ */
+loff_t get_dir_fpos(struct file *dir)
+{
+	if (file_is_stateless(dir))
+		return dir->f_pos & CID_MASK;
+	else
+		return dir->f_pos;
+}
+
+/**
+ * try_to_attach_fsdata - ???
+ * @file:
+ * @inode:
+ *
+ * Finds or creates cursor for readdir-over-nfs.
+ */
+int try_to_attach_fsdata(struct file *file, struct inode *inode)
+{
+	loff_t pos;
+	int result;
+	dir_cursor *cursor;
+
+	/*
+	 * we are serialized by inode->i_mutex
+	 */
+	if (!file_is_stateless(file))
+		return 0;
+
+	pos = file->f_pos;
+	result = 0;
+	if (pos == 0) {
+		/*
+		 * first call to readdir (or rewind to the beginning of
+		 * directory)
+		 */
+		cursor = kmem_cache_alloc(d_cursor_cache, GFP_KERNEL);
+		if (cursor != NULL)
+			result = insert_cursor(cursor, file, inode);
+		else
+			result = RETERR(-ENOMEM);
+	} else {
+		/* try to find existing cursor */
+		d_cursor_key key;
+
+		key.cid = pos >> CID_SHIFT;
+		key.oid = get_inode_oid(inode);
+		spin_lock(&d_lock);
+		cursor = d_cursor_hash_find(&d_info(inode)->table, &key);
+		if (cursor != NULL) {
+			/* cursor was found */
+			if (cursor->ref == 0) {
+				/* move it from unused list */
+				list_del_init(&cursor->alist);
+				--d_cursor_unused;
+			}
+			++cursor->ref;
+		}
+		spin_unlock(&d_lock);
+		if (cursor != NULL) {
+			spin_lock_inode(inode);
+			assert("nikita-3556", cursor->fsdata->back == NULL);
+			clean_fsdata(file);
+			free_file_fsdata_nolock(file);
+			file->private_data = cursor->fsdata;
+			spin_unlock_inode(inode);
+		}
+	}
+	return result;
+}
+
+/**
+ * detach_fsdata - ???
+ * @file:
+ *
+ * detach fsdata, if necessary
+ */
+void detach_fsdata(struct file *file)
+{
+	struct inode *inode;
+
+	if (!file_is_stateless(file))
+		return;
+
+	inode = file->f_dentry->d_inode;
+	spin_lock_inode(inode);
+	clean_fsdata(file);
+	spin_unlock_inode(inode);
+}
+
+/* slab for reiser4_dentry_fsdata */
+static kmem_cache_t *dentry_fsdata_cache;
+
+/**
+ * init_dentry_fsdata - create cache of dentry_fsdata
+ *
+ * Initializes slab cache of structures attached to denty->d_fsdata. It is
+ * part of reiser4 module initialization.
+ */
+int init_dentry_fsdata(void)
+{
+	dentry_fsdata_cache = kmem_cache_create("dentry_fsdata",
+						sizeof(reiser4_dentry_fsdata),
+						0,
+						SLAB_HWCACHE_ALIGN |
+						SLAB_RECLAIM_ACCOUNT, NULL,
+						NULL);
+	if (dentry_fsdata_cache == NULL)
+		return RETERR(-ENOMEM);
+	return 0;
+}
+
+/**
+ * done_dentry_fsdata - delete cache of dentry_fsdata
+ *
+ * This is called on reiser4 module unloading or system shutdown.
+ */
+void done_dentry_fsdata(void)
+{
+	destroy_reiser4_cache(&dentry_fsdata_cache);
+}
+
+/**
+ * reiser4_get_dentry_fsdata - get fs-specific dentry data
+ * @dentry: queried dentry
+ *
+ * Allocates if necessary and returns per-dentry data that we attach to each
+ * dentry.
+ */
+reiser4_dentry_fsdata *reiser4_get_dentry_fsdata(struct dentry *dentry)
+{
+	assert("nikita-1365", dentry != NULL);
+
+	if (dentry->d_fsdata == NULL) {
+		dentry->d_fsdata = kmem_cache_alloc(dentry_fsdata_cache,
+						    GFP_KERNEL);
+		if (dentry->d_fsdata == NULL)
+			return ERR_PTR(RETERR(-ENOMEM));
+		memset(dentry->d_fsdata, 0, sizeof(reiser4_dentry_fsdata));
+	}
+	return dentry->d_fsdata;
+}
+
+/**
+ * reiser4_free_dentry_fsdata - detach and free dentry_fsdata
+ * @dentry: dentry to free fsdata of
+ *
+ * Detaches and frees fs-specific dentry data
+ */
+void reiser4_free_dentry_fsdata(struct dentry *dentry)
+{
+	if (dentry->d_fsdata != NULL) {
+		kmem_cache_free(dentry_fsdata_cache, dentry->d_fsdata);
+		dentry->d_fsdata = NULL;
+	}
+}
+
+
+/* slab for reiser4_file_fsdata */
+static kmem_cache_t *file_fsdata_cache;
+
+/**
+ * init_file_fsdata - create cache of reiser4_file_fsdata
+ *
+ * Initializes slab cache of structures attached to file->private_data. It is
+ * part of reiser4 module initialization.
+ */
+int init_file_fsdata(void)
+{
+	file_fsdata_cache = kmem_cache_create("file_fsdata",
+					      sizeof(reiser4_file_fsdata),
+					      0,
+					      SLAB_HWCACHE_ALIGN |
+					      SLAB_RECLAIM_ACCOUNT, NULL, NULL);
+	if (file_fsdata_cache == NULL)
+		return RETERR(-ENOMEM);
+	return 0;
+}
+
+/**
+ * done_file_fsdata - delete cache of reiser4_file_fsdata
+ *
+ * This is called on reiser4 module unloading or system shutdown.
+ */
+void done_file_fsdata(void)
+{
+	destroy_reiser4_cache(&file_fsdata_cache);
+}
+
+/**
+ * create_fsdata - allocate and initialize reiser4_file_fsdata
+ * @file: what to create file_fsdata for, may be NULL
+ *
+ * Allocates and initializes reiser4_file_fsdata structure.
+ */
+static reiser4_file_fsdata *create_fsdata(struct file *file)
+{
+	reiser4_file_fsdata *fsdata;
+
+	fsdata = kmem_cache_alloc(file_fsdata_cache, GFP_KERNEL);
+	if (fsdata != NULL) {
+		memset(fsdata, 0, sizeof *fsdata);
+		fsdata->ra1.max_window_size = VM_MAX_READAHEAD * 1024;
+		fsdata->back = file;
+		INIT_LIST_HEAD(&fsdata->dir.linkage);
+	}
+	return fsdata;
+}
+
+/**
+ * free_fsdata - free reiser4_file_fsdata
+ * @fsdata: object to free
+ *
+ * Dual to create_fsdata(). Free reiser4_file_fsdata.
+ */
+static void free_fsdata(reiser4_file_fsdata *fsdata)
+{
+	BUG_ON(fsdata == NULL);
+	kmem_cache_free(file_fsdata_cache, fsdata);
+}
+
+/**
+ * reiser4_get_file_fsdata - get fs-specific file data
+ * @file: queried file
+ *
+ * Returns fs-specific data of @file. If it is NULL, allocates it and attaches
+ * to @file.
+ */
+reiser4_file_fsdata *reiser4_get_file_fsdata(struct file *file)
+{
+	assert("nikita-1603", file != NULL);
+
+	if (file->private_data == NULL) {
+		reiser4_file_fsdata *fsdata;
+		struct inode *inode;
+
+		fsdata = create_fsdata(file);
+		if (fsdata == NULL)
+			return ERR_PTR(RETERR(-ENOMEM));
+
+		inode = file->f_dentry->d_inode;
+		spin_lock_inode(inode);
+		if (file->private_data == NULL) {
+			file->private_data = fsdata;
+			fsdata = NULL;
+		}
+		spin_unlock_inode(inode);
+		if (fsdata != NULL)
+			/* other thread initialized ->fsdata */
+			kmem_cache_free(file_fsdata_cache, fsdata);
+	}
+	assert("nikita-2665", file->private_data != NULL);
+	return file->private_data;
+}
+
+/**
+ * free_file_fsdata_nolock - detach and free reiser4_file_fsdata
+ * @file:
+ *
+ * Detaches reiser4_file_fsdata from @file, removes reiser4_file_fsdata from
+ * readdir list, frees if it is not linked to d_cursor object.
+ */
+static void free_file_fsdata_nolock(struct file *file)
+{
+	reiser4_file_fsdata *fsdata;
+
+	assert("", spin_inode_is_locked(file->f_dentry->d_inode));
+	fsdata = file->private_data;
+	if (fsdata != NULL) {
+		list_del_init(&fsdata->dir.linkage);
+		if (fsdata->cursor == NULL)
+			free_fsdata(fsdata);
+	}
+	file->private_data = NULL;
+}
+
+/**
+ * reiser4_free_file_fsdata - detach from struct file and free reiser4_file_fsdata
+ * @file:
+ *
+ * Spinlocks inode and calls free_file_fsdata_nolock to do the work.
+ */
+void reiser4_free_file_fsdata(struct file *file)
+{
+	spin_lock_inode(file->f_dentry->d_inode);
+	free_file_fsdata_nolock(file);
+	spin_unlock_inode(file->f_dentry->d_inode);
+}
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * End:
+ */
diff -urN oldtree/fs/reiser4/fsdata.h newtree/fs/reiser4/fsdata.h
--- oldtree/fs/reiser4/fsdata.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/fsdata.h	2006-02-21 15:58:35.473753728 +0000
@@ -0,0 +1,218 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+#if !defined( __REISER4_FSDATA_H__ )
+#define __REISER4_FSDATA_H__
+
+#include "debug.h"
+#include "kassign.h"
+#include "seal.h"
+#include "type_safe_hash.h"
+#include "plugin/file/file.h"
+#include "readahead.h"
+
+/*
+ * comment about reiser4_dentry_fsdata
+ *
+ *
+ */
+
+/*
+ * locking: fields of per file descriptor readdir_pos and ->f_pos are
+ * protected by ->i_mutex on inode. Under this lock following invariant
+ * holds:
+ *
+ *     file descriptor is "looking" at the entry_no-th directory entry from
+ *     the beginning of directory. This entry has key dir_entry_key and is
+ *     pos-th entry with duplicate-key sequence.
+ *
+ */
+
+/* logical position within directory */
+typedef struct {
+	/* key of directory entry (actually, part of a key sufficient to
+	   identify directory entry)  */
+	de_id dir_entry_key;
+	/* ordinal number of directory entry among all entries with the same
+	   key. (Starting from 0.) */
+	unsigned pos;
+} dir_pos;
+
+typedef struct {
+	/* f_pos corresponding to this readdir position */
+	__u64 fpos;
+	/* logical position within directory */
+	dir_pos position;
+	/* logical number of directory entry within
+	   directory  */
+	__u64 entry_no;
+} readdir_pos;
+
+/*
+ * this is used to speed up lookups for directory entry: on initial call to
+ * ->lookup() seal and coord of directory entry (if found, that is) are stored
+ * in struct dentry and reused later to avoid tree traversals.
+ */
+typedef struct de_location {
+	/* seal covering directory entry */
+	seal_t entry_seal;
+	/* coord of directory entry */
+	coord_t entry_coord;
+	/* ordinal number of directory entry among all entries with the same
+	   key. (Starting from 0.) */
+	int pos;
+} de_location;
+
+/**
+ * reiser4_dentry_fsdata - reiser4-specific data attached to dentries
+ *
+ * This is allocated dynamically and released in d_op->d_release()
+ *
+ * Currently it only contains cached location (hint) of directory entry, but
+ * it is expected that other information will be accumulated here.
+ */
+typedef struct reiser4_dentry_fsdata {
+	/*
+	 * here will go fields filled by ->lookup() to speedup next
+	 * create/unlink, like blocknr of znode with stat-data, or key of
+	 * stat-data.
+	 */
+	de_location dec;
+	int stateless;		/* created through reiser4_decode_fh, needs special
+				 * treatment in readdir. */
+} reiser4_dentry_fsdata;
+
+extern int init_dentry_fsdata(void);
+extern void done_dentry_fsdata(void);
+extern reiser4_dentry_fsdata *reiser4_get_dentry_fsdata(struct dentry *);
+extern void reiser4_free_dentry_fsdata(struct dentry *dentry);
+
+
+/**
+ * reiser4_file_fsdata - reiser4-specific data attached to file->private_data
+ *
+ * This is allocated dynamically and released in inode->i_fop->release
+ */
+typedef struct reiser4_file_fsdata {
+	/*
+	 * pointer back to the struct file which this reiser4_file_fsdata is
+	 * part of
+	 */
+	struct file *back;
+	/* detached cursor for stateless readdir. */
+	struct dir_cursor *cursor;
+	/*
+	 * We need both directory and regular file parts here, because there
+	 * are file system objects that are files and directories.
+	 */
+	struct {
+		/*
+		 * position in directory. It is updated each time directory is
+		 * modified
+		 */
+		readdir_pos readdir;
+		/* head of this list is reiser4_inode->lists.readdir_list */
+		struct list_head linkage;
+	} dir;
+	/* hints to speed up operations with regular files: read and write. */
+	struct {
+		hint_t hint;
+	} reg;
+	/* */
+	struct {
+		/* this is called by reiser4_readpages if set */
+		void (*readpages) (struct address_space *,
+				   struct list_head * pages, void *data);
+		/* reiser4_readpaextended coord. It is set by read_extent before
+		   calling page_cache_readahead */
+		void *data;
+	} ra2;
+	struct reiser4_file_ra_state ra1;
+
+} reiser4_file_fsdata;
+
+extern int init_file_fsdata(void);
+extern void done_file_fsdata(void);
+extern reiser4_file_fsdata *reiser4_get_file_fsdata(struct file *);
+extern void reiser4_free_file_fsdata(struct file *);
+
+
+/*
+ * d_cursor is reiser4_file_fsdata not attached to struct file. d_cursors are
+ * used to address problem reiser4 has with readdir accesses via NFS. See
+ * plugin/file_ops_readdir.c for more details.
+ */
+typedef struct {
+	__u16 cid;
+	__u64 oid;
+} d_cursor_key;
+
+/*
+ * define structures d_cursor_hash_table d_cursor_hash_link which are used to
+ * maintain hash table of dir_cursor-s in reiser4's super block
+ */
+typedef struct dir_cursor dir_cursor;
+TYPE_SAFE_HASH_DECLARE(d_cursor, dir_cursor);
+
+typedef struct d_cursor_info d_cursor_info;
+
+struct dir_cursor {
+	int ref;
+	reiser4_file_fsdata *fsdata;
+
+	/* link to reiser4 super block hash table of cursors */
+	d_cursor_hash_link hash;
+
+	/*
+	 * this is to link cursors to reiser4 super block's radix tree of
+	 * cursors if there are more than one cursor of the same objectid
+	 */
+	struct list_head list;
+	d_cursor_key key;
+	d_cursor_info *info;
+	/* list of unused cursors */
+	struct list_head alist;
+};
+
+extern int init_d_cursor(void);
+extern void done_d_cursor(void);
+
+extern int init_super_d_info(struct super_block *);
+extern void done_super_d_info(struct super_block *);
+
+extern loff_t get_dir_fpos(struct file *);
+extern int try_to_attach_fsdata(struct file *, struct inode *);
+extern void detach_fsdata(struct file *);
+
+
+/* these are needed for "stateless" readdir. See plugin/file_ops_readdir.c for
+   more details */
+void dispose_cursors(struct inode *inode);
+void load_cursors(struct inode *inode);
+void kill_cursors(struct inode *inode);
+void adjust_dir_file(struct inode *dir, const struct dentry *de, int offset, int adj);
+
+/*
+ * this structure is embedded to reise4_super_info_data. It maintains d_cursors
+ * (detached readdir state). See plugin/file_ops_readdir.c for more details.
+ */
+struct d_cursor_info {
+	d_cursor_hash_table table;
+	struct radix_tree_root tree;
+};
+
+/* spinlock protecting readdir cursors */
+extern spinlock_t d_lock;
+
+/* __REISER4_FSDATA_H__ */
+#endif
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 120
+ * End:
+ */
diff -urN oldtree/fs/reiser4/init_super.c newtree/fs/reiser4/init_super.c
--- oldtree/fs/reiser4/init_super.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/init_super.c	2006-02-21 15:58:35.434759656 +0000
@@ -0,0 +1,760 @@
+/* Copyright by Hans Reiser, 2003 */
+
+#include "super.h"
+#include "inode.h"
+#include "plugin/plugin_set.h"
+
+#include <linux/swap.h>
+
+
+/**
+ * init_fs_info - allocate reiser4 specific super block
+ * @super: super block of filesystem
+ *
+ * Allocates and initialize reiser4_super_info_data, attaches it to
+ * super->s_fs_info, initializes structures maintaining d_cursor-s.
+ */
+int init_fs_info(struct super_block *super)
+{
+	reiser4_super_info_data *sbinfo;
+
+	sbinfo = kmalloc(sizeof(reiser4_super_info_data), GFP_KERNEL);
+	if (!sbinfo)
+		return RETERR(-ENOMEM);
+
+	super->s_fs_info = sbinfo;
+	super->s_op = NULL;
+	memset(sbinfo, 0, sizeof(*sbinfo));
+
+	ON_DEBUG(INIT_LIST_HEAD(&sbinfo->all_jnodes));
+	ON_DEBUG(spin_lock_init(&sbinfo->all_guard));
+
+	sema_init(&sbinfo->delete_sema, 1);
+	sema_init(&sbinfo->flush_sema, 1);
+	spin_lock_init(&(sbinfo->guard));
+#if REISER4_USE_EFLUSH
+	spin_lock_init(&(sbinfo->eflush_guard));
+#endif
+	/*  initialize per-super-block d_cursor resources */
+	init_super_d_info(super);
+
+	return 0;
+}
+
+/**
+ * done_fs_info - free reiser4 specific super block
+ * @super: super block of filesystem
+ *
+ * Performs some sanity checks, releases structures maintaining d_cursor-s,
+ * frees reiser4_super_info_data.
+ */
+void done_fs_info(struct super_block *super)
+{
+	assert("zam-990", super->s_fs_info != NULL);
+
+	/* release per-super-block d_cursor resources */
+	done_super_d_info(super);
+
+	/* make sure that there are not jnodes already */
+	assert("", list_empty(&get_super_private(super)->all_jnodes));
+	assert("", get_current_context()->trans->atom == NULL);
+	check_block_counters(super);
+	kfree(super->s_fs_info);
+	super->s_fs_info = NULL;
+}
+
+/* type of option parseable by parse_option() */
+typedef enum {
+	/* value of option is arbitrary string */
+	OPT_STRING,
+
+	/*
+	 * option specifies bit in a bitmask. When option is set - bit in
+	 * sbinfo->fs_flags is set. Examples are bsdgroups, 32bittimes, mtflush,
+	 * dont_load_bitmap, atomic_write.
+	 */
+	OPT_BIT,
+
+	/*
+	 * value of option should conform to sprintf() format. Examples are
+	 * tmgr.atom_max_size=N, tmgr.atom_max_age=N
+	 */
+	OPT_FORMAT,
+
+	/*
+	 * option can take one of predefined values. Example is onerror=panic or
+	 * onerror=remount-ro
+	 */
+	OPT_ONEOF,
+} opt_type_t;
+
+typedef struct opt_bitmask_bit {
+	const char *bit_name;
+	int bit_nr;
+} opt_bitmask_bit;
+
+/* description of option parseable by parse_option() */
+typedef struct opt_desc {
+	/* option name.
+
+	   parsed portion of string has a form "name=value".
+	 */
+	const char *name;
+	/* type of option */
+	opt_type_t type;
+	union {
+		/* where to store value of string option (type == OPT_STRING) */
+		char **string;
+		/* description of bits for bit option (type == OPT_BIT) */
+		struct {
+			int nr;
+			void *addr;
+		} bit;
+		/* description of format and targets for format option (type
+		   == OPT_FORMAT) */
+		struct {
+			const char *format;
+			int nr_args;
+			void *arg1;
+			void *arg2;
+			void *arg3;
+			void *arg4;
+		} f;
+		struct {
+			int *result;
+			const char *list[10];
+		} oneof;
+		struct {
+			void *addr;
+			int nr_bits;
+			opt_bitmask_bit *bits;
+		} bitmask;
+	} u;
+} opt_desc_t;
+
+/**
+ * parse_option - parse one option
+ * @opt_strin: starting point of parsing
+ * @opt: option description
+ *
+ * foo=bar,
+ * ^   ^  ^
+ * |   |  +-- replaced to '\0'
+ * |   +-- val_start
+ * +-- opt_string
+ * Figures out option type and handles option correspondingly.
+ */
+static int parse_option(char *opt_string, opt_desc_t *opt)
+{
+	char *val_start;
+	int result;
+	const char *err_msg;
+
+	/* NOTE-NIKITA think about using lib/cmdline.c functions here. */
+
+	val_start = strchr(opt_string, '=');
+	if (val_start != NULL) {
+		*val_start = '\0';
+		++val_start;
+	}
+
+	err_msg = NULL;
+	result = 0;
+	switch (opt->type) {
+	case OPT_STRING:
+		if (val_start == NULL) {
+			err_msg = "String arg missing";
+			result = RETERR(-EINVAL);
+		} else
+			*opt->u.string = val_start;
+		break;
+	case OPT_BIT:
+		if (val_start != NULL)
+			err_msg = "Value ignored";
+		else
+			set_bit(opt->u.bit.nr, opt->u.bit.addr);
+		break;
+	case OPT_FORMAT:
+		if (val_start == NULL) {
+			err_msg = "Formatted arg missing";
+			result = RETERR(-EINVAL);
+			break;
+		}
+		if (sscanf(val_start, opt->u.f.format,
+			   opt->u.f.arg1, opt->u.f.arg2, opt->u.f.arg3,
+			   opt->u.f.arg4) != opt->u.f.nr_args) {
+			err_msg = "Wrong conversion";
+			result = RETERR(-EINVAL);
+		}
+		break;
+	case OPT_ONEOF:
+		{
+			int i = 0;
+
+			if (val_start == NULL) {
+				err_msg = "Value is missing";
+				result = RETERR(-EINVAL);
+				break;
+			}
+			err_msg = "Wrong option value";
+			result = RETERR(-EINVAL);
+			while (opt->u.oneof.list[i]) {
+				if (!strcmp(opt->u.oneof.list[i], val_start)) {
+					result = 0;
+					err_msg = NULL;
+					*opt->u.oneof.result = i;
+					break;
+				}
+				i++;
+			}
+			break;
+		}
+	default:
+		wrong_return_value("nikita-2100", "opt -> type");
+		break;
+	}
+	if (err_msg != NULL) {
+		warning("nikita-2496", "%s when parsing option \"%s%s%s\"",
+			err_msg, opt->name, val_start ? "=" : "",
+			val_start ? : "");
+	}
+	return result;
+}
+
+/**
+ * parse_options - parse reiser4 mount options
+ * @opt_string: starting point
+ * @opts: array of option description
+ * @nr_opts: number of elements in @opts
+ *
+ * Parses comma separated list of reiser4 mount options.
+ */
+static int parse_options(char *opt_string, opt_desc_t *opts, int nr_opts)
+{
+	int result;
+
+	result = 0;
+	while ((result == 0) && opt_string && *opt_string) {
+		int j;
+		char *next;
+
+		next = strchr(opt_string, ',');
+		if (next != NULL) {
+			*next = '\0';
+			++next;
+		}
+		for (j = 0; j < nr_opts; ++j) {
+			if (!strncmp(opt_string, opts[j].name,
+				     strlen(opts[j].name))) {
+				result = parse_option(opt_string, &opts[j]);
+				break;
+			}
+		}
+		if (j == nr_opts) {
+			warning("nikita-2307", "Unrecognized option: \"%s\"",
+				opt_string);
+			/* traditionally, -EINVAL is returned on wrong mount
+			   option */
+			result = RETERR(-EINVAL);
+		}
+		opt_string = next;
+	}
+	return result;
+}
+
+#define NUM_OPT( label, fmt, addr )				\
+		{						\
+			.name = ( label ),			\
+			.type = OPT_FORMAT,			\
+			.u = {					\
+				.f = {				\
+					.format  = ( fmt ),	\
+					.nr_args = 1,		\
+					.arg1 = ( addr ),	\
+					.arg2 = NULL,		\
+					.arg3 = NULL,		\
+					.arg4 = NULL		\
+				}				\
+			}					\
+		}
+
+#define SB_FIELD_OPT( field, fmt ) NUM_OPT( #field, fmt, &sbinfo -> field )
+
+#define BIT_OPT(label, bitnr)					\
+	{							\
+		.name = label,					\
+		.type = OPT_BIT,				\
+		.u = {						\
+			.bit = {				\
+				.nr = bitnr,			\
+				.addr = &sbinfo->fs_flags	\
+			}					\
+		}						\
+	}
+
+#define MAX_NR_OPTIONS (30)
+
+/**
+ * init_super_data - initialize reiser4 private super block
+ * @super: super block to initialize
+ * @opt_string: list of reiser4 mount options
+ *
+ * Sets various reiser4 parameters to default values. Parses mount options and
+ * overwrites default settings.
+ */
+int init_super_data(struct super_block *super, char *opt_string)
+{
+	int result;
+	opt_desc_t *opts, *p;
+	reiser4_super_info_data *sbinfo = get_super_private(super);
+
+	/* initialize super, export, dentry operations */
+	sbinfo->ops.super = reiser4_super_operations;
+	sbinfo->ops.export = reiser4_export_operations;
+	sbinfo->ops.dentry = reiser4_dentry_operations;
+	super->s_op = &sbinfo->ops.super;
+	super->s_export_op = &sbinfo->ops.export;
+
+	/* initialize transaction manager parameters to default values */
+	sbinfo->tmgr.atom_max_size = totalram_pages / 4;
+	sbinfo->tmgr.atom_max_age = REISER4_ATOM_MAX_AGE / HZ;
+	sbinfo->tmgr.atom_min_size = 256;
+	sbinfo->tmgr.atom_max_flushers = ATOM_MAX_FLUSHERS;
+
+	/* initialize cbk cache parameter */
+	sbinfo->tree.cbk_cache.nr_slots = CBK_CACHE_SLOTS;
+
+	/* initialize flush parameters */
+	sbinfo->flush.relocate_threshold = FLUSH_RELOCATE_THRESHOLD;
+	sbinfo->flush.relocate_distance = FLUSH_RELOCATE_DISTANCE;
+	sbinfo->flush.written_threshold = FLUSH_WRITTEN_THRESHOLD;
+	sbinfo->flush.scan_maxnodes = FLUSH_SCAN_MAXNODES;
+
+	sbinfo->optimal_io_size = REISER4_OPTIMAL_IO_SIZE;
+
+	/* preliminary tree initializations */
+	sbinfo->tree.super = super;
+	sbinfo->tree.carry.new_node_flags = REISER4_NEW_NODE_FLAGS;
+	sbinfo->tree.carry.new_extent_flags = REISER4_NEW_EXTENT_FLAGS;
+	sbinfo->tree.carry.paste_flags = REISER4_PASTE_FLAGS;
+	sbinfo->tree.carry.insert_flags = REISER4_INSERT_FLAGS;
+	rwlock_init(&(sbinfo->tree.tree_lock));
+	spin_lock_init(&(sbinfo->tree.epoch_lock));
+
+	/* initialize default readahead params */
+	sbinfo->ra_params.max = num_physpages / 4;
+	sbinfo->ra_params.flags = 0;
+
+	/* allocate memory for structure describing reiser4 mount options */
+	opts = kmalloc(sizeof(opt_desc_t) * MAX_NR_OPTIONS, GFP_KERNEL);
+	if (opts == NULL)
+		return RETERR(-ENOMEM);
+
+	/* initialize structure describing reiser4 mount options */
+	p = opts;
+
+#if REISER4_DEBUG
+#  define OPT_ARRAY_CHECK if ((p) > (opts) + MAX_NR_OPTIONS) {		\
+		warning ("zam-1046", "opt array is overloaded"); break;	\
+	}
+#else
+#   define OPT_ARRAY_CHECK noop
+#endif
+
+#define PUSH_OPT(...)				\
+do {						\
+	 opt_desc_t o = __VA_ARGS__;		\
+	 OPT_ARRAY_CHECK;			\
+	 *p ++ = o;				\
+} while (0)
+
+#define PUSH_SB_FIELD_OPT(field, format) PUSH_OPT(SB_FIELD_OPT(field, format))
+#define PUSH_BIT_OPT(name, bit) PUSH_OPT(BIT_OPT(name, bit))
+
+	/*
+	 * tmgr.atom_max_size=N
+	 * Atoms containing more than N blocks will be forced to commit. N is
+	 * decimal.
+	 */
+	PUSH_SB_FIELD_OPT(tmgr.atom_max_size, "%u");
+	/*
+	 * tmgr.atom_max_age=N
+	 * Atoms older than N seconds will be forced to commit. N is decimal.
+	 */
+	PUSH_SB_FIELD_OPT(tmgr.atom_max_age, "%u");
+	/*
+	 * tmgr.atom_min_size=N
+	 * In committing an atom to free dirty pages, force the atom less than
+	 * N in size to fuse with another one.
+	 */
+	PUSH_SB_FIELD_OPT(tmgr.atom_min_size, "%u");
+	/*
+	 * tmgr.atom_max_flushers=N
+	 * limit of concurrent flushers for one atom. 0 means no limit.
+	 */
+	PUSH_SB_FIELD_OPT(tmgr.atom_max_flushers, "%u");
+	/*
+	 * tree.cbk_cache_slots=N
+	 * Number of slots in the cbk cache.
+	 */
+	PUSH_SB_FIELD_OPT(tree.cbk_cache.nr_slots, "%u");
+	/*
+	 * If flush finds more than FLUSH_RELOCATE_THRESHOLD adjacent dirty
+	 * leaf-level blocks it will force them to be relocated.
+	 */
+	PUSH_SB_FIELD_OPT(flush.relocate_threshold, "%u");
+	/*
+	 * If flush finds can find a block allocation closer than at most
+	 * FLUSH_RELOCATE_DISTANCE from the preceder it will relocate to that
+	 * position.
+	 */
+	PUSH_SB_FIELD_OPT(flush.relocate_distance, "%u");
+	/*
+	 * If we have written this much or more blocks before encountering busy
+	 * jnode in flush list - abort flushing hoping that next time we get
+	 * called this jnode will be clean already, and we will save some
+	 * seeks.
+	 */
+	PUSH_SB_FIELD_OPT(flush.written_threshold, "%u");
+	/* The maximum number of nodes to scan left on a level during flush. */
+	PUSH_SB_FIELD_OPT(flush.scan_maxnodes, "%u");
+	/* preferred IO size */
+	PUSH_SB_FIELD_OPT(optimal_io_size, "%u");
+	/* carry flags used for insertion of new nodes */
+	PUSH_SB_FIELD_OPT(tree.carry.new_node_flags, "%u");
+	/* carry flags used for insertion of new extents */
+	PUSH_SB_FIELD_OPT(tree.carry.new_extent_flags, "%u");
+	/* carry flags used for paste operations */
+	PUSH_SB_FIELD_OPT(tree.carry.paste_flags, "%u");
+	/* carry flags used for insert operations */
+	PUSH_SB_FIELD_OPT(tree.carry.insert_flags, "%u");
+
+#ifdef CONFIG_REISER4_BADBLOCKS
+	/*
+	 * Alternative master superblock location in case if it's original
+	 * location is not writeable/accessable. This is offset in BYTES.
+	 */
+	PUSH_SB_FIELD_OPT(altsuper, "%lu");
+#endif
+
+	/* turn on BSD-style gid assignment */
+	PUSH_BIT_OPT("bsdgroups", REISER4_BSD_GID);
+	/* turn on 32 bit times */
+	PUSH_BIT_OPT("32bittimes", REISER4_32_BIT_TIMES);
+	/* turn off concurrent flushing */
+	PUSH_BIT_OPT("mtflush", REISER4_MTFLUSH);
+	/*
+	 * Don't load all bitmap blocks at mount time, it is useful for
+	 * machines with tiny RAM and large disks.
+	 */
+	PUSH_BIT_OPT("dont_load_bitmap", REISER4_DONT_LOAD_BITMAP);
+	/* disable transaction commits during write() */
+	PUSH_BIT_OPT("atomic_write", REISER4_ATOMIC_WRITE);
+	/* disable use of write barriers in the reiser4 log writer. */
+	PUSH_BIT_OPT("no_write_barrier", REISER4_NO_WRITE_BARRIER);
+
+	PUSH_OPT(
+	{
+		/*
+		 * tree traversal readahead parameters:
+		 * -o readahead:MAXNUM:FLAGS
+		 * MAXNUM - max number fo nodes to request readahead for: -1UL
+		 * will set it to max_sane_readahead()
+		 * FLAGS - combination of bits: RA_ADJCENT_ONLY, RA_ALL_LEVELS,
+		 * CONTINUE_ON_PRESENT
+		 */
+		.name = "readahead",
+		.type = OPT_FORMAT,
+		.u = {
+			.f = {
+				.format = "%u:%u",
+				.nr_args = 2,
+				.arg1 = &sbinfo->ra_params.max,
+				.arg2 = &sbinfo->ra_params.flags,
+				.arg3 = NULL,
+				.arg4 = NULL
+			}
+		}
+	}
+	);
+
+	/* What to do in case of fs error */
+	PUSH_OPT(
+	{
+		.name = "onerror",
+		.type = OPT_ONEOF,
+		.u = {
+			.oneof = {
+				.result = &sbinfo->onerror,
+				.list = {
+					"panic", "remount-ro", NULL
+				},
+			}
+		}
+	}
+	);
+
+	/* modify default settings to values set by mount options */
+	result = parse_options(opt_string, opts, p - opts);
+	kfree(opts);
+	if (result != 0)
+		return result;
+
+	/* correct settings to sanity values */
+	sbinfo->tmgr.atom_max_age *= HZ;
+	if (sbinfo->tmgr.atom_max_age <= 0)
+		/* overflow */
+		sbinfo->tmgr.atom_max_age = REISER4_ATOM_MAX_AGE;
+
+	/* round optimal io size up to 512 bytes */
+	sbinfo->optimal_io_size >>= VFS_BLKSIZE_BITS;
+	sbinfo->optimal_io_size <<= VFS_BLKSIZE_BITS;
+	if (sbinfo->optimal_io_size == 0) {
+		warning("nikita-2497", "optimal_io_size is too small");
+		return RETERR(-EINVAL);
+	}
+
+	/* disable single-threaded flush as it leads to deadlock */
+	sbinfo->fs_flags |= (1 << REISER4_MTFLUSH);
+	return result;
+}
+
+/**
+ * init_read_super - read reiser4 master super block
+ * @super: super block to fill
+ * @silent: if 0 - print warnings
+ *
+ * Reads reiser4 master super block either from predefined location or from
+ * location specified by altsuper mount option, initializes disk format plugin.
+ */
+int init_read_super(struct super_block *super, int silent)
+{
+	struct buffer_head *super_bh;
+	struct reiser4_master_sb *master_sb;
+	reiser4_super_info_data *sbinfo = get_super_private(super);
+	unsigned long blocksize;
+
+ read_super_block:
+#ifdef CONFIG_REISER4_BADBLOCKS
+	if (sbinfo->altsuper)
+		/*
+		 * read reiser4 master super block at position specified by
+		 * mount option
+		 */
+		super_bh = sb_bread(super,
+				    (sector_t)(sbinfo->altsuper / super->s_blocksize));
+	else
+#endif
+		/* read reiser4 master super block at 16-th 4096 block */
+		super_bh = sb_bread(super,
+				    (sector_t)(REISER4_MAGIC_OFFSET / super->s_blocksize));
+	if (!super_bh)
+		return RETERR(-EIO);
+
+	master_sb = (struct reiser4_master_sb *)super_bh->b_data;
+	/* check reiser4 magic string */
+	if (!strncmp(master_sb->magic, REISER4_SUPER_MAGIC_STRING,
+		     sizeof(REISER4_SUPER_MAGIC_STRING))) {
+		/* reiser4 master super block contains filesystem blocksize */
+		blocksize = le16_to_cpu(get_unaligned(&master_sb->blocksize));
+
+		if (blocksize != PAGE_CACHE_SIZE) {
+			/*
+			 * currenly reiser4's blocksize must be equal to
+			 * pagesize
+			 */
+			if (!silent)
+				warning("nikita-2609",
+					"%s: wrong block size %ld\n", super->s_id,
+					blocksize);
+			brelse(super_bh);
+			return RETERR(-EINVAL);
+		}
+		if (blocksize != super->s_blocksize) {
+			/*
+			 * filesystem uses different blocksize. Reread master
+			 * super block with correct blocksize
+			 */
+			brelse(super_bh);
+			if (!sb_set_blocksize(super, (int)blocksize))
+				return RETERR(-EINVAL);
+			goto read_super_block;
+		}
+
+		sbinfo->df_plug =
+			disk_format_plugin_by_id(
+				le16_to_cpu(get_unaligned(&master_sb->disk_plugin_id)));
+		if (sbinfo->df_plug == NULL) {
+			if (!silent)
+				warning("nikita-26091",
+					"%s: unknown disk format plugin %d\n",
+					super->s_id,
+					le16_to_cpu(get_unaligned(&master_sb->disk_plugin_id)));
+			brelse(super_bh);
+			return RETERR(-EINVAL);
+		}
+		sbinfo->diskmap_block = le64_to_cpu(get_unaligned(&master_sb->diskmap));
+		brelse(super_bh);
+		return 0;
+	}
+
+	/* there is no reiser4 on the device */
+	if (!silent)
+		warning("nikita-2608",
+			"%s: wrong master super block magic", super->s_id);
+	brelse(super_bh);
+	return RETERR(-EINVAL);
+}
+
+static struct {
+	reiser4_plugin_type type;
+	reiser4_plugin_id id;
+} default_plugins[PSET_LAST] = {
+	[PSET_FILE] = {
+		.type = REISER4_FILE_PLUGIN_TYPE,
+		.id = UNIX_FILE_PLUGIN_ID
+	},
+	[PSET_DIR] = {
+		.type = REISER4_DIR_PLUGIN_TYPE,
+		.id = HASHED_DIR_PLUGIN_ID
+	},
+	[PSET_HASH] = {
+		.type = REISER4_HASH_PLUGIN_TYPE,
+		.id = R5_HASH_ID
+	},
+	[PSET_FIBRATION] = {
+		.type = REISER4_FIBRATION_PLUGIN_TYPE,
+		.id = FIBRATION_DOT_O
+	},
+	[PSET_PERM] = {
+		.type = REISER4_PERM_PLUGIN_TYPE,
+		.id = NULL_PERM_ID
+	},
+	[PSET_FORMATTING] = {
+		.type = REISER4_FORMATTING_PLUGIN_TYPE,
+		.id = SMALL_FILE_FORMATTING_ID
+	},
+	[PSET_SD] = {
+		.type = REISER4_ITEM_PLUGIN_TYPE,
+		.id = STATIC_STAT_DATA_ID
+	},
+	[PSET_DIR_ITEM] = {
+		.type = REISER4_ITEM_PLUGIN_TYPE,
+		.id = COMPOUND_DIR_ID
+	},
+	[PSET_CIPHER] = {
+		.type = REISER4_CIPHER_PLUGIN_TYPE,
+		.id = NONE_CIPHER_ID
+	},
+	[PSET_DIGEST] = {
+		.type = REISER4_DIGEST_PLUGIN_TYPE,
+		.id = SHA256_32_DIGEST_ID
+	},
+	[PSET_COMPRESSION] = {
+		.type = REISER4_COMPRESSION_PLUGIN_TYPE,
+		.id = LZO1_COMPRESSION_ID
+	},
+	[PSET_COMPRESSION_MODE] = {
+		.type = REISER4_COMPRESSION_MODE_PLUGIN_TYPE,
+		.id = COL_16_COMPRESSION_MODE_ID
+	},
+	[PSET_CLUSTER] = {
+		.type = REISER4_CLUSTER_PLUGIN_TYPE,
+		.id = CLUSTER_64K_ID
+	},
+	[PSET_REGULAR_ENTRY] = {
+		.type = REISER4_REGULAR_PLUGIN_TYPE,
+		.id = UF_REGULAR_ID
+	}
+};
+
+/* access to default plugin table */
+static reiser4_plugin *get_default_plugin(pset_member memb)
+{
+	return plugin_by_id(default_plugins[memb].type,
+			    default_plugins[memb].id);
+}
+
+/**
+ * init_root_inode - obtain inode of root directory
+ * @super: super block of filesystem
+ *
+ * Obtains inode of root directory (reading it from disk), initializes plugin
+ * set it was not initialized.
+ */
+int init_root_inode(struct super_block *super)
+{
+	reiser4_super_info_data *sbinfo = get_super_private(super);
+	struct inode *inode;
+	int result = 0;
+
+	inode = reiser4_iget(super, sbinfo->df_plug->root_dir_key(super), 0);
+	if (IS_ERR(inode))
+		return RETERR(PTR_ERR(inode));
+
+	super->s_root = d_alloc_root(inode);
+	if (!super->s_root) {
+		iput(inode);
+		return RETERR(-ENOMEM);
+	}
+
+	super->s_root->d_op = &sbinfo->ops.dentry;
+
+	if (!is_inode_loaded(inode)) {
+		pset_member memb;
+
+		for (memb = 0; memb < PSET_LAST; ++memb) {
+			reiser4_plugin *plug;
+
+			plug = get_default_plugin(memb);
+			result = grab_plugin_from(inode, memb, plug);
+			if (result != 0)
+				break;
+		}
+
+		if (result == 0) {
+			if (REISER4_DEBUG) {
+				plugin_set *pset;
+
+				pset = reiser4_inode_data(inode)->pset;
+				for (memb = 0; memb < PSET_LAST; ++memb)
+					assert("nikita-3500",
+					       pset_get(pset, memb) != NULL);
+			}
+		} else
+			warning("nikita-3448", "Cannot set plugins of root: %i",
+				result);
+		reiser4_iget_complete(inode);
+	}
+	super->s_maxbytes = MAX_LFS_FILESIZE;
+	return result;
+}
+
+/**
+ * done_root_inode - put inode of root directory
+ * @super: super block of filesystem
+ *
+ * Puts inode of root directory.
+ */
+#if 0
+void done_root_inode(struct super_block *super)
+{
+	/* remove unused children of the parent dentry */
+	shrink_dcache_parent(super->s_root);
+	assert("vs-1714", hlist_empty(&super->s_anon));
+	dput(super->s_root);
+	super->s_root = NULL;
+	/* discard all inodes of filesystem */
+	invalidate_inodes(super);
+}
+#endif  /*  0  */
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * End:
+ */
diff -urN oldtree/fs/reiser4/inode.c newtree/fs/reiser4/inode.c
--- oldtree/fs/reiser4/inode.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/inode.c	2006-02-21 15:58:35.401764672 +0000
@@ -0,0 +1,725 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Inode specific operations. */
+
+#include "forward.h"
+#include "debug.h"
+#include "key.h"
+#include "kassign.h"
+#include "coord.h"
+#include "seal.h"
+#include "dscale.h"
+#include "plugin/item/item.h"
+#include "plugin/security/perm.h"
+#include "plugin/plugin.h"
+#include "plugin/object.h"
+#include "znode.h"
+#include "vfs_ops.h"
+#include "inode.h"
+#include "super.h"
+#include "reiser4.h"
+
+#include <linux/fs.h>		/* for struct super_block,  address_space */
+
+/* return reiser4 internal tree which inode belongs to */
+/* Audited by: green(2002.06.17) */
+reiser4_tree *tree_by_inode(const struct inode *inode /* inode queried */ )
+{
+	assert("nikita-256", inode != NULL);
+	assert("nikita-257", inode->i_sb != NULL);
+	return get_tree(inode->i_sb);
+}
+
+/* return reiser4-specific inode flags */
+static inline unsigned long *inode_flags(const struct inode *const inode)
+{
+	assert("nikita-2842", inode != NULL);
+	return &reiser4_inode_data(inode)->flags;
+}
+
+/* set reiser4-specific flag @f in @inode */
+void inode_set_flag(struct inode *inode, reiser4_file_plugin_flags f)
+{
+	assert("nikita-2248", inode != NULL);
+	set_bit((int)f, inode_flags(inode));
+}
+
+/* clear reiser4-specific flag @f in @inode */
+void inode_clr_flag(struct inode *inode, reiser4_file_plugin_flags f)
+{
+	assert("nikita-2250", inode != NULL);
+	clear_bit((int)f, inode_flags(inode));
+}
+
+/* true if reiser4-specific flag @f is set in @inode */
+int inode_get_flag(const struct inode *inode, reiser4_file_plugin_flags f)
+{
+	assert("nikita-2251", inode != NULL);
+	return test_bit((int)f, inode_flags(inode));
+}
+
+/* convert oid to inode number */
+ino_t oid_to_ino(oid_t oid)
+{
+	return (ino_t) oid;
+}
+
+/* convert oid to user visible inode number */
+ino_t oid_to_uino(oid_t oid)
+{
+	/* reiser4 object is uniquely identified by oid which is 64 bit
+	   quantity. Kernel in-memory inode is indexed (in the hash table) by
+	   32 bit i_ino field, but this is not a problem, because there is a
+	   way to further distinguish inodes with identical inode numbers
+	   (find_actor supplied to iget()).
+
+	   But user space expects unique 32 bit inode number. Obviously this
+	   is impossible. Work-around is to somehow hash oid into user visible
+	   inode number.
+	 */
+	oid_t max_ino = (ino_t) ~ 0;
+
+	if (REISER4_INO_IS_OID || (oid <= max_ino))
+		return oid;
+	else
+		/* this is remotely similar to algorithm used to find next pid
+		   to use for process: after wrap-around start from some
+		   offset rather than from 0. Idea is that there are some long
+		   living objects with which we don't want to collide.
+		 */
+		return REISER4_UINO_SHIFT + ((oid - max_ino) & (max_ino >> 1));
+}
+
+/* check that "inode" is on reiser4 file-system */
+int is_reiser4_inode(const struct inode *inode /* inode queried */ )
+{
+	return inode != NULL && is_reiser4_super(inode->i_sb);
+}
+
+/* Maximal length of a name that can be stored in directory @inode.
+
+   This is used in check during file creation and lookup. */
+int reiser4_max_filename_len(const struct inode *inode /* inode queried */ )
+{
+	assert("nikita-287", is_reiser4_inode(inode));
+	assert("nikita-1710", inode_dir_item_plugin(inode));
+	if (inode_dir_item_plugin(inode)->s.dir.max_name_len)
+		return inode_dir_item_plugin(inode)->s.dir.max_name_len(inode);
+	else
+		return 255;
+}
+
+#if REISER4_USE_COLLISION_LIMIT
+/* Maximal number of hash collisions for this directory. */
+int max_hash_collisions(const struct inode *dir /* inode queried */ )
+{
+	assert("nikita-1711", dir != NULL);
+	return reiser4_inode_data(dir)->plugin.max_collisions;
+}
+#endif  /*  REISER4_USE_COLLISION_LIMIT  */
+
+/* Install file, inode, and address_space operation on @inode, depending on
+   its mode. */
+int setup_inode_ops(struct inode *inode /* inode to intialize */ ,
+		    reiser4_object_create_data * data	/* parameters to create
+							 * object */ )
+{
+	reiser4_super_info_data *sinfo;
+	file_plugin *fplug;
+	dir_plugin *dplug;
+
+	fplug = inode_file_plugin(inode);
+	dplug = inode_dir_plugin(inode);
+
+	sinfo = get_super_private(inode->i_sb);
+
+	switch (inode->i_mode & S_IFMT) {
+	case S_IFSOCK:
+	case S_IFBLK:
+	case S_IFCHR:
+	case S_IFIFO:
+		{
+			dev_t rdev;	/* to keep gcc happy */
+
+			assert("vs-46", fplug != NULL);
+			/* ugly hack with rdev */
+			if (data == NULL) {
+				rdev = inode->i_rdev;
+				inode->i_rdev = 0;
+			} else
+				rdev = data->rdev;
+			inode->i_blocks = 0;
+			assert("vs-42", fplug->h.id == SPECIAL_FILE_PLUGIN_ID);
+			inode->i_op = &file_plugins[fplug->h.id].inode_ops;
+			/* initialize inode->i_fop and inode->i_rdev for block and char
+			   devices */
+			init_special_inode(inode, inode->i_mode, rdev);
+			/* all address space operations are null */
+			inode->i_mapping->a_ops =
+			    &file_plugins[fplug->h.id].as_ops;
+			break;
+		}
+	case S_IFLNK:
+		assert("vs-46", fplug != NULL);
+		assert("vs-42", fplug->h.id == SYMLINK_FILE_PLUGIN_ID);
+		inode->i_op = &file_plugins[fplug->h.id].inode_ops;
+		inode->i_fop = NULL;
+		/* all address space operations are null */
+		inode->i_mapping->a_ops = &file_plugins[fplug->h.id].as_ops;
+		break;
+	case S_IFDIR:
+		assert("vs-46", dplug != NULL);
+		assert("vs-43", (dplug->h.id == HASHED_DIR_PLUGIN_ID ||
+				 dplug->h.id == SEEKABLE_HASHED_DIR_PLUGIN_ID));
+		inode->i_op = &dir_plugins[dplug->h.id].inode_ops;
+		inode->i_fop = &dir_plugins[dplug->h.id].file_ops;
+		inode->i_mapping->a_ops = &dir_plugins[dplug->h.id].as_ops;
+		break;
+	case S_IFREG:
+		assert("vs-46", fplug != NULL);
+		assert("vs-43", (fplug->h.id == UNIX_FILE_PLUGIN_ID ||
+				 fplug->h.id == CRC_FILE_PLUGIN_ID));
+		inode->i_op = &file_plugins[fplug->h.id].inode_ops;
+		inode->i_fop = &file_plugins[fplug->h.id].file_ops;
+		inode->i_mapping->a_ops = &file_plugins[fplug->h.id].as_ops;
+		break;
+	default:
+		warning("nikita-291", "wrong file mode: %o for %llu",
+			inode->i_mode,
+			(unsigned long long)get_inode_oid(inode));
+		reiser4_make_bad_inode(inode);
+		return RETERR(-EINVAL);
+	}
+	return 0;
+}
+
+/* initialize inode from disk data. Called with inode locked.
+    Return inode locked. */
+static int init_inode(struct inode *inode /* inode to intialise */ ,
+		      coord_t * coord /* coord of stat data */ )
+{
+	int result;
+	item_plugin *iplug;
+	void *body;
+	int length;
+	reiser4_inode *state;
+
+	assert("nikita-292", coord != NULL);
+	assert("nikita-293", inode != NULL);
+
+	coord_clear_iplug(coord);
+	result = zload(coord->node);
+	if (result)
+		return result;
+	iplug = item_plugin_by_coord(coord);
+	body = item_body_by_coord(coord);
+	length = item_length_by_coord(coord);
+
+	assert("nikita-295", iplug != NULL);
+	assert("nikita-296", body != NULL);
+	assert("nikita-297", length > 0);
+
+	/* inode is under I_LOCK now */
+
+	state = reiser4_inode_data(inode);
+	/* call stat-data plugin method to load sd content into inode */
+	result = iplug->s.sd.init_inode(inode, body, length);
+	plugin_set_sd(&state->pset, iplug);
+	if (result == 0) {
+		result = setup_inode_ops(inode, NULL);
+		if (result == 0 &&
+		    inode->i_sb->s_root && inode->i_sb->s_root->d_inode) {
+			struct inode *root;
+			pset_member ind;
+
+			/* take missing plugins from file-system defaults */
+			root = inode->i_sb->s_root->d_inode;
+			/* file and directory plugins are already initialized. */
+			for (ind = PSET_DIR + 1; ind < PSET_LAST; ++ind) {
+				result = grab_plugin(inode, root, ind);
+				if (result != 0)
+					break;
+			}
+			if (result != 0) {
+				warning("nikita-3447",
+					"Cannot set up plugins for %lli",
+					(unsigned long long)
+					get_inode_oid(inode));
+			}
+		}
+	}
+	zrelse(coord->node);
+	return result;
+}
+
+/* read `inode' from the disk. This is what was previously in
+   reiserfs_read_inode2().
+
+   Must be called with inode locked. Return inode still locked.
+*/
+static int read_inode(struct inode *inode /* inode to read from disk */ ,
+		      const reiser4_key * key /* key of stat data */ ,
+		      int silent)
+{
+	int result;
+	lock_handle lh;
+	reiser4_inode *info;
+	coord_t coord;
+
+	assert("nikita-298", inode != NULL);
+	assert("nikita-1945", !is_inode_loaded(inode));
+
+	info = reiser4_inode_data(inode);
+	assert("nikita-300", info->locality_id != 0);
+
+	coord_init_zero(&coord);
+	init_lh(&lh);
+	/* locate stat-data in a tree and return znode locked */
+	result = lookup_sd(inode, ZNODE_READ_LOCK, &coord, &lh, key, silent);
+	assert("nikita-301", !is_inode_loaded(inode));
+	if (result == 0) {
+		/* use stat-data plugin to load sd into inode. */
+		result = init_inode(inode, &coord);
+		if (result == 0) {
+			/* initialize stat-data seal */
+			spin_lock_inode(inode);
+			seal_init(&info->sd_seal, &coord, key);
+			info->sd_coord = coord;
+			spin_unlock_inode(inode);
+
+			/* call file plugin's method to initialize plugin
+			 * specific part of inode */
+			if (inode_file_plugin(inode)->init_inode_data)
+				inode_file_plugin(inode)->init_inode_data(inode,
+									  NULL,
+									  0);
+			/* load detached directory cursors for stateless
+			 * directory readers (NFS). */
+			load_cursors(inode);
+
+			/* Check the opened inode for consistency. */
+			result =
+			    get_super_private(inode->i_sb)->df_plug->
+			    check_open(inode);
+		}
+	}
+	/* lookup_sd() doesn't release coord because we want znode
+	   stay read-locked while stat-data fields are accessed in
+	   init_inode() */
+	done_lh(&lh);
+
+	if (result != 0)
+		reiser4_make_bad_inode(inode);
+	return result;
+}
+
+/* initialise new reiser4 inode being inserted into hash table. */
+static int init_locked_inode(struct inode *inode /* new inode */ ,
+			     void *opaque	/* key of stat data passed to the
+						 * iget5_locked as cookie */ )
+{
+	reiser4_key *key;
+
+	assert("nikita-1995", inode != NULL);
+	assert("nikita-1996", opaque != NULL);
+	key = opaque;
+	set_inode_oid(inode, get_key_objectid(key));
+	reiser4_inode_data(inode)->locality_id = get_key_locality(key);
+	return 0;
+}
+
+/* reiser4_inode_find_actor() - "find actor" supplied by reiser4 to iget5_locked().
+
+   This function is called by iget5_locked() to distinguish reiser4 inodes
+   having the same inode numbers. Such inodes can only exist due to some error
+   condition. One of them should be bad. Inodes with identical inode numbers
+   (objectids) are distinguished by their packing locality.
+
+*/
+static int reiser4_inode_find_actor(struct inode *inode	/* inode from hash table to
+							 * check */ ,
+				    void *opaque	/* "cookie" passed to
+							 * iget5_locked(). This is stat data
+							 * key */ )
+{
+	reiser4_key *key;
+
+	key = opaque;
+	return
+	    /* oid is unique, so first term is enough, actually. */
+	    get_inode_oid(inode) == get_key_objectid(key) &&
+	    /*
+	     * also, locality should be checked, but locality is stored in
+	     * the reiser4-specific part of the inode, and actor can be
+	     * called against arbitrary inode that happened to be in this
+	     * hash chain. Hence we first have to check that this is
+	     * reiser4 inode at least. is_reiser4_inode() is probably too
+	     * early to call, as inode may have ->i_op not yet
+	     * initialised.
+	     */
+	    is_reiser4_super(inode->i_sb) &&
+	    /*
+	     * usually objectid is unique, but pseudo files use counter to
+	     * generate objectid. All pseudo files are placed into special
+	     * (otherwise unused) locality.
+	     */
+	    reiser4_inode_data(inode)->locality_id == get_key_locality(key);
+}
+
+/* hook for kmem_cache_create */
+void loading_init_once(reiser4_inode * info)
+{
+	sema_init(&info->loading, 1);
+}
+
+/* for reiser4_alloc_inode */
+void loading_alloc(reiser4_inode * info)
+{
+#if REISER4_DEBUG
+	assert("vs-1717", down_trylock(&info->loading) == 0);
+	up(&info->loading);
+#endif
+}
+
+/* for reiser4_destroy */
+void loading_destroy(reiser4_inode * info)
+{
+#if REISER4_DEBUG
+	assert("vs-1717", down_trylock(&info->loading) == 0);
+	up(&info->loading);
+#endif
+}
+
+static void loading_down(reiser4_inode * info)
+{
+	down(&info->loading);
+}
+
+static void loading_up(reiser4_inode * info)
+{
+	up(&info->loading);
+}
+
+/**
+ * reiser4_iget - obtain inode via iget5_locked, read from disk if necessary
+ * @super: super block of filesystem
+ * @key: key of inode's stat-data
+ * @silent:
+ *
+ * This is our helper function a la iget(). This is be called by
+ * reiser4_lookup() and reiser4_read_super(). Return inode locked or error
+ * encountered.
+ */
+struct inode *reiser4_iget(struct super_block *super, const reiser4_key *key,
+			   int silent)
+{
+	struct inode *inode;
+	int result;
+	reiser4_inode *info;
+
+	assert("nikita-302", super != NULL);
+	assert("nikita-303", key != NULL);
+
+	result = 0;
+
+	/* call iget(). Our ->read_inode() is dummy, so this will either
+	   find inode in cache or return uninitialised inode */
+	inode = iget5_locked(super,
+			     (unsigned long)get_key_objectid(key),
+			     reiser4_inode_find_actor,
+			     init_locked_inode, (reiser4_key *) key);
+	if (inode == NULL)
+		return ERR_PTR(RETERR(-ENOMEM));
+	if (is_bad_inode(inode)) {
+		warning("nikita-304", "Bad inode found");
+		print_key("key", key);
+		iput(inode);
+		return ERR_PTR(RETERR(-EIO));
+	}
+
+	info = reiser4_inode_data(inode);
+
+	/* Reiser4 inode state bit REISER4_LOADED is used to distinguish fully
+	   loaded and initialized inode from just allocated inode. If
+	   REISER4_LOADED bit is not set, reiser4_iget() completes loading under
+	   info->loading.  The place in reiser4 which uses not initialized inode
+	   is the reiser4 repacker, see repacker-related functions in
+	   plugin/item/extent.c */
+	if (!is_inode_loaded(inode)) {
+		loading_down(info);
+		if (!is_inode_loaded(inode)) {
+			/* locking: iget5_locked returns locked inode */
+			assert("nikita-1941", !is_inode_loaded(inode));
+			assert("nikita-1949",
+			       reiser4_inode_find_actor(inode,
+							(reiser4_key *) key));
+			/* now, inode has objectid as ->i_ino and locality in
+			   reiser4-specific part. This is enough for
+			   read_inode() to read stat data from the disk */
+			result = read_inode(inode, key, silent);
+		} else
+			loading_up(info);
+	}
+
+	if (inode->i_state & I_NEW)
+		unlock_new_inode(inode);
+
+	if (is_bad_inode(inode)) {
+		assert("vs-1717", result != 0);
+		loading_up(info);
+		iput(inode);
+		inode = ERR_PTR(result);
+	} else if (REISER4_DEBUG) {
+		reiser4_key found_key;
+
+		assert("vs-1717", result == 0);
+		build_sd_key(inode, &found_key);
+		if (!keyeq(&found_key, key)) {
+			warning("nikita-305", "Wrong key in sd");
+			print_key("sought for", key);
+			print_key("found", &found_key);
+		}
+		if (inode->i_nlink == 0) {
+			warning("nikita-3559", "Unlinked inode found: %llu\n",
+				(unsigned long long)get_inode_oid(inode));
+		}
+	}
+	return inode;
+}
+
+/* reiser4_iget() may return not fully initialized inode, this function should
+ * be called after one completes reiser4 inode initializing. */
+void reiser4_iget_complete(struct inode *inode)
+{
+	assert("zam-988", is_reiser4_inode(inode));
+
+	if (!is_inode_loaded(inode)) {
+		inode_set_flag(inode, REISER4_LOADED);
+		loading_up(reiser4_inode_data(inode));
+	}
+}
+
+void reiser4_make_bad_inode(struct inode *inode)
+{
+	assert("nikita-1934", inode != NULL);
+
+	/* clear LOADED bit */
+	inode_clr_flag(inode, REISER4_LOADED);
+	make_bad_inode(inode);
+	return;
+}
+
+file_plugin *inode_file_plugin(const struct inode * inode)
+{
+	assert("nikita-1997", inode != NULL);
+	return reiser4_inode_data(inode)->pset->file;
+}
+
+dir_plugin *inode_dir_plugin(const struct inode * inode)
+{
+	assert("nikita-1998", inode != NULL);
+	return reiser4_inode_data(inode)->pset->dir;
+}
+
+perm_plugin *inode_perm_plugin(const struct inode * inode)
+{
+	assert("nikita-1999", inode != NULL);
+	return reiser4_inode_data(inode)->pset->perm;
+}
+
+formatting_plugin *inode_formatting_plugin(const struct inode * inode)
+{
+	assert("nikita-2000", inode != NULL);
+	return reiser4_inode_data(inode)->pset->formatting;
+}
+
+hash_plugin *inode_hash_plugin(const struct inode * inode)
+{
+	assert("nikita-2001", inode != NULL);
+	return reiser4_inode_data(inode)->pset->hash;
+}
+
+fibration_plugin *inode_fibration_plugin(const struct inode * inode)
+{
+	assert("nikita-2001", inode != NULL);
+	return reiser4_inode_data(inode)->pset->fibration;
+}
+
+cipher_plugin *inode_cipher_plugin(const struct inode * inode)
+{
+	assert("edward-36", inode != NULL);
+	return reiser4_inode_data(inode)->pset->cipher;
+}
+
+compression_plugin *inode_compression_plugin(const struct inode * inode)
+{
+	assert("edward-37", inode != NULL);
+	return reiser4_inode_data(inode)->pset->compression;
+}
+
+compression_mode_plugin *inode_compression_mode_plugin(const struct inode *
+						       inode)
+{
+	assert("edward-1330", inode != NULL);
+	return reiser4_inode_data(inode)->pset->compression_mode;
+}
+
+cluster_plugin *inode_cluster_plugin(const struct inode * inode)
+{
+	assert("edward-1328", inode != NULL);
+	return reiser4_inode_data(inode)->pset->cluster;
+}
+
+regular_plugin *inode_regular_plugin(const struct inode * inode)
+{
+	assert("edward-1329", inode != NULL);
+	return reiser4_inode_data(inode)->pset->regular_entry;
+}
+
+digest_plugin *inode_digest_plugin(const struct inode * inode)
+{
+	assert("edward-86", inode != NULL);
+	return reiser4_inode_data(inode)->pset->digest;
+}
+
+item_plugin *inode_sd_plugin(const struct inode * inode)
+{
+	assert("vs-534", inode != NULL);
+	return reiser4_inode_data(inode)->pset->sd;
+}
+
+item_plugin *inode_dir_item_plugin(const struct inode * inode)
+{
+	assert("vs-534", inode != NULL);
+	return reiser4_inode_data(inode)->pset->dir_item;
+}
+
+void inode_set_extension(struct inode *inode, sd_ext_bits ext)
+{
+	reiser4_inode *state;
+
+	assert("nikita-2716", inode != NULL);
+	assert("nikita-2717", ext < LAST_SD_EXTENSION);
+	assert("nikita-3491", spin_inode_is_locked(inode));
+
+	state = reiser4_inode_data(inode);
+	state->extmask |= 1 << ext;
+	/* force re-calculation of stat-data length on next call to
+	   update_sd(). */
+	inode_clr_flag(inode, REISER4_SDLEN_KNOWN);
+}
+
+void
+inode_set_plugin(struct inode *inode, reiser4_plugin * plug, pset_member memb)
+{
+	assert("nikita-2718", inode != NULL);
+	assert("nikita-2719", plug != NULL);
+
+	reiser4_inode_data(inode)->plugin_mask |= (1 << memb);
+}
+
+void inode_check_scale_nolock(struct inode *inode, __u64 old, __u64 new)
+{
+	assert("edward-1287", inode != NULL);
+	if (!dscale_fit(old, new))
+		inode_clr_flag(inode, REISER4_SDLEN_KNOWN);
+	return;
+}
+
+void inode_check_scale(struct inode *inode, __u64 old, __u64 new)
+{
+	assert("nikita-2875", inode != NULL);
+	spin_lock_inode(inode);
+	inode_check_scale_nolock(inode, old, new);
+	spin_unlock_inode(inode);
+}
+
+/*
+ * initialize ->ordering field of inode. This field defines how file stat-data
+ * and body is ordered within a tree with respect to other objects within the
+ * same parent directory.
+ */
+void
+init_inode_ordering(struct inode *inode,
+		    reiser4_object_create_data * crd, int create)
+{
+	reiser4_key key;
+
+	if (create) {
+		struct inode *parent;
+
+		parent = crd->parent;
+		assert("nikita-3224", inode_dir_plugin(parent) != NULL);
+		inode_dir_plugin(parent)->build_entry_key(parent,
+							  &crd->dentry->d_name,
+							  &key);
+	} else {
+		coord_t *coord;
+
+		coord = &reiser4_inode_data(inode)->sd_coord;
+		coord_clear_iplug(coord);
+		/* safe to use ->sd_coord, because node is under long term
+		 * lock */
+		WITH_DATA(coord->node, item_key_by_coord(coord, &key));
+	}
+
+	set_inode_ordering(inode, get_key_ordering(&key));
+}
+
+znode *inode_get_vroot(struct inode *inode)
+{
+	reiser4_block_nr blk;
+	znode *result;
+
+	spin_lock_inode(inode);
+	blk = reiser4_inode_data(inode)->vroot;
+	spin_unlock_inode(inode);
+	if (!disk_addr_eq(&UBER_TREE_ADDR, &blk))
+		result = zlook(tree_by_inode(inode), &blk);
+	else
+		result = NULL;
+	return result;
+}
+
+void inode_set_vroot(struct inode *inode, znode *vroot)
+{
+	spin_lock_inode(inode);
+	reiser4_inode_data(inode)->vroot = *znode_get_block(vroot);
+	spin_unlock_inode(inode);
+}
+
+#if REISER4_DEBUG
+
+void inode_invariant(const struct inode *inode)
+{
+	assert("nikita-3077", spin_inode_is_locked(inode));
+}
+
+int inode_has_no_jnodes(reiser4_inode * r4_inode)
+{
+	return jnode_tree_by_reiser4_inode(r4_inode)->rnode == NULL &&
+		r4_inode->nr_jnodes == 0;
+}
+
+#endif
+
+/* true if directory is empty (only contains dot and dotdot) */
+/* FIXME: shouldn't it be dir plugin method? */
+int is_dir_empty(const struct inode *dir)
+{
+	assert("nikita-1976", dir != NULL);
+
+	/* rely on our method to maintain directory i_size being equal to the
+	   number of entries. */
+	return dir->i_size <= 2 ? 0 : RETERR(-ENOTEMPTY);
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/inode.h newtree/fs/reiser4/inode.h
--- oldtree/fs/reiser4/inode.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/inode.h	2006-02-21 15:58:35.474753576 +0000
@@ -0,0 +1,434 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Inode functions. */
+
+#if !defined( __REISER4_INODE_H__ )
+#define __REISER4_INODE_H__
+
+#include "forward.h"
+#include "debug.h"
+#include "key.h"
+#include "seal.h"
+#include "plugin/plugin.h"
+#include "plugin/file/cryptcompress.h"
+#include "plugin/file/file.h"
+#include "plugin/dir/dir.h"
+#include "plugin/plugin_set.h"
+#include "plugin/security/perm.h"
+#include "vfs_ops.h"
+#include "jnode.h"
+#include "fsdata.h"
+
+#include <linux/types.h>	/* for __u?? , ino_t */
+#include <linux/fs.h>		/* for struct super_block, struct
+				 * rw_semaphore, etc  */
+#include <linux/spinlock.h>
+#include <asm/types.h>
+
+/* reiser4-specific inode flags. They are "transient" and are not
+   supposed to be stored on disk. Used to trace "state" of
+   inode
+*/
+typedef enum {
+	/* this is light-weight inode, inheriting some state from its
+	   parent  */
+	REISER4_LIGHT_WEIGHT = 0,
+	/* stat data wasn't yet created */
+	REISER4_NO_SD = 1,
+	/* internal immutable flag. Currently is only used
+	   to avoid race condition during file creation.
+	   See comment in create_object(). */
+	REISER4_IMMUTABLE = 2,
+	/* inode was read from storage */
+	REISER4_LOADED = 3,
+	/* this bit is set for symlinks. inode->u.generic_ip points to target
+	   name of symlink. */
+	REISER4_GENERIC_PTR_USED = 4,
+	/* set if size of stat-data item for this inode is known. If this is
+	 * set we can avoid recalculating size of stat-data on each update. */
+	REISER4_SDLEN_KNOWN = 5,
+	/* reiser4_inode->crypt points to the crypto stat */
+	REISER4_CRYPTO_STAT_LOADED = 6,
+	/* cryptcompress_inode_data points to the secret key */
+	REISER4_SECRET_KEY_INSTALLED = 7,
+	/* File (possibly) has pages corresponding to the tail items, that
+	 * were created by ->readpage. It is set by mmap_unix_file() and
+	 * sendfile_unix_file(). This bit is inspected by write_unix_file and
+	 * kill-hook of tail items. It is never cleared once set. This bit is
+	 * modified and inspected under i_mutex. */
+	REISER4_HAS_MMAP = 8,
+	/* file was partially converted. It's body consists of a mix of tail
+	 * and extent items. */
+	REISER4_PART_CONV = 9,
+} reiser4_file_plugin_flags;
+
+/* state associated with each inode.
+   reiser4 inode.
+
+   NOTE-NIKITA In 2.5 kernels it is not necessary that all file-system inodes
+   be of the same size. File-system allocates inodes by itself through
+   s_op->allocate_inode() method. So, it is possible to adjust size of inode
+   at the time of its creation.
+
+   Invariants involving parts of this data-type:
+
+      [inode->eflushed]
+
+*/
+
+typedef struct reiser4_inode reiser4_inode;
+/* return pointer to reiser4-specific part of inode */
+static inline reiser4_inode *reiser4_inode_data(const struct inode *inode
+						/* inode queried */ );
+
+#if BITS_PER_LONG == 64
+
+#define REISER4_INO_IS_OID (1)
+typedef struct {;
+} oid_hi_t;
+
+/* BITS_PER_LONG == 64 */
+#else
+
+#define REISER4_INO_IS_OID (0)
+typedef __u32 oid_hi_t;
+
+/* BITS_PER_LONG == 64 */
+#endif
+
+struct reiser4_inode {
+	/* spin lock protecting fields of this structure. */
+	spinlock_t guard;
+	/* object plugins */
+	plugin_set *pset;
+	/* plugins set for inheritance */
+	plugin_set *hset;
+	/* high 32 bits of object id */
+	oid_hi_t oid_hi;
+	/* seal for stat-data */
+	seal_t sd_seal;
+	/* locality id for this file */
+	oid_t locality_id;
+#if REISER4_LARGE_KEY
+	__u64 ordering;
+#endif
+	/* coord of stat-data in sealed node */
+	coord_t sd_coord;
+	/* bit-mask of stat-data extentions used by this file */
+	__u64 extmask;
+	/* bitmask of non-default plugins for this inode */
+	__u16 plugin_mask;
+	union {
+		struct list_head readdir_list;
+		struct list_head not_used;
+	} lists;
+	/* per-inode flags. Filled by values of reiser4_file_plugin_flags */
+	unsigned long flags;
+	union {
+		/* fields specific to unix_file plugin */
+		unix_file_info_t unix_file_info;
+		/* fields specific to cryptcompress plugin */
+		cryptcompress_info_t cryptcompress_info;
+	} file_plugin_data;
+	struct rw_semaphore coc_sem;	/* filemap_nopage takes it for read, copy_on_capture - for write. Under this it
+					   tries to unmap page for which it is called. This prevents process from using page which
+					   was copied on capture */
+
+	/* tree of jnodes. Phantom jnodes (ones not attched to any atom) are
+	   tagged in that tree by EFLUSH_TAG_ANONYMOUS */
+	struct radix_tree_root jnodes_tree;
+#if REISER4_DEBUG
+	/* number of unformatted node jnodes of this file in jnode hash table */
+	unsigned long nr_jnodes;
+#endif
+
+	/* block number of virtual root for this object. See comment above
+	 * fs/reiser4/search.c:handle_vroot() */
+	reiser4_block_nr vroot;
+	struct semaphore loading;
+};
+
+void loading_init_once(reiser4_inode *);
+void loading_alloc(reiser4_inode *);
+void loading_destroy(reiser4_inode *);
+
+typedef struct reiser4_inode_object {
+	/* private part */
+	reiser4_inode p;
+	/* generic fields not specific to reiser4, but used by VFS */
+	struct inode vfs_inode;
+} reiser4_inode_object;
+
+/* return pointer to the reiser4 specific portion of @inode */
+static inline reiser4_inode *reiser4_inode_data(const struct inode *inode
+						/* inode queried */ )
+{
+	assert("nikita-254", inode != NULL);
+	return &container_of(inode, reiser4_inode_object, vfs_inode)->p;
+}
+
+static inline struct inode *inode_by_reiser4_inode(const reiser4_inode *
+						   r4_inode /* inode queried */
+						   )
+{
+	return &container_of(r4_inode, reiser4_inode_object, p)->vfs_inode;
+}
+
+/*
+ * reiser4 inodes are identified by 64bit object-id (oid_t), but in struct
+ * inode ->i_ino field is of type ino_t (long) that can be either 32 or 64
+ * bits.
+ *
+ * If ->i_ino is 32 bits we store remaining 32 bits in reiser4 specific part
+ * of inode, otherwise whole oid is stored in i_ino.
+ *
+ * Wrappers below ([sg]et_inode_oid()) are used to hide this difference.
+ */
+
+#define OID_HI_SHIFT (sizeof(ino_t) * 8)
+
+#if REISER4_INO_IS_OID
+
+static inline oid_t get_inode_oid(const struct inode *inode)
+{
+	return inode->i_ino;
+}
+
+static inline void set_inode_oid(struct inode *inode, oid_t oid)
+{
+	inode->i_ino = oid;
+}
+
+/* REISER4_INO_IS_OID */
+#else
+
+static inline oid_t get_inode_oid(const struct inode *inode)
+{
+	return
+	    ((__u64) reiser4_inode_data(inode)->oid_hi << OID_HI_SHIFT) |
+	    inode->i_ino;
+}
+
+static inline void set_inode_oid(struct inode *inode, oid_t oid)
+{
+	assert("nikita-2519", inode != NULL);
+	inode->i_ino = (ino_t) (oid);
+	reiser4_inode_data(inode)->oid_hi = (oid) >> OID_HI_SHIFT;
+	assert("nikita-2521", get_inode_oid(inode) == (oid));
+}
+
+/* REISER4_INO_IS_OID */
+#endif
+
+static inline oid_t get_inode_locality(const struct inode *inode)
+{
+	return reiser4_inode_data(inode)->locality_id;
+}
+
+#if REISER4_LARGE_KEY
+static inline __u64 get_inode_ordering(const struct inode *inode)
+{
+	return reiser4_inode_data(inode)->ordering;
+}
+
+static inline void set_inode_ordering(const struct inode *inode, __u64 ordering)
+{
+	reiser4_inode_data(inode)->ordering = ordering;
+}
+
+#else
+
+#define get_inode_ordering(inode) (0)
+#define set_inode_ordering(inode, val) noop
+
+#endif
+
+/* return inode in which @uf_info is embedded */
+static inline struct inode *unix_file_info_to_inode(const unix_file_info_t *
+						    uf_info)
+{
+	return &container_of(uf_info, reiser4_inode_object,
+			     p.file_plugin_data.unix_file_info)->vfs_inode;
+}
+
+
+extern ino_t oid_to_ino(oid_t oid) __attribute__ ((const));
+extern ino_t oid_to_uino(oid_t oid) __attribute__ ((const));
+
+extern reiser4_tree *tree_by_inode(const struct inode *inode);
+
+#if REISER4_DEBUG
+extern void inode_invariant(const struct inode *inode);
+extern int inode_has_no_jnodes(reiser4_inode *);
+#else
+#define inode_invariant(inode) noop
+#endif
+
+static inline int spin_inode_is_locked(const struct inode *inode)
+{
+	assert_spin_locked(&reiser4_inode_data(inode)->guard);
+	return 1;
+}
+
+/**
+ * spin_lock_inode - lock reiser4_inode' embedded spinlock
+ * @inode: inode to lock
+ *
+ * In debug mode it checks that lower priority locks are not held and
+ * increments reiser4_context's lock counters on which lock ordering checking
+ * is based.
+ */
+static inline void spin_lock_inode(struct inode *inode)
+{
+	assert("", LOCK_CNT_NIL(spin_locked));
+	/* check lock ordering */
+	assert_spin_not_locked(&d_lock);
+
+	spin_lock(&reiser4_inode_data(inode)->guard);
+
+	LOCK_CNT_INC(spin_locked_inode);
+	LOCK_CNT_INC(spin_locked);
+
+	inode_invariant(inode);
+}
+
+/**
+ * spin_unlock_inode - unlock reiser4_inode' embedded spinlock
+ * @inode: inode to unlock
+ *
+ * In debug mode it checks that spinlock is held and decrements
+ * reiser4_context's lock counters on which lock ordering checking is based.
+ */
+static inline void spin_unlock_inode(struct inode *inode)
+{
+	assert_spin_locked(&reiser4_inode_data(inode)->guard);
+	assert("nikita-1375", LOCK_CNT_GTZ(spin_locked_inode));
+	assert("nikita-1376", LOCK_CNT_GTZ(spin_locked));
+
+	inode_invariant(inode);
+
+	LOCK_CNT_DEC(spin_locked_inode);
+	LOCK_CNT_DEC(spin_locked);
+
+	spin_unlock(&reiser4_inode_data(inode)->guard);
+}
+
+
+extern znode *inode_get_vroot(struct inode *inode);
+extern void inode_set_vroot(struct inode *inode, znode * vroot);
+
+extern int reiser4_max_filename_len(const struct inode *inode);
+extern int max_hash_collisions(const struct inode *dir);
+extern void reiser4_unlock_inode(struct inode *inode);
+extern int is_reiser4_inode(const struct inode *inode);
+extern int setup_inode_ops(struct inode *inode, reiser4_object_create_data *);
+extern struct inode *reiser4_iget(struct super_block *super,
+				  const reiser4_key * key, int silent);
+extern void reiser4_iget_complete(struct inode *inode);
+extern void inode_set_flag(struct inode *inode, reiser4_file_plugin_flags f);
+extern void inode_clr_flag(struct inode *inode, reiser4_file_plugin_flags f);
+extern int inode_get_flag(const struct inode *inode,
+			  reiser4_file_plugin_flags f);
+
+/*  has inode been initialized? */
+static inline int
+is_inode_loaded(const struct inode *inode /* inode queried */ )
+{
+	assert("nikita-1120", inode != NULL);
+	return inode_get_flag(inode, REISER4_LOADED);
+}
+
+extern file_plugin *inode_file_plugin(const struct inode *inode);
+extern dir_plugin *inode_dir_plugin(const struct inode *inode);
+extern perm_plugin *inode_perm_plugin(const struct inode *inode);
+extern formatting_plugin *inode_formatting_plugin(const struct inode *inode);
+extern hash_plugin *inode_hash_plugin(const struct inode *inode);
+extern fibration_plugin *inode_fibration_plugin(const struct inode *inode);
+extern cipher_plugin *inode_cipher_plugin(const struct inode *inode);
+extern digest_plugin *inode_digest_plugin(const struct inode *inode);
+extern compression_plugin *inode_compression_plugin(const struct inode *inode);
+extern compression_mode_plugin *inode_compression_mode_plugin(const struct inode
+							      *inode);
+extern cluster_plugin *inode_cluster_plugin(const struct inode *inode);
+extern regular_plugin *inode_regular_plugin(const struct inode *inode);
+extern item_plugin *inode_sd_plugin(const struct inode *inode);
+extern item_plugin *inode_dir_item_plugin(const struct inode *inode);
+
+extern void inode_set_plugin(struct inode *inode,
+			     reiser4_plugin * plug, pset_member memb);
+extern void reiser4_make_bad_inode(struct inode *inode);
+
+extern void inode_set_extension(struct inode *inode, sd_ext_bits ext);
+extern void inode_check_scale(struct inode *inode, __u64 old, __u64 new);
+extern void inode_check_scale_nolock(struct inode * inode, __u64 old, __u64 new);
+
+/*
+ * update field @field in inode @i to contain value @value.
+ */
+#define INODE_SET_FIELD(i, field, value)		\
+({							\
+	struct inode *__i;				\
+	typeof(value) __v;				\
+							\
+	__i = (i);					\
+	__v = (value);					\
+	inode_check_scale(__i, __i->field, __v);	\
+	__i->field = __v;				\
+})
+
+#define INODE_INC_FIELD(i, field)				\
+({								\
+	struct inode *__i;					\
+								\
+	__i = (i);						\
+	inode_check_scale(__i, __i->field, __i->field + 1);	\
+	++ __i->field;						\
+})
+
+#define INODE_DEC_FIELD(i, field)				\
+({								\
+	struct inode *__i;					\
+								\
+	__i = (i);						\
+	inode_check_scale(__i, __i->field, __i->field - 1);	\
+	-- __i->field;						\
+})
+
+/* See comment before readdir_common() for description. */
+static inline struct list_head *get_readdir_list(const struct inode *inode)
+{
+	return &reiser4_inode_data(inode)->lists.readdir_list;
+}
+
+extern void init_inode_ordering(struct inode *inode,
+				reiser4_object_create_data * crd, int create);
+
+static inline struct radix_tree_root *jnode_tree_by_inode(struct inode *inode)
+{
+	return &reiser4_inode_data(inode)->jnodes_tree;
+}
+
+static inline struct radix_tree_root *jnode_tree_by_reiser4_inode(reiser4_inode
+								  * r4_inode)
+{
+	return &r4_inode->jnodes_tree;
+}
+
+#if REISER4_DEBUG
+extern void print_inode(const char *prefix, const struct inode *i);
+#endif
+
+int is_dir_empty(const struct inode *);
+
+/* __REISER4_INODE_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/ioctl.h newtree/fs/reiser4/ioctl.h
--- oldtree/fs/reiser4/ioctl.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/ioctl.h	2006-02-21 15:58:33.998977928 +0000
@@ -0,0 +1,41 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+#if !defined( __REISER4_IOCTL_H__ )
+#define __REISER4_IOCTL_H__
+
+#include <linux/fs.h>
+
+/*
+ * ioctl(2) command used to "unpack" reiser4 file, that is, convert it into
+ * extents and fix in this state. This is used by applications that rely on
+ *
+ *     . files being block aligned, and
+ *
+ *     . files never migrating on disk
+ *
+ * for example, boot loaders (LILO) need this.
+ *
+ * This ioctl should be used as
+ *
+ *     result = ioctl(fd, REISER4_IOC_UNPACK);
+ *
+ * File behind fd descriptor will be converted to the extents (if necessary),
+ * and its stat-data will be updated so that it will never be converted back
+ * into tails again.
+ */
+#define REISER4_IOC_UNPACK _IOW(0xCD,1,long)
+
+/* __REISER4_IOCTL_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/jnode.c newtree/fs/reiser4/jnode.c
--- oldtree/fs/reiser4/jnode.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/jnode.c	2006-02-21 15:58:35.436759352 +0000
@@ -0,0 +1,1954 @@
+/* Copyright 2001, 2002, 2003, 2004 by Hans Reiser, licensing governed by
+ * reiser4/README */
+/* Jnode manipulation functions. */
+/* Jnode is entity used to track blocks with data and meta-data in reiser4.
+
+   In particular, jnodes are used to track transactional information
+   associated with each block. Each znode contains jnode as ->zjnode field.
+
+   Jnode stands for either Josh or Journal node.
+*/
+
+/*
+ * Taxonomy.
+ *
+ *     Jnode represents block containing data or meta-data. There are jnodes
+ *     for:
+ *
+ *         unformatted blocks (jnodes proper). There are plans, however to
+ *         have a handle per extent unit rather than per each unformatted
+ *         block, because there are so many of them.
+ *
+ *         For bitmaps. Each bitmap is actually represented by two jnodes--one
+ *         for working and another for "commit" data, together forming bnode.
+ *
+ *         For io-heads. These are used by log writer.
+ *
+ *         For formatted nodes (znode). See comment at the top of znode.c for
+ *         details specific to the formatted nodes (znodes).
+ *
+ * Node data.
+ *
+ *     Jnode provides access to the data of node it represents. Data are
+ *     stored in a page. Page is kept in a page cache. This means, that jnodes
+ *     are highly interconnected with page cache and VM internals.
+ *
+ *     jnode has a pointer to page (->pg) containing its data. Pointer to data
+ *     themselves is cached in ->data field to avoid frequent calls to
+ *     page_address().
+ *
+ *     jnode and page are attached to each other by jnode_attach_page(). This
+ *     function places pointer to jnode in set_page_private(), sets PG_private
+ *     flag and increments page counter.
+ *
+ *     Opposite operation is performed by page_clear_jnode().
+ *
+ *     jnode->pg is protected by jnode spin lock, and page->private is
+ *     protected by page lock. See comment at the top of page_cache.c for
+ *     more.
+ *
+ *     page can be detached from jnode for two reasons:
+ *
+ *         . jnode is removed from a tree (file is truncated, of formatted
+ *         node is removed by balancing).
+ *
+ *         . during memory pressure, VM calls ->releasepage() method
+ *         (reiser4_releasepage()) to evict page from memory.
+ *
+ *    (there, of course, is also umount, but this is special case we are not
+ *    concerned with here).
+ *
+ *    To protect jnode page from eviction, one calls jload() function that
+ *    "pins" page in memory (loading it if necessary), increments
+ *    jnode->d_count, and kmap()s page. Page is unpinned through call to
+ *    jrelse().
+ *
+ * Jnode life cycle.
+ *
+ *    jnode is created, placed in hash table, and, optionally, in per-inode
+ *    radix tree. Page can be attached to jnode, pinned, released, etc.
+ *
+ *    When jnode is captured into atom its reference counter is
+ *    increased. While being part of an atom, jnode can be "early
+ *    flushed". This means that as part of flush procedure, jnode is placed
+ *    into "relocate set", and its page is submitted to the disk. After io
+ *    completes, page can be detached, then loaded again, re-dirtied, etc.
+ *
+ *    Thread acquired reference to jnode by calling jref() and releases it by
+ *    jput(). When last reference is removed, jnode is still retained in
+ *    memory (cached) if it has page attached, _unless_ it is scheduled for
+ *    destruction (has JNODE_HEARD_BANSHEE bit set).
+ *
+ *    Tree read-write lock was used as "existential" lock for jnodes. That is,
+ *    jnode->x_count could be changed from 0 to 1 only under tree write lock,
+ *    that is, tree lock protected unreferenced jnodes stored in the hash
+ *    table, from recycling.
+ *
+ *    This resulted in high contention on tree lock, because jref()/jput() is
+ *    frequent operation. To ameliorate this problem, RCU is used: when jput()
+ *    is just about to release last reference on jnode it sets JNODE_RIP bit
+ *    on it, and then proceed with jnode destruction (removing jnode from hash
+ *    table, cbk_cache, detaching page, etc.). All places that change jnode
+ *    reference counter from 0 to 1 (jlookup(), zlook(), zget(), and
+ *    cbk_cache_scan_slots()) check for JNODE_RIP bit (this is done by
+ *    jnode_rip_check() function), and pretend that nothing was found in hash
+ *    table if bit is set.
+ *
+ *    jput defers actual return of jnode into slab cache to some later time
+ *    (by call_rcu()), this guarantees that other threads can safely continue
+ *    working with JNODE_RIP-ped jnode.
+ *
+ */
+
+#include "reiser4.h"
+#include "debug.h"
+#include "dformat.h"
+#include "jnode.h"
+#include "plugin/plugin_header.h"
+#include "plugin/plugin.h"
+#include "txnmgr.h"
+/*#include "jnode.h"*/
+#include "znode.h"
+#include "tree.h"
+#include "tree_walk.h"
+#include "super.h"
+#include "inode.h"
+#include "page_cache.h"
+
+#include <asm/uaccess.h>	/* UML needs this for PAGE_OFFSET */
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/vmalloc.h>	/* for vmalloc(), vfree() */
+#include <linux/swap.h>
+#include <linux/fs.h>		/* for struct address_space  */
+#include <linux/writeback.h>	/* for inode_lock */
+
+static kmem_cache_t *_jnode_slab = NULL;
+
+static void jnode_set_type(jnode * node, jnode_type type);
+static int jdelete(jnode * node);
+static int jnode_try_drop(jnode * node);
+
+#if REISER4_DEBUG
+static int jnode_invariant(const jnode * node, int tlocked, int jlocked);
+#endif
+
+/* true if valid page is attached to jnode */
+static inline int jnode_is_parsed(jnode * node)
+{
+	return JF_ISSET(node, JNODE_PARSED);
+}
+
+/* hash table support */
+
+/* compare two jnode keys for equality. Used by hash-table macros */
+static inline int jnode_key_eq(const jnode_key_t * k1, const jnode_key_t * k2)
+{
+	assert("nikita-2350", k1 != NULL);
+	assert("nikita-2351", k2 != NULL);
+
+	return (k1->index == k2->index && k1->objectid == k2->objectid);
+}
+
+/* Hash jnode by its key (inode plus offset). Used by hash-table macros */
+static inline __u32
+jnode_key_hashfn(j_hash_table * table, const jnode_key_t * key)
+{
+	assert("nikita-2352", key != NULL);
+	assert("nikita-3346", IS_POW(table->_buckets));
+
+	/* yes, this is remarkable simply (where not stupid) hash function. */
+	return (key->objectid + key->index) & (table->_buckets - 1);
+}
+
+/* The hash table definition */
+#define KMALLOC(size) vmalloc(size)
+#define KFREE(ptr, size) vfree(ptr)
+TYPE_SAFE_HASH_DEFINE(j, jnode, jnode_key_t, key.j, link.j, jnode_key_hashfn,
+		      jnode_key_eq);
+#undef KFREE
+#undef KMALLOC
+
+/* call this to initialise jnode hash table */
+int jnodes_tree_init(reiser4_tree * tree /* tree to initialise jnodes for */ )
+{
+	assert("nikita-2359", tree != NULL);
+	return j_hash_init(&tree->jhash_table, 16384);
+}
+
+/* call this to destroy jnode hash table. This is called during umount. */
+int jnodes_tree_done(reiser4_tree * tree /* tree to destroy jnodes for */ )
+{
+	j_hash_table *jtable;
+	jnode *node;
+	jnode *next;
+
+	assert("nikita-2360", tree != NULL);
+
+	/*
+	 * Scan hash table and free all jnodes.
+	 */
+	jtable = &tree->jhash_table;
+	if (jtable->_table) {
+		for_all_in_htable(jtable, j, node, next) {
+			assert("nikita-2361", !atomic_read(&node->x_count));
+			jdrop(node);
+		}
+
+		j_hash_done(&tree->jhash_table);
+	}
+	return 0;
+}
+
+/**
+ * init_jnodes - create jnode cache
+ *
+ * Initializes slab cache jnodes. It is part of reiser4 module initialization.
+ */
+int init_jnodes(void)
+{
+	assert("umka-168", _jnode_slab == NULL);
+
+	_jnode_slab = kmem_cache_create("jnode", sizeof(jnode), 0,
+					SLAB_HWCACHE_ALIGN |
+					SLAB_RECLAIM_ACCOUNT, NULL, NULL);
+	if (_jnode_slab == NULL)
+		return RETERR(-ENOMEM);
+
+	return 0;
+}
+
+/**
+ * done_znodes - delete znode cache
+ *
+ * This is called on reiser4 module unloading or system shutdown.
+ */
+void done_jnodes(void)
+{
+	destroy_reiser4_cache(&_jnode_slab);
+}
+
+/* Initialize a jnode. */
+void jnode_init(jnode * node, reiser4_tree * tree, jnode_type type)
+{
+	assert("umka-175", node != NULL);
+
+	memset(node, 0, sizeof(jnode));
+	ON_DEBUG(node->magic = JMAGIC);
+	jnode_set_type(node, type);
+	atomic_set(&node->d_count, 0);
+	atomic_set(&node->x_count, 0);
+	spin_lock_init(&node->guard);
+	spin_lock_init(&node->load);
+	node->atom = NULL;
+	node->tree = tree;
+	INIT_LIST_HEAD(&node->capture_link);
+
+	ASSIGN_NODE_LIST(node, NOT_CAPTURED);
+
+	INIT_RCU_HEAD(&node->rcu);
+
+#if REISER4_DEBUG
+	{
+		reiser4_super_info_data *sbinfo;
+
+		sbinfo = get_super_private(tree->super);
+		spin_lock_irq(&sbinfo->all_guard);
+		list_add(&node->jnodes, &sbinfo->all_jnodes);
+		spin_unlock_irq(&sbinfo->all_guard);
+	}
+#endif
+}
+
+#if REISER4_DEBUG
+/*
+ * Remove jnode from ->all_jnodes list.
+ */
+static void jnode_done(jnode * node, reiser4_tree * tree)
+{
+	reiser4_super_info_data *sbinfo;
+
+	sbinfo = get_super_private(tree->super);
+
+	spin_lock_irq(&sbinfo->all_guard);
+	assert("nikita-2422", !list_empty(&node->jnodes));
+	list_del_init(&node->jnodes);
+	spin_unlock_irq(&sbinfo->all_guard);
+}
+#endif
+
+/* return already existing jnode of page */
+jnode *jnode_by_page(struct page *pg)
+{
+	assert("nikita-2066", pg != NULL);
+	assert("nikita-2400", PageLocked(pg));
+	assert("nikita-2068", PagePrivate(pg));
+	assert("nikita-2067", jprivate(pg) != NULL);
+	return jprivate(pg);
+}
+
+/* exported functions to allocate/free jnode objects outside this file */
+jnode *jalloc(void)
+{
+	jnode *jal = kmem_cache_alloc(_jnode_slab, GFP_KERNEL);
+	return jal;
+}
+
+/* return jnode back to the slab allocator */
+inline void jfree(jnode * node)
+{
+	assert("zam-449", node != NULL);
+
+	assert("nikita-2663", (list_empty_careful(&node->capture_link) &&
+			       NODE_LIST(node) == NOT_CAPTURED));
+	assert("nikita-2774", !JF_ISSET(node, JNODE_EFLUSH));
+	assert("nikita-3222", list_empty(&node->jnodes));
+	assert("nikita-3221", jnode_page(node) == NULL);
+
+	/* not yet phash_jnode_destroy(node); */
+
+	kmem_cache_free(_jnode_slab, node);
+}
+
+/*
+ * This function is supplied as RCU callback. It actually frees jnode when
+ * last reference to it is gone.
+ */
+static void jnode_free_actor(struct rcu_head *head)
+{
+	jnode *node;
+	jnode_type jtype;
+
+	node = container_of(head, jnode, rcu);
+	jtype = jnode_get_type(node);
+
+	ON_DEBUG(jnode_done(node, jnode_get_tree(node)));
+
+	switch (jtype) {
+	case JNODE_IO_HEAD:
+	case JNODE_BITMAP:
+	case JNODE_UNFORMATTED_BLOCK:
+		jfree(node);
+		break;
+	case JNODE_FORMATTED_BLOCK:
+		zfree(JZNODE(node));
+		break;
+	case JNODE_INODE:
+	default:
+		wrong_return_value("nikita-3197", "Wrong jnode type");
+	}
+}
+
+/*
+ * Free a jnode. Post a callback to be executed later through RCU when all
+ * references to @node are released.
+ */
+static inline void jnode_free(jnode * node, jnode_type jtype)
+{
+	if (jtype != JNODE_INODE) {
+		/*assert("nikita-3219", list_empty(&node->rcu.list)); */
+		call_rcu(&node->rcu, jnode_free_actor);
+	} else
+		jnode_list_remove(node);
+}
+
+/* allocate new unformatted jnode */
+static jnode *jnew_unformatted(void)
+{
+	jnode *jal;
+
+	jal = jalloc();
+	if (jal == NULL)
+		return NULL;
+
+	jnode_init(jal, current_tree, JNODE_UNFORMATTED_BLOCK);
+	jal->key.j.mapping = NULL;
+	jal->key.j.index = (unsigned long)-1;
+	jal->key.j.objectid = 0;
+	return jal;
+}
+
+/* look for jnode with given mapping and offset within hash table */
+jnode *jlookup(reiser4_tree * tree, oid_t objectid, unsigned long index)
+{
+	jnode_key_t jkey;
+	jnode *node;
+
+	assert("nikita-2353", tree != NULL);
+
+	jkey.objectid = objectid;
+	jkey.index = index;
+
+	/*
+	 * hash table is _not_ protected by any lock during lookups. All we
+	 * have to do is to disable preemption to keep RCU happy.
+	 */
+
+	rcu_read_lock();
+	node = j_hash_find(&tree->jhash_table, &jkey);
+	if (node != NULL) {
+		/* protect @node from recycling */
+		jref(node);
+		assert("nikita-2955", jnode_invariant(node, 0, 0));
+		node = jnode_rip_check(tree, node);
+	}
+	rcu_read_unlock();
+	return node;
+}
+
+/* per inode radix tree of jnodes is protected by tree's read write spin lock */
+static jnode *jfind_nolock(struct address_space *mapping, unsigned long index)
+{
+	assert("vs-1694", mapping->host != NULL);
+
+	return radix_tree_lookup(jnode_tree_by_inode(mapping->host), index);
+}
+
+jnode *jfind(struct address_space * mapping, unsigned long index)
+{
+	reiser4_tree *tree;
+	jnode *node;
+
+	assert("vs-1694", mapping->host != NULL);
+	tree = tree_by_inode(mapping->host);
+
+	read_lock_tree(tree);
+	node = jfind_nolock(mapping, index);
+	if (node != NULL)
+		jref(node);
+	read_unlock_tree(tree);
+	return node;
+}
+
+static void inode_attach_jnode(jnode * node)
+{
+	struct inode *inode;
+	reiser4_inode *info;
+	struct radix_tree_root *rtree;
+
+	assert_rw_write_locked(&(jnode_get_tree(node)->tree_lock));
+	assert("zam-1043", node->key.j.mapping != NULL);
+	inode = node->key.j.mapping->host;
+	info = reiser4_inode_data(inode);
+	rtree = jnode_tree_by_reiser4_inode(info);
+	if (rtree->height == 0) {
+		/* prevent inode from being pruned when it has jnodes attached
+		   to it */
+		write_lock_irq(&inode->i_data.tree_lock);
+		inode->i_data.nrpages++;
+		write_unlock_irq(&inode->i_data.tree_lock);
+	}
+	assert("zam-1049", equi(rtree->rnode != NULL, info->nr_jnodes != 0));
+	check_me("zam-1045",
+		 !radix_tree_insert(rtree, node->key.j.index, node));
+	ON_DEBUG(info->nr_jnodes++);
+}
+
+static void inode_detach_jnode(jnode * node)
+{
+	struct inode *inode;
+	reiser4_inode *info;
+	struct radix_tree_root *rtree;
+
+	assert_rw_write_locked(&(jnode_get_tree(node)->tree_lock));
+	assert("zam-1044", node->key.j.mapping != NULL);
+	inode = node->key.j.mapping->host;
+	info = reiser4_inode_data(inode);
+	rtree = jnode_tree_by_reiser4_inode(info);
+
+	assert("zam-1051", info->nr_jnodes != 0);
+	assert("zam-1052", rtree->rnode != NULL);
+	assert("vs-1730", !JF_ISSET(node, JNODE_EFLUSH));
+	ON_DEBUG(info->nr_jnodes--);
+
+	/* delete jnode from inode's radix tree of jnodes */
+	check_me("zam-1046", radix_tree_delete(rtree, node->key.j.index));
+	if (rtree->height == 0) {
+		/* inode can be pruned now */
+		write_lock_irq(&inode->i_data.tree_lock);
+		inode->i_data.nrpages--;
+		write_unlock_irq(&inode->i_data.tree_lock);
+	}
+}
+
+/* put jnode into hash table (where they can be found by flush who does not know
+   mapping) and to inode's tree of jnodes (where they can be found (hopefully
+   faster) in places where mapping is known). Currently it is used by
+   fs/reiser4/plugin/item/extent_file_ops.c:index_extent_jnode when new jnode is
+   created */
+static void
+hash_unformatted_jnode(jnode * node, struct address_space *mapping,
+		       unsigned long index)
+{
+	j_hash_table *jtable;
+
+	assert("vs-1446", jnode_is_unformatted(node));
+	assert("vs-1442", node->key.j.mapping == 0);
+	assert("vs-1443", node->key.j.objectid == 0);
+	assert("vs-1444", node->key.j.index == (unsigned long)-1);
+	assert_rw_write_locked(&(jnode_get_tree(node)->tree_lock));
+
+	node->key.j.mapping = mapping;
+	node->key.j.objectid = get_inode_oid(mapping->host);
+	node->key.j.index = index;
+
+	jtable = &jnode_get_tree(node)->jhash_table;
+
+	/* race with some other thread inserting jnode into the hash table is
+	 * impossible, because we keep the page lock. */
+	/*
+	 * following assertion no longer holds because of RCU: it is possible
+	 * jnode is in the hash table, but with JNODE_RIP bit set.
+	 */
+	/* assert("nikita-3211", j_hash_find(jtable, &node->key.j) == NULL); */
+	j_hash_insert_rcu(jtable, node);
+	inode_attach_jnode(node);
+}
+
+static void unhash_unformatted_node_nolock(jnode * node)
+{
+	assert("vs-1683", node->key.j.mapping != NULL);
+	assert("vs-1684",
+	       node->key.j.objectid ==
+	       get_inode_oid(node->key.j.mapping->host));
+
+	/* remove jnode from hash-table */
+	j_hash_remove_rcu(&node->tree->jhash_table, node);
+	inode_detach_jnode(node);
+	node->key.j.mapping = NULL;
+	node->key.j.index = (unsigned long)-1;
+	node->key.j.objectid = 0;
+
+}
+
+/* remove jnode from hash table and from inode's tree of jnodes. This is used in
+   reiser4_invalidatepage and in kill_hook_extent -> truncate_inode_jnodes ->
+   uncapture_jnode */
+void unhash_unformatted_jnode(jnode * node)
+{
+	assert("vs-1445", jnode_is_unformatted(node));
+
+	write_lock_tree(node->tree);
+	unhash_unformatted_node_nolock(node);
+	write_unlock_tree(node->tree);
+}
+
+/*
+ * search hash table for a jnode with given oid and index. If not found,
+ * allocate new jnode, insert it, and also insert into radix tree for the
+ * given inode/mapping.
+ */
+jnode *find_get_jnode(reiser4_tree * tree, struct address_space *mapping,
+		      oid_t oid, unsigned long index)
+{
+	jnode *result;
+	jnode *shadow;
+	int preload;
+
+	result = jnew_unformatted();
+
+	if (unlikely(result == NULL))
+		return ERR_PTR(RETERR(-ENOMEM));
+
+	preload = radix_tree_preload(GFP_KERNEL);
+	if (preload != 0)
+		return ERR_PTR(preload);
+
+	write_lock_tree(tree);
+	shadow = jfind_nolock(mapping, index);
+	if (likely(shadow == NULL)) {
+		/* add new jnode to hash table and inode's radix tree of jnodes */
+		jref(result);
+		hash_unformatted_jnode(result, mapping, index);
+	} else {
+		/* jnode is found in inode's radix tree of jnodes */
+		jref(shadow);
+		jnode_free(result, JNODE_UNFORMATTED_BLOCK);
+		assert("vs-1498", shadow->key.j.mapping == mapping);
+		result = shadow;
+	}
+	write_unlock_tree(tree);
+
+	assert("nikita-2955",
+	       ergo(result != NULL, jnode_invariant(result, 0, 0)));
+	radix_tree_preload_end();
+	return result;
+}
+
+/* jget() (a la zget() but for unformatted nodes). Returns (and possibly
+   creates) jnode corresponding to page @pg. jnode is attached to page and
+   inserted into jnode hash-table. */
+static jnode *do_jget(reiser4_tree * tree, struct page *pg)
+{
+	/*
+	 * There are two ways to create jnode: starting with pre-existing page
+	 * and without page.
+	 *
+	 * When page already exists, jnode is created
+	 * (jnode_of_page()->do_jget()) under page lock. This is done in
+	 * ->writepage(), or when capturing anonymous page dirtied through
+	 * mmap.
+	 *
+	 * Jnode without page is created by index_extent_jnode().
+	 *
+	 */
+
+	jnode *result;
+	oid_t oid = get_inode_oid(pg->mapping->host);
+
+	assert("umka-176", pg != NULL);
+	assert("nikita-2394", PageLocked(pg));
+
+	result = jprivate(pg);
+	if (likely(result != NULL))
+		return jref(result);
+
+	tree = tree_by_page(pg);
+
+	/* check hash-table first */
+	result = jfind(pg->mapping, pg->index);
+	if (unlikely(result != NULL)) {
+		spin_lock_jnode(result);
+		jnode_attach_page(result, pg);
+		spin_unlock_jnode(result);
+		result->key.j.mapping = pg->mapping;
+		return result;
+	}
+
+	result = find_get_jnode(tree, pg->mapping, oid, pg->index);
+	if (unlikely(IS_ERR(result)))
+		return result;
+	/* attach jnode to page */
+	spin_lock_jnode(result);
+	jnode_attach_page(result, pg);
+	spin_unlock_jnode(result);
+	return result;
+}
+
+/*
+ * return jnode for @pg, creating it if necessary.
+ */
+jnode *jnode_of_page(struct page * pg)
+{
+	jnode *result;
+
+	assert("umka-176", pg != NULL);
+	assert("nikita-2394", PageLocked(pg));
+
+	result = do_jget(tree_by_page(pg), pg);
+
+	if (REISER4_DEBUG && !IS_ERR(result)) {
+		assert("nikita-3210", result == jprivate(pg));
+		assert("nikita-2046", jnode_page(jprivate(pg)) == pg);
+		if (jnode_is_unformatted(jprivate(pg))) {
+			assert("nikita-2364",
+			       jprivate(pg)->key.j.index == pg->index);
+			assert("nikita-2367",
+			       jprivate(pg)->key.j.mapping == pg->mapping);
+			assert("nikita-2365",
+			       jprivate(pg)->key.j.objectid ==
+			       get_inode_oid(pg->mapping->host));
+			assert("vs-1200",
+			       jprivate(pg)->key.j.objectid ==
+			       pg->mapping->host->i_ino);
+			assert("nikita-2356",
+			       jnode_is_unformatted(jnode_by_page(pg)));
+		}
+		assert("nikita-2956", jnode_invariant(jprivate(pg), 0, 0));
+	}
+	return result;
+}
+
+/* attach page to jnode: set ->pg pointer in jnode, and ->private one in the
+ * page.*/
+void jnode_attach_page(jnode * node, struct page *pg)
+{
+	assert("nikita-2060", node != NULL);
+	assert("nikita-2061", pg != NULL);
+
+	assert("nikita-2050", jprivate(pg) == 0ul);
+	assert("nikita-2393", !PagePrivate(pg));
+	assert("vs-1741", node->pg == NULL);
+
+	assert("nikita-2396", PageLocked(pg));
+	assert_spin_locked(&(node->guard));
+
+	page_cache_get(pg);
+	set_page_private(pg, (unsigned long)node);
+	node->pg = pg;
+	SetPagePrivate(pg);
+}
+
+/* Dual to jnode_attach_page: break a binding between page and jnode */
+void page_clear_jnode(struct page *page, jnode * node)
+{
+	assert("nikita-2424", page != NULL);
+	assert("nikita-2425", PageLocked(page));
+	assert("nikita-2426", node != NULL);
+	assert_spin_locked(&(node->guard));
+	assert("nikita-2428", PagePrivate(page));
+
+	assert("nikita-3551", !PageWriteback(page));
+
+	JF_CLR(node, JNODE_PARSED);
+	set_page_private(page, 0ul);
+	ClearPagePrivate(page);
+	node->pg = NULL;
+	page_cache_release(page);
+}
+
+/* it is only used in one place to handle error */
+void
+page_detach_jnode(struct page *page, struct address_space *mapping,
+		  unsigned long index)
+{
+	assert("nikita-2395", page != NULL);
+
+	lock_page(page);
+	if ((page->mapping == mapping) && (page->index == index)
+	    && PagePrivate(page)) {
+		jnode *node;
+
+		node = jprivate(page);
+		spin_lock_jnode(node);
+		page_clear_jnode(page, node);
+		spin_unlock_jnode(node);
+	}
+	unlock_page(page);
+}
+
+/* return @node page locked.
+
+   Locking ordering requires that one first takes page lock and afterwards
+   spin lock on node attached to this page. Sometimes it is necessary to go in
+   the opposite direction. This is done through standard trylock-and-release
+   loop.
+*/
+static struct page *jnode_lock_page(jnode * node)
+{
+	struct page *page;
+
+	assert("nikita-2052", node != NULL);
+	assert("nikita-2401", LOCK_CNT_NIL(spin_locked_jnode));
+
+	while (1) {
+
+		spin_lock_jnode(node);
+		page = jnode_page(node);
+		if (page == NULL) {
+			break;
+		}
+
+		/* no need to page_cache_get( page ) here, because page cannot
+		   be evicted from memory without detaching it from jnode and
+		   this requires spin lock on jnode that we already hold.
+		 */
+		if (!TestSetPageLocked(page)) {
+			/* We won a lock on jnode page, proceed. */
+			break;
+		}
+
+		/* Page is locked by someone else. */
+		page_cache_get(page);
+		spin_unlock_jnode(node);
+		wait_on_page_locked(page);
+		/* it is possible that page was detached from jnode and
+		   returned to the free pool, or re-assigned while we were
+		   waiting on locked bit. This will be rechecked on the next
+		   loop iteration.
+		 */
+		page_cache_release(page);
+
+		/* try again */
+	}
+	return page;
+}
+
+/*
+ * is JNODE_PARSED bit is not set, call ->parse() method of jnode, to verify
+ * validness of jnode content.
+ */
+static inline int jparse(jnode * node)
+{
+	int result;
+
+	assert("nikita-2466", node != NULL);
+
+	spin_lock_jnode(node);
+	if (likely(!jnode_is_parsed(node))) {
+		result = jnode_ops(node)->parse(node);
+		if (likely(result == 0))
+			JF_SET(node, JNODE_PARSED);
+	} else
+		result = 0;
+	spin_unlock_jnode(node);
+	return result;
+}
+
+/* Lock a page attached to jnode, create and attach page to jnode if it had no
+ * one. */
+struct page *jnode_get_page_locked(jnode * node, int gfp_flags)
+{
+	struct page *page;
+
+	spin_lock_jnode(node);
+	page = jnode_page(node);
+
+	if (page == NULL) {
+		spin_unlock_jnode(node);
+		page = find_or_create_page(jnode_get_mapping(node),
+					   jnode_get_index(node), gfp_flags);
+		if (page == NULL)
+			return ERR_PTR(RETERR(-ENOMEM));
+	} else {
+		if (!TestSetPageLocked(page)) {
+			spin_unlock_jnode(node);
+			return page;
+		}
+		page_cache_get(page);
+		spin_unlock_jnode(node);
+		lock_page(page);
+		assert("nikita-3134", page->mapping == jnode_get_mapping(node));
+	}
+
+	spin_lock_jnode(node);
+	if (!jnode_page(node))
+		jnode_attach_page(node, page);
+	spin_unlock_jnode(node);
+
+	page_cache_release(page);
+	assert("zam-894", jnode_page(node) == page);
+	return page;
+}
+
+/* Start read operation for jnode's page if page is not up-to-date. */
+static int jnode_start_read(jnode * node, struct page *page)
+{
+	assert("zam-893", PageLocked(page));
+
+	if (PageUptodate(page)) {
+		unlock_page(page);
+		return 0;
+	}
+	return page_io(page, node, READ, GFP_KERNEL);
+}
+
+#if REISER4_DEBUG
+static void check_jload(jnode * node, struct page *page)
+{
+	if (jnode_is_znode(node)) {
+		node40_header *nh;
+		znode *z;
+
+		z = JZNODE(node);
+		if (znode_is_any_locked(z)) {
+			nh = (node40_header *) kmap(page);
+			/* this only works for node40-only file systems. For
+			 * debugging. */
+			assert("nikita-3253",
+			       z->nr_items == le16_to_cpu(get_unaligned(&nh->nr_items)));
+			kunmap(page);
+		}
+		assert("nikita-3565", znode_invariant(z));
+	}
+}
+#else
+#define check_jload(node, page) noop
+#endif
+
+/* prefetch jnode to speed up next call to jload. Call this when you are going
+ * to call jload() shortly. This will bring appropriate portion of jnode into
+ * CPU cache. */
+void jload_prefetch(jnode * node)
+{
+	prefetchw(&node->x_count);
+}
+
+/* load jnode's data into memory */
+int jload_gfp(jnode * node /* node to load */ ,
+	      int gfp_flags /* allocation flags */ ,
+	      int do_kmap /* true if page should be kmapped */ )
+{
+	struct page *page;
+	int result = 0;
+	int parsed;
+
+	assert("nikita-3010", schedulable());
+
+	prefetchw(&node->pg);
+
+	/* taking d-reference implies taking x-reference. */
+	jref(node);
+
+	/*
+	 * acquiring d-reference to @jnode and check for JNODE_PARSED bit
+	 * should be atomic, otherwise there is a race against
+	 * reiser4_releasepage().
+	 */
+	spin_lock(&(node->load));
+	add_d_ref(node);
+	parsed = jnode_is_parsed(node);
+	spin_unlock(&(node->load));
+
+	if (unlikely(!parsed)) {
+		page = jnode_get_page_locked(node, gfp_flags);
+		if (unlikely(IS_ERR(page))) {
+			result = PTR_ERR(page);
+			goto failed;
+		}
+
+		result = jnode_start_read(node, page);
+		if (unlikely(result != 0))
+			goto failed;
+
+		wait_on_page_locked(page);
+		if (unlikely(!PageUptodate(page))) {
+			result = RETERR(-EIO);
+			goto failed;
+		}
+
+		if (do_kmap)
+			node->data = kmap(page);
+
+		result = jparse(node);
+		if (unlikely(result != 0)) {
+			if (do_kmap)
+				kunmap(page);
+			goto failed;
+		}
+		check_jload(node, page);
+	} else {
+		page = jnode_page(node);
+		check_jload(node, page);
+		if (do_kmap)
+			node->data = kmap(page);
+	}
+
+	if (unlikely(JF_ISSET(node, JNODE_EFLUSH))) {
+		spin_lock_jnode(node);
+		eflush_del(node, 0);
+		spin_unlock_jnode(node);
+	}
+
+	if (!is_writeout_mode())
+		/* We do not mark pages active if jload is called as a part of
+		 * jnode_flush() or reiser4_write_logs().  Both jnode_flush()
+		 * and write_logs() add no value to cached data, there is no
+		 * sense to mark pages as active when they go to disk, it just
+		 * confuses vm scanning routines because clean page could be
+		 * moved out from inactive list as a result of this
+		 * mark_page_accessed() call. */
+		mark_page_accessed(page);
+
+	return 0;
+
+      failed:
+	jrelse_tail(node);
+	return result;
+
+}
+
+/* start asynchronous reading for given jnode's page. */
+int jstartio(jnode * node)
+{
+	struct page *page;
+
+	page = jnode_get_page_locked(node, GFP_KERNEL);
+	if (IS_ERR(page))
+		return PTR_ERR(page);
+
+	return jnode_start_read(node, page);
+}
+
+/* Initialize a node by calling appropriate plugin instead of reading
+ * node from disk as in jload(). */
+int jinit_new(jnode * node, int gfp_flags)
+{
+	struct page *page;
+	int result;
+
+	jref(node);
+	add_d_ref(node);
+
+	page = jnode_get_page_locked(node, gfp_flags);
+	if (IS_ERR(page)) {
+		result = PTR_ERR(page);
+		goto failed;
+	}
+
+	SetPageUptodate(page);
+	unlock_page(page);
+
+	node->data = kmap(page);
+
+	if (!jnode_is_parsed(node)) {
+		jnode_plugin *jplug = jnode_ops(node);
+		spin_lock_jnode(node);
+		result = jplug->init(node);
+		spin_unlock_jnode(node);
+		if (result) {
+			kunmap(page);
+			goto failed;
+		}
+		JF_SET(node, JNODE_PARSED);
+	}
+
+	return 0;
+
+      failed:
+	jrelse(node);
+	return result;
+}
+
+/* release a reference to jnode acquired by jload(), decrement ->d_count */
+void jrelse_tail(jnode * node /* jnode to release references to */ )
+{
+	assert("nikita-489", atomic_read(&node->d_count) > 0);
+	atomic_dec(&node->d_count);
+	/* release reference acquired in jload_gfp() or jinit_new() */
+	jput(node);
+	if (jnode_is_unformatted(node) || jnode_is_znode(node))
+		LOCK_CNT_DEC(d_refs);
+}
+
+/* drop reference to node data. When last reference is dropped, data are
+   unloaded. */
+void jrelse(jnode * node /* jnode to release references to */ )
+{
+	struct page *page;
+
+	assert("nikita-487", node != NULL);
+	assert_spin_not_locked(&(node->guard));
+
+	page = jnode_page(node);
+	if (likely(page != NULL)) {
+		/*
+		 * it is safe not to lock jnode here, because at this point
+		 * @node->d_count is greater than zero (if jrelse() is used
+		 * correctly, that is). JNODE_PARSED may be not set yet, if,
+		 * for example, we got here as a result of error handling path
+		 * in jload(). Anyway, page cannot be detached by
+		 * reiser4_releasepage(). truncate will invalidate page
+		 * regardless, but this should not be a problem.
+		 */
+		kunmap(page);
+	}
+	jrelse_tail(node);
+}
+
+/* called from jput() to wait for io completion */
+static void jnode_finish_io(jnode * node)
+{
+	struct page *page;
+
+	assert("nikita-2922", node != NULL);
+
+	spin_lock_jnode(node);
+	page = jnode_page(node);
+	if (page != NULL) {
+		page_cache_get(page);
+		spin_unlock_jnode(node);
+		wait_on_page_writeback(page);
+		page_cache_release(page);
+	} else
+		spin_unlock_jnode(node);
+}
+
+/*
+ * This is called by jput() when last reference to jnode is released. This is
+ * separate function, because we want fast path of jput() to be inline and,
+ * therefore, small.
+ */
+void jput_final(jnode * node)
+{
+	int r_i_p;
+
+	/* A fast check for keeping node in cache. We always keep node in cache
+	 * if its page is present and node was not marked for deletion */
+	if (jnode_page(node) != NULL && !JF_ISSET(node, JNODE_HEARD_BANSHEE)) {
+		rcu_read_unlock();
+		return;
+	}
+
+	r_i_p = !JF_TEST_AND_SET(node, JNODE_RIP);
+	/*
+	 * if r_i_p is true, we were first to set JNODE_RIP on this node. In
+	 * this case it is safe to access node after unlock.
+	 */
+	rcu_read_unlock();
+	if (r_i_p) {
+		jnode_finish_io(node);
+		if (JF_ISSET(node, JNODE_HEARD_BANSHEE))
+			/* node is removed from the tree. */
+			jdelete(node);
+		else
+			jnode_try_drop(node);
+	}
+	/* if !r_i_p some other thread is already killing it */
+}
+
+int jwait_io(jnode * node, int rw)
+{
+	struct page *page;
+	int result;
+
+	assert("zam-447", node != NULL);
+	assert("zam-448", jnode_page(node) != NULL);
+
+	page = jnode_page(node);
+
+	result = 0;
+	if (rw == READ) {
+		wait_on_page_locked(page);
+	} else {
+		assert("nikita-2227", rw == WRITE);
+		wait_on_page_writeback(page);
+	}
+	if (PageError(page))
+		result = RETERR(-EIO);
+
+	return result;
+}
+
+/*
+ * jnode types and plugins.
+ *
+ * jnode by itself is a "base type". There are several different jnode
+ * flavors, called "jnode types" (see jnode_type for a list). Sometimes code
+ * has to do different things based on jnode type. In the standard reiser4 way
+ * this is done by having jnode plugin (see fs/reiser4/plugin.h:jnode_plugin).
+ *
+ * Functions below deal with jnode types and define methods of jnode plugin.
+ *
+ */
+
+/* set jnode type. This is done during jnode initialization. */
+static void jnode_set_type(jnode * node, jnode_type type)
+{
+	static unsigned long type_to_mask[] = {
+		[JNODE_UNFORMATTED_BLOCK] = 1,
+		[JNODE_FORMATTED_BLOCK] = 0,
+		[JNODE_BITMAP] = 2,
+		[JNODE_IO_HEAD] = 6,
+		[JNODE_INODE] = 4
+	};
+
+	assert("zam-647", type < LAST_JNODE_TYPE);
+	assert("nikita-2815", !jnode_is_loaded(node));
+	assert("nikita-3386", node->state == 0);
+
+	node->state |= (type_to_mask[type] << JNODE_TYPE_1);
+}
+
+/* ->init() method of jnode plugin for jnodes that don't require plugin
+ * specific initialization. */
+static int init_noinit(jnode * node UNUSED_ARG)
+{
+	return 0;
+}
+
+/* ->parse() method of jnode plugin for jnodes that don't require plugin
+ * specific pasring. */
+static int parse_noparse(jnode * node UNUSED_ARG)
+{
+	return 0;
+}
+
+/* ->mapping() method for unformatted jnode */
+struct address_space *mapping_jnode(const jnode * node)
+{
+	struct address_space *map;
+
+	assert("nikita-2713", node != NULL);
+
+	/* mapping is stored in jnode */
+
+	map = node->key.j.mapping;
+	assert("nikita-2714", map != NULL);
+	assert("nikita-2897", is_reiser4_inode(map->host));
+	assert("nikita-2715", get_inode_oid(map->host) == node->key.j.objectid);
+	assert("vs-1447", !JF_ISSET(node, JNODE_CC));
+	return map;
+}
+
+/* ->index() method for unformatted jnodes */
+unsigned long index_jnode(const jnode * node)
+{
+	assert("vs-1447", !JF_ISSET(node, JNODE_CC));
+	/* index is stored in jnode */
+	return node->key.j.index;
+}
+
+/* ->remove() method for unformatted jnodes */
+static inline void remove_jnode(jnode * node, reiser4_tree * tree)
+{
+	/* remove jnode from hash table and radix tree */
+	if (node->key.j.mapping)
+		unhash_unformatted_node_nolock(node);
+}
+
+/* ->mapping() method for znodes */
+static struct address_space *mapping_znode(const jnode * node)
+{
+	assert("vs-1447", !JF_ISSET(node, JNODE_CC));
+	/* all znodes belong to fake inode */
+	return get_super_fake(jnode_get_tree(node)->super)->i_mapping;
+}
+
+/* ->index() method for znodes */
+static unsigned long index_znode(const jnode * node)
+{
+	unsigned long addr;
+	assert("nikita-3317", (1 << znode_shift_order) < sizeof(znode));
+
+	/* index of znode is just its address (shifted) */
+	addr = (unsigned long)node;
+	return (addr - PAGE_OFFSET) >> znode_shift_order;
+}
+
+/* ->mapping() method for bitmap jnode */
+static struct address_space *mapping_bitmap(const jnode * node)
+{
+	/* all bitmap blocks belong to special bitmap inode */
+	return get_super_private(jnode_get_tree(node)->super)->bitmap->
+	    i_mapping;
+}
+
+/* ->index() method for jnodes that are indexed by address */
+static unsigned long index_is_address(const jnode * node)
+{
+	unsigned long ind;
+
+	ind = (unsigned long)node;
+	return ind - PAGE_OFFSET;
+}
+
+/* resolve race with jput */
+jnode *jnode_rip_sync(reiser4_tree *tree, jnode *node)
+{
+	/*
+	 * This is used as part of RCU-based jnode handling.
+	 *
+	 * jlookup(), zlook(), zget(), and cbk_cache_scan_slots() have to work
+	 * with unreferenced jnodes (ones with ->x_count == 0). Hash table is
+	 * not protected during this, so concurrent thread may execute
+	 * zget-set-HEARD_BANSHEE-zput, or somehow else cause jnode to be
+	 * freed in jput_final(). To avoid such races, jput_final() sets
+	 * JNODE_RIP on jnode (under tree lock). All places that work with
+	 * unreferenced jnodes call this function. It checks for JNODE_RIP bit
+	 * (first without taking tree lock), and if this bit is set, released
+	 * reference acquired by the current thread and returns NULL.
+	 *
+	 * As a result, if jnode is being concurrently freed, NULL is returned
+	 * and caller should pretend that jnode wasn't found in the first
+	 * place.
+	 *
+	 * Otherwise it's safe to release "rcu-read-lock" and continue with
+	 * jnode.
+	 */
+	if (unlikely(JF_ISSET(node, JNODE_RIP))) {
+		read_lock_tree(tree);
+		if (JF_ISSET(node, JNODE_RIP)) {
+			dec_x_ref(node);
+			node = NULL;
+		}
+		read_unlock_tree(tree);
+	}
+	return node;
+}
+
+reiser4_key *jnode_build_key(const jnode * node, reiser4_key * key)
+{
+	struct inode *inode;
+	item_plugin *iplug;
+	loff_t off;
+
+	assert("nikita-3092", node != NULL);
+	assert("nikita-3093", key != NULL);
+	assert("nikita-3094", jnode_is_unformatted(node));
+
+	off = ((loff_t) index_jnode(node)) << PAGE_CACHE_SHIFT;
+	inode = mapping_jnode(node)->host;
+
+	if (node->parent_item_id != 0)
+		iplug = item_plugin_by_id(node->parent_item_id);
+	else
+		iplug = NULL;
+
+	if (iplug != NULL && iplug->f.key_by_offset)
+		iplug->f.key_by_offset(inode, off, key);
+	else {
+		file_plugin *fplug;
+
+		fplug = inode_file_plugin(inode);
+		assert("zam-1007", fplug != NULL);
+		assert("zam-1008", fplug->key_by_inode != NULL);
+
+		fplug->key_by_inode(inode, off, key);
+	}
+
+	return key;
+}
+
+/* ->parse() method for formatted nodes */
+static int parse_znode(jnode * node)
+{
+	return zparse(JZNODE(node));
+}
+
+/* ->delete() method for formatted nodes */
+static void delete_znode(jnode * node, reiser4_tree * tree)
+{
+	znode *z;
+
+	assert_rw_write_locked(&(tree->tree_lock));
+	assert("vs-898", JF_ISSET(node, JNODE_HEARD_BANSHEE));
+
+	z = JZNODE(node);
+	assert("vs-899", z->c_count == 0);
+
+	/* delete znode from sibling list. */
+	sibling_list_remove(z);
+
+	znode_remove(z, tree);
+}
+
+/* ->remove() method for formatted nodes */
+static int remove_znode(jnode * node, reiser4_tree * tree)
+{
+	znode *z;
+
+	assert_rw_write_locked(&(tree->tree_lock));
+	z = JZNODE(node);
+
+	if (z->c_count == 0) {
+		/* detach znode from sibling list. */
+		sibling_list_drop(z);
+		/* this is called with tree spin-lock held, so call
+		   znode_remove() directly (rather than znode_lock_remove()). */
+		znode_remove(z, tree);
+		return 0;
+	}
+	return RETERR(-EBUSY);
+}
+
+/* ->init() method for formatted nodes */
+static int init_znode(jnode * node)
+{
+	znode *z;
+
+	z = JZNODE(node);
+	/* call node plugin to do actual initialization */
+	return z->nplug->init(z);
+}
+
+/* ->clone() method for formatted nodes */
+static jnode *clone_formatted(jnode * node)
+{
+	znode *clone;
+
+	assert("vs-1430", jnode_is_znode(node));
+	clone = zalloc(GFP_KERNEL);
+	if (clone == NULL)
+		return ERR_PTR(RETERR(-ENOMEM));
+	zinit(clone, NULL, current_tree);
+	jnode_set_block(ZJNODE(clone), jnode_get_block(node));
+	/* ZJNODE(clone)->key.z is not initialized */
+	clone->level = JZNODE(node)->level;
+
+	return ZJNODE(clone);
+}
+
+/* jplug->clone for unformatted nodes */
+static jnode *clone_unformatted(jnode * node)
+{
+	jnode *clone;
+
+	assert("vs-1431", jnode_is_unformatted(node));
+	clone = jalloc();
+	if (clone == NULL)
+		return ERR_PTR(RETERR(-ENOMEM));
+
+	jnode_init(clone, current_tree, JNODE_UNFORMATTED_BLOCK);
+	jnode_set_block(clone, jnode_get_block(node));
+
+	return clone;
+
+}
+
+/*
+ * Setup jnode plugin methods for various jnode types.
+ */
+jnode_plugin jnode_plugins[LAST_JNODE_TYPE] = {
+	[JNODE_UNFORMATTED_BLOCK] = {
+		.h = {
+			.type_id = REISER4_JNODE_PLUGIN_TYPE,
+			.id = JNODE_UNFORMATTED_BLOCK,
+			.pops = NULL,
+			.label = "unformatted",
+			.desc = "unformatted node",
+			.linkage = {NULL, NULL}
+		},
+		.init = init_noinit,
+		.parse = parse_noparse,
+		.mapping = mapping_jnode,
+		.index = index_jnode,
+		.clone = clone_unformatted
+	},
+	[JNODE_FORMATTED_BLOCK] = {
+		.h = {
+			.type_id = REISER4_JNODE_PLUGIN_TYPE,
+			.id = JNODE_FORMATTED_BLOCK,
+			.pops = NULL,
+			.label = "formatted",
+			.desc = "formatted tree node",
+			.linkage = {NULL, NULL}
+		},
+		.init = init_znode,
+		.parse = parse_znode,
+		.mapping = mapping_znode,
+		.index = index_znode,
+		.clone = clone_formatted
+	},
+	[JNODE_BITMAP] = {
+		.h = {
+			.type_id = REISER4_JNODE_PLUGIN_TYPE,
+			.id = JNODE_BITMAP,
+			.pops = NULL,
+			.label = "bitmap",
+			.desc = "bitmap node",
+			.linkage = {NULL, NULL}
+		},
+		.init = init_noinit,
+		.parse = parse_noparse,
+		.mapping = mapping_bitmap,
+		.index = index_is_address,
+		.clone = NULL
+	},
+	[JNODE_IO_HEAD] = {
+		.h = {
+			.type_id = REISER4_JNODE_PLUGIN_TYPE,
+			.id = JNODE_IO_HEAD,
+			.pops = NULL,
+			.label = "io head",
+			.desc = "io head",
+			.linkage = {NULL, NULL}
+		},
+		.init = init_noinit,
+		.parse = parse_noparse,
+		.mapping = mapping_bitmap,
+		.index = index_is_address,
+		.clone = NULL
+	},
+	[JNODE_INODE] = {
+		.h = {
+			.type_id = REISER4_JNODE_PLUGIN_TYPE,
+			.id = JNODE_INODE,
+			.pops = NULL,
+			.label = "inode",
+			.desc = "inode's builtin jnode",
+			.linkage = {NULL, NULL}
+		},
+		.init = NULL,
+		.parse = NULL,
+		.mapping = NULL,
+		.index = NULL,
+		.clone = NULL
+	}
+};
+
+/*
+ * jnode destruction.
+ *
+ * Thread may use a jnode after it acquired a reference to it. References are
+ * counted in ->x_count field. Reference protects jnode from being
+ * recycled. This is different from protecting jnode data (that are stored in
+ * jnode page) from being evicted from memory. Data are protected by jload()
+ * and released by jrelse().
+ *
+ * If thread already possesses a reference to the jnode it can acquire another
+ * one through jref(). Initial reference is obtained (usually) by locating
+ * jnode in some indexing structure that depends on jnode type: formatted
+ * nodes are kept in global hash table, where they are indexed by block
+ * number, and also in the cbk cache. Unformatted jnodes are also kept in hash
+ * table, which is indexed by oid and offset within file, and in per-inode
+ * radix tree.
+ *
+ * Reference to jnode is released by jput(). If last reference is released,
+ * jput_final() is called. This function determines whether jnode has to be
+ * deleted (this happens when corresponding node is removed from the file
+ * system, jnode is marked with JNODE_HEARD_BANSHEE bit in this case), or it
+ * should be just "removed" (deleted from memory).
+ *
+ * Jnode destruction is signally delicate dance because of locking and RCU.
+ */
+
+/*
+ * Returns true if jnode cannot be removed right now. This check is called
+ * under tree lock. If it returns true, jnode is irrevocably committed to be
+ * deleted/removed.
+ */
+static inline int jnode_is_busy(const jnode * node, jnode_type jtype)
+{
+	/* if other thread managed to acquire a reference to this jnode, don't
+	 * free it. */
+	if (atomic_read(&node->x_count) > 0)
+		return 1;
+	/* also, don't free znode that has children in memory */
+	if (jtype == JNODE_FORMATTED_BLOCK && JZNODE(node)->c_count > 0)
+		return 1;
+	return 0;
+}
+
+/*
+ * this is called as part of removing jnode. Based on jnode type, call
+ * corresponding function that removes jnode from indices and returns it back
+ * to the appropriate slab (through RCU).
+ */
+static inline void
+jnode_remove(jnode * node, jnode_type jtype, reiser4_tree * tree)
+{
+	switch (jtype) {
+	case JNODE_UNFORMATTED_BLOCK:
+		remove_jnode(node, tree);
+		break;
+	case JNODE_IO_HEAD:
+	case JNODE_BITMAP:
+		break;
+	case JNODE_INODE:
+		break;
+	case JNODE_FORMATTED_BLOCK:
+		remove_znode(node, tree);
+		break;
+	default:
+		wrong_return_value("nikita-3196", "Wrong jnode type");
+	}
+}
+
+/*
+ * this is called as part of deleting jnode. Based on jnode type, call
+ * corresponding function that removes jnode from indices and returns it back
+ * to the appropriate slab (through RCU).
+ *
+ * This differs from jnode_remove() only for formatted nodes---for them
+ * sibling list handling is different for removal and deletion.
+ */
+static inline void
+jnode_delete(jnode * node, jnode_type jtype, reiser4_tree * tree UNUSED_ARG)
+{
+	switch (jtype) {
+	case JNODE_UNFORMATTED_BLOCK:
+		remove_jnode(node, tree);
+		break;
+	case JNODE_IO_HEAD:
+	case JNODE_BITMAP:
+		break;
+	case JNODE_FORMATTED_BLOCK:
+		delete_znode(node, tree);
+		break;
+	case JNODE_INODE:
+	default:
+		wrong_return_value("nikita-3195", "Wrong jnode type");
+	}
+}
+
+#if REISER4_DEBUG
+/*
+ * remove jnode from the debugging list of all jnodes hanging off super-block.
+ */
+void jnode_list_remove(jnode * node)
+{
+	reiser4_super_info_data *sbinfo;
+
+	sbinfo = get_super_private(jnode_get_tree(node)->super);
+
+	spin_lock_irq(&sbinfo->all_guard);
+	assert("nikita-2422", !list_empty(&node->jnodes));
+	list_del_init(&node->jnodes);
+	spin_unlock_irq(&sbinfo->all_guard);
+}
+#endif
+
+/*
+ * this is called by jput_final() to remove jnode when last reference to it is
+ * released.
+ */
+static int jnode_try_drop(jnode * node)
+{
+	int result;
+	reiser4_tree *tree;
+	jnode_type jtype;
+
+	assert("nikita-2491", node != NULL);
+	assert("nikita-2583", JF_ISSET(node, JNODE_RIP));
+
+	tree = jnode_get_tree(node);
+	jtype = jnode_get_type(node);
+
+	spin_lock_jnode(node);
+	write_lock_tree(tree);
+	/*
+	 * if jnode has a page---leave it alone. Memory pressure will
+	 * eventually kill page and jnode.
+	 */
+	if (jnode_page(node) != NULL) {
+		write_unlock_tree(tree);
+		spin_unlock_jnode(node);
+		JF_CLR(node, JNODE_RIP);
+		return RETERR(-EBUSY);
+	}
+
+	/* re-check ->x_count under tree lock. */
+	result = jnode_is_busy(node, jtype);
+	if (result == 0) {
+		assert("nikita-2582", !JF_ISSET(node, JNODE_HEARD_BANSHEE));
+		assert("nikita-3223", !JF_ISSET(node, JNODE_EFLUSH));
+		assert("jmacd-511/b", atomic_read(&node->d_count) == 0);
+
+		spin_unlock_jnode(node);
+		/* no page and no references---despatch him. */
+		jnode_remove(node, jtype, tree);
+		write_unlock_tree(tree);
+		jnode_free(node, jtype);
+	} else {
+		/* busy check failed: reference was acquired by concurrent
+		 * thread. */
+		write_unlock_tree(tree);
+		spin_unlock_jnode(node);
+		JF_CLR(node, JNODE_RIP);
+	}
+	return result;
+}
+
+/* jdelete() -- Delete jnode from the tree and file system */
+static int jdelete(jnode * node /* jnode to finish with */ )
+{
+	struct page *page;
+	int result;
+	reiser4_tree *tree;
+	jnode_type jtype;
+
+	assert("nikita-467", node != NULL);
+	assert("nikita-2531", JF_ISSET(node, JNODE_RIP));
+	/* jnode cannot be eflushed at this point, because emegrency flush
+	 * acquired additional reference counter. */
+	assert("nikita-2917", !JF_ISSET(node, JNODE_EFLUSH));
+
+	jtype = jnode_get_type(node);
+
+	page = jnode_lock_page(node);
+	assert_spin_locked(&(node->guard));
+
+	tree = jnode_get_tree(node);
+
+	write_lock_tree(tree);
+	/* re-check ->x_count under tree lock. */
+	result = jnode_is_busy(node, jtype);
+	if (likely(!result)) {
+		assert("nikita-2123", JF_ISSET(node, JNODE_HEARD_BANSHEE));
+		assert("jmacd-511", atomic_read(&node->d_count) == 0);
+
+		/* detach page */
+		if (page != NULL) {
+			/*
+			 * FIXME this is racy against jnode_extent_write().
+			 */
+			page_clear_jnode(page, node);
+		}
+		spin_unlock_jnode(node);
+		/* goodbye */
+		jnode_delete(node, jtype, tree);
+		write_unlock_tree(tree);
+		jnode_free(node, jtype);
+		/* @node is no longer valid pointer */
+		if (page != NULL)
+			drop_page(page);
+	} else {
+		/* busy check failed: reference was acquired by concurrent
+		 * thread. */
+		JF_CLR(node, JNODE_RIP);
+		write_unlock_tree(tree);
+		spin_unlock_jnode(node);
+		if (page != NULL)
+			unlock_page(page);
+	}
+	return result;
+}
+
+/* drop jnode on the floor.
+
+   Return value:
+
+    -EBUSY:  failed to drop jnode, because there are still references to it
+
+    0:       successfully dropped jnode
+
+*/
+static int jdrop_in_tree(jnode * node, reiser4_tree * tree)
+{
+	struct page *page;
+	jnode_type jtype;
+	int result;
+
+	assert("zam-602", node != NULL);
+	assert_rw_not_read_locked(&(tree->tree_lock));
+	assert_rw_not_write_locked(&(tree->tree_lock));
+	assert("nikita-2403", !JF_ISSET(node, JNODE_HEARD_BANSHEE));
+
+	jtype = jnode_get_type(node);
+
+	page = jnode_lock_page(node);
+	assert_spin_locked(&(node->guard));
+
+	write_lock_tree(tree);
+
+	/* re-check ->x_count under tree lock. */
+	result = jnode_is_busy(node, jtype);
+	if (!result) {
+		assert("nikita-2488", page == jnode_page(node));
+		assert("nikita-2533", atomic_read(&node->d_count) == 0);
+		if (page != NULL) {
+			assert("nikita-2126", !PageDirty(page));
+			assert("nikita-2127", PageUptodate(page));
+			assert("nikita-2181", PageLocked(page));
+			page_clear_jnode(page, node);
+		}
+		spin_unlock_jnode(node);
+		jnode_remove(node, jtype, tree);
+		write_unlock_tree(tree);
+		jnode_free(node, jtype);
+		if (page != NULL) {
+			drop_page(page);
+		}
+	} else {
+		/* busy check failed: reference was acquired by concurrent
+		 * thread. */
+		JF_CLR(node, JNODE_RIP);
+		write_unlock_tree(tree);
+		spin_unlock_jnode(node);
+		if (page != NULL)
+			unlock_page(page);
+	}
+	return result;
+}
+
+/* This function frees jnode "if possible". In particular, [dcx]_count has to
+   be 0 (where applicable).  */
+void jdrop(jnode * node)
+{
+	jdrop_in_tree(node, jnode_get_tree(node));
+}
+
+/* IO head jnode implementation; The io heads are simple j-nodes with limited
+   functionality (these j-nodes are not in any hash table) just for reading
+   from and writing to disk. */
+
+jnode *alloc_io_head(const reiser4_block_nr * block)
+{
+	jnode *jal = jalloc();
+
+	if (jal != NULL) {
+		jnode_init(jal, current_tree, JNODE_IO_HEAD);
+		jnode_set_block(jal, block);
+	}
+
+	jref(jal);
+
+	return jal;
+}
+
+void drop_io_head(jnode * node)
+{
+	assert("zam-648", jnode_get_type(node) == JNODE_IO_HEAD);
+
+	jput(node);
+	jdrop(node);
+}
+
+/* protect keep jnode data from reiser4_releasepage()  */
+void pin_jnode_data(jnode * node)
+{
+	assert("zam-671", jnode_page(node) != NULL);
+	page_cache_get(jnode_page(node));
+}
+
+/* make jnode data free-able again */
+void unpin_jnode_data(jnode * node)
+{
+	assert("zam-672", jnode_page(node) != NULL);
+	page_cache_release(jnode_page(node));
+}
+
+struct address_space *jnode_get_mapping(const jnode * node)
+{
+	assert("nikita-3162", node != NULL);
+	return jnode_ops(node)->mapping(node);
+}
+
+#if REISER4_DEBUG
+/* debugging aid: jnode invariant */
+int jnode_invariant_f(const jnode * node, char const **msg)
+{
+#define _ergo(ant, con) 						\
+	((*msg) = "{" #ant "} ergo {" #con "}", ergo((ant), (con)))
+#define _check(exp) ((*msg) = #exp, (exp))
+
+	return _check(node != NULL) &&
+	    /* [jnode-queued] */
+	    /* only relocated node can be queued, except that when znode
+	     * is being deleted, its JNODE_RELOC bit is cleared */
+	    _ergo(JF_ISSET(node, JNODE_FLUSH_QUEUED),
+		  JF_ISSET(node, JNODE_RELOC) ||
+		  JF_ISSET(node, JNODE_HEARD_BANSHEE)) &&
+	    _check(node->jnodes.prev != NULL) &&
+	    _check(node->jnodes.next != NULL) &&
+	    /* [jnode-dirty] invariant */
+	    /* dirty inode is part of atom */
+	    _ergo(JF_ISSET(node, JNODE_DIRTY), node->atom != NULL) &&
+	    /* [jnode-oid] invariant */
+	    /* for unformatted node ->objectid and ->mapping fields are
+	     * consistent */
+	    _ergo(jnode_is_unformatted(node) && node->key.j.mapping != NULL,
+		  node->key.j.objectid ==
+		  get_inode_oid(node->key.j.mapping->host)) &&
+	    /* [jnode-atom-valid] invariant */
+	    /* node atom has valid state */
+	    _ergo(node->atom != NULL, node->atom->stage != ASTAGE_INVALID) &&
+	    /* [jnode-page-binding] invariant */
+	    /* if node points to page, it points back to node */
+	    _ergo(node->pg != NULL, jprivate(node->pg) == node) &&
+	    /* [jnode-refs] invariant */
+	    /* only referenced jnode can be loaded */
+	    _check(atomic_read(&node->x_count) >= atomic_read(&node->d_count));
+
+}
+
+/* debugging aid: check znode invariant and panic if it doesn't hold */
+static int jnode_invariant(const jnode * node, int tlocked, int jlocked)
+{
+	char const *failed_msg;
+	int result;
+	reiser4_tree *tree;
+
+	tree = jnode_get_tree(node);
+
+	assert("umka-063312", node != NULL);
+	assert("umka-064321", tree != NULL);
+
+	if (!jlocked && !tlocked)
+		spin_lock_jnode((jnode *) node);
+	if (!tlocked)
+		read_lock_tree(jnode_get_tree(node));
+	result = jnode_invariant_f(node, &failed_msg);
+	if (!result) {
+		info_jnode("corrupted node", node);
+		warning("jmacd-555", "Condition %s failed", failed_msg);
+	}
+	if (!tlocked)
+		read_unlock_tree(jnode_get_tree(node));
+	if (!jlocked && !tlocked)
+		spin_unlock_jnode((jnode *) node);
+	return result;
+}
+
+static const char *jnode_type_name(jnode_type type)
+{
+	switch (type) {
+	case JNODE_UNFORMATTED_BLOCK:
+		return "unformatted";
+	case JNODE_FORMATTED_BLOCK:
+		return "formatted";
+	case JNODE_BITMAP:
+		return "bitmap";
+	case JNODE_IO_HEAD:
+		return "io head";
+	case JNODE_INODE:
+		return "inode";
+	case LAST_JNODE_TYPE:
+		return "last";
+	default:{
+			static char unknown[30];
+
+			sprintf(unknown, "unknown %i", type);
+			return unknown;
+		}
+	}
+}
+
+#define jnode_state_name( node, flag )			\
+	( JF_ISSET( ( node ), ( flag ) ) ? ((#flag "|")+6) : "" )
+
+/* debugging aid: output human readable information about @node */
+void info_jnode(const char *prefix /* prefix to print */ ,
+		const jnode * node /* node to print */ )
+{
+	assert("umka-068", prefix != NULL);
+
+	if (node == NULL) {
+		printk("%s: null\n", prefix);
+		return;
+	}
+
+	printk
+	    ("%s: %p: state: %lx: [%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s], level: %i,"
+	     " block: %s, d_count: %d, x_count: %d, "
+	     "pg: %p, atom: %p, lock: %i:%i, type: %s, ", prefix, node,
+	     node->state, jnode_state_name(node, JNODE_PARSED),
+	     jnode_state_name(node, JNODE_HEARD_BANSHEE), jnode_state_name(node,
+									   JNODE_LEFT_CONNECTED),
+	     jnode_state_name(node, JNODE_RIGHT_CONNECTED),
+	     jnode_state_name(node, JNODE_ORPHAN), jnode_state_name(node,
+								    JNODE_CREATED),
+	     jnode_state_name(node, JNODE_RELOC), jnode_state_name(node,
+								   JNODE_OVRWR),
+	     jnode_state_name(node, JNODE_DIRTY), jnode_state_name(node,
+								   JNODE_IS_DYING),
+	     jnode_state_name(node, JNODE_EFLUSH), jnode_state_name(node,
+								    JNODE_FLUSH_QUEUED),
+	     jnode_state_name(node, JNODE_RIP), jnode_state_name(node,
+								 JNODE_MISSED_IN_CAPTURE),
+	     jnode_state_name(node, JNODE_WRITEBACK), jnode_state_name(node,
+								       JNODE_NEW),
+	     jnode_state_name(node, JNODE_DKSET), jnode_state_name(node,
+								   JNODE_EPROTECTED),
+	     jnode_state_name(node, JNODE_REPACK), jnode_state_name(node,
+								    JNODE_CLUSTER_PAGE),
+	     jnode_get_level(node), sprint_address(jnode_get_block(node)),
+	     atomic_read(&node->d_count), atomic_read(&node->x_count),
+	     jnode_page(node), node->atom, 0, 0,
+	     jnode_type_name(jnode_get_type(node)));
+	if (jnode_is_unformatted(node)) {
+		printk("inode: %llu, index: %lu, ",
+		       node->key.j.objectid, node->key.j.index);
+	}
+}
+
+
+#endif				/* REISER4_DEBUG */
+
+/* this is only used to created jnode during capture copy */
+jnode *jclone(jnode * node)
+{
+	jnode *clone;
+
+	assert("vs-1429", jnode_ops(node)->clone);
+	clone = jnode_ops(node)->clone(node);
+	if (IS_ERR(clone))
+		return clone;
+
+	jref(clone);
+	JF_SET(clone, JNODE_HEARD_BANSHEE);
+	JF_SET(clone, JNODE_CC);
+	return clone;
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 80
+   End:
+*/
diff -urN oldtree/fs/reiser4/jnode.h newtree/fs/reiser4/jnode.h
--- oldtree/fs/reiser4/jnode.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/jnode.h	2006-02-21 15:58:35.436759352 +0000
@@ -0,0 +1,728 @@
+/* Copyright 2001, 2002, 2003, 2004 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Declaration of jnode. See jnode.c for details. */
+
+#ifndef __JNODE_H__
+#define __JNODE_H__
+
+#include "forward.h"
+#include "type_safe_hash.h"
+#include "txnmgr.h"
+#include "key.h"
+#include "debug.h"
+#include "dformat.h"
+#include "emergency_flush.h"
+
+#include "plugin/plugin.h"
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <linux/list.h>
+#include <linux/rcupdate.h>
+
+/* declare hash table of jnodes (jnodes proper, that is, unformatted
+   nodes)  */
+TYPE_SAFE_HASH_DECLARE(j, jnode);
+
+/* declare hash table of znodes */
+TYPE_SAFE_HASH_DECLARE(z, znode);
+
+typedef struct {
+	__u64 objectid;
+	unsigned long index;
+	struct address_space *mapping;
+} jnode_key_t;
+
+/*
+   Jnode is the "base class" of other nodes in reiser4. It is also happens to
+   be exactly the node we use for unformatted tree nodes.
+
+   Jnode provides following basic functionality:
+
+   . reference counting and indexing.
+
+   . integration with page cache. Jnode has ->pg reference to which page can
+   be attached.
+
+   . interface to transaction manager. It is jnode that is kept in transaction
+   manager lists, attached to atoms, etc. (NOTE-NIKITA one may argue that this
+   means, there should be special type of jnode for inode.)
+
+   Locking:
+
+   Spin lock: the following fields are protected by the per-jnode spin lock:
+
+    ->state
+    ->atom
+    ->capture_link
+
+   Following fields are protected by the global tree lock:
+
+    ->link
+    ->key.z (content of ->key.z is only changed in znode_rehash())
+    ->key.j
+
+   Atomic counters
+
+    ->x_count
+    ->d_count
+
+    ->pg, and ->data are protected by spin lock for unused jnode and are
+    immutable for used jnode (one for which fs/reiser4/vfs_ops.c:releasable()
+    is false).
+
+    ->tree is immutable after creation
+
+   Unclear
+
+    ->blocknr: should be under jnode spin-lock, but current interface is based
+    on passing of block address.
+
+   If you ever need to spin lock two nodes at once, do this in "natural"
+   memory order: lock znode with lower address first. (See lock_two_nodes().)
+
+   Invariants involving this data-type:
+
+      [jnode-dirty]
+      [jnode-refs]
+      [jnode-oid]
+      [jnode-queued]
+      [jnode-atom-valid]
+      [jnode-page-binding]
+*/
+
+struct jnode {
+#if REISER4_DEBUG
+#define JMAGIC 0x52654973	/* "ReIs" */
+	int magic;
+#endif
+	/* FIRST CACHE LINE (16 bytes): data used by jload */
+
+	/* jnode's state: bitwise flags from the reiser4_jnode_state enum. */
+	/*   0 */ unsigned long state;
+
+	/* lock, protecting jnode's fields. */
+	/*   4 */ spinlock_t load;
+
+	/* counter of references to jnode itself. Increased on jref().
+	   Decreased on jput().
+	 */
+	/*   8 */ atomic_t x_count;
+
+	/* counter of references to jnode's data. Pin data page(s) in
+	   memory while this is greater than 0. Increased on jload().
+	   Decreased on jrelse().
+	 */
+	/*   12 */ atomic_t d_count;
+
+	/* SECOND CACHE LINE: data used by hash table lookups */
+
+	/*   16 */ union {
+		/* znodes are hashed by block number */
+		reiser4_block_nr z;
+		/* unformatted nodes are hashed by mapping plus offset */
+		jnode_key_t j;
+	} key;
+
+	/* THIRD CACHE LINE */
+
+	/*   32 */ union {
+		/* pointers to maintain hash-table */
+		z_hash_link z;
+		j_hash_link j;
+	} link;
+
+	/* pointer to jnode page.  */
+	/*   36 */ struct page *pg;
+	/* pointer to node itself. This is page_address(node->pg) when page is
+	   attached to the jnode
+	 */
+	/*   40 */ void *data;
+
+	/*   44 */ reiser4_tree *tree;
+
+	/* FOURTH CACHE LINE: atom related fields */
+
+	/*   48 */ spinlock_t guard;
+
+	/* atom the block is in, if any */
+	/*   52 */ txn_atom *atom;
+
+	/* capture list */
+	/*   56 */ struct list_head capture_link;
+
+	/* FIFTH CACHE LINE */
+
+	/*   64 */ struct rcu_head rcu;
+	/* crosses cache line */
+
+	/* SIXTH CACHE LINE */
+
+	/* the real blocknr (where io is going to/from) */
+	/*   80 */ reiser4_block_nr blocknr;
+	/* Parent item type, unformatted and CRC need it for offset => key conversion.  */
+	/* NOTE: this parent_item_id looks like jnode type. */
+	/*   88 */ reiser4_plugin_id parent_item_id;
+	/*   92 */
+#if REISER4_DEBUG
+	/* number of pages referenced by the jnode (meaningful while capturing of
+	   page clusters) */
+	int page_count;
+	/* list of all jnodes for debugging purposes. */
+	struct list_head jnodes;
+	/* how many times this jnode was written in one transaction */
+	int written;
+	/* this indicates which atom's list the jnode is on */
+	atom_list list;
+#endif
+} __attribute__ ((aligned(16)));
+
+/*
+ * jnode types. Enumeration of existing jnode types.
+ */
+typedef enum {
+	JNODE_UNFORMATTED_BLOCK,	/* unformatted block */
+	JNODE_FORMATTED_BLOCK,	/* formatted block, znode */
+	JNODE_BITMAP,		/* bitmap */
+	JNODE_IO_HEAD,		/* jnode representing a block in the
+				 * wandering log */
+	JNODE_INODE,		/* jnode embedded into inode */
+	LAST_JNODE_TYPE
+} jnode_type;
+
+/* jnode states */
+typedef enum {
+	/* jnode's page is loaded and data checked */
+	JNODE_PARSED = 0,
+	/* node was deleted, not all locks on it were released. This
+	   node is empty and is going to be removed from the tree
+	   shortly. */
+	JNODE_HEARD_BANSHEE = 1,
+	/* left sibling pointer is valid */
+	JNODE_LEFT_CONNECTED = 2,
+	/* right sibling pointer is valid */
+	JNODE_RIGHT_CONNECTED = 3,
+
+	/* znode was just created and doesn't yet have a pointer from
+	   its parent */
+	JNODE_ORPHAN = 4,
+
+	/* this node was created by its transaction and has not been assigned
+	   a block address. */
+	JNODE_CREATED = 5,
+
+	/* this node is currently relocated */
+	JNODE_RELOC = 6,
+	/* this node is currently wandered */
+	JNODE_OVRWR = 7,
+
+	/* this znode has been modified */
+	JNODE_DIRTY = 8,
+
+	/* znode lock is being invalidated */
+	JNODE_IS_DYING = 9,
+
+	/* THIS PLACE IS INTENTIONALLY LEFT BLANK */
+
+	JNODE_EFLUSH = 11,
+
+	/* jnode is queued for flushing. */
+	JNODE_FLUSH_QUEUED = 12,
+
+	/* In the following bits jnode type is encoded. */
+	JNODE_TYPE_1 = 13,
+	JNODE_TYPE_2 = 14,
+	JNODE_TYPE_3 = 15,
+
+	/* jnode is being destroyed */
+	JNODE_RIP = 16,
+
+	/* znode was not captured during locking (it might so be because
+	   ->level != LEAF_LEVEL and lock_mode == READ_LOCK) */
+	JNODE_MISSED_IN_CAPTURE = 17,
+
+	/* write is in progress */
+	JNODE_WRITEBACK = 18,
+
+	/* FIXME: now it is used by crypto-compress plugin only */
+	JNODE_NEW = 19,
+
+	/* delimiting keys are already set for this znode. */
+	JNODE_DKSET = 20,
+
+	/* cheap and effective protection of jnode from emergency flush. This
+	 * bit can only be set by thread that holds long term lock on jnode
+	 * parent node (twig node, where extent unit lives). */
+	JNODE_EPROTECTED = 21,
+	JNODE_CLUSTER_PAGE = 22,
+	/* Jnode is marked for repacking, that means the reiser4 flush and the
+	 * block allocator should process this node special way  */
+	JNODE_REPACK = 23,
+	/* node should be converted by flush in squalloc phase */
+	JNODE_CONVERTIBLE = 24,
+
+	JNODE_SCANNED = 25,
+	JNODE_JLOADED_BY_GET_OVERWRITE_SET = 26,
+	/* capture copy jnode */
+	JNODE_CC = 27,
+	/* this jnode is copy of coced original */
+	JNODE_CCED = 28,
+	/*
+	 * When jnode is dirtied for the first time in given transaction,
+	 * do_jnode_make_dirty() checks whether this jnode can possible became
+	 * member of overwrite set. If so, this bit is set, and one block is
+	 * reserved in the ->flush_reserved space of atom.
+	 *
+	 * This block is "used" (and JNODE_FLUSH_RESERVED bit is cleared) when
+	 *
+	 *     (1) flush decides that we want this block to go into relocate
+	 *     set after all.
+	 *
+	 *     (2) wandering log is allocated (by log writer)
+	 *
+	 *     (3) extent is allocated
+	 *
+	 */
+	JNODE_FLUSH_RESERVED = 29,
+	/* if page was dirtied through mmap, we don't want to lose data, even
+	 * though page and jnode may be clean. Mark jnode with JNODE_KEEPME so
+	 * that ->releasepage() can tell. This is used only for
+	 * unformatted */
+	JNODE_KEEPME = 30,
+#if REISER4_DEBUG
+	/* uneflushed */
+	JNODE_UNEFLUSHED = 31
+#endif
+} reiser4_jnode_state;
+
+/* Macros for accessing the jnode state. */
+
+static inline void JF_CLR(jnode * j, int f)
+{
+	assert("unknown-1", j->magic == JMAGIC);
+	clear_bit(f, &j->state);
+}
+static inline int JF_ISSET(const jnode * j, int f)
+{
+	assert("unknown-2", j->magic == JMAGIC);
+	return test_bit(f, &((jnode *) j)->state);
+}
+static inline void JF_SET(jnode * j, int f)
+{
+	assert("unknown-3", j->magic == JMAGIC);
+	set_bit(f, &j->state);
+}
+
+static inline int JF_TEST_AND_SET(jnode * j, int f)
+{
+	assert("unknown-4", j->magic == JMAGIC);
+	return test_and_set_bit(f, &j->state);
+}
+
+static inline void spin_lock_jnode(jnode *node)
+{
+	/* check that spinlocks of lower priorities are not held */
+	assert("", (LOCK_CNT_NIL(rw_locked_tree) &&
+		    LOCK_CNT_NIL(spin_locked_txnh) &&
+		    LOCK_CNT_NIL(spin_locked_zlock) &&
+		    LOCK_CNT_NIL(rw_locked_dk) &&
+		    LOCK_CNT_LT(spin_locked_jnode, 2)));
+
+	spin_lock(&(node->guard));
+
+	LOCK_CNT_INC(spin_locked_jnode);
+	LOCK_CNT_INC(spin_locked);
+}
+
+static inline void spin_unlock_jnode(jnode *node)
+{
+	assert_spin_locked(&(node->guard));
+	assert("nikita-1375", LOCK_CNT_GTZ(spin_locked_jnode));
+	assert("nikita-1376", LOCK_CNT_GTZ(spin_locked));
+
+	LOCK_CNT_DEC(spin_locked_jnode);
+	LOCK_CNT_DEC(spin_locked);
+
+	spin_unlock(&(node->guard));
+}
+
+static inline int jnode_is_in_deleteset(const jnode * node)
+{
+	return JF_ISSET(node, JNODE_RELOC);
+}
+
+extern int init_jnodes(void);
+extern void done_jnodes(void);
+
+/* Jnode routines */
+extern jnode *jalloc(void);
+extern void jfree(jnode * node) NONNULL;
+extern jnode *jclone(jnode *);
+extern jnode *jlookup(reiser4_tree * tree,
+		      oid_t objectid, unsigned long ind) NONNULL;
+extern jnode *jfind(struct address_space *, unsigned long index) NONNULL;
+extern jnode *jnode_by_page(struct page *pg) NONNULL;
+extern jnode *jnode_of_page(struct page *pg) NONNULL;
+void jnode_attach_page(jnode * node, struct page *pg);
+jnode *find_get_jnode(reiser4_tree * tree,
+		      struct address_space *mapping, oid_t oid,
+		      unsigned long index);
+
+void unhash_unformatted_jnode(jnode *);
+struct page *jnode_get_page_locked(jnode *, int gfp_flags);
+extern jnode *page_next_jnode(jnode * node) NONNULL;
+extern void jnode_init(jnode * node, reiser4_tree * tree, jnode_type) NONNULL;
+extern void jnode_make_dirty(jnode * node) NONNULL;
+extern void jnode_make_clean(jnode * node) NONNULL;
+extern void jnode_make_wander_nolock(jnode * node) NONNULL;
+extern void jnode_make_wander(jnode *) NONNULL;
+extern void znode_make_reloc(znode *, flush_queue_t *) NONNULL;
+extern void unformatted_make_reloc(jnode *, flush_queue_t *) NONNULL;
+
+extern void jnode_set_block(jnode * node,
+			    const reiser4_block_nr * blocknr) NONNULL;
+/*extern struct page *jnode_lock_page(jnode *) NONNULL;*/
+extern struct address_space *jnode_get_mapping(const jnode * node) NONNULL;
+
+/* block number of node */
+static inline const reiser4_block_nr *jnode_get_block(const jnode *
+						      node /* jnode to query */
+						      )
+{
+	assert("nikita-528", node != NULL);
+
+	return &node->blocknr;
+}
+
+/* block number for IO. Usually this is the same as jnode_get_block(), unless
+ * jnode was emergency flushed---then block number chosen by eflush is
+ * used. */
+static inline const reiser4_block_nr *jnode_get_io_block(jnode * node)
+{
+	assert("nikita-2768", node != NULL);
+	assert_spin_locked(&(node->guard));
+
+	if (unlikely(JF_ISSET(node, JNODE_EFLUSH)))
+		return eflush_get(node);
+	else
+		return jnode_get_block(node);
+}
+
+/* Jnode flush interface. */
+extern reiser4_blocknr_hint *pos_hint(flush_pos_t * pos);
+extern flush_queue_t *pos_fq(flush_pos_t * pos);
+
+/* FIXME-VS: these are used in plugin/item/extent.c */
+
+/* does extent_get_block have to be called */
+#define jnode_mapped(node)     JF_ISSET (node, JNODE_MAPPED)
+#define jnode_set_mapped(node) JF_SET (node, JNODE_MAPPED)
+/* pointer to this block was just created (either by appending or by plugging a
+   hole), or zinit_new was called */
+#define jnode_created(node)        JF_ISSET (node, JNODE_CREATED)
+#define jnode_set_created(node)    JF_SET (node, JNODE_CREATED)
+
+/* the node should be converted during flush squalloc phase */
+#define jnode_convertible(node)        JF_ISSET (node, JNODE_CONVERTIBLE)
+#define jnode_set_convertible(node)    JF_SET (node, JNODE_CONVERTIBLE)
+
+/* Macros to convert from jnode to znode, znode to jnode.  These are macros
+   because C doesn't allow overloading of const prototypes. */
+#define ZJNODE(x) (& (x) -> zjnode)
+#define JZNODE(x)						\
+({								\
+	typeof (x) __tmp_x;					\
+								\
+	__tmp_x = (x);						\
+	assert ("jmacd-1300", jnode_is_znode (__tmp_x));	\
+	(znode*) __tmp_x;					\
+})
+
+extern int jnodes_tree_init(reiser4_tree * tree);
+extern int jnodes_tree_done(reiser4_tree * tree);
+
+#if REISER4_DEBUG
+
+extern int znode_is_any_locked(const znode * node);
+extern void jnode_list_remove(jnode * node);
+extern void info_jnode(const char *prefix, const jnode * node);
+
+#else
+
+#define jnode_list_remove(node) noop
+#define info_jnode(p, n) noop
+
+#endif
+
+int znode_is_root(const znode * node) NONNULL;
+
+/* bump reference counter on @node */
+static inline void add_x_ref(jnode * node /* node to increase x_count of */ )
+{
+	assert("nikita-1911", node != NULL);
+
+	atomic_inc(&node->x_count);
+	LOCK_CNT_INC(x_refs);
+}
+
+static inline void dec_x_ref(jnode * node)
+{
+	assert("nikita-3215", node != NULL);
+	assert("nikita-3216", atomic_read(&node->x_count) > 0);
+
+	atomic_dec(&node->x_count);
+	assert("nikita-3217", LOCK_CNT_GTZ(x_refs));
+	LOCK_CNT_DEC(x_refs);
+}
+
+/* jref() - increase counter of references to jnode/znode (x_count) */
+static inline jnode *jref(jnode * node)
+{
+	assert("jmacd-508", (node != NULL) && !IS_ERR(node));
+	add_x_ref(node);
+	return node;
+}
+
+/* get the page of jnode */
+static inline struct page *jnode_page(const jnode * node)
+{
+	return node->pg;
+}
+
+/* return pointer to jnode data */
+static inline char *jdata(const jnode * node)
+{
+	assert("nikita-1415", node != NULL);
+	assert("nikita-3198", jnode_page(node) != NULL);
+	return node->data;
+}
+
+static inline int jnode_is_loaded(const jnode * node)
+{
+	assert("zam-506", node != NULL);
+	return atomic_read(&node->d_count) > 0;
+}
+
+extern void page_detach_jnode(struct page *page,
+			      struct address_space *mapping,
+			      unsigned long index) NONNULL;
+extern void page_clear_jnode(struct page *page, jnode * node) NONNULL;
+
+static inline void jnode_set_reloc(jnode * node)
+{
+	assert("nikita-2431", node != NULL);
+	assert("nikita-2432", !JF_ISSET(node, JNODE_OVRWR));
+	JF_SET(node, JNODE_RELOC);
+}
+
+/* jload/jwrite/junload give a bread/bwrite/brelse functionality for jnodes */
+
+extern int jload_gfp(jnode * node, int gfp, int do_kmap) NONNULL;
+
+static inline int jload(jnode * node)
+{
+	return jload_gfp(node, GFP_KERNEL, 1);
+}
+
+extern int jinit_new(jnode * node, int gfp_flags) NONNULL;
+extern int jstartio(jnode * node) NONNULL;
+
+extern void jdrop(jnode * node) NONNULL;
+extern int jwait_io(jnode * node, int rw) NONNULL;
+
+void jload_prefetch(jnode *);
+
+extern jnode *alloc_io_head(const reiser4_block_nr * block) NONNULL;
+extern void drop_io_head(jnode * node) NONNULL;
+
+static inline reiser4_tree *jnode_get_tree(const jnode * node)
+{
+	assert("nikita-2691", node != NULL);
+	return node->tree;
+}
+
+extern void pin_jnode_data(jnode *);
+extern void unpin_jnode_data(jnode *);
+
+static inline jnode_type jnode_get_type(const jnode * node)
+{
+	static const unsigned long state_mask =
+	    (1 << JNODE_TYPE_1) | (1 << JNODE_TYPE_2) | (1 << JNODE_TYPE_3);
+
+	static jnode_type mask_to_type[] = {
+		/*  JNODE_TYPE_3 : JNODE_TYPE_2 : JNODE_TYPE_1 */
+
+		/* 000 */
+		[0] = JNODE_FORMATTED_BLOCK,
+		/* 001 */
+		[1] = JNODE_UNFORMATTED_BLOCK,
+		/* 010 */
+		[2] = JNODE_BITMAP,
+		/* 011 */
+		[3] = LAST_JNODE_TYPE,	/*invalid */
+		/* 100 */
+		[4] = JNODE_INODE,
+		/* 101 */
+		[5] = LAST_JNODE_TYPE,
+		/* 110 */
+		[6] = JNODE_IO_HEAD,
+		/* 111 */
+		[7] = LAST_JNODE_TYPE,	/* invalid */
+	};
+
+	return mask_to_type[(node->state & state_mask) >> JNODE_TYPE_1];
+}
+
+/* returns true if node is a znode */
+static inline int jnode_is_znode(const jnode * node)
+{
+	return jnode_get_type(node) == JNODE_FORMATTED_BLOCK;
+}
+
+static inline int jnode_is_flushprepped(jnode * node)
+{
+	assert("jmacd-78212", node != NULL);
+	assert_spin_locked(&(node->guard));
+	return !JF_ISSET(node, JNODE_DIRTY) || JF_ISSET(node, JNODE_RELOC) ||
+		JF_ISSET(node, JNODE_OVRWR);
+}
+
+/* Return true if @node has already been processed by the squeeze and allocate
+   process.  This implies the block address has been finalized for the
+   duration of this atom (or it is clean and will remain in place).  If this
+   returns true you may use the block number as a hint. */
+static inline int jnode_check_flushprepped(jnode * node)
+{
+	int result;
+
+	/* It must be clean or relocated or wandered.  New allocations are set to relocate. */
+	spin_lock_jnode(node);
+	result = jnode_is_flushprepped(node);
+	spin_unlock_jnode(node);
+	return result;
+}
+
+/* returns true if node is unformatted */
+static inline int jnode_is_unformatted(const jnode * node)
+{
+	assert("jmacd-0123", node != NULL);
+	return jnode_get_type(node) == JNODE_UNFORMATTED_BLOCK;
+}
+
+/* returns true if node represents a cluster cache page */
+static inline int jnode_is_cluster_page(const jnode * node)
+{
+	assert("edward-50", node != NULL);
+	return (JF_ISSET(node, JNODE_CLUSTER_PAGE));
+}
+
+/* returns true is node is builtin inode's jnode */
+static inline int jnode_is_inode(const jnode * node)
+{
+	assert("vs-1240", node != NULL);
+	return jnode_get_type(node) == JNODE_INODE;
+}
+
+static inline jnode_plugin *jnode_ops_of(const jnode_type type)
+{
+	assert("nikita-2367", type < LAST_JNODE_TYPE);
+	return jnode_plugin_by_id((reiser4_plugin_id) type);
+}
+
+static inline jnode_plugin *jnode_ops(const jnode * node)
+{
+	assert("nikita-2366", node != NULL);
+
+	return jnode_ops_of(jnode_get_type(node));
+}
+
+/* Get the index of a block. */
+static inline unsigned long jnode_get_index(jnode * node)
+{
+	return jnode_ops(node)->index(node);
+}
+
+/* return true if "node" is the root */
+static inline int jnode_is_root(const jnode * node)
+{
+	return jnode_is_znode(node) && znode_is_root(JZNODE(node));
+}
+
+extern struct address_space *mapping_jnode(const jnode * node);
+extern unsigned long index_jnode(const jnode * node);
+
+static inline void jput(jnode * node);
+extern void jput_final(jnode * node);
+
+/* bump data counter on @node */
+static inline void add_d_ref(jnode * node /* node to increase d_count of */ )
+{
+	assert("nikita-1962", node != NULL);
+
+	atomic_inc(&node->d_count);
+	if (jnode_is_unformatted(node) || jnode_is_znode(node))
+		LOCK_CNT_INC(d_refs);
+}
+
+/* jput() - decrement x_count reference counter on znode.
+
+   Count may drop to 0, jnode stays in cache until memory pressure causes the
+   eviction of its page. The c_count variable also ensures that children are
+   pressured out of memory before the parent. The jnode remains hashed as
+   long as the VM allows its page to stay in memory.
+*/
+static inline void jput(jnode * node)
+{
+	assert("jmacd-509", node != NULL);
+	assert("jmacd-510", atomic_read(&node->x_count) > 0);
+	assert("zam-926", schedulable());
+	LOCK_CNT_DEC(x_refs);
+
+	rcu_read_lock();
+	/*
+	 * we don't need any kind of lock here--jput_final() uses RCU.
+	 */
+	if (unlikely(atomic_dec_and_test(&node->x_count))) {
+		jput_final(node);
+	} else
+		rcu_read_unlock();
+	assert("nikita-3473", schedulable());
+}
+
+extern void jrelse(jnode * node);
+extern void jrelse_tail(jnode * node);
+
+extern jnode *jnode_rip_sync(reiser4_tree * t, jnode * node);
+
+/* resolve race with jput */
+static inline jnode *jnode_rip_check(reiser4_tree * tree, jnode * node)
+{
+	if (unlikely(JF_ISSET(node, JNODE_RIP)))
+		node = jnode_rip_sync(tree, node);
+	return node;
+}
+
+extern reiser4_key *jnode_build_key(const jnode *node, reiser4_key * key);
+
+#if REISER4_DEBUG
+extern int jnode_invariant_f(const jnode *node, char const **msg);
+#endif
+
+extern jnode_plugin jnode_plugins[LAST_JNODE_TYPE];
+
+/* __JNODE_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/kassign.c newtree/fs/reiser4/kassign.c
--- oldtree/fs/reiser4/kassign.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/kassign.c	2006-02-21 15:58:34.841849792 +0000
@@ -0,0 +1,659 @@
+/* Copyright 2001, 2002, 2003, 2004 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Key assignment policy implementation */
+
+/*
+ * In reiser4 every piece of file system data and meta-data has a key. Keys
+ * are used to store information in and retrieve it from reiser4 internal
+ * tree. In addition to this, keys define _ordering_ of all file system
+ * information: things having close keys are placed into the same or
+ * neighboring (in the tree order) nodes of the tree. As our block allocator
+ * tries to respect tree order (see flush.c), keys also define order in which
+ * things are laid out on the disk, and hence, affect performance directly.
+ *
+ * Obviously, assignment of keys to data and meta-data should be consistent
+ * across whole file system. Algorithm that calculates a key for a given piece
+ * of data or meta-data is referred to as "key assignment".
+ *
+ * Key assignment is too expensive to be implemented as a plugin (that is,
+ * with an ability to support different key assignment schemas in the same
+ * compiled kernel image). As a compromise, all key-assignment functions and
+ * data-structures are collected in this single file, so that modifications to
+ * key assignment algorithm can be localized. Additional changes may be
+ * required in key.[ch].
+ *
+ * Current default reiser4 key assignment algorithm is dubbed "Plan A". As one
+ * may guess, there is "Plan B" too.
+ *
+ */
+
+/*
+ * Additional complication with key assignment implementation is a requirement
+ * to support different key length.
+ */
+
+/*
+ *                   KEY ASSIGNMENT: PLAN A, LONG KEYS.
+ *
+ * DIRECTORY ITEMS
+ *
+ *  |       60     | 4 | 7 |1|   56        |        64        |        64       |
+ *  +--------------+---+---+-+-------------+------------------+-----------------+
+ *  |    dirid     | 0 | F |H|  prefix-1   |    prefix-2      |  prefix-3/hash  |
+ *  +--------------+---+---+-+-------------+------------------+-----------------+
+ *  |                  |                   |                  |                 |
+ *  |    8 bytes       |      8 bytes      |     8 bytes      |     8 bytes     |
+ *
+ * dirid         objectid of directory this item is for
+ *
+ * F             fibration, see fs/reiser4/plugin/fibration.[ch]
+ *
+ * H             1 if last 8 bytes of the key contain hash,
+ *               0 if last 8 bytes of the key contain prefix-3
+ *
+ * prefix-1      first 7 characters of file name.
+ *               Padded by zeroes if name is not long enough.
+ *
+ * prefix-2      next 8 characters of the file name.
+ *
+ * prefix-3      next 8 characters of the file name.
+ *
+ * hash          hash of the rest of file name (i.e., portion of file
+ *               name not included into prefix-1 and prefix-2).
+ *
+ * File names shorter than 23 (== 7 + 8 + 8) characters are completely encoded
+ * in the key. Such file names are called "short". They are distinguished by H
+ * bit set 0 in the key.
+ *
+ * Other file names are "long". For long name, H bit is 1, and first 15 (== 7
+ * + 8) characters are encoded in prefix-1 and prefix-2 portions of the
+ * key. Last 8 bytes of the key are occupied by hash of the remaining
+ * characters of the name.
+ *
+ * This key assignment reaches following important goals:
+ *
+ *     (1) directory entries are sorted in approximately lexicographical
+ *     order.
+ *
+ *     (2) collisions (when multiple directory items have the same key), while
+ *     principally unavoidable in a tree with fixed length keys, are rare.
+ *
+ * STAT DATA
+ *
+ *  |       60     | 4 |       64        | 4 |     60       |        64       |
+ *  +--------------+---+-----------------+---+--------------+-----------------+
+ *  |  locality id | 1 |    ordering     | 0 |  objectid    |        0        |
+ *  +--------------+---+-----------------+---+--------------+-----------------+
+ *  |                  |                 |                  |                 |
+ *  |    8 bytes       |    8 bytes      |     8 bytes      |     8 bytes     |
+ *
+ * locality id     object id of a directory where first name was created for
+ *                 the object
+ *
+ * ordering        copy of second 8-byte portion of the key of directory
+ *                 entry for the first name of this object. Ordering has a form
+ *                         {
+ *                                 fibration :7;
+ *                                 h         :1;
+ *                                 prefix1   :56;
+ *                         }
+ *                 see description of key for directory entry above.
+ *
+ * objectid        object id for this object
+ *
+ * This key assignment policy is designed to keep stat-data in the same order
+ * as corresponding directory items, thus speeding up readdir/stat types of
+ * workload.
+ *
+ * FILE BODY
+ *
+ *  |       60     | 4 |       64        | 4 |     60       |        64       |
+ *  +--------------+---+-----------------+---+--------------+-----------------+
+ *  |  locality id | 4 |    ordering     | 0 |  objectid    |      offset     |
+ *  +--------------+---+-----------------+---+--------------+-----------------+
+ *  |                  |                 |                  |                 |
+ *  |    8 bytes       |    8 bytes      |     8 bytes      |     8 bytes     |
+ *
+ * locality id     object id of a directory where first name was created for
+ *                 the object
+ *
+ * ordering        the same as in the key of stat-data for this object
+ *
+ * objectid        object id for this object
+ *
+ * offset          logical offset from the beginning of this file.
+ *                 Measured in bytes.
+ *
+ *
+ *                   KEY ASSIGNMENT: PLAN A, SHORT KEYS.
+ *
+ * DIRECTORY ITEMS
+ *
+ *  |       60     | 4 | 7 |1|   56        |        64       |
+ *  +--------------+---+---+-+-------------+-----------------+
+ *  |    dirid     | 0 | F |H|  prefix-1   |  prefix-2/hash  |
+ *  +--------------+---+---+-+-------------+-----------------+
+ *  |                  |                   |                 |
+ *  |    8 bytes       |      8 bytes      |     8 bytes     |
+ *
+ * dirid         objectid of directory this item is for
+ *
+ * F             fibration, see fs/reiser4/plugin/fibration.[ch]
+ *
+ * H             1 if last 8 bytes of the key contain hash,
+ *               0 if last 8 bytes of the key contain prefix-2
+ *
+ * prefix-1      first 7 characters of file name.
+ *               Padded by zeroes if name is not long enough.
+ *
+ * prefix-2      next 8 characters of the file name.
+ *
+ * hash          hash of the rest of file name (i.e., portion of file
+ *               name not included into prefix-1).
+ *
+ * File names shorter than 15 (== 7 + 8) characters are completely encoded in
+ * the key. Such file names are called "short". They are distinguished by H
+ * bit set in the key.
+ *
+ * Other file names are "long". For long name, H bit is 0, and first 7
+ * characters are encoded in prefix-1 portion of the key. Last 8 bytes of the
+ * key are occupied by hash of the remaining characters of the name.
+ *
+ * STAT DATA
+ *
+ *  |       60     | 4 | 4 |     60       |        64       |
+ *  +--------------+---+---+--------------+-----------------+
+ *  |  locality id | 1 | 0 |  objectid    |        0        |
+ *  +--------------+---+---+--------------+-----------------+
+ *  |                  |                  |                 |
+ *  |    8 bytes       |     8 bytes      |     8 bytes     |
+ *
+ * locality id     object id of a directory where first name was created for
+ *                 the object
+ *
+ * objectid        object id for this object
+ *
+ * FILE BODY
+ *
+ *  |       60     | 4 | 4 |     60       |        64       |
+ *  +--------------+---+---+--------------+-----------------+
+ *  |  locality id | 4 | 0 |  objectid    |      offset     |
+ *  +--------------+---+---+--------------+-----------------+
+ *  |                  |                  |                 |
+ *  |    8 bytes       |     8 bytes      |     8 bytes     |
+ *
+ * locality id     object id of a directory where first name was created for
+ *                 the object
+ *
+ * objectid        object id for this object
+ *
+ * offset          logical offset from the beginning of this file.
+ *                 Measured in bytes.
+ *
+ *
+ */
+
+#include "debug.h"
+#include "key.h"
+#include "kassign.h"
+#include "vfs_ops.h"
+#include "inode.h"
+#include "super.h"
+#include "dscale.h"
+
+#include <linux/types.h>	/* for __u??  */
+#include <linux/fs.h>		/* for struct super_block, etc  */
+
+/* bitmask for H bit (see comment at the beginning of this file */
+static const __u64 longname_mark = 0x0100000000000000ull;
+/* bitmask for F and H portions of the key. */
+static const __u64 fibration_mask = 0xff00000000000000ull;
+
+/* return true if name is not completely encoded in @key */
+int is_longname_key(const reiser4_key * key)
+{
+	__u64 highpart;
+
+	assert("nikita-2863", key != NULL);
+	if (get_key_type(key) != KEY_FILE_NAME_MINOR)
+		print_key("oops", key);
+	assert("nikita-2864", get_key_type(key) == KEY_FILE_NAME_MINOR);
+
+	if (REISER4_LARGE_KEY)
+		highpart = get_key_ordering(key);
+	else
+		highpart = get_key_objectid(key);
+
+	return (highpart & longname_mark) ? 1 : 0;
+}
+
+/* return true if @name is too long to be completely encoded in the key */
+int is_longname(const char *name UNUSED_ARG, int len)
+{
+	if (REISER4_LARGE_KEY)
+		return len > 23;
+	else
+		return len > 15;
+}
+
+/* code ascii string into __u64.
+
+   Put characters of @name into result (@str) one after another starting
+   from @start_idx-th highest (arithmetically) byte. This produces
+   endian-safe encoding. memcpy(2) will not do.
+
+*/
+static __u64 pack_string(const char *name /* string to encode */ ,
+			 int start_idx	/* highest byte in result from
+					 * which to start encoding */ )
+{
+	unsigned i;
+	__u64 str;
+
+	str = 0;
+	for (i = 0; (i < sizeof str - start_idx) && name[i]; ++i) {
+		str <<= 8;
+		str |= (unsigned char)name[i];
+	}
+	str <<= (sizeof str - i - start_idx) << 3;
+	return str;
+}
+
+/* opposite to pack_string(). Takes value produced by pack_string(), restores
+ * string encoded in it and stores result in @buf */
+char *unpack_string(__u64 value, char *buf)
+{
+	do {
+		*buf = value >> (64 - 8);
+		if (*buf)
+			++buf;
+		value <<= 8;
+	} while (value != 0);
+	*buf = 0;
+	return buf;
+}
+
+/* obtain name encoded in @key and store it in @buf */
+char *extract_name_from_key(const reiser4_key * key, char *buf)
+{
+	char *c;
+
+	assert("nikita-2868", !is_longname_key(key));
+
+	c = buf;
+	if (REISER4_LARGE_KEY) {
+		c = unpack_string(get_key_ordering(key) & ~fibration_mask, c);
+		c = unpack_string(get_key_fulloid(key), c);
+	} else
+		c = unpack_string(get_key_fulloid(key) & ~fibration_mask, c);
+	unpack_string(get_key_offset(key), c);
+	return buf;
+}
+
+/**
+ * complete_entry_key - calculate entry key by name
+ * @dir: directory where entry is (or will be) in
+ * @name: name to calculate key of
+ * @len: lenth of name
+ * @result: place to store result in
+ *
+ * Sets fields of entry key @result which depend on file name.
+ * When REISER4_LARGE_KEY is defined three fields of @result are set: ordering,
+ * objectid and offset. Otherwise, objectid and offset are set.
+ */
+void complete_entry_key(const struct inode *dir, const char *name,
+			int len, reiser4_key *result)
+{
+#if REISER4_LARGE_KEY
+	__u64 ordering;
+	__u64 objectid;
+	__u64 offset;
+
+	assert("nikita-1139", dir != NULL);
+	assert("nikita-1142", result != NULL);
+	assert("nikita-2867", strlen(name) == len);
+
+	/*
+	 * key allocation algorithm for directory entries in case of large
+	 * keys:
+	 *
+	 * If name is not longer than 7 + 8 + 8 = 23 characters, put first 7
+	 * characters into ordering field of key, next 8 charactes (if any)
+	 * into objectid field of key and next 8 ones (of any) into offset
+	 * field of key
+	 *
+	 * If file name is longer than 23 characters, put first 7 characters
+	 * into key's ordering, next 8 to objectid and hash of remaining
+	 * characters into offset field.
+	 *
+	 * To distinguish above cases, in latter set up unused high bit in
+	 * ordering field.
+	 */
+
+	/* [0-6] characters to ordering */
+	ordering = pack_string(name, 1);
+	if (len > 7) {
+		/* [7-14] characters to objectid */
+		objectid = pack_string(name + 7, 0);
+		if (len > 15) {
+			if (len <= 23) {
+				/* [15-23] characters to offset */
+				offset = pack_string(name + 15, 0);
+			} else {
+				/* note in a key the fact that offset contains hash. */
+				ordering |= longname_mark;
+
+				/* offset is the hash of the file name's tail. */
+				offset = inode_hash_plugin(dir)->hash(name + 15,
+								      len - 15);
+			}
+		} else {
+			offset = 0ull;
+		}
+	} else {
+		objectid = 0ull;
+		offset = 0ull;
+	}
+
+	assert("nikita-3480", inode_fibration_plugin(dir) != NULL);
+	ordering |= inode_fibration_plugin(dir)->fibre(dir, name, len);
+
+	set_key_ordering(result, ordering);
+	set_key_fulloid(result, objectid);
+	set_key_offset(result, offset);
+	return;
+
+#else
+	__u64 objectid;
+	__u64 offset;
+
+	assert("nikita-1139", dir != NULL);
+	assert("nikita-1142", result != NULL);
+	assert("nikita-2867", strlen(name) == len);
+
+	/*
+	 * key allocation algorithm for directory entries in case of not large
+	 * keys:
+	 *
+	 * If name is not longer than 7 + 8 = 15 characters, put first 7
+	 * characters into objectid field of key, next 8 charactes (if any)
+	 * into offset field of key
+	 *
+	 * If file name is longer than 15 characters, put first 7 characters
+	 * into key's objectid, and hash of remaining characters into offset
+	 * field.
+	 *
+	 * To distinguish above cases, in latter set up unused high bit in
+	 * objectid field.
+	 */
+
+	/* [0-6] characters to objectid */
+	objectid = pack_string(name, 1);
+	if (len > 7) {
+		if (len <= 15) {
+			/* [7-14] characters to offset */
+			offset = pack_string(name + 7, 0);
+		} else {
+			/* note in a key the fact that offset contains hash. */
+			objectid |= longname_mark;
+
+			/* offset is the hash of the file name. */
+			offset = inode_hash_plugin(dir)->hash(name + 7,
+							      len - 7);
+		}
+	} else
+		offset = 0ull;
+
+	assert("nikita-3480", inode_fibration_plugin(dir) != NULL);
+	objectid |= inode_fibration_plugin(dir)->fibre(dir, name, len);
+
+	set_key_fulloid(result, objectid);
+	set_key_offset(result, offset);
+	return;
+#endif				/* ! REISER4_LARGE_KEY */
+}
+
+/* true, if @key is the key of "." */
+int is_dot_key(const reiser4_key * key /* key to check */ )
+{
+	assert("nikita-1717", key != NULL);
+	assert("nikita-1718", get_key_type(key) == KEY_FILE_NAME_MINOR);
+	return
+	    (get_key_ordering(key) == 0ull) &&
+	    (get_key_objectid(key) == 0ull) && (get_key_offset(key) == 0ull);
+}
+
+/* build key for stat-data.
+
+   return key of stat-data of this object. This should became sd plugin
+   method in the future. For now, let it be here.
+
+*/
+reiser4_key *build_sd_key(const struct inode * target /* inode of an object */ ,
+			  reiser4_key * result	/* resulting key of @target
+						   stat-data */ )
+{
+	assert("nikita-261", result != NULL);
+
+	reiser4_key_init(result);
+	set_key_locality(result, reiser4_inode_data(target)->locality_id);
+	set_key_ordering(result, get_inode_ordering(target));
+	set_key_objectid(result, get_inode_oid(target));
+	set_key_type(result, KEY_SD_MINOR);
+	set_key_offset(result, (__u64) 0);
+	return result;
+}
+
+/* encode part of key into &obj_key_id
+
+   This encodes into @id part of @key sufficient to restore @key later,
+   given that latter is key of object (key of stat-data).
+
+   See &obj_key_id
+*/
+int build_obj_key_id(const reiser4_key * key /* key to encode */ ,
+		     obj_key_id * id /* id where key is encoded in */ )
+{
+	assert("nikita-1151", key != NULL);
+	assert("nikita-1152", id != NULL);
+
+	memcpy(id, key, sizeof *id);
+	return 0;
+}
+
+/* encode reference to @obj in @id.
+
+   This is like build_obj_key_id() above, but takes inode as parameter. */
+int build_inode_key_id(const struct inode *obj /* object to build key of */ ,
+		       obj_key_id * id /* result */ )
+{
+	reiser4_key sdkey;
+
+	assert("nikita-1166", obj != NULL);
+	assert("nikita-1167", id != NULL);
+
+	build_sd_key(obj, &sdkey);
+	build_obj_key_id(&sdkey, id);
+	return 0;
+}
+
+/* decode @id back into @key
+
+   Restore key of object stat-data from @id. This is dual to
+   build_obj_key_id() above.
+*/
+int extract_key_from_id(const obj_key_id * id	/* object key id to extract key
+						 * from */ ,
+			reiser4_key * key /* result */ )
+{
+	assert("nikita-1153", id != NULL);
+	assert("nikita-1154", key != NULL);
+
+	reiser4_key_init(key);
+	memcpy(key, id, sizeof *id);
+	return 0;
+}
+
+/* extract objectid of directory from key of directory entry within said
+   directory.
+   */
+oid_t extract_dir_id_from_key(const reiser4_key * de_key	/* key of
+								 * directory
+								 * entry */ )
+{
+	assert("nikita-1314", de_key != NULL);
+	return get_key_locality(de_key);
+}
+
+/* encode into @id key of directory entry.
+
+   Encode into @id information sufficient to later distinguish directory
+   entries within the same directory. This is not whole key, because all
+   directory entries within directory item share locality which is equal
+   to objectid of their directory.
+
+*/
+int build_de_id(const struct inode *dir /* inode of directory */ ,
+		const struct qstr *name	/* name to be given to @obj by
+					 * directory entry being
+					 * constructed */ ,
+		de_id * id /* short key of directory entry */ )
+{
+	reiser4_key key;
+
+	assert("nikita-1290", dir != NULL);
+	assert("nikita-1292", id != NULL);
+
+	/* NOTE-NIKITA this is suboptimal. */
+	inode_dir_plugin(dir)->build_entry_key(dir, name, &key);
+	return build_de_id_by_key(&key, id);
+}
+
+/* encode into @id key of directory entry.
+
+   Encode into @id information sufficient to later distinguish directory
+   entries within the same directory. This is not whole key, because all
+   directory entries within directory item share locality which is equal
+   to objectid of their directory.
+
+*/
+int build_de_id_by_key(const reiser4_key * entry_key	/* full key of directory
+							 * entry */ ,
+		       de_id * id /* short key of directory entry */ )
+{
+	memcpy(id, ((__u64 *) entry_key) + 1, sizeof *id);
+	return 0;
+}
+
+/* restore from @id key of directory entry.
+
+   Function dual to build_de_id(): given @id and locality, build full
+   key of directory entry within directory item.
+
+*/
+int extract_key_from_de_id(const oid_t locality	/* locality of directory
+						 * entry */ ,
+			   const de_id * id /* directory entry id */ ,
+			   reiser4_key * key /* result */ )
+{
+	/* no need to initialise key here: all fields are overwritten */
+	memcpy(((__u64 *) key) + 1, id, sizeof *id);
+	set_key_locality(key, locality);
+	set_key_type(key, KEY_FILE_NAME_MINOR);
+	return 0;
+}
+
+/* compare two &de_id's */
+cmp_t de_id_cmp(const de_id * id1 /* first &de_id to compare */ ,
+		const de_id * id2 /* second &de_id to compare */ )
+{
+	/* NOTE-NIKITA ugly implementation */
+	reiser4_key k1;
+	reiser4_key k2;
+
+	extract_key_from_de_id((oid_t) 0, id1, &k1);
+	extract_key_from_de_id((oid_t) 0, id2, &k2);
+	return keycmp(&k1, &k2);
+}
+
+/* compare &de_id with key */
+cmp_t de_id_key_cmp(const de_id * id /* directory entry id to compare */ ,
+		    const reiser4_key * key /* key to compare */ )
+{
+	cmp_t result;
+	reiser4_key *k1;
+
+	k1 = (reiser4_key *) (((unsigned long)id) - sizeof key->el[0]);
+	result = KEY_DIFF_EL(k1, key, 1);
+	if (result == EQUAL_TO) {
+		result = KEY_DIFF_EL(k1, key, 2);
+		if (REISER4_LARGE_KEY && result == EQUAL_TO) {
+			result = KEY_DIFF_EL(k1, key, 3);
+		}
+	}
+	return result;
+}
+
+/*
+ * return number of bytes necessary to encode @inode identity.
+ */
+int inode_onwire_size(const struct inode *inode)
+{
+	int result;
+
+	result = dscale_bytes(get_inode_oid(inode));
+	result += dscale_bytes(get_inode_locality(inode));
+
+	/*
+	 * ordering is large (it usually has highest bits set), so it makes
+	 * little sense to dscale it.
+	 */
+	if (REISER4_LARGE_KEY)
+		result += sizeof(get_inode_ordering(inode));
+	return result;
+}
+
+/*
+ * encode @inode identity at @start
+ */
+char *build_inode_onwire(const struct inode *inode, char *start)
+{
+	start += dscale_write(start, get_inode_locality(inode));
+	start += dscale_write(start, get_inode_oid(inode));
+
+	if (REISER4_LARGE_KEY) {
+		put_unaligned(cpu_to_le64(get_inode_ordering(inode)), (__le64 *)start);
+		start += sizeof(get_inode_ordering(inode));
+	}
+	return start;
+}
+
+/*
+ * extract key that was previously encoded by build_inode_onwire() at @addr
+ */
+char *extract_obj_key_id_from_onwire(char *addr, obj_key_id * key_id)
+{
+	__u64 val;
+
+	addr += dscale_read(addr, &val);
+	val = (val << KEY_LOCALITY_SHIFT) | KEY_SD_MINOR;
+	put_unaligned(cpu_to_le64(val), (__le64 *)key_id->locality);
+	addr += dscale_read(addr, &val);
+	put_unaligned(cpu_to_le64(val), (__le64 *)key_id->objectid);
+#if REISER4_LARGE_KEY
+	memcpy(&key_id->ordering, addr, sizeof key_id->ordering);
+	addr += sizeof key_id->ordering;
+#endif
+	return addr;
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/kassign.h newtree/fs/reiser4/kassign.h
--- oldtree/fs/reiser4/kassign.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/kassign.h	2006-02-21 15:58:34.553893568 +0000
@@ -0,0 +1,110 @@
+/* Copyright 2001, 2002, 2003, 2004 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Key assignment policy interface. See kassign.c for details. */
+
+#if !defined( __KASSIGN_H__ )
+#define __KASSIGN_H__
+
+#include "forward.h"
+#include "key.h"
+#include "dformat.h"
+
+#include <linux/types.h>	/* for __u??  */
+#include <linux/fs.h>		/* for struct super_block, etc  */
+#include <linux/dcache.h>	/* for struct qstr */
+
+/* key assignment functions */
+
+/* Information from which key of file stat-data can be uniquely
+   restored. This depends on key assignment policy for
+   stat-data. Currently it's enough to store object id and locality id
+   (60+60==120) bits, because minor packing locality and offset of
+   stat-data key are always known constants: KEY_SD_MINOR and 0
+   respectively. For simplicity 4 bits are wasted in each id, and just
+   two 64 bit integers are stored.
+
+   This field has to be byte-aligned, because we don't want to waste
+   space in directory entries. There is another side of a coin of
+   course: we waste CPU and bus bandwidth in stead, by copying data back
+   and forth.
+
+   Next optimization: &obj_key_id is mainly used to address stat data from
+   directory entries. Under the assumption that majority of files only have
+   only name (one hard link) from *the* parent directory it seems reasonable
+   to only store objectid of stat data and take its locality from key of
+   directory item.
+
+   This requires some flag to be added to the &obj_key_id to distinguish
+   between these two cases. Remaining bits in flag byte are then asking to be
+   used to store file type.
+
+   This optimization requires changes in directory item handling code.
+
+*/
+typedef struct obj_key_id {
+	d8 locality[sizeof(__u64)];
+	 ON_LARGE_KEY(d8 ordering[sizeof(__u64)];
+	    )
+	d8 objectid[sizeof(__u64)];
+}
+obj_key_id;
+
+/* Information sufficient to uniquely identify directory entry within
+   compressed directory item.
+
+   For alignment issues see &obj_key_id above.
+*/
+typedef struct de_id {
+	ON_LARGE_KEY(d8 ordering[sizeof(__u64)];)
+	d8 objectid[sizeof(__u64)];
+	d8 offset[sizeof(__u64)];
+}
+de_id;
+
+extern int inode_onwire_size(const struct inode *obj);
+extern char *build_inode_onwire(const struct inode *obj, char *area);
+extern char *extract_obj_key_id_from_onwire(char *area, obj_key_id * key_id);
+
+extern int build_inode_key_id(const struct inode *obj, obj_key_id * id);
+extern int extract_key_from_id(const obj_key_id * id, reiser4_key * key);
+extern int build_obj_key_id(const reiser4_key * key, obj_key_id * id);
+extern oid_t extract_dir_id_from_key(const reiser4_key * de_key);
+extern int build_de_id(const struct inode *dir, const struct qstr *name,
+		       de_id * id);
+extern int build_de_id_by_key(const reiser4_key * entry_key, de_id * id);
+extern int extract_key_from_de_id(const oid_t locality, const de_id * id,
+				  reiser4_key * key);
+extern cmp_t de_id_cmp(const de_id * id1, const de_id * id2);
+extern cmp_t de_id_key_cmp(const de_id * id, const reiser4_key * key);
+
+extern int build_readdir_key_common(struct file *dir, reiser4_key * result);
+extern void build_entry_key_common(const struct inode *dir,
+				   const struct qstr *name,
+				   reiser4_key * result);
+extern void build_entry_key_stable_entry(const struct inode *dir,
+					 const struct qstr *name,
+					 reiser4_key * result);
+extern int is_dot_key(const reiser4_key * key);
+extern reiser4_key *build_sd_key(const struct inode *target,
+				 reiser4_key * result);
+
+extern int is_longname_key(const reiser4_key * key);
+extern int is_longname(const char *name, int len);
+extern char *extract_name_from_key(const reiser4_key * key, char *buf);
+extern char *unpack_string(__u64 value, char *buf);
+extern void complete_entry_key(const struct inode *dir, const char *name,
+			       int len, reiser4_key *result);
+
+/* __KASSIGN_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/key.c newtree/fs/reiser4/key.c
--- oldtree/fs/reiser4/key.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/key.c	2006-02-21 15:58:35.436759352 +0000
@@ -0,0 +1,137 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Key manipulations. */
+
+#include "debug.h"
+#include "key.h"
+#include "super.h"
+#include "reiser4.h"
+
+#include <linux/types.h>	/* for __u??  */
+
+/* Minimal possible key: all components are zero. It is presumed that this is
+   independent of key scheme. */
+static const reiser4_key MINIMAL_KEY = {
+	.el = {
+		0ull,
+		ON_LARGE_KEY(0ull,)
+		0ull,
+		0ull
+	}
+};
+
+/* Maximal possible key: all components are ~0. It is presumed that this is
+   independent of key scheme. */
+static const reiser4_key MAXIMAL_KEY = {
+	.el = {
+		__constant_cpu_to_le64(~0ull),
+		ON_LARGE_KEY(__constant_cpu_to_le64(~0ull),)
+		__constant_cpu_to_le64(~0ull),
+		__constant_cpu_to_le64(~0ull)
+	}
+};
+
+/* Initialize key. */
+void reiser4_key_init(reiser4_key * key /* key to init */ )
+{
+	assert("nikita-1169", key != NULL);
+	memset(key, 0, sizeof *key);
+}
+
+/* minimal possible key in the tree. Return pointer to the static storage. */
+const reiser4_key *min_key(void)
+{
+	return &MINIMAL_KEY;
+}
+
+/* maximum possible key in the tree. Return pointer to the static storage. */
+const reiser4_key *max_key(void)
+{
+	return &MAXIMAL_KEY;
+}
+
+#if REISER4_DEBUG
+/* debugging aid: print symbolic name of key type */
+static const char *type_name(unsigned int key_type /* key type */ )
+{
+	switch (key_type) {
+	case KEY_FILE_NAME_MINOR:
+		return "file name";
+	case KEY_SD_MINOR:
+		return "stat data";
+	case KEY_ATTR_NAME_MINOR:
+		return "attr name";
+	case KEY_ATTR_BODY_MINOR:
+		return "attr body";
+	case KEY_BODY_MINOR:
+		return "file body";
+	default:
+		return "unknown";
+	}
+}
+
+/* debugging aid: print human readable information about key */
+void print_key(const char *prefix /* prefix to print */ ,
+	       const reiser4_key * key /* key to print */ )
+{
+	/* turn bold on */
+	/* printf ("\033[1m"); */
+	if (key == NULL)
+		printk("%s: null key\n", prefix);
+	else {
+		if (REISER4_LARGE_KEY)
+			printk("%s: (%Lx:%x:%Lx:%Lx:%Lx:%Lx)", prefix,
+			       get_key_locality(key),
+			       get_key_type(key),
+			       get_key_ordering(key),
+			       get_key_band(key),
+			       get_key_objectid(key), get_key_offset(key));
+		else
+			printk("%s: (%Lx:%x:%Lx:%Lx:%Lx)", prefix,
+			       get_key_locality(key),
+			       get_key_type(key),
+			       get_key_band(key),
+			       get_key_objectid(key), get_key_offset(key));
+		/*
+		 * if this is a key of directory entry, try to decode part of
+		 * a name stored in the key, and output it.
+		 */
+		if (get_key_type(key) == KEY_FILE_NAME_MINOR) {
+			char buf[DE_NAME_BUF_LEN];
+			char *c;
+
+			c = buf;
+			c = unpack_string(get_key_ordering(key), c);
+			unpack_string(get_key_fulloid(key), c);
+			printk("[%s", buf);
+			if (is_longname_key(key))
+				/*
+				 * only part of the name is stored in the key.
+				 */
+				printk("...]\n");
+			else {
+				/*
+				 * whole name is stored in the key.
+				 */
+				unpack_string(get_key_offset(key), buf);
+				printk("%s]\n", buf);
+			}
+		} else {
+			printk("[%s]\n", type_name(get_key_type(key)));
+		}
+	}
+	/* turn bold off */
+	/* printf ("\033[m\017"); */
+}
+
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/key.h newtree/fs/reiser4/key.h
--- oldtree/fs/reiser4/key.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/key.h	2006-02-21 15:58:35.403764368 +0000
@@ -0,0 +1,384 @@
+/* Copyright 2000, 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Declarations of key-related data-structures and operations on keys. */
+
+#if !defined( __REISER4_KEY_H__ )
+#define __REISER4_KEY_H__
+
+#include "dformat.h"
+#include "forward.h"
+#include "debug.h"
+
+#include <linux/types.h>	/* for __u??  */
+
+/* Operations on keys in reiser4 tree */
+
+/* No access to any of these fields shall be done except via a
+   wrapping macro/function, and that wrapping macro/function shall
+   convert to little endian order.  Compare keys will consider cpu byte order. */
+
+/* A storage layer implementation difference between a regular unix file body and its attributes is in the typedef below
+   which causes all of the attributes of a file to be near in key to all of the other attributes for all of the files
+   within that directory, and not near to the file itself.  It is interesting to consider whether this is the wrong
+   approach, and whether there should be no difference at all. For current usage patterns this choice is probably the
+   right one.  */
+
+/* possible values for minor packing locality (4 bits required) */
+typedef enum {
+	/* file name */
+	KEY_FILE_NAME_MINOR = 0,
+	/* stat-data */
+	KEY_SD_MINOR = 1,
+	/* file attribute name */
+	KEY_ATTR_NAME_MINOR = 2,
+	/* file attribute value */
+	KEY_ATTR_BODY_MINOR = 3,
+	/* file body (tail or extent) */
+	KEY_BODY_MINOR = 4,
+} key_minor_locality;
+
+/* everything stored in the tree has a unique key, which means that the tree is (logically) fully ordered by key.
+   Physical order is determined by dynamic heuristics that attempt to reflect key order when allocating available space,
+   and by the repacker.  It is stylistically better to put aggregation information into the key.  Thus, if you want to
+   segregate extents from tails, it is better to give them distinct minor packing localities rather than changing
+   block_alloc.c to check the node type when deciding where to allocate the node.
+
+   The need to randomly displace new directories and large files disturbs this symmetry unfortunately.  However, it
+   should be noted that this is a need that is not clearly established given the existence of a repacker.  Also, in our
+   current implementation tails have a different minor packing locality from extents, and no files have both extents and
+   tails, so maybe symmetry can be had without performance cost after all.  Symmetry is what we ship for now....
+*/
+
+/* Arbitrary major packing localities can be assigned to objects using
+   the reiser4(filenameA/..packing<=some_number) system call.
+
+   In reiser4, the creat() syscall creates a directory
+
+   whose default flow (that which is referred to if the directory is
+   read as a file) is the traditional unix file body.
+
+   whose directory plugin is the 'filedir'
+
+   whose major packing locality is that of the parent of the object created.
+
+   The static_stat item is a particular commonly used directory
+   compression (the one for normal unix files).
+
+   The filedir plugin checks to see if the static_stat item exists.
+   There is a unique key for static_stat.  If yes, then it uses the
+   static_stat item for all of the values that it contains.  The
+   static_stat item contains a flag for each stat it contains which
+   indicates whether one should look outside the static_stat item for its
+   contents.
+*/
+
+/* offset of fields in reiser4_key. Value of each element of this enum
+    is index within key (thought as array of __u64's) where this field
+    is. */
+typedef enum {
+	/* major "locale", aka dirid. Sits in 1st element */
+	KEY_LOCALITY_INDEX = 0,
+	/* minor "locale", aka item type. Sits in 1st element */
+	KEY_TYPE_INDEX = 0,
+	ON_LARGE_KEY(KEY_ORDERING_INDEX,)
+	    /* "object band". Sits in 2nd element */
+	    KEY_BAND_INDEX,
+	/* objectid. Sits in 2nd element */
+	KEY_OBJECTID_INDEX = KEY_BAND_INDEX,
+	/* full objectid. Sits in 2nd element */
+	KEY_FULLOID_INDEX = KEY_BAND_INDEX,
+	/* Offset. Sits in 3rd element */
+	KEY_OFFSET_INDEX,
+	/* Name hash. Sits in 3rd element */
+	KEY_HASH_INDEX = KEY_OFFSET_INDEX,
+	KEY_CACHELINE_END = KEY_OFFSET_INDEX,
+	KEY_LAST_INDEX
+} reiser4_key_field_index;
+
+/* key in reiser4 internal "balanced" tree. It is just array of three
+    64bit integers in disk byte order (little-endian by default). This
+    array is actually indexed by reiser4_key_field.  Each __u64 within
+    this array is called "element". Logical key component encoded within
+    elements are called "fields".
+
+    We declare this as union with second component dummy to suppress
+    inconvenient array<->pointer casts implied in C. */
+union reiser4_key {
+	__le64 el[KEY_LAST_INDEX];
+	int pad;
+};
+
+/* bitmasks showing where within reiser4_key particular key is stored. */
+/* major locality occupies higher 60 bits of the first element */
+#define KEY_LOCALITY_MASK 0xfffffffffffffff0ull
+
+/* minor locality occupies lower 4 bits of the first element */
+#define KEY_TYPE_MASK 0xfull
+
+/* controversial band occupies higher 4 bits of the 2nd element */
+#define KEY_BAND_MASK 0xf000000000000000ull
+
+/* objectid occupies lower 60 bits of the 2nd element */
+#define KEY_OBJECTID_MASK 0x0fffffffffffffffull
+
+/* full 64bit objectid*/
+#define KEY_FULLOID_MASK 0xffffffffffffffffull
+
+/* offset is just 3rd L.M.Nt itself */
+#define KEY_OFFSET_MASK 0xffffffffffffffffull
+
+/* ordering is whole second element */
+#define KEY_ORDERING_MASK 0xffffffffffffffffull
+
+/* how many bits key element should be shifted to left to get particular field */
+typedef enum {
+	KEY_LOCALITY_SHIFT = 4,
+	KEY_TYPE_SHIFT = 0,
+	KEY_BAND_SHIFT = 60,
+	KEY_OBJECTID_SHIFT = 0,
+	KEY_FULLOID_SHIFT = 0,
+	KEY_OFFSET_SHIFT = 0,
+	KEY_ORDERING_SHIFT = 0,
+} reiser4_key_field_shift;
+
+static inline __u64
+get_key_el(const reiser4_key * key, reiser4_key_field_index off)
+{
+	assert("nikita-753", key != NULL);
+	assert("nikita-754", off < KEY_LAST_INDEX);
+	return le64_to_cpu(get_unaligned(&key->el[off]));
+}
+
+static inline void
+set_key_el(reiser4_key * key, reiser4_key_field_index off, __u64 value)
+{
+	assert("nikita-755", key != NULL);
+	assert("nikita-756", off < KEY_LAST_INDEX);
+	put_unaligned(cpu_to_le64(value), &key->el[off]);
+}
+
+/* macro to define getter and setter functions for field F with type T */
+#define DEFINE_KEY_FIELD( L, U, T )					\
+static inline T get_key_ ## L ( const reiser4_key *key )		\
+{									\
+	assert( "nikita-750", key != NULL );				\
+	return ( T ) ( get_key_el( key, KEY_ ## U ## _INDEX ) &		\
+		 KEY_ ## U ## _MASK ) >> KEY_ ## U ## _SHIFT;		\
+}									\
+									\
+static inline void set_key_ ## L ( reiser4_key *key, T loc )		\
+{									\
+	__u64 el;							\
+									\
+	assert( "nikita-752", key != NULL );				\
+									\
+	el = get_key_el( key, KEY_ ## U ## _INDEX );			\
+	/* clear field bits in the key */				\
+	el &= ~KEY_ ## U ## _MASK;					\
+	/* actually it should be					\
+									\
+	   el |= ( loc << KEY_ ## U ## _SHIFT ) & KEY_ ## U ## _MASK;	\
+									\
+	   but we trust user to never pass values that wouldn't fit	\
+	   into field. Clearing extra bits is one operation, but this	\
+	   function is time-critical.					\
+	   But check this in assertion. */				\
+	assert( "nikita-759", ( ( loc << KEY_ ## U ## _SHIFT ) &	\
+		~KEY_ ## U ## _MASK ) == 0 );				\
+	el |= ( loc << KEY_ ## U ## _SHIFT );				\
+	set_key_el( key, KEY_ ## U ## _INDEX, el );			\
+}
+
+typedef __u64 oid_t;
+
+/* define get_key_locality(), set_key_locality() */
+DEFINE_KEY_FIELD(locality, LOCALITY, oid_t);
+/* define get_key_type(), set_key_type() */
+DEFINE_KEY_FIELD(type, TYPE, key_minor_locality);
+/* define get_key_band(), set_key_band() */
+DEFINE_KEY_FIELD(band, BAND, __u64);
+/* define get_key_objectid(), set_key_objectid() */
+DEFINE_KEY_FIELD(objectid, OBJECTID, oid_t);
+/* define get_key_fulloid(), set_key_fulloid() */
+DEFINE_KEY_FIELD(fulloid, FULLOID, oid_t);
+/* define get_key_offset(), set_key_offset() */
+DEFINE_KEY_FIELD(offset, OFFSET, __u64);
+#if (REISER4_LARGE_KEY)
+/* define get_key_ordering(), set_key_ordering() */
+DEFINE_KEY_FIELD(ordering, ORDERING, __u64);
+#else
+static inline __u64 get_key_ordering(const reiser4_key * key)
+{
+	return 0;
+}
+
+static inline void set_key_ordering(reiser4_key * key, __u64 val)
+{
+}
+#endif
+
+/* key comparison result */
+typedef enum { LESS_THAN = -1,	/* if first key is less than second */
+	EQUAL_TO = 0,		/* if keys are equal */
+	GREATER_THAN = +1	/* if first key is greater than second */
+} cmp_t;
+
+void reiser4_key_init(reiser4_key * key);
+
+/* minimal possible key in the tree. Return pointer to the static storage. */
+extern const reiser4_key *min_key(void);
+extern const reiser4_key *max_key(void);
+
+/* helper macro for keycmp() */
+#define KEY_DIFF(k1, k2, field)							\
+({										\
+	typeof (get_key_ ## field (k1)) f1;                              	\
+	typeof (get_key_ ## field (k2)) f2;					\
+										\
+	f1 = get_key_ ## field (k1);						\
+	f2 = get_key_ ## field (k2);						\
+										\
+	(f1 < f2) ? LESS_THAN : ((f1 == f2) ? EQUAL_TO : GREATER_THAN);		\
+})
+
+/* helper macro for keycmp() */
+#define KEY_DIFF_EL(k1, k2, off)						\
+({										\
+	__u64 e1;								\
+	__u64 e2;								\
+										\
+	e1 = get_key_el(k1, off);						\
+	e2 = get_key_el(k2, off);						\
+										\
+	(e1 < e2) ? LESS_THAN : ((e1 == e2) ? EQUAL_TO : GREATER_THAN);		\
+})
+
+/* compare `k1' and `k2'.  This function is a heart of "key allocation
+    policy". All you need to implement new policy is to add yet another
+    clause here. */
+static inline cmp_t keycmp(const reiser4_key * k1 /* first key to compare */ ,
+			   const reiser4_key * k2 /* second key to compare */ )
+{
+	cmp_t result;
+
+	/*
+	 * This function is the heart of reiser4 tree-routines. Key comparison
+	 * is among most heavily used operations in the file system.
+	 */
+
+	assert("nikita-439", k1 != NULL);
+	assert("nikita-440", k2 != NULL);
+
+	/* there is no actual branch here: condition is compile time constant
+	 * and constant folding and propagation ensures that only one branch
+	 * is actually compiled in. */
+
+	if (REISER4_PLANA_KEY_ALLOCATION) {
+		/* if physical order of fields in a key is identical
+		   with logical order, we can implement key comparison
+		   as three 64bit comparisons. */
+		/* logical order of fields in plan-a:
+		   locality->type->objectid->offset. */
+		/* compare locality and type at once */
+		result = KEY_DIFF_EL(k1, k2, 0);
+		if (result == EQUAL_TO) {
+			/* compare objectid (and band if it's there) */
+			result = KEY_DIFF_EL(k1, k2, 1);
+			/* compare offset */
+			if (result == EQUAL_TO) {
+				result = KEY_DIFF_EL(k1, k2, 2);
+				if (REISER4_LARGE_KEY && result == EQUAL_TO) {
+					result = KEY_DIFF_EL(k1, k2, 3);
+				}
+			}
+		}
+	} else if (REISER4_3_5_KEY_ALLOCATION) {
+		result = KEY_DIFF(k1, k2, locality);
+		if (result == EQUAL_TO) {
+			result = KEY_DIFF(k1, k2, objectid);
+			if (result == EQUAL_TO) {
+				result = KEY_DIFF(k1, k2, type);
+				if (result == EQUAL_TO)
+					result = KEY_DIFF(k1, k2, offset);
+			}
+		}
+	} else
+		impossible("nikita-441", "Unknown key allocation scheme!");
+	return result;
+}
+
+/* true if @k1 equals @k2 */
+static inline int keyeq(const reiser4_key * k1 /* first key to compare */ ,
+			const reiser4_key * k2 /* second key to compare */ )
+{
+	assert("nikita-1879", k1 != NULL);
+	assert("nikita-1880", k2 != NULL);
+	return !memcmp(k1, k2, sizeof *k1);
+}
+
+/* true if @k1 is less than @k2 */
+static inline int keylt(const reiser4_key * k1 /* first key to compare */ ,
+			const reiser4_key * k2 /* second key to compare */ )
+{
+	assert("nikita-1952", k1 != NULL);
+	assert("nikita-1953", k2 != NULL);
+	return keycmp(k1, k2) == LESS_THAN;
+}
+
+/* true if @k1 is less than or equal to @k2 */
+static inline int keyle(const reiser4_key * k1 /* first key to compare */ ,
+			const reiser4_key * k2 /* second key to compare */ )
+{
+	assert("nikita-1954", k1 != NULL);
+	assert("nikita-1955", k2 != NULL);
+	return keycmp(k1, k2) != GREATER_THAN;
+}
+
+/* true if @k1 is greater than @k2 */
+static inline int keygt(const reiser4_key * k1 /* first key to compare */ ,
+			const reiser4_key * k2 /* second key to compare */ )
+{
+	assert("nikita-1959", k1 != NULL);
+	assert("nikita-1960", k2 != NULL);
+	return keycmp(k1, k2) == GREATER_THAN;
+}
+
+/* true if @k1 is greater than or equal to @k2 */
+static inline int keyge(const reiser4_key * k1 /* first key to compare */ ,
+			const reiser4_key * k2 /* second key to compare */ )
+{
+	assert("nikita-1956", k1 != NULL);
+	assert("nikita-1957", k2 != NULL);	/* October  4: sputnik launched
+						 * November 3: Laika */
+	return keycmp(k1, k2) != LESS_THAN;
+}
+
+static inline void prefetchkey(reiser4_key * key)
+{
+	prefetch(key);
+	prefetch(&key->el[KEY_CACHELINE_END]);
+}
+
+/* (%Lx:%x:%Lx:%Lx:%Lx:%Lx) =
+           1 + 16 + 1 + 1 + 1 + 1 + 1 + 16 + 1 + 16 + 1 + 16 + 1 */
+/* size of a buffer suitable to hold human readable key representation */
+#define KEY_BUF_LEN (80)
+
+#if REISER4_DEBUG
+extern void print_key(const char *prefix, const reiser4_key * key);
+#else
+#define print_key(p,k) noop
+#endif
+
+/* __FS_REISERFS_KEY_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/ktxnmgrd.c newtree/fs/reiser4/ktxnmgrd.c
--- oldtree/fs/reiser4/ktxnmgrd.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/ktxnmgrd.c	2006-02-21 15:58:34.842849640 +0000
@@ -0,0 +1,214 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+/* Transaction manager daemon. */
+
+/*
+ * ktxnmgrd is a kernel daemon responsible for committing transactions. It is
+ * needed/important for the following reasons:
+ *
+ *     1. in reiser4 atom is not committed immediately when last transaction
+ *     handle closes, unless atom is either too old or too large (see
+ *     atom_should_commit()). This is done to avoid committing too frequently.
+ *     because:
+ *
+ *     2. sometimes we don't want to commit atom when closing last transaction
+ *     handle even if it is old and fat enough. For example, because we are at
+ *     this point under directory semaphore, and committing would stall all
+ *     accesses to this directory.
+ *
+ * ktxnmgrd binds its time sleeping on condition variable. When is awakes
+ * either due to (tunable) timeout or because it was explicitly woken up by
+ * call to ktxnmgrd_kick(), it scans list of all atoms and commits ones
+ * eligible.
+ *
+ */
+
+#include "debug.h"
+#include "txnmgr.h"
+#include "tree.h"
+#include "ktxnmgrd.h"
+#include "super.h"
+#include "reiser4.h"
+
+#include <linux/sched.h>	/* for struct task_struct */
+#include <linux/wait.h>
+#include <linux/suspend.h>
+#include <linux/kernel.h>
+#include <linux/writeback.h>
+#include <linux/kthread.h>
+
+static int scan_mgr(struct super_block *);
+
+/*
+ * change current->comm so that ps, top, and friends will see changed
+ * state. This serves no useful purpose whatsoever, but also costs nothing. May
+ * be it will make lonely system administrator feeling less alone at 3 A.M.
+ */
+#define set_comm( state ) 						\
+	snprintf( current -> comm, sizeof( current -> comm ),	\
+		  "%s:%s:%s", __FUNCTION__, (super)->s_id, ( state ) )
+
+/**
+ * ktxnmgrd - kernel txnmgr daemon
+ * @arg: pointer to super block
+ *
+ * The background transaction manager daemon, started as a kernel thread during
+ * reiser4 initialization.
+ */
+static int ktxnmgrd(void *arg)
+{
+	struct super_block *super;
+	ktxnmgrd_context *ctx;
+	txn_mgr *mgr;
+	int done = 0;
+
+	super = arg;
+	mgr = &get_super_private(super)->tmgr;
+
+	/*
+	 * do_fork() just copies task_struct into the new thread. ->fs_context
+	 * shouldn't be copied of course. This shouldn't be a problem for the
+	 * rest of the code though.
+	 */
+	current->journal_info = NULL;
+	ctx = mgr->daemon;
+	while (1) {
+		try_to_freeze();
+		set_comm("wait");
+		{
+			DEFINE_WAIT(__wait);
+
+			prepare_to_wait(&ctx->wait, &__wait, TASK_INTERRUPTIBLE);
+			if (kthread_should_stop()) {
+				done = 1;
+			} else
+				schedule_timeout(ctx->timeout);
+			finish_wait(&ctx->wait, &__wait);
+		}
+		if (done)
+			break;
+		set_comm("run");
+		spin_lock(&ctx->guard);
+		/*
+		 * wait timed out or ktxnmgrd was woken up by explicit request
+		 * to commit something. Scan list of atoms in txnmgr and look
+		 * for too old atoms.
+		 */
+		do {
+			ctx->rescan = 0;
+			scan_mgr(super);
+			spin_lock(&ctx->guard);
+			if (ctx->rescan) {
+				/*
+				 * the list could be modified while ctx
+				 * spinlock was released, we have to repeat
+				 * scanning from the beginning
+				 */
+				break;
+			}
+		} while (ctx->rescan);
+		spin_unlock(&ctx->guard);
+	}
+	return 0;
+}
+
+#undef set_comm
+
+/**
+ * init_ktxnmgrd - initialize ktxnmgrd context and start kernel daemon
+ * @super: pointer to super block
+ *
+ * Allocates and initializes ktxnmgrd_context, attaches it to transaction
+ * manager. Starts kernel txnmgr daemon. This is called on mount.
+ */
+int init_ktxnmgrd(struct super_block *super)
+{
+	txn_mgr *mgr;
+	ktxnmgrd_context *ctx;
+
+	mgr = &get_super_private(super)->tmgr;
+
+	assert("zam-1014", mgr->daemon == NULL);
+
+	ctx = kmalloc(sizeof(ktxnmgrd_context), GFP_KERNEL);
+	if (ctx == NULL)
+		return RETERR(-ENOMEM);
+
+	assert("nikita-2442", ctx != NULL);
+
+	memset(ctx, 0, sizeof *ctx);
+	init_waitqueue_head(&ctx->wait);
+
+	/*kcond_init(&ctx->startup);*/
+	spin_lock_init(&ctx->guard);
+	ctx->timeout = REISER4_TXNMGR_TIMEOUT;
+	ctx->rescan = 1;
+	mgr->daemon = ctx;
+
+	ctx->tsk = kthread_run(ktxnmgrd, super, "ktxnmgrd");
+	if (IS_ERR(ctx->tsk)) {
+		int ret = PTR_ERR(ctx->tsk);
+		mgr->daemon = NULL;
+		kfree(ctx);
+		return RETERR(ret);
+	}
+	return 0;
+}
+
+void ktxnmgrd_kick(txn_mgr *mgr)
+{
+	assert("nikita-3234", mgr != NULL);
+	assert("nikita-3235", mgr->daemon != NULL);
+	wake_up(&mgr->daemon->wait);
+}
+
+int is_current_ktxnmgrd(void)
+{
+	return (get_current_super_private()->tmgr.daemon->tsk == current);
+}
+
+/**
+ * scan_mgr - commit atoms which are to be committed
+ * @super: super block to commit atoms of
+ *
+ * Commits old atoms.
+ */
+static int scan_mgr(struct super_block *super)
+{
+	int ret;
+	reiser4_context ctx;
+
+	init_stack_context(&ctx, super);
+
+	ret = commit_some_atoms(&get_super_private(super)->tmgr);
+
+	reiser4_exit_context(&ctx);
+	return ret;
+}
+
+/**
+ * done_ktxnmgrd - stop kernel thread and frees ktxnmgrd context
+ * @mgr:
+ *
+ * This is called on umount. Stops ktxnmgrd and free t
+ */
+void done_ktxnmgrd(struct super_block *super)
+{
+	txn_mgr *mgr;
+
+	mgr = &get_super_private(super)->tmgr;
+	assert("zam-1012", mgr->daemon != NULL);
+
+	kthread_stop(mgr->daemon->tsk);
+	kfree(mgr->daemon);
+	mgr->daemon = NULL;
+}
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 120
+ * End:
+ */
diff -urN oldtree/fs/reiser4/ktxnmgrd.h newtree/fs/reiser4/ktxnmgrd.h
--- oldtree/fs/reiser4/ktxnmgrd.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/ktxnmgrd.h	2006-02-21 15:58:34.978828968 +0000
@@ -0,0 +1,52 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Transaction manager daemon. See ktxnmgrd.c for comments. */
+
+#ifndef __KTXNMGRD_H__
+#define __KTXNMGRD_H__
+
+#include "txnmgr.h"
+
+#include <linux/fs.h>
+#include <linux/wait.h>
+#include <linux/completion.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include <linux/sched.h>	/* for struct task_struct */
+
+/* in this structure all data necessary to start up, shut down and communicate
+ * with ktxnmgrd are kept. */
+struct ktxnmgrd_context {
+	/* wait queue head on which ktxnmgrd sleeps */
+	wait_queue_head_t wait;
+	/* spin lock protecting all fields of this structure */
+	spinlock_t guard;
+	/* timeout of sleeping on ->wait */
+	signed long timeout;
+	/* kernel thread running ktxnmgrd */
+	struct task_struct *tsk;
+	/* list of all file systems served by this ktxnmgrd */
+	struct list_head queue;
+	/* should ktxnmgrd repeat scanning of atoms? */
+	unsigned int rescan:1;
+};
+
+extern int init_ktxnmgrd(struct super_block *);
+extern void done_ktxnmgrd(struct super_block *);
+
+extern void ktxnmgrd_kick(txn_mgr * mgr);
+extern int is_current_ktxnmgrd(void);
+
+/* __KTXNMGRD_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/lock.c newtree/fs/reiser4/lock.c
--- oldtree/fs/reiser4/lock.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/lock.c	2006-02-21 15:58:35.438759048 +0000
@@ -0,0 +1,1280 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Traditional deadlock avoidance is achieved by acquiring all locks in a single
+   order.  V4 balances the tree from the bottom up, and searches the tree from
+   the top down, and that is really the way we want it, so tradition won't work
+   for us.
+
+   Instead we have two lock orderings, a high priority lock ordering, and a low
+   priority lock ordering.  Each node in the tree has a lock in its znode.
+
+   Suppose we have a set of processes which lock (R/W) tree nodes. Each process
+   has a set (maybe empty) of already locked nodes ("process locked set"). Each
+   process may have a pending lock request to a node locked by another process.
+   Note: we lock and unlock, but do not transfer locks: it is possible
+   transferring locks instead would save some bus locking....
+
+   Deadlock occurs when we have a loop constructed from process locked sets and
+   lock request vectors.
+
+   NOTE: The reiser4 "tree" is a tree on disk, but its cached representation in
+   memory is extended with "znodes" with which we connect nodes with their left
+   and right neighbors using sibling pointers stored in the znodes.  When we
+   perform balancing operations we often go from left to right and from right to
+   left.
+
+   +-P1-+          +-P3-+
+   |+--+|   V1     |+--+|
+   ||N1|| -------> ||N3||
+   |+--+|          |+--+|
+   +----+          +----+
+     ^               |
+     |V2             |V3
+     |               v
+   +---------P2---------+
+   |+--+            +--+|
+   ||N2|  --------  |N4||
+   |+--+            +--+|
+   +--------------------+
+
+   We solve this by ensuring that only low priority processes lock in top to
+   bottom order and from right to left, and high priority processes lock from
+   bottom to top and left to right.
+
+   ZAM-FIXME-HANS: order not just node locks in this way, order atom locks, and
+   kill those damn busy loops.
+   ANSWER(ZAM): atom locks (which are introduced by ASTAGE_CAPTURE_WAIT atom
+   stage) cannot be ordered that way. There are no rules what nodes can belong
+   to the atom and what nodes cannot.  We cannot define what is right or left
+   direction, what is top or bottom.  We can take immediate parent or side
+   neighbor of one node, but nobody guarantees that, say, left neighbor node is
+   not a far right neighbor for other nodes from the same atom.  It breaks
+   deadlock avoidance rules and hi-low priority locking cannot be applied for
+   atom locks.
+
+   How does it help to avoid deadlocks ?
+
+   Suppose we have a deadlock with n processes. Processes from one priority
+   class never deadlock because they take locks in one consistent
+   order.
+
+   So, any possible deadlock loop must have low priority as well as high
+   priority processes.  There are no other lock priority levels except low and
+   high. We know that any deadlock loop contains at least one node locked by a
+   low priority process and requested by a high priority process. If this
+   situation is caught and resolved it is sufficient to avoid deadlocks.
+
+   V4 DEADLOCK PREVENTION ALGORITHM IMPLEMENTATION.
+
+   The deadlock prevention algorithm is based on comparing
+   priorities of node owners (processes which keep znode locked) and
+   requesters (processes which want to acquire a lock on znode).  We
+   implement a scheme where low-priority owners yield locks to
+   high-priority requesters. We created a signal passing system that
+   is used to ask low-priority processes to yield one or more locked
+   znodes.
+
+   The condition when a znode needs to change its owners is described by the
+   following formula:
+
+   #############################################
+   #                                           #
+   # (number of high-priority requesters) >  0 #
+   #                AND                        #
+   # (numbers of high-priority owners)    == 0 #
+   #                                           #
+   #############################################
+
+   Note that a low-priority process delays node releasing if another
+   high-priority process owns this node.  So, slightly more strictly speaking,
+   to have a deadlock capable cycle you must have a loop in which a high
+   priority process is waiting on a low priority process to yield a node, which
+   is slightly different from saying a high priority process is waiting on a
+   node owned by a low priority process.
+
+   It is enough to avoid deadlocks if we prevent any low-priority process from
+   falling asleep if its locked set contains a node which satisfies the
+   deadlock condition.
+
+   That condition is implicitly or explicitly checked in all places where new
+   high-priority requests may be added or removed from node request queue or
+   high-priority process takes or releases a lock on node. The main
+   goal of these checks is to never lose the moment when node becomes "has
+   wrong owners" and send "must-yield-this-lock" signals to its low-pri owners
+   at that time.
+
+   The information about received signals is stored in the per-process
+   structure (lock stack) and analyzed before a low-priority process goes to
+   sleep but after a "fast" attempt to lock a node fails. Any signal wakes
+   sleeping process up and forces him to re-check lock status and received
+   signal info. If "must-yield-this-lock" signals were received the locking
+   primitive (longterm_lock_znode()) fails with -E_DEADLOCK error code.
+
+   V4 LOCKING DRAWBACKS
+
+   If we have already balanced on one level, and we are propagating our changes
+   upward to a higher level, it could be very messy to surrender all locks on
+   the lower level because we put so much computational work into it, and
+   reverting them to their state before they were locked might be very complex.
+   We also don't want to acquire all locks before performing balancing because
+   that would either be almost as much work as the balancing, or it would be
+   too conservative and lock too much.  We want balancing to be done only at
+   high priority.  Yet, we might want to go to the left one node and use some
+   of its empty space... So we make one attempt at getting the node to the left
+   using try_lock, and if it fails we do without it, because we didn't really
+   need it, it was only a nice to have.
+
+   LOCK STRUCTURES DESCRIPTION
+
+   The following data structures are used in the reiser4 locking
+   implementation:
+
+   All fields related to long-term locking are stored in znode->lock.
+
+   The lock stack is a per thread object.  It owns all znodes locked by the
+   thread. One znode may be locked by several threads in case of read lock or
+   one znode may be write locked by one thread several times. The special link
+   objects (lock handles) support n<->m relation between znodes and lock
+   owners.
+
+   <Thread 1>                       <Thread 2>
+
+   +---------+                     +---------+
+   |  LS1    |		           |  LS2    |
+   +---------+			   +---------+
+       ^                                ^
+       |---------------+                +----------+
+       v               v                v          v
+   +---------+      +---------+    +---------+   +---------+
+   |  LH1    |      |   LH2   |	   |  LH3    |   |   LH4   |
+   +---------+	    +---------+	   +---------+   +---------+
+       ^                   ^            ^           ^
+       |                   +------------+           |
+       v                   v                        v
+   +---------+      +---------+                  +---------+
+   |  Z1     |	    |	Z2    |                  |  Z3     |
+   +---------+	    +---------+                  +---------+
+
+   Thread 1 locked znodes Z1 and Z2, thread 2 locked znodes Z2 and Z3. The
+   picture above shows that lock stack LS1 has a list of 2 lock handles LH1 and
+   LH2, lock stack LS2 has a list with lock handles LH3 and LH4 on it.  Znode
+   Z1 is locked by only one thread, znode has only one lock handle LH1 on its
+   list, similar situation is for Z3 which is locked by the thread 2 only. Z2
+   is locked (for read) twice by different threads and two lock handles are on
+   its list. Each lock handle represents a single relation of a locking of a
+   znode by a thread. Locking of a znode is an establishing of a locking
+   relation between the lock stack and the znode by adding of a new lock handle
+   to a list of lock handles, the lock stack.  The lock stack links all lock
+   handles for all znodes locked by the lock stack.  The znode list groups all
+   lock handles for all locks stacks which locked the znode.
+
+   Yet another relation may exist between znode and lock owners.  If lock
+   procedure cannot immediately take lock on an object it adds the lock owner
+   on special `requestors' list belongs to znode.  That list represents a
+   queue of pending lock requests.  Because one lock owner may request only
+   only one lock object at a time, it is a 1->n relation between lock objects
+   and a lock owner implemented as it is described above. Full information
+   (priority, pointers to lock and link objects) about each lock request is
+   stored in lock owner structure in `request' field.
+
+   SHORT_TERM LOCKING
+
+   This is a list of primitive operations over lock stacks / lock handles /
+   znodes and locking descriptions for them.
+
+   1. locking / unlocking which is done by two list insertion/deletion, one
+      to/from znode's list of lock handles, another one is to/from lock stack's
+      list of lock handles.  The first insertion is protected by
+      znode->lock.guard spinlock.  The list owned by the lock stack can be
+      modified only by thread who owns the lock stack and nobody else can
+      modify/read it. There is nothing to be protected by a spinlock or
+      something else.
+
+   2. adding/removing a lock request to/from znode requesters list. The rule is
+      that znode->lock.guard spinlock should be taken for this.
+
+   3. we can traverse list of lock handles and use references to lock stacks who
+      locked given znode if znode->lock.guard spinlock is taken.
+
+   4. If a lock stack is associated with a znode as a lock requestor or lock
+      owner its existence is guaranteed by znode->lock.guard spinlock.  Some its
+      (lock stack's) fields should be protected from being accessed in parallel
+      by two or more threads. Please look at  lock_stack structure definition
+      for the info how those fields are protected. */
+
+/* Znode lock and capturing intertwining. */
+/* In current implementation we capture formatted nodes before locking
+   them. Take a look on longterm lock znode, try_capture() request precedes
+   locking requests.  The longterm_lock_znode function unconditionally captures
+   znode before even checking of locking conditions.
+
+   Another variant is to capture znode after locking it.  It was not tested, but
+   at least one deadlock condition is supposed to be there.  One thread has
+   locked a znode (Node-1) and calls try_capture() for it.  Try_capture() sleeps
+   because znode's atom has CAPTURE_WAIT state.  Second thread is a flushing
+   thread, its current atom is the atom Node-1 belongs to. Second thread wants
+   to lock Node-1 and sleeps because Node-1 is locked by the first thread.  The
+   described situation is a deadlock. */
+
+#include "debug.h"
+#include "txnmgr.h"
+#include "znode.h"
+#include "jnode.h"
+#include "tree.h"
+#include "plugin/node/node.h"
+#include "super.h"
+
+#include <linux/spinlock.h>
+
+#if REISER4_DEBUG
+static int request_is_deadlock_safe(znode *, znode_lock_mode,
+				    znode_lock_request);
+#endif
+
+/* Returns a lock owner associated with current thread */
+lock_stack *get_current_lock_stack(void)
+{
+	return &get_current_context()->stack;
+}
+
+/* Wakes up all low priority owners informing them about possible deadlock */
+static void wake_up_all_lopri_owners(znode * node)
+{
+	lock_handle *handle;
+
+	assert_spin_locked(&(node->lock.guard));
+	list_for_each_entry(handle, &node->lock.owners, owners_link) {
+		spin_lock_stack(handle->owner);
+
+		assert("nikita-1832", handle->node == node);
+		/* count this signal in owner->nr_signaled */
+		if (!handle->signaled) {
+			handle->signaled = 1;
+			atomic_inc(&handle->owner->nr_signaled);
+			/* Wake up a single process */
+			__reiser4_wake_up(handle->owner);
+		}
+		spin_unlock_stack(handle->owner);
+	}
+}
+
+/* Adds a lock to a lock owner, which means creating a link to the lock and
+   putting the link into the two lists all links are on (the doubly linked list
+   that forms the lock_stack, and the doubly linked list of links attached
+   to a lock.
+*/
+static inline void
+link_object(lock_handle * handle, lock_stack * owner, znode * node)
+{
+	assert("jmacd-810", handle->owner == NULL);
+	assert_spin_locked(&(node->lock.guard));
+
+	handle->owner = owner;
+	handle->node = node;
+
+	assert("reiser4-4",
+	       ergo(list_empty_careful(&owner->locks), owner->nr_locks == 0));
+
+	/* add lock handle to the end of lock_stack's list of locks */
+	list_add_tail(&handle->locks_link, &owner->locks);
+	owner->nr_locks++;
+
+	/* add lock handle to the head of znode's list of owners */
+	list_add(&handle->owners_link, &node->lock.owners);
+	handle->signaled = 0;
+}
+
+/* Breaks a relation between a lock and its owner */
+static inline void unlink_object(lock_handle * handle)
+{
+	assert("zam-354", handle->owner != NULL);
+	assert("nikita-1608", handle->node != NULL);
+	assert_spin_locked(&(handle->node->lock.guard));
+	assert("nikita-1829", handle->owner == get_current_lock_stack());
+	assert("reiser4-5", handle->owner->nr_locks > 0);
+
+	/* remove lock handle from lock_stack's list of locks */
+	list_del_init(&handle->locks_link);
+	handle->owner->nr_locks--;
+	assert("reiser4-6",
+	       ergo(list_empty_careful(&handle->owner->locks),
+		    handle->owner->nr_locks == 0));
+
+	/* remove lock handle from znode's list of owners */
+	list_del_init(&handle->owners_link);
+
+	/* indicates that lock handle is free now */
+	handle->owner = NULL;
+}
+
+/* Actually locks an object knowing that we are able to do this */
+static void lock_object(lock_stack * owner)
+{
+	lock_request *request;
+	znode *node;
+
+	request = &owner->request;
+	node = request->node;
+	assert_spin_locked(&(node->lock.guard));
+	if (request->mode == ZNODE_READ_LOCK) {
+		node->lock.nr_readers++;
+	} else {
+		/* check that we don't switched from read to write lock */
+		assert("nikita-1840", node->lock.nr_readers <= 0);
+		/* We allow recursive locking; a node can be locked several
+		   times for write by same process */
+		node->lock.nr_readers--;
+	}
+
+	link_object(request->handle, owner, node);
+
+	if (owner->curpri) {
+		node->lock.nr_hipri_owners++;
+	}
+}
+
+/* Check for recursive write locking */
+static int recursive(lock_stack * owner)
+{
+	int ret;
+	znode *node;
+	lock_handle *lh;
+
+	node = owner->request.node;
+
+	/* Owners list is not empty for a locked node */
+	assert("zam-314", !list_empty_careful(&node->lock.owners));
+	assert("nikita-1841", owner == get_current_lock_stack());
+	assert_spin_locked(&(node->lock.guard));
+
+
+	lh = list_entry(node->lock.owners.next, lock_handle, owners_link);
+	ret = (lh->owner == owner);
+
+	/* Recursive read locking should be done usual way */
+	assert("zam-315", !ret || owner->request.mode == ZNODE_WRITE_LOCK);
+	/* mixing of read/write locks is not allowed */
+	assert("zam-341", !ret || znode_is_wlocked(node));
+
+	return ret;
+}
+
+#if REISER4_DEBUG
+/* Returns true if the lock is held by the calling thread. */
+int znode_is_any_locked(const znode * node)
+{
+	lock_handle *handle;
+	lock_stack *stack;
+	int ret;
+
+	if (!znode_is_locked(node)) {
+		return 0;
+	}
+
+	stack = get_current_lock_stack();
+
+	spin_lock_stack(stack);
+
+	ret = 0;
+
+	list_for_each_entry(handle, &stack->locks, locks_link) {
+		if (handle->node == node) {
+			ret = 1;
+			break;
+		}
+	}
+
+	spin_unlock_stack(stack);
+
+	return ret;
+}
+
+#endif
+
+/* Returns true if a write lock is held by the calling thread. */
+int znode_is_write_locked(const znode * node)
+{
+	lock_stack *stack;
+	lock_handle *handle;
+
+	assert("jmacd-8765", node != NULL);
+
+	if (!znode_is_wlocked(node)) {
+		return 0;
+	}
+
+	stack = get_current_lock_stack();
+
+	/*
+	 * When znode is write locked, all owner handles point to the same lock
+	 * stack. Get pointer to lock stack from the first lock handle from
+	 * znode's owner list
+	 */
+	handle = list_entry(node->lock.owners.next, lock_handle, owners_link);
+
+	return (handle->owner == stack);
+}
+
+/* This "deadlock" condition is the essential part of reiser4 locking
+   implementation. This condition is checked explicitly by calling
+   check_deadlock_condition() or implicitly in all places where znode lock
+   state (set of owners and request queue) is changed. Locking code is
+   designed to use this condition to trigger procedure of passing object from
+   low priority owner(s) to high priority one(s).
+
+   The procedure results in passing an event (setting lock_handle->signaled
+   flag) and counting this event in nr_signaled field of owner's lock stack
+   object and wakeup owner's process.
+*/
+static inline int check_deadlock_condition(znode * node)
+{
+	assert_spin_locked(&(node->lock.guard));
+	return node->lock.nr_hipri_requests > 0
+	    && node->lock.nr_hipri_owners == 0;
+}
+
+static int check_livelock_condition(znode * node, znode_lock_mode mode)
+{
+	zlock * lock = &node->lock;
+
+	return mode == ZNODE_READ_LOCK &&
+		lock -> nr_readers >= 0 && lock->nr_hipri_write_requests > 0;
+}
+
+/* checks lock/request compatibility */
+static int can_lock_object(lock_stack * owner)
+{
+	znode *node = owner->request.node;
+
+	assert_spin_locked(&(node->lock.guard));
+
+	/* See if the node is disconnected. */
+	if (unlikely(ZF_ISSET(node, JNODE_IS_DYING)))
+		return RETERR(-EINVAL);
+
+	/* Do not ever try to take a lock if we are going in low priority
+	   direction and a node have a high priority request without high
+	   priority owners. */
+	if (unlikely(!owner->curpri && check_deadlock_condition(node)))
+		return RETERR(-E_REPEAT);
+	if (unlikely(owner->curpri && check_livelock_condition(node, owner->request.mode)))
+		return RETERR(-E_REPEAT);
+	if (unlikely(!is_lock_compatible(node, owner->request.mode)))
+		return RETERR(-E_REPEAT);
+	return 0;
+}
+
+/* Setting of a high priority to the process. It clears "signaled" flags
+   because znode locked by high-priority process can't satisfy our "deadlock
+   condition". */
+static void set_high_priority(lock_stack * owner)
+{
+	assert("nikita-1846", owner == get_current_lock_stack());
+	/* Do nothing if current priority is already high */
+	if (!owner->curpri) {
+		/* We don't need locking for owner->locks list, because, this
+		 * function is only called with the lock stack of the current
+		 * thread, and no other thread can play with owner->locks list
+		 * and/or change ->node pointers of lock handles in this list.
+		 *
+		 * (Interrupts also are not involved.)
+		 */
+		lock_handle *item = list_entry(owner->locks.next, lock_handle, locks_link);
+		while (&owner->locks != &item->locks_link) {
+			znode *node = item->node;
+
+			spin_lock_zlock(&node->lock);
+
+			node->lock.nr_hipri_owners++;
+
+			/* we can safely set signaled to zero, because
+			   previous statement (nr_hipri_owners ++) guarantees
+			   that signaled will be never set again. */
+			item->signaled = 0;
+			spin_unlock_zlock(&node->lock);
+
+			item = list_entry(item->locks_link.next, lock_handle, locks_link);
+		}
+		owner->curpri = 1;
+		atomic_set(&owner->nr_signaled, 0);
+	}
+}
+
+/* Sets a low priority to the process. */
+static void set_low_priority(lock_stack * owner)
+{
+	assert("nikita-3075", owner == get_current_lock_stack());
+	/* Do nothing if current priority is already low */
+	if (owner->curpri) {
+		/* scan all locks (lock handles) held by @owner, which is
+		   actually current thread, and check whether we are reaching
+		   deadlock possibility anywhere.
+		 */
+		lock_handle *handle = list_entry(owner->locks.next, lock_handle, locks_link);
+		while (&owner->locks != &handle->locks_link) {
+			znode *node = handle->node;
+			spin_lock_zlock(&node->lock);
+			/* this thread just was hipri owner of @node, so
+			   nr_hipri_owners has to be greater than zero. */
+			assert("nikita-1835", node->lock.nr_hipri_owners > 0);
+			node->lock.nr_hipri_owners--;
+			/* If we have deadlock condition, adjust a nr_signaled
+			   field. It is enough to set "signaled" flag only for
+			   current process, other low-pri owners will be
+			   signaled and waken up after current process unlocks
+			   this object and any high-priority requestor takes
+			   control. */
+			if (check_deadlock_condition(node)
+			    && !handle->signaled) {
+				handle->signaled = 1;
+				atomic_inc(&owner->nr_signaled);
+			}
+			spin_unlock_zlock(&node->lock);
+			handle = list_entry(handle->locks_link.next, lock_handle, locks_link);
+		}
+		owner->curpri = 0;
+	}
+}
+
+static void remove_lock_request(lock_stack * requestor)
+{
+	zlock * lock = &requestor->request.node->lock;
+
+	if (requestor->curpri) {
+		assert("nikita-1838", lock->nr_hipri_requests > 0);
+		lock->nr_hipri_requests--;
+		if (requestor->request.mode == ZNODE_WRITE_LOCK)
+			lock->nr_hipri_write_requests --;
+	}
+	list_del_init(&requestor->requestors_link);
+}
+
+
+static void invalidate_all_lock_requests(znode * node)
+{
+	lock_stack *requestor, *tmp;
+
+	assert_spin_locked(&(node->lock.guard));
+
+	list_for_each_entry_safe(requestor, tmp, &node->lock.requestors, requestors_link) {
+		remove_lock_request(requestor);
+		requestor->request.ret_code = -EINVAL;
+		reiser4_wake_up(requestor);
+		requestor->request.mode = ZNODE_NO_LOCK;
+	}
+}
+
+static void dispatch_lock_requests(znode * node)
+{
+	lock_stack *requestor, *tmp;
+
+	assert_spin_locked(&(node->lock.guard));
+
+	list_for_each_entry_safe(requestor, tmp, &node->lock.requestors, requestors_link) {
+		if (znode_is_write_locked(node))
+			break;
+		if (!can_lock_object(requestor)) {
+			lock_object(requestor);
+			remove_lock_request(requestor);
+			requestor->request.ret_code = 0;
+			reiser4_wake_up(requestor);
+			requestor->request.mode = ZNODE_NO_LOCK;
+		}
+	}
+}
+
+/* release long-term lock, acquired by longterm_lock_znode() */
+void longterm_unlock_znode(lock_handle * handle)
+{
+	znode *node = handle->node;
+	lock_stack *oldowner = handle->owner;
+	int hipri;
+	int readers;
+	int rdelta;
+	int youdie;
+
+	/*
+	 * this is time-critical and highly optimized code. Modify carefully.
+	 */
+
+	assert("jmacd-1021", handle != NULL);
+	assert("jmacd-1022", handle->owner != NULL);
+	assert("nikita-1392", LOCK_CNT_GTZ(long_term_locked_znode));
+
+	assert("zam-130", oldowner == get_current_lock_stack());
+
+	LOCK_CNT_DEC(long_term_locked_znode);
+
+	/*
+	 * to minimize amount of operations performed under lock, pre-compute
+	 * all variables used within critical section. This makes code
+	 * obscure.
+	 */
+
+	/* was this lock of hi or lo priority */
+	hipri = oldowner->curpri ? -1 : 0;
+	/* number of readers */
+	readers = node->lock.nr_readers;
+	/* +1 if write lock, -1 if read lock */
+	rdelta = (readers > 0) ? -1 : +1;
+	/* true if node is to die and write lock is released */
+	youdie = ZF_ISSET(node, JNODE_HEARD_BANSHEE) && (readers < 0);
+
+	spin_lock_zlock(&node->lock);
+
+	assert("zam-101", znode_is_locked(node));
+
+	/* Adjust a number of high priority owners of this lock */
+	node->lock.nr_hipri_owners += hipri;
+	assert("nikita-1836", node->lock.nr_hipri_owners >= 0);
+
+	/* Handle znode deallocation on last write-lock release. */
+	if (znode_is_wlocked_once(node)) {
+		if (youdie) {
+			forget_znode(handle);
+			assert("nikita-2191", znode_invariant(node));
+			zput(node);
+			return;
+		}
+	}
+
+	if (handle->signaled)
+		atomic_dec(&oldowner->nr_signaled);
+
+	/* Unlocking means owner<->object link deletion */
+	unlink_object(handle);
+
+	/* This is enough to be sure whether an object is completely
+	   unlocked. */
+	node->lock.nr_readers += rdelta;
+
+	/* If the node is locked it must have an owners list.  Likewise, if
+	   the node is unlocked it must have an empty owners list. */
+	assert("zam-319", equi(znode_is_locked(node),
+			       !list_empty_careful(&node->lock.owners)));
+
+#if REISER4_DEBUG
+	if (!znode_is_locked(node))
+		++node->times_locked;
+#endif
+
+	/* If there are pending lock requests we wake up a requestor */
+	if (!znode_is_wlocked(node))
+		dispatch_lock_requests(node);
+	if (check_deadlock_condition(node))
+		wake_up_all_lopri_owners(node);
+	spin_unlock_zlock(&node->lock);
+
+	/* minus one reference from handle->node */
+	handle->node = NULL;
+	assert("nikita-2190", znode_invariant(node));
+	ON_DEBUG(check_lock_data());
+	ON_DEBUG(check_lock_node_data(node));
+	zput(node);
+}
+
+/* final portion of longterm-lock */
+static int
+lock_tail(lock_stack * owner, int ok, znode_lock_mode mode)
+{
+	znode *node = owner->request.node;
+
+	assert_spin_locked(&(node->lock.guard));
+
+	/* If we broke with (ok == 0) it means we can_lock, now do it. */
+	if (ok == 0) {
+		lock_object(owner);
+		owner->request.mode = 0;
+		/* count a reference from lockhandle->node
+
+		   znode was already referenced at the entry to this function,
+		   hence taking spin-lock here is not necessary (see comment
+		   in the zref()).
+		 */
+		zref(node);
+
+		LOCK_CNT_INC(long_term_locked_znode);
+	}
+	spin_unlock_zlock(&node->lock);
+	ON_DEBUG(check_lock_data());
+	ON_DEBUG(check_lock_node_data(node));
+	return ok;
+}
+
+/*
+ * version of longterm_znode_lock() optimized for the most common case: read
+ * lock without any special flags. This is the kind of lock that any tree
+ * traversal takes on the root node of the tree, which is very frequent.
+ */
+static int longterm_lock_tryfast(lock_stack * owner)
+{
+	int result;
+	znode *node;
+	zlock *lock;
+
+	node = owner->request.node;
+	lock = &node->lock;
+
+	assert("nikita-3340", schedulable());
+	assert("nikita-3341", request_is_deadlock_safe(node,
+						       ZNODE_READ_LOCK,
+						       ZNODE_LOCK_LOPRI));
+	spin_lock_zlock(lock);
+	result = can_lock_object(owner);
+	spin_unlock_zlock(lock);
+
+	if (likely(result != -EINVAL)) {
+		spin_lock_znode(node);
+		result =
+		    try_capture(ZJNODE(node), ZNODE_READ_LOCK, 0,
+				1 /* can copy on capture */ );
+		spin_unlock_znode(node);
+		spin_lock_zlock(lock);
+		if (unlikely(result != 0)) {
+			owner->request.mode = 0;
+		} else {
+			result = can_lock_object(owner);
+			if (unlikely(result == -E_REPEAT)) {
+				/* fall back to longterm_lock_znode() */
+				spin_unlock_zlock(lock);
+				return 1;
+			}
+		}
+		return lock_tail(owner, result, ZNODE_READ_LOCK);
+	} else
+		return 1;
+}
+
+/* locks given lock object */
+int longterm_lock_znode(
+			       /* local link object (allocated by lock owner thread, usually on its own
+			        * stack) */
+			       lock_handle * handle,
+			       /* znode we want to lock. */
+			       znode * node,
+			       /* {ZNODE_READ_LOCK, ZNODE_WRITE_LOCK}; */
+			       znode_lock_mode mode,
+			       /* {0, -EINVAL, -E_DEADLOCK}, see return codes description. */
+			       znode_lock_request request) {
+	int ret;
+	int hipri = (request & ZNODE_LOCK_HIPRI) != 0;
+	int non_blocking = 0;
+	int has_atom;
+	txn_capture cap_flags;
+	zlock *lock;
+	txn_handle *txnh;
+	tree_level level;
+
+	/* Get current process context */
+	lock_stack *owner = get_current_lock_stack();
+
+	/* Check that the lock handle is initialized and isn't already being
+	 * used. */
+	assert("jmacd-808", handle->owner == NULL);
+	assert("nikita-3026", schedulable());
+	assert("nikita-3219", request_is_deadlock_safe(node, mode, request));
+	assert("zam-1056", atomic_read(&ZJNODE(node)->x_count) > 0);
+	/* long term locks are not allowed in the VM contexts (->writepage(),
+	 * prune_{d,i}cache()).
+	 *
+	 * FIXME this doesn't work due to unused-dentry-with-unlinked-inode
+	 * bug caused by d_splice_alias() only working for directories.
+	 */
+	assert("nikita-3547", 1 || ((current->flags & PF_MEMALLOC) == 0));
+	assert ("zam-1055", mode != ZNODE_NO_LOCK);
+
+	cap_flags = 0;
+	if (request & ZNODE_LOCK_NONBLOCK) {
+		cap_flags |= TXN_CAPTURE_NONBLOCKING;
+		non_blocking = 1;
+	}
+
+	if (request & ZNODE_LOCK_DONT_FUSE)
+		cap_flags |= TXN_CAPTURE_DONT_FUSE;
+
+	/* If we are changing our process priority we must adjust a number
+	   of high priority owners for each znode that we already lock */
+	if (hipri) {
+		set_high_priority(owner);
+	} else {
+		set_low_priority(owner);
+	}
+
+	level = znode_get_level(node);
+
+	/* Fill request structure with our values. */
+	owner->request.mode = mode;
+	owner->request.handle = handle;
+	owner->request.node = node;
+
+	txnh = get_current_context()->trans;
+	lock = &node->lock;
+
+	if (mode == ZNODE_READ_LOCK && request == 0) {
+		ret = longterm_lock_tryfast(owner);
+		if (ret <= 0)
+			return ret;
+	}
+
+	has_atom = (txnh->atom != NULL);
+
+	/* Synchronize on node's zlock guard lock. */
+	spin_lock_zlock(lock);
+
+	if (znode_is_locked(node) &&
+	    mode == ZNODE_WRITE_LOCK && recursive(owner))
+		return lock_tail(owner, 0, mode);
+
+	for (;;) {
+		/* Check the lock's availability: if it is unavaiable we get
+		   E_REPEAT, 0 indicates "can_lock", otherwise the node is
+		   invalid.  */
+		ret = can_lock_object(owner);
+
+		if (unlikely(ret == -EINVAL)) {
+			/* @node is dying. Leave it alone. */
+			break;
+		}
+
+		if (unlikely(ret == -E_REPEAT && non_blocking)) {
+			/* either locking of @node by the current thread will
+			 * lead to the deadlock, or lock modes are
+			 * incompatible. */
+			break;
+		}
+
+		assert("nikita-1844", (ret == 0)
+		       || ((ret == -E_REPEAT) && !non_blocking));
+		/* If we can get the lock... Try to capture first before
+		   taking the lock. */
+
+		/* first handle commonest case where node and txnh are already
+		 * in the same atom. */
+		/* safe to do without taking locks, because:
+		 *
+		 * 1. read of aligned word is atomic with respect to writes to
+		 * this word
+		 *
+		 * 2. false negatives are handled in try_capture().
+		 *
+		 * 3. false positives are impossible.
+		 *
+		 * PROOF: left as an exercise to the curious reader.
+		 *
+		 * Just kidding. Here is one:
+		 *
+		 * At the time T0 txnh->atom is stored in txnh_atom.
+		 *
+		 * At the time T1 node->atom is stored in node_atom.
+		 *
+		 * At the time T2 we observe that
+		 *
+		 *     txnh_atom != NULL && node_atom == txnh_atom.
+		 *
+		 * Imagine that at this moment we acquire node and txnh spin
+		 * lock in this order. Suppose that under spin lock we have
+		 *
+		 *     node->atom != txnh->atom,                       (S1)
+		 *
+		 * at the time T3.
+		 *
+		 * txnh->atom != NULL still, because txnh is open by the
+		 * current thread.
+		 *
+		 * Suppose node->atom == NULL, that is, node was un-captured
+		 * between T1, and T3. But un-capturing of formatted node is
+		 * always preceded by the call to invalidate_lock(), which
+		 * marks znode as JNODE_IS_DYING under zlock spin
+		 * lock. Contradiction, because can_lock_object() above checks
+		 * for JNODE_IS_DYING. Hence, node->atom != NULL at T3.
+		 *
+		 * Suppose that node->atom != node_atom, that is, atom, node
+		 * belongs to was fused into another atom: node_atom was fused
+		 * into node->atom. Atom of txnh was equal to node_atom at T2,
+		 * which means that under spin lock, txnh->atom == node->atom,
+		 * because txnh->atom can only follow fusion
+		 * chain. Contradicts S1.
+		 *
+		 * The same for hypothesis txnh->atom != txnh_atom. Hence,
+		 * node->atom == node_atom == txnh_atom == txnh->atom. Again
+		 * contradicts S1. Hence S1 is false. QED.
+		 *
+		 */
+
+		if (likely(has_atom && ZJNODE(node)->atom == txnh->atom)) {
+			;
+		} else {
+			/*
+			 * unlock zlock spin lock here. It is possible for
+			 * longterm_unlock_znode() to sneak in here, but there
+			 * is no harm: invalidate_lock() will mark znode as
+			 * JNODE_IS_DYING and this will be noted by
+			 * can_lock_object() below.
+			 */
+			spin_unlock_zlock(lock);
+			spin_lock_znode(node);
+			ret =
+			    try_capture(ZJNODE(node), mode, cap_flags,
+					1 /* can copy on capture */ );
+			spin_unlock_znode(node);
+			spin_lock_zlock(lock);
+			if (unlikely(ret != 0)) {
+				/* In the failure case, the txnmgr releases
+				   the znode's lock (or in some cases, it was
+				   released a while ago).  There's no need to
+				   reacquire it so we should return here,
+				   avoid releasing the lock. */
+				owner->request.mode = 0;
+				break;
+			}
+
+			/* Check the lock's availability again -- this is
+			   because under some circumstances the capture code
+			   has to release and reacquire the znode spinlock. */
+			ret = can_lock_object(owner);
+		}
+
+		/* This time, a return of (ret == 0) means we can lock, so we
+		   should break out of the loop. */
+		if (likely(ret != -E_REPEAT || non_blocking)) {
+			break;
+		}
+
+		/* Lock is unavailable, we have to wait. */
+
+		/* By having semaphore initialization here we cannot lose
+		   wakeup signal even if it comes after `nr_signaled' field
+		   check. */
+		ret = prepare_to_sleep(owner);
+		if (unlikely(ret != 0)) {
+			break;
+		}
+
+		assert_spin_locked(&(node->lock.guard));
+		if (hipri) {
+			/* If we are going in high priority direction then
+			   increase high priority requests counter for the
+			   node */
+			lock->nr_hipri_requests++;
+			if (mode == ZNODE_WRITE_LOCK)
+				lock->nr_hipri_write_requests ++;
+			/* If there are no high priority owners for a node,
+			   then immediately wake up low priority owners, so
+			   they can detect possible deadlock */
+			if (lock->nr_hipri_owners == 0)
+				wake_up_all_lopri_owners(node);
+		}
+		list_add_tail(&owner->requestors_link, &lock->requestors);
+
+		/* Ok, here we have prepared a lock request, so unlock
+		   a znode ... */
+		spin_unlock_zlock(lock);
+		/* ... and sleep */
+		go_to_sleep(owner);
+		if (owner->request.mode == ZNODE_NO_LOCK)
+			goto request_is_done;
+		spin_lock_zlock(lock);
+		if (owner->request.mode == ZNODE_NO_LOCK) {
+			spin_unlock_zlock(lock);
+		request_is_done:
+			if (owner->request.ret_code == 0) {
+				LOCK_CNT_INC(long_term_locked_znode);
+				zref(node);
+			}
+			return owner->request.ret_code;
+		}
+		remove_lock_request(owner);
+	}
+
+	return lock_tail(owner, ret, mode);
+}
+
+/* lock object invalidation means changing of lock object state to `INVALID'
+   and waiting for all other processes to cancel theirs lock requests. */
+void invalidate_lock(lock_handle * handle	/* path to lock
+						 * owner and lock
+						 * object is being
+						 * invalidated. */ )
+{
+	znode *node = handle->node;
+	lock_stack *owner = handle->owner;
+
+	assert("zam-325", owner == get_current_lock_stack());
+	assert("zam-103", znode_is_write_locked(node));
+	assert("nikita-1393", !ZF_ISSET(node, JNODE_LEFT_CONNECTED));
+	assert("nikita-1793", !ZF_ISSET(node, JNODE_RIGHT_CONNECTED));
+	assert("nikita-1394", ZF_ISSET(node, JNODE_HEARD_BANSHEE));
+	assert("nikita-3097", znode_is_wlocked_once(node));
+	assert_spin_locked(&(node->lock.guard));
+
+	if (handle->signaled)
+		atomic_dec(&owner->nr_signaled);
+
+	ZF_SET(node, JNODE_IS_DYING);
+	unlink_object(handle);
+	node->lock.nr_readers = 0;
+
+	invalidate_all_lock_requests(node);
+	spin_unlock_zlock(&node->lock);
+}
+
+/* Initializes lock_stack. */
+void init_lock_stack(lock_stack * owner	/* pointer to
+					 * allocated
+					 * structure. */ )
+{
+	INIT_LIST_HEAD(&owner->locks);
+	INIT_LIST_HEAD(&owner->requestors_link);
+	spin_lock_init(&owner->sguard);
+	owner->curpri = 1;
+	sema_init(&owner->sema, 0);
+}
+
+/* Initializes lock object. */
+void reiser4_init_lock(zlock * lock	/* pointer on allocated
+					 * uninitialized lock object
+					 * structure. */ )
+{
+	memset(lock, 0, sizeof(zlock));
+	spin_lock_init(&lock->guard);
+	INIT_LIST_HEAD(&lock->requestors);
+	INIT_LIST_HEAD(&lock->owners);
+}
+
+/* lock handle initialization */
+void init_lh(lock_handle * handle)
+{
+	memset(handle, 0, sizeof *handle);
+	INIT_LIST_HEAD(&handle->locks_link);
+	INIT_LIST_HEAD(&handle->owners_link);
+}
+
+/* freeing of lock handle resources */
+void done_lh(lock_handle * handle)
+{
+	assert("zam-342", handle != NULL);
+	if (handle->owner != NULL)
+		longterm_unlock_znode(handle);
+}
+
+/* Transfer a lock handle (presumably so that variables can be moved between stack and
+   heap locations). */
+static void
+move_lh_internal(lock_handle * new, lock_handle * old, int unlink_old)
+{
+	znode *node = old->node;
+	lock_stack *owner = old->owner;
+	int signaled;
+
+	/* locks_list, modified by link_object() is not protected by
+	   anything. This is valid because only current thread ever modifies
+	   locks_list of its lock_stack.
+	 */
+	assert("nikita-1827", owner == get_current_lock_stack());
+	assert("nikita-1831", new->owner == NULL);
+
+	spin_lock_zlock(&node->lock);
+
+	signaled = old->signaled;
+	if (unlink_old) {
+		unlink_object(old);
+	} else {
+		if (node->lock.nr_readers > 0) {
+			node->lock.nr_readers += 1;
+		} else {
+			node->lock.nr_readers -= 1;
+		}
+		if (signaled) {
+			atomic_inc(&owner->nr_signaled);
+		}
+		if (owner->curpri) {
+			node->lock.nr_hipri_owners += 1;
+		}
+		LOCK_CNT_INC(long_term_locked_znode);
+
+		zref(node);
+	}
+	link_object(new, owner, node);
+	new->signaled = signaled;
+
+	spin_unlock_zlock(&node->lock);
+}
+
+void move_lh(lock_handle * new, lock_handle * old)
+{
+	move_lh_internal(new, old, /*unlink_old */ 1);
+}
+
+void copy_lh(lock_handle * new, lock_handle * old)
+{
+	move_lh_internal(new, old, /*unlink_old */ 0);
+}
+
+/* after getting -E_DEADLOCK we unlock znodes until this function returns false */
+int check_deadlock(void)
+{
+	lock_stack *owner = get_current_lock_stack();
+	return atomic_read(&owner->nr_signaled) != 0;
+}
+
+/* Before going to sleep we re-check "release lock" requests which might come from threads with hi-pri lock
+   priorities. */
+int prepare_to_sleep(lock_stack * owner)
+{
+	assert("nikita-1847", owner == get_current_lock_stack());
+	/* NOTE(Zam): We cannot reset the lock semaphore here because it may
+	   clear wake-up signal. The initial design was to re-check all
+	   conditions under which we continue locking, release locks or sleep
+	   until conditions are changed. However, even lock.c does not follow
+	   that design.  So, wake-up signal which is stored in semaphore state
+	   could we loosen by semaphore reset.  The less complex scheme without
+	   resetting the semaphore is enough to not to loose wake-ups.
+
+	   if (0) {
+
+	   NOTE-NIKITA: I commented call to sema_init() out hoping
+	   that it is the reason or thread sleeping in
+	   down(&owner->sema) without any other thread running.
+
+	   Anyway, it is just an optimization: is semaphore is not
+	   reinitialised at this point, in the worst case
+	   longterm_lock_znode() would have to iterate its loop once
+	   more.
+	   spin_lock_stack(owner);
+	   sema_init(&owner->sema, 0);
+	   spin_unlock_stack(owner);
+	   }
+	 */
+
+	/* We return -E_DEADLOCK if one or more "give me the lock" messages are
+	 * counted in nr_signaled */
+	if (unlikely(atomic_read(&owner->nr_signaled) != 0)) {
+		assert("zam-959", !owner->curpri);
+		return RETERR(-E_DEADLOCK);
+	}
+	return 0;
+}
+
+/* Wakes up a single thread */
+void __reiser4_wake_up(lock_stack * owner)
+{
+	up(&owner->sema);
+}
+
+/* Puts a thread to sleep */
+void go_to_sleep(lock_stack * owner)
+{
+	/* Well, we might sleep here, so holding of any spinlocks is no-no */
+	assert("nikita-3027", schedulable());
+	/* return down_interruptible(&owner->sema); */
+	down(&owner->sema);
+}
+
+int lock_stack_isclean(lock_stack * owner)
+{
+	if (list_empty_careful(&owner->locks)) {
+		assert("zam-353", atomic_read(&owner->nr_signaled) == 0);
+		return 1;
+	}
+
+	return 0;
+}
+
+#if REISER4_DEBUG
+
+/*
+ * debugging functions
+ */
+
+static void list_check(struct list_head *head)
+{
+	struct list_head *pos;
+
+	list_for_each(pos, head)
+		assert("", (pos->prev != NULL && pos->next != NULL &&
+			    pos->prev->next == pos && pos->next->prev == pos));
+}
+
+/* check consistency of locking data-structures hanging of the @stack */
+static void check_lock_stack(lock_stack * stack)
+{
+	spin_lock_stack(stack);
+	/* check that stack->locks is not corrupted */
+	list_check(&stack->locks);
+	spin_unlock_stack(stack);
+}
+
+/* check consistency of locking data structures */
+void check_lock_data(void)
+{
+	check_lock_stack(&get_current_context()->stack);
+}
+
+/* check consistency of locking data structures for @node */
+void check_lock_node_data(znode * node)
+{
+	spin_lock_zlock(&node->lock);
+	list_check(&node->lock.owners);
+	list_check(&node->lock.requestors);
+	spin_unlock_zlock(&node->lock);
+}
+
+/* check that given lock request is dead lock safe. This check is, of course,
+ * not exhaustive. */
+static int
+request_is_deadlock_safe(znode * node, znode_lock_mode mode,
+			 znode_lock_request request)
+{
+	lock_stack *owner;
+
+	owner = get_current_lock_stack();
+	/*
+	 * check that hipri lock request is not issued when there are locked
+	 * nodes at the higher levels.
+	 */
+	if (request & ZNODE_LOCK_HIPRI && !(request & ZNODE_LOCK_NONBLOCK) &&
+	    znode_get_level(node) != 0) {
+		lock_handle *item;
+
+		list_for_each_entry(item, &owner->locks, locks_link) {
+			znode *other;
+
+			other = item->node;
+
+			if (znode_get_level(other) == 0)
+				continue;
+			if (znode_get_level(other) > znode_get_level(node))
+				return 0;
+		}
+	}
+	return 1;
+}
+
+#endif
+
+/* return pointer to static storage with name of lock_mode. For
+    debugging */
+const char *lock_mode_name(znode_lock_mode lock /* lock mode to get name of */ )
+{
+	if (lock == ZNODE_READ_LOCK)
+		return "read";
+	else if (lock == ZNODE_WRITE_LOCK)
+		return "write";
+	else {
+		static char buf[30];
+
+		sprintf(buf, "unknown: %i", lock);
+		return buf;
+	}
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 79
+   End:
+*/
diff -urN oldtree/fs/reiser4/lock.h newtree/fs/reiser4/lock.h
--- oldtree/fs/reiser4/lock.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/lock.h	2006-02-21 15:58:35.438759048 +0000
@@ -0,0 +1,254 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Long term locking data structures. See lock.c for details. */
+
+#ifndef __LOCK_H__
+#define __LOCK_H__
+
+#include "forward.h"
+#include "debug.h"
+#include "dformat.h"
+#include "key.h"
+#include "coord.h"
+#include "plugin/node/node.h"
+#include "txnmgr.h"
+#include "readahead.h"
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/pagemap.h>	/* for PAGE_CACHE_SIZE */
+#include <asm/atomic.h>
+#include <asm/semaphore.h>
+
+/* Per-znode lock object */
+struct zlock {
+	spinlock_t guard;
+	/* The number of readers if positive; the number of recursively taken
+	   write locks if negative. Protected by zlock spin lock. */
+	int nr_readers;
+	/* A number of processes (lock_stacks) that have this object
+	   locked with high priority */
+	unsigned nr_hipri_owners;
+	/* A number of attempts to lock znode in high priority direction */
+	unsigned nr_hipri_requests;
+	/* A linked list of lock_handle objects that contains pointers
+	   for all lock_stacks which have this lock object locked */
+	unsigned nr_hipri_write_requests;
+	struct list_head owners;
+	/* A linked list of lock_stacks that wait for this lock */
+	struct list_head requestors;
+};
+
+static inline void spin_lock_zlock(zlock *lock)
+{
+	/* check that zlock is not locked */
+	assert("", LOCK_CNT_NIL(spin_locked_zlock));
+	/* check that spinlocks of lower priorities are not held */
+	assert("", LOCK_CNT_NIL(spin_locked_stack));
+
+	spin_lock(&lock->guard);
+
+	LOCK_CNT_INC(spin_locked_zlock);
+	LOCK_CNT_INC(spin_locked);
+}
+
+static inline void spin_unlock_zlock(zlock *lock)
+{
+	assert("nikita-1375", LOCK_CNT_GTZ(spin_locked_zlock));
+	assert("nikita-1376", LOCK_CNT_GTZ(spin_locked));
+
+	LOCK_CNT_DEC(spin_locked_zlock);
+	LOCK_CNT_DEC(spin_locked);
+
+	spin_unlock(&lock->guard);
+}
+
+#define lock_is_locked(lock)          ((lock)->nr_readers != 0)
+#define lock_is_rlocked(lock)         ((lock)->nr_readers > 0)
+#define lock_is_wlocked(lock)         ((lock)->nr_readers < 0)
+#define lock_is_wlocked_once(lock)    ((lock)->nr_readers == -1)
+#define lock_can_be_rlocked(lock)     ((lock)->nr_readers >=0)
+#define lock_mode_compatible(lock, mode)				\
+             (((mode) == ZNODE_WRITE_LOCK && !lock_is_locked(lock)) ||	\
+              ((mode) == ZNODE_READ_LOCK && lock_can_be_rlocked(lock)))
+
+/* Since we have R/W znode locks we need additional bidirectional `link'
+   objects to implement n<->m relationship between lock owners and lock
+   objects. We call them `lock handles'.
+
+   Locking: see lock.c/"SHORT-TERM LOCKING"
+*/
+struct lock_handle {
+	/* This flag indicates that a signal to yield a lock was passed to
+	   lock owner and counted in owner->nr_signalled
+
+	   Locking: this is accessed under spin lock on ->node.
+	 */
+	int signaled;
+	/* A link to owner of a lock */
+	lock_stack *owner;
+	/* A link to znode locked */
+	znode *node;
+	/* A list of all locks for a process */
+	struct list_head locks_link;
+	/* A list of all owners for a znode */
+	struct list_head owners_link;
+};
+
+typedef struct lock_request {
+	/* A pointer to uninitialized link object */
+	lock_handle *handle;
+	/* A pointer to the object we want to lock */
+	znode *node;
+	/* Lock mode (ZNODE_READ_LOCK or ZNODE_WRITE_LOCK) */
+	znode_lock_mode mode;
+	/* how dispatch_lock_requests() returns lock request result code */
+	int ret_code;
+} lock_request;
+
+/* A lock stack structure for accumulating locks owned by a process */
+struct lock_stack {
+	/* A guard lock protecting a lock stack */
+	spinlock_t sguard;
+	/* number of znodes which were requested by high priority processes */
+	atomic_t nr_signaled;
+	/* Current priority of a process
+
+	   This is only accessed by the current thread and thus requires no
+	   locking.
+	 */
+	int curpri;
+	/* A list of all locks owned by this process. Elements can be added to
+	 * this list only by the current thread. ->node pointers in this list
+	 * can be only changed by the current thread. */
+	struct list_head locks;
+	int nr_locks;		/* number of lock handles in the above list */
+	/* When lock_stack waits for the lock, it puts itself on double-linked
+	   requestors list of that lock */
+	struct list_head requestors_link;
+	/* Current lock request info.
+
+	   This is only accessed by the current thread and thus requires no
+	   locking.
+	 */
+	lock_request request;
+	/* It is a lock_stack's synchronization object for when process sleeps
+	   when requested lock not on this lock_stack but which it wishes to
+	   add to this lock_stack is not immediately available. It is used
+	   instead of wait_queue_t object due to locking problems (lost wake
+	   up). "lost wakeup" occurs when process is waken up before he actually
+	   becomes 'sleepy' (through sleep_on()). Using of semaphore object is
+	   simplest way to avoid that problem.
+
+	   A semaphore is used in the following way: only the process that is
+	   the owner of the lock_stack initializes it (to zero) and calls
+	   down(sema) on it. Usually this causes the process to sleep on the
+	   semaphore. Other processes may wake him up by calling up(sema). The
+	   advantage to a semaphore is that up() and down() calls are not
+	   required to preserve order. Unlike wait_queue it works when process
+	   is woken up before getting to sleep.
+
+	   NOTE-NIKITA: Transaction manager is going to have condition variables
+	   (&kcondvar_t) anyway, so this probably will be replaced with
+	   one in the future.
+
+	   After further discussion, Nikita has shown me that Zam's implementation is
+	   exactly a condition variable.  The znode's {zguard,requestors_list} represents
+	   condition variable and the lock_stack's {sguard,semaphore} guards entry and
+	   exit from the condition variable's wait queue.  But the existing code can't
+	   just be replaced with a more general abstraction, and I think its fine the way
+	   it is. */
+	struct semaphore sema;
+};
+
+
+/*
+  User-visible znode locking functions
+*/
+
+extern int longterm_lock_znode(lock_handle * handle,
+			       znode * node,
+			       znode_lock_mode mode,
+			       znode_lock_request request);
+
+extern void longterm_unlock_znode(lock_handle * handle);
+
+extern int check_deadlock(void);
+
+extern lock_stack *get_current_lock_stack(void);
+
+extern void init_lock_stack(lock_stack * owner);
+extern void reiser4_init_lock(zlock * lock);
+
+extern void init_lh(lock_handle *);
+extern void move_lh(lock_handle * new, lock_handle * old);
+extern void copy_lh(lock_handle * new, lock_handle * old);
+extern void done_lh(lock_handle *);
+
+extern int prepare_to_sleep(lock_stack * owner);
+extern void go_to_sleep(lock_stack * owner);
+extern void __reiser4_wake_up(lock_stack * owner);
+
+extern int lock_stack_isclean(lock_stack * owner);
+
+/* zlock object state check macros: only used in assertions.  Both forms imply that the
+   lock is held by the current thread. */
+extern int znode_is_write_locked(const znode *);
+extern void invalidate_lock(lock_handle *);
+
+/* lock ordering is: first take zlock spin lock, then lock stack spin lock */
+#define spin_ordering_pred_stack(stack)			\
+	(LOCK_CNT_NIL(spin_locked_stack) &&		\
+	 LOCK_CNT_NIL(spin_locked_txnmgr) &&		\
+	 LOCK_CNT_NIL(spin_locked_inode) &&		\
+	 LOCK_CNT_NIL(rw_locked_cbk_cache) &&		\
+	 LOCK_CNT_NIL(spin_locked_super_eflush) )
+
+static inline void spin_lock_stack(lock_stack *stack)
+{
+	assert("", spin_ordering_pred_stack(stack));
+	spin_lock(&(stack->sguard));
+	LOCK_CNT_INC(spin_locked_stack);
+	LOCK_CNT_INC(spin_locked);
+}
+
+static inline void spin_unlock_stack(lock_stack *stack)
+{
+	assert_spin_locked(&(stack->sguard));
+	assert("nikita-1375", LOCK_CNT_GTZ(spin_locked_stack));
+	assert("nikita-1376", LOCK_CNT_GTZ(spin_locked));
+	LOCK_CNT_DEC(spin_locked_stack);
+	LOCK_CNT_DEC(spin_locked);
+	spin_unlock(&(stack->sguard));
+}
+
+
+static inline void reiser4_wake_up(lock_stack * owner)
+{
+	spin_lock_stack(owner);
+	__reiser4_wake_up(owner);
+	spin_unlock_stack(owner);
+}
+
+const char *lock_mode_name(znode_lock_mode lock);
+
+#if REISER4_DEBUG
+extern void check_lock_data(void);
+extern void check_lock_node_data(znode * node);
+#else
+#define check_lock_data() noop
+#define check_lock_node_data() noop
+#endif
+
+/* __LOCK_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/oid.c newtree/fs/reiser4/oid.c
--- oldtree/fs/reiser4/oid.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/oid.c	2006-02-21 15:58:35.439758896 +0000
@@ -0,0 +1,141 @@
+/* Copyright 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#include "debug.h"
+#include "super.h"
+#include "txnmgr.h"
+
+/* we used to have oid allocation plugin. It was removed because it
+   was recognized as providing unneeded level of abstraction. If one
+   ever will find it useful - look at yet_unneeded_abstractions/oid
+*/
+
+/*
+ * initialize in-memory data for oid allocator at @super. @nr_files and @next
+ * are provided by disk format plugin that reads them from the disk during
+ * mount.
+ */
+int oid_init_allocator(struct super_block *super, oid_t nr_files, oid_t next)
+{
+	reiser4_super_info_data *sbinfo;
+
+	sbinfo = get_super_private(super);
+
+	sbinfo->next_to_use = next;
+	sbinfo->oids_in_use = nr_files;
+	return 0;
+}
+
+/*
+ * allocate oid and return it. ABSOLUTE_MAX_OID is returned when allocator
+ * runs out of oids.
+ */
+oid_t oid_allocate(struct super_block * super)
+{
+	reiser4_super_info_data *sbinfo;
+	oid_t oid;
+
+	sbinfo = get_super_private(super);
+
+	spin_lock_reiser4_super(sbinfo);
+	if (sbinfo->next_to_use != ABSOLUTE_MAX_OID) {
+		oid = sbinfo->next_to_use++;
+		sbinfo->oids_in_use++;
+	} else
+		oid = ABSOLUTE_MAX_OID;
+	spin_unlock_reiser4_super(sbinfo);
+	return oid;
+}
+
+/*
+ * Tell oid allocator that @oid is now free.
+ */
+int oid_release(struct super_block *super, oid_t oid UNUSED_ARG)
+{
+	reiser4_super_info_data *sbinfo;
+
+	sbinfo = get_super_private(super);
+
+	spin_lock_reiser4_super(sbinfo);
+	sbinfo->oids_in_use--;
+	spin_unlock_reiser4_super(sbinfo);
+	return 0;
+}
+
+/*
+ * return next @oid that would be allocated (i.e., returned by oid_allocate())
+ * without actually allocating it. This is used by disk format plugin to save
+ * oid allocator state on the disk.
+ */
+oid_t oid_next(const struct super_block * super)
+{
+	reiser4_super_info_data *sbinfo;
+	oid_t oid;
+
+	sbinfo = get_super_private(super);
+
+	spin_lock_reiser4_super(sbinfo);
+	oid = sbinfo->next_to_use;
+	spin_unlock_reiser4_super(sbinfo);
+	return oid;
+}
+
+/*
+ * returns number of currently used oids. This is used by statfs(2) to report
+ * number of "inodes" and by disk format plugin to save oid allocator state on
+ * the disk.
+ */
+long oids_used(const struct super_block *super)
+{
+	reiser4_super_info_data *sbinfo;
+	oid_t used;
+
+	sbinfo = get_super_private(super);
+
+	spin_lock_reiser4_super(sbinfo);
+	used = sbinfo->oids_in_use;
+	spin_unlock_reiser4_super(sbinfo);
+	if (used < (__u64) ((long)~0) >> 1)
+		return (long)used;
+	else
+		return (long)-1;
+}
+
+/*
+ * Count oid as allocated in atom. This is done after call to oid_allocate()
+ * at the point when we are irrevocably committed to creation of the new file
+ * (i.e., when oid allocation cannot be any longer rolled back due to some
+ * error).
+ */
+void oid_count_allocated(void)
+{
+	txn_atom *atom;
+
+	atom = get_current_atom_locked();
+	atom->nr_objects_created++;
+	spin_unlock_atom(atom);
+}
+
+/*
+ * Count oid as free in atom. This is done after call to oid_release() at the
+ * point when we are irrevocably committed to the deletion of the file (i.e.,
+ * when oid release cannot be any longer rolled back due to some error).
+ */
+void oid_count_released(void)
+{
+	txn_atom *atom;
+
+	atom = get_current_atom_locked();
+	atom->nr_objects_deleted++;
+	spin_unlock_atom(atom);
+}
+
+/*
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/page_cache.c newtree/fs/reiser4/page_cache.c
--- oldtree/fs/reiser4/page_cache.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/page_cache.c	2006-02-21 15:58:35.439758896 +0000
@@ -0,0 +1,761 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Memory pressure hooks. Fake inodes handling. */
+/* We store all file system meta data (and data, of course) in the page cache.
+
+   What does this mean? In stead of using bread/brelse we create special
+   "fake" inode (one per super block) and store content of formatted nodes
+   into pages bound to this inode in the page cache. In newer kernels bread()
+   already uses inode attached to block device (bd_inode). Advantage of having
+   our own fake inode is that we can install appropriate methods in its
+   address_space operations. Such methods are called by VM on memory pressure
+   (or during background page flushing) and we can use them to react
+   appropriately.
+
+   In initial version we only support one block per page. Support for multiple
+   blocks per page is complicated by relocation.
+
+   To each page, used by reiser4, jnode is attached. jnode is analogous to
+   buffer head. Difference is that jnode is bound to the page permanently:
+   jnode cannot be removed from memory until its backing page is.
+
+   jnode contain pointer to page (->pg field) and page contain pointer to
+   jnode in ->private field. Pointer from jnode to page is protected to by
+   jnode's spinlock and pointer from page to jnode is protected by page lock
+   (PG_locked bit). Lock ordering is: first take page lock, then jnode spin
+   lock. To go into reverse direction use jnode_lock_page() function that uses
+   standard try-lock-and-release device.
+
+   Properties:
+
+   1. when jnode-to-page mapping is established (by jnode_attach_page()), page
+   reference counter is increased.
+
+   2. when jnode-to-page mapping is destroyed (by jnode_detach_page() and
+   page_detach_jnode()), page reference counter is decreased.
+
+   3. on jload() reference counter on jnode page is increased, page is
+   kmapped and `referenced'.
+
+   4. on jrelse() inverse operations are performed.
+
+   5. kmapping/kunmapping of unformatted pages is done by read/write methods.
+
+   DEADLOCKS RELATED TO MEMORY PRESSURE. [OUTDATED. Only interesting
+   historically.]
+
+   [In the following discussion, `lock' invariably means long term lock on
+   znode.] (What about page locks?)
+
+   There is some special class of deadlock possibilities related to memory
+   pressure. Locks acquired by other reiser4 threads are accounted for in
+   deadlock prevention mechanism (lock.c), but when ->vm_writeback() is
+   invoked additional hidden arc is added to the locking graph: thread that
+   tries to allocate memory waits for ->vm_writeback() to finish. If this
+   thread keeps lock and ->vm_writeback() tries to acquire this lock, deadlock
+   prevention is useless.
+
+   Another related problem is possibility for ->vm_writeback() to run out of
+   memory itself. This is not a problem for ext2 and friends, because their
+   ->vm_writeback() don't allocate much memory, but reiser4 flush is
+   definitely able to allocate huge amounts of memory.
+
+   It seems that there is no reliable way to cope with the problems above. In
+   stead it was decided that ->vm_writeback() (as invoked in the kswapd
+   context) wouldn't perform any flushing itself, but rather should just wake
+   up some auxiliary thread dedicated for this purpose (or, the same thread
+   that does periodic commit of old atoms (ktxnmgrd.c)).
+
+   Details:
+
+   1. Page is called `reclaimable' against particular reiser4 mount F if this
+   page can be ultimately released by try_to_free_pages() under presumptions
+   that:
+
+    a. ->vm_writeback() for F is no-op, and
+
+    b. none of the threads accessing F are making any progress, and
+
+    c. other reiser4 mounts obey the same memory reservation protocol as F
+    (described below).
+
+   For example, clean un-pinned page, or page occupied by ext2 data are
+   reclaimable against any reiser4 mount.
+
+   When there is more than one reiser4 mount in a system, condition (c) makes
+   reclaim-ability not easily verifiable beyond trivial cases mentioned above.
+
+   THIS COMMENT IS VALID FOR "MANY BLOCKS ON PAGE" CASE
+
+   Fake inode is used to bound formatted nodes and each node is indexed within
+   fake inode by its block number. If block size of smaller than page size, it
+   may so happen that block mapped to the page with formatted node is occupied
+   by unformatted node or is unallocated. This lead to some complications,
+   because flushing whole page can lead to an incorrect overwrite of
+   unformatted node that is moreover, can be cached in some other place as
+   part of the file body. To avoid this, buffers for unformatted nodes are
+   never marked dirty. Also pages in the fake are never marked dirty. This
+   rules out usage of ->writepage() as memory pressure hook. In stead
+   ->releasepage() is used.
+
+   Josh is concerned that page->buffer is going to die. This should not pose
+   significant problem though, because we need to add some data structures to
+   the page anyway (jnode) and all necessary book keeping can be put there.
+
+*/
+
+/* Life cycle of pages/nodes.
+
+   jnode contains reference to page and page contains reference back to
+   jnode. This reference is counted in page ->count. Thus, page bound to jnode
+   cannot be released back into free pool.
+
+    1. Formatted nodes.
+
+      1. formatted node is represented by znode. When new znode is created its
+      ->pg pointer is NULL initially.
+
+      2. when node content is loaded into znode (by call to zload()) for the
+      first time following happens (in call to ->read_node() or
+      ->allocate_node()):
+
+        1. new page is added to the page cache.
+
+        2. this page is attached to znode and its ->count is increased.
+
+        3. page is kmapped.
+
+      3. if more calls to zload() follow (without corresponding zrelses), page
+      counter is left intact and in its stead ->d_count is increased in znode.
+
+      4. each call to zrelse decreases ->d_count. When ->d_count drops to zero
+      ->release_node() is called and page is kunmapped as result.
+
+      5. at some moment node can be captured by a transaction. Its ->x_count
+      is then increased by transaction manager.
+
+      6. if node is removed from the tree (empty node with JNODE_HEARD_BANSHEE
+      bit set) following will happen (also see comment at the top of znode.c):
+
+        1. when last lock is released, node will be uncaptured from
+        transaction. This released reference that transaction manager acquired
+        at the step 5.
+
+        2. when last reference is released, zput() detects that node is
+        actually deleted and calls ->delete_node()
+        operation. page_cache_delete_node() implementation detaches jnode from
+        page and releases page.
+
+      7. otherwise (node wasn't removed from the tree), last reference to
+      znode will be released after transaction manager committed transaction
+      node was in. This implies squallocing of this node (see
+      flush.c). Nothing special happens at this point. Znode is still in the
+      hash table and page is still attached to it.
+
+      8. znode is actually removed from the memory because of the memory
+      pressure, or during umount (znodes_tree_done()). Anyway, znode is
+      removed by the call to zdrop(). At this moment, page is detached from
+      znode and removed from the inode address space.
+
+*/
+
+#include "debug.h"
+#include "dformat.h"
+#include "key.h"
+#include "txnmgr.h"
+#include "jnode.h"
+#include "znode.h"
+#include "block_alloc.h"
+#include "tree.h"
+#include "vfs_ops.h"
+#include "inode.h"
+#include "super.h"
+#include "entd.h"
+#include "page_cache.h"
+#include "ktxnmgrd.h"
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>		/* for struct page */
+#include <linux/swap.h>		/* for struct page */
+#include <linux/pagemap.h>
+#include <linux/bio.h>
+#include <linux/writeback.h>
+#include <linux/blkdev.h>
+
+static struct bio *page_bio(struct page *, jnode *, int rw, unsigned int gfp);
+
+static struct address_space_operations formatted_fake_as_ops;
+
+static const oid_t fake_ino = 0x1;
+static const oid_t bitmap_ino = 0x2;
+static const oid_t cc_ino = 0x3;
+
+static void
+init_fake_inode(struct super_block *super, struct inode *fake,
+		struct inode **pfake)
+{
+	assert("nikita-2168", fake->i_state & I_NEW);
+	fake->i_mapping->a_ops = &formatted_fake_as_ops;
+	fake->i_blkbits = super->s_blocksize_bits;
+	fake->i_size = ~0ull;
+	fake->i_rdev = super->s_bdev->bd_dev;
+	fake->i_bdev = super->s_bdev;
+	*pfake = fake;
+	/* NOTE-NIKITA something else? */
+	unlock_new_inode(fake);
+}
+
+/**
+ * init_formatted_fake - iget inodes for formatted nodes and bitmaps
+ * @super: super block to init fake inode for
+ *
+ * Initializes fake inode to which formatted nodes are bound in the page cache
+ * and inode for bitmaps.
+ */
+int init_formatted_fake(struct super_block *super)
+{
+	struct inode *fake;
+	struct inode *bitmap;
+	struct inode *cc;
+	reiser4_super_info_data *sinfo;
+
+	assert("nikita-1703", super != NULL);
+
+	sinfo = get_super_private_nocheck(super);
+	fake = iget_locked(super, oid_to_ino(fake_ino));
+
+	if (fake != NULL) {
+		init_fake_inode(super, fake, &sinfo->fake);
+
+		bitmap = iget_locked(super, oid_to_ino(bitmap_ino));
+		if (bitmap != NULL) {
+			init_fake_inode(super, bitmap, &sinfo->bitmap);
+
+			cc = iget_locked(super, oid_to_ino(cc_ino));
+			if (cc != NULL) {
+				init_fake_inode(super, cc, &sinfo->cc);
+				return 0;
+			} else {
+				iput(sinfo->fake);
+				iput(sinfo->bitmap);
+				sinfo->fake = NULL;
+				sinfo->bitmap = NULL;
+			}
+		} else {
+			iput(sinfo->fake);
+			sinfo->fake = NULL;
+		}
+	}
+	return RETERR(-ENOMEM);
+}
+
+/**
+ * done_formatted_fake - release inode used by formatted nodes and bitmaps
+ * @super: super block to init fake inode for
+ *
+ * Releases inodes which were used as address spaces of bitmap and formatted
+ * nodes.
+ */
+void done_formatted_fake(struct super_block *super)
+{
+	reiser4_super_info_data *sinfo;
+
+	sinfo = get_super_private_nocheck(super);
+
+	if (sinfo->fake != NULL) {
+		assert("vs-1426", sinfo->fake->i_data.nrpages == 0);
+		iput(sinfo->fake);
+		sinfo->fake = NULL;
+	}
+
+	if (sinfo->bitmap != NULL) {
+		iput(sinfo->bitmap);
+		sinfo->bitmap = NULL;
+	}
+
+	if (sinfo->cc != NULL) {
+		iput(sinfo->cc);
+		sinfo->cc = NULL;
+	}
+	return;
+}
+
+void reiser4_wait_page_writeback(struct page *page)
+{
+	assert("zam-783", PageLocked(page));
+
+	do {
+		unlock_page(page);
+		wait_on_page_writeback(page);
+		lock_page(page);
+	} while (PageWriteback(page));
+}
+
+/* return tree @page is in */
+reiser4_tree *tree_by_page(const struct page *page /* page to query */ )
+{
+	assert("nikita-2461", page != NULL);
+	return &get_super_private(page->mapping->host->i_sb)->tree;
+}
+
+/* completion handler for single page bio-based read.
+
+   mpage_end_io_read() would also do. But it's static.
+
+*/
+static int
+end_bio_single_page_read(struct bio *bio, unsigned int bytes_done UNUSED_ARG,
+			 int err UNUSED_ARG)
+{
+	struct page *page;
+
+	if (bio->bi_size != 0) {
+		warning("nikita-3332", "Truncated single page read: %i",
+			bio->bi_size);
+		return 1;
+	}
+
+	page = bio->bi_io_vec[0].bv_page;
+
+	if (test_bit(BIO_UPTODATE, &bio->bi_flags)) {
+		SetPageUptodate(page);
+	} else {
+		ClearPageUptodate(page);
+		SetPageError(page);
+	}
+	unlock_page(page);
+	bio_put(bio);
+	return 0;
+}
+
+/* completion handler for single page bio-based write.
+
+   mpage_end_io_write() would also do. But it's static.
+
+*/
+static int
+end_bio_single_page_write(struct bio *bio, unsigned int bytes_done UNUSED_ARG,
+			  int err UNUSED_ARG)
+{
+	struct page *page;
+
+	if (bio->bi_size != 0) {
+		warning("nikita-3333", "Truncated single page write: %i",
+			bio->bi_size);
+		return 1;
+	}
+
+	page = bio->bi_io_vec[0].bv_page;
+
+	if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
+		SetPageError(page);
+	end_page_writeback(page);
+	bio_put(bio);
+	return 0;
+}
+
+/* ->readpage() method for formatted nodes */
+static int
+formatted_readpage(struct file *f UNUSED_ARG,
+		   struct page *page /* page to read */ )
+{
+	assert("nikita-2412", PagePrivate(page) && jprivate(page));
+	return page_io(page, jprivate(page), READ, GFP_KERNEL);
+}
+
+/**
+ * page_io - submit single-page bio request
+ * @page: page to perform io for
+ * @node: jnode of page
+ * @rw: read or write
+ * @gfp: gfp mask for bio allocation
+ *
+ * Submits single page read or write.
+ */
+int page_io(struct page *page, jnode *node, int rw, int gfp)
+{
+	struct bio *bio;
+	int result;
+
+	assert("nikita-2094", page != NULL);
+	assert("nikita-2226", PageLocked(page));
+	assert("nikita-2634", node != NULL);
+	assert("nikita-2893", rw == READ || rw == WRITE);
+
+	if (rw) {
+		if (unlikely(page->mapping->host->i_sb->s_flags & MS_RDONLY)) {
+			unlock_page(page);
+			return 0;
+		}
+	}
+
+	bio = page_bio(page, node, rw, gfp);
+	if (!IS_ERR(bio)) {
+		if (rw == WRITE) {
+			SetPageWriteback(page);
+			unlock_page(page);
+		}
+		reiser4_submit_bio(rw, bio);
+		result = 0;
+	} else {
+		unlock_page(page);
+		result = PTR_ERR(bio);
+	}
+
+	return result;
+}
+
+/* helper function to construct bio for page */
+static struct bio *page_bio(struct page *page, jnode * node, int rw,
+			    unsigned int gfp)
+{
+	struct bio *bio;
+	assert("nikita-2092", page != NULL);
+	assert("nikita-2633", node != NULL);
+
+	/* Simple implementation in the assumption that blocksize == pagesize.
+
+	   We only have to submit one block, but submit_bh() will allocate bio
+	   anyway, so lets use all the bells-and-whistles of bio code.
+	 */
+
+	bio = bio_alloc(gfp, 1);
+	if (bio != NULL) {
+		int blksz;
+		struct super_block *super;
+		reiser4_block_nr blocknr;
+
+		super = page->mapping->host->i_sb;
+		assert("nikita-2029", super != NULL);
+		blksz = super->s_blocksize;
+		assert("nikita-2028", blksz == (int)PAGE_CACHE_SIZE);
+
+		spin_lock_jnode(node);
+		blocknr = *jnode_get_io_block(node);
+		spin_unlock_jnode(node);
+
+		assert("nikita-2275", blocknr != (reiser4_block_nr) 0);
+		assert("nikita-2276", !blocknr_is_fake(&blocknr));
+
+		bio->bi_bdev = super->s_bdev;
+		/* fill bio->bi_sector before calling bio_add_page(), because
+		 * q->merge_bvec_fn may want to inspect it (see
+		 * drivers/md/linear.c:linear_mergeable_bvec() for example. */
+		bio->bi_sector = blocknr * (blksz >> 9);
+
+		if (!bio_add_page(bio, page, blksz, 0)) {
+			warning("nikita-3452",
+				"Single page bio cannot be constructed");
+			return ERR_PTR(RETERR(-EINVAL));
+		}
+
+		/* bio -> bi_idx is filled by bio_init() */
+		bio->bi_end_io = (rw == READ) ?
+		    end_bio_single_page_read : end_bio_single_page_write;
+
+		return bio;
+	} else
+		return ERR_PTR(RETERR(-ENOMEM));
+}
+
+/* this function is internally called by jnode_make_dirty() */
+int set_page_dirty_internal(struct page *page)
+{
+	struct address_space *mapping;
+
+	mapping = page->mapping;
+	BUG_ON(mapping == NULL);
+
+	if (!TestSetPageDirty(page)) {
+		if (mapping_cap_account_dirty(mapping))
+			inc_page_state(nr_dirty);
+
+		__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+	}
+
+	/* znode must be dirty ? */
+	if (mapping->host == get_super_fake(mapping->host->i_sb))
+		assert("", JF_ISSET(jprivate(page), JNODE_DIRTY));
+	return 0;
+}
+
+static int can_hit_entd(reiser4_context * ctx, struct super_block *s)
+{
+	if (get_super_private(s)->entd.tsk == current)
+		return 0;
+	if (ctx == NULL || ((unsigned long)ctx->magic) != context_magic)
+		return 1;
+	if (ctx->super != s)
+		return 1;
+	return 0;
+}
+
+/**
+ * reiser4_writepage - writepage of struct address_space_operations
+ * @page: page to write
+ * @wbc:
+ *
+ *
+ */
+/* Common memory pressure notification. */
+int reiser4_writepage(struct page *page,
+		      struct writeback_control *wbc)
+{
+	struct super_block *s;
+	reiser4_context *ctx;
+	reiser4_tree *tree;
+	txn_atom *atom;
+	jnode *node;
+	int result;
+
+	assert("vs-828", PageLocked(page));
+
+	s = page->mapping->host->i_sb;
+	ctx = get_current_context_check();
+
+#if REISER4_USE_ENTD
+	if (can_hit_entd(ctx, s) ||
+	    (ctx && lock_stack_isclean(get_current_lock_stack()) &&
+	     ctx->trans->atom == NULL && ctx->entd == 0)) {
+		/* Throttle memory allocations if we were not in reiser4 or if
+		   lock stack is clean and atom is not opened */
+		return write_page_by_ent(page, wbc);
+	}
+#endif				/* REISER4_USE_ENTD */
+
+	BUG_ON(ctx == NULL);
+	BUG_ON(s != ctx->super);
+
+	tree = &get_super_private(s)->tree;
+	node = jnode_of_page(page);
+	if (!IS_ERR(node)) {
+		int phantom;
+
+		assert("nikita-2419", node != NULL);
+
+		spin_lock_jnode(node);
+		/*
+		 * page was dirty, but jnode is not. This is (only?)
+		 * possible if page was modified through mmap(). We
+		 * want to handle such jnodes specially.
+		 */
+		phantom = !JF_ISSET(node, JNODE_DIRTY);
+		atom = jnode_get_atom(node);
+		if (atom != NULL) {
+			if (!(atom->flags & ATOM_FORCE_COMMIT)) {
+				atom->flags |= ATOM_FORCE_COMMIT;
+				ktxnmgrd_kick(&get_super_private(s)->tmgr);
+			}
+			spin_unlock_atom(atom);
+		}
+		spin_unlock_jnode(node);
+
+		result = emergency_flush(page);
+		if (result == 0)
+			if (phantom && jnode_is_unformatted(node))
+				JF_SET(node, JNODE_KEEPME);
+		jput(node);
+	} else {
+		result = PTR_ERR(node);
+	}
+	if (result != 0) {
+		/*
+		 * shrink list doesn't move page to another mapping
+		 * list when clearing dirty flag. So it is enough to
+		 * just set dirty bit.
+		 */
+		set_page_dirty_internal(page);
+		unlock_page(page);
+	}
+	return result;
+}
+
+/* ->set_page_dirty() method of formatted address_space */
+static int formatted_set_page_dirty(struct page *page)
+{
+	assert("nikita-2173", page != NULL);
+	BUG();
+	return __set_page_dirty_nobuffers(page);
+}
+
+/* writepages method of address space operations in reiser4 is used to involve
+   into transactions pages which are dirtied via mmap. Only regular files can
+   have such pages. Fake inode is used to access formatted nodes via page
+   cache. As formatted nodes can never be mmaped, fake inode's writepages has
+   nothing to do */
+static int
+writepages_fake(struct address_space *mapping, struct writeback_control *wbc)
+{
+	return 0;
+}
+
+/* address space operations for the fake inode */
+static struct address_space_operations formatted_fake_as_ops = {
+	/* Perform a writeback of a single page as a memory-freeing
+	 * operation. */
+	.writepage = reiser4_writepage,
+	/* this is called to read formatted node */
+	.readpage = formatted_readpage,
+	/* ->sync_page() method of fake inode address space operations. Called
+	   from wait_on_page() and lock_page().
+
+	   This is most annoyingly misnomered method. Actually it is called
+	   from wait_on_page_bit() and lock_page() and its purpose is to
+	   actually start io by jabbing device drivers.
+	 */
+	.sync_page = block_sync_page,
+	/* Write back some dirty pages from this mapping. Called from sync.
+	   called during sync (pdflush) */
+	.writepages = writepages_fake,
+	/* Set a page dirty */
+	.set_page_dirty = formatted_set_page_dirty,
+	/* used for read-ahead. Not applicable */
+	.readpages = NULL,
+	.prepare_write = NULL,
+	.commit_write = NULL,
+	.bmap = NULL,
+	/* called just before page is being detached from inode mapping and
+	   removed from memory. Called on truncate, cut/squeeze, and
+	   umount. */
+	.invalidatepage = reiser4_invalidatepage,
+	/* this is called by shrink_cache() so that file system can try to
+	   release objects (jnodes, buffers, journal heads) attached to page
+	   and, may be made page itself free-able.
+	 */
+	.releasepage = reiser4_releasepage,
+	.direct_IO = NULL
+};
+
+/* called just before page is released (no longer used by reiser4). Callers:
+   jdelete() and extent2tail(). */
+void drop_page(struct page *page)
+{
+	assert("nikita-2181", PageLocked(page));
+	clear_page_dirty_for_io(page);
+	ClearPageUptodate(page);
+#if defined(PG_skipped)
+	ClearPageSkipped(page);
+#endif
+	if (page->mapping != NULL) {
+		remove_from_page_cache(page);
+		unlock_page(page);
+		page_cache_release(page);
+	} else
+		unlock_page(page);
+}
+
+/* this is called by truncate_jnodes_range which in its turn is always called
+   after truncate_mapping_pages_range. Therefore, here jnode can not have
+   page. New pages can not be created because truncate_jnodes_range goes under
+   exclusive access on file obtained, where as new page creation requires
+   non-exclusive access obtained */
+static void invalidate_unformatted(jnode * node)
+{
+	struct page *page;
+
+	spin_lock_jnode(node);
+	page = node->pg;
+	if (page) {
+		loff_t from, to;
+
+		page_cache_get(page);
+		spin_unlock_jnode(node);
+		/* FIXME: use truncate_complete_page instead */
+		from = (loff_t) page->index << PAGE_CACHE_SHIFT;
+		to = from + PAGE_CACHE_SIZE - 1;
+		truncate_inode_pages_range(page->mapping, from, to);
+		page_cache_release(page);
+	} else {
+		JF_SET(node, JNODE_HEARD_BANSHEE);
+		uncapture_jnode(node);
+		unhash_unformatted_jnode(node);
+	}
+}
+
+#define JNODE_GANG_SIZE (16)
+
+/* find all eflushed jnodes from range specified and invalidate them */
+static int
+truncate_jnodes_range(struct inode *inode, pgoff_t from, pgoff_t count)
+{
+	reiser4_inode *info;
+	int truncated_jnodes;
+	reiser4_tree *tree;
+	unsigned long index;
+	unsigned long end;
+
+	truncated_jnodes = 0;
+
+	info = reiser4_inode_data(inode);
+	tree = tree_by_inode(inode);
+
+	index = from;
+	end = from + count;
+
+	while (1) {
+		jnode *gang[JNODE_GANG_SIZE];
+		int taken;
+		int i;
+		jnode *node;
+
+		assert("nikita-3466", index <= end);
+
+		read_lock_tree(tree);
+		taken =
+		    radix_tree_gang_lookup(jnode_tree_by_reiser4_inode(info),
+					   (void **)gang, index,
+					   JNODE_GANG_SIZE);
+		for (i = 0; i < taken; ++i) {
+			node = gang[i];
+			if (index_jnode(node) < end)
+				jref(node);
+			else
+				gang[i] = NULL;
+		}
+		read_unlock_tree(tree);
+
+		for (i = 0; i < taken; ++i) {
+			node = gang[i];
+			if (node != NULL) {
+				index = max(index, index_jnode(node));
+				invalidate_unformatted(node);
+				truncated_jnodes++;
+				jput(node);
+			} else
+				break;
+		}
+		if (i != taken || taken == 0)
+			break;
+	}
+	return truncated_jnodes;
+}
+
+void
+reiser4_invalidate_pages(struct address_space *mapping, pgoff_t from,
+			 unsigned long count, int even_cows)
+{
+	loff_t from_bytes, count_bytes;
+
+	if (count == 0)
+		return;
+	from_bytes = ((loff_t) from) << PAGE_CACHE_SHIFT;
+	count_bytes = ((loff_t) count) << PAGE_CACHE_SHIFT;
+
+	unmap_mapping_range(mapping, from_bytes, count_bytes, even_cows);
+	truncate_inode_pages_range(mapping, from_bytes,
+				   from_bytes + count_bytes - 1);
+	truncate_jnodes_range(mapping->host, from, count);
+}
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 120
+ * scroll-step: 1
+ * End:
+ */
diff -urN oldtree/fs/reiser4/page_cache.h newtree/fs/reiser4/page_cache.h
--- oldtree/fs/reiser4/page_cache.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/page_cache.h	2006-02-21 15:58:35.439758896 +0000
@@ -0,0 +1,62 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+/* Memory pressure hooks. Fake inodes handling. See page_cache.c. */
+
+#if !defined( __REISER4_PAGE_CACHE_H__ )
+#define __REISER4_PAGE_CACHE_H__
+
+#include "forward.h"
+#include "debug.h"
+
+#include <linux/fs.h>		/* for struct super_block, address_space  */
+#include <linux/mm.h>		/* for struct page  */
+#include <linux/pagemap.h>	/* for lock_page()  */
+
+
+extern int init_formatted_fake(struct super_block *);
+extern void done_formatted_fake(struct super_block *);
+
+extern reiser4_tree *tree_by_page(const struct page *page);
+
+extern int set_page_dirty_internal(struct page *page);
+
+#define reiser4_submit_bio(rw, bio) submit_bio((rw), (bio))
+
+extern void reiser4_wait_page_writeback(struct page *page);
+static inline void lock_and_wait_page_writeback(struct page *page)
+{
+	lock_page(page);
+	if (unlikely(PageWriteback(page)))
+		reiser4_wait_page_writeback(page);
+}
+
+#define jprivate(page) ((jnode *)page_private(page))
+
+extern int page_io(struct page *page, jnode * node, int rw, int gfp);
+extern void drop_page(struct page *page);
+extern void reiser4_invalidate_pages(struct address_space *, pgoff_t from,
+				     unsigned long count, int even_cows);
+extern void capture_reiser4_inodes(struct super_block *,
+				   struct writeback_control *);
+
+#define PAGECACHE_TAG_REISER4_MOVED PAGECACHE_TAG_DIRTY
+
+#if REISER4_DEBUG
+extern void print_page(const char *prefix, struct page *page);
+#else
+#define print_page(prf, p) noop
+#endif
+
+/* __REISER4_PAGE_CACHE_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/Makefile newtree/fs/reiser4/plugin/Makefile
--- oldtree/fs/reiser4/plugin/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/Makefile	2006-02-21 15:58:35.082813160 +0000
@@ -0,0 +1,26 @@
+obj-$(CONFIG_REISER4_FS) += plugins.o
+
+plugins-objs :=			\
+	plugin.o		\
+	plugin_set.o		\
+	object.o		\
+	inode_ops.o		\
+	inode_ops_rename.o	\
+	file_ops.o		\
+	file_ops_readdir.o	\
+	file_plugin_common.o	\
+	dir_plugin_common.o	\
+	digest.o		\
+	hash.o			\
+	fibration.o		\
+	tail_policy.o		\
+	regular.o
+
+obj-$(CONFIG_REISER4_FS) += item/
+obj-$(CONFIG_REISER4_FS) += file/
+obj-$(CONFIG_REISER4_FS) += dir/
+obj-$(CONFIG_REISER4_FS) += node/
+obj-$(CONFIG_REISER4_FS) += compress/
+obj-$(CONFIG_REISER4_FS) += space/
+obj-$(CONFIG_REISER4_FS) += disk_format/
+obj-$(CONFIG_REISER4_FS) += security/
diff -urN oldtree/fs/reiser4/plugin/cluster.c newtree/fs/reiser4/plugin/cluster.c
--- oldtree/fs/reiser4/plugin/cluster.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/cluster.c	2006-02-21 15:58:35.183797808 +0000
@@ -0,0 +1,66 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Contains reiser4 cluster plugins (see
+   http://www.namesys.com/cryptcompress_design.html
+   "Concepts of clustering" for details). */
+
+#include "plugin_header.h"
+#include "plugin.h"
+#include "../inode.h"
+
+static int change_cluster(struct inode *inode, reiser4_plugin * plugin)
+{
+	int result = 0;
+
+	assert("edward-1324", inode != NULL);
+	assert("edward-1325", plugin != NULL);
+	assert("edward-1326", is_reiser4_inode(inode));
+	assert("edward-1327", plugin->h.type_id == REISER4_CLUSTER_PLUGIN_TYPE);
+
+	if (inode_file_plugin(inode)->h.id == DIRECTORY_FILE_PLUGIN_ID)
+		result = plugin_set_cluster(&reiser4_inode_data(inode)->pset,
+					    &plugin->clust);
+	else
+		result = RETERR(-EINVAL);
+	return result;
+}
+
+static reiser4_plugin_ops cluster_plugin_ops = {
+	.init = NULL,
+	.load = NULL,
+	.save_len = NULL,
+	.save = NULL,
+	.change = &change_cluster
+};
+
+#define SUPPORT_CLUSTER(SHIFT, ID, LABEL, DESC)			\
+	[CLUSTER_ ## ID ## _ID] = {				\
+		.h = {						\
+			.type_id = REISER4_CLUSTER_PLUGIN_TYPE,	\
+			.id = CLUSTER_ ## ID ## _ID,		\
+			.pops = &cluster_plugin_ops,		\
+			.label = LABEL,				\
+			.desc = DESC,				\
+			.linkage = {NULL, NULL}			\
+		},						\
+		.shift = SHIFT					\
+	}
+
+cluster_plugin cluster_plugins[LAST_CLUSTER_ID] = {
+	SUPPORT_CLUSTER(16, 64K, "64K", "Large"),
+	SUPPORT_CLUSTER(15, 32K, "32K", "Big"),
+	SUPPORT_CLUSTER(14, 16K, "16K", "Average"),
+	SUPPORT_CLUSTER(13, 8K, "8K", "Small"),
+	SUPPORT_CLUSTER(12, 4K, "4K", "Minimal")
+};
+
+/*
+  Local variables:
+  c-indentation-style: "K&R"
+  mode-name: "LC"
+  c-basic-offset: 8
+  tab-width: 8
+  fill-column: 120
+  scroll-step: 1
+  End:
+*/
diff -urN oldtree/fs/reiser4/plugin/cluster.h newtree/fs/reiser4/plugin/cluster.h
--- oldtree/fs/reiser4/plugin/cluster.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/cluster.h	2006-02-21 15:58:35.440758744 +0000
@@ -0,0 +1,320 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* This file contains page/cluster index translators and offset modulators
+   See http://www.namesys.com/cryptcompress_design.html for details */
+
+#if !defined( __FS_REISER4_CLUSTER_H__ )
+#define __FS_REISER4_CLUSTER_H__
+
+#include "../inode.h"
+
+static inline int inode_cluster_shift(struct inode *inode)
+{
+	assert("edward-92", inode != NULL);
+	assert("edward-93", reiser4_inode_data(inode) != NULL);
+
+	return inode_cluster_plugin(inode)->shift;
+}
+
+static inline unsigned cluster_nrpages_shift(struct inode *inode)
+{
+	return inode_cluster_shift(inode) - PAGE_CACHE_SHIFT;
+}
+
+/* cluster size in page units */
+static inline unsigned cluster_nrpages(struct inode *inode)
+{
+	return 1U << cluster_nrpages_shift(inode);
+}
+
+static inline size_t inode_cluster_size(struct inode *inode)
+{
+	assert("edward-96", inode != NULL);
+
+	return 1U << inode_cluster_shift(inode);
+}
+
+static inline cloff_t pg_to_clust(pgoff_t idx, struct inode *inode)
+{
+	return idx >> cluster_nrpages_shift(inode);
+}
+
+static inline pgoff_t clust_to_pg(cloff_t idx, struct inode *inode)
+{
+	return idx << cluster_nrpages_shift(inode);
+}
+
+static inline pgoff_t pg_to_clust_to_pg(pgoff_t idx, struct inode *inode)
+{
+	return clust_to_pg(pg_to_clust(idx, inode), inode);
+}
+
+static inline pgoff_t off_to_pg(loff_t off)
+{
+	return (off >> PAGE_CACHE_SHIFT);
+}
+
+static inline loff_t pg_to_off(pgoff_t idx)
+{
+	return ((loff_t) (idx) << PAGE_CACHE_SHIFT);
+}
+
+static inline cloff_t off_to_clust(loff_t off, struct inode *inode)
+{
+	return off >> inode_cluster_shift(inode);
+}
+
+static inline loff_t clust_to_off(cloff_t idx, struct inode *inode)
+{
+	return (loff_t) idx << inode_cluster_shift(inode);
+}
+
+static inline unsigned long count_to_nr(loff_t count, unsigned shift)
+{
+	return (count + (1UL << shift) - 1) >> shift;
+}
+
+/* number of pages occupied by @count bytes */
+static inline pgoff_t count_to_nrpages(loff_t count)
+{
+	return count_to_nr(count, PAGE_CACHE_SHIFT);
+}
+
+/* number of clusters occupied by @count bytes */
+static inline cloff_t count_to_nrclust(loff_t count, struct inode *inode)
+{
+	return count_to_nr(count, inode_cluster_shift(inode));
+}
+
+/* number of clusters occupied by @count pages */
+static inline cloff_t pgcount_to_nrclust(pgoff_t count, struct inode *inode)
+{
+	return count_to_nr(count, cluster_nrpages_shift(inode));
+}
+
+static inline loff_t off_to_clust_to_off(loff_t off, struct inode *inode)
+{
+	return clust_to_off(off_to_clust(off, inode), inode);
+}
+
+static inline pgoff_t off_to_clust_to_pg(loff_t off, struct inode *inode)
+{
+	return clust_to_pg(off_to_clust(off, inode), inode);
+}
+
+static inline unsigned off_to_pgoff(loff_t off)
+{
+	return off & (PAGE_CACHE_SIZE - 1);
+}
+
+static inline unsigned off_to_cloff(loff_t off, struct inode *inode)
+{
+	return off & ((loff_t) (inode_cluster_size(inode)) - 1);
+}
+
+static inline unsigned
+pg_to_off_to_cloff(unsigned long idx, struct inode *inode)
+{
+	return off_to_cloff(pg_to_off(idx), inode);
+}
+
+/* if @size != 0, returns index of the page
+   which contains the last byte of the file */
+static inline pgoff_t size_to_pg(loff_t size)
+{
+	return (size ? off_to_pg(size - 1) : 0);
+}
+
+/* minimal index of the page which doesn't contain
+   file data */
+static inline pgoff_t size_to_next_pg(loff_t size)
+{
+	return (size ? off_to_pg(size - 1) + 1 : 0);
+}
+
+/* how many bytes of file of size @cnt can be contained
+   in page of index @idx */
+static inline unsigned cnt_to_pgcnt(loff_t cnt, pgoff_t idx)
+{
+	if (idx > off_to_pg(cnt))
+		return 0;
+	if (idx < off_to_pg(cnt))
+		return PAGE_CACHE_SIZE;
+	return off_to_pgoff(cnt);
+}
+
+/* how many bytes of file of size @cnt can be contained
+   in logical cluster of index @idx */
+static inline unsigned cnt_to_clcnt(loff_t cnt, cloff_t idx,
+				    struct inode *inode)
+{
+	if (idx > off_to_clust(cnt, inode))
+		return 0;
+	if (idx < off_to_clust(cnt, inode))
+		return inode_cluster_size(inode);
+	return off_to_cloff(cnt, inode);
+}
+
+static inline unsigned
+fsize_to_count(reiser4_cluster_t * clust, struct inode *inode)
+{
+	assert("edward-288", clust != NULL);
+	assert("edward-289", inode != NULL);
+
+	return cnt_to_clcnt(inode->i_size, clust->index, inode);
+}
+
+static inline int
+cluster_is_complete(reiser4_cluster_t * clust, struct inode * inode)
+{
+	return clust->tc.lsize == inode_cluster_size(inode);
+}
+
+static inline void reiser4_slide_init(reiser4_slide_t * win)
+{
+	assert("edward-1084", win != NULL);
+	memset(win, 0, sizeof *win);
+}
+
+static inline void
+tfm_cluster_init_act(tfm_cluster_t * tc, tfm_action act)
+{
+	assert("edward-1356", tc != NULL);
+	assert("edward-1357", act != TFM_INVAL);
+	tc->act = act;
+}
+
+static inline void
+cluster_init_act (reiser4_cluster_t * clust, tfm_action act, reiser4_slide_t * window){
+	assert("edward-84", clust != NULL);
+	memset(clust, 0, sizeof *clust);
+	tfm_cluster_init_act(&clust->tc, act);
+	clust->dstat = INVAL_DISK_CLUSTER;
+	clust->win = window;
+}
+
+static inline void
+cluster_init_read(reiser4_cluster_t * clust, reiser4_slide_t * window)
+{
+	cluster_init_act (clust, TFM_READ, window);
+}
+
+static inline void
+cluster_init_write(reiser4_cluster_t * clust, reiser4_slide_t * window)
+{
+	cluster_init_act (clust, TFM_WRITE, window);
+}
+
+static inline int dclust_get_extension(hint_t * hint)
+{
+	return hint->ext_coord.extension.ctail.shift;
+}
+
+static inline void dclust_set_extension(hint_t * hint)
+{
+	assert("edward-1270",
+	       item_id_by_coord(&hint->ext_coord.coord) == CTAIL_ID);
+	hint->ext_coord.extension.ctail.shift =
+	    cluster_shift_by_coord(&hint->ext_coord.coord);
+}
+
+static inline int hint_is_unprepped_dclust(hint_t * hint)
+{
+	return dclust_get_extension(hint) == (int)UCTAIL_SHIFT;
+}
+
+static inline void coord_set_between_clusters(coord_t * coord)
+{
+#if REISER4_DEBUG
+	int result;
+	result = zload(coord->node);
+	assert("edward-1296", !result);
+#endif
+	if (!coord_is_between_items(coord)) {
+		coord->between = AFTER_ITEM;
+		coord->unit_pos = 0;
+	}
+#if REISER4_DEBUG
+	zrelse(coord->node);
+#endif
+}
+
+int inflate_cluster(reiser4_cluster_t *, struct inode *);
+int find_cluster(reiser4_cluster_t *, struct inode *, int read, int write);
+void forget_cluster_pages(struct page **page, int nrpages);
+int flush_cluster_pages(reiser4_cluster_t *, jnode *, struct inode *);
+int deflate_cluster(reiser4_cluster_t *, struct inode *);
+void truncate_page_cluster(struct inode *inode, cloff_t start);
+void set_hint_cluster(struct inode *inode, hint_t * hint, unsigned long index,
+		      znode_lock_mode mode);
+void invalidate_hint_cluster(reiser4_cluster_t * clust);
+void put_hint_cluster(reiser4_cluster_t * clust, struct inode *inode,
+		      znode_lock_mode mode);
+int get_disk_cluster_locked(reiser4_cluster_t * clust, struct inode *inode,
+			    znode_lock_mode lock_mode);
+void reset_cluster_params(reiser4_cluster_t * clust);
+int set_cluster_by_page(reiser4_cluster_t * clust, struct page * page,
+			int count);
+int prepare_page_cluster(struct inode *inode, reiser4_cluster_t * clust,
+			 int capture);
+void release_cluster_pages_nocapture(reiser4_cluster_t *);
+void put_cluster_handle(reiser4_cluster_t * clust);
+int grab_tfm_stream(struct inode *inode, tfm_cluster_t * tc, tfm_stream_id id);
+int tfm_cluster_is_uptodate(tfm_cluster_t * tc);
+void tfm_cluster_set_uptodate(tfm_cluster_t * tc);
+void tfm_cluster_clr_uptodate(tfm_cluster_t * tc);
+unsigned long clust_by_coord(const coord_t * coord, struct inode *inode);
+
+/* move cluster handle to the target position
+   specified by the page of index @pgidx
+*/
+static inline void
+move_cluster_forward(reiser4_cluster_t * clust, struct inode *inode,
+		     pgoff_t pgidx, int *progress)
+{
+	assert("edward-1297", clust != NULL);
+	assert("edward-1298", inode != NULL);
+
+	reset_cluster_params(clust);
+	if (*progress &&
+	    /* Hole in the indices. Hint became invalid and can not be
+	       used by find_cluster_item() even if seal/node versions
+	       will coincide */
+	    pg_to_clust(pgidx, inode) != clust->index + 1) {
+		unset_hint(clust->hint);
+		invalidate_hint_cluster(clust);
+	}
+	*progress = 1;
+	clust->index = pg_to_clust(pgidx, inode);
+}
+
+static inline int
+alloc_clust_pages(reiser4_cluster_t * clust, struct inode *inode)
+{
+	assert("edward-791", clust != NULL);
+	assert("edward-792", inode != NULL);
+	clust->pages =
+		kmalloc(sizeof(*clust->pages) << inode_cluster_shift(inode),
+			GFP_KERNEL);
+	if (!clust->pages)
+		return -ENOMEM;
+	return 0;
+}
+
+static inline void free_clust_pages(reiser4_cluster_t * clust)
+{
+	kfree(clust->pages);
+}
+
+#endif				/* __FS_REISER4_CLUSTER_H__ */
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/compress/Makefile newtree/fs/reiser4/plugin/compress/Makefile
--- oldtree/fs/reiser4/plugin/compress/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/compress/Makefile	2006-02-21 15:58:35.080813464 +0000
@@ -0,0 +1,6 @@
+obj-$(CONFIG_REISER4_FS) += compress_plugins.o
+
+compress_plugins-objs :=	\
+	compress.o		\
+	minilzo.o		\
+	compress_mode.o
diff -urN oldtree/fs/reiser4/plugin/compress/compress.c newtree/fs/reiser4/plugin/compress/compress.c
--- oldtree/fs/reiser4/plugin/compress/compress.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/compress/compress.c	2006-02-21 15:58:35.441758592 +0000
@@ -0,0 +1,459 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+/* reiser4 compression transform plugins */
+
+#include "../../debug.h"
+#include "../../inode.h"
+#include "../plugin.h"
+#include "minilzo.h"
+
+#include <linux/config.h>
+#include <linux/zlib.h>
+#include <linux/types.h>
+#include <linux/hardirq.h>
+
+static int change_compression(struct inode *inode, reiser4_plugin * plugin)
+{
+	assert("edward-1316", inode != NULL);
+	assert("edward-1317", plugin != NULL);
+	assert("edward-1318", is_reiser4_inode(inode));
+	assert("edward-1319",
+	       plugin->h.type_id == REISER4_COMPRESSION_PLUGIN_TYPE);
+
+	if (inode_file_plugin(inode)->h.id != DIRECTORY_FILE_PLUGIN_ID)
+		if (inode_compression_plugin(inode) !=
+		    dual_compression_plugin(&plugin->compression))
+			return RETERR(-EINVAL);
+	return plugin_set_compression(&reiser4_inode_data(inode)->pset,
+				      &plugin->compression);
+}
+
+static reiser4_plugin_ops compression_plugin_ops = {
+	.init = NULL,
+	.load = NULL,
+	.save_len = NULL,
+	.save = NULL,
+	.change = &change_compression
+};
+
+/******************************************************************************/
+/*                         gzip1 compression                                  */
+/******************************************************************************/
+
+#define GZIP1_DEF_LEVEL		        Z_BEST_SPEED
+#define GZIP1_DEF_WINBITS		15
+#define GZIP1_DEF_MEMLEVEL		MAX_MEM_LEVEL
+
+static int gzip1_init(void)
+{
+	int ret = -EINVAL;
+#if REISER4_ZLIB
+	ret = 0;
+#endif
+	if (ret == -EINVAL)
+		warning("edward-1337", "Zlib not compiled into kernel");
+	return ret;
+}
+
+static int gzip1_overrun(unsigned src_len UNUSED_ARG)
+{
+	return 0;
+}
+
+static coa_t gzip1_alloc(tfm_action act)
+{
+	coa_t coa = NULL;
+#if REISER4_ZLIB
+	int ret = 0;
+	switch (act) {
+	case TFM_WRITE:	/* compress */
+		coa = vmalloc(zlib_deflate_workspacesize());
+		if (!coa) {
+			ret = -ENOMEM;
+			break;
+		}
+		memset(coa, 0, zlib_deflate_workspacesize());
+		break;
+	case TFM_READ:	/* decompress */
+		coa = vmalloc(zlib_inflate_workspacesize());
+		if (!coa) {
+			ret = -ENOMEM;
+			break;
+		}
+		memset(coa, 0, zlib_inflate_workspacesize());
+		break;
+	default:
+		impossible("edward-767",
+			   "trying to alloc workspace for unknown tfm action");
+	}
+	if (ret) {
+		warning("edward-768",
+			"alloc workspace for gzip1 (tfm action = %d) failed\n",
+			act);
+		return ERR_PTR(ret);
+	}
+#endif
+	return coa;
+}
+
+static coa_t gzip1_nocompress_alloc(tfm_action act)
+{
+	coa_t coa = NULL;
+#if REISER4_ZLIB
+	int ret = 0;
+	switch (act) {
+	case TFM_WRITE:	/* compress */
+		break;
+	case TFM_READ:  /* decompress */
+		coa = vmalloc(zlib_inflate_workspacesize());
+		if (!coa) {
+			ret = -ENOMEM;
+			break;
+		}
+		memset(coa, 0, zlib_inflate_workspacesize());
+		break;
+	default:
+		impossible("edward-1299", "unknown tfm action");
+	}
+	if (ret) {
+		warning("edward-1300",
+			"alloc workspace for gzip1 (tfm action = %d) failed\n",
+			act);
+		return ERR_PTR(ret);
+	}
+#endif
+	return coa;
+}
+
+static void gzip1_free(coa_t coa, tfm_action act)
+{
+	assert("edward-769", coa != NULL);
+
+	switch (act) {
+	case TFM_WRITE:	/* compress */
+		vfree(coa);
+		break;
+	case TFM_READ:		/* decompress */
+		vfree(coa);
+		break;
+	default:
+		impossible("edward-770", "unknown tfm action");
+	}
+	return;
+}
+
+static void gzip1_nocompress_free(coa_t coa, tfm_action act)
+{
+	assert("edward-1301", coa != NULL);
+
+	switch (act) {
+	case TFM_READ:		/* decompress */
+		vfree(coa);
+		break;
+	case TFM_WRITE:	/* compress */
+		impossible("edward-1302",
+			   "trying to free non-allocated workspace");
+	default:
+		impossible("edward-1303", "unknown tfm action");
+	}
+	return;
+}
+
+static int gzip1_min_size_deflate(void)
+{
+	return 64;
+}
+
+static void
+gzip1_compress(coa_t coa, __u8 * src_first, unsigned src_len,
+	       __u8 * dst_first, unsigned *dst_len)
+{
+#if REISER4_ZLIB
+	int ret = 0;
+	struct z_stream_s stream;
+
+	memset(&stream, 0, sizeof(stream));
+
+	assert("edward-842", coa != NULL);
+	assert("edward-875", src_len != 0);
+
+	stream.workspace = coa;
+	ret = zlib_deflateInit2(&stream, GZIP1_DEF_LEVEL, Z_DEFLATED,
+				-GZIP1_DEF_WINBITS, GZIP1_DEF_MEMLEVEL,
+				Z_DEFAULT_STRATEGY);
+	if (ret != Z_OK) {
+		warning("edward-771", "zlib_deflateInit2 returned %d\n", ret);
+		goto rollback;
+	}
+	ret = zlib_deflateReset(&stream);
+	if (ret != Z_OK) {
+		warning("edward-772", "zlib_deflateReset returned %d\n", ret);
+		goto rollback;
+	}
+	stream.next_in = src_first;
+	stream.avail_in = src_len;
+	stream.next_out = dst_first;
+	stream.avail_out = *dst_len;
+
+	ret = zlib_deflate(&stream, Z_FINISH);
+	if (ret != Z_STREAM_END) {
+		warning("edward-773", "zlib_deflate returned %d\n", ret);
+		goto rollback;
+	}
+	*dst_len = stream.total_out;
+	return;
+      rollback:
+	*dst_len = src_len;
+#endif
+	return;
+}
+
+static void
+gzip1_decompress(coa_t coa, __u8 * src_first, unsigned src_len,
+		 __u8 * dst_first, unsigned *dst_len)
+{
+#if REISER4_ZLIB
+	int ret = 0;
+	struct z_stream_s stream;
+
+	memset(&stream, 0, sizeof(stream));
+
+	assert("edward-843", coa != NULL);
+	assert("edward-876", src_len != 0);
+
+	stream.workspace = coa;
+	ret = zlib_inflateInit2(&stream, -GZIP1_DEF_WINBITS);
+	if (ret != Z_OK) {
+		warning("edward-774", "zlib_inflateInit2 returned %d\n", ret);
+		return;
+	}
+	ret = zlib_inflateReset(&stream);
+	if (ret != Z_OK) {
+		warning("edward-775", "zlib_inflateReset returned %d\n", ret);
+		return;
+	}
+
+	stream.next_in = src_first;
+	stream.avail_in = src_len;
+	stream.next_out = dst_first;
+	stream.avail_out = *dst_len;
+
+	ret = zlib_inflate(&stream, Z_SYNC_FLUSH);
+	/*
+	 * Work around a bug in zlib, which sometimes wants to taste an extra
+	 * byte when being used in the (undocumented) raw deflate mode.
+	 * (From USAGI).
+	 */
+	if (ret == Z_OK && !stream.avail_in && stream.avail_out) {
+		u8 zerostuff = 0;
+		stream.next_in = &zerostuff;
+		stream.avail_in = 1;
+		ret = zlib_inflate(&stream, Z_FINISH);
+	}
+	if (ret != Z_STREAM_END) {
+		warning("edward-776", "zlib_inflate returned %d\n", ret);
+		return;
+	}
+	*dst_len = stream.total_out;
+#endif
+	return;
+}
+
+/******************************************************************************/
+/*                            lzo1 compression                                */
+/******************************************************************************/
+
+static int lzo1_init(void)
+{
+	int ret;
+	ret = lzo_init();
+	if (ret != LZO_E_OK)
+		warning("edward-848", "lzo_init() failed with ret = %d\n", ret);
+	return ret;
+}
+
+static int lzo1_overrun(unsigned in_len)
+{
+	return in_len / 64 + 16 + 3;
+}
+
+#define LZO_HEAP_SIZE(size) \
+	sizeof(lzo_align_t) * (((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t))
+
+static coa_t lzo1_alloc(tfm_action act)
+{
+	int ret = 0;
+	coa_t coa = NULL;
+
+	switch (act) {
+	case TFM_WRITE:	/* compress */
+		coa = vmalloc(LZO_HEAP_SIZE(LZO1X_1_MEM_COMPRESS));
+		if (!coa) {
+			ret = -ENOMEM;
+			break;
+		}
+		memset(coa, 0, LZO_HEAP_SIZE(LZO1X_1_MEM_COMPRESS));
+	case TFM_READ:		/* decompress */
+		break;
+	default:
+		impossible("edward-877",
+			   "trying to alloc workspace for unknown tfm action");
+	}
+	if (ret) {
+		warning("edward-878",
+			"alloc workspace for lzo1 (tfm action = %d) failed\n",
+			act);
+		return ERR_PTR(ret);
+	}
+	return coa;
+}
+
+static void lzo1_free(coa_t coa, tfm_action act)
+{
+	assert("edward-879", coa != NULL);
+
+	switch (act) {
+	case TFM_WRITE:	/* compress */
+		vfree(coa);
+		break;
+	case TFM_READ:		/* decompress */
+		impossible("edward-1304",
+			   "trying to free non-allocated workspace");
+	default:
+		impossible("edward-880", "unknown tfm action");
+	}
+	return;
+}
+
+static int lzo1_min_size_deflate(void)
+{
+	return 256;
+}
+
+static void
+lzo1_compress(coa_t coa, __u8 * src_first, unsigned src_len,
+	      __u8 * dst_first, unsigned *dst_len)
+{
+	int result;
+
+	assert("edward-846", coa != NULL);
+	assert("edward-847", src_len != 0);
+
+	result = lzo1x_1_compress(src_first, src_len, dst_first, dst_len, coa);
+	if (result != LZO_E_OK) {
+		warning("edward-849", "lzo1x_1_compress failed\n");
+		goto out;
+	}
+	if (*dst_len >= src_len) {
+		//warning("edward-850", "lzo1x_1_compress: incompressible data\n");
+		goto out;
+	}
+	return;
+      out:
+	*dst_len = src_len;
+	return;
+}
+
+static void
+lzo1_decompress(coa_t coa, __u8 * src_first, unsigned src_len,
+		__u8 * dst_first, unsigned *dst_len)
+{
+	int result;
+
+	assert("edward-851", coa == NULL);
+	assert("edward-852", src_len != 0);
+
+	result = lzo1x_decompress(src_first, src_len, dst_first, dst_len, NULL);
+	if (result != LZO_E_OK)
+		warning("edward-853", "lzo1x_1_decompress failed\n");
+	return;
+}
+
+compression_plugin compression_plugins[LAST_COMPRESSION_ID] = {
+	[LZO1_COMPRESSION_ID] = {
+		.h = {
+			.type_id = REISER4_COMPRESSION_PLUGIN_TYPE,
+			.id = LZO1_COMPRESSION_ID,
+			.pops = &compression_plugin_ops,
+			.label = "lzo1",
+			.desc = "lzo1 compression transform",
+			.linkage = {NULL, NULL}
+		},
+		.dual = LZO1_NO_COMPRESSION_ID,
+		.init = lzo1_init,
+		.overrun = lzo1_overrun,
+		.alloc = lzo1_alloc,
+		.free = lzo1_free,
+		.min_size_deflate = lzo1_min_size_deflate,
+		.checksum = reiser4_adler32,
+		.compress = lzo1_compress,
+		.decompress = lzo1_decompress
+	},
+	[LZO1_NO_COMPRESSION_ID] = {
+		.h = {
+			.type_id = REISER4_COMPRESSION_PLUGIN_TYPE,
+			.id = LZO1_NO_COMPRESSION_ID,
+			.pops = &compression_plugin_ops,
+			.label = "lzo1_no",
+			.desc = "Disable lzo1 compression transform",
+			.linkage = {NULL, NULL}
+		},
+		.dual = LZO1_COMPRESSION_ID,
+		.init = lzo1_init,
+		.overrun = NULL,
+		.alloc = NULL,
+		.free = NULL,
+		.min_size_deflate = NULL,
+		.checksum = reiser4_adler32,
+		.compress = NULL,
+		.decompress = lzo1_decompress
+	},
+	[GZIP1_COMPRESSION_ID] = {
+		.h = {
+			.type_id = REISER4_COMPRESSION_PLUGIN_TYPE,
+			.id = GZIP1_COMPRESSION_ID,
+			.pops = &compression_plugin_ops,
+			.label = "gzip1",
+			.desc = "gzip1 compression transform",
+			.linkage = {NULL, NULL}
+		},
+		.dual = GZIP1_NO_COMPRESSION_ID,
+		.init = gzip1_init,
+		.overrun = gzip1_overrun,
+		.alloc = gzip1_alloc,
+		.free = gzip1_free,
+		.min_size_deflate = gzip1_min_size_deflate,
+		.checksum = NULL,
+		.compress = gzip1_compress,
+		.decompress = gzip1_decompress
+	},
+	[GZIP1_NO_COMPRESSION_ID] = {
+		.h = {
+			.type_id = REISER4_COMPRESSION_PLUGIN_TYPE,
+			.id = GZIP1_NO_COMPRESSION_ID,
+			.pops = &compression_plugin_ops,
+			.label = "gzip1_no",
+			.desc =	"Disable gzip1 compression transform",
+			.linkage = {NULL, NULL}
+		},
+		.dual = GZIP1_COMPRESSION_ID,
+		.init = gzip1_init,
+		.overrun = NULL,
+		.alloc = gzip1_nocompress_alloc,
+		.free = gzip1_nocompress_free,
+		.min_size_deflate = NULL,
+		.checksum = NULL,
+		.compress = NULL,
+		.decompress = gzip1_decompress
+	}
+};
+
+/*
+  Local variables:
+  c-indentation-style: "K&R"
+  mode-name: "LC"
+  c-basic-offset: 8
+  tab-width: 8
+  fill-column: 120
+  scroll-step: 1
+  End:
+*/
diff -urN oldtree/fs/reiser4/plugin/compress/compress.h newtree/fs/reiser4/plugin/compress/compress.h
--- oldtree/fs/reiser4/plugin/compress/compress.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/compress/compress.h	2006-02-21 15:58:35.441758592 +0000
@@ -0,0 +1,40 @@
+#if !defined( __FS_REISER4_COMPRESS_H__ )
+#define __FS_REISER4_COMPRESS_H__
+
+#include <linux/types.h>
+#include <linux/string.h>
+
+typedef enum {
+	TFM_INVAL,
+	TFM_READ,
+	TFM_WRITE
+} tfm_action;
+
+/* builtin compression plugins */
+
+typedef enum {
+	LZO1_COMPRESSION_ID,
+	LZO1_NO_COMPRESSION_ID,
+	GZIP1_COMPRESSION_ID,
+	GZIP1_NO_COMPRESSION_ID,
+	LAST_COMPRESSION_ID,
+} reiser4_compression_id;
+
+typedef unsigned long cloff_t;
+typedef void *coa_t;
+typedef coa_t coa_set[LAST_COMPRESSION_ID];
+
+__u32 reiser4_adler32(char *data, __u32 len);
+
+#endif				/* __FS_REISER4_COMPRESS_H__ */
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/compress/compress_mode.c newtree/fs/reiser4/plugin/compress/compress_mode.c
--- oldtree/fs/reiser4/plugin/compress/compress_mode.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/compress/compress_mode.c	2006-02-21 15:58:35.441758592 +0000
@@ -0,0 +1,177 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+/* This file contains Reiser4 compression mode plugins.
+
+   Compression mode plugin is a set of handlers called by compressor
+   at flush time and represent some heuristics including the ones
+   which are to avoid compression of incompressible data, see
+   http://www.namesys.com/cryptcompress_design.html for more details.
+*/
+#include "../../inode.h"
+#include "../plugin.h"
+
+static int should_deflate_test(struct inode * inode, cloff_t index)
+{
+	return !test_bit(0, &index);
+}
+
+static int should_deflate_none(struct inode * inode, cloff_t index)
+{
+	return 0;
+}
+
+static int should_deflate_common(struct inode * inode, cloff_t index)
+{
+	return inode_compression_plugin(inode)->compress != NULL;
+}
+
+/* generic turn on/off compression */
+int switch_compression(struct inode *inode)
+{
+	int result;
+
+	result = force_plugin(inode,
+			      PSET_COMPRESSION,
+			      compression_plugin_to_plugin
+			      (dual_compression_plugin
+			       (inode_compression_plugin(inode))));
+	if (result)
+		return result;
+	__mark_inode_dirty(inode, I_DIRTY_PAGES);
+	return 0;
+}
+
+static int switch_compression_on_zero(struct inode *inode, cloff_t index)
+{
+	assert("edward-1308", inode != NULL);
+	return (index ? 0 : switch_compression(inode));
+}
+
+static int turn_off_compression(struct inode *inode, cloff_t index)
+{
+	return (inode_compression_plugin(inode)->compress ?
+		switch_compression(inode) : 0);
+}
+
+static int turn_on_compression(struct inode *inode, cloff_t index)
+{
+	return (inode_compression_plugin(inode)->compress ?
+		0 : switch_compression(inode));
+}
+
+/* Check on lattice (COL) of some sparseness factor,
+   the family of adaptive compression modes which define
+   the following behavior:
+
+   Compression is on: try to compress everything and turn
+   it off, whenever cluster is incompressible.
+
+   Compression is off: try to compress clusters of indexes
+   k * FACTOR (k = 0, 1, 2, ...) and turn it on, if some of
+   them is compressible. */
+
+/* check if @index belongs to one-dimensional lattice
+   of sparce factor @factor */
+static int check_on_lattice(cloff_t index, int factor)
+{
+	return (factor ? index % factor == 0: index == 0);
+}
+
+#define DEFINE_CHECK_ON_LATTICE(FACTOR)                                 \
+	static int check_on_lattice_ ## FACTOR (struct inode * inode,   \
+						cloff_t index)		\
+{                                                                       \
+	return should_deflate_common(inode, index) ||			\
+		check_on_lattice(index, FACTOR);			\
+}
+
+#define SUPPORT_COL_COMPRESSION_MODE(FACTOR, LABEL)                     \
+[COL_ ## FACTOR ## _COMPRESSION_MODE_ID] = {                            \
+	.h = {                                                          \
+		.type_id = REISER4_COMPRESSION_MODE_PLUGIN_TYPE,        \
+		.id = COL_ ## FACTOR ## _COMPRESSION_MODE_ID,           \
+		.pops = NULL,                                           \
+		.label = LABEL,                                         \
+		.desc = LABEL,                                          \
+		.linkage = {NULL, NULL}                                 \
+	},                                                              \
+	.should_deflate = check_on_lattice_ ## FACTOR,                  \
+	.accept_hook =  turn_on_compression,                            \
+	.discard_hook = turn_off_compression                            \
+}
+
+DEFINE_CHECK_ON_LATTICE(8)
+DEFINE_CHECK_ON_LATTICE(16)
+DEFINE_CHECK_ON_LATTICE(32)
+
+/* compression mode_plugins */
+compression_mode_plugin compression_mode_plugins[LAST_COMPRESSION_MODE_ID] = {
+	[NONE_COMPRESSION_MODE_ID] = {
+		.h = {
+			.type_id = REISER4_COMPRESSION_MODE_PLUGIN_TYPE,
+			.id = NONE_COMPRESSION_MODE_ID,
+			.pops = NULL,
+			.label = "none",
+			.desc = "Don't compress",
+			.linkage = {NULL, NULL}
+		},
+		.should_deflate = should_deflate_none,
+		.accept_hook = NULL,
+		.discard_hook = NULL
+	},
+	/* Check-on-lattice adaptive compression modes */
+	SUPPORT_COL_COMPRESSION_MODE(8, "col8"),
+	SUPPORT_COL_COMPRESSION_MODE(16, "col16"),
+	SUPPORT_COL_COMPRESSION_MODE(32, "col32"),
+	/* Turn off compression if logical cluster of index == 0
+	   is incompressible, then don't check anymore */
+	[COZ_COMPRESSION_MODE_ID] = {
+		.h = {
+			.type_id = REISER4_COMPRESSION_MODE_PLUGIN_TYPE,
+			.id = COZ_COMPRESSION_MODE_ID,
+			.pops = NULL,
+			.label = "coz",
+			.desc = "Check on zero",
+			.linkage = {NULL, NULL}
+		},
+		.should_deflate = should_deflate_common,
+		.accept_hook = NULL,
+		.discard_hook = switch_compression_on_zero
+	},
+	[FORCE_COMPRESSION_MODE_ID] = {
+		.h = {
+			.type_id = REISER4_COMPRESSION_MODE_PLUGIN_TYPE,
+			.id = FORCE_COMPRESSION_MODE_ID,
+			.pops = NULL,
+			.label = "force",
+			.desc = "Compress everything",
+			.linkage = {NULL, NULL}
+		},
+		.should_deflate = NULL,
+		.accept_hook = NULL,
+		.discard_hook = NULL
+	},
+	[TEST_COMPRESSION_MODE_ID] = {
+		.h = {
+			.type_id = REISER4_COMPRESSION_MODE_PLUGIN_TYPE,
+			.id = TEST_COMPRESSION_MODE_ID,
+			.pops = NULL,
+			.label = "test", /* This mode is for benchmarks only */
+			.desc = "Don't compress odd clusters",
+			.linkage = {NULL, NULL}
+		},
+		.should_deflate = should_deflate_test,
+		.accept_hook = NULL,
+		.discard_hook = NULL
+	}
+};
+
+/*
+  Local variables:
+  c-indentation-style: "K&R"
+  mode-name: "LC"
+  c-basic-offset: 8
+  tab-width: 8
+  fill-column: 120
+  scroll-step: 1
+  End:
+*/
diff -urN oldtree/fs/reiser4/plugin/compress/lzoconf.h newtree/fs/reiser4/plugin/compress/lzoconf.h
--- oldtree/fs/reiser4/plugin/compress/lzoconf.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/compress/lzoconf.h	2006-02-21 15:58:34.564891896 +0000
@@ -0,0 +1,420 @@
+/* lzoconf.h -- configuration for the LZO real-time data compression library
+   adopted for reiser4 compression transform plugin.
+
+   This file is part of the LZO real-time data compression library
+   and not included in any proprietary licenses of reiser4.
+
+   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+   Markus F.X.J. Oberhumer
+   <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+ */
+
+#include <linux/kernel.h>	/* for UINT_MAX, ULONG_MAX - edward */
+
+#ifndef __LZOCONF_H
+#define __LZOCONF_H
+
+#define LZO_VERSION             0x1080
+#define LZO_VERSION_STRING      "1.08"
+#define LZO_VERSION_DATE        "Jul 12 2002"
+
+/* internal Autoconf configuration file - only used when building LZO */
+#if defined(LZO_HAVE_CONFIG_H)
+#  include <config.h>
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***********************************************************************
+// LZO requires a conforming <limits.h>
+************************************************************************/
+
+#define CHAR_BIT  8
+#define USHRT_MAX 0xffff
+
+/* workaround a cpp bug under hpux 10.20 */
+#define LZO_0xffffffffL         4294967295ul
+
+/***********************************************************************
+// architecture defines
+************************************************************************/
+
+#if !defined(__LZO_WIN) && !defined(__LZO_DOS) && !defined(__LZO_OS2)
+#  if defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows)
+#    define __LZO_WIN
+#  elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
+#    define __LZO_WIN
+#  elif defined(__NT__) || defined(__NT_DLL__) || defined(__WINDOWS_386__)
+#    define __LZO_WIN
+#  elif defined(__DOS__) || defined(__MSDOS__) || defined(MSDOS)
+#    define __LZO_DOS
+#  elif defined(__OS2__) || defined(__OS2V2__) || defined(OS2)
+#    define __LZO_OS2
+#  elif defined(__palmos__)
+#    define __LZO_PALMOS
+#  elif defined(__TOS__) || defined(__atarist__)
+#    define __LZO_TOS
+#  endif
+#endif
+
+#if (UINT_MAX < LZO_0xffffffffL)
+#  if defined(__LZO_WIN)
+#    define __LZO_WIN16
+#  elif defined(__LZO_DOS)
+#    define __LZO_DOS16
+#  elif defined(__LZO_PALMOS)
+#    define __LZO_PALMOS16
+#  elif defined(__LZO_TOS)
+#    define __LZO_TOS16
+#  elif defined(__C166__)
+#  else
+	/* porting hint: for pure 16-bit architectures try compiling
+	 * everything with -D__LZO_STRICT_16BIT */
+#    error "16-bit target not supported - contact me for porting hints"
+#  endif
+#endif
+
+#if !defined(__LZO_i386)
+#  if defined(__LZO_DOS) || defined(__LZO_WIN16)
+#    define __LZO_i386
+#  elif defined(__i386__) || defined(__386__) || defined(_M_IX86)
+#    define __LZO_i386
+#  endif
+#endif
+
+#if defined(__LZO_STRICT_16BIT)
+#  if (UINT_MAX < LZO_0xffffffffL)
+#    include <lzo16bit.h>
+#  endif
+#endif
+
+/* memory checkers */
+#if !defined(__LZO_CHECKER)
+#  if defined(__BOUNDS_CHECKING_ON)
+#    define __LZO_CHECKER
+#  elif defined(__CHECKER__)
+#    define __LZO_CHECKER
+#  elif defined(__INSURE__)
+#    define __LZO_CHECKER
+#  elif defined(__PURIFY__)
+#    define __LZO_CHECKER
+#  endif
+#endif
+
+/***********************************************************************
+// integral and pointer types
+************************************************************************/
+
+/* Integral types with 32 bits or more */
+#if !defined(LZO_UINT32_MAX)
+#  if (UINT_MAX >= LZO_0xffffffffL)
+	typedef unsigned int lzo_uint32;
+	typedef int lzo_int32;
+#    define LZO_UINT32_MAX      UINT_MAX
+#    define LZO_INT32_MAX       INT_MAX
+#    define LZO_INT32_MIN       INT_MIN
+#  elif (ULONG_MAX >= LZO_0xffffffffL)
+	typedef unsigned long lzo_uint32;
+	typedef long lzo_int32;
+#    define LZO_UINT32_MAX      ULONG_MAX
+#    define LZO_INT32_MAX       LONG_MAX
+#    define LZO_INT32_MIN       LONG_MIN
+#  else
+#    error "lzo_uint32"
+#  endif
+#endif
+
+/* lzo_uint is used like size_t */
+#if !defined(LZO_UINT_MAX)
+#  if (UINT_MAX >= LZO_0xffffffffL)
+	typedef unsigned int lzo_uint;
+	typedef int lzo_int;
+#    define LZO_UINT_MAX        UINT_MAX
+#    define LZO_INT_MAX         INT_MAX
+#    define LZO_INT_MIN         INT_MIN
+#  elif (ULONG_MAX >= LZO_0xffffffffL)
+	typedef unsigned long lzo_uint;
+	typedef long lzo_int;
+#    define LZO_UINT_MAX        ULONG_MAX
+#    define LZO_INT_MAX         LONG_MAX
+#    define LZO_INT_MIN         LONG_MIN
+#  else
+#    error "lzo_uint"
+#  endif
+#endif
+
+	typedef int lzo_bool;
+
+/***********************************************************************
+// memory models
+************************************************************************/
+
+/* Memory model for the public code segment. */
+#if !defined(__LZO_CMODEL)
+#  if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+#    define __LZO_CMODEL        __far
+#  elif defined(__LZO_i386) && defined(__WATCOMC__)
+#    define __LZO_CMODEL        __near
+#  else
+#    define __LZO_CMODEL
+#  endif
+#endif
+
+/* Memory model for the public data segment. */
+#if !defined(__LZO_DMODEL)
+#  if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+#    define __LZO_DMODEL        __far
+#  elif defined(__LZO_i386) && defined(__WATCOMC__)
+#    define __LZO_DMODEL        __near
+#  else
+#    define __LZO_DMODEL
+#  endif
+#endif
+
+/* Memory model that allows to access memory at offsets of lzo_uint. */
+#if !defined(__LZO_MMODEL)
+#  if (LZO_UINT_MAX <= UINT_MAX)
+#    define __LZO_MMODEL
+#  elif defined(__LZO_DOS16) || defined(__LZO_WIN16)
+#    define __LZO_MMODEL        __huge
+#    define LZO_999_UNSUPPORTED
+#  elif defined(__LZO_PALMOS16) || defined(__LZO_TOS16)
+#    define __LZO_MMODEL
+#  else
+#    error "__LZO_MMODEL"
+#  endif
+#endif
+
+/* no typedef here because of const-pointer issues */
+#define lzo_byte                unsigned char __LZO_MMODEL
+#define lzo_bytep               unsigned char __LZO_MMODEL *
+#define lzo_charp               char __LZO_MMODEL *
+#define lzo_voidp               void __LZO_MMODEL *
+#define lzo_shortp              short __LZO_MMODEL *
+#define lzo_ushortp             unsigned short __LZO_MMODEL *
+#define lzo_uint32p             lzo_uint32 __LZO_MMODEL *
+#define lzo_int32p              lzo_int32 __LZO_MMODEL *
+#define lzo_uintp               lzo_uint __LZO_MMODEL *
+#define lzo_intp                lzo_int __LZO_MMODEL *
+#define lzo_voidpp              lzo_voidp __LZO_MMODEL *
+#define lzo_bytepp              lzo_bytep __LZO_MMODEL *
+
+#ifndef lzo_sizeof_dict_t
+#  define lzo_sizeof_dict_t     sizeof(lzo_bytep)
+#endif
+
+/***********************************************************************
+// calling conventions and function types
+************************************************************************/
+
+/* linkage */
+#if !defined(__LZO_EXTERN_C)
+#  ifdef __cplusplus
+#    define __LZO_EXTERN_C      extern "C"
+#  else
+#    define __LZO_EXTERN_C      extern
+#  endif
+#endif
+
+/* calling convention */
+#if !defined(__LZO_CDECL)
+#  if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+#    define __LZO_CDECL         __LZO_CMODEL __cdecl
+#  elif defined(__LZO_i386) && defined(_MSC_VER)
+#    define __LZO_CDECL         __LZO_CMODEL __cdecl
+#  elif defined(__LZO_i386) && defined(__WATCOMC__)
+#    define __LZO_CDECL         __LZO_CMODEL __cdecl
+#  else
+#    define __LZO_CDECL         __LZO_CMODEL
+#  endif
+#endif
+#if !defined(__LZO_ENTRY)
+#  define __LZO_ENTRY           __LZO_CDECL
+#endif
+
+/* C++ exception specification for extern "C" function types */
+#if !defined(__cplusplus)
+#  undef LZO_NOTHROW
+#  define LZO_NOTHROW
+#elif !defined(LZO_NOTHROW)
+#  define LZO_NOTHROW
+#endif
+
+	typedef int
+	 (__LZO_ENTRY * lzo_compress_t) (const lzo_byte * src, lzo_uint src_len,
+					 lzo_byte * dst, lzo_uintp dst_len,
+					 lzo_voidp wrkmem);
+
+	typedef int
+	 (__LZO_ENTRY * lzo_decompress_t) (const lzo_byte * src,
+					   lzo_uint src_len, lzo_byte * dst,
+					   lzo_uintp dst_len, lzo_voidp wrkmem);
+
+	typedef int
+	 (__LZO_ENTRY * lzo_optimize_t) (lzo_byte * src, lzo_uint src_len,
+					 lzo_byte * dst, lzo_uintp dst_len,
+					 lzo_voidp wrkmem);
+
+	typedef int
+	 (__LZO_ENTRY * lzo_compress_dict_t) (const lzo_byte * src,
+					      lzo_uint src_len, lzo_byte * dst,
+					      lzo_uintp dst_len,
+					      lzo_voidp wrkmem,
+					      const lzo_byte * dict,
+					      lzo_uint dict_len);
+
+	typedef int
+	 (__LZO_ENTRY * lzo_decompress_dict_t) (const lzo_byte * src,
+						lzo_uint src_len,
+						lzo_byte * dst,
+						lzo_uintp dst_len,
+						lzo_voidp wrkmem,
+						const lzo_byte * dict,
+						lzo_uint dict_len);
+
+/* assembler versions always use __cdecl */
+	typedef int
+	 (__LZO_CDECL * lzo_compress_asm_t) (const lzo_byte * src,
+					     lzo_uint src_len, lzo_byte * dst,
+					     lzo_uintp dst_len,
+					     lzo_voidp wrkmem);
+
+	typedef int
+	 (__LZO_CDECL * lzo_decompress_asm_t) (const lzo_byte * src,
+					       lzo_uint src_len, lzo_byte * dst,
+					       lzo_uintp dst_len,
+					       lzo_voidp wrkmem);
+
+/* a progress indicator callback function */
+	typedef void (__LZO_ENTRY * lzo_progress_callback_t) (lzo_uint,
+							      lzo_uint);
+
+/***********************************************************************
+// export information
+************************************************************************/
+
+/* DLL export information */
+#if !defined(__LZO_EXPORT1)
+#  define __LZO_EXPORT1
+#endif
+#if !defined(__LZO_EXPORT2)
+#  define __LZO_EXPORT2
+#endif
+
+/* exported calling convention for C functions */
+#if !defined(LZO_PUBLIC)
+#  define LZO_PUBLIC(_rettype) \
+                __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_ENTRY
+#endif
+#if !defined(LZO_EXTERN)
+#  define LZO_EXTERN(_rettype)          __LZO_EXTERN_C LZO_PUBLIC(_rettype)
+#endif
+#if !defined(LZO_PRIVATE)
+#  define LZO_PRIVATE(_rettype)         static _rettype __LZO_ENTRY
+#endif
+
+/* exported __cdecl calling convention for assembler functions */
+#if !defined(LZO_PUBLIC_CDECL)
+#  define LZO_PUBLIC_CDECL(_rettype) \
+                __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL
+#endif
+#if !defined(LZO_EXTERN_CDECL)
+#  define LZO_EXTERN_CDECL(_rettype)    __LZO_EXTERN_C LZO_PUBLIC_CDECL(_rettype)
+#endif
+
+/* exported global variables (LZO currently uses no static variables and
+ * is fully thread safe) */
+#if !defined(LZO_PUBLIC_VAR)
+#  define LZO_PUBLIC_VAR(_type) \
+                __LZO_EXPORT1 _type __LZO_EXPORT2 __LZO_DMODEL
+#endif
+#if !defined(LZO_EXTERN_VAR)
+#  define LZO_EXTERN_VAR(_type)         extern LZO_PUBLIC_VAR(_type)
+#endif
+
+/***********************************************************************
+// error codes and prototypes
+************************************************************************/
+
+/* Error codes for the compression/decompression functions. Negative
+ * values are errors, positive values will be used for special but
+ * normal events.
+ */
+#define LZO_E_OK                    0
+#define LZO_E_ERROR                 (-1)
+#define LZO_E_OUT_OF_MEMORY         (-2)	/* not used right now */
+#define LZO_E_NOT_COMPRESSIBLE      (-3)	/* not used right now */
+#define LZO_E_INPUT_OVERRUN         (-4)
+#define LZO_E_OUTPUT_OVERRUN        (-5)
+#define LZO_E_LOOKBEHIND_OVERRUN    (-6)
+#define LZO_E_EOF_NOT_FOUND         (-7)
+#define LZO_E_INPUT_NOT_CONSUMED    (-8)
+
+/* lzo_init() should be the first function you call.
+ * Check the return code !
+ *
+ * lzo_init() is a macro to allow checking that the library and the
+ * compiler's view of various types are consistent.
+ */
+#define lzo_init() __lzo_init2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\
+    (int)sizeof(long),(int)sizeof(lzo_uint32),(int)sizeof(lzo_uint),\
+    (int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\
+    (int)sizeof(lzo_compress_t))
+	 LZO_EXTERN(int) __lzo_init2(unsigned, int, int, int, int, int, int,
+				     int, int, int);
+
+/* checksum functions */
+	 LZO_EXTERN(lzo_uint32)
+	 lzo_crc32(lzo_uint32 _c, const lzo_byte * _buf, lzo_uint _len);
+
+/* misc. */
+	typedef union {
+		lzo_bytep p;
+		lzo_uint u;
+	} __lzo_pu_u;
+	typedef union {
+		lzo_bytep p;
+		lzo_uint32 u32;
+	} __lzo_pu32_u;
+	typedef union {
+		void *vp;
+		lzo_bytep bp;
+		lzo_uint32 u32;
+		long l;
+	} lzo_align_t;
+
+#define LZO_PTR_ALIGN_UP(_ptr,_size) \
+    ((_ptr) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(_ptr),(lzo_uint)(_size)))
+
+/* deprecated - only for backward compatibility */
+#define LZO_ALIGN(_ptr,_size) LZO_PTR_ALIGN_UP(_ptr,_size)
+
+#ifdef __cplusplus
+}				/* extern "C" */
+#endif
+#endif				/* already included */
diff -urN oldtree/fs/reiser4/plugin/compress/minilzo.c newtree/fs/reiser4/plugin/compress/minilzo.c
--- oldtree/fs/reiser4/plugin/compress/minilzo.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/compress/minilzo.c	2006-02-21 15:58:34.567891440 +0000
@@ -0,0 +1,2155 @@
+/* minilzo.c -- mini subset of the LZO real-time data compression library
+   adopted for reiser4 compression transform plugin.
+
+   This file is part of the LZO real-time data compression library
+   and not included in any proprietary licenses of reiser4.
+
+   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+   Markus F.X.J. Oberhumer
+   <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+ */
+
+/*
+ * NOTE:
+ *   the full LZO package can be found at
+ *   http://www.oberhumer.com/opensource/lzo/
+ */
+
+#include "../../debug.h"	/* for reiser4 assert macro -edward */
+
+#define __LZO_IN_MINILZO
+#define LZO_BUILD
+
+#ifdef MINILZO_HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#undef LZO_HAVE_CONFIG_H
+#include "minilzo.h"
+
+#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x1080)
+#  error "version mismatch in miniLZO source files"
+#endif
+
+#ifdef MINILZO_HAVE_CONFIG_H
+#  define LZO_HAVE_CONFIG_H
+#endif
+
+
+#ifndef __LZO_CONF_H
+#define __LZO_CONF_H
+
+#if !defined(__LZO_IN_MINILZO)
+#  ifndef __LZOCONF_H
+#    include <lzoconf.h>
+#  endif
+#endif
+
+#if defined(__BOUNDS_CHECKING_ON)
+#  include <unchecked.h>
+#else
+#  define BOUNDS_CHECKING_OFF_DURING(stmt)      stmt
+#  define BOUNDS_CHECKING_OFF_IN_EXPR(expr)     (expr)
+#endif
+
+#  define HAVE_MEMCMP
+#  define HAVE_MEMCPY
+#  define HAVE_MEMMOVE
+#  define HAVE_MEMSET
+
+#if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+#  define HAVE_MALLOC_H
+#  define HAVE_HALLOC
+#endif
+
+#undef NDEBUG
+#if !defined(LZO_DEBUG)
+#  define NDEBUG
+#endif
+#if defined(LZO_DEBUG) || !defined(NDEBUG)
+#  if !defined(NO_STDIO_H)
+#    include <stdio.h>
+#  endif
+#endif
+# if 0				/* edward */
+#include <assert.h>
+#endif				/* edward */
+
+#if !defined(LZO_COMPILE_TIME_ASSERT)
+#  define LZO_COMPILE_TIME_ASSERT(expr) \
+	{ typedef int __lzo_compile_time_assert_fail[1 - 2 * !(expr)]; }
+#endif
+
+#if !defined(LZO_UNUSED)
+#  if 1
+#    define LZO_UNUSED(var)     ((void)&var)
+#  elif 0
+#    define LZO_UNUSED(var)     { typedef int __lzo_unused[sizeof(var) ? 2 : 1]; }
+#  else
+#    define LZO_UNUSED(parm)    (parm = parm)
+#  endif
+#endif
+
+#if !defined(__inline__) && !defined(__GNUC__)
+#  if defined(__cplusplus)
+#    define __inline__      inline
+#  else
+#    define __inline__
+#  endif
+#endif
+
+#if defined(NO_MEMCMP)
+#  undef HAVE_MEMCMP
+#endif
+
+#if !defined(HAVE_MEMSET)
+#  undef memset
+#  define memset    lzo_memset
+#endif
+
+#  define LZO_BYTE(x)       ((unsigned char) ((x) & 0xff))
+
+#define LZO_MAX(a,b)        ((a) >= (b) ? (a) : (b))
+#define LZO_MIN(a,b)        ((a) <= (b) ? (a) : (b))
+#define LZO_MAX3(a,b,c)     ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c))
+#define LZO_MIN3(a,b,c)     ((a) <= (b) ? LZO_MIN(a,c) : LZO_MIN(b,c))
+
+#define lzo_sizeof(type)    ((lzo_uint) (sizeof(type)))
+
+#define LZO_HIGH(array)     ((lzo_uint) (sizeof(array)/sizeof(*(array))))
+
+#define LZO_SIZE(bits)      (1u << (bits))
+#define LZO_MASK(bits)      (LZO_SIZE(bits) - 1)
+
+#define LZO_LSIZE(bits)     (1ul << (bits))
+#define LZO_LMASK(bits)     (LZO_LSIZE(bits) - 1)
+
+#define LZO_USIZE(bits)     ((lzo_uint) 1 << (bits))
+#define LZO_UMASK(bits)     (LZO_USIZE(bits) - 1)
+
+#define LZO_STYPE_MAX(b)    (((1l  << (8*(b)-2)) - 1l)  + (1l  << (8*(b)-2)))
+#define LZO_UTYPE_MAX(b)    (((1ul << (8*(b)-1)) - 1ul) + (1ul << (8*(b)-1)))
+
+#if !defined(SIZEOF_UNSIGNED)
+#  if (UINT_MAX == 0xffff)
+#    define SIZEOF_UNSIGNED         2
+#  elif (UINT_MAX == LZO_0xffffffffL)
+#    define SIZEOF_UNSIGNED         4
+#  elif (UINT_MAX >= LZO_0xffffffffL)
+#    define SIZEOF_UNSIGNED         8
+#  else
+#    error "SIZEOF_UNSIGNED"
+#  endif
+#endif
+
+#if !defined(SIZEOF_UNSIGNED_LONG)
+#  if (ULONG_MAX == LZO_0xffffffffL)
+#    define SIZEOF_UNSIGNED_LONG    4
+#  elif (ULONG_MAX >= LZO_0xffffffffL)
+#    define SIZEOF_UNSIGNED_LONG    8
+#  else
+#    error "SIZEOF_UNSIGNED_LONG"
+#  endif
+#endif
+
+#if !defined(SIZEOF_SIZE_T)
+#  define SIZEOF_SIZE_T             SIZEOF_UNSIGNED
+#endif
+#if !defined(SIZE_T_MAX)
+#  define SIZE_T_MAX                LZO_UTYPE_MAX(SIZEOF_SIZE_T)
+#endif
+
+#if 1 && defined(__LZO_i386) && (UINT_MAX == LZO_0xffffffffL)
+#  if !defined(LZO_UNALIGNED_OK_2) && (USHRT_MAX == 0xffff)
+#    define LZO_UNALIGNED_OK_2
+#  endif
+#  if !defined(LZO_UNALIGNED_OK_4) && (LZO_UINT32_MAX == LZO_0xffffffffL)
+#    define LZO_UNALIGNED_OK_4
+#  endif
+#endif
+
+#if defined(LZO_UNALIGNED_OK_2) || defined(LZO_UNALIGNED_OK_4)
+#  if !defined(LZO_UNALIGNED_OK)
+#    define LZO_UNALIGNED_OK
+#  endif
+#endif
+
+#if defined(__LZO_NO_UNALIGNED)
+#  undef LZO_UNALIGNED_OK
+#  undef LZO_UNALIGNED_OK_2
+#  undef LZO_UNALIGNED_OK_4
+#endif
+
+#if defined(LZO_UNALIGNED_OK_2) && (USHRT_MAX != 0xffff)
+#  error "LZO_UNALIGNED_OK_2 must not be defined on this system"
+#endif
+#if defined(LZO_UNALIGNED_OK_4) && (LZO_UINT32_MAX != LZO_0xffffffffL)
+#  error "LZO_UNALIGNED_OK_4 must not be defined on this system"
+#endif
+
+#if defined(__LZO_NO_ALIGNED)
+#  undef LZO_ALIGNED_OK_4
+#endif
+
+#if defined(LZO_ALIGNED_OK_4) && (LZO_UINT32_MAX != LZO_0xffffffffL)
+#  error "LZO_ALIGNED_OK_4 must not be defined on this system"
+#endif
+
+#define LZO_LITTLE_ENDIAN       1234
+#define LZO_BIG_ENDIAN          4321
+#define LZO_PDP_ENDIAN          3412
+
+#if !defined(LZO_BYTE_ORDER)
+#  if defined(MFX_BYTE_ORDER)
+#    define LZO_BYTE_ORDER      MFX_BYTE_ORDER
+#  elif defined(__LZO_i386)
+#    define LZO_BYTE_ORDER      LZO_LITTLE_ENDIAN
+#  elif defined(BYTE_ORDER)
+#    define LZO_BYTE_ORDER      BYTE_ORDER
+#  elif defined(__BYTE_ORDER)
+#    define LZO_BYTE_ORDER      __BYTE_ORDER
+#  endif
+#endif
+
+#if defined(LZO_BYTE_ORDER)
+#  if (LZO_BYTE_ORDER != LZO_LITTLE_ENDIAN) && \
+      (LZO_BYTE_ORDER != LZO_BIG_ENDIAN)
+#    error "invalid LZO_BYTE_ORDER"
+#  endif
+#endif
+
+#if defined(LZO_UNALIGNED_OK) && !defined(LZO_BYTE_ORDER)
+#  error "LZO_BYTE_ORDER is not defined"
+#endif
+
+#define LZO_OPTIMIZE_GNUC_i386_IS_BUGGY
+
+#if defined(NDEBUG) && !defined(LZO_DEBUG) && !defined(__LZO_CHECKER)
+#  if defined(__GNUC__) && defined(__i386__)
+#    if !defined(LZO_OPTIMIZE_GNUC_i386_IS_BUGGY)
+#      define LZO_OPTIMIZE_GNUC_i386
+#    endif
+#  endif
+#endif
+
+__LZO_EXTERN_C const lzo_uint32 _lzo_crc32_table[256];
+
+#define _LZO_STRINGIZE(x)           #x
+#define _LZO_MEXPAND(x)             _LZO_STRINGIZE(x)
+
+#define _LZO_CONCAT2(a,b)           a ## b
+#define _LZO_CONCAT3(a,b,c)         a ## b ## c
+#define _LZO_CONCAT4(a,b,c,d)       a ## b ## c ## d
+#define _LZO_CONCAT5(a,b,c,d,e)     a ## b ## c ## d ## e
+
+#define _LZO_ECONCAT2(a,b)          _LZO_CONCAT2(a,b)
+#define _LZO_ECONCAT3(a,b,c)        _LZO_CONCAT3(a,b,c)
+#define _LZO_ECONCAT4(a,b,c,d)      _LZO_CONCAT4(a,b,c,d)
+#define _LZO_ECONCAT5(a,b,c,d,e)    _LZO_CONCAT5(a,b,c,d,e)
+
+#ifndef __LZO_PTR_H
+#define __LZO_PTR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+#  include <dos.h>
+#  if 1 && defined(__WATCOMC__)
+#    include <i86.h>
+	__LZO_EXTERN_C unsigned char _HShift;
+#    define __LZO_HShift    _HShift
+#  elif 1 && defined(_MSC_VER)
+	__LZO_EXTERN_C unsigned short __near _AHSHIFT;
+#    define __LZO_HShift    ((unsigned) &_AHSHIFT)
+#  elif defined(__LZO_WIN16)
+#    define __LZO_HShift    3
+#  else
+#    define __LZO_HShift    12
+#  endif
+#  if !defined(_FP_SEG) && defined(FP_SEG)
+#    define _FP_SEG         FP_SEG
+#  endif
+#  if !defined(_FP_OFF) && defined(FP_OFF)
+#    define _FP_OFF         FP_OFF
+#  endif
+#endif
+
+#if !defined(lzo_ptrdiff_t)
+#  if (UINT_MAX >= LZO_0xffffffffL)
+	typedef ptrdiff_t lzo_ptrdiff_t;
+#  else
+	typedef long lzo_ptrdiff_t;
+#  endif
+#endif
+
+#if !defined(__LZO_HAVE_PTR_T)
+#  if defined(lzo_ptr_t)
+#    define __LZO_HAVE_PTR_T
+#  endif
+#endif
+#if !defined(__LZO_HAVE_PTR_T)
+#  if defined(SIZEOF_CHAR_P) && defined(SIZEOF_UNSIGNED_LONG)
+#    if (SIZEOF_CHAR_P == SIZEOF_UNSIGNED_LONG)
+	typedef unsigned long lzo_ptr_t;
+	typedef long lzo_sptr_t;
+#      define __LZO_HAVE_PTR_T
+#    endif
+#  endif
+#endif
+#if !defined(__LZO_HAVE_PTR_T)
+#  if defined(SIZEOF_CHAR_P) && defined(SIZEOF_UNSIGNED)
+#    if (SIZEOF_CHAR_P == SIZEOF_UNSIGNED)
+	typedef unsigned int lzo_ptr_t;
+	typedef int lzo_sptr_t;
+#      define __LZO_HAVE_PTR_T
+#    endif
+#  endif
+#endif
+#if !defined(__LZO_HAVE_PTR_T)
+#  if defined(SIZEOF_CHAR_P) && defined(SIZEOF_UNSIGNED_SHORT)
+#    if (SIZEOF_CHAR_P == SIZEOF_UNSIGNED_SHORT)
+	typedef unsigned short lzo_ptr_t;
+	typedef short lzo_sptr_t;
+#      define __LZO_HAVE_PTR_T
+#    endif
+#  endif
+#endif
+#if !defined(__LZO_HAVE_PTR_T)
+#  if defined(LZO_HAVE_CONFIG_H) || defined(SIZEOF_CHAR_P)
+#    error "no suitable type for lzo_ptr_t"
+#  else
+	typedef unsigned long lzo_ptr_t;
+	typedef long lzo_sptr_t;
+#    define __LZO_HAVE_PTR_T
+#  endif
+#endif
+
+#if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+#define PTR(a)              ((lzo_bytep) (a))
+#define PTR_ALIGNED_4(a)    ((_FP_OFF(a) & 3) == 0)
+#define PTR_ALIGNED2_4(a,b) (((_FP_OFF(a) | _FP_OFF(b)) & 3) == 0)
+#else
+#define PTR(a)              ((lzo_ptr_t) (a))
+#define PTR_LINEAR(a)       PTR(a)
+#define PTR_ALIGNED_4(a)    ((PTR_LINEAR(a) & 3) == 0)
+#define PTR_ALIGNED_8(a)    ((PTR_LINEAR(a) & 7) == 0)
+#define PTR_ALIGNED2_4(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0)
+#define PTR_ALIGNED2_8(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0)
+#endif
+
+#define PTR_LT(a,b)         (PTR(a) < PTR(b))
+#define PTR_GE(a,b)         (PTR(a) >= PTR(b))
+#define PTR_DIFF(a,b)       ((lzo_ptrdiff_t) (PTR(a) - PTR(b)))
+#define pd(a,b)             ((lzo_uint) ((a)-(b)))
+
+	typedef union {
+		char a_char;
+		unsigned char a_uchar;
+		short a_short;
+		unsigned short a_ushort;
+		int a_int;
+		unsigned int a_uint;
+		long a_long;
+		unsigned long a_ulong;
+		lzo_int a_lzo_int;
+		lzo_uint a_lzo_uint;
+		lzo_int32 a_lzo_int32;
+		lzo_uint32 a_lzo_uint32;
+		ptrdiff_t a_ptrdiff_t;
+		lzo_ptrdiff_t a_lzo_ptrdiff_t;
+		lzo_ptr_t a_lzo_ptr_t;
+		lzo_voidp a_lzo_voidp;
+		void *a_void_p;
+		lzo_bytep a_lzo_bytep;
+		lzo_bytepp a_lzo_bytepp;
+		lzo_uintp a_lzo_uintp;
+		lzo_uint *a_lzo_uint_p;
+		lzo_uint32p a_lzo_uint32p;
+		lzo_uint32 *a_lzo_uint32_p;
+		unsigned char *a_uchar_p;
+		char *a_char_p;
+	} lzo_full_align_t;
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+#define LZO_DETERMINISTIC
+#define LZO_DICT_USE_PTR
+#if defined(__LZO_DOS16) || defined(__LZO_WIN16) || defined(__LZO_STRICT_16BIT)
+#  undef LZO_DICT_USE_PTR
+#endif
+#if defined(LZO_DICT_USE_PTR)
+#  define lzo_dict_t    const lzo_bytep
+#  define lzo_dict_p    lzo_dict_t __LZO_MMODEL *
+#else
+#  define lzo_dict_t    lzo_uint
+#  define lzo_dict_p    lzo_dict_t __LZO_MMODEL *
+#endif
+#if !defined(lzo_moff_t)
+#define lzo_moff_t      lzo_uint
+#endif
+#endif
+static lzo_ptr_t __lzo_ptr_linear(const lzo_voidp ptr)
+{
+	lzo_ptr_t p;
+
+#if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+	p = (((lzo_ptr_t) (_FP_SEG(ptr))) << (16 - __LZO_HShift)) +
+	    (_FP_OFF(ptr));
+#else
+	p = PTR_LINEAR(ptr);
+#endif
+
+	return p;
+}
+
+static unsigned __lzo_align_gap(const lzo_voidp ptr, lzo_uint size)
+{
+	lzo_ptr_t p, s, n;
+
+	assert("lzo-01", size > 0);
+
+	p = __lzo_ptr_linear(ptr);
+	s = (lzo_ptr_t) (size - 1);
+	n = (((p + s) / size) * size) - p;
+
+	assert("lzo-02", (long)n >= 0);
+	assert("lzo-03", n <= s);
+
+	return (unsigned)n;
+}
+
+#ifndef __LZO_UTIL_H
+#define __LZO_UTIL_H
+
+#ifndef __LZO_CONF_H
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if 1 && defined(HAVE_MEMCPY)
+#if !defined(__LZO_DOS16) && !defined(__LZO_WIN16)
+
+#define MEMCPY8_DS(dest,src,len) \
+    memcpy(dest,src,len); \
+    dest += len; \
+    src += len
+
+#endif
+#endif
+
+#if !defined(MEMCPY8_DS)
+
+#define MEMCPY8_DS(dest,src,len) \
+    { register lzo_uint __l = (len) / 8; \
+    do { \
+	*dest++ = *src++; \
+	*dest++ = *src++; \
+	*dest++ = *src++; \
+	*dest++ = *src++; \
+	*dest++ = *src++; \
+	*dest++ = *src++; \
+	*dest++ = *src++; \
+	*dest++ = *src++; \
+    } while (--__l > 0); }
+
+#endif
+
+#define MEMCPY_DS(dest,src,len) \
+    do *dest++ = *src++; \
+    while (--len > 0)
+
+#define MEMMOVE_DS(dest,src,len) \
+    do *dest++ = *src++; \
+    while (--len > 0)
+
+
+#if (LZO_UINT_MAX <= SIZE_T_MAX) && defined(HAVE_MEMSET)
+
+#define BZERO8_PTR(s,l,n)   memset((s),0,(lzo_uint)(l)*(n))
+
+#else
+
+#define BZERO8_PTR(s,l,n) \
+    lzo_memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n))
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* If you use the LZO library in a product, you *must* keep this
+ * copyright string in the executable of your product.
+ */
+
+static const lzo_byte __lzo_copyright[] =
+#if !defined(__LZO_IN_MINLZO)
+    LZO_VERSION_STRING;
+#else
+    "\n\n\n"
+    "LZO real-time data compression library.\n"
+    "Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 Markus Franz Xaver Johannes Oberhumer\n"
+    "<markus.oberhumer@jk.uni-linz.ac.at>\n"
+    "http://www.oberhumer.com/opensource/lzo/\n"
+    "\n"
+    "LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE "\n"
+    "LZO build date: " __DATE__ " " __TIME__ "\n\n"
+    "LZO special compilation options:\n"
+#ifdef __cplusplus
+    " __cplusplus\n"
+#endif
+#if defined(__PIC__)
+    " __PIC__\n"
+#elif defined(__pic__)
+    " __pic__\n"
+#endif
+#if (UINT_MAX < LZO_0xffffffffL)
+    " 16BIT\n"
+#endif
+#if defined(__LZO_STRICT_16BIT)
+    " __LZO_STRICT_16BIT\n"
+#endif
+#if (UINT_MAX > LZO_0xffffffffL)
+    " UINT_MAX=" _LZO_MEXPAND(UINT_MAX) "\n"
+#endif
+#if (ULONG_MAX > LZO_0xffffffffL)
+    " ULONG_MAX=" _LZO_MEXPAND(ULONG_MAX) "\n"
+#endif
+#if defined(LZO_BYTE_ORDER)
+    " LZO_BYTE_ORDER=" _LZO_MEXPAND(LZO_BYTE_ORDER) "\n"
+#endif
+#if defined(LZO_UNALIGNED_OK_2)
+    " LZO_UNALIGNED_OK_2\n"
+#endif
+#if defined(LZO_UNALIGNED_OK_4)
+    " LZO_UNALIGNED_OK_4\n"
+#endif
+#if defined(LZO_ALIGNED_OK_4)
+    " LZO_ALIGNED_OK_4\n"
+#endif
+#if defined(LZO_DICT_USE_PTR)
+    " LZO_DICT_USE_PTR\n"
+#endif
+#if defined(__LZO_QUERY_COMPRESS)
+    " __LZO_QUERY_COMPRESS\n"
+#endif
+#if defined(__LZO_QUERY_DECOMPRESS)
+    " __LZO_QUERY_DECOMPRESS\n"
+#endif
+#if defined(__LZO_IN_MINILZO)
+    " __LZO_IN_MINILZO\n"
+#endif
+    "\n\n" "$Id: LZO " LZO_VERSION_STRING " built " __DATE__ " " __TIME__
+#if defined(__GNUC__) && defined(__VERSION__)
+    " by gcc " __VERSION__
+#elif defined(__BORLANDC__)
+    " by Borland C " _LZO_MEXPAND(__BORLANDC__)
+#elif defined(_MSC_VER)
+    " by Microsoft C " _LZO_MEXPAND(_MSC_VER)
+#elif defined(__PUREC__)
+    " by Pure C " _LZO_MEXPAND(__PUREC__)
+#elif defined(__SC__)
+    " by Symantec C " _LZO_MEXPAND(__SC__)
+#elif defined(__TURBOC__)
+    " by Turbo C " _LZO_MEXPAND(__TURBOC__)
+#elif defined(__WATCOMC__)
+    " by Watcom C " _LZO_MEXPAND(__WATCOMC__)
+#endif
+    " $\n"
+    "$Copyright: LZO (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 Markus Franz Xaver Johannes Oberhumer $\n";
+#endif
+
+#define LZO_BASE 65521u
+#define LZO_NMAX 5552
+
+#define LZO_DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
+#define LZO_DO2(buf,i)  LZO_DO1(buf,i); LZO_DO1(buf,i+1);
+#define LZO_DO4(buf,i)  LZO_DO2(buf,i); LZO_DO2(buf,i+2);
+#define LZO_DO8(buf,i)  LZO_DO4(buf,i); LZO_DO4(buf,i+4);
+#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8);
+
+#  define IS_SIGNED(type)       (((type) (-1)) < ((type) 0))
+#  define IS_UNSIGNED(type)     (((type) (-1)) > ((type) 0))
+
+#define IS_POWER_OF_2(x)        (((x) & ((x) - 1)) == 0)
+
+static lzo_bool schedule_insns_bug(void);
+static lzo_bool strength_reduce_bug(int *);
+
+#  define __lzo_assert(x)   ((x) ? 1 : 0)
+
+#undef COMPILE_TIME_ASSERT
+
+#  define COMPILE_TIME_ASSERT(expr)     LZO_COMPILE_TIME_ASSERT(expr)
+
+static lzo_bool basic_integral_check(void)
+{
+	lzo_bool r = 1;
+
+	COMPILE_TIME_ASSERT(CHAR_BIT == 8);
+	COMPILE_TIME_ASSERT(sizeof(char) == 1);
+	COMPILE_TIME_ASSERT(sizeof(short) >= 2);
+	COMPILE_TIME_ASSERT(sizeof(long) >= 4);
+	COMPILE_TIME_ASSERT(sizeof(int) >= sizeof(short));
+	COMPILE_TIME_ASSERT(sizeof(long) >= sizeof(int));
+
+	COMPILE_TIME_ASSERT(sizeof(lzo_uint) == sizeof(lzo_int));
+	COMPILE_TIME_ASSERT(sizeof(lzo_uint32) == sizeof(lzo_int32));
+
+	COMPILE_TIME_ASSERT(sizeof(lzo_uint32) >= 4);
+	COMPILE_TIME_ASSERT(sizeof(lzo_uint32) >= sizeof(unsigned));
+#if defined(__LZO_STRICT_16BIT)
+	COMPILE_TIME_ASSERT(sizeof(lzo_uint) == 2);
+#else
+	COMPILE_TIME_ASSERT(sizeof(lzo_uint) >= 4);
+	COMPILE_TIME_ASSERT(sizeof(lzo_uint) >= sizeof(unsigned));
+#endif
+
+#if (USHRT_MAX == 65535u)
+	COMPILE_TIME_ASSERT(sizeof(short) == 2);
+#elif (USHRT_MAX == LZO_0xffffffffL)
+	COMPILE_TIME_ASSERT(sizeof(short) == 4);
+#elif (USHRT_MAX >= LZO_0xffffffffL)
+	COMPILE_TIME_ASSERT(sizeof(short) > 4);
+#endif
+#if 0				/* to make gcc happy -edward */
+#if (UINT_MAX == 65535u)
+	COMPILE_TIME_ASSERT(sizeof(int) == 2);
+#elif (UINT_MAX == LZO_0xffffffffL)
+	COMPILE_TIME_ASSERT(sizeof(int) == 4);
+#elif (UINT_MAX >= LZO_0xffffffffL)
+	COMPILE_TIME_ASSERT(sizeof(int) > 4);
+#endif
+#if (ULONG_MAX == 65535ul)
+	COMPILE_TIME_ASSERT(sizeof(long) == 2);
+#elif (ULONG_MAX == LZO_0xffffffffL)
+	COMPILE_TIME_ASSERT(sizeof(long) == 4);
+#elif (ULONG_MAX >= LZO_0xffffffffL)
+	COMPILE_TIME_ASSERT(sizeof(long) > 4);
+#endif
+#if defined(SIZEOF_UNSIGNED)
+	COMPILE_TIME_ASSERT(SIZEOF_UNSIGNED == sizeof(unsigned));
+#endif
+#if defined(SIZEOF_UNSIGNED_LONG)
+	COMPILE_TIME_ASSERT(SIZEOF_UNSIGNED_LONG == sizeof(unsigned long));
+#endif
+#if defined(SIZEOF_UNSIGNED_SHORT)
+	COMPILE_TIME_ASSERT(SIZEOF_UNSIGNED_SHORT == sizeof(unsigned short));
+#endif
+#if !defined(__LZO_IN_MINILZO)
+#if defined(SIZEOF_SIZE_T)
+	COMPILE_TIME_ASSERT(SIZEOF_SIZE_T == sizeof(size_t));
+#endif
+#endif
+#endif				/* -edward */
+
+	COMPILE_TIME_ASSERT(IS_UNSIGNED(unsigned char));
+	COMPILE_TIME_ASSERT(IS_UNSIGNED(unsigned short));
+	COMPILE_TIME_ASSERT(IS_UNSIGNED(unsigned));
+	COMPILE_TIME_ASSERT(IS_UNSIGNED(unsigned long));
+	COMPILE_TIME_ASSERT(IS_SIGNED(short));
+	COMPILE_TIME_ASSERT(IS_SIGNED(int));
+	COMPILE_TIME_ASSERT(IS_SIGNED(long));
+
+	COMPILE_TIME_ASSERT(IS_UNSIGNED(lzo_uint32));
+	COMPILE_TIME_ASSERT(IS_UNSIGNED(lzo_uint));
+	COMPILE_TIME_ASSERT(IS_SIGNED(lzo_int32));
+	COMPILE_TIME_ASSERT(IS_SIGNED(lzo_int));
+
+	COMPILE_TIME_ASSERT(INT_MAX == LZO_STYPE_MAX(sizeof(int)));
+	COMPILE_TIME_ASSERT(UINT_MAX == LZO_UTYPE_MAX(sizeof(unsigned)));
+	COMPILE_TIME_ASSERT(LONG_MAX == LZO_STYPE_MAX(sizeof(long)));
+	COMPILE_TIME_ASSERT(ULONG_MAX == LZO_UTYPE_MAX(sizeof(unsigned long)));
+	//    COMPILE_TIME_ASSERT(SHRT_MAX   == LZO_STYPE_MAX(sizeof(short))); /* edward */
+	COMPILE_TIME_ASSERT(USHRT_MAX == LZO_UTYPE_MAX(sizeof(unsigned short)));
+	COMPILE_TIME_ASSERT(LZO_UINT32_MAX ==
+			    LZO_UTYPE_MAX(sizeof(lzo_uint32)));
+	COMPILE_TIME_ASSERT(LZO_UINT_MAX == LZO_UTYPE_MAX(sizeof(lzo_uint)));
+#if !defined(__LZO_IN_MINILZO)
+	COMPILE_TIME_ASSERT(SIZE_T_MAX == LZO_UTYPE_MAX(sizeof(size_t)));
+#endif
+
+	r &= __lzo_assert(LZO_BYTE(257) == 1);
+
+	return r;
+}
+
+static lzo_bool basic_ptr_check(void)
+{
+	lzo_bool r = 1;
+
+	COMPILE_TIME_ASSERT(sizeof(char *) >= sizeof(int));
+	COMPILE_TIME_ASSERT(sizeof(lzo_byte *) >= sizeof(char *));
+
+	COMPILE_TIME_ASSERT(sizeof(lzo_voidp) == sizeof(lzo_byte *));
+	COMPILE_TIME_ASSERT(sizeof(lzo_voidp) == sizeof(lzo_voidpp));
+	COMPILE_TIME_ASSERT(sizeof(lzo_voidp) == sizeof(lzo_bytepp));
+	COMPILE_TIME_ASSERT(sizeof(lzo_voidp) >= sizeof(lzo_uint));
+
+	COMPILE_TIME_ASSERT(sizeof(lzo_ptr_t) == sizeof(lzo_voidp));
+	COMPILE_TIME_ASSERT(sizeof(lzo_ptr_t) == sizeof(lzo_sptr_t));
+	COMPILE_TIME_ASSERT(sizeof(lzo_ptr_t) >= sizeof(lzo_uint));
+
+	COMPILE_TIME_ASSERT(sizeof(lzo_ptrdiff_t) >= 4);
+	COMPILE_TIME_ASSERT(sizeof(lzo_ptrdiff_t) >= sizeof(ptrdiff_t));
+
+	COMPILE_TIME_ASSERT(sizeof(ptrdiff_t) >= sizeof(size_t));
+	COMPILE_TIME_ASSERT(sizeof(lzo_ptrdiff_t) >= sizeof(lzo_uint));
+
+#if defined(SIZEOF_CHAR_P)
+	COMPILE_TIME_ASSERT(SIZEOF_CHAR_P == sizeof(char *));
+#endif
+#if defined(SIZEOF_PTRDIFF_T)
+	COMPILE_TIME_ASSERT(SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t));
+#endif
+
+	COMPILE_TIME_ASSERT(IS_SIGNED(ptrdiff_t));
+	COMPILE_TIME_ASSERT(IS_UNSIGNED(size_t));
+	COMPILE_TIME_ASSERT(IS_SIGNED(lzo_ptrdiff_t));
+	COMPILE_TIME_ASSERT(IS_SIGNED(lzo_sptr_t));
+	COMPILE_TIME_ASSERT(IS_UNSIGNED(lzo_ptr_t));
+	COMPILE_TIME_ASSERT(IS_UNSIGNED(lzo_moff_t));
+
+	return r;
+}
+
+static lzo_bool ptr_check(void)
+{
+	lzo_bool r = 1;
+	int i;
+	char _wrkmem[10 * sizeof(lzo_byte *) + sizeof(lzo_full_align_t)];
+	lzo_bytep wrkmem;
+	lzo_bytepp dict;
+	unsigned char x[4 * sizeof(lzo_full_align_t)];
+	long d;
+	lzo_full_align_t a;
+	lzo_full_align_t u;
+
+	for (i = 0; i < (int)sizeof(x); i++)
+		x[i] = LZO_BYTE(i);
+
+	wrkmem =
+	    LZO_PTR_ALIGN_UP((lzo_byte *) _wrkmem, sizeof(lzo_full_align_t));
+
+	u.a_lzo_bytep = wrkmem;
+	dict = u.a_lzo_bytepp;
+
+	d = (long)((const lzo_bytep)dict - (const lzo_bytep)_wrkmem);
+	r &= __lzo_assert(d >= 0);
+	r &= __lzo_assert(d < (long)sizeof(lzo_full_align_t));
+
+	memset(&a, 0, sizeof(a));
+	r &= __lzo_assert(a.a_lzo_voidp == NULL);
+
+	memset(&a, 0xff, sizeof(a));
+	r &= __lzo_assert(a.a_ushort == USHRT_MAX);
+	r &= __lzo_assert(a.a_uint == UINT_MAX);
+	r &= __lzo_assert(a.a_ulong == ULONG_MAX);
+	r &= __lzo_assert(a.a_lzo_uint == LZO_UINT_MAX);
+	r &= __lzo_assert(a.a_lzo_uint32 == LZO_UINT32_MAX);
+
+	if (r == 1) {
+		for (i = 0; i < 8; i++)
+			r &= __lzo_assert((const lzo_voidp)(&dict[i]) ==
+					  (const
+					   lzo_voidp)(&wrkmem[i *
+							      sizeof(lzo_byte
+								     *)]));
+	}
+
+	memset(&a, 0, sizeof(a));
+	r &= __lzo_assert(a.a_char_p == NULL);
+	r &= __lzo_assert(a.a_lzo_bytep == NULL);
+	r &= __lzo_assert(NULL == (void *)0);
+	if (r == 1) {
+		for (i = 0; i < 10; i++)
+			dict[i] = wrkmem;
+		BZERO8_PTR(dict + 1, sizeof(dict[0]), 8);
+		r &= __lzo_assert(dict[0] == wrkmem);
+		for (i = 1; i < 9; i++)
+			r &= __lzo_assert(dict[i] == NULL);
+		r &= __lzo_assert(dict[9] == wrkmem);
+	}
+
+	if (r == 1) {
+		unsigned k = 1;
+		const unsigned n = (unsigned)sizeof(lzo_uint32);
+		lzo_byte *p0;
+		lzo_byte *p1;
+
+		k += __lzo_align_gap(&x[k], n);
+		p0 = (lzo_bytep) & x[k];
+#if defined(PTR_LINEAR)
+		r &= __lzo_assert((PTR_LINEAR(p0) & (n - 1)) == 0);
+#else
+		r &= __lzo_assert(n == 4);
+		r &= __lzo_assert(PTR_ALIGNED_4(p0));
+#endif
+
+		r &= __lzo_assert(k >= 1);
+		p1 = (lzo_bytep) & x[1];
+		r &= __lzo_assert(PTR_GE(p0, p1));
+
+		r &= __lzo_assert(k < 1 + n);
+		p1 = (lzo_bytep) & x[1 + n];
+		r &= __lzo_assert(PTR_LT(p0, p1));
+
+		if (r == 1) {
+			lzo_uint32 v0, v1;
+
+			u.a_uchar_p = &x[k];
+			v0 = *u.a_lzo_uint32_p;
+			u.a_uchar_p = &x[k + n];
+			v1 = *u.a_lzo_uint32_p;
+
+			r &= __lzo_assert(v0 > 0);
+			r &= __lzo_assert(v1 > 0);
+		}
+	}
+
+	return r;
+}
+
+static int _lzo_config_check(void)
+{
+	lzo_bool r = 1;
+	int i;
+	union {
+		lzo_uint32 a;
+		unsigned short b;
+		lzo_uint32 aa[4];
+		unsigned char x[4 * sizeof(lzo_full_align_t)];
+	}
+	u;
+
+	COMPILE_TIME_ASSERT((int)((unsigned char)((signed char)-1)) == 255);
+	COMPILE_TIME_ASSERT((((unsigned char)128) << (int)(8 * sizeof(int) - 8))
+			    < 0);
+
+	r &= basic_integral_check();
+	r &= basic_ptr_check();
+	if (r != 1)
+		return LZO_E_ERROR;
+
+	u.a = 0;
+	u.b = 0;
+	for (i = 0; i < (int)sizeof(u.x); i++)
+		u.x[i] = LZO_BYTE(i);
+
+#if defined(LZO_BYTE_ORDER)
+	if (r == 1) {
+#  if (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+		lzo_uint32 a = (lzo_uint32) (u.a & LZO_0xffffffffL);
+		unsigned short b = (unsigned short)(u.b & 0xffff);
+		r &= __lzo_assert(a == 0x03020100L);
+		r &= __lzo_assert(b == 0x0100);
+#  elif (LZO_BYTE_ORDER == LZO_BIG_ENDIAN)
+		lzo_uint32 a = u.a >> (8 * sizeof(u.a) - 32);
+		unsigned short b = u.b >> (8 * sizeof(u.b) - 16);
+		r &= __lzo_assert(a == 0x00010203L);
+		r &= __lzo_assert(b == 0x0001);
+#  else
+#    error "invalid LZO_BYTE_ORDER"
+#  endif
+	}
+#endif
+
+#if defined(LZO_UNALIGNED_OK_2)
+	COMPILE_TIME_ASSERT(sizeof(short) == 2);
+	if (r == 1) {
+		unsigned short b[4];
+
+		for (i = 0; i < 4; i++)
+			b[i] = *(const unsigned short *)&u.x[i];
+
+#  if (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+		r &= __lzo_assert(b[0] == 0x0100);
+		r &= __lzo_assert(b[1] == 0x0201);
+		r &= __lzo_assert(b[2] == 0x0302);
+		r &= __lzo_assert(b[3] == 0x0403);
+#  elif (LZO_BYTE_ORDER == LZO_BIG_ENDIAN)
+		r &= __lzo_assert(b[0] == 0x0001);
+		r &= __lzo_assert(b[1] == 0x0102);
+		r &= __lzo_assert(b[2] == 0x0203);
+		r &= __lzo_assert(b[3] == 0x0304);
+#  endif
+	}
+#endif
+
+#if defined(LZO_UNALIGNED_OK_4)
+	COMPILE_TIME_ASSERT(sizeof(lzo_uint32) == 4);
+	if (r == 1) {
+		lzo_uint32 a[4];
+
+		for (i = 0; i < 4; i++)
+			a[i] = *(const lzo_uint32 *)&u.x[i];
+
+#  if (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+		r &= __lzo_assert(a[0] == 0x03020100L);
+		r &= __lzo_assert(a[1] == 0x04030201L);
+		r &= __lzo_assert(a[2] == 0x05040302L);
+		r &= __lzo_assert(a[3] == 0x06050403L);
+#  elif (LZO_BYTE_ORDER == LZO_BIG_ENDIAN)
+		r &= __lzo_assert(a[0] == 0x00010203L);
+		r &= __lzo_assert(a[1] == 0x01020304L);
+		r &= __lzo_assert(a[2] == 0x02030405L);
+		r &= __lzo_assert(a[3] == 0x03040506L);
+#  endif
+	}
+#endif
+
+#if defined(LZO_ALIGNED_OK_4)
+	COMPILE_TIME_ASSERT(sizeof(lzo_uint32) == 4);
+#endif
+
+	COMPILE_TIME_ASSERT(lzo_sizeof_dict_t == sizeof(lzo_dict_t));
+
+	if (r == 1) {
+		r &= __lzo_assert(!schedule_insns_bug());
+	}
+
+	if (r == 1) {
+		static int x[3];
+		static unsigned xn = 3;
+		register unsigned j;
+
+		for (j = 0; j < xn; j++)
+			x[j] = (int)j - 3;
+		r &= __lzo_assert(!strength_reduce_bug(x));
+	}
+
+	if (r == 1) {
+		r &= ptr_check();
+	}
+
+	return r == 1 ? LZO_E_OK : LZO_E_ERROR;
+}
+
+static lzo_bool schedule_insns_bug(void)
+{
+#if defined(__LZO_CHECKER)
+	return 0;
+#else
+	const int clone[] = { 1, 2, 0 };
+	const int *q;
+	q = clone;
+	return (*q) ? 0 : 1;
+#endif
+}
+
+static lzo_bool strength_reduce_bug(int *x)
+{
+	return x[0] != -3 || x[1] != -2 || x[2] != -1;
+}
+
+#undef COMPILE_TIME_ASSERT
+
+LZO_PUBLIC(int)
+    __lzo_init2(unsigned v, int s1, int s2, int s3, int s4, int s5,
+	    int s6, int s7, int s8, int s9)
+{
+	int r;
+
+	if (v == 0)
+		return LZO_E_ERROR;
+
+	r = (s1 == -1 || s1 == (int)sizeof(short)) &&
+	    (s2 == -1 || s2 == (int)sizeof(int)) &&
+	    (s3 == -1 || s3 == (int)sizeof(long)) &&
+	    (s4 == -1 || s4 == (int)sizeof(lzo_uint32)) &&
+	    (s5 == -1 || s5 == (int)sizeof(lzo_uint)) &&
+	    (s6 == -1 || s6 == (int)lzo_sizeof_dict_t) &&
+	    (s7 == -1 || s7 == (int)sizeof(char *)) &&
+	    (s8 == -1 || s8 == (int)sizeof(lzo_voidp)) &&
+	    (s9 == -1 || s9 == (int)sizeof(lzo_compress_t));
+	if (!r)
+		return LZO_E_ERROR;
+
+	r = _lzo_config_check();
+	if (r != LZO_E_OK)
+		return r;
+
+	return r;
+}
+
+#if !defined(__LZO_IN_MINILZO)
+
+LZO_EXTERN(int)
+    __lzo_init(unsigned v, int s1, int s2, int s3, int s4, int s5, int s6, int s7);
+
+LZO_PUBLIC(int)
+__lzo_init(unsigned v, int s1, int s2, int s3, int s4, int s5, int s6, int s7)
+{
+	if (v == 0 || v > 0x1010)
+		return LZO_E_ERROR;
+	return __lzo_init2(v, s1, s2, s3, s4, s5, -1, -1, s6, s7);
+}
+
+#endif
+
+#define do_compress         _lzo1x_1_do_compress
+
+#define LZO_NEED_DICT_H
+#define D_BITS          14
+#define D_INDEX1(d,p)       d = DM((0x21*DX3(p,5,5,6)) >> 5)
+#define D_INDEX2(d,p)       d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
+
+#ifndef __LZO_CONFIG1X_H
+#define __LZO_CONFIG1X_H
+
+#if !defined(LZO1X) && !defined(LZO1Y) && !defined(LZO1Z)
+#  define LZO1X
+#endif
+
+#if !defined(__LZO_IN_MINILZO)
+#include <lzo1x.h>
+#endif
+
+#define LZO_EOF_CODE
+#undef LZO_DETERMINISTIC
+
+#define M1_MAX_OFFSET   0x0400
+#ifndef M2_MAX_OFFSET
+#define M2_MAX_OFFSET   0x0800
+#endif
+#define M3_MAX_OFFSET   0x4000
+#define M4_MAX_OFFSET   0xbfff
+
+#define MX_MAX_OFFSET   (M1_MAX_OFFSET + M2_MAX_OFFSET)
+
+#define M1_MIN_LEN      2
+#define M1_MAX_LEN      2
+#define M2_MIN_LEN      3
+#ifndef M2_MAX_LEN
+#define M2_MAX_LEN      8
+#endif
+#define M3_MIN_LEN      3
+#define M3_MAX_LEN      33
+#define M4_MIN_LEN      3
+#define M4_MAX_LEN      9
+
+#define M1_MARKER       0
+#define M2_MARKER       64
+#define M3_MARKER       32
+#define M4_MARKER       16
+
+#ifndef MIN_LOOKAHEAD
+#define MIN_LOOKAHEAD       (M2_MAX_LEN + 1)
+#endif
+
+#if defined(LZO_NEED_DICT_H)
+
+#ifndef LZO_HASH
+#define LZO_HASH            LZO_HASH_LZO_INCREMENTAL_B
+#endif
+#define DL_MIN_LEN          M2_MIN_LEN
+
+#ifndef __LZO_DICT_H
+#define __LZO_DICT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(D_BITS) && defined(DBITS)
+#  define D_BITS        DBITS
+#endif
+#if !defined(D_BITS)
+#  error "D_BITS is not defined"
+#endif
+#if (D_BITS < 16)
+#  define D_SIZE        LZO_SIZE(D_BITS)
+#  define D_MASK        LZO_MASK(D_BITS)
+#else
+#  define D_SIZE        LZO_USIZE(D_BITS)
+#  define D_MASK        LZO_UMASK(D_BITS)
+#endif
+#define D_HIGH          ((D_MASK >> 1) + 1)
+
+#if !defined(DD_BITS)
+#  define DD_BITS       0
+#endif
+#define DD_SIZE         LZO_SIZE(DD_BITS)
+#define DD_MASK         LZO_MASK(DD_BITS)
+
+#if !defined(DL_BITS)
+#  define DL_BITS       (D_BITS - DD_BITS)
+#endif
+#if (DL_BITS < 16)
+#  define DL_SIZE       LZO_SIZE(DL_BITS)
+#  define DL_MASK       LZO_MASK(DL_BITS)
+#else
+#  define DL_SIZE       LZO_USIZE(DL_BITS)
+#  define DL_MASK       LZO_UMASK(DL_BITS)
+#endif
+
+#if (D_BITS != DL_BITS + DD_BITS)
+#  error "D_BITS does not match"
+#endif
+#if (D_BITS < 8 || D_BITS > 18)
+#  error "invalid D_BITS"
+#endif
+#if (DL_BITS < 8 || DL_BITS > 20)
+#  error "invalid DL_BITS"
+#endif
+#if (DD_BITS < 0 || DD_BITS > 6)
+#  error "invalid DD_BITS"
+#endif
+
+#if !defined(DL_MIN_LEN)
+#  define DL_MIN_LEN    3
+#endif
+#if !defined(DL_SHIFT)
+#  define DL_SHIFT      ((DL_BITS + (DL_MIN_LEN - 1)) / DL_MIN_LEN)
+#endif
+
+#define LZO_HASH_GZIP                   1
+#define LZO_HASH_GZIP_INCREMENTAL       2
+#define LZO_HASH_LZO_INCREMENTAL_A      3
+#define LZO_HASH_LZO_INCREMENTAL_B      4
+
+#if !defined(LZO_HASH)
+#  error "choose a hashing strategy"
+#endif
+
+#if (DL_MIN_LEN == 3)
+#  define _DV2_A(p,shift1,shift2) \
+	(((( (lzo_uint32)((p)[0]) << shift1) ^ (p)[1]) << shift2) ^ (p)[2])
+#  define _DV2_B(p,shift1,shift2) \
+	(((( (lzo_uint32)((p)[2]) << shift1) ^ (p)[1]) << shift2) ^ (p)[0])
+#  define _DV3_B(p,shift1,shift2,shift3) \
+	((_DV2_B((p)+1,shift1,shift2) << (shift3)) ^ (p)[0])
+#elif (DL_MIN_LEN == 2)
+#  define _DV2_A(p,shift1,shift2) \
+	(( (lzo_uint32)(p[0]) << shift1) ^ p[1])
+#  define _DV2_B(p,shift1,shift2) \
+	(( (lzo_uint32)(p[1]) << shift1) ^ p[2])
+#else
+#  error "invalid DL_MIN_LEN"
+#endif
+#define _DV_A(p,shift)      _DV2_A(p,shift,shift)
+#define _DV_B(p,shift)      _DV2_B(p,shift,shift)
+#define DA2(p,s1,s2) \
+	(((((lzo_uint32)((p)[2]) << (s2)) + (p)[1]) << (s1)) + (p)[0])
+#define DS2(p,s1,s2) \
+	(((((lzo_uint32)((p)[2]) << (s2)) - (p)[1]) << (s1)) - (p)[0])
+#define DX2(p,s1,s2) \
+	(((((lzo_uint32)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0])
+#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0])
+#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0])
+#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0])
+#define DMS(v,s)        ((lzo_uint) (((v) & (D_MASK >> (s))) << (s)))
+#define DM(v)           DMS(v,0)
+
+#if (LZO_HASH == LZO_HASH_GZIP)
+#  define _DINDEX(dv,p)     (_DV_A((p),DL_SHIFT))
+
+#elif (LZO_HASH == LZO_HASH_GZIP_INCREMENTAL)
+#  define __LZO_HASH_INCREMENTAL
+#  define DVAL_FIRST(dv,p)  dv = _DV_A((p),DL_SHIFT)
+#  define DVAL_NEXT(dv,p)   dv = (((dv) << DL_SHIFT) ^ p[2])
+#  define _DINDEX(dv,p)     (dv)
+#  define DVAL_LOOKAHEAD    DL_MIN_LEN
+
+#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_A)
+#  define __LZO_HASH_INCREMENTAL
+#  define DVAL_FIRST(dv,p)  dv = _DV_A((p),5)
+#  define DVAL_NEXT(dv,p) \
+		dv ^= (lzo_uint32)(p[-1]) << (2*5); dv = (((dv) << 5) ^ p[2])
+#  define _DINDEX(dv,p)     ((0x9f5f * (dv)) >> 5)
+#  define DVAL_LOOKAHEAD    DL_MIN_LEN
+
+#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_B)
+#  define __LZO_HASH_INCREMENTAL
+#  define DVAL_FIRST(dv,p)  dv = _DV_B((p),5)
+#  define DVAL_NEXT(dv,p) \
+		dv ^= p[-1]; dv = (((dv) >> 5) ^ ((lzo_uint32)(p[2]) << (2*5)))
+#  define _DINDEX(dv,p)     ((0x9f5f * (dv)) >> 5)
+#  define DVAL_LOOKAHEAD    DL_MIN_LEN
+
+#else
+#  error "choose a hashing strategy"
+#endif
+
+#ifndef DINDEX
+#define DINDEX(dv,p)        ((lzo_uint)((_DINDEX(dv,p)) & DL_MASK) << DD_BITS)
+#endif
+#if !defined(DINDEX1) && defined(D_INDEX1)
+#define DINDEX1             D_INDEX1
+#endif
+#if !defined(DINDEX2) && defined(D_INDEX2)
+#define DINDEX2             D_INDEX2
+#endif
+
+#if !defined(__LZO_HASH_INCREMENTAL)
+#  define DVAL_FIRST(dv,p)  ((void) 0)
+#  define DVAL_NEXT(dv,p)   ((void) 0)
+#  define DVAL_LOOKAHEAD    0
+#endif
+
+#if !defined(DVAL_ASSERT)
+#if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG)
+	static void DVAL_ASSERT(lzo_uint32 dv, const lzo_byte * p) {
+		lzo_uint32 df;
+		 DVAL_FIRST(df, (p));
+		 assert(DINDEX(dv, p) == DINDEX(df, p));
+	}
+#else
+#  define DVAL_ASSERT(dv,p) ((void) 0)
+#endif
+#endif
+
+#if defined(LZO_DICT_USE_PTR)
+#  define DENTRY(p,in)                          (p)
+#  define GINDEX(m_pos,m_off,dict,dindex,in)    m_pos = dict[dindex]
+#else
+#  define DENTRY(p,in)                          ((lzo_uint) ((p)-(in)))
+#  define GINDEX(m_pos,m_off,dict,dindex,in)    m_off = dict[dindex]
+#endif
+
+#if (DD_BITS == 0)
+
+#  define UPDATE_D(dict,drun,dv,p,in)       dict[ DINDEX(dv,p) ] = DENTRY(p,in)
+#  define UPDATE_I(dict,drun,index,p,in)    dict[index] = DENTRY(p,in)
+#  define UPDATE_P(ptr,drun,p,in)           (ptr)[0] = DENTRY(p,in)
+
+#else
+
+#  define UPDATE_D(dict,drun,dv,p,in)   \
+	dict[ DINDEX(dv,p) + drun++ ] = DENTRY(p,in); drun &= DD_MASK
+#  define UPDATE_I(dict,drun,index,p,in)    \
+	dict[ (index) + drun++ ] = DENTRY(p,in); drun &= DD_MASK
+#  define UPDATE_P(ptr,drun,p,in)   \
+	(ptr) [ drun++ ] = DENTRY(p,in); drun &= DD_MASK
+
+#endif
+
+#if defined(LZO_DICT_USE_PTR)
+
+#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \
+	(m_pos == NULL || (m_off = (lzo_moff_t) (ip - m_pos)) > max_offset)
+
+#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
+    (BOUNDS_CHECKING_OFF_IN_EXPR( \
+	(PTR_LT(m_pos,in) || \
+	 (m_off = (lzo_moff_t) PTR_DIFF(ip,m_pos)) <= 0 || \
+	  m_off > max_offset) ))
+
+#else
+
+#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \
+	(m_off == 0 || \
+	 ((m_off = (lzo_moff_t) ((ip)-(in)) - m_off) > max_offset) || \
+	 (m_pos = (ip) - (m_off), 0) )
+
+#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
+	((lzo_moff_t) ((ip)-(in)) <= m_off || \
+	 ((m_off = (lzo_moff_t) ((ip)-(in)) - m_off) > max_offset) || \
+	 (m_pos = (ip) - (m_off), 0) )
+
+#endif
+
+#if defined(LZO_DETERMINISTIC)
+#  define LZO_CHECK_MPOS    LZO_CHECK_MPOS_DET
+#else
+#  define LZO_CHECK_MPOS    LZO_CHECK_MPOS_NON_DET
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+#endif
+#endif
+#define DO_COMPRESS     lzo1x_1_compress
+static
+lzo_uint do_compress(const lzo_byte * in, lzo_uint in_len,
+		     lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem)
+{
+	register const lzo_byte *ip;
+	lzo_byte *op;
+	const lzo_byte *const in_end = in + in_len;
+	const lzo_byte *const ip_end = in + in_len - M2_MAX_LEN - 5;
+	const lzo_byte *ii;
+	lzo_dict_p const dict = (lzo_dict_p) wrkmem;
+
+	op = out;
+	ip = in;
+	ii = ip;
+
+	ip += 4;
+	for (;;) {
+		register const lzo_byte *m_pos;
+
+		lzo_moff_t m_off;
+		lzo_uint m_len;
+		lzo_uint dindex;
+
+		DINDEX1(dindex, ip);
+		GINDEX(m_pos, m_off, dict, dindex, in);
+		if (LZO_CHECK_MPOS_NON_DET(m_pos, m_off, in, ip, M4_MAX_OFFSET))
+			goto literal;
+#if 1
+		if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+			goto try_match;
+		DINDEX2(dindex, ip);
+#endif
+		GINDEX(m_pos, m_off, dict, dindex, in);
+		if (LZO_CHECK_MPOS_NON_DET(m_pos, m_off, in, ip, M4_MAX_OFFSET))
+			goto literal;
+		if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+			goto try_match;
+		goto literal;
+
+	      try_match:
+#if 1 && defined(LZO_UNALIGNED_OK_2)
+		if (*(const lzo_ushortp)m_pos != *(const lzo_ushortp)ip) {
+#else
+		if (m_pos[0] != ip[0] || m_pos[1] != ip[1]) {
+#endif
+			;
+		} else {
+			if (m_pos[2] == ip[2]) {
+				goto match;
+			} else {
+				;
+			}
+		}
+
+	      literal:
+		UPDATE_I(dict, 0, dindex, ip, in);
+		++ip;
+		if (ip >= ip_end)
+			break;
+		continue;
+
+	      match:
+		UPDATE_I(dict, 0, dindex, ip, in);
+		if (pd(ip, ii) > 0) {
+			register lzo_uint t = pd(ip, ii);
+
+			if (t <= 3) {
+				assert("lzo-04", op - 2 > out);
+				op[-2] |= LZO_BYTE(t);
+			} else if (t <= 18)
+				*op++ = LZO_BYTE(t - 3);
+			else {
+				register lzo_uint tt = t - 18;
+
+				*op++ = 0;
+				while (tt > 255) {
+					tt -= 255;
+					*op++ = 0;
+				}
+				assert("lzo-05", tt > 0);
+				*op++ = LZO_BYTE(tt);
+			}
+			do
+				*op++ = *ii++;
+			while (--t > 0);
+		}
+
+		assert("lzo-06", ii == ip);
+		ip += 3;
+		if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++
+		    || m_pos[6] != *ip++ || m_pos[7] != *ip++
+		    || m_pos[8] != *ip++
+#ifdef LZO1Y
+		    || m_pos[9] != *ip++ || m_pos[10] != *ip++
+		    || m_pos[11] != *ip++ || m_pos[12] != *ip++
+		    || m_pos[13] != *ip++ || m_pos[14] != *ip++
+#endif
+		    ) {
+			--ip;
+			m_len = ip - ii;
+			assert("lzo-07", m_len >= 3);
+			assert("lzo-08", m_len <= M2_MAX_LEN);
+
+			if (m_off <= M2_MAX_OFFSET) {
+				m_off -= 1;
+#if defined(LZO1X)
+				*op++ =
+				    LZO_BYTE(((m_len -
+					       1) << 5) | ((m_off & 7) << 2));
+				*op++ = LZO_BYTE(m_off >> 3);
+#elif defined(LZO1Y)
+				*op++ =
+				    LZO_BYTE(((m_len +
+					       1) << 4) | ((m_off & 3) << 2));
+				*op++ = LZO_BYTE(m_off >> 2);
+#endif
+			} else if (m_off <= M3_MAX_OFFSET) {
+				m_off -= 1;
+				*op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
+				goto m3_m4_offset;
+			} else
+#if defined(LZO1X)
+			{
+				m_off -= 0x4000;
+				assert("lzo-09", m_off > 0);
+				assert("lzo-10", m_off <= 0x7fff);
+				*op++ = LZO_BYTE(M4_MARKER |
+						 ((m_off & 0x4000) >> 11) |
+						 (m_len - 2));
+				goto m3_m4_offset;
+			}
+#elif defined(LZO1Y)
+				goto m4_match;
+#endif
+		} else {
+			{
+				const lzo_byte *end = in_end;
+				const lzo_byte *m = m_pos + M2_MAX_LEN + 1;
+				while (ip < end && *m == *ip)
+					m++, ip++;
+				m_len = (ip - ii);
+			}
+			assert("lzo-11", m_len > M2_MAX_LEN);
+
+			if (m_off <= M3_MAX_OFFSET) {
+				m_off -= 1;
+				if (m_len <= 33)
+					*op++ =
+					    LZO_BYTE(M3_MARKER | (m_len - 2));
+				else {
+					m_len -= 33;
+					*op++ = M3_MARKER | 0;
+					goto m3_m4_len;
+				}
+			} else {
+#if defined(LZO1Y)
+			      m4_match:
+#endif
+				m_off -= 0x4000;
+				assert("lzo-12", m_off > 0);
+				assert("lzo-13", m_off <= 0x7fff);
+				if (m_len <= M4_MAX_LEN)
+					*op++ = LZO_BYTE(M4_MARKER |
+							 ((m_off & 0x4000) >>
+							  11) | (m_len - 2));
+				else {
+					m_len -= M4_MAX_LEN;
+					*op++ =
+					    LZO_BYTE(M4_MARKER |
+						     ((m_off & 0x4000) >> 11));
+				      m3_m4_len:
+					while (m_len > 255) {
+						m_len -= 255;
+						*op++ = 0;
+					}
+					assert("lzo-14", m_len > 0);
+					*op++ = LZO_BYTE(m_len);
+				}
+			}
+
+		      m3_m4_offset:
+			*op++ = LZO_BYTE((m_off & 63) << 2);
+			*op++ = LZO_BYTE(m_off >> 6);
+		}
+
+		ii = ip;
+		if (ip >= ip_end)
+			break;
+	}
+
+	*out_len = op - out;
+	return pd(in_end, ii);
+}
+
+LZO_PUBLIC(int)
+    DO_COMPRESS(const lzo_byte * in, lzo_uint in_len,
+	    lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem)
+{
+	lzo_byte *op = out;
+	lzo_uint t;
+
+#if defined(__LZO_QUERY_COMPRESS)
+	if (__LZO_IS_COMPRESS_QUERY(in, in_len, out, out_len, wrkmem))
+		return __LZO_QUERY_COMPRESS(in, in_len, out, out_len, wrkmem,
+					    D_SIZE, lzo_sizeof(lzo_dict_t));
+#endif
+
+	if (in_len <= M2_MAX_LEN + 5)
+		t = in_len;
+	else {
+		t = do_compress(in, in_len, op, out_len, wrkmem);
+		op += *out_len;
+	}
+
+	if (t > 0) {
+		const lzo_byte *ii = in + in_len - t;
+
+		if (op == out && t <= 238)
+			*op++ = LZO_BYTE(17 + t);
+		else if (t <= 3)
+			op[-2] |= LZO_BYTE(t);
+		else if (t <= 18)
+			*op++ = LZO_BYTE(t - 3);
+		else {
+			lzo_uint tt = t - 18;
+
+			*op++ = 0;
+			while (tt > 255) {
+				tt -= 255;
+				*op++ = 0;
+			}
+			assert("lzo-15", tt > 0);
+			*op++ = LZO_BYTE(tt);
+		}
+		do
+			*op++ = *ii++;
+		while (--t > 0);
+	}
+
+	*op++ = M4_MARKER | 1;
+	*op++ = 0;
+	*op++ = 0;
+
+	*out_len = op - out;
+	return LZO_E_OK;
+}
+
+#undef do_compress
+#undef DO_COMPRESS
+#undef LZO_HASH
+
+#undef LZO_TEST_DECOMPRESS_OVERRUN
+#undef LZO_TEST_DECOMPRESS_OVERRUN_INPUT
+#undef LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT
+#undef LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND
+#undef DO_DECOMPRESS
+#define DO_DECOMPRESS       lzo1x_decompress
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN)
+#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+#    define LZO_TEST_DECOMPRESS_OVERRUN_INPUT       2
+#  endif
+#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+#    define LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT      2
+#  endif
+#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+#    define LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND
+#  endif
+#endif
+
+#undef TEST_IP
+#undef TEST_OP
+#undef TEST_LOOKBEHIND
+#undef NEED_IP
+#undef NEED_OP
+#undef HAVE_TEST_IP
+#undef HAVE_TEST_OP
+#undef HAVE_NEED_IP
+#undef HAVE_NEED_OP
+#undef HAVE_ANY_IP
+#undef HAVE_ANY_OP
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 1)
+#    define TEST_IP             (ip < ip_end)
+#  endif
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 2)
+#    define NEED_IP(x) \
+	    if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x))  goto input_overrun
+#  endif
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 1)
+#    define TEST_OP             (op <= op_end)
+#  endif
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 2)
+#    undef TEST_OP
+#    define NEED_OP(x) \
+	    if ((lzo_uint)(op_end - op) < (lzo_uint)(x))  goto output_overrun
+#  endif
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+#  define TEST_LOOKBEHIND(m_pos,out)    if (m_pos < out) goto lookbehind_overrun
+#else
+#  define TEST_LOOKBEHIND(m_pos,op)     ((void) 0)
+#endif
+
+#if !defined(LZO_EOF_CODE) && !defined(TEST_IP)
+#  define TEST_IP               (ip < ip_end)
+#endif
+
+#if defined(TEST_IP)
+#  define HAVE_TEST_IP
+#else
+#  define TEST_IP               1
+#endif
+#if defined(TEST_OP)
+#  define HAVE_TEST_OP
+#else
+#  define TEST_OP               1
+#endif
+
+#if defined(NEED_IP)
+#  define HAVE_NEED_IP
+#else
+#  define NEED_IP(x)            ((void) 0)
+#endif
+#if defined(NEED_OP)
+#  define HAVE_NEED_OP
+#else
+#  define NEED_OP(x)            ((void) 0)
+#endif
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
+#  define HAVE_ANY_IP
+#endif
+#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)
+#  define HAVE_ANY_OP
+#endif
+
+#undef __COPY4
+#define __COPY4(dst,src)    * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src)
+
+#undef COPY4
+#if defined(LZO_UNALIGNED_OK_4)
+#  define COPY4(dst,src)    __COPY4(dst,src)
+#elif defined(LZO_ALIGNED_OK_4)
+#  define COPY4(dst,src)    __COPY4((lzo_ptr_t)(dst),(lzo_ptr_t)(src))
+#endif
+
+#if defined(DO_DECOMPRESS)
+LZO_PUBLIC(int)
+    DO_DECOMPRESS(const lzo_byte * in, lzo_uint in_len,
+	      lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem)
+#endif
+{
+	register lzo_byte *op;
+	register const lzo_byte *ip;
+	register lzo_uint t;
+#if defined(COPY_DICT)
+	lzo_uint m_off;
+	const lzo_byte *dict_end;
+#else
+	register const lzo_byte *m_pos;
+#endif
+
+	const lzo_byte *const ip_end = in + in_len;
+#if defined(HAVE_ANY_OP)
+	lzo_byte *const op_end = out + *out_len;
+#endif
+#if defined(LZO1Z)
+	lzo_uint last_m_off = 0;
+#endif
+
+	LZO_UNUSED(wrkmem);
+
+#if defined(__LZO_QUERY_DECOMPRESS)
+	if (__LZO_IS_DECOMPRESS_QUERY(in, in_len, out, out_len, wrkmem))
+		return __LZO_QUERY_DECOMPRESS(in, in_len, out, out_len, wrkmem,
+					      0, 0);
+#endif
+
+#if defined(COPY_DICT)
+	if (dict) {
+		if (dict_len > M4_MAX_OFFSET) {
+			dict += dict_len - M4_MAX_OFFSET;
+			dict_len = M4_MAX_OFFSET;
+		}
+		dict_end = dict + dict_len;
+	} else {
+		dict_len = 0;
+		dict_end = NULL;
+	}
+#endif
+
+	*out_len = 0;
+
+	op = out;
+	ip = in;
+
+	if (*ip > 17) {
+		t = *ip++ - 17;
+		if (t < 4)
+			goto match_next;
+		assert("lzo-16", t > 0);
+		NEED_OP(t);
+		NEED_IP(t + 1);
+		do
+			*op++ = *ip++;
+		while (--t > 0);
+		goto first_literal_run;
+	}
+
+	while (TEST_IP && TEST_OP) {
+		t = *ip++;
+		if (t >= 16)
+			goto match;
+		if (t == 0) {
+			NEED_IP(1);
+			while (*ip == 0) {
+				t += 255;
+				ip++;
+				NEED_IP(1);
+			}
+			t += 15 + *ip++;
+		}
+		assert("lzo-17", t > 0);
+		NEED_OP(t + 3);
+		NEED_IP(t + 4);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+		if (PTR_ALIGNED2_4(op, ip)) {
+#endif
+			COPY4(op, ip);
+			op += 4;
+			ip += 4;
+			if (--t > 0) {
+				if (t >= 4) {
+					do {
+						COPY4(op, ip);
+						op += 4;
+						ip += 4;
+						t -= 4;
+					} while (t >= 4);
+					if (t > 0)
+						do
+							*op++ = *ip++;
+						while (--t > 0);
+				} else
+					do
+						*op++ = *ip++;
+					while (--t > 0);
+			}
+#if !defined(LZO_UNALIGNED_OK_4)
+		} else
+#endif
+#endif
+#if !defined(LZO_UNALIGNED_OK_4)
+		{
+			*op++ = *ip++;
+			*op++ = *ip++;
+			*op++ = *ip++;
+			do
+				*op++ = *ip++;
+			while (--t > 0);
+		}
+#endif
+
+	      first_literal_run:
+
+		t = *ip++;
+		if (t >= 16)
+			goto match;
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+		m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+		last_m_off = m_off;
+#else
+		m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2);
+#endif
+		NEED_OP(3);
+		t = 3;
+		COPY_DICT(t, m_off)
+#else
+#if defined(LZO1Z)
+		t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+		m_pos = op - t;
+		last_m_off = t;
+#else
+		m_pos = op - (1 + M2_MAX_OFFSET);
+		m_pos -= t >> 2;
+		m_pos -= *ip++ << 2;
+#endif
+		TEST_LOOKBEHIND(m_pos, out);
+		NEED_OP(3);
+		*op++ = *m_pos++;
+		*op++ = *m_pos++;
+		*op++ = *m_pos;
+#endif
+		goto match_done;
+
+		while (TEST_IP && TEST_OP) {
+		      match:
+			if (t >= 64) {
+#if defined(COPY_DICT)
+#if defined(LZO1X)
+				m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3);
+				t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+				m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2);
+				t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+				m_off = t & 0x1f;
+				if (m_off >= 0x1c)
+					m_off = last_m_off;
+				else {
+					m_off = 1 + (m_off << 6) + (*ip++ >> 2);
+					last_m_off = m_off;
+				}
+				t = (t >> 5) - 1;
+#endif
+#else
+#if defined(LZO1X)
+				m_pos = op - 1;
+				m_pos -= (t >> 2) & 7;
+				m_pos -= *ip++ << 3;
+				t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+				m_pos = op - 1;
+				m_pos -= (t >> 2) & 3;
+				m_pos -= *ip++ << 2;
+				t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+				{
+					lzo_uint off = t & 0x1f;
+					m_pos = op;
+					if (off >= 0x1c) {
+						assert(last_m_off > 0);
+						m_pos -= last_m_off;
+					} else {
+						off =
+						    1 + (off << 6) +
+						    (*ip++ >> 2);
+						m_pos -= off;
+						last_m_off = off;
+					}
+				}
+				t = (t >> 5) - 1;
+#endif
+				TEST_LOOKBEHIND(m_pos, out);
+				assert("lzo-18", t > 0);
+				NEED_OP(t + 3 - 1);
+				goto copy_match;
+#endif
+			} else if (t >= 32) {
+				t &= 31;
+				if (t == 0) {
+					NEED_IP(1);
+					while (*ip == 0) {
+						t += 255;
+						ip++;
+						NEED_IP(1);
+					}
+					t += 31 + *ip++;
+				}
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+				m_off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+				last_m_off = m_off;
+#else
+				m_off = 1 + (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#else
+#if defined(LZO1Z)
+				{
+					lzo_uint off =
+					    1 + (ip[0] << 6) + (ip[1] >> 2);
+					m_pos = op - off;
+					last_m_off = off;
+				}
+#elif defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+				m_pos = op - 1;
+				m_pos -= (*(const lzo_ushortp)ip) >> 2;
+#else
+				m_pos = op - 1;
+				m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#endif
+				ip += 2;
+			} else if (t >= 16) {
+#if defined(COPY_DICT)
+				m_off = (t & 8) << 11;
+#else
+				m_pos = op;
+				m_pos -= (t & 8) << 11;
+#endif
+				t &= 7;
+				if (t == 0) {
+					NEED_IP(1);
+					while (*ip == 0) {
+						t += 255;
+						ip++;
+						NEED_IP(1);
+					}
+					t += 7 + *ip++;
+				}
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+				m_off += (ip[0] << 6) + (ip[1] >> 2);
+#else
+				m_off += (ip[0] >> 2) + (ip[1] << 6);
+#endif
+				ip += 2;
+				if (m_off == 0)
+					goto eof_found;
+				m_off += 0x4000;
+#if defined(LZO1Z)
+				last_m_off = m_off;
+#endif
+#else
+#if defined(LZO1Z)
+				m_pos -= (ip[0] << 6) + (ip[1] >> 2);
+#elif defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+				m_pos -= (*(const lzo_ushortp)ip) >> 2;
+#else
+				m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+				ip += 2;
+				if (m_pos == op)
+					goto eof_found;
+				m_pos -= 0x4000;
+#if defined(LZO1Z)
+				last_m_off = op - m_pos;
+#endif
+#endif
+			} else {
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+				m_off = 1 + (t << 6) + (*ip++ >> 2);
+				last_m_off = m_off;
+#else
+				m_off = 1 + (t >> 2) + (*ip++ << 2);
+#endif
+				NEED_OP(2);
+				t = 2;
+				COPY_DICT(t, m_off)
+#else
+#if defined(LZO1Z)
+				t = 1 + (t << 6) + (*ip++ >> 2);
+				m_pos = op - t;
+				last_m_off = t;
+#else
+				m_pos = op - 1;
+				m_pos -= t >> 2;
+				m_pos -= *ip++ << 2;
+#endif
+				TEST_LOOKBEHIND(m_pos, out);
+				NEED_OP(2);
+				*op++ = *m_pos++;
+				*op++ = *m_pos;
+#endif
+				goto match_done;
+			}
+
+#if defined(COPY_DICT)
+
+			NEED_OP(t + 3 - 1);
+			t += 3 - 1;
+			COPY_DICT(t, m_off)
+#else
+
+			TEST_LOOKBEHIND(m_pos, out);
+			assert("lzo-19", t > 0);
+			NEED_OP(t + 3 - 1);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+			if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op, m_pos)) {
+				assert((op - m_pos) >= 4);
+#else
+			if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) {
+#endif
+				COPY4(op, m_pos);
+				op += 4;
+				m_pos += 4;
+				t -= 4 - (3 - 1);
+				do {
+					COPY4(op, m_pos);
+					op += 4;
+					m_pos += 4;
+					t -= 4;
+				} while (t >= 4);
+				if (t > 0)
+					do
+						*op++ = *m_pos++;
+					while (--t > 0);
+			} else
+#endif
+			{
+			      copy_match:
+				*op++ = *m_pos++;
+				*op++ = *m_pos++;
+				do
+					*op++ = *m_pos++;
+				while (--t > 0);
+			}
+
+#endif
+
+		      match_done:
+#if defined(LZO1Z)
+			t = ip[-1] & 3;
+#else
+			t = ip[-2] & 3;
+#endif
+			if (t == 0)
+				break;
+
+		      match_next:
+			assert("lzo-20", t > 0);
+			NEED_OP(t);
+			NEED_IP(t + 1);
+			do
+				*op++ = *ip++;
+			while (--t > 0);
+			t = *ip++;
+		}
+	}
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
+	*out_len = op - out;
+	return LZO_E_EOF_NOT_FOUND;
+#endif
+
+      eof_found:
+	assert("lzo-21", t == 1);
+	*out_len = op - out;
+	return (ip == ip_end ? LZO_E_OK :
+		(ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+
+#if defined(HAVE_NEED_IP)
+      input_overrun:
+	*out_len = op - out;
+	return LZO_E_INPUT_OVERRUN;
+#endif
+
+#if defined(HAVE_NEED_OP)
+      output_overrun:
+	*out_len = op - out;
+	return LZO_E_OUTPUT_OVERRUN;
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+      lookbehind_overrun:
+	*out_len = op - out;
+	return LZO_E_LOOKBEHIND_OVERRUN;
+#endif
+}
+
+#define LZO_TEST_DECOMPRESS_OVERRUN
+#undef DO_DECOMPRESS
+#define DO_DECOMPRESS       lzo1x_decompress_safe
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN)
+#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+#    define LZO_TEST_DECOMPRESS_OVERRUN_INPUT       2
+#  endif
+#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+#    define LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT      2
+#  endif
+#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+#    define LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND
+#  endif
+#endif
+
+#undef TEST_IP
+#undef TEST_OP
+#undef TEST_LOOKBEHIND
+#undef NEED_IP
+#undef NEED_OP
+#undef HAVE_TEST_IP
+#undef HAVE_TEST_OP
+#undef HAVE_NEED_IP
+#undef HAVE_NEED_OP
+#undef HAVE_ANY_IP
+#undef HAVE_ANY_OP
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 1)
+#    define TEST_IP             (ip < ip_end)
+#  endif
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 2)
+#    define NEED_IP(x) \
+	    if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x))  goto input_overrun
+#  endif
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 1)
+#    define TEST_OP             (op <= op_end)
+#  endif
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 2)
+#    undef TEST_OP
+#    define NEED_OP(x) \
+	    if ((lzo_uint)(op_end - op) < (lzo_uint)(x))  goto output_overrun
+#  endif
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+#  define TEST_LOOKBEHIND(m_pos,out)    if (m_pos < out) goto lookbehind_overrun
+#else
+#  define TEST_LOOKBEHIND(m_pos,op)     ((void) 0)
+#endif
+
+#if !defined(LZO_EOF_CODE) && !defined(TEST_IP)
+#  define TEST_IP               (ip < ip_end)
+#endif
+
+#if defined(TEST_IP)
+#  define HAVE_TEST_IP
+#else
+#  define TEST_IP               1
+#endif
+#if defined(TEST_OP)
+#  define HAVE_TEST_OP
+#else
+#  define TEST_OP               1
+#endif
+
+#if defined(NEED_IP)
+#  define HAVE_NEED_IP
+#else
+#  define NEED_IP(x)            ((void) 0)
+#endif
+#if defined(NEED_OP)
+#  define HAVE_NEED_OP
+#else
+#  define NEED_OP(x)            ((void) 0)
+#endif
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
+#  define HAVE_ANY_IP
+#endif
+#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)
+#  define HAVE_ANY_OP
+#endif
+
+#undef __COPY4
+#define __COPY4(dst,src)    * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src)
+
+#undef COPY4
+#if defined(LZO_UNALIGNED_OK_4)
+#  define COPY4(dst,src)    __COPY4(dst,src)
+#elif defined(LZO_ALIGNED_OK_4)
+#  define COPY4(dst,src)    __COPY4((lzo_ptr_t)(dst),(lzo_ptr_t)(src))
+#endif
+
+/***** End of minilzo.c *****/
diff -urN oldtree/fs/reiser4/plugin/compress/minilzo.h newtree/fs/reiser4/plugin/compress/minilzo.h
--- oldtree/fs/reiser4/plugin/compress/minilzo.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/compress/minilzo.h	2006-02-21 15:58:34.568891288 +0000
@@ -0,0 +1,94 @@
+/* minilzo.h -- mini subset of the LZO real-time data compression library
+   adopted for reiser4 compression transform plugin.
+
+   This file is part of the LZO real-time data compression library
+   and not included in any proprietary licenses of reiser4.
+
+   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+   Markus F.X.J. Oberhumer
+   <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+ */
+
+/*
+ * NOTE:
+ *   the full LZO package can be found at
+ *   http://www.oberhumer.com/opensource/lzo/
+ */
+
+#ifndef __MINILZO_H
+#define __MINILZO_H
+
+#define MINILZO_VERSION         0x1080
+
+#ifdef __LZOCONF_H
+#  error "you cannot use both LZO and miniLZO"
+#endif
+
+#undef LZO_HAVE_CONFIG_H
+#include "lzoconf.h"
+
+#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION)
+#  error "version mismatch in header files"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***********************************************************************
+//
+************************************************************************/
+
+/* Memory required for the wrkmem parameter.
+ * When the required size is 0, you can also pass a NULL pointer.
+ */
+
+#define LZO1X_MEM_COMPRESS      LZO1X_1_MEM_COMPRESS
+#define LZO1X_1_MEM_COMPRESS    ((lzo_uint32) (16384L * lzo_sizeof_dict_t))
+#define LZO1X_MEM_DECOMPRESS    (0)
+
+/* compression */
+	LZO_EXTERN(int)
+	 lzo1x_1_compress(const lzo_byte * src, lzo_uint src_len,
+			  lzo_byte * dst, lzo_uintp dst_len, lzo_voidp wrkmem);
+
+/* decompression */
+	 LZO_EXTERN(int)
+	 lzo1x_decompress(const lzo_byte * src, lzo_uint src_len,
+			  lzo_byte * dst, lzo_uintp dst_len,
+			  lzo_voidp wrkmem /* NOT USED */ );
+
+/* safe decompression with overrun testing */
+	 LZO_EXTERN(int)
+	 lzo1x_decompress_safe(const lzo_byte * src, lzo_uint src_len,
+			       lzo_byte * dst, lzo_uintp dst_len,
+			       lzo_voidp wrkmem /* NOT USED */ );
+
+#ifdef __cplusplus
+}				/* extern "C" */
+#endif
+#endif				/* already included */
diff -urN oldtree/fs/reiser4/plugin/crypto/cipher.c newtree/fs/reiser4/plugin/crypto/cipher.c
--- oldtree/fs/reiser4/plugin/crypto/cipher.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/crypto/cipher.c	2006-02-21 15:58:35.213793248 +0000
@@ -0,0 +1,116 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser,
+   licensing governed by reiser4/README */
+/* Reiser4 cipher transform plugins */
+
+#include "../../debug.h"
+#include "../plugin.h"
+#include "../file/cryptcompress.h"
+#include <linux/types.h>
+#include <linux/random.h>
+
+#define MIN_CIPHER_BLOCKSIZE 8
+#define MAX_CIPHER_BLOCKSIZE 128
+
+/*
+  Default align() method of the cipher plugin (look for description of this
+  method in plugin/plugin.h)
+
+  1) creates the aligning armored format of the input flow before encryption.
+     "armored" means that padding is filled by private data (for example,
+     pseudo-random sequence of bytes is not private data).
+  2) returns length of appended padding
+
+   [ flow | aligning_padding ]
+            ^
+            |
+	  @pad
+*/
+static int align_stream_common(__u8 * pad,
+			       int flow_size /* size of non-aligned flow */,
+			       int blocksize /* cipher block size */)
+{
+	int pad_size;
+
+	assert("edward-01", pad != NULL);
+	assert("edward-02", flow_size != 0);
+	assert("edward-03", blocksize != 0
+	       || blocksize <= MAX_CIPHER_BLOCKSIZE);
+
+	pad_size = blocksize - (flow_size % blocksize);
+	get_random_bytes(pad, pad_size);
+	return pad_size;
+}
+
+/* This is used for all the cipher algorithms which do not inflate
+   block-aligned data */
+static loff_t scale_common(struct inode *inode, size_t blocksize,
+			   loff_t src_off /* offset to scale */ )
+{
+	return src_off;
+}
+
+static void free_aes (struct crypto_tfm * tfm)
+{
+#if REISER4_AES
+	crypto_free_tfm(tfm);
+#endif
+	return;
+}
+
+static struct crypto_tfm * alloc_aes (void)
+{
+#if REISER4_AES
+	return crypto_alloc_tfm ("aes", 0);
+#else
+	warning("edward-1417", "aes unsupported");
+	return ERR_PTR(-EINVAL);
+#endif /* REISER4_AES */
+}
+
+cipher_plugin cipher_plugins[LAST_CIPHER_ID] = {
+	[NONE_CIPHER_ID] = {
+		.h = {
+			.type_id = REISER4_CIPHER_PLUGIN_TYPE,
+			.id = NONE_CIPHER_ID,
+			.pops = NULL,
+			.label = "none",
+			.desc = "no cipher transform",
+			.linkage = {NULL, NULL}
+		},
+		.alloc = NULL,
+		.free = NULL,
+		.scale = NULL,
+		.align_stream = NULL,
+		.setkey = NULL,
+		.encrypt = NULL,
+		.decrypt = NULL
+	},
+	[AES_CIPHER_ID] = {
+		.h = {
+			.type_id = REISER4_CIPHER_PLUGIN_TYPE,
+			.id = AES_CIPHER_ID,
+			.pops = NULL,
+			.label = "aes",
+			.desc = "aes cipher transform",
+			.linkage = {NULL, NULL}
+		},
+		.alloc = alloc_aes,
+		.free = free_aes,
+		.scale = scale_common,
+		.align_stream = align_stream_common,
+		.setkey = NULL,
+		.encrypt = NULL,
+		.decrypt = NULL
+	}
+};
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/crypto/cipher.h newtree/fs/reiser4/plugin/crypto/cipher.h
--- oldtree/fs/reiser4/plugin/crypto/cipher.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/crypto/cipher.h	2006-02-21 15:58:35.184797656 +0000
@@ -0,0 +1,58 @@
+#if !defined( __FS_REISER4_CRYPT_H__ )
+#define __FS_REISER4_CRYPT_H__
+
+#include <linux/crypto.h>
+
+/* Crypto transforms involved in ciphering process and
+   supported by reiser4 via appropriate transform plugins */
+typedef enum {
+	CIPHER_TFM,       /* cipher transform */
+	DIGEST_TFM,       /* digest transform */
+	LAST_TFM
+} reiser4_tfm;
+
+/* This represents a transform from the set above */
+typedef struct reiser4_tfma {
+	reiser4_plugin * plug;     /* transform plugin */
+	struct crypto_tfm * tfm;   /* per-transform allocated info,
+                                      belongs to the crypto-api. */
+} reiser4_tfma_t;
+
+/* This contains cipher related info copied from user space */
+typedef struct crypto_data {
+	int keysize;    /* key size */
+	__u8 * key;     /* uninstantiated key */
+	int keyid_size; /* size of passphrase */
+	__u8 * keyid;   /* passphrase (uninstantiated keyid) */
+} crypto_data_t;
+
+/* Dynamically allocated per instantiated key info */
+typedef struct crypto_stat {
+	reiser4_tfma_t tfma[LAST_TFM];
+//      cipher_key_plugin * kplug; *//* key manager responsible for
+//                                      inheriting, validating, etc... */
+	__u8 * keyid;                /* fingerprint (instantiated keyid) of
+					the cipher key prepared by digest
+					plugin, supposed to be stored in
+					disk stat-data */
+	int inst;                    /* this indicates if the ciper key
+					is instantiated in the system */
+	int keysize;                 /* uninstantiated key size (bytes),
+					supposed to be stored in disk
+					stat-data */
+	int keyload_count;           /* number of the objects which has
+					this crypto-stat attached */
+} crypto_stat_t;
+
+#endif /* __FS_REISER4_CRYPT_H__ */
+
+/*
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/crypto/digest.c newtree/fs/reiser4/plugin/crypto/digest.c
--- oldtree/fs/reiser4/plugin/crypto/digest.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/crypto/digest.c	2006-02-21 15:58:35.184797656 +0000
@@ -0,0 +1,58 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* reiser4 digest transform plugin (is used by cryptcompress object plugin) */
+/* EDWARD-FIXME-HANS: and it does what? a digest is a what? */
+#include "../../debug.h"
+#include "../plugin_header.h"
+#include "../plugin.h"
+#include "../file/cryptcompress.h"
+
+#include <linux/types.h>
+
+extern digest_plugin digest_plugins[LAST_DIGEST_ID];
+
+static struct crypto_tfm * alloc_sha256 (void)
+{
+#if REISER4_SHA256
+	return crypto_alloc_tfm ("sha256", 0);
+#else
+	warning("edward-1418", "sha256 unsupported");
+	return ERR_PTR(-EINVAL);
+#endif
+}
+
+static void free_sha256 (struct crypto_tfm * tfm)
+{
+#if REISER4_SHA256
+	crypto_free_tfm(tfm);
+#endif
+	return;
+}
+
+/* digest plugins */
+digest_plugin digest_plugins[LAST_DIGEST_ID] = {
+	[SHA256_32_DIGEST_ID] = {
+		.h = {
+			.type_id = REISER4_DIGEST_PLUGIN_TYPE,
+			.id = SHA256_32_DIGEST_ID,
+			.pops = NULL,
+			.label = "sha256_32",
+			.desc = "sha256_32 digest transform",
+			.linkage = {NULL, NULL}
+		},
+		.fipsize = sizeof(__u32),
+		.alloc = alloc_sha256,
+		.free = free_sha256
+	}
+};
+
+/*
+  Local variables:
+  c-indentation-style: "K&R"
+  mode-name: "LC"
+  c-basic-offset: 8
+  tab-width: 8
+  fill-column: 120
+  scroll-step: 1
+  End:
+*/
diff -urN oldtree/fs/reiser4/plugin/dir/Makefile newtree/fs/reiser4/plugin/dir/Makefile
--- oldtree/fs/reiser4/plugin/dir/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/dir/Makefile	2006-02-21 15:58:35.081813312 +0000
@@ -0,0 +1,5 @@
+obj-$(CONFIG_REISER4_FS) += dir_plugins.o
+
+dir_plugins-objs :=	\
+	hashed_dir.o	\
+	seekable_dir.o
diff -urN oldtree/fs/reiser4/plugin/dir/dir.h newtree/fs/reiser4/plugin/dir/dir.h
--- oldtree/fs/reiser4/plugin/dir/dir.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/dir/dir.h	2006-02-21 15:58:34.576890072 +0000
@@ -0,0 +1,36 @@
+/* Copyright 2001, 2002, 2003, 2004 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* this file contains declarations of methods implementing directory plugins */
+
+#if !defined( __REISER4_DIR_H__ )
+#define __REISER4_DIR_H__
+
+/*#include "../../key.h"
+
+#include <linux/fs.h>*/
+
+/* declarations of functions implementing HASHED_DIR_PLUGIN_ID dir plugin */
+
+/* "hashed" directory methods of dir plugin */
+void build_entry_key_hashed(const struct inode *, const struct qstr *,
+			    reiser4_key *);
+
+/* declarations of functions implementing SEEKABLE_HASHED_DIR_PLUGIN_ID dir plugin */
+
+/* "seekable" directory methods of dir plugin */
+void build_entry_key_seekable(const struct inode *, const struct qstr *,
+			      reiser4_key *);
+
+/* __REISER4_DIR_H__ */
+#endif
+
+/*
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/dir/hashed_dir.c newtree/fs/reiser4/plugin/dir/hashed_dir.c
--- oldtree/fs/reiser4/plugin/dir/hashed_dir.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/dir/hashed_dir.c	2006-02-21 15:58:34.578889768 +0000
@@ -0,0 +1,81 @@
+/* Copyright 2001, 2002, 2003, 2004 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Directory plugin using hashes (see fs/reiser4/plugin/hash.c) to map file
+   names to the files. */
+
+/*
+ * Hashed directory logically consists of persistent directory
+ * entries. Directory entry is a pair of a file name and a key of stat-data of
+ * a file that has this name in the given directory.
+ *
+ * Directory entries are stored in the tree in the form of directory
+ * items. Directory item should implement dir_entry_ops portion of item plugin
+ * interface (see plugin/item/item.h). Hashed directory interacts with
+ * directory item plugin exclusively through dir_entry_ops operations.
+ *
+ * Currently there are two implementations of directory items: "simple
+ * directory item" (plugin/item/sde.[ch]), and "compound directory item"
+ * (plugin/item/cde.[ch]) with the latter being the default.
+ *
+ * There is, however some delicate way through which directory code interferes
+ * with item plugin: key assignment policy. A key for a directory item is
+ * chosen by directory code, and as described in kassign.c, this key contains
+ * a portion of file name. Directory item uses this knowledge to avoid storing
+ * this portion of file name twice: in the key and in the directory item body.
+ *
+ */
+
+#include "../../inode.h"
+
+void complete_entry_key(const struct inode *, const char *name,
+			int len, reiser4_key * result);
+
+/* this is implementation of build_entry_key method of dir
+   plugin for HASHED_DIR_PLUGIN_ID
+ */
+void build_entry_key_hashed(const struct inode *dir,	/* directory where entry is
+							 * (or will be) in.*/
+			    const struct qstr *qname,	/* name of file referenced
+							 * by this entry */
+			    reiser4_key * result	/* resulting key of directory
+							 * entry */ )
+{
+	const char *name;
+	int len;
+
+	assert("nikita-1139", dir != NULL);
+	assert("nikita-1140", qname != NULL);
+	assert("nikita-1141", qname->name != NULL);
+	assert("nikita-1142", result != NULL);
+
+	name = qname->name;
+	len = qname->len;
+
+	assert("nikita-2867", strlen(name) == len);
+
+	reiser4_key_init(result);
+	/* locality of directory entry's key is objectid of parent
+	   directory */
+	set_key_locality(result, get_inode_oid(dir));
+	/* minor packing locality is constant */
+	set_key_type(result, KEY_FILE_NAME_MINOR);
+	/* dot is special case---we always want it to be first entry in
+	   a directory. Actually, we just want to have smallest
+	   directory entry.
+	 */
+	if (len == 1 && name[0] == '.')
+		return;
+
+	/* initialize part of entry key which depends on file name */
+	complete_entry_key(dir, name, len, result);
+}
+
+/* Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/dir/seekable_dir.c newtree/fs/reiser4/plugin/dir/seekable_dir.c
--- oldtree/fs/reiser4/plugin/dir/seekable_dir.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/dir/seekable_dir.c	2006-02-21 15:58:34.581889312 +0000
@@ -0,0 +1,46 @@
+/* Copyright 2005 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+#include "../../inode.h"
+
+/* this is implementation of build_entry_key method of dir
+   plugin for SEEKABLE_HASHED_DIR_PLUGIN_ID
+   This is for directories where we want repeatable and restartable readdir()
+   even in case 32bit user level struct dirent (readdir(3)).
+*/
+void
+build_entry_key_seekable(const struct inode *dir, const struct qstr *name,
+			 reiser4_key * result)
+{
+	oid_t objectid;
+
+	assert("nikita-2283", dir != NULL);
+	assert("nikita-2284", name != NULL);
+	assert("nikita-2285", name->name != NULL);
+	assert("nikita-2286", result != NULL);
+
+	reiser4_key_init(result);
+	/* locality of directory entry's key is objectid of parent
+	   directory */
+	set_key_locality(result, get_inode_oid(dir));
+	/* minor packing locality is constant */
+	set_key_type(result, KEY_FILE_NAME_MINOR);
+	/* dot is special case---we always want it to be first entry in
+	   a directory. Actually, we just want to have smallest
+	   directory entry.
+	 */
+	if ((name->len == 1) && (name->name[0] == '.'))
+		return;
+
+	/* objectid of key is 31 lowest bits of hash. */
+	objectid =
+	    inode_hash_plugin(dir)->hash(name->name,
+					 (int)name->len) & 0x7fffffff;
+
+	assert("nikita-2303", !(objectid & ~KEY_OBJECTID_MASK));
+	set_key_objectid(result, objectid);
+
+	/* offset is always 0. */
+	set_key_offset(result, (__u64) 0);
+	return;
+}
diff -urN oldtree/fs/reiser4/plugin/dir_plugin_common.c newtree/fs/reiser4/plugin/dir_plugin_common.c
--- oldtree/fs/reiser4/plugin/dir_plugin_common.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/dir_plugin_common.c	2006-02-21 15:58:35.483752208 +0000
@@ -0,0 +1,864 @@
+/* Copyright 2005 by Hans Reiser, licensing governed by
+   reiser4/README */
+
+/* this file contains typical implementations for most of methods of
+   directory plugin
+*/
+
+#include "../inode.h"
+
+int find_entry(struct inode *dir, struct dentry *name,
+	       lock_handle *, znode_lock_mode, reiser4_dir_entry_desc *);
+int lookup_name(struct inode *parent, struct dentry *dentry, reiser4_key * key);
+void check_light_weight(struct inode *inode, struct inode *parent);
+
+/* this is common implementation of get_parent method of dir plugin
+   this is used by NFS kernel server to "climb" up directory tree to
+   check permissions
+ */
+struct dentry *get_parent_common(struct inode *child)
+{
+	struct super_block *s;
+	struct inode *parent;
+	struct dentry dotdot;
+	struct dentry *dentry;
+	reiser4_key key;
+	int result;
+
+	/*
+	 * lookup dotdot entry.
+	 */
+
+	s = child->i_sb;
+	memset(&dotdot, 0, sizeof(dotdot));
+	dotdot.d_name.name = "..";
+	dotdot.d_name.len = 2;
+	dotdot.d_op = &get_super_private(s)->ops.dentry;
+
+	result = lookup_name(child, &dotdot, &key);
+	if (result != 0)
+		return ERR_PTR(result);
+
+	parent = reiser4_iget(s, &key, 1);
+	if (!IS_ERR(parent)) {
+		/*
+		 * FIXME-NIKITA dubious: attributes are inherited from @child
+		 * to @parent. But:
+		 *
+		 *     (*) this is the only this we can do
+		 *
+		 *     (*) attributes of light-weight object are inherited
+		 *     from a parent through which object was looked up first,
+		 *     so it is ambiguous anyway.
+		 *
+		 */
+		check_light_weight(parent, child);
+		reiser4_iget_complete(parent);
+		dentry = d_alloc_anon(parent);
+		if (dentry == NULL) {
+			iput(parent);
+			dentry = ERR_PTR(RETERR(-ENOMEM));
+		} else
+			dentry->d_op = &get_super_private(s)->ops.dentry;
+	} else if (PTR_ERR(parent) == -ENOENT)
+		dentry = ERR_PTR(RETERR(-ESTALE));
+	else
+		dentry = (void *)parent;
+	return dentry;
+}
+
+/* this is common implementation of is_name_acceptable method of dir
+   plugin
+ */
+int is_name_acceptable_common(const struct inode *inode,	/* directory to check */
+			      const char *name UNUSED_ARG,	/* name to check */
+			      int len /* @name's length */ )
+{
+	assert("nikita-733", inode != NULL);
+	assert("nikita-734", name != NULL);
+	assert("nikita-735", len > 0);
+
+	return len <= reiser4_max_filename_len(inode);
+}
+
+/* there is no common implementation of build_entry_key method of dir
+   plugin. See plugin/dir/hashed_dir.c:build_entry_key_hashed() or
+   plugin/dir/seekable.c:build_entry_key_seekable() for example
+*/
+
+/* this is common implementation of build_readdir_key method of dir
+   plugin
+   see readdir_common for more details
+*/
+int build_readdir_key_common(struct file *dir /* directory being read */ ,
+			     reiser4_key * result /* where to store key */ )
+{
+	reiser4_file_fsdata *fdata;
+	struct inode *inode;
+
+	assert("nikita-1361", dir != NULL);
+	assert("nikita-1362", result != NULL);
+	assert("nikita-1363", dir->f_dentry != NULL);
+	inode = dir->f_dentry->d_inode;
+	assert("nikita-1373", inode != NULL);
+
+	fdata = reiser4_get_file_fsdata(dir);
+	if (IS_ERR(fdata))
+		return PTR_ERR(fdata);
+	assert("nikita-1364", fdata != NULL);
+	return extract_key_from_de_id(get_inode_oid(inode),
+				      &fdata->dir.readdir.position.
+				      dir_entry_key, result);
+
+}
+
+void adjust_dir_file(struct inode *, const struct dentry *, int offset,
+		     int adj);
+
+/* this is common implementation of add_entry method of dir plugin
+*/
+int add_entry_common(struct inode *object,	/* directory to add new name
+						 * in */
+		     struct dentry *where,	/* new name */
+		     reiser4_object_create_data * data UNUSED_ARG,	/* parameters
+									 * of new
+									 * object */
+		     reiser4_dir_entry_desc * entry	/* parameters of new
+							 * directory entry */ )
+{
+	int result;
+	coord_t *coord;
+	lock_handle lh;
+	reiser4_dentry_fsdata *fsdata;
+	reiser4_block_nr reserve;
+
+	assert("nikita-1114", object != NULL);
+	assert("nikita-1250", where != NULL);
+
+	fsdata = reiser4_get_dentry_fsdata(where);
+	if (unlikely(IS_ERR(fsdata)))
+		return PTR_ERR(fsdata);
+
+	reserve = inode_dir_plugin(object)->estimate.add_entry(object);
+	if (reiser4_grab_space(reserve, BA_CAN_COMMIT))
+		return RETERR(-ENOSPC);
+
+	init_lh(&lh);
+	coord = &fsdata->dec.entry_coord;
+	coord_clear_iplug(coord);
+
+	/* check for this entry in a directory. This is plugin method. */
+	result = find_entry(object, where, &lh, ZNODE_WRITE_LOCK, entry);
+	if (likely(result == -ENOENT)) {
+		/* add new entry. Just pass control to the directory
+		   item plugin. */
+		assert("nikita-1709", inode_dir_item_plugin(object));
+		assert("nikita-2230", coord->node == lh.node);
+		seal_done(&fsdata->dec.entry_seal);
+		result =
+		    inode_dir_item_plugin(object)->s.dir.add_entry(object,
+								   coord, &lh,
+								   where,
+								   entry);
+		if (result == 0) {
+			adjust_dir_file(object, where, fsdata->dec.pos + 1, +1);
+			INODE_INC_FIELD(object, i_size);
+		}
+	} else if (result == 0) {
+		assert("nikita-2232", coord->node == lh.node);
+		result = RETERR(-EEXIST);
+	}
+	done_lh(&lh);
+
+	return result;
+}
+
+/**
+ * rem_entry - remove entry from directory item
+ * @dir:
+ * @dentry:
+ * @entry:
+ * @coord:
+ * @lh:
+ *
+ * Checks that coordinate @coord is set properly and calls item plugin
+ * method to cut entry.
+ */
+static int
+rem_entry(struct inode *dir, struct dentry *dentry,
+	  reiser4_dir_entry_desc * entry, coord_t * coord, lock_handle * lh)
+{
+	item_plugin *iplug;
+	struct inode *child;
+
+	iplug = inode_dir_item_plugin(dir);
+	child = dentry->d_inode;
+	assert("nikita-3399", child != NULL);
+
+	/* check that we are really destroying an entry for @child */
+	if (REISER4_DEBUG) {
+		int result;
+		reiser4_key key;
+
+		result = iplug->s.dir.extract_key(coord, &key);
+		if (result != 0)
+			return result;
+		if (get_key_objectid(&key) != get_inode_oid(child)) {
+			warning("nikita-3397",
+				"rem_entry: %#llx != %#llx\n",
+				get_key_objectid(&key),
+				(unsigned long long)get_inode_oid(child));
+			return RETERR(-EIO);
+		}
+	}
+	return iplug->s.dir.rem_entry(dir, &dentry->d_name, coord, lh, entry);
+}
+
+/**
+ * rem_entry_common - remove entry from a directory
+ * @dir: directory to remove entry from
+ * @where: name that is being removed
+ * @entry: description of entry being removed
+ *
+ * This is common implementation of rem_entry method of dir plugin.
+ */
+int rem_entry_common(struct inode *dir,
+		     struct dentry *dentry,
+		     reiser4_dir_entry_desc *entry)
+{
+	int result;
+	coord_t *coord;
+	lock_handle lh;
+	reiser4_dentry_fsdata *fsdata;
+	__u64 tograb;
+
+	assert("nikita-1124", dir != NULL);
+	assert("nikita-1125", dentry != NULL);
+
+	tograb = inode_dir_plugin(dir)->estimate.rem_entry(dir);
+	result = reiser4_grab_space(tograb, BA_CAN_COMMIT | BA_RESERVED);
+	if (result != 0)
+		return RETERR(-ENOSPC);
+
+	init_lh(&lh);
+
+	/* check for this entry in a directory. This is plugin method. */
+	result = find_entry(dir, dentry, &lh, ZNODE_WRITE_LOCK, entry);
+	fsdata = reiser4_get_dentry_fsdata(dentry);
+	if (IS_ERR(fsdata)) {
+		done_lh(&lh);
+		return PTR_ERR(fsdata);
+	}
+
+	coord = &fsdata->dec.entry_coord;
+
+	assert("nikita-3404",
+	       get_inode_oid(dentry->d_inode) != get_inode_oid(dir) ||
+	       dir->i_size <= 1);
+
+	coord_clear_iplug(coord);
+	if (result == 0) {
+		/* remove entry. Just pass control to the directory item
+		   plugin. */
+		assert("vs-542", inode_dir_item_plugin(dir));
+		seal_done(&fsdata->dec.entry_seal);
+		adjust_dir_file(dir, dentry, fsdata->dec.pos, -1);
+		result =
+		    WITH_COORD(coord,
+			       rem_entry(dir, dentry, entry, coord, &lh));
+		if (result == 0) {
+			if (dir->i_size >= 1)
+				INODE_DEC_FIELD(dir, i_size);
+			else {
+				warning("nikita-2509", "Dir %llu is runt",
+					(unsigned long long)
+					get_inode_oid(dir));
+				result = RETERR(-EIO);
+			}
+
+			assert("nikita-3405", dentry->d_inode->i_nlink != 1 ||
+			       dentry->d_inode->i_size != 2 ||
+			       inode_dir_plugin(dentry->d_inode) == NULL);
+		}
+	}
+	done_lh(&lh);
+
+	return result;
+}
+
+static reiser4_block_nr estimate_init(struct inode *parent,
+				      struct inode *object);
+static int create_dot_dotdot(struct inode *object, struct inode *parent);
+
+/* this is common implementation of init method of dir plugin
+   create "." and ".." entries
+*/
+int init_common(struct inode *object,	/* new directory */
+		struct inode *parent,	/* parent directory */
+		reiser4_object_create_data * data UNUSED_ARG	/* info passed
+								 * to us, this
+								 * is filled by
+								 * reiser4()
+								 * syscall in
+								 * particular */ )
+{
+	reiser4_block_nr reserve;
+
+	assert("nikita-680", object != NULL);
+	assert("nikita-681", S_ISDIR(object->i_mode));
+	assert("nikita-682", parent != NULL);
+	assert("nikita-684", data != NULL);
+	assert("nikita-686", data->id == DIRECTORY_FILE_PLUGIN_ID);
+	assert("nikita-687", object->i_mode & S_IFDIR);
+
+	reserve = estimate_init(parent, object);
+	if (reiser4_grab_space(reserve, BA_CAN_COMMIT))
+		return RETERR(-ENOSPC);
+
+	return create_dot_dotdot(object, parent);
+}
+
+/* this is common implementation of done method of dir plugin
+   remove "." entry
+*/
+int done_common(struct inode *object /* object being deleted */ )
+{
+	int result;
+	reiser4_block_nr reserve;
+	struct dentry goodby_dots;
+	reiser4_dir_entry_desc entry;
+
+	assert("nikita-1449", object != NULL);
+
+	if (inode_get_flag(object, REISER4_NO_SD))
+		return 0;
+
+	/* of course, this can be rewritten to sweep everything in one
+	   cut_tree(). */
+	memset(&entry, 0, sizeof entry);
+
+	/* FIXME: this done method is called from delete_directory_common which
+	 * reserved space already */
+	reserve = inode_dir_plugin(object)->estimate.rem_entry(object);
+	if (reiser4_grab_space(reserve, BA_CAN_COMMIT | BA_RESERVED))
+		return RETERR(-ENOSPC);
+
+	memset(&goodby_dots, 0, sizeof goodby_dots);
+	entry.obj = goodby_dots.d_inode = object;
+	goodby_dots.d_name.name = ".";
+	goodby_dots.d_name.len = 1;
+	result = rem_entry_common(object, &goodby_dots, &entry);
+	reiser4_free_dentry_fsdata(&goodby_dots);
+	if (unlikely(result != 0 && result != -ENOMEM && result != -ENOENT))
+		/* only worth a warning
+
+		   "values of B will give rise to dom!\n"
+		   -- v6src/s2/mv.c:89
+		 */
+		warning("nikita-2252", "Cannot remove dot of %lli: %i",
+			(unsigned long long)get_inode_oid(object), result);
+	return 0;
+}
+
+/* this is common implementation of attach method of dir plugin
+*/
+int
+attach_common(struct inode *child UNUSED_ARG, struct inode *parent UNUSED_ARG)
+{
+	assert("nikita-2647", child != NULL);
+	assert("nikita-2648", parent != NULL);
+
+	return 0;
+}
+
+/* this is common implementation of detach method of dir plugin
+   remove "..", decrease nlink on parent
+*/
+int detach_common(struct inode *object, struct inode *parent)
+{
+	int result;
+	struct dentry goodby_dots;
+	reiser4_dir_entry_desc entry;
+
+	assert("nikita-2885", object != NULL);
+	assert("nikita-2886", !inode_get_flag(object, REISER4_NO_SD));
+
+	memset(&entry, 0, sizeof entry);
+
+	/* NOTE-NIKITA this only works if @parent is -the- parent of
+	   @object, viz. object whose key is stored in dotdot
+	   entry. Wouldn't work with hard-links on directories. */
+	memset(&goodby_dots, 0, sizeof goodby_dots);
+	entry.obj = goodby_dots.d_inode = parent;
+	goodby_dots.d_name.name = "..";
+	goodby_dots.d_name.len = 2;
+	result = rem_entry_common(object, &goodby_dots, &entry);
+	reiser4_free_dentry_fsdata(&goodby_dots);
+	if (result == 0) {
+		/* the dot should be the only entry remaining at this time... */
+		assert("nikita-3400", object->i_size == 1 &&
+		       (object->i_nlink >= 0 && object->i_nlink <= 2));
+#if 0
+		/* and, together with the only name directory can have, they
+		 * provides for the last 2 remaining references. If we get
+		 * here as part of error handling during mkdir, @object
+		 * possibly has no name yet, so its nlink == 1. If we get here
+		 * from rename (targeting empty directory), it has no name
+		 * already, so its nlink == 1. */
+		assert("nikita-3401",
+		       object->i_nlink == 2 || object->i_nlink == 1);
+#endif
+
+		/* decrement nlink of directory removed ".." pointed
+		   to */
+		reiser4_del_nlink(parent, NULL, 0);
+	}
+	return result;
+}
+
+/* this is common implementation of estimate.add_entry method of
+   dir plugin
+   estimation of adding entry which supposes that entry is inserting a
+   unit into item
+*/
+reiser4_block_nr estimate_add_entry_common(const struct inode * inode)
+{
+	return estimate_one_insert_into_item(tree_by_inode(inode));
+}
+
+/* this is common implementation of estimate.rem_entry method of dir
+   plugin
+*/
+reiser4_block_nr estimate_rem_entry_common(const struct inode * inode)
+{
+	return estimate_one_item_removal(tree_by_inode(inode));
+}
+
+/* this is common implementation of estimate.unlink method of dir
+   plugin
+*/
+reiser4_block_nr
+dir_estimate_unlink_common(const struct inode * parent,
+			   const struct inode * object)
+{
+	reiser4_block_nr res;
+
+	/* hashed_rem_entry(object) */
+	res = inode_dir_plugin(object)->estimate.rem_entry(object);
+	/* del_nlink(parent) */
+	res += 2 * inode_file_plugin(parent)->estimate.update(parent);
+
+	return res;
+}
+
+/*
+ * helper for inode_ops ->lookup() and dir plugin's ->get_parent()
+ * methods: if @inode is a light-weight file, setup its credentials
+ * that are not stored in the stat-data in this case
+ */
+void check_light_weight(struct inode *inode, struct inode *parent)
+{
+	if (inode_get_flag(inode, REISER4_LIGHT_WEIGHT)) {
+		inode->i_uid = parent->i_uid;
+		inode->i_gid = parent->i_gid;
+		/* clear light-weight flag. If inode would be read by any
+		   other name, [ug]id wouldn't change. */
+		inode_clr_flag(inode, REISER4_LIGHT_WEIGHT);
+	}
+}
+
+/* looks for name specified in @dentry in directory @parent and if name is
+   found - key of object found entry points to is stored in @entry->key */
+int lookup_name(struct inode *parent,	/* inode of directory to lookup for
+					 * name in */
+		struct dentry *dentry,	/* name to look for */
+		reiser4_key * key /* place to store key */ )
+{
+	int result;
+	coord_t *coord;
+	lock_handle lh;
+	const char *name;
+	int len;
+	reiser4_dir_entry_desc entry;
+	reiser4_dentry_fsdata *fsdata;
+
+	assert("nikita-1247", parent != NULL);
+	assert("nikita-1248", dentry != NULL);
+	assert("nikita-1123", dentry->d_name.name != NULL);
+	assert("vs-1486",
+	       dentry->d_op == &get_super_private(parent->i_sb)->ops.dentry);
+
+	name = dentry->d_name.name;
+	len = dentry->d_name.len;
+
+	if (!inode_dir_plugin(parent)->is_name_acceptable(parent, name, len))
+		/* some arbitrary error code to return */
+		return RETERR(-ENAMETOOLONG);
+
+	fsdata = reiser4_get_dentry_fsdata(dentry);
+	if (IS_ERR(fsdata))
+		return PTR_ERR(fsdata);
+
+	coord = &fsdata->dec.entry_coord;
+	coord_clear_iplug(coord);
+	init_lh(&lh);
+
+	/* find entry in a directory. This is plugin method. */
+	result = find_entry(parent, dentry, &lh, ZNODE_READ_LOCK, &entry);
+	if (result == 0) {
+		/* entry was found, extract object key from it. */
+		result =
+		    WITH_COORD(coord,
+			       item_plugin_by_coord(coord)->s.dir.
+			       extract_key(coord, key));
+	}
+	done_lh(&lh);
+	return result;
+
+}
+
+/* helper for init_common(): estimate number of blocks to reserve */
+static reiser4_block_nr
+estimate_init(struct inode *parent, struct inode *object)
+{
+	reiser4_block_nr res = 0;
+
+	assert("vpf-321", parent != NULL);
+	assert("vpf-322", object != NULL);
+
+	/* hashed_add_entry(object) */
+	res += inode_dir_plugin(object)->estimate.add_entry(object);
+	/* reiser4_add_nlink(object) */
+	res += inode_file_plugin(object)->estimate.update(object);
+	/* hashed_add_entry(object) */
+	res += inode_dir_plugin(object)->estimate.add_entry(object);
+	/* reiser4_add_nlink(parent) */
+	res += inode_file_plugin(parent)->estimate.update(parent);
+
+	return 0;
+}
+
+/* helper function for init_common(). Create "." and ".." */
+static int create_dot_dotdot(struct inode *object	/* object to create dot and
+							 * dotdot for */ ,
+			     struct inode *parent /* parent of @object */ )
+{
+	int result;
+	struct dentry dots_entry;
+	reiser4_dir_entry_desc entry;
+
+	assert("nikita-688", object != NULL);
+	assert("nikita-689", S_ISDIR(object->i_mode));
+	assert("nikita-691", parent != NULL);
+
+	/* We store dot and dotdot as normal directory entries. This is
+	   not necessary, because almost all information stored in them
+	   is already in the stat-data of directory, the only thing
+	   being missed is objectid of grand-parent directory that can
+	   easily be added there as extension.
+
+	   But it is done the way it is done, because not storing dot
+	   and dotdot will lead to the following complications:
+
+	   . special case handling in ->lookup().
+	   . addition of another extension to the sd.
+	   . dependency on key allocation policy for stat data.
+
+	 */
+
+	memset(&entry, 0, sizeof entry);
+	memset(&dots_entry, 0, sizeof dots_entry);
+	entry.obj = dots_entry.d_inode = object;
+	dots_entry.d_name.name = ".";
+	dots_entry.d_name.len = 1;
+	result = add_entry_common(object, &dots_entry, NULL, &entry);
+	reiser4_free_dentry_fsdata(&dots_entry);
+
+	if (result == 0) {
+		result = reiser4_add_nlink(object, object, 0);
+		if (result == 0) {
+			entry.obj = dots_entry.d_inode = parent;
+			dots_entry.d_name.name = "..";
+			dots_entry.d_name.len = 2;
+			result = add_entry_common(object,
+						  &dots_entry, NULL, &entry);
+			reiser4_free_dentry_fsdata(&dots_entry);
+			/* if creation of ".." failed, iput() will delete
+			   object with ".". */
+			if (result == 0) {
+				result = reiser4_add_nlink(parent, object, 0);
+				if (result != 0)
+					/*
+					 * if we failed to bump i_nlink, try
+					 * to remove ".."
+					 */
+					detach_common(object, parent);
+			}
+		}
+	}
+
+	if (result != 0) {
+		/*
+		 * in the case of error, at least update stat-data so that,
+		 * ->i_nlink updates are not lingering.
+		 */
+		reiser4_update_sd(object);
+		reiser4_update_sd(parent);
+	}
+
+	return result;
+}
+
+/*
+ * return 0 iff @coord contains a directory entry for the file with the name
+ * @name.
+ */
+static int
+check_item(const struct inode *dir, const coord_t * coord, const char *name)
+{
+	item_plugin *iplug;
+	char buf[DE_NAME_BUF_LEN];
+
+	iplug = item_plugin_by_coord(coord);
+	if (iplug == NULL) {
+		warning("nikita-1135", "Cannot get item plugin");
+		print_coord("coord", coord, 1);
+		return RETERR(-EIO);
+	} else if (item_id_by_coord(coord) !=
+		   item_id_by_plugin(inode_dir_item_plugin(dir))) {
+		/* item id of current item does not match to id of items a
+		   directory is built of */
+		warning("nikita-1136", "Wrong item plugin");
+		print_coord("coord", coord, 1);
+		return RETERR(-EIO);
+	}
+	assert("nikita-1137", iplug->s.dir.extract_name);
+
+	/* Compare name stored in this entry with name we are looking for.
+
+	   NOTE-NIKITA Here should go code for support of something like
+	   unicode, code tables, etc.
+	 */
+	return !!strcmp(name, iplug->s.dir.extract_name(coord, buf));
+}
+
+static int
+check_entry(const struct inode *dir, coord_t * coord, const struct qstr *name)
+{
+	return WITH_COORD(coord, check_item(dir, coord, name->name));
+}
+
+/*
+ * argument package used by entry_actor to scan entries with identical keys.
+ */
+typedef struct entry_actor_args {
+	/* name we are looking for */
+	const char *name;
+	/* key of directory entry. entry_actor() scans through sequence of
+	 * items/units having the same key */
+	reiser4_key *key;
+	/* how many entries with duplicate key was scanned so far. */
+	int non_uniq;
+#if REISER4_USE_COLLISION_LIMIT
+	/* scan limit */
+	int max_non_uniq;
+#endif
+	/* return parameter: set to true, if ->name wasn't found */
+	int not_found;
+	/* what type of lock to take when moving to the next node during
+	 * scan */
+	znode_lock_mode mode;
+
+	/* last coord that was visited during scan */
+	coord_t last_coord;
+	/* last node locked during scan */
+	lock_handle last_lh;
+	/* inode of directory */
+	const struct inode *inode;
+} entry_actor_args;
+
+/* Function called by find_entry() to look for given name in the directory. */
+static int entry_actor(reiser4_tree * tree UNUSED_ARG /* tree being scanned */ ,
+		       coord_t * coord /* current coord */ ,
+		       lock_handle * lh /* current lock handle */ ,
+		       void *entry_actor_arg /* argument to scan */ )
+{
+	reiser4_key unit_key;
+	entry_actor_args *args;
+
+	assert("nikita-1131", tree != NULL);
+	assert("nikita-1132", coord != NULL);
+	assert("nikita-1133", entry_actor_arg != NULL);
+
+	args = entry_actor_arg;
+	++args->non_uniq;
+#if REISER4_USE_COLLISION_LIMIT
+	if (args->non_uniq > args->max_non_uniq) {
+		args->not_found = 1;
+		/* hash collision overflow. */
+		return RETERR(-EBUSY);
+	}
+#endif
+
+	/*
+	 * did we just reach the end of the sequence of items/units with
+	 * identical keys?
+	 */
+	if (!keyeq(args->key, unit_key_by_coord(coord, &unit_key))) {
+		assert("nikita-1791",
+		       keylt(args->key, unit_key_by_coord(coord, &unit_key)));
+		args->not_found = 1;
+		args->last_coord.between = AFTER_UNIT;
+		return 0;
+	}
+
+	coord_dup(&args->last_coord, coord);
+	/*
+	 * did scan just moved to the next node?
+	 */
+	if (args->last_lh.node != lh->node) {
+		int lock_result;
+
+		/*
+		 * if so, lock new node with the mode requested by the caller
+		 */
+		done_lh(&args->last_lh);
+		assert("nikita-1896", znode_is_any_locked(lh->node));
+		lock_result = longterm_lock_znode(&args->last_lh, lh->node,
+						  args->mode, ZNODE_LOCK_HIPRI);
+		if (lock_result != 0)
+			return lock_result;
+	}
+	return check_item(args->inode, coord, args->name);
+}
+
+/* Look for given @name within directory @dir.
+
+   This is called during lookup, creation and removal of directory
+   entries and on rename_common
+
+   First calculate key that directory entry for @name would have. Search
+   for this key in the tree. If such key is found, scan all items with
+   the same key, checking name in each directory entry along the way.
+*/
+int find_entry(struct inode *dir,	/* directory to scan */
+	       struct dentry *de,	/* name to search for */
+	       lock_handle * lh,	/* resulting lock handle */
+	       znode_lock_mode mode,	/* required lock mode */
+	       reiser4_dir_entry_desc * entry	/* parameters of found directory
+						 * entry */ )
+{
+	const struct qstr *name;
+	seal_t *seal;
+	coord_t *coord;
+	int result;
+	__u32 flags;
+	de_location *dec;
+	reiser4_dentry_fsdata *fsdata;
+
+	assert("nikita-1130", lh != NULL);
+	assert("nikita-1128", dir != NULL);
+
+	name = &de->d_name;
+	assert("nikita-1129", name != NULL);
+
+	/* dentry private data don't require lock, because dentry
+	   manipulations are protected by i_mutex on parent.
+
+	   This is not so for inodes, because there is no -the- parent in
+	   inode case.
+	 */
+	fsdata = reiser4_get_dentry_fsdata(de);
+	if (IS_ERR(fsdata))
+		return PTR_ERR(fsdata);
+	dec = &fsdata->dec;
+
+	coord = &dec->entry_coord;
+	coord_clear_iplug(coord);
+	seal = &dec->entry_seal;
+	/* compose key of directory entry for @name */
+	inode_dir_plugin(dir)->build_entry_key(dir, name, &entry->key);
+
+	if (seal_is_set(seal)) {
+		/* check seal */
+		result = seal_validate(seal, coord, &entry->key,
+				       lh, mode, ZNODE_LOCK_LOPRI);
+		if (result == 0) {
+			/* key was found. Check that it is really item we are
+			   looking for. */
+			result = check_entry(dir, coord, name);
+			if (result == 0)
+				return 0;
+		}
+	}
+	flags = (mode == ZNODE_WRITE_LOCK) ? CBK_FOR_INSERT : 0;
+	/*
+	 * find place in the tree where directory item should be located.
+	 */
+	result = object_lookup(dir, &entry->key, coord, lh, mode,
+			       FIND_EXACT, LEAF_LEVEL, LEAF_LEVEL, flags,
+			       NULL /*ra_info */ );
+	if (result == CBK_COORD_FOUND) {
+		entry_actor_args arg;
+
+		/* fast path: no hash collisions */
+		result = check_entry(dir, coord, name);
+		if (result == 0) {
+			seal_init(seal, coord, &entry->key);
+			dec->pos = 0;
+		} else if (result > 0) {
+			/* Iterate through all units with the same keys. */
+			arg.name = name->name;
+			arg.key = &entry->key;
+			arg.not_found = 0;
+			arg.non_uniq = 0;
+#if REISER4_USE_COLLISION_LIMIT
+			arg.max_non_uniq = max_hash_collisions(dir);
+			assert("nikita-2851", arg.max_non_uniq > 1);
+#endif
+			arg.mode = mode;
+			arg.inode = dir;
+			coord_init_zero(&arg.last_coord);
+			init_lh(&arg.last_lh);
+
+			result = iterate_tree(tree_by_inode(dir), coord, lh,
+					      entry_actor, &arg, mode, 1);
+			/* if end of the tree or extent was reached during
+			   scanning. */
+			if (arg.not_found || (result == -E_NO_NEIGHBOR)) {
+				/* step back */
+				done_lh(lh);
+
+				result = zload(arg.last_coord.node);
+				if (result == 0) {
+					coord_clear_iplug(&arg.last_coord);
+					coord_dup(coord, &arg.last_coord);
+					move_lh(lh, &arg.last_lh);
+					result = RETERR(-ENOENT);
+					zrelse(arg.last_coord.node);
+					--arg.non_uniq;
+				}
+			}
+
+			done_lh(&arg.last_lh);
+			if (result == 0)
+				seal_init(seal, coord, &entry->key);
+
+			if (result == 0 || result == -ENOENT) {
+				assert("nikita-2580", arg.non_uniq > 0);
+				dec->pos = arg.non_uniq - 1;
+			}
+		}
+	} else
+		dec->pos = -1;
+	return result;
+}
+
+/* Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/disk_format/Makefile newtree/fs/reiser4/plugin/disk_format/Makefile
--- oldtree/fs/reiser4/plugin/disk_format/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/disk_format/Makefile	2006-02-21 15:58:35.081813312 +0000
@@ -0,0 +1,5 @@
+obj-$(CONFIG_REISER4_FS) += df_plugins.o
+
+df_plugins-objs :=	\
+	disk_format40.o	\
+	disk_format.o
diff -urN oldtree/fs/reiser4/plugin/disk_format/disk_format.c newtree/fs/reiser4/plugin/disk_format/disk_format.c
--- oldtree/fs/reiser4/plugin/disk_format/disk_format.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/disk_format/disk_format.c	2006-02-21 15:58:34.582889160 +0000
@@ -0,0 +1,37 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#include "../../debug.h"
+#include "../plugin_header.h"
+#include "disk_format40.h"
+#include "disk_format.h"
+#include "../plugin.h"
+
+/* initialization of disk layout plugins */
+disk_format_plugin format_plugins[LAST_FORMAT_ID] = {
+	[FORMAT40_ID] = {
+		.h = {
+			.type_id = REISER4_FORMAT_PLUGIN_TYPE,
+			.id = FORMAT40_ID,
+			.pops = NULL,
+			.label = "reiser40",
+			.desc = "standard disk layout for reiser40",
+			.linkage = {NULL, NULL}
+		},
+		.init_format = init_format_format40,
+		.root_dir_key = root_dir_key_format40,
+		.release = release_format40,
+		.log_super = log_super_format40,
+		.check_open = check_open_format40
+	}
+};
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/disk_format/disk_format.h newtree/fs/reiser4/plugin/disk_format/disk_format.h
--- oldtree/fs/reiser4/plugin/disk_format/disk_format.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/disk_format/disk_format.h	2006-02-21 15:58:34.583889008 +0000
@@ -0,0 +1,27 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* identifiers for disk layouts, they are also used as indexes in array of disk
+   plugins */
+
+#if !defined( __REISER4_DISK_FORMAT_H__ )
+#define __REISER4_DISK_FORMAT_H__
+
+typedef enum {
+	/* standard reiser4 disk layout plugin id */
+	FORMAT40_ID,
+	LAST_FORMAT_ID
+} disk_format_id;
+
+/* __REISER4_DISK_FORMAT_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/disk_format/disk_format40.c newtree/fs/reiser4/plugin/disk_format/disk_format40.c
--- oldtree/fs/reiser4/plugin/disk_format/disk_format40.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/disk_format/disk_format40.c	2006-02-21 15:58:34.912839000 +0000
@@ -0,0 +1,566 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#include "../../debug.h"
+#include "../../dformat.h"
+#include "../../key.h"
+#include "../node/node.h"
+#include "../space/space_allocator.h"
+#include "disk_format40.h"
+#include "../plugin.h"
+#include "../../txnmgr.h"
+#include "../../jnode.h"
+#include "../../tree.h"
+#include "../../super.h"
+#include "../../wander.h"
+#include "../../inode.h"
+#include "../../ktxnmgrd.h"
+#include "../../status_flags.h"
+
+#include <linux/types.h>	/* for __u??  */
+#include <linux/fs.h>		/* for struct super_block  */
+#include <linux/buffer_head.h>
+
+/* reiser 4.0 default disk layout */
+
+/* Amount of free blocks needed to perform release_format40 when fs gets
+   mounted RW: 1 for SB, 1 for non-leaves in overwrite set, 2 for tx header
+   & tx record. */
+#define RELEASE_RESERVED 4
+
+/* functions to access fields of format40_disk_super_block */
+static __u64 get_format40_block_count(const format40_disk_super_block * sb)
+{
+	return le64_to_cpu(get_unaligned(&sb->block_count));
+}
+
+static __u64 get_format40_free_blocks(const format40_disk_super_block * sb)
+{
+	return le64_to_cpu(get_unaligned(&sb->free_blocks));
+}
+
+static __u64 get_format40_root_block(const format40_disk_super_block * sb)
+{
+	return le64_to_cpu(get_unaligned(&sb->root_block));
+}
+
+static __u16 get_format40_tree_height(const format40_disk_super_block * sb)
+{
+	return le16_to_cpu(get_unaligned(&sb->tree_height));
+}
+
+static __u64 get_format40_file_count(const format40_disk_super_block * sb)
+{
+	return le64_to_cpu(get_unaligned(&sb->file_count));
+}
+
+static __u64 get_format40_oid(const format40_disk_super_block * sb)
+{
+	return le64_to_cpu(get_unaligned(&sb->oid));
+}
+
+static __u32 get_format40_mkfs_id(const format40_disk_super_block * sb)
+{
+	return le32_to_cpu(get_unaligned(&sb->mkfs_id));
+}
+
+static __u64 get_format40_flags(const format40_disk_super_block * sb)
+{
+	return le64_to_cpu(get_unaligned(&sb->flags));
+}
+
+static format40_super_info *get_sb_info(struct super_block *super)
+{
+	return &get_super_private(super)->u.format40;
+}
+
+static int consult_diskmap(struct super_block *s)
+{
+	format40_super_info *info;
+	journal_location *jloc;
+
+	info = get_sb_info(s);
+	jloc = &get_super_private(s)->jloc;
+	/* Default format-specific locations, if there is nothing in
+	 * diskmap */
+	jloc->footer = FORMAT40_JOURNAL_FOOTER_BLOCKNR;
+	jloc->header = FORMAT40_JOURNAL_HEADER_BLOCKNR;
+	info->loc.super = FORMAT40_OFFSET / s->s_blocksize;
+#ifdef CONFIG_REISER4_BADBLOCKS
+	reiser4_get_diskmap_value(FORMAT40_PLUGIN_DISKMAP_ID, FORMAT40_JF,
+				  &jloc->footer);
+	reiser4_get_diskmap_value(FORMAT40_PLUGIN_DISKMAP_ID, FORMAT40_JH,
+				  &jloc->header);
+	reiser4_get_diskmap_value(FORMAT40_PLUGIN_DISKMAP_ID, FORMAT40_SUPER,
+				  &info->loc.super);
+#endif
+	return 0;
+}
+
+/* find any valid super block of disk_format40 (even if the first
+   super block is destroyed), will change block numbers of actual journal header/footer (jf/jh)
+   if needed */
+static struct buffer_head *find_a_disk_format40_super_block(struct super_block
+							    *s)
+{
+	struct buffer_head *super_bh;
+	format40_disk_super_block *disk_sb;
+	format40_super_info *info;
+
+	assert("umka-487", s != NULL);
+
+	info = get_sb_info(s);
+
+	super_bh = sb_bread(s, info->loc.super);
+	if (super_bh == NULL)
+		return ERR_PTR(RETERR(-EIO));
+
+	disk_sb = (format40_disk_super_block *) super_bh->b_data;
+	if (strncmp(disk_sb->magic, FORMAT40_MAGIC, sizeof(FORMAT40_MAGIC))) {
+		brelse(super_bh);
+		return ERR_PTR(RETERR(-EINVAL));
+	}
+
+	reiser4_set_block_count(s, le64_to_cpu(get_unaligned(&disk_sb->block_count)));
+	reiser4_set_data_blocks(s, le64_to_cpu(get_unaligned(&disk_sb->block_count)) -
+				le64_to_cpu(get_unaligned(&disk_sb->free_blocks)));
+	reiser4_set_free_blocks(s, le64_to_cpu(get_unaligned(&disk_sb->free_blocks)));
+
+	return super_bh;
+}
+
+/* find the most recent version of super block. This is called after journal is
+   replayed */
+static struct buffer_head *read_super_block(struct super_block *s UNUSED_ARG)
+{
+	/* Here the most recent superblock copy has to be read. However, as
+	   journal replay isn't complete, we are using
+	   find_a_disk_format40_super_block() function. */
+	return find_a_disk_format40_super_block(s);
+}
+
+static int get_super_jnode(struct super_block *s)
+{
+	reiser4_super_info_data *sbinfo = get_super_private(s);
+	jnode *sb_jnode;
+	int ret;
+
+	sb_jnode = alloc_io_head(&get_sb_info(s)->loc.super);
+
+	ret = jload(sb_jnode);
+
+	if (ret) {
+		drop_io_head(sb_jnode);
+		return ret;
+	}
+
+	pin_jnode_data(sb_jnode);
+	jrelse(sb_jnode);
+
+	sbinfo->u.format40.sb_jnode = sb_jnode;
+
+	return 0;
+}
+
+static void done_super_jnode(struct super_block *s)
+{
+	jnode *sb_jnode = get_super_private(s)->u.format40.sb_jnode;
+
+	if (sb_jnode) {
+		unpin_jnode_data(sb_jnode);
+		drop_io_head(sb_jnode);
+	}
+}
+
+typedef enum format40_init_stage {
+	NONE_DONE = 0,
+	CONSULT_DISKMAP,
+	FIND_A_SUPER,
+	INIT_JOURNAL_INFO,
+	INIT_EFLUSH,
+	INIT_STATUS,
+	JOURNAL_REPLAY,
+	READ_SUPER,
+	KEY_CHECK,
+	INIT_OID,
+	INIT_TREE,
+	JOURNAL_RECOVER,
+	INIT_SA,
+	INIT_JNODE,
+	ALL_DONE
+} format40_init_stage;
+
+static format40_disk_super_block *copy_sb(const struct buffer_head *super_bh)
+{
+	format40_disk_super_block *sb_copy;
+
+	sb_copy = kmalloc(sizeof(format40_disk_super_block), GFP_KERNEL);
+	if (sb_copy == NULL)
+		return ERR_PTR(RETERR(-ENOMEM));
+	memcpy(sb_copy, ((format40_disk_super_block *) super_bh->b_data),
+	       sizeof(format40_disk_super_block));
+	return sb_copy;
+}
+
+static int check_key_format(const format40_disk_super_block *sb_copy)
+{
+	if (!equi(REISER4_LARGE_KEY,
+		  get_format40_flags(sb_copy) & (1 << FORMAT40_LARGE_KEYS))) {
+		warning("nikita-3228", "Key format mismatch. "
+			"Only %s keys are supported.",
+			REISER4_LARGE_KEY ? "large" : "small");
+		return RETERR(-EINVAL);
+	}
+	return 0;
+}
+
+/**
+ * try_init_format40
+ * @super:
+ * @stage:
+ *
+ */
+static int try_init_format40(struct super_block *super,
+			     format40_init_stage *stage)
+{
+	int result;
+	struct buffer_head *super_bh;
+	reiser4_super_info_data *sbinfo;
+	format40_disk_super_block *sb_copy;
+	tree_level height;
+	reiser4_block_nr root_block;
+	node_plugin *nplug;
+
+	assert("vs-475", super != NULL);
+	assert("vs-474", get_super_private(super));
+
+	*stage = NONE_DONE;
+
+	result = consult_diskmap(super);
+	if (result)
+		return result;
+	*stage = CONSULT_DISKMAP;
+
+	super_bh = find_a_disk_format40_super_block(super);
+	if (IS_ERR(super_bh))
+		return PTR_ERR(super_bh);
+	brelse(super_bh);
+	*stage = FIND_A_SUPER;
+
+	/* map jnodes for journal control blocks (header, footer) to disk  */
+	result = init_journal_info(super);
+	if (result)
+		return result;
+	*stage = INIT_JOURNAL_INFO;
+
+	/* FIXME: this has to be in fill_super */
+	result = eflush_init_at(super);
+	if (result)
+		return result;
+	*stage = INIT_EFLUSH;
+
+	/* ok, we are sure that filesystem format is a format40 format */
+	/* Now check it's state */
+	result = reiser4_status_init(FORMAT40_STATUS_BLOCKNR);
+	if (result != 0 && result != -EINVAL)
+		/* -EINVAL means there is no magic, so probably just old
+		 * fs. */
+		return result;
+	*stage = INIT_STATUS;
+
+	result = reiser4_status_query(NULL, NULL);
+	if (result == REISER4_STATUS_MOUNT_WARN)
+		printk("Warning, mounting filesystem with errors\n");
+	if (result == REISER4_STATUS_MOUNT_RO) {
+		printk
+		    ("Warning, mounting filesystem with fatal errors, forcing read-only mount\n");
+		/* FIXME: here we should actually enforce read-only mount,
+		 * only it is unsupported yet. */
+	}
+
+	result = reiser4_journal_replay(super);
+	if (result)
+		return result;
+	*stage = JOURNAL_REPLAY;
+
+	super_bh = read_super_block(super);
+	if (IS_ERR(super_bh))
+		return PTR_ERR(super_bh);
+	*stage = READ_SUPER;
+
+	/* allocate and make a copy of format40_disk_super_block */
+	sb_copy = copy_sb(super_bh);
+	brelse(super_bh);
+	if (IS_ERR(sb_copy))
+		return PTR_ERR(sb_copy);
+
+	/* make sure that key format of kernel and filesyste match */
+	result = check_key_format(sb_copy);
+	if (result) {
+		kfree(sb_copy);
+		return result;
+	}
+	*stage = KEY_CHECK;
+
+	result = oid_init_allocator(super, get_format40_file_count(sb_copy),
+				    get_format40_oid(sb_copy));
+	if (result) {
+		kfree(sb_copy);
+		return result;
+	}
+	*stage = INIT_OID;
+
+	/* get things necessary to init reiser4_tree */
+	root_block = get_format40_root_block(sb_copy);
+	height = get_format40_tree_height(sb_copy);
+	nplug = node_plugin_by_id(NODE40_ID);
+
+
+	/* initialize reiser4_super_info_data */
+	sbinfo = get_super_private(super);
+	assert("", sbinfo->tree.super == super);
+	/* init reiser4_tree for the filesystem */
+	result = init_tree(&sbinfo->tree, &root_block, height, nplug);
+	if (result) {
+		kfree(sb_copy);
+		return result;
+	}
+	*stage = INIT_TREE;
+
+	/*
+	 * initialize reiser4_super_info_data with data from format40 super
+	 * block
+	 */
+	sbinfo->default_uid = 0;
+	sbinfo->default_gid = 0;
+	sbinfo->mkfs_id = get_format40_mkfs_id(sb_copy);
+	/* number of blocks in filesystem and reserved space */
+	reiser4_set_block_count(super, get_format40_block_count(sb_copy));
+	sbinfo->blocks_free = get_format40_free_blocks(sb_copy);
+	kfree(sb_copy);
+
+	sbinfo->fsuid = 0;
+	sbinfo->fs_flags |= (1 << REISER4_ADG);	/* hard links for directories
+						 * are not supported */
+	sbinfo->fs_flags |= (1 << REISER4_ONE_NODE_PLUGIN);	/* all nodes in
+								 * layout 40 are
+								 * of one
+								 * plugin */
+	/* sbinfo->tmgr is initialized already */
+
+	/* recover sb data which were logged separately from sb block */
+
+	/* NOTE-NIKITA: reiser4_journal_recover_sb_data() calls
+	 * oid_init_allocator() and reiser4_set_free_blocks() with new
+	 * data. What's the reason to call them above? */
+	result = reiser4_journal_recover_sb_data(super);
+	if (result != 0)
+		return result;
+	*stage = JOURNAL_RECOVER;
+
+	/*
+	 * Set number of used blocks.  The number of used blocks is not stored
+	 * neither in on-disk super block nor in the journal footer blocks.  At
+	 * this moment actual values of total blocks and free block counters
+	 * are set in the reiser4 super block (in-memory structure) and we can
+	 * calculate number of used blocks from them.
+	 */
+	reiser4_set_data_blocks(super,
+				reiser4_block_count(super) -
+				reiser4_free_blocks(super));
+
+#if REISER4_DEBUG
+	sbinfo->min_blocks_used = 16 /* reserved area */  +
+		2 /* super blocks */  +
+		2 /* journal footer and header */ ;
+#endif
+
+	/* init disk space allocator */
+	result = sa_init_allocator(get_space_allocator(super), super, NULL);
+	if (result)
+		return result;
+	*stage = INIT_SA;
+
+	result = get_super_jnode(super);
+	if (result == 0)
+		*stage = ALL_DONE;
+	return result;
+}
+
+/* plugin->u.format.get_ready */
+int init_format_format40(struct super_block *s, void *data UNUSED_ARG)
+{
+	int result;
+	format40_init_stage stage;
+
+	result = try_init_format40(s, &stage);
+	switch (stage) {
+	case ALL_DONE:
+		assert("nikita-3458", result == 0);
+		break;
+	case INIT_JNODE:
+		done_super_jnode(s);
+	case INIT_SA:
+		sa_destroy_allocator(get_space_allocator(s), s);
+	case JOURNAL_RECOVER:
+	case INIT_TREE:
+		done_tree(&get_super_private(s)->tree);
+	case INIT_OID:
+	case KEY_CHECK:
+	case READ_SUPER:
+	case JOURNAL_REPLAY:
+	case INIT_STATUS:
+		reiser4_status_finish();
+	case INIT_EFLUSH:
+		eflush_done_at(s);
+	case INIT_JOURNAL_INFO:
+		done_journal_info(s);
+	case FIND_A_SUPER:
+	case CONSULT_DISKMAP:
+	case NONE_DONE:
+		break;
+	default:
+		impossible("nikita-3457", "init stage: %i", stage);
+	}
+
+	if (!rofs_super(s) && reiser4_free_blocks(s) < RELEASE_RESERVED)
+		return RETERR(-ENOSPC);
+
+	return result;
+}
+
+static void pack_format40_super(const struct super_block *s, char *data)
+{
+	format40_disk_super_block *super_data =
+	    (format40_disk_super_block *) data;
+	reiser4_super_info_data *sbinfo = get_super_private(s);
+
+	assert("zam-591", data != NULL);
+
+	put_unaligned(cpu_to_le64(reiser4_free_committed_blocks(s)),
+		      &super_data->free_blocks);
+	put_unaligned(cpu_to_le64(sbinfo->tree.root_block), &super_data->root_block);
+
+	put_unaligned(cpu_to_le64(oid_next(s)), &super_data->oid);
+	put_unaligned(cpu_to_le64(oids_used(s)), &super_data->file_count);
+
+	put_unaligned(cpu_to_le16(sbinfo->tree.height), &super_data->tree_height);
+}
+
+/* plugin->u.format.log_super
+   return a jnode which should be added to transaction when the super block
+   gets logged */
+jnode *log_super_format40(struct super_block *s)
+{
+	jnode *sb_jnode;
+
+	sb_jnode = get_super_private(s)->u.format40.sb_jnode;
+
+	jload(sb_jnode);
+
+	pack_format40_super(s, jdata(sb_jnode));
+
+	jrelse(sb_jnode);
+
+	return sb_jnode;
+}
+
+/* plugin->u.format.release */
+int release_format40(struct super_block *s)
+{
+	int ret;
+	reiser4_super_info_data *sbinfo;
+
+	sbinfo = get_super_private(s);
+	assert("zam-579", sbinfo != NULL);
+
+	if (!rofs_super(s)) {
+		ret = capture_super_block(s);
+		if (ret != 0)
+			warning("vs-898", "capture_super_block failed: %d",
+				ret);
+
+		ret = txnmgr_force_commit_all(s, 1);
+		if (ret != 0)
+			warning("jmacd-74438", "txn_force failed: %d", ret);
+
+		all_grabbed2free();
+	}
+
+	sa_destroy_allocator(&sbinfo->space_allocator, s);
+	done_journal_info(s);
+	eflush_done_at(s);
+	done_super_jnode(s);
+
+	rcu_barrier();
+	done_tree(&sbinfo->tree);
+	/* call finish_rcu(), because some znode were "released" in
+	 * done_tree(). */
+	rcu_barrier();
+
+	return 0;
+}
+
+#define FORMAT40_ROOT_LOCALITY 41
+#define FORMAT40_ROOT_OBJECTID 42
+
+/* plugin->u.format.root_dir_key */
+const reiser4_key *root_dir_key_format40(const struct super_block *super
+					 UNUSED_ARG)
+{
+	static const reiser4_key FORMAT40_ROOT_DIR_KEY = {
+		.el = {
+			__constant_cpu_to_le64((FORMAT40_ROOT_LOCALITY << 4) | KEY_SD_MINOR),
+#if REISER4_LARGE_KEY
+			ON_LARGE_KEY(0ull,)
+#endif
+			__constant_cpu_to_le64(FORMAT40_ROOT_OBJECTID),
+			0ull
+		}
+	};
+
+	return &FORMAT40_ROOT_DIR_KEY;
+}
+
+/* plugin->u.format.check_open.
+   Check the opened object for validness. For now it checks for the valid oid &
+   locality only, can be improved later and it its work may depend on the mount
+   options. */
+int check_open_format40(const struct inode *object)
+{
+	oid_t max, oid;
+
+	max = oid_next(object->i_sb) - 1;
+
+	/* Check the oid. */
+	oid = get_inode_oid(object);
+	if (oid > max) {
+		warning("vpf-1360", "The object with the oid %llu "
+			"greater then the max used oid %llu found.",
+			(unsigned long long)oid, (unsigned long long)max);
+
+		return RETERR(-EIO);
+	}
+
+	/* Check the locality. */
+	oid = reiser4_inode_data(object)->locality_id;
+	if (oid > max) {
+		warning("vpf-1360", "The object with the locality %llu "
+			"greater then the max used oid %llu found.",
+			(unsigned long long)oid, (unsigned long long)max);
+
+		return RETERR(-EIO);
+	}
+
+	return 0;
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/disk_format/disk_format40.h newtree/fs/reiser4/plugin/disk_format/disk_format40.h
--- oldtree/fs/reiser4/plugin/disk_format/disk_format40.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/disk_format/disk_format40.h	2006-02-21 15:58:34.582889160 +0000
@@ -0,0 +1,99 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* this file contains:
+   - definition of ondisk super block of standart disk layout for
+     reiser 4.0 (layout 40)
+   - definition of layout 40 specific portion of in-core super block
+   - declarations of functions implementing methods of layout plugin
+     for layout 40
+   - declarations of functions used to get/set fields in layout 40 super block
+*/
+
+#ifndef __DISK_FORMAT40_H__
+#define __DISK_FORMAT40_H__
+
+/* magic for default reiser4 layout */
+#define FORMAT40_MAGIC "ReIsEr40FoRmAt"
+#define FORMAT40_OFFSET (REISER4_MASTER_OFFSET + PAGE_CACHE_SIZE)
+
+#include "../../dformat.h"
+
+#include <linux/fs.h>		/* for struct super_block  */
+
+typedef enum {
+	FORMAT40_LARGE_KEYS
+} format40_flags;
+
+/* ondisk super block for format 40. It is 512 bytes long */
+typedef struct format40_disk_super_block {
+	/*   0 */ d64 block_count;
+	/* number of block in a filesystem */
+	/*   8 */ d64 free_blocks;
+	/* number of free blocks */
+	/*  16 */ d64 root_block;
+	/* filesystem tree root block */
+	/*  24 */ d64 oid;
+	/* smallest free objectid */
+	/*  32 */ d64 file_count;
+	/* number of files in a filesystem */
+	/*  40 */ d64 flushes;
+	/* number of times super block was
+	   flushed. Needed if format 40
+	   will have few super blocks */
+	/*  48 */ d32 mkfs_id;
+	/* unique identifier of fs */
+	/*  52 */ char magic[16];
+	/* magic string ReIsEr40FoRmAt */
+	/*  68 */ d16 tree_height;
+	/* height of filesystem tree */
+	/*  70 */ d16 formatting_policy;
+	/*  72 */ d64 flags;
+	/*  72 */ char not_used[432];
+} format40_disk_super_block;
+
+/* format 40 specific part of reiser4_super_info_data */
+typedef struct format40_super_info {
+/*	format40_disk_super_block actual_sb; */
+	jnode *sb_jnode;
+	struct {
+		reiser4_block_nr super;
+	} loc;
+} format40_super_info;
+
+/* Defines for journal header and footer respectively. */
+#define FORMAT40_JOURNAL_HEADER_BLOCKNR \
+	((REISER4_MASTER_OFFSET / PAGE_CACHE_SIZE) + 3)
+
+#define FORMAT40_JOURNAL_FOOTER_BLOCKNR \
+	((REISER4_MASTER_OFFSET / PAGE_CACHE_SIZE) + 4)
+
+#define FORMAT40_STATUS_BLOCKNR \
+	((REISER4_MASTER_OFFSET / PAGE_CACHE_SIZE) + 5)
+
+/* Diskmap declarations */
+#define FORMAT40_PLUGIN_DISKMAP_ID ((REISER4_FORMAT_PLUGIN_TYPE<<16) | (FORMAT40_ID))
+#define FORMAT40_SUPER 1
+#define FORMAT40_JH 2
+#define FORMAT40_JF 3
+
+/* declarations of functions implementing methods of layout plugin for
+   format 40. The functions theirself are in disk_format40.c */
+int init_format_format40(struct super_block *, void *data);
+const reiser4_key *root_dir_key_format40(const struct super_block *);
+int release_format40(struct super_block *s);
+jnode *log_super_format40(struct super_block *s);
+int check_open_format40(const struct inode *object);
+
+/* __DISK_FORMAT40_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/fibration.c newtree/fs/reiser4/plugin/fibration.c
--- oldtree/fs/reiser4/plugin/fibration.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/fibration.c	2006-02-21 15:58:34.583889008 +0000
@@ -0,0 +1,174 @@
+/* Copyright 2004 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Directory fibrations */
+
+/*
+ * Suppose we have a directory tree with sources of some project. During
+ * compilation .o files are created within this tree. This makes access
+ * to the original source files less efficient, because source files are
+ * now "diluted" by object files: default directory plugin uses prefix
+ * of a file name as a part of the key for directory entry (and this
+ * part is also inherited by the key of file body). This means that
+ * foo.o will be located close to foo.c and foo.h in the tree.
+ *
+ * To avoid this effect directory plugin fill highest 7 (unused
+ * originally) bits of the second component of the directory entry key
+ * by bit-pattern depending on the file name (see
+ * fs/reiser4/kassign.c:build_entry_key_common()). These bits are called
+ * "fibre". Fibre of the file name key is inherited by key of stat data
+ * and keys of file body (in the case of REISER4_LARGE_KEY).
+ *
+ * Fibre for a given file is chosen by per-directory fibration
+ * plugin. Names within given fibre are ordered lexicographically.
+ */
+
+#include "../debug.h"
+#include "plugin_header.h"
+#include "plugin.h"
+#include "../super.h"
+#include "../inode.h"
+
+#include <linux/types.h>
+
+static const int fibre_shift = 57;
+
+#define FIBRE_NO(n) (((__u64)(n)) << fibre_shift)
+
+/*
+ * Trivial fibration: all files of directory are just ordered
+ * lexicographically.
+ */
+static __u64 fibre_trivial(const struct inode *dir, const char *name, int len)
+{
+	return FIBRE_NO(0);
+}
+
+/*
+ * dot-o fibration: place .o files after all others.
+ */
+static __u64 fibre_dot_o(const struct inode *dir, const char *name, int len)
+{
+	/* special treatment for .*\.o */
+	if (len > 2 && name[len - 1] == 'o' && name[len - 2] == '.')
+		return FIBRE_NO(1);
+	else
+		return FIBRE_NO(0);
+}
+
+/*
+ * ext.1 fibration: subdivide directory into 128 fibrations one for each
+ * 7bit extension character (file "foo.h" goes into fibre "h"), plus
+ * default fibre for the rest.
+ */
+static __u64 fibre_ext_1(const struct inode *dir, const char *name, int len)
+{
+	if (len > 2 && name[len - 2] == '.')
+		return FIBRE_NO(name[len - 1]);
+	else
+		return FIBRE_NO(0);
+}
+
+/*
+ * ext.3 fibration: try to separate files with different 3-character
+ * extensions from each other.
+ */
+static __u64 fibre_ext_3(const struct inode *dir, const char *name, int len)
+{
+	if (len > 4 && name[len - 4] == '.')
+		return FIBRE_NO(name[len - 3] + name[len - 2] + name[len - 1]);
+	else
+		return FIBRE_NO(0);
+}
+
+static int change_fibration(struct inode *inode, reiser4_plugin * plugin)
+{
+	int result;
+
+	assert("nikita-3503", inode != NULL);
+	assert("nikita-3504", plugin != NULL);
+
+	assert("nikita-3505", is_reiser4_inode(inode));
+	assert("nikita-3506", inode_dir_plugin(inode) != NULL);
+	assert("nikita-3507",
+	       plugin->h.type_id == REISER4_FIBRATION_PLUGIN_TYPE);
+
+	result = 0;
+	if (inode_fibration_plugin(inode) == NULL ||
+	    inode_fibration_plugin(inode)->h.id != plugin->h.id) {
+		if (is_dir_empty(inode) == 0)
+			result =
+			    plugin_set_fibration(&reiser4_inode_data(inode)->
+						 pset, &plugin->fibration);
+		else
+			result = RETERR(-ENOTEMPTY);
+
+	}
+	return result;
+}
+
+static reiser4_plugin_ops fibration_plugin_ops = {
+	.init = NULL,
+	.load = NULL,
+	.save_len = NULL,
+	.save = NULL,
+	.change = change_fibration
+};
+
+/* fibration plugins */
+fibration_plugin fibration_plugins[LAST_FIBRATION_ID] = {
+	[FIBRATION_LEXICOGRAPHIC] = {
+		.h = {
+			.type_id = REISER4_FIBRATION_PLUGIN_TYPE,
+			.id = FIBRATION_LEXICOGRAPHIC,
+			.pops = &fibration_plugin_ops,
+			.label = "lexicographic",
+			.desc = "no fibration",
+			.linkage = {NULL, NULL}
+		},
+		.fibre = fibre_trivial
+	},
+	[FIBRATION_DOT_O] = {
+		.h = {
+			.type_id = REISER4_FIBRATION_PLUGIN_TYPE,
+			.id = FIBRATION_DOT_O,
+			.pops = &fibration_plugin_ops,
+			.label = "dot-o",
+			.desc = "fibrate .o files separately",
+			.linkage = {NULL, NULL}
+		},
+		.fibre = fibre_dot_o
+	},
+	[FIBRATION_EXT_1] = {
+		.h = {
+			.type_id = REISER4_FIBRATION_PLUGIN_TYPE,
+			.id = FIBRATION_EXT_1,
+			.pops = &fibration_plugin_ops,
+			.label = "ext-1",
+			.desc = "fibrate file by single character extension",
+			.linkage = {NULL, NULL}
+		},
+		.fibre = fibre_ext_1
+	},
+	[FIBRATION_EXT_3] = {
+		.h = {
+			.type_id = REISER4_FIBRATION_PLUGIN_TYPE,
+			.id = FIBRATION_EXT_3,
+			.pops = &fibration_plugin_ops,
+			.label = "ext-3",
+			.desc = "fibrate file by three character extension",
+			.linkage = {NULL, NULL}
+		},
+		.fibre = fibre_ext_3
+	}
+};
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * End:
+ */
diff -urN oldtree/fs/reiser4/plugin/fibration.h newtree/fs/reiser4/plugin/fibration.h
--- oldtree/fs/reiser4/plugin/fibration.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/fibration.h	2006-02-21 15:58:34.583889008 +0000
@@ -0,0 +1,37 @@
+/* Copyright 2004 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Fibration plugin used by hashed directory plugin to segment content
+ * of directory. See fs/reiser4/plugin/fibration.c for more on this. */
+
+#if !defined( __FS_REISER4_PLUGIN_FIBRATION_H__ )
+#define __FS_REISER4_PLUGIN_FIBRATION_H__
+
+#include "plugin_header.h"
+
+typedef struct fibration_plugin {
+	/* generic fields */
+	plugin_header h;
+
+	 __u64(*fibre) (const struct inode * dir, const char *name, int len);
+} fibration_plugin;
+
+typedef enum {
+	FIBRATION_LEXICOGRAPHIC,
+	FIBRATION_DOT_O,
+	FIBRATION_EXT_1,
+	FIBRATION_EXT_3,
+	LAST_FIBRATION_ID
+} reiser4_fibration_id;
+
+/* __FS_REISER4_PLUGIN_FIBRATION_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/file/Makefile newtree/fs/reiser4/plugin/file/Makefile
--- oldtree/fs/reiser4/plugin/file/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/file/Makefile	2006-02-21 15:58:35.081813312 +0000
@@ -0,0 +1,7 @@
+obj-$(CONFIG_REISER4_FS) += file_plugins.o
+
+file_plugins-objs :=		\
+	file.o			\
+	tail_conversion.o	\
+	symlink.o		\
+	cryptcompress.o
diff -urN oldtree/fs/reiser4/plugin/file/cryptcompress.c newtree/fs/reiser4/plugin/file/cryptcompress.c
--- oldtree/fs/reiser4/plugin/file/cryptcompress.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/file/cryptcompress.c	2006-02-21 15:58:35.485751904 +0000
@@ -0,0 +1,3916 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* This file contains methods of the reiser4 cryptcompress object plugin
+   (see http://www.namesys.com/cryptcompress_design.html for details). */
+
+#include "../../page_cache.h"
+#include "../../inode.h"
+#include "../cluster.h"
+#include "../object.h"
+#include "../../tree_walk.h"
+#include "funcs.h"
+#include "cryptcompress.h"
+
+#include <asm/scatterlist.h>
+#include <linux/pagevec.h>
+#include <asm/uaccess.h>
+#include <linux/swap.h>
+#include <linux/writeback.h>
+#include <linux/random.h>
+
+/* get cryptcompress specific portion of inode */
+cryptcompress_info_t *cryptcompress_inode_data(const struct inode *inode)
+{
+	return &reiser4_inode_data(inode)->file_plugin_data.cryptcompress_info;
+}
+
+/* plugin->u.file.init_inode_data */
+void
+init_inode_data_cryptcompress(struct inode *inode,
+			      reiser4_object_create_data * crd, int create)
+{
+	cryptcompress_info_t *data;
+
+	data = cryptcompress_inode_data(inode);
+	assert("edward-685", data != NULL);
+
+	memset(data, 0, sizeof(*data));
+
+	init_rwsem(&data->lock);
+	init_inode_ordering(inode, crd, create);
+}
+
+#if REISER4_DEBUG
+int crc_inode_ok(struct inode *inode)
+{
+	if (cluster_shift_ok(inode_cluster_shift(inode)))
+		return 1;
+	assert("edward-686", 0);
+	return 0;
+}
+#endif
+
+static int check_cryptcompress(struct inode *inode)
+{
+	int result = 0;
+	assert("edward-1307", inode_compression_plugin(inode) != NULL);
+
+	if (inode_cluster_size(inode) < PAGE_CACHE_SIZE) {
+		warning("edward-1331",
+			"%s clusters are unsupported",
+			inode_cluster_plugin(inode)->h.label);
+		return RETERR(-EINVAL);
+	}
+
+	/* FIXME-EDWARD: init? or check? */
+	if (inode_compression_plugin(inode)->init)
+		result = inode_compression_plugin(inode)->init();
+	return result;
+}
+
+crypto_stat_t * inode_crypto_stat (struct inode * inode)
+{
+	assert("edward-90", inode != NULL);
+	assert("edward-91", reiser4_inode_data(inode) != NULL);
+	return cryptcompress_inode_data(inode)->crypt;
+}
+
+static void
+set_inode_crypto_stat (struct inode * inode, crypto_stat_t * stat)
+{
+	cryptcompress_inode_data(inode)->crypt = stat;
+}
+
+crypto_stat_t * alloc_crypto_stat (struct inode * inode)
+{
+	crypto_stat_t * info;
+	int fipsize;
+
+	assert("edward-1421", 0);
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return ERR_PTR(-ENOMEM);
+	memset(info, 0, sizeof (*info));
+	fipsize = inode_digest_plugin(inode)->fipsize;
+	info->keyid = kmalloc(fipsize, GFP_KERNEL);
+	if (!info->keyid) {
+		kfree(info);
+		return ERR_PTR(-ENOMEM);
+	}
+	return info;
+}
+
+static int
+alloc_crypto_tfms(plugin_set * pset, crypto_stat_t * info)
+{
+	struct crypto_tfm * ret = NULL;
+	cipher_plugin * cplug = pset->cipher;
+	digest_plugin * dplug = pset->digest;
+
+	assert("edward-1363", info != NULL);
+	assert("edward-414", cplug != NULL);
+	assert("edward-415", dplug != NULL);
+
+	if (cplug->alloc) {
+		ret = cplug->alloc();
+		if (ret == NULL) {
+			warning("edward-1364",
+				"Can not allocate info for %s\n",
+				cplug->h.desc);
+			return RETERR(-EINVAL);
+		}
+	}
+	info_set_tfm(info, CIPHER_TFM, ret);
+	if (dplug->alloc) {
+		ret = dplug->alloc();
+		if (ret == NULL) {
+			warning("edward-1365",
+				"Can not allocate info for %s\n",
+				dplug->h.desc);
+			goto err;
+		}
+	}
+	info_set_tfm(info, DIGEST_TFM, ret);
+	return 0;
+ err:
+	if (cplug->free) {
+		cplug->free(info->tfma[CIPHER_TFM].tfm);
+		info_set_tfm(info, CIPHER_TFM, NULL);
+	}
+	return RETERR(-EINVAL);
+}
+
+static void
+free_crypto_tfms(crypto_stat_t * info)
+{
+	assert("edward-1366", info != NULL);
+	if (!info_cipher_tfm(info))
+		return;
+	info_cipher_plugin(info)->free(info_cipher_tfm(info));
+	info_set_tfm(info, CIPHER_TFM, NULL);
+	info_digest_plugin(info)->free(info_digest_tfm(info));
+	info_set_tfm(info, DIGEST_TFM, NULL);
+	return;
+}
+
+static int create_keyid (crypto_stat_t * info, crypto_data_t * data)
+{
+	int ret = -ENOMEM;
+	size_t blk, pad;
+	__u8 * dmem;
+	__u8 * cmem;
+	struct crypto_tfm * dtfm;
+	struct crypto_tfm * ctfm;
+	struct scatterlist sg;
+
+	assert("edward-1422", 0);
+	assert("edward-1367", info != NULL);
+	assert("edward-1368", info->keyid != NULL);
+
+	dtfm = info_digest_tfm(info);
+	ctfm = info_cipher_tfm(info);
+
+	dmem = kmalloc((size_t)crypto_tfm_alg_digestsize(dtfm),
+			       GFP_KERNEL);
+	if (!dmem)
+		goto exit1;
+
+	blk = crypto_tfm_alg_blocksize(ctfm);
+
+	pad = data->keyid_size % blk;
+	pad = (pad ? blk - pad : 0);
+
+	cmem = kmalloc((size_t)data->keyid_size + pad, GFP_KERNEL);
+	if (!cmem)
+		goto exit2;
+	memcpy(cmem, data->keyid, data->keyid_size);
+	memset(cmem + data->keyid_size, 0, pad);
+
+	sg.page = virt_to_page(cmem);
+	sg.offset = offset_in_page(cmem);
+	sg.length = data->keyid_size + pad;
+
+	ret = crypto_cipher_encrypt(ctfm, &sg, &sg, data->keyid_size + pad);
+	if (ret) {
+		warning("edward-1369",
+			"encryption failed flags=%x\n", ctfm->crt_flags);
+		goto exit3;
+	}
+	crypto_digest_init (dtfm);
+	crypto_digest_update (dtfm, &sg, 1);
+	crypto_digest_final (dtfm, dmem);
+	memcpy(info->keyid, dmem, info_digest_plugin(info)->fipsize);
+ exit3:
+	kfree(cmem);
+ exit2:
+	kfree(dmem);
+ exit1:
+	return ret;
+}
+
+static void destroy_keyid(crypto_stat_t * info)
+{
+	assert("edward-1370", info != NULL);
+	assert("edward-1371", info->keyid != NULL);
+	kfree(info->keyid);
+	return;
+}
+
+static void free_crypto_stat (crypto_stat_t * info)
+{
+	assert("edward-1372", info != NULL);
+
+	free_crypto_tfms(info);
+	destroy_keyid(info);
+	kfree(info);
+}
+
+static void instantiate_crypto_stat(crypto_stat_t * info)
+{
+	assert("edward-1373", info != NULL);
+	assert("edward-1374", info->inst == 0);
+	info->inst = 1;
+}
+
+static void uninstantiate_crypto_stat(crypto_stat_t * info)
+{
+	assert("edward-1375", info != NULL);
+	info->inst = 0;
+}
+
+int crypto_stat_instantiated(crypto_stat_t * info)
+{
+	return info->inst;
+}
+
+static int inode_has_cipher_key(struct inode * inode)
+{
+	assert("edward-1376", inode != NULL);
+	return inode_crypto_stat(inode) &&
+		crypto_stat_instantiated(inode_crypto_stat(inode));
+}
+
+static void inode_free_crypto_stat (struct inode * inode)
+{
+	uninstantiate_crypto_stat(inode_crypto_stat(inode));
+	free_crypto_stat(inode_crypto_stat(inode));
+}
+
+/* Instantiate a crypto-stat represented by low-lewel @data for the @object */
+crypto_stat_t *
+create_crypto_stat(struct inode * object, crypto_data_t * data)
+{
+	int ret;
+	crypto_stat_t * info;
+
+	assert("edward-1377", data != NULL);
+	assert("edward-1378", need_cipher(object));
+
+	if (inode_file_plugin(object) !=
+	    file_plugin_by_id(DIRECTORY_FILE_PLUGIN_ID))
+		return ERR_PTR(-EINVAL);
+
+	info = alloc_crypto_stat(object);
+	if (IS_ERR(info))
+		return info;
+	ret = alloc_crypto_tfms(reiser4_inode_data(object)->pset, info);
+	if (ret)
+		goto err;
+	/* Someone can change plugins of the host, so
+	   we keep the original ones it the crypto-stat. */
+	info_set_cipher_plugin(info, inode_cipher_plugin(object));
+	info_set_digest_plugin(info, inode_digest_plugin(object));
+
+	ret = crypto_cipher_setkey(info_cipher_tfm(info),
+				   data->key,
+				   data->keysize);
+	if (ret) {
+		warning("edward-1379",
+			"setkey failed flags=%x\n",
+			info_cipher_tfm(info)->crt_flags);
+		goto err;
+	}
+	info->keysize = data->keysize;
+	ret = create_keyid(info, data);
+	if (ret)
+		goto err;
+	instantiate_crypto_stat(info);
+	return info;
+ err:
+	free_crypto_stat(info);
+ 	return ERR_PTR(ret);
+}
+
+static void load_crypto_stat(crypto_stat_t * info)
+{
+	assert("edward-1380", info != NULL);
+	inc_keyload_count(info);
+}
+
+static void
+unload_crypto_stat(struct inode * inode)
+{
+	crypto_stat_t * info = inode_crypto_stat(inode);
+	assert("edward-1381", info->keyload_count > 0);
+
+	dec_keyload_count(inode_crypto_stat(inode));
+	if (info->keyload_count == 0)
+		inode_free_crypto_stat(inode);
+}
+
+void attach_crypto_stat(struct inode * inode, crypto_stat_t * info)
+{
+	assert("edward-1382", inode != NULL);
+	assert("edward-1383", info != NULL);
+	assert("edward-1384", inode_crypto_stat(inode) == NULL);
+
+	set_inode_crypto_stat(inode, info);
+	load_crypto_stat(info);
+}
+
+void detach_crypto_stat(struct inode * inode)
+{
+	assert("edward-1385", inode != NULL);
+	assert("edward-1386", host_allows_crypto_stat(inode));
+
+	if (inode_crypto_stat(inode))
+		unload_crypto_stat(inode);
+	set_inode_crypto_stat(inode, NULL);
+}
+
+static int keyid_eq(crypto_stat_t * child, crypto_stat_t * parent)
+{
+	return !memcmp(child->keyid, parent->keyid, info_digest_plugin(parent)->fipsize);
+}
+
+int can_inherit_crypto_crc(struct inode *child, struct inode *parent)
+{
+	if (!need_cipher(child))
+		return 0;
+	if (!inode_crypto_stat(child))
+		/* the file being created */
+		return 1;
+	/* the file being looked up */
+	if (!inode_crypto_stat(parent))
+		return 0;
+	return (inode_cipher_plugin(child) == inode_cipher_plugin(parent) &&
+		inode_digest_plugin(child) == inode_digest_plugin(parent) &&
+		inode_crypto_stat(child)->keysize == inode_crypto_stat(parent)->keysize &&
+		keyid_eq(inode_crypto_stat(child), inode_crypto_stat(parent)));
+}
+
+int need_cipher(struct inode * inode)
+{
+	return inode_cipher_plugin(inode) !=
+		cipher_plugin_by_id(NONE_CIPHER_ID);
+}
+
+/* returns true, if crypto stat can be attached to the @host */
+int host_allows_crypto_stat(struct inode * host)
+{
+	int ret;
+	file_plugin * fplug = inode_file_plugin(host);
+
+	switch (fplug->h.id) {
+	case CRC_FILE_PLUGIN_ID:
+		ret = 1;
+		break;
+	default:
+		ret = 0;
+	}
+	return ret;
+}
+
+static int inode_set_crypto(struct inode * object)
+{
+	reiser4_inode * info;
+	if (!inode_crypto_stat(object)) {
+		if (need_cipher(object))
+			return RETERR(-EINVAL);
+		/* the file is not to be encrypted */
+		return 0;
+	}
+	info = reiser4_inode_data(object);
+	info->extmask |= (1 << CRYPTO_STAT);
+	info->plugin_mask |= (1 << PSET_CIPHER) | (1 << PSET_DIGEST);
+ 	return 0;
+}
+
+static int
+inode_set_compression(struct inode * object)
+{
+	int result = 0;
+	compression_plugin * cplug;
+	reiser4_inode * info = reiser4_inode_data(object);
+
+	cplug = inode_compression_plugin(object);
+
+	if (cplug->init != NULL) {
+		result = cplug->init();
+		if (result)
+			return result;
+	}
+	info->plugin_mask |= (1 << PSET_COMPRESSION);
+
+	return 0;
+}
+
+static void
+inode_set_compression_mode(struct inode * object)
+{
+	reiser4_inode * info = reiser4_inode_data(object);
+
+	info->plugin_mask |= (1 << PSET_COMPRESSION_MODE);
+	return;
+}
+
+static int inode_set_cluster(struct inode *object)
+{
+	reiser4_inode *info;
+	cluster_plugin *cplug;
+
+	assert("edward-696", object != NULL);
+
+	info = reiser4_inode_data(object);
+	cplug = inode_cluster_plugin(object);
+
+	if (cplug->shift < PAGE_CACHE_SHIFT) {
+		warning("edward-1320",
+			"Can not support %p clusters (less then page size)",
+			cplug->h.label);
+		return RETERR(-EINVAL);
+	}
+	info->plugin_mask |= (1 << PSET_CLUSTER);
+	return 0;
+}
+
+/* plugin->create() method for cryptcompress files
+
+. install plugins
+. attach crypto info if specified
+. attach compression info if specified
+. attach cluster info
+*/
+int
+create_cryptcompress(struct inode *object, struct inode *parent,
+		     reiser4_object_create_data * data)
+{
+	int result;
+	reiser4_inode *info;
+
+	assert("edward-23", object != NULL);
+	assert("edward-24", parent != NULL);
+	assert("edward-30", data != NULL);
+	assert("edward-26", inode_get_flag(object, REISER4_NO_SD));
+	assert("edward-27", data->id == CRC_FILE_PLUGIN_ID);
+
+	info = reiser4_inode_data(object);
+
+	assert("edward-29", info != NULL);
+
+	/* set file bit */
+	info->plugin_mask |= (1 << PSET_FILE);
+
+	/* set crypto */
+	result = inode_set_crypto(object);
+	if (result)
+		goto error;
+	/* set compression */
+	result = inode_set_compression(object);
+	if (result)
+		goto error;
+	inode_set_compression_mode(object);
+
+	/* set cluster info */
+	result = inode_set_cluster(object);
+	if (result)
+		goto error;
+	/* set plugin mask */
+	info->extmask |= (1 << PLUGIN_STAT);
+
+	/* save everything in disk stat-data */
+	result = write_sd_by_inode_common(object);
+	if (!result)
+		return 0;
+ error:
+	detach_crypto_stat(object);
+	return result;
+}
+
+int open_cryptcompress(struct inode * inode, struct file * file)
+{
+	struct inode * parent;
+
+	assert("edward-1394", inode != NULL);
+	assert("edward-1395", file != NULL);
+	assert("edward-1396", file != NULL);
+	assert("edward-1397", file->f_dentry->d_inode == inode);
+	assert("edward-1398", file->f_dentry->d_parent != NULL);
+	assert("edward-1399", file->f_dentry->d_parent->d_inode != NULL);
+	assert("edward-698",
+	       inode_file_plugin(inode) ==
+	       file_plugin_by_id(CRC_FILE_PLUGIN_ID));
+
+	if (!need_cipher(inode))
+		/* the file is not to be ciphered */
+		return 0;
+	parent = file->f_dentry->d_parent->d_inode;
+	if (!inode_has_cipher_key(inode))
+		return RETERR(-EINVAL);
+	return 0;
+}
+
+static unsigned int
+cipher_blocksize(struct inode * inode)
+{
+	assert("edward-758", need_cipher(inode));
+	assert("edward-1400", inode_crypto_stat(inode) != NULL);
+	return crypto_tfm_alg_blocksize
+		(info_cipher_tfm(inode_crypto_stat(inode)));
+}
+
+/* returns translated offset */
+static loff_t inode_scaled_offset (struct inode * inode,
+				   const loff_t src_off /* input offset */)
+{
+	assert("edward-97", inode != NULL);
+
+	if (!need_cipher(inode) ||
+	    src_off == get_key_offset(min_key()) ||
+	    src_off == get_key_offset(max_key()))
+		return src_off;
+
+	return inode_cipher_plugin(inode)->scale(inode,
+						 cipher_blocksize(inode),
+						 src_off);
+}
+
+/* returns disk cluster size */
+size_t inode_scaled_cluster_size(struct inode * inode)
+{
+	assert("edward-110", inode != NULL);
+
+	return inode_scaled_offset(inode, inode_cluster_size(inode));
+}
+
+static int new_cluster(reiser4_cluster_t * clust, struct inode *inode)
+{
+	return (clust_to_off(clust->index, inode) >= inode->i_size);
+}
+
+/* set number of cluster pages */
+static void set_cluster_nrpages(reiser4_cluster_t * clust, struct inode *inode)
+{
+	reiser4_slide_t *win;
+
+	assert("edward-180", clust != NULL);
+	assert("edward-1040", inode != NULL);
+
+	win = clust->win;
+	if (!win) {
+		/* FIXME-EDWARD: i_size should be protected */
+		clust->nr_pages =
+		    count_to_nrpages(fsize_to_count(clust, inode));
+		return;
+	}
+	assert("edward-1176", clust->op != PCL_UNKNOWN);
+	assert("edward-1064", win->off + win->count + win->delta != 0);
+
+	if (win->stat == HOLE_WINDOW &&
+	    win->off == 0 && win->count == inode_cluster_size(inode)) {
+		/* special case: we start write hole from fake cluster */
+		clust->nr_pages = 0;
+		return;
+	}
+	clust->nr_pages =
+	    count_to_nrpages(max_count(win->off + win->count + win->delta,
+				       fsize_to_count(clust, inode)));
+	return;
+}
+
+/* plugin->key_by_inode() */
+/* see plugin/plugin.h for details */
+int
+key_by_inode_cryptcompress(struct inode *inode, loff_t off, reiser4_key * key)
+{
+	loff_t clust_off;
+
+	assert("edward-64", inode != 0);
+	//      assert("edward-112", ergo(off != get_key_offset(max_key()), !off_to_cloff(off, inode)));
+	/* don't come here with other offsets */
+
+	clust_off =
+	    (off ==
+	     get_key_offset(max_key())? get_key_offset(max_key()) :
+	     off_to_clust_to_off(off, inode));
+
+	key_by_inode_and_offset_common(inode, 0, key);
+	set_key_offset(key,
+		       (__u64) (!inode_crypto_stat(inode) ? clust_off :
+				inode_scaled_offset(inode, clust_off)));
+	return 0;
+}
+
+/* plugin->flow_by_inode */
+int
+flow_by_inode_cryptcompress(struct inode *inode /* file to build flow for */ ,
+			    const char __user *buf /* user level buffer */ ,
+			    int user	/* 1 if @buf is of user space, 0 - if it is
+					   kernel space */ ,
+			    loff_t size /* buffer size */ ,
+			    loff_t off /* offset to start io from */ ,
+			    rw_op op /* READ or WRITE */ ,
+			    flow_t * f /* resulting flow */ )
+{
+	assert("edward-436", f != NULL);
+	assert("edward-149", inode != NULL);
+	assert("edward-150", inode_file_plugin(inode) != NULL);
+	assert("edward-151",
+	       inode_file_plugin(inode)->key_by_inode ==
+	       key_by_inode_cryptcompress);
+
+	f->length = size;
+	memcpy(&f->data, &buf, sizeof(buf));
+	f->user = user;
+	f->op = op;
+
+	if (op == WRITE_OP && user == 1)
+		return 0;
+	return key_by_inode_cryptcompress(inode, off, &f->key);
+}
+
+static int
+crc_hint_validate(hint_t * hint, const reiser4_key * key,
+		  znode_lock_mode lock_mode)
+{
+	coord_t *coord;
+
+	assert("edward-704", hint != NULL);
+	assert("edward-1089", !hint->ext_coord.valid);
+	assert("edward-706", hint->lh.owner == NULL);
+
+	coord = &hint->ext_coord.coord;
+
+	if (!hint || !hint_is_set(hint) || hint->mode != lock_mode)
+		/* hint either not set or set by different operation */
+		return RETERR(-E_REPEAT);
+
+	if (get_key_offset(key) != hint->offset)
+		/* hint is set for different key */
+		return RETERR(-E_REPEAT);
+
+	assert("edward-707", schedulable());
+
+	return seal_validate(&hint->seal, &hint->ext_coord.coord,
+			     key, &hint->lh, lock_mode, ZNODE_LOCK_LOPRI);
+}
+
+static int reserve4cluster(struct inode *inode, reiser4_cluster_t *clust)
+{
+	int result = 0;
+
+	assert("edward-965", schedulable());
+	assert("edward-439", inode != NULL);
+	assert("edward-440", clust != NULL);
+	assert("edward-441", clust->pages != NULL);
+	assert("edward-1261", get_current_context()->grabbed_blocks == 0);
+
+	if (clust->nr_pages == 0) {
+		assert("edward-1152", clust->win != NULL);
+		assert("edward-1153", clust->win->stat == HOLE_WINDOW);
+		/* don't reserve space for fake disk clusteer */
+		return 0;
+	}
+	assert("edward-442", jprivate(clust->pages[0]) != NULL);
+
+	result = reiser4_grab_space_force(estimate_insert_cluster(inode) +
+					  estimate_update_cluster(inode),
+ 					  BA_CAN_COMMIT);
+	if (result)
+		return result;
+	clust->reserved = 1;
+	grabbed2cluster_reserved(estimate_insert_cluster(inode) +
+				 estimate_update_cluster(inode));
+#if REISER4_DEBUG
+	clust->reserved_prepped = estimate_update_cluster(inode);
+	clust->reserved_unprepped = estimate_insert_cluster(inode);
+#endif
+	/* there can be space grabbed by txnmgr_force_commit_all */
+	all_grabbed2free();
+	return 0;
+}
+
+static void
+free_reserved4cluster(struct inode *inode, reiser4_cluster_t * clust, int count)
+{
+	assert("edward-967", clust->reserved == 1);
+
+	cluster_reserved2free(count);
+	clust->reserved = 0;
+}
+
+/* The core search procedure.
+   If returned value is not cbk_errored, current znode is locked */
+static int find_cluster_item(hint_t * hint, const reiser4_key * key,	/* key of the item we are
+									   looking for */
+			     znode_lock_mode lock_mode /* which lock */ ,
+			     ra_info_t * ra_info, lookup_bias bias, __u32 flags)
+{
+	int result;
+	reiser4_key ikey;
+	coord_t *coord = &hint->ext_coord.coord;
+	coord_t orig = *coord;
+
+	assert("edward-152", hint != NULL);
+
+	if (hint->ext_coord.valid == 0) {
+		result = crc_hint_validate(hint, key, lock_mode);
+		if (result == -E_REPEAT)
+			goto traverse_tree;
+		else if (result) {
+			assert("edward-1216", 0);
+			return result;
+		}
+		hint->ext_coord.valid = 1;
+	}
+	assert("edward-709", znode_is_any_locked(coord->node));
+
+	/* In-place lookup is going here, it means we just need to
+	   check if next item of the @coord match to the @keyhint) */
+
+	if (equal_to_rdk(coord->node, key)) {
+		result = goto_right_neighbor(coord, &hint->lh);
+		if (result == -E_NO_NEIGHBOR) {
+			assert("edward-1217", 0);
+			return RETERR(-EIO);
+		}
+		if (result)
+			return result;
+		assert("edward-1218", equal_to_ldk(coord->node, key));
+	} else {
+		coord->item_pos++;
+		coord->unit_pos = 0;
+		coord->between = AT_UNIT;
+	}
+	result = zload(coord->node);
+	if (result)
+		return result;
+	assert("edward-1219", !node_is_empty(coord->node));
+
+	if (!coord_is_existing_item(coord)) {
+		zrelse(coord->node);
+		goto not_found;
+	}
+	item_key_by_coord(coord, &ikey);
+	zrelse(coord->node);
+	if (!keyeq(key, &ikey))
+		goto not_found;
+	return CBK_COORD_FOUND;
+
+      not_found:
+	assert("edward-1220", coord->item_pos > 0);
+	//coord->item_pos--;
+	/* roll back */
+	*coord = orig;
+	ON_DEBUG(coord_update_v(coord));
+	return CBK_COORD_NOTFOUND;
+
+      traverse_tree:
+	assert("edward-713", hint->lh.owner == NULL);
+	assert("edward-714", schedulable());
+
+	unset_hint(hint);
+	coord_init_zero(coord);
+	result = coord_by_key(current_tree, key, coord, &hint->lh,
+			      lock_mode, bias, LEAF_LEVEL, LEAF_LEVEL,
+			      CBK_UNIQUE | flags, ra_info);
+	if (cbk_errored(result))
+		return result;
+	hint->ext_coord.valid = 1;
+	return result;
+}
+
+/* The following function is called by defalte[inflate] manager
+ * to check if we need to align[cut] the overhead.
+ * If true, @oh repersents the size of unaligned[aligned] overhead.
+ */
+static int
+need_cut_or_align(struct inode * inode, reiser4_cluster_t * clust,
+		  rw_op rw, int * oh)
+{
+	tfm_cluster_t * tc = &clust->tc;
+	switch (rw) {
+	case WRITE_OP: /* estimate align */
+		*oh = tc->len % cipher_blocksize(inode);
+		if (*oh != 0)
+			return 1;
+		break;
+	case READ_OP:  /* estimate cut */
+		*oh = *(tfm_output_data(clust) + tc->len - 1);
+		break;
+	default:
+		impossible("edward-1401", "bad option");
+	}
+	return (tc->len != tc->lsize);
+}
+
+/* align or cut the overheads of
+   . input stream if @rw is WRITE_OP
+   . output stream if @rw is READ_OP */
+static void
+align_or_cut_overhead(struct inode * inode, reiser4_cluster_t * clust, rw_op rw)
+{
+	int oh;
+	cipher_plugin * cplug = inode_cipher_plugin(inode);
+
+	assert("edward-1402", need_cipher(inode));
+
+	if (!need_cut_or_align(inode, clust, rw, &oh))
+		return;
+	switch (rw) {
+	case WRITE_OP: /* do align */
+		clust->tc.len +=
+			cplug->align_stream(tfm_input_data(clust) +
+					    clust->tc.len, clust->tc.len,
+					    cipher_blocksize(inode));
+		*(tfm_input_data(clust) + clust->tc.len - 1) =
+			cipher_blocksize(inode) - oh;
+		break;
+	case READ_OP: /* do cut */
+		assert("edward-1403", oh <= cipher_blocksize(inode));
+		clust->tc.len -= oh;
+		break;
+	default:
+		impossible("edward-1404", "bad option");
+	}
+	return;
+}
+
+/* the following two functions are to evaluate results
+   of compression transform */
+static unsigned
+max_cipher_overhead(struct inode * inode)
+{
+	if (!need_cipher(inode) || !inode_cipher_plugin(inode)->align_stream)
+		return 0;
+	return cipher_blocksize(inode);
+}
+
+static int deflate_overhead(struct inode *inode)
+{
+	return (inode_compression_plugin(inode)->
+		checksum ? DC_CHECKSUM_SIZE : 0);
+}
+
+static unsigned deflate_overrun(struct inode * inode, int ilen)
+{
+	return max_count
+		(coa_overrun(inode_compression_plugin(inode), ilen),
+		 coa_overrun(dual_compression_plugin
+			     (inode_compression_plugin(inode)), ilen));
+}
+
+/* Estimating compressibility of a logical cluster by various
+   policies represented by compression mode plugin.
+   If this returns false, then compressor won't be called for
+   the cluster of index @index.
+*/
+static int try_compress(tfm_cluster_t * tc, cloff_t index, struct inode *inode)
+{
+	compression_plugin *cplug = inode_compression_plugin(inode);
+	compression_mode_plugin *mplug = inode_compression_mode_plugin(inode);
+
+	assert("edward-1321", tc->len != 0);
+	assert("edward-1322", cplug != NULL);
+	assert("edward-1323", mplug != NULL);
+
+	return /* estimate by size */
+		(cplug->min_size_deflate ?
+		 tc->len >= cplug->min_size_deflate() :
+		 1) &&
+		/* estimate by content */
+		(mplug->should_deflate ?
+		 mplug->should_deflate(inode, index) :
+		 1);
+}
+
+/* Evaluating results of compression transform.
+   Returns true, if we need to accept this results */
+static int
+save_compressed(int size_before, int size_after, struct inode * inode)
+{
+	return (size_after + deflate_overhead(inode) +
+		max_cipher_overhead(inode) < size_before);
+}
+
+/* Guess result of the evaluation above */
+static int
+need_inflate(reiser4_cluster_t * clust, struct inode *inode,
+	     int encrypted /* is cluster encrypted */ )
+{
+	tfm_cluster_t *tc = &clust->tc;
+
+	assert("edward-142", tc != 0);
+	assert("edward-143", inode != NULL);
+
+	return tc->len <
+	    (encrypted ?
+	     inode_scaled_offset(inode, tc->lsize) :
+	     tc->lsize);
+}
+
+/* If logical cluster got compressed we add a checksum to catch possible
+   disk cluster corruptions. The following is a format of the data stored
+   in disk clusters:
+
+		   data                   This is (transformed) logical cluster.
+		   cipher_overhead        This is created by ->align() method
+                                          of cipher plugin. May be absent.
+		   checksum          (4)  This is created by ->checksum method
+                                          of compression plugin to check
+                                          integrity. May be absent.
+
+		   Crypto overhead format:
+
+		   data
+		   control_byte      (1)   contains aligned overhead size:
+		                           1 <= overhead <= cipher_blksize
+*/
+/* Append checksum at the end of input transform stream
+   and increase its length */
+static void dc_set_checksum(compression_plugin * cplug, tfm_cluster_t * tc)
+{
+	__u32 checksum;
+
+	assert("edward-1309", tc != NULL);
+	assert("edward-1310", tc->len > 0);
+	assert("edward-1311", cplug->checksum != NULL);
+
+	checksum = cplug->checksum(tfm_stream_data(tc, OUTPUT_STREAM), tc->len);
+	put_unaligned(cpu_to_le32(checksum),
+		 (d32 *)(tfm_stream_data(tc, OUTPUT_STREAM) + tc->len));
+	tc->len += (int)DC_CHECKSUM_SIZE;
+}
+
+/* returns 0 if checksums coincide, otherwise returns 1,
+   increase the length of input transform stream */
+static int dc_check_checksum(compression_plugin * cplug, tfm_cluster_t * tc)
+{
+	assert("edward-1312", tc != NULL);
+	assert("edward-1313", tc->len > (int)DC_CHECKSUM_SIZE);
+	assert("edward-1314", cplug->checksum != NULL);
+
+	if (cplug->checksum(tfm_stream_data(tc, INPUT_STREAM),
+			    tc->len - (int)DC_CHECKSUM_SIZE) !=
+	    le32_to_cpu(get_unaligned((d32 *)
+				      (tfm_stream_data(tc, INPUT_STREAM)
+				       + tc->len - (int)DC_CHECKSUM_SIZE)))) {
+		warning("edward-156",
+			"Bad disk cluster checksum %d, (should be %d) Fsck?\n",
+			(int)le32_to_cpu
+			(get_unaligned((d32 *)
+				       (tfm_stream_data(tc, INPUT_STREAM) +
+					tc->len - (int)DC_CHECKSUM_SIZE))),
+			(int)cplug->checksum
+			(tfm_stream_data(tc, INPUT_STREAM),
+			 tc->len - (int)DC_CHECKSUM_SIZE));
+		return 1;
+	}
+	tc->len -= (int)DC_CHECKSUM_SIZE;
+	return 0;
+}
+
+int grab_tfm_stream(struct inode * inode, tfm_cluster_t * tc,
+		    tfm_stream_id id)
+{
+	size_t size = inode_scaled_cluster_size(inode);
+
+	assert("edward-901", tc != NULL);
+	assert("edward-1347", tc->act != TFM_INVAL);
+	assert("edward-1027", inode_compression_plugin(inode) != NULL);
+
+	if (tc->act == TFM_WRITE)
+		size += deflate_overrun(inode, inode_cluster_size(inode));
+
+	if (!tfm_stream(tc, id) && id == INPUT_STREAM)
+		alternate_streams(tc);
+	if (!tfm_stream(tc, id))
+		return alloc_tfm_stream(tc, size, id);
+
+	assert("edward-902", tfm_stream_is_set(tc, id));
+
+	if (tfm_stream_size(tc, id) < size)
+		return realloc_tfm_stream(tc, size, id);
+	return 0;
+}
+
+/* Common deflate manager */
+int deflate_cluster(reiser4_cluster_t * clust, struct inode * inode)
+{
+	int result = 0;
+	int compressed = 0;
+	int encrypted = 0;
+	tfm_cluster_t * tc = &clust->tc;
+	compression_plugin * coplug;
+
+	assert("edward-401", inode != NULL);
+	assert("edward-903", tfm_stream_is_set(tc, INPUT_STREAM));
+	assert("edward-1348", tc->act == TFM_WRITE);
+	assert("edward-498", !tfm_cluster_is_uptodate(tc));
+
+	coplug = inode_compression_plugin(inode);
+	if (try_compress(tc, clust->index, inode)) {
+		/* try to compress, discard bad results */
+		__u32 dst_len;
+		compression_mode_plugin * mplug =
+			inode_compression_mode_plugin(inode);
+		assert("edward-602", coplug != NULL);
+
+		if (coplug->compress == NULL)
+			coplug = dual_compression_plugin(coplug);
+		assert("edward-1423", coplug->compress != NULL);
+
+		result = grab_coa(tc, coplug);
+		if (result) {
+		    warning("edward-1424",
+			    "alloc_coa failed with ret=%d, skipped compression",
+			    result);
+		    goto cipher;
+		}
+		result = grab_tfm_stream(inode, tc, OUTPUT_STREAM);
+		if (result) {
+		    warning("edward-1425",
+			 "alloc stream failed with ret=%d, skipped compression",
+			    result);
+		    goto cipher;
+		}
+		dst_len = tfm_stream_size(tc, OUTPUT_STREAM);
+		coplug->compress(get_coa(tc, coplug->h.id),
+				 tfm_input_data(clust), tc->len,
+				 tfm_output_data(clust), &dst_len);
+		/* make sure we didn't overwrite extra bytes */
+		assert("edward-603",
+		       dst_len <= tfm_stream_size(tc, OUTPUT_STREAM));
+
+		/* evaluate results of compression transform */
+		if (save_compressed(tc->len, dst_len, inode)) {
+			/* good result, accept */
+			tc->len = dst_len;
+			if (mplug->accept_hook != NULL) {
+			       result = mplug->accept_hook(inode, clust->index);
+			       if (result)
+				       warning("edward-1426",
+					       "accept_hook failed with ret=%d",
+					       result);
+			}
+			compressed = 1;
+		}
+		else {
+			/* bad result, discard */
+#if REISER4_DEBUG
+			if (cluster_is_complete(clust, inode))
+			      warning("edward-1338",
+				      "incompressible cluster %lu (inode %llu)",
+				      clust->index,
+				      (unsigned long long)get_inode_oid(inode));
+#endif
+			if (mplug->discard_hook != NULL &&
+			    cluster_is_complete(clust, inode)) {
+				result = mplug->discard_hook(inode,
+							     clust->index);
+				if (result)
+				      warning("edward-1427",
+					      "discard_hook failed with ret=%d",
+					      result);
+			}
+		}
+	}
+ cipher:
+	if (need_cipher(inode)) {
+		cipher_plugin * ciplug;
+		struct crypto_tfm * tfm;
+		struct scatterlist src;
+		struct scatterlist dst;
+
+		ciplug = inode_cipher_plugin(inode);
+		tfm = info_cipher_tfm(inode_crypto_stat(inode));
+		if (compressed)
+			alternate_streams(tc);
+		result = grab_tfm_stream(inode, tc, OUTPUT_STREAM);
+		if (result)
+			return result;
+
+		align_or_cut_overhead(inode, clust, WRITE_OP);
+		src.page = virt_to_page(tfm_input_data(clust));
+		src.offset = offset_in_page(tfm_input_data(clust));
+		src.length = tc->len;
+
+		dst.page = virt_to_page(tfm_output_data(clust));
+		dst.offset = offset_in_page(tfm_output_data(clust));
+		dst.length = tc->len;
+
+		result = crypto_cipher_encrypt(tfm, &dst, &src, tc->len);
+		if (result) {
+			warning("edward-1405",
+				"encryption failed flags=%x\n", tfm->crt_flags);
+			return result;
+		}
+		encrypted = 1;
+	}
+	if (compressed && coplug->checksum != NULL)
+		dc_set_checksum(coplug, tc);
+	if (!compressed && !encrypted)
+		alternate_streams(tc);
+	return result;
+}
+
+/* Common inflate cluster manager. */
+int inflate_cluster(reiser4_cluster_t * clust, struct inode * inode)
+{
+	int result = 0;
+	int transformed = 0;
+	tfm_cluster_t * tc = &clust->tc;
+	compression_plugin * coplug;
+
+	assert("edward-905", inode != NULL);
+	assert("edward-1178", clust->dstat == PREP_DISK_CLUSTER);
+	assert("edward-906", tfm_stream_is_set(&clust->tc, INPUT_STREAM));
+	assert("edward-1349", tc->act == TFM_READ);
+	assert("edward-907", !tfm_cluster_is_uptodate(tc));
+
+	/* Handle a checksum (if any) */
+	coplug = inode_compression_plugin(inode);
+	if (need_inflate(clust, inode, need_cipher(inode)) &&
+	    coplug->checksum != NULL) {
+		result = dc_check_checksum(coplug, tc);
+		if (result)
+			return RETERR(-EIO);
+	}
+	if (need_cipher(inode)) {
+		cipher_plugin * ciplug;
+		struct crypto_tfm * tfm;
+		struct scatterlist src;
+		struct scatterlist dst;
+
+		ciplug = inode_cipher_plugin(inode);
+		tfm = info_cipher_tfm(inode_crypto_stat(inode));
+		result = grab_tfm_stream(inode, tc, OUTPUT_STREAM);
+		if (result)
+			return result;
+		assert("edward-909", tfm_cluster_is_set(tc));
+
+		src.page   =   virt_to_page(tfm_input_data(clust));
+		src.offset = offset_in_page(tfm_input_data(clust));
+		src.length = tc->len;
+
+		dst.page   =   virt_to_page(tfm_output_data(clust));
+		dst.offset = offset_in_page(tfm_output_data(clust));
+		dst.length = tc->len;
+
+		result = crypto_cipher_decrypt(tfm, &dst, &src, tc->len);
+		if (result)
+			return result;
+		align_or_cut_overhead(inode, clust, READ_OP);
+		transformed = 1;
+	}
+	if (need_inflate(clust, inode, 0)) {
+		unsigned dst_len = inode_cluster_size(inode);
+		if(transformed)
+			alternate_streams(tc);
+
+		result = grab_tfm_stream(inode, tc, OUTPUT_STREAM);
+		if (result)
+			return result;
+		assert("edward-1305", coplug->decompress != NULL);
+		assert("edward-910", tfm_cluster_is_set(tc));
+
+		coplug->decompress(get_coa(tc, coplug->h.id),
+				   tfm_input_data(clust), tc->len,
+				   tfm_output_data(clust), &dst_len);
+		/* check length */
+		tc->len = dst_len;
+		assert("edward-157", dst_len == tc->lsize);
+		transformed = 1;
+	}
+	if (!transformed)
+		alternate_streams(tc);
+	return result;
+}
+
+/* This is implementation of readpage method of struct
+   address_space_operations for cryptcompress plugin. */
+int readpage_cryptcompress(struct file *file, struct page *page)
+{
+	reiser4_context *ctx;
+	reiser4_cluster_t clust;
+	item_plugin *iplug;
+	int result;
+
+	assert("edward-88", PageLocked(page));
+	assert("vs-976", !PageUptodate(page));
+	assert("edward-89", page->mapping && page->mapping->host);
+
+	ctx = init_context(page->mapping->host->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+	result = check_cryptcompress(page->mapping->host);
+	if (result) {
+		unlock_page(page);
+		reiser4_exit_context(ctx);
+		return result;
+	}
+	assert("edward-113",
+	       ergo(file != NULL,
+		    page->mapping == file->f_dentry->d_inode->i_mapping));
+
+	if (PageUptodate(page)) {
+		warning("edward-1338", "page is already uptodate\n");
+		reiser4_exit_context(ctx);
+		return 0;
+	}
+	cluster_init_read(&clust, NULL);
+	clust.file = file;
+	iplug = item_plugin_by_id(CTAIL_ID);
+	if (!iplug->s.file.readpage) {
+		unlock_page(page);
+		put_cluster_handle(&clust);
+		reiser4_exit_context(ctx);
+		return -EINVAL;
+	}
+	result = iplug->s.file.readpage(&clust, page);
+	if (result)
+		unlock_page(page);
+	assert("edward-64",
+	       ergo(result == 0, (PageLocked(page) || PageUptodate(page))));
+	put_cluster_handle(&clust);
+	reiser4_exit_context(ctx);
+	return result;
+}
+
+/* plugin->readpages() */
+void
+readpages_cryptcompress(struct file *file, struct address_space *mapping,
+			struct list_head *pages)
+{
+	file_plugin *fplug;
+	item_plugin *iplug;
+
+	assert("edward-1112", mapping != NULL);
+	assert("edward-1113", mapping->host != NULL);
+
+	if (check_cryptcompress(mapping->host))
+		return;
+	fplug = inode_file_plugin(mapping->host);
+
+	assert("edward-1114", fplug == file_plugin_by_id(CRC_FILE_PLUGIN_ID));
+
+	iplug = item_plugin_by_id(CTAIL_ID);
+
+	iplug->s.file.readpages(file, mapping, pages);
+
+	return;
+}
+
+/* how much pages will be captured */
+static int cluster_nrpages_to_capture(reiser4_cluster_t * clust)
+{
+	switch (clust->op) {
+	case PCL_APPEND:
+		return clust->nr_pages;
+	case PCL_TRUNCATE:
+		assert("edward-1179", clust->win != NULL);
+		return count_to_nrpages(clust->win->off + clust->win->count);
+	default:
+		impossible("edward-1180", "bad page cluster option");
+		return 0;
+	}
+}
+
+static void set_cluster_pages_dirty(reiser4_cluster_t * clust)
+{
+	int i;
+	struct page *pg;
+	int nrpages = cluster_nrpages_to_capture(clust);
+
+	for (i = 0; i < nrpages; i++) {
+
+		pg = clust->pages[i];
+		assert("edward-968", pg != NULL);
+		lock_page(pg);
+		assert("edward-1065", PageUptodate(pg));
+		set_page_dirty_internal(pg);
+		unlock_page(pg);
+		mark_page_accessed(pg);
+	}
+}
+
+static void clear_cluster_pages_dirty(reiser4_cluster_t * clust)
+{
+	int i;
+	assert("edward-1275", clust != NULL);
+
+	for (i = 0; i < clust->nr_pages; i++) {
+		assert("edward-1276", clust->pages[i] != NULL);
+
+		lock_page(clust->pages[i]);
+		if (PageDirty(clust->pages[i])) {
+			assert("edward-1277", PageUptodate(clust->pages[i]));
+			clear_page_dirty_for_io(clust->pages[i]);
+		}
+#if REISER4_DEBUG
+		else
+			/* Race between flush and write:
+			   some pages became clean when write() (or another
+			   process which modifies data) capture the cluster. */
+			warning("edward-985", "Page of index %lu (inode %llu)"
+				" is not dirty\n", clust->pages[i]->index,
+				(unsigned long long)get_inode_oid(clust->
+								  pages[i]->
+								  mapping->
+								  host));
+#endif
+		unlock_page(clust->pages[i]);
+	}
+}
+
+/* update i_size by window */
+static void inode_set_new_size(reiser4_cluster_t * clust, struct inode *inode)
+{
+	loff_t size;
+	reiser4_slide_t *win;
+
+	assert("edward-1181", clust != NULL);
+	assert("edward-1182", inode != NULL);
+
+	win = clust->win;
+	assert("edward-1183", win != NULL);
+
+	size = clust_to_off(clust->index, inode) + win->off;
+
+	switch (clust->op) {
+	case PCL_APPEND:
+		if (size + win->count <= inode->i_size)
+			/* overwrite only */
+			return;
+		size += win->count;
+		break;
+	case PCL_TRUNCATE:
+		break;
+	default:
+		impossible("edward-1184", "bad page cluster option");
+		break;
+	}
+	inode_check_scale_nolock(inode, inode->i_size, size);
+	inode->i_size = size;
+	return;
+}
+
+/* Check in page cluster modifications.
+   . Make jnode dirty, if it wasn't;
+   . Reserve space for a disk cluster update by flush algorithm, if needed;
+   . Clean up extra-references of cluster pages.
+*/
+static void
+make_cluster_jnode_dirty_locked(reiser4_cluster_t * clust, jnode * node,
+				loff_t * old_isize, struct inode *inode)
+{
+	int i;
+	int old_refcnt;
+	int new_refcnt;
+
+	assert("edward-221", node != NULL);
+	assert("edward-971", clust->reserved == 1);
+	assert_spin_locked(&(node->guard));
+	assert("edward-972", node->page_count < cluster_nrpages(inode));
+	assert("edward-1263",
+	       clust->reserved_prepped == estimate_update_cluster(inode));
+	assert("edward-1264", clust->reserved_unprepped == 0);
+
+	if (JF_ISSET(node, JNODE_DIRTY)) {
+		/* there are >= 1 pages already referenced by this jnode */
+		assert("edward-973",
+		       count_to_nrpages(cnt_to_clcnt
+					(*old_isize, clust->index, inode)));
+		old_refcnt =
+			count_to_nrpages(cnt_to_clcnt
+					 (*old_isize, clust->index, inode)) - 1;
+		/* space for the disk cluster is already reserved */
+
+		free_reserved4cluster(inode, clust,
+				      estimate_update_cluster(inode));
+	} else {
+		/* there is only one page referenced by this jnode */
+		assert("edward-1043", node->page_count == 0);
+		old_refcnt = 0;
+		jnode_make_dirty_locked(node);
+		clust->reserved = 0;
+	}
+#if REISER4_DEBUG
+	clust->reserved_prepped -= estimate_update_cluster(inode);
+#endif
+	new_refcnt = cluster_nrpages_to_capture(clust) - 1;
+
+	/* get rid of duplicated references */
+	for (i = 0; i <= old_refcnt; i++) {
+		assert("edward-975", clust->pages[i]);
+		assert("edward-976", old_refcnt < inode_cluster_size(inode));
+		assert("edward-1185", PageUptodate(clust->pages[i]));
+
+		page_cache_release(clust->pages[i]);
+	}
+	/* truncate old references */
+	if (new_refcnt < old_refcnt) {
+		assert("edward-1186", clust->op == PCL_TRUNCATE);
+		for (i = new_refcnt + 1; i <= old_refcnt; i++) {
+			assert("edward-1187", clust->pages[i]);
+			assert("edward-1188", PageUptodate(clust->pages[i]));
+
+			page_cache_release(clust->pages[i]);
+		}
+	}
+#if REISER4_DEBUG
+	node->page_count = new_refcnt;
+#endif
+	return;
+}
+
+/* This function spawns a transaction and
+   is called by any thread as a final step in page cluster modification.
+*/
+static int try_capture_cluster(reiser4_cluster_t * clust, struct inode *inode)
+{
+	int result = 0;
+	loff_t old_size = inode->i_size;
+	jnode *node;
+
+	assert("edward-1029", clust != NULL);
+	assert("edward-1030", clust->reserved == 1);
+	assert("edward-1031", clust->nr_pages != 0);
+	assert("edward-1032", clust->pages != NULL);
+	assert("edward-1033", clust->pages[0] != NULL);
+
+	node = jprivate(clust->pages[0]);
+
+	assert("edward-1035", node != NULL);
+
+	spin_lock_jnode(node);
+	if (clust->win)
+		inode_set_new_size(clust, inode);
+
+	result = try_capture(node, ZNODE_WRITE_LOCK, 0, 0);
+	if (result)
+		goto exit;
+	make_cluster_jnode_dirty_locked(clust, node, &old_size, inode);
+      exit:
+	assert("edward-1034", !result);
+	spin_unlock_jnode(node);
+	jput(node);
+	return result;
+}
+
+/* Collect unlocked cluster pages for any modifications and attach a jnode.
+   We allocate only one jnode per cluster, this jnode is binded to the first
+   page of this cluster.
+   All extra-references will be released under jnode lock in
+   make_cluster_jnode_dirty_locked() when spawning a transaction.
+*/
+static int
+grab_cluster_pages_jnode(struct inode *inode, reiser4_cluster_t * clust)
+{
+	int i;
+	int result = 0;
+	jnode *node = NULL;
+
+	assert("edward-182", clust != NULL);
+	assert("edward-183", clust->pages != NULL);
+	assert("edward-184", clust->nr_pages <= cluster_nrpages(inode));
+
+	if (clust->nr_pages == 0)
+		return 0;
+
+	for (i = 0; i < clust->nr_pages; i++) {
+
+		assert("edward-1044", clust->pages[i] == NULL);
+
+		clust->pages[i] =
+		    grab_cache_page(inode->i_mapping,
+				    clust_to_pg(clust->index, inode) + i);
+		if (!clust->pages[i]) {
+			result = RETERR(-ENOMEM);
+			break;
+		}
+		if (i == 0) {
+			node = jnode_of_page(clust->pages[i]);
+			if (IS_ERR(node)) {
+				result = PTR_ERR(node);
+				unlock_page(clust->pages[i]);
+				break;
+			}
+			JF_SET(node, JNODE_CLUSTER_PAGE);
+			unlock_page(clust->pages[i]);
+			assert("edward-919", node);
+			continue;
+		}
+		unlock_page(clust->pages[i]);
+	}
+	if (result) {
+		while (i)
+			page_cache_release(clust->pages[--i]);
+		if (node && !IS_ERR(node))
+			jput(node);
+		return result;
+	}
+	assert("edward-920", jprivate(clust->pages[0]));
+	return 0;
+}
+
+/* Collect unlocked cluster pages by any thread wich won't modify it. */
+static int grab_cluster_pages(struct inode *inode, reiser4_cluster_t * clust)
+{
+	int i;
+	int result = 0;
+
+	assert("edward-1428", inode != NULL);
+	assert("edward-1429", inode->i_mapping != NULL);
+	assert("edward-787", clust != NULL);
+	assert("edward-788", clust->pages != NULL);
+	assert("edward-789", clust->nr_pages != 0);
+	assert("edward-790", clust->nr_pages <= cluster_nrpages(inode));
+
+	for (i = 0; i < clust->nr_pages; i++) {
+		clust->pages[i] =
+		    grab_cache_page(inode->i_mapping,
+				    clust_to_pg(clust->index, inode) + i);
+		if (!clust->pages[i]) {
+			result = RETERR(-ENOMEM);
+			break;
+		}
+		unlock_page(clust->pages[i]);
+	}
+	if (result)
+		while (i)
+			page_cache_release(clust->pages[--i]);
+	return result;
+}
+
+/* @node might be attached by reiser4_writepage(), not by
+   cryptcompress plugin code, but emergency flush should
+   understand that pages of cryptcompress files are not
+   flushable.
+*/
+int jnode_of_cluster(const jnode * node, struct page * page)
+{
+	assert("edward-1339", node != NULL);
+	assert("edward-1340", page != NULL);
+	assert("edward-1341", page->mapping != NULL);
+	assert("edward-1342", page->mapping->host != NULL);
+	assert("edward-1343",
+	       ergo(jnode_is_unformatted(node),
+		    get_inode_oid(page->mapping->host) ==
+		    node->key.j.objectid));
+	if (inode_file_plugin(page->mapping->host) ==
+	    file_plugin_by_id(CRC_FILE_PLUGIN_ID)) {
+#if REISER4_DEBUG
+		if (!jnode_is_cluster_page(node))
+			warning("edward-1345",
+			"inode %llu: cluster page of index %lu became private",
+			(unsigned long long)get_inode_oid(page->mapping->host),
+			page->index);
+#endif
+		return 1;
+	}
+	return 0;
+}
+
+/* put cluster pages starting from @from */
+static void release_cluster_pages(reiser4_cluster_t * clust, int from)
+{
+	int i;
+
+	assert("edward-447", clust != NULL);
+	assert("edward-448", from <= clust->nr_pages);
+
+	for (i = from; i < clust->nr_pages; i++) {
+
+		assert("edward-449", clust->pages[i] != NULL);
+
+		page_cache_release(clust->pages[i]);
+	}
+}
+
+static void release_cluster_pages_capture(reiser4_cluster_t * clust)
+{
+	assert("edward-1278", clust != NULL);
+	assert("edward-1279", clust->nr_pages != 0);
+
+	return release_cluster_pages(clust, 1);
+}
+
+void release_cluster_pages_nocapture(reiser4_cluster_t * clust)
+{
+	return release_cluster_pages(clust, 0);
+}
+
+static void release_cluster_pages_and_jnode(reiser4_cluster_t * clust)
+{
+	jnode *node;
+
+	assert("edward-445", clust != NULL);
+	assert("edward-922", clust->pages != NULL);
+	assert("edward-446", clust->pages[0] != NULL);
+
+	node = jprivate(clust->pages[0]);
+
+	assert("edward-447", node != NULL);
+
+	release_cluster_pages(clust, 0);
+
+	jput(node);
+}
+
+#if REISER4_DEBUG
+static int window_ok(reiser4_slide_t * win, struct inode *inode)
+{
+	assert("edward-1115", win != NULL);
+	assert("edward-1116", ergo(win->delta, win->stat == HOLE_WINDOW));
+
+	return (win->off != inode_cluster_size(inode)) &&
+	    (win->off + win->count + win->delta <= inode_cluster_size(inode));
+}
+
+static int cluster_ok(reiser4_cluster_t * clust, struct inode *inode)
+{
+	assert("edward-279", clust != NULL);
+
+	if (!clust->pages)
+		return 0;
+	return (clust->win ? window_ok(clust->win, inode) : 1);
+}
+#endif
+
+/* guess next window stat */
+static inline window_stat next_window_stat(reiser4_slide_t * win)
+{
+	assert("edward-1130", win != NULL);
+	return ((win->stat == HOLE_WINDOW && win->delta == 0) ?
+		HOLE_WINDOW : DATA_WINDOW);
+}
+
+/* guess next cluster index and window params */
+static void
+update_cluster(struct inode *inode, reiser4_cluster_t * clust, loff_t file_off,
+	       loff_t to_file)
+{
+	reiser4_slide_t *win;
+
+	assert("edward-185", clust != NULL);
+	assert("edward-438", clust->pages != NULL);
+	assert("edward-281", cluster_ok(clust, inode));
+
+	win = clust->win;
+	if (!win)
+		return;
+
+	switch (win->stat) {
+	case DATA_WINDOW:
+		/* increment window position */
+		clust->index++;
+		win->stat = DATA_WINDOW;
+		win->off = 0;
+		win->count = min_count(inode_cluster_size(inode), to_file);
+		break;
+	case HOLE_WINDOW:
+		switch (next_window_stat(win)) {
+		case HOLE_WINDOW:
+			/* set window to fit the offset we start write from */
+			clust->index = off_to_clust(file_off, inode);
+			win->stat = HOLE_WINDOW;
+			win->off = 0;
+			win->count = off_to_cloff(file_off, inode);
+			win->delta =
+			    min_count(inode_cluster_size(inode) - win->count,
+				      to_file);
+			break;
+		case DATA_WINDOW:
+			/* do not move the window, just change its state,
+			   off+count+delta=inv */
+			win->stat = DATA_WINDOW;
+			win->off = win->off + win->count;
+			win->count = win->delta;
+			win->delta = 0;
+			break;
+		default:
+			impossible("edward-282", "wrong next window state");
+		}
+		break;
+	default:
+		impossible("edward-283", "wrong current window state");
+	}
+	assert("edward-1068", cluster_ok(clust, inode));
+}
+
+static int update_sd_cryptcompress(struct inode *inode)
+{
+	int result = 0;
+
+	assert("edward-978", schedulable());
+	assert("edward-1265", get_current_context()->grabbed_blocks == 0);
+
+	result = reiser4_grab_space_force(	/* one for stat data update */
+						 estimate_update_common(inode),
+						 BA_CAN_COMMIT);
+	assert("edward-979", !result);
+	if (result)
+		return result;
+	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+	result = reiser4_update_sd(inode);
+
+	all_grabbed2free();
+	return result;
+}
+
+
+/* NOTE-Edward: this is too similar to reiser4/txnmgr.c:uncapture_jnode() */
+static void uncapture_cluster_jnode(jnode * node)
+{
+	txn_atom *atom;
+
+	assert_spin_locked(&(node->guard));
+
+	/*jnode_make_clean(node); */
+	atom = jnode_get_atom(node);
+	if (atom == NULL) {
+		assert("jmacd-7111", !JF_ISSET(node, JNODE_DIRTY));
+		spin_unlock_jnode(node);
+		return;
+	}
+
+	uncapture_block(node);
+	spin_unlock_atom(atom);
+	jput(node);
+}
+
+void forget_cluster_pages(struct page **pages, int nr)
+{
+	int i;
+	for (i = 0; i < nr; i++) {
+
+		assert("edward-1045", pages[i] != NULL);
+		page_cache_release(pages[i]);
+	}
+}
+
+/* Check out last modifications we are about to commit.
+   Prepare input stream for transform operations, return -E_REPEAT, if it is
+   impossible because of races with concurrent processes.
+*/
+int
+flush_cluster_pages(reiser4_cluster_t * clust, jnode * node,
+		    struct inode *inode)
+{
+	int result = 0;
+	int i;
+	int nr_pages = 0;
+	tfm_cluster_t *tc = &clust->tc;
+
+	assert("edward-980", node != NULL);
+	assert("edward-236", inode != NULL);
+	assert("edward-237", clust != NULL);
+	assert("edward-240", !clust->win);
+	assert("edward-241", schedulable());
+	assert("edward-718", crc_inode_ok(inode));
+
+	result = grab_tfm_stream(inode, tc, INPUT_STREAM);
+	if (result) {
+		warning("edward-1430",
+			"alloc stream failed with ret=%d", result);
+		return result;
+	}
+	spin_lock_jnode(node);
+
+	if (!JF_ISSET(node, JNODE_DIRTY)) {
+
+		assert("edward-981", node->page_count == 0);
+
+		/* race with another flush */
+		spin_unlock_jnode(node);
+		warning("edward-982", "flush_cluster_pages: jnode is not dirty "
+			"clust %lu, inode %llu\n",
+			clust->index, (unsigned long long)get_inode_oid(inode));
+		return RETERR(-E_REPEAT);
+	}
+	/* Check out a size of logical cluster and
+	   calculate a number of cluster pages to commit. */
+	tc->len = tc->lsize = fsize_to_count(clust, inode);
+	clust->nr_pages = count_to_nrpages(tc->len);
+
+	assert("edward-983", clust->nr_pages == node->page_count + 1);
+#if REISER4_DEBUG
+	node->page_count = 0;
+#endif
+	cluster_reserved2grabbed(estimate_update_cluster(inode));
+	uncapture_cluster_jnode(node);
+
+	assert("edward-1224", schedulable());
+	/* Check out cluster pages to commit */
+	nr_pages =
+	      find_get_pages(inode->i_mapping, clust_to_pg(clust->index, inode),
+			     clust->nr_pages, clust->pages);
+
+	if (nr_pages != clust->nr_pages) {
+		/* the page cluster got truncated, try again */
+		assert("edward-1280", nr_pages < clust->nr_pages);
+		warning("edward-1281", "Page cluster of index %lu (inode %llu)"
+			" get truncated from %u to %u pages\n",
+			clust->index,
+			(unsigned long long)get_inode_oid(inode),
+			clust->nr_pages, nr_pages);
+		forget_cluster_pages(clust->pages, nr_pages);
+		return RETERR(-E_REPEAT);
+	}
+	/* Try to construct input stream from the checked out cluster pages.
+	   Note, that the last ones can be modified (truncated, appended) by
+	   concurrent processes, so we need to worry this is not mucked up
+	   so the constructed stream became invalid */
+	for (i = 0; i < clust->nr_pages; i++) {
+		char *data;
+
+		assert("edward-242", clust->pages[i] != NULL);
+
+		if (clust->pages[i]->index !=
+		    clust_to_pg(clust->index, inode) + i) {
+			/* holes in the indices of found group of pages:
+			   page cluster got truncated, transform impossible */
+			warning("edward-1282",
+				"Hole in the indices: "
+				"Page %d in the cluster of index %lu "
+				"(inode %llu) has index %lu\n",
+				i, clust->index,
+				(unsigned long long)get_inode_oid(inode),
+				clust->pages[i]->index);
+
+			forget_cluster_pages(clust->pages, nr_pages);
+			result = RETERR(-E_REPEAT);
+			goto finish;
+		}
+		if (!PageUptodate(clust->pages[i])) {
+			/* page cluster got truncated, transform impossible */
+			assert("edward-1283", !PageDirty(clust->pages[i]));
+			warning("edward-1284",
+				"Page of index %lu (inode %llu) "
+				"is not uptodate\n", clust->pages[i]->index,
+				(unsigned long long)get_inode_oid(inode));
+
+			forget_cluster_pages(clust->pages, nr_pages);
+			result = RETERR(-E_REPEAT);
+			goto finish;
+		}
+		/* ok with this page, flush it to the input stream */
+		lock_page(clust->pages[i]);
+		data = kmap(clust->pages[i]);
+
+		assert("edward-986", cnt_to_pgcnt(tc->len, i) != 0);
+
+		memcpy(tfm_stream_data(tc, INPUT_STREAM) + pg_to_off(i),
+		       data, cnt_to_pgcnt(tc->len, i));
+		kunmap(clust->pages[i]);
+		unlock_page(clust->pages[i]);
+	}
+	/* input stream is ready for transform */
+
+	clear_cluster_pages_dirty(clust);
+      finish:
+	release_cluster_pages_capture(clust);
+	return result;
+}
+
+/* set hint for the cluster of the index @index */
+void
+set_hint_cluster(struct inode *inode, hint_t * hint,
+		 cloff_t index, znode_lock_mode mode)
+{
+	reiser4_key key;
+	assert("edward-722", crc_inode_ok(inode));
+	assert("edward-723",
+	       inode_file_plugin(inode) ==
+	       file_plugin_by_id(CRC_FILE_PLUGIN_ID));
+
+	inode_file_plugin(inode)->key_by_inode(inode,
+					       clust_to_off(index, inode),
+					       &key);
+
+	seal_init(&hint->seal, &hint->ext_coord.coord, &key);
+	hint->offset = get_key_offset(&key);
+	hint->mode = mode;
+}
+
+void invalidate_hint_cluster(reiser4_cluster_t * clust)
+{
+	assert("edward-1291", clust != NULL);
+	assert("edward-1292", clust->hint != NULL);
+
+	done_lh(&clust->hint->lh);
+	clust->hint->ext_coord.valid = 0;
+}
+
+void put_hint_cluster(reiser4_cluster_t * clust, struct inode *inode,
+		 znode_lock_mode mode)
+{
+	assert("edward-1286", clust != NULL);
+	assert("edward-1287", clust->hint != NULL);
+
+	set_hint_cluster(inode, clust->hint, clust->index + 1, mode);
+	invalidate_hint_cluster(clust);
+}
+
+static int
+balance_dirty_page_cluster(reiser4_cluster_t * clust, struct inode *inode,
+			   loff_t off, loff_t to_file)
+{
+	int result;
+
+	assert("edward-724", inode != NULL);
+	assert("edward-725", crc_inode_ok(inode));
+	assert("edward-1272", get_current_context()->grabbed_blocks == 0);
+
+	/* set next window params */
+	update_cluster(inode, clust, off, to_file);
+
+	result = update_sd_cryptcompress(inode);
+	assert("edward-988", !result);
+	if (result)
+		return result;
+	assert("edward-726", clust->hint->lh.owner == NULL);
+
+	reiser4_throttle_write(inode);
+	all_grabbed2free();
+	return 0;
+}
+
+/* set zeroes to the cluster, update it, and maybe, try to capture its pages */
+static int
+write_hole(struct inode *inode, reiser4_cluster_t * clust, loff_t file_off,
+	   loff_t to_file)
+{
+	char *data;
+	int result = 0;
+	unsigned cl_off, cl_count = 0;
+	unsigned to_pg, pg_off;
+	reiser4_slide_t *win;
+
+	assert("edward-190", clust != NULL);
+	assert("edward-1069", clust->win != NULL);
+	assert("edward-191", inode != NULL);
+	assert("edward-727", crc_inode_ok(inode));
+	assert("edward-1171", clust->dstat != INVAL_DISK_CLUSTER);
+	assert("edward-1154",
+	       ergo(clust->dstat != FAKE_DISK_CLUSTER, clust->reserved == 1));
+
+	win = clust->win;
+
+	assert("edward-1070", win != NULL);
+	assert("edward-201", win->stat == HOLE_WINDOW);
+	assert("edward-192", cluster_ok(clust, inode));
+
+	if (win->off == 0 && win->count == inode_cluster_size(inode)) {
+		/* the hole will be represented by fake disk cluster */
+		update_cluster(inode, clust, file_off, to_file);
+		return 0;
+	}
+	cl_count = win->count;	/* number of zeroes to write */
+	cl_off = win->off;
+	pg_off = off_to_pgoff(win->off);
+
+	while (cl_count) {
+		struct page *page;
+		page = clust->pages[off_to_pg(cl_off)];
+
+		assert("edward-284", page != NULL);
+
+		to_pg = min_count(PAGE_CACHE_SIZE - pg_off, cl_count);
+		lock_page(page);
+		data = kmap_atomic(page, KM_USER0);
+		memset(data + pg_off, 0, to_pg);
+		flush_dcache_page(page);
+		kunmap_atomic(data, KM_USER0);
+		SetPageUptodate(page);
+		unlock_page(page);
+
+		cl_off += to_pg;
+		cl_count -= to_pg;
+		pg_off = 0;
+	}
+	if (!win->delta) {
+		/* only zeroes, try to capture */
+
+		set_cluster_pages_dirty(clust);
+		result = try_capture_cluster(clust, inode);
+		if (result)
+			return result;
+		put_hint_cluster(clust, inode, ZNODE_WRITE_LOCK);
+		result =
+		    balance_dirty_page_cluster(clust, inode, file_off, to_file);
+	} else
+		update_cluster(inode, clust, file_off, to_file);
+	return result;
+}
+
+/*
+  The main disk search procedure for cryptcompress plugins, which
+  . scans all items of disk cluster
+  . maybe reads each one (if @read != 0)
+  . maybe makes its znode dirty  (if @write != 0)
+
+  NOTE-EDWARD: Callers should handle the case when disk cluster
+  is incomplete (-EIO)
+*/
+int
+find_cluster(reiser4_cluster_t * clust,
+	     struct inode *inode, int read, int write)
+{
+	flow_t f;
+	hint_t *hint;
+	int result = 0;
+	unsigned long cl_idx;
+	ra_info_t ra_info;
+	file_plugin *fplug;
+	item_plugin *iplug;
+	tfm_cluster_t *tc;
+	int was_grabbed;
+
+	assert("edward-138", clust != NULL);
+	assert("edward-728", clust->hint != NULL);
+	assert("edward-225", read || write);
+	assert("edward-226", schedulable());
+	assert("edward-137", inode != NULL);
+	assert("edward-729", crc_inode_ok(inode));
+
+	hint = clust->hint;
+	cl_idx = clust->index;
+	fplug = inode_file_plugin(inode);
+	was_grabbed = get_current_context()->grabbed_blocks;
+	tc = &clust->tc;
+
+	assert("edward-462", !tfm_cluster_is_uptodate(tc));
+	assert("edward-461", ergo(read, tfm_stream_is_set(tc, INPUT_STREAM)));
+
+	/* set key of the first disk cluster item */
+	fplug->flow_by_inode(inode,
+			     (read ? (char __user *)tfm_stream_data(tc, INPUT_STREAM) : NULL),
+			     0 /* kernel space */ ,
+			     inode_scaled_cluster_size(inode),
+			     clust_to_off(cl_idx, inode), READ_OP, &f);
+	if (write) {
+		/* reserve for flush to make dirty all the leaf nodes
+		   which contain disk cluster */
+		result =
+		    reiser4_grab_space_force(estimate_dirty_cluster(inode),
+					     BA_CAN_COMMIT);
+		assert("edward-990", !result);
+		if (result)
+			goto out;
+	}
+
+	ra_info.key_to_stop = f.key;
+	set_key_offset(&ra_info.key_to_stop, get_key_offset(max_key()));
+
+	while (f.length) {
+		result = find_cluster_item(hint,
+					   &f.key,
+					   (write ? ZNODE_WRITE_LOCK :
+					    ZNODE_READ_LOCK), NULL, FIND_EXACT,
+					   (write ? CBK_FOR_INSERT : 0));
+		switch (result) {
+		case CBK_COORD_NOTFOUND:
+			result = 0;
+			if (inode_scaled_offset
+			    (inode,
+			     clust_to_off(cl_idx,
+					  inode)) == get_key_offset(&f.key)) {
+				/* first item not found, this is treated
+				   as disk cluster is absent */
+				clust->dstat = FAKE_DISK_CLUSTER;
+				goto out;
+			}
+			/* we are outside the cluster, stop search here */
+			assert("edward-146",
+			       f.length != inode_scaled_cluster_size(inode));
+			goto ok;
+		case CBK_COORD_FOUND:
+			assert("edward-148",
+			       hint->ext_coord.coord.between == AT_UNIT);
+			assert("edward-460",
+			       hint->ext_coord.coord.unit_pos == 0);
+
+			coord_clear_iplug(&hint->ext_coord.coord);
+			result = zload_ra(hint->ext_coord.coord.node, &ra_info);
+			if (unlikely(result))
+				goto out;
+			iplug = item_plugin_by_coord(&hint->ext_coord.coord);
+			assert("edward-147",
+			       item_id_by_coord(&hint->ext_coord.coord) ==
+			       CTAIL_ID);
+
+			result = iplug->s.file.read(NULL, &f, hint);
+			if (result) {
+				zrelse(hint->ext_coord.coord.node);
+				goto out;
+			}
+			if (write) {
+				znode_make_dirty(hint->ext_coord.coord.node);
+				znode_set_convertible(hint->ext_coord.coord.
+						      node);
+			}
+			zrelse(hint->ext_coord.coord.node);
+			break;
+		default:
+			goto out;
+		}
+	}
+ ok:
+	/* at least one item was found  */
+	/* NOTE-EDWARD: Callers should handle the case
+	   when disk cluster is incomplete (-EIO) */
+	tc->len = inode_scaled_cluster_size(inode) - f.length;
+	tc->lsize = fsize_to_count(clust, inode);
+	assert("edward-1196", tc->len > 0);
+	assert("edward-1406", tc->lsize > 0);
+
+	if (hint_is_unprepped_dclust(clust->hint))
+		clust->dstat = UNPR_DISK_CLUSTER;
+	else
+		clust->dstat = PREP_DISK_CLUSTER;
+ out:
+	assert("edward-1339",
+	       get_current_context()->grabbed_blocks >= was_grabbed);
+	grabbed2free(get_current_context(),
+		     get_current_super_private(),
+		     get_current_context()->grabbed_blocks - was_grabbed);
+	return result;
+}
+
+int
+get_disk_cluster_locked(reiser4_cluster_t * clust, struct inode *inode,
+			znode_lock_mode lock_mode)
+{
+	reiser4_key key;
+	ra_info_t ra_info;
+
+	assert("edward-730", schedulable());
+	assert("edward-731", clust != NULL);
+	assert("edward-732", inode != NULL);
+
+	if (clust->hint->ext_coord.valid) {
+		assert("edward-1293", clust->dstat != INVAL_DISK_CLUSTER);
+		assert("edward-1294",
+		       znode_is_write_locked(clust->hint->lh.node));
+		/* already have a valid locked position */
+		return (clust->dstat ==
+			FAKE_DISK_CLUSTER ? CBK_COORD_NOTFOUND :
+			CBK_COORD_FOUND);
+	}
+	key_by_inode_cryptcompress(inode, clust_to_off(clust->index, inode),
+				   &key);
+	ra_info.key_to_stop = key;
+	set_key_offset(&ra_info.key_to_stop, get_key_offset(max_key()));
+
+	return find_cluster_item(clust->hint, &key, lock_mode, NULL, FIND_EXACT,
+				 CBK_FOR_INSERT);
+}
+
+/* Read needed cluster pages before modifying.
+   If success, @clust->hint contains locked position in the tree.
+   Also:
+   . find and set disk cluster state
+   . make disk cluster dirty if its state is not FAKE_DISK_CLUSTER.
+*/
+static int
+read_some_cluster_pages(struct inode *inode, reiser4_cluster_t * clust)
+{
+	int i;
+	int result = 0;
+	item_plugin *iplug;
+	reiser4_slide_t *win = clust->win;
+
+	iplug = item_plugin_by_id(CTAIL_ID);
+
+	assert("edward-733", get_current_context()->grabbed_blocks == 0);
+	assert("edward-924", !tfm_cluster_is_uptodate(&clust->tc));
+
+#if REISER4_DEBUG
+	if (clust->nr_pages == 0) {
+		/* start write hole from fake disk cluster */
+		assert("edward-1117", win != NULL);
+		assert("edward-1118", win->stat == HOLE_WINDOW);
+		assert("edward-1119", new_cluster(clust, inode));
+	}
+#endif
+	if (new_cluster(clust, inode)) {
+		/*
+		   new page cluster is about to be written, nothing to read,
+		 */
+		assert("edward-734", schedulable());
+		assert("edward-735", clust->hint->lh.owner == NULL);
+
+		if (clust->nr_pages) {
+			int off;
+			char *data;
+			struct page * pg;
+			assert("edward-1419", clust->pages != NULL);
+			pg = clust->pages[clust->nr_pages - 1];
+			assert("edward-1420", pg != NULL);
+			off = off_to_pgoff(win->off+win->count+win->delta);
+			if (off) {
+				lock_page(pg);
+				data = kmap_atomic(pg, KM_USER0);
+				memset(data + off, 0, PAGE_CACHE_SIZE - off);
+				flush_dcache_page(pg);
+				kunmap_atomic(data, KM_USER0);
+				unlock_page(pg);
+			}
+		}
+		clust->dstat = FAKE_DISK_CLUSTER;
+		return 0;
+	}
+	/*
+	   Here we should search for disk cluster to figure out its real state.
+	   Also there is one more important reason to do disk search: we need
+	   to make disk cluster _dirty_ if it exists
+	 */
+
+	/* if windows is specified, read the only pages
+	   that will be modified partially */
+
+	for (i = 0; i < clust->nr_pages; i++) {
+		struct page *pg = clust->pages[i];
+
+		lock_page(pg);
+		if (PageUptodate(pg)) {
+			unlock_page(pg);
+			continue;
+		}
+		unlock_page(pg);
+
+		if (win &&
+		    i >= count_to_nrpages(win->off) &&
+		    i < off_to_pg(win->off + win->count + win->delta))
+			/* page will be completely overwritten */
+			continue;
+
+		if (win && (i == clust->nr_pages - 1) &&
+		    /* the last page is
+		       partially modified,
+		       not uptodate .. */
+		    (count_to_nrpages(inode->i_size) <= pg->index)) {
+			/* .. and appended,
+			   so set zeroes to the rest */
+			char *data;
+			int offset;
+			lock_page(pg);
+			data = kmap_atomic(pg, KM_USER0);
+
+			assert("edward-1260",
+			       count_to_nrpages(win->off + win->count +
+						win->delta) - 1 == i);
+
+			offset =
+			    off_to_pgoff(win->off + win->count + win->delta);
+			memset(data + offset, 0, PAGE_CACHE_SIZE - offset);
+			flush_dcache_page(pg);
+			kunmap_atomic(data, KM_USER0);
+			unlock_page(pg);
+			/* still not uptodate */
+			break;
+		}
+		if (!tfm_cluster_is_uptodate(&clust->tc)) {
+			result = ctail_read_disk_cluster(clust, inode, 1);
+			assert("edward-992", !result);
+			if (result)
+				goto out;
+			assert("edward-925",
+			       tfm_cluster_is_uptodate(&clust->tc));
+		}
+		lock_page(pg);
+		result = do_readpage_ctail(inode, clust, pg);
+		unlock_page(pg);
+		assert("edward-993", !result);
+		if (result) {
+			impossible("edward-219",
+				   "do_readpage_ctail returned crap");
+			goto out;
+		}
+	}
+	if (!tfm_cluster_is_uptodate(&clust->tc)) {
+		/* disk cluster unclaimed, but we need to make its znodes dirty
+		   to make flush update convert its content */
+		result =
+		    find_cluster(clust, inode, 0 /* do not read */ ,
+				 1 /* write */ );
+		assert("edward-994", !result);
+	}
+ out:
+	tfm_cluster_clr_uptodate(&clust->tc);
+	return result;
+}
+
+static int
+should_create_unprepped_cluster(reiser4_cluster_t * clust, struct inode *inode)
+{
+	assert("edward-737", clust != NULL);
+
+	switch (clust->dstat) {
+	case PREP_DISK_CLUSTER:
+	case UNPR_DISK_CLUSTER:
+		return 0;
+	case FAKE_DISK_CLUSTER:
+		if (clust->win &&
+		    clust->win->stat == HOLE_WINDOW && clust->nr_pages == 0) {
+			assert("edward-1172", new_cluster(clust, inode));
+			return 0;
+		}
+		return 1;
+	default:
+		impossible("edward-1173", "bad disk cluster state");
+		return 0;
+	}
+}
+
+static int
+crc_make_unprepped_cluster(reiser4_cluster_t * clust, struct inode *inode)
+{
+	int result;
+
+	assert("edward-1123", schedulable());
+	assert("edward-737", clust != NULL);
+	assert("edward-738", inode != NULL);
+	assert("edward-739", crc_inode_ok(inode));
+	assert("edward-1053", clust->hint != NULL);
+	assert("edward-1266", get_current_context()->grabbed_blocks == 0);
+
+	if (clust->reserved) {
+		cluster_reserved2grabbed(estimate_insert_cluster(inode));
+#if REISER4_DEBUG
+		assert("edward-1267",
+		       clust->reserved_unprepped ==
+		       estimate_insert_cluster(inode));
+		clust->reserved_unprepped -= estimate_insert_cluster(inode);
+#endif
+	}
+	if (!should_create_unprepped_cluster(clust, inode)) {
+		all_grabbed2free();
+		return 0;
+	} else {
+		assert("edward-1268", clust->reserved == 1);
+	}
+	result = ctail_insert_unprepped_cluster(clust, inode);
+	all_grabbed2free();
+	if (result)
+		return result;
+
+	assert("edward-743", crc_inode_ok(inode));
+	assert("edward-1269", get_current_context()->grabbed_blocks == 0);
+	assert("edward-744", znode_is_write_locked(clust->hint->lh.node));
+
+	clust->dstat = UNPR_DISK_CLUSTER;
+	return 0;
+}
+
+#if REISER4_DEBUG
+static int jnode_truncate_ok(struct inode *inode, cloff_t index)
+{
+	jnode *node;
+	node =
+	    jlookup(current_tree, get_inode_oid(inode),
+		    clust_to_pg(index, inode));
+	if (node) {
+		warning("edward-1315", "jnode %p is untruncated\n", node);
+		jput(node);
+	}
+	return (node == NULL);
+}
+
+static int jnodes_truncate_ok(struct inode *inode, cloff_t start)
+{
+	int result;
+	jnode *node = NULL;
+	reiser4_inode *info = reiser4_inode_data(inode);
+	reiser4_tree *tree = tree_by_inode(inode);
+
+	read_lock_tree(tree);
+
+	result =
+	    radix_tree_gang_lookup(jnode_tree_by_reiser4_inode(info),
+				   (void **)&node, clust_to_pg(start, inode),
+				   1);
+	read_unlock_tree(tree);
+	if (result)
+		warning("edward-1332", "Untruncated jnode %p\n", node);
+	return !result;
+}
+
+#endif
+
+/* Collect unlocked cluster pages and jnode (the last is in the
+   case when the page cluster will be modified and captured) */
+int
+prepare_page_cluster(struct inode *inode, reiser4_cluster_t * clust,
+		     int capture)
+{
+	assert("edward-177", inode != NULL);
+	assert("edward-741", crc_inode_ok(inode));
+	assert("edward-740", clust->pages != NULL);
+
+	set_cluster_nrpages(clust, inode);
+	reset_cluster_pgset(clust, cluster_nrpages(inode));
+	return (capture ?
+		grab_cluster_pages_jnode(inode, clust) :
+		grab_cluster_pages(inode, clust));
+}
+
+/* Truncate all the pages and jnode bound with the cluster of index @index */
+void truncate_page_cluster(struct inode *inode, cloff_t index)
+{
+	int i;
+	int found = 0;
+	int nr_pages;
+	jnode *node;
+	struct page *pages[MAX_CLUSTER_NRPAGES];
+
+	node =
+	    jlookup(current_tree, get_inode_oid(inode),
+		    clust_to_pg(index, inode));
+	/* jnode is absent, just drop pages which can not
+	   acquire jnode because of exclusive access */
+	if (!node) {
+		truncate_inode_pages_range(inode->i_mapping,
+					   clust_to_off(index, inode),
+					   clust_to_off(index,
+							inode) +
+					   inode_cluster_size(inode) - 1);
+		return;
+	}
+	/* jnode is present and may be dirty, if so, put
+	   all the cluster pages except the first one */
+	nr_pages = count_to_nrpages(cnt_to_clcnt(inode->i_size, index, inode));
+
+	found = find_get_pages(inode->i_mapping, clust_to_pg(index, inode),
+			       nr_pages, pages);
+
+	spin_lock_jnode(node);
+	if (JF_ISSET(node, JNODE_DIRTY)) {
+		/* jnode is dirty => space for disk cluster
+		   conversion grabbed */
+		cluster_reserved2grabbed(estimate_update_cluster(inode));
+		grabbed2free(get_current_context(),
+			     get_current_super_private(),
+			     estimate_update_cluster(inode));
+
+		assert("edward-1198", found == nr_pages);
+		/* This will clear dirty bit so concurrent flush
+		   won't start to convert the disk cluster */
+		assert("edward-1199", PageUptodate(pages[0]));
+		uncapture_cluster_jnode(node);
+
+		for (i = 1; i < nr_pages; i++) {
+			assert("edward-1200", PageUptodate(pages[i]));
+
+			page_cache_release(pages[i]);
+		}
+	} else
+		spin_unlock_jnode(node);
+	/* now drop pages and jnode */
+	/* FIXME-EDWARD: Use truncate_complete_page in the loop above instead */
+
+	jput(node);
+	forget_cluster_pages(pages, found);
+	truncate_inode_pages_range(inode->i_mapping,
+				   clust_to_off(index, inode),
+				   clust_to_off(index,
+						inode) +
+				   inode_cluster_size(inode) - 1);
+	assert("edward-1201", jnode_truncate_ok(inode, index));
+	return;
+}
+
+/* Prepare cluster handle before write and(or) capture. This function
+   is called by all the clients which modify page cluster and(or) put
+   it into a transaction (file_write, truncate, writepages, etc..)
+
+   . grab cluster pages;
+   . reserve disk space;
+   . maybe read pages from disk and set the disk cluster dirty;
+   . maybe write hole;
+   . maybe create 'unprepped' disk cluster if the last one is fake
+     (isn't represenred by any items on disk)
+*/
+
+static int
+prepare_cluster(struct inode *inode,
+		loff_t file_off /* write position in the file */ ,
+		loff_t to_file,	/* bytes of users data to write to the file */
+		reiser4_cluster_t * clust, page_cluster_op op)
+{
+	int result = 0;
+	reiser4_slide_t *win = clust->win;
+
+	assert("edward-1273", get_current_context()->grabbed_blocks == 0);
+	reset_cluster_params(clust);
+#if REISER4_DEBUG
+	clust->ctx = get_current_context();
+#endif
+	assert("edward-1190", op != PCL_UNKNOWN);
+
+	clust->op = op;
+
+	result = prepare_page_cluster(inode, clust, 1);
+	if (result)
+		return result;
+	result = reserve4cluster(inode, clust);
+	if (result)
+		goto err1;
+	result = read_some_cluster_pages(inode, clust);
+	if (result) {
+		free_reserved4cluster(inode,
+				      clust,
+				      estimate_update_cluster(inode) +
+				      estimate_insert_cluster(inode));
+		goto err1;
+	}
+	assert("edward-1124", clust->dstat != INVAL_DISK_CLUSTER);
+
+	result = crc_make_unprepped_cluster(clust, inode);
+	if (result)
+		goto err2;
+	if (win && win->stat == HOLE_WINDOW) {
+		result = write_hole(inode, clust, file_off, to_file);
+		if (result)
+			goto err2;
+	}
+	return 0;
+      err2:
+	free_reserved4cluster(inode, clust,
+			      estimate_update_cluster(inode));
+      err1:
+	release_cluster_pages_and_jnode(clust);
+	assert("edward-1125", result == -ENOSPC);
+	return result;
+}
+
+/* set window by two offsets */
+static void
+set_window(reiser4_cluster_t * clust, reiser4_slide_t * win,
+	   struct inode *inode, loff_t o1, loff_t o2)
+{
+	assert("edward-295", clust != NULL);
+	assert("edward-296", inode != NULL);
+	assert("edward-1071", win != NULL);
+	assert("edward-297", o1 <= o2);
+
+	clust->index = off_to_clust(o1, inode);
+
+	win->off = off_to_cloff(o1, inode);
+	win->count = min_count(inode_cluster_size(inode) - win->off, o2 - o1);
+	win->delta = 0;
+
+	clust->win = win;
+}
+
+static int
+set_cluster_by_window(struct inode *inode, reiser4_cluster_t * clust,
+		      reiser4_slide_t * win, flow_t * f, loff_t file_off)
+{
+	int result;
+
+	assert("edward-197", clust != NULL);
+	assert("edward-1072", win != NULL);
+	assert("edward-198", inode != NULL);
+
+	result = alloc_cluster_pgset(clust, cluster_nrpages(inode));
+	if (result)
+		return result;
+
+	if (file_off > inode->i_size) {
+		/* Uhmm, hole in cryptcompress file... */
+		loff_t hole_size;
+		hole_size = file_off - inode->i_size;
+
+		set_window(clust, win, inode, inode->i_size, file_off);
+		win->stat = HOLE_WINDOW;
+		if (win->off + hole_size < inode_cluster_size(inode))
+			/* there is also user's data to append to the hole */
+			win->delta =
+			    min_count(inode_cluster_size(inode) -
+				      (win->off + win->count), f->length);
+		return 0;
+	}
+	set_window(clust, win, inode, file_off, file_off + f->length);
+	win->stat = DATA_WINDOW;
+	return 0;
+}
+
+int set_cluster_by_page(reiser4_cluster_t * clust, struct page * page,
+			int count)
+{
+	int result = 0;
+	int (*setting_actor)(reiser4_cluster_t * clust, int count);
+
+	assert("edward-1358", clust != NULL);
+	assert("edward-1359", page != NULL);
+	assert("edward-1360", page->mapping != NULL);
+	assert("edward-1361", page->mapping->host != NULL);
+
+	setting_actor  = (clust->pages ? reset_cluster_pgset : alloc_cluster_pgset);
+	result = setting_actor(clust, count);
+	clust->index = pg_to_clust(page->index, page->mapping->host);
+	return result;
+}
+
+/* reset all the params that not get updated */
+void reset_cluster_params(reiser4_cluster_t * clust)
+{
+	assert("edward-197", clust != NULL);
+
+	clust->dstat = INVAL_DISK_CLUSTER;
+	clust->tc.uptodate = 0;
+	clust->tc.len = 0;
+}
+
+/* Main write procedure for cryptcompress objects,
+   this slices user's data into clusters and copies to page cache.
+   If @buf != NULL, returns number of bytes in successfully written clusters,
+   otherwise returns error */
+/* FIXME_EDWARD replace flow by something lightweigth */
+
+static loff_t
+write_cryptcompress_flow(struct file *file, struct inode *inode,
+			 const char __user *buf, size_t count, loff_t pos)
+{
+	int i;
+	flow_t f;
+	hint_t *hint;
+	int result = 0;
+	size_t to_write = 0;
+	loff_t file_off;
+	reiser4_slide_t win;
+	reiser4_cluster_t clust;
+
+	assert("edward-161", schedulable());
+	assert("edward-748", crc_inode_ok(inode));
+	assert("edward-159", current_blocksize == PAGE_CACHE_SIZE);
+	assert("edward-1274", get_current_context()->grabbed_blocks == 0);
+
+	result = check_cryptcompress(inode);
+	if (result)
+		return result;
+	hint = kmalloc(sizeof(*hint), GFP_KERNEL);
+	if (hint == NULL)
+		return RETERR(-ENOMEM);
+
+	result = load_file_hint(file, hint);
+	if (result) {
+		kfree(hint);
+		return result;
+	}
+
+	result =
+	    flow_by_inode_cryptcompress(inode, buf, 1 /* user space */ ,
+					count, pos, WRITE_OP, &f);
+	if (result)
+		goto out;
+	to_write = f.length;
+
+	/* current write position in file */
+	file_off = pos;
+	reiser4_slide_init(&win);
+	cluster_init_read(&clust, &win);
+	clust.hint = hint;
+
+	result = set_cluster_by_window(inode, &clust, &win, &f, file_off);
+	if (result)
+		goto out;
+
+	if (next_window_stat(&win) == HOLE_WINDOW) {
+		result =
+		    prepare_cluster(inode, file_off, f.length, &clust,
+				    PCL_APPEND);
+		if (result)
+			goto out;
+	}
+	do {
+		char *src;
+		unsigned page_off, page_count;
+
+		assert("edward-750", schedulable());
+
+		result =
+		    prepare_cluster(inode, file_off, f.length, &clust,
+				    PCL_APPEND);
+		if (result)
+			goto out;
+
+		assert("edward-751", crc_inode_ok(inode));
+		assert("edward-204", win.stat == DATA_WINDOW);
+		assert("edward-1288", clust.hint->ext_coord.valid);
+		assert("edward-752",
+		       znode_is_write_locked(hint->ext_coord.coord.node));
+
+		put_hint_cluster(&clust, inode, ZNODE_WRITE_LOCK);
+
+		/* set write position in page */
+		page_off = off_to_pgoff(win.off);
+
+		/* copy user's data to cluster pages */
+		for (i = off_to_pg(win.off), src = f.data;
+		     i < count_to_nrpages(win.off + win.count);
+		     i++, src += page_count) {
+			page_count =
+			    cnt_to_pgcnt(win.off + win.count, i) - page_off;
+
+			assert("edward-1039",
+			       page_off + page_count <= PAGE_CACHE_SIZE);
+			assert("edward-287", clust.pages[i] != NULL);
+
+			lock_page(clust.pages[i]);
+			result =
+			    __copy_from_user((char *)kmap(clust.pages[i]) +
+					     page_off, (char __user *)src, page_count);
+			kunmap(clust.pages[i]);
+			if (unlikely(result)) {
+				unlock_page(clust.pages[i]);
+				result = -EFAULT;
+				goto err2;
+			}
+			SetPageUptodate(clust.pages[i]);
+			unlock_page(clust.pages[i]);
+			page_off = 0;
+		}
+		assert("edward-753", crc_inode_ok(inode));
+
+		set_cluster_pages_dirty(&clust);
+
+		result = try_capture_cluster(&clust, inode);
+		if (result)
+			goto err2;
+
+		assert("edward-998", f.user == 1);
+
+		move_flow_forward(&f, win.count);
+
+		/* disk cluster may be already clean at this point */
+
+		/* . update cluster
+		   . set hint for new offset
+		   . unlock znode
+		   . update inode
+		   . balance dirty pages
+		 */
+		result = balance_dirty_page_cluster(&clust, inode, 0, f.length);
+		if (result)
+			goto err1;
+		assert("edward-755", hint->lh.owner == NULL);
+		reset_cluster_params(&clust);
+		continue;
+	      err2:
+		release_cluster_pages_and_jnode(&clust);
+	      err1:
+		if (clust.reserved)
+			free_reserved4cluster(inode,
+					      &clust,
+					      estimate_update_cluster(inode));
+		break;
+	} while (f.length);
+      out:
+	done_lh(&hint->lh);
+	if (result == -EEXIST)
+		warning("edward-1407", "write returns EEXIST!\n");
+
+	put_cluster_handle(&clust);
+	save_file_hint(file, hint);
+	kfree(hint);
+	if (buf) {
+		/* if nothing were written - there must be an error */
+		assert("edward-195", ergo((to_write == f.length), result < 0));
+		return (to_write - f.length) ? (to_write - f.length) : result;
+	}
+	return result;
+}
+
+static ssize_t write_crc_file(struct file *file,	/* file to write to */
+			      struct inode *inode,	/* inode */
+			      const char __user *buf,	/* address of user-space buffer */
+			      size_t count,	/* number of bytes to write */
+			      loff_t * off /* position to write which */ )
+{
+
+	int result;
+	loff_t pos;
+	ssize_t written;
+	cryptcompress_info_t *info = cryptcompress_inode_data(inode);
+
+	assert("edward-196", crc_inode_ok(inode));
+
+	result = generic_write_checks(file, off, &count, 0);
+	if (unlikely(result != 0))
+		return result;
+
+	if (unlikely(count == 0))
+		return 0;
+
+	down_write(&info->lock);
+	LOCK_CNT_INC(inode_sem_w);
+
+	pos = *off;
+	written =
+	    write_cryptcompress_flow(file, inode, buf, count, pos);
+
+	up_write(&info->lock);
+	LOCK_CNT_DEC(inode_sem_w);
+
+	if (written < 0) {
+		if (written == -EEXIST)
+			printk("write_crc_file returns EEXIST!\n");
+		return written;
+	}
+	/* update position in a file */
+	*off = pos + written;
+	/* return number of written bytes */
+	return written;
+}
+
+/**
+ * write_cryptcompress - write of struct file_operations
+ * @file: file to write to
+ * @buf: address of user-space buffer
+ * @read_amount: number of bytes to write
+ * @off: position in file to write to
+ *
+ * This is implementation of vfs's write method of struct file_operations for
+ * cryptcompress plugin.
+ */
+ssize_t write_cryptcompress(struct file *file, const char __user *buf,
+			    size_t count, loff_t *off)
+{
+	ssize_t result;
+	struct inode *inode;
+	reiser4_context *ctx;
+
+	inode = file->f_dentry->d_inode;
+
+	ctx = init_context(inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	mutex_lock(&inode->i_mutex);
+
+	result = write_crc_file(file, inode, buf, count, off);
+
+	mutex_unlock(&inode->i_mutex);
+
+	context_set_commit_async(ctx);
+	reiser4_exit_context(ctx);
+	return result;
+}
+
+static void
+readpages_crc(struct address_space *mapping, struct list_head *pages,
+	      void *data)
+{
+	file_plugin *fplug;
+	item_plugin *iplug;
+
+	assert("edward-1112", mapping != NULL);
+	assert("edward-1113", mapping->host != NULL);
+
+	fplug = inode_file_plugin(mapping->host);
+	assert("edward-1114", fplug == file_plugin_by_id(CRC_FILE_PLUGIN_ID));
+	iplug = item_plugin_by_id(CTAIL_ID);
+
+	iplug->s.file.readpages(data, mapping, pages);
+
+	return;
+}
+
+static reiser4_block_nr cryptcompress_estimate_read(struct inode *inode)
+{
+	/* reserve one block to update stat data item */
+	assert("edward-1193",
+	       inode_file_plugin(inode)->estimate.update ==
+	       estimate_update_common);
+	return estimate_update_common(inode);
+}
+
+/**
+ * read_cryptcompress - read of struct file_operations
+ * @file: file to read from
+ * @buf: address of user-space buffer
+ * @read_amount: number of bytes to read
+ * @off: position in file to read from
+ *
+ * This is implementation of vfs's read method of struct file_operations for
+ * cryptcompress plugin.
+ */
+ssize_t read_cryptcompress(struct file * file, char __user *buf, size_t size,
+			   loff_t * off)
+{
+	ssize_t result;
+	struct inode *inode;
+	reiser4_context *ctx;
+	reiser4_file_fsdata *fsdata;
+	cryptcompress_info_t *info;
+	reiser4_block_nr needed;
+
+	inode = file->f_dentry->d_inode;
+	assert("edward-1194", !inode_get_flag(inode, REISER4_NO_SD));
+
+	ctx = init_context(inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	info = cryptcompress_inode_data(inode);
+	needed = cryptcompress_estimate_read(inode);
+
+	/* FIXME-EDWARD:
+	   Grab space for sd_update so find_cluster will be happy */
+	result = reiser4_grab_space(needed, BA_CAN_COMMIT);
+	if (result != 0) {
+		reiser4_exit_context(ctx);
+		return result;
+	}
+	fsdata = reiser4_get_file_fsdata(file);
+	fsdata->ra2.data = file;
+	fsdata->ra2.readpages = readpages_crc;
+
+	down_read(&info->lock);
+	LOCK_CNT_INC(inode_sem_r);
+
+	result = generic_file_read(file, buf, size, off);
+
+	up_read(&info->lock);
+	LOCK_CNT_DEC(inode_sem_r);
+
+	context_set_commit_async(ctx);
+	reiser4_exit_context(ctx);
+
+	return result;
+}
+
+/* If @index > 0, find real disk cluster of the index (@index - 1),
+   If @index == 0 find the real disk cluster of the object of maximal index.
+   Keep incremented index of the result in @found.
+   It succes was returned:
+   (@index == 0 && @found == 0) means that the object doesn't have real disk
+   clusters.
+   (@index != 0 && @found == 0) means that disk cluster of (@index -1) doesn't
+   exist.
+*/
+static int
+find_real_disk_cluster(struct inode *inode, cloff_t * found, cloff_t index)
+{
+	int result;
+	reiser4_key key;
+	loff_t offset;
+	hint_t *hint;
+	lock_handle *lh;
+	lookup_bias bias;
+	coord_t *coord;
+	item_plugin *iplug;
+
+	assert("edward-1131", inode != NULL);
+	assert("edward-95", crc_inode_ok(inode));
+
+	hint = kmalloc(sizeof(*hint), GFP_KERNEL);
+	if (hint == NULL)
+		return RETERR(-ENOMEM);
+	hint_init_zero(hint);
+	lh = &hint->lh;
+
+	bias = (index ? FIND_EXACT : FIND_MAX_NOT_MORE_THAN);
+	offset =
+	    (index ? clust_to_off(index, inode) -
+	     1 : get_key_offset(max_key()));
+
+	key_by_inode_cryptcompress(inode, offset, &key);
+
+	/* find the last item of this object */
+	result =
+	    find_cluster_item(hint, &key, ZNODE_READ_LOCK, NULL /* ra_info */,
+			      bias, 0);
+	if (cbk_errored(result)) {
+		done_lh(lh);
+		kfree(hint);
+		return result;
+	}
+	if (result == CBK_COORD_NOTFOUND) {
+		/* no real disk clusters */
+		done_lh(lh);
+		kfree(hint);
+		*found = 0;
+		return 0;
+	}
+	/* disk cluster is found */
+	coord = &hint->ext_coord.coord;
+	coord_clear_iplug(coord);
+	result = zload(coord->node);
+	if (unlikely(result)) {
+		done_lh(lh);
+		kfree(hint);
+		return result;
+	}
+	iplug = item_plugin_by_coord(coord);
+	assert("edward-277", iplug == item_plugin_by_id(CTAIL_ID));
+	assert("edward-1202", ctail_ok(coord));
+
+	item_key_by_coord(coord, &key);
+	*found = off_to_clust(get_key_offset(&key), inode) + 1;
+
+	assert("edward-1132", ergo(index, index == *found));
+
+	zrelse(coord->node);
+	done_lh(lh);
+	kfree(hint);
+	return 0;
+}
+
+static int find_fake_appended(struct inode *inode, cloff_t * index)
+{
+	return find_real_disk_cluster(inode, index,
+				      0 /* find last real one */ );
+}
+
+/* Set left coord when unit is not found after node_lookup()
+   This takes into account that there can be holes in a sequence
+   of disk clusters */
+
+static void adjust_left_coord(coord_t * left_coord)
+{
+	switch (left_coord->between) {
+	case AFTER_UNIT:
+		left_coord->between = AFTER_ITEM;
+	case AFTER_ITEM:
+	case BEFORE_UNIT:
+		break;
+	default:
+		impossible("edward-1204", "bad left coord to cut");
+	}
+	return;
+}
+
+#define CRC_CUT_TREE_MIN_ITERATIONS 64
+int
+cut_tree_worker_cryptcompress(tap_t * tap, const reiser4_key * from_key,
+			      const reiser4_key * to_key,
+			      reiser4_key * smallest_removed,
+			      struct inode *object, int truncate, int *progress)
+{
+	lock_handle next_node_lock;
+	coord_t left_coord;
+	int result;
+
+	assert("edward-1158", tap->coord->node != NULL);
+	assert("edward-1159", znode_is_write_locked(tap->coord->node));
+	assert("edward-1160", znode_get_level(tap->coord->node) == LEAF_LEVEL);
+
+	*progress = 0;
+	init_lh(&next_node_lock);
+
+	while (1) {
+		znode *node;	/* node from which items are cut */
+		node_plugin *nplug;	/* node plugin for @node */
+
+		node = tap->coord->node;
+
+		/* Move next_node_lock to the next node on the left. */
+		result =
+		    reiser4_get_left_neighbor(&next_node_lock, node,
+					      ZNODE_WRITE_LOCK,
+					      GN_CAN_USE_UPPER_LEVELS);
+		if (result != 0 && result != -E_NO_NEIGHBOR)
+			break;
+		/* FIXME-EDWARD: Check can we delete the node as a whole. */
+		result = tap_load(tap);
+		if (result)
+			return result;
+
+		/* Prepare the second (right) point for cut_node() */
+		if (*progress)
+			coord_init_last_unit(tap->coord, node);
+
+		else if (item_plugin_by_coord(tap->coord)->b.lookup == NULL)
+			/* set rightmost unit for the items without lookup method */
+			tap->coord->unit_pos = coord_last_unit_pos(tap->coord);
+
+		nplug = node->nplug;
+
+		assert("edward-1161", nplug);
+		assert("edward-1162", nplug->lookup);
+
+		/* left_coord is leftmost unit cut from @node */
+		result = nplug->lookup(node, from_key, FIND_EXACT, &left_coord);
+
+		if (IS_CBKERR(result))
+			break;
+
+		if (result == CBK_COORD_NOTFOUND)
+			adjust_left_coord(&left_coord);
+
+		/* adjust coordinates so that they are set to existing units */
+		if (coord_set_to_right(&left_coord)
+		    || coord_set_to_left(tap->coord)) {
+			result = 0;
+			break;
+		}
+
+		if (coord_compare(&left_coord, tap->coord) ==
+		    COORD_CMP_ON_RIGHT) {
+			/* keys from @from_key to @to_key are not in the tree */
+			result = 0;
+			break;
+		}
+
+		/* cut data from one node */
+		*smallest_removed = *min_key();
+		result = kill_node_content(&left_coord,
+					   tap->coord,
+					   from_key,
+					   to_key,
+					   smallest_removed,
+					   next_node_lock.node,
+					   object, truncate);
+#if REISER4_DEBUG
+		/*node_check(node, ~0U); */
+#endif
+		tap_relse(tap);
+
+		if (result)
+			break;
+
+		++(*progress);
+
+		/* Check whether all items with keys >= from_key were removed
+		 * from the tree. */
+		if (keyle(smallest_removed, from_key))
+			/* result = 0; */
+			break;
+
+		if (next_node_lock.node == NULL)
+			break;
+
+		result = tap_move(tap, &next_node_lock);
+		done_lh(&next_node_lock);
+		if (result)
+			break;
+
+		/* Break long cut_tree operation (deletion of a large file) if
+		 * atom requires commit. */
+		if (*progress > CRC_CUT_TREE_MIN_ITERATIONS
+		    && current_atom_should_commit()) {
+			result = -E_REPEAT;
+			break;
+		}
+	}
+	done_lh(&next_node_lock);
+	return result;
+}
+
+/* Append or expand hole in two steps (exclusive access should be aquired!)
+   1) write zeroes to the current real cluster,
+   2) expand hole via fake clusters (just increase i_size) */
+static int
+cryptcompress_append_hole(struct inode *inode /*contains old i_size */ ,
+			  loff_t new_size)
+{
+	int result = 0;
+	hint_t *hint;
+	lock_handle *lh;
+	loff_t hole_size;
+	int nr_zeroes;
+	reiser4_slide_t win;
+	reiser4_cluster_t clust;
+
+	assert("edward-1133", inode->i_size < new_size);
+	assert("edward-1134", schedulable());
+	assert("edward-1135", crc_inode_ok(inode));
+	assert("edward-1136", current_blocksize == PAGE_CACHE_SIZE);
+	assert("edward-1333", off_to_cloff(inode->i_size, inode) != 0);
+
+	hint = kmalloc(sizeof(*hint), GFP_KERNEL);
+	if (hint == NULL)
+		return RETERR(-ENOMEM);
+	hint_init_zero(hint);
+	lh = &hint->lh;
+
+	reiser4_slide_init(&win);
+	cluster_init_read(&clust, &win);
+	clust.hint = hint;
+
+	/* set cluster handle */
+	result = alloc_cluster_pgset(&clust, cluster_nrpages(inode));
+	if (result)
+		goto out;
+	if (off_to_cloff(inode->i_size, inode) == 0)
+		goto fake_append;
+	hole_size = new_size - inode->i_size;
+	nr_zeroes =
+		inode_cluster_size(inode) - off_to_cloff(inode->i_size, inode);
+	if (hole_size < nr_zeroes)
+		nr_zeroes = hole_size;
+	set_window(&clust, &win, inode, inode->i_size,
+		   inode->i_size + nr_zeroes);
+	win.stat = HOLE_WINDOW;
+
+	assert("edward-1137",
+	       clust.index == off_to_clust(inode->i_size, inode));
+
+	result = prepare_cluster(inode, 0, 0, &clust, PCL_APPEND);
+
+	assert("edward-1271", !result || result == -ENOSPC);
+	if (result)
+		goto out;
+	assert("edward-1139",
+	       clust.dstat == PREP_DISK_CLUSTER ||
+	       clust.dstat == UNPR_DISK_CLUSTER);
+
+	assert("edward-1431", hole_size >= nr_zeroes);
+	if (hole_size == nr_zeroes)
+	/* nothing to append anymore */
+		goto out;
+      fake_append:
+	INODE_SET_FIELD(inode, i_size, new_size);
+      out:
+	done_lh(lh);
+	kfree(hint);
+	put_cluster_handle(&clust);
+	return result;
+}
+
+#if REISER4_DEBUG
+static int
+pages_truncate_ok(struct inode *inode, loff_t old_size, pgoff_t start)
+{
+	struct pagevec pvec;
+	int i;
+	int count;
+	int rest;
+
+	rest = count_to_nrpages(old_size) - start;
+
+	pagevec_init(&pvec, 0);
+	count = min_count(pagevec_space(&pvec), rest);
+
+	while (rest) {
+		count = min_count(pagevec_space(&pvec), rest);
+		pvec.nr = find_get_pages(inode->i_mapping, start,
+					 count, pvec.pages);
+		for (i = 0; i < pagevec_count(&pvec); i++) {
+			if (PageUptodate(pvec.pages[i])) {
+				warning("edward-1205",
+					"truncated page of index %lu is uptodate",
+					pvec.pages[i]->index);
+				return 0;
+			}
+		}
+		start += count;
+		rest -= count;
+		pagevec_release(&pvec);
+	}
+	return 1;
+}
+
+static int body_truncate_ok(struct inode *inode, cloff_t aidx)
+{
+	int result;
+	cloff_t raidx;
+
+	result = find_fake_appended(inode, &raidx);
+	return !result && (aidx == raidx);
+}
+#endif
+
+static int
+update_cryptcompress_size(struct inode *inode, reiser4_key * key, int update_sd)
+{
+	return (get_key_offset(key) & ((loff_t) (inode_cluster_size(inode)) - 1)
+		? 0 : update_file_size(inode, key, update_sd));
+}
+
+/* prune cryptcompress file in two steps (exclusive access should be acquired!)
+   1) cut all disk clusters but the last one partially truncated,
+   2) set zeroes and capture last partially truncated page cluster if the last
+      one exists, otherwise truncate via prune fake cluster (just decrease i_size)
+*/
+static int
+prune_cryptcompress(struct inode *inode, loff_t new_size, int update_sd,
+		    cloff_t aidx)
+{
+	int result = 0;
+	unsigned nr_zeroes;
+	loff_t to_prune;
+	loff_t old_size;
+	cloff_t ridx;
+
+	hint_t *hint;
+	lock_handle *lh;
+	reiser4_slide_t win;
+	reiser4_cluster_t clust;
+
+	assert("edward-1140", inode->i_size >= new_size);
+	assert("edward-1141", schedulable());
+	assert("edward-1142", crc_inode_ok(inode));
+	assert("edward-1143", current_blocksize == PAGE_CACHE_SIZE);
+
+	hint = kmalloc(sizeof(*hint), GFP_KERNEL);
+	if (hint == NULL)
+		return RETERR(-ENOMEM);
+	hint_init_zero(hint);
+	lh = &hint->lh;
+
+	reiser4_slide_init(&win);
+	cluster_init_read(&clust, &win);
+	clust.hint = hint;
+
+	/* rightmost completely truncated cluster */
+	ridx = count_to_nrclust(new_size, inode);
+
+	assert("edward-1174", ridx <= aidx);
+	old_size = inode->i_size;
+	if (ridx != aidx) {
+		result = cut_file_items(inode,
+					clust_to_off(ridx, inode),
+					update_sd,
+					clust_to_off(aidx, inode),
+					update_cryptcompress_size);
+		if (result)
+			goto out;
+	}
+	if (!off_to_cloff(new_size, inode)) {
+		/* no partially truncated clusters */
+		assert("edward-1145", inode->i_size == new_size);
+		goto finish;
+	}
+	assert("edward-1146", new_size < inode->i_size);
+
+	to_prune = inode->i_size - new_size;
+
+	/* check if partially truncated cluster is fake */
+	result = find_real_disk_cluster(inode, &aidx, ridx);
+	if (result)
+		goto out;
+	if (!aidx)
+		/* yup, this is fake one */
+		goto finish;
+
+	assert("edward-1148", aidx == ridx);
+
+	/* try to capture partially truncated page cluster */
+	result = alloc_cluster_pgset(&clust, cluster_nrpages(inode));
+	if (result)
+		goto out;
+	nr_zeroes = (off_to_pgoff(new_size) ?
+		     PAGE_CACHE_SIZE - off_to_pgoff(new_size) : 0);
+	set_window(&clust, &win, inode, new_size, new_size + nr_zeroes);
+	win.stat = HOLE_WINDOW;
+
+	assert("edward-1149", clust.index == ridx - 1);
+
+	result = prepare_cluster(inode, 0, 0, &clust, PCL_TRUNCATE);
+	if (result)
+		goto out;
+	assert("edward-1151",
+	       clust.dstat == PREP_DISK_CLUSTER ||
+	       clust.dstat == UNPR_DISK_CLUSTER);
+
+	assert("edward-1191", inode->i_size == new_size);
+	assert("edward-1206", body_truncate_ok(inode, ridx));
+      finish:
+	/* drop all the pages that don't have jnodes (i.e. pages
+	   which can not be truncated by cut_file_items() because
+	   of holes represented by fake disk clusters) including
+	   the pages of partially truncated cluster which was
+	   released by prepare_cluster() */
+	truncate_inode_pages(inode->i_mapping, new_size);
+	INODE_SET_FIELD(inode, i_size, new_size);
+      out:
+	assert("edward-1334", !result || result == -ENOSPC);
+	assert("edward-1209",
+	       pages_truncate_ok(inode, old_size, count_to_nrpages(new_size)));
+	assert("edward-1335",
+	       jnodes_truncate_ok(inode, count_to_nrclust(new_size, inode)));
+	done_lh(lh);
+	kfree(hint);
+	put_cluster_handle(&clust);
+	return result;
+}
+
+static int
+start_truncate_fake(struct inode *inode, cloff_t aidx, loff_t new_size,
+		    int update_sd)
+{
+	int result = 0;
+	int bytes;
+
+	if (new_size > inode->i_size) {
+		/* append */
+		if (inode->i_size < clust_to_off(aidx, inode))
+			/* no fake bytes */
+			return 0;
+		bytes = new_size - inode->i_size;
+		INODE_SET_FIELD(inode, i_size, inode->i_size + bytes);
+	} else {
+		/* prune */
+		if (inode->i_size <= clust_to_off(aidx, inode))
+			/* no fake bytes */
+			return 0;
+		bytes =
+		    inode->i_size - max_count(new_size,
+					      clust_to_off(aidx, inode));
+		if (!bytes)
+			return 0;
+		INODE_SET_FIELD(inode, i_size, inode->i_size - bytes);
+		/* In the case of fake prune we need to drop page cluster.
+		   There are only 2 cases for partially truncated page:
+		   1. If is is dirty, therefore it is anonymous
+		   (was dirtied via mmap), and will be captured
+		   later via ->capture().
+		   2. If is clean, therefore it is filled by zeroes.
+		   In both cases we don't need to make it dirty and
+		   capture here.
+		 */
+		truncate_inode_pages(inode->i_mapping, inode->i_size);
+		assert("edward-1336",
+		       jnodes_truncate_ok(inode,
+					  count_to_nrclust(inode->i_size,
+							   inode)));
+	}
+	if (update_sd)
+		result = update_sd_cryptcompress(inode);
+	return result;
+}
+
+/* This is called in setattr_cryptcompress when it is used to truncate,
+   and in delete_cryptcompress */
+static int cryptcompress_truncate(struct inode *inode,	/* old size */
+				  loff_t new_size,	/* new size */
+				  int update_sd)
+{
+	int result;
+	cloff_t aidx;
+
+	result = find_fake_appended(inode, &aidx);
+	if (result)
+		return result;
+	assert("edward-1208",
+	       ergo(aidx > 0, inode->i_size > clust_to_off(aidx - 1, inode)));
+
+	result = start_truncate_fake(inode, aidx, new_size, update_sd);
+	if (result)
+		return result;
+	if (inode->i_size == new_size)
+		/* nothing to truncate anymore */
+		return 0;
+	return (inode->i_size < new_size ?
+		cryptcompress_append_hole(inode, new_size) :
+		prune_cryptcompress(inode, new_size, update_sd, aidx));
+}
+
+/* page cluser is anonymous if it contains at least one anonymous page */
+static int
+capture_page_cluster(reiser4_cluster_t * clust, struct inode *inode)
+{
+	int result;
+
+	assert("edward-1073", clust != NULL);
+	assert("edward-1074", inode != NULL);
+	assert("edward-1075", clust->dstat == INVAL_DISK_CLUSTER);
+
+	result = prepare_cluster(inode, 0, 0, clust, PCL_APPEND);
+	if (result)
+		return result;
+	set_cluster_pages_dirty(clust);
+
+	result = try_capture_cluster(clust, inode);
+	put_hint_cluster(clust, inode, ZNODE_WRITE_LOCK);
+	if (result)
+		release_cluster_pages_and_jnode(clust);
+	return result;
+}
+
+#define MAX_CLUSTERS_TO_CAPTURE(inode)    (1024 >> cluster_nrpages_shift(inode))
+
+/* read lock should be acquired */
+static int
+capture_anonymous_clusters(struct address_space *mapping, pgoff_t * index,
+			   int to_capture)
+{
+	int result = 0;
+	int found;
+	int progress = 0;
+	struct page *page = NULL;
+	hint_t *hint;
+	lock_handle *lh;
+	reiser4_cluster_t clust;
+
+	assert("edward-1127", mapping != NULL);
+	assert("edward-1128", mapping->host != NULL);
+
+	hint = kmalloc(sizeof(*hint), GFP_KERNEL);
+	if (hint == NULL)
+		return RETERR(-ENOMEM);
+	hint_init_zero(hint);
+	lh = &hint->lh;
+
+	cluster_init_read(&clust, NULL);
+	clust.hint = hint;
+
+	result = alloc_cluster_pgset(&clust, cluster_nrpages(mapping->host));
+	if (result)
+		goto out;
+
+	while (to_capture > 0) {
+		found =
+		    find_get_pages_tag(mapping, index,
+				       PAGECACHE_TAG_REISER4_MOVED, 1, &page);
+		if (!found) {
+			*index = (pgoff_t) - 1;
+			break;
+		}
+		assert("edward-1109", page != NULL);
+
+		move_cluster_forward(&clust, mapping->host, page->index,
+				     &progress);
+		result = capture_page_cluster(&clust, mapping->host);
+		page_cache_release(page);
+		if (result)
+			break;
+		to_capture--;
+	}
+	if (result) {
+		warning("edward-1077",
+			"Cannot capture anon pages: result=%i (captured=%d)\n",
+			result,
+			((__u32) MAX_CLUSTERS_TO_CAPTURE(mapping->host)) -
+			to_capture);
+	} else {
+		/* something had to be found */
+		assert("edward-1078",
+		       to_capture <= MAX_CLUSTERS_TO_CAPTURE(mapping->host));
+		if (to_capture <= 0)
+			/* there may be left more pages */
+			__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+	}
+      out:
+	done_lh(lh);
+	kfree(hint);
+	put_cluster_handle(&clust);
+	return result;
+}
+
+/* Check mapping for existence of not captured dirty pages.
+   This returns !0 if either page tree contains pages tagged
+   PAGECACHE_TAG_REISER4_MOVED */
+static int crc_inode_has_anon_pages(struct inode *inode)
+{
+	return mapping_tagged(inode->i_mapping, PAGECACHE_TAG_REISER4_MOVED);
+}
+
+/* this is implementation of vfs's writepages method of struct
+   address_space_operations */
+int
+writepages_cryptcompress(struct address_space *mapping,
+			 struct writeback_control *wbc)
+{
+	int result;
+	int to_capture;
+	pgoff_t nrpages;
+	pgoff_t index = 0;
+	cryptcompress_info_t *info;
+	struct inode *inode;
+
+	inode = mapping->host;
+	if (!crc_inode_has_anon_pages(inode)) {
+		result = 0;
+		goto end;
+	}
+
+	info = cryptcompress_inode_data(inode);
+	nrpages = count_to_nrpages(i_size_read(inode));
+
+	if (wbc->sync_mode != WB_SYNC_ALL)
+		to_capture =
+		    min_count(wbc->nr_to_write, MAX_CLUSTERS_TO_CAPTURE(inode));
+	else
+		to_capture = MAX_CLUSTERS_TO_CAPTURE(inode);
+	do {
+		reiser4_context *ctx;
+
+		if (is_in_reiser4_context()) {
+			/* FIXME-EDWARD: REMOVEME */
+			all_grabbed2free();
+
+			/* It can be in the context of write system call from
+			   balance_dirty_pages() */
+			if (down_read_trylock(&info->lock) == 0) {
+				result = RETERR(-EBUSY);
+				break;
+			}
+		} else
+			down_read(&info->lock);
+
+		ctx = init_context(inode->i_sb);
+		if (IS_ERR(ctx)) {
+			result = PTR_ERR(ctx);
+			break;
+		}
+		ctx->nobalance = 1;
+
+		assert("edward-1079",
+		       lock_stack_isclean(get_current_lock_stack()));
+
+		LOCK_CNT_INC(inode_sem_r);
+
+		result =
+		    capture_anonymous_clusters(inode->i_mapping, &index,
+					       to_capture);
+
+		up_read(&info->lock);
+
+		LOCK_CNT_DEC(inode_sem_r);
+
+		if (result != 0 || wbc->sync_mode != WB_SYNC_ALL) {
+			reiser4_exit_context(ctx);
+			break;
+		}
+		result = txnmgr_force_commit_all(inode->i_sb, 0);
+		reiser4_exit_context(ctx);
+	} while (result == 0 && index < nrpages);
+
+      end:
+	if (is_in_reiser4_context()) {
+		if (get_current_context()->nr_captured >= CAPTURE_APAGE_BURST) {
+			/* there are already pages to flush, flush them out, do
+			   not delay until end of reiser4_sync_inodes */
+			writeout(inode->i_sb, wbc);
+			get_current_context()->nr_captured = 0;
+		}
+	}
+	return result;
+}
+
+/* plugin->u.file.mmap */
+int mmap_cryptcompress(struct file *file, struct vm_area_struct *vma)
+{
+	//return -ENOSYS;
+	return generic_file_mmap(file, vma);
+}
+
+/* plugin->u.file.release */
+/* plugin->u.file.get_block */
+
+/* implentation of vfs' bmap method of struct address_space_operations for
+   cryptcompress plugin
+*/
+sector_t bmap_cryptcompress(struct address_space * mapping, sector_t lblock)
+{
+	struct inode *inode;
+	sector_t block;
+
+	inode = mapping->host;
+	if (off_to_cloff ((loff_t)lblock * current_blocksize, inode))
+		/* mapping not cluster offsets is meaningless */
+		return RETERR(-EINVAL);
+	else {
+		int result;
+		reiser4_key key;
+		hint_t *hint;
+		lock_handle *lh;
+		item_plugin *iplug;
+
+		assert("edward-1166", 0);
+		key_by_inode_cryptcompress(inode,
+					   (loff_t) block * current_blocksize,
+					   &key);
+
+		hint = kmalloc(sizeof(*hint), GFP_KERNEL);
+		if (IS_ERR(hint))
+			return RETERR(-ENOMEM);
+		hint_init_zero(hint);
+		lh = &hint->lh;
+		result =
+		    find_cluster_item(hint, &key, ZNODE_READ_LOCK, NULL,
+				      FIND_EXACT, 0);
+		if (result != CBK_COORD_FOUND) {
+			done_lh(lh);
+			kfree(hint);
+			return result;
+		}
+		result = zload(hint->ext_coord.coord.node);
+		if (unlikely(result)) {
+			done_lh(lh);
+			kfree(hint);
+			return result;
+		}
+		iplug = item_plugin_by_coord(&hint->ext_coord.coord);
+
+		assert("edward-421", iplug == item_plugin_by_id(CTAIL_ID));
+
+		if (iplug->s.file.get_block) {
+			result =
+			    iplug->s.file.get_block(&hint->ext_coord.coord,
+						    lblock, &block);
+			if (result == 0)
+				result = block;
+		} else
+			result = RETERR(-EINVAL);
+
+		zrelse(hint->ext_coord.coord.node);
+		done_lh(lh);
+		kfree(hint);
+		return result;
+	}
+}
+
+/* this is implementation of delete method of file plugin for
+   cryptcompress objects */
+int delete_cryptcompress(struct inode *inode)
+{
+	int result;
+
+	assert("edward-429", inode->i_nlink == 0);
+
+	if (inode->i_size) {
+		result = cryptcompress_truncate(inode, 0, 0);
+		if (result) {
+			warning("edward-430",
+				"cannot truncate cryptcompress file  %lli: %i",
+				(unsigned long long)get_inode_oid(inode),
+				result);
+			return result;
+		}
+	}
+	/* and remove stat data */
+	return delete_object_common(inode);
+}
+
+/* plugin->u.file.setattr method
+   see plugin.h for description */
+int setattr_cryptcompress(struct dentry *dentry,	/* Object to change attributes */
+			  struct iattr *attr /* change description */ )
+{
+	int result;
+	struct inode *inode;
+
+	inode = dentry->d_inode;
+	result = check_cryptcompress(inode);
+	if (result)
+		return result;
+	if (attr->ia_valid & ATTR_SIZE) {
+		/* EDWARD-FIXME-HANS: VS-FIXME-HANS:
+		   Q: this case occurs when? truncate?
+		   A: yes
+
+		   Q: If so, why isn't this code in truncate itself instead of here?
+
+		   A: because vfs calls fs's truncate after it has called truncate_inode_pages to get rid of pages
+		   corresponding to part of file being truncated. In reiser4 it may cause existence of unallocated
+		   extents which do not have jnodes. Flush code does not expect that. Solution of this problem is
+		   straightforward. As vfs's truncate is implemented using setattr operation (common implementaion of
+		   which calls truncate_inode_pages and fs's truncate in case when size of file changes) - it seems
+		   reasonable to have reiser4_setattr which will take care of removing pages, jnodes and extents
+		   simultaneously in case of truncate.
+		   Q: do you think implementing truncate using setattr is ugly,
+		   and vfs needs improving, or is there some sense in which this is a good design?
+
+		   A: VS-FIXME-HANS:
+		 */
+
+		/* truncate does reservation itself and requires exclusive access obtained */
+		if (inode->i_size != attr->ia_size) {
+			reiser4_context *ctx;
+			loff_t old_size;
+			cryptcompress_info_t *info =
+			    cryptcompress_inode_data(inode);
+
+			ctx = init_context(dentry->d_inode->i_sb);
+			if (IS_ERR(ctx))
+				return PTR_ERR(ctx);
+
+			down_write(&info->lock);
+			LOCK_CNT_INC(inode_sem_w);
+
+			inode_check_scale(inode, inode->i_size, attr->ia_size);
+
+			old_size = inode->i_size;
+
+			result =
+			    cryptcompress_truncate(inode, attr->ia_size,
+						   1 /* update stat data */ );
+			if (result) {
+				warning("edward-1192",
+					"truncate_cryptcompress failed: oid %lli, "
+					"old size %lld, new size %lld, retval %d",
+					(unsigned long long)
+					get_inode_oid(inode), old_size,
+					attr->ia_size, result);
+			}
+			up_write(&info->lock);
+			LOCK_CNT_DEC(inode_sem_w);
+			context_set_commit_async(ctx);
+			reiser4_exit_context(ctx);
+		} else
+			result = 0;
+	} else
+		result = setattr_common(dentry, attr);
+	return result;
+}
+
+/* sendfile_cryptcompress - sendfile of struct file_operations */
+ssize_t
+sendfile_cryptcompress(struct file *file, loff_t *ppos, size_t count,
+		       read_actor_t actor, void *target)
+{
+	reiser4_context *ctx;
+	ssize_t result;
+	struct inode *inode;
+	cryptcompress_info_t *info;
+
+	inode = file->f_dentry->d_inode;
+	ctx = init_context(inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+	/*
+	 * generic_file_sndfile may want to call update_atime. Grab space for
+	 * stat data update
+	 */
+	result = reiser4_grab_space(estimate_update_common(inode),
+				    BA_CAN_COMMIT);
+	if (result)
+		goto exit;
+	info = cryptcompress_inode_data(inode);
+	down_read(&info->lock);
+	result = generic_file_sendfile(file, ppos, count, actor, target);
+	up_read(&info->lock);
+ exit:
+	reiser4_exit_context(ctx);
+	return result;
+}
+
+/*
+ * release_cryptcompress - release of struct file_operations
+ * @inode: inode of released file
+ * @file: file to release
+ */
+int release_cryptcompress(struct inode *inode, struct file *file)
+{
+	reiser4_context *ctx = init_context(inode->i_sb);
+
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+	reiser4_free_file_fsdata(file);
+	reiser4_exit_context(ctx);
+	return 0;
+}
+
+static int
+save_len_cryptcompress_plugin(struct inode *inode, reiser4_plugin * plugin)
+{
+	assert("edward-457", inode != NULL);
+	assert("edward-458", plugin != NULL);
+	assert("edward-459", plugin->h.id == CRC_FILE_PLUGIN_ID);
+	return 0;
+}
+
+static int
+load_cryptcompress_plugin(struct inode *inode, reiser4_plugin * plugin,
+			  char **area, int *len)
+{
+	assert("edward-455", inode != NULL);
+	assert("edward-456", (reiser4_inode_data(inode)->pset != NULL));
+
+	plugin_set_file(&reiser4_inode_data(inode)->pset,
+			file_plugin_by_id(CRC_FILE_PLUGIN_ID));
+	return 0;
+}
+
+static int change_cryptcompress(struct inode *inode, reiser4_plugin * plugin)
+{
+	/* cannot change object plugin of already existing object */
+	return RETERR(-EINVAL);
+}
+
+struct reiser4_plugin_ops cryptcompress_plugin_ops = {
+	.load = load_cryptcompress_plugin,
+	.save_len = save_len_cryptcompress_plugin,
+	.save = NULL,
+	.alignment = 8,
+	.change = change_cryptcompress
+};
+
+/*
+  Local variables:
+  c-indentation-style: "K&R"
+  mode-name: "LC"
+  c-basic-offset: 8
+  tab-width: 8
+  fill-column: 80
+  scroll-step: 1
+  End:
+*/
diff -urN oldtree/fs/reiser4/plugin/file/cryptcompress.h newtree/fs/reiser4/plugin/file/cryptcompress.h
--- oldtree/fs/reiser4/plugin/file/cryptcompress.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/file/cryptcompress.h	2006-02-21 15:58:35.444758136 +0000
@@ -0,0 +1,547 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+/* See http://www.namesys.com/cryptcompress_design.html */
+
+#if !defined( __FS_REISER4_CRYPTCOMPRESS_H__ )
+#define __FS_REISER4_CRYPTCOMPRESS_H__
+
+#include "../compress/compress.h"
+#include "../crypto/cipher.h"
+
+#include <linux/pagemap.h>
+#include <linux/vmalloc.h>
+
+#define MIN_CLUSTER_SIZE PAGE_CACHE_SIZE
+#define MIN_CLUSTER_SHIFT PAGE_CACHE_SHIFT
+#define MAX_CLUSTER_SHIFT 16
+#define MAX_CLUSTER_NRPAGES (1U << MAX_CLUSTER_SHIFT >> PAGE_CACHE_SHIFT)
+#define DC_CHECKSUM_SIZE 4
+
+static inline loff_t min_count(loff_t a, loff_t b)
+{
+	return (a < b ? a : b);
+}
+
+static inline loff_t max_count(loff_t a, loff_t b)
+{
+	return (a > b ? a : b);
+}
+
+#if REISER4_DEBUG
+static inline int cluster_shift_ok(int shift)
+{
+	return (shift >= MIN_CLUSTER_SHIFT) && (shift <= MAX_CLUSTER_SHIFT);
+}
+#endif
+
+typedef struct tfm_stream {
+	__u8 *data;
+	size_t size;
+} tfm_stream_t;
+
+typedef enum {
+	INPUT_STREAM,
+	OUTPUT_STREAM,
+	LAST_STREAM
+} tfm_stream_id;
+
+typedef tfm_stream_t *tfm_unit[LAST_STREAM];
+
+static inline __u8 *ts_data(tfm_stream_t * stm)
+{
+	assert("edward-928", stm != NULL);
+	return stm->data;
+}
+
+static inline size_t ts_size(tfm_stream_t * stm)
+{
+	assert("edward-929", stm != NULL);
+	return stm->size;
+}
+
+static inline void set_ts_size(tfm_stream_t * stm, size_t size)
+{
+	assert("edward-930", stm != NULL);
+
+	stm->size = size;
+}
+
+static inline int alloc_ts(tfm_stream_t ** stm)
+{
+	assert("edward-931", stm);
+	assert("edward-932", *stm == NULL);
+
+	*stm = kmalloc(sizeof **stm, GFP_KERNEL);
+	if (*stm == NULL)
+		return -ENOMEM;
+	memset(*stm, 0, sizeof **stm);
+	return 0;
+}
+
+static inline void free_ts(tfm_stream_t * stm)
+{
+	assert("edward-933", !ts_data(stm));
+	assert("edward-934", !ts_size(stm));
+
+	kfree(stm);
+}
+
+static inline int alloc_ts_data(tfm_stream_t * stm, size_t size)
+{
+	assert("edward-935", !ts_data(stm));
+	assert("edward-936", !ts_size(stm));
+	assert("edward-937", size != 0);
+
+	stm->data = vmalloc(size);
+	if (!stm->data)
+		return -ENOMEM;
+	set_ts_size(stm, size);
+	return 0;
+}
+
+static inline void free_ts_data(tfm_stream_t * stm)
+{
+	assert("edward-938", equi(ts_data(stm), ts_size(stm)));
+
+	if (ts_data(stm))
+		vfree(ts_data(stm));
+	memset(stm, 0, sizeof *stm);
+}
+
+/* Write modes for item conversion in flush convert phase */
+typedef enum {
+	CRC_APPEND_ITEM = 1,
+	CRC_OVERWRITE_ITEM = 2,
+	CRC_CUT_ITEM = 3
+} crc_write_mode_t;
+
+typedef enum {
+	PCL_UNKNOWN = 0,	/* invalid option */
+	PCL_APPEND = 1,		/* append and/or overwrite */
+	PCL_TRUNCATE = 2	/* truncate */
+} page_cluster_op;
+
+/* Reiser4 file write/read transforms page cluster into disk cluster (and back)
+   using crypto/compression transforms implemented by reiser4 transform plugins.
+   Before each transform we allocate a pair of streams (tfm_unit) and assemble
+   page cluster into the input one. After transform we split output stream into
+   a set of items (disk cluster).
+*/
+typedef struct tfm_cluster {
+	coa_set coa;
+	tfm_unit tun;
+	tfm_action act;
+	int uptodate;
+	int lsize;        /* size of the logical cluster */
+	int len;          /* length of the transform stream */
+} tfm_cluster_t;
+
+static inline coa_t get_coa(tfm_cluster_t * tc, reiser4_compression_id id)
+{
+	return tc->coa[id];
+}
+
+static inline void
+set_coa(tfm_cluster_t * tc, reiser4_compression_id id, coa_t coa)
+{
+	tc->coa[id] = coa;
+}
+
+static inline int
+alloc_coa(tfm_cluster_t * tc, compression_plugin * cplug)
+{
+	coa_t coa;
+
+	assert("edward-1408", tc->act != TFM_INVAL);
+
+	coa = cplug->alloc(tc->act);
+	if (IS_ERR(coa))
+		return PTR_ERR(coa);
+	set_coa(tc, cplug->h.id, coa);
+	return 0;
+}
+
+static inline int
+grab_coa(tfm_cluster_t * tc, compression_plugin * cplug)
+{
+	return (cplug->alloc && !get_coa(tc, cplug->h.id) ?
+		alloc_coa(tc, cplug) : 0);
+}
+
+static inline void free_coa_set(tfm_cluster_t * tc)
+{
+	reiser4_compression_id i;
+	compression_plugin *cplug;
+
+	assert("edward-810", tc != NULL);
+
+	for (i = 0; i < LAST_COMPRESSION_ID; i++) {
+		if (!get_coa(tc, i))
+			continue;
+		assert("edward-1409", tc->act != TFM_INVAL);
+		cplug = compression_plugin_by_id(i);
+		assert("edward-812", cplug->free != NULL);
+		cplug->free(get_coa(tc, i), tc->act);
+		set_coa(tc, i, 0);
+	}
+	return;
+}
+
+static inline tfm_stream_t *tfm_stream(tfm_cluster_t * tc, tfm_stream_id id)
+{
+	return tc->tun[id];
+}
+
+static inline void
+set_tfm_stream(tfm_cluster_t * tc, tfm_stream_id id, tfm_stream_t * ts)
+{
+	tc->tun[id] = ts;
+}
+
+static inline __u8 *tfm_stream_data(tfm_cluster_t * tc, tfm_stream_id id)
+{
+	return ts_data(tfm_stream(tc, id));
+}
+
+static inline void
+set_tfm_stream_data(tfm_cluster_t * tc, tfm_stream_id id, __u8 * data)
+{
+	tfm_stream(tc, id)->data = data;
+}
+
+static inline size_t tfm_stream_size(tfm_cluster_t * tc, tfm_stream_id id)
+{
+	return ts_size(tfm_stream(tc, id));
+}
+
+static inline void
+set_tfm_stream_size(tfm_cluster_t * tc, tfm_stream_id id, size_t size)
+{
+	tfm_stream(tc, id)->size = size;
+}
+
+static inline int
+alloc_tfm_stream(tfm_cluster_t * tc, size_t size, tfm_stream_id id)
+{
+	assert("edward-939", tc != NULL);
+	assert("edward-940", !tfm_stream(tc, id));
+
+	tc->tun[id] = kmalloc(sizeof(tfm_stream_t), GFP_KERNEL);
+	if (!tc->tun[id])
+		return -ENOMEM;
+	memset(tfm_stream(tc, id), 0, sizeof(tfm_stream_t));
+	return alloc_ts_data(tfm_stream(tc, id), size);
+}
+
+static inline int
+realloc_tfm_stream(tfm_cluster_t * tc, size_t size, tfm_stream_id id)
+{
+	assert("edward-941", tfm_stream_size(tc, id) < size);
+	free_ts_data(tfm_stream(tc, id));
+	return alloc_ts_data(tfm_stream(tc, id), size);
+}
+
+static inline void free_tfm_stream(tfm_cluster_t * tc, tfm_stream_id id)
+{
+	free_ts_data(tfm_stream(tc, id));
+	free_ts(tfm_stream(tc, id));
+	set_tfm_stream(tc, id, 0);
+}
+
+static inline unsigned coa_overrun(compression_plugin * cplug, int ilen)
+{
+	return (cplug->overrun != NULL ? cplug->overrun(ilen) : 0);
+}
+
+static inline void free_tfm_unit(tfm_cluster_t * tc)
+{
+	tfm_stream_id id;
+	for (id = 0; id < LAST_STREAM; id++) {
+		if (!tfm_stream(tc, id))
+			continue;
+		free_tfm_stream(tc, id);
+	}
+}
+
+static inline void put_tfm_cluster(tfm_cluster_t * tc)
+{
+	assert("edward-942", tc != NULL);
+	free_coa_set(tc);
+	free_tfm_unit(tc);
+}
+
+static inline int tfm_cluster_is_uptodate(tfm_cluster_t * tc)
+{
+	assert("edward-943", tc != NULL);
+	assert("edward-944", tc->uptodate == 0 || tc->uptodate == 1);
+	return (tc->uptodate == 1);
+}
+
+static inline void tfm_cluster_set_uptodate(tfm_cluster_t * tc)
+{
+	assert("edward-945", tc != NULL);
+	assert("edward-946", tc->uptodate == 0 || tc->uptodate == 1);
+	tc->uptodate = 1;
+	return;
+}
+
+static inline void tfm_cluster_clr_uptodate(tfm_cluster_t * tc)
+{
+	assert("edward-947", tc != NULL);
+	assert("edward-948", tc->uptodate == 0 || tc->uptodate == 1);
+	tc->uptodate = 0;
+	return;
+}
+
+static inline int tfm_stream_is_set(tfm_cluster_t * tc, tfm_stream_id id)
+{
+	return (tfm_stream(tc, id) &&
+		tfm_stream_data(tc, id) && tfm_stream_size(tc, id));
+}
+
+static inline int tfm_cluster_is_set(tfm_cluster_t * tc)
+{
+	int i;
+	for (i = 0; i < LAST_STREAM; i++)
+		if (!tfm_stream_is_set(tc, i))
+			return 0;
+	return 1;
+}
+
+static inline void alternate_streams(tfm_cluster_t * tc)
+{
+	tfm_stream_t *tmp = tfm_stream(tc, INPUT_STREAM);
+
+	set_tfm_stream(tc, INPUT_STREAM, tfm_stream(tc, OUTPUT_STREAM));
+	set_tfm_stream(tc, OUTPUT_STREAM, tmp);
+}
+
+/* a kind of data that we can write to the window */
+typedef enum {
+	DATA_WINDOW,		/* the data we copy form user space */
+	HOLE_WINDOW		/* zeroes if we write hole */
+} window_stat;
+
+/* Sliding window of cluster size which should be set to the approprite position
+   (defined by cluster index) in a file before page cluster modification by
+   file_write. Then we translate file size, offset to write from, number of
+   bytes to write, etc.. to the following configuration needed to estimate
+   number of pages to read before write, etc...
+*/
+typedef struct reiser4_slide {
+	unsigned off;		/* offset we start to write/truncate from */
+	unsigned count;		/* number of bytes (zeroes) to write/truncate */
+	unsigned delta;		/* number of bytes to append to the hole */
+	window_stat stat;	/* a kind of data to write to the window */
+} reiser4_slide_t;
+
+/* The following is a set of possible disk cluster states */
+typedef enum {
+	INVAL_DISK_CLUSTER,	/* unknown state */
+	PREP_DISK_CLUSTER,	/* disk cluster got converted by flush
+				   at least 1 time */
+	UNPR_DISK_CLUSTER,	/* disk cluster just created and should be
+				   converted by flush */
+	FAKE_DISK_CLUSTER	/* disk cluster doesn't exist neither in memory
+				   nor on disk */
+} disk_cluster_stat;
+
+/*
+   While implementing all transforms (from page to disk cluster, and back)
+   reiser4 cluster manager fills the following structure incapsulating pointers
+   to all the clusters for the same index including the sliding window above
+*/
+typedef struct reiser4_cluster {
+	tfm_cluster_t tc;	/* transform cluster */
+	int nr_pages;		/* number of pages */
+	struct page **pages;	/* page cluster */
+	page_cluster_op op;	/* page cluster operation */
+	struct file *file;
+	hint_t *hint;		/* disk cluster item for traversal */
+	disk_cluster_stat dstat;	/* state of the current disk cluster */
+	cloff_t index;		/* offset in the units of cluster size */
+	reiser4_slide_t *win;	/* sliding window of cluster size */
+	int reserved;		/* this indicates that space for disk
+				   cluster modification is reserved */
+#if REISER4_DEBUG
+	reiser4_context *ctx;
+	int reserved_prepped;
+	int reserved_unprepped;
+#endif
+} reiser4_cluster_t;
+
+static inline __u8 * tfm_input_data (reiser4_cluster_t * clust)
+{
+	return tfm_stream_data(&clust->tc, INPUT_STREAM);
+}
+
+static inline __u8 * tfm_output_data (reiser4_cluster_t * clust)
+{
+	return tfm_stream_data(&clust->tc, OUTPUT_STREAM);
+}
+
+static inline int reset_cluster_pgset(reiser4_cluster_t * clust, int nrpages)
+{
+	assert("edward-1057", clust->pages != NULL);
+	memset(clust->pages, 0, sizeof(*clust->pages) * nrpages);
+	return 0;
+}
+
+static inline int alloc_cluster_pgset(reiser4_cluster_t * clust, int nrpages)
+{
+	assert("edward-949", clust != NULL);
+	assert("edward-1362", clust->pages == NULL);
+	assert("edward-950", nrpages != 0 && nrpages <= MAX_CLUSTER_NRPAGES);
+
+	clust->pages =
+		kmalloc(sizeof(*clust->pages) * nrpages, GFP_KERNEL);
+	if (!clust->pages)
+		return RETERR(-ENOMEM);
+	reset_cluster_pgset(clust, nrpages);
+	return 0;
+}
+
+static inline void free_cluster_pgset(reiser4_cluster_t * clust)
+{
+	assert("edward-951", clust->pages != NULL);
+	kfree(clust->pages);
+	clust->pages = NULL;
+}
+
+static inline void put_cluster_handle(reiser4_cluster_t * clust)
+{
+	assert("edward-435", clust != NULL);
+
+	put_tfm_cluster(&clust->tc);
+	if (clust->pages)
+		free_cluster_pgset(clust);
+	memset(clust, 0, sizeof *clust);
+}
+
+static inline void inc_keyload_count(crypto_stat_t * data)
+{
+ 	assert("edward-1410", data != NULL);
+ 	data->keyload_count++;
+}
+
+static inline void dec_keyload_count(crypto_stat_t * data)
+{
+ 	assert("edward-1411", data != NULL);
+ 	assert("edward-1412", data->keyload_count > 0);
+ 	data->keyload_count--;
+}
+
+/* cryptcompress specific part of reiser4_inode */
+typedef struct cryptcompress_info {
+	struct rw_semaphore lock;
+	crypto_stat_t *crypt;
+} cryptcompress_info_t;
+
+cryptcompress_info_t *cryptcompress_inode_data(const struct inode *inode);
+int equal_to_rdk(znode *, const reiser4_key *);
+int goto_right_neighbor(coord_t *, lock_handle *);
+int load_file_hint(struct file *, hint_t *);
+void save_file_hint(struct file *, const hint_t *);
+void hint_init_zero(hint_t *);
+int need_cipher (struct inode *);
+int host_allows_crypto_stat(struct inode * inode);
+int crc_inode_ok(struct inode *inode);
+int jnode_of_cluster(const jnode * node, struct page * page);
+extern int ctail_read_disk_cluster (reiser4_cluster_t *, struct inode *, int);
+extern int do_readpage_ctail(struct inode *, reiser4_cluster_t *,
+			     struct page * page);
+extern int ctail_insert_unprepped_cluster(reiser4_cluster_t * clust,
+					  struct inode * inode);
+int bind_cryptcompress(struct inode *child, struct inode *parent);
+void destroy_inode_cryptcompress(struct inode * inode);
+crypto_stat_t * inode_crypto_stat (struct inode * inode);
+void inherit_crypto_stat_common(struct inode * parent, struct inode * object,
+				int (*can_inherit)(struct inode * child,
+						   struct inode * parent));
+crypto_stat_t * create_crypto_stat(struct inode * parent, crypto_data_t * data);
+int crypto_stat_instantiated(crypto_stat_t * info);
+void attach_crypto_stat(struct inode * inode, crypto_stat_t * info);
+void detach_crypto_stat(struct inode * inode);
+void change_crypto_stat(struct inode * inode, crypto_stat_t * new);
+int can_inherit_crypto_crc(struct inode *child, struct inode *parent);
+crypto_stat_t * alloc_crypto_stat (struct inode * inode);
+int switch_compression(struct inode *inode);
+
+
+static inline reiser4_tfma_t *
+info_get_tfma (crypto_stat_t * info, reiser4_tfm id)
+{
+	return &info->tfma[id];
+}
+
+static inline struct crypto_tfm *
+info_get_tfm (crypto_stat_t * info, reiser4_tfm id)
+{
+	return info_get_tfma(info, id)->tfm;
+}
+
+static inline void
+info_set_tfm (crypto_stat_t * info, reiser4_tfm id, struct crypto_tfm * tfm)
+{
+	info_get_tfma(info, id)->tfm = tfm;
+}
+
+static inline struct crypto_tfm *
+info_cipher_tfm (crypto_stat_t * info)
+{
+	return info_get_tfm(info, CIPHER_TFM);
+}
+
+static inline struct crypto_tfm *
+info_digest_tfm (crypto_stat_t * info)
+{
+	return info_get_tfm(info, DIGEST_TFM);
+}
+
+static inline cipher_plugin *
+info_cipher_plugin (crypto_stat_t * info)
+{
+	return &info_get_tfma(info, CIPHER_TFM)->plug->cipher;
+}
+
+static inline digest_plugin *
+info_digest_plugin (crypto_stat_t * info)
+{
+	return &info_get_tfma(info, DIGEST_TFM)->plug->digest;
+}
+
+static inline void
+info_set_plugin(crypto_stat_t * info, reiser4_tfm id, reiser4_plugin * plugin)
+{
+	info_get_tfma(info, id)->plug = plugin;
+}
+
+static inline void
+info_set_cipher_plugin(crypto_stat_t * info, cipher_plugin * cplug)
+{
+	info_set_plugin(info, CIPHER_TFM, cipher_plugin_to_plugin(cplug));
+}
+
+static inline void
+info_set_digest_plugin(crypto_stat_t * info, digest_plugin * plug)
+{
+	info_set_plugin(info, DIGEST_TFM, digest_plugin_to_plugin(plug));
+}
+
+static inline compression_plugin *dual_compression_plugin(compression_plugin *
+							  cplug)
+{
+	return compression_plugin_by_id(cplug->dual);
+}
+
+#endif				/* __FS_REISER4_CRYPTCOMPRESS_H__ */
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/file/file.c newtree/fs/reiser4/plugin/file/file.c
--- oldtree/fs/reiser4/plugin/file/file.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/file/file.c	2006-02-21 15:58:35.506748712 +0000
@@ -0,0 +1,3077 @@
+/* Copyright 2001, 2002, 2003, 2004 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/*
+ * this file contains implementations of inode/file/address_space/file plugin
+ * operations specific for "unix file plugin" (plugin id is
+ * UNIX_FILE_PLUGIN_ID). "Unix file" is either built of tail items only
+ * (FORMATTING_ID) or of extent items only (EXTENT_POINTER_ID) or empty (have
+ * no items but stat data)
+ */
+
+#include "../../inode.h"
+#include "../../super.h"
+#include "../../tree_walk.h"
+#include "../../carry.h"
+#include "../../page_cache.h"
+#include "../../ioctl.h"
+#include "../object.h"
+#include "../../safe_link.h"
+#include "funcs.h"
+
+#include <linux/writeback.h>
+#include <linux/pagevec.h>
+#include <linux/syscalls.h>
+
+
+static int unpack(struct file *file, struct inode *inode, int forever);
+
+/* get unix file plugin specific portion of inode */
+unix_file_info_t *unix_file_inode_data(const struct inode *inode)
+{
+	return &reiser4_inode_data(inode)->file_plugin_data.unix_file_info;
+}
+
+static int file_is_built_of_tails(const struct inode *inode)
+{
+	return unix_file_inode_data(inode)->container == UF_CONTAINER_TAILS;
+}
+
+static int file_state_is_unknown(const struct inode *inode)
+{
+	return unix_file_inode_data(inode)->container == UF_CONTAINER_UNKNOWN;
+}
+
+static void set_file_state_extents(struct inode *inode)
+{
+	unix_file_inode_data(inode)->container = UF_CONTAINER_EXTENTS;
+}
+
+static void set_file_state_tails(struct inode *inode)
+{
+	unix_file_inode_data(inode)->container = UF_CONTAINER_TAILS;
+}
+
+static void set_file_state_empty(struct inode *inode)
+{
+	unix_file_inode_data(inode)->container = UF_CONTAINER_EMPTY;
+}
+
+static void set_file_state_unknown(struct inode *inode)
+{
+	unix_file_inode_data(inode)->container = UF_CONTAINER_UNKNOWN;
+}
+
+/**
+ * less_than_ldk - compare key and znode's left delimiting key
+ * @node: node whose left delimiting key to compare with @key
+ * @key: key to compare with @node's left delimiting key
+ *
+ * Returns true if @key is less than left delimiting key of @node.
+ */
+static int less_than_ldk(znode *node, const reiser4_key *key)
+{
+	int result;
+
+	read_lock_dk(znode_get_tree(node));
+	result = keylt(key, znode_get_ld_key(node));
+	read_unlock_dk(znode_get_tree(node));
+	return result;
+}
+
+/**
+ * equal_to_rdk - compare key and znode's right delimiting key
+ * @node: node whose right delimiting key to compare with @key
+ * @key: key to compare with @node's right delimiting key
+ *
+ * Returns true if @key is equal to right delimiting key of @node.
+ */
+int equal_to_rdk(znode *node, const reiser4_key *key)
+{
+	int result;
+
+	read_lock_dk(znode_get_tree(node));
+	result = keyeq(key, znode_get_rd_key(node));
+	read_unlock_dk(znode_get_tree(node));
+	return result;
+}
+
+#if REISER4_DEBUG
+
+/**
+ * less_than_rdk - compare key and znode's right delimiting key
+ * @node: node whose right delimiting key to compare with @key
+ * @key: key to compare with @node's right delimiting key
+ *
+ * Returns true if @key is less than right delimiting key of @node.
+ */
+static int less_than_rdk(znode *node, const reiser4_key *key)
+{
+	int result;
+
+	read_lock_dk(znode_get_tree(node));
+	result = keylt(key, znode_get_rd_key(node));
+	read_unlock_dk(znode_get_tree(node));
+	return result;
+}
+
+/**
+ * equal_to_ldk - compare key and znode's left delimiting key
+ * @node: node whose left delimiting key to compare with @key
+ * @key: key to compare with @node's left delimiting key
+ *
+ * Returns true if @key is equal to left delimiting key of @node.
+ */
+int equal_to_ldk(znode *node, const reiser4_key *key)
+{
+	int result;
+
+	read_lock_dk(znode_get_tree(node));
+	result = keyeq(key, znode_get_ld_key(node));
+	read_unlock_dk(znode_get_tree(node));
+	return result;
+}
+
+/**
+ * get_next_item_key - get key of item next to the one @coord is set to
+ * @coord: left neighbor of item which key is to be calculated
+ * @next_key: where to store key of next item
+ *
+ * If @coord is set to last item in the node - return right delimiting key of
+ * coord->node. Otherwise - return key of next item in the node.
+ */
+static reiser4_key *get_next_item_key(const coord_t *coord,
+				      reiser4_key *next_key)
+{
+	if (coord->item_pos == node_num_items(coord->node) - 1) {
+		/* get key of next item if it is in right neighbor */
+		read_lock_dk(znode_get_tree(coord->node));
+		*next_key = *znode_get_rd_key(coord->node);
+		read_unlock_dk(znode_get_tree(coord->node));
+	} else {
+		/* get key of next item if it is in the same node */
+		coord_t next;
+
+		coord_dup_nocheck(&next, coord);
+		next.unit_pos = 0;
+		check_me("vs-730", coord_next_item(&next) == 0);
+		item_key_by_coord(&next, next_key);
+	}
+	return next_key;
+}
+
+/**
+ * item_of_that_file - check whether item if of certain file
+ * @coord: item to check
+ * @key: key of position in a file
+ *
+ * @key is key of position in a file. Returns true if @coord is set to an item
+ * of that file.
+ */
+static int item_of_that_file(const coord_t *coord, const reiser4_key *key)
+{
+	reiser4_key max_possible;
+	item_plugin *iplug;
+
+	iplug = item_plugin_by_coord(coord);
+	assert("vs-1011", iplug->b.max_key_inside);
+	return keylt(key, iplug->b.max_key_inside(coord, &max_possible));
+}
+
+/**
+ * check_coord - check whether coord corresponds to key
+ * @coord: coord to check
+ * @key: key @coord has to correspond to
+ *
+ * Returns true if @coord is set as if it was set as result of lookup with @key
+ * in coord->node.
+ */
+static int check_coord(const coord_t *coord, const reiser4_key *key)
+{
+	coord_t twin;
+
+	node_plugin_by_node(coord->node)->lookup(coord->node, key,
+						 FIND_MAX_NOT_MORE_THAN, &twin);
+	return coords_equal(coord, &twin);
+}
+
+static int file_is_built_of_extents(const struct inode *inode)
+{
+	return unix_file_inode_data(inode)->container == UF_CONTAINER_EXTENTS;
+}
+
+static int file_is_empty(const struct inode *inode)
+{
+	return unix_file_inode_data(inode)->container == UF_CONTAINER_EMPTY;
+}
+
+#endif /* REISER4_DEBUG */
+
+
+/**
+ * init_uf_coord - initialize extended coord
+ * @uf_coord:
+ * @lh:
+ *
+ *
+ */
+static void init_uf_coord(uf_coord_t *uf_coord, lock_handle *lh)
+{
+	coord_init_zero(&uf_coord->coord);
+	coord_clear_iplug(&uf_coord->coord);
+	uf_coord->lh = lh;
+	init_lh(lh);
+	memset(&uf_coord->extension, 0, sizeof(uf_coord->extension));
+	uf_coord->valid = 0;
+}
+
+static inline void validate_extended_coord(uf_coord_t * uf_coord, loff_t offset)
+{
+	assert("vs-1333", uf_coord->valid == 0);
+	assert("vs-1348",
+	       item_plugin_by_coord(&uf_coord->coord)->s.file.
+	       init_coord_extension);
+
+	item_body_by_coord(&uf_coord->coord);
+	item_plugin_by_coord(&uf_coord->coord)->s.file.
+	    init_coord_extension(uf_coord, offset);
+}
+
+write_mode_t how_to_write(uf_coord_t * uf_coord, const reiser4_key * key)
+{
+	write_mode_t result;
+	coord_t *coord;
+	ON_DEBUG(reiser4_key check);
+
+	coord = &uf_coord->coord;
+
+	assert("vs-1252", znode_is_wlocked(coord->node));
+	assert("vs-1253", znode_is_loaded(coord->node));
+
+	if (uf_coord->valid == 1) {
+		assert("vs-1332", check_coord(coord, key));
+		return (coord->between ==
+			AFTER_UNIT) ? APPEND_ITEM : OVERWRITE_ITEM;
+	}
+
+	if (less_than_ldk(coord->node, key)) {
+		assert("vs-1014", get_key_offset(key) == 0);
+
+		coord_init_before_first_item(coord, coord->node);
+		uf_coord->valid = 1;
+		result = FIRST_ITEM;
+		goto ok;
+	}
+
+	assert("vs-1335", less_than_rdk(coord->node, key));
+
+	if (node_is_empty(coord->node)) {
+		assert("vs-879", znode_get_level(coord->node) == LEAF_LEVEL);
+		assert("vs-880", get_key_offset(key) == 0);
+		/*
+		 * Situation that check below tried to handle is follows: some
+		 * other thread writes to (other) file and has to insert empty
+		 * leaf between two adjacent extents. Generally, we are not
+		 * supposed to muck with this node. But it is possible that
+		 * said other thread fails due to some error (out of disk
+		 * space, for example) and leaves empty leaf
+		 * lingering. Nothing prevents us from reusing it.
+		 */
+		assert("vs-1000", less_than_rdk(coord->node, key));
+		assert("vs-1002", coord->between == EMPTY_NODE);
+		result = FIRST_ITEM;
+		uf_coord->valid = 1;
+		goto ok;
+	}
+
+	assert("vs-1336", coord->item_pos < node_num_items(coord->node));
+	assert("vs-1007",
+	       ergo(coord->between == AFTER_UNIT
+		    || coord->between == AT_UNIT,
+		    keyle(item_key_by_coord(coord, &check), key)));
+	assert("vs-1008",
+	       ergo(coord->between == AFTER_UNIT
+		    || coord->between == AT_UNIT, keylt(key,
+							get_next_item_key(coord,
+									  &check))));
+
+	switch (coord->between) {
+	case AFTER_ITEM:
+		uf_coord->valid = 1;
+		result = FIRST_ITEM;
+		break;
+	case AFTER_UNIT:
+		assert("vs-1323", (item_is_tail(coord) || item_is_extent(coord))
+		       && item_of_that_file(coord, key));
+		assert("vs-1208",
+		       keyeq(item_plugin_by_coord(coord)->s.file.
+			     append_key(coord, &check), key));
+		result = APPEND_ITEM;
+		validate_extended_coord(uf_coord, get_key_offset(key));
+		break;
+	case AT_UNIT:
+		/* FIXME: it would be nice to check that coord matches to key */
+		assert("vs-1324", (item_is_tail(coord) || item_is_extent(coord))
+		       && item_of_that_file(coord, key));
+		validate_extended_coord(uf_coord, get_key_offset(key));
+		result = OVERWRITE_ITEM;
+		break;
+	default:
+		assert("vs-1337", 0);
+		result = OVERWRITE_ITEM;
+		break;
+	}
+
+      ok:
+	assert("vs-1349", uf_coord->valid == 1);
+	assert("vs-1332", check_coord(coord, key));
+	return result;
+}
+
+/* obtain lock on right neighbor and drop lock on current node */
+int goto_right_neighbor(coord_t * coord, lock_handle * lh)
+{
+	int result;
+	lock_handle lh_right;
+
+	assert("vs-1100", znode_is_locked(coord->node));
+
+	init_lh(&lh_right);
+	result = reiser4_get_right_neighbor(&lh_right, coord->node,
+					    znode_is_wlocked(coord->
+							     node) ?
+					    ZNODE_WRITE_LOCK : ZNODE_READ_LOCK,
+					    GN_CAN_USE_UPPER_LEVELS);
+	if (result) {
+		done_lh(&lh_right);
+		return result;
+	}
+
+	done_lh(lh);
+
+	coord_init_first_unit_nocheck(coord, lh_right.node);
+	move_lh(lh, &lh_right);
+
+	return 0;
+
+}
+
+/* this is to be used after find_file_item and in find_file_item_nohint to
+ * determine real state of file */
+static void
+set_file_state(struct inode *inode, int cbk_result, tree_level level)
+{
+	assert("vs-1649", inode != NULL);
+
+	if (cbk_errored(cbk_result))
+		/* error happened in find_file_item */
+		return;
+
+	assert("vs-1164", level == LEAF_LEVEL || level == TWIG_LEVEL);
+
+	if (inode_get_flag(inode, REISER4_PART_CONV)) {
+		set_file_state_unknown(inode);
+		return;
+	}
+
+	if (file_state_is_unknown(inode)) {
+		if (cbk_result == CBK_COORD_NOTFOUND)
+			set_file_state_empty(inode);
+		else if (level == LEAF_LEVEL)
+			set_file_state_tails(inode);
+		else
+			set_file_state_extents(inode);
+	} else {
+		/* file state is known, check that it is set correctly */
+		assert("vs-1161", ergo(cbk_result == CBK_COORD_NOTFOUND,
+				       file_is_empty(inode)));
+		assert("vs-1162",
+		       ergo(level == LEAF_LEVEL
+			    && cbk_result == CBK_COORD_FOUND,
+			    file_is_built_of_tails(inode)));
+		assert("vs-1165",
+		       ergo(level == TWIG_LEVEL
+			    && cbk_result == CBK_COORD_FOUND,
+			    file_is_built_of_extents(inode)));
+	}
+}
+
+/**
+ * find_file_item - look for file item in the tree
+ * @hint: provides coordinate, lock handle, seal
+ * @key: key for search
+ * @mode: mode of lock to put on returned node
+ * @ra_info:
+ * @inode:
+ *
+ * This finds position in the tree corresponding to @key. It first tries to use
+ * @hint's seal if it is set.
+ */
+static int find_file_item(hint_t *hint, const reiser4_key *key,
+			  znode_lock_mode lock_mode,
+			  struct inode *inode)
+{
+	int result;
+	coord_t *coord;
+	lock_handle *lh;
+
+	assert("nikita-3030", schedulable());
+	assert("vs-1707", hint != NULL);
+	assert("vs-47", inode != NULL);
+
+	coord = &hint->ext_coord.coord;
+	lh = hint->ext_coord.lh;
+	init_lh(lh);
+
+	result = hint_validate(hint, key, 1 /* check key */ , lock_mode);
+	if (!result) {
+		if (coord->between == AFTER_UNIT
+		    && equal_to_rdk(coord->node, key)) {
+			result = goto_right_neighbor(coord, lh);
+			if (result == -E_NO_NEIGHBOR)
+				return RETERR(-EIO);
+			if (result)
+				return result;
+			assert("vs-1152", equal_to_ldk(coord->node, key));
+			/* we moved to different node. Invalidate coord
+			   extension, zload is necessary to init it again */
+			hint->ext_coord.valid = 0;
+		}
+
+		set_file_state(inode, CBK_COORD_FOUND,
+			       znode_get_level(coord->node));
+		return CBK_COORD_FOUND;
+	}
+
+	coord_init_zero(coord);
+	result = object_lookup(inode, key, coord, lh, lock_mode,
+			       FIND_MAX_NOT_MORE_THAN,
+			       TWIG_LEVEL, LEAF_LEVEL,
+			       (lock_mode == ZNODE_READ_LOCK) ? CBK_UNIQUE :
+			       (CBK_UNIQUE | CBK_FOR_INSERT), NULL);
+
+	set_file_state(inode, result, znode_get_level(coord->node));
+
+	/* FIXME: we might already have coord extension initialized */
+	hint->ext_coord.valid = 0;
+	return result;
+}
+
+int
+find_file_item_nohint(coord_t * coord, lock_handle * lh,
+		      const reiser4_key * key, znode_lock_mode lock_mode,
+		      struct inode *inode)
+{
+	int result;
+
+	result = object_lookup(inode, key, coord, lh, lock_mode,
+			       FIND_MAX_NOT_MORE_THAN,
+			       TWIG_LEVEL, LEAF_LEVEL,
+			       (lock_mode ==
+				ZNODE_READ_LOCK) ? CBK_UNIQUE : (CBK_UNIQUE |
+								 CBK_FOR_INSERT),
+			       NULL /* ra_info */ );
+	set_file_state(inode, result, znode_get_level(coord->node));
+	return result;
+}
+
+/* plugin->u.file.write_flowom = NULL
+   plugin->u.file.read_flow = NULL */
+
+void hint_init_zero(hint_t * hint)
+{
+	memset(hint, 0, sizeof(*hint));
+	init_lh(&hint->lh);
+	hint->ext_coord.lh = &hint->lh;
+}
+
+/* find position of last byte of last item of the file plus 1. This is used by truncate and mmap to find real file
+   size */
+static int find_file_size(struct inode *inode, loff_t * file_size)
+{
+	int result;
+	reiser4_key key;
+	coord_t coord;
+	lock_handle lh;
+	item_plugin *iplug;
+
+	assert("vs-1247",
+	       inode_file_plugin(inode)->key_by_inode ==
+	       key_by_inode_and_offset_common);
+	key_by_inode_and_offset_common(inode, get_key_offset(max_key()), &key);
+
+	init_lh(&lh);
+	result =
+	    find_file_item_nohint(&coord, &lh, &key, ZNODE_READ_LOCK, inode);
+	if (cbk_errored(result)) {
+		/* error happened */
+		done_lh(&lh);
+		return result;
+	}
+
+	if (result == CBK_COORD_NOTFOUND) {
+		/* empty file */
+		done_lh(&lh);
+		*file_size = 0;
+		return 0;
+	}
+
+	/* there are items of this file (at least one) */
+	/*coord_clear_iplug(&coord); */
+	result = zload(coord.node);
+	if (unlikely(result)) {
+		done_lh(&lh);
+		return result;
+	}
+	iplug = item_plugin_by_coord(&coord);
+
+	assert("vs-853", iplug->s.file.append_key);
+	iplug->s.file.append_key(&coord, &key);
+
+	*file_size = get_key_offset(&key);
+
+	zrelse(coord.node);
+	done_lh(&lh);
+
+	return 0;
+}
+
+static int find_file_state(unix_file_info_t * uf_info)
+{
+	int result;
+
+	assert("vs-1628", ea_obtained(uf_info));
+
+	result = 0;
+	if (uf_info->container == UF_CONTAINER_UNKNOWN) {
+		loff_t file_size;
+
+		result =
+		    find_file_size(unix_file_info_to_inode(uf_info),
+				   &file_size);
+	}
+	assert("vs-1074",
+	       ergo(result == 0, uf_info->container != UF_CONTAINER_UNKNOWN));
+	return result;
+}
+
+/* estimate and reserve space needed to truncate page which gets partially truncated: one block for page itself, stat
+   data update (estimate_one_insert_into_item) and one item insertion (estimate_one_insert_into_item) which may happen
+   if page corresponds to hole extent and unallocated one will have to be created */
+static int reserve_partial_page(reiser4_tree * tree)
+{
+	grab_space_enable();
+	return reiser4_grab_reserved(reiser4_get_current_sb(),
+				     1 +
+				     2 * estimate_one_insert_into_item(tree),
+				     BA_CAN_COMMIT);
+}
+
+/* estimate and reserve space needed to cut one item and update one stat data */
+static int reserve_cut_iteration(reiser4_tree * tree)
+{
+	__u64 estimate = estimate_one_item_removal(tree)
+	    + estimate_one_insert_into_item(tree);
+
+	assert("nikita-3172", lock_stack_isclean(get_current_lock_stack()));
+
+	grab_space_enable();
+	/* We need to double our estimate now that we can delete more than one
+	   node. */
+	return reiser4_grab_reserved(reiser4_get_current_sb(), estimate * 2,
+				     BA_CAN_COMMIT);
+}
+
+int update_file_size(struct inode *inode, reiser4_key * key, int update_sd)
+{
+	int result = 0;
+
+	INODE_SET_FIELD(inode, i_size, get_key_offset(key));
+	if (update_sd) {
+		inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+		result = reiser4_update_sd(inode);
+	}
+	return result;
+}
+
+/* cut file items one by one starting from the last one until new file size (inode->i_size) is reached. Reserve space
+   and update file stat data on every single cut from the tree */
+int
+cut_file_items(struct inode *inode, loff_t new_size, int update_sd,
+	       loff_t cur_size, int (*update_actor) (struct inode *,
+						     reiser4_key *, int))
+{
+	reiser4_key from_key, to_key;
+	reiser4_key smallest_removed;
+	file_plugin *fplug = inode_file_plugin(inode);
+	int result;
+	int progress = 0;
+
+	assert("vs-1248",
+	       fplug == file_plugin_by_id(UNIX_FILE_PLUGIN_ID) ||
+	       fplug == file_plugin_by_id(CRC_FILE_PLUGIN_ID));
+
+	fplug->key_by_inode(inode, new_size, &from_key);
+	to_key = from_key;
+	set_key_offset(&to_key, cur_size - 1 /*get_key_offset(max_key()) */ );
+	/* this loop normally runs just once */
+	while (1) {
+		result = reserve_cut_iteration(tree_by_inode(inode));
+		if (result)
+			break;
+
+		result = cut_tree_object(current_tree, &from_key, &to_key,
+					 &smallest_removed, inode, 1,
+					 &progress);
+		if (result == -E_REPEAT) {
+			/* -E_REPEAT is a signal to interrupt a long file truncation process */
+			if (progress) {
+				result =
+				    update_actor(inode, &smallest_removed,
+						 update_sd);
+				if (result)
+					break;
+			}
+			all_grabbed2free();
+			reiser4_release_reserved(inode->i_sb);
+
+			/* cut_tree_object() was interrupted probably because
+			 * current atom requires commit, we have to release
+			 * transaction handle to allow atom commit. */
+			txn_restart_current();
+			continue;
+		}
+		if (result
+		    && !(result == CBK_COORD_NOTFOUND && new_size == 0
+			 && inode->i_size == 0))
+			break;
+
+		set_key_offset(&smallest_removed, new_size);
+		/* Final sd update after the file gets its correct size */
+		result = update_actor(inode, &smallest_removed, update_sd);
+		break;
+	}
+	all_grabbed2free();
+	reiser4_release_reserved(inode->i_sb);
+
+	return result;
+}
+
+int find_or_create_extent(struct page *page);
+
+static int filler(void *vp, struct page *page)
+{
+	return readpage_unix_file_nolock(vp, page);
+}
+
+/* part of truncate_file_body: it is called when truncate is used to make file
+   shorter */
+static int shorten_file(struct inode *inode, loff_t new_size)
+{
+	int result;
+	struct page *page;
+	int padd_from;
+	unsigned long index;
+	char *kaddr;
+
+	/* all items of ordinary reiser4 file are grouped together. That is why we can use cut_tree. Plan B files (for
+	   instance) can not be truncated that simply */
+	result =
+	    cut_file_items(inode, new_size, 1 /*update_sd */ ,
+			   get_key_offset(max_key()), update_file_size);
+	if (result)
+		return result;
+
+	assert("vs-1105", new_size == inode->i_size);
+	if (new_size == 0) {
+		set_file_state_empty(inode);
+		return 0;
+	}
+
+	result = find_file_state(unix_file_inode_data(inode));
+	if (result)
+		return result;
+	if (file_is_built_of_tails(inode))
+		/* No need to worry about zeroing last page after new file end */
+		return 0;
+
+	padd_from = inode->i_size & (PAGE_CACHE_SIZE - 1);
+	if (!padd_from)
+		/* file is truncated to page boundary */
+		return 0;
+
+	result = reserve_partial_page(tree_by_inode(inode));
+	if (result) {
+		reiser4_release_reserved(inode->i_sb);
+		return result;
+	}
+
+	/* last page is partially truncated - zero its content */
+	index = (inode->i_size >> PAGE_CACHE_SHIFT);
+	page = read_cache_page(inode->i_mapping, index, filler, NULL);
+	if (IS_ERR(page)) {
+		all_grabbed2free();
+		reiser4_release_reserved(inode->i_sb);
+		if (likely(PTR_ERR(page) == -EINVAL)) {
+			/* looks like file is built of tail items */
+			return 0;
+		}
+		return PTR_ERR(page);
+	}
+	wait_on_page_locked(page);
+	if (!PageUptodate(page)) {
+		all_grabbed2free();
+		page_cache_release(page);
+		reiser4_release_reserved(inode->i_sb);
+		return RETERR(-EIO);
+	}
+
+	/* if page correspons to hole extent unit - unallocated one will be
+	   created here. This is not necessary */
+	result = find_or_create_extent(page);
+
+	/* FIXME: cut_file_items has already updated inode. Probably it would
+	   be better to update it here when file is really truncated */
+	all_grabbed2free();
+	if (result) {
+		page_cache_release(page);
+		reiser4_release_reserved(inode->i_sb);
+		return result;
+	}
+
+	lock_page(page);
+	assert("vs-1066", PageLocked(page));
+	kaddr = kmap_atomic(page, KM_USER0);
+	memset(kaddr + padd_from, 0, PAGE_CACHE_SIZE - padd_from);
+	flush_dcache_page(page);
+	kunmap_atomic(kaddr, KM_USER0);
+	unlock_page(page);
+	page_cache_release(page);
+	reiser4_release_reserved(inode->i_sb);
+	return 0;
+}
+
+static loff_t
+write_flow(hint_t *, struct file *, struct inode *, const char __user *buf,
+	   loff_t count, loff_t pos, int exclusive);
+
+/* it is called when truncate is used to make file longer and when write
+   position is set past real end of file. It appends file which has size
+   @cur_size with hole of certain size (@hole_size). It returns 0 on success,
+   error code otherwise */
+static int
+append_hole(hint_t * hint, struct inode *inode, loff_t new_size, int exclusive)
+{
+	int result;
+	loff_t written;
+	loff_t hole_size;
+
+	assert("vs-1107", inode->i_size < new_size);
+
+	result = 0;
+	hole_size = new_size - inode->i_size;
+	written = write_flow(hint, NULL, inode, NULL /*buf */ , hole_size,
+			     inode->i_size, exclusive);
+	if (written != hole_size) {
+		/* return error because file is not expanded as required */
+		if (written > 0)
+			result = RETERR(-ENOSPC);
+		else
+			result = written;
+	} else {
+		assert("vs-1081", inode->i_size == new_size);
+	}
+	return result;
+}
+
+/**
+ * truncate_file_body - change length of file
+ * @inode: inode of file
+ * @new_size: new file length
+ *
+ * Adjusts items file @inode is built of to match @new_size. It may either cut
+ * items or add them to represent a hole at the end of file. The caller has to
+ * obtain exclusive access to the file.
+ */
+static int truncate_file_body(struct inode *inode, loff_t new_size)
+{
+	int result;
+
+	if (inode->i_size < new_size) {
+		hint_t *hint;
+
+		hint = kmalloc(sizeof(*hint), GFP_KERNEL);
+		if (hint == NULL)
+			return RETERR(-ENOMEM);
+		hint_init_zero(hint);
+		result = append_hole(hint, inode, new_size,
+				     1 /* exclusive access is obtained */ );
+		kfree(hint);
+	} else
+		result = shorten_file(inode, new_size);
+	return result;
+}
+
+/* plugin->u.write_sd_by_inode = write_sd_by_inode_common */
+
+/* get access hint (seal, coord, key, level) stored in reiser4 private part of
+   struct file if it was stored in a previous access to the file */
+int load_file_hint(struct file *file, hint_t * hint)
+{
+	reiser4_file_fsdata *fsdata;
+
+	if (file) {
+		fsdata = reiser4_get_file_fsdata(file);
+		if (IS_ERR(fsdata))
+			return PTR_ERR(fsdata);
+
+		spin_lock_inode(file->f_dentry->d_inode);
+		if (seal_is_set(&fsdata->reg.hint.seal)) {
+			*hint = fsdata->reg.hint;
+			init_lh(&hint->lh);
+			hint->ext_coord.lh = &hint->lh;
+			spin_unlock_inode(file->f_dentry->d_inode);
+			/* force re-validation of the coord on the first
+			 * iteration of the read/write loop. */
+			hint->ext_coord.valid = 0;
+			assert("nikita-19892", coords_equal(&hint->seal.coord1,
+							    &hint->ext_coord.
+							    coord));
+			return 0;
+		}
+		memset(&fsdata->reg.hint, 0, sizeof(hint_t));
+		spin_unlock_inode(file->f_dentry->d_inode);
+	}
+	hint_init_zero(hint);
+	return 0;
+}
+
+/* this copies hint for future tree accesses back to reiser4 private part of
+   struct file */
+void save_file_hint(struct file *file, const hint_t * hint)
+{
+	reiser4_file_fsdata *fsdata;
+
+	assert("edward-1337", hint != NULL);
+
+	if (!file || !seal_is_set(&hint->seal))
+		return;
+	fsdata = reiser4_get_file_fsdata(file);
+	assert("vs-965", !IS_ERR(fsdata));
+	assert("nikita-19891",
+	       coords_equal(&hint->seal.coord1, &hint->ext_coord.coord));
+	assert("vs-30", hint->lh.owner == NULL);
+	spin_lock_inode(file->f_dentry->d_inode);
+	fsdata->reg.hint = *hint;
+	spin_unlock_inode(file->f_dentry->d_inode);
+	return;
+}
+
+void unset_hint(hint_t * hint)
+{
+	assert("vs-1315", hint);
+	hint->ext_coord.valid = 0;
+	seal_done(&hint->seal);
+	done_lh(&hint->lh);
+}
+
+/* coord must be set properly. So, that set_hint has nothing to do */
+void set_hint(hint_t * hint, const reiser4_key * key, znode_lock_mode mode)
+{
+	ON_DEBUG(coord_t * coord = &hint->ext_coord.coord);
+	assert("vs-1207", WITH_DATA(coord->node, check_coord(coord, key)));
+
+	seal_init(&hint->seal, &hint->ext_coord.coord, key);
+	hint->offset = get_key_offset(key);
+	hint->mode = mode;
+	done_lh(&hint->lh);
+}
+
+int hint_is_set(const hint_t * hint)
+{
+	return seal_is_set(&hint->seal);
+}
+
+#if REISER4_DEBUG
+static int all_but_offset_key_eq(const reiser4_key * k1, const reiser4_key * k2)
+{
+	return (get_key_locality(k1) == get_key_locality(k2) &&
+		get_key_type(k1) == get_key_type(k2) &&
+		get_key_band(k1) == get_key_band(k2) &&
+		get_key_ordering(k1) == get_key_ordering(k2) &&
+		get_key_objectid(k1) == get_key_objectid(k2));
+}
+#endif
+
+int
+hint_validate(hint_t * hint, const reiser4_key * key, int check_key,
+	      znode_lock_mode lock_mode)
+{
+	if (!hint || !hint_is_set(hint) || hint->mode != lock_mode)
+		/* hint either not set or set by different operation */
+		return RETERR(-E_REPEAT);
+
+	assert("vs-1277", all_but_offset_key_eq(key, &hint->seal.key));
+
+	if (check_key && get_key_offset(key) != hint->offset)
+		/* hint is set for different key */
+		return RETERR(-E_REPEAT);
+
+	assert("vs-31", hint->ext_coord.lh == &hint->lh);
+	return seal_validate(&hint->seal, &hint->ext_coord.coord, key,
+			     hint->ext_coord.lh, lock_mode, ZNODE_LOCK_LOPRI);
+}
+
+/* look for place at twig level for extent corresponding to page, call extent's writepage method to create
+   unallocated extent if it does not exist yet, initialize jnode, capture page */
+int find_or_create_extent(struct page *page)
+{
+	int result;
+	uf_coord_t uf_coord;
+	coord_t *coord;
+	lock_handle lh;
+	reiser4_key key;
+	item_plugin *iplug;
+	znode *loaded;
+	struct inode *inode;
+
+	assert("vs-1065", page->mapping && page->mapping->host);
+	inode = page->mapping->host;
+
+	/* get key of first byte of the page */
+	key_by_inode_and_offset_common(inode,
+				       (loff_t) page->index << PAGE_CACHE_SHIFT,
+				       &key);
+
+	init_uf_coord(&uf_coord, &lh);
+	coord = &uf_coord.coord;
+
+	result =
+	    find_file_item_nohint(coord, &lh, &key, ZNODE_WRITE_LOCK, inode);
+	if (IS_CBKERR(result)) {
+		done_lh(&lh);
+		return result;
+	}
+
+	/*coord_clear_iplug(coord); */
+	result = zload(coord->node);
+	if (result) {
+		done_lh(&lh);
+		return result;
+	}
+	loaded = coord->node;
+
+	/* get plugin of extent item */
+	iplug = item_plugin_by_id(EXTENT_POINTER_ID);
+	result =
+	    iplug->s.file.capture(&key, &uf_coord, page,
+				  how_to_write(&uf_coord, &key));
+	assert("vs-429378", result != -E_REPEAT);
+	zrelse(loaded);
+	done_lh(&lh);
+	return result;
+}
+
+/**
+ * has_anonymous_pages - check whether inode has pages dirtied via mmap
+ * @inode: inode to check
+ *
+ * Returns true if inode's mapping has dirty pages which do not belong to any
+ * atom. Those are either tagged PAGECACHE_TAG_REISER4_MOVED in mapping's page
+ * tree or were eflushed and can be found via jnodes tagged
+ * EFLUSH_TAG_ANONYMOUS in radix tree of jnodes.
+ */
+static int has_anonymous_pages(struct inode *inode)
+{
+	int result;
+
+	read_lock_irq(&inode->i_mapping->tree_lock);
+	result = radix_tree_tagged(&inode->i_mapping->page_tree, PAGECACHE_TAG_REISER4_MOVED)
+#if REISER4_USE_EFLUSH
+		| radix_tree_tagged(jnode_tree_by_inode(inode), EFLUSH_TAG_ANONYMOUS)
+#endif
+		;
+	read_unlock_irq(&inode->i_mapping->tree_lock);
+	return result;
+}
+
+/**
+ * capture_page_and_create_extent -
+ * @page: page to be captured
+ *
+ * Grabs space for extent creation and stat data update and calls function to
+ * do actual work.
+ */
+static int capture_page_and_create_extent(struct page *page)
+{
+	int result;
+	struct inode *inode;
+
+	assert("vs-1084", page->mapping && page->mapping->host);
+	inode = page->mapping->host;
+	assert("vs-1139", file_is_built_of_extents(inode));
+	/* page belongs to file */
+	assert("vs-1393",
+	       inode->i_size > ((loff_t) page->index << PAGE_CACHE_SHIFT));
+
+	/* page capture may require extent creation (if it does not exist yet)
+	   and stat data's update (number of blocks changes on extent
+	   creation) */
+	grab_space_enable();
+	result =
+	    reiser4_grab_space(2 *
+			       estimate_one_insert_into_item(tree_by_inode
+							     (inode)),
+			       BA_CAN_COMMIT);
+	if (likely(!result))
+		result = find_or_create_extent(page);
+
+	all_grabbed2free();
+	if (result != 0)
+		SetPageError(page);
+	return result;
+}
+
+/* this is implementation of method commit_write of struct
+   address_space_operations for unix file plugin */
+int
+commit_write_unix_file(struct file *file, struct page *page,
+		       unsigned from, unsigned to)
+{
+	reiser4_context *ctx;
+	struct inode *inode;
+	int result;
+
+	assert("umka-3101", file != NULL);
+	assert("umka-3102", page != NULL);
+	assert("umka-3093", PageLocked(page));
+
+	SetPageUptodate(page);
+
+	inode = page->mapping->host;
+	ctx = init_context(page->mapping->host->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+	page_cache_get(page);
+	unlock_page(page);
+	result = capture_page_and_create_extent(page);
+	lock_page(page);
+	page_cache_release(page);
+
+	/* don't commit transaction under inode semaphore */
+	context_set_commit_async(ctx);
+	reiser4_exit_context(ctx);
+	return result;
+}
+
+/*
+ * Support for "anonymous" pages and jnodes.
+ *
+ * When file is write-accessed through mmap pages can be dirtied from the user
+ * level. In this case kernel is not notified until one of following happens:
+ *
+ *     (1) msync()
+ *
+ *     (2) truncate() (either explicit or through unlink)
+ *
+ *     (3) VM scanner starts reclaiming mapped pages, dirtying them before
+ *     starting write-back.
+ *
+ * As a result of (3) ->writepage may be called on a dirty page without
+ * jnode. Such page is called "anonymous" in reiser4. Certain work-loads
+ * (iozone) generate huge number of anonymous pages. Emergency flush handles
+ * this situation by creating jnode for anonymous page, starting IO on the
+ * page, and marking jnode with JNODE_KEEPME bit so that it's not thrown out of
+ * memory. Such jnode is also called anonymous.
+ *
+ * reiser4_sync_sb() method tries to insert anonymous pages and jnodes into
+ * tree. This is done by capture_anonymous_*() functions below.
+ */
+
+/**
+ * capture_anonymous_page - involve page into transaction
+ * @pg: page to deal with
+ *
+ * Takes care that @page has corresponding metadata in the tree, creates jnode
+ * for @page and captures it. On success 1 is returned.
+ */
+static int capture_anonymous_page(struct page *page)
+{
+	struct address_space *mapping;
+	jnode *node;
+	int result;
+
+	if (PageWriteback(page))
+		/* FIXME: do nothing? */
+		return 0;
+
+	mapping = page->mapping;
+
+	lock_page(page);
+	/* page is guaranteed to be in the mapping, because we are operating
+	   under rw-semaphore. */
+	assert("nikita-3336", page->mapping == mapping);
+	node = jnode_of_page(page);
+	unlock_page(page);
+	if (!IS_ERR(node)) {
+		result = jload(node);
+		assert("nikita-3334", result == 0);
+		assert("nikita-3335", jnode_page(node) == page);
+		result = capture_page_and_create_extent(page);
+		if (result == 0) {
+			/*
+			 * node has beed captured into atom by
+			 * capture_page_and_create_extent(). Atom cannot commit
+			 * (because we have open transaction handle), and node
+			 * cannot be truncated, because we have non-exclusive
+			 * access to the file.
+			 */
+			assert("nikita-3327", node->atom != NULL);
+			result = 1;
+		} else
+			warning("nikita-3329",
+				"Cannot capture anon page: %i", result);
+		jrelse(node);
+		jput(node);
+	} else
+		result = PTR_ERR(node);
+
+	return result;
+}
+
+/**
+ * capture_anonymous_pages - find and capture pages dirtied via mmap
+ * @mapping: address space where to look for pages
+ * @index: start index
+ * @to_capture: maximum number of pages to capture
+ *
+ * Looks for pages tagged REISER4_MOVED starting from the *@index-th page,
+ * captures (involves into atom) them, returns number of captured pages,
+ * updates @index to next page after the last captured one.
+ */
+static int
+capture_anonymous_pages(struct address_space *mapping, pgoff_t *index,
+			unsigned int to_capture)
+{
+	int result;
+	struct pagevec pvec;
+	unsigned int i, count;
+	int nr;
+
+	pagevec_init(&pvec, 0);
+	count = min(pagevec_space(&pvec), to_capture);
+	nr = 0;
+
+	/* find pages tagged MOVED */
+	write_lock_irq(&mapping->tree_lock);
+	pvec.nr = radix_tree_gang_lookup_tag(&mapping->page_tree,
+					     (void **)pvec.pages, *index, count,
+					     PAGECACHE_TAG_REISER4_MOVED);
+	if (pagevec_count(&pvec) == 0) {
+		/* there are no pages tagged MOVED in mapping->page_tree
+		   starting from *index */
+		write_unlock_irq(&mapping->tree_lock);
+		*index = (pgoff_t)-1;
+		return 0;
+	}
+
+	/* clear tag for all found pages */
+	for (i = 0; i < pagevec_count(&pvec); i++) {
+		void *p;
+
+		page_cache_get(pvec.pages[i]);
+		p = radix_tree_tag_clear(&mapping->page_tree, pvec.pages[i]->index,
+					 PAGECACHE_TAG_REISER4_MOVED);
+		assert("vs-49", p == pvec.pages[i]);
+	}
+	write_unlock_irq(&mapping->tree_lock);
+
+
+	*index = pvec.pages[i - 1]->index + 1;
+
+	for (i = 0; i < pagevec_count(&pvec); i++) {
+		/* tag PAGECACHE_TAG_REISER4_MOVED will be cleared by
+		   set_page_dirty_internal which is called when jnode is
+		   captured */
+		result = capture_anonymous_page(pvec.pages[i]);
+		if (result == 1)
+			nr++;
+		else {
+			if (result < 0) {
+				warning("vs-1454",
+					"failed to capture page: "
+					"result=%d, captured=%d)\n",
+					result, i);
+
+				/* set MOVED tag to all pages which
+				   left not captured */
+				write_lock_irq(&mapping->tree_lock);
+				for (; i < pagevec_count(&pvec); i ++) {
+					radix_tree_tag_set(&mapping->page_tree,
+							   pvec.pages[i]->index,
+							   PAGECACHE_TAG_REISER4_MOVED);
+				}
+				write_unlock_irq(&mapping->tree_lock);
+
+				pagevec_release(&pvec);
+				return result;
+			} else {
+				/* result == 0. capture_anonymous_page returns
+				   0 for Writeback-ed page. Set MOVED tag on
+				   that page */
+				write_lock_irq(&mapping->tree_lock);
+				radix_tree_tag_set(&mapping->page_tree,
+						   pvec.pages[i]->index,
+						   PAGECACHE_TAG_REISER4_MOVED);
+				write_unlock_irq(&mapping->tree_lock);
+				if (i == 0)
+					*index = pvec.pages[0]->index;
+				else
+					*index = pvec.pages[i - 1]->index + 1;
+			}
+		}
+	}
+	pagevec_release(&pvec);
+	return nr;
+}
+
+/**
+ * capture_anonymous_jnodes - find and capture anonymous jnodes
+ * @mapping: address space where to look for jnodes
+ * @from: start index
+ * @to: end index
+ * @to_capture: maximum number of jnodes to capture
+ *
+ * Looks for jnodes tagged EFLUSH_TAG_ANONYMOUS in inode's tree of jnodes in
+ * the range of indexes @from-@to and captures them, returns number of captured
+ * jnodes, updates @from to next jnode after the last captured one.
+ */
+static int
+capture_anonymous_jnodes(struct address_space *mapping,
+			 pgoff_t *from, pgoff_t to, int to_capture)
+{
+#if REISER4_USE_EFLUSH
+	int found_jnodes;
+	int count;
+	int nr;
+	int i;
+	int result;
+	jnode *jvec[PAGEVEC_SIZE];
+	reiser4_tree *tree;
+	struct radix_tree_root *root;
+
+	count = min(PAGEVEC_SIZE, to_capture);
+	nr = 0;
+	result = 0;
+
+	tree = &get_super_private(mapping->host->i_sb)->tree;
+	root = jnode_tree_by_inode(mapping->host);
+
+	write_lock_irq(&mapping->tree_lock);
+
+	found_jnodes =
+	    radix_tree_gang_lookup_tag(root, (void **)&jvec, *from, count,
+				       EFLUSH_TAG_ANONYMOUS);
+	if (found_jnodes == 0) {
+		/* there are no anonymous jnodes from index @from down to the
+		   end of file */
+		write_unlock_irq(&mapping->tree_lock);
+		*from = to;
+		return 0;
+	}
+
+	for (i = 0; i < found_jnodes; i++) {
+		if (index_jnode(jvec[i]) < to) {
+			void *p;
+
+			jref(jvec[i]);
+			p = radix_tree_tag_clear(root, index_jnode(jvec[i]),
+						 EFLUSH_TAG_ANONYMOUS);
+			assert("", p == jvec[i]);
+
+			/* if page is tagged PAGECACHE_TAG_REISER4_MOVED it has
+			   to be untagged because we are about to capture it */
+			radix_tree_tag_clear(&mapping->page_tree, index_jnode(jvec[i]),
+					     PAGECACHE_TAG_REISER4_MOVED);
+		} else {
+			found_jnodes = i;
+			break;
+		}
+	}
+	write_unlock_irq(&mapping->tree_lock);
+
+	if (found_jnodes == 0) {
+		/* there are no anonymous jnodes in the given range of
+		   indexes */
+		*from = to;
+		return 0;
+	}
+
+	/* there are anonymous jnodes from given range */
+
+	/* start i/o for eflushed nodes */
+	for (i = 0; i < found_jnodes; i++)
+		jstartio(jvec[i]);
+
+	*from = index_jnode(jvec[found_jnodes - 1]) + 1;
+
+	for (i = 0; i < found_jnodes; i++) {
+		result = jload(jvec[i]);
+		if (result == 0) {
+			result = capture_anonymous_page(jnode_page(jvec[i]));
+			if (result == 1)
+				nr++;
+			else if (result < 0) {
+				jrelse(jvec[i]);
+				warning("nikita-3328",
+					"failed for anonymous jnode: result=%i, captured %d\n",
+					result, i);
+				/* set ANONYMOUS tag to all jnodes which left
+				   not captured */
+				write_lock_irq(&mapping->tree_lock);
+				for (; i < found_jnodes; i ++)
+					/* page should be in the mapping. Do
+					 * not tag jnode back as anonymous
+					 * because it is not now (after
+					 * jload) */
+					radix_tree_tag_set(&mapping->page_tree,
+							   index_jnode(jvec[i]),
+							   PAGECACHE_TAG_REISER4_MOVED);
+				write_unlock_irq(&mapping->tree_lock);
+				break;
+			} else {
+				/* result == 0. capture_anonymous_page returns
+				   0 for Writeback-ed page. Set ANONYMOUS tag
+				   on that jnode */
+				write_lock_irq(&mapping->tree_lock);
+				radix_tree_tag_set(&mapping->page_tree,
+						   index_jnode(jvec[i]),
+						   PAGECACHE_TAG_REISER4_MOVED);
+				write_unlock_irq(&mapping->tree_lock);
+				if (i == 0)
+					*from = index_jnode(jvec[0]);
+				else
+					*from = index_jnode(jvec[i - 1]) + 1;
+			}
+			jrelse(jvec[i]);
+		} else {
+			warning("vs-1454",
+				"jload for anonymous jnode failed: result=%i, captured %d\n",
+				result, i);
+			break;
+		}
+	}
+
+	for (i = 0; i < found_jnodes; i++)
+		jput(jvec[i]);
+	if (result)
+		return result;
+	return nr;
+#else				/* REISER4_USE_EFLUSH */
+	*from = to;
+	return 0;
+#endif
+}
+
+/*
+ * Commit atom of the jnode of a page.
+ */
+static int sync_page(struct page *page)
+{
+	int result;
+	do {
+		jnode *node;
+		txn_atom *atom;
+
+		lock_page(page);
+		node = jprivate(page);
+		if (node != NULL) {
+			spin_lock_jnode(node);
+			atom = jnode_get_atom(node);
+			spin_unlock_jnode(node);
+		} else
+			atom = NULL;
+		unlock_page(page);
+		result = sync_atom(atom);
+	} while (result == -E_REPEAT);
+	/*
+	 * ZAM-FIXME-HANS: document the logic of this loop, is it just to
+	 * handle the case where more pages get added to the atom while we are
+	 * syncing it?
+	 */
+	assert("nikita-3485", ergo(result == 0,
+				   get_current_context()->trans->atom == NULL));
+	return result;
+}
+
+/*
+ * Commit atoms of pages on @pages list.
+ * call sync_page for each page from mapping's page tree
+ */
+static int sync_page_list(struct inode *inode)
+{
+	int result;
+	struct address_space *mapping;
+	unsigned long from;	/* start index for radix_tree_gang_lookup */
+	unsigned int found;	/* return value for radix_tree_gang_lookup */
+
+	mapping = inode->i_mapping;
+	from = 0;
+	result = 0;
+	read_lock_irq(&mapping->tree_lock);
+	while (result == 0) {
+		struct page *page;
+
+		found =
+		    radix_tree_gang_lookup(&mapping->page_tree, (void **)&page,
+					   from, 1);
+		assert("", found < 2);
+		if (found == 0)
+			break;
+
+		/* page may not leave radix tree because it is protected from truncating by inode->i_mutex locked by
+		   sys_fsync */
+		page_cache_get(page);
+		read_unlock_irq(&mapping->tree_lock);
+
+		from = page->index + 1;
+
+		result = sync_page(page);
+
+		page_cache_release(page);
+		read_lock_irq(&mapping->tree_lock);
+	}
+
+	read_unlock_irq(&mapping->tree_lock);
+	return result;
+}
+
+static int commit_file_atoms(struct inode *inode)
+{
+	int result;
+	unix_file_info_t *uf_info;
+
+	/* close current transaction */
+	txn_restart_current();
+
+	uf_info = unix_file_inode_data(inode);
+
+	/*
+	 * finish extent<->tail conversion if necessary
+	 */
+	get_exclusive_access(uf_info);
+	if (inode_get_flag(inode, REISER4_PART_CONV)) {
+		result = finish_conversion(inode);
+		if (result != 0) {
+			drop_exclusive_access(uf_info);
+			return result;
+		}
+	}
+
+	/*
+	 * find what items file is made from
+	 */
+	result = find_file_state(uf_info);
+	drop_exclusive_access(uf_info);
+	if (result != 0)
+		return result;
+
+	/*
+	 * file state cannot change because we are under ->i_mutex
+	 */
+	switch (uf_info->container) {
+	case UF_CONTAINER_EXTENTS:
+		/* find_file_state might open join an atom */
+		txn_restart_current();
+		result =
+		    /*
+		     * when we are called by
+		     * filemap_fdatawrite->
+		     *    do_writepages()->
+		     *       reiser4_writepages()
+		     *
+		     * inode->i_mapping->dirty_pages are spices into
+		     * ->io_pages, leaving ->dirty_pages dirty.
+		     *
+		     * When we are called from
+		     * reiser4_fsync()->sync_unix_file(), we have to
+		     * commit atoms of all pages on the ->dirty_list.
+		     *
+		     * So for simplicity we just commit ->io_pages and
+		     * ->dirty_pages.
+		     */
+		    sync_page_list(inode);
+		break;
+	case UF_CONTAINER_TAILS:
+		/*
+		 * NOTE-NIKITA probably we can be smarter for tails. For now
+		 * just commit all existing atoms.
+		 */
+		result = txnmgr_force_commit_all(inode->i_sb, 0);
+		break;
+	case UF_CONTAINER_EMPTY:
+		result = 0;
+		break;
+	case UF_CONTAINER_UNKNOWN:
+	default:
+		result = -EIO;
+		break;
+	}
+
+	/*
+	 * commit current transaction: there can be captured nodes from
+	 * find_file_state() and finish_conversion().
+	 */
+	txn_restart_current();
+	return result;
+}
+
+/**
+ * writepages_unix_file - writepages of struct address_space_operations
+ * @mapping:
+ * @wbc:
+ *
+ * This captures anonymous pages and anonymous jnodes. Anonymous pages are
+ * pages which are dirtied via mmapping. Anonymous jnodes are ones which were
+ * created by reiser4_writepage.
+ */
+int
+writepages_unix_file(struct address_space *mapping,
+		     struct writeback_control *wbc)
+{
+	int result;
+	unix_file_info_t *uf_info;
+	pgoff_t pindex, jindex, nr_pages;
+	long to_capture;
+	struct inode *inode;
+
+	inode = mapping->host;
+	if (!has_anonymous_pages(inode)) {
+		result = 0;
+		goto end;
+	}
+	jindex = pindex = wbc->start >> PAGE_CACHE_SHIFT;
+	result = 0;
+	nr_pages =
+	    (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	uf_info = unix_file_inode_data(inode);
+
+	do {
+		reiser4_context *ctx;
+
+		if (wbc->sync_mode != WB_SYNC_ALL)
+			to_capture = min(wbc->nr_to_write, CAPTURE_APAGE_BURST);
+		else
+			to_capture = CAPTURE_APAGE_BURST;
+
+		ctx = init_context(inode->i_sb);
+		if (IS_ERR(ctx)) {
+			result = PTR_ERR(ctx);
+			break;
+		}
+		/* avoid recursive calls to ->sync_inodes */
+		ctx->nobalance = 1;
+		assert("zam-760", lock_stack_isclean(get_current_lock_stack()));
+		assert("", LOCK_CNT_NIL(inode_sem_w));
+		assert("", LOCK_CNT_NIL(inode_sem_r));
+
+		txn_restart_current();
+
+		/* we have to get nonexclusive access to the file */
+		if (get_current_context()->entd) {
+			/*
+			 * use nonblocking version of nonexclusive_access to
+			 * avoid deadlock which might look like the following:
+			 * process P1 holds NEA on file F1 and called entd to
+			 * reclaim some memory. Entd works for P1 and is going
+			 * to capture pages of file F2. To do that entd has to
+			 * get NEA to F2. F2 is held by process P2 which also
+			 * called entd. But entd is serving P1 at the moment
+			 * and P2 has to wait. Process P3 trying to get EA to
+			 * file F2. Existence of pending EA request to file F2
+			 * makes impossible for entd to get NEA to file
+			 * F2. Neither of these process can continue. Using
+			 * nonblocking version of gettign NEA is supposed to
+			 * avoid this deadlock.
+			 */
+			if (try_to_get_nonexclusive_access(uf_info) == 0) {
+				result = RETERR(-EBUSY);
+				reiser4_exit_context(ctx);
+				break;
+			}
+		} else
+			get_nonexclusive_access(uf_info, 0);
+
+		while (to_capture > 0) {
+			pgoff_t start;
+
+			assert("vs-1727", jindex <= pindex);
+			if (pindex == jindex) {
+				start = pindex;
+				result =
+				    capture_anonymous_pages(inode->i_mapping,
+							    &pindex,
+							    to_capture);
+				if (result <= 0)
+					break;
+				to_capture -= result;
+				wbc->nr_to_write -= result;
+				if (start + result == pindex) {
+					jindex = pindex;
+					continue;
+				}
+				if (to_capture <= 0)
+					break;
+			}
+			/* deal with anonymous jnodes between jindex and pindex */
+			result =
+			    capture_anonymous_jnodes(inode->i_mapping, &jindex,
+						     pindex, to_capture);
+			if (result < 0)
+				break;
+			to_capture -= result;
+			get_current_context()->nr_captured += result;
+
+			if (jindex == (pgoff_t) - 1) {
+				assert("vs-1728", pindex == (pgoff_t) - 1);
+				break;
+			}
+		}
+		if (to_capture <= 0)
+			/* there may be left more pages */
+			__mark_inode_dirty(inode, I_DIRTY_PAGES);
+
+		drop_nonexclusive_access(uf_info);
+		if (result < 0) {
+			/* error happened */
+			reiser4_exit_context(ctx);
+			return result;
+		}
+		if (wbc->sync_mode != WB_SYNC_ALL) {
+			reiser4_exit_context(ctx);
+			return 0;
+		}
+		result = commit_file_atoms(inode);
+		reiser4_exit_context(ctx);
+		if (pindex >= nr_pages && jindex == pindex)
+			break;
+	} while (1);
+
+      end:
+	if (is_in_reiser4_context()) {
+		if (get_current_context()->nr_captured >= CAPTURE_APAGE_BURST) {
+			/*
+			 * there are already pages to flush, flush them out, do
+			 * not delay until end of reiser4_sync_inodes
+			 */
+			writeout(inode->i_sb, wbc);
+			get_current_context()->nr_captured = 0;
+		}
+	}
+	return result;
+}
+
+/*
+ * ->sync() method for unix file.
+ *
+ * We are trying to be smart here. Instead of committing all atoms (original
+ * solution), we scan dirty pages of this file and commit all atoms they are
+ * part of.
+ *
+ * Situation is complicated by anonymous pages: i.e., extent-less pages
+ * dirtied through mmap. Fortunately sys_fsync() first calls
+ * filemap_fdatawrite() that will ultimately call reiser4_writepages(), insert
+ * all missing extents and capture anonymous pages.
+ */
+int sync_unix_file(struct file *file, struct dentry *dentry, int datasync)
+{
+	reiser4_context *ctx;
+	txn_atom *atom;
+	reiser4_block_nr reserve;
+
+	ctx = init_context(dentry->d_inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	reserve = estimate_update_common(dentry->d_inode);
+	if (reiser4_grab_space(reserve, BA_CAN_COMMIT)) {
+		reiser4_exit_context(ctx);
+		return RETERR(-ENOSPC);
+	}
+	write_sd_by_inode_common(dentry->d_inode);
+
+	atom = get_current_atom_locked();
+	spin_lock_txnh(ctx->trans);
+	force_commit_atom(ctx->trans);
+	reiser4_exit_context(ctx);
+	return 0;
+}
+
+/**
+ * readpage_unix_file_nolock - readpage of struct address_space_operations
+ * @file:
+ * @page:
+ *
+ * Compose a key and search for item containing information about @page
+ * data. If item is found - its readpage method is called.
+ */
+int readpage_unix_file_nolock(struct file *file, struct page *page)
+{
+	reiser4_context *ctx;
+	int result;
+	struct inode *inode;
+	reiser4_key key;
+	item_plugin *iplug;
+	hint_t *hint;
+	lock_handle *lh;
+	coord_t *coord;
+
+	assert("vs-1062", PageLocked(page));
+	assert("vs-976", !PageUptodate(page));
+	assert("vs-1061", page->mapping && page->mapping->host);
+
+	if ((page->mapping->host->i_size <=
+	     ((loff_t) page->index << PAGE_CACHE_SHIFT))) {
+		/* page is out of file already */
+		unlock_page(page);
+		return -EINVAL;
+	}
+
+	inode = page->mapping->host;
+	ctx = init_context(inode->i_sb);
+	if (IS_ERR(ctx)) {
+		unlock_page(page);
+		return PTR_ERR(ctx);
+	}
+
+	hint = kmalloc(sizeof(*hint), GFP_KERNEL);
+	if (hint == NULL) {
+		unlock_page(page);
+		reiser4_exit_context(ctx);
+		return RETERR(-ENOMEM);
+	}
+
+	result = load_file_hint(file, hint);
+	if (result) {
+		kfree(hint);
+		unlock_page(page);
+		reiser4_exit_context(ctx);
+		return result;
+	}
+	lh = &hint->lh;
+
+	/* get key of first byte of the page */
+	key_by_inode_and_offset_common(inode,
+				       (loff_t) page->index << PAGE_CACHE_SHIFT,
+				       &key);
+
+	/* look for file metadata corresponding to first byte of page */
+	page_cache_get(page);
+	unlock_page(page);
+	result = find_file_item(hint, &key, ZNODE_READ_LOCK, inode);
+	lock_page(page);
+	page_cache_release(page);
+
+	if (page->mapping == NULL) {
+		/*
+		 * readpage allows truncate to run concurrently. Page was
+		 * truncated while it was not locked
+		 */
+		done_lh(lh);
+		kfree(hint);
+		unlock_page(page);
+		reiser4_exit_context(ctx);
+		return -EINVAL;
+	}
+
+	if (result != CBK_COORD_FOUND || hint->ext_coord.coord.between != AT_UNIT) {
+		if (result == CBK_COORD_FOUND &&
+		    hint->ext_coord.coord.between != AT_UNIT)
+			/* file is truncated */
+			result = -EINVAL;
+		done_lh(lh);
+		kfree(hint);
+		unlock_page(page);
+		reiser4_exit_context(ctx);
+		return result;
+	}
+
+	/*
+	 * item corresponding to page is found. It can not be removed because
+	 * znode lock is held
+	 */
+	if (PageUptodate(page)) {
+		done_lh(lh);
+		kfree(hint);
+		unlock_page(page);
+		reiser4_exit_context(ctx);
+		return 0;
+	}
+
+	coord = &hint->ext_coord.coord;
+	result = zload(coord->node);
+	if (result) {
+		done_lh(lh);
+		kfree(hint);
+		unlock_page(page);
+		reiser4_exit_context(ctx);
+		return result;
+	}
+
+	if (hint->ext_coord.valid == 0)
+		validate_extended_coord(&hint->ext_coord,
+					(loff_t) page->
+					index << PAGE_CACHE_SHIFT);
+
+	if (!coord_is_existing_unit(coord)) {
+		/* this indicates corruption */
+		warning("vs-280",
+			"Looking for page %lu of file %llu (size %lli). "
+			"No file items found (%d). File is corrupted?\n",
+			page->index, (unsigned long long)get_inode_oid(inode),
+			inode->i_size, result);
+		zrelse(coord->node);
+		done_lh(lh);
+		kfree(hint);
+		unlock_page(page);
+		reiser4_exit_context(ctx);
+		return RETERR(-EIO);
+	}
+
+	/*
+	 * get plugin of found item or use plugin if extent if there are no
+	 * one
+	 */
+	iplug = item_plugin_by_coord(coord);
+	if (iplug->s.file.readpage)
+		result = iplug->s.file.readpage(coord, page);
+	else
+		result = RETERR(-EINVAL);
+
+	if (!result) {
+		set_key_offset(&key,
+			       (loff_t) (page->index + 1) << PAGE_CACHE_SHIFT);
+		/* FIXME should call set_hint() */
+		unset_hint(hint);
+	} else {
+		unlock_page(page);
+		unset_hint(hint);
+	}
+	assert("vs-979",
+	       ergo(result == 0, (PageLocked(page) || PageUptodate(page))));
+	assert("vs-9791", ergo(result != 0, !PageLocked(page)));
+
+	zrelse(coord->node);
+	done_lh(lh);
+
+	save_file_hint(file, hint);
+	kfree(hint);
+
+	reiser4_exit_context(ctx);
+	return result;
+}
+
+/**
+ * readpage_unix_file - readpage of struct address_space_operations
+ * @file: file @page belongs to
+ * @page: page to read
+ *
+ * Get non exclusive access to a file to avoid races with truncate. If page is
+ * out of file - return error. Call readpage_unix_file_nolock to do the rest.
+ */
+int readpage_unix_file(struct file *file, struct page *page)
+{
+	return readpage_unix_file_nolock(file, page);
+}
+
+/* returns 1 if file of that size (@new_size) has to be stored in unformatted
+   nodes */
+/* Audited by: green(2002.06.15) */
+static int should_have_notail(const unix_file_info_t * uf_info, loff_t new_size)
+{
+	if (!uf_info->tplug)
+		return 1;
+	return !uf_info->tplug->have_tail(unix_file_info_to_inode(uf_info),
+					  new_size);
+
+}
+
+static reiser4_block_nr unix_file_estimate_read(struct inode *inode,
+						loff_t count UNUSED_ARG)
+{
+	/* We should reserve one block, because of updating of the stat data
+	   item */
+	assert("vs-1249",
+	       inode_file_plugin(inode)->estimate.update ==
+	       estimate_update_common);
+	return estimate_update_common(inode);
+}
+
+/* this is called with nonexclusive access obtained, file's container can not change */
+static size_t read_file(hint_t * hint, struct file *file,	/* file to read from to */
+			char __user *buf,	/* address of user-space buffer */
+			size_t count,	/* number of bytes to read */
+			loff_t * off)
+{
+	int result;
+	struct inode *inode;
+	flow_t flow;
+	int (*read_f) (struct file *, flow_t *, hint_t *);
+	coord_t *coord;
+	znode *loaded;
+
+	inode = file->f_dentry->d_inode;
+
+	/* build flow */
+	assert("vs-1250",
+	       inode_file_plugin(inode)->flow_by_inode ==
+	       flow_by_inode_unix_file);
+	result =
+	    flow_by_inode_unix_file(inode, buf, 1 /* user space */ , count,
+				    *off, READ_OP, &flow);
+	if (unlikely(result))
+		return result;
+
+	/* get seal and coord sealed with it from reiser4 private data
+	   of struct file.  The coord will tell us where our last read
+	   of this file finished, and the seal will help to determine
+	   if that location is still valid.
+	 */
+	coord = &hint->ext_coord.coord;
+	while (flow.length && result == 0) {
+		result =
+			find_file_item(hint, &flow.key, ZNODE_READ_LOCK, inode);
+		if (cbk_errored(result))
+			/* error happened */
+			break;
+
+		if (coord->between != AT_UNIT)
+			/* there were no items corresponding to given offset */
+			break;
+
+		loaded = coord->node;
+		result = zload(loaded);
+		if (unlikely(result))
+			break;
+
+		if (hint->ext_coord.valid == 0)
+			validate_extended_coord(&hint->ext_coord,
+						get_key_offset(&flow.key));
+
+		assert("vs-4", hint->ext_coord.valid == 1);
+		assert("vs-33", hint->ext_coord.lh == &hint->lh);
+		/* call item's read method */
+		read_f = item_plugin_by_coord(coord)->s.file.read;
+		result = read_f(file, &flow, hint);
+		zrelse(loaded);
+		done_lh(hint->ext_coord.lh);
+	}
+
+	return (count - flow.length) ? (count - flow.length) : result;
+}
+
+/**
+ * read_unix_file - read of struct file_operations
+ * @file: file to read from
+ * @buf: address of user-space buffer
+ * @read_amount: number of bytes to read
+ * @off: position in file to read from
+ *
+ * This is implementation of vfs's read method of struct file_operations for
+ * unix file plugin.
+ */
+ssize_t
+read_unix_file(struct file *file, char __user *buf, size_t read_amount,
+	       loff_t *off)
+{
+	reiser4_context *ctx;
+	int result;
+	struct inode *inode;
+	hint_t *hint;
+	unix_file_info_t *uf_info;
+	size_t count, read, left;
+	reiser4_block_nr needed;
+	loff_t size;
+
+	if (unlikely(read_amount == 0))
+		return 0;
+
+	assert("umka-072", file != NULL);
+	assert("umka-074", off != NULL);
+	inode = file->f_dentry->d_inode;
+	assert("vs-972", !inode_get_flag(inode, REISER4_NO_SD));
+
+	ctx = init_context(inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	hint = kmalloc(sizeof(*hint), GFP_KERNEL);
+	if (hint == NULL) {
+		context_set_commit_async(ctx);
+		reiser4_exit_context(ctx);
+		return RETERR(-ENOMEM);
+	}
+
+	result = load_file_hint(file, hint);
+	if (result) {
+		kfree(hint);
+		context_set_commit_async(ctx);
+		reiser4_exit_context(ctx);
+		return result;
+	}
+
+	left = read_amount;
+	count = 0;
+	uf_info = unix_file_inode_data(inode);
+	while (left > 0) {
+		txn_restart_current();
+
+		get_nonexclusive_access(uf_info, 0);
+
+		size = i_size_read(inode);
+		if (*off >= size) {
+			/* position to read from is past the end of file */
+			drop_nonexclusive_access(uf_info);
+			break;
+		}
+		if (*off + left > size)
+			left = size - *off;
+
+		/* faultin user page */
+		result = fault_in_pages_writeable(buf, left > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : left);
+		if (result) {
+			drop_nonexclusive_access(uf_info);
+			return RETERR(-EFAULT);
+		}
+
+		read = read_file(hint, file, buf, left, off);
+
+ 		drop_nonexclusive_access(uf_info);
+
+		if (read < 0) {
+			result = read;
+			break;
+		}
+		left -= read;
+		buf += read;
+
+		/* update position in a file */
+		*off += read;
+		/* total number of read bytes */
+		count += read;
+	}
+	save_file_hint(file, hint);
+	kfree(hint);
+
+	if (count) {
+		/*
+		 * something was read. Grab space for stat data update and
+		 * update atime
+		 */
+		needed = unix_file_estimate_read(inode, read_amount);
+		result = reiser4_grab_space_force(needed, BA_CAN_COMMIT);
+		if (result == 0)
+			file_accessed(file);
+		else
+			warning("", "failed to grab space for atime update");
+	}
+
+	context_set_commit_async(ctx);
+	reiser4_exit_context(ctx);
+
+	/* return number of read bytes or error code if nothing is read */
+	return count ? count : result;
+}
+
+typedef int (*write_f_t) (struct inode *, flow_t *, hint_t *, int grabbed,
+			  write_mode_t);
+
+/* This searches for write position in the tree and calls write method of
+   appropriate item to actually copy user data into filesystem. This loops
+   until all the data from flow @f are written to a file. */
+static loff_t
+append_and_or_overwrite(hint_t * hint, struct file *file, struct inode *inode,
+			flow_t * flow,
+			int exclusive
+			/* if 1 - exclusive access on a file is obtained */ )
+{
+	int result;
+	loff_t to_write;
+	write_f_t write_f;
+	file_container_t cur_container, new_container;
+	znode *loaded;
+	unix_file_info_t *uf_info;
+
+	assert("nikita-3031", schedulable());
+	assert("vs-1109", get_current_context()->grabbed_blocks == 0);
+	assert("vs-1708", hint != NULL);
+
+	init_lh(&hint->lh);
+
+	result = 0;
+	uf_info = unix_file_inode_data(inode);
+
+	to_write = flow->length;
+	while (flow->length) {
+
+		assert("vs-1123", get_current_context()->grabbed_blocks == 0);
+
+		if (to_write == flow->length) {
+			/* it may happend that find_file_item will have to insert empty node to the tree (empty leaf
+			   node between two extent items) */
+			result =
+			    reiser4_grab_space_force(1 +
+						     estimate_one_insert_item
+						     (tree_by_inode(inode)), 0);
+			if (result)
+				return result;
+		}
+		/* when hint is set - hint's coord matches seal's coord */
+		assert("nikita-19894",
+		       !hint_is_set(hint) ||
+		       coords_equal(&hint->seal.coord1,
+				    &hint->ext_coord.coord));
+
+		/* look for file's metadata (extent or tail item) corresponding to position we write to */
+		result = find_file_item(hint, &flow->key, ZNODE_WRITE_LOCK,
+					inode);
+		all_grabbed2free();
+		if (IS_CBKERR(result)) {
+			/* error occurred */
+			done_lh(&hint->lh);
+			return result;
+		}
+		assert("vs-32", hint->lh.node == hint->ext_coord.coord.node);
+		cur_container = uf_info->container;
+		switch (cur_container) {
+		case UF_CONTAINER_EMPTY:
+			assert("vs-1196", get_key_offset(&flow->key) == 0);
+			if (should_have_notail
+			    (uf_info,
+			     get_key_offset(&flow->key) + flow->length)) {
+				new_container = UF_CONTAINER_EXTENTS;
+				write_f =
+				    item_plugin_by_id(EXTENT_POINTER_ID)->s.
+				    file.write;
+			} else {
+				new_container = UF_CONTAINER_TAILS;
+				write_f =
+				    item_plugin_by_id(FORMATTING_ID)->s.file.
+				    write;
+			}
+			break;
+
+		case UF_CONTAINER_EXTENTS:
+			write_f =
+			    item_plugin_by_id(EXTENT_POINTER_ID)->s.file.write;
+			new_container = cur_container;
+			break;
+
+		case UF_CONTAINER_TAILS:
+			if (should_have_notail
+			    (uf_info,
+			     get_key_offset(&flow->key) + flow->length)) {
+				done_lh(&hint->lh);
+				if (!exclusive) {
+					drop_nonexclusive_access(uf_info);
+					txn_restart_current();
+					get_exclusive_access(uf_info);
+				}
+				result = tail2extent(uf_info);
+				if (!exclusive) {
+					drop_exclusive_access(uf_info);
+					txn_restart_current();
+					get_nonexclusive_access(uf_info, 0);
+				}
+				if (result)
+					return result;
+				all_grabbed2free();
+				unset_hint(hint);
+				continue;
+			}
+			write_f =
+			    item_plugin_by_id(FORMATTING_ID)->s.file.write;
+			new_container = cur_container;
+			break;
+
+		default:
+			done_lh(&hint->lh);
+			return RETERR(-EIO);
+		}
+
+		result = zload(hint->lh.node);
+		if (result) {
+			done_lh(&hint->lh);
+			return result;
+		}
+		loaded = hint->lh.node;
+		assert("vs-11", hint->ext_coord.coord.node == loaded);
+		result = write_f(inode, flow, hint, 0 /* not grabbed */ ,
+				 how_to_write(&hint->ext_coord, &flow->key));
+
+		assert("nikita-3142",
+		       get_current_context()->grabbed_blocks == 0);
+		/* seal has either to be not set to set properly */
+		assert("nikita-19893",
+		       ((!hint_is_set(hint) && hint->ext_coord.valid == 0) ||
+			(coords_equal
+			 (&hint->seal.coord1, &hint->ext_coord.coord)
+			 && keyeq(&flow->key, &hint->seal.key))));
+
+		if (cur_container == UF_CONTAINER_EMPTY
+		    && to_write != flow->length) {
+			/* file was empty and we have written something and we are having exclusive access to the file -
+			   change file state */
+			assert("vs-1195",
+			       (new_container == UF_CONTAINER_TAILS
+				|| new_container == UF_CONTAINER_EXTENTS));
+			uf_info->container = new_container;
+		}
+		zrelse(loaded);
+		done_lh(&hint->lh);
+		if (result && result != -E_REPEAT && result != -E_DEADLOCK)
+			break;
+		preempt_point();
+	}
+
+	/* if nothing were written - there must be an error */
+	assert("vs-951", ergo((to_write == flow->length), result < 0));
+	assert("vs-1110", get_current_context()->grabbed_blocks == 0);
+
+	return (to_write - flow->length) ? (to_write - flow->length) : result;
+}
+
+/* make flow and write data (@buf) to the file. If @buf == 0 - hole of size @count will be created. This is called with
+   uf_info->latch either read- or write-locked */
+static loff_t
+write_flow(hint_t * hint, struct file *file, struct inode *inode,
+	   const char __user *buf, loff_t count, loff_t pos, int exclusive)
+{
+	int result;
+	flow_t flow;
+
+	assert("vs-1251",
+	       inode_file_plugin(inode)->flow_by_inode ==
+	       flow_by_inode_unix_file);
+
+	result = flow_by_inode_unix_file(inode,
+					 buf, 1 /* user space */ ,
+					 count, pos, WRITE_OP, &flow);
+	if (result)
+		return result;
+
+	return append_and_or_overwrite(hint, file, inode, &flow, exclusive);
+}
+
+/* This function takes care about @file's pages. First of all it checks if
+   filesystems readonly and if so gets out. Otherwise, it throws out all
+   pages of file if it was mapped for read and going to be mapped for write
+   and consists of tails. This is done in order to not manage few copies
+   of the data (first in page cache and second one in tails them selves)
+   for the case of mapping files consisting tails.
+
+   Here also tail2extent conversion is performed if it is allowed and file
+   is going to be written or mapped for write. This functions may be called
+   from write_unix_file() or mmap_unix_file(). */
+static int check_pages_unix_file(struct file *file, struct inode *inode)
+{
+	reiser4_invalidate_pages(inode->i_mapping, 0,
+				 (inode->i_size + PAGE_CACHE_SIZE -
+				  1) >> PAGE_CACHE_SHIFT, 0);
+	return unpack(file, inode, 0 /* not forever */ );
+}
+
+/**
+ * mmap_unix_file - mmap of struct file_operations
+ * @file: file to mmap
+ * @vma:
+ *
+ * This is implementation of vfs's mmap method of struct file_operations for
+ * unix file plugin. It converts file to extent if necessary. Sets
+ * reiser4_inode's flag - REISER4_HAS_MMAP.
+ */
+int mmap_unix_file(struct file *file, struct vm_area_struct *vma)
+{
+	reiser4_context *ctx;
+	int result;
+	struct inode *inode;
+	unix_file_info_t *uf_info;
+	reiser4_block_nr needed;
+
+	inode = file->f_dentry->d_inode;
+	ctx = init_context(inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	uf_info = unix_file_inode_data(inode);
+
+	down(&uf_info->write);
+	get_exclusive_access(uf_info);
+
+	if (!IS_RDONLY(inode) && (vma->vm_flags & (VM_MAYWRITE | VM_SHARED))) {
+		/*
+		 * we need file built of extent items. If it is still built of
+		 * tail items we have to convert it. Find what items the file
+		 * is built of
+		 */
+		result = finish_conversion(inode);
+		if (result) {
+			drop_exclusive_access(uf_info);
+			up(&uf_info->write);
+			reiser4_exit_context(ctx);
+			return result;
+		}
+
+		result = find_file_state(uf_info);
+		if (result != 0) {
+			drop_exclusive_access(uf_info);
+			up(&uf_info->write);
+			reiser4_exit_context(ctx);
+			return result;
+		}
+
+		assert("vs-1648", (uf_info->container == UF_CONTAINER_TAILS ||
+				   uf_info->container == UF_CONTAINER_EXTENTS ||
+				   uf_info->container == UF_CONTAINER_EMPTY));
+		if (uf_info->container == UF_CONTAINER_TAILS) {
+			/*
+			 * invalidate all pages and convert file from tails to
+			 * extents
+			 */
+			result = check_pages_unix_file(file, inode);
+			if (result) {
+				drop_exclusive_access(uf_info);
+				up(&uf_info->write);
+				reiser4_exit_context(ctx);
+				return result;
+			}
+		}
+	}
+
+	/*
+	 * generic_file_mmap will do update_atime. Grab space for stat data
+	 * update.
+	 */
+	needed = inode_file_plugin(inode)->estimate.update(inode);
+	result = reiser4_grab_space_force(needed, BA_CAN_COMMIT);
+	if (result) {
+		drop_exclusive_access(uf_info);
+		up(&uf_info->write);
+		reiser4_exit_context(ctx);
+		return result;
+	}
+
+	result = generic_file_mmap(file, vma);
+	if (result == 0) {
+		/* mark file as having mapping. */
+		inode_set_flag(inode, REISER4_HAS_MMAP);
+	}
+
+	drop_exclusive_access(uf_info);
+	up(&uf_info->write);
+	reiser4_exit_context(ctx);
+	return result;
+}
+
+static ssize_t write_file(hint_t * hint, struct file *file,	/* file to write to */
+			  const char __user *buf,	/* address of user-space buffer */
+			  size_t count,	/* number of bytes to write */
+			  loff_t * off /* position in file to write to */ ,
+			  int exclusive)
+{
+	struct inode *inode;
+	ssize_t written;	/* amount actually written so far */
+	loff_t pos;		/* current location in the file */
+
+	inode = file->f_dentry->d_inode;
+
+	/* estimation for write is entrusted to write item plugins */
+	pos = *off;
+
+	if (inode->i_size < pos) {
+		/* pos is set past real end of file */
+		written = append_hole(hint, inode, pos, exclusive);
+		if (written)
+			return written;
+		assert("vs-1081", pos == inode->i_size);
+	}
+
+	/* write user data to the file */
+	written = write_flow(hint, file, inode, buf, count, pos, exclusive);
+	if (written > 0)
+		/* update position in a file */
+		*off = pos + written;
+
+	/* return number of written bytes, or error code */
+	return written;
+}
+
+/**
+ * write_unix_file - write of struct file_operations
+ * @file: file to write to
+ * @buf: address of user-space buffer
+ * @write_amount: number of bytes to write
+ * @off: position in file to write to
+ *
+ * This is implementation of vfs's write method of struct file_operations for
+ * unix file plugin.
+ */
+ssize_t write_unix_file(struct file *file, const char __user *buf,
+			size_t write_amount, loff_t *off)
+{
+	reiser4_context *ctx;
+	int result;
+	struct inode *inode;
+	hint_t *hint;
+	unix_file_info_t *uf_info;
+	size_t count, written, left;
+	int try_free_space;
+
+	if (unlikely(write_amount == 0))
+		return 0;
+
+	inode = file->f_dentry->d_inode;
+	ctx = init_context(inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	assert("vs-947", !inode_get_flag(inode, REISER4_NO_SD));
+
+	uf_info = unix_file_inode_data(inode);
+
+	down(&uf_info->write);
+
+	result = generic_write_checks(file, off, &write_amount, 0);
+	if (result) {
+		up(&uf_info->write);
+		context_set_commit_async(ctx);
+		reiser4_exit_context(ctx);
+		return result;
+	}
+
+	/* linux's VM requires this. See mm/vmscan.c:shrink_list() */
+	current->backing_dev_info = inode->i_mapping->backing_dev_info;
+
+	if (inode_get_flag(inode, REISER4_PART_CONV)) {
+		/* we can not currently write to a file which is partially converted */
+		get_exclusive_access(uf_info);
+		result = finish_conversion(inode);
+		drop_exclusive_access(uf_info);
+		if (result) {
+			current->backing_dev_info = NULL;
+			up(&uf_info->write);
+			context_set_commit_async(ctx);
+			reiser4_exit_context(ctx);
+			return result;
+		}
+	}
+
+	if (inode_get_flag(inode, REISER4_HAS_MMAP)
+	    && uf_info->container == UF_CONTAINER_TAILS) {
+		/* file built of tails was mmaped. So, there might be
+		   faultin-ed pages filled by tail item contents and mapped to
+		   process address space.
+		   Before starting write:
+
+		   1) block new page creation by obtaining exclusive access to
+		   the file
+
+		   2) unmap address space of all mmap - now it is by
+		   reiser4_invalidate_pages which invalidate pages as well
+
+		   3) convert file to extents to not enter here on each write
+		   to mmaped file */
+		get_exclusive_access(uf_info);
+		result = check_pages_unix_file(file, inode);
+		drop_exclusive_access(uf_info);
+		if (result) {
+			current->backing_dev_info = NULL;
+			up(&uf_info->write);
+			context_set_commit_async(ctx);
+			reiser4_exit_context(ctx);
+			return result;
+		}
+	}
+
+	/* UNIX behavior: clear suid bit on file modification. This cannot be
+	   done earlier, because removing suid bit captures blocks into
+	   transaction, which should be done after taking either exclusive or
+	   non-exclusive access on the file. */
+	result = remove_suid(file->f_dentry);
+	if (result != 0) {
+		current->backing_dev_info = NULL;
+		up(&uf_info->write);
+		context_set_commit_async(ctx);
+		reiser4_exit_context(ctx);
+		return result;
+	}
+	grab_space_enable();
+
+	hint = kmalloc(sizeof(*hint), GFP_KERNEL);
+	if (hint == NULL) {
+		current->backing_dev_info = NULL;
+		up(&uf_info->write);
+		context_set_commit_async(ctx);
+		reiser4_exit_context(ctx);
+		return RETERR(-ENOMEM);
+	}
+
+	/* get seal and coord sealed with it from reiser4 private data of
+	 * struct file */
+	result = load_file_hint(file, hint);
+	if (result) {
+		current->backing_dev_info = NULL;
+		up(&uf_info->write);
+		kfree(hint);
+		context_set_commit_async(ctx);
+		reiser4_exit_context(ctx);
+		return result;
+	}
+
+	left = write_amount;
+	count = 0;
+	try_free_space = 1;
+
+	while (left > 0) {
+		int excl = 0;
+
+		/* getting exclusive or not exclusive access requires no
+		   transaction open */
+		txn_restart_current();
+
+		/* faultin user page */
+		fault_in_pages_readable(buf,
+					left > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : left);
+
+		if (inode->i_size == 0) {
+			get_exclusive_access(uf_info);
+			excl = 1;
+		} else {
+			get_nonexclusive_access(uf_info, 0);
+			excl = 0;
+		}
+
+		all_grabbed2free();
+		written = write_file(hint, file, buf, left, off, excl);
+		if (excl)
+			drop_exclusive_access(uf_info);
+		else
+			drop_nonexclusive_access(uf_info);
+
+		/* With no locks held we can commit atoms in attempt to recover
+		 * free space. */
+		if ((ssize_t) written == -ENOSPC && try_free_space) {
+			txnmgr_force_commit_all(inode->i_sb, 0);
+			try_free_space = 0;
+			continue;
+		}
+		if ((ssize_t) written < 0) {
+			result = written;
+			break;
+		}
+		left -= written;
+		buf += written;
+
+		/* total number of written bytes */
+		count += written;
+	}
+
+	if (result == 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
+		txn_restart_current();
+		grab_space_enable();
+		result =
+		    sync_unix_file(file, file->f_dentry,
+				   0 /* data and stat data */ );
+		if (result)
+			warning("reiser4-7", "failed to sync file %llu",
+				(unsigned long long)get_inode_oid(inode));
+	}
+
+	save_file_hint(file, hint);
+	kfree(hint);
+	up(&uf_info->write);
+	current->backing_dev_info = NULL;
+
+	context_set_commit_async(ctx);
+	reiser4_exit_context(ctx);
+
+	/* return number of written bytes or error code if nothing is written */
+	return count ? count : result;
+}
+
+/**
+ * release_unix_file - release of struct file_operations
+ * @inode: inode of released file
+ * @file: file to release
+ *
+ * Implementation of release method of struct file_operations for unix file
+ * plugin. If last reference to indode is released - convert all extent items
+ * into tail items if necessary. Frees reiser4 specific file data.
+ */
+int release_unix_file(struct inode *inode, struct file *file)
+{
+	reiser4_context *ctx;
+	unix_file_info_t *uf_info;
+	int result;
+	int in_reiser4;
+
+	in_reiser4 = is_in_reiser4_context();
+
+	ctx = init_context(inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	result = 0;
+	if (in_reiser4 == 0) {
+		uf_info = unix_file_inode_data(inode);
+
+		down(&uf_info->write);
+		get_exclusive_access(uf_info);
+		if (atomic_read(&file->f_dentry->d_count) == 1 &&
+		    uf_info->container == UF_CONTAINER_EXTENTS &&
+		    !should_have_notail(uf_info, inode->i_size) &&
+		    !rofs_inode(inode)) {
+			result = extent2tail(uf_info);
+			if (result != 0) {
+				warning("nikita-3233",
+					"Failed to convert in %s (%llu)",
+					__FUNCTION__,
+					(unsigned long long)
+					get_inode_oid(inode));
+			}
+		}
+		drop_exclusive_access(uf_info);
+		up(&uf_info->write);
+	} else {
+		/*
+		   we are within reiser4 context already. How latter is
+		   possible? Simple:
+
+		   (gdb) bt
+		   #0  get_exclusive_access ()
+		   #2  0xc01e56d3 in release_unix_file ()
+		   #3  0xc01c3643 in reiser4_release ()
+		   #4  0xc014cae0 in __fput ()
+		   #5  0xc013ffc3 in remove_vm_struct ()
+		   #6  0xc0141786 in exit_mmap ()
+		   #7  0xc0118480 in mmput ()
+		   #8  0xc0133205 in oom_kill ()
+		   #9  0xc01332d1 in out_of_memory ()
+		   #10 0xc013bc1d in try_to_free_pages ()
+		   #11 0xc013427b in __alloc_pages ()
+		   #12 0xc013f058 in do_anonymous_page ()
+		   #13 0xc013f19d in do_no_page ()
+		   #14 0xc013f60e in handle_mm_fault ()
+		   #15 0xc01131e5 in do_page_fault ()
+		   #16 0xc0104935 in error_code ()
+		   #17 0xc025c0c6 in __copy_to_user_ll ()
+		   #18 0xc01d496f in read_tail ()
+		   #19 0xc01e4def in read_unix_file ()
+		   #20 0xc01c3504 in reiser4_read ()
+		   #21 0xc014bd4f in vfs_read ()
+		   #22 0xc014bf66 in sys_read ()
+		 */
+		warning("vs-44", "out of memory?");
+	}
+
+	reiser4_free_file_fsdata(file);
+
+	reiser4_exit_context(ctx);
+	return result;
+}
+
+static void set_file_notail(struct inode *inode)
+{
+	reiser4_inode *state;
+	formatting_plugin *tplug;
+
+	state = reiser4_inode_data(inode);
+	tplug = formatting_plugin_by_id(NEVER_TAILS_FORMATTING_ID);
+	plugin_set_formatting(&state->pset, tplug);
+	inode_set_plugin(inode,
+			 formatting_plugin_to_plugin(tplug), PSET_FORMATTING);
+}
+
+/* if file is built of tails - convert it to extents */
+static int unpack(struct file *filp, struct inode *inode, int forever)
+{
+	int result = 0;
+	unix_file_info_t *uf_info;
+
+	uf_info = unix_file_inode_data(inode);
+	assert("vs-1628", ea_obtained(uf_info));
+
+	result = find_file_state(uf_info);
+	assert("vs-1074",
+	       ergo(result == 0, uf_info->container != UF_CONTAINER_UNKNOWN));
+	if (result == 0) {
+		if (uf_info->container == UF_CONTAINER_TAILS)
+			result = tail2extent(uf_info);
+		if (result == 0 && forever)
+			set_file_notail(inode);
+		if (result == 0) {
+			__u64 tograb;
+
+			grab_space_enable();
+			tograb =
+			    inode_file_plugin(inode)->estimate.update(inode);
+			result = reiser4_grab_space(tograb, BA_CAN_COMMIT);
+		}
+	}
+
+	return result;
+}
+
+/* implentation of vfs' ioctl method of struct file_operations for unix file
+   plugin
+*/
+int
+ioctl_unix_file(struct inode *inode, struct file *filp,
+		unsigned int cmd, unsigned long arg UNUSED_ARG)
+{
+	reiser4_context *ctx;
+	int result;
+
+	ctx = init_context(inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	switch (cmd) {
+	case REISER4_IOC_UNPACK:
+		get_exclusive_access(unix_file_inode_data(inode));
+		result = unpack(filp, inode, 1 /* forever */ );
+		drop_exclusive_access(unix_file_inode_data(inode));
+		break;
+
+	default:
+		result = RETERR(-ENOSYS);
+		break;
+	}
+	reiser4_exit_context(ctx);
+	return result;
+}
+
+/* implentation of vfs' bmap method of struct address_space_operations for unix
+   file plugin
+*/
+sector_t bmap_unix_file(struct address_space * mapping, sector_t lblock)
+{
+	reiser4_context *ctx;
+	sector_t result;
+	reiser4_key key;
+	coord_t coord;
+	lock_handle lh;
+	struct inode *inode;
+	item_plugin *iplug;
+	sector_t block;
+
+	inode = mapping->host;
+
+	ctx = init_context(inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+	key_by_inode_and_offset_common(inode,
+				       (loff_t) lblock * current_blocksize,
+				       &key);
+
+	init_lh(&lh);
+	result =
+	    find_file_item_nohint(&coord, &lh, &key, ZNODE_READ_LOCK, inode);
+	if (cbk_errored(result)) {
+		done_lh(&lh);
+		reiser4_exit_context(ctx);
+		return result;
+	}
+
+	result = zload(coord.node);
+	if (result) {
+		done_lh(&lh);
+		reiser4_exit_context(ctx);
+		return result;
+	}
+
+	iplug = item_plugin_by_coord(&coord);
+	if (iplug->s.file.get_block) {
+		result = iplug->s.file.get_block(&coord, lblock, &block);
+		if (result == 0)
+			result = block;
+	} else
+		result = RETERR(-EINVAL);
+
+	zrelse(coord.node);
+	done_lh(&lh);
+	reiser4_exit_context(ctx);
+	return result;
+}
+
+/**
+ * flow_by_inode_unix_file - initizlize structure flow
+ * @inode: inode of file for which read or write is abou
+ * @buf: buffer to perform read to or write from
+ * @user: flag showing whether @buf is user space or kernel space
+ * @size: size of buffer @buf
+ * @off: start offset fro read or write
+ * @op: READ or WRITE
+ * @flow:
+ *
+ * Initializes fields of @flow: key, size of data, i/o mode (read or write).
+ */
+int flow_by_inode_unix_file(struct inode *inode,
+			    const char __user *buf, int user,
+			    loff_t size, loff_t off,
+			    rw_op op, flow_t *flow)
+{
+	assert("nikita-1100", inode != NULL);
+
+	flow->length = size;
+	memcpy(&flow->data, &buf, sizeof(buf));
+	flow->user = user;
+	flow->op = op;
+	assert("nikita-1931", inode_file_plugin(inode) != NULL);
+	assert("nikita-1932",
+	       inode_file_plugin(inode)->key_by_inode ==
+	       key_by_inode_and_offset_common);
+	/* calculate key of write position and insert it into flow->key */
+	return key_by_inode_and_offset_common(inode, off, &flow->key);
+}
+
+/* plugin->u.file.set_plug_in_sd = NULL
+   plugin->u.file.set_plug_in_inode = NULL
+   plugin->u.file.create_blank_sd = NULL */
+/* plugin->u.file.delete */
+/*
+   plugin->u.file.add_link = add_link_common
+   plugin->u.file.rem_link = NULL */
+
+/* plugin->u.file.owns_item
+   this is common_file_owns_item with assertion */
+/* Audited by: green(2002.06.15) */
+int
+owns_item_unix_file(const struct inode *inode /* object to check against */ ,
+		    const coord_t * coord /* coord to check */ )
+{
+	int result;
+
+	result = owns_item_common(inode, coord);
+	if (!result)
+		return 0;
+	if (item_type_by_coord(coord) != UNIX_FILE_METADATA_ITEM_TYPE)
+		return 0;
+	assert("vs-547",
+	       item_id_by_coord(coord) == EXTENT_POINTER_ID ||
+	       item_id_by_coord(coord) == FORMATTING_ID);
+	return 1;
+}
+
+static int setattr_truncate(struct inode *inode, struct iattr *attr)
+{
+	int result;
+	int s_result;
+	loff_t old_size;
+	reiser4_tree *tree;
+
+	inode_check_scale(inode, inode->i_size, attr->ia_size);
+
+	old_size = inode->i_size;
+	tree = tree_by_inode(inode);
+
+	result = safe_link_grab(tree, BA_CAN_COMMIT);
+	if (result == 0)
+		result = safe_link_add(inode, SAFE_TRUNCATE);
+	all_grabbed2free();
+	if (result == 0)
+		result = truncate_file_body(inode, attr->ia_size);
+	if (result)
+		warning("vs-1588", "truncate_file failed: oid %lli, "
+			"old size %lld, new size %lld, retval %d",
+			(unsigned long long)get_inode_oid(inode),
+			old_size, attr->ia_size, result);
+
+	s_result = safe_link_grab(tree, BA_CAN_COMMIT);
+	if (s_result == 0)
+		s_result =
+		    safe_link_del(tree, get_inode_oid(inode), SAFE_TRUNCATE);
+	if (s_result != 0) {
+		warning("nikita-3417", "Cannot kill safelink %lli: %i",
+			(unsigned long long)get_inode_oid(inode), s_result);
+	}
+	safe_link_release(tree);
+	all_grabbed2free();
+	return result;
+}
+
+/* plugin->u.file.setattr method */
+/* This calls inode_setattr and if truncate is in effect it also takes
+   exclusive inode access to avoid races */
+int setattr_unix_file(struct dentry *dentry,	/* Object to change attributes */
+		      struct iattr *attr /* change description */ )
+{
+	int result;
+
+	if (attr->ia_valid & ATTR_SIZE) {
+		reiser4_context *ctx;
+		unix_file_info_t *uf_info;
+
+		/* truncate does reservation itself and requires exclusive
+		   access obtained */
+		ctx = init_context(dentry->d_inode->i_sb);
+		if (IS_ERR(ctx))
+			return PTR_ERR(ctx);
+
+		uf_info = unix_file_inode_data(dentry->d_inode);
+		down(&uf_info->write);
+		get_exclusive_access(uf_info);
+		result = setattr_truncate(dentry->d_inode, attr);
+		drop_exclusive_access(uf_info);
+		up(&uf_info->write);
+		context_set_commit_async(ctx);
+		reiser4_exit_context(ctx);
+	} else
+		result = setattr_common(dentry, attr);
+
+	return result;
+}
+
+/* plugin->u.file.init_inode_data */
+void
+init_inode_data_unix_file(struct inode *inode,
+			  reiser4_object_create_data * crd, int create)
+{
+	unix_file_info_t *data;
+
+	data = unix_file_inode_data(inode);
+	data->container = create ? UF_CONTAINER_EMPTY : UF_CONTAINER_UNKNOWN;
+	init_rwsem(&data->latch);
+	sema_init(&data->write, 1);
+	data->tplug = inode_formatting_plugin(inode);
+	data->exclusive_use = 0;
+
+#if REISER4_DEBUG
+	data->ea_owner = NULL;
+	atomic_set(&data->nr_neas, 0);
+#endif
+	init_inode_ordering(inode, crd, create);
+}
+
+/**
+ * delete_object_unix_file - delete_object of file_plugin
+ * @inode: inode to be deleted
+ *
+ * Truncates file to length 0, removes stat data and safe link.
+ */
+int delete_object_unix_file(struct inode *inode)
+{
+	unix_file_info_t *uf_info;
+	int result;
+
+	/*
+	 * transaction can be open already. For example:
+	 * writeback_inodes->sync_sb_inodes->reiser4_sync_inodes->
+	 * generic_sync_sb_inodes->iput->generic_drop_inode->
+	 * generic_delete_inode->reiser4_delete_inode->delete_object_unix_file.
+	 * So, restart transaction to avoid deadlock with file rw semaphore.
+	 */
+	txn_restart_current();
+
+	if (inode_get_flag(inode, REISER4_NO_SD))
+		return 0;
+
+	/* truncate file bogy first */
+	uf_info = unix_file_inode_data(inode);
+	get_exclusive_access(uf_info);
+	result = truncate_file_body(inode, 0 /* size */ );
+	drop_exclusive_access(uf_info);
+
+	if (result)
+		warning("", "failed to truncate file (%llu) on removal: %d",
+			get_inode_oid(inode), result);
+
+	/* remove stat data and safe link */
+	return delete_object_common(inode);
+}
+
+/**
+ * sendfile_unix_file - sendfile of struct file_operations
+ * @file: file to be sent
+ * @ppos: position to start from
+ * @count: number of bytes to send
+ * @actor: function to copy data
+ * @target: where to copy read data
+ *
+ * Reads @count bytes from @file and calls @actor for every page read. This is
+ * needed for loop back devices support.
+ */
+ssize_t
+sendfile_unix_file(struct file *file, loff_t *ppos, size_t count,
+		   read_actor_t actor, void *target)
+{
+	reiser4_context *ctx;
+	ssize_t result;
+	struct inode *inode;
+	unix_file_info_t *uf_info;
+
+	inode = file->f_dentry->d_inode;
+	ctx = init_context(inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	/*
+	 * generic_file_sndfile may want to call update_atime. Grab space for
+	 * stat data update
+	 */
+	result = reiser4_grab_space(estimate_update_common(inode),
+				    BA_CAN_COMMIT);
+	if (result)
+		goto error;
+	mutex_lock(&inode->i_mutex);
+	inode_set_flag(inode, REISER4_HAS_MMAP);
+	mutex_unlock(&inode->i_mutex);
+
+	uf_info = unix_file_inode_data(inode);
+	get_nonexclusive_access(uf_info, 0);
+	result = generic_file_sendfile(file, ppos, count, actor, target);
+	drop_nonexclusive_access(uf_info);
+ error:
+	reiser4_exit_context(ctx);
+	return result;
+}
+
+int
+prepare_write_unix_file(struct file *file, struct page *page,
+			unsigned from, unsigned to)
+{
+	reiser4_context *ctx;
+	unix_file_info_t *uf_info;
+	int ret;
+
+	ctx = init_context(file->f_dentry->d_inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	uf_info = unix_file_inode_data(file->f_dentry->d_inode);
+	get_exclusive_access(uf_info);
+	ret = find_file_state(uf_info);
+	if (ret == 0) {
+		if (uf_info->container == UF_CONTAINER_TAILS)
+			ret = -EINVAL;
+		else
+			ret = do_prepare_write(file, page, from, to);
+	}
+	drop_exclusive_access(uf_info);
+
+	/* don't commit transaction under inode semaphore */
+	context_set_commit_async(ctx);
+	reiser4_exit_context(ctx);
+	return ret;
+}
+
+/*
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/file/file.h newtree/fs/reiser4/plugin/file/file.h
--- oldtree/fs/reiser4/plugin/file/file.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/file/file.h	2006-02-21 15:58:35.487751600 +0000
@@ -0,0 +1,230 @@
+/* Copyright 2001, 2002, 2003, 2004 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* this file contains declarations of methods implementing file plugins
+   (UNIX_FILE_PLUGIN_ID, SYMLINK_FILE_PLUGIN_ID and CRC_FILE_PLUGIN_ID) */
+
+#if !defined( __REISER4_FILE_H__ )
+#define __REISER4_FILE_H__
+
+/* declarations of functions implementing UNIX_FILE_PLUGIN_ID file plugin */
+
+/* inode operations */
+int setattr_unix_file(struct dentry *, struct iattr *);
+
+/* file operations */
+ssize_t read_unix_file(struct file *, char __user *buf, size_t read_amount,
+		       loff_t *off);
+ssize_t write_unix_file(struct file *, const char __user *buf, size_t write_amount,
+			loff_t * off);
+int ioctl_unix_file(struct inode *, struct file *, unsigned int cmd,
+		    unsigned long arg);
+int mmap_unix_file(struct file *, struct vm_area_struct *);
+int release_unix_file(struct inode *, struct file *);
+int sync_unix_file(struct file *, struct dentry *, int datasync);
+ssize_t sendfile_unix_file(struct file *, loff_t *ppos, size_t count,
+			   read_actor_t, void *target);
+
+/* address space operations */
+int readpage_unix_file(struct file *, struct page *);
+int readpage_unix_file_nolock(struct file *, struct page *);
+int writepages_unix_file(struct address_space *, struct writeback_control *);
+int prepare_write_unix_file(struct file *, struct page *, unsigned from,
+			    unsigned to);
+int commit_write_unix_file(struct file *, struct page *, unsigned from,
+			   unsigned to);
+sector_t bmap_unix_file(struct address_space *, sector_t lblock);
+
+/* file plugin operations */
+int flow_by_inode_unix_file(struct inode *, const char __user *buf,
+			    int user, loff_t, loff_t, rw_op, flow_t *);
+int owns_item_unix_file(const struct inode *, const coord_t *);
+void init_inode_data_unix_file(struct inode *, reiser4_object_create_data *,
+			       int create);
+int delete_object_unix_file(struct inode *);
+
+/*
+ * all the write into unix file is performed by item write method. Write method
+ * of unix file plugin only decides which item plugin (extent or tail) and in
+ * which mode (one from the enum below) to call
+ */
+typedef enum {
+	FIRST_ITEM = 1,
+	APPEND_ITEM = 2,
+	OVERWRITE_ITEM = 3
+} write_mode_t;
+
+/* unix file may be in one the following states */
+typedef enum {
+	UF_CONTAINER_UNKNOWN = 0,
+	UF_CONTAINER_TAILS = 1,
+	UF_CONTAINER_EXTENTS = 2,
+	UF_CONTAINER_EMPTY = 3
+} file_container_t;
+
+struct formatting_plugin;
+struct inode;
+
+/* unix file plugin specific part of reiser4 inode */
+typedef struct unix_file_info {
+	/*
+	 * this read-write lock protects file containerization change. Accesses
+	 * which do not change file containerization (see file_container_t)
+	 * (read, readpage, writepage, write (until tail conversion is
+	 * involved)) take read-lock. Accesses which modify file
+	 * containerization (truncate, conversion from tail to extent and back)
+	 * take write-lock.
+	 */
+	struct rw_semaphore latch;
+	/*
+	 * this semaphore is used to serialize writes instead of inode->i_mutex,
+	 * because write_unix_file uses get_user_pages which is to be used
+	 * under mm->mmap_sem and because it is required to take mm->mmap_sem
+	 * before inode->i_mutex, so inode->i_mutex would have to be unlocked
+	 * before calling to get_user_pages which is unacceptable
+	 */
+	struct semaphore write;
+	/* this enum specifies which items are used to build the file */
+	file_container_t container;
+	/*
+	 * plugin which controls when file is to be converted to extents and
+	 * back to tail
+	 */
+	struct formatting_plugin *tplug;
+	/* if this is set, file is in exclusive use */
+	int exclusive_use;
+#if REISER4_DEBUG
+	/* pointer to task struct of thread owning exclusive access to file */
+	void *ea_owner;
+	atomic_t nr_neas;
+	void *last_reader;
+#endif
+} unix_file_info_t;
+
+struct unix_file_info *unix_file_inode_data(const struct inode *inode);
+void get_exclusive_access(unix_file_info_t *);
+void drop_exclusive_access(unix_file_info_t *);
+void get_nonexclusive_access(unix_file_info_t *, int);
+void drop_nonexclusive_access(unix_file_info_t *);
+int try_to_get_nonexclusive_access(unix_file_info_t *);
+
+#include "../item/extent.h"
+#include "../item/tail.h"
+#include "../item/ctail.h"
+
+struct uf_coord {
+	coord_t coord;
+	lock_handle *lh;
+	int valid;
+	union {
+		extent_coord_extension_t extent;
+		tail_coord_extension_t tail;
+		ctail_coord_extension_t ctail;
+	} extension;
+};
+
+#include "../../forward.h"
+#include "../../seal.h"
+#include "../../lock.h"
+
+/*
+ * This structure is used to speed up file operations (reads and writes).  A
+ * hint is a suggestion about where a key resolved to last time.  A seal
+ * indicates whether a node has been modified since a hint was last recorded.
+ * You check the seal, and if the seal is still valid, you can use the hint
+ * without traversing the tree again.
+ */
+struct hint {
+	seal_t seal; /* a seal over last file item accessed */
+	uf_coord_t ext_coord;
+	loff_t offset;
+	znode_lock_mode mode;
+	lock_handle lh;
+};
+
+void set_hint(hint_t *, const reiser4_key *, znode_lock_mode);
+int hint_is_set(const hint_t *);
+void unset_hint(hint_t *);
+int hint_validate(hint_t *, const reiser4_key *, int check_key,
+		  znode_lock_mode);
+int update_file_size(struct inode *, reiser4_key *, int update_sd);
+int cut_file_items(struct inode *, loff_t new_size, int update_sd,
+		   loff_t cur_size, int (*update_actor) (struct inode *,
+							 reiser4_key *, int));
+
+
+#if REISER4_DEBUG
+
+/* return 1 is exclusive access is obtained, 0 - otherwise */
+static inline int ea_obtained(unix_file_info_t * uf_info)
+{
+	int ret;
+
+	ret = down_read_trylock(&uf_info->latch);
+	if (ret)
+		up_read(&uf_info->latch);
+	return !ret;
+}
+
+#endif
+
+/* declarations of functions implementing SYMLINK_FILE_PLUGIN_ID file plugin */
+int create_symlink(struct inode *symlink, struct inode *dir,
+		   reiser4_object_create_data *);
+void destroy_inode_symlink(struct inode *);
+
+/* declarations of functions implementing CRC_FILE_PLUGIN_ID file plugin */
+
+/* inode operations */
+int setattr_cryptcompress(struct dentry *, struct iattr *);
+
+/* file operations */
+ssize_t read_cryptcompress(struct file *, char __user *buf, size_t read_amount,
+			   loff_t * off);
+ssize_t write_cryptcompress(struct file *, const char __user *buf, size_t write_amount,
+			    loff_t * off);
+int mmap_cryptcompress(struct file *, struct vm_area_struct *);
+ssize_t sendfile_cryptcompress(struct file *file, loff_t *ppos, size_t count,
+			       read_actor_t actor, void *target);
+int release_cryptcompress(struct inode *, struct file *);
+
+/* address space operations */
+extern int readpage_cryptcompress(struct file *, struct page *);
+extern int writepages_cryptcompress(struct address_space *,
+				     struct writeback_control *);
+extern void readpages_cryptcompress(struct file *, struct address_space *,
+				    struct list_head *pages);
+extern sector_t bmap_cryptcompress(struct address_space *, sector_t lblock);
+
+
+/* file plugin operations */
+int flow_by_inode_cryptcompress(struct inode *, const char __user *buf,
+				int user, loff_t, loff_t, rw_op, flow_t *);
+int key_by_inode_cryptcompress(struct inode *, loff_t off, reiser4_key *);
+int create_cryptcompress(struct inode *, struct inode *,
+			 reiser4_object_create_data *);
+int delete_cryptcompress(struct inode *);
+void init_inode_data_cryptcompress(struct inode *, reiser4_object_create_data *,
+				   int create);
+int cut_tree_worker_cryptcompress(tap_t *, const reiser4_key * from_key,
+				  const reiser4_key * to_key,
+				  reiser4_key * smallest_removed,
+				  struct inode *object, int truncate,
+				  int *progress);
+void destroy_inode_cryptcompress(struct inode *);
+
+extern reiser4_plugin_ops cryptcompress_plugin_ops;
+
+/* __REISER4_FILE_H__ */
+#endif
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * scroll-step: 1
+ * End:
+*/
diff -urN oldtree/fs/reiser4/plugin/file/funcs.h newtree/fs/reiser4/plugin/file/funcs.h
--- oldtree/fs/reiser4/plugin/file/funcs.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/file/funcs.h	2006-02-21 15:58:34.999825776 +0000
@@ -0,0 +1,28 @@
+/* Copyright 2001, 2002, 2003, 2004 by Hans Reiser, licensing governed by reiser4/README */
+
+/* this prototypes functions used by both file.c and tail_conversion.c */
+void get_exclusive_access(unix_file_info_t *);
+void drop_exclusive_access(unix_file_info_t *);
+void get_nonexclusive_access(unix_file_info_t *, int);
+void drop_nonexclusive_access(unix_file_info_t *);
+
+int tail2extent(unix_file_info_t *);
+int extent2tail(unix_file_info_t *);
+int finish_conversion(struct inode *inode);
+
+void hint_init_zero(hint_t *);
+int find_file_item_nohint(coord_t *, lock_handle *, const reiser4_key *,
+			  znode_lock_mode, struct inode *);
+
+int goto_right_neighbor(coord_t *, lock_handle *);
+int find_or_create_extent(struct page *);
+write_mode_t how_to_write(uf_coord_t *, const reiser4_key *);
+#if REISER4_DEBUG
+int equal_to_ldk(znode *, const reiser4_key *);
+#endif
+
+extern inline int cbk_errored(int cbk_result)
+{
+	return (cbk_result != CBK_COORD_NOTFOUND
+		&& cbk_result != CBK_COORD_FOUND);
+}
diff -urN oldtree/fs/reiser4/plugin/file/invert.c newtree/fs/reiser4/plugin/file/invert.c
--- oldtree/fs/reiser4/plugin/file/invert.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/file/invert.c	2006-02-21 15:58:34.595887184 +0000
@@ -0,0 +1,493 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Suppose you want to conveniently read and write a large variety of small files conveniently within a single emacs
+   buffer, without having a separate buffer for each 8 byte or so file.  Inverts are the way to do that.  An invert
+   provides you with the contents of a set of subfiles plus its own contents.  It is a file which inherits other files
+   when you read it, and allows you to write to it and through it to the files that it inherits from.  In order for it
+   to know which subfiles each part of your write should go into, there must be delimiters indicating that.  It tries to
+   make that easy for you by providing those delimiters in what you read from it.
+
+  When you read it, an invert performs an inverted assignment.  Instead of taking an assignment command and writing a
+  bunch of files, it takes a bunch of files and composes an assignment command for you to read from it that if executed
+  would create those files.  But which files?  Well, that must be specified in the body of the invert using a special
+  syntax, and that specification is called the invert of the assignment.
+
+  When written to, an invert performs the assignment command that is written
+  to it, and modifies its own body to contain the invert of that
+  assignment.
+
+  In other words, writing to an invert file what you have read from it
+  is the identity operation.
+
+  Malformed assignments cause write errors.  Partial writes are not
+  supported in v4.0, but will be.
+
+  Example:
+
+    If an invert contains:
+
+    /filenameA/<>+"(some text stored in the invert)+/filenameB/<>
+
+======================
+Each element in this definition should be an invert, and all files
+should be called recursively - too.  This is bad. If one of the
+included files in not a regular or invert file, then we can't read
+main file.
+
+I think to make it is possible easier:
+
+internal structure of invert file should be like symlink file. But
+read and write method should be explitely indicated in i/o operation..
+
+By default we read and write (if probably) as symlink and if we
+specify ..invert at reading time that too we can specify it at write time.
+
+example:
+/my_invert_file/..invert<- ( (/filenameA<-"(The contents of filenameA))+"(some text stored in the invert)+(/filenameB<-"(The contents of filenameB) ) )
+will create  /my_invert_file as invert, and will creat /filenameA and /filenameB with specified body.
+
+read of /my_invert_file/..invert will be
+/filenameA<-"(The contents of filenameA)+"(some text stored in the invert)+/filenameB<-"(The contents of filenameB)
+
+but read of /my_invert_file/ will be
+The contents of filenameAsome text stored in the invertThe contents of filenameB
+
+we also can creat this file as
+/my_invert_file/<-/filenameA+"(some text stored in the invert)+/filenameB
+will create  /my_invert_file , and use existing files /filenameA and /filenameB.
+
+and when we will read it will be as previously invert file.
+
+This is correct?
+
+ vv
+DEMIDOV-FIXME-HANS:
+
+Maybe you are right, but then you must disable writes to /my_invert_file/ and only allow writes to /my_invert_file/..invert
+
+Do you agree?  Discuss it on reiserfs-list....
+
+-Hans
+=======================
+
+  Then a read will return:
+
+    /filenameA<-"(The contents of filenameA)+"(some text stored in the invert)+/filenameB<-"(The contents of filenameB)
+
+    and a write of the line above to the invert will set the contents of
+    the invert and filenameA and filenameB to their original values.
+
+  Note that the contents of an invert have no influence on the effect
+  of a write unless the write is a partial write (and a write of a
+  shorter file without using truncate first is a partial write).
+
+  truncate() has no effect on filenameA and filenameB, it merely
+  resets the value of the invert.
+
+  Writes to subfiles via the invert are implemented by preceding them
+  with truncates.
+
+  Parse failures cause write failures.
+
+  Questions to ponder: should the invert be acted on prior to file
+  close when writing to an open filedescriptor?
+
+ Example:
+
+ If an invert contains:
+
+   "(This text and a pair of quotes are all that is here.)
+
+Then a read will return:
+
+   "(This text and a pair of quotes are all that is here.)
+
+*/
+
+/* OPEN method places a struct file in memory associated with invert body
+  and returns something like file descriptor to the user for the future access
+  to the invert file.
+  During opening we parse the body of invert and get a list of the 'entryes'
+  (that describes all its subfiles) and place pointer on the first struct in
+  reiserfs-specific part of invert inode (arbitrary decision).
+
+  Each subfile is described by the struct inv_entry that has a pointer @sd on
+  in-core based stat-data and  a pointer on struct file @f (if we find that the
+  subfile uses more then one unformated node (arbitrary decision), we load
+  struct file in memory, otherwise we load base stat-data (and maybe 1-2 bytes
+  of some other information we need)
+
+  Since READ and WRITE methods for inverts were formulated in assignment
+  language, they don't contain arguments 'size' and 'offset' that make sense
+  only in ordinary read/write methods.
+
+  READ method is a combination of two methods:
+  1) ordinary read method (with offset=0, lenght = @f->...->i_size) for entries
+  with @f != 0, this method uses pointer on struct file as an argument
+  2) read method for inode-less files with @sd != 0, this method uses
+  in-core based stat-data instead struct file as an argument.
+  in the first case we don't use pagecache, just copy data that we got after
+  cbk() into userspace.
+
+  WRITE method for invert files is more complex.
+  Besides declared WRITE-interface in assignment languageb above we need
+  to have an opportunity to edit unwrapped body of invert file with some
+  text editor, it means we need GENERIC WRITE METHOD for invert file:
+
+  my_invert_file/..invert <- "string"
+
+  this method parses "string" and looks for correct subfile signatures, also
+  the parsing process splits this "string" on the set of flows in  accordance
+  with the set of subfiles specified by this signarure.
+  The found list of signatures #S is compared with the opened one #I of invert
+  file. If it doesn't have this one (#I==0, it will be so for instance if we
+  have just create this invert file) the write method assignes found signature
+  (#I=#S;) to the invert file. Then if #I==#S, generic write method splits
+  itself to the some write methods for ordinary or light-weight, or call itself
+  recursively for invert files with corresponding flows.
+  I am not sure, but the list of signatures looks like what mr.Demidov means
+  by 'delimiters'.
+
+  The cases when #S<#I (#I<#S) (in the sense of set-theory) are also available
+  and cause delete (create new) subfiles (arbitrary decision - it may looks
+  too complex, but this interface will be the completest). The order of entries
+  of list #S (#I) and inherited order on #I (#S) must coincide.
+  The other parsing results give malformed signature that aborts READ method
+  and releases all resources.
+
+  Format of subfile (entry) signature:
+
+  "START_MAGIC"<>(TYPE="...",LOOKUP_ARG="...")SUBFILE_BODY"END_MAGIC"
+
+  Legend:
+
+    START_MAGIC - keyword indicates the start of subfile signature;
+
+    <> indicates the start of 'subfile metadata', that is the pair
+  (TYPE="...",LOOKUP_ARG="...") in parenthesis separated by comma.
+
+    TYPE - the string "type" indicates the start of one of the three words:
+  - ORDINARY_FILE,
+  - LIGHT_WEIGHT_FILE,
+  - INVERT_FILE;
+
+    LOOKUP_ARG - lookup argument depends on previous type:
+  */
+
+ /************************************************************/
+ /*       TYPE        *          LOOKUP ARGUMENT             */
+ /************************************************************/
+ /* LIGH_WEIGHT_FILE  *           stat-data key              */
+ /************************************************************/
+ /*   ORDINARY_FILE   *             filename                 */
+ /************************************************************/
+ /*   INVERT_FILE     *             filename                 */
+ /************************************************************/
+
+ /* where:
+  *stat-data key - the string contains stat data key of this subfile, it will be
+  passed to fast-access lookup method for light-weight files;
+  *filename - pathname of this subfile, iyt well be passed to VFS lookup methods
+  for ordinary and invert files;
+
+  SUBFILE_BODY - data of this subfile (it will go to the flow)
+  END_MAGIC - the keyword indicates the end of subfile signature.
+
+  The other simbols inside the signature interpreted as 'unformatted content',
+  which is available with VFS's read_link() (arbitraruy decision).
+
+  NOTE: Parse method for a body of invert file uses mentioned signatures _without_
+  subfile bodies.
+
+  Now the only unclear thing is WRITE in regular light-weight subfile A that we
+  can describe only in  assignment language:
+
+  A <- "some_string"
+
+  I guess we don't want to change stat-data and body items of file A
+  if this file exist, and size(A) != size("some_string") because this operation is
+  expencive, so we only do the partial write if size(A) > size("some_string")
+  and do truncate of the "some_string", and then do A <- "truncated string", if
+  size(A) < size("some_string"). This decision is also arbitrary..
+  */
+
+/* here is infrastructure for formated flows */
+
+#define SUBFILE_HEADER_MAGIC 0x19196605
+#define FLOW_HEADER_MAGIC 0x01194304
+
+#include "../plugin.h"
+#include "../../debug.h"
+#include "../../forward.h"
+#include "../object.h"
+#include "../item/item.h"
+#include "../item/static_stat.h"
+#include "../../dformat.h"
+#include "../znode.h"
+#include "../inode.h"
+
+#include <linux/types.h>
+#include <linux/fs.h>		/* for struct file  */
+#include <linux/list.h>		/* for struct list_head */
+
+typedef enum {
+	LIGHT_WEIGHT_FILE,
+	ORDINARY_FILE,
+	INVERT_FILE
+} inv_entry_type;
+
+typedef struct flow_header {
+	d32 fl_magic;
+	d16 fl_nr;		/* number of subfiles in the flow */
+};
+
+typedef struct subfile_header {
+	d32 sh_magic;		/* subfile magic */
+	d16 sh_type;		/* type of subfile: light-weight, ordinary, invert */
+	d16 sh_arg_len;		/* lenght of lookup argument (filename, key) */
+	d32 sh_body_len;	/* lenght of subfile body */
+};
+
+/* functions to get/set fields of flow header */
+
+static void fl_set_magic(flow_header * fh, __u32 value)
+{
+	cputod32(value, &fh->fh_magic);
+}
+
+static __u32 fl_get_magic(flow_header * fh)
+{
+	return d32tocpu(&fh->fh_magic);
+}
+static void fl_set_number(flow_header * fh, __u16 value)
+{
+	cputod16(value, &fh->fh_nr);
+}
+static unsigned fl_get_number(flow_header * fh)
+{
+	return d16tocpu(&fh->fh_nr);
+}
+
+/* functions to get/set fields of subfile header */
+
+static void sh_set_magic(subfile_header * sh, __u32 value)
+{
+	cputod32(value, &sh->sh_magic);
+}
+
+static __u32 sh_get_magic(subfile_header * sh)
+{
+	return d32tocpu(&sh->sh_magic);
+}
+static void sh_set_type(subfile_header * sh, __u16 value)
+{
+	cputod16(value, &sh->sh_magic);
+}
+static unsigned sh_get_type(subfile_header * sh)
+{
+	return d16tocpu(&sh->sh_magic);
+}
+static void sh_set_arg_len(subfile_header * sh, __u16 value)
+{
+	cputod16(value, &sh->sh_arg_len);
+}
+static unsigned sh_get_arg_len(subfile_header * sh)
+{
+	return d16tocpu(&sh->sh_arg_len);
+}
+static void sh_set_body_len(subfile_header * sh, __u32 value)
+{
+	cputod32(value, &sh->sh_body_len);
+}
+
+static __u32 sh_get_body_len(subfile_header * sh)
+{
+	return d32tocpu(&sh->sh_body_len);
+}
+
+/* in-core minimal stat-data, light-weight analog of inode */
+
+struct incore_sd_base {
+	umode_t isd_mode;
+	nlink_t isd_nlink;
+	loff_t isd_size;
+	char *isd_data;		/* 'subflow' to write */
+};
+
+/* open invert create a list of invert entries,
+   every entry is represented by structure inv_entry */
+
+struct inv_entry {
+	struct list_head *ie_list;
+	struct file *ie_file;	/* this is NULL if the file doesn't
+				   have unformated nodes */
+	struct incore_sd_base *ie_sd;	/* inode-less analog of struct file */
+};
+
+/* allocate and init invert entry */
+
+static struct inv_entry *allocate_inv_entry(void)
+{
+	struct inv_entry *inv_entry;
+
+	inv_entry = reiser4_kmalloc(sizeof(struct inv_entry), GFP_KERNEL);
+	if (!inv_entry)
+		return ERR_PTR(RETERR(-ENOMEM));
+	inv_entry->ie_file = NULL;
+	inv_entry->ie_sd = NULL;
+	INIT_LIST_HEAD(&inv_entry->ie_list);
+	return inv_entry;
+}
+
+static int put_inv_entry(struct inv_entry *ientry)
+{
+	int result = 0;
+
+	assert("edward-96", ientry != NULL);
+	assert("edward-97", ientry->ie_list != NULL);
+
+	list_del(ientry->ie_list);
+	if (ientry->ie_sd != NULL) {
+		kfree(ientry->ie_sd);
+		kfree(ientry);
+	}
+	if (ientry->ie_file != NULL)
+		result = filp_close(ientry->file, NULL);
+	return result;
+}
+
+static int allocate_incore_sd_base(struct inv_entry *inv_entry)
+{
+	struct incore_sd_base *isd_base assert("edward-98", inv_entry != NULL);
+	assert("edward-99", inv_entry->ie_inode = NULL);
+	assert("edward-100", inv_entry->ie_sd = NULL);
+
+	isd_base = reiser4_kmalloc(sizeof(struct incore_sd_base), GFP_KERNEL);
+	if (!isd_base)
+		return RETERR(-ENOMEM);
+	inv_entry->ie_sd = isd_base;
+	return 0;
+}
+
+/* this can be installed as ->init_inv_entry () method of
+   item_plugins[ STATIC_STAT_DATA_IT ] (fs/reiser4/plugin/item/item.c).
+   Copies data from on-disk stat-data format into light-weight analog of inode .
+   Doesn't hanlde stat-data extensions. */
+
+static void sd_base_load(struct inv_entry *inv_entry, char *sd)
+{
+	reiser4_stat_data_base *sd_base;
+
+	assert("edward-101", inv_entry != NULL);
+	assert("edward-101", inv_entry->ie_sd != NULL);
+	assert("edward-102", sd != NULL);
+
+	sd_base = (reiser4_stat_data_base *) sd;
+	inv_entry->incore_sd_base->isd_mode = d16tocpu(&sd_base->mode);
+	inv_entry->incore_sd_base->isd_nlink = d32tocpu(&sd_base->nlink);
+	inv_entry->incore_sd_base->isd_size = d64tocpu(&sd_base->size);
+	inv_entry->incore_sd_base->isd_data = NULL;
+}
+
+/* initialise incore stat-data */
+
+static void init_incore_sd_base(struct inv_entry *inv_entry, coord_t * coord)
+{
+	reiser4_plugin *plugin = item_plugin_by_coord(coord);
+	void *body = item_body_by_coord(coord);
+
+	assert("edward-103", inv_entry != NULL);
+	assert("edward-104", plugin != NULL);
+	assert("edward-105", body != NULL);
+
+	sd_base_load(inv_entry, body);
+}
+
+/* takes a key or filename and allocates new invert_entry,
+   init and adds it into the list,
+   we use lookup_sd_by_key() for light-weight files and VFS lookup by filename */
+
+int get_inv_entry(struct inode *invert_inode,	/* inode of invert's body */
+		  inv_entry_type type,	/* LIGHT-WEIGHT or ORDINARY */
+		  const reiser4_key * key,	/* key of invert entry stat-data */
+		  char *filename,	/* filename of the file to be opened */
+		  int flags, int mode)
+{
+	int result;
+	struct inv_entry *ientry;
+
+	assert("edward-107", invert_inode != NULL);
+
+	ientry = allocate_inv_entry();
+	if (IS_ERR(ientry))
+		return (PTR_ERR(ientry));
+
+	if (type == LIGHT_WEIGHT_FILE) {
+		coord_t coord;
+		lock_handle lh;
+
+		assert("edward-108", key != NULL);
+
+		init_coord(&coord);
+		init_lh(&lh);
+		result =
+		    lookup_sd_by_key(tree_by_inode(invert_inode),
+				     ZNODE_READ_LOCK, &coord, &lh, key);
+		if (result == 0)
+			init_incore_sd_base(ientry, coord);
+
+		done_lh(&lh);
+		done_coord(&coord);
+		return (result);
+	} else {
+		struct file *file = filp_open(filename, flags, mode);
+		/* FIXME_EDWARD here we need to check if we
+		   did't follow to any mount point */
+
+		assert("edward-108", filename != NULL);
+
+		if (IS_ERR(file))
+			return (PTR_ERR(file));
+		ientry->ie_file = file;
+		return 0;
+	}
+}
+
+/* takes inode of invert, reads the body of this invert, parses it,
+   opens all invert entries and return pointer on the first inv_entry */
+
+struct inv_entry *open_invert(struct file *invert_file)
+{
+
+}
+
+ssize_t subfile_read(struct *invert_entry, flow * f)
+{
+
+}
+
+ssize_t subfile_write(struct *invert_entry, flow * f)
+{
+
+}
+
+ssize_t invert_read(struct *file, flow * f)
+{
+
+}
+
+ssize_t invert_write(struct *file, flow * f)
+{
+
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/file/symfile.c newtree/fs/reiser4/plugin/file/symfile.c
--- oldtree/fs/reiser4/plugin/file/symfile.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/file/symfile.c	2006-02-21 15:58:34.598886728 +0000
@@ -0,0 +1,87 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Symfiles are a generalization of Unix symlinks.
+
+   A symfile when read behaves as though you took its contents and
+   substituted them into the reiser4 naming system as the right hand side
+   of an assignment, and then read that which you had assigned to it.
+
+   A key issue for symfiles is how to implement writes through to
+   subfiles.  In general, one must have some method of determining what
+   of that which is written to the symfile is written to what subfile.
+   This can be done by use of custom plugin methods written by users, or
+   by using a few general methods we provide for those willing to endure
+   the insertion of delimiters into what is read.
+
+   Writing to symfiles without delimiters to denote what is written to
+   what subfile is not supported by any plugins we provide in this
+   release.  Our most sophisticated support for writes is that embodied
+   by the invert plugin (see invert.c).
+
+   A read only version of the /etc/passwd file might be
+   constructed as a symfile whose contents are as follows:
+
+   /etc/passwd/userlines/*
+
+   or
+
+   /etc/passwd/userlines/demidov+/etc/passwd/userlines/edward+/etc/passwd/userlines/reiser+/etc/passwd/userlines/root
+
+   or
+
+   /etc/passwd/userlines/(demidov+edward+reiser+root)
+
+   A symfile with contents
+
+   /filenameA+"(some text stored in the uninvertable symfile)+/filenameB
+
+   will return when read
+
+   The contents of filenameAsome text stored in the uninvertable symfileThe contents of filenameB
+
+   and write of what has been read will not be possible to implement as
+   an identity operation because there are no delimiters denoting the
+   boundaries of what is to be written to what subfile.
+
+   Note that one could make this a read/write symfile if one specified
+   delimiters, and the write method understood those delimiters delimited
+   what was written to subfiles.
+
+   So, specifying the symfile in a manner that allows writes:
+
+   /etc/passwd/userlines/demidov+"(
+   )+/etc/passwd/userlines/edward+"(
+   )+/etc/passwd/userlines/reiser+"(
+   )+/etc/passwd/userlines/root+"(
+   )
+
+   or
+
+   /etc/passwd/userlines/(demidov+"(
+   )+edward+"(
+   )+reiser+"(
+   )+root+"(
+   ))
+
+   and the file demidov might be specified as:
+
+   /etc/passwd/userlines/demidov/username+"(:)+/etc/passwd/userlines/demidov/password+"(:)+/etc/passwd/userlines/demidov/userid+"(:)+/etc/passwd/userlines/demidov/groupid+"(:)+/etc/passwd/userlines/demidov/gecos+"(:)+/etc/passwd/userlines/demidov/home+"(:)+/etc/passwd/userlines/demidov/shell
+
+   or
+
+   /etc/passwd/userlines/demidov/(username+"(:)+password+"(:)+userid+"(:)+groupid+"(:)+gecos+"(:)+home+"(:)+shell)
+
+   Notice that if the file demidov has a carriage return in it, the
+   parsing fails, but then if you put carriage returns in the wrong place
+   in a normal /etc/passwd file it breaks things also.
+
+   Note that it is forbidden to have no text between two interpolations
+   if one wants to be able to define what parts of a write go to what
+   subfiles referenced in an interpolation.
+
+   If one wants to be able to add new lines by writing to the file, one
+   must either write a custom plugin for /etc/passwd that knows how to
+   name an added line, or one must use an invert, or one must use a more
+   sophisticated symfile syntax that we are not planning to write for
+   version 4.0.
+*/
diff -urN oldtree/fs/reiser4/plugin/file/symlink.c newtree/fs/reiser4/plugin/file/symlink.c
--- oldtree/fs/reiser4/plugin/file/symlink.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/file/symlink.c	2006-02-21 15:58:34.599886576 +0000
@@ -0,0 +1,92 @@
+/* Copyright 2002, 2003, 2005 by Hans Reiser, licensing governed by reiser4/README */
+
+#include "../../inode.h"
+
+#include <linux/types.h>
+#include <linux/fs.h>
+
+/* file plugin methods specific for symlink files
+   (SYMLINK_FILE_PLUGIN_ID) */
+
+/* this is implementation of create_object method of file plugin for
+   SYMLINK_FILE_PLUGIN_ID
+ */
+
+/**
+ * create_symlink - create_object of file plugin for SYMLINK_FILE_PLUGIN_ID
+ * @symlink: inode of symlink object
+ * @dir: inode of parent directory
+ * @info:  parameters of new object
+ *
+ * Inserts stat data with symlink extension where into the tree.
+ */
+int create_symlink(struct inode *symlink,
+		   struct inode *dir UNUSED_ARG,
+		   reiser4_object_create_data *data	/* info passed to us,
+							 * this is filled by
+							 * reiser4() syscall
+							 * in particular */ )
+{
+	int result;
+
+	assert("nikita-680", symlink != NULL);
+	assert("nikita-681", S_ISLNK(symlink->i_mode));
+	assert("nikita-685", inode_get_flag(symlink, REISER4_NO_SD));
+	assert("nikita-682", dir != NULL);
+	assert("nikita-684", data != NULL);
+	assert("nikita-686", data->id == SYMLINK_FILE_PLUGIN_ID);
+
+	/*
+	 * stat data of symlink has symlink extension in which we store
+	 * symlink content, that is, path symlink is pointing to.
+	 */
+	reiser4_inode_data(symlink)->extmask |= (1 << SYMLINK_STAT);
+
+	assert("vs-838", symlink->u.generic_ip == NULL);
+	symlink->u.generic_ip = (void *)data->name;
+
+	assert("vs-843", symlink->i_size == 0);
+	INODE_SET_FIELD(symlink, i_size, strlen(data->name));
+
+	/* insert stat data appended with data->name */
+	result = inode_file_plugin(symlink)->write_sd_by_inode(symlink);
+	if (result) {
+		/* FIXME-VS: Make sure that symlink->u.generic_ip is not attached
+		   to kmalloced data */
+		INODE_SET_FIELD(symlink, i_size, 0);
+	} else {
+		assert("vs-849", symlink->u.generic_ip
+		       && inode_get_flag(symlink, REISER4_GENERIC_PTR_USED));
+		assert("vs-850",
+		       !memcmp((char *)symlink->u.generic_ip, data->name,
+			       (size_t) symlink->i_size + 1));
+	}
+	return result;
+}
+
+/* this is implementation of destroy_inode method of file plugin for
+   SYMLINK_FILE_PLUGIN_ID
+ */
+void destroy_inode_symlink(struct inode *inode)
+{
+	assert("edward-799",
+	       inode_file_plugin(inode) ==
+	       file_plugin_by_id(SYMLINK_FILE_PLUGIN_ID));
+	assert("edward-800", !is_bad_inode(inode) && is_inode_loaded(inode));
+	assert("edward-801", inode_get_flag(inode, REISER4_GENERIC_PTR_USED));
+	assert("vs-839", S_ISLNK(inode->i_mode));
+
+	kfree(inode->u.generic_ip);
+	inode->u.generic_ip = NULL;
+	inode_clr_flag(inode, REISER4_GENERIC_PTR_USED);
+}
+
+/* Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/file/tail_conversion.c newtree/fs/reiser4/plugin/file/tail_conversion.c
--- oldtree/fs/reiser4/plugin/file/tail_conversion.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/file/tail_conversion.c	2006-02-21 15:58:35.448757528 +0000
@@ -0,0 +1,802 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#include "../../inode.h"
+#include "../../super.h"
+#include "../../page_cache.h"
+#include "../../carry.h"
+#include "../../safe_link.h"
+#include "../../vfs_ops.h"
+#include "funcs.h"
+
+#include <linux/writeback.h>
+
+/* this file contains:
+   tail2extent and extent2tail */
+
+/* exclusive access to a file is acquired when file state changes: tail2extent, empty2tail, extent2tail, etc */
+void get_exclusive_access(unix_file_info_t * uf_info)
+{
+	assert("nikita-3028", schedulable());
+	assert("nikita-3047", LOCK_CNT_NIL(inode_sem_w));
+	assert("nikita-3048", LOCK_CNT_NIL(inode_sem_r));
+	/*
+	 * "deadlock detection": sometimes we commit a transaction under
+	 * rw-semaphore on a file. Such commit can deadlock with another
+	 * thread that captured some block (hence preventing atom from being
+	 * committed) and waits on rw-semaphore.
+	 */
+	assert("nikita-3361", get_current_context()->trans->atom == NULL);
+	BUG_ON(get_current_context()->trans->atom != NULL);
+	LOCK_CNT_INC(inode_sem_w);
+	down_write(&uf_info->latch);
+	uf_info->exclusive_use = 1;
+	assert("vs-1713", uf_info->ea_owner == NULL);
+	assert("vs-1713", atomic_read(&uf_info->nr_neas) == 0);
+	ON_DEBUG(uf_info->ea_owner = current);
+}
+
+void drop_exclusive_access(unix_file_info_t * uf_info)
+{
+	assert("vs-1714", uf_info->ea_owner == current);
+	assert("vs-1715", atomic_read(&uf_info->nr_neas) == 0);
+	ON_DEBUG(uf_info->ea_owner = NULL);
+	uf_info->exclusive_use = 0;
+	up_write(&uf_info->latch);
+	assert("nikita-3049", LOCK_CNT_NIL(inode_sem_r));
+	assert("nikita-3049", LOCK_CNT_GTZ(inode_sem_w));
+	LOCK_CNT_DEC(inode_sem_w);
+}
+
+/**
+ * nea_grabbed - do something when file semaphore is down_read-ed
+ * @uf_info:
+ *
+ * This is called when nonexclisive access is obtained on file. All it does is
+ * for debugging purposes.
+ */
+static void nea_grabbed(unix_file_info_t *uf_info)
+{
+#if REISER4_DEBUG
+	LOCK_CNT_INC(inode_sem_r);
+	assert("vs-1716", uf_info->ea_owner == NULL);
+	atomic_inc(&uf_info->nr_neas);
+	uf_info->last_reader = current;
+#endif
+}
+
+/**
+ * get_nonexclusive_access - get nonexclusive access to a file
+ * @uf_info: unix file specific part of inode to obtain access to
+ *
+ * Nonexclusive access is obtained on a file before read, write, readpage.
+ */
+void get_nonexclusive_access(unix_file_info_t *uf_info, int atom_may_exist)
+{
+	assert("nikita-3029", schedulable());
+	/* unix_file_filemap_nopage may call this when current atom exist already */
+	assert("nikita-3361",
+	       ergo(atom_may_exist == 0,
+		    get_current_context()->trans->atom == NULL));
+	BUG_ON(atom_may_exist == 0
+	       && get_current_context()->trans->atom != NULL);
+
+	down_read(&uf_info->latch);
+
+	nea_grabbed(uf_info);
+}
+
+/**
+ * try_to_get_nonexclusive_access - try to get nonexclusive access to a file
+ * @uf_info: unix file specific part of inode to obtain access to
+ *
+ * Non-blocking version of nonexclusive access obtaining.
+ */
+int try_to_get_nonexclusive_access(unix_file_info_t *uf_info)
+{
+	int result;
+
+	result = down_read_trylock(&uf_info->latch);
+	if (result)
+		nea_grabbed(uf_info);
+	return result;
+}
+
+void drop_nonexclusive_access(unix_file_info_t * uf_info)
+{
+	assert("vs-1718", uf_info->ea_owner == NULL);
+	assert("vs-1719", atomic_read(&uf_info->nr_neas) > 0);
+	ON_DEBUG(atomic_dec(&uf_info->nr_neas));
+
+	up_read(&uf_info->latch);
+
+	LOCK_CNT_DEC(inode_sem_r);
+}
+
+/* part of tail2extent. Cut all items covering @count bytes starting from
+   @offset */
+/* Audited by: green(2002.06.15) */
+static int cut_formatting_items(struct inode *inode, loff_t offset, int count)
+{
+	reiser4_key from, to;
+
+	/* AUDIT: How about putting an assertion here, what would check
+	   all provided range is covered by tail items only? */
+	/* key of first byte in the range to be cut  */
+	inode_file_plugin(inode)->key_by_inode(inode, offset, &from);
+
+	/* key of last byte in that range */
+	to = from;
+	set_key_offset(&to, (__u64) (offset + count - 1));
+
+	/* cut everything between those keys */
+	return cut_tree(tree_by_inode(inode), &from, &to, inode, 0);
+}
+
+static void release_all_pages(struct page **pages, unsigned nr_pages)
+{
+	unsigned i;
+
+	for (i = 0; i < nr_pages; i++) {
+		if (pages[i] == NULL) {
+			unsigned j;
+			for (j = i + 1; j < nr_pages; j++)
+				assert("vs-1620", pages[j] == NULL);
+			break;
+		}
+		page_cache_release(pages[i]);
+		pages[i] = NULL;
+	}
+}
+
+/* part of tail2extent. replace tail items with extent one. Content of tail
+   items (@count bytes) being cut are copied already into
+   pages. extent_writepage method is called to create extents corresponding to
+   those pages */
+static int
+replace(struct inode *inode, struct page **pages, unsigned nr_pages, int count)
+{
+	int result;
+	unsigned i;
+	STORE_COUNTERS;
+
+	if (nr_pages == 0)
+		return 0;
+
+	assert("vs-596", pages[0]);
+
+	/* cut copied items */
+	result =
+	    cut_formatting_items(inode,
+				 (loff_t) pages[0]->index << PAGE_CACHE_SHIFT,
+				 count);
+	if (result)
+		return result;
+
+	CHECK_COUNTERS;
+
+	/* put into tree replacement for just removed items: extent item, namely */
+	for (i = 0; i < nr_pages; i++) {
+		result = add_to_page_cache_lru(pages[i], inode->i_mapping,
+					       pages[i]->index,
+					       mapping_gfp_mask(inode->
+								i_mapping));
+		if (result)
+			break;
+		unlock_page(pages[i]);
+		result = find_or_create_extent(pages[i]);
+		if (result)
+			break;
+		SetPageUptodate(pages[i]);
+	}
+	return result;
+}
+
+#define TAIL2EXTENT_PAGE_NUM 3	/* number of pages to fill before cutting tail
+				 * items */
+
+static int reserve_tail2extent_iteration(struct inode *inode)
+{
+	reiser4_block_nr unformatted_nodes;
+	reiser4_tree *tree;
+
+	tree = tree_by_inode(inode);
+
+	/* number of unformatted nodes which will be created */
+	unformatted_nodes = TAIL2EXTENT_PAGE_NUM;
+
+	/*
+	 * space required for one iteration of extent->tail conversion:
+	 *
+	 *     1. kill N tail items
+	 *
+	 *     2. insert TAIL2EXTENT_PAGE_NUM unformatted nodes
+	 *
+	 *     3. insert TAIL2EXTENT_PAGE_NUM (worst-case single-block
+	 *     extents) extent units.
+	 *
+	 *     4. drilling to the leaf level by coord_by_key()
+	 *
+	 *     5. possible update of stat-data
+	 *
+	 */
+	grab_space_enable();
+	return reiser4_grab_space
+	    (2 * tree->height +
+	     TAIL2EXTENT_PAGE_NUM +
+	     TAIL2EXTENT_PAGE_NUM * estimate_one_insert_into_item(tree) +
+	     1 + estimate_one_insert_item(tree) +
+	     inode_file_plugin(inode)->estimate.update(inode), BA_CAN_COMMIT);
+}
+
+/* this is used by tail2extent and extent2tail to detect where previous uncompleted conversion stopped */
+static int
+find_start(struct inode *object, reiser4_plugin_id id, __u64 * offset)
+{
+	int result;
+	lock_handle lh;
+	coord_t coord;
+	unix_file_info_t *ufo;
+	int found;
+	reiser4_key key;
+
+	ufo = unix_file_inode_data(object);
+	init_lh(&lh);
+	result = 0;
+	found = 0;
+	inode_file_plugin(object)->key_by_inode(object, *offset, &key);
+	do {
+		init_lh(&lh);
+		result = find_file_item_nohint(&coord, &lh, &key,
+					       ZNODE_READ_LOCK, object);
+
+		if (result == CBK_COORD_FOUND) {
+			if (coord.between == AT_UNIT) {
+				/*coord_clear_iplug(&coord); */
+				result = zload(coord.node);
+				if (result == 0) {
+					if (item_id_by_coord(&coord) == id)
+						found = 1;
+					else
+						item_plugin_by_coord(&coord)->s.
+						    file.append_key(&coord,
+								    &key);
+					zrelse(coord.node);
+				}
+			} else
+				result = RETERR(-ENOENT);
+		}
+		done_lh(&lh);
+	} while (result == 0 && !found);
+	*offset = get_key_offset(&key);
+	return result;
+}
+
+/* clear stat data's flag indicating that conversion is being converted */
+static int complete_conversion(struct inode *inode)
+{
+	int result;
+
+	all_grabbed2free();
+	grab_space_enable();
+	result =
+	    reiser4_grab_space(inode_file_plugin(inode)->estimate.update(inode),
+			       BA_CAN_COMMIT);
+	if (result == 0) {
+		inode_clr_flag(inode, REISER4_PART_CONV);
+		result = reiser4_update_sd(inode);
+	}
+	if (result)
+		warning("vs-1696", "Failed to clear converting bit of %llu: %i",
+			(unsigned long long)get_inode_oid(inode), result);
+	return 0;
+}
+
+int tail2extent(unix_file_info_t * uf_info)
+{
+	int result;
+	reiser4_key key;	/* key of next byte to be moved to page */
+	ON_DEBUG(reiser4_key tmp;
+	    )
+	char *p_data;		/* data of page */
+	unsigned page_off = 0,	/* offset within the page where to copy data */
+	    count;		/* number of bytes of item which can be
+				 * copied to page */
+	struct page *pages[TAIL2EXTENT_PAGE_NUM];
+	struct page *page;
+	int done;		/* set to 1 when all file is read */
+	char *item;
+	int i;
+	struct inode *inode;
+	__u64 offset;
+	int first_iteration;
+	int bytes;
+
+	assert("nikita-3362", ea_obtained(uf_info));
+	inode = unix_file_info_to_inode(uf_info);
+	assert("nikita-3412", !IS_RDONLY(inode));
+	assert("vs-1649", uf_info->container != UF_CONTAINER_EXTENTS);
+
+	offset = 0;
+	if (inode_get_flag(inode, REISER4_PART_CONV)) {
+		/* find_start() doesn't need block reservation */
+		result = find_start(inode, FORMATTING_ID, &offset);
+		if (result == -ENOENT) {
+			/* no tail items found, everything is converted */
+			uf_info->container = UF_CONTAINER_EXTENTS;
+			complete_conversion(inode);
+			return 0;
+		} else if (result != 0)
+			/* some other error */
+			return result;
+	}
+
+	/* get key of first byte of a file */
+	inode_file_plugin(inode)->key_by_inode(inode, offset, &key);
+
+	done = 0;
+	result = 0;
+	first_iteration = 1;
+	while (done == 0) {
+		memset(pages, 0, sizeof(pages));
+		all_grabbed2free();
+		result = reserve_tail2extent_iteration(inode);
+		if (result != 0)
+			goto out;
+		if (first_iteration) {
+			inode_set_flag(inode, REISER4_PART_CONV);
+			reiser4_update_sd(inode);
+			first_iteration = 0;
+		}
+		bytes = 0;
+		for (i = 0; i < sizeof_array(pages) && done == 0; i++) {
+			assert("vs-598",
+			       (get_key_offset(&key) & ~PAGE_CACHE_MASK) == 0);
+			page = alloc_page(mapping_gfp_mask(inode->i_mapping));
+			if (!page) {
+				result = RETERR(-ENOMEM);
+				goto error;
+			}
+
+			page->index =
+			    (unsigned long)(get_key_offset(&key) >>
+					    PAGE_CACHE_SHIFT);
+			/* usually when one is going to longterm lock znode (as
+			   find_file_item does, for instance) he must not hold
+			   locked pages. However, there is an exception for
+			   case tail2extent. Pages appearing here are not
+			   reachable to everyone else, they are clean, they do
+			   not have jnodes attached so keeping them locked do
+			   not risk deadlock appearance
+			 */
+			assert("vs-983", !PagePrivate(page));
+			reiser4_invalidate_pages(inode->i_mapping, page->index,
+						 1, 0);
+			for (page_off = 0; page_off < PAGE_CACHE_SIZE;) {
+				coord_t coord;
+				lock_handle lh;
+
+				/* get next item */
+				/* FIXME: we might want to readahead here */
+				init_lh(&lh);
+				result =
+				    find_file_item_nohint(&coord, &lh, &key,
+							  ZNODE_READ_LOCK,
+							  inode);
+				if (cbk_errored(result)
+				    || result == CBK_COORD_NOTFOUND) {
+					/* error happened of not items of file were found */
+					done_lh(&lh);
+					page_cache_release(page);
+					goto error;
+				}
+
+				if (coord.between == AFTER_UNIT) {
+					/* this is used to detect end of file when inode->i_size can not be used */
+					done_lh(&lh);
+					done = 1;
+					p_data = kmap_atomic(page, KM_USER0);
+					memset(p_data + page_off, 0,
+					       PAGE_CACHE_SIZE - page_off);
+					kunmap_atomic(p_data, KM_USER0);
+					break;
+				}
+
+				result = zload(coord.node);
+				if (result) {
+					page_cache_release(page);
+					done_lh(&lh);
+					goto error;
+				}
+				assert("vs-562",
+				       owns_item_unix_file(inode, &coord));
+				assert("vs-856", coord.between == AT_UNIT);
+				assert("green-11",
+				       keyeq(&key,
+					     unit_key_by_coord(&coord, &tmp)));
+				item =
+				    ((char *)item_body_by_coord(&coord)) +
+				    coord.unit_pos;
+
+				/* how many bytes to copy */
+				count =
+				    item_length_by_coord(&coord) -
+				    coord.unit_pos;
+				/* limit length of copy to end of page */
+				if (count > PAGE_CACHE_SIZE - page_off)
+					count = PAGE_CACHE_SIZE - page_off;
+
+				/* kmap/kunmap are necessary for pages which are not addressable by direct kernel
+				   virtual addresses */
+				p_data = kmap_atomic(page, KM_USER0);
+				/* copy item (as much as will fit starting from the beginning of the item) into the
+				   page */
+				memcpy(p_data + page_off, item,
+				       (unsigned)count);
+				kunmap_atomic(p_data, KM_USER0);
+
+				page_off += count;
+				bytes += count;
+				set_key_offset(&key,
+					       get_key_offset(&key) + count);
+
+				zrelse(coord.node);
+				done_lh(&lh);
+			}	/* end of loop which fills one page by content of formatting items */
+
+			if (page_off) {
+				/* something was copied into page */
+				pages[i] = page;
+			} else {
+				page_cache_release(page);
+				assert("vs-1648", done == 1);
+				break;
+			}
+		}		/* end of loop through pages of one conversion iteration */
+
+		if (i > 0) {
+			result = replace(inode, pages, i, bytes);
+			release_all_pages(pages, sizeof_array(pages));
+			if (result)
+				goto error;
+			/* we have to drop exclusive access to avoid deadlock
+			 * which may happen because called by
+			 * reiser4_writepages capture_unix_file requires to get
+			 * non-exclusive access to a file. It is safe to drop
+			 * EA in the middle of tail2extent conversion because
+			 * write_unix_file/unix_setattr(truncate)/release_unix_file(extent2tail)
+			 * are serialized by uf_info->write semaphore and
+			 * because read_unix_file works (should at least) on
+			 * partially converted files */
+			drop_exclusive_access(uf_info);
+			/* throttle the conversion */
+			reiser4_throttle_write(inode);
+			get_exclusive_access(uf_info);
+		}
+	}
+
+	if (result == 0) {
+		/* file is converted to extent items */
+		assert("vs-1697", inode_get_flag(inode, REISER4_PART_CONV));
+
+		uf_info->container = UF_CONTAINER_EXTENTS;
+		complete_conversion(inode);
+	} else {
+		/* conversion is not complete. Inode was already marked as
+		 * REISER4_PART_CONV and stat-data were updated at the first
+		 * iteration of the loop above. */
+	      error:
+		release_all_pages(pages, sizeof_array(pages));
+		warning("nikita-2282", "Partial conversion of %llu: %i",
+			(unsigned long long)get_inode_oid(inode), result);
+	}
+
+      out:
+	all_grabbed2free();
+	return result;
+}
+
+/* part of extent2tail. Page contains data which are to be put into tree by
+   tail items. Use tail_write for this. flow is composed like in
+   unix_file_write. The only difference is that data for writing are in
+   kernel space */
+/* Audited by: green(2002.06.15) */
+static int
+write_page_by_tail(struct inode *inode, struct page *page, unsigned count)
+{
+	flow_t f;
+	hint_t *hint;
+	lock_handle *lh;
+	coord_t *coord;
+	znode *loaded;
+	item_plugin *iplug;
+	int result;
+
+	result = 0;
+
+	assert("vs-1089", count);
+	assert("vs-1647",
+	       inode_file_plugin(inode)->flow_by_inode ==
+	       flow_by_inode_unix_file);
+
+	hint = kmalloc(sizeof(*hint), GFP_KERNEL);
+	if (hint == NULL)
+		return RETERR(-ENOMEM);
+	hint_init_zero(hint);
+	lh = &hint->lh;
+
+	/* build flow */
+	/* FIXME: do not kmap here */
+	flow_by_inode_unix_file(inode, (char __user *)kmap(page), 0 /* not user space */ ,
+				count,
+				(loff_t) (page->index << PAGE_CACHE_SHIFT),
+				WRITE_OP, &f);
+	iplug = item_plugin_by_id(FORMATTING_ID);
+
+	coord = &hint->ext_coord.coord;
+	while (f.length) {
+		result =
+		    find_file_item_nohint(coord, lh, &f.key, ZNODE_WRITE_LOCK,
+					  inode);
+		if (IS_CBKERR(result))
+			break;
+
+		assert("vs-957",
+		       ergo(result == CBK_COORD_NOTFOUND,
+			    get_key_offset(&f.key) == 0));
+		assert("vs-958",
+		       ergo(result == CBK_COORD_FOUND,
+			    get_key_offset(&f.key) != 0));
+
+		result = zload(coord->node);
+		if (result)
+			break;
+		loaded = coord->node;
+
+		result =
+		    iplug->s.file.write(inode, &f, hint, 1 /*grabbed */ ,
+					how_to_write(&hint->ext_coord, &f.key));
+		zrelse(loaded);
+		done_lh(lh);
+
+		if (result == -E_REPEAT)
+			result = 0;
+		else if (result)
+			break;
+	}
+
+	done_lh(lh);
+	kfree(hint);
+	kunmap(page);
+
+	/* result of write is 0 or error */
+	assert("vs-589", result <= 0);
+	/* if result is 0 - all @count bytes is written completely */
+	assert("vs-588", ergo(result == 0, f.length == 0));
+	return result;
+}
+
+static int reserve_extent2tail_iteration(struct inode *inode)
+{
+	reiser4_tree *tree;
+
+	tree = tree_by_inode(inode);
+	/*
+	 * reserve blocks for (in this order):
+	 *
+	 *     1. removal of extent item
+	 *
+	 *     2. insertion of tail by insert_flow()
+	 *
+	 *     3. drilling to the leaf level by coord_by_key()
+	 *
+	 *     4. possible update of stat-data
+	 */
+	grab_space_enable();
+	return reiser4_grab_space
+	    (estimate_one_item_removal(tree) +
+	     estimate_insert_flow(tree->height) +
+	     1 + estimate_one_insert_item(tree) +
+	     inode_file_plugin(inode)->estimate.update(inode), BA_CAN_COMMIT);
+}
+
+static int filler(void *vp, struct page *page)
+{
+	return readpage_unix_file_nolock(vp, page);
+}
+
+/* for every page of file: read page, cut part of extent pointing to this page,
+   put data of page tree by tail item */
+int extent2tail(unix_file_info_t * uf_info)
+{
+	int result;
+	struct inode *inode;
+	struct page *page;
+	unsigned long num_pages, i;
+	unsigned long start_page;
+	reiser4_key from;
+	reiser4_key to;
+	unsigned count;
+	__u64 offset;
+
+	assert("nikita-3362", ea_obtained(uf_info));
+	inode = unix_file_info_to_inode(uf_info);
+	assert("nikita-3412", !IS_RDONLY(inode));
+	assert("vs-1649", uf_info->container != UF_CONTAINER_TAILS);
+
+	offset = 0;
+	if (inode_get_flag(inode, REISER4_PART_CONV)) {
+		/* find_start() doesn't need block reservation */
+		result = find_start(inode, EXTENT_POINTER_ID, &offset);
+		if (result == -ENOENT) {
+			/* no extent found, everything is converted */
+			uf_info->container = UF_CONTAINER_TAILS;
+			complete_conversion(inode);
+			return 0;
+		} else if (result != 0)
+			/* some other error */
+			return result;
+	}
+
+	/* number of pages in the file */
+	num_pages =
+	    (inode->i_size - offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	start_page = offset >> PAGE_CACHE_SHIFT;
+
+	inode_file_plugin(inode)->key_by_inode(inode, offset, &from);
+	to = from;
+
+	result = 0;
+	for (i = 0; i < num_pages; i++) {
+		__u64 start_byte;
+
+		all_grabbed2free();
+		result = reserve_extent2tail_iteration(inode);
+		if (result != 0)
+			break;
+		if (i == 0) {
+			inode_set_flag(inode, REISER4_PART_CONV);
+			reiser4_update_sd(inode);
+		}
+
+		page = read_cache_page(inode->i_mapping,
+				       (unsigned)(i + start_page), filler, NULL);
+		if (IS_ERR(page)) {
+			result = PTR_ERR(page);
+			break;
+		}
+
+		wait_on_page_locked(page);
+
+		if (!PageUptodate(page)) {
+			page_cache_release(page);
+			result = RETERR(-EIO);
+			break;
+		}
+
+		/* cut part of file we have read */
+		start_byte = (__u64) (i << PAGE_CACHE_SHIFT) + offset;
+		set_key_offset(&from, start_byte);
+		set_key_offset(&to, start_byte + PAGE_CACHE_SIZE - 1);
+		/*
+		 * cut_tree_object() returns -E_REPEAT to allow atom
+		 * commits during over-long truncates. But
+		 * extent->tail conversion should be performed in one
+		 * transaction.
+		 */
+		result = cut_tree(tree_by_inode(inode), &from, &to, inode, 0);
+
+		if (result) {
+			page_cache_release(page);
+			break;
+		}
+
+		/* put page data into tree via tail_write */
+		count = PAGE_CACHE_SIZE;
+		if (i == num_pages - 1)
+			count =
+			    (inode->
+			     i_size & ~PAGE_CACHE_MASK) ? : PAGE_CACHE_SIZE;
+		result = write_page_by_tail(inode, page, count);
+		if (result) {
+			page_cache_release(page);
+			break;
+		}
+
+		/* release page */
+		lock_page(page);
+		/* page is already detached from jnode and mapping. */
+		assert("vs-1086", page->mapping == NULL);
+		assert("nikita-2690",
+		       (!PagePrivate(page) && jprivate(page) == 0));
+		/* waiting for writeback completion with page lock held is
+		 * perfectly valid. */
+		wait_on_page_writeback(page);
+		drop_page(page);
+		/* release reference taken by read_cache_page() above */
+		page_cache_release(page);
+	}
+
+	if (i == num_pages) {
+		/* file is converted to formatted items */
+		assert("vs-1698", inode_get_flag(inode, REISER4_PART_CONV));
+		assert("vs-1260",
+		       inode_has_no_jnodes(reiser4_inode_data(inode)));
+
+		uf_info->container = UF_CONTAINER_TAILS;
+		complete_conversion(inode);
+	} else {
+		/* conversion is not complete. Inode was already marked as
+		 * REISER4_PART_CONV and stat-data were updated at the first
+		 * iteration of the loop above. */
+		warning("nikita-2282",
+			"Partial conversion of %llu: %lu of %lu: %i",
+			(unsigned long long)get_inode_oid(inode), i,
+			num_pages, result);
+	}
+	all_grabbed2free();
+	return result;
+}
+
+/* this is used to find which conversion did not complete */
+static int find_first_item(struct inode *inode)
+{
+	coord_t coord;
+	lock_handle lh;
+	reiser4_key key;
+	int result;
+
+	coord_init_zero(&coord);
+	init_lh(&lh);
+	inode_file_plugin(inode)->key_by_inode(inode, 0, &key);
+	result =
+	    find_file_item_nohint(&coord, &lh, &key, ZNODE_READ_LOCK, inode);
+	if (result == CBK_COORD_FOUND) {
+		if (coord.between == AT_UNIT) {
+			/*coord_clear_iplug(&coord); */
+			result = zload(coord.node);
+			if (result == 0) {
+				result = item_id_by_coord(&coord);
+				zrelse(coord.node);
+				if (result != EXTENT_POINTER_ID
+				    && result != FORMATTING_ID)
+					result = RETERR(-EIO);
+			}
+		} else
+			result = RETERR(-EIO);
+	}
+	done_lh(&lh);
+	return result;
+}
+
+/* exclusive access is obtained. File may be "partially converted" - that is file body may have both formatting and
+   extent items. Find which conversion did not completed and complete */
+int finish_conversion(struct inode *inode)
+{
+	int result;
+
+	if (inode_get_flag(inode, REISER4_PART_CONV)) {
+		result = find_first_item(inode);
+		if (result == EXTENT_POINTER_ID)
+			/* first item is extent, therefore there was incomplete tail2extent conversion. Complete it */
+			result = tail2extent(unix_file_inode_data(inode));
+		else if (result == FORMATTING_ID)
+			/* first item is formatting item, therefore there was incomplete extent2tail
+			   conversion. Complete it */
+			result = extent2tail(unix_file_inode_data(inode));
+	} else
+		result = 0;
+	assert("vs-1712",
+	       ergo(result == 0, !inode_get_flag(inode, REISER4_PART_CONV)));
+	return result;
+}
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * scroll-step: 1
+ * End:
+ */
diff -urN oldtree/fs/reiser4/plugin/file_ops.c newtree/fs/reiser4/plugin/file_ops.c
--- oldtree/fs/reiser4/plugin/file_ops.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/file_ops.c	2006-02-21 15:58:34.999825776 +0000
@@ -0,0 +1,165 @@
+/* Copyright 2005 by Hans Reiser, licensing governed by
+   reiser4/README */
+
+/* this file contains typical implementations for some of methods of
+   struct file_operations and of struct address_space_operations
+*/
+
+#include "../inode.h"
+#include "object.h"
+
+/* file operations */
+
+/* implementation of vfs's llseek method of struct file_operations for
+   typical directory can be found in readdir_common.c
+*/
+loff_t llseek_common_dir(struct file *, loff_t, int origin);
+
+/* implementation of vfs's readdir method of struct file_operations for
+   typical directory can be found in readdir_common.c
+*/
+int readdir_common(struct file *, void *dirent, filldir_t);
+
+/**
+ * release_dir_common - release of struct file_operations
+ * @inode: inode of released file
+ * @file: file to release
+ *
+ * Implementation of release method of struct file_operations for typical
+ * directory. All it does is freeing of reiser4 specific file data.
+*/
+int release_dir_common(struct inode *inode, struct file *file)
+{
+	reiser4_context *ctx;
+
+	ctx = init_context(inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+	reiser4_free_file_fsdata(file);
+	reiser4_exit_context(ctx);
+	return 0;
+}
+
+/* this is common implementation of vfs's fsync method of struct
+   file_operations
+*/
+int sync_common(struct file *file, struct dentry *dentry, int datasync)
+{
+	reiser4_context *ctx;
+	int result;
+
+	ctx = init_context(dentry->d_inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+	result = txnmgr_force_commit_all(dentry->d_inode->i_sb, 0);
+
+	context_set_commit_async(ctx);
+	reiser4_exit_context(ctx);
+	return result;
+}
+
+/* this is common implementation of vfs's sendfile method of struct
+   file_operations
+
+   Reads @count bytes from @file and calls @actor for every page read. This is
+   needed for loop back devices support.
+*/
+ssize_t
+sendfile_common(struct file *file, loff_t *ppos, size_t count,
+		read_actor_t actor, void *target)
+{
+	reiser4_context *ctx;
+	ssize_t result;
+
+	ctx = init_context(file->f_dentry->d_inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+	result = generic_file_sendfile(file, ppos, count, actor, target);
+	reiser4_exit_context(ctx);
+	return result;
+}
+
+/* address space operations */
+
+/* this is common implementation of vfs's prepare_write method of struct
+   address_space_operations
+*/
+int
+prepare_write_common(struct file *file, struct page *page, unsigned from,
+		     unsigned to)
+{
+	reiser4_context *ctx;
+	int result;
+
+	ctx = init_context(page->mapping->host->i_sb);
+	result = do_prepare_write(file, page, from, to);
+
+	/* don't commit transaction under inode semaphore */
+	context_set_commit_async(ctx);
+	reiser4_exit_context(ctx);
+
+	return result;
+}
+
+/* this is helper for prepare_write_common and prepare_write_unix_file
+ */
+int
+do_prepare_write(struct file *file, struct page *page, unsigned from,
+		 unsigned to)
+{
+	int result;
+	file_plugin *fplug;
+	struct inode *inode;
+
+	assert("umka-3099", file != NULL);
+	assert("umka-3100", page != NULL);
+	assert("umka-3095", PageLocked(page));
+
+	if (to - from == PAGE_CACHE_SIZE || PageUptodate(page))
+		return 0;
+
+	inode = page->mapping->host;
+	fplug = inode_file_plugin(inode);
+
+	if (page->mapping->a_ops->readpage == NULL)
+		return RETERR(-EINVAL);
+
+	result = page->mapping->a_ops->readpage(file, page);
+	if (result != 0) {
+		SetPageError(page);
+		ClearPageUptodate(page);
+		/* All reiser4 readpage() implementations should return the
+		 * page locked in case of error. */
+		assert("nikita-3472", PageLocked(page));
+	} else {
+		/*
+		 * ->readpage() either:
+		 *
+		 *     1. starts IO against @page. @page is locked for IO in
+		 *     this case.
+		 *
+		 *     2. doesn't start IO. @page is unlocked.
+		 *
+		 * In either case, page should be locked.
+		 */
+		lock_page(page);
+		/*
+		 * IO (if any) is completed at this point. Check for IO
+		 * errors.
+		 */
+		if (!PageUptodate(page))
+			result = RETERR(-EIO);
+	}
+	assert("umka-3098", PageLocked(page));
+	return result;
+}
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * End:
+ */
diff -urN oldtree/fs/reiser4/plugin/file_ops_readdir.c newtree/fs/reiser4/plugin/file_ops_readdir.c
--- oldtree/fs/reiser4/plugin/file_ops_readdir.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/file_ops_readdir.c	2006-02-21 15:58:35.487751600 +0000
@@ -0,0 +1,654 @@
+/* Copyright 2005 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+#include "../inode.h"
+
+/* return true, iff @coord points to the valid directory item that is part of
+ * @inode directory. */
+static int is_valid_dir_coord(struct inode *inode, coord_t * coord)
+{
+	return
+	    item_type_by_coord(coord) == DIR_ENTRY_ITEM_TYPE &&
+	    inode_file_plugin(inode)->owns_item(inode, coord);
+}
+
+/* compare two logical positions within the same directory */
+static cmp_t dir_pos_cmp(const dir_pos * p1, const dir_pos * p2)
+{
+	cmp_t result;
+
+	assert("nikita-2534", p1 != NULL);
+	assert("nikita-2535", p2 != NULL);
+
+	result = de_id_cmp(&p1->dir_entry_key, &p2->dir_entry_key);
+	if (result == EQUAL_TO) {
+		int diff;
+
+		diff = p1->pos - p2->pos;
+		result =
+		    (diff < 0) ? LESS_THAN : (diff ? GREATER_THAN : EQUAL_TO);
+	}
+	return result;
+}
+
+
+/* see comment before readdir_common() for overview of why "adjustment" is
+ * necessary. */
+static void
+adjust_dir_pos(struct file *dir,
+	       readdir_pos * readdir_spot, const dir_pos * mod_point, int adj)
+{
+	dir_pos *pos;
+
+	/*
+	 * new directory entry was added (adj == +1) or removed (adj == -1) at
+	 * the @mod_point. Directory file descriptor @dir is doing readdir and
+	 * is currently positioned at @readdir_spot. Latter has to be updated
+	 * to maintain stable readdir.
+	 */
+	/* directory is positioned to the beginning. */
+	if (readdir_spot->entry_no == 0)
+		return;
+
+	pos = &readdir_spot->position;
+	switch (dir_pos_cmp(mod_point, pos)) {
+	case LESS_THAN:
+		/* @mod_pos is _before_ @readdir_spot, that is, entry was
+		 * added/removed on the left (in key order) of current
+		 * position. */
+		/* logical number of directory entry readdir is "looking" at
+		 * changes */
+		readdir_spot->entry_no += adj;
+		assert("nikita-2577",
+		       ergo(dir != NULL, get_dir_fpos(dir) + adj >= 0));
+		if (de_id_cmp(&pos->dir_entry_key,
+			      &mod_point->dir_entry_key) == EQUAL_TO) {
+			assert("nikita-2575", mod_point->pos < pos->pos);
+			/*
+			 * if entry added/removed has the same key as current
+			 * for readdir, update counter of duplicate keys in
+			 * @readdir_spot.
+			 */
+			pos->pos += adj;
+		}
+		break;
+	case GREATER_THAN:
+		/* directory is modified after @pos: nothing to do. */
+		break;
+	case EQUAL_TO:
+		/* cannot insert an entry readdir is looking at, because it
+		   already exists. */
+		assert("nikita-2576", adj < 0);
+		/* directory entry to which @pos points to is being
+		   removed.
+
+		   NOTE-NIKITA: Right thing to do is to update @pos to point
+		   to the next entry. This is complex (we are under spin-lock
+		   for one thing). Just rewind it to the beginning. Next
+		   readdir will have to scan the beginning of
+		   directory. Proper solution is to use semaphore in
+		   spin lock's stead and use rewind_right() here.
+
+		   NOTE-NIKITA: now, semaphore is used, so...
+		 */
+		memset(readdir_spot, 0, sizeof *readdir_spot);
+	}
+}
+
+/* scan all file-descriptors for this directory and adjust their
+   positions respectively. Should be used by implementations of
+   add_entry and rem_entry of dir plugin */
+void
+adjust_dir_file(struct inode *dir, const struct dentry *de, int offset, int adj)
+{
+	reiser4_file_fsdata *scan;
+	dir_pos mod_point;
+
+	assert("nikita-2536", dir != NULL);
+	assert("nikita-2538", de != NULL);
+	assert("nikita-2539", adj != 0);
+
+	build_de_id(dir, &de->d_name, &mod_point.dir_entry_key);
+	mod_point.pos = offset;
+
+	spin_lock_inode(dir);
+
+	/*
+	 * new entry was added/removed in directory @dir. Scan all file
+	 * descriptors for @dir that are currently involved into @readdir and
+	 * update them.
+	 */
+
+	list_for_each_entry(scan, get_readdir_list(dir), dir.linkage)
+		adjust_dir_pos(scan->back, &scan->dir.readdir, &mod_point, adj);
+
+	spin_unlock_inode(dir);
+}
+
+/*
+ * traverse tree to start/continue readdir from the readdir position @pos.
+ */
+static int dir_go_to(struct file *dir, readdir_pos * pos, tap_t * tap)
+{
+	reiser4_key key;
+	int result;
+	struct inode *inode;
+
+	assert("nikita-2554", pos != NULL);
+
+	inode = dir->f_dentry->d_inode;
+	result = inode_dir_plugin(inode)->build_readdir_key(dir, &key);
+	if (result != 0)
+		return result;
+	result = object_lookup(inode,
+			       &key,
+			       tap->coord,
+			       tap->lh,
+			       tap->mode,
+			       FIND_EXACT,
+			       LEAF_LEVEL, LEAF_LEVEL, 0, &tap->ra_info);
+	if (result == CBK_COORD_FOUND)
+		result = rewind_right(tap, (int)pos->position.pos);
+	else {
+		tap->coord->node = NULL;
+		done_lh(tap->lh);
+		result = RETERR(-EIO);
+	}
+	return result;
+}
+
+/*
+ * handling of non-unique keys: calculate at what ordinal position within
+ * sequence of directory items with identical keys @pos is.
+ */
+static int set_pos(struct inode *inode, readdir_pos * pos, tap_t * tap)
+{
+	int result;
+	coord_t coord;
+	lock_handle lh;
+	tap_t scan;
+	de_id *did;
+	reiser4_key de_key;
+
+	coord_init_zero(&coord);
+	init_lh(&lh);
+	tap_init(&scan, &coord, &lh, ZNODE_READ_LOCK);
+	tap_copy(&scan, tap);
+	tap_load(&scan);
+	pos->position.pos = 0;
+
+	did = &pos->position.dir_entry_key;
+
+	if (is_valid_dir_coord(inode, scan.coord)) {
+
+		build_de_id_by_key(unit_key_by_coord(scan.coord, &de_key), did);
+
+		while (1) {
+
+			result = go_prev_unit(&scan);
+			if (result != 0)
+				break;
+
+			if (!is_valid_dir_coord(inode, scan.coord)) {
+				result = -EINVAL;
+				break;
+			}
+
+			/* get key of directory entry */
+			unit_key_by_coord(scan.coord, &de_key);
+			if (de_id_key_cmp(did, &de_key) != EQUAL_TO) {
+				/* duplicate-sequence is over */
+				break;
+			}
+			pos->position.pos++;
+		}
+	} else
+		result = RETERR(-ENOENT);
+	tap_relse(&scan);
+	tap_done(&scan);
+	return result;
+}
+
+/*
+ * "rewind" directory to @offset, i.e., set @pos and @tap correspondingly.
+ */
+static int dir_rewind(struct file *dir, readdir_pos * pos, tap_t * tap)
+{
+	__u64 destination;
+	__s64 shift;
+	int result;
+	struct inode *inode;
+	loff_t dirpos;
+
+	assert("nikita-2553", dir != NULL);
+	assert("nikita-2548", pos != NULL);
+	assert("nikita-2551", tap->coord != NULL);
+	assert("nikita-2552", tap->lh != NULL);
+
+	dirpos = get_dir_fpos(dir);
+	shift = dirpos - pos->fpos;
+	/* this is logical directory entry within @dir which we are rewinding
+	 * to */
+	destination = pos->entry_no + shift;
+
+	inode = dir->f_dentry->d_inode;
+	if (dirpos < 0)
+		return RETERR(-EINVAL);
+	else if (destination == 0ll || dirpos == 0) {
+		/* rewind to the beginning of directory */
+		memset(pos, 0, sizeof *pos);
+		return dir_go_to(dir, pos, tap);
+	} else if (destination >= inode->i_size)
+		return RETERR(-ENOENT);
+
+	if (shift < 0) {
+		/* I am afraid of negative numbers */
+		shift = -shift;
+		/* rewinding to the left */
+		if (shift <= (int)pos->position.pos) {
+			/* destination is within sequence of entries with
+			   duplicate keys. */
+			result = dir_go_to(dir, pos, tap);
+		} else {
+			shift -= pos->position.pos;
+			while (1) {
+				/* repetitions: deadlock is possible when
+				   going to the left. */
+				result = dir_go_to(dir, pos, tap);
+				if (result == 0) {
+					result = rewind_left(tap, shift);
+					if (result == -E_DEADLOCK) {
+						tap_done(tap);
+						continue;
+					}
+				}
+				break;
+			}
+		}
+	} else {
+		/* rewinding to the right */
+		result = dir_go_to(dir, pos, tap);
+		if (result == 0)
+			result = rewind_right(tap, shift);
+	}
+	if (result == 0) {
+		result = set_pos(inode, pos, tap);
+		if (result == 0) {
+			/* update pos->position.pos */
+			pos->entry_no = destination;
+			pos->fpos = dirpos;
+		}
+	}
+	return result;
+}
+
+/*
+ * Function that is called by common_readdir() on each directory entry while
+ * doing readdir. ->filldir callback may block, so we had to release long term
+ * lock while calling it. To avoid repeating tree traversal, seal is used. If
+ * seal is broken, we return -E_REPEAT. Node is unlocked in this case.
+ *
+ * Whether node is unlocked in case of any other error is undefined. It is
+ * guaranteed to be still locked if success (0) is returned.
+ *
+ * When ->filldir() wants no more, feed_entry() returns 1, and node is
+ * unlocked.
+ */
+static int
+feed_entry(struct file *f,
+	   readdir_pos * pos, tap_t * tap, filldir_t filldir, void *dirent)
+{
+	item_plugin *iplug;
+	char *name;
+	reiser4_key sd_key;
+	int result;
+	char buf[DE_NAME_BUF_LEN];
+	char name_buf[32];
+	char *local_name;
+	unsigned file_type;
+	seal_t seal;
+	coord_t *coord;
+	reiser4_key entry_key;
+
+	coord = tap->coord;
+	iplug = item_plugin_by_coord(coord);
+
+	/* pointer to name within the node */
+	name = iplug->s.dir.extract_name(coord, buf);
+	assert("nikita-1371", name != NULL);
+
+	/* key of object the entry points to */
+	if (iplug->s.dir.extract_key(coord, &sd_key) != 0)
+		return RETERR(-EIO);
+
+	/* we must release longterm znode lock before calling filldir to avoid
+	   deadlock which may happen if filldir causes page fault. So, copy
+	   name to intermediate buffer */
+	if (strlen(name) + 1 > sizeof(name_buf)) {
+		local_name = kmalloc(strlen(name) + 1, GFP_KERNEL);
+		if (local_name == NULL)
+			return RETERR(-ENOMEM);
+	} else
+		local_name = name_buf;
+
+	strcpy(local_name, name);
+	file_type = iplug->s.dir.extract_file_type(coord);
+
+	unit_key_by_coord(coord, &entry_key);
+	seal_init(&seal, coord, &entry_key);
+
+	longterm_unlock_znode(tap->lh);
+
+	/*
+	 * send information about directory entry to the ->filldir() filler
+	 * supplied to us by caller (VFS).
+	 *
+	 * ->filldir is entitled to do weird things. For example, ->filldir
+	 * supplied by knfsd re-enters file system. Make sure no locks are
+	 * held.
+	 */
+	assert("nikita-3436", lock_stack_isclean(get_current_lock_stack()));
+
+	result = filldir(dirent, name, (int)strlen(name),
+			 /* offset of this entry */
+			 f->f_pos,
+			 /* inode number of object bounden by this entry */
+			 oid_to_uino(get_key_objectid(&sd_key)), file_type);
+	if (local_name != name_buf)
+		kfree(local_name);
+	if (result < 0)
+		/* ->filldir() is satisfied. (no space in buffer, IOW) */
+		result = 1;
+	else
+		result = seal_validate(&seal, coord, &entry_key,
+				       tap->lh, tap->mode, ZNODE_LOCK_HIPRI);
+	return result;
+}
+
+static void move_entry(readdir_pos * pos, coord_t * coord)
+{
+	reiser4_key de_key;
+	de_id *did;
+
+	/* update @pos */
+	++pos->entry_no;
+	did = &pos->position.dir_entry_key;
+
+	/* get key of directory entry */
+	unit_key_by_coord(coord, &de_key);
+
+	if (de_id_key_cmp(did, &de_key) == EQUAL_TO)
+		/* we are within sequence of directory entries
+		   with duplicate keys. */
+		++pos->position.pos;
+	else {
+		pos->position.pos = 0;
+		build_de_id_by_key(&de_key, did);
+	}
+	++pos->fpos;
+}
+
+/*
+ *     STATELESS READDIR
+ *
+ * readdir support in reiser4 relies on ability to update readdir_pos embedded
+ * into reiser4_file_fsdata on each directory modification (name insertion and
+ * removal), see readdir_common() function below. This obviously doesn't work
+ * when reiser4 is accessed over NFS, because NFS doesn't keep any state
+ * across client READDIR requests for the same directory.
+ *
+ * To address this we maintain a "pool" of detached reiser4_file_fsdata
+ * (d_cursor). Whenever NFS readdir request comes, we detect this, and try to
+ * find detached reiser4_file_fsdata corresponding to previous readdir
+ * request. In other words, additional state is maintained on the
+ * server. (This is somewhat contrary to the design goals of NFS protocol.)
+ *
+ * To efficiently detect when our ->readdir() method is called by NFS server,
+ * dentry is marked as "stateless" in reiser4_decode_fh() (this is checked by
+ * file_is_stateless() function).
+ *
+ * To find out d_cursor in the pool, we encode client id (cid) in the highest
+ * bits of NFS readdir cookie: when first readdir request comes to the given
+ * directory from the given client, cookie is set to 0. This situation is
+ * detected, global cid_counter is incremented, and stored in highest bits of
+ * all direntry offsets returned to the client, including last one. As the
+ * only valid readdir cookie is one obtained as direntry->offset, we are
+ * guaranteed that next readdir request (continuing current one) will have
+ * current cid in the highest bits of starting readdir cookie. All d_cursors
+ * are hashed into per-super-block hash table by (oid, cid) key.
+ *
+ * In addition d_cursors are placed into per-super-block radix tree where they
+ * are keyed by oid alone. This is necessary to efficiently remove them during
+ * rmdir.
+ *
+ * At last, currently unused d_cursors are linked into special list. This list
+ * is used d_cursor_shrink to reclaim d_cursors on memory pressure.
+ *
+ */
+
+
+/*
+ * prepare for readdir.
+ */
+static int dir_readdir_init(struct file *f, tap_t * tap, readdir_pos ** pos)
+{
+	struct inode *inode;
+	reiser4_file_fsdata *fsdata;
+	int result;
+
+	assert("nikita-1359", f != NULL);
+	inode = f->f_dentry->d_inode;
+	assert("nikita-1360", inode != NULL);
+
+	if (!S_ISDIR(inode->i_mode))
+		return RETERR(-ENOTDIR);
+
+	/* try to find detached readdir state */
+	result = try_to_attach_fsdata(f, inode);
+	if (result != 0)
+		return result;
+
+	fsdata = reiser4_get_file_fsdata(f);
+	assert("nikita-2571", fsdata != NULL);
+	if (IS_ERR(fsdata))
+		return PTR_ERR(fsdata);
+
+	/* add file descriptor to the readdir list hanging of directory
+	 * inode. This list is used to scan "readdirs-in-progress" while
+	 * inserting or removing names in the directory. */
+	spin_lock_inode(inode);
+	if (list_empty_careful(&fsdata->dir.linkage))
+		list_add(&fsdata->dir.linkage, get_readdir_list(inode));
+	*pos = &fsdata->dir.readdir;
+	spin_unlock_inode(inode);
+
+	/* move @tap to the current position */
+	return dir_rewind(f, *pos, tap);
+}
+
+/* this is implementation of vfs's llseek method of struct file_operations for
+   typical directory
+   See comment before readdir_common() for explanation.
+*/
+loff_t llseek_common_dir(struct file * file, loff_t off, int origin)
+{
+	reiser4_context *ctx;
+	loff_t result;
+	struct inode *inode;
+
+	inode = file->f_dentry->d_inode;
+
+	ctx = init_context(inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	mutex_lock(&inode->i_mutex);
+
+	/* update ->f_pos */
+	result = default_llseek(file, off, origin);
+	if (result >= 0) {
+		int ff;
+		coord_t coord;
+		lock_handle lh;
+		tap_t tap;
+		readdir_pos *pos;
+
+		coord_init_zero(&coord);
+		init_lh(&lh);
+		tap_init(&tap, &coord, &lh, ZNODE_READ_LOCK);
+
+		ff = dir_readdir_init(file, &tap, &pos);
+		detach_fsdata(file);
+		if (ff != 0)
+			result = (loff_t) ff;
+		tap_done(&tap);
+	}
+	detach_fsdata(file);
+	mutex_unlock(&inode->i_mutex);
+
+	reiser4_exit_context(ctx);
+	return result;
+}
+
+/* this is common implementation of vfs's readdir method of struct
+   file_operations
+
+   readdir problems:
+
+   readdir(2)/getdents(2) interface is based on implicit assumption that
+   readdir can be restarted from any particular point by supplying file system
+   with off_t-full of data. That is, file system fills ->d_off field in struct
+   dirent and later user passes ->d_off to the seekdir(3), which is, actually,
+   implemented by glibc as lseek(2) on directory.
+
+   Reiser4 cannot restart readdir from 64 bits of data, because two last
+   components of the key of directory entry are unknown, which given 128 bits:
+   locality and type fields in the key of directory entry are always known, to
+   start readdir() from given point objectid and offset fields have to be
+   filled.
+
+   Traditional UNIX API for scanning through directory
+   (readdir/seekdir/telldir/opendir/closedir/rewindir/getdents) is based on the
+   assumption that directory is structured very much like regular file, in
+   particular, it is implied that each name within given directory (directory
+   entry) can be uniquely identified by scalar offset and that such offset is
+   stable across the life-time of the name is identifies.
+
+   This is manifestly not so for reiser4. In reiser4 the only stable unique
+   identifies for the directory entry is its key that doesn't fit into
+   seekdir/telldir API.
+
+   solution:
+
+   Within each file descriptor participating in readdir-ing of directory
+   plugin/dir/dir.h:readdir_pos is maintained. This structure keeps track of
+   the "current" directory entry that file descriptor looks at. It contains a
+   key of directory entry (plus some additional info to deal with non-unique
+   keys that we wouldn't dwell onto here) and a logical position of this
+   directory entry starting from the beginning of the directory, that is
+   ordinal number of this entry in the readdir order.
+
+   Obviously this logical position is not stable in the face of directory
+   modifications. To work around this, on each addition or removal of directory
+   entry all file descriptors for directory inode are scanned and their
+   readdir_pos are updated accordingly (adjust_dir_pos()).
+*/
+int readdir_common(struct file *f /* directory file being read */ ,
+		   void *dirent /* opaque data passed to us by VFS */ ,
+		   filldir_t filld /* filler function passed to us by VFS */ )
+{
+	reiser4_context *ctx;
+	int result;
+	struct inode *inode;
+	coord_t coord;
+	lock_handle lh;
+	tap_t tap;
+	readdir_pos *pos;
+
+	assert("nikita-1359", f != NULL);
+	inode = f->f_dentry->d_inode;
+	assert("nikita-1360", inode != NULL);
+
+	if (!S_ISDIR(inode->i_mode))
+		return RETERR(-ENOTDIR);
+
+	ctx = init_context(inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	coord_init_zero(&coord);
+	init_lh(&lh);
+	tap_init(&tap, &coord, &lh, ZNODE_READ_LOCK);
+
+	reiser4_readdir_readahead_init(inode, &tap);
+
+      repeat:
+	result = dir_readdir_init(f, &tap, &pos);
+	if (result == 0) {
+		result = tap_load(&tap);
+		/* scan entries one by one feeding them to @filld */
+		while (result == 0) {
+			coord_t *coord;
+
+			coord = tap.coord;
+			assert("nikita-2572", coord_is_existing_unit(coord));
+			assert("nikita-3227", is_valid_dir_coord(inode, coord));
+
+			result = feed_entry(f, pos, &tap, filld, dirent);
+			if (result > 0) {
+				break;
+			} else if (result == 0) {
+				++f->f_pos;
+				result = go_next_unit(&tap);
+				if (result == -E_NO_NEIGHBOR ||
+				    result == -ENOENT) {
+					result = 0;
+					break;
+				} else if (result == 0) {
+					if (is_valid_dir_coord(inode, coord))
+						move_entry(pos, coord);
+					else
+						break;
+				}
+			} else if (result == -E_REPEAT) {
+				/* feed_entry() had to restart. */
+				++f->f_pos;
+				tap_relse(&tap);
+				goto repeat;
+			} else
+				warning("vs-1617",
+					"readdir_common: unexpected error %d",
+					result);
+		}
+		tap_relse(&tap);
+
+		if (result >= 0)
+			f->f_version = inode->i_version;
+	} else if (result == -E_NO_NEIGHBOR || result == -ENOENT)
+		result = 0;
+	tap_done(&tap);
+	detach_fsdata(f);
+
+	/* try to update directory's atime */
+	if (reiser4_grab_space(inode_file_plugin(inode)->estimate.update(inode),
+			       BA_CAN_COMMIT) != 0)
+		warning("", "failed to update atime on readdir: %llu",
+			get_inode_oid(inode));
+	else
+		file_accessed(f);
+
+	context_set_commit_async(ctx);
+	reiser4_exit_context(ctx);
+
+	return (result <= 0) ? result : 0;
+}
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * End:
+ */
diff -urN oldtree/fs/reiser4/plugin/file_plugin_common.c newtree/fs/reiser4/plugin/file_plugin_common.c
--- oldtree/fs/reiser4/plugin/file_plugin_common.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/file_plugin_common.c	2006-02-21 15:58:35.488751448 +0000
@@ -0,0 +1,930 @@
+/* Copyright 2005 by Hans Reiser, licensing governed by
+   reiser4/README */
+
+/* this file contains typical implementations for most of methods of
+   file plugin
+*/
+
+#include "../inode.h"
+#include "object.h"
+#include "../safe_link.h"
+
+#include <linux/quotaops.h>
+
+static int insert_new_sd(struct inode *inode);
+static int update_sd(struct inode *inode);
+
+/* this is common implementation of write_sd_by_inode method of file plugin
+   either insert stat data or update it
+ */
+int write_sd_by_inode_common(struct inode *inode /* object to save */ )
+{
+	int result;
+
+	assert("nikita-730", inode != NULL);
+
+	if (inode_get_flag(inode, REISER4_NO_SD))
+		/* object doesn't have stat-data yet */
+		result = insert_new_sd(inode);
+	else
+		result = update_sd(inode);
+	if (result != 0 && result != -ENAMETOOLONG && result != -ENOMEM)
+		/* Don't issue warnings about "name is too long" */
+		warning("nikita-2221", "Failed to save sd for %llu: %i",
+			(unsigned long long)get_inode_oid(inode), result);
+	return result;
+}
+
+/* this is common implementation of key_by_inode method of file plugin
+ */
+int
+key_by_inode_and_offset_common(struct inode *inode, loff_t off,
+			       reiser4_key * key)
+{
+	reiser4_key_init(key);
+	set_key_locality(key, reiser4_inode_data(inode)->locality_id);
+	set_key_ordering(key, get_inode_ordering(inode));
+	set_key_objectid(key, get_inode_oid(inode));	/*FIXME: inode->i_ino */
+	set_key_type(key, KEY_BODY_MINOR);
+	set_key_offset(key, (__u64) off);
+	return 0;
+}
+
+/* this is common implementation of set_plug_in_inode method of file plugin
+ */
+int set_plug_in_inode_common(struct inode *object /* inode to set plugin on */ ,
+			     struct inode *parent /* parent object */ ,
+			     reiser4_object_create_data * data	/* creational
+								 * data */ )
+{
+	__u64 mask;
+
+	object->i_mode = data->mode;
+	/* this should be plugin decision */
+	object->i_uid = current->fsuid;
+	object->i_mtime = object->i_atime = object->i_ctime = CURRENT_TIME;
+
+	/* support for BSD style group-id assignment. See mount's manual page
+	   description of bsdgroups ext2 mount options for more details */
+	if (reiser4_is_set(object->i_sb, REISER4_BSD_GID))
+		object->i_gid = parent->i_gid;
+	else if (parent->i_mode & S_ISGID) {
+		/* parent directory has sguid bit */
+		object->i_gid = parent->i_gid;
+		if (S_ISDIR(object->i_mode))
+			/* sguid is inherited by sub-directories */
+			object->i_mode |= S_ISGID;
+	} else
+		object->i_gid = current->fsgid;
+
+	/* this object doesn't have stat-data yet */
+	inode_set_flag(object, REISER4_NO_SD);
+#if 0
+	/* this is now called after all inode plugins are initialized:
+	   do_create_vfs_child after adjust_to_parent */
+	/* setup inode and file-operations for this inode */
+	setup_inode_ops(object, data);
+#endif
+	object->i_nlink = 0;
+	seal_init(&reiser4_inode_data(object)->sd_seal, NULL, NULL);
+	mask = (1 << UNIX_STAT) | (1 << LIGHT_WEIGHT_STAT);
+	if (!reiser4_is_set(object->i_sb, REISER4_32_BIT_TIMES))
+		mask |= (1 << LARGE_TIMES_STAT);
+
+	reiser4_inode_data(object)->extmask = mask;
+	return 0;
+}
+
+/* this is common implementation of adjust_to_parent method of file plugin for
+   regular files
+ */
+int adjust_to_parent_common(struct inode *object /* new object */ ,
+			    struct inode *parent /* parent directory */ ,
+			    struct inode *root /* root directory */ )
+{
+	assert("nikita-2165", object != NULL);
+	if (parent == NULL)
+		parent = root;
+	assert("nikita-2069", parent != NULL);
+
+	/*
+	 * inherit missing plugins from parent
+	 */
+
+	grab_plugin(object, parent, PSET_FILE);
+	grab_plugin(object, parent, PSET_SD);
+	grab_plugin(object, parent, PSET_FORMATTING);
+	grab_plugin(object, parent, PSET_PERM);
+	return 0;
+}
+
+/* this is common implementation of adjust_to_parent method of file plugin for
+   typical directories
+ */
+int adjust_to_parent_common_dir(struct inode *object /* new object */ ,
+				struct inode *parent /* parent directory */ ,
+				struct inode *root /* root directory */ )
+{
+	int result = 0;
+	pset_member memb;
+
+	assert("nikita-2166", object != NULL);
+	if (parent == NULL)
+		parent = root;
+	assert("nikita-2167", parent != NULL);
+
+	/*
+	 * inherit missing plugins from parent
+	 */
+	for (memb = 0; memb < PSET_LAST; ++memb) {
+		result = grab_plugin(object, parent, memb);
+		if (result != 0)
+			break;
+	}
+	return result;
+}
+
+int adjust_to_parent_cryptcompress(struct inode *object /* new object */ ,
+				   struct inode *parent /* parent directory */,
+				   struct inode *root /* root directory */)
+{
+ 	int result;
+ 	result = adjust_to_parent_common(object, parent, root);
+ 	if (result)
+ 		return result;
+ 	assert("edward-1416", parent != NULL);
+
+ 	grab_plugin(object, parent, PSET_CLUSTER);
+ 	grab_plugin(object, parent, PSET_CIPHER);
+ 	grab_plugin(object, parent, PSET_DIGEST);
+ 	grab_plugin(object, parent, PSET_COMPRESSION);
+ 	grab_plugin(object, parent, PSET_COMPRESSION_MODE);
+
+ 	return 0;
+}
+
+/* this is common implementation of create_object method of file plugin
+ */
+int
+create_object_common(struct inode *object, struct inode *parent UNUSED_ARG,
+		     reiser4_object_create_data * data UNUSED_ARG)
+{
+	reiser4_block_nr reserve;
+	assert("nikita-744", object != NULL);
+	assert("nikita-745", parent != NULL);
+	assert("nikita-747", data != NULL);
+	assert("nikita-748", inode_get_flag(object, REISER4_NO_SD));
+
+	reserve = estimate_create_common(object);
+	if (reiser4_grab_space(reserve, BA_CAN_COMMIT))
+		return RETERR(-ENOSPC);
+	return write_sd_by_inode_common(object);
+}
+
+static int common_object_delete_no_reserve(struct inode *inode);
+
+/**
+ * delete_object_common - delete_object of file_plugin
+ * @inode: inode to be deleted
+ *
+ * This is common implementation of delete_object method of file_plugin. It
+ * applies to object its deletion consists of removing two items - stat data
+ * and safe-link.
+ */
+int delete_object_common(struct inode *inode)
+{
+	int result;
+
+	assert("nikita-1477", inode != NULL);
+	/* FIXME: if file body deletion failed (i/o error, for instance),
+	   inode->i_size can be != 0 here */
+	assert("nikita-3420", inode->i_size == 0 || S_ISLNK(inode->i_mode));
+	assert("nikita-3421", inode->i_nlink == 0);
+
+
+	if (!inode_get_flag(inode, REISER4_NO_SD)) {
+		reiser4_block_nr reserve;
+
+		/* grab space which is needed to remove 2 items from the tree:
+		   stat data and safe-link */
+		reserve = 2 * estimate_one_item_removal(tree_by_inode(inode));
+		if (reiser4_grab_space_force(reserve,
+					     BA_RESERVED | BA_CAN_COMMIT))
+			return RETERR(-ENOSPC);
+		result = common_object_delete_no_reserve(inode);
+	} else
+		result = 0;
+	return result;
+}
+
+/**
+ * delete_directory_common - delete_object of file_plugin
+ * @inode: inode to be deleted
+ *
+ * This is common implementation of delete_object method of file_plugin for
+ * typical directory. It calls done method of dir_plugin to remove "." and
+ * removes stat data and safe-link.
+ */
+int delete_directory_common(struct inode *inode)
+{
+	int result;
+	dir_plugin *dplug;
+
+	assert("", (get_current_context() &&
+		    get_current_context()->trans->atom == NULL));
+
+	dplug = inode_dir_plugin(inode);
+	assert("vs-1101", dplug && dplug->done);
+
+	/* kill cursors which might be attached to inode */
+	kill_cursors(inode);
+
+	/* grab space enough for removing two items */
+	if (reiser4_grab_space
+	    (2 * estimate_one_item_removal(tree_by_inode(inode)),
+	     BA_RESERVED | BA_CAN_COMMIT))
+		return RETERR(-ENOSPC);
+
+	result = dplug->done(inode);
+	if (!result)
+		result = common_object_delete_no_reserve(inode);
+	all_grabbed2free();
+	return result;
+}
+
+/* this is common implementation of add_link method of file plugin
+ */
+int add_link_common(struct inode *object, struct inode *parent UNUSED_ARG)
+{
+	/*
+	 * increment ->i_nlink and update ->i_ctime
+	 */
+
+	INODE_INC_FIELD(object, i_nlink);
+	object->i_ctime = CURRENT_TIME;
+	return 0;
+}
+
+/* this is common implementation of rem_link method of file plugin
+ */
+int rem_link_common(struct inode *object, struct inode *parent UNUSED_ARG)
+{
+	assert("nikita-2021", object != NULL);
+	assert("nikita-2163", object->i_nlink > 0);
+
+	/*
+	 * decrement ->i_nlink and update ->i_ctime
+	 */
+
+	INODE_DEC_FIELD(object, i_nlink);
+	object->i_ctime = CURRENT_TIME;
+	return 0;
+}
+
+/* this is common implementation of rem_link method of file plugin for typical
+   directory
+*/
+int rem_link_common_dir(struct inode *object, struct inode *parent UNUSED_ARG)
+{
+	assert("nikita-20211", object != NULL);
+	assert("nikita-21631", object->i_nlink > 0);
+
+	/*
+	 * decrement ->i_nlink and update ->i_ctime
+	 */
+	INODE_DEC_FIELD(object, i_nlink);
+	if (object->i_nlink == 1)
+		INODE_DEC_FIELD(object, i_nlink);
+	object->i_ctime = CURRENT_TIME;
+	return 0;
+}
+
+/* this is common implementation of owns_item method of file plugin
+   compare objectids of keys in inode and coord */
+int owns_item_common(const struct inode *inode,	/* object to check
+						 * against */
+		     const coord_t * coord /* coord to check */ )
+{
+	reiser4_key item_key;
+	reiser4_key file_key;
+
+	assert("nikita-760", inode != NULL);
+	assert("nikita-761", coord != NULL);
+
+	return coord_is_existing_item(coord) &&
+	    (get_key_objectid(build_sd_key(inode, &file_key)) ==
+	     get_key_objectid(item_key_by_coord(coord, &item_key)));
+}
+
+/* this is common implementation of owns_item method of file plugin
+   for typical directory
+*/
+int owns_item_common_dir(const struct inode *inode,	/* object to check against */
+			 const coord_t * coord /* coord of item to check */ )
+{
+	reiser4_key item_key;
+
+	assert("nikita-1335", inode != NULL);
+	assert("nikita-1334", coord != NULL);
+
+	if (item_type_by_coord(coord) == DIR_ENTRY_ITEM_TYPE)
+		return get_key_locality(item_key_by_coord(coord, &item_key)) ==
+		    get_inode_oid(inode);
+	else
+		return owns_item_common(inode, coord);
+}
+
+/* this is common implementation of can_add_link method of file plugin
+   checks whether yet another hard links to this object can be added
+*/
+int can_add_link_common(const struct inode *object /* object to check */ )
+{
+	assert("nikita-732", object != NULL);
+
+	/* inode->i_nlink is unsigned int, so just check for integer
+	   overflow */
+	return object->i_nlink + 1 != 0;
+}
+
+/* this is common implementation of can_rem_link method of file plugin for
+   typical directory
+*/
+int can_rem_link_common_dir(const struct inode *inode)
+{
+	/* is_dir_empty() returns 0 is dir is empty */
+	return !is_dir_empty(inode);
+}
+
+/* this is common implementation of detach method of file plugin for typical
+   directory
+*/
+int detach_common_dir(struct inode *child, struct inode *parent)
+{
+	dir_plugin *dplug;
+
+	dplug = inode_dir_plugin(child);
+	assert("nikita-2883", dplug != NULL);
+	assert("nikita-2884", dplug->detach != NULL);
+	return dplug->detach(child, parent);
+}
+
+/* this is common implementation of bind method of file plugin for typical
+   directory
+*/
+int bind_common_dir(struct inode *child, struct inode *parent)
+{
+	dir_plugin *dplug;
+
+	dplug = inode_dir_plugin(child);
+	assert("nikita-2646", dplug != NULL);
+	return dplug->attach(child, parent);
+}
+
+static int process_truncate(struct inode *, __u64 size);
+
+/* this is common implementation of safelink method of file plugin
+ */
+int safelink_common(struct inode *object, reiser4_safe_link_t link, __u64 value)
+{
+	int result;
+
+	assert("vs-1705", get_current_context()->trans->atom == NULL);
+	if (link == SAFE_UNLINK)
+		/* nothing to do. iput() in the caller (process_safelink) will
+		 * finish with file */
+		result = 0;
+	else if (link == SAFE_TRUNCATE)
+		result = process_truncate(object, value);
+	else {
+		warning("nikita-3438", "Unrecognized safe-link type: %i", link);
+		result = RETERR(-EIO);
+	}
+	return result;
+}
+
+/* this is common implementation of estimate.create method of file plugin
+   can be used when object creation involves insertion of one item (usually stat
+   data) into tree
+*/
+reiser4_block_nr estimate_create_common(const struct inode * object)
+{
+	return estimate_one_insert_item(tree_by_inode(object));
+}
+
+/* this is common implementation of estimate.create method of file plugin for
+   typical directory
+   can be used when directory creation involves insertion of two items (usually
+   stat data and item containing "." and "..") into tree
+*/
+reiser4_block_nr estimate_create_common_dir(const struct inode * object)
+{
+	return 2 * estimate_one_insert_item(tree_by_inode(object));
+}
+
+/* this is common implementation of estimate.update method of file plugin
+   can be used when stat data update does not do more than inserting a unit
+   into a stat data item which is probably true for most cases
+*/
+reiser4_block_nr estimate_update_common(const struct inode * inode)
+{
+	return estimate_one_insert_into_item(tree_by_inode(inode));
+}
+
+/* this is common implementation of estimate.unlink method of file plugin
+ */
+reiser4_block_nr
+estimate_unlink_common(const struct inode * object UNUSED_ARG,
+		       const struct inode * parent UNUSED_ARG)
+{
+	return 0;
+}
+
+/* this is common implementation of estimate.unlink method of file plugin for
+   typical directory
+*/
+reiser4_block_nr
+estimate_unlink_common_dir(const struct inode * object,
+			   const struct inode * parent)
+{
+	dir_plugin *dplug;
+
+	dplug = inode_dir_plugin(object);
+	assert("nikita-2888", dplug != NULL);
+	assert("nikita-2887", dplug->estimate.unlink != NULL);
+	return dplug->estimate.unlink(object, parent);
+}
+
+char *wire_write_common(struct inode *inode, char *start)
+{
+	return build_inode_onwire(inode, start);
+}
+
+char *wire_read_common(char *addr, reiser4_object_on_wire * obj)
+{
+	return extract_obj_key_id_from_onwire(addr, &obj->u.std.key_id);
+}
+
+struct dentry *wire_get_common(struct super_block *sb,
+			       reiser4_object_on_wire * obj)
+{
+	struct inode *inode;
+	struct dentry *dentry;
+	reiser4_key key;
+
+	extract_key_from_id(&obj->u.std.key_id, &key);
+	inode = reiser4_iget(sb, &key, 1);
+	if (!IS_ERR(inode)) {
+		reiser4_iget_complete(inode);
+		dentry = d_alloc_anon(inode);
+		if (dentry == NULL) {
+			iput(inode);
+			dentry = ERR_PTR(-ENOMEM);
+		} else
+			dentry->d_op = &get_super_private(sb)->ops.dentry;
+	} else if (PTR_ERR(inode) == -ENOENT)
+		/*
+		 * inode wasn't found at the key encoded in the file
+		 * handle. Hence, file handle is stale.
+		 */
+		dentry = ERR_PTR(RETERR(-ESTALE));
+	else
+		dentry = (void *)inode;
+	return dentry;
+}
+
+int wire_size_common(struct inode *inode)
+{
+	return inode_onwire_size(inode);
+}
+
+void wire_done_common(reiser4_object_on_wire * obj)
+{
+	/* nothing to do */
+}
+
+/* helper function to print errors */
+static void key_warning(const reiser4_key * key /* key to print */ ,
+			const struct inode *inode,
+			int code /* error code to print */ )
+{
+	assert("nikita-716", key != NULL);
+
+	if (code != -ENOMEM) {
+		warning("nikita-717", "Error for inode %llu (%i)",
+			(unsigned long long)get_key_objectid(key), code);
+		print_key("for key", key);
+	}
+}
+
+/* NIKITA-FIXME-HANS: perhaps this function belongs in another file? */
+#if REISER4_DEBUG
+static void
+check_inode_seal(const struct inode *inode,
+		 const coord_t * coord, const reiser4_key * key)
+{
+	reiser4_key unit_key;
+
+	unit_key_by_coord(coord, &unit_key);
+	assert("nikita-2752",
+	       WITH_DATA_RET(coord->node, 1, keyeq(key, &unit_key)));
+	assert("nikita-2753", get_inode_oid(inode) == get_key_objectid(key));
+}
+
+static void check_sd_coord(coord_t * coord, const reiser4_key * key)
+{
+	reiser4_key ukey;
+
+	coord_clear_iplug(coord);
+	if (zload(coord->node))
+		return;
+
+	if (!coord_is_existing_unit(coord) ||
+	    !item_plugin_by_coord(coord) ||
+	    !keyeq(unit_key_by_coord(coord, &ukey), key) ||
+	    (znode_get_level(coord->node) != LEAF_LEVEL) ||
+	    !item_is_statdata(coord)) {
+		warning("nikita-1901", "Conspicuous seal");
+		print_key("key", key);
+		print_coord("coord", coord, 1);
+		impossible("nikita-2877", "no way");
+	}
+	zrelse(coord->node);
+}
+
+#else
+#define check_inode_seal(inode, coord, key) noop
+#define check_sd_coord(coord, key) noop
+#endif
+
+/* insert new stat-data into tree. Called with inode state
+    locked. Return inode state locked. */
+static int insert_new_sd(struct inode *inode /* inode to create sd for */ )
+{
+	int result;
+	reiser4_key key;
+	coord_t coord;
+	reiser4_item_data data;
+	char *area;
+	reiser4_inode *ref;
+	lock_handle lh;
+	oid_t oid;
+
+	assert("nikita-723", inode != NULL);
+	assert("nikita-3406", inode_get_flag(inode, REISER4_NO_SD));
+
+	ref = reiser4_inode_data(inode);
+	spin_lock_inode(inode);
+
+	if (ref->plugin_mask != 0)
+		/* inode has non-standard plugins */
+		inode_set_extension(inode, PLUGIN_STAT);
+	/*
+	 * prepare specification of new item to be inserted
+	 */
+
+	data.iplug = inode_sd_plugin(inode);
+	data.length = data.iplug->s.sd.save_len(inode);
+	spin_unlock_inode(inode);
+
+	data.data = NULL;
+	data.user = 0;
+/* could be optimized for case where there is only one node format in
+ * use in the filesystem, probably there are lots of such
+ * places we could optimize for only one node layout.... -Hans */
+	if (data.length > tree_by_inode(inode)->nplug->max_item_size()) {
+		/* This is silly check, but we don't know actual node where
+		   insertion will go into. */
+		return RETERR(-ENAMETOOLONG);
+	}
+	oid = oid_allocate(inode->i_sb);
+/* NIKITA-FIXME-HANS: what is your opinion on whether this error check should be encapsulated into oid_allocate? */
+	if (oid == ABSOLUTE_MAX_OID)
+		return RETERR(-EOVERFLOW);
+
+	set_inode_oid(inode, oid);
+
+	coord_init_zero(&coord);
+	init_lh(&lh);
+
+	result = insert_by_key(tree_by_inode(inode),
+			       build_sd_key(inode, &key), &data, &coord, &lh,
+			       /* stat data lives on a leaf level */
+			       LEAF_LEVEL, CBK_UNIQUE);
+
+	/* we don't want to re-check that somebody didn't insert
+	   stat-data while we were doing io, because if it did,
+	   insert_by_key() returned error. */
+	/* but what _is_ possible is that plugin for inode's stat-data,
+	   list of non-standard plugins or their state would change
+	   during io, so that stat-data wouldn't fit into sd. To avoid
+	   this race we keep inode_state lock. This lock has to be
+	   taken each time you access inode in a way that would cause
+	   changes in sd size: changing plugins etc.
+	 */
+
+	if (result == IBK_INSERT_OK) {
+		coord_clear_iplug(&coord);
+		result = zload(coord.node);
+		if (result == 0) {
+			/* have we really inserted stat data? */
+			assert("nikita-725", item_is_statdata(&coord));
+
+			/* inode was just created. It is inserted into hash
+			   table, but no directory entry was yet inserted into
+			   parent. So, inode is inaccessible through
+			   ->lookup(). All places that directly grab inode
+			   from hash-table (like old knfsd), should check
+			   IMMUTABLE flag that is set by common_create_child.
+			 */
+			assert("nikita-3240", data.iplug != NULL);
+			assert("nikita-3241", data.iplug->s.sd.save != NULL);
+			area = item_body_by_coord(&coord);
+			result = data.iplug->s.sd.save(inode, &area);
+			znode_make_dirty(coord.node);
+			if (result == 0) {
+				/* object has stat-data now */
+				inode_clr_flag(inode, REISER4_NO_SD);
+				inode_set_flag(inode, REISER4_SDLEN_KNOWN);
+				/* initialise stat-data seal */
+				seal_init(&ref->sd_seal, &coord, &key);
+				ref->sd_coord = coord;
+				check_inode_seal(inode, &coord, &key);
+			} else if (result != -ENOMEM)
+				/*
+				 * convert any other error code to -EIO to
+				 * avoid confusing user level with unexpected
+				 * errors.
+				 */
+				result = RETERR(-EIO);
+			zrelse(coord.node);
+		}
+	}
+	done_lh(&lh);
+
+	if (result != 0)
+		key_warning(&key, inode, result);
+	else
+		oid_count_allocated();
+
+	return result;
+}
+
+/* find sd of inode in a tree, deal with errors */
+int lookup_sd(struct inode *inode /* inode to look sd for */ ,
+	      znode_lock_mode lock_mode /* lock mode */ ,
+	      coord_t * coord /* resulting coord */ ,
+	      lock_handle * lh /* resulting lock handle */ ,
+	      const reiser4_key * key /* resulting key */ ,
+	      int silent)
+{
+	int result;
+	__u32 flags;
+
+	assert("nikita-1692", inode != NULL);
+	assert("nikita-1693", coord != NULL);
+	assert("nikita-1694", key != NULL);
+
+	/* look for the object's stat data in a tree.
+	   This returns in "node" pointer to a locked znode and in "pos"
+	   position of an item found in node. Both are only valid if
+	   coord_found is returned. */
+	flags = (lock_mode == ZNODE_WRITE_LOCK) ? CBK_FOR_INSERT : 0;
+	flags |= CBK_UNIQUE;
+	/*
+	 * traverse tree to find stat data. We cannot use vroot here, because
+	 * it only covers _body_ of the file, and stat data don't belong
+	 * there.
+	 */
+	result = coord_by_key(tree_by_inode(inode),
+			      key,
+			      coord,
+			      lh,
+			      lock_mode,
+			      FIND_EXACT, LEAF_LEVEL, LEAF_LEVEL, flags, NULL);
+	if (REISER4_DEBUG && result == 0)
+		check_sd_coord(coord, key);
+
+	if (result != 0 && !silent)
+		key_warning(key, inode, result);
+	return result;
+}
+
+int
+locate_inode_sd(struct inode *inode,
+		reiser4_key * key, coord_t * coord, lock_handle * lh)
+{
+	reiser4_inode *state;
+	seal_t seal;
+	int result;
+
+	assert("nikita-3483", inode != NULL);
+
+	state = reiser4_inode_data(inode);
+	spin_lock_inode(inode);
+	*coord = state->sd_coord;
+	coord_clear_iplug(coord);
+	seal = state->sd_seal;
+	spin_unlock_inode(inode);
+
+	build_sd_key(inode, key);
+	if (seal_is_set(&seal)) {
+		/* first, try to use seal */
+		result = seal_validate(&seal,
+				       coord,
+				       key,
+				       lh, ZNODE_WRITE_LOCK, ZNODE_LOCK_LOPRI);
+		if (result == 0)
+			check_sd_coord(coord, key);
+	} else
+		result = -E_REPEAT;
+
+	if (result != 0) {
+		coord_init_zero(coord);
+		result = lookup_sd(inode, ZNODE_WRITE_LOCK, coord, lh, key, 0);
+	}
+	return result;
+}
+
+/* update stat-data at @coord */
+static int
+update_sd_at(struct inode *inode, coord_t * coord, reiser4_key * key,
+	     lock_handle * lh)
+{
+	int result;
+	reiser4_item_data data;
+	char *area;
+	reiser4_inode *state;
+	znode *loaded;
+
+	state = reiser4_inode_data(inode);
+
+	coord_clear_iplug(coord);
+	result = zload(coord->node);
+	if (result != 0)
+		return result;
+	loaded = coord->node;
+
+	spin_lock_inode(inode);
+	assert("nikita-728", inode_sd_plugin(inode) != NULL);
+	data.iplug = inode_sd_plugin(inode);
+
+	/* if inode has non-standard plugins, add appropriate stat data
+	 * extension */
+	if (state->plugin_mask != 0)
+		inode_set_extension(inode, PLUGIN_STAT);
+
+	/* data.length is how much space to add to (or remove
+	   from if negative) sd */
+	if (!inode_get_flag(inode, REISER4_SDLEN_KNOWN)) {
+		/* recalculate stat-data length */
+		data.length =
+		    data.iplug->s.sd.save_len(inode) -
+		    item_length_by_coord(coord);
+		inode_set_flag(inode, REISER4_SDLEN_KNOWN);
+	} else
+		data.length = 0;
+	spin_unlock_inode(inode);
+
+	/* if on-disk stat data is of different length than required
+	   for this inode, resize it */
+	if (data.length != 0) {
+		data.data = NULL;
+		data.user = 0;
+
+		/* insertion code requires that insertion point (coord) was
+		 * between units. */
+		coord->between = AFTER_UNIT;
+		result = resize_item(coord,
+				     &data, key, lh, COPI_DONT_SHIFT_LEFT);
+		if (result != 0) {
+			key_warning(key, inode, result);
+			zrelse(loaded);
+			return result;
+		}
+		if (loaded != coord->node) {
+			/* resize_item moved coord to another node. Zload it */
+			zrelse(loaded);
+			coord_clear_iplug(coord);
+			result = zload(coord->node);
+			if (result != 0)
+				return result;
+			loaded = coord->node;
+		}
+	}
+
+	area = item_body_by_coord(coord);
+	spin_lock_inode(inode);
+	result = data.iplug->s.sd.save(inode, &area);
+	znode_make_dirty(coord->node);
+
+	/* re-initialise stat-data seal */
+
+	/*
+	 * coord.between was possibly skewed from AT_UNIT when stat-data size
+	 * was changed and new extensions were pasted into item.
+	 */
+	coord->between = AT_UNIT;
+	seal_init(&state->sd_seal, coord, key);
+	state->sd_coord = *coord;
+	spin_unlock_inode(inode);
+	check_inode_seal(inode, coord, key);
+	zrelse(loaded);
+	return result;
+}
+
+/* Update existing stat-data in a tree. Called with inode state locked. Return
+   inode state locked. */
+static int update_sd(struct inode *inode /* inode to update sd for */ )
+{
+	int result;
+	reiser4_key key;
+	coord_t coord;
+	lock_handle lh;
+
+	assert("nikita-726", inode != NULL);
+
+	/* no stat-data, nothing to update?! */
+	assert("nikita-3482", !inode_get_flag(inode, REISER4_NO_SD));
+
+	init_lh(&lh);
+
+	result = locate_inode_sd(inode, &key, &coord, &lh);
+	if (result == 0)
+		result = update_sd_at(inode, &coord, &key, &lh);
+	done_lh(&lh);
+
+	return result;
+}
+
+/* helper for delete_object_common and delete_directory_common. Remove object
+   stat data. Space for that must be reserved by caller before
+*/
+static int
+common_object_delete_no_reserve(struct inode *inode /* object to remove */ )
+{
+	int result;
+
+	assert("nikita-1477", inode != NULL);
+
+	if (!inode_get_flag(inode, REISER4_NO_SD)) {
+		reiser4_key sd_key;
+
+		DQUOT_FREE_INODE(inode);
+		DQUOT_DROP(inode);
+
+		build_sd_key(inode, &sd_key);
+		result =
+		    cut_tree(tree_by_inode(inode), &sd_key, &sd_key, NULL, 0);
+		if (result == 0) {
+			inode_set_flag(inode, REISER4_NO_SD);
+			result = oid_release(inode->i_sb, get_inode_oid(inode));
+			if (result == 0) {
+				oid_count_released();
+
+				result = safe_link_del(tree_by_inode(inode),
+						       get_inode_oid(inode),
+						       SAFE_UNLINK);
+			}
+		}
+	} else
+		result = 0;
+	return result;
+}
+
+/* helper for safelink_common */
+static int process_truncate(struct inode *inode, __u64 size)
+{
+	int result;
+	struct iattr attr;
+	file_plugin *fplug;
+	reiser4_context *ctx;
+	struct dentry dentry;
+
+	assert("vs-21", is_in_reiser4_context());
+	ctx = init_context(inode->i_sb);
+	assert("vs-22", !IS_ERR(ctx));
+
+	attr.ia_size = size;
+	attr.ia_valid = ATTR_SIZE | ATTR_CTIME;
+	fplug = inode_file_plugin(inode);
+
+	mutex_lock(&inode->i_mutex);
+	assert("vs-1704", get_current_context()->trans->atom == NULL);
+	dentry.d_inode = inode;
+	result = inode->i_op->setattr(&dentry, &attr);
+	mutex_unlock(&inode->i_mutex);
+
+	context_set_commit_async(ctx);
+	reiser4_exit_context(ctx);
+
+	return result;
+}
+
+/* Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/hash.c newtree/fs/reiser4/plugin/hash.c
--- oldtree/fs/reiser4/plugin/hash.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/hash.c	2006-02-21 15:58:34.601886272 +0000
@@ -0,0 +1,350 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Hash functions */
+
+#include "../debug.h"
+#include "plugin_header.h"
+#include "plugin.h"
+#include "../super.h"
+#include "../inode.h"
+
+#include <linux/types.h>
+
+/* old rupasov (yura) hash */
+static __u64 hash_rupasov(const unsigned char *name /* name to hash */ ,
+			  int len /* @name's length */ )
+{
+	int i;
+	int j;
+	int pow;
+	__u64 a;
+	__u64 c;
+
+	assert("nikita-672", name != NULL);
+	assert("nikita-673", len >= 0);
+
+	for (pow = 1, i = 1; i < len; ++i)
+		pow = pow * 10;
+
+	if (len == 1)
+		a = name[0] - 48;
+	else
+		a = (name[0] - 48) * pow;
+
+	for (i = 1; i < len; ++i) {
+		c = name[i] - 48;
+		for (pow = 1, j = i; j < len - 1; ++j)
+			pow = pow * 10;
+		a = a + c * pow;
+	}
+	for (; i < 40; ++i) {
+		c = '0' - 48;
+		for (pow = 1, j = i; j < len - 1; ++j)
+			pow = pow * 10;
+		a = a + c * pow;
+	}
+
+	for (; i < 256; ++i) {
+		c = i;
+		for (pow = 1, j = i; j < len - 1; ++j)
+			pow = pow * 10;
+		a = a + c * pow;
+	}
+
+	a = a << 7;
+	return a;
+}
+
+/* r5 hash */
+static __u64 hash_r5(const unsigned char *name /* name to hash */ ,
+		     int len UNUSED_ARG /* @name's length */ )
+{
+	__u64 a = 0;
+
+	assert("nikita-674", name != NULL);
+	assert("nikita-675", len >= 0);
+
+	while (*name) {
+		a += *name << 4;
+		a += *name >> 4;
+		a *= 11;
+		name++;
+	}
+	return a;
+}
+
+/* Keyed 32-bit hash function using TEA in a Davis-Meyer function
+     H0 = Key
+     Hi = E Mi(Hi-1) + Hi-1
+
+   (see Applied Cryptography, 2nd edition, p448).
+
+   Jeremy Fitzhardinge <jeremy@zip.com.au> 1998
+
+   Jeremy has agreed to the contents of reiserfs/README. -Hans
+
+   This code was blindly upgraded to __u64 by s/__u32/__u64/g.
+*/
+static __u64 hash_tea(const unsigned char *name /* name to hash */ ,
+		      int len /* @name's length */ )
+{
+	__u64 k[] = { 0x9464a485u, 0x542e1a94u, 0x3e846bffu, 0xb75bcfc3u };
+
+	__u64 h0 = k[0], h1 = k[1];
+	__u64 a, b, c, d;
+	__u64 pad;
+	int i;
+
+	assert("nikita-676", name != NULL);
+	assert("nikita-677", len >= 0);
+
+#define DELTA 0x9E3779B9u
+#define FULLROUNDS 10		/* 32 is overkill, 16 is strong crypto */
+#define PARTROUNDS 6		/* 6 gets complete mixing */
+
+/* a, b, c, d - data; h0, h1 - accumulated hash */
+#define TEACORE(rounds)							\
+	do {								\
+		__u64 sum = 0;						\
+		int n = rounds;						\
+		__u64 b0, b1;						\
+									\
+		b0 = h0;						\
+		b1 = h1;						\
+									\
+		do							\
+		{							\
+			sum += DELTA;					\
+			b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);	\
+			b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);	\
+		} while(--n);						\
+									\
+		h0 += b0;						\
+		h1 += b1;						\
+	} while(0)
+
+	pad = (__u64) len | ((__u64) len << 8);
+	pad |= pad << 16;
+
+	while (len >= 16) {
+		a = (__u64) name[0] | (__u64) name[1] << 8 | (__u64) name[2] <<
+		    16 | (__u64) name[3] << 24;
+		b = (__u64) name[4] | (__u64) name[5] << 8 | (__u64) name[6] <<
+		    16 | (__u64) name[7] << 24;
+		c = (__u64) name[8] | (__u64) name[9] << 8 | (__u64) name[10] <<
+		    16 | (__u64) name[11] << 24;
+		d = (__u64) name[12] | (__u64) name[13] << 8 | (__u64) name[14]
+		    << 16 | (__u64) name[15] << 24;
+
+		TEACORE(PARTROUNDS);
+
+		len -= 16;
+		name += 16;
+	}
+
+	if (len >= 12) {
+		//assert(len < 16);
+		if (len >= 16)
+			*(int *)0 = 0;
+
+		a = (__u64) name[0] | (__u64) name[1] << 8 | (__u64) name[2] <<
+		    16 | (__u64) name[3] << 24;
+		b = (__u64) name[4] | (__u64) name[5] << 8 | (__u64) name[6] <<
+		    16 | (__u64) name[7] << 24;
+		c = (__u64) name[8] | (__u64) name[9] << 8 | (__u64) name[10] <<
+		    16 | (__u64) name[11] << 24;
+
+		d = pad;
+		for (i = 12; i < len; i++) {
+			d <<= 8;
+			d |= name[i];
+		}
+	} else if (len >= 8) {
+		//assert(len < 12);
+		if (len >= 12)
+			*(int *)0 = 0;
+		a = (__u64) name[0] | (__u64) name[1] << 8 | (__u64) name[2] <<
+		    16 | (__u64) name[3] << 24;
+		b = (__u64) name[4] | (__u64) name[5] << 8 | (__u64) name[6] <<
+		    16 | (__u64) name[7] << 24;
+
+		c = d = pad;
+		for (i = 8; i < len; i++) {
+			c <<= 8;
+			c |= name[i];
+		}
+	} else if (len >= 4) {
+		//assert(len < 8);
+		if (len >= 8)
+			*(int *)0 = 0;
+		a = (__u64) name[0] | (__u64) name[1] << 8 | (__u64) name[2] <<
+		    16 | (__u64) name[3] << 24;
+
+		b = c = d = pad;
+		for (i = 4; i < len; i++) {
+			b <<= 8;
+			b |= name[i];
+		}
+	} else {
+		//assert(len < 4);
+		if (len >= 4)
+			*(int *)0 = 0;
+		a = b = c = d = pad;
+		for (i = 0; i < len; i++) {
+			a <<= 8;
+			a |= name[i];
+		}
+	}
+
+	TEACORE(FULLROUNDS);
+
+/*	return 0;*/
+	return h0 ^ h1;
+
+}
+
+/* classical 64 bit Fowler/Noll/Vo-1 (FNV-1) hash.
+
+   See http://www.isthe.com/chongo/tech/comp/fnv/ for details.
+
+   Excerpts:
+
+     FNV hashes are designed to be fast while maintaining a low collision
+     rate.
+
+     [This version also seems to preserve lexicographical order locally.]
+
+     FNV hash algorithms and source code have been released into the public
+     domain.
+
+*/
+static __u64 hash_fnv1(const unsigned char *name /* name to hash */ ,
+		       int len UNUSED_ARG /* @name's length */ )
+{
+	unsigned long long a = 0xcbf29ce484222325ull;
+	const unsigned long long fnv_64_prime = 0x100000001b3ull;
+
+	assert("nikita-678", name != NULL);
+	assert("nikita-679", len >= 0);
+
+	/* FNV-1 hash each octet in the buffer */
+	for (; *name; ++name) {
+		/* multiply by the 32 bit FNV magic prime mod 2^64 */
+		a *= fnv_64_prime;
+		/* xor the bottom with the current octet */
+		a ^= (unsigned long long)(*name);
+	}
+	/* return our new hash value */
+	return a;
+}
+
+/* degenerate hash function used to simplify testing of non-unique key
+   handling */
+static __u64 hash_deg(const unsigned char *name UNUSED_ARG /* name to hash */ ,
+		      int len UNUSED_ARG /* @name's length */ )
+{
+	return 0xc0c0c0c010101010ull;
+}
+
+static int change_hash(struct inode *inode, reiser4_plugin * plugin)
+{
+	int result;
+
+	assert("nikita-3503", inode != NULL);
+	assert("nikita-3504", plugin != NULL);
+
+	assert("nikita-3505", is_reiser4_inode(inode));
+	assert("nikita-3506", inode_dir_plugin(inode) != NULL);
+	assert("nikita-3507", plugin->h.type_id == REISER4_HASH_PLUGIN_TYPE);
+
+	result = 0;
+	if (inode_hash_plugin(inode) == NULL ||
+	    inode_hash_plugin(inode)->h.id != plugin->h.id) {
+		if (is_dir_empty(inode) == 0)
+			result =
+			    plugin_set_hash(&reiser4_inode_data(inode)->pset,
+					    &plugin->hash);
+		else
+			result = RETERR(-ENOTEMPTY);
+
+	}
+	return result;
+}
+
+static reiser4_plugin_ops hash_plugin_ops = {
+	.init = NULL,
+	.load = NULL,
+	.save_len = NULL,
+	.save = NULL,
+	.change = change_hash
+};
+
+/* hash plugins */
+hash_plugin hash_plugins[LAST_HASH_ID] = {
+	[RUPASOV_HASH_ID] = {
+		.h = {
+			.type_id = REISER4_HASH_PLUGIN_TYPE,
+			.id = RUPASOV_HASH_ID,
+			.pops = &hash_plugin_ops,
+			.label = "rupasov",
+			.desc = "Original Yura's hash",
+			.linkage = {NULL, NULL}
+		},
+		.hash = hash_rupasov
+	},
+	[R5_HASH_ID] = {
+		.h = {
+			.type_id = REISER4_HASH_PLUGIN_TYPE,
+			.id = R5_HASH_ID,
+			.pops = &hash_plugin_ops,
+			.label = "r5",
+			.desc = "r5 hash",
+			.linkage = {NULL, NULL}
+		},
+		.hash = hash_r5
+	},
+	[TEA_HASH_ID] = {
+		.h = {
+			.type_id = REISER4_HASH_PLUGIN_TYPE,
+			.id = TEA_HASH_ID,
+			.pops = &hash_plugin_ops,
+			.label = "tea",
+			.desc = "tea hash",
+			.linkage = {NULL, NULL}
+		},
+		.hash = hash_tea
+	},
+	[FNV1_HASH_ID] = {
+		.h = {
+			.type_id = REISER4_HASH_PLUGIN_TYPE,
+			.id = FNV1_HASH_ID,
+			.pops = &hash_plugin_ops,
+			.label = "fnv1",
+			.desc = "fnv1 hash",
+			.linkage = {NULL, NULL}
+		},
+		.hash = hash_fnv1
+	},
+	[DEGENERATE_HASH_ID] = {
+		.h = {
+			.type_id = REISER4_HASH_PLUGIN_TYPE,
+			.id = DEGENERATE_HASH_ID,
+			.pops = &hash_plugin_ops,
+			.label = "degenerate hash",
+			.desc = "Degenerate hash: only for testing",
+			.linkage = {NULL, NULL}
+		},
+		.hash = hash_deg
+	}
+};
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/inode_ops.c newtree/fs/reiser4/plugin/inode_ops.c
--- oldtree/fs/reiser4/plugin/inode_ops.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/inode_ops.c	2006-02-21 15:58:35.488751448 +0000
@@ -0,0 +1,888 @@
+/*
+ * Copyright 2005 by Hans Reiser, licensing governed by reiser4/README
+ */
+
+/*
+ * this file contains typical implementations for most of methods of struct
+ * inode_operations
+ */
+
+#include "../inode.h"
+#include "../safe_link.h"
+
+#include <linux/quotaops.h>
+#include <linux/namei.h>
+
+
+static int create_vfs_object(struct inode *parent, struct dentry *dentry,
+		      reiser4_object_create_data *data);
+
+/**
+ * create_common - create of inode operations
+ * @parent: inode of parent directory
+ * @dentry: dentry of new object to create
+ * @mode: the permissions to use
+ * @nameidata:
+ *
+ * This is common implementation of vfs's create method of struct
+ * inode_operations.
+ * Creates regular file using file plugin from parent directory plugin set.
+ */
+int create_common(struct inode *parent, struct dentry *dentry,
+		  int mode, struct nameidata *nameidata)
+{
+	reiser4_object_create_data data;
+
+	memset(&data, 0, sizeof data);
+	data.mode = S_IFREG | mode;
+	data.id = inode_regular_plugin(parent)->id;
+	return create_vfs_object(parent, dentry, &data);
+}
+
+int lookup_name(struct inode *dir, struct dentry *, reiser4_key *);
+void check_light_weight(struct inode *inode, struct inode *parent);
+
+/**
+ * lookup_common - lookup of inode operations
+ * @parent: inode of directory to lookup into
+ * @dentry: name to look for
+ * @nameidata:
+ *
+ * This is common implementation of vfs's lookup method of struct
+ * inode_operations.
+ */
+struct dentry *lookup_common(struct inode *parent, struct dentry *dentry,
+			     struct nameidata *nameidata)
+{
+	reiser4_context *ctx;
+	int result;
+	struct dentry *new;
+	struct inode *inode;
+	reiser4_dir_entry_desc entry;
+
+	ctx = init_context(parent->i_sb);
+	if (IS_ERR(ctx))
+		return (struct dentry *)ctx;
+
+	/* set up operations on dentry. */
+	dentry->d_op = &get_super_private(parent->i_sb)->ops.dentry;
+
+	result = lookup_name(parent, dentry, &entry.key);
+	if (result) {
+		context_set_commit_async(ctx);
+		reiser4_exit_context(ctx);
+		if (result == -ENOENT) {
+			/* object not found */
+			if (!IS_DEADDIR(parent))
+				d_add(dentry, NULL);
+			return NULL;
+		}
+		return ERR_PTR(result);
+	}
+
+	inode = reiser4_iget(parent->i_sb, &entry.key, 0);
+	if (IS_ERR(inode)) {
+		context_set_commit_async(ctx);
+		reiser4_exit_context(ctx);
+		return ERR_PTR(PTR_ERR(inode));
+	}
+
+	/* success */
+	check_light_weight(inode, parent);
+	new = d_splice_alias(inode, dentry);
+	reiser4_iget_complete(inode);
+
+	/* prevent balance_dirty_pages() from being called: we don't want to
+	 * do this under directory i_mutex. */
+	context_set_commit_async(ctx);
+	reiser4_exit_context(ctx);
+	return new;
+}
+
+static reiser4_block_nr common_estimate_link(struct inode *parent,
+					     struct inode *object);
+int reiser4_update_dir(struct inode *);
+
+/**
+ * link_common - link of inode operations
+ * @existing: dentry of object which is to get new name
+ * @parent: directory where new name is to be created
+ * @newname: new name
+ *
+ * This is common implementation of vfs's link method of struct
+ * inode_operations.
+ */
+int link_common(struct dentry *existing, struct inode *parent,
+		struct dentry *newname)
+{
+	reiser4_context *ctx;
+	int result;
+	struct inode *object;
+	dir_plugin *parent_dplug;
+	reiser4_dir_entry_desc entry;
+	reiser4_object_create_data data;
+	reiser4_block_nr reserve;
+
+	ctx = init_context(parent->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	assert("nikita-1431", existing != NULL);
+	assert("nikita-1432", parent != NULL);
+	assert("nikita-1433", newname != NULL);
+
+	object = existing->d_inode;
+	assert("nikita-1434", object != NULL);
+
+	/* check for race with create_object() */
+	if (inode_get_flag(object, REISER4_IMMUTABLE)) {
+		context_set_commit_async(ctx);
+		reiser4_exit_context(ctx);
+		return RETERR(-E_REPEAT);
+	}
+
+	parent_dplug = inode_dir_plugin(parent);
+
+	memset(&entry, 0, sizeof entry);
+	entry.obj = object;
+
+	data.mode = object->i_mode;
+	data.id = inode_file_plugin(object)->h.id;
+
+	reserve = common_estimate_link(parent, existing->d_inode);
+	if ((__s64) reserve < 0) {
+		context_set_commit_async(ctx);
+		reiser4_exit_context(ctx);
+		return reserve;
+	}
+
+	if (reiser4_grab_space(reserve, BA_CAN_COMMIT)) {
+		context_set_commit_async(ctx);
+		reiser4_exit_context(ctx);
+		return RETERR(-ENOSPC);
+	}
+
+	/*
+	 * Subtle race handling: sys_link() doesn't take i_mutex on @parent. It
+	 * means that link(2) can race against unlink(2) or rename(2), and
+	 * inode is dead (->i_nlink == 0) when reiser4_link() is entered.
+	 *
+	 * For such inode we have to undo special processing done in
+	 * reiser4_unlink() viz. creation of safe-link.
+	 */
+	if (unlikely(object->i_nlink == 0)) {
+		result = safe_link_del(tree_by_inode(object),
+				       get_inode_oid(object), SAFE_UNLINK);
+		if (result != 0) {
+			context_set_commit_async(ctx);
+			reiser4_exit_context(ctx);
+			return result;
+		}
+	}
+
+	/* increment nlink of @existing and update its stat data */
+	result = reiser4_add_nlink(object, parent, 1);
+	if (result == 0) {
+		/* add entry to the parent */
+		result =
+		    parent_dplug->add_entry(parent, newname, &data, &entry);
+		if (result != 0) {
+			/* failed to add entry to the parent, decrement nlink
+			   of @existing */
+			reiser4_del_nlink(object, parent, 1);
+			/*
+			 * now, if that failed, we have a file with too big
+			 * nlink---space leak, much better than directory
+			 * entry pointing to nowhere
+			 */
+		}
+	}
+	if (result == 0) {
+		atomic_inc(&object->i_count);
+		/*
+		 * Upon successful completion, link() shall mark for update
+		 * the st_ctime field of the file. Also, the st_ctime and
+		 * st_mtime fields of the directory that contains the new
+		 * entry shall be marked for update. --SUS
+		 */
+		result = reiser4_update_dir(parent);
+	}
+	if (result == 0)
+		d_instantiate(newname, existing->d_inode);
+
+	context_set_commit_async(ctx);
+	reiser4_exit_context(ctx);
+	return result;
+}
+
+static int unlink_check_and_grab(struct inode *parent, struct dentry *victim);
+
+/**
+ * unlink_common - unlink of inode operations
+ * @parent: inode of directory to remove name from
+ * @victim: name to be removed
+ *
+ * This is common implementation of vfs's unlink method of struct
+ * inode_operations.
+ */
+int unlink_common(struct inode *parent, struct dentry *victim)
+{
+	reiser4_context *ctx;
+	int result;
+	struct inode *object;
+	file_plugin *fplug;
+
+	ctx = init_context(parent->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	object = victim->d_inode;
+	fplug = inode_file_plugin(object);
+	assert("nikita-2882", fplug->detach != NULL);
+
+	result = unlink_check_and_grab(parent, victim);
+	if (result != 0) {
+		context_set_commit_async(ctx);
+		reiser4_exit_context(ctx);
+		return result;
+	}
+
+	result = fplug->detach(object, parent);
+	if (result == 0) {
+		dir_plugin *parent_dplug;
+		reiser4_dir_entry_desc entry;
+
+		parent_dplug = inode_dir_plugin(parent);
+		memset(&entry, 0, sizeof entry);
+
+		/* first, delete directory entry */
+		result = parent_dplug->rem_entry(parent, victim, &entry);
+		if (result == 0) {
+			/*
+			 * if name was removed successfully, we _have_ to
+			 * return 0 from this function, because upper level
+			 * caller (vfs_{rmdir,unlink}) expect this.
+			 *
+			 * now that directory entry is removed, update
+			 * stat-data
+			 */
+			reiser4_del_nlink(object, parent, 1);
+			/*
+			 * Upon successful completion, unlink() shall mark for
+			 * update the st_ctime and st_mtime fields of the
+			 * parent directory. Also, if the file's link count is
+			 * not 0, the st_ctime field of the file shall be
+			 * marked for update. --SUS
+			 */
+			reiser4_update_dir(parent);
+			/* add safe-link for this file */
+			if (object->i_nlink == 0)
+				safe_link_add(object, SAFE_UNLINK);
+		}
+	}
+
+	if (unlikely(result != 0)) {
+		if (result != -ENOMEM)
+			warning("nikita-3398", "Cannot unlink %llu (%i)",
+				(unsigned long long)get_inode_oid(object),
+				result);
+		/* if operation failed commit pending inode modifications to
+		 * the stat-data */
+		reiser4_update_sd(object);
+		reiser4_update_sd(parent);
+	}
+
+	reiser4_release_reserved(object->i_sb);
+
+	/* @object's i_ctime was updated by ->rem_link() method(). */
+
+	/* @victim can be already removed from the disk by this time. Inode is
+	   then marked so that iput() wouldn't try to remove stat data. But
+	   inode itself is still there.
+	 */
+
+	/*
+	 * we cannot release directory semaphore here, because name has
+	 * already been deleted, but dentry (@victim) still exists.  Prevent
+	 * balance_dirty_pages() from being called on exiting this context: we
+	 * don't want to do this under directory i_mutex.
+	 */
+	context_set_commit_async(ctx);
+	reiser4_exit_context(ctx);
+	return result;
+}
+
+/**
+ * symlink_common - symlink of inode operations
+ * @parent: inode of parent directory
+ * @dentry: dentry of object to be created
+ * @linkname: string symlink is to contain
+ *
+ * This is common implementation of vfs's symlink method of struct
+ * inode_operations.
+ * Creates object using file plugin SYMLINK_FILE_PLUGIN_ID.
+ */
+int symlink_common(struct inode *parent, struct dentry *dentry,
+		   const char *linkname)
+{
+	reiser4_object_create_data data;
+
+	memset(&data, 0, sizeof data);
+	data.name = linkname;
+	data.id = SYMLINK_FILE_PLUGIN_ID;
+	data.mode = S_IFLNK | S_IRWXUGO;
+	return create_vfs_object(parent, dentry, &data);
+}
+
+/**
+ * mkdir_common - mkdir of inode operations
+ * @parent: inode of parent directory
+ * @dentry: dentry of object to be created
+ * @mode: the permissions to use
+ *
+ * This is common implementation of vfs's mkdir method of struct
+ * inode_operations.
+ * Creates object using file plugin DIRECTORY_FILE_PLUGIN_ID.
+ */
+int mkdir_common(struct inode *parent, struct dentry *dentry, int mode)
+{
+	reiser4_object_create_data data;
+
+	memset(&data, 0, sizeof data);
+	data.mode = S_IFDIR | mode;
+	data.id = DIRECTORY_FILE_PLUGIN_ID;
+	return create_vfs_object(parent, dentry, &data);
+}
+
+/**
+ * mknod_common - mknod of inode operations
+ * @parent: inode of parent directory
+ * @dentry: dentry of object to be created
+ * @mode: the permissions to use and file type
+ * @rdev: minor and major of new device file
+ *
+ * This is common implementation of vfs's mknod method of struct
+ * inode_operations.
+ * Creates object using file plugin SPECIAL_FILE_PLUGIN_ID.
+ */
+int mknod_common(struct inode *parent, struct dentry *dentry,
+		 int mode, dev_t rdev)
+{
+	reiser4_object_create_data data;
+
+	memset(&data, 0, sizeof data);
+	data.mode = mode;
+	data.rdev = rdev;
+	data.id = SPECIAL_FILE_PLUGIN_ID;
+	return create_vfs_object(parent, dentry, &data);
+}
+
+/*
+ * implementation of vfs's rename method of struct inode_operations for typical
+ * directory is in inode_ops_rename.c
+ */
+
+/**
+ * follow_link_common - follow_link of inode operations
+ * @dentry: dentry of symlink
+ * @data:
+ *
+ * This is common implementation of vfs's followlink method of struct
+ * inode_operations.
+ * Assumes that inode's generic_ip points to the content of symbolic link.
+ */
+void *follow_link_common(struct dentry *dentry, struct nameidata *nd)
+{
+	assert("vs-851", S_ISLNK(dentry->d_inode->i_mode));
+
+	if (!dentry->d_inode->u.generic_ip
+	    || !inode_get_flag(dentry->d_inode, REISER4_GENERIC_PTR_USED))
+		return ERR_PTR(RETERR(-EINVAL));
+	nd_set_link(nd, dentry->d_inode->u.generic_ip);
+	return NULL;
+}
+
+/**
+ * permission_common - permission of inode operations
+ * @inode: inode to check permissions for
+ * @mask: mode bits to check permissions for
+ * @nameidata:
+ *
+ * Uses generic function to check for rwx permissions.
+ */
+int permission_common(struct inode *inode, int mask,
+		      struct nameidata *nameidata)
+{
+	return generic_permission(inode, mask, NULL);
+}
+
+static int setattr_reserve(reiser4_tree *);
+
+/* this is common implementation of vfs's setattr method of struct
+   inode_operations
+*/
+int setattr_common(struct dentry *dentry, struct iattr *attr)
+{
+	reiser4_context *ctx;
+	struct inode *inode;
+	int result;
+
+	inode = dentry->d_inode;
+	result = inode_change_ok(inode, attr);
+	if (result)
+		return result;
+
+	ctx = init_context(inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	assert("nikita-3119", !(attr->ia_valid & ATTR_SIZE));
+
+	/*
+	 * grab disk space and call standard inode_setattr().
+	 */
+	result = setattr_reserve(tree_by_inode(inode));
+	if (!result) {
+		if ((attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid)
+		    || (attr->ia_valid & ATTR_GID
+			&& attr->ia_gid != inode->i_gid)) {
+			result = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
+			if (result) {
+				all_grabbed2free();
+				context_set_commit_async(ctx);
+				reiser4_exit_context(ctx);
+				return result;
+			}
+		}
+		result = inode_setattr(inode, attr);
+		if (!result)
+			reiser4_update_sd(inode);
+	}
+
+	all_grabbed2free();
+	context_set_commit_async(ctx);
+	reiser4_exit_context(ctx);
+	return result;
+}
+
+/* this is common implementation of vfs's getattr method of struct
+   inode_operations
+*/
+int
+getattr_common(struct vfsmount *mnt UNUSED_ARG, struct dentry *dentry,
+	       struct kstat *stat)
+{
+	struct inode *obj;
+
+	assert("nikita-2298", dentry != NULL);
+	assert("nikita-2299", stat != NULL);
+	assert("nikita-2300", dentry->d_inode != NULL);
+
+	obj = dentry->d_inode;
+
+	stat->dev = obj->i_sb->s_dev;
+	stat->ino = oid_to_uino(get_inode_oid(obj));
+	stat->mode = obj->i_mode;
+	/* don't confuse userland with huge nlink. This is not entirely
+	 * correct, because nlink_t is not necessary 16 bit signed. */
+	stat->nlink = min(obj->i_nlink, (typeof(obj->i_nlink)) 0x7fff);
+	stat->uid = obj->i_uid;
+	stat->gid = obj->i_gid;
+	stat->rdev = obj->i_rdev;
+	stat->atime = obj->i_atime;
+	stat->mtime = obj->i_mtime;
+	stat->ctime = obj->i_ctime;
+	stat->size = obj->i_size;
+	stat->blocks =
+	    (inode_get_bytes(obj) + VFS_BLKSIZE - 1) >> VFS_BLKSIZE_BITS;
+	/* "preferred" blocksize for efficient file system I/O */
+	stat->blksize = get_super_private(obj->i_sb)->optimal_io_size;
+
+	return 0;
+}
+
+/* Estimate the maximum amount of nodes which might be allocated or changed on
+   typical new object creation. Typical creation consists of calling create
+   method of file plugin, adding directory entry to parent and update parent
+   directory's stat data.
+*/
+static reiser4_block_nr estimate_create_vfs_object(struct inode *parent,	/* parent object */
+						   struct inode *object
+						   /* object */ )
+{
+	assert("vpf-309", parent != NULL);
+	assert("vpf-307", object != NULL);
+
+	return
+	    /* object creation estimation */
+	    inode_file_plugin(object)->estimate.create(object) +
+	    /* stat data of parent directory estimation */
+	    inode_file_plugin(parent)->estimate.update(parent) +
+	    /* adding entry estimation */
+	    inode_dir_plugin(parent)->estimate.add_entry(parent) +
+	    /* to undo in the case of failure */
+	    inode_dir_plugin(parent)->estimate.rem_entry(parent);
+}
+
+/* Create child in directory.
+
+   . get object's plugin
+   . get fresh inode
+   . initialize inode
+   . add object's stat-data
+   . initialize object's directory
+   . add entry to the parent
+   . instantiate dentry
+
+*/
+static int do_create_vfs_child(reiser4_object_create_data * data,	/* parameters of new
+									   object */
+			       struct inode **retobj)
+{
+	int result;
+
+	struct dentry *dentry;	/* parent object */
+	struct inode *parent;	/* new name */
+
+	dir_plugin *par_dir;	/* directory plugin on the parent */
+	dir_plugin *obj_dir;	/* directory plugin on the new object */
+	file_plugin *obj_plug;	/* object plugin on the new object */
+	struct inode *object;	/* new object */
+	reiser4_block_nr reserve;
+
+	reiser4_dir_entry_desc entry;	/* new directory entry */
+
+	assert("nikita-1420", data != NULL);
+	parent = data->parent;
+	dentry = data->dentry;
+
+	assert("nikita-1418", parent != NULL);
+	assert("nikita-1419", dentry != NULL);
+
+	/* check, that name is acceptable for parent */
+	par_dir = inode_dir_plugin(parent);
+	if (par_dir->is_name_acceptable &&
+	    !par_dir->is_name_acceptable(parent,
+					 dentry->d_name.name,
+					 (int)dentry->d_name.len))
+		return RETERR(-ENAMETOOLONG);
+
+	result = 0;
+	obj_plug = file_plugin_by_id((int)data->id);
+	if (obj_plug == NULL) {
+		warning("nikita-430", "Cannot find plugin %i", data->id);
+		return RETERR(-ENOENT);
+	}
+	object = new_inode(parent->i_sb);
+	if (object == NULL)
+		return RETERR(-ENOMEM);
+	/* we'll update i_nlink below */
+	object->i_nlink = 0;
+	/* new_inode() initializes i_ino to "arbitrary" value. Reset it to 0,
+	 * to simplify error handling: if some error occurs before i_ino is
+	 * initialized with oid, i_ino should already be set to some
+	 * distinguished value. */
+	object->i_ino = 0;
+
+	/* So that on error iput will be called. */
+	*retobj = object;
+
+	if (DQUOT_ALLOC_INODE(object)) {
+		DQUOT_DROP(object);
+		object->i_flags |= S_NOQUOTA;
+		return RETERR(-EDQUOT);
+	}
+
+	memset(&entry, 0, sizeof entry);
+	entry.obj = object;
+
+	plugin_set_file(&reiser4_inode_data(object)->pset, obj_plug);
+	result = obj_plug->set_plug_in_inode(object, parent, data);
+	if (result) {
+		warning("nikita-431", "Cannot install plugin %i on %llx",
+			data->id, (unsigned long long)get_inode_oid(object));
+		DQUOT_FREE_INODE(object);
+		object->i_flags |= S_NOQUOTA;
+		return result;
+	}
+
+	/* reget plugin after installation */
+	obj_plug = inode_file_plugin(object);
+
+	if (obj_plug->create_object == NULL) {
+		DQUOT_FREE_INODE(object);
+		object->i_flags |= S_NOQUOTA;
+		return RETERR(-EPERM);
+	}
+
+	/* if any of hash, tail, sd or permission plugins for newly created
+	   object are not set yet set them here inheriting them from parent
+	   directory
+	 */
+	assert("nikita-2070", obj_plug->adjust_to_parent != NULL);
+	result = obj_plug->adjust_to_parent(object,
+					    parent,
+					    object->i_sb->s_root->d_inode);
+	if (result != 0) {
+		warning("nikita-432", "Cannot inherit from %llx to %llx",
+			(unsigned long long)get_inode_oid(parent),
+			(unsigned long long)get_inode_oid(object));
+		DQUOT_FREE_INODE(object);
+		object->i_flags |= S_NOQUOTA;
+		return result;
+	}
+
+	/* setup inode and file-operations for this inode */
+	setup_inode_ops(object, data);
+
+	/* call file plugin's method to initialize plugin specific part of
+	 * inode */
+	if (obj_plug->init_inode_data)
+		obj_plug->init_inode_data(object, data, 1 /*create */ );
+
+	/* obtain directory plugin (if any) for new object. */
+	obj_dir = inode_dir_plugin(object);
+	if (obj_dir != NULL && obj_dir->init == NULL) {
+		DQUOT_FREE_INODE(object);
+		object->i_flags |= S_NOQUOTA;
+		return RETERR(-EPERM);
+	}
+
+	reiser4_inode_data(object)->locality_id = get_inode_oid(parent);
+
+	reserve = estimate_create_vfs_object(parent, object);
+	if (reiser4_grab_space(reserve, BA_CAN_COMMIT)) {
+		DQUOT_FREE_INODE(object);
+		object->i_flags |= S_NOQUOTA;
+		return RETERR(-ENOSPC);
+	}
+
+	/* mark inode `immutable'. We disable changes to the file being
+	   created until valid directory entry for it is inserted. Otherwise,
+	   if file were expanded and insertion of directory entry fails, we
+	   have to remove file, but we only alloted enough space in
+	   transaction to remove _empty_ file. 3.x code used to remove stat
+	   data in different transaction thus possibly leaking disk space on
+	   crash. This all only matters if it's possible to access file
+	   without name, for example, by inode number
+	 */
+	inode_set_flag(object, REISER4_IMMUTABLE);
+
+	/* create empty object, this includes allocation of new objectid. For
+	   directories this implies creation of dot and dotdot  */
+	assert("nikita-2265", inode_get_flag(object, REISER4_NO_SD));
+
+	/* mark inode as `loaded'. From this point onward
+	   reiser4_delete_inode() will try to remove its stat-data. */
+	inode_set_flag(object, REISER4_LOADED);
+
+	result = obj_plug->create_object(object, parent, data);
+	if (result != 0) {
+		inode_clr_flag(object, REISER4_IMMUTABLE);
+		if (result != -ENAMETOOLONG && result != -ENOMEM)
+			warning("nikita-2219",
+				"Failed to create sd for %llu",
+				(unsigned long long)get_inode_oid(object));
+		DQUOT_FREE_INODE(object);
+		object->i_flags |= S_NOQUOTA;
+		return result;
+	}
+
+	if (obj_dir != NULL)
+		result = obj_dir->init(object, parent, data);
+	if (result == 0) {
+		assert("nikita-434", !inode_get_flag(object, REISER4_NO_SD));
+		/* insert inode into VFS hash table */
+		insert_inode_hash(object);
+		/* create entry */
+		result = par_dir->add_entry(parent, dentry, data, &entry);
+		if (result == 0) {
+			result = reiser4_add_nlink(object, parent, 0);
+			/* If O_CREAT is set and the file did not previously
+			   exist, upon successful completion, open() shall
+			   mark for update the st_atime, st_ctime, and
+			   st_mtime fields of the file and the st_ctime and
+			   st_mtime fields of the parent directory. --SUS
+			 */
+			/* @object times are already updated by
+			   reiser4_add_nlink() */
+			if (result == 0)
+				reiser4_update_dir(parent);
+			if (result != 0)
+				/* cleanup failure to add nlink */
+				par_dir->rem_entry(parent, dentry, &entry);
+		}
+		if (result != 0)
+			/* cleanup failure to add entry */
+			obj_plug->detach(object, parent);
+	} else if (result != -ENOMEM)
+		warning("nikita-2219", "Failed to initialize dir for %llu: %i",
+			(unsigned long long)get_inode_oid(object), result);
+
+	/*
+	 * update stat-data, committing all pending modifications to the inode
+	 * fields.
+	 */
+	reiser4_update_sd(object);
+	if (result != 0) {
+		DQUOT_FREE_INODE(object);
+		object->i_flags |= S_NOQUOTA;
+		/* if everything was ok (result == 0), parent stat-data is
+		 * already updated above (update_parent_dir()) */
+		reiser4_update_sd(parent);
+		/* failure to create entry, remove object */
+		obj_plug->delete_object(object);
+	}
+
+	/* file has name now, clear immutable flag */
+	inode_clr_flag(object, REISER4_IMMUTABLE);
+
+	/* on error, iput() will call ->delete_inode(). We should keep track
+	   of the existence of stat-data for this inode and avoid attempt to
+	   remove it in reiser4_delete_inode(). This is accomplished through
+	   REISER4_NO_SD bit in inode.u.reiser4_i.plugin.flags
+	 */
+	return result;
+}
+
+/* this is helper for common implementations of reiser4_mkdir, reiser4_create,
+   reiser4_mknod and reiser4_symlink
+*/
+static int
+create_vfs_object(struct inode *parent,
+		  struct dentry *dentry, reiser4_object_create_data * data)
+{
+	reiser4_context *ctx;
+	int result;
+	struct inode *child;
+
+	ctx = init_context(parent->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+	context_set_commit_async(ctx);
+
+	data->parent = parent;
+	data->dentry = dentry;
+	child = NULL;
+	result = do_create_vfs_child(data, &child);
+	if (unlikely(result != 0)) {
+		if (child != NULL) {
+			reiser4_make_bad_inode(child);
+			iput(child);
+		}
+	} else
+		d_instantiate(dentry, child);
+
+	reiser4_exit_context(ctx);
+	return result;
+}
+
+/* helper for link_common. Estimate disk space necessary to add a link
+   from @parent to @object
+*/
+static reiser4_block_nr common_estimate_link(struct inode *parent,	/* parent directory */
+					     struct inode *object
+					     /* object to which new link is being cerated */
+					     )
+{
+	reiser4_block_nr res = 0;
+	file_plugin *fplug;
+	dir_plugin *dplug;
+
+	assert("vpf-317", object != NULL);
+	assert("vpf-318", parent != NULL);
+
+	fplug = inode_file_plugin(object);
+	dplug = inode_dir_plugin(parent);
+	/* VS-FIXME-HANS: why do we do fplug->estimate.update(object) twice instead of multiplying by 2? */
+	/* reiser4_add_nlink(object) */
+	res += fplug->estimate.update(object);
+	/* add_entry(parent) */
+	res += dplug->estimate.add_entry(parent);
+	/* reiser4_del_nlink(object) */
+	res += fplug->estimate.update(object);
+	/* update_dir(parent) */
+	res += inode_file_plugin(parent)->estimate.update(parent);
+	/* safe-link */
+	res += estimate_one_item_removal(tree_by_inode(object));
+
+	return res;
+}
+
+/* Estimate disk space necessary to remove a link between @parent and
+   @object.
+*/
+static reiser4_block_nr estimate_unlink(struct inode *parent,	/* parent directory */
+					struct inode *object
+					/* object to which new link is being cerated */
+					)
+{
+	reiser4_block_nr res = 0;
+	file_plugin *fplug;
+	dir_plugin *dplug;
+
+	assert("vpf-317", object != NULL);
+	assert("vpf-318", parent != NULL);
+
+	fplug = inode_file_plugin(object);
+	dplug = inode_dir_plugin(parent);
+
+	/* rem_entry(parent) */
+	res += dplug->estimate.rem_entry(parent);
+	/* reiser4_del_nlink(object) */
+	res += fplug->estimate.update(object);
+	/* update_dir(parent) */
+	res += inode_file_plugin(parent)->estimate.update(parent);
+	/* fplug->unlink */
+	res += fplug->estimate.unlink(object, parent);
+	/* safe-link */
+	res += estimate_one_insert_item(tree_by_inode(object));
+
+	return res;
+}
+
+/* helper for unlink_common. Estimate and grab space for unlink. */
+static int unlink_check_and_grab(struct inode *parent, struct dentry *victim)
+{
+	file_plugin *fplug;
+	struct inode *child;
+	int result;
+
+	result = 0;
+	child = victim->d_inode;
+	fplug = inode_file_plugin(child);
+
+	/* check for race with create_object() */
+	if (inode_get_flag(child, REISER4_IMMUTABLE))
+		return RETERR(-E_REPEAT);
+	/* object being deleted should have stat data */
+	assert("vs-949", !inode_get_flag(child, REISER4_NO_SD));
+
+	/* ask object plugin */
+	if (fplug->can_rem_link != NULL && !fplug->can_rem_link(child))
+		return RETERR(-ENOTEMPTY);
+
+	result = (int)estimate_unlink(parent, child);
+	if (result < 0)
+		return result;
+
+	return reiser4_grab_reserved(child->i_sb, result, BA_CAN_COMMIT);
+}
+
+/* helper for setattr_common */
+static int setattr_reserve(reiser4_tree * tree)
+{
+	assert("vs-1096", is_grab_enabled(get_current_context()));
+	return reiser4_grab_space(estimate_one_insert_into_item(tree),
+				  BA_CAN_COMMIT);
+}
+
+/* helper function. Standards require that for many file-system operations
+   on success ctime and mtime of parent directory is to be updated. */
+int reiser4_update_dir(struct inode *dir)
+{
+	assert("nikita-2525", dir != NULL);
+
+	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+	return reiser4_update_sd(dir);
+}
diff -urN oldtree/fs/reiser4/plugin/inode_ops_rename.c newtree/fs/reiser4/plugin/inode_ops_rename.c
--- oldtree/fs/reiser4/plugin/inode_ops_rename.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/inode_ops_rename.c	2006-02-21 15:58:34.603885968 +0000
@@ -0,0 +1,904 @@
+/* Copyright 2001, 2002, 2003, 2004 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+#include "../inode.h"
+#include "../safe_link.h"
+
+static const char *possible_leak = "Possible disk space leak.";
+
+/* re-bind existing name at @from_coord in @from_dir to point to @to_inode.
+
+   Helper function called from hashed_rename() */
+static int replace_name(struct inode *to_inode,	/* inode where @from_coord is
+						 * to be re-targeted at */
+			struct inode *from_dir,	/* directory where @from_coord
+						 * lives */
+			struct inode *from_inode,	/* inode @from_coord
+							 * originally point to */
+			coord_t * from_coord,	/* where directory entry is in
+						 * the tree */
+			lock_handle * from_lh /* lock handle on @from_coord */ )
+{
+	item_plugin *from_item;
+	int result;
+	znode *node;
+
+	coord_clear_iplug(from_coord);
+	node = from_coord->node;
+	result = zload(node);
+	if (result != 0)
+		return result;
+	from_item = item_plugin_by_coord(from_coord);
+	if (item_type_by_coord(from_coord) == DIR_ENTRY_ITEM_TYPE) {
+		reiser4_key to_key;
+
+		build_sd_key(to_inode, &to_key);
+
+		/* everything is found and prepared to change directory entry
+		   at @from_coord to point to @to_inode.
+
+		   @to_inode is just about to get new name, so bump its link
+		   counter.
+
+		 */
+		result = reiser4_add_nlink(to_inode, from_dir, 0);
+		if (result != 0) {
+			/* Don't issue warning: this may be plain -EMLINK */
+			zrelse(node);
+			return result;
+		}
+
+		result =
+		    from_item->s.dir.update_key(from_coord, &to_key, from_lh);
+		if (result != 0) {
+			reiser4_del_nlink(to_inode, from_dir, 0);
+			zrelse(node);
+			return result;
+		}
+
+		/* @from_inode just lost its name, he-he.
+
+		   If @from_inode was directory, it contained dotdot pointing
+		   to @from_dir. @from_dir i_nlink will be decreased when
+		   iput() will be called on @from_inode.
+
+		   If file-system is not ADG (hard-links are
+		   supported on directories), iput(from_inode) will not remove
+		   @from_inode, and thus above is incorrect, but hard-links on
+		   directories are problematic in many other respects.
+		 */
+		result = reiser4_del_nlink(from_inode, from_dir, 0);
+		if (result != 0) {
+			warning("nikita-2330",
+				"Cannot remove link from source: %i. %s",
+				result, possible_leak);
+		}
+		/* Has to return success, because entry is already
+		 * modified. */
+		result = 0;
+
+		/* NOTE-NIKITA consider calling plugin method in stead of
+		   accessing inode fields directly. */
+		from_dir->i_mtime = CURRENT_TIME;
+	} else {
+		warning("nikita-2326", "Unexpected item type");
+		result = RETERR(-EIO);
+	}
+	zrelse(node);
+	return result;
+}
+
+/* add new entry pointing to @inode into @dir at @coord, locked by @lh
+
+   Helper function used by hashed_rename(). */
+static int add_name(struct inode *inode,	/* inode where @coord is to be
+						 * re-targeted at */
+		    struct inode *dir,	/* directory where @coord lives */
+		    struct dentry *name,	/* new name */
+		    coord_t * coord,	/* where directory entry is in the tree */
+		    lock_handle * lh,	/* lock handle on @coord */
+		    int is_dir /* true, if @inode is directory */ )
+{
+	int result;
+	reiser4_dir_entry_desc entry;
+
+	assert("nikita-2333", lh->node == coord->node);
+	assert("nikita-2334", is_dir == S_ISDIR(inode->i_mode));
+
+	memset(&entry, 0, sizeof entry);
+	entry.obj = inode;
+	/* build key of directory entry description */
+	inode_dir_plugin(dir)->build_entry_key(dir, &name->d_name, &entry.key);
+
+	/* ext2 does this in different order: first inserts new entry,
+	   then increases directory nlink. We don't want do this,
+	   because reiser4_add_nlink() calls ->add_link() plugin
+	   method that can fail for whatever reason, leaving as with
+	   cleanup problems.
+	 */
+	/* @inode is getting new name */
+	reiser4_add_nlink(inode, dir, 0);
+	/* create @new_name in @new_dir pointing to
+	   @old_inode */
+	result = WITH_COORD(coord,
+			    inode_dir_item_plugin(dir)->s.dir.add_entry(dir,
+									coord,
+									lh,
+									name,
+									&entry));
+	if (result != 0) {
+		int result2;
+		result2 = reiser4_del_nlink(inode, dir, 0);
+		if (result2 != 0) {
+			warning("nikita-2327",
+				"Cannot drop link on %lli %i. %s",
+				(unsigned long long)get_inode_oid(inode),
+				result2, possible_leak);
+		}
+	} else
+		INODE_INC_FIELD(dir, i_size);
+	return result;
+}
+
+static reiser4_block_nr estimate_rename(struct inode *old_dir,	/* directory where @old is located */
+					struct dentry *old_name,	/* old name */
+					struct inode *new_dir,	/* directory where @new is located */
+					struct dentry *new_name /* new name */ )
+{
+	reiser4_block_nr res1, res2;
+	dir_plugin *p_parent_old, *p_parent_new;
+	file_plugin *p_child_old, *p_child_new;
+
+	assert("vpf-311", old_dir != NULL);
+	assert("vpf-312", new_dir != NULL);
+	assert("vpf-313", old_name != NULL);
+	assert("vpf-314", new_name != NULL);
+
+	p_parent_old = inode_dir_plugin(old_dir);
+	p_parent_new = inode_dir_plugin(new_dir);
+	p_child_old = inode_file_plugin(old_name->d_inode);
+	if (new_name->d_inode)
+		p_child_new = inode_file_plugin(new_name->d_inode);
+	else
+		p_child_new = NULL;
+
+	/* find_entry - can insert one leaf. */
+	res1 = res2 = 1;
+
+	/* replace_name */
+	{
+		/* reiser4_add_nlink(p_child_old) and reiser4_del_nlink(p_child_old) */
+		res1 += 2 * p_child_old->estimate.update(old_name->d_inode);
+		/* update key */
+		res1 += 1;
+		/* reiser4_del_nlink(p_child_new) */
+		if (p_child_new)
+			res1 += p_child_new->estimate.update(new_name->d_inode);
+	}
+
+	/* else add_name */
+	{
+		/* reiser4_add_nlink(p_parent_new) and reiser4_del_nlink(p_parent_new) */
+		res2 +=
+		    2 * inode_file_plugin(new_dir)->estimate.update(new_dir);
+		/* reiser4_add_nlink(p_parent_old) */
+		res2 += p_child_old->estimate.update(old_name->d_inode);
+		/* add_entry(p_parent_new) */
+		res2 += p_parent_new->estimate.add_entry(new_dir);
+		/* reiser4_del_nlink(p_parent_old) */
+		res2 += p_child_old->estimate.update(old_name->d_inode);
+	}
+
+	res1 = res1 < res2 ? res2 : res1;
+
+	/* reiser4_write_sd(p_parent_new) */
+	res1 += inode_file_plugin(new_dir)->estimate.update(new_dir);
+
+	/* reiser4_write_sd(p_child_new) */
+	if (p_child_new)
+		res1 += p_child_new->estimate.update(new_name->d_inode);
+
+	/* hashed_rem_entry(p_parent_old) */
+	res1 += p_parent_old->estimate.rem_entry(old_dir);
+
+	/* reiser4_del_nlink(p_child_old) */
+	res1 += p_child_old->estimate.update(old_name->d_inode);
+
+	/* replace_name */
+	{
+		/* reiser4_add_nlink(p_parent_dir_new) */
+		res1 += inode_file_plugin(new_dir)->estimate.update(new_dir);
+		/* update_key */
+		res1 += 1;
+		/* reiser4_del_nlink(p_parent_new) */
+		res1 += inode_file_plugin(new_dir)->estimate.update(new_dir);
+		/* reiser4_del_nlink(p_parent_old) */
+		res1 += inode_file_plugin(old_dir)->estimate.update(old_dir);
+	}
+
+	/* reiser4_write_sd(p_parent_old) */
+	res1 += inode_file_plugin(old_dir)->estimate.update(old_dir);
+
+	/* reiser4_write_sd(p_child_old) */
+	res1 += p_child_old->estimate.update(old_name->d_inode);
+
+	return res1;
+}
+
+static int hashed_rename_estimate_and_grab(struct inode *old_dir,	/* directory where @old is located */
+					   struct dentry *old_name,	/* old name */
+					   struct inode *new_dir,	/* directory where @new is located */
+					   struct dentry *new_name
+					   /* new name */ )
+{
+	reiser4_block_nr reserve;
+
+	reserve = estimate_rename(old_dir, old_name, new_dir, new_name);
+
+	if (reiser4_grab_space(reserve, BA_CAN_COMMIT))
+		return RETERR(-ENOSPC);
+
+	return 0;
+}
+
+/* check whether @old_inode and @new_inode can be moved within file system
+ * tree. This singles out attempts to rename pseudo-files, for example. */
+static int can_rename(struct inode *old_dir, struct inode *old_inode,
+		      struct inode *new_dir, struct inode *new_inode)
+{
+	file_plugin *fplug;
+	dir_plugin *dplug;
+
+	assert("nikita-3370", old_inode != NULL);
+
+	dplug = inode_dir_plugin(new_dir);
+	fplug = inode_file_plugin(old_inode);
+
+	if (dplug == NULL)
+		return RETERR(-ENOTDIR);
+	else if (new_dir->i_op->create == NULL)
+		return RETERR(-EPERM);
+	else if (!fplug->can_add_link(old_inode))
+		return RETERR(-EMLINK);
+	else if (new_inode != NULL) {
+		fplug = inode_file_plugin(new_inode);
+		if (fplug->can_rem_link != NULL &&
+		    !fplug->can_rem_link(new_inode))
+			return RETERR(-EBUSY);
+	}
+	return 0;
+}
+
+int find_entry(struct inode *, struct dentry *, lock_handle *,
+	       znode_lock_mode, reiser4_dir_entry_desc *);
+int reiser4_update_dir(struct inode *);
+
+/* this is common implementation of vfs's rename method of struct
+   inode_operations
+   See comments in the body.
+
+   It is arguable that this function can be made generic so, that it
+   will be applicable to any kind of directory plugin that deals with
+   directories composed out of directory entries. The only obstacle
+   here is that we don't have any data-type to represent directory
+   entry. This should be re-considered when more than one different
+   directory plugin will be implemented.
+*/
+int rename_common(struct inode *old_dir /* directory where @old is located */ ,
+		  struct dentry *old_name /* old name */ ,
+		  struct inode *new_dir /* directory where @new is located */ ,
+		  struct dentry *new_name /* new name */ )
+{
+	/* From `The Open Group Base Specifications Issue 6'
+
+	   If either the old or new argument names a symbolic link, rename()
+	   shall operate on the symbolic link itself, and shall not resolve
+	   the last component of the argument. If the old argument and the new
+	   argument resolve to the same existing file, rename() shall return
+	   successfully and perform no other action.
+
+	   [this is done by VFS: vfs_rename()]
+
+	   If the old argument points to the pathname of a file that is not a
+	   directory, the new argument shall not point to the pathname of a
+	   directory.
+
+	   [checked by VFS: vfs_rename->may_delete()]
+
+	   If the link named by the new argument exists, it shall
+	   be removed and old renamed to new. In this case, a link named new
+	   shall remain visible to other processes throughout the renaming
+	   operation and refer either to the file referred to by new or old
+	   before the operation began.
+
+	   [we should assure this]
+
+	   Write access permission is required for
+	   both the directory containing old and the directory containing new.
+
+	   [checked by VFS: vfs_rename->may_delete(), may_create()]
+
+	   If the old argument points to the pathname of a directory, the new
+	   argument shall not point to the pathname of a file that is not a
+	   directory.
+
+	   [checked by VFS: vfs_rename->may_delete()]
+
+	   If the directory named by the new argument exists, it
+	   shall be removed and old renamed to new. In this case, a link named
+	   new shall exist throughout the renaming operation and shall refer
+	   either to the directory referred to by new or old before the
+	   operation began.
+
+	   [we should assure this]
+
+	   If new names an existing directory, it shall be
+	   required to be an empty directory.
+
+	   [we should check this]
+
+	   If the old argument points to a pathname of a symbolic link, the
+	   symbolic link shall be renamed. If the new argument points to a
+	   pathname of a symbolic link, the symbolic link shall be removed.
+
+	   The new pathname shall not contain a path prefix that names
+	   old. Write access permission is required for the directory
+	   containing old and the directory containing new. If the old
+	   argument points to the pathname of a directory, write access
+	   permission may be required for the directory named by old, and, if
+	   it exists, the directory named by new.
+
+	   [checked by VFS: vfs_rename(), vfs_rename_dir()]
+
+	   If the link named by the new argument exists and the file's link
+	   count becomes 0 when it is removed and no process has the file
+	   open, the space occupied by the file shall be freed and the file
+	   shall no longer be accessible. If one or more processes have the
+	   file open when the last link is removed, the link shall be removed
+	   before rename() returns, but the removal of the file contents shall
+	   be postponed until all references to the file are closed.
+
+	   [iput() handles this, but we can do this manually, a la
+	   reiser4_unlink()]
+
+	   Upon successful completion, rename() shall mark for update the
+	   st_ctime and st_mtime fields of the parent directory of each file.
+
+	   [N/A]
+
+	 */
+	reiser4_context *ctx;
+	int result;
+	int is_dir;		/* is @old_name directory */
+
+	struct inode *old_inode;
+	struct inode *new_inode;
+	coord_t *new_coord;
+
+	reiser4_dentry_fsdata *new_fsdata;
+	dir_plugin *dplug;
+	file_plugin *fplug;
+
+	reiser4_dir_entry_desc *old_entry, *new_entry, *dotdot_entry;
+	lock_handle *new_lh, *dotdot_lh;
+	struct dentry *dotdot_name;
+	reiser4_dentry_fsdata *dataonstack;
+
+	ctx = init_context(old_dir->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	old_entry = kmalloc(3 * sizeof(*old_entry) + 2 * sizeof(*new_lh) +
+			    sizeof(*dotdot_name) + sizeof(*dataonstack),
+			    GFP_KERNEL);
+	if (old_entry == NULL) {
+		context_set_commit_async(ctx);
+		reiser4_exit_context(ctx);
+		return RETERR(-ENOMEM);
+	}
+	memset(old_entry, 0, 3 * sizeof(*old_entry) + 2 * sizeof(*new_lh) +
+	       sizeof(*dotdot_name) + sizeof(*dataonstack));
+
+	new_entry = old_entry + 1;
+	dotdot_entry = old_entry + 2;
+	new_lh = (lock_handle *)(old_entry + 3);
+	dotdot_lh = new_lh + 1;
+	dotdot_name = (struct dentry *)(new_lh + 2);
+	dataonstack = (reiser4_dentry_fsdata *)(dotdot_name + 1);
+
+	assert("nikita-2318", old_dir != NULL);
+	assert("nikita-2319", new_dir != NULL);
+	assert("nikita-2320", old_name != NULL);
+	assert("nikita-2321", new_name != NULL);
+
+	old_inode = old_name->d_inode;
+	new_inode = new_name->d_inode;
+
+	dplug = inode_dir_plugin(old_dir);
+	fplug = NULL;
+
+	new_fsdata = reiser4_get_dentry_fsdata(new_name);
+	if (IS_ERR(new_fsdata)) {
+		kfree(old_entry);
+		context_set_commit_async(ctx);
+		reiser4_exit_context(ctx);
+		return PTR_ERR(new_fsdata);
+	}
+
+	new_coord = &new_fsdata->dec.entry_coord;
+	coord_clear_iplug(new_coord);
+
+	is_dir = S_ISDIR(old_inode->i_mode);
+
+	assert("nikita-3461", old_inode->i_nlink >= 1 + !!is_dir);
+
+	/* if target is existing directory and it's not empty---return error.
+
+	   This check is done specifically, because is_dir_empty() requires
+	   tree traversal and have to be done before locks are taken.
+	 */
+	if (is_dir && new_inode != NULL && is_dir_empty(new_inode) != 0) {
+		kfree(old_entry);
+		context_set_commit_async(ctx);
+		reiser4_exit_context(ctx);
+		return RETERR(-ENOTEMPTY);
+	}
+
+	result = can_rename(old_dir, old_inode, new_dir, new_inode);
+	if (result != 0) {
+		kfree(old_entry);
+		context_set_commit_async(ctx);
+		reiser4_exit_context(ctx);
+		return result;
+	}
+
+	result = hashed_rename_estimate_and_grab(old_dir, old_name,
+						 new_dir, new_name);
+	if (result != 0) {
+		kfree(old_entry);
+		context_set_commit_async(ctx);
+		reiser4_exit_context(ctx);
+		return result;
+	}
+
+	init_lh(new_lh);
+
+	/* find entry for @new_name */
+	result = find_entry(new_dir,
+			    new_name, new_lh, ZNODE_WRITE_LOCK, new_entry);
+
+	if (IS_CBKERR(result)) {
+		done_lh(new_lh);
+		kfree(old_entry);
+		context_set_commit_async(ctx);
+		reiser4_exit_context(ctx);
+		return result;
+	}
+
+	seal_done(&new_fsdata->dec.entry_seal);
+
+	/* add or replace name for @old_inode as @new_name */
+	if (new_inode != NULL) {
+		/* target (@new_name) exists. */
+		/* Not clear what to do with objects that are
+		   both directories and files at the same time. */
+		if (result == CBK_COORD_FOUND) {
+			result = replace_name(old_inode,
+					      new_dir,
+					      new_inode, new_coord, new_lh);
+			if (result == 0)
+				fplug = inode_file_plugin(new_inode);
+		} else if (result == CBK_COORD_NOTFOUND) {
+			/* VFS told us that @new_name is bound to existing
+			   inode, but we failed to find directory entry. */
+			warning("nikita-2324", "Target not found");
+			result = RETERR(-ENOENT);
+		}
+	} else {
+		/* target (@new_name) doesn't exists. */
+		if (result == CBK_COORD_NOTFOUND)
+			result = add_name(old_inode,
+					  new_dir,
+					  new_name, new_coord, new_lh, is_dir);
+		else if (result == CBK_COORD_FOUND) {
+			/* VFS told us that @new_name is "negative" dentry,
+			   but we found directory entry. */
+			warning("nikita-2331", "Target found unexpectedly");
+			result = RETERR(-EIO);
+		}
+	}
+
+	assert("nikita-3462", ergo(result == 0,
+				   old_inode->i_nlink >= 2 + !!is_dir));
+
+	/* We are done with all modifications to the @new_dir, release lock on
+	   node. */
+	done_lh(new_lh);
+
+	if (fplug != NULL) {
+		/* detach @new_inode from name-space */
+		result = fplug->detach(new_inode, new_dir);
+		if (result != 0)
+			warning("nikita-2330", "Cannot detach %lli: %i. %s",
+				(unsigned long long)get_inode_oid(new_inode),
+				result, possible_leak);
+	}
+
+	if (new_inode != NULL)
+		reiser4_update_sd(new_inode);
+
+	if (result == 0) {
+		old_entry->obj = old_inode;
+
+		dplug->build_entry_key(old_dir,
+				       &old_name->d_name, &old_entry->key);
+
+		/* At this stage new name was introduced for
+		   @old_inode. @old_inode, @new_dir, and @new_inode i_nlink
+		   counters were updated.
+
+		   We want to remove @old_name now. If @old_inode wasn't
+		   directory this is simple.
+		 */
+		result = dplug->rem_entry(old_dir, old_name, old_entry);
+		if (result != 0 && result != -ENOMEM) {
+			warning("nikita-2335",
+				"Cannot remove old name: %i", result);
+		} else {
+			result = reiser4_del_nlink(old_inode, old_dir, 0);
+			if (result != 0 && result != -ENOMEM) {
+				warning("nikita-2337",
+					"Cannot drop link on old: %i", result);
+			}
+		}
+
+		if (result == 0 && is_dir) {
+			/* @old_inode is directory. We also have to update
+			   dotdot entry. */
+			coord_t *dotdot_coord;
+
+			memset(dataonstack, 0, sizeof dataonstack);
+			memset(dotdot_entry, 0, sizeof dotdot_entry);
+			dotdot_entry->obj = old_dir;
+			memset(dotdot_name, 0, sizeof dotdot_name);
+			dotdot_name->d_name.name = "..";
+			dotdot_name->d_name.len = 2;
+			/*
+			 * allocate ->d_fsdata on the stack to avoid using
+			 * reiser4_get_dentry_fsdata(). Locking is not needed,
+			 * because dentry is private to the current thread.
+			 */
+			dotdot_name->d_fsdata = dataonstack;
+			init_lh(dotdot_lh);
+
+			dotdot_coord = &dataonstack->dec.entry_coord;
+			coord_clear_iplug(dotdot_coord);
+
+			result = find_entry(old_inode, dotdot_name, dotdot_lh,
+					    ZNODE_WRITE_LOCK, dotdot_entry);
+			if (result == 0) {
+				/* replace_name() decreases i_nlink on
+				 * @old_dir */
+				result = replace_name(new_dir,
+						      old_inode,
+						      old_dir,
+						      dotdot_coord, dotdot_lh);
+			} else
+				result = RETERR(-EIO);
+			done_lh(dotdot_lh);
+		}
+	}
+	reiser4_update_dir(new_dir);
+	reiser4_update_dir(old_dir);
+	reiser4_update_sd(old_inode);
+	if (result == 0) {
+		file_plugin *fplug;
+
+		if (new_inode != NULL) {
+			/* add safe-link for target file (in case we removed
+			 * last reference to the poor fellow */
+			fplug = inode_file_plugin(new_inode);
+			if (new_inode->i_nlink == 0)
+				result = safe_link_add(new_inode, SAFE_UNLINK);
+		}
+	}
+	kfree(old_entry);
+	context_set_commit_async(ctx);
+	reiser4_exit_context(ctx);
+	return result;
+}
+
+#if 0
+int rename_common(struct inode *old_dir /* directory where @old is located */ ,
+		  struct dentry *old_name /* old name */ ,
+		  struct inode *new_dir /* directory where @new is located */ ,
+		  struct dentry *new_name /* new name */ )
+{
+	/* From `The Open Group Base Specifications Issue 6'
+
+	   If either the old or new argument names a symbolic link, rename()
+	   shall operate on the symbolic link itself, and shall not resolve
+	   the last component of the argument. If the old argument and the new
+	   argument resolve to the same existing file, rename() shall return
+	   successfully and perform no other action.
+
+	   [this is done by VFS: vfs_rename()]
+
+	   If the old argument points to the pathname of a file that is not a
+	   directory, the new argument shall not point to the pathname of a
+	   directory.
+
+	   [checked by VFS: vfs_rename->may_delete()]
+
+	   If the link named by the new argument exists, it shall
+	   be removed and old renamed to new. In this case, a link named new
+	   shall remain visible to other processes throughout the renaming
+	   operation and refer either to the file referred to by new or old
+	   before the operation began.
+
+	   [we should assure this]
+
+	   Write access permission is required for
+	   both the directory containing old and the directory containing new.
+
+	   [checked by VFS: vfs_rename->may_delete(), may_create()]
+
+	   If the old argument points to the pathname of a directory, the new
+	   argument shall not point to the pathname of a file that is not a
+	   directory.
+
+	   [checked by VFS: vfs_rename->may_delete()]
+
+	   If the directory named by the new argument exists, it
+	   shall be removed and old renamed to new. In this case, a link named
+	   new shall exist throughout the renaming operation and shall refer
+	   either to the directory referred to by new or old before the
+	   operation began.
+
+	   [we should assure this]
+
+	   If new names an existing directory, it shall be
+	   required to be an empty directory.
+
+	   [we should check this]
+
+	   If the old argument points to a pathname of a symbolic link, the
+	   symbolic link shall be renamed. If the new argument points to a
+	   pathname of a symbolic link, the symbolic link shall be removed.
+
+	   The new pathname shall not contain a path prefix that names
+	   old. Write access permission is required for the directory
+	   containing old and the directory containing new. If the old
+	   argument points to the pathname of a directory, write access
+	   permission may be required for the directory named by old, and, if
+	   it exists, the directory named by new.
+
+	   [checked by VFS: vfs_rename(), vfs_rename_dir()]
+
+	   If the link named by the new argument exists and the file's link
+	   count becomes 0 when it is removed and no process has the file
+	   open, the space occupied by the file shall be freed and the file
+	   shall no longer be accessible. If one or more processes have the
+	   file open when the last link is removed, the link shall be removed
+	   before rename() returns, but the removal of the file contents shall
+	   be postponed until all references to the file are closed.
+
+	   [iput() handles this, but we can do this manually, a la
+	   reiser4_unlink()]
+
+	   Upon successful completion, rename() shall mark for update the
+	   st_ctime and st_mtime fields of the parent directory of each file.
+
+	   [N/A]
+
+	 */
+	reiser4_context *ctx;
+	int result;
+	int is_dir;		/* is @old_name directory */
+	struct inode *old_inode;
+	struct inode *new_inode;
+	reiser4_dir_entry_desc old_entry;
+	reiser4_dir_entry_desc new_entry;
+	coord_t *new_coord;
+	reiser4_dentry_fsdata *new_fsdata;
+	lock_handle new_lh;
+	dir_plugin *dplug;
+	file_plugin *fplug;
+
+	ctx = init_context(old_dir->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	assert("nikita-2318", old_dir != NULL);
+	assert("nikita-2319", new_dir != NULL);
+	assert("nikita-2320", old_name != NULL);
+	assert("nikita-2321", new_name != NULL);
+
+	old_inode = old_name->d_inode;
+	new_inode = new_name->d_inode;
+
+	dplug = inode_dir_plugin(old_dir);
+	fplug = NULL;
+
+	new_fsdata = reiser4_get_dentry_fsdata(new_name);
+	if (IS_ERR(new_fsdata)) {
+		result = PTR_ERR(new_fsdata);
+		goto exit;
+	}
+
+	new_coord = &new_fsdata->dec.entry_coord;
+	coord_clear_iplug(new_coord);
+
+	is_dir = S_ISDIR(old_inode->i_mode);
+
+	assert("nikita-3461", old_inode->i_nlink >= 1 + !!is_dir);
+
+	/* if target is existing directory and it's not empty---return error.
+
+	   This check is done specifically, because is_dir_empty() requires
+	   tree traversal and have to be done before locks are taken.
+	 */
+	if (is_dir && new_inode != NULL && is_dir_empty(new_inode) != 0)
+		return RETERR(-ENOTEMPTY);
+
+	result = can_rename(old_dir, old_inode, new_dir, new_inode);
+	if (result != 0)
+		goto exit;
+
+	result = hashed_rename_estimate_and_grab(old_dir, old_name,
+						 new_dir, new_name);
+	if (result != 0)
+		goto exit;
+
+	init_lh(&new_lh);
+
+	/* find entry for @new_name */
+	result = find_entry(new_dir,
+			    new_name, &new_lh, ZNODE_WRITE_LOCK, &new_entry);
+
+	if (IS_CBKERR(result)) {
+		done_lh(&new_lh);
+		goto exit;
+	}
+
+	seal_done(&new_fsdata->dec.entry_seal);
+
+	/* add or replace name for @old_inode as @new_name */
+	if (new_inode != NULL) {
+		/* target (@new_name) exists. */
+		/* Not clear what to do with objects that are
+		   both directories and files at the same time. */
+		if (result == CBK_COORD_FOUND) {
+			result = replace_name(old_inode,
+					      new_dir,
+					      new_inode, new_coord, &new_lh);
+			if (result == 0)
+				fplug = inode_file_plugin(new_inode);
+		} else if (result == CBK_COORD_NOTFOUND) {
+			/* VFS told us that @new_name is bound to existing
+			   inode, but we failed to find directory entry. */
+			warning("nikita-2324", "Target not found");
+			result = RETERR(-ENOENT);
+		}
+	} else {
+		/* target (@new_name) doesn't exists. */
+		if (result == CBK_COORD_NOTFOUND)
+			result = add_name(old_inode,
+					  new_dir,
+					  new_name, new_coord, &new_lh, is_dir);
+		else if (result == CBK_COORD_FOUND) {
+			/* VFS told us that @new_name is "negative" dentry,
+			   but we found directory entry. */
+			warning("nikita-2331", "Target found unexpectedly");
+			result = RETERR(-EIO);
+		}
+	}
+
+	assert("nikita-3462", ergo(result == 0,
+				   old_inode->i_nlink >= 2 + !!is_dir));
+
+	/* We are done with all modifications to the @new_dir, release lock on
+	   node. */
+	done_lh(&new_lh);
+
+	if (fplug != NULL) {
+		/* detach @new_inode from name-space */
+		result = fplug->detach(new_inode, new_dir);
+		if (result != 0)
+			warning("nikita-2330", "Cannot detach %lli: %i. %s",
+				(unsigned long long)get_inode_oid(new_inode),
+				result, possible_leak);
+	}
+
+	if (new_inode != NULL)
+		reiser4_update_sd(new_inode);
+
+	if (result == 0) {
+		memset(&old_entry, 0, sizeof old_entry);
+		old_entry.obj = old_inode;
+
+		dplug->build_entry_key(old_dir,
+				       &old_name->d_name, &old_entry.key);
+
+		/* At this stage new name was introduced for
+		   @old_inode. @old_inode, @new_dir, and @new_inode i_nlink
+		   counters were updated.
+
+		   We want to remove @old_name now. If @old_inode wasn't
+		   directory this is simple.
+		 */
+		result = dplug->rem_entry(old_dir, old_name, &old_entry);
+		/*result = rem_entry_hashed(old_dir, old_name, &old_entry); */
+		if (result != 0 && result != -ENOMEM) {
+			warning("nikita-2335",
+				"Cannot remove old name: %i", result);
+		} else {
+			result = reiser4_del_nlink(old_inode, old_dir, 0);
+			if (result != 0 && result != -ENOMEM) {
+				warning("nikita-2337",
+					"Cannot drop link on old: %i", result);
+			}
+		}
+
+		if (result == 0 && is_dir) {
+			/* @old_inode is directory. We also have to update
+			   dotdot entry. */
+			coord_t *dotdot_coord;
+			lock_handle dotdot_lh;
+			struct dentry dotdot_name;
+			reiser4_dir_entry_desc dotdot_entry;
+			reiser4_dentry_fsdata dataonstack;
+			reiser4_dentry_fsdata *fsdata;
+
+			memset(&dataonstack, 0, sizeof dataonstack);
+			memset(&dotdot_entry, 0, sizeof dotdot_entry);
+			dotdot_entry.obj = old_dir;
+			memset(&dotdot_name, 0, sizeof dotdot_name);
+			dotdot_name.d_name.name = "..";
+			dotdot_name.d_name.len = 2;
+			/*
+			 * allocate ->d_fsdata on the stack to avoid using
+			 * reiser4_get_dentry_fsdata(). Locking is not needed,
+			 * because dentry is private to the current thread.
+			 */
+			dotdot_name.d_fsdata = &dataonstack;
+			init_lh(&dotdot_lh);
+
+			fsdata = &dataonstack;
+			dotdot_coord = &fsdata->dec.entry_coord;
+			coord_clear_iplug(dotdot_coord);
+
+			result = find_entry(old_inode, &dotdot_name, &dotdot_lh,
+					    ZNODE_WRITE_LOCK, &dotdot_entry);
+			if (result == 0) {
+				/* replace_name() decreases i_nlink on
+				 * @old_dir */
+				result = replace_name(new_dir,
+						      old_inode,
+						      old_dir,
+						      dotdot_coord, &dotdot_lh);
+			} else
+				result = RETERR(-EIO);
+			done_lh(&dotdot_lh);
+		}
+	}
+	reiser4_update_dir(new_dir);
+	reiser4_update_dir(old_dir);
+	reiser4_update_sd(old_inode);
+	if (result == 0) {
+		file_plugin *fplug;
+
+		if (new_inode != NULL) {
+			/* add safe-link for target file (in case we removed
+			 * last reference to the poor fellow */
+			fplug = inode_file_plugin(new_inode);
+			if (new_inode->i_nlink == 0)
+				result = safe_link_add(new_inode, SAFE_UNLINK);
+		}
+	}
+      exit:
+	context_set_commit_async(ctx);
+	reiser4_exit_context(ctx);
+	return result;
+}
+#endif
diff -urN oldtree/fs/reiser4/plugin/item/Makefile newtree/fs/reiser4/plugin/item/Makefile
--- oldtree/fs/reiser4/plugin/item/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/Makefile	2006-02-21 15:58:35.081813312 +0000
@@ -0,0 +1,18 @@
+obj-$(CONFIG_REISER4_FS) += item_plugins.o
+
+item_plugins-objs :=		\
+	item.o			\
+	static_stat.o		\
+	sde.o			\
+	cde.o			\
+	blackbox.o		\
+	internal.o		\
+	tail.o			\
+	ctail.o			\
+	extent.o		\
+	extent_item_ops.o	\
+	extent_file_ops.o	\
+	extent_flush_ops.o
+
+
+
diff -urN oldtree/fs/reiser4/plugin/item/acl.h newtree/fs/reiser4/plugin/item/acl.h
--- oldtree/fs/reiser4/plugin/item/acl.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/acl.h	2006-02-21 15:58:34.604885816 +0000
@@ -0,0 +1,66 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Directory entry. */
+
+#if !defined( __FS_REISER4_PLUGIN_DIRECTORY_ENTRY_H__ )
+#define __FS_REISER4_PLUGIN_DIRECTORY_ENTRY_H__
+
+#include "../../forward.h"
+#include "../../dformat.h"
+#include "../../kassign.h"
+#include "../../key.h"
+
+#include <linux/fs.h>
+#include <linux/dcache.h>	/* for struct dentry */
+
+typedef struct directory_entry_format {
+	/* key of object stat-data. It's not necessary to store whole
+	   key here, because it's always key of stat-data, so minor
+	   packing locality and offset can be omitted here. But this
+	   relies on particular key allocation scheme for stat-data, so,
+	   for extensibility sake, whole key can be stored here.
+
+	   We store key as array of bytes, because we don't want 8-byte
+	   alignment of dir entries.
+	 */
+	obj_key_id id;
+	/* file name. Null terminated string. */
+	d8 name[0];
+} directory_entry_format;
+
+void print_de(const char *prefix, coord_t * coord);
+int extract_key_de(const coord_t * coord, reiser4_key * key);
+int update_key_de(const coord_t * coord, const reiser4_key * key,
+		  lock_handle * lh);
+char *extract_name_de(const coord_t * coord, char *buf);
+unsigned extract_file_type_de(const coord_t * coord);
+int add_entry_de(struct inode *dir, coord_t * coord,
+		 lock_handle * lh, const struct dentry *name,
+		 reiser4_dir_entry_desc * entry);
+int rem_entry_de(struct inode *dir, const struct qstr *name, coord_t * coord,
+		 lock_handle * lh, reiser4_dir_entry_desc * entry);
+int max_name_len_de(const struct inode *dir);
+
+int de_rem_and_shrink(struct inode *dir, coord_t * coord, int length);
+
+char *extract_dent_name(const coord_t * coord,
+			directory_entry_format * dent, char *buf);
+
+#if REISER4_LARGE_KEY
+#define DE_NAME_BUF_LEN (24)
+#else
+#define DE_NAME_BUF_LEN (16)
+#endif
+
+/* __FS_REISER4_PLUGIN_DIRECTORY_ENTRY_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/item/blackbox.c newtree/fs/reiser4/plugin/item/blackbox.c
--- oldtree/fs/reiser4/plugin/item/blackbox.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/blackbox.c	2006-02-21 15:58:34.613884448 +0000
@@ -0,0 +1,142 @@
+/* Copyright 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Black box item implementation */
+
+#include "../../forward.h"
+#include "../../debug.h"
+#include "../../dformat.h"
+#include "../../kassign.h"
+#include "../../coord.h"
+#include "../../tree.h"
+#include "../../lock.h"
+
+#include "blackbox.h"
+#include "item.h"
+#include "../plugin.h"
+
+int
+store_black_box(reiser4_tree * tree,
+		const reiser4_key * key, void *data, int length)
+{
+	int result;
+	reiser4_item_data idata;
+	coord_t coord;
+	lock_handle lh;
+
+	memset(&idata, 0, sizeof idata);
+
+	idata.data = data;
+	idata.user = 0;
+	idata.length = length;
+	idata.iplug = item_plugin_by_id(BLACK_BOX_ID);
+
+	init_lh(&lh);
+	result = insert_by_key(tree, key,
+			       &idata, &coord, &lh, LEAF_LEVEL, CBK_UNIQUE);
+
+	assert("nikita-3413",
+	       ergo(result == 0,
+		    WITH_COORD(&coord,
+			       item_length_by_coord(&coord) == length)));
+
+	done_lh(&lh);
+	return result;
+}
+
+int
+load_black_box(reiser4_tree * tree,
+	       reiser4_key * key, void *data, int length, int exact)
+{
+	int result;
+	coord_t coord;
+	lock_handle lh;
+
+	init_lh(&lh);
+	result = coord_by_key(tree, key,
+			      &coord, &lh, ZNODE_READ_LOCK,
+			      exact ? FIND_EXACT : FIND_MAX_NOT_MORE_THAN,
+			      LEAF_LEVEL, LEAF_LEVEL, CBK_UNIQUE, NULL);
+
+	if (result == 0) {
+		int ilen;
+
+		result = zload(coord.node);
+		if (result == 0) {
+			ilen = item_length_by_coord(&coord);
+			if (ilen <= length) {
+				memcpy(data, item_body_by_coord(&coord), ilen);
+				unit_key_by_coord(&coord, key);
+			} else if (exact) {
+				/*
+				 * item is larger than buffer provided by the
+				 * user. Only issue a warning if @exact is
+				 * set. If @exact is false, we are iterating
+				 * over all safe-links and here we are reaching
+				 * the end of the iteration.
+				 */
+				warning("nikita-3415",
+					"Wrong black box length: %i > %i",
+					ilen, length);
+				result = RETERR(-EIO);
+			}
+			zrelse(coord.node);
+		}
+	}
+
+	done_lh(&lh);
+	return result;
+
+}
+
+int
+update_black_box(reiser4_tree * tree,
+		 const reiser4_key * key, void *data, int length)
+{
+	int result;
+	coord_t coord;
+	lock_handle lh;
+
+	init_lh(&lh);
+	result = coord_by_key(tree, key,
+			      &coord, &lh, ZNODE_READ_LOCK,
+			      FIND_EXACT,
+			      LEAF_LEVEL, LEAF_LEVEL, CBK_UNIQUE, NULL);
+	if (result == 0) {
+		int ilen;
+
+		result = zload(coord.node);
+		if (result == 0) {
+			ilen = item_length_by_coord(&coord);
+			if (length <= ilen) {
+				memcpy(item_body_by_coord(&coord), data,
+				       length);
+			} else {
+				warning("nikita-3437",
+					"Wrong black box length: %i < %i",
+					ilen, length);
+				result = RETERR(-EIO);
+			}
+			zrelse(coord.node);
+		}
+	}
+
+	done_lh(&lh);
+	return result;
+
+}
+
+int kill_black_box(reiser4_tree * tree, const reiser4_key * key)
+{
+	return cut_tree(tree, key, key, NULL, 1);
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/item/blackbox.h newtree/fs/reiser4/plugin/item/blackbox.h
--- oldtree/fs/reiser4/plugin/item/blackbox.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/blackbox.h	2006-02-21 15:58:34.613884448 +0000
@@ -0,0 +1,33 @@
+/* Copyright 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* "Black box" entry to fixed-width contain user supplied data */
+
+#if !defined( __FS_REISER4_BLACK_BOX_H__ )
+#define __FS_REISER4_BLACK_BOX_H__
+
+#include "../../forward.h"
+#include "../../dformat.h"
+#include "../../kassign.h"
+#include "../../key.h"
+
+extern int store_black_box(reiser4_tree * tree,
+			   const reiser4_key * key, void *data, int length);
+extern int load_black_box(reiser4_tree * tree,
+			  reiser4_key * key, void *data, int length, int exact);
+extern int kill_black_box(reiser4_tree * tree, const reiser4_key * key);
+extern int update_black_box(reiser4_tree * tree,
+			    const reiser4_key * key, void *data, int length);
+
+/* __FS_REISER4_BLACK_BOX_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/item/cde.c newtree/fs/reiser4/plugin/item/cde.c
--- oldtree/fs/reiser4/plugin/item/cde.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/cde.c	2006-02-21 15:58:34.849848576 +0000
@@ -0,0 +1,1007 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Directory entry implementation */
+
+/* DESCRIPTION:
+
+   This is "compound" directory item plugin implementation. This directory
+   item type is compound (as opposed to the "simple directory item" in
+   fs/reiser4/plugin/item/sde.[ch]), because it consists of several directory
+   entries.
+
+   The reason behind this decision is disk space efficiency: all directory
+   entries inside the same directory have identical fragment in their
+   keys. This, of course, depends on key assignment policy. In our default key
+   assignment policy, all directory entries have the same locality which is
+   equal to the object id of their directory.
+
+   Composing directory item out of several directory entries for the same
+   directory allows us to store said key fragment only once. That is, this is
+   some ad hoc form of key compression (stem compression) that is implemented
+   here, because general key compression is not supposed to be implemented in
+   v4.0.
+
+   Another decision that was made regarding all directory item plugins, is
+   that they will store entry keys unaligned. This is for that sake of disk
+   space efficiency again.
+
+   In should be noted, that storing keys unaligned increases CPU consumption,
+   at least on some architectures.
+
+   Internal on-disk structure of the compound directory item is the following:
+
+        HEADER          cde_item_format.        Here number of entries is stored.
+        ENTRY_HEADER_0  cde_unit_header.        Here part of entry key and
+        ENTRY_HEADER_1                          offset of entry body are stored.
+        ENTRY_HEADER_2				(basically two last parts of key)
+        ...
+        ENTRY_HEADER_N
+        ENTRY_BODY_0    directory_entry_format. Here part of stat data key and
+        ENTRY_BODY_1                            NUL-terminated name are stored.
+        ENTRY_BODY_2				(part of statadta key in the
+  						 sence that since all SDs have
+  						 zero offset, this offset is not
+  						 stored on disk).
+        ...
+        ENTRY_BODY_N
+
+   When it comes to the balancing, each directory entry in compound directory
+   item is unit, that is, something that can be cut from one item and pasted
+   into another item of the same type. Handling of unit cut and paste is major
+   reason for the complexity of code below.
+
+*/
+
+#include "../../forward.h"
+#include "../../debug.h"
+#include "../../dformat.h"
+#include "../../kassign.h"
+#include "../../key.h"
+#include "../../coord.h"
+#include "sde.h"
+#include "cde.h"
+#include "item.h"
+#include "../node/node.h"
+#include "../plugin.h"
+#include "../../znode.h"
+#include "../../carry.h"
+#include "../../tree.h"
+#include "../../inode.h"
+
+#include <linux/fs.h>		/* for struct inode */
+#include <linux/dcache.h>	/* for struct dentry */
+#include <linux/quotaops.h>
+
+#if 0
+#define CHECKME(coord)						\
+({								\
+	const char *message;					\
+	coord_t dup;						\
+								\
+	coord_dup_nocheck(&dup, (coord));			\
+	dup.unit_pos = 0;					\
+	assert("nikita-2871", cde_check(&dup, &message) == 0);	\
+})
+#else
+#define CHECKME(coord) noop
+#endif
+
+/* return body of compound directory item at @coord */
+static inline cde_item_format *formatted_at(const coord_t * coord)
+{
+	assert("nikita-1282", coord != NULL);
+	return item_body_by_coord(coord);
+}
+
+/* return entry header at @coord */
+static inline cde_unit_header *header_at(const coord_t *
+					 coord /* coord of item */ ,
+					 int idx /* index of unit */ )
+{
+	assert("nikita-1283", coord != NULL);
+	return &formatted_at(coord)->entry[idx];
+}
+
+/* return number of units in compound directory item at @coord */
+static int units(const coord_t * coord /* coord of item */ )
+{
+	return le16_to_cpu(get_unaligned(&formatted_at(coord)->num_of_entries));
+}
+
+/* return offset of the body of @idx-th entry in @coord */
+static unsigned int offset_of(const coord_t * coord /* coord of item */ ,
+			      int idx /* index of unit */ )
+{
+	if (idx < units(coord))
+		return le16_to_cpu(get_unaligned(&header_at(coord, idx)->offset));
+	else if (idx == units(coord))
+		return item_length_by_coord(coord);
+	else
+		impossible("nikita-1308", "Wrong idx");
+	return 0;
+}
+
+/* set offset of the body of @idx-th entry in @coord */
+static void set_offset(const coord_t * coord /* coord of item */ ,
+		       int idx /* index of unit */ ,
+		       unsigned int offset /* new offset */ )
+{
+	put_unaligned(cpu_to_le16((__u16) offset), &header_at(coord, idx)->offset);
+}
+
+static void adj_offset(const coord_t * coord /* coord of item */ ,
+		       int idx /* index of unit */ ,
+		       int delta /* offset change */ )
+{
+	d16 *doffset;
+	__u16 offset;
+
+	doffset = &header_at(coord, idx)->offset;
+	offset = le16_to_cpu(get_unaligned(doffset));
+	offset += delta;
+	put_unaligned(cpu_to_le16((__u16) offset), doffset);
+}
+
+/* return pointer to @offset-th byte from the beginning of @coord */
+static char *address(const coord_t * coord /* coord of item */ ,
+		     int offset)
+{
+	return ((char *)item_body_by_coord(coord)) + offset;
+}
+
+/* return pointer to the body of @idx-th entry in @coord */
+static directory_entry_format *entry_at(const coord_t * coord	/* coord of
+								 * item */ ,
+					int idx /* index of unit */ )
+{
+	return (directory_entry_format *) address(coord,
+						  (int)offset_of(coord, idx));
+}
+
+/* return number of unit referenced by @coord */
+static int idx_of(const coord_t * coord /* coord of item */ )
+{
+	assert("nikita-1285", coord != NULL);
+	return coord->unit_pos;
+}
+
+/* find position where entry with @entry_key would be inserted into @coord */
+static int find(const coord_t * coord /* coord of item */ ,
+		const reiser4_key * entry_key /* key to look for */ ,
+		cmp_t * last /* result of last comparison */ )
+{
+	int entries;
+
+	int left;
+	int right;
+
+	cde_unit_header *header;
+
+	assert("nikita-1295", coord != NULL);
+	assert("nikita-1296", entry_key != NULL);
+	assert("nikita-1297", last != NULL);
+
+	entries = units(coord);
+	left = 0;
+	right = entries - 1;
+	while (right - left >= REISER4_SEQ_SEARCH_BREAK) {
+		int median;
+
+		median = (left + right) >> 1;
+
+		header = header_at(coord, median);
+		*last = de_id_key_cmp(&header->hash, entry_key);
+		switch (*last) {
+		case LESS_THAN:
+			left = median;
+			break;
+		case GREATER_THAN:
+			right = median;
+			break;
+		case EQUAL_TO:{
+				do {
+					median--;
+					header--;
+				} while (median >= 0 &&
+					 de_id_key_cmp(&header->hash,
+						       entry_key) == EQUAL_TO);
+				return median + 1;
+			}
+		}
+	}
+	header = header_at(coord, left);
+	for (; left < entries; ++left, ++header) {
+		prefetch(header + 1);
+		*last = de_id_key_cmp(&header->hash, entry_key);
+		if (*last != LESS_THAN)
+			break;
+	}
+	if (left < entries)
+		return left;
+	else
+		return RETERR(-ENOENT);
+
+}
+
+/* expand @coord as to accommodate for insertion of @no new entries starting
+   from @pos, with total bodies size @size. */
+static int expand_item(const coord_t * coord /* coord of item */ ,
+		       int pos /* unit position */ , int no	/* number of new
+								 * units*/ ,
+		       int size /* total size of new units' data */ ,
+		       unsigned int data_size	/* free space already reserved
+						 * in the item for insertion */ )
+{
+	int entries;
+	cde_unit_header *header;
+	char *dent;
+	int i;
+
+	assert("nikita-1310", coord != NULL);
+	assert("nikita-1311", pos >= 0);
+	assert("nikita-1312", no > 0);
+	assert("nikita-1313", data_size >= no * sizeof(directory_entry_format));
+	assert("nikita-1343",
+	       item_length_by_coord(coord) >=
+	       (int)(size + data_size + no * sizeof *header));
+
+	entries = units(coord);
+
+	if (pos == entries)
+		dent = address(coord, size);
+	else
+		dent = (char *)entry_at(coord, pos);
+	/* place where new header will be in */
+	header = header_at(coord, pos);
+	/* free space for new entry headers */
+	memmove(header + no, header,
+		(unsigned)(address(coord, size) - (char *)header));
+	/* if adding to the end initialise first new header */
+	if (pos == entries) {
+		set_offset(coord, pos, (unsigned)size);
+	}
+
+	/* adjust entry pointer and size */
+	dent = dent + no * sizeof *header;
+	size += no * sizeof *header;
+	/* free space for new entries */
+	memmove(dent + data_size, dent,
+		(unsigned)(address(coord, size) - dent));
+
+	/* increase counter */
+	entries += no;
+	put_unaligned(cpu_to_le16((__u16) entries), &formatted_at(coord)->num_of_entries);
+
+	/* [ 0 ... pos ] entries were shifted by no * ( sizeof *header )
+	   bytes.  */
+	for (i = 0; i <= pos; ++i)
+		adj_offset(coord, i, no * sizeof *header);
+	/* [ pos + no ... +\infty ) entries were shifted by ( no *
+	   sizeof *header + data_size ) bytes */
+	for (i = pos + no; i < entries; ++i)
+		adj_offset(coord, i, no * sizeof *header + data_size);
+	return 0;
+}
+
+/* insert new @entry into item */
+static int expand(const coord_t * coord /* coord of item */ ,
+		  cde_entry * entry /* entry to insert */ ,
+		  int len /* length of @entry data */ ,
+		  int *pos /* position to insert */ ,
+		  reiser4_dir_entry_desc * dir_entry	/* parameters for new
+							 * entry */ )
+{
+	cmp_t cmp_res;
+	int datasize;
+
+	*pos = find(coord, &dir_entry->key, &cmp_res);
+	if (*pos < 0)
+		*pos = units(coord);
+
+	datasize = sizeof(directory_entry_format);
+	if (is_longname(entry->name->name, entry->name->len))
+		datasize += entry->name->len + 1;
+
+	expand_item(coord, *pos, 1, item_length_by_coord(coord) - len,
+		    datasize);
+	return 0;
+}
+
+/* paste body of @entry into item */
+static int paste_entry(const coord_t * coord /* coord of item */ ,
+		       cde_entry * entry /* new entry */ ,
+		       int pos /* position to insert */ ,
+		       reiser4_dir_entry_desc * dir_entry	/* parameters for
+								 * new entry */ )
+{
+	cde_unit_header *header;
+	directory_entry_format *dent;
+	const char *name;
+	int len;
+
+	header = header_at(coord, pos);
+	dent = entry_at(coord, pos);
+
+	build_de_id_by_key(&dir_entry->key, &header->hash);
+	build_inode_key_id(entry->obj, &dent->id);
+	/* AUDIT unsafe strcpy() operation! It should be replaced with
+	   much less CPU hungry
+	   memcpy( ( char * ) dent -> name, entry -> name -> name , entry -> name -> len );
+
+	   Also a more major thing is that there should be a way to figure out
+	   amount of space in dent -> name and be able to check that we are
+	   not going to overwrite more than we supposed to */
+	name = entry->name->name;
+	len = entry->name->len;
+	if (is_longname(name, len)) {
+		strcpy((unsigned char *)dent->name, name);
+		put_unaligned(0, &dent->name[len]);
+	}
+	return 0;
+}
+
+/* estimate how much space is necessary in item to insert/paste set of entries
+   described in @data. */
+int estimate_cde(const coord_t * coord /* coord of item */ ,
+		 const reiser4_item_data * data /* parameters for new item */ )
+{
+	cde_entry_data *e;
+	int result;
+	int i;
+
+	e = (cde_entry_data *) data->data;
+
+	assert("nikita-1288", e != NULL);
+	assert("nikita-1289", e->num_of_entries >= 0);
+
+	if (coord == NULL)
+		/* insert */
+		result = sizeof(cde_item_format);
+	else
+		/* paste */
+		result = 0;
+
+	result += e->num_of_entries *
+	    (sizeof(cde_unit_header) + sizeof(directory_entry_format));
+	for (i = 0; i < e->num_of_entries; ++i) {
+		const char *name;
+		int len;
+
+		name = e->entry[i].name->name;
+		len = e->entry[i].name->len;
+		assert("nikita-2054", strlen(name) == len);
+		if (is_longname(name, len))
+			result += len + 1;
+	}
+	((reiser4_item_data *) data)->length = result;
+	return result;
+}
+
+/* ->nr_units() method for this item plugin. */
+pos_in_node_t nr_units_cde(const coord_t * coord /* coord of item */ )
+{
+	return units(coord);
+}
+
+/* ->unit_key() method for this item plugin. */
+reiser4_key *unit_key_cde(const coord_t * coord /* coord of item */ ,
+			  reiser4_key * key /* resulting key */ )
+{
+	assert("nikita-1452", coord != NULL);
+	assert("nikita-1345", idx_of(coord) < units(coord));
+	assert("nikita-1346", key != NULL);
+
+	item_key_by_coord(coord, key);
+	extract_key_from_de_id(extract_dir_id_from_key(key),
+			       &header_at(coord, idx_of(coord))->hash, key);
+	return key;
+}
+
+/* mergeable_cde(): implementation of ->mergeable() item method.
+
+   Two directory items are mergeable iff they are from the same
+   directory. That simple.
+
+*/
+int mergeable_cde(const coord_t * p1 /* coord of first item */ ,
+		  const coord_t * p2 /* coord of second item */ )
+{
+	reiser4_key k1;
+	reiser4_key k2;
+
+	assert("nikita-1339", p1 != NULL);
+	assert("nikita-1340", p2 != NULL);
+
+	return
+	    (item_plugin_by_coord(p1) == item_plugin_by_coord(p2)) &&
+	    (extract_dir_id_from_key(item_key_by_coord(p1, &k1)) ==
+	     extract_dir_id_from_key(item_key_by_coord(p2, &k2)));
+
+}
+
+/* ->max_key_inside() method for this item plugin. */
+reiser4_key *max_key_inside_cde(const coord_t * coord /* coord of item */ ,
+				reiser4_key * result /* resulting key */ )
+{
+	assert("nikita-1342", coord != NULL);
+
+	item_key_by_coord(coord, result);
+	set_key_ordering(result, get_key_ordering(max_key()));
+	set_key_fulloid(result, get_key_fulloid(max_key()));
+	set_key_offset(result, get_key_offset(max_key()));
+	return result;
+}
+
+/* @data contains data which are to be put into tree */
+int can_contain_key_cde(const coord_t * coord /* coord of item */ ,
+			const reiser4_key * key /* key to check */ ,
+			const reiser4_item_data * data	/* parameters of new
+							 * item/unit being
+							 * created */ )
+{
+	reiser4_key item_key;
+
+	/* FIXME-VS: do not rely on anything but iplug field of @data. Only
+	   data->iplug is initialized */
+	assert("vs-457", data && data->iplug);
+/*	assert( "vs-553", data -> user == 0 );*/
+	item_key_by_coord(coord, &item_key);
+
+	return (item_plugin_by_coord(coord) == data->iplug) &&
+	    (extract_dir_id_from_key(&item_key) ==
+	     extract_dir_id_from_key(key));
+}
+
+#if REISER4_DEBUG
+/* cde_check ->check() method for compressed directory items
+
+   used for debugging, every item should have here the most complete
+   possible check of the consistency of the item that the inventor can
+   construct
+*/
+int check_cde(const coord_t * coord /* coord of item to check */ ,
+	      const char **error /* where to store error message */ )
+{
+	int i;
+	int result;
+	char *item_start;
+	char *item_end;
+	reiser4_key key;
+
+	coord_t c;
+
+	assert("nikita-1357", coord != NULL);
+	assert("nikita-1358", error != NULL);
+
+	if (!ergo(coord->item_pos != 0,
+		  is_dot_key(item_key_by_coord(coord, &key)))) {
+		*error = "CDE doesn't start with dot";
+		return -1;
+	}
+	item_start = item_body_by_coord(coord);
+	item_end = item_start + item_length_by_coord(coord);
+
+	coord_dup(&c, coord);
+	result = 0;
+	for (i = 0; i < units(coord); ++i) {
+		directory_entry_format *entry;
+
+		if ((char *)(header_at(coord, i) + 1) >
+		    item_end - units(coord) * sizeof *entry) {
+			*error = "CDE header is out of bounds";
+			result = -1;
+			break;
+		}
+		entry = entry_at(coord, i);
+		if ((char *)entry < item_start + sizeof(cde_item_format)) {
+			*error = "CDE header is too low";
+			result = -1;
+			break;
+		}
+		if ((char *)(entry + 1) > item_end) {
+			*error = "CDE header is too high";
+			result = -1;
+			break;
+		}
+	}
+
+	return result;
+}
+#endif
+
+/* ->init() method for this item plugin. */
+int init_cde(coord_t * coord /* coord of item */ ,
+	     coord_t * from UNUSED_ARG, reiser4_item_data * data	/* structure used for insertion */
+	     UNUSED_ARG)
+{
+	put_unaligned(cpu_to_le16(0), &formatted_at(coord)->num_of_entries);
+	return 0;
+}
+
+/* ->lookup() method for this item plugin. */
+lookup_result lookup_cde(const reiser4_key * key /* key to search for */ ,
+			 lookup_bias bias /* search bias */ ,
+			 coord_t * coord /* coord of item to lookup in */ )
+{
+	cmp_t last_comp;
+	int pos;
+
+	reiser4_key utmost_key;
+
+	assert("nikita-1293", coord != NULL);
+	assert("nikita-1294", key != NULL);
+
+	CHECKME(coord);
+
+	if (keygt(item_key_by_coord(coord, &utmost_key), key)) {
+		coord->unit_pos = 0;
+		coord->between = BEFORE_UNIT;
+		return CBK_COORD_NOTFOUND;
+	}
+	pos = find(coord, key, &last_comp);
+	if (pos >= 0) {
+		coord->unit_pos = (int)pos;
+		switch (last_comp) {
+		case EQUAL_TO:
+			coord->between = AT_UNIT;
+			return CBK_COORD_FOUND;
+		case GREATER_THAN:
+			coord->between = BEFORE_UNIT;
+			return RETERR(-ENOENT);
+		case LESS_THAN:
+		default:
+			impossible("nikita-1298", "Broken find");
+			return RETERR(-EIO);
+		}
+	} else {
+		coord->unit_pos = units(coord) - 1;
+		coord->between = AFTER_UNIT;
+		return (bias ==
+			FIND_MAX_NOT_MORE_THAN) ? CBK_COORD_FOUND :
+		    CBK_COORD_NOTFOUND;
+	}
+}
+
+/* ->paste() method for this item plugin. */
+int paste_cde(coord_t * coord /* coord of item */ ,
+	      reiser4_item_data * data	/* parameters of new unit being
+					 * inserted */ ,
+	      carry_plugin_info * info UNUSED_ARG /* todo carry queue */ )
+{
+	cde_entry_data *e;
+	int result;
+	int i;
+
+	CHECKME(coord);
+	e = (cde_entry_data *) data->data;
+
+	result = 0;
+	for (i = 0; i < e->num_of_entries; ++i) {
+		int pos;
+		int phantom_size;
+
+		phantom_size = data->length;
+		if (units(coord) == 0)
+			phantom_size -= sizeof(cde_item_format);
+
+		result =
+		    expand(coord, e->entry + i, phantom_size, &pos, data->arg);
+		if (result != 0)
+			break;
+		result = paste_entry(coord, e->entry + i, pos, data->arg);
+		if (result != 0)
+			break;
+	}
+	CHECKME(coord);
+	return result;
+}
+
+/* amount of space occupied by all entries starting from @idx both headers and
+   bodies. */
+static unsigned int part_size(const coord_t * coord /* coord of item */ ,
+			      int idx /* index of unit */ )
+{
+	assert("nikita-1299", coord != NULL);
+	assert("nikita-1300", idx < (int)units(coord));
+
+	return sizeof(cde_item_format) +
+	    (idx + 1) * sizeof(cde_unit_header) + offset_of(coord,
+							    idx + 1) -
+	    offset_of(coord, 0);
+}
+
+/* how many but not more than @want units of @source can be merged with
+   item in @target node. If pend == append - we try to append last item
+   of @target by first units of @source. If pend == prepend - we try to
+   "prepend" first item in @target by last units of @source. @target
+   node has @free_space bytes of free space. Total size of those units
+   are returned via @size */
+int can_shift_cde(unsigned free_space /* free space in item */ ,
+		  coord_t * coord /* coord of source item */ ,
+		  znode * target /* target node */ ,
+		  shift_direction pend /* shift direction */ ,
+		  unsigned *size /* resulting number of shifted bytes */ ,
+		  unsigned want /* maximal number of bytes to shift */ )
+{
+	int shift;
+
+	CHECKME(coord);
+	if (want == 0) {
+		*size = 0;
+		return 0;
+	}
+
+	/* pend == SHIFT_LEFT <==> shifting to the left */
+	if (pend == SHIFT_LEFT) {
+		for (shift = min((int)want - 1, units(coord)); shift >= 0;
+		     --shift) {
+			*size = part_size(coord, shift);
+			if (target != NULL)
+				*size -= sizeof(cde_item_format);
+			if (*size <= free_space)
+				break;
+		}
+		shift = shift + 1;
+	} else {
+		int total_size;
+
+		assert("nikita-1301", pend == SHIFT_RIGHT);
+
+		total_size = item_length_by_coord(coord);
+		for (shift = units(coord) - want - 1; shift < units(coord) - 1;
+		     ++shift) {
+			*size = total_size - part_size(coord, shift);
+			if (target == NULL)
+				*size += sizeof(cde_item_format);
+			if (*size <= free_space)
+				break;
+		}
+		shift = units(coord) - shift - 1;
+	}
+	if (shift == 0)
+		*size = 0;
+	CHECKME(coord);
+	return shift;
+}
+
+/* ->copy_units() method for this item plugin. */
+void copy_units_cde(coord_t * target /* coord of target item */ ,
+		    coord_t * source /* coord of source item */ ,
+		    unsigned from /* starting unit */ ,
+		    unsigned count /* how many units to copy */ ,
+		    shift_direction where_is_free_space /* shift direction */ ,
+		    unsigned free_space /* free space in item */ )
+{
+	char *header_from;
+	char *header_to;
+
+	char *entry_from;
+	char *entry_to;
+
+	int pos_in_target;
+	int data_size;
+	int data_delta;
+	int i;
+
+	assert("nikita-1303", target != NULL);
+	assert("nikita-1304", source != NULL);
+	assert("nikita-1305", (int)from < units(source));
+	assert("nikita-1307", (int)(from + count) <= units(source));
+
+	if (where_is_free_space == SHIFT_LEFT) {
+		assert("nikita-1453", from == 0);
+		pos_in_target = units(target);
+	} else {
+		assert("nikita-1309", (int)(from + count) == units(source));
+		pos_in_target = 0;
+		memmove(item_body_by_coord(target),
+			(char *)item_body_by_coord(target) + free_space,
+			item_length_by_coord(target) - free_space);
+	}
+
+	CHECKME(target);
+	CHECKME(source);
+
+	/* expand @target */
+	data_size =
+	    offset_of(source, (int)(from + count)) - offset_of(source,
+							       (int)from);
+
+	if (units(target) == 0)
+		free_space -= sizeof(cde_item_format);
+
+	expand_item(target, pos_in_target, (int)count,
+		    (int)(item_length_by_coord(target) - free_space),
+		    (unsigned)data_size);
+
+	/* copy first @count units of @source into @target */
+	data_delta =
+	    offset_of(target, pos_in_target) - offset_of(source, (int)from);
+
+	/* copy entries */
+	entry_from = (char *)entry_at(source, (int)from);
+	entry_to = (char *)entry_at(source, (int)(from + count));
+	memmove(entry_at(target, pos_in_target), entry_from,
+		(unsigned)(entry_to - entry_from));
+
+	/* copy headers */
+	header_from = (char *)header_at(source, (int)from);
+	header_to = (char *)header_at(source, (int)(from + count));
+	memmove(header_at(target, pos_in_target), header_from,
+		(unsigned)(header_to - header_from));
+
+	/* update offsets */
+	for (i = pos_in_target; i < (int)(pos_in_target + count); ++i)
+		adj_offset(target, i, data_delta);
+	CHECKME(target);
+	CHECKME(source);
+}
+
+/* ->cut_units() method for this item plugin. */
+int cut_units_cde(coord_t * coord /* coord of item */ ,
+		  pos_in_node_t from /* start unit pos */ ,
+		  pos_in_node_t to /* stop unit pos */ ,
+		  struct carry_cut_data *cdata UNUSED_ARG,
+		  reiser4_key * smallest_removed, reiser4_key * new_first)
+{
+	char *header_from;
+	char *header_to;
+
+	char *entry_from;
+	char *entry_to;
+
+	int size;
+	int entry_delta;
+	int header_delta;
+	int i;
+
+	unsigned count;
+
+	CHECKME(coord);
+
+	count = to - from + 1;
+
+	assert("nikita-1454", coord != NULL);
+	assert("nikita-1455", (int)(from + count) <= units(coord));
+
+	if (smallest_removed)
+		unit_key_by_coord(coord, smallest_removed);
+
+	if (new_first) {
+		coord_t next;
+
+		/* not everything is cut from item head */
+		assert("vs-1527", from == 0);
+		assert("vs-1528", to < units(coord) - 1);
+
+		coord_dup(&next, coord);
+		next.unit_pos++;
+		unit_key_by_coord(&next, new_first);
+	}
+
+	size = item_length_by_coord(coord);
+	if (count == (unsigned)units(coord)) {
+		return size;
+	}
+
+	header_from = (char *)header_at(coord, (int)from);
+	header_to = (char *)header_at(coord, (int)(from + count));
+
+	entry_from = (char *)entry_at(coord, (int)from);
+	entry_to = (char *)entry_at(coord, (int)(from + count));
+
+	/* move headers */
+	memmove(header_from, header_to,
+		(unsigned)(address(coord, size) - header_to));
+
+	header_delta = header_to - header_from;
+
+	entry_from -= header_delta;
+	entry_to -= header_delta;
+	size -= header_delta;
+
+	/* copy entries */
+	memmove(entry_from, entry_to,
+		(unsigned)(address(coord, size) - entry_to));
+
+	entry_delta = entry_to - entry_from;
+	size -= entry_delta;
+
+	/* update offsets */
+
+	for (i = 0; i < (int)from; ++i)
+		adj_offset(coord, i, -header_delta);
+
+	for (i = from; i < units(coord) - (int)count; ++i)
+		adj_offset(coord, i, -header_delta - entry_delta);
+
+	put_unaligned(cpu_to_le16((__u16) units(coord) - count),
+		      &formatted_at(coord)->num_of_entries);
+
+	if (from == 0) {
+		/* entries from head was removed - move remaining to right */
+		memmove((char *)item_body_by_coord(coord) +
+			header_delta + entry_delta, item_body_by_coord(coord),
+			(unsigned)size);
+		if (REISER4_DEBUG)
+			memset(item_body_by_coord(coord), 0,
+			       (unsigned)header_delta + entry_delta);
+	} else {
+		/* freed space is already at the end of item */
+		if (REISER4_DEBUG)
+			memset((char *)item_body_by_coord(coord) + size, 0,
+			       (unsigned)header_delta + entry_delta);
+	}
+
+	return header_delta + entry_delta;
+}
+
+int kill_units_cde(coord_t * coord /* coord of item */ ,
+		   pos_in_node_t from /* start unit pos */ ,
+		   pos_in_node_t to /* stop unit pos */ ,
+		   struct carry_kill_data *kdata UNUSED_ARG,
+		   reiser4_key * smallest_removed, reiser4_key * new_first)
+{
+	return cut_units_cde(coord, from, to, NULL, smallest_removed, new_first);
+}
+
+/* ->s.dir.extract_key() method for this item plugin. */
+int extract_key_cde(const coord_t * coord /* coord of item */ ,
+		    reiser4_key * key /* resulting key */ )
+{
+	directory_entry_format *dent;
+
+	assert("nikita-1155", coord != NULL);
+	assert("nikita-1156", key != NULL);
+
+	dent = entry_at(coord, idx_of(coord));
+	return extract_key_from_id(&dent->id, key);
+}
+
+int
+update_key_cde(const coord_t * coord, const reiser4_key * key,
+	       lock_handle * lh UNUSED_ARG)
+{
+	directory_entry_format *dent;
+	obj_key_id obj_id;
+	int result;
+
+	assert("nikita-2344", coord != NULL);
+	assert("nikita-2345", key != NULL);
+
+	dent = entry_at(coord, idx_of(coord));
+	result = build_obj_key_id(key, &obj_id);
+	if (result == 0) {
+		dent->id = obj_id;
+		znode_make_dirty(coord->node);
+	}
+	return 0;
+}
+
+/* ->s.dir.extract_name() method for this item plugin. */
+char *extract_name_cde(const coord_t * coord /* coord of item */ , char *buf)
+{
+	directory_entry_format *dent;
+
+	assert("nikita-1157", coord != NULL);
+
+	dent = entry_at(coord, idx_of(coord));
+	return extract_dent_name(coord, dent, buf);
+}
+
+static int cde_bytes(int pasting, const reiser4_item_data * data)
+{
+	int result;
+
+	result = data->length;
+	if (!pasting)
+		result -= sizeof(cde_item_format);
+	return result;
+}
+
+/* ->s.dir.add_entry() method for this item plugin */
+int add_entry_cde(struct inode *dir /* directory object */ ,
+		  coord_t * coord /* coord of item */ ,
+		  lock_handle * lh /* lock handle for insertion */ ,
+		  const struct dentry *name /* name to insert */ ,
+		  reiser4_dir_entry_desc * dir_entry	/* parameters of new
+							 * directory entry */ )
+{
+	reiser4_item_data data;
+	cde_entry entry;
+	cde_entry_data edata;
+	int result;
+
+	assert("nikita-1656", coord->node == lh->node);
+	assert("nikita-1657", znode_is_write_locked(coord->node));
+
+	edata.num_of_entries = 1;
+	edata.entry = &entry;
+
+	entry.dir = dir;
+	entry.obj = dir_entry->obj;
+	entry.name = &name->d_name;
+
+	data.data = (char *)&edata;
+	data.user = 0;		/* &edata is not user space */
+	data.iplug = item_plugin_by_id(COMPOUND_DIR_ID);
+	data.arg = dir_entry;
+	assert("nikita-1302", data.iplug != NULL);
+
+	result = is_dot_key(&dir_entry->key);
+	data.length = estimate_cde(result ? coord : NULL, &data);
+
+	/* NOTE-NIKITA quota plugin? */
+	if (DQUOT_ALLOC_SPACE_NODIRTY(dir, cde_bytes(result, &data)))
+		return RETERR(-EDQUOT);
+
+	if (result)
+		result = insert_by_coord(coord, &data, &dir_entry->key, lh, 0);
+	else
+		result = resize_item(coord, &data, &dir_entry->key, lh, 0);
+	return result;
+}
+
+/* ->s.dir.rem_entry() */
+int rem_entry_cde(struct inode *dir /* directory of item */ ,
+		  const struct qstr *name, coord_t * coord /* coord of item */ ,
+		  lock_handle * lh UNUSED_ARG	/* lock handle for
+						 * removal */ ,
+		  reiser4_dir_entry_desc * entry UNUSED_ARG	/* parameters of
+								 * directory entry
+								 * being removed */ )
+{
+	coord_t shadow;
+	int result;
+	int length;
+	ON_DEBUG(char buf[DE_NAME_BUF_LEN]);
+
+	assert("nikita-2870", strlen(name->name) == name->len);
+	assert("nikita-2869",
+	       !strcmp(name->name, extract_name_cde(coord, buf)));
+
+	length = sizeof(directory_entry_format) + sizeof(cde_unit_header);
+	if (is_longname(name->name, name->len))
+		length += name->len + 1;
+
+	if (inode_get_bytes(dir) < length) {
+		warning("nikita-2628", "Dir is broke: %llu: %llu",
+			(unsigned long long)get_inode_oid(dir),
+			inode_get_bytes(dir));
+
+		return RETERR(-EIO);
+	}
+
+	/* cut_node() is supposed to take pointers to _different_
+	   coords, because it will modify them without respect to
+	   possible aliasing. To work around this, create temporary copy
+	   of @coord.
+	 */
+	coord_dup(&shadow, coord);
+	result =
+	    kill_node_content(coord, &shadow, NULL, NULL, NULL, NULL, NULL, 0);
+	if (result == 0) {
+		/* NOTE-NIKITA quota plugin? */
+		DQUOT_FREE_SPACE_NODIRTY(dir, length);
+	}
+	return result;
+}
+
+/* ->s.dir.max_name_len() method for this item plugin */
+int max_name_len_cde(const struct inode *dir /* directory */ )
+{
+	return
+	    tree_by_inode(dir)->nplug->max_item_size() -
+	    sizeof(directory_entry_format) - sizeof(cde_item_format) -
+	    sizeof(cde_unit_header) - 2;
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/item/cde.h newtree/fs/reiser4/plugin/item/cde.h
--- oldtree/fs/reiser4/plugin/item/cde.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/cde.h	2006-02-21 15:58:34.615884144 +0000
@@ -0,0 +1,87 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Compound directory item. See cde.c for description. */
+
+#if !defined( __FS_REISER4_PLUGIN_COMPRESSED_DE_H__ )
+#define __FS_REISER4_PLUGIN_COMPRESSED_DE_H__
+
+#include "../../forward.h"
+#include "../../kassign.h"
+#include "../../dformat.h"
+
+#include <linux/fs.h>		/* for struct inode */
+#include <linux/dcache.h>	/* for struct dentry, etc  */
+
+typedef struct cde_unit_header {
+	de_id hash;
+	d16 offset;
+} cde_unit_header;
+
+typedef struct cde_item_format {
+	d16 num_of_entries;
+	cde_unit_header entry[0];
+} cde_item_format;
+
+typedef struct cde_entry {
+	const struct inode *dir;
+	const struct inode *obj;
+	const struct qstr *name;
+} cde_entry;
+
+typedef struct cde_entry_data {
+	int num_of_entries;
+	cde_entry *entry;
+} cde_entry_data;
+
+/* plugin->item.b.* */
+reiser4_key *max_key_inside_cde(const coord_t * coord, reiser4_key * result);
+int can_contain_key_cde(const coord_t * coord, const reiser4_key * key,
+			const reiser4_item_data *);
+int mergeable_cde(const coord_t * p1, const coord_t * p2);
+pos_in_node_t nr_units_cde(const coord_t * coord);
+reiser4_key *unit_key_cde(const coord_t * coord, reiser4_key * key);
+int estimate_cde(const coord_t * coord, const reiser4_item_data * data);
+void print_cde(const char *prefix, coord_t * coord);
+int init_cde(coord_t * coord, coord_t * from, reiser4_item_data * data);
+lookup_result lookup_cde(const reiser4_key * key, lookup_bias bias,
+			 coord_t * coord);
+int paste_cde(coord_t * coord, reiser4_item_data * data,
+	      carry_plugin_info * info UNUSED_ARG);
+int can_shift_cde(unsigned free_space, coord_t * coord, znode * target,
+		  shift_direction pend, unsigned *size, unsigned want);
+void copy_units_cde(coord_t * target, coord_t * source, unsigned from,
+		    unsigned count, shift_direction where_is_free_space,
+		    unsigned free_space);
+int cut_units_cde(coord_t * coord, pos_in_node_t from, pos_in_node_t to,
+		  struct carry_cut_data *, reiser4_key * smallest_removed,
+		  reiser4_key * new_first);
+int kill_units_cde(coord_t * coord, pos_in_node_t from, pos_in_node_t to,
+		   struct carry_kill_data *, reiser4_key * smallest_removed,
+		   reiser4_key * new_first);
+void print_cde(const char *prefix, coord_t * coord);
+int check_cde(const coord_t * coord, const char **error);
+
+/* plugin->u.item.s.dir.* */
+int extract_key_cde(const coord_t * coord, reiser4_key * key);
+int update_key_cde(const coord_t * coord, const reiser4_key * key,
+		   lock_handle * lh);
+char *extract_name_cde(const coord_t * coord, char *buf);
+int add_entry_cde(struct inode *dir, coord_t * coord,
+		  lock_handle * lh, const struct dentry *name,
+		  reiser4_dir_entry_desc * entry);
+int rem_entry_cde(struct inode *dir, const struct qstr *name, coord_t * coord,
+		  lock_handle * lh, reiser4_dir_entry_desc * entry);
+int max_name_len_cde(const struct inode *dir);
+
+/* __FS_REISER4_PLUGIN_COMPRESSED_DE_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/item/ctail.c newtree/fs/reiser4/plugin/item/ctail.c
--- oldtree/fs/reiser4/plugin/item/ctail.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/ctail.c	2006-02-21 15:58:35.449757376 +0000
@@ -0,0 +1,1591 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* ctails (aka "clustered tails") are items for cryptcompress objects */
+
+/* DESCRIPTION:
+
+Each cryptcompress object is stored on disk as a set of clusters sliced
+into ctails.
+
+Internal on-disk structure:
+
+        HEADER   (1)  Here stored disk cluster shift
+	BODY
+*/
+
+#include "../../forward.h"
+#include "../../debug.h"
+#include "../../dformat.h"
+#include "../../kassign.h"
+#include "../../key.h"
+#include "../../coord.h"
+#include "item.h"
+#include "../node/node.h"
+#include "../plugin.h"
+#include "../object.h"
+#include "../../znode.h"
+#include "../../carry.h"
+#include "../../tree.h"
+#include "../../inode.h"
+#include "../../super.h"
+#include "../../context.h"
+#include "../../page_cache.h"
+#include "../cluster.h"
+#include "../../flush.h"
+#include "../../tree_walk.h"
+#include "../file/funcs.h"
+
+#include <linux/pagevec.h>
+#include <linux/swap.h>
+#include <linux/fs.h>
+
+/* return body of ctail item at @coord */
+static ctail_item_format *ctail_formatted_at(const coord_t * coord)
+{
+	assert("edward-60", coord != NULL);
+	return item_body_by_coord(coord);
+}
+
+int cluster_shift_by_coord(const coord_t * coord)
+{
+	return get_unaligned(&ctail_formatted_at(coord)->cluster_shift);
+}
+
+static loff_t off_by_coord(const coord_t * coord)
+{
+	reiser4_key key;
+	return get_key_offset(item_key_by_coord(coord, &key));
+}
+
+static int coord_is_unprepped_ctail(const coord_t * coord)
+{
+	assert("edward-1233", coord != NULL);
+	assert("edward-1234", item_id_by_coord(coord) == CTAIL_ID);
+	assert("edward-1235",
+	       ergo((int)cluster_shift_by_coord(coord) == (int)UCTAIL_SHIFT,
+		    nr_units_ctail(coord) == (pos_in_node_t) UCTAIL_NR_UNITS));
+
+	return (int)cluster_shift_by_coord(coord) == (int)UCTAIL_SHIFT;
+}
+
+cloff_t clust_by_coord(const coord_t * coord, struct inode *inode)
+{
+	int shift;
+
+	if (inode != NULL) {
+		shift = inode_cluster_shift(inode);
+		assert("edward-1236",
+		       ergo(!coord_is_unprepped_ctail(coord),
+			    shift == cluster_shift_by_coord(coord)));
+	} else {
+		assert("edward-1237", !coord_is_unprepped_ctail(coord));
+		shift = cluster_shift_by_coord(coord);
+	}
+	return off_by_coord(coord) >> shift;
+}
+
+static int disk_cluster_size(const coord_t * coord)
+{
+	assert("edward-1156",
+	       item_plugin_by_coord(coord) == item_plugin_by_id(CTAIL_ID));
+	/* calculation of disk cluster size
+	   is meaninless if ctail is unprepped */
+	assert("edward-1238", !coord_is_unprepped_ctail(coord));
+
+	return 1 << cluster_shift_by_coord(coord);
+}
+
+/* true if the key is of first disk cluster item */
+static int is_disk_cluster_key(const reiser4_key * key, const coord_t * coord)
+{
+	assert("edward-1239", item_id_by_coord(coord) == CTAIL_ID);
+
+	return coord_is_unprepped_ctail(coord) ||
+	    ((get_key_offset(key) &
+	      ((loff_t) disk_cluster_size(coord) - 1)) == 0);
+}
+
+static char *first_unit(coord_t * coord)
+{
+	/* FIXME: warning: pointer of type `void *' used in arithmetic */
+	return (char *)item_body_by_coord(coord) + sizeof(ctail_item_format);
+}
+
+/* plugin->u.item.b.max_key_inside :
+   tail_max_key_inside */
+
+/* plugin->u.item.b.can_contain_key */
+int
+can_contain_key_ctail(const coord_t * coord, const reiser4_key * key,
+		      const reiser4_item_data * data)
+{
+	reiser4_key item_key;
+
+	if (item_plugin_by_coord(coord) != data->iplug)
+		return 0;
+
+	item_key_by_coord(coord, &item_key);
+	if (get_key_locality(key) != get_key_locality(&item_key) ||
+	    get_key_objectid(key) != get_key_objectid(&item_key))
+		return 0;
+	if (get_key_offset(&item_key) + nr_units_ctail(coord) !=
+	    get_key_offset(key))
+		return 0;
+	if (is_disk_cluster_key(key, coord))
+		return 0;
+	return 1;
+}
+
+/* plugin->u.item.b.mergeable
+   c-tails of different clusters are not mergeable */
+int mergeable_ctail(const coord_t * p1, const coord_t * p2)
+{
+	reiser4_key key1, key2;
+
+	assert("edward-62", item_id_by_coord(p1) == CTAIL_ID);
+	assert("edward-61",
+	       item_type_by_coord(p1) == UNIX_FILE_METADATA_ITEM_TYPE);
+
+	if (item_id_by_coord(p2) != CTAIL_ID) {
+		/* second item is of another type */
+		return 0;
+	}
+
+	item_key_by_coord(p1, &key1);
+	item_key_by_coord(p2, &key2);
+	if (get_key_locality(&key1) != get_key_locality(&key2) ||
+	    get_key_objectid(&key1) != get_key_objectid(&key2) ||
+	    get_key_type(&key1) != get_key_type(&key2)) {
+		/* items of different objects */
+		return 0;
+	}
+	if (get_key_offset(&key1) + nr_units_ctail(p1) != get_key_offset(&key2))
+		/*  not adjacent items */
+		return 0;
+	if (is_disk_cluster_key(&key2, p2))
+		return 0;
+	return 1;
+}
+
+/* plugin->u.item.b.nr_units */
+pos_in_node_t nr_units_ctail(const coord_t * coord)
+{
+	return (item_length_by_coord(coord) -
+		sizeof(ctail_formatted_at(coord)->cluster_shift));
+}
+
+/* plugin->u.item.b.estimate:
+   estimate how much space is needed to insert/paste @data->length bytes
+   into ctail at @coord */
+int estimate_ctail(const coord_t * coord /* coord of item */ ,
+		   const reiser4_item_data *
+		   data /* parameters for new item */ )
+{
+	if (coord == NULL)
+		/* insert */
+		return (sizeof(ctail_item_format) + data->length);
+	else
+		/* paste */
+		return data->length;
+}
+
+/* ->init() method for this item plugin. */
+int init_ctail(coord_t * to /* coord of item */ ,
+	       coord_t * from /* old_item */ ,
+	       reiser4_item_data * data /* structure used for insertion */ )
+{
+	int cluster_shift;	/* cpu value to convert */
+
+	if (data) {
+		assert("edward-463", data->length > sizeof(ctail_item_format));
+		cluster_shift = *((int *)(data->arg));
+		data->length -= sizeof(ctail_item_format);
+	} else {
+		assert("edward-464", from != NULL);
+		assert("edward-855", ctail_ok(from));
+		cluster_shift = (int)(cluster_shift_by_coord(from));
+	}
+	put_unaligned((d8)cluster_shift, &ctail_formatted_at(to)->cluster_shift);
+	assert("edward-856", ctail_ok(to));
+	return 0;
+}
+
+/* plugin->u.item.b.lookup:
+   NULL: We are looking for item keys only */
+
+#if REISER4_DEBUG
+int ctail_ok(const coord_t * coord)
+{
+	return coord_is_unprepped_ctail(coord) ||
+	    cluster_shift_ok(cluster_shift_by_coord(coord));
+}
+
+/* plugin->u.item.b.check */
+int check_ctail(const coord_t * coord, const char **error)
+{
+	if (!ctail_ok(coord)) {
+		if (error)
+			*error = "bad cluster shift in ctail";
+		return 1;
+	}
+	return 0;
+}
+#endif
+
+/* plugin->u.item.b.paste */
+int
+paste_ctail(coord_t * coord, reiser4_item_data * data,
+	    carry_plugin_info * info UNUSED_ARG)
+{
+	unsigned old_nr_units;
+
+	assert("edward-268", data->data != NULL);
+	/* copy only from kernel space */
+	assert("edward-66", data->user == 0);
+
+	old_nr_units =
+	    item_length_by_coord(coord) - sizeof(ctail_item_format) -
+	    data->length;
+
+	/* ctail items never get pasted in the middle */
+
+	if (coord->unit_pos == 0 && coord->between == AT_UNIT) {
+
+		/* paste at the beginning when create new item */
+		assert("edward-450",
+		       item_length_by_coord(coord) ==
+		       data->length + sizeof(ctail_item_format));
+		assert("edward-451", old_nr_units == 0);
+	} else if (coord->unit_pos == old_nr_units - 1
+		   && coord->between == AFTER_UNIT) {
+
+		/* paste at the end */
+		coord->unit_pos++;
+	} else
+		impossible("edward-453", "bad paste position");
+
+	memcpy(first_unit(coord) + coord->unit_pos, data->data, data->length);
+
+	assert("edward-857", ctail_ok(coord));
+
+	return 0;
+}
+
+/* plugin->u.item.b.fast_paste */
+
+/* plugin->u.item.b.can_shift
+   number of units is returned via return value, number of bytes via @size. For
+   ctail items they coincide */
+int
+can_shift_ctail(unsigned free_space, coord_t * source,
+		znode * target, shift_direction direction UNUSED_ARG,
+		unsigned *size /* number of bytes */ , unsigned want)
+{
+	/* make sure that that we do not want to shift more than we have */
+	assert("edward-68", want > 0 && want <= nr_units_ctail(source));
+
+	*size = min(want, free_space);
+
+	if (!target) {
+		/* new item will be created */
+		if (*size <= sizeof(ctail_item_format)) {
+			*size = 0;
+			return 0;
+		}
+		return *size - sizeof(ctail_item_format);
+	}
+	return *size;
+}
+
+/* plugin->u.item.b.copy_units
+   cooperates with ->can_shift() */
+void
+copy_units_ctail(coord_t * target, coord_t * source,
+		 unsigned from, unsigned count /* units */ ,
+		 shift_direction where_is_free_space,
+		 unsigned free_space /* bytes */ )
+{
+	/* make sure that item @target is expanded already */
+	assert("edward-69", (unsigned)item_length_by_coord(target) >= count);
+	assert("edward-70", free_space == count || free_space == count + 1);
+
+	assert("edward-858", ctail_ok(source));
+
+	if (where_is_free_space == SHIFT_LEFT) {
+		/* append item @target with @count first bytes of @source:
+		   this restriction came from ordinary tails */
+		assert("edward-71", from == 0);
+		assert("edward-860", ctail_ok(target));
+
+		memcpy(first_unit(target) + nr_units_ctail(target) - count,
+		       first_unit(source), count);
+	} else {
+		/* target item is moved to right already */
+		reiser4_key key;
+
+		assert("edward-72", nr_units_ctail(source) == from + count);
+
+		if (free_space == count) {
+			init_ctail(target, source, NULL);
+		} else {
+			/* new item has been created */
+			assert("edward-862", ctail_ok(target));
+		}
+		memcpy(first_unit(target), first_unit(source) + from, count);
+
+		assert("edward-863", ctail_ok(target));
+
+		/* new units are inserted before first unit in an item,
+		   therefore, we have to update item key */
+		item_key_by_coord(source, &key);
+		set_key_offset(&key, get_key_offset(&key) + from);
+
+		node_plugin_by_node(target->node)->update_item_key(target, &key,
+								   NULL /*info */);
+	}
+}
+
+/* plugin->u.item.b.create_hook */
+int create_hook_ctail(const coord_t * coord, void *arg)
+{
+	assert("edward-864", znode_is_loaded(coord->node));
+
+	znode_set_convertible(coord->node);
+	return 0;
+}
+
+/* plugin->u.item.b.kill_hook */
+int
+kill_hook_ctail(const coord_t * coord, pos_in_node_t from, pos_in_node_t count,
+		carry_kill_data * kdata)
+{
+	struct inode *inode;
+
+	assert("edward-1157", item_id_by_coord(coord) == CTAIL_ID);
+	assert("edward-291", znode_is_write_locked(coord->node));
+
+	inode = kdata->inode;
+	if (inode) {
+		reiser4_key key;
+		item_key_by_coord(coord, &key);
+
+		if (from == 0 && is_disk_cluster_key(&key, coord)) {
+			cloff_t start =
+			    off_to_clust(get_key_offset(&key), inode);
+			truncate_page_cluster(inode, start);
+		}
+	}
+	return 0;
+}
+
+/* for shift_hook_ctail(),
+   return true if the first disk cluster item has dirty child
+*/
+static int ctail_convertible(const coord_t * coord)
+{
+	int result;
+	reiser4_key key;
+	jnode *child = NULL;
+
+	assert("edward-477", coord != NULL);
+	assert("edward-478", item_id_by_coord(coord) == CTAIL_ID);
+
+	if (coord_is_unprepped_ctail(coord))
+		/* unprepped ctail should be converted */
+		return 1;
+
+	item_key_by_coord(coord, &key);
+	child = jlookup(current_tree,
+			get_key_objectid(&key),
+			off_to_pg(off_by_coord(coord)));
+	if (!child)
+		return 0;
+	result = JF_ISSET(child, JNODE_DIRTY);
+	jput(child);
+	return result;
+}
+
+/* FIXME-EDWARD */
+/* plugin->u.item.b.shift_hook */
+int shift_hook_ctail(const coord_t * item /* coord of item */ ,
+		     unsigned from UNUSED_ARG /* start unit */ ,
+		     unsigned count UNUSED_ARG /* stop unit */ ,
+		     znode * old_node /* old parent */ )
+{
+	assert("edward-479", item != NULL);
+	assert("edward-480", item->node != old_node);
+
+	if (!znode_convertible(old_node) || znode_convertible(item->node))
+		return 0;
+	if (ctail_convertible(item))
+		znode_set_convertible(item->node);
+	return 0;
+}
+
+static int
+cut_or_kill_ctail_units(coord_t * coord, pos_in_node_t from, pos_in_node_t to,
+			int cut, void *p, reiser4_key * smallest_removed,
+			reiser4_key * new_first)
+{
+	pos_in_node_t count;	/* number of units to cut */
+	char *item;
+
+	count = to - from + 1;
+	item = item_body_by_coord(coord);
+
+	assert("edward-74", ergo(from != 0, to == coord_last_unit_pos(coord)));
+
+	if (smallest_removed) {
+		/* store smallest key removed */
+		item_key_by_coord(coord, smallest_removed);
+		set_key_offset(smallest_removed,
+			       get_key_offset(smallest_removed) + from);
+	}
+
+	if (new_first) {
+		assert("vs-1531", from == 0);
+
+		item_key_by_coord(coord, new_first);
+		set_key_offset(new_first,
+			       get_key_offset(new_first) + from + count);
+	}
+
+	if (!cut)
+		kill_hook_ctail(coord, from, 0, (struct carry_kill_data *)p);
+
+	if (from == 0) {
+		if (count != nr_units_ctail(coord)) {
+			/* part of item is removed, so move free space at the beginning
+			   of the item and update item key */
+			reiser4_key key;
+			memcpy(item + to + 1, item, sizeof(ctail_item_format));
+			item_key_by_coord(coord, &key);
+			set_key_offset(&key, get_key_offset(&key) + count);
+			node_plugin_by_node(coord->node)->update_item_key(coord,
+									  &key,
+									  NULL);
+		} else {
+			/* cut_units should not be called to cut evrything */
+			assert("vs-1532", ergo(cut, 0));
+			/* whole item is cut, so more then amount of space occupied
+			   by units got freed */
+			count += sizeof(ctail_item_format);
+		}
+		if (REISER4_DEBUG)
+			memset(item, 0, count);
+	} else if (REISER4_DEBUG)
+		memset(item + sizeof(ctail_item_format) + from, 0, count);
+	return count;
+}
+
+/* plugin->u.item.b.cut_units */
+int
+cut_units_ctail(coord_t * item, pos_in_node_t from, pos_in_node_t to,
+		carry_cut_data * cdata, reiser4_key * smallest_removed,
+		reiser4_key * new_first)
+{
+	return cut_or_kill_ctail_units(item, from, to, 1, NULL,
+				       smallest_removed, new_first);
+}
+
+/* plugin->u.item.b.kill_units */
+int
+kill_units_ctail(coord_t * item, pos_in_node_t from, pos_in_node_t to,
+		 struct carry_kill_data *kdata, reiser4_key * smallest_removed,
+		 reiser4_key * new_first)
+{
+	return cut_or_kill_ctail_units(item, from, to, 0, kdata,
+				       smallest_removed, new_first);
+}
+
+/* plugin->u.item.s.file.read */
+int read_ctail(struct file *file UNUSED_ARG, flow_t * f, hint_t * hint)
+{
+	uf_coord_t *uf_coord;
+	coord_t *coord;
+
+	uf_coord = &hint->ext_coord;
+	coord = &uf_coord->coord;
+	assert("edward-127", f->user == 0);
+	assert("edward-129", coord && coord->node);
+	assert("edward-130", coord_is_existing_unit(coord));
+	assert("edward-132", znode_is_loaded(coord->node));
+
+	/* start read only from the beginning of ctail */
+	assert("edward-133", coord->unit_pos == 0);
+	/* read only whole ctails */
+	assert("edward-135", nr_units_ctail(coord) <= f->length);
+
+	assert("edward-136", schedulable());
+	assert("edward-886", ctail_ok(coord));
+
+	if (f->data)
+		memcpy(f->data, (char *)first_unit(coord),
+		       (size_t) nr_units_ctail(coord));
+
+	dclust_set_extension(hint);
+	mark_page_accessed(znode_page(coord->node));
+	move_flow_forward(f, nr_units_ctail(coord));
+
+	return 0;
+}
+
+/* Reads a disk cluster consists of ctail items,
+   attaches a transform stream with plain text */
+int ctail_read_disk_cluster(reiser4_cluster_t * clust, struct inode *inode,
+			    int write)
+{
+	int result;
+	assert("edward-671", clust->hint != NULL);
+	assert("edward-140", clust->dstat == INVAL_DISK_CLUSTER);
+	assert("edward-672", crc_inode_ok(inode));
+
+	/* set input stream */
+	result = grab_tfm_stream(inode, &clust->tc, INPUT_STREAM);
+	if (result)
+		return result;
+
+	result = find_cluster(clust, inode, 1 /* read */ , write);
+	assert("edward-1340", !result);
+	if (result)
+		return result;
+	if (!write)
+		/* write still need the lock to insert unprepped
+		   items, etc... */
+		put_hint_cluster(clust, inode, ZNODE_READ_LOCK);
+
+	assert("edward-673",
+	       ergo(write, znode_is_write_locked(clust->hint->lh.node)));
+
+	if (clust->dstat == FAKE_DISK_CLUSTER ||
+	    clust->dstat == UNPR_DISK_CLUSTER) {
+		tfm_cluster_set_uptodate(&clust->tc);
+		return 0;
+	}
+	result = grab_coa(&clust->tc, inode_compression_plugin(inode));
+	if (result)
+		return result;
+	result = inflate_cluster(clust, inode);
+	if (result)
+		return result;
+	tfm_cluster_set_uptodate(&clust->tc);
+	return 0;
+}
+
+/* read one locked page */
+int do_readpage_ctail(struct inode * inode, reiser4_cluster_t * clust,
+		      struct page *page)
+{
+	int ret;
+	unsigned cloff;
+	char *data;
+	size_t pgcnt;
+	tfm_cluster_t *tc = &clust->tc;
+
+	assert("edward-212", PageLocked(page));
+
+	if (PageUptodate(page))
+		goto exit;
+
+	if (!tfm_cluster_is_uptodate(&clust->tc)) {
+		clust->index = pg_to_clust(page->index, inode);
+		unlock_page(page);
+		ret = ctail_read_disk_cluster(clust, inode, 0 /* read */ );
+		lock_page(page);
+		if (ret)
+			return ret;
+	}
+	if (PageUptodate(page))
+		/* races with another read/write */
+		goto exit;
+
+	/* bytes in the page */
+	pgcnt = cnt_to_pgcnt(i_size_read(inode), page->index);
+
+	if (pgcnt == 0) {
+		assert("edward-1290", 0);
+		return RETERR(-EINVAL);
+	}
+	assert("edward-119", tfm_cluster_is_uptodate(tc));
+
+	switch (clust->dstat) {
+	case UNPR_DISK_CLUSTER:
+		assert("edward-1285", 0);
+#if REISER4_DEBUG
+		warning("edward-1168",
+			"page %lu is not uptodate and disk cluster %lu (inode %llu) is unprepped\n",
+			page->index, clust->index,
+			(unsigned long long)get_inode_oid(inode));
+#endif
+	case FAKE_DISK_CLUSTER:
+		/* fill the page by zeroes */
+		data = kmap_atomic(page, KM_USER0);
+
+		memset(data, 0, PAGE_CACHE_SIZE);
+		flush_dcache_page(page);
+		kunmap_atomic(data, KM_USER0);
+		SetPageUptodate(page);
+		break;
+	case PREP_DISK_CLUSTER:
+		/* fill the page by transformed data */
+		assert("edward-1058", !PageUptodate(page));
+		assert("edward-120", tc->len <= inode_cluster_size(inode));
+
+		/* start page offset in the cluster */
+		cloff = pg_to_off_to_cloff(page->index, inode);
+
+		data = kmap(page);
+		memcpy(data, tfm_stream_data(tc, OUTPUT_STREAM) + cloff, pgcnt);
+		memset(data + pgcnt, 0, (size_t) PAGE_CACHE_SIZE - pgcnt);
+		flush_dcache_page(page);
+		kunmap(page);
+		SetPageUptodate(page);
+		break;
+	default:
+		impossible("edward-1169", "bad disk cluster state");
+	}
+      exit:
+	return 0;
+}
+
+/* plugin->u.item.s.file.readpage */
+int readpage_ctail(void *vp, struct page *page)
+{
+	int result;
+	hint_t *hint;
+	reiser4_cluster_t *clust = vp;
+
+	assert("edward-114", clust != NULL);
+	assert("edward-115", PageLocked(page));
+	assert("edward-116", !PageUptodate(page));
+	assert("edward-117", !jprivate(page) && !PagePrivate(page));
+	assert("edward-118", page->mapping && page->mapping->host);
+	assert("edward-867", !tfm_cluster_is_uptodate(&clust->tc));
+
+	hint = kmalloc(sizeof(*hint), GFP_KERNEL);
+	if (hint == NULL)
+		return RETERR(-ENOMEM);
+	clust->hint = hint;
+	result = load_file_hint(clust->file, hint);
+	if (result) {
+		kfree(hint);
+		return result;
+	}
+	assert("vs-25", hint->ext_coord.lh == &hint->lh);
+	result = do_readpage_ctail(page->mapping->host, clust, page);
+
+	assert("edward-213", PageLocked(page));
+	assert("edward-1163", ergo(!result, PageUptodate(page)));
+	assert("edward-868",
+	       ergo(!result, tfm_cluster_is_uptodate(&clust->tc)));
+
+	unlock_page(page);
+	done_lh(&hint->lh);
+	hint->ext_coord.valid = 0;
+	save_file_hint(clust->file, hint);
+	kfree(hint);
+	tfm_cluster_clr_uptodate(&clust->tc);
+
+	return result;
+}
+
+/* This unconditionally reads a disk cluster.
+   Helper function for ->readpages() */
+static int
+ctail_read_page_cluster(reiser4_cluster_t * clust, struct inode *inode)
+{
+	int i;
+	int result;
+	assert("edward-779", clust != NULL);
+	assert("edward-1059", clust->win == NULL);
+	assert("edward-780", inode != NULL);
+
+	result = prepare_page_cluster(inode, clust, 0 /* do not capture */ );
+	if (result)
+		return result;
+	result = ctail_read_disk_cluster(clust, inode, 0 /* read */ );
+	if (result)
+		goto out;
+	/* at this point stream with valid plain text is attached */
+	assert("edward-781", tfm_cluster_is_uptodate(&clust->tc));
+
+	for (i = 0; i < clust->nr_pages; i++) {
+		struct page *page = clust->pages[i];
+		lock_page(page);
+		result = do_readpage_ctail(inode, clust, page);
+		unlock_page(page);
+		if (result)
+			break;
+	}
+	tfm_cluster_clr_uptodate(&clust->tc);
+      out:
+	release_cluster_pages_nocapture(clust);
+	return result;
+}
+
+#define list_to_page(head) (list_entry((head)->prev, struct page, lru))
+#define list_to_next_page(head) (list_entry((head)->prev->prev, struct page, lru))
+
+#if REISER4_DEBUG
+#define check_order(pages)                                                    \
+assert("edward-214", ergo(!list_empty(pages) && pages->next != pages->prev,   \
+       list_to_page(pages)->index < list_to_next_page(pages)->index))
+#endif
+
+/* plugin->u.item.s.file.readpages
+   Populate an address space with some page clusters,
+   and start reads against them.
+   FIXME-EDWARD: this function should return errors?
+*/
+void
+readpages_ctail(void *vp, struct address_space *mapping,
+		struct list_head *pages)
+{
+	int ret = 0;
+	hint_t *hint;
+	reiser4_cluster_t clust;
+	struct page *page;
+	struct pagevec lru_pvec;
+	struct inode *inode = mapping->host;
+	int progress = 0;
+
+	assert("edward-214", ergo(!list_empty(pages) &&
+				  pages->next != pages->prev,
+				  list_to_page(pages)->index <
+				  list_to_next_page(pages)->index));
+	pagevec_init(&lru_pvec, 0);
+	cluster_init_read(&clust, NULL);
+	clust.file = vp;
+	hint = kmalloc(sizeof(*hint), GFP_KERNEL);
+	if (hint == NULL) {
+		warning("vs-28", "failed to allocate hint");
+		goto exit1;
+	}
+	clust.hint = hint;
+	ret = load_file_hint(clust.file, hint);
+	if (ret)
+		goto exit2;
+	ret = alloc_cluster_pgset(&clust, cluster_nrpages(inode));
+	if (ret)
+		goto exit3;
+	assert("vs-26", hint->ext_coord.lh == &hint->lh);
+
+	/* address_space-level file readahead doesn't know about
+	   reiser4 concept of clustering, so we work around this
+	   fact: with each page of the list @pages address space
+	   will be populated with the whole page cluster.
+	*/
+	while (!list_empty(pages)) {
+		page = list_to_page(pages);
+		list_del(&page->lru);
+		if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) {
+			page_cache_release(page);
+			continue;
+		}
+		if (PageUptodate(page)) {
+			if (!pagevec_add(&lru_pvec, page))
+				__pagevec_lru_add(&lru_pvec);
+			unlock_page(page);
+			continue;
+		}
+		unlock_page(page);
+
+		move_cluster_forward(&clust, inode, page->index, &progress);
+		ret = ctail_read_page_cluster(&clust, inode);
+		if (ret)
+			break;
+		assert("edward-869", !tfm_cluster_is_uptodate(&clust.tc));
+		lock_page(page);
+
+		ret = do_readpage_ctail(inode, &clust, page);
+		if (!pagevec_add(&lru_pvec, page))
+			__pagevec_lru_add(&lru_pvec);
+		if (ret) {
+			warning("edward-215", "do_readpage_ctail failed");
+			unlock_page(page);
+			break;
+		}
+		assert("edward-1061", PageUptodate(page));
+
+		unlock_page(page);
+	}
+	assert("edward-870", !tfm_cluster_is_uptodate(&clust.tc));
+ exit3:
+	done_lh(&hint->lh);
+	save_file_hint(clust.file, hint);
+	hint->ext_coord.valid = 0;
+ exit2:
+	kfree(hint);
+ exit1:
+	while (!list_empty(pages)) {
+		struct page *victim;
+		victim = list_to_page(pages);
+		list_del(&victim->lru);
+		page_cache_release(victim);
+	}
+	put_cluster_handle(&clust);
+	pagevec_lru_add(&lru_pvec);
+	return;
+}
+
+/*
+   plugin->u.item.s.file.append_key
+   key of the first item of the next disk cluster
+*/
+reiser4_key *append_key_ctail(const coord_t * coord, reiser4_key * key)
+{
+	assert("edward-1241", item_id_by_coord(coord) == CTAIL_ID);
+	assert("edward-1242", cluster_shift_ok(cluster_shift_by_coord(coord)));
+
+	item_key_by_coord(coord, key);
+	set_key_offset(key,
+		       ((__u64) (clust_by_coord(coord, NULL)) +
+			1) << cluster_shift_by_coord(coord));
+	return key;
+}
+
+static int
+insert_unprepped_ctail(reiser4_cluster_t * clust, struct inode *inode)
+{
+	int result;
+	char buf[UCTAIL_NR_UNITS];
+	reiser4_item_data data;
+	reiser4_key key;
+	int shift = (int)UCTAIL_SHIFT;
+
+	memset(buf, 0, (size_t) UCTAIL_NR_UNITS);
+	result = key_by_inode_cryptcompress(inode,
+					    clust_to_off(clust->index, inode),
+					    &key);
+	if (result)
+		return result;
+	data.user = 0;
+	data.iplug = item_plugin_by_id(CTAIL_ID);
+	data.arg = &shift;
+	data.length = sizeof(ctail_item_format) + (size_t) UCTAIL_NR_UNITS;
+	data.data = buf;
+
+	result = insert_by_coord(&clust->hint->ext_coord.coord,
+				 &data, &key, clust->hint->ext_coord.lh, 0);
+	return result;
+}
+
+static int
+insert_crc_flow(coord_t * coord, lock_handle * lh, flow_t * f,
+		struct inode *inode)
+{
+	int result;
+	carry_pool *pool;
+	carry_level *lowest_level;
+	reiser4_item_data *data;
+	carry_op *op;
+	int cluster_shift = inode_cluster_shift(inode);
+
+	pool =
+	    init_carry_pool(sizeof(*pool) + 3 * sizeof(*lowest_level) +
+			    sizeof(*data));
+	if (IS_ERR(pool))
+		return PTR_ERR(pool);
+	lowest_level = (carry_level *) (pool + 1);
+	init_carry_level(lowest_level, pool);
+	data = (reiser4_item_data *) (lowest_level + 3);
+
+	assert("edward-466", coord->between == AFTER_ITEM
+	       || coord->between == AFTER_UNIT || coord->between == BEFORE_ITEM
+	       || coord->between == EMPTY_NODE
+	       || coord->between == BEFORE_UNIT);
+
+	if (coord->between == AFTER_UNIT) {
+		coord->unit_pos = 0;
+		coord->between = AFTER_ITEM;
+	}
+	op = post_carry(lowest_level, COP_INSERT_FLOW, coord->node,
+			0 /* operate directly on coord -> node */ );
+	if (IS_ERR(op) || (op == NULL)) {
+		done_carry_pool(pool);
+		return RETERR(op ? PTR_ERR(op) : -EIO);
+	}
+	data->user = 0;
+	data->iplug = item_plugin_by_id(CTAIL_ID);
+	data->arg = &cluster_shift;
+
+	data->length = 0;
+	data->data = NULL;
+
+	op->u.insert_flow.flags = COPI_DONT_SHIFT_LEFT | COPI_DONT_SHIFT_RIGHT;
+	op->u.insert_flow.insert_point = coord;
+	op->u.insert_flow.flow = f;
+	op->u.insert_flow.data = data;
+	op->u.insert_flow.new_nodes = 0;
+
+	lowest_level->track_type = CARRY_TRACK_CHANGE;
+	lowest_level->tracked = lh;
+
+	result = carry(lowest_level, NULL);
+	done_carry_pool(pool);
+
+	return result;
+}
+
+/* Implementation of CRC_APPEND_ITEM mode of ctail conversion */
+static int
+insert_crc_flow_in_place(coord_t * coord, lock_handle * lh, flow_t * f,
+			 struct inode *inode)
+{
+	int ret;
+	coord_t pos;
+	lock_handle lock;
+
+	assert("edward-674", f->length <= inode_scaled_cluster_size(inode));
+	assert("edward-484", coord->between == AT_UNIT
+	       || coord->between == AFTER_ITEM);
+	assert("edward-485", item_id_by_coord(coord) == CTAIL_ID);
+
+	coord_dup(&pos, coord);
+	pos.unit_pos = 0;
+	pos.between = AFTER_ITEM;
+
+	init_lh(&lock);
+	copy_lh(&lock, lh);
+
+	ret = insert_crc_flow(&pos, &lock, f, inode);
+	done_lh(&lock);
+	assert("edward-1347", znode_is_write_locked(lh->node));
+	assert("edward-1228", !ret);
+	return ret;
+}
+
+/* Implementation of CRC_OVERWRITE_ITEM mode of ctail conversion */
+static int overwrite_ctail(coord_t * coord, flow_t * f)
+{
+	unsigned count;
+
+	assert("edward-269", f->user == 0);
+	assert("edward-270", f->data != NULL);
+	assert("edward-271", f->length > 0);
+	assert("edward-272", coord_is_existing_unit(coord));
+	assert("edward-273", coord->unit_pos == 0);
+	assert("edward-274", znode_is_write_locked(coord->node));
+	assert("edward-275", schedulable());
+	assert("edward-467", item_id_by_coord(coord) == CTAIL_ID);
+	assert("edward-1243", ctail_ok(coord));
+
+	count = nr_units_ctail(coord);
+
+	if (count > f->length)
+		count = f->length;
+	memcpy(first_unit(coord), f->data, count);
+	move_flow_forward(f, count);
+	coord->unit_pos += count;
+	return 0;
+}
+
+/* Implementation of CRC_CUT_ITEM mode of ctail conversion:
+   cut ctail (part or whole) starting from next unit position */
+static int cut_ctail(coord_t * coord)
+{
+	coord_t stop;
+
+	assert("edward-435", coord->between == AT_UNIT &&
+	       coord->item_pos < coord_num_items(coord) &&
+	       coord->unit_pos <= coord_num_units(coord));
+
+	if (coord->unit_pos == coord_num_units(coord))
+		/* nothing to cut */
+		return 0;
+	coord_dup(&stop, coord);
+	stop.unit_pos = coord_last_unit_pos(coord);
+
+	return cut_node_content(coord, &stop, NULL, NULL, NULL);
+}
+
+int
+ctail_insert_unprepped_cluster(reiser4_cluster_t * clust, struct inode *inode)
+{
+	int result;
+	assert("edward-1244", inode != NULL);
+	assert("edward-1245", clust->hint != NULL);
+	assert("edward-1246", clust->dstat == FAKE_DISK_CLUSTER);
+	assert("edward-1247", clust->reserved == 1);
+	assert("edward-1248", get_current_context()->grabbed_blocks ==
+	       estimate_insert_cluster(inode));
+
+	result = get_disk_cluster_locked(clust, inode, ZNODE_WRITE_LOCK);
+	if (cbk_errored(result))
+		return result;
+	assert("edward-1249", result == CBK_COORD_NOTFOUND);
+	assert("edward-1250", znode_is_write_locked(clust->hint->lh.node));
+
+	assert("edward-1295",
+	       clust->hint->ext_coord.lh->node ==
+	       clust->hint->ext_coord.coord.node);
+
+	coord_set_between_clusters(&clust->hint->ext_coord.coord);
+
+	result = insert_unprepped_ctail(clust, inode);
+	all_grabbed2free();
+
+	assert("edward-1251", !result);
+	assert("edward-1252", crc_inode_ok(inode));
+	assert("edward-1253", znode_is_write_locked(clust->hint->lh.node));
+	assert("edward-1254",
+	       reiser4_clustered_blocks(reiser4_get_current_sb()));
+	assert("edward-1255",
+	       znode_convertible(clust->hint->ext_coord.coord.node));
+
+	return result;
+}
+
+static int do_convert_ctail(flush_pos_t * pos, crc_write_mode_t mode)
+{
+	int result = 0;
+	convert_item_info_t *info;
+
+	assert("edward-468", pos != NULL);
+	assert("edward-469", pos->sq != NULL);
+	assert("edward-845", item_convert_data(pos) != NULL);
+
+	info = item_convert_data(pos);
+	assert("edward-679", info->flow.data != NULL);
+
+	switch (mode) {
+	case CRC_APPEND_ITEM:
+		assert("edward-1229", info->flow.length != 0);
+		assert("edward-1256",
+		       cluster_shift_ok(cluster_shift_by_coord(&pos->coord)));
+		result =
+		    insert_crc_flow_in_place(&pos->coord, &pos->lock,
+					     &info->flow, info->inode);
+		break;
+	case CRC_OVERWRITE_ITEM:
+		assert("edward-1230", info->flow.length != 0);
+		overwrite_ctail(&pos->coord, &info->flow);
+		if (info->flow.length != 0)
+			break;
+	case CRC_CUT_ITEM:
+		assert("edward-1231", info->flow.length == 0);
+		result = cut_ctail(&pos->coord);
+		break;
+	default:
+		result = RETERR(-EIO);
+		impossible("edward-244", "bad convert mode");
+	}
+	return result;
+}
+
+/* plugin->u.item.f.scan */
+int scan_ctail(flush_scan * scan)
+{
+	int result = 0;
+	struct page *page;
+	struct inode *inode;
+	jnode *node = scan->node;
+
+	assert("edward-227", scan->node != NULL);
+	assert("edward-228", jnode_is_cluster_page(scan->node));
+	assert("edward-639", znode_is_write_locked(scan->parent_lock.node));
+
+	page = jnode_page(node);
+	inode = page->mapping->host;
+
+	if (!scanning_left(scan))
+		return result;
+	if (!ZF_ISSET(scan->parent_lock.node, JNODE_DIRTY))
+		znode_make_dirty(scan->parent_lock.node);
+
+	if (!znode_convertible(scan->parent_lock.node)) {
+		if (JF_ISSET(scan->node, JNODE_DIRTY))
+			znode_set_convertible(scan->parent_lock.node);
+		else {
+			warning("edward-681",
+				"cluster page is already processed");
+			return -EAGAIN;
+		}
+	}
+	return result;
+}
+
+/* If true, this function attaches children */
+static int should_attach_convert_idata(flush_pos_t * pos)
+{
+	int result;
+	assert("edward-431", pos != NULL);
+	assert("edward-432", pos->child == NULL);
+	assert("edward-619", znode_is_write_locked(pos->coord.node));
+	assert("edward-470",
+	       item_plugin_by_coord(&pos->coord) ==
+	       item_plugin_by_id(CTAIL_ID));
+
+	/* check for leftmost child */
+	utmost_child_ctail(&pos->coord, LEFT_SIDE, &pos->child);
+
+	if (!pos->child)
+		return 0;
+	spin_lock_jnode(pos->child);
+	result = (JF_ISSET(pos->child, JNODE_DIRTY) &&
+		  pos->child->atom == ZJNODE(pos->coord.node)->atom);
+	spin_unlock_jnode(pos->child);
+	if (!result && pos->child) {
+		/* existing child isn't to attach, clear up this one */
+		jput(pos->child);
+		pos->child = NULL;
+	}
+	return result;
+}
+
+/* plugin->init_convert_data() */
+static int
+init_convert_data_ctail(convert_item_info_t * idata, struct inode *inode)
+{
+	assert("edward-813", idata != NULL);
+	assert("edward-814", inode != NULL);
+
+	idata->inode = inode;
+	idata->d_cur = DC_FIRST_ITEM;
+	idata->d_next = DC_INVALID_STATE;
+
+	return 0;
+}
+
+static int alloc_item_convert_data(convert_info_t * sq)
+{
+	assert("edward-816", sq != NULL);
+	assert("edward-817", sq->itm == NULL);
+
+	sq->itm = kmalloc(sizeof(*sq->itm), GFP_KERNEL);
+	if (sq->itm == NULL)
+		return RETERR(-ENOMEM);
+	return 0;
+}
+
+static void free_item_convert_data(convert_info_t * sq)
+{
+	assert("edward-818", sq != NULL);
+	assert("edward-819", sq->itm != NULL);
+	assert("edward-820", sq->iplug != NULL);
+
+	kfree(sq->itm);
+	sq->itm = NULL;
+	return;
+}
+
+static int alloc_convert_data(flush_pos_t * pos)
+{
+	assert("edward-821", pos != NULL);
+	assert("edward-822", pos->sq == NULL);
+
+	pos->sq = kmalloc(sizeof(*pos->sq), GFP_KERNEL);
+	if (!pos->sq)
+		return RETERR(-ENOMEM);
+	memset(pos->sq, 0, sizeof(*pos->sq));
+	cluster_init_write(&pos->sq->clust, 0);
+	return 0;
+}
+
+void free_convert_data(flush_pos_t * pos)
+{
+	convert_info_t *sq;
+
+	assert("edward-823", pos != NULL);
+	assert("edward-824", pos->sq != NULL);
+
+	sq = pos->sq;
+	if (sq->itm)
+		free_item_convert_data(sq);
+	put_cluster_handle(&sq->clust);
+	kfree(pos->sq);
+	pos->sq = NULL;
+	return;
+}
+
+static int init_item_convert_data(flush_pos_t * pos, struct inode *inode)
+{
+	convert_info_t *sq;
+
+	assert("edward-825", pos != NULL);
+	assert("edward-826", pos->sq != NULL);
+	assert("edward-827", item_convert_data(pos) != NULL);
+	assert("edward-828", inode != NULL);
+
+	sq = pos->sq;
+
+	memset(sq->itm, 0, sizeof(*sq->itm));
+
+	/* iplug->init_convert_data() */
+	return init_convert_data_ctail(sq->itm, inode);
+}
+
+/* create and attach disk cluster info used by 'convert' phase of the flush
+   squalloc() */
+static int attach_convert_idata(flush_pos_t * pos, struct inode *inode)
+{
+	int ret = 0;
+	convert_item_info_t *info;
+	reiser4_cluster_t *clust;
+	file_plugin *fplug = inode_file_plugin(inode);
+	compression_plugin *cplug = inode_compression_plugin(inode);
+
+	assert("edward-248", pos != NULL);
+	assert("edward-249", pos->child != NULL);
+	assert("edward-251", inode != NULL);
+	assert("edward-682", crc_inode_ok(inode));
+	assert("edward-252", fplug == file_plugin_by_id(CRC_FILE_PLUGIN_ID));
+	assert("edward-473",
+	       item_plugin_by_coord(&pos->coord) ==
+	       item_plugin_by_id(CTAIL_ID));
+
+	if (!pos->sq) {
+		ret = alloc_convert_data(pos);
+		if (ret)
+			return ret;
+	}
+	clust = &pos->sq->clust;
+	ret = grab_coa(&clust->tc, cplug);
+	if (ret)
+		goto err;
+	ret = set_cluster_by_page(clust,
+				  jnode_page(pos->child),
+				  MAX_CLUSTER_NRPAGES);
+	if (ret)
+		goto err;
+
+	assert("edward-829", pos->sq != NULL);
+	assert("edward-250", item_convert_data(pos) == NULL);
+
+	pos->sq->iplug = item_plugin_by_id(CTAIL_ID);
+
+	ret = alloc_item_convert_data(pos->sq);
+	if (ret)
+		goto err;
+	ret = init_item_convert_data(pos, inode);
+	if (ret)
+		goto err;
+	info = item_convert_data(pos);
+
+	ret = flush_cluster_pages(clust, pos->child, inode);
+	if (ret)
+		goto err;
+
+	deflate_cluster(clust, inode);
+	inc_item_convert_count(pos);
+
+	/* make flow by transformed stream */
+	fplug->flow_by_inode(info->inode,
+			     (const char __user *)tfm_stream_data(&clust->tc, OUTPUT_STREAM),
+			     0 /* kernel space */ ,
+			     clust->tc.len,
+			     clust_to_off(clust->index, inode),
+			     WRITE_OP, &info->flow);
+	jput(pos->child);
+
+	assert("edward-683", crc_inode_ok(inode));
+	return 0;
+      err:
+	jput(pos->child);
+	free_convert_data(pos);
+	return ret;
+}
+
+/* clear up disk cluster info */
+static void detach_convert_idata(convert_info_t * sq)
+{
+	convert_item_info_t *info;
+
+	assert("edward-253", sq != NULL);
+	assert("edward-840", sq->itm != NULL);
+
+	info = sq->itm;
+	assert("edward-255", info->inode != NULL);
+	assert("edward-1212", info->flow.length == 0);
+
+	/* the final release of pages */
+	forget_cluster_pages(sq->clust.pages, sq->clust.nr_pages);
+	free_item_convert_data(sq);
+	return;
+}
+
+/* plugin->u.item.f.utmost_child */
+
+/* This function sets leftmost child for a first cluster item,
+   if the child exists, and NULL in other cases.
+   NOTE-EDWARD: Do not call this for RIGHT_SIDE */
+
+int utmost_child_ctail(const coord_t * coord, sideof side, jnode ** child)
+{
+	reiser4_key key;
+
+	item_key_by_coord(coord, &key);
+
+	assert("edward-257", coord != NULL);
+	assert("edward-258", child != NULL);
+	assert("edward-259", side == LEFT_SIDE);
+	assert("edward-260",
+	       item_plugin_by_coord(coord) == item_plugin_by_id(CTAIL_ID));
+
+	if (!is_disk_cluster_key(&key, coord))
+		*child = NULL;
+	else
+		*child = jlookup(current_tree,
+				 get_key_objectid(item_key_by_coord
+						  (coord, &key)),
+				 off_to_pg(get_key_offset(&key)));
+	return 0;
+}
+
+/* Returns true if @p2 is the next item to @p1
+   in the _same_ disk cluster.
+   Disk cluster is a set of items. If ->clustered() != NULL,
+   with each item the whole disk cluster should be read/modified
+*/
+static int clustered_ctail(const coord_t * p1, const coord_t * p2)
+{
+	return mergeable_ctail(p1, p2);
+}
+
+/* Go rightward and check for next disk cluster item, set
+   d_next to DC_CHAINED_ITEM, if the last one exists.
+   If the current position is last item, go to right neighbor.
+   Skip empty nodes. Note, that right neighbors may be not in
+   the slum because of races. If so, make it dirty and
+   convertible.
+*/
+static int next_item_dc_stat(flush_pos_t * pos)
+{
+	int ret = 0;
+	int stop = 0;
+	znode *cur;
+	coord_t coord;
+	lock_handle lh;
+	lock_handle right_lock;
+
+	assert("edward-1232", !node_is_empty(pos->coord.node));
+	assert("edward-1014",
+	       pos->coord.item_pos < coord_num_items(&pos->coord));
+	assert("edward-1015", chaining_data_present(pos));
+	assert("edward-1017",
+	       item_convert_data(pos)->d_next == DC_INVALID_STATE);
+
+	item_convert_data(pos)->d_next = DC_AFTER_CLUSTER;
+
+	if (item_convert_data(pos)->d_cur == DC_AFTER_CLUSTER)
+		return ret;
+	if (pos->coord.item_pos < coord_num_items(&pos->coord) - 1)
+		return ret;
+
+	/* check next slum item */
+	init_lh(&right_lock);
+	cur = pos->coord.node;
+
+	while (!stop) {
+		init_lh(&lh);
+		ret = reiser4_get_right_neighbor(&lh,
+						 cur,
+						 ZNODE_WRITE_LOCK,
+						 GN_CAN_USE_UPPER_LEVELS);
+		if (ret)
+			break;
+		ret = zload(lh.node);
+		if (ret) {
+			done_lh(&lh);
+			break;
+		}
+		coord_init_before_first_item(&coord, lh.node);
+
+		if (node_is_empty(lh.node)) {
+			znode_make_dirty(lh.node);
+			znode_set_convertible(lh.node);
+			stop = 0;
+		} else if (clustered_ctail(&pos->coord, &coord)) {
+
+			item_convert_data(pos)->d_next = DC_CHAINED_ITEM;
+
+			if (!ZF_ISSET(lh.node, JNODE_DIRTY)) {
+				/*
+				   warning("edward-1024",
+				   "next slum item mergeable, "
+				   "but znode %p isn't dirty\n",
+				   lh.node);
+				 */
+				znode_make_dirty(lh.node);
+			}
+			if (!znode_convertible(lh.node)) {
+				/*
+				   warning("edward-1272",
+				   "next slum item mergeable, "
+				   "but znode %p isn't convertible\n",
+				   lh.node);
+				 */
+				znode_set_convertible(lh.node);
+			}
+			stop = 1;
+		} else
+			stop = 1;
+		zrelse(lh.node);
+		done_lh(&right_lock);
+		copy_lh(&right_lock, &lh);
+		done_lh(&lh);
+		cur = right_lock.node;
+	}
+	done_lh(&right_lock);
+
+	if (ret == -E_NO_NEIGHBOR)
+		ret = 0;
+	return ret;
+}
+
+static int
+assign_convert_mode(convert_item_info_t * idata, crc_write_mode_t * mode)
+{
+	int result = 0;
+
+	assert("edward-1025", idata != NULL);
+
+	if (idata->flow.length) {
+		/* append or overwrite */
+		switch (idata->d_cur) {
+		case DC_FIRST_ITEM:
+		case DC_CHAINED_ITEM:
+			*mode = CRC_OVERWRITE_ITEM;
+			break;
+		case DC_AFTER_CLUSTER:
+			*mode = CRC_APPEND_ITEM;
+			break;
+		default:
+			impossible("edward-1018", "wrong current item state");
+		}
+	} else {
+		/* cut or invalidate */
+		switch (idata->d_cur) {
+		case DC_FIRST_ITEM:
+		case DC_CHAINED_ITEM:
+			*mode = CRC_CUT_ITEM;
+			break;
+		case DC_AFTER_CLUSTER:
+			result = 1;
+			break;
+		default:
+			impossible("edward-1019", "wrong current item state");
+		}
+	}
+	return result;
+}
+
+/* plugin->u.item.f.convert */
+/* write ctail in guessed mode */
+int convert_ctail(flush_pos_t * pos)
+{
+	int result;
+	int nr_items;
+	crc_write_mode_t mode = CRC_OVERWRITE_ITEM;
+
+	assert("edward-1020", pos != NULL);
+	assert("edward-1213", coord_num_items(&pos->coord) != 0);
+	assert("edward-1257", item_id_by_coord(&pos->coord) == CTAIL_ID);
+	assert("edward-1258", ctail_ok(&pos->coord));
+	assert("edward-261", pos->coord.node != NULL);
+
+	nr_items = coord_num_items(&pos->coord);
+	if (!chaining_data_present(pos)) {
+		if (should_attach_convert_idata(pos)) {
+			/* attach convert item info */
+			struct inode *inode;
+
+			assert("edward-264", pos->child != NULL);
+			assert("edward-265", jnode_page(pos->child) != NULL);
+			assert("edward-266",
+			       jnode_page(pos->child)->mapping != NULL);
+
+			inode = jnode_page(pos->child)->mapping->host;
+
+			assert("edward-267", inode != NULL);
+
+			/* attach item convert info by child and put the last one */
+			result = attach_convert_idata(pos, inode);
+			pos->child = NULL;
+			if (result == -E_REPEAT) {
+				/* jnode became clean, or there is no dirty
+				   pages (nothing to update in disk cluster) */
+				warning("edward-1021",
+					"convert_ctail: nothing to attach");
+				return 0;
+			}
+			if (result != 0)
+				return result;
+		} else
+			/* unconvertible */
+			return 0;
+	} else {
+		/* use old convert info */
+
+		convert_item_info_t *idata;
+
+		idata = item_convert_data(pos);
+
+		result = assign_convert_mode(idata, &mode);
+		if (result) {
+			/* disk cluster is over,
+			   nothing to update anymore */
+			detach_convert_idata(pos->sq);
+			return 0;
+		}
+	}
+
+	assert("edward-433", chaining_data_present(pos));
+	assert("edward-1022",
+	       pos->coord.item_pos < coord_num_items(&pos->coord));
+
+	result = next_item_dc_stat(pos);
+	if (result) {
+		detach_convert_idata(pos->sq);
+		return result;
+	}
+	result = do_convert_ctail(pos, mode);
+	if (result) {
+		detach_convert_idata(pos->sq);
+		return result;
+	}
+	switch (mode) {
+	case CRC_CUT_ITEM:
+		assert("edward-1214", item_convert_data(pos)->flow.length == 0);
+		assert("edward-1215",
+		       coord_num_items(&pos->coord) == nr_items ||
+		       coord_num_items(&pos->coord) == nr_items - 1);
+		if (item_convert_data(pos)->d_next == DC_CHAINED_ITEM)
+			break;
+		if (coord_num_items(&pos->coord) != nr_items) {
+			/* the item was killed, no more chained items */
+			detach_convert_idata(pos->sq);
+			if (!node_is_empty(pos->coord.node))
+				/* make sure the next item will be scanned */
+				coord_init_before_item(&pos->coord);
+			break;
+		}
+	case CRC_APPEND_ITEM:
+		assert("edward-434", item_convert_data(pos)->flow.length == 0);
+		detach_convert_idata(pos->sq);
+		break;
+	case CRC_OVERWRITE_ITEM:
+		if (coord_is_unprepped_ctail(&pos->coord)) {
+			/* convert unpprepped ctail to prepped one */
+			int shift;
+			shift =
+			    inode_cluster_shift(item_convert_data(pos)->inode);
+			assert("edward-1259", cluster_shift_ok(shift));
+			put_unaligned((d8)shift,
+				&ctail_formatted_at(&pos->coord)->
+				cluster_shift);
+		}
+		break;
+	}
+	return result;
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/item/ctail.h newtree/fs/reiser4/plugin/item/ctail.h
--- oldtree/fs/reiser4/plugin/item/ctail.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/ctail.h	2006-02-21 15:58:34.618883688 +0000
@@ -0,0 +1,89 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#if !defined( __FS_REISER4_CTAIL_H__ )
+#define __FS_REISER4_CTAIL_H__
+
+/* cryptcompress object item. See ctail.c for description. */
+
+#define UCTAIL_NR_UNITS 1
+#define UCTAIL_SHIFT 0xff
+
+typedef struct ctail_item_format {
+	/* cluster shift */
+	d8 cluster_shift;
+	/* ctail body */
+	d8 body[0];
+} __attribute__ ((packed)) ctail_item_format;
+
+/* The following is a set of various item states in a disk cluster.
+   Disk cluster is a set of items whose keys belong to the interval
+   [dc_key , dc_key + disk_cluster_size - 1] */
+typedef enum {
+	DC_INVALID_STATE = 0,
+	DC_FIRST_ITEM = 1,
+	DC_CHAINED_ITEM = 2,
+	DC_AFTER_CLUSTER = 3
+} dc_item_stat;
+
+typedef struct {
+	int shift;		/* we keep here a cpu value of cluster_shift field
+				   of ctail_item_format (see above) */
+} ctail_coord_extension_t;
+
+struct cut_list;
+
+/* plugin->item.b.* */
+int can_contain_key_ctail(const coord_t *, const reiser4_key *,
+			  const reiser4_item_data *);
+int mergeable_ctail(const coord_t * p1, const coord_t * p2);
+pos_in_node_t nr_units_ctail(const coord_t * coord);
+int estimate_ctail(const coord_t * coord, const reiser4_item_data * data);
+void print_ctail(const char *prefix, coord_t * coord);
+lookup_result lookup_ctail(const reiser4_key *, lookup_bias, coord_t *);
+
+int paste_ctail(coord_t * coord, reiser4_item_data * data,
+		carry_plugin_info * info UNUSED_ARG);
+int init_ctail(coord_t *, coord_t *, reiser4_item_data *);
+int can_shift_ctail(unsigned free_space, coord_t * coord,
+		    znode * target, shift_direction pend, unsigned *size,
+		    unsigned want);
+void copy_units_ctail(coord_t * target, coord_t * source, unsigned from,
+		      unsigned count, shift_direction where_is_free_space,
+		      unsigned free_space);
+int cut_units_ctail(coord_t * coord, pos_in_node_t from, pos_in_node_t to,
+		    carry_cut_data *, reiser4_key * smallest_removed,
+		    reiser4_key * new_first);
+int kill_units_ctail(coord_t * coord, pos_in_node_t from, pos_in_node_t to,
+		     carry_kill_data *, reiser4_key * smallest_removed,
+		     reiser4_key * new_first);
+int ctail_ok(const coord_t * coord);
+int check_ctail(const coord_t * coord, const char **error);
+
+/* plugin->u.item.s.* */
+int read_ctail(struct file *, flow_t *, hint_t *);
+int readpage_ctail(void *, struct page *);
+void readpages_ctail(void *, struct address_space *, struct list_head *);
+reiser4_key *append_key_ctail(const coord_t *, reiser4_key *);
+int create_hook_ctail(const coord_t * coord, void *arg);
+int kill_hook_ctail(const coord_t *, pos_in_node_t, pos_in_node_t,
+		    carry_kill_data *);
+int shift_hook_ctail(const coord_t *, unsigned, unsigned, znode *);
+
+/* plugin->u.item.f */
+int utmost_child_ctail(const coord_t *, sideof, jnode **);
+int scan_ctail(flush_scan *);
+int convert_ctail(flush_pos_t *);
+size_t inode_scaled_cluster_size(struct inode *);
+int cluster_shift_by_coord(const coord_t * coord);
+
+#endif				/* __FS_REISER4_CTAIL_H__ */
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/item/extent.c newtree/fs/reiser4/plugin/item/extent.c
--- oldtree/fs/reiser4/plugin/item/extent.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/extent.c	2006-02-21 15:58:34.619883536 +0000
@@ -0,0 +1,198 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#include "item.h"
+#include "../../key.h"
+#include "../../super.h"
+#include "../../carry.h"
+#include "../../inode.h"
+#include "../../page_cache.h"
+#include "../../emergency_flush.h"
+#include "../../flush.h"
+#include "../object.h"
+
+/* prepare structure reiser4_item_data. It is used to put one extent unit into tree */
+/* Audited by: green(2002.06.13) */
+reiser4_item_data *init_new_extent(reiser4_item_data * data, void *ext_unit,
+				   int nr_extents)
+{
+	data->data = ext_unit;
+	/* data->data is kernel space */
+	data->user = 0;
+	data->length = sizeof(reiser4_extent) * nr_extents;
+	data->arg = NULL;
+	data->iplug = item_plugin_by_id(EXTENT_POINTER_ID);
+	return data;
+}
+
+/* how many bytes are addressed by @nr first extents of the extent item */
+reiser4_block_nr extent_size(const coord_t * coord, pos_in_node_t nr)
+{
+	pos_in_node_t i;
+	reiser4_block_nr blocks;
+	reiser4_extent *ext;
+
+	ext = item_body_by_coord(coord);
+	assert("vs-263", nr <= nr_units_extent(coord));
+
+	blocks = 0;
+	for (i = 0; i < nr; i++, ext++) {
+		blocks += extent_get_width(ext);
+	}
+
+	return blocks * current_blocksize;
+}
+
+extent_state state_of_extent(reiser4_extent * ext)
+{
+	switch ((int)extent_get_start(ext)) {
+	case 0:
+		return HOLE_EXTENT;
+	case 1:
+		return UNALLOCATED_EXTENT;
+	default:
+		break;
+	}
+	return ALLOCATED_EXTENT;
+}
+
+int extent_is_unallocated(const coord_t * item)
+{
+	assert("jmacd-5133", item_is_extent(item));
+
+	return state_of_extent(extent_by_coord(item)) == UNALLOCATED_EXTENT;
+}
+
+/* set extent's start and width */
+void
+set_extent(reiser4_extent * ext, reiser4_block_nr start, reiser4_block_nr width)
+{
+	extent_set_start(ext, start);
+	extent_set_width(ext, width);
+}
+
+
+/**
+ * replace_extent - replace extent and paste 1 or 2 after it
+ * @un_extent: coordinate of extent to be overwritten
+ * @lh: need better comment
+ * @key: need better comment
+ * @exts_to_add: data prepared for insertion into tree
+ * @replace: need better comment
+ * @flags: need better comment
+ * @return_insert_position: need better comment
+ *
+ * Overwrites one extent, pastes 1 or 2 more ones after overwritten one.  If
+ * @return_inserted_position is 1 - @un_extent and @lh are returned set to
+ * first of newly inserted units, if it is 0 - @un_extent and @lh are returned
+ * set to extent which was overwritten.
+ */
+int replace_extent(struct replace_handle *h, int return_inserted_position)
+{
+	int result;
+	znode *orig_znode;
+	/*ON_DEBUG(reiser4_extent orig_ext);*/	/* this is for debugging */
+
+	assert("vs-990", coord_is_existing_unit(h->coord));
+	assert("vs-1375", znode_is_write_locked(h->coord->node));
+	assert("vs-1426", extent_get_width(&h->overwrite) != 0);
+	assert("vs-1427", extent_get_width(&h->new_extents[0]) != 0);
+	assert("vs-1427", ergo(h->nr_new_extents == 2,
+			       extent_get_width(&h->new_extents[1]) != 0));
+
+	/* compose structure for paste */
+	init_new_extent(&h->item, &h->new_extents[0], h->nr_new_extents);
+
+	coord_dup(&h->coord_after, h->coord);
+	init_lh(&h->lh_after);
+	copy_lh(&h->lh_after, h->lh);
+	tap_init(&h->watch, &h->coord_after, &h->lh_after, ZNODE_WRITE_LOCK);
+	tap_monitor(&h->watch);
+
+	ON_DEBUG(h->orig_ext = *extent_by_coord(h->coord));
+	orig_znode = h->coord->node;
+
+#if REISER4_DEBUG
+	/* make sure that key is set properly */
+	unit_key_by_coord(h->coord, &h->tmp);
+	set_key_offset(&h->tmp,
+		       get_key_offset(&h->tmp) +
+		       extent_get_width(&h->overwrite) * current_blocksize);
+	assert("vs-1080", keyeq(&h->tmp, &h->paste_key));
+#endif
+
+	/* set insert point after unit to be replaced */
+	h->coord->between = AFTER_UNIT;
+
+	result = insert_into_item(h->coord, return_inserted_position ? h->lh : NULL,
+				  &h->paste_key, &h->item, h->flags);
+	if (!result) {
+		/* now we have to replace the unit after which new units were
+		   inserted. Its position is tracked by @watch */
+		reiser4_extent *ext;
+		znode *node;
+
+		node = h->coord_after.node;
+		if (node != orig_znode) {
+			coord_clear_iplug(&h->coord_after);
+			result = zload(node);
+		}
+
+		if (likely(!result)) {
+			ext = extent_by_coord(&h->coord_after);
+
+			assert("vs-987", znode_is_loaded(node));
+			assert("vs-988", !memcmp(ext, &h->orig_ext, sizeof(*ext)));
+
+			/* overwrite extent unit */
+			memcpy(ext, &h->overwrite, sizeof(reiser4_extent));
+			znode_make_dirty(node);
+
+			if (node != orig_znode)
+				zrelse(node);
+
+			if (return_inserted_position == 0) {
+				/* coord and lh are to be set to overwritten
+				   extent */
+				assert("vs-1662",
+				       WITH_DATA(node, !memcmp(&h->overwrite,
+							       extent_by_coord(
+								       &h->coord_after),
+							       sizeof(reiser4_extent))));
+
+				*h->coord = h->coord_after;
+				done_lh(h->lh);
+				copy_lh(h->lh, &h->lh_after);
+			} else {
+				/* h->coord and h->lh are to be set to first of
+				   inserted units */
+				assert("vs-1663",
+				       WITH_DATA(h->coord->node,
+						 !memcmp(&h->new_extents[0],
+							 extent_by_coord(h->coord),
+							 sizeof(reiser4_extent))));
+				assert("vs-1664", h->lh->node == h->coord->node);
+			}
+		}
+	}
+	tap_done(&h->watch);
+
+	return result;
+}
+
+lock_handle *znode_lh(znode *node)
+{
+	assert("vs-1371", znode_is_write_locked(node));
+	assert("vs-1372", znode_is_wlocked_once(node));
+	return list_entry(node->lock.owners.next, lock_handle, owners_link);
+}
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * scroll-step: 1
+ * End:
+ */
diff -urN oldtree/fs/reiser4/plugin/item/extent.h newtree/fs/reiser4/plugin/item/extent.h
--- oldtree/fs/reiser4/plugin/item/extent.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/extent.h	2006-02-21 15:58:34.850848424 +0000
@@ -0,0 +1,227 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#ifndef __REISER4_EXTENT_H__
+#define __REISER4_EXTENT_H__
+
+/* on disk extent */
+typedef struct {
+	reiser4_dblock_nr start;
+	reiser4_dblock_nr width;
+} reiser4_extent;
+
+typedef struct extent_stat {
+	int unallocated_units;
+	int unallocated_blocks;
+	int allocated_units;
+	int allocated_blocks;
+	int hole_units;
+	int hole_blocks;
+} extent_stat;
+
+/* extents in an extent item can be either holes, or unallocated or allocated
+   extents */
+typedef enum {
+	HOLE_EXTENT,
+	UNALLOCATED_EXTENT,
+	ALLOCATED_EXTENT
+} extent_state;
+
+#define HOLE_EXTENT_START 0
+#define UNALLOCATED_EXTENT_START 1
+#define UNALLOCATED_EXTENT_START2 2
+
+typedef struct {
+	reiser4_block_nr pos_in_unit;
+	reiser4_block_nr width;	/* width of current unit */
+	pos_in_node_t nr_units;	/* number of units */
+	int ext_offset;		/* offset from the beginning of zdata() */
+	unsigned long expected_page;
+#if REISER4_DEBUG
+	reiser4_extent extent;
+#endif
+} extent_coord_extension_t;
+
+/* macros to set/get fields of on-disk extent */
+static inline reiser4_block_nr extent_get_start(const reiser4_extent * ext)
+{
+	return le64_to_cpu(ext->start);
+}
+
+static inline reiser4_block_nr extent_get_width(const reiser4_extent * ext)
+{
+	return le64_to_cpu(ext->width);
+}
+
+extern __u64 reiser4_current_block_count(void);
+
+static inline void
+extent_set_start(reiser4_extent * ext, reiser4_block_nr start)
+{
+	cassert(sizeof(ext->start) == 8);
+	assert("nikita-2510",
+	       ergo(start > 1, start < reiser4_current_block_count()));
+	put_unaligned(cpu_to_le64(start), &ext->start);
+}
+
+static inline void
+extent_set_width(reiser4_extent * ext, reiser4_block_nr width)
+{
+	cassert(sizeof(ext->width) == 8);
+	put_unaligned(cpu_to_le64(width), &ext->width);
+	assert("nikita-2511",
+	       ergo(extent_get_start(ext) > 1,
+		    extent_get_start(ext) + width <=
+		    reiser4_current_block_count()));
+}
+
+#define extent_item(coord) 					\
+({								\
+	assert("nikita-3143", item_is_extent(coord));		\
+	((reiser4_extent *)item_body_by_coord (coord));		\
+})
+
+#define extent_by_coord(coord)					\
+({								\
+	assert("nikita-3144", item_is_extent(coord));		\
+	(extent_item (coord) + (coord)->unit_pos);		\
+})
+
+#define width_by_coord(coord) 					\
+({								\
+	assert("nikita-3145", item_is_extent(coord));		\
+	extent_get_width (extent_by_coord(coord));		\
+})
+
+struct carry_cut_data;
+struct carry_kill_data;
+
+/* plugin->u.item.b.* */
+reiser4_key *max_key_inside_extent(const coord_t *, reiser4_key *);
+int can_contain_key_extent(const coord_t * coord, const reiser4_key * key,
+			   const reiser4_item_data *);
+int mergeable_extent(const coord_t * p1, const coord_t * p2);
+pos_in_node_t nr_units_extent(const coord_t *);
+lookup_result lookup_extent(const reiser4_key *, lookup_bias, coord_t *);
+void init_coord_extent(coord_t *);
+int init_extent(coord_t *, reiser4_item_data *);
+int paste_extent(coord_t *, reiser4_item_data *, carry_plugin_info *);
+int can_shift_extent(unsigned free_space,
+		     coord_t * source, znode * target, shift_direction,
+		     unsigned *size, unsigned want);
+void copy_units_extent(coord_t * target, coord_t * source, unsigned from,
+		       unsigned count, shift_direction where_is_free_space,
+		       unsigned free_space);
+int kill_hook_extent(const coord_t *, pos_in_node_t from, pos_in_node_t count,
+		     struct carry_kill_data *);
+int create_hook_extent(const coord_t * coord, void *arg);
+int cut_units_extent(coord_t * coord, pos_in_node_t from, pos_in_node_t to,
+		     struct carry_cut_data *, reiser4_key * smallest_removed,
+		     reiser4_key * new_first);
+int kill_units_extent(coord_t * coord, pos_in_node_t from, pos_in_node_t to,
+		      struct carry_kill_data *, reiser4_key * smallest_removed,
+		      reiser4_key * new_first);
+reiser4_key *unit_key_extent(const coord_t *, reiser4_key *);
+reiser4_key *max_unit_key_extent(const coord_t *, reiser4_key *);
+void print_extent(const char *, coord_t *);
+int utmost_child_extent(const coord_t * coord, sideof side, jnode ** child);
+int utmost_child_real_block_extent(const coord_t * coord, sideof side,
+				   reiser4_block_nr * block);
+void item_stat_extent(const coord_t * coord, void *vp);
+int check_extent(const coord_t * coord, const char **error);
+
+/* plugin->u.item.s.file.* */
+int write_extent(struct inode *, flow_t *, hint_t *, int grabbed, write_mode_t);
+int read_extent(struct file *, flow_t *, hint_t *);
+int readpage_extent(void *, struct page *);
+void readpages_extent(void *, struct address_space *, struct list_head *pages);
+int capture_extent(reiser4_key *, uf_coord_t *, struct page *, write_mode_t);
+reiser4_key *append_key_extent(const coord_t *, reiser4_key *);
+void init_coord_extension_extent(uf_coord_t *, loff_t offset);
+int get_block_address_extent(const coord_t *, sector_t block,
+			     sector_t * result);
+
+/* these are used in flush.c
+   FIXME-VS: should they be somewhere in item_plugin? */
+int allocate_extent_item_in_place(coord_t *, lock_handle *, flush_pos_t * pos);
+int allocate_and_copy_extent(znode * left, coord_t * right, flush_pos_t * pos,
+			     reiser4_key * stop_key);
+
+int extent_is_unallocated(const coord_t * item);	/* True if this extent is unallocated (i.e., not a hole, not allocated). */
+__u64 extent_unit_index(const coord_t * item);	/* Block offset of this unit. */
+__u64 extent_unit_width(const coord_t * item);	/* Number of blocks in this unit. */
+
+/* plugin->u.item.f. */
+int scan_extent(flush_scan * scan);
+extern int key_by_offset_extent(struct inode *, loff_t, reiser4_key *);
+
+reiser4_item_data *init_new_extent(reiser4_item_data * data, void *ext_unit,
+				   int nr_extents);
+reiser4_block_nr extent_size(const coord_t * coord, pos_in_node_t nr);
+extent_state state_of_extent(reiser4_extent * ext);
+void set_extent(reiser4_extent * ext, reiser4_block_nr start,
+		reiser4_block_nr width);
+
+#include "../../coord.h"
+#include "../../lock.h"
+#include "../../tap.h"
+
+struct replace_handle {
+	/* these are to be set before calling replace_extent */
+	coord_t *coord;
+	lock_handle *lh;
+	reiser4_key key;
+	reiser4_key *pkey;
+	reiser4_extent overwrite;
+	reiser4_extent new_extents[2];
+	int nr_new_extents;
+	unsigned flags;
+
+	/* these are used by replace_extent */
+	reiser4_item_data item;
+	coord_t coord_after;
+	lock_handle lh_after;
+	tap_t watch;
+	reiser4_key paste_key;
+#if REISER4_DEBUG
+	reiser4_extent orig_ext;
+	reiser4_key tmp;
+#endif
+};
+
+/* this structure is kmalloced before calling make_extent to avoid excessive
+   stack consumption on plug_hole->replace_extent */
+struct make_extent_handle {
+	uf_coord_t *uf_coord;
+	reiser4_block_nr blocknr;
+	int created;
+	struct inode *inode;
+	union {
+		struct {
+		} append;
+		struct replace_handle replace;
+	} u;
+};
+
+int replace_extent(struct replace_handle *, int return_inserted_position);
+lock_handle *znode_lh(znode *);
+
+/* the reiser4 repacker support */
+struct repacker_cursor;
+extern int process_extent_backward_for_repacking(tap_t *,
+						 struct repacker_cursor *);
+extern int mark_extent_for_repacking(tap_t *, int);
+
+#define coord_by_uf_coord(uf_coord) (&((uf_coord)->coord))
+#define ext_coord_by_uf_coord(uf_coord) (&((uf_coord)->extension.extent))
+
+/* __REISER4_EXTENT_H__ */
+#endif
+/*
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/item/extent_file_ops.c newtree/fs/reiser4/plugin/item/extent_file_ops.c
--- oldtree/fs/reiser4/plugin/item/extent_file_ops.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/extent_file_ops.c	2006-02-21 15:58:35.508748408 +0000
@@ -0,0 +1,1806 @@
+/* COPYRIGHT 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#include "item.h"
+#include "../../inode.h"
+#include "../../page_cache.h"
+#include "../../flush.h"	/* just for jnode_tostring */
+#include "../object.h"
+
+#include <linux/quotaops.h>
+#include <linux/swap.h>
+
+static inline reiser4_extent *ext_by_offset(const znode * node, int offset)
+{
+	reiser4_extent *ext;
+
+	ext = (reiser4_extent *) (zdata(node) + offset);
+	return ext;
+}
+
+static inline reiser4_extent *ext_by_ext_coord(const uf_coord_t * uf_coord)
+{
+	reiser4_extent *ext;
+
+	ext =
+	    ext_by_offset(uf_coord->coord.node,
+			  uf_coord->extension.extent.ext_offset);
+	assert("vs-1650",
+	       extent_get_start(ext) ==
+	       extent_get_start(&uf_coord->extension.extent.extent));
+	assert("vs-1651",
+	       extent_get_width(ext) ==
+	       extent_get_width(&uf_coord->extension.extent.extent));
+	return ext;
+}
+
+#if REISER4_DEBUG
+static int coord_extension_is_ok(const uf_coord_t * uf_coord)
+{
+	const coord_t *coord;
+	const extent_coord_extension_t *ext_coord;
+	reiser4_extent *ext;
+
+	coord = &uf_coord->coord;
+	ext_coord = &uf_coord->extension.extent;
+	ext = ext_by_ext_coord(uf_coord);
+
+	return WITH_DATA(coord->node, (uf_coord->valid == 1 &&
+				       coord_is_iplug_set(coord) &&
+				       item_is_extent(coord) &&
+				       ext_coord->nr_units ==
+				       nr_units_extent(coord)
+				       && ext == extent_by_coord(coord)
+				       && ext_coord->width ==
+				       extent_get_width(ext)
+				       && coord->unit_pos < ext_coord->nr_units
+				       && ext_coord->pos_in_unit <
+				       ext_coord->width
+				       && extent_get_start(ext) ==
+				       extent_get_start(&ext_coord->extent)
+				       && extent_get_width(ext) ==
+				       extent_get_width(&ext_coord->extent)));
+}
+
+/* return 1 if offset @off is inside of extent unit pointed to by @coord. Set
+   pos_in_unit inside of unit correspondingly */
+static int offset_is_in_unit(const coord_t * coord, loff_t off)
+{
+	reiser4_key unit_key;
+	__u64 unit_off;
+	reiser4_extent *ext;
+
+	ext = extent_by_coord(coord);
+
+	unit_key_extent(coord, &unit_key);
+	unit_off = get_key_offset(&unit_key);
+	if (off < unit_off)
+		return 0;
+	if (off >= (unit_off + (current_blocksize * extent_get_width(ext))))
+		return 0;
+	return 1;
+}
+
+static int
+coord_matches_key_extent(const coord_t * coord, const reiser4_key * key)
+{
+	reiser4_key item_key;
+
+	assert("vs-771", coord_is_existing_unit(coord));
+	assert("vs-1258", keylt(key, append_key_extent(coord, &item_key)));
+	assert("vs-1259", keyge(key, item_key_by_coord(coord, &item_key)));
+
+	return offset_is_in_unit(coord, get_key_offset(key));
+}
+
+static int
+coord_extension_is_ok2(const uf_coord_t * uf_coord, const reiser4_key * key)
+{
+	reiser4_key coord_key;
+
+	unit_key_by_coord(&uf_coord->coord, &coord_key);
+	set_key_offset(&coord_key,
+		       get_key_offset(&coord_key) +
+		       (uf_coord->extension.extent.
+			pos_in_unit << PAGE_CACHE_SHIFT));
+	return keyeq(key, &coord_key);
+}
+
+#endif
+
+/* @coord is set either to the end of last extent item of a file
+   (coord->node is a node on the twig level) or to a place where first
+   item of file has to be inserted to (coord->node is leaf
+   node). Calculate size of hole to be inserted. If that hole is too
+   big - only part of it is inserted */
+static int
+add_hole(coord_t * coord, lock_handle * lh,
+	 const reiser4_key * key /* key of position in a file for write */ )
+{
+	int result;
+	znode *loaded;
+	reiser4_extent *ext, new_ext;
+	reiser4_block_nr hole_width;
+	reiser4_item_data item;
+	reiser4_key hole_key;
+
+	result = zload(coord->node);
+	if (result)
+		return result;
+	loaded = coord->node;
+
+	if (znode_get_level(coord->node) == LEAF_LEVEL) {
+		/* there are no items of this file yet. First item will be
+		   hole extent inserted here */
+
+		/* @coord must be set for inserting of new item */
+		assert("vs-711", coord_is_between_items(coord));
+
+		hole_key = *key;
+		set_key_offset(&hole_key, 0ull);
+
+		hole_width = ((get_key_offset(key) + current_blocksize - 1) >>
+			      current_blocksize_bits);
+		assert("vs-710", hole_width > 0);
+
+		/* compose body of hole extent */
+		set_extent(&new_ext, HOLE_EXTENT_START, hole_width);
+
+		result =
+		    insert_extent_by_coord(coord,
+					   init_new_extent(&item, &new_ext, 1),
+					   &hole_key, lh);
+		zrelse(loaded);
+		return result;
+	}
+
+	/* last item of file may have to be appended with hole */
+	assert("vs-708", znode_get_level(coord->node) == TWIG_LEVEL);
+	assert("vs-714", item_id_by_coord(coord) == EXTENT_POINTER_ID);
+
+	/* make sure we are at proper item */
+	assert("vs-918", keylt(key, max_key_inside_extent(coord, &hole_key)));
+
+	/* key of first byte which is not addressed by this extent */
+	append_key_extent(coord, &hole_key);
+
+	if (keyle(key, &hole_key)) {
+		/* there is already extent unit which contains position
+		   specified by @key */
+		zrelse(loaded);
+		return 0;
+	}
+
+	/* extent item has to be appended with hole. Calculate length of that
+	   hole */
+	hole_width = ((get_key_offset(key) - get_key_offset(&hole_key) +
+		       current_blocksize - 1) >> current_blocksize_bits);
+	assert("vs-954", hole_width > 0);
+
+	/* set coord after last unit */
+	coord_init_after_item_end(coord);
+
+	/* get last extent in the item */
+	ext = extent_by_coord(coord);
+	if (state_of_extent(ext) == HOLE_EXTENT) {
+		/* last extent of a file is hole extent. Widen that extent by
+		   @hole_width blocks. Note that we do not worry about
+		   overflowing - extent width is 64 bits */
+		set_extent(ext, HOLE_EXTENT_START,
+			   extent_get_width(ext) + hole_width);
+		znode_make_dirty(coord->node);
+		zrelse(loaded);
+		return 0;
+	}
+
+	/* append item with hole extent unit */
+	assert("vs-713",
+	       (state_of_extent(ext) == ALLOCATED_EXTENT
+		|| state_of_extent(ext) == UNALLOCATED_EXTENT));
+
+	/* compose body of hole extent */
+	set_extent(&new_ext, HOLE_EXTENT_START, hole_width);
+
+	result =
+	    insert_into_item(coord, lh, &hole_key,
+			     init_new_extent(&item, &new_ext, 1),
+			     0 /*flags */ );
+	zrelse(loaded);
+	return result;
+}
+
+
+/* insert extent item (containing one unallocated extent of width 1) to place
+   set by @coord */
+static int
+insert_first_block(uf_coord_t * uf_coord, const reiser4_key * key,
+		   reiser4_block_nr * block)
+{
+	int result;
+	reiser4_extent ext;
+	reiser4_item_data unit;
+
+	/* make sure that we really write to first block */
+	assert("vs-240", get_key_offset(key) == 0);
+
+	/* extent insertion starts at leaf level */
+	assert("vs-719", znode_get_level(uf_coord->coord.node) == LEAF_LEVEL);
+
+	set_extent(&ext, UNALLOCATED_EXTENT_START, 1);
+	result =
+	    insert_extent_by_coord(&uf_coord->coord,
+				   init_new_extent(&unit, &ext, 1), key,
+				   uf_coord->lh);
+	if (result) {
+		/* FIXME-VITALY: this is grabbed at file_write time. */
+		/* grabbed2free ((__u64)1); */
+		return result;
+	}
+
+	*block = fake_blocknr_unformatted();
+
+	/* invalidate coordinate, research must be performed to continue because write will continue on twig level */
+	uf_coord->valid = 0;
+	return 0;
+}
+
+/**
+ * append_one_block - append one unallocated extent to th eend of file
+ * @uf_coord:
+ * @key:
+ * @block:
+ */
+/* @coord is set to the end of extent item. Append it with pointer to one block - either by expanding last unallocated
+   extent or by appending a new one of width 1 */
+static int
+append_one_block(uf_coord_t * uf_coord, reiser4_key * key,
+		 reiser4_block_nr * block)
+{
+	int result;
+	reiser4_extent new_ext;
+	reiser4_item_data unit;
+	coord_t *coord;
+	extent_coord_extension_t *ext_coord;
+	reiser4_extent *ext;
+
+	coord = &uf_coord->coord;
+	ext_coord = &uf_coord->extension.extent;
+	ext = ext_by_ext_coord(uf_coord);
+
+	/* check correctness of position in the item */
+	assert("vs-228", coord->unit_pos == coord_last_unit_pos(coord));
+	assert("vs-1311", coord->between == AFTER_UNIT);
+	assert("vs-1302", ext_coord->pos_in_unit == ext_coord->width - 1);
+	assert("vs-883", ( {
+			  reiser4_key next;
+			  keyeq(key, append_key_extent(coord, &next));}));
+
+	switch (state_of_extent(ext)) {
+	case UNALLOCATED_EXTENT:
+		set_extent(ext, UNALLOCATED_EXTENT_START,
+			   extent_get_width(ext) + 1);
+		znode_make_dirty(coord->node);
+
+		/* update coord extension */
+		ext_coord->width++;
+		ON_DEBUG(extent_set_width
+			 (&uf_coord->extension.extent.extent,
+			  ext_coord->width));
+		break;
+
+	case HOLE_EXTENT:
+	case ALLOCATED_EXTENT:
+		/* append one unallocated extent of width 1 */
+		set_extent(&new_ext, UNALLOCATED_EXTENT_START, 1);
+		result =
+		    insert_into_item(coord, uf_coord->lh, key,
+				     init_new_extent(&unit, &new_ext, 1),
+				     0 /* flags */ );
+		/* FIXME: for now */
+		uf_coord->valid = 0;
+		if (result)
+			return result;
+		break;
+	default:
+		assert("", 0);
+	}
+
+	*block = fake_blocknr_unformatted();
+	return 0;
+}
+
+/**
+ * plug_hole - replace hole extent with unallocated and holes
+ * @h: structure containing coordinate, lock handle, key, etc
+ *
+ * Creates an unallocated extent of width 1 within a hole. In worst case two
+ * additional extents can be created.
+ */
+static int plug_hole(struct make_extent_handle *h)
+{
+	struct replace_handle *rh;
+	reiser4_extent *ext;
+	reiser4_block_nr width, pos_in_unit;
+	coord_t *coord;
+	extent_coord_extension_t *ext_coord;
+	int return_inserted_position;
+
+	rh = &h->u.replace;
+	rh->coord = coord_by_uf_coord(h->uf_coord);
+	rh->lh = h->uf_coord->lh;
+	rh->flags = 0;
+
+	coord = coord_by_uf_coord(h->uf_coord);
+	ext_coord = ext_coord_by_uf_coord(h->uf_coord);
+	ext = ext_by_ext_coord(h->uf_coord);
+
+	width = ext_coord->width;
+	pos_in_unit = ext_coord->pos_in_unit;
+
+	if (width == 1) {
+		set_extent(ext, UNALLOCATED_EXTENT_START, 1);
+		znode_make_dirty(coord->node);
+		/* update uf_coord */
+		ON_DEBUG(ext_coord->extent = *ext);
+		return 0;
+	} else if (pos_in_unit == 0) {
+		/* we deal with first element of extent */
+		if (coord->unit_pos) {
+			/* there is an extent to the left */
+			if (state_of_extent(ext - 1) == UNALLOCATED_EXTENT) {
+				/* unit to the left is an unallocated
+				   extent. Increase its width and decrease
+				   width of hole */
+				extent_set_width(ext - 1,
+						 extent_get_width(ext - 1) + 1);
+				extent_set_width(ext, width - 1);
+				znode_make_dirty(coord->node);
+
+				/* update coord extension */
+				coord->unit_pos--;
+				ext_coord->width = extent_get_width(ext - 1);
+				ext_coord->pos_in_unit = ext_coord->width - 1;
+				ext_coord->ext_offset -= sizeof(reiser4_extent);
+				ON_DEBUG(ext_coord->extent =
+					 *extent_by_coord(coord));
+				return 0;
+			}
+		}
+		/* extent for replace */
+		set_extent(&rh->overwrite, UNALLOCATED_EXTENT_START, 1);
+		/* extent to be inserted */
+		set_extent(&rh->new_extents[0], HOLE_EXTENT_START, width - 1);
+		rh->nr_new_extents = 1;
+
+		/* have replace_extent to return with @coord and @uf_coord->lh
+		   set to unit which was replaced */
+		return_inserted_position = 0;
+	} else if (pos_in_unit == width - 1) {
+		/* we deal with last element of extent */
+		if (coord->unit_pos < nr_units_extent(coord) - 1) {
+			/* there is an extent unit to the right */
+			if (state_of_extent(ext + 1) == UNALLOCATED_EXTENT) {
+				/* unit to the right is an unallocated
+				   extent. Increase its width and decrease
+				   width of hole */
+				extent_set_width(ext + 1,
+						 extent_get_width(ext + 1) + 1);
+				extent_set_width(ext, width - 1);
+				znode_make_dirty(coord->node);
+
+				/* update coord extension */
+				coord->unit_pos++;
+				ext_coord->width = extent_get_width(ext + 1);
+				ext_coord->pos_in_unit = 0;
+				ext_coord->ext_offset += sizeof(reiser4_extent);
+				ON_DEBUG(ext_coord->extent =
+					 *extent_by_coord(coord));
+				return 0;
+			}
+		}
+		/* extent for replace */
+		set_extent(&rh->overwrite, HOLE_EXTENT_START, width - 1);
+		/* extent to be inserted */
+		set_extent(&rh->new_extents[0], UNALLOCATED_EXTENT_START, 1);
+		rh->nr_new_extents = 1;
+
+		/* have replace_extent to return with @coord and @uf_coord->lh
+		   set to unit which was inserted */
+		return_inserted_position = 1;
+	} else {
+		/* extent for replace */
+		set_extent(&rh->overwrite, HOLE_EXTENT_START, pos_in_unit);
+		/* extents to be inserted */
+		set_extent(&rh->new_extents[0], UNALLOCATED_EXTENT_START, 1);
+		set_extent(&rh->new_extents[1], HOLE_EXTENT_START,
+			   width - pos_in_unit - 1);
+		rh->nr_new_extents = 2;
+
+		/* have replace_extent to return with @coord and @uf_coord->lh
+		   set to first of units which were inserted */
+		return_inserted_position = 1;
+	}
+	unit_key_by_coord(coord, &rh->paste_key);
+	set_key_offset(&rh->paste_key, get_key_offset(&rh->paste_key) +
+		       extent_get_width(&rh->overwrite) * current_blocksize);
+
+	h->uf_coord->valid = 0;
+	return replace_extent(rh, return_inserted_position);
+}
+
+/**
+ * overwrite_one_block -
+ * @h:
+ *
+ * make unallocated node pointer in the position @uf_coord is set to
+ */
+static int
+overwrite_one_block(struct make_extent_handle *h)
+{
+	int result;
+	extent_coord_extension_t *ext_coord;
+	reiser4_extent *ext;
+
+	assert("vs-1312", h->uf_coord->coord.between == AT_UNIT);
+
+	result = 0;
+	h->created = 0;
+	ext_coord = ext_coord_by_uf_coord(h->uf_coord);
+	ext = ext_by_ext_coord(h->uf_coord);
+
+	switch (state_of_extent(ext)) {
+	case ALLOCATED_EXTENT:
+		h->blocknr = extent_get_start(ext) + ext_coord->pos_in_unit;
+		break;
+
+	case HOLE_EXTENT:
+		if (h->inode != NULL && DQUOT_ALLOC_BLOCK_NODIRTY(h->inode, 1))
+			return RETERR(-EDQUOT);
+		result = plug_hole(h);
+		if (!result) {
+			h->blocknr = fake_blocknr_unformatted();
+			h->created = 1;
+		} else {
+			if (h->inode != NULL)
+				DQUOT_FREE_BLOCK_NODIRTY(h->inode, 1);
+		}
+		break;
+
+	case UNALLOCATED_EXTENT:
+		break;
+
+	default:
+		impossible("vs-238", "extent of unknown type found");
+		result = RETERR(-EIO);
+		break;
+	}
+
+	return result;
+}
+
+#if REISER4_DEBUG
+
+/* after make extent uf_coord's lock handle must be set to node containing unit
+ * which was inserted/found */
+static void
+check_make_extent_result(int result, write_mode_t mode, const reiser4_key * key,
+			 const lock_handle * lh, reiser4_block_nr block)
+{
+	coord_t coord;
+
+	if (result != 0)
+		return;
+
+	assert("vs-960", znode_is_write_locked(lh->node));
+
+	check_me("vs-9", zload(lh->node) == 0);
+	result = lh->node->nplug->lookup(lh->node, key, FIND_EXACT, &coord);
+	assert("vs-1502", result == NS_FOUND);
+	assert("vs-16561", coord.node == lh->node);
+	assert("vs-1656", coord_is_existing_unit(&coord));
+
+	if (blocknr_is_fake(&block)) {
+		assert("vs-1657",
+		       state_of_extent(extent_by_coord(&coord)) ==
+		       UNALLOCATED_EXTENT);
+	} else if (block == 0) {
+		assert("vs-1660", mode == OVERWRITE_ITEM);
+		assert("vs-1657",
+		       state_of_extent(extent_by_coord(&coord)) ==
+		       UNALLOCATED_EXTENT);
+	} else {
+		reiser4_key tmp;
+		reiser4_block_nr pos_in_unit;
+
+		assert("vs-1658",
+		       state_of_extent(extent_by_coord(&coord)) ==
+		       ALLOCATED_EXTENT);
+		unit_key_by_coord(&coord, &tmp);
+		pos_in_unit =
+		    (get_key_offset(key) -
+		     get_key_offset(&tmp)) >> current_blocksize_bits;
+		assert("vs-1659",
+		       block ==
+		       extent_get_start(extent_by_coord(&coord)) + pos_in_unit);
+	}
+	zrelse(lh->node);
+}
+
+#endif
+
+/**
+ * get_extent -
+ *
+ *
+ *
+ */
+static extent_state
+get_extent(struct make_extent_handle *h)
+{
+	extent_coord_extension_t *ext_coord;
+	reiser4_extent *ext;
+
+	assert("vs-1312", h->uf_coord->coord.between == AT_UNIT);
+
+	ext_coord = ext_coord_by_uf_coord(h->uf_coord);
+	ext = ext_by_ext_coord(h->uf_coord);
+
+	switch (state_of_extent(ext)) {
+	case ALLOCATED_EXTENT:
+		h->blocknr = extent_get_start(ext) + ext_coord->pos_in_unit;
+		return ALLOCATED_EXTENT;
+
+	case HOLE_EXTENT:
+		return HOLE_EXTENT;
+
+	case UNALLOCATED_EXTENT:
+		return UNALLOCATED_EXTENT;
+
+	default:
+		break;
+	}
+
+	return RETERR(-EIO);
+}
+
+
+/**
+ * make_extent - make sure that non hole extent corresponding h->pkey exists
+ * @h: structure containing coordinate, lock handle, key, etc
+ * @mode: preliminary hint obtained via search
+ *
+ * when @inode is not NULL, alloc quota before updating extent item
+ */
+static int
+make_extent(struct make_extent_handle *h, write_mode_t mode)
+{
+	int result;
+
+	assert("vs-960", znode_is_write_locked(h->uf_coord->coord.node));
+	assert("vs-1334", znode_is_loaded(h->uf_coord->coord.node));
+
+	h->blocknr = 0;
+	switch (mode) {
+	case FIRST_ITEM:
+		/* new block will be inserted into file. Check quota */
+		if (h->inode != NULL && DQUOT_ALLOC_BLOCK_NODIRTY(h->inode, 1))
+			return RETERR(-EDQUOT);
+
+		/* create first item of the file */
+		result = insert_first_block(h->uf_coord, h->u.replace.pkey, &h->blocknr);
+		if (result && h->inode != NULL)
+			DQUOT_FREE_BLOCK_NODIRTY(h->inode, 1);
+		h->created = 1;
+		break;
+
+	case APPEND_ITEM:
+		/* new block will be inserted into file. Check quota */
+		if (h->inode != NULL && DQUOT_ALLOC_BLOCK_NODIRTY(h->inode, 1))
+			return RETERR(-EDQUOT);
+
+		/* append one block to the file */
+		assert("vs-1316", coord_extension_is_ok(h->uf_coord));
+		result = append_one_block(h->uf_coord, h->u.replace.pkey, &h->blocknr);
+		if (result && h->inode != NULL)
+			DQUOT_FREE_BLOCK_NODIRTY(h->inode, 1);
+		h->created = 1;
+		break;
+
+	case OVERWRITE_ITEM:
+		assert("vs-1316", coord_extension_is_ok(h->uf_coord));
+		result = overwrite_one_block(h);
+		break;
+
+	default:
+		assert("vs-1346", 0);
+		result = RETERR(-E_REPEAT);
+		break;
+	}
+
+	ON_DEBUG(check_make_extent_result
+		 (result, mode, h->u.replace.pkey, h->uf_coord->lh, h->blocknr));
+
+	return result;
+}
+
+/**
+ * reserve_extent_write_iteration - reserve space for one page file write
+ * @inode:
+ * @tree:
+ *
+ * Estimates and reserves space which may be required for writing one page of
+ * file.
+ */
+static int reserve_extent_write_iteration(struct inode *inode,
+					  reiser4_tree *tree)
+{
+	grab_space_enable();
+	/*
+	 * one unformatted node and one insertion into tree (Hans removed
+	 * reservation for balancing here) and one stat data update may be
+	 * involved
+	 */
+	return reiser4_grab_space(1 + estimate_update_common(inode),
+				  0 /* flags */ );
+}
+
+static void write_move_coord(coord_t *coord, uf_coord_t *uf_coord,
+			     write_mode_t mode, int full_page)
+{
+	extent_coord_extension_t *ext_coord;
+
+	assert("vs-1339",
+	       ergo(mode == OVERWRITE_ITEM, coord->between == AT_UNIT));
+	assert("vs-1341", ergo(mode == FIRST_ITEM, uf_coord->valid == 0));
+
+	if (uf_coord->valid == 0)
+		return;
+
+	ext_coord = &uf_coord->extension.extent;
+
+	if (mode == APPEND_ITEM) {
+		assert("vs-1340", coord->between == AFTER_UNIT);
+		assert("vs-1342", coord->unit_pos == ext_coord->nr_units - 1);
+		assert("vs-1343",
+		       ext_coord->pos_in_unit == ext_coord->width - 2);
+		assert("vs-1344",
+		       state_of_extent(ext_by_ext_coord(uf_coord)) ==
+		       UNALLOCATED_EXTENT);
+		ON_DEBUG(ext_coord->extent = *ext_by_ext_coord(uf_coord));
+		ext_coord->pos_in_unit++;
+		if (!full_page)
+			coord->between = AT_UNIT;
+		return;
+	}
+
+	assert("vs-1345", coord->between == AT_UNIT);
+
+	if (!full_page)
+		return;
+	if (ext_coord->pos_in_unit == ext_coord->width - 1) {
+		/* last position in the unit */
+		if (coord->unit_pos == ext_coord->nr_units - 1) {
+			/* last unit in the item */
+			uf_coord->valid = 0;
+		} else {
+			/* move to the next unit */
+			coord->unit_pos++;
+			ext_coord->ext_offset += sizeof(reiser4_extent);
+			ON_DEBUG(ext_coord->extent =
+				 *ext_by_offset(coord->node,
+						ext_coord->ext_offset));
+			ext_coord->width =
+			    extent_get_width(ext_by_offset
+					     (coord->node,
+					      ext_coord->ext_offset));
+			ext_coord->pos_in_unit = 0;
+		}
+	} else
+		ext_coord->pos_in_unit++;
+}
+
+/**
+ * write_is_partial - check if page is being overwritten partially
+ * @inode:
+ * @file_off: position in a file write starts at
+ * @page_off: offset within a page write starts at
+ * @count: number of bytes to be written to a page
+ *
+ * Returns true if page has to be read before overwrite so that old data do not
+ * get lost. O is returned if all old data in a page are going to be
+ * overwritten.
+ */
+static int write_is_partial(struct inode *inode, loff_t file_off,
+			    unsigned page_off, unsigned count)
+{
+	if (count == inode->i_sb->s_blocksize)
+		return 0;
+	if (page_off == 0 && file_off + count >= inode->i_size)
+		return 0;
+	return 1;
+}
+
+/* this initialize content of page not covered by write */
+static void zero_around(struct page *page, int from, int count)
+{
+	char *data;
+
+	data = kmap_atomic(page, KM_USER0);
+	memset(data, 0, from);
+	memset(data + from + count, 0, PAGE_CACHE_SIZE - from - count);
+	flush_dcache_page(page);
+	kunmap_atomic(data, KM_USER0);
+}
+
+static void assign_jnode_blocknr(jnode * j, reiser4_block_nr blocknr,
+				 int created)
+{
+	assert("vs-1737", !JF_ISSET(j, JNODE_EFLUSH));
+	if (created) {
+		/* extent corresponding to this jnode was just created */
+		assert("vs-1504", *jnode_get_block(j) == 0);
+		JF_SET(j, JNODE_CREATED);
+		/* new block is added to file. Update inode->i_blocks and inode->i_bytes. FIXME:
+		   inode_set/get/add/sub_bytes is used to be called by quota macros */
+		/*inode_add_bytes(inode, PAGE_CACHE_SIZE); */
+	}
+
+	if (*jnode_get_block(j) == 0) {
+		jnode_set_block(j, &blocknr);
+	} else {
+		assert("vs-1508", !blocknr_is_fake(&blocknr));
+		assert("vs-1507",
+		       ergo(blocknr, *jnode_get_block(j) == blocknr));
+	}
+}
+
+static int
+extent_balance_dirty_pages(struct inode *inode, const flow_t *f,hint_t *hint)
+{
+	int result;
+	int excl;
+	unix_file_info_t *uf_info;
+
+	/* seal twig node if possible and unlock it */
+	if (hint->ext_coord.valid)
+		set_hint(hint, &f->key, ZNODE_WRITE_LOCK);
+	else
+		unset_hint(hint);
+
+	/* file was appended, update its size */
+	if (get_key_offset(&f->key) > inode->i_size) {
+		assert("vs-1649", f->user == 1);
+		INODE_SET_FIELD(inode, i_size, get_key_offset(&f->key));
+	}
+	if (f->user != 0) {
+		/*
+		 * this was writing data from user space. Update timestamps,
+		 * therefore. Othrewise, this is tail conversion where we
+		 * should not update timestamps
+		 */
+		inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+		result = reiser4_update_sd(inode);
+		if (result)
+			return result;
+	}
+
+	if (likely(!reiser4_is_set(inode->i_sb, REISER4_ATOMIC_WRITE))) {
+		uf_info = unix_file_inode_data(inode);
+		excl = unix_file_inode_data(inode)->exclusive_use;
+		if (excl) {
+			/*
+			 * we are about to drop exclusive access. Set file
+			 * container to UF_CONTAINER_EXTENTS if file is not
+			 * under tail conversion
+			 */
+			if (!inode_get_flag(inode, REISER4_PART_CONV))
+				uf_info->container = UF_CONTAINER_EXTENTS;
+			drop_exclusive_access(uf_info);
+		} else
+			drop_nonexclusive_access(uf_info);
+		reiser4_throttle_write(inode);
+
+		/* faultin next user page */
+		fault_in_pages_readable(f->data,
+					f->length > PAGE_CACHE_SIZE ?
+					PAGE_CACHE_SIZE : f->length);
+
+		if (excl)
+			get_exclusive_access(uf_info);
+		else
+			get_nonexclusive_access(uf_info, 0);
+	}
+	return 0;
+}
+
+/**
+ * extent_write_flow - core of extent item's write
+ * @inode:
+ * @flow:
+ * @hint:
+ * @grabbed: if it is 1 - space for operation is reserved already
+ * @mode:
+ *
+ * Write flow's data into file by pages.
+ */
+static int extent_write_flow(struct inode *inode, flow_t *flow, hint_t *hint,
+			     int grabbed, write_mode_t mode)
+{
+	int result;
+	loff_t file_off;
+	unsigned long page_nr;
+	unsigned long page_off, count;
+	struct page *page;
+	jnode *j;
+	coord_t *coord;
+	oid_t oid;
+	reiser4_tree *tree;
+	struct make_extent_handle *h;
+
+	assert("nikita-3139", !inode_get_flag(inode, REISER4_NO_SD));
+	assert("vs-885", current_blocksize == PAGE_CACHE_SIZE);
+	assert("vs-700", flow->user == 1);
+	assert("vs-1352", flow->length > 0);
+
+
+	/* position in a file to start write from */
+	file_off = get_key_offset(&flow->key);
+	/* index of page containing that offset */
+	page_nr = (unsigned long)(file_off >> PAGE_CACHE_SHIFT);
+	/* offset within the page */
+	page_off = (unsigned long)(file_off & (PAGE_CACHE_SIZE - 1));
+
+	h = kmalloc(sizeof(*h), GFP_KERNEL);
+	if (h == NULL)
+		return RETERR(-ENOMEM);
+	h->uf_coord = &hint->ext_coord;
+	h->inode = inode;
+	h->u.replace.pkey = &h->u.replace.key;
+
+	/* key of first byte of page */
+	h->u.replace.key = flow->key;
+	set_key_offset(h->u.replace.pkey, file_off & ~((loff_t)(PAGE_CACHE_SIZE - 1)));
+
+	tree = tree_by_inode(inode);
+	oid = get_inode_oid(inode);
+	coord = coord_by_uf_coord(h->uf_coord);
+	do {
+		int do_make_extent = 1;
+
+		if (!grabbed) {
+			result = reserve_extent_write_iteration(inode, tree);
+			if (result)
+				goto exit0;
+		}
+		/* number of bytes to be written to page */
+		count = PAGE_CACHE_SIZE - page_off;
+		if (count > flow->length)
+			count = flow->length;
+
+		/* look for jnode and create it if it does not exist yet */
+		j = find_get_jnode(tree, inode->i_mapping, oid, page_nr);
+		if (IS_ERR(j)) {
+			result = PTR_ERR(j);
+			goto exit1;
+		}
+
+		/* get page looked and attached to jnode */
+		page = jnode_get_page_locked(j, GFP_KERNEL);
+		if (IS_ERR(page)) {
+			result = PTR_ERR(page);
+			goto exit2;
+		}
+
+		page_cache_get(page);
+
+		if (!PageUptodate(page) &&
+		    mode == OVERWRITE_ITEM &&
+		    write_is_partial(inode, file_off, page_off, count)) {
+			/*
+			 * page may have to be read before copy_from_user
+			 */
+			if (get_extent(h) != HOLE_EXTENT) {
+				if (*jnode_get_block(j) == 0)
+					assign_jnode_blocknr(j, h->blocknr, 0);
+				result = page_io(page, j, READ, GFP_KERNEL);
+				if (result)
+					goto exit3;
+				lock_page(page);
+				if (!PageUptodate(page))
+					goto exit3;
+				do_make_extent = 0;
+				spin_lock_jnode(j);
+				eflush_del(j, 1);
+				spin_unlock_jnode(j);
+			} else {
+				zero_around(page, page_off, count);
+			}
+		} else {
+			if (!PageUptodate(page))
+				zero_around(page, page_off, count);
+		}
+
+		assert("nikita-3033", schedulable());
+		/* copy user data into page */
+		result = __copy_from_user((char *)kmap(page) + page_off,
+					  (const char __user *)flow->data,
+					  count);
+		kunmap(page);
+		if (unlikely(result)) {
+			result = RETERR(-EFAULT);
+			goto exit3;
+		}
+
+		if (do_make_extent) {
+			result = make_extent(h, mode);
+			spin_lock_jnode(j);
+			eflush_del(j, 1);
+			assign_jnode_blocknr(j, h->blocknr, h->created);
+			spin_unlock_jnode(j);
+		}
+#if REISER4_DEBUG
+		spin_lock_jnode(j);
+		assert("vs-1503", (!JF_ISSET(j, JNODE_EFLUSH) &&
+				   jnode_page(j) == page));
+		spin_unlock_jnode(j);
+#endif
+
+		set_page_dirty_internal(page);
+		SetPageUptodate(page);
+		if (!PageReferenced(page))
+			SetPageReferenced(page);
+		unlock_page(page);
+
+		/* FIXME: possible optimization: if jnode is not dirty yet - it
+		   gets into clean list in try_capture and then in
+		   jnode_mark_dirty gets moved to dirty list. So, it would be
+		   more optimal to put jnode directly to dirty list */
+		spin_lock_jnode(j);
+		result = try_capture(j, ZNODE_WRITE_LOCK, 0, 1 /* can_coc */ );
+		if (result) {
+			spin_unlock_jnode(j);
+			page_cache_release(page);
+			goto exit2;
+		}
+		jnode_make_dirty_locked(j);
+		JF_CLR(j, JNODE_KEEPME);
+		spin_unlock_jnode(j);
+
+		page_cache_release(page);
+		jput(j);
+
+		move_flow_forward(flow, count);
+		write_move_coord(coord, h->uf_coord, mode,
+				 page_off + count == PAGE_CACHE_SIZE);
+
+		/* set seal, drop long term lock, throttle the writer */
+		result = extent_balance_dirty_pages(inode, flow, hint);
+		if (!grabbed)
+			all_grabbed2free();
+		if (result)
+			break;
+
+		page_off = 0;
+		page_nr++;
+		file_off += count;
+		set_key_offset(h->u.replace.pkey, (loff_t) page_nr << PAGE_CACHE_SHIFT);
+
+		if (flow->length && h->uf_coord->valid == 1) {
+			/*
+			 * flow contains data to write, coord looks set
+			 * properly - try to obtain lock validating a seal set
+			 * in extent_balance_dirty_pages
+			 */
+			result = hint_validate(hint, &flow->key,
+					       0 /* do not check key */,
+					       ZNODE_WRITE_LOCK);
+			if (result == 0)
+				continue;
+		}
+		break;
+
+		/* handling various error code pathes */
+	      exit3:
+		unlock_page(page);
+		page_cache_release(page);
+	      exit2:
+		if (h->created)
+			inode_sub_bytes(inode, PAGE_CACHE_SIZE);
+		jput(j);
+	      exit1:
+		if (!grabbed)
+			all_grabbed2free();
+
+	      exit0:
+		unset_hint(hint);
+		break;
+
+	} while (1);
+
+	kfree(h);
+
+	if (result && result != -E_REPEAT)
+		assert("vs-18", !hint_is_set(hint));
+	else
+		assert("vs-19", ergo(hint_is_set(hint),
+				     coords_equal(&hint->ext_coord.coord,
+						  &hint->seal.coord1)
+				     && keyeq(&flow->key, &hint->seal.key)));
+	assert("vs-20", lock_stack_isclean(get_current_lock_stack()));
+	return result;
+}
+
+/* estimate and reserve space which may be required for appending file with hole stored in extent */
+static int extent_hole_reserve(reiser4_tree * tree)
+{
+	/* adding hole may require adding a hole unit into extent item and stat data update */
+	grab_space_enable();
+	return reiser4_grab_space(estimate_one_insert_into_item(tree) * 2, 0);
+}
+
+static int
+extent_write_hole(struct inode *inode, flow_t * flow, hint_t * hint,
+		  int grabbed)
+{
+	int result;
+	loff_t new_size;
+	coord_t *coord;
+	lock_handle *lh;
+
+	coord = &hint->ext_coord.coord;
+	lh = hint->ext_coord.lh;
+	if (!grabbed) {
+		result = extent_hole_reserve(znode_get_tree(coord->node));
+		if (result) {
+			unset_hint(hint);
+			done_lh(lh);
+			return result;
+		}
+	}
+
+	new_size = get_key_offset(&flow->key) + flow->length;
+	set_key_offset(&flow->key, new_size);
+	flow->length = 0;
+	result = add_hole(coord, lh, &flow->key);
+	hint->ext_coord.valid = 0;
+	unset_hint(hint);
+	done_lh(lh);
+	if (!result) {
+		INODE_SET_FIELD(inode, i_size, new_size);
+		inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+		result = reiser4_update_sd(inode);
+	}
+	if (!grabbed)
+		all_grabbed2free();
+	return result;
+}
+
+/*
+  plugin->s.file.write
+  It can be called in two modes:
+  1. real write - to write data from flow to a file (@flow->data != 0)
+  2. expanding truncate (@f->data == 0)
+*/
+int write_extent(struct inode *inode, flow_t * flow, hint_t * hint, int grabbed,	/* extent's write may be called from plain unix file write and from tail conversion. In first
+											   case (grabbed == 0) space is not reserved forehand, so, it must be done here. When it is
+											   being called from tail conversion - space is reserved already for whole operation which may
+											   involve several calls to item write. In this case space reservation will not be done
+											   here */
+		 write_mode_t mode)
+{
+	if (flow->data)
+		/* real write */
+		return extent_write_flow(inode, flow, hint, grabbed, mode);
+
+	/* expanding truncate. add_hole requires f->key to be set to new end of file */
+	return extent_write_hole(inode, flow, hint, grabbed);
+}
+
+static inline void zero_page(struct page *page)
+{
+	char *kaddr = kmap_atomic(page, KM_USER0);
+
+	memset(kaddr, 0, PAGE_CACHE_SIZE);
+	flush_dcache_page(page);
+	kunmap_atomic(kaddr, KM_USER0);
+	SetPageUptodate(page);
+	unlock_page(page);
+}
+
+static int
+do_readpage_extent(reiser4_extent * ext, reiser4_block_nr pos,
+		   struct page *page)
+{
+	jnode *j;
+	struct address_space *mapping;
+	unsigned long index;
+	oid_t oid;
+
+	mapping = page->mapping;
+	oid = get_inode_oid(mapping->host);
+	index = page->index;
+
+	switch (state_of_extent(ext)) {
+	case HOLE_EXTENT:
+		/*
+		 * it is possible to have hole page with jnode, if page was
+		 * eflushed previously.
+		 */
+		j = jfind(mapping, index);
+		if (j == NULL) {
+			zero_page(page);
+			return 0;
+		}
+		spin_lock_jnode(j);
+		if (!jnode_page(j)) {
+			jnode_attach_page(j, page);
+		} else {
+			BUG_ON(jnode_page(j) != page);
+			assert("vs-1504", jnode_page(j) == page);
+		}
+
+		spin_unlock_jnode(j);
+		break;
+
+	case ALLOCATED_EXTENT:
+		j = jnode_of_page(page);
+		if (IS_ERR(j))
+			return PTR_ERR(j);
+		if (*jnode_get_block(j) == 0) {
+			reiser4_block_nr blocknr;
+
+			blocknr = extent_get_start(ext) + pos;
+			jnode_set_block(j, &blocknr);
+		} else
+			assert("vs-1403",
+			       j->blocknr == extent_get_start(ext) + pos);
+		break;
+
+	case UNALLOCATED_EXTENT:
+		j = jfind(mapping, index);
+		assert("nikita-2688", j);
+		assert("vs-1426", jnode_page(j) == NULL);
+
+		spin_lock_jnode(j);
+		jnode_attach_page(j, page);
+		spin_unlock_jnode(j);
+
+		/* page is locked, it is safe to check JNODE_EFLUSH */
+		assert("vs-1668", JF_ISSET(j, JNODE_EFLUSH));
+		break;
+
+	default:
+		warning("vs-957", "wrong extent\n");
+		return RETERR(-EIO);
+	}
+
+	BUG_ON(j == 0);
+	page_io(page, j, READ, GFP_NOIO);
+	jput(j);
+	return 0;
+}
+
+static int
+move_coord_pages(coord_t * coord, extent_coord_extension_t * ext_coord,
+		 unsigned count)
+{
+	reiser4_extent *ext;
+
+	ext_coord->expected_page += count;
+
+	ext = ext_by_offset(coord->node, ext_coord->ext_offset);
+
+	do {
+		if (ext_coord->pos_in_unit + count < ext_coord->width) {
+			ext_coord->pos_in_unit += count;
+			break;
+		}
+
+		if (coord->unit_pos == ext_coord->nr_units - 1) {
+			coord->between = AFTER_UNIT;
+			return 1;
+		}
+
+		/* shift to next unit */
+		count -= (ext_coord->width - ext_coord->pos_in_unit);
+		coord->unit_pos++;
+		ext_coord->pos_in_unit = 0;
+		ext_coord->ext_offset += sizeof(reiser4_extent);
+		ext++;
+		ON_DEBUG(ext_coord->extent = *ext);
+		ext_coord->width = extent_get_width(ext);
+	} while (1);
+
+	return 0;
+}
+
+static int readahead_readpage_extent(void *vp, struct page *page)
+{
+	int result;
+	uf_coord_t *uf_coord;
+	coord_t *coord;
+	extent_coord_extension_t *ext_coord;
+
+	uf_coord = vp;
+	coord = &uf_coord->coord;
+
+	if (coord->between != AT_UNIT) {
+		unlock_page(page);
+		return RETERR(-EINVAL);
+	}
+
+	ext_coord = &uf_coord->extension.extent;
+	if (ext_coord->expected_page != page->index) {
+		/* read_cache_pages skipped few pages. Try to adjust coord to page */
+		assert("vs-1269", page->index > ext_coord->expected_page);
+		if (move_coord_pages
+		    (coord, ext_coord,
+		     page->index - ext_coord->expected_page)) {
+			/* extent pointing to this page is not here */
+			unlock_page(page);
+			return RETERR(-EINVAL);
+		}
+
+		assert("vs-1274", offset_is_in_unit(coord,
+						    (loff_t) page->
+						    index << PAGE_CACHE_SHIFT));
+		ext_coord->expected_page = page->index;
+	}
+
+	assert("vs-1281", page->index == ext_coord->expected_page);
+	result =
+	    do_readpage_extent(ext_by_ext_coord(uf_coord),
+			       ext_coord->pos_in_unit, page);
+	if (!result)
+		move_coord_pages(coord, ext_coord, 1);
+	return result;
+}
+
+static int move_coord_forward(uf_coord_t * ext_coord)
+{
+	coord_t *coord;
+	extent_coord_extension_t *extension;
+
+	assert("", coord_extension_is_ok(ext_coord));
+
+	extension = &ext_coord->extension.extent;
+	extension->pos_in_unit++;
+	if (extension->pos_in_unit < extension->width)
+		/* stay within the same extent unit */
+		return 0;
+
+	coord = &ext_coord->coord;
+
+	/* try to move to the next extent unit */
+	coord->unit_pos++;
+	if (coord->unit_pos < extension->nr_units) {
+		/* went to the next extent unit */
+		reiser4_extent *ext;
+
+		extension->pos_in_unit = 0;
+		extension->ext_offset += sizeof(reiser4_extent);
+		ext = ext_by_offset(coord->node, extension->ext_offset);
+		ON_DEBUG(extension->extent = *ext);
+		extension->width = extent_get_width(ext);
+		return 0;
+	}
+
+	/* there is no units in the item anymore */
+	return 1;
+}
+
+/* this is called by read_cache_pages for each of readahead pages */
+static int extent_readpage_filler(void *data, struct page *page)
+{
+	hint_t *hint;
+	loff_t offset;
+	reiser4_key key;
+	uf_coord_t *ext_coord;
+	int result;
+
+	offset = (loff_t) page->index << PAGE_CACHE_SHIFT;
+	key_by_inode_and_offset_common(page->mapping->host, offset, &key);
+
+	hint = (hint_t *) data;
+	ext_coord = &hint->ext_coord;
+
+	BUG_ON(PageUptodate(page));
+	unlock_page(page);
+
+	if (hint_validate(hint, &key, 1 /* check key */ , ZNODE_READ_LOCK) != 0) {
+		result = coord_by_key(current_tree, &key, &ext_coord->coord,
+				      ext_coord->lh, ZNODE_READ_LOCK,
+				      FIND_EXACT, TWIG_LEVEL,
+				      TWIG_LEVEL, CBK_UNIQUE, NULL);
+		if (result != CBK_COORD_FOUND) {
+			unset_hint(hint);
+			return result;
+		}
+		ext_coord->valid = 0;
+	}
+
+	if (zload(ext_coord->coord.node)) {
+		unset_hint(hint);
+		return RETERR(-EIO);
+	}
+	if (!item_is_extent(&ext_coord->coord)) {
+		/* tail conversion is running in parallel */
+		zrelse(ext_coord->coord.node);
+		unset_hint(hint);
+		return RETERR(-EIO);
+	}
+
+	if (ext_coord->valid == 0)
+		init_coord_extension_extent(ext_coord, offset);
+
+	assert("vs-48", (coord_extension_is_ok(ext_coord) &&
+			 coord_extension_is_ok2(ext_coord, &key)));
+
+	lock_page(page);
+	if (!PageUptodate(page)) {
+		result = do_readpage_extent(ext_by_ext_coord(ext_coord),
+					    ext_coord->extension.extent.
+					    pos_in_unit, page);
+		if (result)
+			unlock_page(page);
+	} else {
+		unlock_page(page);
+		result = 0;
+	}
+	if (!result && move_coord_forward(ext_coord) == 0) {
+		set_key_offset(&key, offset + PAGE_CACHE_SIZE);
+		set_hint(hint, &key, ZNODE_READ_LOCK);
+	} else
+		unset_hint(hint);
+	zrelse(ext_coord->coord.node);
+	return result;
+}
+
+/* this is called by reiser4_readpages */
+static void
+extent_readpages_hook(struct address_space *mapping, struct list_head *pages,
+		      void *data)
+{
+	/* FIXME: try whether having reiser4_read_cache_pages improves anything */
+	read_cache_pages(mapping, pages, extent_readpage_filler, data);
+}
+
+static int
+call_page_cache_readahead(struct address_space *mapping, struct file *file,
+			  hint_t * hint,
+			  unsigned long page_nr,
+			  unsigned long ra_pages, struct file_ra_state *ra)
+{
+	reiser4_file_fsdata *fsdata;
+	int result;
+
+	fsdata = reiser4_get_file_fsdata(file);
+	if (IS_ERR(fsdata))
+		return page_nr;
+	fsdata->ra2.data = hint;
+	fsdata->ra2.readpages = extent_readpages_hook;
+
+	result = page_cache_readahead(mapping, ra, file, page_nr, ra_pages);
+	fsdata->ra2.readpages = NULL;
+	return result;
+}
+
+/* this is called when readahead did not */
+static int call_readpage(struct file *file, struct page *page)
+{
+	int result;
+
+	result = readpage_unix_file_nolock(file, page);
+	if (result)
+		return result;
+
+	lock_page(page);
+	if (!PageUptodate(page)) {
+		unlock_page(page);
+		page_detach_jnode(page, page->mapping, page->index);
+		warning("jmacd-97178", "page is not up to date");
+		return RETERR(-EIO);
+	}
+	unlock_page(page);
+	return 0;
+}
+
+static int filler(void *vp, struct page *page)
+{
+	return readpage_unix_file_nolock(vp, page);
+}
+
+/* Implements plugin->u.item.s.file.read operation for extent items. */
+int read_extent(struct file *file, flow_t *flow, hint_t *hint)
+{
+	int result;
+	struct page *page;
+	unsigned long cur_page, next_page;
+	unsigned long page_off, count;
+	struct address_space *mapping;
+	loff_t file_off;
+	uf_coord_t *uf_coord;
+	coord_t *coord;
+	extent_coord_extension_t *ext_coord;
+	unsigned long nr_pages, prev_page;
+	struct file_ra_state ra;
+	char *kaddr;
+
+	assert("vs-1353", current_blocksize == PAGE_CACHE_SIZE);
+	assert("vs-572", flow->user == 1);
+	assert("vs-1351", flow->length > 0);
+
+	uf_coord = &hint->ext_coord;
+	assert("vs-1318", coord_extension_is_ok(uf_coord));
+	assert("vs-33", uf_coord->lh == &hint->lh);
+
+	coord = &uf_coord->coord;
+	assert("vs-1119", znode_is_rlocked(coord->node));
+	assert("vs-1120", znode_is_loaded(coord->node));
+	assert("vs-1256", coord_matches_key_extent(coord, &flow->key));
+
+	mapping = file->f_dentry->d_inode->i_mapping;
+	ext_coord = &uf_coord->extension.extent;
+
+	/* offset in a file to start read from */
+	file_off = get_key_offset(&flow->key);
+	/* offset within the page to start read from */
+	page_off = (unsigned long)(file_off & (PAGE_CACHE_SIZE - 1));
+	/* bytes which can be read from the page which contains file_off */
+	count = PAGE_CACHE_SIZE - page_off;
+
+	/* index of page containing offset read is to start from */
+	cur_page = (unsigned long)(file_off >> PAGE_CACHE_SHIFT);
+	next_page = cur_page;
+	/* number of pages flow spans over */
+	nr_pages =
+	    ((file_off + flow->length + PAGE_CACHE_SIZE -
+	      1) >> PAGE_CACHE_SHIFT) - cur_page;
+
+	/* we start having twig node read locked. However, we do not want to
+	   keep that lock all the time readahead works. So, set a sel and
+	   release twig node. */
+	set_hint(hint, &flow->key, ZNODE_READ_LOCK);
+	/* &hint->lh is done-ed */
+
+	ra = file->f_ra;
+	prev_page = ra.prev_page;
+	do {
+		if (next_page == cur_page)
+			next_page =
+			    call_page_cache_readahead(mapping, file, hint,
+						      cur_page, nr_pages, &ra);
+
+		page = find_get_page(mapping, cur_page);
+		if (unlikely(page == NULL)) {
+			handle_ra_miss(mapping, &ra, cur_page);
+			page = read_cache_page(mapping, cur_page, filler, file);
+			if (IS_ERR(page))
+				return PTR_ERR(page);
+			lock_page(page);
+			if (!PageUptodate(page)) {
+				unlock_page(page);
+				page_detach_jnode(page, mapping, cur_page);
+				page_cache_release(page);
+				warning("jmacd-97178",
+					"extent_read: page is not up to date");
+				return RETERR(-EIO);
+			}
+			unlock_page(page);
+		} else {
+			if (!PageUptodate(page)) {
+				lock_page(page);
+
+				assert("", page->mapping == mapping);
+				if (PageUptodate(page))
+					unlock_page(page);
+				else {
+					result = call_readpage(file, page);
+					if (result) {
+						page_cache_release(page);
+						return RETERR(result);
+					}
+				}
+			}
+			if (prev_page != cur_page)
+				mark_page_accessed(page);
+			prev_page = cur_page;
+		}
+
+		/* If users can be writing to this page using arbitrary virtual
+		   addresses, take care about potential aliasing before reading
+		   the page on the kernel side.
+		 */
+		if (mapping_writably_mapped(mapping))
+			flush_dcache_page(page);
+
+		assert("nikita-3034", schedulable());
+
+		/* number of bytes which are to be read from the page */
+		if (count > flow->length)
+			count = flow->length;
+
+		result = fault_in_pages_writeable(flow->data, count);
+		if (result) {
+			page_cache_release(page);
+			return RETERR(-EFAULT);
+		}
+
+		kaddr = kmap_atomic(page, KM_USER0);
+		result = __copy_to_user_inatomic(flow->data,
+					       kaddr + page_off, count);
+		kunmap_atomic(kaddr, KM_USER0);
+		if (result != 0) {
+			kaddr = kmap(page);
+			result = __copy_to_user(flow->data, kaddr + page_off, count);
+			kunmap(page);
+			if (unlikely(result))
+				return RETERR(-EFAULT);
+		}
+
+		page_cache_release(page);
+
+		/* increase key (flow->key), update user area pointer (flow->data) */
+		move_flow_forward(flow, count);
+
+		page_off = 0;
+		cur_page ++;
+		count = PAGE_CACHE_SIZE;
+		nr_pages--;
+	} while (flow->length);
+
+	file->f_ra = ra;
+	return 0;
+}
+
+/*
+  plugin->u.item.s.file.readpages
+*/
+void
+readpages_extent(void *vp, struct address_space *mapping,
+		 struct list_head *pages)
+{
+	assert("vs-1739", 0);
+	if (vp)
+		read_cache_pages(mapping, pages, readahead_readpage_extent, vp);
+}
+
+/*
+   plugin->s.file.readpage
+   reiser4_read->unix_file_read->page_cache_readahead->reiser4_readpage->unix_file_readpage->extent_readpage
+   or
+   filemap_nopage->reiser4_readpage->readpage_unix_file->->readpage_extent
+
+   At the beginning: coord->node is read locked, zloaded, page is
+   locked, coord is set to existing unit inside of extent item (it is not necessary that coord matches to page->index)
+*/
+int readpage_extent(void *vp, struct page *page)
+{
+	uf_coord_t *uf_coord = vp;
+	ON_DEBUG(coord_t * coord = &uf_coord->coord);
+	ON_DEBUG(reiser4_key key);
+
+	assert("vs-1040", PageLocked(page));
+	assert("vs-1050", !PageUptodate(page));
+	assert("vs-757", !jprivate(page) && !PagePrivate(page));
+	assert("vs-1039", page->mapping && page->mapping->host);
+
+	assert("vs-1044", znode_is_loaded(coord->node));
+	assert("vs-758", item_is_extent(coord));
+	assert("vs-1046", coord_is_existing_unit(coord));
+	assert("vs-1045", znode_is_rlocked(coord->node));
+	assert("vs-1047",
+	       page->mapping->host->i_ino ==
+	       get_key_objectid(item_key_by_coord(coord, &key)));
+	assert("vs-1320", coord_extension_is_ok(uf_coord));
+
+	return do_readpage_extent(ext_by_ext_coord(uf_coord),
+				  uf_coord->extension.extent.pos_in_unit, page);
+}
+
+/**
+ * capture_extent - capture page, make sure there is non hole extent for it
+ * @key: key of first byte in @page
+ * @uf_coord: coordinate and lock handle of position in the tree
+ * @page: page to create
+ * @mode: preliminary hint obtained via search
+ *
+ * This implements capture method of item plugin for extent items.  At the
+ * beginning uf_coord->coord.node is write locked, zloaded, @page is not
+ * locked, @uf_coord is set to in accordance to @key. Extent and jnode
+ * corresponding to @page are created if they do not exist yet. Jnode is
+ * captured and marked dirty. Tag of @page->mapping->page_tree specifying that
+ * page may have no corresponding extent item is cleared.
+ */
+int
+capture_extent(reiser4_key *key, uf_coord_t *uf_coord, struct page *page,
+	       write_mode_t mode)
+{
+	jnode *j;
+	int result;
+	struct make_extent_handle *h;
+
+	assert("vs-1051", page->mapping && page->mapping->host);
+	assert("nikita-3139",
+	       !inode_get_flag(page->mapping->host, REISER4_NO_SD));
+	assert("vs-864", znode_is_wlocked(uf_coord->coord.node));
+	assert("vs-1398",
+	       get_key_objectid(key) == get_inode_oid(page->mapping->host));
+
+	h = kmalloc(sizeof(*h), GFP_KERNEL);
+	if (h == NULL)
+		return RETERR(-ENOMEM);
+	h->uf_coord = uf_coord;
+	h->inode = NULL;
+	h->u.replace.pkey = key;
+	h->inode = NULL; /* do not check quota */
+	result = make_extent(h, mode);
+	if (result) {
+		kfree(h);
+		done_lh(uf_coord->lh);
+		return result;
+	}
+
+	lock_page(page);
+	j = jnode_of_page(page);
+	if (IS_ERR(j)) {
+		kfree(h);
+		unlock_page(page);
+		done_lh(uf_coord->lh);
+		return PTR_ERR(j);
+	}
+	spin_lock_jnode(j);
+	eflush_del(j, 1);
+
+	unlock_page(page);
+
+	BUG_ON(JF_ISSET(j, JNODE_EFLUSH));
+	if (h->created) {
+		/* extent corresponding to this jnode was just created */
+		assert("vs-1504", *jnode_get_block(j) == 0);
+		JF_SET(j, JNODE_CREATED);
+		/* new block is added to file. Update inode->i_blocks and inode->i_bytes. FIXME:
+		   inode_set/get/add/sub_bytes is used to be called by quota macros */
+		inode_add_bytes(page->mapping->host, PAGE_CACHE_SIZE);
+	}
+
+	if (*jnode_get_block(j) == 0)
+		jnode_set_block(j, &h->blocknr);
+	else {
+		assert("vs-1508", !blocknr_is_fake(&h->blocknr));
+		assert("vs-1507",
+		       ergo(h->blocknr, *jnode_get_block(j) == h->blocknr));
+	}
+	spin_unlock_jnode(j);
+
+	done_lh(h->uf_coord->lh);
+
+	spin_lock_jnode(j);
+	result = try_capture(j, ZNODE_WRITE_LOCK, 0, 1 /* can_coc */ );
+	if (result != 0)
+		reiser4_panic("nikita-3324", "Cannot capture jnode: %i",
+			      result);
+	jnode_make_dirty_locked(j);
+	JF_CLR(j, JNODE_KEEPME);
+	spin_unlock_jnode(j);
+	jput(j);
+
+	if (h->created)
+		reiser4_update_sd(page->mapping->host);
+
+	if (get_current_context()->entd) {
+		entd_context *ent = get_entd_context(j->tree->super);
+
+		if (ent->cur_request->page == page)
+			ent->cur_request->node = j;
+	}
+	kfree(h);
+	return 0;
+}
+
+/*
+  plugin->u.item.s.file.get_block
+*/
+int
+get_block_address_extent(const coord_t * coord, sector_t block,
+			 sector_t * result)
+{
+	reiser4_extent *ext;
+
+	if (!coord_is_existing_unit(coord))
+		return RETERR(-EINVAL);
+
+	ext = extent_by_coord(coord);
+
+	if (state_of_extent(ext) != ALLOCATED_EXTENT)
+		/* FIXME: bad things may happen if it is unallocated extent */
+		*result = 0;
+	else {
+		reiser4_key key;
+
+		unit_key_by_coord(coord, &key);
+		assert("vs-1645",
+		       block >= get_key_offset(&key) >> current_blocksize_bits);
+		assert("vs-1646",
+		       block <
+		       (get_key_offset(&key) >> current_blocksize_bits) +
+		       extent_get_width(ext));
+		*result =
+		    extent_get_start(ext) + (block -
+					     (get_key_offset(&key) >>
+					      current_blocksize_bits));
+	}
+	return 0;
+}
+
+/*
+  plugin->u.item.s.file.append_key
+  key of first byte which is the next to last byte by addressed by this extent
+*/
+reiser4_key *append_key_extent(const coord_t * coord, reiser4_key * key)
+{
+	item_key_by_coord(coord, key);
+	set_key_offset(key,
+		       get_key_offset(key) + extent_size(coord,
+							 nr_units_extent
+							 (coord)));
+
+	assert("vs-610", get_key_offset(key)
+	       && (get_key_offset(key) & (current_blocksize - 1)) == 0);
+	return key;
+}
+
+/* plugin->u.item.s.file.init_coord_extension */
+void init_coord_extension_extent(uf_coord_t * uf_coord, loff_t lookuped)
+{
+	coord_t *coord;
+	extent_coord_extension_t *ext_coord;
+	reiser4_key key;
+	loff_t offset;
+
+	assert("vs-1295", uf_coord->valid == 0);
+
+	coord = &uf_coord->coord;
+	assert("vs-1288", coord_is_iplug_set(coord));
+	assert("vs-1327", znode_is_loaded(coord->node));
+
+	if (coord->between != AFTER_UNIT && coord->between != AT_UNIT)
+		return;
+
+	ext_coord = &uf_coord->extension.extent;
+	ext_coord->nr_units = nr_units_extent(coord);
+	ext_coord->ext_offset =
+	    (char *)extent_by_coord(coord) - zdata(coord->node);
+	ext_coord->width = extent_get_width(extent_by_coord(coord));
+	ON_DEBUG(ext_coord->extent = *extent_by_coord(coord));
+	uf_coord->valid = 1;
+
+	/* pos_in_unit is the only uninitialized field in extended coord */
+	if (coord->between == AFTER_UNIT) {
+		assert("vs-1330",
+		       coord->unit_pos == nr_units_extent(coord) - 1);
+
+		ext_coord->pos_in_unit = ext_coord->width - 1;
+	} else {
+		/* AT_UNIT */
+		unit_key_by_coord(coord, &key);
+		offset = get_key_offset(&key);
+
+		assert("vs-1328", offset <= lookuped);
+		assert("vs-1329",
+		       lookuped <
+		       offset + ext_coord->width * current_blocksize);
+		ext_coord->pos_in_unit =
+		    ((lookuped - offset) >> current_blocksize_bits);
+	}
+}
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * scroll-step: 1
+ * End:
+ */
diff -urN oldtree/fs/reiser4/plugin/item/extent_flush_ops.c newtree/fs/reiser4/plugin/item/extent_flush_ops.c
--- oldtree/fs/reiser4/plugin/item/extent_flush_ops.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/extent_flush_ops.c	2006-02-21 15:58:35.008824408 +0000
@@ -0,0 +1,1150 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#include "item.h"
+#include "../../tree.h"
+#include "../../jnode.h"
+#include "../../super.h"
+#include "../../flush.h"
+#include "../../carry.h"
+#include "../object.h"
+
+#include <linux/pagemap.h>
+
+static reiser4_block_nr extent_unit_start(const coord_t * item);
+
+/* Return either first or last extent (depending on @side) of the item
+   @coord is set to. Set @pos_in_unit either to first or to last block
+   of extent. */
+static reiser4_extent *extent_utmost_ext(const coord_t * coord, sideof side,
+					 reiser4_block_nr * pos_in_unit)
+{
+	reiser4_extent *ext;
+
+	if (side == LEFT_SIDE) {
+		/* get first extent of item */
+		ext = extent_item(coord);
+		*pos_in_unit = 0;
+	} else {
+		/* get last extent of item and last position within it */
+		assert("vs-363", side == RIGHT_SIDE);
+		ext = extent_item(coord) + coord_last_unit_pos(coord);
+		*pos_in_unit = extent_get_width(ext) - 1;
+	}
+
+	return ext;
+}
+
+/* item_plugin->f.utmost_child */
+/* Return the child. Coord is set to extent item. Find jnode corresponding
+   either to first or to last unformatted node pointed by the item */
+int utmost_child_extent(const coord_t * coord, sideof side, jnode ** childp)
+{
+	reiser4_extent *ext;
+	reiser4_block_nr pos_in_unit;
+
+	ext = extent_utmost_ext(coord, side, &pos_in_unit);
+
+	switch (state_of_extent(ext)) {
+	case HOLE_EXTENT:
+		*childp = NULL;
+		return 0;
+	case ALLOCATED_EXTENT:
+	case UNALLOCATED_EXTENT:
+		break;
+	default:
+		/* this should never happen */
+		assert("vs-1417", 0);
+	}
+
+	{
+		reiser4_key key;
+		reiser4_tree *tree;
+		unsigned long index;
+
+		if (side == LEFT_SIDE) {
+			/* get key of first byte addressed by the extent */
+			item_key_by_coord(coord, &key);
+		} else {
+			/* get key of byte which next after last byte addressed by the extent */
+			append_key_extent(coord, &key);
+		}
+
+		assert("vs-544",
+		       (get_key_offset(&key) >> PAGE_CACHE_SHIFT) < ~0ul);
+		/* index of first or last (depending on @side) page addressed
+		   by the extent */
+		index =
+		    (unsigned long)(get_key_offset(&key) >> PAGE_CACHE_SHIFT);
+		if (side == RIGHT_SIDE)
+			index--;
+
+		tree = coord->node->zjnode.tree;
+		*childp = jlookup(tree, get_key_objectid(&key), index);
+	}
+
+	return 0;
+}
+
+/* item_plugin->f.utmost_child_real_block */
+/* Return the child's block, if allocated. */
+int
+utmost_child_real_block_extent(const coord_t * coord, sideof side,
+			       reiser4_block_nr * block)
+{
+	reiser4_extent *ext;
+
+	ext = extent_by_coord(coord);
+
+	switch (state_of_extent(ext)) {
+	case ALLOCATED_EXTENT:
+		*block = extent_get_start(ext);
+		if (side == RIGHT_SIDE)
+			*block += extent_get_width(ext) - 1;
+		break;
+	case HOLE_EXTENT:
+	case UNALLOCATED_EXTENT:
+		*block = 0;
+		break;
+	default:
+		/* this should never happen */
+		assert("vs-1418", 0);
+	}
+
+	return 0;
+}
+
+/* item_plugin->f.scan */
+/* Performs leftward scanning starting from an unformatted node and its parent coordinate.
+   This scan continues, advancing the parent coordinate, until either it encounters a
+   formatted child or it finishes scanning this node.
+
+   If unallocated, the entire extent must be dirty and in the same atom.  (Actually, I'm
+   not sure this is last property (same atom) is enforced, but it should be the case since
+   one atom must write the parent and the others must read the parent, thus fusing?).  In
+   any case, the code below asserts this case for unallocated extents.  Unallocated
+   extents are thus optimized because we can skip to the endpoint when scanning.
+
+   It returns control to scan_extent, handles these terminating conditions, e.g., by
+   loading the next twig.
+*/
+int scan_extent(flush_scan * scan)
+{
+	coord_t coord;
+	jnode *neighbor;
+	unsigned long scan_index, unit_index, unit_width, scan_max, scan_dist;
+	reiser4_block_nr unit_start;
+	__u64 oid;
+	reiser4_key key;
+	int ret = 0, allocated, incr;
+	reiser4_tree *tree;
+
+	if (!JF_ISSET(scan->node, JNODE_DIRTY)) {
+		scan->stop = 1;
+		return 0;	/* Race with truncate, this node is already
+				 * truncated. */
+	}
+
+	coord_dup(&coord, &scan->parent_coord);
+
+	assert("jmacd-1404", !scan_finished(scan));
+	assert("jmacd-1405", jnode_get_level(scan->node) == LEAF_LEVEL);
+	assert("jmacd-1406", jnode_is_unformatted(scan->node));
+
+	/* The scan_index variable corresponds to the current page index of the
+	   unformatted block scan position. */
+	scan_index = index_jnode(scan->node);
+
+	assert("jmacd-7889", item_is_extent(&coord));
+
+      repeat:
+	/* objectid of file */
+	oid = get_key_objectid(item_key_by_coord(&coord, &key));
+
+	allocated = !extent_is_unallocated(&coord);
+	/* Get the values of this extent unit: */
+	unit_index = extent_unit_index(&coord);
+	unit_width = extent_unit_width(&coord);
+	unit_start = extent_unit_start(&coord);
+
+	assert("jmacd-7187", unit_width > 0);
+	assert("jmacd-7188", scan_index >= unit_index);
+	assert("jmacd-7189", scan_index <= unit_index + unit_width - 1);
+
+	/* Depending on the scan direction, we set different maximum values for scan_index
+	   (scan_max) and the number of nodes that would be passed if the scan goes the
+	   entire way (scan_dist).  Incr is an integer reflecting the incremental
+	   direction of scan_index. */
+	if (scanning_left(scan)) {
+		scan_max = unit_index;
+		scan_dist = scan_index - unit_index;
+		incr = -1;
+	} else {
+		scan_max = unit_index + unit_width - 1;
+		scan_dist = scan_max - unit_index;
+		incr = +1;
+	}
+
+	tree = coord.node->zjnode.tree;
+
+	/* If the extent is allocated we have to check each of its blocks.  If the extent
+	   is unallocated we can skip to the scan_max. */
+	if (allocated) {
+		do {
+			neighbor = jlookup(tree, oid, scan_index);
+			if (neighbor == NULL)
+				goto stop_same_parent;
+
+			if (scan->node != neighbor
+			    && !scan_goto(scan, neighbor)) {
+				/* @neighbor was jput() by scan_goto(). */
+				goto stop_same_parent;
+			}
+
+			ret = scan_set_current(scan, neighbor, 1, &coord);
+			if (ret != 0) {
+				goto exit;
+			}
+
+			/* reference to @neighbor is stored in @scan, no need
+			   to jput(). */
+			scan_index += incr;
+
+		} while (incr + scan_max != scan_index);
+
+	} else {
+		/* Optimized case for unallocated extents, skip to the end. */
+		neighbor = jlookup(tree, oid, scan_max /*index */ );
+		if (neighbor == NULL) {
+			/* Race with truncate */
+			scan->stop = 1;
+			ret = 0;
+			goto exit;
+		}
+
+		assert("zam-1043", blocknr_is_fake(jnode_get_block(neighbor)));
+
+		ret = scan_set_current(scan, neighbor, scan_dist, &coord);
+		if (ret != 0) {
+			goto exit;
+		}
+	}
+
+	if (coord_sideof_unit(&coord, scan->direction) == 0
+	    && item_is_extent(&coord)) {
+		/* Continue as long as there are more extent units. */
+
+		scan_index =
+		    extent_unit_index(&coord) +
+		    (scanning_left(scan) ? extent_unit_width(&coord) - 1 : 0);
+		goto repeat;
+	}
+
+	if (0) {
+	      stop_same_parent:
+
+		/* If we are scanning left and we stop in the middle of an allocated
+		   extent, we know the preceder immediately.. */
+		/* middle of extent is (scan_index - unit_index) != 0. */
+		if (scanning_left(scan) && (scan_index - unit_index) != 0) {
+			/* FIXME(B): Someone should step-through and verify that this preceder
+			   calculation is indeed correct. */
+			/* @unit_start is starting block (number) of extent
+			   unit. Flush stopped at the @scan_index block from
+			   the beginning of the file, which is (scan_index -
+			   unit_index) block within extent.
+			 */
+			if (unit_start) {
+				/* skip preceder update when we are at hole */
+				scan->preceder_blk =
+				    unit_start + scan_index - unit_index;
+				check_preceder(scan->preceder_blk);
+			}
+		}
+
+		/* In this case, we leave coord set to the parent of scan->node. */
+		scan->stop = 1;
+
+	} else {
+		/* In this case, we are still scanning, coord is set to the next item which is
+		   either off-the-end of the node or not an extent. */
+		assert("jmacd-8912", scan->stop == 0);
+		assert("jmacd-7812",
+		       (coord_is_after_sideof_unit(&coord, scan->direction)
+			|| !item_is_extent(&coord)));
+	}
+
+	ret = 0;
+      exit:
+	return ret;
+}
+
+/* ask block allocator for some blocks */
+static void
+extent_allocate_blocks(reiser4_blocknr_hint * preceder,
+		       reiser4_block_nr wanted_count,
+		       reiser4_block_nr * first_allocated,
+		       reiser4_block_nr * allocated, block_stage_t block_stage)
+{
+	*allocated = wanted_count;
+	preceder->max_dist = 0;	/* scan whole disk, if needed */
+
+	/* that number of blocks (wanted_count) is either in UNALLOCATED or in GRABBED */
+	preceder->block_stage = block_stage;
+
+	/* FIXME: we do not handle errors here now */
+	check_me("vs-420",
+		 reiser4_alloc_blocks(preceder, first_allocated, allocated,
+				      BA_PERMANENT) == 0);
+	/* update flush_pos's preceder to last allocated block number */
+	preceder->blk = *first_allocated + *allocated - 1;
+}
+
+/* when on flush time unallocated extent is to be replaced with allocated one it may happen that one unallocated extent
+   will have to be replaced with set of allocated extents. In this case insert_into_item will be called which may have
+   to add new nodes into tree. Space for that is taken from inviolable reserve (5%). */
+static reiser4_block_nr reserve_replace(void)
+{
+	reiser4_block_nr grabbed, needed;
+
+	grabbed = get_current_context()->grabbed_blocks;
+	needed = estimate_one_insert_into_item(current_tree);
+	check_me("vpf-340", !reiser4_grab_space_force(needed, BA_RESERVED));
+	return grabbed;
+}
+
+static void free_replace_reserved(reiser4_block_nr grabbed)
+{
+	reiser4_context *ctx;
+
+	ctx = get_current_context();
+	grabbed2free(ctx, get_super_private(ctx->super),
+		     ctx->grabbed_blocks - grabbed);
+}
+
+/* Block offset of first block addressed by unit */
+__u64 extent_unit_index(const coord_t * item)
+{
+	reiser4_key key;
+
+	assert("vs-648", coord_is_existing_unit(item));
+	unit_key_by_coord(item, &key);
+	return get_key_offset(&key) >> current_blocksize_bits;
+}
+
+/* AUDIT shouldn't return value be of reiser4_block_nr type?
+   Josh's answer: who knows?  Is a "number of blocks" the same type as "block offset"? */
+__u64 extent_unit_width(const coord_t * item)
+{
+	assert("vs-649", coord_is_existing_unit(item));
+	return width_by_coord(item);
+}
+
+/* Starting block location of this unit */
+static reiser4_block_nr extent_unit_start(const coord_t * item)
+{
+	return extent_get_start(extent_by_coord(item));
+}
+
+/**
+ * split_allocated_extent -
+ * @coord:
+ * @pos_in_unit:
+ *
+ * replace allocated extent with two allocated extents
+ */
+static int split_allocated_extent(coord_t *coord, reiser4_block_nr pos_in_unit)
+{
+	int result;
+	struct replace_handle *h;
+	reiser4_extent *ext;
+	reiser4_block_nr grabbed;
+
+	ext = extent_by_coord(coord);
+	assert("vs-1410", state_of_extent(ext) == ALLOCATED_EXTENT);
+	assert("vs-1411", extent_get_width(ext) > pos_in_unit);
+
+	h = kmalloc(sizeof(*h), GFP_KERNEL);
+	if (h == NULL)
+		return RETERR(-ENOMEM);
+	h->coord = coord;
+	h->lh = znode_lh(coord->node);
+	h->pkey = &h->key;
+	unit_key_by_coord(coord, h->pkey);
+	set_key_offset(h->pkey,
+		       (get_key_offset(h->pkey) +
+			pos_in_unit * current_blocksize));
+	set_extent(&h->overwrite, extent_get_start(ext), pos_in_unit);
+	set_extent(&h->new_extents[0], extent_get_start(ext) + pos_in_unit,
+		   extent_get_width(ext) - pos_in_unit);
+	h->nr_new_extents = 1;
+	h->flags = COPI_DONT_SHIFT_LEFT;
+	h->paste_key = h->key;
+
+	/* reserve space for extent unit paste, @grabbed is reserved before */
+	grabbed = reserve_replace();
+	result = replace_extent(h, 0 /* leave @coord set to overwritten
+					extent */);
+	/* restore reserved */
+	free_replace_reserved(grabbed);
+	kfree(h);
+	return result;
+}
+
+/* clear bit preventing node from being written bypassing extent allocation procedure */
+static inline void junprotect(jnode * node)
+{
+	assert("zam-837", !JF_ISSET(node, JNODE_EFLUSH));
+	assert("zam-838", JF_ISSET(node, JNODE_EPROTECTED));
+
+	JF_CLR(node, JNODE_EPROTECTED);
+}
+
+static void
+protected_list_split(struct list_head *head_split,
+		     struct list_head *head_new,
+		     jnode *node)
+{
+	assert("vs-1471", list_empty_careful(head_new));
+
+	/* attach to new list */
+	head_new->next = &node->capture_link;
+	head_new->prev = head_split->prev;
+
+	/* cut from old list */
+	node->capture_link.prev->next = head_split;
+	head_split->prev = node->capture_link.prev;
+
+	/* link new list */
+	head_new->next->prev = head_new;
+	head_new->prev->next = head_new;
+}
+
+/* this is used to unprotect nodes which were protected before allocating but
+   which will not be allocated either because space allocator allocates less
+   blocks than were protected and/or if allocation of those nodes failed */
+static void
+unprotect_extent_nodes(flush_pos_t *flush_pos, __u64 count,
+		       struct list_head *protected_nodes)
+{
+	jnode *node, *tmp;
+	LIST_HEAD(unprotected_nodes);
+	txn_atom *atom;
+
+	atom = atom_locked_by_fq(pos_fq(flush_pos));
+	assert("vs-1468", atom);
+
+	assert("vs-1469", !list_empty_careful(protected_nodes));
+	assert("vs-1474", count > 0);
+	node = list_entry(protected_nodes->prev, jnode, capture_link);
+	do {
+		count--;
+		junprotect(node);
+		ON_DEBUG(
+			spin_lock_jnode(node);
+			count_jnode(atom, node, PROTECT_LIST, DIRTY_LIST, 0);
+			spin_unlock_jnode(node);
+			);
+		if (count == 0) {
+			break;
+		}
+		tmp = list_entry(node->capture_link.prev, jnode, capture_link);
+		node = tmp;
+		assert("vs-1470", protected_nodes != &node->capture_link);
+	} while (1);
+
+	/* move back to dirty list */
+	protected_list_split(protected_nodes, &unprotected_nodes, node);
+	list_splice_init(&unprotected_nodes, ATOM_DIRTY_LIST(atom, LEAF_LEVEL)->prev);
+
+	spin_unlock_atom(atom);
+}
+
+extern int getjevent(void);
+
+/* remove node from atom's list and put to the end of list @jnodes */
+static void protect_reloc_node(struct list_head *jnodes, jnode *node)
+{
+	assert("zam-836", !JF_ISSET(node, JNODE_EPROTECTED));
+	assert("vs-1216", jnode_is_unformatted(node));
+	assert_spin_locked(&(node->atom->alock));
+	assert_spin_locked(&(node->guard));
+
+	JF_SET(node, JNODE_EPROTECTED);
+	list_del_init(&node->capture_link);
+	list_add_tail(&node->capture_link, jnodes);
+	ON_DEBUG(count_jnode(node->atom, node, DIRTY_LIST, PROTECT_LIST, 0));
+}
+
+#define JNODES_TO_UNFLUSH (16)
+
+/* @count nodes of file (objectid @oid) starting from @index are going to be
+   allocated. Protect those nodes from e-flushing. Nodes which are eflushed
+   already will be un-eflushed. There will be not more than JNODES_TO_UNFLUSH
+   un-eflushed nodes. If a node is not found or flushprepped - stop
+   protecting */
+/* FIXME: it is likely that not flushprepped jnodes are on dirty capture list
+ * in sequential order.. */
+static int
+protect_extent_nodes(flush_pos_t *flush_pos, oid_t oid, unsigned long index,
+		     reiser4_block_nr count, reiser4_block_nr *protected,
+		     reiser4_extent *ext, struct list_head *protected_nodes)
+{
+	__u64 i;
+	__u64 j;
+	int result;
+	reiser4_tree *tree;
+	int eflushed;
+	jnode *buf[JNODES_TO_UNFLUSH];
+	txn_atom *atom;
+
+	assert("nikita-3394", list_empty_careful(protected_nodes));
+
+	tree = current_tree;
+
+	atom = atom_locked_by_fq(pos_fq(flush_pos));
+	assert("vs-1468", atom);
+
+	assert("vs-1470", extent_get_width(ext) >= count);
+	eflushed = 0;
+	*protected = 0;
+	for (i = 0; i < count; ++i, ++index) {
+		jnode *node;
+
+		node = jlookup(tree, oid, index);
+		if (!node)
+			break;
+
+		if (jnode_check_flushprepped(node)) {
+			atomic_dec(&node->x_count);
+			break;
+		}
+
+		spin_lock_jnode(node);
+		assert("vs-1476", atomic_read(&node->x_count) > 1);
+		assert("nikita-3393", !JF_ISSET(node, JNODE_EPROTECTED));
+
+		if (JF_ISSET(node, JNODE_EFLUSH)) {
+			if (eflushed == JNODES_TO_UNFLUSH) {
+				spin_unlock_jnode(node);
+				atomic_dec(&node->x_count);
+				break;
+			}
+			buf[eflushed] = node;
+			eflushed++;
+			protect_reloc_node(protected_nodes, node);
+			spin_unlock_jnode(node);
+		} else {
+			assert("nikita-3384", node->atom == atom);
+			protect_reloc_node(protected_nodes, node);
+			assert("nikita-3383", !JF_ISSET(node, JNODE_EFLUSH));
+			spin_unlock_jnode(node);
+			atomic_dec(&node->x_count);
+		}
+
+		(*protected)++;
+	}
+	spin_unlock_atom(atom);
+
+	/* start io for eflushed nodes */
+	for (j = 0; j < eflushed; ++j)
+		jstartio(buf[j]);
+
+	result = 0;
+	for (j = 0; j < eflushed; ++j) {
+		if (result == 0) {
+			result = emergency_unflush(buf[j]);
+			if (result != 0) {
+				warning("nikita-3179",
+					"unflush failed: %i", result);
+			}
+		}
+		jput(buf[j]);
+	}
+	if (result != 0) {
+		/* unprotect all the jnodes we have protected so far */
+		unprotect_extent_nodes(flush_pos, i, protected_nodes);
+	}
+	return result;
+}
+
+/* replace extent @ext by extent @replace. Try to merge @replace with previous extent of the item (if there is
+   one). Return 1 if it succeeded, 0 - otherwise */
+static int
+try_to_merge_with_left(coord_t * coord, reiser4_extent * ext,
+		       reiser4_extent * replace)
+{
+	assert("vs-1415", extent_by_coord(coord) == ext);
+
+	if (coord->unit_pos == 0
+	    || state_of_extent(ext - 1) != ALLOCATED_EXTENT)
+		/* @ext either does not exist or is not allocated extent */
+		return 0;
+	if (extent_get_start(ext - 1) + extent_get_width(ext - 1) !=
+	    extent_get_start(replace))
+		return 0;
+
+	/* we can glue, widen previous unit */
+	extent_set_width(ext - 1,
+			 extent_get_width(ext - 1) + extent_get_width(replace));
+
+	if (extent_get_width(ext) != extent_get_width(replace)) {
+		/* make current extent narrower */
+		if (state_of_extent(ext) == ALLOCATED_EXTENT)
+			extent_set_start(ext,
+					 extent_get_start(ext) +
+					 extent_get_width(replace));
+		extent_set_width(ext,
+				 extent_get_width(ext) -
+				 extent_get_width(replace));
+	} else {
+		/* current extent completely glued with its left neighbor, remove it */
+		coord_t from, to;
+
+		coord_dup(&from, coord);
+		from.unit_pos = nr_units_extent(coord) - 1;
+		coord_dup(&to, &from);
+
+		/* currently cut from extent can cut either from the beginning or from the end. Move place which got
+		   freed after unit removal to end of item */
+		memmove(ext, ext + 1,
+			(from.unit_pos -
+			 coord->unit_pos) * sizeof(reiser4_extent));
+		/* wipe part of item which is going to be cut, so that node_check will not be confused */
+		cut_node_content(&from, &to, NULL, NULL, NULL);
+	}
+	znode_make_dirty(coord->node);
+	/* move coord back */
+	coord->unit_pos--;
+	return 1;
+}
+
+/**
+ * conv_extent - replace extent with 2 ones
+ * @coord: coordinate of extent to be replaced
+ * @replace: extent to overwrite the one @coord is set to
+ *
+ * Overwrites extent @coord is set to and paste one extent unit after
+ * overwritten one if @replace is shorter than initial extent
+ */
+static int conv_extent(coord_t *coord, reiser4_extent *replace)
+{
+	int result;
+	struct replace_handle *h;
+	reiser4_extent *ext;
+	reiser4_block_nr start, width, new_width;
+	reiser4_block_nr grabbed;
+	extent_state state;
+
+	ext = extent_by_coord(coord);
+	state = state_of_extent(ext);
+	start = extent_get_start(ext);
+	width = extent_get_width(ext);
+	new_width = extent_get_width(replace);
+
+	assert("vs-1458", (state == UNALLOCATED_EXTENT ||
+			   state == ALLOCATED_EXTENT));
+	assert("vs-1459", width >= new_width);
+
+	if (try_to_merge_with_left(coord, ext, replace)) {
+		/* merged @replace with left neighbor. Current unit is either
+		   removed or narrowed */
+		return 0;
+	}
+
+	if (width == new_width) {
+		/* replace current extent with @replace */
+		*ext = *replace;
+		znode_make_dirty(coord->node);
+		return 0;
+	}
+
+	h = kmalloc(sizeof(*h), GFP_KERNEL);
+	if (h == NULL)
+		return RETERR(-ENOMEM);
+	h->coord = coord;
+	h->lh = znode_lh(coord->node);
+	h->pkey = &h->key;
+	unit_key_by_coord(coord, h->pkey);
+	set_key_offset(h->pkey,
+		       (get_key_offset(h->pkey) + new_width * current_blocksize));
+	h->overwrite = *replace;
+
+	/* replace @ext with @replace and padding extent */
+	set_extent(&h->new_extents[0],
+		   (state == ALLOCATED_EXTENT) ? (start + new_width) : UNALLOCATED_EXTENT_START,
+		   width - new_width);
+	h->nr_new_extents = 1;
+	h->flags = COPI_DONT_SHIFT_LEFT;
+	h->paste_key = h->key;
+
+	/* reserve space for extent unit paste, @grabbed is reserved before */
+	grabbed = reserve_replace();
+	result = replace_extent(h, 0 /* leave @coord set to overwritten
+					extent */);
+
+	/* restore reserved */
+	free_replace_reserved(grabbed);
+	kfree(h);
+	return result;
+}
+
+/* for every jnode from @protected_nodes list assign block number and mark it
+   RELOC and FLUSH_QUEUED. Attach whole @protected_nodes list to flush queue's
+   prepped list */
+static void
+assign_real_blocknrs(flush_pos_t *flush_pos, reiser4_block_nr first,
+		     reiser4_block_nr count, extent_state state,
+		     struct list_head *protected_nodes)
+{
+	jnode *node;
+	txn_atom *atom;
+	flush_queue_t *fq;
+	int i;
+
+	fq = pos_fq(flush_pos);
+	atom = atom_locked_by_fq(fq);
+	assert("vs-1468", atom);
+
+	i = 0;
+	list_for_each_entry(node, protected_nodes, capture_link) {
+		spin_lock_jnode(node);
+		assert("vs-1132",
+		       ergo(state == UNALLOCATED_EXTENT,
+			    blocknr_is_fake(jnode_get_block(node))));
+		assert("vs-1475", node->atom == atom);
+		assert("vs-1476", atomic_read(&node->x_count) > 0);
+		JF_CLR(node, JNODE_FLUSH_RESERVED);
+		jnode_set_block(node, &first);
+
+		unformatted_make_reloc(node, fq);
+		ON_DEBUG(count_jnode(node->atom, node, PROTECT_LIST,
+				     FQ_LIST, 0));
+		junprotect(node);
+		assert("", NODE_LIST(node) == FQ_LIST);
+		spin_unlock_jnode(node);
+		first++;
+		i++;
+	}
+
+	list_splice_init(protected_nodes, ATOM_FQ_LIST(fq)->prev);
+
+	assert("vs-1687", count == i);
+	if (state == UNALLOCATED_EXTENT)
+		dec_unalloc_unfm_ptrs(count);
+	spin_unlock_atom(atom);
+}
+
+/**
+ * make_node_ovrwr - assign node to overwrite set
+ * @jnodes: overwrite set list head
+ * @node: jnode to belong to overwrite set
+ *
+ * Sets OVRWR jnode state bit and puts @node to the end of list head @jnodes
+ * which is an accumulator for nodes before they get to overwrite set list of
+ * atom.
+ */
+static void make_node_ovrwr(struct list_head *jnodes, jnode *node)
+{
+	spin_lock_jnode(node);
+
+	assert("zam-917", !JF_ISSET(node, JNODE_RELOC));
+	assert("zam-918", !JF_ISSET(node, JNODE_OVRWR));
+
+	JF_SET(node, JNODE_OVRWR);
+	list_del_init(&node->capture_link);
+	list_add_tail(&node->capture_link, jnodes);
+	ON_DEBUG(count_jnode(node->atom, node, DIRTY_LIST, OVRWR_LIST, 0));
+
+	spin_unlock_jnode(node);
+}
+
+/**
+ * mark_jnodes_overwrite - put bunch of jnodes to overwrite set
+ * @flush_pos: flush position
+ * @oid: objectid of file jnodes belong to
+ * @index: starting index
+ * @width: extent width
+ *
+ * Puts nodes of one extent (file objectid @oid, extent width @width) to atom's
+ * overwrite set. Starting from the one with index @index. If end of slum is
+ * detected (node is not found or flushprepped) - stop iterating and set flush
+ * position's state to POS_INVALID.
+ */
+static void mark_jnodes_overwrite(flush_pos_t *flush_pos, oid_t oid,
+				  unsigned long index, reiser4_block_nr width)
+{
+	unsigned long i;
+	reiser4_tree *tree;
+	jnode *node;
+	txn_atom *atom;
+	LIST_HEAD(jnodes);
+
+	tree = current_tree;
+
+	atom = atom_locked_by_fq(pos_fq(flush_pos));
+	assert("vs-1478", atom);
+
+	for (i = flush_pos->pos_in_unit; i < width; i++, index++) {
+		node = jlookup(tree, oid, index);
+		if (!node) {
+			flush_pos->state = POS_INVALID;
+			break;
+		}
+		if (jnode_check_flushprepped(node)) {
+			flush_pos->state = POS_INVALID;
+			atomic_dec(&node->x_count);
+			break;
+		}
+		make_node_ovrwr(&jnodes, node);
+		atomic_dec(&node->x_count);
+	}
+
+	list_splice_init(&jnodes, ATOM_OVRWR_LIST(atom)->prev);
+	spin_unlock_atom(atom);
+}
+
+/* this is called by handle_pos_on_twig to proceed extent unit flush_pos->coord is set to. It is to prepare for flushing
+   sequence of not flushprepped nodes (slum). It supposes that slum starts at flush_pos->pos_in_unit position within the
+   extent. Slum gets to relocate set if flush_pos->leaf_relocate is set to 1 and to overwrite set otherwise */
+int alloc_extent(flush_pos_t * flush_pos)
+{
+	coord_t *coord;
+	reiser4_extent *ext;
+	reiser4_extent replace_ext;
+	oid_t oid;
+	reiser4_block_nr protected;
+	reiser4_block_nr start;
+	__u64 index;
+	__u64 width;
+	extent_state state;
+	int result;
+	reiser4_block_nr first_allocated;
+	__u64 allocated;
+	reiser4_key key;
+	block_stage_t block_stage;
+
+	assert("vs-1468", flush_pos->state == POS_ON_EPOINT);
+	assert("vs-1469", coord_is_existing_unit(&flush_pos->coord)
+	       && item_is_extent(&flush_pos->coord));
+
+	coord = &flush_pos->coord;
+
+	ext = extent_by_coord(coord);
+	state = state_of_extent(ext);
+	if (state == HOLE_EXTENT) {
+		flush_pos->state = POS_INVALID;
+		return 0;
+	}
+
+	item_key_by_coord(coord, &key);
+	oid = get_key_objectid(&key);
+	index = extent_unit_index(coord) + flush_pos->pos_in_unit;
+	start = extent_get_start(ext);
+	width = extent_get_width(ext);
+
+	assert("vs-1457", width > flush_pos->pos_in_unit);
+
+	if (flush_pos->leaf_relocate || state == UNALLOCATED_EXTENT) {
+		protected_jnodes jnodes;
+
+		/* relocate */
+		if (flush_pos->pos_in_unit) {
+			/* split extent unit into two */
+			result =
+			    split_allocated_extent(coord,
+						   flush_pos->pos_in_unit);
+			flush_pos->pos_in_unit = 0;
+			return result;
+		}
+
+		/* Prevent nodes from e-flushing before allocating disk space for them. Nodes which were eflushed will be
+		   read from their temporary locations (but not more than certain limit: JNODES_TO_UNFLUSH) and that
+		   disk space will be freed. */
+
+		protected_jnodes_init(&jnodes);
+
+		/* limit number of nodes to allocate */
+		/*warning("", "nr_to_write = %ld, extent width %llu\n", flush_pos->nr_to_write, width); */
+		if (flush_pos->nr_to_write < width)
+			width = flush_pos->nr_to_write;
+
+		result =
+		    protect_extent_nodes(flush_pos, oid, index, width,
+					 &protected, ext, &jnodes.nodes);
+		if (result) {
+			warning("vs-1469",
+				"Failed to protect extent. Should not happen\n");
+			protected_jnodes_done(&jnodes);
+			return result;
+		}
+		if (protected == 0) {
+			flush_pos->state = POS_INVALID;
+			flush_pos->pos_in_unit = 0;
+			protected_jnodes_done(&jnodes);
+			return 0;
+		}
+
+		if (state == ALLOCATED_EXTENT)
+			/* all protected nodes are not flushprepped, therefore
+			 * they are counted as flush_reserved */
+			block_stage = BLOCK_FLUSH_RESERVED;
+		else
+			block_stage = BLOCK_UNALLOCATED;
+
+		/* look at previous unit if possible. If it is allocated, make preceder more precise */
+		if (coord->unit_pos
+		    && (state_of_extent(ext - 1) == ALLOCATED_EXTENT))
+			pos_hint(flush_pos)->blk =
+			    extent_get_start(ext - 1) + extent_get_width(ext -
+									 1);
+
+		/* allocate new block numbers for protected nodes */
+		extent_allocate_blocks(pos_hint(flush_pos), protected,
+				       &first_allocated, &allocated,
+				       block_stage);
+
+		if (allocated != protected)
+			/* unprotect nodes which will not be
+			 * allocated/relocated on this iteration */
+			unprotect_extent_nodes(flush_pos, protected - allocated,
+					       &jnodes.nodes);
+		if (state == ALLOCATED_EXTENT) {
+			/* on relocating - free nodes which are going to be
+			 * relocated */
+			reiser4_dealloc_blocks(&start, &allocated,
+					       BLOCK_ALLOCATED, BA_DEFER);
+		}
+
+		/* assign new block numbers to protected nodes */
+		assign_real_blocknrs(flush_pos, first_allocated, allocated,
+				     state, &jnodes.nodes);
+
+		protected_jnodes_done(&jnodes);
+
+		/* prepare extent which will replace current one */
+		set_extent(&replace_ext, first_allocated, allocated);
+
+		/* adjust extent item */
+		result = conv_extent(coord, &replace_ext);
+		if (result != 0 && result != -ENOMEM) {
+			warning("vs-1461",
+				"Failed to allocate extent. Should not happen\n");
+			return result;
+		}
+
+		/* break flush we prepared for flushing as many blocks as we
+		   were asked for */
+		if (flush_pos->nr_to_write == allocated)
+			flush_pos->state = POS_INVALID;
+	} else {
+		/* overwrite */
+		mark_jnodes_overwrite(flush_pos, oid, index, width);
+	}
+	flush_pos->pos_in_unit = 0;
+	return 0;
+}
+
+/* if @key is glueable to the item @coord is set to */
+static int must_insert(const coord_t * coord, const reiser4_key * key)
+{
+	reiser4_key last;
+
+	if (item_id_by_coord(coord) == EXTENT_POINTER_ID
+	    && keyeq(append_key_extent(coord, &last), key))
+		return 0;
+	return 1;
+}
+
+  /* copy extent @copy to the end of @node. It may have to either insert new item after the last one, or append last item,
+     or modify last unit of last item to have greater width */
+static int
+put_unit_to_end(znode * node, const reiser4_key * key,
+		reiser4_extent * copy_ext)
+{
+	int result;
+	coord_t coord;
+	cop_insert_flag flags;
+	reiser4_extent *last_ext;
+	reiser4_item_data data;
+
+	/* set coord after last unit in an item */
+	coord_init_last_unit(&coord, node);
+	coord.between = AFTER_UNIT;
+
+	flags =
+	    COPI_DONT_SHIFT_LEFT | COPI_DONT_SHIFT_RIGHT | COPI_DONT_ALLOCATE;
+	if (must_insert(&coord, key)) {
+		result =
+		    insert_by_coord(&coord, init_new_extent(&data, copy_ext, 1),
+				    key, NULL /*lh */ , flags);
+
+	} else {
+		/* try to glue with last unit */
+		last_ext = extent_by_coord(&coord);
+		if (state_of_extent(last_ext) &&
+		    extent_get_start(last_ext) + extent_get_width(last_ext) ==
+		    extent_get_start(copy_ext)) {
+			/* widen last unit of node */
+			extent_set_width(last_ext,
+					 extent_get_width(last_ext) +
+					 extent_get_width(copy_ext));
+			znode_make_dirty(node);
+			return 0;
+		}
+
+		/* FIXME: put an assertion here that we can not merge last unit in @node and new unit */
+		result =
+		    insert_into_item(&coord, NULL /*lh */ , key,
+				     init_new_extent(&data, copy_ext, 1),
+				     flags);
+	}
+
+	assert("vs-438", result == 0 || result == -E_NODE_FULL);
+	return result;
+}
+
+/* @coord is set to extent unit */
+squeeze_result
+squalloc_extent(znode * left, const coord_t * coord, flush_pos_t * flush_pos,
+		reiser4_key * stop_key)
+{
+	reiser4_extent *ext;
+	__u64 index;
+	__u64 width;
+	reiser4_block_nr start;
+	extent_state state;
+	oid_t oid;
+	reiser4_block_nr first_allocated;
+	__u64 allocated;
+	__u64 protected;
+	reiser4_extent copy_extent;
+	reiser4_key key;
+	int result;
+	block_stage_t block_stage;
+
+	assert("vs-1457", flush_pos->pos_in_unit == 0);
+	assert("vs-1467", coord_is_leftmost_unit(coord));
+	assert("vs-1467", item_is_extent(coord));
+
+	ext = extent_by_coord(coord);
+	index = extent_unit_index(coord);
+	start = extent_get_start(ext);
+	width = extent_get_width(ext);
+	state = state_of_extent(ext);
+	unit_key_by_coord(coord, &key);
+	oid = get_key_objectid(&key);
+
+	if (flush_pos->leaf_relocate || state == UNALLOCATED_EXTENT) {
+		protected_jnodes jnodes;
+
+		/* relocate */
+		protected_jnodes_init(&jnodes);
+		result =
+		    protect_extent_nodes(flush_pos, oid, index, width,
+					 &protected, ext, &jnodes.nodes);
+		if (result) {
+			warning("vs-1469",
+				"Failed to protect extent. Should not happen\n");
+			protected_jnodes_done(&jnodes);
+			return result;
+		}
+		if (protected == 0) {
+			flush_pos->state = POS_INVALID;
+			protected_jnodes_done(&jnodes);
+			return 0;
+		}
+
+		if (state == ALLOCATED_EXTENT)
+			/* all protected nodes are not flushprepped, therefore
+			 * they are counted as flush_reserved */
+			block_stage = BLOCK_FLUSH_RESERVED;
+		else
+			block_stage = BLOCK_UNALLOCATED;
+
+		/* look at previous unit if possible. If it is allocated, make preceder more precise */
+		if (coord->unit_pos
+		    && (state_of_extent(ext - 1) == ALLOCATED_EXTENT))
+			pos_hint(flush_pos)->blk =
+			    extent_get_start(ext - 1) + extent_get_width(ext -
+									 1);
+
+		/* allocate new block numbers for protected nodes */
+		extent_allocate_blocks(pos_hint(flush_pos), protected,
+				       &first_allocated, &allocated,
+				       block_stage);
+		if (allocated != protected)
+			unprotect_extent_nodes(flush_pos, protected - allocated,
+					       &jnodes.nodes);
+
+		/* prepare extent which will be copied to left */
+		set_extent(&copy_extent, first_allocated, allocated);
+
+		result = put_unit_to_end(left, &key, &copy_extent);
+		if (result == -E_NODE_FULL) {
+			int target_block_stage;
+
+			/* free blocks which were just allocated */
+			target_block_stage =
+			    (state ==
+			     ALLOCATED_EXTENT) ? BLOCK_FLUSH_RESERVED :
+			    BLOCK_UNALLOCATED;
+			reiser4_dealloc_blocks(&first_allocated, &allocated,
+					       target_block_stage,
+					       BA_PERMANENT);
+			unprotect_extent_nodes(flush_pos, allocated,
+					       &jnodes.nodes);
+
+			/* rewind the preceder. */
+			flush_pos->preceder.blk = first_allocated;
+			check_preceder(flush_pos->preceder.blk);
+
+			protected_jnodes_done(&jnodes);
+			return SQUEEZE_TARGET_FULL;
+		}
+
+		if (state == ALLOCATED_EXTENT) {
+			/* free nodes which were relocated */
+			reiser4_dealloc_blocks(&start, &allocated,
+					       BLOCK_ALLOCATED, BA_DEFER);
+		}
+
+		/* assign new block numbers to protected nodes */
+		assign_real_blocknrs(flush_pos, first_allocated, allocated,
+				     state, &jnodes.nodes);
+		protected_jnodes_done(&jnodes);
+
+		set_key_offset(&key,
+			       get_key_offset(&key) +
+			       (allocated << current_blocksize_bits));
+	} else {
+		/* overwrite: try to copy unit as it is to left neighbor and
+		   make all first not flushprepped nodes overwrite nodes */
+		set_extent(&copy_extent, start, width);
+		result = put_unit_to_end(left, &key, &copy_extent);
+		if (result == -E_NODE_FULL) {
+			return SQUEEZE_TARGET_FULL;
+		}
+		mark_jnodes_overwrite(flush_pos, oid, index, width);
+		set_key_offset(&key,
+			       get_key_offset(&key) +
+			       (width << current_blocksize_bits));
+	}
+	*stop_key = key;
+	return SQUEEZE_CONTINUE;
+}
+
+int key_by_offset_extent(struct inode *inode, loff_t off, reiser4_key * key)
+{
+	return key_by_inode_and_offset_common(inode, off, key);
+}
+
+/*
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/item/extent_item_ops.c newtree/fs/reiser4/plugin/item/extent_item_ops.c
--- oldtree/fs/reiser4/plugin/item/extent_item_ops.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/extent_item_ops.c	2006-02-21 15:58:35.009824256 +0000
@@ -0,0 +1,882 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#include "item.h"
+#include "../../inode.h"
+#include "../../tree_walk.h"	/* check_sibling_list() */
+#include "../../page_cache.h"
+#include "../../carry.h"
+
+#include <linux/quotaops.h>
+
+/* item_plugin->b.max_key_inside */
+reiser4_key *max_key_inside_extent(const coord_t * coord, reiser4_key * key)
+{
+	item_key_by_coord(coord, key);
+	set_key_offset(key, get_key_offset(max_key()));
+	return key;
+}
+
+/* item_plugin->b.can_contain_key
+   this checks whether @key of @data is matching to position set by @coord */
+int
+can_contain_key_extent(const coord_t * coord, const reiser4_key * key,
+		       const reiser4_item_data * data)
+{
+	reiser4_key item_key;
+
+	if (item_plugin_by_coord(coord) != data->iplug)
+		return 0;
+
+	item_key_by_coord(coord, &item_key);
+	if (get_key_locality(key) != get_key_locality(&item_key) ||
+	    get_key_objectid(key) != get_key_objectid(&item_key) ||
+	    get_key_ordering(key) != get_key_ordering(&item_key))
+		return 0;
+
+	return 1;
+}
+
+/* item_plugin->b.mergeable
+   first item is of extent type */
+/* Audited by: green(2002.06.13) */
+int mergeable_extent(const coord_t * p1, const coord_t * p2)
+{
+	reiser4_key key1, key2;
+
+	assert("vs-299", item_id_by_coord(p1) == EXTENT_POINTER_ID);
+	/* FIXME-VS: Which is it? Assert or return 0 */
+	if (item_id_by_coord(p2) != EXTENT_POINTER_ID) {
+		return 0;
+	}
+
+	item_key_by_coord(p1, &key1);
+	item_key_by_coord(p2, &key2);
+	if (get_key_locality(&key1) != get_key_locality(&key2) ||
+	    get_key_objectid(&key1) != get_key_objectid(&key2) ||
+	    get_key_ordering(&key1) != get_key_ordering(&key2) ||
+	    get_key_type(&key1) != get_key_type(&key2))
+		return 0;
+	if (get_key_offset(&key1) + extent_size(p1, nr_units_extent(p1)) !=
+	    get_key_offset(&key2))
+		return 0;
+	return 1;
+}
+
+/* item_plugin->b.nr_units */
+pos_in_node_t nr_units_extent(const coord_t * coord)
+{
+	/* length of extent item has to be multiple of extent size */
+	assert("vs-1424",
+	       (item_length_by_coord(coord) % sizeof(reiser4_extent)) == 0);
+	return item_length_by_coord(coord) / sizeof(reiser4_extent);
+}
+
+/* item_plugin->b.lookup */
+lookup_result
+lookup_extent(const reiser4_key * key, lookup_bias bias UNUSED_ARG,
+	      coord_t * coord)
+{				/* znode and item_pos are
+				   set to an extent item to
+				   look through */
+	reiser4_key item_key;
+	reiser4_block_nr lookuped, offset;
+	unsigned i, nr_units;
+	reiser4_extent *ext;
+	unsigned blocksize;
+	unsigned char blocksize_bits;
+
+	item_key_by_coord(coord, &item_key);
+	offset = get_key_offset(&item_key);
+
+	/* key we are looking for must be greater than key of item @coord */
+	assert("vs-414", keygt(key, &item_key));
+
+	assert("umka-99945",
+	       !keygt(key, max_key_inside_extent(coord, &item_key)));
+
+	ext = extent_item(coord);
+	assert("vs-1350", (char *)ext == (zdata(coord->node) + coord->offset));
+
+	blocksize = current_blocksize;
+	blocksize_bits = current_blocksize_bits;
+
+	/* offset we are looking for */
+	lookuped = get_key_offset(key);
+
+	nr_units = nr_units_extent(coord);
+	/* go through all extents until the one which address given offset */
+	for (i = 0; i < nr_units; i++, ext++) {
+		offset += (extent_get_width(ext) << blocksize_bits);
+		if (offset > lookuped) {
+			/* desired byte is somewhere in this extent */
+			coord->unit_pos = i;
+			coord->between = AT_UNIT;
+			return CBK_COORD_FOUND;
+		}
+	}
+
+	/* set coord after last unit */
+	coord->unit_pos = nr_units - 1;
+	coord->between = AFTER_UNIT;
+	return CBK_COORD_FOUND;
+}
+
+/* item_plugin->b.paste
+   item @coord is set to has been appended with @data->length of free
+   space. data->data contains data to be pasted into the item in position
+   @coord->in_item.unit_pos. It must fit into that free space.
+   @coord must be set between units.
+*/
+int
+paste_extent(coord_t * coord, reiser4_item_data * data,
+	     carry_plugin_info * info UNUSED_ARG)
+{
+	unsigned old_nr_units;
+	reiser4_extent *ext;
+	int item_length;
+
+	ext = extent_item(coord);
+	item_length = item_length_by_coord(coord);
+	old_nr_units = (item_length - data->length) / sizeof(reiser4_extent);
+
+	/* this is also used to copy extent into newly created item, so
+	   old_nr_units could be 0 */
+	assert("vs-260", item_length >= data->length);
+
+	/* make sure that coord is set properly */
+	assert("vs-35",
+	       ((!coord_is_existing_unit(coord))
+		|| (!old_nr_units && !coord->unit_pos)));
+
+	/* first unit to be moved */
+	switch (coord->between) {
+	case AFTER_UNIT:
+		coord->unit_pos++;
+	case BEFORE_UNIT:
+		coord->between = AT_UNIT;
+		break;
+	case AT_UNIT:
+		assert("vs-331", !old_nr_units && !coord->unit_pos);
+		break;
+	default:
+		impossible("vs-330", "coord is set improperly");
+	}
+
+	/* prepare space for new units */
+	memmove(ext + coord->unit_pos + data->length / sizeof(reiser4_extent),
+		ext + coord->unit_pos,
+		(old_nr_units - coord->unit_pos) * sizeof(reiser4_extent));
+
+	/* copy new data from kernel space */
+	assert("vs-556", data->user == 0);
+	memcpy(ext + coord->unit_pos, data->data, (unsigned)data->length);
+
+	/* after paste @coord is set to first of pasted units */
+	assert("vs-332", coord_is_existing_unit(coord));
+	assert("vs-333",
+	       !memcmp(data->data, extent_by_coord(coord),
+		       (unsigned)data->length));
+	return 0;
+}
+
+/* item_plugin->b.can_shift */
+int
+can_shift_extent(unsigned free_space, coord_t * source,
+		 znode * target UNUSED_ARG, shift_direction pend UNUSED_ARG,
+		 unsigned *size, unsigned want)
+{
+	*size = item_length_by_coord(source);
+	if (*size > free_space)
+		/* never split a unit of extent item */
+		*size = free_space - free_space % sizeof(reiser4_extent);
+
+	/* we can shift *size bytes, calculate how many do we want to shift */
+	if (*size > want * sizeof(reiser4_extent))
+		*size = want * sizeof(reiser4_extent);
+
+	if (*size % sizeof(reiser4_extent) != 0)
+		impossible("vs-119", "Wrong extent size: %i %zd", *size,
+			   sizeof(reiser4_extent));
+	return *size / sizeof(reiser4_extent);
+
+}
+
+/* item_plugin->b.copy_units */
+void
+copy_units_extent(coord_t * target, coord_t * source,
+		  unsigned from, unsigned count,
+		  shift_direction where_is_free_space, unsigned free_space)
+{
+	char *from_ext, *to_ext;
+
+	assert("vs-217", free_space == count * sizeof(reiser4_extent));
+
+	from_ext = item_body_by_coord(source);
+	to_ext = item_body_by_coord(target);
+
+	if (where_is_free_space == SHIFT_LEFT) {
+		assert("vs-215", from == 0);
+
+		/* At this moment, item length was already updated in the item
+		   header by shifting code, hence nr_units_extent() will
+		   return "new" number of units---one we obtain after copying
+		   units.
+		 */
+		to_ext +=
+		    (nr_units_extent(target) - count) * sizeof(reiser4_extent);
+	} else {
+		reiser4_key key;
+		coord_t coord;
+
+		assert("vs-216",
+		       from + count == coord_last_unit_pos(source) + 1);
+
+		from_ext += item_length_by_coord(source) - free_space;
+
+		/* new units are inserted before first unit in an item,
+		   therefore, we have to update item key */
+		coord = *source;
+		coord.unit_pos = from;
+		unit_key_extent(&coord, &key);
+
+		node_plugin_by_node(target->node)->update_item_key(target, &key,
+								   NULL /*info */);
+	}
+
+	memcpy(to_ext, from_ext, free_space);
+}
+
+/* item_plugin->b.create_hook
+   @arg is znode of leaf node for which we need to update right delimiting key */
+int create_hook_extent(const coord_t * coord, void *arg)
+{
+	coord_t *child_coord;
+	znode *node;
+	reiser4_key key;
+	reiser4_tree *tree;
+
+	if (!arg)
+		return 0;
+
+	child_coord = arg;
+	tree = znode_get_tree(coord->node);
+
+	assert("nikita-3246", znode_get_level(child_coord->node) == LEAF_LEVEL);
+
+	write_lock_tree(tree);
+	write_lock_dk(tree);
+	/* find a node on the left level for which right delimiting key has to
+	   be updated */
+	if (coord_wrt(child_coord) == COORD_ON_THE_LEFT) {
+		assert("vs-411", znode_is_left_connected(child_coord->node));
+		node = child_coord->node->left;
+	} else {
+		assert("vs-412", coord_wrt(child_coord) == COORD_ON_THE_RIGHT);
+		node = child_coord->node;
+		assert("nikita-3314", node != NULL);
+	}
+
+	if (node != NULL) {
+		znode_set_rd_key(node, item_key_by_coord(coord, &key));
+
+		assert("nikita-3282", check_sibling_list(node));
+		/* break sibling links */
+		if (ZF_ISSET(node, JNODE_RIGHT_CONNECTED) && node->right) {
+			ON_DEBUG(node->right->left_version =
+				 atomic_inc_return(&delim_key_version);
+				 node->right_version =
+				 atomic_inc_return(&delim_key_version););
+
+			node->right->left = NULL;
+			node->right = NULL;
+		}
+	}
+	write_unlock_dk(tree);
+	write_unlock_tree(tree);
+	return 0;
+}
+
+#define ITEM_TAIL_KILLED 0
+#define ITEM_HEAD_KILLED 1
+#define ITEM_KILLED 2
+
+/* item_plugin->b.kill_hook
+   this is called when @count units starting from @from-th one are going to be removed
+   */
+int
+kill_hook_extent(const coord_t * coord, pos_in_node_t from, pos_in_node_t count,
+		 struct carry_kill_data *kdata)
+{
+	reiser4_extent *ext;
+	reiser4_block_nr start, length;
+	const reiser4_key *pfrom_key, *pto_key;
+	struct inode *inode;
+	reiser4_tree *tree;
+	pgoff_t from_off, to_off, offset, skip;
+	int retval;
+
+	/* these are located in memory kmalloc-ed by kill_node_content */
+	reiser4_key *min_item_key, *max_item_key, *from_key, *to_key, *key;
+	coord_t *dup, *next;
+
+	assert("zam-811", znode_is_write_locked(coord->node));
+	assert("nikita-3315", kdata != NULL);
+	assert("vs-34", kdata->buf != NULL);
+
+	/* map structures to kdata->buf */
+	min_item_key = (reiser4_key *) (kdata->buf);
+	max_item_key = min_item_key + 1;
+	from_key = max_item_key + 1;
+	to_key = from_key + 1;
+	key = to_key + 1;
+	dup = (coord_t *) (key + 1);
+	next = dup + 1;
+
+	item_key_by_coord(coord, min_item_key);
+	max_item_key_by_coord(coord, max_item_key);
+
+	if (kdata->params.from_key) {
+		pfrom_key = kdata->params.from_key;
+		pto_key = kdata->params.to_key;
+	} else {
+		assert("vs-1549", from == coord->unit_pos);
+		unit_key_by_coord(coord, from_key);
+		pfrom_key = from_key;
+
+		coord_dup(dup, coord);
+		dup->unit_pos = from + count - 1;
+		max_unit_key_by_coord(dup, to_key);
+		pto_key = to_key;
+	}
+
+	if (!keylt(pto_key, max_item_key)) {
+		if (!keygt(pfrom_key, min_item_key)) {
+			znode *left, *right;
+
+			/* item is to be removed completely */
+			assert("nikita-3316", kdata->left != NULL
+			       && kdata->right != NULL);
+
+			left = kdata->left->node;
+			right = kdata->right->node;
+
+			tree = current_tree;
+			/* we have to do two things:
+			 *
+			 *     1. link left and right formatted neighbors of
+			 *        extent being removed, and
+			 *
+			 *     2. update their delimiting keys.
+			 *
+			 * atomicity of these operations is protected by
+			 * taking dk-lock and tree-lock.
+			 */
+			/* if neighbors of item being removed are znodes -
+			 * link them */
+			write_lock_tree(tree);
+			write_lock_dk(tree);
+			link_left_and_right(left, right);
+			if (left) {
+				/* update right delimiting key of left
+				 * neighbor of extent item */
+				/*coord_t next;
+				   reiser4_key key; */
+
+				coord_dup(next, coord);
+
+				if (coord_next_item(next))
+					*key = *znode_get_rd_key(coord->node);
+				else
+					item_key_by_coord(next, key);
+				znode_set_rd_key(left, key);
+			}
+			write_unlock_dk(tree);
+			write_unlock_tree(tree);
+
+			from_off =
+			    get_key_offset(min_item_key) >> PAGE_CACHE_SHIFT;
+			to_off =
+			    (get_key_offset(max_item_key) +
+			     1) >> PAGE_CACHE_SHIFT;
+			retval = ITEM_KILLED;
+		} else {
+			/* tail of item is to be removed */
+			from_off =
+			    (get_key_offset(pfrom_key) + PAGE_CACHE_SIZE -
+			     1) >> PAGE_CACHE_SHIFT;
+			to_off =
+			    (get_key_offset(max_item_key) +
+			     1) >> PAGE_CACHE_SHIFT;
+			retval = ITEM_TAIL_KILLED;
+		}
+	} else {
+		/* head of item is to be removed */
+		assert("vs-1571", keyeq(pfrom_key, min_item_key));
+		assert("vs-1572",
+		       (get_key_offset(pfrom_key) & (PAGE_CACHE_SIZE - 1)) ==
+		       0);
+		assert("vs-1573",
+		       ((get_key_offset(pto_key) + 1) & (PAGE_CACHE_SIZE -
+							 1)) == 0);
+
+		if (kdata->left->node) {
+			/* update right delimiting key of left neighbor of extent item */
+			/*reiser4_key key; */
+
+			*key = *pto_key;
+			set_key_offset(key, get_key_offset(pto_key) + 1);
+
+			write_lock_dk(current_tree);
+			znode_set_rd_key(kdata->left->node, key);
+			write_unlock_dk(current_tree);
+		}
+
+		from_off = get_key_offset(pfrom_key) >> PAGE_CACHE_SHIFT;
+		to_off = (get_key_offset(pto_key) + 1) >> PAGE_CACHE_SHIFT;
+		retval = ITEM_HEAD_KILLED;
+	}
+
+	inode = kdata->inode;
+	assert("vs-1545", inode != NULL);
+	if (inode != NULL)
+		/* take care of pages and jnodes corresponding to part of item being killed */
+		reiser4_invalidate_pages(inode->i_mapping, from_off,
+					 to_off - from_off,
+					 kdata->params.truncate);
+
+	ext = extent_item(coord) + from;
+	offset =
+	    (get_key_offset(min_item_key) +
+	     extent_size(coord, from)) >> PAGE_CACHE_SHIFT;
+
+	assert("vs-1551", from_off >= offset);
+	assert("vs-1552", from_off - offset <= extent_get_width(ext));
+	skip = from_off - offset;
+	offset = from_off;
+
+	while (offset < to_off) {
+		length = extent_get_width(ext) - skip;
+		if (state_of_extent(ext) == HOLE_EXTENT) {
+			skip = 0;
+			offset += length;
+			ext++;
+			continue;
+		}
+
+		if (offset + length > to_off) {
+			length = to_off - offset;
+		}
+
+		DQUOT_FREE_BLOCK_NODIRTY(inode, length);
+
+		if (state_of_extent(ext) == UNALLOCATED_EXTENT) {
+			/* some jnodes corresponding to this unallocated extent */
+			fake_allocated2free(length, 0 /* unformatted */ );
+
+			skip = 0;
+			offset += length;
+			ext++;
+			continue;
+		}
+
+		assert("vs-1218", state_of_extent(ext) == ALLOCATED_EXTENT);
+
+		if (length != 0) {
+			start = extent_get_start(ext) + skip;
+
+			/* BA_DEFER bit parameter is turned on because blocks which get freed are not safe to be freed
+			   immediately */
+			reiser4_dealloc_blocks(&start, &length,
+					       0 /* not used */ ,
+					       BA_DEFER
+					       /* unformatted with defer */ );
+		}
+		skip = 0;
+		offset += length;
+		ext++;
+	}
+	return retval;
+}
+
+/* item_plugin->b.kill_units */
+int
+kill_units_extent(coord_t * coord, pos_in_node_t from, pos_in_node_t to,
+		  struct carry_kill_data *kdata, reiser4_key * smallest_removed,
+		  reiser4_key * new_first)
+{
+	reiser4_extent *ext;
+	reiser4_key item_key;
+	pos_in_node_t count;
+	reiser4_key from_key, to_key;
+	const reiser4_key *pfrom_key, *pto_key;
+	loff_t off;
+	int result;
+
+	assert("vs-1541",
+	       ((kdata->params.from_key == NULL && kdata->params.to_key == NULL)
+		|| (kdata->params.from_key != NULL
+		    && kdata->params.to_key != NULL)));
+
+	if (kdata->params.from_key) {
+		pfrom_key = kdata->params.from_key;
+		pto_key = kdata->params.to_key;
+	} else {
+		coord_t dup;
+
+		/* calculate key range of kill */
+		assert("vs-1549", from == coord->unit_pos);
+		unit_key_by_coord(coord, &from_key);
+		pfrom_key = &from_key;
+
+		coord_dup(&dup, coord);
+		dup.unit_pos = to;
+		max_unit_key_by_coord(&dup, &to_key);
+		pto_key = &to_key;
+	}
+
+	item_key_by_coord(coord, &item_key);
+
+#if REISER4_DEBUG
+	{
+		reiser4_key max_item_key;
+
+		max_item_key_by_coord(coord, &max_item_key);
+
+		if (new_first) {
+			/* head of item is to be cut */
+			assert("vs-1542", keyeq(pfrom_key, &item_key));
+			assert("vs-1538", keylt(pto_key, &max_item_key));
+		} else {
+			/* tail of item is to be cut */
+			assert("vs-1540", keygt(pfrom_key, &item_key));
+			assert("vs-1543", !keylt(pto_key, &max_item_key));
+		}
+	}
+#endif
+
+	if (smallest_removed)
+		*smallest_removed = *pfrom_key;
+
+	if (new_first) {
+		/* item head is cut. Item key will change. This new key is calculated here */
+		assert("vs-1556",
+		       (get_key_offset(pto_key) & (PAGE_CACHE_SIZE - 1)) ==
+		       (PAGE_CACHE_SIZE - 1));
+		*new_first = *pto_key;
+		set_key_offset(new_first, get_key_offset(new_first) + 1);
+	}
+
+	count = to - from + 1;
+	result = kill_hook_extent(coord, from, count, kdata);
+	if (result == ITEM_TAIL_KILLED) {
+		assert("vs-1553",
+		       get_key_offset(pfrom_key) >=
+		       get_key_offset(&item_key) + extent_size(coord, from));
+		off =
+		    get_key_offset(pfrom_key) - (get_key_offset(&item_key) +
+						 extent_size(coord, from));
+		if (off) {
+			/* unit @from is to be cut partially. Its width decreases */
+			ext = extent_item(coord) + from;
+			extent_set_width(ext,
+					 (off + PAGE_CACHE_SIZE -
+					  1) >> PAGE_CACHE_SHIFT);
+			count--;
+		}
+	} else {
+		__u64 max_to_offset;
+		__u64 rest;
+
+		assert("vs-1575", result == ITEM_HEAD_KILLED);
+		assert("", from == 0);
+		assert("",
+		       ((get_key_offset(pto_key) + 1) & (PAGE_CACHE_SIZE -
+							 1)) == 0);
+		assert("",
+		       get_key_offset(pto_key) + 1 >
+		       get_key_offset(&item_key) + extent_size(coord, to));
+		max_to_offset =
+		    get_key_offset(&item_key) + extent_size(coord, to + 1) - 1;
+		assert("", get_key_offset(pto_key) <= max_to_offset);
+
+		rest =
+		    (max_to_offset -
+		     get_key_offset(pto_key)) >> PAGE_CACHE_SHIFT;
+		if (rest) {
+			/* unit @to is to be cut partially */
+			ext = extent_item(coord) + to;
+
+			assert("", extent_get_width(ext) > rest);
+
+			if (state_of_extent(ext) == ALLOCATED_EXTENT)
+				extent_set_start(ext,
+						 extent_get_start(ext) +
+						 (extent_get_width(ext) -
+						  rest));
+
+			extent_set_width(ext, rest);
+			count--;
+		}
+	}
+	return count * sizeof(reiser4_extent);
+}
+
+/* item_plugin->b.cut_units
+   this is too similar to kill_units_extent */
+int
+cut_units_extent(coord_t * coord, pos_in_node_t from, pos_in_node_t to,
+		 struct carry_cut_data *cdata, reiser4_key * smallest_removed,
+		 reiser4_key * new_first)
+{
+	reiser4_extent *ext;
+	reiser4_key item_key;
+	pos_in_node_t count;
+	reiser4_key from_key, to_key;
+	const reiser4_key *pfrom_key, *pto_key;
+	loff_t off;
+
+	assert("vs-1541",
+	       ((cdata->params.from_key == NULL && cdata->params.to_key == NULL)
+		|| (cdata->params.from_key != NULL
+		    && cdata->params.to_key != NULL)));
+
+	if (cdata->params.from_key) {
+		pfrom_key = cdata->params.from_key;
+		pto_key = cdata->params.to_key;
+	} else {
+		coord_t dup;
+
+		/* calculate key range of kill */
+		coord_dup(&dup, coord);
+		dup.unit_pos = from;
+		unit_key_by_coord(&dup, &from_key);
+
+		dup.unit_pos = to;
+		max_unit_key_by_coord(&dup, &to_key);
+
+		pfrom_key = &from_key;
+		pto_key = &to_key;
+	}
+
+	assert("vs-1555",
+	       (get_key_offset(pfrom_key) & (PAGE_CACHE_SIZE - 1)) == 0);
+	assert("vs-1556",
+	       (get_key_offset(pto_key) & (PAGE_CACHE_SIZE - 1)) ==
+	       (PAGE_CACHE_SIZE - 1));
+
+	item_key_by_coord(coord, &item_key);
+
+#if REISER4_DEBUG
+	{
+		reiser4_key max_item_key;
+
+		assert("vs-1584",
+		       get_key_locality(pfrom_key) ==
+		       get_key_locality(&item_key));
+		assert("vs-1585",
+		       get_key_type(pfrom_key) == get_key_type(&item_key));
+		assert("vs-1586",
+		       get_key_objectid(pfrom_key) ==
+		       get_key_objectid(&item_key));
+		assert("vs-1587",
+		       get_key_ordering(pfrom_key) ==
+		       get_key_ordering(&item_key));
+
+		max_item_key_by_coord(coord, &max_item_key);
+
+		if (new_first != NULL) {
+			/* head of item is to be cut */
+			assert("vs-1542", keyeq(pfrom_key, &item_key));
+			assert("vs-1538", keylt(pto_key, &max_item_key));
+		} else {
+			/* tail of item is to be cut */
+			assert("vs-1540", keygt(pfrom_key, &item_key));
+			assert("vs-1543", keyeq(pto_key, &max_item_key));
+		}
+	}
+#endif
+
+	if (smallest_removed)
+		*smallest_removed = *pfrom_key;
+
+	if (new_first) {
+		/* item head is cut. Item key will change. This new key is calculated here */
+		*new_first = *pto_key;
+		set_key_offset(new_first, get_key_offset(new_first) + 1);
+	}
+
+	count = to - from + 1;
+
+	assert("vs-1553",
+	       get_key_offset(pfrom_key) >=
+	       get_key_offset(&item_key) + extent_size(coord, from));
+	off =
+	    get_key_offset(pfrom_key) - (get_key_offset(&item_key) +
+					 extent_size(coord, from));
+	if (off) {
+		/* tail of unit @from is to be cut partially. Its width decreases */
+		assert("vs-1582", new_first == NULL);
+		ext = extent_item(coord) + from;
+		extent_set_width(ext, off >> PAGE_CACHE_SHIFT);
+		count--;
+	}
+
+	assert("vs-1554",
+	       get_key_offset(pto_key) <=
+	       get_key_offset(&item_key) + extent_size(coord, to + 1) - 1);
+	off =
+	    (get_key_offset(&item_key) + extent_size(coord, to + 1) - 1) -
+	    get_key_offset(pto_key);
+	if (off) {
+		/* @to_key is smaller than max key of unit @to. Unit @to will not be removed. It gets start increased
+		   and width decreased. */
+		assert("vs-1583", (off & (PAGE_CACHE_SIZE - 1)) == 0);
+		ext = extent_item(coord) + to;
+		if (state_of_extent(ext) == ALLOCATED_EXTENT)
+			extent_set_start(ext,
+					 extent_get_start(ext) +
+					 (extent_get_width(ext) -
+					  (off >> PAGE_CACHE_SHIFT)));
+
+		extent_set_width(ext, (off >> PAGE_CACHE_SHIFT));
+		count--;
+	}
+	return count * sizeof(reiser4_extent);
+}
+
+/* item_plugin->b.unit_key */
+reiser4_key *unit_key_extent(const coord_t * coord, reiser4_key * key)
+{
+	assert("vs-300", coord_is_existing_unit(coord));
+
+	item_key_by_coord(coord, key);
+	set_key_offset(key,
+		       (get_key_offset(key) +
+			extent_size(coord, coord->unit_pos)));
+
+	return key;
+}
+
+/* item_plugin->b.max_unit_key */
+reiser4_key *max_unit_key_extent(const coord_t * coord, reiser4_key * key)
+{
+	assert("vs-300", coord_is_existing_unit(coord));
+
+	item_key_by_coord(coord, key);
+	set_key_offset(key,
+		       (get_key_offset(key) +
+			extent_size(coord, coord->unit_pos + 1) - 1));
+	return key;
+}
+
+/* item_plugin->b.estimate
+   item_plugin->b.item_data_by_flow */
+
+#if REISER4_DEBUG
+
+/* item_plugin->b.check
+   used for debugging, every item should have here the most complete
+   possible check of the consistency of the item that the inventor can
+   construct
+*/
+int check_extent(const coord_t * coord /* coord of item to check */ ,
+		 const char **error /* where to store error message */ )
+{
+	reiser4_extent *ext, *first;
+	unsigned i, j;
+	reiser4_block_nr start, width, blk_cnt;
+	unsigned num_units;
+	reiser4_tree *tree;
+	oid_t oid;
+	reiser4_key key;
+	coord_t scan;
+
+	assert("vs-933", REISER4_DEBUG);
+
+	if (znode_get_level(coord->node) != TWIG_LEVEL) {
+		*error = "Extent on the wrong level";
+		return -1;
+	}
+	if (item_length_by_coord(coord) % sizeof(reiser4_extent) != 0) {
+		*error = "Wrong item size";
+		return -1;
+	}
+	ext = first = extent_item(coord);
+	blk_cnt = reiser4_block_count(reiser4_get_current_sb());
+	num_units = coord_num_units(coord);
+	tree = znode_get_tree(coord->node);
+	item_key_by_coord(coord, &key);
+	oid = get_key_objectid(&key);
+	coord_dup(&scan, coord);
+
+	for (i = 0; i < num_units; ++i, ++ext) {
+		__u64 index;
+
+		scan.unit_pos = i;
+		index = extent_unit_index(&scan);
+
+#if 0
+		/* check that all jnodes are present for the unallocated
+		 * extent */
+		if (state_of_extent(ext) == UNALLOCATED_EXTENT) {
+			for (j = 0; j < extent_get_width(ext); j++) {
+				jnode *node;
+
+				node = jlookup(tree, oid, index + j);
+				if (node == NULL) {
+					print_coord("scan", &scan, 0);
+					*error = "Jnode missing";
+					return -1;
+				}
+				jput(node);
+			}
+		}
+#endif
+
+		start = extent_get_start(ext);
+		if (start < 2)
+			continue;
+		/* extent is allocated one */
+		width = extent_get_width(ext);
+		if (start >= blk_cnt) {
+			*error = "Start too large";
+			return -1;
+		}
+		if (start + width > blk_cnt) {
+			*error = "End too large";
+			return -1;
+		}
+		/* make sure that this extent does not overlap with other
+		   allocated extents extents */
+		for (j = 0; j < i; j++) {
+			if (state_of_extent(first + j) != ALLOCATED_EXTENT)
+				continue;
+			if (!
+			    ((extent_get_start(ext) >=
+			      extent_get_start(first + j) +
+			      extent_get_width(first + j))
+			     || (extent_get_start(ext) +
+				 extent_get_width(ext) <=
+				 extent_get_start(first + j)))) {
+				*error = "Extent overlaps with others";
+				return -1;
+			}
+		}
+
+	}
+
+	return 0;
+}
+
+#endif				/* REISER4_DEBUG */
+
+/*
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/item/internal.c newtree/fs/reiser4/plugin/item/internal.c
--- oldtree/fs/reiser4/plugin/item/internal.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/internal.c	2006-02-21 15:58:35.009824256 +0000
@@ -0,0 +1,392 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Implementation of internal-item plugin methods. */
+
+#include "../../forward.h"
+#include "../../debug.h"
+#include "../../dformat.h"
+#include "../../key.h"
+#include "../../coord.h"
+#include "internal.h"
+#include "item.h"
+#include "../node/node.h"
+#include "../plugin.h"
+#include "../../jnode.h"
+#include "../../znode.h"
+#include "../../tree_walk.h"
+#include "../../tree_mod.h"
+#include "../../tree.h"
+#include "../../super.h"
+#include "../../block_alloc.h"
+
+/* see internal.h for explanation */
+
+/* plugin->u.item.b.mergeable */
+int mergeable_internal(const coord_t * p1 UNUSED_ARG /* first item */ ,
+		       const coord_t * p2 UNUSED_ARG /* second item */ )
+{
+	/* internal items are not mergeable */
+	return 0;
+}
+
+/* ->lookup() method for internal items */
+lookup_result lookup_internal(const reiser4_key * key /* key to look up */ ,
+			      lookup_bias bias UNUSED_ARG /* lookup bias */ ,
+			      coord_t * coord /* coord of item */ )
+{
+	reiser4_key ukey;
+
+	switch (keycmp(unit_key_by_coord(coord, &ukey), key)) {
+	default:
+		impossible("", "keycmp()?!");
+	case LESS_THAN:
+		/* FIXME-VS: AFTER_ITEM used to be here. But with new coord
+		   item plugin can not be taken using coord set this way */
+		assert("vs-681", coord->unit_pos == 0);
+		coord->between = AFTER_UNIT;
+	case EQUAL_TO:
+		return CBK_COORD_FOUND;
+	case GREATER_THAN:
+		return CBK_COORD_NOTFOUND;
+	}
+}
+
+/* return body of internal item at @coord */
+static internal_item_layout *internal_at(const coord_t * coord	/* coord of
+								 * item */ )
+{
+	assert("nikita-607", coord != NULL);
+	assert("nikita-1650",
+	       item_plugin_by_coord(coord) ==
+	       item_plugin_by_id(NODE_POINTER_ID));
+	return (internal_item_layout *) item_body_by_coord(coord);
+}
+
+void update_internal(const coord_t * coord, const reiser4_block_nr * blocknr)
+{
+	internal_item_layout *item = internal_at(coord);
+	assert("nikita-2959", reiser4_blocknr_is_sane(blocknr));
+
+	put_unaligned(cpu_to_le64(*blocknr), &item->pointer);
+}
+
+/* return child block number stored in the internal item at @coord */
+static reiser4_block_nr pointer_at(const coord_t * coord /* coord of item */ )
+{
+	assert("nikita-608", coord != NULL);
+	return le64_to_cpu(get_unaligned(&internal_at(coord)->pointer));
+}
+
+/* get znode pointed to by internal @item */
+static znode *znode_at(const coord_t * item /* coord of item */ ,
+		       znode * parent /* parent node */ )
+{
+	return child_znode(item, parent, 1, 0);
+}
+
+/* store pointer from internal item into "block". Implementation of
+    ->down_link() method */
+void down_link_internal(const coord_t * coord /* coord of item */ ,
+			const reiser4_key * key UNUSED_ARG	/* key to get
+								 * pointer for */ ,
+			reiser4_block_nr * block /* resulting block number */ )
+{
+	ON_DEBUG(reiser4_key item_key);
+
+	assert("nikita-609", coord != NULL);
+	assert("nikita-611", block != NULL);
+	assert("nikita-612", (key == NULL) ||
+	       /* twig horrors */
+	       (znode_get_level(coord->node) == TWIG_LEVEL)
+	       || keyle(item_key_by_coord(coord, &item_key), key));
+
+	*block = pointer_at(coord);
+	assert("nikita-2960", reiser4_blocknr_is_sane(block));
+}
+
+/* Get the child's block number, or 0 if the block is unallocated. */
+int
+utmost_child_real_block_internal(const coord_t * coord, sideof side UNUSED_ARG,
+				 reiser4_block_nr * block)
+{
+	assert("jmacd-2059", coord != NULL);
+
+	*block = pointer_at(coord);
+	assert("nikita-2961", reiser4_blocknr_is_sane(block));
+
+	if (blocknr_is_fake(block)) {
+		*block = 0;
+	}
+
+	return 0;
+}
+
+/* Return the child. */
+int
+utmost_child_internal(const coord_t * coord, sideof side UNUSED_ARG,
+		      jnode ** childp)
+{
+	reiser4_block_nr block = pointer_at(coord);
+	znode *child;
+
+	assert("jmacd-2059", childp != NULL);
+	assert("nikita-2962", reiser4_blocknr_is_sane(&block));
+
+	child = zlook(znode_get_tree(coord->node), &block);
+
+	if (IS_ERR(child)) {
+		return PTR_ERR(child);
+	}
+
+	*childp = ZJNODE(child);
+
+	return 0;
+}
+
+static void check_link(znode * left, znode * right)
+{
+	znode *scan;
+
+	for (scan = left; scan != right; scan = scan->right) {
+		if (ZF_ISSET(scan, JNODE_RIP))
+			break;
+		if (znode_is_right_connected(scan) && scan->right != NULL) {
+			if (ZF_ISSET(scan->right, JNODE_RIP))
+				break;
+			assert("nikita-3285",
+			       znode_is_left_connected(scan->right));
+			assert("nikita-3265",
+			       ergo(scan != left,
+				    ZF_ISSET(scan, JNODE_HEARD_BANSHEE)));
+			assert("nikita-3284", scan->right->left == scan);
+		} else
+			break;
+	}
+}
+
+int check__internal(const coord_t * coord, const char **error)
+{
+	reiser4_block_nr blk;
+	znode *child;
+	coord_t cpy;
+
+	blk = pointer_at(coord);
+	if (!reiser4_blocknr_is_sane(&blk)) {
+		*error = "Invalid pointer";
+		return -1;
+	}
+	coord_dup(&cpy, coord);
+	child = znode_at(&cpy, cpy.node);
+	if (child != NULL) {
+		znode *left_child;
+		znode *right_child;
+
+		left_child = right_child = NULL;
+
+		assert("nikita-3256", znode_invariant(child));
+		if (coord_prev_item(&cpy) == 0 && item_is_internal(&cpy)) {
+			left_child = znode_at(&cpy, cpy.node);
+			if (left_child != NULL) {
+				read_lock_tree(znode_get_tree(child));
+				check_link(left_child, child);
+				read_unlock_tree(znode_get_tree(child));
+				zput(left_child);
+			}
+		}
+		coord_dup(&cpy, coord);
+		if (coord_next_item(&cpy) == 0 && item_is_internal(&cpy)) {
+			right_child = znode_at(&cpy, cpy.node);
+			if (right_child != NULL) {
+				read_lock_tree(znode_get_tree(child));
+				check_link(child, right_child);
+				read_unlock_tree(znode_get_tree(child));
+				zput(right_child);
+			}
+		}
+		zput(child);
+	}
+	return 0;
+}
+
+/* return true only if this item really points to "block" */
+/* Audited by: green(2002.06.14) */
+int has_pointer_to_internal(const coord_t * coord /* coord of item */ ,
+			    const reiser4_block_nr * block	/* block number to
+								 * check */ )
+{
+	assert("nikita-613", coord != NULL);
+	assert("nikita-614", block != NULL);
+
+	return pointer_at(coord) == *block;
+}
+
+/* hook called by ->create_item() method of node plugin after new internal
+   item was just created.
+
+   This is point where pointer to new node is inserted into tree. Initialize
+   parent pointer in child znode, insert child into sibling list and slum.
+
+*/
+int create_hook_internal(const coord_t * item /* coord of item */ ,
+			 void *arg /* child's left neighbor, if any */ )
+{
+	znode *child;
+	__u64 child_ptr;
+
+	assert("nikita-1252", item != NULL);
+	assert("nikita-1253", item->node != NULL);
+	assert("nikita-1181", znode_get_level(item->node) > LEAF_LEVEL);
+	assert("nikita-1450", item->unit_pos == 0);
+
+	/*
+	 * preparing to item insertion build_child_ptr_data sets pointer to
+	 * data to be inserted to jnode's blocknr which is in cpu byte
+	 * order. Node's create_item simply copied those data. As result we
+	 * have child pointer in cpu's byte order. Convert content of internal
+	 * item to little endian byte order.
+	 */
+	child_ptr = get_unaligned((__u64 *)item_body_by_coord(item));
+	update_internal(item, &child_ptr);
+
+	child = znode_at(item, item->node);
+	if (child != NULL && !IS_ERR(child)) {
+		znode *left;
+		int result = 0;
+		reiser4_tree *tree;
+
+		left = arg;
+		tree = znode_get_tree(item->node);
+		write_lock_tree(tree);
+		write_lock_dk(tree);
+		assert("nikita-1400", (child->in_parent.node == NULL)
+		       || (znode_above_root(child->in_parent.node)));
+		++item->node->c_count;
+		coord_to_parent_coord(item, &child->in_parent);
+		sibling_list_insert_nolock(child, left);
+
+		assert("nikita-3297", ZF_ISSET(child, JNODE_ORPHAN));
+		ZF_CLR(child, JNODE_ORPHAN);
+
+		if ((left != NULL) && !keyeq(znode_get_rd_key(left),
+					     znode_get_rd_key(child))) {
+			znode_set_rd_key(child, znode_get_rd_key(left));
+		}
+		write_unlock_dk(tree);
+		write_unlock_tree(tree);
+		zput(child);
+		return result;
+	} else {
+		if (child == NULL)
+			child = ERR_PTR(-EIO);
+		return PTR_ERR(child);
+	}
+}
+
+/* hook called by ->cut_and_kill() method of node plugin just before internal
+   item is removed.
+
+   This is point where empty node is removed from the tree. Clear parent
+   pointer in child, and mark node for pending deletion.
+
+   Node will be actually deleted later and in several installations:
+
+    . when last lock on this node will be released, node will be removed from
+    the sibling list and its lock will be invalidated
+
+    . when last reference to this node will be dropped, bitmap will be updated
+    and node will be actually removed from the memory.
+
+
+*/
+int kill_hook_internal(const coord_t * item /* coord of item */ ,
+		       pos_in_node_t from UNUSED_ARG /* start unit */ ,
+		       pos_in_node_t count UNUSED_ARG /* stop unit */ ,
+		       struct carry_kill_data *p UNUSED_ARG)
+{
+	znode *child;
+
+	assert("nikita-1222", item != NULL);
+	assert("nikita-1224", from == 0);
+	assert("nikita-1225", count == 1);
+
+	child = znode_at(item, item->node);
+	if (IS_ERR(child))
+		return PTR_ERR(child);
+	else if (node_is_empty(child)) {
+		reiser4_tree *tree;
+
+		assert("nikita-1397", znode_is_write_locked(child));
+		assert("nikita-1398", child->c_count == 0);
+		assert("nikita-2546", ZF_ISSET(child, JNODE_HEARD_BANSHEE));
+
+		tree = znode_get_tree(item->node);
+		write_lock_tree(tree);
+		init_parent_coord(&child->in_parent, NULL);
+		--item->node->c_count;
+		write_unlock_tree(tree);
+		zput(child);
+		return 0;
+	} else {
+		warning("nikita-1223",
+			"Cowardly refuse to remove link to non-empty node");
+		zput(child);
+		return RETERR(-EIO);
+	}
+}
+
+/* hook called by ->shift() node plugin method when iternal item was just
+   moved from one node to another.
+
+   Update parent pointer in child and c_counts in old and new parent
+
+*/
+int shift_hook_internal(const coord_t * item /* coord of item */ ,
+			unsigned from UNUSED_ARG /* start unit */ ,
+			unsigned count UNUSED_ARG /* stop unit */ ,
+			znode * old_node /* old parent */ )
+{
+	znode *child;
+	znode *new_node;
+	reiser4_tree *tree;
+
+	assert("nikita-1276", item != NULL);
+	assert("nikita-1277", from == 0);
+	assert("nikita-1278", count == 1);
+	assert("nikita-1451", item->unit_pos == 0);
+
+	new_node = item->node;
+	assert("nikita-2132", new_node != old_node);
+	tree = znode_get_tree(item->node);
+	child = child_znode(item, old_node, 1, 0);
+	if (child == NULL)
+		return 0;
+	if (!IS_ERR(child)) {
+		write_lock_tree(tree);
+		++new_node->c_count;
+		assert("nikita-1395", znode_parent(child) == old_node);
+		assert("nikita-1396", old_node->c_count > 0);
+		coord_to_parent_coord(item, &child->in_parent);
+		assert("nikita-1781", znode_parent(child) == new_node);
+		assert("nikita-1782",
+		       check_tree_pointer(item, child) == NS_FOUND);
+		--old_node->c_count;
+		write_unlock_tree(tree);
+		zput(child);
+		return 0;
+	} else
+		return PTR_ERR(child);
+}
+
+/* plugin->u.item.b.max_key_inside - not defined */
+
+/* plugin->u.item.b.nr_units - item.c:single_unit */
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/item/internal.h newtree/fs/reiser4/plugin/item/internal.h
--- oldtree/fs/reiser4/plugin/item/internal.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/internal.h	2006-02-21 15:58:34.629882016 +0000
@@ -0,0 +1,57 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+/* Internal item contains down-link to the child of the internal/twig
+   node in a tree. It is internal items that are actually used during
+   tree traversal. */
+
+#if !defined( __FS_REISER4_PLUGIN_ITEM_INTERNAL_H__ )
+#define __FS_REISER4_PLUGIN_ITEM_INTERNAL_H__
+
+#include "../../forward.h"
+#include "../../dformat.h"
+
+/* on-disk layout of internal item */
+typedef struct internal_item_layout {
+	/*  0 */ reiser4_dblock_nr pointer;
+	/*  4 */
+} internal_item_layout;
+
+struct cut_list;
+
+int mergeable_internal(const coord_t * p1, const coord_t * p2);
+lookup_result lookup_internal(const reiser4_key * key, lookup_bias bias,
+			      coord_t * coord);
+/* store pointer from internal item into "block". Implementation of
+    ->down_link() method */
+extern void down_link_internal(const coord_t * coord, const reiser4_key * key,
+			       reiser4_block_nr * block);
+extern int has_pointer_to_internal(const coord_t * coord,
+				   const reiser4_block_nr * block);
+extern int create_hook_internal(const coord_t * item, void *arg);
+extern int kill_hook_internal(const coord_t * item, pos_in_node_t from,
+			      pos_in_node_t count, struct carry_kill_data *);
+extern int shift_hook_internal(const coord_t * item, unsigned from,
+			       unsigned count, znode * old_node);
+extern void print_internal(const char *prefix, coord_t * coord);
+
+extern int utmost_child_internal(const coord_t * coord, sideof side,
+				 jnode ** child);
+int utmost_child_real_block_internal(const coord_t * coord, sideof side,
+				     reiser4_block_nr * block);
+
+extern void update_internal(const coord_t * coord,
+			    const reiser4_block_nr * blocknr);
+/* FIXME: reiserfs has check_internal */
+extern int check__internal(const coord_t * coord, const char **error);
+
+/* __FS_REISER4_PLUGIN_ITEM_INTERNAL_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/item/item.c newtree/fs/reiser4/plugin/item/item.c
--- oldtree/fs/reiser4/plugin/item/item.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/item.c	2006-02-21 15:58:34.630881864 +0000
@@ -0,0 +1,730 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* definition of item plugins. */
+
+#include "../../forward.h"
+#include "../../debug.h"
+#include "../../key.h"
+#include "../../coord.h"
+#include "../plugin_header.h"
+#include "sde.h"
+#include "internal.h"
+#include "item.h"
+#include "static_stat.h"
+#include "../plugin.h"
+#include "../../znode.h"
+#include "../../tree.h"
+#include "../../context.h"
+#include "ctail.h"
+
+/* return pointer to item body */
+void item_body_by_coord_hard(coord_t * coord /* coord to query */ )
+{
+	assert("nikita-324", coord != NULL);
+	assert("nikita-325", coord->node != NULL);
+	assert("nikita-326", znode_is_loaded(coord->node));
+	assert("nikita-3200", coord->offset == INVALID_OFFSET);
+
+	coord->offset =
+	    node_plugin_by_node(coord->node)->item_by_coord(coord) -
+	    zdata(coord->node);
+	ON_DEBUG(coord->body_v = coord->node->times_locked);
+}
+
+void *item_body_by_coord_easy(const coord_t * coord /* coord to query */ )
+{
+	return zdata(coord->node) + coord->offset;
+}
+
+#if REISER4_DEBUG
+
+int item_body_is_valid(const coord_t * coord)
+{
+	return
+	    coord->offset ==
+	    node_plugin_by_node(coord->node)->item_by_coord(coord) -
+	    zdata(coord->node);
+}
+
+#endif
+
+/* return length of item at @coord */
+pos_in_node_t item_length_by_coord(const coord_t * coord /* coord to query */ )
+{
+	int len;
+
+	assert("nikita-327", coord != NULL);
+	assert("nikita-328", coord->node != NULL);
+	assert("nikita-329", znode_is_loaded(coord->node));
+
+	len = node_plugin_by_node(coord->node)->length_by_coord(coord);
+	return len;
+}
+
+void obtain_item_plugin(const coord_t * coord)
+{
+	assert("nikita-330", coord != NULL);
+	assert("nikita-331", coord->node != NULL);
+	assert("nikita-332", znode_is_loaded(coord->node));
+
+	coord_set_iplug((coord_t *) coord,
+			node_plugin_by_node(coord->node)->
+			plugin_by_coord(coord));
+	assert("nikita-2479",
+	       coord_iplug(coord) ==
+	       node_plugin_by_node(coord->node)->plugin_by_coord(coord));
+}
+
+/* return type of item at @coord */
+item_type_id item_type_by_coord(const coord_t * coord /* coord to query */ )
+{
+	assert("nikita-333", coord != NULL);
+	assert("nikita-334", coord->node != NULL);
+	assert("nikita-335", znode_is_loaded(coord->node));
+	assert("nikita-336", item_plugin_by_coord(coord) != NULL);
+
+	return item_plugin_by_coord(coord)->b.item_type;
+}
+
+/* return id of item */
+/* Audited by: green(2002.06.15) */
+item_id item_id_by_coord(const coord_t * coord /* coord to query */ )
+{
+	assert("vs-539", coord != NULL);
+	assert("vs-538", coord->node != NULL);
+	assert("vs-537", znode_is_loaded(coord->node));
+	assert("vs-536", item_plugin_by_coord(coord) != NULL);
+	assert("vs-540",
+	       item_id_by_plugin(item_plugin_by_coord(coord)) < LAST_ITEM_ID);
+
+	return item_id_by_plugin(item_plugin_by_coord(coord));
+}
+
+/* return key of item at @coord */
+/* Audited by: green(2002.06.15) */
+reiser4_key *item_key_by_coord(const coord_t * coord /* coord to query */ ,
+			       reiser4_key * key /* result */ )
+{
+	assert("nikita-338", coord != NULL);
+	assert("nikita-339", coord->node != NULL);
+	assert("nikita-340", znode_is_loaded(coord->node));
+
+	return node_plugin_by_node(coord->node)->key_at(coord, key);
+}
+
+/* this returns max key in the item */
+reiser4_key *max_item_key_by_coord(const coord_t * coord /* coord to query */ ,
+				   reiser4_key * key /* result */ )
+{
+	coord_t last;
+
+	assert("nikita-338", coord != NULL);
+	assert("nikita-339", coord->node != NULL);
+	assert("nikita-340", znode_is_loaded(coord->node));
+
+	/* make coord pointing to last item's unit */
+	coord_dup(&last, coord);
+	last.unit_pos = coord_num_units(&last) - 1;
+	assert("vs-1560", coord_is_existing_unit(&last));
+
+	max_unit_key_by_coord(&last, key);
+	return key;
+}
+
+/* return key of unit at @coord */
+reiser4_key *unit_key_by_coord(const coord_t * coord /* coord to query */ ,
+			       reiser4_key * key /* result */ )
+{
+	assert("nikita-772", coord != NULL);
+	assert("nikita-774", coord->node != NULL);
+	assert("nikita-775", znode_is_loaded(coord->node));
+
+	if (item_plugin_by_coord(coord)->b.unit_key != NULL)
+		return item_plugin_by_coord(coord)->b.unit_key(coord, key);
+	else
+		return item_key_by_coord(coord, key);
+}
+
+/* return the biggest key contained the unit @coord */
+reiser4_key *max_unit_key_by_coord(const coord_t * coord /* coord to query */ ,
+				   reiser4_key * key /* result */ )
+{
+	assert("nikita-772", coord != NULL);
+	assert("nikita-774", coord->node != NULL);
+	assert("nikita-775", znode_is_loaded(coord->node));
+
+	if (item_plugin_by_coord(coord)->b.max_unit_key != NULL)
+		return item_plugin_by_coord(coord)->b.max_unit_key(coord, key);
+	else
+		return unit_key_by_coord(coord, key);
+}
+
+/* ->max_key_inside() method for items consisting of exactly one key (like
+    stat-data) */
+static reiser4_key *max_key_inside_single_key(const coord_t *
+					      coord /* coord of item */ ,
+					      reiser4_key *
+					      result /* resulting key */ )
+{
+	assert("nikita-604", coord != NULL);
+
+	/* coord -> key is starting key of this item and it has to be already
+	   filled in */
+	return unit_key_by_coord(coord, result);
+}
+
+/* ->nr_units() method for items consisting of exactly one unit always */
+static pos_in_node_t
+nr_units_single_unit(const coord_t * coord UNUSED_ARG /* coord of item */ )
+{
+	return 1;
+}
+
+static int
+paste_no_paste(coord_t * coord UNUSED_ARG,
+	       reiser4_item_data * data UNUSED_ARG,
+	       carry_plugin_info * info UNUSED_ARG)
+{
+	return 0;
+}
+
+/* default ->fast_paste() method */
+static int
+agree_to_fast_op(const coord_t * coord UNUSED_ARG /* coord of item */ )
+{
+	return 1;
+}
+
+int item_can_contain_key(const coord_t * item /* coord of item */ ,
+			 const reiser4_key * key /* key to check */ ,
+			 const reiser4_item_data * data	/* parameters of item
+							 * being created */ )
+{
+	item_plugin *iplug;
+	reiser4_key min_key_in_item;
+	reiser4_key max_key_in_item;
+
+	assert("nikita-1658", item != NULL);
+	assert("nikita-1659", key != NULL);
+
+	iplug = item_plugin_by_coord(item);
+	if (iplug->b.can_contain_key != NULL)
+		return iplug->b.can_contain_key(item, key, data);
+	else {
+		assert("nikita-1681", iplug->b.max_key_inside != NULL);
+		item_key_by_coord(item, &min_key_in_item);
+		iplug->b.max_key_inside(item, &max_key_in_item);
+
+		/* can contain key if
+		   min_key_in_item <= key &&
+		   key <= max_key_in_item
+		 */
+		return keyle(&min_key_in_item, key)
+		    && keyle(key, &max_key_in_item);
+	}
+}
+
+/* mergeable method for non mergeable items */
+static int
+not_mergeable(const coord_t * i1 UNUSED_ARG, const coord_t * i2 UNUSED_ARG)
+{
+	return 0;
+}
+
+/* return 0 if @item1 and @item2 are not mergeable, !0 - otherwise */
+int are_items_mergeable(const coord_t * i1 /* coord of first item */ ,
+			const coord_t * i2 /* coord of second item */ )
+{
+	item_plugin *iplug;
+	reiser4_key k1;
+	reiser4_key k2;
+
+	assert("nikita-1336", i1 != NULL);
+	assert("nikita-1337", i2 != NULL);
+
+	iplug = item_plugin_by_coord(i1);
+	assert("nikita-1338", iplug != NULL);
+
+	/* NOTE-NIKITA are_items_mergeable() is also called by assertions in
+	   shifting code when nodes are in "suspended" state. */
+	assert("nikita-1663",
+	       keyle(item_key_by_coord(i1, &k1), item_key_by_coord(i2, &k2)));
+
+	if (iplug->b.mergeable != NULL) {
+		return iplug->b.mergeable(i1, i2);
+	} else if (iplug->b.max_key_inside != NULL) {
+		iplug->b.max_key_inside(i1, &k1);
+		item_key_by_coord(i2, &k2);
+
+		/* mergeable if ->max_key_inside() >= key of i2; */
+		return keyge(iplug->b.max_key_inside(i1, &k1),
+			     item_key_by_coord(i2, &k2));
+	} else {
+		item_key_by_coord(i1, &k1);
+		item_key_by_coord(i2, &k2);
+
+		return
+		    (get_key_locality(&k1) == get_key_locality(&k2)) &&
+		    (get_key_objectid(&k1) == get_key_objectid(&k2))
+		    && (iplug == item_plugin_by_coord(i2));
+	}
+}
+
+int item_is_extent(const coord_t * item)
+{
+	assert("vs-482", coord_is_existing_item(item));
+	return item_id_by_coord(item) == EXTENT_POINTER_ID;
+}
+
+int item_is_tail(const coord_t * item)
+{
+	assert("vs-482", coord_is_existing_item(item));
+	return item_id_by_coord(item) == FORMATTING_ID;
+}
+
+int item_is_statdata(const coord_t * item)
+{
+	assert("vs-516", coord_is_existing_item(item));
+	return item_type_by_coord(item) == STAT_DATA_ITEM_TYPE;
+}
+
+int item_is_ctail(const coord_t * item)
+{
+	assert("edward-xx", coord_is_existing_item(item));
+	return item_id_by_coord(item) == CTAIL_ID;
+}
+
+static int change_item(struct inode *inode, reiser4_plugin * plugin)
+{
+	/* cannot change constituent item (sd, or dir_item) */
+	return RETERR(-EINVAL);
+}
+
+static reiser4_plugin_ops item_plugin_ops = {
+	.init = NULL,
+	.load = NULL,
+	.save_len = NULL,
+	.save = NULL,
+	.change = change_item
+};
+
+item_plugin item_plugins[LAST_ITEM_ID] = {
+	[STATIC_STAT_DATA_ID] = {
+		.h = {
+			.type_id = REISER4_ITEM_PLUGIN_TYPE,
+			.id = STATIC_STAT_DATA_ID,
+			.pops = &item_plugin_ops,
+			.label = "sd",
+			.desc = "stat-data",
+			.linkage = {NULL, NULL}
+		},
+		.b = {
+			.item_type = STAT_DATA_ITEM_TYPE,
+			.max_key_inside = max_key_inside_single_key,
+			.can_contain_key = NULL,
+			.mergeable = not_mergeable,
+			.nr_units = nr_units_single_unit,
+			.lookup = NULL,
+			.init = NULL,
+			.paste = paste_no_paste,
+			.fast_paste = NULL,
+			.can_shift = NULL,
+			.copy_units = NULL,
+			.create_hook = NULL,
+			.kill_hook = NULL,
+			.shift_hook = NULL,
+			.cut_units = NULL,
+			.kill_units = NULL,
+			.unit_key = NULL,
+			.max_unit_key = NULL,
+			.estimate = NULL,
+			.item_data_by_flow = NULL,
+#if REISER4_DEBUG
+			.check = NULL
+#endif
+		},
+		.f = {
+			.utmost_child = NULL,
+			.utmost_child_real_block = NULL,
+			.update = NULL,
+			.scan = NULL,
+			.convert = NULL
+		},
+		.s = {
+			.sd = {
+				.init_inode = init_inode_static_sd,
+				.save_len = save_len_static_sd,
+				.save = save_static_sd
+			}
+		}
+	},
+	[SIMPLE_DIR_ENTRY_ID] = {
+		.h = {
+			.type_id = REISER4_ITEM_PLUGIN_TYPE,
+			.id = SIMPLE_DIR_ENTRY_ID,
+			.pops = &item_plugin_ops,
+			.label = "de",
+			.desc = "directory entry",
+			.linkage = {NULL, NULL}
+		},
+		.b = {
+			.item_type = DIR_ENTRY_ITEM_TYPE,
+			.max_key_inside = max_key_inside_single_key,
+			.can_contain_key = NULL,
+			.mergeable = NULL,
+			.nr_units = nr_units_single_unit,
+			.lookup = NULL,
+			.init = NULL,
+			.paste = NULL,
+			.fast_paste = NULL,
+			.can_shift = NULL,
+			.copy_units = NULL,
+			.create_hook = NULL,
+			.kill_hook = NULL,
+			.shift_hook = NULL,
+			.cut_units = NULL,
+			.kill_units = NULL,
+			.unit_key = NULL,
+			.max_unit_key = NULL,
+			.estimate = NULL,
+			.item_data_by_flow = NULL,
+#if REISER4_DEBUG
+			.check = NULL
+#endif
+		},
+		.f = {
+			.utmost_child = NULL,
+			.utmost_child_real_block = NULL,
+			.update = NULL,
+			.scan = NULL,
+			.convert = NULL
+		},
+		.s = {
+			.dir = {
+				.extract_key = extract_key_de,
+				.update_key = update_key_de,
+				.extract_name = extract_name_de,
+				.extract_file_type = extract_file_type_de,
+				.add_entry = add_entry_de,
+				.rem_entry = rem_entry_de,
+				.max_name_len = max_name_len_de
+			}
+		}
+	},
+	[COMPOUND_DIR_ID] = {
+		.h = {
+			.type_id = REISER4_ITEM_PLUGIN_TYPE,
+			.id = COMPOUND_DIR_ID,
+			.pops = &item_plugin_ops,
+			.label = "cde",
+			.desc = "compressed directory entry",
+			.linkage = {NULL, NULL}
+		},
+		.b = {
+			.item_type = DIR_ENTRY_ITEM_TYPE,
+			.max_key_inside = max_key_inside_cde,
+			.can_contain_key = can_contain_key_cde,
+			.mergeable = mergeable_cde,
+			.nr_units = nr_units_cde,
+			.lookup = lookup_cde,
+			.init = init_cde,
+			.paste = paste_cde,
+			.fast_paste = agree_to_fast_op,
+			.can_shift = can_shift_cde,
+			.copy_units = copy_units_cde,
+			.create_hook = NULL,
+			.kill_hook = NULL,
+			.shift_hook = NULL,
+			.cut_units = cut_units_cde,
+			.kill_units = kill_units_cde,
+			.unit_key = unit_key_cde,
+			.max_unit_key = unit_key_cde,
+			.estimate = estimate_cde,
+			.item_data_by_flow = NULL,
+#if REISER4_DEBUG
+			.check = check_cde
+#endif
+		},
+		.f = {
+			.utmost_child = NULL,
+			.utmost_child_real_block = NULL,
+			.update = NULL,
+			.scan = NULL,
+			.convert = NULL
+		},
+		.s = {
+			.dir = {
+				.extract_key = extract_key_cde,
+				.update_key = update_key_cde,
+				.extract_name = extract_name_cde,
+				.extract_file_type = extract_file_type_de,
+				.add_entry = add_entry_cde,
+				.rem_entry = rem_entry_cde,
+				.max_name_len = max_name_len_cde
+			}
+		}
+	},
+	[NODE_POINTER_ID] = {
+		.h = {
+			.type_id = REISER4_ITEM_PLUGIN_TYPE,
+			.id = NODE_POINTER_ID,
+			.pops = NULL,
+			.label = "internal",
+			.desc = "internal item",
+			.linkage = {NULL, NULL}
+		},
+		.b = {
+			.item_type = INTERNAL_ITEM_TYPE,
+			.max_key_inside = NULL,
+			.can_contain_key = NULL,
+			.mergeable = mergeable_internal,
+			.nr_units = nr_units_single_unit,
+			.lookup = lookup_internal,
+			.init = NULL,
+			.paste = NULL,
+			.fast_paste = NULL,
+			.can_shift = NULL,
+			.copy_units = NULL,
+			.create_hook = create_hook_internal,
+			.kill_hook = kill_hook_internal,
+			.shift_hook = shift_hook_internal,
+			.cut_units = NULL,
+			.kill_units = NULL,
+			.unit_key = NULL,
+			.max_unit_key = NULL,
+			.estimate = NULL,
+			.item_data_by_flow = NULL,
+#if REISER4_DEBUG
+			.check = check__internal
+#endif
+		},
+		.f = {
+			.utmost_child = utmost_child_internal,
+			.utmost_child_real_block =
+			utmost_child_real_block_internal,
+			.update = update_internal,
+			.scan = NULL,
+			.convert = NULL
+		},
+		.s = {
+			.internal = {
+				.down_link = down_link_internal,
+				.has_pointer_to = has_pointer_to_internal
+			}
+		}
+	},
+	[EXTENT_POINTER_ID] = {
+		.h = {
+			.type_id = REISER4_ITEM_PLUGIN_TYPE,
+			.id = EXTENT_POINTER_ID,
+			.pops = NULL,
+			.label = "extent",
+			.desc = "extent item",
+			.linkage = {NULL, NULL}
+		},
+		.b = {
+			.item_type = UNIX_FILE_METADATA_ITEM_TYPE,
+			.max_key_inside = max_key_inside_extent,
+			.can_contain_key = can_contain_key_extent,
+			.mergeable = mergeable_extent,
+			.nr_units = nr_units_extent,
+			.lookup = lookup_extent,
+			.init = NULL,
+			.paste = paste_extent,
+			.fast_paste = agree_to_fast_op,
+			.can_shift = can_shift_extent,
+			.create_hook = create_hook_extent,
+			.copy_units = copy_units_extent,
+			.kill_hook = kill_hook_extent,
+			.shift_hook = NULL,
+			.cut_units = cut_units_extent,
+			.kill_units = kill_units_extent,
+			.unit_key = unit_key_extent,
+			.max_unit_key = max_unit_key_extent,
+			.estimate = NULL,
+			.item_data_by_flow = NULL,
+#if REISER4_DEBUG
+			.check = check_extent
+#endif
+		},
+		.f = {
+			.utmost_child = utmost_child_extent,
+			.utmost_child_real_block =
+			utmost_child_real_block_extent,
+			.update = NULL,
+			.scan = scan_extent,
+			.convert = NULL,
+			.key_by_offset = key_by_offset_extent
+		},
+		.s = {
+			.file = {
+				.write = write_extent,
+				.read = read_extent,
+				.readpage = readpage_extent,
+				.capture = capture_extent,
+				.get_block = get_block_address_extent,
+				.readpages = readpages_extent,
+				.append_key = append_key_extent,
+				.init_coord_extension =
+				init_coord_extension_extent
+			}
+		}
+	},
+	[FORMATTING_ID] = {
+		.h = {
+			.type_id = REISER4_ITEM_PLUGIN_TYPE,
+			.id = FORMATTING_ID,
+			.pops = NULL,
+			.label = "body",
+			.desc = "body (or tail?) item",
+			.linkage = {NULL, NULL}
+		},
+		.b = {
+			.item_type = UNIX_FILE_METADATA_ITEM_TYPE,
+			.max_key_inside = max_key_inside_tail,
+			.can_contain_key = can_contain_key_tail,
+			.mergeable = mergeable_tail,
+			.nr_units = nr_units_tail,
+			.lookup = lookup_tail,
+			.init = NULL,
+			.paste = paste_tail,
+			.fast_paste = agree_to_fast_op,
+			.can_shift = can_shift_tail,
+			.create_hook = NULL,
+			.copy_units = copy_units_tail,
+			.kill_hook = kill_hook_tail,
+			.shift_hook = NULL,
+			.cut_units = cut_units_tail,
+			.kill_units = kill_units_tail,
+			.unit_key = unit_key_tail,
+			.max_unit_key = unit_key_tail,
+			.estimate = NULL,
+			.item_data_by_flow = NULL,
+#if REISER4_DEBUG
+			.check = NULL
+#endif
+		},
+		.f = {
+			.utmost_child = NULL,
+			.utmost_child_real_block = NULL,
+			.update = NULL,
+			.scan = NULL,
+			.convert = NULL
+		},
+		.s = {
+			.file = {
+				.write = write_tail,
+				.read = read_tail,
+				.readpage = readpage_tail,
+				.capture = NULL,
+				.get_block = NULL,
+				.readpages = NULL,
+				.append_key = append_key_tail,
+				.init_coord_extension =
+				init_coord_extension_tail
+			}
+		}
+	},
+	[CTAIL_ID] = {
+		.h = {
+			.type_id = REISER4_ITEM_PLUGIN_TYPE,
+			.id = CTAIL_ID,
+			.pops = NULL,
+			.label = "ctail",
+			.desc = "cryptcompress tail item",
+			.linkage = {NULL, NULL}
+		},
+		.b = {
+			.item_type = UNIX_FILE_METADATA_ITEM_TYPE,
+			.max_key_inside = max_key_inside_tail,
+			.can_contain_key = can_contain_key_ctail,
+			.mergeable = mergeable_ctail,
+			.nr_units = nr_units_ctail,
+			.lookup = NULL,
+			.init = init_ctail,
+			.paste = paste_ctail,
+			.fast_paste = agree_to_fast_op,
+			.can_shift = can_shift_ctail,
+			.create_hook = create_hook_ctail,
+			.copy_units = copy_units_ctail,
+			.kill_hook = kill_hook_ctail,
+			.shift_hook = shift_hook_ctail,
+			.cut_units = cut_units_ctail,
+			.kill_units = kill_units_ctail,
+			.unit_key = unit_key_tail,
+			.max_unit_key = unit_key_tail,
+			.estimate = estimate_ctail,
+			.item_data_by_flow = NULL,
+#if REISER4_DEBUG
+			.check = check_ctail
+#endif
+		},
+		.f = {
+			.utmost_child = utmost_child_ctail,
+			/* FIXME-EDWARD: write this */
+			.utmost_child_real_block = NULL,
+			.update = NULL,
+			.scan = scan_ctail,
+			.convert = convert_ctail
+		},
+		.s = {
+			.file = {
+				.write = NULL,
+				.read = read_ctail,
+				.readpage = readpage_ctail,
+				.capture = NULL,
+				.get_block = get_block_address_tail,
+				.readpages = readpages_ctail,
+				.append_key = append_key_ctail,
+				.init_coord_extension =
+				init_coord_extension_tail
+			}
+		}
+	},
+	[BLACK_BOX_ID] = {
+		.h = {
+			.type_id = REISER4_ITEM_PLUGIN_TYPE,
+			.id = BLACK_BOX_ID,
+			.pops = NULL,
+			.label = "blackbox",
+			.desc = "black box item",
+			.linkage = {NULL, NULL}
+		},
+		.b = {
+			.item_type = OTHER_ITEM_TYPE,
+			.max_key_inside = NULL,
+			.can_contain_key = NULL,
+			.mergeable = not_mergeable,
+			.nr_units = nr_units_single_unit,
+			/* to need for ->lookup method */
+			.lookup = NULL,
+			.init = NULL,
+			.paste = NULL,
+			.fast_paste = NULL,
+			.can_shift = NULL,
+			.copy_units = NULL,
+			.create_hook = NULL,
+			.kill_hook = NULL,
+			.shift_hook = NULL,
+			.cut_units = NULL,
+			.kill_units = NULL,
+			.unit_key = NULL,
+			.max_unit_key = NULL,
+			.estimate = NULL,
+			.item_data_by_flow = NULL,
+#if REISER4_DEBUG
+			.check = NULL
+#endif
+		}
+	}
+};
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/item/item.h newtree/fs/reiser4/plugin/item/item.h
--- oldtree/fs/reiser4/plugin/item/item.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/item.h	2006-02-21 15:58:34.852848120 +0000
@@ -0,0 +1,400 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* first read balance.c comments before reading this */
+
+/* An item_plugin implements all of the operations required for
+   balancing that are item specific. */
+
+/* an item plugin also implements other operations that are specific to that
+   item.  These go into the item specific operations portion of the item
+   handler, and all of the item specific portions of the item handler are put
+   into a union. */
+
+#if !defined( __REISER4_ITEM_H__ )
+#define __REISER4_ITEM_H__
+
+#include "../../forward.h"
+#include "../plugin_header.h"
+#include "../../dformat.h"
+#include "../../seal.h"
+#include "../../plugin/file/file.h"
+
+#include <linux/fs.h>		/* for struct file, struct inode  */
+#include <linux/mm.h>		/* for struct page */
+#include <linux/dcache.h>	/* for struct dentry */
+
+typedef enum {
+	STAT_DATA_ITEM_TYPE,
+	DIR_ENTRY_ITEM_TYPE,
+	INTERNAL_ITEM_TYPE,
+	UNIX_FILE_METADATA_ITEM_TYPE,
+	OTHER_ITEM_TYPE
+} item_type_id;
+
+/* this is the part of each item plugin that all items are expected to
+   support or at least explicitly fail to support by setting the
+   pointer to null. */
+typedef struct {
+	item_type_id item_type;
+
+	/* operations called by balancing
+
+	   It is interesting to consider that some of these item
+	   operations could be given sources or targets that are not
+	   really items in nodes.  This could be ok/useful.
+
+	 */
+	/* maximal key that can _possibly_ be occupied by this item
+
+	   When inserting, and node ->lookup() method (called by
+	   coord_by_key()) reaches an item after binary search,
+	   the  ->max_key_inside() item plugin method is used to determine
+	   whether new item should pasted into existing item
+	   (new_key<=max_key_inside()) or new item has to be created
+	   (new_key>max_key_inside()).
+
+	   For items that occupy exactly one key (like stat-data)
+	   this method should return this key. For items that can
+	   grow indefinitely (extent, directory item) this should
+	   return max_key().
+
+	   For example extent with the key
+
+	   (LOCALITY,4,OBJID,STARTING-OFFSET), and length BLK blocks,
+
+	   ->max_key_inside is (LOCALITY,4,OBJID,0xffffffffffffffff), and
+	 */
+	reiser4_key *(*max_key_inside) (const coord_t *, reiser4_key *);
+
+	/* true if item @coord can merge data at @key. */
+	int (*can_contain_key) (const coord_t *, const reiser4_key *,
+				const reiser4_item_data *);
+	/* mergeable() - check items for mergeability
+
+	   Optional method. Returns true if two items can be merged.
+
+	 */
+	int (*mergeable) (const coord_t *, const coord_t *);
+
+	/* number of atomic things in an item */
+	 pos_in_node_t(*nr_units) (const coord_t *);
+
+	/* search within item for a unit within the item, and return a
+	   pointer to it.  This can be used to calculate how many
+	   bytes to shrink an item if you use pointer arithmetic and
+	   compare to the start of the item body if the item's data
+	   are continuous in the node, if the item's data are not
+	   continuous in the node, all sorts of other things are maybe
+	   going to break as well. */
+	 lookup_result(*lookup) (const reiser4_key *, lookup_bias, coord_t *);
+	/* method called by ode_plugin->create_item() to initialise new
+	   item */
+	int (*init) (coord_t * target, coord_t * from,
+		     reiser4_item_data * data);
+	/* method called (e.g., by resize_item()) to place new data into
+	   item when it grows */
+	int (*paste) (coord_t *, reiser4_item_data *, carry_plugin_info *);
+	/* return true if paste into @coord is allowed to skip
+	   carry. That is, if such paste would require any changes
+	   at the parent level
+	 */
+	int (*fast_paste) (const coord_t *);
+	/* how many but not more than @want units of @source can be
+	   shifted into @target node. If pend == append - we try to
+	   append last item of @target by first units of @source. If
+	   pend == prepend - we try to "prepend" first item in @target
+	   by last units of @source. @target node has @free_space
+	   bytes of free space. Total size of those units are returned
+	   via @size.
+
+	   @target is not NULL if shifting to the mergeable item and
+	   NULL is new item will be created during shifting.
+	 */
+	int (*can_shift) (unsigned free_space, coord_t *,
+			  znode *, shift_direction, unsigned *size,
+			  unsigned want);
+
+	/* starting off @from-th unit of item @source append or
+	   prepend @count units to @target. @target has been already
+	   expanded by @free_space bytes. That must be exactly what is
+	   needed for those items in @target. If @where_is_free_space
+	   == SHIFT_LEFT - free space is at the end of @target item,
+	   othersize - it is in the beginning of it. */
+	void (*copy_units) (coord_t *, coord_t *,
+			    unsigned from, unsigned count,
+			    shift_direction where_is_free_space,
+			    unsigned free_space);
+
+	int (*create_hook) (const coord_t *, void *);
+	/* do whatever is necessary to do when @count units starting
+	   from @from-th one are removed from the tree */
+	/* FIXME-VS: this is used to be here for, in particular,
+	   extents and items of internal type to free blocks they point
+	   to at the same time with removing items from a
+	   tree. Problems start, however, when dealloc_block fails due
+	   to some reason. Item gets removed, but blocks it pointed to
+	   are not freed. It is not clear how to fix this for items of
+	   internal type because a need to remove internal item may
+	   appear in the middle of balancing, and there is no way to
+	   undo changes made. OTOH, if space allocator involves
+	   balancing to perform dealloc_block - this will probably
+	   break balancing due to deadlock issues
+	 */
+	int (*kill_hook) (const coord_t *, pos_in_node_t from,
+			  pos_in_node_t count, struct carry_kill_data *);
+	int (*shift_hook) (const coord_t *, unsigned from, unsigned count,
+			   znode * _node);
+
+	/* unit @*from contains @from_key. unit @*to contains @to_key. Cut all keys between @from_key and @to_key
+	   including boundaries. When units are cut from item beginning - move space which gets freed to head of
+	   item. When units are cut from item end - move freed space to item end. When units are cut from the middle of
+	   item - move freed space to item head. Return amount of space which got freed. Save smallest removed key in
+	   @smallest_removed if it is not 0. Save new first item key in @new_first_key if it is not 0
+	 */
+	int (*cut_units) (coord_t *, pos_in_node_t from, pos_in_node_t to,
+			  struct carry_cut_data *,
+			  reiser4_key * smallest_removed,
+			  reiser4_key * new_first_key);
+
+	/* like cut_units, except that these units are removed from the
+	   tree, not only from a node */
+	int (*kill_units) (coord_t *, pos_in_node_t from, pos_in_node_t to,
+			   struct carry_kill_data *,
+			   reiser4_key * smallest_removed,
+			   reiser4_key * new_first);
+
+	/* if @key_of_coord == 1 - returned key of coord, otherwise -
+	   key of unit is returned. If @coord is not set to certain
+	   unit - ERR_PTR(-ENOENT) is returned */
+	reiser4_key *(*unit_key) (const coord_t *, reiser4_key *);
+	reiser4_key *(*max_unit_key) (const coord_t *, reiser4_key *);
+	/* estimate how much space is needed for paste @data into item at
+	   @coord. if @coord==0 - estimate insertion, otherwise - estimate
+	   pasting
+	 */
+	int (*estimate) (const coord_t *, const reiser4_item_data *);
+
+	/* converts flow @f to item data. @coord == 0 on insert */
+	int (*item_data_by_flow) (const coord_t *, const flow_t *,
+				  reiser4_item_data *);
+
+	/*void (*show) (struct seq_file *, coord_t *); */
+
+#if REISER4_DEBUG
+	/* used for debugging, every item should have here the most
+	   complete possible check of the consistency of the item that
+	   the inventor can construct */
+	int (*check) (const coord_t *, const char **error);
+#endif
+
+} balance_ops;
+
+typedef struct {
+	/* return the right or left child of @coord, only if it is in memory */
+	int (*utmost_child) (const coord_t *, sideof side, jnode ** child);
+
+	/* return whether the right or left child of @coord has a non-fake
+	   block number. */
+	int (*utmost_child_real_block) (const coord_t *, sideof side,
+					reiser4_block_nr *);
+	/* relocate child at @coord to the @block */
+	void (*update) (const coord_t *, const reiser4_block_nr *);
+	/* count unformatted nodes per item for leave relocation policy, etc.. */
+	int (*scan) (flush_scan * scan);
+	/* convert item by flush */
+	int (*convert) (flush_pos_t * pos);
+	/* backward mapping from jnode offset to a key.  */
+	int (*key_by_offset) (struct inode *, loff_t, reiser4_key *);
+} flush_ops;
+
+/* operations specific to the directory item */
+typedef struct {
+	/* extract stat-data key from directory entry at @coord and place it
+	   into @key. */
+	int (*extract_key) (const coord_t *, reiser4_key * key);
+	/* update object key in item. */
+	int (*update_key) (const coord_t *, const reiser4_key *, lock_handle *);
+	/* extract name from directory entry at @coord and return it */
+	char *(*extract_name) (const coord_t *, char *buf);
+	/* extract file type (DT_* stuff) from directory entry at @coord and
+	   return it */
+	unsigned (*extract_file_type) (const coord_t *);
+	int (*add_entry) (struct inode * dir,
+			  coord_t *, lock_handle *,
+			  const struct dentry * name,
+			  reiser4_dir_entry_desc * entry);
+	int (*rem_entry) (struct inode * dir, const struct qstr * name,
+			  coord_t *, lock_handle *,
+			  reiser4_dir_entry_desc * entry);
+	int (*max_name_len) (const struct inode * dir);
+} dir_entry_ops;
+
+/* operations specific to items regular (unix) file metadata are built of */
+typedef struct {
+	int (*write) (struct inode *, flow_t *, hint_t *, int grabbed,
+		      write_mode_t);
+	int (*read) (struct file *, flow_t *, hint_t *);
+	int (*readpage) (void *, struct page *);
+	int (*capture) (reiser4_key *, uf_coord_t *, struct page *,
+			write_mode_t);
+	int (*get_block) (const coord_t *, sector_t, sector_t *);
+	void (*readpages) (void *, struct address_space *,
+			   struct list_head * pages);
+	/* key of first byte which is not addressed by the item @coord is set to
+	   For example extent with the key
+
+	   (LOCALITY,4,OBJID,STARTING-OFFSET), and length BLK blocks,
+
+	   ->append_key is
+
+	   (LOCALITY,4,OBJID,STARTING-OFFSET + BLK * block_size) */
+	/* FIXME: could be uf_coord also */
+	reiser4_key *(*append_key) (const coord_t *, reiser4_key *);
+
+	void (*init_coord_extension) (uf_coord_t *, loff_t);
+} file_ops;
+
+/* operations specific to items of stat data type */
+typedef struct {
+	int (*init_inode) (struct inode * inode, char *sd, int len);
+	int (*save_len) (struct inode * inode);
+	int (*save) (struct inode * inode, char **area);
+} sd_ops;
+
+/* operations specific to internal item */
+typedef struct {
+	/* all tree traversal want to know from internal item is where
+	   to go next. */
+	void (*down_link) (const coord_t * coord,
+			   const reiser4_key * key, reiser4_block_nr * block);
+	/* check that given internal item contains given pointer. */
+	int (*has_pointer_to) (const coord_t * coord,
+			       const reiser4_block_nr * block);
+} internal_item_ops;
+
+struct item_plugin {
+	/* generic fields */
+	plugin_header h;
+
+	/* methods common for all item types */
+	balance_ops b;
+	/* methods used during flush */
+	flush_ops f;
+
+	/* methods specific to particular type of item */
+	union {
+		dir_entry_ops dir;
+		file_ops file;
+		sd_ops sd;
+		internal_item_ops internal;
+	} s;
+
+};
+
+static inline item_id item_id_by_plugin(item_plugin * plugin)
+{
+	return plugin->h.id;
+}
+
+static inline char get_iplugid(item_plugin * iplug)
+{
+	assert("nikita-2838", iplug != NULL);
+	assert("nikita-2839", iplug->h.id < 0xff);
+	return (char)item_id_by_plugin(iplug);
+}
+
+extern unsigned long znode_times_locked(const znode * z);
+
+static inline void coord_set_iplug(coord_t * coord, item_plugin * iplug)
+{
+	assert("nikita-2837", coord != NULL);
+	assert("nikita-2838", iplug != NULL);
+	coord->iplugid = get_iplugid(iplug);
+	ON_DEBUG(coord->plug_v = znode_times_locked(coord->node));
+}
+
+static inline item_plugin *coord_iplug(const coord_t * coord)
+{
+	assert("nikita-2833", coord != NULL);
+	assert("nikita-2834", coord->iplugid != INVALID_PLUGID);
+	assert("nikita-3549", coord->plug_v == znode_times_locked(coord->node));
+	return (item_plugin *) plugin_by_id(REISER4_ITEM_PLUGIN_TYPE,
+					    coord->iplugid);
+}
+
+extern int item_can_contain_key(const coord_t * item, const reiser4_key * key,
+				const reiser4_item_data *);
+extern int are_items_mergeable(const coord_t * i1, const coord_t * i2);
+extern int item_is_extent(const coord_t *);
+extern int item_is_tail(const coord_t *);
+extern int item_is_statdata(const coord_t * item);
+extern int item_is_ctail(const coord_t *);
+
+extern pos_in_node_t item_length_by_coord(const coord_t * coord);
+extern item_type_id item_type_by_coord(const coord_t * coord);
+extern item_id item_id_by_coord(const coord_t * coord /* coord to query */ );
+extern reiser4_key *item_key_by_coord(const coord_t * coord, reiser4_key * key);
+extern reiser4_key *max_item_key_by_coord(const coord_t *, reiser4_key *);
+extern reiser4_key *unit_key_by_coord(const coord_t * coord, reiser4_key * key);
+extern reiser4_key *max_unit_key_by_coord(const coord_t * coord,
+					  reiser4_key * key);
+
+extern void obtain_item_plugin(const coord_t * coord);
+
+#if defined(REISER4_DEBUG)
+extern int znode_is_loaded(const znode * node);
+#endif
+
+/* return plugin of item at @coord */
+static inline item_plugin *item_plugin_by_coord(const coord_t *
+						coord /* coord to query */ )
+{
+	assert("nikita-330", coord != NULL);
+	assert("nikita-331", coord->node != NULL);
+	assert("nikita-332", znode_is_loaded(coord->node));
+
+	if (unlikely(!coord_is_iplug_set(coord)))
+		obtain_item_plugin(coord);
+	return coord_iplug(coord);
+}
+
+/* this returns true if item is of internal type */
+static inline int item_is_internal(const coord_t * item)
+{
+	assert("vs-483", coord_is_existing_item(item));
+	return item_type_by_coord(item) == INTERNAL_ITEM_TYPE;
+}
+
+extern void item_body_by_coord_hard(coord_t * coord);
+extern void *item_body_by_coord_easy(const coord_t * coord);
+#if REISER4_DEBUG
+extern int item_body_is_valid(const coord_t * coord);
+#endif
+
+/* return pointer to item body */
+static inline void *item_body_by_coord(const coord_t *
+				       coord /* coord to query */ )
+{
+	assert("nikita-324", coord != NULL);
+	assert("nikita-325", coord->node != NULL);
+	assert("nikita-326", znode_is_loaded(coord->node));
+
+	if (coord->offset == INVALID_OFFSET)
+		item_body_by_coord_hard((coord_t *) coord);
+	assert("nikita-3201", item_body_is_valid(coord));
+	assert("nikita-3550", coord->body_v == znode_times_locked(coord->node));
+	return item_body_by_coord_easy(coord);
+}
+
+/* __REISER4_ITEM_H__ */
+#endif
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/item/sde.c newtree/fs/reiser4/plugin/item/sde.c
--- oldtree/fs/reiser4/plugin/item/sde.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/sde.c	2006-02-21 15:58:34.852848120 +0000
@@ -0,0 +1,190 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Directory entry implementation */
+#include "../../forward.h"
+#include "../../debug.h"
+#include "../../dformat.h"
+#include "../../kassign.h"
+#include "../../coord.h"
+#include "sde.h"
+#include "item.h"
+#include "../plugin.h"
+#include "../../znode.h"
+#include "../../carry.h"
+#include "../../tree.h"
+#include "../../inode.h"
+
+#include <linux/fs.h>		/* for struct inode */
+#include <linux/dcache.h>	/* for struct dentry */
+#include <linux/quotaops.h>
+
+/* ->extract_key() method of simple directory item plugin. */
+int extract_key_de(const coord_t * coord /* coord of item */ ,
+		   reiser4_key * key /* resulting key */ )
+{
+	directory_entry_format *dent;
+
+	assert("nikita-1458", coord != NULL);
+	assert("nikita-1459", key != NULL);
+
+	dent = (directory_entry_format *) item_body_by_coord(coord);
+	assert("nikita-1158", item_length_by_coord(coord) >= (int)sizeof *dent);
+	return extract_key_from_id(&dent->id, key);
+}
+
+int
+update_key_de(const coord_t * coord, const reiser4_key * key,
+	      lock_handle * lh UNUSED_ARG)
+{
+	directory_entry_format *dent;
+	obj_key_id obj_id;
+	int result;
+
+	assert("nikita-2342", coord != NULL);
+	assert("nikita-2343", key != NULL);
+
+	dent = (directory_entry_format *) item_body_by_coord(coord);
+	result = build_obj_key_id(key, &obj_id);
+	if (result == 0) {
+		dent->id = obj_id;
+		znode_make_dirty(coord->node);
+	}
+	return 0;
+}
+
+char *extract_dent_name(const coord_t * coord, directory_entry_format * dent,
+			char *buf)
+{
+	reiser4_key key;
+
+	unit_key_by_coord(coord, &key);
+	if (get_key_type(&key) != KEY_FILE_NAME_MINOR)
+		reiser4_print_address("oops", znode_get_block(coord->node));
+	if (!is_longname_key(&key)) {
+		if (is_dot_key(&key))
+			return (char *)".";
+		else
+			return extract_name_from_key(&key, buf);
+	} else
+		return (char *)dent->name;
+}
+
+/* ->extract_name() method of simple directory item plugin. */
+char *extract_name_de(const coord_t * coord /* coord of item */ , char *buf)
+{
+	directory_entry_format *dent;
+
+	assert("nikita-1460", coord != NULL);
+
+	dent = (directory_entry_format *) item_body_by_coord(coord);
+	return extract_dent_name(coord, dent, buf);
+}
+
+/* ->extract_file_type() method of simple directory item plugin. */
+unsigned extract_file_type_de(const coord_t * coord UNUSED_ARG	/* coord of
+								 * item */ )
+{
+	assert("nikita-1764", coord != NULL);
+	/* we don't store file type in the directory entry yet.
+
+	   But see comments at kassign.h:obj_key_id
+	 */
+	return DT_UNKNOWN;
+}
+
+int add_entry_de(struct inode *dir /* directory of item */ ,
+		 coord_t * coord /* coord of item */ ,
+		 lock_handle * lh /* insertion lock handle */ ,
+		 const struct dentry *de /* name to add */ ,
+		 reiser4_dir_entry_desc * entry	/* parameters of new directory
+						 * entry */ )
+{
+	reiser4_item_data data;
+	directory_entry_format *dent;
+	int result;
+	const char *name;
+	int len;
+	int longname;
+
+	name = de->d_name.name;
+	len = de->d_name.len;
+	assert("nikita-1163", strlen(name) == len);
+
+	longname = is_longname(name, len);
+
+	data.length = sizeof *dent;
+	if (longname)
+		data.length += len + 1;
+	data.data = NULL;
+	data.user = 0;
+	data.iplug = item_plugin_by_id(SIMPLE_DIR_ENTRY_ID);
+
+	/* NOTE-NIKITA quota plugin */
+	if (DQUOT_ALLOC_SPACE_NODIRTY(dir, data.length))
+		return -EDQUOT;
+
+	result = insert_by_coord(coord, &data, &entry->key, lh, 0 /*flags */ );
+	if (result != 0)
+		return result;
+
+	dent = (directory_entry_format *) item_body_by_coord(coord);
+	build_inode_key_id(entry->obj, &dent->id);
+	if (longname) {
+		memcpy(dent->name, name, len);
+		put_unaligned(0, &dent->name[len]);
+	}
+	return 0;
+}
+
+int rem_entry_de(struct inode *dir /* directory of item */ ,
+		 const struct qstr *name UNUSED_ARG,
+		 coord_t * coord /* coord of item */ ,
+		 lock_handle * lh UNUSED_ARG	/* lock handle for
+						 * removal */ ,
+		 reiser4_dir_entry_desc * entry UNUSED_ARG	/* parameters of
+								 * directory entry
+								 * being removed */ )
+{
+	coord_t shadow;
+	int result;
+	int length;
+
+	length = item_length_by_coord(coord);
+	if (inode_get_bytes(dir) < length) {
+		warning("nikita-2627", "Dir is broke: %llu: %llu",
+			(unsigned long long)get_inode_oid(dir),
+			inode_get_bytes(dir));
+
+		return RETERR(-EIO);
+	}
+
+	/* cut_node() is supposed to take pointers to _different_
+	   coords, because it will modify them without respect to
+	   possible aliasing. To work around this, create temporary copy
+	   of @coord.
+	 */
+	coord_dup(&shadow, coord);
+	result =
+	    kill_node_content(coord, &shadow, NULL, NULL, NULL, NULL, NULL, 0);
+	if (result == 0) {
+		/* NOTE-NIKITA quota plugin */
+		DQUOT_FREE_SPACE_NODIRTY(dir, length);
+	}
+	return result;
+}
+
+int max_name_len_de(const struct inode *dir)
+{
+	return tree_by_inode(dir)->nplug->max_item_size() -
+	    sizeof(directory_entry_format) - 2;
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/item/sde.h newtree/fs/reiser4/plugin/item/sde.h
--- oldtree/fs/reiser4/plugin/item/sde.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/sde.h	2006-02-21 15:58:34.632881560 +0000
@@ -0,0 +1,66 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Directory entry. */
+
+#if !defined( __FS_REISER4_PLUGIN_DIRECTORY_ENTRY_H__ )
+#define __FS_REISER4_PLUGIN_DIRECTORY_ENTRY_H__
+
+#include "../../forward.h"
+#include "../../dformat.h"
+#include "../../kassign.h"
+#include "../../key.h"
+
+#include <linux/fs.h>
+#include <linux/dcache.h>	/* for struct dentry */
+
+typedef struct directory_entry_format {
+	/* key of object stat-data. It's not necessary to store whole
+	   key here, because it's always key of stat-data, so minor
+	   packing locality and offset can be omitted here. But this
+	   relies on particular key allocation scheme for stat-data, so,
+	   for extensibility sake, whole key can be stored here.
+
+	   We store key as array of bytes, because we don't want 8-byte
+	   alignment of dir entries.
+	 */
+	obj_key_id id;
+	/* file name. Null terminated string. */
+	d8 name[0];
+} directory_entry_format;
+
+void print_de(const char *prefix, coord_t * coord);
+int extract_key_de(const coord_t * coord, reiser4_key * key);
+int update_key_de(const coord_t * coord, const reiser4_key * key,
+		  lock_handle * lh);
+char *extract_name_de(const coord_t * coord, char *buf);
+unsigned extract_file_type_de(const coord_t * coord);
+int add_entry_de(struct inode *dir, coord_t * coord,
+		 lock_handle * lh, const struct dentry *name,
+		 reiser4_dir_entry_desc * entry);
+int rem_entry_de(struct inode *dir, const struct qstr *name, coord_t * coord,
+		 lock_handle * lh, reiser4_dir_entry_desc * entry);
+int max_name_len_de(const struct inode *dir);
+
+int de_rem_and_shrink(struct inode *dir, coord_t * coord, int length);
+
+char *extract_dent_name(const coord_t * coord,
+			directory_entry_format * dent, char *buf);
+
+#if REISER4_LARGE_KEY
+#define DE_NAME_BUF_LEN (24)
+#else
+#define DE_NAME_BUF_LEN (16)
+#endif
+
+/* __FS_REISER4_PLUGIN_DIRECTORY_ENTRY_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/item/static_stat.c newtree/fs/reiser4/plugin/item/static_stat.c
--- oldtree/fs/reiser4/plugin/item/static_stat.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/static_stat.c	2006-02-21 15:58:35.010824104 +0000
@@ -0,0 +1,1028 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* stat data manipulation. */
+
+#include "../../forward.h"
+#include "../../super.h"
+#include "../../vfs_ops.h"
+#include "../../inode.h"
+#include "../../debug.h"
+#include "../../dformat.h"
+#include "../object.h"
+#include "../plugin.h"
+#include "../plugin_header.h"
+#include "static_stat.h"
+#include "item.h"
+
+#include <linux/types.h>
+#include <linux/fs.h>
+
+/* see static_stat.h for explanation */
+
+/* helper function used while we are dumping/loading inode/plugin state
+    to/from the stat-data. */
+
+static void move_on(int *length /* space remaining in stat-data */ ,
+		    char **area /* current coord in stat data */ ,
+		    int size_of /* how many bytes to move forward */ )
+{
+	assert("nikita-615", length != NULL);
+	assert("nikita-616", area != NULL);
+
+	*length -= size_of;
+	*area += size_of;
+
+	assert("nikita-617", *length >= 0);
+}
+
+/* helper function used while loading inode/plugin state from stat-data.
+    Complain if there is less space in stat-data than was expected.
+    Can only happen on disk corruption. */
+static int not_enough_space(struct inode *inode /* object being processed */ ,
+			    const char *where /* error message */ )
+{
+	assert("nikita-618", inode != NULL);
+
+	warning("nikita-619", "Not enough space in %llu while loading %s",
+		(unsigned long long)get_inode_oid(inode), where);
+
+	return RETERR(-EINVAL);
+}
+
+/* helper function used while loading inode/plugin state from
+    stat-data. Call it if invalid plugin id was found. */
+static int unknown_plugin(reiser4_plugin_id id /* invalid id */ ,
+			  struct inode *inode /* object being processed */ )
+{
+	warning("nikita-620", "Unknown plugin %i in %llu",
+		id, (unsigned long long)get_inode_oid(inode));
+
+	return RETERR(-EINVAL);
+}
+
+/* this is installed as ->init_inode() method of
+    item_plugins[ STATIC_STAT_DATA_IT ] (fs/reiser4/plugin/item/item.c).
+    Copies data from on-disk stat-data format into inode.
+    Handles stat-data extensions. */
+/* was sd_load */
+int init_inode_static_sd(struct inode *inode /* object being processed */ ,
+			 char *sd /* stat-data body */ ,
+			 int len /* length of stat-data */ )
+{
+	int result;
+	int bit;
+	int chunk;
+	__u16 mask;
+	__u64 bigmask;
+	reiser4_stat_data_base *sd_base;
+	reiser4_inode *state;
+
+	assert("nikita-625", inode != NULL);
+	assert("nikita-626", sd != NULL);
+
+	result = 0;
+	sd_base = (reiser4_stat_data_base *) sd;
+	state = reiser4_inode_data(inode);
+	mask = le16_to_cpu(get_unaligned(&sd_base->extmask));
+	bigmask = mask;
+	inode_set_flag(inode, REISER4_SDLEN_KNOWN);
+
+	move_on(&len, &sd, sizeof *sd_base);
+	for (bit = 0, chunk = 0;
+	     mask != 0 || bit <= LAST_IMPORTANT_SD_EXTENSION;
+	     ++bit, mask >>= 1) {
+		if (((bit + 1) % 16) != 0) {
+			/* handle extension */
+			sd_ext_plugin *sdplug;
+
+			sdplug = sd_ext_plugin_by_id(bit);
+			if (sdplug == NULL) {
+				warning("nikita-627",
+					"No such extension %i in inode %llu",
+					bit,
+					(unsigned long long)
+					get_inode_oid(inode));
+
+				result = RETERR(-EINVAL);
+				break;
+			}
+			if (mask & 1) {
+				assert("nikita-628", sdplug->present);
+				/* alignment is not supported in node layout
+				   plugin yet.
+				   result = align( inode, &len, &sd,
+				   sdplug -> alignment );
+				   if( result != 0 )
+				   return result; */
+				result = sdplug->present(inode, &sd, &len);
+			} else if (sdplug->absent != NULL)
+				result = sdplug->absent(inode);
+			if (result)
+				break;
+			/* else, we are looking at the last bit in 16-bit
+			   portion of bitmask */
+		} else if (mask & 1) {
+			/* next portion of bitmask */
+			if (len < (int)sizeof(d16)) {
+				warning("nikita-629",
+					"No space for bitmap in inode %llu",
+					(unsigned long long)
+					get_inode_oid(inode));
+
+				result = RETERR(-EINVAL);
+				break;
+			}
+			mask = le16_to_cpu(get_unaligned((d16 *)sd));
+			bigmask <<= 16;
+			bigmask |= mask;
+			move_on(&len, &sd, sizeof(d16));
+			++chunk;
+			if (chunk == 3) {
+				if (!(mask & 0x8000)) {
+					/* clear last bit */
+					mask &= ~0x8000;
+					continue;
+				}
+				/* too much */
+				warning("nikita-630",
+					"Too many extensions in %llu",
+					(unsigned long long)
+					get_inode_oid(inode));
+
+				result = RETERR(-EINVAL);
+				break;
+			}
+		} else
+			/* bitmask exhausted */
+			break;
+	}
+	state->extmask = bigmask;
+	/* common initialisations */
+	inode->i_blksize = get_super_private(inode->i_sb)->optimal_io_size;
+	if (len - (sizeof(d16) * bit / 16) > 0) {
+		/* alignment in save_len_static_sd() is taken into account
+		   -edward */
+		warning("nikita-631", "unused space in inode %llu",
+			(unsigned long long)get_inode_oid(inode));
+	}
+
+	return result;
+}
+
+/* estimates size of stat-data required to store inode.
+    Installed as ->save_len() method of
+    item_plugins[ STATIC_STAT_DATA_IT ] (fs/reiser4/plugin/item/item.c). */
+/* was sd_len */
+int save_len_static_sd(struct inode *inode /* object being processed */ )
+{
+	unsigned int result;
+	__u64 mask;
+	int bit;
+
+	assert("nikita-632", inode != NULL);
+
+	result = sizeof(reiser4_stat_data_base);
+	mask = reiser4_inode_data(inode)->extmask;
+	for (bit = 0; mask != 0; ++bit, mask >>= 1) {
+		if (mask & 1) {
+			sd_ext_plugin *sdplug;
+
+			sdplug = sd_ext_plugin_by_id(bit);
+			assert("nikita-633", sdplug != NULL);
+			/* no aligment support
+			   result +=
+			   round_up( result, sdplug -> alignment ) - result; */
+			result += sdplug->save_len(inode);
+		}
+	}
+	result += sizeof(d16) * bit / 16;
+	return result;
+}
+
+/* saves inode into stat-data.
+    Installed as ->save() method of
+    item_plugins[ STATIC_STAT_DATA_IT ] (fs/reiser4/plugin/item/item.c). */
+/* was sd_save */
+int save_static_sd(struct inode *inode /* object being processed */ ,
+		   char **area /* where to save stat-data */ )
+{
+	int result;
+	__u64 emask;
+	int bit;
+	unsigned int len;
+	reiser4_stat_data_base *sd_base;
+
+	assert("nikita-634", inode != NULL);
+	assert("nikita-635", area != NULL);
+
+	result = 0;
+	emask = reiser4_inode_data(inode)->extmask;
+	sd_base = (reiser4_stat_data_base *) * area;
+	put_unaligned(cpu_to_le16((__u16)(emask & 0xffff)), &sd_base->extmask);
+	/*cputod16((unsigned)(emask & 0xffff), &sd_base->extmask);*/
+
+	*area += sizeof *sd_base;
+	len = 0xffffffffu;
+	for (bit = 0; emask != 0; ++bit, emask >>= 1) {
+		if (emask & 1) {
+			if ((bit + 1) % 16 != 0) {
+				sd_ext_plugin *sdplug;
+				sdplug = sd_ext_plugin_by_id(bit);
+				assert("nikita-636", sdplug != NULL);
+				/* no alignment support yet
+				   align( inode, &len, area,
+				   sdplug -> alignment ); */
+				result = sdplug->save(inode, area);
+				if (result)
+					break;
+			} else {
+				put_unaligned(cpu_to_le16((__u16)(emask & 0xffff)),
+					      (d16 *)(*area));
+				/*cputod16((unsigned)(emask & 0xffff),
+				  (d16 *) * area);*/
+				*area += sizeof(d16);
+			}
+		}
+	}
+	return result;
+}
+
+/* stat-data extension handling functions. */
+
+static int present_lw_sd(struct inode *inode /* object being processed */ ,
+			 char **area /* position in stat-data */ ,
+			 int *len /* remaining length */ )
+{
+	if (*len >= (int)sizeof(reiser4_light_weight_stat)) {
+		reiser4_light_weight_stat *sd_lw;
+
+		sd_lw = (reiser4_light_weight_stat *) * area;
+
+		inode->i_mode = le16_to_cpu(get_unaligned(&sd_lw->mode));
+		inode->i_nlink = le32_to_cpu(get_unaligned(&sd_lw->nlink));
+		inode->i_size = le64_to_cpu(get_unaligned(&sd_lw->size));
+		if ((inode->i_mode & S_IFMT) == (S_IFREG | S_IFIFO)) {
+			inode->i_mode &= ~S_IFIFO;
+			inode_set_flag(inode, REISER4_PART_CONV);
+		}
+		move_on(len, area, sizeof *sd_lw);
+		return 0;
+	} else
+		return not_enough_space(inode, "lw sd");
+}
+
+static int save_len_lw_sd(struct inode *inode UNUSED_ARG	/* object being
+								 * processed */ )
+{
+	return sizeof(reiser4_light_weight_stat);
+}
+
+static int save_lw_sd(struct inode *inode /* object being processed */ ,
+		      char **area /* position in stat-data */ )
+{
+	reiser4_light_weight_stat *sd;
+	mode_t delta;
+
+	assert("nikita-2705", inode != NULL);
+	assert("nikita-2706", area != NULL);
+	assert("nikita-2707", *area != NULL);
+
+	sd = (reiser4_light_weight_stat *) * area;
+
+	delta = inode_get_flag(inode, REISER4_PART_CONV) ? S_IFIFO : 0;
+	put_unaligned(cpu_to_le16(inode->i_mode | delta), &sd->mode);
+	put_unaligned(cpu_to_le32(inode->i_nlink), &sd->nlink);
+	put_unaligned(cpu_to_le64((__u64) inode->i_size), &sd->size);
+	*area += sizeof *sd;
+	return 0;
+}
+
+static int present_unix_sd(struct inode *inode /* object being processed */ ,
+			   char **area /* position in stat-data */ ,
+			   int *len /* remaining length */ )
+{
+	assert("nikita-637", inode != NULL);
+	assert("nikita-638", area != NULL);
+	assert("nikita-639", *area != NULL);
+	assert("nikita-640", len != NULL);
+	assert("nikita-641", *len > 0);
+
+	if (*len >= (int)sizeof(reiser4_unix_stat)) {
+		reiser4_unix_stat *sd;
+
+		sd = (reiser4_unix_stat *) * area;
+
+		inode->i_uid = le32_to_cpu(get_unaligned(&sd->uid));
+		inode->i_gid = le32_to_cpu(get_unaligned(&sd->gid));
+		inode->i_atime.tv_sec = le32_to_cpu(get_unaligned(&sd->atime));
+		inode->i_mtime.tv_sec = le32_to_cpu(get_unaligned(&sd->mtime));
+		inode->i_ctime.tv_sec = le32_to_cpu(get_unaligned(&sd->ctime));
+		if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode))
+			inode->i_rdev = le64_to_cpu(get_unaligned(&sd->u.rdev));
+		else
+			inode_set_bytes(inode, (loff_t) le64_to_cpu(get_unaligned(&sd->u.bytes)));
+		move_on(len, area, sizeof *sd);
+		return 0;
+	} else
+		return not_enough_space(inode, "unix sd");
+}
+
+static int absent_unix_sd(struct inode *inode /* object being processed */ )
+{
+	inode->i_uid = get_super_private(inode->i_sb)->default_uid;
+	inode->i_gid = get_super_private(inode->i_sb)->default_gid;
+	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	inode_set_bytes(inode, inode->i_size);
+	/* mark inode as lightweight, so that caller (reiser4_lookup) will
+	   complete initialisation by copying [ug]id from a parent. */
+	inode_set_flag(inode, REISER4_LIGHT_WEIGHT);
+	return 0;
+}
+
+/* Audited by: green(2002.06.14) */
+static int save_len_unix_sd(struct inode *inode UNUSED_ARG	/* object being
+								 * processed */ )
+{
+	return sizeof(reiser4_unix_stat);
+}
+
+static int save_unix_sd(struct inode *inode /* object being processed */ ,
+			char **area /* position in stat-data */ )
+{
+	reiser4_unix_stat *sd;
+
+	assert("nikita-642", inode != NULL);
+	assert("nikita-643", area != NULL);
+	assert("nikita-644", *area != NULL);
+
+	sd = (reiser4_unix_stat *) * area;
+	put_unaligned(cpu_to_le32(inode->i_uid), &sd->uid);
+	put_unaligned(cpu_to_le32(inode->i_gid), &sd->gid);
+	put_unaligned(cpu_to_le32((__u32) inode->i_atime.tv_sec), &sd->atime);
+	put_unaligned(cpu_to_le32((__u32) inode->i_ctime.tv_sec), &sd->ctime);
+	put_unaligned(cpu_to_le32((__u32) inode->i_mtime.tv_sec), &sd->mtime);
+	if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode))
+		put_unaligned(cpu_to_le64(inode->i_rdev), &sd->u.rdev);
+	else
+		put_unaligned(cpu_to_le64((__u64) inode_get_bytes(inode)), &sd->u.bytes);
+	*area += sizeof *sd;
+	return 0;
+}
+
+static int
+present_large_times_sd(struct inode *inode /* object being processed */ ,
+		       char **area /* position in stat-data */ ,
+		       int *len /* remaining length */ )
+{
+	if (*len >= (int)sizeof(reiser4_large_times_stat)) {
+		reiser4_large_times_stat *sd_lt;
+
+		sd_lt = (reiser4_large_times_stat *) * area;
+
+		inode->i_atime.tv_nsec = le32_to_cpu(get_unaligned(&sd_lt->atime));
+		inode->i_mtime.tv_nsec = le32_to_cpu(get_unaligned(&sd_lt->mtime));
+		inode->i_ctime.tv_nsec = le32_to_cpu(get_unaligned(&sd_lt->ctime));
+
+		move_on(len, area, sizeof *sd_lt);
+		return 0;
+	} else
+		return not_enough_space(inode, "large times sd");
+}
+
+static int
+save_len_large_times_sd(struct inode *inode UNUSED_ARG
+			/* object being processed */ )
+{
+	return sizeof(reiser4_large_times_stat);
+}
+
+static int
+save_large_times_sd(struct inode *inode /* object being processed */ ,
+		    char **area /* position in stat-data */ )
+{
+	reiser4_large_times_stat *sd;
+
+	assert("nikita-2817", inode != NULL);
+	assert("nikita-2818", area != NULL);
+	assert("nikita-2819", *area != NULL);
+
+	sd = (reiser4_large_times_stat *) * area;
+
+	put_unaligned(cpu_to_le32((__u32) inode->i_atime.tv_nsec), &sd->atime);
+	put_unaligned(cpu_to_le32((__u32) inode->i_ctime.tv_nsec), &sd->ctime);
+	put_unaligned(cpu_to_le32((__u32) inode->i_mtime.tv_nsec), &sd->mtime);
+
+	*area += sizeof *sd;
+	return 0;
+}
+
+/* symlink stat data extension */
+
+/* allocate memory for symlink target and attach it to inode->u.generic_ip */
+static int
+symlink_target_to_inode(struct inode *inode, const char *target, int len)
+{
+	assert("vs-845", inode->u.generic_ip == NULL);
+	assert("vs-846", !inode_get_flag(inode, REISER4_GENERIC_PTR_USED));
+
+	/* FIXME-VS: this is prone to deadlock. Not more than other similar
+	   places, though */
+	inode->u.generic_ip = kmalloc((size_t) len + 1, GFP_KERNEL);
+	if (!inode->u.generic_ip)
+		return RETERR(-ENOMEM);
+
+	memcpy((char *)(inode->u.generic_ip), target, (size_t) len);
+	((char *)(inode->u.generic_ip))[len] = 0;
+	inode_set_flag(inode, REISER4_GENERIC_PTR_USED);
+	return 0;
+}
+
+/* this is called on read_inode. There is nothing to do actually, but some
+   sanity checks */
+static int present_symlink_sd(struct inode *inode, char **area, int *len)
+{
+	int result;
+	int length;
+	reiser4_symlink_stat *sd;
+
+	length = (int)inode->i_size;
+	/*
+	 * *len is number of bytes in stat data item from *area to the end of
+	 * item. It must be not less than size of symlink + 1 for ending 0
+	 */
+	if (length > *len)
+		return not_enough_space(inode, "symlink");
+
+	if (*(*area + length) != 0) {
+		warning("vs-840", "Symlink is not zero terminated");
+		return RETERR(-EIO);
+	}
+
+	sd = (reiser4_symlink_stat *) * area;
+	result = symlink_target_to_inode(inode, sd->body, length);
+
+	move_on(len, area, length + 1);
+	return result;
+}
+
+static int save_len_symlink_sd(struct inode *inode)
+{
+	return inode->i_size + 1;
+}
+
+/* this is called on create and update stat data. Do nothing on update but
+   update @area */
+static int save_symlink_sd(struct inode *inode, char **area)
+{
+	int result;
+	int length;
+	reiser4_symlink_stat *sd;
+
+	length = (int)inode->i_size;
+	/* inode->i_size must be set already */
+	assert("vs-841", length);
+
+	result = 0;
+	sd = (reiser4_symlink_stat *) * area;
+	if (!inode_get_flag(inode, REISER4_GENERIC_PTR_USED)) {
+		const char *target;
+
+		target = (const char *)(inode->u.generic_ip);
+		inode->u.generic_ip = NULL;
+
+		result = symlink_target_to_inode(inode, target, length);
+
+		/* copy symlink to stat data */
+		memcpy(sd->body, target, (size_t) length);
+		(*area)[length] = 0;
+	} else {
+		/* there is nothing to do in update but move area */
+		assert("vs-844",
+		       !memcmp(inode->u.generic_ip, sd->body,
+			       (size_t) length + 1));
+	}
+
+	*area += (length + 1);
+	return result;
+}
+
+static int present_flags_sd(struct inode *inode /* object being processed */ ,
+			    char **area /* position in stat-data */ ,
+			    int *len /* remaining length */ )
+{
+	assert("nikita-645", inode != NULL);
+	assert("nikita-646", area != NULL);
+	assert("nikita-647", *area != NULL);
+	assert("nikita-648", len != NULL);
+	assert("nikita-649", *len > 0);
+
+	if (*len >= (int)sizeof(reiser4_flags_stat)) {
+		reiser4_flags_stat *sd;
+
+		sd = (reiser4_flags_stat *) * area;
+		inode->i_flags = le32_to_cpu(get_unaligned(&sd->flags));
+		move_on(len, area, sizeof *sd);
+		return 0;
+	} else
+		return not_enough_space(inode, "generation and attrs");
+}
+
+/* Audited by: green(2002.06.14) */
+static int save_len_flags_sd(struct inode *inode UNUSED_ARG	/* object being
+								 * processed */ )
+{
+	return sizeof(reiser4_flags_stat);
+}
+
+static int save_flags_sd(struct inode *inode /* object being processed */ ,
+			 char **area /* position in stat-data */ )
+{
+	reiser4_flags_stat *sd;
+
+	assert("nikita-650", inode != NULL);
+	assert("nikita-651", area != NULL);
+	assert("nikita-652", *area != NULL);
+
+	sd = (reiser4_flags_stat *) * area;
+	put_unaligned(cpu_to_le32(inode->i_flags), &sd->flags);
+	*area += sizeof *sd;
+	return 0;
+}
+
+static int absent_plugin_sd(struct inode *inode);
+static int present_plugin_sd(struct inode *inode /* object being processed */ ,
+			     char **area /* position in stat-data */ ,
+			     int *len /* remaining length */ )
+{
+	reiser4_plugin_stat *sd;
+	reiser4_plugin *plugin;
+	int i;
+	__u16 mask;
+	int result;
+	int num_of_plugins;
+
+	assert("nikita-653", inode != NULL);
+	assert("nikita-654", area != NULL);
+	assert("nikita-655", *area != NULL);
+	assert("nikita-656", len != NULL);
+	assert("nikita-657", *len > 0);
+
+	if (*len < (int)sizeof(reiser4_plugin_stat))
+		return not_enough_space(inode, "plugin");
+
+	sd = (reiser4_plugin_stat *) * area;
+
+	mask = 0;
+	num_of_plugins = le16_to_cpu(get_unaligned(&sd->plugins_no));
+	move_on(len, area, sizeof *sd);
+	result = 0;
+	for (i = 0; i < num_of_plugins; ++i) {
+		reiser4_plugin_slot *slot;
+		reiser4_plugin_type type;
+		pset_member memb;
+
+		slot = (reiser4_plugin_slot *) * area;
+		if (*len < (int)sizeof *slot)
+			return not_enough_space(inode, "additional plugin");
+
+		memb = le16_to_cpu(get_unaligned(&slot->pset_memb));
+		type = pset_member_to_type_unsafe(memb);
+		if (type == REISER4_PLUGIN_TYPES) {
+			warning("nikita-3502",
+				"wrong pset member (%i) for %llu", memb,
+				(unsigned long long)get_inode_oid(inode));
+			return RETERR(-EINVAL);
+		}
+		plugin = plugin_by_disk_id(tree_by_inode(inode),
+					   type, &slot->id);
+		if (plugin == NULL)
+			return unknown_plugin(le16_to_cpu(get_unaligned(&slot->id)), inode);
+
+		/* plugin is loaded into inode, mark this into inode's
+		   bitmask of loaded non-standard plugins */
+		if (!(mask & (1 << memb))) {
+			mask |= (1 << memb);
+		} else {
+			warning("nikita-658", "duplicate plugin for %llu",
+				(unsigned long long)get_inode_oid(inode));
+			return RETERR(-EINVAL);
+		}
+		move_on(len, area, sizeof *slot);
+		/* load plugin data, if any */
+		if (plugin->h.pops != NULL && plugin->h.pops->load) {
+			result = plugin->h.pops->load(inode, plugin, area, len);
+			if (result != 0)
+				return result;
+		} else
+			result = grab_plugin_from(inode, memb, plugin);
+	}
+	/* if object plugin wasn't loaded from stat-data, guess it by
+	   mode bits */
+	plugin = file_plugin_to_plugin(inode_file_plugin(inode));
+	if (plugin == NULL)
+		result = absent_plugin_sd(inode);
+
+	reiser4_inode_data(inode)->plugin_mask = mask;
+	return result;
+}
+
+/* Determine object plugin for @inode based on i_mode.
+
+   Many objects in reiser4 file system are controlled by standard object
+   plugins that emulate traditional unix objects: unix file, directory, symlink, fifo, and so on.
+
+   For such files we don't explicitly store plugin id in object stat
+   data. Rather required plugin is guessed from mode bits, where file "type"
+   is encoded (see stat(2)).
+*/
+static int
+guess_plugin_by_mode(struct inode *inode /* object to guess plugins for */ )
+{
+	int fplug_id;
+	int dplug_id;
+	reiser4_inode *info;
+
+	assert("nikita-736", inode != NULL);
+
+	dplug_id = fplug_id = -1;
+
+	switch (inode->i_mode & S_IFMT) {
+	case S_IFSOCK:
+	case S_IFBLK:
+	case S_IFCHR:
+	case S_IFIFO:
+		fplug_id = SPECIAL_FILE_PLUGIN_ID;
+		break;
+	case S_IFLNK:
+		fplug_id = SYMLINK_FILE_PLUGIN_ID;
+		break;
+	case S_IFDIR:
+		fplug_id = DIRECTORY_FILE_PLUGIN_ID;
+		dplug_id = HASHED_DIR_PLUGIN_ID;
+		break;
+	default:
+		warning("nikita-737", "wrong file mode: %o", inode->i_mode);
+		return RETERR(-EIO);
+	case S_IFREG:
+		fplug_id = UNIX_FILE_PLUGIN_ID;
+		break;
+	}
+	info = reiser4_inode_data(inode);
+	plugin_set_file(&info->pset,
+			(fplug_id >= 0) ? file_plugin_by_id(fplug_id) : NULL);
+	plugin_set_dir(&info->pset,
+		       (dplug_id >= 0) ? dir_plugin_by_id(dplug_id) : NULL);
+	return 0;
+}
+
+/* Audited by: green(2002.06.14) */
+static int absent_plugin_sd(struct inode *inode /* object being processed */ )
+{
+	int result;
+
+	assert("nikita-659", inode != NULL);
+
+	result = guess_plugin_by_mode(inode);
+	/* if mode was wrong, guess_plugin_by_mode() returns "regular file",
+	   but setup_inode_ops() will call make_bad_inode().
+	   Another, more logical but bit more complex solution is to add
+	   "bad-file plugin". */
+	/* FIXME-VS: activate was called here */
+	return result;
+}
+
+/* helper function for plugin_sd_save_len(): calculate how much space
+    required to save state of given plugin */
+/* Audited by: green(2002.06.14) */
+static int len_for(reiser4_plugin * plugin /* plugin to save */ ,
+		   struct inode *inode /* object being processed */ ,
+		   pset_member memb, int len)
+{
+	reiser4_inode *info;
+	assert("nikita-661", inode != NULL);
+
+	info = reiser4_inode_data(inode);
+	if (plugin != NULL && (info->plugin_mask & (1 << memb))) {
+		len += sizeof(reiser4_plugin_slot);
+		if (plugin->h.pops && plugin->h.pops->save_len != NULL) {
+			/* non-standard plugin, call method */
+			/* commented as it is incompatible with alignment
+			 * policy in save_plug() -edward */
+			/* len = round_up(len, plugin->h.pops->alignment); */
+			len += plugin->h.pops->save_len(inode, plugin);
+		}
+	}
+	return len;
+}
+
+/* calculate how much space is required to save state of all plugins,
+    associated with inode */
+static int save_len_plugin_sd(struct inode *inode /* object being processed */ )
+{
+	int len;
+	reiser4_inode *state;
+	pset_member memb;
+
+	assert("nikita-663", inode != NULL);
+
+	state = reiser4_inode_data(inode);
+	/* common case: no non-standard plugins */
+	if (state->plugin_mask == 0)
+		return 0;
+	len = sizeof(reiser4_plugin_stat);
+	for (memb = 0; memb < PSET_LAST; ++memb)
+		len = len_for(pset_get(state->pset, memb), inode, memb, len);
+	assert("nikita-664", len > (int)sizeof(reiser4_plugin_stat));
+	return len;
+}
+
+/* helper function for plugin_sd_save(): save plugin, associated with
+    inode. */
+static int save_plug(reiser4_plugin * plugin /* plugin to save */ ,
+		     struct inode *inode /* object being processed */ ,
+		     pset_member memb /* what element of pset is saved */ ,
+		     char **area /* position in stat-data */ ,
+		     int *count	/* incremented if plugin were actually
+				 * saved. */ )
+{
+	reiser4_plugin_slot *slot;
+	int fake_len;
+	int result;
+
+	assert("nikita-665", inode != NULL);
+	assert("nikita-666", area != NULL);
+	assert("nikita-667", *area != NULL);
+
+	if (plugin == NULL)
+		return 0;
+	if (!(reiser4_inode_data(inode)->plugin_mask & (1 << memb)))
+		return 0;
+	slot = (reiser4_plugin_slot *) * area;
+	put_unaligned(cpu_to_le16(memb), &slot->pset_memb);
+	put_unaligned(cpu_to_le16(plugin->h.id), &slot->id);
+	fake_len = (int)0xffff;
+	move_on(&fake_len, area, sizeof *slot);
+	++*count;
+	result = 0;
+	if (plugin->h.pops != NULL) {
+		if (plugin->h.pops->save != NULL)
+			result = plugin->h.pops->save(inode, plugin, area);
+	}
+	return result;
+}
+
+/* save state of all non-standard plugins associated with inode */
+static int save_plugin_sd(struct inode *inode /* object being processed */ ,
+			  char **area /* position in stat-data */ )
+{
+	int result = 0;
+	int num_of_plugins;
+	reiser4_plugin_stat *sd;
+	reiser4_inode *state;
+	int fake_len;
+	pset_member memb;
+
+	assert("nikita-669", inode != NULL);
+	assert("nikita-670", area != NULL);
+	assert("nikita-671", *area != NULL);
+
+	state = reiser4_inode_data(inode);
+	if (state->plugin_mask == 0)
+		return 0;
+	sd = (reiser4_plugin_stat *) * area;
+	fake_len = (int)0xffff;
+	move_on(&fake_len, area, sizeof *sd);
+
+	num_of_plugins = 0;
+	for (memb = 0; memb < PSET_LAST; ++memb) {
+		result = save_plug(pset_get(state->pset, memb),
+				   inode, memb, area, &num_of_plugins);
+		if (result != 0)
+			break;
+	}
+
+	put_unaligned(cpu_to_le16((__u16)num_of_plugins), &sd->plugins_no);
+	return result;
+}
+
+/* helper function for crypto_sd_present(), crypto_sd_save.
+   Allocates memory for crypto stat, keyid and attaches it to the inode */
+static int extract_crypto_stat (struct inode * inode,
+				reiser4_crypto_stat * sd)
+{
+	crypto_stat_t * info;
+	assert("edward-11", !inode_crypto_stat(inode));
+	assert("edward-1413",
+	       !inode_get_flag(inode, REISER4_CRYPTO_STAT_LOADED));
+	/* create and attach a crypto-stat without secret key loaded */
+	info = alloc_crypto_stat(inode);
+	if (IS_ERR(info))
+		return PTR_ERR(info);
+	info->keysize = le16_to_cpu(get_unaligned(&sd->keysize));
+	memcpy(info->keyid, sd->keyid, inode_digest_plugin(inode)->fipsize);
+	attach_crypto_stat(inode, info);
+	inode_set_flag(inode, REISER4_CRYPTO_STAT_LOADED);
+	return 0;
+}
+
+/* crypto stat-data extension */
+
+static int present_crypto_sd(struct inode *inode, char **area, int *len)
+{
+	int result;
+	reiser4_crypto_stat *sd;
+	digest_plugin *dplug = inode_digest_plugin(inode);
+
+	assert("edward-06", dplug != NULL);
+	assert("edward-684", dplug->fipsize);
+	assert("edward-07", area != NULL);
+	assert("edward-08", *area != NULL);
+	assert("edward-09", len != NULL);
+	assert("edward-10", *len > 0);
+
+	if (*len < (int)sizeof(reiser4_crypto_stat)) {
+		return not_enough_space(inode, "crypto-sd");
+	}
+	/* *len is number of bytes in stat data item from *area to the end of
+	   item. It must be not less than size of this extension */
+	assert("edward-75", sizeof(*sd) + dplug->fipsize <= *len);
+
+	sd = (reiser4_crypto_stat *) * area;
+	result = extract_crypto_stat(inode, sd);
+	move_on(len, area, sizeof(*sd) + dplug->fipsize);
+
+	return result;
+}
+
+static int save_len_crypto_sd(struct inode *inode)
+{
+	return sizeof(reiser4_crypto_stat) +
+		inode_digest_plugin(inode)->fipsize;
+}
+
+static int save_crypto_sd(struct inode *inode, char **area)
+{
+	int result = 0;
+	reiser4_crypto_stat *sd;
+	crypto_stat_t * info = inode_crypto_stat(inode);
+	digest_plugin *dplug = inode_digest_plugin(inode);
+
+	assert("edward-12", dplug != NULL);
+	assert("edward-13", area != NULL);
+	assert("edward-14", *area != NULL);
+	assert("edward-15", info != NULL);
+	assert("edward-1414", info->keyid != NULL);
+	assert("edward-1415", info->keysize != 0);
+	assert("edward-76", reiser4_inode_data(inode) != NULL);
+
+	if (!inode_get_flag(inode, REISER4_CRYPTO_STAT_LOADED)) {
+		/* file is just created */
+		sd = (reiser4_crypto_stat *) *area;
+		/* copy everything but private key to the disk stat-data */
+		put_unaligned(cpu_to_le16(info->keysize), &sd->keysize);
+		memcpy(sd->keyid, info->keyid, (size_t) dplug->fipsize);
+		inode_set_flag(inode, REISER4_CRYPTO_STAT_LOADED);
+	}
+	*area += (sizeof(*sd) + dplug->fipsize);
+	return result;
+}
+
+static int eio(struct inode *inode, char **area, int *len)
+{
+	return RETERR(-EIO);
+}
+
+sd_ext_plugin sd_ext_plugins[LAST_SD_EXTENSION] = {
+	[LIGHT_WEIGHT_STAT] = {
+		.h = {
+			.type_id = REISER4_SD_EXT_PLUGIN_TYPE,
+			.id = LIGHT_WEIGHT_STAT,
+			.pops = NULL,
+			.label = "light-weight sd",
+			.desc = "sd for light-weight files",
+			.linkage = {NULL,NULL}
+		},
+		.present = present_lw_sd,
+		.absent = NULL,
+		.save_len = save_len_lw_sd,
+		.save = save_lw_sd,
+		.alignment = 8
+	},
+	[UNIX_STAT] = {
+		.h = {
+			.type_id = REISER4_SD_EXT_PLUGIN_TYPE,
+			.id = UNIX_STAT,
+			.pops = NULL,
+			.label = "unix-sd",
+			.desc = "unix stat-data fields",
+			.linkage = {NULL,NULL}
+		},
+		.present = present_unix_sd,
+		.absent = absent_unix_sd,
+		.save_len = save_len_unix_sd,
+		.save = save_unix_sd,
+		.alignment = 8
+	},
+	[LARGE_TIMES_STAT] = {
+		.h = {
+			.type_id = REISER4_SD_EXT_PLUGIN_TYPE,
+			.id = LARGE_TIMES_STAT,
+			.pops = NULL,
+			.label = "64time-sd",
+			.desc = "nanosecond resolution for times",
+			.linkage = {NULL,NULL}
+		},
+		.present = present_large_times_sd,
+		.absent = NULL,
+		.save_len = save_len_large_times_sd,
+		.save = save_large_times_sd,
+		.alignment = 8
+	},
+	[SYMLINK_STAT] = {
+		/* stat data of symlink has this extension */
+		.h = {
+			.type_id = REISER4_SD_EXT_PLUGIN_TYPE,
+			.id = SYMLINK_STAT,
+			.pops = NULL,
+			.label = "symlink-sd",
+			.desc =
+			"stat data is appended with symlink name",
+			.linkage = {NULL,NULL}
+		},
+		.present = present_symlink_sd,
+		.absent = NULL,
+		.save_len = save_len_symlink_sd,
+		.save = save_symlink_sd,
+		.alignment = 8
+	},
+	[PLUGIN_STAT] = {
+		.h = {
+			.type_id = REISER4_SD_EXT_PLUGIN_TYPE,
+			.id = PLUGIN_STAT,
+			.pops = NULL,
+			.label = "plugin-sd",
+			.desc = "plugin stat-data fields",
+			.linkage = {NULL,NULL}
+		},
+		.present = present_plugin_sd,
+		.absent = absent_plugin_sd,
+		.save_len = save_len_plugin_sd,
+		.save = save_plugin_sd,
+		.alignment = 8
+	},
+	[FLAGS_STAT] = {
+		.h = {
+			.type_id = REISER4_SD_EXT_PLUGIN_TYPE,
+			.id = FLAGS_STAT,
+			.pops = NULL,
+			.label = "flags-sd",
+			.desc = "inode bit flags",
+			.linkage = {NULL, NULL}
+		},
+		.present = present_flags_sd,
+		.absent = NULL,
+		.save_len = save_len_flags_sd,
+		.save = save_flags_sd,
+		.alignment = 8
+	},
+	[CAPABILITIES_STAT] = {
+		.h = {
+			.type_id = REISER4_SD_EXT_PLUGIN_TYPE,
+			.id = CAPABILITIES_STAT,
+			.pops = NULL,
+			.label = "capabilities-sd",
+			.desc = "capabilities",
+			.linkage = {NULL, NULL}
+		},
+		.present = eio,
+		.absent = NULL,
+		.save_len = save_len_flags_sd,
+		.save = save_flags_sd,
+		.alignment = 8
+	},
+	[CRYPTO_STAT] = {
+		.h = {
+			.type_id = REISER4_SD_EXT_PLUGIN_TYPE,
+			.id = CRYPTO_STAT,
+			.pops = NULL,
+			.label = "crypto-sd",
+			.desc = "secret key size and id",
+			.linkage = {NULL, NULL}
+		},
+		.present = present_crypto_sd,
+		.absent = NULL,
+		.save_len = save_len_crypto_sd,
+		.save = save_crypto_sd,
+		.alignment = 8
+	}
+};
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/item/static_stat.h newtree/fs/reiser4/plugin/item/static_stat.h
--- oldtree/fs/reiser4/plugin/item/static_stat.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/static_stat.h	2006-02-21 15:58:34.853847968 +0000
@@ -0,0 +1,219 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* This describes the static_stat item, used to hold all information needed by the stat() syscall.
+
+In the case where each file has not less than the fields needed by the
+stat() syscall, it is more compact to store those fields in this
+struct.
+
+If this item does not exist, then all stats are dynamically resolved.
+At the moment, we either resolve all stats dynamically or all of them
+statically.  If you think this is not fully optimal, and the rest of
+reiser4 is working, then fix it...:-)
+
+*/
+
+#if !defined( __FS_REISER4_PLUGIN_ITEM_STATIC_STAT_H__ )
+#define __FS_REISER4_PLUGIN_ITEM_STATIC_STAT_H__
+
+#include "../../forward.h"
+#include "../../dformat.h"
+
+#include <linux/fs.h>		/* for struct inode */
+
+/* Stat data layout: goals and implementation.
+
+   We want to be able to have lightweight files which have complete flexibility in what semantic metadata is attached to
+   them, including not having semantic metadata attached to them.
+
+   There is one problem with doing that, which is that if in fact you have exactly the same metadata for most files you
+   want to store, then it takes more space to store that metadata in a dynamically sized structure than in a statically
+   sized structure because the statically sized structure knows without recording it what the names and lengths of the
+   attributes are.
+
+   This leads to a natural compromise, which is to special case those files which have simply the standard unix file
+   attributes, and only employ the full dynamic stat data mechanism for those files that differ from the standard unix
+   file in their use of file attributes.
+
+   Yet this compromise deserves to be compromised a little.
+
+   We accommodate the case where you have no more than the standard unix file attributes by using an "extension
+   bitmask": each bit in it indicates presence or absence of or particular stat data extension (see sd_ext_bits enum).
+
+   If the first bit of the extension bitmask bit is 0, we have light-weight file whose attributes are either inherited
+   from parent directory (as uid, gid) or initialised to some sane values.
+
+   To capitalize on existing code infrastructure, extensions are
+   implemented as plugins of type REISER4_SD_EXT_PLUGIN_TYPE.
+   Each stat-data extension plugin implements four methods:
+
+    ->present() called by sd_load() when this extension is found in stat-data
+    ->absent() called by sd_load() when this extension is not found in stat-data
+    ->save_len() called by sd_len() to calculate total length of stat-data
+    ->save() called by sd_save() to store extension data into stat-data
+
+    Implementation is in fs/reiser4/plugin/item/static_stat.c
+*/
+
+/* stat-data extension. Please order this by presumed frequency of use */
+typedef enum {
+	/* support for light-weight files */
+	LIGHT_WEIGHT_STAT,
+	/* data required to implement unix stat(2) call. Layout is in
+	   reiser4_unix_stat. If this is not present, file is light-weight */
+	UNIX_STAT,
+	/* this contains additional set of 32bit [anc]time fields to implement
+	   nanosecond resolution. Layout is in reiser4_large_times_stat. Usage
+	   if this extension is governed by 32bittimes mount option. */
+	LARGE_TIMES_STAT,
+	/* stat data has link name included */
+	SYMLINK_STAT,
+	/* if this is present, file is controlled by non-standard
+	   plugin (that is, plugin that cannot be deduced from file
+	   mode bits), for example, aggregation, interpolation etc. */
+	PLUGIN_STAT,
+	/* this extension contains persistent inode flags. These flags are
+	   single bits: immutable, append, only, etc. Layout is in
+	   reiser4_flags_stat. */
+	FLAGS_STAT,
+	/* this extension contains capabilities sets, associated with this
+	   file. Layout is in reiser4_capabilities_stat */
+	CAPABILITIES_STAT,
+	/* this extension contains size and public id of the secret key.
+	   Layout is in reiser4_crypto_stat */
+	CRYPTO_STAT,
+	LAST_SD_EXTENSION,
+	/*
+	 * init_inode_static_sd() iterates over extension mask until all
+	 * non-zero bits are processed. This means, that neither ->present(),
+	 * nor ->absent() methods will be called for stat-data extensions that
+	 * go after last present extension. But some basic extensions, we want
+	 * either ->absent() or ->present() method to be called, because these
+	 * extensions set up something in inode even when they are not
+	 * present. This is what LAST_IMPORTANT_SD_EXTENSION is for: for all
+	 * extensions before and including LAST_IMPORTANT_SD_EXTENSION either
+	 * ->present(), or ->absent() method will be called, independently of
+	 * what other extensions are present.
+	 */
+	LAST_IMPORTANT_SD_EXTENSION = PLUGIN_STAT,
+} sd_ext_bits;
+
+/* minimal stat-data. This allows to support light-weight files. */
+typedef struct reiser4_stat_data_base {
+	/*  0 */ __le16 extmask;
+	/*  2 */
+} PACKED reiser4_stat_data_base;
+
+typedef struct reiser4_light_weight_stat {
+	/*  0 */ __le16 mode;
+	/*  2 */ __le32 nlink;
+	/*  8 */ __le64 size;
+	/* size in bytes */
+	/* 16 */
+} PACKED reiser4_light_weight_stat;
+
+typedef struct reiser4_unix_stat {
+	/* owner id */
+	/*  0 */ __le32 uid;
+	/* group id */
+	/*  4 */ __le32 gid;
+	/* access time */
+	/*  8 */ __le32 atime;
+	/* modification time */
+	/* 12 */ __le32 mtime;
+	/* change time */
+	/* 16 */ __le32 ctime;
+	union {
+		/* minor:major for device files */
+		/* 20 */ __le64 rdev;
+		/* bytes used by file */
+		/* 20 */ __le64 bytes;
+	} u;
+	/* 28 */
+} PACKED reiser4_unix_stat;
+
+/* symlink stored as part of inode */
+typedef struct reiser4_symlink_stat {
+	char body[0];
+} PACKED reiser4_symlink_stat;
+
+typedef struct reiser4_plugin_slot {
+	/*  0 */ __le16 pset_memb;
+	/*  2 */ __le16 id;
+	/*  4 *//* here plugin stores its persistent state */
+} PACKED reiser4_plugin_slot;
+
+/* stat-data extension for files with non-standard plugin. */
+typedef struct reiser4_plugin_stat {
+	/* number of additional plugins, associated with this object */
+	/*  0 */ __le16 plugins_no;
+	/*  2 */ reiser4_plugin_slot slot[0];
+	/*  2 */
+} PACKED reiser4_plugin_stat;
+
+/* stat-data extension for inode flags. Currently it is just fixed-width 32
+ * bit mask. If need arise, this can be replaced with variable width
+ * bitmask. */
+typedef struct reiser4_flags_stat {
+	/*  0 */ __le32 flags;
+	/*  4 */
+} PACKED reiser4_flags_stat;
+
+typedef struct reiser4_capabilities_stat {
+	/*  0 */ __le32 effective;
+	/*  8 */ __le32 permitted;
+	/* 16 */
+} PACKED reiser4_capabilities_stat;
+
+typedef struct reiser4_cluster_stat {
+/* this defines cluster size (an attribute of cryptcompress objects) as PAGE_SIZE << cluster shift */
+	/* 0 */ d8 cluster_shift;
+	/* 1 */
+} PACKED reiser4_cluster_stat;
+
+typedef struct reiser4_crypto_stat {
+	/* secret key size, bits */
+	/*  0 */ d16 keysize;
+	/* secret key id */
+	/*  2 */ d8 keyid[0];
+	/* 2 */
+} PACKED reiser4_crypto_stat;
+
+typedef struct reiser4_large_times_stat {
+	/* access time */
+	/*  0 */ d32 atime;
+	/* modification time */
+	/*  8 */ d32 mtime;
+	/* change time */
+	/* 16 */ d32 ctime;
+	/* 24 */
+} PACKED reiser4_large_times_stat;
+
+/* this structure is filled by sd_item_stat */
+typedef struct sd_stat {
+	int dirs;
+	int files;
+	int others;
+} sd_stat;
+
+/* plugin->item.common.* */
+extern void print_sd(const char *prefix, coord_t * coord);
+extern void item_stat_static_sd(const coord_t * coord, void *vp);
+
+/* plugin->item.s.sd.* */
+extern int init_inode_static_sd(struct inode *inode, char *sd, int len);
+extern int save_len_static_sd(struct inode *inode);
+extern int save_static_sd(struct inode *inode, char **area);
+
+/* __FS_REISER4_PLUGIN_ITEM_STATIC_STAT_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/item/tail.c newtree/fs/reiser4/plugin/item/tail.c
--- oldtree/fs/reiser4/plugin/item/tail.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/tail.c	2006-02-21 15:58:34.730866664 +0000
@@ -0,0 +1,712 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#include "item.h"
+#include "../../inode.h"
+#include "../../page_cache.h"
+#include "../../carry.h"
+#include "../../vfs_ops.h"
+
+#include <linux/quotaops.h>
+#include <asm/uaccess.h>
+#include <linux/swap.h>
+#include <linux/writeback.h>
+
+/* plugin->u.item.b.max_key_inside */
+reiser4_key *max_key_inside_tail(const coord_t * coord, reiser4_key * key)
+{
+	item_key_by_coord(coord, key);
+	set_key_offset(key, get_key_offset(max_key()));
+	return key;
+}
+
+/* plugin->u.item.b.can_contain_key */
+int
+can_contain_key_tail(const coord_t * coord, const reiser4_key * key,
+		     const reiser4_item_data * data)
+{
+	reiser4_key item_key;
+
+	if (item_plugin_by_coord(coord) != data->iplug)
+		return 0;
+
+	item_key_by_coord(coord, &item_key);
+	if (get_key_locality(key) != get_key_locality(&item_key) ||
+	    get_key_objectid(key) != get_key_objectid(&item_key))
+		return 0;
+
+	return 1;
+}
+
+/* plugin->u.item.b.mergeable
+   first item is of tail type */
+/* Audited by: green(2002.06.14) */
+int mergeable_tail(const coord_t * p1, const coord_t * p2)
+{
+	reiser4_key key1, key2;
+
+	assert("vs-535",
+	       item_type_by_coord(p1) == UNIX_FILE_METADATA_ITEM_TYPE);
+	assert("vs-365", item_id_by_coord(p1) == FORMATTING_ID);
+
+	if (item_id_by_coord(p2) != FORMATTING_ID) {
+		/* second item is of another type */
+		return 0;
+	}
+
+	item_key_by_coord(p1, &key1);
+	item_key_by_coord(p2, &key2);
+	if (get_key_locality(&key1) != get_key_locality(&key2) ||
+	    get_key_objectid(&key1) != get_key_objectid(&key2)
+	    || get_key_type(&key1) != get_key_type(&key2)) {
+		/* items of different objects */
+		return 0;
+	}
+	if (get_key_offset(&key1) + nr_units_tail(p1) != get_key_offset(&key2)) {
+		/* not adjacent items */
+		return 0;
+	}
+	return 1;
+}
+
+/* plugin->u.item.b.print
+   plugin->u.item.b.check */
+
+/* plugin->u.item.b.nr_units */
+pos_in_node_t nr_units_tail(const coord_t * coord)
+{
+	return item_length_by_coord(coord);
+}
+
+/* plugin->u.item.b.lookup */
+lookup_result
+lookup_tail(const reiser4_key * key, lookup_bias bias, coord_t * coord)
+{
+	reiser4_key item_key;
+	__u64 lookuped, offset;
+	unsigned nr_units;
+
+	item_key_by_coord(coord, &item_key);
+	offset = get_key_offset(item_key_by_coord(coord, &item_key));
+	nr_units = nr_units_tail(coord);
+
+	/* key we are looking for must be greater than key of item @coord */
+	assert("vs-416", keygt(key, &item_key));
+
+	/* offset we are looking for */
+	lookuped = get_key_offset(key);
+
+	if (lookuped >= offset && lookuped < offset + nr_units) {
+		/* byte we are looking for is in this item */
+		coord->unit_pos = lookuped - offset;
+		coord->between = AT_UNIT;
+		return CBK_COORD_FOUND;
+	}
+
+	/* set coord after last unit */
+	coord->unit_pos = nr_units - 1;
+	coord->between = AFTER_UNIT;
+	return bias ==
+	    FIND_MAX_NOT_MORE_THAN ? CBK_COORD_FOUND : CBK_COORD_NOTFOUND;
+}
+
+/* plugin->u.item.b.paste */
+int
+paste_tail(coord_t *coord, reiser4_item_data *data,
+	   carry_plugin_info *info UNUSED_ARG)
+{
+	unsigned old_item_length;
+	char *item;
+
+	/* length the item had before resizing has been performed */
+	old_item_length = item_length_by_coord(coord) - data->length;
+
+	/* tail items never get pasted in the middle */
+	assert("vs-363",
+	       (coord->unit_pos == 0 && coord->between == BEFORE_UNIT) ||
+	       (coord->unit_pos == old_item_length - 1 &&
+		coord->between == AFTER_UNIT) ||
+	       (coord->unit_pos == 0 && old_item_length == 0
+		&& coord->between == AT_UNIT));
+
+	item = item_body_by_coord(coord);
+	if (coord->unit_pos == 0)
+		/* make space for pasted data when pasting at the beginning of
+		   the item */
+		memmove(item + data->length, item, old_item_length);
+
+	if (coord->between == AFTER_UNIT)
+		coord->unit_pos++;
+
+	if (data->data) {
+		assert("vs-554", data->user == 0 || data->user == 1);
+		if (data->user) {
+			assert("nikita-3035", schedulable());
+			/* copy from user space */
+			if (__copy_from_user(item + coord->unit_pos,
+					     (const char __user *)data->data,
+					     (unsigned)data->length))
+				return RETERR(-EFAULT);
+		} else
+			/* copy from kernel space */
+			memcpy(item + coord->unit_pos, data->data,
+			       (unsigned)data->length);
+	} else {
+		memset(item + coord->unit_pos, 0, (unsigned)data->length);
+	}
+	return 0;
+}
+
+/* plugin->u.item.b.fast_paste */
+
+/* plugin->u.item.b.can_shift
+   number of units is returned via return value, number of bytes via @size. For
+   tail items they coincide */
+int
+can_shift_tail(unsigned free_space, coord_t * source UNUSED_ARG,
+	       znode * target UNUSED_ARG, shift_direction direction UNUSED_ARG,
+	       unsigned *size, unsigned want)
+{
+	/* make sure that that we do not want to shift more than we have */
+	assert("vs-364", want > 0
+	       && want <= (unsigned)item_length_by_coord(source));
+
+	*size = min(want, free_space);
+	return *size;
+}
+
+/* plugin->u.item.b.copy_units */
+void
+copy_units_tail(coord_t * target, coord_t * source,
+		unsigned from, unsigned count,
+		shift_direction where_is_free_space,
+		unsigned free_space UNUSED_ARG)
+{
+	/* make sure that item @target is expanded already */
+	assert("vs-366", (unsigned)item_length_by_coord(target) >= count);
+	assert("vs-370", free_space >= count);
+
+	if (where_is_free_space == SHIFT_LEFT) {
+		/* append item @target with @count first bytes of @source */
+		assert("vs-365", from == 0);
+
+		memcpy((char *)item_body_by_coord(target) +
+		       item_length_by_coord(target) - count,
+		       (char *)item_body_by_coord(source), count);
+	} else {
+		/* target item is moved to right already */
+		reiser4_key key;
+
+		assert("vs-367",
+		       (unsigned)item_length_by_coord(source) == from + count);
+
+		memcpy((char *)item_body_by_coord(target),
+		       (char *)item_body_by_coord(source) + from, count);
+
+		/* new units are inserted before first unit in an item,
+		   therefore, we have to update item key */
+		item_key_by_coord(source, &key);
+		set_key_offset(&key, get_key_offset(&key) + from);
+
+		node_plugin_by_node(target->node)->update_item_key(target, &key,
+								   NULL /*info */);
+	}
+}
+
+/* plugin->u.item.b.create_hook */
+
+/* item_plugin->b.kill_hook
+   this is called when @count units starting from @from-th one are going to be removed
+   */
+int
+kill_hook_tail(const coord_t * coord, pos_in_node_t from,
+	       pos_in_node_t count, struct carry_kill_data *kdata)
+{
+	reiser4_key key;
+	loff_t start, end;
+
+	assert("vs-1577", kdata);
+	assert("vs-1579", kdata->inode);
+
+	item_key_by_coord(coord, &key);
+	start = get_key_offset(&key) + from;
+	end = start + count;
+	fake_kill_hook_tail(kdata->inode, start, end, kdata->params.truncate);
+	return 0;
+}
+
+/* plugin->u.item.b.shift_hook */
+
+/* helper for kill_units_tail and cut_units_tail */
+static int
+do_cut_or_kill(coord_t * coord, pos_in_node_t from, pos_in_node_t to,
+	       reiser4_key * smallest_removed, reiser4_key * new_first)
+{
+	pos_in_node_t count;
+
+	/* this method is only called to remove part of item */
+	assert("vs-374", (to - from + 1) < item_length_by_coord(coord));
+	/* tails items are never cut from the middle of an item */
+	assert("vs-396", ergo(from != 0, to == coord_last_unit_pos(coord)));
+	assert("vs-1558", ergo(from == 0, to < coord_last_unit_pos(coord)));
+
+	count = to - from + 1;
+
+	if (smallest_removed) {
+		/* store smallest key removed */
+		item_key_by_coord(coord, smallest_removed);
+		set_key_offset(smallest_removed,
+			       get_key_offset(smallest_removed) + from);
+	}
+	if (new_first) {
+		/* head of item is cut */
+		assert("vs-1529", from == 0);
+
+		item_key_by_coord(coord, new_first);
+		set_key_offset(new_first,
+			       get_key_offset(new_first) + from + count);
+	}
+
+	if (REISER4_DEBUG)
+		memset((char *)item_body_by_coord(coord) + from, 0, count);
+	return count;
+}
+
+/* plugin->u.item.b.cut_units */
+int
+cut_units_tail(coord_t * coord, pos_in_node_t from, pos_in_node_t to,
+	       struct carry_cut_data *cdata UNUSED_ARG,
+	       reiser4_key * smallest_removed, reiser4_key * new_first)
+{
+	return do_cut_or_kill(coord, from, to, smallest_removed, new_first);
+}
+
+/* plugin->u.item.b.kill_units */
+int
+kill_units_tail(coord_t * coord, pos_in_node_t from, pos_in_node_t to,
+		struct carry_kill_data *kdata, reiser4_key * smallest_removed,
+		reiser4_key * new_first)
+{
+	kill_hook_tail(coord, from, to - from + 1, kdata);
+	return do_cut_or_kill(coord, from, to, smallest_removed, new_first);
+}
+
+/* plugin->u.item.b.unit_key */
+reiser4_key *unit_key_tail(const coord_t * coord, reiser4_key * key)
+{
+	assert("vs-375", coord_is_existing_unit(coord));
+
+	item_key_by_coord(coord, key);
+	set_key_offset(key, (get_key_offset(key) + coord->unit_pos));
+
+	return key;
+}
+
+/* plugin->u.item.b.estimate
+   plugin->u.item.b.item_data_by_flow */
+
+/* overwrite tail item or its part by use data */
+static int overwrite_tail(coord_t *coord, flow_t *f)
+{
+	unsigned count;
+
+	assert("vs-570", f->user == 1);
+	assert("vs-946", f->data);
+	assert("vs-947", coord_is_existing_unit(coord));
+	assert("vs-948", znode_is_write_locked(coord->node));
+	assert("nikita-3036", schedulable());
+
+	count = item_length_by_coord(coord) - coord->unit_pos;
+	if (count > f->length)
+		count = f->length;
+
+	if (__copy_from_user((char *)item_body_by_coord(coord) + coord->unit_pos,
+			     (const char __user *)f->data, count))
+		return RETERR(-EFAULT);
+
+	znode_make_dirty(coord->node);
+
+	move_flow_forward(f, count);
+	return 0;
+}
+
+/* tail redpage function. It is called from readpage_tail(). */
+static int do_readpage_tail(uf_coord_t *uf_coord, struct page *page)
+{
+	tap_t tap;
+	int result;
+	coord_t coord;
+	lock_handle lh;
+	int count, mapped;
+	struct inode *inode;
+	char *pagedata;
+
+	/* saving passed coord in order to do not move it by tap. */
+	init_lh(&lh);
+	copy_lh(&lh, uf_coord->lh);
+	inode = page->mapping->host;
+	coord_dup(&coord, &uf_coord->coord);
+
+	tap_init(&tap, &coord, &lh, ZNODE_READ_LOCK);
+
+	if ((result = tap_load(&tap)))
+		goto out_tap_done;
+
+	/* lookup until page is filled up. */
+	for (mapped = 0; mapped < PAGE_CACHE_SIZE; ) {
+		/* number of bytes to be copied to page */
+		count = item_length_by_coord(&coord) - coord.unit_pos;
+		if (count > PAGE_CACHE_SIZE - mapped)
+			count = PAGE_CACHE_SIZE - mapped;
+
+		/* attach @page to address space and get data address */
+		pagedata = kmap_atomic(page, KM_USER0);
+
+		/* copy tail item to page */
+		memcpy(pagedata + mapped,
+		       ((char *)item_body_by_coord(&coord) + coord.unit_pos),
+		       count);
+		mapped += count;
+
+		flush_dcache_page(page);
+
+		/* dettach page from address space */
+		kunmap_atomic(pagedata, KM_USER0);
+
+		/* Getting next tail item. */
+		if (mapped < PAGE_CACHE_SIZE) {
+			/*
+			 * unlock page in order to avoid keep it locked
+			 * during tree lookup, which takes long term locks
+			 */
+			unlock_page(page);
+
+			/* getting right neighbour. */
+			result = go_dir_el(&tap, RIGHT_SIDE, 0);
+
+			/* lock page back */
+			lock_page(page);
+			if (PageUptodate(page)) {
+				/*
+				 * another thread read the page, we have
+				 * nothing to do
+				 */
+				result = 0;
+				goto out_unlock_page;
+			}
+
+			if (result) {
+				if (result == -E_NO_NEIGHBOR) {
+					/*
+					 * rigth neighbor is not a formatted
+					 * node
+					 */
+					result = 0;
+					goto done;
+				} else {
+					goto out_tap_relse;
+				}
+			} else {
+				if (!inode_file_plugin(inode)->
+				    owns_item(inode, &coord)) {
+					/* item of another file is found */
+					result = 0;
+					goto done;
+				}
+			}
+		}
+	}
+
+ done:
+	if (mapped != PAGE_CACHE_SIZE) {
+		pagedata = kmap_atomic(page, KM_USER0);
+		memset(pagedata + mapped, 0, PAGE_CACHE_SIZE - mapped);
+		flush_dcache_page(page);
+		kunmap_atomic(pagedata, KM_USER0);
+	}
+	SetPageUptodate(page);
+ out_unlock_page:
+	unlock_page(page);
+ out_tap_relse:
+	tap_relse(&tap);
+ out_tap_done:
+	tap_done(&tap);
+	return result;
+}
+
+/*
+   plugin->s.file.readpage
+   reiser4_read->unix_file_read->page_cache_readahead->reiser4_readpage->unix_file_readpage->readpage_tail
+   or
+   filemap_nopage->reiser4_readpage->readpage_unix_file->->readpage_tail
+
+   At the beginning: coord->node is read locked, zloaded, page is locked, coord is set to existing unit inside of tail
+   item. */
+int readpage_tail(void *vp, struct page *page)
+{
+	uf_coord_t *uf_coord = vp;
+	ON_DEBUG(coord_t * coord = &uf_coord->coord);
+	ON_DEBUG(reiser4_key key);
+
+	assert("umka-2515", PageLocked(page));
+	assert("umka-2516", !PageUptodate(page));
+	assert("umka-2517", !jprivate(page) && !PagePrivate(page));
+	assert("umka-2518", page->mapping && page->mapping->host);
+
+	assert("umka-2519", znode_is_loaded(coord->node));
+	assert("umka-2520", item_is_tail(coord));
+	assert("umka-2521", coord_is_existing_unit(coord));
+	assert("umka-2522", znode_is_rlocked(coord->node));
+	assert("umka-2523",
+	       page->mapping->host->i_ino ==
+	       get_key_objectid(item_key_by_coord(coord, &key)));
+
+	return do_readpage_tail(uf_coord, page);
+}
+
+/* drop longterm znode lock before calling
+   balance_dirty_pages. balance_dirty_pages may cause transaction to close,
+   therefore we have to update stat data if necessary */
+static int
+tail_balance_dirty_pages(struct address_space *mapping, const flow_t * f,
+			 hint_t * hint)
+{
+	int result;
+	struct inode *inode;
+	int excl;
+	unix_file_info_t *uf_info;
+
+	if (hint->ext_coord.valid)
+		set_hint(hint, &f->key, ZNODE_WRITE_LOCK);
+	else
+		unset_hint(hint);
+
+	inode = mapping->host;
+	if (get_key_offset(&f->key) > inode->i_size) {
+		assert("vs-1649", f->user == 1);
+		INODE_SET_FIELD(inode, i_size, get_key_offset(&f->key));
+	}
+	if (f->user != 0) {
+		/* this was writing data from user space. Update timestamps, therefore. Othrewise, this is tail
+		   conversion where we should not update timestamps */
+		inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+		result = reiser4_update_sd(inode);
+		if (result)
+			return result;
+	}
+
+	if (!reiser4_is_set(inode->i_sb, REISER4_ATOMIC_WRITE)) {
+		uf_info = unix_file_inode_data(inode);
+		excl = unix_file_inode_data(inode)->exclusive_use;
+		if (excl) {
+			/* we are about to drop exclusive access. Set file
+			   container to UF_CONTAINER_TAILS if file is not under
+			   tail conversion */
+			if (!inode_get_flag(inode, REISER4_PART_CONV))
+				uf_info->container = UF_CONTAINER_TAILS;
+			drop_exclusive_access(uf_info);
+		} else
+			drop_nonexclusive_access(uf_info);
+		reiser4_throttle_write(inode);
+		if (excl)
+			get_exclusive_access(uf_info);
+		else
+			get_nonexclusive_access(uf_info, 0);
+	}
+	return 0;
+}
+
+/* calculate number of blocks which can be dirtied/added when flow is inserted
+   and stat data gets updated and grab them.  FIXME-VS: we may want to call
+   grab_space with BA_CAN_COMMIT flag but that would require all that
+   complexity with sealing coord, releasing long term lock and validating seal
+   later */
+static int insert_flow_reserve(reiser4_tree * tree)
+{
+	grab_space_enable();
+	return reiser4_grab_space(estimate_insert_flow(tree->height) +
+				  estimate_one_insert_into_item(tree), 0);
+}
+
+/* one block gets overwritten and stat data may get updated */
+static int overwrite_reserve(reiser4_tree * tree)
+{
+	grab_space_enable();
+	return reiser4_grab_space(1 + estimate_one_insert_into_item(tree), 0);
+}
+
+/* plugin->u.item.s.file.write
+   access to data stored in tails goes directly through formatted nodes */
+int write_tail(struct inode *inode, flow_t * f, hint_t * hint, int grabbed,	/* tail's write may be called from plain unix file write and from tail conversion. In first
+										   case (grabbed == 0) space is not reserved forehand, so, it must be done here. When it is
+										   being called from tail conversion - space is reserved already for whole operation which may
+										   involve several calls to item write. In this case space reservation will not be done here */
+	       write_mode_t mode)
+{
+	int result;
+	coord_t *coord;
+
+	assert("vs-1338", hint->ext_coord.valid == 1);
+
+	coord = &hint->ext_coord.coord;
+	result = 0;
+	while (f->length && hint->ext_coord.valid == 1) {
+		switch (mode) {
+		case FIRST_ITEM:
+		case APPEND_ITEM:
+			/* check quota before appending data */
+			if (DQUOT_ALLOC_SPACE_NODIRTY(inode, f->length)) {
+				result = RETERR(-EDQUOT);
+				break;
+			}
+
+			if (!grabbed)
+				result =
+				    insert_flow_reserve(znode_get_tree
+							(coord->node));
+			if (!result)
+				result =
+				    insert_flow(coord, hint->ext_coord.lh, f);
+			if (f->length)
+				DQUOT_FREE_SPACE_NODIRTY(inode, f->length);
+			break;
+
+		case OVERWRITE_ITEM:
+			if (!grabbed)
+				result =
+				    overwrite_reserve(znode_get_tree
+						      (coord->node));
+			if (!result)
+				result = overwrite_tail(coord, f);
+			break;
+
+		default:
+			impossible("vs-1031", "does this ever happen?");
+			result = RETERR(-EIO);
+			break;
+
+		}
+
+		if (result) {
+			if (!grabbed)
+				all_grabbed2free();
+			unset_hint(hint);
+			break;
+		}
+
+		/* FIXME: do not rely on a coord yet */
+		unset_hint(hint);
+
+		/* throttle the writer */
+		result = tail_balance_dirty_pages(inode->i_mapping, f, hint);
+		if (!grabbed)
+			all_grabbed2free();
+		if (result)
+			break;
+	}
+
+	return result;
+}
+
+#if REISER4_DEBUG
+
+static int
+coord_matches_key_tail(const coord_t * coord, const reiser4_key * key)
+{
+	reiser4_key item_key;
+
+	assert("vs-1356", coord_is_existing_unit(coord));
+	assert("vs-1354", keylt(key, append_key_tail(coord, &item_key)));
+	assert("vs-1355", keyge(key, item_key_by_coord(coord, &item_key)));
+	return get_key_offset(key) ==
+	    get_key_offset(&item_key) + coord->unit_pos;
+
+}
+
+#endif
+
+/* plugin->u.item.s.file.read */
+int read_tail(struct file *file UNUSED_ARG, flow_t *f, hint_t *hint)
+{
+	unsigned count;
+	int item_length;
+	coord_t *coord;
+	uf_coord_t *uf_coord;
+
+	uf_coord = &hint->ext_coord;
+	coord = &uf_coord->coord;
+
+	assert("vs-571", f->user == 1);
+	assert("vs-571", f->data);
+	assert("vs-967", coord && coord->node);
+	assert("vs-1117", znode_is_rlocked(coord->node));
+	assert("vs-1118", znode_is_loaded(coord->node));
+
+	assert("nikita-3037", schedulable());
+	assert("vs-1357", coord_matches_key_tail(coord, &f->key));
+
+	/* calculate number of bytes to read off the item */
+	item_length = item_length_by_coord(coord);
+	count = item_length_by_coord(coord) - coord->unit_pos;
+	if (count > f->length)
+		count = f->length;
+
+	/* user page has to be brought in so that major page fault does not
+	 * occur here when longtem lock is held */
+	if (__copy_to_user((char __user *)f->data,
+			   ((char *)item_body_by_coord(coord) + coord->unit_pos),
+			   count))
+		return RETERR(-EFAULT);
+
+	/* probably mark_page_accessed() should only be called if
+	 * coord->unit_pos is zero. */
+	mark_page_accessed(znode_page(coord->node));
+	move_flow_forward(f, count);
+
+	coord->unit_pos += count;
+	if (item_length == coord->unit_pos) {
+		coord->unit_pos--;
+		coord->between = AFTER_UNIT;
+	}
+
+	return 0;
+}
+
+/*
+   plugin->u.item.s.file.append_key
+   key of first byte which is the next to last byte by addressed by this item
+*/
+reiser4_key *append_key_tail(const coord_t * coord, reiser4_key * key)
+{
+	item_key_by_coord(coord, key);
+	set_key_offset(key, get_key_offset(key) + item_length_by_coord(coord));
+	return key;
+}
+
+/* plugin->u.item.s.file.init_coord_extension */
+void init_coord_extension_tail(uf_coord_t * uf_coord, loff_t lookuped)
+{
+	uf_coord->valid = 1;
+}
+
+/*
+  plugin->u.item.s.file.get_block
+*/
+int
+get_block_address_tail(const coord_t * coord, sector_t lblock, sector_t * block)
+{
+	assert("nikita-3252", znode_get_level(coord->node) == LEAF_LEVEL);
+
+	*block = *znode_get_block(coord->node);
+	return 0;
+}
+
+/*
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/item/tail.h newtree/fs/reiser4/plugin/item/tail.h
--- oldtree/fs/reiser4/plugin/item/tail.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/item/tail.h	2006-02-21 15:58:34.636880952 +0000
@@ -0,0 +1,57 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#if !defined( __REISER4_TAIL_H__ )
+#define __REISER4_TAIL_H__
+
+typedef struct {
+	int not_used;
+} tail_coord_extension_t;
+
+struct cut_list;
+
+/* plugin->u.item.b.* */
+reiser4_key *max_key_inside_tail(const coord_t *, reiser4_key *);
+int can_contain_key_tail(const coord_t * coord, const reiser4_key * key,
+			 const reiser4_item_data *);
+int mergeable_tail(const coord_t * p1, const coord_t * p2);
+pos_in_node_t nr_units_tail(const coord_t *);
+lookup_result lookup_tail(const reiser4_key *, lookup_bias, coord_t *);
+int paste_tail(coord_t *, reiser4_item_data *, carry_plugin_info *);
+int can_shift_tail(unsigned free_space, coord_t * source,
+		   znode * target, shift_direction, unsigned *size,
+		   unsigned want);
+void copy_units_tail(coord_t * target, coord_t * source, unsigned from,
+		     unsigned count, shift_direction, unsigned free_space);
+int kill_hook_tail(const coord_t *, pos_in_node_t from, pos_in_node_t count,
+		   struct carry_kill_data *);
+int cut_units_tail(coord_t *, pos_in_node_t from, pos_in_node_t to,
+		   struct carry_cut_data *, reiser4_key * smallest_removed,
+		   reiser4_key * new_first);
+int kill_units_tail(coord_t *, pos_in_node_t from, pos_in_node_t to,
+		    struct carry_kill_data *, reiser4_key * smallest_removed,
+		    reiser4_key * new_first);
+reiser4_key *unit_key_tail(const coord_t *, reiser4_key *);
+
+/* plugin->u.item.s.* */
+int write_tail(struct inode *, flow_t *, hint_t *, int grabbed, write_mode_t);
+int read_tail(struct file *, flow_t *, hint_t *);
+int readpage_tail(void *vp, struct page *page);
+reiser4_key *append_key_tail(const coord_t *, reiser4_key *);
+void init_coord_extension_tail(uf_coord_t *, loff_t offset);
+int get_block_address_tail(const coord_t *, sector_t, sector_t *);
+int item_balance_dirty_pages(struct address_space *, const flow_t *,
+			     hint_t *, int back_to_dirty, int set_hint);
+
+/* __REISER4_TAIL_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/node/Makefile newtree/fs/reiser4/plugin/node/Makefile
--- oldtree/fs/reiser4/plugin/node/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/node/Makefile	2006-02-21 15:58:35.082813160 +0000
@@ -0,0 +1,5 @@
+obj-$(CONFIG_REISER4_FS) += node_plugins.o
+
+node_plugins-objs :=	\
+	node.o		\
+	node40.o
diff -urN oldtree/fs/reiser4/plugin/node/node.c newtree/fs/reiser4/plugin/node/node.c
--- oldtree/fs/reiser4/plugin/node/node.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/node/node.c	2006-02-21 15:58:34.641880192 +0000
@@ -0,0 +1,131 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Node plugin interface.
+
+   Description: The tree provides the abstraction of flows, which it
+   internally fragments into items which it stores in nodes.
+
+   A key_atom is a piece of data bound to a single key.
+
+   For reasonable space efficiency to be achieved it is often
+   necessary to store key_atoms in the nodes in the form of items, where
+   an item is a sequence of key_atoms of the same or similar type. It is
+   more space-efficient, because the item can implement (very)
+   efficient compression of key_atom's bodies using internal knowledge
+   about their semantics, and it can often avoid having a key for each
+   key_atom. Each type of item has specific operations implemented by its
+   item handler (see balance.c).
+
+   Rationale: the rest of the code (specifically balancing routines)
+   accesses leaf level nodes through this interface. This way we can
+   implement various block layouts and even combine various layouts
+   within the same tree. Balancing/allocating algorithms should not
+   care about peculiarities of splitting/merging specific item types,
+   but rather should leave that to the item's item handler.
+
+   Items, including those that provide the abstraction of flows, have
+   the property that if you move them in part or in whole to another
+   node, the balancing code invokes their is_left_mergeable()
+   item_operation to determine if they are mergeable with their new
+   neighbor in the node you have moved them to.  For some items the
+   is_left_mergeable() function always returns null.
+
+   When moving the bodies of items from one node to another:
+
+     if a partial item is shifted to another node the balancing code invokes
+     an item handler method to handle the item splitting.
+
+     if the balancing code needs to merge with an item in the node it
+     is shifting to, it will invoke an item handler method to handle
+     the item merging.
+
+     if it needs to move whole item bodies unchanged, the balancing code uses xmemcpy()
+     adjusting the item headers after the move is done using the node handler.
+*/
+
+#include "../../forward.h"
+#include "../../debug.h"
+#include "../../key.h"
+#include "../../coord.h"
+#include "../plugin_header.h"
+#include "../item/item.h"
+#include "node.h"
+#include "../plugin.h"
+#include "../../znode.h"
+#include "../../tree.h"
+#include "../../super.h"
+#include "../../reiser4.h"
+
+/**
+ * leftmost_key_in_node - get the smallest key in node
+ * @node:
+ * @key: store result here
+ *
+ * Stores the leftmost key of @node in @key.
+ */
+reiser4_key *leftmost_key_in_node(const znode *node, reiser4_key *key)
+{
+	assert("nikita-1634", node != NULL);
+	assert("nikita-1635", key != NULL);
+
+	if (!node_is_empty(node)) {
+		coord_t first_item;
+
+		coord_init_first_unit(&first_item, (znode *) node);
+		item_key_by_coord(&first_item, key);
+	} else
+		*key = *max_key();
+	return key;
+}
+
+node_plugin node_plugins[LAST_NODE_ID] = {
+	[NODE40_ID] = {
+		.h = {
+			.type_id = REISER4_NODE_PLUGIN_TYPE,
+			.id = NODE40_ID,
+			.pops = NULL,
+			.label = "unified",
+			.desc = "unified node layout",
+			.linkage = {NULL, NULL}
+		},
+		.item_overhead = item_overhead_node40,
+		.free_space = free_space_node40,
+		.lookup = lookup_node40,
+		.num_of_items = num_of_items_node40,
+		.item_by_coord = item_by_coord_node40,
+		.length_by_coord = length_by_coord_node40,
+		.plugin_by_coord = plugin_by_coord_node40,
+		.key_at = key_at_node40,
+		.estimate = estimate_node40,
+		.check = check_node40,
+		.parse = parse_node40,
+		.init = init_node40,
+#ifdef GUESS_EXISTS
+		.guess = guess_node40,
+#endif
+		.change_item_size = change_item_size_node40,
+		.create_item = create_item_node40,
+		.update_item_key = update_item_key_node40,
+		.cut_and_kill = kill_node40,
+		.cut = cut_node40,
+		.shift = shift_node40,
+		.shrink_item = shrink_item_node40,
+		.fast_insert = fast_insert_node40,
+		.fast_paste = fast_paste_node40,
+		.fast_cut = fast_cut_node40,
+		.max_item_size = max_item_size_node40,
+		.prepare_removal = prepare_removal_node40,
+		.set_item_plugin = set_item_plugin_node40
+	}
+};
+
+/*
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/node/node.h newtree/fs/reiser4/plugin/node/node.h
--- oldtree/fs/reiser4/plugin/node/node.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/node/node.h	2006-02-21 15:58:34.858847208 +0000
@@ -0,0 +1,272 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* We need a definition of the default node layout here. */
+
+/* Generally speaking, it is best to have free space in the middle of the
+   node so that two sets of things can grow towards it, and to have the
+   item bodies on the left so that the last one of them grows into free
+   space.  We optimize for the case where we append new items to the end
+   of the node, or grow the last item, because it hurts nothing to so
+   optimize and it is a common special case to do massive insertions in
+   increasing key order (and one of cases more likely to have a real user
+   notice the delay time for).
+
+   formatted leaf default layout: (leaf1)
+
+   |node header:item bodies:free space:key + pluginid + item offset|
+
+   We grow towards the middle, optimizing layout for the case where we
+   append new items to the end of the node.  The node header is fixed
+   length.  Keys, and item offsets plus pluginids for the items
+   corresponding to them are in increasing key order, and are fixed
+   length.  Item offsets are relative to start of node (16 bits creating
+   a node size limit of 64k, 12 bits might be a better choice....).  Item
+   bodies are in decreasing key order.  Item bodies have a variable size.
+   There is a one to one to one mapping of keys to item offsets to item
+   bodies.  Item offsets consist of pointers to the zeroth byte of the
+   item body.  Item length equals the start of the next item minus the
+   start of this item, except the zeroth item whose length equals the end
+   of the node minus the start of that item (plus a byte).  In other
+   words, the item length is not recorded anywhere, and it does not need
+   to be since it is computable.
+
+   Leaf variable length items and keys layout : (lvar)
+
+   |node header:key offset + item offset + pluginid triplets:free space:key bodies:item bodies|
+
+   We grow towards the middle, optimizing layout for the case where we
+   append new items to the end of the node.  The node header is fixed
+   length.  Keys and item offsets for the items corresponding to them are
+   in increasing key order, and keys are variable length.  Item offsets
+   are relative to start of node (16 bits).  Item bodies are in
+   decreasing key order.  Item bodies have a variable size.  There is a
+   one to one to one mapping of keys to item offsets to item bodies.
+   Item offsets consist of pointers to the zeroth byte of the item body.
+   Item length equals the start of the next item's key minus the start of
+   this item, except the zeroth item whose length equals the end of the
+   node minus the start of that item (plus a byte).
+
+   leaf compressed keys layout: (lcomp)
+
+   |node header:key offset + key inherit + item offset pairs:free space:key bodies:item bodies|
+
+   We grow towards the middle, optimizing layout for the case where we
+   append new items to the end of the node.  The node header is fixed
+   length.  Keys and item offsets for the items corresponding to them are
+   in increasing key order, and keys are variable length.  The "key
+   inherit" field indicates how much of the key prefix is identical to
+   the previous key (stem compression as described in "Managing
+   Gigabytes" is used).  key_inherit is a one byte integer.  The
+   intra-node searches performed through this layout are linear searches,
+   and this is theorized to not hurt performance much due to the high
+   cost of processor stalls on modern CPUs, and the small number of keys
+   in a single node.  Item offsets are relative to start of node (16
+   bits).  Item bodies are in decreasing key order.  Item bodies have a
+   variable size.  There is a one to one to one mapping of keys to item
+   offsets to item bodies.  Item offsets consist of pointers to the
+   zeroth byte of the item body.  Item length equals the start of the
+   next item minus the start of this item, except the zeroth item whose
+   length equals the end of the node minus the start of that item (plus a
+   byte).  In other words, item length and key length is not recorded
+   anywhere, and it does not need to be since it is computable.
+
+   internal node default layout: (idef1)
+
+   just like ldef1 except that item bodies are either blocknrs of
+   children or extents, and moving them may require updating parent
+   pointers in the nodes that they point to.
+*/
+
+/* There is an inherent 3-way tradeoff between optimizing and
+   exchanging disks between different architectures and code
+   complexity.  This is optimal and simple and inexchangeable.
+   Someone else can do the code for exchanging disks and make it
+   complex. It would not be that hard.  Using other than the PAGE_SIZE
+   might be suboptimal.
+*/
+
+#if !defined( __REISER4_NODE_H__ )
+#define __REISER4_NODE_H__
+
+#define LEAF40_NODE_SIZE PAGE_CACHE_SIZE
+
+#include "../../dformat.h"
+#include "../plugin_header.h"
+
+#include <linux/types.h>
+
+typedef enum {
+	NS_FOUND = 0,
+	NS_NOT_FOUND = -ENOENT
+} node_search_result;
+
+/* Maximal possible space overhead for creation of new item in a node */
+#define REISER4_NODE_MAX_OVERHEAD ( sizeof( reiser4_key ) + 32 )
+
+typedef enum {
+	REISER4_NODE_DKEYS = (1 << 0),
+	REISER4_NODE_TREE_STABLE = (1 << 1)
+} reiser4_node_check_flag;
+
+/* cut and cut_and_kill have too long list of parameters. This structure is just to safe some space on stack */
+struct cut_list {
+	coord_t *from;
+	coord_t *to;
+	const reiser4_key *from_key;
+	const reiser4_key *to_key;
+	reiser4_key *smallest_removed;
+	carry_plugin_info *info;
+	__u32 flags;
+	struct inode *inode;	/* this is to pass list of eflushed jnodes down to extent_kill_hook */
+	lock_handle *left;
+	lock_handle *right;
+};
+
+struct carry_cut_data;
+struct carry_kill_data;
+
+/* The responsibility of the node plugin is to store and give access
+   to the sequence of items within the node.  */
+typedef struct node_plugin {
+	/* generic plugin fields */
+	plugin_header h;
+
+	/* calculates the amount of space that will be required to store an
+	   item which is in addition to the space consumed by the item body.
+	   (the space consumed by the item body can be gotten by calling
+	   item->estimate) */
+	 size_t(*item_overhead) (const znode * node, flow_t * f);
+
+	/* returns free space by looking into node (i.e., without using
+	   znode->free_space). */
+	 size_t(*free_space) (znode * node);
+	/* search within the node for the one item which might
+	   contain the key, invoking item->search_within to search within
+	   that item to see if it is in there */
+	 node_search_result(*lookup) (znode * node, const reiser4_key * key,
+				      lookup_bias bias, coord_t * coord);
+	/* number of items in node */
+	int (*num_of_items) (const znode * node);
+
+	/* store information about item in @coord in @data */
+	/* break into several node ops, don't add any more uses of this before doing so */
+	/*int ( *item_at )( const coord_t *coord, reiser4_item_data *data ); */
+	char *(*item_by_coord) (const coord_t * coord);
+	int (*length_by_coord) (const coord_t * coord);
+	item_plugin *(*plugin_by_coord) (const coord_t * coord);
+
+	/* store item key in @key */
+	reiser4_key *(*key_at) (const coord_t * coord, reiser4_key * key);
+	/* conservatively estimate whether unit of what size can fit
+	   into node. This estimation should be performed without
+	   actually looking into the node's content (free space is saved in
+	   znode). */
+	 size_t(*estimate) (znode * node);
+
+	/* performs every consistency check the node plugin author could
+	   imagine. Optional. */
+	int (*check) (const znode * node, __u32 flags, const char **error);
+
+	/* Called when node is read into memory and node plugin is
+	   already detected. This should read some data into znode (like free
+	   space counter) and, optionally, check data consistency.
+	 */
+	int (*parse) (znode * node);
+	/* This method is called on a new node to initialise plugin specific
+	   data (header, etc.) */
+	int (*init) (znode * node);
+	/* Check whether @node content conforms to this plugin format.
+	   Probably only useful after support for old V3.x formats is added.
+	   Uncomment after 4.0 only.
+	 */
+	/*      int ( *guess )( const znode *node ); */
+#if REISER4_DEBUG
+	void (*print) (const char *prefix, const znode * node, __u32 flags);
+#endif
+	/* change size of @item by @by bytes. @item->node has enough free
+	   space. When @by > 0 - free space is appended to end of item. When
+	   @by < 0 - item is truncated - it is assumed that last @by bytes if
+	   the item are freed already */
+	void (*change_item_size) (coord_t * item, int by);
+
+	/* create new item @length bytes long in coord @target */
+	int (*create_item) (coord_t * target, const reiser4_key * key,
+			    reiser4_item_data * data, carry_plugin_info * info);
+
+	/* update key of item. */
+	void (*update_item_key) (coord_t * target, const reiser4_key * key,
+				 carry_plugin_info * info);
+
+	int (*cut_and_kill) (struct carry_kill_data *, carry_plugin_info *);
+	int (*cut) (struct carry_cut_data *, carry_plugin_info *);
+
+	/*
+	 * shrink item pointed to by @coord by @delta bytes.
+	 */
+	int (*shrink_item) (coord_t * coord, int delta);
+
+	/* copy as much as possible but not more than up to @stop from
+	   @stop->node to @target. If (pend == append) then data from beginning of
+	   @stop->node are copied to the end of @target. If (pend == prepend) then
+	   data from the end of @stop->node are copied to the beginning of
+	   @target. Copied data are removed from @stop->node. Information
+	   about what to do on upper level is stored in @todo */
+	int (*shift) (coord_t * stop, znode * target, shift_direction pend,
+		      int delete_node, int including_insert_coord,
+		      carry_plugin_info * info);
+	/* return true if this node allows skip carry() in some situations
+	   (see fs/reiser4/tree.c:insert_by_coord()). Reiser3.x format
+	   emulation doesn't.
+
+	   This will speedup insertions that doesn't require updates to the
+	   parent, by bypassing initialisation of carry() structures. It's
+	   believed that majority of insertions will fit there.
+
+	 */
+	int (*fast_insert) (const coord_t * coord);
+	int (*fast_paste) (const coord_t * coord);
+	int (*fast_cut) (const coord_t * coord);
+	/* this limits max size of item which can be inserted into a node and
+	   number of bytes item in a node may be appended with */
+	int (*max_item_size) (void);
+	int (*prepare_removal) (znode * empty, carry_plugin_info * info);
+	/* change plugin id of items which are in a node already. Currently it is Used in tail conversion for regular
+	 * files */
+	int (*set_item_plugin) (coord_t * coord, item_id);
+} node_plugin;
+
+typedef enum {
+	/* standard unified node layout used for both leaf and internal
+	   nodes */
+	NODE40_ID,
+	LAST_NODE_ID
+} reiser4_node_id;
+
+extern reiser4_key *leftmost_key_in_node(const znode * node, reiser4_key * key);
+#if REISER4_DEBUG
+extern void print_node_content(const char *prefix, const znode * node,
+			       __u32 flags);
+#endif
+
+extern void indent_znode(const znode * node);
+
+typedef struct common_node_header {
+	/*
+	 * identifier of node plugin. Must be located at the very beginning of
+	 * a node.
+	 */
+	__le16 plugin_id;
+} common_node_header;
+
+/* __REISER4_NODE_H__ */
+#endif
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * scroll-step: 1
+ * End:
+ */
diff -urN oldtree/fs/reiser4/plugin/node/node40.c newtree/fs/reiser4/plugin/node/node40.c
--- oldtree/fs/reiser4/plugin/node/node40.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/node/node40.c	2006-02-21 15:58:35.011823952 +0000
@@ -0,0 +1,2922 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#include "../../debug.h"
+#include "../../key.h"
+#include "../../coord.h"
+#include "../plugin_header.h"
+#include "../item/item.h"
+#include "node.h"
+#include "node40.h"
+#include "../plugin.h"
+#include "../../jnode.h"
+#include "../../znode.h"
+#include "../../pool.h"
+#include "../../carry.h"
+#include "../../tap.h"
+#include "../../tree.h"
+#include "../../super.h"
+#include "../../reiser4.h"
+
+#include <asm/uaccess.h>
+#include <linux/types.h>
+#include <linux/prefetch.h>
+
+/* leaf 40 format:
+
+  [node header | item 0, item 1, .., item N-1 |  free space | item_head N-1, .. item_head 1, item head 0 ]
+   plugin_id (16)                                                key
+   free_space (16)                                               pluginid (16)
+   free_space_start (16)                                         offset (16)
+   level (8)
+   num_items (16)
+   magic (32)
+   flush_time (32)
+*/
+/* NIKITA-FIXME-HANS: I told you guys not less than 10 times to not call it r4fs.  Change to "ReIs". */
+/* magic number that is stored in ->magic field of node header */
+static const __u32 REISER4_NODE_MAGIC = 0x52344653;	/* (*(__u32 *)"R4FS"); */
+
+static int prepare_for_update(znode * left, znode * right,
+			      carry_plugin_info * info);
+
+/* header of node of reiser40 format is at the beginning of node */
+static inline node40_header *node40_node_header(const znode * node	/* node to
+									 * query */ )
+{
+	assert("nikita-567", node != NULL);
+	assert("nikita-568", znode_page(node) != NULL);
+	assert("nikita-569", zdata(node) != NULL);
+	return (node40_header *) zdata(node);
+}
+
+/* functions to get/set fields of node40_header */
+#define nh40_get_magic(nh) le32_to_cpu(get_unaligned(&(nh)->magic))
+#define nh40_get_free_space(nh) le16_to_cpu(get_unaligned(&(nh)->free_space))
+#define nh40_get_free_space_start(nh) le16_to_cpu(get_unaligned(&(nh)->free_space_start))
+#define nh40_get_level(nh) get_unaligned(&(nh)->level)
+#define nh40_get_num_items(nh) le16_to_cpu(get_unaligned(&(nh)->nr_items))
+#define nh40_get_flush_id(nh) le64_to_cpu(get_unaligned(&(nh)->flush_id))
+
+#define nh40_set_magic(nh, value) put_unaligned(cpu_to_le32(value), &(nh)->magic)
+#define nh40_set_free_space(nh, value) put_unaligned(cpu_to_le16(value), &(nh)->free_space)
+#define nh40_set_free_space_start(nh, value) put_unaligned(cpu_to_le16(value), &(nh)->free_space_start)
+#define nh40_set_level(nh, value) put_unaligned(value, &(nh)->level)
+#define nh40_set_num_items(nh, value) put_unaligned(cpu_to_le16(value), &(nh)->nr_items)
+#define nh40_set_mkfs_id(nh, value) put_unaligned(cpu_to_le32(value), &(nh)->mkfs_id)
+
+
+/* plugin field of node header should be read/set by
+   plugin_by_disk_id/save_disk_plugin */
+
+/* array of item headers is at the end of node */
+static inline item_header40 *node40_ih_at(const znode * node, unsigned pos)
+{
+	return (item_header40 *) (zdata(node) + znode_size(node)) - pos - 1;
+}
+
+/* ( page_address( node -> pg ) + PAGE_CACHE_SIZE ) - pos - 1
+ */
+static inline item_header40 *node40_ih_at_coord(const coord_t * coord)
+{
+	return (item_header40 *) (zdata(coord->node) +
+				  znode_size(coord->node)) - (coord->item_pos) -
+	    1;
+}
+
+/* functions to get/set fields of item_header40 */
+#define ih40_get_offset(ih) le16_to_cpu(get_unaligned(&(ih)->offset))
+
+#define ih40_set_offset(ih, value) put_unaligned(cpu_to_le16(value), &(ih)->offset)
+
+/* plugin field of item header should be read/set by
+   plugin_by_disk_id/save_disk_plugin */
+
+/* plugin methods */
+
+/* plugin->u.node.item_overhead
+   look for description of this method in plugin/node/node.h */
+size_t
+item_overhead_node40(const znode * node UNUSED_ARG, flow_t * f UNUSED_ARG)
+{
+	return sizeof(item_header40);
+}
+
+/* plugin->u.node.free_space
+   look for description of this method in plugin/node/node.h */
+size_t free_space_node40(znode * node)
+{
+	assert("nikita-577", node != NULL);
+	assert("nikita-578", znode_is_loaded(node));
+	assert("nikita-579", zdata(node) != NULL);
+
+	return nh40_get_free_space(node40_node_header(node));
+}
+
+/* private inline version of node40_num_of_items() for use in this file. This
+   is necessary, because address of node40_num_of_items() is taken and it is
+   never inlined as a result. */
+static inline short node40_num_of_items_internal(const znode * node)
+{
+	return nh40_get_num_items(node40_node_header(node));
+}
+
+#if REISER4_DEBUG
+static inline void check_num_items(const znode * node)
+{
+	assert("nikita-2749",
+	       node40_num_of_items_internal(node) == node->nr_items);
+	assert("nikita-2746", znode_is_write_locked(node));
+}
+#else
+#define check_num_items(node) noop
+#endif
+
+/* plugin->u.node.num_of_items
+   look for description of this method in plugin/node/node.h */
+int num_of_items_node40(const znode * node)
+{
+	return node40_num_of_items_internal(node);
+}
+
+static void
+node40_set_num_items(znode * node, node40_header * nh, unsigned value)
+{
+	assert("nikita-2751", node != NULL);
+	assert("nikita-2750", nh == node40_node_header(node));
+
+	check_num_items(node);
+	nh40_set_num_items(nh, value);
+	node->nr_items = value;
+	check_num_items(node);
+}
+
+/* plugin->u.node.item_by_coord
+   look for description of this method in plugin/node/node.h */
+char *item_by_coord_node40(const coord_t * coord)
+{
+	item_header40 *ih;
+	char *p;
+
+	/* @coord is set to existing item */
+	assert("nikita-596", coord != NULL);
+	assert("vs-255", coord_is_existing_item(coord));
+
+	ih = node40_ih_at_coord(coord);
+	p = zdata(coord->node) + ih40_get_offset(ih);
+	return p;
+}
+
+/* plugin->u.node.length_by_coord
+   look for description of this method in plugin/node/node.h */
+int length_by_coord_node40(const coord_t * coord)
+{
+	item_header40 *ih;
+	int result;
+
+	/* @coord is set to existing item */
+	assert("vs-256", coord != NULL);
+	assert("vs-257", coord_is_existing_item(coord));
+
+	ih = node40_ih_at_coord(coord);
+	if ((int)coord->item_pos ==
+	    node40_num_of_items_internal(coord->node) - 1)
+		result =
+		    nh40_get_free_space_start(node40_node_header(coord->node)) -
+		    ih40_get_offset(ih);
+	else
+		result = ih40_get_offset(ih - 1) - ih40_get_offset(ih);
+
+	return result;
+}
+
+static pos_in_node_t
+node40_item_length(const znode * node, pos_in_node_t item_pos)
+{
+	item_header40 *ih;
+	pos_in_node_t result;
+
+	/* @coord is set to existing item */
+	assert("vs-256", node != NULL);
+	assert("vs-257", node40_num_of_items_internal(node) > item_pos);
+
+	ih = node40_ih_at(node, item_pos);
+	if (item_pos == node40_num_of_items_internal(node) - 1)
+		result =
+		    nh40_get_free_space_start(node40_node_header(node)) -
+		    ih40_get_offset(ih);
+	else
+		result = ih40_get_offset(ih - 1) - ih40_get_offset(ih);
+
+	return result;
+}
+
+/* plugin->u.node.plugin_by_coord
+   look for description of this method in plugin/node/node.h */
+item_plugin *plugin_by_coord_node40(const coord_t * coord)
+{
+	item_header40 *ih;
+	item_plugin *result;
+
+	/* @coord is set to existing item */
+	assert("vs-258", coord != NULL);
+	assert("vs-259", coord_is_existing_item(coord));
+
+	ih = node40_ih_at_coord(coord);
+	/* pass NULL in stead of current tree. This is time critical call. */
+	result = item_plugin_by_disk_id(NULL, &ih->plugin_id);
+	return result;
+}
+
+/* plugin->u.node.key_at
+   look for description of this method in plugin/node/node.h */
+reiser4_key *key_at_node40(const coord_t * coord, reiser4_key * key)
+{
+	item_header40 *ih;
+
+	assert("nikita-1765", coord_is_existing_item(coord));
+
+	/* @coord is set to existing item */
+	ih = node40_ih_at_coord(coord);
+	memcpy(key, &ih->key, sizeof(reiser4_key));
+	return key;
+}
+
+/* VS-FIXME-HANS: please review whether the below are properly disabled when debugging is disabled */
+
+#define NODE_INCSTAT(n, counter)						\
+	reiser4_stat_inc_at_level(znode_get_level(n), node.lookup.counter)
+
+#define NODE_ADDSTAT(n, counter, val)						\
+	reiser4_stat_add_at_level(znode_get_level(n), node.lookup.counter, val)
+
+/* plugin->u.node.lookup
+   look for description of this method in plugin/node/node.h */
+node_search_result lookup_node40(znode * node /* node to query */ ,
+				 const reiser4_key * key /* key to look for */ ,
+				 lookup_bias bias /* search bias */ ,
+				 coord_t * coord /* resulting coord */ )
+{
+	int left;
+	int right;
+	int found;
+	int items;
+
+	item_header40 *lefth;
+	item_header40 *righth;
+
+	item_plugin *iplug;
+	item_header40 *bstop;
+	item_header40 *ih;
+	cmp_t order;
+
+	assert("nikita-583", node != NULL);
+	assert("nikita-584", key != NULL);
+	assert("nikita-585", coord != NULL);
+	assert("nikita-2693", znode_is_any_locked(node));
+	cassert(REISER4_SEQ_SEARCH_BREAK > 2);
+
+	items = node_num_items(node);
+
+	if (unlikely(items == 0)) {
+		coord_init_first_unit(coord, node);
+		return NS_NOT_FOUND;
+	}
+
+	/* binary search for item that can contain given key */
+	left = 0;
+	right = items - 1;
+	coord->node = node;
+	coord_clear_iplug(coord);
+	found = 0;
+
+	lefth = node40_ih_at(node, left);
+	righth = node40_ih_at(node, right);
+
+	/* It is known that for small arrays sequential search is on average
+	   more efficient than binary. This is because sequential search is
+	   coded as tight loop that can be better optimized by compilers and
+	   for small array size gain from this optimization makes sequential
+	   search the winner. Another, maybe more important, reason for this,
+	   is that sequential array is more CPU cache friendly, whereas binary
+	   search effectively destroys CPU caching.
+
+	   Critical here is the notion of "smallness". Reasonable value of
+	   REISER4_SEQ_SEARCH_BREAK can be found by playing with code in
+	   fs/reiser4/ulevel/ulevel.c:test_search().
+
+	   Don't try to further optimize sequential search by scanning from
+	   right to left in attempt to use more efficient loop termination
+	   condition (comparison with 0). This doesn't work.
+
+	 */
+
+	while (right - left >= REISER4_SEQ_SEARCH_BREAK) {
+		int median;
+		item_header40 *medianh;
+
+		median = (left + right) / 2;
+		medianh = node40_ih_at(node, median);
+
+		assert("nikita-1084", median >= 0);
+		assert("nikita-1085", median < items);
+		switch (keycmp(key, &medianh->key)) {
+		case LESS_THAN:
+			right = median;
+			righth = medianh;
+			break;
+		default:
+			wrong_return_value("nikita-586", "keycmp");
+		case GREATER_THAN:
+			left = median;
+			lefth = medianh;
+			break;
+		case EQUAL_TO:
+			do {
+				--median;
+				/* headers are ordered from right to left */
+				++medianh;
+			} while (median >= 0 && keyeq(key, &medianh->key));
+			right = left = median + 1;
+			ih = lefth = righth = medianh - 1;
+			found = 1;
+			break;
+		}
+	}
+	/* sequential scan. Item headers, and, therefore, keys are stored at
+	   the rightmost part of a node from right to left. We are trying to
+	   access memory from left to right, and hence, scan in _descending_
+	   order of item numbers.
+	 */
+	if (!found) {
+		for (left = right, ih = righth; left >= 0; ++ih, --left) {
+			cmp_t comparison;
+
+			prefetchkey(&(ih + 1)->key);
+			comparison = keycmp(&ih->key, key);
+			if (comparison == GREATER_THAN)
+				continue;
+			if (comparison == EQUAL_TO) {
+				found = 1;
+				do {
+					--left;
+					++ih;
+				} while (left >= 0 && keyeq(&ih->key, key));
+				++left;
+				--ih;
+			} else {
+				assert("nikita-1256", comparison == LESS_THAN);
+			}
+			break;
+		}
+		if (unlikely(left < 0))
+			left = 0;
+	}
+
+	assert("nikita-3212", right >= left);
+	assert("nikita-3214",
+	       equi(found, keyeq(&node40_ih_at(node, left)->key, key)));
+
+	coord_set_item_pos(coord, left);
+	coord->unit_pos = 0;
+	coord->between = AT_UNIT;
+
+	/* key < leftmost key in a mode or node is corrupted and keys
+	   are not sorted  */
+	bstop = node40_ih_at(node, (unsigned)left);
+	order = keycmp(&bstop->key, key);
+	if (unlikely(order == GREATER_THAN)) {
+		if (unlikely(left != 0)) {
+			/* screw up */
+			warning("nikita-587", "Key less than %i key in a node",
+				left);
+			print_key("key", key);
+			print_key("min", &bstop->key);
+			print_coord_content("coord", coord);
+			return RETERR(-EIO);
+		} else {
+			coord->between = BEFORE_UNIT;
+			return NS_NOT_FOUND;
+		}
+	}
+	/* left <= key, ok */
+	iplug = item_plugin_by_disk_id(znode_get_tree(node), &bstop->plugin_id);
+
+	if (unlikely(iplug == NULL)) {
+		warning("nikita-588", "Unknown plugin %i",
+			le16_to_cpu(get_unaligned(&bstop->plugin_id)));
+		print_key("key", key);
+		print_coord_content("coord", coord);
+		return RETERR(-EIO);
+	}
+
+	coord_set_iplug(coord, iplug);
+
+	/* if exact key from item header was found by binary search, no
+	   further checks are necessary. */
+	if (found) {
+		assert("nikita-1259", order == EQUAL_TO);
+		return NS_FOUND;
+	}
+	if (iplug->b.max_key_inside != NULL) {
+		reiser4_key max_item_key;
+
+		/* key > max_item_key --- outside of an item */
+		if (keygt(key, iplug->b.max_key_inside(coord, &max_item_key))) {
+			coord->unit_pos = 0;
+			coord->between = AFTER_ITEM;
+			/* FIXME-VS: key we are looking for does not fit into
+			   found item. Return NS_NOT_FOUND then. Without that
+			   the following case does not work: there is extent of
+			   file 10000, 10001. File 10000, 10002 has been just
+			   created. When writing to position 0 in that file -
+			   traverse_tree will stop here on twig level. When we
+			   want it to go down to leaf level
+			 */
+			return NS_NOT_FOUND;
+		}
+	}
+
+	if (iplug->b.lookup != NULL) {
+		return iplug->b.lookup(key, bias, coord);
+	} else {
+		assert("nikita-1260", order == LESS_THAN);
+		coord->between = AFTER_UNIT;
+		return (bias == FIND_EXACT) ? NS_NOT_FOUND : NS_FOUND;
+	}
+}
+
+#undef NODE_ADDSTAT
+#undef NODE_INCSTAT
+
+/* plugin->u.node.estimate
+   look for description of this method in plugin/node/node.h */
+size_t estimate_node40(znode * node)
+{
+	size_t result;
+
+	assert("nikita-597", node != NULL);
+
+	result = free_space_node40(node) - sizeof(item_header40);
+
+	return (result > 0) ? result : 0;
+}
+
+/* plugin->u.node.check
+   look for description of this method in plugin/node/node.h */
+int check_node40(const znode * node /* node to check */ ,
+		 __u32 flags /* check flags */ ,
+		 const char **error /* where to store error message */ )
+{
+	int nr_items;
+	int i;
+	reiser4_key prev;
+	unsigned old_offset;
+	tree_level level;
+	coord_t coord;
+	int result;
+
+	assert("nikita-580", node != NULL);
+	assert("nikita-581", error != NULL);
+	assert("nikita-2948", znode_is_loaded(node));
+
+	if (ZF_ISSET(node, JNODE_HEARD_BANSHEE))
+		return 0;
+
+	assert("nikita-582", zdata(node) != NULL);
+
+	nr_items = node40_num_of_items_internal(node);
+	if (nr_items < 0) {
+		*error = "Negative number of items";
+		return -1;
+	}
+
+	if (flags & REISER4_NODE_DKEYS)
+		prev = *znode_get_ld_key((znode *) node);
+	else
+		prev = *min_key();
+
+	old_offset = 0;
+	coord_init_zero(&coord);
+	coord.node = (znode *) node;
+	coord.unit_pos = 0;
+	coord.between = AT_UNIT;
+	level = znode_get_level(node);
+	for (i = 0; i < nr_items; i++) {
+		item_header40 *ih;
+		reiser4_key unit_key;
+		unsigned j;
+
+		ih = node40_ih_at(node, (unsigned)i);
+		coord_set_item_pos(&coord, i);
+		if ((ih40_get_offset(ih) >=
+		     znode_size(node) - nr_items * sizeof(item_header40)) ||
+		    (ih40_get_offset(ih) < sizeof(node40_header))) {
+			*error = "Offset is out of bounds";
+			return -1;
+		}
+		if (ih40_get_offset(ih) <= old_offset) {
+			*error = "Offsets are in wrong order";
+			return -1;
+		}
+		if ((i == 0) && (ih40_get_offset(ih) != sizeof(node40_header))) {
+			*error = "Wrong offset of first item";
+			return -1;
+		}
+		old_offset = ih40_get_offset(ih);
+
+		if (keygt(&prev, &ih->key)) {
+			*error = "Keys are in wrong order";
+			return -1;
+		}
+		if (!keyeq(&ih->key, unit_key_by_coord(&coord, &unit_key))) {
+			*error = "Wrong key of first unit";
+			return -1;
+		}
+		prev = ih->key;
+		for (j = 0; j < coord_num_units(&coord); ++j) {
+			coord.unit_pos = j;
+			unit_key_by_coord(&coord, &unit_key);
+			if (keygt(&prev, &unit_key)) {
+				*error = "Unit keys are in wrong order";
+				return -1;
+			}
+			prev = unit_key;
+		}
+		coord.unit_pos = 0;
+		if (level != TWIG_LEVEL && item_is_extent(&coord)) {
+			*error = "extent on the wrong level";
+			return -1;
+		}
+		if (level == LEAF_LEVEL && item_is_internal(&coord)) {
+			*error = "internal item on the wrong level";
+			return -1;
+		}
+		if (level != LEAF_LEVEL &&
+		    !item_is_internal(&coord) && !item_is_extent(&coord)) {
+			*error = "wrong item on the internal level";
+			return -1;
+		}
+		if (level > TWIG_LEVEL && !item_is_internal(&coord)) {
+			*error = "non-internal item on the internal level";
+			return -1;
+		}
+#if REISER4_DEBUG
+		if (item_plugin_by_coord(&coord)->b.check
+		    && item_plugin_by_coord(&coord)->b.check(&coord, error))
+			return -1;
+#endif
+		if (i) {
+			coord_t prev_coord;
+			/* two neighboring items can not be mergeable */
+			coord_dup(&prev_coord, &coord);
+			coord_prev_item(&prev_coord);
+			if (are_items_mergeable(&prev_coord, &coord)) {
+				*error = "mergeable items in one node";
+				return -1;
+			}
+
+		}
+	}
+
+	if ((flags & REISER4_NODE_DKEYS) && !node_is_empty(node)) {
+		coord_t coord;
+		item_plugin *iplug;
+
+		coord_init_last_unit(&coord, node);
+		iplug = item_plugin_by_coord(&coord);
+		if ((item_is_extent(&coord) || item_is_tail(&coord)) &&
+		    iplug->s.file.append_key != NULL) {
+			reiser4_key mkey;
+
+			iplug->s.file.append_key(&coord, &mkey);
+			set_key_offset(&mkey, get_key_offset(&mkey) - 1);
+			read_lock_dk(current_tree);
+			result = keygt(&mkey, znode_get_rd_key((znode *) node));
+			read_unlock_dk(current_tree);
+			if (result) {
+				*error = "key of rightmost item is too large";
+				return -1;
+			}
+		}
+	}
+	if (flags & REISER4_NODE_DKEYS) {
+		read_lock_tree(current_tree);
+		read_lock_dk(current_tree);
+
+		flags |= REISER4_NODE_TREE_STABLE;
+
+		if (keygt(&prev, znode_get_rd_key((znode *) node))) {
+			if (flags & REISER4_NODE_TREE_STABLE) {
+				*error = "Last key is greater than rdkey";
+				read_unlock_dk(current_tree);
+				read_unlock_tree(current_tree);
+				return -1;
+			}
+		}
+		if (keygt
+		    (znode_get_ld_key((znode *) node),
+		     znode_get_rd_key((znode *) node))) {
+			*error = "ldkey is greater than rdkey";
+			read_unlock_dk(current_tree);
+			read_unlock_tree(current_tree);
+			return -1;
+		}
+		if (ZF_ISSET(node, JNODE_LEFT_CONNECTED) &&
+		    (node->left != NULL) &&
+		    !ZF_ISSET(node->left, JNODE_HEARD_BANSHEE) &&
+		    ergo(flags & REISER4_NODE_TREE_STABLE,
+			 !keyeq(znode_get_rd_key(node->left),
+				znode_get_ld_key((znode *) node)))
+		    && ergo(!(flags & REISER4_NODE_TREE_STABLE),
+			    keygt(znode_get_rd_key(node->left),
+				  znode_get_ld_key((znode *) node)))) {
+			*error = "left rdkey or ldkey is wrong";
+ 			read_unlock_dk(current_tree);
+			read_unlock_tree(current_tree);
+			return -1;
+		}
+		if (ZF_ISSET(node, JNODE_RIGHT_CONNECTED) &&
+		    (node->right != NULL) &&
+		    !ZF_ISSET(node->right, JNODE_HEARD_BANSHEE) &&
+		    ergo(flags & REISER4_NODE_TREE_STABLE,
+			 !keyeq(znode_get_rd_key((znode *) node),
+				znode_get_ld_key(node->right)))
+		    && ergo(!(flags & REISER4_NODE_TREE_STABLE),
+			    keygt(znode_get_rd_key((znode *) node),
+				  znode_get_ld_key(node->right)))) {
+			*error = "rdkey or right ldkey is wrong";
+ 			read_unlock_dk(current_tree);
+			read_unlock_tree(current_tree);
+			return -1;
+		}
+
+		read_unlock_dk(current_tree);
+		read_unlock_tree(current_tree);
+	}
+
+	return 0;
+}
+
+/* plugin->u.node.parse
+   look for description of this method in plugin/node/node.h */
+int parse_node40(znode * node /* node to parse */ )
+{
+	node40_header *header;
+	int result;
+	d8 level;
+
+	header = node40_node_header((znode *) node);
+	result = -EIO;
+	level = nh40_get_level(header);
+	if (unlikely(((__u8) znode_get_level(node)) != level))
+		warning("nikita-494", "Wrong level found in node: %i != %i",
+			znode_get_level(node), level);
+	else if (unlikely(nh40_get_magic(header) != REISER4_NODE_MAGIC))
+		warning("nikita-495",
+			"Wrong magic in tree node: want %x, got %x",
+			REISER4_NODE_MAGIC, nh40_get_magic(header));
+	else {
+		node->nr_items = node40_num_of_items_internal(node);
+		result = 0;
+	}
+	if (unlikely(result != 0))
+		/* print_znode("node", node) */ ;
+	return RETERR(result);
+}
+
+/* plugin->u.node.init
+   look for description of this method in plugin/node/node.h */
+int init_node40(znode * node /* node to initialise */ )
+{
+	node40_header *header;
+
+	assert("nikita-570", node != NULL);
+	assert("nikita-572", zdata(node) != NULL);
+
+	header = node40_node_header(node);
+	memset(header, 0, sizeof(node40_header));
+	nh40_set_free_space(header, znode_size(node) - sizeof(node40_header));
+	nh40_set_free_space_start(header, sizeof(node40_header));
+	/* sane hypothesis: 0 in CPU format is 0 in disk format */
+	/* items: 0 */
+	save_plugin_id(node_plugin_to_plugin(node->nplug),
+		       &header->common_header.plugin_id);
+	nh40_set_level(header, znode_get_level(node));
+	nh40_set_magic(header, REISER4_NODE_MAGIC);
+	node->nr_items = 0;
+	nh40_set_mkfs_id(header, reiser4_mkfs_id(reiser4_get_current_sb()));
+
+	/* flags: 0 */
+	return 0;
+}
+
+#ifdef GUESS_EXISTS
+int guess_node40(const znode * node /* node to guess plugin of */ )
+{
+	node40_header *nethack;
+
+	assert("nikita-1058", node != NULL);
+	nethack = node40_node_header(node);
+	return
+	    (nh40_get_magic(nethack) == REISER4_NODE_MAGIC) &&
+	    (plugin_by_disk_id(znode_get_tree(node),
+			       REISER4_NODE_PLUGIN_TYPE,
+			       &nethack->common_header.plugin_id)->h.id ==
+	     NODE40_ID);
+}
+#endif
+
+/* plugin->u.node.chage_item_size
+   look for description of this method in plugin/node/node.h */
+void change_item_size_node40(coord_t * coord, int by)
+{
+	node40_header *nh;
+	item_header40 *ih;
+	char *item_data;
+	int item_length;
+	unsigned i;
+
+	/* make sure that @item is coord of existing item */
+	assert("vs-210", coord_is_existing_item(coord));
+
+	nh = node40_node_header(coord->node);
+
+	item_data = item_by_coord_node40(coord);
+	item_length = length_by_coord_node40(coord);
+
+	/* move item bodies */
+	ih = node40_ih_at_coord(coord);
+	memmove(item_data + item_length + by, item_data + item_length,
+		nh40_get_free_space_start(node40_node_header(coord->node)) -
+		(ih40_get_offset(ih) + item_length));
+
+	/* update offsets of moved items */
+	for (i = coord->item_pos + 1; i < nh40_get_num_items(nh); i++) {
+		ih = node40_ih_at(coord->node, i);
+		ih40_set_offset(ih, ih40_get_offset(ih) + by);
+	}
+
+	/* update node header */
+	nh40_set_free_space(nh, nh40_get_free_space(nh) - by);
+	nh40_set_free_space_start(nh, nh40_get_free_space_start(nh) + by);
+}
+
+static int should_notify_parent(const znode * node)
+{
+	/* FIXME_JMACD This looks equivalent to znode_is_root(), right? -josh */
+	return !disk_addr_eq(znode_get_block(node),
+			     &znode_get_tree(node)->root_block);
+}
+
+/* plugin->u.node.create_item
+   look for description of this method in plugin/node/node.h */
+int
+create_item_node40(coord_t *target, const reiser4_key *key,
+		   reiser4_item_data *data, carry_plugin_info *info)
+{
+	node40_header *nh;
+	item_header40 *ih;
+	unsigned offset;
+	unsigned i;
+
+	nh = node40_node_header(target->node);
+
+	assert("vs-212", coord_is_between_items(target));
+	/* node must have enough free space */
+	assert("vs-254",
+	       free_space_node40(target->node) >=
+	       data->length + sizeof(item_header40));
+	assert("vs-1410", data->length >= 0);
+
+	if (coord_set_to_right(target))
+		/* there are not items to the right of @target, so, new item
+		   will be inserted after last one */
+		coord_set_item_pos(target, nh40_get_num_items(nh));
+
+	if (target->item_pos < nh40_get_num_items(nh)) {
+		/* there are items to be moved to prepare space for new
+		   item */
+		ih = node40_ih_at_coord(target);
+		/* new item will start at this offset */
+		offset = ih40_get_offset(ih);
+
+		memmove(zdata(target->node) + offset + data->length,
+			zdata(target->node) + offset,
+			nh40_get_free_space_start(nh) - offset);
+		/* update headers of moved items */
+		for (i = target->item_pos; i < nh40_get_num_items(nh); i++) {
+			ih = node40_ih_at(target->node, i);
+			ih40_set_offset(ih, ih40_get_offset(ih) + data->length);
+		}
+
+		/* @ih is set to item header of the last item, move item headers */
+		memmove(ih - 1, ih,
+			sizeof(item_header40) * (nh40_get_num_items(nh) -
+						 target->item_pos));
+	} else {
+		/* new item will start at this offset */
+		offset = nh40_get_free_space_start(nh);
+	}
+
+	/* make item header for the new item */
+	ih = node40_ih_at_coord(target);
+	memcpy(&ih->key, key, sizeof(reiser4_key));
+	ih40_set_offset(ih, offset);
+	save_plugin_id(item_plugin_to_plugin(data->iplug), &ih->plugin_id);
+
+	/* update node header */
+	nh40_set_free_space(nh,
+			    nh40_get_free_space(nh) - data->length -
+			    sizeof(item_header40));
+	nh40_set_free_space_start(nh,
+				  nh40_get_free_space_start(nh) + data->length);
+	node40_set_num_items(target->node, nh, nh40_get_num_items(nh) + 1);
+
+	/* FIXME: check how does create_item work when between is set to BEFORE_UNIT */
+	target->unit_pos = 0;
+	target->between = AT_UNIT;
+	coord_clear_iplug(target);
+
+	/* initialize item */
+	if (data->iplug->b.init != NULL) {
+		data->iplug->b.init(target, NULL, data);
+	}
+	/* copy item body */
+	if (data->iplug->b.paste != NULL) {
+		data->iplug->b.paste(target, data, info);
+	} else if (data->data != NULL) {
+		if (data->user) {
+			/* AUDIT: Are we really should not check that pointer
+			   from userspace was valid and data bytes were
+			   available? How will we return -EFAULT of some kind
+			   without this check? */
+			assert("nikita-3038", schedulable());
+			/* copy data from user space */
+			__copy_from_user(zdata(target->node) + offset,
+					 (const char __user *)data->data,
+					 (unsigned)data->length);
+		} else
+			/* copy from kernel space */
+			memcpy(zdata(target->node) + offset, data->data,
+			       (unsigned)data->length);
+	}
+
+	if (target->item_pos == 0) {
+		/* left delimiting key has to be updated */
+		prepare_for_update(NULL, target->node, info);
+	}
+
+	if (item_plugin_by_coord(target)->b.create_hook != NULL) {
+		item_plugin_by_coord(target)->b.create_hook(target, data->arg);
+	}
+
+	return 0;
+}
+
+/* plugin->u.node.update_item_key
+   look for description of this method in plugin/node/node.h */
+void
+update_item_key_node40(coord_t * target, const reiser4_key * key,
+		       carry_plugin_info * info)
+{
+	item_header40 *ih;
+
+	ih = node40_ih_at_coord(target);
+	memcpy(&ih->key, key, sizeof(reiser4_key));
+
+	if (target->item_pos == 0) {
+		prepare_for_update(NULL, target->node, info);
+	}
+}
+
+/* this bits encode cut mode */
+#define CMODE_TAIL 1
+#define CMODE_WHOLE 2
+#define CMODE_HEAD 4
+
+struct cut40_info {
+	int mode;
+	pos_in_node_t tail_removed;	/* position of item which gets tail removed */
+	pos_in_node_t first_removed;	/* position of first the leftmost item among items removed completely */
+	pos_in_node_t removed_count;	/* number of items removed completely */
+	pos_in_node_t head_removed;	/* position of item which gets head removed */
+
+	pos_in_node_t freed_space_start;
+	pos_in_node_t freed_space_end;
+	pos_in_node_t first_moved;
+	pos_in_node_t head_removed_location;
+};
+
+static void init_cinfo(struct cut40_info *cinfo)
+{
+	cinfo->mode = 0;
+	cinfo->tail_removed = MAX_POS_IN_NODE;
+	cinfo->first_removed = MAX_POS_IN_NODE;
+	cinfo->removed_count = MAX_POS_IN_NODE;
+	cinfo->head_removed = MAX_POS_IN_NODE;
+	cinfo->freed_space_start = MAX_POS_IN_NODE;
+	cinfo->freed_space_end = MAX_POS_IN_NODE;
+	cinfo->first_moved = MAX_POS_IN_NODE;
+	cinfo->head_removed_location = MAX_POS_IN_NODE;
+}
+
+/* complete cut_node40/kill_node40 content by removing the gap created by */
+static void compact(znode * node, struct cut40_info *cinfo)
+{
+	node40_header *nh;
+	item_header40 *ih;
+	pos_in_node_t freed;
+	pos_in_node_t pos, nr_items;
+
+	assert("vs-1526", (cinfo->freed_space_start != MAX_POS_IN_NODE &&
+			   cinfo->freed_space_end != MAX_POS_IN_NODE &&
+			   cinfo->first_moved != MAX_POS_IN_NODE));
+	assert("vs-1523", cinfo->freed_space_end >= cinfo->freed_space_start);
+
+	nh = node40_node_header(node);
+	nr_items = nh40_get_num_items(nh);
+
+	/* remove gap made up by removal */
+	memmove(zdata(node) + cinfo->freed_space_start,
+		zdata(node) + cinfo->freed_space_end,
+		nh40_get_free_space_start(nh) - cinfo->freed_space_end);
+
+	/* update item headers of moved items - change their locations */
+	pos = cinfo->first_moved;
+	ih = node40_ih_at(node, pos);
+	if (cinfo->head_removed_location != MAX_POS_IN_NODE) {
+		assert("vs-1580", pos == cinfo->head_removed);
+		ih40_set_offset(ih, cinfo->head_removed_location);
+		pos++;
+		ih--;
+	}
+
+	freed = cinfo->freed_space_end - cinfo->freed_space_start;
+	for (; pos < nr_items; pos++, ih--) {
+		assert("vs-1581", ih == node40_ih_at(node, pos));
+		ih40_set_offset(ih, ih40_get_offset(ih) - freed);
+	}
+
+	/* free space start moved to right */
+	nh40_set_free_space_start(nh, nh40_get_free_space_start(nh) - freed);
+
+	if (cinfo->removed_count != MAX_POS_IN_NODE) {
+		/* number of items changed. Remove item headers of those items */
+		ih = node40_ih_at(node, nr_items - 1);
+		memmove(ih + cinfo->removed_count, ih,
+			sizeof(item_header40) * (nr_items -
+						 cinfo->removed_count -
+						 cinfo->first_removed));
+		freed += sizeof(item_header40) * cinfo->removed_count;
+		node40_set_num_items(node, nh, nr_items - cinfo->removed_count);
+	}
+
+	/* total amount of free space increased */
+	nh40_set_free_space(nh, nh40_get_free_space(nh) + freed);
+}
+
+int shrink_item_node40(coord_t * coord, int delta)
+{
+	node40_header *nh;
+	item_header40 *ih;
+	pos_in_node_t pos;
+	pos_in_node_t nr_items;
+	char *end;
+	znode *node;
+
+	assert("nikita-3487", coord != NULL);
+	assert("nikita-3488", delta >= 0);
+
+	node = coord->node;
+	nh = node40_node_header(node);
+	nr_items = nh40_get_num_items(nh);
+
+	ih = node40_ih_at_coord(coord);
+	assert("nikita-3489", delta <= length_by_coord_node40(coord));
+	end = zdata(node) + ih40_get_offset(ih) + length_by_coord_node40(coord);
+
+	/* remove gap made up by removal */
+	memmove(end - delta, end, nh40_get_free_space_start(nh) - delta);
+
+	/* update item headers of moved items - change their locations */
+	pos = coord->item_pos + 1;
+	ih = node40_ih_at(node, pos);
+	for (; pos < nr_items; pos++, ih--) {
+		assert("nikita-3490", ih == node40_ih_at(node, pos));
+		ih40_set_offset(ih, ih40_get_offset(ih) - delta);
+	}
+
+	/* free space start moved to left */
+	nh40_set_free_space_start(nh, nh40_get_free_space_start(nh) - delta);
+	/* total amount of free space increased */
+	nh40_set_free_space(nh, nh40_get_free_space(nh) + delta);
+	/*
+	 * This method does _not_ changes number of items. Hence, it cannot
+	 * make node empty. Also it doesn't remove items at all, which means
+	 * that no keys have to be updated either.
+	 */
+	return 0;
+}
+
+/* this is used by cut_node40 and kill_node40. It analyses input parameters and calculates cut mode. There are 2 types
+   of cut. First is when a unit is removed from the middle of an item.  In this case this function returns 1. All the
+   rest fits into second case: 0 or 1 of items getting tail cut, 0 or more items removed completely and 0 or 1 item
+   getting head cut. Function returns 0 in this case */
+static int
+parse_cut(struct cut40_info *cinfo, const struct cut_kill_params *params)
+{
+	reiser4_key left_key, right_key;
+	reiser4_key min_from_key, max_to_key;
+	const reiser4_key *from_key, *to_key;
+
+	init_cinfo(cinfo);
+
+	/* calculate minimal key stored in first item of items to be cut (params->from) */
+	item_key_by_coord(params->from, &min_from_key);
+	/* and max key stored in last item of items to be cut (params->to) */
+	max_item_key_by_coord(params->to, &max_to_key);
+
+	/* if cut key range is not defined in input parameters - define it using cut coord range */
+	if (params->from_key == NULL) {
+		assert("vs-1513", params->to_key == NULL);
+		unit_key_by_coord(params->from, &left_key);
+		from_key = &left_key;
+		max_unit_key_by_coord(params->to, &right_key);
+		to_key = &right_key;
+	} else {
+		from_key = params->from_key;
+		to_key = params->to_key;
+	}
+
+	if (params->from->item_pos == params->to->item_pos) {
+		if (keylt(&min_from_key, from_key)
+		    && keylt(to_key, &max_to_key))
+			return 1;
+
+		if (keygt(from_key, &min_from_key)) {
+			/* tail of item is to be cut cut */
+			cinfo->tail_removed = params->from->item_pos;
+			cinfo->mode |= CMODE_TAIL;
+		} else if (keylt(to_key, &max_to_key)) {
+			/* head of item is to be cut */
+			cinfo->head_removed = params->from->item_pos;
+			cinfo->mode |= CMODE_HEAD;
+		} else {
+			/* item is removed completely */
+			cinfo->first_removed = params->from->item_pos;
+			cinfo->removed_count = 1;
+			cinfo->mode |= CMODE_WHOLE;
+		}
+	} else {
+		cinfo->first_removed = params->from->item_pos + 1;
+		cinfo->removed_count =
+		    params->to->item_pos - params->from->item_pos - 1;
+
+		if (keygt(from_key, &min_from_key)) {
+			/* first item is not cut completely */
+			cinfo->tail_removed = params->from->item_pos;
+			cinfo->mode |= CMODE_TAIL;
+		} else {
+			cinfo->first_removed--;
+			cinfo->removed_count++;
+		}
+		if (keylt(to_key, &max_to_key)) {
+			/* last item is not cut completely */
+			cinfo->head_removed = params->to->item_pos;
+			cinfo->mode |= CMODE_HEAD;
+		} else {
+			cinfo->removed_count++;
+		}
+		if (cinfo->removed_count)
+			cinfo->mode |= CMODE_WHOLE;
+	}
+
+	return 0;
+}
+
+static void
+call_kill_hooks(znode * node, pos_in_node_t from, pos_in_node_t count,
+		carry_kill_data * kdata)
+{
+	coord_t coord;
+	item_plugin *iplug;
+	pos_in_node_t pos;
+
+	coord.node = node;
+	coord.unit_pos = 0;
+	coord.between = AT_UNIT;
+	for (pos = 0; pos < count; pos++) {
+		coord_set_item_pos(&coord, from + pos);
+		coord.unit_pos = 0;
+		coord.between = AT_UNIT;
+		iplug = item_plugin_by_coord(&coord);
+		if (iplug->b.kill_hook) {
+			iplug->b.kill_hook(&coord, 0, coord_num_units(&coord),
+					   kdata);
+		}
+	}
+}
+
+/* this is used to kill item partially */
+static pos_in_node_t
+kill_units(coord_t * coord, pos_in_node_t from, pos_in_node_t to, void *data,
+	   reiser4_key * smallest_removed, reiser4_key * new_first_key)
+{
+	struct carry_kill_data *kdata;
+	item_plugin *iplug;
+
+	kdata = data;
+	iplug = item_plugin_by_coord(coord);
+
+	assert("vs-1524", iplug->b.kill_units);
+	return iplug->b.kill_units(coord, from, to, kdata, smallest_removed,
+				   new_first_key);
+}
+
+/* call item plugin to cut tail of file */
+static pos_in_node_t
+kill_tail(coord_t * coord, void *data, reiser4_key * smallest_removed)
+{
+	struct carry_kill_data *kdata;
+	pos_in_node_t to;
+
+	kdata = data;
+	to = coord_last_unit_pos(coord);
+	return kill_units(coord, coord->unit_pos, to, kdata, smallest_removed,
+			  NULL);
+}
+
+/* call item plugin to cut head of item */
+static pos_in_node_t
+kill_head(coord_t * coord, void *data, reiser4_key * smallest_removed,
+	  reiser4_key * new_first_key)
+{
+	return kill_units(coord, 0, coord->unit_pos, data, smallest_removed,
+			  new_first_key);
+}
+
+/* this is used to cut item partially */
+static pos_in_node_t
+cut_units(coord_t * coord, pos_in_node_t from, pos_in_node_t to, void *data,
+	  reiser4_key * smallest_removed, reiser4_key * new_first_key)
+{
+	carry_cut_data *cdata;
+	item_plugin *iplug;
+
+	cdata = data;
+	iplug = item_plugin_by_coord(coord);
+	assert("vs-302", iplug->b.cut_units);
+	return iplug->b.cut_units(coord, from, to, cdata, smallest_removed,
+				  new_first_key);
+}
+
+/* call item plugin to cut tail of file */
+static pos_in_node_t
+cut_tail(coord_t * coord, void *data, reiser4_key * smallest_removed)
+{
+	carry_cut_data *cdata;
+	pos_in_node_t to;
+
+	cdata = data;
+	to = coord_last_unit_pos(cdata->params.from);
+	return cut_units(coord, coord->unit_pos, to, data, smallest_removed, NULL);
+}
+
+/* call item plugin to cut head of item */
+static pos_in_node_t
+cut_head(coord_t * coord, void *data, reiser4_key * smallest_removed,
+	 reiser4_key * new_first_key)
+{
+	return cut_units(coord, 0, coord->unit_pos, data, smallest_removed,
+			 new_first_key);
+}
+
+/* this returns 1 of key of first item changed, 0 - if it did not */
+static int
+prepare_for_compact(struct cut40_info *cinfo,
+		    const struct cut_kill_params *params, int is_cut,
+		    void *data, carry_plugin_info * info)
+{
+	znode *node;
+	item_header40 *ih;
+	pos_in_node_t freed;
+	pos_in_node_t item_pos;
+	coord_t coord;
+	reiser4_key new_first_key;
+	pos_in_node_t(*kill_units_f) (coord_t *, pos_in_node_t, pos_in_node_t,
+				      void *, reiser4_key *, reiser4_key *);
+	pos_in_node_t(*kill_tail_f) (coord_t *, void *, reiser4_key *);
+	pos_in_node_t(*kill_head_f) (coord_t *, void *, reiser4_key *,
+				     reiser4_key *);
+	int retval;
+
+	retval = 0;
+
+	node = params->from->node;
+
+	assert("vs-184", node == params->to->node);
+	assert("vs-312", !node_is_empty(node));
+	assert("vs-297",
+	       coord_compare(params->from, params->to) != COORD_CMP_ON_RIGHT);
+
+	if (is_cut) {
+		kill_units_f = cut_units;
+		kill_tail_f = cut_tail;
+		kill_head_f = cut_head;
+	} else {
+		kill_units_f = kill_units;
+		kill_tail_f = kill_tail;
+		kill_head_f = kill_head;
+	}
+
+	if (parse_cut(cinfo, params) == 1) {
+		/* cut from the middle of item */
+		freed =
+		    kill_units_f(params->from, params->from->unit_pos,
+				 params->to->unit_pos, data,
+				 params->smallest_removed, NULL);
+
+		item_pos = params->from->item_pos;
+		ih = node40_ih_at(node, item_pos);
+		cinfo->freed_space_start =
+		    ih40_get_offset(ih) + node40_item_length(node,
+							     item_pos) - freed;
+		cinfo->freed_space_end = cinfo->freed_space_start + freed;
+		cinfo->first_moved = item_pos + 1;
+	} else {
+		assert("vs-1521", (cinfo->tail_removed != MAX_POS_IN_NODE ||
+				   cinfo->first_removed != MAX_POS_IN_NODE ||
+				   cinfo->head_removed != MAX_POS_IN_NODE));
+
+		switch (cinfo->mode) {
+		case CMODE_TAIL:
+			/* one item gets cut partially from its end */
+			assert("vs-1562",
+			       cinfo->tail_removed == params->from->item_pos);
+
+			freed =
+			    kill_tail_f(params->from, data,
+					params->smallest_removed);
+
+			item_pos = cinfo->tail_removed;
+			ih = node40_ih_at(node, item_pos);
+			cinfo->freed_space_start =
+			    ih40_get_offset(ih) + node40_item_length(node,
+								     item_pos) -
+			    freed;
+			cinfo->freed_space_end =
+			    cinfo->freed_space_start + freed;
+			cinfo->first_moved = cinfo->tail_removed + 1;
+			break;
+
+		case CMODE_WHOLE:
+			/* one or more items get removed completely */
+			assert("vs-1563",
+			       cinfo->first_removed == params->from->item_pos);
+			assert("vs-1564", cinfo->removed_count > 0
+			       && cinfo->removed_count != MAX_POS_IN_NODE);
+
+			/* call kill hook for all items removed completely */
+			if (is_cut == 0)
+				call_kill_hooks(node, cinfo->first_removed,
+						cinfo->removed_count, data);
+
+			item_pos = cinfo->first_removed;
+			ih = node40_ih_at(node, item_pos);
+
+			if (params->smallest_removed)
+				memcpy(params->smallest_removed, &ih->key,
+				       sizeof(reiser4_key));
+
+			cinfo->freed_space_start = ih40_get_offset(ih);
+
+			item_pos += (cinfo->removed_count - 1);
+			ih -= (cinfo->removed_count - 1);
+			cinfo->freed_space_end =
+			    ih40_get_offset(ih) + node40_item_length(node,
+								     item_pos);
+			cinfo->first_moved = item_pos + 1;
+			if (cinfo->first_removed == 0)
+				/* key of first item of the node changes */
+				retval = 1;
+			break;
+
+		case CMODE_HEAD:
+			/* one item gets cut partially from its head */
+			assert("vs-1565",
+			       cinfo->head_removed == params->from->item_pos);
+
+			freed =
+			    kill_head_f(params->to, data,
+					params->smallest_removed,
+					&new_first_key);
+
+			item_pos = cinfo->head_removed;
+			ih = node40_ih_at(node, item_pos);
+			cinfo->freed_space_start = ih40_get_offset(ih);
+			cinfo->freed_space_end = ih40_get_offset(ih) + freed;
+			cinfo->first_moved = cinfo->head_removed + 1;
+
+			/* item head is removed, therefore, item key changed */
+			coord.node = node;
+			coord_set_item_pos(&coord, item_pos);
+			coord.unit_pos = 0;
+			coord.between = AT_UNIT;
+			update_item_key_node40(&coord, &new_first_key, NULL);
+			if (item_pos == 0)
+				/* key of first item of the node changes */
+				retval = 1;
+			break;
+
+		case CMODE_TAIL | CMODE_WHOLE:
+			/* one item gets cut from its end and one or more items get removed completely */
+			assert("vs-1566",
+			       cinfo->tail_removed == params->from->item_pos);
+			assert("vs-1567",
+			       cinfo->first_removed == cinfo->tail_removed + 1);
+			assert("vs-1564", cinfo->removed_count > 0
+			       && cinfo->removed_count != MAX_POS_IN_NODE);
+
+			freed =
+			    kill_tail_f(params->from, data,
+					params->smallest_removed);
+
+			item_pos = cinfo->tail_removed;
+			ih = node40_ih_at(node, item_pos);
+			cinfo->freed_space_start =
+			    ih40_get_offset(ih) + node40_item_length(node,
+								     item_pos) -
+			    freed;
+
+			/* call kill hook for all items removed completely */
+			if (is_cut == 0)
+				call_kill_hooks(node, cinfo->first_removed,
+						cinfo->removed_count, data);
+
+			item_pos += cinfo->removed_count;
+			ih -= cinfo->removed_count;
+			cinfo->freed_space_end =
+			    ih40_get_offset(ih) + node40_item_length(node,
+								     item_pos);
+			cinfo->first_moved = item_pos + 1;
+			break;
+
+		case CMODE_WHOLE | CMODE_HEAD:
+			/* one or more items get removed completely and one item gets cut partially from its head */
+			assert("vs-1568",
+			       cinfo->first_removed == params->from->item_pos);
+			assert("vs-1564", cinfo->removed_count > 0
+			       && cinfo->removed_count != MAX_POS_IN_NODE);
+			assert("vs-1569",
+			       cinfo->head_removed ==
+			       cinfo->first_removed + cinfo->removed_count);
+
+			/* call kill hook for all items removed completely */
+			if (is_cut == 0)
+				call_kill_hooks(node, cinfo->first_removed,
+						cinfo->removed_count, data);
+
+			item_pos = cinfo->first_removed;
+			ih = node40_ih_at(node, item_pos);
+
+			if (params->smallest_removed)
+				memcpy(params->smallest_removed, &ih->key,
+				       sizeof(reiser4_key));
+
+			freed =
+			    kill_head_f(params->to, data, NULL, &new_first_key);
+
+			cinfo->freed_space_start = ih40_get_offset(ih);
+
+			ih = node40_ih_at(node, cinfo->head_removed);
+			/* this is the most complex case. Item which got head removed and items which are to be moved
+			   intact change their location differently. */
+			cinfo->freed_space_end = ih40_get_offset(ih) + freed;
+			cinfo->first_moved = cinfo->head_removed;
+			cinfo->head_removed_location = cinfo->freed_space_start;
+
+			/* item head is removed, therefore, item key changed */
+			coord.node = node;
+			coord_set_item_pos(&coord, cinfo->head_removed);
+			coord.unit_pos = 0;
+			coord.between = AT_UNIT;
+			update_item_key_node40(&coord, &new_first_key, NULL);
+
+			assert("vs-1579", cinfo->first_removed == 0);
+			/* key of first item of the node changes */
+			retval = 1;
+			break;
+
+		case CMODE_TAIL | CMODE_HEAD:
+			/* one item get cut from its end and its neighbor gets cut from its tail */
+			impossible("vs-1576", "this can not happen currently");
+			break;
+
+		case CMODE_TAIL | CMODE_WHOLE | CMODE_HEAD:
+			impossible("vs-1577", "this can not happen currently");
+			break;
+		default:
+			impossible("vs-1578", "unexpected cut mode");
+			break;
+		}
+	}
+	return retval;
+}
+
+/* plugin->u.node.kill
+   return value is number of items removed completely */
+int kill_node40(struct carry_kill_data *kdata, carry_plugin_info * info)
+{
+	znode *node;
+	struct cut40_info cinfo;
+	int first_key_changed;
+
+	node = kdata->params.from->node;
+
+	first_key_changed =
+	    prepare_for_compact(&cinfo, &kdata->params, 0 /* not cut */ , kdata,
+				info);
+	compact(node, &cinfo);
+
+	if (info) {
+		/* it is not called by node40_shift, so we have to take care
+		   of changes on upper levels */
+		if (node_is_empty(node)
+		    && !(kdata->flags & DELETE_RETAIN_EMPTY))
+			/* all contents of node is deleted */
+			prepare_removal_node40(node, info);
+		else if (first_key_changed) {
+			prepare_for_update(NULL, node, info);
+		}
+	}
+
+	coord_clear_iplug(kdata->params.from);
+	coord_clear_iplug(kdata->params.to);
+
+	znode_make_dirty(node);
+	return cinfo.removed_count == MAX_POS_IN_NODE ? 0 : cinfo.removed_count;
+}
+
+/* plugin->u.node.cut
+   return value is number of items removed completely */
+int cut_node40(struct carry_cut_data *cdata, carry_plugin_info * info)
+{
+	znode *node;
+	struct cut40_info cinfo;
+	int first_key_changed;
+
+	node = cdata->params.from->node;
+
+	first_key_changed =
+	    prepare_for_compact(&cinfo, &cdata->params, 1 /* not cut */ , cdata,
+				info);
+	compact(node, &cinfo);
+
+	if (info) {
+		/* it is not called by node40_shift, so we have to take care
+		   of changes on upper levels */
+		if (node_is_empty(node))
+			/* all contents of node is deleted */
+			prepare_removal_node40(node, info);
+		else if (first_key_changed) {
+			prepare_for_update(NULL, node, info);
+		}
+	}
+
+	coord_clear_iplug(cdata->params.from);
+	coord_clear_iplug(cdata->params.to);
+
+	znode_make_dirty(node);
+	return cinfo.removed_count == MAX_POS_IN_NODE ? 0 : cinfo.removed_count;
+}
+
+/* this structure is used by shift method of node40 plugin */
+struct shift_params {
+	shift_direction pend;	/* when @pend == append - we are shifting to
+				   left, when @pend == prepend - to right */
+	coord_t wish_stop;	/* when shifting to left this is last unit we
+				   want shifted, when shifting to right - this
+				   is set to unit we want to start shifting
+				   from */
+	znode *target;
+	int everything;		/* it is set to 1 if everything we have to shift is
+				   shifted, 0 - otherwise */
+
+	/* FIXME-VS: get rid of read_stop */
+
+	/* these are set by estimate_shift */
+	coord_t real_stop;	/* this will be set to last unit which will be
+				   really shifted */
+
+	/* coordinate in source node before operation of unit which becomes
+	   first after shift to left of last after shift to right */
+	union {
+		coord_t future_first;
+		coord_t future_last;
+	} u;
+
+	unsigned merging_units;	/* number of units of first item which have to
+				   be merged with last item of target node */
+	unsigned merging_bytes;	/* number of bytes in those units */
+
+	unsigned entire;	/* items shifted in their entirety */
+	unsigned entire_bytes;	/* number of bytes in those items */
+
+	unsigned part_units;	/* number of units of partially copied item */
+	unsigned part_bytes;	/* number of bytes in those units */
+
+	unsigned shift_bytes;	/* total number of bytes in items shifted (item
+				   headers not included) */
+
+};
+
+static int item_creation_overhead(coord_t *item)
+{
+	return node_plugin_by_coord(item)->item_overhead(item->node, NULL);
+}
+
+/* how many units are there in @source starting from source->unit_pos
+   but not further than @stop_coord */
+static int
+wanted_units(coord_t *source, coord_t *stop_coord, shift_direction pend)
+{
+	if (pend == SHIFT_LEFT) {
+		assert("vs-181", source->unit_pos == 0);
+	} else {
+		assert("vs-182",
+		       source->unit_pos == coord_last_unit_pos(source));
+	}
+
+	if (source->item_pos != stop_coord->item_pos) {
+		/* @source and @stop_coord are different items */
+		return coord_last_unit_pos(source) + 1;
+	}
+
+	if (pend == SHIFT_LEFT) {
+		return stop_coord->unit_pos + 1;
+	} else {
+		return source->unit_pos - stop_coord->unit_pos + 1;
+	}
+}
+
+/* this calculates what can be copied from @shift->wish_stop.node to
+   @shift->target */
+static void
+estimate_shift(struct shift_params *shift, const reiser4_context * ctx)
+{
+	unsigned target_free_space, size;
+	pos_in_node_t stop_item;	/* item which estimating should not consider */
+	unsigned want;		/* number of units of item we want shifted */
+	coord_t source;		/* item being estimated */
+	item_plugin *iplug;
+
+	/* shifting to left/right starts from first/last units of
+	   @shift->wish_stop.node */
+	if (shift->pend == SHIFT_LEFT) {
+		coord_init_first_unit(&source, shift->wish_stop.node);
+	} else {
+		coord_init_last_unit(&source, shift->wish_stop.node);
+	}
+	shift->real_stop = source;
+
+	/* free space in target node and number of items in source */
+	target_free_space = znode_free_space(shift->target);
+
+	shift->everything = 0;
+	if (!node_is_empty(shift->target)) {
+		/* target node is not empty, check for boundary items
+		   mergeability */
+		coord_t to;
+
+		/* item we try to merge @source with */
+		if (shift->pend == SHIFT_LEFT) {
+			coord_init_last_unit(&to, shift->target);
+		} else {
+			coord_init_first_unit(&to, shift->target);
+		}
+
+		if ((shift->pend == SHIFT_LEFT) ? are_items_mergeable(&to,
+								      &source) :
+		    are_items_mergeable(&source, &to)) {
+			/* how many units of @source do we want to merge to
+			   item @to */
+			want =
+			    wanted_units(&source, &shift->wish_stop,
+					 shift->pend);
+
+			/* how many units of @source we can merge to item
+			   @to */
+			iplug = item_plugin_by_coord(&source);
+			if (iplug->b.can_shift != NULL)
+				shift->merging_units =
+				    iplug->b.can_shift(target_free_space,
+						       &source, shift->target,
+						       shift->pend, &size,
+						       want);
+			else {
+				shift->merging_units = 0;
+				size = 0;
+			}
+			shift->merging_bytes = size;
+			shift->shift_bytes += size;
+			/* update stop coord to be set to last unit of @source
+			   we can merge to @target */
+			if (shift->merging_units)
+				/* at least one unit can be shifted */
+				shift->real_stop.unit_pos =
+				    (shift->merging_units - source.unit_pos -
+				     1) * shift->pend;
+			else {
+				/* nothing can be shifted */
+				if (shift->pend == SHIFT_LEFT)
+					coord_init_before_first_item(&shift->
+								     real_stop,
+								     source.
+								     node);
+				else
+					coord_init_after_last_item(&shift->
+								   real_stop,
+								   source.node);
+			}
+			assert("nikita-2081", shift->real_stop.unit_pos + 1);
+
+			if (shift->merging_units != want) {
+				/* we could not copy as many as we want, so,
+				   there is no reason for estimating any
+				   longer */
+				return;
+			}
+
+			target_free_space -= size;
+			coord_add_item_pos(&source, shift->pend);
+		}
+	}
+
+	/* number of item nothing of which we want to shift */
+	stop_item = shift->wish_stop.item_pos + shift->pend;
+
+	/* calculate how many items can be copied into given free
+	   space as whole */
+	for (; source.item_pos != stop_item;
+	     coord_add_item_pos(&source, shift->pend)) {
+		if (shift->pend == SHIFT_RIGHT)
+			source.unit_pos = coord_last_unit_pos(&source);
+
+		/* how many units of @source do we want to copy */
+		want = wanted_units(&source, &shift->wish_stop, shift->pend);
+
+		if (want == coord_last_unit_pos(&source) + 1) {
+			/* we want this item to be copied entirely */
+			size =
+			    item_length_by_coord(&source) +
+			    item_creation_overhead(&source);
+			if (size <= target_free_space) {
+				/* item fits into target node as whole */
+				target_free_space -= size;
+				shift->shift_bytes +=
+				    size - item_creation_overhead(&source);
+				shift->entire_bytes +=
+				    size - item_creation_overhead(&source);
+				shift->entire++;
+
+				/* update shift->real_stop coord to be set to
+				   last unit of @source we can merge to
+				   @target */
+				shift->real_stop = source;
+				if (shift->pend == SHIFT_LEFT)
+					shift->real_stop.unit_pos =
+					    coord_last_unit_pos(&shift->
+								real_stop);
+				else
+					shift->real_stop.unit_pos = 0;
+				continue;
+			}
+		}
+
+		/* we reach here only for an item which does not fit into
+		   target node in its entirety. This item may be either
+		   partially shifted, or not shifted at all. We will have to
+		   create new item in target node, so decrease amout of free
+		   space by an item creation overhead. We can reach here also
+		   if stop coord is in this item */
+		if (target_free_space >=
+		    (unsigned)item_creation_overhead(&source)) {
+			target_free_space -= item_creation_overhead(&source);
+			iplug = item_plugin_by_coord(&source);
+			if (iplug->b.can_shift) {
+				shift->part_units = iplug->b.can_shift(target_free_space,
+								       &source,
+								       NULL, /* target */
+								       shift->pend,
+								       &size,
+								       want);
+			} else {
+				target_free_space = 0;
+				shift->part_units = 0;
+				size = 0;
+			}
+		} else {
+			target_free_space = 0;
+			shift->part_units = 0;
+			size = 0;
+		}
+		shift->part_bytes = size;
+		shift->shift_bytes += size;
+
+		/* set @shift->real_stop to last unit of @source we can merge
+		   to @shift->target */
+		if (shift->part_units) {
+			shift->real_stop = source;
+			shift->real_stop.unit_pos =
+			    (shift->part_units - source.unit_pos -
+			     1) * shift->pend;
+			assert("nikita-2082", shift->real_stop.unit_pos + 1);
+		}
+
+		if (want != shift->part_units)
+			/* not everything wanted were shifted */
+			return;
+		break;
+	}
+
+	shift->everything = 1;
+}
+
+static void
+copy_units(coord_t * target, coord_t * source, unsigned from, unsigned count,
+	   shift_direction dir, unsigned free_space)
+{
+	item_plugin *iplug;
+
+	assert("nikita-1463", target != NULL);
+	assert("nikita-1464", source != NULL);
+	assert("nikita-1465", from + count <= coord_num_units(source));
+
+	iplug = item_plugin_by_coord(source);
+	assert("nikita-1468", iplug == item_plugin_by_coord(target));
+	iplug->b.copy_units(target, source, from, count, dir, free_space);
+
+	if (dir == SHIFT_RIGHT) {
+		/* FIXME-VS: this looks not necessary. update_item_key was
+		   called already by copy_units method */
+		reiser4_key split_key;
+
+		assert("nikita-1469", target->unit_pos == 0);
+
+		unit_key_by_coord(target, &split_key);
+		node_plugin_by_coord(target)->update_item_key(target,
+							      &split_key, NULL);
+	}
+}
+
+/* copy part of @shift->real_stop.node starting either from its beginning or
+   from its end and ending at @shift->real_stop to either the end or the
+   beginning of @shift->target */
+static void copy(struct shift_params *shift)
+{
+	node40_header *nh;
+	coord_t from;
+	coord_t to;
+	item_header40 *from_ih, *to_ih;
+	int free_space_start;
+	int new_items;
+	unsigned old_items;
+	int old_offset;
+	unsigned i;
+
+	nh = node40_node_header(shift->target);
+	free_space_start = nh40_get_free_space_start(nh);
+	old_items = nh40_get_num_items(nh);
+	new_items = shift->entire + (shift->part_units ? 1 : 0);
+	assert("vs-185",
+	       shift->shift_bytes ==
+	       shift->merging_bytes + shift->entire_bytes + shift->part_bytes);
+
+	from = shift->wish_stop;
+
+	coord_init_first_unit(&to, shift->target);
+
+	/* NOTE:NIKITA->VS not sure what I am doing: shift->target is empty,
+	   hence to.between is set to EMPTY_NODE above. Looks like we want it
+	   to be AT_UNIT.
+
+	   Oh, wonders of ->betweeness...
+
+	 */
+	to.between = AT_UNIT;
+
+	if (shift->pend == SHIFT_LEFT) {
+		/* copying to left */
+
+		coord_set_item_pos(&from, 0);
+		from_ih = node40_ih_at(from.node, 0);
+
+		coord_set_item_pos(&to,
+				   node40_num_of_items_internal(to.node) - 1);
+		if (shift->merging_units) {
+			/* expand last item, so that plugin methods will see
+			   correct data */
+			free_space_start += shift->merging_bytes;
+			nh40_set_free_space_start(nh,
+						  (unsigned)free_space_start);
+			nh40_set_free_space(nh,
+					    nh40_get_free_space(nh) -
+					    shift->merging_bytes);
+
+			/* appending last item of @target */
+			copy_units(&to, &from, 0,	/* starting from 0-th unit */
+				   shift->merging_units, SHIFT_LEFT,
+				   shift->merging_bytes);
+			coord_inc_item_pos(&from);
+			from_ih--;
+			coord_inc_item_pos(&to);
+		}
+
+		to_ih = node40_ih_at(shift->target, old_items);
+		if (shift->entire) {
+			/* copy @entire items entirely */
+
+			/* copy item headers */
+			memcpy(to_ih - shift->entire + 1,
+			       from_ih - shift->entire + 1,
+			       shift->entire * sizeof(item_header40));
+			/* update item header offset */
+			old_offset = ih40_get_offset(from_ih);
+			/* AUDIT: Looks like if we calculate old_offset + free_space_start here instead of just old_offset, we can perform one "add" operation less per each iteration */
+			for (i = 0; i < shift->entire; i++, to_ih--, from_ih--)
+				ih40_set_offset(to_ih,
+						ih40_get_offset(from_ih) -
+						old_offset + free_space_start);
+
+			/* copy item bodies */
+			memcpy(zdata(shift->target) + free_space_start, zdata(from.node) + old_offset,	/*ih40_get_offset (from_ih), */
+			       shift->entire_bytes);
+
+			coord_add_item_pos(&from, (int)shift->entire);
+			coord_add_item_pos(&to, (int)shift->entire);
+		}
+
+		nh40_set_free_space_start(nh,
+					  free_space_start +
+					  shift->shift_bytes -
+					  shift->merging_bytes);
+		nh40_set_free_space(nh,
+				    nh40_get_free_space(nh) -
+				    (shift->shift_bytes - shift->merging_bytes +
+				     sizeof(item_header40) * new_items));
+
+		/* update node header */
+		node40_set_num_items(shift->target, nh, old_items + new_items);
+		assert("vs-170",
+		       nh40_get_free_space(nh) < znode_size(shift->target));
+
+		if (shift->part_units) {
+			/* copy heading part (@part units) of @source item as
+			   a new item into @target->node */
+
+			/* copy item header of partially copied item */
+			coord_set_item_pos(&to,
+					   node40_num_of_items_internal(to.node)
+					   - 1);
+			memcpy(to_ih, from_ih, sizeof(item_header40));
+			ih40_set_offset(to_ih,
+					nh40_get_free_space_start(nh) -
+					shift->part_bytes);
+			if (item_plugin_by_coord(&to)->b.init)
+				item_plugin_by_coord(&to)->b.init(&to, &from,
+								  NULL);
+			copy_units(&to, &from, 0, shift->part_units, SHIFT_LEFT,
+				   shift->part_bytes);
+		}
+
+	} else {
+		/* copying to right */
+
+		coord_set_item_pos(&from,
+				   node40_num_of_items_internal(from.node) - 1);
+		from_ih = node40_ih_at_coord(&from);
+
+		coord_set_item_pos(&to, 0);
+
+		/* prepare space for new items */
+		memmove(zdata(to.node) + sizeof(node40_header) +
+			shift->shift_bytes,
+			zdata(to.node) + sizeof(node40_header),
+			free_space_start - sizeof(node40_header));
+		/* update item headers of moved items */
+		to_ih = node40_ih_at(to.node, 0);
+		/* first item gets @merging_bytes longer. free space appears
+		   at its beginning */
+		if (!node_is_empty(to.node))
+			ih40_set_offset(to_ih,
+					ih40_get_offset(to_ih) +
+					shift->shift_bytes -
+					shift->merging_bytes);
+
+		for (i = 1; i < old_items; i++)
+			ih40_set_offset(to_ih - i,
+					ih40_get_offset(to_ih - i) +
+					shift->shift_bytes);
+
+		/* move item headers to make space for new items */
+		memmove(to_ih - old_items + 1 - new_items,
+			to_ih - old_items + 1,
+			sizeof(item_header40) * old_items);
+		to_ih -= (new_items - 1);
+
+		nh40_set_free_space_start(nh,
+					  free_space_start +
+					  shift->shift_bytes);
+		nh40_set_free_space(nh,
+				    nh40_get_free_space(nh) -
+				    (shift->shift_bytes +
+				     sizeof(item_header40) * new_items));
+
+		/* update node header */
+		node40_set_num_items(shift->target, nh, old_items + new_items);
+		assert("vs-170",
+		       nh40_get_free_space(nh) < znode_size(shift->target));
+
+		if (shift->merging_units) {
+			coord_add_item_pos(&to, new_items);
+			to.unit_pos = 0;
+			to.between = AT_UNIT;
+			/* prepend first item of @to */
+			copy_units(&to, &from,
+				   coord_last_unit_pos(&from) -
+				   shift->merging_units + 1,
+				   shift->merging_units, SHIFT_RIGHT,
+				   shift->merging_bytes);
+			coord_dec_item_pos(&from);
+			from_ih++;
+		}
+
+		if (shift->entire) {
+			/* copy @entire items entirely */
+
+			/* copy item headers */
+			memcpy(to_ih, from_ih,
+			       shift->entire * sizeof(item_header40));
+
+			/* update item header offset */
+			old_offset =
+			    ih40_get_offset(from_ih + shift->entire - 1);
+			/* AUDIT: old_offset + sizeof (node40_header) + shift->part_bytes calculation can be taken off the loop. */
+			for (i = 0; i < shift->entire; i++, to_ih++, from_ih++)
+				ih40_set_offset(to_ih,
+						ih40_get_offset(from_ih) -
+						old_offset +
+						sizeof(node40_header) +
+						shift->part_bytes);
+			/* copy item bodies */
+			coord_add_item_pos(&from, -(int)(shift->entire - 1));
+			memcpy(zdata(to.node) + sizeof(node40_header) +
+			       shift->part_bytes, item_by_coord_node40(&from),
+			       shift->entire_bytes);
+			coord_dec_item_pos(&from);
+		}
+
+		if (shift->part_units) {
+			coord_set_item_pos(&to, 0);
+			to.unit_pos = 0;
+			to.between = AT_UNIT;
+			/* copy heading part (@part units) of @source item as
+			   a new item into @target->node */
+
+			/* copy item header of partially copied item */
+			memcpy(to_ih, from_ih, sizeof(item_header40));
+			ih40_set_offset(to_ih, sizeof(node40_header));
+			if (item_plugin_by_coord(&to)->b.init)
+				item_plugin_by_coord(&to)->b.init(&to, &from,
+								  NULL);
+			copy_units(&to, &from,
+				   coord_last_unit_pos(&from) -
+				   shift->part_units + 1, shift->part_units,
+				   SHIFT_RIGHT, shift->part_bytes);
+		}
+	}
+}
+
+/* remove everything either before or after @fact_stop. Number of items
+   removed completely is returned */
+static int delete_copied(struct shift_params *shift)
+{
+	coord_t from;
+	coord_t to;
+	struct carry_cut_data cdata;
+
+	if (shift->pend == SHIFT_LEFT) {
+		/* we were shifting to left, remove everything from the
+		   beginning of @shift->wish_stop->node upto
+		   @shift->wish_stop */
+		coord_init_first_unit(&from, shift->real_stop.node);
+		to = shift->real_stop;
+
+		/* store old coordinate of unit which will be first after
+		   shift to left */
+		shift->u.future_first = to;
+		coord_next_unit(&shift->u.future_first);
+	} else {
+		/* we were shifting to right, remove everything from
+		   @shift->stop_coord upto to end of
+		   @shift->stop_coord->node */
+		from = shift->real_stop;
+		coord_init_last_unit(&to, from.node);
+
+		/* store old coordinate of unit which will be last after
+		   shift to right */
+		shift->u.future_last = from;
+		coord_prev_unit(&shift->u.future_last);
+	}
+
+	cdata.params.from = &from;
+	cdata.params.to = &to;
+	cdata.params.from_key = NULL;
+	cdata.params.to_key = NULL;
+	cdata.params.smallest_removed = NULL;
+	return cut_node40(&cdata, NULL);
+}
+
+/* something was moved between @left and @right. Add carry operation to @info
+   list to have carry to update delimiting key between them */
+static int
+prepare_for_update(znode * left, znode * right, carry_plugin_info * info)
+{
+	carry_op *op;
+	carry_node *cn;
+
+	if (info == NULL)
+		/* nowhere to send operation to. */
+		return 0;
+
+	if (!should_notify_parent(right))
+		return 0;
+
+	op = node_post_carry(info, COP_UPDATE, right, 1);
+	if (IS_ERR(op) || op == NULL)
+		return op ? PTR_ERR(op) : -EIO;
+
+	if (left != NULL) {
+		carry_node *reference;
+
+		if (info->doing)
+			reference = insert_carry_node(info->doing,
+						      info->todo, left);
+		else
+			reference = op->node;
+		assert("nikita-2992", reference != NULL);
+		cn = add_carry(info->todo, POOLO_BEFORE, reference);
+		if (IS_ERR(cn))
+			return PTR_ERR(cn);
+		cn->parent = 1;
+		cn->node = left;
+		if (ZF_ISSET(left, JNODE_ORPHAN))
+			cn->left_before = 1;
+		op->u.update.left = cn;
+	} else
+		op->u.update.left = NULL;
+	return 0;
+}
+
+/* plugin->u.node.prepare_removal
+   to delete a pointer to @empty from the tree add corresponding carry
+   operation (delete) to @info list */
+int prepare_removal_node40(znode * empty, carry_plugin_info * info)
+{
+	carry_op *op;
+	reiser4_tree *tree;
+
+	if (!should_notify_parent(empty))
+		return 0;
+	/* already on a road to Styx */
+	if (ZF_ISSET(empty, JNODE_HEARD_BANSHEE))
+		return 0;
+	op = node_post_carry(info, COP_DELETE, empty, 1);
+	if (IS_ERR(op) || op == NULL)
+		return RETERR(op ? PTR_ERR(op) : -EIO);
+
+	op->u.delete.child = NULL;
+	op->u.delete.flags = 0;
+
+	/* fare thee well */
+	tree = znode_get_tree(empty);
+	read_lock_tree(tree);
+	write_lock_dk(tree);
+	znode_set_ld_key(empty, znode_get_rd_key(empty));
+	if (znode_is_left_connected(empty) && empty->left)
+		znode_set_rd_key(empty->left, znode_get_rd_key(empty));
+	write_unlock_dk(tree);
+	read_unlock_tree(tree);
+
+	ZF_SET(empty, JNODE_HEARD_BANSHEE);
+	return 0;
+}
+
+/* something were shifted from @insert_coord->node to @shift->target, update
+   @insert_coord correspondingly */
+static void
+adjust_coord(coord_t * insert_coord, struct shift_params *shift, int removed,
+	     int including_insert_coord)
+{
+	/* item plugin was invalidated by shifting */
+	coord_clear_iplug(insert_coord);
+
+	if (node_is_empty(shift->wish_stop.node)) {
+		assert("vs-242", shift->everything);
+		if (including_insert_coord) {
+			if (shift->pend == SHIFT_RIGHT) {
+				/* set @insert_coord before first unit of
+				   @shift->target node */
+				coord_init_before_first_item(insert_coord,
+							     shift->target);
+			} else {
+				/* set @insert_coord after last in target node */
+				coord_init_after_last_item(insert_coord,
+							   shift->target);
+			}
+		} else {
+			/* set @insert_coord inside of empty node. There is
+			   only one possible coord within an empty
+			   node. init_first_unit will set that coord */
+			coord_init_first_unit(insert_coord,
+					      shift->wish_stop.node);
+		}
+		return;
+	}
+
+	if (shift->pend == SHIFT_RIGHT) {
+		/* there was shifting to right */
+		if (shift->everything) {
+			/* everything wanted was shifted */
+			if (including_insert_coord) {
+				/* @insert_coord is set before first unit of
+				   @to node */
+				coord_init_before_first_item(insert_coord,
+							     shift->target);
+				insert_coord->between = BEFORE_UNIT;
+			} else {
+				/* @insert_coord is set after last unit of
+				   @insert->node */
+				coord_init_last_unit(insert_coord,
+						     shift->wish_stop.node);
+				insert_coord->between = AFTER_UNIT;
+			}
+		}
+		return;
+	}
+
+	/* there was shifting to left */
+	if (shift->everything) {
+		/* everything wanted was shifted */
+		if (including_insert_coord) {
+			/* @insert_coord is set after last unit in @to node */
+			coord_init_after_last_item(insert_coord, shift->target);
+		} else {
+			/* @insert_coord is set before first unit in the same
+			   node */
+			coord_init_before_first_item(insert_coord,
+						     shift->wish_stop.node);
+		}
+		return;
+	}
+
+	/* FIXME-VS: the code below is complicated because with between ==
+	   AFTER_ITEM unit_pos is set to 0 */
+
+	if (!removed) {
+		/* no items were shifted entirely */
+		assert("vs-195", shift->merging_units == 0
+		       || shift->part_units == 0);
+
+		if (shift->real_stop.item_pos == insert_coord->item_pos) {
+			if (shift->merging_units) {
+				if (insert_coord->between == AFTER_UNIT) {
+					assert("nikita-1441",
+					       insert_coord->unit_pos >=
+					       shift->merging_units);
+					insert_coord->unit_pos -=
+					    shift->merging_units;
+				} else if (insert_coord->between == BEFORE_UNIT) {
+					assert("nikita-2090",
+					       insert_coord->unit_pos >
+					       shift->merging_units);
+					insert_coord->unit_pos -=
+					    shift->merging_units;
+				}
+
+				assert("nikita-2083",
+				       insert_coord->unit_pos + 1);
+			} else {
+				if (insert_coord->between == AFTER_UNIT) {
+					assert("nikita-1442",
+					       insert_coord->unit_pos >=
+					       shift->part_units);
+					insert_coord->unit_pos -=
+					    shift->part_units;
+				} else if (insert_coord->between == BEFORE_UNIT) {
+					assert("nikita-2089",
+					       insert_coord->unit_pos >
+					       shift->part_units);
+					insert_coord->unit_pos -=
+					    shift->part_units;
+				}
+
+				assert("nikita-2084",
+				       insert_coord->unit_pos + 1);
+			}
+		}
+		return;
+	}
+
+	/* we shifted to left and there was no enough space for everything */
+	switch (insert_coord->between) {
+	case AFTER_UNIT:
+	case BEFORE_UNIT:
+		if (shift->real_stop.item_pos == insert_coord->item_pos)
+			insert_coord->unit_pos -= shift->part_units;
+	case AFTER_ITEM:
+		coord_add_item_pos(insert_coord, -removed);
+		break;
+	default:
+		impossible("nikita-2087", "not ready");
+	}
+	assert("nikita-2085", insert_coord->unit_pos + 1);
+}
+
+static int call_shift_hooks(struct shift_params *shift)
+{
+	unsigned i, shifted;
+	coord_t coord;
+	item_plugin *iplug;
+
+	assert("vs-275", !node_is_empty(shift->target));
+
+	/* number of items shift touches */
+	shifted =
+	    shift->entire + (shift->merging_units ? 1 : 0) +
+	    (shift->part_units ? 1 : 0);
+
+	if (shift->pend == SHIFT_LEFT) {
+		/* moved items are at the end */
+		coord_init_last_unit(&coord, shift->target);
+		coord.unit_pos = 0;
+
+		assert("vs-279", shift->pend == 1);
+		for (i = 0; i < shifted; i++) {
+			unsigned from, count;
+
+			iplug = item_plugin_by_coord(&coord);
+			if (i == 0 && shift->part_units) {
+				assert("vs-277",
+				       coord_num_units(&coord) ==
+				       shift->part_units);
+				count = shift->part_units;
+				from = 0;
+			} else if (i == shifted - 1 && shift->merging_units) {
+				count = shift->merging_units;
+				from = coord_num_units(&coord) - count;
+			} else {
+				count = coord_num_units(&coord);
+				from = 0;
+			}
+
+			if (iplug->b.shift_hook) {
+				iplug->b.shift_hook(&coord, from, count,
+						    shift->wish_stop.node);
+			}
+			coord_add_item_pos(&coord, -shift->pend);
+		}
+	} else {
+		/* moved items are at the beginning */
+		coord_init_first_unit(&coord, shift->target);
+
+		assert("vs-278", shift->pend == -1);
+		for (i = 0; i < shifted; i++) {
+			unsigned from, count;
+
+			iplug = item_plugin_by_coord(&coord);
+			if (i == 0 && shift->part_units) {
+				assert("vs-277",
+				       coord_num_units(&coord) ==
+				       shift->part_units);
+				count = coord_num_units(&coord);
+				from = 0;
+			} else if (i == shifted - 1 && shift->merging_units) {
+				count = shift->merging_units;
+				from = 0;
+			} else {
+				count = coord_num_units(&coord);
+				from = 0;
+			}
+
+			if (iplug->b.shift_hook) {
+				iplug->b.shift_hook(&coord, from, count,
+						    shift->wish_stop.node);
+			}
+			coord_add_item_pos(&coord, -shift->pend);
+		}
+	}
+
+	return 0;
+}
+
+/* shift to left is completed. Return 1 if unit @old was moved to left neighbor */
+static int
+unit_moved_left(const struct shift_params *shift, const coord_t * old)
+{
+	assert("vs-944", shift->real_stop.node == old->node);
+
+	if (shift->real_stop.item_pos < old->item_pos)
+		return 0;
+	if (shift->real_stop.item_pos == old->item_pos) {
+		if (shift->real_stop.unit_pos < old->unit_pos)
+			return 0;
+	}
+	return 1;
+}
+
+/* shift to right is completed. Return 1 if unit @old was moved to right
+   neighbor */
+static int
+unit_moved_right(const struct shift_params *shift, const coord_t * old)
+{
+	assert("vs-944", shift->real_stop.node == old->node);
+
+	if (shift->real_stop.item_pos > old->item_pos)
+		return 0;
+	if (shift->real_stop.item_pos == old->item_pos) {
+		if (shift->real_stop.unit_pos > old->unit_pos)
+			return 0;
+	}
+	return 1;
+}
+
+/* coord @old was set in node from which shift was performed. What was shifted
+   is stored in @shift. Update @old correspondingly to performed shift */
+static coord_t *adjust_coord2(const struct shift_params *shift,
+			      const coord_t * old, coord_t * new)
+{
+	coord_clear_iplug(new);
+	new->between = old->between;
+
+	coord_clear_iplug(new);
+	if (old->node == shift->target) {
+		if (shift->pend == SHIFT_LEFT) {
+			/* coord which is set inside of left neighbor does not
+			   change during shift to left */
+			coord_dup(new, old);
+			return new;
+		}
+		new->node = old->node;
+		coord_set_item_pos(new,
+				   old->item_pos + shift->entire +
+				   (shift->part_units ? 1 : 0));
+		new->unit_pos = old->unit_pos;
+		if (old->item_pos == 0 && shift->merging_units)
+			new->unit_pos += shift->merging_units;
+		return new;
+	}
+
+	assert("vs-977", old->node == shift->wish_stop.node);
+	if (shift->pend == SHIFT_LEFT) {
+		if (unit_moved_left(shift, old)) {
+			/* unit @old moved to left neighbor. Calculate its
+			   coordinate there */
+			new->node = shift->target;
+			coord_set_item_pos(new,
+					   node_num_items(shift->target) -
+					   shift->entire -
+					   (shift->part_units ? 1 : 0) +
+					   old->item_pos);
+
+			new->unit_pos = old->unit_pos;
+			if (shift->merging_units) {
+				coord_dec_item_pos(new);
+				if (old->item_pos == 0) {
+					/* unit_pos only changes if item got
+					   merged */
+					new->unit_pos =
+					    coord_num_units(new) -
+					    (shift->merging_units -
+					     old->unit_pos);
+				}
+			}
+		} else {
+			/* unit @old did not move to left neighbor.
+
+			   Use _nocheck, because @old is outside of its node.
+			 */
+			coord_dup_nocheck(new, old);
+			coord_add_item_pos(new,
+					   -shift->u.future_first.item_pos);
+			if (new->item_pos == 0)
+				new->unit_pos -= shift->u.future_first.unit_pos;
+		}
+	} else {
+		if (unit_moved_right(shift, old)) {
+			/* unit @old moved to right neighbor */
+			new->node = shift->target;
+			coord_set_item_pos(new,
+					   old->item_pos -
+					   shift->real_stop.item_pos);
+			if (new->item_pos == 0) {
+				/* unit @old might change unit pos */
+				coord_set_item_pos(new,
+						   old->unit_pos -
+						   shift->real_stop.unit_pos);
+			}
+		} else {
+			/* unit @old did not move to right neighbor, therefore
+			   it did not change */
+			coord_dup(new, old);
+		}
+	}
+	coord_set_iplug(new, item_plugin_by_coord(new));
+	return new;
+}
+
+/* this is called when shift is completed (something of source node is copied
+   to target and deleted in source) to update all taps set in current
+   context */
+static void update_taps(const struct shift_params *shift)
+{
+	tap_t *tap;
+	coord_t new;
+
+	for_all_taps(tap) {
+		/* update only taps set to nodes participating in shift */
+		if (tap->coord->node == shift->wish_stop.node
+		    || tap->coord->node == shift->target)
+			tap_to_coord(tap,
+				     adjust_coord2(shift, tap->coord, &new));
+	}
+}
+
+#if REISER4_DEBUG
+
+struct shift_check {
+	reiser4_key key;
+	__u16 plugin_id;
+	union {
+		__u64 bytes;
+		__u64 entries;
+		void *unused;
+	} u;
+};
+
+void *shift_check_prepare(const znode * left, const znode * right)
+{
+	pos_in_node_t i, nr_items;
+	int mergeable;
+	struct shift_check *data;
+	item_header40 *ih;
+
+	if (node_is_empty(left) || node_is_empty(right))
+		mergeable = 0;
+	else {
+		coord_t l, r;
+
+		coord_init_last_unit(&l, left);
+		coord_init_first_unit(&r, right);
+		mergeable = are_items_mergeable(&l, &r);
+	}
+	nr_items =
+	    node40_num_of_items_internal(left) +
+	    node40_num_of_items_internal(right) - (mergeable ? 1 : 0);
+	data =
+		kmalloc(sizeof(struct shift_check) * nr_items, GFP_KERNEL);
+	if (data != NULL) {
+		coord_t coord;
+		pos_in_node_t item_pos;
+
+		coord_init_first_unit(&coord, left);
+		i = 0;
+
+		for (item_pos = 0;
+		     item_pos < node40_num_of_items_internal(left);
+		     item_pos++) {
+
+			coord_set_item_pos(&coord, item_pos);
+			ih = node40_ih_at_coord(&coord);
+
+			data[i].key = ih->key;
+			data[i].plugin_id = le16_to_cpu(get_unaligned(&ih->plugin_id));
+			switch (data[i].plugin_id) {
+			case CTAIL_ID:
+			case FORMATTING_ID:
+				data[i].u.bytes = coord_num_units(&coord);
+				break;
+			case EXTENT_POINTER_ID:
+				data[i].u.bytes =
+				    extent_size(&coord,
+						coord_num_units(&coord));
+				break;
+			case COMPOUND_DIR_ID:
+				data[i].u.entries = coord_num_units(&coord);
+				break;
+			default:
+				data[i].u.unused = NULL;
+				break;
+			}
+			i++;
+		}
+
+		coord_init_first_unit(&coord, right);
+
+		if (mergeable) {
+			assert("vs-1609", i != 0);
+
+			ih = node40_ih_at_coord(&coord);
+
+			assert("vs-1589",
+			       data[i - 1].plugin_id ==
+			       le16_to_cpu(get_unaligned(&ih->plugin_id)));
+			switch (data[i - 1].plugin_id) {
+			case CTAIL_ID:
+			case FORMATTING_ID:
+				data[i - 1].u.bytes += coord_num_units(&coord);
+				break;
+			case EXTENT_POINTER_ID:
+				data[i - 1].u.bytes +=
+				    extent_size(&coord,
+						coord_num_units(&coord));
+				break;
+			case COMPOUND_DIR_ID:
+				data[i - 1].u.entries +=
+				    coord_num_units(&coord);
+				break;
+			default:
+				impossible("vs-1605", "wrong mergeable item");
+				break;
+			}
+			item_pos = 1;
+		} else
+			item_pos = 0;
+		for (; item_pos < node40_num_of_items_internal(right);
+		     item_pos++) {
+
+			assert("vs-1604", i < nr_items);
+			coord_set_item_pos(&coord, item_pos);
+			ih = node40_ih_at_coord(&coord);
+
+			data[i].key = ih->key;
+			data[i].plugin_id = le16_to_cpu(get_unaligned(&ih->plugin_id));
+			switch (data[i].plugin_id) {
+			case CTAIL_ID:
+			case FORMATTING_ID:
+				data[i].u.bytes = coord_num_units(&coord);
+				break;
+			case EXTENT_POINTER_ID:
+				data[i].u.bytes =
+				    extent_size(&coord,
+						coord_num_units(&coord));
+				break;
+			case COMPOUND_DIR_ID:
+				data[i].u.entries = coord_num_units(&coord);
+				break;
+			default:
+				data[i].u.unused = NULL;
+				break;
+			}
+			i++;
+		}
+		assert("vs-1606", i == nr_items);
+	}
+	return data;
+}
+
+void shift_check(void *vp, const znode * left, const znode * right)
+{
+	pos_in_node_t i, nr_items;
+	coord_t coord;
+	__u64 last_bytes;
+	int mergeable;
+	item_header40 *ih;
+	pos_in_node_t item_pos;
+	struct shift_check *data;
+
+	data = (struct shift_check *)vp;
+
+	if (data == NULL)
+		return;
+
+	if (node_is_empty(left) || node_is_empty(right))
+		mergeable = 0;
+	else {
+		coord_t l, r;
+
+		coord_init_last_unit(&l, left);
+		coord_init_first_unit(&r, right);
+		mergeable = are_items_mergeable(&l, &r);
+	}
+
+	nr_items =
+	    node40_num_of_items_internal(left) +
+	    node40_num_of_items_internal(right) - (mergeable ? 1 : 0);
+
+	i = 0;
+	last_bytes = 0;
+
+	coord_init_first_unit(&coord, left);
+
+	for (item_pos = 0; item_pos < node40_num_of_items_internal(left);
+	     item_pos++) {
+
+		coord_set_item_pos(&coord, item_pos);
+		ih = node40_ih_at_coord(&coord);
+
+		assert("vs-1611", i == item_pos);
+		assert("vs-1590", keyeq(&ih->key, &data[i].key));
+		assert("vs-1591",
+		       le16_to_cpu(get_unaligned(&ih->plugin_id)) == data[i].plugin_id);
+		if ((i < (node40_num_of_items_internal(left) - 1))
+		    || !mergeable) {
+			switch (data[i].plugin_id) {
+			case CTAIL_ID:
+			case FORMATTING_ID:
+				assert("vs-1592",
+				       data[i].u.bytes ==
+				       coord_num_units(&coord));
+				break;
+			case EXTENT_POINTER_ID:
+				assert("vs-1593",
+				       data[i].u.bytes == extent_size(&coord,
+								      coord_num_units
+								      (&coord)));
+				break;
+			case COMPOUND_DIR_ID:
+				assert("vs-1594",
+				       data[i].u.entries ==
+				       coord_num_units(&coord));
+				break;
+			default:
+				break;
+			}
+		}
+		if (item_pos == (node40_num_of_items_internal(left) - 1)
+		    && mergeable) {
+			switch (data[i].plugin_id) {
+			case CTAIL_ID:
+			case FORMATTING_ID:
+				last_bytes = coord_num_units(&coord);
+				break;
+			case EXTENT_POINTER_ID:
+				last_bytes =
+				    extent_size(&coord,
+						coord_num_units(&coord));
+				break;
+			case COMPOUND_DIR_ID:
+				last_bytes = coord_num_units(&coord);
+				break;
+			default:
+				impossible("vs-1595", "wrong mergeable item");
+				break;
+			}
+		}
+		i++;
+	}
+
+	coord_init_first_unit(&coord, right);
+	if (mergeable) {
+		ih = node40_ih_at_coord(&coord);
+
+		assert("vs-1589",
+		       data[i - 1].plugin_id == le16_to_cpu(get_unaligned(&ih->plugin_id)));
+		assert("vs-1608", last_bytes != 0);
+		switch (data[i - 1].plugin_id) {
+		case CTAIL_ID:
+		case FORMATTING_ID:
+			assert("vs-1596",
+			       data[i - 1].u.bytes ==
+			       last_bytes + coord_num_units(&coord));
+			break;
+
+		case EXTENT_POINTER_ID:
+			assert("vs-1597",
+			       data[i - 1].u.bytes ==
+			       last_bytes + extent_size(&coord,
+							coord_num_units
+							(&coord)));
+			break;
+
+		case COMPOUND_DIR_ID:
+			assert("vs-1598",
+			       data[i - 1].u.bytes ==
+			       last_bytes + coord_num_units(&coord));
+			break;
+		default:
+			impossible("vs-1599", "wrong mergeable item");
+			break;
+		}
+		item_pos = 1;
+	} else
+		item_pos = 0;
+
+	for (; item_pos < node40_num_of_items_internal(right); item_pos++) {
+
+		coord_set_item_pos(&coord, item_pos);
+		ih = node40_ih_at_coord(&coord);
+
+		assert("vs-1612", keyeq(&ih->key, &data[i].key));
+		assert("vs-1613",
+		       le16_to_cpu(get_unaligned(&ih->plugin_id)) == data[i].plugin_id);
+		switch (data[i].plugin_id) {
+		case CTAIL_ID:
+		case FORMATTING_ID:
+			assert("vs-1600",
+			       data[i].u.bytes == coord_num_units(&coord));
+			break;
+		case EXTENT_POINTER_ID:
+			assert("vs-1601",
+			       data[i].u.bytes == extent_size(&coord,
+							      coord_num_units
+							      (&coord)));
+			break;
+		case COMPOUND_DIR_ID:
+			assert("vs-1602",
+			       data[i].u.entries == coord_num_units(&coord));
+			break;
+		default:
+			break;
+		}
+		i++;
+	}
+
+	assert("vs-1603", i == nr_items);
+	kfree(data);
+}
+
+#endif
+
+/* plugin->u.node.shift
+   look for description of this method in plugin/node/node.h */
+int shift_node40(coord_t * from, znode * to, shift_direction pend, int delete_child,	/* if @from->node becomes empty - it will be
+											   deleted from the tree if this is set to 1 */
+		 int including_stop_coord, carry_plugin_info * info)
+{
+	struct shift_params shift;
+	int result;
+	znode *left, *right;
+	znode *source;
+	int target_empty;
+
+	assert("nikita-2161", coord_check(from));
+
+	memset(&shift, 0, sizeof(shift));
+	shift.pend = pend;
+	shift.wish_stop = *from;
+	shift.target = to;
+
+	assert("nikita-1473", znode_is_write_locked(from->node));
+	assert("nikita-1474", znode_is_write_locked(to));
+
+	source = from->node;
+
+	/* set @shift.wish_stop to rightmost/leftmost unit among units we want
+	   shifted */
+	if (pend == SHIFT_LEFT) {
+		result = coord_set_to_left(&shift.wish_stop);
+		left = to;
+		right = from->node;
+	} else {
+		result = coord_set_to_right(&shift.wish_stop);
+		left = from->node;
+		right = to;
+	}
+
+	if (result) {
+		/* move insertion coord even if there is nothing to move */
+		if (including_stop_coord) {
+			/* move insertion coord (@from) */
+			if (pend == SHIFT_LEFT) {
+				/* after last item in target node */
+				coord_init_after_last_item(from, to);
+			} else {
+				/* before first item in target node */
+				coord_init_before_first_item(from, to);
+			}
+		}
+
+		if (delete_child && node_is_empty(shift.wish_stop.node))
+			result =
+			    prepare_removal_node40(shift.wish_stop.node, info);
+		else
+			result = 0;
+		/* there is nothing to shift */
+		assert("nikita-2078", coord_check(from));
+		return result;
+	}
+
+	target_empty = node_is_empty(to);
+
+	/* when first node plugin with item body compression is implemented,
+	   this must be changed to call node specific plugin */
+
+	/* shift->stop_coord is updated to last unit which really will be
+	   shifted */
+	estimate_shift(&shift, get_current_context());
+	if (!shift.shift_bytes) {
+		/* we could not shift anything */
+		assert("nikita-2079", coord_check(from));
+		return 0;
+	}
+
+	copy(&shift);
+
+	/* result value of this is important. It is used by adjust_coord below */
+	result = delete_copied(&shift);
+
+	assert("vs-1610", result >= 0);
+	assert("vs-1471",
+	       ((reiser4_context *) current->journal_info)->magic ==
+	       context_magic);
+
+	/* item which has been moved from one node to another might want to do
+	   something on that event. This can be done by item's shift_hook
+	   method, which will be now called for every moved items */
+	call_shift_hooks(&shift);
+
+	assert("vs-1472",
+	       ((reiser4_context *) current->journal_info)->magic ==
+	       context_magic);
+
+	update_taps(&shift);
+
+	assert("vs-1473",
+	       ((reiser4_context *) current->journal_info)->magic ==
+	       context_magic);
+
+	/* adjust @from pointer in accordance with @including_stop_coord flag
+	   and amount of data which was really shifted */
+	adjust_coord(from, &shift, result, including_stop_coord);
+
+	if (target_empty)
+		/*
+		 * items were shifted into empty node. Update delimiting key.
+		 */
+		result = prepare_for_update(NULL, left, info);
+
+	/* add update operation to @info, which is the list of operations to
+	   be performed on a higher level */
+	result = prepare_for_update(left, right, info);
+	if (!result && node_is_empty(source) && delete_child) {
+		/* all contents of @from->node is moved to @to and @from->node
+		   has to be removed from the tree, so, on higher level we
+		   will be removing the pointer to node @from->node */
+		result = prepare_removal_node40(source, info);
+	}
+	assert("nikita-2080", coord_check(from));
+	return result ? result : (int)shift.shift_bytes;
+}
+
+/* plugin->u.node.fast_insert()
+   look for description of this method in plugin/node/node.h */
+int fast_insert_node40(const coord_t * coord UNUSED_ARG /* node to query */ )
+{
+	return 1;
+}
+
+/* plugin->u.node.fast_paste()
+   look for description of this method in plugin/node/node.h */
+int fast_paste_node40(const coord_t * coord UNUSED_ARG /* node to query */ )
+{
+	return 1;
+}
+
+/* plugin->u.node.fast_cut()
+   look for description of this method in plugin/node/node.h */
+int fast_cut_node40(const coord_t * coord UNUSED_ARG /* node to query */ )
+{
+	return 1;
+}
+
+/* plugin->u.node.modify - not defined */
+
+/* plugin->u.node.max_item_size */
+int max_item_size_node40(void)
+{
+	return reiser4_get_current_sb()->s_blocksize - sizeof(node40_header) -
+	    sizeof(item_header40);
+}
+
+/* plugin->u.node.set_item_plugin */
+int set_item_plugin_node40(coord_t *coord, item_id id)
+{
+	item_header40 *ih;
+
+	ih = node40_ih_at_coord(coord);
+	put_unaligned(cpu_to_le16(id), &ih->plugin_id);
+	coord->iplugid = id;
+	return 0;
+}
+
+/*
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/node/node40.h newtree/fs/reiser4/plugin/node/node40.h
--- oldtree/fs/reiser4/plugin/node/node40.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/node/node40.h	2006-02-21 15:58:34.641880192 +0000
@@ -0,0 +1,125 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#if !defined( __REISER4_NODE40_H__ )
+#define __REISER4_NODE40_H__
+
+#include "../../forward.h"
+#include "../../dformat.h"
+#include "node.h"
+
+#include <linux/types.h>
+
+/* format of node header for 40 node layouts. Keep bloat out of this struct.  */
+typedef struct node40_header {
+	/* identifier of node plugin. Must be located at the very beginning
+	   of a node. */
+	common_node_header common_header;	/* this is 16 bits */
+	/* number of items. Should be first element in the node header,
+	   because we haven't yet finally decided whether it shouldn't go into
+	   common_header.
+	 */
+/* NIKITA-FIXME-HANS: Create a macro such that if there is only one
+ * node format at compile time, and it is this one, accesses do not function dereference when
+ * accessing these fields (and otherwise they do).  Probably 80% of users will only have one node format at a time throughout the life of reiser4.  */
+	d16 nr_items;
+	/* free space in node measured in bytes */
+	d16 free_space;
+	/* offset to start of free space in node */
+	d16 free_space_start;
+	/* for reiser4_fsck.  When information about what is a free
+	   block is corrupted, and we try to recover everything even
+	   if marked as freed, then old versions of data may
+	   duplicate newer versions, and this field allows us to
+	   restore the newer version.  Also useful for when users
+	   who don't have the new trashcan installed on their linux distro
+	   delete the wrong files and send us desperate emails
+	   offering $25 for them back.  */
+
+	/* magic field we need to tell formatted nodes NIKITA-FIXME-HANS: improve this comment */
+	d32 magic;
+	/* flushstamp is made of mk_id and write_counter. mk_id is an
+	   id generated randomly at mkreiserfs time. So we can just
+	   skip all nodes with different mk_id. write_counter is d64
+	   incrementing counter of writes on disk. It is used for
+	   choosing the newest data at fsck time. NIKITA-FIXME-HANS: why was field name changed but not comment? */
+
+	d32 mkfs_id;
+	d64 flush_id;
+	/* node flags to be used by fsck (reiser4ck or reiser4fsck?)
+	   and repacker NIKITA-FIXME-HANS: say more or reference elsewhere that says more */
+	d16 flags;
+
+	/* 1 is leaf level, 2 is twig level, root is the numerically
+	   largest level */
+	d8 level;
+
+	d8 pad;
+} PACKED node40_header;
+
+/* item headers are not standard across all node layouts, pass
+   pos_in_node to functions instead */
+typedef struct item_header40 {
+	/* key of item */
+	/*  0 */ reiser4_key key;
+	/* offset from start of a node measured in 8-byte chunks */
+	/* 24 */ d16 offset;
+	/* 26 */ d16 flags;
+	/* 28 */ d16 plugin_id;
+} PACKED item_header40;
+
+size_t item_overhead_node40(const znode * node, flow_t * aflow);
+size_t free_space_node40(znode * node);
+node_search_result lookup_node40(znode * node, const reiser4_key * key,
+				 lookup_bias bias, coord_t * coord);
+int num_of_items_node40(const znode * node);
+char *item_by_coord_node40(const coord_t * coord);
+int length_by_coord_node40(const coord_t * coord);
+item_plugin *plugin_by_coord_node40(const coord_t * coord);
+reiser4_key *key_at_node40(const coord_t * coord, reiser4_key * key);
+size_t estimate_node40(znode * node);
+int check_node40(const znode * node, __u32 flags, const char **error);
+int parse_node40(znode * node);
+int init_node40(znode * node);
+#ifdef GUESS_EXISTS
+int guess_node40(const znode * node);
+#endif
+void change_item_size_node40(coord_t * coord, int by);
+int create_item_node40(coord_t * target, const reiser4_key * key,
+		       reiser4_item_data * data, carry_plugin_info * info);
+void update_item_key_node40(coord_t * target, const reiser4_key * key,
+			    carry_plugin_info * info);
+int kill_node40(struct carry_kill_data *, carry_plugin_info *);
+int cut_node40(struct carry_cut_data *, carry_plugin_info *);
+int shift_node40(coord_t * from, znode * to, shift_direction pend,
+		 /* if @from->node becomes
+		    empty - it will be deleted from
+		    the tree if this is set to 1
+		  */
+		 int delete_child, int including_stop_coord,
+		 carry_plugin_info * info);
+
+int fast_insert_node40(const coord_t * coord);
+int fast_paste_node40(const coord_t * coord);
+int fast_cut_node40(const coord_t * coord);
+int max_item_size_node40(void);
+int prepare_removal_node40(znode * empty, carry_plugin_info * info);
+int set_item_plugin_node40(coord_t * coord, item_id id);
+int shrink_item_node40(coord_t * coord, int delta);
+
+#if REISER4_DEBUG
+void *shift_check_prepare(const znode *left, const znode *right);
+void shift_check(void *vp, const znode *left, const znode *right);
+#endif
+
+/* __REISER4_NODE40_H__ */
+#endif
+/*
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/object.c newtree/fs/reiser4/plugin/object.c
--- oldtree/fs/reiser4/plugin/object.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/object.c	2006-02-21 15:58:35.450757224 +0000
@@ -0,0 +1,502 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/*
+ * Examples of object plugins: file, directory, symlink, special file.
+ *
+ * Plugins associated with inode:
+ *
+ * Plugin of inode is plugin referenced by plugin-id field of on-disk
+ * stat-data. How we store this plugin in in-core inode is not
+ * important. Currently pointers are used, another variant is to store offsets
+ * and do array lookup on each access.
+ *
+ * Now, each inode has one selected plugin: object plugin that
+ * determines what type of file this object is: directory, regular etc.
+ *
+ * This main plugin can use other plugins that are thus subordinated to
+ * it. Directory instance of object plugin uses hash; regular file
+ * instance uses tail policy plugin.
+ *
+ * Object plugin is either taken from id in stat-data or guessed from
+ * i_mode bits. Once it is established we ask it to install its
+ * subordinate plugins, by looking again in stat-data or inheriting them
+ * from parent.
+ *
+ * How new inode is initialized during ->read_inode():
+ * 1 read stat-data and initialize inode fields: i_size, i_mode,
+ *   i_generation, capabilities etc.
+ * 2 read plugin id from stat data or try to guess plugin id
+ *   from inode->i_mode bits if plugin id is missing.
+ * 3 Call ->init_inode() method of stat-data plugin to initialise inode fields.
+ *
+ * NIKITA-FIXME-HANS: can you say a little about 1 being done before 3?  What
+ * if stat data does contain i_size, etc., due to it being an unusual plugin?
+ *
+ * 4 Call ->activate() method of object's plugin. Plugin is either read from
+ *    from stat-data or guessed from mode bits
+ * 5 Call ->inherit() method of object plugin to inherit as yet un initialized
+ *    plugins from parent.
+ *
+ * Easy induction proves that on last step all plugins of inode would be
+ * initialized.
+ *
+ * When creating new object:
+ * 1 obtain object plugin id (see next period)
+ * NIKITA-FIXME-HANS: period?
+ * 2 ->install() this plugin
+ * 3 ->inherit() the rest from the parent
+ *
+ * We need some examples of creating an object with default and non-default
+ * plugin ids.  Nikita, please create them.
+ */
+
+#include "../inode.h"
+
+static int _bugop(void)
+{
+	BUG_ON(1);
+	return 0;
+}
+
+#define bugop ((void *)_bugop)
+
+static int _dummyop(void)
+{
+	return 0;
+}
+
+#define dummyop ((void *)_dummyop)
+
+static int change_file(struct inode *inode, reiser4_plugin * plugin)
+{
+	/* cannot change object plugin of already existing object */
+	return RETERR(-EINVAL);
+}
+
+static reiser4_plugin_ops file_plugin_ops = {
+	.change = change_file
+};
+
+/*
+ * Definitions of object plugins.
+ */
+
+file_plugin file_plugins[LAST_FILE_PLUGIN_ID] = {
+	[UNIX_FILE_PLUGIN_ID] = {
+		.h = {
+			.type_id = REISER4_FILE_PLUGIN_TYPE,
+			.id = UNIX_FILE_PLUGIN_ID,
+			.pops = &file_plugin_ops,
+			.label = "reg",
+			.desc = "regular file",
+			.linkage = {NULL, NULL},
+		},
+		.inode_ops = {
+			.permission = permission_common,
+			.setattr = setattr_unix_file,
+			.getattr = getattr_common
+		},
+		.file_ops = {
+			.llseek = generic_file_llseek,
+			.read = read_unix_file,
+			.write = write_unix_file,
+			.ioctl = ioctl_unix_file,
+			.mmap = mmap_unix_file,
+			.release = release_unix_file,
+			.fsync = sync_unix_file,
+			.sendfile = sendfile_unix_file
+		},
+		.as_ops = {
+			.writepage = reiser4_writepage,
+			.readpage = readpage_unix_file,
+			.sync_page = block_sync_page,
+			.writepages = writepages_unix_file,
+			.set_page_dirty = reiser4_set_page_dirty,
+			.readpages = reiser4_readpages,
+			.prepare_write = prepare_write_unix_file,
+			.commit_write =	commit_write_unix_file,
+			.bmap = bmap_unix_file,
+			.invalidatepage = reiser4_invalidatepage,
+			.releasepage = reiser4_releasepage
+		},
+		.write_sd_by_inode = write_sd_by_inode_common,
+		.flow_by_inode = flow_by_inode_unix_file,
+		.key_by_inode = key_by_inode_and_offset_common,
+		.set_plug_in_inode = set_plug_in_inode_common,
+		.adjust_to_parent = adjust_to_parent_common,
+		.create_object = create_object_common,	/* this is not inode_operations's create */
+		.delete_object = delete_object_unix_file,
+		.add_link = add_link_common,
+		.rem_link = rem_link_common,
+		.owns_item = owns_item_unix_file,
+		.can_add_link = can_add_link_common,
+		.detach = dummyop,
+		.bind = dummyop,
+		.safelink = safelink_common,
+		.estimate = {
+			.create = estimate_create_common,
+			.update = estimate_update_common,
+			.unlink = estimate_unlink_common
+		},
+		.init_inode_data = init_inode_data_unix_file,
+		.cut_tree_worker = cut_tree_worker_common,
+		.wire = {
+			.write = wire_write_common,
+			.read = wire_read_common,
+			.get = wire_get_common,
+			.size = wire_size_common,
+			.done = wire_done_common
+		}
+	},
+	[DIRECTORY_FILE_PLUGIN_ID] = {
+		.h = {
+			.type_id = REISER4_FILE_PLUGIN_TYPE,
+			.id = DIRECTORY_FILE_PLUGIN_ID,
+			.pops = &file_plugin_ops,
+			.label = "dir",
+			.desc = "directory",
+			.linkage = {NULL, NULL}
+		},
+		.inode_ops = {NULL,},
+		.file_ops = {NULL,},
+		.as_ops = {NULL,},
+
+		.write_sd_by_inode = write_sd_by_inode_common,
+		.flow_by_inode = bugop,
+		.key_by_inode = bugop,
+		.set_plug_in_inode = set_plug_in_inode_common,
+		.adjust_to_parent = adjust_to_parent_common_dir,
+		.create_object = create_object_common,
+		.delete_object = delete_directory_common,
+		.add_link = add_link_common,
+		.rem_link = rem_link_common_dir,
+		.owns_item = owns_item_common_dir,
+		.can_add_link = can_add_link_common,
+		.can_rem_link = can_rem_link_common_dir,
+		.detach = detach_common_dir,
+		.bind = bind_common_dir,
+		.safelink = safelink_common,
+		.estimate = {
+			.create = estimate_create_common_dir,
+			.update = estimate_update_common,
+			.unlink = estimate_unlink_common_dir
+		},
+		.wire = {
+			.write = wire_write_common,
+			.read = wire_read_common,
+			.get = wire_get_common,
+			.size = wire_size_common,
+			.done = wire_done_common
+		},
+		.init_inode_data = init_inode_ordering,
+		.cut_tree_worker = cut_tree_worker_common,
+	},
+	[SYMLINK_FILE_PLUGIN_ID] = {
+		.h = {
+			.type_id = REISER4_FILE_PLUGIN_TYPE,
+			.id = SYMLINK_FILE_PLUGIN_ID,
+			.pops = &file_plugin_ops,
+			.label = "symlink",
+			.desc = "symbolic link",
+			.linkage = {NULL,NULL}
+		},
+		.inode_ops = {
+			.readlink = generic_readlink,
+			.follow_link = follow_link_common,
+			.permission = permission_common,
+			.setattr = setattr_common,
+			.getattr = getattr_common
+		},
+		/* inode->i_fop of symlink is initialized by NULL in setup_inode_ops */
+		.file_ops = {NULL,},
+		.as_ops = {NULL,},
+
+		.write_sd_by_inode = write_sd_by_inode_common,
+		.set_plug_in_inode = set_plug_in_inode_common,
+		.adjust_to_parent = adjust_to_parent_common,
+		.create_object = create_symlink,
+		.delete_object = delete_object_common,
+		.add_link = add_link_common,
+		.rem_link = rem_link_common,
+		.can_add_link = can_add_link_common,
+		.detach = dummyop,
+		.bind = dummyop,
+		.safelink = safelink_common,
+		.estimate = {
+			.create = estimate_create_common,
+			.update = estimate_update_common,
+			.unlink = estimate_unlink_common
+		},
+		.init_inode_data = init_inode_ordering,
+		.cut_tree_worker = cut_tree_worker_common,
+		.destroy_inode = destroy_inode_symlink,
+		.wire = {
+			.write = wire_write_common,
+			.read = wire_read_common,
+			.get = wire_get_common,
+			.size = wire_size_common,
+			.done = wire_done_common
+		}
+	},
+	[SPECIAL_FILE_PLUGIN_ID] = {
+		.h = {
+			.type_id = REISER4_FILE_PLUGIN_TYPE,
+			.id = SPECIAL_FILE_PLUGIN_ID,
+			.pops = &file_plugin_ops,
+			.label = "special",
+			.desc =
+			"special: fifo, device or socket",
+			.linkage = {NULL, NULL}
+		},
+		.inode_ops = {
+			.permission = permission_common,
+			.setattr = setattr_common,
+			.getattr = getattr_common
+		},
+		/* file_ops of special files (sockets, block, char, fifo) are
+		   initialized by init_special_inode. */
+		.file_ops = {NULL,},
+		.as_ops = {NULL,},
+
+		.write_sd_by_inode = write_sd_by_inode_common,
+		.set_plug_in_inode = set_plug_in_inode_common,
+		.adjust_to_parent = adjust_to_parent_common,
+		.create_object = create_object_common,
+		.delete_object = delete_object_common,
+		.add_link = add_link_common,
+		.rem_link = rem_link_common,
+		.owns_item = owns_item_common,
+		.can_add_link = can_add_link_common,
+		.detach = dummyop,
+		.bind = dummyop,
+		.safelink = safelink_common,
+		.estimate = {
+			.create = estimate_create_common,
+			.update = estimate_update_common,
+			.unlink = estimate_unlink_common
+		},
+		.init_inode_data = init_inode_ordering,
+		.cut_tree_worker = cut_tree_worker_common,
+		.wire = {
+			.write = wire_write_common,
+			.read = wire_read_common,
+			.get = wire_get_common,
+			.size = wire_size_common,
+			.done = wire_done_common
+		}
+	},
+	[CRC_FILE_PLUGIN_ID] = {
+		.h = {
+			.type_id = REISER4_FILE_PLUGIN_TYPE,
+			.id = CRC_FILE_PLUGIN_ID,
+			.pops = &cryptcompress_plugin_ops,
+			.label = "cryptcompress",
+			.desc = "cryptcompress file",
+			.linkage = {NULL, NULL}
+		},
+		.inode_ops = {
+			.permission = permission_common,
+			.setattr = setattr_cryptcompress,
+			.getattr = getattr_common
+		},
+		.file_ops = {
+			.llseek = generic_file_llseek,
+			.read = read_cryptcompress,
+			.write = write_cryptcompress,
+			.mmap = mmap_cryptcompress,
+			.release = release_cryptcompress,
+			.fsync = sync_common,
+			.sendfile = sendfile_cryptcompress
+		},
+		.as_ops = {
+			.writepage = reiser4_writepage,
+			.readpage = readpage_cryptcompress,
+			.sync_page = block_sync_page,
+			.writepages = writepages_cryptcompress,
+			.set_page_dirty = reiser4_set_page_dirty,
+			.readpages = reiser4_readpages,
+			.prepare_write = prepare_write_common,
+			.invalidatepage = reiser4_invalidatepage,
+			.releasepage = reiser4_releasepage
+		},
+		.write_sd_by_inode = write_sd_by_inode_common,
+		.flow_by_inode = flow_by_inode_cryptcompress,
+		.key_by_inode = key_by_inode_cryptcompress,
+		.set_plug_in_inode = set_plug_in_inode_common,
+		.adjust_to_parent = adjust_to_parent_cryptcompress,
+		.create_object = create_cryptcompress,
+		.open_object = open_cryptcompress,
+		.delete_object = delete_cryptcompress,
+		.add_link = add_link_common,
+		.rem_link = rem_link_common,
+		.owns_item = owns_item_common,
+		.can_add_link = can_add_link_common,
+		.detach = dummyop,
+		.bind = dummyop,
+		.safelink = safelink_common,
+		.estimate = {
+			.create = estimate_create_common,
+			.update = estimate_update_common,
+			.unlink = estimate_unlink_common
+		},
+		.init_inode_data = init_inode_data_cryptcompress,
+		.cut_tree_worker = cut_tree_worker_cryptcompress,
+		.destroy_inode = detach_crypto_stat,
+		.wire = {
+			.write = wire_write_common,
+			.read = wire_read_common,
+			.get = wire_get_common,
+			.size = wire_size_common,
+			.done = wire_done_common
+		}
+	}
+};
+
+static int change_dir(struct inode *inode, reiser4_plugin * plugin)
+{
+	/* cannot change dir plugin of already existing object */
+	return RETERR(-EINVAL);
+}
+
+static reiser4_plugin_ops dir_plugin_ops = {
+	.change = change_dir
+};
+
+/*
+ * definition of directory plugins
+ */
+
+dir_plugin dir_plugins[LAST_DIR_ID] = {
+	/* standard hashed directory plugin */
+	[HASHED_DIR_PLUGIN_ID] = {
+		.h = {
+			.type_id = REISER4_DIR_PLUGIN_TYPE,
+			.id = HASHED_DIR_PLUGIN_ID,
+			.pops = &dir_plugin_ops,
+			.label = "dir",
+			.desc = "hashed directory",
+			.linkage = {NULL, NULL}
+		},
+		.inode_ops = {
+			.create = create_common,
+			.lookup = lookup_common,
+			.link = link_common,
+			.unlink = unlink_common,
+			.symlink = symlink_common,
+			.mkdir = mkdir_common,
+			.rmdir = unlink_common,
+			.mknod = mknod_common,
+			.rename = rename_common,
+			.permission = permission_common,
+			.setattr = setattr_common,
+			.getattr = getattr_common
+		},
+		.file_ops = {
+			.llseek = llseek_common_dir,
+			.read = generic_read_dir,
+			.readdir = readdir_common,
+			.release = release_dir_common,
+			.fsync = sync_common
+		},
+		.as_ops = {
+			.writepage = bugop,
+			.readpage = bugop,
+			.sync_page = bugop,
+			.writepages = dummyop,
+			.set_page_dirty = bugop,
+			.readpages = bugop,
+			.prepare_write = bugop,
+			.commit_write = bugop,
+			.bmap = bugop,
+			.invalidatepage = bugop,
+			.releasepage = bugop
+		},
+		.get_parent = get_parent_common,
+		.is_name_acceptable = is_name_acceptable_common,
+		.build_entry_key = build_entry_key_hashed,
+		.build_readdir_key = build_readdir_key_common,
+		.add_entry = add_entry_common,
+		.rem_entry = rem_entry_common,
+		.init = init_common,
+		.done = done_common,
+		.attach = attach_common,
+		.detach = detach_common,
+		.estimate = {
+			.add_entry = estimate_add_entry_common,
+			.rem_entry = estimate_rem_entry_common,
+			.unlink = dir_estimate_unlink_common
+		}
+	},
+	/* hashed directory for which seekdir/telldir are guaranteed to
+	 * work. Brain-damage. */
+	[SEEKABLE_HASHED_DIR_PLUGIN_ID] = {
+		.h = {
+			.type_id = REISER4_DIR_PLUGIN_TYPE,
+			.id = SEEKABLE_HASHED_DIR_PLUGIN_ID,
+			.pops = &dir_plugin_ops,
+			.label = "dir32",
+			.desc = "directory hashed with 31 bit hash",
+			.linkage = {NULL, NULL}
+		},
+		.inode_ops = {
+			.create = create_common,
+			.lookup = lookup_common,
+			.link = link_common,
+			.unlink = unlink_common,
+			.symlink = symlink_common,
+			.mkdir = mkdir_common,
+			.rmdir = unlink_common,
+			.mknod = mknod_common,
+			.rename = rename_common,
+			.permission = permission_common,
+			.setattr = setattr_common,
+			.getattr = getattr_common
+		},
+		.file_ops = {
+			.llseek = llseek_common_dir,
+			.read =	generic_read_dir,
+			.readdir = readdir_common,
+			.release = release_dir_common,
+			.fsync = sync_common
+		},
+		.as_ops = {
+			.writepage = bugop,
+			.readpage = bugop,
+			.sync_page = bugop,
+			.writepages = dummyop,
+			.set_page_dirty = bugop,
+			.readpages = bugop,
+			.prepare_write = bugop,
+			.commit_write = bugop,
+			.bmap = bugop,
+			.invalidatepage = bugop,
+			.releasepage = bugop
+		},
+		.get_parent = get_parent_common,
+		.is_name_acceptable = is_name_acceptable_common,
+		.build_entry_key = build_entry_key_seekable,
+		.build_readdir_key = build_readdir_key_common,
+		.add_entry = add_entry_common,
+		.rem_entry = rem_entry_common,
+		.init = init_common,
+		.done = done_common,
+		.attach = attach_common,
+		.detach = detach_common,
+		.estimate = {
+			.add_entry = estimate_add_entry_common,
+			.rem_entry = estimate_rem_entry_common,
+			.unlink = dir_estimate_unlink_common
+		}
+	}
+};
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/object.h newtree/fs/reiser4/plugin/object.h
--- oldtree/fs/reiser4/plugin/object.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/object.h	2006-02-21 15:58:35.129806016 +0000
@@ -0,0 +1,124 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Declaration of object plugin functions. */
+
+#if !defined( __FS_REISER4_PLUGIN_OBJECT_H__ )
+#define __FS_REISER4_PLUGIN_OBJECT_H__
+
+#include "../type_safe_hash.h"
+
+/* common implementations of inode operations */
+int create_common(struct inode *parent, struct dentry *dentry,
+		  int mode, struct nameidata *);
+struct dentry *lookup_common(struct inode *parent, struct dentry *dentry,
+			     struct nameidata *nameidata);
+int link_common(struct dentry *existing, struct inode *parent,
+		struct dentry *newname);
+int unlink_common(struct inode *parent, struct dentry *victim);
+int mkdir_common(struct inode *parent, struct dentry *dentry, int mode);
+int symlink_common(struct inode *parent, struct dentry *dentry,
+		   const char *linkname);
+int mknod_common(struct inode *parent, struct dentry *dentry,
+		 int mode, dev_t rdev);
+int rename_common(struct inode *old_dir, struct dentry *old_name,
+		  struct inode *new_dir, struct dentry *new_name);
+void *follow_link_common(struct dentry *, struct nameidata *data);
+int permission_common(struct inode *, int mask,	/* mode bits to check permissions for */
+		      struct nameidata *nameidata);
+int setattr_common(struct dentry *, struct iattr *);
+int getattr_common(struct vfsmount *mnt, struct dentry *, struct kstat *);
+
+/* common implementations of file operations */
+loff_t llseek_common_dir(struct file *, loff_t off, int origin);
+int readdir_common(struct file *, void *dirent, filldir_t);
+int release_dir_common(struct inode *, struct file *);
+int sync_common(struct file *, struct dentry *, int datasync);
+ssize_t sendfile_common(struct file *, loff_t *ppos, size_t count,
+			read_actor_t, void *target);
+
+/* common implementations of address space operations */
+int prepare_write_common(struct file *, struct page *, unsigned from,
+			 unsigned to);
+
+/* file plugin operations: common implementations */
+int write_sd_by_inode_common(struct inode *);
+int key_by_inode_and_offset_common(struct inode *, loff_t, reiser4_key *);
+int set_plug_in_inode_common(struct inode *object, struct inode *parent,
+			     reiser4_object_create_data *);
+int adjust_to_parent_common(struct inode *object, struct inode *parent,
+			    struct inode *root);
+int adjust_to_parent_common_dir(struct inode *object, struct inode *parent,
+				struct inode *root);
+int adjust_to_parent_cryptcompress(struct inode *object, struct inode *parent,
+				   struct inode *root);
+int create_object_common(struct inode *object, struct inode *parent,
+			 reiser4_object_create_data *);
+int delete_object_common(struct inode *);
+int delete_directory_common(struct inode *);
+int add_link_common(struct inode *object, struct inode *parent);
+int rem_link_common(struct inode *object, struct inode *parent);
+int rem_link_common_dir(struct inode *object, struct inode *parent);
+int owns_item_common(const struct inode *, const coord_t *);
+int owns_item_common_dir(const struct inode *, const coord_t *);
+int can_add_link_common(const struct inode *);
+int can_rem_link_common_dir(const struct inode *);
+int detach_common_dir(struct inode *child, struct inode *parent);
+int open_cryptcompress(struct inode * inode, struct file * file);
+int bind_common_dir(struct inode *child, struct inode *parent);
+int safelink_common(struct inode *, reiser4_safe_link_t, __u64 value);
+reiser4_block_nr estimate_create_common(const struct inode *);
+reiser4_block_nr estimate_create_common_dir(const struct inode *);
+reiser4_block_nr estimate_update_common(const struct inode *);
+reiser4_block_nr estimate_unlink_common(const struct inode *,
+					const struct inode *);
+reiser4_block_nr estimate_unlink_common_dir(const struct inode *,
+					    const struct inode *);
+char *wire_write_common(struct inode *, char *start);
+char *wire_read_common(char *addr, reiser4_object_on_wire *);
+struct dentry *wire_get_common(struct super_block *, reiser4_object_on_wire *);
+int wire_size_common(struct inode *);
+void wire_done_common(reiser4_object_on_wire *);
+
+/* dir plugin operations: common implementations */
+struct dentry *get_parent_common(struct inode *child);
+int is_name_acceptable_common(const struct inode *, const char *name, int len);
+void build_entry_key_common(const struct inode *,
+			    const struct qstr *qname, reiser4_key *);
+int build_readdir_key_common(struct file *dir, reiser4_key *);
+int add_entry_common(struct inode *object, struct dentry *where,
+		     reiser4_object_create_data *, reiser4_dir_entry_desc *);
+int rem_entry_common(struct inode *object, struct dentry *where,
+		     reiser4_dir_entry_desc *);
+int init_common(struct inode *object, struct inode *parent,
+		reiser4_object_create_data *);
+int done_common(struct inode *);
+int attach_common(struct inode *child, struct inode *parent);
+int detach_common(struct inode *object, struct inode *parent);
+reiser4_block_nr estimate_add_entry_common(const struct inode *);
+reiser4_block_nr estimate_rem_entry_common(const struct inode *);
+reiser4_block_nr dir_estimate_unlink_common(const struct inode *,
+					    const struct inode *);
+
+/* these are essential parts of common implementations, they are to make
+   customized implementations easier */
+int do_prepare_write(struct file *, struct page *, unsigned from, unsigned to);
+
+/* merely useful functions */
+int locate_inode_sd(struct inode *, reiser4_key *, coord_t *, lock_handle *);
+int lookup_sd(struct inode *, znode_lock_mode, coord_t *, lock_handle *,
+	      const reiser4_key *, int silent);
+
+
+/* __FS_REISER4_PLUGIN_OBJECT_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/plugin.c newtree/fs/reiser4/plugin/plugin.c
--- oldtree/fs/reiser4/plugin/plugin.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/plugin.c	2006-02-21 15:58:35.406763912 +0000
@@ -0,0 +1,598 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Basic plugin infrastructure, lookup etc. */
+
+/* PLUGINS:
+
+   Plugins are internal Reiser4 "modules" or "objects" used to increase
+   extensibility and allow external users to easily adapt reiser4 to
+   their needs.
+
+   Plugins are classified into several disjoint "types". Plugins
+   belonging to the particular plugin type are termed "instances" of
+   this type. Currently the following types are present:
+
+    . object plugin
+    . hash plugin
+    . tail plugin
+    . perm plugin
+    . item plugin
+    . node layout plugin
+
+NIKITA-FIXME-HANS: update this list, and review this entire comment for currency
+
+   Object (file) plugin determines how given file-system object serves
+   standard VFS requests for read, write, seek, mmap etc. Instances of
+   file plugins are: regular file, directory, symlink. Another example
+   of file plugin is audit plugin, that optionally records accesses to
+   underlying object and forwards requests to it.
+
+   Hash plugins compute hashes used by reiser4 to store and locate
+   files within directories. Instances of hash plugin type are: r5,
+   tea, rupasov.
+
+   Tail plugins (or, more precisely, tail policy plugins) determine
+   when last part of the file should be stored in a formatted item.
+
+   Perm plugins control permissions granted for a process accessing a file.
+
+   Scope and lookup:
+
+   label such that pair ( type_label, plugin_label ) is unique.  This
+   pair is a globally persistent and user-visible plugin
+   identifier. Internally kernel maintains plugins and plugin types in
+   arrays using an index into those arrays as plugin and plugin type
+   identifiers. File-system in turn, also maintains persistent
+   "dictionary" which is mapping from plugin label to numerical
+   identifier which is stored in file-system objects.  That is, we
+   store the offset into the plugin array for that plugin type as the
+   plugin id in the stat data of the filesystem object.
+
+   plugin_labels have meaning for the user interface that assigns
+   plugins to files, and may someday have meaning for dynamic loading of
+   plugins and for copying of plugins from one fs instance to
+   another by utilities like cp and tar.
+
+   Internal kernel plugin type identifier (index in plugins[] array) is
+   of type reiser4_plugin_type. Set of available plugin types is
+   currently static, but dynamic loading doesn't seem to pose
+   insurmountable problems.
+
+   Within each type plugins are addressed by the identifiers of type
+   reiser4_plugin_id (indices in
+   reiser4_plugin_type_data.builtin[]). Such identifiers are only
+   required to be unique within one type, not globally.
+
+   Thus, plugin in memory is uniquely identified by the pair (type_id,
+   id).
+
+   Usage:
+
+   There exists only one instance of each plugin instance, but this
+   single instance can be associated with many entities (file-system
+   objects, items, nodes, transactions, file-descriptors etc.). Entity
+   to which plugin of given type is termed (due to the lack of
+   imagination) "subject" of this plugin type and, by abuse of
+   terminology, subject of particular instance of this type to which
+   it's attached currently. For example, inode is subject of object
+   plugin type. Inode representing directory is subject of directory
+   plugin, hash plugin type and some particular instance of hash plugin
+   type. Inode, representing regular file is subject of "regular file"
+   plugin, tail-policy plugin type etc.
+
+   With each subject the plugin possibly stores some state. For example,
+   the state of a directory plugin (instance of object plugin type) is pointer
+   to hash plugin (if directories always use hashing that is). State of
+   audit plugin is file descriptor (struct file) of log file or some
+   magic value to do logging through printk().
+
+   Interface:
+
+   In addition to a scalar identifier, each plugin type and plugin
+   proper has a "label": short string and a "description"---longer
+   descriptive string. Labels and descriptions of plugin types are
+   hard-coded into plugins[] array, declared and defined in
+   plugin.c. Label and description of plugin are stored in .label and
+   .desc fields of reiser4_plugin_header respectively. It's possible to
+   locate plugin by the pair of labels.
+
+   Features:
+
+    . user-level plugin manipulations:
+      + reiser4("filename/..file_plugin<='audit'");
+      + write(open("filename/..file_plugin"), "audit", 8);
+
+    . user level utilities lsplug and chplug to manipulate plugins.
+      Utilities are not of primary priority. Possibly they will be not
+      working on v4.0
+
+NIKITA-FIXME-HANS: this should be a mkreiserfs option not a mount option, do you agree?  I don't think that specifying it at mount time, and then changing it with each mount, is a good model for usage.
+
+    . mount option "plug" to set-up plugins of root-directory.
+      "plug=foo:bar" will set "bar" as default plugin of type "foo".
+
+   Limitations:
+
+    . each plugin type has to provide at least one builtin
+      plugin. This is technical limitation and it can be lifted in the
+      future.
+
+   TODO:
+
+   New plugin types/plugings:
+   Things we should be able to separately choose to inherit:
+
+   security plugins
+
+   stat data
+
+   file bodies
+
+   file plugins
+
+   dir plugins
+
+    . perm:acl
+
+    d audi---audit plugin intercepting and possibly logging all
+      accesses to object. Requires to put stub functions in file_operations
+      in stead of generic_file_*.
+
+NIKITA-FIXME-HANS: why make overflows a plugin?
+    . over---handle hash overflows
+
+    . sqnt---handle different access patterns and instruments read-ahead
+
+NIKITA-FIXME-HANS: describe the line below in more detail.
+
+    . hier---handle inheritance of plugins along file-system hierarchy
+
+   Different kinds of inheritance: on creation vs. on access.
+   Compatible/incompatible plugins.
+   Inheritance for multi-linked files.
+   Layered plugins.
+   Notion of plugin context is abandoned.
+
+Each file is associated
+   with one plugin and dependant plugins (hash, etc.) are stored as
+   main plugin state. Now, if we have plugins used for regular files
+   but not for directories, how such plugins would be inherited?
+    . always store them with directories also
+
+NIKTIA-FIXME-HANS: Do the line above.  It is not exclusive of doing the line below which is also useful.
+
+    . use inheritance hierarchy, independent of file-system namespace
+
+*/
+
+#include "../debug.h"
+#include "../dformat.h"
+#include "plugin_header.h"
+#include "item/static_stat.h"
+#include "node/node.h"
+#include "security/perm.h"
+#include "space/space_allocator.h"
+#include "disk_format/disk_format.h"
+#include "plugin.h"
+#include "../reiser4.h"
+#include "../jnode.h"
+#include "../inode.h"
+
+#include <linux/fs.h>		/* for struct super_block  */
+
+/* public interface */
+
+/* initialise plugin sub-system. Just call this once on reiser4 startup. */
+int init_plugins(void);
+int setup_plugins(struct super_block *super, reiser4_plugin ** area);
+int locate_plugin(struct inode *inode, plugin_locator * loc);
+
+
+/**
+ * init_plugins - initialize plugins
+ *
+ * Initializes plugin sub-system. It is part of reiser4 module
+ * initialization. For each plugin of each type init method is called and each
+ * plugin is put into list of plugins.
+ */
+int init_plugins(void)
+{
+	reiser4_plugin_type type_id;
+
+	for (type_id = 0; type_id < REISER4_PLUGIN_TYPES; ++type_id) {
+		reiser4_plugin_type_data *ptype;
+		int i;
+
+		ptype = &plugins[type_id];
+		assert("nikita-3508", ptype->label != NULL);
+		assert("nikita-3509", ptype->type_id == type_id);
+
+		INIT_LIST_HEAD(&ptype->plugins_list);
+/* NIKITA-FIXME-HANS: change builtin_num to some other name lacking the term builtin. */
+		for (i = 0; i < ptype->builtin_num; ++i) {
+			reiser4_plugin *plugin;
+
+			plugin = plugin_at(ptype, i);
+
+			if (plugin->h.label == NULL)
+				/* uninitialized slot encountered */
+				continue;
+			assert("nikita-3445", plugin->h.type_id == type_id);
+			plugin->h.id = i;
+			if (plugin->h.pops != NULL &&
+			    plugin->h.pops->init != NULL) {
+				int result;
+
+				result = plugin->h.pops->init(plugin);
+				if (result != 0)
+					return result;
+			}
+			INIT_LIST_HEAD(&plugin->h.linkage);
+			list_add_tail(&plugin->h.linkage, &ptype->plugins_list);
+		}
+	}
+	return 0;
+}
+
+/* true if plugin type id is valid */
+int is_type_id_valid(reiser4_plugin_type type_id /* plugin type id */ )
+{
+	/* "type_id" is unsigned, so no comparison with 0 is
+	   necessary */
+	return (type_id < REISER4_PLUGIN_TYPES);
+}
+
+/* true if plugin id is valid */
+int is_plugin_id_valid(reiser4_plugin_type type_id /* plugin type id */ ,
+		       reiser4_plugin_id id /* plugin id */ )
+{
+	assert("nikita-1653", is_type_id_valid(type_id));
+	return id < plugins[type_id].builtin_num;
+}
+
+#if 0
+/* lookup plugin by scanning tables */
+reiser4_plugin *lookup_plugin(const char *type_label /* plugin type label */ ,
+			      const char *plug_label /* plugin label */ )
+{
+	reiser4_plugin *result;
+	reiser4_plugin_type type_id;
+
+	assert("nikita-546", type_label != NULL);
+	assert("nikita-547", plug_label != NULL);
+
+	type_id = find_type(type_label);
+	if (is_type_id_valid(type_id))
+		result = find_plugin(&plugins[type_id], plug_label);
+	else
+		result = NULL;
+	return result;
+}
+#endif  /*  0  */
+
+/* return plugin by its @type_id and @id.
+
+   Both arguments are checked for validness: this is supposed to be called
+   from user-level.
+
+NIKITA-FIXME-HANS: Do you instead mean that this checks ids created in
+user space, and passed to the filesystem by use of method files? Your
+comment really confused me on the first reading....
+
+*/
+reiser4_plugin *plugin_by_unsafe_id(reiser4_plugin_type type_id	/* plugin
+								 * type id,
+								 * unchecked */ ,
+				    reiser4_plugin_id id	/* plugin id,
+								 * unchecked */ )
+{
+	if (is_type_id_valid(type_id)) {
+		if (is_plugin_id_valid(type_id, id))
+			return plugin_at(&plugins[type_id], id);
+		else
+			/* id out of bounds */
+			warning("nikita-2913",
+				"Invalid plugin id: [%i:%i]", type_id, id);
+	} else
+		/* type_id out of bounds */
+		warning("nikita-2914", "Invalid type_id: %i", type_id);
+	return NULL;
+}
+
+/**
+ * save_plugin_id - store plugin id in disk format
+ * @plugin: plugin to convert
+ * @area: where to store result
+ *
+ * Puts id of @plugin in little endian format to address @area.
+ */
+int save_plugin_id(reiser4_plugin *plugin /* plugin to convert */ ,
+		   d16 *area /* where to store result */ )
+{
+	assert("nikita-1261", plugin != NULL);
+	assert("nikita-1262", area != NULL);
+
+	put_unaligned(cpu_to_le16(plugin->h.id), area);
+	return 0;
+}
+
+/* list of all plugins of given type */
+struct list_head *get_plugin_list(reiser4_plugin_type type_id	/* plugin type
+								 * id */ )
+{
+	assert("nikita-1056", is_type_id_valid(type_id));
+	return &plugins[type_id].plugins_list;
+}
+
+#if 0
+
+/* find plugin type by label */
+static reiser4_plugin_type find_type(const char *label	/* plugin type
+							 * label */ )
+{
+	reiser4_plugin_type type_id;
+
+	assert("nikita-550", label != NULL);
+
+	for (type_id = 0; type_id < REISER4_PLUGIN_TYPES &&
+	     strcmp(label, plugins[type_id].label); ++type_id) {
+		;
+	}
+	return type_id;
+}
+
+/* given plugin label find it within given plugin type by scanning
+    array. Used to map user-visible symbolic name to internal kernel
+    id */
+static reiser4_plugin *find_plugin(reiser4_plugin_type_data * ptype	/* plugin
+									 * type to
+									 * find
+									 * plugin
+									 * within */ ,
+				   const char *label /* plugin label */ )
+{
+	int i;
+	reiser4_plugin *result;
+
+	assert("nikita-551", ptype != NULL);
+	assert("nikita-552", label != NULL);
+
+	for (i = 0; i < ptype->builtin_num; ++i) {
+		result = plugin_at(ptype, i);
+		if (result->h.label == NULL)
+			continue;
+		if (!strcmp(result->h.label, label))
+			return result;
+	}
+	return NULL;
+}
+
+#endif  /*  0  */
+
+int grab_plugin(struct inode *self, struct inode *ancestor, pset_member memb)
+{
+	reiser4_plugin *plug;
+	reiser4_inode *parent;
+
+	parent = reiser4_inode_data(ancestor);
+	plug = pset_get(parent->hset, memb) ? : pset_get(parent->pset, memb);
+	return grab_plugin_from(self, memb, plug);
+}
+
+static void update_plugin_mask(reiser4_inode * info, pset_member memb)
+{
+	struct dentry *rootdir;
+	reiser4_inode *root;
+
+	rootdir = inode_by_reiser4_inode(info)->i_sb->s_root;
+	if (rootdir != NULL) {
+		root = reiser4_inode_data(rootdir->d_inode);
+		/*
+		 * if inode is different from the default one, or we are
+		 * changing plugin of root directory, update plugin_mask
+		 */
+		if (pset_get(info->pset, memb) != pset_get(root->pset, memb) ||
+		    info == root)
+			info->plugin_mask |= (1 << memb);
+	}
+}
+
+int
+grab_plugin_from(struct inode *self, pset_member memb, reiser4_plugin * plug)
+{
+	reiser4_inode *info;
+	int result = 0;
+
+	info = reiser4_inode_data(self);
+	if (pset_get(info->pset, memb) == NULL) {
+		result = pset_set(&info->pset, memb, plug);
+		if (result == 0)
+			update_plugin_mask(info, memb);
+	}
+	return result;
+}
+
+int force_plugin(struct inode *self, pset_member memb, reiser4_plugin * plug)
+{
+	reiser4_inode *info;
+	int result = 0;
+
+	info = reiser4_inode_data(self);
+	if (plug->h.pops != NULL && plug->h.pops->change != NULL)
+		result = plug->h.pops->change(self, plug);
+	else
+		result = pset_set(&info->pset, memb, plug);
+	if (result == 0)
+		update_plugin_mask(info, memb);
+	return result;
+}
+
+reiser4_plugin_type_data plugins[REISER4_PLUGIN_TYPES] = {
+	/* C90 initializers */
+	[REISER4_FILE_PLUGIN_TYPE] = {
+		.type_id = REISER4_FILE_PLUGIN_TYPE,
+		.label = "file",
+		.desc = "Object plugins",
+		.builtin_num = sizeof_array(file_plugins),
+		.builtin = file_plugins,
+		.plugins_list = {NULL, NULL},
+		.size = sizeof(file_plugin)
+	},
+	[REISER4_DIR_PLUGIN_TYPE] = {
+		.type_id = REISER4_DIR_PLUGIN_TYPE,
+		.label = "dir",
+		.desc = "Directory plugins",
+		.builtin_num = sizeof_array(dir_plugins),
+		.builtin = dir_plugins,
+		.plugins_list = {NULL, NULL},
+		.size = sizeof(dir_plugin)
+	},
+	[REISER4_HASH_PLUGIN_TYPE] = {
+		.type_id = REISER4_HASH_PLUGIN_TYPE,
+		.label = "hash",
+		.desc = "Directory hashes",
+		.builtin_num = sizeof_array(hash_plugins),
+		.builtin = hash_plugins,
+		.plugins_list = {NULL, NULL},
+		.size = sizeof(hash_plugin)
+	},
+	[REISER4_FIBRATION_PLUGIN_TYPE] = {
+		.type_id =
+		REISER4_FIBRATION_PLUGIN_TYPE,
+		.label = "fibration",
+		.desc = "Directory fibrations",
+		.builtin_num = sizeof_array(fibration_plugins),
+		.builtin = fibration_plugins,
+		.plugins_list =	{NULL, NULL},
+		.size = sizeof(fibration_plugin)
+	},
+	[REISER4_CIPHER_PLUGIN_TYPE] = {
+		.type_id = REISER4_CIPHER_PLUGIN_TYPE,
+		.label = "cipher",
+		.desc = "Cipher plugins",
+		.builtin_num = sizeof_array(cipher_plugins),
+		.builtin = cipher_plugins,
+		.plugins_list =	{NULL, NULL},
+		.size = sizeof(cipher_plugin)
+	},
+	[REISER4_DIGEST_PLUGIN_TYPE] = {
+		.type_id = REISER4_DIGEST_PLUGIN_TYPE,
+		.label = "digest",
+		.desc = "Digest plugins",
+		.builtin_num = sizeof_array(digest_plugins),
+		.builtin = digest_plugins,
+		.plugins_list =	{NULL, NULL},
+		.size = sizeof(digest_plugin)
+	},
+	[REISER4_COMPRESSION_PLUGIN_TYPE] = {
+		.type_id = REISER4_COMPRESSION_PLUGIN_TYPE,
+		.label = "compression",
+		.desc = "Compression plugins",
+		.builtin_num = sizeof_array(compression_plugins),
+		.builtin = compression_plugins,
+		.plugins_list = {NULL, NULL},
+		.size = sizeof(compression_plugin)
+	},
+	[REISER4_FORMATTING_PLUGIN_TYPE] = {
+		.type_id = REISER4_FORMATTING_PLUGIN_TYPE,
+		.label = "formatting",
+		.desc = "Tail inlining policies",
+		.builtin_num = sizeof_array(formatting_plugins),
+		.builtin = formatting_plugins,
+		.plugins_list = {NULL, NULL},
+		.size = sizeof(formatting_plugin)
+	},
+	[REISER4_PERM_PLUGIN_TYPE] = {
+		.type_id = REISER4_PERM_PLUGIN_TYPE,
+		.label = "perm",
+		.desc = "Permission checks",
+		.builtin_num = sizeof_array(perm_plugins),
+		.builtin = perm_plugins,
+		.plugins_list = {NULL, NULL},
+		.size = sizeof(perm_plugin)
+	},
+	[REISER4_ITEM_PLUGIN_TYPE] = {
+		.type_id = REISER4_ITEM_PLUGIN_TYPE,
+		.label = "item",
+		.desc = "Item handlers",
+		.builtin_num = sizeof_array(item_plugins),
+		.builtin = item_plugins,
+		.plugins_list = {NULL, NULL},
+		.size = sizeof(item_plugin)
+	},
+	[REISER4_NODE_PLUGIN_TYPE] = {
+		.type_id = REISER4_NODE_PLUGIN_TYPE,
+		.label = "node",
+		.desc = "node layout handlers",
+		.builtin_num = sizeof_array(node_plugins),
+		.builtin = node_plugins,
+		.plugins_list = {NULL, NULL},
+		.size = sizeof(node_plugin)
+	},
+	[REISER4_SD_EXT_PLUGIN_TYPE] = {
+		.type_id = REISER4_SD_EXT_PLUGIN_TYPE,
+		.label = "sd_ext",
+		.desc = "Parts of stat-data",
+		.builtin_num = sizeof_array(sd_ext_plugins),
+		.builtin = sd_ext_plugins,
+		.plugins_list = {NULL, NULL},
+		.size = sizeof(sd_ext_plugin)
+	},
+	[REISER4_FORMAT_PLUGIN_TYPE] = {
+		.type_id = REISER4_FORMAT_PLUGIN_TYPE,
+		.label = "disk_layout",
+		.desc = "defines filesystem on disk layout",
+		.builtin_num = sizeof_array(format_plugins),
+		.builtin = format_plugins,
+		.plugins_list = {NULL, NULL},
+		.size = sizeof(disk_format_plugin)
+	},
+	[REISER4_JNODE_PLUGIN_TYPE] = {
+		.type_id = REISER4_JNODE_PLUGIN_TYPE,
+		.label = "jnode",
+		.desc = "defines kind of jnode",
+		.builtin_num = sizeof_array(jnode_plugins),
+		.builtin = jnode_plugins,
+		.plugins_list = {NULL, NULL},
+		.size = sizeof(jnode_plugin)
+	},
+	[REISER4_COMPRESSION_MODE_PLUGIN_TYPE] = {
+		.type_id = REISER4_COMPRESSION_MODE_PLUGIN_TYPE,
+		.label = "compression_mode",
+		.desc = "Defines compression mode",
+		.builtin_num = sizeof_array(compression_mode_plugins),
+		.builtin = compression_mode_plugins,
+		.plugins_list = {NULL, NULL},
+		.size = sizeof(compression_mode_plugin)
+	},
+	[REISER4_CLUSTER_PLUGIN_TYPE] = {
+		.type_id = REISER4_CLUSTER_PLUGIN_TYPE,
+		.label = "cluster",
+		.desc = "Defines cluster size",
+		.builtin_num = sizeof_array(cluster_plugins),
+		.builtin = cluster_plugins,
+		.plugins_list = {NULL, NULL},
+		.size = sizeof(cluster_plugin)
+	},
+	[REISER4_REGULAR_PLUGIN_TYPE] = {
+		.type_id = REISER4_REGULAR_PLUGIN_TYPE,
+		.label = "regular",
+		.desc = "Defines kind of regular file",
+		.builtin_num =
+		sizeof_array(regular_plugins),
+		.builtin = regular_plugins,
+		.plugins_list = {NULL, NULL},
+		.size = sizeof(regular_plugin)
+	}
+};
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 120
+ * End:
+ */
diff -urN oldtree/fs/reiser4/plugin/plugin.h newtree/fs/reiser4/plugin/plugin.h
--- oldtree/fs/reiser4/plugin/plugin.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/plugin.h	2006-02-21 15:58:35.451757072 +0000
@@ -0,0 +1,938 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Basic plugin data-types.
+   see fs/reiser4/plugin/plugin.c for details */
+
+#if !defined( __FS_REISER4_PLUGIN_TYPES_H__ )
+#define __FS_REISER4_PLUGIN_TYPES_H__
+
+#include "../forward.h"
+#include "../debug.h"
+#include "../dformat.h"
+#include "../key.h"
+#include "compress/compress.h"
+#include "crypto/cipher.h"
+#include "plugin_header.h"
+#include "item/static_stat.h"
+#include "item/internal.h"
+#include "item/sde.h"
+#include "item/cde.h"
+#include "item/item.h"
+#include "node/node.h"
+#include "node/node40.h"
+#include "security/perm.h"
+#include "fibration.h"
+
+#include "space/bitmap.h"
+#include "space/space_allocator.h"
+
+#include "disk_format/disk_format40.h"
+#include "disk_format/disk_format.h"
+
+#include <linux/fs.h>		/* for struct super_block, address_space  */
+#include <linux/mm.h>		/* for struct page */
+#include <linux/buffer_head.h>	/* for struct buffer_head */
+#include <linux/dcache.h>	/* for struct dentry */
+#include <linux/types.h>
+#include <linux/crypto.h>
+
+typedef struct reiser4_object_on_wire reiser4_object_on_wire;
+
+/*
+ * File plugin.  Defines the set of methods that file plugins implement, some
+ * of which are optional.
+ *
+ * A file plugin offers to the caller an interface for IO ( writing to and/or
+ * reading from) to what the caller sees as one sequence of bytes.  An IO to it
+ * may affect more than one physical sequence of bytes, or no physical sequence
+ * of bytes, it may affect sequences of bytes offered by other file plugins to
+ * the semantic layer, and the file plugin may invoke other plugins and
+ * delegate work to them, but its interface is structured for offering the
+ * caller the ability to read and/or write what the caller sees as being a
+ * single sequence of bytes.
+ *
+ * The file plugin must present a sequence of bytes to the caller, but it does
+ * not necessarily have to store a sequence of bytes, it does not necessarily
+ * have to support efficient tree traversal to any offset in the sequence of
+ * bytes (tail and extent items, whose keys contain offsets, do however provide
+ * efficient non-sequential lookup of any offset in the sequence of bytes).
+ *
+ * Directory plugins provide methods for selecting file plugins by resolving a
+ * name for them.
+ *
+ * The functionality other filesystems call an attribute, and rigidly tie
+ * together, we decompose into orthogonal selectable features of files.  Using
+ * the terminology we will define next, an attribute is a perhaps constrained,
+ * perhaps static length, file whose parent has a uni-count-intra-link to it,
+ * which might be grandparent-major-packed, and whose parent has a deletion
+ * method that deletes it.
+ *
+ * File plugins can implement constraints.
+ *
+ * Files can be of variable length (e.g. regular unix files), or of static
+ * length (e.g. static sized attributes).
+ *
+ * An object may have many sequences of bytes, and many file plugins, but, it
+ * has exactly one objectid.  It is usually desirable that an object has a
+ * deletion method which deletes every item with that objectid.  Items cannot
+ * in general be found by just their objectids.  This means that an object must
+ * have either a method built into its deletion plugin method for knowing what
+ * items need to be deleted, or links stored with the object that provide the
+ * plugin with a method for finding those items.  Deleting a file within an
+ * object may or may not have the effect of deleting the entire object,
+ * depending on the file plugin's deletion method.
+ *
+ * LINK TAXONOMY:
+ *
+ * Many objects have a reference count, and when the reference count reaches 0
+ * the object's deletion method is invoked.  Some links embody a reference
+ * count increase ("countlinks"), and others do not ("nocountlinks").
+ *
+ * Some links are bi-directional links ("bilinks"), and some are
+ * uni-directional("unilinks").
+ *
+ * Some links are between parts of the same object ("intralinks"), and some are
+ * between different objects ("interlinks").
+ *
+ * PACKING TAXONOMY:
+ *
+ * Some items of an object are stored with a major packing locality based on
+ * their object's objectid (e.g. unix directory items in plan A), and these are
+ * called "self-major-packed".
+ *
+ * Some items of an object are stored with a major packing locality based on
+ * their semantic parent object's objectid (e.g. unix file bodies in plan A),
+ * and these are called "parent-major-packed".
+ *
+ * Some items of an object are stored with a major packing locality based on
+ * their semantic grandparent, and these are called "grandparent-major-packed".
+ * Now carefully notice that we run into trouble with key length if we have to
+ * store a 8 byte major+minor grandparent based packing locality, an 8 byte
+ * parent objectid, an 8 byte attribute objectid, and an 8 byte offset, all in
+ * a 24 byte key.  One of these fields must be sacrificed if an item is to be
+ * grandparent-major-packed, and which to sacrifice is left to the item author
+ * choosing to make the item grandparent-major-packed.  You cannot make tail
+ * items and extent items grandparent-major-packed, though you could make them
+ * self-major-packed (usually they are parent-major-packed).
+ *
+ * In the case of ACLs (which are composed of fixed length ACEs which consist
+ * of {subject-type, subject, and permission bitmask} triples), it makes sense
+ * to not have an offset field in the ACE item key, and to allow duplicate keys
+ * for ACEs.  Thus, the set of ACES for a given file is found by looking for a
+ * key consisting of the objectid of the grandparent (thus grouping all ACLs in
+ * a directory together), the minor packing locality of ACE, the objectid of
+ * the file, and 0.
+ *
+ * IO involves moving data from one location to another, which means that two
+ * locations must be specified, source and destination.
+ *
+ * This source and destination can be in the filesystem, or they can be a
+ * pointer in the user process address space plus a byte count.
+ *
+ * If both source and destination are in the filesystem, then at least one of
+ * them must be representable as a pure stream of bytes (which we call a flow,
+ * and define as a struct containing a key, a data pointer, and a length).
+ * This may mean converting one of them into a flow.  We provide a generic
+ * cast_into_flow() method, which will work for any plugin supporting
+ * read_flow(), though it is inefficiently implemented in that it temporarily
+ * stores the flow in a buffer (Question: what to do with huge flows that
+ * cannot fit into memory?  Answer: we must not convert them all at once. )
+ *
+ * Performing a write requires resolving the write request into a flow defining
+ * the source, and a method that performs the write, and a key that defines
+ * where in the tree the write is to go.
+ *
+ * Performing a read requires resolving the read request into a flow defining
+ * the target, and a method that performs the read, and a key that defines
+ * where in the tree the read is to come from.
+ *
+ * There will exist file plugins which have no pluginid stored on the disk for
+ * them, and which are only invoked by other plugins.
+ */
+
+/* builtin file-plugins */
+typedef enum {
+	/* regular file */
+	UNIX_FILE_PLUGIN_ID,
+	/* directory */
+	DIRECTORY_FILE_PLUGIN_ID,
+	/* symlink */
+	SYMLINK_FILE_PLUGIN_ID,
+	/* for objects completely handled by the VFS: fifos, devices,
+	   sockets  */
+	SPECIAL_FILE_PLUGIN_ID,
+	/* regular cryptcompress file */
+	CRC_FILE_PLUGIN_ID,
+	/* number of file plugins. Used as size of arrays to hold
+	   file plugins. */
+	LAST_FILE_PLUGIN_ID
+} reiser4_file_id;
+
+typedef struct file_plugin {
+
+	/* generic fields */
+	plugin_header h;
+
+	struct inode_operations inode_ops;
+	struct file_operations file_ops;
+	struct address_space_operations as_ops;
+
+	/* save inode cached stat-data onto disk. It was called
+	   reiserfs_update_sd() in 3.x */
+	int (*write_sd_by_inode) (struct inode *);
+
+	/*
+	 * private methods: These are optional.  If used they will allow you to
+	 * minimize the amount of code needed to implement a deviation from
+	 * some other method that also uses them.
+	 */
+
+	/*
+	 * Construct flow into @flow according to user-supplied data.
+	 *
+	 * This is used by read/write methods to construct a flow to
+	 * write/read. ->flow_by_inode() is plugin method, rather than single
+	 * global implementation, because key in a flow used by plugin may
+	 * depend on data in a @buf.
+	 *
+	 * NIKITA-FIXME-HANS: please create statistics on what functions are
+	 * dereferenced how often for the mongo benchmark.  You can supervise
+	 * Elena doing this for you if that helps.  Email me the list of the
+	 * top 10, with their counts, and an estimate of the total number of
+	 * CPU cycles spent dereferencing as a percentage of CPU cycles spent
+	 * processing (non-idle processing).  If the total percent is, say,
+	 * less than 1%, it will make our coding discussions much easier, and
+	 * keep me from questioning whether functions like the below are too
+	 * frequently called to be dereferenced.  If the total percent is more
+	 * than 1%, perhaps private methods should be listed in a "required"
+	 * comment at the top of each plugin (with stern language about how if
+	 * the comment is missing it will not be accepted by the maintainer),
+	 * and implemented using macros not dereferenced functions.  How about
+	 * replacing this whole private methods part of the struct with a
+	 * thorough documentation of what the standard helper functions are for
+	 * use in constructing plugins?  I think users have been asking for
+	 * that, though not in so many words.
+	 */
+	int (*flow_by_inode) (struct inode *, const char __user *buf,
+			      int user, loff_t size,
+			      loff_t off, rw_op op, flow_t *);
+
+	/*
+	 * Return the key used to retrieve an offset of a file. It is used by
+	 * default implementation of ->flow_by_inode() method
+	 * (common_build_flow()) and, among other things, to get to the extent
+	 * from jnode of unformatted node.
+	 */
+	int (*key_by_inode) (struct inode *, loff_t off, reiser4_key *);
+
+	/* NIKITA-FIXME-HANS: this comment is not as clear to others as you think.... */
+	/*
+	 * set the plugin for a file.  Called during file creation in creat()
+	 * but not reiser4() unless an inode already exists for the file.
+	 */
+	int (*set_plug_in_inode) (struct inode *inode, struct inode *parent,
+				  reiser4_object_create_data *);
+
+	/* NIKITA-FIXME-HANS: comment and name seem to say different things,
+	 * are you setting up the object itself also or just adjusting the
+	 * parent?.... */
+	/* set up plugins for new @object created in @parent. @root is root
+	   directory. */
+	int (*adjust_to_parent) (struct inode *object, struct inode *parent,
+				 struct inode *root);
+	/*
+	 * this does whatever is necessary to do when object is created. For
+	 * instance, for unix files stat data is inserted. It is supposed to be
+	 * called by create of struct inode_operations.
+	 */
+	int (*create_object) (struct inode *object, struct inode *parent,
+			      reiser4_object_create_data *);
+
+	/* this does whatever is necessary to do when object is opened */
+	int (*open_object) (struct inode * inode, struct file * file);
+	/*
+	 * this method should check REISER4_NO_SD and set REISER4_NO_SD on
+	 * success. Deletion of an object usually includes removal of items
+	 * building file body (for directories this is removal of "." and "..")
+	 * and removal of stat-data item.
+	 */
+	int (*delete_object) (struct inode *);
+
+	/* add link from @parent to @object */
+	int (*add_link) (struct inode *object, struct inode *parent);
+
+	/* remove link from @parent to @object */
+	int (*rem_link) (struct inode *object, struct inode *parent);
+
+	/*
+	 * return true if item addressed by @coord belongs to @inode.  This is
+	 * used by read/write to properly slice flow into items in presence of
+	 * multiple key assignment policies, because items of a file are not
+	 * necessarily contiguous in a key space, for example, in a plan-b.
+	 */
+	int (*owns_item) (const struct inode *, const coord_t *);
+
+	/* checks whether yet another hard links to this object can be
+	   added  */
+	int (*can_add_link) (const struct inode *);
+
+	/* checks whether hard links to this object can be removed */
+	int (*can_rem_link) (const struct inode *);
+
+	/* not empty for DIRECTORY_FILE_PLUGIN_ID only currently. It calls
+	   detach of directory plugin to remove ".." */
+	int (*detach) (struct inode * child, struct inode * parent);
+
+	/* called when @child was just looked up in the @parent. It is not
+	   empty for DIRECTORY_FILE_PLUGIN_ID only where it calls attach of
+	   directory plugin */
+	int (*bind) (struct inode * child, struct inode * parent);
+
+	/* process safe-link during mount */
+	int (*safelink) (struct inode * object, reiser4_safe_link_t link,
+			 __u64 value);
+
+	/* The couple of estimate methods for all file operations */
+	struct {
+		reiser4_block_nr(*create) (const struct inode *);
+		reiser4_block_nr(*update) (const struct inode *);
+		reiser4_block_nr(*unlink) (const struct inode *,
+					   const struct inode *);
+	} estimate;
+
+	/*
+	 * reiser4 specific part of inode has a union of structures which are
+	 * specific to a plugin. This method is called when inode is read
+	 * (read_inode) and when file is created (common_create_child) so that
+	 * file plugin could initialize its inode data
+	 */
+	void (*init_inode_data) (struct inode *, reiser4_object_create_data *,
+				 int);
+
+	/*
+	 * This method performs progressive deletion of items and whole nodes
+	 * from right to left.
+	 *
+	 * @tap: the point deletion process begins from,
+	 * @from_key: the beginning of the deleted key range,
+	 * @to_key: the end of the deleted key range,
+	 * @smallest_removed: the smallest removed key,
+	 *
+	 * @return: 0 if success, error code otherwise, -E_REPEAT means that long cut_tree
+	 * operation was interrupted for allowing atom commit .
+	 */
+	int (*cut_tree_worker) (tap_t *, const reiser4_key * from_key,
+				const reiser4_key * to_key,
+				reiser4_key * smallest_removed, struct inode *,
+				int, int *);
+
+	/* called from ->destroy_inode() */
+	void (*destroy_inode) (struct inode *);
+
+	/*
+	 * methods to serialize object identify. This is used, for example, by
+	 * reiser4_{en,de}code_fh().
+	 */
+	struct {
+		/* store object's identity at @area */
+		char *(*write) (struct inode * inode, char *area);
+		/* parse object from wire to the @obj */
+		char *(*read) (char *area, reiser4_object_on_wire * obj);
+		/* given object identity in @obj, find or create its dentry */
+		struct dentry *(*get) (struct super_block * s,
+				       reiser4_object_on_wire * obj);
+		/* how many bytes ->wire.write() consumes */
+		int (*size) (struct inode * inode);
+		/* finish with object identify */
+		void (*done) (reiser4_object_on_wire * obj);
+	} wire;
+} file_plugin;
+
+extern file_plugin file_plugins[LAST_FILE_PLUGIN_ID];
+
+struct reiser4_object_on_wire {
+	file_plugin *plugin;
+	union {
+		struct {
+			obj_key_id key_id;
+		} std;
+		void *generic;
+	} u;
+};
+
+/* builtin dir-plugins */
+typedef enum {
+	HASHED_DIR_PLUGIN_ID,
+	SEEKABLE_HASHED_DIR_PLUGIN_ID,
+	LAST_DIR_ID
+} reiser4_dir_id;
+
+typedef struct dir_plugin {
+	/* generic fields */
+	plugin_header h;
+
+	struct inode_operations inode_ops;
+	struct file_operations file_ops;
+	struct address_space_operations as_ops;
+
+	/*
+	 * private methods: These are optional.  If used they will allow you to
+	 * minimize the amount of code needed to implement a deviation from
+	 * some other method that uses them.  You could logically argue that
+	 * they should be a separate type of plugin.
+	 */
+
+	struct dentry *(*get_parent) (struct inode * childdir);
+
+	/*
+	 * check whether "name" is acceptable name to be inserted into this
+	 * object. Optionally implemented by directory-like objects.  Can check
+	 * for maximal length, reserved symbols etc
+	 */
+	int (*is_name_acceptable) (const struct inode * inode, const char *name,
+				   int len);
+
+	void (*build_entry_key) (const struct inode * dir	/* directory where
+								 * entry is (or will
+								 * be) in.*/ ,
+				 const struct qstr * name	/* name of file
+								 * referenced by this
+								 * entry */ ,
+				 reiser4_key * result	/* resulting key of
+							 * directory entry */ );
+	int (*build_readdir_key) (struct file * dir, reiser4_key * result);
+	int (*add_entry) (struct inode * object, struct dentry * where,
+			  reiser4_object_create_data * data,
+			  reiser4_dir_entry_desc * entry);
+	int (*rem_entry) (struct inode * object, struct dentry * where,
+			  reiser4_dir_entry_desc * entry);
+
+	/*
+	 * initialize directory structure for newly created object. For normal
+	 * unix directories, insert dot and dotdot.
+	 */
+	int (*init) (struct inode * object, struct inode * parent,
+		     reiser4_object_create_data * data);
+
+	/* destroy directory */
+	int (*done) (struct inode * child);
+
+	/* called when @subdir was just looked up in the @dir */
+	int (*attach) (struct inode * subdir, struct inode * dir);
+	int (*detach) (struct inode * subdir, struct inode * dir);
+
+	struct {
+		reiser4_block_nr(*add_entry) (const struct inode *);
+		reiser4_block_nr(*rem_entry) (const struct inode *);
+		reiser4_block_nr(*unlink) (const struct inode *,
+					   const struct inode *);
+	} estimate;
+} dir_plugin;
+
+extern dir_plugin dir_plugins[LAST_DIR_ID];
+
+typedef struct formatting_plugin {
+	/* generic fields */
+	plugin_header h;
+	/* returns non-zero iff file's tail has to be stored
+	   in a direct item. */
+	int (*have_tail) (const struct inode * inode, loff_t size);
+} formatting_plugin;
+
+typedef struct hash_plugin {
+	/* generic fields */
+	plugin_header h;
+	/* computes hash of the given name */
+	 __u64(*hash) (const unsigned char *name, int len);
+} hash_plugin;
+
+typedef struct cipher_plugin {
+	/* generic fields */
+	plugin_header h;
+	struct crypto_tfm * (*alloc) (void);
+	void (*free) (struct crypto_tfm * tfm);
+	/* Offset translator. For each offset this returns (k * offset), where
+	   k (k >= 1) is an expansion factor of the cipher algorithm.
+	   For all symmetric algorithms k == 1. For asymmetric algorithms (which
+	   inflate data) offset translation guarantees that all disk cluster's
+	   units will have keys smaller then next cluster's one.
+	 */
+	 loff_t(*scale) (struct inode * inode, size_t blocksize, loff_t src);
+	/* Cipher algorithms can accept data only by chunks of cipher block
+	   size. This method is to align any flow up to cipher block size when
+	   we pass it to cipher algorithm. To align means to append padding of
+	   special format specific to the cipher algorithm */
+	int (*align_stream) (__u8 * tail, int clust_size, int blocksize);
+	/* low-level key manager (check, install, etc..) */
+	int (*setkey) (struct crypto_tfm * tfm, const __u8 * key,
+		       unsigned int keylen);
+	/* main text processing procedures */
+	void (*encrypt) (__u32 * expkey, __u8 * dst, const __u8 * src);
+	void (*decrypt) (__u32 * expkey, __u8 * dst, const __u8 * src);
+} cipher_plugin;
+
+typedef struct digest_plugin {
+	/* generic fields */
+	plugin_header h;
+	/* fingerprint size in bytes */
+	int fipsize;
+	struct crypto_tfm * (*alloc) (void);
+	void (*free) (struct crypto_tfm * tfm);
+} digest_plugin;
+
+typedef struct compression_plugin {
+	/* generic fields */
+	plugin_header h;
+	/* id of the dual plugin */
+	reiser4_compression_id dual;
+	int (*init) (void);
+	/* the maximum number of bytes the size of the "compressed" data can
+	 * exceed the uncompressed data. */
+	int (*overrun) (unsigned src_len);
+	 coa_t(*alloc) (tfm_action act);
+	void (*free) (coa_t coa, tfm_action act);
+	/* minimal size of the flow we still try to compress */
+	int (*min_size_deflate) (void);
+	 __u32(*checksum) (char *data, __u32 length);
+	/* main transform procedures */
+	void (*compress) (coa_t coa, __u8 * src_first, unsigned src_len,
+			  __u8 * dst_first, unsigned *dst_len);
+	void (*decompress) (coa_t coa, __u8 * src_first, unsigned src_len,
+			    __u8 * dst_first, unsigned *dst_len);
+} compression_plugin;
+
+typedef struct compression_mode_plugin {
+	/* generic fields */
+	plugin_header h;
+	/* this is called when estimating compressibility
+	   of a logical cluster by its content */
+	int (*should_deflate) (struct inode * inode, cloff_t index);
+	/* this is called when results of compression should be saved */
+	int (*accept_hook) (struct inode * inode, cloff_t index);
+	/* this is called when results of compression should be discarded */
+	int (*discard_hook) (struct inode * inode, cloff_t index);
+} compression_mode_plugin;
+
+typedef struct regular_plugin {
+	/* generic fields */
+	plugin_header h;
+	/* file plugin id which implements regular file */
+	reiser4_file_id id;
+} regular_plugin;
+
+typedef struct cluster_plugin {
+	/* generic fields */
+	plugin_header h;
+	int shift;
+} cluster_plugin;
+
+typedef struct sd_ext_plugin {
+	/* generic fields */
+	plugin_header h;
+	int (*present) (struct inode * inode, char **area, int *len);
+	int (*absent) (struct inode * inode);
+	int (*save_len) (struct inode * inode);
+	int (*save) (struct inode * inode, char **area);
+	/* alignment requirement for this stat-data part */
+	int alignment;
+} sd_ext_plugin;
+
+/* this plugin contains methods to allocate objectid for newly created files,
+   to deallocate objectid when file gets removed, to report number of used and
+   free objectids */
+typedef struct oid_allocator_plugin {
+	/* generic fields */
+	plugin_header h;
+	int (*init_oid_allocator) (reiser4_oid_allocator * map, __u64 nr_files,
+				   __u64 oids);
+	/* used to report statfs->f_files */
+	 __u64(*oids_used) (reiser4_oid_allocator * map);
+	/* get next oid to use */
+	 __u64(*next_oid) (reiser4_oid_allocator * map);
+	/* used to report statfs->f_ffree */
+	 __u64(*oids_free) (reiser4_oid_allocator * map);
+	/* allocate new objectid */
+	int (*allocate_oid) (reiser4_oid_allocator * map, oid_t *);
+	/* release objectid */
+	int (*release_oid) (reiser4_oid_allocator * map, oid_t);
+	/* how many pages to reserve in transaction for allocation of new
+	   objectid */
+	int (*oid_reserve_allocate) (reiser4_oid_allocator * map);
+	/* how many pages to reserve in transaction for freeing of an
+	   objectid */
+	int (*oid_reserve_release) (reiser4_oid_allocator * map);
+	void (*print_info) (const char *, reiser4_oid_allocator *);
+} oid_allocator_plugin;
+
+/* disk layout plugin: this specifies super block, journal, bitmap (if there
+   are any) locations, etc */
+typedef struct disk_format_plugin {
+	/* generic fields */
+	plugin_header h;
+	/* replay journal, initialize super_info_data, etc */
+	int (*init_format) (struct super_block *, void *data);
+
+	/* key of root directory stat data */
+	const reiser4_key *(*root_dir_key) (const struct super_block *);
+
+	int (*release) (struct super_block *);
+	jnode *(*log_super) (struct super_block *);
+	int (*check_open) (const struct inode * object);
+} disk_format_plugin;
+
+struct jnode_plugin {
+	/* generic fields */
+	plugin_header h;
+	int (*init) (jnode * node);
+	int (*parse) (jnode * node);
+	struct address_space *(*mapping) (const jnode * node);
+	unsigned long (*index) (const jnode * node);
+	jnode *(*clone) (jnode * node);
+};
+
+/* plugin instance.                                                         */
+/*                                                                          */
+/* This is "wrapper" union for all types of plugins. Most of the code uses  */
+/* plugins of particular type (file_plugin, dir_plugin, etc.)  rather than  */
+/* operates with pointers to reiser4_plugin. This union is only used in     */
+/* some generic code in plugin/plugin.c that operates on all                */
+/* plugins. Technically speaking purpose of this union is to add type       */
+/* safety to said generic code: each plugin type (file_plugin, for          */
+/* example), contains plugin_header as its first memeber. This first member */
+/* is located at the same place in memory as .h member of                   */
+/* reiser4_plugin. Generic code, obtains pointer to reiser4_plugin and      */
+/* looks in the .h which is header of plugin type located in union. This    */
+/* allows to avoid type-casts.                                              */
+union reiser4_plugin {
+	/* generic fields */
+	plugin_header h;
+	/* file plugin */
+	file_plugin file;
+	/* directory plugin */
+	dir_plugin dir;
+	/* hash plugin, used by directory plugin */
+	hash_plugin hash;
+	/* fibration plugin used by directory plugin */
+	fibration_plugin fibration;
+	/* cipher transform plugin, used by file plugin */
+	cipher_plugin cipher;
+	/* digest transform plugin, used by file plugin */
+	digest_plugin digest;
+	/* compression transform plugin, used by file plugin */
+	compression_plugin compression;
+	/* tail plugin, used by file plugin */
+	formatting_plugin formatting;
+	/* permission plugin */
+	perm_plugin perm;
+	/* node plugin */
+	node_plugin node;
+	/* item plugin */
+	item_plugin item;
+	/* stat-data extension plugin */
+	sd_ext_plugin sd_ext;
+	/* disk layout plugin */
+	disk_format_plugin format;
+	/* object id allocator plugin */
+	oid_allocator_plugin oid_allocator;
+	/* plugin for different jnode types */
+	jnode_plugin jnode;
+	/* compression mode plugin, used by object plugin */
+	compression_mode_plugin compression_mode;
+	/* cluster plugin, used by object plugin */
+	cluster_plugin clust;
+	/* regular plugin, used by directory plugin */
+	regular_plugin regular;
+	/* place-holder for new plugin types that can be registered
+	   dynamically, and used by other dynamically loaded plugins.  */
+	void *generic;
+};
+
+struct reiser4_plugin_ops {
+	/* called when plugin is initialized */
+	int (*init) (reiser4_plugin * plugin);
+	/* called when plugin is unloaded */
+	int (*done) (reiser4_plugin * plugin);
+	/* load given plugin from disk */
+	int (*load) (struct inode * inode,
+		     reiser4_plugin * plugin, char **area, int *len);
+	/* how many space is required to store this plugin's state
+	   in stat-data */
+	int (*save_len) (struct inode * inode, reiser4_plugin * plugin);
+	/* save persistent plugin-data to disk */
+	int (*save) (struct inode * inode, reiser4_plugin * plugin,
+		     char **area);
+	/* alignment requirement for on-disk state of this plugin
+	   in number of bytes */
+	int alignment;
+	/* install itself into given inode. This can return error
+	   (e.g., you cannot change hash of non-empty directory). */
+	int (*change) (struct inode * inode, reiser4_plugin * plugin);
+	/* install itself into given inode. This can return error
+	   (e.g., you cannot change hash of non-empty directory). */
+	int (*inherit) (struct inode * inode, struct inode * parent,
+			reiser4_plugin * plugin);
+};
+
+/* functions implemented in fs/reiser4/plugin/plugin.c */
+
+/* stores plugin reference in reiser4-specific part of inode */
+extern int set_object_plugin(struct inode *inode, reiser4_plugin_id id);
+extern int setup_plugins(struct super_block *super, reiser4_plugin ** area);
+extern int init_plugins(void);
+
+/* builtin plugins */
+
+/* builtin hash-plugins */
+
+typedef enum {
+	RUPASOV_HASH_ID,
+	R5_HASH_ID,
+	TEA_HASH_ID,
+	FNV1_HASH_ID,
+	DEGENERATE_HASH_ID,
+	LAST_HASH_ID
+} reiser4_hash_id;
+
+/* builtin cipher plugins */
+
+typedef enum {
+	NONE_CIPHER_ID,
+	AES_CIPHER_ID,
+	LAST_CIPHER_ID
+} reiser4_cipher_id;
+
+/* builtin digest plugins */
+
+typedef enum {
+	SHA256_32_DIGEST_ID,
+	LAST_DIGEST_ID
+} reiser4_digest_id;
+
+/* builtin compression mode plugins */
+typedef enum {
+	NONE_COMPRESSION_MODE_ID,
+	COL_8_COMPRESSION_MODE_ID,
+	COL_16_COMPRESSION_MODE_ID,
+	COL_32_COMPRESSION_MODE_ID,
+	COZ_COMPRESSION_MODE_ID,
+	FORCE_COMPRESSION_MODE_ID,
+	TEST_COMPRESSION_MODE_ID,
+  	LAST_COMPRESSION_MODE_ID
+} reiser4_compression_mode_id;
+
+/* builtin cluster plugins */
+typedef enum {
+	CLUSTER_64K_ID,
+	CLUSTER_32K_ID,
+	CLUSTER_16K_ID,
+	CLUSTER_8K_ID,
+	CLUSTER_4K_ID,
+	LAST_CLUSTER_ID
+} reiser4_cluster_id;
+
+/* builtin regular plugins */
+typedef enum {
+	UF_REGULAR_ID,
+	CRC_REGULAR_ID,
+	LAST_REGULAR_ID
+} reiser4_regular_id;
+
+/* builtin tail-plugins */
+
+typedef enum {
+	NEVER_TAILS_FORMATTING_ID,
+	ALWAYS_TAILS_FORMATTING_ID,
+	SMALL_FILE_FORMATTING_ID,
+	LAST_TAIL_FORMATTING_ID
+} reiser4_formatting_id;
+
+/* compression/clustering specific data */
+typedef struct compression_data {
+	reiser4_compression_id coa;	/* id of the compression algorithm */
+} compression_data_t;
+
+typedef __u8 cluster_data_t;	/* cluster info */
+
+/* data type used to pack parameters that we pass to vfs object creation
+   function create_object() */
+struct reiser4_object_create_data {
+	/* plugin to control created object */
+	reiser4_file_id id;
+	/* mode of regular file, directory or special file */
+/* what happens if some other sort of perm plugin is in use? */
+	int mode;
+	/* rdev of special file */
+	dev_t rdev;
+	/* symlink target */
+	const char *name;
+	/* add here something for non-standard objects you invent, like
+	   query for interpolation file etc. */
+
+ 	crypto_stat_t * crypto;
+	compression_data_t *compression;
+	cluster_data_t *cluster;
+
+	struct inode *parent;
+	struct dentry *dentry;
+};
+
+/* description of directory entry being created/destroyed/sought for
+
+   It is passed down to the directory plugin and farther to the
+   directory item plugin methods. Creation of new directory is done in
+   several stages: first we search for an entry with the same name, then
+   create new one. reiser4_dir_entry_desc is used to store some information
+   collected at some stage of this process and required later: key of
+   item that we want to insert/delete and pointer to an object that will
+   be bound by the new directory entry. Probably some more fields will
+   be added there.
+
+*/
+struct reiser4_dir_entry_desc {
+	/* key of directory entry */
+	reiser4_key key;
+	/* object bound by this entry. */
+	struct inode *obj;
+};
+
+#define MAX_PLUGIN_TYPE_LABEL_LEN  32
+#define MAX_PLUGIN_PLUG_LABEL_LEN  32
+
+/* used for interface with user-land: table-driven parsing in
+    reiser4(). */
+typedef struct plugin_locator {
+	reiser4_plugin_type type_id;
+	reiser4_plugin_id id;
+	char type_label[MAX_PLUGIN_TYPE_LABEL_LEN];
+	char plug_label[MAX_PLUGIN_PLUG_LABEL_LEN];
+} plugin_locator;
+
+extern int locate_plugin(struct inode *inode, plugin_locator * loc);
+
+
+#define PLUGIN_BY_ID(TYPE,ID,FIELD)					\
+static inline TYPE *TYPE ## _by_id( reiser4_plugin_id id )		\
+{									\
+	reiser4_plugin *plugin = plugin_by_id ( ID, id );		\
+	return plugin ? & plugin -> FIELD : NULL;			\
+}									\
+static inline TYPE *TYPE ## _by_disk_id( reiser4_tree *tree, d16 *id )	\
+{									\
+	reiser4_plugin *plugin = plugin_by_disk_id ( tree, ID, id );	\
+	return plugin ? & plugin -> FIELD : NULL;			\
+}									\
+static inline TYPE *TYPE ## _by_unsafe_id( reiser4_plugin_id id )	\
+{									\
+	reiser4_plugin *plugin = plugin_by_unsafe_id ( ID, id );	\
+	return plugin ? & plugin -> FIELD : NULL;			\
+}									\
+static inline reiser4_plugin* TYPE ## _to_plugin( TYPE* plugin )	\
+{									\
+	return ( reiser4_plugin * ) plugin;				\
+}									\
+static inline reiser4_plugin_id TYPE ## _id( TYPE* plugin )		\
+{									\
+	return TYPE ## _to_plugin (plugin) -> h.id;			\
+}									\
+typedef struct { int foo; } TYPE ## _plugin_dummy
+
+PLUGIN_BY_ID(item_plugin, REISER4_ITEM_PLUGIN_TYPE, item);
+PLUGIN_BY_ID(file_plugin, REISER4_FILE_PLUGIN_TYPE, file);
+PLUGIN_BY_ID(dir_plugin, REISER4_DIR_PLUGIN_TYPE, dir);
+PLUGIN_BY_ID(node_plugin, REISER4_NODE_PLUGIN_TYPE, node);
+PLUGIN_BY_ID(sd_ext_plugin, REISER4_SD_EXT_PLUGIN_TYPE, sd_ext);
+PLUGIN_BY_ID(perm_plugin, REISER4_PERM_PLUGIN_TYPE, perm);
+PLUGIN_BY_ID(hash_plugin, REISER4_HASH_PLUGIN_TYPE, hash);
+PLUGIN_BY_ID(fibration_plugin, REISER4_FIBRATION_PLUGIN_TYPE, fibration);
+PLUGIN_BY_ID(cipher_plugin, REISER4_CIPHER_PLUGIN_TYPE, cipher);
+PLUGIN_BY_ID(digest_plugin, REISER4_DIGEST_PLUGIN_TYPE, digest);
+PLUGIN_BY_ID(compression_plugin, REISER4_COMPRESSION_PLUGIN_TYPE, compression);
+PLUGIN_BY_ID(formatting_plugin, REISER4_FORMATTING_PLUGIN_TYPE, formatting);
+PLUGIN_BY_ID(disk_format_plugin, REISER4_FORMAT_PLUGIN_TYPE, format);
+PLUGIN_BY_ID(jnode_plugin, REISER4_JNODE_PLUGIN_TYPE, jnode);
+PLUGIN_BY_ID(compression_mode_plugin, REISER4_COMPRESSION_MODE_PLUGIN_TYPE,
+	     compression_mode);
+PLUGIN_BY_ID(cluster_plugin, REISER4_CLUSTER_PLUGIN_TYPE, clust);
+PLUGIN_BY_ID(regular_plugin, REISER4_REGULAR_PLUGIN_TYPE, regular);
+
+extern int save_plugin_id(reiser4_plugin * plugin, d16 * area);
+
+extern struct list_head *get_plugin_list(reiser4_plugin_type type_id);
+
+#define for_all_plugins(ptype, plugin)							\
+for (plugin = list_entry(get_plugin_list(ptype)->next, reiser4_plugin, h.linkage);	\
+     get_plugin_list(ptype) != &plugin->h.linkage;					\
+     plugin = list_entry(plugin->h.linkage.next, reiser4_plugin, h.linkage))
+
+
+/* enumeration of fields within plugin_set */
+typedef enum {
+	PSET_FILE,
+	PSET_DIR,		/* PSET_FILE and PSET_DIR should be first elements:
+				 * inode.c:read_inode() depends on this. */
+	PSET_PERM,
+	PSET_FORMATTING,
+	PSET_HASH,
+	PSET_FIBRATION,
+	PSET_SD,
+	PSET_DIR_ITEM,
+	PSET_CIPHER,
+	PSET_DIGEST,
+	PSET_COMPRESSION,
+	PSET_COMPRESSION_MODE,
+	PSET_CLUSTER,
+	PSET_REGULAR_ENTRY,
+	PSET_LAST
+} pset_member;
+
+int grab_plugin(struct inode *self, struct inode *ancestor, pset_member memb);
+int grab_plugin_from(struct inode *self, pset_member memb,
+		     reiser4_plugin * plug);
+int force_plugin(struct inode *self, pset_member memb, reiser4_plugin * plug);
+
+/* defined in fs/reiser4/plugin/object.c */
+extern file_plugin file_plugins[LAST_FILE_PLUGIN_ID];
+/* defined in fs/reiser4/plugin/object.c */
+extern dir_plugin dir_plugins[LAST_DIR_ID];
+/* defined in fs/reiser4/plugin/item/static_stat.c */
+extern sd_ext_plugin sd_ext_plugins[LAST_SD_EXTENSION];
+/* defined in fs/reiser4/plugin/hash.c */
+extern hash_plugin hash_plugins[LAST_HASH_ID];
+/* defined in fs/reiser4/plugin/fibration.c */
+extern fibration_plugin fibration_plugins[LAST_FIBRATION_ID];
+/* defined in fs/reiser4/plugin/crypt.c */
+extern cipher_plugin cipher_plugins[LAST_CIPHER_ID];
+/* defined in fs/reiser4/plugin/digest.c */
+extern digest_plugin digest_plugins[LAST_DIGEST_ID];
+/* defined in fs/reiser4/plugin/compress/compress.c */
+extern compression_plugin compression_plugins[LAST_COMPRESSION_ID];
+/* defined in fs/reiser4/plugin/compress/compression_mode.c */
+extern compression_mode_plugin
+compression_mode_plugins[LAST_COMPRESSION_MODE_ID];
+/* defined in fs/reiser4/plugin/cluster.c */
+extern cluster_plugin cluster_plugins[LAST_CLUSTER_ID];
+/* defined in fs/reiser4/plugin/regular.c */
+extern regular_plugin regular_plugins[LAST_REGULAR_ID];
+/* defined in fs/reiser4/plugin/tail.c */
+extern formatting_plugin formatting_plugins[LAST_TAIL_FORMATTING_ID];
+/* defined in fs/reiser4/plugin/security/security.c */
+extern perm_plugin perm_plugins[LAST_PERM_ID];
+/* defined in fs/reiser4/plugin/item/item.c */
+extern item_plugin item_plugins[LAST_ITEM_ID];
+/* defined in fs/reiser4/plugin/node/node.c */
+extern node_plugin node_plugins[LAST_NODE_ID];
+/* defined in fs/reiser4/plugin/disk_format/disk_format.c */
+extern disk_format_plugin format_plugins[LAST_FORMAT_ID];
+
+/* __FS_REISER4_PLUGIN_TYPES_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/plugin_header.h newtree/fs/reiser4/plugin/plugin_header.h
--- oldtree/fs/reiser4/plugin/plugin_header.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/plugin_header.h	2006-02-21 15:58:35.231790512 +0000
@@ -0,0 +1,136 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* plugin header. Data structures required by all plugin types. */
+
+#if !defined( __PLUGIN_HEADER_H__ )
+#define __PLUGIN_HEADER_H__
+
+/* plugin data-types and constants */
+
+#include "../debug.h"
+#include "../dformat.h"
+
+typedef enum {
+	REISER4_FILE_PLUGIN_TYPE,
+	REISER4_DIR_PLUGIN_TYPE,
+	REISER4_ITEM_PLUGIN_TYPE,
+	REISER4_NODE_PLUGIN_TYPE,
+	REISER4_HASH_PLUGIN_TYPE,
+	REISER4_FIBRATION_PLUGIN_TYPE,
+	REISER4_FORMATTING_PLUGIN_TYPE,
+	REISER4_PERM_PLUGIN_TYPE,
+	REISER4_SD_EXT_PLUGIN_TYPE,
+	REISER4_FORMAT_PLUGIN_TYPE,
+	REISER4_JNODE_PLUGIN_TYPE,
+	REISER4_CIPHER_PLUGIN_TYPE,
+	REISER4_DIGEST_PLUGIN_TYPE,
+	REISER4_COMPRESSION_PLUGIN_TYPE,
+	REISER4_COMPRESSION_MODE_PLUGIN_TYPE,
+	REISER4_CLUSTER_PLUGIN_TYPE,
+	REISER4_REGULAR_PLUGIN_TYPE,
+	REISER4_PLUGIN_TYPES
+} reiser4_plugin_type;
+
+struct reiser4_plugin_ops;
+/* generic plugin operations, supported by each
+    plugin type. */
+typedef struct reiser4_plugin_ops reiser4_plugin_ops;
+
+/* the common part of all plugin instances. */
+typedef struct plugin_header {
+	/* plugin type */
+	reiser4_plugin_type type_id;
+	/* id of this plugin */
+	reiser4_plugin_id id;
+	/* plugin operations */
+	reiser4_plugin_ops *pops;
+/* NIKITA-FIXME-HANS: usage of and access to label and desc is not commented and defined. */
+	/* short label of this plugin */
+	const char *label;
+	/* descriptive string.. */
+	const char *desc;
+	/* list linkage */
+	struct list_head linkage;
+} plugin_header;
+
+/* PRIVATE INTERFACES */
+/* NIKITA-FIXME-HANS: what is this for and why does it duplicate what is in plugin_header? */
+/* plugin type representation. */
+typedef struct reiser4_plugin_type_data {
+	/* internal plugin type identifier. Should coincide with
+	   index of this item in plugins[] array. */
+	reiser4_plugin_type type_id;
+	/* short symbolic label of this plugin type. Should be no longer
+	   than MAX_PLUGIN_TYPE_LABEL_LEN characters including '\0'. */
+	const char *label;
+	/* plugin type description longer than .label */
+	const char *desc;
+
+/* NIKITA-FIXME-HANS: define built-in */
+	/* number of built-in plugin instances of this type */
+	int builtin_num;
+	/* array of built-in plugins */
+	void *builtin;
+	struct list_head plugins_list;
+	size_t size;
+} reiser4_plugin_type_data;
+
+extern reiser4_plugin_type_data plugins[REISER4_PLUGIN_TYPES];
+
+int is_type_id_valid(reiser4_plugin_type type_id);
+int is_plugin_id_valid(reiser4_plugin_type type_id, reiser4_plugin_id id);
+
+static inline reiser4_plugin *plugin_at(reiser4_plugin_type_data * ptype, int i)
+{
+	char *builtin;
+
+	builtin = ptype->builtin;
+	return (reiser4_plugin *) (builtin + i * ptype->size);
+}
+
+/* return plugin by its @type_id and @id */
+static inline reiser4_plugin *plugin_by_id(reiser4_plugin_type type_id
+					   /* plugin type id */ ,
+					   reiser4_plugin_id id /* plugin id */
+					   )
+{
+	assert("nikita-1651", is_type_id_valid(type_id));
+	assert("nikita-1652", is_plugin_id_valid(type_id, id));
+	return plugin_at(&plugins[type_id], id);
+}
+
+extern reiser4_plugin *plugin_by_unsafe_id(reiser4_plugin_type type_id,
+					   reiser4_plugin_id id);
+
+/**
+ * plugin_by_disk_id - get reiser4_plugin
+ * @type_id: plugin type id
+ * @did: plugin id in disk format
+ *
+ * Returns reiser4_plugin by plugin type id an dplugin_id.
+ */
+static inline reiser4_plugin *plugin_by_disk_id(reiser4_tree * tree UNUSED_ARG,
+						reiser4_plugin_type type_id,
+						__le16 *plugin_id)
+{
+	/*
+	 * what we should do properly is to maintain within each file-system a
+	 * dictionary that maps on-disk plugin ids to "universal" ids. This
+	 * dictionary will be resolved on mount time, so that this function
+	 * will perform just one additional array lookup.
+	 */
+	return plugin_by_unsafe_id(type_id, le16_to_cpu(*plugin_id));
+}
+
+/* __PLUGIN_HEADER_H__ */
+#endif
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * End:
+ */
diff -urN oldtree/fs/reiser4/plugin/plugin_set.c newtree/fs/reiser4/plugin/plugin_set.c
--- oldtree/fs/reiser4/plugin/plugin_set.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/plugin_set.c	2006-02-21 15:58:35.231790512 +0000
@@ -0,0 +1,378 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+/* NIKITA-FIXME-HANS: you didn't discuss this with me before coding it did you?  Remove plugin-sets from code by March 15th, 2004 */
+/* plugin-sets */
+
+/*
+ * Each inode comes with a whole set of plugins: file plugin, directory
+ * plugin, hash plugin, tail policy plugin, security plugin, etc.
+ *
+ * Storing them (pointers to them, that is) in inode is a waste of
+ * space. Especially, given that on average file system plugins of vast
+ * majority of files will belong to few sets (e.g., one set for regular files,
+ * another set for standard directory, etc.)
+ *
+ * Plugin set (pset) is an object containing pointers to all plugins required
+ * by inode. Inode only stores a pointer to pset. psets are "interned", that
+ * is, different inodes with the same set of plugins point to the same
+ * pset. This is archived by storing psets in global hash table. Races are
+ * avoided by simple (and efficient so far) solution of never recycling psets,
+ * even when last inode pointing to it is destroyed.
+ *
+ */
+
+#include "../debug.h"
+#include "../super.h"
+#include "plugin_set.h"
+
+#include <linux/slab.h>
+#include <linux/stddef.h>
+
+/* slab for plugin sets */
+static kmem_cache_t *plugin_set_slab;
+
+static spinlock_t plugin_set_lock[8] __cacheline_aligned_in_smp = {
+	[0 ... 7] = SPIN_LOCK_UNLOCKED
+};
+
+/* hash table support */
+
+#define PS_TABLE_SIZE (32)
+
+static inline plugin_set *cast_to(const unsigned long *a)
+{
+	return container_of(a, plugin_set, hashval);
+}
+
+static inline int pseq(const unsigned long *a1, const unsigned long *a2)
+{
+	plugin_set *set1;
+	plugin_set *set2;
+
+	/* make sure fields are not missed in the code below */
+	cassert(sizeof *set1 ==
+		sizeof set1->hashval +
+		sizeof set1->link +
+		sizeof set1->file +
+		sizeof set1->dir +
+		sizeof set1->perm +
+		sizeof set1->formatting +
+		sizeof set1->hash +
+		sizeof set1->fibration +
+		sizeof set1->sd +
+		sizeof set1->dir_item +
+		sizeof set1->cipher +
+		sizeof set1->digest +
+		sizeof set1->compression +
+		sizeof set1->compression_mode +
+		sizeof set1->cluster + sizeof set1->regular_entry);
+
+	set1 = cast_to(a1);
+	set2 = cast_to(a2);
+	return
+	    set1->hashval == set2->hashval &&
+	    set1->file == set2->file &&
+	    set1->dir == set2->dir &&
+	    set1->perm == set2->perm &&
+	    set1->formatting == set2->formatting &&
+	    set1->hash == set2->hash &&
+	    set1->fibration == set2->fibration &&
+	    set1->sd == set2->sd &&
+	    set1->dir_item == set2->dir_item &&
+	    set1->cipher == set2->cipher &&
+	    set1->digest == set2->digest &&
+	    set1->compression == set2->compression &&
+	    set1->compression_mode == set2->compression_mode &&
+	    set1->cluster == set2->cluster &&
+	    set1->regular_entry == set2->regular_entry;
+}
+
+#define HASH_FIELD(hash, set, field)		\
+({						\
+        (hash) += (unsigned long)(set)->field >> 2;	\
+})
+
+static inline unsigned long calculate_hash(const plugin_set * set)
+{
+	unsigned long result;
+
+	result = 0;
+	HASH_FIELD(result, set, file);
+	HASH_FIELD(result, set, dir);
+	HASH_FIELD(result, set, perm);
+	HASH_FIELD(result, set, formatting);
+	HASH_FIELD(result, set, hash);
+	HASH_FIELD(result, set, fibration);
+	HASH_FIELD(result, set, sd);
+	HASH_FIELD(result, set, dir_item);
+	HASH_FIELD(result, set, cipher);
+	HASH_FIELD(result, set, digest);
+	HASH_FIELD(result, set, compression);
+	HASH_FIELD(result, set, compression_mode);
+	HASH_FIELD(result, set, cluster);
+	HASH_FIELD(result, set, regular_entry);
+	return result & (PS_TABLE_SIZE - 1);
+}
+
+static inline unsigned long
+pshash(ps_hash_table * table, const unsigned long *a)
+{
+	return *a;
+}
+
+/* The hash table definition */
+#define KMALLOC(size) kmalloc((size), GFP_KERNEL)
+#define KFREE(ptr, size) kfree(ptr)
+TYPE_SAFE_HASH_DEFINE(ps, plugin_set, unsigned long, hashval, link, pshash,
+		      pseq);
+#undef KFREE
+#undef KMALLOC
+
+static ps_hash_table ps_table;
+static plugin_set empty_set = {
+	.hashval = 0,
+	.file = NULL,
+	.dir = NULL,
+	.perm = NULL,
+	.formatting = NULL,
+	.hash = NULL,
+	.fibration = NULL,
+	.sd = NULL,
+	.dir_item = NULL,
+	.cipher = NULL,
+	.digest = NULL,
+	.compression = NULL,
+	.compression_mode = NULL,
+	.cluster = NULL,
+	.regular_entry = NULL,
+	.link = {NULL}
+};
+
+plugin_set *plugin_set_get_empty(void)
+{
+	return &empty_set;
+}
+
+void plugin_set_put(plugin_set * set)
+{
+}
+
+static inline unsigned long *pset_field(plugin_set * set, int offset)
+{
+	return (unsigned long *)(((char *)set) + offset);
+}
+
+static int plugin_set_field(plugin_set ** set, const unsigned long val,
+			    const int offset)
+{
+	unsigned long *spot;
+	spinlock_t *lock;
+	plugin_set replica;
+	plugin_set *twin;
+	plugin_set *psal;
+	plugin_set *orig;
+
+	assert("nikita-2902", set != NULL);
+	assert("nikita-2904", *set != NULL);
+
+	spot = pset_field(*set, offset);
+	if (unlikely(*spot == val))
+		return 0;
+
+	replica = *(orig = *set);
+	*pset_field(&replica, offset) = val;
+	replica.hashval = calculate_hash(&replica);
+	rcu_read_lock();
+	twin = ps_hash_find(&ps_table, &replica.hashval);
+	if (unlikely(twin == NULL)) {
+		rcu_read_unlock();
+		psal = kmem_cache_alloc(plugin_set_slab, GFP_KERNEL);
+		if (psal == NULL)
+			return RETERR(-ENOMEM);
+		*psal = replica;
+		lock = &plugin_set_lock[replica.hashval & 7];
+		spin_lock(lock);
+		twin = ps_hash_find(&ps_table, &replica.hashval);
+		if (likely(twin == NULL)) {
+			*set = psal;
+			ps_hash_insert_rcu(&ps_table, psal);
+		} else {
+			*set = twin;
+			kmem_cache_free(plugin_set_slab, psal);
+		}
+		spin_unlock(lock);
+	} else {
+		rcu_read_unlock();
+		*set = twin;
+	}
+	return 0;
+}
+
+static struct {
+	int offset;
+	reiser4_plugin_type type;
+} pset_descr[PSET_LAST] = {
+	[PSET_FILE] = {
+		.offset = offsetof(plugin_set, file),
+		.type = REISER4_FILE_PLUGIN_TYPE
+	},
+	[PSET_DIR] = {
+		.offset = offsetof(plugin_set, dir),
+		.type = REISER4_DIR_PLUGIN_TYPE
+	},
+	[PSET_PERM] = {
+		.offset = offsetof(plugin_set, perm),
+		.type = REISER4_PERM_PLUGIN_TYPE
+	},
+	[PSET_FORMATTING] = {
+		.offset = offsetof(plugin_set, formatting),
+		.type = REISER4_FORMATTING_PLUGIN_TYPE
+	},
+	[PSET_HASH] = {
+		.offset = offsetof(plugin_set, hash),
+		.type = REISER4_HASH_PLUGIN_TYPE
+	},
+	[PSET_FIBRATION] = {
+		.offset = offsetof(plugin_set, fibration),
+		.type = REISER4_FIBRATION_PLUGIN_TYPE
+	},
+	[PSET_SD] = {
+		.offset = offsetof(plugin_set, sd),
+		.type = REISER4_ITEM_PLUGIN_TYPE
+	},
+	[PSET_DIR_ITEM] = {
+		.offset = offsetof(plugin_set, dir_item),
+		.type = REISER4_ITEM_PLUGIN_TYPE
+	},
+	[PSET_CIPHER] = {
+		.offset = offsetof(plugin_set, cipher),
+		.type = REISER4_CIPHER_PLUGIN_TYPE
+	},
+	[PSET_DIGEST] = {
+		.offset = offsetof(plugin_set, digest),
+		.type = REISER4_DIGEST_PLUGIN_TYPE
+	},
+	[PSET_COMPRESSION] = {
+		.offset = offsetof(plugin_set, compression),
+		.type = REISER4_COMPRESSION_PLUGIN_TYPE
+	},
+	[PSET_COMPRESSION_MODE] = {
+		.offset = offsetof(plugin_set, compression_mode),
+		.type = REISER4_COMPRESSION_MODE_PLUGIN_TYPE
+	},
+	[PSET_CLUSTER] = {
+		.offset = offsetof(plugin_set, cluster),
+		.type = REISER4_CLUSTER_PLUGIN_TYPE
+	},
+	[PSET_REGULAR_ENTRY] = {
+		.offset = offsetof(plugin_set, regular_entry),
+		.type = REISER4_REGULAR_PLUGIN_TYPE
+	}
+};
+
+#if REISER4_DEBUG
+static reiser4_plugin_type pset_member_to_type(pset_member memb)
+{
+	assert("nikita-3501", 0 <= memb && memb < PSET_LAST);
+	return pset_descr[memb].type;
+}
+#endif
+
+reiser4_plugin_type pset_member_to_type_unsafe(pset_member memb)
+{
+	if (0 <= memb && memb < PSET_LAST)
+		return pset_descr[memb].type;
+	else
+		return REISER4_PLUGIN_TYPES;
+}
+
+int pset_set(plugin_set ** set, pset_member memb, reiser4_plugin * plugin)
+{
+	assert("nikita-3492", set != NULL);
+	assert("nikita-3493", *set != NULL);
+	assert("nikita-3494", plugin != NULL);
+	assert("nikita-3495", 0 <= memb && memb < PSET_LAST);
+	assert("nikita-3496", plugin->h.type_id == pset_member_to_type(memb));
+
+	return plugin_set_field(set,
+				(unsigned long)plugin, pset_descr[memb].offset);
+}
+
+reiser4_plugin *pset_get(plugin_set * set, pset_member memb)
+{
+	assert("nikita-3497", set != NULL);
+	assert("nikita-3498", 0 <= memb && memb < PSET_LAST);
+
+	return *(reiser4_plugin **) (((char *)set) + pset_descr[memb].offset);
+}
+
+#define DEFINE_PLUGIN_SET(type, field)					\
+int plugin_set_ ## field(plugin_set **set, type *val)	\
+{									\
+	cassert(sizeof val == sizeof(unsigned long));			\
+	return plugin_set_field(set, (unsigned long)val,		\
+				offsetof(plugin_set, field));		\
+}
+
+DEFINE_PLUGIN_SET(file_plugin, file)
+    DEFINE_PLUGIN_SET(dir_plugin, dir)
+    DEFINE_PLUGIN_SET(formatting_plugin, formatting)
+    DEFINE_PLUGIN_SET(hash_plugin, hash)
+    DEFINE_PLUGIN_SET(fibration_plugin, fibration)
+    DEFINE_PLUGIN_SET(item_plugin, sd)
+    DEFINE_PLUGIN_SET(cipher_plugin, cipher)
+    DEFINE_PLUGIN_SET(digest_plugin, digest)
+    DEFINE_PLUGIN_SET(compression_plugin, compression)
+    DEFINE_PLUGIN_SET(compression_mode_plugin, compression_mode)
+    DEFINE_PLUGIN_SET(cluster_plugin, cluster)
+    DEFINE_PLUGIN_SET(regular_plugin, regular_entry)
+
+
+/**
+ * init_plugin_set - create pset cache and hash table
+ *
+ * Initializes slab cache of plugin_set-s and their hash table. It is part of
+ * reiser4 module initialization.
+ */
+int init_plugin_set(void)
+{
+	int result;
+
+	result = ps_hash_init(&ps_table, PS_TABLE_SIZE);
+	if (result == 0) {
+		plugin_set_slab = kmem_cache_create("plugin_set",
+						    sizeof(plugin_set), 0,
+						    SLAB_HWCACHE_ALIGN,
+						    NULL, NULL);
+		if (plugin_set_slab == NULL)
+			result = RETERR(-ENOMEM);
+	}
+	return result;
+}
+
+/**
+ * done_plugin_set - delete plugin_set cache and plugin_set hash table
+ *
+ * This is called on reiser4 module unloading or system shutdown.
+ */
+void done_plugin_set(void)
+{
+	plugin_set *cur, *next;
+
+	for_all_in_htable(&ps_table, ps, cur, next) {
+		ps_hash_remove(&ps_table, cur);
+		kmem_cache_free(plugin_set_slab, cur);
+	}
+	destroy_reiser4_cache(&plugin_set_slab);
+	ps_hash_done(&ps_table);
+}
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 120
+ * End:
+ */
diff -urN oldtree/fs/reiser4/plugin/plugin_set.h newtree/fs/reiser4/plugin/plugin_set.h
--- oldtree/fs/reiser4/plugin/plugin_set.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/plugin_set.h	2006-02-21 15:58:35.232790360 +0000
@@ -0,0 +1,88 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* plugin-sets. see fs/reiser4/plugin/plugin_set.c for details */
+
+#if !defined( __PLUGIN_SET_H__ )
+#define __PLUGIN_SET_H__
+
+#include "../type_safe_hash.h"
+#include "plugin.h"
+
+#include <linux/rcupdate.h>
+
+struct plugin_set;
+typedef struct plugin_set plugin_set;
+
+TYPE_SAFE_HASH_DECLARE(ps, plugin_set);
+
+struct plugin_set {
+	unsigned long hashval;
+	/* plugin of file */
+	file_plugin *file;
+	/* plugin of dir */
+	dir_plugin *dir;
+	/* perm plugin for this file */
+	perm_plugin *perm;
+	/* tail policy plugin. Only meaningful for regular files */
+	formatting_plugin *formatting;
+	/* hash plugin. Only meaningful for directories. */
+	hash_plugin *hash;
+	/* fibration plugin. Only meaningful for directories. */
+	fibration_plugin *fibration;
+	/* plugin of stat-data */
+	item_plugin *sd;
+	/* plugin of items a directory is built of */
+	item_plugin *dir_item;
+	/* cipher plugin */
+	cipher_plugin *cipher;
+	/* digest plugin */
+	digest_plugin *digest;
+	/* compression plugin */
+	compression_plugin *compression;
+	/* compression mode plugin */
+	compression_mode_plugin *compression_mode;
+	/* cluster plugin */
+	cluster_plugin *cluster;
+	/* plugin of regular child should be created */
+	regular_plugin *regular_entry;
+	ps_hash_link link;
+};
+
+extern plugin_set *plugin_set_get_empty(void);
+extern void plugin_set_put(plugin_set * set);
+
+extern int plugin_set_file(plugin_set ** set, file_plugin * plug);
+extern int plugin_set_dir(plugin_set ** set, dir_plugin * plug);
+extern int plugin_set_formatting(plugin_set ** set, formatting_plugin * plug);
+extern int plugin_set_hash(plugin_set ** set, hash_plugin * plug);
+extern int plugin_set_fibration(plugin_set ** set, fibration_plugin * plug);
+extern int plugin_set_sd(plugin_set ** set, item_plugin * plug);
+extern int plugin_set_cipher(plugin_set ** set, cipher_plugin * plug);
+extern int plugin_set_digest(plugin_set ** set, digest_plugin * plug);
+extern int plugin_set_compression(plugin_set ** set, compression_plugin * plug);
+extern int plugin_set_compression_mode(plugin_set ** set,
+				       compression_mode_plugin * plug);
+extern int plugin_set_cluster(plugin_set ** set, cluster_plugin * plug);
+extern int plugin_set_regular_entry(plugin_set ** set, regular_plugin * plug);
+
+extern int init_plugin_set(void);
+extern void done_plugin_set(void);
+
+extern int pset_set(plugin_set ** set, pset_member memb,
+		    reiser4_plugin * plugin);
+extern reiser4_plugin *pset_get(plugin_set * set, pset_member memb);
+
+extern reiser4_plugin_type pset_member_to_type_unsafe(pset_member memb);
+
+/* __PLUGIN_SET_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/regular.c newtree/fs/reiser4/plugin/regular.c
--- oldtree/fs/reiser4/plugin/regular.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/regular.c	2006-02-21 15:58:34.657877760 +0000
@@ -0,0 +1,44 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Contains Reiser4 regular plugins which:
+   . specify a set of reiser4 regular object plugins,
+   . used by directory plugin to create entries powered by specified
+     regular plugins */
+
+#include "plugin.h"
+
+regular_plugin regular_plugins[LAST_REGULAR_ID] = {
+	[UF_REGULAR_ID] = {
+		.h = {
+			.type_id = REISER4_REGULAR_PLUGIN_TYPE,
+			.id = UF_REGULAR_ID,
+			.pops = NULL,
+			.label = "unixfile",
+			.desc = "Unix file regular plugin",
+			.linkage = {NULL, NULL}
+		},
+		.id = UNIX_FILE_PLUGIN_ID
+	},
+	[CRC_REGULAR_ID] = {
+		.h = {
+			.type_id = REISER4_REGULAR_PLUGIN_TYPE,
+			.id = CRC_REGULAR_ID,
+			.pops = NULL,
+			.label = "cryptcompress",
+			.desc = "Cryptcompress regular plugin",
+			.linkage = {NULL, NULL}
+		},
+		.id = CRC_FILE_PLUGIN_ID
+	}
+};
+
+/*
+  Local variables:
+  c-indentation-style: "K&R"
+  mode-name: "LC"
+  c-basic-offset: 8
+  tab-width: 8
+  fill-column: 120
+  scroll-step: 1
+  End:
+*/
diff -urN oldtree/fs/reiser4/plugin/security/Makefile newtree/fs/reiser4/plugin/security/Makefile
--- oldtree/fs/reiser4/plugin/security/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/security/Makefile	2006-02-21 15:58:35.082813160 +0000
@@ -0,0 +1,4 @@
+obj-$(CONFIG_REISER4_FS) += security_plugins.o
+
+security_plugins-objs :=	\
+	perm.o
diff -urN oldtree/fs/reiser4/plugin/security/perm.c newtree/fs/reiser4/plugin/security/perm.c
--- oldtree/fs/reiser4/plugin/security/perm.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/security/perm.c	2006-02-21 15:58:35.099810576 +0000
@@ -0,0 +1,44 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/*
+ * this file contains implementation of permission plugins. Currently, only
+ * RWX_PERM_ID is implemented
+ */
+
+#include "../plugin.h"
+#include "../plugin_header.h"
+#include "../../debug.h"
+
+perm_plugin perm_plugins[LAST_PERM_ID] = {
+	[NULL_PERM_ID] = {
+		.h = {
+			.type_id = REISER4_PERM_PLUGIN_TYPE,
+			.id = NULL_PERM_ID,
+			.pops = NULL,
+			.label = "null",
+			.desc = "stub permission plugin",
+			.linkage = {NULL, NULL}
+		},
+		.read_ok = NULL,
+		.write_ok = NULL,
+		.lookup_ok = NULL,
+		.create_ok = NULL,
+		.link_ok = NULL,
+		.unlink_ok = NULL,
+		.delete_ok = NULL,
+		.mask_ok = NULL,
+		.setattr_ok = NULL,
+		.getattr_ok = NULL,
+		.rename_ok = NULL,
+	}
+};
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * End:
+ */
diff -urN oldtree/fs/reiser4/plugin/security/perm.h newtree/fs/reiser4/plugin/security/perm.h
--- oldtree/fs/reiser4/plugin/security/perm.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/security/perm.h	2006-02-21 15:58:35.099810576 +0000
@@ -0,0 +1,82 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Perm (short for "permissions") plugins common stuff. */
+
+#if !defined( __REISER4_PERM_H__ )
+#define __REISER4_PERM_H__
+
+#include "../../forward.h"
+#include "../plugin_header.h"
+
+#include <linux/types.h>
+#include <linux/fs.h>		/* for struct file  */
+#include <linux/dcache.h>	/* for struct dentry */
+
+/* interface for perm plugin.
+
+   Perm plugin method can be implemented through:
+
+    1. consulting ->i_mode bits in stat data
+
+    2. obtaining acl from the tree and inspecting it
+
+    3. asking some kernel module or user-level program to authorize access.
+
+   This allows for integration with things like capabilities, SELinux-style
+   secutiry contexts, etc.
+
+*/
+/* NIKITA-FIXME-HANS: define what this is targeted for.  It does not seem to be intended for use with sys_reiser4.  Explain. */
+typedef struct perm_plugin {
+	/* generic plugin fields */
+	plugin_header h;
+
+	/* check permissions for read/write */
+	int (*read_ok) (struct file *file, const char __user *buf,
+			size_t size, loff_t *off);
+	int (*write_ok) (struct file *file, const char __user *buf,
+			 size_t size, loff_t *off);
+
+	/* check permissions for lookup */
+	int (*lookup_ok) (struct inode * parent, struct dentry * dentry);
+
+	/* check permissions for create */
+	int (*create_ok) (struct inode * parent, struct dentry * dentry,
+			  reiser4_object_create_data * data);
+
+	/* check permissions for linking @where to @existing */
+	int (*link_ok) (struct dentry * existing, struct inode * parent,
+			struct dentry * where);
+
+	/* check permissions for unlinking @victim from @parent */
+	int (*unlink_ok) (struct inode * parent, struct dentry * victim);
+
+	/* check permissions for deletion of @object whose last reference is
+	   by @parent */
+	int (*delete_ok) (struct inode * parent, struct dentry * victim);
+	int (*mask_ok) (struct inode * inode, int mask);
+	/* check whether attribute change is acceptable */
+	int (*setattr_ok) (struct dentry * dentry, struct iattr * attr);
+
+	/* check whether stat(2) is allowed */
+	int (*getattr_ok) (struct vfsmount * mnt UNUSED_ARG,
+			   struct dentry * dentry, struct kstat * stat);
+	/* check whether rename(2) is allowed */
+	int (*rename_ok) (struct inode * old_dir, struct dentry * old,
+			  struct inode * new_dir, struct dentry * new);
+} perm_plugin;
+
+typedef enum { NULL_PERM_ID, LAST_PERM_ID } reiser4_perm_id;
+
+/* __REISER4_PERM_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/space/Makefile newtree/fs/reiser4/plugin/space/Makefile
--- oldtree/fs/reiser4/plugin/space/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/space/Makefile	2006-02-21 15:58:35.082813160 +0000
@@ -0,0 +1,4 @@
+obj-$(CONFIG_REISER4_FS) += space_plugins.o
+
+space_plugins-objs := \
+	bitmap.o
diff -urN oldtree/fs/reiser4/plugin/space/bitmap.c newtree/fs/reiser4/plugin/space/bitmap.c
--- oldtree/fs/reiser4/plugin/space/bitmap.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/space/bitmap.c	2006-02-21 15:58:35.014823496 +0000
@@ -0,0 +1,1702 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#include "../../debug.h"
+#include "../../dformat.h"
+#include "../../txnmgr.h"
+#include "../../jnode.h"
+#include "../../block_alloc.h"
+#include "../../tree.h"
+#include "../../super.h"
+#include "../plugin.h"
+#include "space_allocator.h"
+#include "bitmap.h"
+
+#include <linux/types.h>
+#include <linux/fs.h>		/* for struct super_block  */
+#include <asm/semaphore.h>
+#include <linux/vmalloc.h>
+#include <asm/div64.h>
+
+/* Proposed (but discarded) optimization: dynamic loading/unloading of bitmap
+ * blocks
+
+   A useful optimization of reiser4 bitmap handling would be dynamic bitmap
+   blocks loading/unloading which is different from v3.x where all bitmap
+   blocks are loaded at mount time.
+
+   To implement bitmap blocks unloading we need to count bitmap block usage
+   and detect currently unused blocks allowing them to be unloaded. It is not
+   a simple task since we allow several threads to modify one bitmap block
+   simultaneously.
+
+   Briefly speaking, the following schema is proposed: we count in special
+   variable associated with each bitmap block. That is for counting of block
+   alloc/dealloc operations on that bitmap block. With a deferred block
+   deallocation feature of reiser4 all those operation will be represented in
+   atom dirty/deleted lists as jnodes for freshly allocated or deleted
+   nodes.
+
+   So, we increment usage counter for each new node allocated or deleted, and
+   decrement it at atom commit one time for each node from the dirty/deleted
+   atom's list.  Of course, freshly allocated node deletion and node reusing
+   from atom deleted (if we do so) list should decrement bitmap usage counter
+   also.
+
+   This schema seems to be working but that reference counting is
+   not easy to debug. I think we should agree with Hans and do not implement
+   it in v4.0. Current code implements "on-demand" bitmap blocks loading only.
+
+   For simplicity all bitmap nodes (both commit and working bitmap blocks) are
+   loaded into memory on fs mount time or each bitmap nodes are loaded at the
+   first access to it, the "dont_load_bitmap" mount option controls whether
+   bimtap nodes should be loaded at mount time. Dynamic unloading of bitmap
+   nodes currently is not supported. */
+
+#define CHECKSUM_SIZE    4
+
+#define BYTES_PER_LONG   (sizeof(long))
+
+#if BITS_PER_LONG == 64
+#  define LONG_INT_SHIFT (6)
+#else
+#  define LONG_INT_SHIFT (5)
+#endif
+
+#define LONG_INT_MASK (BITS_PER_LONG - 1UL)
+
+typedef unsigned long ulong_t;
+
+#define bmap_size(blocksize)	    ((blocksize) - CHECKSUM_SIZE)
+#define bmap_bit_count(blocksize)   (bmap_size(blocksize) << 3)
+
+/* Block allocation/deallocation are done through special bitmap objects which
+   are allocated in an array at fs mount. */
+struct bitmap_node {
+	struct semaphore sema;	/* long term lock object */
+
+	jnode *wjnode;		/* j-nodes for WORKING ... */
+	jnode *cjnode;		/* ... and COMMIT bitmap blocks */
+
+	bmap_off_t first_zero_bit;	/* for skip_busy option implementation */
+
+	atomic_t loaded;	/* a flag which shows that bnode is loaded
+				 * already */
+};
+
+static inline char *bnode_working_data(struct bitmap_node *bnode)
+{
+	char *data;
+
+	data = jdata(bnode->wjnode);
+	assert("zam-429", data != NULL);
+
+	return data + CHECKSUM_SIZE;
+}
+
+static inline char *bnode_commit_data(const struct bitmap_node *bnode)
+{
+	char *data;
+
+	data = jdata(bnode->cjnode);
+	assert("zam-430", data != NULL);
+
+	return data + CHECKSUM_SIZE;
+}
+
+static inline __u32 bnode_commit_crc(const struct bitmap_node *bnode)
+{
+	char *data;
+
+	data = jdata(bnode->cjnode);
+	assert("vpf-261", data != NULL);
+
+	return le32_to_cpu(get_unaligned((d32 *)data));
+}
+
+static inline void bnode_set_commit_crc(struct bitmap_node *bnode, __u32 crc)
+{
+	char *data;
+
+	data = jdata(bnode->cjnode);
+	assert("vpf-261", data != NULL);
+
+	put_unaligned(cpu_to_le32(crc), (d32 *)data);
+}
+
+/* ZAM-FIXME-HANS: is the idea that this might be a union someday? having
+ * written the code, does this added abstraction still have */
+/* ANSWER(Zam): No, the abstractions is in the level above (exact place is the
+ * reiser4_space_allocator structure) */
+/* ZAM-FIXME-HANS: I don't understand your english in comment above. */
+/* FIXME-HANS(Zam): I don't understand the questions like "might be a union
+ * someday?". What they about?  If there is a reason to have a union, it should
+ * be a union, if not, it should not be a union.  "..might be someday" means no
+ * reason. */
+struct bitmap_allocator_data {
+	/* an array for bitmap blocks direct access */
+	struct bitmap_node *bitmap;
+};
+
+#define get_barray(super) \
+(((struct bitmap_allocator_data *)(get_super_private(super)->space_allocator.u.generic)) -> bitmap)
+
+#define get_bnode(super, i) (get_barray(super) + i)
+
+/* allocate and initialize jnode with JNODE_BITMAP type */
+static jnode *bnew(void)
+{
+	jnode *jal = jalloc();
+
+	if (jal)
+		jnode_init(jal, current_tree, JNODE_BITMAP);
+
+	return jal;
+}
+
+/* this file contains:
+   - bitmap based implementation of space allocation plugin
+   - all the helper functions like set bit, find_first_zero_bit, etc */
+
+/* Audited by: green(2002.06.12) */
+static int find_next_zero_bit_in_word(ulong_t word, int start_bit)
+{
+	ulong_t mask = 1UL << start_bit;
+	int i = start_bit;
+
+	while ((word & mask) != 0) {
+		mask <<= 1;
+		if (++i >= BITS_PER_LONG)
+			break;
+	}
+
+	return i;
+}
+
+#include <asm/bitops.h>
+
+#if BITS_PER_LONG == 64
+
+#define OFF(addr)  (((ulong_t)(addr) & (BYTES_PER_LONG - 1)) << 3)
+#define BASE(addr) ((ulong_t*) ((ulong_t)(addr) & ~(BYTES_PER_LONG - 1)))
+
+static inline void reiser4_set_bit(int nr, void *addr)
+{
+	ext2_set_bit(nr + OFF(addr), BASE(addr));
+}
+
+static inline void reiser4_clear_bit(int nr, void *addr)
+{
+	ext2_clear_bit(nr + OFF(addr), BASE(addr));
+}
+
+static inline int reiser4_test_bit(int nr, void *addr)
+{
+	return ext2_test_bit(nr + OFF(addr), BASE(addr));
+}
+static inline int reiser4_find_next_zero_bit(void *addr, int maxoffset,
+					     int offset)
+{
+	int off = OFF(addr);
+
+	return ext2_find_next_zero_bit(BASE(addr), maxoffset + off,
+				       offset + off) - off;
+}
+
+#else
+
+#define reiser4_set_bit(nr, addr)    ext2_set_bit(nr, addr)
+#define reiser4_clear_bit(nr, addr)  ext2_clear_bit(nr, addr)
+#define reiser4_test_bit(nr, addr)  ext2_test_bit(nr, addr)
+
+#define reiser4_find_next_zero_bit(addr, maxoffset, offset) \
+ext2_find_next_zero_bit(addr, maxoffset, offset)
+#endif
+
+/* Search for a set bit in the bit array [@start_offset, @max_offset[, offsets
+ * are counted from @addr, return the offset of the first bit if it is found,
+ * @maxoffset otherwise. */
+static bmap_off_t __reiser4_find_next_set_bit(void *addr, bmap_off_t max_offset,
+					      bmap_off_t start_offset)
+{
+	ulong_t *base = addr;
+	/* start_offset is in bits, convert it to byte offset within bitmap. */
+	int word_nr = start_offset >> LONG_INT_SHIFT;
+	/* bit number within the byte. */
+	int bit_nr = start_offset & LONG_INT_MASK;
+	int max_word_nr = (max_offset - 1) >> LONG_INT_SHIFT;
+
+	assert("zam-387", max_offset != 0);
+
+	/* Unaligned @start_offset case.  */
+	if (bit_nr != 0) {
+		bmap_nr_t nr;
+
+		nr = find_next_zero_bit_in_word(~(base[word_nr]), bit_nr);
+
+		if (nr < BITS_PER_LONG)
+			return (word_nr << LONG_INT_SHIFT) + nr;
+
+		++word_nr;
+	}
+
+	/* Fast scan trough aligned words. */
+	while (word_nr <= max_word_nr) {
+		if (base[word_nr] != 0) {
+			return (word_nr << LONG_INT_SHIFT)
+			    + find_next_zero_bit_in_word(~(base[word_nr]), 0);
+		}
+
+		++word_nr;
+	}
+
+	return max_offset;
+}
+
+#if BITS_PER_LONG == 64
+
+static bmap_off_t reiser4_find_next_set_bit(void *addr, bmap_off_t max_offset,
+					    bmap_off_t start_offset)
+{
+	bmap_off_t off = OFF(addr);
+
+	return __reiser4_find_next_set_bit(BASE(addr), max_offset + off,
+					   start_offset + off) - off;
+}
+
+#else
+#define reiser4_find_next_set_bit(addr, max_offset, start_offset) \
+  __reiser4_find_next_set_bit(addr, max_offset, start_offset)
+#endif
+
+/* search for the first set bit in single word. */
+static int find_last_set_bit_in_word(ulong_t word, int start_bit)
+{
+	ulong_t bit_mask;
+	int nr = start_bit;
+
+	assert("zam-965", start_bit < BITS_PER_LONG);
+	assert("zam-966", start_bit >= 0);
+
+	bit_mask = (1UL << nr);
+
+	while (bit_mask != 0) {
+		if (bit_mask & word)
+			return nr;
+		bit_mask >>= 1;
+		nr--;
+	}
+	return BITS_PER_LONG;
+}
+
+/* Search bitmap for a set bit in backward direction from the end to the
+ * beginning of given region
+ *
+ * @result: result offset of the last set bit
+ * @addr:   base memory address,
+ * @low_off:  low end of the search region, edge bit included into the region,
+ * @high_off: high end of the search region, edge bit included into the region,
+ *
+ * @return: 0 - set bit was found, -1 otherwise.
+ */
+static int
+reiser4_find_last_set_bit(bmap_off_t * result, void *addr, bmap_off_t low_off,
+			  bmap_off_t high_off)
+{
+	ulong_t *base = addr;
+	int last_word;
+	int first_word;
+	int last_bit;
+	int nr;
+
+	assert("zam-961", high_off >= 0);
+	assert("zam-962", high_off >= low_off);
+
+	last_word = high_off >> LONG_INT_SHIFT;
+	last_bit = high_off & LONG_INT_MASK;
+	first_word = low_off >> LONG_INT_SHIFT;
+
+	if (last_bit < BITS_PER_LONG) {
+		nr = find_last_set_bit_in_word(base[last_word], last_bit);
+		if (nr < BITS_PER_LONG) {
+			*result = (last_word << LONG_INT_SHIFT) + nr;
+			return 0;
+		}
+		--last_word;
+	}
+	while (last_word >= first_word) {
+		if (base[last_word] != 0x0) {
+			last_bit =
+			    find_last_set_bit_in_word(base[last_word],
+						      BITS_PER_LONG - 1);
+			assert("zam-972", last_bit < BITS_PER_LONG);
+			*result = (last_word << LONG_INT_SHIFT) + last_bit;
+			return 0;
+		}
+		--last_word;
+	}
+
+	return -1;		/* set bit not found */
+}
+
+/* Search bitmap for a clear bit in backward direction from the end to the
+ * beginning of given region */
+static int
+reiser4_find_last_zero_bit(bmap_off_t * result, void *addr, bmap_off_t low_off,
+			   bmap_off_t high_off)
+{
+	ulong_t *base = addr;
+	int last_word;
+	int first_word;
+	int last_bit;
+	int nr;
+
+	last_word = high_off >> LONG_INT_SHIFT;
+	last_bit = high_off & LONG_INT_MASK;
+	first_word = low_off >> LONG_INT_SHIFT;
+
+	if (last_bit < BITS_PER_LONG) {
+		nr = find_last_set_bit_in_word(~base[last_word], last_bit);
+		if (nr < BITS_PER_LONG) {
+			*result = (last_word << LONG_INT_SHIFT) + nr;
+			return 0;
+		}
+		--last_word;
+	}
+	while (last_word >= first_word) {
+		if (base[last_word] != (ulong_t) (-1)) {
+			*result = (last_word << LONG_INT_SHIFT) +
+			    find_last_set_bit_in_word(~base[last_word],
+						      BITS_PER_LONG - 1);
+			return 0;
+		}
+		--last_word;
+	}
+
+	return -1;		/* zero bit not found */
+}
+
+/* Audited by: green(2002.06.12) */
+static void reiser4_clear_bits(char *addr, bmap_off_t start, bmap_off_t end)
+{
+	int first_byte;
+	int last_byte;
+
+	unsigned char first_byte_mask = 0xFF;
+	unsigned char last_byte_mask = 0xFF;
+
+	assert("zam-410", start < end);
+
+	first_byte = start >> 3;
+	last_byte = (end - 1) >> 3;
+
+	if (last_byte > first_byte + 1)
+		memset(addr + first_byte + 1, 0,
+		       (size_t) (last_byte - first_byte - 1));
+
+	first_byte_mask >>= 8 - (start & 0x7);
+	last_byte_mask <<= ((end - 1) & 0x7) + 1;
+
+	if (first_byte == last_byte) {
+		addr[first_byte] &= (first_byte_mask | last_byte_mask);
+	} else {
+		addr[first_byte] &= first_byte_mask;
+		addr[last_byte] &= last_byte_mask;
+	}
+}
+
+/* Audited by: green(2002.06.12) */
+/* ZAM-FIXME-HANS: comment this */
+static void reiser4_set_bits(char *addr, bmap_off_t start, bmap_off_t end)
+{
+	int first_byte;
+	int last_byte;
+
+	unsigned char first_byte_mask = 0xFF;
+	unsigned char last_byte_mask = 0xFF;
+
+	assert("zam-386", start < end);
+
+	first_byte = start >> 3;
+	last_byte = (end - 1) >> 3;
+
+	if (last_byte > first_byte + 1)
+		memset(addr + first_byte + 1, 0xFF,
+		       (size_t) (last_byte - first_byte - 1));
+
+	first_byte_mask <<= start & 0x7;
+	last_byte_mask >>= 7 - ((end - 1) & 0x7);
+
+	if (first_byte == last_byte) {
+		addr[first_byte] |= (first_byte_mask & last_byte_mask);
+	} else {
+		addr[first_byte] |= first_byte_mask;
+		addr[last_byte] |= last_byte_mask;
+	}
+}
+
+#define ADLER_BASE    65521
+#define ADLER_NMAX    5552
+
+/* Calculates the adler32 checksum for the data pointed by `data` of the
+    length `len`. This function was originally taken from zlib, version 1.1.3,
+    July 9th, 1998.
+
+    Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
+
+    This software is provided 'as-is', without any express or implied
+    warranty.  In no event will the authors be held liable for any damages
+    arising from the use of this software.
+
+    Permission is granted to anyone to use this software for any purpose,
+    including commercial applications, and to alter it and redistribute it
+    freely, subject to the following restrictions:
+
+    1. The origin of this software must not be misrepresented; you must not
+	claim that you wrote the original software. If you use this software
+	in a product, an acknowledgment in the product documentation would be
+	appreciated but is not required.
+    2. Altered source versions must be plainly marked as such, and must not be
+	misrepresented as being the original software.
+    3. This notice may not be removed or altered from any source distribution.
+
+    Jean-loup Gailly        Mark Adler
+    jloup@gzip.org          madler@alumni.caltech.edu
+
+    The above comment applies only to the reiser4_adler32 function.
+*/
+
+__u32 reiser4_adler32(char *data, __u32 len)
+{
+	unsigned char *t = data;
+	__u32 s1 = 1;
+	__u32 s2 = 0;
+	int k;
+
+	while (len > 0) {
+		k = len < ADLER_NMAX ? len : ADLER_NMAX;
+		len -= k;
+
+		while (k--) {
+			s1 += *t++;
+			s2 += s1;
+		}
+
+		s1 %= ADLER_BASE;
+		s2 %= ADLER_BASE;
+	}
+	return (s2 << 16) | s1;
+}
+
+#define sb_by_bnode(bnode) \
+	((struct super_block *)jnode_get_tree(bnode->wjnode)->super)
+
+static __u32 bnode_calc_crc(const struct bitmap_node *bnode, unsigned long size)
+{
+	return reiser4_adler32(bnode_commit_data(bnode), bmap_size(size));
+}
+
+static int
+bnode_check_adler32(const struct bitmap_node *bnode, unsigned long size)
+{
+	if (bnode_calc_crc(bnode, size) != bnode_commit_crc(bnode)) {
+		bmap_nr_t bmap;
+
+		bmap = bnode - get_bnode(sb_by_bnode(bnode), 0);
+
+		warning("vpf-263",
+			"Checksum for the bitmap block %llu is incorrect",
+			bmap);
+
+		return RETERR(-EIO);
+	}
+
+	return 0;
+}
+
+#define REISER4_CHECK_BMAP_CRC (0)
+
+#if REISER4_CHECK_BMAP_CRC
+static int bnode_check_crc(const struct bitmap_node *bnode)
+{
+	return bnode_check_adler32(bnode,
+				   bmap_size(sb_by_bnode(bnode)->s_blocksize));
+}
+
+/* REISER4_CHECK_BMAP_CRC */
+#else
+
+#define bnode_check_crc(bnode) (0)
+
+/* REISER4_CHECK_BMAP_CRC */
+#endif
+
+/* Recalculates the adler32 checksum for only 1 byte change.
+    adler - previous adler checksum
+    old_data, data - old, new byte values.
+    tail == (chunk - offset) : length, checksum was calculated for, - offset of
+    the changed byte within this chunk.
+    This function can be used for checksum calculation optimisation.
+*/
+
+static __u32
+adler32_recalc(__u32 adler, unsigned char old_data, unsigned char data,
+	       __u32 tail)
+{
+	__u32 delta = data - old_data + 2 * ADLER_BASE;
+	__u32 s1 = adler & 0xffff;
+	__u32 s2 = (adler >> 16) & 0xffff;
+
+	s1 = (delta + s1) % ADLER_BASE;
+	s2 = (delta * tail + s2) % ADLER_BASE;
+
+	return (s2 << 16) | s1;
+}
+
+#define LIMIT(val, boundary) ((val) > (boundary) ? (boundary) : (val))
+
+/**
+ * get_nr_bitmap - calculate number of bitmap blocks
+ * @super: super block with initialized blocksize and block count
+ *
+ * Calculates number of bitmap blocks of a filesystem which uses bitmaps to
+ * maintain free disk space. It assumes that each bitmap addresses the same
+ * number of blocks which is calculated by bmap_block_count macro defined in
+ * above. Number of blocks in the filesystem has to be initialized in reiser4
+ * private data of super block already so that it can be obtained via
+ * reiser4_block_count(). Unfortunately, number of blocks addressed by a bitmap
+ * is not power of 2 because 4 bytes are used for checksum. Therefore, we have
+ * to use special function to divide and modulo 64bits filesystem block
+ * counters.
+ *
+ * Example: suppose filesystem have 32768 blocks. Blocksize is 4096. Each bitmap
+ * block addresses (4096 - 4) * 8 = 32736 blocks. Number of bitmaps to address
+ * all 32768 blocks is calculated as (32768 - 1) / 32736 + 1 = 2.
+ */
+static bmap_nr_t get_nr_bmap(const struct super_block *super)
+{
+	u64 quotient;
+
+	assert("zam-393", reiser4_block_count(super) != 0);
+
+	quotient = reiser4_block_count(super) - 1;
+	do_div(quotient, bmap_bit_count(super->s_blocksize));
+	return quotient + 1;
+}
+
+/**
+ * parse_blocknr - calculate bitmap number and offset in it by block number
+ * @block: pointer to block number to calculate location in bitmap of
+ * @bmap: pointer where to store bitmap block number
+ * @offset: pointer where to store offset within bitmap block
+ *
+ * Calculates location of bit which is responsible for allocation/freeing of
+ * block @*block. That location is represented by bitmap block number and offset
+ * within that bitmap block.
+ */
+static void
+parse_blocknr(const reiser4_block_nr *block, bmap_nr_t *bmap,
+	      bmap_off_t *offset)
+{
+	struct super_block *super = get_current_context()->super;
+	u64 quotient = *block;
+
+	*offset = do_div(quotient, bmap_bit_count(super->s_blocksize));
+	*bmap = quotient;
+
+	assert("zam-433", *bmap < get_nr_bmap(super));
+	assert("", *offset < bmap_bit_count(super->s_blocksize));
+}
+
+#if REISER4_DEBUG
+/* Audited by: green(2002.06.12) */
+static void
+check_block_range(const reiser4_block_nr * start, const reiser4_block_nr * len)
+{
+	struct super_block *sb = reiser4_get_current_sb();
+
+	assert("zam-436", sb != NULL);
+
+	assert("zam-455", start != NULL);
+	assert("zam-437", *start != 0);
+	assert("zam-541", !blocknr_is_fake(start));
+	assert("zam-441", *start < reiser4_block_count(sb));
+
+	if (len != NULL) {
+		assert("zam-438", *len != 0);
+		assert("zam-442", *start + *len <= reiser4_block_count(sb));
+	}
+}
+
+static void check_bnode_loaded(const struct bitmap_node *bnode)
+{
+	assert("zam-485", bnode != NULL);
+	assert("zam-483", jnode_page(bnode->wjnode) != NULL);
+	assert("zam-484", jnode_page(bnode->cjnode) != NULL);
+	assert("nikita-2820", jnode_is_loaded(bnode->wjnode));
+	assert("nikita-2821", jnode_is_loaded(bnode->cjnode));
+}
+
+#else
+
+#  define check_block_range(start, len) do { /* nothing */} while(0)
+#  define check_bnode_loaded(bnode)     do { /* nothing */} while(0)
+
+#endif
+
+/* modify bnode->first_zero_bit (if we free bits before); bnode should be
+   spin-locked */
+static inline void
+adjust_first_zero_bit(struct bitmap_node *bnode, bmap_off_t offset)
+{
+	if (offset < bnode->first_zero_bit)
+		bnode->first_zero_bit = offset;
+}
+
+/* return a physical disk address for logical bitmap number @bmap */
+/* FIXME-VS: this is somehow related to disk layout? */
+/* ZAM-FIXME-HANS: your answer is? Use not more than one function dereference
+ * per block allocation so that performance is not affected.  Probably this
+ * whole file should be considered part of the disk layout plugin, and other
+ * disk layouts can use other defines and efficiency will not be significantly
+ * affected.  */
+
+#define REISER4_FIRST_BITMAP_BLOCK \
+	((REISER4_MASTER_OFFSET / PAGE_CACHE_SIZE) + 2)
+
+/* Audited by: green(2002.06.12) */
+static void
+get_bitmap_blocknr(struct super_block *super, bmap_nr_t bmap,
+		   reiser4_block_nr * bnr)
+{
+
+	assert("zam-390", bmap < get_nr_bmap(super));
+
+#ifdef CONFIG_REISER4_BADBLOCKS
+#define BITMAP_PLUGIN_DISKMAP_ID ((0xc0e1<<16) | (0xe0ff))
+	/* Check if the diskmap have this already, first. */
+	if (reiser4_get_diskmap_value(BITMAP_PLUGIN_DISKMAP_ID, bmap, bnr) == 0)
+		return;		/* Found it in diskmap */
+#endif
+	/* FIXME_ZAM: before discussing of disk layouts and disk format
+	   plugins I implement bitmap location scheme which is close to scheme
+	   used in reiser 3.6 */
+	if (bmap == 0) {
+		*bnr = REISER4_FIRST_BITMAP_BLOCK;
+	} else {
+		*bnr = bmap * bmap_bit_count(super->s_blocksize);
+	}
+}
+
+/* construct a fake block number for shadow bitmap (WORKING BITMAP) block */
+/* Audited by: green(2002.06.12) */
+static void get_working_bitmap_blocknr(bmap_nr_t bmap, reiser4_block_nr * bnr)
+{
+	*bnr =
+	    (reiser4_block_nr) ((bmap & ~REISER4_BLOCKNR_STATUS_BIT_MASK) |
+				REISER4_BITMAP_BLOCKS_STATUS_VALUE);
+}
+
+/* bnode structure initialization */
+static void
+init_bnode(struct bitmap_node *bnode,
+	   struct super_block *super UNUSED_ARG, bmap_nr_t bmap UNUSED_ARG)
+{
+	memset(bnode, 0, sizeof(struct bitmap_node));
+
+	sema_init(&bnode->sema, 1);
+	atomic_set(&bnode->loaded, 0);
+}
+
+static void release(jnode * node)
+{
+	jrelse(node);
+	JF_SET(node, JNODE_HEARD_BANSHEE);
+	jput(node);
+}
+
+/* This function is for internal bitmap.c use because it assumes that jnode is
+   in under full control of this thread */
+static void done_bnode(struct bitmap_node *bnode)
+{
+	if (bnode) {
+		atomic_set(&bnode->loaded, 0);
+		if (bnode->wjnode != NULL)
+			release(bnode->wjnode);
+		if (bnode->cjnode != NULL)
+			release(bnode->cjnode);
+		bnode->wjnode = bnode->cjnode = NULL;
+	}
+}
+
+/* ZAM-FIXME-HANS: comment this.  Called only by load_and_lock_bnode()*/
+static int
+prepare_bnode(struct bitmap_node *bnode, jnode ** cjnode_ret,
+	      jnode ** wjnode_ret)
+{
+	struct super_block *super;
+	jnode *cjnode;
+	jnode *wjnode;
+	bmap_nr_t bmap;
+	int ret;
+
+	super = reiser4_get_current_sb();
+
+	*wjnode_ret = wjnode = bnew();
+	if (wjnode == NULL)
+		return RETERR(-ENOMEM);
+
+	*cjnode_ret = cjnode = bnew();
+	if (cjnode == NULL)
+		return RETERR(-ENOMEM);
+
+	bmap = bnode - get_bnode(super, 0);
+
+	get_working_bitmap_blocknr(bmap, &wjnode->blocknr);
+	get_bitmap_blocknr(super, bmap, &cjnode->blocknr);
+
+	jref(cjnode);
+	jref(wjnode);
+
+	/* load commit bitmap */
+	ret = jload_gfp(cjnode, GFP_NOFS, 1);
+
+	if (ret)
+		goto error;
+
+	/* allocate memory for working bitmap block. Note that for
+	 * bitmaps jinit_new() doesn't actually modifies node content,
+	 * so parallel calls to this are ok. */
+	ret = jinit_new(wjnode, GFP_NOFS);
+
+	if (ret != 0) {
+		jrelse(cjnode);
+		goto error;
+	}
+
+	return 0;
+
+      error:
+	jput(cjnode);
+	jput(wjnode);
+	*wjnode_ret = *cjnode_ret = NULL;
+	return ret;
+
+}
+
+/* Check the bnode data on read. */
+static int check_struct_bnode(struct bitmap_node *bnode, __u32 blksize)
+{
+	void *data;
+	int ret;
+
+	/* Check CRC */
+	ret = bnode_check_adler32(bnode, blksize);
+
+	if (ret) {
+		return ret;
+	}
+
+	data = jdata(bnode->cjnode) + CHECKSUM_SIZE;
+
+	/* Check the very first bit -- it must be busy. */
+	if (!reiser4_test_bit(0, data)) {
+		warning("vpf-1362", "The allocator block %llu is not marked "
+			"as used.", (unsigned long long)bnode->cjnode->blocknr);
+
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* load bitmap blocks "on-demand" */
+static int load_and_lock_bnode(struct bitmap_node *bnode)
+{
+	int ret;
+
+	jnode *cjnode;
+	jnode *wjnode;
+
+	assert("nikita-3040", schedulable());
+
+/* ZAM-FIXME-HANS: since bitmaps are never unloaded, this does not
+ * need to be atomic, right? Just leave a comment that if bitmaps were
+ * unloadable, this would need to be atomic.  */
+	if (atomic_read(&bnode->loaded)) {
+		/* bitmap is already loaded, nothing to do */
+		check_bnode_loaded(bnode);
+		down(&bnode->sema);
+		assert("nikita-2827", atomic_read(&bnode->loaded));
+		return 0;
+	}
+
+	ret = prepare_bnode(bnode, &cjnode, &wjnode);
+	if (ret == 0) {
+		down(&bnode->sema);
+
+		if (!atomic_read(&bnode->loaded)) {
+			assert("nikita-2822", cjnode != NULL);
+			assert("nikita-2823", wjnode != NULL);
+			assert("nikita-2824", jnode_is_loaded(cjnode));
+			assert("nikita-2825", jnode_is_loaded(wjnode));
+
+			bnode->wjnode = wjnode;
+			bnode->cjnode = cjnode;
+
+			ret = check_struct_bnode(bnode, current_blocksize);
+			if (!ret) {
+				cjnode = wjnode = NULL;
+				atomic_set(&bnode->loaded, 1);
+				/* working bitmap is initialized by on-disk
+				 * commit bitmap. This should be performed
+				 * under semaphore. */
+				memcpy(bnode_working_data(bnode),
+				       bnode_commit_data(bnode),
+				       bmap_size(current_blocksize));
+			} else {
+				up(&bnode->sema);
+			}
+		} else
+			/* race: someone already loaded bitmap while we were
+			 * busy initializing data. */
+			check_bnode_loaded(bnode);
+	}
+
+	if (wjnode != NULL) {
+		release(wjnode);
+		bnode->wjnode = NULL;
+	}
+	if (cjnode != NULL) {
+		release(cjnode);
+		bnode->cjnode = NULL;
+	}
+
+	return ret;
+}
+
+static void release_and_unlock_bnode(struct bitmap_node *bnode)
+{
+	check_bnode_loaded(bnode);
+	up(&bnode->sema);
+}
+
+/* This function does all block allocation work but only for one bitmap
+   block.*/
+/* FIXME_ZAM: It does not allow us to allocate block ranges across bitmap
+   block responsibility zone boundaries. This had no sense in v3.6 but may
+   have it in v4.x */
+/* ZAM-FIXME-HANS: do you mean search one bitmap block forward? */
+static int
+search_one_bitmap_forward(bmap_nr_t bmap, bmap_off_t * offset,
+			  bmap_off_t max_offset, int min_len, int max_len)
+{
+	struct super_block *super = get_current_context()->super;
+	struct bitmap_node *bnode = get_bnode(super, bmap);
+
+	char *data;
+
+	bmap_off_t search_end;
+	bmap_off_t start;
+	bmap_off_t end;
+
+	int set_first_zero_bit = 0;
+
+	int ret;
+
+	assert("zam-364", min_len > 0);
+	assert("zam-365", max_len >= min_len);
+	assert("zam-366", *offset < max_offset);
+
+	ret = load_and_lock_bnode(bnode);
+
+	if (ret)
+		return ret;
+
+	data = bnode_working_data(bnode);
+
+	start = *offset;
+
+	if (bnode->first_zero_bit >= start) {
+		start = bnode->first_zero_bit;
+		set_first_zero_bit = 1;
+	}
+
+	while (start + min_len < max_offset) {
+
+		start =
+		    reiser4_find_next_zero_bit((long *)data, max_offset, start);
+		if (set_first_zero_bit) {
+			bnode->first_zero_bit = start;
+			set_first_zero_bit = 0;
+		}
+		if (start >= max_offset)
+			break;
+
+		search_end = LIMIT(start + max_len, max_offset);
+		end =
+		    reiser4_find_next_set_bit((long *)data, search_end, start);
+		if (end >= start + min_len) {
+			/* we can't trust find_next_set_bit result if set bit
+			   was not fount, result may be bigger than
+			   max_offset */
+			if (end > search_end)
+				end = search_end;
+
+			ret = end - start;
+			*offset = start;
+
+			reiser4_set_bits(data, start, end);
+
+			/* FIXME: we may advance first_zero_bit if [start,
+			   end] region overlaps the first_zero_bit point */
+
+			break;
+		}
+
+		start = end + 1;
+	}
+
+	release_and_unlock_bnode(bnode);
+
+	return ret;
+}
+
+static int
+search_one_bitmap_backward(bmap_nr_t bmap, bmap_off_t * start_offset,
+			   bmap_off_t end_offset, int min_len, int max_len)
+{
+	struct super_block *super = get_current_context()->super;
+	struct bitmap_node *bnode = get_bnode(super, bmap);
+	char *data;
+	bmap_off_t start;
+	int ret;
+
+	assert("zam-958", min_len > 0);
+	assert("zam-959", max_len >= min_len);
+	assert("zam-960", *start_offset >= end_offset);
+
+	ret = load_and_lock_bnode(bnode);
+	if (ret)
+		return ret;
+
+	data = bnode_working_data(bnode);
+	start = *start_offset;
+
+	while (1) {
+		bmap_off_t end, search_end;
+
+		/* Find the beginning of the zero filled region */
+		if (reiser4_find_last_zero_bit(&start, data, end_offset, start))
+			break;
+		/* Is there more than `min_len' bits from `start' to
+		 * `end_offset'?  */
+		if (start < end_offset + min_len - 1)
+			break;
+
+		/* Do not search to `end_offset' if we need to find less than
+		 * `max_len' zero bits. */
+		if (end_offset + max_len - 1 < start)
+			search_end = start - max_len + 1;
+		else
+			search_end = end_offset;
+
+		if (reiser4_find_last_set_bit(&end, data, search_end, start))
+			end = search_end;
+		else
+			end++;
+
+		if (end + min_len <= start + 1) {
+			if (end < search_end)
+				end = search_end;
+			ret = start - end + 1;
+			*start_offset = end;	/* `end' is lowest offset */
+			assert("zam-987",
+			       reiser4_find_next_set_bit(data, start + 1,
+							 end) >= start + 1);
+			reiser4_set_bits(data, end, start + 1);
+			break;
+		}
+
+		if (end <= end_offset)
+			/* left search boundary reached. */
+			break;
+		start = end - 1;
+	}
+
+	release_and_unlock_bnode(bnode);
+	return ret;
+}
+
+/* allocate contiguous range of blocks in bitmap */
+static int bitmap_alloc_forward(reiser4_block_nr * start,
+				const reiser4_block_nr * end, int min_len,
+				int max_len)
+{
+	bmap_nr_t bmap, end_bmap;
+	bmap_off_t offset, end_offset;
+	int len;
+
+	reiser4_block_nr tmp;
+
+	struct super_block *super = get_current_context()->super;
+	const bmap_off_t max_offset = bmap_bit_count(super->s_blocksize);
+
+	parse_blocknr(start, &bmap, &offset);
+
+	tmp = *end - 1;
+	parse_blocknr(&tmp, &end_bmap, &end_offset);
+	++end_offset;
+
+	assert("zam-358", end_bmap >= bmap);
+	assert("zam-359", ergo(end_bmap == bmap, end_offset > offset));
+
+	for (; bmap < end_bmap; bmap++, offset = 0) {
+		len =
+		    search_one_bitmap_forward(bmap, &offset, max_offset,
+					      min_len, max_len);
+		if (len != 0)
+			goto out;
+	}
+
+	len =
+	    search_one_bitmap_forward(bmap, &offset, end_offset, min_len,
+				      max_len);
+      out:
+	*start = bmap * max_offset + offset;
+	return len;
+}
+
+/* allocate contiguous range of blocks in bitmap (from @start to @end in
+ * backward direction) */
+static int bitmap_alloc_backward(reiser4_block_nr * start,
+				 const reiser4_block_nr * end, int min_len,
+				 int max_len)
+{
+	bmap_nr_t bmap, end_bmap;
+	bmap_off_t offset, end_offset;
+	int len;
+	struct super_block *super = get_current_context()->super;
+	const bmap_off_t max_offset = bmap_bit_count(super->s_blocksize);
+
+	parse_blocknr(start, &bmap, &offset);
+	parse_blocknr(end, &end_bmap, &end_offset);
+
+	assert("zam-961", end_bmap <= bmap);
+	assert("zam-962", ergo(end_bmap == bmap, end_offset <= offset));
+
+	for (; bmap > end_bmap; bmap--, offset = max_offset - 1) {
+		len =
+		    search_one_bitmap_backward(bmap, &offset, 0, min_len,
+					       max_len);
+		if (len != 0)
+			goto out;
+	}
+
+	len =
+	    search_one_bitmap_backward(bmap, &offset, end_offset, min_len,
+				       max_len);
+      out:
+	*start = bmap * max_offset + offset;
+	return len;
+}
+
+/* plugin->u.space_allocator.alloc_blocks() */
+static int
+alloc_blocks_forward(reiser4_blocknr_hint * hint, int needed,
+		     reiser4_block_nr * start, reiser4_block_nr * len)
+{
+	struct super_block *super = get_current_context()->super;
+	int actual_len;
+
+	reiser4_block_nr search_start;
+	reiser4_block_nr search_end;
+
+	assert("zam-398", super != NULL);
+	assert("zam-412", hint != NULL);
+	assert("zam-397", hint->blk < reiser4_block_count(super));
+
+	if (hint->max_dist == 0)
+		search_end = reiser4_block_count(super);
+	else
+		search_end =
+		    LIMIT(hint->blk + hint->max_dist,
+			  reiser4_block_count(super));
+
+	/* We use @hint -> blk as a search start and search from it to the end
+	   of the disk or in given region if @hint -> max_dist is not zero */
+	search_start = hint->blk;
+
+	actual_len =
+	    bitmap_alloc_forward(&search_start, &search_end, 1, needed);
+
+	/* There is only one bitmap search if max_dist was specified or first
+	   pass was from the beginning of the bitmap. We also do one pass for
+	   scanning bitmap in backward direction. */
+	if (!(actual_len != 0 || hint->max_dist != 0 || search_start == 0)) {
+		/* next step is a scanning from 0 to search_start */
+		search_end = search_start;
+		search_start = 0;
+		actual_len =
+		    bitmap_alloc_forward(&search_start, &search_end, 1, needed);
+	}
+	if (actual_len == 0)
+		return RETERR(-ENOSPC);
+	if (actual_len < 0)
+		return RETERR(actual_len);
+	*len = actual_len;
+	*start = search_start;
+	return 0;
+}
+
+static int alloc_blocks_backward(reiser4_blocknr_hint * hint, int needed,
+				 reiser4_block_nr * start,
+				 reiser4_block_nr * len)
+{
+	reiser4_block_nr search_start;
+	reiser4_block_nr search_end;
+	int actual_len;
+
+	ON_DEBUG(struct super_block *super = reiser4_get_current_sb());
+
+	assert("zam-969", super != NULL);
+	assert("zam-970", hint != NULL);
+	assert("zam-971", hint->blk < reiser4_block_count(super));
+
+	search_start = hint->blk;
+	if (hint->max_dist == 0 || search_start <= hint->max_dist)
+		search_end = 0;
+	else
+		search_end = search_start - hint->max_dist;
+
+	actual_len =
+	    bitmap_alloc_backward(&search_start, &search_end, 1, needed);
+	if (actual_len == 0)
+		return RETERR(-ENOSPC);
+	if (actual_len < 0)
+		return RETERR(actual_len);
+	*len = actual_len;
+	*start = search_start;
+	return 0;
+}
+
+/* plugin->u.space_allocator.alloc_blocks() */
+int
+alloc_blocks_bitmap(reiser4_space_allocator * allocator UNUSED_ARG,
+		    reiser4_blocknr_hint * hint, int needed,
+		    reiser4_block_nr * start, reiser4_block_nr * len)
+{
+	if (hint->backward)
+		return alloc_blocks_backward(hint, needed, start, len);
+	return alloc_blocks_forward(hint, needed, start, len);
+}
+
+/* plugin->u.space_allocator.dealloc_blocks(). */
+/* It just frees blocks in WORKING BITMAP. Usually formatted an unformatted
+   nodes deletion is deferred until transaction commit.  However, deallocation
+   of temporary objects like wandered blocks and transaction commit records
+   requires immediate node deletion from WORKING BITMAP.*/
+void
+dealloc_blocks_bitmap(reiser4_space_allocator * allocator UNUSED_ARG,
+		      reiser4_block_nr start, reiser4_block_nr len)
+{
+	struct super_block *super = reiser4_get_current_sb();
+
+	bmap_nr_t bmap;
+	bmap_off_t offset;
+
+	struct bitmap_node *bnode;
+	int ret;
+
+	assert("zam-468", len != 0);
+	check_block_range(&start, &len);
+
+	parse_blocknr(&start, &bmap, &offset);
+
+	assert("zam-469", offset + len <= bmap_bit_count(super->s_blocksize));
+
+	bnode = get_bnode(super, bmap);
+
+	assert("zam-470", bnode != NULL);
+
+	ret = load_and_lock_bnode(bnode);
+	assert("zam-481", ret == 0);
+
+	reiser4_clear_bits(bnode_working_data(bnode), offset,
+			   (bmap_off_t) (offset + len));
+
+	adjust_first_zero_bit(bnode, offset);
+
+	release_and_unlock_bnode(bnode);
+}
+
+/* plugin->u.space_allocator.check_blocks(). */
+void
+check_blocks_bitmap(const reiser4_block_nr * start,
+		    const reiser4_block_nr * len, int desired)
+{
+#if REISER4_DEBUG
+	struct super_block *super = reiser4_get_current_sb();
+
+	bmap_nr_t bmap;
+	bmap_off_t start_offset;
+	bmap_off_t end_offset;
+
+	struct bitmap_node *bnode;
+	int ret;
+
+	assert("zam-622", len != NULL);
+	check_block_range(start, len);
+	parse_blocknr(start, &bmap, &start_offset);
+
+	end_offset = start_offset + *len;
+	assert("nikita-2214", end_offset <= bmap_bit_count(super->s_blocksize));
+
+	bnode = get_bnode(super, bmap);
+
+	assert("nikita-2215", bnode != NULL);
+
+	ret = load_and_lock_bnode(bnode);
+	assert("zam-626", ret == 0);
+
+	assert("nikita-2216", jnode_is_loaded(bnode->wjnode));
+
+	if (desired) {
+		assert("zam-623",
+		       reiser4_find_next_zero_bit(bnode_working_data(bnode),
+						  end_offset, start_offset)
+		       >= end_offset);
+	} else {
+		assert("zam-624",
+		       reiser4_find_next_set_bit(bnode_working_data(bnode),
+						 end_offset, start_offset)
+		       >= end_offset);
+	}
+
+	release_and_unlock_bnode(bnode);
+#endif
+}
+
+/* conditional insertion of @node into atom's overwrite set  if it was not there */
+static void cond_add_to_overwrite_set(txn_atom * atom, jnode * node)
+{
+	assert("zam-546", atom != NULL);
+	assert("zam-547", atom->stage == ASTAGE_PRE_COMMIT);
+	assert("zam-548", node != NULL);
+
+	spin_lock_atom(atom);
+	spin_lock_jnode(node);
+
+	if (node->atom == NULL) {
+		JF_SET(node, JNODE_OVRWR);
+		insert_into_atom_ovrwr_list(atom, node);
+	} else {
+		assert("zam-549", node->atom == atom);
+	}
+
+	spin_unlock_jnode(node);
+	spin_unlock_atom(atom);
+}
+
+/* an actor which applies delete set to COMMIT bitmap pages and link modified
+   pages in a single-linked list */
+static int
+apply_dset_to_commit_bmap(txn_atom * atom, const reiser4_block_nr * start,
+			  const reiser4_block_nr * len, void *data)
+{
+
+	bmap_nr_t bmap;
+	bmap_off_t offset;
+	int ret;
+
+	long long *blocks_freed_p = data;
+
+	struct bitmap_node *bnode;
+
+	struct super_block *sb = reiser4_get_current_sb();
+
+	check_block_range(start, len);
+
+	parse_blocknr(start, &bmap, &offset);
+
+	/* FIXME-ZAM: we assume that all block ranges are allocated by this
+	   bitmap-based allocator and each block range can't go over a zone of
+	   responsibility of one bitmap block; same assumption is used in
+	   other journal hooks in bitmap code. */
+	bnode = get_bnode(sb, bmap);
+	assert("zam-448", bnode != NULL);
+
+	/* it is safe to unlock atom with is in ASTAGE_PRE_COMMIT */
+	assert("zam-767", atom->stage == ASTAGE_PRE_COMMIT);
+	ret = load_and_lock_bnode(bnode);
+	if (ret)
+		return ret;
+
+	/* put bnode into atom's overwrite set */
+	cond_add_to_overwrite_set(atom, bnode->cjnode);
+
+	data = bnode_commit_data(bnode);
+
+	ret = bnode_check_crc(bnode);
+	if (ret != 0)
+		return ret;
+
+	if (len != NULL) {
+		/* FIXME-ZAM: a check that all bits are set should be there */
+		assert("zam-443",
+		       offset + *len <= bmap_bit_count(sb->s_blocksize));
+		reiser4_clear_bits(data, offset, (bmap_off_t) (offset + *len));
+
+		(*blocks_freed_p) += *len;
+	} else {
+		reiser4_clear_bit(offset, data);
+		(*blocks_freed_p)++;
+	}
+
+	bnode_set_commit_crc(bnode, bnode_calc_crc(bnode, sb->s_blocksize));
+
+	release_and_unlock_bnode(bnode);
+
+	return 0;
+}
+
+/* plugin->u.space_allocator.pre_commit_hook(). */
+/* It just applies transaction changes to fs-wide COMMIT BITMAP, hoping the
+   rest is done by transaction manager (allocate wandered locations for COMMIT
+   BITMAP blocks, copy COMMIT BITMAP blocks data). */
+/* Only one instance of this function can be running at one given time, because
+   only one transaction can be committed a time, therefore it is safe to access
+   some global variables without any locking */
+
+#if REISER4_COPY_ON_CAPTURE
+
+extern spinlock_t scan_lock;
+
+int pre_commit_hook_bitmap(void)
+{
+	struct super_block *super = reiser4_get_current_sb();
+	txn_atom *atom;
+
+	long long blocks_freed = 0;
+
+	atom = get_current_atom_locked();
+	BUG_ON(atom->stage != ASTAGE_PRE_COMMIT);
+	assert("zam-876", atom->stage == ASTAGE_PRE_COMMIT);
+	spin_unlock_atom(atom);
+
+	{			/* scan atom's captured list and find all freshly allocated nodes,
+				 * mark corresponded bits in COMMIT BITMAP as used */
+		/* how cpu significant is this scan, should we someday have a freshly_allocated list? -Hans */
+		capture_list_head *head = ATOM_CLEAN_LIST(atom);
+		jnode *node;
+
+		spin_lock(&scan_lock);
+		node = capture_list_front(head);
+
+		while (!capture_list_end(head, node)) {
+			int ret;
+
+			assert("vs-1445", NODE_LIST(node) == CLEAN_LIST);
+			BUG_ON(node->atom != atom);
+			JF_SET(node, JNODE_SCANNED);
+			spin_unlock(&scan_lock);
+
+			/* we detect freshly allocated jnodes */
+			if (JF_ISSET(node, JNODE_RELOC)) {
+				bmap_nr_t bmap;
+
+				bmap_off_t offset;
+				bmap_off_t index;
+				struct bitmap_node *bn;
+				__u32 size = bmap_size(super->s_blocksize);
+				char byte;
+				__u32 crc;
+
+				assert("zam-559", !JF_ISSET(node, JNODE_OVRWR));
+				assert("zam-460",
+				       !blocknr_is_fake(&node->blocknr));
+
+				parse_blocknr(&node->blocknr, &bmap, &offset);
+				bn = get_bnode(super, bmap);
+
+				index = offset >> 3;
+				assert("vpf-276", index < size);
+
+				ret = bnode_check_crc(bnode);
+				if (ret != 0)
+					return ret;
+
+				check_bnode_loaded(bn);
+				load_and_lock_bnode(bn);
+
+				byte = *(bnode_commit_data(bn) + index);
+				reiser4_set_bit(offset, bnode_commit_data(bn));
+
+				crc = adler32_recalc(bnode_commit_crc(bn), byte,
+						     *(bnode_commit_data(bn) +
+						       index),
+						     size - index),
+				    bnode_set_commit_crc(bn, crc);
+
+				release_and_unlock_bnode(bn);
+
+				ret = bnode_check_crc(bnode);
+				if (ret != 0)
+					return ret;
+
+				/* working of this depends on how it inserts
+				   new j-node into clean list, because we are
+				   scanning the same list now. It is OK, if
+				   insertion is done to the list front */
+				cond_add_to_overwrite_set(atom, bn->cjnode);
+			}
+
+			spin_lock(&scan_lock);
+			JF_CLR(node, JNODE_SCANNED);
+			node = capture_list_next(node);
+		}
+		spin_unlock(&scan_lock);
+	}
+
+	blocknr_set_iterator(atom, &atom->delete_set, apply_dset_to_commit_bmap,
+			     &blocks_freed, 0);
+
+	blocks_freed -= atom->nr_blocks_allocated;
+
+	{
+		reiser4_super_info_data *sbinfo;
+
+		sbinfo = get_super_private(super);
+
+		reiser4_spin_lock_sb(sbinfo);
+		sbinfo->blocks_free_committed += blocks_freed;
+		reiser4_spin_unlock_sb(sbinfo);
+	}
+
+	return 0;
+}
+
+#else				/* ! REISER4_COPY_ON_CAPTURE */
+
+int pre_commit_hook_bitmap(void)
+{
+	struct super_block *super = reiser4_get_current_sb();
+	txn_atom *atom;
+
+	long long blocks_freed = 0;
+
+	atom = get_current_atom_locked();
+	assert("zam-876", atom->stage == ASTAGE_PRE_COMMIT);
+	spin_unlock_atom(atom);
+
+	{			/* scan atom's captured list and find all freshly allocated nodes,
+				 * mark corresponded bits in COMMIT BITMAP as used */
+		struct list_head *head = ATOM_CLEAN_LIST(atom);
+		jnode *node = list_entry(head->next, jnode, capture_link);
+
+		while (head != &node->capture_link) {
+			/* we detect freshly allocated jnodes */
+			if (JF_ISSET(node, JNODE_RELOC)) {
+				int ret;
+				bmap_nr_t bmap;
+
+				bmap_off_t offset;
+				bmap_off_t index;
+				struct bitmap_node *bn;
+				__u32 size = bmap_size(super->s_blocksize);
+				__u32 crc;
+				char byte;
+
+				assert("zam-559", !JF_ISSET(node, JNODE_OVRWR));
+				assert("zam-460",
+				       !blocknr_is_fake(&node->blocknr));
+
+				parse_blocknr(&node->blocknr, &bmap, &offset);
+				bn = get_bnode(super, bmap);
+
+				index = offset >> 3;
+				assert("vpf-276", index < size);
+
+				ret = bnode_check_crc(bnode);
+				if (ret != 0)
+					return ret;
+
+				check_bnode_loaded(bn);
+				load_and_lock_bnode(bn);
+
+				byte = *(bnode_commit_data(bn) + index);
+				reiser4_set_bit(offset, bnode_commit_data(bn));
+
+				crc = adler32_recalc(bnode_commit_crc(bn), byte,
+						     *(bnode_commit_data(bn) +
+						       index),
+						     size - index),
+				    bnode_set_commit_crc(bn, crc);
+
+				release_and_unlock_bnode(bn);
+
+				ret = bnode_check_crc(bn);
+				if (ret != 0)
+					return ret;
+
+				/* working of this depends on how it inserts
+				   new j-node into clean list, because we are
+				   scanning the same list now. It is OK, if
+				   insertion is done to the list front */
+				cond_add_to_overwrite_set(atom, bn->cjnode);
+			}
+
+			node = list_entry(node->capture_link.next, jnode, capture_link);
+		}
+	}
+
+	blocknr_set_iterator(atom, &atom->delete_set, apply_dset_to_commit_bmap,
+			     &blocks_freed, 0);
+
+	blocks_freed -= atom->nr_blocks_allocated;
+
+	{
+		reiser4_super_info_data *sbinfo;
+
+		sbinfo = get_super_private(super);
+
+		spin_lock_reiser4_super(sbinfo);
+		sbinfo->blocks_free_committed += blocks_freed;
+		spin_unlock_reiser4_super(sbinfo);
+	}
+
+	return 0;
+}
+#endif				/* ! REISER4_COPY_ON_CAPTURE */
+
+/* plugin->u.space_allocator.init_allocator
+    constructor of reiser4_space_allocator object. It is called on fs mount */
+int
+init_allocator_bitmap(reiser4_space_allocator * allocator,
+		      struct super_block *super, void *arg UNUSED_ARG)
+{
+	struct bitmap_allocator_data *data = NULL;
+	bmap_nr_t bitmap_blocks_nr;
+	bmap_nr_t i;
+
+	assert("nikita-3039", schedulable());
+
+	/* getting memory for bitmap allocator private data holder */
+	data =
+		kmalloc(sizeof(struct bitmap_allocator_data), GFP_KERNEL);
+
+	if (data == NULL)
+		return RETERR(-ENOMEM);
+
+	/* allocation and initialization for the array of bnodes */
+	bitmap_blocks_nr = get_nr_bmap(super);
+
+	/* FIXME-ZAM: it is not clear what to do with huge number of bitmaps
+	   which is bigger than 2^32 (= 8 * 4096 * 4096 * 2^32 bytes = 5.76e+17,
+	   may I never meet someone who still uses the ia32 architecture when
+	   storage devices of that size enter the market, and wants to use ia32
+	   with that storage device, much less reiser4. ;-) -Hans). Kmalloc is not possible and,
+	   probably, another dynamic data structure should replace a static
+	   array of bnodes. */
+	/*data->bitmap = reiser4_kmalloc((size_t) (sizeof (struct bitmap_node) * bitmap_blocks_nr), GFP_KERNEL); */
+	data->bitmap = vmalloc(sizeof(struct bitmap_node) * bitmap_blocks_nr);
+	if (data->bitmap == NULL) {
+		kfree(data);
+		return RETERR(-ENOMEM);
+	}
+
+	for (i = 0; i < bitmap_blocks_nr; i++)
+		init_bnode(data->bitmap + i, super, i);
+
+	allocator->u.generic = data;
+
+#if REISER4_DEBUG
+	get_super_private(super)->min_blocks_used += bitmap_blocks_nr;
+#endif
+
+	/* Load all bitmap blocks at mount time. */
+	if (!test_bit
+	    (REISER4_DONT_LOAD_BITMAP, &get_super_private(super)->fs_flags)) {
+		__u64 start_time, elapsed_time;
+		struct bitmap_node *bnode;
+		int ret;
+
+		if (REISER4_DEBUG)
+			printk(KERN_INFO "loading reiser4 bitmap...");
+		start_time = jiffies;
+
+		for (i = 0; i < bitmap_blocks_nr; i++) {
+			bnode = data->bitmap + i;
+			ret = load_and_lock_bnode(bnode);
+			if (ret) {
+				destroy_allocator_bitmap(allocator, super);
+				return ret;
+			}
+			release_and_unlock_bnode(bnode);
+		}
+
+		elapsed_time = jiffies - start_time;
+		if (REISER4_DEBUG)
+			printk("...done (%llu jiffies)\n",
+			       (unsigned long long)elapsed_time);
+	}
+
+	return 0;
+}
+
+/* plugin->u.space_allocator.destroy_allocator
+   destructor. It is called on fs unmount */
+int
+destroy_allocator_bitmap(reiser4_space_allocator * allocator,
+			 struct super_block *super)
+{
+	bmap_nr_t bitmap_blocks_nr;
+	bmap_nr_t i;
+
+	struct bitmap_allocator_data *data = allocator->u.generic;
+
+	assert("zam-414", data != NULL);
+	assert("zam-376", data->bitmap != NULL);
+
+	bitmap_blocks_nr = get_nr_bmap(super);
+
+	for (i = 0; i < bitmap_blocks_nr; i++) {
+		struct bitmap_node *bnode = data->bitmap + i;
+
+		down(&bnode->sema);
+
+#if REISER4_DEBUG
+		if (atomic_read(&bnode->loaded)) {
+			jnode *wj = bnode->wjnode;
+			jnode *cj = bnode->cjnode;
+
+			assert("zam-480", jnode_page(cj) != NULL);
+			assert("zam-633", jnode_page(wj) != NULL);
+
+			assert("zam-634",
+			       memcmp(jdata(wj), jdata(wj),
+				      bmap_size(super->s_blocksize)) == 0);
+
+		}
+#endif
+		done_bnode(bnode);
+		up(&bnode->sema);
+	}
+
+	vfree(data->bitmap);
+	kfree(data);
+
+	allocator->u.generic = NULL;
+
+	return 0;
+}
+
+/*
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 80
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/space/bitmap.h newtree/fs/reiser4/plugin/space/bitmap.h
--- oldtree/fs/reiser4/plugin/space/bitmap.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/space/bitmap.h	2006-02-21 15:58:34.780859064 +0000
@@ -0,0 +1,47 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#if !defined (__REISER4_PLUGIN_SPACE_BITMAP_H__)
+#define __REISER4_PLUGIN_SPACE_BITMAP_H__
+
+#include "../../dformat.h"
+#include "../../block_alloc.h"
+
+#include <linux/types.h>	/* for __u??  */
+#include <linux/fs.h>		/* for struct super_block  */
+/* EDWARD-FIXME-HANS: write something as informative as the below for every .h file lacking it. */
+/* declarations of functions implementing methods of space allocator plugin for
+   bitmap based allocator. The functions themselves are in bitmap.c */
+extern int init_allocator_bitmap(reiser4_space_allocator *,
+				 struct super_block *, void *);
+extern int destroy_allocator_bitmap(reiser4_space_allocator *,
+				    struct super_block *);
+extern int alloc_blocks_bitmap(reiser4_space_allocator *,
+			       reiser4_blocknr_hint *, int needed,
+			       reiser4_block_nr * start,
+			       reiser4_block_nr * len);
+extern void check_blocks_bitmap(const reiser4_block_nr *,
+				const reiser4_block_nr *, int);
+
+extern void dealloc_blocks_bitmap(reiser4_space_allocator *, reiser4_block_nr,
+				  reiser4_block_nr);
+extern int pre_commit_hook_bitmap(void);
+
+#define post_commit_hook_bitmap() do{}while(0)
+#define post_write_back_hook_bitmap() do{}while(0)
+#define print_info_bitmap(pref, al) do{}while(0)
+
+typedef __u64 bmap_nr_t;
+typedef __u32 bmap_off_t;
+
+#endif				/* __REISER4_PLUGIN_SPACE_BITMAP_H__ */
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/space/space_allocator.h newtree/fs/reiser4/plugin/space/space_allocator.h
--- oldtree/fs/reiser4/plugin/space/space_allocator.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/space/space_allocator.h	2006-02-21 15:58:34.100962424 +0000
@@ -0,0 +1,80 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#ifndef __SPACE_ALLOCATOR_H__
+#define __SPACE_ALLOCATOR_H__
+
+#include "../../forward.h"
+#include "bitmap.h"
+/* NIKITA-FIXME-HANS: surely this could use a comment. Something about how bitmap is the only space allocator for now,
+ * but... */
+#define DEF_SPACE_ALLOCATOR(allocator)											\
+															\
+static inline int sa_init_allocator (reiser4_space_allocator * al, struct super_block *s, void * opaque)		\
+{															\
+	return init_allocator_##allocator (al, s, opaque);								\
+}															\
+															\
+static inline void sa_destroy_allocator (reiser4_space_allocator *al, struct super_block *s)				\
+{															\
+	destroy_allocator_##allocator (al, s);										\
+}															\
+															\
+static inline int sa_alloc_blocks (reiser4_space_allocator *al, reiser4_blocknr_hint * hint, 				\
+				   int needed, reiser4_block_nr * start, reiser4_block_nr * len)			\
+{															\
+	return alloc_blocks_##allocator (al, hint, needed, start, len);							\
+}															\
+static inline void sa_dealloc_blocks (reiser4_space_allocator * al, reiser4_block_nr start, reiser4_block_nr len)	\
+{															\
+	dealloc_blocks_##allocator (al, start, len); 									\
+}															\
+															\
+static inline void sa_check_blocks (const reiser4_block_nr * start, const reiser4_block_nr * end, int desired) 		\
+{															\
+	check_blocks_##allocator (start, end, desired);								        \
+}															\
+															\
+static inline void sa_pre_commit_hook (void)										\
+{ 															\
+	pre_commit_hook_##allocator ();											\
+}															\
+															\
+static inline void sa_post_commit_hook (void) 										\
+{ 															\
+	post_commit_hook_##allocator ();										\
+}															\
+															\
+static inline void sa_post_write_back_hook (void) 									\
+{ 															\
+	post_write_back_hook_##allocator();										\
+}															\
+															\
+static inline void sa_print_info(const char * prefix, reiser4_space_allocator * al)					\
+{															\
+	print_info_##allocator (prefix, al);                                                                            \
+}
+
+DEF_SPACE_ALLOCATOR(bitmap)
+
+/* this object is part of reiser4 private in-core super block */
+struct reiser4_space_allocator {
+	union {
+		/* space allocators might use this pointer to reference their
+		 * data. */
+		void *generic;
+	} u;
+};
+
+/* __SPACE_ALLOCATOR_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/plugin/tail_policy.c newtree/fs/reiser4/plugin/tail_policy.c
--- oldtree/fs/reiser4/plugin/tail_policy.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/plugin/tail_policy.c	2006-02-21 15:58:34.661877152 +0000
@@ -0,0 +1,113 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Formatting policy plugins */
+
+/*
+ * Formatting policy plugin is used by object plugin (of regular file) to
+ * convert file between two representations.
+ *
+ * Currently following policies are implemented:
+ *  never store file in formatted nodes
+ *  always store file in formatted nodes
+ *  store file in formatted nodes if file is smaller than 4 blocks (default)
+ */
+
+#include "../tree.h"
+#include "../inode.h"
+#include "../super.h"
+#include "object.h"
+#include "plugin.h"
+#include "node/node.h"
+#include "plugin_header.h"
+
+#include <linux/pagemap.h>
+#include <linux/fs.h>		/* For struct inode */
+
+/**
+ * have_formatting_never -
+ * @inode:
+ * @size:
+ *
+ *
+ */
+/* Never store file's tail as direct item */
+/* Audited by: green(2002.06.12) */
+static int have_formatting_never(const struct inode *inode UNUSED_ARG
+		      /* inode to operate on */ ,
+		      loff_t size UNUSED_ARG /* new object size */ )
+{
+	return 0;
+}
+
+/* Always store file's tail as direct item */
+/* Audited by: green(2002.06.12) */
+static int
+have_formatting_always(const struct inode *inode UNUSED_ARG
+		       /* inode to operate on */ ,
+		       loff_t size UNUSED_ARG /* new object size */ )
+{
+	return 1;
+}
+
+/* This function makes test if we should store file denoted @inode as tails only or
+   as extents only. */
+static int
+have_formatting_default(const struct inode *inode UNUSED_ARG
+			/* inode to operate on */ ,
+			loff_t size /* new object size */ )
+{
+	assert("umka-1253", inode != NULL);
+
+	if (size > inode->i_sb->s_blocksize * 4)
+		return 0;
+
+	return 1;
+}
+
+/* tail plugins */
+formatting_plugin formatting_plugins[LAST_TAIL_FORMATTING_ID] = {
+	[NEVER_TAILS_FORMATTING_ID] = {
+		.h = {
+			.type_id = REISER4_FORMATTING_PLUGIN_TYPE,
+			.id = NEVER_TAILS_FORMATTING_ID,
+			.pops = NULL,
+			.label = "never",
+			.desc = "Never store file's tail",
+			.linkage = {NULL, NULL}
+		},
+		.have_tail = have_formatting_never
+	},
+	[ALWAYS_TAILS_FORMATTING_ID] = {
+		.h = {
+			.type_id = REISER4_FORMATTING_PLUGIN_TYPE,
+			.id = ALWAYS_TAILS_FORMATTING_ID,
+			.pops = NULL,
+			.label = "always",
+			.desc =	"Always store file's tail",
+			.linkage = {NULL, NULL}
+		},
+		.have_tail = have_formatting_always
+	},
+	[SMALL_FILE_FORMATTING_ID] = {
+		.h = {
+			.type_id = REISER4_FORMATTING_PLUGIN_TYPE,
+			.id = SMALL_FILE_FORMATTING_ID,
+			.pops = NULL,
+			.label = "4blocks",
+			.desc = "store files shorter than 4 blocks in tail items",
+			.linkage = {NULL, NULL}
+		},
+		.have_tail = have_formatting_default
+	}
+};
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * End:
+ */
diff -urN oldtree/fs/reiser4/pool.c newtree/fs/reiser4/pool.c
--- oldtree/fs/reiser4/pool.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/pool.c	2006-02-21 15:58:34.662877000 +0000
@@ -0,0 +1,236 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Fast pool allocation.
+
+   There are situations when some sub-system normally asks memory allocator
+   for only few objects, but under some circumstances could require much
+   more. Typical and actually motivating example is tree balancing. It needs
+   to keep track of nodes that were involved into it, and it is well-known
+   that in reasonable packed balanced tree most (92.938121%) percent of all
+   balancings end up after working with only few nodes (3.141592 on
+   average). But in rare cases balancing can involve much more nodes
+   (3*tree_height+1 in extremal situation).
+
+   On the one hand, we don't want to resort to dynamic allocation (slab,
+    malloc(), etc.) to allocate data structures required to keep track of
+   nodes during balancing. On the other hand, we cannot statically allocate
+   required amount of space on the stack, because first: it is useless wastage
+   of precious resource, and second: this amount is unknown in advance (tree
+   height can change).
+
+   Pools, implemented in this file are solution for this problem:
+
+    - some configurable amount of objects is statically preallocated on the
+    stack
+
+    - if this preallocated pool is exhausted and more objects is requested
+    they are allocated dynamically.
+
+   Pools encapsulate distinction between statically and dynamically allocated
+   objects. Both allocation and recycling look exactly the same.
+
+   To keep track of dynamically allocated objects, pool adds its own linkage
+   to each object.
+
+   NOTE-NIKITA This linkage also contains some balancing-specific data. This
+   is not perfect. On the other hand, balancing is currently the only client
+   of pool code.
+
+   NOTE-NIKITA Another desirable feature is to rewrite all pool manipulation
+   functions in the style of tslist/tshash, i.e., make them unreadable, but
+   type-safe.
+
+
+*/
+
+#include "debug.h"
+#include "pool.h"
+#include "super.h"
+
+#include <linux/types.h>
+#include <linux/err.h>
+
+/* initialize new pool object */
+static void reiser4_init_pool_obj(reiser4_pool_header * h	/* pool object to
+								 * initialize */ )
+{
+	INIT_LIST_HEAD(&h->usage_linkage);
+	INIT_LIST_HEAD(&h->level_linkage);
+	INIT_LIST_HEAD(&h->extra_linkage);
+}
+
+/* initialize new pool */
+void reiser4_init_pool(reiser4_pool * pool /* pool to initialize */ ,
+		       size_t obj_size /* size of objects in @pool */ ,
+		       int num_of_objs /* number of preallocated objects */ ,
+		       char *data /* area for preallocated objects */ )
+{
+	reiser4_pool_header *h;
+	int i;
+
+	assert("nikita-955", pool != NULL);
+	assert("nikita-1044", obj_size > 0);
+	assert("nikita-956", num_of_objs >= 0);
+	assert("nikita-957", data != NULL);
+
+	memset(pool, 0, sizeof *pool);
+	pool->obj_size = obj_size;
+	pool->data = data;
+	INIT_LIST_HEAD(&pool->free);
+	INIT_LIST_HEAD(&pool->used);
+	INIT_LIST_HEAD(&pool->extra);
+	memset(data, 0, obj_size * num_of_objs);
+	for (i = 0; i < num_of_objs; ++i) {
+		h = (reiser4_pool_header *) (data + i * obj_size);
+		reiser4_init_pool_obj(h);
+		/* add pool header to the end of pool's free list */
+		list_add_tail(&h->usage_linkage, &pool->free);
+	}
+}
+
+/* release pool resources
+
+   Release all resources acquired by this pool, specifically, dynamically
+   allocated objects.
+
+*/
+void reiser4_done_pool(reiser4_pool * pool UNUSED_ARG /* pool to destroy */ )
+{
+}
+
+/* allocate carry object from pool
+
+   First, try to get preallocated object. If this fails, resort to dynamic
+   allocation.
+
+*/
+static void *reiser4_pool_alloc(reiser4_pool * pool	/* pool to allocate object
+							 * from */ )
+{
+	reiser4_pool_header *result;
+
+	assert("nikita-959", pool != NULL);
+
+	if (!list_empty(&pool->free)) {
+		struct list_head *linkage;
+
+		linkage = pool->free.next;
+		list_del(linkage);
+		INIT_LIST_HEAD(linkage);
+		result = list_entry(linkage, reiser4_pool_header, usage_linkage);
+		BUG_ON(!list_empty(&result->level_linkage) ||
+		       !list_empty(&result->extra_linkage));
+	} else {
+		/* pool is empty. Extra allocations don't deserve dedicated
+		   slab to be served from, as they are expected to be rare. */
+		result = kmalloc(pool->obj_size, GFP_KERNEL);
+		if (result != 0) {
+			reiser4_init_pool_obj(result);
+			list_add(&result->extra_linkage, &pool->extra);
+		} else
+			return ERR_PTR(RETERR(-ENOMEM));
+		BUG_ON(!list_empty(&result->usage_linkage) ||
+		       !list_empty(&result->level_linkage));
+	}
+	++pool->objs;
+	list_add(&result->usage_linkage, &pool->used);
+	memset(result + 1, 0, pool->obj_size - sizeof *result);
+	return result;
+}
+
+/* return object back to the pool */
+void reiser4_pool_free(reiser4_pool * pool, reiser4_pool_header * h	/* pool to return object back
+									 * into */ )
+{
+	assert("nikita-961", h != NULL);
+	assert("nikita-962", pool != NULL);
+
+	--pool->objs;
+	assert("nikita-963", pool->objs >= 0);
+
+	list_del_init(&h->usage_linkage);
+	list_del_init(&h->level_linkage);
+
+	if (list_empty(&h->extra_linkage))
+		/*
+		 * pool header is not an extra one. Push it onto free list
+		 * using usage_linkage
+		 */
+		list_add(&h->usage_linkage, &pool->free);
+	else {
+		/* remove pool header from pool's extra list and kfree it */
+		list_del(&h->extra_linkage);
+		kfree(h);
+	}
+}
+
+/* add new object to the carry level list
+
+   Carry level is FIFO most of the time, but not always. Complications arise
+   when make_space() function tries to go to the left neighbor and thus adds
+   carry node before existing nodes, and also, when updating delimiting keys
+   after moving data between two nodes, we want left node to be locked before
+   right node.
+
+   Latter case is confusing at the first glance. Problem is that COP_UPDATE
+   opration that updates delimiting keys is sometimes called with two nodes
+   (when data are moved between two nodes) and sometimes with only one node
+   (when leftmost item is deleted in a node). In any case operation is
+   supplied with at least node whose left delimiting key is to be updated
+   (that is "right" node).
+
+*/
+reiser4_pool_header *add_obj(reiser4_pool * pool	/* pool from which to
+							 * allocate new object */ ,
+			     struct list_head *list,	/* list where to add
+							 * object */
+			     pool_ordering order /* where to add */ ,
+			     reiser4_pool_header * reference	/* after (or
+								 * before) which
+								 * existing
+								 * object to
+								 * add */ )
+{
+	reiser4_pool_header *result;
+
+	assert("nikita-972", pool != NULL);
+
+	result = reiser4_pool_alloc(pool);
+	if (IS_ERR(result))
+		return result;
+
+	assert("nikita-973", result != NULL);
+
+	switch (order) {
+	case POOLO_BEFORE:
+		__list_add(&result->level_linkage,
+			   reference->level_linkage.prev,
+			   &reference->level_linkage);
+		break;
+	case POOLO_AFTER:
+		__list_add(&result->level_linkage,
+			   &reference->level_linkage,
+			   reference->level_linkage.next);
+		break;
+	case POOLO_LAST:
+		list_add_tail(&result->level_linkage, list);
+		break;
+	case POOLO_FIRST:
+		list_add(&result->level_linkage, list);
+		break;
+	default:
+		wrong_return_value("nikita-927", "order");
+	}
+	return result;
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/pool.h newtree/fs/reiser4/pool.h
--- oldtree/fs/reiser4/pool.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/pool.h	2006-02-21 15:58:34.662877000 +0000
@@ -0,0 +1,54 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Fast pool allocation */
+
+#ifndef __REISER4_POOL_H__
+#define __REISER4_POOL_H__
+
+#include <linux/types.h>
+
+typedef struct reiser4_pool {
+	size_t obj_size;
+	int objs;
+	char *data;
+	struct list_head free;
+	struct list_head used;
+	struct list_head extra;
+} reiser4_pool;
+
+typedef struct reiser4_pool_header {
+	/* object is either on free or "used" lists */
+	struct list_head usage_linkage;
+	struct list_head level_linkage;
+	struct list_head extra_linkage;
+} reiser4_pool_header;
+
+typedef enum {
+	POOLO_BEFORE,
+	POOLO_AFTER,
+	POOLO_LAST,
+	POOLO_FIRST
+} pool_ordering;
+
+/* pool manipulation functions */
+
+extern void reiser4_init_pool(reiser4_pool * pool, size_t obj_size,
+			      int num_of_objs, char *data);
+extern void reiser4_done_pool(reiser4_pool * pool);
+extern void reiser4_pool_free(reiser4_pool * pool, reiser4_pool_header * h);
+reiser4_pool_header *add_obj(reiser4_pool * pool, struct list_head * list,
+			     pool_ordering order,
+			     reiser4_pool_header * reference);
+
+/* __REISER4_POOL_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/readahead.c newtree/fs/reiser4/readahead.c
--- oldtree/fs/reiser4/readahead.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/readahead.c	2006-02-21 15:58:35.452756920 +0000
@@ -0,0 +1,144 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+#include "forward.h"
+#include "tree.h"
+#include "tree_walk.h"
+#include "super.h"
+#include "inode.h"
+#include "key.h"
+#include "znode.h"
+
+#include <linux/swap.h>		/* for totalram_pages */
+
+void init_ra_info(ra_info_t * rai)
+{
+	rai->key_to_stop = *min_key();
+}
+
+/* global formatted node readahead parameter. It can be set by mount option -o readahead:NUM:1 */
+static inline int ra_adjacent_only(int flags)
+{
+	return flags & RA_ADJACENT_ONLY;
+}
+
+/* this is used by formatted_readahead to decide whether read for right neighbor of node is to be issued. It returns 1
+   if right neighbor's first key is less or equal to readahead's stop key */
+static int should_readahead_neighbor(znode * node, ra_info_t * info)
+{
+	int result;
+
+	read_lock_dk(znode_get_tree(node));
+	result = keyle(znode_get_rd_key(node), &info->key_to_stop);
+	read_unlock_dk(znode_get_tree(node));
+	return result;
+}
+
+#define LOW_MEM_PERCENTAGE (5)
+
+static int low_on_memory(void)
+{
+	unsigned int freepages;
+
+	freepages = nr_free_pages();
+	return freepages < (totalram_pages * LOW_MEM_PERCENTAGE / 100);
+}
+
+/* start read for @node and for a few of its right neighbors */
+void formatted_readahead(znode * node, ra_info_t * info)
+{
+	ra_params_t *ra_params;
+	znode *cur;
+	int i;
+	int grn_flags;
+	lock_handle next_lh;
+
+	/* do nothing if node block number has not been assigned to node (which means it is still in cache). */
+	if (blocknr_is_fake(znode_get_block(node)))
+		return;
+
+	ra_params = get_current_super_ra_params();
+
+	if (znode_page(node) == NULL)
+		jstartio(ZJNODE(node));
+
+	if (znode_get_level(node) != LEAF_LEVEL)
+		return;
+
+	/* don't waste memory for read-ahead when low on memory */
+	if (low_on_memory())
+		return;
+
+	/* We can have locked nodes on upper tree levels, in this situation lock
+	   priorities do not help to resolve deadlocks, we have to use TRY_LOCK
+	   here. */
+	grn_flags = (GN_CAN_USE_UPPER_LEVELS | GN_TRY_LOCK);
+
+	i = 0;
+	cur = zref(node);
+	init_lh(&next_lh);
+	while (i < ra_params->max) {
+		const reiser4_block_nr *nextblk;
+
+		if (!should_readahead_neighbor(cur, info))
+			break;
+
+		if (reiser4_get_right_neighbor
+		    (&next_lh, cur, ZNODE_READ_LOCK, grn_flags))
+			break;
+
+		if (JF_ISSET(ZJNODE(next_lh.node), JNODE_EFLUSH)) {
+			/* emergency flushed znode is encountered. That means we are low on memory. Do not readahead
+			   then */
+			break;
+		}
+
+		nextblk = znode_get_block(next_lh.node);
+		if (blocknr_is_fake(nextblk) ||
+		    (ra_adjacent_only(ra_params->flags)
+		     && *nextblk != *znode_get_block(cur) + 1)) {
+			break;
+		}
+
+		zput(cur);
+		cur = zref(next_lh.node);
+		done_lh(&next_lh);
+		if (znode_page(cur) == NULL)
+			jstartio(ZJNODE(cur));
+		else
+			/* Do not scan read-ahead window if pages already
+			 * allocated (and i/o already started). */
+			break;
+
+		i++;
+	}
+	zput(cur);
+	done_lh(&next_lh);
+}
+
+void reiser4_readdir_readahead_init(struct inode *dir, tap_t * tap)
+{
+	reiser4_key *stop_key;
+
+	assert("nikita-3542", dir != NULL);
+	assert("nikita-3543", tap != NULL);
+
+	stop_key = &tap->ra_info.key_to_stop;
+	/* initialize readdir readahead information: include into readahead
+	 * stat data of all files of the directory */
+	set_key_locality(stop_key, get_inode_oid(dir));
+	set_key_type(stop_key, KEY_SD_MINOR);
+	set_key_ordering(stop_key, get_key_ordering(max_key()));
+	set_key_objectid(stop_key, get_key_objectid(max_key()));
+	set_key_offset(stop_key, get_key_offset(max_key()));
+}
+
+/*
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 80
+   End:
+*/
diff -urN oldtree/fs/reiser4/readahead.h newtree/fs/reiser4/readahead.h
--- oldtree/fs/reiser4/readahead.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/readahead.h	2006-02-21 15:58:35.407763760 +0000
@@ -0,0 +1,48 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#ifndef __READAHEAD_H__
+#define __READAHEAD_H__
+
+#include "key.h"
+
+typedef enum {
+	RA_ADJACENT_ONLY = 1,	/* only requests nodes which are adjacent. Default is NO (not only adjacent) */
+} ra_global_flags;
+
+/* reiser4 super block has a field of this type. It controls readahead during tree traversals */
+typedef struct formatted_read_ahead_params {
+	unsigned long max;	/* request not more than this amount of nodes. Default is totalram_pages / 4 */
+	int flags;
+} ra_params_t;
+
+typedef struct {
+	reiser4_key key_to_stop;
+} ra_info_t;
+
+void formatted_readahead(znode *, ra_info_t *);
+void init_ra_info(ra_info_t * rai);
+
+struct reiser4_file_ra_state {
+	loff_t start;		/* Current window */
+	loff_t size;
+	loff_t next_size;	/* Next window size */
+	loff_t ahead_start;	/* Ahead window */
+	loff_t ahead_size;
+	loff_t max_window_size;	/* Maximum readahead window */
+	loff_t slow_start;	/* enlarging r/a size algorithm. */
+};
+
+extern void reiser4_readdir_readahead_init(struct inode *dir, tap_t * tap);
+
+/* __READAHEAD_H__ */
+#endif
+
+/*
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/reiser4.h newtree/fs/reiser4/reiser4.h
--- oldtree/fs/reiser4/reiser4.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/reiser4.h	2006-02-21 15:58:35.015823344 +0000
@@ -0,0 +1,289 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* definitions of common constants used by reiser4 */
+
+#if !defined( __REISER4_H__ )
+#define __REISER4_H__
+
+#include <linux/config.h>
+#include <asm/param.h>		/* for HZ */
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <asm/hardirq.h>
+#include <linux/sched.h>
+
+/*
+ * reiser4 compilation options.
+ */
+
+#if defined(CONFIG_REISER4_DEBUG)
+/* turn on assertion checks */
+#define REISER4_DEBUG (1)
+#else
+#define REISER4_DEBUG (0)
+#endif
+
+#if defined(CONFIG_ZLIB_INFLATE)
+/* turn on zlib */
+#define REISER4_ZLIB (1)
+#else
+#define REISER4_ZLIB (0)
+#endif
+
+#if defined(CONFIG_CRYPTO_SHA256)
+#define REISER4_SHA256 (1)
+#else
+#define REISER4_SHA256 (0)
+#endif
+
+#if defined(CONFIG_CRYPTO_AES_586)
+#define REISER4_AES (1)
+#else
+#define REISER4_AES (0)
+#endif
+
+#if defined(CONFIG_REISER4_COPY_ON_CAPTURE)
+/*
+ * Turns on copy-on-capture (COC) optimization. See
+ * http://www.namesys.com/v4/v4.html#cp_on_capture
+ */
+#define REISER4_COPY_ON_CAPTURE (1)
+#else
+#define REISER4_COPY_ON_CAPTURE (0)
+#endif
+
+/*
+ * Turn on large keys mode. In his mode (which is default), reiser4 key has 4
+ * 8-byte components. In the old "small key" mode, it's 3 8-byte
+ * components. Additional component, referred to as "ordering" is used to
+ * order items from which given object is composed of. As such, ordering is
+ * placed between locality and objectid. For directory item ordering contains
+ * initial prefix of the file name this item is for. This sorts all directory
+ * items within given directory lexicographically (but see
+ * fibration.[ch]). For file body and stat-data, ordering contains initial
+ * prefix of the name file was initially created with. In the common case
+ * (files with single name) this allows to order file bodies and stat-datas in
+ * the same order as their respective directory entries, thus speeding up
+ * readdir.
+ *
+ * Note, that kernel can only mount file system with the same key size as one
+ * it is compiled for, so flipping this option may render your data
+ * inaccessible.
+ */
+#define REISER4_LARGE_KEY (1)
+/*#define REISER4_LARGE_KEY (0)*/
+
+/*#define GUESS_EXISTS 1*/
+
+/*
+ * PLEASE update fs/reiser4/kattr.c:show_options() when adding new compilation
+ * option
+ */
+
+extern const char *REISER4_SUPER_MAGIC_STRING;
+extern const int REISER4_MAGIC_OFFSET;	/* offset to magic string from the
+					 * beginning of device */
+
+/* here go tunable parameters that are not worth special entry in kernel
+   configuration */
+
+/* default number of slots in coord-by-key caches */
+#define CBK_CACHE_SLOTS    (16)
+/* how many elementary tree operation to carry on the next level */
+#define CARRIES_POOL_SIZE        (5)
+/* size of pool of preallocated nodes for carry process. */
+#define NODES_LOCKED_POOL_SIZE   (5)
+
+#define REISER4_NEW_NODE_FLAGS (COPI_LOAD_LEFT | COPI_LOAD_RIGHT | COPI_GO_LEFT)
+#define REISER4_NEW_EXTENT_FLAGS (COPI_LOAD_LEFT | COPI_LOAD_RIGHT | COPI_GO_LEFT)
+#define REISER4_PASTE_FLAGS (COPI_GO_LEFT)
+#define REISER4_INSERT_FLAGS (COPI_GO_LEFT)
+
+/* we are supporting reservation of disk space on uid basis */
+#define REISER4_SUPPORT_UID_SPACE_RESERVATION (0)
+/* we are supporting reservation of disk space for groups */
+#define REISER4_SUPPORT_GID_SPACE_RESERVATION (0)
+/* we are supporting reservation of disk space for root */
+#define REISER4_SUPPORT_ROOT_SPACE_RESERVATION (0)
+/* we use rapid flush mode, see flush.c for comments.  */
+#define REISER4_USE_RAPID_FLUSH (1)
+
+/*
+ * set this to 0 if you don't want to use wait-for-flush in ->writepage().
+ */
+#define REISER4_USE_ENTD (1)
+
+/* Using of emergency flush is an option. */
+#define REISER4_USE_EFLUSH (1)
+
+/* key allocation is Plan-A */
+#define REISER4_PLANA_KEY_ALLOCATION (1)
+/* key allocation follows good old 3.x scheme */
+#define REISER4_3_5_KEY_ALLOCATION (0)
+
+/* size of hash-table for znodes */
+#define REISER4_ZNODE_HASH_TABLE_SIZE (1 << 13)
+
+/* number of buckets in lnode hash-table */
+#define LNODE_HTABLE_BUCKETS (1024)
+
+/* some ridiculously high maximal limit on height of znode tree. This
+    is used in declaration of various per level arrays and
+    to allocate stattistics gathering array for per-level stats. */
+#define REISER4_MAX_ZTREE_HEIGHT     (8)
+
+#define REISER4_PANIC_MSG_BUFFER_SIZE (1024)
+
+/* If array contains less than REISER4_SEQ_SEARCH_BREAK elements then,
+   sequential search is on average faster than binary. This is because
+   of better optimization and because sequential search is more CPU
+   cache friendly. This number (25) was found by experiments on dual AMD
+   Athlon(tm), 1400MHz.
+
+   NOTE: testing in kernel has shown that binary search is more effective than
+   implied by results of the user level benchmarking. Probably because in the
+   node keys are separated by other data. So value was adjusted after few
+   tests. More thorough tuning is needed.
+*/
+#define REISER4_SEQ_SEARCH_BREAK      (3)
+
+/* don't allow tree to be lower than this */
+#define REISER4_MIN_TREE_HEIGHT       (TWIG_LEVEL)
+
+/* NOTE NIKITA this is no longer used: maximal atom size is auto-adjusted to
+ * available memory. */
+/* Default value of maximal atom size. Can be ovewritten by
+   tmgr.atom_max_size mount option. By default infinity. */
+#define REISER4_ATOM_MAX_SIZE         ((unsigned)(~0))
+
+/* Default value of maximal atom age (in jiffies). After reaching this age
+   atom will be forced to commit, either synchronously or asynchronously. Can
+   be overwritten by tmgr.atom_max_age mount option. */
+#define REISER4_ATOM_MAX_AGE          (600 * HZ)
+
+/* sleeping period for ktxnmrgd */
+#define REISER4_TXNMGR_TIMEOUT  (5 * HZ)
+
+/* timeout to wait for ent thread in writepage. Default: 3 milliseconds. */
+#define REISER4_ENTD_TIMEOUT (3 * HZ / 1000)
+
+/* start complaining after that many restarts in coord_by_key().
+
+   This either means incredibly heavy contention for this part of a tree, or
+   some corruption or bug.
+*/
+#define REISER4_CBK_ITERATIONS_LIMIT  (100)
+
+/* return -EIO after that many iterations in coord_by_key().
+
+   I have witnessed more than 800 iterations (in 30 thread test) before cbk
+   finished. --nikita
+*/
+#define REISER4_MAX_CBK_ITERATIONS    500000
+
+/* put a per-inode limit on maximal number of directory entries with identical
+   keys in hashed directory.
+
+   Disable this until inheritance interfaces stabilize: we need some way to
+   set per directory limit.
+*/
+#define REISER4_USE_COLLISION_LIMIT    (0)
+
+/* If flush finds more than FLUSH_RELOCATE_THRESHOLD adjacent dirty leaf-level blocks it
+   will force them to be relocated. */
+#define FLUSH_RELOCATE_THRESHOLD 64
+/* If flush finds can find a block allocation closer than at most FLUSH_RELOCATE_DISTANCE
+   from the preceder it will relocate to that position. */
+#define FLUSH_RELOCATE_DISTANCE  64
+
+/* If we have written this much or more blocks before encountering busy jnode
+   in flush list - abort flushing hoping that next time we get called
+   this jnode will be clean already, and we will save some seeks. */
+#define FLUSH_WRITTEN_THRESHOLD 50
+
+/* The maximum number of nodes to scan left on a level during flush. */
+#define FLUSH_SCAN_MAXNODES 10000
+
+/* per-atom limit of flushers */
+#define ATOM_MAX_FLUSHERS (1)
+
+/* default tracing buffer size */
+#define REISER4_TRACE_BUF_SIZE (1 << 15)
+
+/* what size units of IO we would like cp, etc., to use, in writing to
+   reiser4. In bytes.
+
+   Can be overwritten by optimal_io_size mount option.
+*/
+#define REISER4_OPTIMAL_IO_SIZE (64 * 1024)
+
+/* see comments in inode.c:oid_to_uino() */
+#define REISER4_UINO_SHIFT (1 << 30)
+
+/* Mark function argument as unused to avoid compiler warnings. */
+#define UNUSED_ARG __attribute__((unused))
+
+#if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)
+#define NONNULL __attribute__((nonnull))
+#else
+#define NONNULL
+#endif
+
+/* master super block offset in bytes.*/
+#define REISER4_MASTER_OFFSET 65536
+
+/* size of VFS block */
+#define VFS_BLKSIZE 512
+/* number of bits in size of VFS block (512==2^9) */
+#define VFS_BLKSIZE_BITS 9
+
+#define REISER4_I reiser4_inode_data
+
+/* implication */
+#define ergo( antecedent, consequent ) ( !( antecedent ) || ( consequent ) )
+/* logical equivalence */
+#define equi( p1, p2 ) ( ergo( ( p1 ), ( p2 ) ) && ergo( ( p2 ), ( p1 ) ) )
+
+#define sizeof_array(x) ((int) (sizeof(x) / sizeof(x[0])))
+
+#define NOT_YET                       (0)
+
+/** Reiser4 specific error codes **/
+
+#define REISER4_ERROR_CODE_BASE 500
+
+/* Neighbor is not available (side neighbor or parent) */
+#define E_NO_NEIGHBOR  (REISER4_ERROR_CODE_BASE)
+
+/* Node was not found in cache */
+#define E_NOT_IN_CACHE (REISER4_ERROR_CODE_BASE + 1)
+
+/* node has no free space enough for completion of balancing operation */
+#define E_NODE_FULL    (REISER4_ERROR_CODE_BASE + 2)
+
+/* repeat operation */
+#define E_REPEAT       (REISER4_ERROR_CODE_BASE + 3)
+
+/* deadlock happens */
+#define E_DEADLOCK     (REISER4_ERROR_CODE_BASE + 4)
+
+/* operation cannot be performed, because it would block and non-blocking mode
+ * was requested. */
+#define E_BLOCK        (REISER4_ERROR_CODE_BASE + 5)
+
+/* wait some event (depends on context), then repeat */
+#define E_WAIT         (REISER4_ERROR_CODE_BASE + 6)
+
+#endif				/* __REISER4_H__ */
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/safe_link.c newtree/fs/reiser4/safe_link.c
--- oldtree/fs/reiser4/safe_link.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/safe_link.c	2006-02-21 15:58:34.861846752 +0000
@@ -0,0 +1,351 @@
+/* Copyright 2003, 2004 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Safe-links. */
+
+/*
+ * Safe-links are used to maintain file system consistency during operations
+ * that spawns multiple transactions. For example:
+ *
+ *     1. Unlink. UNIX supports "open-but-unlinked" files, that is files
+ *     without user-visible names in the file system, but still opened by some
+ *     active process. What happens here is that unlink proper (i.e., removal
+ *     of the last file name) and file deletion (truncate of file body to zero
+ *     and deletion of stat-data, that happens when last file descriptor is
+ *     closed), may belong to different transactions T1 and T2. If a crash
+ *     happens after T1 commit, but before T2 commit, on-disk file system has
+ *     a file without name, that is, disk space leak.
+ *
+ *     2. Truncate. Truncate of large file may spawn multiple transactions. If
+ *     system crashes while truncate was in-progress, file is left partially
+ *     truncated, which violates "atomicity guarantees" of reiser4, viz. that
+ *     every system is atomic.
+ *
+ * Safe-links address both above cases. Basically, safe-link is a way post
+ * some operation to be executed during commit of some other transaction than
+ * current one. (Another way to look at the safe-link is to interpret it as a
+ * logical logging.)
+ *
+ * Specifically, at the beginning of unlink safe-link in inserted in the
+ * tree. This safe-link is normally removed by file deletion code (during
+ * transaction T2 in the above terms). Truncate also inserts safe-link that is
+ * normally removed when truncate operation is finished.
+ *
+ * This means, that in the case of "clean umount" there are no safe-links in
+ * the tree. If safe-links are observed during mount, it means that (a) system
+ * was terminated abnormally, and (b) safe-link correspond to the "pending"
+ * (i.e., not finished) operations that were in-progress during system
+ * termination. Each safe-link record enough information to complete
+ * corresponding operation, and mount simply "replays" them (hence, the
+ * analogy with the logical logging).
+ *
+ * Safe-links are implemented as blackbox items (see
+ * plugin/item/blackbox.[ch]).
+ *
+ * For the reference: ext3 also has similar mechanism, it's called "an orphan
+ * list" there.
+ */
+
+#include "safe_link.h"
+#include "debug.h"
+#include "inode.h"
+
+#include "plugin/item/blackbox.h"
+
+#include <linux/fs.h>
+
+/*
+ * On-disk format of safe-link.
+ */
+typedef struct safelink {
+	reiser4_key sdkey;	/* key of stat-data for the file safe-link is
+				 * for */
+	d64 size;		/* size to which file should be truncated */
+} safelink_t;
+
+/*
+ * locality where safe-link items are stored. Next to the objectid of root
+ * directory.
+ */
+static oid_t safe_link_locality(reiser4_tree * tree)
+{
+	return get_key_objectid(get_super_private(tree->super)->df_plug->
+				root_dir_key(tree->super)) + 1;
+}
+
+/*
+  Construct a key for the safe-link. Key has the following format:
+
+|        60     | 4 |        64        | 4 |      60       |         64       |
++---------------+---+------------------+---+---------------+------------------+
+|   locality    | 0 |        0         | 0 |   objectid    |     link type    |
++---------------+---+------------------+---+---------------+------------------+
+|                   |                  |                   |                  |
+|     8 bytes       |     8 bytes      |      8 bytes      |      8 bytes     |
+
+   This is in large keys format. In small keys format second 8 byte chunk is
+   out. Locality is a constant returned by safe_link_locality(). objectid is
+   an oid of a file on which operation protected by this safe-link is
+   performed. link-type is used to distinguish safe-links for different
+   operations.
+
+ */
+static reiser4_key *build_link_key(reiser4_tree * tree, oid_t oid,
+				   reiser4_safe_link_t link, reiser4_key * key)
+{
+	reiser4_key_init(key);
+	set_key_locality(key, safe_link_locality(tree));
+	set_key_objectid(key, oid);
+	set_key_offset(key, link);
+	return key;
+}
+
+/*
+ * how much disk space is necessary to insert and remove (in the
+ * error-handling path) safe-link.
+ */
+static __u64 safe_link_tograb(reiser4_tree * tree)
+{
+	return
+	    /* insert safe link */
+	    estimate_one_insert_item(tree) +
+	    /* remove safe link */
+	    estimate_one_item_removal(tree) +
+	    /* drill to the leaf level during insertion */
+	    1 + estimate_one_insert_item(tree) +
+	    /*
+	     * possible update of existing safe-link. Actually, if
+	     * safe-link existed already (we failed to remove it), then no
+	     * insertion is necessary, so this term is already "covered",
+	     * but for simplicity let's left it.
+	     */
+	    1;
+}
+
+/*
+ * grab enough disk space to insert and remove (in the error-handling path)
+ * safe-link.
+ */
+int safe_link_grab(reiser4_tree * tree, reiser4_ba_flags_t flags)
+{
+	int result;
+
+	grab_space_enable();
+	/* The sbinfo->delete semaphore can be taken here.
+	 * safe_link_release() should be called before leaving reiser4
+	 * context. */
+	result =
+	    reiser4_grab_reserved(tree->super, safe_link_tograb(tree), flags);
+	grab_space_enable();
+	return result;
+}
+
+/*
+ * release unused disk space reserved by safe_link_grab().
+ */
+void safe_link_release(reiser4_tree * tree)
+{
+	reiser4_release_reserved(tree->super);
+}
+
+/*
+ * insert into tree safe-link for operation @link on inode @inode.
+ */
+int safe_link_add(struct inode *inode, reiser4_safe_link_t link)
+{
+	reiser4_key key;
+	safelink_t sl;
+	int length;
+	int result;
+	reiser4_tree *tree;
+
+	build_sd_key(inode, &sl.sdkey);
+	length = sizeof sl.sdkey;
+
+	if (link == SAFE_TRUNCATE) {
+		/*
+		 * for truncate we have to store final file length also,
+		 * expand item.
+		 */
+		length += sizeof(sl.size);
+		put_unaligned(cpu_to_le64(inode->i_size), &sl.size);
+	}
+	tree = tree_by_inode(inode);
+	build_link_key(tree, get_inode_oid(inode), link, &key);
+
+	result = store_black_box(tree, &key, &sl, length);
+	if (result == -EEXIST)
+		result = update_black_box(tree, &key, &sl, length);
+	return result;
+}
+
+/*
+ * remove safe-link corresponding to the operation @link on inode @inode from
+ * the tree.
+ */
+int safe_link_del(reiser4_tree * tree, oid_t oid, reiser4_safe_link_t link)
+{
+	reiser4_key key;
+
+	return kill_black_box(tree, build_link_key(tree, oid, link, &key));
+}
+
+/*
+ * in-memory structure to keep information extracted from safe-link. This is
+ * used to iterate over all safe-links.
+ */
+typedef struct {
+	reiser4_tree *tree;	/* internal tree */
+	reiser4_key key;	/* safe-link key */
+	reiser4_key sdkey;	/* key of object stat-data */
+	reiser4_safe_link_t link;	/* safe-link type */
+	oid_t oid;		/* object oid */
+	__u64 size;		/* final size for truncate */
+} safe_link_context;
+
+/*
+ * start iterating over all safe-links.
+ */
+static void safe_link_iter_begin(reiser4_tree * tree, safe_link_context * ctx)
+{
+	ctx->tree = tree;
+	reiser4_key_init(&ctx->key);
+	set_key_locality(&ctx->key, safe_link_locality(tree));
+	set_key_objectid(&ctx->key, get_key_objectid(max_key()));
+	set_key_offset(&ctx->key, get_key_offset(max_key()));
+}
+
+/*
+ * return next safe-link.
+ */
+static int safe_link_iter_next(safe_link_context * ctx)
+{
+	int result;
+	safelink_t sl;
+
+	result = load_black_box(ctx->tree, &ctx->key, &sl, sizeof sl, 0);
+	if (result == 0) {
+		ctx->oid = get_key_objectid(&ctx->key);
+		ctx->link = get_key_offset(&ctx->key);
+		ctx->sdkey = sl.sdkey;
+		if (ctx->link == SAFE_TRUNCATE)
+			ctx->size = le64_to_cpu(get_unaligned(&sl.size));
+	}
+	return result;
+}
+
+/*
+ * check are there any more safe-links left in the tree.
+ */
+static int safe_link_iter_finished(safe_link_context * ctx)
+{
+	return get_key_locality(&ctx->key) != safe_link_locality(ctx->tree);
+}
+
+/*
+ * finish safe-link iteration.
+ */
+static void safe_link_iter_end(safe_link_context * ctx)
+{
+	/* nothing special */
+}
+
+/*
+ * process single safe-link.
+ */
+static int process_safelink(struct super_block *super, reiser4_safe_link_t link,
+			    reiser4_key * sdkey, oid_t oid, __u64 size)
+{
+	struct inode *inode;
+	int result;
+
+	/*
+	 * obtain object inode by reiser4_iget(), then call object plugin
+	 * ->safelink() method to do actual work, then delete safe-link on
+	 * success.
+	 */
+	inode = reiser4_iget(super, sdkey, 1);
+	if (!IS_ERR(inode)) {
+		file_plugin *fplug;
+
+		fplug = inode_file_plugin(inode);
+		assert("nikita-3428", fplug != NULL);
+		assert("", oid == get_inode_oid(inode));
+		if (fplug->safelink != NULL) {
+			/* txn_restart_current is not necessary because
+			 * mounting is signle thread. However, without it
+			 * deadlock detection code will complain (see
+			 * nikita-3361). */
+			txn_restart_current();
+			result = fplug->safelink(inode, link, size);
+		} else {
+			warning("nikita-3430",
+				"Cannot handle safelink for %lli",
+				(unsigned long long)oid);
+			print_key("key", sdkey);
+			result = 0;
+		}
+		if (result != 0) {
+			warning("nikita-3431",
+				"Error processing safelink for %lli: %i",
+				(unsigned long long)oid, result);
+		}
+		reiser4_iget_complete(inode);
+		iput(inode);
+		if (result == 0) {
+			result = safe_link_grab(get_tree(super), BA_CAN_COMMIT);
+			if (result == 0)
+				result =
+				    safe_link_del(get_tree(super), oid, link);
+			safe_link_release(get_tree(super));
+			/*
+			 * restart transaction: if there was large number of
+			 * safe-links, their processing may fail to fit into
+			 * single transaction.
+			 */
+			if (result == 0)
+				txn_restart_current();
+		}
+	} else
+		result = PTR_ERR(inode);
+	return result;
+}
+
+/*
+ * iterate over all safe-links in the file-system processing them one by one.
+ */
+int process_safelinks(struct super_block *super)
+{
+	safe_link_context ctx;
+	int result;
+
+	if (rofs_super(super))
+		/* do nothing on the read-only file system */
+		return 0;
+	safe_link_iter_begin(&get_super_private(super)->tree, &ctx);
+	result = 0;
+	do {
+		result = safe_link_iter_next(&ctx);
+		if (safe_link_iter_finished(&ctx) || result == -ENOENT) {
+			result = 0;
+			break;
+		}
+		if (result == 0)
+			result = process_safelink(super, ctx.link,
+						  &ctx.sdkey, ctx.oid,
+						  ctx.size);
+	} while (result == 0);
+	safe_link_iter_end(&ctx);
+	return result;
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/safe_link.h newtree/fs/reiser4/safe_link.h
--- oldtree/fs/reiser4/safe_link.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/safe_link.h	2006-02-21 15:58:34.665876544 +0000
@@ -0,0 +1,29 @@
+/* Copyright 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Safe-links. See safe_link.c for details. */
+
+#if !defined( __FS_SAFE_LINK_H__ )
+#define __FS_SAFE_LINK_H__
+
+#include "tree.h"
+
+int safe_link_grab(reiser4_tree * tree, reiser4_ba_flags_t flags);
+void safe_link_release(reiser4_tree * tree);
+int safe_link_add(struct inode *inode, reiser4_safe_link_t link);
+int safe_link_del(reiser4_tree *, oid_t oid, reiser4_safe_link_t link);
+
+int process_safelinks(struct super_block *super);
+
+/* __FS_SAFE_LINK_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/seal.c newtree/fs/reiser4/seal.c
--- oldtree/fs/reiser4/seal.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/seal.c	2006-02-21 15:58:35.016823192 +0000
@@ -0,0 +1,217 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+/* Seals implementation. */
+/* Seals are "weak" tree pointers. They are analogous to tree coords in
+   allowing to bypass tree traversal. But normal usage of coords implies that
+   node pointed to by coord is locked, whereas seals don't keep a lock (or
+   even a reference) to znode. In stead, each znode contains a version number,
+   increased on each znode modification. This version number is copied into a
+   seal when seal is created. Later, one can "validate" seal by calling
+   seal_validate(). If znode is in cache and its version number is still the
+   same, seal is "pristine" and coord associated with it can be re-used
+   immediately.
+
+   If, on the other hand, znode is out of cache, or it is obviously different
+   one from the znode seal was initially attached to (for example, it is on
+   the different level, or is being removed from the tree), seal is
+   irreparably invalid ("burned") and tree traversal has to be repeated.
+
+   Otherwise, there is some hope, that while znode was modified (and seal was
+   "broken" as a result), key attached to the seal is still in the node. This
+   is checked by first comparing this key with delimiting keys of node and, if
+   key is ok, doing intra-node lookup.
+
+   Znode version is maintained in the following way:
+
+   there is reiser4_tree.znode_epoch counter. Whenever new znode is created,
+   znode_epoch is incremented and its new value is stored in ->version field
+   of new znode. Whenever znode is dirtied (which means it was probably
+   modified), znode_epoch is also incremented and its new value is stored in
+   znode->version. This is done so, because just incrementing znode->version
+   on each update is not enough: it may so happen, that znode get deleted, new
+   znode is allocated for the same disk block and gets the same version
+   counter, tricking seal code into false positive.
+*/
+
+#include "forward.h"
+#include "debug.h"
+#include "key.h"
+#include "coord.h"
+#include "seal.h"
+#include "plugin/item/item.h"
+#include "plugin/node/node.h"
+#include "jnode.h"
+#include "znode.h"
+#include "super.h"
+
+static znode *seal_node(const seal_t * seal);
+static int seal_matches(const seal_t * seal, znode * node);
+
+/* initialise seal. This can be called several times on the same seal. @coord
+   and @key can be NULL.  */
+void seal_init(seal_t * seal /* seal to initialise */ ,
+	       const coord_t * coord /* coord @seal will be attached to */ ,
+	       const reiser4_key * key UNUSED_ARG	/* key @seal will be
+							 * attached to */ )
+{
+	assert("nikita-1886", seal != NULL);
+	memset(seal, 0, sizeof *seal);
+	if (coord != NULL) {
+		znode *node;
+
+		node = coord->node;
+		assert("nikita-1987", node != NULL);
+		spin_lock_znode(node);
+		seal->version = node->version;
+		assert("nikita-1988", seal->version != 0);
+		seal->block = *znode_get_block(node);
+#if REISER4_DEBUG
+		seal->coord1 = *coord;
+		if (key != NULL)
+			seal->key = *key;
+#endif
+		spin_unlock_znode(node);
+	}
+}
+
+/* finish with seal */
+void seal_done(seal_t * seal /* seal to clear */ )
+{
+	assert("nikita-1887", seal != NULL);
+	seal->version = 0;
+}
+
+/* true if seal was initialised */
+int seal_is_set(const seal_t * seal /* seal to query */ )
+{
+	assert("nikita-1890", seal != NULL);
+	return seal->version != 0;
+}
+
+#if REISER4_DEBUG
+/* helper function for seal_validate(). It checks that item at @coord has
+ * expected key. This is to detect cases where node was modified but wasn't
+ * marked dirty. */
+static inline int check_seal_match(const coord_t * coord /* coord to check */ ,
+				   const reiser4_key * k /* expected key */ )
+{
+	reiser4_key ukey;
+
+	return (coord->between != AT_UNIT) ||
+	    /* FIXME-VS: we only can compare keys for items whose units
+	       represent exactly one key */
+	    ((coord_is_existing_unit(coord))
+	     && (item_is_extent(coord)
+		 || keyeq(k, unit_key_by_coord(coord, &ukey))))
+	    || ((coord_is_existing_unit(coord)) && (item_is_ctail(coord))
+		&& keyge(k, unit_key_by_coord(coord, &ukey)));
+}
+#endif
+
+/* this is used by seal_validate. It accepts return value of
+ * longterm_lock_znode and returns 1 if it can be interpreted as seal
+ * validation failure. For instance, when longterm_lock_znode returns -EINVAL,
+ * seal_validate returns -E_REPEAT and caller will call tre search. We cannot
+ * do this in longterm_lock_znode(), because sometimes we want to distinguish
+ * between -EINVAL and -E_REPEAT. */
+static int should_repeat(int return_code)
+{
+	return return_code == -EINVAL;
+}
+
+/* (re-)validate seal.
+
+   Checks whether seal is pristine, and try to revalidate it if possible.
+
+   If seal was burned, or broken irreparably, return -E_REPEAT.
+
+   NOTE-NIKITA currently seal_validate() returns -E_REPEAT if key we are
+   looking for is in range of keys covered by the sealed node, but item wasn't
+   found by node ->lookup() method. Alternative is to return -ENOENT in this
+   case, but this would complicate callers logic.
+
+*/
+int seal_validate(seal_t * seal /* seal to validate */ ,
+		  coord_t * coord /* coord to validate against */ ,
+		  const reiser4_key * key /* key to validate against */ ,
+		  lock_handle * lh /* resulting lock handle */ ,
+		  znode_lock_mode mode /* lock node */ ,
+		  znode_lock_request request /* locking priority */ )
+{
+	znode *node;
+	int result;
+
+	assert("nikita-1889", seal != NULL);
+	assert("nikita-1881", seal_is_set(seal));
+	assert("nikita-1882", key != NULL);
+	assert("nikita-1883", coord != NULL);
+	assert("nikita-1884", lh != NULL);
+	assert("nikita-1885", keyeq(&seal->key, key));
+	assert("nikita-1989", coords_equal(&seal->coord1, coord));
+
+	/* obtain znode by block number */
+	node = seal_node(seal);
+	if (node != NULL) {
+		/* znode was in cache, lock it */
+		result = longterm_lock_znode(lh, node, mode, request);
+		zput(node);
+		if (result == 0) {
+			if (seal_matches(seal, node)) {
+				/* if seal version and znode version
+				   coincide */
+				ON_DEBUG(coord_update_v(coord));
+				assert("nikita-1990",
+				       node == seal->coord1.node);
+				assert("nikita-1898",
+				       WITH_DATA_RET(coord->node, 1,
+						     check_seal_match(coord,
+								      key)));
+			} else
+				result = RETERR(-E_REPEAT);
+		}
+		if (result != 0) {
+			if (should_repeat(result))
+				result = RETERR(-E_REPEAT);
+			/* unlock node on failure */
+			done_lh(lh);
+		}
+	} else {
+		/* znode wasn't in cache */
+		result = RETERR(-E_REPEAT);
+	}
+	return result;
+}
+
+/* helpers functions */
+
+/* obtain reference to znode seal points to, if in cache */
+static znode *seal_node(const seal_t * seal /* seal to query */ )
+{
+	assert("nikita-1891", seal != NULL);
+	return zlook(current_tree, &seal->block);
+}
+
+/* true if @seal version and @node version coincide */
+static int seal_matches(const seal_t * seal /* seal to check */ ,
+			znode * node /* node to check */ )
+{
+	int result;
+
+	assert("nikita-1991", seal != NULL);
+	assert("nikita-1993", node != NULL);
+
+	spin_lock_znode(node);
+	result = (seal->version == node->version);
+	spin_unlock_znode(node);
+	return result;
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/seal.h newtree/fs/reiser4/seal.h
--- oldtree/fs/reiser4/seal.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/seal.h	2006-02-21 15:58:34.665876544 +0000
@@ -0,0 +1,49 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Declaration of seals: "weak" tree pointers. See seal.c for comments. */
+
+#ifndef __SEAL_H__
+#define __SEAL_H__
+
+#include "forward.h"
+#include "debug.h"
+#include "dformat.h"
+#include "key.h"
+#include "coord.h"
+
+/* for __u?? types */
+/*#include <linux/types.h>*/
+
+/* seal. See comment at the top of seal.c */
+typedef struct seal_s {
+	/* version of znode recorder at the time of seal creation */
+	__u64 version;
+	/* block number of znode attached to this seal */
+	reiser4_block_nr block;
+#if REISER4_DEBUG
+	/* coord this seal is attached to. For debugging. */
+	coord_t coord1;
+	/* key this seal is attached to. For debugging. */
+	reiser4_key key;
+#endif
+} seal_t;
+
+extern void seal_init(seal_t *, const coord_t *, const reiser4_key *);
+extern void seal_done(seal_t *);
+extern int seal_is_set(const seal_t *);
+extern int seal_validate(seal_t *, coord_t *,
+			 const reiser4_key *, lock_handle *,
+			 znode_lock_mode mode, znode_lock_request request);
+
+/* __SEAL_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/search.c newtree/fs/reiser4/search.c
--- oldtree/fs/reiser4/search.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/search.c	2006-02-21 15:58:35.049818176 +0000
@@ -0,0 +1,1622 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+#include "forward.h"
+#include "debug.h"
+#include "dformat.h"
+#include "key.h"
+#include "coord.h"
+#include "seal.h"
+#include "plugin/item/item.h"
+#include "plugin/node/node.h"
+#include "plugin/plugin.h"
+#include "jnode.h"
+#include "znode.h"
+#include "block_alloc.h"
+#include "tree_walk.h"
+#include "tree.h"
+#include "reiser4.h"
+#include "super.h"
+#include "inode.h"
+
+#include <linux/slab.h>
+
+static const char *bias_name(lookup_bias bias);
+
+/* tree searching algorithm, intranode searching algorithms are in
+   plugin/node/ */
+
+/* tree lookup cache
+ *
+ * The coord by key cache consists of small list of recently accessed nodes
+ * maintained according to the LRU discipline. Before doing real top-to-down
+ * tree traversal this cache is scanned for nodes that can contain key
+ * requested.
+ *
+ * The efficiency of coord cache depends heavily on locality of reference for
+ * tree accesses. Our user level simulations show reasonably good hit ratios
+ * for coord cache under most loads so far.
+ */
+
+/* Initialise coord cache slot */
+static void cbk_cache_init_slot(cbk_cache_slot *slot)
+{
+	assert("nikita-345", slot != NULL);
+
+	INIT_LIST_HEAD(&slot->lru);
+	slot->node = NULL;
+}
+
+/* Initialize coord cache */
+int cbk_cache_init(cbk_cache *cache /* cache to init */ )
+{
+	int i;
+
+	assert("nikita-346", cache != NULL);
+
+	cache->slot =
+	    kmalloc(sizeof(cbk_cache_slot) * cache->nr_slots, GFP_KERNEL);
+	if (cache->slot == NULL)
+		return RETERR(-ENOMEM);
+
+	INIT_LIST_HEAD(&cache->lru);
+	for (i = 0; i < cache->nr_slots; ++i) {
+		cbk_cache_init_slot(cache->slot + i);
+		list_add_tail(&((cache->slot + i)->lru), &cache->lru);
+	}
+	rwlock_init(&cache->guard);
+	return 0;
+}
+
+/* free cbk cache data */
+void cbk_cache_done(cbk_cache * cache /* cache to release */ )
+{
+	assert("nikita-2493", cache != NULL);
+	if (cache->slot != NULL) {
+		kfree(cache->slot);
+		cache->slot = NULL;
+	}
+}
+
+#if 0
+/* macro to iterate over all cbk cache slots */
+#define for_all_slots( cache, slot )					\
+	for( ( slot ) = cbk_cache_list_front( &( cache ) -> lru ) ;	\
+	     !cbk_cache_list_end( &( cache ) -> lru, ( slot ) ) ; 	\
+	     ( slot ) = cbk_cache_list_next( slot ) )
+#endif
+
+/* macro to iterate over all cbk cache slots */
+#define for_all_slots(cache, slot)						\
+	for ((slot) = list_entry((cache)->lru.next, cbk_cache_slot, lru);	\
+	     &(cache)->lru != &(slot)->lru;					\
+	     (slot) = list_entry(slot->lru.next, cbk_cache_slot, lru))
+
+
+#if REISER4_DEBUG
+/* this function assures that [cbk-cache-invariant] invariant holds */
+static int cbk_cache_invariant(const cbk_cache *cache)
+{
+	cbk_cache_slot *slot;
+	int result;
+	int unused;
+
+	if (cache->nr_slots == 0)
+		return 1;
+
+	assert("nikita-2469", cache != NULL);
+	unused = 0;
+	result = 1;
+	read_lock(&((cbk_cache *)cache)->guard);
+	for_all_slots(cache, slot) {
+		/* in LRU first go all `used' slots followed by `unused' */
+		if (unused && (slot->node != NULL))
+			result = 0;
+		if (slot->node == NULL)
+			unused = 1;
+		else {
+			cbk_cache_slot *scan;
+
+			/* all cached nodes are different */
+			scan = slot;
+			while (result) {
+				scan = list_entry(scan->lru.next, cbk_cache_slot, lru);
+				if (&cache->lru == &scan->lru)
+					break;
+				if (slot->node == scan->node)
+					result = 0;
+			}
+		}
+		if (!result)
+			break;
+	}
+	read_unlock(&((cbk_cache *)cache)->guard);
+	return result;
+}
+
+#endif
+
+/* Remove references, if any, to @node from coord cache */
+void cbk_cache_invalidate(const znode * node /* node to remove from cache */ ,
+			  reiser4_tree * tree /* tree to remove node from */ )
+{
+	cbk_cache_slot *slot;
+	cbk_cache *cache;
+	int i;
+
+	assert("nikita-350", node != NULL);
+	assert("nikita-1479", LOCK_CNT_GTZ(rw_locked_tree));
+
+	cache = &tree->cbk_cache;
+	assert("nikita-2470", cbk_cache_invariant(cache));
+
+	write_lock(&(cache->guard));
+	for (i = 0, slot = cache->slot; i < cache->nr_slots; ++i, ++slot) {
+		if (slot->node == node) {
+			list_del(&slot->lru);
+			list_add_tail(&slot->lru, &cache->lru);
+			slot->node = NULL;
+			break;
+		}
+	}
+	write_unlock(&(cache->guard));
+	assert("nikita-2471", cbk_cache_invariant(cache));
+}
+
+/* add to the cbk-cache in the "tree" information about "node". This
+    can actually be update of existing slot in a cache. */
+static void cbk_cache_add(const znode *node /* node to add to the cache */ )
+{
+	cbk_cache *cache;
+	cbk_cache_slot *slot;
+	int i;
+
+	assert("nikita-352", node != NULL);
+
+	cache = &znode_get_tree(node)->cbk_cache;
+	assert("nikita-2472", cbk_cache_invariant(cache));
+
+	if (cache->nr_slots == 0)
+		return;
+
+	write_lock(&(cache->guard));
+	/* find slot to update/add */
+	for (i = 0, slot = cache->slot; i < cache->nr_slots; ++i, ++slot) {
+		/* oops, this node is already in a cache */
+		if (slot->node == node)
+			break;
+	}
+	/* if all slots are used, reuse least recently used one */
+	if (i == cache->nr_slots) {
+		slot = list_entry(cache->lru.prev, cbk_cache_slot, lru);
+		slot->node = (znode *) node;
+	}
+	list_del(&slot->lru);
+	list_add(&slot->lru, &cache->lru);
+	write_unlock(&(cache->guard));
+	assert("nikita-2473", cbk_cache_invariant(cache));
+}
+
+static int setup_delimiting_keys(cbk_handle * h);
+static lookup_result coord_by_handle(cbk_handle * handle);
+static lookup_result traverse_tree(cbk_handle * h);
+static int cbk_cache_search(cbk_handle * h);
+
+static level_lookup_result cbk_level_lookup(cbk_handle * h);
+static level_lookup_result cbk_node_lookup(cbk_handle * h);
+
+/* helper functions */
+
+static void update_stale_dk(reiser4_tree * tree, znode * node);
+
+/* release parent node during traversal */
+static void put_parent(cbk_handle * h);
+/* check consistency of fields */
+static int sanity_check(cbk_handle * h);
+/* release resources in handle */
+static void hput(cbk_handle * h);
+
+static level_lookup_result search_to_left(cbk_handle * h);
+
+/* pack numerous (numberous I should say) arguments of coord_by_key() into
+ * cbk_handle */
+static cbk_handle *cbk_pack(cbk_handle * handle,
+			    reiser4_tree * tree,
+			    const reiser4_key * key,
+			    coord_t * coord,
+			    lock_handle * active_lh,
+			    lock_handle * parent_lh,
+			    znode_lock_mode lock_mode,
+			    lookup_bias bias,
+			    tree_level lock_level,
+			    tree_level stop_level,
+			    __u32 flags, ra_info_t * info)
+{
+	memset(handle, 0, sizeof *handle);
+
+	handle->tree = tree;
+	handle->key = key;
+	handle->lock_mode = lock_mode;
+	handle->bias = bias;
+	handle->lock_level = lock_level;
+	handle->stop_level = stop_level;
+	handle->coord = coord;
+	/* set flags. See comment in tree.h:cbk_flags */
+	handle->flags = flags | CBK_TRUST_DK | CBK_USE_CRABLOCK;
+
+	handle->active_lh = active_lh;
+	handle->parent_lh = parent_lh;
+	handle->ra_info = info;
+	return handle;
+}
+
+/* main tree lookup procedure
+
+   Check coord cache. If key we are looking for is not found there, call cbk()
+   to do real tree traversal.
+
+   As we have extents on the twig level, @lock_level and @stop_level can
+   be different from LEAF_LEVEL and each other.
+
+   Thread cannot keep any reiser4 locks (tree, znode, dk spin-locks, or znode
+   long term locks) while calling this.
+*/
+lookup_result coord_by_key(reiser4_tree * tree	/* tree to perform search
+						 * in. Usually this tree is
+						 * part of file-system
+						 * super-block */ ,
+			   const reiser4_key * key /* key to look for */ ,
+			   coord_t * coord	/* where to store found
+						 * position in a tree. Fields
+						 * in "coord" are only valid if
+						 * coord_by_key() returned
+						 * "CBK_COORD_FOUND" */ ,
+			   lock_handle * lh,	/* resulting lock handle */
+			   znode_lock_mode lock_mode	/* type of lookup we
+							 * want on node. Pass
+							 * ZNODE_READ_LOCK here
+							 * if you only want to
+							 * read item found and
+							 * ZNODE_WRITE_LOCK if
+							 * you want to modify
+							 * it */ ,
+			   lookup_bias bias	/* what to return if coord
+						 * with exactly the @key is
+						 * not in the tree */ ,
+			   tree_level lock_level	/* tree level where to start
+							 * taking @lock type of
+							 * locks */ ,
+			   tree_level stop_level	/* tree level to stop. Pass
+							 * LEAF_LEVEL or TWIG_LEVEL
+							 * here Item being looked
+							 * for has to be between
+							 * @lock_level and
+							 * @stop_level, inclusive */ ,
+			   __u32 flags /* search flags */ ,
+			   ra_info_t *
+			   info
+			   /* information about desired tree traversal readahead */
+			   )
+{
+	cbk_handle handle;
+	lock_handle parent_lh;
+	lookup_result result;
+
+	init_lh(lh);
+	init_lh(&parent_lh);
+
+	assert("nikita-3023", schedulable());
+
+	assert("nikita-353", tree != NULL);
+	assert("nikita-354", key != NULL);
+	assert("nikita-355", coord != NULL);
+	assert("nikita-356", (bias == FIND_EXACT)
+	       || (bias == FIND_MAX_NOT_MORE_THAN));
+	assert("nikita-357", stop_level >= LEAF_LEVEL);
+	/* no locks can be held during tree traversal */
+	assert("nikita-2104", lock_stack_isclean(get_current_lock_stack()));
+
+	cbk_pack(&handle,
+		 tree,
+		 key,
+		 coord,
+		 lh,
+		 &parent_lh,
+		 lock_mode, bias, lock_level, stop_level, flags, info);
+
+	result = coord_by_handle(&handle);
+	assert("nikita-3247",
+	       ergo(!IS_CBKERR(result), coord->node == lh->node));
+	return result;
+}
+
+/* like coord_by_key(), but starts traversal from vroot of @object rather than
+ * from tree root. */
+lookup_result
+object_lookup(struct inode * object,
+	      const reiser4_key * key,
+	      coord_t * coord,
+	      lock_handle * lh,
+	      znode_lock_mode lock_mode,
+	      lookup_bias bias,
+	      tree_level lock_level,
+	      tree_level stop_level, __u32 flags, ra_info_t * info)
+{
+	cbk_handle handle;
+	lock_handle parent_lh;
+	lookup_result result;
+
+	init_lh(lh);
+	init_lh(&parent_lh);
+
+	assert("nikita-3023", schedulable());
+
+	assert("nikita-354", key != NULL);
+	assert("nikita-355", coord != NULL);
+	assert("nikita-356", (bias == FIND_EXACT)
+	       || (bias == FIND_MAX_NOT_MORE_THAN));
+	assert("nikita-357", stop_level >= LEAF_LEVEL);
+	/* no locks can be held during tree search by key */
+	assert("nikita-2104", lock_stack_isclean(get_current_lock_stack()));
+
+	cbk_pack(&handle,
+		 object != NULL ? tree_by_inode(object) : current_tree,
+		 key,
+		 coord,
+		 lh,
+		 &parent_lh,
+		 lock_mode, bias, lock_level, stop_level, flags, info);
+	handle.object = object;
+
+	result = coord_by_handle(&handle);
+	assert("nikita-3247",
+	       ergo(!IS_CBKERR(result), coord->node == lh->node));
+	return result;
+}
+
+/* lookup by cbk_handle. Common part of coord_by_key() and object_lookup(). */
+static lookup_result coord_by_handle(cbk_handle * handle)
+{
+	/*
+	 * first check cbk_cache (which is look-aside cache for our tree) and
+	 * of this fails, start traversal.
+	 */
+	/* first check whether "key" is in cache of recent lookups. */
+	if (cbk_cache_search(handle) == 0)
+		return handle->result;
+	else
+		return traverse_tree(handle);
+}
+
+/* Execute actor for each item (or unit, depending on @through_units_p),
+   starting from @coord, right-ward, until either:
+
+   - end of the tree is reached
+   - unformatted node is met
+   - error occurred
+   - @actor returns 0 or less
+
+   Error code, or last actor return value is returned.
+
+   This is used by plugin/dir/hashe_dir.c:find_entry() to move through
+   sequence of entries with identical keys and alikes.
+*/
+int iterate_tree(reiser4_tree * tree /* tree to scan */ ,
+		 coord_t * coord /* coord to start from */ ,
+		 lock_handle * lh	/* lock handle to start with and to
+					 * update along the way */ ,
+		 tree_iterate_actor_t actor	/* function to call on each
+						 * item/unit */ ,
+		 void *arg /* argument to pass to @actor */ ,
+		 znode_lock_mode mode /* lock mode on scanned nodes */ ,
+		 int through_units_p	/* call @actor on each item or on each
+					 * unit */ )
+{
+	int result;
+
+	assert("nikita-1143", tree != NULL);
+	assert("nikita-1145", coord != NULL);
+	assert("nikita-1146", lh != NULL);
+	assert("nikita-1147", actor != NULL);
+
+	result = zload(coord->node);
+	coord_clear_iplug(coord);
+	if (result != 0)
+		return result;
+	if (!coord_is_existing_unit(coord)) {
+		zrelse(coord->node);
+		return -ENOENT;
+	}
+	while ((result = actor(tree, coord, lh, arg)) > 0) {
+		/* move further  */
+		if ((through_units_p && coord_next_unit(coord)) ||
+		    (!through_units_p && coord_next_item(coord))) {
+			do {
+				lock_handle couple;
+
+				/* move to the next node  */
+				init_lh(&couple);
+				result =
+				    reiser4_get_right_neighbor(&couple,
+							       coord->node,
+							       (int)mode,
+							       GN_CAN_USE_UPPER_LEVELS);
+				zrelse(coord->node);
+				if (result == 0) {
+
+					result = zload(couple.node);
+					if (result != 0) {
+						done_lh(&couple);
+						return result;
+					}
+
+					coord_init_first_unit(coord,
+							      couple.node);
+					done_lh(lh);
+					move_lh(lh, &couple);
+				} else
+					return result;
+			} while (node_is_empty(coord->node));
+		}
+
+		assert("nikita-1149", coord_is_existing_unit(coord));
+	}
+	zrelse(coord->node);
+	return result;
+}
+
+/* return locked uber znode for @tree */
+int get_uber_znode(reiser4_tree * tree, znode_lock_mode mode,
+		   znode_lock_request pri, lock_handle * lh)
+{
+	int result;
+
+	result = longterm_lock_znode(lh, tree->uber, mode, pri);
+	return result;
+}
+
+/* true if @key is strictly within @node
+
+   we are looking for possibly non-unique key and it is item is at the edge of
+   @node. May be it is in the neighbor.
+*/
+static int znode_contains_key_strict(znode * node	/* node to check key
+							 * against */ ,
+				     const reiser4_key *
+				     key /* key to check */ ,
+				     int isunique)
+{
+	int answer;
+
+	assert("nikita-1760", node != NULL);
+	assert("nikita-1722", key != NULL);
+
+	if (keyge(key, &node->rd_key))
+		return 0;
+
+	answer = keycmp(&node->ld_key, key);
+
+	if (isunique)
+		return answer != GREATER_THAN;
+	else
+		return answer == LESS_THAN;
+}
+
+/*
+ * Virtual Root (vroot) code.
+ *
+ *     For given file system object (e.g., regular file or directory) let's
+ *     define its "virtual root" as lowest in the tree (that is, furtherest
+ *     from the tree root) node such that all body items of said object are
+ *     located in a tree rooted at this node.
+ *
+ *     Once vroot of object is found all tree lookups for items within body of
+ *     this object ("object lookups") can be started from its vroot rather
+ *     than from real root. This has following advantages:
+ *
+ *         1. amount of nodes traversed during lookup (and, hence, amount of
+ *         key comparisons made) decreases, and
+ *
+ *         2. contention on tree root is decreased. This latter was actually
+ *         motivating reason behind vroot, because spin lock of root node,
+ *         which is taken when acquiring long-term lock on root node is the
+ *         hottest lock in the reiser4.
+ *
+ * How to find vroot.
+ *
+ *     When vroot of object F is not yet determined, all object lookups start
+ *     from the root of the tree. At each tree level during traversal we have
+ *     a node N such that a key we are looking for (which is the key inside
+ *     object's body) is located within N. In function handle_vroot() called
+ *     from cbk_level_lookup() we check whether N is possible vroot for
+ *     F. Check is trivial---if neither leftmost nor rightmost item of N
+ *     belongs to F (and we already have helpful ->owns_item() method of
+ *     object plugin for this), then N is possible vroot of F. This, of
+ *     course, relies on the assumption that each object occupies contiguous
+ *     range of keys in the tree.
+ *
+ *     Thus, traversing tree downward and checking each node as we go, we can
+ *     find lowest such node, which, by definition, is vroot.
+ *
+ * How to track vroot.
+ *
+ *     Nohow. If actual vroot changes, next object lookup will just restart
+ *     from the actual tree root, refreshing object's vroot along the way.
+ *
+ */
+
+/*
+ * Check whether @node is possible vroot of @object.
+ */
+static void handle_vroot(struct inode *object, znode * node)
+{
+	file_plugin *fplug;
+	coord_t coord;
+
+	fplug = inode_file_plugin(object);
+	assert("nikita-3353", fplug != NULL);
+	assert("nikita-3354", fplug->owns_item != NULL);
+
+	if (unlikely(node_is_empty(node)))
+		return;
+
+	coord_init_first_unit(&coord, node);
+	/*
+	 * if leftmost item of @node belongs to @object, we cannot be sure
+	 * that @node is vroot of @object, because, some items of @object are
+	 * probably in the sub-tree rooted at the left neighbor of @node.
+	 */
+	if (fplug->owns_item(object, &coord))
+		return;
+	coord_init_last_unit(&coord, node);
+	/* mutatis mutandis for the rightmost item */
+	if (fplug->owns_item(object, &coord))
+		return;
+	/* otherwise, @node is possible vroot of @object */
+	inode_set_vroot(object, node);
+}
+
+/*
+ * helper function used by traverse tree to start tree traversal not from the
+ * tree root, but from @h->object's vroot, if possible.
+ */
+static int prepare_object_lookup(cbk_handle * h)
+{
+	znode *vroot;
+	int result;
+
+	vroot = inode_get_vroot(h->object);
+	if (vroot == NULL) {
+		/*
+		 * object doesn't have known vroot, start from real tree root.
+		 */
+		return LOOKUP_CONT;
+	}
+
+	h->level = znode_get_level(vroot);
+	/* take a long-term lock on vroot */
+	h->result = longterm_lock_znode(h->active_lh, vroot,
+					cbk_lock_mode(h->level, h),
+					ZNODE_LOCK_LOPRI);
+	result = LOOKUP_REST;
+	if (h->result == 0) {
+		int isunique;
+		int inside;
+
+		isunique = h->flags & CBK_UNIQUE;
+		/* check that key is inside vroot */
+		read_lock_dk(h->tree);
+		inside = (znode_contains_key_strict(vroot, h->key, isunique) &&
+			  !ZF_ISSET(vroot, JNODE_HEARD_BANSHEE));
+		read_unlock_dk(h->tree);
+		if (inside) {
+			h->result = zload(vroot);
+			if (h->result == 0) {
+				/* search for key in vroot. */
+				result = cbk_node_lookup(h);
+				zrelse(vroot);	/*h->active_lh->node); */
+				if (h->active_lh->node != vroot) {
+					result = LOOKUP_REST;
+				} else if (result == LOOKUP_CONT) {
+					move_lh(h->parent_lh, h->active_lh);
+					h->flags &= ~CBK_DKSET;
+				}
+			}
+		}
+	} else
+		/* long-term locking failed. Restart. */
+		;
+
+	zput(vroot);
+
+	if (IS_CBKERR(h->result) || result == LOOKUP_REST)
+		hput(h);
+	return result;
+}
+
+/* main function that handles common parts of tree traversal: starting
+    (fake znode handling), restarts, error handling, completion */
+static lookup_result traverse_tree(cbk_handle * h /* search handle */ )
+{
+	int done;
+	int iterations;
+	int vroot_used;
+
+	assert("nikita-365", h != NULL);
+	assert("nikita-366", h->tree != NULL);
+	assert("nikita-367", h->key != NULL);
+	assert("nikita-368", h->coord != NULL);
+	assert("nikita-369", (h->bias == FIND_EXACT)
+	       || (h->bias == FIND_MAX_NOT_MORE_THAN));
+	assert("nikita-370", h->stop_level >= LEAF_LEVEL);
+	assert("nikita-2949", !(h->flags & CBK_DKSET));
+	assert("zam-355", lock_stack_isclean(get_current_lock_stack()));
+
+	done = 0;
+	iterations = 0;
+	vroot_used = 0;
+
+	/* loop for restarts */
+      restart:
+
+	assert("nikita-3024", schedulable());
+
+	h->result = CBK_COORD_FOUND;
+	/* connect_znode() needs it */
+	h->ld_key = *min_key();
+	h->rd_key = *max_key();
+	h->flags |= CBK_DKSET;
+	h->error = NULL;
+
+	if (!vroot_used && h->object != NULL) {
+		vroot_used = 1;
+		done = prepare_object_lookup(h);
+		if (done == LOOKUP_REST) {
+			goto restart;
+		} else if (done == LOOKUP_DONE)
+			return h->result;
+	}
+	if (h->parent_lh->node == NULL) {
+		done =
+		    get_uber_znode(h->tree, ZNODE_READ_LOCK, ZNODE_LOCK_LOPRI,
+				   h->parent_lh);
+
+		assert("nikita-1637", done != -E_DEADLOCK);
+
+		h->block = h->tree->root_block;
+		h->level = h->tree->height;
+		h->coord->node = h->parent_lh->node;
+
+		if (done != 0)
+			return done;
+	}
+
+	/* loop descending a tree */
+	while (!done) {
+
+		if (unlikely((iterations > REISER4_CBK_ITERATIONS_LIMIT) &&
+			     IS_POW(iterations))) {
+			warning("nikita-1481", "Too many iterations: %i",
+				iterations);
+			print_key("key", h->key);
+			++iterations;
+		} else if (unlikely(iterations > REISER4_MAX_CBK_ITERATIONS)) {
+			h->error =
+			    "reiser-2018: Too many iterations. Tree corrupted, or (less likely) starvation occurring.";
+			h->result = RETERR(-EIO);
+			break;
+		}
+		switch (cbk_level_lookup(h)) {
+		case LOOKUP_CONT:
+			move_lh(h->parent_lh, h->active_lh);
+			continue;
+		default:
+			wrong_return_value("nikita-372", "cbk_level");
+		case LOOKUP_DONE:
+			done = 1;
+			break;
+		case LOOKUP_REST:
+			hput(h);
+			/* deadlock avoidance is normal case. */
+			if (h->result != -E_DEADLOCK)
+				++iterations;
+			preempt_point();
+			goto restart;
+		}
+	}
+	/* that's all. The rest is error handling */
+	if (unlikely(h->error != NULL)) {
+		warning("nikita-373", "%s: level: %i, "
+			"lock_level: %i, stop_level: %i "
+			"lock_mode: %s, bias: %s",
+			h->error, h->level, h->lock_level, h->stop_level,
+			lock_mode_name(h->lock_mode), bias_name(h->bias));
+		reiser4_print_address("block", &h->block);
+		print_key("key", h->key);
+		print_coord_content("coord", h->coord);
+	}
+	/* `unlikely' error case */
+	if (unlikely(IS_CBKERR(h->result))) {
+		/* failure. do cleanup */
+		hput(h);
+	} else {
+		assert("nikita-1605", WITH_DATA_RET
+		       (h->coord->node, 1,
+			ergo((h->result == CBK_COORD_FOUND) &&
+			     (h->bias == FIND_EXACT) &&
+			     (!node_is_empty(h->coord->node)),
+			     coord_is_existing_item(h->coord))));
+	}
+	return h->result;
+}
+
+/* find delimiting keys of child
+
+   Determine left and right delimiting keys for child pointed to by
+   @parent_coord.
+
+*/
+static void find_child_delimiting_keys(znode * parent	/* parent znode, passed
+							 * locked */ ,
+				       const coord_t * parent_coord	/* coord where
+									 * pointer to
+									 * child is
+									 * stored */ ,
+				       reiser4_key * ld	/* where to store left
+							 * delimiting key */ ,
+				       reiser4_key * rd	/* where to store right
+							 * delimiting key */ )
+{
+	coord_t neighbor;
+
+	assert("nikita-1484", parent != NULL);
+	assert_rw_locked(&(znode_get_tree(parent)->dk_lock));
+
+	coord_dup(&neighbor, parent_coord);
+
+	if (neighbor.between == AT_UNIT)
+		/* imitate item ->lookup() behavior. */
+		neighbor.between = AFTER_UNIT;
+
+	if (coord_set_to_left(&neighbor) == 0)
+		unit_key_by_coord(&neighbor, ld);
+	else {
+		assert("nikita-14851", 0);
+		*ld = *znode_get_ld_key(parent);
+	}
+
+	coord_dup(&neighbor, parent_coord);
+	if (neighbor.between == AT_UNIT)
+		neighbor.between = AFTER_UNIT;
+	if (coord_set_to_right(&neighbor) == 0)
+		unit_key_by_coord(&neighbor, rd);
+	else
+		*rd = *znode_get_rd_key(parent);
+}
+
+/*
+ * setup delimiting keys for a child
+ *
+ * @parent parent node
+ *
+ * @coord location in @parent where pointer to @child is
+ *
+ * @child child node
+ */
+int
+set_child_delimiting_keys(znode * parent, const coord_t * coord, znode * child)
+{
+	reiser4_tree *tree;
+
+	assert("nikita-2952",
+	       znode_get_level(parent) == znode_get_level(coord->node));
+
+	/* fast check without taking dk lock. This is safe, because
+	 * JNODE_DKSET is never cleared once set. */
+	if (!ZF_ISSET(child, JNODE_DKSET)) {
+		tree = znode_get_tree(parent);
+		write_lock_dk(tree);
+		if (likely(!ZF_ISSET(child, JNODE_DKSET))) {
+			find_child_delimiting_keys(parent, coord,
+						   &child->ld_key,
+						   &child->rd_key);
+			ON_DEBUG(child->ld_key_version =
+				 atomic_inc_return(&delim_key_version);
+				 child->rd_key_version =
+				 atomic_inc_return(&delim_key_version););
+			ZF_SET(child, JNODE_DKSET);
+		}
+		write_unlock_dk(tree);
+		return 1;
+	}
+	return 0;
+}
+
+/* Perform tree lookup at one level. This is called from cbk_traverse()
+   function that drives lookup through tree and calls cbk_node_lookup() to
+   perform lookup within one node.
+
+   See comments in a code.
+*/
+static level_lookup_result cbk_level_lookup(cbk_handle * h /* search handle */ )
+{
+	int ret;
+	int setdk;
+	int ldkeyset = 0;
+	reiser4_key ldkey;
+	reiser4_key key;
+	znode *active;
+
+	assert("nikita-3025", schedulable());
+
+	/* acquire reference to @active node */
+	active =
+	    zget(h->tree, &h->block, h->parent_lh->node, h->level, GFP_KERNEL);
+
+	if (IS_ERR(active)) {
+		h->result = PTR_ERR(active);
+		return LOOKUP_DONE;
+	}
+
+	/* lock @active */
+	h->result = longterm_lock_znode(h->active_lh,
+					active,
+					cbk_lock_mode(h->level, h),
+					ZNODE_LOCK_LOPRI);
+	/* longterm_lock_znode() acquires additional reference to znode (which
+	   will be later released by longterm_unlock_znode()). Release
+	   reference acquired by zget().
+	 */
+	zput(active);
+	if (unlikely(h->result != 0))
+		goto fail_or_restart;
+
+	setdk = 0;
+	/* if @active is accessed for the first time, setup delimiting keys on
+	   it. Delimiting keys are taken from the parent node. See
+	   setup_delimiting_keys() for details.
+	 */
+	if (h->flags & CBK_DKSET) {
+		setdk = setup_delimiting_keys(h);
+		h->flags &= ~CBK_DKSET;
+	} else {
+		znode *parent;
+
+		parent = h->parent_lh->node;
+		h->result = zload(parent);
+		if (unlikely(h->result != 0))
+			goto fail_or_restart;
+
+		if (!ZF_ISSET(active, JNODE_DKSET))
+			setdk = set_child_delimiting_keys(parent,
+							  h->coord, active);
+		else {
+			read_lock_dk(h->tree);
+			find_child_delimiting_keys(parent, h->coord, &ldkey,
+						   &key);
+			read_unlock_dk(h->tree);
+			ldkeyset = 1;
+		}
+		zrelse(parent);
+	}
+
+	/* this is ugly kludge. Reminder: this is necessary, because
+	   ->lookup() method returns coord with ->between field probably set
+	   to something different from AT_UNIT.
+	 */
+	h->coord->between = AT_UNIT;
+
+	if (znode_just_created(active) && (h->coord->node != NULL)) {
+		write_lock_tree(h->tree);
+		/* if we are going to load znode right now, setup
+		   ->in_parent: coord where pointer to this node is stored in
+		   parent.
+		 */
+		coord_to_parent_coord(h->coord, &active->in_parent);
+		write_unlock_tree(h->tree);
+	}
+
+	/* check connectedness without holding tree lock---false negatives
+	 * will be re-checked by connect_znode(), and false positives are
+	 * impossible---@active cannot suddenly turn into unconnected
+	 * state. */
+	if (!znode_is_connected(active)) {
+		h->result = connect_znode(h->coord, active);
+		if (unlikely(h->result != 0)) {
+			put_parent(h);
+			goto fail_or_restart;
+		}
+	}
+
+	jload_prefetch(ZJNODE(active));
+
+	if (setdk)
+		update_stale_dk(h->tree, active);
+
+	/* put_parent() cannot be called earlier, because connect_znode()
+	   assumes parent node is referenced; */
+	put_parent(h);
+
+	if ((!znode_contains_key_lock(active, h->key) &&
+	     (h->flags & CBK_TRUST_DK))
+	    || ZF_ISSET(active, JNODE_HEARD_BANSHEE)) {
+		/* 1. key was moved out of this node while this thread was
+		   waiting for the lock. Restart. More elaborate solution is
+		   to determine where key moved (to the left, or to the right)
+		   and try to follow it through sibling pointers.
+
+		   2. or, node itself is going to be removed from the
+		   tree. Release lock and restart.
+		 */
+		h->result = -E_REPEAT;
+	}
+	if (h->result == -E_REPEAT)
+		return LOOKUP_REST;
+
+	h->result = zload_ra(active, h->ra_info);
+	if (h->result) {
+		return LOOKUP_DONE;
+	}
+
+	/* sanity checks */
+	if (sanity_check(h)) {
+		zrelse(active);
+		return LOOKUP_DONE;
+	}
+
+	/* check that key of leftmost item in the @active is the same as in
+	 * its parent */
+	if (ldkeyset && !node_is_empty(active) &&
+	    !keyeq(leftmost_key_in_node(active, &key), &ldkey)) {
+		warning("vs-3533", "Keys are inconsistent. Fsck?");
+		print_key("inparent", &ldkey);
+		print_key("inchild", &key);
+		h->result = RETERR(-EIO);
+		zrelse(active);
+		return LOOKUP_DONE;
+	}
+
+	if (h->object != NULL)
+		handle_vroot(h->object, active);
+
+	ret = cbk_node_lookup(h);
+
+	/* h->active_lh->node might change, but active is yet to be zrelsed */
+	zrelse(active);
+
+	return ret;
+
+      fail_or_restart:
+	if (h->result == -E_DEADLOCK)
+		return LOOKUP_REST;
+	return LOOKUP_DONE;
+}
+
+#if REISER4_DEBUG
+/* check left and right delimiting keys of a znode */
+void check_dkeys(znode * node)
+{
+	znode *left;
+	znode *right;
+
+	read_lock_tree(current_tree);
+	read_lock_dk(current_tree);
+
+	assert("vs-1710", znode_is_any_locked(node));
+	assert("vs-1197",
+	       !keygt(znode_get_ld_key(node), znode_get_rd_key(node)));
+
+	left = node->left;
+	right = node->right;
+
+	if (ZF_ISSET(node, JNODE_LEFT_CONNECTED) && ZF_ISSET(node, JNODE_DKSET)
+	    && left != NULL && ZF_ISSET(left, JNODE_DKSET))
+		/* check left neighbor. Note that left neighbor is not locked,
+		   so it might get wrong delimiting keys therefore */
+		assert("vs-1198",
+		       (keyeq(znode_get_rd_key(left), znode_get_ld_key(node))
+			|| ZF_ISSET(left, JNODE_HEARD_BANSHEE)));
+
+	if (ZF_ISSET(node, JNODE_RIGHT_CONNECTED) && ZF_ISSET(node, JNODE_DKSET)
+	    && right != NULL && ZF_ISSET(right, JNODE_DKSET))
+		/* check right neighbor. Note that right neighbor is not
+		   locked, so it might get wrong delimiting keys therefore  */
+		assert("vs-1199",
+		       (keyeq(znode_get_rd_key(node), znode_get_ld_key(right))
+			|| ZF_ISSET(right, JNODE_HEARD_BANSHEE)));
+
+	read_unlock_dk(current_tree);
+	read_unlock_tree(current_tree);
+}
+#endif
+
+/* true if @key is left delimiting key of @node */
+static int key_is_ld(znode * node, const reiser4_key * key)
+{
+	int ld;
+
+	assert("nikita-1716", node != NULL);
+	assert("nikita-1758", key != NULL);
+
+	read_lock_dk(znode_get_tree(node));
+	assert("nikita-1759", znode_contains_key(node, key));
+	ld = keyeq(znode_get_ld_key(node), key);
+	read_unlock_dk(znode_get_tree(node));
+	return ld;
+}
+
+/* Process one node during tree traversal.
+
+   This is called by cbk_level_lookup(). */
+static level_lookup_result cbk_node_lookup(cbk_handle * h /* search handle */ )
+{
+	/* node plugin of @active */
+	node_plugin *nplug;
+	/* item plugin of item that was found */
+	item_plugin *iplug;
+	/* search bias */
+	lookup_bias node_bias;
+	/* node we are operating upon */
+	znode *active;
+	/* tree we are searching in */
+	reiser4_tree *tree;
+	/* result */
+	int result;
+
+	assert("nikita-379", h != NULL);
+
+	active = h->active_lh->node;
+	tree = h->tree;
+
+	nplug = active->nplug;
+	assert("nikita-380", nplug != NULL);
+
+	ON_DEBUG(check_dkeys(active));
+
+	/* return item from "active" node with maximal key not greater than
+	   "key"  */
+	node_bias = h->bias;
+	result = nplug->lookup(active, h->key, node_bias, h->coord);
+	if (unlikely(result != NS_FOUND && result != NS_NOT_FOUND)) {
+		/* error occurred */
+		h->result = result;
+		return LOOKUP_DONE;
+	}
+	if (h->level == h->stop_level) {
+		/* welcome to the stop level */
+		assert("nikita-381", h->coord->node == active);
+		if (result == NS_FOUND) {
+			/* success of tree lookup */
+			if (!(h->flags & CBK_UNIQUE)
+			    && key_is_ld(active, h->key)) {
+				return search_to_left(h);
+			} else
+				h->result = CBK_COORD_FOUND;
+		} else {
+			h->result = CBK_COORD_NOTFOUND;
+		}
+		if (!(h->flags & CBK_IN_CACHE))
+			cbk_cache_add(active);
+		return LOOKUP_DONE;
+	}
+
+	if (h->level > TWIG_LEVEL && result == NS_NOT_FOUND) {
+		h->error = "not found on internal node";
+		h->result = result;
+		return LOOKUP_DONE;
+	}
+
+	assert("vs-361", h->level > h->stop_level);
+
+	if (handle_eottl(h, &result)) {
+		assert("vs-1674", (result == LOOKUP_DONE ||
+				   result == LOOKUP_REST));
+		return result;
+	}
+
+	/* go down to next level */
+	check_me("vs-12", zload(h->coord->node) == 0);
+	assert("nikita-2116", item_is_internal(h->coord));
+	iplug = item_plugin_by_coord(h->coord);
+	iplug->s.internal.down_link(h->coord, h->key, &h->block);
+	zrelse(h->coord->node);
+	--h->level;
+	return LOOKUP_CONT;	/* continue */
+}
+
+/* scan cbk_cache slots looking for a match for @h */
+static int cbk_cache_scan_slots(cbk_handle * h /* cbk handle */ )
+{
+	level_lookup_result llr;
+	znode *node;
+	reiser4_tree *tree;
+	cbk_cache_slot *slot;
+	cbk_cache *cache;
+	tree_level level;
+	int isunique;
+	const reiser4_key *key;
+	int result;
+
+	assert("nikita-1317", h != NULL);
+	assert("nikita-1315", h->tree != NULL);
+	assert("nikita-1316", h->key != NULL);
+
+	tree = h->tree;
+	cache = &tree->cbk_cache;
+	if (cache->nr_slots == 0)
+		/* size of cbk cache was set to 0 by mount time option. */
+		return RETERR(-ENOENT);
+
+	assert("nikita-2474", cbk_cache_invariant(cache));
+	node = NULL;		/* to keep gcc happy */
+	level = h->level;
+	key = h->key;
+	isunique = h->flags & CBK_UNIQUE;
+	result = RETERR(-ENOENT);
+
+	/*
+	 * this is time-critical function and dragons had, hence, been settled
+	 * here.
+	 *
+	 * Loop below scans cbk cache slots trying to find matching node with
+	 * suitable range of delimiting keys and located at the h->level.
+	 *
+	 * Scan is done under cbk cache spin lock that protects slot->node
+	 * pointers. If suitable node is found we want to pin it in
+	 * memory. But slot->node can point to the node with x_count 0
+	 * (unreferenced). Such node can be recycled at any moment, or can
+	 * already be in the process of being recycled (within jput()).
+	 *
+	 * As we found node in the cbk cache, it means that jput() hasn't yet
+	 * called cbk_cache_invalidate().
+	 *
+	 * We acquire reference to the node without holding tree lock, and
+	 * later, check node's RIP bit. This avoids races with jput().
+	 */
+
+	rcu_read_lock();
+	read_lock(&((cbk_cache *)cache)->guard);
+
+	slot = list_entry(cache->lru.next, cbk_cache_slot, lru);
+	slot = list_entry(slot->lru.prev, cbk_cache_slot, lru);
+	BUG_ON(&slot->lru != &cache->lru);/*????*/
+	while (1) {
+
+		slot = list_entry(slot->lru.next, cbk_cache_slot, lru);
+
+		if (&cache->lru != &slot->lru)
+			node = slot->node;
+		else
+			node = NULL;
+
+		if (unlikely(node == NULL))
+			break;
+
+		/*
+		 * this is (hopefully) the only place in the code where we are
+		 * working with delimiting keys without holding dk lock. This
+		 * is fine here, because this is only "guess" anyway---keys
+		 * are rechecked under dk lock below.
+		 */
+		if (znode_get_level(node) == level &&
+		    /* min_key < key < max_key */
+		    znode_contains_key_strict(node, key, isunique)) {
+			zref(node);
+			result = 0;
+			spin_lock_prefetch(&tree->tree_lock);
+			break;
+		}
+	}
+	read_unlock(&((cbk_cache *)cache)->guard);
+
+	assert("nikita-2475", cbk_cache_invariant(cache));
+
+	if (unlikely(result == 0 && ZF_ISSET(node, JNODE_RIP)))
+		result = -ENOENT;
+
+	rcu_read_unlock();
+
+	if (result != 0) {
+		h->result = CBK_COORD_NOTFOUND;
+		return RETERR(-ENOENT);
+	}
+
+	result =
+	    longterm_lock_znode(h->active_lh, node, cbk_lock_mode(level, h),
+				ZNODE_LOCK_LOPRI);
+	zput(node);
+	if (result != 0)
+		return result;
+	result = zload(node);
+	if (result != 0)
+		return result;
+
+	/* recheck keys */
+	read_lock_dk(tree);
+	result = (znode_contains_key_strict(node, key, isunique) &&
+		!ZF_ISSET(node, JNODE_HEARD_BANSHEE));
+	read_unlock_dk(tree);
+	if (result) {
+		/* do lookup inside node */
+		llr = cbk_node_lookup(h);
+		/* if cbk_node_lookup() wandered to another node (due to eottl
+		   or non-unique keys), adjust @node */
+		/*node = h->active_lh->node; */
+
+		if (llr != LOOKUP_DONE) {
+			/* restart or continue on the next level */
+			result = RETERR(-ENOENT);
+		} else if (IS_CBKERR(h->result))
+			/* io or oom */
+			result = RETERR(-ENOENT);
+		else {
+			/* good. Either item found or definitely not found. */
+			result = 0;
+
+			write_lock(&(cache->guard));
+			if (slot->node == h->active_lh->node /*node */ ) {
+				/* if this node is still in cbk cache---move
+				   its slot to the head of the LRU list. */
+				list_del(&slot->lru);
+				list_add(&slot->lru, &cache->lru);
+			}
+			write_unlock(&(cache->guard));
+		}
+	} else {
+		/* race. While this thread was waiting for the lock, node was
+		   rebalanced and item we are looking for, shifted out of it
+		   (if it ever was here).
+
+		   Continuing scanning is almost hopeless: node key range was
+		   moved to, is almost certainly at the beginning of the LRU
+		   list at this time, because it's hot, but restarting
+		   scanning from the very beginning is complex. Just return,
+		   so that cbk() will be performed. This is not that
+		   important, because such races should be rare. Are they?
+		 */
+		result = RETERR(-ENOENT);	/* -ERAUGHT */
+	}
+	zrelse(node);
+	assert("nikita-2476", cbk_cache_invariant(cache));
+	return result;
+}
+
+/* look for item with given key in the coord cache
+
+   This function, called by coord_by_key(), scans "coord cache" (&cbk_cache)
+   which is a small LRU list of znodes accessed lately. For each znode in
+   znode in this list, it checks whether key we are looking for fits into key
+   range covered by this node. If so, and in addition, node lies at allowed
+   level (this is to handle extents on a twig level), node is locked, and
+   lookup inside it is performed.
+
+   we need a measurement of the cost of this cache search compared to the cost
+   of coord_by_key.
+
+*/
+static int cbk_cache_search(cbk_handle * h /* cbk handle */ )
+{
+	int result = 0;
+	tree_level level;
+
+	/* add CBK_IN_CACHE to the handle flags. This means that
+	 * cbk_node_lookup() assumes that cbk_cache is scanned and would add
+	 * found node to the cache. */
+	h->flags |= CBK_IN_CACHE;
+	for (level = h->stop_level; level <= h->lock_level; ++level) {
+		h->level = level;
+		result = cbk_cache_scan_slots(h);
+		if (result != 0) {
+			done_lh(h->active_lh);
+			done_lh(h->parent_lh);
+		} else {
+			assert("nikita-1319", !IS_CBKERR(h->result));
+			break;
+		}
+	}
+	h->flags &= ~CBK_IN_CACHE;
+	return result;
+}
+
+/* type of lock we want to obtain during tree traversal. On stop level
+    we want type of lock user asked for, on upper levels: read lock. */
+znode_lock_mode cbk_lock_mode(tree_level level, cbk_handle * h)
+{
+	assert("nikita-382", h != NULL);
+
+	return (level <= h->lock_level) ? h->lock_mode : ZNODE_READ_LOCK;
+}
+
+/* update outdated delimiting keys */
+static void stale_dk(reiser4_tree * tree, znode * node)
+{
+	znode *right;
+
+	read_lock_tree(tree);
+	write_lock_dk(tree);
+	right = node->right;
+
+	if (ZF_ISSET(node, JNODE_RIGHT_CONNECTED) &&
+	    right && ZF_ISSET(right, JNODE_DKSET) &&
+	    !keyeq(znode_get_rd_key(node), znode_get_ld_key(right)))
+		znode_set_rd_key(node, znode_get_ld_key(right));
+
+	write_unlock_dk(tree);
+	read_unlock_tree(tree);
+}
+
+/* check for possibly outdated delimiting keys, and update them if
+ * necessary. */
+static void update_stale_dk(reiser4_tree * tree, znode * node)
+{
+	znode *right;
+	reiser4_key rd;
+
+	read_lock_tree(tree);
+	read_lock_dk(tree);
+	rd = *znode_get_rd_key(node);
+	right = node->right;
+	if (unlikely(ZF_ISSET(node, JNODE_RIGHT_CONNECTED) &&
+		     right && ZF_ISSET(right, JNODE_DKSET) &&
+		     !keyeq(&rd, znode_get_ld_key(right)))) {
+		assert("nikita-38211", ZF_ISSET(node, JNODE_DKSET));
+		read_unlock_dk(tree);
+		read_unlock_tree(tree);
+		stale_dk(tree, node);
+		return;
+	}
+	read_unlock_dk(tree);
+	read_unlock_tree(tree);
+}
+
+/*
+ * handle searches a the non-unique key.
+ *
+ * Suppose that we are looking for an item with possibly non-unique key 100.
+ *
+ * Root node contains two pointers: one to a node with left delimiting key 0,
+ * and another to a node with left delimiting key 100. Item we interested in
+ * may well happen in the sub-tree rooted at the first pointer.
+ *
+ * To handle this search_to_left() is called when search reaches stop
+ * level. This function checks it is _possible_ that item we are looking for
+ * is in the left neighbor (this can be done by comparing delimiting keys) and
+ * if so, tries to lock left neighbor (this is low priority lock, so it can
+ * deadlock, tree traversal is just restarted if it did) and then checks
+ * whether left neighbor actually contains items with our key.
+ *
+ * Note that this is done on the stop level only. It is possible to try such
+ * left-check on each level, but as duplicate keys are supposed to be rare
+ * (very unlikely that more than one node is completely filled with items with
+ * duplicate keys), it sis cheaper to scan to the left on the stop level once.
+ *
+ */
+static level_lookup_result search_to_left(cbk_handle * h /* search handle */ )
+{
+	level_lookup_result result;
+	coord_t *coord;
+	znode *node;
+	znode *neighbor;
+
+	lock_handle lh;
+
+	assert("nikita-1761", h != NULL);
+	assert("nikita-1762", h->level == h->stop_level);
+
+	init_lh(&lh);
+	coord = h->coord;
+	node = h->active_lh->node;
+	assert("nikita-1763", coord_is_leftmost_unit(coord));
+
+	h->result =
+	    reiser4_get_left_neighbor(&lh, node, (int)h->lock_mode,
+				      GN_CAN_USE_UPPER_LEVELS);
+	neighbor = NULL;
+	switch (h->result) {
+	case -E_DEADLOCK:
+		result = LOOKUP_REST;
+		break;
+	case 0:{
+			node_plugin *nplug;
+			coord_t crd;
+			lookup_bias bias;
+
+			neighbor = lh.node;
+			h->result = zload(neighbor);
+			if (h->result != 0) {
+				result = LOOKUP_DONE;
+				break;
+			}
+
+			nplug = neighbor->nplug;
+
+			coord_init_zero(&crd);
+			bias = h->bias;
+			h->bias = FIND_EXACT;
+			h->result =
+			    nplug->lookup(neighbor, h->key, h->bias, &crd);
+			h->bias = bias;
+
+			if (h->result == NS_NOT_FOUND) {
+	case -E_NO_NEIGHBOR:
+				h->result = CBK_COORD_FOUND;
+				if (!(h->flags & CBK_IN_CACHE))
+					cbk_cache_add(node);
+	default:		/* some other error */
+				result = LOOKUP_DONE;
+			} else if (h->result == NS_FOUND) {
+				read_lock_dk(znode_get_tree(neighbor));
+				h->rd_key = *znode_get_ld_key(node);
+				leftmost_key_in_node(neighbor, &h->ld_key);
+				read_unlock_dk(znode_get_tree(neighbor));
+				h->flags |= CBK_DKSET;
+
+				h->block = *znode_get_block(neighbor);
+				/* clear coord -> node so that cbk_level_lookup()
+				   wouldn't overwrite parent hint in neighbor.
+
+				   Parent hint was set up by
+				   reiser4_get_left_neighbor()
+				 */
+				/* FIXME: why do we have to spinlock here? */
+				write_lock_tree(znode_get_tree(neighbor));
+				h->coord->node = NULL;
+				write_unlock_tree(znode_get_tree(neighbor));
+				result = LOOKUP_CONT;
+			} else {
+				result = LOOKUP_DONE;
+			}
+			if (neighbor != NULL)
+				zrelse(neighbor);
+		}
+	}
+	done_lh(&lh);
+	return result;
+}
+
+/* debugging aid: return symbolic name of search bias */
+static const char *bias_name(lookup_bias bias /* bias to get name of */ )
+{
+	if (bias == FIND_EXACT)
+		return "exact";
+	else if (bias == FIND_MAX_NOT_MORE_THAN)
+		return "left-slant";
+/* 	else if( bias == RIGHT_SLANT_BIAS ) */
+/* 		return "right-bias"; */
+	else {
+		static char buf[30];
+
+		sprintf(buf, "unknown: %i", bias);
+		return buf;
+	}
+}
+
+#if REISER4_DEBUG
+/* debugging aid: print human readable information about @p */
+void print_coord_content(const char *prefix /* prefix to print */ ,
+			 coord_t * p /* coord to print */ )
+{
+	reiser4_key key;
+
+	if (p == NULL) {
+		printk("%s: null\n", prefix);
+		return;
+	}
+	if ((p->node != NULL) && znode_is_loaded(p->node)
+	    && coord_is_existing_item(p))
+		printk("%s: data: %p, length: %i\n", prefix,
+		       item_body_by_coord(p), item_length_by_coord(p));
+	if (znode_is_loaded(p->node)) {
+		item_key_by_coord(p, &key);
+		print_key(prefix, &key);
+	}
+}
+
+/* debugging aid: print human readable information about @block */
+void reiser4_print_address(const char *prefix /* prefix to print */ ,
+		   const reiser4_block_nr * block /* block number to print */ )
+{
+	printk("%s: %s\n", prefix, sprint_address(block));
+}
+#endif
+
+/* return string containing human readable representation of @block */
+char *sprint_address(const reiser4_block_nr *
+		     block /* block number to print */ )
+{
+	static char address[30];
+
+	if (block == NULL)
+		sprintf(address, "null");
+	else if (blocknr_is_fake(block))
+		sprintf(address, "%llx", (unsigned long long)(*block));
+	else
+		sprintf(address, "%llu", (unsigned long long)(*block));
+	return address;
+}
+
+/* release parent node during traversal */
+static void put_parent(cbk_handle * h /* search handle */ )
+{
+	assert("nikita-383", h != NULL);
+	if (h->parent_lh->node != NULL) {
+		longterm_unlock_znode(h->parent_lh);
+	}
+}
+
+/* helper function used by coord_by_key(): release reference to parent znode
+   stored in handle before processing its child. */
+static void hput(cbk_handle * h /* search handle */ )
+{
+	assert("nikita-385", h != NULL);
+	done_lh(h->parent_lh);
+	done_lh(h->active_lh);
+}
+
+/* Helper function used by cbk(): update delimiting keys of child node (stored
+   in h->active_lh->node) using key taken from parent on the parent level. */
+static int setup_delimiting_keys(cbk_handle * h /* search handle */ )
+{
+	znode *active;
+	reiser4_tree *tree;
+
+	assert("nikita-1088", h != NULL);
+
+	active = h->active_lh->node;
+
+	/* fast check without taking dk lock. This is safe, because
+	 * JNODE_DKSET is never cleared once set. */
+	if (!ZF_ISSET(active, JNODE_DKSET)) {
+		tree = znode_get_tree(active);
+		write_lock_dk(tree);
+		if (!ZF_ISSET(active, JNODE_DKSET)) {
+			znode_set_ld_key(active, &h->ld_key);
+			znode_set_rd_key(active, &h->rd_key);
+			ZF_SET(active, JNODE_DKSET);
+		}
+		write_unlock_dk(tree);
+		return 1;
+	}
+	return 0;
+}
+
+/* true if @block makes sense for the @tree. Used to detect corrupted node
+ * pointers */
+static int
+block_nr_is_correct(reiser4_block_nr * block /* block number to check */ ,
+		    reiser4_tree * tree /* tree to check against */ )
+{
+	assert("nikita-757", block != NULL);
+	assert("nikita-758", tree != NULL);
+
+	/* check to see if it exceeds the size of the device. */
+	return reiser4_blocknr_is_sane_for(tree->super, block);
+}
+
+/* check consistency of fields */
+static int sanity_check(cbk_handle * h /* search handle */ )
+{
+	assert("nikita-384", h != NULL);
+
+	if (h->level < h->stop_level) {
+		h->error = "Buried under leaves";
+		h->result = RETERR(-EIO);
+		return LOOKUP_DONE;
+	} else if (!block_nr_is_correct(&h->block, h->tree)) {
+		h->error = "bad block number";
+		h->result = RETERR(-EIO);
+		return LOOKUP_DONE;
+	} else
+		return 0;
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/status_flags.c newtree/fs/reiser4/status_flags.c
--- oldtree/fs/reiser4/status_flags.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/status_flags.c	2006-02-21 15:58:34.862846600 +0000
@@ -0,0 +1,176 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Functions that deal with reiser4 status block, query status and update it, if needed */
+
+#include <linux/bio.h>
+#include <linux/highmem.h>
+#include <linux/fs.h>
+#include <linux/blkdev.h>
+#include "debug.h"
+#include "dformat.h"
+#include "status_flags.h"
+#include "super.h"
+
+/* This is our end I/O handler that marks page uptodate if IO was successful. It also
+   unconditionally unlocks the page, so we can see that io was done.
+   We do not free bio, because we hope to reuse that. */
+static int reiser4_status_endio(struct bio *bio, unsigned int bytes_done,
+				int err)
+{
+	if (bio->bi_size)
+		return 1;
+
+	if (test_bit(BIO_UPTODATE, &bio->bi_flags)) {
+		SetPageUptodate(bio->bi_io_vec->bv_page);
+	} else {
+		ClearPageUptodate(bio->bi_io_vec->bv_page);
+		SetPageError(bio->bi_io_vec->bv_page);
+	}
+	unlock_page(bio->bi_io_vec->bv_page);
+	return 0;
+}
+
+/* Initialise status code. This is expected to be called from the disk format
+   code. block paremeter is where status block lives. */
+int reiser4_status_init(reiser4_block_nr block)
+{
+	struct super_block *sb = reiser4_get_current_sb();
+	struct reiser4_status *statuspage;
+	struct bio *bio;
+	struct page *page;
+
+
+	get_super_private(sb)->status_page = NULL;
+	get_super_private(sb)->status_bio = NULL;
+
+	page = alloc_pages(GFP_KERNEL, 0);
+	if (!page)
+		return -ENOMEM;
+
+	bio = bio_alloc(GFP_KERNEL, 1);
+	if (bio != NULL) {
+		bio->bi_sector = block * (sb->s_blocksize >> 9);
+		bio->bi_bdev = sb->s_bdev;
+		bio->bi_io_vec[0].bv_page = page;
+		bio->bi_io_vec[0].bv_len = sb->s_blocksize;
+		bio->bi_io_vec[0].bv_offset = 0;
+		bio->bi_vcnt = 1;
+		bio->bi_size = sb->s_blocksize;
+		bio->bi_end_io = reiser4_status_endio;
+	} else {
+		__free_pages(page, 0);
+		return -ENOMEM;
+	}
+	lock_page(page);
+	submit_bio(READ, bio);
+	blk_run_address_space(get_super_fake(sb)->i_mapping);
+	wait_on_page_locked(page);
+	if (!PageUptodate(page)) {
+		warning("green-2007",
+			"I/O error while tried to read status page\n");
+		return -EIO;
+	}
+
+	statuspage = (struct reiser4_status *)kmap_atomic(page, KM_USER0);
+	if (memcmp
+	    (statuspage->magic, REISER4_STATUS_MAGIC,
+	     sizeof(REISER4_STATUS_MAGIC))) {
+		/* Magic does not match. */
+		kunmap_atomic((char *)statuspage, KM_USER0);
+		warning("green-2008", "Wrong magic in status block\n");
+		__free_pages(page, 0);
+		bio_put(bio);
+		return -EINVAL;
+	}
+	kunmap_atomic((char *)statuspage, KM_USER0);
+
+	get_super_private(sb)->status_page = page;
+	get_super_private(sb)->status_bio = bio;
+	return 0;
+}
+
+/* Query the status of fs. Returns if the FS can be safely mounted.
+   Also if "status" and "extended" parameters are given, it will fill
+   actual parts of status from disk there. */
+int reiser4_status_query(u64 * status, u64 * extended)
+{
+	struct super_block *sb = reiser4_get_current_sb();
+	struct reiser4_status *statuspage;
+	int retval;
+
+	if (!get_super_private(sb)->status_page) {	// No status page?
+		return REISER4_STATUS_MOUNT_UNKNOWN;
+	}
+	statuspage = (struct reiser4_status *)
+	    kmap_atomic(get_super_private(sb)->status_page, KM_USER0);
+	switch ((long)le64_to_cpu(get_unaligned(&statuspage->status))) {	// FIXME: this cast is a hack for 32 bit arches to work.
+	case REISER4_STATUS_OK:
+		retval = REISER4_STATUS_MOUNT_OK;
+		break;
+	case REISER4_STATUS_CORRUPTED:
+		retval = REISER4_STATUS_MOUNT_WARN;
+		break;
+	case REISER4_STATUS_DAMAGED:
+	case REISER4_STATUS_DESTROYED:
+	case REISER4_STATUS_IOERROR:
+		retval = REISER4_STATUS_MOUNT_RO;
+		break;
+	default:
+		retval = REISER4_STATUS_MOUNT_UNKNOWN;
+		break;
+	}
+
+	if (status)
+		*status = le64_to_cpu(get_unaligned(&statuspage->status));
+	if (extended)
+		*extended = le64_to_cpu(get_unaligned(&statuspage->extended_status));
+
+	kunmap_atomic((char *)statuspage, KM_USER0);
+	return retval;
+}
+
+/* This function should be called when something bad happens (e.g. from reiser4_panic).
+   It fills the status structure and tries to push it to disk. */
+int reiser4_status_write(__u64 status, __u64 extended_status, char *message)
+{
+	struct super_block *sb = reiser4_get_current_sb();
+	struct reiser4_status *statuspage;
+	struct bio *bio = get_super_private(sb)->status_bio;
+
+	if (!get_super_private(sb)->status_page) {	// No status page?
+		return -1;
+	}
+	statuspage = (struct reiser4_status *)
+	    kmap_atomic(get_super_private(sb)->status_page, KM_USER0);
+
+	put_unaligned(cpu_to_le64(status), &statuspage->status);
+	put_unaligned(cpu_to_le64(extended_status), &statuspage->extended_status);
+	strncpy(statuspage->texterror, message, REISER4_TEXTERROR_LEN);
+
+	kunmap_atomic((char *)statuspage, KM_USER0);
+	bio->bi_bdev = sb->s_bdev;
+	bio->bi_io_vec[0].bv_page = get_super_private(sb)->status_page;
+	bio->bi_io_vec[0].bv_len = sb->s_blocksize;
+	bio->bi_io_vec[0].bv_offset = 0;
+	bio->bi_vcnt = 1;
+	bio->bi_size = sb->s_blocksize;
+	bio->bi_end_io = reiser4_status_endio;
+	lock_page(get_super_private(sb)->status_page);	// Safe as nobody should touch our page.
+	/* We can block now, but we have no other choice anyway */
+	submit_bio(WRITE, bio);
+	blk_run_address_space(get_super_fake(sb)->i_mapping);
+	return 0;		// We do not wait for io to finish.
+}
+
+/* Frees the page with status and bio structure. Should be called by disk format at umount time */
+int reiser4_status_finish(void)
+{
+	struct super_block *sb = reiser4_get_current_sb();
+
+	__free_pages(get_super_private(sb)->status_page, 0);
+	get_super_private(sb)->status_page = NULL;
+	bio_put(get_super_private(sb)->status_bio);
+	get_super_private(sb)->status_bio = NULL;
+	return 0;
+}
diff -urN oldtree/fs/reiser4/status_flags.h newtree/fs/reiser4/status_flags.h
--- oldtree/fs/reiser4/status_flags.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/status_flags.h	2006-02-21 15:58:34.672875480 +0000
@@ -0,0 +1,43 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Here we declare structures and flags that store reiser4 status on disk.
+   The status that helps us to find out if the filesystem is valid or if it
+   contains some critical, or not so critical errors */
+
+#if !defined( __REISER4_STATUS_FLAGS_H__ )
+#define __REISER4_STATUS_FLAGS_H__
+
+#include "dformat.h"
+/* These are major status flags */
+#define REISER4_STATUS_OK 0
+#define REISER4_STATUS_CORRUPTED 0x1
+#define REISER4_STATUS_DAMAGED 0x2
+#define REISER4_STATUS_DESTROYED 0x4
+#define REISER4_STATUS_IOERROR 0x8
+
+/* Return values for reiser4_status_query() */
+#define REISER4_STATUS_MOUNT_OK 0
+#define REISER4_STATUS_MOUNT_WARN 1
+#define REISER4_STATUS_MOUNT_RO 2
+#define REISER4_STATUS_MOUNT_UNKNOWN -1
+
+#define REISER4_TEXTERROR_LEN 256
+
+#define REISER4_STATUS_MAGIC "ReiSeR4StATusBl"
+/* We probably need to keep its size under sector size which is 512 bytes */
+struct reiser4_status {
+	char magic[16];
+	d64 status;		/* Current FS state */
+	d64 extended_status;	/* Any additional info that might have sense in addition to "status". E.g.
+				   last sector where io error happened if status is "io error encountered" */
+	d64 stacktrace[10];	/* Last ten functional calls made (addresses) */
+	char texterror[REISER4_TEXTERROR_LEN];	/* Any error message if appropriate, otherwise filled with zeroes */
+};
+
+int reiser4_status_init(reiser4_block_nr block);
+int reiser4_status_query(u64 * status, u64 * extended);
+int reiser4_status_write(u64 status, u64 extended_status, char *message);
+int reiser4_status_finish(void);
+
+#endif
diff -urN oldtree/fs/reiser4/super.c newtree/fs/reiser4/super.c
--- oldtree/fs/reiser4/super.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/super.c	2006-02-21 15:58:35.452756920 +0000
@@ -0,0 +1,341 @@
+/* Copyright 2001, 2002, 2003, 2004 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Super-block manipulations. */
+
+#include "debug.h"
+#include "dformat.h"
+#include "key.h"
+#include "plugin/security/perm.h"
+#include "plugin/space/space_allocator.h"
+#include "plugin/plugin.h"
+#include "tree.h"
+#include "vfs_ops.h"
+#include "super.h"
+#include "reiser4.h"
+
+#include <linux/types.h>	/* for __u??  */
+#include <linux/fs.h>		/* for struct super_block  */
+
+
+static __u64 reserved_for_gid(const struct super_block *super, gid_t gid);
+static __u64 reserved_for_uid(const struct super_block *super, uid_t uid);
+static __u64 reserved_for_root(const struct super_block *super);
+
+/* Return reiser4-specific part of super block */
+reiser4_super_info_data *get_super_private_nocheck(const struct super_block *super	/* super block
+											 * queried */ )
+{
+	return (reiser4_super_info_data *) super->s_fs_info;
+}
+
+/* Return reiser4 fstype: value that is returned in ->f_type field by statfs() */
+long statfs_type(const struct super_block *super UNUSED_ARG	/* super block
+								 * queried */ )
+{
+	assert("nikita-448", super != NULL);
+	assert("nikita-449", is_reiser4_super(super));
+	return (long)REISER4_SUPER_MAGIC;
+}
+
+/* functions to read/modify fields of reiser4_super_info_data */
+
+/* get number of blocks in file system */
+__u64 reiser4_block_count(const struct super_block *super	/* super block
+								   queried */ )
+{
+	assert("vs-494", super != NULL);
+	assert("vs-495", is_reiser4_super(super));
+	return get_super_private(super)->block_count;
+}
+
+/*
+ * number of blocks in the current file system
+ */
+__u64 reiser4_current_block_count(void)
+{
+	return get_current_super_private()->block_count;
+}
+
+/* set number of block in filesystem */
+void reiser4_set_block_count(const struct super_block *super, __u64 nr)
+{
+	assert("vs-501", super != NULL);
+	assert("vs-502", is_reiser4_super(super));
+	get_super_private(super)->block_count = nr;
+	/*
+	 * The proper calculation of the reserved space counter (%5 of device
+	 * block counter) we need a 64 bit division which is missing in Linux
+	 * on i386 platform. Because we do not need a precise calculation here
+	 * we can replace a div64 operation by this combination of
+	 * multiplication and shift: 51. / (2^10) == .0498 .
+	 * FIXME: this is a bug. It comes up only for very small filesystems
+	 * which probably are never used. Nevertheless, it is a bug. Number of
+	 * reserved blocks must be not less than maximal number of blocks which
+	 * get grabbed with BA_RESERVED.
+	 */
+	get_super_private(super)->blocks_reserved = ((nr * 51) >> 10);
+}
+
+/* amount of blocks used (allocated for data) in file system */
+__u64 reiser4_data_blocks(const struct super_block *super	/* super block
+								   queried */ )
+{
+	assert("nikita-452", super != NULL);
+	assert("nikita-453", is_reiser4_super(super));
+	return get_super_private(super)->blocks_used;
+}
+
+/* set number of block used in filesystem */
+void reiser4_set_data_blocks(const struct super_block *super, __u64 nr)
+{
+	assert("vs-503", super != NULL);
+	assert("vs-504", is_reiser4_super(super));
+	get_super_private(super)->blocks_used = nr;
+}
+
+/* amount of free blocks in file system */
+__u64 reiser4_free_blocks(const struct super_block *super	/* super block
+								   queried */ )
+{
+	assert("nikita-454", super != NULL);
+	assert("nikita-455", is_reiser4_super(super));
+	return get_super_private(super)->blocks_free;
+}
+
+/* set number of blocks free in filesystem */
+void reiser4_set_free_blocks(const struct super_block *super, __u64 nr)
+{
+	assert("vs-505", super != NULL);
+	assert("vs-506", is_reiser4_super(super));
+	get_super_private(super)->blocks_free = nr;
+}
+
+/* get mkfs unique identifier */
+__u32 reiser4_mkfs_id(const struct super_block *super	/* super block
+							   queried */ )
+{
+	assert("vpf-221", super != NULL);
+	assert("vpf-222", is_reiser4_super(super));
+	return get_super_private(super)->mkfs_id;
+}
+
+/* amount of free blocks in file system */
+__u64 reiser4_free_committed_blocks(const struct super_block *super)
+{
+	assert("vs-497", super != NULL);
+	assert("vs-498", is_reiser4_super(super));
+	return get_super_private(super)->blocks_free_committed;
+}
+
+/* amount of blocks in the file system reserved for @uid and @gid */
+long reiser4_reserved_blocks(const struct super_block *super	/* super block
+								   queried */ ,
+			     uid_t uid /* user id */ ,
+			     gid_t gid /* group id */ )
+{
+	long reserved;
+
+	assert("nikita-456", super != NULL);
+	assert("nikita-457", is_reiser4_super(super));
+
+	reserved = 0;
+	if (REISER4_SUPPORT_GID_SPACE_RESERVATION)
+		reserved += reserved_for_gid(super, gid);
+	if (REISER4_SUPPORT_UID_SPACE_RESERVATION)
+		reserved += reserved_for_uid(super, uid);
+	if (REISER4_SUPPORT_ROOT_SPACE_RESERVATION && (uid == 0))
+		reserved += reserved_for_root(super);
+	return reserved;
+}
+
+/* get/set value of/to grabbed blocks counter */
+__u64 reiser4_grabbed_blocks(const struct super_block * super)
+{
+	assert("zam-512", super != NULL);
+	assert("zam-513", is_reiser4_super(super));
+
+	return get_super_private(super)->blocks_grabbed;
+}
+
+__u64 flush_reserved(const struct super_block * super)
+{
+	assert("vpf-285", super != NULL);
+	assert("vpf-286", is_reiser4_super(super));
+
+	return get_super_private(super)->blocks_flush_reserved;
+}
+
+/* get/set value of/to counter of fake allocated formatted blocks */
+__u64 reiser4_fake_allocated(const struct super_block * super)
+{
+	assert("zam-516", super != NULL);
+	assert("zam-517", is_reiser4_super(super));
+
+	return get_super_private(super)->blocks_fake_allocated;
+}
+
+/* get/set value of/to counter of fake allocated unformatted blocks */
+__u64 reiser4_fake_allocated_unformatted(const struct super_block * super)
+{
+	assert("zam-516", super != NULL);
+	assert("zam-517", is_reiser4_super(super));
+
+	return get_super_private(super)->blocks_fake_allocated_unformatted;
+}
+
+/* get/set value of/to counter of clustered blocks */
+__u64 reiser4_clustered_blocks(const struct super_block * super)
+{
+	assert("edward-601", super != NULL);
+	assert("edward-602", is_reiser4_super(super));
+
+	return get_super_private(super)->blocks_clustered;
+}
+
+/* space allocator used by this file system */
+reiser4_space_allocator *get_space_allocator(const struct super_block * super)
+{
+	assert("nikita-1965", super != NULL);
+	assert("nikita-1966", is_reiser4_super(super));
+	return &get_super_private(super)->space_allocator;
+}
+
+/* return fake inode used to bind formatted nodes in the page cache */
+struct inode *get_super_fake(const struct super_block *super	/* super block
+								   queried */ )
+{
+	assert("nikita-1757", super != NULL);
+	return get_super_private(super)->fake;
+}
+
+/* return fake inode used to bind copied on capture nodes in the page cache */
+struct inode *get_cc_fake(const struct super_block *super	/* super block
+								   queried */ )
+{
+	assert("nikita-1757", super != NULL);
+	return get_super_private(super)->cc;
+}
+
+/* return fake inode used to bind bitmaps and journlal heads */
+struct inode *get_bitmap_fake(const struct super_block *super)
+{
+	assert("nikita-17571", super != NULL);
+	return get_super_private(super)->bitmap;
+}
+
+/* tree used by this file system */
+reiser4_tree *get_tree(const struct super_block * super	/* super block
+							 * queried */ )
+{
+	assert("nikita-460", super != NULL);
+	assert("nikita-461", is_reiser4_super(super));
+	return &get_super_private(super)->tree;
+}
+
+/* Check that @super is (looks like) reiser4 super block. This is mainly for
+   use in assertions. */
+int is_reiser4_super(const struct super_block *super	/* super block
+							 * queried */ )
+{
+	return
+	    super != NULL &&
+	    get_super_private(super) != NULL &&
+	    super->s_op == &(get_super_private(super)->ops.super);
+}
+
+int reiser4_is_set(const struct super_block *super, reiser4_fs_flag f)
+{
+	return test_bit((int)f, &get_super_private(super)->fs_flags);
+}
+
+/* amount of blocks reserved for given group in file system */
+static __u64 reserved_for_gid(const struct super_block *super UNUSED_ARG	/* super
+										 * block
+										 * queried */ ,
+			      gid_t gid UNUSED_ARG /* group id */ )
+{
+	return 0;
+}
+
+/* amount of blocks reserved for given user in file system */
+static __u64 reserved_for_uid(const struct super_block *super UNUSED_ARG	/* super
+										   block
+										   queried */ ,
+			      uid_t uid UNUSED_ARG /* user id */ )
+{
+	return 0;
+}
+
+/* amount of blocks reserved for super user in file system */
+static __u64 reserved_for_root(const struct super_block *super UNUSED_ARG	/* super
+										   block
+										   queried */ )
+{
+	return 0;
+}
+
+/*
+ * true if block number @blk makes sense for the file system at @super.
+ */
+int
+reiser4_blocknr_is_sane_for(const struct super_block *super,
+			    const reiser4_block_nr * blk)
+{
+	reiser4_super_info_data *sbinfo;
+
+	assert("nikita-2957", super != NULL);
+	assert("nikita-2958", blk != NULL);
+
+	if (blocknr_is_fake(blk))
+		return 1;
+
+	sbinfo = get_super_private(super);
+	return *blk < sbinfo->block_count;
+}
+
+/*
+ * true, if block number @blk makes sense for the current file system
+ */
+int reiser4_blocknr_is_sane(const reiser4_block_nr * blk)
+{
+	return reiser4_blocknr_is_sane_for(reiser4_get_current_sb(), blk);
+}
+
+#if REISER4_DEBUG
+
+/* this is caller when unallocated extent pointer is added */
+void inc_unalloc_unfm_ptr(void)
+{
+	reiser4_super_info_data *sbinfo;
+
+	sbinfo = get_super_private(get_current_context()->super);
+	spin_lock_reiser4_super(sbinfo);
+	sbinfo->unalloc_extent_pointers++;
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+/* this is called when unallocated extent is converted to allocated */
+void dec_unalloc_unfm_ptrs(int nr)
+{
+	reiser4_super_info_data *sbinfo;
+
+	sbinfo = get_super_private(get_current_context()->super);
+	spin_lock_reiser4_super(sbinfo);
+	BUG_ON(sbinfo->unalloc_extent_pointers < nr);
+	sbinfo->unalloc_extent_pointers -= nr;
+	spin_unlock_reiser4_super(sbinfo);
+}
+
+
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/super.h newtree/fs/reiser4/super.h
--- oldtree/fs/reiser4/super.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/super.h	2006-02-21 15:58:35.408763608 +0000
@@ -0,0 +1,489 @@
+/* Copyright 2001, 2002, 2003, 2004 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Super-block functions. See super.c for details. */
+
+#if !defined( __REISER4_SUPER_H__ )
+#define __REISER4_SUPER_H__
+
+#include "tree.h"
+#include "entd.h"
+#include "wander.h"
+#include "fsdata.h"
+#include "plugin/object.h"
+#include "plugin/space/space_allocator.h"
+
+/*
+ * Flush algorithms parameters.
+ */
+typedef struct {
+	unsigned relocate_threshold;
+	unsigned relocate_distance;
+	unsigned written_threshold;
+	unsigned scan_maxnodes;
+} flush_params;
+
+typedef enum {
+	/*
+	 * True if this file system doesn't support hard-links (multiple names)
+	 * for directories: this is default UNIX behavior.
+	 *
+	 * If hard-links on directoires are not allowed, file system is Acyclic
+	 * Directed Graph (modulo dot, and dotdot, of course).
+	 *
+	 * This is used by reiser4_link().
+	 */
+	REISER4_ADG = 0,
+	/*
+	 * set if all nodes in internal tree have the same node layout plugin.
+	 * If so, znode_guess_plugin() will return tree->node_plugin in stead
+	 * of guessing plugin by plugin id stored in the node.
+	 */
+	REISER4_ONE_NODE_PLUGIN = 1,
+	/* if set, bsd gid assignment is supported. */
+	REISER4_BSD_GID = 2,
+	/* [mac]_time are 32 bit in inode */
+	REISER4_32_BIT_TIMES = 3,
+	/* allow concurrent flushes */
+	REISER4_MTFLUSH = 4,
+	/* load all bitmap blocks at mount time */
+	REISER4_DONT_LOAD_BITMAP = 5,
+	/* enforce atomicity during write(2) */
+	REISER4_ATOMIC_WRITE = 6,
+	/* don't use write barriers in the log writer code. */
+	REISER4_NO_WRITE_BARRIER = 7
+
+} reiser4_fs_flag;
+
+/*
+ * VFS related operation vectors.
+ */
+typedef struct object_ops {
+	struct super_operations super;
+	struct dentry_operations dentry;
+	struct export_operations export;
+} object_ops;
+
+/* reiser4-specific part of super block
+
+   Locking
+
+   Fields immutable after mount:
+
+    ->oid*
+    ->space*
+    ->default_[ug]id
+    ->mkfs_id
+    ->trace_flags
+    ->debug_flags
+    ->fs_flags
+    ->df_plug
+    ->optimal_io_size
+    ->plug
+    ->flush
+    ->u (bad name)
+    ->txnmgr
+    ->ra_params
+    ->fsuid
+    ->journal_header
+    ->journal_footer
+
+   Fields protected by ->lnode_guard
+
+    ->lnode_htable
+
+   Fields protected by per-super block spin lock
+
+    ->block_count
+    ->blocks_used
+    ->blocks_free
+    ->blocks_free_committed
+    ->blocks_grabbed
+    ->blocks_fake_allocated_unformatted
+    ->blocks_fake_allocated
+    ->blocks_flush_reserved
+    ->eflushed
+    ->blocknr_hint_default
+
+   After journal replaying during mount,
+
+    ->last_committed_tx
+
+   is protected by ->tmgr.commit_semaphore
+
+   Invariants involving this data-type:
+
+      [sb-block-counts]
+      [sb-grabbed]
+      [sb-fake-allocated]
+*/
+struct reiser4_super_info_data {
+	/*
+	 * guard spinlock which protects reiser4 super block fields (currently
+	 * blocks_free, blocks_free_committed)
+	 */
+	spinlock_t guard;
+
+	/* next oid that will be returned by oid_allocate() */
+	oid_t next_to_use;
+	/* total number of used oids */
+	oid_t oids_in_use;
+
+	/* space manager plugin */
+	reiser4_space_allocator space_allocator;
+
+	/* reiser4 internal tree */
+	reiser4_tree tree;
+
+	/*
+	 * default user id used for light-weight files without their own
+	 * stat-data.
+	 */
+	uid_t default_uid;
+
+	/*
+	 * default group id used for light-weight files without their own
+	 * stat-data.
+	 */
+	gid_t default_gid;
+
+	/* mkfs identifier generated at mkfs time. */
+	__u32 mkfs_id;
+	/* amount of blocks in a file system */
+	__u64 block_count;
+
+	/* inviolable reserve */
+	__u64 blocks_reserved;
+
+	/* amount of blocks used by file system data and meta-data. */
+	__u64 blocks_used;
+
+	/*
+	 * amount of free blocks. This is "working" free blocks counter. It is
+	 * like "working" bitmap, please see block_alloc.c for description.
+	 */
+	__u64 blocks_free;
+
+	/*
+	 * free block count for fs committed state. This is "commit" version of
+	 * free block counter.
+	 */
+	__u64 blocks_free_committed;
+
+	/*
+	 * number of blocks reserved for further allocation, for all
+	 * threads.
+	 */
+	__u64 blocks_grabbed;
+
+	/* number of fake allocated unformatted blocks in tree. */
+	__u64 blocks_fake_allocated_unformatted;
+
+	/* number of fake allocated formatted blocks in tree. */
+	__u64 blocks_fake_allocated;
+
+	/* number of blocks reserved for flush operations. */
+	__u64 blocks_flush_reserved;
+
+	/* number of blocks reserved for cluster operations. */
+	__u64 blocks_clustered;
+
+	/* unique file-system identifier */
+	__u32 fsuid;
+
+	/* file-system wide flags. See reiser4_fs_flag enum */
+	unsigned long fs_flags;
+
+	/* transaction manager */
+	txn_mgr tmgr;
+
+	/* ent thread */
+	entd_context entd;
+
+	/* fake inode used to bind formatted nodes */
+	struct inode *fake;
+	/* inode used to bind bitmaps (and journal heads) */
+	struct inode *bitmap;
+	/* inode used to bind copied on capture nodes */
+	struct inode *cc;
+
+	/* disk layout plugin */
+	disk_format_plugin *df_plug;
+
+	/* disk layout specific part of reiser4 super info data */
+	union {
+		format40_super_info format40;
+	} u;
+
+	/* value we return in st_blksize on stat(2) */
+	unsigned long optimal_io_size;
+
+	/* parameters for the flush algorithm */
+	flush_params flush;
+
+#if REISER4_USE_EFLUSH
+	/* see emergency_flush.c for details */
+	spinlock_t eflush_guard;
+	/* number of emergency flushed nodes */
+	int eflushed;
+	/* hash table used by emergency flush. Protected by ->eflush_guard */
+	ef_hash_table efhash_table;
+	__u64 eflushed_unformatted;	/* number of eflushed unformatted nodes */
+#endif
+	/* pointers to jnodes for journal header and footer */
+	jnode *journal_header;
+	jnode *journal_footer;
+
+	journal_location jloc;
+
+	/* head block number of last committed transaction */
+	__u64 last_committed_tx;
+
+	/*
+	 * we remember last written location for using as a hint for new block
+	 * allocation
+	 */
+	__u64 blocknr_hint_default;
+
+	/* committed number of files (oid allocator state variable ) */
+	__u64 nr_files_committed;
+
+	ra_params_t ra_params;
+
+	/*
+	 * A semaphore for serializing cut tree operation if out-of-free-space:
+	 * the only one cut_tree thread is allowed to grab space from reserved
+	 * area (it is 5% of disk space)
+	 */
+	struct semaphore delete_sema;
+	/* task owning ->delete_sema */
+	struct task_struct *delete_sema_owner;
+
+	/* serialize semaphore */
+	struct semaphore flush_sema;
+
+	/* Diskmap's blocknumber */
+	__u64 diskmap_block;
+
+	/* What to do in case of error */
+	int onerror;
+
+	/* operations for objects on this file system */
+	object_ops ops;
+
+	/*
+	 * structure to maintain d_cursors. See plugin/file_ops_readdir.c for
+	 * more details
+	 */
+	d_cursor_info d_info;
+
+#ifdef CONFIG_REISER4_BADBLOCKS
+	/* Alternative master superblock offset (in bytes) */
+	unsigned long altsuper;
+#endif
+	struct repacker *repacker;
+	struct page *status_page;
+	struct bio *status_bio;
+
+#if REISER4_DEBUG
+	/*
+	 * minimum used blocks value (includes super blocks, bitmap blocks and
+	 * other fs reserved areas), depends on fs format and fs size.
+	 */
+	__u64 min_blocks_used;
+
+	/*
+	 * when debugging is on, all jnodes (including znodes, bitmaps, etc.)
+	 * are kept on a list anchored at sbinfo->all_jnodes. This list is
+	 * protected by sbinfo->all_guard spin lock. This lock should be taken
+	 * with _irq modifier, because it is also modified from interrupt
+	 * contexts (by RCU).
+	 */
+	spinlock_t all_guard;
+	/* list of all jnodes */
+	struct list_head all_jnodes;
+	/* number of unallocated extent pointers in the tree */
+	__u64 unalloc_extent_pointers;
+#endif
+};
+
+extern reiser4_super_info_data *get_super_private_nocheck(const struct
+							  super_block *super);
+
+
+/* Return reiser4-specific part of super block */
+static inline reiser4_super_info_data *get_super_private(const struct
+							 super_block *super)
+{
+	assert("nikita-447", super != NULL);
+
+	return (reiser4_super_info_data *) super->s_fs_info;
+}
+
+/* get ent context for the @super */
+static inline entd_context *get_entd_context(struct super_block *super)
+{
+	return &get_super_private(super)->entd;
+}
+
+
+/* "Current" super-block: main super block used during current system
+   call. Reference to this super block is stored in reiser4_context. */
+static inline struct super_block *reiser4_get_current_sb(void)
+{
+	return get_current_context()->super;
+}
+
+/* Reiser4-specific part of "current" super-block: main super block used
+   during current system call. Reference to this super block is stored in
+   reiser4_context. */
+static inline reiser4_super_info_data *get_current_super_private(void)
+{
+	return get_super_private(reiser4_get_current_sb());
+}
+
+static inline ra_params_t *get_current_super_ra_params(void)
+{
+	return &(get_current_super_private()->ra_params);
+}
+
+/*
+ * true, if file system on @super is read-only
+ */
+static inline int rofs_super(struct super_block *super)
+{
+	return super->s_flags & MS_RDONLY;
+}
+
+/*
+ * true, if @tree represents read-only file system
+ */
+static inline int rofs_tree(reiser4_tree * tree)
+{
+	return rofs_super(tree->super);
+}
+
+/*
+ * true, if file system where @inode lives on, is read-only
+ */
+static inline int rofs_inode(struct inode *inode)
+{
+	return rofs_super(inode->i_sb);
+}
+
+/*
+ * true, if file system where @node lives on, is read-only
+ */
+static inline int rofs_jnode(jnode * node)
+{
+	return rofs_tree(jnode_get_tree(node));
+}
+
+extern __u64 reiser4_current_block_count(void);
+
+extern void build_object_ops(struct super_block *super, object_ops * ops);
+
+#define REISER4_SUPER_MAGIC 0x52345362	/* (*(__u32 *)"R4Sb"); */
+
+static inline void spin_lock_reiser4_super(reiser4_super_info_data *sbinfo)
+{
+	spin_lock(&(sbinfo->guard));
+}
+
+static inline void spin_unlock_reiser4_super(reiser4_super_info_data *sbinfo)
+{
+	assert_spin_locked(&(sbinfo->guard));
+	spin_unlock(&(sbinfo->guard));
+}
+
+extern __u64 flush_reserved(const struct super_block *);
+extern int reiser4_is_set(const struct super_block *super, reiser4_fs_flag f);
+extern long statfs_type(const struct super_block *super);
+extern __u64 reiser4_block_count(const struct super_block *super);
+extern void reiser4_set_block_count(const struct super_block *super, __u64 nr);
+extern __u64 reiser4_data_blocks(const struct super_block *super);
+extern void reiser4_set_data_blocks(const struct super_block *super, __u64 nr);
+extern __u64 reiser4_free_blocks(const struct super_block *super);
+extern void reiser4_set_free_blocks(const struct super_block *super, __u64 nr);
+extern __u32 reiser4_mkfs_id(const struct super_block *super);
+
+extern __u64 reiser4_free_committed_blocks(const struct super_block *super);
+
+extern __u64 reiser4_grabbed_blocks(const struct super_block *);
+extern __u64 reiser4_fake_allocated(const struct super_block *);
+extern __u64 reiser4_fake_allocated_unformatted(const struct super_block *);
+extern __u64 reiser4_clustered_blocks(const struct super_block *);
+
+extern long reiser4_reserved_blocks(const struct super_block *super, uid_t uid,
+				    gid_t gid);
+
+extern reiser4_space_allocator *get_space_allocator(const struct super_block
+						    *super);
+extern reiser4_oid_allocator *get_oid_allocator(const struct super_block
+						*super);
+extern struct inode *get_super_fake(const struct super_block *super);
+extern struct inode *get_cc_fake(const struct super_block *super);
+extern struct inode *get_bitmap_fake(const struct super_block *super);
+extern reiser4_tree *get_tree(const struct super_block *super);
+extern int is_reiser4_super(const struct super_block *super);
+
+extern int reiser4_blocknr_is_sane(const reiser4_block_nr * blk);
+extern int reiser4_blocknr_is_sane_for(const struct super_block *super,
+				       const reiser4_block_nr * blk);
+extern int reiser4_fill_super(struct super_block *s, void *data, int silent);
+extern int reiser4_done_super(struct super_block *s);
+
+/* step of fill super */
+extern int init_fs_info(struct super_block *);
+extern void done_fs_info(struct super_block *);
+extern int init_super_data(struct super_block *, char *opt_string);
+extern int init_read_super(struct super_block *, int silent);
+extern int init_root_inode(struct super_block *);
+
+
+/* Maximal possible object id. */
+#define  ABSOLUTE_MAX_OID ((oid_t)~0)
+
+#define OIDS_RESERVED  ( 1 << 16 )
+int oid_init_allocator(struct super_block *, oid_t nr_files, oid_t next);
+oid_t oid_allocate(struct super_block *);
+int oid_release(struct super_block *, oid_t);
+oid_t oid_next(const struct super_block *);
+void oid_count_allocated(void);
+void oid_count_released(void);
+long oids_used(const struct super_block *);
+
+#if REISER4_DEBUG
+void print_fs_info(const char *prefix, const struct super_block *);
+#endif
+
+#if REISER4_DEBUG
+
+void inc_unalloc_unfm_ptr(void);
+void dec_unalloc_unfm_ptrs(int nr);
+
+#else
+
+#define inc_unalloc_unfm_ptr() noop
+#define dec_unalloc_unfm_ptrs(nr) noop
+
+#endif
+
+extern void destroy_reiser4_cache(kmem_cache_t **);
+
+extern struct super_operations reiser4_super_operations;
+extern struct export_operations reiser4_export_operations;
+extern struct dentry_operations reiser4_dentry_operations;
+
+/* __REISER4_SUPER_H__ */
+#endif
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 120
+ * End:
+ */
diff -urN oldtree/fs/reiser4/super_ops.c newtree/fs/reiser4/super_ops.c
--- oldtree/fs/reiser4/super_ops.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/super_ops.c	2006-02-21 15:58:35.020822584 +0000
@@ -0,0 +1,707 @@
+/* Copyright 2005 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+#include "inode.h"
+#include "page_cache.h"
+#include "ktxnmgrd.h"
+#include "flush.h"
+#include "emergency_flush.h"
+#include "safe_link.h"
+
+#include <linux/vfs.h>
+#include <linux/writeback.h>
+#include <linux/mount.h>
+#include <linux/seq_file.h>
+
+/* slab cache for inodes */
+static kmem_cache_t *inode_cache;
+
+/**
+ * init_once - constructor for reiser4 inodes
+ * @obj: inode to be initialized
+ * @cache: cache @obj belongs to
+ * @flags: SLAB flags
+ *
+ * Initialization function to be called when new page is allocated by reiser4
+ * inode cache. It is set on inode cache creation.
+ */
+static void init_once(void *obj, kmem_cache_t *cache, unsigned long flags)
+{
+	reiser4_inode_object *info;
+
+	info = obj;
+
+	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		/* initialize vfs inode */
+		inode_init_once(&info->vfs_inode);
+
+		/*
+		 * initialize reiser4 specific part fo inode.
+		 * NOTE-NIKITA add here initializations for locks, list heads,
+		 * etc. that will be added to our private inode part.
+		 */
+		INIT_LIST_HEAD(get_readdir_list(&info->vfs_inode));
+		init_rwsem(&info->p.coc_sem);
+		/* init semaphore which is used during inode loading */
+		loading_init_once(&info->p);
+		INIT_RADIX_TREE(jnode_tree_by_reiser4_inode(&info->p),
+				GFP_ATOMIC);
+#if REISER4_DEBUG
+		info->p.nr_jnodes = 0;
+#endif
+	}
+}
+
+/**
+ * init_inodes - create znode cache
+ *
+ * Initializes slab cache of inodes. It is part of reiser4 module initialization.
+ */
+static int init_inodes(void)
+{
+	inode_cache = kmem_cache_create("reiser4_inode",
+					sizeof(reiser4_inode_object),
+					0,
+					SLAB_HWCACHE_ALIGN |
+					SLAB_RECLAIM_ACCOUNT, init_once, NULL);
+	if (inode_cache == NULL)
+		return RETERR(-ENOMEM);
+	return 0;
+}
+
+/**
+ * done_inodes - delete inode cache
+ *
+ * This is called on reiser4 module unloading or system shutdown.
+ */
+static void done_inodes(void)
+{
+	destroy_reiser4_cache(&inode_cache);
+}
+
+/**
+ * reiser4_alloc_inode - alloc_inode of super operations
+ * @super: super block new inode is allocated for
+ *
+ * Allocates new inode, initializes reiser4 specific part of it.
+ */
+static struct inode *reiser4_alloc_inode(struct super_block *super)
+{
+	reiser4_inode_object *obj;
+
+	assert("nikita-1696", super != NULL);
+	obj = kmem_cache_alloc(inode_cache, SLAB_KERNEL);
+	if (obj != NULL) {
+		reiser4_inode *info;
+
+		info = &obj->p;
+
+		info->hset = info->pset = plugin_set_get_empty();
+		info->extmask = 0;
+		info->locality_id = 0ull;
+		info->plugin_mask = 0;
+#if !REISER4_INO_IS_OID
+		info->oid_hi = 0;
+#endif
+		seal_init(&info->sd_seal, NULL, NULL);
+		coord_init_invalid(&info->sd_coord, NULL);
+		info->flags = 0;
+		spin_lock_init(&info->guard);
+		/* this deals with info's loading semaphore */
+		loading_alloc(info);
+		info->vroot = UBER_TREE_ADDR;
+		return &obj->vfs_inode;
+	} else
+		return NULL;
+}
+
+/**
+ * reiser4_destroy_inode - destroy_inode of super operations
+ * @inode: inode being destroyed
+ *
+ * Puts reiser4 specific portion of inode, frees memory occupied by inode.
+ */
+static void reiser4_destroy_inode(struct inode *inode)
+{
+	reiser4_inode *info;
+
+	info = reiser4_inode_data(inode);
+
+	assert("vs-1220", inode_has_no_jnodes(info));
+
+	if (!is_bad_inode(inode) && is_inode_loaded(inode)) {
+		file_plugin *fplug = inode_file_plugin(inode);
+		if (fplug->destroy_inode != NULL)
+			fplug->destroy_inode(inode);
+	}
+	dispose_cursors(inode);
+	if (info->pset)
+		plugin_set_put(info->pset);
+
+	/*
+	 * cannot add similar assertion about ->i_list as prune_icache return
+	 * inode into slab with dangling ->list.{next,prev}. This is safe,
+	 * because they are re-initialized in the new_inode().
+	 */
+	assert("nikita-2895", list_empty(&inode->i_dentry));
+	assert("nikita-2896", hlist_unhashed(&inode->i_hash));
+	assert("nikita-2898", list_empty_careful(get_readdir_list(inode)));
+
+	/* this deals with info's loading semaphore */
+	loading_destroy(info);
+
+	kmem_cache_free(inode_cache,
+			container_of(info, reiser4_inode_object, p));
+}
+
+/**
+ * reiser4_dirty_inode - dirty_inode of super operations
+ * @inode: inode being dirtied
+ *
+ * Updates stat data.
+ */
+static void reiser4_dirty_inode(struct inode *inode)
+{
+	int result;
+
+	if (!is_in_reiser4_context())
+		return;
+	assert("", !IS_RDONLY(inode));
+	assert("", (inode_file_plugin(inode)->estimate.update(inode) <=
+		    get_current_context()->grabbed_blocks));
+
+	result = reiser4_update_sd(inode);
+	if (result)
+		warning("", "failed to dirty inode for %llu: %d",
+			get_inode_oid(inode), result);
+}
+
+/**
+ * reiser4_delete_inode - delete_inode of super operations
+ * @inode: inode to delete
+ *
+ * Calls file plugin's delete_object method to delete object items from
+ * filesystem tree and calls clear_inode.
+ */
+static void reiser4_delete_inode(struct inode *inode)
+{
+	reiser4_context *ctx;
+	file_plugin *fplug;
+
+	ctx = init_context(inode->i_sb);
+	if (IS_ERR(ctx)) {
+		warning("vs-15", "failed to init context");
+		return;
+	}
+
+	if (is_inode_loaded(inode)) {
+		fplug = inode_file_plugin(inode);
+		if (fplug != NULL && fplug->delete_object != NULL)
+			fplug->delete_object(inode);
+	}
+
+	inode->i_blocks = 0;
+	clear_inode(inode);
+	reiser4_exit_context(ctx);
+}
+
+/**
+ * reiser4_put_super - put_super of super operations
+ * @super: super block to free
+ *
+ * Stops daemons, release resources, umounts in short.
+ */
+static void reiser4_put_super(struct super_block *super)
+{
+	reiser4_super_info_data *sbinfo;
+	reiser4_context *ctx;
+
+	sbinfo = get_super_private(super);
+	assert("vs-1699", sbinfo);
+
+	ctx = init_context(super);
+	if (IS_ERR(ctx)) {
+		warning("vs-17", "failed to init context");
+		return;
+	}
+
+	/* have disk format plugin to free its resources */
+	if (get_super_private(super)->df_plug->release)
+		get_super_private(super)->df_plug->release(super);
+
+	done_formatted_fake(super);
+
+	/* stop daemons: ktxnmgr and entd */
+	done_entd(super);
+	done_ktxnmgrd(super);
+	done_txnmgr(&sbinfo->tmgr);
+
+	done_fs_info(super);
+	reiser4_exit_context(ctx);
+}
+
+/**
+ * reiser4_write_super - write_super of super operations
+ * @super: super block to write
+ *
+ * Captures znode associated with super block, comit all transactions.
+ */
+static void reiser4_write_super(struct super_block *super)
+{
+	int ret;
+	reiser4_context *ctx;
+
+	assert("vs-1700", !rofs_super(super));
+
+	ctx = init_context(super);
+	if (IS_ERR(ctx)) {
+		warning("vs-16", "failed to init context");
+		return;
+	}
+
+	ret = capture_super_block(super);
+	if (ret != 0)
+		warning("vs-1701",
+			"capture_super_block failed in write_super: %d", ret);
+	ret = txnmgr_force_commit_all(super, 1);
+	if (ret != 0)
+		warning("jmacd-77113",
+			"txn_force failed in write_super: %d", ret);
+
+	super->s_dirt = 0;
+
+	reiser4_exit_context(ctx);
+}
+
+/**
+ * reiser4_statfs - statfs of super operations
+ * @super: super block of file system in queried
+ * @stafs: buffer to fill with statistics
+ *
+ * Returns information about filesystem.
+ */
+static int reiser4_statfs(struct super_block *super, struct kstatfs *statfs)
+{
+	sector_t total;
+	sector_t reserved;
+	sector_t free;
+	sector_t forroot;
+	sector_t deleted;
+	reiser4_context *ctx;
+
+	assert("nikita-408", super != NULL);
+	assert("nikita-409", statfs != NULL);
+
+	ctx = init_context(super);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	statfs->f_type = statfs_type(super);
+	statfs->f_bsize = super->s_blocksize;
+
+	/*
+	 * 5% of total block space is reserved. This is needed for flush and
+	 * for truncates (so that we are able to perform truncate/unlink even
+	 * on the otherwise completely full file system). If this reservation
+	 * is hidden from statfs(2), users will mistakenly guess that they
+	 * have enough free space to complete some operation, which is
+	 * frustrating.
+	 *
+	 * Another possible solution is to subtract ->blocks_reserved from
+	 * ->f_bfree, but changing available space seems less intrusive than
+	 * letting user to see 5% of disk space to be used directly after
+	 * mkfs.
+	 */
+	total = reiser4_block_count(super);
+	reserved = get_super_private(super)->blocks_reserved;
+	deleted = txnmgr_count_deleted_blocks();
+	free = reiser4_free_blocks(super) + deleted;
+	forroot = reiser4_reserved_blocks(super, 0, 0);
+
+	/*
+	 * These counters may be in inconsistent state because we take the
+	 * values without keeping any global spinlock.  Here we do a sanity
+	 * check that free block counter does not exceed the number of all
+	 * blocks.
+	 */
+	if (free > total)
+		free = total;
+	statfs->f_blocks = total - reserved;
+	/* make sure statfs->f_bfree is never larger than statfs->f_blocks */
+	if (free > reserved)
+		free -= reserved;
+	else
+		free = 0;
+	statfs->f_bfree = free;
+
+	if (free > forroot)
+		free -= forroot;
+	else
+		free = 0;
+	statfs->f_bavail = free;
+
+	statfs->f_files = 0;
+	statfs->f_ffree = 0;
+
+	/* maximal acceptable name length depends on directory plugin. */
+	assert("nikita-3351", super->s_root->d_inode != NULL);
+	statfs->f_namelen = reiser4_max_filename_len(super->s_root->d_inode);
+	reiser4_exit_context(ctx);
+	return 0;
+}
+
+/**
+ * reiser4_clear_inode - clear_inode of super operation
+ * @inode: inode about to destroy
+ *
+ * Does sanity checks: being destroyed should have all jnodes detached.
+ */
+static void reiser4_clear_inode(struct inode *inode)
+{
+#if REISER4_DEBUG
+	reiser4_inode *r4_inode;
+
+	r4_inode = reiser4_inode_data(inode);
+	if (!inode_has_no_jnodes(r4_inode))
+		warning("vs-1732", "reiser4 inode has %ld jnodes\n",
+			r4_inode->nr_jnodes);
+#endif
+}
+
+/**
+ * reiser4_sync_inodes - sync_inodes of super operations
+ * @super:
+ * @wbc:
+ *
+ * This method is called by background and non-backgound writeback. Reiser4's
+ * implementation uses generic_sync_sb_inodes to call reiser4_writepages for
+ * each of dirty inodes. Reiser4_writepages handles pages dirtied via shared
+ * mapping - dirty pages get into atoms. Writeout is called to flush some
+ * atoms.
+ */
+static void reiser4_sync_inodes(struct super_block *super,
+				struct writeback_control *wbc)
+{
+	reiser4_context *ctx;
+	long to_write;
+
+	if (wbc->for_kupdate)
+		/* reiser4 has its own means of periodical write-out */
+		return;
+
+	to_write = wbc->nr_to_write;
+	assert("vs-49", wbc->older_than_this == NULL);
+
+	ctx = init_context(super);
+	if (IS_ERR(ctx)) {
+		warning("vs-13", "failed to init context");
+		return;
+	}
+
+	/*
+	 * call reiser4_writepages for each of dirty inodes to turn dirty pages
+	 * into transactions if they were not yet.
+	 */
+	generic_sync_sb_inodes(super, wbc);
+
+	/* flush goes here */
+	wbc->nr_to_write = to_write;
+	writeout(super, wbc);
+
+	/* avoid recursive calls to ->sync_inodes */
+	context_set_commit_async(ctx);
+	reiser4_exit_context(ctx);
+}
+
+/**
+ * reiser4_show_options - show_options of super operations
+ * @m: file where to write information
+ * @mnt: mount structure
+ *
+ * Makes reiser4 mount options visible in /proc/mounts.
+ */
+static int reiser4_show_options(struct seq_file *m, struct vfsmount *mnt)
+{
+	struct super_block *super;
+	reiser4_super_info_data *sbinfo;
+
+	super = mnt->mnt_sb;
+	sbinfo = get_super_private(super);
+
+	seq_printf(m, ",atom_max_size=0x%x", sbinfo->tmgr.atom_max_size);
+	seq_printf(m, ",atom_max_age=0x%x", sbinfo->tmgr.atom_max_age);
+	seq_printf(m, ",atom_min_size=0x%x", sbinfo->tmgr.atom_min_size);
+	seq_printf(m, ",atom_max_flushers=0x%x",
+		   sbinfo->tmgr.atom_max_flushers);
+	seq_printf(m, ",cbk_cache_slots=0x%x",
+		   sbinfo->tree.cbk_cache.nr_slots);
+
+	return 0;
+}
+
+struct super_operations reiser4_super_operations = {
+	.alloc_inode = reiser4_alloc_inode,
+	.destroy_inode = reiser4_destroy_inode,
+	.dirty_inode = reiser4_dirty_inode,
+	.delete_inode = reiser4_delete_inode,
+	.put_super = reiser4_put_super,
+	.write_super = reiser4_write_super,
+	.statfs = reiser4_statfs,
+	.clear_inode = reiser4_clear_inode,
+	.sync_inodes = reiser4_sync_inodes,
+	.show_options = reiser4_show_options
+};
+
+/**
+ * fill_super - initialize super block on mount
+ * @super: super block to fill
+ * @data: reiser4 specific mount option
+ * @silent:
+ *
+ * This is to be called by reiser4_get_sb. Mounts filesystem.
+ */
+static int fill_super(struct super_block *super, void *data, int silent)
+{
+	reiser4_context ctx;
+	int result;
+	reiser4_super_info_data *sbinfo;
+
+	assert("zam-989", super != NULL);
+
+	super->s_op = NULL;
+	init_stack_context(&ctx, super);
+
+	/* allocate reiser4 specific super block */
+	if ((result = init_fs_info(super)) != 0)
+		goto failed_init_sinfo;
+
+	sbinfo = get_super_private(super);
+	/* initialize various reiser4 parameters, parse mount options */
+	if ((result = init_super_data(super, data)) != 0)
+		goto failed_init_super_data;
+
+	/* read reiser4 master super block, initialize disk format plugin */
+	if ((result = init_read_super(super, silent)) != 0)
+		goto failed_init_read_super;
+
+	/* initialize transaction manager */
+	init_txnmgr(&sbinfo->tmgr);
+
+	/* initialize ktxnmgrd context and start kernel thread ktxnmrgd */
+	if ((result = init_ktxnmgrd(super)) != 0)
+		goto failed_init_ktxnmgrd;
+
+	/* initialize entd context and start kernel thread entd */
+	if ((result = init_entd(super)) != 0)
+		goto failed_init_entd;
+
+	/* initialize address spaces for formatted nodes and bitmaps */
+	if ((result = init_formatted_fake(super)) != 0)
+		goto failed_init_formatted_fake;
+
+	/* initialize disk format plugin */
+	if ((result = get_super_private(super)->df_plug->init_format(super, data)) != 0 )
+		goto failed_init_disk_format;
+
+	/*
+	 * There are some 'committed' versions of reiser4 super block counters,
+	 * which correspond to reiser4 on-disk state. These counters are
+	 * initialized here
+	 */
+	sbinfo->blocks_free_committed = sbinfo->blocks_free;
+	sbinfo->nr_files_committed = oids_used(super);
+
+	/* get inode of root directory */
+	if ((result = init_root_inode(super)) != 0)
+		goto failed_init_root_inode;
+
+	process_safelinks(super);
+	reiser4_exit_context(&ctx);
+	return 0;
+
+ failed_init_root_inode:
+	if (sbinfo->df_plug->release)
+		sbinfo->df_plug->release(super);
+ failed_init_disk_format:
+	done_formatted_fake(super);
+ failed_init_formatted_fake:
+	done_entd(super);
+ failed_init_entd:
+	done_ktxnmgrd(super);
+ failed_init_ktxnmgrd:
+	done_txnmgr(&sbinfo->tmgr);
+ failed_init_read_super:
+ failed_init_super_data:
+	done_fs_info(super);
+ failed_init_sinfo:
+	reiser4_exit_context(&ctx);
+	return result;
+}
+
+/**
+ * reiser4_get_sb - get_sb of file_system_type operations
+ * @fs_type:
+ * @flags: mount flags MS_RDONLY, MS_VERBOSE, etc
+ * @dev_name: block device file name
+ * @data: specific mount options
+ *
+ * Reiser4 mount entry.
+ */
+static struct super_block *reiser4_get_sb(struct file_system_type *fs_type,
+					  int flags,
+					  const char *dev_name,
+					  void *data)
+{
+	return get_sb_bdev(fs_type, flags, dev_name, data, fill_super);
+}
+
+/* structure describing the reiser4 filesystem implementation */
+static struct file_system_type reiser4_fs_type = {
+	.owner = THIS_MODULE,
+	.name = "reiser4",
+	.fs_flags = FS_REQUIRES_DEV,
+	.get_sb = reiser4_get_sb,
+	.kill_sb = kill_block_super,
+	.next = NULL
+};
+
+void destroy_reiser4_cache(kmem_cache_t **cachep)
+{
+	int result;
+
+	BUG_ON(*cachep == NULL);
+	result = kmem_cache_destroy(*cachep);
+	BUG_ON(result != 0);
+	*cachep = NULL;
+}
+
+/**
+ * init_reiser4 - reiser4 initialization entry point
+ *
+ * Initializes reiser4 slabs, registers reiser4 filesystem type. It is called
+ * on kernel initialization or during reiser4 module load.
+ */
+static int __init init_reiser4(void)
+{
+	int result;
+
+	printk(KERN_INFO
+	       "Loading Reiser4. "
+	       "See www.namesys.com for a description of Reiser4.\n");
+
+	/* initialize slab cache of inodes */
+	if ((result = init_inodes()) != 0)
+		goto failed_inode_cache;
+
+	/* initialize cache of znodes */
+	if ((result = init_znodes()) != 0)
+		goto failed_init_znodes;
+
+	/* initialize all plugins */
+	if ((result = init_plugins()) != 0)
+		goto failed_init_plugins;
+
+	/* initialize cache of plugin_set-s and plugin_set's hash table */
+	if ((result = init_plugin_set()) != 0)
+		goto failed_init_plugin_set;
+
+	/* initialize caches of txn_atom-s and txn_handle-s */
+	if ((result = init_txnmgr_static()) != 0)
+		goto failed_init_txnmgr_static;
+
+	/* initialize cache of jnodes */
+	if ((result = init_jnodes()) != 0)
+		goto failed_init_jnodes;
+
+	/* initialize cache of eflush nodes */
+	if ((result = init_eflush()) != 0)
+		goto failed_init_eflush;
+
+	/* initialize cache of flush queues */
+	if ((result = init_fqs()) != 0)
+		goto failed_init_fqs;
+
+	/* initialize cache of structures attached to dentry->d_fsdata */
+	if ((result = init_dentry_fsdata()) != 0)
+		goto failed_init_dentry_fsdata;
+
+	/* initialize cache of structures attached to file->private_data */
+	if ((result = init_file_fsdata()) != 0)
+		goto failed_init_file_fsdata;
+
+	/*
+	 * initialize cache of d_cursors. See plugin/file_ops_readdir.c for
+	 * more details
+	 */
+	if ((result = init_d_cursor()) != 0)
+		goto failed_init_d_cursor;
+
+	if ((result = register_filesystem(&reiser4_fs_type)) == 0)
+		return 0;
+
+	done_d_cursor();
+ failed_init_d_cursor:
+	done_file_fsdata();
+ failed_init_file_fsdata:
+	done_dentry_fsdata();
+ failed_init_dentry_fsdata:
+	done_fqs();
+ failed_init_fqs:
+	done_eflush();
+ failed_init_eflush:
+	done_jnodes();
+ failed_init_jnodes:
+	done_txnmgr_static();
+ failed_init_txnmgr_static:
+	done_plugin_set();
+ failed_init_plugin_set:
+ failed_init_plugins:
+	done_znodes();
+ failed_init_znodes:
+	done_inodes();
+ failed_inode_cache:
+	return result;
+}
+
+/**
+ * done_reiser4 - reiser4 exit entry point
+ *
+ * Unregister reiser4 filesystem type, deletes caches. It is called on shutdown
+ * or at module unload.
+ */
+static void __exit done_reiser4(void)
+{
+	int result;
+
+	result = unregister_filesystem(&reiser4_fs_type);
+	BUG_ON(result != 0);
+	done_d_cursor();
+	done_file_fsdata();
+	done_dentry_fsdata();
+	done_fqs();
+	done_eflush();
+	done_jnodes();
+	done_txnmgr_static();
+	done_plugin_set();
+	done_znodes();
+	destroy_reiser4_cache(&inode_cache);
+}
+
+module_init(init_reiser4);
+module_exit(done_reiser4);
+
+MODULE_DESCRIPTION("Reiser4 filesystem");
+MODULE_AUTHOR("Hans Reiser <Reiser@Namesys.COM>");
+
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * End:
+ */
diff -urN oldtree/fs/reiser4/tap.c newtree/fs/reiser4/tap.c
--- oldtree/fs/reiser4/tap.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/tap.c	2006-02-21 15:58:34.675875024 +0000
@@ -0,0 +1,377 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/*
+   Tree Access Pointer (tap).
+
+   tap is data structure combining coord and lock handle (mostly). It is
+   useful when one has to scan tree nodes (for example, in readdir, or flush),
+   for tap functions allow to move tap in either direction transparently
+   crossing unit/item/node borders.
+
+   Tap doesn't provide automatic synchronization of its fields as it is
+   supposed to be per-thread object.
+*/
+
+#include "forward.h"
+#include "debug.h"
+#include "coord.h"
+#include "tree.h"
+#include "context.h"
+#include "tap.h"
+#include "znode.h"
+#include "tree_walk.h"
+
+#if REISER4_DEBUG
+static int tap_invariant(const tap_t * tap);
+static void tap_check(const tap_t * tap);
+#else
+#define tap_check(tap) noop
+#endif
+
+/** load node tap is pointing to, if not loaded already */
+int tap_load(tap_t * tap)
+{
+	tap_check(tap);
+	if (tap->loaded == 0) {
+		int result;
+
+		result = zload_ra(tap->coord->node, &tap->ra_info);
+		if (result != 0)
+			return result;
+		coord_clear_iplug(tap->coord);
+	}
+	++tap->loaded;
+	tap_check(tap);
+	return 0;
+}
+
+/** release node tap is pointing to. Dual to tap_load() */
+void tap_relse(tap_t * tap)
+{
+	tap_check(tap);
+	if (tap->loaded > 0) {
+		--tap->loaded;
+		if (tap->loaded == 0) {
+			zrelse(tap->coord->node);
+		}
+	}
+	tap_check(tap);
+}
+
+/**
+ * init tap to consist of @coord and @lh. Locks on nodes will be acquired with
+ * @mode
+ */
+void
+tap_init(tap_t * tap, coord_t * coord, lock_handle * lh, znode_lock_mode mode)
+{
+	tap->coord = coord;
+	tap->lh = lh;
+	tap->mode = mode;
+	tap->loaded = 0;
+	INIT_LIST_HEAD(&tap->linkage);
+	init_ra_info(&tap->ra_info);
+}
+
+/** add @tap to the per-thread list of all taps */
+void tap_monitor(tap_t * tap)
+{
+	assert("nikita-2623", tap != NULL);
+	tap_check(tap);
+	list_add(&tap->linkage, taps_list());
+	tap_check(tap);
+}
+
+/* duplicate @src into @dst. Copy lock handle. @dst is not initially
+ * loaded. */
+void tap_copy(tap_t * dst, tap_t * src)
+{
+	assert("nikita-3193", src != NULL);
+	assert("nikita-3194", dst != NULL);
+
+	*dst->coord = *src->coord;
+	if (src->lh->node)
+		copy_lh(dst->lh, src->lh);
+	dst->mode = src->mode;
+	dst->loaded = 0;
+	INIT_LIST_HEAD(&dst->linkage);
+	dst->ra_info = src->ra_info;
+}
+
+/** finish with @tap */
+void tap_done(tap_t * tap)
+{
+	assert("nikita-2565", tap != NULL);
+	tap_check(tap);
+	if (tap->loaded > 0)
+		zrelse(tap->coord->node);
+	done_lh(tap->lh);
+	tap->loaded = 0;
+	list_del_init(&tap->linkage);
+	tap->coord->node = NULL;
+}
+
+/**
+ * move @tap to the new node, locked with @target. Load @target, if @tap was
+ * already loaded.
+ */
+int tap_move(tap_t * tap, lock_handle * target)
+{
+	int result = 0;
+
+	assert("nikita-2567", tap != NULL);
+	assert("nikita-2568", target != NULL);
+	assert("nikita-2570", target->node != NULL);
+	assert("nikita-2569", tap->coord->node == tap->lh->node);
+
+	tap_check(tap);
+	if (tap->loaded > 0)
+		result = zload_ra(target->node, &tap->ra_info);
+
+	if (result == 0) {
+		if (tap->loaded > 0)
+			zrelse(tap->coord->node);
+		done_lh(tap->lh);
+		copy_lh(tap->lh, target);
+		tap->coord->node = target->node;
+		coord_clear_iplug(tap->coord);
+	}
+	tap_check(tap);
+	return result;
+}
+
+/**
+ * move @tap to @target. Acquire lock on @target, if @tap was already
+ * loaded.
+ */
+static int tap_to(tap_t * tap, znode * target)
+{
+	int result;
+
+	assert("nikita-2624", tap != NULL);
+	assert("nikita-2625", target != NULL);
+
+	tap_check(tap);
+	result = 0;
+	if (tap->coord->node != target) {
+		lock_handle here;
+
+		init_lh(&here);
+		result = longterm_lock_znode(&here, target,
+					     tap->mode, ZNODE_LOCK_HIPRI);
+		if (result == 0) {
+			result = tap_move(tap, &here);
+			done_lh(&here);
+		}
+	}
+	tap_check(tap);
+	return result;
+}
+
+/**
+ * move @tap to given @target, loading and locking @target->node if
+ * necessary
+ */
+int tap_to_coord(tap_t * tap, coord_t * target)
+{
+	int result;
+
+	tap_check(tap);
+	result = tap_to(tap, target->node);
+	if (result == 0)
+		coord_dup(tap->coord, target);
+	tap_check(tap);
+	return result;
+}
+
+/** return list of all taps */
+struct list_head *taps_list(void)
+{
+	return &get_current_context()->taps;
+}
+
+/** helper function for go_{next,prev}_{item,unit,node}() */
+int go_dir_el(tap_t * tap, sideof dir, int units_p)
+{
+	coord_t dup;
+	coord_t *coord;
+	int result;
+
+	int (*coord_dir) (coord_t *);
+	int (*get_dir_neighbor) (lock_handle *, znode *, int, int);
+	void (*coord_init) (coord_t *, const znode *);
+	ON_DEBUG(int (*coord_check) (const coord_t *));
+
+	assert("nikita-2556", tap != NULL);
+	assert("nikita-2557", tap->coord != NULL);
+	assert("nikita-2558", tap->lh != NULL);
+	assert("nikita-2559", tap->coord->node != NULL);
+
+	tap_check(tap);
+	if (dir == LEFT_SIDE) {
+		coord_dir = units_p ? coord_prev_unit : coord_prev_item;
+		get_dir_neighbor = reiser4_get_left_neighbor;
+		coord_init = coord_init_last_unit;
+	} else {
+		coord_dir = units_p ? coord_next_unit : coord_next_item;
+		get_dir_neighbor = reiser4_get_right_neighbor;
+		coord_init = coord_init_first_unit;
+	}
+	ON_DEBUG(coord_check =
+		 units_p ? coord_is_existing_unit : coord_is_existing_item);
+	assert("nikita-2560", coord_check(tap->coord));
+
+	coord = tap->coord;
+	coord_dup(&dup, coord);
+	if (coord_dir(&dup) != 0) {
+		do {
+			/* move to the left neighboring node */
+			lock_handle dup;
+
+			init_lh(&dup);
+			result =
+			    get_dir_neighbor(&dup, coord->node, (int)tap->mode,
+					     GN_CAN_USE_UPPER_LEVELS);
+			if (result == 0) {
+				result = tap_move(tap, &dup);
+				if (result == 0)
+					coord_init(tap->coord, dup.node);
+				done_lh(&dup);
+			}
+			/* skip empty nodes */
+		} while ((result == 0) && node_is_empty(coord->node));
+	} else {
+		result = 0;
+		coord_dup(coord, &dup);
+	}
+	assert("nikita-2564", ergo(!result, coord_check(tap->coord)));
+	tap_check(tap);
+	return result;
+}
+
+/**
+ * move @tap to the next unit, transparently crossing item and node
+ * boundaries
+ */
+int go_next_unit(tap_t * tap)
+{
+	return go_dir_el(tap, RIGHT_SIDE, 1);
+}
+
+/**
+ * move @tap to the previous unit, transparently crossing item and node
+ * boundaries
+ */
+int go_prev_unit(tap_t * tap)
+{
+	return go_dir_el(tap, LEFT_SIDE, 1);
+}
+
+/**
+ * @shift times apply @actor to the @tap. This is used to move @tap by
+ * @shift units (or items, or nodes) in either direction.
+ */
+static int rewind_to(tap_t * tap, go_actor_t actor, int shift)
+{
+	int result;
+
+	assert("nikita-2555", shift >= 0);
+	assert("nikita-2562", tap->coord->node == tap->lh->node);
+
+	tap_check(tap);
+	result = tap_load(tap);
+	if (result != 0)
+		return result;
+
+	for (; shift > 0; --shift) {
+		result = actor(tap);
+		assert("nikita-2563", tap->coord->node == tap->lh->node);
+		if (result != 0)
+			break;
+	}
+	tap_relse(tap);
+	tap_check(tap);
+	return result;
+}
+
+/** move @tap @shift units rightward */
+int rewind_right(tap_t * tap, int shift)
+{
+	return rewind_to(tap, go_next_unit, shift);
+}
+
+/** move @tap @shift units leftward */
+int rewind_left(tap_t * tap, int shift)
+{
+	return rewind_to(tap, go_prev_unit, shift);
+}
+
+#if REISER4_DEBUG
+/** debugging function: print @tap content in human readable form */
+static void print_tap(const char *prefix, const tap_t * tap)
+{
+	if (tap == NULL) {
+		printk("%s: null tap\n", prefix);
+		return;
+	}
+	printk("%s: loaded: %i, in-list: %i, node: %p, mode: %s\n", prefix,
+	       tap->loaded, (&tap->linkage == tap->linkage.next &&
+			     &tap->linkage == tap->linkage.prev),
+	       tap->lh->node,
+	       lock_mode_name(tap->mode));
+	print_coord("\tcoord", tap->coord, 0);
+}
+
+/** check [tap-sane] invariant */
+static int tap_invariant(const tap_t * tap)
+{
+	/* [tap-sane] invariant */
+
+	if (tap == NULL)
+		return 1;
+	/* tap->mode is one of
+	 *
+	 * {ZNODE_NO_LOCK, ZNODE_READ_LOCK, ZNODE_WRITE_LOCK}, and
+	 */
+	if (tap->mode != ZNODE_NO_LOCK &&
+	    tap->mode != ZNODE_READ_LOCK && tap->mode != ZNODE_WRITE_LOCK)
+		return 2;
+	/* tap->coord != NULL, and */
+	if (tap->coord == NULL)
+		return 3;
+	/* tap->lh != NULL, and */
+	if (tap->lh == NULL)
+		return 4;
+	/* tap->loaded > 0 => znode_is_loaded(tap->coord->node), and */
+	if (!ergo(tap->loaded, znode_is_loaded(tap->coord->node)))
+		return 5;
+	/* tap->coord->node == tap->lh->node if tap->lh->node is not 0 */
+	if (tap->lh->node != NULL && tap->coord->node != tap->lh->node)
+		return 6;
+	return 0;
+}
+
+/** debugging function: check internal @tap consistency */
+static void tap_check(const tap_t * tap)
+{
+	int result;
+
+	result = tap_invariant(tap);
+	if (result != 0) {
+		print_tap("broken", tap);
+		reiser4_panic("nikita-2831", "tap broken: %i\n", result);
+	}
+}
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/tap.h newtree/fs/reiser4/tap.h
--- oldtree/fs/reiser4/tap.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/tap.h	2006-02-21 15:58:34.676874872 +0000
@@ -0,0 +1,69 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* Tree Access Pointers. See tap.c for more details. */
+
+#if !defined( __REISER4_TAP_H__ )
+#define __REISER4_TAP_H__
+
+#include "forward.h"
+#include "readahead.h"
+
+/**
+    tree_access_pointer aka tap. Data structure combining coord_t and lock
+    handle.
+    Invariants involving this data-type, see doc/lock-ordering for details:
+
+      [tap-sane]
+ */
+struct tree_access_pointer {
+	/* coord tap is at */
+	coord_t *coord;
+	/* lock handle on ->coord->node */
+	lock_handle *lh;
+	/* mode of lock acquired by this tap */
+	znode_lock_mode mode;
+	/* incremented by tap_load(). Decremented by tap_relse(). */
+	int loaded;
+	/* list of taps */
+	struct list_head linkage;
+	/* read-ahead hint */
+	ra_info_t ra_info;
+};
+
+typedef int (*go_actor_t) (tap_t * tap);
+
+extern int tap_load(tap_t * tap);
+extern void tap_relse(tap_t * tap);
+extern void tap_init(tap_t * tap, coord_t * coord, lock_handle * lh,
+		     znode_lock_mode mode);
+extern void tap_monitor(tap_t * tap);
+extern void tap_copy(tap_t * dst, tap_t * src);
+extern void tap_done(tap_t * tap);
+extern int tap_move(tap_t * tap, lock_handle * target);
+extern int tap_to_coord(tap_t * tap, coord_t * target);
+
+extern int go_dir_el(tap_t * tap, sideof dir, int units_p);
+extern int go_next_unit(tap_t * tap);
+extern int go_prev_unit(tap_t * tap);
+extern int rewind_right(tap_t * tap, int shift);
+extern int rewind_left(tap_t * tap, int shift);
+
+extern struct list_head *taps_list(void);
+
+#define for_all_taps(tap)						\
+	for (tap = list_entry(taps_list()->next, tap_t, linkage);	\
+	     taps_list() != &tap->linkage;				\
+	     tap = list_entry(tap->linkage.next, tap_t, linkage))
+
+/* __REISER4_TAP_H__ */
+#endif
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/tree.c newtree/fs/reiser4/tree.c
--- oldtree/fs/reiser4/tree.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/tree.c	2006-02-21 15:58:35.453756768 +0000
@@ -0,0 +1,1882 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/*
+ * KEYS IN A TREE.
+ *
+ * The tree consists of nodes located on the disk. Node in the tree is either
+ * formatted or unformatted. Formatted node is one that has structure
+ * understood by the tree balancing and traversal code. Formatted nodes are
+ * further classified into leaf and internal nodes. Latter distinctions is
+ * (almost) of only historical importance: general structure of leaves and
+ * internal nodes is the same in Reiser4. Unformatted nodes contain raw data
+ * that are part of bodies of ordinary files and attributes.
+ *
+ * Each node in the tree spawns some interval in the key space. Key ranges for
+ * all nodes in the tree are disjoint. Actually, this only holds in some weak
+ * sense, because of the non-unique keys: intersection of key ranges for
+ * different nodes is either empty, or consists of exactly one key.
+ *
+ * Formatted node consists of a sequence of items. Each item spawns some
+ * interval in key space. Key ranges for all items in a tree are disjoint,
+ * modulo non-unique keys again. Items within nodes are ordered in the key
+ * order of the smallest key in a item.
+ *
+ * Particular type of item can be further split into units. Unit is piece of
+ * item that can be cut from item and moved into another item of the same
+ * time. Units are used by balancing code to repack data during balancing.
+ *
+ * Unit can be further split into smaller entities (for example, extent unit
+ * represents several pages, and it is natural for extent code to operate on
+ * particular pages and even bytes within one unit), but this is of no
+ * relevance to the generic balancing and lookup code.
+ *
+ * Although item is said to "spawn" range or interval of keys, it is not
+ * necessary that item contains piece of data addressable by each and every
+ * key in this range. For example, compound directory item, consisting of
+ * units corresponding to directory entries and keyed by hashes of file names,
+ * looks more as having "discrete spectrum": only some disjoint keys inside
+ * range occupied by this item really address data.
+ *
+ * No than less, each item always has well-defined least (minimal) key, that
+ * is recorded in item header, stored in the node this item is in. Also, item
+ * plugin can optionally define method ->max_key_inside() returning maximal
+ * key that can _possibly_ be located within this item. This method is used
+ * (mainly) to determine when given piece of data should be merged into
+ * existing item, in stead of creating new one. Because of this, even though
+ * ->max_key_inside() can be larger that any key actually located in the item,
+ * intervals
+ *
+ * [ min_key( item ), ->max_key_inside( item ) ]
+ *
+ * are still disjoint for all items within the _same_ node.
+ *
+ * In memory node is represented by znode. It plays several roles:
+ *
+ *  . something locks are taken on
+ *
+ *  . something tracked by transaction manager (this is going to change)
+ *
+ *  . something used to access node data
+ *
+ *  . something used to maintain tree structure in memory: sibling and
+ *  parental linkage.
+ *
+ *  . something used to organize nodes into "slums"
+ *
+ * More on znodes see in znode.[ch]
+ *
+ * DELIMITING KEYS
+ *
+ *   To simplify balancing, allow some flexibility in locking and speed up
+ *   important coord cache optimization, we keep delimiting keys of nodes in
+ *   memory. Depending on disk format (implemented by appropriate node plugin)
+ *   node on disk can record both left and right delimiting key, only one of
+ *   them, or none. Still, our balancing and tree traversal code keep both
+ *   delimiting keys for a node that is in memory stored in the znode. When
+ *   node is first brought into memory during tree traversal, its left
+ *   delimiting key is taken from its parent, and its right delimiting key is
+ *   either next key in its parent, or is right delimiting key of parent if
+ *   node is the rightmost child of parent.
+ *
+ *   Physical consistency of delimiting key is protected by special dk
+ *   read-write lock. That is, delimiting keys can only be inspected or
+ *   modified under this lock. But dk lock is only sufficient for fast
+ *   "pessimistic" check, because to simplify code and to decrease lock
+ *   contention, balancing (carry) only updates delimiting keys right before
+ *   unlocking all locked nodes on the given tree level. For example,
+ *   coord-by-key cache scans LRU list of recently accessed znodes. For each
+ *   node it first does fast check under dk spin lock. If key looked for is
+ *   not between delimiting keys for this node, next node is inspected and so
+ *   on. If key is inside of the key range, long term lock is taken on node
+ *   and key range is rechecked.
+ *
+ * COORDINATES
+ *
+ *   To find something in the tree, you supply a key, and the key is resolved
+ *   by coord_by_key() into a coord (coordinate) that is valid as long as the
+ *   node the coord points to remains locked.  As mentioned above trees
+ *   consist of nodes that consist of items that consist of units. A unit is
+ *   the smallest and indivisible piece of tree as far as balancing and tree
+ *   search are concerned. Each node, item, and unit can be addressed by
+ *   giving its level in the tree and the key occupied by this entity.  A node
+ *   knows what the key ranges are of the items within it, and how to find its
+ *   items and invoke their item handlers, but it does not know how to access
+ *   individual units within its items except through the item handlers.
+ *   coord is a structure containing a pointer to the node, the ordinal number
+ *   of the item within this node (a sort of item offset), and the ordinal
+ *   number of the unit within this item.
+ *
+ * TREE LOOKUP
+ *
+ *   There are two types of access to the tree: lookup and modification.
+ *
+ *   Lookup is a search for the key in the tree. Search can look for either
+ *   exactly the key given to it, or for the largest key that is not greater
+ *   than the key given to it. This distinction is determined by "bias"
+ *   parameter of search routine (coord_by_key()). coord_by_key() either
+ *   returns error (key is not in the tree, or some kind of external error
+ *   occurred), or successfully resolves key into coord.
+ *
+ *   This resolution is done by traversing tree top-to-bottom from root level
+ *   to the desired level. On levels above twig level (level one above the
+ *   leaf level) nodes consist exclusively of internal items. Internal item is
+ *   nothing more than pointer to the tree node on the child level. On twig
+ *   level nodes consist of internal items intermixed with extent
+ *   items. Internal items form normal search tree structure used by traversal
+ *   to descent through the tree.
+ *
+ * TREE LOOKUP OPTIMIZATIONS
+ *
+ * Tree lookup described above is expensive even if all nodes traversed are
+ * already in the memory: for each node binary search within it has to be
+ * performed and binary searches are CPU consuming and tend to destroy CPU
+ * caches.
+ *
+ * Several optimizations are used to work around this:
+ *
+ *   . cbk_cache (look-aside cache for tree traversals, see search.c for
+ *   details)
+ *
+ *   . seals (see seal.[ch])
+ *
+ *   . vroot (see search.c)
+ *
+ * General search-by-key is layered thusly:
+ *
+ *                   [check seal, if any]   --ok--> done
+ *                           |
+ *                         failed
+ *                           |
+ *                           V
+ *                     [vroot defined] --no--> node = tree_root
+ *                           |                   |
+ *                          yes                  |
+ *                           |                   |
+ *                           V                   |
+ *                       node = vroot            |
+ *                                 |             |
+ *                                 |             |
+ *                                 |             |
+ *                                 V             V
+ *                            [check cbk_cache for key]  --ok--> done
+ *                                        |
+ *                                      failed
+ *                                        |
+ *                                        V
+ *                       [start tree traversal from node]
+ *
+ */
+
+#include "forward.h"
+#include "debug.h"
+#include "dformat.h"
+#include "key.h"
+#include "coord.h"
+#include "plugin/item/static_stat.h"
+#include "plugin/item/item.h"
+#include "plugin/node/node.h"
+#include "plugin/plugin.h"
+#include "txnmgr.h"
+#include "jnode.h"
+#include "znode.h"
+#include "block_alloc.h"
+#include "tree_walk.h"
+#include "carry.h"
+#include "carry_ops.h"
+#include "tap.h"
+#include "tree.h"
+#include "vfs_ops.h"
+#include "page_cache.h"
+#include "super.h"
+#include "reiser4.h"
+#include "inode.h"
+
+#include <linux/fs.h>		/* for struct super_block  */
+#include <linux/spinlock.h>
+
+/* Disk address (block number) never ever used for any real tree node. This is
+   used as block number of "uber" znode.
+
+   Invalid block addresses are 0 by tradition.
+
+*/
+const reiser4_block_nr UBER_TREE_ADDR = 0ull;
+
+#define CUT_TREE_MIN_ITERATIONS 64
+
+static int find_child_by_addr(znode * parent, znode * child, coord_t * result);
+
+/* return node plugin of coord->node */
+node_plugin *node_plugin_by_coord(const coord_t * coord)
+{
+	assert("vs-1", coord != NULL);
+	assert("vs-2", coord->node != NULL);
+
+	return coord->node->nplug;
+}
+
+/* insert item into tree. Fields of @coord are updated so that they can be
+ * used by consequent insert operation. */
+insert_result insert_by_key(reiser4_tree * tree	/* tree to insert new item
+						 * into */ ,
+			    const reiser4_key * key /* key of new item */ ,
+			    reiser4_item_data * data	/* parameters for item
+							 * creation */ ,
+			    coord_t * coord /* resulting insertion coord */ ,
+			    lock_handle * lh	/* resulting lock
+						 * handle */ ,
+			    tree_level stop_level /** level where to insert */ ,
+			    __u32 flags /* insertion flags */ )
+{
+	int result;
+
+	assert("nikita-358", tree != NULL);
+	assert("nikita-360", coord != NULL);
+
+	result = coord_by_key(tree, key, coord, lh, ZNODE_WRITE_LOCK,
+			      FIND_EXACT, stop_level, stop_level,
+			      flags | CBK_FOR_INSERT, NULL /*ra_info */ );
+	switch (result) {
+	default:
+		break;
+	case CBK_COORD_FOUND:
+		result = IBK_ALREADY_EXISTS;
+		break;
+	case CBK_COORD_NOTFOUND:
+		assert("nikita-2017", coord->node != NULL);
+		result = insert_by_coord(coord, data, key, lh, 0 /*flags */ );
+		break;
+	}
+	return result;
+}
+
+/* insert item by calling carry. Helper function called if short-cut
+   insertion failed  */
+static insert_result insert_with_carry_by_coord(coord_t * coord,	/* coord where to insert */
+						lock_handle * lh,	/* lock handle of insertion
+									 * node */
+						reiser4_item_data * data,	/* parameters of new
+										 * item */
+						const reiser4_key * key,	/* key of new item */
+						carry_opcode cop,	/* carry operation to perform */
+						cop_insert_flag flags
+						/* carry flags */ )
+{
+	int result;
+	carry_pool *pool;
+	carry_level *lowest_level;
+	carry_insert_data *cdata;
+	carry_op *op;
+
+	assert("umka-314", coord != NULL);
+
+	/* allocate carry_pool and 3 carry_level-s */
+	pool =
+	    init_carry_pool(sizeof(*pool) + 3 * sizeof(*lowest_level) +
+			    sizeof(*cdata));
+	if (IS_ERR(pool))
+		return PTR_ERR(pool);
+	lowest_level = (carry_level *) (pool + 1);
+	init_carry_level(lowest_level, pool);
+
+	op = post_carry(lowest_level, cop, coord->node, 0);
+	if (IS_ERR(op) || (op == NULL)) {
+		done_carry_pool(pool);
+		return RETERR(op ? PTR_ERR(op) : -EIO);
+	}
+	cdata = (carry_insert_data *) (lowest_level + 3);
+	cdata->coord = coord;
+	cdata->data = data;
+	cdata->key = key;
+	op->u.insert.d = cdata;
+	if (flags == 0)
+		flags = znode_get_tree(coord->node)->carry.insert_flags;
+	op->u.insert.flags = flags;
+	op->u.insert.type = COPT_ITEM_DATA;
+	op->u.insert.child = NULL;
+	if (lh != NULL) {
+		assert("nikita-3245", lh->node == coord->node);
+		lowest_level->track_type = CARRY_TRACK_CHANGE;
+		lowest_level->tracked = lh;
+	}
+
+	result = carry(lowest_level, NULL);
+	done_carry_pool(pool);
+
+	return result;
+}
+
+/* form carry queue to perform paste of @data with @key at @coord, and launch
+   its execution by calling carry().
+
+   Instruct carry to update @lh it after balancing insertion coord moves into
+   different block.
+
+*/
+static int paste_with_carry(coord_t * coord,	/* coord of paste */
+			    lock_handle * lh,	/* lock handle of node
+						 * where item is
+						 * pasted */
+			    reiser4_item_data * data,	/* parameters of new
+							 * item */
+			    const reiser4_key * key,	/* key of new item */
+			    unsigned flags /* paste flags */ )
+{
+	int result;
+	carry_pool *pool;
+	carry_level *lowest_level;
+	carry_insert_data *cdata;
+	carry_op *op;
+
+	assert("umka-315", coord != NULL);
+	assert("umka-316", key != NULL);
+
+	pool =
+	    init_carry_pool(sizeof(*pool) + 3 * sizeof(*lowest_level) +
+			    sizeof(*cdata));
+	if (IS_ERR(pool))
+		return PTR_ERR(pool);
+	lowest_level = (carry_level *) (pool + 1);
+	init_carry_level(lowest_level, pool);
+
+	op = post_carry(lowest_level, COP_PASTE, coord->node, 0);
+	if (IS_ERR(op) || (op == NULL)) {
+		done_carry_pool(pool);
+		return RETERR(op ? PTR_ERR(op) : -EIO);
+	}
+	cdata = (carry_insert_data *) (lowest_level + 3);
+	cdata->coord = coord;
+	cdata->data = data;
+	cdata->key = key;
+	op->u.paste.d = cdata;
+	if (flags == 0)
+		flags = znode_get_tree(coord->node)->carry.paste_flags;
+	op->u.paste.flags = flags;
+	op->u.paste.type = COPT_ITEM_DATA;
+	if (lh != NULL) {
+		lowest_level->track_type = CARRY_TRACK_CHANGE;
+		lowest_level->tracked = lh;
+	}
+
+	result = carry(lowest_level, NULL);
+	done_carry_pool(pool);
+
+	return result;
+}
+
+/* insert item at the given coord.
+
+   First try to skip carry by directly calling ->create_item() method of node
+   plugin. If this is impossible (there is not enough free space in the node,
+   or leftmost item in the node is created), call insert_with_carry_by_coord()
+   that will do full carry().
+
+*/
+insert_result insert_by_coord(coord_t * coord	/* coord where to
+						 * insert. coord->node has
+						 * to be write locked by
+						 * caller */ ,
+			      reiser4_item_data * data	/* data to be
+							 * inserted */ ,
+			      const reiser4_key * key /* key of new item */ ,
+			      lock_handle * lh	/* lock handle of write
+						 * lock on node */ ,
+			      __u32 flags /* insertion flags */ )
+{
+	unsigned item_size;
+	int result;
+	znode *node;
+
+	assert("vs-247", coord != NULL);
+	assert("vs-248", data != NULL);
+	assert("vs-249", data->length >= 0);
+	assert("nikita-1191", znode_is_write_locked(coord->node));
+
+	node = coord->node;
+	coord_clear_iplug(coord);
+	result = zload(node);
+	if (result != 0)
+		return result;
+
+	item_size = space_needed(node, NULL, data, 1);
+	if (item_size > znode_free_space(node) &&
+	    (flags & COPI_DONT_SHIFT_LEFT) && (flags & COPI_DONT_SHIFT_RIGHT)
+	    && (flags & COPI_DONT_ALLOCATE)) {
+		/* we are forced to use free space of coord->node and new item
+		   does not fit into it.
+
+		   Currently we get here only when we allocate and copy units
+		   of extent item from a node to its left neighbor during
+		   "squalloc"-ing.  If @node (this is left neighbor) does not
+		   have enough free space - we do not want to attempt any
+		   shifting and allocations because we are in squeezing and
+		   everything to the left of @node is tightly packed.
+		 */
+		result = -E_NODE_FULL;
+	} else if ((item_size <= znode_free_space(node)) &&
+		   !coord_is_before_leftmost(coord) &&
+		   (node_plugin_by_node(node)->fast_insert != NULL)
+		   && node_plugin_by_node(node)->fast_insert(coord)) {
+		/* shortcut insertion without carry() overhead.
+
+		   Only possible if:
+
+		   - there is enough free space
+
+		   - insertion is not into the leftmost position in a node
+		   (otherwise it would require updating of delimiting key in a
+		   parent)
+
+		   - node plugin agrees with this
+
+		 */
+		result =
+		    node_plugin_by_node(node)->create_item(coord, key, data,
+							   NULL);
+		znode_make_dirty(node);
+	} else {
+		/* otherwise do full-fledged carry(). */
+		result =
+		    insert_with_carry_by_coord(coord, lh, data, key, COP_INSERT,
+					       flags);
+	}
+	zrelse(node);
+	return result;
+}
+
+/* @coord is set to leaf level and @data is to be inserted to twig level */
+insert_result
+insert_extent_by_coord(coord_t *
+		       coord
+		       /* coord where to insert. coord->node * has to be write * locked by caller */
+		       ,
+		       reiser4_item_data * data /* data to be inserted */ ,
+		       const reiser4_key * key /* key of new item */ ,
+		       lock_handle *
+		       lh /* lock handle of write lock on * node */ )
+{
+	assert("vs-405", coord != NULL);
+	assert("vs-406", data != NULL);
+	assert("vs-407", data->length > 0);
+	assert("vs-408", znode_is_write_locked(coord->node));
+	assert("vs-409", znode_get_level(coord->node) == LEAF_LEVEL);
+
+	return insert_with_carry_by_coord(coord, lh, data, key, COP_EXTENT,
+					  0 /*flags */ );
+}
+
+/* Insert into the item at the given coord.
+
+   First try to skip carry by directly calling ->paste() method of item
+   plugin. If this is impossible (there is not enough free space in the node,
+   or we are pasting into leftmost position in the node), call
+   paste_with_carry() that will do full carry().
+
+*/
+/* paste_into_item */
+int insert_into_item(coord_t * coord /* coord of pasting */ ,
+		     lock_handle * lh /* lock handle on node involved */ ,
+		     const reiser4_key * key /* key of unit being pasted */ ,
+		     reiser4_item_data * data /* parameters for new unit */ ,
+		     unsigned flags /* insert/paste flags */ )
+{
+	int result;
+	int size_change;
+	node_plugin *nplug;
+	item_plugin *iplug;
+
+	assert("umka-317", coord != NULL);
+	assert("umka-318", key != NULL);
+
+	iplug = item_plugin_by_coord(coord);
+	nplug = node_plugin_by_coord(coord);
+
+	assert("nikita-1480", iplug == data->iplug);
+
+	size_change = space_needed(coord->node, coord, data, 0);
+	if (size_change > (int)znode_free_space(coord->node) &&
+	    (flags & COPI_DONT_SHIFT_LEFT) && (flags & COPI_DONT_SHIFT_RIGHT)
+	    && (flags & COPI_DONT_ALLOCATE)) {
+		/* we are forced to use free space of coord->node and new data
+		   does not fit into it. */
+		return -E_NODE_FULL;
+	}
+
+	/* shortcut paste without carry() overhead.
+
+	   Only possible if:
+
+	   - there is enough free space
+
+	   - paste is not into the leftmost unit in a node (otherwise
+	   it would require updating of delimiting key in a parent)
+
+	   - node plugin agrees with this
+
+	   - item plugin agrees with us
+	 */
+	if (size_change <= (int)znode_free_space(coord->node) &&
+	    (coord->item_pos != 0 ||
+	     coord->unit_pos != 0 || coord->between == AFTER_UNIT) &&
+	    coord->unit_pos != 0 && nplug->fast_paste != NULL &&
+	    nplug->fast_paste(coord) &&
+	    iplug->b.fast_paste != NULL && iplug->b.fast_paste(coord)) {
+		if (size_change > 0)
+			nplug->change_item_size(coord, size_change);
+		/* NOTE-NIKITA: huh? where @key is used? */
+		result = iplug->b.paste(coord, data, NULL);
+		if (size_change < 0)
+			nplug->change_item_size(coord, size_change);
+		znode_make_dirty(coord->node);
+	} else
+		/* otherwise do full-fledged carry(). */
+		result = paste_with_carry(coord, lh, data, key, flags);
+	return result;
+}
+
+/* this either appends or truncates item @coord */
+int resize_item(coord_t * coord /* coord of item being resized */ ,
+		reiser4_item_data * data /* parameters of resize */ ,
+		reiser4_key * key /* key of new unit */ ,
+		lock_handle * lh	/* lock handle of node
+					 * being modified */ ,
+		cop_insert_flag flags /* carry flags */ )
+{
+	int result;
+	znode *node;
+
+	assert("nikita-362", coord != NULL);
+	assert("nikita-363", data != NULL);
+	assert("vs-245", data->length != 0);
+
+	node = coord->node;
+	coord_clear_iplug(coord);
+	result = zload(node);
+	if (result != 0)
+		return result;
+
+	if (data->length < 0)
+		result = node_plugin_by_coord(coord)->shrink_item(coord,
+								  data->length);
+	else
+		result = insert_into_item(coord, lh, key, data, flags);
+
+	zrelse(node);
+	return result;
+}
+
+/* insert flow @f */
+int insert_flow(coord_t * coord, lock_handle * lh, flow_t * f)
+{
+	int result;
+	carry_pool *pool;
+	carry_level *lowest_level;
+	reiser4_item_data *data;
+	carry_op *op;
+
+	pool =
+	    init_carry_pool(sizeof(*pool) + 3 * sizeof(*lowest_level) +
+			    sizeof(*data));
+	if (IS_ERR(pool))
+		return PTR_ERR(pool);
+	lowest_level = (carry_level *) (pool + 1);
+	init_carry_level(lowest_level, pool);
+
+	op = post_carry(lowest_level, COP_INSERT_FLOW, coord->node,
+			0 /* operate directly on coord -> node */ );
+	if (IS_ERR(op) || (op == NULL)) {
+		done_carry_pool(pool);
+		return RETERR(op ? PTR_ERR(op) : -EIO);
+	}
+
+	/* these are permanent during insert_flow */
+	data = (reiser4_item_data *) (lowest_level + 3);
+	data->user = 1;
+	data->iplug = item_plugin_by_id(FORMATTING_ID);
+	data->arg = NULL;
+	/* data.length and data.data will be set before calling paste or
+	   insert */
+	data->length = 0;
+	data->data = NULL;
+
+	op->u.insert_flow.flags = 0;
+	op->u.insert_flow.insert_point = coord;
+	op->u.insert_flow.flow = f;
+	op->u.insert_flow.data = data;
+	op->u.insert_flow.new_nodes = 0;
+
+	lowest_level->track_type = CARRY_TRACK_CHANGE;
+	lowest_level->tracked = lh;
+
+	result = carry(lowest_level, NULL);
+	done_carry_pool(pool);
+
+	return result;
+}
+
+/* Given a coord in parent node, obtain a znode for the corresponding child */
+znode *child_znode(const coord_t * parent_coord	/* coord of pointer to
+						 * child */ ,
+		   znode * parent /* parent of child */ ,
+		   int incore_p	/* if !0 only return child if already in
+				 * memory */ ,
+		   int setup_dkeys_p	/* if !0 update delimiting keys of
+					 * child */ )
+{
+	znode *child;
+
+	assert("nikita-1374", parent_coord != NULL);
+	assert("nikita-1482", parent != NULL);
+#if REISER4_DEBUG
+	if (setup_dkeys_p)
+		assert_rw_not_locked(&(znode_get_tree(parent)->dk_lock));
+#endif
+	assert("nikita-2947", znode_is_any_locked(parent));
+
+	if (znode_get_level(parent) <= LEAF_LEVEL) {
+		/* trying to get child of leaf node */
+		warning("nikita-1217", "Child of maize?");
+		return ERR_PTR(RETERR(-EIO));
+	}
+	if (item_is_internal(parent_coord)) {
+		reiser4_block_nr addr;
+		item_plugin *iplug;
+		reiser4_tree *tree;
+
+		iplug = item_plugin_by_coord(parent_coord);
+		assert("vs-512", iplug->s.internal.down_link);
+		iplug->s.internal.down_link(parent_coord, NULL, &addr);
+
+		tree = znode_get_tree(parent);
+		if (incore_p)
+			child = zlook(tree, &addr);
+		else
+			child =
+			    zget(tree, &addr, parent,
+				 znode_get_level(parent) - 1, GFP_KERNEL);
+		if ((child != NULL) && !IS_ERR(child) && setup_dkeys_p)
+			set_child_delimiting_keys(parent, parent_coord, child);
+	} else {
+		warning("nikita-1483", "Internal item expected");
+		child = ERR_PTR(RETERR(-EIO));
+	}
+	return child;
+}
+
+/* remove znode from transaction */
+static void uncapture_znode(znode * node)
+{
+	struct page *page;
+
+	assert("zam-1001", ZF_ISSET(node, JNODE_HEARD_BANSHEE));
+
+	/* Get e-flush block allocation back before deallocating node's
+	 * block number. */
+	spin_lock_znode(node);
+	if (ZF_ISSET(node, JNODE_EFLUSH))
+		eflush_del(ZJNODE(node), 0);
+	spin_unlock_znode(node);
+
+	if (!blocknr_is_fake(znode_get_block(node))) {
+		int ret;
+
+		/* An already allocated block goes right to the atom's delete set. */
+		ret =
+		    reiser4_dealloc_block(znode_get_block(node), 0,
+					  BA_DEFER | BA_FORMATTED);
+		if (ret)
+			warning("zam-942",
+				"can\'t add a block (%llu) number to atom's delete set\n",
+				(unsigned long long)(*znode_get_block(node)));
+
+		spin_lock_znode(node);
+		/* Here we return flush reserved block which was reserved at the
+		 * moment when this allocated node was marked dirty and still
+		 * not used by flush in node relocation procedure.  */
+		if (ZF_ISSET(node, JNODE_FLUSH_RESERVED)) {
+			txn_atom *atom;
+
+			atom = jnode_get_atom(ZJNODE(node));
+			assert("zam-939", atom != NULL);
+			spin_unlock_znode(node);
+			flush_reserved2grabbed(atom, (__u64) 1);
+			spin_unlock_atom(atom);
+		} else
+			spin_unlock_znode(node);
+	} else {
+		/* znode has assigned block which is counted as "fake
+		   allocated". Return it back to "free blocks") */
+		fake_allocated2free((__u64) 1, BA_FORMATTED);
+	}
+
+	/*
+	 * uncapture page from transaction. There is a possibility of a race
+	 * with ->releasepage(): reiser4_releasepage() detaches page from this
+	 * jnode and we have nothing to uncapture. To avoid this, get
+	 * reference of node->pg under jnode spin lock. uncapture_page() will
+	 * deal with released page itself.
+	 */
+	spin_lock_znode(node);
+	page = znode_page(node);
+	if (likely(page != NULL)) {
+		/*
+		 * uncapture_page() can only be called when we are sure that
+		 * znode is pinned in memory, which we are, because
+		 * forget_znode() is only called from longterm_unlock_znode().
+		 */
+		page_cache_get(page);
+		spin_unlock_znode(node);
+		lock_page(page);
+		uncapture_page(page);
+		unlock_page(page);
+		page_cache_release(page);
+	} else {
+		txn_atom *atom;
+
+		/* handle "flush queued" znodes */
+		while (1) {
+			atom = jnode_get_atom(ZJNODE(node));
+			assert("zam-943", atom != NULL);
+
+			if (!ZF_ISSET(node, JNODE_FLUSH_QUEUED)
+			    || !atom->nr_running_queues)
+				break;
+
+			spin_unlock_znode(node);
+			atom_wait_event(atom);
+			spin_lock_znode(node);
+		}
+
+		uncapture_block(ZJNODE(node));
+		spin_unlock_atom(atom);
+		zput(node);
+	}
+}
+
+/* This is called from longterm_unlock_znode() when last lock is released from
+   the node that has been removed from the tree. At this point node is removed
+   from sibling list and its lock is invalidated. */
+void forget_znode(lock_handle * handle)
+{
+	znode *node;
+	reiser4_tree *tree;
+
+	assert("umka-319", handle != NULL);
+
+	node = handle->node;
+	tree = znode_get_tree(node);
+
+	assert("vs-164", znode_is_write_locked(node));
+	assert("nikita-1280", ZF_ISSET(node, JNODE_HEARD_BANSHEE));
+	assert_rw_locked(&(node->lock.guard));
+
+	/* We assume that this node was detached from its parent before
+	 * unlocking, it gives no way to reach this node from parent through a
+	 * down link.  The node should have no children and, thereby, can't be
+	 * reached from them by their parent pointers.  The only way to obtain a
+	 * reference to the node is to use sibling pointers from its left and
+	 * right neighbors.  In the next several lines we remove the node from
+	 * the sibling list. */
+
+	write_lock_tree(tree);
+	sibling_list_remove(node);
+	znode_remove(node, tree);
+	write_unlock_tree(tree);
+
+	/* Here we set JNODE_DYING and cancel all pending lock requests.  It
+	 * forces all lock requestor threads to repeat iterations of getting
+	 * lock on a child, neighbor or parent node.  But, those threads can't
+	 * come to this node again, because this node is no longer a child,
+	 * neighbor or parent of any other node.  This order of znode
+	 * invalidation does not allow other threads to waste cpu time is a busy
+	 * loop, trying to lock dying object.  The exception is in the flush
+	 * code when we take node directly from atom's capture list.*/
+	invalidate_lock(handle);
+	uncapture_znode(node);
+}
+
+/* Check that internal item at @pointer really contains pointer to @child. */
+int check_tree_pointer(const coord_t * pointer	/* would-be pointer to
+						 * @child */ ,
+		       const znode * child /* child znode */ )
+{
+	assert("nikita-1016", pointer != NULL);
+	assert("nikita-1017", child != NULL);
+	assert("nikita-1018", pointer->node != NULL);
+
+	assert("nikita-1325", znode_is_any_locked(pointer->node));
+
+	assert("nikita-2985",
+	       znode_get_level(pointer->node) == znode_get_level(child) + 1);
+
+	coord_clear_iplug((coord_t *) pointer);
+
+	if (coord_is_existing_unit(pointer)) {
+		item_plugin *iplug;
+		reiser4_block_nr addr;
+
+		if (item_is_internal(pointer)) {
+			iplug = item_plugin_by_coord(pointer);
+			assert("vs-513", iplug->s.internal.down_link);
+			iplug->s.internal.down_link(pointer, NULL, &addr);
+			/* check that cached value is correct */
+			if (disk_addr_eq(&addr, znode_get_block(child))) {
+				return NS_FOUND;
+			}
+		}
+	}
+	/* warning ("jmacd-1002", "tree pointer incorrect"); */
+	return NS_NOT_FOUND;
+}
+
+/* find coord of pointer to new @child in @parent.
+
+   Find the &coord_t in the @parent where pointer to a given @child will
+   be in.
+
+*/
+int find_new_child_ptr(znode * parent /* parent znode, passed locked */ ,
+		       znode *
+		       child UNUSED_ARG /* child znode, passed locked */ ,
+		       znode * left /* left brother of new node */ ,
+		       coord_t * result /* where result is stored in */ )
+{
+	int ret;
+
+	assert("nikita-1486", parent != NULL);
+	assert("nikita-1487", child != NULL);
+	assert("nikita-1488", result != NULL);
+
+	ret = find_child_ptr(parent, left, result);
+	if (ret != NS_FOUND) {
+		warning("nikita-1489", "Cannot find brother position: %i", ret);
+		return RETERR(-EIO);
+	} else {
+		result->between = AFTER_UNIT;
+		return RETERR(NS_NOT_FOUND);
+	}
+}
+
+/* find coord of pointer to @child in @parent.
+
+   Find the &coord_t in the @parent where pointer to a given @child is in.
+
+*/
+int find_child_ptr(znode * parent /* parent znode, passed locked */ ,
+		   znode * child /* child znode, passed locked */ ,
+		   coord_t * result /* where result is stored in */ )
+{
+	int lookup_res;
+	node_plugin *nplug;
+	/* left delimiting key of a child */
+	reiser4_key ld;
+	reiser4_tree *tree;
+
+	assert("nikita-934", parent != NULL);
+	assert("nikita-935", child != NULL);
+	assert("nikita-936", result != NULL);
+	assert("zam-356", znode_is_loaded(parent));
+
+	coord_init_zero(result);
+	result->node = parent;
+
+	nplug = parent->nplug;
+	assert("nikita-939", nplug != NULL);
+
+	tree = znode_get_tree(parent);
+	/* NOTE-NIKITA taking read-lock on tree here assumes that @result is
+	 * not aliased to ->in_parent of some znode. Otherwise,
+	 * parent_coord_to_coord() below would modify data protected by tree
+	 * lock. */
+	read_lock_tree(tree);
+	/* fast path. Try to use cached value. Lock tree to keep
+	   node->pos_in_parent and pos->*_blocknr consistent. */
+	if (child->in_parent.item_pos + 1 != 0) {
+		parent_coord_to_coord(&child->in_parent, result);
+		if (check_tree_pointer(result, child) == NS_FOUND) {
+			read_unlock_tree(tree);
+			return NS_FOUND;
+		}
+
+		child->in_parent.item_pos = (unsigned short)~0;
+	}
+	read_unlock_tree(tree);
+
+	/* is above failed, find some key from @child. We are looking for the
+	   least key in a child. */
+	read_lock_dk(tree);
+	ld = *znode_get_ld_key(child);
+	read_unlock_dk(tree);
+	/*
+	 * now, lookup parent with key just found. Note, that left delimiting
+	 * key doesn't identify node uniquely, because (in extremely rare
+	 * case) two nodes can have equal left delimiting keys, if one of them
+	 * is completely filled with directory entries that all happened to be
+	 * hash collision. But, we check block number in check_tree_pointer()
+	 * and, so, are safe.
+	 */
+	lookup_res = nplug->lookup(parent, &ld, FIND_EXACT, result);
+	/* update cached pos_in_node */
+	if (lookup_res == NS_FOUND) {
+		write_lock_tree(tree);
+		coord_to_parent_coord(result, &child->in_parent);
+		write_unlock_tree(tree);
+		lookup_res = check_tree_pointer(result, child);
+	}
+	if (lookup_res == NS_NOT_FOUND)
+		lookup_res = find_child_by_addr(parent, child, result);
+	return lookup_res;
+}
+
+/* find coord of pointer to @child in @parent by scanning
+
+   Find the &coord_t in the @parent where pointer to a given @child
+   is in by scanning all internal items in @parent and comparing block
+   numbers in them with that of @child.
+
+*/
+static int find_child_by_addr(znode * parent /* parent znode, passed locked */ ,
+			      znode * child /* child znode, passed locked */ ,
+			      coord_t * result /* where result is stored in */ )
+{
+	int ret;
+
+	assert("nikita-1320", parent != NULL);
+	assert("nikita-1321", child != NULL);
+	assert("nikita-1322", result != NULL);
+
+	ret = NS_NOT_FOUND;
+
+	for_all_units(result, parent) {
+		if (check_tree_pointer(result, child) == NS_FOUND) {
+			write_lock_tree(znode_get_tree(parent));
+			coord_to_parent_coord(result, &child->in_parent);
+			write_unlock_tree(znode_get_tree(parent));
+			ret = NS_FOUND;
+			break;
+		}
+	}
+	return ret;
+}
+
+/* true, if @addr is "unallocated block number", which is just address, with
+   highest bit set. */
+int is_disk_addr_unallocated(const reiser4_block_nr * addr	/* address to
+								 * check */ )
+{
+	assert("nikita-1766", addr != NULL);
+	cassert(sizeof(reiser4_block_nr) == 8);
+	return (*addr & REISER4_BLOCKNR_STATUS_BIT_MASK) ==
+	    REISER4_UNALLOCATED_STATUS_VALUE;
+}
+
+/* returns true if removing bytes of given range of key [from_key, to_key]
+   causes removing of whole item @from */
+static int
+item_removed_completely(coord_t * from, const reiser4_key * from_key,
+			const reiser4_key * to_key)
+{
+	item_plugin *iplug;
+	reiser4_key key_in_item;
+
+	assert("umka-325", from != NULL);
+	assert("", item_is_extent(from));
+
+	/* check first key just for case */
+	item_key_by_coord(from, &key_in_item);
+	if (keygt(from_key, &key_in_item))
+		return 0;
+
+	/* check last key */
+	iplug = item_plugin_by_coord(from);
+	assert("vs-611", iplug && iplug->s.file.append_key);
+
+	iplug->s.file.append_key(from, &key_in_item);
+	set_key_offset(&key_in_item, get_key_offset(&key_in_item) - 1);
+
+	if (keylt(to_key, &key_in_item))
+		/* last byte is not removed */
+		return 0;
+	return 1;
+}
+
+/* helper function for prepare_twig_kill(): @left and @right are formatted
+ * neighbors of extent item being completely removed. Load and lock neighbors
+ * and store lock handles into @cdata for later use by kill_hook_extent() */
+static int
+prepare_children(znode * left, znode * right, carry_kill_data * kdata)
+{
+	int result;
+	int left_loaded;
+	int right_loaded;
+
+	result = 0;
+	left_loaded = right_loaded = 0;
+
+	if (left != NULL) {
+		result = zload(left);
+		if (result == 0) {
+			left_loaded = 1;
+			result = longterm_lock_znode(kdata->left, left,
+						     ZNODE_READ_LOCK,
+						     ZNODE_LOCK_LOPRI);
+		}
+	}
+	if (result == 0 && right != NULL) {
+		result = zload(right);
+		if (result == 0) {
+			right_loaded = 1;
+			result = longterm_lock_znode(kdata->right, right,
+						     ZNODE_READ_LOCK,
+						     ZNODE_LOCK_HIPRI |
+						     ZNODE_LOCK_NONBLOCK);
+		}
+	}
+	if (result != 0) {
+		done_lh(kdata->left);
+		done_lh(kdata->right);
+		if (left_loaded != 0)
+			zrelse(left);
+		if (right_loaded != 0)
+			zrelse(right);
+	}
+	return result;
+}
+
+static void done_children(carry_kill_data * kdata)
+{
+	if (kdata->left != NULL && kdata->left->node != NULL) {
+		zrelse(kdata->left->node);
+		done_lh(kdata->left);
+	}
+	if (kdata->right != NULL && kdata->right->node != NULL) {
+		zrelse(kdata->right->node);
+		done_lh(kdata->right);
+	}
+}
+
+/* part of cut_node. It is called when cut_node is called to remove or cut part
+   of extent item. When head of that item is removed - we have to update right
+   delimiting of left neighbor of extent. When item is removed completely - we
+   have to set sibling link between left and right neighbor of removed
+   extent. This may return -E_DEADLOCK because of trying to get left neighbor
+   locked. So, caller should repeat an attempt
+*/
+/* Audited by: umka (2002.06.16) */
+static int
+prepare_twig_kill(carry_kill_data * kdata, znode * locked_left_neighbor)
+{
+	int result;
+	reiser4_key key;
+	lock_handle left_lh;
+	lock_handle right_lh;
+	coord_t left_coord;
+	coord_t *from;
+	znode *left_child;
+	znode *right_child;
+	reiser4_tree *tree;
+	int left_zloaded_here, right_zloaded_here;
+
+	from = kdata->params.from;
+	assert("umka-326", from != NULL);
+	assert("umka-327", kdata->params.to != NULL);
+
+	/* for one extent item only yet */
+	assert("vs-591", item_is_extent(from));
+	assert("vs-592", from->item_pos == kdata->params.to->item_pos);
+
+	if ((kdata->params.from_key
+	     && keygt(kdata->params.from_key, item_key_by_coord(from, &key)))
+	    || from->unit_pos != 0) {
+		/* head of item @from is not removed, there is nothing to
+		   worry about */
+		return 0;
+	}
+
+	result = 0;
+	left_zloaded_here = 0;
+	right_zloaded_here = 0;
+
+	left_child = right_child = NULL;
+
+	coord_dup(&left_coord, from);
+	init_lh(&left_lh);
+	init_lh(&right_lh);
+	if (coord_prev_unit(&left_coord)) {
+		/* @from is leftmost item in its node */
+		if (!locked_left_neighbor) {
+			result =
+			    reiser4_get_left_neighbor(&left_lh, from->node,
+						      ZNODE_READ_LOCK,
+						      GN_CAN_USE_UPPER_LEVELS);
+			switch (result) {
+			case 0:
+				break;
+			case -E_NO_NEIGHBOR:
+				/* there is no formatted node to the left of
+				   from->node */
+				warning("vs-605",
+					"extent item has smallest key in "
+					"the tree and it is about to be removed");
+				return 0;
+			case -E_DEADLOCK:
+				/* need to restart */
+			default:
+				return result;
+			}
+
+			/* we have acquired left neighbor of from->node */
+			result = zload(left_lh.node);
+			if (result)
+				goto done;
+
+			locked_left_neighbor = left_lh.node;
+		} else {
+			/* squalloc_right_twig_cut should have supplied locked
+			 * left neighbor */
+			assert("vs-834",
+			       znode_is_write_locked(locked_left_neighbor));
+			result = zload(locked_left_neighbor);
+			if (result)
+				return result;
+		}
+
+		left_zloaded_here = 1;
+		coord_init_last_unit(&left_coord, locked_left_neighbor);
+	}
+
+	if (!item_is_internal(&left_coord)) {
+		/* what else but extent can be on twig level */
+		assert("vs-606", item_is_extent(&left_coord));
+
+		/* there is no left formatted child */
+		if (left_zloaded_here)
+			zrelse(locked_left_neighbor);
+		done_lh(&left_lh);
+		return 0;
+	}
+
+	tree = znode_get_tree(left_coord.node);
+	left_child = child_znode(&left_coord, left_coord.node, 1, 0);
+
+	if (IS_ERR(left_child)) {
+		result = PTR_ERR(left_child);
+		goto done;
+	}
+
+	/* left child is acquired, calculate new right delimiting key for it
+	   and get right child if it is necessary */
+	if (item_removed_completely
+	    (from, kdata->params.from_key, kdata->params.to_key)) {
+		/* try to get right child of removed item */
+		coord_t right_coord;
+
+		assert("vs-607",
+		       kdata->params.to->unit_pos ==
+		       coord_last_unit_pos(kdata->params.to));
+		coord_dup(&right_coord, kdata->params.to);
+		if (coord_next_unit(&right_coord)) {
+			/* @to is rightmost unit in the node */
+			result =
+			    reiser4_get_right_neighbor(&right_lh, from->node,
+						       ZNODE_READ_LOCK,
+						       GN_CAN_USE_UPPER_LEVELS);
+			switch (result) {
+			case 0:
+				result = zload(right_lh.node);
+				if (result)
+					goto done;
+
+				right_zloaded_here = 1;
+				coord_init_first_unit(&right_coord,
+						      right_lh.node);
+				item_key_by_coord(&right_coord, &key);
+				break;
+
+			case -E_NO_NEIGHBOR:
+				/* there is no formatted node to the right of
+				   from->node */
+				read_lock_dk(tree);
+				key = *znode_get_rd_key(from->node);
+				read_unlock_dk(tree);
+				right_coord.node = NULL;
+				result = 0;
+				break;
+			default:
+				/* real error */
+				goto done;
+			}
+		} else {
+			/* there is an item to the right of @from - take its key */
+			item_key_by_coord(&right_coord, &key);
+		}
+
+		/* try to get right child of @from */
+		if (right_coord.node &&	/* there is right neighbor of @from */
+		    item_is_internal(&right_coord)) {	/* it is internal item */
+			right_child = child_znode(&right_coord,
+						  right_coord.node, 1, 0);
+
+			if (IS_ERR(right_child)) {
+				result = PTR_ERR(right_child);
+				goto done;
+			}
+
+		}
+		/* whole extent is removed between znodes left_child and right_child. Prepare them for linking and
+		   update of right delimiting key of left_child */
+		result = prepare_children(left_child, right_child, kdata);
+	} else {
+		/* head of item @to is removed. left_child has to get right delimting key update. Prepare it for that */
+		result = prepare_children(left_child, NULL, kdata);
+	}
+
+      done:
+	if (right_child)
+		zput(right_child);
+	if (right_zloaded_here)
+		zrelse(right_lh.node);
+	done_lh(&right_lh);
+
+	if (left_child)
+		zput(left_child);
+	if (left_zloaded_here)
+		zrelse(locked_left_neighbor);
+	done_lh(&left_lh);
+	return result;
+}
+
+/* this is used to remove part of node content between coordinates @from and @to. Units to which @from and @to are set
+   are to be cut completely */
+/* for try_to_merge_with_left, delete_copied, delete_node */
+int cut_node_content(coord_t * from, coord_t * to, const reiser4_key * from_key,	/* first key to be removed */
+		     const reiser4_key * to_key,	/* last key to be removed */
+		     reiser4_key *
+		     smallest_removed /* smallest key actually removed */ )
+{
+	int result;
+	carry_pool *pool;
+	carry_level *lowest_level;
+	carry_cut_data *cut_data;
+	carry_op *op;
+
+	assert("vs-1715", coord_compare(from, to) != COORD_CMP_ON_RIGHT);
+
+	pool =
+	    init_carry_pool(sizeof(*pool) + 3 * sizeof(*lowest_level) +
+			    sizeof(*cut_data));
+	if (IS_ERR(pool))
+		return PTR_ERR(pool);
+	lowest_level = (carry_level *) (pool + 1);
+	init_carry_level(lowest_level, pool);
+
+	op = post_carry(lowest_level, COP_CUT, from->node, 0);
+	assert("vs-1509", op != 0);
+	if (IS_ERR(op)) {
+		done_carry_pool(pool);
+		return PTR_ERR(op);
+	}
+
+	cut_data = (carry_cut_data *) (lowest_level + 3);
+	cut_data->params.from = from;
+	cut_data->params.to = to;
+	cut_data->params.from_key = from_key;
+	cut_data->params.to_key = to_key;
+	cut_data->params.smallest_removed = smallest_removed;
+
+	op->u.cut_or_kill.is_cut = 1;
+	op->u.cut_or_kill.u.cut = cut_data;
+
+	result = carry(lowest_level, NULL);
+	done_carry_pool(pool);
+
+	return result;
+}
+
+/* cut part of the node
+
+   Cut part or whole content of node.
+
+   cut data between @from and @to of @from->node and call carry() to make
+   corresponding changes in the tree. @from->node may become empty. If so -
+   pointer to it will be removed. Neighboring nodes are not changed. Smallest
+   removed key is stored in @smallest_removed
+
+*/
+int kill_node_content(coord_t * from,	/* coord of the first unit/item that will be eliminated */
+		      coord_t * to,	/* coord of the last unit/item that will be eliminated */
+		      const reiser4_key * from_key,	/* first key to be removed */
+		      const reiser4_key * to_key,	/* last key to be removed */
+		      reiser4_key * smallest_removed,	/* smallest key actually removed */
+		      znode * locked_left_neighbor,	/* this is set when kill_node_content is called with left neighbor
+							 * locked (in squalloc_right_twig_cut, namely) */
+		      struct inode *inode,	/* inode of file whose item (or its part) is to be killed. This is necessary to
+						   invalidate pages together with item pointing to them */
+		      int truncate)
+{				/* this call is made for file truncate)  */
+	int result;
+	carry_pool *pool;
+	carry_level *lowest_level;
+	carry_kill_data *kdata;
+	lock_handle *left_child;
+	lock_handle *right_child;
+	carry_op *op;
+
+	assert("umka-328", from != NULL);
+	assert("vs-316", !node_is_empty(from->node));
+	assert("nikita-1812", coord_is_existing_unit(from)
+	       && coord_is_existing_unit(to));
+
+	/* allocate carry_pool, 3 carry_level-s, carry_kill_data and structures for kill_hook_extent */
+	pool = init_carry_pool(sizeof(*pool) + 3 * sizeof(*lowest_level) +
+			       sizeof(carry_kill_data) +
+			       2 * sizeof(lock_handle) +
+			       5 * sizeof(reiser4_key) + 2 * sizeof(coord_t));
+	if (IS_ERR(pool))
+		return PTR_ERR(pool);
+
+	lowest_level = (carry_level *) (pool + 1);
+	init_carry_level(lowest_level, pool);
+
+	kdata = (carry_kill_data *) (lowest_level + 3);
+	left_child = (lock_handle *) (kdata + 1);
+	right_child = left_child + 1;
+
+	init_lh(left_child);
+	init_lh(right_child);
+
+	kdata->params.from = from;
+	kdata->params.to = to;
+	kdata->params.from_key = from_key;
+	kdata->params.to_key = to_key;
+	kdata->params.smallest_removed = smallest_removed;
+	kdata->params.truncate = truncate;
+	kdata->flags = 0;
+	kdata->inode = inode;
+	kdata->left = left_child;
+	kdata->right = right_child;
+	/* memory for 5 reiser4_key and 2 coord_t will be used in kill_hook_extent */
+	kdata->buf = (char *)(right_child + 1);
+
+	if (znode_get_level(from->node) == TWIG_LEVEL && item_is_extent(from)) {
+		/* left child of extent item may have to get updated right
+		   delimiting key and to get linked with right child of extent
+		   @from if it will be removed completely */
+		result = prepare_twig_kill(kdata, locked_left_neighbor);
+		if (result) {
+			done_children(kdata);
+			done_carry_pool(pool);
+			return result;
+		}
+	}
+
+	op = post_carry(lowest_level, COP_CUT, from->node, 0);
+	if (IS_ERR(op) || (op == NULL)) {
+		done_children(kdata);
+		done_carry_pool(pool);
+		return RETERR(op ? PTR_ERR(op) : -EIO);
+	}
+
+	op->u.cut_or_kill.is_cut = 0;
+	op->u.cut_or_kill.u.kill = kdata;
+
+	result = carry(lowest_level, NULL);
+
+	done_children(kdata);
+	done_carry_pool(pool);
+	return result;
+}
+
+void
+fake_kill_hook_tail(struct inode *inode, loff_t start, loff_t end, int truncate)
+{
+	if (inode_get_flag(inode, REISER4_HAS_MMAP)) {
+		pgoff_t start_pg, end_pg;
+
+		start_pg = start >> PAGE_CACHE_SHIFT;
+		end_pg = (end - 1) >> PAGE_CACHE_SHIFT;
+
+		if ((start & (PAGE_CACHE_SIZE - 1)) == 0) {
+			/*
+			 * kill up to the page boundary.
+			 */
+			assert("vs-123456", start_pg == end_pg);
+			reiser4_invalidate_pages(inode->i_mapping, start_pg, 1,
+						 truncate);
+		} else if (start_pg != end_pg) {
+			/*
+			 * page boundary is within killed portion of node.
+			 */
+			assert("vs-654321", end_pg - start_pg == 1);
+			reiser4_invalidate_pages(inode->i_mapping, end_pg,
+						 end_pg - start_pg, 1);
+		}
+	}
+	inode_sub_bytes(inode, end - start);
+}
+
+/**
+ * Delete whole @node from the reiser4 tree without loading it.
+ *
+ * @left: locked left neighbor,
+ * @node: node to be deleted,
+ * @smallest_removed: leftmost key of deleted node,
+ * @object: inode pointer, if we truncate a file body.
+ * @truncate: true if called for file truncate.
+ *
+ * @return: 0 if success, error code otherwise.
+ *
+ * NOTE: if @object!=NULL we assume that @smallest_removed != NULL and it
+ * contains the right value of the smallest removed key from the previous
+ * cut_worker() iteration.  This is needed for proper accounting of
+ * "i_blocks" and "i_bytes" fields of the @object.
+ */
+int delete_node(znode * node, reiser4_key * smallest_removed,
+		struct inode *object, int truncate)
+{
+	lock_handle parent_lock;
+	coord_t cut_from;
+	coord_t cut_to;
+	reiser4_tree *tree;
+	int ret;
+
+	assert("zam-937", node != NULL);
+	assert("zam-933", znode_is_write_locked(node));
+	assert("zam-999", smallest_removed != NULL);
+
+	init_lh(&parent_lock);
+
+	ret = reiser4_get_parent(&parent_lock, node, ZNODE_WRITE_LOCK);
+	if (ret)
+		return ret;
+
+	assert("zam-934", !znode_above_root(parent_lock.node));
+
+	ret = zload(parent_lock.node);
+	if (ret)
+		goto failed_nozrelse;
+
+	ret = find_child_ptr(parent_lock.node, node, &cut_from);
+	if (ret)
+		goto failed;
+
+	/* decrement child counter and set parent pointer to NULL before
+	   deleting the list from parent node because of checks in
+	   internal_kill_item_hook (we can delete the last item from the parent
+	   node, the parent node is going to be deleted and its c_count should
+	   be zero). */
+
+	tree = znode_get_tree(node);
+	write_lock_tree(tree);
+	init_parent_coord(&node->in_parent, NULL);
+	--parent_lock.node->c_count;
+	write_unlock_tree(tree);
+
+	assert("zam-989", item_is_internal(&cut_from));
+
+	/* @node should be deleted after unlocking. */
+	ZF_SET(node, JNODE_HEARD_BANSHEE);
+
+	/* remove a pointer from the parent node to the node being deleted. */
+	coord_dup(&cut_to, &cut_from);
+	/* FIXME: shouldn't this be kill_node_content */
+	ret = cut_node_content(&cut_from, &cut_to, NULL, NULL, NULL);
+	if (ret)
+		/* FIXME(Zam): Should we re-connect the node to its parent if
+		 * cut_node fails? */
+		goto failed;
+
+	{
+		reiser4_tree *tree = current_tree;
+		__u64 start_offset = 0, end_offset = 0;
+
+		read_lock_tree(tree);
+		write_lock_dk(tree);
+		if (object) {
+			/* We use @smallest_removed and the left delimiting of
+			 * the current node for @object->i_blocks, i_bytes
+			 * calculation.  We assume that the items after the
+			 * *@smallest_removed key have been deleted from the
+			 * file body. */
+			start_offset = get_key_offset(znode_get_ld_key(node));
+			end_offset = get_key_offset(smallest_removed);
+		}
+
+		assert("zam-1021", znode_is_connected(node));
+		if (node->left)
+			znode_set_rd_key(node->left, znode_get_rd_key(node));
+
+		*smallest_removed = *znode_get_ld_key(node);
+
+		write_unlock_dk(tree);
+		read_unlock_tree(tree);
+
+		if (object) {
+			/* we used to perform actions which are to be performed on items on their removal from tree in
+			   special item method - kill_hook. Here for optimization reasons we avoid reading node
+			   containing item we remove and can not call item's kill hook. Instead we call function which
+			   does exactly the same things as tail kill hook in assumption that node we avoid reading
+			   contains only one item and that item is a tail one. */
+			fake_kill_hook_tail(object, start_offset, end_offset,
+					    truncate);
+		}
+	}
+      failed:
+	zrelse(parent_lock.node);
+      failed_nozrelse:
+	done_lh(&parent_lock);
+
+	return ret;
+}
+
+static int can_delete(const reiser4_key *key, znode *node)
+{
+	int result;
+
+	read_lock_dk(current_tree);
+	result = keyle(key, znode_get_ld_key(node));
+	read_unlock_dk(current_tree);
+	return result;
+}
+
+/**
+ * This subroutine is not optimal but implementation seems to
+ * be easier).
+ *
+ * @tap: the point deletion process begins from,
+ * @from_key: the beginning of the deleted key range,
+ * @to_key: the end of the deleted key range,
+ * @smallest_removed: the smallest removed key,
+ * @truncate: true if called for file truncate.
+ * @progress: return true if a progress in file items deletions was made,
+ *            @smallest_removed value is actual in that case.
+ *
+ * @return: 0 if success, error code otherwise, -E_REPEAT means that long cut_tree
+ * operation was interrupted for allowing atom commit .
+ */
+int
+cut_tree_worker_common(tap_t * tap, const reiser4_key * from_key,
+		       const reiser4_key * to_key,
+		       reiser4_key * smallest_removed, struct inode *object,
+		       int truncate, int *progress)
+{
+	lock_handle next_node_lock;
+	coord_t left_coord;
+	int result;
+
+	assert("zam-931", tap->coord->node != NULL);
+	assert("zam-932", znode_is_write_locked(tap->coord->node));
+
+	*progress = 0;
+	init_lh(&next_node_lock);
+
+	while (1) {
+		znode *node;	/* node from which items are cut */
+		node_plugin *nplug;	/* node plugin for @node */
+
+		node = tap->coord->node;
+
+		/* Move next_node_lock to the next node on the left. */
+		result =
+		    reiser4_get_left_neighbor(&next_node_lock, node,
+					      ZNODE_WRITE_LOCK,
+					      GN_CAN_USE_UPPER_LEVELS);
+		if (result != 0 && result != -E_NO_NEIGHBOR)
+			break;
+		/* Check can we delete the node as a whole. */
+		if (*progress && znode_get_level(node) == LEAF_LEVEL &&
+		    can_delete(from_key, node)) {
+			result = delete_node(node, smallest_removed, object,
+					     truncate);
+		} else {
+			result = tap_load(tap);
+			if (result)
+				return result;
+
+			/* Prepare the second (right) point for cut_node() */
+			if (*progress)
+				coord_init_last_unit(tap->coord, node);
+
+			else if (item_plugin_by_coord(tap->coord)->b.lookup ==
+				 NULL)
+				/* set rightmost unit for the items without lookup method */
+				tap->coord->unit_pos =
+				    coord_last_unit_pos(tap->coord);
+
+			nplug = node->nplug;
+
+			assert("vs-686", nplug);
+			assert("vs-687", nplug->lookup);
+
+			/* left_coord is leftmost unit cut from @node */
+			result = nplug->lookup(node, from_key,
+					       FIND_MAX_NOT_MORE_THAN,
+					       &left_coord);
+
+			if (IS_CBKERR(result))
+				break;
+
+			/* adjust coordinates so that they are set to existing units */
+			if (coord_set_to_right(&left_coord)
+			    || coord_set_to_left(tap->coord)) {
+				result = 0;
+				break;
+			}
+
+			if (coord_compare(&left_coord, tap->coord) ==
+			    COORD_CMP_ON_RIGHT) {
+				/* keys from @from_key to @to_key are not in the tree */
+				result = 0;
+				break;
+			}
+
+			if (left_coord.item_pos != tap->coord->item_pos) {
+				/* do not allow to cut more than one item. It is added to solve problem of truncating
+				   partially converted files. If file is partially converted there may exist a twig node
+				   containing both internal item or items pointing to leaf nodes with formatting items
+				   and extent item. We do not want to kill internal items being at twig node here
+				   because cut_tree_worker assumes killing them from level level */
+				coord_dup(&left_coord, tap->coord);
+				assert("vs-1652",
+				       coord_is_existing_unit(&left_coord));
+				left_coord.unit_pos = 0;
+			}
+
+			/* cut data from one node */
+			// *smallest_removed = *min_key();
+			result =
+			    kill_node_content(&left_coord, tap->coord, from_key,
+					      to_key, smallest_removed,
+					      next_node_lock.node, object,
+					      truncate);
+			tap_relse(tap);
+		}
+		if (result)
+			break;
+
+		++(*progress);
+
+		/* Check whether all items with keys >= from_key were removed
+		 * from the tree. */
+		if (keyle(smallest_removed, from_key))
+			/* result = 0; */
+			break;
+
+		if (next_node_lock.node == NULL)
+			break;
+
+		result = tap_move(tap, &next_node_lock);
+		done_lh(&next_node_lock);
+		if (result)
+			break;
+
+		/* Break long cut_tree operation (deletion of a large file) if
+		 * atom requires commit. */
+		if (*progress > CUT_TREE_MIN_ITERATIONS
+		    && current_atom_should_commit()) {
+			result = -E_REPEAT;
+			break;
+		}
+	}
+	done_lh(&next_node_lock);
+	// assert("vs-301", !keyeq(&smallest_removed, min_key()));
+	return result;
+}
+
+/* there is a fundamental problem with optimizing deletes: VFS does it
+   one file at a time.  Another problem is that if an item can be
+   anything, then deleting items must be done one at a time.  It just
+   seems clean to writes this to specify a from and a to key, and cut
+   everything between them though.  */
+
+/* use this function with care if deleting more than what is part of a single file. */
+/* do not use this when cutting a single item, it is suboptimal for that */
+
+/* You are encouraged to write plugin specific versions of this.  It
+   cannot be optimal for all plugins because it works item at a time,
+   and some plugins could sometimes work node at a time. Regular files
+   however are not optimizable to work node at a time because of
+   extents needing to free the blocks they point to.
+
+   Optimizations compared to v3 code:
+
+   It does not balance (that task is left to memory pressure code).
+
+   Nodes are deleted only if empty.
+
+   Uses extents.
+
+   Performs read-ahead of formatted nodes whose contents are part of
+   the deletion.
+*/
+
+/**
+ * Delete everything from the reiser4 tree between two keys: @from_key and
+ * @to_key.
+ *
+ * @from_key: the beginning of the deleted key range,
+ * @to_key: the end of the deleted key range,
+ * @smallest_removed: the smallest removed key,
+ * @object: owner of cutting items.
+ * @truncate: true if called for file truncate.
+ * @progress: return true if a progress in file items deletions was made,
+ *            @smallest_removed value is actual in that case.
+ *
+ * @return: 0 if success, error code otherwise, -E_REPEAT means that long cut_tree
+ * operation was interrupted for allowing atom commit .
+ */
+
+int
+cut_tree_object(reiser4_tree * tree, const reiser4_key * from_key,
+		const reiser4_key * to_key, reiser4_key * smallest_removed_p,
+		struct inode *object, int truncate, int *progress)
+{
+	lock_handle lock;
+	int result;
+	tap_t tap;
+	coord_t right_coord;
+	reiser4_key smallest_removed;
+	int (*cut_tree_worker) (tap_t *, const reiser4_key *,
+				const reiser4_key *, reiser4_key *,
+				struct inode *, int, int *);
+	STORE_COUNTERS;
+
+	assert("umka-329", tree != NULL);
+	assert("umka-330", from_key != NULL);
+	assert("umka-331", to_key != NULL);
+	assert("zam-936", keyle(from_key, to_key));
+
+	if (smallest_removed_p == NULL)
+		smallest_removed_p = &smallest_removed;
+
+	init_lh(&lock);
+
+	do {
+		/* Find rightmost item to cut away from the tree. */
+		result = object_lookup(object, to_key, &right_coord, &lock,
+				       ZNODE_WRITE_LOCK, FIND_MAX_NOT_MORE_THAN,
+				       TWIG_LEVEL, LEAF_LEVEL, CBK_UNIQUE,
+				       NULL /*ra_info */ );
+		if (result != CBK_COORD_FOUND)
+			break;
+		if (object == NULL
+		    || inode_file_plugin(object)->cut_tree_worker == NULL)
+			cut_tree_worker = cut_tree_worker_common;
+		else
+			cut_tree_worker =
+			    inode_file_plugin(object)->cut_tree_worker;
+		tap_init(&tap, &right_coord, &lock, ZNODE_WRITE_LOCK);
+		result =
+		    cut_tree_worker(&tap, from_key, to_key, smallest_removed_p,
+				    object, truncate, progress);
+		tap_done(&tap);
+
+		preempt_point();
+
+	} while (0);
+
+	done_lh(&lock);
+
+	if (result) {
+		switch (result) {
+		case -E_NO_NEIGHBOR:
+			result = 0;
+			break;
+		case -E_DEADLOCK:
+			result = -E_REPEAT;
+		case -E_REPEAT:
+		case -ENOMEM:
+		case -ENOENT:
+			break;
+		default:
+			warning("nikita-2861", "failure: %i", result);
+		}
+	}
+
+	CHECK_COUNTERS;
+	return result;
+}
+
+/* repeat cut_tree_object until everything is deleted. unlike cut_file_items, it
+ * does not end current transaction if -E_REPEAT is returned by
+ * cut_tree_object. */
+int
+cut_tree(reiser4_tree * tree, const reiser4_key * from, const reiser4_key * to,
+	 struct inode *inode, int truncate)
+{
+	int result;
+	int progress;
+
+	do {
+		result =
+		    cut_tree_object(tree, from, to, NULL, inode, truncate,
+				    &progress);
+	} while (result == -E_REPEAT);
+
+	return result;
+}
+
+/* finishing reiser4 initialization */
+int init_tree(reiser4_tree * tree	/* pointer to structure being
+					 * initialized */ ,
+	      const reiser4_block_nr * root_block	/* address of a root block
+							 * on a disk */ ,
+	      tree_level height /* height of a tree */ ,
+	      node_plugin * nplug /* default node plugin */ )
+{
+	int result;
+
+	assert("nikita-306", tree != NULL);
+	assert("nikita-307", root_block != NULL);
+	assert("nikita-308", height > 0);
+	assert("nikita-309", nplug != NULL);
+	assert("zam-587", tree->super != NULL);
+
+	tree->root_block = *root_block;
+	tree->height = height;
+	tree->estimate_one_insert = calc_estimate_one_insert(height);
+	tree->nplug = nplug;
+
+	tree->znode_epoch = 1ull;
+
+	cbk_cache_init(&tree->cbk_cache);
+
+	result = znodes_tree_init(tree);
+	if (result == 0)
+		result = jnodes_tree_init(tree);
+	if (result == 0) {
+		tree->uber = zget(tree, &UBER_TREE_ADDR, NULL, 0, GFP_KERNEL);
+		if (IS_ERR(tree->uber)) {
+			result = PTR_ERR(tree->uber);
+			tree->uber = NULL;
+		}
+	}
+	return result;
+}
+
+/* release resources associated with @tree */
+void done_tree(reiser4_tree * tree /* tree to release */ )
+{
+	if (tree == NULL)
+		return;
+
+	if (tree->uber != NULL) {
+		zput(tree->uber);
+		tree->uber = NULL;
+	}
+	znodes_tree_done(tree);
+	jnodes_tree_done(tree);
+	cbk_cache_done(&tree->cbk_cache);
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/tree.h newtree/fs/reiser4/tree.h
--- oldtree/fs/reiser4/tree.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/tree.h	2006-02-21 15:58:35.410763304 +0000
@@ -0,0 +1,579 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Tree operations. See fs/reiser4/tree.c for comments */
+
+#if !defined( __REISER4_TREE_H__ )
+#define __REISER4_TREE_H__
+
+#include "forward.h"
+#include "debug.h"
+#include "dformat.h"
+#include "plugin/node/node.h"
+#include "plugin/plugin.h"
+#include "znode.h"
+#include "tap.h"
+
+#include <linux/types.h>	/* for __u??  */
+#include <linux/fs.h>		/* for struct super_block  */
+#include <linux/spinlock.h>
+#include <linux/sched.h>	/* for struct task_struct */
+
+/* fictive block number never actually used */
+extern const reiser4_block_nr UBER_TREE_ADDR;
+
+/* &cbk_cache_slot - entry in a coord cache.
+
+   This is entry in a coord_by_key (cbk) cache, represented by
+   &cbk_cache.
+
+*/
+typedef struct cbk_cache_slot {
+	/* cached node */
+	znode *node;
+	/* linkage to the next cbk cache slot in a LRU order */
+	struct list_head lru;
+} cbk_cache_slot;
+
+/* &cbk_cache - coord cache. This is part of reiser4_tree.
+
+   cbk_cache is supposed to speed up tree lookups by caching results of recent
+   successful lookups (we don't cache negative results as dentry cache
+   does). Cache consists of relatively small number of entries kept in a LRU
+   order. Each entry (&cbk_cache_slot) contains a pointer to znode, from
+   which we can obtain a range of keys that covered by this znode. Before
+   embarking into real tree traversal we scan cbk_cache slot by slot and for
+   each slot check whether key we are looking for is between minimal and
+   maximal keys for node pointed to by this slot. If no match is found, real
+   tree traversal is performed and if result is successful, appropriate entry
+   is inserted into cache, possibly pulling least recently used entry out of
+   it.
+
+   Tree spin lock is used to protect coord cache. If contention for this
+   lock proves to be too high, more finer grained locking can be added.
+
+   Invariants involving parts of this data-type:
+
+      [cbk-cache-invariant]
+*/
+typedef struct cbk_cache {
+	/* serializator */
+	rwlock_t guard;
+	int nr_slots;
+	/* head of LRU list of cache slots */
+	struct list_head lru;
+	/* actual array of slots */
+	cbk_cache_slot *slot;
+} cbk_cache;
+
+
+/* level_lookup_result - possible outcome of looking up key at some level.
+   This is used by coord_by_key when traversing tree downward. */
+typedef enum {
+	/* continue to the next level */
+	LOOKUP_CONT,
+	/* done. Either required item was found, or we can prove it
+	   doesn't exist, or some error occurred. */
+	LOOKUP_DONE,
+	/* restart traversal from the root. Infamous "repetition". */
+	LOOKUP_REST
+} level_lookup_result;
+
+/*    This is representation of internal reiser4 tree where all file-system
+   data and meta-data are stored. This structure is passed to all tree
+   manipulation functions. It's different from the super block because:
+   we don't want to limit ourselves to strictly one to one mapping
+   between super blocks and trees, and, because they are logically
+   different: there are things in a super block that have no relation to
+   the tree (bitmaps, journalling area, mount options, etc.) and there
+   are things in a tree that bear no relation to the super block, like
+   tree of znodes.
+
+   At this time, there is only one tree
+   per filesystem, and this struct is part of the super block.  We only
+   call the super block the super block for historical reasons (most
+   other filesystems call the per filesystem metadata the super block).
+*/
+
+struct reiser4_tree {
+	/* block_nr == 0 is fake znode. Write lock it, while changing
+	   tree height. */
+	/* disk address of root node of a tree */
+	reiser4_block_nr root_block;
+
+	/* level of the root node. If this is 1, tree consists of root
+	   node only */
+	tree_level height;
+
+	/*
+	 * this is cached here avoid calling plugins through function
+	 * dereference all the time.
+	 */
+	__u64 estimate_one_insert;
+
+	/* cache of recent tree lookup results */
+	cbk_cache cbk_cache;
+
+	/* hash table to look up znodes by block number. */
+	z_hash_table zhash_table;
+	z_hash_table zfake_table;
+	/* hash table to look up jnodes by inode and offset. */
+	j_hash_table jhash_table;
+
+	/* lock protecting:
+	   - parent pointers,
+	   - sibling pointers,
+	   - znode hash table
+	   - coord cache
+	 */
+	/* NOTE: The "giant" tree lock can be replaced by more spin locks,
+	   hoping they will be less contented. We can use one spin lock per one
+	   znode hash bucket.  With adding of some code complexity, sibling
+	   pointers can be protected by both znode spin locks.  However it looks
+	   more SMP scalable we should test this locking change on n-ways (n >
+	   4) SMP machines.  Current 4-ways machine test does not show that tree
+	   lock is contented and it is a bottleneck (2003.07.25). */
+
+	rwlock_t tree_lock;
+
+	/* lock protecting delimiting keys */
+	rwlock_t dk_lock;
+
+	/* spin lock protecting znode_epoch */
+	spinlock_t epoch_lock;
+	/* version stamp used to mark znode updates. See seal.[ch] for more
+	 * information. */
+	__u64 znode_epoch;
+
+	znode *uber;
+	node_plugin *nplug;
+	struct super_block *super;
+	struct {
+		/* carry flags used for insertion of new nodes */
+		__u32 new_node_flags;
+		/* carry flags used for insertion of new extents */
+		__u32 new_extent_flags;
+		/* carry flags used for paste operations */
+		__u32 paste_flags;
+		/* carry flags used for insert operations */
+		__u32 insert_flags;
+	} carry;
+};
+
+extern int init_tree(reiser4_tree * tree,
+		     const reiser4_block_nr * root_block, tree_level height,
+		     node_plugin * default_plugin);
+extern void done_tree(reiser4_tree * tree);
+
+/* cbk flags: options for coord_by_key() */
+typedef enum {
+	/* coord_by_key() is called for insertion. This is necessary because
+	   of extents being located at the twig level. For explanation, see
+	   comment just above is_next_item_internal().
+	 */
+	CBK_FOR_INSERT = (1 << 0),
+	/* coord_by_key() is called with key that is known to be unique */
+	CBK_UNIQUE = (1 << 1),
+	/* coord_by_key() can trust delimiting keys. This options is not user
+	   accessible. coord_by_key() will set it automatically. It will be
+	   only cleared by special-case in extents-on-the-twig-level handling
+	   where it is necessary to insert item with a key smaller than
+	   leftmost key in a node. This is necessary because of extents being
+	   located at the twig level. For explanation, see comment just above
+	   is_next_item_internal().
+	 */
+	CBK_TRUST_DK = (1 << 2),
+	CBK_READA = (1 << 3),	/* original: readahead leaves which contain items of certain file */
+	CBK_READDIR_RA = (1 << 4),	/* readdir: readahead whole directory and all its stat datas */
+	CBK_DKSET = (1 << 5),
+	CBK_EXTENDED_COORD = (1 << 6),	/* coord_t is actually */
+	CBK_IN_CACHE = (1 << 7),	/* node is already in cache */
+	CBK_USE_CRABLOCK = (1 << 8)	/* use crab_lock in stead of long term
+					 * lock */
+} cbk_flags;
+
+/* insertion outcome. IBK = insert by key */
+typedef enum {
+	IBK_INSERT_OK = 0,
+	IBK_ALREADY_EXISTS = -EEXIST,
+	IBK_IO_ERROR = -EIO,
+	IBK_NO_SPACE = -E_NODE_FULL,
+	IBK_OOM = -ENOMEM
+} insert_result;
+
+#define IS_CBKERR(err) ((err) != CBK_COORD_FOUND && (err) != CBK_COORD_NOTFOUND)
+
+typedef int (*tree_iterate_actor_t) (reiser4_tree * tree, coord_t * coord,
+				     lock_handle * lh, void *arg);
+extern int iterate_tree(reiser4_tree * tree, coord_t * coord, lock_handle * lh,
+			tree_iterate_actor_t actor, void *arg,
+			znode_lock_mode mode, int through_units_p);
+extern int get_uber_znode(reiser4_tree * tree, znode_lock_mode mode,
+			  znode_lock_request pri, lock_handle * lh);
+
+/* return node plugin of @node */
+static inline node_plugin *node_plugin_by_node(const znode *
+					       node /* node to query */ )
+{
+	assert("vs-213", node != NULL);
+	assert("vs-214", znode_is_loaded(node));
+
+	return node->nplug;
+}
+
+/* number of items in @node */
+static inline pos_in_node_t node_num_items(const znode * node)
+{
+	assert("nikita-2754", znode_is_loaded(node));
+	assert("nikita-2468",
+	       node_plugin_by_node(node)->num_of_items(node) == node->nr_items);
+
+	return node->nr_items;
+}
+
+/* Return the number of items at the present node.  Asserts coord->node !=
+   NULL. */
+static inline unsigned coord_num_items(const coord_t * coord)
+{
+	assert("jmacd-9805", coord->node != NULL);
+
+	return node_num_items(coord->node);
+}
+
+/* true if @node is empty */
+static inline int node_is_empty(const znode * node)
+{
+	return node_num_items(node) == 0;
+}
+
+typedef enum {
+	SHIFTED_SOMETHING = 0,
+	SHIFT_NO_SPACE = -E_NODE_FULL,
+	SHIFT_IO_ERROR = -EIO,
+	SHIFT_OOM = -ENOMEM,
+} shift_result;
+
+extern node_plugin *node_plugin_by_coord(const coord_t * coord);
+extern int is_coord_in_node(const coord_t * coord);
+extern int key_in_node(const reiser4_key *, const coord_t *);
+extern void coord_item_move_to(coord_t * coord, int items);
+extern void coord_unit_move_to(coord_t * coord, int units);
+
+/* there are two types of repetitive accesses (ra): intra-syscall
+   (local) and inter-syscall (global). Local ra is used when
+   during single syscall we add/delete several items and units in the
+   same place in a tree. Note that plan-A fragments local ra by
+   separating stat-data and file body in key-space. Global ra is
+   used when user does repetitive modifications in the same place in a
+   tree.
+
+   Our ra implementation serves following purposes:
+    1 it affects balancing decisions so that next operation in a row
+      can be performed faster;
+    2 it affects lower-level read-ahead in page-cache;
+    3 it allows to avoid unnecessary lookups by maintaining some state
+      across several operations (this is only for local ra);
+    4 it leaves room for lazy-micro-balancing: when we start a sequence of
+      operations they are performed without actually doing any intra-node
+      shifts, until we finish sequence or scope of sequence leaves
+      current node, only then we really pack node (local ra only).
+*/
+
+/* another thing that can be useful is to keep per-tree and/or
+   per-process cache of recent lookups. This cache can be organised as a
+   list of block numbers of formatted nodes sorted by starting key in
+   this node. Balancings should invalidate appropriate parts of this
+   cache.
+*/
+
+lookup_result coord_by_key(reiser4_tree * tree, const reiser4_key * key,
+			   coord_t * coord, lock_handle * handle,
+			   znode_lock_mode lock, lookup_bias bias,
+			   tree_level lock_level, tree_level stop_level,
+			   __u32 flags, ra_info_t *);
+
+lookup_result object_lookup(struct inode *object,
+			    const reiser4_key * key,
+			    coord_t * coord,
+			    lock_handle * lh,
+			    znode_lock_mode lock_mode,
+			    lookup_bias bias,
+			    tree_level lock_level,
+			    tree_level stop_level,
+			    __u32 flags, ra_info_t * info);
+
+insert_result insert_by_key(reiser4_tree * tree, const reiser4_key * key,
+			    reiser4_item_data * data, coord_t * coord,
+			    lock_handle * lh,
+			    tree_level stop_level, __u32 flags);
+insert_result insert_by_coord(coord_t * coord,
+			      reiser4_item_data * data, const reiser4_key * key,
+			      lock_handle * lh, __u32);
+insert_result insert_extent_by_coord(coord_t * coord,
+				     reiser4_item_data * data,
+				     const reiser4_key * key, lock_handle * lh);
+int cut_node_content(coord_t * from, coord_t * to, const reiser4_key * from_key,
+		     const reiser4_key * to_key,
+		     reiser4_key * smallest_removed);
+int kill_node_content(coord_t * from, coord_t * to,
+		      const reiser4_key * from_key, const reiser4_key * to_key,
+		      reiser4_key * smallest_removed,
+		      znode * locked_left_neighbor, struct inode *inode,
+		      int truncate);
+
+int resize_item(coord_t * coord, reiser4_item_data * data,
+		reiser4_key * key, lock_handle * lh, cop_insert_flag);
+int insert_into_item(coord_t * coord, lock_handle * lh, const reiser4_key * key,
+		     reiser4_item_data * data, unsigned);
+int insert_flow(coord_t * coord, lock_handle * lh, flow_t * f);
+int find_new_child_ptr(znode * parent, znode * child, znode * left,
+		       coord_t * result);
+
+int shift_right_of_but_excluding_insert_coord(coord_t * insert_coord);
+int shift_left_of_and_including_insert_coord(coord_t * insert_coord);
+
+void fake_kill_hook_tail(struct inode *, loff_t start, loff_t end, int);
+
+extern int cut_tree_worker_common(tap_t *, const reiser4_key *,
+				  const reiser4_key *, reiser4_key *,
+				  struct inode *, int, int *);
+extern int cut_tree_object(reiser4_tree *, const reiser4_key *,
+			   const reiser4_key *, reiser4_key *, struct inode *,
+			   int, int *);
+extern int cut_tree(reiser4_tree * tree, const reiser4_key * from,
+		    const reiser4_key * to, struct inode *, int);
+
+extern int delete_node(znode * node, reiser4_key *, struct inode *, int);
+extern int check_tree_pointer(const coord_t * pointer, const znode * child);
+extern int find_new_child_ptr(znode * parent, znode * child UNUSED_ARG,
+			      znode * left, coord_t * result);
+extern int find_child_ptr(znode * parent, znode * child, coord_t * result);
+extern int set_child_delimiting_keys(znode * parent, const coord_t * in_parent,
+				     znode * child);
+extern znode *child_znode(const coord_t * in_parent, znode * parent,
+			  int incore_p, int setup_dkeys_p);
+
+extern int cbk_cache_init(cbk_cache * cache);
+extern void cbk_cache_done(cbk_cache * cache);
+extern void cbk_cache_invalidate(const znode * node, reiser4_tree * tree);
+
+extern char *sprint_address(const reiser4_block_nr * block);
+
+#if REISER4_DEBUG
+extern void print_coord_content(const char *prefix, coord_t * p);
+extern void reiser4_print_address(const char *prefix,
+			const reiser4_block_nr * block);
+extern void print_tree_rec(const char *prefix, reiser4_tree * tree,
+			   __u32 flags);
+extern void check_dkeys(znode *node);
+#else
+#define print_coord_content(p, c) noop
+#define reiser4_print_address(p, b) noop
+#endif
+
+extern void forget_znode(lock_handle * handle);
+extern int deallocate_znode(znode * node);
+
+extern int is_disk_addr_unallocated(const reiser4_block_nr * addr);
+
+/* struct used internally to pack all numerous arguments of tree lookup.
+    Used to avoid passing a lot of arguments to helper functions. */
+typedef struct cbk_handle {
+	/* tree we are in */
+	reiser4_tree *tree;
+	/* key we are going after */
+	const reiser4_key *key;
+	/* coord we will store result in */
+	coord_t *coord;
+	/* type of lock to take on target node */
+	znode_lock_mode lock_mode;
+	/* lookup bias. See comments at the declaration of lookup_bias */
+	lookup_bias bias;
+	/* lock level: level starting from which tree traversal starts taking
+	 * write locks. */
+	tree_level lock_level;
+	/* level where search will stop. Either item will be found between
+	   lock_level and stop_level, or CBK_COORD_NOTFOUND will be
+	   returned.
+	 */
+	tree_level stop_level;
+	/* level we are currently at */
+	tree_level level;
+	/* block number of @active node. Tree traversal operates on two
+	   nodes: active and parent.  */
+	reiser4_block_nr block;
+	/* put here error message to be printed by caller */
+	const char *error;
+	/* result passed back to caller */
+	lookup_result result;
+	/* lock handles for active and parent */
+	lock_handle *parent_lh;
+	lock_handle *active_lh;
+	reiser4_key ld_key;
+	reiser4_key rd_key;
+	/* flags, passed to the cbk routine. Bits of this bitmask are defined
+	   in tree.h:cbk_flags enum. */
+	__u32 flags;
+	ra_info_t *ra_info;
+	struct inode *object;
+} cbk_handle;
+
+extern znode_lock_mode cbk_lock_mode(tree_level level, cbk_handle * h);
+
+/* eottl.c */
+extern int handle_eottl(cbk_handle *h, int *outcome);
+
+int lookup_multikey(cbk_handle * handle, int nr_keys);
+int lookup_couple(reiser4_tree * tree,
+		  const reiser4_key * key1, const reiser4_key * key2,
+		  coord_t * coord1, coord_t * coord2,
+		  lock_handle * lh1, lock_handle * lh2,
+		  znode_lock_mode lock_mode, lookup_bias bias,
+		  tree_level lock_level, tree_level stop_level, __u32 flags,
+		  int *result1, int *result2);
+
+
+static inline void read_lock_tree(reiser4_tree *tree)
+{
+	/* check that tree is not locked */
+	assert("", (LOCK_CNT_NIL(rw_locked_tree) &&
+		    LOCK_CNT_NIL(read_locked_tree) &&
+		    LOCK_CNT_NIL(write_locked_tree)));
+	/* check that spinlocks of lower priorities are not held */
+	assert("", (LOCK_CNT_NIL(spin_locked_txnh) &&
+		    LOCK_CNT_NIL(rw_locked_dk) &&
+		    LOCK_CNT_NIL(spin_locked_stack)));
+
+	read_lock(&(tree->tree_lock));
+
+	LOCK_CNT_INC(read_locked_tree);
+	LOCK_CNT_INC(rw_locked_tree);
+	LOCK_CNT_INC(spin_locked);
+}
+
+static inline void read_unlock_tree(reiser4_tree *tree)
+{
+	assert("nikita-1375", LOCK_CNT_GTZ(read_locked_tree));
+	assert("nikita-1376", LOCK_CNT_GTZ(rw_locked_tree));
+	assert("nikita-1376", LOCK_CNT_GTZ(spin_locked));
+
+	LOCK_CNT_DEC(read_locked_tree);
+	LOCK_CNT_DEC(rw_locked_tree);
+	LOCK_CNT_DEC(spin_locked);
+
+	read_unlock(&(tree->tree_lock));
+}
+
+static inline void write_lock_tree(reiser4_tree *tree)
+{
+	/* check that tree is not locked */
+	assert("", (LOCK_CNT_NIL(rw_locked_tree) &&
+		    LOCK_CNT_NIL(read_locked_tree) &&
+		    LOCK_CNT_NIL(write_locked_tree)));
+	/* check that spinlocks of lower priorities are not held */
+	assert("", (LOCK_CNT_NIL(spin_locked_txnh) &&
+		    LOCK_CNT_NIL(rw_locked_dk) &&
+		    LOCK_CNT_NIL(spin_locked_stack)));
+
+	write_lock(&(tree->tree_lock));
+
+	LOCK_CNT_INC(write_locked_tree);
+	LOCK_CNT_INC(rw_locked_tree);
+	LOCK_CNT_INC(spin_locked);
+}
+
+static inline void write_unlock_tree(reiser4_tree *tree)
+{
+	assert("nikita-1375", LOCK_CNT_GTZ(write_locked_tree));
+	assert("nikita-1376", LOCK_CNT_GTZ(rw_locked_tree));
+	assert("nikita-1376", LOCK_CNT_GTZ(spin_locked));
+
+	LOCK_CNT_DEC(write_locked_tree);
+	LOCK_CNT_DEC(rw_locked_tree);
+	LOCK_CNT_DEC(spin_locked);
+
+	write_unlock(&(tree->tree_lock));
+}
+
+static inline void read_lock_dk(reiser4_tree *tree)
+{
+	/* check that dk is not locked */
+	assert("", (LOCK_CNT_NIL(rw_locked_dk) &&
+		    LOCK_CNT_NIL(read_locked_dk) &&
+		    LOCK_CNT_NIL(write_locked_dk)));
+	/* check that spinlocks of lower priorities are not held */
+	assert("", LOCK_CNT_NIL(spin_locked_stack));
+
+	read_lock(&((tree)->dk_lock));
+
+	LOCK_CNT_INC(read_locked_dk);
+	LOCK_CNT_INC(rw_locked_dk);
+	LOCK_CNT_INC(spin_locked);
+}
+
+static inline void read_unlock_dk(reiser4_tree *tree)
+{
+	assert("nikita-1375", LOCK_CNT_GTZ(read_locked_dk));
+	assert("nikita-1376", LOCK_CNT_GTZ(rw_locked_dk));
+	assert("nikita-1376", LOCK_CNT_GTZ(spin_locked));
+
+	LOCK_CNT_DEC(read_locked_dk);
+	LOCK_CNT_DEC(rw_locked_dk);
+	LOCK_CNT_DEC(spin_locked);
+
+	read_unlock(&(tree->dk_lock));
+}
+
+static inline void write_lock_dk(reiser4_tree *tree)
+{
+	/* check that dk is not locked */
+	assert("", (LOCK_CNT_NIL(rw_locked_dk) &&
+		    LOCK_CNT_NIL(read_locked_dk) &&
+		    LOCK_CNT_NIL(write_locked_dk)));
+	/* check that spinlocks of lower priorities are not held */
+	assert("", LOCK_CNT_NIL(spin_locked_stack));
+
+	write_lock(&((tree)->dk_lock));
+
+	LOCK_CNT_INC(write_locked_dk);
+	LOCK_CNT_INC(rw_locked_dk);
+	LOCK_CNT_INC(spin_locked);
+}
+
+static inline void write_unlock_dk(reiser4_tree *tree)
+{
+	assert("nikita-1375", LOCK_CNT_GTZ(write_locked_dk));
+	assert("nikita-1376", LOCK_CNT_GTZ(rw_locked_dk));
+	assert("nikita-1376", LOCK_CNT_GTZ(spin_locked));
+
+	LOCK_CNT_DEC(write_locked_dk);
+	LOCK_CNT_DEC(rw_locked_dk);
+	LOCK_CNT_DEC(spin_locked);
+
+	write_unlock(&(tree->dk_lock));
+}
+
+/* estimate api. Implementation is in estimate.c */
+reiser4_block_nr estimate_one_insert_item(reiser4_tree *);
+reiser4_block_nr estimate_one_insert_into_item(reiser4_tree *);
+reiser4_block_nr estimate_insert_flow(tree_level);
+reiser4_block_nr estimate_one_item_removal(reiser4_tree *);
+reiser4_block_nr calc_estimate_one_insert(tree_level);
+reiser4_block_nr estimate_dirty_cluster(struct inode *);
+reiser4_block_nr estimate_insert_cluster(struct inode *);
+reiser4_block_nr estimate_update_cluster(struct inode *);
+
+
+/* __REISER4_TREE_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/tree_mod.c newtree/fs/reiser4/tree_mod.c
--- oldtree/fs/reiser4/tree_mod.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/tree_mod.c	2006-02-21 15:58:35.022822280 +0000
@@ -0,0 +1,383 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/*
+ * Functions to add/delete new nodes to/from the tree.
+ *
+ * Functions from this file are used by carry (see carry*) to handle:
+ *
+ *     . insertion of new formatted node into tree
+ *
+ *     . addition of new tree root, increasing tree height
+ *
+ *     . removing tree root, decreasing tree height
+ *
+ */
+
+#include "forward.h"
+#include "debug.h"
+#include "dformat.h"
+#include "key.h"
+#include "coord.h"
+#include "plugin/plugin.h"
+#include "jnode.h"
+#include "znode.h"
+#include "tree_mod.h"
+#include "block_alloc.h"
+#include "tree_walk.h"
+#include "tree.h"
+#include "super.h"
+
+#include <linux/err.h>
+
+static int add_child_ptr(znode * parent, znode * child);
+/* warning only issued if error is not -E_REPEAT */
+#define ewarning( error, ... )			\
+	if( ( error ) != -E_REPEAT )		\
+		warning( __VA_ARGS__ )
+
+/* allocate new node on the @level and immediately on the right of @brother. */
+znode *new_node(znode * brother /* existing left neighbor of new node */ ,
+		tree_level level	/* tree level at which new node is to
+					 * be allocated */ )
+{
+	znode *result;
+	int retcode;
+	reiser4_block_nr blocknr;
+
+	assert("nikita-930", brother != NULL);
+	assert("umka-264", level < REAL_MAX_ZTREE_HEIGHT);
+
+	retcode = assign_fake_blocknr_formatted(&blocknr);
+	if (retcode == 0) {
+		result =
+		    zget(znode_get_tree(brother), &blocknr, NULL, level,
+			 GFP_KERNEL);
+		if (IS_ERR(result)) {
+			ewarning(PTR_ERR(result), "nikita-929",
+				 "Cannot allocate znode for carry: %li",
+				 PTR_ERR(result));
+			return result;
+		}
+		/* cheap test, can be executed even when debugging is off */
+		if (!znode_just_created(result)) {
+			warning("nikita-2213",
+				"Allocated already existing block: %llu",
+				(unsigned long long)blocknr);
+			zput(result);
+			return ERR_PTR(RETERR(-EIO));
+		}
+
+		assert("nikita-931", result != NULL);
+		result->nplug = znode_get_tree(brother)->nplug;
+		assert("nikita-933", result->nplug != NULL);
+
+		retcode = zinit_new(result, GFP_KERNEL);
+		if (retcode == 0) {
+			ZF_SET(result, JNODE_CREATED);
+			zrelse(result);
+		} else {
+			zput(result);
+			result = ERR_PTR(retcode);
+		}
+	} else {
+		/* failure to allocate new node during balancing.
+		   This should never happen. Ever. Returning -E_REPEAT
+		   is not viable solution, because "out of disk space"
+		   is not transient error that will go away by itself.
+		 */
+		ewarning(retcode, "nikita-928",
+			 "Cannot allocate block for carry: %i", retcode);
+		result = ERR_PTR(retcode);
+	}
+	assert("nikita-1071", result != NULL);
+	return result;
+}
+
+/* allocate new root and add it to the tree
+
+   This helper function is called by add_new_root().
+
+*/
+znode *add_tree_root(znode * old_root /* existing tree root */ ,
+		     znode * fake /* "fake" znode */ )
+{
+	reiser4_tree *tree = znode_get_tree(old_root);
+	znode *new_root = NULL;	/* to shut gcc up */
+	int result;
+
+	assert("nikita-1069", old_root != NULL);
+	assert("umka-262", fake != NULL);
+	assert("umka-263", tree != NULL);
+
+	/* "fake" znode---one always hanging just above current root. This
+	   node is locked when new root is created or existing root is
+	   deleted. Downward tree traversal takes lock on it before taking
+	   lock on a root node. This avoids race conditions with root
+	   manipulations.
+
+	 */
+	assert("nikita-1348", znode_above_root(fake));
+	assert("nikita-1211", znode_is_root(old_root));
+
+	result = 0;
+	if (tree->height >= REAL_MAX_ZTREE_HEIGHT) {
+		warning("nikita-1344", "Tree is too tall: %i", tree->height);
+		/* ext2 returns -ENOSPC when it runs out of free inodes with a
+		   following comment (fs/ext2/ialloc.c:441): Is it really
+		   ENOSPC?
+
+		   -EXFULL? -EINVAL?
+		 */
+		result = RETERR(-ENOSPC);
+	} else {
+		/* Allocate block for new root. It's not that
+		   important where it will be allocated, as root is
+		   almost always in memory. Moreover, allocate on
+		   flush can be going here.
+		 */
+		assert("nikita-1448", znode_is_root(old_root));
+		new_root = new_node(fake, tree->height + 1);
+		if (!IS_ERR(new_root) && (result = zload(new_root)) == 0) {
+			lock_handle rlh;
+
+			init_lh(&rlh);
+			result =
+			    longterm_lock_znode(&rlh, new_root,
+						ZNODE_WRITE_LOCK,
+						ZNODE_LOCK_LOPRI);
+			if (result == 0) {
+				parent_coord_t *in_parent;
+
+				znode_make_dirty(fake);
+
+				/* new root is a child of "fake" node */
+				write_lock_tree(tree);
+
+				++tree->height;
+
+				/* recalculate max balance overhead */
+				tree->estimate_one_insert =
+				    estimate_one_insert_item(tree);
+
+				tree->root_block = *znode_get_block(new_root);
+				in_parent = &new_root->in_parent;
+				init_parent_coord(in_parent, fake);
+				/* manually insert new root into sibling
+				 * list. With this all nodes involved into
+				 * balancing are connected after balancing is
+				 * done---useful invariant to check. */
+				sibling_list_insert_nolock(new_root, NULL);
+				write_unlock_tree(tree);
+
+				/* insert into new root pointer to the
+				   @old_root. */
+				assert("nikita-1110",
+				       WITH_DATA(new_root,
+						 node_is_empty(new_root)));
+				write_lock_dk(tree);
+				znode_set_ld_key(new_root, min_key());
+				znode_set_rd_key(new_root, max_key());
+				write_unlock_dk(tree);
+				if (REISER4_DEBUG) {
+					ZF_CLR(old_root, JNODE_LEFT_CONNECTED);
+					ZF_CLR(old_root, JNODE_RIGHT_CONNECTED);
+					ZF_SET(old_root, JNODE_ORPHAN);
+				}
+				result = add_child_ptr(new_root, old_root);
+				done_lh(&rlh);
+			}
+			zrelse(new_root);
+		}
+	}
+	if (result != 0)
+		new_root = ERR_PTR(result);
+	return new_root;
+}
+
+/* build &reiser4_item_data for inserting child pointer
+
+   Build &reiser4_item_data that can be later used to insert pointer to @child
+   in its parent.
+
+*/
+void build_child_ptr_data(znode * child	/* node pointer to which will be
+					 * inserted */ ,
+			  reiser4_item_data * data /* where to store result */ )
+{
+	assert("nikita-1116", child != NULL);
+	assert("nikita-1117", data != NULL);
+
+	/*
+	 * NOTE: use address of child's blocknr as address of data to be
+	 * inserted. As result of this data gets into on-disk structure in cpu
+	 * byte order. internal's create_hook converts it to little endian byte
+	 * order.
+	 */
+	data->data = (char *)znode_get_block(child);
+	/* data -> data is kernel space */
+	data->user = 0;
+	data->length = sizeof(reiser4_block_nr);
+	/* FIXME-VS: hardcoded internal item? */
+
+	/* AUDIT: Is it possible that "item_plugin_by_id" may find nothing? */
+	data->iplug = item_plugin_by_id(NODE_POINTER_ID);
+}
+
+/* add pointer to @child into empty @parent.
+
+   This is used when pointer to old root is inserted into new root which is
+   empty.
+*/
+static int add_child_ptr(znode * parent, znode * child)
+{
+	coord_t coord;
+	reiser4_item_data data;
+	int result;
+	reiser4_key key;
+
+	assert("nikita-1111", parent != NULL);
+	assert("nikita-1112", child != NULL);
+	assert("nikita-1115",
+	       znode_get_level(parent) == znode_get_level(child) + 1);
+
+	result = zload(parent);
+	if (result != 0)
+		return result;
+	assert("nikita-1113", node_is_empty(parent));
+	coord_init_first_unit(&coord, parent);
+
+	build_child_ptr_data(child, &data);
+	data.arg = NULL;
+
+	read_lock_dk(znode_get_tree(parent));
+	key = *znode_get_ld_key(child);
+	read_unlock_dk(znode_get_tree(parent));
+
+	result = node_plugin_by_node(parent)->create_item(&coord, &key, &data,
+							  NULL);
+	znode_make_dirty(parent);
+	zrelse(parent);
+	return result;
+}
+
+/* actually remove tree root */
+static int kill_root(reiser4_tree * tree	/* tree from which root is being
+						 * removed */ ,
+		     znode * old_root /* root node that is being removed */ ,
+		     znode * new_root	/* new root---sole child of *
+					 * @old_root */ ,
+		     const reiser4_block_nr * new_root_blk	/* disk address of
+								 * @new_root */ )
+{
+	znode *uber;
+	int result;
+	lock_handle handle_for_uber;
+
+	assert("umka-265", tree != NULL);
+	assert("nikita-1198", new_root != NULL);
+	assert("nikita-1199",
+	       znode_get_level(new_root) + 1 == znode_get_level(old_root));
+
+	assert("nikita-1201", znode_is_write_locked(old_root));
+
+	assert("nikita-1203",
+	       disk_addr_eq(new_root_blk, znode_get_block(new_root)));
+
+	init_lh(&handle_for_uber);
+	/* obtain and lock "fake" znode protecting changes in tree height. */
+	result = get_uber_znode(tree, ZNODE_WRITE_LOCK, ZNODE_LOCK_HIPRI,
+				&handle_for_uber);
+	if (result == 0) {
+		uber = handle_for_uber.node;
+
+		znode_make_dirty(uber);
+
+		/* don't take long term lock a @new_root. Take spinlock. */
+
+		write_lock_tree(tree);
+
+		tree->root_block = *new_root_blk;
+		--tree->height;
+
+		/* recalculate max balance overhead */
+		tree->estimate_one_insert = estimate_one_insert_item(tree);
+
+		assert("nikita-1202",
+		       tree->height == znode_get_level(new_root));
+
+		/* new root is child on "fake" node */
+		init_parent_coord(&new_root->in_parent, uber);
+		++uber->c_count;
+
+		/* sibling_list_insert_nolock(new_root, NULL); */
+		write_unlock_tree(tree);
+
+		/* reinitialise old root. */
+		result = node_plugin_by_node(old_root)->init(old_root);
+		znode_make_dirty(old_root);
+		if (result == 0) {
+			assert("nikita-1279", node_is_empty(old_root));
+			ZF_SET(old_root, JNODE_HEARD_BANSHEE);
+			old_root->c_count = 0;
+		}
+	}
+	done_lh(&handle_for_uber);
+
+	return result;
+}
+
+/* remove tree root
+
+   This function removes tree root, decreasing tree height by one.  Tree root
+   and its only child (that is going to become new tree root) are write locked
+   at the entry.
+
+   To remove tree root we need to take lock on special "fake" znode that
+   protects changes of tree height. See comments in add_tree_root() for more
+   on this.
+
+   Also parent pointers have to be updated in
+   old and new root. To simplify code, function is split into two parts: outer
+   kill_tree_root() collects all necessary arguments and calls kill_root()
+   to do the actual job.
+
+*/
+int kill_tree_root(znode * old_root /* tree root that we are removing */ )
+{
+	int result;
+	coord_t down_link;
+	znode *new_root;
+	reiser4_tree *tree;
+
+	assert("umka-266", current_tree != NULL);
+	assert("nikita-1194", old_root != NULL);
+	assert("nikita-1196", znode_is_root(old_root));
+	assert("nikita-1200", node_num_items(old_root) == 1);
+	assert("nikita-1401", znode_is_write_locked(old_root));
+
+	coord_init_first_unit(&down_link, old_root);
+
+	tree = znode_get_tree(old_root);
+	new_root = child_znode(&down_link, old_root, 0, 1);
+	if (!IS_ERR(new_root)) {
+		result =
+		    kill_root(tree, old_root, new_root,
+			      znode_get_block(new_root));
+		zput(new_root);
+	} else
+		result = PTR_ERR(new_root);
+
+	return result;
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/tree_mod.h newtree/fs/reiser4/tree_mod.h
--- oldtree/fs/reiser4/tree_mod.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/tree_mod.h	2006-02-21 15:58:34.115960144 +0000
@@ -0,0 +1,29 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Functions to add/delete new nodes to/from the tree. See tree_mod.c for
+ * comments. */
+
+#if !defined( __REISER4_TREE_MOD_H__ )
+#define __REISER4_TREE_MOD_H__
+
+#include "forward.h"
+
+znode *new_node(znode * brother, tree_level level);
+znode *add_tree_root(znode * old_root, znode * fake);
+int kill_tree_root(znode * old_root);
+void build_child_ptr_data(znode * child, reiser4_item_data * data);
+
+/* __REISER4_TREE_MOD_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/tree_walk.c newtree/fs/reiser4/tree_walk.c
--- oldtree/fs/reiser4/tree_walk.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/tree_walk.c	2006-02-21 15:58:35.454756616 +0000
@@ -0,0 +1,926 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Routines and macros to:
+
+   get_left_neighbor()
+
+   get_right_neighbor()
+
+   get_parent()
+
+   get_first_child()
+
+   get_last_child()
+
+   various routines to walk the whole tree and do things to it like
+   repack it, or move it to tertiary storage.  Please make them as
+   generic as is reasonable.
+
+*/
+
+#include "forward.h"
+#include "debug.h"
+#include "dformat.h"
+#include "coord.h"
+#include "plugin/item/item.h"
+#include "jnode.h"
+#include "znode.h"
+#include "tree_walk.h"
+#include "tree.h"
+#include "super.h"
+
+/* These macros are used internally in tree_walk.c in attempt to make
+   lock_neighbor() code usable to build lock_parent(), lock_right_neighbor,
+   lock_left_neighbor */
+#define GET_NODE_BY_PTR_OFFSET(node, off) (*(znode**)(((unsigned long)(node)) + (off)))
+#define FIELD_OFFSET(name)  offsetof(znode, name)
+#define PARENT_PTR_OFFSET FIELD_OFFSET(in_parent.node)
+#define LEFT_PTR_OFFSET   FIELD_OFFSET(left)
+#define RIGHT_PTR_OFFSET  FIELD_OFFSET(right)
+
+/* This is the generic procedure to get and lock `generic' neighbor (left or
+    right neighbor or parent). It implements common algorithm for all cases of
+    getting lock on neighbor node, only znode structure field is different in
+    each case. This is parameterized by ptr_offset argument, which is byte
+    offset for the pointer to the desired neighbor within the current node's
+    znode structure. This function should be called with the tree lock held */
+static int lock_neighbor(
+				/* resulting lock handle */
+				lock_handle * result,
+				/* znode to lock */
+				znode * node,
+				/* pointer to neighbor (or parent) znode field offset, in bytes from
+				   the base address of znode structure  */
+				int ptr_offset,
+				/* lock mode for longterm_lock_znode call */
+				znode_lock_mode mode,
+				/* lock request for longterm_lock_znode call */
+				znode_lock_request req,
+				/* GN_* flags */
+				int flags, int rlocked)
+{
+	reiser4_tree *tree = znode_get_tree(node);
+	znode *neighbor;
+	int ret;
+
+	assert("umka-236", node != NULL);
+	assert("umka-237", tree != NULL);
+	assert_rw_locked(&(tree->tree_lock));
+
+	if (flags & GN_TRY_LOCK)
+		req |= ZNODE_LOCK_NONBLOCK;
+	if (flags & GN_SAME_ATOM)
+		req |= ZNODE_LOCK_DONT_FUSE;
+
+	/* get neighbor's address by using of sibling link, quit while loop
+	   (and return) if link is not available. */
+	while (1) {
+		neighbor = GET_NODE_BY_PTR_OFFSET(node, ptr_offset);
+
+		/* return -E_NO_NEIGHBOR if parent or side pointer is NULL or if
+		 * node pointed by it is not connected.
+		 *
+		 * However, GN_ALLOW_NOT_CONNECTED option masks "connected"
+		 * check and allows passing reference to not connected znode to
+		 * subsequent longterm_lock_znode() call.  This kills possible
+		 * busy loop if we are trying to get longterm lock on locked but
+		 * not yet connected parent node. */
+		if (neighbor == NULL || !((flags & GN_ALLOW_NOT_CONNECTED)
+					  || znode_is_connected(neighbor))) {
+			return RETERR(-E_NO_NEIGHBOR);
+		}
+
+		/* protect it from deletion. */
+		zref(neighbor);
+
+		rlocked ? read_unlock_tree(tree) : write_unlock_tree(tree);
+
+		ret = longterm_lock_znode(result, neighbor, mode, req);
+
+		/* The lock handle obtains its own reference, release the one from above. */
+		zput(neighbor);
+
+		rlocked ? read_lock_tree(tree) : write_lock_tree(tree);
+
+		/* restart if node we got reference to is being
+		   invalidated. we should not get reference to this node
+		   again. */
+		if (ret == -EINVAL)
+			continue;
+		if (ret)
+			return ret;
+
+		/* check if neighbor link still points to just locked znode;
+		   the link could have been changed while the process slept. */
+		if (neighbor == GET_NODE_BY_PTR_OFFSET(node, ptr_offset))
+			return 0;
+
+		/* znode was locked by mistake; unlock it and restart locking
+		   process from beginning. */
+		rlocked ? read_unlock_tree(tree) : write_unlock_tree(tree);
+		longterm_unlock_znode(result);
+		rlocked ? read_lock_tree(tree) : write_lock_tree(tree);
+	}
+}
+
+/* get parent node with longterm lock, accepts GN* flags. */
+int reiser4_get_parent_flags(lock_handle * lh /* resulting lock handle */ ,
+			     znode * node /* child node */ ,
+			     znode_lock_mode mode
+			     /* type of lock: read or write */ ,
+			     int flags /* GN_* flags */ )
+{
+	int result;
+
+	read_lock_tree(znode_get_tree(node));
+	result = lock_neighbor(lh, node, PARENT_PTR_OFFSET, mode,
+			       ZNODE_LOCK_HIPRI, flags, 1);
+	read_unlock_tree(znode_get_tree(node));
+	return result;
+}
+
+/* wrapper function to lock right or left neighbor depending on GN_GO_LEFT
+   bit in @flags parameter  */
+/* Audited by: umka (2002.06.14) */
+static inline int
+lock_side_neighbor(lock_handle * result,
+		   znode * node, znode_lock_mode mode, int flags, int rlocked)
+{
+	int ret;
+	int ptr_offset;
+	znode_lock_request req;
+
+	if (flags & GN_GO_LEFT) {
+		ptr_offset = LEFT_PTR_OFFSET;
+		req = ZNODE_LOCK_LOPRI;
+	} else {
+		ptr_offset = RIGHT_PTR_OFFSET;
+		req = ZNODE_LOCK_HIPRI;
+	}
+
+	ret =
+	    lock_neighbor(result, node, ptr_offset, mode, req, flags, rlocked);
+
+	if (ret == -E_NO_NEIGHBOR)	/* if we walk left or right -E_NO_NEIGHBOR does not
+					 * guarantee that neighbor is absent in the
+					 * tree; in this case we return -ENOENT --
+					 * means neighbor at least not found in
+					 * cache */
+		return RETERR(-ENOENT);
+
+	return ret;
+}
+
+#if REISER4_DEBUG
+
+int check_sibling_list(znode * node)
+{
+	znode *scan;
+	znode *next;
+
+	assert("nikita-3283", LOCK_CNT_GTZ(write_locked_tree));
+
+	if (node == NULL)
+		return 1;
+
+	if (ZF_ISSET(node, JNODE_RIP))
+		return 1;
+
+	assert("nikita-3270", node != NULL);
+	assert_rw_write_locked(&(znode_get_tree(node)->tree_lock));
+
+	for (scan = node; znode_is_left_connected(scan); scan = next) {
+		next = scan->left;
+		if (next != NULL && !ZF_ISSET(next, JNODE_RIP)) {
+			assert("nikita-3271", znode_is_right_connected(next));
+			assert("nikita-3272", next->right == scan);
+		} else
+			break;
+	}
+	for (scan = node; znode_is_right_connected(scan); scan = next) {
+		next = scan->right;
+		if (next != NULL && !ZF_ISSET(next, JNODE_RIP)) {
+			assert("nikita-3273", znode_is_left_connected(next));
+			assert("nikita-3274", next->left == scan);
+		} else
+			break;
+	}
+	return 1;
+}
+
+#endif
+
+/* Znode sibling pointers maintenence. */
+
+/* Znode sibling pointers are established between any neighbored nodes which are
+   in cache.  There are two znode state bits (JNODE_LEFT_CONNECTED,
+   JNODE_RIGHT_CONNECTED), if left or right sibling pointer contains actual
+   value (even NULL), corresponded JNODE_*_CONNECTED bit is set.
+
+   Reiser4 tree operations which may allocate new znodes (CBK, tree balancing)
+   take care about searching (hash table lookup may be required) of znode
+   neighbors, establishing sibling pointers between them and setting
+   JNODE_*_CONNECTED state bits. */
+
+/* adjusting of sibling pointers and `connected' states for two
+   neighbors; works if one neighbor is NULL (was not found). */
+
+/* FIXME-VS: this is unstatic-ed to use in tree.c in prepare_twig_cut */
+void link_left_and_right(znode * left, znode * right)
+{
+	assert("nikita-3275", check_sibling_list(left));
+	assert("nikita-3275", check_sibling_list(right));
+
+	if (left != NULL) {
+		if (left->right == NULL) {
+			left->right = right;
+			ZF_SET(left, JNODE_RIGHT_CONNECTED);
+
+			ON_DEBUG(left->right_version =
+				 atomic_inc_return(&delim_key_version);
+			    );
+
+		} else if (ZF_ISSET(left->right, JNODE_HEARD_BANSHEE)
+			   && left->right != right) {
+
+			ON_DEBUG(left->right->left_version =
+				 atomic_inc_return(&delim_key_version);
+				 left->right_version =
+				 atomic_inc_return(&delim_key_version););
+
+			left->right->left = NULL;
+			left->right = right;
+			ZF_SET(left, JNODE_RIGHT_CONNECTED);
+		} else
+			/*
+			 * there is a race condition in renew_sibling_link()
+			 * and assertions below check that it is only one
+			 * there. Thread T1 calls renew_sibling_link() without
+			 * GN_NO_ALLOC flag. zlook() doesn't find neighbor
+			 * node, but before T1 gets to the
+			 * link_left_and_right(), another thread T2 creates
+			 * neighbor node and connects it. check for
+			 * left->right == NULL above protects T1 from
+			 * overwriting correct left->right pointer installed
+			 * by T2.
+			 */
+			assert("nikita-3302",
+			       right == NULL || left->right == right);
+	}
+	if (right != NULL) {
+		if (right->left == NULL) {
+			right->left = left;
+			ZF_SET(right, JNODE_LEFT_CONNECTED);
+
+			ON_DEBUG(right->left_version =
+				 atomic_inc_return(&delim_key_version);
+			    );
+
+		} else if (ZF_ISSET(right->left, JNODE_HEARD_BANSHEE)
+			   && right->left != left) {
+
+			ON_DEBUG(right->left->right_version =
+				 atomic_inc_return(&delim_key_version);
+				 right->left_version =
+				 atomic_inc_return(&delim_key_version););
+
+			right->left->right = NULL;
+			right->left = left;
+			ZF_SET(right, JNODE_LEFT_CONNECTED);
+
+		} else
+			assert("nikita-3303",
+			       left == NULL || right->left == left);
+	}
+	assert("nikita-3275", check_sibling_list(left));
+	assert("nikita-3275", check_sibling_list(right));
+}
+
+/* Audited by: umka (2002.06.14) */
+static void link_znodes(znode * first, znode * second, int to_left)
+{
+	if (to_left)
+		link_left_and_right(second, first);
+	else
+		link_left_and_right(first, second);
+}
+
+/* getting of next (to left or to right, depend on gn_to_left bit in flags)
+   coord's unit position in horizontal direction, even across node
+   boundary. Should be called under tree lock, it protects nonexistence of
+   sibling link on parent level, if lock_side_neighbor() fails with
+   -ENOENT. */
+static int far_next_coord(coord_t * coord, lock_handle * handle, int flags)
+{
+	int ret;
+	znode *node;
+	reiser4_tree *tree;
+
+	assert("umka-243", coord != NULL);
+	assert("umka-244", handle != NULL);
+
+	handle->owner = NULL;	/* mark lock handle as unused */
+
+	ret =
+	    (flags & GN_GO_LEFT) ? coord_prev_unit(coord) :
+	    coord_next_unit(coord);
+	if (!ret)
+		return 0;
+
+	ret =
+	    lock_side_neighbor(handle, coord->node, ZNODE_READ_LOCK, flags, 0);
+	if (ret)
+		return ret;
+
+	node = handle->node;
+	tree = znode_get_tree(node);
+	write_unlock_tree(tree);
+
+	coord_init_zero(coord);
+
+	/* We avoid synchronous read here if it is specified by flag. */
+	if ((flags & GN_ASYNC) && znode_page(handle->node) == NULL) {
+		ret = jstartio(ZJNODE(handle->node));
+		if (!ret)
+			ret = -E_REPEAT;
+		goto error_locked;
+	}
+
+	/* corresponded zrelse() should be called by the clients of
+	   far_next_coord(), in place when this node gets unlocked. */
+	ret = zload(handle->node);
+	if (ret)
+		goto error_locked;
+
+	if (flags & GN_GO_LEFT)
+		coord_init_last_unit(coord, node);
+	else
+		coord_init_first_unit(coord, node);
+
+	if (0) {
+	      error_locked:
+		longterm_unlock_znode(handle);
+	}
+	write_lock_tree(tree);
+	return ret;
+}
+
+/* Very significant function which performs a step in horizontal direction
+   when sibling pointer is not available.  Actually, it is only function which
+   does it.
+   Note: this function does not restore locking status at exit,
+   caller should does care about proper unlocking and zrelsing */
+static int
+renew_sibling_link(coord_t * coord, lock_handle * handle, znode * child,
+		   tree_level level, int flags, int *nr_locked)
+{
+	int ret;
+	int to_left = flags & GN_GO_LEFT;
+	reiser4_block_nr da;
+	/* parent of the neighbor node; we set it to parent until not sharing
+	   of one parent between child and neighbor node is detected */
+	znode *side_parent = coord->node;
+	reiser4_tree *tree = znode_get_tree(child);
+	znode *neighbor = NULL;
+
+	assert("umka-245", coord != NULL);
+	assert("umka-246", handle != NULL);
+	assert("umka-247", child != NULL);
+	assert("umka-303", tree != NULL);
+
+	write_lock_tree(tree);
+	ret = far_next_coord(coord, handle, flags);
+
+	if (ret) {
+		if (ret != -ENOENT) {
+			write_unlock_tree(tree);
+			return ret;
+		}
+	} else {
+		item_plugin *iplug;
+
+		if (handle->owner != NULL) {
+			(*nr_locked)++;
+			side_parent = handle->node;
+		}
+
+		/* does coord object points to internal item? We do not
+		   support sibling pointers between znode for formatted and
+		   unformatted nodes and return -E_NO_NEIGHBOR in that case. */
+		iplug = item_plugin_by_coord(coord);
+		if (!item_is_internal(coord)) {
+			link_znodes(child, NULL, to_left);
+			write_unlock_tree(tree);
+			/* we know there can't be formatted neighbor */
+			return RETERR(-E_NO_NEIGHBOR);
+		}
+		write_unlock_tree(tree);
+
+		iplug->s.internal.down_link(coord, NULL, &da);
+
+		if (flags & GN_NO_ALLOC) {
+			neighbor = zlook(tree, &da);
+		} else {
+			neighbor =
+			    zget(tree, &da, side_parent, level, GFP_KERNEL);
+		}
+
+		if (IS_ERR(neighbor)) {
+			ret = PTR_ERR(neighbor);
+			return ret;
+		}
+
+		if (neighbor)
+			/* update delimiting keys */
+			set_child_delimiting_keys(coord->node, coord, neighbor);
+
+		write_lock_tree(tree);
+	}
+
+	if (likely(neighbor == NULL ||
+		   (znode_get_level(child) == znode_get_level(neighbor)
+		    && child != neighbor)))
+		link_znodes(child, neighbor, to_left);
+	else {
+		warning("nikita-3532",
+			"Sibling nodes on the different levels: %i != %i\n",
+			znode_get_level(child), znode_get_level(neighbor));
+		ret = RETERR(-EIO);
+	}
+
+	write_unlock_tree(tree);
+
+	/* if GN_NO_ALLOC isn't set we keep reference to neighbor znode */
+	if (neighbor != NULL && (flags & GN_NO_ALLOC))
+		/* atomic_dec(&ZJNODE(neighbor)->x_count); */
+		zput(neighbor);
+
+	return ret;
+}
+
+/* This function is for establishing of one side relation. */
+/* Audited by: umka (2002.06.14) */
+static int connect_one_side(coord_t * coord, znode * node, int flags)
+{
+	coord_t local;
+	lock_handle handle;
+	int nr_locked;
+	int ret;
+
+	assert("umka-248", coord != NULL);
+	assert("umka-249", node != NULL);
+
+	coord_dup_nocheck(&local, coord);
+
+	init_lh(&handle);
+
+	ret =
+	    renew_sibling_link(&local, &handle, node, znode_get_level(node),
+			       flags | GN_NO_ALLOC, &nr_locked);
+
+	if (handle.owner != NULL) {
+		/* complementary operations for zload() and lock() in far_next_coord() */
+		zrelse(handle.node);
+		longterm_unlock_znode(&handle);
+	}
+
+	/* we catch error codes which are not interesting for us because we
+	   run renew_sibling_link() only for znode connection. */
+	if (ret == -ENOENT || ret == -E_NO_NEIGHBOR)
+		return 0;
+
+	return ret;
+}
+
+/* if @child is not in `connected' state, performs hash searches for left and
+   right neighbor nodes and establishes horizontal sibling links */
+/* Audited by: umka (2002.06.14), umka (2002.06.15) */
+int connect_znode(coord_t * parent_coord, znode * child)
+{
+	reiser4_tree *tree = znode_get_tree(child);
+	int ret = 0;
+
+	assert("zam-330", parent_coord != NULL);
+	assert("zam-331", child != NULL);
+	assert("zam-332", parent_coord->node != NULL);
+	assert("umka-305", tree != NULL);
+
+	/* it is trivial to `connect' root znode because it can't have
+	   neighbors */
+	if (znode_above_root(parent_coord->node)) {
+		child->left = NULL;
+		child->right = NULL;
+		ZF_SET(child, JNODE_LEFT_CONNECTED);
+		ZF_SET(child, JNODE_RIGHT_CONNECTED);
+
+		ON_DEBUG(child->left_version =
+			 atomic_inc_return(&delim_key_version);
+			 child->right_version =
+			 atomic_inc_return(&delim_key_version););
+
+		return 0;
+	}
+
+	/* load parent node */
+	coord_clear_iplug(parent_coord);
+	ret = zload(parent_coord->node);
+
+	if (ret != 0)
+		return ret;
+
+	/* protect `connected' state check by tree_lock */
+	read_lock_tree(tree);
+
+	if (!znode_is_right_connected(child)) {
+		read_unlock_tree(tree);
+		/* connect right (default is right) */
+		ret = connect_one_side(parent_coord, child, GN_NO_ALLOC);
+		if (ret)
+			goto zrelse_and_ret;
+
+		read_lock_tree(tree);
+	}
+
+	ret = znode_is_left_connected(child);
+
+	read_unlock_tree(tree);
+
+	if (!ret) {
+		ret =
+		    connect_one_side(parent_coord, child,
+				     GN_NO_ALLOC | GN_GO_LEFT);
+	} else
+		ret = 0;
+
+      zrelse_and_ret:
+	zrelse(parent_coord->node);
+
+	return ret;
+}
+
+/* this function is like renew_sibling_link() but allocates neighbor node if
+   it doesn't exist and `connects' it. It may require making two steps in
+   horizontal direction, first one for neighbor node finding/allocation,
+   second one is for finding neighbor of neighbor to connect freshly allocated
+   znode. */
+/* Audited by: umka (2002.06.14), umka (2002.06.15) */
+static int
+renew_neighbor(coord_t * coord, znode * node, tree_level level, int flags)
+{
+	coord_t local;
+	lock_handle empty[2];
+	reiser4_tree *tree = znode_get_tree(node);
+	znode *neighbor = NULL;
+	int nr_locked = 0;
+	int ret;
+
+	assert("umka-250", coord != NULL);
+	assert("umka-251", node != NULL);
+	assert("umka-307", tree != NULL);
+	assert("umka-308", level <= tree->height);
+
+	/* umka (2002.06.14)
+	   Here probably should be a check for given "level" validness.
+	   Something like assert("xxx-yyy", level < REAL_MAX_ZTREE_HEIGHT);
+	 */
+
+	coord_dup(&local, coord);
+
+	ret =
+	    renew_sibling_link(&local, &empty[0], node, level,
+			       flags & ~GN_NO_ALLOC, &nr_locked);
+	if (ret)
+		goto out;
+
+	/* tree lock is not needed here because we keep parent node(s) locked
+	   and reference to neighbor znode incremented */
+	neighbor = (flags & GN_GO_LEFT) ? node->left : node->right;
+
+	read_lock_tree(tree);
+	ret = znode_is_connected(neighbor);
+	read_unlock_tree(tree);
+	if (ret) {
+		ret = 0;
+		goto out;
+	}
+
+	ret =
+	    renew_sibling_link(&local, &empty[nr_locked], neighbor, level,
+			       flags | GN_NO_ALLOC, &nr_locked);
+	/* second renew_sibling_link() call is used for znode connection only,
+	   so we can live with these errors */
+	if (-ENOENT == ret || -E_NO_NEIGHBOR == ret)
+		ret = 0;
+
+      out:
+
+	for (--nr_locked; nr_locked >= 0; --nr_locked) {
+		zrelse(empty[nr_locked].node);
+		longterm_unlock_znode(&empty[nr_locked]);
+	}
+
+	if (neighbor != NULL)
+		/* decrement znode reference counter without actually
+		   releasing it. */
+		atomic_dec(&ZJNODE(neighbor)->x_count);
+
+	return ret;
+}
+
+/*
+   reiser4_get_neighbor() -- lock node's neighbor.
+
+   reiser4_get_neighbor() locks node's neighbor (left or right one, depends on
+   given parameter) using sibling link to it. If sibling link is not available
+   (i.e. neighbor znode is not in cache) and flags allow read blocks, we go one
+   level up for information about neighbor's disk address. We lock node's
+   parent, if it is common parent for both 'node' and its neighbor, neighbor's
+   disk address is in next (to left or to right) down link from link that points
+   to original node. If not, we need to lock parent's neighbor, read its content
+   and take first(last) downlink with neighbor's disk address.  That locking
+   could be done by using sibling link and lock_neighbor() function, if sibling
+   link exists. In another case we have to go level up again until we find
+   common parent or valid sibling link. Then go down
+   allocating/connecting/locking/reading nodes until neighbor of first one is
+   locked.
+
+   @neighbor:  result lock handle,
+   @node: a node which we lock neighbor of,
+   @lock_mode: lock mode {LM_READ, LM_WRITE},
+   @flags: logical OR of {GN_*} (see description above) subset.
+
+   @return: 0 if success, negative value if lock was impossible due to an error
+   or lack of neighbor node.
+*/
+
+/* Audited by: umka (2002.06.14), umka (2002.06.15) */
+int
+reiser4_get_neighbor(lock_handle * neighbor, znode * node,
+		     znode_lock_mode lock_mode, int flags)
+{
+	reiser4_tree *tree = znode_get_tree(node);
+	lock_handle path[REAL_MAX_ZTREE_HEIGHT];
+
+	coord_t coord;
+
+	tree_level base_level;
+	tree_level h = 0;
+	int ret;
+
+	assert("umka-252", tree != NULL);
+	assert("umka-253", neighbor != NULL);
+	assert("umka-254", node != NULL);
+
+	base_level = znode_get_level(node);
+
+	assert("umka-310", base_level <= tree->height);
+
+	coord_init_zero(&coord);
+
+      again:
+	/* first, we try to use simple lock_neighbor() which requires sibling
+	   link existence */
+	read_lock_tree(tree);
+	ret = lock_side_neighbor(neighbor, node, lock_mode, flags, 1);
+	read_unlock_tree(tree);
+	if (!ret) {
+		/* load znode content if it was specified */
+		if (flags & GN_LOAD_NEIGHBOR) {
+			ret = zload(node);
+			if (ret)
+				longterm_unlock_znode(neighbor);
+		}
+		return ret;
+	}
+
+	/* only -ENOENT means we may look upward and try to connect
+	   @node with its neighbor (if @flags allow us to do it) */
+	if (ret != -ENOENT || !(flags & GN_CAN_USE_UPPER_LEVELS))
+		return ret;
+
+	/* before establishing of sibling link we lock parent node; it is
+	   required by renew_neighbor() to work.  */
+	init_lh(&path[0]);
+	ret = reiser4_get_parent(&path[0], node, ZNODE_READ_LOCK);
+	if (ret)
+		return ret;
+	if (znode_above_root(path[0].node)) {
+		longterm_unlock_znode(&path[0]);
+		return RETERR(-E_NO_NEIGHBOR);
+	}
+
+	while (1) {
+		znode *child = (h == 0) ? node : path[h - 1].node;
+		znode *parent = path[h].node;
+
+		ret = zload(parent);
+		if (ret)
+			break;
+
+		ret = find_child_ptr(parent, child, &coord);
+
+		if (ret) {
+			zrelse(parent);
+			break;
+		}
+
+		/* try to establish missing sibling link */
+		ret = renew_neighbor(&coord, child, h + base_level, flags);
+
+		zrelse(parent);
+
+		switch (ret) {
+		case 0:
+			/* unlocking of parent znode prevents simple
+			   deadlock situation */
+			done_lh(&path[h]);
+
+			/* depend on tree level we stay on we repeat first
+			   locking attempt ...  */
+			if (h == 0)
+				goto again;
+
+			/* ... or repeat establishing of sibling link at
+			   one level below. */
+			--h;
+			break;
+
+		case -ENOENT:
+			/* sibling link is not available -- we go
+			   upward. */
+			init_lh(&path[h + 1]);
+			ret =
+			    reiser4_get_parent(&path[h + 1], parent,
+					       ZNODE_READ_LOCK);
+			if (ret)
+				goto fail;
+			++h;
+			if (znode_above_root(path[h].node)) {
+				ret = RETERR(-E_NO_NEIGHBOR);
+				goto fail;
+			}
+			break;
+
+		case -E_DEADLOCK:
+			/* there was lock request from hi-pri locker. if
+			   it is possible we unlock last parent node and
+			   re-lock it again. */
+			for (; check_deadlock(); h--) {
+				done_lh(&path[h]);
+				if (h == 0)
+					goto fail;
+			}
+
+			break;
+
+		default:	/* other errors. */
+			goto fail;
+		}
+	}
+      fail:
+	ON_DEBUG(check_lock_node_data(node));
+	ON_DEBUG(check_lock_data());
+
+	/* unlock path */
+	do {
+		/* FIXME-Zam: when we get here from case -E_DEADLOCK's goto
+		   fail; path[0] is already done_lh-ed, therefore
+		   longterm_unlock_znode(&path[h]); is not applicable */
+		done_lh(&path[h]);
+		--h;
+	} while (h + 1 != 0);
+
+	return ret;
+}
+
+/* remove node from sibling list */
+/* Audited by: umka (2002.06.14) */
+void sibling_list_remove(znode * node)
+{
+	reiser4_tree *tree;
+
+	tree = znode_get_tree(node);
+	assert("umka-255", node != NULL);
+	assert_rw_write_locked(&(tree->tree_lock));
+	assert("nikita-3275", check_sibling_list(node));
+
+	write_lock_dk(tree);
+	if (znode_is_right_connected(node) && node->right != NULL &&
+	    znode_is_left_connected(node) && node->left != NULL) {
+		assert("zam-32245",
+		       keyeq(znode_get_rd_key(node),
+			     znode_get_ld_key(node->right)));
+		znode_set_rd_key(node->left, znode_get_ld_key(node->right));
+	}
+	write_unlock_dk(tree);
+
+	if (znode_is_right_connected(node) && node->right != NULL) {
+		assert("zam-322", znode_is_left_connected(node->right));
+		node->right->left = node->left;
+		ON_DEBUG(node->right->left_version =
+			 atomic_inc_return(&delim_key_version);
+		    );
+	}
+	if (znode_is_left_connected(node) && node->left != NULL) {
+		assert("zam-323", znode_is_right_connected(node->left));
+		node->left->right = node->right;
+		ON_DEBUG(node->left->right_version =
+			 atomic_inc_return(&delim_key_version);
+		    );
+	}
+
+	ZF_CLR(node, JNODE_LEFT_CONNECTED);
+	ZF_CLR(node, JNODE_RIGHT_CONNECTED);
+	ON_DEBUG(node->left = node->right = NULL;
+		 node->left_version = atomic_inc_return(&delim_key_version);
+		 node->right_version = atomic_inc_return(&delim_key_version););
+	assert("nikita-3276", check_sibling_list(node));
+}
+
+/* disconnect node from sibling list */
+void sibling_list_drop(znode * node)
+{
+	znode *right;
+	znode *left;
+
+	assert("nikita-2464", node != NULL);
+	assert("nikita-3277", check_sibling_list(node));
+
+	right = node->right;
+	if (right != NULL) {
+		assert("nikita-2465", znode_is_left_connected(right));
+		right->left = NULL;
+		ON_DEBUG(right->left_version =
+			 atomic_inc_return(&delim_key_version);
+		    );
+	}
+	left = node->left;
+	if (left != NULL) {
+		assert("zam-323", znode_is_right_connected(left));
+		left->right = NULL;
+		ON_DEBUG(left->right_version =
+			 atomic_inc_return(&delim_key_version);
+		    );
+	}
+	ZF_CLR(node, JNODE_LEFT_CONNECTED);
+	ZF_CLR(node, JNODE_RIGHT_CONNECTED);
+	ON_DEBUG(node->left = node->right = NULL;
+		 node->left_version = atomic_inc_return(&delim_key_version);
+		 node->right_version = atomic_inc_return(&delim_key_version););
+}
+
+/* Insert new node into sibling list. Regular balancing inserts new node
+   after (at right side) existing and locked node (@before), except one case
+   of adding new tree root node. @before should be NULL in that case. */
+void sibling_list_insert_nolock(znode * new, znode * before)
+{
+	assert("zam-334", new != NULL);
+	assert("nikita-3298", !znode_is_left_connected(new));
+	assert("nikita-3299", !znode_is_right_connected(new));
+	assert("nikita-3300", new->left == NULL);
+	assert("nikita-3301", new->right == NULL);
+	assert("nikita-3278", check_sibling_list(new));
+	assert("nikita-3279", check_sibling_list(before));
+
+	if (before != NULL) {
+		assert("zam-333", znode_is_connected(before));
+		new->right = before->right;
+		new->left = before;
+		ON_DEBUG(new->right_version =
+			 atomic_inc_return(&delim_key_version);
+			 new->left_version =
+			 atomic_inc_return(&delim_key_version););
+		if (before->right != NULL) {
+			before->right->left = new;
+			ON_DEBUG(before->right->left_version =
+				 atomic_inc_return(&delim_key_version);
+			    );
+		}
+		before->right = new;
+		ON_DEBUG(before->right_version =
+			 atomic_inc_return(&delim_key_version);
+		    );
+	} else {
+		new->right = NULL;
+		new->left = NULL;
+		ON_DEBUG(new->right_version =
+			 atomic_inc_return(&delim_key_version);
+			 new->left_version =
+			 atomic_inc_return(&delim_key_version););
+	}
+	ZF_SET(new, JNODE_LEFT_CONNECTED);
+	ZF_SET(new, JNODE_RIGHT_CONNECTED);
+	assert("nikita-3280", check_sibling_list(new));
+	assert("nikita-3281", check_sibling_list(before));
+}
+
+/*
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 80
+   End:
+*/
diff -urN oldtree/fs/reiser4/tree_walk.h newtree/fs/reiser4/tree_walk.h
--- oldtree/fs/reiser4/tree_walk.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/tree_walk.h	2006-02-21 15:58:35.410763304 +0000
@@ -0,0 +1,125 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+/* definitions of reiser4 tree walk functions */
+
+#ifndef __FS_REISER4_TREE_WALK_H__
+#define __FS_REISER4_TREE_WALK_H__
+
+#include "debug.h"
+#include "forward.h"
+
+/* establishes horizontal links between cached znodes */
+int connect_znode(coord_t * coord, znode * node);
+
+/* tree traversal functions (reiser4_get_parent(), reiser4_get_neighbor())
+  have the following common arguments:
+
+  return codes:
+
+  @return : 0        - OK,
+
+ZAM-FIXME-HANS: wrong return code name.  Change them all.
+	    -ENOENT  - neighbor is not in cache, what is detected by sibling
+	               link absence.
+
+            -E_NO_NEIGHBOR - we are sure that neighbor (or parent) node cannot be
+                       found (because we are left-/right- most node of the
+		       tree, for example). Also, this return code is for
+		       reiser4_get_parent() when we see no parent link -- it
+		       means that our node is root node.
+
+            -E_DEADLOCK - deadlock detected (request from high-priority process
+	               received), other error codes are conformed to
+		       /usr/include/asm/errno.h .
+*/
+
+int
+reiser4_get_parent_flags(lock_handle * result, znode * node,
+			 znode_lock_mode mode, int flags);
+
+/* bits definition for reiser4_get_neighbor function `flags' arg. */
+typedef enum {
+	/* If sibling pointer is NULL, this flag allows get_neighbor() to try to
+	 * find not allocated not connected neigbor by going though upper
+	 * levels */
+	GN_CAN_USE_UPPER_LEVELS = 0x1,
+	/* locking left neighbor instead of right one */
+	GN_GO_LEFT = 0x2,
+	/* automatically load neighbor node content */
+	GN_LOAD_NEIGHBOR = 0x4,
+	/* return -E_REPEAT if can't lock  */
+	GN_TRY_LOCK = 0x8,
+	/* used internally in tree_walk.c, causes renew_sibling to not
+	   allocate neighbor znode, but only search for it in znode cache */
+	GN_NO_ALLOC = 0x10,
+	/* do not go across atom boundaries */
+	GN_SAME_ATOM = 0x20,
+	/* allow to lock not connected nodes */
+	GN_ALLOW_NOT_CONNECTED = 0x40,
+	/*  Avoid synchronous jload, instead, call jstartio() and return -E_REPEAT. */
+	GN_ASYNC = 0x80
+} znode_get_neigbor_flags;
+
+/* A commonly used wrapper for reiser4_get_parent_flags(). */
+static inline int reiser4_get_parent(lock_handle * result, znode * node,
+				     znode_lock_mode mode)
+{
+	return reiser4_get_parent_flags(result, node, mode,
+					GN_ALLOW_NOT_CONNECTED);
+}
+
+int reiser4_get_neighbor(lock_handle * neighbor, znode * node,
+			 znode_lock_mode lock_mode, int flags);
+
+/* there are wrappers for most common usages of reiser4_get_neighbor() */
+static inline int
+reiser4_get_left_neighbor(lock_handle * result, znode * node, int lock_mode,
+			  int flags)
+{
+	return reiser4_get_neighbor(result, node, lock_mode,
+				    flags | GN_GO_LEFT);
+}
+
+static inline int
+reiser4_get_right_neighbor(lock_handle * result, znode * node, int lock_mode,
+			   int flags)
+{
+	ON_DEBUG(check_lock_node_data(node));
+	ON_DEBUG(check_lock_data());
+	return reiser4_get_neighbor(result, node, lock_mode,
+				    flags & (~GN_GO_LEFT));
+}
+
+extern void sibling_list_remove(znode * node);
+extern void sibling_list_drop(znode * node);
+extern void sibling_list_insert_nolock(znode * new, znode * before);
+extern void link_left_and_right(znode * left, znode * right);
+
+/* Functions called by tree_walk() when tree_walk() ...  */
+struct tree_walk_actor {
+	/* ... meets a formatted node, */
+	int (*process_znode) (tap_t *, void *);
+	/* ... meets an extent, */
+	int (*process_extent) (tap_t *, void *);
+	/* ... begins tree traversal or repeats it after -E_REPEAT was returned by
+	 * node or extent processing functions. */
+	int (*before) (void *);
+};
+
+#if REISER4_DEBUG
+int check_sibling_list(znode * node);
+#else
+#define check_sibling_list(n) (1)
+#endif
+
+#endif				/* __FS_REISER4_TREE_WALK_H__ */
+
+/*
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/txnmgr.c newtree/fs/reiser4/txnmgr.c
--- oldtree/fs/reiser4/txnmgr.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/txnmgr.c	2006-02-21 15:58:35.456756312 +0000
@@ -0,0 +1,3870 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Joshua MacDonald wrote the first draft of this code. */
+
+/* ZAM-LONGTERM-FIXME-HANS: The locking in this file is badly designed, and a
+filesystem scales only as well as its worst locking design.  You need to
+substantially restructure this code. Josh was not as experienced a programmer
+as you.  Particularly review how the locking style differs from what you did
+for znodes usingt hi-lo priority locking, and present to me an opinion on
+whether the differences are well founded.  */
+
+/* I cannot help but to disagree with the sentiment above. Locking of
+ * transaction manager is _not_ badly designed, and, at the very least, is not
+ * the scaling bottleneck. Scaling bottleneck is _exactly_ hi-lo priority
+ * locking on znodes, especially on the root node of the tree. --nikita,
+ * 2003.10.13 */
+
+/* The txnmgr is a set of interfaces that keep track of atoms and transcrash handles.  The
+   txnmgr processes capture_block requests and manages the relationship between jnodes and
+   atoms through the various stages of a transcrash, and it also oversees the fusion and
+   capture-on-copy processes.  The main difficulty with this task is maintaining a
+   deadlock-free lock ordering between atoms and jnodes/handles.  The reason for the
+   difficulty is that jnodes, handles, and atoms contain pointer circles, and the cycle
+   must be broken.  The main requirement is that atom-fusion be deadlock free, so once you
+   hold the atom_lock you may then wait to acquire any jnode or handle lock.  This implies
+   that any time you check the atom-pointer of a jnode or handle and then try to lock that
+   atom, you must use trylock() and possibly reverse the order.
+
+   This code implements the design documented at:
+
+     http://namesys.com/txn-doc.html
+
+ZAM-FIXME-HANS: update v4.html to contain all of the information present in the above (but updated), and then remove the
+above document and reference the new.  Be sure to provide some credit to Josh.  I already have some writings on this
+topic in v4.html, but they are lacking in details present in the above.  Cure that.  Remember to write for the bright 12
+year old --- define all technical terms used.
+
+*/
+
+/* Thoughts on the external transaction interface:
+
+   In the current code, a TRANSCRASH handle is created implicitly by init_context() (which
+   creates state that lasts for the duration of a system call and is called at the start
+   of ReiserFS methods implementing VFS operations), and closed by reiser4_exit_context(),
+   occupying the scope of a single system call.  We wish to give certain applications an
+   interface to begin and close (commit) transactions.  Since our implementation of
+   transactions does not yet support isolation, allowing an application to open a
+   transaction implies trusting it to later close the transaction.  Part of the
+   transaction interface will be aimed at enabling that trust, but the interface for
+   actually using transactions is fairly narrow.
+
+   BEGIN_TRANSCRASH: Returns a transcrash identifier.  It should be possible to translate
+   this identifier into a string that a shell-script could use, allowing you to start a
+   transaction by issuing a command.  Once open, the transcrash should be set in the task
+   structure, and there should be options (I suppose) to allow it to be carried across
+   fork/exec.  A transcrash has several options:
+
+     - READ_FUSING or WRITE_FUSING: The default policy is for txn-capture to capture only
+     on writes (WRITE_FUSING) and allow "dirty reads".  If the application wishes to
+     capture on reads as well, it should set READ_FUSING.
+
+     - TIMEOUT: Since a non-isolated transcrash cannot be undone, every transcrash must
+     eventually close (or else the machine must crash).  If the application dies an
+     unexpected death with an open transcrash, for example, or if it hangs for a long
+     duration, one solution (to avoid crashing the machine) is to simply close it anyway.
+     This is a dangerous option, but it is one way to solve the problem until isolated
+     transcrashes are available for untrusted applications.
+
+     It seems to be what databases do, though it is unclear how one avoids a DoS attack
+     creating a vulnerability based on resource starvation.  Guaranteeing that some
+     minimum amount of computational resources are made available would seem more correct
+     than guaranteeing some amount of time.  When we again have someone to code the work,
+     this issue should be considered carefully.  -Hans
+
+   RESERVE_BLOCKS: A running transcrash should indicate to the transaction manager how
+   many dirty blocks it expects.  The reserve_blocks interface should be called at a point
+   where it is safe for the application to fail, because the system may not be able to
+   grant the allocation and the application must be able to back-out.  For this reason,
+   the number of reserve-blocks can also be passed as an argument to BEGIN_TRANSCRASH, but
+   the application may also wish to extend the allocation after beginning its transcrash.
+
+   CLOSE_TRANSCRASH: The application closes the transcrash when it is finished making
+   modifications that require transaction protection.  When isolated transactions are
+   supported the CLOSE operation is replaced by either COMMIT or ABORT.  For example, if a
+   RESERVE_BLOCKS call fails for the application, it should "abort" by calling
+   CLOSE_TRANSCRASH, even though it really commits any changes that were made (which is
+   why, for safety, the application should call RESERVE_BLOCKS before making any changes).
+
+   For actually implementing these out-of-system-call-scopped transcrashes, the
+   reiser4_context has a "txn_handle *trans" pointer that may be set to an open
+   transcrash.  Currently there are no dynamically-allocated transcrashes, but there is a
+   "kmem_cache_t *_txnh_slab" created for that purpose in this file.
+*/
+
+/* Extending the other system call interfaces for future transaction features:
+
+   Specialized applications may benefit from passing flags to the ordinary system call
+   interface such as read(), write(), or stat().  For example, the application specifies
+   WRITE_FUSING by default but wishes to add that a certain read() command should be
+   treated as READ_FUSING.  But which read?  Is it the directory-entry read, the stat-data
+   read, or the file-data read?  These issues are straight-forward, but there are a lot of
+   them and adding the necessary flags-passing code will be tedious.
+
+   When supporting isolated transactions, there is a corresponding READ_MODIFY_WRITE (RMW)
+   flag, which specifies that although it is a read operation being requested, a
+   write-lock should be taken.  The reason is that read-locks are shared while write-locks
+   are exclusive, so taking a read-lock when a later-write is known in advance will often
+   leads to deadlock.  If a reader knows it will write later, it should issue read
+   requests with the RMW flag set.
+*/
+
+/*
+   The znode/atom deadlock avoidance.
+
+   FIXME(Zam): writing of this comment is in progress.
+
+   The atom's special stage ASTAGE_CAPTURE_WAIT introduces a kind of atom's
+   long-term locking, which makes reiser4 locking scheme more complex.  It had
+   deadlocks until we implement deadlock avoidance algorithms.  That deadlocks
+   looked as the following: one stopped thread waits for a long-term lock on
+   znode, the thread who owns that lock waits when fusion with another atom will
+   be allowed.
+
+   The source of the deadlocks is an optimization of not capturing index nodes
+   for read.  Let's prove it.  Suppose we have dumb node capturing scheme which
+   unconditionally captures each block before locking it.
+
+   That scheme has no deadlocks.  Let's begin with the thread which stage is
+   ASTAGE_CAPTURE_WAIT and it waits for a znode lock.  The thread can't wait for
+   a capture because it's stage allows fusion with any atom except which are
+   being committed currently. A process of atom commit can't deadlock because
+   atom commit procedure does not acquire locks and does not fuse with other
+   atoms.  Reiser4 does capturing right before going to sleep inside the
+   longtertm_lock_znode() function, it means the znode which we want to lock is
+   already captured and its atom is in ASTAGE_CAPTURE_WAIT stage.  If we
+   continue the analysis we understand that no one process in the sequence may
+   waits atom fusion.  Thereby there are no deadlocks of described kind.
+
+   The capturing optimization makes the deadlocks possible.  A thread can wait a
+   lock which owner did not captured that node.  The lock owner's current atom
+   is not fused with the first atom and it does not get a ASTAGE_CAPTURE_WAIT
+   state. A deadlock is possible when that atom meets another one which is in
+   ASTAGE_CAPTURE_WAIT already.
+
+   The deadlock avoidance scheme includes two algorithms:
+
+   First algorithm is used when a thread captures a node which is locked but not
+   captured by another thread.  Those nodes are marked MISSED_IN_CAPTURE at the
+   moment we skip their capturing.  If such a node (marked MISSED_IN_CAPTURE) is
+   being captured by a thread with current atom is in ASTAGE_CAPTURE_WAIT, the
+   routine which forces all lock owners to join with current atom is executed.
+
+   Second algorithm does not allow to skip capturing of already captured nodes.
+
+   Both algorithms together prevent waiting a longterm lock without atom fusion
+   with atoms of all lock owners, which is a key thing for getting atom/znode
+   locking deadlocks.
+*/
+
+/*
+ * Transactions and mmap(2).
+ *
+ *     1. Transactions are not supported for accesses through mmap(2), because
+ *     this would effectively amount to user-level transactions whose duration
+ *     is beyond control of the kernel.
+ *
+ *     2. That said, we still want to preserve some decency with regard to
+ *     mmap(2). During normal write(2) call, following sequence of events
+ *     happens:
+ *
+ *         1. page is created;
+ *
+ *         2. jnode is created, dirtied and captured into current atom.
+ *
+ *         3. extent is inserted and modified.
+ *
+ *     Steps (2) and (3) take place under long term lock on the twig node.
+ *
+ *     When file is accessed through mmap(2) page is always created during
+ *     page fault. After this (in reiser4_readpage()->readpage_extent()):
+ *
+ *         1. if access is made to non-hole page new jnode is created, (if
+ *         necessary)
+ *
+ *         2. if access is made to the hole page, jnode is not created (XXX
+ *         not clear why).
+ *
+ *     Also, even if page is created by write page fault it is not marked
+ *     dirty immediately by handle_mm_fault(). Probably this is to avoid races
+ *     with page write-out.
+ *
+ *     Dirty bit installed by hardware is only transferred to the struct page
+ *     later, when page is unmapped (in zap_pte_range(), or
+ *     try_to_unmap_one()).
+ *
+ *     So, with mmap(2) we have to handle following irksome situations:
+ *
+ *         1. there exists modified page (clean or dirty) without jnode
+ *
+ *         2. there exists modified page (clean or dirty) with clean jnode
+ *
+ *         3. clean page which is a part of atom can be transparently modified
+ *         at any moment through mapping without becoming dirty.
+ *
+ *     (1) and (2) can lead to the out-of-memory situation: ->writepage()
+ *     doesn't know what to do with such pages and ->sync_sb()/->writepages()
+ *     don't see them, because these methods operate on atoms.
+ *
+ *     (3) can lead to the loss of data: suppose we have dirty page with dirty
+ *     captured jnode captured by some atom. As part of early flush (for
+ *     example) page was written out. Dirty bit was cleared on both page and
+ *     jnode. After this page is modified through mapping, but kernel doesn't
+ *     notice and just discards page and jnode as part of commit. (XXX
+ *     actually it doesn't, because to reclaim page ->releasepage() has to be
+ *     called and before this dirty bit will be transferred to the struct
+ *     page).
+ *
+ */
+
+#include "debug.h"
+#include "txnmgr.h"
+#include "jnode.h"
+#include "znode.h"
+#include "block_alloc.h"
+#include "tree.h"
+#include "wander.h"
+#include "ktxnmgrd.h"
+#include "super.h"
+#include "page_cache.h"
+#include "reiser4.h"
+#include "vfs_ops.h"
+#include "inode.h"
+#include "flush.h"
+
+#include <asm/atomic.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/writeback.h>
+#include <linux/swap.h>		/* for totalram_pages */
+
+static void atom_free(txn_atom * atom);
+
+static int commit_txnh(txn_handle * txnh);
+
+static void wakeup_atom_waitfor_list(txn_atom * atom);
+static void wakeup_atom_waiting_list(txn_atom * atom);
+
+static void capture_assign_txnh_nolock(txn_atom * atom, txn_handle * txnh);
+
+static void capture_assign_block_nolock(txn_atom * atom, jnode * node);
+
+static void fuse_not_fused_lock_owners(txn_handle * txnh, znode * node);
+
+static int capture_init_fusion(jnode * node, txn_handle * txnh,
+			       txn_capture mode, int can_coc);
+
+static int capture_fuse_wait(txn_handle *, txn_atom *, txn_atom *, txn_capture);
+
+static void capture_fuse_into(txn_atom * small, txn_atom * large);
+
+void invalidate_list(struct list_head *);
+
+/* GENERIC STRUCTURES */
+
+typedef struct _txn_wait_links txn_wait_links;
+
+struct _txn_wait_links {
+	lock_stack *_lock_stack;
+	struct list_head _fwaitfor_link;
+	struct list_head _fwaiting_link;
+	int (*waitfor_cb) (txn_atom * atom, struct _txn_wait_links * wlinks);
+	int (*waiting_cb) (txn_atom * atom, struct _txn_wait_links * wlinks);
+};
+
+/* FIXME: In theory, we should be using the slab cache init & destructor
+   methods instead of, e.g., jnode_init, etc. */
+static kmem_cache_t *_atom_slab = NULL;
+/* this is for user-visible, cross system-call transactions. */
+static kmem_cache_t *_txnh_slab = NULL;
+
+/**
+ * init_txnmgr_static - create transaction manager slab caches
+ *
+ * Initializes caches of txn-atoms and txn_handle. It is part of reiser4 module
+ * initialization.
+ */
+int init_txnmgr_static(void)
+{
+	assert("jmacd-600", _atom_slab == NULL);
+	assert("jmacd-601", _txnh_slab == NULL);
+
+	ON_DEBUG(atomic_set(&flush_cnt, 0));
+
+	_atom_slab = kmem_cache_create("txn_atom", sizeof(txn_atom), 0,
+				       SLAB_HWCACHE_ALIGN |
+				       SLAB_RECLAIM_ACCOUNT, NULL, NULL);
+	if (_atom_slab == NULL)
+		return RETERR(-ENOMEM);
+
+	_txnh_slab = kmem_cache_create("txn_handle", sizeof(txn_handle), 0,
+			      SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (_txnh_slab == NULL) {
+		kmem_cache_destroy(_atom_slab);
+		_atom_slab = NULL;
+		return RETERR(-ENOMEM);
+	}
+
+	return 0;
+}
+
+/**
+ * done_txnmgr_static - delete txn_atom and txn_handle caches
+ *
+ * This is called on reiser4 module unloading or system shutdown.
+ */
+void done_txnmgr_static(void)
+{
+	destroy_reiser4_cache(&_atom_slab);
+	destroy_reiser4_cache(&_txnh_slab);
+}
+
+/**
+ * init_txnmgr - initialize a new transaction manager
+ * @mgr: pointer to transaction manager embedded in reiser4 super block
+ *
+ * This is called on mount. Makes necessary initializations.
+ */
+void init_txnmgr(txn_mgr *mgr)
+{
+	assert("umka-169", mgr != NULL);
+
+	mgr->atom_count = 0;
+	mgr->id_count = 1;
+	INIT_LIST_HEAD(&mgr->atoms_list);
+	spin_lock_init(&mgr->tmgr_lock);
+	sema_init(&mgr->commit_semaphore, 1);
+}
+
+/**
+ * done_txnmgr - stop transaction manager
+ * @mgr: pointer to transaction manager embedded in reiser4 super block
+ *
+ * This is called on umount. Does sanity checks.
+ */
+void done_txnmgr(txn_mgr *mgr)
+{
+	assert("umka-170", mgr != NULL);
+	assert("umka-1701", list_empty_careful(&mgr->atoms_list));
+	assert("umka-1702", mgr->atom_count == 0);
+}
+
+/* Initialize a transaction handle. */
+/* Audited by: umka (2002.06.13) */
+static void txnh_init(txn_handle * txnh, txn_mode mode)
+{
+	assert("umka-171", txnh != NULL);
+
+	txnh->mode = mode;
+	txnh->atom = NULL;
+	txnh->flags = 0;
+	spin_lock_init(&txnh->hlock);
+	INIT_LIST_HEAD(&txnh->txnh_link);
+}
+
+#if REISER4_DEBUG
+/* Check if a transaction handle is clean. */
+static int txnh_isclean(txn_handle * txnh)
+{
+	assert("umka-172", txnh != NULL);
+	return txnh->atom == NULL &&
+		LOCK_CNT_NIL(spin_locked_txnh);
+}
+#endif
+
+/* Initialize an atom. */
+static void atom_init(txn_atom * atom)
+{
+	int level;
+
+	assert("umka-173", atom != NULL);
+
+	memset(atom, 0, sizeof(txn_atom));
+
+	atom->stage = ASTAGE_FREE;
+	atom->start_time = jiffies;
+
+	for (level = 0; level < REAL_MAX_ZTREE_HEIGHT + 1; level += 1)
+		INIT_LIST_HEAD(ATOM_DIRTY_LIST(atom, level));
+
+	INIT_LIST_HEAD(ATOM_CLEAN_LIST(atom));
+	INIT_LIST_HEAD(ATOM_OVRWR_LIST(atom));
+	INIT_LIST_HEAD(ATOM_WB_LIST(atom));
+	INIT_LIST_HEAD(&atom->inodes);
+	spin_lock_init(&atom->alock);
+	/* list of transaction handles */
+	INIT_LIST_HEAD(&atom->txnh_list);
+	/* link to transaction manager's list of atoms */
+	INIT_LIST_HEAD(&atom->atom_link);
+	INIT_LIST_HEAD(&atom->fwaitfor_list);
+	INIT_LIST_HEAD(&atom->fwaiting_list);
+	INIT_LIST_HEAD(&atom->protected);
+	blocknr_set_init(&atom->delete_set);
+	blocknr_set_init(&atom->wandered_map);
+
+	init_atom_fq_parts(atom);
+}
+
+#if REISER4_DEBUG
+/* Check if an atom is clean. */
+static int atom_isclean(txn_atom * atom)
+{
+	int level;
+
+	assert("umka-174", atom != NULL);
+
+	for (level = 0; level < REAL_MAX_ZTREE_HEIGHT + 1; level += 1) {
+		if (!list_empty_careful(ATOM_DIRTY_LIST(atom, level))) {
+			return 0;
+		}
+	}
+
+	return	atom->stage == ASTAGE_FREE &&
+		atom->txnh_count == 0 &&
+		atom->capture_count == 0 &&
+		atomic_read(&atom->refcount) == 0 &&
+		(&atom->atom_link == atom->atom_link.next &&
+		 &atom->atom_link == atom->atom_link.prev) &&
+		list_empty_careful(&atom->txnh_list) &&
+		list_empty_careful(ATOM_CLEAN_LIST(atom)) &&
+		list_empty_careful(ATOM_OVRWR_LIST(atom)) &&
+		list_empty_careful(ATOM_WB_LIST(atom)) &&
+		list_empty_careful(&atom->fwaitfor_list) &&
+		list_empty_careful(&atom->fwaiting_list) &&
+		list_empty_careful(&atom->protected) &&
+		atom_fq_parts_are_clean(atom);
+}
+#endif
+
+/* Begin a transaction in this context.  Currently this uses the reiser4_context's
+   trans_in_ctx, which means that transaction handles are stack-allocated.  Eventually
+   this will be extended to allow transaction handles to span several contexts. */
+/* Audited by: umka (2002.06.13) */
+void txn_begin(reiser4_context * context)
+{
+	assert("jmacd-544", context->trans == NULL);
+
+	context->trans = &context->trans_in_ctx;
+
+	/* FIXME_LATER_JMACD Currently there's no way to begin a TXN_READ_FUSING
+	   transcrash.  Default should be TXN_WRITE_FUSING.  Also, the _trans variable is
+	   stack allocated right now, but we would like to allow for dynamically allocated
+	   transcrashes that span multiple system calls.
+	 */
+	txnh_init(context->trans, TXN_WRITE_FUSING);
+}
+
+/* Finish a transaction handle context. */
+int txn_end(reiser4_context * context)
+{
+	long ret = 0;
+	txn_handle *txnh;
+
+	assert("umka-283", context != NULL);
+	assert("nikita-3012", schedulable());
+	assert("vs-24", context == get_current_context());
+	assert("nikita-2967", lock_stack_isclean(get_current_lock_stack()));
+
+	txnh = context->trans;
+	if (txnh != NULL) {
+		if (txnh->atom != NULL)
+			ret = commit_txnh(txnh);
+		assert("jmacd-633", txnh_isclean(txnh));
+		context->trans = NULL;
+	}
+	return ret;
+}
+
+void txn_restart(reiser4_context * context)
+{
+	txn_end(context);
+	preempt_point();
+	txn_begin(context);
+}
+
+void txn_restart_current(void)
+{
+	txn_restart(get_current_context());
+}
+
+/* TXN_ATOM */
+
+/* Get the atom belonging to a txnh, which is not locked.  Return txnh locked. Locks atom, if atom
+   is not NULL.  This performs the necessary spin_trylock to break the lock-ordering cycle.  May
+   return NULL. */
+static txn_atom *txnh_get_atom(txn_handle * txnh)
+{
+	txn_atom *atom;
+
+	assert("umka-180", txnh != NULL);
+	assert_spin_not_locked(&(txnh->hlock));
+
+	while (1) {
+		spin_lock_txnh(txnh);
+		atom = txnh->atom;
+
+		if (atom == NULL)
+			break;
+
+		if (spin_trylock_atom(atom))
+			break;
+
+		atomic_inc(&atom->refcount);
+
+		spin_unlock_txnh(txnh);
+		spin_lock_atom(atom);
+		spin_lock_txnh(txnh);
+
+		if (txnh->atom == atom) {
+			atomic_dec(&atom->refcount);
+			break;
+		}
+
+		spin_unlock_txnh(txnh);
+		atom_dec_and_unlock(atom);
+	}
+
+	return atom;
+}
+
+/* Get the current atom and spinlock it if current atom present. May return NULL  */
+txn_atom *get_current_atom_locked_nocheck(void)
+{
+	reiser4_context *cx;
+	txn_atom *atom;
+	txn_handle *txnh;
+
+	cx = get_current_context();
+	assert("zam-437", cx != NULL);
+
+	txnh = cx->trans;
+	assert("zam-435", txnh != NULL);
+
+	atom = txnh_get_atom(txnh);
+
+	spin_unlock_txnh(txnh);
+	return atom;
+}
+
+/* Get the atom belonging to a jnode, which is initially locked.  Return with
+   both jnode and atom locked.  This performs the necessary spin_trylock to
+   break the lock-ordering cycle.  Assumes the jnode is already locked, and
+   returns NULL if atom is not set. */
+txn_atom *jnode_get_atom(jnode * node)
+{
+	txn_atom *atom;
+
+	assert("umka-181", node != NULL);
+
+	while (1) {
+		assert_spin_locked(&(node->guard));
+
+		atom = node->atom;
+		/* node is not in any atom */
+		if (atom == NULL)
+			break;
+
+		/* If atom is not locked, grab the lock and return */
+		if (spin_trylock_atom(atom))
+			break;
+
+		/* At least one jnode belongs to this atom it guarantees that
+		 * atom->refcount > 0, we can safely increment refcount. */
+		atomic_inc(&atom->refcount);
+		spin_unlock_jnode(node);
+
+		/* re-acquire spin locks in the right order */
+		spin_lock_atom(atom);
+		spin_lock_jnode(node);
+
+		/* check if node still points to the same atom. */
+		if (node->atom == atom) {
+			atomic_dec(&atom->refcount);
+			break;
+		}
+
+		/* releasing of atom lock and reference requires not holding
+		 * locks on jnodes.  */
+		spin_unlock_jnode(node);
+
+		/* We do not sure that this atom has extra references except our
+		 * one, so we should call proper function which may free atom if
+		 * last reference is released. */
+		atom_dec_and_unlock(atom);
+
+		/* lock jnode again for getting valid node->atom pointer
+		 * value. */
+		spin_lock_jnode(node);
+	}
+
+	return atom;
+}
+
+/* Returns true if @node is dirty and part of the same atom as one of its neighbors.  Used
+   by flush code to indicate whether the next node (in some direction) is suitable for
+   flushing. */
+int
+same_slum_check(jnode * node, jnode * check, int alloc_check, int alloc_value)
+{
+	int compat;
+	txn_atom *atom;
+
+	assert("umka-182", node != NULL);
+	assert("umka-183", check != NULL);
+
+	/* Not sure what this function is supposed to do if supplied with @check that is
+	   neither formatted nor unformatted (bitmap or so). */
+	assert("nikita-2373", jnode_is_znode(check)
+	       || jnode_is_unformatted(check));
+
+	/* Need a lock on CHECK to get its atom and to check various state bits.
+	   Don't need a lock on NODE once we get the atom lock. */
+	/* It is not enough to lock two nodes and check (node->atom ==
+	   check->atom) because atom could be locked and being fused at that
+	   moment, jnodes of the atom of that state (being fused) can point to
+	   different objects, but the atom is the same. */
+	spin_lock_jnode(check);
+
+	atom = jnode_get_atom(check);
+
+	if (atom == NULL) {
+		compat = 0;
+	} else {
+		compat = (node->atom == atom && JF_ISSET(check, JNODE_DIRTY));
+
+		if (compat && jnode_is_znode(check)) {
+			compat &= znode_is_connected(JZNODE(check));
+		}
+
+		if (compat && alloc_check) {
+			compat &= (alloc_value == jnode_is_flushprepped(check));
+		}
+
+		spin_unlock_atom(atom);
+	}
+
+	spin_unlock_jnode(check);
+
+	return compat;
+}
+
+/* Decrement the atom's reference count and if it falls to zero, free it. */
+void atom_dec_and_unlock(txn_atom * atom)
+{
+	txn_mgr *mgr = &get_super_private(reiser4_get_current_sb())->tmgr;
+
+	assert("umka-186", atom != NULL);
+	assert_spin_locked(&(atom->alock));
+	assert("zam-1039", atomic_read(&atom->refcount) > 0);
+
+	if (atomic_dec_and_test(&atom->refcount)) {
+		/* take txnmgr lock and atom lock in proper order. */
+		if (!spin_trylock_txnmgr(mgr)) {
+			/* This atom should exist after we re-acquire its
+			 * spinlock, so we increment its reference counter. */
+			atomic_inc(&atom->refcount);
+			spin_unlock_atom(atom);
+			spin_lock_txnmgr(mgr);
+			spin_lock_atom(atom);
+
+			if (!atomic_dec_and_test(&atom->refcount)) {
+				spin_unlock_atom(atom);
+				spin_unlock_txnmgr(mgr);
+				return;
+			}
+		}
+		assert_spin_locked(&(mgr->tmgr_lock));
+		atom_free(atom);
+		spin_unlock_txnmgr(mgr);
+	} else
+		spin_unlock_atom(atom);
+}
+
+/* Create new atom and connect it to given transaction handle.  This adds the
+   atom to the transaction manager's list and sets its reference count to 1, an
+   artificial reference which is kept until it commits.  We play strange games
+   to avoid allocation under jnode & txnh spinlocks.*/
+
+static int atom_begin_and_assign_to_txnh(txn_atom ** atom_alloc, txn_handle * txnh)
+{
+	txn_atom *atom;
+	txn_mgr *mgr;
+
+	if (REISER4_DEBUG && rofs_tree(current_tree)) {
+		warning("nikita-3366", "Creating atom on rofs");
+		dump_stack();
+	}
+
+	if (*atom_alloc == NULL) {
+		(*atom_alloc) = kmem_cache_alloc(_atom_slab, GFP_KERNEL);
+
+		if (*atom_alloc == NULL)
+			return RETERR(-ENOMEM);
+	}
+
+	/* and, also, txnmgr spin lock should be taken before jnode and txnh
+	   locks. */
+	mgr = &get_super_private(reiser4_get_current_sb())->tmgr;
+	spin_lock_txnmgr(mgr);
+	spin_lock_txnh(txnh);
+
+	/* Check whether new atom still needed */
+	if (txnh->atom != NULL) {
+		/* NOTE-NIKITA probably it is rather better to free
+		 * atom_alloc here than thread it up to try_capture(). */
+
+		spin_unlock_txnh(txnh);
+		spin_unlock_txnmgr(mgr);
+
+		return -E_REPEAT;
+	}
+
+	atom = *atom_alloc;
+	*atom_alloc = NULL;
+
+	atom_init(atom);
+
+	assert("jmacd-17", atom_isclean(atom));
+
+        /*
+	 * do not use spin_lock_atom because we have broken lock ordering here
+	 * which is ok, as long as @atom is new and inaccessible for others.
+	 */
+	spin_lock(&(atom->alock));
+
+	/* add atom to the end of transaction manager's list of atoms */
+	list_add_tail(&atom->atom_link, &mgr->atoms_list);
+	atom->atom_id = mgr->id_count++;
+	mgr->atom_count += 1;
+
+	/* Release txnmgr lock */
+	spin_unlock_txnmgr(mgr);
+
+	/* One reference until it commits. */
+	atomic_inc(&atom->refcount);
+	atom->stage = ASTAGE_CAPTURE_FUSE;
+	atom->super = reiser4_get_current_sb();
+	capture_assign_txnh_nolock(atom, txnh);
+
+	spin_unlock(&(atom->alock));
+	spin_unlock_txnh(txnh);
+
+	return -E_REPEAT;
+}
+
+/* Return true if an atom is currently "open". */
+static int atom_isopen(const txn_atom * atom)
+{
+	assert("umka-185", atom != NULL);
+
+	return atom->stage > 0 && atom->stage < ASTAGE_PRE_COMMIT;
+}
+
+/* Return the number of pointers to this atom that must be updated during fusion.  This
+   approximates the amount of work to be done.  Fusion chooses the atom with fewer
+   pointers to fuse into the atom with more pointers. */
+static int atom_pointer_count(const txn_atom * atom)
+{
+	assert("umka-187", atom != NULL);
+
+	/* This is a measure of the amount of work needed to fuse this atom
+	 * into another. */
+	return atom->txnh_count + atom->capture_count;
+}
+
+/* Called holding the atom lock, this removes the atom from the transaction manager list
+   and frees it. */
+static void atom_free(txn_atom * atom)
+{
+	txn_mgr *mgr = &get_super_private(reiser4_get_current_sb())->tmgr;
+
+	assert("umka-188", atom != NULL);
+	assert_spin_locked(&(atom->alock));
+
+	/* Remove from the txn_mgr's atom list */
+	assert_spin_locked(&(mgr->tmgr_lock));
+	mgr->atom_count -= 1;
+	list_del_init(&atom->atom_link);
+
+	/* Clean the atom */
+	assert("jmacd-16",
+	       (atom->stage == ASTAGE_INVALID || atom->stage == ASTAGE_DONE));
+	atom->stage = ASTAGE_FREE;
+
+	blocknr_set_destroy(&atom->delete_set);
+	blocknr_set_destroy(&atom->wandered_map);
+
+	assert("jmacd-16", atom_isclean(atom));
+
+	spin_unlock_atom(atom);
+
+	kmem_cache_free(_atom_slab, atom);
+}
+
+static int atom_is_dotard(const txn_atom * atom)
+{
+	return time_after(jiffies, atom->start_time +
+			  get_current_super_private()->tmgr.atom_max_age);
+}
+
+static int atom_can_be_committed(txn_atom * atom)
+{
+	assert_spin_locked(&(atom->alock));
+	assert("zam-885", atom->txnh_count > atom->nr_waiters);
+	return atom->txnh_count == atom->nr_waiters + 1;
+}
+
+/* Return true if an atom should commit now.  This is determined by aging, atom
+   size or atom flags. */
+static int atom_should_commit(const txn_atom * atom)
+{
+	assert("umka-189", atom != NULL);
+	return
+	    (atom->flags & ATOM_FORCE_COMMIT) ||
+	    ((unsigned)atom_pointer_count(atom) >
+	     get_current_super_private()->tmgr.atom_max_size)
+	    || atom_is_dotard(atom);
+}
+
+/* return 1 if current atom exists and requires commit. */
+int current_atom_should_commit(void)
+{
+	txn_atom *atom;
+	int result = 0;
+
+	atom = get_current_atom_locked_nocheck();
+	if (atom) {
+		result = atom_should_commit(atom);
+		spin_unlock_atom(atom);
+	}
+	return result;
+}
+
+static int atom_should_commit_asap(const txn_atom * atom)
+{
+	unsigned int captured;
+	unsigned int pinnedpages;
+
+	assert("nikita-3309", atom != NULL);
+
+	captured = (unsigned)atom->capture_count;
+	pinnedpages = (captured >> PAGE_CACHE_SHIFT) * sizeof(znode);
+
+	return (pinnedpages > (totalram_pages >> 3)) || (atom->flushed > 100);
+}
+
+static jnode *find_first_dirty_in_list(struct list_head *head, int flags)
+{
+	jnode *first_dirty;
+
+	list_for_each_entry(first_dirty, head, capture_link) {
+		if (!(flags & JNODE_FLUSH_COMMIT)) {
+			/*
+			 * skip jnodes which "heard banshee" or having active
+			 * I/O
+			 */
+			if (JF_ISSET(first_dirty, JNODE_HEARD_BANSHEE) ||
+			    JF_ISSET(first_dirty, JNODE_WRITEBACK))
+				continue;
+		}
+		return first_dirty;
+	}
+	return NULL;
+}
+
+/* Get first dirty node from the atom's dirty_nodes[n] lists; return NULL if atom has no dirty
+   nodes on atom's lists */
+jnode *find_first_dirty_jnode(txn_atom * atom, int flags)
+{
+	jnode *first_dirty;
+	tree_level level;
+
+	assert_spin_locked(&(atom->alock));
+
+	/* The flush starts from LEAF_LEVEL (=1). */
+	for (level = 1; level < REAL_MAX_ZTREE_HEIGHT + 1; level += 1) {
+		if (list_empty_careful(ATOM_DIRTY_LIST(atom, level)))
+			continue;
+
+		first_dirty =
+		    find_first_dirty_in_list(ATOM_DIRTY_LIST(atom, level),
+					     flags);
+		if (first_dirty)
+			return first_dirty;
+	}
+
+	/* znode-above-root is on the list #0. */
+	return find_first_dirty_in_list(ATOM_DIRTY_LIST(atom, 0), flags);
+}
+
+#if REISER4_COPY_ON_CAPTURE
+
+/* this spin lock is used to prevent races during steal on capture.
+   FIXME: should be per filesystem or even per atom */
+spinlock_t scan_lock = SPIN_LOCK_UNLOCKED;
+
+/* Scan atom->writeback_nodes list and dispatch jnodes according to their state:
+ * move dirty and !writeback jnodes to @fq, clean jnodes to atom's clean
+ * list. */
+/* NOTE: doing that in end IO handler requires using of special spinlocks which
+ * disables interrupts in all places except IO handler. That is expensive. */
+static void dispatch_wb_list(txn_atom * atom, flush_queue_t * fq)
+{
+	jnode *cur;
+	int total, moved;
+
+	assert_spin_locked(&(atom->alock));
+
+	total = 0;
+	moved = 0;
+
+	spin_lock(&scan_lock);
+	cur = capture_list_front(ATOM_WB_LIST(atom));
+	while (!capture_list_end(ATOM_WB_LIST(atom), cur)) {
+		jnode *next;
+
+		total++;
+		JF_SET(cur, JNODE_SCANNED);
+		next = capture_list_next(cur);
+		if (!capture_list_end(ATOM_WB_LIST(atom), next))
+			JF_SET(next, JNODE_SCANNED);
+
+		spin_unlock(&scan_lock);
+
+		LOCK_JNODE(cur);
+		assert("vs-1441", NODE_LIST(cur) == WB_LIST);
+		if (!JF_ISSET(cur, JNODE_WRITEBACK)) {
+			moved++;
+			if (JF_ISSET(cur, JNODE_DIRTY)) {
+				queue_jnode(fq, cur);
+			} else {
+				/* move from writeback list to clean list */
+				capture_list_remove(cur);
+				capture_list_push_back(ATOM_CLEAN_LIST(atom),
+						       cur);
+				ON_DEBUG(count_jnode
+					 (atom, cur, WB_LIST, CLEAN_LIST, 1));
+			}
+		}
+		UNLOCK_JNODE(cur);
+
+		spin_lock(&scan_lock);
+		JF_CLR(cur, JNODE_SCANNED);
+		cur = next;
+		assert("vs-1450",
+		       ergo(!capture_list_end(ATOM_WB_LIST(atom), cur),
+			    JF_ISSET(cur, JNODE_SCANNED)
+			    && NODE_LIST(cur) == WB_LIST));
+	}
+	spin_unlock(&scan_lock);
+}
+
+#else
+
+static void dispatch_wb_list(txn_atom * atom, flush_queue_t * fq)
+{
+	jnode *cur;
+
+	assert("zam-905", atom_is_protected(atom));
+
+	cur = list_entry(ATOM_WB_LIST(atom)->next, jnode, capture_link);
+	while (ATOM_WB_LIST(atom) != &cur->capture_link) {
+		jnode *next = list_entry(cur->capture_link.next, jnode, capture_link);
+
+		spin_lock_jnode(cur);
+		if (!JF_ISSET(cur, JNODE_WRITEBACK)) {
+			if (JF_ISSET(cur, JNODE_DIRTY)) {
+				queue_jnode(fq, cur);
+			} else {
+				/* move jnode to atom's clean list */
+				list_del(&cur->capture_link);
+				list_add_tail(&cur->capture_link,
+					      ATOM_CLEAN_LIST(atom));
+			}
+		}
+		spin_unlock_jnode(cur);
+
+		cur = next;
+	}
+}
+
+#endif
+
+/* Scan current atom->writeback_nodes list, re-submit dirty and !writeback
+ * jnodes to disk. */
+static int submit_wb_list(void)
+{
+	int ret;
+	flush_queue_t *fq;
+
+	fq = get_fq_for_current_atom();
+	if (IS_ERR(fq))
+		return PTR_ERR(fq);
+
+	dispatch_wb_list(fq->atom, fq);
+	spin_unlock_atom(fq->atom);
+
+	ret = write_fq(fq, NULL, 1);
+	fq_put(fq);
+
+	return ret;
+}
+
+/* Wait completion of all writes, re-submit atom writeback list if needed. */
+static int current_atom_complete_writes(void)
+{
+	int ret;
+
+	/* Each jnode from that list was modified and dirtied when it had i/o
+	 * request running already. After i/o completion we have to resubmit
+	 * them to disk again.*/
+	ret = submit_wb_list();
+	if (ret < 0)
+		return ret;
+
+	/* Wait all i/o completion */
+	ret = current_atom_finish_all_fq();
+	if (ret)
+		return ret;
+
+	/* Scan wb list again; all i/o should be completed, we re-submit dirty
+	 * nodes to disk */
+	ret = submit_wb_list();
+	if (ret < 0)
+		return ret;
+
+	/* Wait all nodes we just submitted */
+	return current_atom_finish_all_fq();
+}
+
+#define TOOMANYFLUSHES (1 << 13)
+
+/* Called with the atom locked and no open "active" transaction handlers except
+   ours, this function calls flush_current_atom() until all dirty nodes are
+   processed.  Then it initiates commit processing.
+
+   Called by the single remaining open "active" txnh, which is closing. Other
+   open txnhs belong to processes which wait atom commit in commit_txnh()
+   routine. They are counted as "waiters" in atom->nr_waiters.  Therefore as
+   long as we hold the atom lock none of the jnodes can be captured and/or
+   locked.
+
+   Return value is an error code if commit fails.
+*/
+static int commit_current_atom(long *nr_submitted, txn_atom ** atom)
+{
+	reiser4_super_info_data *sbinfo = get_current_super_private();
+	long ret = 0;
+	/* how many times jnode_flush() was called as a part of attempt to
+	 * commit this atom. */
+	int flushiters;
+
+	assert("zam-888", atom != NULL && *atom != NULL);
+	assert_spin_locked(&((*atom)->alock));
+	assert("zam-887", get_current_context()->trans->atom == *atom);
+	assert("jmacd-151", atom_isopen(*atom));
+
+	/* lock ordering: delete_sema and commit_sema are unordered */
+	assert("nikita-3184",
+	       get_current_super_private()->delete_sema_owner != current);
+
+	for (flushiters = 0;; ++flushiters) {
+		ret =
+		    flush_current_atom(JNODE_FLUSH_WRITE_BLOCKS |
+				       JNODE_FLUSH_COMMIT,
+				       LONG_MAX /* nr_to_write */ ,
+				       nr_submitted, atom, NULL);
+		if (ret != -E_REPEAT)
+			break;
+
+		/* if atom's dirty list contains one znode which is
+		   HEARD_BANSHEE and is locked we have to allow lock owner to
+		   continue and uncapture that znode */
+		preempt_point();
+
+		*atom = get_current_atom_locked();
+		if (flushiters > TOOMANYFLUSHES && IS_POW(flushiters)) {
+			warning("nikita-3176",
+				"Flushing like mad: %i", flushiters);
+			info_atom("atom", *atom);
+			DEBUGON(flushiters > (1 << 20));
+		}
+	}
+
+	if (ret)
+		return ret;
+
+	assert_spin_locked(&((*atom)->alock));
+
+	if (!atom_can_be_committed(*atom)) {
+		spin_unlock_atom(*atom);
+		return RETERR(-E_REPEAT);
+	}
+
+	if ((*atom)->capture_count == 0)
+		goto done;
+
+	/* Up to this point we have been flushing and after flush is called we
+	   return -E_REPEAT.  Now we can commit.  We cannot return -E_REPEAT
+	   at this point, commit should be successful. */
+	atom_set_stage(*atom, ASTAGE_PRE_COMMIT);
+	ON_DEBUG(((*atom)->committer = current));
+	spin_unlock_atom(*atom);
+
+	ret = current_atom_complete_writes();
+	if (ret)
+		return ret;
+
+	assert("zam-906", list_empty(ATOM_WB_LIST(*atom)));
+
+	/* isolate critical code path which should be executed by only one
+	 * thread using tmgr semaphore */
+	down(&sbinfo->tmgr.commit_semaphore);
+
+	ret = reiser4_write_logs(nr_submitted);
+	if (ret < 0)
+		reiser4_panic("zam-597", "write log failed (%ld)\n", ret);
+
+	/* The atom->ovrwr_nodes list is processed under commit semaphore held
+	   because of bitmap nodes which are captured by special way in
+	   bitmap_pre_commit_hook(), that way does not include
+	   capture_fuse_wait() as a capturing of other nodes does -- the commit
+	   semaphore is used for transaction isolation instead. */
+	invalidate_list(ATOM_OVRWR_LIST(*atom));
+	up(&sbinfo->tmgr.commit_semaphore);
+
+	invalidate_list(ATOM_CLEAN_LIST(*atom));
+	invalidate_list(ATOM_WB_LIST(*atom));
+	assert("zam-927", list_empty(&(*atom)->inodes));
+
+	spin_lock_atom(*atom);
+ done:
+	atom_set_stage(*atom, ASTAGE_DONE);
+	ON_DEBUG((*atom)->committer = NULL);
+
+	/* Atom's state changes, so wake up everybody waiting for this
+	   event. */
+	wakeup_atom_waiting_list(*atom);
+
+	/* Decrement the "until commit" reference, at least one txnh (the caller) is
+	   still open. */
+	atomic_dec(&(*atom)->refcount);
+
+	assert("jmacd-1070", atomic_read(&(*atom)->refcount) > 0);
+	assert("jmacd-1062", (*atom)->capture_count == 0);
+	BUG_ON((*atom)->capture_count != 0);
+	assert_spin_locked(&((*atom)->alock));
+
+	return ret;
+}
+
+/* TXN_TXNH */
+
+/**
+ * force_commit_atom - commit current atom and wait commit completion
+ * @txnh:
+ *
+ * Commits current atom and wait commit completion; current atom and @txnh have
+ * to be spinlocked before call, this function unlocks them on exit.
+ */
+int force_commit_atom(txn_handle *txnh)
+{
+	txn_atom *atom;
+
+	assert("zam-837", txnh != NULL);
+	assert_spin_locked(&(txnh->hlock));
+	assert("nikita-2966", lock_stack_isclean(get_current_lock_stack()));
+
+	atom = txnh->atom;
+
+	assert("zam-834", atom != NULL);
+	assert_spin_locked(&(atom->alock));
+
+	/*
+	 * Set flags for atom and txnh: forcing atom commit and waiting for
+	 * commit completion
+	 */
+	txnh->flags |= TXNH_WAIT_COMMIT;
+	atom->flags |= ATOM_FORCE_COMMIT;
+
+	spin_unlock_txnh(txnh);
+	spin_unlock_atom(atom);
+
+	/* commit is here */
+	txn_restart_current();
+	return 0;
+}
+
+/* Called to force commit of any outstanding atoms.  @commit_all_atoms controls
+ * should we commit all atoms including new ones which are created after this
+ * functions is called. */
+int txnmgr_force_commit_all(struct super_block *super, int commit_all_atoms)
+{
+	int ret;
+	txn_atom *atom;
+	txn_mgr *mgr;
+	txn_handle *txnh;
+	unsigned long start_time = jiffies;
+	reiser4_context *ctx = get_current_context();
+
+	assert("nikita-2965", lock_stack_isclean(get_current_lock_stack()));
+	assert("nikita-3058", commit_check_locks());
+
+	txn_restart_current();
+
+	mgr = &get_super_private(super)->tmgr;
+
+	txnh = ctx->trans;
+
+      again:
+
+	spin_lock_txnmgr(mgr);
+
+	list_for_each_entry(atom, &mgr->atoms_list, atom_link) {
+		spin_lock_atom(atom);
+
+		/* Commit any atom which can be committed.  If @commit_new_atoms
+		 * is not set we commit only atoms which were created before
+		 * this call is started. */
+		if (commit_all_atoms
+		    || time_before_eq(atom->start_time, start_time)) {
+			if (atom->stage <= ASTAGE_POST_COMMIT) {
+				spin_unlock_txnmgr(mgr);
+
+				if (atom->stage < ASTAGE_PRE_COMMIT) {
+					spin_lock_txnh(txnh);
+					/* Add force-context txnh */
+					capture_assign_txnh_nolock(atom, txnh);
+					ret = force_commit_atom(txnh);
+					if (ret)
+						return ret;
+				} else
+					/* wait atom commit */
+					atom_wait_event(atom);
+
+				goto again;
+			}
+		}
+
+		spin_unlock_atom(atom);
+	}
+
+#if REISER4_DEBUG
+	if (commit_all_atoms) {
+		reiser4_super_info_data *sbinfo = get_super_private(super);
+		spin_lock_reiser4_super(sbinfo);
+		assert("zam-813",
+		       sbinfo->blocks_fake_allocated_unformatted == 0);
+		assert("zam-812", sbinfo->blocks_fake_allocated == 0);
+		spin_unlock_reiser4_super(sbinfo);
+	}
+#endif
+
+	spin_unlock_txnmgr(mgr);
+
+	return 0;
+}
+
+/* check whether commit_some_atoms() can commit @atom. Locking is up to the
+ * caller */
+static int atom_is_committable(txn_atom * atom)
+{
+	return
+	    atom->stage < ASTAGE_PRE_COMMIT &&
+	    atom->txnh_count == atom->nr_waiters && atom_should_commit(atom);
+}
+
+/* called periodically from ktxnmgrd to commit old atoms. Releases ktxnmgrd spin
+ * lock at exit */
+int commit_some_atoms(txn_mgr * mgr)
+{
+	int ret = 0;
+	txn_atom *atom;
+	txn_handle *txnh;
+	reiser4_context *ctx;
+	struct list_head *pos, *tmp;
+
+	ctx = get_current_context();
+	assert("nikita-2444", ctx != NULL);
+
+	txnh = ctx->trans;
+	spin_lock_txnmgr(mgr);
+
+	/*
+	 * this is to avoid gcc complain that atom might be used
+	 * uninitialized
+	 */
+	atom = NULL;
+
+	/* look for atom to commit */
+	list_for_each_safe(pos, tmp, &mgr->atoms_list) {
+		atom = list_entry(pos, txn_atom, atom_link);
+		/*
+		 * first test without taking atom spin lock, whether it is
+		 * eligible for committing at all
+		 */
+		if (atom_is_committable(atom)) {
+			/* now, take spin lock and re-check */
+			spin_lock_atom(atom);
+			if (atom_is_committable(atom))
+				break;
+			spin_unlock_atom(atom);
+		}
+	}
+
+	ret = (&mgr->atoms_list == pos);
+	spin_unlock_txnmgr(mgr);
+
+	if (ret) {
+		/* nothing found */
+		spin_unlock(&mgr->daemon->guard);
+		return 0;
+	}
+
+	spin_lock_txnh(txnh);
+
+	BUG_ON(atom == NULL);
+	/* Set the atom to force committing */
+	atom->flags |= ATOM_FORCE_COMMIT;
+
+	/* Add force-context txnh */
+	capture_assign_txnh_nolock(atom, txnh);
+
+	spin_unlock_txnh(txnh);
+	spin_unlock_atom(atom);
+
+	/* we are about to release daemon spin lock, notify daemon it
+	   has to rescan atoms */
+	mgr->daemon->rescan = 1;
+	spin_unlock(&mgr->daemon->guard);
+	txn_restart_current();
+	return 0;
+}
+
+static int txn_try_to_fuse_small_atom(txn_mgr * tmgr, txn_atom * atom)
+{
+	int atom_stage;
+	txn_atom *atom_2;
+	int repeat;
+
+	assert("zam-1051", atom->stage < ASTAGE_PRE_COMMIT);
+
+	atom_stage = atom->stage;
+	repeat = 0;
+
+	if (!spin_trylock_txnmgr(tmgr)) {
+		atomic_inc(&atom->refcount);
+		spin_unlock_atom(atom);
+		spin_lock_txnmgr(tmgr);
+		spin_lock_atom(atom);
+		repeat = 1;
+		if (atom->stage != atom_stage) {
+			spin_unlock_txnmgr(tmgr);
+			atom_dec_and_unlock(atom);
+			return -E_REPEAT;
+		}
+		atomic_dec(&atom->refcount);
+	}
+
+	list_for_each_entry(atom_2, &tmgr->atoms_list, atom_link) {
+		if (atom == atom_2)
+			continue;
+		/*
+		 * if trylock does not succeed we just do not fuse with that
+		 * atom.
+		 */
+		if (spin_trylock_atom(atom_2)) {
+			if (atom_2->stage < ASTAGE_PRE_COMMIT) {
+				spin_unlock_txnmgr(tmgr);
+				capture_fuse_into(atom_2, atom);
+				/* all locks are lost we can only repeat here */
+				return -E_REPEAT;
+			}
+			spin_unlock_atom(atom_2);
+		}
+	}
+	atom->flags |= ATOM_CANCEL_FUSION;
+	spin_unlock_txnmgr(tmgr);
+	if (repeat) {
+		spin_unlock_atom(atom);
+		return -E_REPEAT;
+	}
+	return 0;
+}
+
+/* Calls jnode_flush for current atom if it exists; if not, just take another
+   atom and call jnode_flush() for him.  If current transaction handle has
+   already assigned atom (current atom) we have to close current transaction
+   prior to switch to another atom or do something with current atom. This
+   code tries to flush current atom.
+
+   flush_some_atom() is called as part of memory clearing process. It is
+   invoked from balance_dirty_pages(), pdflushd, and entd.
+
+   If we can flush no nodes, atom is committed, because this frees memory.
+
+   If atom is too large or too old it is committed also.
+*/
+int
+flush_some_atom(jnode * start, long *nr_submitted, const struct writeback_control *wbc,
+		int flags)
+{
+	reiser4_context *ctx = get_current_context();
+	txn_mgr *tmgr = &get_super_private(ctx->super)->tmgr;
+	txn_handle *txnh = ctx->trans;
+	txn_atom *atom;
+	int ret;
+
+	BUG_ON(wbc->nr_to_write == 0);
+	BUG_ON(*nr_submitted != 0);
+	assert("zam-1042", txnh != NULL);
+      repeat:
+	if (txnh->atom == NULL) {
+		/* current atom is not available, take first from txnmgr */
+		spin_lock_txnmgr(tmgr);
+
+		/* traverse the list of all atoms */
+		list_for_each_entry(atom, &tmgr->atoms_list, atom_link) {
+			/* lock atom before checking its state */
+			spin_lock_atom(atom);
+
+			/*
+			 * we need an atom which is not being committed and
+			 * which has no flushers (jnode_flush() add one flusher
+			 * at the beginning and subtract one at the end).
+			 */
+			if (atom->stage < ASTAGE_PRE_COMMIT &&
+			    atom->nr_flushers == 0) {
+				spin_lock_txnh(txnh);
+				capture_assign_txnh_nolock(atom, txnh);
+				spin_unlock_txnh(txnh);
+
+				goto found;
+			}
+
+			spin_unlock_atom(atom);
+		}
+
+		/*
+		 * Write throttling is case of no one atom can be
+		 * flushed/committed.
+		 */
+		if (!current_is_pdflush() && !wbc->nonblocking) {
+			list_for_each_entry(atom, &tmgr->atoms_list, atom_link) {
+				spin_lock_atom(atom);
+				/* Repeat the check from the above. */
+				if (atom->stage < ASTAGE_PRE_COMMIT
+				    && atom->nr_flushers == 0) {
+					spin_lock_txnh(txnh);
+					capture_assign_txnh_nolock(atom, txnh);
+					spin_unlock_txnh(txnh);
+
+					goto found;
+				}
+				if (atom->stage <= ASTAGE_POST_COMMIT) {
+					spin_unlock_txnmgr(tmgr);
+					/*
+					 * we just wait until atom's flusher
+					 * makes a progress in flushing or
+					 * committing the atom
+					 */
+					atom_wait_event(atom);
+					goto repeat;
+				}
+				spin_unlock_atom(atom);
+			}
+		}
+		spin_unlock_txnmgr(tmgr);
+		return 0;
+	      found:
+		spin_unlock_txnmgr(tmgr);
+	} else
+		atom = get_current_atom_locked();
+
+	BUG_ON(atom->super != ctx->super);
+	assert("vs-35", atom->super == ctx->super);
+	if (start) {
+		spin_lock_jnode(start);
+		ret = (atom == start->atom) ? 1 : 0;
+		spin_unlock_jnode(start);
+		if (ret == 0)
+			start = NULL;
+	}
+	ret = flush_current_atom(flags, wbc->nr_to_write, nr_submitted, &atom, start);
+	if (ret == 0) {
+		/* flush_current_atom returns 0 only if it submitted for write
+		   nothing */
+		BUG_ON(*nr_submitted != 0);
+		if (*nr_submitted == 0 || atom_should_commit_asap(atom)) {
+			if (atom->capture_count < tmgr->atom_min_size &&
+			    !(atom->flags & ATOM_CANCEL_FUSION)) {
+				ret = txn_try_to_fuse_small_atom(tmgr, atom);
+				if (ret == -E_REPEAT) {
+					preempt_point();
+					goto repeat;
+				}
+			}
+			/* if early flushing could not make more nodes clean,
+			 * or atom is too old/large,
+			 * we force current atom to commit */
+			/* wait for commit completion but only if this
+			 * wouldn't stall pdflushd and ent thread. */
+			if (!wbc->nonblocking && !ctx->entd)
+				txnh->flags |= TXNH_WAIT_COMMIT;
+			atom->flags |= ATOM_FORCE_COMMIT;
+		}
+		spin_unlock_atom(atom);
+	} else if (ret == -E_REPEAT) {
+		if (*nr_submitted == 0) {
+			/* let others who hampers flushing (hold longterm locks,
+			   for instance) to free the way for flush */
+			preempt_point();
+			goto repeat;
+		}
+		ret = 0;
+	}
+/*
+	if (*nr_submitted > wbc->nr_to_write)
+		warning("", "asked for %ld, written %ld\n", wbc->nr_to_write, *nr_submitted);
+*/
+	txn_restart(ctx);
+
+	return ret;
+}
+
+#if REISER4_COPY_ON_CAPTURE
+
+/* Remove processed nodes from atom's clean list (thereby remove them from transaction). */
+void invalidate_list(capture_list_head * head)
+{
+	txn_atom *atom;
+
+	spin_lock(&scan_lock);
+	while (!capture_list_empty(head)) {
+		jnode *node;
+
+		node = capture_list_front(head);
+		JF_SET(node, JNODE_SCANNED);
+		spin_unlock(&scan_lock);
+
+		atom = node->atom;
+		spin_lock_atom(atom);
+		LOCK_JNODE(node);
+		if (JF_ISSET(node, JNODE_CC) && node->pg)
+			page_cache_release(node->pg);
+		uncapture_block(node);
+		spin_unlock_atom(atom);
+		JF_CLR(node, JNODE_SCANNED);
+		jput(node);
+
+		spin_lock(&scan_lock);
+	}
+	spin_unlock(&scan_lock);
+}
+
+#else
+
+/* Remove processed nodes from atom's clean list (thereby remove them from transaction). */
+void invalidate_list(struct list_head *head)
+{
+	while (!list_empty(head)) {
+		jnode *node;
+
+		node = list_entry(head->next, jnode, capture_link);
+		spin_lock_jnode(node);
+		uncapture_block(node);
+		jput(node);
+	}
+}
+
+#endif
+
+static void init_wlinks(txn_wait_links * wlinks)
+{
+	wlinks->_lock_stack = get_current_lock_stack();
+	INIT_LIST_HEAD(&wlinks->_fwaitfor_link);
+	INIT_LIST_HEAD(&wlinks->_fwaiting_link);
+	wlinks->waitfor_cb = NULL;
+	wlinks->waiting_cb = NULL;
+}
+
+/* Add atom to the atom's waitfor list and wait for somebody to wake us up; */
+void atom_wait_event(txn_atom * atom)
+{
+	txn_wait_links _wlinks;
+
+	assert_spin_locked(&(atom->alock));
+	assert("nikita-3156",
+	       lock_stack_isclean(get_current_lock_stack()) ||
+	       atom->nr_running_queues > 0);
+
+	init_wlinks(&_wlinks);
+	list_add_tail(&_wlinks._fwaitfor_link, &atom->fwaitfor_list);
+	atomic_inc(&atom->refcount);
+	spin_unlock_atom(atom);
+
+	prepare_to_sleep(_wlinks._lock_stack);
+	go_to_sleep(_wlinks._lock_stack);
+
+	spin_lock_atom(atom);
+	list_del(&_wlinks._fwaitfor_link);
+	atom_dec_and_unlock(atom);
+}
+
+void atom_set_stage(txn_atom * atom, txn_stage stage)
+{
+	assert("nikita-3535", atom != NULL);
+	assert_spin_locked(&(atom->alock));
+	assert("nikita-3536", ASTAGE_FREE <= stage && stage <= ASTAGE_INVALID);
+	/* Excelsior! */
+	assert("nikita-3537", stage >= atom->stage);
+	if (atom->stage != stage) {
+		atom->stage = stage;
+		atom_send_event(atom);
+	}
+}
+
+/* wake all threads which wait for an event */
+void atom_send_event(txn_atom * atom)
+{
+	assert_spin_locked(&(atom->alock));
+	wakeup_atom_waitfor_list(atom);
+}
+
+/* Informs txn manager code that owner of this txn_handle should wait atom commit completion (for
+   example, because it does fsync(2)) */
+static int should_wait_commit(txn_handle * h)
+{
+	return h->flags & TXNH_WAIT_COMMIT;
+}
+
+typedef struct commit_data {
+	txn_atom *atom;
+	txn_handle *txnh;
+	long nr_written;
+	/* as an optimization we start committing atom by first trying to
+	 * flush it few times without switching into ASTAGE_CAPTURE_WAIT. This
+	 * allows to reduce stalls due to other threads waiting for atom in
+	 * ASTAGE_CAPTURE_WAIT stage. ->preflush is counter of these
+	 * preliminary flushes. */
+	int preflush;
+	/* have we waited on atom. */
+	int wait;
+	int failed;
+	int wake_ktxnmgrd_up;
+} commit_data;
+
+/*
+ * Called from commit_txnh() repeatedly, until either error happens, or atom
+ * commits successfully.
+ */
+static int try_commit_txnh(commit_data * cd)
+{
+	int result;
+
+	assert("nikita-2968", lock_stack_isclean(get_current_lock_stack()));
+
+	/* Get the atom and txnh locked. */
+	cd->atom = txnh_get_atom(cd->txnh);
+	assert("jmacd-309", cd->atom != NULL);
+	spin_unlock_txnh(cd->txnh);
+
+	if (cd->wait) {
+		cd->atom->nr_waiters--;
+		cd->wait = 0;
+	}
+
+	if (cd->atom->stage == ASTAGE_DONE)
+		return 0;
+
+	if (cd->failed)
+		return 0;
+
+	if (atom_should_commit(cd->atom)) {
+		/* if atom is _very_ large schedule it for commit as soon as
+		 * possible. */
+		if (atom_should_commit_asap(cd->atom)) {
+			/*
+			 * When atom is in PRE_COMMIT or later stage following
+			 * invariant (encoded   in    atom_can_be_committed())
+			 * holds:  there is exactly one non-waiter transaction
+			 * handle opened  on this atom.  When  thread wants to
+			 * wait  until atom  commits (for  example  sync()) it
+			 * waits    on    atom  event     after     increasing
+			 * atom->nr_waiters (see blow  in  this  function). It
+			 * cannot be guaranteed that atom is already committed
+			 * after    receiving event,  so     loop has   to  be
+			 * re-started. But  if  atom switched into  PRE_COMMIT
+			 * stage and became  too  large, we cannot  change its
+			 * state back   to CAPTURE_WAIT (atom  stage can  only
+			 * increase monotonically), hence this check.
+			 */
+			if (cd->atom->stage < ASTAGE_CAPTURE_WAIT)
+				atom_set_stage(cd->atom, ASTAGE_CAPTURE_WAIT);
+			cd->atom->flags |= ATOM_FORCE_COMMIT;
+		}
+		if (cd->txnh->flags & TXNH_DONT_COMMIT) {
+			/*
+			 * this  thread (transaction  handle  that is) doesn't
+			 * want to commit  atom. Notify waiters that handle is
+			 * closed. This can happen, for  example, when we  are
+			 * under  VFS directory lock  and don't want to commit
+			 * atom  right   now to  avoid  stalling other threads
+			 * working in the same directory.
+			 */
+
+			/* Wake  the ktxnmgrd up if  the ktxnmgrd is needed to
+			 * commit this  atom: no  atom  waiters  and only  one
+			 * (our) open transaction handle. */
+			cd->wake_ktxnmgrd_up =
+			    cd->atom->txnh_count == 1 &&
+			    cd->atom->nr_waiters == 0;
+			atom_send_event(cd->atom);
+			result = 0;
+		} else if (!atom_can_be_committed(cd->atom)) {
+			if (should_wait_commit(cd->txnh)) {
+				/* sync(): wait for commit */
+				cd->atom->nr_waiters++;
+				cd->wait = 1;
+				atom_wait_event(cd->atom);
+				result = RETERR(-E_REPEAT);
+			} else {
+				result = 0;
+			}
+		} else if (cd->preflush > 0 && !is_current_ktxnmgrd()) {
+			/*
+			 * optimization: flush  atom without switching it into
+			 * ASTAGE_CAPTURE_WAIT.
+			 *
+			 * But don't  do this for  ktxnmgrd, because  ktxnmgrd
+			 * should never block on atom fusion.
+			 */
+			result = flush_current_atom(JNODE_FLUSH_WRITE_BLOCKS,
+						    LONG_MAX, &cd->nr_written,
+						    &cd->atom, NULL);
+			if (result == 0) {
+				spin_unlock_atom(cd->atom);
+				cd->preflush = 0;
+				result = RETERR(-E_REPEAT);
+			} else	/* Atoms wasn't flushed
+				 * completely. Rinse. Repeat. */
+				--cd->preflush;
+		} else {
+			/* We change   atom state  to   ASTAGE_CAPTURE_WAIT to
+			   prevent atom fusion and count  ourself as an active
+			   flusher */
+			atom_set_stage(cd->atom, ASTAGE_CAPTURE_WAIT);
+			cd->atom->flags |= ATOM_FORCE_COMMIT;
+
+			result =
+			    commit_current_atom(&cd->nr_written, &cd->atom);
+			if (result != 0 && result != -E_REPEAT)
+				cd->failed = 1;
+		}
+	} else
+		result = 0;
+
+#if REISER4_DEBUG
+	if (result == 0)
+		assert_spin_locked(&(cd->atom->alock));
+#endif
+
+	/* perfectly valid assertion, except that when atom/txnh is not locked
+	 * fusion can take place, and cd->atom points nowhere. */
+	/*
+	   assert("jmacd-1028", ergo(result != 0, spin_atom_is_not_locked(cd->atom)));
+	 */
+	return result;
+}
+
+/* Called to commit a transaction handle.  This decrements the atom's number of open
+   handles and if it is the last handle to commit and the atom should commit, initiates
+   atom commit. if commit does not fail, return number of written blocks */
+static int commit_txnh(txn_handle * txnh)
+{
+	commit_data cd;
+	assert("umka-192", txnh != NULL);
+
+	memset(&cd, 0, sizeof cd);
+	cd.txnh = txnh;
+	cd.preflush = 10;
+
+	/* calls try_commit_txnh() until either atom commits, or error
+	 * happens */
+	while (try_commit_txnh(&cd) != 0)
+		preempt_point();
+
+	spin_lock_txnh(txnh);
+
+	cd.atom->txnh_count -= 1;
+	txnh->atom = NULL;
+	/* remove transaction handle from atom's list of transaction handles */
+	list_del_init(&txnh->txnh_link);
+
+	spin_unlock_txnh(txnh);
+	atom_dec_and_unlock(cd.atom);
+	/* if we don't want to do a commit (TXNH_DONT_COMMIT is set, probably
+	 * because it takes time) by current thread, we do that work
+	 * asynchronously by ktxnmgrd daemon. */
+	if (cd.wake_ktxnmgrd_up)
+		ktxnmgrd_kick(&get_current_super_private()->tmgr);
+
+	return 0;
+}
+
+/* TRY_CAPTURE */
+
+/* This routine attempts a single block-capture request.  It may return -E_REPEAT if some
+   condition indicates that the request should be retried, and it may block if the
+   txn_capture mode does not include the TXN_CAPTURE_NONBLOCKING request flag.
+
+   This routine encodes the basic logic of block capturing described by:
+
+     http://namesys.com/v4/v4.html
+
+   Our goal here is to ensure that any two blocks that contain dependent modifications
+   should commit at the same time.  This function enforces this discipline by initiating
+   fusion whenever a transaction handle belonging to one atom requests to read or write a
+   block belonging to another atom (TXN_CAPTURE_WRITE or TXN_CAPTURE_READ_ATOMIC).
+
+   In addition, this routine handles the initial assignment of atoms to blocks and
+   transaction handles.  These are possible outcomes of this function:
+
+   1. The block and handle are already part of the same atom: return immediate success
+
+   2. The block is assigned but the handle is not: call capture_assign_txnh to assign
+      the handle to the block's atom.
+
+   3. The handle is assigned but the block is not: call capture_assign_block to assign
+      the block to the handle's atom.
+
+   4. Both handle and block are assigned, but to different atoms: call capture_init_fusion
+      to fuse atoms.
+
+   5. Neither block nor handle are assigned: create a new atom and assign them both.
+
+   6. A read request for a non-captured block: return immediate success.
+
+   This function acquires and releases the handle's spinlock.  This function is called
+   under the jnode lock and if the return value is 0, it returns with the jnode lock still
+   held.  If the return is -E_REPEAT or some other error condition, the jnode lock is
+   released.  The external interface (try_capture) manages re-aquiring the jnode lock
+   in the failure case.
+*/
+static int try_capture_block(
+	txn_handle * txnh, jnode * node, txn_capture mode,
+	txn_atom ** atom_alloc)
+{
+	txn_atom *block_atom;
+	txn_atom *txnh_atom;
+
+	/* Should not call capture for READ_NONCOM requests, handled in try_capture. */
+	assert("jmacd-567", CAPTURE_TYPE(mode) != TXN_CAPTURE_READ_NONCOM);
+
+	/* FIXME-ZAM-HANS: FIXME_LATER_JMACD Should assert that atom->tree ==
+	 * node->tree somewhere. */
+	assert("umka-194", txnh != NULL);
+	assert("umka-195", node != NULL);
+
+	/* The jnode is already locked!  Being called from try_capture(). */
+	assert_spin_locked(&(node->guard));
+	block_atom = node->atom;
+
+	/* Get txnh spinlock, this allows us to compare txn_atom pointers but it doesn't
+	   let us touch the atoms themselves. */
+	spin_lock_txnh(txnh);
+	txnh_atom = txnh->atom;
+	/* Process of capturing continues into one of four branches depends on
+	   which atoms from (block atom (node->atom), current atom (txnh->atom))
+	   exist. */
+	if (txnh_atom == NULL) {
+		if (block_atom == NULL) {
+			spin_unlock_txnh(txnh);
+			spin_unlock_jnode(node);
+			/* assign empty atom to the txnh and repeat */
+			return atom_begin_and_assign_to_txnh(atom_alloc, txnh);
+		} else {
+			atomic_inc(&block_atom->refcount);
+			/* node spin-lock isn't needed anymore */
+			spin_unlock_jnode(node);
+			if (!spin_trylock_atom(block_atom)) {
+				spin_unlock_txnh(txnh);
+				spin_lock_atom(block_atom);
+				spin_lock_txnh(txnh);
+			}
+			/* re-check state after getting txnh and the node
+			 * atom spin-locked */
+			if (node->atom != block_atom || txnh->atom != NULL) {
+				spin_unlock_txnh(txnh);
+				atom_dec_and_unlock(block_atom);
+				return RETERR(-E_REPEAT);
+			}
+			atomic_dec(&block_atom->refcount);
+			if (block_atom->stage > ASTAGE_CAPTURE_WAIT ||
+			    (block_atom->stage == ASTAGE_CAPTURE_WAIT &&
+			     block_atom->txnh_count != 0))
+				return capture_fuse_wait(txnh, block_atom, NULL, mode);
+			capture_assign_txnh_nolock(block_atom, txnh);
+			spin_unlock_txnh(txnh);
+			spin_unlock_atom(block_atom);
+			return RETERR(-E_REPEAT);
+		}
+	} else {
+		/* It is time to perform deadlock prevention check over the
+                  node we want to capture.  It is possible this node was locked
+                  for read without capturing it. The optimization which allows
+                  to do it helps us in keeping atoms independent as long as
+                  possible but it may cause lock/fuse deadlock problems.
+
+                  A number of similar deadlock situations with locked but not
+                  captured nodes were found.  In each situation there are two
+                  or more threads: one of them does flushing while another one
+                  does routine balancing or tree lookup.  The flushing thread
+                  (F) sleeps in long term locking request for node (N), another
+                  thread (A) sleeps in trying to capture some node already
+                  belonging the atom F, F has a state which prevents
+                  immediately fusion .
+
+                  Deadlocks of this kind cannot happen if node N was properly
+                  captured by thread A. The F thread fuse atoms before locking
+                  therefore current atom of thread F and current atom of thread
+                  A became the same atom and thread A may proceed.  This does
+                  not work if node N was not captured because the fusion of
+                  atom does not happens.
+
+                  The following scheme solves the deadlock: If
+                  longterm_lock_znode locks and does not capture a znode, that
+                  znode is marked as MISSED_IN_CAPTURE.  A node marked this way
+                  is processed by the code below which restores the missed
+                  capture and fuses current atoms of all the node lock owners
+                  by calling the fuse_not_fused_lock_owners() function. */
+		if (JF_ISSET(node, JNODE_MISSED_IN_CAPTURE)) {
+			JF_CLR(node, JNODE_MISSED_IN_CAPTURE);
+			if (jnode_is_znode(node) && znode_is_locked(JZNODE(node))) {
+				spin_unlock_txnh(txnh);
+				spin_unlock_jnode(node);
+				fuse_not_fused_lock_owners(txnh, JZNODE(node));
+				return RETERR(-E_REPEAT);
+			}
+		}
+		if (block_atom == NULL) {
+			atomic_inc(&txnh_atom->refcount);
+			spin_unlock_txnh(txnh);
+			if (!spin_trylock_atom(txnh_atom)) {
+				spin_unlock_jnode(node);
+				spin_lock_atom(txnh_atom);
+				spin_lock_jnode(node);
+			}
+			if (txnh->atom != txnh_atom || node->atom != NULL
+				|| JF_ISSET(node, JNODE_IS_DYING)) {
+				spin_unlock_jnode(node);
+				atom_dec_and_unlock(txnh_atom);
+				return RETERR(-E_REPEAT);
+			}
+			atomic_dec(&txnh_atom->refcount);
+			capture_assign_block_nolock(txnh_atom, node);
+			spin_unlock_atom(txnh_atom);
+		} else {
+			if (txnh_atom != block_atom) {
+				if (mode & TXN_CAPTURE_DONT_FUSE) {
+					spin_unlock_txnh(txnh);
+					spin_unlock_jnode(node);
+					/* we are in a "no-fusion" mode and @node is
+					 * already part of transaction. */
+					return RETERR(-E_NO_NEIGHBOR);
+				}
+				return capture_init_fusion(node, txnh, mode, 1);
+			}
+			spin_unlock_txnh(txnh);
+		}
+	}
+	return 0;
+}
+
+static txn_capture
+build_capture_mode(jnode * node, znode_lock_mode lock_mode, txn_capture flags)
+{
+	txn_capture cap_mode;
+
+	assert_spin_locked(&(node->guard));
+
+	/* FIXME_JMACD No way to set TXN_CAPTURE_READ_MODIFY yet. */
+
+	if (lock_mode == ZNODE_WRITE_LOCK) {
+		cap_mode = TXN_CAPTURE_WRITE;
+	} else if (node->atom != NULL) {
+		cap_mode = TXN_CAPTURE_WRITE;
+	} else if (0 &&		/* txnh->mode == TXN_READ_FUSING && */
+		   jnode_get_level(node) == LEAF_LEVEL) {
+		/* NOTE-NIKITA TXN_READ_FUSING is not currently used */
+		/* We only need a READ_FUSING capture at the leaf level.  This
+		   is because the internal levels of the tree (twigs included)
+		   are redundant from the point of the user that asked for a
+		   read-fusing transcrash.  The user only wants to read-fuse
+		   atoms due to reading uncommitted data that another user has
+		   written.  It is the file system that reads/writes the
+		   internal tree levels, the user only reads/writes leaves. */
+		cap_mode = TXN_CAPTURE_READ_ATOMIC;
+	} else {
+		/* In this case (read lock at a non-leaf) there's no reason to
+		 * capture. */
+		/* cap_mode = TXN_CAPTURE_READ_NONCOM; */
+		return 0;
+	}
+
+	cap_mode |= (flags & (TXN_CAPTURE_NONBLOCKING | TXN_CAPTURE_DONT_FUSE));
+	assert("nikita-3186", cap_mode != 0);
+	return cap_mode;
+}
+
+/* This is an external interface to try_capture_block(), it calls
+   try_capture_block() repeatedly as long as -E_REPEAT is returned.
+
+   @node:         node to capture,
+   @lock_mode:    read or write lock is used in capture mode calculation,
+   @flags:        see txn_capture flags enumeration,
+   @can_coc     : can copy-on-capture
+
+   @return: 0 - node was successfully captured, -E_REPEAT - capture request
+            cannot be processed immediately as it was requested in flags,
+	    < 0 - other errors.
+*/
+int try_capture(jnode * node, znode_lock_mode lock_mode,
+		txn_capture flags, int can_coc)
+{
+	txn_atom *atom_alloc = NULL;
+	txn_capture cap_mode;
+	txn_handle *txnh = get_current_context()->trans;
+	int ret;
+
+	assert_spin_locked(&(node->guard));
+
+      repeat:
+	if (JF_ISSET(node, JNODE_IS_DYING))
+		return RETERR(-EINVAL);
+	if (node->atom != NULL && txnh->atom == node->atom)
+		return 0;
+	cap_mode = build_capture_mode(node, lock_mode, flags);
+	if (cap_mode == 0 ||
+	    (!(cap_mode & TXN_CAPTURE_WTYPES) && node->atom == NULL)) {
+		/* Mark this node as "MISSED".  It helps in further deadlock
+		 * analysis */
+		if (jnode_is_znode(node))
+			JF_SET(node, JNODE_MISSED_IN_CAPTURE);
+		return 0;
+	}
+	/* Repeat try_capture as long as -E_REPEAT is returned. */
+	ret = try_capture_block(txnh, node, cap_mode, &atom_alloc);
+	/* Regardless of non_blocking:
+
+	   If ret == 0 then jnode is still locked.
+	   If ret != 0 then jnode is unlocked.
+	 */
+#if REISER4_DEBUG
+	if (ret == 0)
+		assert_spin_locked(&(node->guard));
+	else
+		assert_spin_not_locked(&(node->guard));
+#endif
+	assert_spin_not_locked(&(txnh->guard));
+
+	if (ret == -E_REPEAT) {
+		/* E_REPEAT implies all locks were released, therefore we need
+		   to take the jnode's lock again. */
+		spin_lock_jnode(node);
+
+		/* Although this may appear to be a busy loop, it is not.
+		   There are several conditions that cause E_REPEAT to be
+		   returned by the call to try_capture_block, all cases
+		   indicating some kind of state change that means you should
+		   retry the request and will get a different result.  In some
+		   cases this could be avoided with some extra code, but
+		   generally it is done because the necessary locks were
+		   released as a result of the operation and repeating is the
+		   simplest thing to do (less bug potential).  The cases are:
+		   atom fusion returns E_REPEAT after it completes (jnode and
+		   txnh were unlocked); race conditions in assign_block,
+		   assign_txnh, and init_fusion return E_REPEAT (trylock
+		   failure); after going to sleep in capture_fuse_wait
+		   (request was blocked but may now succeed).  I'm not quite
+		   sure how capture_copy works yet, but it may also return
+		   E_REPEAT.  When the request is legitimately blocked, the
+		   requestor goes to sleep in fuse_wait, so this is not a busy
+		   loop. */
+		/* NOTE-NIKITA: still don't understand:
+
+		   try_capture_block->capture_assign_txnh->spin_trylock_atom->E_REPEAT
+
+		   looks like busy loop?
+		 */
+		goto repeat;
+	}
+#if REISER4_COPY_ON_CAPTURE
+	if (ret == -E_WAIT) {
+		reiser4_stat_inc(coc.coc_wait);
+		/* disable COC for the next loop iteration */
+		coc_enabled = 0;
+		spin_lock_jnode(node);
+		goto repeat;
+	}
+#endif
+
+	/* free extra atom object that was possibly allocated by
+	   try_capture_block().
+
+	   Do this before acquiring jnode spin lock to
+	   minimize time spent under lock. --nikita */
+	if (atom_alloc != NULL) {
+		kmem_cache_free(_atom_slab, atom_alloc);
+	}
+
+	if (ret != 0) {
+		if (ret == -E_BLOCK) {
+			assert("nikita-3360",
+			       cap_mode & TXN_CAPTURE_NONBLOCKING);
+			ret = -E_REPEAT;
+		}
+
+		/* Failure means jnode is not locked.  FIXME_LATER_JMACD May
+		   want to fix the above code to avoid releasing the lock and
+		   re-acquiring it, but there are cases were failure occurs
+		   when the lock is not held, and those cases would need to be
+		   modified to re-take the lock. */
+		spin_lock_jnode(node);
+	}
+
+	/* Jnode is still locked. */
+	assert_spin_locked(&(node->guard));
+	return ret;
+}
+
+static void release_two_atoms(txn_atom *one, txn_atom *two)
+{
+	spin_unlock_atom(one);
+	atom_dec_and_unlock(two);
+	spin_lock_atom(one);
+	atom_dec_and_unlock(one);
+}
+
+/* This function sets up a call to try_capture_block and repeats as long as -E_REPEAT is
+   returned by that routine.  The txn_capture request mode is computed here depending on
+   the transaction handle's type and the lock request.  This is called from the depths of
+   the lock manager with the jnode lock held and it always returns with the jnode lock
+   held.
+*/
+
+/* fuse all 'active' atoms of lock owners of given node. */
+static void fuse_not_fused_lock_owners(txn_handle * txnh, znode * node)
+{
+	lock_handle *lh;
+	int repeat;
+	txn_atom *atomh, *atomf;
+	reiser4_context *me = get_current_context();
+	reiser4_context *ctx = NULL;
+
+	assert_spin_not_locked(&(ZJNODE(node)->guard));
+	assert_spin_not_locked(&(txnh->hlock));
+
+ repeat:
+	repeat = 0;
+	atomh = txnh_get_atom(txnh);
+	spin_unlock_txnh(txnh);
+	assert("zam-692", atomh != NULL);
+
+	spin_lock_zlock(&node->lock);
+	/* inspect list of lock owners */
+	list_for_each_entry(lh, &node->lock.owners, owners_link) {
+		ctx = get_context_by_lock_stack(lh->owner);
+		if (ctx == me)
+			continue;
+		/* below we use two assumptions to avoid addition spin-locks
+		   for checking the condition :
+
+		   1) if the lock stack has lock, the transaction should be
+		   opened, i.e. ctx->trans != NULL;
+
+		   2) reading of well-aligned ctx->trans->atom is atomic, if it
+		   equals to the address of spin-locked atomh, we take that
+		   the atoms are the same, nothing has to be captured. */
+		if (atomh != ctx->trans->atom) {
+			reiser4_wake_up(lh->owner);
+			repeat = 1;
+			break;
+		}
+	}
+	if (repeat) {
+		if (!spin_trylock_txnh(ctx->trans)) {
+			spin_unlock_zlock(&node->lock);
+			spin_unlock_atom(atomh);
+			goto repeat;
+		}
+		atomf = ctx->trans->atom;
+		if (atomf == NULL) {
+			capture_assign_txnh_nolock(atomh, ctx->trans);
+			/* release zlock lock _after_ assigning the atom to the
+			 * transaction handle, otherwise the lock owner thread
+			 * may unlock all znodes, exit kernel context and here
+			 * we would access an invalid transaction handle. */
+			spin_unlock_zlock(&node->lock);
+			spin_unlock_atom(atomh);
+			spin_unlock_txnh(ctx->trans);
+			goto repeat;
+		}
+		assert("zam-1059", atomf != atomh);
+		spin_unlock_zlock(&node->lock);
+		atomic_inc(&atomh->refcount);
+		atomic_inc(&atomf->refcount);
+		spin_unlock_txnh(ctx->trans);
+		if (atomf > atomh) {
+			spin_lock_atom(atomf);
+		} else {
+			spin_unlock_atom(atomh);
+			spin_lock_atom(atomf);
+			spin_lock_atom(atomh);
+		}
+		if (atomh == atomf || !atom_isopen(atomh) || !atom_isopen(atomf)) {
+			release_two_atoms(atomf, atomh);
+			goto repeat;
+		}
+		atomic_dec(&atomh->refcount);
+		atomic_dec(&atomf->refcount);
+		capture_fuse_into(atomf, atomh);
+		goto repeat;
+	}
+	spin_unlock_zlock(&node->lock);
+	spin_unlock_atom(atomh);
+}
+
+/* This is the interface to capture unformatted nodes via their struct page
+   reference. Currently it is only used in reiser4_invalidatepage */
+int try_capture_page_to_invalidate(struct page *pg)
+{
+	int ret;
+	jnode *node;
+
+	assert("umka-292", pg != NULL);
+	assert("nikita-2597", PageLocked(pg));
+
+	if (IS_ERR(node = jnode_of_page(pg))) {
+		return PTR_ERR(node);
+	}
+
+	spin_lock_jnode(node);
+	unlock_page(pg);
+
+	ret =
+	    try_capture(node, ZNODE_WRITE_LOCK, 0, 0 /* no copy on capture */ );
+	spin_unlock_jnode(node);
+	jput(node);
+	lock_page(pg);
+	return ret;
+}
+
+/* This informs the transaction manager when a node is deleted.  Add the block to the
+   atom's delete set and uncapture the block.
+
+VS-FIXME-HANS: this E_REPEAT paradigm clutters the code and creates a need for
+explanations.  find all the functions that use it, and unless there is some very
+good reason to use it (I have not noticed one so far and I doubt it exists, but maybe somewhere somehow....),
+move the loop to inside the function.
+
+VS-FIXME-HANS: can this code be at all streamlined?  In particular, can you lock and unlock the jnode fewer times?
+  */
+void uncapture_page(struct page *pg)
+{
+	jnode *node;
+	txn_atom *atom;
+
+	assert("umka-199", pg != NULL);
+	assert("nikita-3155", PageLocked(pg));
+
+	clear_page_dirty_for_io(pg);
+
+	reiser4_wait_page_writeback(pg);
+
+	node = jprivate(pg);
+	BUG_ON(node == NULL);
+
+	spin_lock_jnode(node);
+
+	eflush_del(node, 1 /* page is locked */ );
+	/*assert ("zam-815", !JF_ISSET(node, JNODE_EFLUSH)); */
+
+	atom = jnode_get_atom(node);
+	if (atom == NULL) {
+		assert("jmacd-7111", !JF_ISSET(node, JNODE_DIRTY));
+		spin_unlock_jnode(node);
+		return;
+	}
+
+	/* We can remove jnode from transaction even if it is on flush queue
+	 * prepped list, we only need to be sure that flush queue is not being
+	 * written by write_fq().  write_fq() does not use atom spin lock for
+	 * protection of the prepped nodes list, instead write_fq() increments
+	 * atom's nr_running_queues counters for the time when prepped list is
+	 * not protected by spin lock.  Here we check this counter if we want
+	 * to remove jnode from flush queue and, if the counter is not zero,
+	 * wait all write_fq() for this atom to complete. This is not
+	 * significant overhead. */
+	while (JF_ISSET(node, JNODE_FLUSH_QUEUED) && atom->nr_running_queues) {
+		spin_unlock_jnode(node);
+		/*
+		 * at this moment we want to wait for "atom event", viz. wait
+		 * until @node can be removed from flush queue. But
+		 * atom_wait_event() cannot be called with page locked, because
+		 * it deadlocks with jnode_extent_write(). Unlock page, after
+		 * making sure (through page_cache_get()) that it cannot be
+		 * released from memory.
+		 */
+		page_cache_get(pg);
+		unlock_page(pg);
+		atom_wait_event(atom);
+		lock_page(pg);
+		/*
+		 * page may has been detached by ->writepage()->releasepage().
+		 */
+		reiser4_wait_page_writeback(pg);
+		spin_lock_jnode(node);
+		eflush_del(node, 1);
+		page_cache_release(pg);
+		atom = jnode_get_atom(node);
+/* VS-FIXME-HANS: improve the commenting in this function */
+		if (atom == NULL) {
+			spin_unlock_jnode(node);
+			return;
+		}
+	}
+	uncapture_block(node);
+	spin_unlock_atom(atom);
+	jput(node);
+}
+
+/* this is used in extent's kill hook to uncapture and unhash jnodes attached to
+ * inode's tree of jnodes */
+void uncapture_jnode(jnode * node)
+{
+	txn_atom *atom;
+
+	assert_spin_locked(&(node->guard));
+	assert("", node->pg == 0);
+
+	if (JF_ISSET(node, JNODE_EFLUSH)) {
+		eflush_free(node);
+		JF_CLR(node, JNODE_EFLUSH);
+	}
+	/*eflush_del(node, 0); */
+
+	/*jnode_make_clean(node); */
+	atom = jnode_get_atom(node);
+	if (atom == NULL) {
+		assert("jmacd-7111", !JF_ISSET(node, JNODE_DIRTY));
+		spin_unlock_jnode(node);
+		return;
+	}
+
+	uncapture_block(node);
+	spin_unlock_atom(atom);
+	jput(node);
+}
+
+/* No-locking version of assign_txnh.  Sets the transaction handle's atom pointer,
+   increases atom refcount and txnh_count, adds to txnh_list. */
+static void capture_assign_txnh_nolock(txn_atom *atom, txn_handle *txnh)
+{
+	assert("umka-200", atom != NULL);
+	assert("umka-201", txnh != NULL);
+
+	assert_spin_locked(&(txnh->hlock));
+	assert_spin_locked(&(atom->alock));
+	assert("jmacd-824", txnh->atom == NULL);
+	assert("nikita-3540", atom_isopen(atom));
+	BUG_ON(txnh->atom != NULL);
+
+	atomic_inc(&atom->refcount);
+	txnh->atom = atom;
+	list_add_tail(&txnh->txnh_link, &atom->txnh_list);
+	atom->txnh_count += 1;
+}
+
+/* No-locking version of assign_block.  Sets the block's atom pointer, references the
+   block, adds it to the clean or dirty capture_jnode list, increments capture_count. */
+static void capture_assign_block_nolock(txn_atom *atom, jnode *node)
+{
+	assert("umka-202", atom != NULL);
+	assert("umka-203", node != NULL);
+	assert_spin_locked(&(node->guard));
+	assert_spin_locked(&(atom->alock));
+	assert("jmacd-323", node->atom == NULL);
+	BUG_ON(!list_empty_careful(&node->capture_link));
+	assert("nikita-3470", !JF_ISSET(node, JNODE_DIRTY));
+
+	/* Pointer from jnode to atom is not counted in atom->refcount. */
+	node->atom = atom;
+
+	list_add_tail(&node->capture_link, ATOM_CLEAN_LIST(atom));
+	atom->capture_count += 1;
+	/* reference to jnode is acquired by atom. */
+	jref(node);
+
+	ON_DEBUG(count_jnode(atom, node, NOT_CAPTURED, CLEAN_LIST, 1));
+
+	LOCK_CNT_INC(t_refs);
+}
+
+#if REISER4_COPY_ON_CAPTURE
+static void set_cced_bit(jnode * node)
+{
+	BUG_ON(JF_ISSET(node, JNODE_CCED));
+	JF_SET(node, JNODE_CCED);
+}
+#endif
+
+static void clear_cced_bits(jnode * node)
+{
+	JF_CLR(node, JNODE_CCED);
+}
+
+int is_cced(const jnode * node)
+{
+	return JF_ISSET(node, JNODE_CCED);
+}
+
+/* common code for dirtying both unformatted jnodes and formatted znodes. */
+static void do_jnode_make_dirty(jnode * node, txn_atom * atom)
+{
+	assert_spin_locked(&(node->guard));
+	assert_spin_locked(&(atom->alock));
+	assert("jmacd-3981", !JF_ISSET(node, JNODE_DIRTY));
+
+	JF_SET(node, JNODE_DIRTY);
+
+	get_current_context()->nr_marked_dirty++;
+
+	/* We grab2flush_reserve one additional block only if node was
+	   not CREATED and jnode_flush did not sort it into neither
+	   relocate set nor overwrite one. If node is in overwrite or
+	   relocate set we assume that atom's flush reserved counter was
+	   already adjusted. */
+	if (!JF_ISSET(node, JNODE_CREATED) && !JF_ISSET(node, JNODE_RELOC)
+	    && !JF_ISSET(node, JNODE_OVRWR) && jnode_is_leaf(node)
+	    && !jnode_is_cluster_page(node)) {
+		assert("vs-1093", !blocknr_is_fake(&node->blocknr));
+		assert("vs-1506", *jnode_get_block(node) != 0);
+		grabbed2flush_reserved_nolock(atom, (__u64) 1);
+		JF_SET(node, JNODE_FLUSH_RESERVED);
+	}
+
+	if (!JF_ISSET(node, JNODE_FLUSH_QUEUED)) {
+		/* If the atom is not set yet, it will be added to the appropriate list in
+		   capture_assign_block_nolock. */
+		/* Sometimes a node is set dirty before being captured -- the case for new
+		   jnodes.  In that case the jnode will be added to the appropriate list
+		   in capture_assign_block_nolock. Another reason not to re-link jnode is
+		   that jnode is on a flush queue (see flush.c for details) */
+
+		int level = jnode_get_level(node);
+
+		assert("nikita-3152", !JF_ISSET(node, JNODE_OVRWR));
+		assert("zam-654", atom->stage < ASTAGE_PRE_COMMIT);
+		assert("nikita-2607", 0 <= level);
+		assert("nikita-2606", level <= REAL_MAX_ZTREE_HEIGHT);
+
+		/* move node to atom's dirty list */
+		list_del(&node->capture_link);
+		list_add_tail(&node->capture_link, ATOM_DIRTY_LIST(atom, level));
+		ON_DEBUG(count_jnode
+			 (atom, node, NODE_LIST(node), DIRTY_LIST, 1));
+		/*
+		 * JNODE_CCED bit protects clean copy (page created by
+		 * copy-on-capture) from being evicted from the memory. This
+		 * is necessary, because otherwise jload() would load obsolete
+		 * disk block (up-to-date original is still in memory). But
+		 * once jnode is dirtied, it cannot be released without
+		 * storing its content on the disk, so protection is no longer
+		 * necessary.
+		 */
+		clear_cced_bits(node);
+	}
+}
+
+/* Set the dirty status for this (spin locked) jnode. */
+void jnode_make_dirty_locked(jnode * node)
+{
+	assert("umka-204", node != NULL);
+	assert_spin_locked(&(node->guard));
+
+	if (REISER4_DEBUG && rofs_jnode(node)) {
+		warning("nikita-3365", "Dirtying jnode on rofs");
+		dump_stack();
+	}
+
+	/* Fast check for already dirty node */
+	if (!JF_ISSET(node, JNODE_DIRTY)) {
+		txn_atom *atom;
+
+		atom = jnode_get_atom(node);
+		assert("vs-1094", atom);
+		/* Check jnode dirty status again because node spin lock might
+		 * be released inside jnode_get_atom(). */
+		if (likely(!JF_ISSET(node, JNODE_DIRTY)))
+			do_jnode_make_dirty(node, atom);
+		spin_unlock_atom(atom);
+	}
+}
+
+/* Set the dirty status for this znode. */
+void znode_make_dirty(znode * z)
+{
+	jnode *node;
+	struct page *page;
+
+	assert("umka-204", z != NULL);
+	assert("nikita-3290", znode_above_root(z) || znode_is_loaded(z));
+	assert("nikita-3291", !ZF_ISSET(z, JNODE_EFLUSH));
+	assert("nikita-3560", znode_is_write_locked(z));
+
+	node = ZJNODE(z);
+	/* znode is longterm locked, we can check dirty bit without spinlock */
+	if (JF_ISSET(node, JNODE_DIRTY)) {
+		/* znode is dirty already. All we have to do is to change znode version */
+		z->version = znode_build_version(jnode_get_tree(node));
+		return;
+	}
+
+	spin_lock_jnode(node);
+	jnode_make_dirty_locked(node);
+	page = jnode_page(node);
+	if (page != NULL) {
+		/* this is useful assertion (allows one to check that no
+		 * modifications are lost due to update of in-flight page),
+		 * but it requires locking on page to check PG_writeback
+		 * bit. */
+		/* assert("nikita-3292",
+		   !PageWriteback(page) || ZF_ISSET(z, JNODE_WRITEBACK)); */
+		page_cache_get(page);
+
+		/* jnode lock is not needed for the rest of
+		 * znode_set_dirty(). */
+		spin_unlock_jnode(node);
+		/* reiser4 file write code calls set_page_dirty for
+		 * unformatted nodes, for formatted nodes we do it here. */
+		set_page_dirty_internal(page);
+		page_cache_release(page);
+		/* bump version counter in znode */
+		z->version = znode_build_version(jnode_get_tree(node));
+	} else {
+		assert("zam-596", znode_above_root(JZNODE(node)));
+		spin_unlock_jnode(node);
+	}
+
+	assert("nikita-1900", znode_is_write_locked(z));
+	assert("jmacd-9777", node->atom != NULL);
+}
+
+int sync_atom(txn_atom * atom)
+{
+	int result;
+	txn_handle *txnh;
+
+	txnh = get_current_context()->trans;
+
+	result = 0;
+	if (atom != NULL) {
+		if (atom->stage < ASTAGE_PRE_COMMIT) {
+			spin_lock_txnh(txnh);
+			capture_assign_txnh_nolock(atom, txnh);
+			result = force_commit_atom(txnh);
+		} else if (atom->stage < ASTAGE_POST_COMMIT) {
+			/* wait atom commit */
+			atom_wait_event(atom);
+			/* try once more */
+			result = RETERR(-E_REPEAT);
+		} else
+			spin_unlock_atom(atom);
+	}
+	return result;
+}
+
+#if REISER4_DEBUG
+
+/* move jnode form one list to another
+   call this after atom->capture_count is updated */
+void
+count_jnode(txn_atom * atom, jnode * node, atom_list old_list,
+	    atom_list new_list, int check_lists)
+{
+	struct list_head *pos;
+#if REISER4_COPY_ON_CAPTURE
+	assert_spin_locked(&(atom->alock));
+#else
+	assert("zam-1018", atom_is_protected(atom));
+#endif
+	assert_spin_locked(&(node->guard));
+	assert("", NODE_LIST(node) == old_list);
+
+	switch (NODE_LIST(node)) {
+	case NOT_CAPTURED:
+		break;
+	case DIRTY_LIST:
+		assert("", atom->dirty > 0);
+		atom->dirty--;
+		break;
+	case CLEAN_LIST:
+		assert("", atom->clean > 0);
+		atom->clean--;
+		break;
+	case FQ_LIST:
+		assert("", atom->fq > 0);
+		atom->fq--;
+		break;
+	case WB_LIST:
+		assert("", atom->wb > 0);
+		atom->wb--;
+		break;
+	case OVRWR_LIST:
+		assert("", atom->ovrwr > 0);
+		atom->ovrwr--;
+		break;
+	case PROTECT_LIST:
+		/* protect list is an intermediate atom's list to which jnodes
+		   get put from dirty list before disk space is allocated for
+		   them. From this list jnodes can either go to flush queue list
+		   or back to dirty list */
+		assert("", atom->protect > 0);
+		assert("", new_list == FQ_LIST || new_list == DIRTY_LIST);
+		atom->protect--;
+		break;
+	default:
+		impossible("", "");
+	}
+
+	switch (new_list) {
+	case NOT_CAPTURED:
+		break;
+	case DIRTY_LIST:
+		atom->dirty++;
+		break;
+	case CLEAN_LIST:
+		atom->clean++;
+		break;
+	case FQ_LIST:
+		atom->fq++;
+		break;
+	case WB_LIST:
+		atom->wb++;
+		break;
+	case OVRWR_LIST:
+		atom->ovrwr++;
+		break;
+	case PROTECT_LIST:
+		assert("", old_list == DIRTY_LIST);
+		atom->protect++;
+		break;
+	default:
+		impossible("", "");
+	}
+	ASSIGN_NODE_LIST(node, new_list);
+	if (0 && check_lists) {
+		int count;
+		tree_level level;
+
+		count = 0;
+
+		/* flush queue list */
+		/*check_fq(atom); */
+
+		/* dirty list */
+		count = 0;
+		for (level = 0; level < REAL_MAX_ZTREE_HEIGHT + 1; level += 1) {
+			list_for_each(pos, ATOM_DIRTY_LIST(atom, level))
+				count++;
+		}
+		if (count != atom->dirty)
+			warning("", "dirty counter %d, real %d\n", atom->dirty,
+				count);
+
+		/* clean list */
+		count = 0;
+		list_for_each(pos, ATOM_CLEAN_LIST(atom))
+			count++;
+		if (count != atom->clean)
+			warning("", "clean counter %d, real %d\n", atom->clean,
+				count);
+
+		/* wb list */
+		count = 0;
+		list_for_each(pos, ATOM_WB_LIST(atom))
+			count++;
+		if (count != atom->wb)
+			warning("", "wb counter %d, real %d\n", atom->wb,
+				count);
+
+		/* overwrite list */
+		count = 0;
+		list_for_each(pos, ATOM_OVRWR_LIST(atom))
+			count++;
+
+		if (count != atom->ovrwr)
+			warning("", "ovrwr counter %d, real %d\n", atom->ovrwr,
+				count);
+	}
+	assert("vs-1624", atom->num_queued == atom->fq);
+	if (atom->capture_count !=
+	    atom->dirty + atom->clean + atom->ovrwr + atom->wb + atom->fq +
+	    atom->protect) {
+		printk
+		    ("count %d, dirty %d clean %d ovrwr %d wb %d fq %d protect %d\n",
+		     atom->capture_count, atom->dirty, atom->clean, atom->ovrwr,
+		     atom->wb, atom->fq, atom->protect);
+		assert("vs-1622",
+		       atom->capture_count ==
+		       atom->dirty + atom->clean + atom->ovrwr + atom->wb +
+		       atom->fq + atom->protect);
+	}
+}
+
+#endif
+
+/* Make node OVRWR and put it on atom->overwrite_nodes list, atom lock and jnode
+ * lock should be taken before calling this function. */
+void jnode_make_wander_nolock(jnode * node)
+{
+	txn_atom *atom;
+
+	assert("nikita-2431", node != NULL);
+	assert("nikita-2432", !JF_ISSET(node, JNODE_RELOC));
+	assert("nikita-3153", JF_ISSET(node, JNODE_DIRTY));
+	assert("zam-897", !JF_ISSET(node, JNODE_FLUSH_QUEUED));
+	assert("nikita-3367", !blocknr_is_fake(jnode_get_block(node)));
+
+	atom = node->atom;
+
+	assert("zam-895", atom != NULL);
+	assert("zam-894", atom_is_protected(atom));
+
+	JF_SET(node, JNODE_OVRWR);
+	/* move node to atom's overwrite list */
+	list_del(&node->capture_link);
+	list_add_tail(&node->capture_link, ATOM_OVRWR_LIST(atom));
+	ON_DEBUG(count_jnode(atom, node, DIRTY_LIST, OVRWR_LIST, 1));
+}
+
+/* Same as jnode_make_wander_nolock, but all necessary locks are taken inside
+ * this function. */
+void jnode_make_wander(jnode * node)
+{
+	txn_atom *atom;
+
+	spin_lock_jnode(node);
+	atom = jnode_get_atom(node);
+	assert("zam-913", atom != NULL);
+	assert("zam-914", !JF_ISSET(node, JNODE_RELOC));
+
+	jnode_make_wander_nolock(node);
+	spin_unlock_atom(atom);
+	spin_unlock_jnode(node);
+}
+
+/* this just sets RELOC bit  */
+static void jnode_make_reloc_nolock(flush_queue_t * fq, jnode * node)
+{
+	assert_spin_locked(&(node->guard));
+	assert("zam-916", JF_ISSET(node, JNODE_DIRTY));
+	assert("zam-917", !JF_ISSET(node, JNODE_RELOC));
+	assert("zam-918", !JF_ISSET(node, JNODE_OVRWR));
+	assert("zam-920", !JF_ISSET(node, JNODE_FLUSH_QUEUED));
+	assert("nikita-3367", !blocknr_is_fake(jnode_get_block(node)));
+
+	jnode_set_reloc(node);
+}
+
+/* Make znode RELOC and put it on flush queue */
+void znode_make_reloc(znode * z, flush_queue_t * fq)
+{
+	jnode *node;
+	txn_atom *atom;
+
+	node = ZJNODE(z);
+	spin_lock_jnode(node);
+
+	atom = jnode_get_atom(node);
+	assert("zam-919", atom != NULL);
+
+	jnode_make_reloc_nolock(fq, node);
+	queue_jnode(fq, node);
+
+	spin_unlock_atom(atom);
+	spin_unlock_jnode(node);
+
+}
+
+/* Make unformatted node RELOC and put it on flush queue */
+void unformatted_make_reloc(jnode * node, flush_queue_t * fq)
+{
+	assert("vs-1479", jnode_is_unformatted(node));
+
+	jnode_make_reloc_nolock(fq, node);
+	mark_jnode_queued(fq, node);
+}
+
+int capture_super_block(struct super_block *s)
+{
+	int result;
+	znode *uber;
+	lock_handle lh;
+
+	init_lh(&lh);
+	result = get_uber_znode(get_tree(s),
+				ZNODE_WRITE_LOCK, ZNODE_LOCK_LOPRI, &lh);
+	if (result)
+		return result;
+
+	uber = lh.node;
+	/* Grabbing one block for superblock */
+	result = reiser4_grab_space_force((__u64) 1, BA_RESERVED);
+	if (result != 0)
+		return result;
+
+	znode_make_dirty(uber);
+
+	done_lh(&lh);
+	return 0;
+}
+
+/* Wakeup every handle on the atom's WAITFOR list */
+static void wakeup_atom_waitfor_list(txn_atom * atom)
+{
+	txn_wait_links *wlinks;
+
+	assert("umka-210", atom != NULL);
+
+	/* atom is locked */
+	list_for_each_entry(wlinks, &atom->fwaitfor_list, _fwaitfor_link) {
+		if (wlinks->waitfor_cb == NULL ||
+		    wlinks->waitfor_cb(atom, wlinks))
+			/* Wake up. */
+			reiser4_wake_up(wlinks->_lock_stack);
+	}
+}
+
+/* Wakeup every handle on the atom's WAITING list */
+static void wakeup_atom_waiting_list(txn_atom * atom)
+{
+	txn_wait_links *wlinks;
+
+	assert("umka-211", atom != NULL);
+
+	/* atom is locked */
+	list_for_each_entry(wlinks, &atom->fwaiting_list, _fwaiting_link) {
+		if (wlinks->waiting_cb == NULL ||
+		    wlinks->waiting_cb(atom, wlinks))
+			/* Wake up. */
+			reiser4_wake_up(wlinks->_lock_stack);
+	}
+}
+
+/* helper function used by capture_fuse_wait() to avoid "spurious wake-ups" */
+static int wait_for_fusion(txn_atom * atom, txn_wait_links * wlinks)
+{
+	assert("nikita-3330", atom != NULL);
+	assert_spin_locked(&(atom->alock));
+
+	/* atom->txnh_count == 1 is for waking waiters up if we are releasing
+	 * last transaction handle. */
+	return atom->stage != ASTAGE_CAPTURE_WAIT || atom->txnh_count == 1;
+}
+
+/* The general purpose of this function is to wait on the first of two possible events.
+   The situation is that a handle (and its atom atomh) is blocked trying to capture a
+   block (i.e., node) but the node's atom (atomf) is in the CAPTURE_WAIT state.  The
+   handle's atom (atomh) is not in the CAPTURE_WAIT state.  However, atomh could fuse with
+   another atom or, due to age, enter the CAPTURE_WAIT state itself, at which point it
+   needs to unblock the handle to avoid deadlock.  When the txnh is unblocked it will
+   proceed and fuse the two atoms in the CAPTURE_WAIT state.
+
+   In other words, if either atomh or atomf change state, the handle will be awakened,
+   thus there are two lists per atom: WAITING and WAITFOR.
+
+   This is also called by capture_assign_txnh with (atomh == NULL) to wait for atomf to
+   close but it is not assigned to an atom of its own.
+
+   Lock ordering in this method: all four locks are held: JNODE_LOCK, TXNH_LOCK,
+   BOTH_ATOM_LOCKS.  Result: all four locks are released.
+*/
+static int capture_fuse_wait(txn_handle * txnh, txn_atom * atomf,
+		    txn_atom * atomh, txn_capture mode)
+{
+	int ret;
+	txn_wait_links wlinks;
+
+	assert("umka-213", txnh != NULL);
+	assert("umka-214", atomf != NULL);
+
+	if ((mode & TXN_CAPTURE_NONBLOCKING) != 0) {
+		spin_unlock_txnh(txnh);
+		spin_unlock_atom(atomf);
+
+		if (atomh) {
+			spin_unlock_atom(atomh);
+		}
+
+		return RETERR(-E_BLOCK);
+	}
+
+	/* Initialize the waiting list links. */
+	init_wlinks(&wlinks);
+
+	/* Add txnh to atomf's waitfor list, unlock atomf. */
+	list_add_tail(&wlinks._fwaitfor_link, &atomf->fwaitfor_list);
+	wlinks.waitfor_cb = wait_for_fusion;
+	atomic_inc(&atomf->refcount);
+	spin_unlock_atom(atomf);
+
+	if (atomh) {
+		/* Add txnh to atomh's waiting list, unlock atomh. */
+		list_add_tail(&wlinks._fwaiting_link, &atomh->fwaiting_list);
+		atomic_inc(&atomh->refcount);
+		spin_unlock_atom(atomh);
+	}
+
+	/* Go to sleep. */
+	spin_unlock_txnh(txnh);
+
+	ret = prepare_to_sleep(wlinks._lock_stack);
+	if (ret == 0) {
+		go_to_sleep(wlinks._lock_stack);
+		ret = RETERR(-E_REPEAT);
+	}
+
+	/* Remove from the waitfor list. */
+	spin_lock_atom(atomf);
+
+	list_del(&wlinks._fwaitfor_link);
+	atom_dec_and_unlock(atomf);
+
+	if (atomh) {
+		/* Remove from the waiting list. */
+		spin_lock_atom(atomh);
+		list_del(&wlinks._fwaiting_link);
+		atom_dec_and_unlock(atomh);
+	}
+	return ret;
+}
+
+static void lock_two_atoms(txn_atom * one, txn_atom * two)
+{
+	assert("zam-1067", one != two);
+
+	/* lock the atom with lesser address first */
+	if (one < two) {
+		spin_lock_atom(one);
+		spin_lock_atom(two);
+	} else {
+		spin_lock_atom(two);
+		spin_lock_atom(one);
+	}
+}
+
+
+/* Perform the necessary work to prepare for fusing two atoms, which involves
+ * acquiring two atom locks in the proper order.  If one of the node's atom is
+ * blocking fusion (i.e., it is in the CAPTURE_WAIT stage) and the handle's
+ * atom is not then the handle's request is put to sleep.  If the node's atom
+ * is committing, then the node can be copy-on-captured.  Otherwise, pick the
+ * atom with fewer pointers to be fused into the atom with more pointer and
+ * call capture_fuse_into.
+ */
+static int
+capture_init_fusion(jnode * node, txn_handle * txnh, txn_capture mode,
+		    int can_coc)
+{
+	txn_atom * txnh_atom = txnh->atom;
+	txn_atom * block_atom = node->atom;
+
+	atomic_inc(&txnh_atom->refcount);
+	atomic_inc(&block_atom->refcount);
+
+	spin_unlock_txnh(txnh);
+	spin_unlock_jnode(node);
+
+	lock_two_atoms(txnh_atom, block_atom);
+
+	if (txnh->atom != txnh_atom || node->atom != block_atom ) {
+		release_two_atoms(txnh_atom, block_atom);
+		return RETERR(-E_REPEAT);
+	}
+
+	atomic_dec(&txnh_atom->refcount);
+	atomic_dec(&block_atom->refcount);
+
+	assert ("zam-1066", atom_isopen(txnh_atom));
+
+	if (txnh_atom->stage >= block_atom->stage ||
+	    (block_atom->stage == ASTAGE_CAPTURE_WAIT && block_atom->txnh_count == 0)) {
+		capture_fuse_into(txnh_atom, block_atom);
+		return RETERR(-E_REPEAT);
+	}
+	spin_lock_txnh(txnh);
+	return capture_fuse_wait(txnh, block_atom, txnh_atom, mode);
+}
+
+/* This function splices together two jnode lists (small and large) and sets all jnodes in
+   the small list to point to the large atom.  Returns the length of the list. */
+static int
+capture_fuse_jnode_lists(txn_atom *large, struct list_head *large_head,
+			 struct list_head *small_head)
+{
+	int count = 0;
+	jnode *node;
+
+	assert("umka-218", large != NULL);
+	assert("umka-219", large_head != NULL);
+	assert("umka-220", small_head != NULL);
+	/* small atom should be locked also. */
+	assert_spin_locked(&(large->alock));
+
+	/* For every jnode on small's capture list... */
+	list_for_each_entry(node, small_head, capture_link) {
+		count += 1;
+
+		/* With the jnode lock held, update atom pointer. */
+		spin_lock_jnode(node);
+		node->atom = large;
+		spin_unlock_jnode(node);
+	}
+
+	/* Splice the lists. */
+	list_splice_init(small_head, large_head->prev);
+
+	return count;
+}
+
+/* This function splices together two txnh lists (small and large) and sets all txn handles in
+   the small list to point to the large atom.  Returns the length of the list. */
+static int
+capture_fuse_txnh_lists(txn_atom *large, struct list_head *large_head,
+			struct list_head *small_head)
+{
+	int count = 0;
+	txn_handle *txnh;
+
+	assert("umka-221", large != NULL);
+	assert("umka-222", large_head != NULL);
+	assert("umka-223", small_head != NULL);
+
+	/* Adjust every txnh to the new atom. */
+	list_for_each_entry(txnh, small_head, txnh_link) {
+		count += 1;
+
+		/* With the txnh lock held, update atom pointer. */
+		spin_lock_txnh(txnh);
+		txnh->atom = large;
+		spin_unlock_txnh(txnh);
+	}
+
+	/* Splice the txn_handle list. */
+	list_splice_init(small_head, large_head->prev);
+
+	return count;
+}
+
+/* This function fuses two atoms.  The captured nodes and handles belonging to SMALL are
+   added to LARGE and their ->atom pointers are all updated.  The associated counts are
+   updated as well, and any waiting handles belonging to either are awakened.  Finally the
+   smaller atom's refcount is decremented.
+*/
+static void capture_fuse_into(txn_atom * small, txn_atom * large)
+{
+	int level;
+	unsigned zcount = 0;
+	unsigned tcount = 0;
+	protected_jnodes *prot_list;
+
+	assert("umka-224", small != NULL);
+	assert("umka-225", small != NULL);
+
+	assert_spin_locked(&(large->alock));
+	assert_spin_locked(&(small->alock));
+
+	assert("jmacd-201", atom_isopen(small));
+	assert("jmacd-202", atom_isopen(large));
+
+	/* Splice and update the per-level dirty jnode lists */
+	for (level = 0; level < REAL_MAX_ZTREE_HEIGHT + 1; level += 1) {
+		zcount +=
+		    capture_fuse_jnode_lists(large,
+					     ATOM_DIRTY_LIST(large, level),
+					     ATOM_DIRTY_LIST(small, level));
+	}
+
+	/* Splice and update the [clean,dirty] jnode and txnh lists */
+	zcount +=
+	    capture_fuse_jnode_lists(large, ATOM_CLEAN_LIST(large),
+				     ATOM_CLEAN_LIST(small));
+	zcount +=
+	    capture_fuse_jnode_lists(large, ATOM_OVRWR_LIST(large),
+				     ATOM_OVRWR_LIST(small));
+	zcount +=
+	    capture_fuse_jnode_lists(large, ATOM_WB_LIST(large),
+				     ATOM_WB_LIST(small));
+	zcount +=
+	    capture_fuse_jnode_lists(large, &large->inodes, &small->inodes);
+	tcount +=
+	    capture_fuse_txnh_lists(large, &large->txnh_list,
+				    &small->txnh_list);
+
+	list_for_each_entry(prot_list, &small->protected, inatom) {
+		jnode *node;
+
+		list_for_each_entry(node, &prot_list->nodes, capture_link) {
+			zcount += 1;
+
+			spin_lock_jnode(node);
+			assert("nikita-3375", node->atom == small);
+			/* With the jnode lock held, update atom pointer. */
+			node->atom = large;
+			spin_unlock_jnode(node);
+		}
+	}
+	/* Splice the lists of lists. */
+	list_splice_init(&small->protected, large->protected.prev);
+
+	/* Check our accounting. */
+	assert("jmacd-1063",
+	       zcount + small->num_queued == small->capture_count);
+	assert("jmacd-1065", tcount == small->txnh_count);
+
+	/* sum numbers of waiters threads */
+	large->nr_waiters += small->nr_waiters;
+	small->nr_waiters = 0;
+
+	/* splice flush queues */
+	fuse_fq(large, small);
+
+	/* update counter of jnode on every atom' list */
+	ON_DEBUG(large->dirty += small->dirty;
+		 small->dirty = 0;
+		 large->clean += small->clean;
+		 small->clean = 0;
+		 large->ovrwr += small->ovrwr;
+		 small->ovrwr = 0;
+		 large->wb += small->wb;
+		 small->wb = 0;
+		 large->fq += small->fq;
+		 small->fq = 0;
+		 large->protect += small->protect; small->protect = 0;);
+
+	/* count flushers in result atom */
+	large->nr_flushers += small->nr_flushers;
+	small->nr_flushers = 0;
+
+	/* update counts of flushed nodes */
+	large->flushed += small->flushed;
+	small->flushed = 0;
+
+	/* Transfer list counts to large. */
+	large->txnh_count += small->txnh_count;
+	large->capture_count += small->capture_count;
+
+	/* Add all txnh references to large. */
+	atomic_add(small->txnh_count, &large->refcount);
+	atomic_sub(small->txnh_count, &small->refcount);
+
+	/* Reset small counts */
+	small->txnh_count = 0;
+	small->capture_count = 0;
+
+	/* Assign the oldest start_time, merge flags. */
+	large->start_time = min(large->start_time, small->start_time);
+	large->flags |= small->flags;
+
+	/* Merge blocknr sets. */
+	blocknr_set_merge(&small->delete_set, &large->delete_set);
+	blocknr_set_merge(&small->wandered_map, &large->wandered_map);
+
+	/* Merge allocated/deleted file counts */
+	large->nr_objects_deleted += small->nr_objects_deleted;
+	large->nr_objects_created += small->nr_objects_created;
+
+	small->nr_objects_deleted = 0;
+	small->nr_objects_created = 0;
+
+	/* Merge allocated blocks counts */
+	large->nr_blocks_allocated += small->nr_blocks_allocated;
+
+	large->nr_running_queues += small->nr_running_queues;
+	small->nr_running_queues = 0;
+
+	/* Merge blocks reserved for overwrite set. */
+	large->flush_reserved += small->flush_reserved;
+	small->flush_reserved = 0;
+
+	if (large->stage < small->stage) {
+		/* Large only needs to notify if it has changed state. */
+		atom_set_stage(large, small->stage);
+		wakeup_atom_waiting_list(large);
+	}
+
+	atom_set_stage(small, ASTAGE_INVALID);
+
+	/* Notify any waiters--small needs to unload its wait lists.  Waiters
+	   actually remove themselves from the list before returning from the
+	   fuse_wait function. */
+	wakeup_atom_waiting_list(small);
+
+	/* Unlock atoms */
+	spin_unlock_atom(large);
+	atom_dec_and_unlock(small);
+}
+
+void protected_jnodes_init(protected_jnodes *list)
+{
+	txn_atom *atom;
+
+	assert("nikita-3376", list != NULL);
+
+	atom = get_current_atom_locked();
+	list_add(&list->inatom, &atom->protected);
+	INIT_LIST_HEAD(&list->nodes);
+	spin_unlock_atom(atom);
+}
+
+void protected_jnodes_done(protected_jnodes *list)
+{
+	txn_atom *atom;
+
+	assert("nikita-3379", list_empty(&list->nodes));
+
+	atom = get_current_atom_locked();
+	list_del_init(&list->inatom);
+	spin_unlock_atom(atom);
+}
+
+/* TXNMGR STUFF */
+
+#if REISER4_COPY_ON_CAPTURE
+
+/* copy on capture steals jnode (J) from capture list. It may replace (J) with
+   special newly created jnode (CCJ) to which J's page gets attached. J in its
+   turn gets newly created copy of page.
+   Or, it may merely take J from capture list if J was never dirtied
+
+   The problem with this replacement is that capture lists are being contiguously
+   scanned.
+   Race between replacement and scanning are avoided with one global spin lock
+   (scan_lock) and JNODE_SCANNED state of jnode. Replacement (in capture copy)
+   goes under scan_lock locked only if jnode is not in JNODE_SCANNED state. This
+   state gets set under scan_lock locked whenever scanning is working with that
+   jnode.
+*/
+
+/* remove jnode page from mapping's tree and insert new page with the same index */
+static void replace_page_in_mapping(jnode * node, struct page *new_page)
+{
+	struct address_space *mapping;
+	unsigned long index;
+
+	mapping = jnode_get_mapping(node);
+	index = jnode_get_index(node);
+
+	spin_lock(&mapping->page_lock);
+
+	/* delete old page from. This resembles __remove_from_page_cache */
+	assert("vs-1416",
+	       radix_tree_lookup(&mapping->page_tree, index) == node->pg);
+	assert("vs-1428", node->pg->mapping == mapping);
+	__remove_from_page_cache(node->pg);
+
+	/* insert new page into mapping */
+	check_me("vs-1411",
+		 radix_tree_insert(&mapping->page_tree, index, new_page) == 0);
+
+	/* this resembles add_to_page_cache */
+	page_cache_get(new_page);
+	___add_to_page_cache(new_page, mapping, index);
+
+	spin_unlock(&mapping->page_lock);
+	lru_cache_add(new_page);
+}
+
+/* attach page of @node to @copy, @new_page to @node */
+static void swap_jnode_pages(jnode * node, jnode * copy, struct page *new_page)
+{
+	/* attach old page to new jnode */
+	assert("vs-1414", jnode_by_page(node->pg) == node);
+	copy->pg = node->pg;
+	copy->data = page_address(copy->pg);
+	jnode_set_block(copy, jnode_get_block(node));
+	set_page_private(copy->pg, (unsigned long)copy);
+
+	/* attach new page to jnode */
+	assert("vs-1412", !PagePrivate(new_page));
+	page_cache_get(new_page);
+	node->pg = new_page;
+	node->data = page_address(new_page);
+	set_page_private(new_page, (unsigned long)node);
+	SetPagePrivate(new_page);
+
+	{
+		/* insert old page to new mapping */
+		struct address_space *mapping;
+		unsigned long index;
+
+		mapping = get_current_super_private()->cc->i_mapping;
+		index = (unsigned long)copy;
+		spin_lock(&mapping->page_lock);
+
+		/* insert old page into new (fake) mapping. No page_cache_get
+		   because page reference counter was not decreased on removing
+		   it from old mapping */
+		assert("vs-1416",
+		       radix_tree_lookup(&mapping->page_tree, index) == NULL);
+		check_me("vs-1418",
+			 radix_tree_insert(&mapping->page_tree, index,
+					   copy->pg) == 0);
+		___add_to_page_cache(copy->pg, mapping, index);
+
+		/* corresponding page_cache_release is in invalidate_list */
+		page_cache_get(copy->pg);
+		spin_unlock(&mapping->page_lock);
+	}
+}
+
+/* this is to make capture copied jnode looking like if there were jload called for it */
+static void fake_jload(jnode * node)
+{
+	jref(node);
+	atomic_inc(&node->d_count);
+	JF_SET(node, JNODE_PARSED);
+}
+
+/* for now - refuse to copy-on-capture any suspicious nodes (WRITEBACK, DIRTY, FLUSH_QUEUED) */
+static int check_capturable(jnode * node, const txn_atom * atom)
+{
+	assert_spin_locked(&(node->guard));
+	assert_spin_locked(&scan_lock);
+
+	if (JF_ISSET(node, JNODE_WRITEBACK)) {
+		reiser4_stat_inc(coc.writeback);
+		return RETERR(-E_WAIT);
+	}
+	if (JF_ISSET(node, JNODE_FLUSH_QUEUED)) {
+		reiser4_stat_inc(coc.flush_queued);
+		return RETERR(-E_WAIT);
+	}
+	if (JF_ISSET(node, JNODE_DIRTY)) {
+		reiser4_stat_inc(coc.dirty);
+		return RETERR(-E_WAIT);
+	}
+	if (JF_ISSET(node, JNODE_SCANNED)) {
+		reiser4_stat_inc(coc.scan_race);
+		return RETERR(-E_REPEAT);
+	}
+	if (node->atom != atom) {
+		reiser4_stat_inc(coc.atom_changed);
+		return RETERR(-E_WAIT);
+	}
+	return 0;		/* OK */
+}
+
+static void remove_from_capture_list(jnode * node)
+{
+	ON_DEBUG_MODIFY(znode_set_checksum(node, 1));
+	JF_CLR(node, JNODE_DIRTY);
+	JF_CLR(node, JNODE_RELOC);
+	JF_CLR(node, JNODE_OVRWR);
+	JF_CLR(node, JNODE_CREATED);
+	JF_CLR(node, JNODE_WRITEBACK);
+	JF_CLR(node, JNODE_REPACK);
+
+	capture_list_remove_clean(node);
+	node->atom->capture_count--;
+	atomic_dec(&node->x_count);
+
+	ON_DEBUG(count_jnode(node->atom, node, NODE_LIST(node),
+			     NOT_CAPTURED, 1));
+	node->atom = 0;
+}
+
+/* insert new jnode (copy) to capture list instead of old one */
+static void replace_on_capture_list(jnode * node, jnode * copy)
+{
+	assert("vs-1415", node->atom);
+	assert("vs-1489", !capture_list_is_clean(node));
+	assert("vs-1493", JF_ISSET(copy, JNODE_CC)
+	       && JF_ISSET(copy, JNODE_HEARD_BANSHEE));
+
+	copy->state |= node->state;
+
+	/* insert cc-jnode @copy into capture list before old jnode @node */
+	capture_list_insert_before(node, copy);
+	jref(copy);
+	copy->atom = node->atom;
+	node->atom->capture_count++;
+
+	ON_DEBUG(count_jnode(node->atom, copy, NODE_LIST(copy),
+			     NODE_LIST(node), 1));
+
+	/* remove old jnode from capture list */
+	remove_from_capture_list(node);
+}
+
+/* when capture request is made for a node which is captured but was never
+   dirtied copy on capture will merely uncapture it */
+static int copy_on_capture_clean(jnode * node, txn_atom * atom)
+{
+	int result;
+
+	assert_spin_locked(&(atom->alock));
+	assert_spin_locked(&(node->guard));
+	assert("vs-1627", !JF_ISSET(node, JNODE_WRITEBACK));
+
+	spin_lock(&scan_lock);
+	result = check_capturable(node, atom);
+	if (result == 0) {
+		/* remove jnode from capture list */
+		remove_from_capture_list(node);
+		reiser4_stat_inc(coc.ok_clean);
+	}
+	spin_unlock(&scan_lock);
+	spin_unlock_jnode(node);
+	spin_unlock_atom(atom);
+
+	return result;
+}
+
+static void lock_two_nodes(jnode * node1, jnode * node2)
+{
+	if (node1 > node2) {
+		spin_lock_jnode(node2);
+		spin_lock_jnode(node1);
+	} else {
+		spin_lock_jnode(node1);
+		spin_lock_jnode(node2);
+	}
+}
+
+/* capture request is made for node which does not have page. In most cases this
+   is "uber" znode */
+static int copy_on_capture_nopage(jnode * node, txn_atom * atom)
+{
+	int result;
+	jnode *copy;
+
+
+	assert("vs-1432", spin_atom_is_locked(atom));
+	assert("vs-1432", spin_jnode_is_locked(node));
+
+	jref(node);
+	spin_unlock_jnode(node);
+	spin_unlock_atom(atom);
+	assert("nikita-3475", schedulable());
+	copy = jclone(node);
+	if (IS_ERR(copy)) {
+		jput(node);
+		return PTR_ERR(copy);
+	}
+
+	spin_lock_atom(atom);
+	lock_two_nodes(node, copy);
+	spin_lock(&scan_lock);
+
+	result = check_capturable(node, atom);
+	if (result == 0) {
+		if (jnode_page(node) == NULL) {
+			replace_on_capture_list(node, copy);
+#if REISER4_STATS
+			if (znode_above_root(JZNODE(node)))
+				reiser4_stat_inc(coc.ok_uber);
+			else
+				reiser4_stat_inc(coc.ok_nopage);
+#endif
+		} else
+			result = RETERR(-E_REPEAT);
+	}
+
+	spin_unlock(&scan_lock);
+	spin_unlock_jnode(node);
+	spin_unlock_jnode(copy);
+	spin_unlock_atom(atom);
+	assert("nikita-3476", schedulable());
+	jput(copy);
+	assert("nikita-3477", schedulable());
+	jput(node);
+	assert("nikita-3478", schedulable());
+	ON_TRACE(TRACE_CAPTURE_COPY, "nopage\n");
+	return result;
+}
+
+static int
+handle_coc(jnode * node, jnode * copy, struct page *page, struct page *new_page,
+	   txn_atom * atom)
+{
+	char *to;
+	char *from;
+	int result;
+
+	to = kmap(new_page);
+	lock_page(page);
+	from = kmap(page);
+	/*
+	 * FIXME(zam): one preloaded radix tree node may be not enough for two
+	 * insertions, one insertion is in replace_page_in_mapping(), another
+	 * one is in swap_jnode_pages(). The radix_tree_delete() call might
+	 * not help, because an empty radix tree node is freed and the node's
+	 * free space may not be re-used in insertion.
+	 */
+	radix_tree_preload(GFP_KERNEL);
+	spin_lock_atom(atom);
+	lock_two_nodes(node, copy);
+	spin_lock(&scan_lock);
+
+	result = check_capturable(node, atom);
+	if (result == 0) {
+		/* if node was jloaded by get_overwrite_set, we have to jrelse
+		   it here, because we remove jnode from atom's capture list -
+		   put_overwrite_set will not jrelse it */
+		int was_jloaded;
+
+		was_jloaded =
+		    JF_ISSET(node, JNODE_JLOADED_BY_GET_OVERWRITE_SET);
+
+		replace_page_in_mapping(node, new_page);
+		swap_jnode_pages(node, copy, new_page);
+		replace_on_capture_list(node, copy);
+		/* statistics */
+		if (JF_ISSET(copy, JNODE_RELOC)) {
+			reiser4_stat_inc(coc.ok_reloc);
+		} else if (JF_ISSET(copy, JNODE_OVRWR)) {
+			reiser4_stat_inc(coc.ok_ovrwr);
+		} else
+			impossible("", "");
+
+		memcpy(to, from, PAGE_CACHE_SIZE);
+		SetPageUptodate(new_page);
+		if (was_jloaded)
+			fake_jload(copy);
+		else
+			kunmap(page);
+
+		assert("vs-1419", page_count(new_page) >= 3);
+		spin_unlock(&scan_lock);
+		spin_unlock_jnode(node);
+		spin_unlock_jnode(copy);
+		spin_unlock_atom(atom);
+		radix_tree_preload_end();
+		unlock_page(page);
+
+		if (was_jloaded) {
+			jrelse_tail(node);
+			assert("vs-1494",
+			       JF_ISSET(node,
+					JNODE_JLOADED_BY_GET_OVERWRITE_SET));
+			JF_CLR(node, JNODE_JLOADED_BY_GET_OVERWRITE_SET);
+		} else
+			kunmap(new_page);
+
+		jput(copy);
+		jrelse(node);
+		jput(node);
+		page_cache_release(page);
+		page_cache_release(new_page);
+		ON_TRACE(TRACE_CAPTURE_COPY, "copy on capture done\n");
+	} else {
+		spin_unlock(&scan_lock);
+		spin_unlock_jnode(node);
+		spin_unlock_jnode(copy);
+		spin_unlock_atom(atom);
+		radix_tree_preload_end();
+		kunmap(page);
+		unlock_page(page);
+		kunmap(new_page);
+		page_cache_release(new_page);
+	}
+	return result;
+}
+
+static int real_copy_on_capture(jnode * node, txn_atom * atom)
+{
+	int result;
+	jnode *copy;
+	struct page *page;
+	struct page *new_page;
+
+	assert("vs-1432", spin_jnode_is_locked(node));
+	assert("vs-1490", !JF_ISSET(node, JNODE_EFLUSH));
+	assert("vs-1491", node->pg);
+	assert("vs-1492", jprivate(node->pg) == node);
+
+	page = node->pg;
+	page_cache_get(page);
+	jref(node);
+	spin_unlock_jnode(node);
+	spin_unlock_atom(atom);
+
+	/* prevent node from eflushing */
+	result = jload(node);
+	if (!result) {
+		copy = jclone(node);
+		if (likely(!IS_ERR(copy))) {
+			new_page = alloc_page(GFP_KERNEL);
+			if (new_page) {
+				result = handle_coc(node,
+						    copy, page, new_page, atom);
+				if (result == 0)
+					return 0;
+			} else
+				result = RETERR(-ENOMEM);
+			jput(copy);
+		}
+		jrelse(node);
+	}
+
+	jput(node);
+	page_cache_release(page);
+	return result;
+}
+
+/* create new jnode, create new page, jload old jnode, copy data, detach old
+   page from old jnode, attach new page to old jnode, attach old page to new
+   jnode this returns 0 if copy on capture succeeded, E_REPEAT to have
+   capture_fuse_wait to be called */
+static int create_copy_and_replace(jnode * node, txn_atom * atom)
+{
+	int result;
+	struct inode *inode;	/* inode for which filemap_nopage is blocked */
+
+	assert("jmacd-321", spin_jnode_is_locked(node));
+	assert("umka-295", spin_atom_is_locked(atom));
+	assert("vs-1381", node->atom == atom);
+	assert("vs-1409", atom->stage > ASTAGE_CAPTURE_WAIT
+	       && atom->stage < ASTAGE_DONE);
+	assert("vs-1410", jnode_is_znode(node) || jnode_is_unformatted(node));
+
+	if (JF_ISSET(node, JNODE_CCED)) {
+		/* node is under copy on capture already */
+		reiser4_stat_inc(coc.coc_race);
+		spin_unlock_jnode(node);
+		spin_unlock_atom(atom);
+		return RETERR(-E_WAIT);
+	}
+
+	/* measure how often suspicious (WRITEBACK, DIRTY, FLUSH_QUEUED) appear
+	   here. For most often case we can return EAGAIN right here and avoid
+	   all the preparations made for copy on capture */
+	ON_TRACE(TRACE_CAPTURE_COPY, "copy_on_capture: node %p, atom %p..",
+		 node, atom);
+	if (JF_ISSET(node, JNODE_EFLUSH)) {
+		spin_unlock_jnode(node);
+		spin_unlock_atom(atom);
+
+		reiser4_stat_inc(coc.eflush);
+		ON_TRACE(TRACE_CAPTURE_COPY, "eflushed\n");
+		result = jload(node);
+		if (result)
+			return RETERR(result);
+		jrelse(node);
+		return RETERR(-E_REPEAT);
+	}
+
+	set_cced_bit(node);
+
+	if (jnode_is_unformatted(node)) {
+		/* to capture_copy unformatted node we have to take care of its
+		   page mappings. Page gets unmapped here and concurrent
+		   mappings are blocked on reiser4 inodes's coc_sem in reiser4's
+		   filemap_nopage */
+		struct page *page;
+
+		inode = mapping_jnode(node)->host;
+		page = jnode_page(node);
+		assert("vs-1640", inode != NULL);
+		assert("vs-1641", page != NULL);
+		assert("vs-1642", page->mapping != NULL);
+		spin_unlock_jnode(node);
+		spin_unlock_atom(atom);
+
+		down_write(&reiser4_inode_data(inode)->coc_sem);
+		lock_page(page);
+		pte_chain_lock(page);
+
+		if (page_mapped(page)) {
+			result = try_to_unmap(page);
+			if (result == SWAP_AGAIN) {
+				result = RETERR(-E_REPEAT);
+
+			} else if (result == SWAP_FAIL)
+				result = RETERR(-E_WAIT);
+			else {
+				assert("vs-1643", result == SWAP_SUCCESS);
+				result = 0;
+			}
+			if (result != 0) {
+				unlock_page(page);
+				pte_chain_unlock(page);
+				up_write(&reiser4_inode_data(inode)->coc_sem);
+				return result;
+			}
+		}
+		pte_chain_unlock(page);
+		unlock_page(page);
+		spin_lock_atom(atom);
+		spin_lock_jnode(node);
+	} else
+		inode = NULL;
+
+	if (!JF_ISSET(node, JNODE_OVRWR) && !JF_ISSET(node, JNODE_RELOC)) {
+		/* clean node can be made available for capturing. Just take
+		   care to preserve atom list during uncapturing */
+		ON_TRACE(TRACE_CAPTURE_COPY, "clean\n");
+		result = copy_on_capture_clean(node, atom);
+	} else if (!node->pg) {
+		ON_TRACE(TRACE_CAPTURE_COPY, "uber\n");
+		result = copy_on_capture_nopage(node, atom);
+	} else
+		result = real_copy_on_capture(node, atom);
+	if (result != 0)
+		clear_cced_bits(node);
+	assert("vs-1626", spin_atom_is_not_locked(atom));
+
+	if (inode != NULL)
+		up_write(&reiser4_inode_data(inode)->coc_sem);
+
+	return result;
+}
+#endif				/* REISER4_COPY_ON_CAPTURE */
+
+/* Release a block from the atom, reversing the effects of being captured,
+   do not release atom's reference to jnode due to holding spin-locks.
+   Currently this is only called when the atom commits.
+
+   NOTE: this function does not release a (journal) reference to jnode
+   due to locking optimizations, you should call jput() somewhere after
+   calling uncapture_block(). */
+void uncapture_block(jnode * node)
+{
+	txn_atom *atom;
+
+	assert("umka-226", node != NULL);
+	atom = node->atom;
+	assert("umka-228", atom != NULL);
+
+	assert("jmacd-1021", node->atom == atom);
+	assert_spin_locked(&(node->guard));
+#if REISER4_COPY_ON_CAPTURE
+	assert_spin_locked(&(atom->alock));
+#else
+	assert("jmacd-1023", atom_is_protected(atom));
+#endif
+	assert("", !JF_ISSET(node, JNODE_EFLUSH));
+
+	JF_CLR(node, JNODE_DIRTY);
+	JF_CLR(node, JNODE_RELOC);
+	JF_CLR(node, JNODE_OVRWR);
+	JF_CLR(node, JNODE_CREATED);
+	JF_CLR(node, JNODE_WRITEBACK);
+	JF_CLR(node, JNODE_REPACK);
+	clear_cced_bits(node);
+
+	list_del_init(&node->capture_link);
+	if (JF_ISSET(node, JNODE_FLUSH_QUEUED)) {
+		assert("zam-925", atom_isopen(atom));
+		assert("vs-1623", NODE_LIST(node) == FQ_LIST);
+		ON_DEBUG(atom->num_queued--);
+		JF_CLR(node, JNODE_FLUSH_QUEUED);
+	}
+	atom->capture_count -= 1;
+	ON_DEBUG(count_jnode(atom, node, NODE_LIST(node), NOT_CAPTURED, 1));
+	node->atom = NULL;
+
+	spin_unlock_jnode(node);
+	LOCK_CNT_DEC(t_refs);
+}
+
+/* Unconditional insert of jnode into atom's overwrite list. Currently used in
+   bitmap-based allocator code for adding modified bitmap blocks the
+   transaction. @atom and @node are spin locked */
+void insert_into_atom_ovrwr_list(txn_atom * atom, jnode * node)
+{
+	assert("zam-538", atom_is_protected(atom));
+	assert_spin_locked(&(node->guard));
+	assert("zam-899", JF_ISSET(node, JNODE_OVRWR));
+	assert("zam-543", node->atom == NULL);
+	assert("vs-1433", !jnode_is_unformatted(node) && !jnode_is_znode(node));
+
+	list_add(&node->capture_link, ATOM_OVRWR_LIST(atom));
+	jref(node);
+	node->atom = atom;
+	atom->capture_count++;
+	ON_DEBUG(count_jnode(atom, node, NODE_LIST(node), OVRWR_LIST, 1));
+}
+
+
+#if REISER4_DEBUG
+
+void info_atom(const char *prefix, const txn_atom * atom)
+{
+	if (atom == NULL) {
+		printk("%s: no atom\n", prefix);
+		return;
+	}
+
+	printk("%s: refcount: %i id: %i flags: %x txnh_count: %i"
+	       " capture_count: %i stage: %x start: %lu, flushed: %i\n", prefix,
+	       atomic_read(&atom->refcount), atom->atom_id, atom->flags,
+	       atom->txnh_count, atom->capture_count, atom->stage,
+	       atom->start_time, atom->flushed);
+}
+
+#endif
+
+static int count_deleted_blocks_actor(txn_atom * atom,
+				      const reiser4_block_nr * a,
+				      const reiser4_block_nr * b, void *data)
+{
+	reiser4_block_nr *counter = data;
+
+	assert("zam-995", data != NULL);
+	assert("zam-996", a != NULL);
+	if (b == NULL)
+		*counter += 1;
+	else
+		*counter += *b;
+	return 0;
+}
+
+reiser4_block_nr txnmgr_count_deleted_blocks(void)
+{
+	reiser4_block_nr result;
+	txn_mgr *tmgr = &get_super_private(reiser4_get_current_sb())->tmgr;
+	txn_atom *atom;
+
+	result = 0;
+
+	spin_lock_txnmgr(tmgr);
+	list_for_each_entry(atom, &tmgr->atoms_list, atom_link) {
+		spin_lock_atom(atom);
+		if (atom_isopen(atom))
+			blocknr_set_iterator(
+				atom, &atom->delete_set,
+				count_deleted_blocks_actor, &result, 0);
+		spin_unlock_atom(atom);
+	}
+	spin_unlock_txnmgr(tmgr);
+
+	return result;
+}
+
+/*
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * fill-column: 79
+ * End:
+ */
diff -urN oldtree/fs/reiser4/txnmgr.h newtree/fs/reiser4/txnmgr.h
--- oldtree/fs/reiser4/txnmgr.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/txnmgr.h	2006-02-21 15:58:35.456756312 +0000
@@ -0,0 +1,711 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* data-types and function declarations for transaction manager. See txnmgr.c
+ * for details. */
+
+#ifndef __REISER4_TXNMGR_H__
+#define __REISER4_TXNMGR_H__
+
+#include "forward.h"
+#include "dformat.h"
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include <asm/semaphore.h>
+
+/* TYPE DECLARATIONS */
+
+/* This enumeration describes the possible types of a capture request (try_capture).
+   A capture request dynamically assigns a block to the calling thread's transaction
+   handle. */
+typedef enum {
+	/* A READ_ATOMIC request indicates that a block will be read and that the caller's
+	   atom should fuse in order to ensure that the block commits atomically with the
+	   caller. */
+	TXN_CAPTURE_READ_ATOMIC = (1 << 0),
+
+	/* A READ_NONCOM request indicates that a block will be read and that the caller is
+	   willing to read a non-committed block without causing atoms to fuse. */
+	TXN_CAPTURE_READ_NONCOM = (1 << 1),
+
+	/* A READ_MODIFY request indicates that a block will be read but that the caller
+	   wishes for the block to be captured as it will be written.  This capture request
+	   mode is not currently used, but eventually it will be useful for preventing
+	   deadlock in read-modify-write cycles. */
+	TXN_CAPTURE_READ_MODIFY = (1 << 2),
+
+	/* A WRITE capture request indicates that a block will be modified and that atoms
+	   should fuse to make the commit atomic. */
+	TXN_CAPTURE_WRITE = (1 << 3),
+
+	/* CAPTURE_TYPES is a mask of the four above capture types, used to separate the
+	   exclusive type designation from extra bits that may be supplied -- see
+	   below. */
+	TXN_CAPTURE_TYPES = (TXN_CAPTURE_READ_ATOMIC |
+			     TXN_CAPTURE_READ_NONCOM | TXN_CAPTURE_READ_MODIFY |
+			     TXN_CAPTURE_WRITE),
+
+	/* A subset of CAPTURE_TYPES, CAPTURE_WTYPES is a mask of request types that
+	   indicate modification will occur. */
+	TXN_CAPTURE_WTYPES = (TXN_CAPTURE_READ_MODIFY | TXN_CAPTURE_WRITE),
+
+	/* An option to try_capture, NONBLOCKING indicates that the caller would
+	   prefer not to sleep waiting for an aging atom to commit. */
+	TXN_CAPTURE_NONBLOCKING = (1 << 4),
+
+	/* An option to try_capture to prevent atom fusion, just simple capturing is allowed */
+	TXN_CAPTURE_DONT_FUSE = (1 << 5),
+
+	/* if it is set - copy on capture is allowed */
+	/*TXN_CAPTURE_CAN_COC = (1 << 6) */
+
+	/* This macro selects only the exclusive capture request types, stripping out any
+	   options that were supplied (i.e., NONBLOCKING). */
+#define CAPTURE_TYPE(x) ((x) & TXN_CAPTURE_TYPES)
+} txn_capture;
+
+/* There are two kinds of transaction handle: WRITE_FUSING and READ_FUSING, the only
+   difference is in the handling of read requests.  A WRITE_FUSING transaction handle
+   defaults read capture requests to TXN_CAPTURE_READ_NONCOM whereas a READ_FUSIONG
+   transaction handle defaults to TXN_CAPTURE_READ_ATOMIC. */
+typedef enum {
+	TXN_WRITE_FUSING = (1 << 0),
+	TXN_READ_FUSING = (1 << 1) | TXN_WRITE_FUSING,	/* READ implies WRITE */
+} txn_mode;
+
+/* Every atom has a stage, which is one of these exclusive values: */
+typedef enum {
+	/* Initially an atom is free. */
+	ASTAGE_FREE = 0,
+
+	/* An atom begins by entering the CAPTURE_FUSE stage, where it proceeds to capture
+	   blocks and fuse with other atoms. */
+	ASTAGE_CAPTURE_FUSE = 1,
+
+	/* We need to have a ASTAGE_CAPTURE_SLOW in which an atom fuses with one node for every X nodes it flushes to disk where X > 1. */
+
+	/* When an atom reaches a certain age it must do all it can to commit.  An atom in
+	   the CAPTURE_WAIT stage refuses new transaction handles and prevents fusion from
+	   atoms in the CAPTURE_FUSE stage. */
+	ASTAGE_CAPTURE_WAIT = 2,
+
+	/* Waiting for I/O before commit.  Copy-on-capture (see
+	   http://namesys.com/v4/v4.html). */
+	ASTAGE_PRE_COMMIT = 3,
+
+	/* Post-commit overwrite I/O.  Steal-on-capture. */
+	ASTAGE_POST_COMMIT = 4,
+
+	/* Atom which waits for the removal of the last reference to (it? ) to
+	 * be deleted from memory  */
+	ASTAGE_DONE = 5,
+
+	/* invalid atom. */
+	ASTAGE_INVALID = 6,
+
+} txn_stage;
+
+/* Certain flags may be set in the txn_atom->flags field. */
+typedef enum {
+	/* Indicates that the atom should commit as soon as possible. */
+	ATOM_FORCE_COMMIT = (1 << 0),
+	/* to avoid endless loop, mark the atom (which was considered as too
+	 * small) after failed attempt to fuse it. */
+	ATOM_CANCEL_FUSION = (1 << 1)
+} txn_flags;
+
+/* Flags for controlling commit_txnh */
+typedef enum {
+	/* Wait commit atom completion in commit_txnh */
+	TXNH_WAIT_COMMIT = 0x2,
+	/* Don't commit atom when this handle is closed */
+	TXNH_DONT_COMMIT = 0x4
+} txn_handle_flags_t;
+
+/* TYPE DEFINITIONS */
+
+/* A note on lock ordering: the handle & jnode spinlock protects reading of their ->atom
+   fields, so typically an operation on the atom through either of these objects must (1)
+   lock the object, (2) read the atom pointer, (3) lock the atom.
+
+   During atom fusion, the process holds locks on both atoms at once.  Then, it iterates
+   through the list of handles and pages held by the smaller of the two atoms.  For each
+   handle and page referencing the smaller atom, the fusing process must: (1) lock the
+   object, and (2) update the atom pointer.
+
+   You can see that there is a conflict of lock ordering here, so the more-complex
+   procedure should have priority, i.e., the fusing process has priority so that it is
+   guaranteed to make progress and to avoid restarts.
+
+   This decision, however, means additional complexity for aquiring the atom lock in the
+   first place.
+
+   The general original procedure followed in the code was:
+
+       TXN_OBJECT *obj = ...;
+       TXN_ATOM   *atom;
+
+       spin_lock (& obj->_lock);
+
+       atom = obj->_atom;
+
+       if (! spin_trylock_atom (atom))
+         {
+           spin_unlock (& obj->_lock);
+           RESTART OPERATION, THERE WAS A RACE;
+         }
+
+       ELSE YOU HAVE BOTH ATOM AND OBJ LOCKED
+
+   It has however been found that this wastes CPU a lot in a manner that is
+   hard to profile. So, proper refcounting was added to atoms, and new
+   standard locking sequence is like following:
+
+       TXN_OBJECT *obj = ...;
+       TXN_ATOM   *atom;
+
+       spin_lock (& obj->_lock);
+
+       atom = obj->_atom;
+
+       if (! spin_trylock_atom (atom))
+         {
+           atomic_inc (& atom->refcount);
+           spin_unlock (& obj->_lock);
+           spin_lock (&atom->_lock);
+           atomic_dec (& atom->refcount);
+           // HERE atom is locked
+           spin_unlock (&atom->_lock);
+           RESTART OPERATION, THERE WAS A RACE;
+         }
+
+       ELSE YOU HAVE BOTH ATOM AND OBJ LOCKED
+
+   (core of this is implemented in trylock_throttle() function)
+
+   See the jnode_get_atom() function for a common case.
+
+   As an additional (and important) optimization allowing to avoid restarts,
+   it is possible to re-check required pre-conditions at the HERE point in
+   code above and proceed without restarting if they are still satisfied.
+*/
+
+/* A block number set consists of only the list head. */
+struct blocknr_set {
+	struct list_head entries;
+};
+
+/* An atomic transaction: this is the underlying system representation
+   of a transaction, not the one seen by clients.
+
+   Invariants involving this data-type:
+
+      [sb-fake-allocated]
+*/
+struct txn_atom {
+	/* The spinlock protecting the atom, held during fusion and various other state
+	   changes. */
+	spinlock_t alock;
+
+	/* The atom's reference counter, increasing (in case of a duplication
+	   of an existing reference or when we are sure that some other
+	   reference exists) may be done without taking spinlock, decrementing
+	   of the ref. counter requires a spinlock to be held.
+
+	   Each transaction handle counts in ->refcount. All jnodes count as
+	   one reference acquired in atom_begin_andlock(), released in
+	   commit_current_atom().
+	 */
+	atomic_t refcount;
+
+	/* The atom_id identifies the atom in persistent records such as the log. */
+	__u32 atom_id;
+
+	/* Flags holding any of the txn_flags enumerated values (e.g.,
+	   ATOM_FORCE_COMMIT). */
+	__u32 flags;
+
+	/* Number of open handles. */
+	__u32 txnh_count;
+
+	/* The number of znodes captured by this atom.  Equal to the sum of lengths of the
+	   dirty_nodes[level] and clean_nodes lists. */
+	__u32 capture_count;
+
+#if REISER4_DEBUG
+	int clean;
+	int dirty;
+	int ovrwr;
+	int wb;
+	int fq;
+	int protect;
+#endif
+
+	__u32 flushed;
+
+	/* Current transaction stage. */
+	txn_stage stage;
+
+	/* Start time. */
+	unsigned long start_time;
+
+	/* The atom's delete set. It collects block numbers of the nodes
+	   which were deleted during the transaction. */
+	blocknr_set delete_set;
+
+	/* The atom's wandered_block mapping. */
+	blocknr_set wandered_map;
+
+	/* The transaction's list of dirty captured nodes--per level.  Index
+	   by (level). dirty_nodes[0] is for znode-above-root */
+	struct list_head dirty_nodes[REAL_MAX_ZTREE_HEIGHT + 1];
+
+	/* The transaction's list of clean captured nodes. */
+	struct list_head clean_nodes;
+
+	/* The atom's overwrite set */
+	struct list_head ovrwr_nodes;
+
+	/* nodes which are being written to disk */
+	struct list_head writeback_nodes;
+
+	/* list of inodes */
+	struct list_head inodes;
+
+	/* List of handles associated with this atom. */
+	struct list_head txnh_list;
+
+	/* Transaction list link: list of atoms in the transaction manager. */
+	struct list_head atom_link;
+
+	/* List of handles waiting FOR this atom: see 'capture_fuse_wait' comment. */
+	struct list_head fwaitfor_list;
+
+	/* List of this atom's handles that are waiting: see 'capture_fuse_wait' comment. */
+	struct list_head fwaiting_list;
+
+	struct list_head protected;
+
+	/* Numbers of objects which were deleted/created in this transaction
+	   thereby numbers of objects IDs which were released/deallocated. */
+	int nr_objects_deleted;
+	int nr_objects_created;
+	/* number of blocks allocated during the transaction */
+	__u64 nr_blocks_allocated;
+	/* All atom's flush queue objects are on this list  */
+	struct list_head flush_queues;
+#if REISER4_DEBUG
+	/* number of flush queues for this atom. */
+	int nr_flush_queues;
+	/* Number of jnodes which were removed from atom's lists and put
+	   on flush_queue */
+	int num_queued;
+#endif
+	/* number of threads who wait for this atom to complete commit */
+	int nr_waiters;
+	/* number of threads which do jnode_flush() over this atom */
+	int nr_flushers;
+	/* number of flush queues which are IN_USE and jnodes from fq->prepped
+	   are submitted to disk by the write_fq() routine. */
+	int nr_running_queues;
+	/* A counter of grabbed unformatted nodes, see a description of the
+	 * reiser4 space reservation scheme at block_alloc.c */
+	reiser4_block_nr flush_reserved;
+#if REISER4_DEBUG
+	void *committer;
+#endif
+	struct super_block *super;
+};
+
+#define ATOM_DIRTY_LIST(atom, level) (&(atom)->dirty_nodes[level])
+#define ATOM_CLEAN_LIST(atom) (&(atom)->clean_nodes)
+#define ATOM_OVRWR_LIST(atom) (&(atom)->ovrwr_nodes)
+#define ATOM_WB_LIST(atom) (&(atom)->writeback_nodes)
+#define ATOM_FQ_LIST(fq) (&(fq)->prepped)
+
+#define NODE_LIST(node) (node)->list
+#define ASSIGN_NODE_LIST(node, list) ON_DEBUG(NODE_LIST(node) = list)
+ON_DEBUG(void
+	 count_jnode(txn_atom *, jnode *, atom_list old_list,
+		     atom_list new_list, int check_lists));
+
+typedef struct protected_jnodes {
+	struct list_head inatom; /* link to atom's list these structures */
+	struct list_head nodes; /* head of list of protected nodes */
+} protected_jnodes;
+
+/* A transaction handle: the client obtains and commits this handle which is assigned by
+   the system to a txn_atom. */
+struct txn_handle {
+	/* Spinlock protecting ->atom pointer */
+	spinlock_t hlock;
+
+	/* Flags for controlling commit_txnh() behavior */
+	/* from txn_handle_flags_t */
+	txn_handle_flags_t flags;
+
+	/* Whether it is READ_FUSING or WRITE_FUSING. */
+	txn_mode mode;
+
+	/* If assigned, the atom it is part of. */
+	txn_atom *atom;
+
+	/* Transaction list link. Head is in txn_atom. */
+	struct list_head txnh_link;
+};
+
+/* The transaction manager: one is contained in the reiser4_super_info_data */
+struct txn_mgr {
+	/* A spinlock protecting the atom list, id_count, flush_control */
+	spinlock_t tmgr_lock;
+
+	/* List of atoms. */
+	struct list_head atoms_list;
+
+	/* Number of atoms. */
+	int atom_count;
+
+	/* A counter used to assign atom->atom_id values. */
+	__u32 id_count;
+
+	/* a semaphore object for commit serialization */
+	struct semaphore commit_semaphore;
+
+	/* a list of all txnmrgs served by particular daemon. */
+	struct list_head linkage;
+
+	/* description of daemon for this txnmgr */
+	ktxnmgrd_context *daemon;
+
+	/* parameters. Adjustable through mount options. */
+	unsigned int atom_max_size;
+	unsigned int atom_max_age;
+	unsigned int atom_min_size;
+	/* max number of concurrent flushers for one atom, 0 - unlimited.  */
+	unsigned int atom_max_flushers;
+};
+
+/* FUNCTION DECLARATIONS */
+
+extern int is_cced(const jnode *node);
+
+/* These are the externally (within Reiser4) visible transaction functions, therefore they
+   are prefixed with "txn_".  For comments, see txnmgr.c. */
+
+extern int init_txnmgr_static(void);
+extern void done_txnmgr_static(void);
+
+extern void init_txnmgr(txn_mgr *);
+extern void done_txnmgr(txn_mgr *);
+
+extern int txn_reserve(int reserved);
+
+extern void txn_begin(reiser4_context * context);
+extern int txn_end(reiser4_context * context);
+
+extern void txn_restart(reiser4_context * context);
+extern void txn_restart_current(void);
+
+extern int txnmgr_force_commit_all(struct super_block *, int);
+extern int current_atom_should_commit(void);
+
+extern jnode *find_first_dirty_jnode(txn_atom *, int);
+
+extern int commit_some_atoms(txn_mgr *);
+extern int force_commit_atom(txn_handle *);
+extern int flush_current_atom(int, long, long *, txn_atom **, jnode *);
+
+extern int flush_some_atom(jnode *, long *, const struct writeback_control *, int);
+
+extern void atom_set_stage(txn_atom * atom, txn_stage stage);
+
+extern int same_slum_check(jnode * base, jnode * check, int alloc_check,
+			   int alloc_value);
+extern void atom_dec_and_unlock(txn_atom * atom);
+
+extern int try_capture(jnode * node, znode_lock_mode mode, txn_capture flags,
+		       int can_coc);
+extern int try_capture_page_to_invalidate(struct page *pg);
+
+extern void uncapture_page(struct page *pg);
+extern void uncapture_block(jnode *);
+extern void uncapture_jnode(jnode *);
+
+extern int capture_inode(struct inode *);
+extern int uncapture_inode(struct inode *);
+
+extern txn_atom *get_current_atom_locked_nocheck(void);
+
+#if REISER4_DEBUG
+
+/**
+ * atom_is_protected - make sure that nobody but us can do anything with atom
+ * @atom: atom to be checked
+ *
+ * This is used to assert that atom either entered commit stages or is spin
+ * locked.
+ */
+static inline int atom_is_protected(txn_atom *atom)
+{
+	if (atom->stage >= ASTAGE_PRE_COMMIT)
+		return 1;
+	assert_spin_locked(&(atom->alock));
+	return 1;
+}
+
+#endif
+
+/* Get the current atom and spinlock it if current atom present. May not return NULL */
+static inline txn_atom *get_current_atom_locked(void)
+{
+	txn_atom *atom;
+
+	atom = get_current_atom_locked_nocheck();
+	assert("zam-761", atom != NULL);
+
+	return atom;
+}
+
+extern txn_atom *jnode_get_atom(jnode *);
+
+extern void atom_wait_event(txn_atom *);
+extern void atom_send_event(txn_atom *);
+
+extern void insert_into_atom_ovrwr_list(txn_atom * atom, jnode * node);
+extern int capture_super_block(struct super_block *s);
+
+/* See the comment on the function blocknrset.c:blocknr_set_add for the
+   calling convention of these three routines. */
+extern void blocknr_set_init(blocknr_set * bset);
+extern void blocknr_set_destroy(blocknr_set * bset);
+extern void blocknr_set_merge(blocknr_set * from, blocknr_set * into);
+extern int blocknr_set_add_extent(txn_atom * atom,
+				  blocknr_set * bset,
+				  blocknr_set_entry ** new_bsep,
+				  const reiser4_block_nr * start,
+				  const reiser4_block_nr * len);
+extern int blocknr_set_add_pair(txn_atom * atom, blocknr_set * bset,
+				blocknr_set_entry ** new_bsep,
+				const reiser4_block_nr * a,
+				const reiser4_block_nr * b);
+
+typedef int (*blocknr_set_actor_f) (txn_atom *, const reiser4_block_nr *,
+				    const reiser4_block_nr *, void *);
+
+extern int blocknr_set_iterator(txn_atom * atom, blocknr_set * bset,
+				blocknr_set_actor_f actor, void *data,
+				int delete);
+
+/* flush code takes care about how to fuse flush queues */
+extern void flush_init_atom(txn_atom * atom);
+extern void flush_fuse_queues(txn_atom * large, txn_atom * small);
+
+static inline void spin_lock_atom(txn_atom *atom)
+{
+	/* check that spinlocks of lower priorities are not held */
+	assert("", (LOCK_CNT_NIL(spin_locked_txnh) &&
+		    LOCK_CNT_NIL(spin_locked_jnode) &&
+		    LOCK_CNT_NIL(spin_locked_zlock) &&
+		    LOCK_CNT_NIL(rw_locked_dk) &&
+		    LOCK_CNT_NIL(rw_locked_tree)));
+
+	spin_lock(&(atom->alock));
+
+	LOCK_CNT_INC(spin_locked_atom);
+	LOCK_CNT_INC(spin_locked);
+}
+
+static inline int spin_trylock_atom(txn_atom *atom)
+{
+	if (spin_trylock(&(atom->alock))) {
+		LOCK_CNT_INC(spin_locked_atom);
+		LOCK_CNT_INC(spin_locked);
+		return 1;
+	}
+	return 0;
+}
+
+static inline void spin_unlock_atom(txn_atom *atom)
+{
+	assert_spin_locked(&(atom->alock));
+	assert("nikita-1375", LOCK_CNT_GTZ(spin_locked_atom));
+	assert("nikita-1376", LOCK_CNT_GTZ(spin_locked));
+
+	LOCK_CNT_DEC(spin_locked_atom);
+	LOCK_CNT_DEC(spin_locked);
+
+	spin_unlock(&(atom->alock));
+}
+
+static inline void spin_lock_txnh(txn_handle *txnh)
+{
+	/* check that spinlocks of lower priorities are not held */
+	assert("", (LOCK_CNT_NIL(rw_locked_dk) &&
+		    LOCK_CNT_NIL(spin_locked_zlock) &&
+		    LOCK_CNT_NIL(rw_locked_tree)));
+
+	spin_lock(&(txnh->hlock));
+
+	LOCK_CNT_INC(spin_locked_txnh);
+	LOCK_CNT_INC(spin_locked);
+}
+
+static inline int spin_trylock_txnh(txn_handle *txnh)
+{
+	if (spin_trylock(&(txnh->hlock))) {
+		LOCK_CNT_INC(spin_locked_txnh);
+		LOCK_CNT_INC(spin_locked);
+		return 1;
+	}
+	return 0;
+}
+
+static inline void spin_unlock_txnh(txn_handle *txnh)
+{
+	assert_spin_locked(&(txnh->hlock));
+	assert("nikita-1375", LOCK_CNT_GTZ(spin_locked_txnh));
+	assert("nikita-1376", LOCK_CNT_GTZ(spin_locked));
+
+	LOCK_CNT_DEC(spin_locked_txnh);
+	LOCK_CNT_DEC(spin_locked);
+
+	spin_unlock(&(txnh->hlock));
+}
+
+#define spin_ordering_pred_txnmgr(tmgr)		\
+	( LOCK_CNT_NIL(spin_locked_atom) &&	\
+	  LOCK_CNT_NIL(spin_locked_txnh) &&	\
+	  LOCK_CNT_NIL(spin_locked_jnode) &&	\
+	  LOCK_CNT_NIL(rw_locked_zlock) &&	\
+	  LOCK_CNT_NIL(rw_locked_dk) &&		\
+	  LOCK_CNT_NIL(rw_locked_tree) )
+
+static inline void spin_lock_txnmgr(txn_mgr *mgr)
+{
+	/* check that spinlocks of lower priorities are not held */
+	assert("", (LOCK_CNT_NIL(spin_locked_atom) &&
+		    LOCK_CNT_NIL(spin_locked_txnh) &&
+		    LOCK_CNT_NIL(spin_locked_jnode) &&
+		    LOCK_CNT_NIL(spin_locked_zlock) &&
+		    LOCK_CNT_NIL(rw_locked_dk) &&
+		    LOCK_CNT_NIL(rw_locked_tree)));
+
+	spin_lock(&(mgr->tmgr_lock));
+
+	LOCK_CNT_INC(spin_locked_txnmgr);
+	LOCK_CNT_INC(spin_locked);
+}
+
+static inline int spin_trylock_txnmgr(txn_mgr *mgr)
+{
+	if (spin_trylock(&(mgr->tmgr_lock))) {
+		LOCK_CNT_INC(spin_locked_txnmgr);
+		LOCK_CNT_INC(spin_locked);
+		return 1;
+	}
+	return 0;
+}
+
+static inline void spin_unlock_txnmgr(txn_mgr *mgr)
+{
+	assert_spin_locked(&(mgr->tmgr_lock));
+	assert("nikita-1375", LOCK_CNT_GTZ(spin_locked_txnmgr));
+	assert("nikita-1376", LOCK_CNT_GTZ(spin_locked));
+
+	LOCK_CNT_DEC(spin_locked_txnmgr);
+	LOCK_CNT_DEC(spin_locked);
+
+	spin_unlock(&(mgr->tmgr_lock));
+}
+
+typedef enum {
+	FQ_IN_USE = 0x1
+} flush_queue_state_t;
+
+typedef struct flush_queue flush_queue_t;
+
+/* This is an accumulator for jnodes prepared for writing to disk. A flush queue
+   is filled by the jnode_flush() routine, and written to disk under memory
+   pressure or at atom commit time. */
+/* LOCKING: fq state and fq->atom are protected by guard spinlock, fq->nr_queued
+   field and fq->prepped list can be modified if atom is spin-locked and fq
+   object is "in-use" state.  For read-only traversal of the fq->prepped list
+   and reading of the fq->nr_queued field it is enough to keep fq "in-use" or
+   only have atom spin-locked. */
+struct flush_queue {
+	/* linkage element is the first in this structure to make debugging
+	   easier.  See field in atom struct for description of list. */
+	struct list_head alink;
+	/* A spinlock to protect changes of fq state and fq->atom pointer */
+	spinlock_t guard;
+	/* flush_queue state: [in_use | ready] */
+	flush_queue_state_t state;
+	/* A list which contains queued nodes, queued nodes are removed from any
+	 * atom's list and put on this ->prepped one. */
+	struct list_head prepped;
+	/* number of submitted i/o requests */
+	atomic_t nr_submitted;
+	/* number of i/o errors */
+	atomic_t nr_errors;
+	/* An atom this flush queue is attached to */
+	txn_atom *atom;
+	/* A semaphore for waiting on i/o completion */
+	struct semaphore io_sem;
+#if REISER4_DEBUG
+	/* A thread which took this fq in exclusive use, NULL if fq is free,
+	 * used for debugging. */
+	struct task_struct *owner;
+#endif
+};
+
+extern int fq_by_atom(txn_atom *, flush_queue_t **);
+extern int fq_by_jnode_gfp(jnode *, flush_queue_t **, int);
+extern void fq_put_nolock(flush_queue_t *);
+extern void fq_put(flush_queue_t *);
+extern void fuse_fq(txn_atom * to, txn_atom * from);
+extern void queue_jnode(flush_queue_t *, jnode *);
+extern void mark_jnode_queued(flush_queue_t *, jnode *);
+
+extern int write_fq(flush_queue_t *, long *, int);
+extern int current_atom_finish_all_fq(void);
+extern void init_atom_fq_parts(txn_atom *);
+
+extern reiser4_block_nr txnmgr_count_deleted_blocks(void);
+
+extern void znode_make_dirty(znode * node);
+extern void jnode_make_dirty_locked(jnode * node);
+
+extern int sync_atom(txn_atom * atom);
+
+#if REISER4_DEBUG
+extern int atom_fq_parts_are_clean(txn_atom *);
+#endif
+
+extern void add_fq_to_bio(flush_queue_t *, struct bio *);
+extern flush_queue_t *get_fq_for_current_atom(void);
+
+void protected_jnodes_init(protected_jnodes * list);
+void protected_jnodes_done(protected_jnodes * list);
+void invalidate_list(struct list_head * head);
+
+#if REISER4_DEBUG
+void info_atom(const char *prefix, const txn_atom * atom);
+#else
+#define info_atom(p,a) noop
+#endif
+
+# endif				/* __REISER4_TXNMGR_H__ */
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/type_safe_hash.h newtree/fs/reiser4/type_safe_hash.h
--- oldtree/fs/reiser4/type_safe_hash.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/type_safe_hash.h	2006-02-21 15:58:34.124958776 +0000
@@ -0,0 +1,320 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* A hash table class that uses hash chains (singly-linked) and is
+   parametrized to provide type safety.  */
+
+#ifndef __REISER4_TYPE_SAFE_HASH_H__
+#define __REISER4_TYPE_SAFE_HASH_H__
+
+#include "debug.h"
+
+#include <asm/errno.h>
+/* Step 1: Use TYPE_SAFE_HASH_DECLARE() to define the TABLE and LINK objects
+   based on the object type.  You need to declare the item type before
+   this definition, define it after this definition. */
+#define TYPE_SAFE_HASH_DECLARE(PREFIX,ITEM_TYPE)                                                     \
+                                                                                              \
+typedef struct PREFIX##_hash_table_  PREFIX##_hash_table;                                     \
+typedef struct PREFIX##_hash_link_   PREFIX##_hash_link;                                      \
+                                                                                              \
+struct PREFIX##_hash_table_                                                                   \
+{                                                                                             \
+  ITEM_TYPE  **_table;                                                                        \
+  __u32        _buckets;                                                                      \
+};                                                                                            \
+                                                                                              \
+struct PREFIX##_hash_link_                                                                    \
+{                                                                                             \
+  ITEM_TYPE *_next;                                                                           \
+}
+
+/* Step 2: Define the object type of the hash: give it field of type
+   PREFIX_hash_link. */
+
+/* Step 3: Use TYPE_SAFE_HASH_DEFINE to define the hash table interface using
+   the type and field name used in step 3.  The arguments are:
+
+   ITEM_TYPE    The item type being hashed
+   KEY_TYPE     The type of key being hashed
+   KEY_NAME     The name of the key field within the item
+   LINK_NAME    The name of the link field within the item, which you must make type PREFIX_hash_link)
+   HASH_FUNC    The name of the hash function (or macro, takes const pointer to key)
+   EQ_FUNC      The name of the equality function (or macro, takes const pointer to two keys)
+
+   It implements these functions:
+
+   prefix_hash_init           Initialize the table given its size.
+   prefix_hash_insert         Insert an item
+   prefix_hash_insert_index   Insert an item w/ precomputed hash_index
+   prefix_hash_find           Find an item by key
+   prefix_hash_find_index     Find an item w/ precomputed hash_index
+   prefix_hash_remove         Remove an item, returns 1 if found, 0 if not found
+   prefix_hash_remove_index   Remove an item w/ precomputed hash_index
+
+   If you'd like something to be done differently, feel free to ask me
+   for modifications.  Additional features that could be added but
+   have not been:
+
+   prefix_hash_remove_key           Find and remove an item by key
+   prefix_hash_remove_key_index     Find and remove an item by key w/ precomputed hash_index
+
+   The hash_function currently receives only the key as an argument,
+   meaning it must somehow know the number of buckets.  If this is a
+   problem let me know.
+
+   This hash table uses a single-linked hash chain.  This means
+   insertion is fast but deletion requires searching the chain.
+
+   There is also the doubly-linked hash chain approach, under which
+   deletion requires no search but the code is longer and it takes two
+   pointers per item.
+
+   The circularly-linked approach has the shortest code but requires
+   two pointers per bucket, doubling the size of the bucket array (in
+   addition to two pointers per item).
+*/
+#define TYPE_SAFE_HASH_DEFINE(PREFIX,ITEM_TYPE,KEY_TYPE,KEY_NAME,LINK_NAME,HASH_FUNC,EQ_FUNC)	\
+											\
+static __inline__ void									\
+PREFIX##_check_hash (PREFIX##_hash_table *table UNUSED_ARG,				\
+		     __u32                hash UNUSED_ARG)				\
+{											\
+	assert("nikita-2780", hash < table->_buckets);					\
+}											\
+											\
+static __inline__ int									\
+PREFIX##_hash_init (PREFIX##_hash_table *hash,						\
+		    __u32                buckets)					\
+{											\
+  hash->_table   = (ITEM_TYPE**) KMALLOC (sizeof (ITEM_TYPE*) * buckets);		\
+  hash->_buckets = buckets;								\
+  if (hash->_table == NULL)								\
+    {											\
+      return RETERR(-ENOMEM);								\
+    }											\
+  memset (hash->_table, 0, sizeof (ITEM_TYPE*) * buckets);				\
+  ON_DEBUG(printk(#PREFIX "_hash_table: %i buckets\n", buckets));			\
+  return 0;										\
+}											\
+											\
+static __inline__ void									\
+PREFIX##_hash_done (PREFIX##_hash_table *hash)						\
+{											\
+  if (REISER4_DEBUG && hash->_table != NULL) {                                          \
+	    __u32 i;                                                                    \
+	    for (i = 0 ; i < hash->_buckets ; ++ i)                                     \
+		    assert("nikita-2905", hash->_table[i] == NULL);                     \
+  }                                                                                     \
+  if (hash->_table != NULL)								\
+    KFREE (hash->_table, sizeof (ITEM_TYPE*) * hash->_buckets);				\
+  hash->_table = NULL;									\
+}											\
+											\
+static __inline__ void									\
+PREFIX##_hash_prefetch_next (ITEM_TYPE *item)						\
+{											\
+	prefetch(item->LINK_NAME._next);						\
+}											\
+											\
+static __inline__ void									\
+PREFIX##_hash_prefetch_bucket (PREFIX##_hash_table *hash,				\
+			       __u32                index)				\
+{											\
+	prefetch(hash->_table[index]);  						\
+}											\
+											\
+static __inline__ ITEM_TYPE*								\
+PREFIX##_hash_find_index (PREFIX##_hash_table *hash,					\
+			  __u32                hash_index,				\
+			  KEY_TYPE const      *find_key)				\
+{											\
+  ITEM_TYPE *item;									\
+											\
+  PREFIX##_check_hash(hash, hash_index);						\
+											\
+  for (item  = hash->_table[hash_index];						\
+       item != NULL;									\
+       item  = item->LINK_NAME._next)							\
+    {											\
+      prefetch(item->LINK_NAME._next);							\
+      prefetch(item->LINK_NAME._next + offsetof(ITEM_TYPE, KEY_NAME));			\
+      if (EQ_FUNC (& item->KEY_NAME, find_key))						\
+        {										\
+          return item;									\
+        }										\
+    }											\
+											\
+  return NULL;										\
+}											\
+											\
+static __inline__ ITEM_TYPE*								\
+PREFIX##_hash_find_index_lru (PREFIX##_hash_table *hash,				\
+			      __u32                hash_index,				\
+			      KEY_TYPE const      *find_key)				\
+{											\
+  ITEM_TYPE ** item = &hash->_table[hash_index];                                        \
+											\
+  PREFIX##_check_hash(hash, hash_index);						\
+                                                                                        \
+  while (*item != NULL) {                                                               \
+    prefetch(&(*item)->LINK_NAME._next);						\
+    if (EQ_FUNC (&(*item)->KEY_NAME, find_key)) {                                       \
+      ITEM_TYPE *found; 								\
+											\
+      found = *item;    								\
+      *item = found->LINK_NAME._next;                                                   \
+      found->LINK_NAME._next = hash->_table[hash_index];				\
+      hash->_table[hash_index] = found;							\
+      return found;                                                                     \
+    }                                                                                   \
+    item = &(*item)->LINK_NAME._next;                                                   \
+  }											\
+  return NULL;										\
+}											\
+											\
+static __inline__ int									\
+PREFIX##_hash_remove_index (PREFIX##_hash_table *hash,					\
+			    __u32                hash_index,				\
+			    ITEM_TYPE           *del_item)				\
+{											\
+  ITEM_TYPE ** hash_item_p = &hash->_table[hash_index];                                 \
+											\
+  PREFIX##_check_hash(hash, hash_index);						\
+                                                                                        \
+  while (*hash_item_p != NULL) {                                                        \
+    prefetch(&(*hash_item_p)->LINK_NAME._next);						\
+    if (*hash_item_p == del_item) {                                                     \
+      *hash_item_p = (*hash_item_p)->LINK_NAME._next;                                   \
+      return 1;                                                                         \
+    }                                                                                   \
+    hash_item_p = &(*hash_item_p)->LINK_NAME._next;                                     \
+  }											\
+  return 0;										\
+}											\
+											\
+static __inline__ void									\
+PREFIX##_hash_insert_index (PREFIX##_hash_table *hash,					\
+			    __u32                hash_index,				\
+			    ITEM_TYPE           *ins_item)				\
+{											\
+  PREFIX##_check_hash(hash, hash_index);						\
+											\
+  ins_item->LINK_NAME._next = hash->_table[hash_index];					\
+  hash->_table[hash_index]  = ins_item;							\
+}											\
+											\
+static __inline__ void									\
+PREFIX##_hash_insert_index_rcu (PREFIX##_hash_table *hash,				\
+			        __u32                hash_index,			\
+			        ITEM_TYPE           *ins_item)				\
+{											\
+  PREFIX##_check_hash(hash, hash_index);						\
+											\
+  ins_item->LINK_NAME._next = hash->_table[hash_index];					\
+  smp_wmb();    									\
+  hash->_table[hash_index]  = ins_item;							\
+}											\
+											\
+static __inline__ ITEM_TYPE*								\
+PREFIX##_hash_find (PREFIX##_hash_table *hash,						\
+	            KEY_TYPE const      *find_key)					\
+{											\
+  return PREFIX##_hash_find_index (hash, HASH_FUNC(hash, find_key), find_key);		\
+}											\
+											\
+static __inline__ ITEM_TYPE*								\
+PREFIX##_hash_find_lru (PREFIX##_hash_table *hash,					\
+	                KEY_TYPE const      *find_key)					\
+{											\
+  return PREFIX##_hash_find_index_lru (hash, HASH_FUNC(hash, find_key), find_key);	\
+}											\
+											\
+static __inline__ int									\
+PREFIX##_hash_remove (PREFIX##_hash_table *hash,					\
+		      ITEM_TYPE           *del_item)					\
+{											\
+  return PREFIX##_hash_remove_index (hash,      					\
+                                     HASH_FUNC(hash, &del_item->KEY_NAME), del_item);	\
+}											\
+											\
+static __inline__ int									\
+PREFIX##_hash_remove_rcu (PREFIX##_hash_table *hash,					\
+		      ITEM_TYPE           *del_item)					\
+{											\
+  return PREFIX##_hash_remove (hash, del_item);						\
+}											\
+											\
+static __inline__ void									\
+PREFIX##_hash_insert (PREFIX##_hash_table *hash,					\
+		      ITEM_TYPE           *ins_item)					\
+{											\
+  return PREFIX##_hash_insert_index (hash,      					\
+                                     HASH_FUNC(hash, &ins_item->KEY_NAME), ins_item);	\
+}											\
+											\
+static __inline__ void									\
+PREFIX##_hash_insert_rcu (PREFIX##_hash_table *hash,					\
+		          ITEM_TYPE           *ins_item)				\
+{											\
+  return PREFIX##_hash_insert_index_rcu (hash, HASH_FUNC(hash, &ins_item->KEY_NAME),   	\
+                                         ins_item);     				\
+}											\
+											\
+static __inline__ ITEM_TYPE *								\
+PREFIX##_hash_first (PREFIX##_hash_table *hash, __u32 ind)				\
+{											\
+  ITEM_TYPE *first;									\
+											\
+  for (first = NULL; ind < hash->_buckets; ++ ind) {					\
+    first = hash->_table[ind];  							\
+    if (first != NULL)									\
+      break;										\
+  }											\
+  return first;										\
+}											\
+											\
+static __inline__ ITEM_TYPE *								\
+PREFIX##_hash_next (PREFIX##_hash_table *hash,						\
+		    ITEM_TYPE           *item)						\
+{											\
+  ITEM_TYPE  *next;									\
+											\
+  if (item == NULL)									\
+    return NULL;									\
+  next = item->LINK_NAME._next;								\
+  if (next == NULL)									\
+    next = PREFIX##_hash_first (hash, HASH_FUNC(hash, &item->KEY_NAME) + 1);		\
+  return next;										\
+}											\
+											\
+typedef struct {} PREFIX##_hash_dummy
+
+#define for_all_ht_buckets(table, head)					\
+for ((head) = &(table) -> _table[ 0 ] ;					\
+     (head) != &(table) -> _table[ (table) -> _buckets ] ; ++ (head))
+
+#define for_all_in_bucket(bucket, item, next, field)				\
+for ((item) = *(bucket), (next) = (item) ? (item) -> field._next : NULL ;	\
+     (item) != NULL ;								\
+     (item) = (next), (next) = (item) ? (item) -> field._next : NULL )
+
+#define for_all_in_htable(table, prefix, item, next)	\
+for ((item) = prefix ## _hash_first ((table), 0), 	\
+     (next) = prefix ## _hash_next ((table), (item)) ;	\
+     (item) != NULL ;					\
+     (item) = (next), 					\
+     (next) = prefix ## _hash_next ((table), (item)))
+
+/* __REISER4_TYPE_SAFE_HASH_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/vfs_ops.c newtree/fs/reiser4/vfs_ops.c
--- oldtree/fs/reiser4/vfs_ops.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/vfs_ops.c	2006-02-21 15:58:35.028821368 +0000
@@ -0,0 +1,268 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Interface to VFS. Reiser4 {super|export|dentry}_operations are defined
+   here. */
+
+#include "forward.h"
+#include "debug.h"
+#include "dformat.h"
+#include "coord.h"
+#include "plugin/item/item.h"
+#include "plugin/file/file.h"
+#include "plugin/security/perm.h"
+#include "plugin/disk_format/disk_format.h"
+#include "plugin/plugin.h"
+#include "plugin/plugin_set.h"
+#include "plugin/object.h"
+#include "txnmgr.h"
+#include "jnode.h"
+#include "znode.h"
+#include "block_alloc.h"
+#include "tree.h"
+#include "vfs_ops.h"
+#include "inode.h"
+#include "page_cache.h"
+#include "ktxnmgrd.h"
+#include "super.h"
+#include "reiser4.h"
+#include "entd.h"
+#include "emergency_flush.h"
+#include "status_flags.h"
+#include "flush.h"
+#include "dscale.h"
+
+#include <linux/profile.h>
+#include <linux/types.h>
+#include <linux/mount.h>
+#include <linux/vfs.h>
+#include <linux/mm.h>
+#include <linux/buffer_head.h>
+#include <linux/dcache.h>
+#include <linux/list.h>
+#include <linux/pagemap.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/writeback.h>
+#include <linux/blkdev.h>
+#include <linux/quotaops.h>
+#include <linux/security.h>
+#include <linux/reboot.h>
+#include <linux/rcupdate.h>
+
+
+/* update inode stat-data by calling plugin */
+int reiser4_update_sd(struct inode *object)
+{
+	file_plugin *fplug;
+
+	assert("nikita-2338", object != NULL);
+	/* check for read-only file system. */
+	if (IS_RDONLY(object))
+		return 0;
+
+	fplug = inode_file_plugin(object);
+	assert("nikita-2339", fplug != NULL);
+	return fplug->write_sd_by_inode(object);
+}
+
+/* helper function: increase inode nlink count and call plugin method to save
+   updated stat-data.
+
+   Used by link/create and during creation of dot and dotdot in mkdir
+*/
+int reiser4_add_nlink(struct inode *object /* object to which link is added */ ,
+		      struct inode *parent /* parent where new entry will be */
+		      ,
+		      int write_sd_p	/* true if stat-data has to be
+					 * updated */ )
+{
+	file_plugin *fplug;
+	int result;
+
+	assert("nikita-1351", object != NULL);
+
+	fplug = inode_file_plugin(object);
+	assert("nikita-1445", fplug != NULL);
+
+	/* ask plugin whether it can add yet another link to this
+	   object */
+	if (!fplug->can_add_link(object))
+		return RETERR(-EMLINK);
+
+	assert("nikita-2211", fplug->add_link != NULL);
+	/* call plugin to do actual addition of link */
+	result = fplug->add_link(object, parent);
+
+	/* optionally update stat data */
+	if (result == 0 && write_sd_p)
+		result = fplug->write_sd_by_inode(object);
+	return result;
+}
+
+/* helper function: decrease inode nlink count and call plugin method to save
+   updated stat-data.
+
+   Used by unlink/create
+*/
+int reiser4_del_nlink(struct inode *object	/* object from which link is
+						 * removed */ ,
+		      struct inode *parent /* parent where entry was */ ,
+		      int write_sd_p	/* true is stat-data has to be
+					 * updated */ )
+{
+	file_plugin *fplug;
+	int result;
+
+	assert("nikita-1349", object != NULL);
+
+	fplug = inode_file_plugin(object);
+	assert("nikita-1350", fplug != NULL);
+	assert("nikita-1446", object->i_nlink > 0);
+	assert("nikita-2210", fplug->rem_link != NULL);
+
+	/* call plugin to do actual deletion of link */
+	result = fplug->rem_link(object, parent);
+
+	/* optionally update stat data */
+	if (result == 0 && write_sd_p)
+		result = fplug->write_sd_by_inode(object);
+	return result;
+}
+
+
+
+
+/* Release reiser4 dentry. This is d_op->d_release() method. */
+static void reiser4_d_release(struct dentry *dentry /* dentry released */ )
+{
+	reiser4_free_dentry_fsdata(dentry);
+}
+
+/*
+ * Called by reiser4_sync_inodes(), during speculative write-back (through
+ * pdflush, or balance_dirty_pages()).
+ */
+void writeout(struct super_block *sb, struct writeback_control *wbc)
+{
+	long written = 0;
+	int repeats = 0;
+	int result;
+	struct address_space *mapping;
+
+	/*
+	 * Performs early flushing, trying to free some memory. If there is
+	 * nothing to flush, commits some atoms.
+	 */
+
+	/* Commit all atoms if reiser4_writepages() is called from sys_sync() or
+	   sys_fsync(). */
+	if (wbc->sync_mode != WB_SYNC_NONE) {
+		txnmgr_force_commit_all(sb, 1);
+		return;
+	}
+
+	BUG_ON(get_super_fake(sb) == NULL);
+	mapping = get_super_fake(sb)->i_mapping;
+	do {
+		long nr_submitted = 0;
+		jnode *node = NULL;
+
+		/* do not put more requests to overload write queue */
+		if (wbc->nonblocking &&
+		    bdi_write_congested(mapping->backing_dev_info)) {
+			blk_run_address_space(mapping);
+			wbc->encountered_congestion = 1;
+			break;
+		}
+		repeats++;
+		BUG_ON(wbc->nr_to_write <= 0);
+
+		if (get_current_context()->entd) {
+			entd_context *ent = get_entd_context(sb);
+
+			if (ent->cur_request->node)
+				/*
+				 * this is ent thread and it managed to capture
+				 * requested page itself - start flush from
+				 * that page
+				 */
+				node = jref(ent->cur_request->node);
+		}
+
+		result = flush_some_atom(node, &nr_submitted, wbc,
+					 JNODE_FLUSH_WRITE_BLOCKS);
+		if (result != 0)
+			warning("nikita-31001", "Flush failed: %i", result);
+		if (node)
+			jput(node);
+		if (!nr_submitted)
+			break;
+
+		wbc->nr_to_write -= nr_submitted;
+		written += nr_submitted;
+	} while (wbc->nr_to_write > 0);
+}
+
+
+void reiser4_throttle_write(struct inode *inode)
+{
+	txn_restart_current();
+	balance_dirty_pages_ratelimited(inode->i_mapping);
+}
+
+const char *REISER4_SUPER_MAGIC_STRING = "ReIsEr4";
+const int REISER4_MAGIC_OFFSET = 16 * 4096;	/* offset to magic string from the
+						 * beginning of device */
+
+
+
+/*
+ * Reiser4 initialization/shutdown.
+ *
+ * Code below performs global reiser4 initialization that is done either as
+ * part of kernel initialization (when reiser4 is statically built-in), or
+ * during reiser4 module load (when compiled as module).
+ */
+
+
+void reiser4_handle_error(void)
+{
+	struct super_block *sb = reiser4_get_current_sb();
+
+	if (!sb)
+		return;
+	reiser4_status_write(REISER4_STATUS_DAMAGED, 0,
+			     "Filesystem error occured");
+	switch (get_super_private(sb)->onerror) {
+	case 0:
+		reiser4_panic("foobar-42", "Filesystem error occured\n");
+	case 1:
+	default:
+		if (sb->s_flags & MS_RDONLY)
+			return;
+		sb->s_flags |= MS_RDONLY;
+		break;
+	}
+}
+
+struct dentry_operations reiser4_dentry_operations = {
+	.d_revalidate = NULL,
+	.d_hash = NULL,
+	.d_compare = NULL,
+	.d_delete = NULL,
+	.d_release = reiser4_d_release,
+	.d_iput = NULL,
+};
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/vfs_ops.h newtree/fs/reiser4/vfs_ops.h
--- oldtree/fs/reiser4/vfs_ops.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/vfs_ops.h	2006-02-21 15:58:35.457756160 +0000
@@ -0,0 +1,58 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* vfs_ops.c's exported symbols */
+
+#if !defined( __FS_REISER4_VFS_OPS_H__ )
+#define __FS_REISER4_VFS_OPS_H__
+
+#include "forward.h"
+#include "coord.h"
+#include "seal.h"
+#include "plugin/file/file.h"
+#include "super.h"
+#include "readahead.h"
+
+#include <linux/types.h>	/* for loff_t */
+#include <linux/fs.h>		/* for struct address_space */
+#include <linux/dcache.h>	/* for struct dentry */
+#include <linux/mm.h>
+#include <linux/backing-dev.h>
+
+/* address space operations */
+int reiser4_writepage(struct page *, struct writeback_control *);
+int reiser4_set_page_dirty(struct page *);
+int reiser4_readpages(struct file *, struct address_space *,
+		      struct list_head *pages, unsigned nr_pages);
+int reiser4_invalidatepage(struct page *, unsigned long offset);
+int reiser4_releasepage(struct page *, gfp_t);
+
+extern int reiser4_update_sd(struct inode *);
+extern int reiser4_add_nlink(struct inode *, struct inode *, int);
+extern int reiser4_del_nlink(struct inode *, struct inode *, int);
+
+
+extern int reiser4_start_up_io(struct page *page);
+extern void reiser4_throttle_write(struct inode *);
+extern int jnode_is_releasable(jnode *);
+
+#define CAPTURE_APAGE_BURST (1024l)
+void writeout(struct super_block *, struct writeback_control *);
+
+
+extern void reiser4_handle_error(void);
+
+
+/* __FS_REISER4_VFS_OPS_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/wander.c newtree/fs/reiser4/wander.c
--- oldtree/fs/reiser4/wander.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/wander.c	2006-02-21 15:58:35.457756160 +0000
@@ -0,0 +1,1800 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Reiser4 Wandering Log */
+
+/* You should read http://www.namesys.com/txn-doc.html
+
+   That describes how filesystem operations are performed as atomic
+   transactions, and how we try to arrange it so that we can write most of the
+   data only once while performing the operation atomically.
+
+   For the purposes of this code, it is enough for it to understand that it
+   has been told a given block should be written either once, or twice (if
+   twice then once to the wandered location and once to the real location).
+
+   This code guarantees that those blocks that are defined to be part of an
+   atom either all take effect or none of them take effect.
+
+   Relocate set nodes are submitted to write by the jnode_flush() routine, and
+   the overwrite set is submitted by reiser4_write_log().  This is because with
+   the overwrite set we seek to optimize writes, and with the relocate set we
+   seek to cause disk order to correlate with the parent first pre-order.
+
+   reiser4_write_log() allocates and writes wandered blocks and maintains
+   additional on-disk structures of the atom as wander records (each wander
+   record occupies one block) for storing of the "wandered map" (a table which
+   contains a relation between wandered and real block numbers) and other
+   information which might be needed at transaction recovery time.
+
+   The wander records are unidirectionally linked into a circle: each wander
+   record contains a block number of the next wander record, the last wander
+   record points to the first one.
+
+   One wander record (named "tx head" in this file) has a format which is
+   different from the other wander records. The "tx head" has a reference to the
+   "tx head" block of the previously committed atom.  Also, "tx head" contains
+   fs information (the free blocks counter, and the oid allocator state) which
+   is logged in a special way .
+
+   There are two journal control blocks, named journal header and journal
+   footer which have fixed on-disk locations.  The journal header has a
+   reference to the "tx head" block of the last committed atom.  The journal
+   footer points to the "tx head" of the last flushed atom.  The atom is
+   "played" when all blocks from its overwrite set are written to disk the
+   second time (i.e. written to their real locations).
+
+   NOTE: People who know reiserfs internals and its journal structure might be
+   confused with these terms journal footer and journal header. There is a table
+   with terms of similar semantics in reiserfs (reiser3) and reiser4:
+
+   REISER3 TERM        |  REISER4 TERM         | DESCRIPTION
+   --------------------+-----------------------+----------------------------
+   commit record       |  journal header       | atomic write of this record
+                       |                       | ends transaction commit
+   --------------------+-----------------------+----------------------------
+   journal header      |  journal footer       | atomic write of this record
+                       |                       | ends post-commit writes.
+                       |                       | After successful
+                       |                       | writing of this journal
+                       |                       | blocks (in reiser3) or
+                       |                       | wandered blocks/records are
+                       |                       | free for re-use.
+   --------------------+-----------------------+----------------------------
+
+   The atom commit process is the following:
+
+   1. The overwrite set is taken from atom's clean list, and its size is
+      counted.
+
+   2. The number of necessary wander records (including tx head) is calculated,
+      and the wander record blocks are allocated.
+
+   3. Allocate wandered blocks and populate wander records by wandered map.
+
+   4. submit write requests for wander records and wandered blocks.
+
+   5. wait until submitted write requests complete.
+
+   6. update journal header: change the pointer to the block number of just
+   written tx head, submit an i/o for modified journal header block and wait
+   for i/o completion.
+
+   NOTE: The special logging for bitmap blocks and some reiser4 super block
+   fields makes processes of atom commit, flush and recovering a bit more
+   complex (see comments in the source code for details).
+
+   The atom playing process is the following:
+
+   1. Write atom's overwrite set in-place.
+
+   2. Wait on i/o.
+
+   3. Update journal footer: change the pointer to block number of tx head
+   block of the atom we currently flushing, submit an i/o, wait on i/o
+   completion.
+
+   4. Free disk space which was used for wandered blocks and wander records.
+
+   After the freeing of wandered blocks and wander records we have that journal
+   footer points to the on-disk structure which might be overwritten soon.
+   Neither the log writer nor the journal recovery procedure use that pointer
+   for accessing the data.  When the journal recovery procedure finds the oldest
+   transaction it compares the journal footer pointer value with the "prev_tx"
+   pointer value in tx head, if values are equal the oldest not flushed
+   transaction is found.
+
+   NOTE on disk space leakage: the information about of what blocks and how many
+   blocks are allocated for wandered blocks, wandered records is not written to
+   the disk because of special logging for bitmaps and some super blocks
+   counters.  After a system crash we the reiser4 does not remember those
+   objects allocation, thus we have no such a kind of disk space leakage.
+*/
+
+/* Special logging of reiser4 super block fields. */
+
+/* There are some reiser4 super block fields (free block count and OID allocator
+   state (number of files and next free OID) which are logged separately from
+   super block to avoid unnecessary atom fusion.
+
+   So, the reiser4 super block can be not captured by a transaction with
+   allocates/deallocates disk blocks or create/delete file objects.  Moreover,
+   the reiser4 on-disk super block is not touched when such a transaction is
+   committed and flushed.  Those "counters logged specially" are logged in "tx
+   head" blocks and in the journal footer block.
+
+   A step-by-step description of special logging:
+
+   0. The per-atom information about deleted or created files and allocated or
+   freed blocks is collected during the transaction.  The atom's
+   ->nr_objects_created and ->nr_objects_deleted are for object
+   deletion/creation tracking, the numbers of allocated and freed blocks are
+   calculated using atom's delete set and atom's capture list -- all new and
+   relocated nodes should be on atom's clean list and should have JNODE_RELOC
+   bit set.
+
+   1. The "logged specially" reiser4 super block fields have their "committed"
+   versions in the reiser4 in-memory super block.  They get modified only at
+   atom commit time.  The atom's commit thread has an exclusive access to those
+   "committed" fields because the log writer implementation supports only one
+   atom commit a time (there is a per-fs "commit" semaphore).  At
+   that time "committed" counters are modified using per-atom information
+   collected during the transaction. These counters are stored on disk as a
+   part of tx head block when atom is committed.
+
+   2. When the atom is flushed the value of the free block counter and the OID
+   allocator state get written to the journal footer block.  A special journal
+   procedure (journal_recover_sb_data()) takes those values from the journal
+   footer and updates the reiser4 in-memory super block.
+
+   NOTE: That means free block count and OID allocator state are logged
+   separately from the reiser4 super block regardless of the fact that the
+   reiser4 super block has fields to store both the free block counter and the
+   OID allocator.
+
+   Writing the whole super block at commit time requires knowing true values of
+   all its fields without changes made by not yet committed transactions. It is
+   possible by having their "committed" version of the super block like the
+   reiser4 bitmap blocks have "committed" and "working" versions.  However,
+   another scheme was implemented which stores special logged values in the
+   unused free space inside transaction head block.  In my opinion it has an
+   advantage of not writing whole super block when only part of it was
+   modified. */
+
+#include "debug.h"
+#include "dformat.h"
+#include "txnmgr.h"
+#include "jnode.h"
+#include "znode.h"
+#include "block_alloc.h"
+#include "page_cache.h"
+#include "wander.h"
+#include "reiser4.h"
+#include "super.h"
+#include "vfs_ops.h"
+#include "writeout.h"
+#include "inode.h"
+#include "entd.h"
+
+#include <linux/types.h>
+#include <linux/fs.h>		/* for struct super_block  */
+#include <linux/mm.h>		/* for struct page */
+#include <linux/pagemap.h>
+#include <linux/bio.h>		/* for struct bio */
+#include <linux/blkdev.h>
+
+static int write_jnodes_to_disk_extent(
+	jnode *, int, const reiser4_block_nr *, flush_queue_t *, int);
+
+/* The commit_handle is a container for objects needed at atom commit time  */
+struct commit_handle {
+	/* A pointer to atom's list of OVRWR nodes */
+	struct list_head *overwrite_set;
+	/* atom's overwrite set size */
+	int overwrite_set_size;
+	/* jnodes for wander record blocks */
+	struct list_head tx_list;
+	/* number of wander records */
+	__u32 tx_size;
+	/* 'committed' sb counters are saved here until atom is completely
+	   flushed  */
+	__u64 free_blocks;
+	__u64 nr_files;
+	__u64 next_oid;
+	/* A pointer to the atom which is being committed */
+	txn_atom *atom;
+	/* A pointer to current super block */
+	struct super_block *super;
+	/* The counter of modified bitmaps */
+	reiser4_block_nr nr_bitmap;
+};
+
+static void init_commit_handle(struct commit_handle *ch, txn_atom *atom)
+{
+	memset(ch, 0, sizeof(struct commit_handle));
+	INIT_LIST_HEAD(&ch->tx_list);
+
+	ch->atom = atom;
+	ch->super = reiser4_get_current_sb();
+}
+
+static void done_commit_handle(struct commit_handle *ch)
+{
+	assert("zam-690", list_empty(&ch->tx_list));
+}
+
+static inline int reiser4_use_write_barrier(struct super_block * s)
+{
+	return !reiser4_is_set(s, REISER4_NO_WRITE_BARRIER);
+}
+
+static void disable_write_barrier(struct super_block * s)
+{
+	notice("zam-1055", "%s does not support write barriers,"
+	       " using synchronous write instead.\n", s->s_id);
+	set_bit((int)REISER4_NO_WRITE_BARRIER, &get_super_private(s)->fs_flags);
+}
+
+
+/* fill journal header block data  */
+static void format_journal_header(struct commit_handle *ch)
+{
+	struct reiser4_super_info_data *sbinfo;
+	struct journal_header *header;
+	jnode *txhead;
+
+	sbinfo = get_super_private(ch->super);
+	assert("zam-479", sbinfo != NULL);
+	assert("zam-480", sbinfo->journal_header != NULL);
+
+	txhead = list_entry(ch->tx_list.next, jnode, capture_link);
+
+	jload(sbinfo->journal_header);
+
+	header = (struct journal_header *)jdata(sbinfo->journal_header);
+	assert("zam-484", header != NULL);
+
+	put_unaligned(cpu_to_le64(*jnode_get_block(txhead)),
+		      &header->last_committed_tx);
+
+	jrelse(sbinfo->journal_header);
+}
+
+/* fill journal footer block data */
+static void format_journal_footer(struct commit_handle *ch)
+{
+	struct reiser4_super_info_data *sbinfo;
+	struct journal_footer *footer;
+	jnode *tx_head;
+
+	sbinfo = get_super_private(ch->super);
+
+	tx_head = list_entry(ch->tx_list.next, jnode, capture_link);
+
+	assert("zam-493", sbinfo != NULL);
+	assert("zam-494", sbinfo->journal_header != NULL);
+
+	check_me("zam-691", jload(sbinfo->journal_footer) == 0);
+
+	footer = (struct journal_footer *)jdata(sbinfo->journal_footer);
+	assert("zam-495", footer != NULL);
+
+	put_unaligned(cpu_to_le64(*jnode_get_block(tx_head)),
+		      &footer->last_flushed_tx);
+	put_unaligned(cpu_to_le64(ch->free_blocks), &footer->free_blocks);
+
+	put_unaligned(cpu_to_le64(ch->nr_files), &footer->nr_files);
+	put_unaligned(cpu_to_le64(ch->next_oid), &footer->next_oid);
+
+	jrelse(sbinfo->journal_footer);
+}
+
+/* wander record capacity depends on current block size */
+static int wander_record_capacity(const struct super_block *super)
+{
+	return (super->s_blocksize -
+		sizeof(struct wander_record_header)) /
+	    sizeof(struct wander_entry);
+}
+
+/* Fill first wander record (tx head) in accordance with supplied given data */
+static void format_tx_head(struct commit_handle *ch)
+{
+	jnode *tx_head;
+	jnode *next;
+	struct tx_header *header;
+
+	tx_head = list_entry(ch->tx_list.next, jnode, capture_link);
+	assert("zam-692", &ch->tx_list != &tx_head->capture_link);
+
+	next = list_entry(tx_head->capture_link.next, jnode, capture_link);
+	if (&ch->tx_list == &next->capture_link)
+		next = tx_head;
+
+	header = (struct tx_header *)jdata(tx_head);
+
+	assert("zam-460", header != NULL);
+	assert("zam-462", ch->super->s_blocksize >= sizeof(struct tx_header));
+
+	memset(jdata(tx_head), 0, (size_t) ch->super->s_blocksize);
+	memcpy(jdata(tx_head), TX_HEADER_MAGIC, TX_HEADER_MAGIC_SIZE);
+
+	put_unaligned(cpu_to_le32(ch->tx_size), &header->total);
+	put_unaligned(cpu_to_le64(get_super_private(ch->super)->last_committed_tx),
+		      &header->prev_tx);
+	put_unaligned(cpu_to_le64(*jnode_get_block(next)), &header->next_block);
+	put_unaligned(cpu_to_le64(ch->free_blocks), &header->free_blocks);
+	put_unaligned(cpu_to_le64(ch->nr_files), &header->nr_files);
+	put_unaligned(cpu_to_le64(ch->next_oid), &header->next_oid);
+}
+
+/* prepare ordinary wander record block (fill all service fields) */
+static void
+format_wander_record(struct commit_handle *ch, jnode *node, __u32 serial)
+{
+	struct wander_record_header *LRH;
+	jnode *next;
+
+	assert("zam-464", node != NULL);
+
+	LRH = (struct wander_record_header *)jdata(node);
+	next = list_entry(node->capture_link.next, jnode, capture_link);
+
+	if (&ch->tx_list == &next->capture_link)
+		next = list_entry(ch->tx_list.next, jnode, capture_link);
+
+	assert("zam-465", LRH != NULL);
+	assert("zam-463",
+	       ch->super->s_blocksize > sizeof(struct wander_record_header));
+
+	memset(jdata(node), 0, (size_t) ch->super->s_blocksize);
+	memcpy(jdata(node), WANDER_RECORD_MAGIC, WANDER_RECORD_MAGIC_SIZE);
+
+	put_unaligned(cpu_to_le32(ch->tx_size), &LRH->total);
+	put_unaligned(cpu_to_le32(serial), &LRH->serial);
+	put_unaligned(cpu_to_le64(*jnode_get_block(next)), &LRH->next_block);
+}
+
+/* add one wandered map entry to formatted wander record */
+static void
+store_entry(jnode * node, int index, const reiser4_block_nr * a,
+	    const reiser4_block_nr * b)
+{
+	char *data;
+	struct wander_entry *pairs;
+
+	data = jdata(node);
+	assert("zam-451", data != NULL);
+
+	pairs =
+	    (struct wander_entry *)(data + sizeof(struct wander_record_header));
+
+	put_unaligned(cpu_to_le64(*a), &pairs[index].original);
+	put_unaligned(cpu_to_le64(*b), &pairs[index].wandered);
+}
+
+/* currently, wander records contains contain only wandered map, which depend on
+   overwrite set size */
+static void get_tx_size(struct commit_handle *ch)
+{
+	assert("zam-440", ch->overwrite_set_size != 0);
+	assert("zam-695", ch->tx_size == 0);
+
+	/* count all ordinary wander records
+	   (<overwrite_set_size> - 1) / <wander_record_capacity> + 1 and add one
+	   for tx head block */
+	ch->tx_size =
+	    (ch->overwrite_set_size - 1) / wander_record_capacity(ch->super) +
+	    2;
+}
+
+/* A special structure for using in store_wmap_actor() for saving its state
+   between calls */
+struct store_wmap_params {
+	jnode *cur;		/* jnode of current wander record to fill */
+	int idx;		/* free element index in wander record  */
+	int capacity;		/* capacity  */
+
+#if REISER4_DEBUG
+	struct list_head *tx_list;
+#endif
+};
+
+/* an actor for use in blocknr_set_iterator routine which populates the list
+   of pre-formatted wander records by wandered map info */
+static int
+store_wmap_actor(txn_atom * atom UNUSED_ARG, const reiser4_block_nr * a,
+		 const reiser4_block_nr * b, void *data)
+{
+	struct store_wmap_params *params = data;
+
+	if (params->idx >= params->capacity) {
+		/* a new wander record should be taken from the tx_list */
+		params->cur = list_entry(params->cur->capture_link.next, jnode, capture_link);
+		assert("zam-454",
+		       params->tx_list != &params->cur->capture_link);
+
+		params->idx = 0;
+	}
+
+	store_entry(params->cur, params->idx, a, b);
+	params->idx++;
+
+	return 0;
+}
+
+/* This function is called after Relocate set gets written to disk, Overwrite
+   set is written to wandered locations and all wander records are written
+   also. Updated journal header blocks contains a pointer (block number) to
+   first wander record of the just written transaction */
+static int update_journal_header(struct commit_handle *ch, int use_barrier)
+{
+	struct reiser4_super_info_data *sbinfo = get_super_private(ch->super);
+	jnode *jh = sbinfo->journal_header;
+	jnode *head = list_entry(ch->tx_list.next, jnode, capture_link);
+	int ret;
+
+	format_journal_header(ch);
+
+	ret = write_jnodes_to_disk_extent(jh, 1, jnode_get_block(jh), NULL,
+					  use_barrier ? WRITEOUT_BARRIER : 0);
+	if (ret)
+		return ret;
+
+	// blk_run_address_space(sbinfo->fake->i_mapping);
+	/*blk_run_queues(); */
+
+	ret = jwait_io(jh, WRITE);
+
+	if (ret)
+		return ret;
+
+	sbinfo->last_committed_tx = *jnode_get_block(head);
+
+	return 0;
+}
+
+/* This function is called after write-back is finished. We update journal
+   footer block and free blocks which were occupied by wandered blocks and
+   transaction wander records */
+static int update_journal_footer(struct commit_handle *ch, int use_barrier)
+{
+	reiser4_super_info_data *sbinfo = get_super_private(ch->super);
+
+	jnode *jf = sbinfo->journal_footer;
+
+	int ret;
+
+	format_journal_footer(ch);
+
+	ret = write_jnodes_to_disk_extent(jf, 1, jnode_get_block(jf), NULL,
+					  use_barrier ? WRITEOUT_BARRIER : 0);
+	if (ret)
+		return ret;
+
+	// blk_run_address_space(sbinfo->fake->i_mapping);
+	/*blk_run_queue(); */
+
+	ret = jwait_io(jf, WRITE);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/* free block numbers of wander records of already written in place transaction */
+static void dealloc_tx_list(struct commit_handle *ch)
+{
+	while (!list_empty(&ch->tx_list)) {
+		jnode *cur = list_entry(ch->tx_list.next, jnode, capture_link);
+		list_del(&cur->capture_link);
+		ON_DEBUG(INIT_LIST_HEAD(&cur->capture_link));
+		reiser4_dealloc_block(jnode_get_block(cur), BLOCK_NOT_COUNTED,
+				      BA_FORMATTED);
+
+		unpin_jnode_data(cur);
+		drop_io_head(cur);
+	}
+}
+
+/* An actor for use in block_nr_iterator() routine which frees wandered blocks
+   from atom's overwrite set. */
+static int
+dealloc_wmap_actor(txn_atom * atom UNUSED_ARG,
+		   const reiser4_block_nr * a UNUSED_ARG,
+		   const reiser4_block_nr * b, void *data UNUSED_ARG)
+{
+
+	assert("zam-499", b != NULL);
+	assert("zam-500", *b != 0);
+	assert("zam-501", !blocknr_is_fake(b));
+
+	reiser4_dealloc_block(b, BLOCK_NOT_COUNTED, BA_FORMATTED);
+	return 0;
+}
+
+/* free wandered block locations of already written in place transaction */
+static void dealloc_wmap(struct commit_handle *ch)
+{
+	assert("zam-696", ch->atom != NULL);
+
+	blocknr_set_iterator(ch->atom, &ch->atom->wandered_map,
+			     dealloc_wmap_actor, NULL, 1);
+}
+
+/* helper function for alloc wandered blocks, which refill set of block
+   numbers needed for wandered blocks  */
+static int
+get_more_wandered_blocks(int count, reiser4_block_nr * start, int *len)
+{
+	reiser4_blocknr_hint hint;
+	int ret;
+
+	reiser4_block_nr wide_len = count;
+
+	/* FIXME-ZAM: A special policy needed for allocation of wandered blocks
+	   ZAM-FIXME-HANS: yes, what happened to our discussion of using a fixed
+	   reserved allocation area so as to get the best qualities of fixed
+	   journals? */
+	blocknr_hint_init(&hint);
+	hint.block_stage = BLOCK_GRABBED;
+
+	ret = reiser4_alloc_blocks(&hint, start, &wide_len,
+				   BA_FORMATTED | BA_USE_DEFAULT_SEARCH_START);
+
+	*len = (int)wide_len;
+
+	return ret;
+}
+
+/*
+ * roll back changes made before issuing BIO in the case of IO error.
+ */
+static void undo_bio(struct bio *bio)
+{
+	int i;
+
+	for (i = 0; i < bio->bi_vcnt; ++i) {
+		struct page *pg;
+		jnode *node;
+
+		pg = bio->bi_io_vec[i].bv_page;
+		ClearPageWriteback(pg);
+		node = jprivate(pg);
+		spin_lock_jnode(node);
+		JF_CLR(node, JNODE_WRITEBACK);
+		JF_SET(node, JNODE_DIRTY);
+		spin_unlock_jnode(node);
+	}
+	bio_put(bio);
+}
+
+/* put overwrite set back to atom's clean list */
+static void put_overwrite_set(struct commit_handle *ch)
+{
+	jnode *cur;
+
+	list_for_each_entry(cur, ch->overwrite_set, capture_link)
+		jrelse_tail(cur);
+}
+
+/* Count overwrite set size, grab disk space for wandered blocks allocation.
+   Since we have a separate list for atom's overwrite set we just scan the list,
+   count bitmap and other not leaf nodes which wandered blocks allocation we
+   have to grab space for. */
+static int get_overwrite_set(struct commit_handle *ch)
+{
+	int ret;
+	jnode *cur;
+	__u64 nr_not_leaves = 0;
+#if REISER4_DEBUG
+	__u64 nr_formatted_leaves = 0;
+	__u64 nr_unformatted_leaves = 0;
+#endif
+
+	assert("zam-697", ch->overwrite_set_size == 0);
+
+	ch->overwrite_set = ATOM_OVRWR_LIST(ch->atom);
+	cur = list_entry(ch->overwrite_set->next, jnode, capture_link);
+
+	while (ch->overwrite_set != &cur->capture_link) {
+		jnode *next = list_entry(cur->capture_link.next, jnode, capture_link);
+
+		/* Count bitmap locks for getting correct statistics what number
+		 * of blocks were cleared by the transaction commit. */
+		if (jnode_get_type(cur) == JNODE_BITMAP)
+			ch->nr_bitmap++;
+
+		assert("zam-939", JF_ISSET(cur, JNODE_OVRWR)
+		       || jnode_get_type(cur) == JNODE_BITMAP);
+
+		if (jnode_is_znode(cur) && znode_above_root(JZNODE(cur))) {
+			/* we replace fake znode by another (real)
+			   znode which is suggested by disk_layout
+			   plugin */
+
+			/* FIXME: it looks like fake znode should be
+			   replaced by jnode supplied by
+			   disk_layout. */
+
+			struct super_block *s = reiser4_get_current_sb();
+			reiser4_super_info_data *sbinfo =
+			    get_current_super_private();
+
+			if (sbinfo->df_plug->log_super) {
+				jnode *sj = sbinfo->df_plug->log_super(s);
+
+				assert("zam-593", sj != NULL);
+
+				if (IS_ERR(sj))
+					return PTR_ERR(sj);
+
+				spin_lock_jnode(sj);
+				JF_SET(sj, JNODE_OVRWR);
+				insert_into_atom_ovrwr_list(ch->atom, sj);
+				spin_unlock_jnode(sj);
+
+				/* jload it as the rest of overwrite set */
+				jload_gfp(sj, GFP_KERNEL, 0);
+
+				ch->overwrite_set_size++;
+			}
+			spin_lock_jnode(cur);
+			uncapture_block(cur);
+			jput(cur);
+
+		} else {
+			int ret;
+			ch->overwrite_set_size++;
+			ret = jload_gfp(cur, GFP_KERNEL, 0);
+			if (ret)
+				reiser4_panic("zam-783",
+					      "cannot load e-flushed jnode back (ret = %d)\n",
+					      ret);
+		}
+
+		/* Count not leaves here because we have to grab disk space
+		 * for wandered blocks. They were not counted as "flush
+		 * reserved". Counting should be done _after_ nodes are pinned
+		 * into memory by jload(). */
+		if (!jnode_is_leaf(cur))
+			nr_not_leaves++;
+		else {
+#if REISER4_DEBUG
+			/* at this point @cur either has JNODE_FLUSH_RESERVED
+			 * or is eflushed. Locking is not strong enough to
+			 * write an assertion checking for this. */
+			if (jnode_is_znode(cur))
+				nr_formatted_leaves++;
+			else
+				nr_unformatted_leaves++;
+#endif
+			JF_CLR(cur, JNODE_FLUSH_RESERVED);
+		}
+
+		cur = next;
+	}
+
+	/* Grab space for writing (wandered blocks) of not leaves found in
+	 * overwrite set. */
+	ret = reiser4_grab_space_force(nr_not_leaves, BA_RESERVED);
+	if (ret)
+		return ret;
+
+	/* Disk space for allocation of wandered blocks of leaf nodes already
+	 * reserved as "flush reserved", move it to grabbed space counter. */
+	spin_lock_atom(ch->atom);
+	assert("zam-940",
+	       nr_formatted_leaves + nr_unformatted_leaves <=
+	       ch->atom->flush_reserved);
+	flush_reserved2grabbed(ch->atom, ch->atom->flush_reserved);
+	spin_unlock_atom(ch->atom);
+
+	return ch->overwrite_set_size;
+}
+
+/**
+ * write_jnodes_to_disk_extent - submit write request
+ * @head:
+ * @first: first jnode of the list
+ * @nr: number of jnodes on the list
+ * @block_p:
+ * @fq:
+ * @flags: used to decide whether page is to get PG_reclaim flag
+ *
+ * Submits a write request for @nr jnodes beginning from the @first, other
+ * jnodes are after the @first on the double-linked "capture" list.  All jnodes
+ * will be written to the disk region of @nr blocks starting with @block_p block
+ * number.  If @fq is not NULL it means that waiting for i/o completion will be
+ * done more efficiently by using flush_queue_t objects.
+ * This function is the one which writes list of jnodes in batch mode. It does
+ * all low-level things as bio construction and page states manipulation.
+ *
+ * ZAM-FIXME-HANS: brief me on why this function exists, and why bios are
+ * aggregated in this function instead of being left to the layers below
+ *
+ * FIXME: ZAM->HANS: What layer are you talking about? Can you point me to that?
+ * Why that layer needed? Why BIOs cannot be constructed here?
+ */
+static int write_jnodes_to_disk_extent(
+	jnode *first, int nr, const reiser4_block_nr *block_p,
+	flush_queue_t *fq, int flags)
+{
+	struct super_block *super = reiser4_get_current_sb();
+	int write_op = ( flags & WRITEOUT_BARRIER ) ? WRITE_BARRIER : WRITE;
+	int max_blocks;
+	jnode *cur = first;
+	reiser4_block_nr block;
+
+	assert("zam-571", first != NULL);
+	assert("zam-572", block_p != NULL);
+	assert("zam-570", nr > 0);
+
+	block = *block_p;
+	max_blocks = min(bio_get_nr_vecs(super->s_bdev), BIO_MAX_PAGES);
+
+	while (nr > 0) {
+		struct bio *bio;
+		int nr_blocks = min(nr, max_blocks);
+		int i;
+		int nr_used;
+
+		bio = bio_alloc(GFP_NOIO, nr_blocks);
+		if (!bio)
+			return RETERR(-ENOMEM);
+
+		bio->bi_bdev = super->s_bdev;
+		bio->bi_sector = block * (super->s_blocksize >> 9);
+		for (nr_used = 0, i = 0; i < nr_blocks; i++) {
+			struct page *pg;
+
+			pg = jnode_page(cur);
+			assert("zam-573", pg != NULL);
+
+			page_cache_get(pg);
+
+			lock_and_wait_page_writeback(pg);
+
+			if (!bio_add_page(bio, pg, super->s_blocksize, 0)) {
+				/*
+				 * underlying device is satiated. Stop adding
+				 * pages to the bio.
+				 */
+				unlock_page(pg);
+				page_cache_release(pg);
+				break;
+			}
+
+			spin_lock_jnode(cur);
+			assert("nikita-3166",
+			       pg->mapping == jnode_get_mapping(cur));
+			assert("zam-912", !JF_ISSET(cur, JNODE_WRITEBACK));
+			assert("", !JF_ISSET(cur, JNODE_EFLUSH));
+#if REISER4_DEBUG
+			spin_lock(&cur->load);
+			assert("nikita-3165", !jnode_is_releasable(cur));
+			spin_unlock(&cur->load);
+#endif
+			JF_SET(cur, JNODE_WRITEBACK);
+			JF_CLR(cur, JNODE_DIRTY);
+			ON_DEBUG(cur->written++);
+			spin_unlock_jnode(cur);
+
+			ClearPageError(pg);
+			set_page_writeback(pg);
+
+			if (get_current_context()->entd) {
+				/* this is ent thread */
+				entd_context *ent = get_entd_context(super);
+				struct wbq *rq, *next;
+
+				spin_lock(&ent->guard);
+
+				if (pg == ent->cur_request->page) {
+					/*
+					 * entd is called for this page. This
+					 * request is not in th etodo list
+					 */
+					ent->cur_request->written = 1;
+				} else {
+					/*
+					 * if we have written a page for which writepage
+					 * is called for - move request to another list.
+					 */
+					list_for_each_entry_safe(rq, next, &ent->todo_list, link) {
+						assert("", rq->magic == WBQ_MAGIC);
+						if (pg == rq->page) {
+							/*
+							 * remove request from
+							 * entd's queue, but do
+							 * not wake up a thread
+							 * which put this
+							 * request
+							 */
+							list_del_init(&rq->link);
+							ent->nr_todo_reqs --;
+							list_add_tail(&rq->link, &ent->done_list);
+							ent->nr_done_reqs ++;
+							rq->written = 1;
+							break;
+						}
+					}
+				}
+				spin_unlock(&ent->guard);
+			}
+
+			clear_page_dirty_for_io(pg);
+
+			unlock_page(pg);
+
+			cur = list_entry(cur->capture_link.next, jnode, capture_link);
+			nr_used++;
+		}
+		if (nr_used > 0) {
+			assert("nikita-3453",
+			       bio->bi_size == super->s_blocksize * nr_used);
+			assert("nikita-3454", bio->bi_vcnt == nr_used);
+
+			/* Check if we are allowed to write at all */
+			if (super->s_flags & MS_RDONLY)
+				undo_bio(bio);
+			else {
+				int not_supported;
+
+				add_fq_to_bio(fq, bio);
+				bio_get(bio);
+				reiser4_submit_bio(write_op, bio);
+				not_supported = bio_flagged(bio, BIO_EOPNOTSUPP);
+				bio_put(bio);
+				if (not_supported)
+					return -EOPNOTSUPP;
+			}
+
+			block += nr_used - 1;
+			update_blocknr_hint_default(super, &block);
+			block += 1;
+		} else {
+			bio_put(bio);
+		}
+		nr -= nr_used;
+	}
+
+	return 0;
+}
+
+/* This is a procedure which recovers a contiguous sequences of disk block
+   numbers in the given list of j-nodes and submits write requests on this
+   per-sequence basis */
+int
+write_jnode_list(struct list_head *head, flush_queue_t *fq,
+		 long *nr_submitted, int flags)
+{
+	int ret;
+	jnode *beg = list_entry(head->next, jnode, capture_link);
+
+	while (head != &beg->capture_link) {
+		int nr = 1;
+		jnode *cur = list_entry(beg->capture_link.next, jnode, capture_link);
+
+		while (head != &cur->capture_link) {
+			if (*jnode_get_block(cur) != *jnode_get_block(beg) + nr)
+				break;
+			++nr;
+			cur = list_entry(cur->capture_link.next, jnode, capture_link);
+		}
+
+		ret = write_jnodes_to_disk_extent(
+			beg, nr, jnode_get_block(beg), fq, flags);
+		if (ret)
+			return ret;
+
+		if (nr_submitted)
+			*nr_submitted += nr;
+
+		beg = cur;
+	}
+
+	return 0;
+}
+
+/* add given wandered mapping to atom's wandered map */
+static int
+add_region_to_wmap(jnode * cur, int len, const reiser4_block_nr * block_p)
+{
+	int ret;
+	blocknr_set_entry *new_bsep = NULL;
+	reiser4_block_nr block;
+
+	txn_atom *atom;
+
+	assert("zam-568", block_p != NULL);
+	block = *block_p;
+	assert("zam-569", len > 0);
+
+	while ((len--) > 0) {
+		do {
+			atom = get_current_atom_locked();
+			assert("zam-536",
+			       !blocknr_is_fake(jnode_get_block(cur)));
+			ret =
+			    blocknr_set_add_pair(atom, &atom->wandered_map,
+						 &new_bsep,
+						 jnode_get_block(cur), &block);
+		} while (ret == -E_REPEAT);
+
+		if (ret) {
+			/* deallocate blocks which were not added to wandered
+			   map */
+			reiser4_block_nr wide_len = len;
+
+			reiser4_dealloc_blocks(&block, &wide_len,
+					       BLOCK_NOT_COUNTED,
+					       BA_FORMATTED
+					       /* formatted, without defer */ );
+
+			return ret;
+		}
+
+		spin_unlock_atom(atom);
+
+		cur = list_entry(cur->capture_link.next, jnode, capture_link);
+		++block;
+	}
+
+	return 0;
+}
+
+/* Allocate wandered blocks for current atom's OVERWRITE SET and immediately
+   submit IO for allocated blocks.  We assume that current atom is in a stage
+   when any atom fusion is impossible and atom is unlocked and it is safe. */
+static int alloc_wandered_blocks(struct commit_handle *ch, flush_queue_t *fq)
+{
+	reiser4_block_nr block;
+
+	int rest;
+	int len;
+	int ret;
+
+	jnode *cur;
+
+	assert("zam-534", ch->overwrite_set_size > 0);
+
+	rest = ch->overwrite_set_size;
+
+	cur = list_entry(ch->overwrite_set->next, jnode, capture_link);
+	while (ch->overwrite_set != &cur->capture_link) {
+		assert("zam-567", JF_ISSET(cur, JNODE_OVRWR));
+
+		ret = get_more_wandered_blocks(rest, &block, &len);
+		if (ret)
+			return ret;
+
+		rest -= len;
+
+		ret = add_region_to_wmap(cur, len, &block);
+		if (ret)
+			return ret;
+
+		ret = write_jnodes_to_disk_extent(cur, len, &block, fq, 0);
+		if (ret)
+			return ret;
+
+		while ((len--) > 0) {
+			assert("zam-604",
+			       ch->overwrite_set != &cur->capture_link);
+			cur = list_entry(cur->capture_link.next, jnode, capture_link);
+		}
+	}
+
+	return 0;
+}
+
+/* allocate given number of nodes over the journal area and link them into a
+   list, return pointer to the first jnode in the list */
+static int alloc_tx(struct commit_handle *ch, flush_queue_t * fq)
+{
+	reiser4_blocknr_hint hint;
+	reiser4_block_nr allocated = 0;
+	reiser4_block_nr first, len;
+	jnode *cur;
+	jnode *txhead;
+	int ret;
+
+	assert("zam-698", ch->tx_size > 0);
+	assert("zam-699", list_empty_careful(&ch->tx_list));
+
+	while (allocated < (unsigned)ch->tx_size) {
+		len = (ch->tx_size - allocated);
+
+		blocknr_hint_init(&hint);
+
+		hint.block_stage = BLOCK_GRABBED;
+
+		/* FIXME: there should be some block allocation policy for
+		   nodes which contain wander records */
+
+		/* We assume that disk space for wandered record blocks can be
+		 * taken from reserved area. */
+		ret = reiser4_alloc_blocks(&hint, &first, &len,
+					   BA_FORMATTED | BA_RESERVED |
+					   BA_USE_DEFAULT_SEARCH_START);
+
+		blocknr_hint_done(&hint);
+
+		if (ret)
+			return ret;
+
+		allocated += len;
+
+		/* create jnodes for all wander records */
+		while (len--) {
+			cur = alloc_io_head(&first);
+
+			if (cur == NULL) {
+				ret = RETERR(-ENOMEM);
+				goto free_not_assigned;
+			}
+
+			ret = jinit_new(cur, GFP_KERNEL);
+
+			if (ret != 0) {
+				jfree(cur);
+				goto free_not_assigned;
+			}
+
+			pin_jnode_data(cur);
+
+			list_add_tail(&cur->capture_link, &ch->tx_list);
+
+			first++;
+		}
+	}
+
+	{ /* format a on-disk linked list of wander records */
+		int serial = 1;
+
+		txhead = list_entry(ch->tx_list.next, jnode, capture_link);
+		format_tx_head(ch);
+
+		cur = list_entry(txhead->capture_link.next, jnode, capture_link);
+		while (&ch->tx_list != &cur->capture_link) {
+			format_wander_record(ch, cur, serial++);
+			cur = list_entry(cur->capture_link.next, jnode, capture_link);
+		}
+	}
+
+	{ /* Fill wander records with Wandered Set */
+		struct store_wmap_params params;
+		txn_atom *atom;
+
+		params.cur = list_entry(txhead->capture_link.next, jnode, capture_link);
+
+		params.idx = 0;
+		params.capacity =
+		    wander_record_capacity(reiser4_get_current_sb());
+
+		atom = get_current_atom_locked();
+		blocknr_set_iterator(atom, &atom->wandered_map,
+				     &store_wmap_actor, &params, 0);
+		spin_unlock_atom(atom);
+	}
+
+	{ /* relse all jnodes from tx_list */
+		cur = list_entry(ch->tx_list.next, jnode, capture_link);
+		while (&ch->tx_list != &cur->capture_link) {
+			jrelse(cur);
+			cur = list_entry(cur->capture_link.next, jnode, capture_link);
+		}
+	}
+
+	ret = write_jnode_list(&ch->tx_list, fq, NULL, 0);
+
+	return ret;
+
+      free_not_assigned:
+	/* We deallocate blocks not yet assigned to jnodes on tx_list. The
+	   caller takes care about invalidating of tx list  */
+	reiser4_dealloc_blocks(&first, &len, BLOCK_NOT_COUNTED, BA_FORMATTED);
+
+	return ret;
+}
+
+static int commit_tx(struct commit_handle *ch)
+{
+	flush_queue_t *fq;
+	int barrier;
+	int ret;
+
+	/* Grab more space for wandered records. */
+	ret = reiser4_grab_space_force((__u64) (ch->tx_size), BA_RESERVED);
+	if (ret)
+		return ret;
+
+	fq = get_fq_for_current_atom();
+	if (IS_ERR(fq))
+		return PTR_ERR(fq);
+
+	spin_unlock_atom(fq->atom);
+	do {
+		ret = alloc_wandered_blocks(ch, fq);
+		if (ret)
+			break;
+		ret = alloc_tx(ch, fq);
+		if (ret)
+			break;
+	} while (0);
+
+	/* Release all grabbed space if it was not fully used for
+	 * wandered blocks/records allocation. */
+	all_grabbed2free();
+	fq_put(fq);
+	if (ret)
+		return ret;
+ repeat_wo_barrier:
+	barrier = reiser4_use_write_barrier(ch->super);
+	if (!barrier) {
+		ret = current_atom_finish_all_fq();
+		if (ret)
+			return ret;
+	}
+	ret = update_journal_header(ch, barrier);
+	if (barrier) {
+		if (ret) {
+			if (ret == -EOPNOTSUPP) {
+				disable_write_barrier(ch->super);
+				goto repeat_wo_barrier;
+			}
+			return ret;
+		}
+		ret = current_atom_finish_all_fq();
+	}
+	return ret;
+}
+
+
+static int write_tx_back(struct commit_handle * ch)
+{
+	flush_queue_t *fq;
+	int ret;
+	int barrier;
+
+	post_commit_hook();
+	fq = get_fq_for_current_atom();
+	if (IS_ERR(fq))
+		return  PTR_ERR(fq);
+	spin_unlock_atom(fq->atom);
+	ret = write_jnode_list(
+		ch->overwrite_set, fq, NULL, WRITEOUT_FOR_PAGE_RECLAIM);
+	fq_put(fq);
+	if (ret)
+		return ret;
+ repeat_wo_barrier:
+	barrier = reiser4_use_write_barrier(ch->super);
+	if (!barrier) {
+		ret = current_atom_finish_all_fq();
+		if (ret)
+			return ret;
+	}
+	ret = update_journal_footer(ch, barrier);
+	if (barrier) {
+		if (ret) {
+			if (ret == -EOPNOTSUPP) {
+				disable_write_barrier(ch->super);
+				goto repeat_wo_barrier;
+			}
+			return ret;
+		}
+		ret = current_atom_finish_all_fq();
+	}
+	if (ret)
+		return ret;
+	post_write_back_hook();
+	return 0;
+}
+
+/* We assume that at this moment all captured blocks are marked as RELOC or
+   WANDER (belong to Relocate o Overwrite set), all nodes from Relocate set
+   are submitted to write.
+*/
+
+int reiser4_write_logs(long *nr_submitted)
+{
+	txn_atom *atom;
+	struct super_block *super = reiser4_get_current_sb();
+	reiser4_super_info_data *sbinfo = get_super_private(super);
+	struct commit_handle ch;
+	int ret;
+
+	writeout_mode_enable();
+
+	/* block allocator may add j-nodes to the clean_list */
+	ret = pre_commit_hook();
+	if (ret)
+		return ret;
+
+	/* No locks are required if we take atom which stage >=
+	 * ASTAGE_PRE_COMMIT */
+	atom = get_current_context()->trans->atom;
+	assert("zam-965", atom != NULL);
+
+	/* relocate set is on the atom->clean_nodes list after
+	 * current_atom_complete_writes() finishes. It can be safely
+	 * uncaptured after commit_semaphore is taken, because any atom that
+	 * captures these nodes is guaranteed to commit after current one.
+	 *
+	 * This can only be done after pre_commit_hook(), because it is where
+	 * early flushed jnodes with CREATED bit are transferred to the
+	 * overwrite list. */
+	invalidate_list(ATOM_CLEAN_LIST(atom));
+	spin_lock_atom(atom);
+	/* There might be waiters for the relocate nodes which we have
+	 * released, wake them up. */
+	atom_send_event(atom);
+	spin_unlock_atom(atom);
+
+	if (REISER4_DEBUG) {
+		int level;
+
+		for (level = 0; level < REAL_MAX_ZTREE_HEIGHT + 1; ++level)
+			assert("nikita-3352",
+			       list_empty_careful(ATOM_DIRTY_LIST(atom, level)));
+	}
+
+	sbinfo->nr_files_committed += (unsigned)atom->nr_objects_created;
+	sbinfo->nr_files_committed -= (unsigned)atom->nr_objects_deleted;
+
+	init_commit_handle(&ch, atom);
+
+	ch.free_blocks = sbinfo->blocks_free_committed;
+	ch.nr_files = sbinfo->nr_files_committed;
+	/* ZAM-FIXME-HANS: email me what the contention level is for the super
+	 * lock. */
+	ch.next_oid = oid_next(super);
+
+	/* count overwrite set and place it in a separate list */
+	ret = get_overwrite_set(&ch);
+
+	if (ret <= 0) {
+		/* It is possible that overwrite set is empty here, it means
+		   all captured nodes are clean */
+		goto up_and_ret;
+	}
+
+	/* Inform the caller about what number of dirty pages will be
+	 * submitted to disk. */
+	*nr_submitted += ch.overwrite_set_size - ch.nr_bitmap;
+
+	/* count all records needed for storing of the wandered set */
+	get_tx_size(&ch);
+
+	ret = commit_tx(&ch);
+	if (ret)
+		goto up_and_ret;
+
+	spin_lock_atom(atom);
+	atom_set_stage(atom, ASTAGE_POST_COMMIT);
+	spin_unlock_atom(atom);
+
+	ret = write_tx_back(&ch);
+	post_write_back_hook();
+
+      up_and_ret:
+	if (ret) {
+		/* there could be fq attached to current atom; the only way to
+		   remove them is: */
+		current_atom_finish_all_fq();
+	}
+
+	/* free blocks of flushed transaction */
+	dealloc_tx_list(&ch);
+	dealloc_wmap(&ch);
+
+	put_overwrite_set(&ch);
+
+	done_commit_handle(&ch);
+
+	writeout_mode_disable();
+
+	return ret;
+}
+
+/* consistency checks for journal data/control blocks: header, footer, log
+   records, transactions head blocks. All functions return zero on success. */
+
+static int check_journal_header(const jnode * node UNUSED_ARG)
+{
+	/* FIXME: journal header has no magic field yet. */
+	return 0;
+}
+
+/* wait for write completion for all jnodes from given list */
+static int wait_on_jnode_list(struct list_head *head)
+{
+	jnode *scan;
+	int ret = 0;
+
+	list_for_each_entry(scan, head, capture_link) {
+		struct page *pg = jnode_page(scan);
+
+		if (pg) {
+			if (PageWriteback(pg))
+				wait_on_page_writeback(pg);
+
+			if (PageError(pg))
+				ret++;
+		}
+	}
+
+	return ret;
+}
+
+static int check_journal_footer(const jnode * node UNUSED_ARG)
+{
+	/* FIXME: journal footer has no magic field yet. */
+	return 0;
+}
+
+static int check_tx_head(const jnode * node)
+{
+	struct tx_header *header = (struct tx_header *)jdata(node);
+
+	if (memcmp(&header->magic, TX_HEADER_MAGIC, TX_HEADER_MAGIC_SIZE) != 0) {
+		warning("zam-627", "tx head at block %s corrupted\n",
+			sprint_address(jnode_get_block(node)));
+		return RETERR(-EIO);
+	}
+
+	return 0;
+}
+
+static int check_wander_record(const jnode * node)
+{
+	struct wander_record_header *RH =
+	    (struct wander_record_header *)jdata(node);
+
+	if (memcmp(&RH->magic, WANDER_RECORD_MAGIC, WANDER_RECORD_MAGIC_SIZE) !=
+	    0) {
+		warning("zam-628", "wander record at block %s corrupted\n",
+			sprint_address(jnode_get_block(node)));
+		return RETERR(-EIO);
+	}
+
+	return 0;
+}
+
+/* fill commit_handler structure by everything what is needed for update_journal_footer */
+static int restore_commit_handle(struct commit_handle *ch, jnode *tx_head)
+{
+	struct tx_header *TXH;
+	int ret;
+
+	ret = jload(tx_head);
+	if (ret)
+		return ret;
+
+	TXH = (struct tx_header *)jdata(tx_head);
+
+	ch->free_blocks = le64_to_cpu(get_unaligned(&TXH->free_blocks));
+	ch->nr_files = le64_to_cpu(get_unaligned(&TXH->nr_files));
+	ch->next_oid = le64_to_cpu(get_unaligned(&TXH->next_oid));
+
+	jrelse(tx_head);
+
+	list_add(&tx_head->capture_link, &ch->tx_list);
+
+	return 0;
+}
+
+/* replay one transaction: restore and write overwrite set in place */
+static int replay_transaction(const struct super_block *s,
+			      jnode * tx_head,
+			      const reiser4_block_nr * log_rec_block_p,
+			      const reiser4_block_nr * end_block,
+			      unsigned int nr_wander_records)
+{
+	reiser4_block_nr log_rec_block = *log_rec_block_p;
+	struct commit_handle ch;
+	LIST_HEAD(overwrite_set);
+	jnode *log;
+	int ret;
+
+	init_commit_handle(&ch, NULL);
+	ch.overwrite_set = &overwrite_set;
+
+	restore_commit_handle(&ch, tx_head);
+
+	while (log_rec_block != *end_block) {
+		struct wander_record_header *header;
+		struct wander_entry *entry;
+
+		int i;
+
+		if (nr_wander_records == 0) {
+			warning("zam-631",
+				"number of wander records in the linked list"
+				" greater than number stored in tx head.\n");
+			ret = RETERR(-EIO);
+			goto free_ow_set;
+		}
+
+		log = alloc_io_head(&log_rec_block);
+		if (log == NULL)
+			return RETERR(-ENOMEM);
+
+		ret = jload(log);
+		if (ret < 0) {
+			drop_io_head(log);
+			return ret;
+		}
+
+		ret = check_wander_record(log);
+		if (ret) {
+			jrelse(log);
+			drop_io_head(log);
+			return ret;
+		}
+
+		header = (struct wander_record_header *)jdata(log);
+		log_rec_block = le64_to_cpu(get_unaligned(&header->next_block));
+
+		entry = (struct wander_entry *)(header + 1);
+
+		/* restore overwrite set from wander record content */
+		for (i = 0; i < wander_record_capacity(s); i++) {
+			reiser4_block_nr block;
+			jnode *node;
+
+			block = le64_to_cpu(get_unaligned(&entry->wandered));
+			if (block == 0)
+				break;
+
+			node = alloc_io_head(&block);
+			if (node == NULL) {
+				ret = RETERR(-ENOMEM);
+				/*
+				 * FIXME-VS:???
+				 */
+				jrelse(log);
+				drop_io_head(log);
+				goto free_ow_set;
+			}
+
+			ret = jload(node);
+
+			if (ret < 0) {
+				drop_io_head(node);
+				/*
+				 * FIXME-VS:???
+				 */
+				jrelse(log);
+				drop_io_head(log);
+				goto free_ow_set;
+			}
+
+			block = le64_to_cpu(get_unaligned(&entry->original));
+
+			assert("zam-603", block != 0);
+
+			jnode_set_block(node, &block);
+
+			list_add_tail(&node->capture_link, ch.overwrite_set);
+
+			++entry;
+		}
+
+		jrelse(log);
+		drop_io_head(log);
+
+		--nr_wander_records;
+	}
+
+	if (nr_wander_records != 0) {
+		warning("zam-632", "number of wander records in the linked list"
+			" less than number stored in tx head.\n");
+		ret = RETERR(-EIO);
+		goto free_ow_set;
+	}
+
+	{			/* write wandered set in place */
+		write_jnode_list(ch.overwrite_set, NULL, NULL, 0);
+		ret = wait_on_jnode_list(ch.overwrite_set);
+
+		if (ret) {
+			ret = RETERR(-EIO);
+			goto free_ow_set;
+		}
+	}
+
+	ret = update_journal_footer(&ch, 0);
+
+      free_ow_set:
+
+	while (!list_empty(ch.overwrite_set)) {
+		jnode *cur = list_entry(ch.overwrite_set->next, jnode, capture_link);
+		list_del_init(&cur->capture_link);
+		jrelse(cur);
+		drop_io_head(cur);
+	}
+
+	list_del_init(&tx_head->capture_link);
+
+	done_commit_handle(&ch);
+
+	return ret;
+}
+
+/* find oldest committed and not played transaction and play it. The transaction
+ * was committed and journal header block was updated but the blocks from the
+ * process of writing the atom's overwrite set in-place and updating of journal
+ * footer block were not completed. This function completes the process by
+ * recovering the atom's overwrite set from their wandered locations and writes
+ * them in-place and updating the journal footer. */
+static int replay_oldest_transaction(struct super_block *s)
+{
+	reiser4_super_info_data *sbinfo = get_super_private(s);
+	jnode *jf = sbinfo->journal_footer;
+	unsigned int total;
+	struct journal_footer *F;
+	struct tx_header *T;
+
+	reiser4_block_nr prev_tx;
+	reiser4_block_nr last_flushed_tx;
+	reiser4_block_nr log_rec_block = 0;
+
+	jnode *tx_head;
+
+	int ret;
+
+	if ((ret = jload(jf)) < 0)
+		return ret;
+
+	F = (struct journal_footer *)jdata(jf);
+
+	last_flushed_tx = le64_to_cpu(get_unaligned(&F->last_flushed_tx));
+
+	jrelse(jf);
+
+	if (sbinfo->last_committed_tx == last_flushed_tx) {
+		/* all transactions are replayed */
+		return 0;
+	}
+
+	prev_tx = sbinfo->last_committed_tx;
+
+	/* searching for oldest not flushed transaction */
+	while (1) {
+		tx_head = alloc_io_head(&prev_tx);
+		if (!tx_head)
+			return RETERR(-ENOMEM);
+
+		ret = jload(tx_head);
+		if (ret < 0) {
+			drop_io_head(tx_head);
+			return ret;
+		}
+
+		ret = check_tx_head(tx_head);
+		if (ret) {
+			jrelse(tx_head);
+			drop_io_head(tx_head);
+			return ret;
+		}
+
+		T = (struct tx_header *)jdata(tx_head);
+
+		prev_tx = le64_to_cpu(get_unaligned(&T->prev_tx));
+
+		if (prev_tx == last_flushed_tx)
+			break;
+
+		jrelse(tx_head);
+		drop_io_head(tx_head);
+	}
+
+	total = le32_to_cpu(get_unaligned(&T->total));
+	log_rec_block = le64_to_cpu(get_unaligned(&T->next_block));
+
+	pin_jnode_data(tx_head);
+	jrelse(tx_head);
+
+	ret =
+	    replay_transaction(s, tx_head, &log_rec_block,
+			       jnode_get_block(tx_head), total - 1);
+
+	unpin_jnode_data(tx_head);
+	drop_io_head(tx_head);
+
+	if (ret)
+		return ret;
+	return -E_REPEAT;
+}
+
+/* The reiser4 journal current implementation was optimized to not to capture
+   super block if certain super blocks fields are modified. Currently, the set
+   is (<free block count>, <OID allocator>). These fields are logged by
+   special way which includes storing them in each transaction head block at
+   atom commit time and writing that information to journal footer block at
+   atom flush time.  For getting info from journal footer block to the
+   in-memory super block there is a special function
+   reiser4_journal_recover_sb_data() which should be called after disk format
+   plugin re-reads super block after journal replaying.
+*/
+
+/* get the information from journal footer in-memory super block */
+int reiser4_journal_recover_sb_data(struct super_block *s)
+{
+	reiser4_super_info_data *sbinfo = get_super_private(s);
+	struct journal_footer *jf;
+	int ret;
+
+	assert("zam-673", sbinfo->journal_footer != NULL);
+
+	ret = jload(sbinfo->journal_footer);
+	if (ret != 0)
+		return ret;
+
+	ret = check_journal_footer(sbinfo->journal_footer);
+	if (ret != 0)
+		goto out;
+
+	jf = (struct journal_footer *)jdata(sbinfo->journal_footer);
+
+	/* was there at least one flushed transaction?  */
+	if (jf->last_flushed_tx) {
+
+		/* restore free block counter logged in this transaction */
+		reiser4_set_free_blocks(s, le64_to_cpu(get_unaligned(&jf->free_blocks)));
+
+		/* restore oid allocator state */
+		oid_init_allocator(s,
+				   le64_to_cpu(get_unaligned(&jf->nr_files)),
+				   le64_to_cpu(get_unaligned(&jf->next_oid)));
+	}
+      out:
+	jrelse(sbinfo->journal_footer);
+	return ret;
+}
+
+/* reiser4 replay journal procedure */
+int reiser4_journal_replay(struct super_block *s)
+{
+	reiser4_super_info_data *sbinfo = get_super_private(s);
+	jnode *jh, *jf;
+	struct journal_header *header;
+	int nr_tx_replayed = 0;
+	int ret;
+
+	assert("zam-582", sbinfo != NULL);
+
+	jh = sbinfo->journal_header;
+	jf = sbinfo->journal_footer;
+
+	if (!jh || !jf) {
+		/* it is possible that disk layout does not support journal
+		   structures, we just warn about this */
+		warning("zam-583",
+			"journal control blocks were not loaded by disk layout plugin.  "
+			"journal replaying is not possible.\n");
+		return 0;
+	}
+
+	/* Take free block count from journal footer block. The free block
+	   counter value corresponds the last flushed transaction state */
+	ret = jload(jf);
+	if (ret < 0)
+		return ret;
+
+	ret = check_journal_footer(jf);
+	if (ret) {
+		jrelse(jf);
+		return ret;
+	}
+
+	jrelse(jf);
+
+	/* store last committed transaction info in reiser4 in-memory super
+	   block */
+	ret = jload(jh);
+	if (ret < 0)
+		return ret;
+
+	ret = check_journal_header(jh);
+	if (ret) {
+		jrelse(jh);
+		return ret;
+	}
+
+	header = (struct journal_header *)jdata(jh);
+	sbinfo->last_committed_tx = le64_to_cpu(get_unaligned(&header->last_committed_tx));
+
+	jrelse(jh);
+
+	/* replay committed transactions */
+	while ((ret = replay_oldest_transaction(s)) == -E_REPEAT)
+		nr_tx_replayed++;
+
+	return ret;
+}
+
+/* load journal control block (either journal header or journal footer block) */
+static int
+load_journal_control_block(jnode ** node, const reiser4_block_nr * block)
+{
+	int ret;
+
+	*node = alloc_io_head(block);
+	if (!(*node))
+		return RETERR(-ENOMEM);
+
+	ret = jload(*node);
+
+	if (ret) {
+		drop_io_head(*node);
+		*node = NULL;
+		return ret;
+	}
+
+	pin_jnode_data(*node);
+	jrelse(*node);
+
+	return 0;
+}
+
+/* unload journal header or footer and free jnode */
+static void unload_journal_control_block(jnode ** node)
+{
+	if (*node) {
+		unpin_jnode_data(*node);
+		drop_io_head(*node);
+		*node = NULL;
+	}
+}
+
+/* release journal control blocks */
+void done_journal_info(struct super_block *s)
+{
+	reiser4_super_info_data *sbinfo = get_super_private(s);
+
+	assert("zam-476", sbinfo != NULL);
+
+	unload_journal_control_block(&sbinfo->journal_header);
+	unload_journal_control_block(&sbinfo->journal_footer);
+	rcu_barrier();
+}
+
+/* load journal control blocks */
+int init_journal_info(struct super_block *s)
+{
+	reiser4_super_info_data *sbinfo = get_super_private(s);
+	journal_location *loc;
+	int ret;
+
+	loc = &sbinfo->jloc;
+
+	assert("zam-651", loc != NULL);
+	assert("zam-652", loc->header != 0);
+	assert("zam-653", loc->footer != 0);
+
+	ret = load_journal_control_block(&sbinfo->journal_header, &loc->header);
+
+	if (ret)
+		return ret;
+
+	ret = load_journal_control_block(&sbinfo->journal_footer, &loc->footer);
+
+	if (ret) {
+		unload_journal_control_block(&sbinfo->journal_header);
+	}
+
+	return ret;
+}
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 80
+   End:
+*/
diff -urN oldtree/fs/reiser4/wander.h newtree/fs/reiser4/wander.h
--- oldtree/fs/reiser4/wander.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/wander.h	2006-02-21 15:58:34.696871832 +0000
@@ -0,0 +1,135 @@
+/* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
+
+#if !defined (__FS_REISER4_WANDER_H__)
+#define __FS_REISER4_WANDER_H__
+
+#include "dformat.h"
+
+#include <linux/fs.h>		/* for struct super_block  */
+
+/* REISER4 JOURNAL ON-DISK DATA STRUCTURES   */
+
+#define TX_HEADER_MAGIC  "TxMagic4"
+#define WANDER_RECORD_MAGIC "LogMagc4"
+
+#define TX_HEADER_MAGIC_SIZE  (8)
+#define WANDER_RECORD_MAGIC_SIZE (8)
+
+/* journal header block format */
+struct journal_header {
+	/* last written transaction head location */
+	d64 last_committed_tx;
+};
+
+typedef struct journal_location {
+	reiser4_block_nr footer;
+	reiser4_block_nr header;
+} journal_location;
+
+/* The wander.c head comment describes usage and semantic of all these structures */
+/* journal footer block format */
+struct journal_footer {
+	/* last flushed transaction location. */
+	/* This block number is no more valid after the transaction it points
+	   to gets flushed, this number is used only at journal replaying time
+	   for detection of the end of on-disk list of committed transactions
+	   which were not flushed completely */
+	d64 last_flushed_tx;
+
+	/* free block counter is written in journal footer at transaction
+	   flushing , not in super block because free blocks counter is logged
+	   by another way than super block fields (root pointer, for
+	   example). */
+	d64 free_blocks;
+
+	/* number of used OIDs and maximal used OID are logged separately from
+	   super block */
+	d64 nr_files;
+	d64 next_oid;
+};
+
+/* Each wander record (except the first one) has unified format with wander
+   record header followed by an array of log entries */
+struct wander_record_header {
+	/* when there is no predefined location for wander records, this magic
+	   string should help reiser4fsck. */
+	char magic[WANDER_RECORD_MAGIC_SIZE];
+
+	/* transaction id */
+	d64 id;
+
+	/* total number of wander records in current transaction  */
+	d32 total;
+
+	/* this block number in transaction */
+	d32 serial;
+
+	/* number of previous block in commit */
+	d64 next_block;
+};
+
+/* The first wander record (transaction head) of written transaction has the
+   special format */
+struct tx_header {
+	/* magic string makes first block in transaction different from other
+	   logged blocks, it should help fsck. */
+	char magic[TX_HEADER_MAGIC_SIZE];
+
+	/* transaction id */
+	d64 id;
+
+	/* total number of records (including this first tx head) in the
+	   transaction */
+	d32 total;
+
+	/* align next field to 8-byte boundary; this field always is zero */
+	d32 padding;
+
+	/* block number of previous transaction head */
+	d64 prev_tx;
+
+	/* next wander record location */
+	d64 next_block;
+
+	/* committed versions of free blocks counter */
+	d64 free_blocks;
+
+	/* number of used OIDs (nr_files) and maximal used OID are logged
+	   separately from super block */
+	d64 nr_files;
+	d64 next_oid;
+};
+
+/* A transaction gets written to disk as a set of wander records (each wander
+   record size is fs block) */
+
+/* As it was told above a wander The rest of wander record is filled by these log entries, unused space filled
+   by zeroes */
+struct wander_entry {
+	d64 original;		/* block original location */
+	d64 wandered;		/* block wandered location */
+};
+
+/* REISER4 JOURNAL WRITER FUNCTIONS   */
+
+extern int reiser4_write_logs(long *);
+extern int reiser4_journal_replay(struct super_block *);
+extern int reiser4_journal_recover_sb_data(struct super_block *);
+
+extern int init_journal_info(struct super_block *);
+extern void done_journal_info(struct super_block *);
+
+extern int write_jnode_list(struct list_head *, flush_queue_t *, long *, int);
+
+#endif				/* __FS_REISER4_WANDER_H__ */
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 80
+   scroll-step: 1
+   End:
+*/
diff -urN oldtree/fs/reiser4/writeout.h newtree/fs/reiser4/writeout.h
--- oldtree/fs/reiser4/writeout.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/writeout.h	2006-02-21 15:58:35.031820912 +0000
@@ -0,0 +1,21 @@
+/* Copyright 2002, 2003, 2004 by Hans Reiser, licensing governed by reiser4/README  */
+
+#if !defined (__FS_REISER4_WRITEOUT_H__)
+
+#define WRITEOUT_SINGLE_STREAM (0x1)
+#define WRITEOUT_FOR_PAGE_RECLAIM  (0x2)
+#define WRITEOUT_BARRIER (0x4)
+
+extern int get_writeout_flags(void);
+
+#endif				/* __FS_REISER4_WRITEOUT_H__ */
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 80
+   End:
+*/
diff -urN oldtree/fs/reiser4/znode.c newtree/fs/reiser4/znode.c
--- oldtree/fs/reiser4/znode.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/znode.c	2006-02-21 15:58:35.032820760 +0000
@@ -0,0 +1,1029 @@
+/* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
+ * reiser4/README */
+/* Znode manipulation functions. */
+/* Znode is the in-memory header for a tree node. It is stored
+   separately from the node itself so that it does not get written to
+   disk.  In this respect znode is like buffer head or page head. We
+   also use znodes for additional reiser4 specific purposes:
+
+    . they are organized into tree structure which is a part of whole
+      reiser4 tree.
+    . they are used to implement node grained locking
+    . they are used to keep additional state associated with a
+      node
+    . they contain links to lists used by the transaction manager
+
+   Znode is attached to some variable "block number" which is instance of
+   fs/reiser4/tree.h:reiser4_block_nr type. Znode can exist without
+   appropriate node being actually loaded in memory. Existence of znode itself
+   is regulated by reference count (->x_count) in it. Each time thread
+   acquires reference to znode through call to zget(), ->x_count is
+   incremented and decremented on call to zput().  Data (content of node) are
+   brought in memory through call to zload(), which also increments ->d_count
+   reference counter.  zload can block waiting on IO.  Call to zrelse()
+   decreases this counter. Also, ->c_count keeps track of number of child
+   znodes and prevents parent znode from being recycled until all of its
+   children are. ->c_count is decremented whenever child goes out of existence
+   (being actually recycled in zdestroy()) which can be some time after last
+   reference to this child dies if we support some form of LRU cache for
+   znodes.
+
+*/
+/* EVERY ZNODE'S STORY
+
+   1. His infancy.
+
+   Once upon a time, the znode was born deep inside of zget() by call to
+   zalloc(). At the return from zget() znode had:
+
+    . reference counter (x_count) of 1
+    . assigned block number, marked as used in bitmap
+    . pointer to parent znode. Root znode parent pointer points
+      to its father: "fake" znode. This, in turn, has NULL parent pointer.
+    . hash table linkage
+    . no data loaded from disk
+    . no node plugin
+    . no sibling linkage
+
+   2. His childhood
+
+   Each node is either brought into memory as a result of tree traversal, or
+   created afresh, creation of the root being a special case of the latter. In
+   either case it's inserted into sibling list. This will typically require
+   some ancillary tree traversing, but ultimately both sibling pointers will
+   exist and JNODE_LEFT_CONNECTED and JNODE_RIGHT_CONNECTED will be true in
+   zjnode.state.
+
+   3. His youth.
+
+   If znode is bound to already existing node in a tree, its content is read
+   from the disk by call to zload(). At that moment, JNODE_LOADED bit is set
+   in zjnode.state and zdata() function starts to return non null for this
+   znode. zload() further calls zparse() that determines which node layout
+   this node is rendered in, and sets ->nplug on success.
+
+   If znode is for new node just created, memory for it is allocated and
+   zinit_new() function is called to initialise data, according to selected
+   node layout.
+
+   4. His maturity.
+
+   After this point, znode lingers in memory for some time. Threads can
+   acquire references to znode either by blocknr through call to zget(), or by
+   following a pointer to unallocated znode from internal item. Each time
+   reference to znode is obtained, x_count is increased. Thread can read/write
+   lock znode. Znode data can be loaded through calls to zload(), d_count will
+   be increased appropriately. If all references to znode are released
+   (x_count drops to 0), znode is not recycled immediately. Rather, it is
+   still cached in the hash table in the hope that it will be accessed
+   shortly.
+
+   There are two ways in which znode existence can be terminated:
+
+    . sudden death: node bound to this znode is removed from the tree
+    . overpopulation: znode is purged out of memory due to memory pressure
+
+   5. His death.
+
+   Death is complex process.
+
+   When we irrevocably commit ourselves to decision to remove node from the
+   tree, JNODE_HEARD_BANSHEE bit is set in zjnode.state of corresponding
+   znode. This is done either in ->kill_hook() of internal item or in
+   kill_root() function when tree root is removed.
+
+   At this moment znode still has:
+
+    . locks held on it, necessary write ones
+    . references to it
+    . disk block assigned to it
+    . data loaded from the disk
+    . pending requests for lock
+
+   But once JNODE_HEARD_BANSHEE bit set, last call to unlock_znode() does node
+   deletion. Node deletion includes two phases. First all ways to get
+   references to that znode (sibling and parent links and hash lookup using
+   block number stored in parent node) should be deleted -- it is done through
+   sibling_list_remove(), also we assume that nobody uses down link from
+   parent node due to its nonexistence or proper parent node locking and
+   nobody uses parent pointers from children due to absence of them. Second we
+   invalidate all pending lock requests which still are on znode's lock
+   request queue, this is done by invalidate_lock(). Another JNODE_IS_DYING
+   znode status bit is used to invalidate pending lock requests. Once it set
+   all requesters are forced to return -EINVAL from
+   longterm_lock_znode(). Future locking attempts are not possible because all
+   ways to get references to that znode are removed already. Last, node is
+   uncaptured from transaction.
+
+   When last reference to the dying znode is just about to be released,
+   block number for this lock is released and znode is removed from the
+   hash table.
+
+   Now znode can be recycled.
+
+   [it's possible to free bitmap block and remove znode from the hash
+   table when last lock is released. This will result in having
+   referenced but completely orphaned znode]
+
+   6. Limbo
+
+   As have been mentioned above znodes with reference counter 0 are
+   still cached in a hash table. Once memory pressure increases they are
+   purged out of there [this requires something like LRU list for
+   efficient implementation. LRU list would also greatly simplify
+   implementation of coord cache that would in this case morph to just
+   scanning some initial segment of LRU list]. Data loaded into
+   unreferenced znode are flushed back to the durable storage if
+   necessary and memory is freed. Znodes themselves can be recycled at
+   this point too.
+
+*/
+
+#include "debug.h"
+#include "dformat.h"
+#include "key.h"
+#include "coord.h"
+#include "plugin/plugin_header.h"
+#include "plugin/node/node.h"
+#include "plugin/plugin.h"
+#include "txnmgr.h"
+#include "jnode.h"
+#include "znode.h"
+#include "block_alloc.h"
+#include "tree.h"
+#include "tree_walk.h"
+#include "super.h"
+#include "reiser4.h"
+
+#include <linux/pagemap.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+static z_hash_table *get_htable(reiser4_tree *,
+				const reiser4_block_nr * const blocknr);
+static z_hash_table *znode_get_htable(const znode *);
+static void zdrop(znode *);
+
+/* hash table support */
+
+/* compare two block numbers for equality. Used by hash-table macros */
+static inline int
+blknreq(const reiser4_block_nr * b1, const reiser4_block_nr * b2)
+{
+	assert("nikita-534", b1 != NULL);
+	assert("nikita-535", b2 != NULL);
+
+	return *b1 == *b2;
+}
+
+/* Hash znode by block number. Used by hash-table macros */
+/* Audited by: umka (2002.06.11) */
+static inline __u32
+blknrhashfn(z_hash_table * table, const reiser4_block_nr * b)
+{
+	assert("nikita-536", b != NULL);
+
+	return *b & (REISER4_ZNODE_HASH_TABLE_SIZE - 1);
+}
+
+/* The hash table definition */
+#define KMALLOC(size) kmalloc((size), GFP_KERNEL)
+#define KFREE(ptr, size) kfree(ptr)
+TYPE_SAFE_HASH_DEFINE(z, znode, reiser4_block_nr, zjnode.key.z, zjnode.link.z,
+		      blknrhashfn, blknreq);
+#undef KFREE
+#undef KMALLOC
+
+/* slab for znodes */
+static kmem_cache_t *znode_cache;
+
+int znode_shift_order;
+
+/**
+ * init_znodes - create znode cache
+ *
+ * Initializes slab cache of znodes. It is part of reiser4 module initialization.
+ */
+int init_znodes(void)
+{
+	znode_cache = kmem_cache_create("znode", sizeof(znode), 0,
+					SLAB_HWCACHE_ALIGN |
+					SLAB_RECLAIM_ACCOUNT, NULL, NULL);
+	if (znode_cache == NULL)
+		return RETERR(-ENOMEM);
+
+	for (znode_shift_order = 0; (1 << znode_shift_order) < sizeof(znode);
+	     ++znode_shift_order);
+	--znode_shift_order;
+	return 0;
+}
+
+/**
+ * done_znodes - delete znode cache
+ *
+ * This is called on reiser4 module unloading or system shutdown.
+ */
+void done_znodes(void)
+{
+	destroy_reiser4_cache(&znode_cache);
+}
+
+/* call this to initialise tree of znodes */
+int znodes_tree_init(reiser4_tree * tree /* tree to initialise znodes for */ )
+{
+	int result;
+	assert("umka-050", tree != NULL);
+
+	rwlock_init(&tree->dk_lock);
+
+	result = z_hash_init(&tree->zhash_table, REISER4_ZNODE_HASH_TABLE_SIZE);
+	if (result != 0)
+		return result;
+	result = z_hash_init(&tree->zfake_table, REISER4_ZNODE_HASH_TABLE_SIZE);
+	return result;
+}
+
+/* free this znode */
+void zfree(znode * node /* znode to free */ )
+{
+	assert("nikita-465", node != NULL);
+	assert("nikita-2120", znode_page(node) == NULL);
+	assert("nikita-2301", list_empty_careful(&node->lock.owners));
+	assert("nikita-2302", list_empty_careful(&node->lock.requestors));
+	assert("nikita-2663", (list_empty_careful(&ZJNODE(node)->capture_link) &&
+			       NODE_LIST(ZJNODE(node)) == NOT_CAPTURED));
+	assert("nikita-2773", !JF_ISSET(ZJNODE(node), JNODE_EFLUSH));
+	assert("nikita-3220", list_empty(&ZJNODE(node)->jnodes));
+	assert("nikita-3293", !znode_is_right_connected(node));
+	assert("nikita-3294", !znode_is_left_connected(node));
+	assert("nikita-3295", node->left == NULL);
+	assert("nikita-3296", node->right == NULL);
+
+	/* not yet phash_jnode_destroy(ZJNODE(node)); */
+
+	kmem_cache_free(znode_cache, node);
+}
+
+/* call this to free tree of znodes */
+void znodes_tree_done(reiser4_tree * tree /* tree to finish with znodes of */ )
+{
+	znode *node;
+	znode *next;
+	z_hash_table *ztable;
+
+	/* scan znode hash-tables and kill all znodes, then free hash tables
+	 * themselves. */
+
+	assert("nikita-795", tree != NULL);
+
+	ztable = &tree->zhash_table;
+
+	if (ztable->_table != NULL) {
+		for_all_in_htable(ztable, z, node, next) {
+			node->c_count = 0;
+			node->in_parent.node = NULL;
+			assert("nikita-2179", atomic_read(&ZJNODE(node)->x_count) == 0);
+			zdrop(node);
+		}
+
+		z_hash_done(&tree->zhash_table);
+	}
+
+	ztable = &tree->zfake_table;
+
+	if (ztable->_table != NULL) {
+		for_all_in_htable(ztable, z, node, next) {
+			node->c_count = 0;
+			node->in_parent.node = NULL;
+			assert("nikita-2179", atomic_read(&ZJNODE(node)->x_count) == 0);
+			zdrop(node);
+		}
+
+		z_hash_done(&tree->zfake_table);
+	}
+}
+
+/* ZNODE STRUCTURES */
+
+/* allocate fresh znode */
+znode *zalloc(unsigned int gfp_flag /* allocation flag */ )
+{
+	znode *node;
+
+	node = kmem_cache_alloc(znode_cache, gfp_flag);
+	return node;
+}
+
+/* Initialize fields of znode
+   @node:    znode to initialize;
+   @parent:  parent znode;
+   @tree:    tree we are in. */
+void zinit(znode * node, const znode * parent, reiser4_tree * tree)
+{
+	assert("nikita-466", node != NULL);
+	assert("umka-268", current_tree != NULL);
+
+	memset(node, 0, sizeof *node);
+
+	assert("umka-051", tree != NULL);
+
+	jnode_init(&node->zjnode, tree, JNODE_FORMATTED_BLOCK);
+	reiser4_init_lock(&node->lock);
+	init_parent_coord(&node->in_parent, parent);
+}
+
+/*
+ * remove znode from indices. This is called jput() when last reference on
+ * znode is released.
+ */
+void znode_remove(znode * node /* znode to remove */ , reiser4_tree * tree)
+{
+	assert("nikita-2108", node != NULL);
+	assert("nikita-470", node->c_count == 0);
+	assert_rw_write_locked(&(tree->tree_lock));
+
+	/* remove reference to this znode from cbk cache */
+	cbk_cache_invalidate(node, tree);
+
+	/* update c_count of parent */
+	if (znode_parent(node) != NULL) {
+		assert("nikita-472", znode_parent(node)->c_count > 0);
+		/* father, onto your hands I forward my spirit... */
+		znode_parent(node)->c_count--;
+		node->in_parent.node = NULL;
+	} else {
+		/* orphaned znode?! Root? */
+	}
+
+	/* remove znode from hash-table */
+	z_hash_remove_rcu(znode_get_htable(node), node);
+}
+
+/* zdrop() -- Remove znode from the tree.
+
+   This is called when znode is removed from the memory. */
+static void zdrop(znode * node /* znode to finish with */ )
+{
+	jdrop(ZJNODE(node));
+}
+
+/*
+ * put znode into right place in the hash table. This is called by relocate
+ * code.
+ */
+int znode_rehash(znode * node /* node to rehash */ ,
+		 const reiser4_block_nr * new_block_nr /* new block number */ )
+{
+	z_hash_table *oldtable;
+	z_hash_table *newtable;
+	reiser4_tree *tree;
+
+	assert("nikita-2018", node != NULL);
+
+	tree = znode_get_tree(node);
+	oldtable = znode_get_htable(node);
+	newtable = get_htable(tree, new_block_nr);
+
+	write_lock_tree(tree);
+	/* remove znode from hash-table */
+	z_hash_remove_rcu(oldtable, node);
+
+	/* assertion no longer valid due to RCU */
+	/* assert("nikita-2019", z_hash_find(newtable, new_block_nr) == NULL); */
+
+	/* update blocknr */
+	znode_set_block(node, new_block_nr);
+	node->zjnode.key.z = *new_block_nr;
+
+	/* insert it into hash */
+	z_hash_insert_rcu(newtable, node);
+	write_unlock_tree(tree);
+	return 0;
+}
+
+/* ZNODE LOOKUP, GET, PUT */
+
+/* zlook() - get znode with given block_nr in a hash table or return NULL
+
+   If result is non-NULL then the znode's x_count is incremented.  Internal version
+   accepts pre-computed hash index.  The hash table is accessed under caller's
+   tree->hash_lock.
+*/
+znode *zlook(reiser4_tree * tree, const reiser4_block_nr * const blocknr)
+{
+	znode *result;
+	__u32 hash;
+	z_hash_table *htable;
+
+	assert("jmacd-506", tree != NULL);
+	assert("jmacd-507", blocknr != NULL);
+
+	htable = get_htable(tree, blocknr);
+	hash = blknrhashfn(htable, blocknr);
+
+	rcu_read_lock();
+	result = z_hash_find_index(htable, hash, blocknr);
+
+	if (result != NULL) {
+		add_x_ref(ZJNODE(result));
+		result = znode_rip_check(tree, result);
+	}
+	rcu_read_unlock();
+
+	return result;
+}
+
+/* return hash table where znode with block @blocknr is (or should be)
+ * stored */
+static z_hash_table *get_htable(reiser4_tree * tree,
+				const reiser4_block_nr * const blocknr)
+{
+	z_hash_table *table;
+	if (is_disk_addr_unallocated(blocknr))
+		table = &tree->zfake_table;
+	else
+		table = &tree->zhash_table;
+	return table;
+}
+
+/* return hash table where znode @node is (or should be) stored */
+static z_hash_table *znode_get_htable(const znode * node)
+{
+	return get_htable(znode_get_tree(node), znode_get_block(node));
+}
+
+/* zget() - get znode from hash table, allocating it if necessary.
+
+   First a call to zlook, locating a x-referenced znode if one
+   exists.  If znode is not found, allocate new one and return.  Result
+   is returned with x_count reference increased.
+
+   LOCKS TAKEN:   TREE_LOCK, ZNODE_LOCK
+   LOCK ORDERING: NONE
+*/
+znode *zget(reiser4_tree * tree,
+	    const reiser4_block_nr * const blocknr,
+	    znode * parent, tree_level level, int gfp_flag)
+{
+	znode *result;
+	__u32 hashi;
+
+	z_hash_table *zth;
+
+	assert("jmacd-512", tree != NULL);
+	assert("jmacd-513", blocknr != NULL);
+	assert("jmacd-514", level < REISER4_MAX_ZTREE_HEIGHT);
+
+	zth = get_htable(tree, blocknr);
+	hashi = blknrhashfn(zth, blocknr);
+
+	/* NOTE-NIKITA address-as-unallocated-blocknr still is not
+	   implemented. */
+
+	z_hash_prefetch_bucket(zth, hashi);
+
+	rcu_read_lock();
+	/* Find a matching BLOCKNR in the hash table.  If the znode is found,
+	   we obtain an reference (x_count) but the znode remains unlocked.
+	   Have to worry about race conditions later. */
+	result = z_hash_find_index(zth, hashi, blocknr);
+	/* According to the current design, the hash table lock protects new
+	   znode references. */
+	if (result != NULL) {
+		add_x_ref(ZJNODE(result));
+		/* NOTE-NIKITA it should be so, but special case during
+		   creation of new root makes such assertion highly
+		   complicated.  */
+		assert("nikita-2131", 1 || znode_parent(result) == parent ||
+		       (ZF_ISSET(result, JNODE_ORPHAN)
+			&& (znode_parent(result) == NULL)));
+		result = znode_rip_check(tree, result);
+	}
+
+	rcu_read_unlock();
+
+	if (!result) {
+		znode *shadow;
+
+		result = zalloc(gfp_flag);
+		if (!result) {
+			return ERR_PTR(RETERR(-ENOMEM));
+		}
+
+		zinit(result, parent, tree);
+		ZJNODE(result)->blocknr = *blocknr;
+		ZJNODE(result)->key.z = *blocknr;
+		result->level = level;
+
+		write_lock_tree(tree);
+
+		shadow = z_hash_find_index(zth, hashi, blocknr);
+		if (unlikely(shadow != NULL && !ZF_ISSET(shadow, JNODE_RIP))) {
+			jnode_list_remove(ZJNODE(result));
+			zfree(result);
+			result = shadow;
+		} else {
+			result->version = znode_build_version(tree);
+			z_hash_insert_index_rcu(zth, hashi, result);
+
+			if (parent != NULL)
+				++parent->c_count;
+		}
+
+		add_x_ref(ZJNODE(result));
+
+		write_unlock_tree(tree);
+	}
+#if REISER4_DEBUG
+	if (!blocknr_is_fake(blocknr) && *blocknr != 0)
+		reiser4_check_block(blocknr, 1);
+#endif
+	/* Check for invalid tree level, return -EIO */
+	if (unlikely(znode_get_level(result) != level)) {
+		warning("jmacd-504",
+			"Wrong level for cached block %llu: %i expecting %i",
+			(unsigned long long)(*blocknr), znode_get_level(result),
+			level);
+		zput(result);
+		return ERR_PTR(RETERR(-EIO));
+	}
+
+	assert("nikita-1227", znode_invariant(result));
+
+	return result;
+}
+
+/* ZNODE PLUGINS/DATA */
+
+/* "guess" plugin for node loaded from the disk. Plugin id of node plugin is
+   stored at the fixed offset from the beginning of the node. */
+static node_plugin *znode_guess_plugin(const znode * node	/* znode to guess
+								 * plugin of */ )
+{
+	reiser4_tree *tree;
+
+	assert("nikita-1053", node != NULL);
+	assert("nikita-1055", zdata(node) != NULL);
+
+	tree = znode_get_tree(node);
+	assert("umka-053", tree != NULL);
+
+	if (reiser4_is_set(tree->super, REISER4_ONE_NODE_PLUGIN)) {
+		return tree->nplug;
+	} else {
+		return node_plugin_by_disk_id
+		    (tree, &((common_node_header *) zdata(node))->plugin_id);
+#ifdef GUESS_EXISTS
+		reiser4_plugin *plugin;
+
+		/* NOTE-NIKITA add locking here when dynamic plugins will be
+		 * implemented */
+		for_all_plugins(REISER4_NODE_PLUGIN_TYPE, plugin) {
+			if ((plugin->u.node.guess != NULL)
+			    && plugin->u.node.guess(node))
+				return plugin;
+		}
+		warning("nikita-1057", "Cannot guess node plugin");
+		print_znode("node", node);
+		return NULL;
+#endif
+	}
+}
+
+/* parse node header and install ->node_plugin */
+int zparse(znode * node /* znode to parse */ )
+{
+	int result;
+
+	assert("nikita-1233", node != NULL);
+	assert("nikita-2370", zdata(node) != NULL);
+
+	if (node->nplug == NULL) {
+		node_plugin *nplug;
+
+		nplug = znode_guess_plugin(node);
+		if (likely(nplug != NULL)) {
+			result = nplug->parse(node);
+			if (likely(result == 0))
+				node->nplug = nplug;
+		} else {
+			result = RETERR(-EIO);
+		}
+	} else
+		result = 0;
+	return result;
+}
+
+/* zload with readahead */
+int zload_ra(znode * node /* znode to load */ , ra_info_t * info)
+{
+	int result;
+
+	assert("nikita-484", node != NULL);
+	assert("nikita-1377", znode_invariant(node));
+	assert("jmacd-7771", !znode_above_root(node));
+	assert("nikita-2125", atomic_read(&ZJNODE(node)->x_count) > 0);
+	assert("nikita-3016", schedulable());
+
+	if (info)
+		formatted_readahead(node, info);
+
+	result = jload(ZJNODE(node));
+	assert("nikita-1378", znode_invariant(node));
+	return result;
+}
+
+/* load content of node into memory */
+int zload(znode * node)
+{
+	return zload_ra(node, NULL);
+}
+
+/* call node plugin to initialise newly allocated node. */
+int zinit_new(znode * node /* znode to initialise */ , int gfp_flags)
+{
+	return jinit_new(ZJNODE(node), gfp_flags);
+}
+
+/* drop reference to node data. When last reference is dropped, data are
+   unloaded. */
+void zrelse(znode * node /* znode to release references to */ )
+{
+	assert("nikita-1381", znode_invariant(node));
+
+	jrelse(ZJNODE(node));
+}
+
+/* returns free space in node */
+unsigned znode_free_space(znode * node /* znode to query */ )
+{
+	assert("nikita-852", node != NULL);
+	return node_plugin_by_node(node)->free_space(node);
+}
+
+/* left delimiting key of znode */
+reiser4_key *znode_get_rd_key(znode * node /* znode to query */ )
+{
+	assert("nikita-958", node != NULL);
+	assert_rw_locked(&(znode_get_tree(node)->dk_lock));
+	assert("nikita-3067", LOCK_CNT_GTZ(rw_locked_dk));
+	assert("nikita-30671", node->rd_key_version != 0);
+	return &node->rd_key;
+}
+
+/* right delimiting key of znode */
+reiser4_key *znode_get_ld_key(znode * node /* znode to query */ )
+{
+	assert("nikita-974", node != NULL);
+	assert_rw_locked(&(znode_get_tree(node)->dk_lock));
+	assert("nikita-3068", LOCK_CNT_GTZ(rw_locked_dk));
+	assert("nikita-30681", node->ld_key_version != 0);
+	return &node->ld_key;
+}
+
+ON_DEBUG(atomic_t delim_key_version = ATOMIC_INIT(0);
+    )
+
+/* update right-delimiting key of @node */
+reiser4_key *znode_set_rd_key(znode * node, const reiser4_key * key)
+{
+	assert("nikita-2937", node != NULL);
+	assert("nikita-2939", key != NULL);
+	assert_rw_write_locked(&(znode_get_tree(node)->dk_lock));
+	assert("nikita-3069", LOCK_CNT_GTZ(write_locked_dk));
+	assert("nikita-2944",
+	       znode_is_any_locked(node) ||
+	       znode_get_level(node) != LEAF_LEVEL ||
+	       keyge(key, &node->rd_key) ||
+	       keyeq(&node->rd_key, min_key()) ||
+	       ZF_ISSET(node, JNODE_HEARD_BANSHEE));
+
+	node->rd_key = *key;
+	ON_DEBUG(node->rd_key_version = atomic_inc_return(&delim_key_version));
+	return &node->rd_key;
+}
+
+/* update left-delimiting key of @node */
+reiser4_key *znode_set_ld_key(znode * node, const reiser4_key * key)
+{
+	assert("nikita-2940", node != NULL);
+	assert("nikita-2941", key != NULL);
+	assert_rw_write_locked(&(znode_get_tree(node)->dk_lock));
+	assert("nikita-3070", LOCK_CNT_GTZ(write_locked_dk));
+	assert("nikita-2943",
+	       znode_is_any_locked(node) || keyeq(&node->ld_key, min_key()));
+
+	node->ld_key = *key;
+	ON_DEBUG(node->ld_key_version = atomic_inc_return(&delim_key_version));
+	return &node->ld_key;
+}
+
+/* true if @key is inside key range for @node */
+int znode_contains_key(znode * node /* znode to look in */ ,
+		       const reiser4_key * key /* key to look for */ )
+{
+	assert("nikita-1237", node != NULL);
+	assert("nikita-1238", key != NULL);
+
+	/* left_delimiting_key <= key <= right_delimiting_key */
+	return keyle(znode_get_ld_key(node), key)
+	    && keyle(key, znode_get_rd_key(node));
+}
+
+/* same as znode_contains_key(), but lock dk lock */
+int znode_contains_key_lock(znode * node /* znode to look in */ ,
+			    const reiser4_key * key /* key to look for */ )
+{
+	int result;
+
+	assert("umka-056", node != NULL);
+	assert("umka-057", key != NULL);
+
+	read_lock_dk(znode_get_tree(node));
+	result = znode_contains_key(node, key);
+	read_unlock_dk(znode_get_tree(node));
+	return result;
+}
+
+/* get parent pointer, assuming tree is not locked */
+znode *znode_parent_nolock(const znode * node /* child znode */ )
+{
+	assert("nikita-1444", node != NULL);
+	return node->in_parent.node;
+}
+
+/* get parent pointer of znode */
+znode *znode_parent(const znode * node /* child znode */ )
+{
+	assert("nikita-1226", node != NULL);
+	assert("nikita-1406", LOCK_CNT_GTZ(rw_locked_tree));
+	return znode_parent_nolock(node);
+}
+
+/* detect uber znode used to protect in-superblock tree root pointer */
+int znode_above_root(const znode * node /* znode to query */ )
+{
+	assert("umka-059", node != NULL);
+
+	return disk_addr_eq(&ZJNODE(node)->blocknr, &UBER_TREE_ADDR);
+}
+
+/* check that @node is root---that its block number is recorder in the tree as
+   that of root node */
+#if REISER4_DEBUG
+static int znode_is_true_root(const znode * node /* znode to query */ )
+{
+	assert("umka-060", node != NULL);
+	assert("umka-061", current_tree != NULL);
+
+	return disk_addr_eq(znode_get_block(node),
+			    &znode_get_tree(node)->root_block);
+}
+#endif
+
+/* check that @node is root */
+int znode_is_root(const znode * node /* znode to query */ )
+{
+	assert("nikita-1206", node != NULL);
+
+	return znode_get_level(node) == znode_get_tree(node)->height;
+}
+
+/* Returns true is @node was just created by zget() and wasn't ever loaded
+   into memory. */
+/* NIKITA-HANS: yes */
+int znode_just_created(const znode * node)
+{
+	assert("nikita-2188", node != NULL);
+	return (znode_page(node) == NULL);
+}
+
+/* obtain updated ->znode_epoch. See seal.c for description. */
+__u64 znode_build_version(reiser4_tree * tree)
+{
+	__u64 result;
+
+	spin_lock(&tree->epoch_lock);
+	result = ++tree->znode_epoch;
+	spin_unlock(&tree->epoch_lock);
+	return result;
+}
+
+void init_load_count(load_count * dh)
+{
+	assert("nikita-2105", dh != NULL);
+	memset(dh, 0, sizeof *dh);
+}
+
+void done_load_count(load_count * dh)
+{
+	assert("nikita-2106", dh != NULL);
+	if (dh->node != NULL) {
+		for (; dh->d_ref > 0; --dh->d_ref)
+			zrelse(dh->node);
+		dh->node = NULL;
+	}
+}
+
+static int incr_load_count(load_count * dh)
+{
+	int result;
+
+	assert("nikita-2110", dh != NULL);
+	assert("nikita-2111", dh->node != NULL);
+
+	result = zload(dh->node);
+	if (result == 0)
+		++dh->d_ref;
+	return result;
+}
+
+int incr_load_count_znode(load_count * dh, znode * node)
+{
+	assert("nikita-2107", dh != NULL);
+	assert("nikita-2158", node != NULL);
+	assert("nikita-2109",
+	       ergo(dh->node != NULL, (dh->node == node) || (dh->d_ref == 0)));
+
+	dh->node = node;
+	return incr_load_count(dh);
+}
+
+int incr_load_count_jnode(load_count * dh, jnode * node)
+{
+	if (jnode_is_znode(node)) {
+		return incr_load_count_znode(dh, JZNODE(node));
+	}
+	return 0;
+}
+
+void copy_load_count(load_count * new, load_count * old)
+{
+	int ret = 0;
+	done_load_count(new);
+	new->node = old->node;
+	new->d_ref = 0;
+
+	while ((new->d_ref < old->d_ref) && (ret = incr_load_count(new)) == 0) {
+	}
+
+	assert("jmacd-87589", ret == 0);
+}
+
+void move_load_count(load_count * new, load_count * old)
+{
+	done_load_count(new);
+	new->node = old->node;
+	new->d_ref = old->d_ref;
+	old->node = NULL;
+	old->d_ref = 0;
+}
+
+/* convert parent pointer into coord */
+void parent_coord_to_coord(const parent_coord_t * pcoord, coord_t * coord)
+{
+	assert("nikita-3204", pcoord != NULL);
+	assert("nikita-3205", coord != NULL);
+
+	coord_init_first_unit_nocheck(coord, pcoord->node);
+	coord_set_item_pos(coord, pcoord->item_pos);
+	coord->between = AT_UNIT;
+}
+
+/* pack coord into parent_coord_t */
+void coord_to_parent_coord(const coord_t * coord, parent_coord_t * pcoord)
+{
+	assert("nikita-3206", pcoord != NULL);
+	assert("nikita-3207", coord != NULL);
+
+	pcoord->node = coord->node;
+	pcoord->item_pos = coord->item_pos;
+}
+
+/* Initialize a parent hint pointer. (parent hint pointer is a field in znode,
+   look for comments there) */
+void init_parent_coord(parent_coord_t * pcoord, const znode * node)
+{
+	pcoord->node = (znode *) node;
+	pcoord->item_pos = (unsigned short)~0;
+}
+
+#if REISER4_DEBUG
+
+/* debugging aid: znode invariant */
+static int znode_invariant_f(const znode * node /* znode to check */ ,
+			     char const **msg	/* where to store error
+						 * message, if any */ )
+{
+#define _ergo(ant, con) 						\
+	((*msg) = "{" #ant "} ergo {" #con "}", ergo((ant), (con)))
+
+#define _equi(e1, e2) 						\
+	((*msg) = "{" #e1 "} <=> {" #e2 "}", equi((e1), (e2)))
+
+#define _check(exp) ((*msg) = #exp, (exp))
+
+	return jnode_invariant_f(ZJNODE(node), msg) &&
+	    /* [znode-fake] invariant */
+	    /* fake znode doesn't have a parent, and */
+	    _ergo(znode_get_level(node) == 0, znode_parent(node) == NULL) &&
+	    /* there is another way to express this very check, and */
+	    _ergo(znode_above_root(node), znode_parent(node) == NULL) &&
+	    /* it has special block number, and */
+	    _ergo(znode_get_level(node) == 0,
+		  disk_addr_eq(znode_get_block(node), &UBER_TREE_ADDR)) &&
+	    /* it is the only znode with such block number, and */
+	    _ergo(!znode_above_root(node) && znode_is_loaded(node),
+		  !disk_addr_eq(znode_get_block(node), &UBER_TREE_ADDR)) &&
+	    /* it is parent of the tree root node */
+	    _ergo(znode_is_true_root(node),
+		  znode_above_root(znode_parent(node))) &&
+	    /* [znode-level] invariant */
+	    /* level of parent znode is one larger than that of child,
+	       except for the fake znode, and */
+	    _ergo(znode_parent(node) && !znode_above_root(znode_parent(node)),
+		  znode_get_level(znode_parent(node)) ==
+		  znode_get_level(node) + 1) &&
+	    /* left neighbor is at the same level, and */
+	    _ergo(znode_is_left_connected(node) && node->left != NULL,
+		  znode_get_level(node) == znode_get_level(node->left)) &&
+	    /* right neighbor is at the same level */
+	    _ergo(znode_is_right_connected(node) && node->right != NULL,
+		  znode_get_level(node) == znode_get_level(node->right)) &&
+	    /* [znode-connected] invariant */
+	    _ergo(node->left != NULL, znode_is_left_connected(node)) &&
+	    _ergo(node->right != NULL, znode_is_right_connected(node)) &&
+	    _ergo(!znode_is_root(node) && node->left != NULL,
+		  znode_is_right_connected(node->left) &&
+		  node->left->right == node) &&
+	    _ergo(!znode_is_root(node) && node->right != NULL,
+		  znode_is_left_connected(node->right) &&
+		  node->right->left == node) &&
+	    /* [znode-c_count] invariant */
+	    /* for any znode, c_count of its parent is greater than 0 */
+	    _ergo(znode_parent(node) != NULL &&
+		  !znode_above_root(znode_parent(node)),
+		  znode_parent(node)->c_count > 0) &&
+	    /* leaves don't have children */
+	    _ergo(znode_get_level(node) == LEAF_LEVEL,
+		  node->c_count == 0) &&
+	    _check(node->zjnode.jnodes.prev != NULL) &&
+	    _check(node->zjnode.jnodes.next != NULL) &&
+	    /* orphan doesn't have a parent */
+	    _ergo(ZF_ISSET(node, JNODE_ORPHAN), znode_parent(node) == 0) &&
+	    /* [znode-modify] invariant */
+	    /* if znode is not write-locked, its checksum remains
+	     * invariant */
+	    /* unfortunately, zlock is unordered w.r.t. jnode_lock, so we
+	     * cannot check this. */
+	    /* [znode-refs] invariant */
+	    /* only referenced znode can be long-term locked */
+	    _ergo(znode_is_locked(node),
+		  atomic_read(&ZJNODE(node)->x_count) != 0);
+}
+
+/* debugging aid: check znode invariant and panic if it doesn't hold */
+int znode_invariant(znode * node /* znode to check */ )
+{
+	char const *failed_msg;
+	int result;
+
+	assert("umka-063", node != NULL);
+	assert("umka-064", current_tree != NULL);
+
+	spin_lock_znode(node);
+	read_lock_tree(znode_get_tree(node));
+	result = znode_invariant_f(node, &failed_msg);
+	if (!result) {
+		/* print_znode("corrupted node", node); */
+		warning("jmacd-555", "Condition %s failed", failed_msg);
+	}
+	read_unlock_tree(znode_get_tree(node));
+	spin_unlock_znode(node);
+	return result;
+}
+
+/* return non-0 iff data are loaded into znode */
+int znode_is_loaded(const znode * node /* znode to query */ )
+{
+	assert("nikita-497", node != NULL);
+	return jnode_is_loaded(ZJNODE(node));
+}
+
+unsigned long znode_times_locked(const znode * z)
+{
+	return z->times_locked;
+}
+
+#endif				/* REISER4_DEBUG */
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/reiser4/znode.h newtree/fs/reiser4/znode.h
--- oldtree/fs/reiser4/znode.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/reiser4/znode.h	2006-02-21 15:58:35.411763152 +0000
@@ -0,0 +1,434 @@
+/* Copyright 2001, 2002, 2003, 2004 by Hans Reiser, licensing governed by
+ * reiser4/README */
+
+/* Declaration of znode (Zam's node). See znode.c for more details. */
+
+#ifndef __ZNODE_H__
+#define __ZNODE_H__
+
+#include "forward.h"
+#include "debug.h"
+#include "dformat.h"
+#include "key.h"
+#include "coord.h"
+#include "plugin/node/node.h"
+#include "jnode.h"
+#include "lock.h"
+#include "readahead.h"
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/pagemap.h>	/* for PAGE_CACHE_SIZE */
+#include <asm/atomic.h>
+#include <asm/semaphore.h>
+
+/* znode tracks its position within parent (internal item in a parent node,
+ * that contains znode's block number). */
+typedef struct parent_coord {
+	znode *node;
+	pos_in_node_t item_pos;
+} parent_coord_t;
+
+/* &znode - node in a reiser4 tree.
+
+   NOTE-NIKITA fields in this struct have to be rearranged (later) to reduce
+   cacheline pressure.
+
+   Locking:
+
+   Long term: data in a disk node attached to this znode are protected
+   by long term, deadlock aware lock ->lock;
+
+   Spin lock: the following fields are protected by the spin lock:
+
+    ->lock
+
+   Following fields are protected by the global tree lock:
+
+    ->left
+    ->right
+    ->in_parent
+    ->c_count
+
+   Following fields are protected by the global delimiting key lock (dk_lock):
+
+    ->ld_key (to update ->ld_key long-term lock on the node is also required)
+    ->rd_key
+
+   Following fields are protected by the long term lock:
+
+    ->nr_items
+
+   ->node_plugin is never changed once set. This means that after code made
+   itself sure that field is valid it can be accessed without any additional
+   locking.
+
+   ->level is immutable.
+
+   Invariants involving this data-type:
+
+      [znode-fake]
+      [znode-level]
+      [znode-connected]
+      [znode-c_count]
+      [znode-refs]
+      [jnode-refs]
+      [jnode-queued]
+      [znode-modify]
+
+    For this to be made into a clustering or NUMA filesystem, we would want to eliminate all of the global locks.
+    Suggestions for how to do that are desired.*/
+struct znode {
+	/* Embedded jnode. */
+	jnode zjnode;
+
+	/* contains three subfields, node, pos_in_node, and pos_in_unit.
+
+	   pos_in_node and pos_in_unit are only hints that are cached to
+	   speed up lookups during balancing. They are not required to be up to
+	   date. Synched in find_child_ptr().
+
+	   This value allows us to avoid expensive binary searches.
+
+	   in_parent->node points to the parent of this node, and is NOT a
+	   hint.
+	 */
+	parent_coord_t in_parent;
+
+	/*
+	 * sibling list pointers
+	 */
+
+	/* left-neighbor */
+	znode *left;
+	/* right-neighbor */
+	znode *right;
+
+	/* long term lock on node content. This lock supports deadlock
+	   detection. See lock.c
+	 */
+	zlock lock;
+
+	/* You cannot remove from memory a node that has children in
+	   memory. This is because we rely on the fact that parent of given
+	   node can always be reached without blocking for io. When reading a
+	   node into memory you must increase the c_count of its parent, when
+	   removing it from memory you must decrease the c_count.  This makes
+	   the code simpler, and the cases where it is suboptimal are truly
+	   obscure.
+	 */
+	int c_count;
+
+	/* plugin of node attached to this znode. NULL if znode is not
+	   loaded. */
+	node_plugin *nplug;
+
+	/* version of znode data. This is increased on each modification. This
+	 * is necessary to implement seals (see seal.[ch]) efficiently. */
+	__u64 version;
+
+	/* left delimiting key. Necessary to efficiently perform
+	   balancing with node-level locking. Kept in memory only. */
+	reiser4_key ld_key;
+	/* right delimiting key. */
+	reiser4_key rd_key;
+
+	/* znode's tree level */
+	__u16 level;
+	/* number of items in this node. This field is modified by node
+	 * plugin. */
+	__u16 nr_items;
+
+#if REISER4_DEBUG
+	void *creator;
+	reiser4_key first_key;
+	unsigned long times_locked;
+	int left_version;	/* when node->left was updated */
+	int right_version;	/* when node->right was updated */
+	int ld_key_version;	/* when node->ld_key was updated */
+	int rd_key_version;	/* when node->rd_key was updated */
+#endif
+
+} __attribute__ ((aligned(16)));
+
+ON_DEBUG(extern atomic_t delim_key_version;
+    )
+
+/* In general I think these macros should not be exposed. */
+#define znode_is_locked(node)          (lock_is_locked(&node->lock))
+#define znode_is_rlocked(node)         (lock_is_rlocked(&node->lock))
+#define znode_is_wlocked(node)         (lock_is_wlocked(&node->lock))
+#define znode_is_wlocked_once(node)    (lock_is_wlocked_once(&node->lock))
+#define znode_can_be_rlocked(node)     (lock_can_be_rlocked(&node->lock))
+#define is_lock_compatible(node, mode) (lock_mode_compatible(&node->lock, mode))
+/* Macros for accessing the znode state. */
+#define	ZF_CLR(p,f)	        JF_CLR  (ZJNODE(p), (f))
+#define	ZF_ISSET(p,f)	        JF_ISSET(ZJNODE(p), (f))
+#define	ZF_SET(p,f)		JF_SET  (ZJNODE(p), (f))
+extern znode *zget(reiser4_tree * tree, const reiser4_block_nr * const block,
+		   znode * parent, tree_level level, int gfp_flag);
+extern znode *zlook(reiser4_tree * tree, const reiser4_block_nr * const block);
+extern int zload(znode * node);
+extern int zload_ra(znode * node, ra_info_t * info);
+extern int zinit_new(znode * node, int gfp_flags);
+extern void zrelse(znode * node);
+extern void znode_change_parent(znode * new_parent, reiser4_block_nr * block);
+
+/* size of data in znode */
+static inline unsigned
+znode_size(const znode * node UNUSED_ARG /* znode to query */ )
+{
+	assert("nikita-1416", node != NULL);
+	return PAGE_CACHE_SIZE;
+}
+
+extern void parent_coord_to_coord(const parent_coord_t * pcoord,
+				  coord_t * coord);
+extern void coord_to_parent_coord(const coord_t * coord,
+				  parent_coord_t * pcoord);
+extern void init_parent_coord(parent_coord_t * pcoord, const znode * node);
+
+extern unsigned znode_free_space(znode * node);
+
+extern reiser4_key *znode_get_rd_key(znode * node);
+extern reiser4_key *znode_get_ld_key(znode * node);
+
+extern reiser4_key *znode_set_rd_key(znode * node, const reiser4_key * key);
+extern reiser4_key *znode_set_ld_key(znode * node, const reiser4_key * key);
+
+/* `connected' state checks */
+static inline int znode_is_right_connected(const znode * node)
+{
+	return ZF_ISSET(node, JNODE_RIGHT_CONNECTED);
+}
+
+static inline int znode_is_left_connected(const znode * node)
+{
+	return ZF_ISSET(node, JNODE_LEFT_CONNECTED);
+}
+
+static inline int znode_is_connected(const znode * node)
+{
+	return znode_is_right_connected(node) && znode_is_left_connected(node);
+}
+
+extern int znode_shift_order;
+extern int znode_rehash(znode * node, const reiser4_block_nr * new_block_nr);
+extern void znode_remove(znode *, reiser4_tree *);
+extern znode *znode_parent(const znode * node);
+extern znode *znode_parent_nolock(const znode * node);
+extern int znode_above_root(const znode * node);
+extern int init_znodes(void);
+extern void done_znodes(void);
+extern int znodes_tree_init(reiser4_tree * ztree);
+extern void znodes_tree_done(reiser4_tree * ztree);
+extern int znode_contains_key(znode * node, const reiser4_key * key);
+extern int znode_contains_key_lock(znode * node, const reiser4_key * key);
+extern unsigned znode_save_free_space(znode * node);
+extern unsigned znode_recover_free_space(znode * node);
+extern znode *zalloc(unsigned int gfp_flag);
+extern void zinit(znode *, const znode * parent, reiser4_tree *);
+extern int zparse(znode * node);
+
+
+extern int znode_just_created(const znode * node);
+
+extern void zfree(znode * node);
+
+#if REISER4_DEBUG
+extern void print_znode(const char *prefix, const znode * node);
+#else
+#define print_znode( p, n ) noop
+#endif
+
+/* Make it look like various znode functions exist instead of treating znodes as
+   jnodes in znode-specific code. */
+#define znode_page(x)               jnode_page ( ZJNODE(x) )
+#define zdata(x)                    jdata ( ZJNODE(x) )
+#define znode_get_block(x)          jnode_get_block ( ZJNODE(x) )
+#define znode_created(x)            jnode_created ( ZJNODE(x) )
+#define znode_set_created(x)        jnode_set_created ( ZJNODE(x) )
+#define znode_convertible(x)        jnode_convertible (ZJNODE(x))
+#define znode_set_convertible(x)    jnode_set_convertible (ZJNODE(x))
+
+#define znode_is_dirty(x)           jnode_is_dirty    ( ZJNODE(x) )
+#define znode_check_dirty(x)        jnode_check_dirty ( ZJNODE(x) )
+#define znode_make_clean(x)         jnode_make_clean   ( ZJNODE(x) )
+#define znode_set_block(x, b)       jnode_set_block ( ZJNODE(x), (b) )
+
+#define spin_lock_znode(x)          spin_lock_jnode ( ZJNODE(x) )
+#define spin_unlock_znode(x)        spin_unlock_jnode ( ZJNODE(x) )
+#define spin_trylock_znode(x)       spin_trylock_jnode ( ZJNODE(x) )
+#define spin_znode_is_locked(x)     spin_jnode_is_locked ( ZJNODE(x) )
+#define spin_znode_is_not_locked(x) spin_jnode_is_not_locked ( ZJNODE(x) )
+
+#if REISER4_DEBUG
+extern int znode_x_count_is_protected(const znode * node);
+extern int znode_invariant(znode * node);
+#endif
+
+/* acquire reference to @node */
+static inline znode *zref(znode * node)
+{
+	/* change of x_count from 0 to 1 is protected by tree spin-lock */
+	return JZNODE(jref(ZJNODE(node)));
+}
+
+/* release reference to @node */
+static inline void zput(znode * node)
+{
+	assert("nikita-3564", znode_invariant(node));
+	jput(ZJNODE(node));
+}
+
+/* get the level field for a znode */
+static inline tree_level znode_get_level(const znode * node)
+{
+	return node->level;
+}
+
+/* get the level field for a jnode */
+static inline tree_level jnode_get_level(const jnode * node)
+{
+	if (jnode_is_znode(node))
+		return znode_get_level(JZNODE(node));
+	else
+		/* unformatted nodes are all at the LEAF_LEVEL and for
+		   "semi-formatted" nodes like bitmaps, level doesn't matter. */
+		return LEAF_LEVEL;
+}
+
+/* true if jnode is on leaf level */
+static inline int jnode_is_leaf(const jnode * node)
+{
+	if (jnode_is_znode(node))
+		return (znode_get_level(JZNODE(node)) == LEAF_LEVEL);
+	if (jnode_get_type(node) == JNODE_UNFORMATTED_BLOCK)
+		return 1;
+	return 0;
+}
+
+/* return znode's tree */
+static inline reiser4_tree *znode_get_tree(const znode * node)
+{
+	assert("nikita-2692", node != NULL);
+	return jnode_get_tree(ZJNODE(node));
+}
+
+/* resolve race with zput */
+static inline znode *znode_rip_check(reiser4_tree * tree, znode * node)
+{
+	jnode *j;
+
+	j = jnode_rip_sync(tree, ZJNODE(node));
+	if (likely(j != NULL))
+		node = JZNODE(j);
+	else
+		node = NULL;
+	return node;
+}
+
+#if defined(REISER4_DEBUG)
+int znode_is_loaded(const znode * node /* znode to query */ );
+#endif
+
+extern __u64 znode_build_version(reiser4_tree * tree);
+
+/* Data-handles.  A data handle object manages pairing calls to zload() and zrelse().  We
+   must load the data for a node in many places.  We could do this by simply calling
+   zload() everywhere, the difficulty arises when we must release the loaded data by
+   calling zrelse.  In a function with many possible error/return paths, it requires extra
+   work to figure out which exit paths must call zrelse and those which do not.  The data
+   handle automatically calls zrelse for every zload that it is responsible for.  In that
+   sense, it acts much like a lock_handle.
+*/
+typedef struct load_count {
+	znode *node;
+	int d_ref;
+} load_count;
+
+extern void init_load_count(load_count * lc);	/* Initialize a load_count set the current node to NULL. */
+extern void done_load_count(load_count * dh);	/* Finalize a load_count: call zrelse() if necessary */
+extern int incr_load_count_znode(load_count * dh, znode * node);	/* Set the argument znode to the current node, call zload(). */
+extern int incr_load_count_jnode(load_count * dh, jnode * node);	/* If the argument jnode is formatted, do the same as
+									 * incr_load_count_znode, otherwise do nothing (unformatted nodes
+									 * don't require zload/zrelse treatment). */
+extern void move_load_count(load_count * new, load_count * old);	/* Move the contents of a load_count.  Old handle is released. */
+extern void copy_load_count(load_count * new, load_count * old);	/* Copy the contents of a load_count.  Old handle remains held. */
+
+/* Variable initializers for load_count. */
+#define INIT_LOAD_COUNT ( load_count * ){ .node = NULL, .d_ref = 0 }
+#define INIT_LOAD_COUNT_NODE( n ) ( load_count ){ .node = ( n ), .d_ref = 0 }
+/* A convenience macro for use in assertions or debug-only code, where loaded
+   data is only required to perform the debugging check.  This macro
+   encapsulates an expression inside a pair of calls to zload()/zrelse(). */
+#define WITH_DATA( node, exp )				\
+({							\
+	long __with_dh_result;				\
+	znode *__with_dh_node;				\
+							\
+	__with_dh_node = ( node );			\
+	__with_dh_result = zload( __with_dh_node );	\
+	if( __with_dh_result == 0 ) {			\
+		__with_dh_result = ( long )( exp );	\
+		zrelse( __with_dh_node );		\
+	}						\
+	__with_dh_result;				\
+})
+
+/* Same as above, but accepts a return value in case zload fails. */
+#define WITH_DATA_RET( node, ret, exp )			\
+({							\
+	int __with_dh_result;				\
+	znode *__with_dh_node;				\
+							\
+	__with_dh_node = ( node );			\
+	__with_dh_result = zload( __with_dh_node );	\
+	if( __with_dh_result == 0 ) {			\
+		__with_dh_result = ( int )( exp );	\
+		zrelse( __with_dh_node );		\
+	} else						\
+		__with_dh_result = ( ret );		\
+	__with_dh_result;				\
+})
+
+#define WITH_COORD(coord, exp)			\
+({						\
+	coord_t *__coord;			\
+						\
+	__coord = (coord);			\
+	coord_clear_iplug(__coord);		\
+	WITH_DATA(__coord->node, exp);		\
+})
+
+#if REISER4_DEBUG
+#define STORE_COUNTERS						\
+	lock_counters_info __entry_counters = *lock_counters()
+#define CHECK_COUNTERS						\
+ON_DEBUG_CONTEXT(						\
+({								\
+	__entry_counters.x_refs = lock_counters() -> x_refs;	\
+	__entry_counters.t_refs = lock_counters() -> t_refs;	\
+	__entry_counters.d_refs = lock_counters() -> d_refs;	\
+	assert("nikita-2159",					\
+	       !memcmp(&__entry_counters, lock_counters(),	\
+		       sizeof __entry_counters));		\
+}) )
+
+#else
+#define STORE_COUNTERS
+#define CHECK_COUNTERS noop
+#endif
+
+/* __ZNODE_H__ */
+#endif
+
+/* Make Linus happy.
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/
diff -urN oldtree/fs/relayfs/inode.c newtree/fs/relayfs/inode.c
--- oldtree/fs/relayfs/inode.c	2006-02-19 11:41:05.334532128 +0000
+++ newtree/fs/relayfs/inode.c	2006-02-21 15:58:11.950329832 +0000
@@ -32,6 +32,12 @@
 	.capabilities	= BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
 };
 
+static int relayfs_readpage(struct file *file, struct page *page);
+
+static struct address_space_operations relayfs_aops = {
+	.readpage       = relayfs_readpage,
+};
+
 static struct inode *relayfs_get_inode(struct super_block *sb,
 				       int mode,
  				       struct file_operations *fops,
@@ -48,6 +54,7 @@
 	inode->i_gid = 0;
 	inode->i_blksize = PAGE_CACHE_SIZE;
 	inode->i_blocks = 0;
+	inode->i_mapping->a_ops = &relayfs_aops;
 	inode->i_mapping->backing_dev_info = &relayfs_backing_dev_info;
 	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 	switch (mode & S_IFMT) {
@@ -505,8 +512,41 @@
 	.read		= relay_file_read,
 	.llseek		= no_llseek,
 	.release	= relay_file_release,
+	.sendfile       = generic_file_sendfile,
 };
 
+static int relayfs_readpage(struct file *file, struct page *page)
+{
+	struct rchan_buf *buf = file->private_data;
+	size_t buf_size = buf->chan->subbuf_size * buf->chan->n_subbufs;
+	size_t read_start, buf_nr_pages;
+	void *kaddr, *from;
+	pgoff_t page_idx;
+
+	if (PageUptodate(page))
+		goto out;
+
+	buf_nr_pages = buf_size / PAGE_CACHE_SIZE;
+	page_idx = page->index % buf_nr_pages;
+	read_start = page_idx * PAGE_CACHE_SIZE;
+	from = buf->start + read_start;
+
+	kaddr = kmap_atomic(page, KM_USER0);
+	memcpy(kaddr, from, PAGE_CACHE_SIZE);
+	kunmap_atomic(kaddr, KM_USER0);
+	flush_dcache_page(page);
+	SetPageUptodate(page);
+
+	buf->bytes_consumed += PAGE_CACHE_SIZE;
+	if (buf->bytes_consumed >= buf->chan->subbuf_size) {
+		relay_subbufs_consumed(buf->chan, buf->cpu, 1);
+		buf->bytes_consumed = 0;
+	}
+out:
+	unlock_page(page);
+	return 0;
+}
+
 static struct super_operations relayfs_ops = {
 	.statfs		= simple_statfs,
 	.drop_inode	= generic_delete_inode,
diff -urN oldtree/fs/relayfs/relay.c newtree/fs/relayfs/relay.c
--- oldtree/fs/relayfs/relay.c	2006-02-19 11:41:05.335531976 +0000
+++ newtree/fs/relayfs/relay.c	2006-02-21 15:58:11.951329680 +0000
@@ -353,6 +353,7 @@
 		old_subbuf = buf->subbufs_produced % buf->chan->n_subbufs;
 		buf->padding[old_subbuf] = buf->prev_padding;
 		buf->subbufs_produced++;
+		buf->dentry->d_inode->i_size += buf->chan->subbuf_size;
 		if (waitqueue_active(&buf->read_wait)) {
 			PREPARE_WORK(&buf->wake_readers, wakeup_readers, buf);
 			schedule_delayed_work(&buf->wake_readers, 1);
diff -urN oldtree/fs/seq_file.c newtree/fs/seq_file.c
--- oldtree/fs/seq_file.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/seq_file.c	2006-02-21 15:58:26.209162160 +0000
@@ -37,7 +37,7 @@
 		file->private_data = p;
 	}
 	memset(p, 0, sizeof(*p));
-	sema_init(&p->sem, 1);
+	mutex_init(&p->lock);
 	p->op = op;
 
 	/*
@@ -71,7 +71,7 @@
 	void *p;
 	int err = 0;
 
-	down(&m->sem);
+	mutex_lock(&m->lock);
 	/*
 	 * seq_file->op->..m_start/m_stop/m_next may do special actions
 	 * or optimisations based on the file->f_version, so we want to
@@ -164,7 +164,7 @@
 	else
 		*ppos += copied;
 	file->f_version = m->version;
-	up(&m->sem);
+	mutex_unlock(&m->lock);
 	return copied;
 Enomem:
 	err = -ENOMEM;
@@ -237,7 +237,7 @@
 	struct seq_file *m = (struct seq_file *)file->private_data;
 	long long retval = -EINVAL;
 
-	down(&m->sem);
+	mutex_lock(&m->lock);
 	m->version = file->f_version;
 	switch (origin) {
 		case 1:
@@ -260,7 +260,7 @@
 				}
 			}
 	}
-	up(&m->sem);
+	mutex_unlock(&m->lock);
 	file->f_version = m->version;
 	return retval;
 }
diff -urN oldtree/fs/super.c newtree/fs/super.c
--- oldtree/fs/super.c	2006-02-19 11:41:05.344530608 +0000
+++ newtree/fs/super.c	2006-02-21 15:58:24.499422080 +0000
@@ -37,6 +37,7 @@
 #include <linux/writeback.h>		/* for the emergency remount stuff */
 #include <linux/idr.h>
 #include <linux/kobject.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 
@@ -381,9 +382,9 @@
 void sync_filesystems(int wait)
 {
 	struct super_block *sb;
-	static DECLARE_MUTEX(mutex);
+	static DEFINE_MUTEX(mutex);
 
-	down(&mutex);		/* Could be down_interruptible */
+	mutex_lock(&mutex);		/* Could be down_interruptible */
 	spin_lock(&sb_lock);
 	list_for_each_entry(sb, &super_blocks, s_list) {
 		if (!sb->s_op->sync_fs)
@@ -412,7 +413,7 @@
 			goto restart;
 	}
 	spin_unlock(&sb_lock);
-	up(&mutex);
+	mutex_unlock(&mutex);
 }
 
 /**
@@ -683,9 +684,9 @@
 	 * will protect the lockfs code from trying to start a snapshot
 	 * while we are mounting
 	 */
-	down(&bdev->bd_mount_sem);
+	mutex_lock(&bdev->bd_mount_mutex);
 	s = sget(fs_type, test_bdev_super, set_bdev_super, bdev);
-	up(&bdev->bd_mount_sem);
+	mutex_unlock(&bdev->bd_mount_mutex);
 	if (IS_ERR(s))
 		goto out;
 
diff -urN oldtree/fs/sysfs/dir.c newtree/fs/sysfs/dir.c
--- oldtree/fs/sysfs/dir.c	2006-02-19 11:41:05.345530456 +0000
+++ newtree/fs/sysfs/dir.c	2006-02-21 15:58:12.329272224 +0000
@@ -43,6 +43,7 @@
 
 	memset(sd, 0, sizeof(*sd));
 	atomic_set(&sd->s_count, 1);
+	atomic_set(&sd->s_event, 0);
 	INIT_LIST_HEAD(&sd->s_children);
 	list_add(&sd->s_sibling, &parent_sd->s_children);
 	sd->s_element = element;
diff -urN oldtree/fs/sysfs/file.c newtree/fs/sysfs/file.c
--- oldtree/fs/sysfs/file.c	2006-02-19 11:41:05.346530304 +0000
+++ newtree/fs/sysfs/file.c	2006-02-21 15:58:12.788202456 +0000
@@ -6,6 +6,9 @@
 #include <linux/fsnotify.h>
 #include <linux/kobject.h>
 #include <linux/namei.h>
+#include <linux/poll.h>
+#include <linux/limits.h>
+
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 
@@ -14,6 +17,9 @@
 #define to_subsys(k) container_of(k,struct subsystem,kset.kobj)
 #define to_sattr(a) container_of(a,struct subsys_attribute,attr)
 
+/* used in crash dumps to help with debugging */
+static char last_sysfs_file[PATH_MAX];
+
 /*
  * Subsystem file operations.
  * These operations allow subsystems to have files that can be 
@@ -57,6 +63,7 @@
 	struct sysfs_ops	* ops;
 	struct semaphore	sem;
 	int			needs_read_fill;
+	int			event;
 };
 
 
@@ -72,6 +79,7 @@
  */
 static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
 {
+	struct sysfs_dirent * sd = dentry->d_fsdata;
 	struct attribute * attr = to_attr(dentry);
 	struct kobject * kobj = to_kobj(dentry->d_parent);
 	struct sysfs_ops * ops = buffer->ops;
@@ -83,6 +91,7 @@
 	if (!buffer->page)
 		return -ENOMEM;
 
+	buffer->event = atomic_read(&sd->s_event);
 	count = ops->show(kobj,attr,buffer->page);
 	buffer->needs_read_fill = 0;
 	BUG_ON(count > (ssize_t)PAGE_SIZE);
@@ -326,9 +335,18 @@
 
 static int sysfs_open_file(struct inode * inode, struct file * filp)
 {
+	char *p = d_path(filp->f_dentry, sysfs_mount, last_sysfs_file,
+			sizeof(last_sysfs_file));
+	if (p)
+		memmove(last_sysfs_file, p, strlen(p) + 1);
 	return check_perm(inode,filp);
 }
 
+void sysfs_printk_last_file(void)
+{
+	printk(KERN_EMERG "last sysfs file: %s\n", last_sysfs_file);
+}
+
 static int sysfs_release(struct inode * inode, struct file * filp)
 {
 	struct kobject * kobj = to_kobj(filp->f_dentry->d_parent);
@@ -349,12 +367,83 @@
 	return 0;
 }
 
+/* Sysfs attribute files are pollable.  The idea is that you read
+ * the content and then you use 'poll' or 'select' to wait for
+ * the content to change.  When the content changes (assuming the
+ * manager for the kobject supports notification), poll will
+ * return POLLERR|POLLPRI, and select will return the fd whether
+ * it is waiting for read, write, or exceptions.
+ * Once poll/select indicates that the value has changed, you
+ * need to close and re-open the file, as simply seeking and reading
+ * again will not get new data, or reset the state of 'poll'.
+ * Reminder: this only works for attributes which actively support
+ * it, and it is not possible to test an attribute from userspace
+ * to see if it supports poll.
+ */
+static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
+{
+	struct sysfs_buffer * buffer = filp->private_data;
+	struct kobject * kobj = to_kobj(filp->f_dentry->d_parent);
+	struct sysfs_dirent * sd = filp->f_dentry->d_fsdata;
+	int res = 0;
+
+	poll_wait(filp, &kobj->poll, wait);
+
+	if (buffer->event != atomic_read(&sd->s_event)) {
+		res = POLLERR|POLLPRI;
+		buffer->needs_read_fill = 1;
+	}
+
+	return res;
+}
+
+
+static struct dentry *step_down(struct dentry *dir, const char * name)
+{
+	struct dentry * de;
+
+	if (dir == NULL || dir->d_inode == NULL)
+		return NULL;
+
+	mutex_lock(&dir->d_inode->i_mutex);
+	de = lookup_one_len(name, dir, strlen(name));
+	mutex_unlock(&dir->d_inode->i_mutex);
+	dput(dir);
+	if (IS_ERR(de))
+		return NULL;
+	if (de->d_inode == NULL) {
+		dput(de);
+		return NULL;
+	}
+	return de;
+}
+
+void sysfs_notify(struct kobject * k, char *dir, char *attr)
+{
+	struct dentry *de = k->dentry;
+	if (de)
+		dget(de);
+	if (de && dir)
+		de = step_down(de, dir);
+	if (de && attr)
+		de = step_down(de, attr);
+	if (de) {
+		struct sysfs_dirent * sd = de->d_fsdata;
+		if (sd)
+			atomic_inc(&sd->s_event);
+		wake_up_interruptible(&k->poll);
+		dput(de);
+	}
+}
+EXPORT_SYMBOL_GPL(sysfs_notify);
+
 struct file_operations sysfs_file_operations = {
 	.read		= sysfs_read_file,
 	.write		= sysfs_write_file,
 	.llseek		= generic_file_llseek,
 	.open		= sysfs_open_file,
 	.release	= sysfs_release,
+	.poll		= sysfs_poll,
 };
 
 
diff -urN oldtree/fs/sysfs/sysfs.h newtree/fs/sysfs/sysfs.h
--- oldtree/fs/sysfs/sysfs.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/sysfs/sysfs.h	2006-02-21 15:58:12.331271920 +0000
@@ -10,6 +10,7 @@
 
 extern int sysfs_add_file(struct dentry *, const struct attribute *, int);
 extern void sysfs_hash_and_remove(struct dentry * dir, const char * name);
+extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name);
 
 extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **);
 extern void sysfs_remove_subdir(struct dentry *);
diff -urN oldtree/fs/udf/balloc.c newtree/fs/udf/balloc.c
--- oldtree/fs/udf/balloc.c	2006-02-19 11:41:05.348530000 +0000
+++ newtree/fs/udf/balloc.c	2006-02-21 15:58:28.288846000 +0000
@@ -152,7 +152,7 @@
 	int bitmap_nr;
 	unsigned long overflow;
 
-	down(&sbi->s_alloc_sem);
+	mutex_lock(&sbi->s_alloc_mutex);
 	if (bloc.logicalBlockNum < 0 ||
 		(bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum))
 	{
@@ -211,7 +211,7 @@
 	sb->s_dirt = 1;
 	if (UDF_SB_LVIDBH(sb))
 		mark_buffer_dirty(UDF_SB_LVIDBH(sb));
-	up(&sbi->s_alloc_sem);
+	mutex_unlock(&sbi->s_alloc_mutex);
 	return;
 }
 
@@ -226,7 +226,7 @@
 	int nr_groups, bitmap_nr;
 	struct buffer_head *bh;
 
-	down(&sbi->s_alloc_sem);
+	mutex_lock(&sbi->s_alloc_mutex);
 	if (first_block < 0 || first_block >= UDF_SB_PARTLEN(sb, partition))
 		goto out;
 
@@ -275,7 +275,7 @@
 		mark_buffer_dirty(UDF_SB_LVIDBH(sb));
 	}
 	sb->s_dirt = 1;
-	up(&sbi->s_alloc_sem);
+	mutex_unlock(&sbi->s_alloc_mutex);
 	return alloc_count;
 }
 
@@ -291,7 +291,7 @@
 	int newblock = 0;
 
 	*err = -ENOSPC;
-	down(&sbi->s_alloc_sem);
+	mutex_lock(&sbi->s_alloc_mutex);
 
 repeat:
 	if (goal < 0 || goal >= UDF_SB_PARTLEN(sb, partition))
@@ -364,7 +364,7 @@
 	}
 	if (i >= (nr_groups*2))
 	{
-		up(&sbi->s_alloc_sem);
+		mutex_unlock(&sbi->s_alloc_mutex);
 		return newblock;
 	}
 	if (bit < sb->s_blocksize << 3)
@@ -373,7 +373,7 @@
 		bit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, group_start << 3);
 	if (bit >= sb->s_blocksize << 3)
 	{
-		up(&sbi->s_alloc_sem);
+		mutex_unlock(&sbi->s_alloc_mutex);
 		return 0;
 	}
 
@@ -387,7 +387,7 @@
 	 */
 	if (inode && DQUOT_ALLOC_BLOCK(inode, 1))
 	{
-		up(&sbi->s_alloc_sem);
+		mutex_unlock(&sbi->s_alloc_mutex);
 		*err = -EDQUOT;
 		return 0;
 	}
@@ -410,13 +410,13 @@
 		mark_buffer_dirty(UDF_SB_LVIDBH(sb));
 	}
 	sb->s_dirt = 1;
-	up(&sbi->s_alloc_sem);
+	mutex_unlock(&sbi->s_alloc_mutex);
 	*err = 0;
 	return newblock;
 
 error_return:
 	*err = -EIO;
-	up(&sbi->s_alloc_sem);
+	mutex_unlock(&sbi->s_alloc_mutex);
 	return 0;
 }
 
@@ -433,7 +433,7 @@
 	int8_t etype;
 	int i;
 
-	down(&sbi->s_alloc_sem);
+	mutex_lock(&sbi->s_alloc_mutex);
 	if (bloc.logicalBlockNum < 0 ||
 		(bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum))
 	{
@@ -666,7 +666,7 @@
 
 error_return:
 	sb->s_dirt = 1;
-	up(&sbi->s_alloc_sem);
+	mutex_unlock(&sbi->s_alloc_mutex);
 	return;
 }
 
@@ -692,7 +692,7 @@
 	else
 		return 0;
 
-	down(&sbi->s_alloc_sem);
+	mutex_lock(&sbi->s_alloc_mutex);
 	extoffset = sizeof(struct unallocSpaceEntry);
 	bloc = UDF_I_LOCATION(table);
 
@@ -736,7 +736,7 @@
 		mark_buffer_dirty(UDF_SB_LVIDBH(sb));
 		sb->s_dirt = 1;
 	}
-	up(&sbi->s_alloc_sem);
+	mutex_unlock(&sbi->s_alloc_mutex);
 	return alloc_count;
 }
 
@@ -761,7 +761,7 @@
 	else
 		return newblock;
 
-	down(&sbi->s_alloc_sem);
+	mutex_lock(&sbi->s_alloc_mutex);
 	if (goal < 0 || goal >= UDF_SB_PARTLEN(sb, partition))
 		goal = 0;
 
@@ -811,7 +811,7 @@
 	if (spread == 0xFFFFFFFF)
 	{
 		udf_release_data(goal_bh);
-		up(&sbi->s_alloc_sem);
+		mutex_unlock(&sbi->s_alloc_mutex);
 		return 0;
 	}
 
@@ -827,7 +827,7 @@
 	if (inode && DQUOT_ALLOC_BLOCK(inode, 1))
 	{
 		udf_release_data(goal_bh);
-		up(&sbi->s_alloc_sem);
+		mutex_unlock(&sbi->s_alloc_mutex);
 		*err = -EDQUOT;
 		return 0;
 	}
@@ -846,7 +846,7 @@
 	}
 
 	sb->s_dirt = 1;
-	up(&sbi->s_alloc_sem);
+	mutex_unlock(&sbi->s_alloc_mutex);
 	*err = 0;
 	return newblock;
 }
diff -urN oldtree/fs/udf/ialloc.c newtree/fs/udf/ialloc.c
--- oldtree/fs/udf/ialloc.c	2006-02-19 11:41:05.350529696 +0000
+++ newtree/fs/udf/ialloc.c	2006-02-21 15:58:28.291845544 +0000
@@ -42,7 +42,7 @@
 
 	clear_inode(inode);
 
-	down(&sbi->s_alloc_sem);
+	mutex_lock(&sbi->s_alloc_mutex);
 	if (sbi->s_lvidbh) {
 		if (S_ISDIR(inode->i_mode))
 			UDF_SB_LVIDIU(sb)->numDirs =
@@ -53,7 +53,7 @@
 		
 		mark_buffer_dirty(sbi->s_lvidbh);
 	}
-	up(&sbi->s_alloc_sem);
+	mutex_unlock(&sbi->s_alloc_mutex);
 
 	udf_free_blocks(sb, NULL, UDF_I_LOCATION(inode), 0, 1);
 }
@@ -83,7 +83,7 @@
 		return NULL;
 	}
 
-	down(&sbi->s_alloc_sem);
+	mutex_lock(&sbi->s_alloc_mutex);
 	UDF_I_UNIQUE(inode) = 0;
 	UDF_I_LENEXTENTS(inode) = 0;
 	UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
@@ -148,7 +148,7 @@
 		UDF_I_CRTIME(inode) = current_fs_time(inode->i_sb);
 	insert_inode_hash(inode);
 	mark_inode_dirty(inode);
-	up(&sbi->s_alloc_sem);
+	mutex_unlock(&sbi->s_alloc_mutex);
 
 	if (DQUOT_ALLOC_INODE(inode))
 	{
diff -urN oldtree/fs/udf/super.c newtree/fs/udf/super.c
--- oldtree/fs/udf/super.c	2006-02-19 11:41:05.354529088 +0000
+++ newtree/fs/udf/super.c	2006-02-21 15:58:28.301844024 +0000
@@ -1499,7 +1499,7 @@
 	sb->s_fs_info = sbi;
 	memset(UDF_SB(sb), 0x00, sizeof(struct udf_sb_info));
 
-	init_MUTEX(&sbi->s_alloc_sem);
+	mutex_init(&sbi->s_alloc_mutex);
 
 	if (!udf_parse_options((char *)options, &uopt))
 		goto error_out;
diff -urN oldtree/fs/ufs/util.c newtree/fs/ufs/util.c
--- oldtree/fs/ufs/util.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/ufs/util.c	2006-02-21 15:58:36.675571024 +0000
@@ -206,14 +206,13 @@
 dev_t
 ufs_get_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi)
 {
-	__fs32 fs32;
+	__u32 fs32;
 	dev_t dev;
 
 	if ((UFS_SB(sb)->s_flags & UFS_ST_MASK) == UFS_ST_SUNx86)
-		fs32 = ufsi->i_u1.i_data[1];
+		fs32 = fs32_to_cpu(sb, ufsi->i_u1.i_data[1]);
 	else
-		fs32 = ufsi->i_u1.i_data[0];
-	fs32 = fs32_to_cpu(sb, fs32);
+		fs32 = fs32_to_cpu(sb, ufsi->i_u1.i_data[0]);
 	switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
 	case UFS_ST_SUNx86:
 	case UFS_ST_SUN:
@@ -234,7 +233,7 @@
 void
 ufs_set_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi, dev_t dev)
 {
-	__fs32 fs32;
+	__u32 fs32;
 
 	switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
 	case UFS_ST_SUNx86:
@@ -249,9 +248,8 @@
 		fs32 = old_encode_dev(dev);
 		break;
 	}
-	fs32 = cpu_to_fs32(sb, fs32);
 	if ((UFS_SB(sb)->s_flags & UFS_ST_MASK) == UFS_ST_SUNx86)
-		ufsi->i_u1.i_data[1] = fs32;
+		ufsi->i_u1.i_data[1] = cpu_to_fs32(sb, fs32);
 	else
-		ufsi->i_u1.i_data[0] = fs32;
+		ufsi->i_u1.i_data[0] = cpu_to_fs32(sb, fs32);
 }
diff -urN oldtree/fs/xattr.c newtree/fs/xattr.c
--- oldtree/fs/xattr.c	2006-02-19 11:41:05.361528024 +0000
+++ newtree/fs/xattr.c	2006-02-21 15:58:11.760358712 +0000
@@ -17,6 +17,7 @@
 #include <linux/syscalls.h>
 #include <linux/module.h>
 #include <linux/fsnotify.h>
+#include <linux/audit.h>
 #include <asm/uaccess.h>
 
 
@@ -234,12 +235,15 @@
 	      size_t size, int flags)
 {
 	struct file *f;
+	struct dentry *dentry;
 	int error = -EBADF;
 
 	f = fget(fd);
 	if (!f)
 		return error;
-	error = setxattr(f->f_dentry, name, value, size, flags);
+	dentry = f->f_dentry;
+	audit_inode(NULL, dentry->d_inode, 0);
+	error = setxattr(dentry, name, value, size, flags);
 	fput(f);
 	return error;
 }
@@ -458,12 +462,15 @@
 sys_fremovexattr(int fd, char __user *name)
 {
 	struct file *f;
+	struct dentry *dentry;
 	int error = -EBADF;
 
 	f = fget(fd);
 	if (!f)
 		return error;
-	error = removexattr(f->f_dentry, name);
+	dentry = f->f_dentry;
+	audit_inode(NULL, dentry->d_inode, 0);
+	error = removexattr(dentry, name);
 	fput(f);
 	return error;
 }
diff -urN oldtree/fs/xfs/linux-2.6/kmem.h newtree/fs/xfs/linux-2.6/kmem.h
--- oldtree/fs/xfs/linux-2.6/kmem.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/xfs/linux-2.6/kmem.h	2006-02-21 15:58:21.810830808 +0000
@@ -23,15 +23,8 @@
 #include <linux/mm.h>
 
 /*
- * memory management routines
+ * Process flags handling
  */
-#define KM_SLEEP	0x0001u
-#define KM_NOSLEEP	0x0002u
-#define KM_NOFS		0x0004u
-#define KM_MAYFAIL	0x0008u
-
-#define	kmem_zone	kmem_cache
-#define kmem_zone_t	struct kmem_cache
 
 typedef unsigned long xfs_pflags_t;
 
@@ -67,74 +60,102 @@
 	*(NSTATEP) = *(OSTATEP);	\
 } while (0)
 
-static __inline gfp_t kmem_flags_convert(unsigned int __nocast flags)
+/*
+ * General memory allocation interfaces
+ */
+
+#define KM_SLEEP	0x0001u
+#define KM_NOSLEEP	0x0002u
+#define KM_NOFS		0x0004u
+#define KM_MAYFAIL	0x0008u
+
+/*
+ * We use a special process flag to avoid recursive callbacks into
+ * the filesystem during transactions.  We will also issue our own
+ * warnings, so we explicitly skip any generic ones (silly of us).
+ */
+static inline gfp_t
+kmem_flags_convert(unsigned int __nocast flags)
 {
-	gfp_t	lflags = __GFP_NOWARN;	/* we'll report problems, if need be */
+	gfp_t	lflags;
 
-#ifdef DEBUG
-	if (unlikely(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS|KM_MAYFAIL))) {
-		printk(KERN_WARNING
-		    "XFS: memory allocation with wrong flags (%x)\n", flags);
-		BUG();
-	}
-#endif
+	BUG_ON(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS|KM_MAYFAIL));
 
 	if (flags & KM_NOSLEEP) {
-		lflags |= GFP_ATOMIC;
+		lflags = GFP_ATOMIC | __GFP_NOWARN;
 	} else {
-		lflags |= GFP_KERNEL;
-
-		/* avoid recusive callbacks to filesystem during transactions */
+		lflags = GFP_KERNEL | __GFP_NOWARN;
 		if (PFLAGS_TEST_FSTRANS() || (flags & KM_NOFS))
 			lflags &= ~__GFP_FS;
 	}
-
-        return lflags;
+	return lflags;
 }
 
-static __inline kmem_zone_t *
+extern void *kmem_alloc(size_t, unsigned int __nocast);
+extern void *kmem_realloc(void *, size_t, size_t, unsigned int __nocast);
+extern void *kmem_zalloc(size_t, unsigned int __nocast);
+extern void  kmem_free(void *, size_t);
+
+/*
+ * Zone interfaces
+ */
+
+#define KM_ZONE_HWALIGN	SLAB_HWCACHE_ALIGN
+#define KM_ZONE_RECLAIM	SLAB_RECLAIM_ACCOUNT
+#define KM_ZONE_SPREAD	0
+
+#define kmem_zone	kmem_cache
+#define kmem_zone_t	struct kmem_cache
+
+static inline kmem_zone_t *
 kmem_zone_init(int size, char *zone_name)
 {
 	return kmem_cache_create(zone_name, size, 0, 0, NULL, NULL);
 }
 
-static __inline void
+static inline kmem_zone_t *
+kmem_zone_init_flags(int size, char *zone_name, unsigned long flags,
+		     void (*construct)(void *, kmem_zone_t *, unsigned long))
+{
+	return kmem_cache_create(zone_name, size, 0, flags, construct, NULL);
+}
+
+static inline void
 kmem_zone_free(kmem_zone_t *zone, void *ptr)
 {
 	kmem_cache_free(zone, ptr);
 }
 
-static __inline void
+static inline void
 kmem_zone_destroy(kmem_zone_t *zone)
 {
 	if (zone && kmem_cache_destroy(zone))
 		BUG();
 }
 
-extern void *kmem_zone_zalloc(kmem_zone_t *, unsigned int __nocast);
 extern void *kmem_zone_alloc(kmem_zone_t *, unsigned int __nocast);
+extern void *kmem_zone_zalloc(kmem_zone_t *, unsigned int __nocast);
 
-extern void *kmem_alloc(size_t, unsigned int __nocast);
-extern void *kmem_realloc(void *, size_t, size_t, unsigned int __nocast);
-extern void *kmem_zalloc(size_t, unsigned int __nocast);
-extern void  kmem_free(void *, size_t);
+/*
+ * Low memory cache shrinkers
+ */
 
 typedef struct shrinker *kmem_shaker_t;
 typedef int (*kmem_shake_func_t)(int, gfp_t);
 
-static __inline kmem_shaker_t
+static inline kmem_shaker_t
 kmem_shake_register(kmem_shake_func_t sfunc)
 {
 	return set_shrinker(DEFAULT_SEEKS, sfunc);
 }
 
-static __inline void
+static inline void
 kmem_shake_deregister(kmem_shaker_t shrinker)
 {
 	remove_shrinker(shrinker);
 }
 
-static __inline int
+static inline int
 kmem_shake_allow(gfp_t gfp_mask)
 {
 	return (gfp_mask & __GFP_WAIT);
diff -urN oldtree/fs/xfs/linux-2.6/sema.h newtree/fs/xfs/linux-2.6/sema.h
--- oldtree/fs/xfs/linux-2.6/sema.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/xfs/linux-2.6/sema.h	2006-02-21 15:58:36.682569960 +0000
@@ -34,8 +34,11 @@
 #define initnsema(sp, val, name)	sema_init(sp, val)
 #define psema(sp, b)			down(sp)
 #define vsema(sp)			up(sp)
-#define valusema(sp)			(atomic_read(&(sp)->count))
 #define freesema(sema)
+static inline int sem_is_locked(sema_t *sp)
+{
+	return down_trylock(sp) || (up(sp), 0);
+}
 
 /*
  * Map cpsema (try to get the sema) to down_trylock. We need to switch
diff -urN oldtree/fs/xfs/linux-2.6/xfs_buf.c newtree/fs/xfs/linux-2.6/xfs_buf.c
--- oldtree/fs/xfs/linux-2.6/xfs_buf.c	2006-02-19 11:41:05.367527112 +0000
+++ newtree/fs/xfs/linux-2.6/xfs_buf.c	2006-02-21 15:58:21.820829288 +0000
@@ -1805,13 +1805,12 @@
 int __init
 xfs_buf_init(void)
 {
-	int		error = -ENOMEM;
-
 #ifdef XFS_BUF_TRACE
 	xfs_buf_trace_buf = ktrace_alloc(XFS_BUF_TRACE_SIZE, KM_SLEEP);
 #endif
 
-	xfs_buf_zone = kmem_zone_init(sizeof(xfs_buf_t), "xfs_buf");
+	xfs_buf_zone = kmem_zone_init_flags(sizeof(xfs_buf_t), "xfs_buf",
+						KM_ZONE_HWALIGN, NULL);
 	if (!xfs_buf_zone)
 		goto out_free_trace_buf;
 
@@ -1839,7 +1838,7 @@
 #ifdef XFS_BUF_TRACE
 	ktrace_free(xfs_buf_trace_buf);
 #endif
-	return error;
+	return -ENOMEM;
 }
 
 void
diff -urN oldtree/fs/xfs/linux-2.6/xfs_linux.h newtree/fs/xfs/linux-2.6/xfs_linux.h
--- oldtree/fs/xfs/linux-2.6/xfs_linux.h	2006-02-19 11:41:05.373526200 +0000
+++ newtree/fs/xfs/linux-2.6/xfs_linux.h	2006-02-21 15:58:21.824828680 +0000
@@ -100,6 +100,11 @@
  */
 #undef  HAVE_REFCACHE	/* reference cache not needed for NFS in 2.6 */
 #define HAVE_SENDFILE	/* sendfile(2) exists in 2.6, but not in 2.4 */
+#ifdef CONFIG_SMP
+#define HAVE_PERCPU_SB	/* per cpu superblock counters are a 2.6 feature */
+#else
+#undef  HAVE_PERCPU_SB	/* per cpu superblock counters are a 2.6 feature */
+#endif
 
 /*
  * State flag for unwritten extent buffers.
diff -urN oldtree/fs/xfs/linux-2.6/xfs_super.c newtree/fs/xfs/linux-2.6/xfs_super.c
--- oldtree/fs/xfs/linux-2.6/xfs_super.c	2006-02-19 11:41:05.376525744 +0000
+++ newtree/fs/xfs/linux-2.6/xfs_super.c	2006-02-21 15:58:30.959440008 +0000
@@ -76,8 +76,6 @@
 	strncpy(args->fsname, sb->s_id, MAXNAMELEN);
 
 	/* Copy the already-parsed mount(2) flags we're interested in */
-	if (sb->s_flags & MS_NOATIME)
-		args->flags |= XFSMNT_NOATIME;
 	if (sb->s_flags & MS_DIRSYNC)
 		args->flags |= XFSMNT_DIRSYNC;
 	if (sb->s_flags & MS_SYNCHRONOUS)
@@ -339,8 +337,8 @@
 {
 	vnode_t			*vp;
 
-	vp = kmem_cache_alloc(xfs_vnode_zone, kmem_flags_convert(KM_SLEEP));
-	if (!vp)
+	vp = kmem_zone_alloc(xfs_vnode_zone, KM_SLEEP);
+	if (unlikely(!vp))
 		return NULL;
 	return LINVFS_GET_IP(vp);
 }
@@ -354,23 +352,22 @@
 
 STATIC void
 linvfs_inode_init_once(
-	void			*data,
-	kmem_cache_t		*cachep,
+	void			*vnode,
+	kmem_zone_t		*zonep,
 	unsigned long		flags)
 {
-	vnode_t			*vp = (vnode_t *)data;
-
 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
-		inode_init_once(LINVFS_GET_IP(vp));
+		      SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(LINVFS_GET_IP((vnode_t *)vnode));
 }
 
 STATIC int
-linvfs_init_zones(void)
+xfs_init_zones(void)
 {
-	xfs_vnode_zone = kmem_cache_create("xfs_vnode",
-				sizeof(vnode_t), 0, SLAB_RECLAIM_ACCOUNT,
-				linvfs_inode_init_once, NULL);
+	xfs_vnode_zone = kmem_zone_init_flags(sizeof(vnode_t), "xfs_vnode_t",
+					KM_ZONE_HWALIGN | KM_ZONE_RECLAIM |
+					KM_ZONE_SPREAD,
+					linvfs_inode_init_once);
 	if (!xfs_vnode_zone)
 		goto out;
 
@@ -378,15 +375,12 @@
 	if (!xfs_ioend_zone)
 		goto out_destroy_vnode_zone;
 
-	xfs_ioend_pool = mempool_create(4 * MAX_BUF_PER_PAGE,
-			mempool_alloc_slab, mempool_free_slab,
-			xfs_ioend_zone);
+	xfs_ioend_pool = mempool_create_slab_pool(4 * MAX_BUF_PER_PAGE,
+						  xfs_ioend_zone);
 	if (!xfs_ioend_pool)
 		goto out_free_ioend_zone;
-
 	return 0;
 
-
  out_free_ioend_zone:
 	kmem_zone_destroy(xfs_ioend_zone);
  out_destroy_vnode_zone:
@@ -396,7 +390,7 @@
 }
 
 STATIC void
-linvfs_destroy_zones(void)
+xfs_destroy_zones(void)
 {
 	mempool_destroy(xfs_ioend_pool);
 	kmem_zone_destroy(xfs_vnode_zone);
@@ -407,7 +401,7 @@
  * Attempt to flush the inode, this will actually fail
  * if the inode is pinned, but we dirty the inode again
  * at the point when it is unpinned after a log write,
- * since this is when the inode itself becomes flushable. 
+ * since this is when the inode itself becomes flushable.
  */
 STATIC int
 linvfs_write_inode(
@@ -965,7 +959,7 @@
 
 	ktrace_init(64);
 
-	error = linvfs_init_zones();
+	error = xfs_init_zones();
 	if (error < 0)
 		goto undo_zones;
 
@@ -988,7 +982,7 @@
 	xfs_buf_terminate();
 
 undo_buffers:
-	linvfs_destroy_zones();
+	xfs_destroy_zones();
 
 undo_zones:
 	return error;
@@ -1002,7 +996,7 @@
 	unregister_filesystem(&xfs_fs_type);
 	xfs_cleanup();
 	xfs_buf_terminate();
-	linvfs_destroy_zones();
+	xfs_destroy_zones();
 	ktrace_uninit();
 }
 
diff -urN oldtree/fs/xfs/quota/xfs_dquot.h newtree/fs/xfs/quota/xfs_dquot.h
--- oldtree/fs/xfs/quota/xfs_dquot.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/xfs/quota/xfs_dquot.h	2006-02-21 15:58:36.683569808 +0000
@@ -119,7 +119,7 @@
  */
 #define xfs_dqflock(dqp)	 { psema(&((dqp)->q_flock), PINOD | PRECALC);\
 				   (dqp)->dq_flags |= XFS_DQ_FLOCKED; }
-#define xfs_dqfunlock(dqp)	 { ASSERT(valusema(&((dqp)->q_flock)) <= 0); \
+#define xfs_dqfunlock(dqp)	 { ASSERT(sem_is_locked(&((dqp)->q_flock))); \
 				   vsema(&((dqp)->q_flock)); \
 				   (dqp)->dq_flags &= ~(XFS_DQ_FLOCKED); }
 
@@ -128,7 +128,7 @@
 #define XFS_DQ_PINUNLOCK(dqp, s)   mutex_spinunlock( \
 				     &(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s)
 
-#define XFS_DQ_IS_FLUSH_LOCKED(dqp) (valusema(&((dqp)->q_flock)) <= 0)
+#define XFS_DQ_IS_FLUSH_LOCKED(dqp) (sem_is_locked(&((dqp)->q_flock)))
 #define XFS_DQ_IS_ON_FREELIST(dqp)  ((dqp)->dq_flnext != (dqp))
 #define XFS_DQ_IS_DIRTY(dqp)	((dqp)->dq_flags & XFS_DQ_DIRTY)
 #define XFS_QM_ISUDQ(dqp)	((dqp)->dq_flags & XFS_DQ_USER)
diff -urN oldtree/fs/xfs/quota/xfs_dquot_item.c newtree/fs/xfs/quota/xfs_dquot_item.c
--- oldtree/fs/xfs/quota/xfs_dquot_item.c	2006-02-19 11:41:05.380525136 +0000
+++ newtree/fs/xfs/quota/xfs_dquot_item.c	2006-02-21 15:58:36.689568896 +0000
@@ -246,7 +246,7 @@
 	 * inode flush completed and the inode was taken off the AIL.
 	 * So, just get out.
 	 */
-	if ((valusema(&(dqp->q_flock)) > 0)  ||
+	if (!sem_is_locked(&(dqp->q_flock))  ||
 	    ((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) {
 		qip->qli_pushbuf_flag = 0;
 		xfs_dqunlock(dqp);
@@ -259,7 +259,7 @@
 	if (bp != NULL) {
 		if (XFS_BUF_ISDELAYWRITE(bp)) {
 			dopush = ((qip->qli_item.li_flags & XFS_LI_IN_AIL) &&
-				  (valusema(&(dqp->q_flock)) <= 0));
+				  sem_is_locked(&(dqp->q_flock)));
 			qip->qli_pushbuf_flag = 0;
 			xfs_dqunlock(dqp);
 
diff -urN oldtree/fs/xfs/quota/xfs_qm.c newtree/fs/xfs/quota/xfs_qm.c
--- oldtree/fs/xfs/quota/xfs_qm.c	2006-02-19 11:41:05.382524832 +0000
+++ newtree/fs/xfs/quota/xfs_qm.c	2006-02-21 15:58:21.832827464 +0000
@@ -2789,9 +2789,7 @@
 		xfs_qm_dqdestroy(dqp);
 		dqp = nextdqp;
 	}
-	/*
-	 * Don't bother about unlocking.
-	 */
+	mutex_unlock(&ql->qh_lock);
 	mutex_destroy(&ql->qh_lock);
 
 	ASSERT(ql->qh_nelems == 0);
diff -urN oldtree/fs/xfs/xfs_attr.c newtree/fs/xfs/xfs_attr.c
--- oldtree/fs/xfs/xfs_attr.c	2006-02-19 11:41:05.388523920 +0000
+++ newtree/fs/xfs/xfs_attr.c	2006-02-21 15:58:36.700567224 +0000
@@ -1127,8 +1127,7 @@
 		return(error);
 	ASSERT(bp != NULL);
 	leaf = bp->data;
-	if (unlikely(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
-						!= XFS_ATTR_LEAF_MAGIC)) {
+	if (unlikely(be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC)) {
 		XFS_CORRUPTION_ERROR("xfs_attr_leaf_list", XFS_ERRLEVEL_LOW,
 				     context->dp->i_mount, leaf);
 		xfs_da_brelse(NULL, bp);
@@ -1541,8 +1540,8 @@
 						     XFS_ATTR_FORK);
 		if (error)
 			goto out;
-		ASSERT(INT_GET(((xfs_attr_leafblock_t *)
-				      bp->data)->hdr.info.magic, ARCH_CONVERT)
+		ASSERT(be16_to_cpu(((xfs_attr_leafblock_t *)
+				      bp->data)->hdr.info.magic)
 						       == XFS_ATTR_LEAF_MAGIC);
 
 		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
@@ -1763,7 +1762,7 @@
 			return(error);
 		if (bp) {
 			node = bp->data;
-			switch (INT_GET(node->hdr.info.magic, ARCH_CONVERT)) {
+			switch (be16_to_cpu(node->hdr.info.magic)) {
 			case XFS_DA_NODE_MAGIC:
 				xfs_attr_trace_l_cn("wrong blk", context, node);
 				xfs_da_brelse(NULL, bp);
@@ -1771,18 +1770,14 @@
 				break;
 			case XFS_ATTR_LEAF_MAGIC:
 				leaf = bp->data;
-				if (cursor->hashval >
-				    INT_GET(leaf->entries[
-					 INT_GET(leaf->hdr.count,
-						ARCH_CONVERT)-1].hashval,
-							ARCH_CONVERT)) {
+				if (cursor->hashval > be32_to_cpu(leaf->entries[
+				    be16_to_cpu(leaf->hdr.count)-1].hashval)) {
 					xfs_attr_trace_l_cl("wrong blk",
 							   context, leaf);
 					xfs_da_brelse(NULL, bp);
 					bp = NULL;
 				} else if (cursor->hashval <=
-					     INT_GET(leaf->entries[0].hashval,
-							ARCH_CONVERT)) {
+					     be32_to_cpu(leaf->entries[0].hashval)) {
 					xfs_attr_trace_l_cl("maybe wrong blk",
 							   context, leaf);
 					xfs_da_brelse(NULL, bp);
@@ -1817,10 +1812,10 @@
 				return(XFS_ERROR(EFSCORRUPTED));
 			}
 			node = bp->data;
-			if (INT_GET(node->hdr.info.magic, ARCH_CONVERT)
+			if (be16_to_cpu(node->hdr.info.magic)
 							== XFS_ATTR_LEAF_MAGIC)
 				break;
-			if (unlikely(INT_GET(node->hdr.info.magic, ARCH_CONVERT)
+			if (unlikely(be16_to_cpu(node->hdr.info.magic)
 							!= XFS_DA_NODE_MAGIC)) {
 				XFS_CORRUPTION_ERROR("xfs_attr_node_list(3)",
 						     XFS_ERRLEVEL_LOW,
@@ -1830,19 +1825,17 @@
 				return(XFS_ERROR(EFSCORRUPTED));
 			}
 			btree = node->btree;
-			for (i = 0;
-				i < INT_GET(node->hdr.count, ARCH_CONVERT);
+			for (i = 0; i < be16_to_cpu(node->hdr.count);
 								btree++, i++) {
 				if (cursor->hashval
-						<= INT_GET(btree->hashval,
-							    ARCH_CONVERT)) {
-					cursor->blkno = INT_GET(btree->before, ARCH_CONVERT);
+						<= be32_to_cpu(btree->hashval)) {
+					cursor->blkno = be32_to_cpu(btree->before);
 					xfs_attr_trace_l_cb("descending",
 							    context, btree);
 					break;
 				}
 			}
-			if (i == INT_GET(node->hdr.count, ARCH_CONVERT)) {
+			if (i == be16_to_cpu(node->hdr.count)) {
 				xfs_da_brelse(NULL, bp);
 				return(0);
 			}
@@ -1858,7 +1851,7 @@
 	 */
 	for (;;) {
 		leaf = bp->data;
-		if (unlikely(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
+		if (unlikely(be16_to_cpu(leaf->hdr.info.magic)
 						!= XFS_ATTR_LEAF_MAGIC)) {
 			XFS_CORRUPTION_ERROR("xfs_attr_node_list(4)",
 					     XFS_ERRLEVEL_LOW,
@@ -1869,7 +1862,7 @@
 		error = xfs_attr_leaf_list_int(bp, context);
 		if (error || !leaf->hdr.info.forw)
 			break;	/* not really an error, buffer full or EOF */
-		cursor->blkno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT);
+		cursor->blkno = be32_to_cpu(leaf->hdr.info.forw);
 		xfs_da_brelse(NULL, bp);
 		error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1,
 					      &bp, XFS_ATTR_FORK);
@@ -2232,9 +2225,10 @@
 				: 0,
 		(__psunsigned_t)context->dupcnt,
 		(__psunsigned_t)context->flags,
-		(__psunsigned_t)INT_GET(node->hdr.count, ARCH_CONVERT),
-		(__psunsigned_t)INT_GET(node->btree[0].hashval, ARCH_CONVERT),
-		(__psunsigned_t)INT_GET(node->btree[INT_GET(node->hdr.count, ARCH_CONVERT)-1].hashval, ARCH_CONVERT));
+		(__psunsigned_t)be16_to_cpu(node->hdr.count),
+		(__psunsigned_t)be32_to_cpu(node->btree[0].hashval),
+		(__psunsigned_t)be32_to_cpu(node->btree[
+				    be16_to_cpu(node->hdr.count)-1].hashval));
 }
 
 /*
@@ -2261,8 +2255,8 @@
 				: 0,
 		(__psunsigned_t)context->dupcnt,
 		(__psunsigned_t)context->flags,
-		(__psunsigned_t)INT_GET(btree->hashval, ARCH_CONVERT),
-		(__psunsigned_t)INT_GET(btree->before, ARCH_CONVERT),
+		(__psunsigned_t)be32_to_cpu(btree->hashval),
+		(__psunsigned_t)be32_to_cpu(btree->before),
 		(__psunsigned_t)NULL);
 }
 
@@ -2290,9 +2284,10 @@
 				: 0,
 		(__psunsigned_t)context->dupcnt,
 		(__psunsigned_t)context->flags,
-		(__psunsigned_t)INT_GET(leaf->hdr.count, ARCH_CONVERT),
-		(__psunsigned_t)INT_GET(leaf->entries[0].hashval, ARCH_CONVERT),
-		(__psunsigned_t)INT_GET(leaf->entries[INT_GET(leaf->hdr.count, ARCH_CONVERT)-1].hashval, ARCH_CONVERT));
+		(__psunsigned_t)be16_to_cpu(leaf->hdr.count),
+		(__psunsigned_t)be32_to_cpu(leaf->entries[0].hashval),
+		(__psunsigned_t)be32_to_cpu(leaf->entries[
+				be16_to_cpu(leaf->hdr.count)-1].hashval));
 }
 
 /*
diff -urN oldtree/fs/xfs/xfs_attr_leaf.c newtree/fs/xfs/xfs_attr_leaf.c
--- oldtree/fs/xfs/xfs_attr_leaf.c	2006-02-19 11:41:05.390523616 +0000
+++ newtree/fs/xfs/xfs_attr_leaf.c	2006-02-21 15:58:36.704566616 +0000
@@ -194,7 +194,7 @@
 	xfs_idata_realloc(dp, sizeof(*hdr), XFS_ATTR_FORK);
 	hdr = (xfs_attr_sf_hdr_t *)ifp->if_u1.if_data;
 	hdr->count = 0;
-	INT_SET(hdr->totsize, ARCH_CONVERT, sizeof(*hdr));
+	hdr->totsize = cpu_to_be16(sizeof(*hdr));
 	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);
 }
 
@@ -224,8 +224,7 @@
 	ASSERT(ifp->if_flags & XFS_IFINLINE);
 	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
 	sfe = &sf->list[0];
-	for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT);
-				sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
+	for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
 #ifdef DEBUG
 		if (sfe->namelen != args->namelen)
 			continue;
@@ -248,13 +247,13 @@
 	sfe = (xfs_attr_sf_entry_t *)((char *)sf + offset);
 
 	sfe->namelen = args->namelen;
-	INT_SET(sfe->valuelen, ARCH_CONVERT, args->valuelen);
+	sfe->valuelen = args->valuelen;
 	sfe->flags = (args->flags & ATTR_SECURE) ? XFS_ATTR_SECURE :
 			((args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0);
 	memcpy(sfe->nameval, args->name, args->namelen);
 	memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen);
-	INT_MOD(sf->hdr.count, ARCH_CONVERT, 1);
-	INT_MOD(sf->hdr.totsize, ARCH_CONVERT, size);
+	sf->hdr.count++;
+	be16_add(&sf->hdr.totsize, size);
 	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);
 
 	xfs_sbversion_add_attr2(mp, args->trans);
@@ -277,7 +276,7 @@
 	base = sizeof(xfs_attr_sf_hdr_t);
 	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
 	sfe = &sf->list[0];
-	end = INT_GET(sf->hdr.count, ARCH_CONVERT);
+	end = sf->hdr.count;
 	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
 					base += size, i++) {
 		size = XFS_ATTR_SF_ENTSIZE(sfe);
@@ -300,11 +299,11 @@
 	 * Fix up the attribute fork data, covering the hole
 	 */
 	end = base + size;
-	totsize = INT_GET(sf->hdr.totsize, ARCH_CONVERT);
+	totsize = be16_to_cpu(sf->hdr.totsize);
 	if (end != totsize)
 		memmove(&((char *)sf)[base], &((char *)sf)[end], totsize - end);
-	INT_MOD(sf->hdr.count, ARCH_CONVERT, -1);
-	INT_MOD(sf->hdr.totsize, ARCH_CONVERT, -size);
+	sf->hdr.count--;
+	be16_add(&sf->hdr.totsize, -size);
 
 	/*
 	 * Fix up the start offset of the attribute fork
@@ -360,7 +359,7 @@
 	ASSERT(ifp->if_flags & XFS_IFINLINE);
 	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
 	sfe = &sf->list[0];
-	for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT);
+	for (i = 0; i < sf->hdr.count;
 				sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
 		if (sfe->namelen != args->namelen)
 			continue;
@@ -391,7 +390,7 @@
 	ASSERT(args->dp->i_d.di_aformat == XFS_IFINLINE);
 	sf = (xfs_attr_shortform_t *)args->dp->i_afp->if_u1.if_data;
 	sfe = &sf->list[0];
-	for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT);
+	for (i = 0; i < sf->hdr.count;
 				sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
 		if (sfe->namelen != args->namelen)
 			continue;
@@ -404,14 +403,14 @@
 		    ((sfe->flags & XFS_ATTR_ROOT) != 0))
 			continue;
 		if (args->flags & ATTR_KERNOVAL) {
-			args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT);
+			args->valuelen = sfe->valuelen;
 			return(XFS_ERROR(EEXIST));
 		}
-		if (args->valuelen < INT_GET(sfe->valuelen, ARCH_CONVERT)) {
-			args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT);
+		if (args->valuelen < sfe->valuelen) {
+			args->valuelen = sfe->valuelen;
 			return(XFS_ERROR(ERANGE));
 		}
-		args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT);
+		args->valuelen = sfe->valuelen;
 		memcpy(args->value, &sfe->nameval[args->namelen],
 						    args->valuelen);
 		return(XFS_ERROR(EEXIST));
@@ -438,7 +437,7 @@
 	dp = args->dp;
 	ifp = dp->i_afp;
 	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
-	size = INT_GET(sf->hdr.totsize, ARCH_CONVERT);
+	size = be16_to_cpu(sf->hdr.totsize);
 	tmpbuffer = kmem_alloc(size, KM_SLEEP);
 	ASSERT(tmpbuffer != NULL);
 	memcpy(tmpbuffer, ifp->if_u1.if_data, size);
@@ -481,11 +480,11 @@
 	nargs.oknoent = 1;
 
 	sfe = &sf->list[0];
-	for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) {
+	for (i = 0; i < sf->hdr.count; i++) {
 		nargs.name = (char *)sfe->nameval;
 		nargs.namelen = sfe->namelen;
 		nargs.value = (char *)&sfe->nameval[nargs.namelen];
-		nargs.valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT);
+		nargs.valuelen = sfe->valuelen;
 		nargs.hashval = xfs_da_hashname((char *)sfe->nameval,
 						sfe->namelen);
 		nargs.flags = (sfe->flags & XFS_ATTR_SECURE) ? ATTR_SECURE :
@@ -514,11 +513,9 @@
 
 	sa = (xfs_attr_sf_sort_t *)a;
 	sb = (xfs_attr_sf_sort_t *)b;
-	if (INT_GET(sa->hash, ARCH_CONVERT)
-				< INT_GET(sb->hash, ARCH_CONVERT)) {
+	if (sa->hash < sb->hash) {
 		return(-1);
-	} else if (INT_GET(sa->hash, ARCH_CONVERT)
-				> INT_GET(sb->hash, ARCH_CONVERT)) {
+	} else if (sa->hash > sb->hash) {
 		return(1);
 	} else {
 		return(sa->entno - sb->entno);
@@ -560,10 +557,8 @@
 	 * If the buffer is large enough, do not bother with sorting.
 	 * Note the generous fudge factor of 16 overhead bytes per entry.
 	 */
-	if ((dp->i_afp->if_bytes + INT_GET(sf->hdr.count, ARCH_CONVERT) * 16)
-							< context->bufsize) {
-		for (i = 0, sfe = &sf->list[0];
-				i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) {
+	if ((dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize) {
+		for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
 			attrnames_t	*namesp;
 
 			if (((context->flags & ATTR_SECURE) != 0) !=
@@ -584,14 +579,13 @@
 			if (context->flags & ATTR_KERNOVAL) {
 				ASSERT(context->flags & ATTR_KERNAMELS);
 				context->count += namesp->attr_namelen +
-					INT_GET(sfe->namelen, ARCH_CONVERT) + 1;
+					sfe->namelen + 1;
 			}
 			else {
 				if (xfs_attr_put_listent(context, namesp,
 						   (char *)sfe->nameval,
 						   (int)sfe->namelen,
-						   (int)INT_GET(sfe->valuelen,
-								ARCH_CONVERT)))
+						   (int)sfe->valuelen))
 					break;
 			}
 			sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
@@ -603,7 +597,7 @@
 	/*
 	 * It didn't all fit, so we have to sort everything on hashval.
 	 */
-	sbsize = INT_GET(sf->hdr.count, ARCH_CONVERT) * sizeof(*sbuf);
+	sbsize = sf->hdr.count * sizeof(*sbuf);
 	sbp = sbuf = kmem_alloc(sbsize, KM_SLEEP);
 
 	/*
@@ -611,8 +605,7 @@
 	 * the relevant info from only those that match into a buffer.
 	 */
 	nsbuf = 0;
-	for (i = 0, sfe = &sf->list[0];
-			i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) {
+	for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
 		if (unlikely(
 		    ((char *)sfe < (char *)sf) ||
 		    ((char *)sfe >= ((char *)sf + dp->i_afp->if_bytes)))) {
@@ -636,8 +629,7 @@
 			continue;
 		}
 		sbp->entno = i;
-		INT_SET(sbp->hash, ARCH_CONVERT,
-			xfs_da_hashname((char *)sfe->nameval, sfe->namelen));
+		sbp->hash = xfs_da_hashname((char *)sfe->nameval, sfe->namelen);
 		sbp->name = (char *)sfe->nameval;
 		sbp->namelen = sfe->namelen;
 		/* These are bytes, and both on-disk, don't endian-flip */
@@ -660,12 +652,12 @@
 	cursor->initted = 1;
 	cursor->blkno = 0;
 	for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) {
-		if (INT_GET(sbp->hash, ARCH_CONVERT) == cursor->hashval) {
+		if (sbp->hash == cursor->hashval) {
 			if (cursor->offset == count) {
 				break;
 			}
 			count++;
-		} else if (INT_GET(sbp->hash, ARCH_CONVERT) > cursor->hashval) {
+		} else if (sbp->hash > cursor->hashval) {
 			break;
 		}
 	}
@@ -685,8 +677,8 @@
 			((sbp->flags & XFS_ATTR_ROOT) ? &attr_trusted :
 			  &attr_user);
 
-		if (cursor->hashval != INT_GET(sbp->hash, ARCH_CONVERT)) {
-			cursor->hashval = INT_GET(sbp->hash, ARCH_CONVERT);
+		if (cursor->hashval != sbp->hash) {
+			cursor->hashval = sbp->hash;
 			cursor->offset = 0;
 		}
 		if (context->flags & ATTR_KERNOVAL) {
@@ -696,7 +688,7 @@
 		} else {
 			if (xfs_attr_put_listent(context, namesp,
 					sbp->name, sbp->namelen,
-					INT_GET(sbp->valuelen, ARCH_CONVERT)))
+					sbp->valuelen))
 				break;
 		}
 		cursor->offset++;
@@ -720,12 +712,11 @@
 	int bytes, i;
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
 
 	entry = &leaf->entries[0];
 	bytes = sizeof(struct xfs_attr_sf_hdr);
-	for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) {
+	for (i = 0; i < be16_to_cpu(leaf->hdr.count); entry++, i++) {
 		if (entry->flags & XFS_ATTR_INCOMPLETE)
 			continue;		/* don't copy partial entries */
 		if (!(entry->flags & XFS_ATTR_LOCAL))
@@ -733,11 +724,11 @@
 		name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
 		if (name_loc->namelen >= XFS_ATTR_SF_ENTSIZE_MAX)
 			return(0);
-		if (INT_GET(name_loc->valuelen, ARCH_CONVERT) >= XFS_ATTR_SF_ENTSIZE_MAX)
+		if (be16_to_cpu(name_loc->valuelen) >= XFS_ATTR_SF_ENTSIZE_MAX)
 			return(0);
 		bytes += sizeof(struct xfs_attr_sf_entry)-1
 				+ name_loc->namelen
-				+ INT_GET(name_loc->valuelen, ARCH_CONVERT);
+				+ be16_to_cpu(name_loc->valuelen);
 	}
 	if ((dp->i_mount->m_flags & XFS_MOUNT_ATTR2) &&
 	    (bytes == sizeof(struct xfs_attr_sf_hdr)))
@@ -766,8 +757,7 @@
 	ASSERT(bp != NULL);
 	memcpy(tmpbuffer, bp->data, XFS_LBSIZE(dp->i_mount));
 	leaf = (xfs_attr_leafblock_t *)tmpbuffer;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
 	memset(bp->data, 0, XFS_LBSIZE(dp->i_mount));
 
 	/*
@@ -810,7 +800,7 @@
 	nargs.trans = args->trans;
 	nargs.oknoent = 1;
 	entry = &leaf->entries[0];
-	for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) {
+	for (i = 0; i < be16_to_cpu(leaf->hdr.count); entry++, i++) {
 		if (entry->flags & XFS_ATTR_INCOMPLETE)
 			continue;	/* don't copy partial entries */
 		if (!entry->nameidx)
@@ -820,8 +810,8 @@
 		nargs.name = (char *)name_loc->nameval;
 		nargs.namelen = name_loc->namelen;
 		nargs.value = (char *)&name_loc->nameval[nargs.namelen];
-		nargs.valuelen = INT_GET(name_loc->valuelen, ARCH_CONVERT);
-		nargs.hashval = INT_GET(entry->hashval, ARCH_CONVERT);
+		nargs.valuelen = be16_to_cpu(name_loc->valuelen);
+		nargs.hashval = be32_to_cpu(entry->hashval);
 		nargs.flags = (entry->flags & XFS_ATTR_SECURE) ? ATTR_SECURE :
 			      ((entry->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0);
 		xfs_attr_shortform_add(&nargs, forkoff);
@@ -875,13 +865,12 @@
 		goto out;
 	node = bp1->data;
 	leaf = bp2->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
 	/* both on-disk, don't endian-flip twice */
 	node->btree[0].hashval =
-		leaf->entries[INT_GET(leaf->hdr.count, ARCH_CONVERT)-1 ].hashval;
-	INT_SET(node->btree[0].before, ARCH_CONVERT, blkno);
-	INT_SET(node->hdr.count, ARCH_CONVERT, 1);
+		leaf->entries[be16_to_cpu(leaf->hdr.count)-1 ].hashval;
+	node->btree[0].before = cpu_to_be32(blkno);
+	node->hdr.count = cpu_to_be16(1);
 	xfs_da_log_buf(args->trans, bp1, 0, XFS_LBSIZE(dp->i_mount) - 1);
 	error = 0;
 out:
@@ -920,19 +909,16 @@
 	leaf = bp->data;
 	memset((char *)leaf, 0, XFS_LBSIZE(dp->i_mount));
 	hdr = &leaf->hdr;
-	INT_SET(hdr->info.magic, ARCH_CONVERT, XFS_ATTR_LEAF_MAGIC);
-	INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount));
+	hdr->info.magic = cpu_to_be16(XFS_ATTR_LEAF_MAGIC);
+	hdr->firstused = cpu_to_be16(XFS_LBSIZE(dp->i_mount));
 	if (!hdr->firstused) {
-		INT_SET(hdr->firstused, ARCH_CONVERT,
+		hdr->firstused = cpu_to_be16(
 			XFS_LBSIZE(dp->i_mount) - XFS_ATTR_LEAF_NAME_ALIGN);
 	}
 
-	INT_SET(hdr->freemap[0].base, ARCH_CONVERT,
-						sizeof(xfs_attr_leaf_hdr_t));
-	INT_SET(hdr->freemap[0].size, ARCH_CONVERT,
-					  INT_GET(hdr->firstused, ARCH_CONVERT)
-					- INT_GET(hdr->freemap[0].base,
-								ARCH_CONVERT));
+	hdr->freemap[0].base = cpu_to_be16(sizeof(xfs_attr_leaf_hdr_t));
+	hdr->freemap[0].size = cpu_to_be16(be16_to_cpu(hdr->firstused) -
+					   sizeof(xfs_attr_leaf_hdr_t));
 
 	xfs_da_log_buf(args->trans, bp, 0, XFS_LBSIZE(dp->i_mount) - 1);
 
@@ -1004,10 +990,9 @@
 	int tablesize, entsize, sum, tmp, i;
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
 	ASSERT((args->index >= 0)
-		&& (args->index <= INT_GET(leaf->hdr.count, ARCH_CONVERT)));
+		&& (args->index <= be16_to_cpu(leaf->hdr.count)));
 	hdr = &leaf->hdr;
 	entsize = xfs_attr_leaf_newentsize(args->namelen, args->valuelen,
 			   args->trans->t_mountp->m_sb.sb_blocksize, NULL);
@@ -1016,26 +1001,25 @@
 	 * Search through freemap for first-fit on new name length.
 	 * (may need to figure in size of entry struct too)
 	 */
-	tablesize = (INT_GET(hdr->count, ARCH_CONVERT) + 1)
+	tablesize = (be16_to_cpu(hdr->count) + 1)
 					* sizeof(xfs_attr_leaf_entry_t)
 					+ sizeof(xfs_attr_leaf_hdr_t);
 	map = &hdr->freemap[XFS_ATTR_LEAF_MAPSIZE-1];
 	for (sum = 0, i = XFS_ATTR_LEAF_MAPSIZE-1; i >= 0; map--, i--) {
-		if (tablesize > INT_GET(hdr->firstused, ARCH_CONVERT)) {
-			sum += INT_GET(map->size, ARCH_CONVERT);
+		if (tablesize > be16_to_cpu(hdr->firstused)) {
+			sum += be16_to_cpu(map->size);
 			continue;
 		}
 		if (!map->size)
 			continue;	/* no space in this map */
 		tmp = entsize;
-		if (INT_GET(map->base, ARCH_CONVERT)
-				< INT_GET(hdr->firstused, ARCH_CONVERT))
+		if (be16_to_cpu(map->base) < be16_to_cpu(hdr->firstused))
 			tmp += sizeof(xfs_attr_leaf_entry_t);
-		if (INT_GET(map->size, ARCH_CONVERT) >= tmp) {
+		if (be16_to_cpu(map->size) >= tmp) {
 			tmp = xfs_attr_leaf_add_work(bp, args, i);
 			return(tmp);
 		}
-		sum += INT_GET(map->size, ARCH_CONVERT);
+		sum += be16_to_cpu(map->size);
 	}
 
 	/*
@@ -1056,7 +1040,7 @@
 	 * After compaction, the block is guaranteed to have only one
 	 * free region, in freemap[0].  If it is not big enough, give up.
 	 */
-	if (INT_GET(hdr->freemap[0].size, ARCH_CONVERT)
+	if (be16_to_cpu(hdr->freemap[0].size)
 				< (entsize + sizeof(xfs_attr_leaf_entry_t)))
 		return(XFS_ERROR(ENOSPC));
 
@@ -1079,45 +1063,42 @@
 	int tmp, i;
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
 	hdr = &leaf->hdr;
 	ASSERT((mapindex >= 0) && (mapindex < XFS_ATTR_LEAF_MAPSIZE));
-	ASSERT((args->index >= 0)
-		&& (args->index <= INT_GET(hdr->count, ARCH_CONVERT)));
+	ASSERT((args->index >= 0) && (args->index <= be16_to_cpu(hdr->count)));
 
 	/*
 	 * Force open some space in the entry array and fill it in.
 	 */
 	entry = &leaf->entries[args->index];
-	if (args->index < INT_GET(hdr->count, ARCH_CONVERT)) {
-		tmp  = INT_GET(hdr->count, ARCH_CONVERT) - args->index;
+	if (args->index < be16_to_cpu(hdr->count)) {
+		tmp  = be16_to_cpu(hdr->count) - args->index;
 		tmp *= sizeof(xfs_attr_leaf_entry_t);
 		memmove((char *)(entry+1), (char *)entry, tmp);
 		xfs_da_log_buf(args->trans, bp,
 		    XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry)));
 	}
-	INT_MOD(hdr->count, ARCH_CONVERT, 1);
+	be16_add(&hdr->count, 1);
 
 	/*
 	 * Allocate space for the new string (at the end of the run).
 	 */
 	map = &hdr->freemap[mapindex];
 	mp = args->trans->t_mountp;
-	ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp));
-	ASSERT((INT_GET(map->base, ARCH_CONVERT) & 0x3) == 0);
-	ASSERT(INT_GET(map->size, ARCH_CONVERT) >=
+	ASSERT(be16_to_cpu(map->base) < XFS_LBSIZE(mp));
+	ASSERT((be16_to_cpu(map->base) & 0x3) == 0);
+	ASSERT(be16_to_cpu(map->size) >=
 		xfs_attr_leaf_newentsize(args->namelen, args->valuelen,
 					 mp->m_sb.sb_blocksize, NULL));
-	ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp));
-	ASSERT((INT_GET(map->size, ARCH_CONVERT) & 0x3) == 0);
-	INT_MOD(map->size, ARCH_CONVERT,
+	ASSERT(be16_to_cpu(map->size) < XFS_LBSIZE(mp));
+	ASSERT((be16_to_cpu(map->size) & 0x3) == 0);
+	be16_add(&map->size,
 		-xfs_attr_leaf_newentsize(args->namelen, args->valuelen,
 					  mp->m_sb.sb_blocksize, &tmp));
-	INT_SET(entry->nameidx, ARCH_CONVERT,
-					INT_GET(map->base, ARCH_CONVERT)
-				      + INT_GET(map->size, ARCH_CONVERT));
-	INT_SET(entry->hashval, ARCH_CONVERT, args->hashval);
+	entry->nameidx = cpu_to_be16(be16_to_cpu(map->base) +
+				     be16_to_cpu(map->size));
+	entry->hashval = cpu_to_be32(args->hashval);
 	entry->flags = tmp ? XFS_ATTR_LOCAL : 0;
 	entry->flags |= (args->flags & ATTR_SECURE) ? XFS_ATTR_SECURE :
 			((args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0);
@@ -1130,12 +1111,10 @@
 	}
 	xfs_da_log_buf(args->trans, bp,
 			  XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry)));
-	ASSERT((args->index == 0) || (INT_GET(entry->hashval, ARCH_CONVERT)
-						>= INT_GET((entry-1)->hashval,
-							    ARCH_CONVERT)));
-	ASSERT((args->index == INT_GET(hdr->count, ARCH_CONVERT)-1) ||
-	       (INT_GET(entry->hashval, ARCH_CONVERT)
-			    <= (INT_GET((entry+1)->hashval, ARCH_CONVERT))));
+	ASSERT((args->index == 0) ||
+	       (be32_to_cpu(entry->hashval) >= be32_to_cpu((entry-1)->hashval)));
+	ASSERT((args->index == be16_to_cpu(hdr->count)-1) ||
+	       (be32_to_cpu(entry->hashval) <= be32_to_cpu((entry+1)->hashval)));
 
 	/*
 	 * Copy the attribute name and value into the new space.
@@ -1149,10 +1128,10 @@
 	if (entry->flags & XFS_ATTR_LOCAL) {
 		name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index);
 		name_loc->namelen = args->namelen;
-		INT_SET(name_loc->valuelen, ARCH_CONVERT, args->valuelen);
+		name_loc->valuelen = cpu_to_be16(args->valuelen);
 		memcpy((char *)name_loc->nameval, args->name, args->namelen);
 		memcpy((char *)&name_loc->nameval[args->namelen], args->value,
-				   INT_GET(name_loc->valuelen, ARCH_CONVERT));
+				   be16_to_cpu(name_loc->valuelen));
 	} else {
 		name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index);
 		name_rmt->namelen = args->namelen;
@@ -1171,28 +1150,23 @@
 	/*
 	 * Update the control info for this leaf node
 	 */
-	if (INT_GET(entry->nameidx, ARCH_CONVERT)
-				< INT_GET(hdr->firstused, ARCH_CONVERT)) {
+	if (be16_to_cpu(entry->nameidx) < be16_to_cpu(hdr->firstused)) {
 		/* both on-disk, don't endian-flip twice */
 		hdr->firstused = entry->nameidx;
 	}
-	ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT)
-				>= ((INT_GET(hdr->count, ARCH_CONVERT)
-					* sizeof(*entry))+sizeof(*hdr)));
-	tmp = (INT_GET(hdr->count, ARCH_CONVERT)-1)
-					* sizeof(xfs_attr_leaf_entry_t)
+	ASSERT(be16_to_cpu(hdr->firstused) >=
+	       ((be16_to_cpu(hdr->count) * sizeof(*entry)) + sizeof(*hdr)));
+	tmp = (be16_to_cpu(hdr->count)-1) * sizeof(xfs_attr_leaf_entry_t)
 					+ sizeof(xfs_attr_leaf_hdr_t);
 	map = &hdr->freemap[0];
 	for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; map++, i++) {
-		if (INT_GET(map->base, ARCH_CONVERT) == tmp) {
-			INT_MOD(map->base, ARCH_CONVERT,
-					sizeof(xfs_attr_leaf_entry_t));
-			INT_MOD(map->size, ARCH_CONVERT,
-					-sizeof(xfs_attr_leaf_entry_t));
+		if (be16_to_cpu(map->base) == tmp) {
+			be16_add(&map->base, sizeof(xfs_attr_leaf_entry_t));
+			be16_add(&map->size,
+				 -((int)sizeof(xfs_attr_leaf_entry_t)));
 		}
 	}
-	INT_MOD(hdr->usedbytes, ARCH_CONVERT,
-				xfs_attr_leaf_entsize(leaf, args->index));
+	be16_add(&hdr->usedbytes, xfs_attr_leaf_entsize(leaf, args->index));
 	xfs_da_log_buf(args->trans, bp,
 		XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr)));
 	return(0);
@@ -1223,28 +1197,25 @@
 	hdr_s = &leaf_s->hdr;
 	hdr_d = &leaf_d->hdr;
 	hdr_d->info = hdr_s->info;	/* struct copy */
-	INT_SET(hdr_d->firstused, ARCH_CONVERT, XFS_LBSIZE(mp));
+	hdr_d->firstused = cpu_to_be16(XFS_LBSIZE(mp));
 	/* handle truncation gracefully */
 	if (!hdr_d->firstused) {
-		INT_SET(hdr_d->firstused, ARCH_CONVERT,
+		hdr_d->firstused = cpu_to_be16(
 				XFS_LBSIZE(mp) - XFS_ATTR_LEAF_NAME_ALIGN);
 	}
 	hdr_d->usedbytes = 0;
 	hdr_d->count = 0;
 	hdr_d->holes = 0;
-	INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT,
-					sizeof(xfs_attr_leaf_hdr_t));
-	INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT,
-				INT_GET(hdr_d->firstused, ARCH_CONVERT)
-			      - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT));
+	hdr_d->freemap[0].base = cpu_to_be16(sizeof(xfs_attr_leaf_hdr_t));
+	hdr_d->freemap[0].size = cpu_to_be16(be16_to_cpu(hdr_d->firstused) -
+					     sizeof(xfs_attr_leaf_hdr_t));
 
 	/*
 	 * Copy all entry's in the same (sorted) order,
 	 * but allocate name/value pairs packed and in sequence.
 	 */
 	xfs_attr_leaf_moveents(leaf_s, 0, leaf_d, 0,
-				(int)INT_GET(hdr_s->count, ARCH_CONVERT), mp);
-
+				be16_to_cpu(hdr_s->count), mp);
 	xfs_da_log_buf(trans, bp, 0, XFS_LBSIZE(mp) - 1);
 
 	kmem_free(tmpbuffer, XFS_LBSIZE(mp));
@@ -1279,10 +1250,8 @@
 	ASSERT(blk2->magic == XFS_ATTR_LEAF_MAGIC);
 	leaf1 = blk1->bp->data;
 	leaf2 = blk2->bp->data;
-	ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
-	ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf1->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf2->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
 	args = state->args;
 
 	/*
@@ -1319,22 +1288,21 @@
 	/*
 	 * Move any entries required from leaf to leaf:
 	 */
-	if (count < INT_GET(hdr1->count, ARCH_CONVERT)) {
+	if (count < be16_to_cpu(hdr1->count)) {
 		/*
 		 * Figure the total bytes to be added to the destination leaf.
 		 */
 		/* number entries being moved */
-		count = INT_GET(hdr1->count, ARCH_CONVERT) - count;
-		space  = INT_GET(hdr1->usedbytes, ARCH_CONVERT) - totallen;
+		count = be16_to_cpu(hdr1->count) - count;
+		space  = be16_to_cpu(hdr1->usedbytes) - totallen;
 		space += count * sizeof(xfs_attr_leaf_entry_t);
 
 		/*
 		 * leaf2 is the destination, compact it if it looks tight.
 		 */
-		max  = INT_GET(hdr2->firstused, ARCH_CONVERT)
+		max  = be16_to_cpu(hdr2->firstused)
 						- sizeof(xfs_attr_leaf_hdr_t);
-		max -= INT_GET(hdr2->count, ARCH_CONVERT)
-					* sizeof(xfs_attr_leaf_entry_t);
+		max -= be16_to_cpu(hdr2->count) * sizeof(xfs_attr_leaf_entry_t);
 		if (space > max) {
 			xfs_attr_leaf_compact(args->trans, blk2->bp);
 		}
@@ -1342,13 +1310,12 @@
 		/*
 		 * Move high entries from leaf1 to low end of leaf2.
 		 */
-		xfs_attr_leaf_moveents(leaf1,
-				INT_GET(hdr1->count, ARCH_CONVERT)-count,
+		xfs_attr_leaf_moveents(leaf1, be16_to_cpu(hdr1->count) - count,
 				leaf2, 0, count, state->mp);
 
 		xfs_da_log_buf(args->trans, blk1->bp, 0, state->blocksize-1);
 		xfs_da_log_buf(args->trans, blk2->bp, 0, state->blocksize-1);
-	} else if (count > INT_GET(hdr1->count, ARCH_CONVERT)) {
+	} else if (count > be16_to_cpu(hdr1->count)) {
 		/*
 		 * I assert that since all callers pass in an empty
 		 * second buffer, this code should never execute.
@@ -1358,17 +1325,16 @@
 		 * Figure the total bytes to be added to the destination leaf.
 		 */
 		/* number entries being moved */
-		count -= INT_GET(hdr1->count, ARCH_CONVERT);
-		space  = totallen - INT_GET(hdr1->usedbytes, ARCH_CONVERT);
+		count -= be16_to_cpu(hdr1->count);
+		space  = totallen - be16_to_cpu(hdr1->usedbytes);
 		space += count * sizeof(xfs_attr_leaf_entry_t);
 
 		/*
 		 * leaf1 is the destination, compact it if it looks tight.
 		 */
-		max  = INT_GET(hdr1->firstused, ARCH_CONVERT)
+		max  = be16_to_cpu(hdr1->firstused)
 						- sizeof(xfs_attr_leaf_hdr_t);
-		max -= INT_GET(hdr1->count, ARCH_CONVERT)
-					* sizeof(xfs_attr_leaf_entry_t);
+		max -= be16_to_cpu(hdr1->count) * sizeof(xfs_attr_leaf_entry_t);
 		if (space > max) {
 			xfs_attr_leaf_compact(args->trans, blk1->bp);
 		}
@@ -1377,8 +1343,7 @@
 		 * Move low entries from leaf2 to high end of leaf1.
 		 */
 		xfs_attr_leaf_moveents(leaf2, 0, leaf1,
-				(int)INT_GET(hdr1->count, ARCH_CONVERT), count,
-				state->mp);
+				be16_to_cpu(hdr1->count), count, state->mp);
 
 		xfs_da_log_buf(args->trans, blk1->bp, 0, state->blocksize-1);
 		xfs_da_log_buf(args->trans, blk2->bp, 0, state->blocksize-1);
@@ -1387,12 +1352,10 @@
 	/*
 	 * Copy out last hashval in each block for B-tree code.
 	 */
-	blk1->hashval =
-	    INT_GET(leaf1->entries[INT_GET(leaf1->hdr.count,
-				    ARCH_CONVERT)-1].hashval, ARCH_CONVERT);
-	blk2->hashval =
-	    INT_GET(leaf2->entries[INT_GET(leaf2->hdr.count,
-				    ARCH_CONVERT)-1].hashval, ARCH_CONVERT);
+	blk1->hashval = be32_to_cpu(
+		leaf1->entries[be16_to_cpu(leaf1->hdr.count)-1].hashval);
+	blk2->hashval = be32_to_cpu(
+		leaf2->entries[be16_to_cpu(leaf2->hdr.count)-1].hashval);
 
 	/*
 	 * Adjust the expected index for insertion.
@@ -1406,13 +1369,12 @@
 	 * inserting.  The index/blkno fields refer to the "old" entry,
 	 * while the index2/blkno2 fields refer to the "new" entry.
 	 */
-	if (blk1->index > INT_GET(leaf1->hdr.count, ARCH_CONVERT)) {
+	if (blk1->index > be16_to_cpu(leaf1->hdr.count)) {
 		ASSERT(state->inleaf == 0);
-		blk2->index = blk1->index
-				- INT_GET(leaf1->hdr.count, ARCH_CONVERT);
+		blk2->index = blk1->index - be16_to_cpu(leaf1->hdr.count);
 		args->index = args->index2 = blk2->index;
 		args->blkno = args->blkno2 = blk2->blkno;
-	} else if (blk1->index == INT_GET(leaf1->hdr.count, ARCH_CONVERT)) {
+	} else if (blk1->index == be16_to_cpu(leaf1->hdr.count)) {
 		if (state->inleaf) {
 			args->index = blk1->index;
 			args->blkno = blk1->blkno;
@@ -1420,7 +1382,7 @@
 			args->blkno2 = blk2->blkno;
 		} else {
 			blk2->index = blk1->index
-				    - INT_GET(leaf1->hdr.count, ARCH_CONVERT);
+				    - be16_to_cpu(leaf1->hdr.count);
 			args->index = args->index2 = blk2->index;
 			args->blkno = args->blkno2 = blk2->blkno;
 		}
@@ -1464,15 +1426,14 @@
 	 * Examine entries until we reduce the absolute difference in
 	 * byte usage between the two blocks to a minimum.
 	 */
-	max = INT_GET(hdr1->count, ARCH_CONVERT)
-			+ INT_GET(hdr2->count, ARCH_CONVERT);
+	max = be16_to_cpu(hdr1->count) + be16_to_cpu(hdr2->count);
 	half  = (max+1) * sizeof(*entry);
-	half += INT_GET(hdr1->usedbytes, ARCH_CONVERT)
-				+ INT_GET(hdr2->usedbytes, ARCH_CONVERT)
-				+ xfs_attr_leaf_newentsize(
-						state->args->namelen,
-						state->args->valuelen,
-						state->blocksize, NULL);
+	half += be16_to_cpu(hdr1->usedbytes) +
+		be16_to_cpu(hdr2->usedbytes) +
+		xfs_attr_leaf_newentsize(
+				state->args->namelen,
+				state->args->valuelen,
+				state->blocksize, NULL);
 	half /= 2;
 	lastdelta = state->blocksize;
 	entry = &leaf1->entries[0];
@@ -1498,7 +1459,7 @@
 		/*
 		 * Wrap around into the second block if necessary.
 		 */
-		if (count == INT_GET(hdr1->count, ARCH_CONVERT)) {
+		if (count == be16_to_cpu(hdr1->count)) {
 			leaf1 = leaf2;
 			entry = &leaf1->entries[0];
 			index = 0;
@@ -1566,12 +1527,12 @@
 	 */
 	blk = &state->path.blk[ state->path.active-1 ];
 	info = blk->bp->data;
-	ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(info->magic) == XFS_ATTR_LEAF_MAGIC);
 	leaf = (xfs_attr_leafblock_t *)info;
-	count = INT_GET(leaf->hdr.count, ARCH_CONVERT);
+	count = be16_to_cpu(leaf->hdr.count);
 	bytes = sizeof(xfs_attr_leaf_hdr_t) +
 		count * sizeof(xfs_attr_leaf_entry_t) +
-		INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT);
+		be16_to_cpu(leaf->hdr.usedbytes);
 	if (bytes > (state->blocksize >> 1)) {
 		*action = 0;	/* blk over 50%, don't try to join */
 		return(0);
@@ -1588,7 +1549,7 @@
 		 * Make altpath point to the block we want to keep and
 		 * path point to the block we want to drop (this one).
 		 */
-		forward = info->forw;
+		forward = (info->forw != 0);
 		memcpy(&state->altpath, &state->path, sizeof(state->path));
 		error = xfs_da_path_shift(state, &state->altpath, forward,
 						 0, &retval);
@@ -1610,13 +1571,12 @@
 	 * to shrink an attribute list over time.
 	 */
 	/* start with smaller blk num */
-	forward = (INT_GET(info->forw, ARCH_CONVERT)
-					< INT_GET(info->back, ARCH_CONVERT));
+	forward = (be32_to_cpu(info->forw) < be32_to_cpu(info->back));
 	for (i = 0; i < 2; forward = !forward, i++) {
 		if (forward)
-			blkno = INT_GET(info->forw, ARCH_CONVERT);
+			blkno = be32_to_cpu(info->forw);
 		else
-			blkno = INT_GET(info->back, ARCH_CONVERT);
+			blkno = be32_to_cpu(info->back);
 		if (blkno == 0)
 			continue;
 		error = xfs_da_read_buf(state->args->trans, state->args->dp,
@@ -1626,14 +1586,13 @@
 		ASSERT(bp != NULL);
 
 		leaf = (xfs_attr_leafblock_t *)info;
-		count  = INT_GET(leaf->hdr.count, ARCH_CONVERT);
+		count  = be16_to_cpu(leaf->hdr.count);
 		bytes  = state->blocksize - (state->blocksize>>2);
-		bytes -= INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT);
+		bytes -= be16_to_cpu(leaf->hdr.usedbytes);
 		leaf = bp->data;
-		ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
-		count += INT_GET(leaf->hdr.count, ARCH_CONVERT);
-		bytes -= INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT);
+		ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
+		count += be16_to_cpu(leaf->hdr.count);
+		bytes -= be16_to_cpu(leaf->hdr.usedbytes);
 		bytes -= count * sizeof(xfs_attr_leaf_entry_t);
 		bytes -= sizeof(xfs_attr_leaf_hdr_t);
 		xfs_da_brelse(state->args->trans, bp);
@@ -1685,21 +1644,18 @@
 	xfs_mount_t *mp;
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
 	hdr = &leaf->hdr;
 	mp = args->trans->t_mountp;
-	ASSERT((INT_GET(hdr->count, ARCH_CONVERT) > 0)
-		&& (INT_GET(hdr->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8)));
+	ASSERT((be16_to_cpu(hdr->count) > 0)
+		&& (be16_to_cpu(hdr->count) < (XFS_LBSIZE(mp)/8)));
 	ASSERT((args->index >= 0)
-		&& (args->index < INT_GET(hdr->count, ARCH_CONVERT)));
-	ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT)
-				>= ((INT_GET(hdr->count, ARCH_CONVERT)
-					* sizeof(*entry))+sizeof(*hdr)));
+		&& (args->index < be16_to_cpu(hdr->count)));
+	ASSERT(be16_to_cpu(hdr->firstused) >=
+	       ((be16_to_cpu(hdr->count) * sizeof(*entry)) + sizeof(*hdr)));
 	entry = &leaf->entries[args->index];
-	ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT)
-				>= INT_GET(hdr->firstused, ARCH_CONVERT));
-	ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp));
+	ASSERT(be16_to_cpu(entry->nameidx) >= be16_to_cpu(hdr->firstused));
+	ASSERT(be16_to_cpu(entry->nameidx) < XFS_LBSIZE(mp));
 
 	/*
 	 * Scan through free region table:
@@ -1707,33 +1663,30 @@
 	 *    find smallest free region in case we need to replace it,
 	 *    adjust any map that borders the entry table,
 	 */
-	tablesize = INT_GET(hdr->count, ARCH_CONVERT)
-					* sizeof(xfs_attr_leaf_entry_t)
+	tablesize = be16_to_cpu(hdr->count) * sizeof(xfs_attr_leaf_entry_t)
 					+ sizeof(xfs_attr_leaf_hdr_t);
 	map = &hdr->freemap[0];
-	tmp = INT_GET(map->size, ARCH_CONVERT);
+	tmp = be16_to_cpu(map->size);
 	before = after = -1;
 	smallest = XFS_ATTR_LEAF_MAPSIZE - 1;
 	entsize = xfs_attr_leaf_entsize(leaf, args->index);
 	for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; map++, i++) {
-		ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp));
-		ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp));
-		if (INT_GET(map->base, ARCH_CONVERT) == tablesize) {
-			INT_MOD(map->base, ARCH_CONVERT,
-					-sizeof(xfs_attr_leaf_entry_t));
-			INT_MOD(map->size, ARCH_CONVERT,
-					sizeof(xfs_attr_leaf_entry_t));
+		ASSERT(be16_to_cpu(map->base) < XFS_LBSIZE(mp));
+		ASSERT(be16_to_cpu(map->size) < XFS_LBSIZE(mp));
+		if (be16_to_cpu(map->base) == tablesize) {
+			be16_add(&map->base,
+				 -((int)sizeof(xfs_attr_leaf_entry_t)));
+			be16_add(&map->size, sizeof(xfs_attr_leaf_entry_t));
 		}
 
-		if ((INT_GET(map->base, ARCH_CONVERT)
-					+ INT_GET(map->size, ARCH_CONVERT))
-				== INT_GET(entry->nameidx, ARCH_CONVERT)) {
+		if ((be16_to_cpu(map->base) + be16_to_cpu(map->size))
+				== be16_to_cpu(entry->nameidx)) {
 			before = i;
-		} else if (INT_GET(map->base, ARCH_CONVERT)
-			== (INT_GET(entry->nameidx, ARCH_CONVERT) + entsize)) {
+		} else if (be16_to_cpu(map->base)
+			== (be16_to_cpu(entry->nameidx) + entsize)) {
 			after = i;
-		} else if (INT_GET(map->size, ARCH_CONVERT) < tmp) {
-			tmp = INT_GET(map->size, ARCH_CONVERT);
+		} else if (be16_to_cpu(map->size) < tmp) {
+			tmp = be16_to_cpu(map->size);
 			smallest = i;
 		}
 	}
@@ -1745,38 +1698,35 @@
 	if ((before >= 0) || (after >= 0)) {
 		if ((before >= 0) && (after >= 0)) {
 			map = &hdr->freemap[before];
-			INT_MOD(map->size, ARCH_CONVERT, entsize);
-			INT_MOD(map->size, ARCH_CONVERT,
-				INT_GET(hdr->freemap[after].size,
-							ARCH_CONVERT));
+			be16_add(&map->size, entsize);
+			be16_add(&map->size,
+				 be16_to_cpu(hdr->freemap[after].size));
 			hdr->freemap[after].base = 0;
 			hdr->freemap[after].size = 0;
 		} else if (before >= 0) {
 			map = &hdr->freemap[before];
-			INT_MOD(map->size, ARCH_CONVERT, entsize);
+			be16_add(&map->size, entsize);
 		} else {
 			map = &hdr->freemap[after];
 			/* both on-disk, don't endian flip twice */
 			map->base = entry->nameidx;
-			INT_MOD(map->size, ARCH_CONVERT, entsize);
+			be16_add(&map->size, entsize);
 		}
 	} else {
 		/*
 		 * Replace smallest region (if it is smaller than free'd entry)
 		 */
 		map = &hdr->freemap[smallest];
-		if (INT_GET(map->size, ARCH_CONVERT) < entsize) {
-			INT_SET(map->base, ARCH_CONVERT,
-					INT_GET(entry->nameidx, ARCH_CONVERT));
-			INT_SET(map->size, ARCH_CONVERT, entsize);
+		if (be16_to_cpu(map->size) < entsize) {
+			map->base = cpu_to_be16(be16_to_cpu(entry->nameidx));
+			map->size = cpu_to_be16(entsize);
 		}
 	}
 
 	/*
 	 * Did we remove the first entry?
 	 */
-	if (INT_GET(entry->nameidx, ARCH_CONVERT)
-				== INT_GET(hdr->firstused, ARCH_CONVERT))
+	if (be16_to_cpu(entry->nameidx) == be16_to_cpu(hdr->firstused))
 		smallest = 1;
 	else
 		smallest = 0;
@@ -1785,18 +1735,18 @@
 	 * Compress the remaining entries and zero out the removed stuff.
 	 */
 	memset(XFS_ATTR_LEAF_NAME(leaf, args->index), 0, entsize);
-	INT_MOD(hdr->usedbytes, ARCH_CONVERT, -entsize);
+	be16_add(&hdr->usedbytes, -entsize);
 	xfs_da_log_buf(args->trans, bp,
 	     XFS_DA_LOGRANGE(leaf, XFS_ATTR_LEAF_NAME(leaf, args->index),
 				   entsize));
 
-	tmp = (INT_GET(hdr->count, ARCH_CONVERT) - args->index)
+	tmp = (be16_to_cpu(hdr->count) - args->index)
 					* sizeof(xfs_attr_leaf_entry_t);
 	memmove((char *)entry, (char *)(entry+1), tmp);
-	INT_MOD(hdr->count, ARCH_CONVERT, -1);
+	be16_add(&hdr->count, -1);
 	xfs_da_log_buf(args->trans, bp,
 	    XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry)));
-	entry = &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)];
+	entry = &leaf->entries[be16_to_cpu(hdr->count)];
 	memset((char *)entry, 0, sizeof(xfs_attr_leaf_entry_t));
 
 	/*
@@ -1808,18 +1758,17 @@
 	if (smallest) {
 		tmp = XFS_LBSIZE(mp);
 		entry = &leaf->entries[0];
-		for (i = INT_GET(hdr->count, ARCH_CONVERT)-1;
-						i >= 0; entry++, i--) {
-			ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT)
-				>= INT_GET(hdr->firstused, ARCH_CONVERT));
-			ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT)
-							< XFS_LBSIZE(mp));
-			if (INT_GET(entry->nameidx, ARCH_CONVERT) < tmp)
-				tmp = INT_GET(entry->nameidx, ARCH_CONVERT);
+		for (i = be16_to_cpu(hdr->count)-1; i >= 0; entry++, i--) {
+			ASSERT(be16_to_cpu(entry->nameidx) >=
+			       be16_to_cpu(hdr->firstused));
+			ASSERT(be16_to_cpu(entry->nameidx) < XFS_LBSIZE(mp));
+
+			if (be16_to_cpu(entry->nameidx) < tmp)
+				tmp = be16_to_cpu(entry->nameidx);
 		}
-		INT_SET(hdr->firstused, ARCH_CONVERT, tmp);
+		hdr->firstused = cpu_to_be16(tmp);
 		if (!hdr->firstused) {
-			INT_SET(hdr->firstused, ARCH_CONVERT,
+			hdr->firstused = cpu_to_be16(
 					tmp - XFS_ATTR_LEAF_NAME_ALIGN);
 		}
 	} else {
@@ -1833,9 +1782,8 @@
 	 * "join" the leaf with a sibling if so.
 	 */
 	tmp  = sizeof(xfs_attr_leaf_hdr_t);
-	tmp += INT_GET(leaf->hdr.count, ARCH_CONVERT)
-					* sizeof(xfs_attr_leaf_entry_t);
-	tmp += INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT);
+	tmp += be16_to_cpu(leaf->hdr.count) * sizeof(xfs_attr_leaf_entry_t);
+	tmp += be16_to_cpu(leaf->hdr.usedbytes);
 	return(tmp < mp->m_attr_magicpct); /* leaf is < 37% full */
 }
 
@@ -1859,20 +1807,16 @@
 	ASSERT(save_blk->magic == XFS_ATTR_LEAF_MAGIC);
 	drop_leaf = drop_blk->bp->data;
 	save_leaf = save_blk->bp->data;
-	ASSERT(INT_GET(drop_leaf->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
-	ASSERT(INT_GET(save_leaf->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(drop_leaf->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(save_leaf->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
 	drop_hdr = &drop_leaf->hdr;
 	save_hdr = &save_leaf->hdr;
 
 	/*
 	 * Save last hashval from dying block for later Btree fixup.
 	 */
-	drop_blk->hashval =
-		INT_GET(drop_leaf->entries[INT_GET(drop_leaf->hdr.count,
-						ARCH_CONVERT)-1].hashval,
-								ARCH_CONVERT);
+	drop_blk->hashval = be32_to_cpu(
+		drop_leaf->entries[be16_to_cpu(drop_leaf->hdr.count)-1].hashval);
 
 	/*
 	 * Check if we need a temp buffer, or can we do it in place.
@@ -1886,12 +1830,11 @@
 		 */
 		if (xfs_attr_leaf_order(save_blk->bp, drop_blk->bp)) {
 			xfs_attr_leaf_moveents(drop_leaf, 0, save_leaf, 0,
-			     (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp);
+			     be16_to_cpu(drop_hdr->count), mp);
 		} else {
 			xfs_attr_leaf_moveents(drop_leaf, 0, save_leaf,
-				  INT_GET(save_hdr->count, ARCH_CONVERT),
-				  (int)INT_GET(drop_hdr->count, ARCH_CONVERT),
-				  mp);
+				  be16_to_cpu(save_hdr->count),
+				  be16_to_cpu(drop_hdr->count), mp);
 		}
 	} else {
 		/*
@@ -1905,28 +1848,24 @@
 		tmp_hdr = &tmp_leaf->hdr;
 		tmp_hdr->info = save_hdr->info;	/* struct copy */
 		tmp_hdr->count = 0;
-		INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize);
+		tmp_hdr->firstused = cpu_to_be16(state->blocksize);
 		if (!tmp_hdr->firstused) {
-			INT_SET(tmp_hdr->firstused, ARCH_CONVERT,
+			tmp_hdr->firstused = cpu_to_be16(
 				state->blocksize - XFS_ATTR_LEAF_NAME_ALIGN);
 		}
 		tmp_hdr->usedbytes = 0;
 		if (xfs_attr_leaf_order(save_blk->bp, drop_blk->bp)) {
 			xfs_attr_leaf_moveents(drop_leaf, 0, tmp_leaf, 0,
-				(int)INT_GET(drop_hdr->count, ARCH_CONVERT),
-				mp);
+				be16_to_cpu(drop_hdr->count), mp);
 			xfs_attr_leaf_moveents(save_leaf, 0, tmp_leaf,
-				  INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT),
-				 (int)INT_GET(save_hdr->count, ARCH_CONVERT),
-				 mp);
+				  be16_to_cpu(tmp_leaf->hdr.count),
+				  be16_to_cpu(save_hdr->count), mp);
 		} else {
 			xfs_attr_leaf_moveents(save_leaf, 0, tmp_leaf, 0,
-				(int)INT_GET(save_hdr->count, ARCH_CONVERT),
-				mp);
+				be16_to_cpu(save_hdr->count), mp);
 			xfs_attr_leaf_moveents(drop_leaf, 0, tmp_leaf,
-				INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT),
-				(int)INT_GET(drop_hdr->count, ARCH_CONVERT),
-				mp);
+				be16_to_cpu(tmp_leaf->hdr.count),
+				be16_to_cpu(drop_hdr->count), mp);
 		}
 		memcpy((char *)save_leaf, (char *)tmp_leaf, state->blocksize);
 		kmem_free(tmpbuffer, state->blocksize);
@@ -1938,10 +1877,8 @@
 	/*
 	 * Copy out last hashval in each block for B-tree code.
 	 */
-	save_blk->hashval =
-		INT_GET(save_leaf->entries[INT_GET(save_leaf->hdr.count,
-						ARCH_CONVERT)-1].hashval,
-								ARCH_CONVERT);
+	save_blk->hashval = be32_to_cpu(
+		save_leaf->entries[be16_to_cpu(save_leaf->hdr.count)-1].hashval);
 }
 
 /*========================================================================
@@ -1972,48 +1909,45 @@
 	xfs_dahash_t hashval;
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
-	ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT)
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.count)
 					< (XFS_LBSIZE(args->dp->i_mount)/8));
 
 	/*
 	 * Binary search.  (note: small blocks will skip this loop)
 	 */
 	hashval = args->hashval;
-	probe = span = INT_GET(leaf->hdr.count, ARCH_CONVERT) / 2;
+	probe = span = be16_to_cpu(leaf->hdr.count) / 2;
 	for (entry = &leaf->entries[probe]; span > 4;
 		   entry = &leaf->entries[probe]) {
 		span /= 2;
-		if (INT_GET(entry->hashval, ARCH_CONVERT) < hashval)
+		if (be32_to_cpu(entry->hashval) < hashval)
 			probe += span;
-		else if (INT_GET(entry->hashval, ARCH_CONVERT) > hashval)
+		else if (be32_to_cpu(entry->hashval) > hashval)
 			probe -= span;
 		else
 			break;
 	}
 	ASSERT((probe >= 0) && 
 	       (!leaf->hdr.count
-	       || (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT))));
-	ASSERT((span <= 4) || (INT_GET(entry->hashval, ARCH_CONVERT)
-							== hashval));
+	       || (probe < be16_to_cpu(leaf->hdr.count))));
+	ASSERT((span <= 4) || (be32_to_cpu(entry->hashval) == hashval));
 
 	/*
 	 * Since we may have duplicate hashval's, find the first matching
 	 * hashval in the leaf.
 	 */
-	while ((probe > 0) && (INT_GET(entry->hashval, ARCH_CONVERT)
-							>= hashval)) {
+	while ((probe > 0) && (be32_to_cpu(entry->hashval) >= hashval)) {
 		entry--;
 		probe--;
 	}
-	while ((probe < INT_GET(leaf->hdr.count, ARCH_CONVERT))
-		&& (INT_GET(entry->hashval, ARCH_CONVERT) < hashval)) {
+	while ((probe < be16_to_cpu(leaf->hdr.count)) &&
+	       (be32_to_cpu(entry->hashval) < hashval)) {
 		entry++;
 		probe++;
 	}
-	if ((probe == INT_GET(leaf->hdr.count, ARCH_CONVERT))
-		    || (INT_GET(entry->hashval, ARCH_CONVERT) != hashval)) {
+	if ((probe == be16_to_cpu(leaf->hdr.count)) ||
+	    (be32_to_cpu(entry->hashval) != hashval)) {
 		args->index = probe;
 		return(XFS_ERROR(ENOATTR));
 	}
@@ -2021,8 +1955,8 @@
 	/*
 	 * Duplicate keys may be present, so search all of them for a match.
 	 */
-	for (  ; (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT))
-			&& (INT_GET(entry->hashval, ARCH_CONVERT) == hashval);
+	for (  ; (probe < be16_to_cpu(leaf->hdr.count)) &&
+			(be32_to_cpu(entry->hashval) == hashval);
 			entry++, probe++) {
 /*
  * GROT: Add code to remove incomplete entries.
@@ -2064,11 +1998,9 @@
 			    ((entry->flags & XFS_ATTR_ROOT) != 0))
 				continue;
 			args->index = probe;
-			args->rmtblkno
-				  = INT_GET(name_rmt->valueblk, ARCH_CONVERT);
+			args->rmtblkno = be32_to_cpu(name_rmt->valueblk);
 			args->rmtblkcnt = XFS_B_TO_FSB(args->dp->i_mount,
-						   INT_GET(name_rmt->valuelen,
-								ARCH_CONVERT));
+						   be32_to_cpu(name_rmt->valuelen));
 			return(XFS_ERROR(EEXIST));
 		}
 	}
@@ -2090,18 +2022,17 @@
 	xfs_attr_leaf_name_remote_t *name_rmt;
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
-	ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT)
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.count)
 					< (XFS_LBSIZE(args->dp->i_mount)/8));
-	ASSERT(args->index < ((int)INT_GET(leaf->hdr.count, ARCH_CONVERT)));
+	ASSERT(args->index < be16_to_cpu(leaf->hdr.count));
 
 	entry = &leaf->entries[args->index];
 	if (entry->flags & XFS_ATTR_LOCAL) {
 		name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index);
 		ASSERT(name_loc->namelen == args->namelen);
 		ASSERT(memcmp(args->name, name_loc->nameval, args->namelen) == 0);
-		valuelen = INT_GET(name_loc->valuelen, ARCH_CONVERT);
+		valuelen = be16_to_cpu(name_loc->valuelen);
 		if (args->flags & ATTR_KERNOVAL) {
 			args->valuelen = valuelen;
 			return(0);
@@ -2116,8 +2047,8 @@
 		name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index);
 		ASSERT(name_rmt->namelen == args->namelen);
 		ASSERT(memcmp(args->name, name_rmt->name, args->namelen) == 0);
-		valuelen = INT_GET(name_rmt->valuelen, ARCH_CONVERT);
-		args->rmtblkno = INT_GET(name_rmt->valueblk, ARCH_CONVERT);
+		valuelen = be32_to_cpu(name_rmt->valuelen);
+		args->rmtblkno = be32_to_cpu(name_rmt->valueblk);
 		args->rmtblkcnt = XFS_B_TO_FSB(args->dp->i_mount, valuelen);
 		if (args->flags & ATTR_KERNOVAL) {
 			args->valuelen = valuelen;
@@ -2159,32 +2090,29 @@
 	/*
 	 * Set up environment.
 	 */
-	ASSERT(INT_GET(leaf_s->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
-	ASSERT(INT_GET(leaf_d->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf_s->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf_d->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
 	hdr_s = &leaf_s->hdr;
 	hdr_d = &leaf_d->hdr;
-	ASSERT((INT_GET(hdr_s->count, ARCH_CONVERT) > 0)
-				&& (INT_GET(hdr_s->count, ARCH_CONVERT)
-						< (XFS_LBSIZE(mp)/8)));
-	ASSERT(INT_GET(hdr_s->firstused, ARCH_CONVERT) >=
-		((INT_GET(hdr_s->count, ARCH_CONVERT)
+	ASSERT((be16_to_cpu(hdr_s->count) > 0) &&
+	       (be16_to_cpu(hdr_s->count) < (XFS_LBSIZE(mp)/8)));
+	ASSERT(be16_to_cpu(hdr_s->firstused) >=
+		((be16_to_cpu(hdr_s->count)
 					* sizeof(*entry_s))+sizeof(*hdr_s)));
-	ASSERT(INT_GET(hdr_d->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8));
-	ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >=
-		((INT_GET(hdr_d->count, ARCH_CONVERT)
+	ASSERT(be16_to_cpu(hdr_d->count) < (XFS_LBSIZE(mp)/8));
+	ASSERT(be16_to_cpu(hdr_d->firstused) >=
+		((be16_to_cpu(hdr_d->count)
 					* sizeof(*entry_d))+sizeof(*hdr_d)));
 
-	ASSERT(start_s < INT_GET(hdr_s->count, ARCH_CONVERT));
-	ASSERT(start_d <= INT_GET(hdr_d->count, ARCH_CONVERT));
-	ASSERT(count <= INT_GET(hdr_s->count, ARCH_CONVERT));
+	ASSERT(start_s < be16_to_cpu(hdr_s->count));
+	ASSERT(start_d <= be16_to_cpu(hdr_d->count));
+	ASSERT(count <= be16_to_cpu(hdr_s->count));
 
 	/*
 	 * Move the entries in the destination leaf up to make a hole?
 	 */
-	if (start_d < INT_GET(hdr_d->count, ARCH_CONVERT)) {
-		tmp  = INT_GET(hdr_d->count, ARCH_CONVERT) - start_d;
+	if (start_d < be16_to_cpu(hdr_d->count)) {
+		tmp  = be16_to_cpu(hdr_d->count) - start_d;
 		tmp *= sizeof(xfs_attr_leaf_entry_t);
 		entry_s = &leaf_d->entries[start_d];
 		entry_d = &leaf_d->entries[start_d + count];
@@ -2199,8 +2127,8 @@
 	entry_d = &leaf_d->entries[start_d];
 	desti = start_d;
 	for (i = 0; i < count; entry_s++, entry_d++, desti++, i++) {
-		ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT)
-				>= INT_GET(hdr_s->firstused, ARCH_CONVERT));
+		ASSERT(be16_to_cpu(entry_s->nameidx)
+				>= be16_to_cpu(hdr_s->firstused));
 		tmp = xfs_attr_leaf_entsize(leaf_s, start_s + i);
 #ifdef GROT
 		/*
@@ -2210,35 +2138,35 @@
 		 */
 		if (entry_s->flags & XFS_ATTR_INCOMPLETE) { /* skip partials? */
 			memset(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), 0, tmp);
-			INT_MOD(hdr_s->usedbytes, ARCH_CONVERT, -tmp);
-			INT_MOD(hdr_s->count, ARCH_CONVERT, -1);
+			be16_add(&hdr_s->usedbytes, -tmp);
+			be16_add(&hdr_s->count, -1);
 			entry_d--;	/* to compensate for ++ in loop hdr */
 			desti--;
 			if ((start_s + i) < offset)
 				result++;	/* insertion index adjustment */
 		} else {
 #endif /* GROT */
-			INT_MOD(hdr_d->firstused, ARCH_CONVERT, -tmp);
+			be16_add(&hdr_d->firstused, -tmp);
 			/* both on-disk, don't endian flip twice */
 			entry_d->hashval = entry_s->hashval;
 			/* both on-disk, don't endian flip twice */
 			entry_d->nameidx = hdr_d->firstused;
 			entry_d->flags = entry_s->flags;
-			ASSERT(INT_GET(entry_d->nameidx, ARCH_CONVERT) + tmp
+			ASSERT(be16_to_cpu(entry_d->nameidx) + tmp
 							<= XFS_LBSIZE(mp));
 			memmove(XFS_ATTR_LEAF_NAME(leaf_d, desti),
 				XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), tmp);
-			ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + tmp
+			ASSERT(be16_to_cpu(entry_s->nameidx) + tmp
 							<= XFS_LBSIZE(mp));
 			memset(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), 0, tmp);
-			INT_MOD(hdr_s->usedbytes, ARCH_CONVERT, -tmp);
-			INT_MOD(hdr_d->usedbytes, ARCH_CONVERT, tmp);
-			INT_MOD(hdr_s->count, ARCH_CONVERT, -1);
-			INT_MOD(hdr_d->count, ARCH_CONVERT, 1);
-			tmp = INT_GET(hdr_d->count, ARCH_CONVERT)
+			be16_add(&hdr_s->usedbytes, -tmp);
+			be16_add(&hdr_d->usedbytes, tmp);
+			be16_add(&hdr_s->count, -1);
+			be16_add(&hdr_d->count, 1);
+			tmp = be16_to_cpu(hdr_d->count)
 						* sizeof(xfs_attr_leaf_entry_t)
 						+ sizeof(xfs_attr_leaf_hdr_t);
-			ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= tmp);
+			ASSERT(be16_to_cpu(hdr_d->firstused) >= tmp);
 #ifdef GROT
 		}
 #endif /* GROT */
@@ -2247,7 +2175,7 @@
 	/*
 	 * Zero out the entries we just copied.
 	 */
-	if (start_s == INT_GET(hdr_s->count, ARCH_CONVERT)) {
+	if (start_s == be16_to_cpu(hdr_s->count)) {
 		tmp = count * sizeof(xfs_attr_leaf_entry_t);
 		entry_s = &leaf_s->entries[start_s];
 		ASSERT(((char *)entry_s + tmp) <=
@@ -2258,15 +2186,14 @@
 		 * Move the remaining entries down to fill the hole,
 		 * then zero the entries at the top.
 		 */
-		tmp  = INT_GET(hdr_s->count, ARCH_CONVERT) - count;
+		tmp  = be16_to_cpu(hdr_s->count) - count;
 		tmp *= sizeof(xfs_attr_leaf_entry_t);
 		entry_s = &leaf_s->entries[start_s + count];
 		entry_d = &leaf_s->entries[start_s];
 		memmove((char *)entry_d, (char *)entry_s, tmp);
 
 		tmp = count * sizeof(xfs_attr_leaf_entry_t);
-		entry_s = &leaf_s->entries[INT_GET(hdr_s->count,
-							ARCH_CONVERT)];
+		entry_s = &leaf_s->entries[be16_to_cpu(hdr_s->count)];
 		ASSERT(((char *)entry_s + tmp) <=
 		       ((char *)leaf_s + XFS_LBSIZE(mp)));
 		memset((char *)entry_s, 0, tmp);
@@ -2275,14 +2202,11 @@
 	/*
 	 * Fill in the freemap information
 	 */
-	INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT,
-					sizeof(xfs_attr_leaf_hdr_t));
-	INT_MOD(hdr_d->freemap[0].base, ARCH_CONVERT,
-				INT_GET(hdr_d->count, ARCH_CONVERT)
-					* sizeof(xfs_attr_leaf_entry_t));
-	INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT,
-				INT_GET(hdr_d->firstused, ARCH_CONVERT)
-			      - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT));
+	hdr_d->freemap[0].base = cpu_to_be16(sizeof(xfs_attr_leaf_hdr_t));
+	be16_add(&hdr_d->freemap[0].base, be16_to_cpu(hdr_d->count) *
+			sizeof(xfs_attr_leaf_entry_t));
+	hdr_d->freemap[0].size = cpu_to_be16(be16_to_cpu(hdr_d->firstused)
+			      - be16_to_cpu(hdr_d->freemap[0].base));
 	hdr_d->freemap[1].base = 0;
 	hdr_d->freemap[2].base = 0;
 	hdr_d->freemap[1].size = 0;
@@ -2301,18 +2225,16 @@
 
 	leaf1 = leaf1_bp->data;
 	leaf2 = leaf2_bp->data;
-	ASSERT((INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC) &&
-	       (INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC));
-	if (   (INT_GET(leaf1->hdr.count, ARCH_CONVERT) > 0)
-	    && (INT_GET(leaf2->hdr.count, ARCH_CONVERT) > 0)
-	    && (   (INT_GET(leaf2->entries[ 0 ].hashval, ARCH_CONVERT) <
-		      INT_GET(leaf1->entries[ 0 ].hashval, ARCH_CONVERT))
-		|| (INT_GET(leaf2->entries[INT_GET(leaf2->hdr.count,
-				ARCH_CONVERT)-1].hashval, ARCH_CONVERT) <
-		      INT_GET(leaf1->entries[INT_GET(leaf1->hdr.count,
-				ARCH_CONVERT)-1].hashval, ARCH_CONVERT))) ) {
+	ASSERT((be16_to_cpu(leaf1->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC) &&
+	       (be16_to_cpu(leaf2->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC));
+	if ((be16_to_cpu(leaf1->hdr.count) > 0) &&
+	    (be16_to_cpu(leaf2->hdr.count) > 0) &&
+	    ((be32_to_cpu(leaf2->entries[0].hashval) <
+	      be32_to_cpu(leaf1->entries[0].hashval)) ||
+	     (be32_to_cpu(leaf2->entries[
+			be16_to_cpu(leaf2->hdr.count)-1].hashval) <
+	      be32_to_cpu(leaf1->entries[
+			be16_to_cpu(leaf1->hdr.count)-1].hashval)))) {
 		return(1);
 	}
 	return(0);
@@ -2327,14 +2249,12 @@
 	xfs_attr_leafblock_t *leaf;
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
 	if (count)
-		*count = INT_GET(leaf->hdr.count, ARCH_CONVERT);
+		*count = be16_to_cpu(leaf->hdr.count);
 	if (!leaf->hdr.count)
 		return(0);
-	return(INT_GET(leaf->entries[INT_GET(leaf->hdr.count,
-				ARCH_CONVERT)-1].hashval, ARCH_CONVERT));
+	return be32_to_cpu(leaf->entries[be16_to_cpu(leaf->hdr.count)-1].hashval);
 }
 
 /*
@@ -2348,13 +2268,11 @@
 	xfs_attr_leaf_name_remote_t *name_rmt;
 	int size;
 
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
 	if (leaf->entries[index].flags & XFS_ATTR_LOCAL) {
 		name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, index);
 		size = XFS_ATTR_LEAF_ENTSIZE_LOCAL(name_loc->namelen,
-						   INT_GET(name_loc->valuelen,
-								ARCH_CONVERT));
+						   be16_to_cpu(name_loc->valuelen));
 	} else {
 		name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, index);
 		size = XFS_ATTR_LEAF_ENTSIZE_REMOTE(name_rmt->namelen);
@@ -2412,22 +2330,20 @@
 	 */
 	if (context->resynch) {
 		entry = &leaf->entries[0];
-		for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT);
-							entry++, i++) {
-			if (INT_GET(entry->hashval, ARCH_CONVERT)
-							== cursor->hashval) {
+		for (i = 0; i < be16_to_cpu(leaf->hdr.count); entry++, i++) {
+			if (be32_to_cpu(entry->hashval) == cursor->hashval) {
 				if (cursor->offset == context->dupcnt) {
 					context->dupcnt = 0;
 					break;
 				}
 				context->dupcnt++;
-			} else if (INT_GET(entry->hashval, ARCH_CONVERT)
-							> cursor->hashval) {
+			} else if (be32_to_cpu(entry->hashval) >
+					cursor->hashval) {
 				context->dupcnt = 0;
 				break;
 			}
 		}
-		if (i == INT_GET(leaf->hdr.count, ARCH_CONVERT)) {
+		if (i == be16_to_cpu(leaf->hdr.count)) {
 			xfs_attr_trace_l_c("not found", context);
 			return(0);
 		}
@@ -2441,12 +2357,12 @@
 	 * We have found our place, start copying out the new attributes.
 	 */
 	retval = 0;
-	for (  ; (i < INT_GET(leaf->hdr.count, ARCH_CONVERT))
+	for (  ; (i < be16_to_cpu(leaf->hdr.count))
 	     && (retval == 0); entry++, i++) {
 		attrnames_t	*namesp;
 
-		if (INT_GET(entry->hashval, ARCH_CONVERT) != cursor->hashval) {
-			cursor->hashval = INT_GET(entry->hashval, ARCH_CONVERT);
+		if (be32_to_cpu(entry->hashval) != cursor->hashval) {
+			cursor->hashval = be32_to_cpu(entry->hashval);
 			cursor->offset = 0;
 		}
 
@@ -2475,8 +2391,7 @@
 				retval = xfs_attr_put_listent(context, namesp,
 					(char *)name_loc->nameval,
 					(int)name_loc->namelen,
-					(int)INT_GET(name_loc->valuelen,
-								ARCH_CONVERT));
+					be16_to_cpu(name_loc->valuelen));
 			}
 		} else {
 			name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
@@ -2488,8 +2403,7 @@
 				retval = xfs_attr_put_listent(context, namesp,
 					(char *)name_rmt->name,
 					(int)name_rmt->namelen,
-					(int)INT_GET(name_rmt->valuelen,
-								ARCH_CONVERT));
+					be32_to_cpu(name_rmt->valuelen));
 			}
 		}
 		if (retval == 0) {
@@ -2596,9 +2510,8 @@
 	ASSERT(bp != NULL);
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
-	ASSERT(args->index < INT_GET(leaf->hdr.count, ARCH_CONVERT));
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
+	ASSERT(args->index < be16_to_cpu(leaf->hdr.count));
 	ASSERT(args->index >= 0);
 	entry = &leaf->entries[ args->index ];
 	ASSERT(entry->flags & XFS_ATTR_INCOMPLETE);
@@ -2613,7 +2526,7 @@
 		namelen = name_rmt->namelen;
 		name = (char *)name_rmt->name;
 	}
-	ASSERT(INT_GET(entry->hashval, ARCH_CONVERT) == args->hashval);
+	ASSERT(be32_to_cpu(entry->hashval) == args->hashval);
 	ASSERT(namelen == args->namelen);
 	ASSERT(memcmp(name, args->name, namelen) == 0);
 #endif /* DEBUG */
@@ -2625,8 +2538,8 @@
 	if (args->rmtblkno) {
 		ASSERT((entry->flags & XFS_ATTR_LOCAL) == 0);
 		name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index);
-		INT_SET(name_rmt->valueblk, ARCH_CONVERT, args->rmtblkno);
-		INT_SET(name_rmt->valuelen, ARCH_CONVERT, args->valuelen);
+		name_rmt->valueblk = cpu_to_be32(args->rmtblkno);
+		name_rmt->valuelen = cpu_to_be32(args->valuelen);
 		xfs_da_log_buf(args->trans, bp,
 			 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
 	}
@@ -2663,9 +2576,8 @@
 	ASSERT(bp != NULL);
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
-	ASSERT(args->index < INT_GET(leaf->hdr.count, ARCH_CONVERT));
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
+	ASSERT(args->index < be16_to_cpu(leaf->hdr.count));
 	ASSERT(args->index >= 0);
 	entry = &leaf->entries[ args->index ];
 
@@ -2736,16 +2648,14 @@
 	}
 
 	leaf1 = bp1->data;
-	ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
-	ASSERT(args->index < INT_GET(leaf1->hdr.count, ARCH_CONVERT));
+	ASSERT(be16_to_cpu(leaf1->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
+	ASSERT(args->index < be16_to_cpu(leaf1->hdr.count));
 	ASSERT(args->index >= 0);
 	entry1 = &leaf1->entries[ args->index ];
 
 	leaf2 = bp2->data;
-	ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
-	ASSERT(args->index2 < INT_GET(leaf2->hdr.count, ARCH_CONVERT));
+	ASSERT(be16_to_cpu(leaf2->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
+	ASSERT(args->index2 < be16_to_cpu(leaf2->hdr.count));
 	ASSERT(args->index2 >= 0);
 	entry2 = &leaf2->entries[ args->index2 ];
 
@@ -2768,7 +2678,7 @@
 		namelen2 = name_rmt->namelen;
 		name2 = (char *)name_rmt->name;
 	}
-	ASSERT(INT_GET(entry1->hashval, ARCH_CONVERT) == INT_GET(entry2->hashval, ARCH_CONVERT));
+	ASSERT(be32_to_cpu(entry1->hashval) == be32_to_cpu(entry2->hashval));
 	ASSERT(namelen1 == namelen2);
 	ASSERT(memcmp(name1, name2, namelen1) == 0);
 #endif /* DEBUG */
@@ -2782,8 +2692,8 @@
 	if (args->rmtblkno) {
 		ASSERT((entry1->flags & XFS_ATTR_LOCAL) == 0);
 		name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf1, args->index);
-		INT_SET(name_rmt->valueblk, ARCH_CONVERT, args->rmtblkno);
-		INT_SET(name_rmt->valuelen, ARCH_CONVERT, args->valuelen);
+		name_rmt->valueblk = cpu_to_be32(args->rmtblkno);
+		name_rmt->valuelen = cpu_to_be32(args->valuelen);
 		xfs_da_log_buf(args->trans, bp1,
 			 XFS_DA_LOGRANGE(leaf1, name_rmt, sizeof(*name_rmt)));
 	}
@@ -2842,9 +2752,9 @@
 	 * This is a depth-first traversal!
 	 */
 	info = bp->data;
-	if (INT_GET(info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) {
+	if (be16_to_cpu(info->magic) == XFS_DA_NODE_MAGIC) {
 		error = xfs_attr_node_inactive(trans, dp, bp, 1);
-	} else if (INT_GET(info->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC) {
+	} else if (be16_to_cpu(info->magic) == XFS_ATTR_LEAF_MAGIC) {
 		error = xfs_attr_leaf_inactive(trans, dp, bp);
 	} else {
 		error = XFS_ERROR(EIO);
@@ -2892,15 +2802,14 @@
 	}
 
 	node = bp->data;
-	ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT)
-						== XFS_DA_NODE_MAGIC);
+	ASSERT(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
 	parent_blkno = xfs_da_blkno(bp);	/* save for re-read later */
-	count = INT_GET(node->hdr.count, ARCH_CONVERT);
+	count = be16_to_cpu(node->hdr.count);
 	if (!count) {
 		xfs_da_brelse(*trans, bp);
 		return(0);
 	}
-	child_fsb = INT_GET(node->btree[0].before, ARCH_CONVERT);
+	child_fsb = be32_to_cpu(node->btree[0].before);
 	xfs_da_brelse(*trans, bp);	/* no locks for later trans */
 
 	/*
@@ -2927,12 +2836,10 @@
 			 * Invalidate the subtree, however we have to.
 			 */
 			info = child_bp->data;
-			if (INT_GET(info->magic, ARCH_CONVERT)
-							== XFS_DA_NODE_MAGIC) {
+			if (be16_to_cpu(info->magic) == XFS_DA_NODE_MAGIC) {
 				error = xfs_attr_node_inactive(trans, dp,
 						child_bp, level+1);
-			} else if (INT_GET(info->magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC) {
+			} else if (be16_to_cpu(info->magic) == XFS_ATTR_LEAF_MAGIC) {
 				error = xfs_attr_leaf_inactive(trans, dp,
 						child_bp);
 			} else {
@@ -2962,7 +2869,7 @@
 				&bp, XFS_ATTR_FORK);
 			if (error)
 				return(error);
-			child_fsb = INT_GET(node->btree[i+1].before, ARCH_CONVERT);
+			child_fsb = be32_to_cpu(node->btree[i+1].before);
 			xfs_da_brelse(*trans, bp);
 		}
 		/*
@@ -2991,17 +2898,16 @@
 	int error, count, size, tmp, i;
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
-						== XFS_ATTR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_ATTR_LEAF_MAGIC);
 
 	/*
 	 * Count the number of "remote" value extents.
 	 */
 	count = 0;
 	entry = &leaf->entries[0];
-	for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) {
-		if (   INT_GET(entry->nameidx, ARCH_CONVERT)
-		    && ((entry->flags & XFS_ATTR_LOCAL) == 0)) {
+	for (i = 0; i < be16_to_cpu(leaf->hdr.count); entry++, i++) {
+		if (be16_to_cpu(entry->nameidx) &&
+		    ((entry->flags & XFS_ATTR_LOCAL) == 0)) {
 			name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
 			if (name_rmt->valueblk)
 				count++;
@@ -3027,17 +2933,14 @@
 	 */
 	lp = list;
 	entry = &leaf->entries[0];
-	for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) {
-		if (   INT_GET(entry->nameidx, ARCH_CONVERT)
-		    && ((entry->flags & XFS_ATTR_LOCAL) == 0)) {
+	for (i = 0; i < be16_to_cpu(leaf->hdr.count); entry++, i++) {
+		if (be16_to_cpu(entry->nameidx) &&
+		    ((entry->flags & XFS_ATTR_LOCAL) == 0)) {
 			name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
 			if (name_rmt->valueblk) {
-				/* both on-disk, don't endian flip twice */
-				lp->valueblk = name_rmt->valueblk;
-				INT_SET(lp->valuelen, ARCH_CONVERT,
-						XFS_B_TO_FSB(dp->i_mount,
-						    INT_GET(name_rmt->valuelen,
-							      ARCH_CONVERT)));
+				lp->valueblk = be32_to_cpu(name_rmt->valueblk);
+				lp->valuelen = XFS_B_TO_FSB(dp->i_mount,
+						    be32_to_cpu(name_rmt->valuelen));
 				lp++;
 			}
 		}
@@ -3050,10 +2953,8 @@
 	error = 0;
 	for (lp = list, i = 0; i < count; i++, lp++) {
 		tmp = xfs_attr_leaf_freextent(trans, dp,
-						     INT_GET(lp->valueblk,
-								ARCH_CONVERT),
-						     INT_GET(lp->valuelen,
-								ARCH_CONVERT));
+				lp->valueblk, lp->valuelen);
+
 		if (error == 0)
 			error = tmp;	/* save only the 1st errno */
 	}
diff -urN oldtree/fs/xfs/xfs_attr_leaf.h newtree/fs/xfs/xfs_attr_leaf.h
--- oldtree/fs/xfs/xfs_attr_leaf.h	2006-02-19 11:41:05.391523464 +0000
+++ newtree/fs/xfs/xfs_attr_leaf.h	2006-02-21 15:58:36.712565400 +0000
@@ -73,39 +73,39 @@
 #define XFS_ATTR_LEAF_MAPSIZE	3	/* how many freespace slots */
 
 typedef struct xfs_attr_leaf_map {	/* RLE map of free bytes */
-	__uint16_t	base;	 	/* base of free region */
-	__uint16_t	size;	  	/* length of free region */
+	__be16	base;			  /* base of free region */
+	__be16	size;			  /* length of free region */
 } xfs_attr_leaf_map_t;
 
 typedef struct xfs_attr_leaf_hdr {	/* constant-structure header block */
 	xfs_da_blkinfo_t info;		/* block type, links, etc. */
-	__uint16_t	count;		/* count of active leaf_entry's */
-	__uint16_t	usedbytes;	/* num bytes of names/values stored */
-	__uint16_t	firstused;	/* first used byte in name area */
-	__uint8_t	holes;		/* != 0 if blk needs compaction */
-	__uint8_t	pad1;
+	__be16	count;			/* count of active leaf_entry's */
+	__be16	usedbytes;		/* num bytes of names/values stored */
+	__be16	firstused;		/* first used byte in name area */
+	__u8	holes;			/* != 0 if blk needs compaction */
+	__u8	pad1;
 	xfs_attr_leaf_map_t freemap[XFS_ATTR_LEAF_MAPSIZE];
 					/* N largest free regions */
 } xfs_attr_leaf_hdr_t;
 
 typedef struct xfs_attr_leaf_entry {	/* sorted on key, not name */
-	xfs_dahash_t	hashval;	/* hash value of name */
-	__uint16_t	nameidx;	/* index into buffer of name/value */
-	__uint8_t	flags;		/* LOCAL/ROOT/SECURE/INCOMPLETE flag */
-	__uint8_t	pad2;		/* unused pad byte */
+	__be32	hashval;		/* hash value of name */
+ 	__be16	nameidx;		/* index into buffer of name/value */
+	__u8	flags;			/* LOCAL/ROOT/SECURE/INCOMPLETE flag */
+	__u8	pad2;			/* unused pad byte */
 } xfs_attr_leaf_entry_t;
 
 typedef struct xfs_attr_leaf_name_local {
-	__uint16_t	valuelen;	/* number of bytes in value */
-	__uint8_t	namelen;	/* length of name bytes */
-	__uint8_t	nameval[1];	/* name/value bytes */
+	__be16	valuelen;		/* number of bytes in value */
+	__u8	namelen;		/* length of name bytes */
+	__u8	nameval[1];		/* name/value bytes */
 } xfs_attr_leaf_name_local_t;
 
 typedef struct xfs_attr_leaf_name_remote {
-	xfs_dablk_t	valueblk;	/* block number of value bytes */
-	__uint32_t	valuelen;	/* number of bytes in value */
-	__uint8_t	namelen;	/* length of name bytes */
-	__uint8_t	name[1];	/* name bytes */
+	__be32	valueblk;		/* block number of value bytes */
+	__be32	valuelen;		/* number of bytes in value */
+	__u8	namelen;		/* length of name bytes */
+	__u8	name[1];		/* name bytes */
 } xfs_attr_leaf_name_remote_t;
 
 typedef struct xfs_attr_leafblock {
@@ -143,8 +143,8 @@
 static inline xfs_attr_leaf_name_remote_t *
 xfs_attr_leaf_name_remote(xfs_attr_leafblock_t *leafp, int idx)
 {
-	return (xfs_attr_leaf_name_remote_t *) &((char *)
-		(leafp))[INT_GET((leafp)->entries[idx].nameidx, ARCH_CONVERT)];
+	return (xfs_attr_leaf_name_remote_t *)
+		&((char *)leafp)[be16_to_cpu(leafp->entries[idx].nameidx)];
 }
 
 #define XFS_ATTR_LEAF_NAME_LOCAL(leafp,idx)	\
@@ -152,16 +152,15 @@
 static inline xfs_attr_leaf_name_local_t *
 xfs_attr_leaf_name_local(xfs_attr_leafblock_t *leafp, int idx)
 {
-	return (xfs_attr_leaf_name_local_t *) &((char *)
-		(leafp))[INT_GET((leafp)->entries[idx].nameidx, ARCH_CONVERT)];
+	return (xfs_attr_leaf_name_local_t *)
+		&((char *)leafp)[be16_to_cpu(leafp->entries[idx].nameidx)];
 }
 
 #define XFS_ATTR_LEAF_NAME(leafp,idx)		\
 	xfs_attr_leaf_name(leafp,idx)
 static inline char *xfs_attr_leaf_name(xfs_attr_leafblock_t *leafp, int idx)
 {
-	return (&((char *)
-		(leafp))[INT_GET((leafp)->entries[idx].nameidx, ARCH_CONVERT)]);
+	return &((char *)leafp)[be16_to_cpu(leafp->entries[idx].nameidx)];
 }
 
 /*
diff -urN oldtree/fs/xfs/xfs_attr_sf.h newtree/fs/xfs/xfs_attr_sf.h
--- oldtree/fs/xfs/xfs_attr_sf.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/xfs/xfs_attr_sf.h	2006-02-21 15:58:36.712565400 +0000
@@ -32,8 +32,8 @@
  */
 typedef struct xfs_attr_shortform {
 	struct xfs_attr_sf_hdr {	/* constant-structure header block */
-		__uint16_t totsize;	/* total bytes in shortform list */
-		__uint8_t count;	/* count of active entries */
+		__be16	totsize;	/* total bytes in shortform list */
+		__u8	count;	/* count of active entries */
 	} hdr;
 	struct xfs_attr_sf_entry {
 		__uint8_t namelen;	/* actual length of name (no NULL) */
@@ -66,8 +66,8 @@
 #define XFS_ATTR_SF_NEXTENTRY(sfep)		/* next entry in struct */ \
 	((xfs_attr_sf_entry_t *)((char *)(sfep) + XFS_ATTR_SF_ENTSIZE(sfep)))
 #define XFS_ATTR_SF_TOTSIZE(dp)			/* total space in use */ \
-	(INT_GET(((xfs_attr_shortform_t *)	\
-		((dp)->i_afp->if_u1.if_data))->hdr.totsize, ARCH_CONVERT))
+	(be16_to_cpu(((xfs_attr_shortform_t *)	\
+		((dp)->i_afp->if_u1.if_data))->hdr.totsize))
 
 #if defined(XFS_ATTR_TRACE)
 /*
diff -urN oldtree/fs/xfs/xfs_clnt.h newtree/fs/xfs/xfs_clnt.h
--- oldtree/fs/xfs/xfs_clnt.h	2006-02-19 11:41:05.395522856 +0000
+++ newtree/fs/xfs/xfs_clnt.h	2006-02-21 15:58:21.837826704 +0000
@@ -68,8 +68,6 @@
 						 * enforcement */
 #define XFSMNT_PQUOTAENF	0x00000040	/* IRIX project quota limit
 						 * enforcement */
-#define XFSMNT_NOATIME		0x00000100	/* don't modify access
-						 * times on reads */
 #define XFSMNT_NOALIGN		0x00000200	/* don't allocate at
 						 * stripe boundaries*/
 #define XFSMNT_RETERR		0x00000400	/* return error to user */
diff -urN oldtree/fs/xfs/xfs_da_btree.c newtree/fs/xfs/xfs_da_btree.c
--- oldtree/fs/xfs/xfs_da_btree.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/xfs/xfs_da_btree.c	2006-02-21 15:58:36.721564032 +0000
@@ -126,10 +126,10 @@
 	node = bp->data;
 	node->hdr.info.forw = 0;
 	node->hdr.info.back = 0;
-	INT_SET(node->hdr.info.magic, ARCH_CONVERT, XFS_DA_NODE_MAGIC);
+	node->hdr.info.magic = cpu_to_be16(XFS_DA_NODE_MAGIC);
 	node->hdr.info.pad = 0;
 	node->hdr.count = 0;
-	INT_SET(node->hdr.level, ARCH_CONVERT, level);
+	node->hdr.level = cpu_to_be16(level);
 
 	xfs_da_log_buf(tp, bp,
 		XFS_DA_LOGRANGE(node, &node->hdr, sizeof(node->hdr)));
@@ -290,28 +290,28 @@
 
 	node = oldblk->bp->data;
 	if (node->hdr.info.forw) {
-		if (INT_GET(node->hdr.info.forw, ARCH_CONVERT) == addblk->blkno) {
+		if (be32_to_cpu(node->hdr.info.forw) == addblk->blkno) {
 			bp = addblk->bp;
 		} else {
 			ASSERT(state->extravalid);
 			bp = state->extrablk.bp;
 		}
 		node = bp->data;
-		INT_SET(node->hdr.info.back, ARCH_CONVERT, oldblk->blkno);
+		node->hdr.info.back = cpu_to_be32(oldblk->blkno);
 		xfs_da_log_buf(state->args->trans, bp,
 		    XFS_DA_LOGRANGE(node, &node->hdr.info,
 		    sizeof(node->hdr.info)));
 	}
 	node = oldblk->bp->data;
-	if (INT_GET(node->hdr.info.back, ARCH_CONVERT)) {
-		if (INT_GET(node->hdr.info.back, ARCH_CONVERT) == addblk->blkno) {
+	if (node->hdr.info.back) {
+		if (be32_to_cpu(node->hdr.info.back) == addblk->blkno) {
 			bp = addblk->bp;
 		} else {
 			ASSERT(state->extravalid);
 			bp = state->extrablk.bp;
 		}
 		node = bp->data;
-		INT_SET(node->hdr.info.forw, ARCH_CONVERT, oldblk->blkno);
+		node->hdr.info.forw = cpu_to_be32(oldblk->blkno);
 		xfs_da_log_buf(state->args->trans, bp,
 		    XFS_DA_LOGRANGE(node, &node->hdr.info,
 		    sizeof(node->hdr.info)));
@@ -359,14 +359,14 @@
 	ASSERT(bp != NULL);
 	node = bp->data;
 	oldroot = blk1->bp->data;
-	if (INT_GET(oldroot->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) {
-		size = (int)((char *)&oldroot->btree[INT_GET(oldroot->hdr.count, ARCH_CONVERT)] -
+	if (be16_to_cpu(oldroot->hdr.info.magic) == XFS_DA_NODE_MAGIC) {
+		size = (int)((char *)&oldroot->btree[be16_to_cpu(oldroot->hdr.count)] -
 			     (char *)oldroot);
 	} else {
 		ASSERT(XFS_DIR_IS_V2(mp));
-		ASSERT(INT_GET(oldroot->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC);
+		ASSERT(be16_to_cpu(oldroot->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);
 		leaf = (xfs_dir2_leaf_t *)oldroot;
-		size = (int)((char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] -
+		size = (int)((char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] -
 			     (char *)leaf);
 	}
 	memcpy(node, oldroot, size);
@@ -381,18 +381,18 @@
 	error = xfs_da_node_create(args,
 		args->whichfork == XFS_DATA_FORK &&
 		XFS_DIR_IS_V2(mp) ? mp->m_dirleafblk : 0,
-		INT_GET(node->hdr.level, ARCH_CONVERT) + 1, &bp, args->whichfork);
+		be16_to_cpu(node->hdr.level) + 1, &bp, args->whichfork);
 	if (error)
 		return(error);
 	node = bp->data;
-	INT_SET(node->btree[0].hashval, ARCH_CONVERT, blk1->hashval);
-	INT_SET(node->btree[0].before, ARCH_CONVERT, blk1->blkno);
-	INT_SET(node->btree[1].hashval, ARCH_CONVERT, blk2->hashval);
-	INT_SET(node->btree[1].before, ARCH_CONVERT, blk2->blkno);
-	INT_SET(node->hdr.count, ARCH_CONVERT, 2);
+	node->btree[0].hashval = cpu_to_be32(blk1->hashval);
+	node->btree[0].before = cpu_to_be32(blk1->blkno);
+	node->btree[1].hashval = cpu_to_be32(blk2->hashval);
+	node->btree[1].before = cpu_to_be32(blk2->blkno);
+	node->hdr.count = cpu_to_be16(2);
 
 #ifdef DEBUG
-	if (INT_GET(oldroot->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC) {
+	if (be16_to_cpu(oldroot->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC) {
 		ASSERT(blk1->blkno >= mp->m_dirleafblk &&
 		       blk1->blkno < mp->m_dirfreeblk);
 		ASSERT(blk2->blkno >= mp->m_dirleafblk &&
@@ -424,7 +424,7 @@
 	int useextra;
 
 	node = oldblk->bp->data;
-	ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC);
+	ASSERT(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
 
 	/*
 	 * With V2 the extra block is data or freespace.
@@ -435,7 +435,7 @@
 	/*
 	 * Do we have to split the node?
 	 */
-	if ((INT_GET(node->hdr.count, ARCH_CONVERT) + newcount) > state->node_ents) {
+	if ((be16_to_cpu(node->hdr.count) + newcount) > state->node_ents) {
 		/*
 		 * Allocate a new node, add to the doubly linked chain of
 		 * nodes, then move some of our excess entries into it.
@@ -472,7 +472,7 @@
 	 * If we had double-split op below us, then add the extra block too.
 	 */
 	node = oldblk->bp->data;
-	if (oldblk->index <= INT_GET(node->hdr.count, ARCH_CONVERT)) {
+	if (oldblk->index <= be16_to_cpu(node->hdr.count)) {
 		oldblk->index++;
 		xfs_da_node_add(state, oldblk, addblk);
 		if (useextra) {
@@ -516,17 +516,17 @@
 	 * Figure out how many entries need to move, and in which direction.
 	 * Swap the nodes around if that makes it simpler.
 	 */
-	if ((INT_GET(node1->hdr.count, ARCH_CONVERT) > 0) && (INT_GET(node2->hdr.count, ARCH_CONVERT) > 0) &&
-	    ((INT_GET(node2->btree[ 0 ].hashval, ARCH_CONVERT) < INT_GET(node1->btree[ 0 ].hashval, ARCH_CONVERT)) ||
-	     (INT_GET(node2->btree[ INT_GET(node2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT) <
-	      INT_GET(node1->btree[ INT_GET(node1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)))) {
+	if ((be16_to_cpu(node1->hdr.count) > 0) && (be16_to_cpu(node2->hdr.count) > 0) &&
+	    ((be32_to_cpu(node2->btree[0].hashval) < be32_to_cpu(node1->btree[0].hashval)) ||
+	     (be32_to_cpu(node2->btree[be16_to_cpu(node2->hdr.count)-1].hashval) <
+	      be32_to_cpu(node1->btree[be16_to_cpu(node1->hdr.count)-1].hashval)))) {
 		tmpnode = node1;
 		node1 = node2;
 		node2 = tmpnode;
 	}
-	ASSERT(INT_GET(node1->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC);
-	ASSERT(INT_GET(node2->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC);
-	count = (INT_GET(node1->hdr.count, ARCH_CONVERT) - INT_GET(node2->hdr.count, ARCH_CONVERT)) / 2;
+	ASSERT(be16_to_cpu(node1->hdr.info.magic) == XFS_DA_NODE_MAGIC);
+	ASSERT(be16_to_cpu(node2->hdr.info.magic) == XFS_DA_NODE_MAGIC);
+	count = (be16_to_cpu(node1->hdr.count) - be16_to_cpu(node2->hdr.count)) / 2;
 	if (count == 0)
 		return;
 	tp = state->args->trans;
@@ -537,7 +537,7 @@
 		/*
 		 * Move elements in node2 up to make a hole.
 		 */
-		if ((tmp = INT_GET(node2->hdr.count, ARCH_CONVERT)) > 0) {
+		if ((tmp = be16_to_cpu(node2->hdr.count)) > 0) {
 			tmp *= (uint)sizeof(xfs_da_node_entry_t);
 			btree_s = &node2->btree[0];
 			btree_d = &node2->btree[count];
@@ -548,13 +548,12 @@
 		 * Move the req'd B-tree elements from high in node1 to
 		 * low in node2.
 		 */
-		INT_MOD(node2->hdr.count, ARCH_CONVERT, count);
+		be16_add(&node2->hdr.count, count);
 		tmp = count * (uint)sizeof(xfs_da_node_entry_t);
-		btree_s = &node1->btree[INT_GET(node1->hdr.count, ARCH_CONVERT) - count];
+		btree_s = &node1->btree[be16_to_cpu(node1->hdr.count) - count];
 		btree_d = &node2->btree[0];
 		memcpy(btree_d, btree_s, tmp);
-		INT_MOD(node1->hdr.count, ARCH_CONVERT, -(count));
-
+		be16_add(&node1->hdr.count, -count);
 	} else {
 		/*
 		 * Move the req'd B-tree elements from low in node2 to
@@ -563,21 +562,21 @@
 		count = -count;
 		tmp = count * (uint)sizeof(xfs_da_node_entry_t);
 		btree_s = &node2->btree[0];
-		btree_d = &node1->btree[INT_GET(node1->hdr.count, ARCH_CONVERT)];
+		btree_d = &node1->btree[be16_to_cpu(node1->hdr.count)];
 		memcpy(btree_d, btree_s, tmp);
-		INT_MOD(node1->hdr.count, ARCH_CONVERT, count);
+		be16_add(&node1->hdr.count, count);
 		xfs_da_log_buf(tp, blk1->bp,
 			XFS_DA_LOGRANGE(node1, btree_d, tmp));
 
 		/*
 		 * Move elements in node2 down to fill the hole.
 		 */
-		tmp  = INT_GET(node2->hdr.count, ARCH_CONVERT) - count;
+		tmp  = be16_to_cpu(node2->hdr.count) - count;
 		tmp *= (uint)sizeof(xfs_da_node_entry_t);
 		btree_s = &node2->btree[count];
 		btree_d = &node2->btree[0];
 		memmove(btree_d, btree_s, tmp);
-		INT_MOD(node2->hdr.count, ARCH_CONVERT, -(count));
+		be16_add(&node2->hdr.count, -count);
 	}
 
 	/*
@@ -588,7 +587,7 @@
 	xfs_da_log_buf(tp, blk2->bp,
 		XFS_DA_LOGRANGE(node2, &node2->hdr,
 			sizeof(node2->hdr) +
-			sizeof(node2->btree[0]) * INT_GET(node2->hdr.count, ARCH_CONVERT)));
+			sizeof(node2->btree[0]) * be16_to_cpu(node2->hdr.count)));
 
 	/*
 	 * Record the last hashval from each block for upward propagation.
@@ -596,15 +595,15 @@
 	 */
 	node1 = blk1->bp->data;
 	node2 = blk2->bp->data;
-	blk1->hashval = INT_GET(node1->btree[ INT_GET(node1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT);
-	blk2->hashval = INT_GET(node2->btree[ INT_GET(node2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT);
+	blk1->hashval = be32_to_cpu(node1->btree[be16_to_cpu(node1->hdr.count)-1].hashval);
+	blk2->hashval = be32_to_cpu(node2->btree[be16_to_cpu(node2->hdr.count)-1].hashval);
 
 	/*
 	 * Adjust the expected index for insertion.
 	 */
-	if (blk1->index >= INT_GET(node1->hdr.count, ARCH_CONVERT)) {
-		blk2->index = blk1->index - INT_GET(node1->hdr.count, ARCH_CONVERT);
-		blk1->index = INT_GET(node1->hdr.count, ARCH_CONVERT) + 1;	/* make it invalid */
+	if (blk1->index >= be16_to_cpu(node1->hdr.count)) {
+		blk2->index = blk1->index - be16_to_cpu(node1->hdr.count);
+		blk1->index = be16_to_cpu(node1->hdr.count) + 1;	/* make it invalid */
 	}
 }
 
@@ -622,8 +621,8 @@
 
 	node = oldblk->bp->data;
 	mp = state->mp;
-	ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC);
-	ASSERT((oldblk->index >= 0) && (oldblk->index <= INT_GET(node->hdr.count, ARCH_CONVERT)));
+	ASSERT(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
+	ASSERT((oldblk->index >= 0) && (oldblk->index <= be16_to_cpu(node->hdr.count)));
 	ASSERT(newblk->blkno != 0);
 	if (state->args->whichfork == XFS_DATA_FORK && XFS_DIR_IS_V2(mp))
 		ASSERT(newblk->blkno >= mp->m_dirleafblk &&
@@ -634,22 +633,22 @@
 	 */
 	tmp = 0;
 	btree = &node->btree[ oldblk->index ];
-	if (oldblk->index < INT_GET(node->hdr.count, ARCH_CONVERT)) {
-		tmp = (INT_GET(node->hdr.count, ARCH_CONVERT) - oldblk->index) * (uint)sizeof(*btree);
+	if (oldblk->index < be16_to_cpu(node->hdr.count)) {
+		tmp = (be16_to_cpu(node->hdr.count) - oldblk->index) * (uint)sizeof(*btree);
 		memmove(btree + 1, btree, tmp);
 	}
-	INT_SET(btree->hashval, ARCH_CONVERT, newblk->hashval);
-	INT_SET(btree->before, ARCH_CONVERT, newblk->blkno);
+	btree->hashval = cpu_to_be32(newblk->hashval);
+	btree->before = cpu_to_be32(newblk->blkno);
 	xfs_da_log_buf(state->args->trans, oldblk->bp,
 		XFS_DA_LOGRANGE(node, btree, tmp + sizeof(*btree)));
-	INT_MOD(node->hdr.count, ARCH_CONVERT, +1);
+	be16_add(&node->hdr.count, 1);
 	xfs_da_log_buf(state->args->trans, oldblk->bp,
 		XFS_DA_LOGRANGE(node, &node->hdr, sizeof(node->hdr)));
 
 	/*
 	 * Copy the last hash value from the oldblk to propagate upwards.
 	 */
-	oldblk->hashval = INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT);
+	oldblk->hashval = be32_to_cpu(node->btree[be16_to_cpu(node->hdr.count)-1 ].hashval);
 }
 
 /*========================================================================
@@ -768,21 +767,21 @@
 	ASSERT(args != NULL);
 	ASSERT(root_blk->magic == XFS_DA_NODE_MAGIC);
 	oldroot = root_blk->bp->data;
-	ASSERT(INT_GET(oldroot->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC);
+	ASSERT(be16_to_cpu(oldroot->hdr.info.magic) == XFS_DA_NODE_MAGIC);
 	ASSERT(!oldroot->hdr.info.forw);
 	ASSERT(!oldroot->hdr.info.back);
 
 	/*
 	 * If the root has more than one child, then don't do anything.
 	 */
-	if (INT_GET(oldroot->hdr.count, ARCH_CONVERT) > 1)
+	if (be16_to_cpu(oldroot->hdr.count) > 1)
 		return(0);
 
 	/*
 	 * Read in the (only) child block, then copy those bytes into
 	 * the root block's buffer and free the original child block.
 	 */
-	child = INT_GET(oldroot->btree[ 0 ].before, ARCH_CONVERT);
+	child = be32_to_cpu(oldroot->btree[0].before);
 	ASSERT(child != 0);
 	error = xfs_da_read_buf(args->trans, args->dp, child, -1, &bp,
 					     args->whichfork);
@@ -790,11 +789,11 @@
 		return(error);
 	ASSERT(bp != NULL);
 	blkinfo = bp->data;
-	if (INT_GET(oldroot->hdr.level, ARCH_CONVERT) == 1) {
-		ASSERT(INT_GET(blkinfo->magic, ARCH_CONVERT) == XFS_DIRX_LEAF_MAGIC(state->mp) ||
-		       INT_GET(blkinfo->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC);
+	if (be16_to_cpu(oldroot->hdr.level) == 1) {
+		ASSERT(be16_to_cpu(blkinfo->magic) == XFS_DIRX_LEAF_MAGIC(state->mp) ||
+		       be16_to_cpu(blkinfo->magic) == XFS_ATTR_LEAF_MAGIC);
 	} else {
-		ASSERT(INT_GET(blkinfo->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC);
+		ASSERT(be16_to_cpu(blkinfo->magic) == XFS_DA_NODE_MAGIC);
 	}
 	ASSERT(!blkinfo->forw);
 	ASSERT(!blkinfo->back);
@@ -830,9 +829,9 @@
 	 */
 	blk = &state->path.blk[ state->path.active-1 ];
 	info = blk->bp->data;
-	ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC);
+	ASSERT(be16_to_cpu(info->magic) == XFS_DA_NODE_MAGIC);
 	node = (xfs_da_intnode_t *)info;
-	count = INT_GET(node->hdr.count, ARCH_CONVERT);
+	count = be16_to_cpu(node->hdr.count);
 	if (count > (state->node_ents >> 1)) {
 		*action = 0;	/* blk over 50%, don't try to join */
 		return(0);	/* blk over 50%, don't try to join */
@@ -849,7 +848,7 @@
 		 * Make altpath point to the block we want to keep and
 		 * path point to the block we want to drop (this one).
 		 */
-		forward = info->forw;
+		forward = (info->forw != 0);
 		memcpy(&state->altpath, &state->path, sizeof(state->path));
 		error = xfs_da_path_shift(state, &state->altpath, forward,
 						 0, &retval);
@@ -871,13 +870,12 @@
 	 * to shrink a directory over time.
 	 */
 	/* start with smaller blk num */
-	forward = (INT_GET(info->forw, ARCH_CONVERT)
-				< INT_GET(info->back, ARCH_CONVERT));
+	forward = (be32_to_cpu(info->forw) < be32_to_cpu(info->back));
 	for (i = 0; i < 2; forward = !forward, i++) {
 		if (forward)
-			blkno = INT_GET(info->forw, ARCH_CONVERT);
+			blkno = be32_to_cpu(info->forw);
 		else
-			blkno = INT_GET(info->back, ARCH_CONVERT);
+			blkno = be32_to_cpu(info->back);
 		if (blkno == 0)
 			continue;
 		error = xfs_da_read_buf(state->args->trans, state->args->dp,
@@ -889,10 +887,10 @@
 		node = (xfs_da_intnode_t *)info;
 		count  = state->node_ents;
 		count -= state->node_ents >> 2;
-		count -= INT_GET(node->hdr.count, ARCH_CONVERT);
+		count -= be16_to_cpu(node->hdr.count);
 		node = bp->data;
-		ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC);
-		count -= INT_GET(node->hdr.count, ARCH_CONVERT);
+		ASSERT(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
+		count -= be16_to_cpu(node->hdr.count);
 		xfs_da_brelse(state->args->trans, bp);
 		if (count >= 0)
 			break;	/* fits with at least 25% to spare */
@@ -973,16 +971,16 @@
 	}
 	for (blk--, level--; level >= 0; blk--, level--) {
 		node = blk->bp->data;
-		ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC);
+		ASSERT(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
 		btree = &node->btree[ blk->index ];
-		if (INT_GET(btree->hashval, ARCH_CONVERT) == lasthash)
+		if (be32_to_cpu(btree->hashval) == lasthash)
 			break;
 		blk->hashval = lasthash;
-		INT_SET(btree->hashval, ARCH_CONVERT, lasthash);
+		btree->hashval = cpu_to_be32(lasthash);
 		xfs_da_log_buf(state->args->trans, blk->bp,
 				  XFS_DA_LOGRANGE(node, btree, sizeof(*btree)));
 
-		lasthash = INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT);
+		lasthash = be32_to_cpu(node->btree[be16_to_cpu(node->hdr.count)-1].hashval);
 	}
 }
 
@@ -997,25 +995,25 @@
 	int tmp;
 
 	node = drop_blk->bp->data;
-	ASSERT(drop_blk->index < INT_GET(node->hdr.count, ARCH_CONVERT));
+	ASSERT(drop_blk->index < be16_to_cpu(node->hdr.count));
 	ASSERT(drop_blk->index >= 0);
 
 	/*
 	 * Copy over the offending entry, or just zero it out.
 	 */
 	btree = &node->btree[drop_blk->index];
-	if (drop_blk->index < (INT_GET(node->hdr.count, ARCH_CONVERT)-1)) {
-		tmp  = INT_GET(node->hdr.count, ARCH_CONVERT) - drop_blk->index - 1;
+	if (drop_blk->index < (be16_to_cpu(node->hdr.count)-1)) {
+		tmp  = be16_to_cpu(node->hdr.count) - drop_blk->index - 1;
 		tmp *= (uint)sizeof(xfs_da_node_entry_t);
 		memmove(btree, btree + 1, tmp);
 		xfs_da_log_buf(state->args->trans, drop_blk->bp,
 		    XFS_DA_LOGRANGE(node, btree, tmp));
-		btree = &node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ];
+		btree = &node->btree[be16_to_cpu(node->hdr.count)-1];
 	}
 	memset((char *)btree, 0, sizeof(xfs_da_node_entry_t));
 	xfs_da_log_buf(state->args->trans, drop_blk->bp,
 	    XFS_DA_LOGRANGE(node, btree, sizeof(*btree)));
-	INT_MOD(node->hdr.count, ARCH_CONVERT, -1);
+	be16_add(&node->hdr.count, -1);
 	xfs_da_log_buf(state->args->trans, drop_blk->bp,
 	    XFS_DA_LOGRANGE(node, &node->hdr, sizeof(node->hdr)));
 
@@ -1023,7 +1021,7 @@
 	 * Copy the last hash value from the block to propagate upwards.
 	 */
 	btree--;
-	drop_blk->hashval = INT_GET(btree->hashval, ARCH_CONVERT);
+	drop_blk->hashval = be32_to_cpu(btree->hashval);
 }
 
 /*
@@ -1041,40 +1039,40 @@
 
 	drop_node = drop_blk->bp->data;
 	save_node = save_blk->bp->data;
-	ASSERT(INT_GET(drop_node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC);
-	ASSERT(INT_GET(save_node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC);
+	ASSERT(be16_to_cpu(drop_node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
+	ASSERT(be16_to_cpu(save_node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
 	tp = state->args->trans;
 
 	/*
 	 * If the dying block has lower hashvals, then move all the
 	 * elements in the remaining block up to make a hole.
 	 */
-	if ((INT_GET(drop_node->btree[ 0 ].hashval, ARCH_CONVERT) < INT_GET(save_node->btree[ 0 ].hashval, ARCH_CONVERT)) ||
-	    (INT_GET(drop_node->btree[ INT_GET(drop_node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT) <
-	     INT_GET(save_node->btree[ INT_GET(save_node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)))
+	if ((be32_to_cpu(drop_node->btree[0].hashval) < be32_to_cpu(save_node->btree[ 0 ].hashval)) ||
+	    (be32_to_cpu(drop_node->btree[be16_to_cpu(drop_node->hdr.count)-1].hashval) <
+	     be32_to_cpu(save_node->btree[be16_to_cpu(save_node->hdr.count)-1].hashval)))
 	{
-		btree = &save_node->btree[ INT_GET(drop_node->hdr.count, ARCH_CONVERT) ];
-		tmp = INT_GET(save_node->hdr.count, ARCH_CONVERT) * (uint)sizeof(xfs_da_node_entry_t);
+		btree = &save_node->btree[be16_to_cpu(drop_node->hdr.count)];
+		tmp = be16_to_cpu(save_node->hdr.count) * (uint)sizeof(xfs_da_node_entry_t);
 		memmove(btree, &save_node->btree[0], tmp);
 		btree = &save_node->btree[0];
 		xfs_da_log_buf(tp, save_blk->bp,
 			XFS_DA_LOGRANGE(save_node, btree,
-				(INT_GET(save_node->hdr.count, ARCH_CONVERT) + INT_GET(drop_node->hdr.count, ARCH_CONVERT)) *
+				(be16_to_cpu(save_node->hdr.count) + be16_to_cpu(drop_node->hdr.count)) *
 				sizeof(xfs_da_node_entry_t)));
 	} else {
-		btree = &save_node->btree[ INT_GET(save_node->hdr.count, ARCH_CONVERT) ];
+		btree = &save_node->btree[be16_to_cpu(save_node->hdr.count)];
 		xfs_da_log_buf(tp, save_blk->bp,
 			XFS_DA_LOGRANGE(save_node, btree,
-				INT_GET(drop_node->hdr.count, ARCH_CONVERT) *
+				be16_to_cpu(drop_node->hdr.count) *
 				sizeof(xfs_da_node_entry_t)));
 	}
 
 	/*
 	 * Move all the B-tree elements from drop_blk to save_blk.
 	 */
-	tmp = INT_GET(drop_node->hdr.count, ARCH_CONVERT) * (uint)sizeof(xfs_da_node_entry_t);
+	tmp = be16_to_cpu(drop_node->hdr.count) * (uint)sizeof(xfs_da_node_entry_t);
 	memcpy(btree, &drop_node->btree[0], tmp);
-	INT_MOD(save_node->hdr.count, ARCH_CONVERT, INT_GET(drop_node->hdr.count, ARCH_CONVERT));
+	be16_add(&save_node->hdr.count, be16_to_cpu(drop_node->hdr.count));
 
 	xfs_da_log_buf(tp, save_blk->bp,
 		XFS_DA_LOGRANGE(save_node, &save_node->hdr,
@@ -1083,7 +1081,7 @@
 	/*
 	 * Save the last hashval in the remaining block for upward propagation.
 	 */
-	save_blk->hashval = INT_GET(save_node->btree[ INT_GET(save_node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT);
+	save_blk->hashval = be32_to_cpu(save_node->btree[be16_to_cpu(save_node->hdr.count)-1].hashval);
 }
 
 /*========================================================================
@@ -1138,46 +1136,46 @@
 			return(error);
 		}
 		curr = blk->bp->data;
-		ASSERT(INT_GET(curr->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC ||
-		       INT_GET(curr->magic, ARCH_CONVERT) == XFS_DIRX_LEAF_MAGIC(state->mp) ||
-		       INT_GET(curr->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC);
+		ASSERT(be16_to_cpu(curr->magic) == XFS_DA_NODE_MAGIC ||
+		       be16_to_cpu(curr->magic) == XFS_DIRX_LEAF_MAGIC(state->mp) ||
+		       be16_to_cpu(curr->magic) == XFS_ATTR_LEAF_MAGIC);
 
 		/*
 		 * Search an intermediate node for a match.
 		 */
-		blk->magic = INT_GET(curr->magic, ARCH_CONVERT);
-		if (INT_GET(curr->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) {
+		blk->magic = be16_to_cpu(curr->magic);
+		if (blk->magic == XFS_DA_NODE_MAGIC) {
 			node = blk->bp->data;
-			blk->hashval = INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT);
+			blk->hashval = be32_to_cpu(node->btree[be16_to_cpu(node->hdr.count)-1].hashval);
 
 			/*
 			 * Binary search.  (note: small blocks will skip loop)
 			 */
-			max = INT_GET(node->hdr.count, ARCH_CONVERT);
+			max = be16_to_cpu(node->hdr.count);
 			probe = span = max / 2;
 			hashval = args->hashval;
 			for (btree = &node->btree[probe]; span > 4;
 				   btree = &node->btree[probe]) {
 				span /= 2;
-				if (INT_GET(btree->hashval, ARCH_CONVERT) < hashval)
+				if (be32_to_cpu(btree->hashval) < hashval)
 					probe += span;
-				else if (INT_GET(btree->hashval, ARCH_CONVERT) > hashval)
+				else if (be32_to_cpu(btree->hashval) > hashval)
 					probe -= span;
 				else
 					break;
 			}
 			ASSERT((probe >= 0) && (probe < max));
-			ASSERT((span <= 4) || (INT_GET(btree->hashval, ARCH_CONVERT) == hashval));
+			ASSERT((span <= 4) || (be32_to_cpu(btree->hashval) == hashval));
 
 			/*
 			 * Since we may have duplicate hashval's, find the first
 			 * matching hashval in the node.
 			 */
-			while ((probe > 0) && (INT_GET(btree->hashval, ARCH_CONVERT) >= hashval)) {
+			while ((probe > 0) && (be32_to_cpu(btree->hashval) >= hashval)) {
 				btree--;
 				probe--;
 			}
-			while ((probe < max) && (INT_GET(btree->hashval, ARCH_CONVERT) < hashval)) {
+			while ((probe < max) && (be32_to_cpu(btree->hashval) < hashval)) {
 				btree++;
 				probe++;
 			}
@@ -1187,21 +1185,21 @@
 			 */
 			if (probe == max) {
 				blk->index = max-1;
-				blkno = INT_GET(node->btree[ max-1 ].before, ARCH_CONVERT);
+				blkno = be32_to_cpu(node->btree[max-1].before);
 			} else {
 				blk->index = probe;
-				blkno = INT_GET(btree->before, ARCH_CONVERT);
+				blkno = be32_to_cpu(btree->before);
 			}
 		}
-		else if (INT_GET(curr->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC) {
+		else if (be16_to_cpu(curr->magic) == XFS_ATTR_LEAF_MAGIC) {
 			blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL);
 			break;
 		}
-		else if (INT_GET(curr->magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC) {
+		else if (be16_to_cpu(curr->magic) == XFS_DIR_LEAF_MAGIC) {
 			blk->hashval = xfs_dir_leaf_lasthash(blk->bp, NULL);
 			break;
 		}
-		else if (INT_GET(curr->magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC) {
+		else if (be16_to_cpu(curr->magic) == XFS_DIR2_LEAFN_MAGIC) {
 			blk->hashval = xfs_dir2_leafn_lasthash(blk->bp, NULL);
 			break;
 		}
@@ -1274,8 +1272,8 @@
 	ASSERT(old_blk->magic == XFS_DA_NODE_MAGIC ||
 	       old_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp) ||
 	       old_blk->magic == XFS_ATTR_LEAF_MAGIC);
-	ASSERT(old_blk->magic == INT_GET(old_info->magic, ARCH_CONVERT));
-	ASSERT(new_blk->magic == INT_GET(new_info->magic, ARCH_CONVERT));
+	ASSERT(old_blk->magic == be16_to_cpu(old_info->magic));
+	ASSERT(new_blk->magic == be16_to_cpu(new_info->magic));
 	ASSERT(old_blk->magic == new_blk->magic);
 
 	switch (old_blk->magic) {
@@ -1302,47 +1300,44 @@
 		/*
 		 * Link new block in before existing block.
 		 */
-		INT_SET(new_info->forw, ARCH_CONVERT, old_blk->blkno);
-		new_info->back = old_info->back; /* INT_: direct copy */
-		if (INT_GET(old_info->back, ARCH_CONVERT)) {
+		new_info->forw = cpu_to_be32(old_blk->blkno);
+		new_info->back = old_info->back;
+		if (old_info->back) {
 			error = xfs_da_read_buf(args->trans, args->dp,
-						INT_GET(old_info->back,
-							ARCH_CONVERT), -1, &bp,
-						args->whichfork);
+						be32_to_cpu(old_info->back),
+						-1, &bp, args->whichfork);
 			if (error)
 				return(error);
 			ASSERT(bp != NULL);
 			tmp_info = bp->data;
-			ASSERT(INT_GET(tmp_info->magic, ARCH_CONVERT) == INT_GET(old_info->magic, ARCH_CONVERT));
-			ASSERT(INT_GET(tmp_info->forw, ARCH_CONVERT) == old_blk->blkno);
-			INT_SET(tmp_info->forw, ARCH_CONVERT, new_blk->blkno);
+			ASSERT(be16_to_cpu(tmp_info->magic) == be16_to_cpu(old_info->magic));
+			ASSERT(be32_to_cpu(tmp_info->forw) == old_blk->blkno);
+			tmp_info->forw = cpu_to_be32(new_blk->blkno);
 			xfs_da_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1);
 			xfs_da_buf_done(bp);
 		}
-		INT_SET(old_info->back, ARCH_CONVERT, new_blk->blkno);
+		old_info->back = cpu_to_be32(new_blk->blkno);
 	} else {
 		/*
 		 * Link new block in after existing block.
 		 */
-		new_info->forw = old_info->forw; /* INT_: direct copy */
-		INT_SET(new_info->back, ARCH_CONVERT, old_blk->blkno);
-		if (INT_GET(old_info->forw, ARCH_CONVERT)) {
+		new_info->forw = old_info->forw;
+		new_info->back = cpu_to_be32(old_blk->blkno);
+		if (old_info->forw) {
 			error = xfs_da_read_buf(args->trans, args->dp,
-						INT_GET(old_info->forw, ARCH_CONVERT), -1, &bp,
-						args->whichfork);
+						be32_to_cpu(old_info->forw),
+						-1, &bp, args->whichfork);
 			if (error)
 				return(error);
 			ASSERT(bp != NULL);
 			tmp_info = bp->data;
-			ASSERT(INT_GET(tmp_info->magic, ARCH_CONVERT)
-				    == INT_GET(old_info->magic, ARCH_CONVERT));
-			ASSERT(INT_GET(tmp_info->back, ARCH_CONVERT)
-				    == old_blk->blkno);
-			INT_SET(tmp_info->back, ARCH_CONVERT, new_blk->blkno);
+			ASSERT(tmp_info->magic == old_info->magic);
+			ASSERT(be32_to_cpu(tmp_info->back) == old_blk->blkno);
+			tmp_info->back = cpu_to_be32(new_blk->blkno);
 			xfs_da_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1);
 			xfs_da_buf_done(bp);
 		}
-		INT_SET(old_info->forw, ARCH_CONVERT, new_blk->blkno);
+		old_info->forw = cpu_to_be32(new_blk->blkno);
 	}
 
 	xfs_da_log_buf(args->trans, old_blk->bp, 0, sizeof(*tmp_info) - 1);
@@ -1360,13 +1355,13 @@
 
 	node1 = node1_bp->data;
 	node2 = node2_bp->data;
-	ASSERT((INT_GET(node1->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) &&
-	       (INT_GET(node2->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC));
-	if ((INT_GET(node1->hdr.count, ARCH_CONVERT) > 0) && (INT_GET(node2->hdr.count, ARCH_CONVERT) > 0) &&
-	    ((INT_GET(node2->btree[ 0 ].hashval, ARCH_CONVERT) <
-	      INT_GET(node1->btree[ 0 ].hashval, ARCH_CONVERT)) ||
-	     (INT_GET(node2->btree[ INT_GET(node2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT) <
-	      INT_GET(node1->btree[ INT_GET(node1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)))) {
+	ASSERT((be16_to_cpu(node1->hdr.info.magic) == XFS_DA_NODE_MAGIC) &&
+	       (be16_to_cpu(node2->hdr.info.magic) == XFS_DA_NODE_MAGIC));
+	if ((be16_to_cpu(node1->hdr.count) > 0) && (be16_to_cpu(node2->hdr.count) > 0) &&
+	    ((be32_to_cpu(node2->btree[0].hashval) <
+	      be32_to_cpu(node1->btree[0].hashval)) ||
+	     (be32_to_cpu(node2->btree[be16_to_cpu(node2->hdr.count)-1].hashval) <
+	      be32_to_cpu(node1->btree[be16_to_cpu(node1->hdr.count)-1].hashval)))) {
 		return(1);
 	}
 	return(0);
@@ -1381,12 +1376,12 @@
 	xfs_da_intnode_t *node;
 
 	node = bp->data;
-	ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC);
+	ASSERT(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
 	if (count)
-		*count = INT_GET(node->hdr.count, ARCH_CONVERT);
+		*count = be16_to_cpu(node->hdr.count);
 	if (!node->hdr.count)
 		return(0);
-	return(INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT));
+	return be32_to_cpu(node->btree[be16_to_cpu(node->hdr.count)-1].hashval);
 }
 
 /*
@@ -1411,50 +1406,47 @@
 	ASSERT(save_blk->magic == XFS_DA_NODE_MAGIC ||
 	       save_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp) ||
 	       save_blk->magic == XFS_ATTR_LEAF_MAGIC);
-	ASSERT(save_blk->magic == INT_GET(save_info->magic, ARCH_CONVERT));
-	ASSERT(drop_blk->magic == INT_GET(drop_info->magic, ARCH_CONVERT));
+	ASSERT(save_blk->magic == be16_to_cpu(save_info->magic));
+	ASSERT(drop_blk->magic == be16_to_cpu(drop_info->magic));
 	ASSERT(save_blk->magic == drop_blk->magic);
-	ASSERT((INT_GET(save_info->forw, ARCH_CONVERT) == drop_blk->blkno) ||
-	       (INT_GET(save_info->back, ARCH_CONVERT) == drop_blk->blkno));
-	ASSERT((INT_GET(drop_info->forw, ARCH_CONVERT) == save_blk->blkno) ||
-	       (INT_GET(drop_info->back, ARCH_CONVERT) == save_blk->blkno));
+	ASSERT((be32_to_cpu(save_info->forw) == drop_blk->blkno) ||
+	       (be32_to_cpu(save_info->back) == drop_blk->blkno));
+	ASSERT((be32_to_cpu(drop_info->forw) == save_blk->blkno) ||
+	       (be32_to_cpu(drop_info->back) == save_blk->blkno));
 
 	/*
 	 * Unlink the leaf block from the doubly linked chain of leaves.
 	 */
-	if (INT_GET(save_info->back, ARCH_CONVERT) == drop_blk->blkno) {
-		save_info->back = drop_info->back; /* INT_: direct copy */
-		if (INT_GET(drop_info->back, ARCH_CONVERT)) {
+	if (be32_to_cpu(save_info->back) == drop_blk->blkno) {
+		save_info->back = drop_info->back;
+		if (drop_info->back) {
 			error = xfs_da_read_buf(args->trans, args->dp,
-						INT_GET(drop_info->back,
-							ARCH_CONVERT), -1, &bp,
-						args->whichfork);
+						be32_to_cpu(drop_info->back),
+						-1, &bp, args->whichfork);
 			if (error)
 				return(error);
 			ASSERT(bp != NULL);
 			tmp_info = bp->data;
-			ASSERT(INT_GET(tmp_info->magic, ARCH_CONVERT) == INT_GET(save_info->magic, ARCH_CONVERT));
-			ASSERT(INT_GET(tmp_info->forw, ARCH_CONVERT) == drop_blk->blkno);
-			INT_SET(tmp_info->forw, ARCH_CONVERT, save_blk->blkno);
+			ASSERT(tmp_info->magic == save_info->magic);
+			ASSERT(be32_to_cpu(tmp_info->forw) == drop_blk->blkno);
+			tmp_info->forw = cpu_to_be32(save_blk->blkno);
 			xfs_da_log_buf(args->trans, bp, 0,
 						    sizeof(*tmp_info) - 1);
 			xfs_da_buf_done(bp);
 		}
 	} else {
-		save_info->forw = drop_info->forw; /* INT_: direct copy */
-		if (INT_GET(drop_info->forw, ARCH_CONVERT)) {
+		save_info->forw = drop_info->forw;
+		if (drop_info->forw) {
 			error = xfs_da_read_buf(args->trans, args->dp,
-						INT_GET(drop_info->forw, ARCH_CONVERT), -1, &bp,
-						args->whichfork);
+						be32_to_cpu(drop_info->forw),
+						-1, &bp, args->whichfork);
 			if (error)
 				return(error);
 			ASSERT(bp != NULL);
 			tmp_info = bp->data;
-			ASSERT(INT_GET(tmp_info->magic, ARCH_CONVERT)
-				    == INT_GET(save_info->magic, ARCH_CONVERT));
-			ASSERT(INT_GET(tmp_info->back, ARCH_CONVERT)
-				    == drop_blk->blkno);
-			INT_SET(tmp_info->back, ARCH_CONVERT, save_blk->blkno);
+			ASSERT(tmp_info->magic == save_info->magic);
+			ASSERT(be32_to_cpu(tmp_info->back) == drop_blk->blkno);
+			tmp_info->back = cpu_to_be32(save_blk->blkno);
 			xfs_da_log_buf(args->trans, bp, 0,
 						    sizeof(*tmp_info) - 1);
 			xfs_da_buf_done(bp);
@@ -1497,14 +1489,14 @@
 	for (blk = &path->blk[level]; level >= 0; blk--, level--) {
 		ASSERT(blk->bp != NULL);
 		node = blk->bp->data;
-		ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC);
-		if (forward && (blk->index < INT_GET(node->hdr.count, ARCH_CONVERT)-1)) {
+		ASSERT(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
+		if (forward && (blk->index < be16_to_cpu(node->hdr.count)-1)) {
 			blk->index++;
-			blkno = INT_GET(node->btree[ blk->index ].before, ARCH_CONVERT);
+			blkno = be32_to_cpu(node->btree[blk->index].before);
 			break;
 		} else if (!forward && (blk->index > 0)) {
 			blk->index--;
-			blkno = INT_GET(node->btree[ blk->index ].before, ARCH_CONVERT);
+			blkno = be32_to_cpu(node->btree[blk->index].before);
 			break;
 		}
 	}
@@ -1536,18 +1528,18 @@
 			return(error);
 		ASSERT(blk->bp != NULL);
 		info = blk->bp->data;
-		ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC ||
-		       INT_GET(info->magic, ARCH_CONVERT) == XFS_DIRX_LEAF_MAGIC(state->mp) ||
-		       INT_GET(info->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC);
-		blk->magic = INT_GET(info->magic, ARCH_CONVERT);
-		if (INT_GET(info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) {
+		ASSERT(be16_to_cpu(info->magic) == XFS_DA_NODE_MAGIC ||
+		       be16_to_cpu(info->magic) == XFS_DIRX_LEAF_MAGIC(state->mp) ||
+		       be16_to_cpu(info->magic) == XFS_ATTR_LEAF_MAGIC);
+		blk->magic = be16_to_cpu(info->magic);
+		if (blk->magic == XFS_DA_NODE_MAGIC) {
 			node = (xfs_da_intnode_t *)info;
-			blk->hashval = INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT);
+			blk->hashval = be32_to_cpu(node->btree[be16_to_cpu(node->hdr.count)-1].hashval);
 			if (forward)
 				blk->index = 0;
 			else
-				blk->index = INT_GET(node->hdr.count, ARCH_CONVERT)-1;
-			blkno = INT_GET(node->btree[ blk->index ].before, ARCH_CONVERT);
+				blk->index = be16_to_cpu(node->hdr.count)-1;
+			blkno = be32_to_cpu(node->btree[blk->index].before);
 		} else {
 			ASSERT(level == path->active-1);
 			blk->index = 0;
@@ -1788,40 +1780,40 @@
 	/*
 	 * Get values from the moved block.
 	 */
-	if (INT_GET(dead_info->magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC) {
+	if (be16_to_cpu(dead_info->magic) == XFS_DIR_LEAF_MAGIC) {
 		ASSERT(XFS_DIR_IS_V1(mp));
 		dead_leaf = (xfs_dir_leafblock_t *)dead_info;
 		dead_level = 0;
-		dead_hash =
-			INT_GET(dead_leaf->entries[INT_GET(dead_leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT);
-	} else if (INT_GET(dead_info->magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC) {
+		dead_hash = be32_to_cpu(dead_leaf->entries[
+				be16_to_cpu(dead_leaf->hdr.count) - 1].hashval);
+	} else if (be16_to_cpu(dead_info->magic) == XFS_DIR2_LEAFN_MAGIC) {
 		ASSERT(XFS_DIR_IS_V2(mp));
 		dead_leaf2 = (xfs_dir2_leaf_t *)dead_info;
 		dead_level = 0;
-		dead_hash = INT_GET(dead_leaf2->ents[INT_GET(dead_leaf2->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT);
+		dead_hash = be32_to_cpu(dead_leaf2->ents[be16_to_cpu(dead_leaf2->hdr.count) - 1].hashval);
 	} else {
-		ASSERT(INT_GET(dead_info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC);
+		ASSERT(be16_to_cpu(dead_info->magic) == XFS_DA_NODE_MAGIC);
 		dead_node = (xfs_da_intnode_t *)dead_info;
-		dead_level = INT_GET(dead_node->hdr.level, ARCH_CONVERT);
-		dead_hash = INT_GET(dead_node->btree[INT_GET(dead_node->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT);
+		dead_level = be16_to_cpu(dead_node->hdr.level);
+		dead_hash = be32_to_cpu(dead_node->btree[be16_to_cpu(dead_node->hdr.count) - 1].hashval);
 	}
 	sib_buf = par_buf = NULL;
 	/*
 	 * If the moved block has a left sibling, fix up the pointers.
 	 */
-	if ((sib_blkno = INT_GET(dead_info->back, ARCH_CONVERT))) {
+	if ((sib_blkno = be32_to_cpu(dead_info->back))) {
 		if ((error = xfs_da_read_buf(tp, ip, sib_blkno, -1, &sib_buf, w)))
 			goto done;
 		sib_info = sib_buf->data;
 		if (unlikely(
-		    INT_GET(sib_info->forw, ARCH_CONVERT) != last_blkno ||
-		    INT_GET(sib_info->magic, ARCH_CONVERT) != INT_GET(dead_info->magic, ARCH_CONVERT))) {
+		    be32_to_cpu(sib_info->forw) != last_blkno ||
+		    sib_info->magic != dead_info->magic)) {
 			XFS_ERROR_REPORT("xfs_da_swap_lastblock(2)",
 					 XFS_ERRLEVEL_LOW, mp);
 			error = XFS_ERROR(EFSCORRUPTED);
 			goto done;
 		}
-		INT_SET(sib_info->forw, ARCH_CONVERT, dead_blkno);
+		sib_info->forw = cpu_to_be32(dead_blkno);
 		xfs_da_log_buf(tp, sib_buf,
 			XFS_DA_LOGRANGE(sib_info, &sib_info->forw,
 					sizeof(sib_info->forw)));
@@ -1831,20 +1823,19 @@
 	/*
 	 * If the moved block has a right sibling, fix up the pointers.
 	 */
-	if ((sib_blkno = INT_GET(dead_info->forw, ARCH_CONVERT))) {
+	if ((sib_blkno = be32_to_cpu(dead_info->forw))) {
 		if ((error = xfs_da_read_buf(tp, ip, sib_blkno, -1, &sib_buf, w)))
 			goto done;
 		sib_info = sib_buf->data;
 		if (unlikely(
-		       INT_GET(sib_info->back, ARCH_CONVERT) != last_blkno
-		    || INT_GET(sib_info->magic, ARCH_CONVERT)
-				!= INT_GET(dead_info->magic, ARCH_CONVERT))) {
+		       be32_to_cpu(sib_info->back) != last_blkno ||
+		       sib_info->magic != dead_info->magic)) {
 			XFS_ERROR_REPORT("xfs_da_swap_lastblock(3)",
 					 XFS_ERRLEVEL_LOW, mp);
 			error = XFS_ERROR(EFSCORRUPTED);
 			goto done;
 		}
-		INT_SET(sib_info->back, ARCH_CONVERT, dead_blkno);
+		sib_info->back = cpu_to_be32(dead_blkno);
 		xfs_da_log_buf(tp, sib_buf,
 			XFS_DA_LOGRANGE(sib_info, &sib_info->back,
 					sizeof(sib_info->back)));
@@ -1861,26 +1852,26 @@
 			goto done;
 		par_node = par_buf->data;
 		if (unlikely(
-		    INT_GET(par_node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC ||
-		    (level >= 0 && level != INT_GET(par_node->hdr.level, ARCH_CONVERT) + 1))) {
+		    be16_to_cpu(par_node->hdr.info.magic) != XFS_DA_NODE_MAGIC ||
+		    (level >= 0 && level != be16_to_cpu(par_node->hdr.level) + 1))) {
 			XFS_ERROR_REPORT("xfs_da_swap_lastblock(4)",
 					 XFS_ERRLEVEL_LOW, mp);
 			error = XFS_ERROR(EFSCORRUPTED);
 			goto done;
 		}
-		level = INT_GET(par_node->hdr.level, ARCH_CONVERT);
+		level = be16_to_cpu(par_node->hdr.level);
 		for (entno = 0;
-		     entno < INT_GET(par_node->hdr.count, ARCH_CONVERT) &&
-		     INT_GET(par_node->btree[entno].hashval, ARCH_CONVERT) < dead_hash;
+		     entno < be16_to_cpu(par_node->hdr.count) &&
+		     be32_to_cpu(par_node->btree[entno].hashval) < dead_hash;
 		     entno++)
 			continue;
-		if (unlikely(entno == INT_GET(par_node->hdr.count, ARCH_CONVERT))) {
+		if (unlikely(entno == be16_to_cpu(par_node->hdr.count))) {
 			XFS_ERROR_REPORT("xfs_da_swap_lastblock(5)",
 					 XFS_ERRLEVEL_LOW, mp);
 			error = XFS_ERROR(EFSCORRUPTED);
 			goto done;
 		}
-		par_blkno = INT_GET(par_node->btree[entno].before, ARCH_CONVERT);
+		par_blkno = be32_to_cpu(par_node->btree[entno].before);
 		if (level == dead_level + 1)
 			break;
 		xfs_da_brelse(tp, par_buf);
@@ -1892,13 +1883,13 @@
 	 */
 	for (;;) {
 		for (;
-		     entno < INT_GET(par_node->hdr.count, ARCH_CONVERT) &&
-		     INT_GET(par_node->btree[entno].before, ARCH_CONVERT) != last_blkno;
+		     entno < be16_to_cpu(par_node->hdr.count) &&
+		     be32_to_cpu(par_node->btree[entno].before) != last_blkno;
 		     entno++)
 			continue;
-		if (entno < INT_GET(par_node->hdr.count, ARCH_CONVERT))
+		if (entno < be16_to_cpu(par_node->hdr.count))
 			break;
-		par_blkno = INT_GET(par_node->hdr.info.forw, ARCH_CONVERT);
+		par_blkno = be32_to_cpu(par_node->hdr.info.forw);
 		xfs_da_brelse(tp, par_buf);
 		par_buf = NULL;
 		if (unlikely(par_blkno == 0)) {
@@ -1911,8 +1902,8 @@
 			goto done;
 		par_node = par_buf->data;
 		if (unlikely(
-		    INT_GET(par_node->hdr.level, ARCH_CONVERT) != level ||
-		    INT_GET(par_node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC)) {
+		    be16_to_cpu(par_node->hdr.level) != level ||
+		    be16_to_cpu(par_node->hdr.info.magic) != XFS_DA_NODE_MAGIC)) {
 			XFS_ERROR_REPORT("xfs_da_swap_lastblock(7)",
 					 XFS_ERRLEVEL_LOW, mp);
 			error = XFS_ERROR(EFSCORRUPTED);
@@ -1923,7 +1914,7 @@
 	/*
 	 * Update the parent entry pointing to the moved block.
 	 */
-	INT_SET(par_node->btree[entno].before, ARCH_CONVERT, dead_blkno);
+	par_node->btree[entno].before = cpu_to_be32(dead_blkno);
 	xfs_da_log_buf(tp, par_buf,
 		XFS_DA_LOGRANGE(par_node, &par_node->btree[entno].before,
 				sizeof(par_node->btree[entno].before)));
@@ -2203,8 +2194,8 @@
 		info = rbp->data;
 		data = rbp->data;
 		free = rbp->data;
-		magic = INT_GET(info->magic, ARCH_CONVERT);
-		magic1 = INT_GET(data->hdr.magic, ARCH_CONVERT);
+		magic = be16_to_cpu(info->magic);
+		magic1 = be32_to_cpu(data->hdr.magic);
 		if (unlikely(
 		    XFS_TEST_ERROR((magic != XFS_DA_NODE_MAGIC) &&
 				   (magic != XFS_DIR_LEAF_MAGIC) &&
@@ -2213,7 +2204,7 @@
 				   (magic != XFS_DIR2_LEAFN_MAGIC) &&
 				   (magic1 != XFS_DIR2_BLOCK_MAGIC) &&
 				   (magic1 != XFS_DIR2_DATA_MAGIC) &&
-				   (INT_GET(free->hdr.magic, ARCH_CONVERT) != XFS_DIR2_FREE_MAGIC),
+				   (be32_to_cpu(free->hdr.magic) != XFS_DIR2_FREE_MAGIC),
 				mp, XFS_ERRTAG_DA_READ_BUF,
 				XFS_RANDOM_DA_READ_BUF))) {
 			xfs_buftrace("DA READ ERROR", rbp->bps[0]);
diff -urN oldtree/fs/xfs/xfs_da_btree.h newtree/fs/xfs/xfs_da_btree.h
--- oldtree/fs/xfs/xfs_da_btree.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/xfs/xfs_da_btree.h	2006-02-21 15:58:36.722563880 +0000
@@ -45,10 +45,10 @@
 	(XFS_DIR_IS_V1(mp) ? XFS_DIR_LEAF_MAGIC : XFS_DIR2_LEAFN_MAGIC)
 
 typedef struct xfs_da_blkinfo {
-	xfs_dablk_t forw;			/* previous block in list */
-	xfs_dablk_t back;			/* following block in list */
-	__uint16_t magic;			/* validity check on block */
-	__uint16_t pad;				/* unused */
+	__be32		forw;			/* previous block in list */
+	__be32		back;			/* following block in list */
+	__be16		magic;			/* validity check on block */
+	__be16		pad;			/* unused */
 } xfs_da_blkinfo_t;
 
 /*
@@ -65,12 +65,12 @@
 typedef struct xfs_da_intnode {
 	struct xfs_da_node_hdr {	/* constant-structure header block */
 		xfs_da_blkinfo_t info;	/* block type, links, etc. */
-		__uint16_t count;	/* count of active entries */
-		__uint16_t level;	/* level above leaves (leaf == 0) */
+		__be16	count;		/* count of active entries */
+		__be16	level;		/* level above leaves (leaf == 0) */
 	} hdr;
 	struct xfs_da_node_entry {
-		xfs_dahash_t hashval;	/* hash value for this descendant */
-		xfs_dablk_t before;	/* Btree block before this key */
+		__be32	hashval;	/* hash value for this descendant */
+		__be32	before;		/* Btree block before this key */
 	} btree[1];			/* variable sized array of keys */
 } xfs_da_intnode_t;
 typedef struct xfs_da_node_hdr xfs_da_node_hdr_t;
diff -urN oldtree/fs/xfs/xfs_dir.c newtree/fs/xfs/xfs_dir.c
--- oldtree/fs/xfs/xfs_dir.c	2006-02-19 11:41:05.397522552 +0000
+++ newtree/fs/xfs/xfs_dir.c	2006-02-21 15:58:36.736561752 +0000
@@ -634,12 +634,12 @@
 		return(retval);
 	ASSERT(bp != NULL);
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
 	retval = xfs_dir_leaf_lookup_int(bp, args, &index);
 	if (retval == EEXIST) {
 		(void)xfs_dir_leaf_remove(args->trans, bp, index);
-		*count = INT_GET(leaf->hdr.count, ARCH_CONVERT);
-		*totallen = INT_GET(leaf->hdr.namebytes, ARCH_CONVERT);
+		*count = be16_to_cpu(leaf->hdr.count);
+		*totallen = be16_to_cpu(leaf->hdr.namebytes);
 		retval = 0;
 	}
 	xfs_da_buf_done(bp);
@@ -710,7 +710,7 @@
 	if (retval == EEXIST) {
 		leaf = bp->data;
 		entry = &leaf->entries[index];
-		namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
+		namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, be16_to_cpu(entry->nameidx));
 		/* XXX - replace assert? */
 		XFS_DIR_SF_PUT_DIRINO(&inum, &namest->inumber);
 		xfs_da_log_buf(args->trans, bp,
@@ -912,20 +912,20 @@
 			return(error);
 		if (bp)
 			leaf = bp->data;
-		if (bp && INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) {
+		if (bp && be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR_LEAF_MAGIC) {
 			xfs_dir_trace_g_dub("node: block not a leaf",
 						   dp, uio, bno);
 			xfs_da_brelse(trans, bp);
 			bp = NULL;
 		}
-		if (bp && INT_GET(leaf->entries[0].hashval, ARCH_CONVERT) > cookhash) {
+		if (bp && be32_to_cpu(leaf->entries[0].hashval) > cookhash) {
 			xfs_dir_trace_g_dub("node: leaf hash too large",
 						   dp, uio, bno);
 			xfs_da_brelse(trans, bp);
 			bp = NULL;
 		}
-		if (bp &&
-		    cookhash > INT_GET(leaf->entries[INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT)) {
+		if (bp && cookhash > be32_to_cpu(leaf->entries[
+					be16_to_cpu(leaf->hdr.count) - 1].hashval)) {
 			xfs_dir_trace_g_dub("node: leaf hash too small",
 						   dp, uio, bno);
 			xfs_da_brelse(trans, bp);
@@ -949,17 +949,17 @@
 			if (bp == NULL)
 				return(XFS_ERROR(EFSCORRUPTED));
 			node = bp->data;
-			if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC)
+			if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC)
 				break;
 			btree = &node->btree[0];
 			xfs_dir_trace_g_dun("node: node detail", dp, uio, node);
-			for (i = 0; i < INT_GET(node->hdr.count, ARCH_CONVERT); btree++, i++) {
-				if (INT_GET(btree->hashval, ARCH_CONVERT) >= cookhash) {
-					bno = INT_GET(btree->before, ARCH_CONVERT);
+			for (i = 0; i < be16_to_cpu(node->hdr.count); btree++, i++) {
+				if (be32_to_cpu(btree->hashval) >= cookhash) {
+					bno = be32_to_cpu(btree->before);
 					break;
 				}
 			}
-			if (i == INT_GET(node->hdr.count, ARCH_CONVERT)) {
+			if (i == be16_to_cpu(node->hdr.count)) {
 				xfs_da_brelse(trans, bp);
 				xfs_dir_trace_g_du("node: hash beyond EOF",
 							  dp, uio);
@@ -982,7 +982,7 @@
 	 */
 	for (;;) {
 		leaf = bp->data;
-		if (unlikely(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC)) {
+		if (unlikely(be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR_LEAF_MAGIC)) {
 			xfs_dir_trace_g_dul("node: not a leaf", dp, uio, leaf);
 			xfs_da_brelse(trans, bp);
 			XFS_CORRUPTION_ERROR("xfs_dir_node_getdents(1)",
@@ -990,7 +990,7 @@
 			return XFS_ERROR(EFSCORRUPTED);
 		}
 		xfs_dir_trace_g_dul("node: leaf detail", dp, uio, leaf);
-		if ((nextbno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT))) {
+		if ((nextbno = be32_to_cpu(leaf->hdr.info.forw))) {
 			nextda = xfs_da_reada_buf(trans, dp, nextbno,
 						  XFS_DATA_FORK);
 		} else
@@ -1059,7 +1059,7 @@
 		bp = blk->bp;
 		leaf = bp->data;
 		entry = &leaf->entries[blk->index];
-		namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
+		namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, be16_to_cpu(entry->nameidx));
 		/* XXX - replace assert ? */
 		XFS_DIR_SF_PUT_DIRINO(&inum, &namest->inumber);
 		xfs_da_log_buf(args->trans, bp,
@@ -1118,21 +1118,20 @@
 xfs_dir_trace_g_dun(char *where, xfs_inode_t *dp, uio_t *uio,
 			xfs_da_intnode_t *node)
 {
-	int	last = INT_GET(node->hdr.count, ARCH_CONVERT) - 1;
+	int	last = be16_to_cpu(node->hdr.count) - 1;
 
 	xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUN, where,
 		     (void *)dp, (void *)dp->i_mount,
 		     (void *)((unsigned long)(uio->uio_offset >> 32)),
 		     (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)),
 		     (void *)(unsigned long)uio->uio_resid,
+		     (void *)(unsigned long)be32_to_cpu(node->hdr.info.forw),
 		     (void *)(unsigned long)
-			INT_GET(node->hdr.info.forw, ARCH_CONVERT),
+			be16_to_cpu(node->hdr.count),
 		     (void *)(unsigned long)
-			INT_GET(node->hdr.count, ARCH_CONVERT),
+			be32_to_cpu(node->btree[0].hashval),
 		     (void *)(unsigned long)
-			INT_GET(node->btree[0].hashval, ARCH_CONVERT),
-		     (void *)(unsigned long)
-			INT_GET(node->btree[last].hashval, ARCH_CONVERT),
+			be32_to_cpu(node->btree[last].hashval),
 		     NULL, NULL, NULL);
 }
 
@@ -1143,21 +1142,17 @@
 xfs_dir_trace_g_dul(char *where, xfs_inode_t *dp, uio_t *uio,
 			xfs_dir_leafblock_t *leaf)
 {
-	int	last = INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1;
+	int	last = be16_to_cpu(leaf->hdr.count) - 1;
 
 	xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUL, where,
 		     (void *)dp, (void *)dp->i_mount,
 		     (void *)((unsigned long)(uio->uio_offset >> 32)),
 		     (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)),
 		     (void *)(unsigned long)uio->uio_resid,
-		     (void *)(unsigned long)
-			INT_GET(leaf->hdr.info.forw, ARCH_CONVERT),
-		     (void *)(unsigned long)
-			INT_GET(leaf->hdr.count, ARCH_CONVERT),
-		     (void *)(unsigned long)
-			INT_GET(leaf->entries[0].hashval, ARCH_CONVERT),
-		     (void *)(unsigned long)
-			INT_GET(leaf->entries[last].hashval, ARCH_CONVERT),
+		     (void *)(unsigned long)be32_to_cpu(leaf->hdr.info.forw),
+		     (void *)(unsigned long)be16_to_cpu(leaf->hdr.count),
+		     (void *)(unsigned long)be32_to_cpu(leaf->entries[0].hashval),
+		     (void *)(unsigned long)be32_to_cpu(leaf->entries[last].hashval),
 		     NULL, NULL, NULL);
 }
 
@@ -1173,8 +1168,7 @@
 		     (void *)((unsigned long)(uio->uio_offset >> 32)),
 		     (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)),
 		     (void *)(unsigned long)uio->uio_resid,
-		     (void *)(unsigned long)
-			INT_GET(entry->hashval, ARCH_CONVERT),
+		     (void *)(unsigned long)be32_to_cpu(entry->hashval),
 		     NULL, NULL, NULL, NULL, NULL, NULL);
 }
 
diff -urN oldtree/fs/xfs/xfs_dir2_block.c newtree/fs/xfs/xfs_dir2_block.c
--- oldtree/fs/xfs/xfs_dir2_block.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/xfs/xfs_dir2_block.c	2006-02-21 15:58:36.724563576 +0000
@@ -81,7 +81,7 @@
 	xfs_mount_t		*mp;		/* filesystem mount point */
 	int			needlog;	/* need to log header */
 	int			needscan;	/* need to rescan freespace */
-	xfs_dir2_data_off_t	*tagp;		/* pointer to tag value */
+	__be16			*tagp;		/* pointer to tag value */
 	xfs_trans_t		*tp;		/* transaction structure */
 
 	xfs_dir2_trace_args("block_addname", args);
@@ -100,8 +100,7 @@
 	/*
 	 * Check the magic number, corrupted if wrong.
 	 */
-	if (unlikely(INT_GET(block->hdr.magic, ARCH_CONVERT)
-						!= XFS_DIR2_BLOCK_MAGIC)) {
+	if (unlikely(be32_to_cpu(block->hdr.magic) != XFS_DIR2_BLOCK_MAGIC)) {
 		XFS_CORRUPTION_ERROR("xfs_dir2_block_addname",
 				     XFS_ERRLEVEL_LOW, mp, block);
 		xfs_da_brelse(tp, bp);
@@ -121,38 +120,38 @@
 		/*
 		 * Tag just before the first leaf entry.
 		 */
-		tagp = (xfs_dir2_data_off_t *)blp - 1;
+		tagp = (__be16 *)blp - 1;
 		/*
 		 * Data object just before the first leaf entry.
 		 */
-		enddup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT));
+		enddup = (xfs_dir2_data_unused_t *)((char *)block + be16_to_cpu(*tagp));
 		/*
 		 * If it's not free then can't do this add without cleaning up:
 		 * the space before the first leaf entry needs to be free so it
 		 * can be expanded to hold the pointer to the new entry.
 		 */
-		if (INT_GET(enddup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG)
+		if (be16_to_cpu(enddup->freetag) != XFS_DIR2_DATA_FREE_TAG)
 			dup = enddup = NULL;
 		/*
 		 * Check out the biggest freespace and see if it's the same one.
 		 */
 		else {
 			dup = (xfs_dir2_data_unused_t *)
-			      ((char *)block + INT_GET(bf[0].offset, ARCH_CONVERT));
+			      ((char *)block + be16_to_cpu(bf[0].offset));
 			if (dup == enddup) {
 				/*
 				 * It is the biggest freespace, is it too small
 				 * to hold the new leaf too?
 				 */
-				if (INT_GET(dup->length, ARCH_CONVERT) < len + (uint)sizeof(*blp)) {
+				if (be16_to_cpu(dup->length) < len + (uint)sizeof(*blp)) {
 					/*
 					 * Yes, we use the second-largest
 					 * entry instead if it works.
 					 */
-					if (INT_GET(bf[1].length, ARCH_CONVERT) >= len)
+					if (be16_to_cpu(bf[1].length) >= len)
 						dup = (xfs_dir2_data_unused_t *)
 						      ((char *)block +
-						       INT_GET(bf[1].offset, ARCH_CONVERT));
+						       be16_to_cpu(bf[1].offset));
 					else
 						dup = NULL;
 				}
@@ -161,7 +160,7 @@
 				 * Not the same free entry,
 				 * just check its length.
 				 */
-				if (INT_GET(dup->length, ARCH_CONVERT) < len) {
+				if (be16_to_cpu(dup->length) < len) {
 					dup = NULL;
 				}
 			}
@@ -172,9 +171,9 @@
 	 * If there are stale entries we'll use one for the leaf.
 	 * Is the biggest entry enough to avoid compaction?
 	 */
-	else if (INT_GET(bf[0].length, ARCH_CONVERT) >= len) {
+	else if (be16_to_cpu(bf[0].length) >= len) {
 		dup = (xfs_dir2_data_unused_t *)
-		      ((char *)block + INT_GET(bf[0].offset, ARCH_CONVERT));
+		      ((char *)block + be16_to_cpu(bf[0].offset));
 		compact = 0;
 	}
 	/*
@@ -184,20 +183,20 @@
 		/*
 		 * Tag just before the first leaf entry.
 		 */
-		tagp = (xfs_dir2_data_off_t *)blp - 1;
+		tagp = (__be16 *)blp - 1;
 		/*
 		 * Data object just before the first leaf entry.
 		 */
-		dup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT));
+		dup = (xfs_dir2_data_unused_t *)((char *)block + be16_to_cpu(*tagp));
 		/*
 		 * If it's not free then the data will go where the
 		 * leaf data starts now, if it works at all.
 		 */
-		if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) {
-			if (INT_GET(dup->length, ARCH_CONVERT) + (INT_GET(btp->stale, ARCH_CONVERT) - 1) *
+		if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
+			if (be16_to_cpu(dup->length) + (be32_to_cpu(btp->stale) - 1) *
 			    (uint)sizeof(*blp) < len)
 				dup = NULL;
-		} else if ((INT_GET(btp->stale, ARCH_CONVERT) - 1) * (uint)sizeof(*blp) < len)
+		} else if ((be32_to_cpu(btp->stale) - 1) * (uint)sizeof(*blp) < len)
 			dup = NULL;
 		else
 			dup = (xfs_dir2_data_unused_t *)blp;
@@ -243,11 +242,11 @@
 		int	fromidx;		/* source leaf index */
 		int	toidx;			/* target leaf index */
 
-		for (fromidx = toidx = INT_GET(btp->count, ARCH_CONVERT) - 1,
+		for (fromidx = toidx = be32_to_cpu(btp->count) - 1,
 			highstale = lfloghigh = -1;
 		     fromidx >= 0;
 		     fromidx--) {
-			if (INT_GET(blp[fromidx].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) {
+			if (be32_to_cpu(blp[fromidx].address) == XFS_DIR2_NULL_DATAPTR) {
 				if (highstale == -1)
 					highstale = toidx;
 				else {
@@ -260,15 +259,15 @@
 				blp[toidx] = blp[fromidx];
 			toidx--;
 		}
-		lfloglow = toidx + 1 - (INT_GET(btp->stale, ARCH_CONVERT) - 1);
-		lfloghigh -= INT_GET(btp->stale, ARCH_CONVERT) - 1;
-		INT_MOD(btp->count, ARCH_CONVERT, -(INT_GET(btp->stale, ARCH_CONVERT) - 1));
+		lfloglow = toidx + 1 - (be32_to_cpu(btp->stale) - 1);
+		lfloghigh -= be32_to_cpu(btp->stale) - 1;
+		be32_add(&btp->count, -(be32_to_cpu(btp->stale) - 1));
 		xfs_dir2_data_make_free(tp, bp,
 			(xfs_dir2_data_aoff_t)((char *)blp - (char *)block),
-			(xfs_dir2_data_aoff_t)((INT_GET(btp->stale, ARCH_CONVERT) - 1) * sizeof(*blp)),
+			(xfs_dir2_data_aoff_t)((be32_to_cpu(btp->stale) - 1) * sizeof(*blp)),
 			&needlog, &needscan);
-		blp += INT_GET(btp->stale, ARCH_CONVERT) - 1;
-		INT_SET(btp->stale, ARCH_CONVERT, 1);
+		blp += be32_to_cpu(btp->stale) - 1;
+		btp->stale = cpu_to_be32(1);
 		/*
 		 * If we now need to rebuild the bestfree map, do so.
 		 * This needs to happen before the next call to use_free.
@@ -283,23 +282,23 @@
 	 * Set leaf logging boundaries to impossible state.
 	 * For the no-stale case they're set explicitly.
 	 */
-	else if (INT_GET(btp->stale, ARCH_CONVERT)) {
-		lfloglow = INT_GET(btp->count, ARCH_CONVERT);
+	else if (btp->stale) {
+		lfloglow = be32_to_cpu(btp->count);
 		lfloghigh = -1;
 	}
 	/*
 	 * Find the slot that's first lower than our hash value, -1 if none.
 	 */
-	for (low = 0, high = INT_GET(btp->count, ARCH_CONVERT) - 1; low <= high; ) {
+	for (low = 0, high = be32_to_cpu(btp->count) - 1; low <= high; ) {
 		mid = (low + high) >> 1;
-		if ((hash = INT_GET(blp[mid].hashval, ARCH_CONVERT)) == args->hashval)
+		if ((hash = be32_to_cpu(blp[mid].hashval)) == args->hashval)
 			break;
 		if (hash < args->hashval)
 			low = mid + 1;
 		else
 			high = mid - 1;
 	}
-	while (mid >= 0 && INT_GET(blp[mid].hashval, ARCH_CONVERT) >= args->hashval) {
+	while (mid >= 0 && be32_to_cpu(blp[mid].hashval) >= args->hashval) {
 		mid--;
 	}
 	/*
@@ -311,14 +310,14 @@
 		 */
 		xfs_dir2_data_use_free(tp, bp, enddup,
 			(xfs_dir2_data_aoff_t)
-			((char *)enddup - (char *)block + INT_GET(enddup->length, ARCH_CONVERT) -
+			((char *)enddup - (char *)block + be16_to_cpu(enddup->length) -
 			 sizeof(*blp)),
 			(xfs_dir2_data_aoff_t)sizeof(*blp),
 			&needlog, &needscan);
 		/*
 		 * Update the tail (entry count).
 		 */
-		INT_MOD(btp->count, ARCH_CONVERT, +1);
+		be32_add(&btp->count, 1);
 		/*
 		 * If we now need to rebuild the bestfree map, do so.
 		 * This needs to happen before the next call to use_free.
@@ -346,12 +345,12 @@
 	else {
 		for (lowstale = mid;
 		     lowstale >= 0 &&
-			INT_GET(blp[lowstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR;
+			be32_to_cpu(blp[lowstale].address) != XFS_DIR2_NULL_DATAPTR;
 		     lowstale--)
 			continue;
 		for (highstale = mid + 1;
-		     highstale < INT_GET(btp->count, ARCH_CONVERT) &&
-			INT_GET(blp[highstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR &&
+		     highstale < be32_to_cpu(btp->count) &&
+			be32_to_cpu(blp[highstale].address) != XFS_DIR2_NULL_DATAPTR &&
 			(lowstale < 0 || mid - lowstale > highstale - mid);
 		     highstale++)
 			continue;
@@ -359,7 +358,7 @@
 		 * Move entries toward the low-numbered stale entry.
 		 */
 		if (lowstale >= 0 &&
-		    (highstale == INT_GET(btp->count, ARCH_CONVERT) ||
+		    (highstale == be32_to_cpu(btp->count) ||
 		     mid - lowstale <= highstale - mid)) {
 			if (mid - lowstale)
 				memmove(&blp[lowstale], &blp[lowstale + 1],
@@ -371,7 +370,7 @@
 		 * Move entries toward the high-numbered stale entry.
 		 */
 		else {
-			ASSERT(highstale < INT_GET(btp->count, ARCH_CONVERT));
+			ASSERT(highstale < be32_to_cpu(btp->count));
 			mid++;
 			if (highstale - mid)
 				memmove(&blp[mid + 1], &blp[mid],
@@ -379,7 +378,7 @@
 			lfloglow = MIN(mid, lfloglow);
 			lfloghigh = MAX(highstale, lfloghigh);
 		}
-		INT_MOD(btp->stale, ARCH_CONVERT, -1);
+		be32_add(&btp->stale, -1);
 	}
 	/*
 	 * Point to the new data entry.
@@ -388,8 +387,9 @@
 	/*
 	 * Fill in the leaf entry.
 	 */
-	INT_SET(blp[mid].hashval, ARCH_CONVERT, args->hashval);
-	INT_SET(blp[mid].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, (char *)dep - (char *)block));
+	blp[mid].hashval = cpu_to_be32(args->hashval);
+	blp[mid].address = cpu_to_be32(XFS_DIR2_BYTE_TO_DATAPTR(mp,
+				(char *)dep - (char *)block));
 	xfs_dir2_block_log_leaf(tp, bp, lfloglow, lfloghigh);
 	/*
 	 * Mark space for the data entry used.
@@ -400,11 +400,11 @@
 	/*
 	 * Create the new data entry.
 	 */
-	INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
+	dep->inumber = cpu_to_be64(args->inumber);
 	dep->namelen = args->namelen;
 	memcpy(dep->name, args->name, args->namelen);
 	tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
-	INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block));
+	*tagp = cpu_to_be16((char *)dep - (char *)block);
 	/*
 	 * Clean up the bestfree array and log the header, tail, and entry.
 	 */
@@ -485,8 +485,8 @@
 		/*
 		 * Unused, skip it.
 		 */
-		if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) {
-			ptr += INT_GET(dup->length, ARCH_CONVERT);
+		if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
+			ptr += be16_to_cpu(dup->length);
 			continue;
 		}
 
@@ -508,7 +508,7 @@
 
 		p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
 						    ptr - (char *)block);
-		p.ino = INT_GET(dep->inumber, ARCH_CONVERT);
+		p.ino = be64_to_cpu(dep->inumber);
 #if XFS_BIG_INUMS
 		p.ino += mp->m_inoadd;
 #endif
@@ -622,11 +622,11 @@
 	 * Get the offset from the leaf entry, to point to the data.
 	 */
 	dep = (xfs_dir2_data_entry_t *)
-	      ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(blp[ent].address, ARCH_CONVERT)));
+	      ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(blp[ent].address)));
 	/*
 	 * Fill in inode number, release the block.
 	 */
-	args->inumber = INT_GET(dep->inumber, ARCH_CONVERT);
+	args->inumber = be64_to_cpu(dep->inumber);
 	xfs_da_brelse(args->trans, bp);
 	return XFS_ERROR(EEXIST);
 }
@@ -674,10 +674,10 @@
 	 * Loop doing a binary search for our hash value.
 	 * Find our entry, ENOENT if it's not there.
 	 */
-	for (low = 0, high = INT_GET(btp->count, ARCH_CONVERT) - 1; ; ) {
+	for (low = 0, high = be32_to_cpu(btp->count) - 1; ; ) {
 		ASSERT(low <= high);
 		mid = (low + high) >> 1;
-		if ((hash = INT_GET(blp[mid].hashval, ARCH_CONVERT)) == args->hashval)
+		if ((hash = be32_to_cpu(blp[mid].hashval)) == args->hashval)
 			break;
 		if (hash < args->hashval)
 			low = mid + 1;
@@ -692,7 +692,7 @@
 	/*
 	 * Back up to the first one with the right hash value.
 	 */
-	while (mid > 0 && INT_GET(blp[mid - 1].hashval, ARCH_CONVERT) == args->hashval) {
+	while (mid > 0 && be32_to_cpu(blp[mid - 1].hashval) == args->hashval) {
 		mid--;
 	}
 	/*
@@ -700,7 +700,7 @@
 	 * right hash value looking for our name.
 	 */
 	do {
-		if ((addr = INT_GET(blp[mid].address, ARCH_CONVERT)) == XFS_DIR2_NULL_DATAPTR)
+		if ((addr = be32_to_cpu(blp[mid].address)) == XFS_DIR2_NULL_DATAPTR)
 			continue;
 		/*
 		 * Get pointer to the entry from the leaf.
@@ -717,7 +717,7 @@
 			*entno = mid;
 			return 0;
 		}
-	} while (++mid < INT_GET(btp->count, ARCH_CONVERT) && INT_GET(blp[mid].hashval, ARCH_CONVERT) == hash);
+	} while (++mid < be32_to_cpu(btp->count) && be32_to_cpu(blp[mid].hashval) == hash);
 	/*
 	 * No match, release the buffer and return ENOENT.
 	 */
@@ -767,7 +767,7 @@
 	 * Point to the data entry using the leaf entry.
 	 */
 	dep = (xfs_dir2_data_entry_t *)
-	      ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(blp[ent].address, ARCH_CONVERT)));
+	      ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(blp[ent].address)));
 	/*
 	 * Mark the data entry's space free.
 	 */
@@ -778,12 +778,12 @@
 	/*
 	 * Fix up the block tail.
 	 */
-	INT_MOD(btp->stale, ARCH_CONVERT, +1);
+	be32_add(&btp->stale, 1);
 	xfs_dir2_block_log_tail(tp, bp);
 	/*
 	 * Remove the leaf entry by marking it stale.
 	 */
-	INT_SET(blp[ent].address, ARCH_CONVERT, XFS_DIR2_NULL_DATAPTR);
+	blp[ent].address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR);
 	xfs_dir2_block_log_leaf(tp, bp, ent, ent);
 	/*
 	 * Fix up bestfree, log the header if necessary.
@@ -843,12 +843,12 @@
 	 * Point to the data entry we need to change.
 	 */
 	dep = (xfs_dir2_data_entry_t *)
-	      ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(blp[ent].address, ARCH_CONVERT)));
-	ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) != args->inumber);
+	      ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(blp[ent].address)));
+	ASSERT(be64_to_cpu(dep->inumber) != args->inumber);
 	/*
 	 * Change the inode number to the new value.
 	 */
-	INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
+	dep->inumber = cpu_to_be64(args->inumber);
 	xfs_dir2_data_log_entry(args->trans, bp, dep);
 	xfs_dir2_data_check(dp, bp);
 	xfs_da_buf_done(bp);
@@ -868,8 +868,8 @@
 
 	la = a;
 	lb = b;
-	return INT_GET(la->hashval, ARCH_CONVERT) < INT_GET(lb->hashval, ARCH_CONVERT) ? -1 :
-		(INT_GET(la->hashval, ARCH_CONVERT) > INT_GET(lb->hashval, ARCH_CONVERT) ? 1 : 0);
+	return be32_to_cpu(la->hashval) < be32_to_cpu(lb->hashval) ? -1 :
+		(be32_to_cpu(la->hashval) > be32_to_cpu(lb->hashval) ? 1 : 0);
 }
 
 /*
@@ -881,7 +881,7 @@
 	xfs_dabuf_t		*lbp,		/* leaf buffer */
 	xfs_dabuf_t		*dbp)		/* data buffer */
 {
-	xfs_dir2_data_off_t	*bestsp;	/* leaf bests table */
+	__be16			*bestsp;	/* leaf bests table */
 	xfs_dir2_block_t	*block;		/* block structure */
 	xfs_dir2_block_tail_t	*btp;		/* block tail */
 	xfs_inode_t		*dp;		/* incore directory inode */
@@ -896,7 +896,7 @@
 	int			needscan;	/* need to scan for bestfree */
 	xfs_dir2_sf_hdr_t	sfh;		/* shortform header */
 	int			size;		/* bytes used */
-	xfs_dir2_data_off_t	*tagp;		/* end of entry (tag) */
+	__be16			*tagp;		/* end of entry (tag) */
 	int			to;		/* block/leaf to index */
 	xfs_trans_t		*tp;		/* transaction pointer */
 
@@ -905,7 +905,7 @@
 	tp = args->trans;
 	mp = dp->i_mount;
 	leaf = lbp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC);
 	ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
 	/*
 	 * If there are data blocks other than the first one, take this
@@ -915,11 +915,11 @@
 	 */
 	while (dp->i_d.di_size > mp->m_dirblksize) {
 		bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
-		if (INT_GET(bestsp[INT_GET(ltp->bestcount, ARCH_CONVERT) - 1], ARCH_CONVERT) ==
+		if (be16_to_cpu(bestsp[be32_to_cpu(ltp->bestcount) - 1]) ==
 		    mp->m_dirblksize - (uint)sizeof(block->hdr)) {
 			if ((error =
 			    xfs_dir2_leaf_trim_data(args, lbp,
-				    (xfs_dir2_db_t)(INT_GET(ltp->bestcount, ARCH_CONVERT) - 1))))
+				    (xfs_dir2_db_t)(be32_to_cpu(ltp->bestcount) - 1))))
 				goto out;
 		} else {
 			error = 0;
@@ -935,28 +935,29 @@
 		goto out;
 	}
 	block = dbp->data;
-	ASSERT(INT_GET(block->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC);
+	ASSERT(be32_to_cpu(block->hdr.magic) == XFS_DIR2_DATA_MAGIC);
 	/*
 	 * Size of the "leaf" area in the block.
 	 */
 	size = (uint)sizeof(block->tail) +
-	       (uint)sizeof(*lep) * (INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT));
+	       (uint)sizeof(*lep) * (be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale));
 	/*
 	 * Look at the last data entry.
 	 */
-	tagp = (xfs_dir2_data_off_t *)((char *)block + mp->m_dirblksize) - 1;
-	dup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT));
+	tagp = (__be16 *)((char *)block + mp->m_dirblksize) - 1;
+	dup = (xfs_dir2_data_unused_t *)((char *)block + be16_to_cpu(*tagp));
 	/*
 	 * If it's not free or is too short we can't do it.
 	 */
-	if (INT_GET(dup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG || INT_GET(dup->length, ARCH_CONVERT) < size) {
+	if (be16_to_cpu(dup->freetag) != XFS_DIR2_DATA_FREE_TAG ||
+	    be16_to_cpu(dup->length) < size) {
 		error = 0;
 		goto out;
 	}
 	/*
 	 * Start converting it to block form.
 	 */
-	INT_SET(block->hdr.magic, ARCH_CONVERT, XFS_DIR2_BLOCK_MAGIC);
+	block->hdr.magic = cpu_to_be32(XFS_DIR2_BLOCK_MAGIC);
 	needlog = 1;
 	needscan = 0;
 	/*
@@ -968,20 +969,20 @@
 	 * Initialize the block tail.
 	 */
 	btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-	INT_SET(btp->count, ARCH_CONVERT, INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT));
+	btp->count = cpu_to_be32(be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale));
 	btp->stale = 0;
 	xfs_dir2_block_log_tail(tp, dbp);
 	/*
 	 * Initialize the block leaf area.  We compact out stale entries.
 	 */
 	lep = XFS_DIR2_BLOCK_LEAF_P(btp);
-	for (from = to = 0; from < INT_GET(leaf->hdr.count, ARCH_CONVERT); from++) {
-		if (INT_GET(leaf->ents[from].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR)
+	for (from = to = 0; from < be16_to_cpu(leaf->hdr.count); from++) {
+		if (be32_to_cpu(leaf->ents[from].address) == XFS_DIR2_NULL_DATAPTR)
 			continue;
 		lep[to++] = leaf->ents[from];
 	}
-	ASSERT(to == INT_GET(btp->count, ARCH_CONVERT));
-	xfs_dir2_block_log_leaf(tp, dbp, 0, INT_GET(btp->count, ARCH_CONVERT) - 1);
+	ASSERT(to == be32_to_cpu(btp->count));
+	xfs_dir2_block_log_leaf(tp, dbp, 0, be32_to_cpu(btp->count) - 1);
 	/*
 	 * Scan the bestfree if we need it and log the data block header.
 	 */
@@ -1043,7 +1044,7 @@
 	int			offset;		/* target block offset */
 	xfs_dir2_sf_entry_t	*sfep;		/* sf entry pointer */
 	xfs_dir2_sf_t		*sfp;		/* shortform structure */
-	xfs_dir2_data_off_t	*tagp;		/* end of data entry */
+	__be16			*tagp;		/* end of data entry */
 	xfs_trans_t		*tp;		/* transaction pointer */
 
 	xfs_dir2_trace_args("sf_to_block", args);
@@ -1095,12 +1096,12 @@
 		return error;
 	}
 	block = bp->data;
-	INT_SET(block->hdr.magic, ARCH_CONVERT, XFS_DIR2_BLOCK_MAGIC);
+	block->hdr.magic = cpu_to_be32(XFS_DIR2_BLOCK_MAGIC);
 	/*
 	 * Compute size of block "tail" area.
 	 */
 	i = (uint)sizeof(*btp) +
-	    (INT_GET(sfp->hdr.count, ARCH_CONVERT) + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t);
+	    (sfp->hdr.count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t);
 	/*
 	 * The whole thing is initialized to free by the init routine.
 	 * Say we're using the leaf and tail area.
@@ -1114,7 +1115,7 @@
 	 * Fill in the tail.
 	 */
 	btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-	INT_SET(btp->count, ARCH_CONVERT, INT_GET(sfp->hdr.count, ARCH_CONVERT) + 2);	/* ., .. */
+	btp->count = cpu_to_be32(sfp->hdr.count + 2);	/* ., .. */
 	btp->stale = 0;
 	blp = XFS_DIR2_BLOCK_LEAF_P(btp);
 	endoffset = (uint)((char *)blp - (char *)block);
@@ -1123,38 +1124,40 @@
 	 */
 	xfs_dir2_data_use_free(tp, bp, dup,
 		(xfs_dir2_data_aoff_t)((char *)dup - (char *)block),
-		INT_GET(dup->length, ARCH_CONVERT), &needlog, &needscan);
+		be16_to_cpu(dup->length), &needlog, &needscan);
 	/*
 	 * Create entry for .
 	 */
 	dep = (xfs_dir2_data_entry_t *)
 	      ((char *)block + XFS_DIR2_DATA_DOT_OFFSET);
-	INT_SET(dep->inumber, ARCH_CONVERT, dp->i_ino);
+	dep->inumber = cpu_to_be64(dp->i_ino);
 	dep->namelen = 1;
 	dep->name[0] = '.';
 	tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
-	INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block));
+	*tagp = cpu_to_be16((char *)dep - (char *)block);
 	xfs_dir2_data_log_entry(tp, bp, dep);
-	INT_SET(blp[0].hashval, ARCH_CONVERT, xfs_dir_hash_dot);
-	INT_SET(blp[0].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, (char *)dep - (char *)block));
+	blp[0].hashval = cpu_to_be32(xfs_dir_hash_dot);
+	blp[0].address = cpu_to_be32(XFS_DIR2_BYTE_TO_DATAPTR(mp,
+				(char *)dep - (char *)block));
 	/*
 	 * Create entry for ..
 	 */
 	dep = (xfs_dir2_data_entry_t *)
 		((char *)block + XFS_DIR2_DATA_DOTDOT_OFFSET);
-	INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent));
+	dep->inumber = cpu_to_be64(XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent));
 	dep->namelen = 2;
 	dep->name[0] = dep->name[1] = '.';
 	tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
-	INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block));
+	*tagp = cpu_to_be16((char *)dep - (char *)block);
 	xfs_dir2_data_log_entry(tp, bp, dep);
-	INT_SET(blp[1].hashval, ARCH_CONVERT, xfs_dir_hash_dotdot);
-	INT_SET(blp[1].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, (char *)dep - (char *)block));
+	blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot);
+	blp[1].address = cpu_to_be32(XFS_DIR2_BYTE_TO_DATAPTR(mp,
+				(char *)dep - (char *)block));
 	offset = XFS_DIR2_DATA_FIRST_OFFSET;
 	/*
 	 * Loop over existing entries, stuff them in.
 	 */
-	if ((i = 0) == INT_GET(sfp->hdr.count, ARCH_CONVERT))
+	if ((i = 0) == sfp->hdr.count)
 		sfep = NULL;
 	else
 		sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
@@ -1176,33 +1179,33 @@
 		if (offset < newoffset) {
 			dup = (xfs_dir2_data_unused_t *)
 			      ((char *)block + offset);
-			INT_SET(dup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG);
-			INT_SET(dup->length, ARCH_CONVERT, newoffset - offset);
-			INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(dup), ARCH_CONVERT,
-				(xfs_dir2_data_off_t)
+			dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
+			dup->length = cpu_to_be16(newoffset - offset);
+			*XFS_DIR2_DATA_UNUSED_TAG_P(dup) = cpu_to_be16(
 				((char *)dup - (char *)block));
 			xfs_dir2_data_log_unused(tp, bp, dup);
 			(void)xfs_dir2_data_freeinsert((xfs_dir2_data_t *)block,
 				dup, &dummy);
-			offset += INT_GET(dup->length, ARCH_CONVERT);
+			offset += be16_to_cpu(dup->length);
 			continue;
 		}
 		/*
 		 * Copy a real entry.
 		 */
 		dep = (xfs_dir2_data_entry_t *)((char *)block + newoffset);
-		INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER(sfp,
+		dep->inumber = cpu_to_be64(XFS_DIR2_SF_GET_INUMBER(sfp,
 				XFS_DIR2_SF_INUMBERP(sfep)));
 		dep->namelen = sfep->namelen;
 		memcpy(dep->name, sfep->name, dep->namelen);
 		tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
-		INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block));
+		*tagp = cpu_to_be16((char *)dep - (char *)block);
 		xfs_dir2_data_log_entry(tp, bp, dep);
-		INT_SET(blp[2 + i].hashval, ARCH_CONVERT, xfs_da_hashname((char *)sfep->name, sfep->namelen));
-		INT_SET(blp[2 + i].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp,
+		blp[2 + i].hashval = cpu_to_be32(xfs_da_hashname(
+					(char *)sfep->name, sfep->namelen));
+		blp[2 + i].address = cpu_to_be32(XFS_DIR2_BYTE_TO_DATAPTR(mp,
 						 (char *)dep - (char *)block));
 		offset = (int)((char *)(tagp + 1) - (char *)block);
-		if (++i == INT_GET(sfp->hdr.count, ARCH_CONVERT))
+		if (++i == sfp->hdr.count)
 			sfep = NULL;
 		else
 			sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep);
@@ -1212,13 +1215,13 @@
 	/*
 	 * Sort the leaf entries by hash value.
 	 */
-	xfs_sort(blp, INT_GET(btp->count, ARCH_CONVERT), sizeof(*blp), xfs_dir2_block_sort);
+	xfs_sort(blp, be32_to_cpu(btp->count), sizeof(*blp), xfs_dir2_block_sort);
 	/*
 	 * Log the leaf entry area and tail.
 	 * Already logged the header in data_init, ignore needlog.
 	 */
 	ASSERT(needscan == 0);
-	xfs_dir2_block_log_leaf(tp, bp, 0, INT_GET(btp->count, ARCH_CONVERT) - 1);
+	xfs_dir2_block_log_leaf(tp, bp, 0, be32_to_cpu(btp->count) - 1);
 	xfs_dir2_block_log_tail(tp, bp);
 	xfs_dir2_data_check(dp, bp);
 	xfs_da_buf_done(bp);
diff -urN oldtree/fs/xfs/xfs_dir2_block.h newtree/fs/xfs/xfs_dir2_block.h
--- oldtree/fs/xfs/xfs_dir2_block.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/xfs/xfs_dir2_block.h	2006-02-21 15:58:36.724563576 +0000
@@ -43,8 +43,8 @@
 #define	XFS_DIR2_BLOCK_MAGIC	0x58443242	/* XD2B: for one block dirs */
 
 typedef struct xfs_dir2_block_tail {
-	__uint32_t	count;			/* count of leaf entries */
-	__uint32_t	stale;			/* count of stale lf entries */
+	__be32		count;			/* count of leaf entries */
+	__be32		stale;			/* count of stale lf entries */
 } xfs_dir2_block_tail_t;
 
 /*
@@ -75,8 +75,7 @@
 static inline struct xfs_dir2_leaf_entry *
 xfs_dir2_block_leaf_p(xfs_dir2_block_tail_t *btp)
 {
-	return (((struct xfs_dir2_leaf_entry *)
-		(btp)) - INT_GET((btp)->count, ARCH_CONVERT));
+	return ((struct xfs_dir2_leaf_entry *)btp) - be32_to_cpu(btp->count);
 }
 
 /*
diff -urN oldtree/fs/xfs/xfs_dir2_data.c newtree/fs/xfs/xfs_dir2_data.c
--- oldtree/fs/xfs/xfs_dir2_data.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/xfs/xfs_dir2_data.c	2006-02-21 15:58:36.726563272 +0000
@@ -70,11 +70,11 @@
 
 	mp = dp->i_mount;
 	d = bp->data;
-	ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC ||
-	       INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC);
+	ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
+	       be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
 	bf = d->hdr.bestfree;
 	p = (char *)d->u;
-	if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) {
+	if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
 		btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d);
 		lep = XFS_DIR2_BLOCK_LEAF_P(btp);
 		endp = (char *)lep;
@@ -96,8 +96,8 @@
 		ASSERT(!bf[2].offset);
 		freeseen |= 1 << 2;
 	}
-	ASSERT(INT_GET(bf[0].length, ARCH_CONVERT) >= INT_GET(bf[1].length, ARCH_CONVERT));
-	ASSERT(INT_GET(bf[1].length, ARCH_CONVERT) >= INT_GET(bf[2].length, ARCH_CONVERT));
+	ASSERT(be16_to_cpu(bf[0].length) >= be16_to_cpu(bf[1].length));
+	ASSERT(be16_to_cpu(bf[1].length) >= be16_to_cpu(bf[2].length));
 	/*
 	 * Loop over the data/unused entries.
 	 */
@@ -108,18 +108,20 @@
 		 * If we find it, account for that, else make sure it
 		 * doesn't need to be there.
 		 */
-		if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) {
+		if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
 			ASSERT(lastfree == 0);
-			ASSERT(INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P(dup), ARCH_CONVERT) ==
+			ASSERT(be16_to_cpu(*XFS_DIR2_DATA_UNUSED_TAG_P(dup)) ==
 			       (char *)dup - (char *)d);
 			dfp = xfs_dir2_data_freefind(d, dup);
 			if (dfp) {
 				i = (int)(dfp - bf);
 				ASSERT((freeseen & (1 << i)) == 0);
 				freeseen |= 1 << i;
-			} else
-				ASSERT(INT_GET(dup->length, ARCH_CONVERT) <= INT_GET(bf[2].length, ARCH_CONVERT));
-			p += INT_GET(dup->length, ARCH_CONVERT);
+			} else {
+				ASSERT(be16_to_cpu(dup->length) <=
+				       be16_to_cpu(bf[2].length));
+			}
+			p += be16_to_cpu(dup->length);
 			lastfree = 1;
 			continue;
 		}
@@ -131,22 +133,22 @@
 		 */
 		dep = (xfs_dir2_data_entry_t *)p;
 		ASSERT(dep->namelen != 0);
-		ASSERT(xfs_dir_ino_validate(mp, INT_GET(dep->inumber, ARCH_CONVERT)) == 0);
-		ASSERT(INT_GET(*XFS_DIR2_DATA_ENTRY_TAG_P(dep), ARCH_CONVERT) ==
+		ASSERT(xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber)) == 0);
+		ASSERT(be16_to_cpu(*XFS_DIR2_DATA_ENTRY_TAG_P(dep)) ==
 		       (char *)dep - (char *)d);
 		count++;
 		lastfree = 0;
-		if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) {
+		if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
 			addr = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
 				(xfs_dir2_data_aoff_t)
 				((char *)dep - (char *)d));
 			hash = xfs_da_hashname((char *)dep->name, dep->namelen);
-			for (i = 0; i < INT_GET(btp->count, ARCH_CONVERT); i++) {
-				if (INT_GET(lep[i].address, ARCH_CONVERT) == addr &&
-				    INT_GET(lep[i].hashval, ARCH_CONVERT) == hash)
+			for (i = 0; i < be32_to_cpu(btp->count); i++) {
+				if (be32_to_cpu(lep[i].address) == addr &&
+				    be32_to_cpu(lep[i].hashval) == hash)
 					break;
 			}
-			ASSERT(i < INT_GET(btp->count, ARCH_CONVERT));
+			ASSERT(i < be32_to_cpu(btp->count));
 		}
 		p += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
 	}
@@ -154,15 +156,15 @@
 	 * Need to have seen all the entries and all the bestfree slots.
 	 */
 	ASSERT(freeseen == 7);
-	if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) {
-		for (i = stale = 0; i < INT_GET(btp->count, ARCH_CONVERT); i++) {
-			if (INT_GET(lep[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR)
+	if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
+		for (i = stale = 0; i < be32_to_cpu(btp->count); i++) {
+			if (be32_to_cpu(lep[i].address) == XFS_DIR2_NULL_DATAPTR)
 				stale++;
 			if (i > 0)
-				ASSERT(INT_GET(lep[i].hashval, ARCH_CONVERT) >= INT_GET(lep[i - 1].hashval, ARCH_CONVERT));
+				ASSERT(be32_to_cpu(lep[i].hashval) >= be32_to_cpu(lep[i - 1].hashval));
 		}
-		ASSERT(count == INT_GET(btp->count, ARCH_CONVERT) - INT_GET(btp->stale, ARCH_CONVERT));
-		ASSERT(stale == INT_GET(btp->stale, ARCH_CONVERT));
+		ASSERT(count == be32_to_cpu(btp->count) - be32_to_cpu(btp->stale));
+		ASSERT(stale == be32_to_cpu(btp->stale));
 	}
 }
 #endif
@@ -190,8 +192,8 @@
 	 * Check order, non-overlapping entries, and if we find the
 	 * one we're looking for it has to be exact.
 	 */
-	ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC ||
-	       INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC);
+	ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
+	       be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
 	for (dfp = &d->hdr.bestfree[0], seenzero = matched = 0;
 	     dfp < &d->hdr.bestfree[XFS_DIR2_DATA_FD_COUNT];
 	     dfp++) {
@@ -201,23 +203,24 @@
 			continue;
 		}
 		ASSERT(seenzero == 0);
-		if (INT_GET(dfp->offset, ARCH_CONVERT) == off) {
+		if (be16_to_cpu(dfp->offset) == off) {
 			matched = 1;
-			ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(dup->length, ARCH_CONVERT));
-		} else if (off < INT_GET(dfp->offset, ARCH_CONVERT))
-			ASSERT(off + INT_GET(dup->length, ARCH_CONVERT) <= INT_GET(dfp->offset, ARCH_CONVERT));
+			ASSERT(dfp->length == dup->length);
+		} else if (off < be16_to_cpu(dfp->offset))
+			ASSERT(off + be16_to_cpu(dup->length) <= be16_to_cpu(dfp->offset));
 		else
-			ASSERT(INT_GET(dfp->offset, ARCH_CONVERT) + INT_GET(dfp->length, ARCH_CONVERT) <= off);
-		ASSERT(matched || INT_GET(dfp->length, ARCH_CONVERT) >= INT_GET(dup->length, ARCH_CONVERT));
+			ASSERT(be16_to_cpu(dfp->offset) + be16_to_cpu(dfp->length) <= off);
+		ASSERT(matched || be16_to_cpu(dfp->length) >= be16_to_cpu(dup->length));
 		if (dfp > &d->hdr.bestfree[0])
-			ASSERT(INT_GET(dfp[-1].length, ARCH_CONVERT) >= INT_GET(dfp[0].length, ARCH_CONVERT));
+			ASSERT(be16_to_cpu(dfp[-1].length) >= be16_to_cpu(dfp[0].length));
 	}
 #endif
 	/*
 	 * If this is smaller than the smallest bestfree entry,
 	 * it can't be there since they're sorted.
 	 */
-	if (INT_GET(dup->length, ARCH_CONVERT) < INT_GET(d->hdr.bestfree[XFS_DIR2_DATA_FD_COUNT - 1].length, ARCH_CONVERT))
+	if (be16_to_cpu(dup->length) <
+	    be16_to_cpu(d->hdr.bestfree[XFS_DIR2_DATA_FD_COUNT - 1].length))
 		return NULL;
 	/*
 	 * Look at the three bestfree entries for our guy.
@@ -227,7 +230,7 @@
 	     dfp++) {
 		if (!dfp->offset)
 			return NULL;
-		if (INT_GET(dfp->offset, ARCH_CONVERT) == off)
+		if (be16_to_cpu(dfp->offset) == off)
 			return dfp;
 	}
 	/*
@@ -249,29 +252,29 @@
 	xfs_dir2_data_free_t	new;		/* new bestfree entry */
 
 #ifdef __KERNEL__
-	ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC ||
-	       INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC);
+	ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
+	       be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
 #endif
 	dfp = d->hdr.bestfree;
-	INT_COPY(new.length, dup->length, ARCH_CONVERT);
-	INT_SET(new.offset, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dup - (char *)d));
+	new.length = dup->length;
+	new.offset = cpu_to_be16((char *)dup - (char *)d);
 	/*
 	 * Insert at position 0, 1, or 2; or not at all.
 	 */
-	if (INT_GET(new.length, ARCH_CONVERT) > INT_GET(dfp[0].length, ARCH_CONVERT)) {
+	if (be16_to_cpu(new.length) > be16_to_cpu(dfp[0].length)) {
 		dfp[2] = dfp[1];
 		dfp[1] = dfp[0];
 		dfp[0] = new;
 		*loghead = 1;
 		return &dfp[0];
 	}
-	if (INT_GET(new.length, ARCH_CONVERT) > INT_GET(dfp[1].length, ARCH_CONVERT)) {
+	if (be16_to_cpu(new.length) > be16_to_cpu(dfp[1].length)) {
 		dfp[2] = dfp[1];
 		dfp[1] = new;
 		*loghead = 1;
 		return &dfp[1];
 	}
-	if (INT_GET(new.length, ARCH_CONVERT) > INT_GET(dfp[2].length, ARCH_CONVERT)) {
+	if (be16_to_cpu(new.length) > be16_to_cpu(dfp[2].length)) {
 		dfp[2] = new;
 		*loghead = 1;
 		return &dfp[2];
@@ -289,8 +292,8 @@
 	int			*loghead)	/* out: log data header */
 {
 #ifdef __KERNEL__
-	ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC ||
-	       INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC);
+	ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
+	       be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
 #endif
 	/*
 	 * It's the first entry, slide the next 2 up.
@@ -334,8 +337,8 @@
 	char			*p;		/* current entry pointer */
 
 #ifdef __KERNEL__
-	ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC ||
-	       INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC);
+	ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
+	       be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
 #endif
 	/*
 	 * Start by clearing the table.
@@ -348,7 +351,7 @@
 	p = (char *)d->u;
 	if (aendp)
 		endp = aendp;
-	else if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) {
+	else if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
 		btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d);
 		endp = (char *)XFS_DIR2_BLOCK_LEAF_P(btp);
 	} else
@@ -361,11 +364,11 @@
 		/*
 		 * If it's a free entry, insert it.
 		 */
-		if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) {
+		if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
 			ASSERT((char *)dup - (char *)d ==
-			       INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P(dup), ARCH_CONVERT));
+			       be16_to_cpu(*XFS_DIR2_DATA_UNUSED_TAG_P(dup)));
 			xfs_dir2_data_freeinsert(d, dup, loghead);
-			p += INT_GET(dup->length, ARCH_CONVERT);
+			p += be16_to_cpu(dup->length);
 		}
 		/*
 		 * For active entries, check their tags and skip them.
@@ -373,7 +376,7 @@
 		else {
 			dep = (xfs_dir2_data_entry_t *)p;
 			ASSERT((char *)dep - (char *)d ==
-			       INT_GET(*XFS_DIR2_DATA_ENTRY_TAG_P(dep), ARCH_CONVERT));
+			       be16_to_cpu(*XFS_DIR2_DATA_ENTRY_TAG_P(dep)));
 			p += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
 		}
 	}
@@ -415,8 +418,8 @@
 	 * Initialize the header.
 	 */
 	d = bp->data;
-	INT_SET(d->hdr.magic, ARCH_CONVERT, XFS_DIR2_DATA_MAGIC);
-	INT_SET(d->hdr.bestfree[0].offset, ARCH_CONVERT, (xfs_dir2_data_off_t)sizeof(d->hdr));
+	d->hdr.magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
+	d->hdr.bestfree[0].offset = cpu_to_be16(sizeof(d->hdr));
 	for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) {
 		d->hdr.bestfree[i].length = 0;
 		d->hdr.bestfree[i].offset = 0;
@@ -425,13 +428,12 @@
 	 * Set up an unused entry for the block's body.
 	 */
 	dup = &d->u[0].unused;
-	INT_SET(dup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG);
+	dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
 
 	t=mp->m_dirblksize - (uint)sizeof(d->hdr);
-	INT_SET(d->hdr.bestfree[0].length, ARCH_CONVERT, t);
-	INT_SET(dup->length, ARCH_CONVERT, t);
-	INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(dup), ARCH_CONVERT,
-		(xfs_dir2_data_off_t)((char *)dup - (char *)d));
+	d->hdr.bestfree[0].length = cpu_to_be16(t);
+	dup->length = cpu_to_be16(t);
+	*XFS_DIR2_DATA_UNUSED_TAG_P(dup) = cpu_to_be16((char *)dup - (char *)d);
 	/*
 	 * Log it and return it.
 	 */
@@ -453,8 +455,8 @@
 	xfs_dir2_data_t		*d;		/* data block pointer */
 
 	d = bp->data;
-	ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC ||
-	       INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC);
+	ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
+	       be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
 	xfs_da_log_buf(tp, bp, (uint)((char *)dep - (char *)d),
 		(uint)((char *)(XFS_DIR2_DATA_ENTRY_TAG_P(dep) + 1) -
 		       (char *)d - 1));
@@ -471,8 +473,8 @@
 	xfs_dir2_data_t		*d;		/* data block pointer */
 
 	d = bp->data;
-	ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC ||
-	       INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC);
+	ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
+	       be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
 	xfs_da_log_buf(tp, bp, (uint)((char *)&d->hdr - (char *)d),
 		(uint)(sizeof(d->hdr) - 1));
 }
@@ -489,8 +491,8 @@
 	xfs_dir2_data_t		*d;		/* data block pointer */
 
 	d = bp->data;
-	ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC ||
-	       INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC);
+	ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
+	       be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
 	/*
 	 * Log the first part of the unused entry.
 	 */
@@ -533,12 +535,12 @@
 	/*
 	 * Figure out where the end of the data area is.
 	 */
-	if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC)
+	if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC)
 		endptr = (char *)d + mp->m_dirblksize;
 	else {
 		xfs_dir2_block_tail_t	*btp;	/* block tail */
 
-		ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC);
+		ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
 		btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d);
 		endptr = (char *)XFS_DIR2_BLOCK_LEAF_P(btp);
 	}
@@ -547,11 +549,11 @@
 	 * the previous entry and see if it's free.
 	 */
 	if (offset > sizeof(d->hdr)) {
-		xfs_dir2_data_off_t	*tagp;	/* tag just before us */
+		__be16			*tagp;	/* tag just before us */
 
-		tagp = (xfs_dir2_data_off_t *)((char *)d + offset) - 1;
-		prevdup = (xfs_dir2_data_unused_t *)((char *)d + INT_GET(*tagp, ARCH_CONVERT));
-		if (INT_GET(prevdup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG)
+		tagp = (__be16 *)((char *)d + offset) - 1;
+		prevdup = (xfs_dir2_data_unused_t *)((char *)d + be16_to_cpu(*tagp));
+		if (be16_to_cpu(prevdup->freetag) != XFS_DIR2_DATA_FREE_TAG)
 			prevdup = NULL;
 	} else
 		prevdup = NULL;
@@ -562,7 +564,7 @@
 	if ((char *)d + offset + len < endptr) {
 		postdup =
 			(xfs_dir2_data_unused_t *)((char *)d + offset + len);
-		if (INT_GET(postdup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG)
+		if (be16_to_cpu(postdup->freetag) != XFS_DIR2_DATA_FREE_TAG)
 			postdup = NULL;
 	} else
 		postdup = NULL;
@@ -586,13 +588,13 @@
 		 * since the third bestfree is there, there might be more
 		 * entries.
 		 */
-		needscan = d->hdr.bestfree[2].length;
+		needscan = (d->hdr.bestfree[2].length != 0);
 		/*
 		 * Fix up the new big freespace.
 		 */
-		INT_MOD(prevdup->length, ARCH_CONVERT, len + INT_GET(postdup->length, ARCH_CONVERT));
-		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(prevdup), ARCH_CONVERT,
-			(xfs_dir2_data_off_t)((char *)prevdup - (char *)d));
+		be16_add(&prevdup->length, len + be16_to_cpu(postdup->length));
+		*XFS_DIR2_DATA_UNUSED_TAG_P(prevdup) =
+			cpu_to_be16((char *)prevdup - (char *)d);
 		xfs_dir2_data_log_unused(tp, bp, prevdup);
 		if (!needscan) {
 			/*
@@ -614,7 +616,7 @@
 			 */
 			dfp = xfs_dir2_data_freeinsert(d, prevdup, needlogp);
 			ASSERT(dfp == &d->hdr.bestfree[0]);
-			ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(prevdup->length, ARCH_CONVERT));
+			ASSERT(dfp->length == prevdup->length);
 			ASSERT(!dfp[1].length);
 			ASSERT(!dfp[2].length);
 		}
@@ -624,9 +626,9 @@
 	 */
 	else if (prevdup) {
 		dfp = xfs_dir2_data_freefind(d, prevdup);
-		INT_MOD(prevdup->length, ARCH_CONVERT, len);
-		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(prevdup), ARCH_CONVERT,
-			(xfs_dir2_data_off_t)((char *)prevdup - (char *)d));
+		be16_add(&prevdup->length, len);
+		*XFS_DIR2_DATA_UNUSED_TAG_P(prevdup) =
+			cpu_to_be16((char *)prevdup - (char *)d);
 		xfs_dir2_data_log_unused(tp, bp, prevdup);
 		/*
 		 * If the previous entry was in the table, the new entry
@@ -640,8 +642,10 @@
 		/*
 		 * Otherwise we need a scan if the new entry is big enough.
 		 */
-		else
-			needscan = INT_GET(prevdup->length, ARCH_CONVERT) > INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT);
+		else {
+			needscan = be16_to_cpu(prevdup->length) >
+				   be16_to_cpu(d->hdr.bestfree[2].length);
+		}
 	}
 	/*
 	 * The following entry is free, merge with it.
@@ -649,10 +653,10 @@
 	else if (postdup) {
 		dfp = xfs_dir2_data_freefind(d, postdup);
 		newdup = (xfs_dir2_data_unused_t *)((char *)d + offset);
-		INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG);
-		INT_SET(newdup->length, ARCH_CONVERT, len + INT_GET(postdup->length, ARCH_CONVERT));
-		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(newdup), ARCH_CONVERT,
-			(xfs_dir2_data_off_t)((char *)newdup - (char *)d));
+		newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
+		newdup->length = cpu_to_be16(len + be16_to_cpu(postdup->length));
+		*XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
+			cpu_to_be16((char *)newdup - (char *)d);
 		xfs_dir2_data_log_unused(tp, bp, newdup);
 		/*
 		 * If the following entry was in the table, the new entry
@@ -666,18 +670,20 @@
 		/*
 		 * Otherwise we need a scan if the new entry is big enough.
 		 */
-		else
-			needscan = INT_GET(newdup->length, ARCH_CONVERT) > INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT);
+		else {
+			needscan = be16_to_cpu(newdup->length) >
+				   be16_to_cpu(d->hdr.bestfree[2].length);
+		}
 	}
 	/*
 	 * Neither neighbor is free.  Make a new entry.
 	 */
 	else {
 		newdup = (xfs_dir2_data_unused_t *)((char *)d + offset);
-		INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG);
-		INT_SET(newdup->length, ARCH_CONVERT, len);
-		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(newdup), ARCH_CONVERT,
-			(xfs_dir2_data_off_t)((char *)newdup - (char *)d));
+		newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
+		newdup->length = cpu_to_be16(len);
+		*XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
+			cpu_to_be16((char *)newdup - (char *)d);
 		xfs_dir2_data_log_unused(tp, bp, newdup);
 		(void)xfs_dir2_data_freeinsert(d, newdup, needlogp);
 	}
@@ -707,18 +713,18 @@
 	int			oldlen;		/* old unused entry's length */
 
 	d = bp->data;
-	ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC ||
-	       INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC);
-	ASSERT(INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG);
+	ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
+	       be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
+	ASSERT(be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG);
 	ASSERT(offset >= (char *)dup - (char *)d);
-	ASSERT(offset + len <= (char *)dup + INT_GET(dup->length, ARCH_CONVERT) - (char *)d);
-	ASSERT((char *)dup - (char *)d == INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P(dup), ARCH_CONVERT));
+	ASSERT(offset + len <= (char *)dup + be16_to_cpu(dup->length) - (char *)d);
+	ASSERT((char *)dup - (char *)d == be16_to_cpu(*XFS_DIR2_DATA_UNUSED_TAG_P(dup)));
 	/*
 	 * Look up the entry in the bestfree table.
 	 */
 	dfp = xfs_dir2_data_freefind(d, dup);
-	oldlen = INT_GET(dup->length, ARCH_CONVERT);
-	ASSERT(dfp || oldlen <= INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT));
+	oldlen = be16_to_cpu(dup->length);
+	ASSERT(dfp || oldlen <= be16_to_cpu(d->hdr.bestfree[2].length));
 	/*
 	 * Check for alignment with front and back of the entry.
 	 */
@@ -732,7 +738,7 @@
 	 */
 	if (matchfront && matchback) {
 		if (dfp) {
-			needscan = d->hdr.bestfree[2].offset;
+			needscan = (d->hdr.bestfree[2].offset != 0);
 			if (!needscan)
 				xfs_dir2_data_freeremove(d, dfp, needlogp);
 		}
@@ -743,10 +749,10 @@
 	 */
 	else if (matchfront) {
 		newdup = (xfs_dir2_data_unused_t *)((char *)d + offset + len);
-		INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG);
-		INT_SET(newdup->length, ARCH_CONVERT, oldlen - len);
-		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(newdup), ARCH_CONVERT,
-			(xfs_dir2_data_off_t)((char *)newdup - (char *)d));
+		newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
+		newdup->length = cpu_to_be16(oldlen - len);
+		*XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
+			cpu_to_be16((char *)newdup - (char *)d);
 		xfs_dir2_data_log_unused(tp, bp, newdup);
 		/*
 		 * If it was in the table, remove it and add the new one.
@@ -755,8 +761,8 @@
 			xfs_dir2_data_freeremove(d, dfp, needlogp);
 			dfp = xfs_dir2_data_freeinsert(d, newdup, needlogp);
 			ASSERT(dfp != NULL);
-			ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(newdup->length, ARCH_CONVERT));
-			ASSERT(INT_GET(dfp->offset, ARCH_CONVERT) == (char *)newdup - (char *)d);
+			ASSERT(dfp->length == newdup->length);
+			ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)d);
 			/*
 			 * If we got inserted at the last slot,
 			 * that means we don't know if there was a better
@@ -771,10 +777,9 @@
 	 */
 	else if (matchback) {
 		newdup = dup;
-		INT_SET(newdup->length, ARCH_CONVERT, (xfs_dir2_data_off_t)
-			(((char *)d + offset) - (char *)newdup));
-		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(newdup), ARCH_CONVERT,
-			(xfs_dir2_data_off_t)((char *)newdup - (char *)d));
+		newdup->length = cpu_to_be16(((char *)d + offset) - (char *)newdup);
+		*XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
+			cpu_to_be16((char *)newdup - (char *)d);
 		xfs_dir2_data_log_unused(tp, bp, newdup);
 		/*
 		 * If it was in the table, remove it and add the new one.
@@ -783,8 +788,8 @@
 			xfs_dir2_data_freeremove(d, dfp, needlogp);
 			dfp = xfs_dir2_data_freeinsert(d, newdup, needlogp);
 			ASSERT(dfp != NULL);
-			ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(newdup->length, ARCH_CONVERT));
-			ASSERT(INT_GET(dfp->offset, ARCH_CONVERT) == (char *)newdup - (char *)d);
+			ASSERT(dfp->length == newdup->length);
+			ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)d);
 			/*
 			 * If we got inserted at the last slot,
 			 * that means we don't know if there was a better
@@ -799,16 +804,15 @@
 	 */
 	else {
 		newdup = dup;
-		INT_SET(newdup->length, ARCH_CONVERT, (xfs_dir2_data_off_t)
-			(((char *)d + offset) - (char *)newdup));
-		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(newdup), ARCH_CONVERT,
-			(xfs_dir2_data_off_t)((char *)newdup - (char *)d));
+		newdup->length = cpu_to_be16(((char *)d + offset) - (char *)newdup);
+		*XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
+			cpu_to_be16((char *)newdup - (char *)d);
 		xfs_dir2_data_log_unused(tp, bp, newdup);
 		newdup2 = (xfs_dir2_data_unused_t *)((char *)d + offset + len);
-		INT_SET(newdup2->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG);
-		INT_SET(newdup2->length, ARCH_CONVERT, oldlen - len - INT_GET(newdup->length, ARCH_CONVERT));
-		INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(newdup2), ARCH_CONVERT,
-			(xfs_dir2_data_off_t)((char *)newdup2 - (char *)d));
+		newdup2->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
+		newdup2->length = cpu_to_be16(oldlen - len - be16_to_cpu(newdup->length));
+		*XFS_DIR2_DATA_UNUSED_TAG_P(newdup2) =
+			cpu_to_be16((char *)newdup2 - (char *)d);
 		xfs_dir2_data_log_unused(tp, bp, newdup2);
 		/*
 		 * If the old entry was in the table, we need to scan
@@ -819,7 +823,7 @@
 		 * the 2 new will work.
 		 */
 		if (dfp) {
-			needscan = d->hdr.bestfree[2].length;
+			needscan = (d->hdr.bestfree[2].length != 0);
 			if (!needscan) {
 				xfs_dir2_data_freeremove(d, dfp, needlogp);
 				(void)xfs_dir2_data_freeinsert(d, newdup,
diff -urN oldtree/fs/xfs/xfs_dir2_data.h newtree/fs/xfs/xfs_dir2_data.h
--- oldtree/fs/xfs/xfs_dir2_data.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/xfs/xfs_dir2_data.h	2006-02-21 15:58:36.727563120 +0000
@@ -65,8 +65,8 @@
  * The freespace will be formatted as a xfs_dir2_data_unused_t.
  */
 typedef struct xfs_dir2_data_free {
-	xfs_dir2_data_off_t	offset;		/* start of freespace */
-	xfs_dir2_data_off_t	length;		/* length of freespace */
+	__be16			offset;		/* start of freespace */
+	__be16			length;		/* length of freespace */
 } xfs_dir2_data_free_t;
 
 /*
@@ -75,7 +75,7 @@
  * The code knows that XFS_DIR2_DATA_FD_COUNT is 3.
  */
 typedef struct xfs_dir2_data_hdr {
-	__uint32_t		magic;		/* XFS_DIR2_DATA_MAGIC */
+	__be32			magic;		/* XFS_DIR2_DATA_MAGIC */
 						/* or XFS_DIR2_BLOCK_MAGIC */
 	xfs_dir2_data_free_t	bestfree[XFS_DIR2_DATA_FD_COUNT];
 } xfs_dir2_data_hdr_t;
@@ -85,11 +85,11 @@
  * Tag appears as the last 2 bytes.
  */
 typedef struct xfs_dir2_data_entry {
-	xfs_ino_t		inumber;	/* inode number */
-	__uint8_t		namelen;	/* name length */
-	__uint8_t		name[1];	/* name bytes, no null */
+	__be64			inumber;	/* inode number */
+	__u8			namelen;	/* name length */
+	__u8			name[1];	/* name bytes, no null */
 						/* variable offset */
-	xfs_dir2_data_off_t	tag;		/* starting offset of us */
+	__be16			tag;		/* starting offset of us */
 } xfs_dir2_data_entry_t;
 
 /*
@@ -97,10 +97,10 @@
  * Tag appears as the last 2 bytes.
  */
 typedef struct xfs_dir2_data_unused {
-	__uint16_t		freetag;	/* XFS_DIR2_DATA_FREE_TAG */
-	xfs_dir2_data_off_t	length;		/* total free length */
+	__be16			freetag;	/* XFS_DIR2_DATA_FREE_TAG */
+	__be16			length;		/* total free length */
 						/* variable offset */
-	xfs_dir2_data_off_t	tag;		/* starting offset of us */
+	__be16			tag;		/* starting offset of us */
 } xfs_dir2_data_unused_t;
 
 typedef union {
@@ -134,12 +134,11 @@
  * Pointer to an entry's tag word.
  */
 #define	XFS_DIR2_DATA_ENTRY_TAG_P(dep)	xfs_dir2_data_entry_tag_p(dep)
-static inline xfs_dir2_data_off_t *
+static inline __be16 *
 xfs_dir2_data_entry_tag_p(xfs_dir2_data_entry_t *dep)
 {
-	return (xfs_dir2_data_off_t *) \
-		 ((char *)(dep) + XFS_DIR2_DATA_ENTSIZE((dep)->namelen) - \
-		  (uint)sizeof(xfs_dir2_data_off_t));
+	return (__be16 *)((char *)dep +
+		XFS_DIR2_DATA_ENTSIZE(dep->namelen) - sizeof(__be16));
 }
 
 /*
@@ -147,12 +146,11 @@
  */
 #define	XFS_DIR2_DATA_UNUSED_TAG_P(dup) \
 	xfs_dir2_data_unused_tag_p(dup)
-static inline xfs_dir2_data_off_t *
+static inline __be16 *
 xfs_dir2_data_unused_tag_p(xfs_dir2_data_unused_t *dup)
 {
-	return (xfs_dir2_data_off_t *) \
-		 ((char *)(dup) + INT_GET((dup)->length, ARCH_CONVERT) \
-				- (uint)sizeof(xfs_dir2_data_off_t));
+	return (__be16 *)((char *)dup +
+			be16_to_cpu(dup->length) - sizeof(__be16));
 }
 
 /*
diff -urN oldtree/fs/xfs/xfs_dir2_leaf.c newtree/fs/xfs/xfs_dir2_leaf.c
--- oldtree/fs/xfs/xfs_dir2_leaf.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/xfs/xfs_dir2_leaf.c	2006-02-21 15:58:36.729562816 +0000
@@ -66,7 +66,7 @@
 	xfs_da_args_t		*args,		/* operation arguments */
 	xfs_dabuf_t		*dbp)		/* input block's buffer */
 {
-	xfs_dir2_data_off_t	*bestsp;	/* leaf's bestsp entries */
+	__be16			*bestsp;	/* leaf's bestsp entries */
 	xfs_dablk_t		blkno;		/* leaf block's bno */
 	xfs_dir2_block_t	*block;		/* block structure */
 	xfs_dir2_leaf_entry_t	*blp;		/* block's leaf entries */
@@ -111,14 +111,14 @@
 	/*
 	 * Set the counts in the leaf header.
 	 */
-	INT_COPY(leaf->hdr.count, btp->count, ARCH_CONVERT); /* INT_: type change */
-	INT_COPY(leaf->hdr.stale, btp->stale, ARCH_CONVERT); /* INT_: type change */
+	leaf->hdr.count = cpu_to_be16(be32_to_cpu(btp->count));
+	leaf->hdr.stale = cpu_to_be16(be32_to_cpu(btp->stale));
 	/*
 	 * Could compact these but I think we always do the conversion
 	 * after squeezing out stale entries.
 	 */
-	memcpy(leaf->ents, blp, INT_GET(btp->count, ARCH_CONVERT) * sizeof(xfs_dir2_leaf_entry_t));
-	xfs_dir2_leaf_log_ents(tp, lbp, 0, INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1);
+	memcpy(leaf->ents, blp, be32_to_cpu(btp->count) * sizeof(xfs_dir2_leaf_entry_t));
+	xfs_dir2_leaf_log_ents(tp, lbp, 0, be16_to_cpu(leaf->hdr.count) - 1);
 	needscan = 0;
 	needlog = 1;
 	/*
@@ -133,7 +133,7 @@
 	/*
 	 * Fix up the block header, make it a data block.
 	 */
-	INT_SET(block->hdr.magic, ARCH_CONVERT, XFS_DIR2_DATA_MAGIC);
+	block->hdr.magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
 	if (needscan)
 		xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog,
 			NULL);
@@ -141,9 +141,9 @@
 	 * Set up leaf tail and bests table.
 	 */
 	ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
-	INT_SET(ltp->bestcount, ARCH_CONVERT, 1);
+	ltp->bestcount = cpu_to_be32(1);
 	bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
-	INT_COPY(bestsp[0], block->hdr.bestfree[0].length, ARCH_CONVERT);
+	bestsp[0] =  block->hdr.bestfree[0].length;
 	/*
 	 * Log the data header and leaf bests table.
 	 */
@@ -163,7 +163,7 @@
 xfs_dir2_leaf_addname(
 	xfs_da_args_t		*args)		/* operation arguments */
 {
-	xfs_dir2_data_off_t	*bestsp;	/* freespace table in leaf */
+	__be16			*bestsp;	/* freespace table in leaf */
 	int			compact;	/* need to compact leaves */
 	xfs_dir2_data_t		*data;		/* data block structure */
 	xfs_dabuf_t		*dbp;		/* data block buffer */
@@ -187,7 +187,7 @@
 	int			needbytes;	/* leaf block bytes needed */
 	int			needlog;	/* need to log data header */
 	int			needscan;	/* need to rescan data free */
-	xfs_dir2_data_off_t	*tagp;		/* end of data entry */
+	__be16			*tagp;		/* end of data entry */
 	xfs_trans_t		*tp;		/* transaction pointer */
 	xfs_dir2_db_t		use_block;	/* data block number */
 
@@ -222,14 +222,14 @@
 	 * in a data block, improving the lookup of those entries.
 	 */
 	for (use_block = -1, lep = &leaf->ents[index];
-	     index < INT_GET(leaf->hdr.count, ARCH_CONVERT) && INT_GET(lep->hashval, ARCH_CONVERT) == args->hashval;
+	     index < be16_to_cpu(leaf->hdr.count) && be32_to_cpu(lep->hashval) == args->hashval;
 	     index++, lep++) {
-		if (INT_GET(lep->address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR)
+		if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
 			continue;
-		i = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT));
-		ASSERT(i < INT_GET(ltp->bestcount, ARCH_CONVERT));
-		ASSERT(INT_GET(bestsp[i], ARCH_CONVERT) != NULLDATAOFF);
-		if (INT_GET(bestsp[i], ARCH_CONVERT) >= length) {
+		i = XFS_DIR2_DATAPTR_TO_DB(mp, be32_to_cpu(lep->address));
+		ASSERT(i < be32_to_cpu(ltp->bestcount));
+		ASSERT(be16_to_cpu(bestsp[i]) != NULLDATAOFF);
+		if (be16_to_cpu(bestsp[i]) >= length) {
 			use_block = i;
 			break;
 		}
@@ -238,13 +238,13 @@
 	 * Didn't find a block yet, linear search all the data blocks.
 	 */
 	if (use_block == -1) {
-		for (i = 0; i < INT_GET(ltp->bestcount, ARCH_CONVERT); i++) {
+		for (i = 0; i < be32_to_cpu(ltp->bestcount); i++) {
 			/*
 			 * Remember a block we see that's missing.
 			 */
-			if (INT_GET(bestsp[i], ARCH_CONVERT) == NULLDATAOFF && use_block == -1)
+			if (be16_to_cpu(bestsp[i]) == NULLDATAOFF && use_block == -1)
 				use_block = i;
-			else if (INT_GET(bestsp[i], ARCH_CONVERT) >= length) {
+			else if (be16_to_cpu(bestsp[i]) >= length) {
 				use_block = i;
 				break;
 			}
@@ -260,21 +260,21 @@
 	 * Now kill use_block if it refers to a missing block, so we
 	 * can use it as an indication of allocation needed.
 	 */
-	if (use_block != -1 && INT_GET(bestsp[use_block], ARCH_CONVERT) == NULLDATAOFF)
+	if (use_block != -1 && be16_to_cpu(bestsp[use_block]) == NULLDATAOFF)
 		use_block = -1;
 	/*
 	 * If we don't have enough free bytes but we can make enough
 	 * by compacting out stale entries, we'll do that.
 	 */
-	if ((char *)bestsp - (char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] < needbytes &&
-	    INT_GET(leaf->hdr.stale, ARCH_CONVERT) > 1) {
+	if ((char *)bestsp - (char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] < needbytes &&
+	    be16_to_cpu(leaf->hdr.stale) > 1) {
 		compact = 1;
 	}
 	/*
 	 * Otherwise if we don't have enough free bytes we need to
 	 * convert to node form.
 	 */
-	else if ((char *)bestsp - (char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] <
+	else if ((char *)bestsp - (char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] <
 		 needbytes) {
 		/*
 		 * Just checking or no space reservation, give up.
@@ -330,8 +330,8 @@
 	 * There are stale entries, so we'll need log-low and log-high
 	 * impossibly bad values later.
 	 */
-	else if (INT_GET(leaf->hdr.stale, ARCH_CONVERT)) {
-		lfloglow = INT_GET(leaf->hdr.count, ARCH_CONVERT);
+	else if (be16_to_cpu(leaf->hdr.stale)) {
+		lfloglow = be16_to_cpu(leaf->hdr.count);
 		lfloghigh = -1;
 	}
 	/*
@@ -358,13 +358,13 @@
 		 * If we're adding a new data block on the end we need to
 		 * extend the bests table.  Copy it up one entry.
 		 */
-		if (use_block >= INT_GET(ltp->bestcount, ARCH_CONVERT)) {
+		if (use_block >= be32_to_cpu(ltp->bestcount)) {
 			bestsp--;
 			memmove(&bestsp[0], &bestsp[1],
-				INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(bestsp[0]));
-			INT_MOD(ltp->bestcount, ARCH_CONVERT, +1);
+				be32_to_cpu(ltp->bestcount) * sizeof(bestsp[0]));
+			be32_add(&ltp->bestcount, 1);
 			xfs_dir2_leaf_log_tail(tp, lbp);
-			xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1);
+			xfs_dir2_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
 		}
 		/*
 		 * If we're filling in a previously empty block just log it.
@@ -372,7 +372,7 @@
 		else
 			xfs_dir2_leaf_log_bests(tp, lbp, use_block, use_block);
 		data = dbp->data;
-		INT_COPY(bestsp[use_block], data->hdr.bestfree[0].length, ARCH_CONVERT);
+		bestsp[use_block] = data->hdr.bestfree[0].length;
 		grown = 1;
 	}
 	/*
@@ -394,8 +394,8 @@
 	 * Point to the biggest freespace in our data block.
 	 */
 	dup = (xfs_dir2_data_unused_t *)
-	      ((char *)data + INT_GET(data->hdr.bestfree[0].offset, ARCH_CONVERT));
-	ASSERT(INT_GET(dup->length, ARCH_CONVERT) >= length);
+	      ((char *)data + be16_to_cpu(data->hdr.bestfree[0].offset));
+	ASSERT(be16_to_cpu(dup->length) >= length);
 	needscan = needlog = 0;
 	/*
 	 * Mark the initial part of our freespace in use for the new entry.
@@ -407,11 +407,11 @@
 	 * Initialize our new entry (at last).
 	 */
 	dep = (xfs_dir2_data_entry_t *)dup;
-	INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
+	dep->inumber = cpu_to_be64(args->inumber);
 	dep->namelen = args->namelen;
 	memcpy(dep->name, args->name, dep->namelen);
 	tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
-	INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)data));
+	*tagp = cpu_to_be16((char *)dep - (char *)data);
 	/*
 	 * Need to scan fix up the bestfree table.
 	 */
@@ -427,8 +427,8 @@
 	 * If the bests table needs to be changed, do it.
 	 * Log the change unless we've already done that.
 	 */
-	if (INT_GET(bestsp[use_block], ARCH_CONVERT) != INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT)) {
-		INT_COPY(bestsp[use_block], data->hdr.bestfree[0].length, ARCH_CONVERT);
+	if (be16_to_cpu(bestsp[use_block]) != be16_to_cpu(data->hdr.bestfree[0].length)) {
+		bestsp[use_block] = data->hdr.bestfree[0].length;
 		if (!grown)
 			xfs_dir2_leaf_log_bests(tp, lbp, use_block, use_block);
 	}
@@ -440,15 +440,15 @@
 		/*
 		 * lep is still good as the index leaf entry.
 		 */
-		if (index < INT_GET(leaf->hdr.count, ARCH_CONVERT))
+		if (index < be16_to_cpu(leaf->hdr.count))
 			memmove(lep + 1, lep,
-				(INT_GET(leaf->hdr.count, ARCH_CONVERT) - index) * sizeof(*lep));
+				(be16_to_cpu(leaf->hdr.count) - index) * sizeof(*lep));
 		/*
 		 * Record low and high logging indices for the leaf.
 		 */
 		lfloglow = index;
-		lfloghigh = INT_GET(leaf->hdr.count, ARCH_CONVERT);
-		INT_MOD(leaf->hdr.count, ARCH_CONVERT, +1);
+		lfloghigh = be16_to_cpu(leaf->hdr.count);
+		be16_add(&leaf->hdr.count, 1);
 	}
 	/*
 	 * There are stale entries.
@@ -468,7 +468,7 @@
 			 */
 			for (lowstale = index - 1;
 			     lowstale >= 0 &&
-				INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) !=
+				be32_to_cpu(leaf->ents[lowstale].address) !=
 				XFS_DIR2_NULL_DATAPTR;
 			     lowstale--)
 				continue;
@@ -478,8 +478,8 @@
 			 * lowstale entry would be better.
 			 */
 			for (highstale = index;
-			     highstale < INT_GET(leaf->hdr.count, ARCH_CONVERT) &&
-				INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) !=
+			     highstale < be16_to_cpu(leaf->hdr.count) &&
+				be32_to_cpu(leaf->ents[highstale].address) !=
 				XFS_DIR2_NULL_DATAPTR &&
 				(lowstale < 0 ||
 				 index - lowstale - 1 >= highstale - index);
@@ -490,10 +490,10 @@
 		 * If the low one is better, use it.
 		 */
 		if (lowstale >= 0 &&
-		    (highstale == INT_GET(leaf->hdr.count, ARCH_CONVERT) ||
+		    (highstale == be16_to_cpu(leaf->hdr.count) ||
 		     index - lowstale - 1 < highstale - index)) {
 			ASSERT(index - lowstale - 1 >= 0);
-			ASSERT(INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) ==
+			ASSERT(be32_to_cpu(leaf->ents[lowstale].address) ==
 			       XFS_DIR2_NULL_DATAPTR);
 			/*
 			 * Copy entries up to cover the stale entry
@@ -512,7 +512,7 @@
 		 */
 		else {
 			ASSERT(highstale - index >= 0);
-			ASSERT(INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) ==
+			ASSERT(be32_to_cpu(leaf->ents[highstale].address) ==
 			       XFS_DIR2_NULL_DATAPTR);
 			/*
 			 * Copy entries down to copver the stale entry
@@ -526,13 +526,14 @@
 			lfloglow = MIN(index, lfloglow);
 			lfloghigh = MAX(highstale, lfloghigh);
 		}
-		INT_MOD(leaf->hdr.stale, ARCH_CONVERT, -1);
+		be16_add(&leaf->hdr.stale, -1);
 	}
 	/*
 	 * Fill in the new leaf entry.
 	 */
-	INT_SET(lep->hashval, ARCH_CONVERT, args->hashval);
-	INT_SET(lep->address, ARCH_CONVERT, XFS_DIR2_DB_OFF_TO_DATAPTR(mp, use_block, INT_GET(*tagp, ARCH_CONVERT)));
+	lep->hashval = cpu_to_be32(args->hashval);
+	lep->address = cpu_to_be32(XFS_DIR2_DB_OFF_TO_DATAPTR(mp, use_block,
+				be16_to_cpu(*tagp)));
 	/*
 	 * Log the leaf fields and give up the buffers.
 	 */
@@ -563,30 +564,30 @@
 
 	leaf = bp->data;
 	mp = dp->i_mount;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC);
 	/*
 	 * This value is not restrictive enough.
 	 * Should factor in the size of the bests table as well.
 	 * We can deduce a value for that from di_size.
 	 */
-	ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) <= XFS_DIR2_MAX_LEAF_ENTS(mp));
+	ASSERT(be16_to_cpu(leaf->hdr.count) <= XFS_DIR2_MAX_LEAF_ENTS(mp));
 	ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
 	/*
 	 * Leaves and bests don't overlap.
 	 */
-	ASSERT((char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] <=
+	ASSERT((char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] <=
 	       (char *)XFS_DIR2_LEAF_BESTS_P(ltp));
 	/*
 	 * Check hash value order, count stale entries.
 	 */
-	for (i = stale = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); i++) {
-		if (i + 1 < INT_GET(leaf->hdr.count, ARCH_CONVERT))
-			ASSERT(INT_GET(leaf->ents[i].hashval, ARCH_CONVERT) <=
-			       INT_GET(leaf->ents[i + 1].hashval, ARCH_CONVERT));
-		if (INT_GET(leaf->ents[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR)
+	for (i = stale = 0; i < be16_to_cpu(leaf->hdr.count); i++) {
+		if (i + 1 < be16_to_cpu(leaf->hdr.count))
+			ASSERT(be32_to_cpu(leaf->ents[i].hashval) <=
+			       be32_to_cpu(leaf->ents[i + 1].hashval));
+		if (be32_to_cpu(leaf->ents[i].address) == XFS_DIR2_NULL_DATAPTR)
 			stale++;
 	}
-	ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) == stale);
+	ASSERT(be16_to_cpu(leaf->hdr.stale) == stale);
 }
 #endif	/* DEBUG */
 
@@ -611,8 +612,8 @@
 	/*
 	 * Compress out the stale entries in place.
 	 */
-	for (from = to = 0, loglow = -1; from < INT_GET(leaf->hdr.count, ARCH_CONVERT); from++) {
-		if (INT_GET(leaf->ents[from].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR)
+	for (from = to = 0, loglow = -1; from < be16_to_cpu(leaf->hdr.count); from++) {
+		if (be32_to_cpu(leaf->ents[from].address) == XFS_DIR2_NULL_DATAPTR)
 			continue;
 		/*
 		 * Only actually copy the entries that are different.
@@ -627,8 +628,8 @@
 	/*
 	 * Update and log the header, log the leaf entries.
 	 */
-	ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) == from - to);
-	INT_MOD(leaf->hdr.count, ARCH_CONVERT, -(INT_GET(leaf->hdr.stale, ARCH_CONVERT)));
+	ASSERT(be16_to_cpu(leaf->hdr.stale) == from - to);
+	be16_add(&leaf->hdr.count, -(be16_to_cpu(leaf->hdr.stale)));
 	leaf->hdr.stale = 0;
 	xfs_dir2_leaf_log_header(args->trans, bp);
 	if (loglow != -1)
@@ -662,14 +663,14 @@
 	int		to;		/* destination copy index */
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) > 1);
+	ASSERT(be16_to_cpu(leaf->hdr.stale) > 1);
 	index = *indexp;
 	/*
 	 * Find the first stale entry before our index, if any.
 	 */
 	for (lowstale = index - 1;
 	     lowstale >= 0 &&
-		INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR;
+		be32_to_cpu(leaf->ents[lowstale].address) != XFS_DIR2_NULL_DATAPTR;
 	     lowstale--)
 		continue;
 	/*
@@ -677,8 +678,8 @@
 	 * Stop if the answer would be worse than lowstale.
 	 */
 	for (highstale = index;
-	     highstale < INT_GET(leaf->hdr.count, ARCH_CONVERT) &&
-		INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR &&
+	     highstale < be16_to_cpu(leaf->hdr.count) &&
+		be32_to_cpu(leaf->ents[highstale].address) != XFS_DIR2_NULL_DATAPTR &&
 		(lowstale < 0 || index - lowstale > highstale - index);
 	     highstale++)
 		continue;
@@ -686,7 +687,7 @@
 	 * Pick the better of lowstale and highstale.
 	 */
 	if (lowstale >= 0 &&
-	    (highstale == INT_GET(leaf->hdr.count, ARCH_CONVERT) ||
+	    (highstale == be16_to_cpu(leaf->hdr.count) ||
 	     index - lowstale <= highstale - index))
 		keepstale = lowstale;
 	else
@@ -695,14 +696,14 @@
 	 * Copy the entries in place, removing all the stale entries
 	 * except keepstale.
 	 */
-	for (from = to = 0; from < INT_GET(leaf->hdr.count, ARCH_CONVERT); from++) {
+	for (from = to = 0; from < be16_to_cpu(leaf->hdr.count); from++) {
 		/*
 		 * Notice the new value of index.
 		 */
 		if (index == from)
 			newindex = to;
 		if (from != keepstale &&
-		    INT_GET(leaf->ents[from].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) {
+		    be32_to_cpu(leaf->ents[from].address) == XFS_DIR2_NULL_DATAPTR) {
 			if (from == to)
 				*lowlogp = to;
 			continue;
@@ -730,8 +731,8 @@
 	/*
 	 * Adjust the leaf header values.
 	 */
-	INT_MOD(leaf->hdr.count, ARCH_CONVERT, -(from - to));
-	INT_SET(leaf->hdr.stale, ARCH_CONVERT, 1);
+	be16_add(&leaf->hdr.count, -(from - to));
+	leaf->hdr.stale = cpu_to_be16(1);
 	/*
 	 * Remember the low/high stale value only in the "right"
 	 * direction.
@@ -739,8 +740,8 @@
 	if (lowstale >= newindex)
 		lowstale = -1;
 	else
-		highstale = INT_GET(leaf->hdr.count, ARCH_CONVERT);
-	*highlogp = INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1;
+		highstale = be16_to_cpu(leaf->hdr.count);
+	*highlogp = be16_to_cpu(leaf->hdr.count) - 1;
 	*lowstalep = lowstale;
 	*highstalep = highstale;
 }
@@ -1046,11 +1047,10 @@
 				while ((char *)ptr - (char *)data < byteoff) {
 					dup = (xfs_dir2_data_unused_t *)ptr;
 
-					if (INT_GET(dup->freetag, ARCH_CONVERT)
+					if (be16_to_cpu(dup->freetag)
 						  == XFS_DIR2_DATA_FREE_TAG) {
 
-						length = INT_GET(dup->length,
-								 ARCH_CONVERT);
+						length = be16_to_cpu(dup->length);
 						ptr += length;
 						continue;
 					}
@@ -1079,9 +1079,8 @@
 		/*
 		 * No, it's unused, skip over it.
 		 */
-		if (INT_GET(dup->freetag, ARCH_CONVERT)
-						== XFS_DIR2_DATA_FREE_TAG) {
-			length = INT_GET(dup->length, ARCH_CONVERT);
+		if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
+			length = be16_to_cpu(dup->length);
 			ptr += length;
 			curoff += length;
 			continue;
@@ -1098,7 +1097,7 @@
 
 		p.cook = XFS_DIR2_BYTE_TO_DATAPTR(mp, curoff + length);
 
-		p.ino = INT_GET(dep->inumber, ARCH_CONVERT);
+		p.ino = be64_to_cpu(dep->inumber);
 #if XFS_BIG_INUMS
 		p.ino += mp->m_inoadd;
 #endif
@@ -1171,7 +1170,7 @@
 	/*
 	 * Initialize the header.
 	 */
-	INT_SET(leaf->hdr.info.magic, ARCH_CONVERT, magic);
+	leaf->hdr.info.magic = cpu_to_be16(magic);
 	leaf->hdr.info.forw = 0;
 	leaf->hdr.info.back = 0;
 	leaf->hdr.count = 0;
@@ -1201,13 +1200,13 @@
 	int			first,		/* first entry to log */
 	int			last)		/* last entry to log */
 {
-	xfs_dir2_data_off_t	*firstb;	/* pointer to first entry */
-	xfs_dir2_data_off_t	*lastb;		/* pointer to last entry */
+	__be16			*firstb;	/* pointer to first entry */
+	__be16			*lastb;		/* pointer to last entry */
 	xfs_dir2_leaf_t		*leaf;		/* leaf structure */
 	xfs_dir2_leaf_tail_t	*ltp;		/* leaf tail structure */
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC);
 	ltp = XFS_DIR2_LEAF_TAIL_P(tp->t_mountp, leaf);
 	firstb = XFS_DIR2_LEAF_BESTS_P(ltp) + first;
 	lastb = XFS_DIR2_LEAF_BESTS_P(ltp) + last;
@@ -1230,8 +1229,8 @@
 	xfs_dir2_leaf_t		*leaf;		/* leaf structure */
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC ||
-	       INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC ||
+	       be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);
 	firstlep = &leaf->ents[first];
 	lastlep = &leaf->ents[last];
 	xfs_da_log_buf(tp, bp, (uint)((char *)firstlep - (char *)leaf),
@@ -1249,8 +1248,8 @@
 	xfs_dir2_leaf_t		*leaf;		/* leaf structure */
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC ||
-	       INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC ||
+	       be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);
 	xfs_da_log_buf(tp, bp, (uint)((char *)&leaf->hdr - (char *)leaf),
 		(uint)(sizeof(leaf->hdr) - 1));
 }
@@ -1269,7 +1268,7 @@
 
 	mp = tp->t_mountp;
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC);
 	ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
 	xfs_da_log_buf(tp, bp, (uint)((char *)ltp - (char *)leaf),
 		(uint)(mp->m_dirblksize - 1));
@@ -1314,11 +1313,11 @@
 	 */
 	dep = (xfs_dir2_data_entry_t *)
 	      ((char *)dbp->data +
-	       XFS_DIR2_DATAPTR_TO_OFF(dp->i_mount, INT_GET(lep->address, ARCH_CONVERT)));
+	       XFS_DIR2_DATAPTR_TO_OFF(dp->i_mount, be32_to_cpu(lep->address)));
 	/*
 	 * Return the found inode number.
 	 */
-	args->inumber = INT_GET(dep->inumber, ARCH_CONVERT);
+	args->inumber = be64_to_cpu(dep->inumber);
 	xfs_da_brelse(tp, dbp);
 	xfs_da_brelse(tp, lbp);
 	return XFS_ERROR(EEXIST);
@@ -1373,17 +1372,17 @@
 	 * looking to match the name.
 	 */
 	for (lep = &leaf->ents[index], dbp = NULL, curdb = -1;
-	     index < INT_GET(leaf->hdr.count, ARCH_CONVERT) && INT_GET(lep->hashval, ARCH_CONVERT) == args->hashval;
+	     index < be16_to_cpu(leaf->hdr.count) && be32_to_cpu(lep->hashval) == args->hashval;
 	     lep++, index++) {
 		/*
 		 * Skip over stale leaf entries.
 		 */
-		if (INT_GET(lep->address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR)
+		if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
 			continue;
 		/*
 		 * Get the new data block number.
 		 */
-		newdb = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT));
+		newdb = XFS_DIR2_DATAPTR_TO_DB(mp, be32_to_cpu(lep->address));
 		/*
 		 * If it's not the same as the old data block number,
 		 * need to pitch the old one and read the new one.
@@ -1406,7 +1405,7 @@
 		 */
 		dep = (xfs_dir2_data_entry_t *)
 		      ((char *)dbp->data +
-		       XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(lep->address, ARCH_CONVERT)));
+		       XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(lep->address)));
 		/*
 		 * If it matches then return it.
 		 */
@@ -1435,7 +1434,7 @@
 xfs_dir2_leaf_removename(
 	xfs_da_args_t		*args)		/* operation arguments */
 {
-	xfs_dir2_data_off_t	*bestsp;	/* leaf block best freespace */
+	__be16			*bestsp;	/* leaf block best freespace */
 	xfs_dir2_data_t		*data;		/* data block structure */
 	xfs_dir2_db_t		db;		/* data block number */
 	xfs_dabuf_t		*dbp;		/* data block buffer */
@@ -1471,14 +1470,14 @@
 	 * Point to the leaf entry, use that to point to the data entry.
 	 */
 	lep = &leaf->ents[index];
-	db = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT));
+	db = XFS_DIR2_DATAPTR_TO_DB(mp, be32_to_cpu(lep->address));
 	dep = (xfs_dir2_data_entry_t *)
-	      ((char *)data + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(lep->address, ARCH_CONVERT)));
+	      ((char *)data + XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(lep->address)));
 	needscan = needlog = 0;
-	oldbest = INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT);
+	oldbest = be16_to_cpu(data->hdr.bestfree[0].length);
 	ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
 	bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
-	ASSERT(INT_GET(bestsp[db], ARCH_CONVERT) == oldbest);
+	ASSERT(be16_to_cpu(bestsp[db]) == oldbest);
 	/*
 	 * Mark the former data entry unused.
 	 */
@@ -1488,9 +1487,9 @@
 	/*
 	 * We just mark the leaf entry stale by putting a null in it.
 	 */
-	INT_MOD(leaf->hdr.stale, ARCH_CONVERT, +1);
+	be16_add(&leaf->hdr.stale, 1);
 	xfs_dir2_leaf_log_header(tp, lbp);
-	INT_SET(lep->address, ARCH_CONVERT, XFS_DIR2_NULL_DATAPTR);
+	lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR);
 	xfs_dir2_leaf_log_ents(tp, lbp, index, index);
 	/*
 	 * Scan the freespace in the data block again if necessary,
@@ -1504,15 +1503,15 @@
 	 * If the longest freespace in the data block has changed,
 	 * put the new value in the bests table and log that.
 	 */
-	if (INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT) != oldbest) {
-		INT_COPY(bestsp[db], data->hdr.bestfree[0].length, ARCH_CONVERT);
+	if (be16_to_cpu(data->hdr.bestfree[0].length) != oldbest) {
+		bestsp[db] = data->hdr.bestfree[0].length;
 		xfs_dir2_leaf_log_bests(tp, lbp, db, db);
 	}
 	xfs_dir2_data_check(dp, dbp);
 	/*
 	 * If the data block is now empty then get rid of the data block.
 	 */
-	if (INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT) ==
+	if (be16_to_cpu(data->hdr.bestfree[0].length) ==
 	    mp->m_dirblksize - (uint)sizeof(data->hdr)) {
 		ASSERT(db != mp->m_dirdatablk);
 		if ((error = xfs_dir2_shrink_inode(args, db, dbp))) {
@@ -1535,12 +1534,12 @@
 		 * If this is the last data block then compact the
 		 * bests table by getting rid of entries.
 		 */
-		if (db == INT_GET(ltp->bestcount, ARCH_CONVERT) - 1) {
+		if (db == be32_to_cpu(ltp->bestcount) - 1) {
 			/*
 			 * Look for the last active entry (i).
 			 */
 			for (i = db - 1; i > 0; i--) {
-				if (INT_GET(bestsp[i], ARCH_CONVERT) != NULLDATAOFF)
+				if (be16_to_cpu(bestsp[i]) != NULLDATAOFF)
 					break;
 			}
 			/*
@@ -1548,12 +1547,12 @@
 			 * end are removed.
 			 */
 			memmove(&bestsp[db - i], bestsp,
-				(INT_GET(ltp->bestcount, ARCH_CONVERT) - (db - i)) * sizeof(*bestsp));
-			INT_MOD(ltp->bestcount, ARCH_CONVERT, -(db - i));
+				(be32_to_cpu(ltp->bestcount) - (db - i)) * sizeof(*bestsp));
+			be32_add(&ltp->bestcount, -(db - i));
 			xfs_dir2_leaf_log_tail(tp, lbp);
-			xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1);
+			xfs_dir2_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
 		} else
-			INT_SET(bestsp[db], ARCH_CONVERT, NULLDATAOFF);
+			bestsp[db] = cpu_to_be16(NULLDATAOFF);
 	}
 	/*
 	 * If the data block was not the first one, drop it.
@@ -1604,12 +1603,12 @@
 	 */
 	dep = (xfs_dir2_data_entry_t *)
 	      ((char *)dbp->data +
-	       XFS_DIR2_DATAPTR_TO_OFF(dp->i_mount, INT_GET(lep->address, ARCH_CONVERT)));
-	ASSERT(args->inumber != INT_GET(dep->inumber, ARCH_CONVERT));
+	       XFS_DIR2_DATAPTR_TO_OFF(dp->i_mount, be32_to_cpu(lep->address)));
+	ASSERT(args->inumber != be64_to_cpu(dep->inumber));
 	/*
 	 * Put the new inode number in, log it.
 	 */
-	INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
+	dep->inumber = cpu_to_be64(args->inumber);
 	tp = args->trans;
 	xfs_dir2_data_log_entry(tp, dbp, dep);
 	xfs_da_buf_done(dbp);
@@ -1645,11 +1644,11 @@
 	 * Note, the table cannot be empty, so we have to go through the loop.
 	 * Binary search the leaf entries looking for our hash value.
 	 */
-	for (lep = leaf->ents, low = 0, high = INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1,
+	for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) - 1,
 		hashwant = args->hashval;
 	     low <= high; ) {
 		mid = (low + high) >> 1;
-		if ((hash = INT_GET(lep[mid].hashval, ARCH_CONVERT)) == hashwant)
+		if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant)
 			break;
 		if (hash < hashwant)
 			low = mid + 1;
@@ -1660,7 +1659,7 @@
 	 * Found one, back up through all the equal hash values.
 	 */
 	if (hash == hashwant) {
-		while (mid > 0 && INT_GET(lep[mid - 1].hashval, ARCH_CONVERT) == hashwant) {
+		while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant) {
 			mid--;
 		}
 	}
@@ -1682,7 +1681,7 @@
 	xfs_dabuf_t		*lbp,		/* leaf buffer */
 	xfs_dir2_db_t		db)		/* data block number */
 {
-	xfs_dir2_data_off_t	*bestsp;	/* leaf bests table */
+	__be16			*bestsp;	/* leaf bests table */
 #ifdef DEBUG
 	xfs_dir2_data_t		*data;		/* data block structure */
 #endif
@@ -1706,7 +1705,7 @@
 	}
 #ifdef DEBUG
 	data = dbp->data;
-	ASSERT(INT_GET(data->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC);
+	ASSERT(be32_to_cpu(data->hdr.magic) == XFS_DIR2_DATA_MAGIC);
 #endif
 	/* this seems to be an error
 	 * data is only valid if DEBUG is defined?
@@ -1715,9 +1714,9 @@
 
 	leaf = lbp->data;
 	ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
-	ASSERT(INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT) ==
+	ASSERT(be16_to_cpu(data->hdr.bestfree[0].length) ==
 	       mp->m_dirblksize - (uint)sizeof(data->hdr));
-	ASSERT(db == INT_GET(ltp->bestcount, ARCH_CONVERT) - 1);
+	ASSERT(db == be32_to_cpu(ltp->bestcount) - 1);
 	/*
 	 * Get rid of the data block.
 	 */
@@ -1730,10 +1729,10 @@
 	 * Eliminate the last bests entry from the table.
 	 */
 	bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
-	INT_MOD(ltp->bestcount, ARCH_CONVERT, -1);
-	memmove(&bestsp[1], &bestsp[0], INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(*bestsp));
+	be32_add(&ltp->bestcount, -1);
+	memmove(&bestsp[1], &bestsp[0], be32_to_cpu(ltp->bestcount) * sizeof(*bestsp));
 	xfs_dir2_leaf_log_tail(tp, lbp);
-	xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1);
+	xfs_dir2_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
 	return 0;
 }
 
@@ -1805,7 +1804,7 @@
 		return 0;
 	lbp = state->path.blk[0].bp;
 	leaf = lbp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);
 	/*
 	 * Read the freespace block.
 	 */
@@ -1814,15 +1813,15 @@
 		return error;
 	}
 	free = fbp->data;
-	ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC);
+	ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);
 	ASSERT(!free->hdr.firstdb);
 	/*
 	 * Now see if the leafn and free data will fit in a leaf1.
 	 * If not, release the buffer and give up.
 	 */
 	if ((uint)sizeof(leaf->hdr) +
-	    (INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT)) * (uint)sizeof(leaf->ents[0]) +
-	    INT_GET(free->hdr.nvalid, ARCH_CONVERT) * (uint)sizeof(leaf->bests[0]) +
+	    (be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale)) * (uint)sizeof(leaf->ents[0]) +
+	    be32_to_cpu(free->hdr.nvalid) * (uint)sizeof(leaf->bests[0]) +
 	    (uint)sizeof(leaf->tail) >
 	    mp->m_dirblksize) {
 		xfs_da_brelse(tp, fbp);
@@ -1832,22 +1831,22 @@
 	 * If the leaf has any stale entries in it, compress them out.
 	 * The compact routine will log the header.
 	 */
-	if (INT_GET(leaf->hdr.stale, ARCH_CONVERT))
+	if (be16_to_cpu(leaf->hdr.stale))
 		xfs_dir2_leaf_compact(args, lbp);
 	else
 		xfs_dir2_leaf_log_header(tp, lbp);
-	INT_SET(leaf->hdr.info.magic, ARCH_CONVERT, XFS_DIR2_LEAF1_MAGIC);
+	leaf->hdr.info.magic = cpu_to_be16(XFS_DIR2_LEAF1_MAGIC);
 	/*
 	 * Set up the leaf tail from the freespace block.
 	 */
 	ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
-	INT_COPY(ltp->bestcount, free->hdr.nvalid, ARCH_CONVERT);
+	ltp->bestcount = free->hdr.nvalid;
 	/*
 	 * Set up the leaf bests table.
 	 */
 	memcpy(XFS_DIR2_LEAF_BESTS_P(ltp), free->bests,
-		INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(leaf->bests[0]));
-	xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1);
+		be32_to_cpu(ltp->bestcount) * sizeof(leaf->bests[0]));
+	xfs_dir2_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
 	xfs_dir2_leaf_log_tail(tp, lbp);
 	xfs_dir2_leaf_check(dp, lbp);
 	/*
diff -urN oldtree/fs/xfs/xfs_dir2_leaf.h newtree/fs/xfs/xfs_dir2_leaf.h
--- oldtree/fs/xfs/xfs_dir2_leaf.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/xfs/xfs_dir2_leaf.h	2006-02-21 15:58:36.730562664 +0000
@@ -46,23 +46,23 @@
  */
 typedef struct xfs_dir2_leaf_hdr {
 	xfs_da_blkinfo_t	info;		/* header for da routines */
-	__uint16_t		count;		/* count of entries */
-	__uint16_t		stale;		/* count of stale entries */
+	__be16			count;		/* count of entries */
+	__be16			stale;		/* count of stale entries */
 } xfs_dir2_leaf_hdr_t;
 
 /*
  * Leaf block entry.
  */
 typedef struct xfs_dir2_leaf_entry {
-	xfs_dahash_t		hashval;	/* hash value of name */
-	xfs_dir2_dataptr_t	address;	/* address of data entry */
+	__be32			hashval;	/* hash value of name */
+	__be32			address;	/* address of data entry */
 } xfs_dir2_leaf_entry_t;
 
 /*
  * Leaf block tail.
  */
 typedef struct xfs_dir2_leaf_tail {
-	__uint32_t		bestcount;
+	__be32			bestcount;
 } xfs_dir2_leaf_tail_t;
 
 /*
@@ -105,11 +105,10 @@
  * Get address of the bests array in the single-leaf block.
  */
 #define	XFS_DIR2_LEAF_BESTS_P(ltp)	xfs_dir2_leaf_bests_p(ltp)
-static inline xfs_dir2_data_off_t *
+static inline __be16 *
 xfs_dir2_leaf_bests_p(xfs_dir2_leaf_tail_t *ltp)
 {
-	return (xfs_dir2_data_off_t *)
-		(ltp) - INT_GET((ltp)->bestcount, ARCH_CONVERT);
+	return (__be16 *)ltp - be32_to_cpu(ltp->bestcount);
 }
 
 /*
diff -urN oldtree/fs/xfs/xfs_dir2_node.c newtree/fs/xfs/xfs_dir2_node.c
--- oldtree/fs/xfs/xfs_dir2_node.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/xfs/xfs_dir2_node.c	2006-02-21 15:58:36.733562208 +0000
@@ -76,7 +76,7 @@
 	xfs_dir2_free_t		*free;		/* freespace structure */
 
 	free = bp->data;
-	ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC);
+	ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);
 	xfs_da_log_buf(tp, bp,
 		(uint)((char *)&free->bests[first] - (char *)free),
 		(uint)((char *)&free->bests[last] - (char *)free +
@@ -94,7 +94,7 @@
 	xfs_dir2_free_t		*free;		/* freespace structure */
 
 	free = bp->data;
-	ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC);
+	ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);
 	xfs_da_log_buf(tp, bp, (uint)((char *)&free->hdr - (char *)free),
 		(uint)(sizeof(xfs_dir2_free_hdr_t) - 1));
 }
@@ -114,14 +114,14 @@
 	xfs_dabuf_t		*fbp;		/* freespace buffer */
 	xfs_dir2_db_t		fdb;		/* freespace block number */
 	xfs_dir2_free_t		*free;		/* freespace structure */
-	xfs_dir2_data_off_t	*from;		/* pointer to freespace entry */
+	__be16			*from;		/* pointer to freespace entry */
 	int			i;		/* leaf freespace index */
 	xfs_dir2_leaf_t		*leaf;		/* leaf structure */
 	xfs_dir2_leaf_tail_t	*ltp;		/* leaf tail structure */
 	xfs_mount_t		*mp;		/* filesystem mount point */
 	int			n;		/* count of live freespc ents */
 	xfs_dir2_data_off_t	off;		/* freespace entry value */
-	xfs_dir2_data_off_t	*to;		/* pointer to freespace entry */
+	__be16			*to;		/* pointer to freespace entry */
 	xfs_trans_t		*tp;		/* transaction pointer */
 
 	xfs_dir2_trace_args_b("leaf_to_node", args, lbp);
@@ -149,28 +149,28 @@
 	/*
 	 * Initialize the freespace block header.
 	 */
-	INT_SET(free->hdr.magic, ARCH_CONVERT, XFS_DIR2_FREE_MAGIC);
+	free->hdr.magic = cpu_to_be32(XFS_DIR2_FREE_MAGIC);
 	free->hdr.firstdb = 0;
-	ASSERT(INT_GET(ltp->bestcount, ARCH_CONVERT) <= (uint)dp->i_d.di_size / mp->m_dirblksize);
-	INT_COPY(free->hdr.nvalid, ltp->bestcount, ARCH_CONVERT);
+	ASSERT(be32_to_cpu(ltp->bestcount) <= (uint)dp->i_d.di_size / mp->m_dirblksize);
+	free->hdr.nvalid = ltp->bestcount;
 	/*
 	 * Copy freespace entries from the leaf block to the new block.
 	 * Count active entries.
 	 */
 	for (i = n = 0, from = XFS_DIR2_LEAF_BESTS_P(ltp), to = free->bests;
-	     i < INT_GET(ltp->bestcount, ARCH_CONVERT); i++, from++, to++) {
-		if ((off = INT_GET(*from, ARCH_CONVERT)) != NULLDATAOFF)
+	     i < be32_to_cpu(ltp->bestcount); i++, from++, to++) {
+		if ((off = be16_to_cpu(*from)) != NULLDATAOFF)
 			n++;
-		INT_SET(*to, ARCH_CONVERT, off);
+		*to = cpu_to_be16(off);
 	}
-	INT_SET(free->hdr.nused, ARCH_CONVERT, n);
-	INT_SET(leaf->hdr.info.magic, ARCH_CONVERT, XFS_DIR2_LEAFN_MAGIC);
+	free->hdr.nused = cpu_to_be32(n);
+	leaf->hdr.info.magic = cpu_to_be16(XFS_DIR2_LEAFN_MAGIC);
 	/*
 	 * Log everything.
 	 */
 	xfs_dir2_leaf_log_header(tp, lbp);
 	xfs_dir2_free_log_header(tp, fbp);
-	xfs_dir2_free_log_bests(tp, fbp, 0, INT_GET(free->hdr.nvalid, ARCH_CONVERT) - 1);
+	xfs_dir2_free_log_bests(tp, fbp, 0, be32_to_cpu(free->hdr.nvalid) - 1);
 	xfs_da_buf_done(fbp);
 	xfs_dir2_leafn_check(dp, lbp);
 	return 0;
@@ -217,15 +217,15 @@
 	 * a compact.
 	 */
 
-	if (INT_GET(leaf->hdr.count, ARCH_CONVERT) == XFS_DIR2_MAX_LEAF_ENTS(mp)) {
+	if (be16_to_cpu(leaf->hdr.count) == XFS_DIR2_MAX_LEAF_ENTS(mp)) {
 		if (!leaf->hdr.stale)
 			return XFS_ERROR(ENOSPC);
-		compact = INT_GET(leaf->hdr.stale, ARCH_CONVERT) > 1;
+		compact = be16_to_cpu(leaf->hdr.stale) > 1;
 	} else
 		compact = 0;
-	ASSERT(index == 0 || INT_GET(leaf->ents[index - 1].hashval, ARCH_CONVERT) <= args->hashval);
-	ASSERT(index == INT_GET(leaf->hdr.count, ARCH_CONVERT) ||
-	       INT_GET(leaf->ents[index].hashval, ARCH_CONVERT) >= args->hashval);
+	ASSERT(index == 0 || be32_to_cpu(leaf->ents[index - 1].hashval) <= args->hashval);
+	ASSERT(index == be16_to_cpu(leaf->hdr.count) ||
+	       be32_to_cpu(leaf->ents[index].hashval) >= args->hashval);
 
 	if (args->justcheck)
 		return 0;
@@ -242,7 +242,7 @@
 	 * Set impossible logging indices for this case.
 	 */
 	else if (leaf->hdr.stale) {
-		lfloglow = INT_GET(leaf->hdr.count, ARCH_CONVERT);
+		lfloglow = be16_to_cpu(leaf->hdr.count);
 		lfloghigh = -1;
 	}
 	/*
@@ -250,12 +250,12 @@
 	 */
 	if (!leaf->hdr.stale) {
 		lep = &leaf->ents[index];
-		if (index < INT_GET(leaf->hdr.count, ARCH_CONVERT))
+		if (index < be16_to_cpu(leaf->hdr.count))
 			memmove(lep + 1, lep,
-				(INT_GET(leaf->hdr.count, ARCH_CONVERT) - index) * sizeof(*lep));
+				(be16_to_cpu(leaf->hdr.count) - index) * sizeof(*lep));
 		lfloglow = index;
-		lfloghigh = INT_GET(leaf->hdr.count, ARCH_CONVERT);
-		INT_MOD(leaf->hdr.count, ARCH_CONVERT, +1);
+		lfloghigh = be16_to_cpu(leaf->hdr.count);
+		be16_add(&leaf->hdr.count, 1);
 	}
 	/*
 	 * There are stale entries.  We'll use one for the new entry.
@@ -271,7 +271,7 @@
 			 */
 			for (lowstale = index - 1;
 			     lowstale >= 0 &&
-				INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) !=
+				be32_to_cpu(leaf->ents[lowstale].address) !=
 				XFS_DIR2_NULL_DATAPTR;
 			     lowstale--)
 				continue;
@@ -281,8 +281,8 @@
 			 * lowstale already found.
 			 */
 			for (highstale = index;
-			     highstale < INT_GET(leaf->hdr.count, ARCH_CONVERT) &&
-				INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) !=
+			     highstale < be16_to_cpu(leaf->hdr.count) &&
+				be32_to_cpu(leaf->ents[highstale].address) !=
 				XFS_DIR2_NULL_DATAPTR &&
 				(lowstale < 0 ||
 				 index - lowstale - 1 >= highstale - index);
@@ -294,9 +294,9 @@
 		 * Shift entries up toward the stale slot.
 		 */
 		if (lowstale >= 0 &&
-		    (highstale == INT_GET(leaf->hdr.count, ARCH_CONVERT) ||
+		    (highstale == be16_to_cpu(leaf->hdr.count) ||
 		     index - lowstale - 1 < highstale - index)) {
-			ASSERT(INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) ==
+			ASSERT(be32_to_cpu(leaf->ents[lowstale].address) ==
 			       XFS_DIR2_NULL_DATAPTR);
 			ASSERT(index - lowstale - 1 >= 0);
 			if (index - lowstale - 1 > 0)
@@ -312,7 +312,7 @@
 		 * Shift entries down toward the stale slot.
 		 */
 		else {
-			ASSERT(INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) ==
+			ASSERT(be32_to_cpu(leaf->ents[highstale].address) ==
 			       XFS_DIR2_NULL_DATAPTR);
 			ASSERT(highstale - index >= 0);
 			if (highstale - index > 0)
@@ -323,13 +323,14 @@
 			lfloglow = MIN(index, lfloglow);
 			lfloghigh = MAX(highstale, lfloghigh);
 		}
-		INT_MOD(leaf->hdr.stale, ARCH_CONVERT, -1);
+		be16_add(&leaf->hdr.stale, -1);
 	}
 	/*
 	 * Insert the new entry, log everything.
 	 */
-	INT_SET(lep->hashval, ARCH_CONVERT, args->hashval);
-	INT_SET(lep->address, ARCH_CONVERT, XFS_DIR2_DB_OFF_TO_DATAPTR(mp, args->blkno, args->index));
+	lep->hashval = cpu_to_be32(args->hashval);
+	lep->address = cpu_to_be32(XFS_DIR2_DB_OFF_TO_DATAPTR(mp,
+				args->blkno, args->index));
 	xfs_dir2_leaf_log_header(tp, bp);
 	xfs_dir2_leaf_log_ents(tp, bp, lfloglow, lfloghigh);
 	xfs_dir2_leafn_check(dp, bp);
@@ -352,17 +353,17 @@
 
 	leaf = bp->data;
 	mp = dp->i_mount;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC);
-	ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) <= XFS_DIR2_MAX_LEAF_ENTS(mp));
-	for (i = stale = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); i++) {
-		if (i + 1 < INT_GET(leaf->hdr.count, ARCH_CONVERT)) {
-			ASSERT(INT_GET(leaf->ents[i].hashval, ARCH_CONVERT) <=
-			       INT_GET(leaf->ents[i + 1].hashval, ARCH_CONVERT));
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.count) <= XFS_DIR2_MAX_LEAF_ENTS(mp));
+	for (i = stale = 0; i < be16_to_cpu(leaf->hdr.count); i++) {
+		if (i + 1 < be16_to_cpu(leaf->hdr.count)) {
+			ASSERT(be32_to_cpu(leaf->ents[i].hashval) <=
+			       be32_to_cpu(leaf->ents[i + 1].hashval));
 		}
-		if (INT_GET(leaf->ents[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR)
+		if (be32_to_cpu(leaf->ents[i].address) == XFS_DIR2_NULL_DATAPTR)
 			stale++;
 	}
-	ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) == stale);
+	ASSERT(be16_to_cpu(leaf->hdr.stale) == stale);
 }
 #endif	/* DEBUG */
 
@@ -378,12 +379,12 @@
 	xfs_dir2_leaf_t	*leaf;			/* leaf structure */
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);
 	if (count)
-		*count = INT_GET(leaf->hdr.count, ARCH_CONVERT);
+		*count = be16_to_cpu(leaf->hdr.count);
 	if (!leaf->hdr.count)
 		return 0;
-	return INT_GET(leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT);
+	return be32_to_cpu(leaf->ents[be16_to_cpu(leaf->hdr.count) - 1].hashval);
 }
 
 /*
@@ -419,9 +420,9 @@
 	tp = args->trans;
 	mp = dp->i_mount;
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);
 #ifdef __KERNEL__
-	ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) > 0);
+	ASSERT(be16_to_cpu(leaf->hdr.count) > 0);
 #endif
 	xfs_dir2_leafn_check(dp, bp);
 	/*
@@ -443,7 +444,7 @@
 		curdb = -1;
 		length = XFS_DIR2_DATA_ENTSIZE(args->namelen);
 		if ((free = (curbp ? curbp->data : NULL)))
-			ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC);
+			ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);
 	}
 	/*
 	 * For others, it's a data block buffer, get the block number.
@@ -456,17 +457,17 @@
 	 * Loop over leaf entries with the right hash value.
 	 */
 	for (lep = &leaf->ents[index];
-	     index < INT_GET(leaf->hdr.count, ARCH_CONVERT) && INT_GET(lep->hashval, ARCH_CONVERT) == args->hashval;
+	     index < be16_to_cpu(leaf->hdr.count) && be32_to_cpu(lep->hashval) == args->hashval;
 	     lep++, index++) {
 		/*
 		 * Skip stale leaf entries.
 		 */
-		if (INT_GET(lep->address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR)
+		if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
 			continue;
 		/*
 		 * Pull the data block number from the entry.
 		 */
-		newdb = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT));
+		newdb = XFS_DIR2_DATAPTR_TO_DB(mp, be32_to_cpu(lep->address));
 		/*
 		 * For addname, we're looking for a place to put the new entry.
 		 * We want to use a data block with an entry of equal
@@ -506,15 +507,15 @@
 					}
 					curfdb = newfdb;
 					free = curbp->data;
-					ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) ==
+					ASSERT(be32_to_cpu(free->hdr.magic) ==
 					       XFS_DIR2_FREE_MAGIC);
-					ASSERT((INT_GET(free->hdr.firstdb, ARCH_CONVERT) %
+					ASSERT((be32_to_cpu(free->hdr.firstdb) %
 						XFS_DIR2_MAX_FREE_BESTS(mp)) ==
 					       0);
-					ASSERT(INT_GET(free->hdr.firstdb, ARCH_CONVERT) <= curdb);
+					ASSERT(be32_to_cpu(free->hdr.firstdb) <= curdb);
 					ASSERT(curdb <
-					       INT_GET(free->hdr.firstdb, ARCH_CONVERT) +
-					       INT_GET(free->hdr.nvalid, ARCH_CONVERT));
+					       be32_to_cpu(free->hdr.firstdb) +
+					       be32_to_cpu(free->hdr.nvalid));
 				}
 				/*
 				 * Get the index for our entry.
@@ -523,12 +524,12 @@
 				/*
 				 * If it has room, return it.
 				 */
-				if (unlikely(INT_GET(free->bests[fi], ARCH_CONVERT) == NULLDATAOFF)) {
+				if (unlikely(be16_to_cpu(free->bests[fi]) == NULLDATAOFF)) {
 					XFS_ERROR_REPORT("xfs_dir2_leafn_lookup_int",
 							 XFS_ERRLEVEL_LOW, mp);
 					return XFS_ERROR(EFSCORRUPTED);
 				}
-				if (INT_GET(free->bests[fi], ARCH_CONVERT) >= length) {
+				if (be16_to_cpu(free->bests[fi]) >= length) {
 					*indexp = index;
 					state->extravalid = 1;
 					state->extrablk.bp = curbp;
@@ -572,14 +573,14 @@
 			 */
 			dep = (xfs_dir2_data_entry_t *)
 			      ((char *)curbp->data +
-			       XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(lep->address, ARCH_CONVERT)));
+			       XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(lep->address)));
 			/*
 			 * Compare the entry, return it if it matches.
 			 */
 			if (dep->namelen == args->namelen &&
 			    dep->name[0] == args->name[0] &&
 			    memcmp(dep->name, args->name, args->namelen) == 0) {
-				args->inumber = INT_GET(dep->inumber, ARCH_CONVERT);
+				args->inumber = be64_to_cpu(dep->inumber);
 				*indexp = index;
 				state->extravalid = 1;
 				state->extrablk.bp = curbp;
@@ -619,7 +620,7 @@
 	 * Return the final index, that will be the insertion point.
 	 */
 	*indexp = index;
-	ASSERT(index == INT_GET(leaf->hdr.count, ARCH_CONVERT) || args->oknoent);
+	ASSERT(index == be16_to_cpu(leaf->hdr.count) || args->oknoent);
 	return XFS_ERROR(ENOENT);
 }
 
@@ -657,12 +658,12 @@
 	 * destination leaf entries, open up a hole in the destination
 	 * to hold the new entries.
 	 */
-	if (start_d < INT_GET(leaf_d->hdr.count, ARCH_CONVERT)) {
+	if (start_d < be16_to_cpu(leaf_d->hdr.count)) {
 		memmove(&leaf_d->ents[start_d + count], &leaf_d->ents[start_d],
-			(INT_GET(leaf_d->hdr.count, ARCH_CONVERT) - start_d) *
+			(be16_to_cpu(leaf_d->hdr.count) - start_d) *
 			sizeof(xfs_dir2_leaf_entry_t));
 		xfs_dir2_leaf_log_ents(tp, bp_d, start_d + count,
-			count + INT_GET(leaf_d->hdr.count, ARCH_CONVERT) - 1);
+			count + be16_to_cpu(leaf_d->hdr.count) - 1);
 	}
 	/*
 	 * If the source has stale leaves, count the ones in the copy range
@@ -672,7 +673,7 @@
 		int	i;			/* temp leaf index */
 
 		for (i = start_s, stale = 0; i < start_s + count; i++) {
-			if (INT_GET(leaf_s->ents[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR)
+			if (be32_to_cpu(leaf_s->ents[i].address) == XFS_DIR2_NULL_DATAPTR)
 				stale++;
 		}
 	} else
@@ -687,7 +688,7 @@
 	 * If there are source entries after the ones we copied,
 	 * delete the ones we copied by sliding the next ones down.
 	 */
-	if (start_s + count < INT_GET(leaf_s->hdr.count, ARCH_CONVERT)) {
+	if (start_s + count < be16_to_cpu(leaf_s->hdr.count)) {
 		memmove(&leaf_s->ents[start_s], &leaf_s->ents[start_s + count],
 			count * sizeof(xfs_dir2_leaf_entry_t));
 		xfs_dir2_leaf_log_ents(tp, bp_s, start_s, start_s + count - 1);
@@ -695,10 +696,10 @@
 	/*
 	 * Update the headers and log them.
 	 */
-	INT_MOD(leaf_s->hdr.count, ARCH_CONVERT, -(count));
-	INT_MOD(leaf_s->hdr.stale, ARCH_CONVERT, -(stale));
-	INT_MOD(leaf_d->hdr.count, ARCH_CONVERT, count);
-	INT_MOD(leaf_d->hdr.stale, ARCH_CONVERT, stale);
+	be16_add(&leaf_s->hdr.count, -(count));
+	be16_add(&leaf_s->hdr.stale, -(stale));
+	be16_add(&leaf_d->hdr.count, count);
+	be16_add(&leaf_d->hdr.stale, stale);
 	xfs_dir2_leaf_log_header(tp, bp_s);
 	xfs_dir2_leaf_log_header(tp, bp_d);
 	xfs_dir2_leafn_check(args->dp, bp_s);
@@ -719,13 +720,13 @@
 
 	leaf1 = leaf1_bp->data;
 	leaf2 = leaf2_bp->data;
-	ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC);
-	ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC);
-	if (INT_GET(leaf1->hdr.count, ARCH_CONVERT) > 0 &&
-	    INT_GET(leaf2->hdr.count, ARCH_CONVERT) > 0 &&
-	    (INT_GET(leaf2->ents[0].hashval, ARCH_CONVERT) < INT_GET(leaf1->ents[0].hashval, ARCH_CONVERT) ||
-	     INT_GET(leaf2->ents[INT_GET(leaf2->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT) <
-	     INT_GET(leaf1->ents[INT_GET(leaf1->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT)))
+	ASSERT(be16_to_cpu(leaf1->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);
+	ASSERT(be16_to_cpu(leaf2->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);
+	if (be16_to_cpu(leaf1->hdr.count) > 0 &&
+	    be16_to_cpu(leaf2->hdr.count) > 0 &&
+	    (be32_to_cpu(leaf2->ents[0].hashval) < be32_to_cpu(leaf1->ents[0].hashval) ||
+	     be32_to_cpu(leaf2->ents[be16_to_cpu(leaf2->hdr.count) - 1].hashval) <
+	     be32_to_cpu(leaf1->ents[be16_to_cpu(leaf1->hdr.count) - 1].hashval)))
 		return 1;
 	return 0;
 }
@@ -768,9 +769,9 @@
 	}
 	leaf1 = blk1->bp->data;
 	leaf2 = blk2->bp->data;
-	oldsum = INT_GET(leaf1->hdr.count, ARCH_CONVERT) + INT_GET(leaf2->hdr.count, ARCH_CONVERT);
+	oldsum = be16_to_cpu(leaf1->hdr.count) + be16_to_cpu(leaf2->hdr.count);
 #ifdef DEBUG
-	oldstale = INT_GET(leaf1->hdr.stale, ARCH_CONVERT) + INT_GET(leaf2->hdr.stale, ARCH_CONVERT);
+	oldstale = be16_to_cpu(leaf1->hdr.stale) + be16_to_cpu(leaf2->hdr.stale);
 #endif
 	mid = oldsum >> 1;
 	/*
@@ -780,10 +781,10 @@
 	if (oldsum & 1) {
 		xfs_dahash_t	midhash;	/* middle entry hash value */
 
-		if (mid >= INT_GET(leaf1->hdr.count, ARCH_CONVERT))
-			midhash = INT_GET(leaf2->ents[mid - INT_GET(leaf1->hdr.count, ARCH_CONVERT)].hashval, ARCH_CONVERT);
+		if (mid >= be16_to_cpu(leaf1->hdr.count))
+			midhash = be32_to_cpu(leaf2->ents[mid - be16_to_cpu(leaf1->hdr.count)].hashval);
 		else
-			midhash = INT_GET(leaf1->ents[mid].hashval, ARCH_CONVERT);
+			midhash = be32_to_cpu(leaf1->ents[mid].hashval);
 		isleft = args->hashval <= midhash;
 	}
 	/*
@@ -797,30 +798,30 @@
 	 * Calculate moved entry count.  Positive means left-to-right,
 	 * negative means right-to-left.  Then move the entries.
 	 */
-	count = INT_GET(leaf1->hdr.count, ARCH_CONVERT) - mid + (isleft == 0);
+	count = be16_to_cpu(leaf1->hdr.count) - mid + (isleft == 0);
 	if (count > 0)
 		xfs_dir2_leafn_moveents(args, blk1->bp,
-			INT_GET(leaf1->hdr.count, ARCH_CONVERT) - count, blk2->bp, 0, count);
+			be16_to_cpu(leaf1->hdr.count) - count, blk2->bp, 0, count);
 	else if (count < 0)
 		xfs_dir2_leafn_moveents(args, blk2->bp, 0, blk1->bp,
-			INT_GET(leaf1->hdr.count, ARCH_CONVERT), count);
-	ASSERT(INT_GET(leaf1->hdr.count, ARCH_CONVERT) + INT_GET(leaf2->hdr.count, ARCH_CONVERT) == oldsum);
-	ASSERT(INT_GET(leaf1->hdr.stale, ARCH_CONVERT) + INT_GET(leaf2->hdr.stale, ARCH_CONVERT) == oldstale);
+			be16_to_cpu(leaf1->hdr.count), count);
+	ASSERT(be16_to_cpu(leaf1->hdr.count) + be16_to_cpu(leaf2->hdr.count) == oldsum);
+	ASSERT(be16_to_cpu(leaf1->hdr.stale) + be16_to_cpu(leaf2->hdr.stale) == oldstale);
 	/*
 	 * Mark whether we're inserting into the old or new leaf.
 	 */
-	if (INT_GET(leaf1->hdr.count, ARCH_CONVERT) < INT_GET(leaf2->hdr.count, ARCH_CONVERT))
+	if (be16_to_cpu(leaf1->hdr.count) < be16_to_cpu(leaf2->hdr.count))
 		state->inleaf = swap;
-	else if (INT_GET(leaf1->hdr.count, ARCH_CONVERT) > INT_GET(leaf2->hdr.count, ARCH_CONVERT))
+	else if (be16_to_cpu(leaf1->hdr.count) > be16_to_cpu(leaf2->hdr.count))
 		state->inleaf = !swap;
 	else
 		state->inleaf =
-			swap ^ (blk1->index <= INT_GET(leaf1->hdr.count, ARCH_CONVERT));
+			swap ^ (blk1->index <= be16_to_cpu(leaf1->hdr.count));
 	/*
 	 * Adjust the expected index for insertion.
 	 */
 	if (!state->inleaf)
-		blk2->index = blk1->index - INT_GET(leaf1->hdr.count, ARCH_CONVERT);
+		blk2->index = blk1->index - be16_to_cpu(leaf1->hdr.count);
 	
 	/* 
 	 * Finally sanity check just to make sure we are not returning a negative index 
@@ -867,7 +868,7 @@
 	tp = args->trans;
 	mp = dp->i_mount;
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);
 	/*
 	 * Point to the entry we're removing.
 	 */
@@ -875,17 +876,17 @@
 	/*
 	 * Extract the data block and offset from the entry.
 	 */
-	db = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT));
+	db = XFS_DIR2_DATAPTR_TO_DB(mp, be32_to_cpu(lep->address));
 	ASSERT(dblk->blkno == db);
-	off = XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(lep->address, ARCH_CONVERT));
+	off = XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(lep->address));
 	ASSERT(dblk->index == off);
 	/*
 	 * Kill the leaf entry by marking it stale.
 	 * Log the leaf block changes.
 	 */
-	INT_MOD(leaf->hdr.stale, ARCH_CONVERT, +1);
+	be16_add(&leaf->hdr.stale, 1);
 	xfs_dir2_leaf_log_header(tp, bp);
-	INT_SET(lep->address, ARCH_CONVERT, XFS_DIR2_NULL_DATAPTR);
+	lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR);
 	xfs_dir2_leaf_log_ents(tp, bp, index, index);
 	/*
 	 * Make the data entry free.  Keep track of the longest freespace
@@ -894,7 +895,7 @@
 	dbp = dblk->bp;
 	data = dbp->data;
 	dep = (xfs_dir2_data_entry_t *)((char *)data + off);
-	longest = INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT);
+	longest = be16_to_cpu(data->hdr.bestfree[0].length);
 	needlog = needscan = 0;
 	xfs_dir2_data_make_free(tp, dbp, off,
 		XFS_DIR2_DATA_ENTSIZE(dep->namelen), &needlog, &needscan);
@@ -911,7 +912,7 @@
 	 * If the longest data block freespace changes, need to update
 	 * the corresponding freeblock entry.
 	 */
-	if (longest < INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT)) {
+	if (longest < be16_to_cpu(data->hdr.bestfree[0].length)) {
 		int		error;		/* error return value */
 		xfs_dabuf_t	*fbp;		/* freeblock buffer */
 		xfs_dir2_db_t	fdb;		/* freeblock block number */
@@ -929,15 +930,15 @@
 			return error;
 		}
 		free = fbp->data;
-		ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC);
-		ASSERT(INT_GET(free->hdr.firstdb, ARCH_CONVERT) ==
+		ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);
+		ASSERT(be32_to_cpu(free->hdr.firstdb) ==
 		       XFS_DIR2_MAX_FREE_BESTS(mp) *
 		       (fdb - XFS_DIR2_FREE_FIRSTDB(mp)));
 		/*
 		 * Calculate which entry we need to fix.
 		 */
 		findex = XFS_DIR2_DB_TO_FDINDEX(mp, db);
-		longest = INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT);
+		longest = be16_to_cpu(data->hdr.bestfree[0].length);
 		/*
 		 * If the data block is now empty we can get rid of it
 		 * (usually).
@@ -969,7 +970,7 @@
 			/*
 			 * One less used entry in the free table.
 			 */
-			INT_MOD(free->hdr.nused, ARCH_CONVERT, -1);
+			free->hdr.nused = cpu_to_be32(-1);
 			xfs_dir2_free_log_header(tp, fbp);
 			/*
 			 * If this was the last entry in the table, we can
@@ -977,21 +978,21 @@
 			 * entries at the end referring to non-existent
 			 * data blocks, get those too.
 			 */
-			if (findex == INT_GET(free->hdr.nvalid, ARCH_CONVERT) - 1) {
+			if (findex == be32_to_cpu(free->hdr.nvalid) - 1) {
 				int	i;		/* free entry index */
 
 				for (i = findex - 1;
-				     i >= 0 && INT_GET(free->bests[i], ARCH_CONVERT) == NULLDATAOFF;
+				     i >= 0 && be16_to_cpu(free->bests[i]) == NULLDATAOFF;
 				     i--)
 					continue;
-				INT_SET(free->hdr.nvalid, ARCH_CONVERT, i + 1);
+				free->hdr.nvalid = cpu_to_be32(i + 1);
 				logfree = 0;
 			}
 			/*
 			 * Not the last entry, just punch it out.
 			 */
 			else {
-				INT_SET(free->bests[findex], ARCH_CONVERT, NULLDATAOFF);
+				free->bests[findex] = cpu_to_be16(NULLDATAOFF);
 				logfree = 1;
 			}
 			/*
@@ -1017,7 +1018,7 @@
 		 * the new value.
 		 */
 		else {
-			INT_SET(free->bests[findex], ARCH_CONVERT, longest);
+			free->bests[findex] = cpu_to_be16(longest);
 			logfree = 1;
 		}
 		/*
@@ -1039,7 +1040,7 @@
 	*rval =
 		((uint)sizeof(leaf->hdr) +
 		 (uint)sizeof(leaf->ents[0]) *
-		 (INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT))) <
+		 (be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale))) <
 		mp->m_dir_magicpct;
 	return 0;
 }
@@ -1138,9 +1139,9 @@
 	 */
 	blk = &state->path.blk[state->path.active - 1];
 	info = blk->bp->data;
-	ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC);
+	ASSERT(be16_to_cpu(info->magic) == XFS_DIR2_LEAFN_MAGIC);
 	leaf = (xfs_dir2_leaf_t *)info;
-	count = INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT);
+	count = be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale);
 	bytes = (uint)sizeof(leaf->hdr) + count * (uint)sizeof(leaf->ents[0]);
 	if (bytes > (state->blocksize >> 1)) {
 		/*
@@ -1160,7 +1161,7 @@
 		 * Make altpath point to the block we want to keep and
 		 * path point to the block we want to drop (this one).
 		 */
-		forward = info->forw;
+		forward = (info->forw != 0);
 		memcpy(&state->altpath, &state->path, sizeof(state->path));
 		error = xfs_da_path_shift(state, &state->altpath, forward, 0,
 			&rval);
@@ -1176,9 +1177,9 @@
 	 * We prefer coalescing with the lower numbered sibling so as
 	 * to shrink a directory over time.
 	 */
-	forward = INT_GET(info->forw, ARCH_CONVERT) < INT_GET(info->back, ARCH_CONVERT);
+	forward = be32_to_cpu(info->forw) < be32_to_cpu(info->back);
 	for (i = 0, bp = NULL; i < 2; forward = !forward, i++) {
-		blkno = forward ?INT_GET( info->forw, ARCH_CONVERT) : INT_GET(info->back, ARCH_CONVERT);
+		blkno = forward ? be32_to_cpu(info->forw) : be32_to_cpu(info->back);
 		if (blkno == 0)
 			continue;
 		/*
@@ -1194,11 +1195,11 @@
 		 * Count bytes in the two blocks combined.
 		 */
 		leaf = (xfs_dir2_leaf_t *)info;
-		count = INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT);
+		count = be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale);
 		bytes = state->blocksize - (state->blocksize >> 2);
 		leaf = bp->data;
-		ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC);
-		count += INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT);
+		ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);
+		count += be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale);
 		bytes -= count * (uint)sizeof(leaf->ents[0]);
 		/*
 		 * Fits with at least 25% to spare.
@@ -1256,27 +1257,27 @@
 	ASSERT(save_blk->magic == XFS_DIR2_LEAFN_MAGIC);
 	drop_leaf = drop_blk->bp->data;
 	save_leaf = save_blk->bp->data;
-	ASSERT(INT_GET(drop_leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC);
-	ASSERT(INT_GET(save_leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC);
+	ASSERT(be16_to_cpu(drop_leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);
+	ASSERT(be16_to_cpu(save_leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);
 	/*
 	 * If there are any stale leaf entries, take this opportunity
 	 * to purge them.
 	 */
-	if (INT_GET(drop_leaf->hdr.stale, ARCH_CONVERT))
+	if (drop_leaf->hdr.stale)
 		xfs_dir2_leaf_compact(args, drop_blk->bp);
-	if (INT_GET(save_leaf->hdr.stale, ARCH_CONVERT))
+	if (save_leaf->hdr.stale)
 		xfs_dir2_leaf_compact(args, save_blk->bp);
 	/*
 	 * Move the entries from drop to the appropriate end of save.
 	 */
-	drop_blk->hashval = INT_GET(drop_leaf->ents[INT_GET(drop_leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT);
+	drop_blk->hashval = be32_to_cpu(drop_leaf->ents[be16_to_cpu(drop_leaf->hdr.count) - 1].hashval);
 	if (xfs_dir2_leafn_order(save_blk->bp, drop_blk->bp))
 		xfs_dir2_leafn_moveents(args, drop_blk->bp, 0, save_blk->bp, 0,
-			INT_GET(drop_leaf->hdr.count, ARCH_CONVERT));
+			be16_to_cpu(drop_leaf->hdr.count));
 	else
 		xfs_dir2_leafn_moveents(args, drop_blk->bp, 0, save_blk->bp,
-			INT_GET(save_leaf->hdr.count, ARCH_CONVERT), INT_GET(drop_leaf->hdr.count, ARCH_CONVERT));
-	save_blk->hashval = INT_GET(save_leaf->ents[INT_GET(save_leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT);
+			be16_to_cpu(save_leaf->hdr.count), be16_to_cpu(drop_leaf->hdr.count));
+	save_blk->hashval = be32_to_cpu(save_leaf->ents[be16_to_cpu(save_leaf->hdr.count) - 1].hashval);
 	xfs_dir2_leafn_check(args->dp, save_blk->bp);
 }
 
@@ -1378,7 +1379,7 @@
 	xfs_mount_t		*mp;		/* filesystem mount point */
 	int			needlog;	/* need to log data header */
 	int			needscan;	/* need to rescan data frees */
-	xfs_dir2_data_off_t	*tagp;		/* data entry tag pointer */
+	__be16			*tagp;		/* data entry tag pointer */
 	xfs_trans_t		*tp;		/* transaction pointer */
 
 	dp = args->dp;
@@ -1397,7 +1398,7 @@
 		 */
 		ifbno = fblk->blkno;
 		free = fbp->data;
-		ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC);
+		ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);
 		findex = fblk->index;
 		/*
 		 * This means the free entry showed that the data block had
@@ -1405,10 +1406,10 @@
 		 * Use that data block.
 		 */
 		if (findex >= 0) {
-			ASSERT(findex < INT_GET(free->hdr.nvalid, ARCH_CONVERT));
-			ASSERT(INT_GET(free->bests[findex], ARCH_CONVERT) != NULLDATAOFF);
-			ASSERT(INT_GET(free->bests[findex], ARCH_CONVERT) >= length);
-			dbno = INT_GET(free->hdr.firstdb, ARCH_CONVERT) + findex;
+			ASSERT(findex < be32_to_cpu(free->hdr.nvalid));
+			ASSERT(be16_to_cpu(free->bests[findex]) != NULLDATAOFF);
+			ASSERT(be16_to_cpu(free->bests[findex]) >= length);
+			dbno = be32_to_cpu(free->hdr.firstdb) + findex;
 		}
 		/*
 		 * The data block looked at didn't have enough room.
@@ -1481,20 +1482,20 @@
 				continue;
 			}
 			free = fbp->data;
-			ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC);
+			ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);
 			findex = 0;
 		}
 		/*
 		 * Look at the current free entry.  Is it good enough?
 		 */
-		if (INT_GET(free->bests[findex], ARCH_CONVERT) != NULLDATAOFF &&
-		    INT_GET(free->bests[findex], ARCH_CONVERT) >= length)
-			dbno = INT_GET(free->hdr.firstdb, ARCH_CONVERT) + findex;
+		if (be16_to_cpu(free->bests[findex]) != NULLDATAOFF &&
+		    be16_to_cpu(free->bests[findex]) >= length)
+			dbno = be32_to_cpu(free->hdr.firstdb) + findex;
 		else {
 			/*
 			 * Are we done with the freeblock?
 			 */
-			if (++findex == INT_GET(free->hdr.nvalid, ARCH_CONVERT)) {
+			if (++findex == be32_to_cpu(free->hdr.nvalid)) {
 				/*
 				 * Drop the block.
 				 */
@@ -1608,15 +1609,15 @@
 			 * its first slot as our empty slot.
 			 */
 			free = fbp->data;
-			INT_SET(free->hdr.magic, ARCH_CONVERT, XFS_DIR2_FREE_MAGIC);
-			INT_SET(free->hdr.firstdb, ARCH_CONVERT,
+			free->hdr.magic = cpu_to_be32(XFS_DIR2_FREE_MAGIC);
+			free->hdr.firstdb = cpu_to_be32(
 				(fbno - XFS_DIR2_FREE_FIRSTDB(mp)) *
 				XFS_DIR2_MAX_FREE_BESTS(mp));
 			free->hdr.nvalid = 0;
 			free->hdr.nused = 0;
 		} else {
 			free = fbp->data;
-			ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC);
+			ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);
 		}
 
 		/*
@@ -1627,20 +1628,20 @@
 		 * If it's after the end of the current entries in the
 		 * freespace block, extend that table.
 		 */
-		if (findex >= INT_GET(free->hdr.nvalid, ARCH_CONVERT)) {
+		if (findex >= be32_to_cpu(free->hdr.nvalid)) {
 			ASSERT(findex < XFS_DIR2_MAX_FREE_BESTS(mp));
-			INT_SET(free->hdr.nvalid, ARCH_CONVERT, findex + 1);
+			free->hdr.nvalid = cpu_to_be32(findex + 1);
 			/*
 			 * Tag new entry so nused will go up.
 			 */
-			INT_SET(free->bests[findex], ARCH_CONVERT, NULLDATAOFF);
+			free->bests[findex] = cpu_to_be16(NULLDATAOFF);
 		}
 		/*
 		 * If this entry was for an empty data block
 		 * (this should always be true) then update the header.
 		 */
-		if (INT_GET(free->bests[findex], ARCH_CONVERT) == NULLDATAOFF) {
-			INT_MOD(free->hdr.nused, ARCH_CONVERT, +1);
+		if (be16_to_cpu(free->bests[findex]) == NULLDATAOFF) {
+			be32_add(&free->hdr.nused, 1);
 			xfs_dir2_free_log_header(tp, fbp);
 		}
 		/*
@@ -1649,7 +1650,7 @@
 		 * change again.
 		 */
 		data = dbp->data;
-		INT_COPY(free->bests[findex], data->hdr.bestfree[0].length, ARCH_CONVERT);
+		free->bests[findex] = data->hdr.bestfree[0].length;
 		logfree = 1;
 	}
 	/*
@@ -1677,12 +1678,12 @@
 		data = dbp->data;
 		logfree = 0;
 	}
-	ASSERT(INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT) >= length);
+	ASSERT(be16_to_cpu(data->hdr.bestfree[0].length) >= length);
 	/*
 	 * Point to the existing unused space.
 	 */
 	dup = (xfs_dir2_data_unused_t *)
-	      ((char *)data + INT_GET(data->hdr.bestfree[0].offset, ARCH_CONVERT));
+	      ((char *)data + be16_to_cpu(data->hdr.bestfree[0].offset));
 	needscan = needlog = 0;
 	/*
 	 * Mark the first part of the unused space, inuse for us.
@@ -1694,11 +1695,11 @@
 	 * Fill in the new entry and log it.
 	 */
 	dep = (xfs_dir2_data_entry_t *)dup;
-	INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
+	dep->inumber = cpu_to_be64(args->inumber);
 	dep->namelen = args->namelen;
 	memcpy(dep->name, args->name, dep->namelen);
 	tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
-	INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)data));
+	*tagp = cpu_to_be16((char *)dep - (char *)data);
 	xfs_dir2_data_log_entry(tp, dbp, dep);
 	/*
 	 * Rescan the block for bestfree if needed.
@@ -1713,8 +1714,8 @@
 	/*
 	 * If the freespace entry is now wrong, update it.
 	 */
-	if (INT_GET(free->bests[findex], ARCH_CONVERT) != INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT)) {
-		INT_COPY(free->bests[findex], data->hdr.bestfree[0].length, ARCH_CONVERT);
+	if (be16_to_cpu(free->bests[findex]) != be16_to_cpu(data->hdr.bestfree[0].length)) {
+		free->bests[findex] = data->hdr.bestfree[0].length;
 		logfree = 1;
 	}
 	/*
@@ -1731,7 +1732,7 @@
 	 * Return the data block and offset in args, then drop the data block.
 	 */
 	args->blkno = (xfs_dablk_t)dbno;
-	args->index = INT_GET(*tagp, ARCH_CONVERT);
+	args->index = be16_to_cpu(*tagp);
 	xfs_da_buf_done(dbp);
 	return 0;
 }
@@ -1900,15 +1901,15 @@
 		 * Point to the data entry.
 		 */
 		data = state->extrablk.bp->data;
-		ASSERT(INT_GET(data->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC);
+		ASSERT(be32_to_cpu(data->hdr.magic) == XFS_DIR2_DATA_MAGIC);
 		dep = (xfs_dir2_data_entry_t *)
 		      ((char *)data +
-		       XFS_DIR2_DATAPTR_TO_OFF(state->mp, INT_GET(lep->address, ARCH_CONVERT)));
-		ASSERT(inum != INT_GET(dep->inumber, ARCH_CONVERT));
+		       XFS_DIR2_DATAPTR_TO_OFF(state->mp, be32_to_cpu(lep->address)));
+		ASSERT(inum != be64_to_cpu(dep->inumber));
 		/*
 		 * Fill in the new inode number and log the entry.
 		 */
-		INT_SET(dep->inumber, ARCH_CONVERT, inum);
+		dep->inumber = cpu_to_be64(inum);
 		xfs_dir2_data_log_entry(args->trans, state->extrablk.bp, dep);
 		rval = 0;
 	}
@@ -1966,11 +1967,11 @@
 		return 0;
 	}
 	free = bp->data;
-	ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC);
+	ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);
 	/*
 	 * If there are used entries, there's nothing to do.
 	 */
-	if (INT_GET(free->hdr.nused, ARCH_CONVERT) > 0) {
+	if (be32_to_cpu(free->hdr.nused) > 0) {
 		xfs_da_brelse(tp, bp);
 		*rvalp = 0;
 		return 0;
diff -urN oldtree/fs/xfs/xfs_dir2_node.h newtree/fs/xfs/xfs_dir2_node.h
--- oldtree/fs/xfs/xfs_dir2_node.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/xfs/xfs_dir2_node.h	2006-02-21 15:58:36.733562208 +0000
@@ -41,15 +41,15 @@
 #define	XFS_DIR2_FREE_MAGIC	0x58443246	/* XD2F */
 
 typedef	struct xfs_dir2_free_hdr {
-	__uint32_t		magic;		/* XFS_DIR2_FREE_MAGIC */
-	__int32_t		firstdb;	/* db of first entry */
-	__int32_t		nvalid;		/* count of valid entries */
-	__int32_t		nused;		/* count of used entries */
+	__be32			magic;		/* XFS_DIR2_FREE_MAGIC */
+	__be32			firstdb;	/* db of first entry */
+	__be32			nvalid;		/* count of valid entries */
+	__be32			nused;		/* count of used entries */
 } xfs_dir2_free_hdr_t;
 
 typedef struct xfs_dir2_free {
 	xfs_dir2_free_hdr_t	hdr;		/* block header */
-	xfs_dir2_data_off_t	bests[1];	/* best free counts */
+	__be16			bests[1];	/* best free counts */
 						/* unused entries are -1 */
 } xfs_dir2_free_t;
 
diff -urN oldtree/fs/xfs/xfs_dir2_sf.c newtree/fs/xfs/xfs_dir2_sf.c
--- oldtree/fs/xfs/xfs_dir2_sf.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/fs/xfs/xfs_dir2_sf.c	2006-02-21 15:58:36.735561904 +0000
@@ -98,8 +98,8 @@
 	/*
 	 * Iterate over the block's data entries by using the leaf pointers.
 	 */
-	for (i = 0; i < INT_GET(btp->count, ARCH_CONVERT); i++) {
-		if ((addr = INT_GET(blp[i].address, ARCH_CONVERT)) == XFS_DIR2_NULL_DATAPTR)
+	for (i = 0; i < be32_to_cpu(btp->count); i++) {
+		if ((addr = be32_to_cpu(blp[i].address)) == XFS_DIR2_NULL_DATAPTR)
 			continue;
 		/*
 		 * Calculate the pointer to the entry at hand.
@@ -117,13 +117,13 @@
 			dep->name[0] == '.' && dep->name[1] == '.';
 #if XFS_BIG_INUMS
 		if (!isdot)
-			i8count += INT_GET(dep->inumber, ARCH_CONVERT) > XFS_DIR2_MAX_SHORT_INUM;
+			i8count += be64_to_cpu(dep->inumber) > XFS_DIR2_MAX_SHORT_INUM;
 #endif
 		if (!isdot && !isdotdot) {
 			count++;
 			namelen += dep->namelen;
 		} else if (isdotdot)
-			parent = INT_GET(dep->inumber, ARCH_CONVERT);
+			parent = be64_to_cpu(dep->inumber);
 		/*
 		 * Calculate the new size, see if we should give up yet.
 		 */
@@ -220,8 +220,8 @@
 		 * If it's unused, just skip over it.
 		 */
 		dup = (xfs_dir2_data_unused_t *)ptr;
-		if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) {
-			ptr += INT_GET(dup->length, ARCH_CONVERT);
+		if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
+			ptr += be16_to_cpu(dup->length);
 			continue;
 		}
 		dep = (xfs_dir2_data_entry_t *)ptr;
@@ -229,13 +229,13 @@
 		 * Skip .
 		 */
 		if (dep->namelen == 1 && dep->name[0] == '.')
-			ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) == dp->i_ino);
+			ASSERT(be64_to_cpu(dep->inumber) == dp->i_ino);
 		/*
 		 * Skip .., but make sure the inode number is right.
 		 */
 		else if (dep->namelen == 2 &&
 			 dep->name[0] == '.' && dep->name[1] == '.')
-			ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) ==
+			ASSERT(be64_to_cpu(dep->inumber) ==
 			       XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent));
 		/*
 		 * Normal entry, copy it into shortform.
@@ -246,7 +246,7 @@
 				(xfs_dir2_data_aoff_t)
 				((char *)dep - (char *)block));
 			memcpy(sfep->name, dep->name, dep->namelen);
-			temp=INT_GET(dep->inumber, ARCH_CONVERT);
+			temp = be64_to_cpu(dep->inumber);
 			XFS_DIR2_SF_PUT_INUMBER(sfp, &temp,
 				XFS_DIR2_SF_INUMBERP(sfep));
 			sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep);
diff -urN oldtree/fs/xfs/xfs_dir_leaf.c newtree/fs/xfs/xfs_dir_leaf.c
--- oldtree/fs/xfs/xfs_dir_leaf.c	2006-02-19 11:41:05.400522096 +0000
+++ newtree/fs/xfs/xfs_dir_leaf.c	2006-02-21 15:58:36.740561144 +0000
@@ -176,7 +176,7 @@
 	ASSERT(dp->i_df.if_u1.if_data != NULL);
 	sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data;
 	sfe = &sf->list[0];
-	for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) {
+	for (i = sf->hdr.count-1; i >= 0; i--) {
 		if (sfe->namelen == args->namelen &&
 		    args->name[0] == sfe->name[0] &&
 		    memcmp(args->name, sfe->name, args->namelen) == 0)
@@ -193,7 +193,7 @@
 	XFS_DIR_SF_PUT_DIRINO(&args->inumber, &sfe->inumber);
 	sfe->namelen = args->namelen;
 	memcpy(sfe->name, args->name, sfe->namelen);
-	INT_MOD(sf->hdr.count, ARCH_CONVERT, +1);
+	sf->hdr.count++;
 
 	dp->i_d.di_size += size;
 	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
@@ -227,7 +227,7 @@
 	base = sizeof(xfs_dir_sf_hdr_t);
 	sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data;
 	sfe = &sf->list[0];
-	for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) {
+	for (i = sf->hdr.count-1; i >= 0; i--) {
 		size = XFS_DIR_SF_ENTSIZE_BYENTRY(sfe);
 		if (sfe->namelen == args->namelen &&
 		    sfe->name[0] == args->name[0] &&
@@ -245,7 +245,7 @@
 		memmove(&((char *)sf)[base], &((char *)sf)[base+size],
 					      dp->i_d.di_size - (base+size));
 	}
-	INT_MOD(sf->hdr.count, ARCH_CONVERT, -1);
+	sf->hdr.count--;
 
 	xfs_idata_realloc(dp, -size, XFS_DATA_FORK);
 	dp->i_d.di_size -= size;
@@ -288,7 +288,7 @@
 		return(XFS_ERROR(EEXIST));
 	}
 	sfe = &sf->list[0];
-	for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) {
+	for (i = sf->hdr.count-1; i >= 0; i--) {
 		if (sfe->namelen == args->namelen &&
 		    sfe->name[0] == args->name[0] &&
 		    memcmp(args->name, sfe->name, args->namelen) == 0) {
@@ -375,7 +375,7 @@
 		goto out;
 
 	sfe = &sf->list[0];
-	for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) {
+	for (i = 0; i < sf->hdr.count; i++) {
 		args.name = (char *)(sfe->name);
 		args.namelen = sfe->namelen;
 		args.hashval = xfs_da_hashname((char *)(sfe->name),
@@ -428,7 +428,7 @@
 	sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data;
 	cookhash = XFS_DA_COOKIE_HASH(mp, uio->uio_offset);
 	want_entno = XFS_DA_COOKIE_ENTRY(mp, uio->uio_offset);
-	nsbuf = INT_GET(sf->hdr.count, ARCH_CONVERT) + 2;
+	nsbuf = sf->hdr.count + 2;
 	sbsize = (nsbuf + 1) * sizeof(*sbuf);
 	sbp = sbuf = kmem_alloc(sbsize, KM_SLEEP);
 
@@ -460,8 +460,7 @@
 	/*
 	 * Scan the directory data for the rest of the entries.
 	 */
-	for (i = 0, sfe = &sf->list[0];
-			i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) {
+	for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
 
 		if (unlikely(
 		    ((char *)sfe < (char *)sf) ||
@@ -600,7 +599,7 @@
 	}
 	ASSERT(args->namelen != 1 || args->name[0] != '.');
 	sfe = &sf->list[0];
-	for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) {
+	for (i = sf->hdr.count-1; i >= 0; i--) {
 		if (sfe->namelen == args->namelen &&
 		    sfe->name[0] == args->name[0] &&
 		    memcmp(args->name, sfe->name, args->namelen) == 0) {
@@ -644,7 +643,7 @@
 	ASSERT(bp != NULL);
 	memcpy(tmpbuffer, bp->data, XFS_LBSIZE(dp->i_mount));
 	leaf = (xfs_dir_leafblock_t *)tmpbuffer;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
 	memset(bp->data, 0, XFS_LBSIZE(dp->i_mount));
 
 	/*
@@ -652,8 +651,8 @@
 	 */
 	hdr = &leaf->hdr;
 	entry = &leaf->entries[0];
-	for (i = INT_GET(hdr->count, ARCH_CONVERT)-1; i >= 0; entry++, i--) {
-		namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
+	for (i = be16_to_cpu(hdr->count)-1; i >= 0; entry++, i--) {
+		namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, be16_to_cpu(entry->nameidx));
 		if ((entry->namelen == 2) &&
 		    (namest->name[0] == '.') &&
 		    (namest->name[1] == '.')) {
@@ -682,13 +681,13 @@
 	args.trans = iargs->trans;
 	args.justcheck = 0;
 	args.addname = args.oknoent = 1;
-	for (i = 0; i < INT_GET(hdr->count, ARCH_CONVERT); entry++, i++) {
+	for (i = 0; i < be16_to_cpu(hdr->count); entry++, i++) {
 		if (!entry->nameidx)
 			continue;
-		namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
+		namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, be16_to_cpu(entry->nameidx));
 		args.name = (char *)(namest->name);
 		args.namelen = entry->namelen;
-		args.hashval = INT_GET(entry->hashval, ARCH_CONVERT);
+		args.hashval = be32_to_cpu(entry->hashval);
 		XFS_DIR_SF_GET_DIRINO(&namest->inumber, &args.inumber);
 		xfs_dir_shortform_addname(&args);
 	}
@@ -742,11 +741,11 @@
 	}
 	node = bp1->data;
 	leaf = bp2->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
-	INT_SET(node->btree[0].hashval, ARCH_CONVERT, INT_GET(leaf->entries[ INT_GET(leaf->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT));
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
+	node->btree[0].hashval = leaf->entries[be16_to_cpu(leaf->hdr.count)-1].hashval;
 	xfs_da_buf_done(bp2);
-	INT_SET(node->btree[0].before, ARCH_CONVERT, blkno);
-	INT_SET(node->hdr.count, ARCH_CONVERT, 1);
+	node->btree[0].before = cpu_to_be32(blkno);
+	node->hdr.count = cpu_to_be16(1);
 	xfs_da_log_buf(args->trans, bp1,
 		XFS_DA_LOGRANGE(node, &node->btree[0], sizeof(node->btree[0])));
 	xfs_da_buf_done(bp1);
@@ -781,12 +780,13 @@
 	leaf = bp->data;
 	memset((char *)leaf, 0, XFS_LBSIZE(dp->i_mount));
 	hdr = &leaf->hdr;
-	INT_SET(hdr->info.magic, ARCH_CONVERT, XFS_DIR_LEAF_MAGIC);
-	INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount));
+	hdr->info.magic = cpu_to_be16(XFS_DIR_LEAF_MAGIC);
+	hdr->firstused = cpu_to_be16(XFS_LBSIZE(dp->i_mount));
 	if (!hdr->firstused)
-		INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount) - 1);
-	INT_SET(hdr->freemap[0].base, ARCH_CONVERT, sizeof(xfs_dir_leaf_hdr_t));
-	INT_SET(hdr->freemap[0].size, ARCH_CONVERT, INT_GET(hdr->firstused, ARCH_CONVERT) - INT_GET(hdr->freemap[0].base, ARCH_CONVERT));
+		hdr->firstused = cpu_to_be16(XFS_LBSIZE(dp->i_mount) - 1);
+	hdr->freemap[0].base = cpu_to_be16(sizeof(xfs_dir_leaf_hdr_t));
+	hdr->freemap[0].size = cpu_to_be16(be16_to_cpu(hdr->firstused) -
+					   be16_to_cpu(hdr->freemap[0].base));
 
 	xfs_da_log_buf(args->trans, bp, 0, XFS_LBSIZE(dp->i_mount) - 1);
 
@@ -860,8 +860,8 @@
 	int tablesize, entsize, sum, i, tmp, error;
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
-	ASSERT((index >= 0) && (index <= INT_GET(leaf->hdr.count, ARCH_CONVERT)));
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
+	ASSERT((index >= 0) && (index <= be16_to_cpu(leaf->hdr.count)));
 	hdr = &leaf->hdr;
 	entsize = XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen);
 
@@ -869,25 +869,25 @@
 	 * Search through freemap for first-fit on new name length.
 	 * (may need to figure in size of entry struct too)
 	 */
-	tablesize = (INT_GET(hdr->count, ARCH_CONVERT) + 1) * (uint)sizeof(xfs_dir_leaf_entry_t)
-			+ (uint)sizeof(xfs_dir_leaf_hdr_t);
+	tablesize = (be16_to_cpu(hdr->count) + 1) *
+		sizeof(xfs_dir_leaf_entry_t) + sizeof(xfs_dir_leaf_hdr_t);
 	map = &hdr->freemap[XFS_DIR_LEAF_MAPSIZE-1];
 	for (sum = 0, i = XFS_DIR_LEAF_MAPSIZE-1; i >= 0; map--, i--) {
-		if (tablesize > INT_GET(hdr->firstused, ARCH_CONVERT)) {
-			sum += INT_GET(map->size, ARCH_CONVERT);
+		if (tablesize > be16_to_cpu(hdr->firstused)) {
+			sum += be16_to_cpu(map->size);
 			continue;
 		}
 		if (!map->size)
 			continue;	/* no space in this map */
 		tmp = entsize;
-		if (INT_GET(map->base, ARCH_CONVERT) < INT_GET(hdr->firstused, ARCH_CONVERT))
+		if (be16_to_cpu(map->base) < be16_to_cpu(hdr->firstused))
 			tmp += (uint)sizeof(xfs_dir_leaf_entry_t);
-		if (INT_GET(map->size, ARCH_CONVERT) >= tmp) {
+		if (be16_to_cpu(map->size) >= tmp) {
 			if (!args->justcheck)
 				xfs_dir_leaf_add_work(bp, args, index, i);
 			return 0;
 		}
-		sum += INT_GET(map->size, ARCH_CONVERT);
+		sum += be16_to_cpu(map->size);
 	}
 
 	/*
@@ -914,7 +914,7 @@
 	 * After compaction, the block is guaranteed to have only one
 	 * free region, in freemap[0].  If it is not big enough, give up.
 	 */
-	if (INT_GET(hdr->freemap[0].size, ARCH_CONVERT) <
+	if (be16_to_cpu(hdr->freemap[0].size) <
 	    (entsize + (uint)sizeof(xfs_dir_leaf_entry_t)))
 		return XFS_ERROR(ENOSPC);
 
@@ -940,35 +940,37 @@
 	int tmp, i;
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
 	hdr = &leaf->hdr;
 	ASSERT((mapindex >= 0) && (mapindex < XFS_DIR_LEAF_MAPSIZE));
-	ASSERT((index >= 0) && (index <= INT_GET(hdr->count, ARCH_CONVERT)));
+	ASSERT((index >= 0) && (index <= be16_to_cpu(hdr->count)));
 
 	/*
 	 * Force open some space in the entry array and fill it in.
 	 */
 	entry = &leaf->entries[index];
-	if (index < INT_GET(hdr->count, ARCH_CONVERT)) {
-		tmp  = INT_GET(hdr->count, ARCH_CONVERT) - index;
+	if (index < be16_to_cpu(hdr->count)) {
+		tmp  = be16_to_cpu(hdr->count) - index;
 		tmp *= (uint)sizeof(xfs_dir_leaf_entry_t);
 		memmove(entry + 1, entry, tmp);
 		xfs_da_log_buf(args->trans, bp,
 		    XFS_DA_LOGRANGE(leaf, entry, tmp + (uint)sizeof(*entry)));
 	}
-	INT_MOD(hdr->count, ARCH_CONVERT, +1);
+	be16_add(&hdr->count, 1);
 
 	/*
 	 * Allocate space for the new string (at the end of the run).
 	 */
 	map = &hdr->freemap[mapindex];
 	mp = args->trans->t_mountp;
-	ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp));
-	ASSERT(INT_GET(map->size, ARCH_CONVERT) >= XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen));
-	ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp));
-	INT_MOD(map->size, ARCH_CONVERT, -(XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen)));
-	INT_SET(entry->nameidx, ARCH_CONVERT, INT_GET(map->base, ARCH_CONVERT) + INT_GET(map->size, ARCH_CONVERT));
-	INT_SET(entry->hashval, ARCH_CONVERT, args->hashval);
+	ASSERT(be16_to_cpu(map->base) < XFS_LBSIZE(mp));
+	ASSERT(be16_to_cpu(map->size) >= XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen));
+	ASSERT(be16_to_cpu(map->size) < XFS_LBSIZE(mp));
+
+	be16_add(&map->size, -(XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen)));
+	entry->nameidx = cpu_to_be16(be16_to_cpu(map->base) +
+				     be16_to_cpu(map->size));
+	entry->hashval = cpu_to_be32(args->hashval);
 	entry->namelen = args->namelen;
 	xfs_da_log_buf(args->trans, bp,
 	    XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry)));
@@ -976,7 +978,7 @@
 	/*
 	 * Copy the string and inode number into the new space.
 	 */
-	namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
+	namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, be16_to_cpu(entry->nameidx));
 	XFS_DIR_SF_PUT_DIRINO(&args->inumber, &namest->inumber);
 	memcpy(namest->name, args->name, args->namelen);
 	xfs_da_log_buf(args->trans, bp,
@@ -985,19 +987,21 @@
 	/*
 	 * Update the control info for this leaf node
 	 */
-	if (INT_GET(entry->nameidx, ARCH_CONVERT) < INT_GET(hdr->firstused, ARCH_CONVERT))
-		INT_COPY(hdr->firstused, entry->nameidx, ARCH_CONVERT);
-	ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) >= ((INT_GET(hdr->count, ARCH_CONVERT)*sizeof(*entry))+sizeof(*hdr)));
-	tmp = (INT_GET(hdr->count, ARCH_CONVERT)-1) * (uint)sizeof(xfs_dir_leaf_entry_t)
+	if (be16_to_cpu(entry->nameidx) < be16_to_cpu(hdr->firstused))
+		hdr->firstused = entry->nameidx;
+	ASSERT(be16_to_cpu(hdr->firstused) >=
+	       ((be16_to_cpu(hdr->count)*sizeof(*entry))+sizeof(*hdr)));
+	tmp = (be16_to_cpu(hdr->count)-1) * (uint)sizeof(xfs_dir_leaf_entry_t)
 			+ (uint)sizeof(xfs_dir_leaf_hdr_t);
 	map = &hdr->freemap[0];
 	for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; map++, i++) {
-		if (INT_GET(map->base, ARCH_CONVERT) == tmp) {
-			INT_MOD(map->base, ARCH_CONVERT, (uint)sizeof(xfs_dir_leaf_entry_t));
-			INT_MOD(map->size, ARCH_CONVERT, -((uint)sizeof(xfs_dir_leaf_entry_t)));
+		if (be16_to_cpu(map->base) == tmp) {
+			int entry_size = sizeof(xfs_dir_leaf_entry_t);
+			be16_add(&map->base, entry_size);
+			be16_add(&map->size, -entry_size);
 		}
 	}
-	INT_MOD(hdr->namebytes, ARCH_CONVERT, args->namelen);
+	be16_add(&hdr->namebytes, args->namelen);
 	xfs_da_log_buf(args->trans, bp,
 		XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr)));
 }
@@ -1041,23 +1045,24 @@
 	hdr_s = &leaf_s->hdr;
 	hdr_d = &leaf_d->hdr;
 	hdr_d->info = hdr_s->info;	/* struct copy */
-	INT_SET(hdr_d->firstused, ARCH_CONVERT, lbsize);
+	hdr_d->firstused = cpu_to_be16(lbsize);
 	if (!hdr_d->firstused)
-		INT_SET(hdr_d->firstused, ARCH_CONVERT, lbsize - 1);
+		hdr_d->firstused = cpu_to_be16(lbsize - 1);
 	hdr_d->namebytes = 0;
 	hdr_d->count = 0;
 	hdr_d->holes = 0;
-	INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, sizeof(xfs_dir_leaf_hdr_t));
-	INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, INT_GET(hdr_d->firstused, ARCH_CONVERT) - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT));
+	hdr_d->freemap[0].base = cpu_to_be16(sizeof(xfs_dir_leaf_hdr_t));
+	hdr_d->freemap[0].size = cpu_to_be16(be16_to_cpu(hdr_d->firstused) -
+			                     be16_to_cpu(hdr_d->freemap[0].base));
 
 	/*
 	 * Copy all entry's in the same (sorted) order,
 	 * but allocate filenames packed and in sequence.
 	 * This changes the source (leaf_s) as well.
 	 */
-	xfs_dir_leaf_moveents(leaf_s, 0, leaf_d, 0, (int)INT_GET(hdr_s->count, ARCH_CONVERT), mp);
+	xfs_dir_leaf_moveents(leaf_s, 0, leaf_d, 0, be16_to_cpu(hdr_s->count), mp);
 
-	if (musthave && INT_GET(hdr_d->freemap[0].size, ARCH_CONVERT) < musthave)
+	if (musthave && be16_to_cpu(hdr_d->freemap[0].size) < musthave)
 		rval = XFS_ERROR(ENOSPC);
 	else
 		rval = 0;
@@ -1097,8 +1102,8 @@
 	ASSERT(blk2->magic == XFS_DIR_LEAF_MAGIC);
 	leaf1 = blk1->bp->data;
 	leaf2 = blk2->bp->data;
-	ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
-	ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf1->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf2->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
 
 	/*
 	 * Check ordering of blocks, reverse if it makes things simpler.
@@ -1128,20 +1133,20 @@
 	/*
 	 * Move any entries required from leaf to leaf:
 	 */
-	if (count < INT_GET(hdr1->count, ARCH_CONVERT)) {
+	if (count < be16_to_cpu(hdr1->count)) {
 		/*
 		 * Figure the total bytes to be added to the destination leaf.
 		 */
-		count = INT_GET(hdr1->count, ARCH_CONVERT) - count;	/* number entries being moved */
-		space  = INT_GET(hdr1->namebytes, ARCH_CONVERT) - totallen;
+		count = be16_to_cpu(hdr1->count) - count;	/* number entries being moved */
+		space = be16_to_cpu(hdr1->namebytes) - totallen;
 		space += count * ((uint)sizeof(xfs_dir_leaf_name_t)-1);
 		space += count * (uint)sizeof(xfs_dir_leaf_entry_t);
 
 		/*
 		 * leaf2 is the destination, compact it if it looks tight.
 		 */
-		max  = INT_GET(hdr2->firstused, ARCH_CONVERT) - (uint)sizeof(xfs_dir_leaf_hdr_t);
-		max -= INT_GET(hdr2->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t);
+		max  = be16_to_cpu(hdr2->firstused) - (uint)sizeof(xfs_dir_leaf_hdr_t);
+		max -= be16_to_cpu(hdr2->count) * (uint)sizeof(xfs_dir_leaf_entry_t);
 		if (space > max) {
 			xfs_dir_leaf_compact(state->args->trans, blk2->bp,
 								 0, 0);
@@ -1150,7 +1155,7 @@
 		/*
 		 * Move high entries from leaf1 to low end of leaf2.
 		 */
-		xfs_dir_leaf_moveents(leaf1, INT_GET(hdr1->count, ARCH_CONVERT) - count,
+		xfs_dir_leaf_moveents(leaf1, be16_to_cpu(hdr1->count) - count,
 					     leaf2, 0, count, state->mp);
 
 		xfs_da_log_buf(state->args->trans, blk1->bp, 0,
@@ -1158,20 +1163,20 @@
 		xfs_da_log_buf(state->args->trans, blk2->bp, 0,
 						   state->blocksize-1);
 
-	} else if (count > INT_GET(hdr1->count, ARCH_CONVERT)) {
+	} else if (count > be16_to_cpu(hdr1->count)) {
 		/*
 		 * Figure the total bytes to be added to the destination leaf.
 		 */
-		count -= INT_GET(hdr1->count, ARCH_CONVERT);		/* number entries being moved */
-		space  = totallen - INT_GET(hdr1->namebytes, ARCH_CONVERT);
+		count -= be16_to_cpu(hdr1->count);		/* number entries being moved */
+		space  = totallen - be16_to_cpu(hdr1->namebytes);
 		space += count * ((uint)sizeof(xfs_dir_leaf_name_t)-1);
 		space += count * (uint)sizeof(xfs_dir_leaf_entry_t);
 
 		/*
 		 * leaf1 is the destination, compact it if it looks tight.
 		 */
-		max  = INT_GET(hdr1->firstused, ARCH_CONVERT) - (uint)sizeof(xfs_dir_leaf_hdr_t);
-		max -= INT_GET(hdr1->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t);
+		max  = be16_to_cpu(hdr1->firstused) - (uint)sizeof(xfs_dir_leaf_hdr_t);
+		max -= be16_to_cpu(hdr1->count) * (uint)sizeof(xfs_dir_leaf_entry_t);
 		if (space > max) {
 			xfs_dir_leaf_compact(state->args->trans, blk1->bp,
 								 0, 0);
@@ -1180,7 +1185,7 @@
 		/*
 		 * Move low entries from leaf2 to high end of leaf1.
 		 */
-		xfs_dir_leaf_moveents(leaf2, 0, leaf1, (int)INT_GET(hdr1->count, ARCH_CONVERT),
+		xfs_dir_leaf_moveents(leaf2, 0, leaf1, be16_to_cpu(hdr1->count),
 					     count, state->mp);
 
 		xfs_da_log_buf(state->args->trans, blk1->bp, 0,
@@ -1192,15 +1197,17 @@
 	/*
 	 * Copy out last hashval in each block for B-tree code.
 	 */
-	blk1->hashval = INT_GET(leaf1->entries[ INT_GET(leaf1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT);
-	blk2->hashval = INT_GET(leaf2->entries[ INT_GET(leaf2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT);
+	blk1->hashval = be32_to_cpu(leaf1->entries[
+			be16_to_cpu(leaf1->hdr.count)-1].hashval);
+	blk2->hashval = be32_to_cpu(leaf2->entries[
+			be16_to_cpu(leaf2->hdr.count)-1].hashval);
 
 	/*
 	 * Adjust the expected index for insertion.
 	 * GROT: this doesn't work unless blk2 was originally empty.
 	 */
 	if (!state->inleaf) {
-		blk2->index = blk1->index - INT_GET(leaf1->hdr.count, ARCH_CONVERT);
+		blk2->index = blk1->index - be16_to_cpu(leaf1->hdr.count);
 	}
 }
 
@@ -1237,9 +1244,10 @@
 	 * Examine entries until we reduce the absolute difference in
 	 * byte usage between the two blocks to a minimum.
 	 */
-	max = INT_GET(hdr1->count, ARCH_CONVERT) + INT_GET(hdr2->count, ARCH_CONVERT);
+	max = be16_to_cpu(hdr1->count) + be16_to_cpu(hdr2->count);
 	half  = (max+1) * (uint)(sizeof(*entry)+sizeof(xfs_dir_leaf_entry_t)-1);
-	half += INT_GET(hdr1->namebytes, ARCH_CONVERT) + INT_GET(hdr2->namebytes, ARCH_CONVERT) + state->args->namelen;
+	half += be16_to_cpu(hdr1->namebytes) + be16_to_cpu(hdr2->namebytes) +
+		state->args->namelen;
 	half /= 2;
 	lastdelta = state->blocksize;
 	entry = &leaf1->entries[0];
@@ -1262,7 +1270,7 @@
 		/*
 		 * Wrap around into the second block if necessary.
 		 */
-		if (count == INT_GET(hdr1->count, ARCH_CONVERT)) {
+		if (count == be16_to_cpu(hdr1->count)) {
 			leaf1 = leaf2;
 			entry = &leaf1->entries[0];
 		}
@@ -1325,13 +1333,13 @@
 	 */
 	blk = &state->path.blk[ state->path.active-1 ];
 	info = blk->bp->data;
-	ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(info->magic) == XFS_DIR_LEAF_MAGIC);
 	leaf = (xfs_dir_leafblock_t *)info;
-	count = INT_GET(leaf->hdr.count, ARCH_CONVERT);
+	count = be16_to_cpu(leaf->hdr.count);
 	bytes = (uint)sizeof(xfs_dir_leaf_hdr_t) +
 		count * (uint)sizeof(xfs_dir_leaf_entry_t) +
 		count * ((uint)sizeof(xfs_dir_leaf_name_t)-1) +
-		INT_GET(leaf->hdr.namebytes, ARCH_CONVERT);
+		be16_to_cpu(leaf->hdr.namebytes);
 	if (bytes > (state->blocksize >> 1)) {
 		*action = 0;	/* blk over 50%, don't try to join */
 		return 0;
@@ -1348,7 +1356,7 @@
 		 * Make altpath point to the block we want to keep and
 		 * path point to the block we want to drop (this one).
 		 */
-		forward = info->forw;
+		forward = (info->forw != 0);
 		memcpy(&state->altpath, &state->path, sizeof(state->path));
 		error = xfs_da_path_shift(state, &state->altpath, forward,
 						 0, &retval);
@@ -1369,12 +1377,12 @@
 	 * We prefer coalescing with the lower numbered sibling so as
 	 * to shrink a directory over time.
 	 */
-	forward = (INT_GET(info->forw, ARCH_CONVERT) < INT_GET(info->back, ARCH_CONVERT));	/* start with smaller blk num */
+	forward = (be32_to_cpu(info->forw) < be32_to_cpu(info->back));	/* start with smaller blk num */
 	for (i = 0; i < 2; forward = !forward, i++) {
 		if (forward)
-			blkno = INT_GET(info->forw, ARCH_CONVERT);
+			blkno = be32_to_cpu(info->forw);
 		else
-			blkno = INT_GET(info->back, ARCH_CONVERT);
+			blkno = be32_to_cpu(info->back);
 		if (blkno == 0)
 			continue;
 		error = xfs_da_read_buf(state->args->trans, state->args->dp,
@@ -1385,13 +1393,13 @@
 		ASSERT(bp != NULL);
 
 		leaf = (xfs_dir_leafblock_t *)info;
-		count  = INT_GET(leaf->hdr.count, ARCH_CONVERT);
+		count  = be16_to_cpu(leaf->hdr.count);
 		bytes  = state->blocksize - (state->blocksize>>2);
-		bytes -= INT_GET(leaf->hdr.namebytes, ARCH_CONVERT);
+		bytes -= be16_to_cpu(leaf->hdr.namebytes);
 		leaf = bp->data;
-		ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
-		count += INT_GET(leaf->hdr.count, ARCH_CONVERT);
-		bytes -= INT_GET(leaf->hdr.namebytes, ARCH_CONVERT);
+		ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
+		count += be16_to_cpu(leaf->hdr.count);
+		bytes -= be16_to_cpu(leaf->hdr.namebytes);
 		bytes -= count * ((uint)sizeof(xfs_dir_leaf_name_t) - 1);
 		bytes -= count * (uint)sizeof(xfs_dir_leaf_entry_t);
 		bytes -= (uint)sizeof(xfs_dir_leaf_hdr_t);
@@ -1447,15 +1455,16 @@
 	xfs_mount_t *mp;
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
 	hdr = &leaf->hdr;
 	mp = trans->t_mountp;
-	ASSERT((INT_GET(hdr->count, ARCH_CONVERT) > 0) && (INT_GET(hdr->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8)));
-	ASSERT((index >= 0) && (index < INT_GET(hdr->count, ARCH_CONVERT)));
-	ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) >= ((INT_GET(hdr->count, ARCH_CONVERT)*sizeof(*entry))+sizeof(*hdr)));
+	ASSERT(hdr->count && (be16_to_cpu(hdr->count) < (XFS_LBSIZE(mp)/8)));
+	ASSERT((index >= 0) && (index < be16_to_cpu(hdr->count)));
+	ASSERT(be16_to_cpu(hdr->firstused) >=
+	       ((be16_to_cpu(hdr->count)*sizeof(*entry))+sizeof(*hdr)));
 	entry = &leaf->entries[index];
-	ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) >= INT_GET(hdr->firstused, ARCH_CONVERT));
-	ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp));
+	ASSERT(be16_to_cpu(entry->nameidx) >= be16_to_cpu(hdr->firstused));
+	ASSERT(be16_to_cpu(entry->nameidx) < XFS_LBSIZE(mp));
 
 	/*
 	 * Scan through free region table:
@@ -1463,27 +1472,30 @@
 	 *    find smallest free region in case we need to replace it,
 	 *    adjust any map that borders the entry table,
 	 */
-	tablesize = INT_GET(hdr->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t)
+	tablesize = be16_to_cpu(hdr->count) * (uint)sizeof(xfs_dir_leaf_entry_t)
 			+ (uint)sizeof(xfs_dir_leaf_hdr_t);
 	map = &hdr->freemap[0];
-	tmp = INT_GET(map->size, ARCH_CONVERT);
+	tmp = be16_to_cpu(map->size);
 	before = after = -1;
 	smallest = XFS_DIR_LEAF_MAPSIZE - 1;
 	entsize = XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry);
 	for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; map++, i++) {
-		ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp));
-		ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp));
-		if (INT_GET(map->base, ARCH_CONVERT) == tablesize) {
-			INT_MOD(map->base, ARCH_CONVERT, -((uint)sizeof(xfs_dir_leaf_entry_t)));
-			INT_MOD(map->size, ARCH_CONVERT, (uint)sizeof(xfs_dir_leaf_entry_t));
+		ASSERT(be16_to_cpu(map->base) < XFS_LBSIZE(mp));
+		ASSERT(be16_to_cpu(map->size) < XFS_LBSIZE(mp));
+		if (be16_to_cpu(map->base) == tablesize) {
+			int entry_size = sizeof(xfs_dir_leaf_entry_t);
+			be16_add(&map->base, -entry_size);
+			be16_add(&map->size, entry_size);
 		}
 
-		if ((INT_GET(map->base, ARCH_CONVERT) + INT_GET(map->size, ARCH_CONVERT)) == INT_GET(entry->nameidx, ARCH_CONVERT)) {
+		if ((be16_to_cpu(map->base) + be16_to_cpu(map->size)) ==
+				be16_to_cpu(entry->nameidx)) {
 			before = i;
-		} else if (INT_GET(map->base, ARCH_CONVERT) == (INT_GET(entry->nameidx, ARCH_CONVERT) + entsize)) {
+		} else if (be16_to_cpu(map->base) ==
+				(be16_to_cpu(entry->nameidx) + entsize)) {
 			after = i;
-		} else if (INT_GET(map->size, ARCH_CONVERT) < tmp) {
-			tmp = INT_GET(map->size, ARCH_CONVERT);
+		} else if (be16_to_cpu(map->size) < tmp) {
+			tmp = be16_to_cpu(map->size);
 			smallest = i;
 		}
 	}
@@ -1495,33 +1507,33 @@
 	if ((before >= 0) || (after >= 0)) {
 		if ((before >= 0) && (after >= 0)) {
 			map = &hdr->freemap[before];
-			INT_MOD(map->size, ARCH_CONVERT, entsize);
-			INT_MOD(map->size, ARCH_CONVERT, INT_GET(hdr->freemap[after].size, ARCH_CONVERT));
+			be16_add(&map->size, entsize);
+			be16_add(&map->size, be16_to_cpu(hdr->freemap[after].size));
 			hdr->freemap[after].base = 0;
 			hdr->freemap[after].size = 0;
 		} else if (before >= 0) {
 			map = &hdr->freemap[before];
-			INT_MOD(map->size, ARCH_CONVERT, entsize);
+			be16_add(&map->size, entsize);
 		} else {
 			map = &hdr->freemap[after];
-			INT_COPY(map->base, entry->nameidx, ARCH_CONVERT);
-			INT_MOD(map->size, ARCH_CONVERT, entsize);
+			map->base = entry->nameidx;
+			be16_add(&map->size, entsize);
 		}
 	} else {
 		/*
 		 * Replace smallest region (if it is smaller than free'd entry)
 		 */
 		map = &hdr->freemap[smallest];
-		if (INT_GET(map->size, ARCH_CONVERT) < entsize) {
-			INT_COPY(map->base, entry->nameidx, ARCH_CONVERT);
-			INT_SET(map->size, ARCH_CONVERT, entsize);
+		if (be16_to_cpu(map->size) < entsize) {
+			map->base = entry->nameidx;
+			map->size = cpu_to_be16(entsize);
 		}
 	}
 
 	/*
 	 * Did we remove the first entry?
 	 */
-	if (INT_GET(entry->nameidx, ARCH_CONVERT) == INT_GET(hdr->firstused, ARCH_CONVERT))
+	if (be16_to_cpu(entry->nameidx) == be16_to_cpu(hdr->firstused))
 		smallest = 1;
 	else
 		smallest = 0;
@@ -1529,17 +1541,17 @@
 	/*
 	 * Compress the remaining entries and zero out the removed stuff.
 	 */
-	namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
+	namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, be16_to_cpu(entry->nameidx));
 	memset((char *)namest, 0, entsize);
 	xfs_da_log_buf(trans, bp, XFS_DA_LOGRANGE(leaf, namest, entsize));
 
-	INT_MOD(hdr->namebytes, ARCH_CONVERT, -(entry->namelen));
-	tmp = (INT_GET(hdr->count, ARCH_CONVERT) - index) * (uint)sizeof(xfs_dir_leaf_entry_t);
+	be16_add(&hdr->namebytes, -(entry->namelen));
+	tmp = (be16_to_cpu(hdr->count) - index) * (uint)sizeof(xfs_dir_leaf_entry_t);
 	memmove(entry, entry + 1, tmp);
-	INT_MOD(hdr->count, ARCH_CONVERT, -1);
+	be16_add(&hdr->count, -1);
 	xfs_da_log_buf(trans, bp,
 	    XFS_DA_LOGRANGE(leaf, entry, tmp + (uint)sizeof(*entry)));
-	entry = &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)];
+	entry = &leaf->entries[be16_to_cpu(hdr->count)];
 	memset((char *)entry, 0, sizeof(xfs_dir_leaf_entry_t));
 
 	/*
@@ -1551,15 +1563,16 @@
 	if (smallest) {
 		tmp = XFS_LBSIZE(mp);
 		entry = &leaf->entries[0];
-		for (i = INT_GET(hdr->count, ARCH_CONVERT)-1; i >= 0; entry++, i--) {
-			ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) >= INT_GET(hdr->firstused, ARCH_CONVERT));
-			ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp));
-			if (INT_GET(entry->nameidx, ARCH_CONVERT) < tmp)
-				tmp = INT_GET(entry->nameidx, ARCH_CONVERT);
+		for (i = be16_to_cpu(hdr->count)-1; i >= 0; entry++, i--) {
+			ASSERT(be16_to_cpu(entry->nameidx) >=
+			       be16_to_cpu(hdr->firstused));
+			ASSERT(be16_to_cpu(entry->nameidx) < XFS_LBSIZE(mp));
+			if (be16_to_cpu(entry->nameidx) < tmp)
+				tmp = be16_to_cpu(entry->nameidx);
 		}
-		INT_SET(hdr->firstused, ARCH_CONVERT, tmp);
+		hdr->firstused = cpu_to_be16(tmp);
 		if (!hdr->firstused)
-			INT_SET(hdr->firstused, ARCH_CONVERT, tmp - 1);
+			hdr->firstused = cpu_to_be16(tmp - 1);
 	} else {
 		hdr->holes = 1;		/* mark as needing compaction */
 	}
@@ -1571,9 +1584,9 @@
 	 * "join" the leaf with a sibling if so.
 	 */
 	tmp  = (uint)sizeof(xfs_dir_leaf_hdr_t);
-	tmp += INT_GET(leaf->hdr.count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t);
-	tmp += INT_GET(leaf->hdr.count, ARCH_CONVERT) * ((uint)sizeof(xfs_dir_leaf_name_t) - 1);
-	tmp += INT_GET(leaf->hdr.namebytes, ARCH_CONVERT);
+	tmp += be16_to_cpu(leaf->hdr.count) * (uint)sizeof(xfs_dir_leaf_entry_t);
+	tmp += be16_to_cpu(leaf->hdr.count) * ((uint)sizeof(xfs_dir_leaf_name_t) - 1);
+	tmp += be16_to_cpu(leaf->hdr.namebytes);
 	if (tmp < mp->m_dir_magicpct)
 		return 1;			/* leaf is < 37% full */
 	return 0;
@@ -1599,15 +1612,16 @@
 	ASSERT(save_blk->magic == XFS_DIR_LEAF_MAGIC);
 	drop_leaf = drop_blk->bp->data;
 	save_leaf = save_blk->bp->data;
-	ASSERT(INT_GET(drop_leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
-	ASSERT(INT_GET(save_leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(drop_leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(save_leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
 	drop_hdr = &drop_leaf->hdr;
 	save_hdr = &save_leaf->hdr;
 
 	/*
 	 * Save last hashval from dying block for later Btree fixup.
 	 */
-	drop_blk->hashval = INT_GET(drop_leaf->entries[ drop_leaf->hdr.count-1 ].hashval, ARCH_CONVERT);
+	drop_blk->hashval = be32_to_cpu(drop_leaf->entries[
+			be16_to_cpu(drop_leaf->hdr.count)-1].hashval);
 
 	/*
 	 * Check if we need a temp buffer, or can we do it in place.
@@ -1621,11 +1635,11 @@
 		 */
 		if (xfs_dir_leaf_order(save_blk->bp, drop_blk->bp)) {
 			xfs_dir_leaf_moveents(drop_leaf, 0, save_leaf, 0,
-						 (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp);
+					be16_to_cpu(drop_hdr->count), mp);
 		} else {
 			xfs_dir_leaf_moveents(drop_leaf, 0,
-					      save_leaf, INT_GET(save_hdr->count, ARCH_CONVERT),
-					      (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp);
+					save_leaf, be16_to_cpu(save_hdr->count),
+					be16_to_cpu(drop_hdr->count), mp);
 		}
 	} else {
 		/*
@@ -1639,22 +1653,22 @@
 		tmp_hdr = &tmp_leaf->hdr;
 		tmp_hdr->info = save_hdr->info;	/* struct copy */
 		tmp_hdr->count = 0;
-		INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize);
+		tmp_hdr->firstused = cpu_to_be16(state->blocksize);
 		if (!tmp_hdr->firstused)
-			INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize - 1);
+			tmp_hdr->firstused = cpu_to_be16(state->blocksize - 1);
 		tmp_hdr->namebytes = 0;
 		if (xfs_dir_leaf_order(save_blk->bp, drop_blk->bp)) {
 			xfs_dir_leaf_moveents(drop_leaf, 0, tmp_leaf, 0,
-						 (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp);
+					be16_to_cpu(drop_hdr->count), mp);
 			xfs_dir_leaf_moveents(save_leaf, 0,
-					      tmp_leaf, INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT),
-					      (int)INT_GET(save_hdr->count, ARCH_CONVERT), mp);
+					tmp_leaf, be16_to_cpu(tmp_leaf->hdr.count),
+					be16_to_cpu(save_hdr->count), mp);
 		} else {
 			xfs_dir_leaf_moveents(save_leaf, 0, tmp_leaf, 0,
-						 (int)INT_GET(save_hdr->count, ARCH_CONVERT), mp);
+						 be16_to_cpu(save_hdr->count), mp);
 			xfs_dir_leaf_moveents(drop_leaf, 0,
-					      tmp_leaf, INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT),
-					      (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp);
+					      tmp_leaf, be16_to_cpu(tmp_leaf->hdr.count),
+					      be16_to_cpu(drop_hdr->count), mp);
 		}
 		memcpy(save_leaf, tmp_leaf, state->blocksize);
 		kmem_free(tmpbuffer, state->blocksize);
@@ -1666,7 +1680,8 @@
 	/*
 	 * Copy out last hashval in each block for B-tree code.
 	 */
-	save_blk->hashval = INT_GET(save_leaf->entries[ INT_GET(save_leaf->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT);
+	save_blk->hashval = be32_to_cpu(save_leaf->entries[
+			be16_to_cpu(save_leaf->hdr.count)-1].hashval);
 }
 
 /*========================================================================
@@ -1695,41 +1710,43 @@
 	xfs_dahash_t hashval;
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
-	ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) < (XFS_LBSIZE(args->dp->i_mount)/8));
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.count) < (XFS_LBSIZE(args->dp->i_mount)/8));
 
 	/*
 	 * Binary search.  (note: small blocks will skip this loop)
 	 */
 	hashval = args->hashval;
-	probe = span = INT_GET(leaf->hdr.count, ARCH_CONVERT) / 2;
+	probe = span = be16_to_cpu(leaf->hdr.count) / 2;
 	for (entry = &leaf->entries[probe]; span > 4;
 		   entry = &leaf->entries[probe]) {
 		span /= 2;
-		if (INT_GET(entry->hashval, ARCH_CONVERT) < hashval)
+		if (be32_to_cpu(entry->hashval) < hashval)
 			probe += span;
-		else if (INT_GET(entry->hashval, ARCH_CONVERT) > hashval)
+		else if (be32_to_cpu(entry->hashval) > hashval)
 			probe -= span;
 		else
 			break;
 	}
 	ASSERT((probe >= 0) && \
-	       ((!leaf->hdr.count) || (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT))));
-	ASSERT((span <= 4) || (INT_GET(entry->hashval, ARCH_CONVERT) == hashval));
+	       ((!leaf->hdr.count) || (probe < be16_to_cpu(leaf->hdr.count))));
+	ASSERT((span <= 4) || (be32_to_cpu(entry->hashval) == hashval));
 
 	/*
 	 * Since we may have duplicate hashval's, find the first matching
 	 * hashval in the leaf.
 	 */
-	while ((probe > 0) && (INT_GET(entry->hashval, ARCH_CONVERT) >= hashval)) {
+	while ((probe > 0) && (be32_to_cpu(entry->hashval) >= hashval)) {
 		entry--;
 		probe--;
 	}
-	while ((probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)) && (INT_GET(entry->hashval, ARCH_CONVERT) < hashval)) {
+	while ((probe < be16_to_cpu(leaf->hdr.count)) &&
+	       (be32_to_cpu(entry->hashval) < hashval)) {
 		entry++;
 		probe++;
 	}
-	if ((probe == INT_GET(leaf->hdr.count, ARCH_CONVERT)) || (INT_GET(entry->hashval, ARCH_CONVERT) != hashval)) {
+	if ((probe == be16_to_cpu(leaf->hdr.count)) ||
+	    (be32_to_cpu(entry->hashval) != hashval)) {
 		*index = probe;
 		ASSERT(args->oknoent);
 		return XFS_ERROR(ENOENT);
@@ -1738,8 +1755,9 @@
 	/*
 	 * Duplicate keys may be present, so search all of them for a match.
 	 */
-	while ((probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)) && (INT_GET(entry->hashval, ARCH_CONVERT) == hashval)) {
-		namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
+	while ((probe < be16_to_cpu(leaf->hdr.count)) &&
+	       (be32_to_cpu(entry->hashval) == hashval)) {
+		namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, be16_to_cpu(entry->nameidx));
 		if (entry->namelen == args->namelen &&
 		    namest->name[0] == args->name[0] &&
 		    memcmp(args->name, namest->name, args->namelen) == 0) {
@@ -1751,7 +1769,7 @@
 		probe++;
 	}
 	*index = probe;
-	ASSERT(probe == INT_GET(leaf->hdr.count, ARCH_CONVERT) || args->oknoent);
+	ASSERT(probe == be16_to_cpu(leaf->hdr.count) || args->oknoent);
 	return XFS_ERROR(ENOENT);
 }
 
@@ -1782,26 +1800,26 @@
 	/*
 	 * Set up environment.
 	 */
-	ASSERT(INT_GET(leaf_s->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
-	ASSERT(INT_GET(leaf_d->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf_s->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf_d->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
 	hdr_s = &leaf_s->hdr;
 	hdr_d = &leaf_d->hdr;
-	ASSERT((INT_GET(hdr_s->count, ARCH_CONVERT) > 0) && (INT_GET(hdr_s->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8)));
-	ASSERT(INT_GET(hdr_s->firstused, ARCH_CONVERT) >=
-		((INT_GET(hdr_s->count, ARCH_CONVERT)*sizeof(*entry_s))+sizeof(*hdr_s)));
-	ASSERT(INT_GET(hdr_d->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8));
-	ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >=
-		((INT_GET(hdr_d->count, ARCH_CONVERT)*sizeof(*entry_d))+sizeof(*hdr_d)));
-
-	ASSERT(start_s < INT_GET(hdr_s->count, ARCH_CONVERT));
-	ASSERT(start_d <= INT_GET(hdr_d->count, ARCH_CONVERT));
-	ASSERT(count <= INT_GET(hdr_s->count, ARCH_CONVERT));
+	ASSERT(hdr_s->count && (be16_to_cpu(hdr_s->count) < (XFS_LBSIZE(mp)/8)));
+	ASSERT(be16_to_cpu(hdr_s->firstused) >=
+		((be16_to_cpu(hdr_s->count)*sizeof(*entry_s))+sizeof(*hdr_s)));
+	ASSERT(be16_to_cpu(hdr_d->count) < (XFS_LBSIZE(mp)/8));
+	ASSERT(be16_to_cpu(hdr_d->firstused) >=
+		((be16_to_cpu(hdr_d->count)*sizeof(*entry_d))+sizeof(*hdr_d)));
+
+	ASSERT(start_s < be16_to_cpu(hdr_s->count));
+	ASSERT(start_d <= be16_to_cpu(hdr_d->count));
+	ASSERT(count <= be16_to_cpu(hdr_s->count));
 
 	/*
 	 * Move the entries in the destination leaf up to make a hole?
 	 */
-	if (start_d < INT_GET(hdr_d->count, ARCH_CONVERT)) {
-		tmp  = INT_GET(hdr_d->count, ARCH_CONVERT) - start_d;
+	if (start_d < be16_to_cpu(hdr_d->count)) {
+		tmp  = be16_to_cpu(hdr_d->count) - start_d;
 		tmp *= (uint)sizeof(xfs_dir_leaf_entry_t);
 		entry_s = &leaf_d->entries[start_d];
 		entry_d = &leaf_d->entries[start_d + count];
@@ -1815,32 +1833,33 @@
 	entry_s = &leaf_s->entries[start_s];
 	entry_d = &leaf_d->entries[start_d];
 	for (i = 0; i < count; entry_s++, entry_d++, i++) {
-		ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) >= INT_GET(hdr_s->firstused, ARCH_CONVERT));
+		ASSERT(be16_to_cpu(entry_s->nameidx) >=
+		       be16_to_cpu(hdr_s->firstused));
 		tmp = XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry_s);
-		INT_MOD(hdr_d->firstused, ARCH_CONVERT, -(tmp));
-		entry_d->hashval = entry_s->hashval; /* INT_: direct copy */
-		INT_COPY(entry_d->nameidx, hdr_d->firstused, ARCH_CONVERT);
+		be16_add(&hdr_d->firstused, -(tmp));
+		entry_d->hashval = entry_s->hashval;
+		entry_d->nameidx = hdr_d->firstused;
 		entry_d->namelen = entry_s->namelen;
-		ASSERT(INT_GET(entry_d->nameidx, ARCH_CONVERT) + tmp <= XFS_LBSIZE(mp));
-		memcpy(XFS_DIR_LEAF_NAMESTRUCT(leaf_d, INT_GET(entry_d->nameidx, ARCH_CONVERT)),
-		       XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)), tmp);
-		ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + tmp <= XFS_LBSIZE(mp));
-		memset((char *)XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)),
-		      0, tmp);
-		INT_MOD(hdr_s->namebytes, ARCH_CONVERT, -(entry_d->namelen));
-		INT_MOD(hdr_d->namebytes, ARCH_CONVERT, entry_d->namelen);
-		INT_MOD(hdr_s->count, ARCH_CONVERT, -1);
-		INT_MOD(hdr_d->count, ARCH_CONVERT, +1);
-		tmp  = INT_GET(hdr_d->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t)
+		ASSERT(be16_to_cpu(entry_d->nameidx) + tmp <= XFS_LBSIZE(mp));
+		memcpy(XFS_DIR_LEAF_NAMESTRUCT(leaf_d, be16_to_cpu(entry_d->nameidx)),
+		       XFS_DIR_LEAF_NAMESTRUCT(leaf_s, be16_to_cpu(entry_s->nameidx)), tmp);
+		ASSERT(be16_to_cpu(entry_s->nameidx) + tmp <= XFS_LBSIZE(mp));
+		memset((char *)XFS_DIR_LEAF_NAMESTRUCT(leaf_s,
+					be16_to_cpu(entry_s->nameidx)), 0, tmp);
+		be16_add(&hdr_s->namebytes, -(entry_d->namelen));
+		be16_add(&hdr_d->namebytes, entry_d->namelen);
+		be16_add(&hdr_s->count, -1);
+		be16_add(&hdr_d->count, +1);
+		tmp = be16_to_cpu(hdr_d->count) * (uint)sizeof(xfs_dir_leaf_entry_t)
 				+ (uint)sizeof(xfs_dir_leaf_hdr_t);
-		ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= tmp);
+		ASSERT(be16_to_cpu(hdr_d->firstused) >= tmp);
 
 	}
 
 	/*
 	 * Zero out the entries we just copied.
 	 */
-	if (start_s == INT_GET(hdr_s->count, ARCH_CONVERT)) {
+	if (start_s == be16_to_cpu(hdr_s->count)) {
 		tmp = count * (uint)sizeof(xfs_dir_leaf_entry_t);
 		entry_s = &leaf_s->entries[start_s];
 		ASSERT((char *)entry_s + tmp <= (char *)leaf_s + XFS_LBSIZE(mp));
@@ -1850,14 +1869,14 @@
 		 * Move the remaining entries down to fill the hole,
 		 * then zero the entries at the top.
 		 */
-		tmp  = INT_GET(hdr_s->count, ARCH_CONVERT) - count;
+		tmp  = be16_to_cpu(hdr_s->count) - count;
 		tmp *= (uint)sizeof(xfs_dir_leaf_entry_t);
 		entry_s = &leaf_s->entries[start_s + count];
 		entry_d = &leaf_s->entries[start_s];
 		memcpy(entry_d, entry_s, tmp);
 
 		tmp = count * (uint)sizeof(xfs_dir_leaf_entry_t);
-		entry_s = &leaf_s->entries[INT_GET(hdr_s->count, ARCH_CONVERT)];
+		entry_s = &leaf_s->entries[be16_to_cpu(hdr_s->count)];
 		ASSERT((char *)entry_s + tmp <= (char *)leaf_s + XFS_LBSIZE(mp));
 		memset((char *)entry_s, 0, tmp);
 	}
@@ -1865,11 +1884,14 @@
 	/*
 	 * Fill in the freemap information
 	 */
-	INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, (uint)sizeof(xfs_dir_leaf_hdr_t));
-	INT_MOD(hdr_d->freemap[0].base, ARCH_CONVERT, INT_GET(hdr_d->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t));
-	INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, INT_GET(hdr_d->firstused, ARCH_CONVERT) - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT));
-	INT_SET(hdr_d->freemap[1].base, ARCH_CONVERT, (hdr_d->freemap[2].base = 0));
-	INT_SET(hdr_d->freemap[1].size, ARCH_CONVERT, (hdr_d->freemap[2].size = 0));
+	hdr_d->freemap[0].base = cpu_to_be16(sizeof(xfs_dir_leaf_hdr_t) +
+			be16_to_cpu(hdr_d->count) * sizeof(xfs_dir_leaf_entry_t));
+	hdr_d->freemap[0].size = cpu_to_be16(be16_to_cpu(hdr_d->firstused) -
+			be16_to_cpu(hdr_d->freemap[0].base));
+	hdr_d->freemap[1].base = 0;
+	hdr_d->freemap[1].size = 0;
+	hdr_d->freemap[2].base = 0;
+	hdr_d->freemap[2].size = 0;
 	hdr_s->holes = 1;	/* leaf may not be compact */
 }
 
@@ -1883,13 +1905,15 @@
 
 	leaf1 = leaf1_bp->data;
 	leaf2 = leaf2_bp->data;
-	ASSERT((INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC) &&
-	       (INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC));
-	if ((INT_GET(leaf1->hdr.count, ARCH_CONVERT) > 0) && (INT_GET(leaf2->hdr.count, ARCH_CONVERT) > 0) &&
-	    ((INT_GET(leaf2->entries[ 0 ].hashval, ARCH_CONVERT) <
-	      INT_GET(leaf1->entries[ 0 ].hashval, ARCH_CONVERT)) ||
-	     (INT_GET(leaf2->entries[ INT_GET(leaf2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT) <
-	      INT_GET(leaf1->entries[ INT_GET(leaf1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)))) {
+	ASSERT((be16_to_cpu(leaf1->hdr.info.magic) == XFS_DIR_LEAF_MAGIC) &&
+	       (be16_to_cpu(leaf2->hdr.info.magic) == XFS_DIR_LEAF_MAGIC));
+	if (leaf1->hdr.count && leaf2->hdr.count &&
+	    ((be32_to_cpu(leaf2->entries[0].hashval) <
+	      be32_to_cpu(leaf1->entries[0 ].hashval)) ||
+	     (be32_to_cpu(leaf2->entries[
+			  be16_to_cpu(leaf2->hdr.count)-1].hashval) <
+	      be32_to_cpu(leaf1->entries[
+			  be16_to_cpu(leaf1->hdr.count)-1].hashval)))) {
 		return 1;
 	}
 	return 0;
@@ -1904,12 +1928,12 @@
 	xfs_dir_leafblock_t *leaf;
 
 	leaf = bp->data;
-	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
+	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
 	if (count)
-		*count = INT_GET(leaf->hdr.count, ARCH_CONVERT);
+		*count = be16_to_cpu(leaf->hdr.count);
 	if (!leaf->hdr.count)
 		return(0);
-	return(INT_GET(leaf->entries[ INT_GET(leaf->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT));
+	return be32_to_cpu(leaf->entries[be16_to_cpu(leaf->hdr.count)-1].hashval);
 }
 
 /*
@@ -1940,7 +1964,7 @@
 
 	mp = dp->i_mount;
 	leaf = bp->data;
-	if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) {
+	if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR_LEAF_MAGIC) {
 		*eobp = 1;
 		return XFS_ERROR(ENOENT);	/* XXX wrong code */
 	}
@@ -1955,11 +1979,10 @@
 	 * Re-find our place.
 	 */
 	for (i = entno = 0, entry = &leaf->entries[0];
-		     i < INT_GET(leaf->hdr.count, ARCH_CONVERT);
-			     entry++, i++) {
+		     i < be16_to_cpu(leaf->hdr.count); entry++, i++) {
 
 		namest = XFS_DIR_LEAF_NAMESTRUCT(leaf,
-				    INT_GET(entry->nameidx, ARCH_CONVERT));
+				    be16_to_cpu(entry->nameidx));
 
 		if (unlikely(
 		    ((char *)namest < (char *)leaf) ||
@@ -1969,19 +1992,16 @@
 			xfs_dir_trace_g_du("leaf: corrupted", dp, uio);
 			return XFS_ERROR(EFSCORRUPTED);
 		}
-		if (INT_GET(entry->hashval, ARCH_CONVERT) >= cookhash) {
-			if (   entno < want_entno
-			    && INT_GET(entry->hashval, ARCH_CONVERT)
-							== cookhash) {
+		if (be32_to_cpu(entry->hashval) >= cookhash) {
+			if (entno < want_entno &&
+			    be32_to_cpu(entry->hashval) == cookhash) {
 				/*
 				 * Trying to get to a particular offset in a
 				 * run of equal-hashval entries.
 				 */
 				entno++;
-			} else if (   want_entno > 0
-				   && entno == want_entno
-				   && INT_GET(entry->hashval, ARCH_CONVERT)
-							== cookhash) {
+			} else if (want_entno > 0 && entno == want_entno &&
+				   be32_to_cpu(entry->hashval) == cookhash) {
 				break;
 			} else {
 				entno = 0;
@@ -1990,9 +2010,9 @@
 		}
 	}
 
-	if (i == INT_GET(leaf->hdr.count, ARCH_CONVERT)) {
+	if (i == be16_to_cpu(leaf->hdr.count)) {
 		xfs_dir_trace_g_du("leaf: hash not found", dp, uio);
-		if (!INT_GET(leaf->hdr.info.forw, ARCH_CONVERT))
+		if (!leaf->hdr.info.forw)
 			uio->uio_offset =
 				XFS_DA_MAKE_COOKIE(mp, 0, 0, XFS_DA_MAXHASH);
 		/*
@@ -2011,7 +2031,7 @@
 	/*
 	 * We're synchronized, start copying entries out to the user.
 	 */
-	for (; entno >= 0 && i < INT_GET(leaf->hdr.count, ARCH_CONVERT);
+	for (; entno >= 0 && i < be16_to_cpu(leaf->hdr.count);
 			     entry++, i++, (entno = nextentno)) {
 		int lastresid=0, retval;
 		xfs_dircook_t lastoffset;
@@ -2022,7 +2042,7 @@
 		 * the inode number from this entry.
 		 */
 		namest = XFS_DIR_LEAF_NAMESTRUCT(leaf,
-				    INT_GET(entry->nameidx, ARCH_CONVERT));
+				    be16_to_cpu(entry->nameidx));
 
 		if (unlikely(
 		    ((char *)namest < (char *)leaf) ||
@@ -2036,10 +2056,10 @@
 		xfs_dir_trace_g_duc("leaf: middle cookie  ",
 						   dp, uio, p.cook.o);
 
-		if (i < (INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1)) {
-			nexthash = INT_GET(entry[1].hashval, ARCH_CONVERT);
+		if (i < (be16_to_cpu(leaf->hdr.count) - 1)) {
+			nexthash = be32_to_cpu(entry[1].hashval);
 
-			if (nexthash == INT_GET(entry->hashval, ARCH_CONVERT))
+			if (nexthash == be32_to_cpu(entry->hashval))
 				nextentno = entno + 1;
 			else
 				nextentno = 0;
@@ -2047,8 +2067,7 @@
 			xfs_dir_trace_g_duc("leaf: middle cookie  ",
 						   dp, uio, p.cook.o);
 
-		} else if ((thishash = INT_GET(leaf->hdr.info.forw,
-							ARCH_CONVERT))) {
+		} else if ((thishash = be32_to_cpu(leaf->hdr.info.forw))) {
 			xfs_dabuf_t *bp2;
 			xfs_dir_leafblock_t *leaf2;
 
@@ -2064,9 +2083,9 @@
 			leaf2 = bp2->data;
 
 			if (unlikely(
-			       (INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT)
+			       (be16_to_cpu(leaf2->hdr.info.magic)
 						!= XFS_DIR_LEAF_MAGIC)
-			    || (INT_GET(leaf2->hdr.info.back, ARCH_CONVERT)
+			    || (be32_to_cpu(leaf2->hdr.info.back)
 						!= bno))) {	/* GROT */
 				XFS_CORRUPTION_ERROR("xfs_dir_leaf_getdents_int(3)",
 						     XFS_ERRLEVEL_LOW, mp,
@@ -2076,8 +2095,7 @@
 				return XFS_ERROR(EFSCORRUPTED);
 			}
 
-			nexthash = INT_GET(leaf2->entries[0].hashval,
-								ARCH_CONVERT);
+			nexthash = be32_to_cpu(leaf2->entries[0].hashval);
 			nextentno = -1;
 			XFS_PUT_COOKIE(p.cook, mp, thishash, 0, nexthash);
 			xfs_da_brelse(dp->i_transp, bp2);
@@ -2101,9 +2119,9 @@
 		 * that share the same hashval.  Hopefully the buffer
 		 * provided is big enough to handle it (see pv763517).
 		 */
+		thishash = be32_to_cpu(entry->hashval);
 #if (BITS_PER_LONG == 32)
-		if ((thishash = INT_GET(entry->hashval, ARCH_CONVERT))
-								!= lasthash) {
+		if (thishash != lasthash) {
 			XFS_PUT_COOKIE(lastoffset, mp, bno, entno, thishash);
 			lastresid = uio->uio_resid;
 			lasthash = thishash;
@@ -2112,7 +2130,6 @@
 						   dp, uio, p.cook.o);
 		}
 #else
-		thishash = INT_GET(entry->hashval, ARCH_CONVERT);
 		XFS_PUT_COOKIE(lastoffset, mp, bno, entno, thishash);
 		lastresid = uio->uio_resid;
 #endif /* BITS_PER_LONG == 32 */
diff -urN oldtree/fs/xfs/xfs_dir_leaf.h newtree/fs/xfs/xfs_dir_leaf.h
--- oldtree/fs/xfs/xfs_dir_leaf.h	2006-02-19 11:41:05.400522096 +0000
+++ newtree/fs/xfs/xfs_dir_leaf.h	2006-02-21 15:58:36.740561144 +0000
@@ -68,25 +68,25 @@
 #define XFS_DIR_LEAF_MAPSIZE	3	/* how many freespace slots */
 
 typedef struct xfs_dir_leaf_map {	/* RLE map of free bytes */
-	__uint16_t	base;	 	/* base of free region */
-	__uint16_t	size; 		/* run length of free region */
+	__be16		base;	 	/* base of free region */
+	__be16		size; 		/* run length of free region */
 } xfs_dir_leaf_map_t;
 
 typedef struct xfs_dir_leaf_hdr {	/* constant-structure header block */
 	xfs_da_blkinfo_t info;		/* block type, links, etc. */
-	__uint16_t	count;		/* count of active leaf_entry's */
-	__uint16_t	namebytes;	/* num bytes of name strings stored */
-	__uint16_t	firstused;	/* first used byte in name area */
-	__uint8_t	holes;		/* != 0 if blk needs compaction */
-	__uint8_t	pad1;
+	__be16		count;		/* count of active leaf_entry's */
+	__be16		namebytes;	/* num bytes of name strings stored */
+	__be16		firstused;	/* first used byte in name area */
+	__u8		holes;		/* != 0 if blk needs compaction */
+	__u8		pad1;
 	xfs_dir_leaf_map_t freemap[XFS_DIR_LEAF_MAPSIZE];
 } xfs_dir_leaf_hdr_t;
 
 typedef struct xfs_dir_leaf_entry {	/* sorted on key, not name */
-	xfs_dahash_t	hashval;	/* hash value of name */
-	__uint16_t	nameidx;	/* index into buffer of name */
-	__uint8_t	namelen;	/* length of name string */
-	__uint8_t	pad2;
+	__be32		hashval;	/* hash value of name */
+	__be16		nameidx;	/* index into buffer of name */
+	__u8		namelen;	/* length of name string */
+	__u8		pad2;
 } xfs_dir_leaf_entry_t;
 
 typedef struct xfs_dir_leaf_name {
diff -urN oldtree/fs/xfs/xfs_fsops.c newtree/fs/xfs/xfs_fsops.c
--- oldtree/fs/xfs/xfs_fsops.c	2006-02-19 11:41:05.403521640 +0000
+++ newtree/fs/xfs/xfs_fsops.c	2006-02-21 15:58:21.845825488 +0000
@@ -462,6 +462,7 @@
 {
 	unsigned long	s;
 
+	xfs_icsb_sync_counters_lazy(mp);
 	s = XFS_SB_LOCK(mp);
 	cnt->freedata = mp->m_sb.sb_fdblocks;
 	cnt->freertx = mp->m_sb.sb_frextents;
diff -urN oldtree/fs/xfs/xfs_iget.c newtree/fs/xfs/xfs_iget.c
--- oldtree/fs/xfs/xfs_iget.c	2006-02-19 11:41:05.404521488 +0000
+++ newtree/fs/xfs/xfs_iget.c	2006-02-21 15:58:36.741560992 +0000
@@ -1038,6 +1038,6 @@
 void
 xfs_ifunlock(xfs_inode_t *ip)
 {
-	ASSERT(valusema(&(ip->i_flock)) <= 0);
+	ASSERT(sem_is_locked(&(ip->i_flock)));
 	vsema(&(ip->i_flock));
 }
diff -urN oldtree/fs/xfs/xfs_inode.c newtree/fs/xfs/xfs_inode.c
--- oldtree/fs/xfs/xfs_inode.c	2006-02-19 11:41:05.406521184 +0000
+++ newtree/fs/xfs/xfs_inode.c	2006-02-21 15:58:36.744560536 +0000
@@ -504,7 +504,7 @@
 	switch (INT_GET(dip->di_core.di_aformat, ARCH_CONVERT)) {
 	case XFS_DINODE_FMT_LOCAL:
 		atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip);
-		size = (int)INT_GET(atp->hdr.totsize, ARCH_CONVERT);
+		size = be16_to_cpu(atp->hdr.totsize);
 		error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size);
 		break;
 	case XFS_DINODE_FMT_EXTENTS:
@@ -3071,7 +3071,7 @@
 	XFS_STATS_INC(xs_iflush_count);
 
 	ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS));
-	ASSERT(valusema(&ip->i_flock) <= 0);
+	ASSERT(sem_is_locked(&(ip->i_flock)));
 	ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
 	       ip->i_d.di_nextents > ip->i_df.if_ext_max);
 
@@ -3329,7 +3329,7 @@
 	SPLDECL(s);
 
 	ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS));
-	ASSERT(valusema(&ip->i_flock) <= 0);
+	ASSERT(sem_is_locked(&(ip->i_flock)));
 	ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
 	       ip->i_d.di_nextents > ip->i_df.if_ext_max);
 
diff -urN oldtree/fs/xfs/xfs_inode_item.c newtree/fs/xfs/xfs_inode_item.c
--- oldtree/fs/xfs/xfs_inode_item.c	2006-02-19 11:41:05.407521032 +0000
+++ newtree/fs/xfs/xfs_inode_item.c	2006-02-21 15:58:36.749559776 +0000
@@ -794,7 +794,7 @@
 	 * inode flush completed and the inode was taken off the AIL.
 	 * So, just get out.
 	 */
-	if ((valusema(&(ip->i_flock)) > 0)  ||
+	if (!sem_is_locked(&(ip->i_flock)) ||
 	    ((iip->ili_item.li_flags & XFS_LI_IN_AIL) == 0)) {
 		iip->ili_pushbuf_flag = 0;
 		xfs_iunlock(ip, XFS_ILOCK_SHARED);
@@ -816,7 +816,7 @@
 			 * If not, we can flush it async.
 			 */
 			dopush = ((iip->ili_item.li_flags & XFS_LI_IN_AIL) &&
-				  (valusema(&(ip->i_flock)) <= 0));
+				  sem_is_locked(&(ip->i_flock)));
 			iip->ili_pushbuf_flag = 0;
 			xfs_iunlock(ip, XFS_ILOCK_SHARED);
 			xfs_buftrace("INODE ITEM PUSH", bp);
@@ -864,7 +864,7 @@
 	ip = iip->ili_inode;
 
 	ASSERT(ismrlocked(&(ip->i_lock), MR_ACCESS));
-	ASSERT(valusema(&(ip->i_flock)) <= 0);
+	ASSERT(sem_is_locked(&(ip->i_flock)));
 	/*
 	 * Since we were able to lock the inode's flush lock and
 	 * we found it on the AIL, the inode must be dirty.  This
diff -urN oldtree/fs/xfs/xfs_mount.c newtree/fs/xfs/xfs_mount.c
--- oldtree/fs/xfs/xfs_mount.c	2006-02-19 11:41:05.416519664 +0000
+++ newtree/fs/xfs/xfs_mount.c	2006-02-21 15:58:21.860823208 +0000
@@ -51,11 +51,31 @@
 STATIC void	xfs_uuid_unmount(xfs_mount_t *mp);
 STATIC void	xfs_unmountfs_wait(xfs_mount_t *);
 
+
+#ifdef HAVE_PERCPU_SB
+STATIC void	xfs_icsb_destroy_counters(xfs_mount_t *);
+STATIC void	xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t, int);
+STATIC void	xfs_icsb_sync_counters(xfs_mount_t *);
+STATIC int	xfs_icsb_modify_counters(xfs_mount_t *, xfs_sb_field_t,
+						int, int);
+STATIC int	xfs_icsb_modify_counters_locked(xfs_mount_t *, xfs_sb_field_t,
+						int, int);
+
+#else
+
+#define xfs_icsb_destroy_counters(mp)			do { } while (0)
+#define xfs_icsb_balance_counter(mp, a, b)		do { } while (0)
+#define xfs_icsb_sync_counters(mp)			do { } while (0)
+#define xfs_icsb_modify_counters(mp, a, b, c)		do { } while (0)
+#define xfs_icsb_modify_counters_locked(mp, a, b, c)	do { } while (0)
+
+#endif
+
 static const struct {
-    short offset;
-    short type;     /* 0 = integer
-		* 1 = binary / string (no translation)
-		*/
+	short offset;
+	short type;	/* 0 = integer
+			 * 1 = binary / string (no translation)
+			 */
 } xfs_sb_info[] = {
     { offsetof(xfs_sb_t, sb_magicnum),   0 },
     { offsetof(xfs_sb_t, sb_blocksize),  0 },
@@ -113,7 +133,11 @@
 {
 	xfs_mount_t *mp;
 
-	mp = kmem_zalloc(sizeof(*mp), KM_SLEEP);
+	mp = kmem_zalloc(sizeof(xfs_mount_t), KM_SLEEP);
+
+	if (xfs_icsb_init_counters(mp)) {
+		mp->m_flags |= XFS_MOUNT_NO_PERCPU_SB;
+	}
 
 	AIL_LOCKINIT(&mp->m_ail_lock, "xfs_ail");
 	spinlock_init(&mp->m_sb_lock, "xfs_sb");
@@ -136,8 +160,8 @@
  */
 void
 xfs_mount_free(
-	xfs_mount_t *mp,
-	int	    remove_bhv)
+	xfs_mount_t	*mp,
+	int		remove_bhv)
 {
 	if (mp->m_ihash)
 		xfs_ihash_free(mp);
@@ -177,6 +201,7 @@
 		VFS_REMOVEBHV(vfsp, &mp->m_bhv);
 	}
 
+	xfs_icsb_destroy_counters(mp);
 	kmem_free(mp, sizeof(xfs_mount_t));
 }
 
@@ -527,6 +552,10 @@
 		ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
 	}
 
+	xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0);
+	xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0);
+	xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0);
+
 	mp->m_sb_bp = bp;
 	xfs_buf_relse(bp);
 	ASSERT(XFS_BUF_VALUSEMA(bp) > 0);
@@ -1154,6 +1183,9 @@
 	sbp = xfs_getsb(mp, 0);
 	if (!(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY ||
 		XFS_FORCED_SHUTDOWN(mp))) {
+
+		xfs_icsb_sync_counters(mp);
+
 		/*
 		 * mark shared-readonly if desired
 		 */
@@ -1227,7 +1259,6 @@
 
 	xfs_trans_log_buf(tp, bp, first, last);
 }
-
 /*
  * xfs_mod_incore_sb_unlocked() is a utility routine common used to apply
  * a delta to a specified field in the in-core superblock.  Simply
@@ -1237,7 +1268,7 @@
  *
  * The SB_LOCK must be held when this routine is called.
  */
-STATIC int
+int
 xfs_mod_incore_sb_unlocked(xfs_mount_t *mp, xfs_sb_field_t field,
 			int delta, int rsvd)
 {
@@ -1405,13 +1436,30 @@
 {
 	unsigned long	s;
 	int	status;
+  
+	/* check for per-cpu counters */
+	switch (field) {
+#ifdef HAVE_PERCPU_SB
+	case XFS_SBS_ICOUNT:
+	case XFS_SBS_IFREE:
+	case XFS_SBS_FDBLOCKS:
+		if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) {
+			status = xfs_icsb_modify_counters(mp, field,
+							delta, rsvd);
+			break;
+		}
+		/* FALLTHROUGH */
+#endif
+	default:
+		s = XFS_SB_LOCK(mp);
+		status = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd);
+		XFS_SB_UNLOCK(mp, s);
+		break;
+	}
 
-	s = XFS_SB_LOCK(mp);
-	status = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd);
-	XFS_SB_UNLOCK(mp, s);
 	return status;
 }
-
+  
 /*
  * xfs_mod_incore_sb_batch() is used to change more than one field
  * in the in-core superblock structure at a time.  This modification
@@ -1445,8 +1493,26 @@
 		 * from the loop so we'll fall into the undo loop
 		 * below.
 		 */
-		status = xfs_mod_incore_sb_unlocked(mp, msbp->msb_field,
-						    msbp->msb_delta, rsvd);
+		switch (msbp->msb_field) {
+#ifdef HAVE_PERCPU_SB
+		case XFS_SBS_ICOUNT:
+		case XFS_SBS_IFREE:
+		case XFS_SBS_FDBLOCKS:
+			if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) {
+				status = xfs_icsb_modify_counters_locked(mp,
+							msbp->msb_field,
+							msbp->msb_delta, rsvd);
+				break;
+			}
+			/* FALLTHROUGH */
+#endif
+		default:
+			status = xfs_mod_incore_sb_unlocked(mp,
+						msbp->msb_field,
+						msbp->msb_delta, rsvd);
+			break;
+		}
+
 		if (status != 0) {
 			break;
 		}
@@ -1463,8 +1529,28 @@
 	if (status != 0) {
 		msbp--;
 		while (msbp >= msb) {
-			status = xfs_mod_incore_sb_unlocked(mp,
-				    msbp->msb_field, -(msbp->msb_delta), rsvd);
+			switch (msbp->msb_field) {
+#ifdef HAVE_PERCPU_SB
+			case XFS_SBS_ICOUNT:
+			case XFS_SBS_IFREE:
+			case XFS_SBS_FDBLOCKS:
+				if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) {
+					status =
+					    xfs_icsb_modify_counters_locked(mp,
+							msbp->msb_field,
+							-(msbp->msb_delta),
+							rsvd);
+					break;
+				}
+				/* FALLTHROUGH */
+#endif
+			default:
+				status = xfs_mod_incore_sb_unlocked(mp,
+							msbp->msb_field,
+							-(msbp->msb_delta),
+							rsvd);
+				break;
+			}
 			ASSERT(status == 0);
 			msbp--;
 		}
@@ -1577,3 +1663,445 @@
 	xfs_mod_sb(tp, fields);
 	xfs_trans_commit(tp, 0, NULL);
 }
+
+
+#ifdef HAVE_PERCPU_SB
+/*
+ * Per-cpu incore superblock counters
+ *
+ * Simple concept, difficult implementation
+ *
+ * Basically, replace the incore superblock counters with a distributed per cpu
+ * counter for contended fields (e.g.  free block count).
+ *
+ * Difficulties arise in that the incore sb is used for ENOSPC checking, and
+ * hence needs to be accurately read when we are running low on space. Hence
+ * there is a method to enable and disable the per-cpu counters based on how
+ * much "stuff" is available in them.
+ *
+ * Basically, a counter is enabled if there is enough free resource to justify
+ * running a per-cpu fast-path. If the per-cpu counter runs out (i.e. a local
+ * ENOSPC), then we disable the counters to synchronise all callers and
+ * re-distribute the available resources.
+ *
+ * If, once we redistributed the available resources, we still get a failure,
+ * we disable the per-cpu counter and go through the slow path.
+ *
+ * The slow path is the current xfs_mod_incore_sb() function.  This means that
+ * when we disable a per-cpu counter, we need to drain it's resources back to
+ * the global superblock. We do this after disabling the counter to prevent
+ * more threads from queueing up on the counter.
+ *
+ * Essentially, this means that we still need a lock in the fast path to enable
+ * synchronisation between the global counters and the per-cpu counters. This
+ * is not a problem because the lock will be local to a CPU almost all the time
+ * and have little contention except when we get to ENOSPC conditions.
+ *
+ * Basically, this lock becomes a barrier that enables us to lock out the fast
+ * path while we do things like enabling and disabling counters and
+ * synchronising the counters.
+ *
+ * Locking rules:
+ *
+ * 	1. XFS_SB_LOCK() before picking up per-cpu locks
+ * 	2. per-cpu locks always picked up via for_each_online_cpu() order
+ * 	3. accurate counter sync requires XFS_SB_LOCK + per cpu locks
+ * 	4. modifying per-cpu counters requires holding per-cpu lock
+ * 	5. modifying global counters requires holding XFS_SB_LOCK
+ *	6. enabling or disabling a counter requires holding the XFS_SB_LOCK
+ *	   and _none_ of the per-cpu locks.
+ *
+ * Disabled counters are only ever re-enabled by a balance operation
+ * that results in more free resources per CPU than a given threshold.
+ * To ensure counters don't remain disabled, they are rebalanced when
+ * the global resource goes above a higher threshold (i.e. some hysteresis
+ * is present to prevent thrashing).
+ *
+ * Note: hotplug CPUs not yet supported
+ */
+int
+xfs_icsb_init_counters(
+	xfs_mount_t	*mp)
+{
+	xfs_icsb_cnts_t *cntp;
+	int		i;
+
+	mp->m_sb_cnts = alloc_percpu(xfs_icsb_cnts_t);
+	if (mp->m_sb_cnts == NULL)
+		return -ENOMEM;
+
+	for_each_online_cpu(i) {
+		cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);
+		spin_lock_init(&cntp->icsb_lock);
+	}
+	/*
+	 * start with all counters disabled so that the
+	 * initial balance kicks us off correctly
+	 */
+	mp->m_icsb_counters = -1;
+	return 0;
+}
+
+STATIC void
+xfs_icsb_destroy_counters(
+	xfs_mount_t	*mp)
+{
+	if (mp->m_sb_cnts)
+		free_percpu(mp->m_sb_cnts);
+}
+
+
+STATIC inline void
+xfs_icsb_lock_all_counters(
+	xfs_mount_t	*mp)
+{
+	xfs_icsb_cnts_t *cntp;
+	int		i;
+
+	for_each_online_cpu(i) {
+		cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);
+		spin_lock(&cntp->icsb_lock);
+	}
+}
+
+STATIC inline void
+xfs_icsb_unlock_all_counters(
+	xfs_mount_t	*mp)
+{
+	xfs_icsb_cnts_t *cntp;
+	int		i;
+
+	for_each_online_cpu(i) {
+		cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);
+		spin_unlock(&cntp->icsb_lock);
+	}
+}
+
+STATIC void
+xfs_icsb_count(
+	xfs_mount_t	*mp,
+	xfs_icsb_cnts_t	*cnt,
+	int		flags)
+{
+	xfs_icsb_cnts_t *cntp;
+	int		i;
+
+	memset(cnt, 0, sizeof(xfs_icsb_cnts_t));
+
+	if (!(flags & XFS_ICSB_LAZY_COUNT))
+		xfs_icsb_lock_all_counters(mp);
+
+	for_each_online_cpu(i) {
+		cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);
+		cnt->icsb_icount += cntp->icsb_icount;
+		cnt->icsb_ifree += cntp->icsb_ifree;
+		cnt->icsb_fdblocks += cntp->icsb_fdblocks;
+	}
+
+	if (!(flags & XFS_ICSB_LAZY_COUNT))
+		xfs_icsb_unlock_all_counters(mp);
+}
+
+STATIC int
+xfs_icsb_counter_disabled(
+	xfs_mount_t	*mp,
+	xfs_sb_field_t	field)
+{
+	ASSERT((field >= XFS_SBS_ICOUNT) && (field <= XFS_SBS_FDBLOCKS));
+	return test_bit(field, &mp->m_icsb_counters);
+}
+
+STATIC int
+xfs_icsb_disable_counter(
+	xfs_mount_t	*mp,
+	xfs_sb_field_t	field)
+{
+	xfs_icsb_cnts_t	cnt;
+
+	ASSERT((field >= XFS_SBS_ICOUNT) && (field <= XFS_SBS_FDBLOCKS));
+
+	xfs_icsb_lock_all_counters(mp);
+	if (!test_and_set_bit(field, &mp->m_icsb_counters)) {
+		/* drain back to superblock */
+
+		xfs_icsb_count(mp, &cnt, XFS_ICSB_SB_LOCKED|XFS_ICSB_LAZY_COUNT);
+		switch(field) {
+		case XFS_SBS_ICOUNT:
+			mp->m_sb.sb_icount = cnt.icsb_icount;
+			break;
+		case XFS_SBS_IFREE:
+			mp->m_sb.sb_ifree = cnt.icsb_ifree;
+			break;
+		case XFS_SBS_FDBLOCKS:
+			mp->m_sb.sb_fdblocks = cnt.icsb_fdblocks;
+			break;
+		default:
+			BUG();
+		}
+	}
+
+	xfs_icsb_unlock_all_counters(mp);
+
+	return 0;
+}
+
+STATIC void
+xfs_icsb_enable_counter(
+	xfs_mount_t	*mp,
+	xfs_sb_field_t	field,
+	uint64_t	count,
+	uint64_t	resid)
+{
+	xfs_icsb_cnts_t	*cntp;
+	int		i;
+
+	ASSERT((field >= XFS_SBS_ICOUNT) && (field <= XFS_SBS_FDBLOCKS));
+
+	xfs_icsb_lock_all_counters(mp);
+	for_each_online_cpu(i) {
+		cntp = per_cpu_ptr(mp->m_sb_cnts, i);
+		switch (field) {
+		case XFS_SBS_ICOUNT:
+			cntp->icsb_icount = count + resid;
+			break;
+		case XFS_SBS_IFREE:
+			cntp->icsb_ifree = count + resid;
+			break;
+		case XFS_SBS_FDBLOCKS:
+			cntp->icsb_fdblocks = count + resid;
+			break;
+		default:
+			BUG();
+			break;
+		}
+		resid = 0;
+	}
+	clear_bit(field, &mp->m_icsb_counters);
+	xfs_icsb_unlock_all_counters(mp);
+}
+
+STATIC void
+xfs_icsb_sync_counters_int(
+	xfs_mount_t	*mp,
+	int		flags)
+{
+	xfs_icsb_cnts_t	cnt;
+	int		s;
+
+	/* Pass 1: lock all counters */
+	if ((flags & XFS_ICSB_SB_LOCKED) == 0)
+		s = XFS_SB_LOCK(mp);
+
+	xfs_icsb_count(mp, &cnt, flags);
+
+	/* Step 3: update mp->m_sb fields */
+	if (!xfs_icsb_counter_disabled(mp, XFS_SBS_ICOUNT))
+		mp->m_sb.sb_icount = cnt.icsb_icount;
+	if (!xfs_icsb_counter_disabled(mp, XFS_SBS_IFREE))
+		mp->m_sb.sb_ifree = cnt.icsb_ifree;
+	if (!xfs_icsb_counter_disabled(mp, XFS_SBS_FDBLOCKS))
+		mp->m_sb.sb_fdblocks = cnt.icsb_fdblocks;
+
+	if ((flags & XFS_ICSB_SB_LOCKED) == 0)
+		XFS_SB_UNLOCK(mp, s);
+}
+
+/*
+ * Accurate update of per-cpu counters to incore superblock
+ */
+STATIC void
+xfs_icsb_sync_counters(
+	xfs_mount_t	*mp)
+{
+	xfs_icsb_sync_counters_int(mp, 0);
+}
+
+/*
+ * lazy addition used for things like df, background sb syncs, etc
+ */
+void
+xfs_icsb_sync_counters_lazy(
+	xfs_mount_t	*mp)
+{
+	xfs_icsb_sync_counters_int(mp, XFS_ICSB_LAZY_COUNT);
+}
+
+/*
+ * Balance and enable/disable counters as necessary.
+ *
+ * Thresholds for re-enabling counters are somewhat magic.
+ * inode counts are chosen to be the same number as single
+ * on disk allocation chunk per CPU, and free blocks is
+ * something far enough zero that we aren't going thrash
+ * when we get near ENOSPC.
+ */
+#define XFS_ICSB_INO_CNTR_REENABLE	64
+#define XFS_ICSB_FDBLK_CNTR_REENABLE	512
+STATIC void
+xfs_icsb_balance_counter(
+	xfs_mount_t	*mp,
+	xfs_sb_field_t  field,
+	int		flags)
+{
+	uint64_t	count, resid = 0;
+	int		weight = num_online_cpus();
+	int		s;
+
+	if (!(flags & XFS_ICSB_SB_LOCKED))
+		s = XFS_SB_LOCK(mp);
+
+	/* disable counter and sync counter */
+	xfs_icsb_disable_counter(mp, field);
+
+	/* update counters  - first CPU gets residual*/
+	switch (field) {
+	case XFS_SBS_ICOUNT:
+		count = mp->m_sb.sb_icount;
+		resid = do_div(count, weight);
+		if (count < XFS_ICSB_INO_CNTR_REENABLE)
+			goto out;
+		break;
+	case XFS_SBS_IFREE:
+		count = mp->m_sb.sb_ifree;
+		resid = do_div(count, weight);
+		if (count < XFS_ICSB_INO_CNTR_REENABLE)
+			goto out;
+		break;
+	case XFS_SBS_FDBLOCKS:
+		count = mp->m_sb.sb_fdblocks;
+		resid = do_div(count, weight);
+		if (count < XFS_ICSB_FDBLK_CNTR_REENABLE)
+			goto out;
+		break;
+	default:
+		BUG();
+		break;
+	}
+
+	xfs_icsb_enable_counter(mp, field, count, resid);
+out:
+	if (!(flags & XFS_ICSB_SB_LOCKED))
+		XFS_SB_UNLOCK(mp, s);
+}
+
+STATIC int
+xfs_icsb_modify_counters_int(
+	xfs_mount_t	*mp,
+	xfs_sb_field_t	field,
+	int		delta,
+	int		rsvd,
+	int		flags)
+{
+	xfs_icsb_cnts_t	*icsbp;
+	long long	lcounter;	/* long counter for 64 bit fields */
+	int		cpu, s, locked = 0;
+	int		ret = 0, balance_done = 0;
+
+again:
+	cpu = get_cpu();
+	icsbp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, cpu),
+	spin_lock(&icsbp->icsb_lock);
+	if (unlikely(xfs_icsb_counter_disabled(mp, field)))
+		goto slow_path;
+
+	switch (field) {
+	case XFS_SBS_ICOUNT:
+		lcounter = icsbp->icsb_icount;
+		lcounter += delta;
+		if (unlikely(lcounter < 0))
+			goto slow_path;
+		icsbp->icsb_icount = lcounter;
+		break;
+
+	case XFS_SBS_IFREE:
+		lcounter = icsbp->icsb_ifree;
+		lcounter += delta;
+		if (unlikely(lcounter < 0))
+			goto slow_path;
+		icsbp->icsb_ifree = lcounter;
+		break;
+
+	case XFS_SBS_FDBLOCKS:
+		BUG_ON((mp->m_resblks - mp->m_resblks_avail) != 0);
+
+		lcounter = icsbp->icsb_fdblocks;
+		lcounter += delta;
+		if (unlikely(lcounter < 0))
+			goto slow_path;
+		icsbp->icsb_fdblocks = lcounter;
+		break;
+	default:
+		BUG();
+		break;
+	}
+	spin_unlock(&icsbp->icsb_lock);
+	put_cpu();
+	if (locked)
+		XFS_SB_UNLOCK(mp, s);
+	return 0;
+
+	/*
+	 * The slow path needs to be run with the SBLOCK
+	 * held so that we prevent other threads from
+	 * attempting to run this path at the same time.
+	 * this provides exclusion for the balancing code,
+	 * and exclusive fallback if the balance does not
+	 * provide enough resources to continue in an unlocked
+	 * manner.
+	 */
+slow_path:
+	spin_unlock(&icsbp->icsb_lock);
+	put_cpu();
+
+	/* need to hold superblock incase we need
+	 * to disable a counter */
+	if (!(flags & XFS_ICSB_SB_LOCKED)) {
+		s = XFS_SB_LOCK(mp);
+		locked = 1;
+		flags |= XFS_ICSB_SB_LOCKED;
+	}
+	if (!balance_done) {
+		xfs_icsb_balance_counter(mp, field, flags);
+		balance_done = 1;
+		goto again;
+	} else {
+		/*
+		 * we might not have enough on this local
+		 * cpu to allocate for a bulk request.
+		 * We need to drain this field from all CPUs
+		 * and disable the counter fastpath
+		 */
+		xfs_icsb_disable_counter(mp, field);
+	}
+
+	ret = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd);
+
+	if (locked)
+		XFS_SB_UNLOCK(mp, s);
+	return ret;
+}
+
+STATIC int
+xfs_icsb_modify_counters(
+	xfs_mount_t	*mp,
+	xfs_sb_field_t	field,
+	int		delta,
+	int		rsvd)
+{
+	return xfs_icsb_modify_counters_int(mp, field, delta, rsvd, 0);
+}
+
+/*
+ * Called when superblock is already locked
+ */
+STATIC int
+xfs_icsb_modify_counters_locked(
+	xfs_mount_t	*mp,
+	xfs_sb_field_t	field,
+	int		delta,
+	int		rsvd)
+{
+	return xfs_icsb_modify_counters_int(mp, field, delta,
+						rsvd, XFS_ICSB_SB_LOCKED);
+}
+#endif
diff -urN oldtree/fs/xfs/xfs_mount.h newtree/fs/xfs/xfs_mount.h
--- oldtree/fs/xfs/xfs_mount.h	2006-02-19 11:41:05.417519512 +0000
+++ newtree/fs/xfs/xfs_mount.h	2006-02-21 15:58:21.866822296 +0000
@@ -267,6 +267,32 @@
 #define XFS_IODONE(vfsp) \
 	(*(mp)->m_io_ops.xfs_iodone)(vfsp)
 
+#ifdef HAVE_PERCPU_SB
+
+/*
+ * Valid per-cpu incore superblock counters. Note that if you add new counters,
+ * you may need to define new counter disabled bit field descriptors as there
+ * are more possible fields in the superblock that can fit in a bitfield on a
+ * 32 bit platform. The XFS_SBS_* values for the current current counters just
+ * fit.
+ */
+typedef struct xfs_icsb_cnts {
+	uint64_t	icsb_fdblocks;
+	uint64_t	icsb_ifree;
+	uint64_t	icsb_icount;
+	spinlock_t	icsb_lock;
+} xfs_icsb_cnts_t;
+
+#define XFS_ICSB_SB_LOCKED	(1 << 0)	/* sb already locked */
+#define XFS_ICSB_LAZY_COUNT	(1 << 1)	/* accuracy not needed */
+
+extern int	xfs_icsb_init_counters(struct xfs_mount *);
+extern void	xfs_icsb_sync_counters_lazy(struct xfs_mount *);
+
+#else
+#define xfs_icsb_init_counters(mp)	(0)
+#define xfs_icsb_sync_counters_lazy(mp)	do { } while (0)
+#endif
 
 typedef struct xfs_mount {
 	bhv_desc_t		m_bhv;		/* vfs xfs behavior */
@@ -372,6 +398,10 @@
 	struct xfs_qmops	m_qm_ops;	/* vector of XQM ops */
 	struct xfs_ioops	m_io_ops;	/* vector of I/O ops */
 	atomic_t		m_active_trans;	/* number trans frozen */
+#ifdef HAVE_PERCPU_SB
+	xfs_icsb_cnts_t		*m_sb_cnts;	/* per-cpu superblock counters */
+	unsigned long		m_icsb_counters; /* disabled per-cpu counters */
+#endif
 } xfs_mount_t;
 
 /*
@@ -386,8 +416,6 @@
 #define XFS_MOUNT_FS_SHUTDOWN	(1ULL << 4)	/* atomic stop of all filesystem
 						   operations, typically for
 						   disk errors in metadata */
-#define XFS_MOUNT_NOATIME	(1ULL << 5)	/* don't modify inode access
-						   times on reads */
 #define XFS_MOUNT_RETERR	(1ULL << 6)     /* return alignment errors to
 						   user */
 #define XFS_MOUNT_NOALIGN	(1ULL << 7)	/* turn off stripe alignment
@@ -411,6 +439,8 @@
 #define XFS_MOUNT_DIRSYNC	(1ULL << 21)	/* synchronous directory ops */
 #define XFS_MOUNT_COMPAT_IOSIZE	(1ULL << 22)	/* don't report large preferred
 						 * I/O size in stat() */
+#define XFS_MOUNT_NO_PERCPU_SB	(1ULL << 23)	/* don't use per-cpu superblock
+						   counters */
 
 
 /*
@@ -548,6 +578,8 @@
 extern int	xfs_unmountfs_writesb(xfs_mount_t *);
 extern int	xfs_unmount_flush(xfs_mount_t *, int);
 extern int	xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int, int);
+extern int	xfs_mod_incore_sb_unlocked(xfs_mount_t *, xfs_sb_field_t,
+			int, int);
 extern int	xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *,
 			uint, int);
 extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int);
diff -urN oldtree/fs/xfs/xfs_trans.h newtree/fs/xfs/xfs_trans.h
--- oldtree/fs/xfs/xfs_trans.h	2006-02-19 11:41:05.420519056 +0000
+++ newtree/fs/xfs/xfs_trans.h	2006-02-21 15:58:21.871821536 +0000
@@ -380,7 +380,7 @@
 	xfs_trans_header_t	t_header;	/* header for in-log trans */
 	unsigned int		t_busy_free;	/* busy descs free */
 	xfs_log_busy_chunk_t	t_busy;		/* busy/async free blocks */
-        xfs_pflags_t            t_pflags;       /* saved pflags state */
+	unsigned long		t_pflags;	/* saved process flags state */
 } xfs_trans_t;
 
 #endif	/* __KERNEL__ */
diff -urN oldtree/fs/xfs/xfs_vfsops.c newtree/fs/xfs/xfs_vfsops.c
--- oldtree/fs/xfs/xfs_vfsops.c	2006-02-19 11:41:05.423518600 +0000
+++ newtree/fs/xfs/xfs_vfsops.c	2006-02-21 15:58:21.883819712 +0000
@@ -55,7 +55,7 @@
 #include "xfs_clnt.h"
 #include "xfs_fsops.h"
 
-STATIC int xfs_sync(bhv_desc_t *, int, cred_t *);
+STATIC int	xfs_sync(bhv_desc_t *, int, cred_t *);
 
 int
 xfs_init(void)
@@ -77,11 +77,12 @@
 						 "xfs_bmap_free_item");
 	xfs_btree_cur_zone = kmem_zone_init(sizeof(xfs_btree_cur_t),
 					    "xfs_btree_cur");
-	xfs_inode_zone = kmem_zone_init(sizeof(xfs_inode_t), "xfs_inode");
 	xfs_trans_zone = kmem_zone_init(sizeof(xfs_trans_t), "xfs_trans");
 	xfs_da_state_zone =
 		kmem_zone_init(sizeof(xfs_da_state_t), "xfs_da_state");
 	xfs_dabuf_zone = kmem_zone_init(sizeof(xfs_dabuf_t), "xfs_dabuf");
+	xfs_ifork_zone = kmem_zone_init(sizeof(xfs_ifork_t), "xfs_ifork");
+	xfs_acl_zone_init(xfs_acl_zone, "xfs_acl");
 
 	/*
 	 * The size of the zone allocated buf log item is the maximum
@@ -93,17 +94,30 @@
 				(((XFS_MAX_BLOCKSIZE / XFS_BLI_CHUNK) /
 				  NBWORD) * sizeof(int))),
 			       "xfs_buf_item");
-	xfs_efd_zone = kmem_zone_init((sizeof(xfs_efd_log_item_t) +
-				       ((XFS_EFD_MAX_FAST_EXTENTS - 1) * sizeof(xfs_extent_t))),
+	xfs_efd_zone =
+		kmem_zone_init((sizeof(xfs_efd_log_item_t) +
+			       ((XFS_EFD_MAX_FAST_EXTENTS - 1) *
+				 sizeof(xfs_extent_t))),
 				      "xfs_efd_item");
-	xfs_efi_zone = kmem_zone_init((sizeof(xfs_efi_log_item_t) +
-				       ((XFS_EFI_MAX_FAST_EXTENTS - 1) * sizeof(xfs_extent_t))),
+	xfs_efi_zone =
+		kmem_zone_init((sizeof(xfs_efi_log_item_t) +
+			       ((XFS_EFI_MAX_FAST_EXTENTS - 1) *
+				 sizeof(xfs_extent_t))),
 				      "xfs_efi_item");
-	xfs_ifork_zone = kmem_zone_init(sizeof(xfs_ifork_t), "xfs_ifork");
-	xfs_ili_zone = kmem_zone_init(sizeof(xfs_inode_log_item_t), "xfs_ili");
-	xfs_chashlist_zone = kmem_zone_init(sizeof(xfs_chashlist_t),
-					    "xfs_chashlist");
-	xfs_acl_zone_init(xfs_acl_zone, "xfs_acl");
+
+	/*
+	 * These zones warrant special memory allocator hints
+	 */
+	xfs_inode_zone =
+		kmem_zone_init_flags(sizeof(xfs_inode_t), "xfs_inode",
+					KM_ZONE_HWALIGN | KM_ZONE_RECLAIM |
+					KM_ZONE_SPREAD, NULL);
+	xfs_ili_zone =
+		kmem_zone_init_flags(sizeof(xfs_inode_log_item_t), "xfs_ili",
+					KM_ZONE_SPREAD, NULL);
+	xfs_chashlist_zone =
+		kmem_zone_init_flags(sizeof(xfs_chashlist_t), "xfs_chashlist",
+					KM_ZONE_SPREAD, NULL);
 
 	/*
 	 * Allocate global trace buffers.
@@ -258,8 +272,6 @@
 		mp->m_inoadd = XFS_INO64_OFFSET;
 	}
 #endif
-	if (ap->flags & XFSMNT_NOATIME)
-		mp->m_flags |= XFS_MOUNT_NOATIME;
 	if (ap->flags & XFSMNT_RETERR)
 		mp->m_flags |= XFS_MOUNT_RETERR;
 	if (ap->flags & XFSMNT_NOALIGN)
@@ -654,11 +666,6 @@
 	xfs_mount_t	*mp = XFS_BHVTOM(bdp);
 	int		error;
 
-	if (args->flags & XFSMNT_NOATIME)
-		mp->m_flags |= XFS_MOUNT_NOATIME;
-	else
-		mp->m_flags &= ~XFS_MOUNT_NOATIME;
-
 	if (args->flags & XFSMNT_BARRIER)
 		mp->m_flags |= XFS_MOUNT_BARRIER;
 	else
@@ -814,6 +821,7 @@
 
 	statp->f_type = XFS_SB_MAGIC;
 
+	xfs_icsb_sync_counters_lazy(mp);
 	s = XFS_SB_LOCK(mp);
 	statp->f_bsize = sbp->sb_blocksize;
 	lsize = sbp->sb_logstart ? sbp->sb_logblocks : 0;
diff -urN oldtree/include/acpi/acconfig.h newtree/include/acpi/acconfig.h
--- oldtree/include/acpi/acconfig.h	2006-02-19 11:41:05.426518144 +0000
+++ newtree/include/acpi/acconfig.h	2006-02-21 15:58:10.419562544 +0000
@@ -63,7 +63,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20060127
+#define ACPI_CA_VERSION                 0x20060210
 
 /*
  * OS name, used for the _OS object.  The _OS object is essentially obsolete,
diff -urN oldtree/include/acpi/acdisasm.h newtree/include/acpi/acdisasm.h
--- oldtree/include/acpi/acdisasm.h	2006-02-19 11:41:05.427517992 +0000
+++ newtree/include/acpi/acdisasm.h	2006-02-21 15:58:10.428561176 +0000
@@ -70,6 +70,7 @@
 struct acpi_op_walk_info {
 	u32 level;
 	u32 bit_offset;
+	u32 flags;
 	struct acpi_walk_state *walk_state;
 };
 
diff -urN oldtree/include/acpi/acutils.h newtree/include/acpi/acutils.h
--- oldtree/include/acpi/acutils.h	2006-02-19 11:41:05.443515560 +0000
+++ newtree/include/acpi/acutils.h	2006-02-21 15:58:10.444558744 +0000
@@ -483,8 +483,6 @@
 acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc,
 			     u8 ** end_tag);
 
-u8 acpi_ut_generate_checksum(u8 * buffer, u32 length);
-
 u32 acpi_ut_dword_byte_swap(u32 value);
 
 void acpi_ut_set_integer_width(u8 revision);
diff -urN oldtree/include/acpi/pdc_intel.h newtree/include/acpi/pdc_intel.h
--- oldtree/include/acpi/pdc_intel.h	2006-02-19 11:41:05.444515408 +0000
+++ newtree/include/acpi/pdc_intel.h	2006-02-21 15:58:10.445558592 +0000
@@ -18,6 +18,11 @@
 					 ACPI_PDC_C_C1_HALT | \
 					 ACPI_PDC_P_FFH)
 
+#define ACPI_PDC_EST_CAPABILITY_SWSMP	(ACPI_PDC_SMP_C1PT | \
+					 ACPI_PDC_C_C1_HALT | \
+					 ACPI_PDC_SMP_P_SWCOORD | \
+					 ACPI_PDC_P_FFH)
+
 #define ACPI_PDC_C_CAPABILITY_SMP	(ACPI_PDC_SMP_C2C3 | \
 					 ACPI_PDC_SMP_C1PT | \
 					 ACPI_PDC_C_C1_HALT)
diff -urN oldtree/include/acpi/processor.h newtree/include/acpi/processor.h
--- oldtree/include/acpi/processor.h	2006-02-19 11:41:05.446515104 +0000
+++ newtree/include/acpi/processor.h	2006-02-21 15:58:10.445558592 +0000
@@ -3,6 +3,7 @@
 
 #include <linux/kernel.h>
 #include <linux/config.h>
+#include <linux/cpu.h>
 
 #include <asm/acpi.h>
 
@@ -18,6 +19,17 @@
 
 #define ACPI_PDC_REVISION_ID		0x1
 
+#define ACPI_PSD_REV0_REVISION		0 /* Support for _PSD as in ACPI 3.0 */
+#define ACPI_PSD_REV0_ENTRIES		5
+
+/*
+ * Types of coordination defined in ACPI 3.0. Same macros can be used across
+ * P, C and T states
+ */
+#define DOMAIN_COORD_TYPE_SW_ALL	0xfc
+#define DOMAIN_COORD_TYPE_SW_ANY	0xfd
+#define DOMAIN_COORD_TYPE_HW_ALL	0xfe
+
 /* Power Management */
 
 struct acpi_processor_cx;
@@ -66,6 +78,14 @@
 
 /* Performance Management */
 
+struct acpi_psd_package {
+	acpi_integer num_entries;
+	acpi_integer revision;
+	acpi_integer domain;
+	acpi_integer coord_type;
+	acpi_integer num_processors;
+} __attribute__ ((packed));
+
 struct acpi_pct_register {
 	u8 descriptor;
 	u16 length;
@@ -92,7 +112,9 @@
 	struct acpi_pct_register status_register;
 	unsigned int state_count;
 	struct acpi_processor_px *states;
-
+	struct acpi_psd_package domain_info;
+	cpumask_t shared_cpu_map;
+	unsigned int shared_type;
 };
 
 /* Throttling Control */
@@ -161,6 +183,9 @@
 	} piix4;
 };
 
+extern int acpi_processor_preregister_performance(
+		struct acpi_processor_performance **performance);
+
 extern int acpi_processor_register_performance(struct acpi_processor_performance
 					       *performance, unsigned int cpu);
 extern void acpi_processor_unregister_performance(struct
diff -urN oldtree/include/asm-alpha/serial.h newtree/include/asm-alpha/serial.h
--- oldtree/include/asm-alpha/serial.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-alpha/serial.h	2006-02-21 15:58:36.751559472 +0000
@@ -15,11 +15,11 @@
 
 /* Standard COM flags (except for COM4, because of the 8514 problem) */
 #ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
+#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ)
+#define STD_COM4_FLAGS (UPF_BOOT_AUTOCONF | UPF_AUTO_IRQ)
 #else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
+#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
+#define STD_COM4_FLAGS UPF_BOOT_AUTOCONF
 #endif
 
 #define SERIAL_PORT_DFNS			\
diff -urN oldtree/include/asm-arm/arch-pxa/audio.h newtree/include/asm-arm/arch-pxa/audio.h
--- oldtree/include/asm-arm/arch-pxa/audio.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-arm/arch-pxa/audio.h	2006-02-21 15:58:11.178447176 +0000
@@ -6,8 +6,8 @@
 #include <sound/pcm.h>
 
 typedef struct {
-	int (*startup)(snd_pcm_substream_t *, void *);
-	void (*shutdown)(snd_pcm_substream_t *, void *);
+	int (*startup)(struct snd_pcm_substream *, void *);
+	void (*shutdown)(struct snd_pcm_substream *, void *);
 	void (*suspend)(void *);
 	void (*resume)(void *);
 	void *priv;
diff -urN oldtree/include/asm-frv/checksum.h newtree/include/asm-frv/checksum.h
--- oldtree/include/asm-frv/checksum.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-frv/checksum.h	2006-02-21 15:58:36.761557952 +0000
@@ -43,7 +43,7 @@
  * here even more important to align src and dst on a 32-bit (or even
  * better 64-bit) boundary
  */
-extern unsigned int csum_partial_copy_from_user(const char *src, char *dst,
+extern unsigned int csum_partial_copy_from_user(const char __user *src, char *dst,
 						int len, int sum, int *csum_err);
 
 #define csum_partial_copy_nocheck(src, dst, len, sum)	\
diff -urN oldtree/include/asm-frv/highmem.h newtree/include/asm-frv/highmem.h
--- oldtree/include/asm-frv/highmem.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-frv/highmem.h	2006-02-21 15:58:36.763557648 +0000
@@ -135,7 +135,7 @@
 
 	default:
 		BUG();
-		return 0;
+		return NULL;
 	}
 }
 
diff -urN oldtree/include/asm-frv/io.h newtree/include/asm-frv/io.h
--- oldtree/include/asm-frv/io.h	2006-02-19 11:41:05.526502944 +0000
+++ newtree/include/asm-frv/io.h	2006-02-21 15:58:36.764557496 +0000
@@ -41,13 +41,13 @@
 //#define __iormb() asm volatile("membar")
 //#define __iowmb() asm volatile("membar")
 
-#define __raw_readb(addr) __builtin_read8((void *) (addr))
-#define __raw_readw(addr) __builtin_read16((void *) (addr))
-#define __raw_readl(addr) __builtin_read32((void *) (addr))
-
-#define __raw_writeb(datum, addr) __builtin_write8((void *) (addr), datum)
-#define __raw_writew(datum, addr) __builtin_write16((void *) (addr), datum)
-#define __raw_writel(datum, addr) __builtin_write32((void *) (addr), datum)
+#define __raw_readb __builtin_read8
+#define __raw_readw __builtin_read16
+#define __raw_readl __builtin_read32
+
+#define __raw_writeb(datum, addr) __builtin_write8(addr, datum)
+#define __raw_writew(datum, addr) __builtin_write16(addr, datum)
+#define __raw_writel(datum, addr) __builtin_write32(addr, datum)
 
 static inline void io_outsb(unsigned int addr, const void *buf, int len)
 {
@@ -129,12 +129,12 @@
 
 static inline uint8_t inb(unsigned long addr)
 {
-	return __builtin_read8((void *)addr);
+	return __builtin_read8((void __iomem *)addr);
 }
 
 static inline uint16_t inw(unsigned long addr)
 {
-	uint16_t ret = __builtin_read16((void *)addr);
+	uint16_t ret = __builtin_read16((void __iomem *)addr);
 
 	if (__is_PCI_IO(addr))
 		ret = _swapw(ret);
@@ -144,7 +144,7 @@
 
 static inline uint32_t inl(unsigned long addr)
 {
-	uint32_t ret = __builtin_read32((void *)addr);
+	uint32_t ret = __builtin_read32((void __iomem *)addr);
 
 	if (__is_PCI_IO(addr))
 		ret = _swapl(ret);
@@ -154,21 +154,21 @@
 
 static inline void outb(uint8_t datum, unsigned long addr)
 {
-	__builtin_write8((void *)addr, datum);
+	__builtin_write8((void __iomem *)addr, datum);
 }
 
 static inline void outw(uint16_t datum, unsigned long addr)
 {
 	if (__is_PCI_IO(addr))
 		datum = _swapw(datum);
-	__builtin_write16((void *)addr, datum);
+	__builtin_write16((void __iomem *)addr, datum);
 }
 
 static inline void outl(uint32_t datum, unsigned long addr)
 {
 	if (__is_PCI_IO(addr))
 		datum = _swapl(datum);
-	__builtin_write32((void *)addr, datum);
+	__builtin_write32((void __iomem *)addr, datum);
 }
 
 #define inb_p(addr)	inb(addr)
@@ -190,12 +190,12 @@
 
 static inline uint8_t readb(const volatile void __iomem *addr)
 {
-	return __builtin_read8((volatile uint8_t __force *) addr);
+	return __builtin_read8((__force void volatile __iomem *) addr);
 }
 
 static inline uint16_t readw(const volatile void __iomem *addr)
 {
-	uint16_t ret =	__builtin_read16((volatile uint16_t __force *)addr);
+	uint16_t ret =	__builtin_read16((__force void volatile __iomem *)addr);
 
 	if (__is_PCI_MEM(addr))
 		ret = _swapw(ret);
@@ -204,7 +204,7 @@
 
 static inline uint32_t readl(const volatile void __iomem *addr)
 {
-	uint32_t ret =	__builtin_read32((volatile uint32_t __force *)addr);
+	uint32_t ret =	__builtin_read32((__force void volatile __iomem *)addr);
 
 	if (__is_PCI_MEM(addr))
 		ret = _swapl(ret);
@@ -218,7 +218,7 @@
 
 static inline void writeb(uint8_t datum, volatile void __iomem *addr)
 {
-	__builtin_write8((volatile uint8_t __force *) addr, datum);
+	__builtin_write8(addr, datum);
 	if (__is_PCI_MEM(addr))
 		__flush_PCI_writes();
 }
@@ -228,7 +228,7 @@
 	if (__is_PCI_MEM(addr))
 		datum = _swapw(datum);
 
-	__builtin_write16((volatile uint16_t __force *) addr, datum);
+	__builtin_write16(addr, datum);
 	if (__is_PCI_MEM(addr))
 		__flush_PCI_writes();
 }
@@ -238,7 +238,7 @@
 	if (__is_PCI_MEM(addr))
 		datum = _swapl(datum);
 
-	__builtin_write32((volatile uint32_t __force *) addr, datum);
+	__builtin_write32(addr, datum);
 	if (__is_PCI_MEM(addr))
 		__flush_PCI_writes();
 }
@@ -272,7 +272,7 @@
 	return __ioremap(physaddr, size, IOMAP_FULL_CACHING);
 }
 
-extern void iounmap(void __iomem *addr);
+extern void iounmap(void volatile __iomem *addr);
 
 static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
 {
diff -urN oldtree/include/asm-frv/mb-regs.h newtree/include/asm-frv/mb-regs.h
--- oldtree/include/asm-frv/mb-regs.h	2006-02-19 11:41:05.527502792 +0000
+++ newtree/include/asm-frv/mb-regs.h	2006-02-21 15:58:36.764557496 +0000
@@ -16,6 +16,17 @@
 #include <asm/sections.h>
 #include <asm/mem-layout.h>
 
+#ifndef __ASSEMBLY__
+/* gcc builtins, annotated */
+
+unsigned long __builtin_read8(volatile void __iomem *);
+unsigned long __builtin_read16(volatile void __iomem *);
+unsigned long __builtin_read32(volatile void __iomem *);
+void __builtin_write8(volatile void __iomem *, unsigned char);
+void __builtin_write16(volatile void __iomem *, unsigned short);
+void __builtin_write32(volatile void __iomem *, unsigned long);
+#endif
+
 #define __region_IO	KERNEL_IO_START	/* the region from 0xe0000000 to 0xffffffff has suitable
 					 * protection laid over the top for use in memory-mapped
 					 * I/O
@@ -59,7 +70,7 @@
 #define __region_PCI_MEM	(__region_CS2 + 0x08000000UL)
 #define __flush_PCI_writes()						\
 do {									\
-	__builtin_write8((volatile void *) __region_PCI_MEM, 0);	\
+	__builtin_write8((volatile void __iomem *) __region_PCI_MEM, 0);	\
 } while(0)
 
 #define __is_PCI_IO(addr) \
@@ -83,15 +94,15 @@
 #define __set_LEDS(X)							\
 do {									\
 	if (mb93090_mb00_detected)					\
-		__builtin_write32((void *) __addr_LEDS(), ~(X));	\
+		__builtin_write32((void __iomem *) __addr_LEDS(), ~(X));	\
 } while (0)
 #else
 #define __set_LEDS(X)
 #endif
 
 #define __addr_LCD()		(__region_CS2 + 0x01200008UL)
-#define __get_LCD(B)		__builtin_read32((volatile void *) (B))
-#define __set_LCD(B,X)		__builtin_write32((volatile void *) (B), (X))
+#define __get_LCD(B)		__builtin_read32((volatile void __iomem *) (B))
+#define __set_LCD(B,X)		__builtin_write32((volatile void __iomem *) (B), (X))
 
 #define LCD_D			0x000000ff		/* LCD data bus */
 #define LCD_RW			0x00000100		/* LCD R/W signal */
@@ -161,11 +172,11 @@
 #define __get_CLKIN()		66000000UL
 
 #define __addr_LEDS()		(__region_CS2 + 0x00000023UL)
-#define __set_LEDS(X)		__builtin_write8((volatile void *) __addr_LEDS(), (X))
+#define __set_LEDS(X)		__builtin_write8((volatile void __iomem *) __addr_LEDS(), (X))
 
 #define __addr_FPGATR()		(__region_CS2 + 0x00000030UL)
-#define __set_FPGATR(X)		__builtin_write32((volatile void *) __addr_FPGATR(), (X))
-#define __get_FPGATR()		__builtin_read32((volatile void *) __addr_FPGATR())
+#define __set_FPGATR(X)		__builtin_write32((volatile void __iomem *) __addr_FPGATR(), (X))
+#define __get_FPGATR()		__builtin_read32((volatile void __iomem *) __addr_FPGATR())
 
 #define MB93093_FPGA_FPGATR_AUDIO_CLK	0x00000003
 
@@ -180,7 +191,7 @@
 #define MB93093_FPGA_SWR_PUSHSWMASK	(0x1F<<26)
 #define MB93093_FPGA_SWR_PUSHSW4	(1<<29)
 
-#define __addr_FPGA_SWR		((volatile void *)(__region_CS2 + 0x28UL))
+#define __addr_FPGA_SWR		((volatile void __iomem *)(__region_CS2 + 0x28UL))
 #define __get_FPGA_PUSHSW1_5()	(__builtin_read32(__addr_FPGA_SWR) & MB93093_FPGA_SWR_PUSHSWMASK)
 
 
diff -urN oldtree/include/asm-frv/pgtable.h newtree/include/asm-frv/pgtable.h
--- oldtree/include/asm-frv/pgtable.h	2006-02-19 11:41:05.529502488 +0000
+++ newtree/include/asm-frv/pgtable.h	2006-02-21 15:58:36.765557344 +0000
@@ -173,7 +173,7 @@
 #define set_pte(pteptr, pteval)				\
 do {							\
 	*(pteptr) = (pteval);				\
-	asm volatile("dcf %M0" :: "U"(*pteptr));	\
+	asm volatile("dcf %M0" :: "m"(*pteptr));	\
 } while(0)
 #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
@@ -209,7 +209,7 @@
 #define set_pgd(pgdptr, pgdval)				\
 do {							\
 	memcpy((pgdptr), &(pgdval), sizeof(pgd_t));	\
-	asm volatile("dcf %M0" :: "U"(*(pgdptr)));	\
+	asm volatile("dcf %M0" :: "m"(*(pgdptr)));	\
 } while(0)
 
 static inline pud_t *pud_offset(pgd_t *pgd, unsigned long address)
@@ -396,28 +396,28 @@
 static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
 	int i = test_and_clear_bit(_PAGE_BIT_DIRTY, ptep);
-	asm volatile("dcf %M0" :: "U"(*ptep));
+	asm volatile("dcf %M0" :: "m"(*ptep));
 	return i;
 }
 
 static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
 	int i = test_and_clear_bit(_PAGE_BIT_ACCESSED, ptep);
-	asm volatile("dcf %M0" :: "U"(*ptep));
+	asm volatile("dcf %M0" :: "m"(*ptep));
 	return i;
 }
 
 static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	unsigned long x = xchg(&ptep->pte, 0);
-	asm volatile("dcf %M0" :: "U"(*ptep));
+	asm volatile("dcf %M0" :: "m"(*ptep));
 	return __pte(x);
 }
 
 static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	set_bit(_PAGE_BIT_WP, ptep);
-	asm volatile("dcf %M0" :: "U"(*ptep));
+	asm volatile("dcf %M0" :: "m"(*ptep));
 }
 
 /*
diff -urN oldtree/include/asm-frv/serial.h newtree/include/asm-frv/serial.h
--- oldtree/include/asm-frv/serial.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-frv/serial.h	2006-02-21 15:58:36.766557192 +0000
@@ -14,6 +14,6 @@
  */
 #define BASE_BAUD 0
 
-#define STD_COM_FLAGS		ASYNC_BOOT_AUTOCONF
+#define STD_COM_FLAGS		UPF_BOOT_AUTOCONF
 
 #define SERIAL_PORT_DFNS
diff -urN oldtree/include/asm-frv/signal.h newtree/include/asm-frv/signal.h
--- oldtree/include/asm-frv/signal.h	2006-02-19 11:41:05.529502488 +0000
+++ newtree/include/asm-frv/signal.h	2006-02-21 15:58:36.766557192 +0000
@@ -114,13 +114,13 @@
 	__sighandler_t sa_handler;
 	old_sigset_t sa_mask;
 	unsigned long sa_flags;
-	void (*sa_restorer)(void);
+	__sigrestore_t sa_restorer;
 };
 
 struct sigaction {
 	__sighandler_t sa_handler;
 	unsigned long sa_flags;
-	void (*sa_restorer)(void);
+	__sigrestore_t sa_restorer;
 	sigset_t sa_mask;		/* mask last for extensibility */
 };
 
@@ -146,7 +146,7 @@
 #endif /* __KERNEL__ */
 
 typedef struct sigaltstack {
-	void *ss_sp;
+	void __user *ss_sp;
 	int ss_flags;
 	size_t ss_size;
 } stack_t;
diff -urN oldtree/include/asm-frv/uaccess.h newtree/include/asm-frv/uaccess.h
--- oldtree/include/asm-frv/uaccess.h	2006-02-19 11:41:05.532502032 +0000
+++ newtree/include/asm-frv/uaccess.h	2006-02-21 15:58:36.767557040 +0000
@@ -22,7 +22,7 @@
 
 #define HAVE_ARCH_UNMAPPED_AREA	/* we decide where to put mmaps */
 
-#define __ptr(x) ((unsigned long *)(x))
+#define __ptr(x) ((unsigned long __force *)(x))
 
 #define VERIFY_READ	0
 #define VERIFY_WRITE	1
@@ -64,7 +64,7 @@
 
 #define __range_ok(addr,size) ___range_ok((unsigned long) (addr), (unsigned long) (size))
 
-#define access_ok(type,addr,size) (__range_ok((addr), (size)) == 0)
+#define access_ok(type,addr,size) (__range_ok((void __user *)(addr), (size)) == 0)
 #define __access_ok(addr,size) (__range_ok((addr), (size)) == 0)
 
 /*
@@ -97,6 +97,7 @@
 	int __pu_err = 0;						\
 									\
 	typeof(*(ptr)) __pu_val = (x);					\
+	__chk_user_ptr(ptr);						\
 									\
 	switch (sizeof (*(ptr))) {					\
 	case 1:								\
@@ -120,7 +121,7 @@
 
 #define put_user(x, ptr)			\
 ({						\
-	typeof(&*ptr) _p = (ptr);		\
+	typeof(*(ptr)) __user *_p = (ptr);	\
 	int _e;					\
 						\
 	_e = __range_ok(_p, sizeof(*_p));	\
@@ -175,33 +176,44 @@
  */
 #define __get_user(x, ptr)						\
 ({									\
-	typeof(*(ptr)) __gu_val = 0;					\
 	int __gu_err = 0;						\
+	__chk_user_ptr(ptr);						\
 									\
 	switch (sizeof(*(ptr))) {					\
-	case 1:								\
-		__get_user_asm(__gu_err, *(u8*)&__gu_val, ptr, "ub", "=r"); \
+	case 1: {							\
+		unsigned char __gu_val;					\
+		__get_user_asm(__gu_err, __gu_val, ptr, "ub", "=r");	\
+		(x) = *(__force __typeof__(*(ptr)) *) &__gu_val;	\
 		break;							\
-	case 2:								\
-		__get_user_asm(__gu_err, *(u16*)&__gu_val, ptr, "uh", "=r"); \
+	}								\
+	case 2: {							\
+		unsigned short __gu_val;				\
+		__get_user_asm(__gu_err, __gu_val, ptr, "uh", "=r");	\
+		(x) = *(__force __typeof__(*(ptr)) *) &__gu_val;	\
 		break;							\
-	case 4:								\
-		__get_user_asm(__gu_err, *(u32*)&__gu_val, ptr, "", "=r"); \
+	}								\
+	case 4: {							\
+		unsigned int __gu_val;					\
+		__get_user_asm(__gu_err, __gu_val, ptr, "", "=r");	\
+		(x) = *(__force __typeof__(*(ptr)) *) &__gu_val;	\
 		break;							\
-	case 8:								\
-		__get_user_asm(__gu_err, *(u64*)&__gu_val, ptr, "d", "=e"); \
+	}								\
+	case 8: {							\
+		unsigned long long __gu_val;				\
+		__get_user_asm(__gu_err, __gu_val, ptr, "d", "=e");	\
+		(x) = *(__force __typeof__(*(ptr)) *) &__gu_val;	\
 		break;							\
+	}								\
 	default:							\
 		__gu_err = __get_user_bad();				\
 		break;							\
 	}								\
-	(x) = __gu_val;							\
 	__gu_err;							\
 })
 
 #define get_user(x, ptr)			\
 ({						\
-	typeof(&*ptr) _p = (ptr);		\
+	const typeof(*(ptr)) __user *_p = (ptr);\
 	int _e;					\
 						\
 	_e = __range_ok(_p, sizeof(*_p));	\
@@ -248,19 +260,20 @@
 /*
  *
  */
+#define ____force(x) (__force void *)(void __user *)(x)
 #ifdef CONFIG_MMU
 extern long __memset_user(void *dst, unsigned long count);
 extern long __memcpy_user(void *dst, const void *src, unsigned long count);
 
-#define clear_user(dst,count)			__memset_user((dst), (count))
-#define __copy_from_user_inatomic(to, from, n)	__memcpy_user((to), (from), (n))
-#define __copy_to_user_inatomic(to, from, n)	__memcpy_user((to), (from), (n))
+#define clear_user(dst,count)			__memset_user(____force(dst), (count))
+#define __copy_from_user_inatomic(to, from, n)	__memcpy_user((to), ____force(from), (n))
+#define __copy_to_user_inatomic(to, from, n)	__memcpy_user(____force(to), (from), (n))
 
 #else
 
-#define clear_user(dst,count)			(memset((dst), 0, (count)), 0)
-#define __copy_from_user_inatomic(to, from, n)	(memcpy((to), (from), (n)), 0)
-#define __copy_to_user_inatomic(to, from, n)	(memcpy((to), (from), (n)), 0)
+#define clear_user(dst,count)			(memset(____force(dst), 0, (count)), 0)
+#define __copy_from_user_inatomic(to, from, n)	(memcpy((to), ____force(from), (n)), 0)
+#define __copy_to_user_inatomic(to, from, n)	(memcpy(____force(to), (from), (n)), 0)
 
 #endif
 
@@ -278,7 +291,7 @@
        return __copy_from_user_inatomic(to, from, n);
 }
 
-static inline long copy_from_user(void *to, const void *from, unsigned long n)
+static inline long copy_from_user(void *to, const void __user *from, unsigned long n)
 {
 	unsigned long ret = n;
 
@@ -291,16 +304,13 @@
 	return ret;
 }
 
-static inline long copy_to_user(void *to, const void *from, unsigned long n)
+static inline long copy_to_user(void __user *to, const void *from, unsigned long n)
 {
 	return likely(__access_ok(to, n)) ? __copy_to_user(to, from, n) : n;
 }
 
-#define copy_to_user_ret(to,from,n,retval)	({ if (copy_to_user(to,from,n)) return retval; })
-#define copy_from_user_ret(to,from,n,retval)	({ if (copy_from_user(to,from,n)) return retval; })
-
-extern long strncpy_from_user(char *dst, const char *src, long count);
-extern long strnlen_user(const char *src, long count);
+extern long strncpy_from_user(char *dst, const char __user *src, long count);
+extern long strnlen_user(const char __user *src, long count);
 
 #define strlen_user(str) strnlen_user(str, 32767)
 
diff -urN oldtree/include/asm-frv/unistd.h newtree/include/asm-frv/unistd.h
--- oldtree/include/asm-frv/unistd.h	2006-02-19 11:41:05.532502032 +0000
+++ newtree/include/asm-frv/unistd.h	2006-02-21 15:58:36.768556888 +0000
@@ -306,7 +306,7 @@
 #define __NR_mknodat		297
 #define __NR_fchownat		298
 #define __NR_futimesat		299
-#define __NR_newfstatat		300
+#define __NR_fstatat64		300
 #define __NR_unlinkat		301
 #define __NR_renameat		302
 #define __NR_linkat		303
diff -urN oldtree/include/asm-generic/mutex-dec.h newtree/include/asm-generic/mutex-dec.h
--- oldtree/include/asm-generic/mutex-dec.h	2006-02-19 11:41:05.536501424 +0000
+++ newtree/include/asm-generic/mutex-dec.h	2006-02-21 15:58:31.977285272 +0000
@@ -17,13 +17,14 @@
  * it wasn't 1 originally. This function MUST leave the value lower than
  * 1 even when the "1" assertion wasn't true.
  */
-#define __mutex_fastpath_lock(count, fail_fn)				\
-do {									\
-	if (unlikely(atomic_dec_return(count) < 0))			\
-		fail_fn(count);						\
-	else								\
-		smp_mb();						\
-} while (0)
+static inline void
+__mutex_fastpath_lock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *))
+{
+	if (unlikely(atomic_dec_return(count) < 0))
+		fail_fn(count);
+	else
+		smp_mb();
+}
 
 /**
  *  __mutex_fastpath_lock_retval - try to take the lock by moving the count
@@ -36,7 +37,7 @@
  * or anything the slow path function returns.
  */
 static inline int
-__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
+__mutex_fastpath_lock_retval(atomic_t *count, fastcall int (*fail_fn)(atomic_t *))
 {
 	if (unlikely(atomic_dec_return(count) < 0))
 		return fail_fn(count);
@@ -59,12 +60,13 @@
  * __mutex_slowpath_needs_to_unlock() macro needs to return 1, it needs
  * to return 0 otherwise.
  */
-#define __mutex_fastpath_unlock(count, fail_fn)				\
-do {									\
-	smp_mb();							\
-	if (unlikely(atomic_inc_return(count) <= 0))			\
-		fail_fn(count);						\
-} while (0)
+static inline void
+__mutex_fastpath_unlock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *))
+{
+	smp_mb();
+	if (unlikely(atomic_inc_return(count) <= 0))
+		fail_fn(count);
+}
 
 #define __mutex_slowpath_needs_to_unlock()		1
 
diff -urN oldtree/include/asm-generic/mutex-xchg.h newtree/include/asm-generic/mutex-xchg.h
--- oldtree/include/asm-generic/mutex-xchg.h	2006-02-19 11:41:05.537501272 +0000
+++ newtree/include/asm-generic/mutex-xchg.h	2006-02-21 15:58:31.978285120 +0000
@@ -3,7 +3,7 @@
  *
  * Generic implementation of the mutex fastpath, based on xchg().
  *
- * NOTE: An xchg based implementation is less optimal than an atomic
+ * NOTE: An xchg based implementation might be less optimal than an atomic
  *       decrement/increment based implementation. If your architecture
  *       has a reasonable atomic dec/inc then you should probably use
  *	 asm-generic/mutex-dec.h instead, or you could open-code an
@@ -22,14 +22,14 @@
  * wasn't 1 originally. This function MUST leave the value lower than 1
  * even when the "1" assertion wasn't true.
  */
-#define __mutex_fastpath_lock(count, fail_fn)				\
-do {									\
-	if (unlikely(atomic_xchg(count, 0) != 1))			\
-		fail_fn(count);						\
-	else								\
-		smp_mb();						\
-} while (0)
-
+static inline void
+__mutex_fastpath_lock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *))
+{
+	if (unlikely(atomic_xchg(count, 0) != 1))
+		fail_fn(count);
+	else
+		smp_mb();
+}
 
 /**
  *  __mutex_fastpath_lock_retval - try to take the lock by moving the count
@@ -42,7 +42,7 @@
  * or anything the slow path function returns
  */
 static inline int
-__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
+__mutex_fastpath_lock_retval(atomic_t *count, fastcall int (*fail_fn)(atomic_t *))
 {
 	if (unlikely(atomic_xchg(count, 0) != 1))
 		return fail_fn(count);
@@ -64,12 +64,13 @@
  * __mutex_slowpath_needs_to_unlock() macro needs to return 1, it needs
  * to return 0 otherwise.
  */
-#define __mutex_fastpath_unlock(count, fail_fn)				\
-do {									\
-	smp_mb();							\
-	if (unlikely(atomic_xchg(count, 1) != 0))			\
-		fail_fn(count);						\
-} while (0)
+static inline void
+__mutex_fastpath_unlock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *))
+{
+	smp_mb();
+	if (unlikely(atomic_xchg(count, 1) != 0))
+		fail_fn(count);
+}
 
 #define __mutex_slowpath_needs_to_unlock()		0
 
diff -urN oldtree/include/asm-generic/vmlinux.lds.h newtree/include/asm-generic/vmlinux.lds.h
--- oldtree/include/asm-generic/vmlinux.lds.h	2006-02-19 11:41:05.537501272 +0000
+++ newtree/include/asm-generic/vmlinux.lds.h	2006-02-21 15:58:12.648223736 +0000
@@ -58,6 +58,13 @@
 		VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .;		\
 	}								\
 									\
+	/* Kernel symbol table: GPL-future-only symbols */		\
+	__ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
+		VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .;	\
+		*(__ksymtab_gpl_future)					\
+		VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .;	\
+	}								\
+									\
 	/* Kernel symbol table: Normal symbols */			\
 	__kcrctab         : AT(ADDR(__kcrctab) - LOAD_OFFSET) {		\
 		VMLINUX_SYMBOL(__start___kcrctab) = .;			\
@@ -72,6 +79,13 @@
 		VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .;		\
 	}								\
 									\
+	/* Kernel symbol table: GPL-future-only symbols */		\
+	__kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
+		VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .;	\
+		*(__kcrctab_gpl_future)					\
+		VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .;	\
+	}								\
+									\
 	/* Kernel symbol table: strings */				\
         __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
 		*(__ksymtab_strings)					\
diff -urN oldtree/include/asm-i386/mach-es7000/mach_mpparse.h newtree/include/asm-i386/mach-es7000/mach_mpparse.h
--- oldtree/include/asm-i386/mach-es7000/mach_mpparse.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-i386/mach-es7000/mach_mpparse.h	2006-02-21 15:58:22.773684432 +0000
@@ -30,7 +30,8 @@
 	return 0;
 }
 
-static inline int es7000_check_dsdt()
+#ifdef CONFIG_ACPI
+static inline int es7000_check_dsdt(void)
 {
 	struct acpi_table_header *header = NULL;
 	if(!acpi_get_table_header_early(ACPI_DSDT, &header))
@@ -54,6 +55,11 @@
 	}
 	return 0;
 }
-
+#else
+static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+	return 0;
+}
+#endif
 
 #endif /* __ASM_MACH_MPPARSE_H */
diff -urN oldtree/include/asm-i386/pci.h newtree/include/asm-i386/pci.h
--- oldtree/include/asm-i386/pci.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-i386/pci.h	2006-02-21 15:58:17.951417528 +0000
@@ -4,6 +4,26 @@
 #include <linux/config.h>
 
 #ifdef __KERNEL__
+
+struct pci_sysdata {
+	int		domain;		/* PCI domain */
+	int		node;		/* NUMA node */
+};
+extern struct pci_sysdata pci_default_sysdata;
+
+#ifdef CONFIG_PCI_DOMAINS
+static inline int pci_domain_nr(struct pci_bus *bus)
+{
+	struct pci_sysdata *sd = bus->sysdata;
+	return sd->domain;
+}
+
+static inline int pci_proc_domain(struct pci_bus *bus)
+{
+	return pci_domain_nr(bus);
+}
+#endif /* CONFIG_PCI_DOMAINS */
+
 #include <linux/mm.h>		/* for struct page */
 
 /* Can be used to override the logic in pci_scan_bus for skipping
diff -urN oldtree/include/asm-i386/serial.h newtree/include/asm-i386/serial.h
--- oldtree/include/asm-i386/serial.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-i386/serial.h	2006-02-21 15:58:36.778555368 +0000
@@ -15,11 +15,11 @@
 
 /* Standard COM flags (except for COM4, because of the 8514 problem) */
 #ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
+#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ)
+#define STD_COM4_FLAGS (UPF_BOOT_AUTOCONF | UPF_AUTO_IRQ)
 #else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
+#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
+#define STD_COM4_FLAGS UPF_BOOT_AUTOCONF
 #endif
 
 #define SERIAL_PORT_DFNS			\
diff -urN oldtree/include/asm-i386/stat.h newtree/include/asm-i386/stat.h
--- oldtree/include/asm-i386/stat.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-i386/stat.h	2006-02-21 15:58:31.471362184 +0000
@@ -58,8 +58,7 @@
 	long long	st_size;
 	unsigned long	st_blksize;
 
-	unsigned long	st_blocks;	/* Number 512-byte blocks allocated. */
-	unsigned long	__pad4;		/* future possible st_blocks high bits */
+	unsigned long long	st_blocks;	/* Number 512-byte blocks allocated. */
 
 	unsigned long	st_atime;
 	unsigned long	st_atime_nsec;
diff -urN oldtree/include/asm-i386/topology.h newtree/include/asm-i386/topology.h
--- oldtree/include/asm-i386/topology.h	2006-02-19 11:41:05.556498384 +0000
+++ newtree/include/asm-i386/topology.h	2006-02-21 15:58:17.886427408 +0000
@@ -69,7 +69,7 @@
 	return first_cpu(mask);
 }
 
-#define pcibus_to_node(bus) ((long) (bus)->sysdata)
+#define pcibus_to_node(bus) ((struct pci_sysdata *)((bus)->sysdata))->node
 #define pcibus_to_cpumask(bus) node_to_cpumask(pcibus_to_node(bus))
 
 /* sched_domains SD_NODE_INIT for NUMAQ machines */
diff -urN oldtree/include/asm-ia64/hw_irq.h newtree/include/asm-ia64/hw_irq.h
--- oldtree/include/asm-ia64/hw_irq.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-ia64/hw_irq.h	2006-02-21 15:58:17.805439720 +0000
@@ -47,9 +47,19 @@
 #define IA64_CMC_VECTOR			0x1f	/* corrected machine-check interrupt vector */
 /*
  * Vectors 0x20-0x2f are reserved for legacy ISA IRQs.
+ * Use vectors 0x30-0xe7 as the default device vector range for ia64.
+ * Platforms may choose to reduce this range in platform_irq_setup, but the
+ * platform range must fall within
+ *	[IA64_DEF_FIRST_DEVICE_VECTOR..IA64_DEF_LAST_DEVICE_VECTOR]
  */
-#define IA64_FIRST_DEVICE_VECTOR	0x30
-#define IA64_LAST_DEVICE_VECTOR		0xe7
+extern int ia64_first_device_vector;
+extern int ia64_last_device_vector;
+
+#define IA64_DEF_FIRST_DEVICE_VECTOR	0x30
+#define IA64_DEF_LAST_DEVICE_VECTOR	0xe7
+#define IA64_FIRST_DEVICE_VECTOR	ia64_first_device_vector
+#define IA64_LAST_DEVICE_VECTOR		ia64_last_device_vector
+#define IA64_MAX_DEVICE_VECTORS		(IA64_DEF_LAST_DEVICE_VECTOR - IA64_DEF_FIRST_DEVICE_VECTOR + 1)
 #define IA64_NUM_DEVICE_VECTORS		(IA64_LAST_DEVICE_VECTOR - IA64_FIRST_DEVICE_VECTOR + 1)
 
 #define IA64_MCA_RENDEZ_VECTOR		0xe8	/* MCA rendez interrupt */
@@ -83,6 +93,7 @@
 
 extern int assign_irq_vector (int irq);	/* allocate a free vector */
 extern void free_irq_vector (int vector);
+extern int reserve_irq_vector (int vector);
 extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect);
 extern void register_percpu_irq (ia64_vector vec, struct irqaction *action);
 
diff -urN oldtree/include/asm-m68k/raw_io.h newtree/include/asm-m68k/raw_io.h
--- oldtree/include/asm-m68k/raw_io.h	2006-02-19 11:41:05.600491696 +0000
+++ newtree/include/asm-m68k/raw_io.h	2006-02-21 15:58:36.785554304 +0000
@@ -336,6 +336,7 @@
 		: "d0", "a0", "a1", "d6");
 }
 
+#define __raw_writel raw_outl
 
 #endif /* __KERNEL__ */
 
diff -urN oldtree/include/asm-m68k/serial.h newtree/include/asm-m68k/serial.h
--- oldtree/include/asm-m68k/serial.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-m68k/serial.h	2006-02-21 15:58:36.786554152 +0000
@@ -19,11 +19,11 @@
 
 /* Standard COM flags (except for COM4, because of the 8514 problem) */
 #ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
+#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ)
+#define STD_COM4_FLAGS (UPF_BOOT_AUTOCONF | UPF_AUTO_IRQ)
 #else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
+#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
+#define STD_COM4_FLAGS UPF_BOOT_AUTOCONF
 #endif
 
 #define SERIAL_PORT_DFNS			\
diff -urN oldtree/include/asm-m68k/signal.h newtree/include/asm-m68k/signal.h
--- oldtree/include/asm-m68k/signal.h	2006-02-19 11:41:05.600491696 +0000
+++ newtree/include/asm-m68k/signal.h	2006-02-21 15:58:36.786554152 +0000
@@ -156,13 +156,13 @@
 
 static inline void sigaddset(sigset_t *set, int _sig)
 {
-	__asm__("bfset %0{%1,#1}" : "=m" (*set) : "id" ((_sig - 1) ^ 31)
+	__asm__("bfset %0{%1,#1}" : "=o" (*set) : "id" ((_sig - 1) ^ 31)
 		: "cc");
 }
 
 static inline void sigdelset(sigset_t *set, int _sig)
 {
-	__asm__("bfclr %0{%1,#1}" : "=m"(*set) : "id"((_sig - 1) ^ 31)
+	__asm__("bfclr %0{%1,#1}" : "=o"(*set) : "id"((_sig - 1) ^ 31)
 		: "cc");
 }
 
@@ -176,7 +176,7 @@
 {
 	int ret;
 	__asm__("bfextu %1{%2,#1},%0"
-		: "=d"(ret) : "m"(*set), "id"((_sig-1) ^ 31));
+		: "=d"(ret) : "o"(*set), "id"((_sig-1) ^ 31));
 	return ret;
 }
 
diff -urN oldtree/include/asm-m68k/stat.h newtree/include/asm-m68k/stat.h
--- oldtree/include/asm-m68k/stat.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-m68k/stat.h	2006-02-21 15:58:31.522354432 +0000
@@ -60,8 +60,7 @@
 	long long	st_size;
 	unsigned long	st_blksize;
 
-	unsigned long	__pad4;		/* future possible st_blocks high bits */
-	unsigned long	st_blocks;	/* Number 512-byte blocks allocated. */
+	unsigned long long	st_blocks;	/* Number 512-byte blocks allocated. */
 
 	unsigned long	st_atime;
 	unsigned long	st_atime_nsec;
diff -urN oldtree/include/asm-powerpc/atomic.h newtree/include/asm-powerpc/atomic.h
--- oldtree/include/asm-powerpc/atomic.h	2006-02-19 11:41:05.645484856 +0000
+++ newtree/include/asm-powerpc/atomic.h	2006-02-21 15:58:22.685697808 +0000
@@ -8,6 +8,7 @@
 typedef struct { volatile int counter; } atomic_t;
 
 #ifdef __KERNEL__
+#include <linux/compiler.h>
 #include <asm/synch.h>
 #include <asm/asm-compat.h>
 
@@ -176,20 +177,29 @@
  * Atomically adds @a to @v, so long as it was not @u.
  * Returns non-zero if @v was not @u, and zero otherwise.
  */
-#define atomic_add_unless(v, a, u)			\
-({							\
-	int c, old;					\
-	c = atomic_read(v);				\
-	for (;;) {					\
-		if (unlikely(c == (u)))			\
-			break;				\
-		old = atomic_cmpxchg((v), c, c + (a));	\
-		if (likely(old == c))			\
-			break;				\
-		c = old;				\
-	}						\
-	c != (u);					\
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int t;
+
+	__asm__ __volatile__ (
+	LWSYNC_ON_SMP
+"1:	lwarx	%0,0,%1		# atomic_add_unless\n\
+	cmpw	0,%0,%3 \n\
+	beq-	2f \n\
+	add	%0,%2,%0 \n"
+	PPC405_ERR77(0,%2)
+"	stwcx.	%0,0,%1 \n\
+	bne-	1b \n"
+	ISYNC_ON_SMP
+"	subf	%0,%2,%0 \n\
+2:"
+	: "=&r" (t)
+	: "r" (&v->counter), "r" (a), "r" (u)
+	: "cc", "memory");
+
+	return t != u;
+}
+
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
 #define atomic_sub_and_test(a, v)	(atomic_sub_return((a), (v)) == 0)
diff -urN oldtree/include/asm-powerpc/firmware.h newtree/include/asm-powerpc/firmware.h
--- oldtree/include/asm-powerpc/firmware.h	2006-02-19 11:41:05.652483792 +0000
+++ newtree/include/asm-powerpc/firmware.h	2006-02-21 15:58:17.523482584 +0000
@@ -89,15 +89,6 @@
 		(FW_FEATURE_POSSIBLE & ppc64_firmware_features & feature);
 }
 
-#ifdef CONFIG_PPC_PSERIES
-typedef struct {
-    unsigned long val;
-    char * name;
-} firmware_feature_t;
-
-extern firmware_feature_t firmware_features_table[];
-#endif
-
 extern void system_reset_fwnmi(void);
 extern void machine_check_fwnmi(void);
 
diff -urN oldtree/include/asm-powerpc/lmb.h newtree/include/asm-powerpc/lmb.h
--- oldtree/include/asm-powerpc/lmb.h	2006-02-19 11:41:05.664481968 +0000
+++ newtree/include/asm-powerpc/lmb.h	2006-02-21 15:58:17.533481064 +0000
@@ -19,8 +19,6 @@
 
 #define MAX_LMB_REGIONS 128
 
-#define LMB_ALLOC_ANYWHERE	0
-
 struct lmb_property {
 	unsigned long base;
 	unsigned long size;
@@ -43,15 +41,16 @@
 
 extern void __init lmb_init(void);
 extern void __init lmb_analyze(void);
-extern long __init lmb_add(unsigned long, unsigned long);
-extern long __init lmb_reserve(unsigned long, unsigned long);
-extern unsigned long __init lmb_alloc(unsigned long, unsigned long);
-extern unsigned long __init lmb_alloc_base(unsigned long, unsigned long,
-					   unsigned long);
+extern long __init lmb_add(unsigned long base, unsigned long size);
+extern long __init lmb_reserve(unsigned long base, unsigned long size);
+extern unsigned long __init lmb_alloc(unsigned long size, unsigned long align);
+extern unsigned long __init lmb_alloc_base(unsigned long size,
+		unsigned long align, unsigned long max_addr);
+extern unsigned long __init __lmb_alloc_base(unsigned long size,
+		unsigned long align, unsigned long max_addr);
 extern unsigned long __init lmb_phys_mem_size(void);
 extern unsigned long __init lmb_end_of_DRAM(void);
-extern unsigned long __init lmb_abs_to_phys(unsigned long);
-extern void __init lmb_enforce_memory_limit(unsigned long);
+extern void __init lmb_enforce_memory_limit(unsigned long memory_limit);
 
 extern void lmb_dump_all(void);
 
diff -urN oldtree/include/asm-powerpc/paca.h newtree/include/asm-powerpc/paca.h
--- oldtree/include/asm-powerpc/paca.h	2006-02-19 11:41:05.670481056 +0000
+++ newtree/include/asm-powerpc/paca.h	2006-02-21 15:58:17.533481064 +0000
@@ -54,7 +54,7 @@
 #endif /* CONFIG_PPC_ISERIES */
 
 	/*
-	 * MAGIC: the spinlock functions in arch/ppc64/lib/locks.c
+	 * MAGIC: the spinlock functions in arch/powerpc/lib/locks.c 
 	 * load lock_token and paca_index with a single lwz
 	 * instruction.  They must travel together and be properly
 	 * aligned.
diff -urN oldtree/include/asm-powerpc/rwsem.h newtree/include/asm-powerpc/rwsem.h
--- oldtree/include/asm-powerpc/rwsem.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-powerpc/rwsem.h	2006-02-21 15:58:17.534480912 +0000
@@ -4,7 +4,7 @@
 #ifdef __KERNEL__
 
 /*
- * include/asm-ppc64/rwsem.h: R/W semaphores for PPC using the stuff
+ * include/asm-powerpc/rwsem.h: R/W semaphores for PPC using the stuff
  * in lib/rwsem.c.  Adapted largely from include/asm-i386/rwsem.h
  * by Paul Mackerras <paulus@samba.org>.
  */
diff -urN oldtree/include/asm-powerpc/synch.h newtree/include/asm-powerpc/synch.h
--- oldtree/include/asm-powerpc/synch.h	2006-02-19 11:41:05.687478472 +0000
+++ newtree/include/asm-powerpc/synch.h	2006-02-21 15:58:22.665700848 +0000
@@ -15,7 +15,7 @@
 #endif
 
 #ifdef CONFIG_SMP
-#define ISYNC_ON_SMP	"\n\tisync"
+#define ISYNC_ON_SMP	"\n\tisync\n"
 #define LWSYNC_ON_SMP	__stringify(LWSYNC) "\n"
 #else
 #define ISYNC_ON_SMP
diff -urN oldtree/include/asm-ppc/harrier.h newtree/include/asm-ppc/harrier.h
--- oldtree/include/asm-ppc/harrier.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-ppc/harrier.h	2006-02-21 15:58:17.546479088 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/kernel/harrier.h
- *
  * Definitions for Motorola MCG Harrier North Bridge & Memory controller
  *
  * Author: Dale Farnsworth
diff -urN oldtree/include/asm-ppc/ibm44x.h newtree/include/asm-ppc/ibm44x.h
--- oldtree/include/asm-ppc/ibm44x.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-ppc/ibm44x.h	2006-02-21 15:58:17.547478936 +0000
@@ -29,7 +29,7 @@
 
 /* TLB entry offset/size used for pinning kernel lowmem */
 #define PPC44x_PIN_SHIFT	28
-#define PPC44x_PIN_SIZE		(1 << PPC44x_PIN_SHIFT)
+#define PPC_PIN_SIZE		(1 << PPC44x_PIN_SHIFT)
 
 /* Lowest TLB slot consumed by the default pinned TLBs */
 #define PPC44x_LOW_SLOT		63
diff -urN oldtree/include/asm-ppc/ibm4xx.h newtree/include/asm-ppc/ibm4xx.h
--- oldtree/include/asm-ppc/ibm4xx.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-ppc/ibm4xx.h	2006-02-21 15:58:17.548478784 +0000
@@ -51,6 +51,10 @@
 #include <platforms/4xx/xilinx_ml300.h>
 #endif
 
+#if defined(CONFIG_XILINX_ML403)
+#include <platforms/4xx/xilinx_ml403.h>
+#endif
+
 #ifndef __ASSEMBLY__
 
 #ifdef CONFIG_40x
diff -urN oldtree/include/asm-ppc/io.h newtree/include/asm-ppc/io.h
--- oldtree/include/asm-ppc/io.h	2006-02-19 11:41:05.693477560 +0000
+++ newtree/include/asm-ppc/io.h	2006-02-21 15:58:17.549478632 +0000
@@ -575,4 +575,11 @@
  */
 #define xlate_dev_kmem_ptr(p)	p
 
+/* access ports */
+#define setbits32(_addr, _v) out_be32((_addr), in_be32(_addr) |  (_v))
+#define clrbits32(_addr, _v) out_be32((_addr), in_be32(_addr) & ~(_v))
+
+#define setbits16(_addr, _v) out_be16((_addr), in_be16(_addr) |  (_v))
+#define clrbits16(_addr, _v) out_be16((_addr), in_be16(_addr) & ~(_v))
+
 #endif /* __KERNEL__ */
diff -urN oldtree/include/asm-ppc/mpc10x.h newtree/include/asm-ppc/mpc10x.h
--- oldtree/include/asm-ppc/mpc10x.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-ppc/mpc10x.h	2006-02-21 15:58:17.549478632 +0000
@@ -1,6 +1,4 @@
 /*
- * arch/ppc/kernel/mpc10x.h
- *
  * Common routines for the Motorola SPS MPC106/8240/107 Host bridge/Mem
  * ctlr/EPIC/etc.
  *
@@ -165,6 +163,7 @@
 	MPC10X_DMA1,
 	MPC10X_UART0,
 	MPC10X_UART1,
+	NUM_PPC_SYS_DEVS,
 };
 
 int mpc10x_bridge_init(struct pci_controller *hose,
diff -urN oldtree/include/asm-ppc/mpc52xx.h newtree/include/asm-ppc/mpc52xx.h
--- oldtree/include/asm-ppc/mpc52xx.h	2006-02-19 11:41:05.694477408 +0000
+++ newtree/include/asm-ppc/mpc52xx.h	2006-02-21 15:58:17.550478480 +0000
@@ -60,6 +60,7 @@
 	MPC52xx_ATA,
 	MPC52xx_I2C1,
 	MPC52xx_I2C2,
+	NUM_PPC_SYS_DEVS,
 };
 
 
diff -urN oldtree/include/asm-ppc/mpc8260.h newtree/include/asm-ppc/mpc8260.h
--- oldtree/include/asm-ppc/mpc8260.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-ppc/mpc8260.h	2006-02-21 15:58:17.550478480 +0000
@@ -83,6 +83,7 @@
 	MPC82xx_CPM_SMC2,
 	MPC82xx_CPM_USB,
 	MPC82xx_SEC1,
+	NUM_PPC_SYS_DEVS,
 };
 
 #ifndef __ASSEMBLY__
diff -urN oldtree/include/asm-ppc/mpc83xx.h newtree/include/asm-ppc/mpc83xx.h
--- oldtree/include/asm-ppc/mpc83xx.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-ppc/mpc83xx.h	2006-02-21 15:58:17.551478328 +0000
@@ -108,6 +108,7 @@
 	MPC83xx_USB2_DR,
 	MPC83xx_USB2_MPH,
 	MPC83xx_MDIO,
+	NUM_PPC_SYS_DEVS,
 };
 
 #endif /* CONFIG_83xx */
diff -urN oldtree/include/asm-ppc/mpc85xx.h newtree/include/asm-ppc/mpc85xx.h
--- oldtree/include/asm-ppc/mpc85xx.h	2006-02-19 11:41:05.694477408 +0000
+++ newtree/include/asm-ppc/mpc85xx.h	2006-02-21 15:58:17.551478328 +0000
@@ -139,6 +139,7 @@
 	MPC85xx_eTSEC4,
 	MPC85xx_IIC2,
 	MPC85xx_MDIO,
+	NUM_PPC_SYS_DEVS,
 };
 
 /* Internal interrupts are all Level Sensitive, and Positive Polarity */
diff -urN oldtree/include/asm-ppc/mpc8xx.h newtree/include/asm-ppc/mpc8xx.h
--- oldtree/include/asm-ppc/mpc8xx.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-ppc/mpc8xx.h	2006-02-21 15:58:17.551478328 +0000
@@ -111,8 +111,11 @@
 	MPC8xx_CPM_SMC1,
 	MPC8xx_CPM_SMC2,
 	MPC8xx_CPM_USB,
+	NUM_PPC_SYS_DEVS,
 };
 
+#define PPC_PIN_SIZE	(24 * 1024 * 1024)	/* 24Mbytes of data pinned */
+
 #ifndef BOARD_CHIP_NAME
 #define BOARD_CHIP_NAME ""
 #endif
diff -urN oldtree/include/asm-ppc/pc_serial.h newtree/include/asm-ppc/pc_serial.h
--- oldtree/include/asm-ppc/pc_serial.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-ppc/pc_serial.h	2006-02-21 15:58:36.786554152 +0000
@@ -28,11 +28,11 @@
 
 /* Standard COM flags (except for COM4, because of the 8514 problem) */
 #ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
+#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ)
+#define STD_COM4_FLAGS (UPF_BOOT_AUTOCONF | UPF_AUTO_IRQ)
 #else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
+#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
+#define STD_COM4_FLAGS UPF_BOOT_AUTOCONF
 #endif
 
 #define SERIAL_PORT_DFNS			\
diff -urN oldtree/include/asm-ppc/pgtable.h newtree/include/asm-ppc/pgtable.h
--- oldtree/include/asm-ppc/pgtable.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-ppc/pgtable.h	2006-02-21 15:58:17.552478176 +0000
@@ -12,6 +12,7 @@
 #include <asm/processor.h>		/* For TASK_SIZE */
 #include <asm/mmu.h>
 #include <asm/page.h>
+#include <asm/io.h>			/* For sub-arch specific PPC_PIN_SIZE */
 struct mm_struct;
 
 extern unsigned long va_to_phys(unsigned long address);
@@ -127,9 +128,8 @@
  * of RAM.  -- Cort
  */
 #define VMALLOC_OFFSET (0x1000000) /* 16M */
-#ifdef CONFIG_44x
-#include <asm/ibm44x.h>
-#define VMALLOC_START (((_ALIGN((long)high_memory, PPC44x_PIN_SIZE) + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
+#ifdef PPC_PIN_SIZE
+#define VMALLOC_START (((_ALIGN((long)high_memory, PPC_PIN_SIZE) + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
 #else
 #define VMALLOC_START ((((long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
 #endif
diff -urN oldtree/include/asm-ppc/ppc_sys.h newtree/include/asm-ppc/ppc_sys.h
--- oldtree/include/asm-ppc/ppc_sys.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-ppc/ppc_sys.h	2006-02-21 15:58:17.553478024 +0000
@@ -33,6 +33,8 @@
 #include <asm/mpc52xx.h>
 #elif defined(CONFIG_MPC10X_BRIDGE)
 #include <asm/mpc10x.h>
+#elif defined(CONFIG_XILINX_VIRTEX)
+#include <platforms/4xx/virtex.h>
 #else
 #error "need definition of ppc_sys_devices"
 #endif
@@ -44,9 +46,26 @@
 	u32 			value;
 	u32 			num_devices;
 	char 			*ppc_sys_name;
+	u8			config[NUM_PPC_SYS_DEVS];
 	enum ppc_sys_devices 	*device_list;
 };
 
+struct platform_notify_dev_map {
+	const char *bus_id;
+	void (*rtn)(struct platform_device * pdev, int idx);
+};
+
+enum platform_device_func {
+	PPC_SYS_FUNC_DUMMY = 0,
+	PPC_SYS_FUNC_ETH = 1,
+	PPC_SYS_FUNC_UART = 2,
+	PPC_SYS_FUNC_HLDC = 3,
+	PPC_SYS_FUNC_USB = 4,
+	PPC_SYS_FUNC_IRDA = 5,
+};
+
+#define PPC_SYS_CONFIG_DISABLED		1
+
 /* describes all specific chips and which devices they have on them */
 extern struct ppc_sys_spec ppc_sys_specs[];
 extern struct ppc_sys_spec *cur_ppc_sys_spec;
@@ -72,5 +91,20 @@
 /* remove a device from the system */
 extern void ppc_sys_device_remove(enum ppc_sys_devices dev);
 
+/* Function assignment stuff */
+void ppc_sys_device_initfunc(void);
+void ppc_sys_device_setfunc(enum ppc_sys_devices dev,
+			    enum platform_device_func func);
+void ppc_sys_device_set_func_all(enum platform_device_func func);
+
+void platform_notify_map(const struct platform_notify_dev_map *map,
+			 struct device *dev);
+
+/* Enable / disable stuff */
+void ppc_sys_device_disable(enum ppc_sys_devices dev);
+void ppc_sys_device_enable(enum ppc_sys_devices dev);
+void ppc_sys_device_enable_all(void);
+void ppc_sys_device_disable_all(void);
+
 #endif				/* __ASM_PPC_SYS_H */
 #endif				/* __KERNEL__ */
diff -urN oldtree/include/asm-ppc/todc.h newtree/include/asm-ppc/todc.h
--- oldtree/include/asm-ppc/todc.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-ppc/todc.h	2006-02-21 15:58:17.555477720 +0000
@@ -1,6 +1,4 @@
 /*
- * include/asm-ppc/todc.h
- *
  * Definitions for the M48Txx and mc146818 series of Time of day/Real Time
  * Clock chips.
  *
diff -urN oldtree/include/asm-ppc/xparameters.h newtree/include/asm-ppc/xparameters.h
--- oldtree/include/asm-ppc/xparameters.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-ppc/xparameters.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,18 +0,0 @@
-/*
- * include/asm-ppc/xparameters.h
- *
- * This file includes the correct xparameters.h for the CONFIG'ed board
- *
- * Author: MontaVista Software, Inc.
- *         source@mvista.com
- *
- * 2004 (c) MontaVista Software, Inc.  This file is licensed under the terms
- * of the GNU General Public License version 2.  This program is licensed
- * "as is" without any warranty of any kind, whether express or implied.
- */
-
-#include <linux/config.h>
-
-#if defined(CONFIG_XILINX_ML300)
-#include <platforms/4xx/xparameters/xparameters_ml300.h>
-#endif
diff -urN oldtree/include/asm-s390/sgrb.h newtree/include/asm-s390/sgrb.h
--- oldtree/include/asm-s390/sgrb.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/include/asm-s390/sgrb.h	2006-02-21 15:58:23.520570888 +0000
@@ -0,0 +1,94 @@
+/*
+ * linux/asm-s390/sgrb.h
+ *
+ * a ringbuffer made up of scattered buffers; holds fixed-size entries
+ * (resizing has not been implemented)
+ '
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef SGRB_H
+#define SGRB_H
+
+#define SGRB_H_REVISION "$Revision: 1.2 $"
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+
+#define SGRB_BUFFER_SIZE	PAGE_SIZE
+
+struct sgrb_seg {
+	struct list_head list;
+	char *address;
+	int offset;
+	int size;
+};
+
+struct sgrb_ptr {
+	struct sgrb_seg *seg;
+	signed int offset;
+};
+
+struct sgrb {
+	struct list_head seg_lh;
+	struct sgrb_ptr first;
+	struct sgrb_ptr last;
+	int entry_size;
+	int entries;
+};
+
+/**
+ * sgrb_ptr_copy - prepare pointer a by copying b
+ * @a: duplicate
+ * @b: original
+ *
+ * required to prepare a pointer for use with sgrb_consume_nodelete()
+ */
+static inline void
+sgrb_ptr_copy(
+	struct sgrb_ptr *a,
+	struct sgrb_ptr *b)
+{
+	a->seg = b->seg;
+	a->offset = b->offset;
+}
+
+/**
+ * sgrb_entry - returns address of entry
+ * @a: pointer that determines entry
+ */
+static inline void *
+sgrb_entry(struct sgrb_ptr *a)
+{
+	return (a->seg->address + a->offset);
+}
+
+struct sgrb_seg * sgrb_seg_find(struct list_head *, int, unsigned int);
+void sgrb_seg_release_all(struct list_head *);
+
+int sgrb_alloc(struct sgrb *, int, int, int, int);
+void sgrb_release(struct sgrb *);
+
+void * sgrb_produce_overwrite(struct sgrb *);
+void * sgrb_produce_nooverwrite(struct sgrb *);
+void * sgrb_consume_delete(struct sgrb *);
+void * sgrb_consume_nodelete(struct sgrb *, struct sgrb_ptr *);
+
+#endif /* SGRB_H */
diff -urN oldtree/include/asm-s390/statistic.h newtree/include/asm-s390/statistic.h
--- oldtree/include/asm-s390/statistic.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/include/asm-s390/statistic.h	2006-02-21 15:58:23.520570888 +0000
@@ -0,0 +1,334 @@
+/*
+ * linux/asm-s390/statistic.h
+ *
+ * Statistics facility
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef STATISTIC_H
+#define STATISTIC_H
+
+#define STATISTIC_H_REVISION "$Revision: 1.12 $"
+
+#include <linux/fs.h>
+#include <linux/types.h>
+
+#include <asm/spinlock.h>
+#include <asm/sgrb.h>
+
+#define STATISTIC_ROOT_DIR	"s390stat"
+
+#define STATISTIC_FILENAME_DATA	"data"
+#define STATISTIC_FILENAME_DEF	"definition"
+
+#define STATISTIC_NAME_SIZE	64
+
+#define STATISTIC_RANGE_MIN	-0x7fffffffffffffffLL
+#define STATISTIC_RANGE_MAX	 0x7ffffffffffffffeLL
+
+enum {
+	STATISTIC_DEF_NAME,
+	STATISTIC_DEF_UNIT,
+	STATISTIC_DEF_TYPE_VALUE,
+	STATISTIC_DEF_TYPE_RANGE,
+	STATISTIC_DEF_TYPE_ARRAY,
+	STATISTIC_DEF_TYPE_LIST,
+	STATISTIC_DEF_TYPE_RAW,
+	STATISTIC_DEF_TYPE_HISTORY,
+	STATISTIC_DEF_ON,
+	STATISTIC_DEF_OFF,
+	STATISTIC_DEF_STARTED,
+	STATISTIC_DEF_STOPPED,
+	STATISTIC_DEF_RANGEMIN,
+	STATISTIC_DEF_RANGEMAX,
+	STATISTIC_DEF_SCALE_LIN,
+	STATISTIC_DEF_SCALE_LOG2,
+	STATISTIC_DEF_ENTRIESMAX,
+	STATISTIC_DEF_BASEINT,
+	STATISTIC_DEF_HITSMISSED,
+	STATISTIC_DEF_HITSOUT,
+	STATISTIC_DEF_RESET,
+	STATISTIC_DEF_MODE_INC,
+	STATISTIC_DEF_MODE_PROD,
+	STATISTIC_DEF_MODE_RANGE,
+	STATISTIC_DEF_PERIOD,
+	STATISTIC_DEF_VOID,
+};
+
+struct statistic;
+struct statistic_file_private;
+
+typedef int (statistic_alloc_fn) (struct statistic *);
+typedef void (statistic_release_fn) (struct statistic *);
+typedef int (statistic_format_data_fn)
+		(struct statistic *, struct statistic_file_private *);
+typedef int (statistic_format_def_fn) (struct statistic *, char *);
+typedef u64 (statistic_add_fn) (struct statistic *, s64, u64);
+
+struct statistic_entry_list {
+	struct list_head	list;
+	s64			value;
+	u64			hits;
+};
+
+struct statistic_entry_raw {
+	u64 clock;
+	u64 serial;
+	s64 value;
+	u64 incr;
+};
+
+struct statistic_entry_range {
+	u32 res;
+	u32 num;	/* FIXME: better 64 bit; do_div can't deal with it) */
+	s64 acc;
+	s64 min;
+	s64 max;
+};
+
+struct statistic {
+	struct list_head		list;
+	struct statistic_interface	*interface;
+	struct statistic		**stat_ptr;
+	statistic_alloc_fn		*alloc;
+	statistic_release_fn		*release;
+	statistic_format_data_fn	*format_data;
+	statistic_format_def_fn		*format_def;
+	statistic_add_fn		*add;
+	char	name[STATISTIC_NAME_SIZE];
+	char	units[STATISTIC_NAME_SIZE];
+	u8	type;
+	u8	on;
+	u64	started;
+	u64	stopped;
+	u64	reset;
+	s64 	range_min;
+	s64 	range_max;
+	u64	hits_out_of_range;
+	union {
+		struct {
+			/* data */
+			u64 hits;
+			/* user-writeable */
+			int mode;
+		} value;
+		struct {
+			/* data */
+			struct statistic_entry_range range;
+		} range;
+		struct {
+			/* data */
+			u64 *hits;
+			/* user-writeable */
+			u32 base_interval;
+			u8 scale;
+			/* internal */
+			u32 entries;
+		} array;
+		struct {
+			/* data */
+			struct list_head entry_lh;
+			/* user-writeable */
+			u32 entries_max;
+			/* informational for user */
+			u64 hits_missed;
+			/* internal */
+			u32 entries;
+		} list;
+		struct {
+			/* data */
+			struct sgrb rb;
+			/* user-writeable */
+			u32 entries_max;
+			/* internal */
+			u64 next_serial;
+		} raw;
+		struct {
+			/* data */
+			struct sgrb rb;
+			/* user-writeable */
+			u32 entries_max;
+			int mode;
+			u64 period;
+			/* internal */
+			u64 checkpoint;
+			u64 window;
+			u8 entry_size;
+		} history;
+	} data;
+};
+
+struct statistic_interface {
+	struct list_head	list;
+	struct dentry		*debugfs_dir;
+	struct dentry		*data_file;
+	struct dentry		*def_file;
+	struct list_head	statistic_lh;
+	struct semaphore	sem;
+	spinlock_t		lock;
+};
+
+struct statistic_file_private {
+	struct list_head read_seg_lh;
+	struct list_head write_seg_lh;
+	size_t write_seg_total_size;
+};
+
+struct statistic_global_data {
+	struct dentry		*root_dir;
+	struct list_head	interface_lh;
+	struct semaphore	sem;
+};
+
+int statistic_interface_create(struct statistic_interface **, const char *);
+int statistic_interface_remove(struct statistic_interface **);
+
+int statistic_create(struct statistic **, struct statistic_interface *, const char *, const char *);
+int statistic_remove(struct statistic **);
+
+int statistic_define_value(struct statistic *, s64, s64, int);
+int statistic_define_range(struct statistic *, s64, s64);
+int statistic_define_array(struct statistic *, s64, s64, u32, u8);
+int statistic_define_list(struct statistic *, s64, s64, u32);
+int statistic_define_raw(struct statistic *, s64, s64, u32);
+int statistic_define_history(struct statistic *, s64, s64, u32, u64, int);
+
+int statistic_start(struct statistic *);
+int statistic_stop(struct statistic *);
+int statistic_reset(struct statistic *);
+
+/**
+ * statistic_add - update statistic with (discriminator, increment) pair
+ * @stat: statistic
+ * @value: discriminator
+ * @incr: increment
+ *
+ * The actual processing of (discriminator, increment) is determined by the
+ * the definition applied to the statistic. See the statistic_define_*()
+ * routine desciption for details.
+ *
+ * This variant grabs a lock to ensure a) data integrity with regard to
+ * to potentially concurrent data gathering, and b) data consistency across
+ * all statistic attached to the parent interface when being read as a
+ * snapshot by the user through the "data" file.
+ *
+ * On success, the return value is dependend on which type of accumulation
+ * has been applied through the recent definition. Usually, returns the
+ * updated total of increments reported for this discriminator, if the
+ * defined type of accumulation does this kind of computation.
+ *
+ * If the struct statistic pointer provided by the caller
+ * is NULL (unused), this routine fails, and 0 is returned.
+ *
+ * If some required memory could not be allocated this routine fails,
+ * and 0 is returned.
+ *
+ * If the discriminator is not valid (out of range), this routine failes,
+ * and 0 is returned.
+ **/
+static inline u64
+statistic_add(struct statistic *stat, s64 value, u64 incr)
+{
+	unsigned long flags;
+	int retval;
+
+	if (stat->on != STATISTIC_DEF_ON)
+		return 0;
+
+	spin_lock_irqsave(&stat->interface->lock, flags);
+	retval = stat->add(stat, value, incr);
+	spin_unlock_irqrestore(&stat->interface->lock, flags);
+
+	return retval;
+}
+
+/**
+ * statistic_add_nolock - a statistic_add() variant
+ * @stat: statistic
+ * @value: discriminator
+ * @incr: increment
+ *
+ * Same purpose and behavious as statistic_add(). See there for details.
+ *
+ * Only difference to statistic_add():
+ * Lock management is up to the exploiter. Basically, we give exploiters
+ * the option to ensure data consistency across all statistics attached
+ * to a parent interface by adding several calls to this routine into one
+ * critical section protected by stat->interface->lock,
+ **/
+static inline u64
+statistic_add_nolock(struct statistic *stat, s64 value, u64 incr)
+{
+	if (stat->on != STATISTIC_DEF_ON)
+		return 0;
+
+#ifdef DEBUG
+	assert_spin_locked(&stat->interface->lock);
+#endif
+
+	return stat->add(stat, value, incr);
+}
+
+/**
+ * statistic_inc - a statistic_add() variant
+ * @stat: statistic
+ * @value: discriminator
+ *
+ * Same purpose and behavious as statistic_add(). See there for details.
+ * Difference: Increment defaults to 1.
+ **/
+static inline u64
+statistic_inc(struct statistic *stat, s64 value)
+{
+	unsigned long flags;
+	int retval;
+
+	if (stat->on != STATISTIC_DEF_ON)
+		return 0;
+
+	spin_lock_irqsave(&stat->interface->lock, flags);
+	retval = stat->add(stat, value, 1);
+	spin_unlock_irqrestore(&stat->interface->lock, flags);
+
+	return retval;
+}
+
+/**
+ * statistic_inc_nolock - a statistic_add_nolock() variant
+ * @stat: statistic
+ * @value: discriminator
+ *
+ * Same purpose and behavious as statistic_add_nolock(). See there for details.
+ * Difference: Increment defaults to 1.
+ **/
+static inline u64
+statistic_inc_nolock(struct statistic *stat, s64 value)
+{
+	if (stat->on != STATISTIC_DEF_ON)
+		return 0;
+
+#ifdef DEBUG
+	assert_spin_locked(&stat->interface->lock);
+#endif
+
+	return stat->add(stat, value, 1);
+}
+
+#endif /* STATISTIC_H */
diff -urN oldtree/include/asm-sh/stat.h newtree/include/asm-sh/stat.h
--- oldtree/include/asm-sh/stat.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sh/stat.h	2006-02-21 15:58:31.522354432 +0000
@@ -60,13 +60,7 @@
 	long long	st_size;
 	unsigned long	st_blksize;
 
-#if defined(__BIG_ENDIAN__)
-	unsigned long	__pad4;		/* Future possible st_blocks hi bits */
-	unsigned long	st_blocks;	/* Number 512-byte blocks allocated. */
-#else /* Must be little */
-	unsigned long	st_blocks;	/* Number 512-byte blocks allocated. */
-	unsigned long	__pad4;		/* Future possible st_blocks hi bits */
-#endif
+	unsigned long long	st_blocks;	/* Number 512-byte blocks allocated. */
 
 	unsigned long	st_atime;
 	unsigned long	st_atime_nsec;
diff -urN oldtree/include/asm-sparc/idprom.h newtree/include/asm-sparc/idprom.h
--- oldtree/include/asm-sparc/idprom.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sparc/idprom.h	2006-02-21 15:58:20.568019744 +0000
@@ -7,27 +7,19 @@
 #ifndef _SPARC_IDPROM_H
 #define _SPARC_IDPROM_H
 
-/* Offset into the EEPROM where the id PROM is located on the 4c */
-#define IDPROM_OFFSET  0x7d8
+#include <linux/types.h>
 
-/* On sun4m; physical. */
-/* MicroSPARC(-II) does not decode 31rd bit, but it works. */
-#define IDPROM_OFFSET_M  0xfd8
-
-struct idprom
-{
-	unsigned char	id_format;	/* Format identifier (always 0x01) */
-	unsigned char	id_machtype;	/* Machine type */
-	unsigned char	id_ethaddr[6];	/* Hardware ethernet address */
-	long		id_date;	/* Date of manufacture */
-	unsigned int	id_sernum:24;	/* Unique serial number */
-	unsigned char	id_cksum;	/* Checksum - xor of the data bytes */
-	unsigned char	reserved[16];
+struct idprom {
+	u8		id_format;	/* Format identifier (always 0x01) */
+	u8		id_machtype;	/* Machine type */
+	u8		id_ethaddr[6];	/* Hardware ethernet address */
+	s32		id_date;	/* Date of manufacture */
+	u32		id_sernum:24;	/* Unique serial number */
+	u8		id_cksum;	/* Checksum - xor of the data bytes */
+	u8		reserved[16];
 };
 
 extern struct idprom *idprom;
 extern void idprom_init(void);
 
-#define IDPROM_SIZE  (sizeof(struct idprom))
-
 #endif /* !(_SPARC_IDPROM_H) */
diff -urN oldtree/include/asm-sparc/oplib.h newtree/include/asm-sparc/oplib.h
--- oldtree/include/asm-sparc/oplib.h	2006-02-19 11:41:05.730471936 +0000
+++ newtree/include/asm-sparc/oplib.h	2006-02-21 15:58:20.744992840 +0000
@@ -165,6 +165,7 @@
 	PROMDEV_ITTYA,			/* input from ttya */
 	PROMDEV_ITTYB,			/* input from ttyb */
 	PROMDEV_IRSC,			/* input from rsc */
+	PROMDEV_IVCONS,			/* input from virtual-console */
 	PROMDEV_I_UNK,
 };
 
@@ -177,6 +178,7 @@
 	PROMDEV_OTTYA,			/* to ttya */
 	PROMDEV_OTTYB,			/* to ttyb */
 	PROMDEV_ORSC,			/* to rsc */
+	PROMDEV_OVCONS,			/* to virtual-console */
 	PROMDEV_O_UNK,
 };
 
diff -urN oldtree/include/asm-sparc/uaccess.h newtree/include/asm-sparc/uaccess.h
--- oldtree/include/asm-sparc/uaccess.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sparc/uaccess.h	2006-02-21 15:58:20.757990864 +0000
@@ -120,17 +120,6 @@
 default: __pu_ret = __put_user_bad(); break; \
 } } else { __pu_ret = -EFAULT; } __pu_ret; })
 
-#define __put_user_check_ret(x,addr,size,retval) ({ \
-register int __foo __asm__ ("l1"); \
-if (__access_ok(addr,size)) { \
-switch (size) { \
-case 1: __put_user_asm_ret(x,b,addr,retval,__foo); break; \
-case 2: __put_user_asm_ret(x,h,addr,retval,__foo); break; \
-case 4: __put_user_asm_ret(x,,addr,retval,__foo); break; \
-case 8: __put_user_asm_ret(x,d,addr,retval,__foo); break; \
-default: if (__put_user_bad()) return retval; break; \
-} } else return retval; })
-
 #define __put_user_nocheck(x,addr,size) ({ \
 register int __pu_ret; \
 switch (size) { \
@@ -141,16 +130,6 @@
 default: __pu_ret = __put_user_bad(); break; \
 } __pu_ret; })
 
-#define __put_user_nocheck_ret(x,addr,size,retval) ({ \
-register int __foo __asm__ ("l1"); \
-switch (size) { \
-case 1: __put_user_asm_ret(x,b,addr,retval,__foo); break; \
-case 2: __put_user_asm_ret(x,h,addr,retval,__foo); break; \
-case 4: __put_user_asm_ret(x,,addr,retval,__foo); break; \
-case 8: __put_user_asm_ret(x,d,addr,retval,__foo); break; \
-default: if (__put_user_bad()) return retval; break; \
-} })
-
 #define __put_user_asm(x,size,addr,ret)					\
 __asm__ __volatile__(							\
 	"/* Put user asm, inline. */\n"					\
@@ -170,32 +149,6 @@
        : "=&r" (ret) : "r" (x), "m" (*__m(addr)),			\
 	 "i" (-EFAULT))
 
-#define __put_user_asm_ret(x,size,addr,ret,foo)				\
-if (__builtin_constant_p(ret) && ret == -EFAULT)			\
-__asm__ __volatile__(							\
-	"/* Put user asm ret, inline. */\n"				\
-"1:\t"	"st"#size " %1, %2\n\n\t"					\
-	".section __ex_table,#alloc\n\t"				\
-	".align	4\n\t"							\
-	".word	1b, __ret_efault\n\n\t"					\
-	".previous\n\n\t"						\
-       : "=r" (foo) : "r" (x), "m" (*__m(addr)));			\
-else									\
-__asm__ __volatile(							\
-	"/* Put user asm ret, inline. */\n"				\
-"1:\t"	"st"#size " %1, %2\n\n\t"					\
-	".section .fixup,#alloc,#execinstr\n\t"				\
-	".align	4\n"							\
-"3:\n\t"								\
-	"ret\n\t"							\
-	" restore %%g0, %3, %%o0\n\t"					\
-	".previous\n\n\t"						\
-	".section __ex_table,#alloc\n\t"				\
-	".align	4\n\t"							\
-	".word	1b, 3b\n\n\t"						\
-	".previous\n\n\t"						\
-       : "=r" (foo) : "r" (x), "m" (*__m(addr)), "i" (ret))
-
 extern int __put_user_bad(void);
 
 #define __get_user_check(x,addr,size,type) ({ \
diff -urN oldtree/include/asm-sparc64/asi.h newtree/include/asm-sparc64/asi.h
--- oldtree/include/asm-sparc64/asi.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sparc64/asi.h	2006-02-21 15:58:20.759990560 +0000
@@ -25,14 +25,27 @@
 
 /* SpitFire and later extended ASIs.  The "(III)" marker designates
  * UltraSparc-III and later specific ASIs.  The "(CMT)" marker designates
- * Chip Multi Threading specific ASIs.
+ * Chip Multi Threading specific ASIs.  "(NG)" designates Niagara specific
+ * ASIs, "(4V)" designates SUN4V specific ASIs.
  */
 #define ASI_PHYS_USE_EC		0x14 /* PADDR, E-cachable		*/
 #define ASI_PHYS_BYPASS_EC_E	0x15 /* PADDR, E-bit			*/
+#define ASI_BLK_AIUP_4V		0x16 /* (4V) Prim, user, block ld/st	*/
+#define ASI_BLK_AIUS_4V		0x17 /* (4V) Sec, user, block ld/st	*/
 #define ASI_PHYS_USE_EC_L	0x1c /* PADDR, E-cachable, little endian*/
 #define ASI_PHYS_BYPASS_EC_E_L	0x1d /* PADDR, E-bit, little endian	*/
+#define ASI_BLK_AIUP_L_4V	0x1e /* (4V) Prim, user, block, l-endian*/
+#define ASI_BLK_AIUS_L_4V	0x1f /* (4V) Sec, user, block, l-endian	*/
+#define ASI_SCRATCHPAD		0x20 /* (4V) Scratch Pad Registers	*/
+#define ASI_MMU			0x21 /* (4V) MMU Context Registers	*/
+#define ASI_BLK_INIT_QUAD_LDD_AIUS 0x23 /* (NG) init-store, twin load,
+					 * secondary, user
+					 */
 #define ASI_NUCLEUS_QUAD_LDD	0x24 /* Cachable, qword load		*/
+#define ASI_QUEUE		0x25 /* (4V) Interrupt Queue Registers	*/
+#define ASI_QUAD_LDD_PHYS_4V	0x26 /* (4V) Physical, qword load	*/
 #define ASI_NUCLEUS_QUAD_LDD_L	0x2c /* Cachable, qword load, l-endian 	*/
+#define ASI_QUAD_LDD_PHYS_L_4V	0x2e /* (4V) Phys, qword load, l-endian	*/
 #define ASI_PCACHE_DATA_STATUS	0x30 /* (III) PCache data stat RAM diag	*/
 #define ASI_PCACHE_DATA		0x31 /* (III) PCache data RAM diag	*/
 #define ASI_PCACHE_TAG		0x32 /* (III) PCache tag RAM diag	*/
@@ -137,6 +150,9 @@
 #define ASI_FL16_SL		0xdb /* Secondary, 1 16-bit, fpu ld/st,L*/
 #define ASI_BLK_COMMIT_P	0xe0 /* Primary, blk store commit	*/
 #define ASI_BLK_COMMIT_S	0xe1 /* Secondary, blk store commit	*/
+#define ASI_BLK_INIT_QUAD_LDD_P	0xe2 /* (NG) init-store, twin load,
+				      * primary, implicit
+				      */
 #define ASI_BLK_P		0xf0 /* Primary, blk ld/st		*/
 #define ASI_BLK_S		0xf1 /* Secondary, blk ld/st		*/
 #define ASI_BLK_PL		0xf8 /* Primary, blk ld/st, little	*/
diff -urN oldtree/include/asm-sparc64/cpudata.h newtree/include/asm-sparc64/cpudata.h
--- oldtree/include/asm-sparc64/cpudata.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sparc64/cpudata.h	2006-02-21 15:58:20.759990560 +0000
@@ -1,12 +1,18 @@
 /* cpudata.h: Per-cpu parameters.
  *
- * Copyright (C) 2003, 2005 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2003, 2005, 2006 David S. Miller (davem@davemloft.net)
  */
 
 #ifndef _SPARC64_CPUDATA_H
 #define _SPARC64_CPUDATA_H
 
+#include <asm/hypervisor.h>
+#include <asm/asi.h>
+
+#ifndef __ASSEMBLY__
+
 #include <linux/percpu.h>
+#include <linux/threads.h>
 
 typedef struct {
 	/* Dcache line 1 */
@@ -17,25 +23,202 @@
 	unsigned long	clock_tick;	/* %tick's per second */
 	unsigned long	udelay_val;
 
-	/* Dcache line 2 */
-	unsigned int	pgcache_size;
-	unsigned int	__pad1;
-	unsigned long	*pte_cache[2];
-	unsigned long	*pgd_cache;
-
-	/* Dcache line 3, rarely used */
+	/* Dcache line 2, rarely used */
 	unsigned int	dcache_size;
 	unsigned int	dcache_line_size;
 	unsigned int	icache_size;
 	unsigned int	icache_line_size;
 	unsigned int	ecache_size;
 	unsigned int	ecache_line_size;
-	unsigned int	__pad2;
 	unsigned int	__pad3;
+	unsigned int	__pad4;
 } cpuinfo_sparc;
 
 DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data);
 #define cpu_data(__cpu)		per_cpu(__cpu_data, (__cpu))
 #define local_cpu_data()	__get_cpu_var(__cpu_data)
 
+/* Trap handling code needs to get at a few critical values upon
+ * trap entry and to process TSB misses.  These cannot be in the
+ * per_cpu() area as we really need to lock them into the TLB and
+ * thus make them part of the main kernel image.  As a result we
+ * try to make this as small as possible.
+ *
+ * This is padded out and aligned to 64-bytes to avoid false sharing
+ * on SMP.
+ */
+
+/* If you modify the size of this structure, please update
+ * TRAP_BLOCK_SZ_SHIFT below.
+ */
+struct thread_info;
+struct trap_per_cpu {
+/* D-cache line 1: Basic thread information, cpu and device mondo queues */
+	struct thread_info	*thread;
+	unsigned long		pgd_paddr;
+	unsigned long		cpu_mondo_pa;
+	unsigned long		dev_mondo_pa;
+
+/* D-cache line 2: Error Mondo Queue and kernel buffer pointers */
+	unsigned long		resum_mondo_pa;
+	unsigned long		resum_kernel_buf_pa;
+	unsigned long		nonresum_mondo_pa;
+	unsigned long		nonresum_kernel_buf_pa;
+
+/* Dcache lines 3, 4, 5, and 6: Hypervisor Fault Status */
+	struct hv_fault_status	fault_info;
+
+/* Dcache line 7: Physical addresses of CPU send mondo block and CPU list.  */
+	unsigned long		cpu_mondo_block_pa;
+	unsigned long		cpu_list_pa;
+	unsigned long		__pad1[2];
+
+/* Dcache line 8: Unused, needed to keep trap_block a power-of-2 in size.  */
+	unsigned long		__pad2[4];
+} __attribute__((aligned(64)));
+extern struct trap_per_cpu trap_block[NR_CPUS];
+extern void init_cur_cpu_trap(struct thread_info *);
+extern void setup_tba(void);
+
+struct cpuid_patch_entry {
+	unsigned int	addr;
+	unsigned int	cheetah_safari[4];
+	unsigned int	cheetah_jbus[4];
+	unsigned int	starfire[4];
+	unsigned int	sun4v[4];
+};
+extern struct cpuid_patch_entry __cpuid_patch, __cpuid_patch_end;
+
+struct sun4v_1insn_patch_entry {
+	unsigned int	addr;
+	unsigned int	insn;
+};
+extern struct sun4v_1insn_patch_entry __sun4v_1insn_patch,
+	__sun4v_1insn_patch_end;
+
+struct sun4v_2insn_patch_entry {
+	unsigned int	addr;
+	unsigned int	insns[2];
+};
+extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch,
+	__sun4v_2insn_patch_end;
+
+#endif /* !(__ASSEMBLY__) */
+
+#define TRAP_PER_CPU_THREAD		0x00
+#define TRAP_PER_CPU_PGD_PADDR		0x08
+#define TRAP_PER_CPU_CPU_MONDO_PA	0x10
+#define TRAP_PER_CPU_DEV_MONDO_PA	0x18
+#define TRAP_PER_CPU_RESUM_MONDO_PA	0x20
+#define TRAP_PER_CPU_RESUM_KBUF_PA	0x28
+#define TRAP_PER_CPU_NONRESUM_MONDO_PA	0x30
+#define TRAP_PER_CPU_NONRESUM_KBUF_PA	0x38
+#define TRAP_PER_CPU_FAULT_INFO		0x40
+#define TRAP_PER_CPU_CPU_MONDO_BLOCK_PA	0xc0
+#define TRAP_PER_CPU_CPU_LIST_PA	0xc8
+
+#define TRAP_BLOCK_SZ_SHIFT		8
+
+#include <asm/scratchpad.h>
+
+#define __GET_CPUID(REG)				\
+	/* Spitfire implementation (default). */	\
+661:	ldxa		[%g0] ASI_UPA_CONFIG, REG;	\
+	srlx		REG, 17, REG;			\
+	 and		REG, 0x1f, REG;			\
+	nop;						\
+	.section	.cpuid_patch, "ax";		\
+	/* Instruction location. */			\
+	.word		661b;				\
+	/* Cheetah Safari implementation. */		\
+	ldxa		[%g0] ASI_SAFARI_CONFIG, REG;	\
+	srlx		REG, 17, REG;			\
+	and		REG, 0x3ff, REG;		\
+	nop;						\
+	/* Cheetah JBUS implementation. */		\
+	ldxa		[%g0] ASI_JBUS_CONFIG, REG;	\
+	srlx		REG, 17, REG;			\
+	and		REG, 0x1f, REG;			\
+	nop;						\
+	/* Starfire implementation. */			\
+	sethi		%hi(0x1fff40000d0 >> 9), REG;	\
+	sllx		REG, 9, REG;			\
+	or		REG, 0xd0, REG;			\
+	lduwa		[REG] ASI_PHYS_BYPASS_EC_E, REG;\
+	/* sun4v implementation. */			\
+	mov		SCRATCHPAD_CPUID, REG;		\
+	ldxa		[REG] ASI_SCRATCHPAD, REG;	\
+	nop;						\
+	nop;						\
+	.previous;
+
+#ifdef CONFIG_SMP
+
+#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP)		\
+	__GET_CPUID(TMP)			\
+	sethi	%hi(trap_block), DEST;		\
+	sllx	TMP, TRAP_BLOCK_SZ_SHIFT, TMP;	\
+	or	DEST, %lo(trap_block), DEST;	\
+	add	DEST, TMP, DEST;		\
+
+/* Clobbers TMP, current address space PGD phys address into DEST.  */
+#define TRAP_LOAD_PGD_PHYS(DEST, TMP)		\
+	TRAP_LOAD_TRAP_BLOCK(DEST, TMP)		\
+	ldx	[DEST + TRAP_PER_CPU_PGD_PADDR], DEST;
+
+/* Clobbers TMP, loads local processor's IRQ work area into DEST.  */
+#define TRAP_LOAD_IRQ_WORK(DEST, TMP)		\
+	__GET_CPUID(TMP)			\
+	sethi	%hi(__irq_work), DEST;		\
+	sllx	TMP, 6, TMP;			\
+	or	DEST, %lo(__irq_work), DEST;	\
+	add	DEST, TMP, DEST;
+
+/* Clobbers TMP, loads DEST with current thread info pointer.  */
+#define TRAP_LOAD_THREAD_REG(DEST, TMP)		\
+	TRAP_LOAD_TRAP_BLOCK(DEST, TMP)		\
+	ldx	[DEST + TRAP_PER_CPU_THREAD], DEST;
+
+/* Given the current thread info pointer in THR, load the per-cpu
+ * area base of the current processor into DEST.  REG1, REG2, and REG3 are
+ * clobbered.
+ *
+ * You absolutely cannot use DEST as a temporary in this code.  The
+ * reason is that traps can happen during execution, and return from
+ * trap will load the fully resolved DEST per-cpu base.  This can corrupt
+ * the calculations done by the macro mid-stream.
+ */
+#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3)	\
+	ldub	[THR + TI_CPU], REG1;			\
+	sethi	%hi(__per_cpu_shift), REG3;		\
+	sethi	%hi(__per_cpu_base), REG2;		\
+	ldx	[REG3 + %lo(__per_cpu_shift)], REG3;	\
+	ldx	[REG2 + %lo(__per_cpu_base)], REG2;	\
+	sllx	REG1, REG3, REG3;			\
+	add	REG3, REG2, DEST;
+
+#else
+
+#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP)		\
+	sethi	%hi(trap_block), DEST;		\
+	or	DEST, %lo(trap_block), DEST;	\
+
+/* Uniprocessor versions, we know the cpuid is zero.  */
+#define TRAP_LOAD_PGD_PHYS(DEST, TMP)		\
+	TRAP_LOAD_TRAP_BLOCK(DEST, TMP)		\
+	ldx	[DEST + TRAP_PER_CPU_PGD_PADDR], DEST;
+
+#define TRAP_LOAD_IRQ_WORK(DEST, TMP)		\
+	sethi	%hi(__irq_work), DEST;		\
+	or	DEST, %lo(__irq_work), DEST;
+
+#define TRAP_LOAD_THREAD_REG(DEST, TMP)		\
+	TRAP_LOAD_TRAP_BLOCK(DEST, TMP)		\
+	ldx	[DEST + TRAP_PER_CPU_THREAD], DEST;
+
+/* No per-cpu areas on uniprocessor, so no need to load DEST.  */
+#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3)
+
+#endif /* !(CONFIG_SMP) */
+
 #endif /* _SPARC64_CPUDATA_H */
diff -urN oldtree/include/asm-sparc64/elf.h newtree/include/asm-sparc64/elf.h
--- oldtree/include/asm-sparc64/elf.h	2006-02-19 11:41:05.733471480 +0000
+++ newtree/include/asm-sparc64/elf.h	2006-02-21 15:58:20.760990408 +0000
@@ -10,6 +10,7 @@
 #ifdef __KERNEL__
 #include <asm/processor.h>
 #include <asm/uaccess.h>
+#include <asm/spitfire.h>
 #endif
 
 /*
@@ -68,6 +69,7 @@
 #define HWCAP_SPARC_MULDIV      8
 #define HWCAP_SPARC_V9		16
 #define HWCAP_SPARC_ULTRA3	32
+#define HWCAP_SPARC_BLKINIT	64
 
 /*
  * These are used to set parameters in the core dumps.
@@ -145,11 +147,21 @@
    instruction set this cpu supports.  */
 
 /* On Ultra, we support all of the v8 capabilities. */
-#define ELF_HWCAP	((HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \
-			  HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV | \
-			  HWCAP_SPARC_V9) | \
-			 ((tlb_type == cheetah || tlb_type == cheetah_plus) ? \
-			  HWCAP_SPARC_ULTRA3 : 0))
+static inline unsigned int sparc64_elf_hwcap(void)
+{
+	unsigned int cap = (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR |
+			    HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV |
+			    HWCAP_SPARC_V9);
+
+	if (tlb_type == cheetah || tlb_type == cheetah_plus)
+		cap |= HWCAP_SPARC_ULTRA3;
+	else if (tlb_type == hypervisor)
+		cap |= HWCAP_SPARC_BLKINIT;
+
+	return cap;
+}
+
+#define ELF_HWCAP	sparc64_elf_hwcap();
 
 /* This yields a string that ld.so will use to load implementation
    specific libraries for optimization.  This is more specific in
diff -urN oldtree/include/asm-sparc64/head.h newtree/include/asm-sparc64/head.h
--- oldtree/include/asm-sparc64/head.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sparc64/head.h	2006-02-21 15:58:20.761990256 +0000
@@ -4,12 +4,21 @@
 
 #include <asm/pstate.h>
 
+	/* wrpr	%g0, val, %gl */
+#define SET_GL(val)	\
+	.word	0xa1902000 | val
+
+	/* rdpr %gl, %gN */
+#define GET_GL_GLOBAL(N)	\
+	.word	0x81540000 | (N << 25)
+
 #define KERNBASE	0x400000
 
 #define	PTREGS_OFF	(STACK_BIAS + STACKFRAME_SZ)
 
 #define __CHEETAH_ID	0x003e0014
 #define __JALAPENO_ID	0x003e0016
+#define __SERRANO_ID	0x003e0022
 
 #define CHEETAH_MANUF		0x003e
 #define CHEETAH_IMPL		0x0014 /* Ultra-III   */
@@ -19,6 +28,12 @@
 #define PANTHER_IMPL		0x0019 /* Ultra-IV+   */
 #define SERRANO_IMPL		0x0022 /* Ultra-IIIi+ */
 
+#define BRANCH_IF_SUN4V(tmp1,label)		\
+	sethi	%hi(is_sun4v), %tmp1;		\
+	lduw	[%tmp1 + %lo(is_sun4v)], %tmp1; \
+	brnz,pn	%tmp1, label;			\
+	 nop
+
 #define BRANCH_IF_CHEETAH_BASE(tmp1,tmp2,label)	\
 	rdpr	%ver, %tmp1;			\
 	sethi	%hi(__CHEETAH_ID), %tmp2;	\
diff -urN oldtree/include/asm-sparc64/hypervisor.h newtree/include/asm-sparc64/hypervisor.h
--- oldtree/include/asm-sparc64/hypervisor.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/include/asm-sparc64/hypervisor.h	2006-02-21 15:58:20.763989952 +0000
@@ -0,0 +1,2115 @@
+#ifndef _SPARC64_HYPERVISOR_H
+#define _SPARC64_HYPERVISOR_H
+
+/* Sun4v hypervisor interfaces and defines.
+ *
+ * Hypervisor calls are made via traps to software traps number 0x80
+ * and above.  Registers %o0 to %o5 serve as argument, status, and
+ * return value registers.
+ *
+ * There are two kinds of these traps.  First there are the normal
+ * "fast traps" which use software trap 0x80 and encode the function
+ * to invoke by number in register %o5.  Argument and return value
+ * handling is as follows:
+ *
+ * -----------------------------------------------
+ * |  %o5  | function number |     undefined     |
+ * |  %o0  |   argument 0    |   return status   |
+ * |  %o1  |   argument 1    |   return value 1  |
+ * |  %o2  |   argument 2    |   return value 2  |
+ * |  %o3  |   argument 3    |   return value 3  |
+ * |  %o4  |   argument 4    |   return value 4  |
+ * -----------------------------------------------
+ *
+ * The second type are "hyper-fast traps" which encode the function
+ * number in the software trap number itself.  So these use trap
+ * numbers > 0x80.  The register usage for hyper-fast traps is as
+ * follows:
+ *
+ * -----------------------------------------------
+ * |  %o0  |   argument 0    |   return status   |
+ * |  %o1  |   argument 1    |   return value 1  |
+ * |  %o2  |   argument 2    |   return value 2  |
+ * |  %o3  |   argument 3    |   return value 3  |
+ * |  %o4  |   argument 4    |   return value 4  |
+ * -----------------------------------------------
+ *
+ * Registers providing explicit arguments to the hypervisor calls
+ * are volatile across the call.  Upon return their values are
+ * undefined unless explicitly specified as containing a particular
+ * return value by the specific call.  The return status is always
+ * returned in register %o0, zero indicates a successful execution of
+ * the hypervisor call and other values indicate an error status as
+ * defined below.  So, for example, if a hyper-fast trap takes
+ * arguments 0, 1, and 2, then %o0, %o1, and %o2 are volatile across
+ * the call and %o3, %o4, and %o5 would be preserved.
+ *
+ * If the hypervisor trap is invalid, or the fast trap function number
+ * is invalid, HV_EBADTRAP will be returned in %o0.  Also, all 64-bits
+ * of the argument and return values are significant.
+ */
+
+/* Trap numbers.  */
+#define HV_FAST_TRAP		0x80
+#define HV_MMU_MAP_ADDR_TRAP	0x83
+#define HV_MMU_UNMAP_ADDR_TRAP	0x84
+#define HV_TTRACE_ADDENTRY_TRAP	0x85
+#define HV_CORE_TRAP		0xff
+
+/* Error codes.  */
+#define HV_EOK				0  /* Successful return            */
+#define HV_ENOCPU			1  /* Invalid CPU id               */
+#define HV_ENORADDR			2  /* Invalid real address         */
+#define HV_ENOINTR			3  /* Invalid interrupt id         */
+#define HV_EBADPGSZ			4  /* Invalid pagesize encoding    */
+#define HV_EBADTSB			5  /* Invalid TSB description      */
+#define HV_EINVAL			6  /* Invalid argument             */
+#define HV_EBADTRAP			7  /* Invalid function number      */
+#define HV_EBADALIGN			8  /* Invalid address alignment    */
+#define HV_EWOULDBLOCK			9  /* Cannot complete w/o blocking */
+#define HV_ENOACCESS			10 /* No access to resource        */
+#define HV_EIO				11 /* I/O error                    */
+#define HV_ECPUERROR			12 /* CPU in error state           */
+#define HV_ENOTSUPPORTED		13 /* Function not supported       */
+#define HV_ENOMAP			14 /* No mapping found             */
+#define HV_ETOOMANY			15 /* Too many items specified     */
+
+/* mach_exit()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MACH_EXIT
+ * ARG0:	exit code
+ * ERRORS:	This service does not return.
+ *
+ * Stop all CPUs in the virtual domain and place them into the stopped
+ * state.  The 64-bit exit code may be passed to a service entity as
+ * the domain's exit status.  On systems without a service entity, the
+ * domain will undergo a reset, and the boot firmware will be
+ * reloaded.
+ *
+ * This function will never return to the guest that invokes it.
+ *
+ * Note: By convention an exit code of zero denotes a successful exit by
+ *       the guest code.  A non-zero exit code denotes a guest specific
+ *       error indication.
+ *
+ */
+#define HV_FAST_MACH_EXIT		0x00
+
+/* Domain services.  */
+
+/* mach_desc()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MACH_DESC
+ * ARG0:	buffer
+ * ARG1:	length
+ * RET0:	status
+ * RET1:	length
+ * ERRORS:	HV_EBADALIGN	Buffer is badly aligned
+ *		HV_ENORADDR	Buffer is to an illegal real address.
+ *		HV_EINVAL	Buffer length is too small for complete
+ *				machine description.
+ *
+ * Copy the most current machine description into the buffer indicated
+ * by the real address in ARG0.  The buffer provided must be 16 byte
+ * aligned.  Upon success or HV_EINVAL, this service returns the
+ * actual size of the machine description in the RET1 return value.
+ *
+ * Note: A method of determining the appropriate buffer size for the
+ *       machine description is to first call this service with a buffer
+ *       length of 0 bytes.
+ */
+#define HV_FAST_MACH_DESC		0x01
+
+/* mach_exit()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MACH_SIR
+ * ERRORS:	This service does not return.
+ *
+ * Perform a software initiated reset of the virtual machine domain.
+ * All CPUs are captured as soon as possible, all hardware devices are
+ * returned to the entry default state, and the domain is restarted at
+ * the SIR (trap type 0x04) real trap table (RTBA) entry point on one
+ * of the CPUs.  The single CPU restarted is selected as determined by
+ * platform specific policy.  Memory is preserved across this
+ * operation.
+ */
+#define HV_FAST_MACH_SIR		0x02
+
+/* mach_set_soft_state()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MACH_SET_SOFT_STATE
+ * ARG0:	software state
+ * ARG1:	software state description pointer
+ * RET0:	status
+ * ERRORS:	EINVAL		software state not valid or software state
+ *				description is not NULL terminated
+ *		ENORADDR	software state description pointer is not a
+ *				valid real address
+ *		EBADALIGNED	software state description is not correctly
+ *				aligned
+ *
+ * This allows the guest to report it's soft state to the hypervisor.  There
+ * are two primary components to this state.  The first part states whether
+ * the guest software is running or not.  The second containts optional
+ * details specific to the software.
+ *
+ * The software state argument is defined below in HV_SOFT_STATE_*, and
+ * indicates whether the guest is operating normally or in a transitional
+ * state.
+ *
+ * The software state description argument is a real address of a data buffer
+ * of size 32-bytes aligned on a 32-byte boundary.  It is treated as a NULL
+ * terminated 7-bit ASCII string of up to 31 characters not including the
+ * NULL termination.
+ */
+#define HV_FAST_MACH_SET_SOFT_STATE	0x03
+#define  HV_SOFT_STATE_NORMAL		 0x01
+#define  HV_SOFT_STATE_TRANSITION	 0x02
+
+/* mach_get_soft_state()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MACH_GET_SOFT_STATE
+ * ARG0:	software state description pointer
+ * RET0:	status
+ * RET1:	software state
+ * ERRORS:	ENORADDR	software state description pointer is not a
+ *				valid real address
+ *		EBADALIGNED	software state description is not correctly
+ *				aligned
+ *
+ * Retrieve the current value of the guest's software state.  The rules
+ * for the software state pointer are the same as for mach_set_soft_state()
+ * above.
+ */
+#define HV_FAST_MACH_GET_SOFT_STATE	0x04
+
+/* CPU services.
+ *
+ * CPUs represent devices that can execute software threads.  A single
+ * chip that contains multiple cores or strands is represented as
+ * multiple CPUs with unique CPU identifiers.  CPUs are exported to
+ * OBP via the machine description (and to the OS via the OBP device
+ * tree).  CPUs are always in one of three states: stopped, running,
+ * or error.
+ *
+ * A CPU ID is a pre-assigned 16-bit value that uniquely identifies a
+ * CPU within a logical domain.  Operations that are to be performed
+ * on multiple CPUs specify them via a CPU list.  A CPU list is an
+ * array in real memory, of which each 16-bit word is a CPU ID.  CPU
+ * lists are passed through the API as two arguments.  The first is
+ * the number of entries (16-bit words) in the CPU list, and the
+ * second is the (real address) pointer to the CPU ID list.
+ */
+
+/* cpu_start()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_CPU_START
+ * ARG0:	CPU ID
+ * ARG1:	PC
+ * ARG1:	RTBA
+ * ARG1:	target ARG0
+ * RET0:	status
+ * ERRORS:	ENOCPU		Invalid CPU ID
+ *		EINVAL		Target CPU ID is not in the stopped state
+ *		ENORADDR	Invalid PC or RTBA real address
+ *		EBADALIGN	Unaligned PC or unaligned RTBA
+ *		EWOULDBLOCK	Starting resources are not available
+ *
+ * Start CPU with given CPU ID with PC in %pc and with a real trap
+ * base address value of RTBA.  The indicated CPU must be in the
+ * stopped state.  The supplied RTBA must be aligned on a 256 byte
+ * boundary.  On successful completion, the specified CPU will be in
+ * the running state and will be supplied with "target ARG0" in %o0
+ * and RTBA in %tba.
+ */
+#define HV_FAST_CPU_START		0x10
+
+/* cpu_stop()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_CPU_STOP
+ * ARG0:	CPU ID
+ * RET0:	status
+ * ERRORS:	ENOCPU		Invalid CPU ID
+ *		EINVAL		Target CPU ID is the current cpu
+ *		EINVAL		Target CPU ID is not in the running state
+ *		EWOULDBLOCK	Stopping resources are not available
+ *		ENOTSUPPORTED	Not supported on this platform
+ *
+ * The specified CPU is stopped.  The indicated CPU must be in the
+ * running state.  On completion, it will be in the stopped state.  It
+ * is not legal to stop the current CPU.
+ *
+ * Note: As this service cannot be used to stop the current cpu, this service
+ *       may not be used to stop the last running CPU in a domain.  To stop
+ *       and exit a running domain, a guest must use the mach_exit() service.
+ */
+#define HV_FAST_CPU_STOP		0x11
+
+/* cpu_yield()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_CPU_YIELD
+ * RET0:	status
+ * ERRORS:	No possible error.
+ *
+ * Suspend execution on the current CPU.  Execution will resume when
+ * an interrupt (device, %stick_compare, or cross-call) is targeted to
+ * the CPU.  On some CPUs, this API may be used by the hypervisor to
+ * save power by disabling hardware strands.
+ */
+#define HV_FAST_CPU_YIELD		0x12
+
+
+/* cpu_qconf()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_CPU_QCONF
+ * ARG0:	queue
+ * ARG1:	base real address
+ * ARG2:	number of entries
+ * RET0:	status
+ * ERRORS:	ENORADDR	Invalid base real address
+ *		EINVAL		Invalid queue or number of entries is less
+ *				than 2 or too large.
+ *		EBADALIGN	Base real address is not correctly aligned
+ *				for size.
+ *
+ * Configure the given queue to be placed at the given base real
+ * address, with the given number of entries.  The number of entries
+ * must be a power of 2.  The base real address must be aligned
+ * exactly to match the queue size.  Each queue entry is 64 bytes
+ * long, so for example a 32 entry queue must be aligned on a 2048
+ * byte real address boundary.
+ *
+ * The specified queue is unconfigured if the number of entries is given
+ * as zero.
+ *
+ * For the current version of this API service, the argument queue is defined
+ * as follows:
+ *
+ *	queue		description
+ *	-----		-------------------------
+ *	0x3c		cpu mondo queue
+ *	0x3d		device mondo queue
+ *	0x3e		resumable error queue
+ *	0x3f		non-resumable error queue
+ *
+ * Note: The maximum number of entries for each queue for a specific cpu may
+ *       be determined from the machine description.
+ */
+#define HV_FAST_CPU_QCONF		0x14
+#define  HV_CPU_QUEUE_CPU_MONDO		 0x3c
+#define  HV_CPU_QUEUE_DEVICE_MONDO	 0x3d
+#define  HV_CPU_QUEUE_RES_ERROR		 0x3e
+#define  HV_CPU_QUEUE_NONRES_ERROR	 0x3f
+
+#ifndef __ASSEMBLY__
+extern unsigned long sun4v_cpu_qconf(unsigned long type,
+				     unsigned long queue_paddr,
+				     unsigned long num_queue_entries);
+#endif
+
+/* cpu_qinfo()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_CPU_QINFO
+ * ARG0:	queue
+ * RET0:	status
+ * RET1:	base real address
+ * RET1:	number of entries
+ * ERRORS:	EINVAL		Invalid queue
+ *
+ * Return the configuration info for the given queue.  The base real
+ * address and number of entries of the defined queue are returned.
+ * The queue argument values are the same as for cpu_qconf() above.
+ *
+ * If the specified queue is a valid queue number, but no queue has
+ * been defined, the number of entries will be set to zero and the
+ * base real address returned is undefined.
+ */
+#define HV_FAST_CPU_QINFO		0x15
+
+/* cpu_mondo_send()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_CPU_MONDO_SEND
+ * ARG0-1:	CPU list
+ * ARG2:	data real address
+ * RET0:	status
+ * ERRORS:	EBADALIGN	Mondo data is not 64-byte aligned or CPU list
+ *				is not 2-byte aligned.
+ *		ENORADDR	Invalid data mondo address, or invalid cpu list
+ *				address.
+ *		ENOCPU		Invalid cpu in CPU list
+ *		EWOULDBLOCK	Some or all of the listed CPUs did not receive
+ *				the mondo
+ *		EINVAL		CPU list includes caller's CPU ID
+ *
+ * Send a mondo interrupt to the CPUs in the given CPU list with the
+ * 64-bytes at the given data real address.  The data must be 64-byte
+ * aligned.  The mondo data will be delivered to the cpu_mondo queues
+ * of the recipient CPUs.
+ *
+ * In all cases, error or not, the CPUs in the CPU list to which the
+ * mondo has been successfully delivered will be indicated by having
+ * their entry in CPU list updated with the value 0xffff.
+ */
+#define HV_FAST_CPU_MONDO_SEND		0x42
+
+/* cpu_myid()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_CPU_MYID
+ * RET0:	status
+ * RET1:	CPU ID
+ * ERRORS:	No errors defined.
+ *
+ * Return the hypervisor ID handle for the current CPU.  Use by a
+ * virtual CPU to discover it's own identity.
+ */
+#define HV_FAST_CPU_MYID		0x16
+
+/* cpu_state()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_CPU_STATE
+ * ARG0:	CPU ID
+ * RET0:	status
+ * RET1:	state
+ * ERRORS:	ENOCPU		Invalid CPU ID
+ *
+ * Retrieve the current state of the CPU with the given CPU ID.
+ */
+#define HV_FAST_CPU_STATE		0x17
+#define  HV_CPU_STATE_STOPPED		 0x01
+#define  HV_CPU_STATE_RUNNING		 0x02
+#define  HV_CPU_STATE_ERROR		 0x03
+
+/* cpu_set_rtba()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_CPU_SET_RTBA
+ * ARG0:	RTBA
+ * RET0:	status
+ * RET1:	previous RTBA
+ * ERRORS:	ENORADDR	Invalid RTBA real address
+ *		EBADALIGN	RTBA is incorrectly aligned for a trap table
+ *
+ * Set the real trap base address of the local cpu to the given RTBA.
+ * The supplied RTBA must be aligned on a 256 byte boundary.  Upon
+ * success the previous value of the RTBA is returned in RET1.
+ *
+ * Note: This service does not affect %tba
+ */
+#define HV_FAST_CPU_SET_RTBA		0x18
+
+/* cpu_set_rtba()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_CPU_GET_RTBA
+ * RET0:	status
+ * RET1:	previous RTBA
+ * ERRORS:	No possible error.
+ *
+ * Returns the current value of RTBA in RET1.
+ */
+#define HV_FAST_CPU_GET_RTBA		0x19
+
+/* MMU services.
+ *
+ * Layout of a TSB description for mmu_tsb_ctx{,non}0() calls.
+ */
+#ifndef __ASSEMBLY__
+struct hv_tsb_descr {
+	unsigned short		pgsz_idx;
+	unsigned short		assoc;
+	unsigned int		num_ttes;	/* in TTEs */
+	unsigned int		ctx_idx;
+	unsigned int		pgsz_mask;
+	unsigned long		tsb_base;
+	unsigned long		resv;
+};
+#endif
+#define HV_TSB_DESCR_PGSZ_IDX_OFFSET	0x00
+#define HV_TSB_DESCR_ASSOC_OFFSET	0x02
+#define HV_TSB_DESCR_NUM_TTES_OFFSET	0x04
+#define HV_TSB_DESCR_CTX_IDX_OFFSET	0x08
+#define HV_TSB_DESCR_PGSZ_MASK_OFFSET	0x0c
+#define HV_TSB_DESCR_TSB_BASE_OFFSET	0x10
+#define HV_TSB_DESCR_RESV_OFFSET	0x18
+
+/* Page size bitmask.  */
+#define HV_PGSZ_MASK_8K			(1 << 0)
+#define HV_PGSZ_MASK_64K		(1 << 1)
+#define HV_PGSZ_MASK_512K		(1 << 2)
+#define HV_PGSZ_MASK_4MB		(1 << 3)
+#define HV_PGSZ_MASK_32MB		(1 << 4)
+#define HV_PGSZ_MASK_256MB		(1 << 5)
+#define HV_PGSZ_MASK_2GB		(1 << 6)
+#define HV_PGSZ_MASK_16GB		(1 << 7)
+
+/* Page size index.  The value given in the TSB descriptor must correspond
+ * to the smallest page size specified in the pgsz_mask page size bitmask.
+ */
+#define HV_PGSZ_IDX_8K			0
+#define HV_PGSZ_IDX_64K			1
+#define HV_PGSZ_IDX_512K		2
+#define HV_PGSZ_IDX_4MB			3
+#define HV_PGSZ_IDX_32MB		4
+#define HV_PGSZ_IDX_256MB		5
+#define HV_PGSZ_IDX_2GB			6
+#define HV_PGSZ_IDX_16GB		7
+
+/* MMU fault status area.
+ *
+ * MMU related faults have their status and fault address information
+ * placed into a memory region made available by privileged code.  Each
+ * virtual processor must make a mmu_fault_area_conf() call to tell the
+ * hypervisor where that processor's fault status should be stored.
+ *
+ * The fault status block is a multiple of 64-bytes and must be aligned
+ * on a 64-byte boundary.
+ */
+#ifndef __ASSEMBLY__
+struct hv_fault_status {
+	unsigned long		i_fault_type;
+	unsigned long		i_fault_addr;
+	unsigned long		i_fault_ctx;
+	unsigned long		i_reserved[5];
+	unsigned long		d_fault_type;
+	unsigned long		d_fault_addr;
+	unsigned long		d_fault_ctx;
+	unsigned long		d_reserved[5];
+};
+#endif
+#define HV_FAULT_I_TYPE_OFFSET	0x00
+#define HV_FAULT_I_ADDR_OFFSET	0x08
+#define HV_FAULT_I_CTX_OFFSET	0x10
+#define HV_FAULT_D_TYPE_OFFSET	0x40
+#define HV_FAULT_D_ADDR_OFFSET	0x48
+#define HV_FAULT_D_CTX_OFFSET	0x50
+
+#define HV_FAULT_TYPE_FAST_MISS	1
+#define HV_FAULT_TYPE_FAST_PROT	2
+#define HV_FAULT_TYPE_MMU_MISS	3
+#define HV_FAULT_TYPE_INV_RA	4
+#define HV_FAULT_TYPE_PRIV_VIOL	5
+#define HV_FAULT_TYPE_PROT_VIOL	6
+#define HV_FAULT_TYPE_NFO	7
+#define HV_FAULT_TYPE_NFO_SEFF	8
+#define HV_FAULT_TYPE_INV_VA	9
+#define HV_FAULT_TYPE_INV_ASI	10
+#define HV_FAULT_TYPE_NC_ATOMIC	11
+#define HV_FAULT_TYPE_PRIV_ACT	12
+#define HV_FAULT_TYPE_RESV1	13
+#define HV_FAULT_TYPE_UNALIGNED	14
+#define HV_FAULT_TYPE_INV_PGSZ	15
+/* Values 16 --> -2 are reserved.  */
+#define HV_FAULT_TYPE_MULTIPLE	-1
+
+/* Flags argument for mmu_{map,unmap}_addr(), mmu_demap_{page,context,all}(),
+ * and mmu_{map,unmap}_perm_addr().
+ */
+#define HV_MMU_DMMU			0x01
+#define HV_MMU_IMMU			0x02
+#define HV_MMU_ALL			(HV_MMU_DMMU | HV_MMU_IMMU)
+
+/* mmu_map_addr()
+ * TRAP:	HV_MMU_MAP_ADDR_TRAP
+ * ARG0:	virtual address
+ * ARG1:	mmu context
+ * ARG2:	TTE
+ * ARG3:	flags (HV_MMU_{IMMU,DMMU})
+ * ERRORS:	EINVAL		Invalid virtual address, mmu context, or flags
+ *		EBADPGSZ	Invalid page size value
+ *		ENORADDR	Invalid real address in TTE
+ *
+ * Create a non-permanent mapping using the given TTE, virtual
+ * address, and mmu context.  The flags argument determines which
+ * (data, or instruction, or both) TLB the mapping gets loaded into.
+ *
+ * The behavior is undefined if the valid bit is clear in the TTE.
+ *
+ * Note: This API call is for privileged code to specify temporary translation
+ *       mappings without the need to create and manage a TSB.
+ */
+
+/* mmu_unmap_addr()
+ * TRAP:	HV_MMU_UNMAP_ADDR_TRAP
+ * ARG0:	virtual address
+ * ARG1:	mmu context
+ * ARG2:	flags (HV_MMU_{IMMU,DMMU})
+ * ERRORS:	EINVAL		Invalid virtual address, mmu context, or flags
+ *
+ * Demaps the given virtual address in the given mmu context on this
+ * CPU.  This function is intended to be used to demap pages mapped
+ * with mmu_map_addr.  This service is equivalent to invoking
+ * mmu_demap_page() with only the current CPU in the CPU list. The
+ * flags argument determines which (data, or instruction, or both) TLB
+ * the mapping gets unmapped from.
+ *
+ * Attempting to perform an unmap operation for a previously defined
+ * permanent mapping will have undefined results.
+ */
+
+/* mmu_tsb_ctx0()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MMU_TSB_CTX0
+ * ARG0:	number of TSB descriptions
+ * ARG1:	TSB descriptions pointer
+ * RET0:	status
+ * ERRORS:	ENORADDR		Invalid TSB descriptions pointer or
+ *					TSB base within a descriptor
+ *		EBADALIGN		TSB descriptions pointer is not aligned
+ *					to an 8-byte boundary, or TSB base
+ *					within a descriptor is not aligned for
+ *					the given TSB size
+ *		EBADPGSZ		Invalid page size in a TSB descriptor
+ *		EBADTSB			Invalid associativity or size in a TSB
+ *					descriptor
+ *		EINVAL			Invalid number of TSB descriptions, or
+ *					invalid context index in a TSB
+ *					descriptor, or index page size not
+ *					equal to smallest page size in page
+ *					size bitmask field.
+ *
+ * Configures the TSBs for the current CPU for virtual addresses with
+ * context zero.  The TSB descriptions pointer is a pointer to an
+ * array of the given number of TSB descriptions.
+ *
+ * Note: The maximum number of TSBs available to a virtual CPU is given by the
+ *       mmu-max-#tsbs property of the cpu's corresponding "cpu" node in the
+ *       machine description.
+ */
+#define HV_FAST_MMU_TSB_CTX0		0x20
+
+/* mmu_tsb_ctxnon0()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MMU_TSB_CTXNON0
+ * ARG0:	number of TSB descriptions
+ * ARG1:	TSB descriptions pointer
+ * RET0:	status
+ * ERRORS:	Same as for mmu_tsb_ctx0() above.
+ *
+ * Configures the TSBs for the current CPU for virtual addresses with
+ * non-zero contexts.  The TSB descriptions pointer is a pointer to an
+ * array of the given number of TSB descriptions.
+ *
+ * Note: A maximum of 16 TSBs may be specified in the TSB description list.
+ */
+#define HV_FAST_MMU_TSB_CTXNON0		0x21
+
+/* mmu_demap_page()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MMU_DEMAP_PAGE
+ * ARG0:	reserved, must be zero
+ * ARG1:	reserved, must be zero
+ * ARG2:	virtual address
+ * ARG3:	mmu context
+ * ARG4:	flags (HV_MMU_{IMMU,DMMU})
+ * RET0:	status
+ * ERRORS:	EINVAL			Invalid virutal address, context, or
+ *					flags value
+ *		ENOTSUPPORTED		ARG0 or ARG1 is non-zero
+ *
+ * Demaps any page mapping of the given virtual address in the given
+ * mmu context for the current virtual CPU.  Any virtually tagged
+ * caches are guaranteed to be kept consistent.  The flags argument
+ * determines which TLB (instruction, or data, or both) participate in
+ * the operation.
+ *
+ * ARG0 and ARG1 are both reserved and must be set to zero.
+ */
+#define HV_FAST_MMU_DEMAP_PAGE		0x22
+
+/* mmu_demap_ctx()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MMU_DEMAP_CTX
+ * ARG0:	reserved, must be zero
+ * ARG1:	reserved, must be zero
+ * ARG2:	mmu context
+ * ARG3:	flags (HV_MMU_{IMMU,DMMU})
+ * RET0:	status
+ * ERRORS:	EINVAL			Invalid context or flags value
+ *		ENOTSUPPORTED		ARG0 or ARG1 is non-zero
+ *
+ * Demaps all non-permanent virtual page mappings previously specified
+ * for the given context for the current virtual CPU.  Any virtual
+ * tagged caches are guaranteed to be kept consistent.  The flags
+ * argument determines which TLB (instruction, or data, or both)
+ * participate in the operation.
+ *
+ * ARG0 and ARG1 are both reserved and must be set to zero.
+ */
+#define HV_FAST_MMU_DEMAP_CTX		0x23
+
+/* mmu_demap_all()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MMU_DEMAP_ALL
+ * ARG0:	reserved, must be zero
+ * ARG1:	reserved, must be zero
+ * ARG2:	flags (HV_MMU_{IMMU,DMMU})
+ * RET0:	status
+ * ERRORS:	EINVAL			Invalid flags value
+ *		ENOTSUPPORTED		ARG0 or ARG1 is non-zero
+ *
+ * Demaps all non-permanent virtual page mappings previously specified
+ * for the current virtual CPU.  Any virtual tagged caches are
+ * guaranteed to be kept consistent.  The flags argument determines
+ * which TLB (instruction, or data, or both) participate in the
+ * operation.
+ *
+ * ARG0 and ARG1 are both reserved and must be set to zero.
+ */
+#define HV_FAST_MMU_DEMAP_ALL		0x24
+
+/* mmu_map_perm_addr()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MMU_MAP_PERM_ADDR
+ * ARG0:	virtual address
+ * ARG1:	reserved, must be zero
+ * ARG2:	TTE
+ * ARG3:	flags (HV_MMU_{IMMU,DMMU})
+ * RET0:	status
+ * ERRORS:	EINVAL			Invalid virutal address or flags value
+ *		EBADPGSZ		Invalid page size value
+ *		ENORADDR		Invalid real address in TTE
+ *		ETOOMANY		Too many mappings (max of 8 reached)
+ *
+ * Create a permanent mapping using the given TTE and virtual address
+ * for context 0 on the calling virtual CPU.  A maximum of 8 such
+ * permanent mappings may be specified by privileged code.  Mappings
+ * may be removed with mmu_unmap_perm_addr().
+ *
+ * The behavior is undefined if a TTE with the valid bit clear is given.
+ *
+ * Note: This call is used to specify address space mappings for which
+ *       privileged code does not expect to receive misses.  For example,
+ *       this mechanism can be used to map kernel nucleus code and data.
+ */
+#define HV_FAST_MMU_MAP_PERM_ADDR	0x25
+
+/* mmu_fault_area_conf()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MMU_FAULT_AREA_CONF
+ * ARG0:	real address
+ * RET0:	status
+ * RET1:	previous mmu fault area real address
+ * ERRORS:	ENORADDR		Invalid real address
+ *		EBADALIGN		Invalid alignment for fault area
+ *
+ * Configure the MMU fault status area for the calling CPU.  A 64-byte
+ * aligned real address specifies where MMU fault status information
+ * is placed.  The return value is the previously specified area, or 0
+ * for the first invocation.  Specifying a fault area at real address
+ * 0 is not allowed.
+ */
+#define HV_FAST_MMU_FAULT_AREA_CONF	0x26
+
+/* mmu_enable()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MMU_ENABLE
+ * ARG0:	enable flag
+ * ARG1:	return target address
+ * RET0:	status
+ * ERRORS:	ENORADDR		Invalid real address when disabling
+ *					translation.
+ *		EBADALIGN		The return target address is not
+ *					aligned to an instruction.
+ *		EINVAL			The enable flag request the current
+ *					operating mode (e.g. disable if already
+ *					disabled)
+ *
+ * Enable or disable virtual address translation for the calling CPU
+ * within the virtual machine domain.  If the enable flag is zero,
+ * translation is disabled, any non-zero value will enable
+ * translation.
+ *
+ * When this function returns, the newly selected translation mode
+ * will be active.  If the mmu is being enabled, then the return
+ * target address is a virtual address else it is a real address.
+ *
+ * Upon successful completion, control will be returned to the given
+ * return target address (ie. the cpu will jump to that address).  On
+ * failure, the previous mmu mode remains and the trap simply returns
+ * as normal with the appropriate error code in RET0.
+ */
+#define HV_FAST_MMU_ENABLE		0x27
+
+/* mmu_unmap_perm_addr()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MMU_UNMAP_PERM_ADDR
+ * ARG0:	virtual address
+ * ARG1:	reserved, must be zero
+ * ARG2:	flags (HV_MMU_{IMMU,DMMU})
+ * RET0:	status
+ * ERRORS:	EINVAL			Invalid virutal address or flags value
+ *		ENOMAP			Specified mapping was not found
+ *
+ * Demaps any permanent page mapping (established via
+ * mmu_map_perm_addr()) at the given virtual address for context 0 on
+ * the current virtual CPU.  Any virtual tagged caches are guaranteed
+ * to be kept consistent.
+ */
+#define HV_FAST_MMU_UNMAP_PERM_ADDR	0x28
+
+/* mmu_tsb_ctx0_info()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MMU_TSB_CTX0_INFO
+ * ARG0:	max TSBs
+ * ARG1:	buffer pointer
+ * RET0:	status
+ * RET1:	number of TSBs
+ * ERRORS:	EINVAL			Supplied buffer is too small
+ *		EBADALIGN		The buffer pointer is badly aligned
+ *		ENORADDR		Invalid real address for buffer pointer
+ *
+ * Return the TSB configuration as previous defined by mmu_tsb_ctx0()
+ * into the provided buffer.  The size of the buffer is given in ARG1
+ * in terms of the number of TSB description entries.
+ *
+ * Upon return, RET1 always contains the number of TSB descriptions
+ * previously configured.  If zero TSBs were configured, EOK is
+ * returned with RET1 containing 0.
+ */
+#define HV_FAST_MMU_TSB_CTX0_INFO	0x29
+
+/* mmu_tsb_ctxnon0_info()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MMU_TSB_CTXNON0_INFO
+ * ARG0:	max TSBs
+ * ARG1:	buffer pointer
+ * RET0:	status
+ * RET1:	number of TSBs
+ * ERRORS:	EINVAL			Supplied buffer is too small
+ *		EBADALIGN		The buffer pointer is badly aligned
+ *		ENORADDR		Invalid real address for buffer pointer
+ *
+ * Return the TSB configuration as previous defined by
+ * mmu_tsb_ctxnon0() into the provided buffer.  The size of the buffer
+ * is given in ARG1 in terms of the number of TSB description entries.
+ *
+ * Upon return, RET1 always contains the number of TSB descriptions
+ * previously configured.  If zero TSBs were configured, EOK is
+ * returned with RET1 containing 0.
+ */
+#define HV_FAST_MMU_TSB_CTXNON0_INFO	0x2a
+
+/* mmu_fault_area_info()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MMU_FAULT_AREA_INFO
+ * RET0:	status
+ * RET1:	fault area real address
+ * ERRORS:	No errors defined.
+ *
+ * Return the currently defined MMU fault status area for the current
+ * CPU.  The real address of the fault status area is returned in
+ * RET1, or 0 is returned in RET1 if no fault status area is defined.
+ *
+ * Note: mmu_fault_area_conf() may be called with the return value (RET1)
+ *       from this service if there is a need to save and restore the fault
+ *	 area for a cpu.
+ */
+#define HV_FAST_MMU_FAULT_AREA_INFO	0x2b
+
+/* Cache and Memory services. */
+
+/* mem_scrub()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MEM_SCRUB
+ * ARG0:	real address
+ * ARG1:	length
+ * RET0:	status
+ * RET1:	length scrubbed
+ * ERRORS:	ENORADDR	Invalid real address
+ *		EBADALIGN	Start address or length are not correctly
+ *				aligned
+ *		EINVAL		Length is zero
+ *
+ * Zero the memory contents in the range real address to real address
+ * plus length minus 1.  Also, valid ECC will be generated for that
+ * memory address range.  Scrubbing is started at the given real
+ * address, but may not scrub the entire given length.  The actual
+ * length scrubbed will be returned in RET1.
+ *
+ * The real address and length must be aligned on an 8K boundary, or
+ * contain the start address and length from a sun4v error report.
+ *
+ * Note: There are two uses for this function.  The first use is to block clear
+ *       and initialize memory and the second is to scrub an u ncorrectable
+ *       error reported via a resumable or non-resumable trap.  The second
+ *       use requires the arguments to be equal to the real address and length
+ *       provided in a sun4v memory error report.
+ */
+#define HV_FAST_MEM_SCRUB		0x31
+
+/* mem_sync()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MEM_SYNC
+ * ARG0:	real address
+ * ARG1:	length
+ * RET0:	status
+ * RET1:	length synced
+ * ERRORS:	ENORADDR	Invalid real address
+ *		EBADALIGN	Start address or length are not correctly
+ *				aligned
+ *		EINVAL		Length is zero
+ *
+ * Force the next access within the real address to real address plus
+ * length minus 1 to be fetches from main system memory.  Less than
+ * the given length may be synced, the actual amount synced is
+ * returned in RET1.  The real address and length must be aligned on
+ * an 8K boundary.
+ */
+#define HV_FAST_MEM_SYNC		0x32
+
+/* Time of day services.
+ *
+ * The hypervisor maintains the time of day on a per-domain basis.
+ * Changing the time of day in one domain does not affect the time of
+ * day on any other domain.
+ *
+ * Time is described by a single unsigned 64-bit word which is the
+ * number of seconds since the UNIX Epoch (00:00:00 UTC, January 1,
+ * 1970).
+ */
+
+/* tod_get()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_TOD_GET
+ * RET0:	status
+ * RET1:	TOD
+ * ERRORS:	EWOULDBLOCK	TOD resource is temporarily unavailable
+ *		ENOTSUPPORTED	If TOD not supported on this platform
+ *
+ * Return the current time of day.  May block if TOD access is
+ * temporarily not possible.
+ */
+#define HV_FAST_TOD_GET			0x50
+
+/* tod_set()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_TOD_SET
+ * ARG0:	TOD
+ * RET0:	status
+ * ERRORS:	EWOULDBLOCK	TOD resource is temporarily unavailable
+ *		ENOTSUPPORTED	If TOD not supported on this platform
+ *
+ * The current time of day is set to the value specified in ARG0.  May
+ * block if TOD access is temporarily not possible.
+ */
+#define HV_FAST_TOD_SET			0x51
+
+/* Console services */
+
+/* con_getchar()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_CONS_GETCHAR
+ * RET0:	status
+ * RET1:	character
+ * ERRORS:	EWOULDBLOCK	No character available.
+ *
+ * Returns a character from the console device.  If no character is
+ * available then an EWOULDBLOCK error is returned.  If a character is
+ * available, then the returned status is EOK and the character value
+ * is in RET1.
+ *
+ * A virtual BREAK is represented by the 64-bit value -1.
+ *
+ * A virtual HUP signal is represented by the 64-bit value -2.
+ */
+#define HV_FAST_CONS_GETCHAR		0x60
+
+/* con_putchar()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_CONS_PUTCHAR
+ * ARG0:	character
+ * RET0:	status
+ * ERRORS:	EINVAL		Illegal character
+ *		EWOULDBLOCK	Output buffer currently full, would block
+ *
+ * Send a character to the console device.  Only character values
+ * between 0 and 255 may be used.  Values outside this range are
+ * invalid except for the 64-bit value -1 which is used to send a
+ * virtual BREAK.
+ */
+#define HV_FAST_CONS_PUTCHAR		0x61
+
+/* Trap trace services.
+ *
+ * The hypervisor provides a trap tracing capability for privileged
+ * code running on each virtual CPU.  Privileged code provides a
+ * round-robin trap trace queue within which the hypervisor writes
+ * 64-byte entries detailing hyperprivileged traps taken n behalf of
+ * privileged code.  This is provided as a debugging capability for
+ * privileged code.
+ *
+ * The trap trace control structure is 64-bytes long and placed at the
+ * start (offset 0) of the trap trace buffer, and is described as
+ * follows:
+ */
+#ifndef __ASSEMBLY__
+struct hv_trap_trace_control {
+	unsigned long		head_offset;
+	unsigned long		tail_offset;
+	unsigned long		__reserved[0x30 / sizeof(unsigned long)];
+};
+#endif
+#define HV_TRAP_TRACE_CTRL_HEAD_OFFSET	0x00
+#define HV_TRAP_TRACE_CTRL_TAIL_OFFSET	0x08
+
+/* The head offset is the offset of the most recently completed entry
+ * in the trap-trace buffer.  The tail offset is the offset of the
+ * next entry to be written.  The control structure is owned and
+ * modified by the hypervisor.  A guest may not modify the control
+ * structure contents.  Attempts to do so will result in undefined
+ * behavior for the guest.
+ *
+ * Each trap trace buffer entry is layed out as follows:
+ */
+#ifndef __ASSEMBLY__
+struct hv_trap_trace_entry {
+	unsigned char	type;		/* Hypervisor or guest entry?	*/
+	unsigned char	hpstate;	/* Hyper-privileged state	*/
+	unsigned char	tl;		/* Trap level			*/
+	unsigned char	gl;		/* Global register level	*/
+	unsigned short	tt;		/* Trap type			*/
+	unsigned short	tag;		/* Extended trap identifier	*/
+	unsigned long	tstate;		/* Trap state			*/
+	unsigned long	tick;		/* Tick				*/
+	unsigned long	tpc;		/* Trap PC			*/
+	unsigned long	f1;		/* Entry specific		*/
+	unsigned long	f2;		/* Entry specific		*/
+	unsigned long	f3;		/* Entry specific		*/
+	unsigned long	f4;		/* Entry specific		*/
+};
+#endif
+#define HV_TRAP_TRACE_ENTRY_TYPE	0x00
+#define HV_TRAP_TRACE_ENTRY_HPSTATE	0x01
+#define HV_TRAP_TRACE_ENTRY_TL		0x02
+#define HV_TRAP_TRACE_ENTRY_GL		0x03
+#define HV_TRAP_TRACE_ENTRY_TT		0x04
+#define HV_TRAP_TRACE_ENTRY_TAG		0x06
+#define HV_TRAP_TRACE_ENTRY_TSTATE	0x08
+#define HV_TRAP_TRACE_ENTRY_TICK	0x10
+#define HV_TRAP_TRACE_ENTRY_TPC		0x18
+#define HV_TRAP_TRACE_ENTRY_F1		0x20
+#define HV_TRAP_TRACE_ENTRY_F2		0x28
+#define HV_TRAP_TRACE_ENTRY_F3		0x30
+#define HV_TRAP_TRACE_ENTRY_F4		0x38
+
+/* The type field is encoded as follows.  */
+#define HV_TRAP_TYPE_UNDEF		0x00 /* Entry content undefined     */
+#define HV_TRAP_TYPE_HV			0x01 /* Hypervisor trap entry       */
+#define HV_TRAP_TYPE_GUEST		0xff /* Added via ttrace_addentry() */
+
+/* ttrace_buf_conf()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_TTRACE_BUF_CONF
+ * ARG0:	real address
+ * ARG1:	number of entries
+ * RET0:	status
+ * RET1:	number of entries
+ * ERRORS:	ENORADDR	Invalid real address
+ *		EINVAL		Size is too small
+ *		EBADALIGN	Real address not aligned on 64-byte boundary
+ *
+ * Requests hypervisor trap tracing and declares a virtual CPU's trap
+ * trace buffer to the hypervisor.  The real address supplies the real
+ * base address of the trap trace queue and must be 64-byte aligned.
+ * Specifying a value of 0 for the number of entries disables trap
+ * tracing for the calling virtual CPU.  The buffer allocated must be
+ * sized for a power of two number of 64-byte trap trace entries plus
+ * an initial 64-byte control structure.
+ * 
+ * This may be invoked any number of times so that a virtual CPU may
+ * relocate a trap trace buffer or create "snapshots" of information.
+ *
+ * If the real address is illegal or badly aligned, then trap tracing
+ * is disabled and an error is returned.
+ *
+ * Upon failure with EINVAL, this service call returns in RET1 the
+ * minimum number of buffer entries required.  Upon other failures
+ * RET1 is undefined.
+ */
+#define HV_FAST_TTRACE_BUF_CONF		0x90
+
+/* ttrace_buf_info()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_TTRACE_BUF_INFO
+ * RET0:	status
+ * RET1:	real address
+ * RET2:	size
+ * ERRORS:	None defined.
+ *
+ * Returns the size and location of the previously declared trap-trace
+ * buffer.  In the event that no buffer was previously defined, or the
+ * buffer is disabled, this call will return a size of zero bytes.
+ */
+#define HV_FAST_TTRACE_BUF_INFO		0x91
+
+/* ttrace_enable()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_TTRACE_ENABLE
+ * ARG0:	enable
+ * RET0:	status
+ * RET1:	previous enable state
+ * ERRORS:	EINVAL		No trap trace buffer currently defined
+ *
+ * Enable or disable trap tracing, and return the previous enabled
+ * state in RET1.  Future systems may define various flags for the
+ * enable argument (ARG0), for the moment a guest should pass
+ * "(uint64_t) -1" to enable, and "(uint64_t) 0" to disable all
+ * tracing - which will ensure future compatability.
+ */
+#define HV_FAST_TTRACE_ENABLE		0x92
+
+/* ttrace_freeze()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_TTRACE_FREEZE
+ * ARG0:	freeze
+ * RET0:	status
+ * RET1:	previous freeze state
+ * ERRORS:	EINVAL		No trap trace buffer currently defined
+ *
+ * Freeze or unfreeze trap tracing, returning the previous freeze
+ * state in RET1.  A guest should pass a non-zero value to freeze and
+ * a zero value to unfreeze all tracing.  The returned previous state
+ * is 0 for not frozen and 1 for frozen.
+ */
+#define HV_FAST_TTRACE_FREEZE		0x93
+
+/* ttrace_addentry()
+ * TRAP:	HV_TTRACE_ADDENTRY_TRAP
+ * ARG0:	tag (16-bits)
+ * ARG1:	data word 0
+ * ARG2:	data word 1
+ * ARG3:	data word 2
+ * ARG4:	data word 3
+ * RET0:	status
+ * ERRORS:	EINVAL		No trap trace buffer currently defined
+ *
+ * Add an entry to the trap trace buffer.  Upon return only ARG0/RET0
+ * is modified - none of the other registers holding arguments are
+ * volatile across this hypervisor service.
+ */
+
+/* Core dump services.
+ *
+ * Since the hypervisor viraulizes and thus obscures a lot of the
+ * physical machine layout and state, traditional OS crash dumps can
+ * be difficult to diagnose especially when the problem is a
+ * configuration error of some sort.
+ *
+ * The dump services provide an opaque buffer into which the
+ * hypervisor can place it's internal state in order to assist in
+ * debugging such situations.  The contents are opaque and extremely
+ * platform and hypervisor implementation specific.  The guest, during
+ * a core dump, requests that the hypervisor update any information in
+ * the dump buffer in preparation to being dumped as part of the
+ * domain's memory image.
+ */
+
+/* dump_buf_update()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_DUMP_BUF_UPDATE
+ * ARG0:	real address
+ * ARG1:	size
+ * RET0:	status
+ * RET1:	required size of dump buffer
+ * ERRORS:	ENORADDR	Invalid real address
+ *		EBADALIGN	Real address is not aligned on a 64-byte
+ *				boundary
+ *		EINVAL		Size is non-zero but less than minimum size
+ *				required
+ *		ENOTSUPPORTED	Operation not supported on current logical
+ *				domain
+ *
+ * Declare a domain dump buffer to the hypervisor.  The real address
+ * provided for the domain dump buffer must be 64-byte aligned.  The
+ * size specifies the size of the dump buffer and may be larger than
+ * the minimum size specified in the machine description.  The
+ * hypervisor will fill the dump buffer with opaque data.
+ *
+ * Note: A guest may elect to include dump buffer contents as part of a crash
+ *       dump to assist with debugging.  This function may be called any number
+ *       of times so that a guest may relocate a dump buffer, or create
+ *       "snapshots" of any dump-buffer information.  Each call to
+ *       dump_buf_update() atomically declares the new dump buffer to the
+ *       hypervisor.
+ *
+ * A specified size of 0 unconfigures the dump buffer.  If the real
+ * address is illegal or badly aligned, then any currently active dump
+ * buffer is disabled and an error is returned.
+ *
+ * In the event that the call fails with EINVAL, RET1 contains the
+ * minimum size requires by the hypervisor for a valid dump buffer.
+ */
+#define HV_FAST_DUMP_BUF_UPDATE		0x94
+
+/* dump_buf_info()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_DUMP_BUF_INFO
+ * RET0:	status
+ * RET1:	real address of current dump buffer
+ * RET2:	size of current dump buffer
+ * ERRORS:	No errors defined.
+ *
+ * Return the currently configures dump buffer description.  A
+ * returned size of 0 bytes indicates an undefined dump buffer.  In
+ * this case the return address in RET1 is undefined.
+ */
+#define HV_FAST_DUMP_BUF_INFO		0x95
+
+/* Device interrupt services.
+ *
+ * Device interrupts are allocated to system bus bridges by the hypervisor,
+ * and described to OBP in the machine description.  OBP then describes
+ * these interrupts to the OS via properties in the device tree.
+ *
+ * Terminology:
+ *
+ *	cpuid		Unique opaque value which represents a target cpu.
+ *
+ *	devhandle	Device handle.  It uniquely identifies a device, and
+ *			consistes of the lower 28-bits of the hi-cell of the
+ *			first entry of the device's "reg" property in the
+ *			OBP device tree.
+ *
+ *	devino		Device interrupt number.  Specifies the relative
+ *			interrupt number within the device.  The unique
+ *			combination of devhandle and devino are used to
+ *			identify a specific device interrupt.
+ *
+ *			Note: The devino value is the same as the values in the
+ *			      "interrupts" property or "interrupt-map" property
+ *			      in the OBP device tree for that device.
+ *
+ *	sysino		System interrupt number.  A 64-bit unsigned interger
+ *			representing a unique interrupt within a virtual
+ *			machine.
+ *
+ *	intr_state	A flag representing the interrupt state for a given
+ *			sysino.  The state values are defined below.
+ *
+ *	intr_enabled	A flag representing the 'enabled' state for a given
+ *			sysino.  The enable values are defined below.
+ */
+
+#define HV_INTR_STATE_IDLE		0 /* Nothing pending */
+#define HV_INTR_STATE_RECEIVED		1 /* Interrupt received by hardware */
+#define HV_INTR_STATE_DELIVERED		2 /* Interrupt delivered to queue */
+
+#define HV_INTR_DISABLED		0 /* sysino not enabled */
+#define HV_INTR_ENABLED			1 /* sysino enabled */
+
+/* intr_devino_to_sysino()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_INTR_DEVINO2SYSINO
+ * ARG0:	devhandle
+ * ARG1:	devino
+ * RET0:	status
+ * RET1:	sysino
+ * ERRORS:	EINVAL		Invalid devhandle/devino
+ *
+ * Converts a device specific interrupt number of the given
+ * devhandle/devino into a system specific ino (sysino).
+ */
+#define HV_FAST_INTR_DEVINO2SYSINO	0xa0
+
+#ifndef __ASSEMBLY__
+extern unsigned long sun4v_devino_to_sysino(unsigned long devhandle,
+					    unsigned long devino);
+#endif
+
+/* intr_getenabled()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_INTR_GETENABLED
+ * ARG0:	sysino
+ * RET0:	status
+ * RET1:	intr_enabled (HV_INTR_{DISABLED,ENABLED})
+ * ERRORS:	EINVAL		Invalid sysino
+ *
+ * Returns interrupt enabled state in RET1 for the interrupt defined
+ * by the given sysino.
+ */
+#define HV_FAST_INTR_GETENABLED		0xa1
+
+#ifndef __ASSEMBLY__
+extern unsigned long sun4v_intr_getenabled(unsigned long sysino);
+#endif
+
+/* intr_setenabled()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_INTR_SETENABLED
+ * ARG0:	sysino
+ * ARG1:	intr_enabled (HV_INTR_{DISABLED,ENABLED})
+ * RET0:	status
+ * ERRORS:	EINVAL		Invalid sysino or intr_enabled value
+ *
+ * Set the 'enabled' state of the interrupt sysino.
+ */
+#define HV_FAST_INTR_SETENABLED		0xa2
+
+#ifndef __ASSEMBLY__
+extern unsigned long sun4v_intr_setenabled(unsigned long sysino, unsigned long intr_enabled);
+#endif
+
+/* intr_getstate()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_INTR_GETSTATE
+ * ARG0:	sysino
+ * RET0:	status
+ * RET1:	intr_state (HV_INTR_STATE_*)
+ * ERRORS:	EINVAL		Invalid sysino
+ *
+ * Returns current state of the interrupt defined by the given sysino.
+ */
+#define HV_FAST_INTR_GETSTATE		0xa3
+
+#ifndef __ASSEMBLY__
+extern unsigned long sun4v_intr_getstate(unsigned long sysino);
+#endif
+
+/* intr_setstate()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_INTR_SETSTATE
+ * ARG0:	sysino
+ * ARG1:	intr_state (HV_INTR_STATE_*)
+ * RET0:	status
+ * ERRORS:	EINVAL		Invalid sysino or intr_state value
+ *
+ * Sets the current state of the interrupt described by the given sysino
+ * value.
+ *
+ * Note: Setting the state to HV_INTR_STATE_IDLE clears any pending
+ *       interrupt for sysino.
+ */
+#define HV_FAST_INTR_SETSTATE		0xa4
+
+#ifndef __ASSEMBLY__
+extern unsigned long sun4v_intr_setstate(unsigned long sysino, unsigned long intr_state);
+#endif
+
+/* intr_gettarget()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_INTR_GETTARGET
+ * ARG0:	sysino
+ * RET0:	status
+ * RET1:	cpuid
+ * ERRORS:	EINVAL		Invalid sysino
+ *
+ * Returns CPU that is the current target of the interrupt defined by
+ * the given sysino.  The CPU value returned is undefined if the target
+ * has not been set via intr_settarget().
+ */
+#define HV_FAST_INTR_GETTARGET		0xa5
+
+#ifndef __ASSEMBLY__
+extern unsigned long sun4v_intr_gettarget(unsigned long sysino);
+#endif
+
+/* intr_settarget()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_INTR_SETTARGET
+ * ARG0:	sysino
+ * ARG1:	cpuid
+ * RET0:	status
+ * ERRORS:	EINVAL		Invalid sysino
+ *		ENOCPU		Invalid cpuid
+ *
+ * Set the target CPU for the interrupt defined by the given sysino.
+ */
+#define HV_FAST_INTR_SETTARGET		0xa6
+
+#ifndef __ASSEMBLY__
+extern unsigned long sun4v_intr_settarget(unsigned long sysino, unsigned long cpuid);
+#endif
+
+/* PCI IO services.
+ *
+ * See the terminology descriptions in the device interrupt services
+ * section above as those apply here too.  Here are terminology
+ * definitions specific to these PCI IO services:
+ *
+ *	tsbnum		TSB number.  Indentifies which io-tsb is used.
+ *			For this version of the specification, tsbnum
+ *			must be zero.
+ *
+ *	tsbindex	TSB index.  Identifies which entry in the TSB
+ *			is used.  The first entry is zero.
+ *
+ *	tsbid		A 64-bit aligned data structure which contains
+ *			a tsbnum and a tsbindex.  Bits 63:32 contain the
+ *			tsbnum and bits 31:00 contain the tsbindex.
+ *
+ *			Use the HV_PCI_TSBID() macro to construct such
+ * 			values.
+ *
+ *	io_attributes	IO attributes for IOMMU mappings.  One of more
+ *			of the attritbute bits are stores in a 64-bit
+ *			value.  The values are defined below.
+ *
+ *	r_addr		64-bit real address
+ *
+ *	pci_device	PCI device address.  A PCI device address identifies
+ *			a specific device on a specific PCI bus segment.
+ *			A PCI device address ia a 32-bit unsigned integer
+ *			with the following format:
+ *
+ *				00000000.bbbbbbbb.dddddfff.00000000
+ *
+ *			Use the HV_PCI_DEVICE_BUILD() macro to construct
+ *			such values.
+ *
+ *	pci_config_offset
+ *			PCI configureation space offset.  For conventional
+ *			PCI a value between 0 and 255.  For extended
+ *			configuration space, a value between 0 and 4095.
+ *
+ *			Note: For PCI configuration space accesses, the offset
+ *			      must be aligned to the access size.
+ *
+ *	error_flag	A return value which specifies if the action succeeded
+ *			or failed.  0 means no error, non-0 means some error
+ *			occurred while performing the service.
+ *
+ *	io_sync_direction
+ *			Direction definition for pci_dma_sync(), defined
+ *			below in HV_PCI_SYNC_*.
+ *
+ *	io_page_list	A list of io_page_addresses, an io_page_address is
+ *			a real address.
+ *
+ *	io_page_list_p	A pointer to an io_page_list.
+ *
+ *	"size based byte swap" - Some functions do size based byte swapping
+ *				 which allows sw to access pointers and
+ *				 counters in native form when the processor
+ *				 operates in a different endianness than the
+ *				 IO bus.  Size-based byte swapping converts a
+ *				 multi-byte field between big-endian and
+ *				 little-endian format.
+ */
+
+#define HV_PCI_MAP_ATTR_READ		0x01
+#define HV_PCI_MAP_ATTR_WRITE		0x02
+
+#define HV_PCI_DEVICE_BUILD(b,d,f)	\
+	((((b) & 0xff) << 16) | \
+	 (((d) & 0x1f) << 11) | \
+	 (((f) & 0x07) <<  8))
+
+#define HV_PCI_TSBID(__tsb_num, __tsb_index) \
+	((((u64)(__tsb_num)) << 32UL) | ((u64)(__tsb_index)))
+
+#define HV_PCI_SYNC_FOR_DEVICE		0x01
+#define HV_PCI_SYNC_FOR_CPU		0x02
+
+/* pci_iommu_map()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_IOMMU_MAP
+ * ARG0:	devhandle
+ * ARG1:	tsbid
+ * ARG2:	#ttes
+ * ARG3:	io_attributes
+ * ARG4:	io_page_list_p
+ * RET0:	status
+ * RET1:	#ttes mapped
+ * ERRORS:	EINVAL		Invalid devhandle/tsbnum/tsbindex/io_attributes
+ *		EBADALIGN	Improperly aligned real address
+ *		ENORADDR	Invalid real address
+ *
+ * Create IOMMU mappings in the sun4v device defined by the given
+ * devhandle.  The mappings are created in the TSB defined by the
+ * tsbnum component of the given tsbid.  The first mapping is created
+ * in the TSB i ndex defined by the tsbindex component of the given tsbid.
+ * The call creates up to #ttes mappings, the first one at tsbnum, tsbindex,
+ * the second at tsbnum, tsbindex + 1, etc.
+ *
+ * All mappings are created with the attributes defined by the io_attributes
+ * argument.  The page mapping addresses are described in the io_page_list
+ * defined by the given io_page_list_p, which is a pointer to the io_page_list.
+ * The first entry in the io_page_list is the address for the first iotte, the
+ * 2nd for the 2nd iotte, and so on.
+ *
+ * Each io_page_address in the io_page_list must be appropriately aligned.
+ * #ttes must be greater than zero.  For this version of the spec, the tsbnum
+ * component of the given tsbid must be zero.
+ *
+ * Returns the actual number of mappings creates, which may be less than
+ * or equal to the argument #ttes.  If the function returns a value which
+ * is less than the #ttes, the caller may continus to call the function with
+ * an updated tsbid, #ttes, io_page_list_p arguments until all pages are
+ * mapped.
+ *
+ * Note: This function does not imply an iotte cache flush.  The guest must
+ *       demap an entry before re-mapping it.
+ */
+#define HV_FAST_PCI_IOMMU_MAP		0xb0
+
+/* pci_iommu_demap()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_IOMMU_DEMAP
+ * ARG0:	devhandle
+ * ARG1:	tsbid
+ * ARG2:	#ttes
+ * RET0:	status
+ * RET1:	#ttes demapped
+ * ERRORS:	EINVAL		Invalid devhandle/tsbnum/tsbindex
+ *
+ * Demap and flush IOMMU mappings in the device defined by the given
+ * devhandle.  Demaps up to #ttes entries in the TSB defined by the tsbnum
+ * component of the given tsbid, starting at the TSB index defined by the
+ * tsbindex component of the given tsbid.
+ *
+ * For this version of the spec, the tsbnum of the given tsbid must be zero.
+ * #ttes must be greater than zero.
+ *
+ * Returns the actual number of ttes demapped, which may be less than or equal
+ * to the argument #ttes.  If #ttes demapped is less than #ttes, the caller
+ * may continue to call this function with updated tsbid and #ttes arguments
+ * until all pages are demapped.
+ *
+ * Note: Entries do not have to be mapped to be demapped.  A demap of an
+ *       unmapped page will flush the entry from the tte cache.
+ */
+#define HV_FAST_PCI_IOMMU_DEMAP		0xb1
+
+/* pci_iommu_getmap()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_IOMMU_GETMAP
+ * ARG0:	devhandle
+ * ARG1:	tsbid
+ * RET0:	status
+ * RET1:	io_attributes
+ * RET2:	real address
+ * ERRORS:	EINVAL		Invalid devhandle/tsbnum/tsbindex
+ *		ENOMAP		Mapping is not valid, no translation exists
+ *
+ * Read and return the mapping in the device described by the given devhandle
+ * and tsbid.  If successful, the io_attributes shall be returned in RET1
+ * and the page address of the mapping shall be returned in RET2.
+ *
+ * For this version of the spec, the tsbnum component of the given tsbid
+ * must be zero.
+ */
+#define HV_FAST_PCI_IOMMU_GETMAP	0xb2
+
+/* pci_iommu_getbypass()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_IOMMU_GETBYPASS
+ * ARG0:	devhandle
+ * ARG1:	real address
+ * ARG2:	io_attributes
+ * RET0:	status
+ * RET1:	io_addr
+ * ERRORS:	EINVAL		Invalid devhandle/io_attributes
+ *		ENORADDR	Invalid real address
+ *		ENOTSUPPORTED	Function not supported in this implementation.
+ *
+ * Create a "special" mapping in the device described by the given devhandle,
+ * for the given real address and attributes.  Return the IO address in RET1
+ * if successful.
+ */
+#define HV_FAST_PCI_IOMMU_GETBYPASS	0xb3
+
+/* pci_config_get()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_CONFIG_GET
+ * ARG0:	devhandle
+ * ARG1:	pci_device
+ * ARG2:	pci_config_offset
+ * ARG3:	size
+ * RET0:	status
+ * RET1:	error_flag
+ * RET2:	data
+ * ERRORS:	EINVAL		Invalid devhandle/pci_device/offset/size
+ *		EBADALIGN	pci_config_offset not size aligned
+ *		ENOACCESS	Access to this offset is not permitted
+ *
+ * Read PCI configuration space for the adapter described by the given
+ * devhandle.  Read size (1, 2, or 4) bytes of data from the given
+ * pci_device, at pci_config_offset from the beginning of the device's
+ * configuration space.  If there was no error, RET1 is set to zero and
+ * RET2 is set to the data read.  Insignificant bits in RET2 are not
+ * guarenteed to have any specific value and therefore must be ignored.
+ *
+ * The data returned in RET2 is size based byte swapped.
+ *
+ * If an error occurs during the read, set RET1 to a non-zero value.  The
+ * given pci_config_offset must be 'size' aligned.
+ */
+#define HV_FAST_PCI_CONFIG_GET		0xb4
+
+/* pci_config_put()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_CONFIG_PUT
+ * ARG0:	devhandle
+ * ARG1:	pci_device
+ * ARG2:	pci_config_offset
+ * ARG3:	size
+ * ARG4:	data
+ * RET0:	status
+ * RET1:	error_flag
+ * ERRORS:	EINVAL		Invalid devhandle/pci_device/offset/size
+ *		EBADALIGN	pci_config_offset not size aligned
+ *		ENOACCESS	Access to this offset is not permitted
+ *
+ * Write PCI configuration space for the adapter described by the given
+ * devhandle.  Write size (1, 2, or 4) bytes of data in a single operation,
+ * at pci_config_offset from the beginning of the device's configuration
+ * space.  The data argument contains the data to be written to configuration
+ * space.  Prior to writing, the data is size based byte swapped.
+ *
+ * If an error occurs during the write access, do not generate an error
+ * report, do set RET1 to a non-zero value.  Otherwise RET1 is zero.
+ * The given pci_config_offset must be 'size' aligned.
+ *
+ * This function is permitted to read from offset zero in the configuration
+ * space described by the given pci_device if necessary to ensure that the
+ * write access to config space completes.
+ */
+#define HV_FAST_PCI_CONFIG_PUT		0xb5
+
+/* pci_peek()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_PEEK
+ * ARG0:	devhandle
+ * ARG1:	real address
+ * ARG2:	size
+ * RET0:	status
+ * RET1:	error_flag
+ * RET2:	data
+ * ERRORS:	EINVAL		Invalid devhandle or size
+ *		EBADALIGN	Improperly aligned real address
+ *		ENORADDR	Bad real address
+ *		ENOACCESS	Guest access prohibited
+ *
+ * Attempt to read the IO address given by the given devhandle, real address,
+ * and size.  Size must be 1, 2, 4, or 8.  The read is performed as a single
+ * access operation using the given size.  If an error occurs when reading
+ * from the given location, do not generate an error report, but return a
+ * non-zero value in RET1.  If the read was successful, return zero in RET1
+ * and return the actual data read in RET2.  The data returned is size based
+ * byte swapped.
+ *
+ * Non-significant bits in RET2 are not guarenteed to have any specific value
+ * and therefore must be ignored.  If RET1 is returned as non-zero, the data 
+ * value is not guarenteed to have any specific value and should be ignored.
+ *
+ * The caller must have permission to read from the given devhandle, real
+ * address, which must be an IO address.  The argument real address must be a
+ * size aligned address.
+ *
+ * The hypervisor implementation of this function must block access to any
+ * IO address that the guest does not have explicit permission to access.
+ */
+#define HV_FAST_PCI_PEEK		0xb6
+
+/* pci_poke()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_POKE
+ * ARG0:	devhandle
+ * ARG1:	real address
+ * ARG2:	size
+ * ARG3:	data
+ * ARG4:	pci_device
+ * RET0:	status
+ * RET1:	error_flag
+ * ERRORS:	EINVAL		Invalid devhandle, size, or pci_device
+ *		EBADALIGN	Improperly aligned real address
+ *		ENORADDR	Bad real address
+ *		ENOACCESS	Guest access prohibited
+ *		ENOTSUPPORTED	Function is not supported by implementation
+ *
+ * Attempt to write data to the IO address given by the given devhandle,
+ * real address, and size.  Size must be 1, 2, 4, or 8.  The write is
+ * performed as a single access operation using the given size. Prior to
+ * writing the data is size based swapped.
+ *
+ * If an error occurs when writing to the given location, do not generate an
+ * error report, but return a non-zero value in RET1.  If the write was
+ * successful, return zero in RET1.
+ *
+ * pci_device describes the configuration address of the device being
+ * written to.  The implementation may safely read from offset 0 with
+ * the configuration space of the device described by devhandle and
+ * pci_device in order to guarantee that the write portion of the operation
+ * completes
+ *
+ * Any error that occurs due to the read shall be reported using the normal
+ * error reporting mechanisms .. the read error is not suppressed.
+ *
+ * The caller must have permission to write to the given devhandle, real
+ * address, which must be an IO address.  The argument real address must be a
+ * size aligned address.  The caller must have permission to read from
+ * the given devhandle, pci_device cofiguration space offset 0.
+ *
+ * The hypervisor implementation of this function must block access to any
+ * IO address that the guest does not have explicit permission to access.
+ */
+#define HV_FAST_PCI_POKE		0xb7
+
+/* pci_dma_sync()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_DMA_SYNC
+ * ARG0:	devhandle
+ * ARG1:	real address
+ * ARG2:	size
+ * ARG3:	io_sync_direction
+ * RET0:	status
+ * RET1:	#synced
+ * ERRORS:	EINVAL		Invalid devhandle or io_sync_direction
+ *		ENORADDR	Bad real address
+ *
+ * Synchronize a memory region described by the given real address and size,
+ * for the device defined by the given devhandle using the direction(s)
+ * defined by the given io_sync_direction.  The argument size is the size of
+ * the memory region in bytes.
+ *
+ * Return the actual number of bytes synchronized in the return value #synced,
+ * which may be less than or equal to the argument size.  If the return
+ * value #synced is less than size, the caller must continue to call this
+ * function with updated real address and size arguments until the entire
+ * memory region is synchronized.
+ */
+#define HV_FAST_PCI_DMA_SYNC		0xb8
+
+/* PCI MSI services.  */
+
+#define HV_MSITYPE_MSI32		0x00
+#define HV_MSITYPE_MSI64		0x01
+
+#define HV_MSIQSTATE_IDLE		0x00
+#define HV_MSIQSTATE_ERROR		0x01
+
+#define HV_MSIQ_INVALID			0x00
+#define HV_MSIQ_VALID			0x01
+
+#define HV_MSISTATE_IDLE		0x00
+#define HV_MSISTATE_DELIVERED		0x01
+
+#define HV_MSIVALID_INVALID		0x00
+#define HV_MSIVALID_VALID		0x01
+
+#define HV_PCIE_MSGTYPE_PME_MSG		0x18
+#define HV_PCIE_MSGTYPE_PME_ACK_MSG	0x1b
+#define HV_PCIE_MSGTYPE_CORR_MSG	0x30
+#define HV_PCIE_MSGTYPE_NONFATAL_MSG	0x31
+#define HV_PCIE_MSGTYPE_FATAL_MSG	0x33
+
+#define HV_MSG_INVALID			0x00
+#define HV_MSG_VALID			0x01
+
+/* pci_msiq_conf()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_MSIQ_CONF
+ * ARG0:	devhandle
+ * ARG1:	msiqid
+ * ARG2:	real address
+ * ARG3:	number of entries
+ * RET0:	status
+ * ERRORS:	EINVAL		Invalid devhandle, msiqid or nentries
+ *		EBADALIGN	Improperly aligned real address
+ *		ENORADDR	Bad real address
+ *
+ * Configure the MSI queue given by the devhandle and msiqid arguments,
+ * and to be placed at the given real address and be of the given
+ * number of entries.  The real address must be aligned exactly to match
+ * the queue size.  Each queue entry is 64-bytes long, so f.e. a 32 entry
+ * queue must be aligned on a 2048 byte real address boundary.  The MSI-EQ
+ * Head and Tail are initialized so that the MSI-EQ is 'empty'.
+ *
+ * Implementation Note: Certain implementations have fixed sized queues.  In
+ *                      that case, number of entries must contain the correct
+ *                      value.
+ */
+#define HV_FAST_PCI_MSIQ_CONF		0xc0
+
+/* pci_msiq_info()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_MSIQ_INFO
+ * ARG0:	devhandle
+ * ARG1:	msiqid
+ * RET0:	status
+ * RET1:	real address
+ * RET2:	number of entries
+ * ERRORS:	EINVAL		Invalid devhandle or msiqid
+ *
+ * Return the configuration information for the MSI queue described
+ * by the given devhandle and msiqid.  The base address of the queue
+ * is returned in ARG1 and the number of entries is returned in ARG2.
+ * If the queue is unconfigured, the real address is undefined and the
+ * number of entries will be returned as zero.
+ */
+#define HV_FAST_PCI_MSIQ_INFO		0xc1
+
+/* pci_msiq_getvalid()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_MSIQ_GETVALID
+ * ARG0:	devhandle
+ * ARG1:	msiqid
+ * RET0:	status
+ * RET1:	msiqvalid	(HV_MSIQ_VALID or HV_MSIQ_INVALID)
+ * ERRORS:	EINVAL		Invalid devhandle or msiqid
+ *
+ * Get the valid state of the MSI-EQ described by the given devhandle and
+ * msiqid.
+ */
+#define HV_FAST_PCI_MSIQ_GETVALID	0xc2
+
+/* pci_msiq_setvalid()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_MSIQ_SETVALID
+ * ARG0:	devhandle
+ * ARG1:	msiqid
+ * ARG2:	msiqvalid	(HV_MSIQ_VALID or HV_MSIQ_INVALID)
+ * RET0:	status
+ * ERRORS:	EINVAL		Invalid devhandle or msiqid or msiqvalid
+ *				value or MSI EQ is uninitialized
+ *
+ * Set the valid state of the MSI-EQ described by the given devhandle and
+ * msiqid to the given msiqvalid.
+ */
+#define HV_FAST_PCI_MSIQ_SETVALID	0xc3
+
+/* pci_msiq_getstate()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_MSIQ_GETSTATE
+ * ARG0:	devhandle
+ * ARG1:	msiqid
+ * RET0:	status
+ * RET1:	msiqstate	(HV_MSIQSTATE_IDLE or HV_MSIQSTATE_ERROR)
+ * ERRORS:	EINVAL		Invalid devhandle or msiqid
+ *
+ * Get the state of the MSI-EQ described by the given devhandle and
+ * msiqid.
+ */
+#define HV_FAST_PCI_MSIQ_GETSTATE	0xc4
+
+/* pci_msiq_getvalid()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_MSIQ_GETVALID
+ * ARG0:	devhandle
+ * ARG1:	msiqid
+ * ARG2:	msiqstate	(HV_MSIQSTATE_IDLE or HV_MSIQSTATE_ERROR)
+ * RET0:	status
+ * ERRORS:	EINVAL		Invalid devhandle or msiqid or msiqstate
+ *				value or MSI EQ is uninitialized
+ *
+ * Set the state of the MSI-EQ described by the given devhandle and
+ * msiqid to the given msiqvalid.
+ */
+#define HV_FAST_PCI_MSIQ_SETSTATE	0xc5
+
+/* pci_msiq_gethead()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_MSIQ_GETHEAD
+ * ARG0:	devhandle
+ * ARG1:	msiqid
+ * RET0:	status
+ * RET1:	msiqhead
+ * ERRORS:	EINVAL		Invalid devhandle or msiqid
+ *
+ * Get the current MSI EQ queue head for the MSI-EQ described by the
+ * given devhandle and msiqid.
+ */
+#define HV_FAST_PCI_MSIQ_GETHEAD	0xc6
+
+/* pci_msiq_sethead()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_MSIQ_SETHEAD
+ * ARG0:	devhandle
+ * ARG1:	msiqid
+ * ARG2:	msiqhead
+ * RET0:	status
+ * ERRORS:	EINVAL		Invalid devhandle or msiqid or msiqhead,
+ *				or MSI EQ is uninitialized
+ *
+ * Set the current MSI EQ queue head for the MSI-EQ described by the
+ * given devhandle and msiqid.
+ */
+#define HV_FAST_PCI_MSIQ_SETHEAD	0xc7
+
+/* pci_msiq_gettail()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_MSIQ_GETTAIL
+ * ARG0:	devhandle
+ * ARG1:	msiqid
+ * RET0:	status
+ * RET1:	msiqtail
+ * ERRORS:	EINVAL		Invalid devhandle or msiqid
+ *
+ * Get the current MSI EQ queue tail for the MSI-EQ described by the
+ * given devhandle and msiqid.
+ */
+#define HV_FAST_PCI_MSIQ_GETTAIL	0xc8
+
+/* pci_msi_getvalid()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_MSI_GETVALID
+ * ARG0:	devhandle
+ * ARG1:	msinum
+ * RET0:	status
+ * RET1:	msivalidstate
+ * ERRORS:	EINVAL		Invalid devhandle or msinum
+ *
+ * Get the current valid/enabled state for the MSI defined by the
+ * given devhandle and msinum.
+ */
+#define HV_FAST_PCI_MSI_GETVALID	0xc9
+
+/* pci_msi_setvalid()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_MSI_SETVALID
+ * ARG0:	devhandle
+ * ARG1:	msinum
+ * ARG2:	msivalidstate
+ * RET0:	status
+ * ERRORS:	EINVAL		Invalid devhandle or msinum or msivalidstate
+ *
+ * Set the current valid/enabled state for the MSI defined by the
+ * given devhandle and msinum.
+ */
+#define HV_FAST_PCI_MSI_SETVALID	0xca
+
+/* pci_msi_getmsiq()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_MSI_GETMSIQ
+ * ARG0:	devhandle
+ * ARG1:	msinum
+ * RET0:	status
+ * RET1:	msiqid
+ * ERRORS:	EINVAL		Invalid devhandle or msinum or MSI is unbound
+ *
+ * Get the MSI EQ that the MSI defined by the given devhandle and
+ * msinum is bound to.
+ */
+#define HV_FAST_PCI_MSI_GETMSIQ		0xcb
+
+/* pci_msi_setmsiq()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_MSI_SETMSIQ
+ * ARG0:	devhandle
+ * ARG1:	msinum
+ * ARG2:	msitype
+ * ARG3:	msiqid
+ * RET0:	status
+ * ERRORS:	EINVAL		Invalid devhandle or msinum or msiqid
+ *
+ * Set the MSI EQ that the MSI defined by the given devhandle and
+ * msinum is bound to.
+ */
+#define HV_FAST_PCI_MSI_SETMSIQ		0xcc
+
+/* pci_msi_getstate()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_MSI_GETSTATE
+ * ARG0:	devhandle
+ * ARG1:	msinum
+ * RET0:	status
+ * RET1:	msistate
+ * ERRORS:	EINVAL		Invalid devhandle or msinum
+ *
+ * Get the state of the MSI defined by the given devhandle and msinum.
+ * If not initialized, return HV_MSISTATE_IDLE.
+ */
+#define HV_FAST_PCI_MSI_GETSTATE	0xcd
+
+/* pci_msi_setstate()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_MSI_SETSTATE
+ * ARG0:	devhandle
+ * ARG1:	msinum
+ * ARG2:	msistate
+ * RET0:	status
+ * ERRORS:	EINVAL		Invalid devhandle or msinum or msistate
+ *
+ * Set the state of the MSI defined by the given devhandle and msinum.
+ */
+#define HV_FAST_PCI_MSI_SETSTATE	0xce
+
+/* pci_msg_getmsiq()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_MSG_GETMSIQ
+ * ARG0:	devhandle
+ * ARG1:	msgtype
+ * RET0:	status
+ * RET1:	msiqid
+ * ERRORS:	EINVAL		Invalid devhandle or msgtype
+ *
+ * Get the MSI EQ of the MSG defined by the given devhandle and msgtype.
+ */
+#define HV_FAST_PCI_MSG_GETMSIQ		0xd0
+
+/* pci_msg_setmsiq()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_MSG_SETMSIQ
+ * ARG0:	devhandle
+ * ARG1:	msgtype
+ * ARG2:	msiqid
+ * RET0:	status
+ * ERRORS:	EINVAL		Invalid devhandle, msgtype, or msiqid
+ *
+ * Set the MSI EQ of the MSG defined by the given devhandle and msgtype.
+ */
+#define HV_FAST_PCI_MSG_SETMSIQ		0xd1
+
+/* pci_msg_getvalid()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_MSG_GETVALID
+ * ARG0:	devhandle
+ * ARG1:	msgtype
+ * RET0:	status
+ * RET1:	msgvalidstate
+ * ERRORS:	EINVAL		Invalid devhandle or msgtype
+ *
+ * Get the valid/enabled state of the MSG defined by the given
+ * devhandle and msgtype.
+ */
+#define HV_FAST_PCI_MSG_GETVALID	0xd2
+
+/* pci_msg_setvalid()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_PCI_MSG_SETVALID
+ * ARG0:	devhandle
+ * ARG1:	msgtype
+ * ARG2:	msgvalidstate
+ * RET0:	status
+ * ERRORS:	EINVAL		Invalid devhandle or msgtype or msgvalidstate
+ *
+ * Set the valid/enabled state of the MSG defined by the given
+ * devhandle and msgtype.
+ */
+#define HV_FAST_PCI_MSG_SETVALID	0xd3
+
+/* Performance counter services.  */
+
+#define HV_PERF_JBUS_PERF_CTRL_REG	0x00
+#define HV_PERF_JBUS_PERF_CNT_REG	0x01
+#define HV_PERF_DRAM_PERF_CTRL_REG_0	0x02
+#define HV_PERF_DRAM_PERF_CNT_REG_0	0x03
+#define HV_PERF_DRAM_PERF_CTRL_REG_1	0x04
+#define HV_PERF_DRAM_PERF_CNT_REG_1	0x05
+#define HV_PERF_DRAM_PERF_CTRL_REG_2	0x06
+#define HV_PERF_DRAM_PERF_CNT_REG_2	0x07
+#define HV_PERF_DRAM_PERF_CTRL_REG_3	0x08
+#define HV_PERF_DRAM_PERF_CNT_REG_3	0x09
+
+/* get_perfreg()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_GET_PERFREG
+ * ARG0:	performance reg number
+ * RET0:	status
+ * RET1:	performance reg value
+ * ERRORS:	EINVAL		Invalid performance register number
+ *		ENOACCESS	No access allowed to performance counters
+ *
+ * Read the value of the given DRAM/JBUS performance counter/control register.
+ */
+#define HV_FAST_GET_PERFREG		0x100
+
+/* set_perfreg()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_SET_PERFREG
+ * ARG0:	performance reg number
+ * ARG1:	performance reg value
+ * RET0:	status
+ * ERRORS:	EINVAL		Invalid performance register number
+ *		ENOACCESS	No access allowed to performance counters
+ *
+ * Write the given performance reg value to the given DRAM/JBUS
+ * performance counter/control register.
+ */
+#define HV_FAST_SET_PERFREG		0x101
+
+/* MMU statistics services.
+ *
+ * The hypervisor maintains MMU statistics and privileged code provides
+ * a buffer where these statistics can be collected.  It is continually
+ * updated once configured.  The layout is as follows:
+ */
+#ifndef __ASSEMBLY__
+struct hv_mmu_statistics {
+	unsigned long immu_tsb_hits_ctx0_8k_tte;
+	unsigned long immu_tsb_ticks_ctx0_8k_tte;
+	unsigned long immu_tsb_hits_ctx0_64k_tte;
+	unsigned long immu_tsb_ticks_ctx0_64k_tte;
+	unsigned long __reserved1[2];
+	unsigned long immu_tsb_hits_ctx0_4mb_tte;
+	unsigned long immu_tsb_ticks_ctx0_4mb_tte;
+	unsigned long __reserved2[2];
+	unsigned long immu_tsb_hits_ctx0_256mb_tte;
+	unsigned long immu_tsb_ticks_ctx0_256mb_tte;
+	unsigned long __reserved3[4];
+	unsigned long immu_tsb_hits_ctxnon0_8k_tte;
+	unsigned long immu_tsb_ticks_ctxnon0_8k_tte;
+	unsigned long immu_tsb_hits_ctxnon0_64k_tte;
+	unsigned long immu_tsb_ticks_ctxnon0_64k_tte;
+	unsigned long __reserved4[2];
+	unsigned long immu_tsb_hits_ctxnon0_4mb_tte;
+	unsigned long immu_tsb_ticks_ctxnon0_4mb_tte;
+	unsigned long __reserved5[2];
+	unsigned long immu_tsb_hits_ctxnon0_256mb_tte;
+	unsigned long immu_tsb_ticks_ctxnon0_256mb_tte;
+	unsigned long __reserved6[4];
+	unsigned long dmmu_tsb_hits_ctx0_8k_tte;
+	unsigned long dmmu_tsb_ticks_ctx0_8k_tte;
+	unsigned long dmmu_tsb_hits_ctx0_64k_tte;
+	unsigned long dmmu_tsb_ticks_ctx0_64k_tte;
+	unsigned long __reserved7[2];
+	unsigned long dmmu_tsb_hits_ctx0_4mb_tte;
+	unsigned long dmmu_tsb_ticks_ctx0_4mb_tte;
+	unsigned long __reserved8[2];
+	unsigned long dmmu_tsb_hits_ctx0_256mb_tte;
+	unsigned long dmmu_tsb_ticks_ctx0_256mb_tte;
+	unsigned long __reserved9[4];
+	unsigned long dmmu_tsb_hits_ctxnon0_8k_tte;
+	unsigned long dmmu_tsb_ticks_ctxnon0_8k_tte;
+	unsigned long dmmu_tsb_hits_ctxnon0_64k_tte;
+	unsigned long dmmu_tsb_ticks_ctxnon0_64k_tte;
+	unsigned long __reserved10[2];
+	unsigned long dmmu_tsb_hits_ctxnon0_4mb_tte;
+	unsigned long dmmu_tsb_ticks_ctxnon0_4mb_tte;
+	unsigned long __reserved11[2];
+	unsigned long dmmu_tsb_hits_ctxnon0_256mb_tte;
+	unsigned long dmmu_tsb_ticks_ctxnon0_256mb_tte;
+	unsigned long __reserved12[4];
+};
+#endif
+
+/* mmustat_conf()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MMUSTAT_CONF
+ * ARG0:	real address
+ * RET0:	status
+ * RET1:	real address
+ * ERRORS:	ENORADDR	Invalid real address
+ *		EBADALIGN	Real address not aligned on 64-byte boundary
+ *		EBADTRAP	API not supported on this processor
+ *
+ * Enable MMU statistic gathering using the buffer at the given real
+ * address on the current virtual CPU.  The new buffer real address
+ * is given in ARG1, and the previously specified buffer real address
+ * is returned in RET1, or is returned as zero for the first invocation.
+ *
+ * If the passed in real address argument is zero, this will disable
+ * MMU statistic collection on the current virtual CPU.  If an error is
+ * returned then no statistics are collected.
+ *
+ * The buffer contents should be initialized to all zeros before being
+ * given to the hypervisor or else the statistics will be meaningless.
+ */
+#define HV_FAST_MMUSTAT_CONF		0x102
+
+/* mmustat_info()
+ * TRAP:	HV_FAST_TRAP
+ * FUNCTION:	HV_FAST_MMUSTAT_INFO
+ * RET0:	status
+ * RET1:	real address
+ * ERRORS:	EBADTRAP	API not supported on this processor
+ *
+ * Return the current state and real address of the currently configured
+ * MMU statistics buffer on the current virtual CPU.
+ */
+#define HV_FAST_MMUSTAT_INFO		0x103
+
+/* Function numbers for HV_CORE_TRAP.  */
+#define HV_CORE_VER			0x00
+#define HV_CORE_PUTCHAR			0x01
+#define HV_CORE_EXIT			0x02
+
+#endif /* !(_SPARC64_HYPERVISOR_H) */
diff -urN oldtree/include/asm-sparc64/idprom.h newtree/include/asm-sparc64/idprom.h
--- oldtree/include/asm-sparc64/idprom.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sparc64/idprom.h	2006-02-21 15:58:20.764989800 +0000
@@ -9,15 +9,7 @@
 
 #include <linux/types.h>
 
-/* Offset into the EEPROM where the id PROM is located on the 4c */
-#define IDPROM_OFFSET  0x7d8
-
-/* On sun4m; physical. */
-/* MicroSPARC(-II) does not decode 31rd bit, but it works. */
-#define IDPROM_OFFSET_M  0xfd8
-
-struct idprom
-{
+struct idprom {
 	u8		id_format;	/* Format identifier (always 0x01) */
 	u8		id_machtype;	/* Machine type */
 	u8		id_ethaddr[6];	/* Hardware ethernet address */
@@ -30,6 +22,4 @@
 extern struct idprom *idprom;
 extern void idprom_init(void);
 
-#define IDPROM_SIZE  (sizeof(struct idprom))
-
 #endif /* !(_SPARC_IDPROM_H) */
diff -urN oldtree/include/asm-sparc64/intr_queue.h newtree/include/asm-sparc64/intr_queue.h
--- oldtree/include/asm-sparc64/intr_queue.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/include/asm-sparc64/intr_queue.h	2006-02-21 15:58:20.764989800 +0000
@@ -0,0 +1,15 @@
+#ifndef _SPARC64_INTR_QUEUE_H
+#define _SPARC64_INTR_QUEUE_H
+
+/* Sun4v interrupt queue registers, accessed via ASI_QUEUE.  */
+
+#define INTRQ_CPU_MONDO_HEAD	  0x3c0 /* CPU mondo head	          */
+#define INTRQ_CPU_MONDO_TAIL	  0x3c8 /* CPU mondo tail	          */
+#define INTRQ_DEVICE_MONDO_HEAD	  0x3d0 /* Device mondo head	          */
+#define INTRQ_DEVICE_MONDO_TAIL	  0x3d8 /* Device mondo tail	          */
+#define INTRQ_RESUM_MONDO_HEAD	  0x3e0 /* Resumable error mondo head     */
+#define INTRQ_RESUM_MONDO_TAIL	  0x3e8 /* Resumable error mondo tail     */
+#define INTRQ_NONRESUM_MONDO_HEAD 0x3f0 /* Non-resumable error mondo head */
+#define INTRQ_NONRESUM_MONDO_TAIL 0x3f8 /* Non-resumable error mondo head */
+
+#endif /* !(_SPARC64_INTR_QUEUE_H) */
diff -urN oldtree/include/asm-sparc64/irq.h newtree/include/asm-sparc64/irq.h
--- oldtree/include/asm-sparc64/irq.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sparc64/irq.h	2006-02-21 15:58:20.779987520 +0000
@@ -72,8 +72,11 @@
 #define IMAP_VALID		0x80000000	/* IRQ Enabled		*/
 #define IMAP_TID_UPA		0x7c000000	/* UPA TargetID		*/
 #define IMAP_TID_JBUS		0x7c000000	/* JBUS TargetID	*/
+#define IMAP_TID_SHIFT		26
 #define IMAP_AID_SAFARI		0x7c000000	/* Safari AgentID	*/
+#define IMAP_AID_SHIFT		26
 #define IMAP_NID_SAFARI		0x03e00000	/* Safari NodeID	*/
+#define IMAP_NID_SHIFT		21
 #define IMAP_IGN		0x000007c0	/* IRQ Group Number	*/
 #define IMAP_INO		0x0000003f	/* IRQ Number		*/
 #define IMAP_INR		0x000007ff	/* Full interrupt number*/
@@ -111,6 +114,7 @@
 #define disable_irq_nosync disable_irq
 extern void enable_irq(unsigned int);
 extern unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap);
+extern unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, int pil, unsigned char flags);
 extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
 
 static __inline__ void set_softint(unsigned long bits)
diff -urN oldtree/include/asm-sparc64/mmu.h newtree/include/asm-sparc64/mmu.h
--- oldtree/include/asm-sparc64/mmu.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sparc64/mmu.h	2006-02-21 15:58:20.779987520 +0000
@@ -4,6 +4,7 @@
 #include <linux/config.h>
 #include <asm/page.h>
 #include <asm/const.h>
+#include <asm/hypervisor.h>
 
 /*
  * For the 8k pagesize kernel, use only 10 hw context bits to optimize some
@@ -90,8 +91,25 @@
 
 #ifndef __ASSEMBLY__
 
+#define TSB_ENTRY_ALIGNMENT	16
+
+struct tsb {
+	unsigned long tag;
+	unsigned long pte;
+} __attribute__((aligned(TSB_ENTRY_ALIGNMENT)));
+
+extern void __tsb_insert(unsigned long ent, unsigned long tag, unsigned long pte);
+extern void tsb_flush(unsigned long ent, unsigned long tag);
+
 typedef struct {
-	unsigned long	sparc64_ctx_val;
+	unsigned long		sparc64_ctx_val;
+	struct tsb		*tsb;
+	unsigned long		tsb_rss_limit;
+	unsigned long		tsb_nentries;
+	unsigned long		tsb_reg_val;
+	unsigned long		tsb_map_vaddr;
+	unsigned long		tsb_map_pte;
+	struct hv_tsb_descr	tsb_descr;
 } mm_context_t;
 
 #endif /* !__ASSEMBLY__ */
diff -urN oldtree/include/asm-sparc64/mmu_context.h newtree/include/asm-sparc64/mmu_context.h
--- oldtree/include/asm-sparc64/mmu_context.h	2006-02-19 11:41:05.734471328 +0000
+++ newtree/include/asm-sparc64/mmu_context.h	2006-02-21 15:58:20.780987368 +0000
@@ -19,67 +19,42 @@
 extern unsigned long mmu_context_bmap[];
 
 extern void get_new_mmu_context(struct mm_struct *mm);
+extern int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+extern void destroy_context(struct mm_struct *mm);
 
-/* Initialize a new mmu context.  This is invoked when a new
- * address space instance (unique or shared) is instantiated.
- * This just needs to set mm->context to an invalid context.
- */
-#define init_new_context(__tsk, __mm)	\
-	(((__mm)->context.sparc64_ctx_val = 0UL), 0)
-
-/* Destroy a dead context.  This occurs when mmput drops the
- * mm_users count to zero, the mmaps have been released, and
- * all the page tables have been flushed.  Our job is to destroy
- * any remaining processor-specific state, and in the sparc64
- * case this just means freeing up the mmu context ID held by
- * this task if valid.
- */
-#define destroy_context(__mm)					\
-do {	spin_lock(&ctx_alloc_lock);				\
-	if (CTX_VALID((__mm)->context)) {			\
-		unsigned long nr = CTX_NRBITS((__mm)->context);	\
-		mmu_context_bmap[nr>>6] &= ~(1UL << (nr & 63));	\
-	}							\
-	spin_unlock(&ctx_alloc_lock);				\
-} while(0)
-
-/* Reload the two core values used by TLB miss handler
- * processing on sparc64.  They are:
- * 1) The physical address of mm->pgd, when full page
- *    table walks are necessary, this is where the
- *    search begins.
- * 2) A "PGD cache".  For 32-bit tasks only pgd[0] is
- *    ever used since that maps the entire low 4GB
- *    completely.  To speed up TLB miss processing we
- *    make this value available to the handlers.  This
- *    decreases the amount of memory traffic incurred.
- */
-#define reload_tlbmiss_state(__tsk, __mm) \
-do { \
-	register unsigned long paddr asm("o5"); \
-	register unsigned long pgd_cache asm("o4"); \
-	paddr = __pa((__mm)->pgd); \
-	pgd_cache = 0UL; \
-	if (task_thread_info(__tsk)->flags & _TIF_32BIT) \
-		pgd_cache = get_pgd_cache((__mm)->pgd); \
-	__asm__ __volatile__("wrpr	%%g0, 0x494, %%pstate\n\t" \
-			     "mov	%3, %%g4\n\t" \
-			     "mov	%0, %%g7\n\t" \
-			     "stxa	%1, [%%g4] %2\n\t" \
-			     "membar	#Sync\n\t" \
-			     "wrpr	%%g0, 0x096, %%pstate" \
-			     : /* no outputs */ \
-			     : "r" (paddr), "r" (pgd_cache),\
-			       "i" (ASI_DMMU), "i" (TSB_REG)); \
-} while(0)
+extern void __tsb_context_switch(unsigned long pgd_pa,
+				 unsigned long tsb_reg,
+				 unsigned long tsb_vaddr,
+				 unsigned long tsb_pte,
+				 unsigned long tsb_descr_pa);
+
+static inline void tsb_context_switch(struct mm_struct *mm)
+{
+	__tsb_context_switch(__pa(mm->pgd), mm->context.tsb_reg_val,
+			     mm->context.tsb_map_vaddr,
+			     mm->context.tsb_map_pte,
+			     __pa(&mm->context.tsb_descr));
+}
+
+extern void tsb_grow(struct mm_struct *mm, unsigned long mm_rss, gfp_t gfp_flags);
+#ifdef CONFIG_SMP
+extern void smp_tsb_sync(struct mm_struct *mm);
+#else
+#define smp_tsb_sync(__mm) do { } while (0)
+#endif
 
 /* Set MMU context in the actual hardware. */
 #define load_secondary_context(__mm) \
-	__asm__ __volatile__("stxa	%0, [%1] %2\n\t" \
-			     "flush	%%g6" \
-			     : /* No outputs */ \
-			     : "r" (CTX_HWBITS((__mm)->context)), \
-			       "r" (SECONDARY_CONTEXT), "i" (ASI_DMMU))
+	__asm__ __volatile__( \
+	"\n661:	stxa		%0, [%1] %2\n" \
+	"	.section	.sun4v_1insn_patch, \"ax\"\n" \
+	"	.word		661b\n" \
+	"	stxa		%0, [%1] %3\n" \
+	"	.previous\n" \
+	"	flush		%%g6\n" \
+	: /* No outputs */ \
+	: "r" (CTX_HWBITS((__mm)->context)), \
+	  "r" (SECONDARY_CONTEXT), "i" (ASI_DMMU), "i" (ASI_MMU))
 
 extern void __flush_tlb_mm(unsigned long, unsigned long);
 
@@ -101,7 +76,7 @@
 
 	if (!ctx_valid || (old_mm != mm)) {
 		load_secondary_context(mm);
-		reload_tlbmiss_state(tsk, mm);
+		tsb_context_switch(mm);
 	}
 
 	/* Even if (mm == old_mm) we _must_ check
@@ -139,7 +114,7 @@
 
 	load_secondary_context(mm);
 	__flush_tlb_mm(CTX_HWBITS(mm->context), SECONDARY_CONTEXT);
-	reload_tlbmiss_state(current, mm);
+	tsb_context_switch(mm);
 }
 
 #endif /* !(__ASSEMBLY__) */
diff -urN oldtree/include/asm-sparc64/oplib.h newtree/include/asm-sparc64/oplib.h
--- oldtree/include/asm-sparc64/oplib.h	2006-02-19 11:41:05.735471176 +0000
+++ newtree/include/asm-sparc64/oplib.h	2006-02-21 15:58:20.780987368 +0000
@@ -39,6 +39,9 @@
 extern int prom_chosen_node;
 
 /* Helper values and strings in arch/sparc64/kernel/head.S */
+extern const char prom_peer_name[];
+extern const char prom_compatible_name[];
+extern const char prom_root_compatible[];
 extern const char prom_finddev_name[];
 extern const char prom_chosen_path[];
 extern const char prom_getprop_name[];
@@ -164,6 +167,7 @@
 	PROMDEV_ITTYA,			/* input from ttya */
 	PROMDEV_ITTYB,			/* input from ttyb */
 	PROMDEV_IRSC,			/* input from rsc */
+	PROMDEV_IVCONS,			/* input from virtual-console */
 	PROMDEV_I_UNK,
 };
 
@@ -176,6 +180,7 @@
 	PROMDEV_OTTYA,			/* to ttya */
 	PROMDEV_OTTYB,			/* to ttyb */
 	PROMDEV_ORSC,			/* to rsc */
+	PROMDEV_OVCONS,			/* to virtual-console */
 	PROMDEV_O_UNK,
 };
 
@@ -183,10 +188,18 @@
 
 /* Multiprocessor operations... */
 #ifdef CONFIG_SMP
-/* Start the CPU with the given device tree node, context table, and context
- * at the passed program counter.
+/* Start the CPU with the given device tree node at the passed program
+ * counter with the given arg passed in via register %o0.
  */
-extern void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0);
+extern void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg);
+
+/* Start the CPU with the given cpu ID at the passed program
+ * counter with the given arg passed in via register %o0.
+ */
+extern void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg);
+
+/* Stop the CPU with the given cpu ID.  */
+extern void prom_stopcpu_cpuid(int cpuid);
 
 /* Stop the current CPU. */
 extern void prom_stopself(void);
@@ -335,6 +348,7 @@
 
 /* Client interface level routines. */
 extern void prom_set_trap_table(unsigned long tba);
+extern void prom_set_trap_table_sun4v(unsigned long tba, unsigned long mmfsa);
 
 extern long p1275_cmd(const char *, long, ...);
 				   
diff -urN oldtree/include/asm-sparc64/pbm.h newtree/include/asm-sparc64/pbm.h
--- oldtree/include/asm-sparc64/pbm.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sparc64/pbm.h	2006-02-21 15:58:20.782987064 +0000
@@ -139,6 +139,9 @@
 	/* Opaque 32-bit system bus Port ID. */
 	u32				portid;
 
+	/* Opaque 32-bit handle used for hypervisor calls.  */
+	u32				devhandle;
+
 	/* Chipset version information. */
 	int				chip_type;
 #define PBM_CHIP_TYPE_SABRE		1
diff -urN oldtree/include/asm-sparc64/pci.h newtree/include/asm-sparc64/pci.h
--- oldtree/include/asm-sparc64/pci.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sparc64/pci.h	2006-02-21 15:58:20.782987064 +0000
@@ -41,10 +41,26 @@
 
 struct pci_dev;
 
+struct pci_iommu_ops {
+	void *(*alloc_consistent)(struct pci_dev *, size_t, dma_addr_t *);
+	void (*free_consistent)(struct pci_dev *, size_t, void *, dma_addr_t);
+	dma_addr_t (*map_single)(struct pci_dev *, void *, size_t, int);
+	void (*unmap_single)(struct pci_dev *, dma_addr_t, size_t, int);
+	int (*map_sg)(struct pci_dev *, struct scatterlist *, int, int);
+	void (*unmap_sg)(struct pci_dev *, struct scatterlist *, int, int);
+	void (*dma_sync_single_for_cpu)(struct pci_dev *, dma_addr_t, size_t, int);
+	void (*dma_sync_sg_for_cpu)(struct pci_dev *, struct scatterlist *, int, int);
+};
+
+extern struct pci_iommu_ops *pci_iommu_ops;
+
 /* Allocate and map kernel buffer using consistent mode DMA for a device.
  * hwdev should be valid struct pci_dev pointer for PCI devices.
  */
-extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle);
+static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
+{
+	return pci_iommu_ops->alloc_consistent(hwdev, size, dma_handle);
+}
 
 /* Free and unmap a consistent DMA buffer.
  * cpu_addr is what was returned from pci_alloc_consistent,
@@ -54,7 +70,10 @@
  * References to the memory and mappings associated with cpu_addr/dma_addr
  * past this call are illegal.
  */
-extern void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle);
+static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
+{
+	return pci_iommu_ops->free_consistent(hwdev, size, vaddr, dma_handle);
+}
 
 /* Map a single buffer of the indicated size for DMA in streaming mode.
  * The 32-bit bus address to use is returned.
@@ -62,7 +81,10 @@
  * Once the device is given the dma address, the device owns this memory
  * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed.
  */
-extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction);
+static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
+{
+	return pci_iommu_ops->map_single(hwdev, ptr, size, direction);
+}
 
 /* Unmap a single streaming mode DMA translation.  The dma_addr and size
  * must match what was provided for in a previous pci_map_single call.  All
@@ -71,7 +93,10 @@
  * After this call, reads by the cpu to the buffer are guaranteed to see
  * whatever the device wrote there.
  */
-extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction);
+static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction)
+{
+	pci_iommu_ops->unmap_single(hwdev, dma_addr, size, direction);
+}
 
 /* No highmem on sparc64, plus we have an IOMMU, so mapping pages is easy. */
 #define pci_map_page(dev, page, off, size, dir) \
@@ -107,15 +132,19 @@
  * Device ownership issues as mentioned above for pci_map_single are
  * the same here.
  */
-extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-		      int nents, int direction);
+static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
+{
+	return pci_iommu_ops->map_sg(hwdev, sg, nents, direction);
+}
 
 /* Unmap a set of streaming mode DMA translations.
  * Again, cpu read rules concerning calls here are the same as for
  * pci_unmap_single() above.
  */
-extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-			 int nhwents, int direction);
+static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction)
+{
+	pci_iommu_ops->unmap_sg(hwdev, sg, nhwents, direction);
+}
 
 /* Make physical memory consistent for a single
  * streaming mode DMA translation after a transfer.
@@ -127,8 +156,10 @@
  * must first perform a pci_dma_sync_for_device, and then the
  * device again owns the buffer.
  */
-extern void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle,
-					size_t size, int direction);
+static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
+{
+	pci_iommu_ops->dma_sync_single_for_cpu(hwdev, dma_handle, size, direction);
+}
 
 static inline void
 pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle,
@@ -144,7 +175,10 @@
  * The same as pci_dma_sync_single_* but for a scatter-gather list,
  * same rules and usage.
  */
-extern void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction);
+static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
+{
+	pci_iommu_ops->dma_sync_sg_for_cpu(hwdev, sg, nelems, direction);
+}
 
 static inline void
 pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg,
diff -urN oldtree/include/asm-sparc64/pgalloc.h newtree/include/asm-sparc64/pgalloc.h
--- oldtree/include/asm-sparc64/pgalloc.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sparc64/pgalloc.h	2006-02-21 15:58:20.783986912 +0000
@@ -6,6 +6,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/slab.h>
 
 #include <asm/spitfire.h>
 #include <asm/cpudata.h>
@@ -13,172 +14,59 @@
 #include <asm/page.h>
 
 /* Page table allocation/freeing. */
-#ifdef CONFIG_SMP
-/* Sliiiicck */
-#define pgt_quicklists	local_cpu_data()
-#else
-extern struct pgtable_cache_struct {
-	unsigned long *pgd_cache;
-	unsigned long *pte_cache[2];
-	unsigned int pgcache_size;
-} pgt_quicklists;
-#endif
-#define pgd_quicklist		(pgt_quicklists.pgd_cache)
-#define pmd_quicklist		((unsigned long *)0)
-#define pte_quicklist		(pgt_quicklists.pte_cache)
-#define pgtable_cache_size	(pgt_quicklists.pgcache_size)
-
-static __inline__ void free_pgd_fast(pgd_t *pgd)
-{
-	preempt_disable();
-	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
-	pgd_quicklist = (unsigned long *) pgd;
-	pgtable_cache_size++;
-	preempt_enable();
-}
-
-static __inline__ pgd_t *get_pgd_fast(void)
-{
-	unsigned long *ret;
-
-	preempt_disable();
-	if((ret = pgd_quicklist) != NULL) {
-		pgd_quicklist = (unsigned long *)(*ret);
-		ret[0] = 0;
-		pgtable_cache_size--;
-		preempt_enable();
-	} else {
-		preempt_enable();
-		ret = (unsigned long *) __get_free_page(GFP_KERNEL|__GFP_REPEAT);
-		if(ret)
-			memset(ret, 0, PAGE_SIZE);
-	}
-	return (pgd_t *)ret;
-}
-
-static __inline__ void free_pgd_slow(pgd_t *pgd)
-{
-	free_page((unsigned long)pgd);
-}
-
-#ifdef DCACHE_ALIASING_POSSIBLE
-#define VPTE_COLOR(address)		(((address) >> (PAGE_SHIFT + 10)) & 1UL)
-#define DCACHE_COLOR(address)		(((address) >> PAGE_SHIFT) & 1UL)
-#else
-#define VPTE_COLOR(address)		0
-#define DCACHE_COLOR(address)		0
-#endif
+extern kmem_cache_t *pgtable_cache;
 
-#define pud_populate(MM, PUD, PMD)	pud_set(PUD, PMD)
-
-static __inline__ pmd_t *pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address)
-{
-	unsigned long *ret;
-	int color = 0;
-
-	preempt_disable();
-	if (pte_quicklist[color] == NULL)
-		color = 1;
-
-	if((ret = (unsigned long *)pte_quicklist[color]) != NULL) {
-		pte_quicklist[color] = (unsigned long *)(*ret);
-		ret[0] = 0;
-		pgtable_cache_size--;
-	}
-	preempt_enable();
-
-	return (pmd_t *)ret;
-}
-
-static __inline__ pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
+static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
-	pmd_t *pmd;
-
-	pmd = pmd_alloc_one_fast(mm, address);
-	if (!pmd) {
-		pmd = (pmd_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
-		if (pmd)
-			memset(pmd, 0, PAGE_SIZE);
-	}
-	return pmd;
+	return kmem_cache_alloc(pgtable_cache, GFP_KERNEL);
 }
 
-static __inline__ void free_pmd_fast(pmd_t *pmd)
+static inline void pgd_free(pgd_t *pgd)
 {
-	unsigned long color = DCACHE_COLOR((unsigned long)pmd);
-
-	preempt_disable();
-	*(unsigned long *)pmd = (unsigned long) pte_quicklist[color];
-	pte_quicklist[color] = (unsigned long *) pmd;
-	pgtable_cache_size++;
-	preempt_enable();
+	kmem_cache_free(pgtable_cache, pgd);
 }
 
-static __inline__ void free_pmd_slow(pmd_t *pmd)
-{
-	free_page((unsigned long)pmd);
-}
-
-#define pmd_populate_kernel(MM, PMD, PTE)	pmd_set(PMD, PTE)
-#define pmd_populate(MM,PMD,PTE_PAGE)		\
-	pmd_populate_kernel(MM,PMD,page_address(PTE_PAGE))
-
-extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address);
+#define pud_populate(MM, PUD, PMD)	pud_set(PUD, PMD)
 
-static inline struct page *
-pte_alloc_one(struct mm_struct *mm, unsigned long addr)
+static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
-	pte_t *pte = pte_alloc_one_kernel(mm, addr);
-
-	if (pte)
-		return virt_to_page(pte);
-
-	return NULL;
+	return kmem_cache_alloc(pgtable_cache,
+				GFP_KERNEL|__GFP_REPEAT);
 }
 
-static __inline__ pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
+static inline void pmd_free(pmd_t *pmd)
 {
-	unsigned long color = VPTE_COLOR(address);
-	unsigned long *ret;
-
-	preempt_disable();
-	if((ret = (unsigned long *)pte_quicklist[color]) != NULL) {
-		pte_quicklist[color] = (unsigned long *)(*ret);
-		ret[0] = 0;
-		pgtable_cache_size--;
-	}
-	preempt_enable();
-	return (pte_t *)ret;
+	kmem_cache_free(pgtable_cache, pmd);
 }
 
-static __inline__ void free_pte_fast(pte_t *pte)
+static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
+					  unsigned long address)
 {
-	unsigned long color = DCACHE_COLOR((unsigned long)pte);
-
-	preempt_disable();
-	*(unsigned long *)pte = (unsigned long) pte_quicklist[color];
-	pte_quicklist[color] = (unsigned long *) pte;
-	pgtable_cache_size++;
-	preempt_enable();
+	return kmem_cache_alloc(pgtable_cache,
+				GFP_KERNEL|__GFP_REPEAT);
 }
 
-static __inline__ void free_pte_slow(pte_t *pte)
+static inline struct page *pte_alloc_one(struct mm_struct *mm,
+					 unsigned long address)
 {
-	free_page((unsigned long)pte);
+	return virt_to_page(pte_alloc_one_kernel(mm, address));
 }
-
+		
 static inline void pte_free_kernel(pte_t *pte)
 {
-	free_pte_fast(pte);
+	kmem_cache_free(pgtable_cache, pte);
 }
 
 static inline void pte_free(struct page *ptepage)
 {
-	free_pte_fast(page_address(ptepage));
+	pte_free_kernel(page_address(ptepage));
 }
 
-#define pmd_free(pmd)		free_pmd_fast(pmd)
-#define pgd_free(pgd)		free_pgd_fast(pgd)
-#define pgd_alloc(mm)		get_pgd_fast()
+
+#define pmd_populate_kernel(MM, PMD, PTE)	pmd_set(PMD, PTE)
+#define pmd_populate(MM,PMD,PTE_PAGE)		\
+	pmd_populate_kernel(MM,PMD,page_address(PTE_PAGE))
+
+#define check_pgt_cache()	do { } while (0)
 
 #endif /* _SPARC64_PGALLOC_H */
diff -urN oldtree/include/asm-sparc64/pgtable.h newtree/include/asm-sparc64/pgtable.h
--- oldtree/include/asm-sparc64/pgtable.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sparc64/pgtable.h	2006-02-21 15:58:20.784986760 +0000
@@ -25,7 +25,8 @@
 #include <asm/const.h>
 
 /* The kernel image occupies 0x4000000 to 0x1000000 (4MB --> 32MB).
- * The page copy blockops can use 0x2000000 to 0x10000000.
+ * The page copy blockops can use 0x2000000 to 0x4000000.
+ * The TSB is mapped in the 0x4000000 to 0x6000000 range.
  * The PROM resides in an area spanning 0xf0000000 to 0x100000000.
  * The vmalloc area spans 0x100000000 to 0x200000000.
  * Since modules need to be in the lowest 32-bits of the address space,
@@ -34,6 +35,7 @@
  * 0x400000000.
  */
 #define	TLBTEMP_BASE		_AC(0x0000000002000000,UL)
+#define	TSBMAP_BASE		_AC(0x0000000004000000,UL)
 #define MODULES_VADDR		_AC(0x0000000010000000,UL)
 #define MODULES_LEN		_AC(0x00000000e0000000,UL)
 #define MODULES_END		_AC(0x00000000f0000000,UL)
@@ -88,130 +90,133 @@
 
 #endif /* !(__ASSEMBLY__) */
 
-/* Spitfire/Cheetah TTE bits. */
-#define _PAGE_VALID	_AC(0x8000000000000000,UL) /* Valid TTE              */
-#define _PAGE_R		_AC(0x8000000000000000,UL) /* Keep ref bit up to date*/
-#define _PAGE_SZ4MB	_AC(0x6000000000000000,UL) /* 4MB Page               */
-#define _PAGE_SZ512K	_AC(0x4000000000000000,UL) /* 512K Page              */
-#define _PAGE_SZ64K	_AC(0x2000000000000000,UL) /* 64K Page               */
-#define _PAGE_SZ8K	_AC(0x0000000000000000,UL) /* 8K Page                */
-#define _PAGE_NFO	_AC(0x1000000000000000,UL) /* No Fault Only          */
-#define _PAGE_IE	_AC(0x0800000000000000,UL) /* Invert Endianness      */
-#define _PAGE_SOFT2	_AC(0x07FC000000000000,UL) /* Software bits, set 2   */
-#define _PAGE_RES1	_AC(0x0002000000000000,UL) /* Reserved               */
-#define _PAGE_SZ32MB	_AC(0x0001000000000000,UL) /* (Panther) 32MB page    */
-#define _PAGE_SZ256MB	_AC(0x2001000000000000,UL) /* (Panther) 256MB page   */
-#define _PAGE_SN	_AC(0x0000800000000000,UL) /* (Cheetah) Snoop        */
-#define _PAGE_RES2	_AC(0x0000780000000000,UL) /* Reserved               */
-#define _PAGE_PADDR_SF	_AC(0x000001FFFFFFE000,UL) /* (Spitfire) paddr[40:13]*/
-#define _PAGE_PADDR	_AC(0x000007FFFFFFE000,UL) /* (Cheetah) paddr[42:13] */
-#define _PAGE_SOFT	_AC(0x0000000000001F80,UL) /* Software bits          */
-#define _PAGE_L		_AC(0x0000000000000040,UL) /* Locked TTE             */
-#define _PAGE_CP	_AC(0x0000000000000020,UL) /* Cacheable in P-Cache   */
-#define _PAGE_CV	_AC(0x0000000000000010,UL) /* Cacheable in V-Cache   */
-#define _PAGE_E		_AC(0x0000000000000008,UL) /* side-Effect            */
-#define _PAGE_P		_AC(0x0000000000000004,UL) /* Privileged Page        */
-#define _PAGE_W		_AC(0x0000000000000002,UL) /* Writable               */
-#define _PAGE_G		_AC(0x0000000000000001,UL) /* Global                 */
-
-/* Here are the SpitFire software bits we use in the TTE's.
- *
- * WARNING: If you are going to try and start using some
- *          of the soft2 bits, you will need to make
- *          modifications to the swap entry implementation.
- *	    For example, one thing that could happen is that
- *          swp_entry_to_pte() would BUG_ON() if you tried
- *          to use one of the soft2 bits for _PAGE_FILE.
- *
- * Like other architectures, I have aliased _PAGE_FILE with
- * _PAGE_MODIFIED.  This works because _PAGE_FILE is never
- * interpreted that way unless _PAGE_PRESENT is clear.
- */
-#define _PAGE_EXEC	_AC(0x0000000000001000,UL)	/* Executable SW bit */
-#define _PAGE_MODIFIED	_AC(0x0000000000000800,UL)	/* Modified (dirty)  */
-#define _PAGE_FILE	_AC(0x0000000000000800,UL)	/* Pagecache page    */
-#define _PAGE_ACCESSED	_AC(0x0000000000000400,UL)	/* Accessed (ref'd)  */
-#define _PAGE_READ	_AC(0x0000000000000200,UL)	/* Readable SW Bit   */
-#define _PAGE_WRITE	_AC(0x0000000000000100,UL)	/* Writable SW Bit   */
-#define _PAGE_PRESENT	_AC(0x0000000000000080,UL)	/* Present           */
+/* PTE bits which are the same in SUN4U and SUN4V format.  */
+#define _PAGE_VALID	  _AC(0x8000000000000000,UL) /* Valid TTE            */
+#define _PAGE_R	  	  _AC(0x8000000000000000,UL) /* Keep ref bit uptodate*/
+
+/* SUN4U pte bits... */
+#define _PAGE_SZ4MB_4U	  _AC(0x6000000000000000,UL) /* 4MB Page             */
+#define _PAGE_SZ512K_4U	  _AC(0x4000000000000000,UL) /* 512K Page            */
+#define _PAGE_SZ64K_4U	  _AC(0x2000000000000000,UL) /* 64K Page             */
+#define _PAGE_SZ8K_4U	  _AC(0x0000000000000000,UL) /* 8K Page              */
+#define _PAGE_NFO_4U	  _AC(0x1000000000000000,UL) /* No Fault Only        */
+#define _PAGE_IE_4U	  _AC(0x0800000000000000,UL) /* Invert Endianness    */
+#define _PAGE_SOFT2_4U	  _AC(0x07FC000000000000,UL) /* Software bits, set 2 */
+#define _PAGE_RES1_4U	  _AC(0x0002000000000000,UL) /* Reserved             */
+#define _PAGE_SZ32MB_4U	  _AC(0x0001000000000000,UL) /* (Panther) 32MB page  */
+#define _PAGE_SZ256MB_4U  _AC(0x2001000000000000,UL) /* (Panther) 256MB page */
+#define _PAGE_SN_4U	  _AC(0x0000800000000000,UL) /* (Cheetah) Snoop      */
+#define _PAGE_RES2_4U	  _AC(0x0000780000000000,UL) /* Reserved             */
+#define _PAGE_PADDR_4U	  _AC(0x000007FFFFFFE000,UL) /* (Cheetah) pa[42:13]  */
+#define _PAGE_SOFT_4U	  _AC(0x0000000000001F80,UL) /* Software bits:       */
+#define _PAGE_EXEC_4U	  _AC(0x0000000000001000,UL) /* Executable SW bit    */
+#define _PAGE_MODIFIED_4U _AC(0x0000000000000800,UL) /* Modified (dirty)     */
+#define _PAGE_FILE_4U	  _AC(0x0000000000000800,UL) /* Pagecache page       */
+#define _PAGE_ACCESSED_4U _AC(0x0000000000000400,UL) /* Accessed (ref'd)     */
+#define _PAGE_READ_4U	  _AC(0x0000000000000200,UL) /* Readable SW Bit      */
+#define _PAGE_WRITE_4U	  _AC(0x0000000000000100,UL) /* Writable SW Bit      */
+#define _PAGE_PRESENT_4U  _AC(0x0000000000000080,UL) /* Present              */
+#define _PAGE_L_4U	  _AC(0x0000000000000040,UL) /* Locked TTE           */
+#define _PAGE_CP_4U	  _AC(0x0000000000000020,UL) /* Cacheable in P-Cache */
+#define _PAGE_CV_4U	  _AC(0x0000000000000010,UL) /* Cacheable in V-Cache */
+#define _PAGE_E_4U	  _AC(0x0000000000000008,UL) /* side-Effect          */
+#define _PAGE_P_4U	  _AC(0x0000000000000004,UL) /* Privileged Page      */
+#define _PAGE_W_4U	  _AC(0x0000000000000002,UL) /* Writable             */
+
+/* SUN4V pte bits... */
+#define _PAGE_NFO_4V	  _AC(0x4000000000000000,UL) /* No Fault Only        */
+#define _PAGE_SOFT2_4V	  _AC(0x3F00000000000000,UL) /* Software bits, set 2 */
+#define _PAGE_MODIFIED_4V _AC(0x2000000000000000,UL) /* Modified (dirty)     */
+#define _PAGE_ACCESSED_4V _AC(0x1000000000000000,UL) /* Accessed (ref'd)     */
+#define _PAGE_READ_4V	  _AC(0x0800000000000000,UL) /* Readable SW Bit      */
+#define _PAGE_WRITE_4V	  _AC(0x0400000000000000,UL) /* Writable SW Bit      */
+#define _PAGE_PADDR_4V	  _AC(0x00FFFFFFFFFFE000,UL) /* paddr[55:13]         */
+#define _PAGE_IE_4V	  _AC(0x0000000000001000,UL) /* Invert Endianness    */
+#define _PAGE_E_4V	  _AC(0x0000000000000800,UL) /* side-Effect          */
+#define _PAGE_CP_4V	  _AC(0x0000000000000400,UL) /* Cacheable in P-Cache */
+#define _PAGE_CV_4V	  _AC(0x0000000000000200,UL) /* Cacheable in V-Cache */
+#define _PAGE_P_4V	  _AC(0x0000000000000100,UL) /* Privileged Page      */
+#define _PAGE_EXEC_4V	  _AC(0x0000000000000080,UL) /* Executable Page      */
+#define _PAGE_W_4V	  _AC(0x0000000000000040,UL) /* Writable             */
+#define _PAGE_SOFT_4V	  _AC(0x0000000000000030,UL) /* Software bits        */
+#define _PAGE_FILE_4V	  _AC(0x0000000000000020,UL) /* Pagecache page       */
+#define _PAGE_PRESENT_4V  _AC(0x0000000000000010,UL) /* Present              */
+#define _PAGE_RESV_4V	  _AC(0x0000000000000008,UL) /* Reserved             */
+#define _PAGE_SZ16GB_4V	  _AC(0x0000000000000007,UL) /* 16GB Page            */
+#define _PAGE_SZ2GB_4V	  _AC(0x0000000000000006,UL) /* 2GB Page             */
+#define _PAGE_SZ256MB_4V  _AC(0x0000000000000005,UL) /* 256MB Page           */
+#define _PAGE_SZ32MB_4V	  _AC(0x0000000000000004,UL) /* 32MB Page            */
+#define _PAGE_SZ4MB_4V	  _AC(0x0000000000000003,UL) /* 4MB Page             */
+#define _PAGE_SZ512K_4V	  _AC(0x0000000000000002,UL) /* 512K Page            */
+#define _PAGE_SZ64K_4V	  _AC(0x0000000000000001,UL) /* 64K Page             */
+#define _PAGE_SZ8K_4V	  _AC(0x0000000000000000,UL) /* 8K Page              */
 
 #if PAGE_SHIFT == 13
-#define _PAGE_SZBITS	_PAGE_SZ8K
+#define _PAGE_SZBITS_4U	_PAGE_SZ8K_4U
+#define _PAGE_SZBITS_4V	_PAGE_SZ8K_4V
 #elif PAGE_SHIFT == 16
-#define _PAGE_SZBITS	_PAGE_SZ64K
+#define _PAGE_SZBITS_4U	_PAGE_SZ64K_4U
+#define _PAGE_SZBITS_4V	_PAGE_SZ64K_4V
 #elif PAGE_SHIFT == 19
-#define _PAGE_SZBITS	_PAGE_SZ512K
+#define _PAGE_SZBITS_4U	_PAGE_SZ512K_4U
+#define _PAGE_SZBITS_4V	_PAGE_SZ512K_4V
 #elif PAGE_SHIFT == 22
-#define _PAGE_SZBITS	_PAGE_SZ4MB
+#define _PAGE_SZBITS_4U	_PAGE_SZ4MB_4U
+#define _PAGE_SZBITS_4V	_PAGE_SZ4MB_4V
 #else
 #error Wrong PAGE_SHIFT specified
 #endif
 
 #if defined(CONFIG_HUGETLB_PAGE_SIZE_4MB)
-#define _PAGE_SZHUGE	_PAGE_SZ4MB
+#define _PAGE_SZHUGE_4U	_PAGE_SZ4MB_4U
+#define _PAGE_SZHUGE_4V	_PAGE_SZ4MB_4V
 #elif defined(CONFIG_HUGETLB_PAGE_SIZE_512K)
-#define _PAGE_SZHUGE	_PAGE_SZ512K
+#define _PAGE_SZHUGE_4U	_PAGE_SZ512K_4U
+#define _PAGE_SZHUGE_4V	_PAGE_SZ512K_4V
 #elif defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
-#define _PAGE_SZHUGE	_PAGE_SZ64K
+#define _PAGE_SZHUGE_4U	_PAGE_SZ64K_4U
+#define _PAGE_SZHUGE_4V	_PAGE_SZ64K_4V
 #endif
 
-#define _PAGE_CACHE	(_PAGE_CP | _PAGE_CV)
-
-#define __DIRTY_BITS	(_PAGE_MODIFIED | _PAGE_WRITE | _PAGE_W)
-#define __ACCESS_BITS	(_PAGE_ACCESSED | _PAGE_READ | _PAGE_R)
-#define __PRIV_BITS	_PAGE_P
-
-#define PAGE_NONE	__pgprot (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_CACHE)
-
-/* Don't set the TTE _PAGE_W bit here, else the dirty bit never gets set. */
-#define PAGE_SHARED	__pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \
-				  __ACCESS_BITS | _PAGE_WRITE | _PAGE_EXEC)
-
-#define PAGE_COPY	__pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \
-				  __ACCESS_BITS | _PAGE_EXEC)
-
-#define PAGE_READONLY	__pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \
-				  __ACCESS_BITS | _PAGE_EXEC)
-
-#define PAGE_KERNEL	__pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \
-				  __PRIV_BITS | \
-				  __ACCESS_BITS | __DIRTY_BITS | _PAGE_EXEC)
-
-#define PAGE_SHARED_NOEXEC	__pgprot (_PAGE_PRESENT | _PAGE_VALID | \
-					  _PAGE_CACHE | \
-					  __ACCESS_BITS | _PAGE_WRITE)
-
-#define PAGE_COPY_NOEXEC	__pgprot (_PAGE_PRESENT | _PAGE_VALID | \
-					  _PAGE_CACHE | __ACCESS_BITS)
-
-#define PAGE_READONLY_NOEXEC	__pgprot (_PAGE_PRESENT | _PAGE_VALID | \
-					  _PAGE_CACHE | __ACCESS_BITS)
-
-#define _PFN_MASK	_PAGE_PADDR
-
-#define pg_iobits (_PAGE_VALID | _PAGE_PRESENT | __DIRTY_BITS | \
-		   __ACCESS_BITS | _PAGE_E)
-
-#define __P000	PAGE_NONE
-#define __P001	PAGE_READONLY_NOEXEC
-#define __P010	PAGE_COPY_NOEXEC
-#define __P011	PAGE_COPY_NOEXEC
-#define __P100	PAGE_READONLY
-#define __P101	PAGE_READONLY
-#define __P110	PAGE_COPY
-#define __P111	PAGE_COPY
-
-#define __S000	PAGE_NONE
-#define __S001	PAGE_READONLY_NOEXEC
-#define __S010	PAGE_SHARED_NOEXEC
-#define __S011	PAGE_SHARED_NOEXEC
-#define __S100	PAGE_READONLY
-#define __S101	PAGE_READONLY
-#define __S110	PAGE_SHARED
-#define __S111	PAGE_SHARED
+/* These are actually filled in at boot time by sun4{u,v}_pgprot_init() */
+#define __P000	__pgprot(0)
+#define __P001	__pgprot(0)
+#define __P010	__pgprot(0)
+#define __P011	__pgprot(0)
+#define __P100	__pgprot(0)
+#define __P101	__pgprot(0)
+#define __P110	__pgprot(0)
+#define __P111	__pgprot(0)
+
+#define __S000	__pgprot(0)
+#define __S001	__pgprot(0)
+#define __S010	__pgprot(0)
+#define __S011	__pgprot(0)
+#define __S100	__pgprot(0)
+#define __S101	__pgprot(0)
+#define __S110	__pgprot(0)
+#define __S111	__pgprot(0)
 
 #ifndef __ASSEMBLY__
 
+extern pte_t mk_pte_io(unsigned long, pgprot_t, int, unsigned long);
+
+extern unsigned long pte_sz_bits(unsigned long size);
+
+extern pgprot_t PAGE_KERNEL;
+extern pgprot_t PAGE_KERNEL_LOCKED;
+extern pgprot_t PAGE_COPY;
+extern pgprot_t PAGE_SHARED;
+
+/* XXX This uglyness is for the atyfb driver's sparc mmap() support. XXX */
+extern unsigned long _PAGE_IE;
+extern unsigned long _PAGE_E;
+extern unsigned long _PAGE_CACHE;
+
+extern unsigned long pg_iobits;
+extern unsigned long _PAGE_ALL_SZ_BITS;
+extern unsigned long _PAGE_SZBITS;
+
 extern unsigned long phys_base;
 extern unsigned long pfn_base;
 
@@ -223,27 +228,403 @@
  * the first physical page in the machine is at some huge physical address,
  * such as 4GB.   This is common on a partitioned E10000, for example.
  */
+static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot)
+{
+	unsigned long paddr = pfn << PAGE_SHIFT;
+	unsigned long sz_bits;
 
-#define pfn_pte(pfn, prot)	\
-	__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot) | _PAGE_SZBITS)
+	sz_bits = 0UL;
+	if (_PAGE_SZBITS_4U != 0UL || _PAGE_SZBITS_4V != 0UL) {
+		__asm__ __volatile__(
+		"\n661:	sethi		%uhi(%1), %0\n"
+		"	sllx		%0, 32, %0\n"
+		"	.section	.sun4v_2insn_patch, \"ax\"\n"
+		"	.word		661b\n"
+		"	mov		%2, %0\n"
+		"	nop\n"
+		"	.previous\n"
+		: "=r" (sz_bits)
+		: "i" (_PAGE_SZBITS_4U), "i" (_PAGE_SZBITS_4V));
+	}
+	return __pte(paddr | sz_bits | pgprot_val(prot));
+}
 #define mk_pte(page, pgprot)	pfn_pte(page_to_pfn(page), (pgprot))
 
-#define pte_pfn(x)		((pte_val(x) & _PAGE_PADDR)>>PAGE_SHIFT)
-#define pte_page(x)		pfn_to_page(pte_pfn(x))
+/* This one can be done with two shifts.  */
+static inline unsigned long pte_pfn(pte_t pte)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__(
+	"\n661:	sllx		%1, %2, %0\n"
+	"	srlx		%0, %3, %0\n"
+	"	.section	.sun4v_2insn_patch, \"ax\"\n"
+	"	.word		661b\n"
+	"	sllx		%1, %4, %0\n"
+	"	srlx		%0, %5, %0\n"
+	"	.previous\n"
+	: "=r" (ret)
+	: "r" (pte_val(pte)),
+	  "i" (21), "i" (21 + PAGE_SHIFT),
+	  "i" (8), "i" (8 + PAGE_SHIFT));
+
+	return ret;
+}
+#define pte_page(x) pfn_to_page(pte_pfn(x))
+
+static inline pte_t pte_modify(pte_t pte, pgprot_t prot)
+{
+	unsigned long mask, tmp;
+
+	/* SUN4U: 0x600307ffffffecb8 (negated == 0x9ffcf80000001347)
+	 * SUN4V: 0x30ffffffffffee17 (negated == 0xcf000000000011e8)
+	 *
+	 * Even if we use negation tricks the result is still a 6
+	 * instruction sequence, so don't try to play fancy and just
+	 * do the most straightforward implementation.
+	 *
+	 * Note: We encode this into 3 sun4v 2-insn patch sequences.
+	 */
+
+	__asm__ __volatile__(
+	"\n661:	sethi		%%uhi(%2), %1\n"
+	"	sethi		%%hi(%2), %0\n"
+	"\n662:	or		%1, %%ulo(%2), %1\n"
+	"	or		%0, %%lo(%2), %0\n"
+	"\n663:	sllx		%1, 32, %1\n"
+	"	or		%0, %1, %0\n"
+	"	.section	.sun4v_2insn_patch, \"ax\"\n"
+	"	.word		661b\n"
+	"	sethi		%%uhi(%3), %1\n"
+	"	sethi		%%hi(%3), %0\n"
+	"	.word		662b\n"
+	"	or		%1, %%ulo(%3), %1\n"
+	"	or		%0, %%lo(%3), %0\n"
+	"	.word		663b\n"
+	"	sllx		%1, 32, %1\n"
+	"	or		%0, %1, %0\n"
+	"	.previous\n"
+	: "=r" (mask), "=r" (tmp)
+	: "i" (_PAGE_PADDR_4U | _PAGE_MODIFIED_4U | _PAGE_ACCESSED_4U |
+	       _PAGE_CP_4U | _PAGE_CV_4U | _PAGE_E_4U | _PAGE_PRESENT_4U |
+	       _PAGE_SZBITS_4U),
+	  "i" (_PAGE_PADDR_4V | _PAGE_MODIFIED_4V | _PAGE_ACCESSED_4V |
+	       _PAGE_CP_4V | _PAGE_CV_4V | _PAGE_E_4V | _PAGE_PRESENT_4V |
+	       _PAGE_SZBITS_4V));
+
+	return __pte((pte_val(pte) & mask) | (pgprot_val(prot) & ~mask));
+}
+
+static inline pte_t pgoff_to_pte(unsigned long off)
+{
+	off <<= PAGE_SHIFT;
+
+	__asm__ __volatile__(
+	"\n661:	or		%0, %2, %0\n"
+	"	.section	.sun4v_1insn_patch, \"ax\"\n"
+	"	.word		661b\n"
+	"	or		%0, %3, %0\n"
+	"	.previous\n"
+	: "=r" (off)
+	: "0" (off), "i" (_PAGE_FILE_4U), "i" (_PAGE_FILE_4V));
+
+	return __pte(off);
+}
+
+static inline pgprot_t pgprot_noncached(pgprot_t prot)
+{
+	unsigned long val = pgprot_val(prot);
+
+	__asm__ __volatile__(
+	"\n661:	andn		%0, %2, %0\n"
+	"	or		%0, %3, %0\n"
+	"	.section	.sun4v_2insn_patch, \"ax\"\n"
+	"	.word		661b\n"
+	"	andn		%0, %4, %0\n"
+	"	or		%0, %3, %0\n"
+	"	.previous\n"
+	: "=r" (val)
+	: "0" (val), "i" (_PAGE_CP_4U | _PAGE_CV_4U), "i" (_PAGE_E_4U),
+	             "i" (_PAGE_CP_4V | _PAGE_CV_4V), "i" (_PAGE_E_4V));
+
+	return __pgprot(val);
+}
+/* Various pieces of code check for platform support by ifdef testing
+ * on "pgprot_noncached".  That's broken and should be fixed, but for
+ * now...
+ */
+#define pgprot_noncached pgprot_noncached
+
+#ifdef CONFIG_HUGETLB_PAGE
+static inline pte_t pte_mkhuge(pte_t pte)
+{
+	unsigned long mask;
+
+	__asm__ __volatile__(
+	"\n661:	sethi		%%uhi(%1), %0\n"
+	"	sllx		%0, 32, %0\n"
+	"	.section	.sun4v_2insn_patch, \"ax\"\n"
+	"	.word		661b\n"
+	"	mov		%2, %0\n"
+	"	nop\n"
+	"	.previous\n"
+	: "=r" (mask)
+	: "i" (_PAGE_SZHUGE_4U), "i" (_PAGE_SZHUGE_4V));
+
+	return __pte(pte_val(pte) | mask);
+}
+#endif
+
+static inline pte_t pte_mkdirty(pte_t pte)
+{
+	unsigned long val = pte_val(pte), tmp;
+
+	__asm__ __volatile__(
+	"\n661:	or		%0, %3, %0\n"
+	"	nop\n"
+	"\n662:	nop\n"
+	"	nop\n"
+	"	.section	.sun4v_2insn_patch, \"ax\"\n"
+	"	.word		661b\n"
+	"	sethi		%%uhi(%4), %1\n"
+	"	sllx		%1, 32, %1\n"
+	"	.word		662b\n"
+	"	or		%1, %%lo(%4), %1\n"
+	"	or		%0, %1, %0\n"
+	"	.previous\n"
+	: "=r" (val), "=r" (tmp)
+	: "0" (val), "i" (_PAGE_MODIFIED_4U | _PAGE_W_4U),
+	  "i" (_PAGE_MODIFIED_4V | _PAGE_W_4V));
+
+	return __pte(val);
+}
+
+static inline pte_t pte_mkclean(pte_t pte)
+{
+	unsigned long val = pte_val(pte), tmp;
+
+	__asm__ __volatile__(
+	"\n661:	andn		%0, %3, %0\n"
+	"	nop\n"
+	"\n662:	nop\n"
+	"	nop\n"
+	"	.section	.sun4v_2insn_patch, \"ax\"\n"
+	"	.word		661b\n"
+	"	sethi		%%uhi(%4), %1\n"
+	"	sllx		%1, 32, %1\n"
+	"	.word		662b\n"
+	"	or		%1, %%lo(%4), %1\n"
+	"	andn		%0, %1, %0\n"
+	"	.previous\n"
+	: "=r" (val), "=r" (tmp)
+	: "0" (val), "i" (_PAGE_MODIFIED_4U | _PAGE_W_4U),
+	  "i" (_PAGE_MODIFIED_4V | _PAGE_W_4V));
+
+	return __pte(val);
+}
+
+static inline pte_t pte_mkwrite(pte_t pte)
+{
+	unsigned long val = pte_val(pte), mask;
+
+	__asm__ __volatile__(
+	"\n661:	mov		%1, %0\n"
+	"	nop\n"
+	"	.section	.sun4v_2insn_patch, \"ax\"\n"
+	"	.word		661b\n"
+	"	sethi		%%uhi(%2), %0\n"
+	"	sllx		%0, 32, %0\n"
+	"	.previous\n"
+	: "=r" (mask)
+	: "i" (_PAGE_WRITE_4U), "i" (_PAGE_WRITE_4V));
+
+	return __pte(val | mask);
+}
 
-static inline pte_t pte_modify(pte_t orig_pte, pgprot_t new_prot)
+static inline pte_t pte_wrprotect(pte_t pte)
 {
-	pte_t __pte;
-	const unsigned long preserve_mask = (_PFN_MASK |
-					     _PAGE_MODIFIED | _PAGE_ACCESSED |
-					     _PAGE_CACHE | _PAGE_E |
-					     _PAGE_PRESENT | _PAGE_SZBITS);
+	unsigned long val = pte_val(pte), tmp;
+
+	__asm__ __volatile__(
+	"\n661:	andn		%0, %3, %0\n"
+	"	nop\n"
+	"\n662:	nop\n"
+	"	nop\n"
+	"	.section	.sun4v_2insn_patch, \"ax\"\n"
+	"	.word		661b\n"
+	"	sethi		%%uhi(%4), %1\n"
+	"	sllx		%1, 32, %1\n"
+	"	.word		662b\n"
+	"	or		%1, %%lo(%4), %1\n"
+	"	andn		%0, %1, %0\n"
+	"	.previous\n"
+	: "=r" (val), "=r" (tmp)
+	: "0" (val), "i" (_PAGE_WRITE_4U | _PAGE_W_4U),
+	  "i" (_PAGE_WRITE_4V | _PAGE_W_4V));
+
+	return __pte(val);
+}
+
+static inline pte_t pte_mkold(pte_t pte)
+{
+	unsigned long mask;
+
+	__asm__ __volatile__(
+	"\n661:	mov		%1, %0\n"
+	"	nop\n"
+	"	.section	.sun4v_2insn_patch, \"ax\"\n"
+	"	.word		661b\n"
+	"	sethi		%%uhi(%2), %0\n"
+	"	sllx		%0, 32, %0\n"
+	"	.previous\n"
+	: "=r" (mask)
+	: "i" (_PAGE_ACCESSED_4U), "i" (_PAGE_ACCESSED_4V));
 
-	pte_val(__pte) = (pte_val(orig_pte) & preserve_mask) |
-		(pgprot_val(new_prot) & ~preserve_mask);
+	mask |= _PAGE_R;
 
-	return __pte;
+	return __pte(pte_val(pte) & ~mask);
 }
+
+static inline pte_t pte_mkyoung(pte_t pte)
+{
+	unsigned long mask;
+
+	__asm__ __volatile__(
+	"\n661:	mov		%1, %0\n"
+	"	nop\n"
+	"	.section	.sun4v_2insn_patch, \"ax\"\n"
+	"	.word		661b\n"
+	"	sethi		%%uhi(%2), %0\n"
+	"	sllx		%0, 32, %0\n"
+	"	.previous\n"
+	: "=r" (mask)
+	: "i" (_PAGE_ACCESSED_4U), "i" (_PAGE_ACCESSED_4V));
+
+	mask |= _PAGE_R;
+
+	return __pte(pte_val(pte) | mask);
+}
+
+static inline unsigned long pte_young(pte_t pte)
+{
+	unsigned long mask;
+
+	__asm__ __volatile__(
+	"\n661:	mov		%1, %0\n"
+	"	nop\n"
+	"	.section	.sun4v_2insn_patch, \"ax\"\n"
+	"	.word		661b\n"
+	"	sethi		%%uhi(%2), %0\n"
+	"	sllx		%0, 32, %0\n"
+	"	.previous\n"
+	: "=r" (mask)
+	: "i" (_PAGE_ACCESSED_4U), "i" (_PAGE_ACCESSED_4V));
+
+	return (pte_val(pte) & mask);
+}
+
+static inline unsigned long pte_dirty(pte_t pte)
+{
+	unsigned long mask;
+
+	__asm__ __volatile__(
+	"\n661:	mov		%1, %0\n"
+	"	nop\n"
+	"	.section	.sun4v_2insn_patch, \"ax\"\n"
+	"	.word		661b\n"
+	"	sethi		%%uhi(%2), %0\n"
+	"	sllx		%0, 32, %0\n"
+	"	.previous\n"
+	: "=r" (mask)
+	: "i" (_PAGE_MODIFIED_4U), "i" (_PAGE_MODIFIED_4V));
+
+	return (pte_val(pte) & mask);
+}
+
+static inline unsigned long pte_write(pte_t pte)
+{
+	unsigned long mask;
+
+	__asm__ __volatile__(
+	"\n661:	mov		%1, %0\n"
+	"	nop\n"
+	"	.section	.sun4v_2insn_patch, \"ax\"\n"
+	"	.word		661b\n"
+	"	sethi		%%uhi(%2), %0\n"
+	"	sllx		%0, 32, %0\n"
+	"	.previous\n"
+	: "=r" (mask)
+	: "i" (_PAGE_WRITE_4U), "i" (_PAGE_WRITE_4V));
+
+	return (pte_val(pte) & mask);
+}
+
+static inline unsigned long pte_exec(pte_t pte)
+{
+	unsigned long mask;
+
+	__asm__ __volatile__(
+	"\n661:	sethi		%%hi(%1), %0\n"
+	"	.section	.sun4v_1insn_patch, \"ax\"\n"
+	"	.word		661b\n"
+	"	mov		%2, %0\n"
+	"	.previous\n"
+	: "=r" (mask)
+	: "i" (_PAGE_EXEC_4U), "i" (_PAGE_EXEC_4V));
+
+	return (pte_val(pte) & mask);
+}
+
+static inline unsigned long pte_read(pte_t pte)
+{
+	unsigned long mask;
+
+	__asm__ __volatile__(
+	"\n661:	mov		%1, %0\n"
+	"	nop\n"
+	"	.section	.sun4v_2insn_patch, \"ax\"\n"
+	"	.word		661b\n"
+	"	sethi		%%uhi(%2), %0\n"
+	"	sllx		%0, 32, %0\n"
+	"	.previous\n"
+	: "=r" (mask)
+	: "i" (_PAGE_READ_4U), "i" (_PAGE_READ_4V));
+
+	return (pte_val(pte) & mask);
+}
+
+static inline unsigned long pte_file(pte_t pte)
+{
+	unsigned long val = pte_val(pte);
+
+	__asm__ __volatile__(
+	"\n661:	and		%0, %2, %0\n"
+	"	.section	.sun4v_1insn_patch, \"ax\"\n"
+	"	.word		661b\n"
+	"	and		%0, %3, %0\n"
+	"	.previous\n"
+	: "=r" (val)
+	: "0" (val), "i" (_PAGE_FILE_4U), "i" (_PAGE_FILE_4V));
+
+	return val;
+}
+
+static inline unsigned long pte_present(pte_t pte)
+{
+	unsigned long val = pte_val(pte);
+
+	__asm__ __volatile__(
+	"\n661:	and		%0, %2, %0\n"
+	"	.section	.sun4v_1insn_patch, \"ax\"\n"
+	"	.word		661b\n"
+	"	and		%0, %3, %0\n"
+	"	.previous\n"
+	: "=r" (val)
+	: "0" (val), "i" (_PAGE_PRESENT_4U), "i" (_PAGE_PRESENT_4V));
+
+	return val;
+}
+
 #define pmd_set(pmdp, ptep)	\
 	(pmd_val(*(pmdp)) = (__pa((unsigned long) (ptep)) >> 11UL))
 #define pud_set(pudp, pmdp)	\
@@ -253,8 +634,6 @@
 #define pmd_page(pmd) 			virt_to_page((void *)__pmd_page(pmd))
 #define pud_page(pud)		\
 	((unsigned long) __va((((unsigned long)pud_val(pud))<<11UL)))
-#define pte_none(pte) 			(!pte_val(pte))
-#define pte_present(pte)		(pte_val(pte) & _PAGE_PRESENT)
 #define pmd_none(pmd)			(!pmd_val(pmd))
 #define pmd_bad(pmd)			(0)
 #define pmd_present(pmd)		(pmd_val(pmd) != 0U)
@@ -264,30 +643,29 @@
 #define pud_present(pud)		(pud_val(pud) != 0U)
 #define pud_clear(pudp)			(pud_val(*(pudp)) = 0U)
 
+/* Same in both SUN4V and SUN4U.  */
+#define pte_none(pte) 			(!pte_val(pte))
+
+extern unsigned long pte_present(pte_t);
+
 /* The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-#define pte_read(pte)		(pte_val(pte) & _PAGE_READ)
-#define pte_exec(pte)		(pte_val(pte) & _PAGE_EXEC)
-#define pte_write(pte)		(pte_val(pte) & _PAGE_WRITE)
-#define pte_dirty(pte)		(pte_val(pte) & _PAGE_MODIFIED)
-#define pte_young(pte)		(pte_val(pte) & _PAGE_ACCESSED)
-#define pte_wrprotect(pte)	(__pte(pte_val(pte) & ~(_PAGE_WRITE|_PAGE_W)))
-#define pte_rdprotect(pte)	\
-	(__pte(((pte_val(pte)<<1UL)>>1UL) & ~_PAGE_READ))
-#define pte_mkclean(pte)	\
-	(__pte(pte_val(pte) & ~(_PAGE_MODIFIED|_PAGE_W)))
-#define pte_mkold(pte)		\
-	(__pte(((pte_val(pte)<<1UL)>>1UL) & ~_PAGE_ACCESSED))
-
-/* Permanent address of a page. */
-#define __page_address(page)	page_address(page)
+extern unsigned long pte_read(pte_t);
+extern unsigned long pte_exec(pte_t);
+extern unsigned long pte_write(pte_t);
+extern unsigned long pte_dirty(pte_t);
+extern unsigned long pte_young(pte_t);
+extern pte_t pte_wrprotect(pte_t);
+extern pte_t pte_rdprotect(pte_t);
+extern pte_t pte_mkclean(pte_t);
+extern pte_t pte_mkold(pte_t);
 
 /* Be very careful when you change these three, they are delicate. */
-#define pte_mkyoung(pte)	(__pte(pte_val(pte) | _PAGE_ACCESSED | _PAGE_R))
-#define pte_mkwrite(pte)	(__pte(pte_val(pte) | _PAGE_WRITE))
-#define pte_mkdirty(pte)	(__pte(pte_val(pte) | _PAGE_MODIFIED | _PAGE_W))
-#define pte_mkhuge(pte)		(__pte(pte_val(pte) | _PAGE_SZHUGE))
+extern pte_t pte_mkyoung(pte_t);
+extern pte_t pte_mkwrite(pte_t);
+extern pte_t pte_mkdirty(pte_t);
+extern pte_t pte_mkhuge(pte_t);
 
 /* to find an entry in a page-table-directory. */
 #define pgd_index(address)	(((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
@@ -296,11 +674,6 @@
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
-/* extract the pgd cache used for optimizing the tlb miss
- * slow path when executing 32-bit compat processes
- */
-#define get_pgd_cache(pgd)	((unsigned long) pgd_val(*pgd) << 11)
-
 /* Find an entry in the second-level page table.. */
 #define pmd_offset(pudp, address)	\
 	((pmd_t *) pud_page(*(pudp)) + \
@@ -327,6 +700,9 @@
 
 	/* It is more efficient to let flush_tlb_kernel_range()
 	 * handle init_mm tlb flushes.
+	 *
+	 * SUN4V NOTE: _PAGE_VALID is the same value in both the SUN4U
+	 *             and SUN4V pte layout, so this inline test is fine.
 	 */
 	if (likely(mm != &init_mm) && (pte_val(orig) & _PAGE_VALID))
 		tlb_batch_add(mm, addr, ptep, orig);
@@ -361,42 +737,23 @@
 #define __swp_entry_to_pte(x)		((pte_t) { (x).val })
 
 /* File offset in PTE support. */
-#define pte_file(pte)		(pte_val(pte) & _PAGE_FILE)
+extern unsigned long pte_file(pte_t);
 #define pte_to_pgoff(pte)	(pte_val(pte) >> PAGE_SHIFT)
-#define pgoff_to_pte(off)	(__pte(((off) << PAGE_SHIFT) | _PAGE_FILE))
+extern pte_t pgoff_to_pte(unsigned long);
 #define PTE_FILE_MAX_BITS	(64UL - PAGE_SHIFT - 1UL)
 
 extern unsigned long prom_virt_to_phys(unsigned long, int *);
 
-static __inline__ unsigned long
-sun4u_get_pte (unsigned long addr)
-{
-	pgd_t *pgdp;
-	pud_t *pudp;
-	pmd_t *pmdp;
-	pte_t *ptep;
-
-	if (addr >= PAGE_OFFSET)
-		return addr & _PAGE_PADDR;
-	if ((addr >= LOW_OBP_ADDRESS) && (addr < HI_OBP_ADDRESS))
-		return prom_virt_to_phys(addr, NULL);
-	pgdp = pgd_offset_k(addr);
-	pudp = pud_offset(pgdp, addr);
-	pmdp = pmd_offset(pudp, addr);
-	ptep = pte_offset_kernel(pmdp, addr);
-	return pte_val(*ptep) & _PAGE_PADDR;
-}
+extern unsigned long sun4u_get_pte(unsigned long);
 
-static __inline__ unsigned long
-__get_phys (unsigned long addr)
+static inline unsigned long __get_phys(unsigned long addr)
 {
-	return sun4u_get_pte (addr);
+	return sun4u_get_pte(addr);
 }
 
-static __inline__ int
-__get_iospace (unsigned long addr)
+static inline int __get_iospace(unsigned long addr)
 {
-	return ((sun4u_get_pte (addr) & 0xf0000000) >> 28);
+	return ((sun4u_get_pte(addr) & 0xf0000000) >> 28);
 }
 
 extern unsigned long *sparc64_valid_addr_bitmap;
@@ -410,9 +767,7 @@
 			       unsigned long size, pgprot_t prot);
 
 /* Clear virtual and physical cachability, set side-effect bit.  */
-#define pgprot_noncached(prot) \
-	(__pgprot((pgprot_val(prot) & ~(_PAGE_CP | _PAGE_CV)) | \
-	 _PAGE_E))
+extern pgprot_t pgprot_noncached(pgprot_t);
 
 /*
  * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in
@@ -435,12 +790,9 @@
 					  unsigned long);
 #define HAVE_ARCH_FB_UNMAPPED_AREA
 
-/*
- * No page table caches to initialise
- */
-#define pgtable_cache_init()	do { } while (0)
-
-extern void check_pgt_cache(void);
+extern void pgtable_cache_init(void);
+extern void sun4v_register_fault_status(void);
+extern void sun4v_ktsb_register(void);
 
 #endif /* !(__ASSEMBLY__) */
 
diff -urN oldtree/include/asm-sparc64/processor.h newtree/include/asm-sparc64/processor.h
--- oldtree/include/asm-sparc64/processor.h	2006-02-19 11:41:05.736471024 +0000
+++ newtree/include/asm-sparc64/processor.h	2006-02-21 15:58:20.785986608 +0000
@@ -28,6 +28,8 @@
  * User lives in his very own context, and cannot reference us. Note
  * that TASK_SIZE is a misnomer, it really gives maximum user virtual 
  * address that the kernel will allocate out.
+ *
+ * XXX No longer using virtual page tables, kill this upper limit...
  */
 #define VA_BITS		44
 #ifndef __ASSEMBLY__
@@ -37,18 +39,6 @@
 #endif
 #define TASK_SIZE	((unsigned long)-VPTE_SIZE)
 
-/*
- * The vpte base must be able to hold the entire vpte, half
- * of which lives above, and half below, the base. And it
- * is placed as close to the highest address range as possible.
- */
-#define VPTE_BASE_SPITFIRE	(-(VPTE_SIZE/2))
-#if 1
-#define VPTE_BASE_CHEETAH	VPTE_BASE_SPITFIRE
-#else
-#define VPTE_BASE_CHEETAH	0xffe0000000000000
-#endif
-
 #ifndef __ASSEMBLY__
 
 typedef struct {
diff -urN oldtree/include/asm-sparc64/pstate.h newtree/include/asm-sparc64/pstate.h
--- oldtree/include/asm-sparc64/pstate.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sparc64/pstate.h	2006-02-21 15:58:20.786986456 +0000
@@ -28,11 +28,12 @@
 
 /* The V9 TSTATE Register (with SpitFire and Linux extensions).
  *
- * ---------------------------------------------------------------
- * |  Resv  |  CCR  |  ASI  |  %pil  |  PSTATE  |  Resv  |  CWP  |
- * ---------------------------------------------------------------
- *  63    40 39   32 31   24 23    20 19       8 7      5 4     0
+ * ---------------------------------------------------------------------
+ * |  Resv |  GL  |  CCR  |  ASI  |  %pil  |  PSTATE  |  Resv  |  CWP  |
+ * ---------------------------------------------------------------------
+ *  63   43 42  40 39   32 31   24 23    20 19       8 7      5 4     0
  */
+#define TSTATE_GL	_AC(0x0000070000000000,UL) /* Global reg level  */
 #define TSTATE_CCR	_AC(0x000000ff00000000,UL) /* Condition Codes.	*/
 #define TSTATE_XCC	_AC(0x000000f000000000,UL) /* Condition Codes.	*/
 #define TSTATE_XNEG	_AC(0x0000008000000000,UL) /* %xcc Negative.	*/
diff -urN oldtree/include/asm-sparc64/scratchpad.h newtree/include/asm-sparc64/scratchpad.h
--- oldtree/include/asm-sparc64/scratchpad.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/include/asm-sparc64/scratchpad.h	2006-02-21 15:58:20.787986304 +0000
@@ -0,0 +1,14 @@
+#ifndef _SPARC64_SCRATCHPAD_H
+#define _SPARC64_SCRATCHPAD_H
+
+/* Sun4v scratchpad registers, accessed via ASI_SCRATCHPAD.  */
+
+#define SCRATCHPAD_MMU_MISS	0x00 /* Shared with OBP - set by OBP	    */
+#define SCRATCHPAD_CPUID	0x08 /* Shared with OBP - set by hypervisor */
+#define SCRATCHPAD_UTSBREG1	0x10
+#define SCRATCHPAD_UTSBREG2	0x18
+	/* 0x20 and 0x28, hypervisor only... */
+#define SCRATCHPAD_UNUSED1	0x30
+#define SCRATCHPAD_UNUSED2	0x38 /* Reserved for OBP		    */
+
+#endif /* !(_SPARC64_SCRATCHPAD_H) */
diff -urN oldtree/include/asm-sparc64/smp.h newtree/include/asm-sparc64/smp.h
--- oldtree/include/asm-sparc64/smp.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sparc64/smp.h	2006-02-21 15:58:20.787986304 +0000
@@ -37,33 +37,7 @@
  *	General functions that each host system must provide.
  */
 
-static __inline__ int hard_smp_processor_id(void)
-{
-	if (tlb_type == cheetah || tlb_type == cheetah_plus) {
-		unsigned long cfg, ver;
-		__asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
-		if ((ver >> 32) == 0x003e0016) {
-			__asm__ __volatile__("ldxa [%%g0] %1, %0"
-					     : "=r" (cfg)
-					     : "i" (ASI_JBUS_CONFIG));
-			return ((cfg >> 17) & 0x1f);
-		} else {
-			__asm__ __volatile__("ldxa [%%g0] %1, %0"
-					     : "=r" (cfg)
-					     : "i" (ASI_SAFARI_CONFIG));
-			return ((cfg >> 17) & 0x3ff);
-		}
-	} else if (this_is_starfire != 0) {
-		return starfire_hard_smp_processor_id();
-	} else {
-		unsigned long upaconfig;
-		__asm__ __volatile__("ldxa	[%%g0] %1, %0"
-				     : "=r" (upaconfig)
-				     : "i" (ASI_UPA_CONFIG));
-		return ((upaconfig >> 17) & 0x1f);
-	}
-}
-
+extern int hard_smp_processor_id(void);
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
 #endif /* !(__ASSEMBLY__) */
diff -urN oldtree/include/asm-sparc64/spitfire.h newtree/include/asm-sparc64/spitfire.h
--- oldtree/include/asm-sparc64/spitfire.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sparc64/spitfire.h	2006-02-21 15:58:20.788986152 +0000
@@ -44,6 +44,7 @@
 	spitfire = 0,
 	cheetah = 1,
 	cheetah_plus = 2,
+	hypervisor = 3,
 };
 
 extern enum ultra_tlb_layout tlb_type;
diff -urN oldtree/include/asm-sparc64/system.h newtree/include/asm-sparc64/system.h
--- oldtree/include/asm-sparc64/system.h	2006-02-19 11:41:05.737470872 +0000
+++ newtree/include/asm-sparc64/system.h	2006-02-21 15:58:20.788986152 +0000
@@ -209,9 +209,10 @@
 	/* so that ASI is only written if it changes, think again. */	\
 	__asm__ __volatile__("wr %%g0, %0, %%asi"			\
 	: : "r" (__thread_flag_byte_ptr(task_thread_info(next))[TI_FLAG_BYTE_CURRENT_DS]));\
+	trap_block[current_thread_info()->cpu].thread =			\
+		task_thread_info(next);					\
 	__asm__ __volatile__(						\
 	"mov	%%g4, %%g7\n\t"						\
-	"wrpr	%%g0, 0x95, %%pstate\n\t"				\
 	"stx	%%i6, [%%sp + 2047 + 0x70]\n\t"				\
 	"stx	%%i7, [%%sp + 2047 + 0x78]\n\t"				\
 	"rdpr	%%wstate, %%o5\n\t"					\
@@ -225,14 +226,10 @@
 	"ldx	[%%g6 + %3], %%o6\n\t"					\
 	"ldub	[%%g6 + %2], %%o5\n\t"					\
 	"ldub	[%%g6 + %4], %%o7\n\t"					\
-	"mov	%%g6, %%l2\n\t"						\
 	"wrpr	%%o5, 0x0, %%wstate\n\t"				\
 	"ldx	[%%sp + 2047 + 0x70], %%i6\n\t"				\
 	"ldx	[%%sp + 2047 + 0x78], %%i7\n\t"				\
-	"wrpr	%%g0, 0x94, %%pstate\n\t"				\
-	"mov	%%l2, %%g6\n\t"						\
 	"ldx	[%%g6 + %6], %%g4\n\t"					\
-	"wrpr	%%g0, 0x96, %%pstate\n\t"				\
 	"brz,pt %%o7, 1f\n\t"						\
 	" mov	%%g7, %0\n\t"						\
 	"b,a ret_from_syscall\n\t"					\
diff -urN oldtree/include/asm-sparc64/thread_info.h newtree/include/asm-sparc64/thread_info.h
--- oldtree/include/asm-sparc64/thread_info.h	2006-02-19 11:41:05.737470872 +0000
+++ newtree/include/asm-sparc64/thread_info.h	2006-02-21 15:58:20.789986000 +0000
@@ -64,8 +64,6 @@
 	__u64			kernel_cntd0, kernel_cntd1;
 	__u64			pcr_reg;
 
-	__u64			cee_stuff;
-
 	struct restart_block	restart_block;
 
 	struct pt_regs		*kern_una_regs;
@@ -104,10 +102,9 @@
 #define TI_KERN_CNTD0	0x00000480
 #define TI_KERN_CNTD1	0x00000488
 #define TI_PCR		0x00000490
-#define TI_CEE_STUFF	0x00000498
-#define TI_RESTART_BLOCK 0x000004a0
-#define TI_KUNA_REGS	0x000004c8
-#define TI_KUNA_INSN	0x000004d0
+#define TI_RESTART_BLOCK 0x00000498
+#define TI_KUNA_REGS	0x000004c0
+#define TI_KUNA_INSN	0x000004c8
 #define TI_FPREGS	0x00000500
 
 /* We embed this in the uppermost byte of thread_info->flags */
diff -urN oldtree/include/asm-sparc64/timex.h newtree/include/asm-sparc64/timex.h
--- oldtree/include/asm-sparc64/timex.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sparc64/timex.h	2006-02-21 15:58:20.789986000 +0000
@@ -14,4 +14,10 @@
 typedef unsigned long cycles_t;
 #define get_cycles()	tick_ops->get_tick()
 
+#define ARCH_HAS_READ_CURRENT_TIMER	1
+#define read_current_timer(timer_val_p) 	\
+({	*timer_val_p = tick_ops->get_tick();	\
+	0;					\
+})
+
 #endif
diff -urN oldtree/include/asm-sparc64/tlbflush.h newtree/include/asm-sparc64/tlbflush.h
--- oldtree/include/asm-sparc64/tlbflush.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sparc64/tlbflush.h	2006-02-21 15:58:20.790985848 +0000
@@ -5,6 +5,11 @@
 #include <linux/mm.h>
 #include <asm/mmu_context.h>
 
+/* TSB flush operations. */
+struct mmu_gather;
+extern void flush_tsb_kernel_range(unsigned long start, unsigned long end);
+extern void flush_tsb_user(struct mmu_gather *mp);
+
 /* TLB flush operations. */
 
 extern void flush_tlb_pending(void);
@@ -14,28 +19,36 @@
 #define flush_tlb_page(vma,addr)	flush_tlb_pending()
 #define flush_tlb_mm(mm)		flush_tlb_pending()
 
+/* Local cpu only.  */
 extern void __flush_tlb_all(void);
+
 extern void __flush_tlb_page(unsigned long context, unsigned long page, unsigned long r);
 
 extern void __flush_tlb_kernel_range(unsigned long start, unsigned long end);
 
 #ifndef CONFIG_SMP
 
-#define flush_tlb_all()		__flush_tlb_all()
 #define flush_tlb_kernel_range(start,end) \
-	__flush_tlb_kernel_range(start,end)
+do {	flush_tsb_kernel_range(start,end); \
+	__flush_tlb_kernel_range(start,end); \
+} while (0)
 
 #else /* CONFIG_SMP */
 
-extern void smp_flush_tlb_all(void);
 extern void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end);
 
-#define flush_tlb_all()		smp_flush_tlb_all()
 #define flush_tlb_kernel_range(start, end) \
-	smp_flush_tlb_kernel_range(start, end)
+do {	flush_tsb_kernel_range(start,end); \
+	smp_flush_tlb_kernel_range(start, end); \
+} while (0)
 
 #endif /* ! CONFIG_SMP */
 
-extern void flush_tlb_pgtables(struct mm_struct *, unsigned long, unsigned long);
+static inline void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+	/* We don't use virtual page tables for TLB miss processing
+	 * any more.  Nowadays we use the TSB.
+	 */
+}
 
 #endif /* _SPARC64_TLBFLUSH_H */
diff -urN oldtree/include/asm-sparc64/tsb.h newtree/include/asm-sparc64/tsb.h
--- oldtree/include/asm-sparc64/tsb.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/include/asm-sparc64/tsb.h	2006-02-21 15:58:20.790985848 +0000
@@ -0,0 +1,266 @@
+#ifndef _SPARC64_TSB_H
+#define _SPARC64_TSB_H
+
+/* The sparc64 TSB is similar to the powerpc hashtables.  It's a
+ * power-of-2 sized table of TAG/PTE pairs.  The cpu precomputes
+ * pointers into this table for 8K and 64K page sizes, and also a
+ * comparison TAG based upon the virtual address and context which
+ * faults.
+ *
+ * TLB miss trap handler software does the actual lookup via something
+ * of the form:
+ *
+ * 	ldxa		[%g0] ASI_{D,I}MMU_TSB_8KB_PTR, %g1
+ * 	ldxa		[%g0] ASI_{D,I}MMU, %g6
+ *	sllx		%g6, 22, %g6
+ *	srlx		%g6, 22, %g6
+ * 	ldda		[%g1] ASI_NUCLEUS_QUAD_LDD, %g4
+ * 	cmp		%g4, %g6
+ * 	bne,pn	%xcc, tsb_miss_{d,i}tlb
+ * 	 mov		FAULT_CODE_{D,I}TLB, %g3
+ * 	stxa		%g5, [%g0] ASI_{D,I}TLB_DATA_IN
+ * 	retry
+ *
+ *
+ * Each 16-byte slot of the TSB is the 8-byte tag and then the 8-byte
+ * PTE.  The TAG is of the same layout as the TLB TAG TARGET mmu
+ * register which is:
+ *
+ * -------------------------------------------------
+ * |  -  |  CONTEXT |  -  |    VADDR bits 63:22    |
+ * -------------------------------------------------
+ *  63 61 60      48 47 42 41                     0
+ *
+ * But actually, since we use per-mm TSB's, we zero out the CONTEXT
+ * field.
+ *
+ * Like the powerpc hashtables we need to use locking in order to
+ * synchronize while we update the entries.  PTE updates need locking
+ * as well.
+ *
+ * We need to carefully choose a lock bits for the TSB entry.  We
+ * choose to use bit 47 in the tag.  Also, since we never map anything
+ * at page zero in context zero, we use zero as an invalid tag entry.
+ * When the lock bit is set, this forces a tag comparison failure.
+ */
+
+#define TSB_TAG_LOCK_BIT	47
+#define TSB_TAG_LOCK_HIGH	(1 << (TSB_TAG_LOCK_BIT - 32))
+
+#define TSB_TAG_INVALID_BIT	46
+#define TSB_TAG_INVALID_HIGH	(1 << (TSB_TAG_INVALID_BIT - 32))
+
+#define TSB_MEMBAR	membar	#StoreStore
+
+/* Some cpus support physical address quad loads.  We want to use
+ * those if possible so we don't need to hard-lock the TSB mapping
+ * into the TLB.  We encode some instruction patching in order to
+ * support this.
+ *
+ * The kernel TSB is locked into the TLB by virtue of being in the
+ * kernel image, so we don't play these games for swapper_tsb access.
+ */
+#ifndef __ASSEMBLY__
+struct tsb_ldquad_phys_patch_entry {
+	unsigned int	addr;
+	unsigned int	sun4u_insn;
+	unsigned int	sun4v_insn;
+};
+extern struct tsb_ldquad_phys_patch_entry __tsb_ldquad_phys_patch,
+	__tsb_ldquad_phys_patch_end;
+
+struct tsb_phys_patch_entry {
+	unsigned int	addr;
+	unsigned int	insn;
+};
+extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
+#endif
+#define TSB_LOAD_QUAD(TSB, REG)	\
+661:	ldda		[TSB] ASI_NUCLEUS_QUAD_LDD, REG; \
+	.section	.tsb_ldquad_phys_patch, "ax"; \
+	.word		661b; \
+	ldda		[TSB] ASI_QUAD_LDD_PHYS, REG; \
+	ldda		[TSB] ASI_QUAD_LDD_PHYS_4V, REG; \
+	.previous
+
+#define TSB_LOAD_TAG_HIGH(TSB, REG) \
+661:	lduwa		[TSB] ASI_N, REG; \
+	.section	.tsb_phys_patch, "ax"; \
+	.word		661b; \
+	lduwa		[TSB] ASI_PHYS_USE_EC, REG; \
+	.previous
+
+#define TSB_LOAD_TAG(TSB, REG) \
+661:	ldxa		[TSB] ASI_N, REG; \
+	.section	.tsb_phys_patch, "ax"; \
+	.word		661b; \
+	ldxa		[TSB] ASI_PHYS_USE_EC, REG; \
+	.previous
+
+#define TSB_CAS_TAG_HIGH(TSB, REG1, REG2) \
+661:	casa		[TSB] ASI_N, REG1, REG2; \
+	.section	.tsb_phys_patch, "ax"; \
+	.word		661b; \
+	casa		[TSB] ASI_PHYS_USE_EC, REG1, REG2; \
+	.previous
+
+#define TSB_CAS_TAG(TSB, REG1, REG2) \
+661:	casxa		[TSB] ASI_N, REG1, REG2; \
+	.section	.tsb_phys_patch, "ax"; \
+	.word		661b; \
+	casxa		[TSB] ASI_PHYS_USE_EC, REG1, REG2; \
+	.previous
+
+#define TSB_STORE(ADDR, VAL) \
+661:	stxa		VAL, [ADDR] ASI_N; \
+	.section	.tsb_phys_patch, "ax"; \
+	.word		661b; \
+	stxa		VAL, [ADDR] ASI_PHYS_USE_EC; \
+	.previous
+
+#define TSB_LOCK_TAG(TSB, REG1, REG2)	\
+99:	TSB_LOAD_TAG_HIGH(TSB, REG1);	\
+	sethi	%hi(TSB_TAG_LOCK_HIGH), REG2;\
+	andcc	REG1, REG2, %g0;	\
+	bne,pn	%icc, 99b;		\
+	 nop;				\
+	TSB_CAS_TAG_HIGH(TSB, REG1, REG2);	\
+	cmp	REG1, REG2;		\
+	bne,pn	%icc, 99b;		\
+	 nop;				\
+	TSB_MEMBAR
+
+#define TSB_WRITE(TSB, TTE, TAG) \
+	add	TSB, 0x8, TSB;   \
+	TSB_STORE(TSB, TTE);     \
+	sub	TSB, 0x8, TSB;   \
+	TSB_MEMBAR;              \
+	TSB_STORE(TSB, TAG);
+
+#define KTSB_LOAD_QUAD(TSB, REG) \
+	ldda		[TSB] ASI_NUCLEUS_QUAD_LDD, REG;
+
+#define KTSB_STORE(ADDR, VAL) \
+	stxa		VAL, [ADDR] ASI_N;
+
+#define KTSB_LOCK_TAG(TSB, REG1, REG2)	\
+99:	lduwa	[TSB] ASI_N, REG1;	\
+	sethi	%hi(TSB_TAG_LOCK_HIGH), REG2;\
+	andcc	REG1, REG2, %g0;	\
+	bne,pn	%icc, 99b;		\
+	 nop;				\
+	casa	[TSB] ASI_N, REG1, REG2;\
+	cmp	REG1, REG2;		\
+	bne,pn	%icc, 99b;		\
+	 nop;				\
+	TSB_MEMBAR
+
+#define KTSB_WRITE(TSB, TTE, TAG) \
+	add	TSB, 0x8, TSB;   \
+	stxa	TTE, [TSB] ASI_N;     \
+	sub	TSB, 0x8, TSB;   \
+	TSB_MEMBAR;              \
+	stxa	TAG, [TSB] ASI_N;
+
+	/* Do a kernel page table walk.  Leaves physical PTE pointer in
+	 * REG1.  Jumps to FAIL_LABEL on early page table walk termination.
+	 * VADDR will not be clobbered, but REG2 will.
+	 */
+#define KERN_PGTABLE_WALK(VADDR, REG1, REG2, FAIL_LABEL)	\
+	sethi		%hi(swapper_pg_dir), REG1; \
+	or		REG1, %lo(swapper_pg_dir), REG1; \
+	sllx		VADDR, 64 - (PGDIR_SHIFT + PGDIR_BITS), REG2; \
+	srlx		REG2, 64 - PAGE_SHIFT, REG2; \
+	andn		REG2, 0x3, REG2; \
+	lduw		[REG1 + REG2], REG1; \
+	brz,pn		REG1, FAIL_LABEL; \
+	 sllx		VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \
+	srlx		REG2, 64 - PAGE_SHIFT, REG2; \
+	sllx		REG1, 11, REG1; \
+	andn		REG2, 0x3, REG2; \
+	lduwa		[REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
+	brz,pn		REG1, FAIL_LABEL; \
+	 sllx		VADDR, 64 - PMD_SHIFT, REG2; \
+	srlx		REG2, 64 - PAGE_SHIFT, REG2; \
+	sllx		REG1, 11, REG1; \
+	andn		REG2, 0x7, REG2; \
+	add		REG1, REG2, REG1;
+
+	/* Do a user page table walk in MMU globals.  Leaves physical PTE
+	 * pointer in REG1.  Jumps to FAIL_LABEL on early page table walk
+	 * termination.  Physical base of page tables is in PHYS_PGD which
+	 * will not be modified.
+	 *
+	 * VADDR will not be clobbered, but REG1 and REG2 will.
+	 */
+#define USER_PGTABLE_WALK_TL1(VADDR, PHYS_PGD, REG1, REG2, FAIL_LABEL)	\
+	sllx		VADDR, 64 - (PGDIR_SHIFT + PGDIR_BITS), REG2; \
+	srlx		REG2, 64 - PAGE_SHIFT, REG2; \
+	andn		REG2, 0x3, REG2; \
+	lduwa		[PHYS_PGD + REG2] ASI_PHYS_USE_EC, REG1; \
+	brz,pn		REG1, FAIL_LABEL; \
+	 sllx		VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \
+	srlx		REG2, 64 - PAGE_SHIFT, REG2; \
+	sllx		REG1, 11, REG1; \
+	andn		REG2, 0x3, REG2; \
+	lduwa		[REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
+	brz,pn		REG1, FAIL_LABEL; \
+	 sllx		VADDR, 64 - PMD_SHIFT, REG2; \
+	srlx		REG2, 64 - PAGE_SHIFT, REG2; \
+	sllx		REG1, 11, REG1; \
+	andn		REG2, 0x7, REG2; \
+	add		REG1, REG2, REG1;
+
+/* Lookup a OBP mapping on VADDR in the prom_trans[] table at TL>0.
+ * If no entry is found, FAIL_LABEL will be branched to.  On success
+ * the resulting PTE value will be left in REG1.  VADDR is preserved
+ * by this routine.
+ */
+#define OBP_TRANS_LOOKUP(VADDR, REG1, REG2, REG3, FAIL_LABEL) \
+	sethi		%hi(prom_trans), REG1; \
+	or		REG1, %lo(prom_trans), REG1; \
+97:	ldx		[REG1 + 0x00], REG2; \
+	brz,pn		REG2, FAIL_LABEL; \
+	 nop; \
+	ldx		[REG1 + 0x08], REG3; \
+	add		REG2, REG3, REG3; \
+	cmp		REG2, VADDR; \
+	bgu,pt		%xcc, 98f; \
+	 cmp		VADDR, REG3; \
+	bgeu,pt		%xcc, 98f; \
+	 ldx		[REG1 + 0x10], REG3; \
+	sub		VADDR, REG2, REG2; \
+	ba,pt		%xcc, 99f; \
+	 add		REG3, REG2, REG1; \
+98:	ba,pt		%xcc, 97b; \
+	 add		REG1, (3 * 8), REG1; \
+99:
+
+	/* We use a 32K TSB for the whole kernel, this allows to
+	 * handle about 16MB of modules and vmalloc mappings without
+	 * incurring many hash conflicts.
+	 */
+#define KERNEL_TSB_SIZE_BYTES	(32 * 1024)
+#define KERNEL_TSB_NENTRIES	\
+	(KERNEL_TSB_SIZE_BYTES / 16)
+
+	/* Do a kernel TSB lookup at tl>0 on VADDR+TAG, branch to OK_LABEL
+	 * on TSB hit.  REG1, REG2, REG3, and REG4 are used as temporaries
+	 * and the found TTE will be left in REG1.  REG3 and REG4 must
+	 * be an even/odd pair of registers.
+	 *
+	 * VADDR and TAG will be preserved and not clobbered by this macro.
+	 */
+#define KERN_TSB_LOOKUP_TL1(VADDR, TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
+	sethi		%hi(swapper_tsb), REG1; \
+	or		REG1, %lo(swapper_tsb), REG1; \
+	srlx		VADDR, PAGE_SHIFT, REG2; \
+	and		REG2, (KERNEL_TSB_NENTRIES - 1), REG2; \
+	sllx		REG2, 4, REG2; \
+	add		REG1, REG2, REG2; \
+	KTSB_LOAD_QUAD(REG2, REG3); \
+	cmp		REG3, TAG; \
+	be,a,pt		%xcc, OK_LABEL; \
+	 mov		REG4, REG1;
+
+#endif /* !(_SPARC64_TSB_H) */
diff -urN oldtree/include/asm-sparc64/ttable.h newtree/include/asm-sparc64/ttable.h
--- oldtree/include/asm-sparc64/ttable.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sparc64/ttable.h	2006-02-21 15:58:20.791985696 +0000
@@ -93,7 +93,7 @@
 	
 #define SYSCALL_TRAP(routine, systbl)			\
 	sethi	%hi(109f), %g7;				\
-	ba,pt	%xcc, scetrap;				\
+	ba,pt	%xcc, etrap;				\
 109:	 or	%g7, %lo(109b), %g7;			\
 	sethi	%hi(systbl), %l7;			\
 	ba,pt	%xcc, routine;				\
@@ -109,14 +109,14 @@
 	nop;nop;nop;
 	
 #define TRAP_UTRAP(handler,lvl)				\
-	ldx	[%g6 + TI_UTRAPS], %g1;			\
-	sethi	%hi(109f), %g7;				\
-	brz,pn	%g1, utrap;				\
-	 or	%g7, %lo(109f), %g7;			\
-	ba,pt	%xcc, utrap;				\
-109:	 ldx	[%g1 + handler*8], %g1;			\
-	ba,pt	%xcc, utrap_ill;			\
-	 mov	lvl, %o1;
+	mov	handler, %g3;				\
+	ba,pt	%xcc, utrap_trap;			\
+	 mov	lvl, %g4;				\
+	nop;						\
+	nop;						\
+	nop;						\
+	nop;						\
+	nop;
 
 #ifdef CONFIG_SUNOS_EMUL
 #define SUNOS_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall32, sunos_sys_table)
@@ -136,8 +136,6 @@
 #else
 #define SOLARIS_SYSCALL_TRAP TRAP(solaris_syscall)
 #endif
-/* FIXME: Write these actually */	
-#define NETBSD_SYSCALL_TRAP TRAP(netbsd_syscall)
 #define BREAKPOINT_TRAP TRAP(breakpoint_trap)
 
 #define TRAP_IRQ(routine, level)			\
@@ -182,6 +180,26 @@
 #define KPROBES_TRAP(lvl) TRAP_ARG(bad_trap, lvl)
 #endif
 
+#define SUN4V_ITSB_MISS					\
+	ldxa	[%g0] ASI_SCRATCHPAD, %g2;		\
+	ldx	[%g2 + HV_FAULT_I_ADDR_OFFSET], %g4;	\
+	ldx	[%g2 + HV_FAULT_I_CTX_OFFSET], %g5;	\
+	srlx	%g4, 22, %g6;				\
+	ba,pt	%xcc, sun4v_itsb_miss;			\
+	 nop;						\
+	nop;						\
+	nop;
+
+#define SUN4V_DTSB_MISS					\
+	ldxa	[%g0] ASI_SCRATCHPAD, %g2;		\
+	ldx	[%g2 + HV_FAULT_D_ADDR_OFFSET], %g4;	\
+	ldx	[%g2 + HV_FAULT_D_CTX_OFFSET], %g5;	\
+	srlx	%g4, 22, %g6;				\
+	ba,pt	%xcc, sun4v_dtsb_miss;			\
+	 nop;						\
+	nop;						\
+	nop;
+
 /* Before touching these macros, you owe it to yourself to go and
  * see how arch/sparc64/kernel/winfixup.S works... -DaveM
  *
@@ -221,6 +239,31 @@
 	saved; retry; nop; nop; nop; nop; nop; nop;	\
 	nop; nop; nop; nop; nop; nop; nop; nop;
 
+#define SPILL_0_NORMAL_ETRAP				\
+etrap_kernel_spill:					\
+	stx	%l0, [%sp + STACK_BIAS + 0x00];		\
+	stx	%l1, [%sp + STACK_BIAS + 0x08];		\
+	stx	%l2, [%sp + STACK_BIAS + 0x10];		\
+	stx	%l3, [%sp + STACK_BIAS + 0x18];		\
+	stx	%l4, [%sp + STACK_BIAS + 0x20];		\
+	stx	%l5, [%sp + STACK_BIAS + 0x28];		\
+	stx	%l6, [%sp + STACK_BIAS + 0x30];		\
+	stx	%l7, [%sp + STACK_BIAS + 0x38];		\
+	stx	%i0, [%sp + STACK_BIAS + 0x40];		\
+	stx	%i1, [%sp + STACK_BIAS + 0x48];		\
+	stx	%i2, [%sp + STACK_BIAS + 0x50];		\
+	stx	%i3, [%sp + STACK_BIAS + 0x58];		\
+	stx	%i4, [%sp + STACK_BIAS + 0x60];		\
+	stx	%i5, [%sp + STACK_BIAS + 0x68];		\
+	stx	%i6, [%sp + STACK_BIAS + 0x70];		\
+	stx	%i7, [%sp + STACK_BIAS + 0x78];		\
+	saved;						\
+	sub	%g1, 2, %g1;				\
+	ba,pt	%xcc, etrap_save;			\
+	wrpr	%g1, %cwp;				\
+	nop; nop; nop; nop; nop; nop; nop; nop;		\
+	nop; nop; nop; nop;
+
 /* Normal 64bit spill */
 #define SPILL_1_GENERIC(ASI)				\
 	add	%sp, STACK_BIAS + 0x00, %g1;		\
@@ -254,6 +297,67 @@
 	b,a,pt	%xcc, spill_fixup_mna;			\
 	b,a,pt	%xcc, spill_fixup;
 
+#define SPILL_1_GENERIC_ETRAP				\
+etrap_user_spill_64bit:					\
+	stxa	%l0, [%sp + STACK_BIAS + 0x00] %asi;	\
+	stxa	%l1, [%sp + STACK_BIAS + 0x08] %asi;	\
+	stxa	%l2, [%sp + STACK_BIAS + 0x10] %asi;	\
+	stxa	%l3, [%sp + STACK_BIAS + 0x18] %asi;	\
+	stxa	%l4, [%sp + STACK_BIAS + 0x20] %asi;	\
+	stxa	%l5, [%sp + STACK_BIAS + 0x28] %asi;	\
+	stxa	%l6, [%sp + STACK_BIAS + 0x30] %asi;	\
+	stxa	%l7, [%sp + STACK_BIAS + 0x38] %asi;	\
+	stxa	%i0, [%sp + STACK_BIAS + 0x40] %asi;	\
+	stxa	%i1, [%sp + STACK_BIAS + 0x48] %asi;	\
+	stxa	%i2, [%sp + STACK_BIAS + 0x50] %asi;	\
+	stxa	%i3, [%sp + STACK_BIAS + 0x58] %asi;	\
+	stxa	%i4, [%sp + STACK_BIAS + 0x60] %asi;	\
+	stxa	%i5, [%sp + STACK_BIAS + 0x68] %asi;	\
+	stxa	%i6, [%sp + STACK_BIAS + 0x70] %asi;	\
+	stxa	%i7, [%sp + STACK_BIAS + 0x78] %asi;	\
+	saved;						\
+	sub	%g1, 2, %g1;				\
+	ba,pt	%xcc, etrap_save;			\
+	 wrpr	%g1, %cwp;				\
+	nop; nop; nop; nop; nop;			\
+	nop; nop; nop; nop;				\
+	ba,a,pt	%xcc, etrap_spill_fixup_64bit;		\
+	ba,a,pt	%xcc, etrap_spill_fixup_64bit;		\
+	ba,a,pt	%xcc, etrap_spill_fixup_64bit;
+
+#define SPILL_1_GENERIC_ETRAP_FIXUP			\
+etrap_spill_fixup_64bit:				\
+	ldub	[%g6 + TI_WSAVED], %g1;			\
+	sll	%g1, 3, %g3;				\
+	add	%g6, %g3, %g3;				\
+	stx	%sp, [%g3 + TI_RWIN_SPTRS];		\
+	sll	%g1, 7, %g3;				\
+	add	%g6, %g3, %g3;				\
+	stx	%l0, [%g3 + TI_REG_WINDOW + 0x00];	\
+	stx	%l1, [%g3 + TI_REG_WINDOW + 0x08];	\
+	stx	%l2, [%g3 + TI_REG_WINDOW + 0x10];	\
+	stx	%l3, [%g3 + TI_REG_WINDOW + 0x18];	\
+	stx	%l4, [%g3 + TI_REG_WINDOW + 0x20];	\
+	stx	%l5, [%g3 + TI_REG_WINDOW + 0x28];	\
+	stx	%l6, [%g3 + TI_REG_WINDOW + 0x30];	\
+	stx	%l7, [%g3 + TI_REG_WINDOW + 0x38];	\
+	stx	%i0, [%g3 + TI_REG_WINDOW + 0x40];	\
+	stx	%i1, [%g3 + TI_REG_WINDOW + 0x48];	\
+	stx	%i2, [%g3 + TI_REG_WINDOW + 0x50];	\
+	stx	%i3, [%g3 + TI_REG_WINDOW + 0x58];	\
+	stx	%i4, [%g3 + TI_REG_WINDOW + 0x60];	\
+	stx	%i5, [%g3 + TI_REG_WINDOW + 0x68];	\
+	stx	%i6, [%g3 + TI_REG_WINDOW + 0x70];	\
+	stx	%i7, [%g3 + TI_REG_WINDOW + 0x78];	\
+	add	%g1, 1, %g1;				\
+	stb	%g1, [%g6 + TI_WSAVED];			\
+	saved;						\
+	rdpr	%cwp, %g1;				\
+	sub	%g1, 2, %g1;				\
+	ba,pt	%xcc, etrap_save;			\
+	 wrpr	%g1, %cwp;				\
+	nop; nop; nop
+
 /* Normal 32bit spill */
 #define SPILL_2_GENERIC(ASI)				\
 	srl	%sp, 0, %sp;				\
@@ -287,6 +391,68 @@
 	b,a,pt	%xcc, spill_fixup_mna;			\
 	b,a,pt	%xcc, spill_fixup;
 
+#define SPILL_2_GENERIC_ETRAP		\
+etrap_user_spill_32bit:			\
+	srl	%sp, 0, %sp;		\
+	stwa	%l0, [%sp + 0x00] %asi;	\
+	stwa	%l1, [%sp + 0x04] %asi;	\
+	stwa	%l2, [%sp + 0x08] %asi;	\
+	stwa	%l3, [%sp + 0x0c] %asi;	\
+	stwa	%l4, [%sp + 0x10] %asi;	\
+	stwa	%l5, [%sp + 0x14] %asi;	\
+	stwa	%l6, [%sp + 0x18] %asi;	\
+	stwa	%l7, [%sp + 0x1c] %asi;	\
+	stwa	%i0, [%sp + 0x20] %asi;	\
+	stwa	%i1, [%sp + 0x24] %asi;	\
+	stwa	%i2, [%sp + 0x28] %asi;	\
+	stwa	%i3, [%sp + 0x2c] %asi;	\
+	stwa	%i4, [%sp + 0x30] %asi;	\
+	stwa	%i5, [%sp + 0x34] %asi;	\
+	stwa	%i6, [%sp + 0x38] %asi;	\
+	stwa	%i7, [%sp + 0x3c] %asi;	\
+	saved;				\
+	sub	%g1, 2, %g1;		\
+	ba,pt	%xcc, etrap_save;	\
+	 wrpr	%g1, %cwp;		\
+	nop; nop; nop; nop;		\
+	nop; nop; nop; nop;		\
+	ba,a,pt	%xcc, etrap_spill_fixup_32bit; \
+	ba,a,pt	%xcc, etrap_spill_fixup_32bit; \
+	ba,a,pt	%xcc, etrap_spill_fixup_32bit;
+
+#define SPILL_2_GENERIC_ETRAP_FIXUP			\
+etrap_spill_fixup_32bit:				\
+	ldub	[%g6 + TI_WSAVED], %g1;			\
+	sll	%g1, 3, %g3;				\
+	add	%g6, %g3, %g3;				\
+	stx	%sp, [%g3 + TI_RWIN_SPTRS];		\
+	sll	%g1, 7, %g3;				\
+	add	%g6, %g3, %g3;				\
+	stw	%l0, [%g3 + TI_REG_WINDOW + 0x00];	\
+	stw	%l1, [%g3 + TI_REG_WINDOW + 0x04];	\
+	stw	%l2, [%g3 + TI_REG_WINDOW + 0x08];	\
+	stw	%l3, [%g3 + TI_REG_WINDOW + 0x0c];	\
+	stw	%l4, [%g3 + TI_REG_WINDOW + 0x10];	\
+	stw	%l5, [%g3 + TI_REG_WINDOW + 0x14];	\
+	stw	%l6, [%g3 + TI_REG_WINDOW + 0x18];	\
+	stw	%l7, [%g3 + TI_REG_WINDOW + 0x1c];	\
+	stw	%i0, [%g3 + TI_REG_WINDOW + 0x20];	\
+	stw	%i1, [%g3 + TI_REG_WINDOW + 0x24];	\
+	stw	%i2, [%g3 + TI_REG_WINDOW + 0x28];	\
+	stw	%i3, [%g3 + TI_REG_WINDOW + 0x2c];	\
+	stw	%i4, [%g3 + TI_REG_WINDOW + 0x30];	\
+	stw	%i5, [%g3 + TI_REG_WINDOW + 0x34];	\
+	stw	%i6, [%g3 + TI_REG_WINDOW + 0x38];	\
+	stw	%i7, [%g3 + TI_REG_WINDOW + 0x3c];	\
+	add	%g1, 1, %g1;				\
+	stb	%g1, [%g6 + TI_WSAVED];			\
+	saved;						\
+	rdpr	%cwp, %g1;				\
+	sub	%g1, 2, %g1;				\
+	ba,pt	%xcc, etrap_save;			\
+	 wrpr	%g1, %cwp;				\
+	nop; nop; nop
+
 #define SPILL_1_NORMAL SPILL_1_GENERIC(ASI_AIUP)
 #define SPILL_2_NORMAL SPILL_2_GENERIC(ASI_AIUP)
 #define SPILL_3_NORMAL SPILL_0_NORMAL
@@ -325,6 +491,35 @@
 	restored; retry; nop; nop; nop; nop; nop; nop;	\
 	nop; nop; nop; nop; nop; nop; nop; nop;
 
+#define FILL_0_NORMAL_RTRAP				\
+kern_rtt_fill:						\
+	rdpr	%cwp, %g1;				\
+	sub	%g1, 1, %g1;				\
+	wrpr	%g1, %cwp;				\
+	ldx	[%sp + STACK_BIAS + 0x00], %l0;		\
+	ldx	[%sp + STACK_BIAS + 0x08], %l1;		\
+	ldx	[%sp + STACK_BIAS + 0x10], %l2;		\
+	ldx	[%sp + STACK_BIAS + 0x18], %l3;		\
+	ldx	[%sp + STACK_BIAS + 0x20], %l4;		\
+	ldx	[%sp + STACK_BIAS + 0x28], %l5;		\
+	ldx	[%sp + STACK_BIAS + 0x30], %l6;		\
+	ldx	[%sp + STACK_BIAS + 0x38], %l7;		\
+	ldx	[%sp + STACK_BIAS + 0x40], %i0;		\
+	ldx	[%sp + STACK_BIAS + 0x48], %i1;		\
+	ldx	[%sp + STACK_BIAS + 0x50], %i2;		\
+	ldx	[%sp + STACK_BIAS + 0x58], %i3;		\
+	ldx	[%sp + STACK_BIAS + 0x60], %i4;		\
+	ldx	[%sp + STACK_BIAS + 0x68], %i5;		\
+	ldx	[%sp + STACK_BIAS + 0x70], %i6;		\
+	ldx	[%sp + STACK_BIAS + 0x78], %i7;		\
+	restored;					\
+	add	%g1, 1, %g1;				\
+	ba,pt	%xcc, kern_rtt_restore;			\
+	 wrpr	%g1, %cwp;				\
+	nop; nop; nop; nop; nop;			\
+	nop; nop; nop; nop;
+
+
 /* Normal 64bit fill */
 #define FILL_1_GENERIC(ASI)				\
 	add	%sp, STACK_BIAS + 0x00, %g1;		\
@@ -356,6 +551,33 @@
 	b,a,pt	%xcc, fill_fixup_mna;			\
 	b,a,pt	%xcc, fill_fixup;
 
+#define FILL_1_GENERIC_RTRAP				\
+user_rtt_fill_64bit:					\
+	ldxa	[%sp + STACK_BIAS + 0x00] %asi, %l0;	\
+	ldxa	[%sp + STACK_BIAS + 0x08] %asi, %l1;	\
+	ldxa	[%sp + STACK_BIAS + 0x10] %asi, %l2;	\
+	ldxa	[%sp + STACK_BIAS + 0x18] %asi, %l3;	\
+	ldxa	[%sp + STACK_BIAS + 0x20] %asi, %l4;	\
+	ldxa	[%sp + STACK_BIAS + 0x28] %asi, %l5;	\
+	ldxa	[%sp + STACK_BIAS + 0x30] %asi, %l6;	\
+	ldxa	[%sp + STACK_BIAS + 0x38] %asi, %l7;	\
+	ldxa	[%sp + STACK_BIAS + 0x40] %asi, %i0;	\
+	ldxa	[%sp + STACK_BIAS + 0x48] %asi, %i1;	\
+	ldxa	[%sp + STACK_BIAS + 0x50] %asi, %i2;	\
+	ldxa	[%sp + STACK_BIAS + 0x58] %asi, %i3;	\
+	ldxa	[%sp + STACK_BIAS + 0x60] %asi, %i4;	\
+	ldxa	[%sp + STACK_BIAS + 0x68] %asi, %i5;	\
+	ldxa	[%sp + STACK_BIAS + 0x70] %asi, %i6;	\
+	ldxa	[%sp + STACK_BIAS + 0x78] %asi, %i7;	\
+	ba,pt	%xcc, user_rtt_pre_restore;		\
+	 restored;					\
+	nop; nop; nop; nop; nop; nop;			\
+	nop; nop; nop; nop; nop;			\
+	ba,a,pt	%xcc, user_rtt_fill_fixup;		\
+	ba,a,pt	%xcc, user_rtt_fill_fixup;		\
+	ba,a,pt	%xcc, user_rtt_fill_fixup;
+
+
 /* Normal 32bit fill */
 #define FILL_2_GENERIC(ASI)				\
 	srl	%sp, 0, %sp;				\
@@ -387,6 +609,34 @@
 	b,a,pt	%xcc, fill_fixup_mna;			\
 	b,a,pt	%xcc, fill_fixup;
 
+#define FILL_2_GENERIC_RTRAP				\
+user_rtt_fill_32bit:					\
+	srl	%sp, 0, %sp;				\
+	lduwa	[%sp + 0x00] %asi, %l0;			\
+	lduwa	[%sp + 0x04] %asi, %l1;			\
+	lduwa	[%sp + 0x08] %asi, %l2;			\
+	lduwa	[%sp + 0x0c] %asi, %l3;			\
+	lduwa	[%sp + 0x10] %asi, %l4;			\
+	lduwa	[%sp + 0x14] %asi, %l5;			\
+	lduwa	[%sp + 0x18] %asi, %l6;			\
+	lduwa	[%sp + 0x1c] %asi, %l7;			\
+	lduwa	[%sp + 0x20] %asi, %i0;			\
+	lduwa	[%sp + 0x24] %asi, %i1;			\
+	lduwa	[%sp + 0x28] %asi, %i2;			\
+	lduwa	[%sp + 0x2c] %asi, %i3;			\
+	lduwa	[%sp + 0x30] %asi, %i4;			\
+	lduwa	[%sp + 0x34] %asi, %i5;			\
+	lduwa	[%sp + 0x38] %asi, %i6;			\
+	lduwa	[%sp + 0x3c] %asi, %i7;			\
+	ba,pt	%xcc, user_rtt_pre_restore;		\
+	 restored;					\
+	nop; nop; nop; nop; nop;			\
+	nop; nop; nop; nop; nop;			\
+	ba,a,pt	%xcc, user_rtt_fill_fixup;		\
+	ba,a,pt	%xcc, user_rtt_fill_fixup;		\
+	ba,a,pt	%xcc, user_rtt_fill_fixup;
+		
+
 #define FILL_1_NORMAL FILL_1_GENERIC(ASI_AIUP)
 #define FILL_2_NORMAL FILL_2_GENERIC(ASI_AIUP)
 #define FILL_3_NORMAL FILL_0_NORMAL
diff -urN oldtree/include/asm-sparc64/uaccess.h newtree/include/asm-sparc64/uaccess.h
--- oldtree/include/asm-sparc64/uaccess.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-sparc64/uaccess.h	2006-02-21 15:58:20.792985544 +0000
@@ -114,16 +114,6 @@
 default: __pu_ret = __put_user_bad(); break; \
 } __pu_ret; })
 
-#define __put_user_nocheck_ret(data,addr,size,retval) ({ \
-register int __foo __asm__ ("l1"); \
-switch (size) { \
-case 1: __put_user_asm_ret(data,b,addr,retval,__foo); break; \
-case 2: __put_user_asm_ret(data,h,addr,retval,__foo); break; \
-case 4: __put_user_asm_ret(data,w,addr,retval,__foo); break; \
-case 8: __put_user_asm_ret(data,x,addr,retval,__foo); break; \
-default: if (__put_user_bad()) return retval; break; \
-} })
-
 #define __put_user_asm(x,size,addr,ret)					\
 __asm__ __volatile__(							\
 	"/* Put user asm, inline. */\n"					\
@@ -143,33 +133,6 @@
        : "=r" (ret) : "r" (x), "r" (__m(addr)),				\
 	 "i" (-EFAULT))
 
-#define __put_user_asm_ret(x,size,addr,ret,foo)				\
-if (__builtin_constant_p(ret) && ret == -EFAULT)			\
-__asm__ __volatile__(							\
-	"/* Put user asm ret, inline. */\n"				\
-"1:\t"	"st"#size "a %1, [%2] %%asi\n\n\t"				\
-	".section __ex_table,#alloc\n\t"				\
-	".align	4\n\t"							\
-	".word	1b, __ret_efault\n\n\t"					\
-	".previous\n\n\t"						\
-       : "=r" (foo) : "r" (x), "r" (__m(addr)));			\
-else									\
-__asm__ __volatile__(							\
-	"/* Put user asm ret, inline. */\n"				\
-"1:\t"	"st"#size "a %1, [%2] %%asi\n\n\t"				\
-	".section .fixup,#alloc,#execinstr\n\t"				\
-	".align	4\n"							\
-"3:\n\t"								\
-	"ret\n\t"							\
-	" restore %%g0, %3, %%o0\n\n\t"					\
-	".previous\n\t"							\
-	".section __ex_table,#alloc\n\t"				\
-	".align	4\n\t"							\
-	".word	1b, 3b\n\n\t"						\
-	".previous\n\n\t"						\
-       : "=r" (foo) : "r" (x), "r" (__m(addr)),				\
-         "i" (ret))
-
 extern int __put_user_bad(void);
 
 #define __get_user_nocheck(data,addr,size,type) ({ \
@@ -289,14 +252,7 @@
 }
 #define __copy_in_user copy_in_user
 
-extern unsigned long __must_check __bzero_noasi(void __user *, unsigned long);
-
-static inline unsigned long __must_check
-__clear_user(void __user *addr, unsigned long size)
-{
-	
-	return __bzero_noasi(addr, size);
-}
+extern unsigned long __must_check __clear_user(void __user *, unsigned long);
 
 #define clear_user __clear_user
 
diff -urN oldtree/include/asm-sparc64/vdev.h newtree/include/asm-sparc64/vdev.h
--- oldtree/include/asm-sparc64/vdev.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/include/asm-sparc64/vdev.h	2006-02-21 15:58:20.792985544 +0000
@@ -0,0 +1,16 @@
+/* vdev.h: SUN4V virtual device interfaces and defines.
+ *
+ * Copyright (C) 2006 David S. Miller <davem@davemloft.net>
+ */
+
+#ifndef _SPARC64_VDEV_H
+#define _SPARC64_VDEV_H
+
+#include <linux/types.h>
+
+extern u32 sun4v_vdev_devhandle;
+extern int sun4v_vdev_root;
+
+extern unsigned int sun4v_vdev_device_interrupt(unsigned int);
+
+#endif /* !(_SPARC64_VDEV_H) */
diff -urN oldtree/include/asm-um/ptrace-generic.h newtree/include/asm-um/ptrace-generic.h
--- oldtree/include/asm-um/ptrace-generic.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-um/ptrace-generic.h	2006-02-21 15:58:36.787554000 +0000
@@ -28,7 +28,7 @@
 	union uml_pt_regs regs;
 };
 
-#define EMPTY_REGS { regs : EMPTY_UML_PT_REGS }
+#define EMPTY_REGS { .regs = EMPTY_UML_PT_REGS }
 
 #define PT_REGS_IP(r) UPT_IP(&(r)->regs)
 #define PT_REGS_SP(r) UPT_SP(&(r)->regs)
diff -urN oldtree/include/asm-um/thread_info.h newtree/include/asm-um/thread_info.h
--- oldtree/include/asm-um/thread_info.h	2006-02-19 11:41:05.741470264 +0000
+++ newtree/include/asm-um/thread_info.h	2006-02-21 15:58:36.795552784 +0000
@@ -27,14 +27,14 @@
 
 #define INIT_THREAD_INFO(tsk)			\
 {						\
-	task:		&tsk,			\
-	exec_domain:	&default_exec_domain,	\
-	flags:		0,			\
-	cpu:		0,			\
-	preempt_count:	1,			\
-	addr_limit:	KERNEL_DS,		\
-	restart_block:  {			\
-		fn:  do_no_restart_syscall,	\
+	.task =		&tsk,			\
+	.exec_domain =	&default_exec_domain,	\
+	.flags =		0,		\
+	.cpu =		0,			\
+	.preempt_count =	1,		\
+	.addr_limit =	KERNEL_DS,		\
+	.restart_block =  {			\
+		.fn =  do_no_restart_syscall,	\
 	},					\
 }
 
diff -urN oldtree/include/asm-um/uaccess.h newtree/include/asm-um/uaccess.h
--- oldtree/include/asm-um/uaccess.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-um/uaccess.h	2006-02-21 15:58:36.795552784 +0000
@@ -57,7 +57,7 @@
 ({ \
         const __typeof__((*(ptr))) __user *private_ptr = (ptr); \
         (access_ok(VERIFY_READ, private_ptr, sizeof(*private_ptr)) ? \
-	 __get_user(x, private_ptr) : ((x) = 0, -EFAULT)); \
+	 __get_user(x, private_ptr) : ((x) = (__typeof__(*ptr))0, -EFAULT)); \
 })
 
 #define __put_user(x, ptr) \
diff -urN oldtree/include/asm-v850/system.h newtree/include/asm-v850/system.h
--- oldtree/include/asm-v850/system.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-v850/system.h	2006-02-21 15:58:36.801551872 +0000
@@ -68,7 +68,7 @@
 #define rmb()			mb ()
 #define wmb()			mb ()
 #define read_barrier_depends()	((void)0)
-#define set_rmb(var, value)	do { xchg (&var, value); } while (0)
+#define set_rmb(var, value)	do { (void)xchg (&var, value); } while (0)
 #define set_mb(var, value)	set_rmb (var, value)
 #define set_wmb(var, value)	do { var = value; wmb (); } while (0)
 
diff -urN oldtree/include/asm-v850/uaccess.h newtree/include/asm-v850/uaccess.h
--- oldtree/include/asm-v850/uaccess.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-v850/uaccess.h	2006-02-21 15:58:36.801551872 +0000
@@ -59,18 +59,13 @@
 #define __get_user(var, ptr)						      \
   ({									      \
 	  int __gu_err = 0;						      \
-	  typeof(*(ptr)) __gu_val = 0;					      \
+	  typeof(*(ptr)) __gu_val = *ptr;				      \
 	  switch (sizeof (*(ptr))) {					      \
 	  case 1:							      \
 	  case 2:							      \
 	  case 4:							      \
-		  __gu_val = *(ptr);					      \
-		  break;						      \
-	  case 8:							      \
-		  memcpy(&__gu_val, ptr, sizeof(__gu_val));		      \
 		  break;						      \
 	  default:							      \
-		  __gu_val = 0;						      \
 		  __gu_err = __get_user_bad ();				      \
 		  break;						      \
 	  }								      \
diff -urN oldtree/include/asm-x86_64/acpi.h newtree/include/asm-x86_64/acpi.h
--- oldtree/include/asm-x86_64/acpi.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-x86_64/acpi.h	2006-02-21 15:58:10.462556008 +0000
@@ -162,6 +162,8 @@
 
 extern u8 x86_acpiid_to_apicid[];
 
+#define ARCH_HAS_POWER_INIT 1
+
 extern int acpi_skip_timer_override;
 
 #endif /*__KERNEL__*/
diff -urN oldtree/include/asm-x86_64/pci.h newtree/include/asm-x86_64/pci.h
--- oldtree/include/asm-x86_64/pci.h	2006-02-19 11:41:05.761467224 +0000
+++ newtree/include/asm-x86_64/pci.h	2006-02-21 15:58:17.916422848 +0000
@@ -6,6 +6,25 @@
 
 #ifdef __KERNEL__
 
+struct pci_sysdata {
+	int		domain;		/* PCI domain */
+	int		node;		/* NUMA node */
+};
+extern struct pci_sysdata pci_default_sysdata;
+
+#ifdef CONFIG_PCI_DOMAINS
+static inline int pci_domain_nr(struct pci_bus *bus)
+{
+	struct pci_sysdata *sd = bus->sysdata;
+	return sd->domain;
+}
+
+static inline int pci_proc_domain(struct pci_bus *bus)
+{
+	return pci_domain_nr(bus);
+}
+#endif /* CONFIG_PCI_DOMAINS */
+
 #include <linux/mm.h> /* for struct page */
 
 /* Can be used to override the logic in pci_scan_bus for skipping
diff -urN oldtree/include/asm-x86_64/serial.h newtree/include/asm-x86_64/serial.h
--- oldtree/include/asm-x86_64/serial.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/asm-x86_64/serial.h	2006-02-21 15:58:36.809550656 +0000
@@ -15,11 +15,11 @@
 
 /* Standard COM flags (except for COM4, because of the 8514 problem) */
 #ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
+#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ)
+#define STD_COM4_FLAGS (UPF_BOOT_AUTOCONF | UPF_AUTO_IRQ)
 #else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
+#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
+#define STD_COM4_FLAGS UPF_BOOT_AUTOCONF
 #endif
 
 #define SERIAL_PORT_DFNS			\
diff -urN oldtree/include/asm-x86_64/topology.h newtree/include/asm-x86_64/topology.h
--- oldtree/include/asm-x86_64/topology.h	2006-02-19 11:41:05.766466464 +0000
+++ newtree/include/asm-x86_64/topology.h	2006-02-21 15:58:17.891426648 +0000
@@ -25,7 +25,7 @@
 #define parent_node(node)		(node)
 #define node_to_first_cpu(node) 	(first_cpu(node_to_cpumask[node]))
 #define node_to_cpumask(node)		(node_to_cpumask[node])
-#define pcibus_to_node(bus)		((long)(bus->sysdata))	
+#define pcibus_to_node(bus)	((struct pci_sysdata *)((bus)->sysdata))->node
 #define pcibus_to_cpumask(bus)		node_to_cpumask(pcibus_to_node(bus));
 
 #define numa_node_id()			read_pda(nodenumber)
diff -urN oldtree/include/linux/acpi.h newtree/include/linux/acpi.h
--- oldtree/include/linux/acpi.h	2006-02-19 11:41:05.772465552 +0000
+++ newtree/include/linux/acpi.h	2006-02-21 15:58:08.779811824 +0000
@@ -427,7 +427,8 @@
 extern struct acpi_table_mcfg_config *pci_mmcfg_config;
 extern int pci_mmcfg_config_num;
 
-extern int sbf_port ;
+extern int sbf_port;
+extern unsigned long acpi_video_flags;
 
 #else	/* !CONFIG_ACPI */
 
diff -urN oldtree/include/linux/amigasfs.h newtree/include/linux/amigasfs.h
--- oldtree/include/linux/amigasfs.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/include/linux/amigasfs.h	2006-02-21 15:58:33.161105304 +0000
@@ -0,0 +1,276 @@
+#ifndef __LINUX_AMIGASFS_H
+#define __LINUX_AMIGASFS_H
+
+#include <linux/types.h>
+
+/* some helper macros... */
+#define ASFS_MAKE_ID(a,b,c,d) (((a)&0xff)<<24|((b)&0xff)<<16|((c)&0xff)<<8|((d)&0xff))
+
+/* Amiga SFS block IDs */
+#define ASFS_ROOTID                 ASFS_MAKE_ID('S','F','S','\0')
+#define ASFS_OBJECTCONTAINER_ID     ASFS_MAKE_ID('O','B','J','C')
+#define ASFS_BNODECONTAINER_ID      ASFS_MAKE_ID('B','N','D','C')
+#define ASFS_NODECONTAINER_ID       ASFS_MAKE_ID('N','D','C',' ')
+#define ASFS_HASHTABLE_ID           ASFS_MAKE_ID('H','T','A','B')
+#define ASFS_SOFTLINK_ID            ASFS_MAKE_ID('S','L','N','K')
+#define ASFS_ADMINSPACECONTAINER_ID ASFS_MAKE_ID('A','D','M','C')
+#define ASFS_BITMAP_ID              ASFS_MAKE_ID('B','T','M','P')
+#define ASFS_TRANSACTIONFAILURE_ID  ASFS_MAKE_ID('T','R','F','A')
+
+/* Amiga SFS defines and magic values */
+
+#define ASFS_MAGIC 0xa0ff
+#define ASFS_MAXFN (105u)
+#define ASFS_MAXFILESIZE 0x8FFFFFFE
+
+#define ASFS_STRUCTURE_VERISON (3)
+#define ASFS_BLCKFACCURACY	(5)
+
+#define ASFS_ROOTBITS_CASESENSITIVE (128)
+#define ASFS_READONLY (512)
+#define ASFS_VOL_LOWERCASE (1024)
+
+#define ASFS_ROOTNODE   (1)
+#define ASFS_RECYCLEDNODE (2)
+
+#define OTYPE_HIDDEN      (1)
+#define OTYPE_HARDLINK    (32)
+#define OTYPE_LINK        (64)
+#define OTYPE_DIR         (128)
+
+#define MSB_MASK (1ul << 31)
+
+#define NODE_STRUCT_SIZE (10)	/* (sizeof(struct fsObjectNode)) */
+#define NODECONT_BLOCK_COUNT ((sb->s_blocksize - sizeof(struct fsNodeContainer)) / sizeof(u32))
+
+#define ASFS_ALWAYSFREE (16)		/* keep this amount of blocks free */
+
+#define ASFS_BLOCKCHUNKS (16)		/* try to allocate this number of blocks in one request */
+
+#ifndef TRUE
+#define TRUE		1
+#endif
+#ifndef FALSE
+#define FALSE		0
+#endif
+
+/* amigados protection bits */
+
+#define FIBB_SCRIPT    6	/* program is a script (execute) file */
+#define FIBB_PURE      5	/* program is reentrant and rexecutable */
+#define FIBB_ARCHIVE   4	/* cleared whenever file is changed */
+#define FIBB_READ      3	/* ignored by old filesystem */
+#define FIBB_WRITE     2	/* ignored by old filesystem */
+#define FIBB_EXECUTE   1	/* ignored by system, used by Shell */
+#define FIBB_DELETE    0	/* prevent file from being deleted */
+
+#define FIBF_SCRIPT    (1<<FIBB_SCRIPT)
+#define FIBF_PURE      (1<<FIBB_PURE)
+#define FIBF_ARCHIVE   (1<<FIBB_ARCHIVE)
+#define FIBF_READ      (1<<FIBB_READ)
+#define FIBF_WRITE     (1<<FIBB_WRITE)
+#define FIBF_EXECUTE   (1<<FIBB_EXECUTE)
+#define FIBF_DELETE    (1<<FIBB_DELETE)
+
+/* name hashing macro */
+
+#define HASHCHAIN(x) (u16)(x % (u16)(((sb->s_blocksize) - sizeof(struct fsHashTable))>>2))
+
+/* Each block has its own header with checksum and id, its called fsBlockHeader */
+
+struct fsBlockHeader {
+	u32 id;			/* 4 character id string of this block */
+	u32 checksum;		/* The checksum */
+	u32 ownblock;		/* The blocknumber of the block this block is stored at */
+};
+
+/* On-disk "super block", called fsRootBlock */
+
+struct fsRootBlock {
+	struct fsBlockHeader bheader;
+
+	u16 version;		/* Version number of the filesystem block structure */
+	u16 sequencenumber;	/* The Root with the highest sequencenumber is valid */
+
+	u32 datecreated;	/* Creation date (when first formatted).  Cannot be changed. */
+	u8 bits;		/* various settings, see defines below. */
+	u8 pad1;
+	u16 pad2;
+
+	u32 reserved1[2];
+
+	u32 firstbyteh;		/* The first byte of our partition from the start of the */
+	u32 firstbyte;		/* disk.  firstbyteh = upper 32 bits, firstbyte = lower 32 bits. */
+
+	u32 lastbyteh;		/* The last byte of our partition, excluding this one. */
+	u32 lastbyte;
+
+	u32 totalblocks;	/* size of this partition in blocks */
+	u32 blocksize;		/* blocksize used */
+
+	u32 reserved2[2];
+	u32 reserved3[8];
+
+	u32 bitmapbase;		/* location of the bitmap */
+	u32 adminspacecontainer;	/* location of first adminspace container */
+	u32 rootobjectcontainer;	/* location of the root objectcontainer */
+	u32 extentbnoderoot;	/* location of the root of the extentbnode B-tree */
+	u32 objectnoderoot;	/* location of the root of the objectnode tree */
+
+	u32 reserved4[3];
+};
+
+/* On disk inode, called fsObject */
+
+struct fsObject {
+	u16 owneruid;
+	u16 ownergid;
+	u32 objectnode;
+	u32 protection;
+
+	union {
+		struct {
+			u32 data;
+			u32 size;
+		} file;
+
+		struct {
+			u32 hashtable;	/* for directories & root, 0 means no hashblock */
+			u32 firstdirblock;
+		} dir;
+	} object;
+
+	u32 datemodified;
+	u8 bits;
+
+	u8 name[0];
+	u8 comment[0];
+};
+
+/* On disk block containging a number of fsObjects */
+
+struct fsObjectContainer {
+	struct fsBlockHeader bheader;
+
+	u32 parent;
+	u32 next;
+	u32 previous;		/* 0 for the first block in the directory chain */
+
+	struct fsObject object[0];
+};
+
+/* BTree structures, used to collect file data position on disk */
+
+struct fsExtentBNode {
+	u32 key;		/* data! */
+	u32 next;
+	u32 prev;
+	u16 blocks;		/* The size in blocks of the region this Extent controls */
+};
+
+struct BNode {
+	u32 key;
+	u32 data;
+};
+
+struct BTreeContainer {
+	u16 nodecount;
+	u8 isleaf;
+	u8 nodesize;		/* Must be a multiple of 2 */
+
+	struct BNode bnode[0];
+};
+
+/* On disk block with BTreeContainer */
+
+struct fsBNodeContainer {
+	struct fsBlockHeader bheader;
+	struct BTreeContainer btc;
+};
+
+/* On disk block  with soft link data */
+
+struct fsSoftLink {
+	struct fsBlockHeader bheader;
+	u32 parent;
+	u32 next;
+	u32 previous;
+	u8 string[0];
+};
+
+/* On disk block with hashtable data */
+
+struct fsHashTable {
+	struct fsBlockHeader bheader;
+	u32 parent;
+	u32 hashentry[0];
+};
+
+/* On disk block with node index and some helper structures */
+
+struct fsNodeContainer {
+	struct fsBlockHeader bheader;
+	u32 nodenumber;
+	u32 nodes;
+	u32 node[0];
+};
+
+struct fsNode {
+	u32 data;
+};
+
+struct fsObjectNode {
+	struct fsNode node;
+	u32 next;
+	u16 hash16;
+} __attribute__ ((packed));
+
+/* Some adminspace and bitmap block structures */
+
+struct fsAdminSpace {
+	u32 space;
+	u32 bits;
+/* Set bits are used blocks, bit 31 is	the first block in the AdminSpace. */
+};
+
+struct fsAdminSpaceContainer {
+	struct fsBlockHeader bheader;
+
+	u32 next;
+	u32 previous;
+
+	u8 bits;
+	u8 pad1;
+	u16 pad2;
+
+	struct fsAdminSpace adminspace[0];
+};
+
+struct fsBitmap {
+	struct fsBlockHeader bheader;
+
+	u32 bitmap[0];
+
+/* Bits are 1 if the block is free, and 0 if full.
+   Bitmap must consist of an integral number of longwords. */
+};
+
+/* The fsRootInfo structure has all kinds of information about the format
+   of the disk. */
+
+struct fsRootInfo {
+	u32 deletedblocks;	/* Amount in blocks which deleted files consume. */
+	u32 deletedfiles;	/* Number of deleted files in recycled. */
+	u32 freeblocks;		/* Cached number of free blocks on disk. */
+
+	u32 datecreated;
+
+	u32 lastallocatedblock;	/* Block which was most recently allocated */
+	u32 lastallocatedadminspace;	/* AdminSpaceContainer which most recently was used to allocate a block */
+	u32 lastallocatedextentnode;	/* ExtentNode which was most recently created */
+	u32 lastallocatedobjectnode;	/* ObjectNode which was most recently created */
+
+	u32 rovingpointer;
+};
+
+#endif
diff -urN oldtree/include/linux/arcdevice.h newtree/include/linux/arcdevice.h
--- oldtree/include/linux/arcdevice.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/arcdevice.h	2006-02-21 15:58:15.694760592 +0000
@@ -206,7 +206,6 @@
 
 extern struct ArcProto *arc_proto_map[256], *arc_proto_default,
 	*arc_bcast_proto, *arc_raw_proto;
-extern struct ArcProto arc_proto_null;
 
 
 /*
@@ -334,17 +333,9 @@
 #define arcnet_dump_skb(dev,skb,desc) ;
 #endif
 
-#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX)
-void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc,
-			int take_arcnet_lock);
-#else
-#define arcnet_dump_packet(dev, bufnum, desc,take_arcnet_lock) ;
-#endif
-
 void arcnet_unregister_proto(struct ArcProto *proto);
 irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 struct net_device *alloc_arcdev(char *name);
-void arcnet_rx(struct net_device *dev, int bufnum);
 
 #endif				/* __KERNEL__ */
 #endif				/* _LINUX_ARCDEVICE_H */
diff -urN oldtree/include/linux/atalk.h newtree/include/linux/atalk.h
--- oldtree/include/linux/atalk.h	2006-02-19 11:41:05.776464944 +0000
+++ newtree/include/linux/atalk.h	2006-02-21 15:58:36.817549440 +0000
@@ -88,15 +88,7 @@
 #include <asm/byteorder.h>
 
 struct ddpehdr {
-#ifdef __LITTLE_ENDIAN_BITFIELD
-	__u16	deh_len:10,
-		deh_hops:4,
-		deh_pad:2;
-#else
-	__u16	deh_pad:2,
-		deh_hops:4,
-		deh_len:10;
-#endif
+	__be16	deh_len_hops;	/* lower 10 bits are length, next 4 - hops */
 	__be16	deh_sum;
 	__be16	deh_dnet;
 	__be16	deh_snet;
@@ -112,36 +104,6 @@
 	return (struct ddpehdr *)skb->h.raw;
 }
 
-/*
- *	Don't drop the struct into the struct above.  You'll get some
- *	surprise padding.
- */
-struct ddpebits {
-#ifdef __LITTLE_ENDIAN_BITFIELD
-	__u16	deh_len:10,
-		deh_hops:4,
-		deh_pad:2;
-#else
-	__u16	deh_pad:2,
-		deh_hops:4,
-		deh_len:10;
-#endif
-};
-
-/* Short form header */
-struct ddpshdr {
-#ifdef __LITTLE_ENDIAN_BITFIELD
-	__u16	dsh_len:10,
-		dsh_pad:6;
-#else
-	__u16	dsh_pad:6,
-		dsh_len:10;
-#endif
-	__u8	dsh_dport;
-	__u8	dsh_sport;
-	/* And netatalk apps expect to stick the type in themselves */
-};
-
 /* AppleTalk AARP headers */
 struct elapaarp {
 	__be16	hw_type;
diff -urN oldtree/include/linux/audit.h newtree/include/linux/audit.h
--- oldtree/include/linux/audit.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/audit.h	2006-02-21 15:58:11.770357192 +0000
@@ -33,27 +33,41 @@
  * 1200 - 1299 messages internal to the audit daemon
  * 1300 - 1399 audit event messages
  * 1400 - 1499 SE Linux use
- * 1500 - 1999 future use
- * 2000 is for otherwise unclassified kernel audit messages
+ * 1500 - 1599 kernel LSPP events
+ * 1600 - 1699 kernel crypto events
+ * 1700 - 1999 future kernel use (maybe integrity labels and related events)
+ * 2000 is for otherwise unclassified kernel audit messages (legacy)
+ * 2001 - 2099 unused (kernel)
+ * 2100 - 2199 user space anomaly records
+ * 2200 - 2299 user space actions taken in response to anomalies
+ * 2300 - 2399 user space generated LSPP events
+ * 2400 - 2499 user space crypto events
+ * 2500 - 2999 future user space (maybe integrity labels and related events)
  *
- * Messages from 1000-1199 are bi-directional. 1200-1299 are exclusively user
- * space. Anything over that is kernel --> user space communication.
+ * Messages from 1000-1199 are bi-directional. 1200-1299 & 2100 - 2999 are
+ * exclusively user space. 1300-2099 is kernel --> user space 
+ * communication.
  */
 #define AUDIT_GET		1000	/* Get status */
 #define AUDIT_SET		1001	/* Set status (enable/disable/auditd) */
-#define AUDIT_LIST		1002	/* List syscall filtering rules */
-#define AUDIT_ADD		1003	/* Add syscall filtering rule */
-#define AUDIT_DEL		1004	/* Delete syscall filtering rule */
+#define AUDIT_LIST		1002	/* List syscall rules -- deprecated */
+#define AUDIT_ADD		1003	/* Add syscall rule -- deprecated */
+#define AUDIT_DEL		1004	/* Delete syscall rule -- deprecated */
 #define AUDIT_USER		1005	/* Message from userspace -- deprecated */
 #define AUDIT_LOGIN		1006	/* Define the login id and information */
 #define AUDIT_WATCH_INS		1007	/* Insert file/dir watch entry */
 #define AUDIT_WATCH_REM		1008	/* Remove file/dir watch entry */
 #define AUDIT_WATCH_LIST	1009	/* List all file/dir watches */
 #define AUDIT_SIGNAL_INFO	1010	/* Get info about sender of signal to auditd */
+#define AUDIT_ADD_RULE		1011	/* Add syscall filtering rule */
+#define AUDIT_DEL_RULE		1012	/* Delete syscall filtering rule */
+#define AUDIT_LIST_RULES	1013	/* List syscall filtering rules */
 
 #define AUDIT_FIRST_USER_MSG	1100	/* Userspace messages mostly uninteresting to kernel */
 #define AUDIT_USER_AVC		1107	/* We filter this differently */
 #define AUDIT_LAST_USER_MSG	1199
+#define AUDIT_FIRST_USER_MSG2	2100	/* More user space messages */
+#define AUDIT_LAST_USER_MSG2	2999
  
 #define AUDIT_DAEMON_START      1200    /* Daemon startup record */
 #define AUDIT_DAEMON_END        1201    /* Daemon normal stop record */
@@ -72,6 +86,9 @@
 #define AUDIT_AVC		1400	/* SE Linux avc denial or grant */
 #define AUDIT_SELINUX_ERR	1401	/* Internal SE Linux Errors */
 #define AUDIT_AVC_PATH		1402	/* dentry, vfsmount pair from avc */
+#define AUDIT_MAC_POLICY_LOAD	1403	/* Policy file load */
+#define AUDIT_MAC_STATUS	1404	/* Changed enforcing,permissive,off */
+#define AUDIT_MAC_CONFIG_CHANGE	1405	/* Changes to booleans */
 
 #define AUDIT_KERNEL		2000	/* Asynchronous audit record. NOT A REQUEST. */
 
@@ -81,8 +98,9 @@
 #define AUDIT_FILTER_ENTRY	0x02	/* Apply rule at syscall entry */
 #define AUDIT_FILTER_WATCH	0x03	/* Apply rule to file system watches */
 #define AUDIT_FILTER_EXIT	0x04	/* Apply rule at syscall exit */
+#define AUDIT_FILTER_TYPE	0x05	/* Apply rule at audit_log_start */
 
-#define AUDIT_NR_FILTERS	5
+#define AUDIT_NR_FILTERS	6
 
 #define AUDIT_FILTER_PREPEND	0x10	/* Prepend to front of list */
 
@@ -98,6 +116,13 @@
 #define AUDIT_WORD(nr) ((__u32)((nr)/32))
 #define AUDIT_BIT(nr)  (1 << ((nr) - AUDIT_WORD(nr)*32))
 
+/* This bitmask is used to validate user input.  It represents all bits that
+ * are currently used in an audit field constant understood by the kernel.
+ * If you are adding a new #define AUDIT_<whatever>, please ensure that
+ * AUDIT_UNUSED_BITS is updated if need be. */
+#define AUDIT_UNUSED_BITS	0x0FFFFC00
+
+
 /* Rule fields */
 				/* These are useful when checking the
 				 * task structure at task creation time
@@ -114,6 +139,7 @@
 #define AUDIT_LOGINUID	9
 #define AUDIT_PERS	10
 #define AUDIT_ARCH	11
+#define AUDIT_MSGTYPE	12
 
 				/* These are ONLY useful when checking
 				 * at syscall exit time (AUDIT_AT_EXIT). */
@@ -122,14 +148,35 @@
 #define AUDIT_INODE	102
 #define AUDIT_EXIT	103
 #define AUDIT_SUCCESS   104	/* exit >= 0; value ignored */
+#define AUDIT_WATCH	105
 
 #define AUDIT_ARG0      200
 #define AUDIT_ARG1      (AUDIT_ARG0+1)
 #define AUDIT_ARG2      (AUDIT_ARG0+2)
 #define AUDIT_ARG3      (AUDIT_ARG0+3)
 
-#define AUDIT_NEGATE    0x80000000
+#define AUDIT_NEGATE			0x80000000
 
+/* These are the supported operators.
+ *	4  2  1
+ *	=  >  <
+ *	-------
+ *	0  0  0		0	nonsense
+ *	0  0  1		1	<
+ *	0  1  0		2	>
+ *	0  1  1		3	!=
+ *	1  0  0		4	=
+ *	1  0  1		5	<=
+ *	1  1  0		6	>=
+ *	1  1  1		7	all operators
+ */
+#define AUDIT_LESS_THAN			0x10000000
+#define AUDIT_GREATER_THAN		0x20000000
+#define AUDIT_NOT_EQUAL			0x30000000
+#define AUDIT_EQUAL			0x40000000
+#define AUDIT_LESS_THAN_OR_EQUAL	(AUDIT_LESS_THAN|AUDIT_EQUAL)
+#define AUDIT_GREATER_THAN_OR_EQUAL	(AUDIT_GREATER_THAN|AUDIT_EQUAL)
+#define AUDIT_OPERATORS			(AUDIT_EQUAL|AUDIT_NOT_EQUAL)
 
 /* Status symbols */
 				/* Mask values */
@@ -186,6 +233,26 @@
 	__u32		backlog;	/* messages waiting in queue */
 };
 
+/* audit_rule_data supports filter rules with both integer and string
+ * fields.  It corresponds with AUDIT_ADD_RULE, AUDIT_DEL_RULE and
+ * AUDIT_LIST_RULES requests.
+ */
+struct audit_rule_data {
+	__u32		flags;	/* AUDIT_PER_{TASK,CALL}, AUDIT_PREPEND */
+	__u32		action;	/* AUDIT_NEVER, AUDIT_POSSIBLE, AUDIT_ALWAYS */
+	__u32		field_count;
+	__u32		mask[AUDIT_BITMASK_SIZE]; /* syscall(s) affected */
+	__u32		fields[AUDIT_MAX_FIELDS];
+	__u32		values[AUDIT_MAX_FIELDS];
+	__u32		fieldflags[AUDIT_MAX_FIELDS];
+	__u32		buflen;	/* total length of string fields */
+	char		buf[0];	/* string fields buffer */
+};
+
+/* audit_rule is supported to maintain backward compatibility with
+ * userspace.  It supports integer fields only and corresponds to
+ * AUDIT_ADD, AUDIT_DEL and AUDIT_LIST requests.
+ */
 struct audit_rule {		/* for AUDIT_LIST, AUDIT_ADD, and AUDIT_DEL */
 	__u32		flags;	/* AUDIT_PER_{TASK,CALL}, AUDIT_PREPEND */
 	__u32		action;	/* AUDIT_NEVER, AUDIT_POSSIBLE, AUDIT_ALWAYS */
@@ -222,22 +289,34 @@
 extern void audit_syscall_exit(struct task_struct *task, int failed, long return_code);
 extern void audit_getname(const char *name);
 extern void audit_putname(const char *name);
-extern void audit_inode(const char *name, const struct inode *inode, unsigned flags);
+extern void __audit_inode(const char *name, const struct inode *inode, unsigned flags);
+extern void __audit_inode_child(const char *dname, const struct inode *inode,
+				unsigned long pino);
+static inline void audit_inode(const char *name, const struct inode *inode,
+			       unsigned flags) {
+	if (unlikely(current->audit_context))
+		__audit_inode(name, inode, flags);
+}
+static inline void audit_inode_child(const char *dname, 
+				     const struct inode *inode, 
+				     unsigned long pino) {
+	if (unlikely(current->audit_context))
+		__audit_inode_child(dname, inode, pino);
+}
 
 				/* Private API (for audit.c only) */
-extern int  audit_receive_filter(int type, int pid, int uid, int seq,
-				 void *data, uid_t loginuid);
 extern unsigned int audit_serial(void);
 extern void auditsc_get_stamp(struct audit_context *ctx,
 			      struct timespec *t, unsigned int *serial);
 extern int  audit_set_loginuid(struct task_struct *task, uid_t loginuid);
 extern uid_t audit_get_loginuid(struct audit_context *ctx);
-extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
+extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp);
 extern int audit_socketcall(int nargs, unsigned long *args);
 extern int audit_sockaddr(int len, void *addr);
 extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt);
 extern void audit_signal_info(int sig, struct task_struct *t);
-extern int audit_filter_user(struct netlink_skb_parms *cb, int type);
+extern char *audit_ipc_context(struct kern_ipc_perm *ipcp);
+extern int audit_set_macxattr(const char *name);
 #else
 #define audit_alloc(t) ({ 0; })
 #define audit_free(t) do { ; } while (0)
@@ -245,16 +324,19 @@
 #define audit_syscall_exit(t,f,r) do { ; } while (0)
 #define audit_getname(n) do { ; } while (0)
 #define audit_putname(n) do { ; } while (0)
+#define __audit_inode(n,i,f) do { ; } while (0)
+#define __audit_inode_child(d,i,p) do { ; } while (0)
 #define audit_inode(n,i,f) do { ; } while (0)
-#define audit_receive_filter(t,p,u,s,d,l) ({ -EOPNOTSUPP; })
+#define audit_inode_child(d,i,p) do { ; } while (0)
 #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0)
 #define audit_get_loginuid(c) ({ -1; })
-#define audit_ipc_perms(q,u,g,m) ({ 0; })
+#define audit_ipc_perms(q,u,g,m,i) ({ 0; })
 #define audit_socketcall(n,a) ({ 0; })
 #define audit_sockaddr(len, addr) ({ 0; })
 #define audit_avc_path(dentry, mnt) ({ 0; })
 #define audit_signal_info(s,t) do { ; } while (0)
-#define audit_filter_user(cb,t) ({ 1; })
+#define audit_ipc_context(i) do { ; } while (0)
+#define audit_set_macxattr(n) do { ; } while (0)
 #endif
 
 #ifdef CONFIG_AUDIT
@@ -278,12 +360,11 @@
 					     const char *prefix,
 					     struct dentry *dentry,
 					     struct vfsmount *vfsmnt);
-				/* Private API (for auditsc.c only) */
-extern void		    audit_send_reply(int pid, int seq, int type,
-					     int done, int multi,
-					     void *payload, int size);
-extern void		    audit_log_lost(const char *message);
-extern struct semaphore audit_netlink_sem;
+				/* Private API (for audit.c only) */
+extern int audit_filter_user(struct netlink_skb_parms *cb, int type);
+extern int audit_filter_type(int type);
+extern int  audit_receive_filter(int type, int pid, int uid, int seq,
+				 void *data, size_t datasz, uid_t loginuid);
 #else
 #define audit_log(c,g,t,f,...) do { ; } while (0)
 #define audit_log_start(c,g,t) ({ NULL; })
@@ -293,6 +374,7 @@
 #define audit_log_hex(a,b,l) do { ; } while (0)
 #define audit_log_untrustedstring(a,s) do { ; } while (0)
 #define audit_log_d_path(b,p,d,v) do { ; } while (0)
+#define audit_panic(m) do { ; } while (0)
 #endif
 #endif
 #endif
diff -urN oldtree/include/linux/bitmap.h newtree/include/linux/bitmap.h
--- oldtree/include/linux/bitmap.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/bitmap.h	2006-02-21 15:58:29.250699776 +0000
@@ -46,6 +46,9 @@
  * bitmap_parse(ubuf, ulen, dst, nbits)		Parse bitmap dst from user buf
  * bitmap_scnlistprintf(buf, len, src, nbits)	Print bitmap src as list to buf
  * bitmap_parselist(buf, dst, nbits)		Parse bitmap dst from list
+ * bitmap_find_free_region(bitmap, bits, order)	Find and allocate bit region
+ * bitmap_release_region(bitmap, pos, order)	Free specified bit region
+ * bitmap_allocate_region(bitmap, pos, order)	Allocate specified bit region
  */
 
 /*
diff -urN oldtree/include/linux/blkdev.h newtree/include/linux/blkdev.h
--- oldtree/include/linux/blkdev.h	2006-02-19 11:41:05.779464488 +0000
+++ newtree/include/linux/blkdev.h	2006-02-21 15:58:12.022318888 +0000
@@ -22,6 +22,7 @@
 struct elevator_queue;
 typedef struct elevator_queue elevator_t;
 struct request_pm_state;
+struct blk_trace;
 
 #define BLKDEV_MIN_RQ	4
 #define BLKDEV_MAX_RQ	128	/* Default maximum */
@@ -54,23 +55,27 @@
 
 struct cfq_queue;
 struct cfq_io_context {
-	/*
-	 * circular list of cfq_io_contexts belonging to a process io context
-	 */
-	struct list_head list;
-	struct cfq_queue *cfqq;
+	struct rb_node rb_node;
 	void *key;
 
+	struct cfq_queue *cfqq;
+
 	struct io_context *ioc;
 
 	unsigned long last_end_request;
-	unsigned long last_queue;
+	sector_t last_request_pos;
+ 	unsigned long last_queue;
+
 	unsigned long ttime_total;
 	unsigned long ttime_samples;
 	unsigned long ttime_mean;
 
-	void (*dtor)(struct cfq_io_context *);
-	void (*exit)(struct cfq_io_context *);
+	unsigned int seek_samples;
+	u64 seek_total;
+	sector_t seek_mean;
+
+	void (*dtor)(struct io_context *); /* destructor */
+	void (*exit)(struct io_context *); /* called on task exit */
 };
 
 /*
@@ -91,7 +96,7 @@
 	int nr_batch_requests;     /* Number of requests left in the batch */
 
 	struct as_io_context *aic;
-	struct cfq_io_context *cic;
+	struct rb_root cic_root;
 };
 
 void put_io_context(struct io_context *ioc);
@@ -416,6 +421,8 @@
 	unsigned int		sg_reserved_size;
 	int			node;
 
+	struct blk_trace	*blk_trace;
+
 	/*
 	 * reserved for flush operations
 	 */
diff -urN oldtree/include/linux/blktrace_api.h newtree/include/linux/blktrace_api.h
--- oldtree/include/linux/blktrace_api.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/include/linux/blktrace_api.h	2006-02-21 15:58:11.952329528 +0000
@@ -0,0 +1,283 @@
+#ifndef BLKTRACE_H
+#define BLKTRACE_H
+
+#include <linux/config.h>
+#include <linux/blkdev.h>
+#include <linux/relayfs_fs.h>
+
+/*
+ * Trace categories
+ */
+enum blktrace_cat {
+	BLK_TC_READ	= 1 << 0,	/* reads */
+	BLK_TC_WRITE	= 1 << 1,	/* writes */
+	BLK_TC_BARRIER	= 1 << 2,	/* barrier */
+	BLK_TC_SYNC	= 1 << 3,	/* barrier */
+	BLK_TC_QUEUE	= 1 << 4,	/* queueing/merging */
+	BLK_TC_REQUEUE	= 1 << 5,	/* requeueing */
+	BLK_TC_ISSUE	= 1 << 6,	/* issue */
+	BLK_TC_COMPLETE	= 1 << 7,	/* completions */
+	BLK_TC_FS	= 1 << 8,	/* fs requests */
+	BLK_TC_PC	= 1 << 9,	/* pc requests */
+	BLK_TC_NOTIFY	= 1 << 10,	/* special message */
+
+	BLK_TC_END	= 1 << 15,	/* only 16-bits, reminder */
+};
+
+#define BLK_TC_SHIFT		(16)
+#define BLK_TC_ACT(act)		((act) << BLK_TC_SHIFT)
+
+/*
+ * Basic trace actions
+ */
+enum blktrace_act {
+	__BLK_TA_QUEUE = 1,		/* queued */
+	__BLK_TA_BACKMERGE,		/* back merged to existing rq */
+	__BLK_TA_FRONTMERGE,		/* front merge to existing rq */
+	__BLK_TA_GETRQ,			/* allocated new request */
+	__BLK_TA_SLEEPRQ,		/* sleeping on rq allocation */
+	__BLK_TA_REQUEUE,		/* request requeued */
+	__BLK_TA_ISSUE,			/* sent to driver */
+	__BLK_TA_COMPLETE,		/* completed by driver */
+	__BLK_TA_PLUG,			/* queue was plugged */
+	__BLK_TA_UNPLUG_IO,		/* queue was unplugged by io */
+	__BLK_TA_UNPLUG_TIMER,		/* queue was unplugged by timer */
+	__BLK_TA_INSERT,		/* insert request */
+	__BLK_TA_SPLIT,			/* bio was split */
+	__BLK_TA_BOUNCE,		/* bio was bounced */
+	__BLK_TA_REMAP,			/* bio was remapped */
+};
+
+/*
+ * Trace actions in full. Additionally, read or write is masked
+ */
+#define BLK_TA_QUEUE		(__BLK_TA_QUEUE | BLK_TC_ACT(BLK_TC_QUEUE))
+#define BLK_TA_BACKMERGE	(__BLK_TA_BACKMERGE | BLK_TC_ACT(BLK_TC_QUEUE))
+#define BLK_TA_FRONTMERGE	(__BLK_TA_FRONTMERGE | BLK_TC_ACT(BLK_TC_QUEUE))
+#define	BLK_TA_GETRQ		(__BLK_TA_GETRQ | BLK_TC_ACT(BLK_TC_QUEUE))
+#define	BLK_TA_SLEEPRQ		(__BLK_TA_SLEEPRQ | BLK_TC_ACT(BLK_TC_QUEUE))
+#define	BLK_TA_REQUEUE		(__BLK_TA_REQUEUE | BLK_TC_ACT(BLK_TC_REQUEUE))
+#define BLK_TA_ISSUE		(__BLK_TA_ISSUE | BLK_TC_ACT(BLK_TC_ISSUE))
+#define BLK_TA_COMPLETE		(__BLK_TA_COMPLETE| BLK_TC_ACT(BLK_TC_COMPLETE))
+#define BLK_TA_PLUG		(__BLK_TA_PLUG | BLK_TC_ACT(BLK_TC_QUEUE))
+#define BLK_TA_UNPLUG_IO	(__BLK_TA_UNPLUG_IO | BLK_TC_ACT(BLK_TC_QUEUE))
+#define BLK_TA_UNPLUG_TIMER	(__BLK_TA_UNPLUG_TIMER | BLK_TC_ACT(BLK_TC_QUEUE))
+#define BLK_TA_INSERT		(__BLK_TA_INSERT | BLK_TC_ACT(BLK_TC_QUEUE))
+#define BLK_TA_SPLIT		(__BLK_TA_SPLIT)
+#define BLK_TA_BOUNCE		(__BLK_TA_BOUNCE)
+#define BLK_TA_REMAP		(__BLK_TA_REMAP | BLK_TC_ACT(BLK_TC_QUEUE))
+
+#define BLK_IO_TRACE_MAGIC	0x65617400
+#define BLK_IO_TRACE_VERSION	0x07
+
+/*
+ * The trace itself
+ */
+struct blk_io_trace {
+	u32 magic;		/* MAGIC << 8 | version */
+	u32 sequence;		/* event number */
+	u64 time;		/* in microseconds */
+	u64 sector;		/* disk offset */
+	u32 bytes;		/* transfer length */
+	u32 action;		/* what happened */
+	u32 pid;		/* who did it */
+	u32 device;		/* device number */
+	u32 cpu;		/* on what cpu did it happen */
+	u16 error;		/* completion error */
+	u16 pdu_len;		/* length of data after this trace */
+};
+
+/*
+ * The remap event
+ */
+struct blk_io_trace_remap {
+	u32 device;
+	u32 __pad;
+	u64 sector;
+};
+
+enum {
+	Blktrace_setup = 1,
+	Blktrace_running,
+	Blktrace_stopped,
+};
+
+struct rchan_ctrl
+{
+	struct dentry	*padding[NR_CPUS];
+};
+
+struct blk_trace {
+	int trace_state;
+	struct rchan *rchan;
+	unsigned long *sequence;
+	u16 act_mask;
+	u64 start_lba;
+	u64 end_lba;
+	u32 pid;
+	u32 dev;
+	struct dentry *dir;
+	struct dentry *dropped_file;
+	atomic_t dropped;
+	struct rchan_ctrl *ctrl;
+};
+
+/*
+ * User setup structure passed with BLKTRACESTART
+ */
+struct blk_user_trace_setup {
+	char name[BDEVNAME_SIZE];	/* output */
+	u16 act_mask;			/* input */
+	u32 buf_size;			/* input */
+	u32 buf_nr;			/* input */
+	u64 start_lba;
+	u64 end_lba;
+	u32 pid;
+};
+
+#if defined(CONFIG_BLK_DEV_IO_TRACE)
+extern int blk_trace_ioctl(struct block_device *, unsigned, char __user *);
+extern void blk_trace_shutdown(request_queue_t *);
+extern void __blk_add_trace(struct blk_trace *, sector_t, int, int, u32, int, int, void *);
+
+/**
+ * blk_add_trace_rq - Add a trace for a request oriented action
+ * @q:		queue the io is for
+ * @rq:		the source request
+ * @what:	the action
+ *
+ * Description:
+ *     Records an action against a request. Will log the bio offset + size.
+ *
+ **/
+static inline void blk_add_trace_rq(struct request_queue *q, struct request *rq,
+				    u32 what)
+{
+	struct blk_trace *bt = q->blk_trace;
+	int rw = rq->flags & 0x07;
+
+	if (likely(!bt))
+		return;
+
+	if (blk_pc_request(rq)) {
+		what |= BLK_TC_ACT(BLK_TC_PC);
+		__blk_add_trace(bt, 0, rq->data_len, rw, what, rq->errors, sizeof(rq->cmd), rq->cmd);
+	} else  {
+		what |= BLK_TC_ACT(BLK_TC_FS);
+		__blk_add_trace(bt, rq->hard_sector, rq->hard_nr_sectors << 9, rw, what, rq->errors, 0, NULL);
+	}
+}
+
+/**
+ * blk_add_trace_bio - Add a trace for a bio oriented action
+ * @q:		queue the io is for
+ * @bio:	the source bio
+ * @what:	the action
+ *
+ * Description:
+ *     Records an action against a bio. Will log the bio offset + size.
+ *
+ **/
+static inline void blk_add_trace_bio(struct request_queue *q, struct bio *bio,
+				     u32 what)
+{
+	struct blk_trace *bt = q->blk_trace;
+
+	if (likely(!bt))
+		return;
+
+	__blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, what, !bio_flagged(bio, BIO_UPTODATE), 0, NULL);
+}
+
+/**
+ * blk_add_trace_generic - Add a trace for a generic action
+ * @q:		queue the io is for
+ * @bio:	the source bio
+ * @rw:		the data direction
+ * @what:	the action
+ *
+ * Description:
+ *     Records a simple trace
+ *
+ **/
+static inline void blk_add_trace_generic(struct request_queue *q,
+					 struct bio *bio, int rw, u32 what)
+{
+	struct blk_trace *bt = q->blk_trace;
+
+	if (likely(!bt))
+		return;
+
+	if (bio)
+		blk_add_trace_bio(q, bio, what);
+	else
+		__blk_add_trace(bt, 0, 0, rw, what, 0, 0, NULL);
+}
+
+/**
+ * blk_add_trace_pdu_int - Add a trace for a bio with an integer payload
+ * @q:		queue the io is for
+ * @what:	the action
+ * @bio:	the source bio
+ * @pdu:	the integer payload
+ *
+ * Description:
+ *     Adds a trace with some integer payload. This might be an unplug
+ *     option given as the action, with the depth at unplug time given
+ *     as the payload
+ *
+ **/
+static inline void blk_add_trace_pdu_int(struct request_queue *q, u32 what,
+					 struct bio *bio, unsigned int pdu)
+{
+	struct blk_trace *bt = q->blk_trace;
+	u64 rpdu = cpu_to_be64(pdu);
+
+	if (likely(!bt))
+		return;
+
+	if (bio)
+		__blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, what, !bio_flagged(bio, BIO_UPTODATE), sizeof(rpdu), &rpdu);
+	else
+		__blk_add_trace(bt, 0, 0, 0, what, 0, sizeof(rpdu), &rpdu);
+}
+
+/**
+ * blk_add_trace_remap - Add a trace for a remap operation
+ * @q:		queue the io is for
+ * @bio:	the source bio
+ * @dev:	target device
+ * @from:	source sector
+ * @to:		target sector
+ *
+ * Description:
+ *     Device mapper or raid target sometimes need to split a bio because
+ *     it spans a stripe (or similar). Add a trace for that action.
+ *
+ **/
+static inline void blk_add_trace_remap(struct request_queue *q, struct bio *bio,
+				       dev_t dev, sector_t from, sector_t to)
+{
+	struct blk_trace *bt = q->blk_trace;
+	struct blk_io_trace_remap r;
+
+	if (likely(!bt))
+		return;
+
+	r.device = cpu_to_be32(dev);
+	r.sector = cpu_to_be64(to);
+
+	__blk_add_trace(bt, from, bio->bi_size, bio->bi_rw, BLK_TA_REMAP, !bio_flagged(bio, BIO_UPTODATE), sizeof(r), &r);
+}
+
+#else /* !CONFIG_BLK_DEV_IO_TRACE */
+#define blk_trace_ioctl(bdev, cmd, arg)		(-ENOTTY)
+#define blk_trace_shutdown(q)			do { } while (0)
+#define blk_add_trace_rq(q, rq, what)		do { } while (0)
+#define blk_add_trace_bio(q, rq, what)		do { } while (0)
+#define blk_add_trace_generic(q, rq, rw, what)	do { } while (0)
+#define blk_add_trace_pdu_int(q, what, bio, pdu)	do { } while (0)
+#define blk_add_trace_remap(q, bio, dev, f, t)	do {} while (0)
+#endif /* CONFIG_BLK_DEV_IO_TRACE */
+
+#endif
diff -urN oldtree/include/linux/cdrom.h newtree/include/linux/cdrom.h
--- oldtree/include/linux/cdrom.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/cdrom.h	2006-02-21 15:58:36.833547008 +0000
@@ -750,7 +750,7 @@
 #define MRW_MODE_PC			0x03
 
 struct mrw_feature_desc {
-	__u16 feature_code;
+	__be16 feature_code;
 #if defined(__BIG_ENDIAN_BITFIELD)
 	__u8 reserved1		: 2;
 	__u8 feature_version	: 4;
@@ -777,7 +777,7 @@
 
 /* cf. mmc4r02g.pdf 5.3.10 Random Writable Feature (0020h) pg 197 of 635 */
 struct rwrt_feature_desc {
-	__u16 feature_code;
+	__be16 feature_code;
 #if defined(__BIG_ENDIAN_BITFIELD)
 	__u8 reserved1		: 2;
 	__u8 feature_version	: 4;
@@ -804,7 +804,7 @@
 };
 
 typedef struct {
-	__u16 disc_information_length;
+	__be16 disc_information_length;
 #if defined(__BIG_ENDIAN_BITFIELD)
 	__u8 reserved1			: 3;
         __u8 erasable			: 1;
@@ -850,7 +850,7 @@
 } disc_information;
 
 typedef struct {
-	__u16 track_information_length;
+	__be16 track_information_length;
 	__u8 track_lsb;
 	__u8 session_lsb;
 	__u8 reserved1;
@@ -881,12 +881,12 @@
 	__u8 lra_v			: 1;
 	__u8 reserved3			: 6;
 #endif
-	__u32 track_start;
-	__u32 next_writable;
-	__u32 free_blocks;
-	__u32 fixed_packet_size;
-	__u32 track_size;
-	__u32 last_rec_address;
+	__be32 track_start;
+	__be32 next_writable;
+	__be32 free_blocks;
+	__be32 fixed_packet_size;
+	__be32 track_size;
+	__be32 last_rec_address;
 } track_information;
 
 struct feature_header {
@@ -897,12 +897,12 @@
 };
 
 struct mode_page_header {
-	__u16 mode_data_length;
+	__be16 mode_data_length;
 	__u8 medium_type;
 	__u8 reserved1;
 	__u8 reserved2;
 	__u8 reserved3;
-	__u16 desc_length;
+	__be16 desc_length;
 };
 
 #ifdef __KERNEL__
@@ -1109,7 +1109,7 @@
 #endif
 	__u8 session_format;
 	__u8 reserved6;
-	__u32 packet_size;
+	__be32 packet_size;
 	__u16 audio_pause;
 	__u8 mcn[16];
 	__u8 isrc[16];
@@ -1154,7 +1154,7 @@
 } rpc_state_t;
 
 struct event_header {
-	__u16 data_len;
+	__be16 data_len;
 #if defined(__BIG_ENDIAN_BITFIELD)
 	__u8 nea		: 1;
 	__u8 reserved1		: 4;
diff -urN oldtree/include/linux/compat_ioctl.h newtree/include/linux/compat_ioctl.h
--- oldtree/include/linux/compat_ioctl.h	2006-02-19 11:41:05.783463880 +0000
+++ newtree/include/linux/compat_ioctl.h	2006-02-21 15:58:11.953329376 +0000
@@ -97,6 +97,10 @@
 COMPATIBLE_IOCTL(BLKFLSBUF)
 COMPATIBLE_IOCTL(BLKSECTSET)
 COMPATIBLE_IOCTL(BLKSSZGET)
+COMPATIBLE_IOCTL(BLKTRACESTART)
+COMPATIBLE_IOCTL(BLKTRACESTOP)
+COMPATIBLE_IOCTL(BLKTRACESETUP)
+COMPATIBLE_IOCTL(BLKTRACETEARDOWN)
 ULONG_IOCTL(BLKRASET)
 ULONG_IOCTL(BLKFRASET)
 /* RAID */
diff -urN oldtree/include/linux/cpufreq.h newtree/include/linux/cpufreq.h
--- oldtree/include/linux/cpufreq.h	2006-02-19 11:41:05.786463424 +0000
+++ newtree/include/linux/cpufreq.h	2006-02-21 15:58:10.528545976 +0000
@@ -73,6 +73,8 @@
 
 struct cpufreq_policy {
 	cpumask_t		cpus;	/* affected CPUs */
+	unsigned int		shared_type; /* ANY or ALL affected CPUs
+						should set cpufreq */
 	unsigned int		cpu;    /* cpu nr of registered CPU */
 	struct cpufreq_cpuinfo	cpuinfo;/* see above */
 
@@ -99,6 +101,8 @@
 #define CPUFREQ_INCOMPATIBLE	(1)
 #define CPUFREQ_NOTIFY		(2)
 
+#define CPUFREQ_SHARED_TYPE_ALL	(0) /* All dependent CPUs should set freq */
+#define CPUFREQ_SHARED_TYPE_ANY	(1) /* Freq can be set from any dependent CPU */
 
 /******************** cpufreq transition notifiers *******************/
 
diff -urN oldtree/include/linux/cpuset.h newtree/include/linux/cpuset.h
--- oldtree/include/linux/cpuset.h	2006-02-19 11:41:05.787463272 +0000
+++ newtree/include/linux/cpuset.h	2006-02-21 15:58:29.569651288 +0000
@@ -4,7 +4,7 @@
  *  cpuset interface
  *
  *  Copyright (C) 2003 BULL SA
- *  Copyright (C) 2004 Silicon Graphics, Inc.
+ *  Copyright (C) 2004-2006 Silicon Graphics, Inc.
  *
  */
 
@@ -51,6 +51,18 @@
 extern void cpuset_lock(void);
 extern void cpuset_unlock(void);
 
+extern int cpuset_mem_spread_node(void);
+
+static inline int cpuset_do_page_mem_spread(void)
+{
+	return current->flags & PF_SPREAD_PAGE;
+}
+
+static inline int cpuset_do_slab_mem_spread(void)
+{
+	return current->flags & PF_SPREAD_SLAB;
+}
+
 #else /* !CONFIG_CPUSETS */
 
 static inline int cpuset_init_early(void) { return 0; }
@@ -99,6 +111,21 @@
 static inline void cpuset_lock(void) {}
 static inline void cpuset_unlock(void) {}
 
+static inline int cpuset_mem_spread_node(void)
+{
+	return 0;
+}
+
+static inline int cpuset_do_page_mem_spread(void)
+{
+	return 0;
+}
+
+static inline int cpuset_do_slab_mem_spread(void)
+{
+	return 0;
+}
+
 #endif /* !CONFIG_CPUSETS */
 
 #endif /* _LINUX_CPUSET_H */
diff -urN oldtree/include/linux/dccp.h newtree/include/linux/dccp.h
--- oldtree/include/linux/dccp.h	2006-02-19 11:41:05.789462968 +0000
+++ newtree/include/linux/dccp.h	2006-02-21 15:58:16.170688240 +0000
@@ -154,6 +154,10 @@
 	DCCPO_MANDATORY = 1,
 	DCCPO_MIN_RESERVED = 3,
 	DCCPO_MAX_RESERVED = 31,
+	DCCPO_CHANGE_L = 32,
+	DCCPO_CONFIRM_L = 33,
+	DCCPO_CHANGE_R = 34,
+	DCCPO_CONFIRM_R = 35,
 	DCCPO_NDP_COUNT = 37,
 	DCCPO_ACK_VECTOR_0 = 38,
 	DCCPO_ACK_VECTOR_1 = 39,
@@ -168,7 +172,9 @@
 /* DCCP features */
 enum {
 	DCCPF_RESERVED = 0,
+	DCCPF_CCID = 1,
 	DCCPF_SEQUENCE_WINDOW = 3,
+	DCCPF_ACK_RATIO = 5,
 	DCCPF_SEND_ACK_VECTOR = 6,
 	DCCPF_SEND_NDP_COUNT = 7,
 	/* 10-127 reserved */
@@ -176,9 +182,18 @@
 	DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 
+/* this structure is argument to DCCP_SOCKOPT_CHANGE_X */
+struct dccp_so_feat {
+	__u8 dccpsf_feat;
+	__u8 *dccpsf_val;
+	__u8 dccpsf_len;
+};
+
 /* DCCP socket options */
 #define DCCP_SOCKOPT_PACKET_SIZE	1
 #define DCCP_SOCKOPT_SERVICE		2
+#define DCCP_SOCKOPT_CHANGE_L		3
+#define DCCP_SOCKOPT_CHANGE_R		4
 #define DCCP_SOCKOPT_CCID_RX_INFO	128
 #define DCCP_SOCKOPT_CCID_TX_INFO	192
 
@@ -314,9 +329,18 @@
 
 /* initial values for each feature */
 #define DCCPF_INITIAL_SEQUENCE_WINDOW		100
-/* FIXME: for now we're using CCID 3 (TFRC) */
+#define DCCPF_INITIAL_ACK_RATIO			2
+
+#if defined(CONFIG_IP_DCCP_CCID2) || defined(CONFIG_IP_DCCP_CCID2_MODULE)
+#define DCCPF_INITIAL_CCID			2
+#define DCCPF_INITIAL_SEND_ACK_VECTOR		1
+#elif defined(CONFIG_IP_DCCP_CCID3) || defined(CONFIG_IP_DCCP_CCID3_MODULE)
 #define DCCPF_INITIAL_CCID			3
 #define DCCPF_INITIAL_SEND_ACK_VECTOR		0
+#else
+#error  "At least one CCID must be built as the default"
+#endif
+
 /* FIXME: for now we're default to 1 but it should really be 0 */
 #define DCCPF_INITIAL_SEND_NDP_COUNT		1
 
@@ -335,6 +359,24 @@
 	__u8	dccpo_tx_ccid;
 	__u8	dccpo_send_ack_vector;
 	__u8	dccpo_send_ndp_count;
+	__u8			dccpo_ack_ratio;
+	struct list_head	dccpo_pending;
+	struct list_head	dccpo_conf;
+};
+
+struct dccp_opt_conf {
+	__u8			*dccpoc_val;
+	__u8			dccpoc_len;
+};
+
+struct dccp_opt_pend {
+	struct list_head	dccpop_node;
+	__u8			dccpop_type;
+	__u8			dccpop_feat;
+	__u8		        *dccpop_val;
+	__u8			dccpop_len;
+	int			dccpop_conf;
+	struct dccp_opt_conf    *dccpop_sc;
 };
 
 extern void __dccp_options_init(struct dccp_options *dccpo);
@@ -430,6 +472,8 @@
 	struct timeval			dccps_timestamp_time;
 	__u32				dccps_timestamp_echo;
 	__u32				dccps_packet_size;
+	__u16				dccps_l_ack_ratio;
+	__u16				dccps_r_ack_ratio;
 	unsigned long			dccps_ndp_count;
 	__u32				dccps_mss_cache;
 	struct dccp_options		dccps_options;
diff -urN oldtree/include/linux/delay.h newtree/include/linux/delay.h
--- oldtree/include/linux/delay.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/delay.h	2006-02-21 15:58:35.945681984 +0000
@@ -10,7 +10,7 @@
 extern unsigned long loops_per_jiffy;
 
 #include <asm/delay.h>
-
+#include <linux/hardirq.h>
 /*
  * Using udelay() for intervals greater than a few milliseconds can
  * risk overflow for high loops_per_jiffy (high bogomips) machines. The
@@ -25,14 +25,13 @@
 #define MAX_UDELAY_MS	5
 #endif
 
-#ifdef notdef
-#define mdelay(n) (\
-	{unsigned long __ms=(n); while (__ms--) udelay(1000);})
-#else
-#define mdelay(n) (\
-	(__builtin_constant_p(n) && (n)<=MAX_UDELAY_MS) ? udelay((n)*1000) : \
-	({unsigned long __ms=(n); while (__ms--) udelay(1000);}))
-#endif
+#define mdelay(n) (					\
+	{						\
+		static int warned=0; 			\
+		unsigned long __ms=(n); 		\
+		WARN_ON(in_irq() && !(warned++)); 	\
+		while (__ms--) udelay(1000);		\
+	})
 
 #ifndef ndelay
 #define ndelay(x)	udelay(((x)+999)/1000)
diff -urN oldtree/include/linux/divert.h newtree/include/linux/divert.h
--- oldtree/include/linux/divert.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/divert.h	2006-02-21 15:58:36.833547008 +0000
@@ -27,10 +27,10 @@
 {
 	int		divert;  /* are we active */
 	unsigned int protos;	/* protocols */
-	u16		tcp_dst[MAX_DIVERT_PORTS]; /* specific tcp dst ports to divert */
-	u16		tcp_src[MAX_DIVERT_PORTS]; /* specific tcp src ports to divert */
-	u16		udp_dst[MAX_DIVERT_PORTS]; /* specific udp dst ports to divert */
-	u16		udp_src[MAX_DIVERT_PORTS]; /* specific udp src ports to divert */
+	__be16		tcp_dst[MAX_DIVERT_PORTS]; /* specific tcp dst ports to divert */
+	__be16		tcp_src[MAX_DIVERT_PORTS]; /* specific tcp src ports to divert */
+	__be16		udp_dst[MAX_DIVERT_PORTS]; /* specific udp dst ports to divert */
+	__be16		udp_src[MAX_DIVERT_PORTS]; /* specific udp src ports to divert */
 };
 
 /*
diff -urN oldtree/include/linux/dlm.h newtree/include/linux/dlm.h
--- oldtree/include/linux/dlm.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/include/linux/dlm.h	2006-02-21 15:58:32.600190576 +0000
@@ -0,0 +1,312 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __DLM_DOT_H__
+#define __DLM_DOT_H__
+
+/*
+ * Interface to Distributed Lock Manager (DLM)
+ * routines and structures to use DLM lockspaces
+ */
+
+/*
+ * Lock Modes
+ */
+
+#define DLM_LOCK_IV		-1	/* invalid */
+#define DLM_LOCK_NL		0	/* null */
+#define DLM_LOCK_CR		1	/* concurrent read */
+#define DLM_LOCK_CW		2	/* concurrent write */
+#define DLM_LOCK_PR		3	/* protected read */
+#define DLM_LOCK_PW		4	/* protected write */
+#define DLM_LOCK_EX		5	/* exclusive */
+
+/*
+ * Maximum size in bytes of a dlm_lock name
+ */
+
+#define DLM_RESNAME_MAXLEN	64
+
+/*
+ * Flags to dlm_lock
+ *
+ * DLM_LKF_NOQUEUE
+ *
+ * Do not queue the lock request on the wait queue if it cannot be granted
+ * immediately.  If the lock cannot be granted because of this flag, DLM will
+ * either return -EAGAIN from the dlm_lock call or will return 0 from
+ * dlm_lock and -EAGAIN in the lock status block when the AST is executed.
+ *
+ * DLM_LKF_CANCEL
+ *
+ * Used to cancel a pending lock request or conversion.  A converting lock is
+ * returned to its previously granted mode.
+ *
+ * DLM_LKF_CONVERT
+ *
+ * Indicates a lock conversion request.  For conversions the name and namelen
+ * are ignored and the lock ID in the LKSB is used to identify the lock.
+ *
+ * DLM_LKF_VALBLK
+ *
+ * Requests DLM to return the current contents of the lock value block in the
+ * lock status block.  When this flag is set in a lock conversion from PW or EX
+ * modes, DLM assigns the value specified in the lock status block to the lock
+ * value block of the lock resource.  The LVB is a DLM_LVB_LEN size array
+ * containing application-specific information.
+ *
+ * DLM_LKF_QUECVT
+ *
+ * Force a conversion request to be queued, even if it is compatible with
+ * the granted modes of other locks on the same resource.
+ *
+ * DLM_LKF_IVVALBLK
+ *
+ * Invalidate the lock value block.
+ *
+ * DLM_LKF_CONVDEADLK
+ *
+ * Allows the dlm to resolve conversion deadlocks internally by demoting the
+ * granted mode of a converting lock to NL.  The DLM_SBF_DEMOTED flag is
+ * returned for a conversion that's been effected by this.
+ *
+ * DLM_LKF_PERSISTENT
+ *
+ * Only relevant to locks originating in userspace.  A persistent lock will not
+ * be removed if the process holding the lock exits.
+ *
+ * DLM_LKF_NODLKWT
+ * DLM_LKF_NODLCKBLK
+ *
+ * net yet implemented
+ *
+ * DLM_LKF_EXPEDITE
+ *
+ * Used only with new requests for NL mode locks.  Tells the lock manager
+ * to grant the lock, ignoring other locks in convert and wait queues.
+ *
+ * DLM_LKF_NOQUEUEBAST
+ *
+ * Send blocking AST's before returning -EAGAIN to the caller.  It is only
+ * used along with the NOQUEUE flag.  Blocking AST's are not sent for failed
+ * NOQUEUE requests otherwise.
+ *
+ * DLM_LKF_HEADQUE
+ *
+ * Add a lock to the head of the convert or wait queue rather than the tail.
+ *
+ * DLM_LKF_NOORDER
+ *
+ * Disregard the standard grant order rules and grant a lock as soon as it
+ * is compatible with other granted locks.
+ *
+ * DLM_LKF_ORPHAN
+ *
+ * not yet implemented
+ *
+ * DLM_LKF_ALTPR
+ *
+ * If the requested mode cannot be granted immediately, try to grant the lock
+ * in PR mode instead.  If this alternate mode is granted instead of the
+ * requested mode, DLM_SBF_ALTMODE is returned in the lksb.
+ *
+ * DLM_LKF_ALTCW
+ *
+ * The same as ALTPR, but the alternate mode is CW.
+ *
+ * DLM_LKF_FORCEUNLOCK
+ *
+ * Unlock the lock even if it is converting or waiting or has sublocks.
+ * Only really for use by the userland device.c code.
+ *
+ */
+
+#define DLM_LKF_NOQUEUE		0x00000001
+#define DLM_LKF_CANCEL		0x00000002
+#define DLM_LKF_CONVERT		0x00000004
+#define DLM_LKF_VALBLK		0x00000008
+#define DLM_LKF_QUECVT		0x00000010
+#define DLM_LKF_IVVALBLK	0x00000020
+#define DLM_LKF_CONVDEADLK	0x00000040
+#define DLM_LKF_PERSISTENT	0x00000080
+#define DLM_LKF_NODLCKWT	0x00000100
+#define DLM_LKF_NODLCKBLK	0x00000200
+#define DLM_LKF_EXPEDITE	0x00000400
+#define DLM_LKF_NOQUEUEBAST	0x00000800
+#define DLM_LKF_HEADQUE		0x00001000
+#define DLM_LKF_NOORDER		0x00002000
+#define DLM_LKF_ORPHAN		0x00004000
+#define DLM_LKF_ALTPR		0x00008000
+#define DLM_LKF_ALTCW		0x00010000
+#define DLM_LKF_FORCEUNLOCK	0x00020000
+
+/*
+ * Some return codes that are not in errno.h
+ */
+
+#define DLM_ECANCEL		0x10001
+#define DLM_EUNLOCK		0x10002
+
+typedef void dlm_lockspace_t;
+
+/*
+ * Lock range structure
+ */
+
+struct dlm_range {
+	uint64_t ra_start;
+	uint64_t ra_end;
+};
+
+/*
+ * Lock status block
+ *
+ * Use this structure to specify the contents of the lock value block.  For a
+ * conversion request, this structure is used to specify the lock ID of the
+ * lock.  DLM writes the status of the lock request and the lock ID assigned
+ * to the request in the lock status block.
+ *
+ * sb_lkid: the returned lock ID.  It is set on new (non-conversion) requests.
+ * It is available when dlm_lock returns.
+ *
+ * sb_lvbptr: saves or returns the contents of the lock's LVB according to rules
+ * shown for the DLM_LKF_VALBLK flag.
+ *
+ * sb_flags: DLM_SBF_DEMOTED is returned if in the process of promoting a lock,
+ * it was first demoted to NL to avoid conversion deadlock.
+ * DLM_SBF_VALNOTVALID is returned if the resource's LVB is marked invalid.
+ *
+ * sb_status: the returned status of the lock request set prior to AST
+ * execution.  Possible return values:
+ *
+ * 0 if lock request was successful
+ * -EAGAIN if request would block and is flagged DLM_LKF_NOQUEUE
+ * -ENOMEM if there is no memory to process request
+ * -EINVAL if there are invalid parameters
+ * -DLM_EUNLOCK if unlock request was successful
+ * -DLM_ECANCEL if a cancel completed successfully
+ */
+
+#define DLM_SBF_DEMOTED		0x01
+#define DLM_SBF_VALNOTVALID	0x02
+#define DLM_SBF_ALTMODE		0x04
+
+struct dlm_lksb {
+	int 	 sb_status;
+	uint32_t sb_lkid;
+	char 	 sb_flags;
+	char *	 sb_lvbptr;
+};
+
+
+#ifdef __KERNEL__
+
+#define DLM_LSFL_NODIR		0x00000001
+
+/*
+ * dlm_new_lockspace
+ *
+ * Starts a lockspace with the given name.  If the named lockspace exists in
+ * the cluster, the calling node joins it.
+ */
+
+int dlm_new_lockspace(char *name, int namelen, dlm_lockspace_t **lockspace,
+		      uint32_t flags, int lvblen);
+
+/*
+ * dlm_release_lockspace
+ *
+ * Stop a lockspace.
+ */
+
+int dlm_release_lockspace(dlm_lockspace_t *lockspace, int force);
+
+/*
+ * dlm_lock
+ *
+ * Make an asyncronous request to acquire or convert a lock on a named
+ * resource.
+ *
+ * lockspace: context for the request
+ * mode: the requested mode of the lock (DLM_LOCK_)
+ * lksb: lock status block for input and async return values
+ * flags: input flags (DLM_LKF_)
+ * name: name of the resource to lock, can be binary
+ * namelen: the length in bytes of the resource name (MAX_RESNAME_LEN)
+ * parent: the lock ID of a parent lock or 0 if none
+ * lockast: function DLM executes when it completes processing the request
+ * astarg: argument passed to lockast and bast functions
+ * bast: function DLM executes when this lock later blocks another request
+ *
+ * Returns:
+ * 0 if request is successfully queued for processing
+ * -EINVAL if any input parameters are invalid
+ * -EAGAIN if request would block and is flagged DLM_LKF_NOQUEUE
+ * -ENOMEM if there is no memory to process request
+ * -ENOTCONN if there is a communication error
+ *
+ * If the call to dlm_lock returns an error then the operation has failed and
+ * the AST routine will not be called.  If dlm_lock returns 0 it is still
+ * possible that the lock operation will fail. The AST routine will be called
+ * when the locking is complete and the status is returned in the lksb.
+ *
+ * If the AST routines or parameter are passed to a conversion operation then
+ * they will overwrite those values that were passed to a previous dlm_lock
+ * call.
+ *
+ * AST routines should not block (at least not for long), but may make
+ * any locking calls they please.
+ */
+
+int dlm_lock(dlm_lockspace_t *lockspace,
+	     int mode,
+	     struct dlm_lksb *lksb,
+	     uint32_t flags,
+	     void *name,
+	     unsigned int namelen,
+	     uint32_t parent_lkid,
+	     void (*lockast) (void *astarg),
+	     void *astarg,
+	     void (*bast) (void *astarg, int mode),
+	     struct dlm_range *range);
+
+/*
+ * dlm_unlock
+ *
+ * Asynchronously release a lock on a resource.  The AST routine is called
+ * when the resource is successfully unlocked.
+ *
+ * lockspace: context for the request
+ * lkid: the lock ID as returned in the lksb
+ * flags: input flags (DLM_LKF_)
+ * lksb: if NULL the lksb parameter passed to last lock request is used
+ * astarg: the arg used with the completion ast for the unlock
+ *
+ * Returns:
+ * 0 if request is successfully queued for processing
+ * -EINVAL if any input parameters are invalid
+ * -ENOTEMPTY if the lock still has sublocks
+ * -EBUSY if the lock is waiting for a remote lock operation
+ * -ENOTCONN if there is a communication error
+ */
+
+int dlm_unlock(dlm_lockspace_t *lockspace,
+	       uint32_t lkid,
+	       uint32_t flags,
+	       struct dlm_lksb *lksb,
+	       void *astarg);
+
+#endif				/* __KERNEL__ */
+
+#endif				/* __DLM_DOT_H__ */
+
diff -urN oldtree/include/linux/dlm_device.h newtree/include/linux/dlm_device.h
--- oldtree/include/linux/dlm_device.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/include/linux/dlm_device.h	2006-02-21 15:58:32.380224016 +0000
@@ -0,0 +1,84 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+/* This is the device interface for dlm, most users will use a library
+ * interface.
+ */
+
+#define DLM_USER_LVB_LEN	32
+
+/* Version of the device interface */
+#define DLM_DEVICE_VERSION_MAJOR 3
+#define DLM_DEVICE_VERSION_MINOR 0
+#define DLM_DEVICE_VERSION_PATCH 0
+
+/* struct passed to the lock write */
+struct dlm_lock_params {
+	__u8 mode;
+	__u16 flags;
+	__u32 lkid;
+	__u32 parent;
+	struct dlm_range range;
+	__u8 namelen;
+        void __user *castparam;
+	void __user *castaddr;
+	void __user *bastparam;
+        void __user *bastaddr;
+	struct dlm_lksb __user *lksb;
+	char lvb[DLM_USER_LVB_LEN];
+	char name[1];
+};
+
+struct dlm_lspace_params {
+	__u32 flags;
+	__u32 minor;
+	char name[1];
+};
+
+struct dlm_write_request {
+	__u32 version[3];
+	__u8 cmd;
+
+	union  {
+		struct dlm_lock_params   lock;
+		struct dlm_lspace_params lspace;
+	} i;
+};
+
+/* struct read from the "device" fd,
+   consists mainly of userspace pointers for the library to use */
+struct dlm_lock_result {
+	__u32 length;
+	void __user * user_astaddr;
+	void __user * user_astparam;
+	struct dlm_lksb __user * user_lksb;
+	struct dlm_lksb lksb;
+	__u8 bast_mode;
+	/* Offsets may be zero if no data is present */
+	__u32 lvb_offset;
+};
+
+/* Commands passed to the device */
+#define DLM_USER_LOCK         1
+#define DLM_USER_UNLOCK       2
+#define DLM_USER_QUERY        3
+#define DLM_USER_CREATE_LOCKSPACE  4
+#define DLM_USER_REMOVE_LOCKSPACE  5
+
+/* Arbitrary length restriction */
+#define MAX_LS_NAME_LEN 64
+
+/* Lockspace flags */
+#define DLM_USER_LSFLG_AUTOFREE   1
+#define DLM_USER_LSFLG_FORCEFREE  2
+
diff -urN oldtree/include/linux/errqueue.h newtree/include/linux/errqueue.h
--- oldtree/include/linux/errqueue.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/errqueue.h	2006-02-21 15:58:36.834546856 +0000
@@ -39,7 +39,7 @@
 	} header;
 	struct sock_extended_err	ee;
 	u16				addr_offset;
-	u16				port;
+	__be16				port;
 };
 
 #endif
diff -urN oldtree/include/linux/ext3_fs.h newtree/include/linux/ext3_fs.h
--- oldtree/include/linux/ext3_fs.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/ext3_fs.h	2006-02-21 15:58:36.835546704 +0000
@@ -468,7 +468,7 @@
 	 */
 	__u8	s_prealloc_blocks;	/* Nr of blocks to try to preallocate*/
 	__u8	s_prealloc_dir_blocks;	/* Nr to preallocate for dirs */
-	__u16	s_reserved_gdt_blocks;	/* Per group desc for online growth */
+	__le16	s_reserved_gdt_blocks;	/* Per group desc for online growth */
 	/*
 	 * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
 	 */
diff -urN oldtree/include/linux/ext3_fs_i.h newtree/include/linux/ext3_fs_i.h
--- oldtree/include/linux/ext3_fs_i.h	2006-02-19 11:41:05.794462208 +0000
+++ newtree/include/linux/ext3_fs_i.h	2006-02-21 15:58:28.212857552 +0000
@@ -19,6 +19,7 @@
 #include <linux/rwsem.h>
 #include <linux/rbtree.h>
 #include <linux/seqlock.h>
+#include <linux/mutex.h>
 
 struct ext3_reserve_window {
 	__u32			_rsv_start;	/* First byte reserved */
@@ -122,16 +123,16 @@
 	__u16 i_extra_isize;
 
 	/*
-	 * truncate_sem is for serialising ext3_truncate() against
+	 * truncate_mutex is for serialising ext3_truncate() against
 	 * ext3_getblock().  In the 2.4 ext2 design, great chunks of inode's
 	 * data tree are chopped off during truncate. We can't do that in
 	 * ext3 because whenever we perform intermediate commits during
 	 * truncate, the inode and all the metadata blocks *must* be in a
 	 * consistent state which allows truncation of the orphans to restart
 	 * during recovery.  Hence we must fix the get_block-vs-truncate race
-	 * by other means, so we have truncate_sem.
+	 * by other means, so we have truncate_mutex.
 	 */
-	struct semaphore truncate_sem;
+	struct mutex truncate_mutex;
 	struct inode vfs_inode;
 };
 
diff -urN oldtree/include/linux/file.h newtree/include/linux/file.h
--- oldtree/include/linux/file.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/file.h	2006-02-21 15:58:23.598559032 +0000
@@ -10,6 +10,7 @@
 #include <linux/compiler.h>
 #include <linux/spinlock.h>
 #include <linux/rcupdate.h>
+#include <linux/types.h>
 
 /*
  * The default fd array needs to be at least BITS_PER_LONG,
@@ -17,10 +18,22 @@
  */
 #define NR_OPEN_DEFAULT BITS_PER_LONG
 
+/*
+ * The embedded_fd_set is a small fd_set,
+ * suitable for most tasks (which open <= BITS_PER_LONG files)
+ */
+struct embedded_fd_set {
+	unsigned long fds_bits[1];
+};
+
+/*
+ * More than this number of fds: we use a separately allocated fd_set
+ */
+#define EMBEDDED_FD_SET_SIZE (BITS_PER_BYTE * sizeof(struct embedded_fd_set))
+
 struct fdtable {
 	unsigned int max_fds;
 	int max_fdset;
-	int next_fd;
 	struct file ** fd;      /* current fd array */
 	fd_set *close_on_exec;
 	fd_set *open_fds;
@@ -33,13 +46,20 @@
  * Open file table structure
  */
 struct files_struct {
+  /*
+   * read mostly part
+   */
 	atomic_t count;
 	struct fdtable *fdt;
 	struct fdtable fdtab;
-	fd_set close_on_exec_init;
-	fd_set open_fds_init;
+  /*
+   * written part on a separate cache line in SMP
+   */
+	spinlock_t file_lock ____cacheline_aligned_in_smp;
+	int next_fd;
+	struct embedded_fd_set close_on_exec_init;
+	struct embedded_fd_set open_fds_init;
 	struct file * fd_array[NR_OPEN_DEFAULT];
-	spinlock_t file_lock;     /* Protects concurrent writers.  Nests inside tsk->alloc_lock */
 };
 
 #define files_fdtable(files) (rcu_dereference((files)->fdt))
diff -urN oldtree/include/linux/fs.h newtree/include/linux/fs.h
--- oldtree/include/linux/fs.h	2006-02-19 11:41:05.797461752 +0000
+++ newtree/include/linux/fs.h	2006-02-21 15:58:33.792009392 +0000
@@ -196,6 +196,10 @@
 #define BLKBSZGET  _IOR(0x12,112,size_t)
 #define BLKBSZSET  _IOW(0x12,113,size_t)
 #define BLKGETSIZE64 _IOR(0x12,114,size_t)	/* return device size in bytes (u64 *arg) */
+#define BLKTRACESETUP _IOWR(0x12,115,struct blk_user_trace_setup)
+#define BLKTRACESTART _IO(0x12,116)
+#define BLKTRACESTOP _IO(0x12,117)
+#define BLKTRACETEARDOWN _IO(0x12,118)
 
 #define BMAP_IOCTL 1		/* obsolete - kept for compatibility */
 #define FIBMAP	   _IO(0x00,1)	/* bmap access */
@@ -343,7 +347,7 @@
 	/* Write back some dirty pages from this mapping. */
 	int (*writepages)(struct address_space *, struct writeback_control *);
 
-	/* Set a page dirty */
+	/* Set a page dirty.  Return true if this dirtied it */
 	int (*set_page_dirty)(struct page *page);
 
 	int (*readpages)(struct file *filp, struct address_space *mapping,
@@ -396,8 +400,8 @@
 	dev_t			bd_dev;  /* not a kdev_t - it's a search key */
 	struct inode *		bd_inode;	/* will die */
 	int			bd_openers;
-	struct semaphore	bd_sem;	/* open/close mutex */
-	struct semaphore	bd_mount_sem;	/* mount mutex */
+	struct mutex		bd_mutex;	/* open/close mutex */
+	struct mutex		bd_mount_mutex;	/* mount mutex */
 	struct list_head	bd_inodes;
 	void *			bd_holder;
 	int			bd_holders;
@@ -478,7 +482,7 @@
 	unsigned int		i_blkbits;
 	unsigned long		i_blksize;
 	unsigned long		i_version;
-	unsigned long		i_blocks;
+	sector_t		i_blocks;
 	unsigned short          i_bytes;
 	spinlock_t		i_lock;	/* i_blocks, i_bytes, maybe i_size */
 	struct mutex		i_mutex;
@@ -508,7 +512,7 @@
 
 #ifdef CONFIG_INOTIFY
 	struct list_head	inotify_watches; /* watches on this inode */
-	struct semaphore	inotify_sem;	/* protects the watches list */
+	struct mutex		inotify_mutex;	/* protects the watches list */
 #endif
 
 	unsigned long		i_state;
@@ -1084,6 +1088,8 @@
 	void (*clear_inode) (struct inode *);
 	void (*umount_begin) (struct super_block *);
 
+	void (*sync_inodes) (struct super_block *sb,
+				struct writeback_control *wbc);
 	int (*show_options)(struct seq_file *, struct vfsmount *);
 
 	ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
@@ -1114,6 +1120,18 @@
 	__mark_inode_dirty(inode, I_DIRTY_SYNC);
 }
 
+static inline void inode_inc_link_count(struct inode *inode)
+{
+	inode->i_nlink++;
+	mark_inode_dirty(inode);
+}
+
+static inline void inode_dec_link_count(struct inode *inode)
+{
+	inode->i_nlink--;
+	mark_inode_dirty(inode);
+}
+
 extern void touch_atime(struct vfsmount *mnt, struct dentry *dentry);
 static inline void file_accessed(struct file *file)
 {
@@ -1451,6 +1469,7 @@
 extern int invalidate_inode_pages2_range(struct address_space *mapping,
 					 pgoff_t start, pgoff_t end);
 extern int write_inode_now(struct inode *, int);
+extern void generic_sync_sb_inodes(struct super_block *, struct writeback_control *);
 extern int filemap_fdatawrite(struct address_space *);
 extern int filemap_flush(struct address_space *);
 extern int filemap_fdatawait(struct address_space *);
@@ -1536,7 +1555,7 @@
 extern struct inode *new_inode(struct super_block *);
 extern int remove_suid(struct dentry *);
 extern void remove_dquot_ref(struct super_block *, int, struct list_head *);
-extern struct semaphore iprune_sem;
+extern struct mutex iprune_mutex;
 
 extern void __insert_inode_hash(struct inode *, unsigned long hashval);
 extern void remove_inode_hash(struct inode *);
diff -urN oldtree/include/linux/fsnotify.h newtree/include/linux/fsnotify.h
--- oldtree/include/linux/fsnotify.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/fsnotify.h	2006-02-21 15:58:11.779355824 +0000
@@ -15,6 +15,7 @@
 
 #include <linux/dnotify.h>
 #include <linux/inotify.h>
+#include <linux/audit.h>
 
 /*
  * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir
@@ -34,17 +35,21 @@
 
 	if (isdir)
 		isdir = IN_ISDIR;
-	inotify_inode_queue_event(old_dir, IN_MOVED_FROM|isdir,cookie,old_name);
-	inotify_inode_queue_event(new_dir, IN_MOVED_TO|isdir, cookie, new_name);
+	inotify_inode_queue_event(old_dir, IN_MOVED_FROM|isdir, cookie,
+				  old_name, NULL);
+	inotify_inode_queue_event(new_dir, IN_MOVED_TO|isdir, cookie,
+				  new_name, source);
 
 	if (target) {
-		inotify_inode_queue_event(target, IN_DELETE_SELF, 0, NULL);
+		inotify_inode_queue_event(target, IN_DELETE_SELF, 0, NULL,NULL);
 		inotify_inode_is_dead(target);
 	}
 
 	if (source) {
-		inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL);
+		inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL);
 	}
+	audit_inode_child(old_name, source, old_dir->i_ino);
+	audit_inode_child(new_name, target, new_dir->i_ino);
 }
 
 /*
@@ -63,26 +68,30 @@
  */
 static inline void fsnotify_inoderemove(struct inode *inode)
 {
-	inotify_inode_queue_event(inode, IN_DELETE_SELF, 0, NULL);
+	inotify_inode_queue_event(inode, IN_DELETE_SELF, 0, NULL, NULL);
 	inotify_inode_is_dead(inode);
 }
 
 /*
  * fsnotify_create - 'name' was linked in
  */
-static inline void fsnotify_create(struct inode *inode, const char *name)
+static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
 {
 	inode_dir_notify(inode, DN_CREATE);
-	inotify_inode_queue_event(inode, IN_CREATE, 0, name);
+	inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name,
+				  dentry->d_inode);
+	audit_inode_child(dentry->d_name.name, dentry->d_inode, inode->i_ino);
 }
 
 /*
  * fsnotify_mkdir - directory 'name' was created
  */
-static inline void fsnotify_mkdir(struct inode *inode, const char *name)
+static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
 {
 	inode_dir_notify(inode, DN_CREATE);
-	inotify_inode_queue_event(inode, IN_CREATE | IN_ISDIR, 0, name);
+	inotify_inode_queue_event(inode, IN_CREATE | IN_ISDIR, 0, 
+				  dentry->d_name.name, dentry->d_inode);
+	audit_inode_child(dentry->d_name.name, dentry->d_inode, inode->i_ino);
 }
 
 /*
@@ -98,7 +107,7 @@
 
 	dnotify_parent(dentry, DN_ACCESS);
 	inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
-	inotify_inode_queue_event(inode, mask, 0, NULL);
+	inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
 }
 
 /*
@@ -114,7 +123,7 @@
 
 	dnotify_parent(dentry, DN_MODIFY);
 	inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
-	inotify_inode_queue_event(inode, mask, 0, NULL);
+	inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
 }
 
 /*
@@ -129,7 +138,7 @@
 		mask |= IN_ISDIR;
 
 	inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
-	inotify_inode_queue_event(inode, mask, 0, NULL);	
+	inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
 }
 
 /*
@@ -147,7 +156,7 @@
 		mask |= IN_ISDIR;
 
 	inotify_dentry_parent_queue_event(dentry, mask, 0, name);
-	inotify_inode_queue_event(inode, mask, 0, NULL);
+	inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
 }
 
 /*
@@ -162,7 +171,7 @@
 		mask |= IN_ISDIR;
 
 	inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
-	inotify_inode_queue_event(inode, mask, 0, NULL);
+	inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
 }
 
 /*
@@ -209,7 +218,7 @@
 	if (in_mask) {
 		if (S_ISDIR(inode->i_mode))
 			in_mask |= IN_ISDIR;
-		inotify_inode_queue_event(inode, in_mask, 0, NULL);
+		inotify_inode_queue_event(inode, in_mask, 0, NULL, NULL);
 		inotify_dentry_parent_queue_event(dentry, in_mask, 0,
 						  dentry->d_name.name);
 	}
diff -urN oldtree/include/linux/generic_serial.h newtree/include/linux/generic_serial.h
--- oldtree/include/linux/generic_serial.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/generic_serial.h	2006-02-21 15:58:28.361834904 +0000
@@ -12,6 +12,8 @@
 #ifndef GENERIC_SERIAL_H
 #define GENERIC_SERIAL_H
 
+#include <linux/mutex.h>
+
 struct real_driver {
   void                    (*disable_tx_interrupts) (void *);
   void                    (*enable_tx_interrupts) (void *);
@@ -34,7 +36,7 @@
   int                     xmit_head;
   int                     xmit_tail;
   int                     xmit_cnt;
-  struct semaphore        port_write_sem;
+  struct mutex            port_write_mutex;
   int                     flags;
   wait_queue_head_t       open_wait;
   wait_queue_head_t       close_wait;
diff -urN oldtree/include/linux/gigaset_dev.h newtree/include/linux/gigaset_dev.h
--- oldtree/include/linux/gigaset_dev.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/include/linux/gigaset_dev.h	2006-02-21 15:58:32.913143000 +0000
@@ -0,0 +1,32 @@
+/*
+ * interface to user space for the gigaset driver
+ *
+ * Copyright (c) 2004 by Hansjoerg Lipp <hjlipp@web.de>
+ *
+ * =====================================================================
+ *    This program is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU General Public License as
+ *    published by the Free Software Foundation; either version 2 of
+ *    the License, or (at your option) any later version.
+ * =====================================================================
+ * Version: $Id: gigaset_dev.h,v 1.4.4.4 2005/11/21 22:28:09 hjlipp Exp $
+ * =====================================================================
+ */
+
+#ifndef GIGASET_INTERFACE_H
+#define GIGASET_INTERFACE_H
+
+#include <linux/ioctl.h>
+
+#define GIGASET_IOCTL 0x47
+
+#define GIGVER_DRIVER 0
+#define GIGVER_COMPAT 1
+#define GIGVER_FWBASE 2
+
+#define GIGASET_REDIR    _IOWR (GIGASET_IOCTL, 0, int)
+#define GIGASET_CONFIG   _IOWR (GIGASET_IOCTL, 1, int)
+#define GIGASET_BRKCHARS _IOW  (GIGASET_IOCTL, 2, unsigned char[6]) //FIXME [6] okay?
+#define GIGASET_VERSION  _IOWR (GIGASET_IOCTL, 3, unsigned[4])
+
+#endif
diff -urN oldtree/include/linux/hwmon-sysfs.h newtree/include/linux/hwmon-sysfs.h
--- oldtree/include/linux/hwmon-sysfs.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/hwmon-sysfs.h	2006-02-21 15:58:14.056009720 +0000
@@ -27,11 +27,13 @@
 #define to_sensor_dev_attr(_dev_attr) \
 	container_of(_dev_attr, struct sensor_device_attribute, dev_attr)
 
-#define SENSOR_DEVICE_ATTR(_name,_mode,_show,_store,_index)	\
-struct sensor_device_attribute sensor_dev_attr_##_name = {	\
-	.dev_attr =	__ATTR(_name,_mode,_show,_store),	\
-	.index =	_index,					\
-}
+#define SENSOR_ATTR(_name, _mode, _show, _store, _index)	\
+	{ .dev_attr = __ATTR(_name, _mode, _show, _store),	\
+	  .index = _index }
+
+#define SENSOR_DEVICE_ATTR(_name, _mode, _show, _store, _index)	\
+struct sensor_device_attribute sensor_dev_attr_##_name		\
+	= SENSOR_ATTR(_name, _mode, _show, _store, _index)
 
 struct sensor_device_attribute_2 {
 	struct device_attribute dev_attr;
@@ -41,11 +43,13 @@
 #define to_sensor_dev_attr_2(_dev_attr) \
 	container_of(_dev_attr, struct sensor_device_attribute_2, dev_attr)
 
+#define SENSOR_ATTR_2(_name, _mode, _show, _store, _nr, _index)	\
+	{ .dev_attr = __ATTR(_name, _mode, _show, _store),	\
+	  .index = _index,					\
+	  .nr = _nr }
+
 #define SENSOR_DEVICE_ATTR_2(_name,_mode,_show,_store,_nr,_index)	\
-struct sensor_device_attribute_2 sensor_dev_attr_##_name = {	\
-	.dev_attr =	__ATTR(_name,_mode,_show,_store),	\
-	.index =	_index,					\
-	.nr =		_nr,					\
-}
+struct sensor_device_attribute_2 sensor_dev_attr_##_name		\
+	= SENSOR_ATTR_2(_name, _mode, _show, _store, _nr, _index)
 
 #endif /* _LINUX_HWMON_SYSFS_H */
diff -urN oldtree/include/linux/i2c-id.h newtree/include/linux/i2c-id.h
--- oldtree/include/linux/i2c-id.h	2006-02-19 11:41:05.800461296 +0000
+++ newtree/include/linux/i2c-id.h	2006-02-21 15:58:14.481944968 +0000
@@ -172,7 +172,6 @@
 #define I2C_HW_B_RIVA		0x010010 /* Riva based graphics cards */
 #define I2C_HW_B_IOC		0x010011 /* IOC bit-wiggling */
 #define I2C_HW_B_TSUNA		0x010012 /* DEC Tsunami chipset */
-#define I2C_HW_B_FRODO		0x010013 /* 2d3D SA-1110 Development Board */
 #define I2C_HW_B_OMAHA		0x010014 /* Omaha I2C interface (ARM) */
 #define I2C_HW_B_GUIDE		0x010015 /* Guide bit-basher */
 #define I2C_HW_B_IXP2000	0x010016 /* GPIO on IXP2000 systems */
diff -urN oldtree/include/linux/i2c.h newtree/include/linux/i2c.h
--- oldtree/include/linux/i2c.h	2006-02-19 11:41:05.801461144 +0000
+++ newtree/include/linux/i2c.h	2006-02-21 15:58:14.146995888 +0000
@@ -32,7 +32,7 @@
 #include <linux/mod_devicetable.h>
 #include <linux/device.h>	/* for struct device */
 #include <linux/sched.h>	/* for completion */
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 /* --- For i2c-isa ---------------------------------------------------- */
 
@@ -225,8 +225,8 @@
 	int (*client_unregister)(struct i2c_client *);
 
 	/* data fields that are valid for all devices	*/
-	struct semaphore bus_lock;
-	struct semaphore clist_lock;
+	struct mutex bus_lock;
+	struct mutex clist_lock;
 
 	int timeout;
 	int retries;
diff -urN oldtree/include/linux/i2o.h newtree/include/linux/i2o.h
--- oldtree/include/linux/i2o.h	2006-02-19 11:41:05.805460536 +0000
+++ newtree/include/linux/i2o.h	2006-02-21 15:58:30.970438336 +0000
@@ -950,9 +950,7 @@
 	if (!pool->slab)
 		goto free_name;
 
-	pool->mempool =
-	    mempool_create(min_nr, mempool_alloc_slab, mempool_free_slab,
-			   pool->slab);
+	pool->mempool = mempool_create_slab_pool(min_nr, pool->slab);
 	if (!pool->mempool)
 		goto free_slab;
 
diff -urN oldtree/include/linux/icmp.h newtree/include/linux/icmp.h
--- oldtree/include/linux/icmp.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/icmp.h	2006-02-21 15:58:36.844545336 +0000
@@ -68,16 +68,16 @@
 struct icmphdr {
   __u8		type;
   __u8		code;
-  __u16		checksum;
+  __be16	checksum;
   union {
 	struct {
-		__u16	id;
-		__u16	sequence;
+		__be16	id;
+		__be16	sequence;
 	} echo;
-	__u32	gateway;
+	__be32	gateway;
 	struct {
-		__u16	__unused;
-		__u16	mtu;
+		__be16	__unused;
+		__be16	mtu;
 	} frag;
   } un;
 };
diff -urN oldtree/include/linux/icmpv6.h newtree/include/linux/icmpv6.h
--- oldtree/include/linux/icmpv6.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/icmpv6.h	2006-02-21 15:58:36.844545336 +0000
@@ -7,17 +7,17 @@
 
 	__u8		icmp6_type;
 	__u8		icmp6_code;
-	__u16		icmp6_cksum;
+	__be16		icmp6_cksum;
 
 
 	union {
-		__u32			un_data32[1];
-		__u16			un_data16[2];
+		__be32			un_data32[1];
+		__be16			un_data16[2];
 		__u8			un_data8[4];
 
 		struct icmpv6_echo {
-			__u16		identifier;
-			__u16		sequence;
+			__be16		identifier;
+			__be16		sequence;
 		} u_echo;
 
                 struct icmpv6_nd_advt {
@@ -40,18 +40,20 @@
                 struct icmpv6_nd_ra {
 			__u8		hop_limit;
 #if defined(__LITTLE_ENDIAN_BITFIELD)
-			__u8		reserved:6,
+			__u8		reserved:4,
+					router_pref:2,
 					other:1,
 					managed:1;
 
 #elif defined(__BIG_ENDIAN_BITFIELD)
 			__u8		managed:1,
 					other:1,
-					reserved:6;
+					router_pref:2,
+					reserved:4;
 #else
 #error	"Please fix <asm/byteorder.h>"
 #endif
-			__u16		rt_lifetime;
+			__be16		rt_lifetime;
                 } u_nd_ra;
 
 	} icmp6_dataun;
@@ -70,8 +72,13 @@
 #define icmp6_addrconf_managed	icmp6_dataun.u_nd_ra.managed
 #define icmp6_addrconf_other	icmp6_dataun.u_nd_ra.other
 #define icmp6_rt_lifetime	icmp6_dataun.u_nd_ra.rt_lifetime
+#define icmp6_router_pref	icmp6_dataun.u_nd_ra.router_pref
 };
 
+#define ICMPV6_ROUTER_PREF_LOW		0x3
+#define ICMPV6_ROUTER_PREF_MEDIUM	0x0
+#define ICMPV6_ROUTER_PREF_HIGH		0x1
+#define ICMPV6_ROUTER_PREF_INVALID	0x2
 
 #define ICMPV6_DEST_UNREACH		1
 #define ICMPV6_PKT_TOOBIG		2
diff -urN oldtree/include/linux/if.h newtree/include/linux/if.h
--- oldtree/include/linux/if.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/if.h	2006-02-21 15:58:16.178687024 +0000
@@ -33,7 +33,7 @@
 #define	IFF_LOOPBACK	0x8		/* is a loopback net		*/
 #define	IFF_POINTOPOINT	0x10		/* interface is has p-p link	*/
 #define	IFF_NOTRAILERS	0x20		/* avoid use of trailers	*/
-#define	IFF_RUNNING	0x40		/* interface running and carrier ok */
+#define	IFF_RUNNING	0x40		/* interface RFC2863 OPER_UP	*/
 #define	IFF_NOARP	0x80		/* no ARP protocol		*/
 #define	IFF_PROMISC	0x100		/* receive all packets		*/
 #define	IFF_ALLMULTI	0x200		/* receive all multicast packets*/
@@ -43,12 +43,16 @@
 
 #define IFF_MULTICAST	0x1000		/* Supports multicast		*/
 
-#define IFF_VOLATILE	(IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_MASTER|IFF_SLAVE|IFF_RUNNING)
-
 #define IFF_PORTSEL	0x2000          /* can set media type		*/
 #define IFF_AUTOMEDIA	0x4000		/* auto media select active	*/
 #define IFF_DYNAMIC	0x8000		/* dialup device with changing addresses*/
 
+#define IFF_LOWER_UP	0x10000		/* driver signals L1 up		*/
+#define IFF_DORMANT	0x20000		/* driver signals dormant	*/
+
+#define IFF_VOLATILE	(IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|\
+		IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT)
+
 /* Private (from user) interface flags (netdevice->priv_flags). */
 #define IFF_802_1Q_VLAN 0x1             /* 802.1Q VLAN device.          */
 #define IFF_EBRIDGE	0x2		/* Ethernet bridging device.	*/
@@ -80,6 +84,22 @@
 #define IF_PROTO_FR_ETH_PVC 0x200B
 #define IF_PROTO_RAW    0x200C          /* RAW Socket                   */
 
+/* RFC 2863 operational status */
+enum {
+	IF_OPER_UNKNOWN,
+	IF_OPER_NOTPRESENT,
+	IF_OPER_DOWN,
+	IF_OPER_LOWERLAYERDOWN,
+	IF_OPER_TESTING,
+	IF_OPER_DORMANT,
+	IF_OPER_UP,
+};
+
+/* link modes */
+enum {
+	IF_LINK_MODE_DEFAULT,
+	IF_LINK_MODE_DORMANT,	/* limit upward transition to dormant */
+};
 
 /*
  *	Device mapping structure. I'd just gone off and designed a 
diff -urN oldtree/include/linux/if_arp.h newtree/include/linux/if_arp.h
--- oldtree/include/linux/if_arp.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/if_arp.h	2006-02-21 15:58:36.845545184 +0000
@@ -130,11 +130,11 @@
 
 struct arphdr
 {
-	unsigned short	ar_hrd;		/* format of hardware address	*/
-	unsigned short	ar_pro;		/* format of protocol address	*/
+	__be16		ar_hrd;		/* format of hardware address	*/
+	__be16		ar_pro;		/* format of protocol address	*/
 	unsigned char	ar_hln;		/* length of hardware address	*/
 	unsigned char	ar_pln;		/* length of protocol address	*/
-	unsigned short	ar_op;		/* ARP opcode (command)		*/
+	__be16		ar_op;		/* ARP opcode (command)		*/
 
 #if 0
 	 /*
diff -urN oldtree/include/linux/if_tunnel.h newtree/include/linux/if_tunnel.h
--- oldtree/include/linux/if_tunnel.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/if_tunnel.h	2006-02-21 15:58:36.847544880 +0000
@@ -19,10 +19,10 @@
 {
 	char			name[IFNAMSIZ];
 	int			link;
-	__u16			i_flags;
-	__u16			o_flags;
-	__u32			i_key;
-	__u32			o_key;
+	__be16			i_flags;
+	__be16			o_flags;
+	__be32			i_key;
+	__be32			o_key;
 	struct iphdr		iph;
 };
 
diff -urN oldtree/include/linux/if_vlan.h newtree/include/linux/if_vlan.h
--- oldtree/include/linux/if_vlan.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/if_vlan.h	2006-02-21 15:58:36.847544880 +0000
@@ -44,7 +44,7 @@
    unsigned char	h_source[ETH_ALEN];	   /* source ether addr	*/
    __be16               h_vlan_proto;              /* Should always be 0x8100 */
    __be16               h_vlan_TCI;                /* Encapsulates priority and VLAN ID */
-   unsigned short	h_vlan_encapsulated_proto; /* packet type ID field (or len) */
+   __be16		h_vlan_encapsulated_proto; /* packet type ID field (or len) */
 };
 
 #include <linux/skbuff.h>
diff -urN oldtree/include/linux/igmp.h newtree/include/linux/igmp.h
--- oldtree/include/linux/igmp.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/igmp.h	2006-02-21 15:58:36.848544728 +0000
@@ -30,8 +30,8 @@
 {
 	__u8 type;
 	__u8 code;		/* For newer IGMP */
-	__u16 csum;
-	__u32 group;
+	__be16 csum;
+	__be32 group;
 };
 
 /* V3 group record types [grec_type] */
@@ -45,25 +45,25 @@
 struct igmpv3_grec {
 	__u8	grec_type;
 	__u8	grec_auxwords;
-	__u16	grec_nsrcs;
-	__u32	grec_mca;
-	__u32	grec_src[0];
+	__be16	grec_nsrcs;
+	__be32	grec_mca;
+	__be32	grec_src[0];
 };
 
 struct igmpv3_report {
 	__u8 type;
 	__u8 resv1;
-	__u16 csum;
-	__u16 resv2;
-	__u16 ngrec;
+	__be16 csum;
+	__be16 resv2;
+	__be16 ngrec;
 	struct igmpv3_grec grec[0];
 };
 
 struct igmpv3_query {
 	__u8 type;
 	__u8 code;
-	__u16 csum;
-	__u32 group;
+	__be16 csum;
+	__be32 group;
 #if defined(__LITTLE_ENDIAN_BITFIELD)
 	__u8 qrv:3,
 	     suppress:1,
@@ -76,8 +76,8 @@
 #error "Please fix <asm/byteorder.h>"
 #endif
 	__u8 qqic;
-	__u16 nsrcs;
-	__u32 srcs[0];
+	__be16 nsrcs;
+	__be32 srcs[0];
 };
 
 #define IGMP_HOST_MEMBERSHIP_QUERY	0x11	/* From RFC1112 */
@@ -136,11 +136,11 @@
 {
 	unsigned int		sl_max;
 	unsigned int		sl_count;
-	__u32			sl_addr[0];
+	__be32			sl_addr[0];
 };
 
 #define IP_SFLSIZE(count)	(sizeof(struct ip_sf_socklist) + \
-	(count) * sizeof(__u32))
+	(count) * sizeof(__be32))
 
 #define IP_SFBLOCK	10	/* allocate this many at once */
 
@@ -159,7 +159,7 @@
 struct ip_sf_list
 {
 	struct ip_sf_list	*sf_next;
-	__u32			sf_inaddr;
+	__be32			sf_inaddr;
 	unsigned long		sf_count[2];	/* include/exclude counts */
 	unsigned char		sf_gsresp;	/* include in g & s response? */
 	unsigned char		sf_oldin;	/* change state */
@@ -169,7 +169,7 @@
 struct ip_mc_list
 {
 	struct in_device	*interface;
-	unsigned long		multiaddr;
+	__be32			multiaddr;
 	struct ip_sf_list	*sources;
 	struct ip_sf_list	*tomb;
 	unsigned int		sfmode;
@@ -197,7 +197,7 @@
 #define IGMPV3_QQIC(value) IGMPV3_EXP(0x80, 4, 3, value)
 #define IGMPV3_MRC(value) IGMPV3_EXP(0x80, 4, 3, value)
 
-extern int ip_check_mc(struct in_device *dev, u32 mc_addr, u32 src_addr, u16 proto);
+extern int ip_check_mc(struct in_device *dev, __be32 mc_addr, __be32 src_addr, u16 proto);
 extern int igmp_rcv(struct sk_buff *);
 extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr);
 extern int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr);
@@ -209,13 +209,13 @@
 		struct ip_msfilter __user *optval, int __user *optlen);
 extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
 		struct group_filter __user *optval, int __user *optlen);
-extern int ip_mc_sf_allow(struct sock *sk, u32 local, u32 rmt, int dif);
+extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt, int dif);
 extern void ip_mr_init(void);
 extern void ip_mc_init_dev(struct in_device *);
 extern void ip_mc_destroy_dev(struct in_device *);
 extern void ip_mc_up(struct in_device *);
 extern void ip_mc_down(struct in_device *);
-extern void ip_mc_dec_group(struct in_device *in_dev, u32 addr);
-extern void ip_mc_inc_group(struct in_device *in_dev, u32 addr);
+extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);
+extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);
 #endif
 #endif
diff -urN oldtree/include/linux/in.h newtree/include/linux/in.h
--- oldtree/include/linux/in.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/in.h	2006-02-21 15:58:36.850544424 +0000
@@ -52,7 +52,7 @@
 
 /* Internet address. */
 struct in_addr {
-	__u32	s_addr;
+	__be32	s_addr;
 };
 
 #define IP_TOS		1
@@ -122,17 +122,17 @@
 };
 
 struct ip_mreq_source {
-	__u32		imr_multiaddr;
-	__u32		imr_interface;
-	__u32		imr_sourceaddr;
+	__be32		imr_multiaddr;
+	__be32		imr_interface;
+	__be32		imr_sourceaddr;
 };
 
 struct ip_msfilter {
-	__u32		imsf_multiaddr;
-	__u32		imsf_interface;
+	__be32		imsf_multiaddr;
+	__be32		imsf_interface;
 	__u32		imsf_fmode;
 	__u32		imsf_numsrc;
-	__u32		imsf_slist[1];
+	__be32		imsf_slist[1];
 };
 
 #define IP_MSFILTER_SIZE(numsrc) \
@@ -176,7 +176,7 @@
 #define __SOCK_SIZE__	16		/* sizeof(struct sockaddr)	*/
 struct sockaddr_in {
   sa_family_t		sin_family;	/* Address family		*/
-  unsigned short int	sin_port;	/* Port number			*/
+  __be16		sin_port;	/* Port number			*/
   struct in_addr	sin_addr;	/* Internet address		*/
 
   /* Pad to size of `struct sockaddr'. */
@@ -222,7 +222,11 @@
 #define	INADDR_BROADCAST	((unsigned long int) 0xffffffff)
 
 /* Address indicating an error return. */
+#ifndef __KERNEL__
 #define	INADDR_NONE		((unsigned long int) 0xffffffff)
+#else
+#define	INADDR_NONE		__constant_htonl(0xffffffff)
+#endif
 
 /* Network number for local host loopback. */
 #define	IN_LOOPBACKNET		127
diff -urN oldtree/include/linux/in6.h newtree/include/linux/in6.h
--- oldtree/include/linux/in6.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/in6.h	2006-02-21 15:58:36.849544576 +0000
@@ -32,8 +32,8 @@
 	union 
 	{
 		__u8		u6_addr8[16];
-		__u16		u6_addr16[8];
-		__u32		u6_addr32[4];
+		__be16		u6_addr16[8];
+		__be32		u6_addr32[4];
 	} in6_u;
 #define s6_addr			in6_u.u6_addr8
 #define s6_addr16		in6_u.u6_addr16
@@ -53,8 +53,8 @@
 
 struct sockaddr_in6 {
 	unsigned short int	sin6_family;    /* AF_INET6 */
-	__u16			sin6_port;      /* Transport layer port # */
-	__u32			sin6_flowinfo;  /* IPv6 flow information */
+	__be16			sin6_port;      /* Transport layer port # */
+	__be32			sin6_flowinfo;  /* IPv6 flow information */
 	struct in6_addr		sin6_addr;      /* IPv6 address */
 	__u32			sin6_scope_id;  /* scope id (new in RFC2553) */
 };
@@ -72,7 +72,7 @@
 struct in6_flowlabel_req
 {
 	struct in6_addr	flr_dst;
-	__u32	flr_label;
+	__be32	flr_label;
 	__u8	flr_action;
 	__u8	flr_share;
 	__u16	flr_flags;
diff -urN oldtree/include/linux/inet_diag.h newtree/include/linux/inet_diag.h
--- oldtree/include/linux/inet_diag.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/inet_diag.h	2006-02-21 15:58:36.849544576 +0000
@@ -9,10 +9,10 @@
 
 /* Socket identity */
 struct inet_diag_sockid {
-	__u16	idiag_sport;
-	__u16	idiag_dport;
-	__u32	idiag_src[4];
-	__u32	idiag_dst[4];
+	__be16	idiag_sport;
+	__be16	idiag_dport;
+	__be32	idiag_src[4];
+	__be32	idiag_dst[4];
 	__u32	idiag_if;
 	__u32	idiag_cookie[2];
 #define INET_DIAG_NOCOOKIE (~0U)
@@ -67,7 +67,7 @@
 	__u8	family;
 	__u8	prefix_len;
 	int	port;
-	__u32	addr[0];
+	__be32	addr[0];
 };
 
 /* Base info structure. It contains socket identity (addrs/ports/cookie)
diff -urN oldtree/include/linux/inetdevice.h newtree/include/linux/inetdevice.h
--- oldtree/include/linux/inetdevice.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/inetdevice.h	2006-02-21 15:58:36.849544576 +0000
@@ -89,11 +89,11 @@
 	struct in_ifaddr	*ifa_next;
 	struct in_device	*ifa_dev;
 	struct rcu_head		rcu_head;
-	u32			ifa_local;
-	u32			ifa_address;
-	u32			ifa_mask;
-	u32			ifa_broadcast;
-	u32			ifa_anycast;
+	__be32			ifa_local;
+	__be32			ifa_address;
+	__be32			ifa_mask;
+	__be32			ifa_broadcast;
+	__be32			ifa_anycast;
 	unsigned char		ifa_scope;
 	unsigned char		ifa_flags;
 	unsigned char		ifa_prefixlen;
@@ -103,18 +103,18 @@
 extern int register_inetaddr_notifier(struct notifier_block *nb);
 extern int unregister_inetaddr_notifier(struct notifier_block *nb);
 
-extern struct net_device 	*ip_dev_find(u32 addr);
-extern int		inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b);
+extern struct net_device 	*ip_dev_find(__be32 addr);
+extern int		inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b);
 extern int		devinet_ioctl(unsigned int cmd, void __user *);
 extern void		devinet_init(void);
 extern struct in_device *inetdev_init(struct net_device *dev);
 extern struct in_device	*inetdev_by_index(int);
-extern u32		inet_select_addr(const struct net_device *dev, u32 dst, int scope);
-extern u32		inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope);
-extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask);
+extern __be32		inet_select_addr(const struct net_device *dev, __be32 dst, int scope);
+extern __be32		inet_confirm_addr(const struct net_device *dev, __be32 dst, __be32 local, int scope);
+extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, __be32 mask);
 extern void		inet_forward_change(void);
 
-static __inline__ int inet_ifa_match(u32 addr, struct in_ifaddr *ifa)
+static __inline__ int inet_ifa_match(__be32 addr, struct in_ifaddr *ifa)
 {
 	return !((addr^ifa->ifa_address)&ifa->ifa_mask);
 }
@@ -123,12 +123,13 @@
  *	Check if a mask is acceptable.
  */
  
-static __inline__ int bad_mask(u32 mask, u32 addr)
+static __inline__ int bad_mask(__be32 mask, __be32 addr)
 {
+	__u32 hmask;
 	if (addr & (mask = ~mask))
 		return 1;
-	mask = ntohl(mask);
-	if (mask & (mask+1))
+	hmask = ntohl(mask);
+	if (hmask & (hmask+1))
 		return 1;
 	return 0;
 }
@@ -182,18 +183,19 @@
 
 #endif /* __KERNEL__ */
 
-static __inline__ __u32 inet_make_mask(int logmask)
+static __inline__ __be32 inet_make_mask(int logmask)
 {
 	if (logmask)
 		return htonl(~((1<<(32-logmask))-1));
 	return 0;
 }
 
-static __inline__ int inet_mask_len(__u32 mask)
+static __inline__ int inet_mask_len(__be32 mask)
 {
-	if (!(mask = ntohl(mask)))
+	__u32 hmask = ntohl(mask);
+	if (!hmask)
 		return 0;
-	return 32 - ffz(~mask);
+	return 32 - ffz(~hmask);
 }
 
 
diff -urN oldtree/include/linux/init_task.h newtree/include/linux/init_task.h
--- oldtree/include/linux/init_task.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/init_task.h	2006-02-21 15:58:23.611557056 +0000
@@ -7,11 +7,10 @@
 #define INIT_FDTABLE \
 {							\
 	.max_fds	= NR_OPEN_DEFAULT, 		\
-	.max_fdset	= __FD_SETSIZE, 		\
-	.next_fd	= 0, 				\
+	.max_fdset	= EMBEDDED_FD_SET_SIZE,		\
 	.fd		= &init_files.fd_array[0], 	\
-	.close_on_exec	= &init_files.close_on_exec_init, \
-	.open_fds	= &init_files.open_fds_init, 	\
+	.close_on_exec	= (fd_set *)&init_files.close_on_exec_init, \
+	.open_fds	= (fd_set *)&init_files.open_fds_init, 	\
 	.rcu		= RCU_HEAD_INIT, 		\
 	.free_files	= NULL,		 		\
 	.next		= NULL,		 		\
@@ -20,9 +19,10 @@
 #define INIT_FILES \
 { 							\
 	.count		= ATOMIC_INIT(1), 		\
-	.file_lock	= SPIN_LOCK_UNLOCKED, 		\
 	.fdt		= &init_files.fdtab, 		\
 	.fdtab		= INIT_FDTABLE,			\
+	.file_lock	= SPIN_LOCK_UNLOCKED, 		\
+	.next_fd	= 0, 				\
 	.close_on_exec_init = { { 0, } }, 		\
 	.open_fds_init	= { { 0, } }, 			\
 	.fd_array	= { NULL, } 			\
diff -urN oldtree/include/linux/inotify.h newtree/include/linux/inotify.h
--- oldtree/include/linux/inotify.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/inotify.h	2006-02-21 15:58:11.867342448 +0000
@@ -14,6 +14,9 @@
  *
  * When you are watching a directory, you will receive the filename for events
  * such as IN_CREATE, IN_DELETE, IN_OPEN, IN_CLOSE, ..., relative to the wd.
+ *
+ * When using inotify from the kernel, len will always be zero.  Instead you
+ * should check the path for non-NULL in your callback.
  */
 struct inotify_event {
 	__s32		wd;		/* watch descriptor */
@@ -71,8 +74,19 @@
 
 #ifdef CONFIG_INOTIFY
 
+/* Kernel consumer API */
+
+extern struct inotify_device *inotify_init(void (*)(struct inotify_event *,
+						    const char *,
+						    struct inode *, void *));
+extern int inotify_free(struct inotify_device *);
+extern __s32 inotify_add_watch(struct inotify_device *, struct inode *, __u32,
+			       void *);
+extern int inotify_ignore(struct inotify_device *, __s32);
+
+/* Kernel producer API */
 extern void inotify_inode_queue_event(struct inode *, __u32, __u32,
-				      const char *);
+				      const char *, struct inode *);
 extern void inotify_dentry_parent_queue_event(struct dentry *, __u32, __u32,
 					      const char *);
 extern void inotify_unmount_inodes(struct list_head *);
@@ -81,9 +95,9 @@
 
 #else
 
-static inline void inotify_inode_queue_event(struct inode *inode,
-					     __u32 mask, __u32 cookie,
-					     const char *filename)
+/* Kernel producer API stubs */
+static inline void inotify_inode_queue_event(struct inode *inode, u32 mask,
+			u32 cookie, const char *name, struct inode *cinode)
 {
 }
 
diff -urN oldtree/include/linux/ip.h newtree/include/linux/ip.h
--- oldtree/include/linux/ip.h	2006-02-19 11:41:05.873450200 +0000
+++ newtree/include/linux/ip.h	2006-02-21 15:58:36.850544424 +0000
@@ -95,7 +95,7 @@
 	__be16	frag_off;
 	__u8	ttl;
 	__u8	protocol;
-	__u16	check;
+	__be16	check;
 	__be32	saddr;
 	__be32	daddr;
 	/*The options start here. */
@@ -104,22 +104,22 @@
 struct ip_auth_hdr {
 	__u8  nexthdr;
 	__u8  hdrlen;		/* This one is measured in 32 bit units! */
-	__u16 reserved;
-	__u32 spi;
-	__u32 seq_no;		/* Sequence number */
+	__be16 reserved;
+	__be32 spi;
+	__be32 seq_no;		/* Sequence number */
 	__u8  auth_data[0];	/* Variable len but >=4. Mind the 64 bit alignment! */
 };
 
 struct ip_esp_hdr {
-	__u32 spi;
-	__u32 seq_no;		/* Sequence number */
+	__be32 spi;
+	__be32 seq_no;		/* Sequence number */
 	__u8  enc_data[0];	/* Variable len but >=8. Mind the 64 bit alignment! */
 };
 
 struct ip_comp_hdr {
 	__u8 nexthdr;
 	__u8 flags;
-	__u16 cpi;
+	__be16 cpi;
 };
 
 #endif	/* _LINUX_IP_H */
diff -urN oldtree/include/linux/ipv6.h newtree/include/linux/ipv6.h
--- oldtree/include/linux/ipv6.h	2006-02-19 11:41:05.874450048 +0000
+++ newtree/include/linux/ipv6.h	2006-02-21 15:58:36.851544272 +0000
@@ -77,22 +77,22 @@
 struct ipv6_auth_hdr {
 	__u8  nexthdr;
 	__u8  hdrlen;           /* This one is measured in 32 bit units! */
-	__u16 reserved;
-	__u32 spi;
-	__u32 seq_no;           /* Sequence number */
+	__be16 reserved;
+	__be32 spi;
+	__be32 seq_no;           /* Sequence number */
 	__u8  auth_data[0];     /* Length variable but >=4. Mind the 64 bit alignment! */
 };
 
 struct ipv6_esp_hdr {
-	__u32 spi;
-	__u32 seq_no;           /* Sequence number */
+	__be32 spi;
+	__be32 seq_no;           /* Sequence number */
 	__u8  enc_data[0];      /* Length variable but >=8. Mind the 64 bit alignment! */
 };
 
 struct ipv6_comp_hdr {
 	__u8 nexthdr;
 	__u8 flags;
-	__u16 cpi;
+	__be16 cpi;
 };
 
 /*
@@ -114,7 +114,7 @@
 #endif
 	__u8			flow_lbl[3];
 
-	__u16			payload_len;
+	__be16			payload_len;
 	__u8			nexthdr;
 	__u8			hop_limit;
 
@@ -145,6 +145,15 @@
 	__s32		max_desync_factor;
 #endif
 	__s32		max_addresses;
+	__s32		accept_ra_defrtr;
+	__s32		accept_ra_pinfo;
+#ifdef CONFIG_IPV6_ROUTER_PREF
+	__s32		accept_ra_rtr_pref;
+	__s32		rtr_probe_interval;
+#ifdef CONFIG_IPV6_ROUTE_INFO
+	__s32		accept_ra_rt_info_max_plen;
+#endif
+#endif
 	void		*sysctl;
 };
 
@@ -167,6 +176,11 @@
 	DEVCONF_MAX_DESYNC_FACTOR,
 	DEVCONF_MAX_ADDRESSES,
 	DEVCONF_FORCE_MLD_VERSION,
+	DEVCONF_ACCEPT_RA_DEFRTR,
+	DEVCONF_ACCEPT_RA_PINFO,
+	DEVCONF_ACCEPT_RA_RTR_PREF,
+	DEVCONF_RTR_PROBE_INTERVAL,
+	DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN,
 	DEVCONF_MAX
 };
 
@@ -230,7 +244,7 @@
 	struct in6_addr		daddr;
 	struct in6_addr		*daddr_cache;
 
-	__u32			flow_label;
+	__be32			flow_label;
 	__u32			frag_size;
 	__s16			hop_limit;
 	__s16			mcast_hops;
diff -urN oldtree/include/linux/ipv6_route.h newtree/include/linux/ipv6_route.h
--- oldtree/include/linux/ipv6_route.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/ipv6_route.h	2006-02-21 15:58:16.185685960 +0000
@@ -23,12 +23,22 @@
 #define RTF_NONEXTHOP	0x00200000	/* route with no nexthop	*/
 #define RTF_EXPIRES	0x00400000
 
+#define RTF_ROUTEINFO	0x00800000	/* route information - RA	*/
+
 #define RTF_CACHE	0x01000000	/* cache entry			*/
 #define RTF_FLOW	0x02000000	/* flow significant route	*/
 #define RTF_POLICY	0x04000000	/* policy route			*/
 
+#define RTF_PREF(pref)	((pref) << 27)
+#define RTF_PREF_MASK	0x18000000
+
 #define RTF_LOCAL	0x80000000
 
+#ifdef __KERNEL__
+#define IPV6_EXTRACT_PREF(flag)	(((flag) & RTF_PREF_MASK) >> 27)
+#define IPV6_DECODE_PREF(pref)	((pref) ^ 2)	/* 1:low,2:med,3:high */
+#endif
+
 struct in6_rtmsg {
 	struct in6_addr		rtmsg_dst;
 	struct in6_addr		rtmsg_src;
diff -urN oldtree/include/linux/jbd.h newtree/include/linux/jbd.h
--- oldtree/include/linux/jbd.h	2006-02-19 11:41:05.876449744 +0000
+++ newtree/include/linux/jbd.h	2006-02-21 15:58:25.971198336 +0000
@@ -28,6 +28,7 @@
 #include <linux/journal-head.h>
 #include <linux/stddef.h>
 #include <linux/bit_spinlock.h>
+#include <linux/mutex.h>
 #include <asm/semaphore.h>
 #endif
 
@@ -575,7 +576,7 @@
  * @j_wait_checkpoint:  Wait queue to trigger checkpointing
  * @j_wait_commit: Wait queue to trigger commit
  * @j_wait_updates: Wait queue to wait for updates to complete
- * @j_checkpoint_sem: Semaphore for locking against concurrent checkpoints
+ * @j_checkpoint_mutex: Mutex for locking against concurrent checkpoints
  * @j_head: Journal head - identifies the first unused block in the journal
  * @j_tail: Journal tail - identifies the oldest still-used block in the
  *  journal.
@@ -645,7 +646,7 @@
 	int			j_barrier_count;
 
 	/* The barrier lock itself */
-	struct semaphore	j_barrier;
+	struct mutex		j_barrier;
 
 	/*
 	 * Transactions: The current running transaction...
@@ -687,7 +688,7 @@
 	wait_queue_head_t	j_wait_updates;
 
 	/* Semaphore for locking against concurrent checkpoints */
-	struct semaphore 	j_checkpoint_sem;
+	struct mutex	 	j_checkpoint_mutex;
 
 	/*
 	 * Journal head: identifies the first unused block in the journal.
diff -urN oldtree/include/linux/kobj_map.h newtree/include/linux/kobj_map.h
--- oldtree/include/linux/kobj_map.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/kobj_map.h	2006-02-21 15:58:12.591232400 +0000
@@ -1,6 +1,6 @@
 #ifdef __KERNEL__
 
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 typedef struct kobject *kobj_probe_t(dev_t, int *, void *);
 struct kobj_map;
@@ -9,6 +9,6 @@
 	     kobj_probe_t *, int (*)(dev_t, void *), void *);
 void kobj_unmap(struct kobj_map *, dev_t, unsigned long);
 struct kobject *kobj_lookup(struct kobj_map *, dev_t, int *);
-struct kobj_map *kobj_map_init(kobj_probe_t *, struct semaphore *);
+struct kobj_map *kobj_map_init(kobj_probe_t *, struct mutex *);
 
 #endif
diff -urN oldtree/include/linux/kobject.h newtree/include/linux/kobject.h
--- oldtree/include/linux/kobject.h	2006-02-19 11:41:05.880449136 +0000
+++ newtree/include/linux/kobject.h	2006-02-21 15:58:12.340270552 +0000
@@ -24,6 +24,7 @@
 #include <linux/rwsem.h>
 #include <linux/kref.h>
 #include <linux/kernel.h>
+#include <linux/wait.h>
 #include <asm/atomic.h>
 
 #define KOBJ_NAME_LEN			20
@@ -54,6 +55,7 @@
 	struct kset		* kset;
 	struct kobj_type	* ktype;
 	struct dentry		* dentry;
+	wait_queue_head_t	poll;
 };
 
 extern int kobject_set_name(struct kobject *, const char *, ...)
diff -urN oldtree/include/linux/kprobes.h newtree/include/linux/kprobes.h
--- oldtree/include/linux/kprobes.h	2006-02-19 11:41:05.881448984 +0000
+++ newtree/include/linux/kprobes.h	2006-02-21 15:58:26.058185112 +0000
@@ -36,6 +36,7 @@
 #include <linux/percpu.h>
 #include <linux/spinlock.h>
 #include <linux/rcupdate.h>
+#include <linux/mutex.h>
 
 #ifdef CONFIG_KPROBES
 #include <asm/kprobes.h>
@@ -152,7 +153,7 @@
 };
 
 extern spinlock_t kretprobe_lock;
-extern struct semaphore kprobe_mutex;
+extern struct mutex kprobe_mutex;
 extern int arch_prepare_kprobe(struct kprobe *p);
 extern void arch_arm_kprobe(struct kprobe *p);
 extern void arch_disarm_kprobe(struct kprobe *p);
diff -urN oldtree/include/linux/leds.h newtree/include/linux/leds.h
--- oldtree/include/linux/leds.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/include/linux/leds.h	2006-02-21 15:58:31.165408696 +0000
@@ -0,0 +1,105 @@
+/*
+ * Driver model for leds and led triggers
+ *
+ * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
+ * Copyright (C) 2005 Richard Purdie <rpurdie@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#ifndef __LINUX_LEDS_H_INCLUDED
+#define __LINUX_LEDS_H_INCLUDED
+
+struct device;
+struct class_device;
+/*
+ * LED Core
+ */
+
+enum led_brightness {
+	LED_OFF = 0,
+	LED_HALF = 127,
+	LED_FULL = 255,
+};
+
+struct led_classdev {
+	const char *name;
+	int brightness;
+	int flags;
+#define LED_SUSPENDED       (1 << 0)
+
+	/* A function to set the brightness of the led */
+	void (*brightness_set)(struct led_classdev *led_cdev,
+				enum led_brightness brightness);
+
+	struct class_device *class_dev;
+	/* LED Device linked list */
+	struct list_head node;
+
+	/* Protects the LED properties data above */
+	rwlock_t lock;
+
+	/* Trigger data */
+	char *default_trigger;
+#ifdef CONFIG_LEDS_TRIGGERS
+	rwlock_t trigger_lock;
+	/* Protects the trigger data below */
+
+	struct led_trigger *trigger;
+	struct list_head trig_list;
+	void *trigger_data;
+#endif
+};
+
+extern int led_classdev_register(struct device *parent,
+				struct led_classdev *led_cdev);
+extern void led_classdev_unregister(struct led_classdev *led_cdev);
+extern void led_classdev_suspend(struct led_classdev *led_cdev);
+extern void led_classdev_resume(struct led_classdev *led_cdev);
+
+/*
+ * LED Triggers
+ */
+#ifdef CONFIG_LEDS_TRIGGERS
+
+#define TRIG_NAME_MAX 50
+
+struct led_trigger {
+	/* Trigger Properties */
+	const char *name;
+	void (*activate)(struct led_classdev *led_cdev);
+	void (*deactivate)(struct led_classdev *led_cdev);
+
+	/* LEDs under control by this trigger (for simple triggers) */
+	rwlock_t leddev_list_lock;
+	struct list_head led_cdevs;
+
+	/* Link to next registered trigger */
+	struct list_head next_trig;
+};
+
+/* Registration functions for complex triggers */
+int led_trigger_register(struct led_trigger *trigger);
+void led_trigger_unregister(struct led_trigger *trigger);
+
+/* Registration functions for simple triggers */
+#define DEFINE_LED_TRIGGER(x)		static struct led_trigger *x;
+#define DEFINE_LED_TRIGGER_GLOBAL(x)	struct led_trigger *x;
+void led_trigger_register_simple(const char *name,
+				struct led_trigger **trigger);
+void led_trigger_unregister_simple(struct led_trigger *trigger);
+void led_trigger_event(struct led_trigger *trigger, enum led_brightness event);
+
+#else
+
+/* Triggers aren't active - null macros */
+#define DEFINE_LED_TRIGGER(x)
+#define DEFINE_LED_TRIGGER_GLOBAL(x)
+#define led_trigger_register_simple(x, y) do {} while(0)
+#define led_trigger_unregister_simple(x) do {} while(0)
+#define led_trigger_event(x, y) do {} while(0)
+
+#endif
+#endif		/* __LINUX_LEDS_H_INCLUDED */
diff -urN oldtree/include/linux/list.h newtree/include/linux/list.h
--- oldtree/include/linux/list.h	2006-02-19 11:41:05.884448528 +0000
+++ newtree/include/linux/list.h	2006-02-21 15:58:23.521570736 +0000
@@ -411,6 +411,29 @@
 	     pos = list_entry(pos->member.next, typeof(*pos), member))
 
 /**
+ * list_for_each_entry_from -	iterate over list of given type
+ *			continuing from existing point
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_from(pos, head, member) 			\
+	for (; prefetch(pos->member.next), &pos->member != (head);	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue_reverse -       iterate backwards over list
+ *                      of given type continuing before existing point
+ * @pos:        the type * to use as a loop counter.
+ * @head:       the head for your list.
+ * @member:     the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_continue_reverse(pos, head, member)                 \
+        for (pos = list_entry(pos->member.prev, typeof(*pos), member);  \
+             prefetch(pos->member.prev), &pos->member != (head);        \
+             pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
  * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
  * @pos:	the type * to use as a loop counter.
  * @n:		another type * to use as temporary storage
@@ -438,6 +461,19 @@
 	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
 
 /**
+ * list_for_each_entry_safe_from - iterate over list of given type
+ *			from existing point safe against removal of list entry
+ * @pos:	the type * to use as a loop counter.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member) 			\
+	for (n = list_entry(pos->member.next, typeof(*pos), member);		\
+	     &pos->member != (head);						\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
  * list_for_each_entry_safe_reverse - iterate backwards over list of given type safe against
  *				      removal of list entry
  * @pos:	the type * to use as a loop counter.
diff -urN oldtree/include/linux/lockd/lockd.h newtree/include/linux/lockd/lockd.h
--- oldtree/include/linux/lockd/lockd.h	2006-02-19 11:41:05.884448528 +0000
+++ newtree/include/linux/lockd/lockd.h	2006-02-21 15:58:36.857543360 +0000
@@ -149,7 +149,7 @@
 int		  nlmclnt_prepare_block(struct nlm_rqst *req, struct nlm_host *host, struct file_lock *fl);
 void		  nlmclnt_finish_block(struct nlm_rqst *req);
 long		  nlmclnt_block(struct nlm_rqst *req, long timeout);
-u32		  nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *);
+__be32		  nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *);
 void		  nlmclnt_recovery(struct nlm_host *, u32);
 int		  nlmclnt_reclaim(struct nlm_host *, struct file_lock *);
 int		  nlmclnt_setgrantargs(struct nlm_rqst *, struct nlm_lock *);
@@ -173,12 +173,12 @@
  * Server-side lock handling
  */
 int		  nlmsvc_async_call(struct nlm_rqst *, u32, const struct rpc_call_ops *);
-u32		  nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
+__be32		  nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
 					struct nlm_lock *, int, struct nlm_cookie *);
-u32		  nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
-u32		  nlmsvc_testlock(struct nlm_file *, struct nlm_lock *,
+__be32		  nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
+__be32		  nlmsvc_testlock(struct nlm_file *, struct nlm_lock *,
 					struct nlm_lock *);
-u32		  nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *);
+__be32		  nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *);
 unsigned long	  nlmsvc_retry_blocked(void);
 int		  nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *,
 					int action);
@@ -187,7 +187,7 @@
 /*
  * File handling for the server personality
  */
-u32		  nlm_lookup_file(struct svc_rqst *, struct nlm_file **,
+__be32		  nlm_lookup_file(struct svc_rqst *, struct nlm_file **,
 					struct nfs_fh *);
 void		  nlm_release_file(struct nlm_file *);
 void		  nlmsvc_mark_resources(void);
diff -urN oldtree/include/linux/lockd/share.h newtree/include/linux/lockd/share.h
--- oldtree/include/linux/lockd/share.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/lockd/share.h	2006-02-21 15:58:36.858543208 +0000
@@ -21,9 +21,9 @@
 	u32			s_mode;		/* deny mode */
 };
 
-u32	nlmsvc_share_file(struct nlm_host *, struct nlm_file *,
+__be32	nlmsvc_share_file(struct nlm_host *, struct nlm_file *,
 					       struct nlm_args *);
-u32	nlmsvc_unshare_file(struct nlm_host *, struct nlm_file *,
+__be32	nlmsvc_unshare_file(struct nlm_host *, struct nlm_file *,
 					       struct nlm_args *);
 int	nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *, int);
 
diff -urN oldtree/include/linux/lockd/xdr.h newtree/include/linux/lockd/xdr.h
--- oldtree/include/linux/lockd/xdr.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/lockd/xdr.h	2006-02-21 15:58:36.859543056 +0000
@@ -85,19 +85,19 @@
  */
 #define NLMSVC_XDRSIZE		sizeof(struct nlm_args)
 
-int	nlmsvc_decode_testargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int	nlmsvc_encode_testres(struct svc_rqst *, u32 *, struct nlm_res *);
-int	nlmsvc_decode_lockargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int	nlmsvc_decode_cancargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int	nlmsvc_decode_unlockargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int	nlmsvc_encode_res(struct svc_rqst *, u32 *, struct nlm_res *);
-int	nlmsvc_decode_res(struct svc_rqst *, u32 *, struct nlm_res *);
-int	nlmsvc_encode_void(struct svc_rqst *, u32 *, void *);
-int	nlmsvc_decode_void(struct svc_rqst *, u32 *, void *);
-int	nlmsvc_decode_shareargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int	nlmsvc_encode_shareres(struct svc_rqst *, u32 *, struct nlm_res *);
-int	nlmsvc_decode_notify(struct svc_rqst *, u32 *, struct nlm_args *);
-int	nlmsvc_decode_reboot(struct svc_rqst *, u32 *, struct nlm_reboot *);
+int	nlmsvc_decode_testargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int	nlmsvc_encode_testres(struct svc_rqst *, __be32 *, struct nlm_res *);
+int	nlmsvc_decode_lockargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int	nlmsvc_decode_cancargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int	nlmsvc_decode_unlockargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int	nlmsvc_encode_res(struct svc_rqst *, __be32 *, struct nlm_res *);
+int	nlmsvc_decode_res(struct svc_rqst *, __be32 *, struct nlm_res *);
+int	nlmsvc_encode_void(struct svc_rqst *, __be32 *, void *);
+int	nlmsvc_decode_void(struct svc_rqst *, __be32 *, void *);
+int	nlmsvc_decode_shareargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int	nlmsvc_encode_shareres(struct svc_rqst *, __be32 *, struct nlm_res *);
+int	nlmsvc_decode_notify(struct svc_rqst *, __be32 *, struct nlm_args *);
+int	nlmsvc_decode_reboot(struct svc_rqst *, __be32 *, struct nlm_reboot *);
 /*
 int	nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *);
 int	nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
diff -urN oldtree/include/linux/lockd/xdr4.h newtree/include/linux/lockd/xdr4.h
--- oldtree/include/linux/lockd/xdr4.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/lockd/xdr4.h	2006-02-21 15:58:36.858543208 +0000
@@ -23,19 +23,19 @@
 
 
 
-int	nlm4svc_decode_testargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int	nlm4svc_encode_testres(struct svc_rqst *, u32 *, struct nlm_res *);
-int	nlm4svc_decode_lockargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int	nlm4svc_decode_cancargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int	nlm4svc_decode_unlockargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int	nlm4svc_encode_res(struct svc_rqst *, u32 *, struct nlm_res *);
-int	nlm4svc_decode_res(struct svc_rqst *, u32 *, struct nlm_res *);
-int	nlm4svc_encode_void(struct svc_rqst *, u32 *, void *);
-int	nlm4svc_decode_void(struct svc_rqst *, u32 *, void *);
-int	nlm4svc_decode_shareargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int	nlm4svc_encode_shareres(struct svc_rqst *, u32 *, struct nlm_res *);
-int	nlm4svc_decode_notify(struct svc_rqst *, u32 *, struct nlm_args *);
-int	nlm4svc_decode_reboot(struct svc_rqst *, u32 *, struct nlm_reboot *);
+int	nlm4svc_decode_testargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int	nlm4svc_encode_testres(struct svc_rqst *, __be32 *, struct nlm_res *);
+int	nlm4svc_decode_lockargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int	nlm4svc_decode_cancargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int	nlm4svc_decode_unlockargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int	nlm4svc_encode_res(struct svc_rqst *, __be32 *, struct nlm_res *);
+int	nlm4svc_decode_res(struct svc_rqst *, __be32 *, struct nlm_res *);
+int	nlm4svc_encode_void(struct svc_rqst *, __be32 *, void *);
+int	nlm4svc_decode_void(struct svc_rqst *, __be32 *, void *);
+int	nlm4svc_decode_shareargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int	nlm4svc_encode_shareres(struct svc_rqst *, __be32 *, struct nlm_res *);
+int	nlm4svc_decode_notify(struct svc_rqst *, __be32 *, struct nlm_args *);
+int	nlm4svc_decode_reboot(struct svc_rqst *, __be32 *, struct nlm_reboot *);
 /*
 int	nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *);
 int	nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
diff -urN oldtree/include/linux/loop.h newtree/include/linux/loop.h
--- oldtree/include/linux/loop.h	2006-02-19 11:41:05.885448376 +0000
+++ newtree/include/linux/loop.h	2006-02-21 15:58:26.292149544 +0000
@@ -17,6 +17,7 @@
 #include <linux/bio.h>
 #include <linux/blkdev.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 
 /* Possible states of device */
 enum {
@@ -60,7 +61,7 @@
 	int			lo_state;
 	struct completion	lo_done;
 	struct completion	lo_bh_done;
-	struct semaphore	lo_ctl_mutex;
+	struct mutex		lo_ctl_mutex;
 	int			lo_pending;
 
 	request_queue_t		*lo_queue;
diff -urN oldtree/include/linux/mempolicy.h newtree/include/linux/mempolicy.h
--- oldtree/include/linux/mempolicy.h	2006-02-19 11:41:05.886448224 +0000
+++ newtree/include/linux/mempolicy.h	2006-02-21 15:58:29.639640648 +0000
@@ -147,6 +147,7 @@
 extern void mpol_rebind_task(struct task_struct *tsk,
 					const nodemask_t *new);
 extern void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new);
+extern void mpol_fix_fork_child_flag(struct task_struct *p);
 #define set_cpuset_being_rebound(x) (cpuset_being_rebound = (x))
 
 #ifdef CONFIG_CPUSET
@@ -248,6 +249,10 @@
 {
 }
 
+static inline void mpol_fix_fork_child_flag(struct task_struct *p)
+{
+}
+
 #define set_cpuset_being_rebound(x) do {} while (0)
 
 static inline struct zonelist *huge_zonelist(struct vm_area_struct *vma,
diff -urN oldtree/include/linux/mempool.h newtree/include/linux/mempool.h
--- oldtree/include/linux/mempool.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/mempool.h	2006-02-21 15:58:30.814462048 +0000
@@ -6,6 +6,8 @@
 
 #include <linux/wait.h>
 
+struct kmem_cache;
+
 typedef void * (mempool_alloc_t)(gfp_t gfp_mask, void *pool_data);
 typedef void (mempool_free_t)(void *element, void *pool_data);
 
@@ -37,5 +39,41 @@
  */
 void *mempool_alloc_slab(gfp_t gfp_mask, void *pool_data);
 void mempool_free_slab(void *element, void *pool_data);
+static inline mempool_t *
+mempool_create_slab_pool(int min_nr, struct kmem_cache *kc)
+{
+	return mempool_create(min_nr, mempool_alloc_slab, mempool_free_slab,
+			      (void *) kc);
+}
+
+/*
+ * 2 mempool_alloc_t's and a mempool_free_t to kmalloc/kzalloc and kfree
+ * the amount of memory specified by pool_data
+ */
+void *mempool_kmalloc(gfp_t gfp_mask, void *pool_data);
+void *mempool_kzalloc(gfp_t gfp_mask, void *pool_data);
+void mempool_kfree(void *element, void *pool_data);
+static inline mempool_t *mempool_create_kmalloc_pool(int min_nr, size_t size)
+{
+	return mempool_create(min_nr, mempool_kmalloc, mempool_kfree,
+			      (void *) size);
+}
+static inline mempool_t *mempool_create_kzalloc_pool(int min_nr, size_t size)
+{
+	return mempool_create(min_nr, mempool_kzalloc, mempool_kfree,
+			      (void *) size);
+}
+
+/*
+ * A mempool_alloc_t and mempool_free_t for a simple page allocator that
+ * allocates pages of the order specified by pool_data
+ */
+void *mempool_alloc_pages(gfp_t gfp_mask, void *pool_data);
+void mempool_free_pages(void *element, void *pool_data);
+static inline mempool_t *mempool_create_page_pool(int min_nr, int order)
+{
+	return mempool_create(min_nr, mempool_alloc_pages, mempool_free_pages,
+			      (void *)(long)order);
+}
 
 #endif /* _LINUX_MEMPOOL_H */
diff -urN oldtree/include/linux/module.h newtree/include/linux/module.h
--- oldtree/include/linux/module.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/module.h	2006-02-21 15:58:12.774204584 +0000
@@ -198,6 +198,9 @@
 #define EXPORT_SYMBOL_GPL(sym)					\
 	__EXPORT_SYMBOL(sym, "_gpl")
 
+#define EXPORT_SYMBOL_GPL_FUTURE(sym)				\
+	__EXPORT_SYMBOL(sym, "_gpl_future")
+
 #endif
 
 struct module_ref
@@ -242,6 +245,7 @@
 	/* Sysfs stuff. */
 	struct module_kobject mkobj;
 	struct module_param_attrs *param_attrs;
+	struct module_attribute *modinfo_attrs;
 	const char *version;
 	const char *srcversion;
 
@@ -255,6 +259,11 @@
 	unsigned int num_gpl_syms;
 	const unsigned long *gpl_crcs;
 
+	/* symbols that will be GPL-only in the near future. */
+	const struct kernel_symbol *gpl_future_syms;
+	unsigned int num_gpl_future_syms;
+	const unsigned long *gpl_future_crcs;
+
 	/* Exception table */
 	unsigned int num_exentries;
 	const struct exception_table_entry *extable;
@@ -441,6 +450,7 @@
 #else /* !CONFIG_MODULES... */
 #define EXPORT_SYMBOL(sym)
 #define EXPORT_SYMBOL_GPL(sym)
+#define EXPORT_SYMBOL_GPL_FUTURE(sym)
 
 /* Given an address, look for it in the exception tables. */
 static inline const struct exception_table_entry *
diff -urN oldtree/include/linux/mroute.h newtree/include/linux/mroute.h
--- oldtree/include/linux/mroute.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/mroute.h	2006-02-21 15:58:36.859543056 +0000
@@ -142,7 +142,7 @@
 	unsigned long	rate_limit;		/* Traffic shaping (NI) 	*/
 	unsigned char	threshold;		/* TTL threshold 		*/
 	unsigned short	flags;			/* Control flags 		*/
-	__u32		local,remote;		/* Addresses(remote for tunnels)*/
+	__be32		local,remote;		/* Addresses(remote for tunnels)*/
 	int		link;			/* Physical interface index	*/
 };
 
@@ -151,8 +151,8 @@
 struct mfc_cache 
 {
 	struct mfc_cache *next;			/* Next entry on cache line 	*/
-	__u32 mfc_mcastgrp;			/* Group the entry belongs to 	*/
-	__u32 mfc_origin;			/* Source of packet 		*/
+	__be32 mfc_mcastgrp;			/* Group the entry belongs to 	*/
+	__be32 mfc_origin;			/* Source of packet 		*/
 	vifi_t mfc_parent;			/* Source interface		*/
 	int mfc_flags;				/* Flags on line		*/
 
@@ -179,9 +179,9 @@
 #define MFC_LINES		64
 
 #ifdef __BIG_ENDIAN
-#define MFC_HASH(a,b)	((((a)>>24)^((b)>>26))&(MFC_LINES-1))
+#define MFC_HASH(a,b)	(((((__force u32)(__be32)a)>>24)^(((__force u32)(__be32)b)>>26))&(MFC_LINES-1))
 #else
-#define MFC_HASH(a,b)	(((a)^((b)>>2))&(MFC_LINES-1))
+#define MFC_HASH(a,b)	((((__force u32)(__be32)a)^(((__force u32)(__be32)b)>>2))&(MFC_LINES-1))
 #endif		
 
 #endif
@@ -213,8 +213,8 @@
 {
 	__u8	type;
 	__u8	reserved;
-	__u16	csum;
-	__u32	flags;
+	__be16	csum;
+	__be32	flags;
 };
 
 extern int pim_rcv_v1(struct sk_buff *);
diff -urN oldtree/include/linux/msdos_fs.h newtree/include/linux/msdos_fs.h
--- oldtree/include/linux/msdos_fs.h	2006-02-19 11:41:05.891447464 +0000
+++ newtree/include/linux/msdos_fs.h	2006-02-21 15:58:28.926749024 +0000
@@ -184,6 +184,7 @@
 #include <linux/string.h>
 #include <linux/nls.h>
 #include <linux/fs.h>
+#include <linux/mutex.h>
 
 struct fat_mount_options {
 	uid_t fs_uid;
@@ -226,7 +227,7 @@
 	unsigned long max_cluster;   /* maximum cluster number */
 	unsigned long root_cluster;  /* first cluster of the root directory */
 	unsigned long fsinfo_sector; /* sector number of FAT32 fsinfo */
-	struct semaphore fat_lock;
+	struct mutex fat_lock;
 	unsigned int prev_free;      /* previously allocated cluster number */
 	unsigned int free_clusters;  /* -1 if undefined */
 	struct fat_mount_options options;
diff -urN oldtree/include/linux/mtd/blktrans.h newtree/include/linux/mtd/blktrans.h
--- oldtree/include/linux/mtd/blktrans.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/mtd/blktrans.h	2006-02-21 15:58:15.045859240 +0000
@@ -10,7 +10,7 @@
 #ifndef __MTD_TRANS_H__
 #define __MTD_TRANS_H__
 
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 struct hd_geometry;
 struct mtd_info;
@@ -22,7 +22,7 @@
 	struct mtd_blktrans_ops *tr;
 	struct list_head list;
 	struct mtd_info *mtd;
-	struct semaphore sem;
+	struct mutex lock;
 	int devnum;
 	int blksize;
 	unsigned long size;
diff -urN oldtree/include/linux/mtd/doc2000.h newtree/include/linux/mtd/doc2000.h
--- oldtree/include/linux/mtd/doc2000.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/mtd/doc2000.h	2006-02-21 15:58:15.053858024 +0000
@@ -15,7 +15,7 @@
 #define __MTD_DOC2000_H__
 
 #include <linux/mtd/mtd.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #define DoC_Sig1 0
 #define DoC_Sig2 1
@@ -187,7 +187,7 @@
 	int numchips;
 	struct Nand *chips;
 	struct mtd_info *nextdoc;
-	struct semaphore lock;
+	struct mutex lock;
 };
 
 int doc_decode_ecc(unsigned char sector[512], unsigned char ecc1[6]);
diff -urN oldtree/include/linux/mtd/inftl.h newtree/include/linux/mtd/inftl.h
--- oldtree/include/linux/mtd/inftl.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/mtd/inftl.h	2006-02-21 15:58:15.234830512 +0000
@@ -52,6 +52,11 @@
 int INFTL_mount(struct INFTLrecord *s);
 int INFTL_formatblock(struct INFTLrecord *s, int block);
 
+extern char inftlmountrev[];
+
+void INFTL_dumptables(struct INFTLrecord *s);
+void INFTL_dumpVUchains(struct INFTLrecord *s);
+
 #endif /* __KERNEL__ */
 
 #endif /* __MTD_INFTL_H__ */
diff -urN oldtree/include/linux/mv643xx.h newtree/include/linux/mv643xx.h
--- oldtree/include/linux/mv643xx.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/mv643xx.h	2006-02-21 15:58:15.699759832 +0000
@@ -1214,6 +1214,7 @@
 #define MV643XX_ETH_FORCE_BP_MODE_NO_JAM		0
 #define MV643XX_ETH_FORCE_BP_MODE_JAM_TX		(1<<7)
 #define MV643XX_ETH_FORCE_BP_MODE_JAM_TX_ON_RX_ERR	(1<<8)
+#define MV643XX_ETH_SERIAL_PORT_CONTROL_RESERVED	(1<<9)
 #define MV643XX_ETH_FORCE_LINK_FAIL			0
 #define MV643XX_ETH_DO_NOT_FORCE_LINK_FAIL		(1<<10)
 #define MV643XX_ETH_RETRANSMIT_16_ATTEMPTS		0
@@ -1243,6 +1244,8 @@
 #define MV643XX_ETH_SET_MII_SPEED_TO_10			0
 #define MV643XX_ETH_SET_MII_SPEED_TO_100		(1<<24)
 
+#define MV643XX_ETH_MAX_RX_PACKET_MASK			(0x7<<17)
+
 #define	MV643XX_ETH_PORT_SERIAL_CONTROL_DEFAULT_VALUE		\
 		MV643XX_ETH_DO_NOT_FORCE_LINK_PASS	|	\
 		MV643XX_ETH_ENABLE_AUTO_NEG_FOR_DUPLX	|	\
@@ -1285,23 +1288,15 @@
 #define MV643XX_ETH_NAME	"mv643xx_eth"
 
 struct mv643xx_eth_platform_data {
-	/* 
-	 * Non-values for mac_addr, phy_addr, port_config, etc.
-	 * override the default value.  Setting the corresponding
-	 * force_* field, causes the default value to be overridden
-	 * even when zero.
-	 */
-	unsigned int	force_phy_addr:1;
-	unsigned int	force_port_config:1;
-	unsigned int	force_port_config_extend:1;
-	unsigned int	force_port_sdma_config:1;
-	unsigned int	force_port_serial_control:1;
-	int		phy_addr;
 	char		*mac_addr;	/* pointer to mac address */
-	u32		port_config;
-	u32		port_config_extend;
-	u32		port_sdma_config;
-	u32		port_serial_control;
+	u16		force_phy_addr;	/* force override if phy_addr == 0 */
+	u16		phy_addr;
+
+	/* If speed is 0, then speed and duplex are autonegotiated. */
+	int		speed;		/* 0, SPEED_10, SPEED_100, SPEED_1000 */
+	int		duplex;		/* DUPLEX_HALF or DUPLEX_FULL */
+
+	/* non-zero values of the following fields override defaults */
 	u32		tx_queue_size;
 	u32		rx_queue_size;
 	u32		tx_sram_addr;
diff -urN oldtree/include/linux/nbd.h newtree/include/linux/nbd.h
--- oldtree/include/linux/nbd.h	2006-02-19 11:41:05.893447160 +0000
+++ newtree/include/linux/nbd.h	2006-02-21 15:58:36.859543056 +0000
@@ -38,6 +38,7 @@
 #ifdef __KERNEL__
 
 #include <linux/wait.h>
+#include <linux/mutex.h>
 
 /* values for flags field */
 #define NBD_READ_ONLY 0x0001
@@ -57,7 +58,7 @@
 	struct request *active_req;
 	wait_queue_head_t active_wq;
 
-	struct semaphore tx_lock;
+	struct mutex tx_lock;
 	struct gendisk *disk;
 	int blksize;
 	u64 bytesize;
@@ -76,11 +77,11 @@
  * server. All data are in network byte order.
  */
 struct nbd_request {
-	u32 magic;
-	u32 type;	/* == READ || == WRITE 	*/
+	__be32 magic;
+	__be32 type;	/* == READ || == WRITE 	*/
 	char handle[8];
-	u64 from;
-	u32 len;
+	__be64 from;
+	__be32 len;
 }
 #ifdef __GNUC__
 	__attribute__ ((packed))
@@ -92,8 +93,8 @@
  * it has completed an I/O request (or an error occurs).
  */
 struct nbd_reply {
-	u32 magic;
-	u32 error;		/* 0 = ok, else error	*/
+	__be32 magic;
+	__be32 error;		/* 0 = ok, else error	*/
 	char handle[8];		/* handle you got from request	*/
 };
 #endif
diff -urN oldtree/include/linux/ncp_fs_i.h newtree/include/linux/ncp_fs_i.h
--- oldtree/include/linux/ncp_fs_i.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/ncp_fs_i.h	2006-02-21 15:58:28.263849800 +0000
@@ -19,7 +19,7 @@
 	__le32	DosDirNum;
 	__u8	volNumber;
 	__le32	nwattr;
-	struct semaphore open_sem;
+	struct mutex open_mutex;
 	atomic_t	opened;
 	int	access;
 	int	flags;
diff -urN oldtree/include/linux/ncp_fs_sb.h newtree/include/linux/ncp_fs_sb.h
--- oldtree/include/linux/ncp_fs_sb.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/ncp_fs_sb.h	2006-02-21 15:58:28.263849800 +0000
@@ -11,6 +11,7 @@
 #include <linux/types.h>
 #include <linux/ncp_mount.h>
 #include <linux/net.h>
+#include <linux/mutex.h>
 
 #ifdef __KERNEL__
 
@@ -51,7 +52,7 @@
 				   receive replies */
 
 	int lock;		/* To prevent mismatch in protocols. */
-	struct semaphore sem;
+	struct mutex mutex;
 
 	int current_size;	/* for packet preparation */
 	int has_subfunction;
@@ -96,7 +97,7 @@
 	struct {
 		struct work_struct tq;		/* STREAM/DGRAM: data/error ready */
 		struct ncp_request_reply* creq;	/* STREAM/DGRAM: awaiting reply from this request */
-		struct semaphore creq_sem;	/* DGRAM only: lock accesses to rcv.creq */
+		struct mutex creq_mutex;	/* DGRAM only: lock accesses to rcv.creq */
 
 		unsigned int state;		/* STREAM only: receiver state */
 		struct {
diff -urN oldtree/include/linux/net.h newtree/include/linux/net.h
--- oldtree/include/linux/net.h	2006-02-19 11:41:05.894447008 +0000
+++ newtree/include/linux/net.h	2006-02-21 15:58:16.991563448 +0000
@@ -143,6 +143,8 @@
 				      struct poll_table_struct *wait);
 	int		(*ioctl)     (struct socket *sock, unsigned int cmd,
 				      unsigned long arg);
+	int	 	(*compat_ioctl) (struct socket *sock, unsigned int cmd,
+				      unsigned long arg);
 	int		(*listen)    (struct socket *sock, int len);
 	int		(*shutdown)  (struct socket *sock, int flags);
 	int		(*setsockopt)(struct socket *sock, int level,
@@ -247,6 +249,8 @@
 	      (file, sock, wait)) \
 SOCKCALL_WRAP(name, ioctl, (struct socket *sock, unsigned int cmd, \
 			 unsigned long arg), (sock, cmd, arg)) \
+SOCKCALL_WRAP(name, compat_ioctl, (struct socket *sock, unsigned int cmd, \
+			 unsigned long arg), (sock, cmd, arg)) \
 SOCKCALL_WRAP(name, listen, (struct socket *sock, int len), (sock, len)) \
 SOCKCALL_WRAP(name, shutdown, (struct socket *sock, int flags), (sock, flags)) \
 SOCKCALL_WRAP(name, setsockopt, (struct socket *sock, int level, int optname, \
@@ -271,6 +275,7 @@
 	.getname	= __lock_##name##_getname,	\
 	.poll		= __lock_##name##_poll,		\
 	.ioctl		= __lock_##name##_ioctl,	\
+	.compat_ioctl	= __lock_##name##_compat_ioctl,	\
 	.listen		= __lock_##name##_listen,	\
 	.shutdown	= __lock_##name##_shutdown,	\
 	.setsockopt	= __lock_##name##_setsockopt,	\
@@ -279,6 +284,7 @@
 	.recvmsg	= __lock_##name##_recvmsg,	\
 	.mmap		= __lock_##name##_mmap,		\
 };
+
 #endif
 
 #define MODULE_ALIAS_NETPROTO(proto) \
diff -urN oldtree/include/linux/netdevice.h newtree/include/linux/netdevice.h
--- oldtree/include/linux/netdevice.h	2006-02-19 11:41:05.895446856 +0000
+++ newtree/include/linux/netdevice.h	2006-02-21 15:58:36.860542904 +0000
@@ -187,7 +187,7 @@
 {
 	struct hh_cache *hh_next;	/* Next entry			     */
 	atomic_t	hh_refcnt;	/* number of users                   */
-	unsigned short  hh_type;	/* protocol identifier, f.e ETH_P_IP
+	__be16		hh_type;	/* protocol identifier, f.e ETH_P_IP
                                          *  NOTE:  For VLANs, this will be the
                                          *  encapuslated type. --BLG
                                          */
@@ -230,7 +230,8 @@
 	__LINK_STATE_SCHED,
 	__LINK_STATE_NOCARRIER,
 	__LINK_STATE_RX_SCHED,
-	__LINK_STATE_LINKWATCH_PENDING
+	__LINK_STATE_LINKWATCH_PENDING,
+	__LINK_STATE_DORMANT,
 };
 
 
@@ -335,11 +336,14 @@
 	 */
 
 
-	unsigned short		flags;	/* interface flags (a la BSD)	*/
+	unsigned int		flags;	/* interface flags (a la BSD)	*/
 	unsigned short		gflags;
         unsigned short          priv_flags; /* Like 'flags' but invisible to userspace. */
 	unsigned short		padded;	/* How much padding added by alloc_netdev() */
 
+	unsigned char		operstate; /* RFC2863 operstate */
+	unsigned char		link_mode; /* mapping policy to operstate */
+
 	unsigned		mtu;	/* interface MTU value		*/
 	unsigned short		type;	/* interface hardware type	*/
 	unsigned short		hard_header_len;	/* hardware hdr length	*/
@@ -714,6 +718,10 @@
 /* Carrier loss detection, dial on demand. The functions netif_carrier_on
  * and _off may be called from IRQ context, but it is caller
  * who is responsible for serialization of these calls.
+ *
+ * The name carrier is inappropriate, these functions should really be
+ * called netif_lowerlayer_*() because they represent the state of any
+ * kind of lower layer not just hardware media.
  */
 
 extern void linkwatch_fire_event(struct net_device *dev);
@@ -729,6 +737,29 @@
 
 extern void netif_carrier_off(struct net_device *dev);
 
+static inline void netif_dormant_on(struct net_device *dev)
+{
+	if (!test_and_set_bit(__LINK_STATE_DORMANT, &dev->state))
+		linkwatch_fire_event(dev);
+}
+
+static inline void netif_dormant_off(struct net_device *dev)
+{
+	if (test_and_clear_bit(__LINK_STATE_DORMANT, &dev->state))
+		linkwatch_fire_event(dev);
+}
+
+static inline int netif_dormant(const struct net_device *dev)
+{
+	return test_bit(__LINK_STATE_DORMANT, &dev->state);
+}
+
+
+static inline int netif_oper_up(const struct net_device *dev) {
+	return (dev->operstate == IF_OPER_UP ||
+		dev->operstate == IF_OPER_UNKNOWN /* backward compat */);
+}
+
 /* Hot-plugging. */
 static inline int netif_device_present(struct net_device *dev)
 {
diff -urN oldtree/include/linux/netfilter/nfnetlink.h newtree/include/linux/netfilter/nfnetlink.h
--- oldtree/include/linux/netfilter/nfnetlink.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/netfilter/nfnetlink.h	2006-02-21 15:58:16.211682008 +0000
@@ -164,6 +164,7 @@
  	__res;								\
 })
 
+extern int nfnetlink_has_listeners(unsigned int group);
 extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, 
 			  int echo);
 extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags);
diff -urN oldtree/include/linux/netfilter/nfnetlink_log.h newtree/include/linux/netfilter/nfnetlink_log.h
--- oldtree/include/linux/netfilter/nfnetlink_log.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/netfilter/nfnetlink_log.h	2006-02-21 15:58:16.211682008 +0000
@@ -47,6 +47,8 @@
 	NFULA_PAYLOAD,			/* opaque data payload */
 	NFULA_PREFIX,			/* string prefix */
 	NFULA_UID,			/* user id of socket */
+	NFULA_SEQ,			/* instance-local sequence number */
+	NFULA_SEQ_GLOBAL,		/* global sequence number */
 
 	__NFULA_MAX
 };
@@ -77,6 +79,7 @@
 	NFULA_CFG_NLBUFSIZ,		/* u_int32_t buffer size */
 	NFULA_CFG_TIMEOUT,		/* u_int32_t in 1/100 s */
 	NFULA_CFG_QTHRESH,		/* u_int32_t */
+	NFULA_CFG_FLAGS,		/* u_int16_t */
 	__NFULA_CFG_MAX
 };
 #define NFULA_CFG_MAX (__NFULA_CFG_MAX -1)
@@ -85,4 +88,7 @@
 #define NFULNL_COPY_META	0x01
 #define NFULNL_COPY_PACKET	0x02
 
+#define NFULNL_CFG_F_SEQ	0x0001
+#define NFULNL_CFG_F_SEQ_GLOBAL	0x0002
+
 #endif /* _NFNETLINK_LOG_H */
diff -urN oldtree/include/linux/netfilter/x_tables.h newtree/include/linux/netfilter/x_tables.h
--- oldtree/include/linux/netfilter/x_tables.h	2006-02-19 11:41:05.897446552 +0000
+++ newtree/include/linux/netfilter/x_tables.h	2006-02-21 15:58:16.212681856 +0000
@@ -92,8 +92,6 @@
 
 	const char name[XT_FUNCTION_MAXNAMELEN-1];
 
-	u_int8_t revision;
-
 	/* Return true or false: return FALSE and set *hotdrop = 1 to
            force immediate packet drop. */
 	/* Arguments changed since 2.6.9, as this must now handle
@@ -102,6 +100,7 @@
 	int (*match)(const struct sk_buff *skb,
 		     const struct net_device *in,
 		     const struct net_device *out,
+		     const struct xt_match *match,
 		     const void *matchinfo,
 		     int offset,
 		     unsigned int protoff,
@@ -111,15 +110,25 @@
 	/* Should return true or false. */
 	int (*checkentry)(const char *tablename,
 			  const void *ip,
+			  const struct xt_match *match,
 			  void *matchinfo,
 			  unsigned int matchinfosize,
 			  unsigned int hook_mask);
 
 	/* Called when entry of this type deleted. */
-	void (*destroy)(void *matchinfo, unsigned int matchinfosize);
+	void (*destroy)(const struct xt_match *match, void *matchinfo,
+			unsigned int matchinfosize);
 
 	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
 	struct module *me;
+
+	char *table;
+	unsigned int matchsize;
+	unsigned int hooks;
+	unsigned short proto;
+
+	unsigned short family;
+	u_int8_t revision;
 };
 
 /* Registration hooks for targets. */
@@ -129,8 +138,6 @@
 
 	const char name[XT_FUNCTION_MAXNAMELEN-1];
 
-	u_int8_t revision;
-
 	/* Returns verdict. Argument order changed since 2.6.9, as this
 	   must now handle non-linear skbs, using skb_copy_bits and
 	   skb_ip_make_writable. */
@@ -138,6 +145,7 @@
 			       const struct net_device *in,
 			       const struct net_device *out,
 			       unsigned int hooknum,
+			       const struct xt_target *target,
 			       const void *targinfo,
 			       void *userdata);
 
@@ -147,15 +155,25 @@
 	/* Should return true or false. */
 	int (*checkentry)(const char *tablename,
 			  const void *entry,
+			  const struct xt_target *target,
 			  void *targinfo,
 			  unsigned int targinfosize,
 			  unsigned int hook_mask);
 
 	/* Called when entry of this type deleted. */
-	void (*destroy)(void *targinfo, unsigned int targinfosize);
+	void (*destroy)(const struct xt_target *target, void *targinfo,
+			unsigned int targinfosize);
 
 	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
 	struct module *me;
+
+	char *table;
+	unsigned int targetsize;
+	unsigned int hooks;
+	unsigned short proto;
+
+	unsigned short family;
+	u_int8_t revision;
 };
 
 /* Furniture shopping... */
@@ -207,6 +225,13 @@
 extern int xt_register_match(int af, struct xt_match *target);
 extern void xt_unregister_match(int af, struct xt_match *target);
 
+extern int xt_check_match(const struct xt_match *match, unsigned short family,
+			  unsigned int size, const char *table, unsigned int hook,
+			  unsigned short proto, int inv_proto);
+extern int xt_check_target(const struct xt_target *target, unsigned short family,
+			   unsigned int size, const char *table, unsigned int hook,
+			   unsigned short proto, int inv_proto);
+
 extern int xt_register_table(struct xt_table *table,
 			     struct xt_table_info *bootstrap,
 			     struct xt_table_info *newinfo);
diff -urN oldtree/include/linux/netfilter/xt_policy.h newtree/include/linux/netfilter/xt_policy.h
--- oldtree/include/linux/netfilter/xt_policy.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/include/linux/netfilter/xt_policy.h	2006-02-21 15:58:16.212681856 +0000
@@ -0,0 +1,58 @@
+#ifndef _XT_POLICY_H
+#define _XT_POLICY_H
+
+#define XT_POLICY_MAX_ELEM	4
+
+enum xt_policy_flags
+{
+	XT_POLICY_MATCH_IN	= 0x1,
+	XT_POLICY_MATCH_OUT	= 0x2,
+	XT_POLICY_MATCH_NONE	= 0x4,
+	XT_POLICY_MATCH_STRICT	= 0x8,
+};
+
+enum xt_policy_modes
+{
+	XT_POLICY_MODE_TRANSPORT,
+	XT_POLICY_MODE_TUNNEL
+};
+
+struct xt_policy_spec
+{
+	u_int8_t	saddr:1,
+			daddr:1,
+			proto:1,
+			mode:1,
+			spi:1,
+			reqid:1;
+};
+
+union xt_policy_addr
+{
+	struct in_addr	a4;
+	struct in6_addr	a6;
+};
+
+struct xt_policy_elem
+{
+	union xt_policy_addr	saddr;
+	union xt_policy_addr	smask;
+	union xt_policy_addr	daddr;
+	union xt_policy_addr	dmask;
+	u_int32_t		spi;
+	u_int32_t		reqid;
+	u_int8_t		proto;
+	u_int8_t		mode;
+
+	struct xt_policy_spec	match;
+	struct xt_policy_spec	invert;
+};
+
+struct xt_policy_info
+{
+	struct xt_policy_elem pol[XT_POLICY_MAX_ELEM];
+	u_int16_t flags;
+	u_int16_t len;
+};
+
+#endif /* _XT_POLICY_H */
diff -urN oldtree/include/linux/netfilter_arp/arp_tables.h newtree/include/linux/netfilter_arp/arp_tables.h
--- oldtree/include/linux/netfilter_arp/arp_tables.h	2006-02-19 11:41:05.904445488 +0000
+++ newtree/include/linux/netfilter_arp/arp_tables.h	2006-02-21 15:58:36.861542752 +0000
@@ -46,11 +46,11 @@
 	struct arpt_devaddr_info tgt_devaddr;
 
 	/* ARP operation code. */
-	u_int16_t arpop, arpop_mask;
+	__be16 arpop, arpop_mask;
 
 	/* ARP hardware address and protocol address format. */
-	u_int16_t arhrd, arhrd_mask;
-	u_int16_t arpro, arpro_mask;
+	__be16 arhrd, arhrd_mask;
+	__be16 arpro, arpro_mask;
 
 	/* The protocol address length is only accepted if it is 4
 	 * so there is no use in offering a way to do filtering on it.
diff -urN oldtree/include/linux/netfilter_ipv4/ip_conntrack_tuple.h newtree/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
--- oldtree/include/linux/netfilter_ipv4/ip_conntrack_tuple.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/netfilter_ipv4/ip_conntrack_tuple.h	2006-02-21 15:58:36.862542600 +0000
@@ -23,13 +23,13 @@
 		__be16 port;
 	} tcp;
 	struct {
-		u_int16_t port;
+		__be16 port;
 	} udp;
 	struct {
-		u_int16_t id;
+		__be16 id;
 	} icmp;
 	struct {
-		u_int16_t port;
+		__be16 port;
 	} sctp;
 	struct {
 		__be16 key;	/* key is 32bit, pptp only uses 16 */
@@ -39,7 +39,7 @@
 /* The manipulable part of the tuple. */
 struct ip_conntrack_manip
 {
-	u_int32_t ip;
+	__be32 ip;
 	union ip_conntrack_manip_proto u;
 };
 
@@ -50,22 +50,22 @@
 
 	/* These are the parts of the tuple which are fixed. */
 	struct {
-		u_int32_t ip;
+		__be32 ip;
 		union {
 			/* Add other protocols here. */
 			u_int16_t all;
 
 			struct {
-				u_int16_t port;
+				__be16 port;
 			} tcp;
 			struct {
-				u_int16_t port;
+				__be16 port;
 			} udp;
 			struct {
 				u_int8_t type, code;
 			} icmp;
 			struct {
-				u_int16_t port;
+				__be16 port;
 			} sctp;
 			struct {
 				__be16 key;	/* key is 32bit, 
diff -urN oldtree/include/linux/netfilter_ipv4/ip_nat.h newtree/include/linux/netfilter_ipv4/ip_nat.h
--- oldtree/include/linux/netfilter_ipv4/ip_nat.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/netfilter_ipv4/ip_nat.h	2006-02-21 15:58:36.862542600 +0000
@@ -23,7 +23,7 @@
 	 * modification (if any) */
 	u_int32_t correction_pos;
 	/* sequence number offset before and after last modification */
-	int32_t offset_before, offset_after;
+	int16_t offset_before, offset_after;
 };
 
 /* Single range specification. */
@@ -33,7 +33,7 @@
 	unsigned int flags;
 
 	/* Inclusive: network order. */
-	u_int32_t min_ip, max_ip;
+	__be32 min_ip, max_ip;
 
 	/* Inclusive: network order */
 	union ip_conntrack_manip_proto min, max;
diff -urN oldtree/include/linux/netfilter_ipv4/ip_queue.h newtree/include/linux/netfilter_ipv4/ip_queue.h
--- oldtree/include/linux/netfilter_ipv4/ip_queue.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/netfilter_ipv4/ip_queue.h	2006-02-21 15:58:36.862542600 +0000
@@ -26,7 +26,7 @@
 	unsigned int hook;		/* Netfilter hook we rode in on */
 	char indev_name[IFNAMSIZ];	/* Name of incoming interface */
 	char outdev_name[IFNAMSIZ];	/* Name of outgoing interface */
-	unsigned short hw_protocol;	/* Hardware protocol (network order) */
+	__be16 hw_protocol;		/* Hardware protocol (network order) */
 	unsigned short hw_type;		/* Hardware type */
 	unsigned char hw_addrlen;	/* Hardware address length */
 	unsigned char hw_addr[8];	/* Hardware address */
diff -urN oldtree/include/linux/netfilter_ipv4/ipt_iprange.h newtree/include/linux/netfilter_ipv4/ipt_iprange.h
--- oldtree/include/linux/netfilter_ipv4/ipt_iprange.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/netfilter_ipv4/ipt_iprange.h	2006-02-21 15:58:36.863542448 +0000
@@ -8,7 +8,7 @@
 
 struct ipt_iprange {
 	/* Inclusive: network order. */
-	u_int32_t min_ip, max_ip;
+	__be32 min_ip, max_ip;
 };
 
 struct ipt_iprange_info
diff -urN oldtree/include/linux/netfilter_ipv4/ipt_policy.h newtree/include/linux/netfilter_ipv4/ipt_policy.h
--- oldtree/include/linux/netfilter_ipv4/ipt_policy.h	2006-02-19 11:41:05.912444272 +0000
+++ newtree/include/linux/netfilter_ipv4/ipt_policy.h	2006-02-21 15:58:16.213681704 +0000
@@ -1,58 +1,21 @@
 #ifndef _IPT_POLICY_H
 #define _IPT_POLICY_H
 
-#define IPT_POLICY_MAX_ELEM	4
+#define IPT_POLICY_MAX_ELEM		XT_POLICY_MAX_ELEM
 
-enum ipt_policy_flags
-{
-	IPT_POLICY_MATCH_IN	= 0x1,
-	IPT_POLICY_MATCH_OUT	= 0x2,
-	IPT_POLICY_MATCH_NONE	= 0x4,
-	IPT_POLICY_MATCH_STRICT	= 0x8,
-};
-
-enum ipt_policy_modes
-{
-	IPT_POLICY_MODE_TRANSPORT,
-	IPT_POLICY_MODE_TUNNEL
-};
-
-struct ipt_policy_spec
-{
-	u_int8_t	saddr:1,
-			daddr:1,
-			proto:1,
-			mode:1,
-			spi:1,
-			reqid:1;
-};
-
-union ipt_policy_addr
-{
-	struct in_addr	a4;
-	struct in6_addr	a6;
-};
-
-struct ipt_policy_elem
-{
-	union ipt_policy_addr	saddr;
-	union ipt_policy_addr	smask;
-	union ipt_policy_addr	daddr;
-	union ipt_policy_addr	dmask;
-	u_int32_t		spi;
-	u_int32_t		reqid;
-	u_int8_t		proto;
-	u_int8_t		mode;
-
-	struct ipt_policy_spec	match;
-	struct ipt_policy_spec	invert;
-};
-
-struct ipt_policy_info
-{
-	struct ipt_policy_elem pol[IPT_POLICY_MAX_ELEM];
-	u_int16_t flags;
-	u_int16_t len;
-};
+/* ipt_policy_flags */
+#define IPT_POLICY_MATCH_IN		XT_POLICY_MATCH_IN
+#define IPT_POLICY_MATCH_OUT		XT_POLICY_MATCH_OUT
+#define IPT_POLICY_MATCH_NONE		XT_POLICY_MATCH_NONE
+#define IPT_POLICY_MATCH_STRICT		XT_POLICY_MATCH_STRICT
+
+/* ipt_policy_modes */
+#define IPT_POLICY_MODE_TRANSPORT	XT_POLICY_MODE_TRANSPORT
+#define IPT_POLICY_MODE_TUNNEL		XT_POLICY_MODE_TUNNEL
+
+#define ipt_policy_spec			xt_policy_spec
+#define ipt_policy_addr			xt_policy_addr
+#define ipt_policy_elem			xt_policy_elem
+#define ipt_policy_info			xt_policy_info
 
 #endif /* _IPT_POLICY_H */
diff -urN oldtree/include/linux/netfilter_ipv6/ip6t_policy.h newtree/include/linux/netfilter_ipv6/ip6t_policy.h
--- oldtree/include/linux/netfilter_ipv6/ip6t_policy.h	2006-02-19 11:41:05.918443360 +0000
+++ newtree/include/linux/netfilter_ipv6/ip6t_policy.h	2006-02-21 15:58:16.213681704 +0000
@@ -1,58 +1,21 @@
 #ifndef _IP6T_POLICY_H
 #define _IP6T_POLICY_H
 
-#define IP6T_POLICY_MAX_ELEM	4
+#define IP6T_POLICY_MAX_ELEM		XT_POLICY_MAX_ELEM
 
-enum ip6t_policy_flags
-{
-	IP6T_POLICY_MATCH_IN		= 0x1,
-	IP6T_POLICY_MATCH_OUT		= 0x2,
-	IP6T_POLICY_MATCH_NONE		= 0x4,
-	IP6T_POLICY_MATCH_STRICT	= 0x8,
-};
-
-enum ip6t_policy_modes
-{
-	IP6T_POLICY_MODE_TRANSPORT,
-	IP6T_POLICY_MODE_TUNNEL
-};
-
-struct ip6t_policy_spec
-{
-	u_int8_t	saddr:1,
-			daddr:1,
-			proto:1,
-			mode:1,
-			spi:1,
-			reqid:1;
-};
-
-union ip6t_policy_addr
-{
-	struct in_addr	a4;
-	struct in6_addr	a6;
-};
-
-struct ip6t_policy_elem
-{
-	union ip6t_policy_addr	saddr;
-	union ip6t_policy_addr	smask;
-	union ip6t_policy_addr	daddr;
-	union ip6t_policy_addr	dmask;
-	u_int32_t		spi;
-	u_int32_t		reqid;
-	u_int8_t		proto;
-	u_int8_t		mode;
-
-	struct ip6t_policy_spec	match;
-	struct ip6t_policy_spec	invert;
-};
-
-struct ip6t_policy_info
-{
-	struct ip6t_policy_elem pol[IP6T_POLICY_MAX_ELEM];
-	u_int16_t flags;
-	u_int16_t len;
-};
+/* ip6t_policy_flags */
+#define IP6T_POLICY_MATCH_IN		XT_POLICY_MATCH_IN
+#define IP6T_POLICY_MATCH_OUT		XT_POLICY_MATCH_OUT
+#define IP6T_POLICY_MATCH_NONE		XT_POLICY_MATCH_NONE
+#define IP6T_POLICY_MATCH_STRICT	XT_POLICY_MATCH_STRICT
+
+/* ip6t_policy_modes */
+#define IP6T_POLICY_MODE_TRANSPORT	XT_POLICY_MODE_TRANSPORT
+#define IP6T_POLICY_MODE_TUNNEL		XT_POLICY_MODE_TUNNEL
+
+#define ip6t_policy_spec		xt_policy_spec
+#define ip6t_policy_addr		xt_policy_addr
+#define ip6t_policy_elem		xt_policy_elem
+#define ip6t_policy_info		xt_policy_info
 
 #endif /* _IP6T_POLICY_H */
diff -urN oldtree/include/linux/netlink.h newtree/include/linux/netlink.h
--- oldtree/include/linux/netlink.h	2006-02-19 11:41:05.919443208 +0000
+++ newtree/include/linux/netlink.h	2006-02-21 15:58:16.214681552 +0000
@@ -151,6 +151,7 @@
 
 extern struct sock *netlink_kernel_create(int unit, unsigned int groups, void (*input)(struct sock *sk, int len), struct module *module);
 extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
+extern int netlink_has_listeners(struct sock *sk, unsigned int group);
 extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock);
 extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid,
 			     __u32 group, gfp_t allocation);
diff -urN oldtree/include/linux/nfs_fs.h newtree/include/linux/nfs_fs.h
--- oldtree/include/linux/nfs_fs.h	2006-02-19 11:41:05.920443056 +0000
+++ newtree/include/linux/nfs_fs.h	2006-02-21 15:58:36.876540472 +0000
@@ -161,7 +161,7 @@
 	 * This is the cookie verifier used for NFSv3 readdir
 	 * operations
 	 */
-	__u32			cookieverf[2];
+	__be32			cookieverf[2];
 
 	/*
 	 * This is the list of dirty unwritten pages.
@@ -319,7 +319,7 @@
 extern void nfs_file_clear_open_context(struct file *filp);
 
 /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
-extern u32 root_nfs_parse_addr(char *name); /*__init*/
+extern __be32 root_nfs_parse_addr(char *name); /*__init*/
 
 static inline void nfs_fattr_init(struct nfs_fattr *fattr)
 {
diff -urN oldtree/include/linux/nfs_xdr.h newtree/include/linux/nfs_xdr.h
--- oldtree/include/linux/nfs_xdr.h	2006-02-19 11:41:05.922442752 +0000
+++ newtree/include/linux/nfs_xdr.h	2006-02-21 15:58:36.877540320 +0000
@@ -262,7 +262,7 @@
 
 struct nfs_writeverf {
 	enum nfs3_stable_how	committed;
-	__u32			verifier[2];
+	__be32			verifier[2];
 };
 
 struct nfs_writeres {
@@ -416,7 +416,7 @@
 	unsigned int		len;
 	struct iattr *		sattr;
 	enum nfs3_createmode	createmode;
-	__u32			verifier[2];
+	__be32			verifier[2];
 };
 
 struct nfs3_mkdirargs {
@@ -463,7 +463,7 @@
 struct nfs3_readdirargs {
 	struct nfs_fh *		fh;
 	__u64			cookie;
-	__u32			verf[2];
+	__be32			verf[2];
 	int			plus;
 	unsigned int            count;
 	struct page **		pages;
@@ -499,7 +499,7 @@
 
 struct nfs3_readdirres {
 	struct nfs_fattr *	dir_attr;
-	__u32 *			verf;
+	__be32 *		verf;
 	int			plus;
 };
 
@@ -767,7 +767,7 @@
 			    struct nfs_fsinfo *);
 	int	(*pathconf) (struct nfs_server *, struct nfs_fh *,
 			     struct nfs_pathconf *);
-	u32 *	(*decode_dirent)(u32 *, struct nfs_entry *, int plus);
+	__be32 *(*decode_dirent)(__be32 *, struct nfs_entry *, int plus);
 	void	(*read_setup)   (struct nfs_read_data *);
 	void	(*write_setup)  (struct nfs_write_data *, int how);
 	void	(*commit_setup) (struct nfs_write_data *, int how);
diff -urN oldtree/include/linux/nfsd/cache.h newtree/include/linux/nfsd/cache.h
--- oldtree/include/linux/nfsd/cache.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/nfsd/cache.h	2006-02-21 15:58:36.864542296 +0000
@@ -33,7 +33,7 @@
 	unsigned long		c_timestamp;
 	union {
 		struct kvec	u_vec;
-		u32		u_status;
+		__be32		u_status;
 	}			c_u;
 };
 
@@ -75,7 +75,7 @@
 void	nfsd_cache_init(void);
 void	nfsd_cache_shutdown(void);
 int	nfsd_cache_lookup(struct svc_rqst *, int);
-void	nfsd_cache_update(struct svc_rqst *, int, u32 *);
+void	nfsd_cache_update(struct svc_rqst *, int, __be32 *);
 
 #endif /* __KERNEL__ */
 #endif /* NFSCACHE_H */
diff -urN oldtree/include/linux/nfsd/export.h newtree/include/linux/nfsd/export.h
--- oldtree/include/linux/nfsd/export.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/nfsd/export.h	2006-02-21 15:58:36.865542144 +0000
@@ -98,8 +98,8 @@
 				   struct cache_req *reqp);
 int			exp_rootfh(struct auth_domain *, 
 					char *path, struct knfsd_fh *, int maxsize);
-int			exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp, struct cache_req *creq);
-int			nfserrno(int errno);
+__be32			exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp, struct cache_req *creq);
+__be32			nfserrno(int errno);
 
 extern void expkey_put(struct cache_head *item, struct cache_detail *cd);
 extern void svc_export_put(struct cache_head *item, struct cache_detail *cd);
diff -urN oldtree/include/linux/nfsd/nfsd.h newtree/include/linux/nfsd/nfsd.h
--- oldtree/include/linux/nfsd/nfsd.h	2006-02-19 11:41:05.922442752 +0000
+++ newtree/include/linux/nfsd/nfsd.h	2006-02-21 15:58:36.865542144 +0000
@@ -51,7 +51,7 @@
  * Callback function for readdir
  */
 struct readdir_cd {
-	int			err;	/* 0, nfserr, or nfserr_eof */
+	__be32			err;	/* 0, nfserr, or nfserr_eof */
 };
 typedef int		(*encode_dent_fn)(struct readdir_cd *, const char *,
 						int, loff_t, ino_t, unsigned int);
@@ -65,7 +65,7 @@
  * Function prototypes.
  */
 int		nfsd_svc(unsigned short port, int nrservs);
-int		nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp);
+int		nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp);
 
 /* nfsd/vfs.c */
 int		fh_lock_parent(struct svc_fh *, struct dentry *);
@@ -73,57 +73,57 @@
 void		nfsd_racache_shutdown(void);
 int		nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
 		                struct svc_export **expp);
-int		nfsd_lookup(struct svc_rqst *, struct svc_fh *,
+__be32		nfsd_lookup(struct svc_rqst *, struct svc_fh *,
 				const char *, int, struct svc_fh *);
-int		nfsd_setattr(struct svc_rqst *, struct svc_fh *,
+__be32		nfsd_setattr(struct svc_rqst *, struct svc_fh *,
 				struct iattr *, int, time_t);
 #ifdef CONFIG_NFSD_V4
-int             nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
+__be32          nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
                     struct nfs4_acl *);
 int             nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **);
 #endif /* CONFIG_NFSD_V4 */
-int		nfsd_create(struct svc_rqst *, struct svc_fh *,
+__be32		nfsd_create(struct svc_rqst *, struct svc_fh *,
 				char *name, int len, struct iattr *attrs,
 				int type, dev_t rdev, struct svc_fh *res);
 #ifdef CONFIG_NFSD_V3
-int		nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *);
-int		nfsd_create_v3(struct svc_rqst *, struct svc_fh *,
+__be32		nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *);
+__be32		nfsd_create_v3(struct svc_rqst *, struct svc_fh *,
 				char *name, int len, struct iattr *attrs,
 				struct svc_fh *res, int createmode,
 				u32 *verifier, int *truncp);
-int		nfsd_commit(struct svc_rqst *, struct svc_fh *,
+__be32		nfsd_commit(struct svc_rqst *, struct svc_fh *,
 				loff_t, unsigned long);
 #endif /* CONFIG_NFSD_V3 */
-int		nfsd_open(struct svc_rqst *, struct svc_fh *, int,
+__be32		nfsd_open(struct svc_rqst *, struct svc_fh *, int,
 				int, struct file **);
 void		nfsd_close(struct file *);
-int 		nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *,
+__be32 		nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *,
 				loff_t, struct kvec *, int, unsigned long *);
-int 		nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *,
+__be32 		nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *,
 				loff_t, struct kvec *,int, unsigned long, int *);
-int		nfsd_readlink(struct svc_rqst *, struct svc_fh *,
+__be32		nfsd_readlink(struct svc_rqst *, struct svc_fh *,
 				char *, int *);
-int		nfsd_symlink(struct svc_rqst *, struct svc_fh *,
+__be32		nfsd_symlink(struct svc_rqst *, struct svc_fh *,
 				char *name, int len, char *path, int plen,
 				struct svc_fh *res, struct iattr *);
-int		nfsd_link(struct svc_rqst *, struct svc_fh *,
+__be32		nfsd_link(struct svc_rqst *, struct svc_fh *,
 				char *, int, struct svc_fh *);
-int		nfsd_rename(struct svc_rqst *,
+__be32		nfsd_rename(struct svc_rqst *,
 				struct svc_fh *, char *, int,
 				struct svc_fh *, char *, int);
-int		nfsd_remove(struct svc_rqst *,
+__be32		nfsd_remove(struct svc_rqst *,
 				struct svc_fh *, char *, int);
-int		nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type,
+__be32		nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type,
 				char *name, int len);
 int		nfsd_truncate(struct svc_rqst *, struct svc_fh *,
 				unsigned long size);
-int		nfsd_readdir(struct svc_rqst *, struct svc_fh *,
+__be32		nfsd_readdir(struct svc_rqst *, struct svc_fh *,
 			     loff_t *, struct readdir_cd *, encode_dent_fn);
-int		nfsd_statfs(struct svc_rqst *, struct svc_fh *,
+__be32		nfsd_statfs(struct svc_rqst *, struct svc_fh *,
 				struct kstatfs *);
 
 int		nfsd_notify_change(struct inode *, struct iattr *);
-int		nfsd_permission(struct svc_export *, struct dentry *, int);
+__be32		nfsd_permission(struct svc_export *, struct dentry *, int);
 int		nfsd_sync_dir(struct dentry *dp);
 
 #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
@@ -232,6 +232,7 @@
 #define	nfserr_badname		__constant_htonl(NFSERR_BADNAME)
 #define	nfserr_cb_path_down	__constant_htonl(NFSERR_CB_PATH_DOWN)
 #define	nfserr_locked		__constant_htonl(NFSERR_LOCKED)
+#define	nfserr_replay_me	__constant_htonl(NFSERR_REPLAY_ME)
 
 /* error codes for internal use */
 /* if a request fails due to kmalloc failure, it gets dropped.
diff -urN oldtree/include/linux/nfsd/nfsfh.h newtree/include/linux/nfsd/nfsfh.h
--- oldtree/include/linux/nfsd/nfsfh.h	2006-02-19 11:41:05.923442600 +0000
+++ newtree/include/linux/nfsd/nfsfh.h	2006-02-21 15:58:36.866541992 +0000
@@ -158,7 +158,7 @@
 	__u64			fh_post_size;	/* i_size */
 	unsigned long		fh_post_blocks; /* i_blocks */
 	unsigned long		fh_post_blksize;/* i_blksize */
-	__u32			fh_post_rdev[2];/* i_rdev */
+	__be32			fh_post_rdev[2];/* i_rdev */
 	struct timespec		fh_post_atime;	/* i_atime */
 	struct timespec		fh_post_mtime;	/* i_mtime */
 	struct timespec		fh_post_ctime;	/* i_ctime */
@@ -210,9 +210,9 @@
 /*
  * Function prototypes
  */
-u32	fh_verify(struct svc_rqst *, struct svc_fh *, int, int);
-int	fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *);
-int	fh_update(struct svc_fh *);
+__be32	fh_verify(struct svc_rqst *, struct svc_fh *, int, int);
+__be32	fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *);
+__be32	fh_update(struct svc_fh *);
 void	fh_put(struct svc_fh *);
 
 static __inline__ struct svc_fh *
diff -urN oldtree/include/linux/nfsd/state.h newtree/include/linux/nfsd/state.h
--- oldtree/include/linux/nfsd/state.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/nfsd/state.h	2006-02-21 15:58:36.867541840 +0000
@@ -125,7 +125,7 @@
 	char                    cl_recdir[HEXDIR_LEN]; /* recovery dir */
 	nfs4_verifier		cl_verifier; 	/* generated by client */
 	time_t                  cl_time;        /* time of last lease renewal */
-	u32			cl_addr; 	/* client ipaddress */
+	__be32			cl_addr; 	/* client ipaddress */
 	struct svc_cred		cl_cred; 	/* setclientid principal */
 	clientid_t		cl_clientid;	/* generated by server */
 	nfs4_verifier		cl_confirm;	/* generated by server */
@@ -164,7 +164,7 @@
  * is cached. 
  */
 struct nfs4_replay {
-	u32			rp_status;
+	__be32			rp_status;
 	unsigned int		rp_buflen;
 	char			*rp_buf;
 	unsigned		intrp_allocated;
@@ -273,19 +273,19 @@
 	((err) != nfserr_stale_stateid) &&      \
 	((err) != nfserr_bad_stateid))
 
-extern int nfsd4_renew(clientid_t *clid);
-extern int nfs4_preprocess_stateid_op(struct svc_fh *current_fh, 
+extern __be32 nfsd4_renew(clientid_t *clid);
+extern __be32 nfs4_preprocess_stateid_op(struct svc_fh *current_fh, 
 		stateid_t *stateid, int flags, struct file **filp);
 extern void nfs4_lock_state(void);
 extern void nfs4_unlock_state(void);
 extern int nfs4_in_grace(void);
-extern int nfs4_check_open_reclaim(clientid_t *clid);
+extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
 extern void put_nfs4_client(struct nfs4_client *clp);
 extern void nfs4_free_stateowner(struct kref *kref);
 extern void nfsd4_probe_callback(struct nfs4_client *clp);
 extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
 extern void nfs4_put_delegation(struct nfs4_delegation *dp);
-extern int nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
+extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
 extern void nfsd4_init_recdir(char *recdir_name);
 extern int nfsd4_recdir_load(void);
 extern void nfsd4_shutdown_recdir(void);
diff -urN oldtree/include/linux/nfsd/xdr.h newtree/include/linux/nfsd/xdr.h
--- oldtree/include/linux/nfsd/xdr.h	2006-02-19 11:41:05.923442600 +0000
+++ newtree/include/linux/nfsd/xdr.h	2006-02-21 15:58:36.869541536 +0000
@@ -83,7 +83,7 @@
 	struct svc_fh		fh;
 	__u32			cookie;
 	__u32			count;
-	u32 *			buffer;
+	__be32 *		buffer;
 };
 
 struct nfsd_attrstat {
@@ -110,9 +110,9 @@
 	int			count;
 
 	struct readdir_cd	common;
-	u32 *			buffer;
+	__be32 *		buffer;
 	int			buflen;
-	u32 *			offset;
+	__be32 *		offset;
 };
 
 struct nfsd_statfsres {
@@ -137,43 +137,43 @@
 #define NFS2_SVC_XDRSIZE	sizeof(union nfsd_xdrstore)
 
 
-int nfssvc_decode_void(struct svc_rqst *, u32 *, void *);
-int nfssvc_decode_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *);
-int nfssvc_decode_sattrargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_void(struct svc_rqst *, __be32 *, void *);
+int nfssvc_decode_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *);
+int nfssvc_decode_sattrargs(struct svc_rqst *, __be32 *,
 				struct nfsd_sattrargs *);
-int nfssvc_decode_diropargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_diropargs(struct svc_rqst *, __be32 *,
 				struct nfsd_diropargs *);
-int nfssvc_decode_readargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_readargs(struct svc_rqst *, __be32 *,
 				struct nfsd_readargs *);
-int nfssvc_decode_writeargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_writeargs(struct svc_rqst *, __be32 *,
 				struct nfsd_writeargs *);
-int nfssvc_decode_createargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_createargs(struct svc_rqst *, __be32 *,
 				struct nfsd_createargs *);
-int nfssvc_decode_renameargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_renameargs(struct svc_rqst *, __be32 *,
 				struct nfsd_renameargs *);
-int nfssvc_decode_readlinkargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_readlinkargs(struct svc_rqst *, __be32 *,
 				struct nfsd_readlinkargs *);
-int nfssvc_decode_linkargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_linkargs(struct svc_rqst *, __be32 *,
 				struct nfsd_linkargs *);
-int nfssvc_decode_symlinkargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_symlinkargs(struct svc_rqst *, __be32 *,
 				struct nfsd_symlinkargs *);
-int nfssvc_decode_readdirargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_readdirargs(struct svc_rqst *, __be32 *,
 				struct nfsd_readdirargs *);
-int nfssvc_encode_void(struct svc_rqst *, u32 *, void *);
-int nfssvc_encode_attrstat(struct svc_rqst *, u32 *, struct nfsd_attrstat *);
-int nfssvc_encode_diropres(struct svc_rqst *, u32 *, struct nfsd_diropres *);
-int nfssvc_encode_readlinkres(struct svc_rqst *, u32 *, struct nfsd_readlinkres *);
-int nfssvc_encode_readres(struct svc_rqst *, u32 *, struct nfsd_readres *);
-int nfssvc_encode_statfsres(struct svc_rqst *, u32 *, struct nfsd_statfsres *);
-int nfssvc_encode_readdirres(struct svc_rqst *, u32 *, struct nfsd_readdirres *);
+int nfssvc_encode_void(struct svc_rqst *, __be32 *, void *);
+int nfssvc_encode_attrstat(struct svc_rqst *, __be32 *, struct nfsd_attrstat *);
+int nfssvc_encode_diropres(struct svc_rqst *, __be32 *, struct nfsd_diropres *);
+int nfssvc_encode_readlinkres(struct svc_rqst *, __be32 *, struct nfsd_readlinkres *);
+int nfssvc_encode_readres(struct svc_rqst *, __be32 *, struct nfsd_readres *);
+int nfssvc_encode_statfsres(struct svc_rqst *, __be32 *, struct nfsd_statfsres *);
+int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *, struct nfsd_readdirres *);
 
 int nfssvc_encode_entry(struct readdir_cd *, const char *name,
 				int namlen, loff_t offset, ino_t ino, unsigned int);
 
-int nfssvc_release_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *);
+int nfssvc_release_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *);
 
 /* Helper functions for NFSv2 ACL code */
-u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp);
-u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp);
+__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp);
+__be32 *nfs2svc_decode_fh(__be32 *p, struct svc_fh *fhp);
 
 #endif /* LINUX_NFSD_H */
diff -urN oldtree/include/linux/nfsd/xdr3.h newtree/include/linux/nfsd/xdr3.h
--- oldtree/include/linux/nfsd/xdr3.h	2006-02-19 11:41:05.923442600 +0000
+++ newtree/include/linux/nfsd/xdr3.h	2006-02-21 15:58:36.867541840 +0000
@@ -53,7 +53,7 @@
 	int			len;
 	int			createmode;
 	struct iattr		attrs;
-	__u32 *			verf;
+	__be32 *		verf;
 };
 
 struct nfsd3_mknodargs {
@@ -100,8 +100,8 @@
 	__u64			cookie;
 	__u32			dircount;
 	__u32			count;
-	__u32 *			verf;
-	u32 *			buffer;
+	__be32 *		verf;
+	__be32 *		buffer;
 };
 
 struct nfsd3_commitargs {
@@ -124,79 +124,79 @@
 };
 
 struct nfsd3_attrstat {
-	__u32			status;
+	__be32			status;
 	struct svc_fh		fh;
 	struct kstat            stat;
 };
 
 /* LOOKUP, CREATE, MKDIR, SYMLINK, MKNOD */
 struct nfsd3_diropres  {
-	__u32			status;
+	__be32			status;
 	struct svc_fh		dirfh;
 	struct svc_fh		fh;
 };
 
 struct nfsd3_accessres {
-	__u32			status;
+	__be32			status;
 	struct svc_fh		fh;
 	__u32			access;
 };
 
 struct nfsd3_readlinkres {
-	__u32			status;
+	__be32			status;
 	struct svc_fh		fh;
 	__u32			len;
 };
 
 struct nfsd3_readres {
-	__u32			status;
+	__be32			status;
 	struct svc_fh		fh;
 	unsigned long		count;
 	int			eof;
 };
 
 struct nfsd3_writeres {
-	__u32			status;
+	__be32			status;
 	struct svc_fh		fh;
 	unsigned long		count;
 	int			committed;
 };
 
 struct nfsd3_renameres {
-	__u32			status;
+	__be32			status;
 	struct svc_fh		ffh;
 	struct svc_fh		tfh;
 };
 
 struct nfsd3_linkres {
-	__u32			status;
+	__be32			status;
 	struct svc_fh		tfh;
 	struct svc_fh		fh;
 };
 
 struct nfsd3_readdirres {
-	__u32			status;
+	__be32			status;
 	struct svc_fh		fh;
 	int			count;
-	__u32			verf[2];
+	__be32			verf[2];
 
 	struct readdir_cd	common;
-	u32 *			buffer;
+	__be32 *		buffer;
 	int			buflen;
-	u32 *			offset;
-	u32 *			offset1;
+	__be32 *		offset;
+	__be32 *		offset1;
 	struct svc_rqst *	rqstp;
 
 };
 
 struct nfsd3_fsstatres {
-	__u32			status;
+	__be32			status;
 	struct kstatfs		stats;
 	__u32			invarsec;
 };
 
 struct nfsd3_fsinfores {
-	__u32			status;
+	__be32			status;
 	__u32			f_rtmax;
 	__u32			f_rtpref;
 	__u32			f_rtmult;
@@ -209,7 +209,7 @@
 };
 
 struct nfsd3_pathconfres {
-	__u32			status;
+	__be32			status;
 	__u32			p_link_max;
 	__u32			p_name_max;
 	__u32			p_no_trunc;
@@ -219,12 +219,12 @@
 };
 
 struct nfsd3_commitres {
-	__u32			status;
+	__be32			status;
 	struct svc_fh		fh;
 };
 
 struct nfsd3_getaclres {
-	__u32			status;
+	__be32			status;
 	struct svc_fh		fh;
 	int			mask;
 	struct posix_acl	*acl_access;
@@ -268,70 +268,70 @@
 
 #define NFS3_SVC_XDRSIZE		sizeof(union nfsd3_xdrstore)
 
-int nfs3svc_decode_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *);
-int nfs3svc_decode_sattrargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *);
+int nfs3svc_decode_sattrargs(struct svc_rqst *, __be32 *,
 				struct nfsd3_sattrargs *);
-int nfs3svc_decode_diropargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_diropargs(struct svc_rqst *, __be32 *,
 				struct nfsd3_diropargs *);
-int nfs3svc_decode_accessargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_accessargs(struct svc_rqst *, __be32 *,
 				struct nfsd3_accessargs *);
-int nfs3svc_decode_readargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_readargs(struct svc_rqst *, __be32 *,
 				struct nfsd3_readargs *);
-int nfs3svc_decode_writeargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_writeargs(struct svc_rqst *, __be32 *,
 				struct nfsd3_writeargs *);
-int nfs3svc_decode_createargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_createargs(struct svc_rqst *, __be32 *,
 				struct nfsd3_createargs *);
-int nfs3svc_decode_mkdirargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_mkdirargs(struct svc_rqst *, __be32 *,
 				struct nfsd3_createargs *);
-int nfs3svc_decode_mknodargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_mknodargs(struct svc_rqst *, __be32 *,
 				struct nfsd3_mknodargs *);
-int nfs3svc_decode_renameargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_renameargs(struct svc_rqst *, __be32 *,
 				struct nfsd3_renameargs *);
-int nfs3svc_decode_readlinkargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_readlinkargs(struct svc_rqst *, __be32 *,
 				struct nfsd3_readlinkargs *);
-int nfs3svc_decode_linkargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_linkargs(struct svc_rqst *, __be32 *,
 				struct nfsd3_linkargs *);
-int nfs3svc_decode_symlinkargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_symlinkargs(struct svc_rqst *, __be32 *,
 				struct nfsd3_symlinkargs *);
-int nfs3svc_decode_readdirargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_readdirargs(struct svc_rqst *, __be32 *,
 				struct nfsd3_readdirargs *);
-int nfs3svc_decode_readdirplusargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_readdirplusargs(struct svc_rqst *, __be32 *,
 				struct nfsd3_readdirargs *);
-int nfs3svc_decode_commitargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_commitargs(struct svc_rqst *, __be32 *,
 				struct nfsd3_commitargs *);
-int nfs3svc_encode_voidres(struct svc_rqst *, u32 *, void *);
-int nfs3svc_encode_attrstat(struct svc_rqst *, u32 *,
+int nfs3svc_encode_voidres(struct svc_rqst *, __be32 *, void *);
+int nfs3svc_encode_attrstat(struct svc_rqst *, __be32 *,
 				struct nfsd3_attrstat *);
-int nfs3svc_encode_wccstat(struct svc_rqst *, u32 *,
+int nfs3svc_encode_wccstat(struct svc_rqst *, __be32 *,
 				struct nfsd3_attrstat *);
-int nfs3svc_encode_diropres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_diropres(struct svc_rqst *, __be32 *,
 				struct nfsd3_diropres *);
-int nfs3svc_encode_accessres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_accessres(struct svc_rqst *, __be32 *,
 				struct nfsd3_accessres *);
-int nfs3svc_encode_readlinkres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_readlinkres(struct svc_rqst *, __be32 *,
 				struct nfsd3_readlinkres *);
-int nfs3svc_encode_readres(struct svc_rqst *, u32 *, struct nfsd3_readres *);
-int nfs3svc_encode_writeres(struct svc_rqst *, u32 *, struct nfsd3_writeres *);
-int nfs3svc_encode_createres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_readres(struct svc_rqst *, __be32 *, struct nfsd3_readres *);
+int nfs3svc_encode_writeres(struct svc_rqst *, __be32 *, struct nfsd3_writeres *);
+int nfs3svc_encode_createres(struct svc_rqst *, __be32 *,
 				struct nfsd3_diropres *);
-int nfs3svc_encode_renameres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_renameres(struct svc_rqst *, __be32 *,
 				struct nfsd3_renameres *);
-int nfs3svc_encode_linkres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_linkres(struct svc_rqst *, __be32 *,
 				struct nfsd3_linkres *);
-int nfs3svc_encode_readdirres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_readdirres(struct svc_rqst *, __be32 *,
 				struct nfsd3_readdirres *);
-int nfs3svc_encode_fsstatres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_fsstatres(struct svc_rqst *, __be32 *,
 				struct nfsd3_fsstatres *);
-int nfs3svc_encode_fsinfores(struct svc_rqst *, u32 *,
+int nfs3svc_encode_fsinfores(struct svc_rqst *, __be32 *,
 				struct nfsd3_fsinfores *);
-int nfs3svc_encode_pathconfres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_pathconfres(struct svc_rqst *, __be32 *,
 				struct nfsd3_pathconfres *);
-int nfs3svc_encode_commitres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_commitres(struct svc_rqst *, __be32 *,
 				struct nfsd3_commitres *);
 
-int nfs3svc_release_fhandle(struct svc_rqst *, u32 *,
+int nfs3svc_release_fhandle(struct svc_rqst *, __be32 *,
 				struct nfsd3_attrstat *);
-int nfs3svc_release_fhandle2(struct svc_rqst *, u32 *,
+int nfs3svc_release_fhandle2(struct svc_rqst *, __be32 *,
 				struct nfsd3_fhandle_pair *);
 int nfs3svc_encode_entry(struct readdir_cd *, const char *name,
 				int namlen, loff_t offset, ino_t ino,
@@ -340,9 +340,9 @@
 				int namlen, loff_t offset, ino_t ino,
 				unsigned int);
 /* Helper functions for NFSv3 ACL code */
-u32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p,
+__be32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p,
 				struct svc_fh *fhp);
-u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp);
+__be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp);
 
 
 #endif /* _LINUX_NFSD_XDR3_H */
diff -urN oldtree/include/linux/nfsd/xdr4.h newtree/include/linux/nfsd/xdr4.h
--- oldtree/include/linux/nfsd/xdr4.h	2006-02-19 11:41:05.924442448 +0000
+++ newtree/include/linux/nfsd/xdr4.h	2006-02-21 15:58:36.868541688 +0000
@@ -259,9 +259,9 @@
 	struct svc_fh * rd_fhp;             /* response */
 
 	struct readdir_cd	common;
-	u32 *			buffer;
+	__be32 *		buffer;
 	int			buflen;
-	u32 *			offset;
+	__be32 *		offset;
 };
 
 struct nfsd4_release_lockowner {
@@ -336,7 +336,7 @@
 
 struct nfsd4_op {
 	int					opnum;
-	int					status;
+	__be32					status;
 	union {
 		struct nfsd4_access		access;
 		struct nfsd4_close		close;
@@ -373,12 +373,12 @@
 
 struct nfsd4_compoundargs {
 	/* scratch variables for XDR decode */
-	u32 *				p;
-	u32 *				end;
+	__be32 *			p;
+	__be32 *			end;
 	struct page **			pagelist;
 	int				pagelen;
-	u32				tmp[8];
-	u32 *				tmpp;
+	__be32				tmp[8];
+	__be32 *			tmpp;
 	struct tmpbuf {
 		struct tmpbuf *next;
 		void (*release)(const void *);
@@ -397,15 +397,15 @@
 
 struct nfsd4_compoundres {
 	/* scratch variables for XDR encode */
-	u32 *				p;
-	u32 *				end;
+	__be32 *			p;
+	__be32 *			end;
 	struct xdr_buf *		xbuf;
 	struct svc_rqst *		rqstp;
 
 	u32				taglen;
 	char *				tag;
 	u32				opcnt;
-	u32 *				tagp; /* where to encode tag and  opcount */
+	__be32 *			tagp; /* where to encode tag and  opcount */
 };
 
 #define NFS4_SVC_XDRSIZE		sizeof(struct nfsd4_compoundargs)
@@ -421,45 +421,45 @@
 	cinfo->after_ctime_nsec = fhp->fh_post_ctime.tv_nsec;
 }
 
-int nfs4svc_encode_voidres(struct svc_rqst *, u32 *, void *);
-int nfs4svc_decode_compoundargs(struct svc_rqst *, u32 *, 
+int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *);
+int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *, 
 		struct nfsd4_compoundargs *);
-int nfs4svc_encode_compoundres(struct svc_rqst *, u32 *, 
+int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *, 
 		struct nfsd4_compoundres *);
 void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
 void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op);
-int nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
-		       struct dentry *dentry, u32 *buffer, int *countp, 
+__be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
+		       struct dentry *dentry, __be32 *buffer, int *countp, 
 		       u32 *bmval, struct svc_rqst *);
-extern int nfsd4_setclientid(struct svc_rqst *rqstp, 
+extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp, 
 		struct nfsd4_setclientid *setclid);
-extern int nfsd4_setclientid_confirm(struct svc_rqst *rqstp, 
+extern __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp, 
 		struct nfsd4_setclientid_confirm *setclientid_confirm);
-extern int nfsd4_process_open1(struct nfsd4_open *open);
-extern int nfsd4_process_open2(struct svc_rqst *rqstp, 
+extern __be32 nfsd4_process_open1(struct nfsd4_open *open);
+extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp, 
 		struct svc_fh *current_fh, struct nfsd4_open *open);
-extern int nfsd4_open_confirm(struct svc_rqst *rqstp, 
+extern __be32 nfsd4_open_confirm(struct svc_rqst *rqstp, 
 		struct svc_fh *current_fh, struct nfsd4_open_confirm *oc,
 		struct nfs4_stateowner **);
-extern  int nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, 
+extern __be32 nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, 
 		struct nfsd4_close *close,
 		struct nfs4_stateowner **replay_owner);
-extern int nfsd4_open_downgrade(struct svc_rqst *rqstp, 
+extern __be32 nfsd4_open_downgrade(struct svc_rqst *rqstp, 
 		struct svc_fh *current_fh, struct nfsd4_open_downgrade *od,
 		struct nfs4_stateowner **replay_owner);
-extern int nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, 
+extern __be32 nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, 
 		struct nfsd4_lock *lock,
 		struct nfs4_stateowner **replay_owner);
-extern int nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, 
+extern __be32 nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, 
 		struct nfsd4_lockt *lockt);
-extern int nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, 
+extern __be32 nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, 
 		struct nfsd4_locku *locku,
 		struct nfs4_stateowner **replay_owner);
-extern int
+extern __be32
 nfsd4_release_lockowner(struct svc_rqst *rqstp,
 		struct nfsd4_release_lockowner *rlockowner);
 extern void nfsd4_release_compoundargs(struct nfsd4_compoundargs *);
-extern int nfsd4_delegreturn(struct svc_rqst *rqstp,
+extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp,
 		struct svc_fh *current_fh, struct nfsd4_delegreturn *dr);
 #endif
 
diff -urN oldtree/include/linux/pagemap.h newtree/include/linux/pagemap.h
--- oldtree/include/linux/pagemap.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/pagemap.h	2006-02-21 15:58:29.585648856 +0000
@@ -51,6 +51,10 @@
 #define page_cache_release(page)	put_page(page)
 void release_pages(struct page **pages, int nr, int cold);
 
+#ifdef CONFIG_NUMA
+extern struct page *page_cache_alloc(struct address_space *x);
+extern struct page *page_cache_alloc_cold(struct address_space *x);
+#else
 static inline struct page *page_cache_alloc(struct address_space *x)
 {
 	return alloc_pages(mapping_gfp_mask(x), 0);
@@ -60,6 +64,7 @@
 {
 	return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD, 0);
 }
+#endif
 
 typedef int filler_t(void *, struct page *);
 
diff -urN oldtree/include/linux/parser.h newtree/include/linux/parser.h
--- oldtree/include/linux/parser.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/parser.h	2006-02-21 15:58:23.521570736 +0000
@@ -31,3 +31,5 @@
 int match_hex(substring_t *, int *result);
 void match_strcpy(char *, substring_t *);
 char *match_strdup(substring_t *);
+int match_u64(substring_t *, u64 *result, int);
+int match_s64(substring_t *, s64 *result, int);
diff -urN oldtree/include/linux/pci.h newtree/include/linux/pci.h
--- oldtree/include/linux/pci.h	2006-02-19 11:41:05.927441992 +0000
+++ newtree/include/linux/pci.h	2006-02-21 15:58:17.994410992 +0000
@@ -516,6 +516,7 @@
 void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
 		  void *userdata);
 int pci_cfg_space_size(struct pci_dev *dev);
+unsigned char pci_bus_max_busnr(struct pci_bus* bus);
 
 /* kmem_cache style wrapper around pci_alloc_consistent() */
 
diff -urN oldtree/include/linux/pci_ids.h newtree/include/linux/pci_ids.h
--- oldtree/include/linux/pci_ids.h	2006-02-19 11:41:05.929441688 +0000
+++ newtree/include/linux/pci_ids.h	2006-02-21 15:58:29.977589272 +0000
@@ -69,6 +69,7 @@
 #define PCI_CLASS_SYSTEM_TIMER		0x0802
 #define PCI_CLASS_SYSTEM_RTC		0x0803
 #define PCI_CLASS_SYSTEM_PCI_HOTPLUG	0x0804
+#define PCI_CLASS_SYSTEM_SDHCI		0x0805
 #define PCI_CLASS_SYSTEM_OTHER		0x0880
 
 #define PCI_BASE_CLASS_INPUT		0x09
@@ -1854,12 +1855,14 @@
 #define PCI_DEVICE_ID_TIGON3_5705M	0x165d
 #define PCI_DEVICE_ID_TIGON3_5705M_2	0x165e
 #define PCI_DEVICE_ID_TIGON3_5714	0x1668
+#define PCI_DEVICE_ID_TIGON3_5714S	0x1669
 #define PCI_DEVICE_ID_TIGON3_5780	0x166a
 #define PCI_DEVICE_ID_TIGON3_5780S	0x166b
 #define PCI_DEVICE_ID_TIGON3_5705F	0x166e
 #define PCI_DEVICE_ID_TIGON3_5750	0x1676
 #define PCI_DEVICE_ID_TIGON3_5751	0x1677
 #define PCI_DEVICE_ID_TIGON3_5715	0x1678
+#define PCI_DEVICE_ID_TIGON3_5715S	0x1679
 #define PCI_DEVICE_ID_TIGON3_5750M	0x167c
 #define PCI_DEVICE_ID_TIGON3_5751M	0x167d
 #define PCI_DEVICE_ID_TIGON3_5751F	0x167e
diff -urN oldtree/include/linux/pm.h newtree/include/linux/pm.h
--- oldtree/include/linux/pm.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/pm.h	2006-02-21 15:58:23.207618464 +0000
@@ -140,6 +140,7 @@
 
 typedef struct pm_message {
 	int event;
+	u32 state;
 } pm_message_t;
 
 /*
diff -urN oldtree/include/linux/rtnetlink.h newtree/include/linux/rtnetlink.h
--- oldtree/include/linux/rtnetlink.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/rtnetlink.h	2006-02-21 15:58:16.576626528 +0000
@@ -733,6 +733,8 @@
 #define IFLA_MAP IFLA_MAP
 	IFLA_WEIGHT,
 #define IFLA_WEIGHT IFLA_WEIGHT
+	IFLA_OPERSTATE,
+	IFLA_LINKMODE,
 	__IFLA_MAX
 };
 
@@ -905,6 +907,7 @@
 #ifdef __KERNEL__
 
 #include <linux/config.h>
+#include <linux/mutex.h>
 
 extern size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size);
 static __inline__ int rtattr_strcmp(const struct rtattr *rta, const char *str)
@@ -1036,24 +1039,17 @@
 
 extern void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change);
 
-extern struct semaphore rtnl_sem;
-
-#define rtnl_shlock()		down(&rtnl_sem)
-#define rtnl_shlock_nowait()	down_trylock(&rtnl_sem)
-
-#define rtnl_shunlock()	do { up(&rtnl_sem); \
-		             if (rtnl && rtnl->sk_receive_queue.qlen) \
-				     rtnl->sk_data_ready(rtnl, 0); \
-		        } while(0)
-
+/* RTNL is used as a global lock for all changes to network configuration  */
 extern void rtnl_lock(void);
-extern int rtnl_lock_interruptible(void);
 extern void rtnl_unlock(void);
+extern int rtnl_trylock(void);
+
 extern void rtnetlink_init(void);
+extern void __rtnl_unlock(void);
 
 #define ASSERT_RTNL() do { \
-	if (unlikely(down_trylock(&rtnl_sem) == 0)) { \
-		up(&rtnl_sem); \
+	if (unlikely(rtnl_trylock())) { \
+		rtnl_unlock(); \
 		printk(KERN_ERR "RTNL: assertion failed at %s (%d)\n", \
 		       __FILE__,  __LINE__); \
 		dump_stack(); \
diff -urN oldtree/include/linux/sched.h newtree/include/linux/sched.h
--- oldtree/include/linux/sched.h	2006-02-19 11:41:05.947438952 +0000
+++ newtree/include/linux/sched.h	2006-02-21 15:58:35.652726520 +0000
@@ -39,6 +39,7 @@
 #include <linux/auxvec.h>	/* For AT_VECTOR_SIZE */
 
 struct exec_domain;
+struct bio;
 
 /*
  * cloning flags:
@@ -705,6 +706,7 @@
 	prio_array_t *array;
 
 	unsigned short ioprio;
+	unsigned int btrace_seq;
 
 	unsigned long sleep_avg;
 	unsigned long long timestamp, last_ran;
@@ -835,6 +837,9 @@
 /* journalling filesystem info */
 	void *journal_info;
 
+/* stacked block device info */
+	struct bio *bio_list, **bio_tail;
+
 /* VM state */
 	struct reclaim_state *reclaim_state;
 
@@ -867,6 +872,7 @@
 	struct cpuset *cpuset;
 	nodemask_t mems_allowed;
 	int cpuset_mems_generation;
+	int cpuset_mem_spread_rotor;
 #endif
 	atomic_t fs_excl;	/* holding fs exclusive resources */
 	struct rcu_head rcu;
@@ -928,6 +934,9 @@
 #define PF_BORROWED_MM	0x00400000	/* I am a kthread doing use_mm */
 #define PF_RANDOMIZE	0x00800000	/* randomize virtual address space */
 #define PF_SWAPWRITE	0x01000000	/* Allowed to write to swap */
+#define PF_SPREAD_PAGE	0x04000000	/* Spread page cache over cpuset */
+#define PF_SPREAD_SLAB	0x08000000	/* Spread some slab caches over cpuset */
+#define PF_MEMPOLICY	0x10000000	/* Non-default NUMA mempolicy */
 
 /*
  * Only the _current_ task can read/write to tsk->flags, but other
@@ -1236,6 +1245,15 @@
 	spin_unlock(&p->alloc_lock);
 }
 
+extern struct sighand_struct *lock_task_sighand(struct task_struct *tsk,
+							unsigned long *flags);
+
+static inline void unlock_task_sighand(struct task_struct *tsk,
+						unsigned long *flags)
+{
+	spin_unlock_irqrestore(&tsk->sighand->siglock, *flags);
+}
+
 #ifndef __HAVE_THREAD_FUNCTIONS
 
 #define task_thread_info(task) (task)->thread_info
diff -urN oldtree/include/linux/security.h newtree/include/linux/security.h
--- oldtree/include/linux/security.h	2006-02-19 11:41:05.950438496 +0000
+++ newtree/include/linux/security.h	2006-02-21 15:58:11.801352480 +0000
@@ -869,6 +869,11 @@
  *	@ipcp contains the kernel IPC permission structure
  *	@flag contains the desired (requested) permission set
  *	Return 0 if permission is granted.
+ * @ipc_getsecurity:
+ *      Copy the security label associated with the ipc object into
+ *      @buffer.  @buffer may be NULL to request the size of the buffer 
+ *      required.  @size indicates the size of @buffer in bytes. Return 
+ *      number of bytes used/required on success.
  *
  * Security hooks for individual messages held in System V IPC message queues
  * @msg_msg_alloc_security:
@@ -1168,7 +1173,8 @@
 	int (*inode_getxattr) (struct dentry *dentry, char *name);
 	int (*inode_listxattr) (struct dentry *dentry);
 	int (*inode_removexattr) (struct dentry *dentry, char *name);
-  	int (*inode_getsecurity)(struct inode *inode, const char *name, void *buffer, size_t size, int err);
+	const char *(*inode_xattr_getsuffix) (void);
+  	int (*inode_getsecurity)(const struct inode *inode, const char *name, void *buffer, size_t size, int err);
   	int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
   	int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size);
 
@@ -1217,6 +1223,7 @@
 	void (*task_to_inode)(struct task_struct *p, struct inode *inode);
 
 	int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag);
+	int (*ipc_getsecurity)(struct kern_ipc_perm *ipcp, void *buffer, size_t size);
 
 	int (*msg_msg_alloc_security) (struct msg_msg * msg);
 	void (*msg_msg_free_security) (struct msg_msg * msg);
@@ -1674,7 +1681,12 @@
 	return security_ops->inode_removexattr (dentry, name);
 }
 
-static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
+static inline const char *security_inode_xattr_getsuffix(void)
+{
+	return security_ops->inode_xattr_getsuffix();
+}
+
+static inline int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
 {
 	if (unlikely (IS_PRIVATE (inode)))
 		return 0;
@@ -1869,6 +1881,11 @@
 	return security_ops->ipc_permission (ipcp, flag);
 }
 
+static inline int security_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
+{
+	return security_ops->ipc_getsecurity(ipcp, buffer, size);
+}
+
 static inline int security_msg_msg_alloc (struct msg_msg * msg)
 {
 	return security_ops->msg_msg_alloc_security (msg);
@@ -2316,7 +2333,12 @@
 	return cap_inode_removexattr(dentry, name);
 }
 
-static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
+static inline const char *security_inode_xattr_getsuffix (void)
+{
+	return NULL ;
+}
+
+static inline int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
 {
 	return -EOPNOTSUPP;
 }
@@ -2499,6 +2521,11 @@
 	return 0;
 }
 
+static inline int security_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
+{
+	return -EOPNOTSUPP;
+}
+
 static inline int security_msg_msg_alloc (struct msg_msg * msg)
 {
 	return 0;
diff -urN oldtree/include/linux/seq_file.h newtree/include/linux/seq_file.h
--- oldtree/include/linux/seq_file.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/seq_file.h	2006-02-21 15:58:26.210162008 +0000
@@ -4,7 +4,7 @@
 
 #include <linux/types.h>
 #include <linux/string.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 struct seq_operations;
 struct file;
@@ -19,7 +19,7 @@
 	size_t count;
 	loff_t index;
 	loff_t version;
-	struct semaphore sem;
+	struct mutex lock;
 	struct seq_operations *op;
 	void *private;
 };
diff -urN oldtree/include/linux/serial_core.h newtree/include/linux/serial_core.h
--- oldtree/include/linux/serial_core.h	2006-02-19 11:41:05.952438192 +0000
+++ newtree/include/linux/serial_core.h	2006-02-21 15:58:20.802984024 +0000
@@ -127,6 +127,9 @@
 /* Hilscher netx */
 #define PORT_NETX	71
 
+/* SUN4V Hypervisor Console */
+#define PORT_SUNHV	72
+
 #ifdef __KERNEL__
 
 #include <linux/config.h>
diff -urN oldtree/include/linux/skbuff.h newtree/include/linux/skbuff.h
--- oldtree/include/linux/skbuff.h	2006-02-19 11:41:05.954437888 +0000
+++ newtree/include/linux/skbuff.h	2006-02-21 15:58:36.878540168 +0000
@@ -137,7 +137,7 @@
 	unsigned short	tso_size;
 	unsigned short	tso_segs;
 	unsigned short  ufo_size;
-	unsigned int    ip6_frag_id;
+	__be32		ip6_frag_id;
 	struct sk_buff	*frag_list;
 	skb_frag_t	frags[MAX_SKB_FRAGS];
 };
@@ -270,7 +270,6 @@
 
 	void			(*destructor)(struct sk_buff *skb);
 #ifdef CONFIG_NETFILTER
-	__u32			nfmark;
 	struct nf_conntrack	*nfct;
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 	struct sk_buff		*nfct_reasm;
@@ -278,6 +277,7 @@
 #ifdef CONFIG_BRIDGE_NETFILTER
 	struct nf_bridge_info	*nf_bridge;
 #endif
+	__u32			nfmark;
 #endif /* CONFIG_NETFILTER */
 #ifdef CONFIG_NET_SCHED
 	__u16			tc_index;	/* traffic control index */
diff -urN oldtree/include/linux/slab.h newtree/include/linux/slab.h
--- oldtree/include/linux/slab.h	2006-02-19 11:41:05.955437736 +0000
+++ newtree/include/linux/slab.h	2006-02-21 15:58:29.615644296 +0000
@@ -47,6 +47,7 @@
 						   what is reclaimable later*/
 #define SLAB_PANIC		0x00040000UL	/* panic if kmem_cache_create() fails */
 #define SLAB_DESTROY_BY_RCU	0x00080000UL	/* defer freeing pages to RCU */
+#define SLAB_MEM_SPREAD		0x00100000UL	/* Spread some memory over cpuset */
 
 /* flags passed to a constructor func */
 #define	SLAB_CTOR_CONSTRUCTOR	0x001UL		/* if not set, then deconstructor */
diff -urN oldtree/include/linux/smb_fs.h newtree/include/linux/smb_fs.h
--- oldtree/include/linux/smb_fs.h	2006-02-19 11:41:05.955437736 +0000
+++ newtree/include/linux/smb_fs.h	2006-02-21 15:58:36.886538952 +0000
@@ -43,17 +43,17 @@
 
 /* macro names are short for word, double-word, long value (?) */
 #define WVAL(buf,pos) \
-	(le16_to_cpu(get_unaligned((u16 *)((u8 *)(buf) + (pos)))))
+	(le16_to_cpu(get_unaligned((__le16 *)((u8 *)(buf) + (pos)))))
 #define DVAL(buf,pos) \
-	(le32_to_cpu(get_unaligned((u32 *)((u8 *)(buf) + (pos)))))
+	(le32_to_cpu(get_unaligned((__le32 *)((u8 *)(buf) + (pos)))))
 #define LVAL(buf,pos) \
-	(le64_to_cpu(get_unaligned((u64 *)((u8 *)(buf) + (pos)))))
+	(le64_to_cpu(get_unaligned((__le64 *)((u8 *)(buf) + (pos)))))
 #define WSET(buf,pos,val) \
-	put_unaligned(cpu_to_le16((u16)(val)), (u16 *)((u8 *)(buf) + (pos)))
+	put_unaligned(cpu_to_le16((u16)(val)), (__le16 *)((u8 *)(buf) + (pos)))
 #define DSET(buf,pos,val) \
-	put_unaligned(cpu_to_le32((u32)(val)), (u32 *)((u8 *)(buf) + (pos)))
+	put_unaligned(cpu_to_le32((u32)(val)), (__le32 *)((u8 *)(buf) + (pos)))
 #define LSET(buf,pos,val) \
-	put_unaligned(cpu_to_le64((u64)(val)), (u64 *)((u8 *)(buf) + (pos)))
+	put_unaligned(cpu_to_le64((u64)(val)), (__le64 *)((u8 *)(buf) + (pos)))
 
 /* where to find the base of the SMB packet proper */
 #define smb_base(buf) ((u8 *)(((u8 *)(buf))+4))
diff -urN oldtree/include/linux/stat.h newtree/include/linux/stat.h
--- oldtree/include/linux/stat.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/stat.h	2006-02-21 15:58:31.574346528 +0000
@@ -69,7 +69,7 @@
 	struct timespec	mtime;
 	struct timespec	ctime;
 	unsigned long	blksize;
-	unsigned long	blocks;
+	unsigned long long	blocks;
 };
 
 #endif
diff -urN oldtree/include/linux/statfs.h newtree/include/linux/statfs.h
--- oldtree/include/linux/statfs.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/statfs.h	2006-02-21 15:58:31.797312632 +0000
@@ -8,11 +8,11 @@
 struct kstatfs {
 	long f_type;
 	long f_bsize;
-	sector_t f_blocks;
-	sector_t f_bfree;
-	sector_t f_bavail;
-	sector_t f_files;
-	sector_t f_ffree;
+	u64 f_blocks;
+	u64 f_bfree;
+	u64 f_bavail;
+	u64 f_files;
+	u64 f_ffree;
 	__kernel_fsid_t f_fsid;
 	long f_namelen;
 	long f_frsize;
diff -urN oldtree/include/linux/sunrpc/auth.h newtree/include/linux/sunrpc/auth.h
--- oldtree/include/linux/sunrpc/auth.h	2006-02-19 11:41:05.960436976 +0000
+++ newtree/include/linux/sunrpc/auth.h	2006-02-21 15:58:36.886538952 +0000
@@ -110,13 +110,13 @@
 	void			(*crdestroy)(struct rpc_cred *);
 
 	int			(*crmatch)(struct auth_cred *, struct rpc_cred *, int);
-	u32 *			(*crmarshal)(struct rpc_task *, u32 *);
+	__be32 *		(*crmarshal)(struct rpc_task *, __be32 *);
 	int			(*crrefresh)(struct rpc_task *);
-	u32 *			(*crvalidate)(struct rpc_task *, u32 *);
+	__be32 *		(*crvalidate)(struct rpc_task *, __be32 *);
 	int			(*crwrap_req)(struct rpc_task *, kxdrproc_t,
-						void *, u32 *, void *);
+						void *, __be32 *, void *);
 	int			(*crunwrap_resp)(struct rpc_task *, kxdrproc_t,
-						void *, u32 *, void *);
+						void *, __be32 *, void *);
 };
 
 extern struct rpc_authops	authunix_ops;
@@ -135,10 +135,10 @@
 void			rpcauth_holdcred(struct rpc_task *);
 void			put_rpccred(struct rpc_cred *);
 void			rpcauth_unbindcred(struct rpc_task *);
-u32 *			rpcauth_marshcred(struct rpc_task *, u32 *);
-u32 *			rpcauth_checkverf(struct rpc_task *, u32 *);
-int			rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, u32 *data, void *obj);
-int			rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, u32 *data, void *obj);
+__be32 *		rpcauth_marshcred(struct rpc_task *, __be32 *);
+__be32 *		rpcauth_checkverf(struct rpc_task *, __be32 *);
+int			rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, __be32 *data, void *obj);
+int			rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, __be32 *data, void *obj);
 int			rpcauth_refreshcred(struct rpc_task *);
 void			rpcauth_invalcred(struct rpc_task *);
 int			rpcauth_uptodatecred(struct rpc_task *);
diff -urN oldtree/include/linux/sunrpc/msg_prot.h newtree/include/linux/sunrpc/msg_prot.h
--- oldtree/include/linux/sunrpc/msg_prot.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/sunrpc/msg_prot.h	2006-02-21 15:58:36.887538800 +0000
@@ -95,7 +95,7 @@
  * 2GB.
  */
 
-typedef u32	rpc_fraghdr;
+typedef __be32	rpc_fraghdr;
 
 #define	RPC_LAST_STREAM_FRAGMENT	(1U << 31)
 #define	RPC_FRAGMENT_SIZE_MASK		(~RPC_LAST_STREAM_FRAGMENT)
diff -urN oldtree/include/linux/sunrpc/svc.h newtree/include/linux/sunrpc/svc.h
--- oldtree/include/linux/sunrpc/svc.h	2006-02-19 11:41:05.962436672 +0000
+++ newtree/include/linux/sunrpc/svc.h	2006-02-21 15:58:36.888538648 +0000
@@ -78,6 +78,23 @@
  */
 #define RPCSVC_MAXPAGES		((RPCSVC_MAXPAYLOAD+PAGE_SIZE-1)/PAGE_SIZE + 2)
 
+static inline u32 svc_getnl(struct kvec *iov)
+{
+	__be32 val, *vp;
+	vp = iov->iov_base;
+	val = *vp++;
+	iov->iov_base = (void*)vp;
+	iov->iov_len -= sizeof(__be32);
+	return ntohl(val);
+}
+
+static inline void svc_putnl(struct kvec *iov, u32 val)
+{
+	__be32 *vp = iov->iov_base + iov->iov_len;
+	*vp = htonl(val);
+	iov->iov_len += sizeof(__be32);
+}
+
 static inline u32 svc_getu32(struct kvec *iov)
 {
 	u32 val, *vp;
@@ -167,7 +184,7 @@
  * Check buffer bounds after decoding arguments
  */
 static inline int
-xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
+xdr_argsize_check(struct svc_rqst *rqstp, __be32 *p)
 {
 	char *cp = (char *)p;
 	struct kvec *vec = &rqstp->rq_arg.head[0];
@@ -176,7 +193,7 @@
 }
 
 static inline int
-xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
+xdr_ressize_check(struct svc_rqst *rqstp, __be32 *p)
 {
 	struct kvec *vec = &rqstp->rq_res.head[0];
 	char *cp = (char*)p;
@@ -281,13 +298,13 @@
 	 * A return value of 0 means drop the request. 
 	 * vs_dispatch == NULL means use default dispatcher.
 	 */
-	int			(*vs_dispatch)(struct svc_rqst *, u32 *);
+	int			(*vs_dispatch)(struct svc_rqst *, __be32 *);
 };
 
 /*
  * RPC procedure info
  */
-typedef int	(*svc_procfunc)(struct svc_rqst *, void *argp, void *resp);
+typedef __be32	(*svc_procfunc)(struct svc_rqst *, void *argp, void *resp);
 struct svc_procedure {
 	svc_procfunc		pc_func;	/* process the request */
 	kxdrproc_t		pc_decode;	/* XDR decode args */
diff -urN oldtree/include/linux/sunrpc/svcauth.h newtree/include/linux/sunrpc/svcauth.h
--- oldtree/include/linux/sunrpc/svcauth.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/sunrpc/svcauth.h	2006-02-21 15:58:36.887538800 +0000
@@ -91,7 +91,7 @@
 	char *	name;
 	struct module *owner;
 	int	flavour;
-	int	(*accept)(struct svc_rqst *rq, u32 *authp);
+	int	(*accept)(struct svc_rqst *rq, __be32 *authp);
 	int	(*release)(struct svc_rqst *rq);
 	void	(*domain_release)(struct auth_domain *);
 	int	(*set_client)(struct svc_rqst *rq);
@@ -108,7 +108,7 @@
 #define	SVC_COMPLETE	9
 
 
-extern int	svc_authenticate(struct svc_rqst *rqstp, u32 *authp);
+extern int	svc_authenticate(struct svc_rqst *rqstp, __be32 *authp);
 extern int	svc_authorise(struct svc_rqst *rqstp);
 extern int	svc_set_client(struct svc_rqst *rqstp);
 extern int	svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops);
diff -urN oldtree/include/linux/sunrpc/svcsock.h newtree/include/linux/sunrpc/svcsock.h
--- oldtree/include/linux/sunrpc/svcsock.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/sunrpc/svcsock.h	2006-02-21 15:58:16.803592024 +0000
@@ -36,7 +36,7 @@
 
 	struct list_head	sk_deferred;	/* deferred requests that need to
 						 * be revisted */
-	struct semaphore        sk_sem;		/* to serialize sending data */
+	struct mutex		sk_mutex;	/* to serialize sending data */
 
 	int			(*sk_recvfrom)(struct svc_rqst *rqstp);
 	int			(*sk_sendto)(struct svc_rqst *rqstp);
diff -urN oldtree/include/linux/sunrpc/xdr.h newtree/include/linux/sunrpc/xdr.h
--- oldtree/include/linux/sunrpc/xdr.h	2006-02-19 11:41:05.962436672 +0000
+++ newtree/include/linux/sunrpc/xdr.h	2006-02-21 15:58:36.888538648 +0000
@@ -32,7 +32,7 @@
  * side) or svc_rqst pointer (server side).
  * Encode functions always assume there's enough room in the buffer.
  */
-typedef int	(*kxdrproc_t)(void *rqstp, u32 *data, void *obj);
+typedef int	(*kxdrproc_t)(void *rqstp, __be32 *data, void *obj);
 
 /*
  * Basic structure for transmission/reception of a client XDR message.
@@ -88,19 +88,19 @@
 /*
  * Miscellaneous XDR helper functions
  */
-u32 *	xdr_encode_opaque_fixed(u32 *p, const void *ptr, unsigned int len);
-u32 *	xdr_encode_opaque(u32 *p, const void *ptr, unsigned int len);
-u32 *	xdr_encode_string(u32 *p, const char *s);
-u32 *	xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen);
-u32 *	xdr_encode_netobj(u32 *p, const struct xdr_netobj *);
-u32 *	xdr_decode_netobj(u32 *p, struct xdr_netobj *);
+__be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int len);
+__be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int len);
+__be32 *xdr_encode_string(__be32 *p, const char *s);
+__be32 *xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen);
+__be32 *xdr_encode_netobj(__be32 *p, const struct xdr_netobj *);
+__be32 *xdr_decode_netobj(__be32 *p, struct xdr_netobj *);
 
 void	xdr_encode_pages(struct xdr_buf *, struct page **, unsigned int,
 			 unsigned int);
 void	xdr_inline_pages(struct xdr_buf *, unsigned int,
 			 struct page **, unsigned int, unsigned int);
 
-static inline u32 *xdr_encode_array(u32 *p, const void *s, unsigned int len)
+static inline __be32 *xdr_encode_array(__be32 *p, const void *s, unsigned int len)
 {
 	return xdr_encode_opaque(p, s, len);
 }
@@ -108,16 +108,16 @@
 /*
  * Decode 64bit quantities (NFSv3 support)
  */
-static inline u32 *
-xdr_encode_hyper(u32 *p, __u64 val)
+static inline __be32 *
+xdr_encode_hyper(__be32 *p, __u64 val)
 {
 	*p++ = htonl(val >> 32);
 	*p++ = htonl(val & 0xFFFFFFFF);
 	return p;
 }
 
-static inline u32 *
-xdr_decode_hyper(u32 *p, __u64 *valp)
+static inline __be32 *
+xdr_decode_hyper(__be32 *p, __u64 *valp)
 {
 	*valp  = ((__u64) ntohl(*p++)) << 32;
 	*valp |= ntohl(*p++);
@@ -128,7 +128,7 @@
  * Adjust kvec to reflect end of xdr'ed data (RPC client XDR)
  */
 static inline int
-xdr_adjust_iovec(struct kvec *iov, u32 *p)
+xdr_adjust_iovec(struct kvec *iov, __be32 *p)
 {
 	return iov->iov_len = ((u8 *) p - (u8 *) iov->iov_base);
 }
@@ -180,19 +180,19 @@
  * Provide some simple tools for XDR buffer overflow-checking etc.
  */
 struct xdr_stream {
-	uint32_t *p;		/* start of available buffer */
+	__be32 *p;		/* start of available buffer */
 	struct xdr_buf *buf;	/* XDR buffer to read/write */
 
-	uint32_t *end;		/* end of available buffer space */
+	__be32 *end;		/* end of available buffer space */
 	struct kvec *iov;	/* pointer to the current kvec */
 };
 
-extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p);
-extern uint32_t *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
+extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
+extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
 extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
 		unsigned int base, unsigned int len);
-extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p);
-extern uint32_t *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
+extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
+extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
 extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
 
 #endif /* __KERNEL__ */
diff -urN oldtree/include/linux/sunrpc/xprt.h newtree/include/linux/sunrpc/xprt.h
--- oldtree/include/linux/sunrpc/xprt.h	2006-02-19 11:41:05.963436520 +0000
+++ newtree/include/linux/sunrpc/xprt.h	2006-02-21 15:58:36.889538496 +0000
@@ -69,7 +69,7 @@
 	 * This is the private part
 	 */
 	struct rpc_task *	rq_task;	/* RPC task data */
-	__u32			rq_xid;		/* request XID */
+	__be32			rq_xid;		/* request XID */
 	int			rq_cong;	/* has incremented xprt->cong */
 	int			rq_received;	/* receive completed */
 	u32			rq_seqno;	/* gss seq no. used on req. */
@@ -155,9 +155,9 @@
 	/*
 	 * State of TCP reply receive stuff
 	 */
-	u32			tcp_recm,	/* Fragment header */
-				tcp_xid,	/* Current XID */
-				tcp_reclen,	/* fragment length */
+	__be32			tcp_recm,	/* Fragment header */
+				tcp_xid;	/* Current XID */
+	u32			tcp_reclen,	/* fragment length */
 				tcp_offset;	/* fragment offset */
 	unsigned long		tcp_copied,	/* copied to request */
 				tcp_flags;
@@ -222,7 +222,7 @@
 void			xprt_release(struct rpc_task *task);
 int			xprt_destroy(struct rpc_xprt *xprt);
 
-static inline u32 *xprt_skip_transport_header(struct rpc_xprt *xprt, u32 *p)
+static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 *p)
 {
 	return p + xprt->tsh_size;
 }
@@ -237,7 +237,7 @@
 void			xprt_write_space(struct rpc_xprt *xprt);
 void			xprt_update_rtt(struct rpc_task *task);
 void			xprt_adjust_cwnd(struct rpc_task *task, int result);
-struct rpc_rqst *	xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid);
+struct rpc_rqst *	xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid);
 void			xprt_complete_rqst(struct rpc_task *task, int copied);
 void			xprt_release_rqst_cong(struct rpc_task *task);
 void			xprt_disconnect(struct rpc_xprt *xprt);
diff -urN oldtree/include/linux/sysctl.h newtree/include/linux/sysctl.h
--- oldtree/include/linux/sysctl.h	2006-02-19 11:41:05.965436216 +0000
+++ newtree/include/linux/sysctl.h	2006-02-21 15:58:16.247676536 +0000
@@ -146,6 +146,7 @@
 	KERN_RANDOMIZE=68, /* int: randomize virtual address space */
 	KERN_SETUID_DUMPABLE=69, /* int: behaviour of dumps for setuid core */
 	KERN_SPIN_RETRY=70,	/* int: number of spinlock retries */
+	KERN_ACPI_VIDEO_FLAGS=71, /* int: flags for setting up video after ACPI sleep */
 };
 
 
@@ -259,6 +260,8 @@
 	NET_CORE_DEV_WEIGHT=17,
 	NET_CORE_SOMAXCONN=18,
 	NET_CORE_BUDGET=19,
+	NET_CORE_AEVENT_ETIME=20,
+	NET_CORE_AEVENT_RSEQTH=21,
 };
 
 /* /proc/sys/net/ethernet */
@@ -395,6 +398,8 @@
 	NET_TCP_CONG_CONTROL=110,
 	NET_TCP_ABC=111,
 	NET_IPV4_IPFRAG_MAX_DIST=112,
+ 	NET_TCP_MTU_PROBING=113,
+	NET_TCP_BASE_MSS=114,
 };
 
 enum {
@@ -529,6 +534,11 @@
 	NET_IPV6_MAX_DESYNC_FACTOR=15,
 	NET_IPV6_MAX_ADDRESSES=16,
 	NET_IPV6_FORCE_MLD_VERSION=17,
+	NET_IPV6_ACCEPT_RA_DEFRTR=18,
+	NET_IPV6_ACCEPT_RA_PINFO=19,
+	NET_IPV6_ACCEPT_RA_RTR_PREF=20,
+	NET_IPV6_RTR_PROBE_INTERVAL=21,
+	NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN=22,
 	__NET_IPV6_MAX
 };
 
diff -urN oldtree/include/linux/sysfs.h newtree/include/linux/sysfs.h
--- oldtree/include/linux/sysfs.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/sysfs.h	2006-02-21 15:58:12.802200328 +0000
@@ -74,6 +74,7 @@
 	umode_t			s_mode;
 	struct dentry		* s_dentry;
 	struct iattr		* s_iattr;
+	atomic_t		s_event;
 };
 
 #define SYSFS_ROOT		0x0001
@@ -118,6 +119,9 @@
 int sysfs_create_group(struct kobject *, const struct attribute_group *);
 void sysfs_remove_group(struct kobject *, const struct attribute_group *);
 
+void sysfs_notify(struct kobject * k, char *dir, char *attr);
+void sysfs_printk_last_file(void);
+
 #else /* CONFIG_SYSFS */
 
 static inline int sysfs_create_dir(struct kobject * k)
@@ -185,6 +189,16 @@
 	;
 }
 
+static inline void sysfs_notify(struct kobject * k, char *dir, char *attr)
+{
+	;
+}
+
+static inline void sysfs_printk_last_file(void)
+{
+	;
+}
+
 #endif /* CONFIG_SYSFS */
 
 #endif /* _SYSFS_H_ */
diff -urN oldtree/include/linux/tcp.h newtree/include/linux/tcp.h
--- oldtree/include/linux/tcp.h	2006-02-19 11:41:05.966436064 +0000
+++ newtree/include/linux/tcp.h	2006-02-21 15:58:36.891538192 +0000
@@ -21,10 +21,10 @@
 #include <asm/byteorder.h>
 
 struct tcphdr {
-	__u16	source;
-	__u16	dest;
-	__u32	seq;
-	__u32	ack_seq;
+	__be16	source;
+	__be16	dest;
+	__be32	seq;
+	__be32	ack_seq;
 #if defined(__LITTLE_ENDIAN_BITFIELD)
 	__u16	res1:4,
 		doff:4,
@@ -50,9 +50,9 @@
 #else
 #error	"Adjust your <asm/byteorder.h> defines"
 #endif	
-	__u16	window;
-	__u16	check;
-	__u16	urg_ptr;
+	__be16	window;
+	__be16	check;
+	__be16	urg_ptr;
 };
 
 /*
@@ -62,7 +62,7 @@
  */
 union tcp_word_hdr { 
 	struct tcphdr hdr;
-	__u32 		  words[5];
+	__be32 		  words[5];
 }; 
 
 #define tcp_flag_word(tp) ( ((union tcp_word_hdr *)(tp))->words [3]) 
@@ -166,6 +166,11 @@
 #include <net/inet_timewait_sock.h>
 
 /* This defines a selective acknowledgement block. */
+struct tcp_sack_block_wire {
+	__be32	start_seq;
+	__be32	end_seq;
+};
+
 struct tcp_sack_block {
 	__u32	start_seq;
 	__u32	end_seq;
@@ -211,7 +216,7 @@
  *	Header prediction flags
  *	0x5?10 << 16 + snd_wnd in net byte order
  */
-	__u32	pred_flags;
+	__be32	pred_flags;
 
 /*
  *	RFC793 variables by their proper names. This means you can
diff -urN oldtree/include/linux/tipc_config.h newtree/include/linux/tipc_config.h
--- oldtree/include/linux/tipc_config.h	2006-02-19 11:41:05.969435608 +0000
+++ newtree/include/linux/tipc_config.h	2006-02-21 15:58:36.893537888 +0000
@@ -194,34 +194,34 @@
 
 
 struct tipc_node_info {
-	__u32 addr;			/* network address of node */
-	__u32 up;			/* 0=down, 1= up */
+	__be32 addr;			/* network address of node */
+	__be32 up;			/* 0=down, 1= up */
 };
 
 struct tipc_link_info {
-	__u32 dest;			/* network address of peer node */
-	__u32 up;			/* 0=down, 1=up */
+	__be32 dest;			/* network address of peer node */
+	__be32 up;			/* 0=down, 1=up */
 	char str[TIPC_MAX_LINK_NAME];	/* link name */
 };
 
 struct tipc_bearer_config {
-	__u32 priority;			/* Range [1,31]. Override per link  */
-	__u32 detect_scope;     
+	__be32 priority;		/* Range [1,31]. Override per link  */
+	__be32 detect_scope;     
 	char name[TIPC_MAX_BEARER_NAME];
 };
 
 struct tipc_link_config {
-	__u32 value;
+	__be32 value;
 	char name[TIPC_MAX_LINK_NAME];
 };
 
 #define TIPC_NTQ_ALLTYPES 0x80000000
 
 struct tipc_name_table_query {
-	__u32 depth;	/* 1:type, 2:+name info, 3:+port info, 4+:+debug info */
-	__u32 type;	/* {t,l,u} info ignored if high bit of "depth" is set */
-	__u32 lowbound; /* (i.e. displays all entries of name table) */
-	__u32 upbound;
+	__be32 depth;	/* 1:type, 2:+name info, 3:+port info, 4+:+debug info */
+	__be32 type;	/* {t,l,u} info ignored if high bit of "depth" is set */
+	__be32 lowbound; /* (i.e. displays all entries of name table) */
+	__be32 upbound;
 };
 
 /*
@@ -262,8 +262,8 @@
  */
 
 struct tlv_desc {
-	__u16 tlv_len;		/* TLV length (descriptor + value) */
-	__u16 tlv_type;		/* TLV identifier */
+	__be16 tlv_len;		/* TLV length (descriptor + value) */
+	__be16 tlv_type;		/* TLV identifier */
 };
 
 #define TLV_ALIGNTO 4
@@ -377,9 +377,9 @@
 
 struct tipc_cfg_msg_hdr
 {
-	__u32 tcm_len;		/* Message length (including header) */
-	__u16 tcm_type;		/* Command type */
-	__u16 tcm_flags;	/* Additional flags */
+	__be32 tcm_len;		/* Message length (including header) */
+	__be16 tcm_type;	/* Command type */
+	__be16 tcm_flags;	/* Additional flags */
 	char  tcm_reserved[8];	/* Unused */
 };
 
diff -urN oldtree/include/linux/trdevice.h newtree/include/linux/trdevice.h
--- oldtree/include/linux/trdevice.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/linux/trdevice.h	2006-02-21 15:58:36.893537888 +0000
@@ -28,7 +28,7 @@
 #include <linux/if_tr.h>
 
 #ifdef __KERNEL__
-extern unsigned short	tr_type_trans(struct sk_buff *skb, struct net_device *dev);
+extern __be16 tr_type_trans(struct sk_buff *skb, struct net_device *dev);
 extern void tr_source_route(struct sk_buff *skb, struct trh_hdr *trh, struct net_device *dev);
 extern struct net_device *alloc_trdev(int sizeof_priv);
 
diff -urN oldtree/include/linux/tty.h newtree/include/linux/tty.h
--- oldtree/include/linux/tty.h	2006-02-19 11:41:05.970435456 +0000
+++ newtree/include/linux/tty.h	2006-02-21 15:58:25.630250168 +0000
@@ -24,6 +24,7 @@
 #include <linux/tty_driver.h>
 #include <linux/tty_ldisc.h>
 #include <linux/screen_info.h>
+#include <linux/mutex.h>
 
 #include <asm/system.h>
 
@@ -231,8 +232,8 @@
 	int canon_data;
 	unsigned long canon_head;
 	unsigned int canon_column;
-	struct semaphore atomic_read;
-	struct semaphore atomic_write;
+	struct mutex atomic_read_lock;
+	struct mutex atomic_write_lock;
 	unsigned char *write_buf;
 	int write_cnt;
 	spinlock_t read_lock;
@@ -319,8 +320,7 @@
 extern void tty_wakeup(struct tty_struct *tty);
 extern void tty_ldisc_flush(struct tty_struct *tty);
 
-struct semaphore;
-extern struct semaphore tty_sem;
+extern struct mutex tty_mutex;
 
 /* n_tty.c */
 extern struct tty_ldisc tty_ldisc_N_TTY;
diff -urN oldtree/include/linux/udf_fs_sb.h newtree/include/linux/udf_fs_sb.h
--- oldtree/include/linux/udf_fs_sb.h	2006-02-19 11:41:05.972435152 +0000
+++ newtree/include/linux/udf_fs_sb.h	2006-02-21 15:58:28.308842960 +0000
@@ -13,7 +13,7 @@
 #ifndef _UDF_FS_SB_H
 #define _UDF_FS_SB_H 1
 
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #pragma pack(1)
 
@@ -111,7 +111,7 @@
 	/* VAT inode */
 	struct inode		*s_vat;
 
-	struct semaphore	s_alloc_sem;
+	struct mutex		s_alloc_mutex;
 };
 
 #endif /* _UDF_FS_SB_H */
diff -urN oldtree/include/linux/udp.h newtree/include/linux/udp.h
--- oldtree/include/linux/udp.h	2006-02-19 11:41:05.973435000 +0000
+++ newtree/include/linux/udp.h	2006-02-21 15:58:36.893537888 +0000
@@ -20,10 +20,10 @@
 #include <linux/types.h>
 
 struct udphdr {
-	__u16	source;
-	__u16	dest;
-	__u16	len;
-	__u16	check;
+	__be16	source;
+	__be16	dest;
+	__be16	len;
+	__be16	check;
 };
 
 /* UDP socket options */
diff -urN oldtree/include/linux/videodev2.h newtree/include/linux/videodev2.h
--- oldtree/include/linux/videodev2.h	2006-02-19 11:41:05.977434392 +0000
+++ newtree/include/linux/videodev2.h	2006-02-21 15:58:13.665069152 +0000
@@ -17,6 +17,7 @@
 #include <linux/time.h> /* need struct timeval */
 #include <linux/poll.h>
 #include <linux/device.h>
+#include <linux/mutex.h>
 #endif
 #include <linux/compiler.h> /* need __user */
 
@@ -80,7 +81,7 @@
 
 	/* for videodev.c intenal usage -- please don't touch */
 	int users;                     /* video_exclusive_{open|close} ... */
-	struct semaphore lock;         /* ... helper function uses these   */
+	struct mutex lock;             /* ... helper function uses these   */
 	char devfs_name[64];           /* devfs */
 	struct class_device class_dev; /* sysfs */
 };
diff -urN oldtree/include/linux/writeback.h newtree/include/linux/writeback.h
--- oldtree/include/linux/writeback.h	2006-02-19 11:41:05.978434240 +0000
+++ newtree/include/linux/writeback.h	2006-02-21 15:58:29.883603560 +0000
@@ -99,7 +99,15 @@
 				      void __user *, size_t *, loff_t *);
 
 void page_writeback_init(void);
-void balance_dirty_pages_ratelimited(struct address_space *mapping);
+void balance_dirty_pages_ratelimited_nr(struct address_space *mapping,
+					unsigned long nr_pages_dirtied);
+
+static inline void
+balance_dirty_pages_ratelimited(struct address_space *mapping)
+{
+	balance_dirty_pages_ratelimited_nr(mapping, 1);
+}
+
 int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0);
 int do_writepages(struct address_space *mapping, struct writeback_control *wbc);
 int sync_page_range(struct inode *inode, struct address_space *mapping,
diff -urN oldtree/include/linux/xfrm.h newtree/include/linux/xfrm.h
--- oldtree/include/linux/xfrm.h	2006-02-19 11:41:05.979434088 +0000
+++ newtree/include/linux/xfrm.h	2006-02-21 15:58:36.894537736 +0000
@@ -12,8 +12,8 @@
  */
 typedef union
 {
-	__u32		a4;
-	__u32		a6[4];
+	__be32		a4;
+	__be32		a6[4];
 } xfrm_address_t;
 
 /* Ident of a specific xfrm_state. It is used on input to lookup
@@ -23,7 +23,7 @@
 struct xfrm_id
 {
 	xfrm_address_t	daddr;
-	__u32		spi;
+	__be32		spi;
 	__u8		proto;
 };
 
@@ -49,10 +49,10 @@
 {
 	xfrm_address_t	daddr;
 	xfrm_address_t	saddr;
-	__u16	dport;
-	__u16	dport_mask;
-	__u16	sport;
-	__u16	sport_mask;
+	__be16	dport;
+	__be16	dport_mask;
+	__be16	sport;
+	__be16	sport_mask;
 	__u16	family;
 	__u8	prefixlen_d;
 	__u8	prefixlen_s;
@@ -156,6 +156,10 @@
 	XFRM_MSG_FLUSHPOLICY,
 #define XFRM_MSG_FLUSHPOLICY XFRM_MSG_FLUSHPOLICY
 
+	XFRM_MSG_NEWAE,
+#define XFRM_MSG_NEWAE XFRM_MSG_NEWAE
+	XFRM_MSG_GETAE,
+#define XFRM_MSG_GETAE XFRM_MSG_GETAE
 	__XFRM_MSG_MAX
 };
 #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1)
@@ -189,11 +193,26 @@
 
 struct xfrm_encap_tmpl {
 	__u16		encap_type;
-	__u16		encap_sport;
-	__u16		encap_dport;
+	__be16		encap_sport;
+	__be16		encap_dport;
 	xfrm_address_t	encap_oa;
 };
 
+/* AEVENT flags  */
+enum xfrm_ae_ftype_t {
+	XFRM_AE_UNSPEC,
+	XFRM_AE_RTHR=1,	/* replay threshold*/
+	XFRM_AE_RVAL=2, /* replay value */
+	XFRM_AE_LVAL=4, /* lifetime value */
+	XFRM_AE_ETHR=8, /* expiry timer threshold */
+	XFRM_AE_CR=16, /* Event cause is replay update */
+	XFRM_AE_CE=32, /* Event cause is timer expiry */
+	XFRM_AE_CU=64, /* Event cause is policy update */
+	__XFRM_AE_MAX
+
+#define XFRM_AE_MAX (__XFRM_AE_MAX - 1)
+};
+
 /* Netlink message attributes.  */
 enum xfrm_attr_type_t {
 	XFRMA_UNSPEC,
@@ -205,6 +224,10 @@
 	XFRMA_SA,
 	XFRMA_POLICY,
 	XFRMA_SEC_CTX,		/* struct xfrm_sec_ctx */
+	XFRMA_LTIME_VAL,
+	XFRMA_REPLAY_VAL,
+	XFRMA_REPLAY_THRESH,
+	XFRMA_ETIMER_THRESH,
 	__XFRMA_MAX
 
 #define XFRMA_MAX (__XFRMA_MAX - 1)
@@ -230,11 +253,16 @@
 
 struct xfrm_usersa_id {
 	xfrm_address_t			daddr;
-	__u32				spi;
+	__be32				spi;
 	__u16				family;
 	__u8				proto;
 };
 
+struct xfrm_aevent_id {
+	__u32				flags;
+	struct xfrm_usersa_id		sa_id;
+};
+
 struct xfrm_userspi_info {
 	struct xfrm_usersa_info		info;
 	__u32				min;
@@ -306,6 +334,8 @@
 #define XFRMNLGRP_SA		XFRMNLGRP_SA
 	XFRMNLGRP_POLICY,
 #define XFRMNLGRP_POLICY	XFRMNLGRP_POLICY
+	XFRMNLGRP_AEVENTS,
+#define XFRMNLGRP_AEVENTS	XFRMNLGRP_AEVENTS
 	__XFRMNLGRP_MAX
 };
 #define XFRMNLGRP_MAX	(__XFRMNLGRP_MAX - 1)
diff -urN oldtree/include/media/saa7146.h newtree/include/media/saa7146.h
--- oldtree/include/media/saa7146.h	2006-02-19 11:41:05.981433784 +0000
+++ newtree/include/media/saa7146.h	2006-02-21 15:58:13.670068392 +0000
@@ -11,6 +11,8 @@
 #include <linux/i2c.h>		/* for i2c subsystem */
 #include <asm/io.h>		/* for accessing devices */
 #include <linux/stringify.h>
+#include <linux/mutex.h>
+
 #include <linux/vmalloc.h>	/* for vmalloc() */
 #include <linux/mm.h>		/* for vmalloc_to_page() */
 
@@ -112,7 +114,7 @@
 
 	/* different device locks */
 	spinlock_t			slock;
-	struct semaphore		lock;
+	struct mutex			lock;
 
 	unsigned char			__iomem *mem;		/* pointer to mapped IO memory */
 	int				revision;	/* chip revision; needed for bug-workarounds*/
@@ -133,7 +135,7 @@
 	void (*vv_callback)(struct saa7146_dev *dev, unsigned long status);
 
 	/* i2c-stuff */
-	struct semaphore	i2c_lock;
+	struct mutex			i2c_lock;
 	u32			i2c_bitrate;
 	struct saa7146_dma	d_i2c;	/* pointer to i2c memory */
 	wait_queue_head_t	i2c_wq;
@@ -150,7 +152,7 @@
 
 /* from saa7146_core.c */
 extern struct list_head saa7146_devices;
-extern struct semaphore saa7146_devices_lock;
+extern struct mutex saa7146_devices_lock;
 int saa7146_register_extension(struct saa7146_extension*);
 int saa7146_unregister_extension(struct saa7146_extension*);
 struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc);
diff -urN oldtree/include/media/video-buf-dvb.h newtree/include/media/video-buf-dvb.h
--- oldtree/include/media/video-buf-dvb.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/media/video-buf-dvb.h	2006-02-21 15:58:13.671068240 +0000
@@ -11,7 +11,7 @@
 	struct videobuf_queue      dvbq;
 
 	/* video-buf-dvb state info */
-	struct semaphore           lock;
+	struct mutex               lock;
 	struct task_struct         *thread;
 	int                        nfeeds;
 
diff -urN oldtree/include/media/video-buf.h newtree/include/media/video-buf.h
--- oldtree/include/media/video-buf.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/media/video-buf.h	2006-02-21 15:58:13.672068088 +0000
@@ -18,6 +18,8 @@
  */
 
 #include <linux/videodev2.h>
+#include <linux/mutex.h>
+
 
 #define UNSET (-1U)
 
@@ -177,7 +179,7 @@
 };
 
 struct videobuf_queue {
-	struct semaphore           lock;
+	struct mutex               lock;
 	spinlock_t                 *irqlock;
 	struct pci_dev             *pci;
 
diff -urN oldtree/include/net/af_unix.h newtree/include/net/af_unix.h
--- oldtree/include/net/af_unix.h	2006-02-19 11:41:05.984433328 +0000
+++ newtree/include/net/af_unix.h	2006-02-21 15:58:16.803592024 +0000
@@ -4,6 +4,7 @@
 #include <linux/config.h>
 #include <linux/socket.h>
 #include <linux/un.h>
+#include <linux/mutex.h>
 #include <net/sock.h>
 
 extern void unix_inflight(struct file *fp);
@@ -71,7 +72,7 @@
         struct unix_address     *addr;
         struct dentry		*dentry;
         struct vfsmount		*mnt;
-        struct semaphore        readsem;
+	struct mutex		readlock;
         struct sock		*peer;
         struct sock		*other;
         struct sock		*gc_tree;
diff -urN oldtree/include/net/arp.h newtree/include/net/arp.h
--- oldtree/include/net/arp.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/net/arp.h	2006-02-21 15:58:36.908535608 +0000
@@ -14,15 +14,15 @@
 			struct packet_type *pt, struct net_device *orig_dev);
 extern int	arp_find(unsigned char *haddr, struct sk_buff *skb);
 extern int	arp_ioctl(unsigned int cmd, void __user *arg);
-extern void     arp_send(int type, int ptype, u32 dest_ip, 
-			 struct net_device *dev, u32 src_ip, 
+extern void     arp_send(int type, int ptype, __be32 dest_ip, 
+			 struct net_device *dev, __be32 src_ip, 
 			 unsigned char *dest_hw, unsigned char *src_hw, unsigned char *th);
 extern int	arp_bind_neighbour(struct dst_entry *dst);
-extern int	arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir);
+extern int	arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir);
 extern void	arp_ifdown(struct net_device *dev);
 
-extern struct sk_buff *arp_create(int type, int ptype, u32 dest_ip,
-				  struct net_device *dev, u32 src_ip,
+extern struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
+				  struct net_device *dev, __be32 src_ip,
 				  unsigned char *dest_hw, unsigned char *src_hw,
 				  unsigned char *target_hw);
 extern void arp_xmit(struct sk_buff *skb);
diff -urN oldtree/include/net/bluetooth/l2cap.h newtree/include/net/bluetooth/l2cap.h
--- oldtree/include/net/bluetooth/l2cap.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/net/bluetooth/l2cap.h	2006-02-21 15:58:36.916534392 +0000
@@ -34,7 +34,7 @@
 /* L2CAP socket address */
 struct sockaddr_l2 {
 	sa_family_t	l2_family;
-	unsigned short	l2_psm;
+	__le16		l2_psm;
 	bdaddr_t	l2_bdaddr;
 };
 
@@ -76,32 +76,32 @@
 
 /* L2CAP structures */
 struct l2cap_hdr {
-	__u16      len;
-	__u16      cid;
+	__le16      len;
+	__le16      cid;
 } __attribute__ ((packed));
 #define L2CAP_HDR_SIZE		4
 
 struct l2cap_cmd_hdr {
 	__u8       code;
 	__u8       ident;
-	__u16      len;
+	__le16     len;
 } __attribute__ ((packed));
 #define L2CAP_CMD_HDR_SIZE	4
 
 struct l2cap_cmd_rej {
-	__u16      reason;
+	__le16      reason;
 } __attribute__ ((packed));
 
 struct l2cap_conn_req {
-	__u16      psm;
-	__u16      scid;
+	__le16      psm;
+	__le16      scid;
 } __attribute__ ((packed));
 
 struct l2cap_conn_rsp {
-	__u16      dcid;
-	__u16      scid;
-	__u16      result;
-	__u16      status;
+	__le16      dcid;
+	__le16      scid;
+	__le16      result;
+	__le16      status;
 } __attribute__ ((packed));
 
 /* connect result */
@@ -117,15 +117,15 @@
 #define L2CAP_CS_AUTHOR_PEND  0x0002
 
 struct l2cap_conf_req {
-	__u16      dcid;
-	__u16      flags;
+	__le16      dcid;
+	__le16      flags;
 	__u8       data[0];
 } __attribute__ ((packed));
 
 struct l2cap_conf_rsp {
-	__u16      scid;
-	__u16      flags;
-	__u16      result;
+	__le16      scid;
+	__le16      flags;
+	__le16      result;
 	__u8       data[0];
 } __attribute__ ((packed));
 
@@ -147,23 +147,23 @@
 #define L2CAP_CONF_MAX_SIZE	22
 
 struct l2cap_disconn_req {
-	__u16      dcid;
-	__u16      scid;
+	__le16      dcid;
+	__le16      scid;
 } __attribute__ ((packed));
 
 struct l2cap_disconn_rsp {
-	__u16      dcid;
-	__u16      scid;
+	__le16      dcid;
+	__le16      scid;
 } __attribute__ ((packed));
 
 struct l2cap_info_req {
-	__u16       type;
+	__le16       type;
 	__u8        data[0];
 } __attribute__ ((packed));
 
 struct l2cap_info_rsp {
-	__u16       type;
-	__u16       result;
+	__le16       type;
+	__le16       result;
 	__u8        data[0];
 } __attribute__ ((packed));
 
@@ -205,7 +205,7 @@
 
 struct l2cap_pinfo {
 	struct bt_sock	bt;
-	__u16		psm;
+	__le16		psm;
 	__u16		dcid;
 	__u16		scid;
 
@@ -221,7 +221,7 @@
 
 	__u8		ident;
 
-	__u16		sport;
+	__le16		sport;
 
 	struct l2cap_conn	*conn;
 	struct sock		*next_c;
diff -urN oldtree/include/net/bluetooth/rfcomm.h newtree/include/net/bluetooth/rfcomm.h
--- oldtree/include/net/bluetooth/rfcomm.h	2006-02-19 11:41:05.985433176 +0000
+++ newtree/include/net/bluetooth/rfcomm.h	2006-02-21 15:58:36.916534392 +0000
@@ -124,7 +124,7 @@
 	u8  flow_ctrl;
 	u8  priority;
 	u8  ack_timer;
-	u16 mtu;
+	__le16 mtu;
 	u8  max_retrans;
 	u8  credits;
 } __attribute__ ((packed));
@@ -136,7 +136,7 @@
 	u8  flow_ctrl;
 	u8  xon_char;
 	u8  xoff_char;
-	u16 param_mask;
+	u16 param_mask;		/* XXX: it should be fixed-endian */
 } __attribute__ ((packed));
 
 struct rfcomm_rls {
diff -urN oldtree/include/net/dst.h newtree/include/net/dst.h
--- oldtree/include/net/dst.h	2006-02-19 11:41:05.987432872 +0000
+++ newtree/include/net/dst.h	2006-02-21 15:58:36.917534240 +0000
@@ -84,7 +84,7 @@
 struct dst_ops
 {
 	unsigned short		family;
-	unsigned short		protocol;
+	__be16			protocol;
 	unsigned		gc_thresh;
 
 	int			(*gc)(void);
diff -urN oldtree/include/net/flow.h newtree/include/net/flow.h
--- oldtree/include/net/flow.h	2006-02-19 11:41:05.987432872 +0000
+++ newtree/include/net/flow.h	2006-02-21 15:58:36.917534240 +0000
@@ -16,8 +16,8 @@
 
 	union {
 		struct {
-			__u32			daddr;
-			__u32			saddr;
+			__be32			daddr;
+			__be32			saddr;
 			__u32			fwmark;
 			__u8			tos;
 			__u8			scope;
@@ -26,7 +26,7 @@
 		struct {
 			struct in6_addr		daddr;
 			struct in6_addr		saddr;
-			__u32			flowlabel;
+			__be32			flowlabel;
 		} ip6_u;
 
 		struct {
@@ -54,8 +54,8 @@
 #define FLOWI_FLAG_MULTIPATHOLDROUTE 0x01
 	union {
 		struct {
-			__u16	sport;
-			__u16	dport;
+			__be16	sport;
+			__be16	dport;
 		} ports;
 
 		struct {
@@ -71,7 +71,7 @@
 			__u8	objname[16]; /* Not zero terminated */
 		} dnports;
 
-		__u32		spi;
+		__be32		spi;
 	} uli_u;
 #define fl_ip_sport	uli_u.ports.sport
 #define fl_ip_dport	uli_u.ports.dport
diff -urN oldtree/include/net/icmp.h newtree/include/net/icmp.h
--- oldtree/include/net/icmp.h	2006-02-19 11:41:05.988432720 +0000
+++ newtree/include/net/icmp.h	2006-02-21 15:58:36.918534088 +0000
@@ -39,7 +39,7 @@
 struct net_proto_family;
 struct sk_buff;
 
-extern void	icmp_send(struct sk_buff *skb_in,  int type, int code, u32 info);
+extern void	icmp_send(struct sk_buff *skb_in,  int type, int code, __be32 info);
 extern int	icmp_rcv(struct sk_buff *skb);
 extern int	icmp_ioctl(struct sock *sk, int cmd, unsigned long arg);
 extern void	icmp_init(struct net_proto_family *ops);
diff -urN oldtree/include/net/ieee80211.h newtree/include/net/ieee80211.h
--- oldtree/include/net/ieee80211.h	2006-02-19 11:41:05.989432568 +0000
+++ newtree/include/net/ieee80211.h	2006-02-21 15:58:15.712757856 +0000
@@ -220,6 +220,7 @@
 /* Authentication algorithms */
 #define WLAN_AUTH_OPEN 0
 #define WLAN_AUTH_SHARED_KEY 1
+#define WLAN_AUTH_LEAP 2
 
 #define WLAN_AUTH_CHALLENGE_LEN 128
 
@@ -299,6 +300,23 @@
 	WLAN_REASON_CIPHER_SUITE_REJECTED = 24,
 };
 
+/* Action categories - 802.11h */
+enum ieee80211_actioncategories {
+	WLAN_ACTION_SPECTRUM_MGMT = 0,
+	/* Reserved 1-127  */
+	/* Error    128-255 */
+};
+
+/* Action details - 802.11h */
+enum ieee80211_actiondetails {
+	WLAN_ACTION_CATEGORY_MEASURE_REQUEST = 0,
+	WLAN_ACTION_CATEGORY_MEASURE_REPORT = 1,
+	WLAN_ACTION_CATEGORY_TPC_REQUEST = 2,
+	WLAN_ACTION_CATEGORY_TPC_REPORT = 3,
+	WLAN_ACTION_CATEGORY_CHANNEL_SWITCH = 4,
+	/* 5 - 255 Reserved */
+};
+
 #define IEEE80211_STATMASK_SIGNAL (1<<0)
 #define IEEE80211_STATMASK_RSSI (1<<1)
 #define IEEE80211_STATMASK_NOISE (1<<2)
@@ -377,6 +395,8 @@
 	u8 mask;
 	u8 freq;
 	u16 len;
+	u64 tsf;
+	u32 beacon_time;
 };
 
 /* IEEE 802.11 requires that STA supports concurrent reception of at least
@@ -608,6 +628,28 @@
 	struct ieee80211_info_element info_element[0];
 } __attribute__ ((packed));
 
+struct ieee80211_channel_switch {
+	u8 id;
+	u8 len;
+	u8 mode;
+	u8 channel;
+	u8 count;
+} __attribute__ ((packed));
+
+struct ieee80211_action {
+	struct ieee80211_hdr_3addr header;
+	u8 category;
+	u8 action;
+	union {
+		struct ieee80211_action_exchange {
+			u8 token;
+			struct ieee80211_info_element info_element[0];
+		} exchange;
+		struct ieee80211_channel_switch channel_switch;
+
+	} format;
+} __attribute__ ((packed));
+
 struct ieee80211_disassoc {
 	struct ieee80211_hdr_3addr header;
 	__le16 reason;
@@ -692,7 +734,15 @@
 /* QoS structure */
 #define NETWORK_HAS_QOS_PARAMETERS      (1<<3)
 #define NETWORK_HAS_QOS_INFORMATION     (1<<4)
-#define NETWORK_HAS_QOS_MASK            (NETWORK_HAS_QOS_PARAMETERS | NETWORK_HAS_QOS_INFORMATION)
+#define NETWORK_HAS_QOS_MASK            (NETWORK_HAS_QOS_PARAMETERS | \
+					 NETWORK_HAS_QOS_INFORMATION)
+
+/* 802.11h */
+#define NETWORK_HAS_POWER_CONSTRAINT    (1<<5)
+#define NETWORK_HAS_CSA                 (1<<6)
+#define NETWORK_HAS_QUIET               (1<<7)
+#define NETWORK_HAS_IBSS_DFS            (1<<8)
+#define NETWORK_HAS_TPC_REPORT          (1<<9)
 
 #define QOS_QUEUE_NUM                   4
 #define QOS_OUI_LEN                     3
@@ -748,6 +798,91 @@
 
 /*******************************************************/
 
+enum {				/* ieee80211_basic_report.map */
+	IEEE80211_BASIC_MAP_BSS = (1 << 0),
+	IEEE80211_BASIC_MAP_OFDM = (1 << 1),
+	IEEE80211_BASIC_MAP_UNIDENTIFIED = (1 << 2),
+	IEEE80211_BASIC_MAP_RADAR = (1 << 3),
+	IEEE80211_BASIC_MAP_UNMEASURED = (1 << 4),
+	/* Bits 5-7 are reserved */
+
+};
+struct ieee80211_basic_report {
+	u8 channel;
+	__le64 start_time;
+	__le16 duration;
+	u8 map;
+} __attribute__ ((packed));
+
+enum {				/* ieee80211_measurement_request.mode */
+	/* Bit 0 is reserved */
+	IEEE80211_MEASUREMENT_ENABLE = (1 << 1),
+	IEEE80211_MEASUREMENT_REQUEST = (1 << 2),
+	IEEE80211_MEASUREMENT_REPORT = (1 << 3),
+	/* Bits 4-7 are reserved */
+};
+
+enum {
+	IEEE80211_REPORT_BASIC = 0,	/* required */
+	IEEE80211_REPORT_CCA = 1,	/* optional */
+	IEEE80211_REPORT_RPI = 2,	/* optional */
+	/* 3-255 reserved */
+};
+
+struct ieee80211_measurement_params {
+	u8 channel;
+	__le64 start_time;
+	__le16 duration;
+} __attribute__ ((packed));
+
+struct ieee80211_measurement_request {
+	struct ieee80211_info_element ie;
+	u8 token;
+	u8 mode;
+	u8 type;
+	struct ieee80211_measurement_params params[0];
+} __attribute__ ((packed));
+
+struct ieee80211_measurement_report {
+	struct ieee80211_info_element ie;
+	u8 token;
+	u8 mode;
+	u8 type;
+	union {
+		struct ieee80211_basic_report basic[0];
+	} u;
+} __attribute__ ((packed));
+
+struct ieee80211_tpc_report {
+	u8 transmit_power;
+	u8 link_margin;
+} __attribute__ ((packed));
+
+struct ieee80211_channel_map {
+	u8 channel;
+	u8 map;
+} __attribute__ ((packed));
+
+struct ieee80211_ibss_dfs {
+	struct ieee80211_info_element ie;
+	u8 owner[ETH_ALEN];
+	u8 recovery_interval;
+	struct ieee80211_channel_map channel_map[0];
+};
+
+struct ieee80211_csa {
+	u8 mode;
+	u8 channel;
+	u8 count;
+} __attribute__ ((packed));
+
+struct ieee80211_quiet {
+	u8 count;
+	u8 period;
+	u8 duration;
+	u8 offset;
+} __attribute__ ((packed));
+
 struct ieee80211_network {
 	/* These entries are used to identify a unique network */
 	u8 bssid[ETH_ALEN];
@@ -767,7 +902,7 @@
 	u8 rates_ex_len;
 	unsigned long last_scanned;
 	u8 mode;
-	u8 flags;
+	u32 flags;
 	u32 last_associate;
 	u32 time_stamp[2];
 	u16 beacon_interval;
@@ -779,6 +914,25 @@
 	u8 rsn_ie[MAX_WPA_IE_LEN];
 	size_t rsn_ie_len;
 	struct ieee80211_tim_parameters tim;
+
+	/* 802.11h info */
+
+	/* Power Constraint - mandatory if spctrm mgmt required */
+	u8 power_constraint;
+
+	/* TPC Report - mandatory if spctrm mgmt required */
+	struct ieee80211_tpc_report tpc_report;
+
+	/* IBSS DFS - mandatory if spctrm mgmt required and IBSS
+	 * NOTE: This is variable length and so must be allocated dynamically */
+	struct ieee80211_ibss_dfs *ibss_dfs;
+
+	/* Channel Switch Announcement - optional if spctrm mgmt required */
+	struct ieee80211_csa csa;
+
+	/* Quiet - optional if spctrm mgmt required */
+	struct ieee80211_quiet quiet;
+
 	struct list_head list;
 };
 
@@ -924,7 +1078,10 @@
 	int (*handle_auth) (struct net_device * dev,
 			    struct ieee80211_auth * auth);
 	int (*handle_deauth) (struct net_device * dev,
-			      struct ieee80211_auth * auth);
+			      struct ieee80211_deauth * auth);
+	int (*handle_action) (struct net_device * dev,
+			      struct ieee80211_action * action,
+			      struct ieee80211_rx_stats * stats);
 	int (*handle_disassoc) (struct net_device * dev,
 				struct ieee80211_disassoc * assoc);
 	int (*handle_beacon) (struct net_device * dev,
@@ -1093,6 +1250,7 @@
 extern void ieee80211_rx_mgt(struct ieee80211_device *ieee,
 			     struct ieee80211_hdr_4addr *header,
 			     struct ieee80211_rx_stats *stats);
+extern void ieee80211_network_reset(struct ieee80211_network *network);
 
 /* ieee80211_geo.c */
 extern const struct ieee80211_geo *ieee80211_get_geo(struct ieee80211_device
@@ -1105,6 +1263,11 @@
 extern int ieee80211_channel_to_index(struct ieee80211_device *ieee,
 				      u8 channel);
 extern u8 ieee80211_freq_to_channel(struct ieee80211_device *ieee, u32 freq);
+extern u8 ieee80211_get_channel_flags(struct ieee80211_device *ieee,
+				      u8 channel);
+extern const struct ieee80211_channel *ieee80211_get_channel(struct
+							     ieee80211_device
+							     *ieee, u8 channel);
 
 /* ieee80211_wx.c */
 extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
@@ -1122,6 +1285,14 @@
 extern int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
 				      struct iw_request_info *info,
 				      union iwreq_data *wrqu, char *extra);
+extern int ieee80211_wx_set_auth(struct net_device *dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu,
+				 char *extra);
+extern int ieee80211_wx_get_auth(struct net_device *dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu,
+				 char *extra);
 
 static inline void ieee80211_increment_scans(struct ieee80211_device *ieee)
 {
diff -urN oldtree/include/net/ieee80211_crypt.h newtree/include/net/ieee80211_crypt.h
--- oldtree/include/net/ieee80211_crypt.h	2006-02-19 11:41:05.989432568 +0000
+++ newtree/include/net/ieee80211_crypt.h	2006-02-21 15:58:15.713757704 +0000
@@ -47,7 +47,8 @@
 	/* deinitialize crypto context and free allocated private data */
 	void (*deinit) (void *priv);
 
-	int (*build_iv) (struct sk_buff * skb, int hdr_len, void *priv);
+	int (*build_iv) (struct sk_buff * skb, int hdr_len,
+			 u8 *key, int keylen, void *priv);
 
 	/* encrypt/decrypt return < 0 on error or >= 0 on success. The return
 	 * value from decrypt_mpdu is passed as the keyidx value for
diff -urN oldtree/include/net/if_inet6.h newtree/include/net/if_inet6.h
--- oldtree/include/net/if_inet6.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/net/if_inet6.h	2006-02-21 15:58:16.261674408 +0000
@@ -180,11 +180,8 @@
 
 #ifdef CONFIG_IPV6_PRIVACY
 	u8			rndid[8];
-	u8			entropy[8];
 	struct timer_list	regen_timer;
 	struct inet6_ifaddr	*tempaddr_list;
-	__u8			work_eui64[8];
-	__u8			work_digest[16];
 #endif
 
 	struct neigh_parms	*nd_parms;
diff -urN oldtree/include/net/inet6_hashtables.h newtree/include/net/inet6_hashtables.h
--- oldtree/include/net/inet6_hashtables.h	2006-02-19 11:41:05.990432416 +0000
+++ newtree/include/net/inet6_hashtables.h	2006-02-21 15:58:36.927532720 +0000
@@ -27,11 +27,11 @@
 
 /* I have no idea if this is a good hash for v6 or not. -DaveM */
 static inline unsigned int inet6_ehashfn(const struct in6_addr *laddr, const u16 lport,
-				const struct in6_addr *faddr, const u16 fport)
+				const struct in6_addr *faddr, const __be16 fport)
 {
-	unsigned int hashent = (lport ^ fport);
+	unsigned int hashent = (lport ^ (__force u16)fport);
 
-	hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]);
+	hashent ^= (__force u32)(laddr->s6_addr32[3] ^ faddr->s6_addr32[3]);
 	hashent ^= hashent >> 16;
 	hashent ^= hashent >> 8;
 	return hashent;
@@ -44,7 +44,7 @@
 	const struct in6_addr *laddr = &np->rcv_saddr;
 	const struct in6_addr *faddr = &np->daddr;
 	const __u16 lport = inet->num;
-	const __u16 fport = inet->dport;
+	const __be16 fport = inet->dport;
 	return inet6_ehashfn(laddr, lport, faddr, fport);
 }
 
@@ -83,7 +83,7 @@
 static inline struct sock *
 		__inet6_lookup_established(struct inet_hashinfo *hashinfo,
 					   const struct in6_addr *saddr,
-					   const u16 sport,
+					   const __be16 sport,
 					   const struct in6_addr *daddr,
 					   const u16 hnum,
 					   const int dif)
@@ -134,7 +134,7 @@
 
 static inline struct sock *__inet6_lookup(struct inet_hashinfo *hashinfo,
 					  const struct in6_addr *saddr,
-					  const u16 sport,
+					  const __be16 sport,
 					  const struct in6_addr *daddr,
 					  const u16 hnum,
 					  const int dif)
@@ -148,8 +148,8 @@
 }
 
 extern struct sock *inet6_lookup(struct inet_hashinfo *hashinfo,
-				 const struct in6_addr *saddr, const u16 sport,
-				 const struct in6_addr *daddr, const u16 dport,
+				 const struct in6_addr *saddr, const __be16 sport,
+				 const struct in6_addr *daddr, const __be16 dport,
 				 const int dif);
 #endif /* defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) */
 #endif /* _INET6_HASHTABLES_H */
diff -urN oldtree/include/net/inet_connection_sock.h newtree/include/net/inet_connection_sock.h
--- oldtree/include/net/inet_connection_sock.h	2006-02-19 11:41:05.991432264 +0000
+++ newtree/include/net/inet_connection_sock.h	2006-02-21 15:58:36.927532720 +0000
@@ -72,6 +72,7 @@
  * @icsk_probes_out:	   unanswered 0 window probes
  * @icsk_ext_hdr_len:	   Network protocol overhead (IP/IPv6 options)
  * @icsk_ack:		   Delayed ACK control data
+ * @icsk_mtup;		   MTU probing control data
  */
 struct inet_connection_sock {
 	/* inet_sock has to be the first member! */
@@ -104,6 +105,18 @@
 		__u16		  last_seg_size; /* Size of last incoming segment	   */
 		__u16		  rcv_mss;	 /* MSS used for delayed ACK decisions	   */ 
 	} icsk_ack;
+	struct {
+		int		  enabled;
+		
+		/* Range of MTUs to search */
+		int		  search_high;
+		int		  search_low;
+		
+		/* Information on the current probe. */
+		int		  probe_size;
+		__u32		  probe_seq_start;
+		__u32		  probe_seq_end;
+	} icsk_mtup;
 	u32			  icsk_ca_priv[16];
 #define ICSK_CA_PRIV_SIZE	(16 * sizeof(u32))
 };
@@ -220,9 +233,9 @@
 
 extern struct request_sock *inet_csk_search_req(const struct sock *sk,
 						struct request_sock ***prevp,
-						const __u16 rport,
-						const __u32 raddr,
-						const __u32 laddr);
+						const __be16 rport,
+						const __be32 raddr,
+						const __be32 laddr);
 extern int inet_csk_bind_conflict(const struct sock *sk,
 				  const struct inet_bind_bucket *tb);
 extern int inet_csk_get_port(struct inet_hashinfo *hashinfo,
diff -urN oldtree/include/net/inet_hashtables.h newtree/include/net/inet_hashtables.h
--- oldtree/include/net/inet_hashtables.h	2006-02-19 11:41:05.992432112 +0000
+++ newtree/include/net/inet_hashtables.h	2006-02-21 15:58:36.928532568 +0000
@@ -273,14 +273,14 @@
 }
 
 extern struct sock *__inet_lookup_listener(const struct hlist_head *head,
-					   const u32 daddr,
+					   const __be32 daddr,
 					   const unsigned short hnum,
 					   const int dif);
 
 /* Optimize the common listener case. */
 static inline struct sock *
 		inet_lookup_listener(struct inet_hashinfo *hashinfo,
-				     const u32 daddr,
+				     const __be32 daddr,
 				     const unsigned short hnum, const int dif)
 {
 	struct sock *sk = NULL;
@@ -309,19 +309,19 @@
 /* Socket demux engine toys. */
 #ifdef __BIG_ENDIAN
 #define INET_COMBINED_PORTS(__sport, __dport) \
-	(((__u32)(__sport) << 16) | (__u32)(__dport))
+	(((__force __u32)(__be16)(__sport) << 16) | (__u32)(__dport))
 #else /* __LITTLE_ENDIAN */
 #define INET_COMBINED_PORTS(__sport, __dport) \
-	(((__u32)(__dport) << 16) | (__u32)(__sport))
+	(((__u32)(__dport) << 16) | (__force __u32)(__be16)(__sport))
 #endif
 
 #if (BITS_PER_LONG == 64)
 #ifdef __BIG_ENDIAN
 #define INET_ADDR_COOKIE(__name, __saddr, __daddr) \
-	const __u64 __name = (((__u64)(__saddr)) << 32) | ((__u64)(__daddr));
+	const __u64 __name = (((__force __u64)(__be32)(__saddr)) << 32) | ((__force __u64)(__be32)(__daddr));
 #else /* __LITTLE_ENDIAN */
 #define INET_ADDR_COOKIE(__name, __saddr, __daddr) \
-	const __u64 __name = (((__u64)(__daddr)) << 32) | ((__u64)(__saddr));
+	const __u64 __name = (((__force __u64)(__be32)(__daddr)) << 32) | ((__force __u64)(__be32)(__saddr));
 #endif /* __BIG_ENDIAN */
 #define INET_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
 	(((__sk)->sk_hash == (__hash))				&&	\
@@ -357,8 +357,8 @@
  */
 static inline struct sock *
 	__inet_lookup_established(struct inet_hashinfo *hashinfo,
-				  const u32 saddr, const u16 sport,
-				  const u32 daddr, const u16 hnum,
+				  const __be32 saddr, const __be16 sport,
+				  const __be32 daddr, const u16 hnum,
 				  const int dif)
 {
 	INET_ADDR_COOKIE(acookie, saddr, daddr)
@@ -393,8 +393,8 @@
 }
 
 static inline struct sock *__inet_lookup(struct inet_hashinfo *hashinfo,
-					 const u32 saddr, const u16 sport,
-					 const u32 daddr, const u16 hnum,
+					 const __be32 saddr, const __be16 sport,
+					 const __be32 daddr, const u16 hnum,
 					 const int dif)
 {
 	struct sock *sk = __inet_lookup_established(hashinfo, saddr, sport, daddr,
@@ -403,8 +403,8 @@
 }
 
 static inline struct sock *inet_lookup(struct inet_hashinfo *hashinfo,
-				       const u32 saddr, const u16 sport,
-				       const u32 daddr, const u16 dport,
+				       const __be32 saddr, const __be16 sport,
+				       const __be32 daddr, const __be16 dport,
 				       const int dif)
 {
 	struct sock *sk;
diff -urN oldtree/include/net/inet_sock.h newtree/include/net/inet_sock.h
--- oldtree/include/net/inet_sock.h	2006-02-19 11:41:05.992432112 +0000
+++ newtree/include/net/inet_sock.h	2006-02-21 15:58:36.929532416 +0000
@@ -38,7 +38,7 @@
  * @ts_needaddr - Need to record addr of outgoing dev
  */
 struct ip_options {
-	__u32		faddr;
+	__be32		faddr;
 	unsigned char	optlen;
 	unsigned char	srr;
 	unsigned char	rr;
@@ -65,9 +65,9 @@
 	u16			inet6_rsk_offset;
 	/* 2 bytes hole, try to pack */
 #endif
-	u32			loc_addr;
-	u32			rmt_addr;
-	u16			rmt_port;
+	__be32			loc_addr;
+	__be32			rmt_addr;
+	__be16			rmt_port;
 	u16			snd_wscale : 4, 
 				rcv_wscale : 4, 
 				tstamp_ok  : 1,
@@ -113,15 +113,15 @@
 	struct ipv6_pinfo	*pinet6;
 #endif
 	/* Socket demultiplex comparisons on incoming packets. */
-	__u32			daddr;
-	__u32			rcv_saddr;
-	__u16			dport;
+	__be32			daddr;
+	__be32			rcv_saddr;
+	__be16			dport;
 	__u16			num;
-	__u32			saddr;
+	__be32			saddr;
 	__s16			uc_ttl;
 	__u16			cmsg_flags;
 	struct ip_options	*opt;
-	__u16			sport;
+	__be16			sport;
 	__u16			id;
 	__u8			tos;
 	__u8			mc_ttl;
@@ -132,7 +132,7 @@
 				hdrincl:1,
 				mc_loop:1;
 	int			mc_index;
-	__u32			mc_addr;
+	__be32			mc_addr;
 	struct ip_mc_socklist	*mc_list;
 	struct {
 		unsigned int		flags;
@@ -140,7 +140,7 @@
 		struct ip_options	*opt;
 		struct rtable		*rt;
 		int			length; /* Total length of all frames */
-		u32			addr;
+		__be32			addr;
 		struct flowi		fl;
 	} cork;
 };
@@ -170,10 +170,10 @@
 
 extern int inet_sk_rebuild_header(struct sock *sk);
 
-static inline unsigned int inet_ehashfn(const __u32 laddr, const __u16 lport,
-					const __u32 faddr, const __u16 fport)
+static inline unsigned int inet_ehashfn(const __be32 laddr, const __u16 lport,
+					const __be32 faddr, const __be16 fport)
 {
-	unsigned int h = (laddr ^ lport) ^ (faddr ^ fport);
+	unsigned int h = ((__force __u32)laddr ^ lport) ^ ((__force __u32)faddr ^ (__force __u32)fport);
 	h ^= h >> 16;
 	h ^= h >> 8;
 	return h;
@@ -182,10 +182,10 @@
 static inline int inet_sk_ehashfn(const struct sock *sk)
 {
 	const struct inet_sock *inet = inet_sk(sk);
-	const __u32 laddr = inet->rcv_saddr;
+	const __be32 laddr = inet->rcv_saddr;
 	const __u16 lport = inet->num;
-	const __u32 faddr = inet->daddr;
-	const __u16 fport = inet->dport;
+	const __be32 faddr = inet->daddr;
+	const __be16 fport = inet->dport;
 
 	return inet_ehashfn(laddr, lport, faddr, fport);
 }
diff -urN oldtree/include/net/inet_timewait_sock.h newtree/include/net/inet_timewait_sock.h
--- oldtree/include/net/inet_timewait_sock.h	2006-02-19 11:41:05.993431960 +0000
+++ newtree/include/net/inet_timewait_sock.h	2006-02-21 15:58:36.929532416 +0000
@@ -121,10 +121,10 @@
 	unsigned char		tw_rcv_wscale;
 	/* Socket demultiplex comparisons on incoming packets. */
 	/* these five are in inet_sock */
-	__u16			tw_sport;
-	__u32			tw_daddr __attribute__((aligned(INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES)));
-	__u32			tw_rcv_saddr;
-	__u16			tw_dport;
+	__be16			tw_sport;
+	__be32			tw_daddr __attribute__((aligned(INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES)));
+	__be32			tw_rcv_saddr;
+	__be16			tw_dport;
 	__u16			tw_num;
 	/* And these are ours. */
 	__u8			tw_ipv6only:1;
@@ -187,7 +187,7 @@
 	return (struct inet_timewait_sock *)sk;
 }
 
-static inline u32 inet_rcv_saddr(const struct sock *sk)
+static inline __be32 inet_rcv_saddr(const struct sock *sk)
 {
 	return likely(sk->sk_state != TCP_TIME_WAIT) ?
 		inet_sk(sk)->rcv_saddr : inet_twsk(sk)->tw_rcv_saddr;
diff -urN oldtree/include/net/inetpeer.h newtree/include/net/inetpeer.h
--- oldtree/include/net/inetpeer.h	2006-02-19 11:41:05.994431808 +0000
+++ newtree/include/net/inetpeer.h	2006-02-21 15:58:36.928532568 +0000
@@ -22,7 +22,7 @@
 	unsigned long		dtime;		/* the time of last use of not
 						 * referenced entries */
 	atomic_t		refcnt;
-	__u32			v4daddr;	/* peer's address */
+	__be32			v4daddr;	/* peer's address */
 	__u16			avl_height;
 	__u16			ip_id_count;	/* IP ID for the next packet */
 	atomic_t		rid;		/* Frag reception counter */
@@ -33,7 +33,7 @@
 void			inet_initpeers(void) __init;
 
 /* can be called with or without local BH being disabled */
-struct inet_peer	*inet_getpeer(__u32 daddr, int create);
+struct inet_peer	*inet_getpeer(__be32 daddr, int create);
 
 extern spinlock_t inet_peer_unused_lock;
 extern struct inet_peer **inet_peer_unused_tailp;
diff -urN oldtree/include/net/ip.h newtree/include/net/ip.h
--- oldtree/include/net/ip.h	2006-02-19 11:41:05.995431656 +0000
+++ newtree/include/net/ip.h	2006-02-21 15:58:36.931532112 +0000
@@ -46,7 +46,7 @@
 
 struct ipcm_cookie
 {
-	u32			addr;
+	__be32			addr;
 	int			oif;
 	struct ip_options	*opt;
 };
@@ -87,7 +87,7 @@
  */
 
 extern int		ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
-					      u32 saddr, u32 daddr,
+					      __be32 saddr, __be32 daddr,
 					      struct ip_options *opt);
 extern int		ip_rcv(struct sk_buff *skb, struct net_device *dev,
 			       struct packet_type *pt, struct net_device *orig_dev);
@@ -123,7 +123,7 @@
  *      multicast packets.
  */
 
-static inline void ip_tr_mc_map(u32 addr, char *buf)
+static inline void ip_tr_mc_map(__be32 addr, char *buf)
 {
 	buf[0]=0xC0;
 	buf[1]=0x00;
@@ -239,9 +239,9 @@
  *	Map a multicast IP onto multicast MAC for type ethernet.
  */
 
-static inline void ip_eth_mc_map(u32 addr, char *buf)
+static inline void ip_eth_mc_map(__be32 naddr, char *buf)
 {
-	addr=ntohl(addr);
+	__u32 addr=ntohl(naddr);
 	buf[0]=0x01;
 	buf[1]=0x00;
 	buf[2]=0x5e;
@@ -257,13 +257,14 @@
  *	Leave P_Key as 0 to be filled in by driver.
  */
 
-static inline void ip_ib_mc_map(u32 addr, char *buf)
+static inline void ip_ib_mc_map(__be32 naddr, char *buf)
 {
+	__u32 addr;
 	buf[0]  = 0;		/* Reserved */
 	buf[1]  = 0xff;		/* Multicast QPN */
 	buf[2]  = 0xff;
 	buf[3]  = 0xff;
-	addr    = ntohl(addr);
+	addr    = ntohl(naddr);
 	buf[4]  = 0xff;
 	buf[5]  = 0x12;		/* link local scope */
 	buf[6]  = 0x40;		/* IPv4 signature */
@@ -336,7 +337,7 @@
  *	Functions provided by ip_options.c
  */
  
-extern void ip_options_build(struct sk_buff *skb, struct ip_options *opt, u32 daddr, struct rtable *rt, int is_frag);
+extern void ip_options_build(struct sk_buff *skb, struct ip_options *opt, __be32 daddr, struct rtable *rt, int is_frag);
 extern int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb);
 extern void ip_options_fragment(struct sk_buff *skb);
 extern int ip_options_compile(struct ip_options *opt, struct sk_buff *skb);
@@ -360,8 +361,8 @@
 
 extern int 	ip_recv_error(struct sock *sk, struct msghdr *msg, int len);
 extern void	ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err, 
-			      u16 port, u32 info, u8 *payload);
-extern void	ip_local_error(struct sock *sk, int err, u32 daddr, u16 dport,
+			      __be16 port, u32 info, u8 *payload);
+extern void	ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 dport,
 			       u32 info);
 
 /* sysctl helpers - any sysctl which holds a value that ends up being
diff -urN oldtree/include/net/ip6_route.h newtree/include/net/ip6_route.h
--- oldtree/include/net/ip6_route.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/net/ip6_route.h	2006-02-21 15:58:16.263674104 +0000
@@ -7,6 +7,23 @@
 #define IP6_RT_PRIO_KERN	512
 #define IP6_RT_FLOW_MASK	0x00ff
 
+struct route_info {
+	__u8			type;
+	__u8			length;
+	__u8			prefix_len;
+#if defined(__BIG_ENDIAN_BITFIELD)
+	__u8			reserved_h:3,
+				route_pref:2,
+				reserved_l:3;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8			reserved_l:3,
+				route_pref:2,
+				reserved_h:3;
+#endif
+	__u32			lifetime;
+	__u8			prefix[0];	/* 0,8 or 16 */
+};
+
 #ifdef __KERNEL__
 
 #include <net/flow.h>
@@ -87,11 +104,14 @@
 extern struct rt6_info *	rt6_get_dflt_router(struct in6_addr *addr,
 						    struct net_device *dev);
 extern struct rt6_info *	rt6_add_dflt_router(struct in6_addr *gwaddr,
-						    struct net_device *dev);
+						    struct net_device *dev,
+						    unsigned int pref);
 
 extern void			rt6_purge_dflt_routers(void);
 
-extern void			rt6_reset_dflt_pointer(struct rt6_info *rt);
+extern int			rt6_route_rcv(struct net_device *dev,
+					      u8 *opt, int len,
+					      struct in6_addr *gwaddr);
 
 extern void			rt6_redirect(struct in6_addr *dest,
 					     struct in6_addr *saddr,
diff -urN oldtree/include/net/ip_fib.h newtree/include/net/ip_fib.h
--- oldtree/include/net/ip_fib.h	2006-02-19 11:41:05.995431656 +0000
+++ newtree/include/net/ip_fib.h	2006-02-21 15:58:36.930532264 +0000
@@ -56,7 +56,7 @@
 	__u32			nh_tclassid;
 #endif
 	int			nh_oif;
-	u32			nh_gw;
+	__be32			nh_gw;
 };
 
 /*
@@ -71,7 +71,7 @@
 	int			fib_dead;
 	unsigned		fib_flags;
 	int			fib_protocol;
-	u32			fib_prefsrc;
+	__be32			fib_prefsrc;
 	u32			fib_priority;
 	u32			fib_metrics[RTAX_MAX];
 #define fib_mtu fib_metrics[RTAX_MTU-1]
@@ -110,7 +110,7 @@
 };
 
 struct fib_result_nl {
-	u32		fl_addr;   /* To be looked up*/ 
+	__be32		fl_addr;   /* To be looked up*/ 
 	u32		fl_fwmark; 
 	unsigned char	fl_tos;
 	unsigned char   fl_scope;
@@ -234,19 +234,19 @@
 extern int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
 extern int inet_rtm_getroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
 extern int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb);
-extern int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
-			       struct net_device *dev, u32 *spec_dst, u32 *itag);
+extern int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
+			       struct net_device *dev, __be32 *spec_dst, u32 *itag);
 extern void fib_select_multipath(const struct flowi *flp, struct fib_result *res);
 
 struct rtentry;
 
 /* Exported by fib_semantics.c */
-extern int ip_fib_check_default(u32 gw, struct net_device *dev);
-extern int fib_sync_down(u32 local, struct net_device *dev, int force);
+extern int ip_fib_check_default(__be32 gw, struct net_device *dev);
+extern int fib_sync_down(__be32 local, struct net_device *dev, int force);
 extern int fib_sync_up(struct net_device *dev);
 extern int fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm,
 			       struct kern_rta *rta, struct rtentry *r);
-extern u32  __fib_res_prefsrc(struct fib_result *res);
+extern __be32  __fib_res_prefsrc(struct fib_result *res);
 
 /* Exported by fib_hash.c */
 extern struct fib_table *fib_hash_init(int id);
diff -urN oldtree/include/net/ip_vs.h newtree/include/net/ip_vs.h
--- oldtree/include/net/ip_vs.h	2006-02-19 11:41:05.996431504 +0000
+++ newtree/include/net/ip_vs.h	2006-02-21 15:58:36.933531808 +0000
@@ -100,22 +100,22 @@
 struct ip_vs_service_user {
 	/* virtual service addresses */
 	u_int16_t		protocol;
-	u_int32_t		addr;		/* virtual ip address */
-	u_int16_t		port;
+	__be32			addr;		/* virtual ip address */
+	__be16			port;
 	u_int32_t		fwmark;		/* firwall mark of service */
 
 	/* virtual service options */
 	char			sched_name[IP_VS_SCHEDNAME_MAXLEN];
 	unsigned		flags;		/* virtual service flags */
 	unsigned		timeout;	/* persistent timeout in sec */
-	u_int32_t		netmask;	/* persistent netmask */
+	__be32			netmask;	/* persistent netmask */
 };
 
 
 struct ip_vs_dest_user {
 	/* destination server address */
-	u_int32_t		addr;
-	u_int16_t		port;
+	__be32			addr;
+	__be16			port;
 
 	/* real server options */
 	unsigned		conn_flags;	/* connection flags */
@@ -163,15 +163,15 @@
 struct ip_vs_service_entry {
 	/* which service: user fills in these */
 	u_int16_t		protocol;
-	u_int32_t		addr;		/* virtual address */
-	u_int16_t		port;
+	__be32			addr;		/* virtual address */
+	__be16			port;
 	u_int32_t		fwmark;		/* firwall mark of service */
 
 	/* service options */
 	char			sched_name[IP_VS_SCHEDNAME_MAXLEN];
 	unsigned		flags;          /* virtual service flags */
 	unsigned		timeout;	/* persistent timeout */
-	u_int32_t		netmask;	/* persistent netmask */
+	__be32			netmask;	/* persistent netmask */
 
 	/* number of real servers */
 	unsigned int		num_dests;
@@ -182,8 +182,8 @@
 
 
 struct ip_vs_dest_entry {
-	u_int32_t		addr;		/* destination address */
-	u_int16_t		port;
+	__be32			addr;		/* destination address */
+	__be16			port;
 	unsigned		conn_flags;	/* connection flags */
 	int			weight;		/* destination weight */
 
@@ -203,8 +203,8 @@
 struct ip_vs_get_dests {
 	/* which service: user fills in these */
 	u_int16_t		protocol;
-	u_int32_t		addr;		/* virtual address */
-	u_int16_t		port;
+	__be32			addr;		/* virtual address */
+	__be16			port;
 	u_int32_t		fwmark;		/* firwall mark of service */
 
 	/* number of real servers */
@@ -503,12 +503,12 @@
 	struct list_head        c_list;         /* hashed list heads */
 
 	/* Protocol, addresses and port numbers */
-	__u32                   caddr;          /* client address */
-	__u32                   vaddr;          /* virtual address */
-	__u32                   daddr;          /* destination address */
-	__u16                   cport;
-	__u16                   vport;
-	__u16                   dport;
+	__be32                   caddr;          /* client address */
+	__be32                   vaddr;          /* virtual address */
+	__be32                   daddr;          /* destination address */
+	__be16                   cport;
+	__be16                   vport;
+	__be16                   dport;
 	__u16                   protocol;       /* Which protocol (TCP/UDP) */
 
 	/* counter and timer */
@@ -555,12 +555,12 @@
 	atomic_t		usecnt;   /* use counter */
 
 	__u16			protocol; /* which protocol (TCP/UDP) */
-	__u32			addr;	  /* IP address for virtual service */
-	__u16			port;	  /* port number for the service */
+	__be32			addr;	  /* IP address for virtual service */
+	__be16			port;	  /* port number for the service */
 	__u32                   fwmark;   /* firewall mark of the service */
 	unsigned		flags;	  /* service status flags */
 	unsigned		timeout;  /* persistent timeout in ticks */
-	__u32			netmask;  /* grouping granularity */
+	__be32			netmask;  /* grouping granularity */
 
 	struct list_head	destinations;  /* real server d-linked list */
 	__u32			num_dests;     /* number of servers */
@@ -582,8 +582,8 @@
 	struct list_head	n_list;   /* for the dests in the service */
 	struct list_head	d_list;   /* for table with all the dests */
 
-	__u32			addr;		/* IP address of the server */
-	__u16			port;		/* port number of the server */
+	__be32			addr;		/* IP address of the server */
+	__be16			port;		/* port number of the server */
 	volatile unsigned	flags;		/* dest status flags */
 	atomic_t		conn_flags;	/* flags to copy to conn */
 	atomic_t		weight;		/* server weight */
@@ -606,8 +606,8 @@
 	/* for virtual service */
 	struct ip_vs_service	*svc;		/* service it belongs to */
 	__u16			protocol;	/* which protocol (TCP/UDP) */
-	__u32			vaddr;		/* virtual IP address */
-	__u16			vport;		/* virtual port number */
+	__be32			vaddr;		/* virtual IP address */
+	__be16			vport;		/* virtual port number */
 	__u32			vfwmark;	/* firewall mark of service */
 };
 
@@ -649,7 +649,7 @@
 	/* members for application incarnations */
 	struct list_head	p_list;		/* member in proto app list */
 	struct ip_vs_app	*app;		/* its real application */
-	__u16			port;		/* port number in net order */
+	__be16			port;		/* port number in net order */
 	atomic_t		usecnt;		/* usage counter */
 
 	/* output hook: return false if can't linearize. diff set for TCP.  */
@@ -741,11 +741,11 @@
 };
 
 extern struct ip_vs_conn *ip_vs_conn_in_get
-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
+(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port);
 extern struct ip_vs_conn *ip_vs_ct_in_get
-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
+(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port);
 extern struct ip_vs_conn *ip_vs_conn_out_get
-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
+(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port);
 
 /* put back the conn without restarting its timer */
 static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
@@ -753,11 +753,11 @@
 	atomic_dec(&cp->refcnt);
 }
 extern void ip_vs_conn_put(struct ip_vs_conn *cp);
-extern void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __u16 cport);
+extern void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport);
 
 extern struct ip_vs_conn *
-ip_vs_conn_new(int proto, __u32 caddr, __u16 cport, __u32 vaddr, __u16 vport,
-	       __u32 daddr, __u16 dport, unsigned flags,
+ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport,
+	       __be32 daddr, __be16 dport, unsigned flags,
 	       struct ip_vs_dest *dest);
 extern void ip_vs_conn_expire_now(struct ip_vs_conn *cp);
 
@@ -888,7 +888,7 @@
 extern struct ip_vs_stats ip_vs_stats;
 
 extern struct ip_vs_service *
-ip_vs_service_get(__u32 fwmark, __u16 protocol, __u32 vaddr, __u16 vport);
+ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport);
 
 static inline void ip_vs_service_put(struct ip_vs_service *svc)
 {
@@ -896,7 +896,7 @@
 }
 
 extern struct ip_vs_dest *
-ip_vs_lookup_real_service(__u16 protocol, __u32 daddr, __u16 dport);
+ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport);
 extern int ip_vs_use_count_inc(void);
 extern void ip_vs_use_count_dec(void);
 extern int ip_vs_control_init(void);
diff -urN oldtree/include/net/ipconfig.h newtree/include/net/ipconfig.h
--- oldtree/include/net/ipconfig.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/net/ipconfig.h	2006-02-21 15:58:36.930532264 +0000
@@ -11,12 +11,12 @@
 extern int ic_proto_enabled;	/* Protocols enabled (see IC_xxx) */
 extern int ic_set_manually;	/* IPconfig parameters set manually */
 
-extern u32 ic_myaddr;		/* My IP address */
-extern u32 ic_gateway;		/* Gateway IP address */
+extern __be32 ic_myaddr;	/* My IP address */
+extern __be32 ic_gateway;	/* Gateway IP address */
 
-extern u32 ic_servaddr;		/* Boot server IP address */
+extern __be32 ic_servaddr;	/* Boot server IP address */
 
-extern u32 root_server_addr;	/* Address of NFS server */
+extern __be32 root_server_addr;	/* Address of NFS server */
 extern u8 root_server_path[];	/* Path to mount as root */
 
 
diff -urN oldtree/include/net/ipv6.h newtree/include/net/ipv6.h
--- oldtree/include/net/ipv6.h	2006-02-19 11:41:05.996431504 +0000
+++ newtree/include/net/ipv6.h	2006-02-21 15:58:36.931532112 +0000
@@ -94,10 +94,10 @@
  */
 
 struct frag_hdr {
-	unsigned char	nexthdr;
-	unsigned char	reserved;	
-	unsigned short	frag_off;
-	__u32		identification;
+	__u8	nexthdr;
+	__u8	reserved;	
+	__be16	frag_off;
+	__be32	identification;
 };
 
 #define	IP6_MF	0x0001
@@ -191,7 +191,7 @@
 struct ip6_flowlabel
 {
 	struct ip6_flowlabel	*next;
-	u32			label;
+	__be32			label;
 	struct in6_addr		dst;
 	struct ipv6_txoptions	*opt;
 	atomic_t		users;
@@ -211,7 +211,7 @@
 	struct ip6_flowlabel	*fl;
 };
 
-extern struct ip6_flowlabel	*fl6_sock_lookup(struct sock *sk, u32 label);
+extern struct ip6_flowlabel	*fl6_sock_lookup(struct sock *sk, __be32 label);
 extern struct ipv6_txoptions	*fl6_merge_options(struct ipv6_txoptions * opt_space,
 						   struct ip6_flowlabel * fl,
 						   struct ipv6_txoptions * fopt);
@@ -282,6 +282,18 @@
 	return memcmp((const void *) a1, (const void *) a2, sizeof(struct in6_addr));
 }
 
+static inline int
+ipv6_masked_addr_cmp(const struct in6_addr *a1, const struct in6_addr *m,
+		     const struct in6_addr *a2)
+{
+	unsigned int i;
+
+	for (i = 0; i < 4; i++)
+		if ((a1->s6_addr32[i] ^ a2->s6_addr32[i]) & m->s6_addr32[i])
+			return 1;
+	return 0;
+}
+
 static inline void ipv6_addr_copy(struct in6_addr *a1, const struct in6_addr *a2)
 {
 	memcpy((void *) a1, (const void *) a2, sizeof(struct in6_addr));
@@ -306,8 +318,8 @@
 
 #ifndef __HAVE_ARCH_ADDR_SET
 static inline void ipv6_addr_set(struct in6_addr *addr, 
-				     __u32 w1, __u32 w2,
-				     __u32 w3, __u32 w4)
+				     __be32 w1, __be32 w2,
+				     __be32 w3, __be32 w4)
 {
 	addr->s6_addr32[0] = w1;
 	addr->s6_addr32[1] = w2;
@@ -325,7 +337,7 @@
 		a1->s6_addr32[3] == a2->s6_addr32[3]);
 }
 
-static inline int __ipv6_prefix_equal(const u32 *a1, const u32 *a2,
+static inline int __ipv6_prefix_equal(const __be32 *a1, const __be32 *a2,
 				      unsigned int prefixlen)
 {
 	unsigned pdw, pbi;
@@ -517,7 +529,7 @@
 						     struct sockaddr *addr, int addr_len);
 
 extern int 			ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len);
-extern void			ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, u16 port,
+extern void			ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, __be16 port,
 						u32 info, u8 *payload);
 extern void			ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info);
 
diff -urN oldtree/include/net/ndisc.h newtree/include/net/ndisc.h
--- oldtree/include/net/ndisc.h	2006-02-19 11:41:05.998431200 +0000
+++ newtree/include/net/ndisc.h	2006-02-21 15:58:36.933531808 +0000
@@ -22,6 +22,8 @@
 	ND_OPT_PREFIX_INFO = 3,		/* RFC2461 */
 	ND_OPT_REDIRECT_HDR = 4,	/* RFC2461 */
 	ND_OPT_MTU = 5,			/* RFC2461 */
+	__ND_OPT_ARRAY_MAX,
+	ND_OPT_ROUTE_INFO = 24,		/* RFC4191 */
 	__ND_OPT_MAX
 };
 
@@ -65,8 +67,8 @@
 
 struct ra_msg {
         struct icmp6hdr		icmph;
-	__u32			reachable_time;
-	__u32			retrans_timer;
+	__be32			reachable_time;
+	__be32			retrans_timer;
 };
 
 struct nd_opt_hdr {
diff -urN oldtree/include/net/netfilter/nf_conntrack.h newtree/include/net/netfilter/nf_conntrack.h
--- oldtree/include/net/netfilter/nf_conntrack.h	2006-02-19 11:41:06.000430896 +0000
+++ newtree/include/net/netfilter/nf_conntrack.h	2006-02-21 15:58:16.272672736 +0000
@@ -67,6 +67,18 @@
 
 struct nf_conntrack_helper;
 
+/* nf_conn feature for connections that have a helper */
+struct nf_conn_help {
+	/* Helper. if any */
+	struct nf_conntrack_helper *helper;
+	
+	union nf_conntrack_help help;
+	
+	/* Current number of expected connections */
+	unsigned int expecting;
+};
+
+
 #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
 struct nf_conn
 {
@@ -81,6 +93,9 @@
 	/* Have we seen traffic both ways yet? (bitset) */
 	unsigned long status;
 
+	/* If we were expected by an expectation, this will be it */
+	struct nf_conn *master;
+
 	/* Timer function; drops refcnt when it goes off. */
 	struct timer_list timeout;
 
@@ -88,38 +103,22 @@
 	/* Accounting Information (same cache line as other written members) */
 	struct ip_conntrack_counter counters[IP_CT_DIR_MAX];
 #endif
-	/* If we were expected by an expectation, this will be it */
-	struct nf_conn *master;
-	
-	/* Current number of expected connections */
-	unsigned int expecting;
 
 	/* Unique ID that identifies this conntrack*/
 	unsigned int id;
 
-	/* Helper. if any */
-	struct nf_conntrack_helper *helper;
-
 	/* features - nat, helper, ... used by allocating system */
 	u_int32_t features;
 
-	/* Storage reserved for other modules: */
-
-	union nf_conntrack_proto proto;
-
 #if defined(CONFIG_NF_CONNTRACK_MARK)
 	u_int32_t mark;
 #endif
 
-	/* These members are dynamically allocated. */
-
-	union nf_conntrack_help *help;
+	/* Storage reserved for other modules: */
+	union nf_conntrack_proto proto;
 
-	/* Layer 3 dependent members. (ex: NAT) */
-	union {
-		struct nf_conntrack_ipv4 *ipv4;
-	} l3proto;
-	void *data[0];
+	/* features dynamically at the end: helper, nat (both optional) */
+	char data[0];
 };
 
 struct nf_conntrack_expect
@@ -373,10 +372,23 @@
 #define NF_CT_F_NUM	4
 
 extern int
-nf_conntrack_register_cache(u_int32_t features, const char *name, size_t size,
-			    int (*init_conntrack)(struct nf_conn *, u_int32_t));
+nf_conntrack_register_cache(u_int32_t features, const char *name, size_t size);
 extern void
 nf_conntrack_unregister_cache(u_int32_t features);
 
+/* valid combinations:
+ * basic: nf_conn, nf_conn .. nf_conn_help
+ * nat: nf_conn .. nf_conn_nat, nf_conn .. nf_conn_nat, nf_conn help
+ */
+static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
+{
+	unsigned int offset = sizeof(struct nf_conn);
+
+	if (!(ct->features & NF_CT_F_HELP))
+		return NULL;
+
+	return (struct nf_conn_help *) ((void *)ct + offset);
+}
+
 #endif /* __KERNEL__ */
 #endif /* _NF_CONNTRACK_H */
diff -urN oldtree/include/net/protocol.h newtree/include/net/protocol.h
--- oldtree/include/net/protocol.h	2006-02-19 11:41:06.002430592 +0000
+++ newtree/include/net/protocol.h	2006-02-21 15:58:36.933531808 +0000
@@ -48,7 +48,7 @@
 	void	(*err_handler)(struct sk_buff *skb,
 			       struct inet6_skb_parm *opt,
 			       int type, int code, int offset,
-			       __u32 info);
+			       __be32 info);
 	unsigned int	flags;	/* INET6_PROTO_xxx */
 };
 
diff -urN oldtree/include/net/rawv6.h newtree/include/net/rawv6.h
--- oldtree/include/net/rawv6.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/net/rawv6.h	2006-02-21 15:58:36.933531808 +0000
@@ -21,7 +21,7 @@
 					  struct sk_buff *skb,
 					  struct inet6_skb_parm *opt,
 					  int type, int code, 
-					  int offset, u32 info);
+					  int offset, __be32 info);
 
 #endif
 
diff -urN oldtree/include/net/route.h newtree/include/net/route.h
--- oldtree/include/net/route.h	2006-02-19 11:41:06.004430288 +0000
+++ newtree/include/net/route.h	2006-02-21 15:58:36.934531656 +0000
@@ -62,18 +62,18 @@
 	__u16			rt_type;
 	__u16			rt_multipath_alg;
 
-	__u32			rt_dst;	/* Path destination	*/
-	__u32			rt_src;	/* Path source		*/
+	__be32			rt_dst;	/* Path destination	*/
+	__be32			rt_src;	/* Path source		*/
 	int			rt_iif;
 
 	/* Info on neighbour */
-	__u32			rt_gateway;
+	__be32			rt_gateway;
 
 	/* Cache lookup keys */
 	struct flowi		fl;
 
 	/* Miscellaneous cached information */
-	__u32			rt_spec_dst; /* RFC1122 specific destination */
+	__be32			rt_spec_dst; /* RFC1122 specific destination */
 	struct inet_peer	*peer; /* long-living peer info */
 };
 
@@ -109,18 +109,18 @@
 
 struct in_device;
 extern int		ip_rt_init(void);
-extern void		ip_rt_redirect(u32 old_gw, u32 dst, u32 new_gw,
-				       u32 src, u8 tos, struct net_device *dev);
+extern void		ip_rt_redirect(__be32 old_gw, __be32 dst, __be32 new_gw,
+				       __be32 src, u8 tos, struct net_device *dev);
 extern void		ip_rt_advice(struct rtable **rp, int advice);
 extern void		rt_cache_flush(int how);
 extern int		__ip_route_output_key(struct rtable **, const struct flowi *flp);
 extern int		ip_route_output_key(struct rtable **, struct flowi *flp);
 extern int		ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, int flags);
-extern int		ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin);
+extern int		ip_route_input(struct sk_buff*, __be32 dst, __be32 src, u8 tos, struct net_device *devin);
 extern unsigned short	ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu);
 extern void		ip_rt_send_redirect(struct sk_buff *skb);
 
-extern unsigned		inet_addr_type(u32 addr);
+extern unsigned		inet_addr_type(__be32 addr);
 extern void		ip_rt_multicast_event(struct in_device *);
 extern int		ip_rt_ioctl(unsigned int cmd, void __user *arg);
 extern void		ip_rt_get_source(u8 *src, struct rtable *rt);
@@ -144,9 +144,9 @@
 	return ip_tos2prio[IPTOS_TOS(tos)>>1];
 }
 
-static inline int ip_route_connect(struct rtable **rp, u32 dst,
-				   u32 src, u32 tos, int oif, u8 protocol,
-				   u16 sport, u16 dport, struct sock *sk)
+static inline int ip_route_connect(struct rtable **rp, __be32 dst,
+				   __be32 src, u32 tos, int oif, u8 protocol,
+				   __be16 sport, __be16 dport, struct sock *sk)
 {
 	struct flowi fl = { .oif = oif,
 			    .nl_u = { .ip4_u = { .daddr = dst,
@@ -171,7 +171,7 @@
 }
 
 static inline int ip_route_newports(struct rtable **rp, u8 protocol,
-				    u16 sport, u16 dport, struct sock *sk)
+				    __be16 sport, __be16 dport, struct sock *sk)
 {
 	if (sport != (*rp)->fl.fl_ip_sport ||
 	    dport != (*rp)->fl.fl_ip_dport) {
diff -urN oldtree/include/net/tcp.h newtree/include/net/tcp.h
--- oldtree/include/net/tcp.h	2006-02-19 11:41:06.009429528 +0000
+++ newtree/include/net/tcp.h	2006-02-21 15:58:16.282671216 +0000
@@ -60,6 +60,9 @@
 /* Minimal RCV_MSS. */
 #define TCP_MIN_RCVMSS		536U
 
+/* The least MTU to use for probing */
+#define TCP_BASE_MSS		512
+
 /* After receiving this amount of duplicate ACKs fast retransmit starts. */
 #define TCP_FASTRETRANS_THRESH 3
 
@@ -219,6 +222,8 @@
 extern int sysctl_tcp_moderate_rcvbuf;
 extern int sysctl_tcp_tso_win_divisor;
 extern int sysctl_tcp_abc;
+extern int sysctl_tcp_mtu_probing;
+extern int sysctl_tcp_base_mss;
 
 extern atomic_t tcp_memory_allocated;
 extern atomic_t tcp_sockets_allocated;
@@ -447,6 +452,10 @@
 
 extern void tcp_initialize_rcv_mss(struct sock *sk);
 
+extern int tcp_mtu_to_mss(struct sock *sk, int pmtu);
+extern int tcp_mss_to_mtu(struct sock *sk, int mss);
+extern void tcp_mtup_init(struct sock *sk);
+
 static inline void __tcp_fast_path_on(struct tcp_sock *tp, u32 snd_wnd)
 {
 	tp->pred_flags = htonl((tp->tcp_header_len << 26) |
diff -urN oldtree/include/net/tipc/tipc_bearer.h newtree/include/net/tipc/tipc_bearer.h
--- oldtree/include/net/tipc/tipc_bearer.h	2006-02-19 11:41:06.011429224 +0000
+++ newtree/include/net/tipc/tipc_bearer.h	2006-02-21 15:58:36.940530744 +0000
@@ -50,7 +50,7 @@
 #define TIPC_MEDIA_TYPE_ETH	1
 
 struct tipc_media_addr {
-	__u32  type;
+	__be32  type;
 	union {
 		__u8   eth_addr[6];	/* Ethernet bearer */ 
 #if 0
diff -urN oldtree/include/net/tipc/tipc_msg.h newtree/include/net/tipc/tipc_msg.h
--- oldtree/include/net/tipc/tipc_msg.h	2006-02-19 11:41:06.012429072 +0000
+++ newtree/include/net/tipc/tipc_msg.h	2006-02-21 15:58:36.940530744 +0000
@@ -40,7 +40,7 @@
 #ifdef __KERNEL__
 
 struct tipc_msg {
-	u32 hdr[15];
+	__be32 hdr[15];
 };
 
 
diff -urN oldtree/include/net/xfrm.h newtree/include/net/xfrm.h
--- oldtree/include/net/xfrm.h	2006-02-19 11:41:06.014428768 +0000
+++ newtree/include/net/xfrm.h	2006-02-21 15:58:36.941530592 +0000
@@ -11,6 +11,7 @@
 #include <linux/crypto.h>
 #include <linux/pfkeyv2.h>
 #include <linux/in6.h>
+#include <linux/mutex.h>
 
 #include <net/sock.h>
 #include <net/dst.h>
@@ -20,7 +21,11 @@
 
 #define XFRM_ALIGN8(len)	(((len) + 7) & ~7)
 
-extern struct semaphore xfrm_cfg_sem;
+extern struct sock *xfrm_nl;
+extern u32 sysctl_xfrm_aevent_etime;
+extern u32 sysctl_xfrm_aevent_rseqth;
+
+extern struct mutex xfrm_cfg_mutex;
 
 /* Organization of SPD aka "XFRM rules"
    ------------------------------------
@@ -135,6 +140,16 @@
 	/* State for replay detection */
 	struct xfrm_replay_state replay;
 
+	/* Replay detection state at the time we sent the last notification */
+	struct xfrm_replay_state preplay;
+
+	/* Replay detection notification settings */
+	u32			replay_maxage;
+	u32			replay_maxdiff;
+
+	/* Replay detection notification timer */
+	struct timer_list	rtimer;
+
 	/* Statistics */
 	struct xfrm_stats	stats;
 
@@ -169,6 +184,7 @@
 		u32 hard;
 		u32 proto;
 		u32 byid;
+		u32 aevent;
 	} data;
 
 	u32	seq;
@@ -199,10 +215,13 @@
 extern int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo);
 extern void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c);
 extern void km_state_notify(struct xfrm_state *x, struct km_event *c);
-
 #define XFRM_ACQ_EXPIRES	30
 
 struct xfrm_tmpl;
+extern int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
+extern void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
+extern int __xfrm_state_delete(struct xfrm_state *x);
+
 struct xfrm_state_afinfo {
 	unsigned short		family;
 	rwlock_t		lock;
@@ -212,7 +231,7 @@
 	void			(*init_tempsel)(struct xfrm_state *x, struct flowi *fl,
 						struct xfrm_tmpl *tmpl,
 						xfrm_address_t *daddr, xfrm_address_t *saddr);
-	struct xfrm_state	*(*state_lookup)(xfrm_address_t *daddr, u32 spi, u8 proto);
+	struct xfrm_state	*(*state_lookup)(xfrm_address_t *daddr, __be32 spi, u8 proto);
 	struct xfrm_state	*(*find_acq)(u8 mode, u32 reqid, u8 proto, 
 					     xfrm_address_t *daddr, xfrm_address_t *saddr, 
 					     int create);
@@ -306,7 +325,21 @@
 	struct xfrm_tmpl       	xfrm_vec[XFRM_MAX_DEPTH];
 };
 
-#define XFRM_KM_TIMEOUT		30
+#define XFRM_KM_TIMEOUT                30
+/* which seqno */
+#define XFRM_REPLAY_SEQ		1
+#define XFRM_REPLAY_OSEQ	2
+#define XFRM_REPLAY_SEQ_MASK	3
+/* what happened */
+#define XFRM_REPLAY_UPDATE	XFRM_AE_CR
+#define XFRM_REPLAY_TIMEOUT	XFRM_AE_CE
+
+/* default aevent timeout in units of 100ms */
+#define XFRM_AE_ETIME			10
+/* Async Event timer multiplier */
+#define XFRM_AE_ETH_M			10
+/* default seq threshold size */
+#define XFRM_AE_SEQT_SIZE		2
 
 struct xfrm_mgr
 {
@@ -372,25 +405,25 @@
 }
 
 static __inline__
-unsigned __xfrm4_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto)
+unsigned __xfrm4_spi_hash(xfrm_address_t *addr, __be32 spi, u8 proto)
 {
 	unsigned h;
-	h = ntohl(addr->a4^spi^proto);
+	h = ntohl(addr->a4^spi^(__force __be32)proto);
 	h = (h ^ (h>>10) ^ (h>>20)) % XFRM_DST_HSIZE;
 	return h;
 }
 
 static __inline__
-unsigned __xfrm6_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto)
+unsigned __xfrm6_spi_hash(xfrm_address_t *addr, __be32 spi, u8 proto)
 {
 	unsigned h;
-	h = ntohl(addr->a6[2]^addr->a6[3]^spi^proto);
+	h = ntohl(addr->a6[2]^addr->a6[3]^spi^(__force __be32)proto);
 	h = (h ^ (h>>10) ^ (h>>20)) % XFRM_DST_HSIZE;
 	return h;
 }
 
 static __inline__
-unsigned xfrm_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto, unsigned short family)
+unsigned xfrm_spi_hash(xfrm_address_t *addr, __be32 spi, u8 proto, unsigned short family)
 {
 	switch (family) {
 	case AF_INET:
@@ -416,8 +449,8 @@
 
 static __inline__ int addr_match(void *token1, void *token2, int prefixlen)
 {
-	__u32 *a1 = token1;
-	__u32 *a2 = token2;
+	__be32 *a1 = token1;
+	__be32 *a2 = token2;
 	int pdw;
 	int pbi;
 
@@ -429,7 +462,7 @@
 			return 0;
 
 	if (pbi) {
-		__u32 mask;
+		__be32 mask;
 
 		mask = htonl((0xffffffff) << (32 - pbi));
 
@@ -441,9 +474,9 @@
 }
 
 static __inline__
-u16 xfrm_flowi_sport(struct flowi *fl)
+__be16 xfrm_flowi_sport(struct flowi *fl)
 {
-	u16 port;
+	__be16 port;
 	switch(fl->proto) {
 	case IPPROTO_TCP:
 	case IPPROTO_UDP:
@@ -461,9 +494,9 @@
 }
 
 static __inline__
-u16 xfrm_flowi_dport(struct flowi *fl)
+__be16 xfrm_flowi_dport(struct flowi *fl)
 {
-	u16 port;
+	__be16 port;
 	switch(fl->proto) {
 	case IPPROTO_TCP:
 	case IPPROTO_UDP:
@@ -833,7 +866,7 @@
 struct xfrm6_tunnel {
 	int (*handler)(struct sk_buff **pskb);
 	void (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt,
-			    int type, int code, int offset, __u32 info);
+			    int type, int code, int offset, __be32 info);
 };
 
 extern void xfrm_init(void);
@@ -861,6 +894,7 @@
 extern void xfrm_state_flush(u8 proto);
 extern int xfrm_replay_check(struct xfrm_state *x, u32 seq);
 extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq);
+extern void xfrm_replay_notify(struct xfrm_state *x, int event);
 extern int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb);
 extern int xfrm_state_mtu(struct xfrm_state *x, int mtu);
 extern int xfrm_init_state(struct xfrm_state *x);
@@ -868,13 +902,13 @@
 extern int xfrm4_output(struct sk_buff *skb);
 extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
 extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler);
-extern int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi);
+extern int xfrm6_rcv_spi(struct sk_buff **pskb, __be32 spi);
 extern int xfrm6_rcv(struct sk_buff **pskb);
 extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler);
 extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler);
-extern u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr);
+extern __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr);
 extern void xfrm6_tunnel_free_spi(xfrm_address_t *saddr);
-extern u32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr);
+extern __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr);
 extern int xfrm6_output(struct sk_buff *skb);
 
 #ifdef CONFIG_XFRM
@@ -907,7 +941,7 @@
 struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete);
 void xfrm_policy_flush(void);
 u32 xfrm_get_acqseq(void);
-void xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi);
+void xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi);
 struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, 
 				  xfrm_address_t *daddr, xfrm_address_t *saddr, 
 				  int create, unsigned short family);
@@ -920,10 +954,10 @@
 
 extern wait_queue_head_t km_waitq;
 extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport);
-extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard);
+extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid);
 
 extern void xfrm_input_init(void);
-extern int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq);
+extern int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq);
 
 extern void xfrm_probe_algs(void);
 extern int xfrm_count_auth_supported(void);
@@ -949,7 +983,7 @@
 	switch (family) {
 	default:
 	case AF_INET:
-		return a->a4 - b->a4;
+		return (__force __u32)a->a4 - (__force __u32)b->a4;
 	case AF_INET6:
 		return ipv6_addr_cmp((struct in6_addr *)a,
 				     (struct in6_addr *)b);
@@ -961,4 +995,16 @@
 	return index & 7;
 }
 
+static inline int xfrm_aevent_is_on(void)
+{
+	return netlink_has_listeners(xfrm_nl,XFRMNLGRP_AEVENTS);
+}
+
+static inline void xfrm_aevent_doreplay(struct xfrm_state *x)
+{
+	if (xfrm_aevent_is_on())
+		xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
+}
+
+
 #endif	/* _NET_XFRM_H */
diff -urN oldtree/include/rdma/ib_fmr_pool.h newtree/include/rdma/ib_fmr_pool.h
--- oldtree/include/rdma/ib_fmr_pool.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/rdma/ib_fmr_pool.h	2006-02-21 15:58:14.903880824 +0000
@@ -43,6 +43,7 @@
 /**
  * struct ib_fmr_pool_param - Parameters for creating FMR pool
  * @max_pages_per_fmr:Maximum number of pages per map request.
+ * @page_shift: Log2 of sizeof "pages" mapped by this fmr
  * @access:Access flags for FMRs in pool.
  * @pool_size:Number of FMRs to allocate for pool.
  * @dirty_watermark:Flush is triggered when @dirty_watermark dirty
@@ -55,6 +56,7 @@
  */
 struct ib_fmr_pool_param {
 	int                     max_pages_per_fmr;
+	int                     page_shift;
 	enum ib_access_flags    access;
 	int                     pool_size;
 	int                     dirty_watermark;
diff -urN oldtree/include/rdma/ib_user_verbs.h newtree/include/rdma/ib_user_verbs.h
--- oldtree/include/rdma/ib_user_verbs.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/rdma/ib_user_verbs.h	2006-02-21 15:58:14.915879000 +0000
@@ -1,7 +1,8 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 PathScale, Inc.  All rights reserved.
+ * Copyright (c) 2006 Mellanox Technologies.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -43,7 +44,7 @@
  * Increment this value if any changes that break userspace ABI
  * compatibility are made.
  */
-#define IB_USER_VERBS_ABI_VERSION	4
+#define IB_USER_VERBS_ABI_VERSION	5
 
 enum {
 	IB_USER_VERBS_CMD_GET_CONTEXT,
@@ -265,6 +266,17 @@
 	__u32 cqe;
 };
 
+struct ib_uverbs_resize_cq {
+	__u64 response;
+	__u32 cq_handle;
+	__u32 cqe;
+	__u64 driver_data[0];
+};
+
+struct ib_uverbs_resize_cq_resp {
+	__u32 cqe;
+};
+
 struct ib_uverbs_poll_cq {
 	__u64 response;
 	__u32 cq_handle;
@@ -338,6 +350,7 @@
 	__u32 max_send_sge;
 	__u32 max_recv_sge;
 	__u32 max_inline_data;
+	__u32 reserved;
 };
 
 /*
@@ -359,6 +372,47 @@
 	__u8  port_num;
 };
 
+struct ib_uverbs_query_qp {
+	__u64 response;
+	__u32 qp_handle;
+	__u32 attr_mask;
+	__u64 driver_data[0];
+};
+
+struct ib_uverbs_query_qp_resp {
+	struct ib_uverbs_qp_dest dest;
+	struct ib_uverbs_qp_dest alt_dest;
+	__u32 max_send_wr;
+	__u32 max_recv_wr;
+	__u32 max_send_sge;
+	__u32 max_recv_sge;
+	__u32 max_inline_data;
+	__u32 qkey;
+	__u32 rq_psn;
+	__u32 sq_psn;
+	__u32 dest_qp_num;
+	__u32 qp_access_flags;
+	__u16 pkey_index;
+	__u16 alt_pkey_index;
+	__u8  qp_state;
+	__u8  cur_qp_state;
+	__u8  path_mtu;
+	__u8  path_mig_state;
+	__u8  en_sqd_async_notify;
+	__u8  max_rd_atomic;
+	__u8  max_dest_rd_atomic;
+	__u8  min_rnr_timer;
+	__u8  port_num;
+	__u8  timeout;
+	__u8  retry_cnt;
+	__u8  rnr_retry;
+	__u8  alt_port_num;
+	__u8  alt_timeout;
+	__u8  sq_sig_all;
+	__u8  reserved[5];
+	__u64 driver_data[0];
+};
+
 struct ib_uverbs_modify_qp {
 	struct ib_uverbs_qp_dest dest;
 	struct ib_uverbs_qp_dest alt_dest;
@@ -415,7 +469,7 @@
 };
 
 struct ib_uverbs_send_wr {
-	__u64 wr_id; 
+	__u64 wr_id;
 	__u32 num_sge;
 	__u32 opcode;
 	__u32 send_flags;
@@ -489,7 +543,7 @@
 
 struct ib_uverbs_global_route {
 	__u8  dgid[16];
-	__u32 flow_label;    
+	__u32 flow_label;
 	__u8  sgid_index;
 	__u8  hop_limit;
 	__u8  traffic_class;
@@ -561,6 +615,20 @@
 	__u64 driver_data[0];
 };
 
+struct ib_uverbs_query_srq {
+	__u64 response;
+	__u32 srq_handle;
+	__u32 reserved;
+	__u64 driver_data[0];
+};
+
+struct ib_uverbs_query_srq_resp {
+	__u32 max_wr;
+	__u32 max_sge;
+	__u32 srq_limit;
+	__u32 reserved;
+};
+
 struct ib_uverbs_destroy_srq {
 	__u64 response;
 	__u32 srq_handle;
diff -urN oldtree/include/rdma/ib_verbs.h newtree/include/rdma/ib_verbs.h
--- oldtree/include/rdma/ib_verbs.h	2006-02-19 11:41:06.016428464 +0000
+++ newtree/include/rdma/ib_verbs.h	2006-02-21 15:58:14.916878848 +0000
@@ -5,7 +5,7 @@
  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
  * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -222,11 +222,13 @@
 };
 
 enum ib_device_modify_flags {
-	IB_DEVICE_MODIFY_SYS_IMAGE_GUID	= 1
+	IB_DEVICE_MODIFY_SYS_IMAGE_GUID	= 1 << 0,
+	IB_DEVICE_MODIFY_NODE_DESC	= 1 << 1
 };
 
 struct ib_device_modify {
 	u64	sys_image_guid;
+	char	node_desc[64];
 };
 
 enum ib_port_modify_flags {
@@ -649,7 +651,7 @@
 struct ib_fmr_attr {
 	int	max_pages;
 	int	max_maps;
-	u8	page_size;
+	u8	page_shift;
 };
 
 struct ib_ucontext {
@@ -880,7 +882,8 @@
 						struct ib_ucontext *context,
 						struct ib_udata *udata);
 	int                        (*destroy_cq)(struct ib_cq *cq);
-	int                        (*resize_cq)(struct ib_cq *cq, int cqe);
+	int                        (*resize_cq)(struct ib_cq *cq, int cqe,
+						struct ib_udata *udata);
 	int                        (*poll_cq)(struct ib_cq *cq, int num_entries,
 					      struct ib_wc *wc);
 	int                        (*peek_cq)(struct ib_cq *cq, int wc_cnt);
@@ -950,6 +953,7 @@
 	u64			     uverbs_cmd_mask;
 	int			     uverbs_abi_ver;
 
+	char			     node_desc[64];
 	__be64			     node_guid;
 	u8                           node_type;
 	u8                           phys_port_cnt;
@@ -986,6 +990,24 @@
 	return copy_to_user(udata->outbuf, src, len) ? -EFAULT : 0;
 }
 
+/**
+ * ib_modify_qp_is_ok - Check that the supplied attribute mask
+ * contains all required attributes and no attributes not allowed for
+ * the given QP state transition.
+ * @cur_state: Current QP state
+ * @next_state: Next QP state
+ * @type: QP type
+ * @mask: Mask of supplied QP attributes
+ *
+ * This function is a helper function that a low-level driver's
+ * modify_qp method can use to validate the consumer's input.  It
+ * checks that cur_state and next_state are valid QP states, that a
+ * transition from cur_state to next_state is allowed by the IB spec,
+ * and that the attribute mask supplied is allowed for the transition.
+ */
+int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
+		       enum ib_qp_type type, enum ib_qp_attr_mask mask);
+
 int ib_register_event_handler  (struct ib_event_handler *event_handler);
 int ib_unregister_event_handler(struct ib_event_handler *event_handler);
 void ib_dispatch_event(struct ib_event *event);
diff -urN oldtree/include/scsi/scsi_cmnd.h newtree/include/scsi/scsi_cmnd.h
--- oldtree/include/scsi/scsi_cmnd.h	2006-02-19 11:41:06.017428312 +0000
+++ newtree/include/scsi/scsi_cmnd.h	2006-02-21 15:58:19.060248960 +0000
@@ -104,10 +104,10 @@
 				   	   working on */
 
 #define SCSI_SENSE_BUFFERSIZE 	96
-	unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];		/* obtained by REQUEST SENSE
-						 * when CHECK CONDITION is
-						 * received on original command 
-						 * (auto-sense) */
+	unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
+				/* obtained by REQUEST SENSE when
+				 * CHECK CONDITION is received on original
+				 * command (auto-sense) */
 
 	/* Low-level done function - can be used by low-level driver to point
 	 *        to completion function.  Not used by mid/upper level code. */
@@ -120,12 +120,12 @@
 	struct scsi_pointer SCp;	/* Scratchpad used by some host adapters */
 
 	unsigned char *host_scribble;	/* The host adapter is allowed to
-					   * call scsi_malloc and get some memory
-					   * and hang it here.     The host adapter
-					   * is also expected to call scsi_free
-					   * to release this memory.  (The memory
-					   * obtained by scsi_malloc is guaranteed
-					   * to be at an address < 16Mb). */
+					 * call scsi_malloc and get some memory
+					 * and hang it here.  The host adapter
+					 * is also expected to call scsi_free
+					 * to release this memory.  (The memory
+					 * obtained by scsi_malloc is guaranteed
+					 * to be at an address < 16Mb). */
 
 	int result;		/* Status code from lower level driver */
 
diff -urN oldtree/include/scsi/scsi_device.h newtree/include/scsi/scsi_device.h
--- oldtree/include/scsi/scsi_device.h	2006-02-19 11:41:06.018428160 +0000
+++ newtree/include/scsi/scsi_device.h	2006-02-21 15:58:19.061248808 +0000
@@ -73,7 +73,6 @@
 	unsigned sector_size;	/* size in bytes */
 
 	void *hostdata;		/* available to low-level driver */
-	char devfs_name[256];	/* devfs junk */
 	char type;
 	char scsi_level;
 	char inq_periph_qual;	/* PQ from INQUIRY data */	
diff -urN oldtree/include/scsi/scsi_transport_sas.h newtree/include/scsi/scsi_transport_sas.h
--- oldtree/include/scsi/scsi_transport_sas.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/include/scsi/scsi_transport_sas.h	2006-02-21 15:58:19.062248656 +0000
@@ -94,6 +94,8 @@
 /* The functions by which the transport class and the driver communicate */
 struct sas_function_template {
 	int (*get_linkerrors)(struct sas_phy *);
+	int (*get_enclosure_identifier)(struct sas_rphy *, u64 *);
+	int (*get_bay_identifier)(struct sas_rphy *);
 	int (*phy_reset)(struct sas_phy *, int);
 };
 
diff -urN oldtree/include/scsi/scsi_transport_spi.h newtree/include/scsi/scsi_transport_spi.h
--- oldtree/include/scsi/scsi_transport_spi.h	2006-02-19 11:41:06.021427704 +0000
+++ newtree/include/scsi/scsi_transport_spi.h	2006-02-21 15:58:19.062248656 +0000
@@ -148,5 +148,9 @@
 void spi_dv_device(struct scsi_device *);
 void spi_display_xfer_agreement(struct scsi_target *);
 int spi_print_msg(const unsigned char *);
+int spi_populate_width_msg(unsigned char *msg, int width);
+int spi_populate_sync_msg(unsigned char *msg, int period, int offset);
+int spi_populate_ppr_msg(unsigned char *msg, int period, int offset, int width,
+		int options);
 
 #endif /* SCSI_TRANSPORT_SPI_H */
diff -urN oldtree/include/sound/ac97_codec.h newtree/include/sound/ac97_codec.h
--- oldtree/include/sound/ac97_codec.h	2006-02-19 11:41:06.022427552 +0000
+++ newtree/include/sound/ac97_codec.h	2006-02-21 15:58:11.192445048 +0000
@@ -456,8 +456,8 @@
 	struct snd_info_entry *proc_regs;
 	unsigned short subsystem_vendor;
 	unsigned short subsystem_device;
-	struct semaphore reg_mutex;
-	struct semaphore page_mutex;	/* mutex for AD18xx multi-codecs and paging (2.3) */
+	struct mutex reg_mutex;
+	struct mutex page_mutex;	/* mutex for AD18xx multi-codecs and paging (2.3) */
 	unsigned short num;	/* number of codec: 0 = primary, 1 = secondary */
 	unsigned short addr;	/* physical address of codec [0-3] */
 	unsigned int id;	/* identification of codec */
diff -urN oldtree/include/sound/ad1848.h newtree/include/sound/ad1848.h
--- oldtree/include/sound/ad1848.h	2006-02-19 11:41:06.023427400 +0000
+++ newtree/include/sound/ad1848.h	2006-02-21 15:58:11.192445048 +0000
@@ -154,7 +154,7 @@
 #endif
 
 	spinlock_t reg_lock;
-	struct semaphore open_mutex;
+	struct mutex open_mutex;
 };
 
 /* exported functions */
diff -urN oldtree/include/sound/ak4531_codec.h newtree/include/sound/ak4531_codec.h
--- oldtree/include/sound/ak4531_codec.h	2006-02-19 11:41:06.027426792 +0000
+++ newtree/include/sound/ak4531_codec.h	2006-02-21 15:58:11.193444896 +0000
@@ -71,7 +71,7 @@
 	void (*private_free) (struct snd_ak4531 *ak4531);
 	/* --- */
 	unsigned char regs[0x20];
-	struct semaphore reg_mutex;
+	struct mutex reg_mutex;
 };
 
 int snd_ak4531_mixer(struct snd_card *card, struct snd_ak4531 *_ak4531,
diff -urN oldtree/include/sound/core.h newtree/include/sound/core.h
--- oldtree/include/sound/core.h	2006-02-19 11:41:06.033425880 +0000
+++ newtree/include/sound/core.h	2006-02-21 15:58:11.206442920 +0000
@@ -23,7 +23,7 @@
  */
 
 #include <linux/sched.h>		/* wake_up() */
-#include <asm/semaphore.h>		/* struct semaphore */
+#include <linux/mutex.h>		/* struct mutex */
 #include <linux/rwsem.h>		/* struct rw_semaphore */
 #include <linux/workqueue.h>		/* struct workqueue_struct */
 #include <linux/pm.h>			/* pm_message_t */
@@ -137,7 +137,7 @@
 
 #ifdef CONFIG_PM
 	unsigned int power_state;	/* power state */
-	struct semaphore power_lock;	/* power lock */
+	struct mutex power_lock;	/* power lock */
 	wait_queue_head_t power_sleep;
 #endif
 
@@ -150,12 +150,12 @@
 #ifdef CONFIG_PM
 static inline void snd_power_lock(struct snd_card *card)
 {
-	down(&card->power_lock);
+	mutex_lock(&card->power_lock);
 }
 
 static inline void snd_power_unlock(struct snd_card *card)
 {
-	up(&card->power_lock);
+	mutex_unlock(&card->power_lock);
 }
 
 static inline unsigned int snd_power_get_state(struct snd_card *card)
diff -urN oldtree/include/sound/cs4231.h newtree/include/sound/cs4231.h
--- oldtree/include/sound/cs4231.h	2006-02-19 11:41:06.110414176 +0000
+++ newtree/include/sound/cs4231.h	2006-02-21 15:58:11.207442768 +0000
@@ -248,8 +248,8 @@
 	unsigned int c_dma_size;
 
 	spinlock_t reg_lock;
-	struct semaphore mce_mutex;
-	struct semaphore open_mutex;
+	struct mutex mce_mutex;
+	struct mutex open_mutex;
 
 	int (*rate_constraint) (struct snd_pcm_runtime *runtime);
 	void (*set_playback_format) (struct snd_cs4231 *chip, struct snd_pcm_hw_params *hw_params, unsigned char pdfr);
diff -urN oldtree/include/sound/cs46xx.h newtree/include/sound/cs46xx.h
--- oldtree/include/sound/cs46xx.h	2006-02-19 11:41:06.111414024 +0000
+++ newtree/include/sound/cs46xx.h	2006-02-21 15:58:11.208442616 +0000
@@ -1711,7 +1711,7 @@
 	int current_gpio;
 #endif
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-	struct semaphore spos_mutex;
+	struct mutex spos_mutex;
 
 	struct dsp_spos_instance * dsp_spos_instance;
 
diff -urN oldtree/include/sound/emu10k1.h newtree/include/sound/emu10k1.h
--- oldtree/include/sound/emu10k1.h	2006-02-19 11:41:06.118412960 +0000
+++ newtree/include/sound/emu10k1.h	2006-02-21 15:58:11.210442312 +0000
@@ -33,6 +33,7 @@
 #include <sound/pcm-indirect.h>
 #include <sound/timer.h>
 #include <linux/interrupt.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 
 /* ------------------- DEFINES -------------------- */
@@ -1022,7 +1023,7 @@
 	int gpr_size;			/* size of allocated GPR controls */
 	int gpr_count;			/* count of used kcontrols */
 	struct list_head gpr_ctl;	/* GPR controls */
-	struct semaphore lock;
+	struct mutex lock;
 	struct snd_emu10k1_fx8010_pcm pcm[8];
 	spinlock_t irq_lock;
 	struct snd_emu10k1_fx8010_irq *irq_handlers;
@@ -1122,7 +1123,6 @@
 	spinlock_t reg_lock;
 	spinlock_t emu_lock;
 	spinlock_t voice_lock;
-	struct semaphore ptb_lock;
 
 	struct snd_emu10k1_voice voices[NUM_G];
 	struct snd_emu10k1_voice p16v_voices[4];
diff -urN oldtree/include/sound/emux_synth.h newtree/include/sound/emux_synth.h
--- oldtree/include/sound/emux_synth.h	2006-02-19 11:41:06.120412656 +0000
+++ newtree/include/sound/emux_synth.h	2006-02-21 15:58:11.211442160 +0000
@@ -113,7 +113,7 @@
 	struct snd_emux_voice *voices;	/* Voices (EMU 'channel') */
 	int use_time;	/* allocation counter */
 	spinlock_t voice_lock;	/* Lock for voice access */
-	struct semaphore register_mutex;
+	struct mutex register_mutex;
 	int client;		/* For the sequencer client */
 	int ports[SNDRV_EMUX_MAX_PORTS];	/* The ports for this device */
 	struct snd_emux_port *portptrs[SNDRV_EMUX_MAX_PORTS];
diff -urN oldtree/include/sound/gus.h newtree/include/sound/gus.h
--- oldtree/include/sound/gus.h	2006-02-19 11:41:06.122412352 +0000
+++ newtree/include/sound/gus.h	2006-02-21 15:58:11.212442008 +0000
@@ -209,7 +209,7 @@
 	struct snd_gf1_bank_info banks_16[4];
 	struct snd_gf1_mem_block *first;
 	struct snd_gf1_mem_block *last;
-	struct semaphore memory_mutex;
+	struct mutex memory_mutex;
 };
 
 struct snd_gf1_dma_block {
@@ -467,8 +467,8 @@
 	spinlock_t dma_lock;
 	spinlock_t pcm_volume_level_lock;
 	spinlock_t uart_cmd_lock;
-	struct semaphore dma_mutex;
-	struct semaphore register_mutex;
+	struct mutex dma_mutex;
+	struct mutex register_mutex;
 };
 
 /* I/O functions for GF1/InterWave chip - gus_io.c */
diff -urN oldtree/include/sound/hwdep.h newtree/include/sound/hwdep.h
--- oldtree/include/sound/hwdep.h	2006-02-19 11:41:06.123412200 +0000
+++ newtree/include/sound/hwdep.h	2006-02-21 15:58:11.212442008 +0000
@@ -60,7 +60,7 @@
 	void *private_data;
 	void (*private_free) (struct snd_hwdep *hwdep);
 
-	struct semaphore open_mutex;
+	struct mutex open_mutex;
 	int used;
 	unsigned int dsp_loaded;
 	unsigned int exclusive: 1;
diff -urN oldtree/include/sound/i2c.h newtree/include/sound/i2c.h
--- oldtree/include/sound/i2c.h	2006-02-19 11:41:06.124412048 +0000
+++ newtree/include/sound/i2c.h	2006-02-21 15:58:11.213441856 +0000
@@ -55,7 +55,7 @@
 	struct snd_card *card;	/* card which I2C belongs to */
 	char name[32];		/* some useful label */
 
-	struct semaphore lock_mutex;
+	struct mutex lock_mutex;
 
 	struct snd_i2c_bus *master;	/* master bus when SCK/SCL is shared */
 	struct list_head buses;	/* master: slave buses sharing SCK/SCL, slave: link list */
@@ -84,17 +84,17 @@
 static inline void snd_i2c_lock(struct snd_i2c_bus *bus)
 {
 	if (bus->master)
-		down(&bus->master->lock_mutex);
+		mutex_lock(&bus->master->lock_mutex);
 	else
-		down(&bus->lock_mutex);
+		mutex_lock(&bus->lock_mutex);
 }
 
 static inline void snd_i2c_unlock(struct snd_i2c_bus *bus)
 {
 	if (bus->master)
-		up(&bus->master->lock_mutex);
+		mutex_unlock(&bus->master->lock_mutex);
 	else
-		up(&bus->lock_mutex);
+		mutex_unlock(&bus->lock_mutex);
 }
 
 int snd_i2c_sendbytes(struct snd_i2c_device *device, unsigned char *bytes, int count);
diff -urN oldtree/include/sound/info.h newtree/include/sound/info.h
--- oldtree/include/sound/info.h	2006-02-19 11:41:06.124412048 +0000
+++ newtree/include/sound/info.h	2006-02-21 15:58:11.213441856 +0000
@@ -84,7 +84,7 @@
 	void *private_data;
 	void (*private_free)(struct snd_info_entry *entry);
 	struct proc_dir_entry *p;
-	struct semaphore access;
+	struct mutex access;
 };
 
 #if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
diff -urN oldtree/include/sound/mixer_oss.h newtree/include/sound/mixer_oss.h
--- oldtree/include/sound/mixer_oss.h	2006-02-19 11:41:06.125411896 +0000
+++ newtree/include/sound/mixer_oss.h	2006-02-21 15:58:11.214441704 +0000
@@ -61,7 +61,7 @@
 			  unsigned int active_index);
 	void *private_data_recsrc;
 	void (*private_free_recsrc)(struct snd_mixer_oss *mixer);
-	struct semaphore reg_mutex;
+	struct mutex reg_mutex;
 	struct snd_info_entry *proc_entry;
 	int oss_dev_alloc;
 	/* --- */
diff -urN oldtree/include/sound/opl3.h newtree/include/sound/opl3.h
--- oldtree/include/sound/opl3.h	2006-02-19 11:41:06.127411592 +0000
+++ newtree/include/sound/opl3.h	2006-02-21 15:58:11.214441704 +0000
@@ -53,6 +53,7 @@
 
 #include "driver.h"
 #include <linux/time.h>
+#include <linux/mutex.h>
 #include "core.h"
 #include "hwdep.h"
 #include "timer.h"
@@ -312,7 +313,7 @@
 	int sys_timer_status;		/* system timer run status */
 	spinlock_t sys_timer_lock;	/* Lock for system timer access */
 #endif
-	struct semaphore access_mutex;	/* locking */
+	struct mutex access_mutex;	/* locking */
 };
 
 /* opl3.c */
diff -urN oldtree/include/sound/pcm.h newtree/include/sound/pcm.h
--- oldtree/include/sound/pcm.h	2006-02-19 11:41:06.130411136 +0000
+++ newtree/include/sound/pcm.h	2006-02-21 15:58:11.215441552 +0000
@@ -420,7 +420,7 @@
 	char id[64];
 	char name[80];
 	struct snd_pcm_str streams[2];
-	struct semaphore open_mutex;
+	struct mutex open_mutex;
 	wait_queue_head_t open_wait;
 	void *private_data;
 	void (*private_free) (struct snd_pcm *pcm);
diff -urN oldtree/include/sound/pcm_oss.h newtree/include/sound/pcm_oss.h
--- oldtree/include/sound/pcm_oss.h	2006-02-19 11:41:06.130411136 +0000
+++ newtree/include/sound/pcm_oss.h	2006-02-21 15:58:11.216441400 +0000
@@ -56,8 +56,10 @@
 	size_t mmap_bytes;
 	char *buffer;				/* vmallocated period */
 	size_t buffer_used;			/* used length from period buffer */
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
 	struct snd_pcm_plugin *plugin_first;
 	struct snd_pcm_plugin *plugin_last;
+#endif
 	unsigned int prev_hw_ptr_interrupt;
 };
 
@@ -73,7 +75,7 @@
 
 struct snd_pcm_oss_stream {
 	struct snd_pcm_oss_setup *setup_list;	/* setup list */
-        struct semaphore setup_mutex;
+	struct mutex setup_mutex;
 	struct snd_info_entry *proc_entry;
 };
 
diff -urN oldtree/include/sound/rawmidi.h newtree/include/sound/rawmidi.h
--- oldtree/include/sound/rawmidi.h	2006-02-19 11:41:06.132410832 +0000
+++ newtree/include/sound/rawmidi.h	2006-02-21 15:58:11.216441400 +0000
@@ -26,7 +26,7 @@
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
 #include "seq_device.h"
@@ -130,7 +130,7 @@
 	void *private_data;
 	void (*private_free) (struct snd_rawmidi *rmidi);
 
-	struct semaphore open_mutex;
+	struct mutex open_mutex;
 	wait_queue_head_t open_wait;
 
 	struct snd_info_entry *dev;
diff -urN oldtree/include/sound/sb16_csp.h newtree/include/sound/sb16_csp.h
--- oldtree/include/sound/sb16_csp.h	2006-02-19 11:41:06.134410528 +0000
+++ newtree/include/sound/sb16_csp.h	2006-02-21 15:58:11.217441248 +0000
@@ -158,7 +158,7 @@
 	struct snd_kcontrol *qsound_switch;
 	struct snd_kcontrol *qsound_space;
 
-	struct semaphore access_mutex;	/* locking */
+	struct mutex access_mutex;	/* locking */
 };
 
 int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep);
diff -urN oldtree/include/sound/seq_instr.h newtree/include/sound/seq_instr.h
--- oldtree/include/sound/seq_instr.h	2006-02-19 11:41:06.135410376 +0000
+++ newtree/include/sound/seq_instr.h	2006-02-21 15:58:11.217441248 +0000
@@ -64,7 +64,7 @@
 
 	spinlock_t lock;
 	spinlock_t ops_lock;
-	struct semaphore ops_mutex;
+	struct mutex ops_mutex;
 	unsigned long ops_flags;
 };
 
diff -urN oldtree/include/sound/soundfont.h newtree/include/sound/soundfont.h
--- oldtree/include/sound/soundfont.h	2006-02-19 11:41:06.139409768 +0000
+++ newtree/include/sound/soundfont.h	2006-02-21 15:58:11.217441248 +0000
@@ -93,7 +93,7 @@
 	int sample_locked;	/* locked time for sample */
 	struct snd_sf_callback callback;	/* callback functions */
 	int presets_locked;
-	struct semaphore presets_mutex;
+	struct mutex presets_mutex;
 	spinlock_t lock;
 	struct snd_util_memhdr *memhdr;
 };
diff -urN oldtree/include/sound/util_mem.h newtree/include/sound/util_mem.h
--- oldtree/include/sound/util_mem.h	2006-02-19 11:41:06.143409160 +0000
+++ newtree/include/sound/util_mem.h	2006-02-21 15:58:11.218441096 +0000
@@ -1,5 +1,7 @@
 #ifndef __SOUND_UTIL_MEM_H
 #define __SOUND_UTIL_MEM_H
+
+#include <linux/mutex.h>
 /*
  *  Copyright (C) 2000 Takashi Iwai <tiwai@suse.de>
  *
@@ -40,7 +42,7 @@
 	int nblocks;			/* # of allocated blocks */
 	unsigned int used;		/* used memory size */
 	int block_extra_size;		/* extra data size of chunk */
-	struct semaphore block_mutex;	/* lock */
+	struct mutex block_mutex;	/* lock */
 };
 
 /*
diff -urN oldtree/include/sound/version.h newtree/include/sound/version.h
--- oldtree/include/sound/version.h	2006-02-19 11:41:06.144409008 +0000
+++ newtree/include/sound/version.h	2006-02-21 15:58:11.218441096 +0000
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated by configure.  */
-#define CONFIG_SND_VERSION "1.0.11rc2"
-#define CONFIG_SND_DATE " (Wed Jan 04 08:57:20 2006 UTC)"
+#define CONFIG_SND_VERSION "1.0.11rc3"
+#define CONFIG_SND_DATE " (Thu Feb 02 07:50:46 2006 UTC)"
diff -urN oldtree/include/sound/vx_core.h newtree/include/sound/vx_core.h
--- oldtree/include/sound/vx_core.h	2006-02-19 11:41:06.144409008 +0000
+++ newtree/include/sound/vx_core.h	2006-02-21 15:58:11.219440944 +0000
@@ -206,7 +206,7 @@
 	int audio_monitor[4];			/* playback hw-monitor level */
 	unsigned char audio_monitor_active[4];	/* playback hw-monitor mute/unmute */
 
-	struct semaphore mixer_mutex;
+	struct mutex mixer_mutex;
 
 	const struct firmware *firmware[4]; /* loaded firmware data */
 };
diff -urN oldtree/include/sound/ymfpci.h newtree/include/sound/ymfpci.h
--- oldtree/include/sound/ymfpci.h	2006-02-19 11:41:06.146408704 +0000
+++ newtree/include/sound/ymfpci.h	2006-02-21 15:58:11.220440792 +0000
@@ -269,9 +269,10 @@
 	enum snd_ymfpci_pcm_type type;
 	struct snd_pcm_substream *substream;
 	struct snd_ymfpci_voice *voices[2];	/* playback only */
-	unsigned int running: 1;
-	unsigned int output_front: 1;
-	unsigned int output_rear: 1;
+	unsigned int running: 1,
+	             output_front: 1,
+	             output_rear: 1,
+	             swap_rear: 1;
 	unsigned int update_pcm_vol;
 	u32 period_size;		/* cached from runtime->period_size */
 	u32 buffer_size;		/* cached from runtime->buffer_size */
@@ -344,6 +345,7 @@
 	struct snd_kcontrol *spdif_pcm_ctl;
 	int mode_dup4ch;
 	int rear_opened;
+	int rear_swap;
 	int spdif_opened;
 	struct {
 		u16 left;
@@ -376,7 +378,7 @@
 int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
 int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
 int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
-int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch);
+int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch, int rear_swap);
 int snd_ymfpci_timer(struct snd_ymfpci *chip, int device);
 
 #endif /* __SOUND_YMFPCI_H */
diff -urN oldtree/init/Kconfig newtree/init/Kconfig
--- oldtree/init/Kconfig	2006-02-19 11:41:06.149408248 +0000
+++ newtree/init/Kconfig	2006-02-21 15:58:31.877300472 +0000
@@ -400,6 +400,15 @@
 	  SLOB is more space efficient but does not scale well and is
 	  more susceptible to fragmentation.
 
+config SERIAL_PCI
+	depends PCI && SERIAL_8250
+	default y
+	bool "Enable standard PCI serial support" if EMBEDDED
+	help
+	  This builds standard PCI serial support. You may be able to disable
+          this feature if you only need legacy serial support.
+	  Saves about 9K.
+
 endmenu		# General setup
 
 config TINY_SHMEM
diff -urN oldtree/ipc/compat.c newtree/ipc/compat.c
--- oldtree/ipc/compat.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/ipc/compat.c	2006-02-21 15:58:26.113176752 +0000
@@ -30,7 +30,7 @@
 #include <linux/slab.h>
 #include <linux/syscalls.h>
 
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include "util.h"
diff -urN oldtree/ipc/mqueue.c newtree/ipc/mqueue.c
--- oldtree/ipc/mqueue.c	2006-02-19 11:41:06.154407488 +0000
+++ newtree/ipc/mqueue.c	2006-02-21 15:58:26.114176600 +0000
@@ -25,6 +25,8 @@
 #include <linux/netlink.h>
 #include <linux/syscalls.h>
 #include <linux/signal.h>
+#include <linux/mutex.h>
+
 #include <net/sock.h>
 #include "util.h"
 
@@ -761,7 +763,7 @@
  * The receiver accepts the message and returns without grabbing the queue
  * spinlock. Therefore an intermediate STATE_PENDING state and memory barriers
  * are necessary. The same algorithm is used for sysv semaphores, see
- * ipc/sem.c fore more details.
+ * ipc/mutex.c fore more details.
  *
  * The same algorithm is used for senders.
  */
diff -urN oldtree/ipc/msg.c newtree/ipc/msg.c
--- oldtree/ipc/msg.c	2006-02-19 11:41:06.154407488 +0000
+++ newtree/ipc/msg.c	2006-02-21 15:58:26.115176448 +0000
@@ -28,6 +28,8 @@
 #include <linux/syscalls.h>
 #include <linux/audit.h>
 #include <linux/seq_file.h>
+#include <linux/mutex.h>
+
 #include <asm/current.h>
 #include <asm/uaccess.h>
 #include "util.h"
@@ -179,8 +181,8 @@
  * removes the message queue from message queue ID 
  * array, and cleans up all the messages associated with this queue.
  *
- * msg_ids.sem and the spinlock for this message queue is hold
- * before freeque() is called. msg_ids.sem remains locked on exit.
+ * msg_ids.mutex and the spinlock for this message queue is hold
+ * before freeque() is called. msg_ids.mutex remains locked on exit.
  */
 static void freeque (struct msg_queue *msq, int id)
 {
@@ -208,7 +210,7 @@
 	int id, ret = -EPERM;
 	struct msg_queue *msq;
 	
-	down(&msg_ids.sem);
+	mutex_lock(&msg_ids.mutex);
 	if (key == IPC_PRIVATE) 
 		ret = newque(key, msgflg);
 	else if ((id = ipc_findkey(&msg_ids, key)) == -1) { /* key not used */
@@ -232,7 +234,7 @@
 		}
 		msg_unlock(msq);
 	}
-	up(&msg_ids.sem);
+	mutex_unlock(&msg_ids.mutex);
 	return ret;
 }
 
@@ -362,7 +364,7 @@
 		msginfo.msgmnb = msg_ctlmnb;
 		msginfo.msgssz = MSGSSZ;
 		msginfo.msgseg = MSGSEG;
-		down(&msg_ids.sem);
+		mutex_lock(&msg_ids.mutex);
 		if (cmd == MSG_INFO) {
 			msginfo.msgpool = msg_ids.in_use;
 			msginfo.msgmap = atomic_read(&msg_hdrs);
@@ -373,7 +375,7 @@
 			msginfo.msgtql = MSGTQL;
 		}
 		max_id = msg_ids.max_id;
-		up(&msg_ids.sem);
+		mutex_unlock(&msg_ids.mutex);
 		if (copy_to_user (buf, &msginfo, sizeof(struct msginfo)))
 			return -EFAULT;
 		return (max_id < 0) ? 0: max_id;
@@ -429,8 +431,6 @@
 			return -EFAULT;
 		if (copy_msqid_from_user (&setbuf, buf, version))
 			return -EFAULT;
-		if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode)))
-			return err;
 		break;
 	case IPC_RMID:
 		break;
@@ -438,7 +438,7 @@
 		return  -EINVAL;
 	}
 
-	down(&msg_ids.sem);
+	mutex_lock(&msg_ids.mutex);
 	msq = msg_lock(msqid);
 	err=-EINVAL;
 	if (msq == NULL)
@@ -461,6 +461,9 @@
 	switch (cmd) {
 	case IPC_SET:
 	{
+		if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
+			goto out_unlock_up;
+
 		err = -EPERM;
 		if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
 			goto out_unlock_up;
@@ -489,7 +492,7 @@
 	}
 	err = 0;
 out_up:
-	up(&msg_ids.sem);
+	mutex_unlock(&msg_ids.mutex);
 	return err;
 out_unlock_up:
 	msg_unlock(msq);
diff -urN oldtree/ipc/sem.c newtree/ipc/sem.c
--- oldtree/ipc/sem.c	2006-02-19 11:41:06.155407336 +0000
+++ newtree/ipc/sem.c	2006-02-21 15:58:26.131174016 +0000
@@ -75,6 +75,8 @@
 #include <linux/audit.h>
 #include <linux/capability.h>
 #include <linux/seq_file.h>
+#include <linux/mutex.h>
+
 #include <asm/uaccess.h>
 #include "util.h"
 
@@ -139,7 +141,7 @@
  *   	* if it's IN_WAKEUP, then it must wait until the value changes
  *   	* if it's not -EINTR, then the operation was completed by
  *   	  update_queue. semtimedop can return queue.status without
- *   	  performing any operation on the semaphore array.
+ *   	  performing any operation on the sem array.
  *   	* otherwise it must acquire the spinlock and check what's up.
  *
  * The two-stage algorithm is necessary to protect against the following
@@ -214,7 +216,7 @@
 
 	if (nsems < 0 || nsems > sc_semmsl)
 		return -EINVAL;
-	down(&sem_ids.sem);
+	mutex_lock(&sem_ids.mutex);
 	
 	if (key == IPC_PRIVATE) {
 		err = newary(key, nsems, semflg);
@@ -242,7 +244,7 @@
 		sem_unlock(sma);
 	}
 
-	up(&sem_ids.sem);
+	mutex_unlock(&sem_ids.mutex);
 	return err;
 }
 
@@ -437,8 +439,8 @@
 	return semzcnt;
 }
 
-/* Free a semaphore set. freeary() is called with sem_ids.sem down and
- * the spinlock for this semaphore set hold. sem_ids.sem remains locked
+/* Free a semaphore set. freeary() is called with sem_ids.mutex locked and
+ * the spinlock for this semaphore set hold. sem_ids.mutex remains locked
  * on exit.
  */
 static void freeary (struct sem_array *sma, int id)
@@ -525,7 +527,7 @@
 		seminfo.semmnu = SEMMNU;
 		seminfo.semmap = SEMMAP;
 		seminfo.semume = SEMUME;
-		down(&sem_ids.sem);
+		mutex_lock(&sem_ids.mutex);
 		if (cmd == SEM_INFO) {
 			seminfo.semusz = sem_ids.in_use;
 			seminfo.semaem = used_sems;
@@ -534,7 +536,7 @@
 			seminfo.semaem = SEMAEM;
 		}
 		max_id = sem_ids.max_id;
-		up(&sem_ids.sem);
+		mutex_unlock(&sem_ids.mutex);
 		if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo))) 
 			return -EFAULT;
 		return (max_id < 0) ? 0: max_id;
@@ -809,8 +811,6 @@
 	if(cmd == IPC_SET) {
 		if(copy_semid_from_user (&setbuf, arg.buf, version))
 			return -EFAULT;
-		if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
-			return err;
 	}
 	sma = sem_lock(semid);
 	if(sma==NULL)
@@ -821,7 +821,6 @@
 		goto out_unlock;
 	}	
 	ipcp = &sma->sem_perm;
-	
 	if (current->euid != ipcp->cuid && 
 	    current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
 	    	err=-EPERM;
@@ -838,6 +837,8 @@
 		err = 0;
 		break;
 	case IPC_SET:
+		if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
+			goto out_unlock;
 		ipcp->uid = setbuf.uid;
 		ipcp->gid = setbuf.gid;
 		ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
@@ -886,9 +887,9 @@
 		return err;
 	case IPC_RMID:
 	case IPC_SET:
-		down(&sem_ids.sem);
+		mutex_lock(&sem_ids.mutex);
 		err = semctl_down(semid,semnum,cmd,version,arg);
-		up(&sem_ids.sem);
+		mutex_unlock(&sem_ids.mutex);
 		return err;
 	default:
 		return -EINVAL;
@@ -1300,9 +1301,9 @@
 		/* perform adjustments registered in u */
 		nsems = sma->sem_nsems;
 		for (i = 0; i < nsems; i++) {
-			struct sem * sem = &sma->sem_base[i];
+			struct sem * semaphore = &sma->sem_base[i];
 			if (u->semadj[i]) {
-				sem->semval += u->semadj[i];
+				semaphore->semval += u->semadj[i];
 				/*
 				 * Range checks of the new semaphore value,
 				 * not defined by sus:
@@ -1316,11 +1317,11 @@
 				 *
 				 * 	Manfred <manfred@colorfullife.com>
 				 */
-				if (sem->semval < 0)
-					sem->semval = 0;
-				if (sem->semval > SEMVMX)
-					sem->semval = SEMVMX;
-				sem->sempid = current->tgid;
+				if (semaphore->semval < 0)
+					semaphore->semval = 0;
+				if (semaphore->semval > SEMVMX)
+					semaphore->semval = SEMVMX;
+				semaphore->sempid = current->tgid;
 			}
 		}
 		sma->sem_otime = get_seconds();
diff -urN oldtree/ipc/shm.c newtree/ipc/shm.c
--- oldtree/ipc/shm.c	2006-02-19 11:41:06.156407184 +0000
+++ newtree/ipc/shm.c	2006-02-21 15:58:29.823612680 +0000
@@ -30,6 +30,7 @@
 #include <linux/capability.h>
 #include <linux/ptrace.h>
 #include <linux/seq_file.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 
@@ -109,7 +110,7 @@
  *
  * @shp: struct to free
  *
- * It has to be called with shp and shm_ids.sem locked,
+ * It has to be called with shp and shm_ids.mutex locked,
  * but returns with shp unlocked and freed.
  */
 static void shm_destroy (struct shmid_kernel *shp)
@@ -139,7 +140,7 @@
 	int id = file->f_dentry->d_inode->i_ino;
 	struct shmid_kernel *shp;
 
-	down (&shm_ids.sem);
+	mutex_lock(&shm_ids.mutex);
 	/* remove from the list of attaches of the shm segment */
 	if(!(shp = shm_lock(id)))
 		BUG();
@@ -151,7 +152,7 @@
 		shm_destroy (shp);
 	else
 		shm_unlock(shp);
-	up (&shm_ids.sem);
+	mutex_unlock(&shm_ids.mutex);
 }
 
 static int shm_mmap(struct file * file, struct vm_area_struct * vma)
@@ -270,7 +271,7 @@
 	struct shmid_kernel *shp;
 	int err, id = 0;
 
-	down(&shm_ids.sem);
+	mutex_lock(&shm_ids.mutex);
 	if (key == IPC_PRIVATE) {
 		err = newseg(key, shmflg, size);
 	} else if ((id = ipc_findkey(&shm_ids, key)) == -1) {
@@ -296,7 +297,7 @@
 		}
 		shm_unlock(shp);
 	}
-	up(&shm_ids.sem);
+	mutex_unlock(&shm_ids.mutex);
 
 	return err;
 }
@@ -467,14 +468,14 @@
 			return err;
 
 		memset(&shm_info,0,sizeof(shm_info));
-		down(&shm_ids.sem);
+		mutex_lock(&shm_ids.mutex);
 		shm_info.used_ids = shm_ids.in_use;
 		shm_get_stat (&shm_info.shm_rss, &shm_info.shm_swp);
 		shm_info.shm_tot = shm_tot;
 		shm_info.swap_attempts = 0;
 		shm_info.swap_successes = 0;
 		err = shm_ids.max_id;
-		up(&shm_ids.sem);
+		mutex_unlock(&shm_ids.mutex);
 		if(copy_to_user (buf, &shm_info, sizeof(shm_info))) {
 			err = -EFAULT;
 			goto out;
@@ -583,7 +584,7 @@
 		 *	Instead we set a destroyed flag, and then blow
 		 *	the name away when the usage hits zero.
 		 */
-		down(&shm_ids.sem);
+		mutex_lock(&shm_ids.mutex);
 		shp = shm_lock(shmid);
 		err = -EINVAL;
 		if (shp == NULL) 
@@ -610,7 +611,7 @@
 			shm_unlock(shp);
 		} else
 			shm_destroy (shp);
-		up(&shm_ids.sem);
+		mutex_unlock(&shm_ids.mutex);
 		goto out;
 	}
 
@@ -620,13 +621,13 @@
 			err = -EFAULT;
 			goto out;
 		}
-		if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
-			return err;
-		down(&shm_ids.sem);
+		mutex_lock(&shm_ids.mutex);
 		shp = shm_lock(shmid);
 		err=-EINVAL;
 		if(shp==NULL)
 			goto out_up;
+		if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, &(shp->shm_perm))))
+			goto out_unlock_up;
 		err = shm_checkid(shp,shmid);
 		if(err)
 			goto out_unlock_up;
@@ -658,7 +659,7 @@
 out_unlock_up:
 	shm_unlock(shp);
 out_up:
-	up(&shm_ids.sem);
+	mutex_unlock(&shm_ids.mutex);
 	goto out;
 out_unlock:
 	shm_unlock(shp);
@@ -771,7 +772,7 @@
 invalid:
 	up_write(&current->mm->mmap_sem);
 
-	down (&shm_ids.sem);
+	mutex_lock(&shm_ids.mutex);
 	if(!(shp = shm_lock(shmid)))
 		BUG();
 	shp->shm_nattch--;
@@ -780,7 +781,7 @@
 		shm_destroy (shp);
 	else
 		shm_unlock(shp);
-	up (&shm_ids.sem);
+	mutex_unlock(&shm_ids.mutex);
 
 	*raddr = (unsigned long) user_addr;
 	err = 0;
@@ -814,6 +815,9 @@
 	loff_t size = 0;
 	int retval = -EINVAL;
 
+	if (addr & ~PAGE_MASK)
+		return retval;
+
 	down_write(&mm->mmap_sem);
 
 	/*
diff -urN oldtree/ipc/util.c newtree/ipc/util.c
--- oldtree/ipc/util.c	2006-02-19 11:41:06.156407184 +0000
+++ newtree/ipc/util.c	2006-02-21 15:58:26.117176144 +0000
@@ -27,6 +27,7 @@
 #include <linux/workqueue.h>
 #include <linux/seq_file.h>
 #include <linux/proc_fs.h>
+#include <linux/audit.h>
 
 #include <asm/unistd.h>
 
@@ -68,7 +69,8 @@
 void __init ipc_init_ids(struct ipc_ids* ids, int size)
 {
 	int i;
-	sema_init(&ids->sem,1);
+
+	mutex_init(&ids->mutex);
 
 	if(size > IPCMNI)
 		size = IPCMNI;
@@ -138,7 +140,7 @@
  *	@ids: Identifier set
  *	@key: The key to find
  *	
- *	Requires ipc_ids.sem locked.
+ *	Requires ipc_ids.mutex locked.
  *	Returns the identifier if found or -1 if not.
  */
  
@@ -150,7 +152,7 @@
 
 	/*
 	 * rcu_dereference() is not needed here
-	 * since ipc_ids.sem is held
+	 * since ipc_ids.mutex is held
 	 */
 	for (id = 0; id <= max_id; id++) {
 		p = ids->entries->p[id];
@@ -163,7 +165,7 @@
 }
 
 /*
- * Requires ipc_ids.sem locked
+ * Requires ipc_ids.mutex locked
  */
 static int grow_ary(struct ipc_ids* ids, int newsize)
 {
@@ -210,7 +212,7 @@
  *	is returned. The list is returned in a locked state on success.
  *	On failure the list is not locked and -1 is returned.
  *
- *	Called with ipc_ids.sem held.
+ *	Called with ipc_ids.mutex held.
  */
  
 int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
@@ -221,7 +223,7 @@
 
 	/*
 	 * rcu_dereference()() is not needed here since
-	 * ipc_ids.sem is held
+	 * ipc_ids.mutex is held
 	 */
 	for (id = 0; id < size; id++) {
 		if(ids->entries->p[id] == NULL)
@@ -257,7 +259,7 @@
  *	fed an invalid identifier. The entry is removed and internal
  *	variables recomputed. The object associated with the identifier
  *	is returned.
- *	ipc_ids.sem and the spinlock for this ID is hold before this function
+ *	ipc_ids.mutex and the spinlock for this ID is hold before this function
  *	is called, and remain locked on the exit.
  */
  
@@ -270,7 +272,7 @@
 
 	/* 
 	 * do not need a rcu_dereference()() here to force ordering
-	 * on Alpha, since the ipc_ids.sem is held.
+	 * on Alpha, since the ipc_ids.mutex is held.
 	 */	
 	p = ids->entries->p[lid];
 	ids->entries->p[lid] = NULL;
@@ -468,6 +470,7 @@
 {	/* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
 	int requested_mode, granted_mode;
 
+	audit_ipc_context(ipcp);
 	requested_mode = (flag >> 6) | (flag >> 3) | flag;
 	granted_mode = ipcp->mode;
 	if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
@@ -530,13 +533,13 @@
 
 /*
  * So far only shm_get_stat() calls ipc_get() via shm_get(), so ipc_get()
- * is called with shm_ids.sem locked.  Since grow_ary() is also called with
- * shm_ids.sem down(for Shared Memory), there is no need to add read 
+ * is called with shm_ids.mutex locked.  Since grow_ary() is also called with
+ * shm_ids.mutex down(for Shared Memory), there is no need to add read
  * barriers here to gurantee the writes in grow_ary() are seen in order 
  * here (for Alpha).
  *
- * However ipc_get() itself does not necessary require ipc_ids.sem down. So
- * if in the future ipc_get() is used by other places without ipc_ids.sem
+ * However ipc_get() itself does not necessary require ipc_ids.mutex down. So
+ * if in the future ipc_get() is used by other places without ipc_ids.mutex
  * down, then ipc_get() needs read memery barriers as ipc_lock() does.
  */
 struct kern_ipc_perm* ipc_get(struct ipc_ids* ids, int id)
@@ -667,7 +670,7 @@
 	 * Take the lock - this will be released by the corresponding
 	 * call to stop().
 	 */
-	down(&iface->ids->sem);
+	mutex_lock(&iface->ids->mutex);
 
 	/* pos < 0 is invalid */
 	if (*pos < 0)
@@ -697,7 +700,7 @@
 		ipc_unlock(ipc);
 
 	/* Release the lock we took in start() */
-	up(&iface->ids->sem);
+	mutex_unlock(&iface->ids->mutex);
 }
 
 static int sysvipc_proc_show(struct seq_file *s, void *it)
diff -urN oldtree/ipc/util.h newtree/ipc/util.h
--- oldtree/ipc/util.h	2006-02-19 11:41:06.157407032 +0000
+++ newtree/ipc/util.h	2006-02-21 15:58:26.118175992 +0000
@@ -25,7 +25,7 @@
 	int max_id;
 	unsigned short seq;
 	unsigned short seq_max;
-	struct semaphore sem;	
+	struct mutex mutex;
 	struct ipc_id_ary nullentry;
 	struct ipc_id_ary* entries;
 };
@@ -40,7 +40,7 @@
 #define ipc_init_proc_interface(path, header, ids, show) do {} while (0)
 #endif
 
-/* must be called with ids->sem acquired.*/
+/* must be called with ids->mutex acquired.*/
 int ipc_findkey(struct ipc_ids* ids, key_t key);
 int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size);
 
diff -urN oldtree/kernel/Makefile newtree/kernel/Makefile
--- oldtree/kernel/Makefile	2006-02-19 11:41:06.157407032 +0000
+++ newtree/kernel/Makefile	2006-02-21 15:58:31.992282992 +0000
@@ -26,7 +26,7 @@
 obj-$(CONFIG_CPUSETS) += cpuset.o
 obj-$(CONFIG_IKCONFIG) += configs.o
 obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
-obj-$(CONFIG_AUDIT) += audit.o
+obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
 obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
 obj-$(CONFIG_KPROBES) += kprobes.o
 obj-$(CONFIG_SYSFS) += ksysfs.o
@@ -34,6 +34,7 @@
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_SECCOMP) += seccomp.o
 obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
+obj-$(CONFIG_DEBUG_SYNCHRO_TEST) += synchro-test.o
 
 ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff -urN oldtree/kernel/audit.c newtree/kernel/audit.c
--- oldtree/kernel/audit.c	2006-02-19 11:41:06.159406728 +0000
+++ newtree/kernel/audit.c	2006-02-21 15:58:11.879340624 +0000
@@ -52,6 +52,7 @@
 #include <linux/audit.h>
 
 #include <net/sock.h>
+#include <net/netlink.h>
 #include <linux/skbuff.h>
 #include <linux/netlink.h>
 
@@ -72,7 +73,7 @@
  * contains the (non-zero) pid. */
 int		audit_pid;
 
-/* If audit_limit is non-zero, limit the rate of sending audit records
+/* If audit_rate_limit is non-zero, limit the rate of sending audit records
  * to that number per second.  This prevents DoS attacks, but results in
  * audit records being dropped. */
 static int	audit_rate_limit;
@@ -102,7 +103,7 @@
  * than AUDIT_MAXFREE are in use, the audit buffer is freed instead of
  * being placed on the freelist). */
 static DEFINE_SPINLOCK(audit_freelist_lock);
-static int	   audit_freelist_count = 0;
+static int	   audit_freelist_count;
 static LIST_HEAD(audit_freelist);
 
 static struct sk_buff_head audit_skb_queue;
@@ -113,7 +114,7 @@
 /* The netlink socket is only to be read by 1 CPU, which lets us assume
  * that list additions and deletions never happen simultaneously in
  * auditsc.c */
-DECLARE_MUTEX(audit_netlink_sem);
+DEFINE_MUTEX(audit_netlink_mutex);
 
 /* AUDIT_BUFSIZ is the size of the temporary buffer used for formatting
  * audit records.  Since printk uses a 1024 byte buffer, this buffer
@@ -142,7 +143,7 @@
 	nlh->nlmsg_pid = pid;
 }
 
-static void audit_panic(const char *message)
+void audit_panic(const char *message)
 {
 	switch (audit_failure)
 	{
@@ -186,8 +187,14 @@
 	return retval;
 }
 
-/* Emit at least 1 message per second, even if audit_rate_check is
- * throttling. */
+/**
+ * audit_log_lost - conditionally log lost audit message event
+ * @message: the message stating reason for lost audit message
+ *
+ * Emit at least 1 message per second, even if audit_rate_check is
+ * throttling.
+ * Always increment the lost messages counter.
+*/
 void audit_log_lost(const char *message)
 {
 	static unsigned long	last_msg = 0;
@@ -218,7 +225,6 @@
 		       audit_backlog_limit);
 		audit_panic(message);
 	}
-
 }
 
 static int audit_set_rate_limit(int limit, uid_t loginuid)
@@ -300,8 +306,22 @@
 			remove_wait_queue(&kauditd_wait, &wait);
 		}
 	}
+	return 0;
 }
 
+/**
+ * audit_send_reply - send an audit reply message via netlink
+ * @pid: process id to send reply to
+ * @seq: sequence number
+ * @type: audit message type
+ * @done: done (last) flag
+ * @multi: multi-part message flag
+ * @payload: payload data
+ * @size: payload size
+ *
+ * Allocates an skb, builds the netlink message, and sends it to the pid.
+ * No failure notifications.
+ */
 void audit_send_reply(int pid, int seq, int type, int done, int multi,
 		      void *payload, int size)
 {
@@ -342,15 +362,19 @@
 	switch (msg_type) {
 	case AUDIT_GET:
 	case AUDIT_LIST:
+	case AUDIT_LIST_RULES:
 	case AUDIT_SET:
 	case AUDIT_ADD:
+	case AUDIT_ADD_RULE:
 	case AUDIT_DEL:
+	case AUDIT_DEL_RULE:
 	case AUDIT_SIGNAL_INFO:
 		if (!cap_raised(eff_cap, CAP_AUDIT_CONTROL))
 			err = -EPERM;
 		break;
 	case AUDIT_USER:
 	case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
+	case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2:
 		if (!cap_raised(eff_cap, CAP_AUDIT_WRITE))
 			err = -EPERM;
 		break;
@@ -376,7 +400,8 @@
 	if (err)
 		return err;
 
-	/* As soon as there's any sign of userspace auditd, start kauditd to talk to it */
+	/* As soon as there's any sign of userspace auditd,
+	 * start kauditd to talk to it */
 	if (!kauditd_task)
 		kauditd_task = kthread_run(kauditd_thread, NULL, "kauditd");
 	if (IS_ERR(kauditd_task)) {
@@ -430,6 +455,7 @@
 		break;
 	case AUDIT_USER:
 	case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
+	case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2:
 		if (!audit_enabled && msg_type != AUDIT_USER_AVC)
 			return 0;
 
@@ -448,12 +474,23 @@
 		break;
 	case AUDIT_ADD:
 	case AUDIT_DEL:
-		if (nlh->nlmsg_len < sizeof(struct audit_rule))
+		if (nlmsg_len(nlh) < sizeof(struct audit_rule))
 			return -EINVAL;
 		/* fallthrough */
 	case AUDIT_LIST:
 		err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
-					   uid, seq, data, loginuid);
+					   uid, seq, data, nlmsg_len(nlh),
+					   loginuid);
+		break;
+	case AUDIT_ADD_RULE:
+	case AUDIT_DEL_RULE:
+		if (nlmsg_len(nlh) < sizeof(struct audit_rule_data))
+			return -EINVAL;
+		/* fallthrough */
+	case AUDIT_LIST_RULES:
+		err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
+					   uid, seq, data, nlmsg_len(nlh),
+					   loginuid);
 		break;
 	case AUDIT_SIGNAL_INFO:
 		sig_data.uid = audit_sig_uid;
@@ -469,9 +506,11 @@
 	return err < 0 ? err : 0;
 }
 
-/* Get message from skb (based on rtnetlink_rcv_skb).  Each message is
+/*
+ * Get message from skb (based on rtnetlink_rcv_skb).  Each message is
  * processed by audit_receive_msg.  Malformed skbs with wrong length are
- * discarded silently.  */
+ * discarded silently.
+ */
 static void audit_receive_skb(struct sk_buff *skb)
 {
 	int		err;
@@ -499,14 +538,14 @@
 	struct sk_buff  *skb;
 	unsigned int qlen;
 
-	down(&audit_netlink_sem);
+	mutex_lock(&audit_netlink_mutex);
 
 	for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) {
 		skb = skb_dequeue(&sk->sk_receive_queue);
 		audit_receive_skb(skb);
 		kfree_skb(skb);
 	}
-	up(&audit_netlink_sem);
+	mutex_unlock(&audit_netlink_mutex);
 }
 
 
@@ -600,7 +639,10 @@
 	return NULL;
 }
 
-/* Compute a serial number for the audit record.  Audit records are
+/**
+ * audit_serial - compute a serial number for the audit record
+ *
+ * Compute a serial number for the audit record.  Audit records are
  * written to user-space as soon as they are generated, so a complete
  * audit record may be written in several pieces.  The timestamp of the
  * record and this serial number are used by the user-space tools to
@@ -612,8 +654,8 @@
  * audit context (for those records that have a context), and emit them
  * all at syscall exit.  However, this could delay the reporting of
  * significant errors until syscall exit (or never, if the system
- * halts). */
-
+ * halts).
+ */
 unsigned int audit_serial(void)
 {
 	static spinlock_t serial_lock = SPIN_LOCK_UNLOCKED;
@@ -649,6 +691,21 @@
  * will be written at syscall exit.  If there is no associated task, tsk
  * should be NULL. */
 
+/**
+ * audit_log_start - obtain an audit buffer
+ * @ctx: audit_context (may be NULL)
+ * @gfp_mask: type of allocation
+ * @type: audit message type
+ *
+ * Returns audit_buffer pointer on success or NULL on error.
+ *
+ * Obtain an audit buffer.  This routine does locking to obtain the
+ * audit buffer, but then no locking is required for calls to
+ * audit_log_*format.  If the task (ctx) is a task that is currently in a
+ * syscall, then the syscall is marked as auditable and an audit record
+ * will be written at syscall exit.  If there is no associated task, then
+ * task context (ctx) should be NULL.
+ */
 struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
 				     int type)
 {
@@ -661,6 +718,9 @@
 	if (!audit_initialized)
 		return NULL;
 
+	if (unlikely(audit_filter_type(type)))
+		return NULL;
+
 	if (gfp_mask & __GFP_WAIT)
 		reserve = 0;
 	else
@@ -713,6 +773,7 @@
 /**
  * audit_expand - expand skb in the audit buffer
  * @ab: audit_buffer
+ * @extra: space to add at tail of the skb
  *
  * Returns 0 (no space) on failed expansion, or available space if
  * successful.
@@ -729,10 +790,12 @@
 	return skb_tailroom(skb);
 }
 
-/* Format an audit message into the audit buffer.  If there isn't enough
+/*
+ * Format an audit message into the audit buffer.  If there isn't enough
  * room in the audit buffer, more room will be allocated and vsnprint
  * will be called a second time.  Currently, we assume that a printk
- * can't format message larger than 1024 bytes, so we don't either. */
+ * can't format message larger than 1024 bytes, so we don't either.
+ */
 static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
 			      va_list args)
 {
@@ -757,7 +820,8 @@
 		/* The printk buffer is 1024 bytes long, so if we get
 		 * here and AUDIT_BUFSIZ is at least 1024, then we can
 		 * log everything that printk could have logged. */
-		avail = audit_expand(ab, max_t(unsigned, AUDIT_BUFSIZ, 1+len-avail));
+		avail = audit_expand(ab,
+			max_t(unsigned, AUDIT_BUFSIZ, 1+len-avail));
 		if (!avail)
 			goto out;
 		len = vsnprintf(skb->tail, avail, fmt, args2);
@@ -768,8 +832,14 @@
 	return;
 }
 
-/* Format a message into the audit buffer.  All the work is done in
- * audit_log_vformat. */
+/**
+ * audit_log_format - format a message into the audit buffer.
+ * @ab: audit_buffer
+ * @fmt: format string
+ * @...: optional parameters matching @fmt string
+ *
+ * All the work is done in audit_log_vformat.
+ */
 void audit_log_format(struct audit_buffer *ab, const char *fmt, ...)
 {
 	va_list args;
@@ -781,9 +851,18 @@
 	va_end(args);
 }
 
-/* This function will take the passed buf and convert it into a string of
- * ascii hex digits. The new string is placed onto the skb. */
-void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf, 
+/**
+ * audit_log_hex - convert a buffer to hex and append it to the audit skb
+ * @ab: the audit_buffer
+ * @buf: buffer to convert to hex
+ * @len: length of @buf to be converted
+ *
+ * No return value; failure to expand is silently ignored.
+ *
+ * This function will take the passed buf and convert it into a string of
+ * ascii hex digits. The new string is placed onto the skb.
+ */
+void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf,
 		size_t len)
 {
 	int i, avail, new_len;
@@ -812,10 +891,16 @@
 	skb_put(skb, len << 1); /* new string is twice the old string */
 }
 
-/* This code will escape a string that is passed to it if the string
- * contains a control character, unprintable character, double quote mark, 
+/**
+ * audit_log_unstrustedstring - log a string that may contain random characters
+ * @ab: audit_buffer
+ * @string: string to be logged
+ *
+ * This code will escape a string that is passed to it if the string
+ * contains a control character, unprintable character, double quote mark,
  * or a space. Unescaped strings will start and end with a double quote mark.
- * Strings that are escaped are printed in hex (2 digits per char). */
+ * Strings that are escaped are printed in hex (2 digits per char).
+ */
 void audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
 {
 	const unsigned char *p = string;
@@ -854,10 +939,15 @@
 	kfree(path);
 }
 
-/* The netlink_* functions cannot be called inside an irq context, so
- * the audit buffer is places on a queue and a tasklet is scheduled to
+/**
+ * audit_log_end - end one audit record
+ * @ab: the audit_buffer
+ *
+ * The netlink_* functions cannot be called inside an irq context, so
+ * the audit buffer is placed on a queue and a tasklet is scheduled to
  * remove them from the queue outside the irq context.  May be called in
- * any context. */
+ * any context.
+ */
 void audit_log_end(struct audit_buffer *ab)
 {
 	if (!ab)
@@ -878,9 +968,18 @@
 	audit_buffer_free(ab);
 }
 
-/* Log an audit record.  This is a convenience function that calls
- * audit_log_start, audit_log_vformat, and audit_log_end.  It may be
- * called in any context. */
+/**
+ * audit_log - Log an audit record
+ * @ctx: audit context
+ * @gfp_mask: type of allocation
+ * @type: audit message type
+ * @fmt: format string to use
+ * @...: variable parameters matching the format string
+ *
+ * This is a convenience function that calls audit_log_start,
+ * audit_log_vformat, and audit_log_end.  It may be called
+ * in any context.
+ */
 void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type, 
 	       const char *fmt, ...)
 {
diff -urN oldtree/kernel/audit.h newtree/kernel/audit.h
--- oldtree/kernel/audit.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/kernel/audit.h	2006-02-21 15:58:11.880340472 +0000
@@ -0,0 +1,96 @@
+/* audit -- definition of audit_context structure and supporting types 
+ *
+ * Copyright 2003-2004 Red Hat, Inc.
+ * Copyright 2005 Hewlett-Packard Development Company, L.P.
+ * Copyright 2005 IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/mutex.h>
+#include <linux/fs.h>
+#include <linux/audit.h>
+
+/* 0 = no checking
+   1 = put_count checking
+   2 = verbose put_count checking
+*/
+#define AUDIT_DEBUG 0
+
+/* At task start time, the audit_state is set in the audit_context using
+   a per-task filter.  At syscall entry, the audit_state is augmented by
+   the syscall filter. */
+enum audit_state {
+	AUDIT_DISABLED,		/* Do not create per-task audit_context.
+				 * No syscall-specific audit records can
+				 * be generated. */
+	AUDIT_SETUP_CONTEXT,	/* Create the per-task audit_context,
+				 * but don't necessarily fill it in at
+				 * syscall entry time (i.e., filter
+				 * instead). */
+	AUDIT_BUILD_CONTEXT,	/* Create the per-task audit_context,
+				 * and always fill it in at syscall
+				 * entry time.  This makes a full
+				 * syscall record available if some
+				 * other part of the kernel decides it
+				 * should be recorded. */
+	AUDIT_RECORD_CONTEXT	/* Create the per-task audit_context,
+				 * always fill it in at syscall entry
+				 * time, and always write out the audit
+				 * record at syscall exit time.  */
+};
+
+/* Rule lists */
+struct audit_watch {
+	char			*path;	 /* watch insertion path */
+	struct list_head	mlist;	 /* entry in master_watchlist */
+	struct list_head	rules;	 /* associated rules */
+};
+
+struct audit_field {
+	u32			type;
+	u32			val;
+	u32			op;
+};
+
+struct audit_krule {
+	int			vers_ops;
+	u32			flags;
+	u32			listnr;
+	u32			action;
+	u32			mask[AUDIT_BITMASK_SIZE];
+	u32			buflen; /* for data alloc on list rules */
+	u32			field_count;
+	struct audit_field	*fields;
+	struct audit_watch	*watch;	 /* associated watch */
+	struct list_head	rlist;	 /* entry in audit_watch.rules list */
+};
+
+struct audit_entry {
+	struct list_head	list;
+	struct rcu_head		rcu;
+	struct audit_krule	rule;
+};
+
+
+extern int audit_pid;
+extern int audit_comparator(const u32 left, const u32 op, const u32 right);
+
+extern void		    audit_send_reply(int pid, int seq, int type,
+					     int done, int multi,
+					     void *payload, int size);
+extern void		    audit_log_lost(const char *message);
+extern void		    audit_panic(const char *message);
+extern struct mutex audit_netlink_mutex;
diff -urN oldtree/kernel/auditfilter.c newtree/kernel/auditfilter.c
--- oldtree/kernel/auditfilter.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/kernel/auditfilter.c	2006-02-21 15:58:11.879340624 +0000
@@ -0,0 +1,728 @@
+/* auditfilter.c -- filtering of audit events
+ *
+ * Copyright 2003-2004 Red Hat, Inc.
+ * Copyright 2005 Hewlett-Packard Development Company, L.P.
+ * Copyright 2005 IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/audit.h>
+#include <linux/kthread.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/netlink.h>
+#include "audit.h"
+
+/* There are three lists of rules -- one to search at task creation
+ * time, one to search at syscall entry time, and another to search at
+ * syscall exit time. */
+struct list_head audit_filter_list[AUDIT_NR_FILTERS] = {
+	LIST_HEAD_INIT(audit_filter_list[0]),
+	LIST_HEAD_INIT(audit_filter_list[1]),
+	LIST_HEAD_INIT(audit_filter_list[2]),
+	LIST_HEAD_INIT(audit_filter_list[3]),
+	LIST_HEAD_INIT(audit_filter_list[4]),
+	LIST_HEAD_INIT(audit_filter_list[5]),
+#if AUDIT_NR_FILTERS != 6
+#error Fix audit_filter_list initialiser
+#endif
+};
+
+static inline void audit_free_watch(struct audit_watch *watch)
+{
+	kfree(watch->path);
+	kfree(watch);
+}
+
+static inline void audit_free_rule(struct audit_entry *e)
+{
+	kfree(e->rule.fields);
+	kfree(e);
+}
+
+static inline void audit_free_rule_rcu(struct rcu_head *head)
+{
+	struct audit_entry *e = container_of(head, struct audit_entry, rcu);
+	audit_free_rule(e);
+}
+
+static LIST_HEAD(master_watchlist);
+
+/* Unpack a filter field's string representation from user-space
+ * buffer. */
+static char *audit_unpack_string(void **bufp, size_t *remain, size_t len)
+{
+	char *str;
+
+	if (!*bufp || (len == 0) || (len > *remain))
+		return ERR_PTR(-EINVAL);
+
+	/* Of the currently implemented string fields, PATH_MAX
+	 * defines the longest valid length.
+	 */
+	if (len > PATH_MAX)
+		return ERR_PTR(-ENAMETOOLONG);
+
+	str = kmalloc(len + 1, GFP_KERNEL);
+	if (unlikely(!str))
+		return ERR_PTR(-ENOMEM);
+
+	memcpy(str, *bufp, len);
+	str[len] = 0;
+	*bufp += len;
+	*remain -= len;
+
+	return str;
+}
+
+/* Translate a watch string to kernel respresentation. */
+static int audit_to_watch(char *path, struct audit_krule *krule, int fidx)
+{
+	struct audit_field *f = &krule->fields[fidx];
+	struct nameidata nd;
+	struct audit_watch *watch;
+
+	if (path[0] != '/' || path[f->val-1] == '/' ||
+	    krule->listnr != AUDIT_FILTER_EXIT ||
+	    f->op & ~AUDIT_EQUAL)
+		return -EINVAL;
+
+	if (path_lookup(path, 0, &nd) == 0)
+		f->val = nd.dentry->d_inode->i_ino;
+	else
+		f->val = (unsigned int)-1;
+	path_release(&nd);
+
+	watch = kmalloc(sizeof(*watch), GFP_KERNEL);
+	if (unlikely(!watch))
+		return -ENOMEM;
+	watch->path = path;
+	krule->watch = watch;
+
+	return 0;
+}
+
+/* Common user-space to kernel rule translation. */
+static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule)
+{
+	unsigned listnr;
+	struct audit_entry *entry;
+	struct audit_field *fields;
+	int i, err;
+
+	err = -EINVAL;
+	listnr = rule->flags & ~AUDIT_FILTER_PREPEND;
+	switch(listnr) {
+	default:
+		goto exit_err;
+	case AUDIT_FILTER_USER:
+	case AUDIT_FILTER_TYPE:
+#ifdef CONFIG_AUDITSYSCALL
+	case AUDIT_FILTER_ENTRY:
+	case AUDIT_FILTER_EXIT:
+	case AUDIT_FILTER_TASK:
+#endif
+		;
+	}
+	if (rule->action != AUDIT_NEVER && rule->action != AUDIT_POSSIBLE &&
+	    rule->action != AUDIT_ALWAYS)
+		goto exit_err;
+	if (rule->field_count > AUDIT_MAX_FIELDS)
+		goto exit_err;
+
+	err = -ENOMEM;
+	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+	if (unlikely(!entry))
+		goto exit_err;
+	fields = kmalloc(sizeof(*fields) * rule->field_count, GFP_KERNEL);
+	if (unlikely(!fields)) {
+		kfree(entry);
+		goto exit_err;
+	}
+
+	memset(&entry->rule, 0, sizeof(struct audit_krule));
+	memset(fields, 0, sizeof(struct audit_field));
+
+	entry->rule.flags = rule->flags & AUDIT_FILTER_PREPEND;
+	entry->rule.listnr = listnr;
+	entry->rule.action = rule->action;
+	entry->rule.field_count = rule->field_count;
+	entry->rule.fields = fields;
+
+	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
+		entry->rule.mask[i] = rule->mask[i];
+
+	return entry;
+
+exit_err:
+	return ERR_PTR(err);
+}
+
+/* Translate struct audit_rule to kernel's rule respresentation.
+ * Exists for backward compatibility with userspace. */
+static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
+{
+	struct audit_entry *entry;
+	int err = 0;
+	int i;
+
+	entry = audit_to_entry_common(rule);
+	if (IS_ERR(entry))
+		goto exit_nofree;
+
+	for (i = 0; i < rule->field_count; i++) {
+		struct audit_field *f = &entry->rule.fields[i];
+
+		f->op = rule->fields[i] & (AUDIT_NEGATE|AUDIT_OPERATORS);
+		f->type = rule->fields[i] & ~(AUDIT_NEGATE|AUDIT_OPERATORS);
+		f->val = rule->values[i];
+
+		if (f->type & AUDIT_UNUSED_BITS ||
+		    f->type == AUDIT_WATCH) {
+			err = -EINVAL;
+			goto exit_free;
+		}
+
+		entry->rule.vers_ops = (f->op & AUDIT_OPERATORS) ? 2 : 1;
+		if (f->op & AUDIT_NEGATE)
+			f->op |= AUDIT_NOT_EQUAL;
+		else if (!(f->op & AUDIT_OPERATORS))
+			f->op |= AUDIT_EQUAL;
+		f->op &= ~AUDIT_NEGATE;
+	}
+
+exit_nofree:
+	return entry;
+
+exit_free:
+	audit_free_rule(entry);
+	return ERR_PTR(err);
+}
+
+/* Translate struct audit_rule_data to kernel's rule respresentation. */
+static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
+					       size_t datasz)
+{
+	int err = 0;
+	struct audit_entry *entry;
+	void *bufp;
+	size_t remain = datasz - sizeof(struct audit_rule_data);
+	int i;
+	char *path;
+
+	entry = audit_to_entry_common((struct audit_rule *)data);
+	if (IS_ERR(entry))
+		goto exit_nofree;
+
+	bufp = data->buf;
+	entry->rule.vers_ops = 2;
+	for (i = 0; i < data->field_count; i++) {
+		struct audit_field *f = &entry->rule.fields[i];
+
+		err = -EINVAL;
+		if (!(data->fieldflags[i] & AUDIT_OPERATORS) ||
+		    data->fieldflags[i] & ~AUDIT_OPERATORS)
+			goto exit_free;
+
+		f->op = data->fieldflags[i] & AUDIT_OPERATORS;
+		f->type = data->fields[i];
+		f->val = data->values[i];
+		switch(f->type) {
+		case AUDIT_WATCH:
+			path = audit_unpack_string(&bufp, &remain, f->val);
+			if (IS_ERR(path))
+				goto exit_free;
+			entry->rule.buflen += f->val;
+
+			err = audit_to_watch(path, &entry->rule, i);
+			if (err) {
+				kfree(path);
+				goto exit_free;
+			}
+			break;
+		}
+	}
+
+exit_nofree:
+	return entry;
+
+exit_free:
+	audit_free_rule(entry);
+	return ERR_PTR(err);
+}
+
+/* Pack a filter field's string representation into data block. */
+static inline size_t audit_pack_string(void **bufp, char *str)
+{
+	size_t len = strlen(str);
+
+	memcpy(*bufp, str, len);
+	*bufp += len;
+
+	return len;
+}
+
+/* Translate kernel rule respresentation to struct audit_rule.
+ * Exists for backward compatibility with userspace. */
+static struct audit_rule *audit_krule_to_rule(struct audit_krule *krule)
+{
+	struct audit_rule *rule;
+	int i;
+
+	rule = kmalloc(sizeof(*rule), GFP_KERNEL);
+	if (unlikely(!rule))
+		return ERR_PTR(-ENOMEM);
+	memset(rule, 0, sizeof(*rule));
+
+	rule->flags = krule->flags | krule->listnr;
+	rule->action = krule->action;
+	rule->field_count = krule->field_count;
+	for (i = 0; i < rule->field_count; i++) {
+		rule->values[i] = krule->fields[i].val;
+		rule->fields[i] = krule->fields[i].type;
+
+		if (krule->vers_ops == 1) {
+			if (krule->fields[i].op & AUDIT_NOT_EQUAL)
+				rule->fields[i] |= AUDIT_NEGATE;
+		} else {
+			rule->fields[i] |= krule->fields[i].op;
+		}
+	}
+	for (i = 0; i < AUDIT_BITMASK_SIZE; i++) rule->mask[i] = krule->mask[i];
+
+	return rule;
+}
+
+/* Translate kernel rule respresentation to struct audit_rule_data. */
+static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
+{
+	struct audit_rule_data *data;
+	void *bufp;
+	int i;
+
+	data = kmalloc(sizeof(*data) + krule->buflen, GFP_KERNEL);
+	if (unlikely(!data))
+		return ERR_PTR(-ENOMEM);
+	memset(data, 0, sizeof(*data));
+
+	data->flags = krule->flags | krule->listnr;
+	data->action = krule->action;
+	data->field_count = krule->field_count;
+	bufp = data->buf;
+	for (i = 0; i < data->field_count; i++) {
+		struct audit_field *f = &krule->fields[i];
+
+		data->fields[i] = f->type;
+		data->fieldflags[i] = f->op;
+		switch(f->type) {
+		case AUDIT_WATCH:
+			data->buflen += data->values[i] =
+				audit_pack_string(&bufp, krule->watch->path);
+			break;
+		default:
+			data->values[i] = f->val;
+		}
+	}
+	for (i = 0; i < AUDIT_BITMASK_SIZE; i++) data->mask[i] = krule->mask[i];
+
+	return data;
+}
+
+/* Compare two watches.  Considered success if rules don't match. */
+static inline int audit_compare_watch(struct audit_watch *a, struct audit_watch *b)
+{
+	return strcmp(a->path, b->path);
+}
+
+/* Compare two rules in kernel format.  Considered success if rules
+ * don't match. */
+static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
+{
+	int i;
+
+	if (a->flags != b->flags ||
+	    a->listnr != b->listnr ||
+	    a->action != b->action ||
+	    a->field_count != b->field_count)
+		return 1;
+
+	for (i = 0; i < a->field_count; i++) {
+		if (a->fields[i].type != b->fields[i].type ||
+		    a->fields[i].op != b->fields[i].op)
+			return 1;
+
+		switch(a->fields[i].type) {
+		case AUDIT_WATCH:
+			if (audit_compare_watch(a->watch, b->watch))
+				return 1;
+			break;
+		default:
+			if (a->fields[i].val != b->fields[i].val)
+				return 1;
+		}
+	}
+
+	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
+		if (a->mask[i] != b->mask[i])
+			return 1;
+
+	return 0;
+}
+
+/* Attach krule's watch to master_watchlist, using existing watches
+ * when possible. */
+static inline void audit_add_watch(struct audit_krule *krule)
+{
+	struct audit_watch *w;
+
+	list_for_each_entry(w, &master_watchlist, mlist) {
+		if (audit_compare_watch(w, krule->watch))
+			continue;
+
+		audit_free_watch(krule->watch);
+		krule->watch = w;
+		list_add(&krule->rlist, &w->rules);
+		return;
+	}
+	INIT_LIST_HEAD(&krule->watch->rules);
+	list_add(&krule->rlist, &krule->watch->rules);
+	list_add(&krule->watch->mlist, &master_watchlist);
+}
+
+/* Add rule to given filterlist if not a duplicate.  Protected by
+ * audit_netlink_mutex. */
+static inline int audit_add_rule(struct audit_entry *entry,
+				  struct list_head *list)
+{
+	struct audit_entry *e;
+
+	/* Do not use the _rcu iterator here, since this is the only
+	 * addition routine. */
+	list_for_each_entry(e, list, list) {
+		if (!audit_compare_rule(&entry->rule, &e->rule))
+			return -EEXIST;
+	}
+
+	if (entry->rule.watch)
+		audit_add_watch(&entry->rule);
+	if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
+		list_add_rcu(&entry->list, list);
+	} else {
+		list_add_tail_rcu(&entry->list, list);
+	}
+
+	return 0;
+}
+
+/* Detach watch from krule, freeing if it has no associated rules. */
+static inline void audit_detach_watch(struct audit_krule *krule)
+{
+	struct audit_watch *watch = krule->watch;
+
+	list_del(&krule->rlist);
+	krule->watch = NULL;
+
+	if (list_empty(&watch->rules)) {
+		list_del(&watch->mlist);
+		audit_free_watch(watch);
+	}
+}
+
+/* Remove an existing rule from filterlist.  Protected by
+ * audit_netlink_mutex. */
+static inline int audit_del_rule(struct audit_entry *entry,
+				 struct list_head *list)
+{
+	struct audit_entry  *e;
+
+	/* Do not use the _rcu iterator here, since this is the only
+	 * deletion routine. */
+	list_for_each_entry(e, list, list) {
+		if (!audit_compare_rule(&entry->rule, &e->rule)) {
+			list_del_rcu(&e->list);
+			if (e->rule.watch)
+				audit_detach_watch(&e->rule);
+			call_rcu(&e->rcu, audit_free_rule_rcu);
+			return 0;
+		}
+	}
+	return -ENOENT;		/* No matching rule */
+}
+
+/* List rules using struct audit_rule.  Exists for backward
+ * compatibility with userspace. */
+static int audit_list(void *_dest)
+{
+	int pid, seq;
+	int *dest = _dest;
+	struct audit_entry *entry;
+	int i;
+
+	pid = dest[0];
+	seq = dest[1];
+	kfree(dest);
+
+	mutex_lock(&audit_netlink_mutex);
+
+	/* The *_rcu iterators not needed here because we are
+	   always called with audit_netlink_mutex held. */
+	for (i=0; i<AUDIT_NR_FILTERS; i++) {
+		list_for_each_entry(entry, &audit_filter_list[i], list) {
+			struct audit_rule *rule;
+
+			rule = audit_krule_to_rule(&entry->rule);
+			if (unlikely(!rule))
+				break;
+			audit_send_reply(pid, seq, AUDIT_LIST, 0, 1,
+					 rule, sizeof(*rule));
+			kfree(rule);
+		}
+	}
+	audit_send_reply(pid, seq, AUDIT_LIST, 1, 1, NULL, 0);
+	
+	mutex_unlock(&audit_netlink_mutex);
+	return 0;
+}
+
+/* List rules using struct audit_rule_data. */
+static int audit_list_rules(void *_dest)
+{
+	int pid, seq;
+	int *dest = _dest;
+	struct audit_entry *e;
+	int i;
+
+	pid = dest[0];
+	seq = dest[1];
+	kfree(dest);
+
+	mutex_lock(&audit_netlink_mutex);
+
+	/* The *_rcu iterators not needed here because we are
+	   always called with audit_netlink_mutex held. */
+	for (i=0; i<AUDIT_NR_FILTERS; i++) {
+		list_for_each_entry(e, &audit_filter_list[i], list) {
+			struct audit_rule_data *data;
+
+			data = audit_krule_to_data(&e->rule);
+			if (unlikely(!data))
+				break;
+			audit_send_reply(pid, seq, AUDIT_LIST_RULES, 0, 1,
+					 data, sizeof(*data) + data->buflen);
+			kfree(data);
+		}
+	}
+	audit_send_reply(pid, seq, AUDIT_LIST_RULES, 1, 1, NULL, 0);
+
+	mutex_unlock(&audit_netlink_mutex);
+	return 0;
+}
+
+/**
+ * audit_receive_filter - apply all rules to the specified message type
+ * @type: audit message type
+ * @pid: target pid for netlink audit messages
+ * @uid: target uid for netlink audit messages
+ * @seq: netlink audit message sequence (serial) number
+ * @data: payload data
+ * @datasz: size of payload data
+ * @loginuid: loginuid of sender
+ */
+int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
+			 size_t datasz, uid_t loginuid)
+{
+	struct task_struct *tsk;
+	int *dest;
+	int err = 0;
+	struct audit_entry *entry;
+
+	switch (type) {
+	case AUDIT_LIST:
+	case AUDIT_LIST_RULES:
+		/* We can't just spew out the rules here because we might fill
+		 * the available socket buffer space and deadlock waiting for
+		 * auditctl to read from it... which isn't ever going to
+		 * happen if we're actually running in the context of auditctl
+		 * trying to _send_ the stuff */
+		 
+		dest = kmalloc(2 * sizeof(int), GFP_KERNEL);
+		if (!dest)
+			return -ENOMEM;
+		dest[0] = pid;
+		dest[1] = seq;
+
+		if (type == AUDIT_LIST)
+			tsk = kthread_run(audit_list, dest, "audit_list");
+		else
+			tsk = kthread_run(audit_list_rules, dest,
+					  "audit_list_rules");
+		if (IS_ERR(tsk)) {
+			kfree(dest);
+			err = PTR_ERR(tsk);
+		}
+		break;
+	case AUDIT_ADD:
+	case AUDIT_ADD_RULE:
+		if (type == AUDIT_ADD)
+			entry = audit_rule_to_entry(data);
+		else
+			entry = audit_data_to_entry(data, datasz);
+		if (IS_ERR(entry))
+			return PTR_ERR(entry);
+
+		err = audit_add_rule(entry,
+				     &audit_filter_list[entry->rule.listnr]);
+		audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+			"auid=%u add rule to list=%d res=%d\n",
+			loginuid, entry->rule.listnr, !err);
+
+		if (err) {
+			if (entry->rule.watch)
+				audit_free_watch(entry->rule.watch);
+			audit_free_rule(entry);
+		}
+		break;
+	case AUDIT_DEL:
+	case AUDIT_DEL_RULE:
+		if (type == AUDIT_DEL)
+			entry = audit_rule_to_entry(data);
+		else
+			entry = audit_data_to_entry(data, datasz);
+		if (IS_ERR(entry))
+			return PTR_ERR(entry);
+
+		err = audit_del_rule(entry,
+				     &audit_filter_list[entry->rule.listnr]);
+		audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+			"auid=%u remove rule from list=%d res=%d\n",
+			loginuid, entry->rule.listnr, !err);
+
+		if (entry->rule.watch)
+			audit_free_watch(entry->rule.watch);
+		audit_free_rule(entry);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return err;
+}
+
+int audit_comparator(const u32 left, const u32 op, const u32 right)
+{
+	switch (op) {
+	case AUDIT_EQUAL:
+		return (left == right);
+	case AUDIT_NOT_EQUAL:
+		return (left != right);
+	case AUDIT_LESS_THAN:
+		return (left < right);
+	case AUDIT_LESS_THAN_OR_EQUAL:
+		return (left <= right);
+	case AUDIT_GREATER_THAN:
+		return (left > right);
+	case AUDIT_GREATER_THAN_OR_EQUAL:
+		return (left >= right);
+	default:
+		return -EINVAL;
+	}
+}
+
+
+
+static int audit_filter_user_rules(struct netlink_skb_parms *cb,
+				   struct audit_krule *rule,
+				   enum audit_state *state)
+{
+	int i;
+
+	for (i = 0; i < rule->field_count; i++) {
+		struct audit_field *f = &rule->fields[i];
+		int result = 0;
+
+		switch (f->type) {
+		case AUDIT_PID:
+			result = audit_comparator(cb->creds.pid, f->op, f->val);
+			break;
+		case AUDIT_UID:
+			result = audit_comparator(cb->creds.uid, f->op, f->val);
+			break;
+		case AUDIT_GID:
+			result = audit_comparator(cb->creds.gid, f->op, f->val);
+			break;
+		case AUDIT_LOGINUID:
+			result = audit_comparator(cb->loginuid, f->op, f->val);
+			break;
+		}
+
+		if (!result)
+			return 0;
+	}
+	switch (rule->action) {
+	case AUDIT_NEVER:    *state = AUDIT_DISABLED;	    break;
+	case AUDIT_POSSIBLE: *state = AUDIT_BUILD_CONTEXT;  break;
+	case AUDIT_ALWAYS:   *state = AUDIT_RECORD_CONTEXT; break;
+	}
+	return 1;
+}
+
+int audit_filter_user(struct netlink_skb_parms *cb, int type)
+{
+	struct audit_entry *e;
+	enum audit_state   state;
+	int ret = 1;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) {
+		if (audit_filter_user_rules(cb, &e->rule, &state)) {
+			if (state == AUDIT_DISABLED)
+				ret = 0;
+			break;
+		}
+	}
+	rcu_read_unlock();
+
+	return ret; /* Audit by default */
+}
+
+int audit_filter_type(int type)
+{
+	struct audit_entry *e;
+	int result = 0;
+	
+	rcu_read_lock();
+	if (list_empty(&audit_filter_list[AUDIT_FILTER_TYPE]))
+		goto unlock_and_return;
+
+	list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TYPE],
+				list) {
+		int i;
+		for (i = 0; i < e->rule.field_count; i++) {
+			struct audit_field *f = &e->rule.fields[i];
+			if (f->type == AUDIT_MSGTYPE) {
+				result = audit_comparator(type, f->op, f->val);
+				if (!result)
+					break;
+			}
+		}
+		if (result)
+			goto unlock_and_return;
+	}
+unlock_and_return:
+	rcu_read_unlock();
+	return result;
+}
diff -urN oldtree/kernel/auditsc.c newtree/kernel/auditsc.c
--- oldtree/kernel/auditsc.c	2006-02-19 11:41:06.159406728 +0000
+++ newtree/kernel/auditsc.c	2006-02-21 15:58:17.561476808 +0000
@@ -2,6 +2,8 @@
  * Handles all system-call specific auditing features.
  *
  * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
+ * Copyright 2005 Hewlett-Packard Development Company, L.P.
+ * Copyright (C) 2005 IBM Corporation
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -27,11 +29,22 @@
  * this file -- see entry.S) is based on a GPL'd patch written by
  * okir@suse.de and Copyright 2003 SuSE Linux AG.
  *
+ * The support of additional filter rules compares (>, <, >=, <=) was
+ * added by Dustin Kirkland <dustin.kirkland@us.ibm.com>, 2005.
+ *
+ * Modified by Amy Griffis <amy.griffis@hp.com> to collect additional
+ * filesystem information.
+ *
+ * Subject and object context labeling support added by <danjones@us.ibm.com>
+ * and <dustin.kirkland@us.ibm.com> for LSPP certification compliance.
  */
 
 #include <linux/init.h>
 #include <asm/types.h>
 #include <asm/atomic.h>
+#include <asm/types.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/mount.h>
@@ -39,16 +52,16 @@
 #include <linux/audit.h>
 #include <linux/personality.h>
 #include <linux/time.h>
-#include <linux/kthread.h>
 #include <linux/netlink.h>
 #include <linux/compiler.h>
 #include <asm/unistd.h>
+#include <linux/security.h>
+#include <linux/list.h>
+#include <linux/tty.h>
+
+#include "audit.h"
 
-/* 0 = no checking
-   1 = put_count checking
-   2 = verbose put_count checking
-*/
-#define AUDIT_DEBUG 0
+extern struct list_head audit_filter_list[];
 
 /* No syscall auditing will take place unless audit_enabled != 0. */
 extern int audit_enabled;
@@ -62,29 +75,6 @@
  * path_lookup. */
 #define AUDIT_NAMES_RESERVED 7
 
-/* At task start time, the audit_state is set in the audit_context using
-   a per-task filter.  At syscall entry, the audit_state is augmented by
-   the syscall filter. */
-enum audit_state {
-	AUDIT_DISABLED,		/* Do not create per-task audit_context.
-				 * No syscall-specific audit records can
-				 * be generated. */
-	AUDIT_SETUP_CONTEXT,	/* Create the per-task audit_context,
-				 * but don't necessarily fill it in at
-				 * syscall entry time (i.e., filter
-				 * instead). */
-	AUDIT_BUILD_CONTEXT,	/* Create the per-task audit_context,
-				 * and always fill it in at syscall
-				 * entry time.  This makes a full
-				 * syscall record available if some
-				 * other part of the kernel decides it
-				 * should be recorded. */
-	AUDIT_RECORD_CONTEXT	/* Create the per-task audit_context,
-				 * always fill it in at syscall entry
-				 * time, and always write out the audit
-				 * record at syscall exit time.  */
-};
-
 /* When fs/namei.c:getname() is called, we store the pointer in name and
  * we don't let putname() free it (instead we free all of the saved
  * pointers at syscall exit time).
@@ -93,12 +83,13 @@
 struct audit_names {
 	const char	*name;
 	unsigned long	ino;
+	unsigned long	pino;
 	dev_t		dev;
 	umode_t		mode;
 	uid_t		uid;
 	gid_t		gid;
 	dev_t		rdev;
-	unsigned	flags;
+	char		*ctx;
 };
 
 struct audit_aux_data {
@@ -115,6 +106,7 @@
 	uid_t			uid;
 	gid_t			gid;
 	mode_t			mode;
+	char 			*ctx;
 };
 
 struct audit_aux_data_socketcall {
@@ -167,290 +159,72 @@
 #endif
 };
 
-				/* Public API */
-/* There are three lists of rules -- one to search at task creation
- * time, one to search at syscall entry time, and another to search at
- * syscall exit time. */
-static struct list_head audit_filter_list[AUDIT_NR_FILTERS] = {
-	LIST_HEAD_INIT(audit_filter_list[0]),
-	LIST_HEAD_INIT(audit_filter_list[1]),
-	LIST_HEAD_INIT(audit_filter_list[2]),
-	LIST_HEAD_INIT(audit_filter_list[3]),
-	LIST_HEAD_INIT(audit_filter_list[4]),
-#if AUDIT_NR_FILTERS != 5
-#error Fix audit_filter_list initialiser
-#endif
-};
-
-struct audit_entry {
-	struct list_head  list;
-	struct rcu_head   rcu;
-	struct audit_rule rule;
-};
-
-extern int audit_pid;
-
-/* Copy rule from user-space to kernel-space.  Called from 
- * audit_add_rule during AUDIT_ADD. */
-static inline int audit_copy_rule(struct audit_rule *d, struct audit_rule *s)
-{
-	int i;
-
-	if (s->action != AUDIT_NEVER
-	    && s->action != AUDIT_POSSIBLE
-	    && s->action != AUDIT_ALWAYS)
-		return -1;
-	if (s->field_count < 0 || s->field_count > AUDIT_MAX_FIELDS)
-		return -1;
-	if ((s->flags & ~AUDIT_FILTER_PREPEND) >= AUDIT_NR_FILTERS)
-		return -1;
-
-	d->flags	= s->flags;
-	d->action	= s->action;
-	d->field_count	= s->field_count;
-	for (i = 0; i < d->field_count; i++) {
-		d->fields[i] = s->fields[i];
-		d->values[i] = s->values[i];
-	}
-	for (i = 0; i < AUDIT_BITMASK_SIZE; i++) d->mask[i] = s->mask[i];
-	return 0;
-}
-
-/* Check to see if two rules are identical.  It is called from
- * audit_add_rule during AUDIT_ADD and 
- * audit_del_rule during AUDIT_DEL. */
-static inline int audit_compare_rule(struct audit_rule *a, struct audit_rule *b)
-{
-	int i;
-
-	if (a->flags != b->flags)
-		return 1;
-
-	if (a->action != b->action)
-		return 1;
-
-	if (a->field_count != b->field_count)
-		return 1;
-
-	for (i = 0; i < a->field_count; i++) {
-		if (a->fields[i] != b->fields[i]
-		    || a->values[i] != b->values[i])
-			return 1;
-	}
-
-	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
-		if (a->mask[i] != b->mask[i])
-			return 1;
-
-	return 0;
-}
-
-/* Note that audit_add_rule and audit_del_rule are called via
- * audit_receive() in audit.c, and are protected by
- * audit_netlink_sem. */
-static inline int audit_add_rule(struct audit_rule *rule,
-				  struct list_head *list)
-{
-	struct audit_entry  *entry;
-
-	/* Do not use the _rcu iterator here, since this is the only
-	 * addition routine. */
-	list_for_each_entry(entry, list, list) {
-		if (!audit_compare_rule(rule, &entry->rule)) {
-			return -EEXIST;
-		}
-	}
-
-	if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL)))
-		return -ENOMEM;
-	if (audit_copy_rule(&entry->rule, rule)) {
-		kfree(entry);
-		return -EINVAL;
-	}
-
-	if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
-		entry->rule.flags &= ~AUDIT_FILTER_PREPEND;
-		list_add_rcu(&entry->list, list);
-	} else {
-		list_add_tail_rcu(&entry->list, list);
-	}
-
-	return 0;
-}
-
-static inline void audit_free_rule(struct rcu_head *head)
-{
-	struct audit_entry *e = container_of(head, struct audit_entry, rcu);
-	kfree(e);
-}
-
-/* Note that audit_add_rule and audit_del_rule are called via
- * audit_receive() in audit.c, and are protected by
- * audit_netlink_sem. */
-static inline int audit_del_rule(struct audit_rule *rule,
-				 struct list_head *list)
-{
-	struct audit_entry  *e;
-
-	/* Do not use the _rcu iterator here, since this is the only
-	 * deletion routine. */
-	list_for_each_entry(e, list, list) {
-		if (!audit_compare_rule(rule, &e->rule)) {
-			list_del_rcu(&e->list);
-			call_rcu(&e->rcu, audit_free_rule);
-			return 0;
-		}
-	}
-	return -ENOENT;		/* No matching rule */
-}
-
-static int audit_list_rules(void *_dest)
-{
-	int pid, seq;
-	int *dest = _dest;
-	struct audit_entry *entry;
-	int i;
-
-	pid = dest[0];
-	seq = dest[1];
-	kfree(dest);
-
-	down(&audit_netlink_sem);
-
-	/* The *_rcu iterators not needed here because we are
-	   always called with audit_netlink_sem held. */
-	for (i=0; i<AUDIT_NR_FILTERS; i++) {
-		list_for_each_entry(entry, &audit_filter_list[i], list)
-			audit_send_reply(pid, seq, AUDIT_LIST, 0, 1,
-					 &entry->rule, sizeof(entry->rule));
-	}
-	audit_send_reply(pid, seq, AUDIT_LIST, 1, 1, NULL, 0);
-	
-	up(&audit_netlink_sem);
-	return 0;
-}
-
-int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
-							uid_t loginuid)
-{
-	struct task_struct *tsk;
-	int *dest;
-	int		   err = 0;
-	unsigned listnr;
-
-	switch (type) {
-	case AUDIT_LIST:
-		/* We can't just spew out the rules here because we might fill
-		 * the available socket buffer space and deadlock waiting for
-		 * auditctl to read from it... which isn't ever going to
-		 * happen if we're actually running in the context of auditctl
-		 * trying to _send_ the stuff */
-		 
-		dest = kmalloc(2 * sizeof(int), GFP_KERNEL);
-		if (!dest)
-			return -ENOMEM;
-		dest[0] = pid;
-		dest[1] = seq;
-
-		tsk = kthread_run(audit_list_rules, dest, "audit_list_rules");
-		if (IS_ERR(tsk)) {
-			kfree(dest);
-			err = PTR_ERR(tsk);
-		}
-		break;
-	case AUDIT_ADD:
-		listnr =((struct audit_rule *)data)->flags & ~AUDIT_FILTER_PREPEND;
-		if (listnr >= AUDIT_NR_FILTERS)
-			return -EINVAL;
-
-		err = audit_add_rule(data, &audit_filter_list[listnr]);
-		if (!err)
-			audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
-				  "auid=%u added an audit rule\n", loginuid);
-		break;
-	case AUDIT_DEL:
-		listnr =((struct audit_rule *)data)->flags & ~AUDIT_FILTER_PREPEND;
-		if (listnr >= AUDIT_NR_FILTERS)
-			return -EINVAL;
-
-		err = audit_del_rule(data, &audit_filter_list[listnr]);
-		if (!err)
-			audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
-				  "auid=%u removed an audit rule\n", loginuid);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return err;
-}
 
 /* Compare a task_struct with an audit_rule.  Return 1 on match, 0
  * otherwise. */
 static int audit_filter_rules(struct task_struct *tsk,
-			      struct audit_rule *rule,
+			      struct audit_krule *rule,
 			      struct audit_context *ctx,
 			      enum audit_state *state)
 {
 	int i, j;
 
 	for (i = 0; i < rule->field_count; i++) {
-		u32 field  = rule->fields[i] & ~AUDIT_NEGATE;
-		u32 value  = rule->values[i];
+		struct audit_field *f = &rule->fields[i];
 		int result = 0;
 
-		switch (field) {
+		switch (f->type) {
 		case AUDIT_PID:
-			result = (tsk->pid == value);
+			result = audit_comparator(tsk->pid, f->op, f->val);
 			break;
 		case AUDIT_UID:
-			result = (tsk->uid == value);
+			result = audit_comparator(tsk->uid, f->op, f->val);
 			break;
 		case AUDIT_EUID:
-			result = (tsk->euid == value);
+			result = audit_comparator(tsk->euid, f->op, f->val);
 			break;
 		case AUDIT_SUID:
-			result = (tsk->suid == value);
+			result = audit_comparator(tsk->suid, f->op, f->val);
 			break;
 		case AUDIT_FSUID:
-			result = (tsk->fsuid == value);
+			result = audit_comparator(tsk->fsuid, f->op, f->val);
 			break;
 		case AUDIT_GID:
-			result = (tsk->gid == value);
+			result = audit_comparator(tsk->gid, f->op, f->val);
 			break;
 		case AUDIT_EGID:
-			result = (tsk->egid == value);
+			result = audit_comparator(tsk->egid, f->op, f->val);
 			break;
 		case AUDIT_SGID:
-			result = (tsk->sgid == value);
+			result = audit_comparator(tsk->sgid, f->op, f->val);
 			break;
 		case AUDIT_FSGID:
-			result = (tsk->fsgid == value);
+			result = audit_comparator(tsk->fsgid, f->op, f->val);
 			break;
 		case AUDIT_PERS:
-			result = (tsk->personality == value);
+			result = audit_comparator(tsk->personality, f->op, f->val);
 			break;
 		case AUDIT_ARCH:
-			if (ctx) 
-				result = (ctx->arch == value);
+ 			if (ctx)
+				result = audit_comparator(ctx->arch, f->op, f->val);
 			break;
 
 		case AUDIT_EXIT:
 			if (ctx && ctx->return_valid)
-				result = (ctx->return_code == value);
+				result = audit_comparator(ctx->return_code, f->op, f->val);
 			break;
 		case AUDIT_SUCCESS:
 			if (ctx && ctx->return_valid) {
-				if (value)
-					result = (ctx->return_valid == AUDITSC_SUCCESS);
+				if (f->val)
+					result = audit_comparator(ctx->return_valid, f->op, AUDITSC_SUCCESS);
 				else
-					result = (ctx->return_valid == AUDITSC_FAILURE);
+					result = audit_comparator(ctx->return_valid, f->op, AUDITSC_FAILURE);
 			}
 			break;
 		case AUDIT_DEVMAJOR:
 			if (ctx) {
 				for (j = 0; j < ctx->name_count; j++) {
-					if (MAJOR(ctx->names[j].dev)==value) {
+					if (audit_comparator(MAJOR(ctx->names[j].dev),	f->op, f->val)) {
 						++result;
 						break;
 					}
@@ -460,7 +234,7 @@
 		case AUDIT_DEVMINOR:
 			if (ctx) {
 				for (j = 0; j < ctx->name_count; j++) {
-					if (MINOR(ctx->names[j].dev)==value) {
+					if (audit_comparator(MINOR(ctx->names[j].dev), f->op, f->val)) {
 						++result;
 						break;
 					}
@@ -468,9 +242,11 @@
 			}
 			break;
 		case AUDIT_INODE:
-			if (ctx) {
+		case AUDIT_WATCH:
+			if (ctx && f->val != (unsigned int)-1) {
 				for (j = 0; j < ctx->name_count; j++) {
-					if (ctx->names[j].ino == value) {
+					if (audit_comparator(ctx->names[j].ino, f->op, f->val) ||
+					    audit_comparator(ctx->names[j].pino, f->op, f->val)) {
 						++result;
 						break;
 					}
@@ -480,19 +256,17 @@
 		case AUDIT_LOGINUID:
 			result = 0;
 			if (ctx)
-				result = (ctx->loginuid == value);
+				result = audit_comparator(ctx->loginuid, f->op, f->val);
 			break;
 		case AUDIT_ARG0:
 		case AUDIT_ARG1:
 		case AUDIT_ARG2:
 		case AUDIT_ARG3:
 			if (ctx)
-				result = (ctx->argv[field-AUDIT_ARG0]==value);
+				result = audit_comparator(ctx->argv[f->type-AUDIT_ARG0], f->op, f->val);
 			break;
 		}
 
-		if (rule->fields[i] & AUDIT_NEGATE)
-			result = !result;
 		if (!result)
 			return 0;
 	}
@@ -527,7 +301,7 @@
 /* At syscall entry and exit time, this filter is called if the
  * audit_state is not low enough that auditing cannot take place, but is
  * also not high enough that we already know we have to write an audit
- * record (i.e., the state is AUDIT_SETUP_CONTEXT or  AUDIT_BUILD_CONTEXT).
+ * record (i.e., the state is AUDIT_SETUP_CONTEXT or AUDIT_BUILD_CONTEXT).
  */
 static enum audit_state audit_filter_syscall(struct task_struct *tsk,
 					     struct audit_context *ctx,
@@ -541,77 +315,19 @@
 
 	rcu_read_lock();
 	if (!list_empty(list)) {
-		    int word = AUDIT_WORD(ctx->major);
-		    int bit  = AUDIT_BIT(ctx->major);
-
-		    list_for_each_entry_rcu(e, list, list) {
-			    if ((e->rule.mask[word] & bit) == bit
-				&& audit_filter_rules(tsk, &e->rule, ctx, &state)) {
-				    rcu_read_unlock();
-				    return state;
-			    }
-		    }
-	}
-	rcu_read_unlock();
-	return AUDIT_BUILD_CONTEXT;
-}
+		int word = AUDIT_WORD(ctx->major);
+		int bit  = AUDIT_BIT(ctx->major);
 
-static int audit_filter_user_rules(struct netlink_skb_parms *cb,
-			      struct audit_rule *rule,
-			      enum audit_state *state)
-{
-	int i;
-
-	for (i = 0; i < rule->field_count; i++) {
-		u32 field  = rule->fields[i] & ~AUDIT_NEGATE;
-		u32 value  = rule->values[i];
-		int result = 0;
-
-		switch (field) {
-		case AUDIT_PID:
-			result = (cb->creds.pid == value);
-			break;
-		case AUDIT_UID:
-			result = (cb->creds.uid == value);
-			break;
-		case AUDIT_GID:
-			result = (cb->creds.gid == value);
-			break;
-		case AUDIT_LOGINUID:
-			result = (cb->loginuid == value);
-			break;
-		}
-
-		if (rule->fields[i] & AUDIT_NEGATE)
-			result = !result;
-		if (!result)
-			return 0;
-	}
-	switch (rule->action) {
-	case AUDIT_NEVER:    *state = AUDIT_DISABLED;	    break;
-	case AUDIT_POSSIBLE: *state = AUDIT_BUILD_CONTEXT;  break;
-	case AUDIT_ALWAYS:   *state = AUDIT_RECORD_CONTEXT; break;
-	}
-	return 1;
-}
-
-int audit_filter_user(struct netlink_skb_parms *cb, int type)
-{
-	struct audit_entry *e;
-	enum audit_state   state;
-	int ret = 1;
-
-	rcu_read_lock();
-	list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) {
-		if (audit_filter_user_rules(cb, &e->rule, &state)) {
-			if (state == AUDIT_DISABLED)
-				ret = 0;
-			break;
+		list_for_each_entry_rcu(e, list, list) {
+			if ((e->rule.mask[word] & bit) == bit
+					&& audit_filter_rules(tsk, &e->rule, ctx, &state)) {
+				rcu_read_unlock();
+				return state;
+			}
 		}
 	}
 	rcu_read_unlock();
-
-	return ret; /* Audit by default */
+	return AUDIT_BUILD_CONTEXT;
 }
 
 /* This should be called with task_lock() held. */
@@ -654,17 +370,19 @@
 #if AUDIT_DEBUG == 2
 	if (context->auditable
 	    ||context->put_count + context->ino_count != context->name_count) {
-		printk(KERN_ERR "audit.c:%d(:%d): major=%d in_syscall=%d"
+		printk(KERN_ERR "%s:%d(:%d): major=%d in_syscall=%d"
 		       " name_count=%d put_count=%d"
 		       " ino_count=%d [NOT freeing]\n",
-		       __LINE__,
+		       __FILE__, __LINE__,
 		       context->serial, context->major, context->in_syscall,
 		       context->name_count, context->put_count,
 		       context->ino_count);
-		for (i = 0; i < context->name_count; i++)
+		for (i = 0; i < context->name_count; i++) {
 			printk(KERN_ERR "names[%d] = %p = %s\n", i,
 			       context->names[i].name,
-			       context->names[i].name);
+			       context->names[i].name ?: "(null)");
+			kfree(context->names[i].ctx);
+		}
 		dump_stack();
 		return;
 	}
@@ -696,6 +414,12 @@
 			dput(axi->dentry);
 			mntput(axi->mnt);
 		}
+		if ( aux->type == AUDIT_IPC ) {
+			struct audit_aux_data_ipcctl *axi = (void *)aux;
+			if (axi->ctx)
+				kfree(axi->ctx);
+		}
+
 		context->aux = aux->next;
 		kfree(aux);
 	}
@@ -721,10 +445,15 @@
 	return context;
 }
 
-/* Filter on the task information and allocate a per-task audit context
+/**
+ * audit_alloc - allocate an audit context block for a task
+ * @tsk: task
+ *
+ * Filter on the task information and allocate a per-task audit context
  * if necessary.  Doing so turns on system call auditing for the
  * specified task.  This is called from copy_process, so no lock is
- * needed. */
+ * needed.
+ */
 int audit_alloc(struct task_struct *tsk)
 {
 	struct audit_context *context;
@@ -775,7 +504,37 @@
 		printk(KERN_ERR "audit: freed %d contexts\n", count);
 }
 
-static void audit_log_task_info(struct audit_buffer *ab)
+static void audit_log_task_context(struct audit_buffer *ab, gfp_t gfp_mask)
+{
+	char *ctx = NULL;
+	ssize_t len = 0;
+
+	len = security_getprocattr(current, "current", NULL, 0);
+	if (len < 0) {
+		if (len != -EINVAL)
+			goto error_path;
+		return;
+	}
+
+	ctx = kmalloc(len, gfp_mask);
+	if (!ctx)
+		goto error_path;
+
+	len = security_getprocattr(current, "current", ctx, len);
+	if (len < 0 )
+		goto error_path;
+
+	audit_log_format(ab, " subj=%s", ctx);
+	return;
+
+error_path:
+	if (ctx)
+		kfree(ctx);
+	audit_panic("error in audit_log_task_context");
+	return;
+}
+
+static void audit_log_task_info(struct audit_buffer *ab, gfp_t gfp_mask)
 {
 	char name[sizeof(current->comm)];
 	struct mm_struct *mm = current->mm;
@@ -788,6 +547,10 @@
 	if (!mm)
 		return;
 
+	/*
+	 * this is brittle; all callers that pass GFP_ATOMIC will have
+	 * NULL current->mm and we won't get here.
+	 */
 	down_read(&mm->mmap_sem);
 	vma = mm->mmap;
 	while (vma) {
@@ -801,6 +564,7 @@
 		vma = vma->vm_next;
 	}
 	up_read(&mm->mmap_sem);
+	audit_log_task_context(ab, gfp_mask);
 }
 
 static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask)
@@ -808,6 +572,7 @@
 	int i;
 	struct audit_buffer *ab;
 	struct audit_aux_data *aux;
+	const char *tty;
 
 	ab = audit_log_start(context, gfp_mask, AUDIT_SYSCALL);
 	if (!ab)
@@ -820,11 +585,15 @@
 		audit_log_format(ab, " success=%s exit=%ld", 
 				 (context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
 				 context->return_code);
+	if (current->signal->tty && current->signal->tty->name)
+		tty = current->signal->tty->name;
+	else
+		tty = "(none)";
 	audit_log_format(ab,
 		  " a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
 		  " pid=%d auid=%u uid=%u gid=%u"
 		  " euid=%u suid=%u fsuid=%u"
-		  " egid=%u sgid=%u fsgid=%u",
+		  " egid=%u sgid=%u fsgid=%u tty=%s",
 		  context->argv[0],
 		  context->argv[1],
 		  context->argv[2],
@@ -835,13 +604,13 @@
 		  context->uid,
 		  context->gid,
 		  context->euid, context->suid, context->fsuid,
-		  context->egid, context->sgid, context->fsgid);
-	audit_log_task_info(ab);
+		  context->egid, context->sgid, context->fsgid, tty);
+	audit_log_task_info(ab, gfp_mask);
 	audit_log_end(ab);
 
 	for (aux = context->aux; aux; aux = aux->next) {
 
-		ab = audit_log_start(context, GFP_KERNEL, aux->type);
+		ab = audit_log_start(context, gfp_mask, aux->type);
 		if (!ab)
 			continue; /* audit_panic has been called */
 
@@ -849,8 +618,8 @@
 		case AUDIT_IPC: {
 			struct audit_aux_data_ipcctl *axi = (void *)aux;
 			audit_log_format(ab, 
-					 " qbytes=%lx iuid=%u igid=%u mode=%x",
-					 axi->qbytes, axi->uid, axi->gid, axi->mode);
+					 " qbytes=%lx iuid=%u igid=%u mode=%x obj=%s",
+					 axi->qbytes, axi->uid, axi->gid, axi->mode, axi->ctx);
 			break; }
 
 		case AUDIT_SOCKETCALL: {
@@ -878,41 +647,57 @@
 	}
 
 	if (context->pwd && context->pwdmnt) {
-		ab = audit_log_start(context, GFP_KERNEL, AUDIT_CWD);
+		ab = audit_log_start(context, gfp_mask, AUDIT_CWD);
 		if (ab) {
 			audit_log_d_path(ab, "cwd=", context->pwd, context->pwdmnt);
 			audit_log_end(ab);
 		}
 	}
 	for (i = 0; i < context->name_count; i++) {
-		ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH);
+		unsigned long ino  = context->names[i].ino;
+		unsigned long pino = context->names[i].pino;
+
+		ab = audit_log_start(context, gfp_mask, AUDIT_PATH);
 		if (!ab)
 			continue; /* audit_panic has been called */
 
 		audit_log_format(ab, "item=%d", i);
-		if (context->names[i].name) {
-			audit_log_format(ab, " name=");
+
+		audit_log_format(ab, " name=");
+		if (context->names[i].name)
 			audit_log_untrustedstring(ab, context->names[i].name);
-		}
-		audit_log_format(ab, " flags=%x\n", context->names[i].flags);
-			 
-		if (context->names[i].ino != (unsigned long)-1)
-			audit_log_format(ab, " inode=%lu dev=%02x:%02x mode=%#o"
-					     " ouid=%u ogid=%u rdev=%02x:%02x",
-					 context->names[i].ino,
-					 MAJOR(context->names[i].dev),
-					 MINOR(context->names[i].dev),
-					 context->names[i].mode,
-					 context->names[i].uid,
-					 context->names[i].gid,
-					 MAJOR(context->names[i].rdev),
+		else
+			audit_log_format(ab, "(null)");
+
+		if (pino != (unsigned long)-1)
+			audit_log_format(ab, " parent=%lu",  pino);
+		if (ino != (unsigned long)-1)
+			audit_log_format(ab, " inode=%lu",  ino);
+		if ((pino != (unsigned long)-1) || (ino != (unsigned long)-1))
+			audit_log_format(ab, " dev=%02x:%02x mode=%#o" 
+					 " ouid=%u ogid=%u rdev=%02x:%02x", 
+					 MAJOR(context->names[i].dev), 
+					 MINOR(context->names[i].dev), 
+					 context->names[i].mode, 
+					 context->names[i].uid, 
+					 context->names[i].gid, 
+					 MAJOR(context->names[i].rdev), 
 					 MINOR(context->names[i].rdev));
+		if (context->names[i].ctx) {
+			audit_log_format(ab, " obj=%s",
+					context->names[i].ctx);
+		}
+
 		audit_log_end(ab);
 	}
 }
 
-/* Free a per-task audit context.  Called from copy_process and
- * __put_task_struct. */
+/**
+ * audit_free - free a per-task audit context
+ * @tsk: task whose audit context block to free
+ *
+ * Called from copy_process and __put_task_struct.
+ */
 void audit_free(struct task_struct *tsk)
 {
 	struct audit_context *context;
@@ -934,13 +719,24 @@
 	audit_free_context(context);
 }
 
-/* Fill in audit context at syscall entry.  This only happens if the
+/**
+ * audit_syscall_entry - fill in an audit record at syscall entry
+ * @tsk: task being audited
+ * @arch: architecture type
+ * @major: major syscall type (function)
+ * @a1: additional syscall register 1
+ * @a2: additional syscall register 2
+ * @a3: additional syscall register 3
+ * @a4: additional syscall register 4
+ *
+ * Fill in audit context at syscall entry.  This only happens if the
  * audit context was created when the task was created and the state or
  * filters demand the audit context be built.  If the state from the
  * per-task filter or from the per-syscall filter is AUDIT_RECORD_CONTEXT,
  * then the record will be written at syscall exit time (otherwise, it
  * will only be written if another part of the kernel requests that it
- * be written). */
+ * be written).
+ */
 void audit_syscall_entry(struct task_struct *tsk, int arch, int major,
 			 unsigned long a1, unsigned long a2,
 			 unsigned long a3, unsigned long a4)
@@ -950,7 +746,8 @@
 
 	BUG_ON(!context);
 
-	/* This happens only on certain architectures that make system
+	/*
+	 * This happens only on certain architectures that make system
 	 * calls in kernel_thread via the entry.S interface, instead of
 	 * with direct calls.  (If you are porting to a new
 	 * architecture, hitting this condition can indicate that you
@@ -958,7 +755,7 @@
 	 *
 	 * i386     no
 	 * x86_64   no
-	 * ppc64    yes (see arch/ppc64/kernel/misc.S)
+	 * ppc64    yes (see arch/powerpc/platforms/iseries/misc.S)
 	 *
 	 * This also happens with vm86 emulation in a non-nested manner
 	 * (entries without exits), so this case must be caught.
@@ -966,11 +763,6 @@
 	if (context->in_syscall) {
 		struct audit_context *newctx;
 
-#if defined(__NR_vm86) && defined(__NR_vm86old)
-		/* vm86 mode should only be entered once */
-		if (major == __NR_vm86 || major == __NR_vm86old)
-			return;
-#endif
 #if AUDIT_DEBUG
 		printk(KERN_ERR
 		       "audit(:%d) pid=%d in syscall=%d;"
@@ -1014,11 +806,18 @@
 	context->auditable  = !!(state == AUDIT_RECORD_CONTEXT);
 }
 
-/* Tear down after system call.  If the audit context has been marked as
+/**
+ * audit_syscall_exit - deallocate audit context after a system call
+ * @tsk: task being audited
+ * @valid: success/failure flag
+ * @return_code: syscall return value
+ *
+ * Tear down after system call.  If the audit context has been marked as
  * auditable (either because of the AUDIT_RECORD_CONTEXT state from
  * filtering, or because some other part of the kernel write an audit
  * message), then write out the syscall information.  In call cases,
- * free the names stored from getname(). */
+ * free the names stored from getname().
+ */
 void audit_syscall_exit(struct task_struct *tsk, int valid, long return_code)
 {
 	struct audit_context *context;
@@ -1053,7 +852,13 @@
 	put_task_struct(tsk);
 }
 
-/* Add a name to the list.  Called from fs/namei.c:getname(). */
+/**
+ * audit_getname - add a name to the list
+ * @name: name to add
+ *
+ * Add a name to the list of audit names for this context.
+ * Called from fs/namei.c:getname().
+ */
 void audit_getname(const char *name)
 {
 	struct audit_context *context = current->audit_context;
@@ -1082,10 +887,13 @@
 		
 }
 
-/* Intercept a putname request.  Called from
- * include/linux/fs.h:putname().  If we have stored the name from
- * getname in the audit context, then we delay the putname until syscall
- * exit. */
+/* audit_putname - intercept a putname request
+ * @name: name to intercept and delay for putname
+ *
+ * If we have stored the name from getname in the audit context,
+ * then we delay the putname until syscall exit.
+ * Called from include/linux/fs.h:putname().
+ */
 void audit_putname(const char *name)
 {
 	struct audit_context *context = current->audit_context;
@@ -1100,7 +908,7 @@
 			for (i = 0; i < context->name_count; i++)
 				printk(KERN_ERR "name[%d] = %p = %s\n", i,
 				       context->names[i].name,
-				       context->names[i].name);
+				       context->names[i].name ?: "(null)");
 		}
 #endif
 		__putname(name);
@@ -1122,9 +930,51 @@
 #endif
 }
 
-/* Store the inode and device from a lookup.  Called from
- * fs/namei.c:path_lookup(). */
-void audit_inode(const char *name, const struct inode *inode, unsigned flags)
+void audit_inode_context(int idx, const struct inode *inode)
+{
+	struct audit_context *context = current->audit_context;
+	const char *suffix = security_inode_xattr_getsuffix();
+	char *ctx = NULL;
+	int len = 0;
+
+	if (!suffix)
+		goto ret;
+
+	len = security_inode_getsecurity(inode, suffix, NULL, 0, 0);
+	if (len == -EOPNOTSUPP)
+		goto ret;
+	if (len < 0) 
+		goto error_path;
+
+	ctx = kmalloc(len, GFP_KERNEL);
+	if (!ctx) 
+		goto error_path;
+
+	len = security_inode_getsecurity(inode, suffix, ctx, len, 0);
+	if (len < 0)
+		goto error_path;
+
+	context->names[idx].ctx = ctx;
+	goto ret;
+
+error_path:
+	if (ctx)
+		kfree(ctx);
+	audit_panic("error in audit_inode_context");
+ret:
+	return;
+}
+
+
+/**
+ * audit_inode - store the inode and device from a lookup
+ * @name: name being audited
+ * @inode: inode being audited
+ * @flags: lookup flags (as used in path_lookup())
+ *
+ * Called from fs/namei.c:path_lookup().
+ */
+void __audit_inode(const char *name, const struct inode *inode, unsigned flags)
 {
 	int idx;
 	struct audit_context *context = current->audit_context;
@@ -1150,15 +1000,105 @@
 		++context->ino_count;
 #endif
 	}
-	context->names[idx].flags = flags;
-	context->names[idx].ino   = inode->i_ino;
 	context->names[idx].dev	  = inode->i_sb->s_dev;
 	context->names[idx].mode  = inode->i_mode;
 	context->names[idx].uid   = inode->i_uid;
 	context->names[idx].gid   = inode->i_gid;
 	context->names[idx].rdev  = inode->i_rdev;
+	audit_inode_context(idx, inode);
+	if ((flags & LOOKUP_PARENT) && (strcmp(name, "/") != 0) && 
+	    (strcmp(name, ".") != 0)) {
+		context->names[idx].ino   = (unsigned long)-1;
+		context->names[idx].pino  = inode->i_ino;
+	} else {
+		context->names[idx].ino   = inode->i_ino;
+		context->names[idx].pino  = (unsigned long)-1;
+	}
+}
+
+/**
+ * audit_inode_child - collect inode info for created/removed objects
+ * @dname: inode's dentry name
+ * @inode: inode being audited
+ * @pino: inode number of dentry parent
+ *
+ * For syscalls that create or remove filesystem objects, audit_inode
+ * can only collect information for the filesystem object's parent.
+ * This call updates the audit context with the child's information.
+ * Syscalls that create a new filesystem object must be hooked after
+ * the object is created.  Syscalls that remove a filesystem object
+ * must be hooked prior, in order to capture the target inode during
+ * unsuccessful attempts.
+ */
+void __audit_inode_child(const char *dname, const struct inode *inode,
+			 unsigned long pino)
+{
+	int idx;
+	struct audit_context *context = current->audit_context;
+
+	if (!context->in_syscall)
+		return;
+
+	/* determine matching parent */
+	if (dname)
+		for (idx = 0; idx < context->name_count; idx++)
+			if (context->names[idx].pino == pino) {
+				const char *n;
+				const char *name = context->names[idx].name;
+				int dlen = strlen(dname);
+				int nlen = name ? strlen(name) : 0;
+
+				if (nlen < dlen)
+					continue;
+				
+				/* disregard trailing slashes */
+				n = name + nlen - 1;
+				while ((*n == '/') && (n > name))
+					n--;
+
+				/* find last path component */
+				n = n - dlen + 1;
+				if (n < name)
+					continue;
+				else if (n > name) {
+					if (*--n != '/')
+						continue;
+					else
+						n++;
+				}
+
+				if (strncmp(n, dname, dlen) == 0)
+					goto update_context;
+			}
+
+	/* catch-all in case match not found */
+	idx = context->name_count++;
+	context->names[idx].name  = NULL;
+	context->names[idx].pino  = pino;
+#if AUDIT_DEBUG
+	context->ino_count++;
+#endif
+
+update_context:
+	if (inode) {
+		context->names[idx].ino   = inode->i_ino;
+		context->names[idx].dev	  = inode->i_sb->s_dev;
+		context->names[idx].mode  = inode->i_mode;
+		context->names[idx].uid   = inode->i_uid;
+		context->names[idx].gid   = inode->i_gid;
+		context->names[idx].rdev  = inode->i_rdev;
+		audit_inode_context(idx, inode);
+	}
 }
 
+/**
+ * auditsc_get_stamp - get local copies of audit_context values
+ * @ctx: audit_context for the task
+ * @t: timespec to store time recorded in the audit_context
+ * @serial: serial value that is recorded in the audit_context
+ *
+ * Also sets the context as auditable.
+ */
 void auditsc_get_stamp(struct audit_context *ctx,
 		       struct timespec *t, unsigned int *serial)
 {
@@ -1170,6 +1110,15 @@
 	ctx->auditable = 1;
 }
 
+/**
+ * audit_set_loginuid - set a task's audit_context loginuid
+ * @task: task whose audit context is being modified
+ * @loginuid: loginuid value
+ *
+ * Returns 0.
+ *
+ * Called (set) from fs/proc/base.c::proc_loginuid_write().
+ */
 int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
 {
 	if (task->audit_context) {
@@ -1188,12 +1137,27 @@
 	return 0;
 }
 
+/**
+ * audit_get_loginuid - get the loginuid for an audit_context
+ * @ctx: the audit_context
+ *
+ * Returns the context's loginuid or -1 if @ctx is NULL.
+ */
 uid_t audit_get_loginuid(struct audit_context *ctx)
 {
 	return ctx ? ctx->loginuid : -1;
 }
 
-int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode)
+/**
+ * audit_ipc_perms - record audit data for ipc
+ * @qbytes: msgq bytes
+ * @uid: msgq user id
+ * @gid: msgq group id
+ * @mode: msgq mode (permissions)
+ *
+ * Returns 0 for success or NULL context or < 0 on error.
+ */
+int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp)
 {
 	struct audit_aux_data_ipcctl *ax;
 	struct audit_context *context = current->audit_context;
@@ -1201,7 +1165,7 @@
 	if (likely(!context))
 		return 0;
 
-	ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
 	if (!ax)
 		return -ENOMEM;
 
@@ -1209,6 +1173,7 @@
 	ax->uid = uid;
 	ax->gid = gid;
 	ax->mode = mode;
+	ax->ctx = audit_ipc_context(ipcp);
 
 	ax->d.type = AUDIT_IPC;
 	ax->d.next = context->aux;
@@ -1216,6 +1181,45 @@
 	return 0;
 }
 
+char *audit_ipc_context(struct kern_ipc_perm *ipcp)
+{
+	struct audit_context *context = current->audit_context;
+	char *ctx = NULL;
+	int len = 0;
+
+	if (likely(!context))
+		return NULL;
+
+	len = security_ipc_getsecurity(ipcp, NULL, 0);
+	if (len == -EOPNOTSUPP)
+		goto ret;
+	if (len < 0)
+		goto error_path;
+
+	ctx = kmalloc(len, GFP_ATOMIC);
+	if (!ctx)
+		goto error_path;
+
+	len = security_ipc_getsecurity(ipcp, ctx, len);
+	if (len < 0)
+		goto error_path;
+
+	return ctx;
+
+error_path:
+	kfree(ctx);
+	audit_panic("error in audit_ipc_context");
+ret:
+	return NULL;
+}
+
+/**
+ * audit_socketcall - record audit data for sys_socketcall
+ * @nargs: number of args
+ * @args: args array
+ *
+ * Returns 0 for success or NULL context or < 0 on error.
+ */
 int audit_socketcall(int nargs, unsigned long *args)
 {
 	struct audit_aux_data_socketcall *ax;
@@ -1237,6 +1241,13 @@
 	return 0;
 }
 
+/**
+ * audit_sockaddr - record audit data for sys_bind, sys_connect, sys_sendto
+ * @len: data length in user space
+ * @a: data address in kernel space
+ *
+ * Returns 0 for success or NULL context or < 0 on error.
+ */
 int audit_sockaddr(int len, void *a)
 {
 	struct audit_aux_data_sockaddr *ax;
@@ -1258,6 +1269,15 @@
 	return 0;
 }
 
+/**
+ * audit_avc_path - record the granting or denial of permissions
+ * @dentry: dentry to record
+ * @mnt: mnt to record
+ *
+ * Returns 0 for success or NULL context or < 0 on error.
+ *
+ * Called from security/selinux/avc.c::avc_audit()
+ */
 int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt)
 {
 	struct audit_aux_data_path *ax;
@@ -1279,6 +1299,14 @@
 	return 0;
 }
 
+/**
+ * audit_signal_info - record signal info for shutting down audit subsystem
+ * @sig: signal value
+ * @t: task being signaled
+ *
+ * If the audit subsystem is being terminated, record the task (pid)
+ * and uid that is doing that.
+ */
 void audit_signal_info(int sig, struct task_struct *t)
 {
 	extern pid_t audit_sig_pid;
@@ -1295,4 +1323,3 @@
 		}
 	}
 }
-
diff -urN oldtree/kernel/cpu.c newtree/kernel/cpu.c
--- oldtree/kernel/cpu.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/kernel/cpu.c	2006-02-21 15:58:28.898753280 +0000
@@ -13,10 +13,10 @@
 #include <linux/module.h>
 #include <linux/kthread.h>
 #include <linux/stop_machine.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 /* This protects CPUs going up and down... */
-static DECLARE_MUTEX(cpucontrol);
+static DEFINE_MUTEX(cpucontrol);
 
 static struct notifier_block *cpu_chain;
 
@@ -30,9 +30,9 @@
 
 	if (lock_cpu_hotplug_owner != current) {
 		if (interruptible)
-			ret = down_interruptible(&cpucontrol);
+			ret = mutex_lock_interruptible(&cpucontrol);
 		else
-			down(&cpucontrol);
+			mutex_lock(&cpucontrol);
 	}
 
 	/*
@@ -56,7 +56,7 @@
 {
 	if (--lock_cpu_hotplug_depth == 0) {
 		lock_cpu_hotplug_owner = NULL;
-		up(&cpucontrol);
+		mutex_unlock(&cpucontrol);
 	}
 }
 EXPORT_SYMBOL_GPL(unlock_cpu_hotplug);
diff -urN oldtree/kernel/cpuset.c newtree/kernel/cpuset.c
--- oldtree/kernel/cpuset.c	2006-02-19 11:41:06.163406120 +0000
+++ newtree/kernel/cpuset.c	2006-02-21 15:58:29.571650984 +0000
@@ -4,15 +4,14 @@
  *  Processor and Memory placement constraints for sets of tasks.
  *
  *  Copyright (C) 2003 BULL SA.
- *  Copyright (C) 2004 Silicon Graphics, Inc.
+ *  Copyright (C) 2004-2006 Silicon Graphics, Inc.
  *
  *  Portions derived from Patrick Mochel's sysfs code.
  *  sysfs is Copyright (c) 2001-3 Patrick Mochel
- *  Portions Copyright (c) 2004 Silicon Graphics, Inc.
  *
- *  2003-10-10 Written by Simon Derr <simon.derr@bull.net>
+ *  2003-10-10 Written by Simon Derr.
  *  2003-10-22 Updates by Stephen Hemminger.
- *  2004 May-July Rework by Paul Jackson <pj@sgi.com>
+ *  2004 May-July Rework by Paul Jackson.
  *
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License.  See the file COPYING in the main directory of the Linux
@@ -53,7 +52,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/atomic.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #define CPUSET_SUPER_MAGIC		0x27e0eb
 
@@ -108,33 +107,45 @@
 	CS_MEM_EXCLUSIVE,
 	CS_MEMORY_MIGRATE,
 	CS_REMOVED,
-	CS_NOTIFY_ON_RELEASE
+	CS_NOTIFY_ON_RELEASE,
+	CS_SPREAD_PAGE,
+	CS_SPREAD_SLAB,
 } cpuset_flagbits_t;
 
 /* convenient tests for these bits */
 static inline int is_cpu_exclusive(const struct cpuset *cs)
 {
-	return !!test_bit(CS_CPU_EXCLUSIVE, &cs->flags);
+	return test_bit(CS_CPU_EXCLUSIVE, &cs->flags);
 }
 
 static inline int is_mem_exclusive(const struct cpuset *cs)
 {
-	return !!test_bit(CS_MEM_EXCLUSIVE, &cs->flags);
+	return test_bit(CS_MEM_EXCLUSIVE, &cs->flags);
 }
 
 static inline int is_removed(const struct cpuset *cs)
 {
-	return !!test_bit(CS_REMOVED, &cs->flags);
+	return test_bit(CS_REMOVED, &cs->flags);
 }
 
 static inline int notify_on_release(const struct cpuset *cs)
 {
-	return !!test_bit(CS_NOTIFY_ON_RELEASE, &cs->flags);
+	return test_bit(CS_NOTIFY_ON_RELEASE, &cs->flags);
 }
 
 static inline int is_memory_migrate(const struct cpuset *cs)
 {
-	return !!test_bit(CS_MEMORY_MIGRATE, &cs->flags);
+	return test_bit(CS_MEMORY_MIGRATE, &cs->flags);
+}
+
+static inline int is_spread_page(const struct cpuset *cs)
+{
+	return test_bit(CS_SPREAD_PAGE, &cs->flags);
+}
+
+static inline int is_spread_slab(const struct cpuset *cs)
+{
+	return test_bit(CS_SPREAD_SLAB, &cs->flags);
 }
 
 /*
@@ -168,63 +179,57 @@
 static struct super_block *cpuset_sb;
 
 /*
- * We have two global cpuset semaphores below.  They can nest.
- * It is ok to first take manage_sem, then nest callback_sem.  We also
+ * We have two global cpuset mutexes below.  They can nest.
+ * It is ok to first take manage_mutex, then nest callback_mutex.  We also
  * require taking task_lock() when dereferencing a tasks cpuset pointer.
  * See "The task_lock() exception", at the end of this comment.
  *
- * A task must hold both semaphores to modify cpusets.  If a task
- * holds manage_sem, then it blocks others wanting that semaphore,
- * ensuring that it is the only task able to also acquire callback_sem
+ * A task must hold both mutexes to modify cpusets.  If a task
+ * holds manage_mutex, then it blocks others wanting that mutex,
+ * ensuring that it is the only task able to also acquire callback_mutex
  * and be able to modify cpusets.  It can perform various checks on
  * the cpuset structure first, knowing nothing will change.  It can
- * also allocate memory while just holding manage_sem.  While it is
+ * also allocate memory while just holding manage_mutex.  While it is
  * performing these checks, various callback routines can briefly
- * acquire callback_sem to query cpusets.  Once it is ready to make
- * the changes, it takes callback_sem, blocking everyone else.
+ * acquire callback_mutex to query cpusets.  Once it is ready to make
+ * the changes, it takes callback_mutex, blocking everyone else.
  *
  * Calls to the kernel memory allocator can not be made while holding
- * callback_sem, as that would risk double tripping on callback_sem
+ * callback_mutex, as that would risk double tripping on callback_mutex
  * from one of the callbacks into the cpuset code from within
  * __alloc_pages().
  *
- * If a task is only holding callback_sem, then it has read-only
+ * If a task is only holding callback_mutex, then it has read-only
  * access to cpusets.
  *
  * The task_struct fields mems_allowed and mems_generation may only
  * be accessed in the context of that task, so require no locks.
  *
  * Any task can increment and decrement the count field without lock.
- * So in general, code holding manage_sem or callback_sem can't rely
+ * So in general, code holding manage_mutex or callback_mutex can't rely
  * on the count field not changing.  However, if the count goes to
- * zero, then only attach_task(), which holds both semaphores, can
+ * zero, then only attach_task(), which holds both mutexes, can
  * increment it again.  Because a count of zero means that no tasks
  * are currently attached, therefore there is no way a task attached
  * to that cpuset can fork (the other way to increment the count).
- * So code holding manage_sem or callback_sem can safely assume that
+ * So code holding manage_mutex or callback_mutex can safely assume that
  * if the count is zero, it will stay zero.  Similarly, if a task
- * holds manage_sem or callback_sem on a cpuset with zero count, it
+ * holds manage_mutex or callback_mutex on a cpuset with zero count, it
  * knows that the cpuset won't be removed, as cpuset_rmdir() needs
- * both of those semaphores.
- *
- * A possible optimization to improve parallelism would be to make
- * callback_sem a R/W semaphore (rwsem), allowing the callback routines
- * to proceed in parallel, with read access, until the holder of
- * manage_sem needed to take this rwsem for exclusive write access
- * and modify some cpusets.
+ * both of those mutexes.
  *
  * The cpuset_common_file_write handler for operations that modify
- * the cpuset hierarchy holds manage_sem across the entire operation,
+ * the cpuset hierarchy holds manage_mutex across the entire operation,
  * single threading all such cpuset modifications across the system.
  *
- * The cpuset_common_file_read() handlers only hold callback_sem across
+ * The cpuset_common_file_read() handlers only hold callback_mutex across
  * small pieces of code, such as when reading out possibly multi-word
  * cpumasks and nodemasks.
  *
  * The fork and exit callbacks cpuset_fork() and cpuset_exit(), don't
- * (usually) take either semaphore.  These are the two most performance
+ * (usually) take either mutex.  These are the two most performance
  * critical pieces of code here.  The exception occurs on cpuset_exit(),
- * when a task in a notify_on_release cpuset exits.  Then manage_sem
+ * when a task in a notify_on_release cpuset exits.  Then manage_mutex
  * is taken, and if the cpuset count is zero, a usermode call made
  * to /sbin/cpuset_release_agent with the name of the cpuset (path
  * relative to the root of cpuset file system) as the argument.
@@ -242,9 +247,9 @@
  *
  * The need for this exception arises from the action of attach_task(),
  * which overwrites one tasks cpuset pointer with another.  It does
- * so using both semaphores, however there are several performance
+ * so using both mutexes, however there are several performance
  * critical places that need to reference task->cpuset without the
- * expense of grabbing a system global semaphore.  Therefore except as
+ * expense of grabbing a system global mutex.  Therefore except as
  * noted below, when dereferencing or, as in attach_task(), modifying
  * a tasks cpuset pointer we use task_lock(), which acts on a spinlock
  * (task->alloc_lock) already in the task_struct routinely used for
@@ -256,8 +261,8 @@
  * the routine cpuset_update_task_memory_state().
  */
 
-static DECLARE_MUTEX(manage_sem);
-static DECLARE_MUTEX(callback_sem);
+static DEFINE_MUTEX(manage_mutex);
+static DEFINE_MUTEX(callback_mutex);
 
 /*
  * A couple of forward declarations required, due to cyclic reference loop:
@@ -432,7 +437,7 @@
 }
 
 /*
- * Call with manage_sem held.  Writes path of cpuset into buf.
+ * Call with manage_mutex held.  Writes path of cpuset into buf.
  * Returns 0 on success, -errno on error.
  */
 
@@ -484,11 +489,11 @@
  * status of the /sbin/cpuset_release_agent task, so no sense holding
  * our caller up for that.
  *
- * When we had only one cpuset semaphore, we had to call this
+ * When we had only one cpuset mutex, we had to call this
  * without holding it, to avoid deadlock when call_usermodehelper()
  * allocated memory.  With two locks, we could now call this while
- * holding manage_sem, but we still don't, so as to minimize
- * the time manage_sem is held.
+ * holding manage_mutex, but we still don't, so as to minimize
+ * the time manage_mutex is held.
  */
 
 static void cpuset_release_agent(const char *pathbuf)
@@ -520,15 +525,15 @@
  * cs is notify_on_release() and now both the user count is zero and
  * the list of children is empty, prepare cpuset path in a kmalloc'd
  * buffer, to be returned via ppathbuf, so that the caller can invoke
- * cpuset_release_agent() with it later on, once manage_sem is dropped.
- * Call here with manage_sem held.
+ * cpuset_release_agent() with it later on, once manage_mutex is dropped.
+ * Call here with manage_mutex held.
  *
  * This check_for_release() routine is responsible for kmalloc'ing
  * pathbuf.  The above cpuset_release_agent() is responsible for
  * kfree'ing pathbuf.  The caller of these routines is responsible
  * for providing a pathbuf pointer, initialized to NULL, then
- * calling check_for_release() with manage_sem held and the address
- * of the pathbuf pointer, then dropping manage_sem, then calling
+ * calling check_for_release() with manage_mutex held and the address
+ * of the pathbuf pointer, then dropping manage_mutex, then calling
  * cpuset_release_agent() with pathbuf, as set by check_for_release().
  */
 
@@ -559,7 +564,7 @@
  * One way or another, we guarantee to return some non-empty subset
  * of cpu_online_map.
  *
- * Call with callback_sem held.
+ * Call with callback_mutex held.
  */
 
 static void guarantee_online_cpus(const struct cpuset *cs, cpumask_t *pmask)
@@ -583,7 +588,7 @@
  * One way or another, we guarantee to return some non-empty subset
  * of node_online_map.
  *
- * Call with callback_sem held.
+ * Call with callback_mutex held.
  */
 
 static void guarantee_online_mems(const struct cpuset *cs, nodemask_t *pmask)
@@ -608,12 +613,12 @@
  * current->cpuset if a task has its memory placement changed.
  * Do not call this routine if in_interrupt().
  *
- * Call without callback_sem or task_lock() held.  May be called
- * with or without manage_sem held.  Doesn't need task_lock to guard
+ * Call without callback_mutex or task_lock() held.  May be called
+ * with or without manage_mutex held.  Doesn't need task_lock to guard
  * against another task changing a non-NULL cpuset pointer to NULL,
  * as that is only done by a task on itself, and if the current task
  * is here, it is not simultaneously in the exit code NULL'ing its
- * cpuset pointer.  This routine also might acquire callback_sem and
+ * cpuset pointer.  This routine also might acquire callback_mutex and
  * current->mm->mmap_sem during call.
  *
  * Reading current->cpuset->mems_generation doesn't need task_lock
@@ -658,13 +663,21 @@
 	}
 
 	if (my_cpusets_mem_gen != tsk->cpuset_mems_generation) {
-		down(&callback_sem);
+		mutex_lock(&callback_mutex);
 		task_lock(tsk);
 		cs = tsk->cpuset;	/* Maybe changed when task not locked */
 		guarantee_online_mems(cs, &tsk->mems_allowed);
 		tsk->cpuset_mems_generation = cs->mems_generation;
+		if (is_spread_page(cs))
+			tsk->flags |= PF_SPREAD_PAGE;
+		else
+			tsk->flags &= ~PF_SPREAD_PAGE;
+		if (is_spread_slab(cs))
+			tsk->flags |= PF_SPREAD_SLAB;
+		else
+			tsk->flags &= ~PF_SPREAD_SLAB;
 		task_unlock(tsk);
-		up(&callback_sem);
+		mutex_unlock(&callback_mutex);
 		mpol_rebind_task(tsk, &tsk->mems_allowed);
 	}
 }
@@ -674,7 +687,7 @@
  *
  * One cpuset is a subset of another if all its allowed CPUs and
  * Memory Nodes are a subset of the other, and its exclusive flags
- * are only set if the other's are set.  Call holding manage_sem.
+ * are only set if the other's are set.  Call holding manage_mutex.
  */
 
 static int is_cpuset_subset(const struct cpuset *p, const struct cpuset *q)
@@ -692,7 +705,7 @@
  * If we replaced the flag and mask values of the current cpuset
  * (cur) with those values in the trial cpuset (trial), would
  * our various subset and exclusive rules still be valid?  Presumes
- * manage_sem held.
+ * manage_mutex held.
  *
  * 'cur' is the address of an actual, in-use cpuset.  Operations
  * such as list traversal that depend on the actual address of the
@@ -746,7 +759,7 @@
  *    exclusive child cpusets
  * Build these two partitions by calling partition_sched_domains
  *
- * Call with manage_sem held.  May nest a call to the
+ * Call with manage_mutex held.  May nest a call to the
  * lock_cpu_hotplug()/unlock_cpu_hotplug() pair.
  */
 
@@ -792,7 +805,7 @@
 }
 
 /*
- * Call with manage_sem held.  May take callback_sem during call.
+ * Call with manage_mutex held.  May take callback_mutex during call.
  */
 
 static int update_cpumask(struct cpuset *cs, char *buf)
@@ -811,9 +824,9 @@
 	if (retval < 0)
 		return retval;
 	cpus_unchanged = cpus_equal(cs->cpus_allowed, trialcs.cpus_allowed);
-	down(&callback_sem);
+	mutex_lock(&callback_mutex);
 	cs->cpus_allowed = trialcs.cpus_allowed;
-	up(&callback_sem);
+	mutex_unlock(&callback_mutex);
 	if (is_cpu_exclusive(cs) && !cpus_unchanged)
 		update_cpu_domains(cs);
 	return 0;
@@ -827,7 +840,7 @@
  * the cpuset is marked 'memory_migrate', migrate the tasks
  * pages to the new memory.
  *
- * Call with manage_sem held.  May take callback_sem during call.
+ * Call with manage_mutex held.  May take callback_mutex during call.
  * Will take tasklist_lock, scan tasklist for tasks in cpuset cs,
  * lock each such tasks mm->mmap_sem, scan its vma's and rebind
  * their mempolicies to the cpusets new mems_allowed.
@@ -862,11 +875,11 @@
 	if (retval < 0)
 		goto done;
 
-	down(&callback_sem);
+	mutex_lock(&callback_mutex);
 	cs->mems_allowed = trialcs.mems_allowed;
 	atomic_inc(&cpuset_mems_generation);
 	cs->mems_generation = atomic_read(&cpuset_mems_generation);
-	up(&callback_sem);
+	mutex_unlock(&callback_mutex);
 
 	set_cpuset_being_rebound(cs);		/* causes mpol_copy() rebind */
 
@@ -922,7 +935,7 @@
 	 * tasklist_lock.  Forks can happen again now - the mpol_copy()
 	 * cpuset_being_rebound check will catch such forks, and rebind
 	 * their vma mempolicies too.  Because we still hold the global
-	 * cpuset manage_sem, we know that no other rebind effort will
+	 * cpuset manage_mutex, we know that no other rebind effort will
 	 * be contending for the global variable cpuset_being_rebound.
 	 * It's ok if we rebind the same mm twice; mpol_rebind_mm()
 	 * is idempotent.  Also migrate pages in each mm to new nodes.
@@ -948,7 +961,7 @@
 }
 
 /*
- * Call with manage_sem held.
+ * Call with manage_mutex held.
  */
 
 static int update_memory_pressure_enabled(struct cpuset *cs, char *buf)
@@ -963,11 +976,12 @@
 /*
  * update_flag - read a 0 or a 1 in a file and update associated flag
  * bit:	the bit to update (CS_CPU_EXCLUSIVE, CS_MEM_EXCLUSIVE,
- *				CS_NOTIFY_ON_RELEASE, CS_MEMORY_MIGRATE)
+ *				CS_NOTIFY_ON_RELEASE, CS_MEMORY_MIGRATE,
+ *				CS_SPREAD_PAGE, CS_SPREAD_SLAB)
  * cs:	the cpuset to update
  * buf:	the buffer where we read the 0 or 1
  *
- * Call with manage_sem held.
+ * Call with manage_mutex held.
  */
 
 static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, char *buf)
@@ -989,12 +1003,12 @@
 		return err;
 	cpu_exclusive_changed =
 		(is_cpu_exclusive(cs) != is_cpu_exclusive(&trialcs));
-	down(&callback_sem);
+	mutex_lock(&callback_mutex);
 	if (turning_on)
 		set_bit(bit, &cs->flags);
 	else
 		clear_bit(bit, &cs->flags);
-	up(&callback_sem);
+	mutex_unlock(&callback_mutex);
 
 	if (cpu_exclusive_changed)
                 update_cpu_domains(cs);
@@ -1104,7 +1118,7 @@
  * writing the path of the old cpuset in 'ppathbuf' if it needs to be
  * notified on release.
  *
- * Call holding manage_sem.  May take callback_sem and task_lock of
+ * Call holding manage_mutex.  May take callback_mutex and task_lock of
  * the task 'pid' during call.
  */
 
@@ -1144,13 +1158,13 @@
 		get_task_struct(tsk);
 	}
 
-	down(&callback_sem);
+	mutex_lock(&callback_mutex);
 
 	task_lock(tsk);
 	oldcs = tsk->cpuset;
 	if (!oldcs) {
 		task_unlock(tsk);
-		up(&callback_sem);
+		mutex_unlock(&callback_mutex);
 		put_task_struct(tsk);
 		return -ESRCH;
 	}
@@ -1164,7 +1178,7 @@
 	from = oldcs->mems_allowed;
 	to = cs->mems_allowed;
 
-	up(&callback_sem);
+	mutex_unlock(&callback_mutex);
 
 	mm = get_task_mm(tsk);
 	if (mm) {
@@ -1194,6 +1208,8 @@
 	FILE_NOTIFY_ON_RELEASE,
 	FILE_MEMORY_PRESSURE_ENABLED,
 	FILE_MEMORY_PRESSURE,
+	FILE_SPREAD_PAGE,
+	FILE_SPREAD_SLAB,
 	FILE_TASKLIST,
 } cpuset_filetype_t;
 
@@ -1221,7 +1237,7 @@
 	}
 	buffer[nbytes] = 0;	/* nul-terminate */
 
-	down(&manage_sem);
+	mutex_lock(&manage_mutex);
 
 	if (is_removed(cs)) {
 		retval = -ENODEV;
@@ -1253,6 +1269,14 @@
 	case FILE_MEMORY_PRESSURE:
 		retval = -EACCES;
 		break;
+	case FILE_SPREAD_PAGE:
+		retval = update_flag(CS_SPREAD_PAGE, cs, buffer);
+		cs->mems_generation = atomic_inc_return(&cpuset_mems_generation);
+		break;
+	case FILE_SPREAD_SLAB:
+		retval = update_flag(CS_SPREAD_SLAB, cs, buffer);
+		cs->mems_generation = atomic_inc_return(&cpuset_mems_generation);
+		break;
 	case FILE_TASKLIST:
 		retval = attach_task(cs, buffer, &pathbuf);
 		break;
@@ -1264,7 +1288,7 @@
 	if (retval == 0)
 		retval = nbytes;
 out2:
-	up(&manage_sem);
+	mutex_unlock(&manage_mutex);
 	cpuset_release_agent(pathbuf);
 out1:
 	kfree(buffer);
@@ -1304,9 +1328,9 @@
 {
 	cpumask_t mask;
 
-	down(&callback_sem);
+	mutex_lock(&callback_mutex);
 	mask = cs->cpus_allowed;
-	up(&callback_sem);
+	mutex_unlock(&callback_mutex);
 
 	return cpulist_scnprintf(page, PAGE_SIZE, mask);
 }
@@ -1315,9 +1339,9 @@
 {
 	nodemask_t mask;
 
-	down(&callback_sem);
+	mutex_lock(&callback_mutex);
 	mask = cs->mems_allowed;
-	up(&callback_sem);
+	mutex_unlock(&callback_mutex);
 
 	return nodelist_scnprintf(page, PAGE_SIZE, mask);
 }
@@ -1362,6 +1386,12 @@
 	case FILE_MEMORY_PRESSURE:
 		s += sprintf(s, "%d", fmeter_getrate(&cs->fmeter));
 		break;
+	case FILE_SPREAD_PAGE:
+		*s++ = is_spread_page(cs) ? '1' : '0';
+		break;
+	case FILE_SPREAD_SLAB:
+		*s++ = is_spread_slab(cs) ? '1' : '0';
+		break;
 	default:
 		retval = -EINVAL;
 		goto out;
@@ -1598,7 +1628,7 @@
  * Handle an open on 'tasks' file.  Prepare a buffer listing the
  * process id's of tasks currently attached to the cpuset being opened.
  *
- * Does not require any specific cpuset semaphores, and does not take any.
+ * Does not require any specific cpuset mutexes, and does not take any.
  */
 static int cpuset_tasks_open(struct inode *unused, struct file *file)
 {
@@ -1725,6 +1755,16 @@
 	.private = FILE_MEMORY_PRESSURE,
 };
 
+static struct cftype cft_spread_page = {
+	.name = "memory_spread_page",
+	.private = FILE_SPREAD_PAGE,
+};
+
+static struct cftype cft_spread_slab = {
+	.name = "memory_spread_slab",
+	.private = FILE_SPREAD_SLAB,
+};
+
 static int cpuset_populate_dir(struct dentry *cs_dentry)
 {
 	int err;
@@ -1743,6 +1783,10 @@
 		return err;
 	if ((err = cpuset_add_file(cs_dentry, &cft_memory_pressure)) < 0)
 		return err;
+	if ((err = cpuset_add_file(cs_dentry, &cft_spread_page)) < 0)
+		return err;
+	if ((err = cpuset_add_file(cs_dentry, &cft_spread_slab)) < 0)
+		return err;
 	if ((err = cpuset_add_file(cs_dentry, &cft_tasks)) < 0)
 		return err;
 	return 0;
@@ -1754,7 +1798,7 @@
  *	name:		name of the new cpuset. Will be strcpy'ed.
  *	mode:		mode to set on new inode
  *
- *	Must be called with the semaphore on the parent inode held
+ *	Must be called with the mutex on the parent inode held
  */
 
 static long cpuset_create(struct cpuset *parent, const char *name, int mode)
@@ -1766,11 +1810,15 @@
 	if (!cs)
 		return -ENOMEM;
 
-	down(&manage_sem);
+	mutex_lock(&manage_mutex);
 	cpuset_update_task_memory_state();
 	cs->flags = 0;
 	if (notify_on_release(parent))
 		set_bit(CS_NOTIFY_ON_RELEASE, &cs->flags);
+	if (is_spread_page(parent))
+		set_bit(CS_SPREAD_PAGE, &cs->flags);
+	if (is_spread_slab(parent))
+		set_bit(CS_SPREAD_SLAB, &cs->flags);
 	cs->cpus_allowed = CPU_MASK_NONE;
 	cs->mems_allowed = NODE_MASK_NONE;
 	atomic_set(&cs->count, 0);
@@ -1782,28 +1830,28 @@
 
 	cs->parent = parent;
 
-	down(&callback_sem);
+	mutex_lock(&callback_mutex);
 	list_add(&cs->sibling, &cs->parent->children);
 	number_of_cpusets++;
-	up(&callback_sem);
+	mutex_unlock(&callback_mutex);
 
 	err = cpuset_create_dir(cs, name, mode);
 	if (err < 0)
 		goto err;
 
 	/*
-	 * Release manage_sem before cpuset_populate_dir() because it
+	 * Release manage_mutex before cpuset_populate_dir() because it
 	 * will down() this new directory's i_mutex and if we race with
 	 * another mkdir, we might deadlock.
 	 */
-	up(&manage_sem);
+	mutex_unlock(&manage_mutex);
 
 	err = cpuset_populate_dir(cs->dentry);
 	/* If err < 0, we have a half-filled directory - oh well ;) */
 	return 0;
 err:
 	list_del(&cs->sibling);
-	up(&manage_sem);
+	mutex_unlock(&manage_mutex);
 	kfree(cs);
 	return err;
 }
@@ -1825,18 +1873,18 @@
 
 	/* the vfs holds both inode->i_mutex already */
 
-	down(&manage_sem);
+	mutex_lock(&manage_mutex);
 	cpuset_update_task_memory_state();
 	if (atomic_read(&cs->count) > 0) {
-		up(&manage_sem);
+		mutex_unlock(&manage_mutex);
 		return -EBUSY;
 	}
 	if (!list_empty(&cs->children)) {
-		up(&manage_sem);
+		mutex_unlock(&manage_mutex);
 		return -EBUSY;
 	}
 	parent = cs->parent;
-	down(&callback_sem);
+	mutex_lock(&callback_mutex);
 	set_bit(CS_REMOVED, &cs->flags);
 	if (is_cpu_exclusive(cs))
 		update_cpu_domains(cs);
@@ -1848,10 +1896,10 @@
 	cpuset_d_remove_dir(d);
 	dput(d);
 	number_of_cpusets--;
-	up(&callback_sem);
+	mutex_unlock(&callback_mutex);
 	if (list_empty(&parent->children))
 		check_for_release(parent, &pathbuf);
-	up(&manage_sem);
+	mutex_unlock(&manage_mutex);
 	cpuset_release_agent(pathbuf);
 	return 0;
 }
@@ -1960,19 +2008,19 @@
  * Description: Detach cpuset from @tsk and release it.
  *
  * Note that cpusets marked notify_on_release force every task in
- * them to take the global manage_sem semaphore when exiting.
+ * them to take the global manage_mutex mutex when exiting.
  * This could impact scaling on very large systems.  Be reluctant to
  * use notify_on_release cpusets where very high task exit scaling
  * is required on large systems.
  *
  * Don't even think about derefencing 'cs' after the cpuset use count
- * goes to zero, except inside a critical section guarded by manage_sem
- * or callback_sem.   Otherwise a zero cpuset use count is a license to
+ * goes to zero, except inside a critical section guarded by manage_mutex
+ * or callback_mutex.   Otherwise a zero cpuset use count is a license to
  * any other task to nuke the cpuset immediately, via cpuset_rmdir().
  *
- * This routine has to take manage_sem, not callback_sem, because
- * it is holding that semaphore while calling check_for_release(),
- * which calls kmalloc(), so can't be called holding callback__sem().
+ * This routine has to take manage_mutex, not callback_mutex, because
+ * it is holding that mutex while calling check_for_release(),
+ * which calls kmalloc(), so can't be called holding callback_mutex().
  *
  * We don't need to task_lock() this reference to tsk->cpuset,
  * because tsk is already marked PF_EXITING, so attach_task() won't
@@ -2022,10 +2070,10 @@
 	if (notify_on_release(cs)) {
 		char *pathbuf = NULL;
 
-		down(&manage_sem);
+		mutex_lock(&manage_mutex);
 		if (atomic_dec_and_test(&cs->count))
 			check_for_release(cs, &pathbuf);
-		up(&manage_sem);
+		mutex_unlock(&manage_mutex);
 		cpuset_release_agent(pathbuf);
 	} else {
 		atomic_dec(&cs->count);
@@ -2046,11 +2094,11 @@
 {
 	cpumask_t mask;
 
-	down(&callback_sem);
+	mutex_lock(&callback_mutex);
 	task_lock(tsk);
 	guarantee_online_cpus(tsk->cpuset, &mask);
 	task_unlock(tsk);
-	up(&callback_sem);
+	mutex_unlock(&callback_mutex);
 
 	return mask;
 }
@@ -2074,11 +2122,11 @@
 {
 	nodemask_t mask;
 
-	down(&callback_sem);
+	mutex_lock(&callback_mutex);
 	task_lock(tsk);
 	guarantee_online_mems(tsk->cpuset, &mask);
 	task_unlock(tsk);
-	up(&callback_sem);
+	mutex_unlock(&callback_mutex);
 
 	return mask;
 }
@@ -2104,7 +2152,7 @@
 
 /*
  * nearest_exclusive_ancestor() - Returns the nearest mem_exclusive
- * ancestor to the specified cpuset.  Call holding callback_sem.
+ * ancestor to the specified cpuset.  Call holding callback_mutex.
  * If no ancestor is mem_exclusive (an unusual configuration), then
  * returns the root cpuset.
  */
@@ -2131,12 +2179,12 @@
  * GFP_KERNEL allocations are not so marked, so can escape to the
  * nearest mem_exclusive ancestor cpuset.
  *
- * Scanning up parent cpusets requires callback_sem.  The __alloc_pages()
+ * Scanning up parent cpusets requires callback_mutex.  The __alloc_pages()
  * routine only calls here with __GFP_HARDWALL bit _not_ set if
  * it's a GFP_KERNEL allocation, and all nodes in the current tasks
  * mems_allowed came up empty on the first pass over the zonelist.
  * So only GFP_KERNEL allocations, if all nodes in the cpuset are
- * short of memory, might require taking the callback_sem semaphore.
+ * short of memory, might require taking the callback_mutex mutex.
  *
  * The first loop over the zonelist in mm/page_alloc.c:__alloc_pages()
  * calls here with __GFP_HARDWALL always set in gfp_mask, enforcing
@@ -2171,31 +2219,31 @@
 		return 1;
 
 	/* Not hardwall and node outside mems_allowed: scan up cpusets */
-	down(&callback_sem);
+	mutex_lock(&callback_mutex);
 
 	task_lock(current);
 	cs = nearest_exclusive_ancestor(current->cpuset);
 	task_unlock(current);
 
 	allowed = node_isset(node, cs->mems_allowed);
-	up(&callback_sem);
+	mutex_unlock(&callback_mutex);
 	return allowed;
 }
 
 /**
  * cpuset_lock - lock out any changes to cpuset structures
  *
- * The out of memory (oom) code needs to lock down cpusets
+ * The out of memory (oom) code needs to mutex_lock cpusets
  * from being changed while it scans the tasklist looking for a
- * task in an overlapping cpuset.  Expose callback_sem via this
+ * task in an overlapping cpuset.  Expose callback_mutex via this
  * cpuset_lock() routine, so the oom code can lock it, before
  * locking the task list.  The tasklist_lock is a spinlock, so
- * must be taken inside callback_sem.
+ * must be taken inside callback_mutex.
  */
 
 void cpuset_lock(void)
 {
-	down(&callback_sem);
+	mutex_lock(&callback_mutex);
 }
 
 /**
@@ -2206,8 +2254,46 @@
 
 void cpuset_unlock(void)
 {
-	up(&callback_sem);
+	mutex_unlock(&callback_mutex);
+}
+
+/**
+ * cpuset_mem_spread_node() - On which node to begin search for a page
+ *
+ * If a task is marked PF_SPREAD_PAGE or PF_SPREAD_SLAB (as for
+ * tasks in a cpuset with is_spread_page or is_spread_slab set),
+ * and if the memory allocation used cpuset_mem_spread_node()
+ * to determine on which node to start looking, as it will for
+ * certain page cache or slab cache pages such as used for file
+ * system buffers and inode caches, then instead of starting on the
+ * local node to look for a free page, rather spread the starting
+ * node around the tasks mems_allowed nodes.
+ *
+ * We don't have to worry about the returned node being offline
+ * because "it can't happen", and even if it did, it would be ok.
+ *
+ * The routines calling guarantee_online_mems() are careful to
+ * only set nodes in task->mems_allowed that are online.  So it
+ * should not be possible for the following code to return an
+ * offline node.  But if it did, that would be ok, as this routine
+ * is not returning the node where the allocation must be, only
+ * the node where the search should start.  The zonelist passed to
+ * __alloc_pages() will include all nodes.  If the slab allocator
+ * is passed an offline node, it will fall back to the local node.
+ * See kmem_cache_alloc_node().
+ */
+
+int cpuset_mem_spread_node(void)
+{
+	int node;
+
+	node = next_node(current->cpuset_mem_spread_rotor, current->mems_allowed);
+	if (node == MAX_NUMNODES)
+		node = first_node(current->mems_allowed);
+	current->cpuset_mem_spread_rotor = node;
+	return node;
 }
+EXPORT_SYMBOL_GPL(cpuset_mem_spread_node);
 
 /**
  * cpuset_excl_nodes_overlap - Do we overlap @p's mem_exclusive ancestors?
@@ -2218,7 +2304,7 @@
  * determine if task @p's memory usage might impact the memory
  * available to the current task.
  *
- * Call while holding callback_sem.
+ * Call while holding callback_mutex.
  **/
 
 int cpuset_excl_nodes_overlap(const struct task_struct *p)
@@ -2289,7 +2375,7 @@
  *  - Used for /proc/<pid>/cpuset.
  *  - No need to task_lock(tsk) on this tsk->cpuset reference, as it
  *    doesn't really matter if tsk->cpuset changes after we read it,
- *    and we take manage_sem, keeping attach_task() from changing it
+ *    and we take manage_mutex, keeping attach_task() from changing it
  *    anyway.
  */
 
@@ -2305,7 +2391,7 @@
 		return -ENOMEM;
 
 	tsk = m->private;
-	down(&manage_sem);
+	mutex_lock(&manage_mutex);
 	cs = tsk->cpuset;
 	if (!cs) {
 		retval = -EINVAL;
@@ -2318,7 +2404,7 @@
 	seq_puts(m, buf);
 	seq_putc(m, '\n');
 out:
-	up(&manage_sem);
+	mutex_unlock(&manage_mutex);
 	kfree(buf);
 	return retval;
 }
diff -urN oldtree/kernel/exit.c newtree/kernel/exit.c
--- oldtree/kernel/exit.c	2006-02-19 11:41:06.164405968 +0000
+++ newtree/kernel/exit.c	2006-02-21 15:58:30.466514944 +0000
@@ -345,9 +345,9 @@
 	exit_mm(current);
 
 	set_special_pids(1, 1);
-	down(&tty_sem);
+	mutex_lock(&tty_mutex);
 	current->signal->tty = NULL;
-	up(&tty_sem);
+	mutex_unlock(&tty_mutex);
 
 	/* Block and flush all signals */
 	sigfillset(&blocked);
@@ -802,7 +802,7 @@
 		panic("Aiee, killing interrupt handler!");
 	if (unlikely(!tsk->pid))
 		panic("Attempted to kill the idle task!");
-	if (unlikely(tsk->pid == 1))
+	if (unlikely(tsk == child_reaper))
 		panic("Attempted to kill init!");
 	if (tsk->io_context)
 		exit_io_context();
diff -urN oldtree/kernel/fork.c newtree/kernel/fork.c
--- oldtree/kernel/fork.c	2006-02-19 11:41:06.166405664 +0000
+++ newtree/kernel/fork.c	2006-02-21 15:58:29.641640344 +0000
@@ -179,6 +179,7 @@
 	/* One for us, one for whoever does the "release_task()" (usually parent) */
 	atomic_set(&tsk->usage,2);
 	atomic_set(&tsk->fs_excl, 0);
+	tsk->btrace_seq = 0;
 	return tsk;
 }
 
@@ -605,12 +606,12 @@
 	atomic_set(&newf->count, 1);
 
 	spin_lock_init(&newf->file_lock);
+	newf->next_fd = 0;
 	fdt = &newf->fdtab;
-	fdt->next_fd = 0;
 	fdt->max_fds = NR_OPEN_DEFAULT;
-	fdt->max_fdset = __FD_SETSIZE;
-	fdt->close_on_exec = &newf->close_on_exec_init;
-	fdt->open_fds = &newf->open_fds_init;
+	fdt->max_fdset = EMBEDDED_FD_SET_SIZE;
+	fdt->close_on_exec = (fd_set *)&newf->close_on_exec_init;
+	fdt->open_fds = (fd_set *)&newf->open_fds_init;
 	fdt->fd = &newf->fd_array[0];
 	INIT_RCU_HEAD(&fdt->rcu);
 	fdt->free_files = NULL;
@@ -1018,6 +1019,7 @@
  		p->mempolicy = NULL;
  		goto bad_fork_cleanup_cpuset;
  	}
+	mpol_fix_fork_child_flag(p);
 #endif
 
 #ifdef CONFIG_DEBUG_MUTEXES
diff -urN oldtree/kernel/irq/manage.c newtree/kernel/irq/manage.c
--- oldtree/kernel/irq/manage.c	2006-02-19 11:41:06.169405208 +0000
+++ newtree/kernel/irq/manage.c	2006-02-21 15:58:35.966678792 +0000
@@ -238,6 +238,10 @@
 	return 0;
 }
 
+#ifdef CONFIG_DEBUG_SHIRQ
+static struct pt_regs shirq_fakeregs;
+#endif
+
 /**
  *	free_irq - free an interrupt
  *	@irq: Interrupt line to free
@@ -257,6 +261,7 @@
 	struct irq_desc *desc;
 	struct irqaction **p;
 	unsigned long flags;
+	irqreturn_t (*handler)(int, void *, struct pt_regs *) = NULL;
 
 	if (irq >= NR_IRQS)
 		return;
@@ -295,6 +300,8 @@
 
 			/* Make sure it's not being used on another CPU */
 			synchronize_irq(irq);
+			if (action->flags & SA_SHIRQ)
+				handler = action->handler;
 			kfree(action);
 			return;
 		}
@@ -302,6 +309,15 @@
 		spin_unlock_irqrestore(&desc->lock,flags);
 		return;
 	}
+#ifdef CONFIG_DEBUG_SHIRQ
+	if (handler) {
+		/* It's a shared IRQ -- the driver ought to be prepared for it to happen
+		   even now it's being freed, so let's make sure....
+		   We do this after actually deregistering it, to make sure that a 'real'
+		   IRQ doesn't run in parallel with our fake. */
+		handler(irq, dev_id, &shirq_fakeregs);
+	}
+#endif
 }
 
 EXPORT_SYMBOL(free_irq);
@@ -368,6 +384,23 @@
 
 	select_smp_affinity(irq);
 
+#ifdef CONFIG_DEBUG_SHIRQ
+	if (irqflags & SA_SHIRQ) {
+		/* It's a shared IRQ -- the driver ought to be prepared for it to happen
+		   immediately, so let's make sure....
+		   We do this before actually registering it, to make sure that a 'real'
+		   IRQ doesn't run in parallel with our fake. */
+		if (irqflags & SA_INTERRUPT) {
+			unsigned long flags;
+
+			local_irq_save(flags);
+			handler(irq, dev_id, &shirq_fakeregs);
+			local_irq_restore(flags);
+		} else
+			handler(irq, dev_id, &shirq_fakeregs);
+	}
+#endif
+
 	retval = setup_irq(irq, action);
 	if (retval)
 		kfree(action);
diff -urN oldtree/kernel/kmod.c newtree/kernel/kmod.c
--- oldtree/kernel/kmod.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/kernel/kmod.c	2006-02-21 15:58:30.642488192 +0000
@@ -170,7 +170,7 @@
 	sa.sa.sa_handler = SIG_IGN;
 	sa.sa.sa_flags = 0;
 	siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
-	do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
+	do_sigaction(SIGCHLD, &sa, NULL);
 	allow_signal(SIGCHLD);
 
 	pid = kernel_thread(____call_usermodehelper, sub_info, SIGCHLD);
diff -urN oldtree/kernel/kprobes.c newtree/kernel/kprobes.c
--- oldtree/kernel/kprobes.c	2006-02-19 11:41:06.171404904 +0000
+++ newtree/kernel/kprobes.c	2006-02-21 15:58:26.096179336 +0000
@@ -48,7 +48,7 @@
 static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
 static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
 
-DECLARE_MUTEX(kprobe_mutex);		/* Protects kprobe_table */
+DEFINE_MUTEX(kprobe_mutex);		/* Protects kprobe_table */
 DEFINE_SPINLOCK(kretprobe_lock);	/* Protects kretprobe_inst_table */
 static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL;
 
@@ -460,7 +460,7 @@
 	}
 
 	p->nmissed = 0;
-	down(&kprobe_mutex);
+	mutex_lock(&kprobe_mutex);
 	old_p = get_kprobe(p->addr);
 	if (old_p) {
 		ret = register_aggr_kprobe(old_p, p);
@@ -477,7 +477,7 @@
   	arch_arm_kprobe(p);
 
 out:
-	up(&kprobe_mutex);
+	mutex_unlock(&kprobe_mutex);
 
 	if (ret && probed_mod)
 		module_put(probed_mod);
@@ -496,10 +496,10 @@
 	struct kprobe *old_p, *list_p;
 	int cleanup_p;
 
-	down(&kprobe_mutex);
+	mutex_lock(&kprobe_mutex);
 	old_p = get_kprobe(p->addr);
 	if (unlikely(!old_p)) {
-		up(&kprobe_mutex);
+		mutex_unlock(&kprobe_mutex);
 		return;
 	}
 	if (p != old_p) {
@@ -507,7 +507,7 @@
 			if (list_p == p)
 			/* kprobe p is a valid probe */
 				goto valid_p;
-		up(&kprobe_mutex);
+		mutex_unlock(&kprobe_mutex);
 		return;
 	}
 valid_p:
@@ -523,7 +523,7 @@
 		cleanup_p = 0;
 	}
 
-	up(&kprobe_mutex);
+	mutex_unlock(&kprobe_mutex);
 
 	synchronize_sched();
 	if (p->mod_refcounted &&
diff -urN oldtree/kernel/kthread.c newtree/kernel/kthread.c
--- oldtree/kernel/kthread.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/kernel/kthread.c	2006-02-21 15:58:23.845521488 +0000
@@ -12,6 +12,7 @@
 #include <linux/unistd.h>
 #include <linux/file.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <asm/semaphore.h>
 
 /*
@@ -41,7 +42,7 @@
 
 /* Thread stopping is done by setthing this var: lock serializes
  * multiple kthread_stop calls. */
-static DECLARE_MUTEX(kthread_stop_lock);
+static DEFINE_MUTEX(kthread_stop_lock);
 static struct kthread_stop_info kthread_stop_info;
 
 int kthread_should_stop(void)
@@ -173,7 +174,7 @@
 {
 	int ret;
 
-	down(&kthread_stop_lock);
+	mutex_lock(&kthread_stop_lock);
 
 	/* It could exit after stop_info.k set, but before wake_up_process. */
 	get_task_struct(k);
@@ -194,7 +195,7 @@
 	wait_for_completion(&kthread_stop_info.done);
 	kthread_stop_info.k = NULL;
 	ret = kthread_stop_info.err;
-	up(&kthread_stop_lock);
+	mutex_unlock(&kthread_stop_lock);
 
 	return ret;
 }
diff -urN oldtree/kernel/module.c newtree/kernel/module.c
--- oldtree/kernel/module.c	2006-02-19 11:41:06.173404600 +0000
+++ newtree/kernel/module.c	2006-02-21 15:58:31.110417056 +0000
@@ -39,6 +39,7 @@
 #include <linux/device.h>
 #include <linux/string.h>
 #include <linux/sched.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 #include <asm/cacheflush.h>
@@ -60,18 +61,18 @@
 static DEFINE_SPINLOCK(modlist_lock);
 
 /* List of modules, protected by module_mutex AND modlist_lock */
-static DECLARE_MUTEX(module_mutex);
+static DEFINE_MUTEX(module_mutex);
 static LIST_HEAD(modules);
 
-static DECLARE_MUTEX(notify_mutex);
+static DEFINE_MUTEX(notify_mutex);
 static struct notifier_block * module_notify_list;
 
 int register_module_notifier(struct notifier_block * nb)
 {
 	int err;
-	down(&notify_mutex);
+	mutex_lock(&notify_mutex);
 	err = notifier_chain_register(&module_notify_list, nb);
-	up(&notify_mutex);
+	mutex_unlock(&notify_mutex);
 	return err;
 }
 EXPORT_SYMBOL(register_module_notifier);
@@ -79,9 +80,9 @@
 int unregister_module_notifier(struct notifier_block * nb)
 {
 	int err;
-	down(&notify_mutex);
+	mutex_lock(&notify_mutex);
 	err = notifier_chain_unregister(&module_notify_list, nb);
-	up(&notify_mutex);
+	mutex_unlock(&notify_mutex);
 	return err;
 }
 EXPORT_SYMBOL(unregister_module_notifier);
@@ -126,8 +127,11 @@
 extern const struct kernel_symbol __stop___ksymtab[];
 extern const struct kernel_symbol __start___ksymtab_gpl[];
 extern const struct kernel_symbol __stop___ksymtab_gpl[];
+extern const struct kernel_symbol __start___ksymtab_gpl_future[];
+extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
 extern const unsigned long __start___kcrctab[];
 extern const unsigned long __start___kcrctab_gpl[];
+extern const unsigned long __start___kcrctab_gpl_future[];
 
 #ifndef CONFIG_MODVERSIONS
 #define symversion(base, idx) NULL
@@ -135,6 +139,18 @@
 #define symversion(base, idx) ((base) ? ((base) + (idx)) : NULL)
 #endif
 
+/* lookup symbol in given range of kernel_symbols */
+static const struct kernel_symbol *lookup_symbol(const char *name,
+	const struct kernel_symbol *start,
+	const struct kernel_symbol *stop)
+{
+	const struct kernel_symbol *ks = start;
+	for (; ks < stop; ks++)
+		if (strcmp(ks->name, name) == 0)
+			return ks;
+	return NULL;
+}
+
 /* Find a symbol, return value, crc and module which owns it */
 static unsigned long __find_symbol(const char *name,
 				   struct module **owner,
@@ -142,41 +158,76 @@
 				   int gplok)
 {
 	struct module *mod;
-	unsigned int i;
+	const struct kernel_symbol *ks;
 
 	/* Core kernel first. */ 
 	*owner = NULL;
-	for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++) {
-		if (strcmp(__start___ksymtab[i].name, name) == 0) {
-			*crc = symversion(__start___kcrctab, i);
-			return __start___ksymtab[i].value;
-		}
+	ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab);
+	if (ks) {
+		*crc = symversion(__start___kcrctab, (ks - __start___ksymtab));
+		return ks->value;
 	}
 	if (gplok) {
-		for (i = 0; __start___ksymtab_gpl+i<__stop___ksymtab_gpl; i++)
-			if (strcmp(__start___ksymtab_gpl[i].name, name) == 0) {
-				*crc = symversion(__start___kcrctab_gpl, i);
-				return __start___ksymtab_gpl[i].value;
-			}
+		ks = lookup_symbol(name, __start___ksymtab_gpl,
+					 __stop___ksymtab_gpl);
+		if (ks) {
+			*crc = symversion(__start___kcrctab_gpl,
+					  (ks - __start___ksymtab_gpl));
+			return ks->value;
+		}
+	}
+	ks = lookup_symbol(name, __start___ksymtab_gpl_future,
+				 __stop___ksymtab_gpl_future);
+	if (ks) {
+		if (!gplok) {
+			printk(KERN_WARNING "Symbol %s is being used "
+			       "by a non-GPL module, which will not "
+			       "be allowed in the future\n", name);
+			printk(KERN_WARNING "Please see the file "
+			       "Documentation/feature-removal-schedule.txt "
+			       "in the kernel source tree for more "
+			       "details.\n");
+		}
+		*crc = symversion(__start___kcrctab_gpl_future,
+				  (ks - __start___ksymtab_gpl_future));
+		return ks->value;
 	}
 
 	/* Now try modules. */ 
 	list_for_each_entry(mod, &modules, list) {
 		*owner = mod;
-		for (i = 0; i < mod->num_syms; i++)
-			if (strcmp(mod->syms[i].name, name) == 0) {
-				*crc = symversion(mod->crcs, i);
-				return mod->syms[i].value;
-			}
+		ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms);
+		if (ks) {
+			*crc = symversion(mod->crcs, (ks - mod->syms));
+			return ks->value;
+		}
 
 		if (gplok) {
-			for (i = 0; i < mod->num_gpl_syms; i++) {
-				if (strcmp(mod->gpl_syms[i].name, name) == 0) {
-					*crc = symversion(mod->gpl_crcs, i);
-					return mod->gpl_syms[i].value;
-				}
+			ks = lookup_symbol(name, mod->gpl_syms,
+					   mod->gpl_syms + mod->num_gpl_syms);
+			if (ks) {
+				*crc = symversion(mod->gpl_crcs,
+						  (ks - mod->gpl_syms));
+				return ks->value;
 			}
 		}
+		ks = lookup_symbol(name, mod->gpl_future_syms,
+				   (mod->gpl_future_syms +
+				    mod->num_gpl_future_syms));
+		if (ks) {
+			if (!gplok) {
+				printk(KERN_WARNING "Symbol %s is being used "
+				       "by a non-GPL module, which will not "
+				       "be allowed in the future\n", name);
+				printk(KERN_WARNING "Please see the file "
+				       "Documentation/feature-removal-schedule.txt "
+				       "in the kernel source tree for more "
+				       "details.\n");
+			}
+			*crc = symversion(mod->gpl_future_crcs,
+					  (ks - mod->gpl_future_syms));
+			return ks->value;
+		}
 	}
 	DEBUGP("Failed to find symbol %s\n", name);
  	return 0;
@@ -379,7 +430,6 @@
 }
 #endif /* CONFIG_SMP */
 
-#ifdef CONFIG_MODULE_UNLOAD
 #define MODINFO_ATTR(field)	\
 static void setup_modinfo_##field(struct module *mod, const char *s)  \
 {                                                                     \
@@ -411,12 +461,7 @@
 MODINFO_ATTR(version);
 MODINFO_ATTR(srcversion);
 
-static struct module_attribute *modinfo_attrs[] = {
-	&modinfo_version,
-	&modinfo_srcversion,
-	NULL,
-};
-
+#ifdef CONFIG_MODULE_UNLOAD
 /* Init the unload section of the module. */
 static void module_unload_init(struct module *mod)
 {
@@ -557,7 +602,7 @@
 static void wait_for_zero_refcount(struct module *mod)
 {
 	/* Since we might sleep for some time, drop the semaphore first */
-	up(&module_mutex);
+	mutex_unlock(&module_mutex);
 	for (;;) {
 		DEBUGP("Looking at refcount...\n");
 		set_current_state(TASK_UNINTERRUPTIBLE);
@@ -566,7 +611,7 @@
 		schedule();
 	}
 	current->state = TASK_RUNNING;
-	down(&module_mutex);
+	mutex_lock(&module_mutex);
 }
 
 asmlinkage long
@@ -583,7 +628,7 @@
 		return -EFAULT;
 	name[MODULE_NAME_LEN-1] = '\0';
 
-	if (down_interruptible(&module_mutex) != 0)
+	if (mutex_lock_interruptible(&module_mutex) != 0)
 		return -EINTR;
 
 	mod = find_module(name);
@@ -632,14 +677,14 @@
 
 	/* Final destruction now noone is using it. */
 	if (mod->exit != NULL) {
-		up(&module_mutex);
+		mutex_unlock(&module_mutex);
 		mod->exit();
-		down(&module_mutex);
+		mutex_lock(&module_mutex);
 	}
 	free_module(mod);
 
  out:
-	up(&module_mutex);
+	mutex_unlock(&module_mutex);
 	return ret;
 }
 
@@ -731,6 +776,15 @@
 }
 #endif /* CONFIG_MODULE_UNLOAD */
 
+static struct module_attribute *modinfo_attrs[] = {
+	&modinfo_version,
+	&modinfo_srcversion,
+#ifdef CONFIG_MODULE_UNLOAD
+	&refcnt,
+#endif
+	NULL,
+};
+
 #ifdef CONFIG_OBSOLETE_MODPARM
 /* Bounds checking done below */
 static int obsparm_copy_string(const char *val, struct kernel_param *kp)
@@ -1056,37 +1110,28 @@
 }
 #endif /* CONFIG_KALLSYMS */
 
-
-#ifdef CONFIG_MODULE_UNLOAD
-static inline int module_add_refcnt_attr(struct module *mod)
-{
-	return sysfs_create_file(&mod->mkobj.kobj, &refcnt.attr);
-}
-static void module_remove_refcnt_attr(struct module *mod)
-{
-	return sysfs_remove_file(&mod->mkobj.kobj, &refcnt.attr);
-}
-#else
-static inline int module_add_refcnt_attr(struct module *mod)
-{
-	return 0;
-}
-static void module_remove_refcnt_attr(struct module *mod)
-{
-}
-#endif
-
-#ifdef CONFIG_MODULE_UNLOAD
 static int module_add_modinfo_attrs(struct module *mod)
 {
 	struct module_attribute *attr;
+	struct module_attribute *temp_attr;
 	int error = 0;
 	int i;
 
+	mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) *
+					(ARRAY_SIZE(modinfo_attrs) + 1)),
+					GFP_KERNEL);
+	if (!mod->modinfo_attrs)
+		return -ENOMEM;
+
+	temp_attr = mod->modinfo_attrs;
 	for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) {
 		if (!attr->test ||
-		    (attr->test && attr->test(mod)))
-			error = sysfs_create_file(&mod->mkobj.kobj,&attr->attr);
+		    (attr->test && attr->test(mod))) {
+			memcpy(temp_attr, attr, sizeof(*temp_attr));
+			temp_attr->attr.owner = mod;
+			error = sysfs_create_file(&mod->mkobj.kobj,&temp_attr->attr);
+			++temp_attr;
+		}
 	}
 	return error;
 }
@@ -1096,12 +1141,16 @@
 	struct module_attribute *attr;
 	int i;
 
-	for (i = 0; (attr = modinfo_attrs[i]); i++) {
+	for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
+		/* pick a field to test for end of list */
+		if (!attr->attr.name)
+			break;
 		sysfs_remove_file(&mod->mkobj.kobj,&attr->attr);
-		attr->free(mod);
+		if (attr->free)
+			attr->free(mod);
 	}
+	kfree(mod->modinfo_attrs);
 }
-#endif
 
 static int mod_sysfs_setup(struct module *mod,
 			   struct kernel_param *kparam,
@@ -1119,19 +1168,13 @@
 	if (err)
 		goto out;
 
-	err = module_add_refcnt_attr(mod);
-	if (err)
-		goto out_unreg;
-
 	err = module_param_sysfs_setup(mod, kparam, num_params);
 	if (err)
 		goto out_unreg;
 
-#ifdef CONFIG_MODULE_UNLOAD
 	err = module_add_modinfo_attrs(mod);
 	if (err)
 		goto out_unreg;
-#endif
 
 	return 0;
 
@@ -1143,10 +1186,7 @@
 
 static void mod_kobject_remove(struct module *mod)
 {
-#ifdef CONFIG_MODULE_UNLOAD
 	module_remove_modinfo_attrs(mod);
-#endif
-	module_remove_refcnt_attr(mod);
 	module_param_sysfs_remove(mod);
 
 	kobject_unregister(&mod->mkobj.kobj);
@@ -1374,6 +1414,7 @@
 		|| strcmp(license, "GPL v2") == 0
 		|| strcmp(license, "GPL and additional rights") == 0
 		|| strcmp(license, "Dual BSD/GPL") == 0
+		|| strcmp(license, "Dual MIT/GPL") == 0
 		|| strcmp(license, "Dual MPL/GPL") == 0);
 }
 
@@ -1424,7 +1465,6 @@
 	return NULL;
 }
 
-#ifdef CONFIG_MODULE_UNLOAD
 static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
 			  unsigned int infoindex)
 {
@@ -1439,23 +1479,17 @@
 						attr->attr.name));
 	}
 }
-#endif
 
 #ifdef CONFIG_KALLSYMS
 int is_exported(const char *name, const struct module *mod)
 {
-	unsigned int i;
-
-	if (!mod) {
-		for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++)
-			if (strcmp(__start___ksymtab[i].name, name) == 0)
-				return 1;
-		return 0;
-	}
-	for (i = 0; i < mod->num_syms; i++)
-		if (strcmp(mod->syms[i].name, name) == 0)
+	if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab))
+		return 1;
+	else
+		if (lookup_symbol(name, mod->syms, mod->syms + mod->num_syms))
 			return 1;
-	return 0;
+		else
+			return 0;
 }
 
 /* As per nm */
@@ -1537,7 +1571,8 @@
 	char *secstrings, *args, *modmagic, *strtab = NULL;
 	unsigned int i, symindex = 0, strindex = 0, setupindex, exindex,
 		exportindex, modindex, obsparmindex, infoindex, gplindex,
-		crcindex, gplcrcindex, versindex, pcpuindex;
+		crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex,
+		gplfuturecrcindex;
 	long arglen;
 	struct module *mod;
 	long err = 0;
@@ -1618,8 +1653,10 @@
 	/* Optional sections */
 	exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab");
 	gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl");
+	gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future");
 	crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab");
 	gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl");
+	gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future");
 	setupindex = find_sec(hdr, sechdrs, secstrings, "__param");
 	exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table");
 	obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm");
@@ -1755,10 +1792,8 @@
 	if (strcmp(mod->name, "driverloader") == 0)
 		add_taint(TAINT_PROPRIETARY_MODULE);
 
-#ifdef CONFIG_MODULE_UNLOAD
 	/* Set up MODINFO_ATTR fields */
 	setup_modinfo(mod, sechdrs, infoindex);
-#endif
 
 	/* Fix up syms, so that st_value is a pointer to location. */
 	err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex,
@@ -1775,10 +1810,16 @@
 	mod->gpl_syms = (void *)sechdrs[gplindex].sh_addr;
 	if (gplcrcindex)
 		mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr;
+	mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size /
+					sizeof(*mod->gpl_future_syms);
+	mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr;
+	if (gplfuturecrcindex)
+		mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr;
 
 #ifdef CONFIG_MODVERSIONS
 	if ((mod->num_syms && !crcindex) || 
-	    (mod->num_gpl_syms && !gplcrcindex)) {
+	    (mod->num_gpl_syms && !gplcrcindex) ||
+	    (mod->num_gpl_future_syms && !gplfuturecrcindex)) {
 		printk(KERN_WARNING "%s: No versions for exported symbols."
 		       " Tainting kernel.\n", mod->name);
 		add_taint(TAINT_FORCED_MODULE);
@@ -1933,13 +1974,13 @@
 		return -EPERM;
 
 	/* Only one module load at a time, please */
-	if (down_interruptible(&module_mutex) != 0)
+	if (mutex_lock_interruptible(&module_mutex) != 0)
 		return -EINTR;
 
 	/* Do all the hard work */
 	mod = load_module(umod, len, uargs);
 	if (IS_ERR(mod)) {
-		up(&module_mutex);
+		mutex_unlock(&module_mutex);
 		return PTR_ERR(mod);
 	}
 
@@ -1948,11 +1989,11 @@
 	stop_machine_run(__link_module, mod, NR_CPUS);
 
 	/* Drop lock so they can recurse */
-	up(&module_mutex);
+	mutex_unlock(&module_mutex);
 
-	down(&notify_mutex);
+	mutex_lock(&notify_mutex);
 	notifier_call_chain(&module_notify_list, MODULE_STATE_COMING, mod);
-	up(&notify_mutex);
+	mutex_unlock(&notify_mutex);
 
 	/* Start the module */
 	if (mod->init != NULL)
@@ -1967,15 +2008,15 @@
 			       mod->name);
 		else {
 			module_put(mod);
-			down(&module_mutex);
+			mutex_lock(&module_mutex);
 			free_module(mod);
-			up(&module_mutex);
+			mutex_unlock(&module_mutex);
 		}
 		return ret;
 	}
 
 	/* Now it's a first class citizen! */
-	down(&module_mutex);
+	mutex_lock(&module_mutex);
 	mod->state = MODULE_STATE_LIVE;
 	/* Drop initial reference. */
 	module_put(mod);
@@ -1983,7 +2024,7 @@
 	mod->module_init = NULL;
 	mod->init_size = 0;
 	mod->init_text_size = 0;
-	up(&module_mutex);
+	mutex_unlock(&module_mutex);
 
 	return 0;
 }
@@ -2073,7 +2114,7 @@
 {
 	struct module *mod;
 
-	down(&module_mutex);
+	mutex_lock(&module_mutex);
 	list_for_each_entry(mod, &modules, list) {
 		if (symnum < mod->num_symtab) {
 			*value = mod->symtab[symnum].st_value;
@@ -2081,12 +2122,12 @@
 			strncpy(namebuf,
 				mod->strtab + mod->symtab[symnum].st_name,
 				127);
-			up(&module_mutex);
+			mutex_unlock(&module_mutex);
 			return mod;
 		}
 		symnum -= mod->num_symtab;
 	}
-	up(&module_mutex);
+	mutex_unlock(&module_mutex);
 	return NULL;
 }
 
@@ -2129,7 +2170,7 @@
 	struct list_head *i;
 	loff_t n = 0;
 
-	down(&module_mutex);
+	mutex_lock(&module_mutex);
 	list_for_each(i, &modules) {
 		if (n++ == *pos)
 			break;
@@ -2150,7 +2191,7 @@
 
 static void m_stop(struct seq_file *m, void *p)
 {
-	up(&module_mutex);
+	mutex_unlock(&module_mutex);
 }
 
 static int m_show(struct seq_file *m, void *p)
diff -urN oldtree/kernel/mutex-debug.c newtree/kernel/mutex-debug.c
--- oldtree/kernel/mutex-debug.c	2006-02-19 11:41:06.173404600 +0000
+++ newtree/kernel/mutex-debug.c	2006-02-21 15:58:28.866758144 +0000
@@ -153,13 +153,13 @@
 			continue;
 		count++;
 		cursor = curr->next;
-		debug_spin_lock_restore(&debug_mutex_lock, flags);
+		debug_spin_unlock_restore(&debug_mutex_lock, flags);
 
 		printk("\n#%03d:            ", count);
 		printk_lock(lock, filter ? 0 : 1);
 		goto next;
 	}
-	debug_spin_lock_restore(&debug_mutex_lock, flags);
+	debug_spin_unlock_restore(&debug_mutex_lock, flags);
 	printk("\n");
 }
 
@@ -316,7 +316,7 @@
 			continue;
 		list_del_init(curr);
 		DEBUG_OFF();
-		debug_spin_lock_restore(&debug_mutex_lock, flags);
+		debug_spin_unlock_restore(&debug_mutex_lock, flags);
 
 		printk("BUG: %s/%d, lock held at task exit time!\n",
 			task->comm, task->pid);
@@ -325,7 +325,7 @@
 			printk("exiting task is not even the owner??\n");
 		return;
 	}
-	debug_spin_lock_restore(&debug_mutex_lock, flags);
+	debug_spin_unlock_restore(&debug_mutex_lock, flags);
 }
 
 /*
@@ -352,7 +352,7 @@
 			continue;
 		list_del_init(curr);
 		DEBUG_OFF();
-		debug_spin_lock_restore(&debug_mutex_lock, flags);
+		debug_spin_unlock_restore(&debug_mutex_lock, flags);
 
 		printk("BUG: %s/%d, active lock [%p(%p-%p)] freed!\n",
 			current->comm, current->pid, lock, from, to);
@@ -362,7 +362,7 @@
 			printk("freeing task is not even the owner??\n");
 		return;
 	}
-	debug_spin_lock_restore(&debug_mutex_lock, flags);
+	debug_spin_unlock_restore(&debug_mutex_lock, flags);
 }
 
 /*
diff -urN oldtree/kernel/mutex-debug.h newtree/kernel/mutex-debug.h
--- oldtree/kernel/mutex-debug.h	2006-02-19 11:41:06.174404448 +0000
+++ newtree/kernel/mutex-debug.h	2006-02-21 15:58:28.878756320 +0000
@@ -46,21 +46,6 @@
 extern void debug_mutex_unlock(struct mutex *lock);
 extern void debug_mutex_init(struct mutex *lock, const char *name);
 
-#define debug_spin_lock(lock)				\
-	do {						\
-		local_irq_disable();			\
-		if (debug_mutex_on)			\
-			spin_lock(lock);		\
-	} while (0)
-
-#define debug_spin_unlock(lock)				\
-	do {						\
-		if (debug_mutex_on)			\
-			spin_unlock(lock);		\
-		local_irq_enable();			\
-		preempt_check_resched();		\
-	} while (0)
-
 #define debug_spin_lock_save(lock, flags)		\
 	do {						\
 		local_irq_save(flags);			\
@@ -68,7 +53,7 @@
 			spin_lock(lock);		\
 	} while (0)
 
-#define debug_spin_lock_restore(lock, flags)		\
+#define debug_spin_unlock_restore(lock, flags)		\
 	do {						\
 		if (debug_mutex_on)			\
 			spin_unlock(lock);		\
@@ -76,20 +61,20 @@
 		preempt_check_resched();		\
 	} while (0)
 
-#define spin_lock_mutex(lock)				\
+#define spin_lock_mutex(lock, flags)			\
 	do {						\
 		struct mutex *l = container_of(lock, struct mutex, wait_lock); \
 							\
 		DEBUG_WARN_ON(in_interrupt());		\
-		debug_spin_lock(&debug_mutex_lock);	\
+		debug_spin_lock_save(&debug_mutex_lock, flags); \
 		spin_lock(lock);			\
 		DEBUG_WARN_ON(l->magic != l);		\
 	} while (0)
 
-#define spin_unlock_mutex(lock)				\
+#define spin_unlock_mutex(lock, flags)			\
 	do {						\
 		spin_unlock(lock);			\
-		debug_spin_unlock(&debug_mutex_lock);	\
+		debug_spin_unlock_restore(&debug_mutex_lock, flags);	\
 	} while (0)
 
 #define DEBUG_OFF()					\
diff -urN oldtree/kernel/mutex.c newtree/kernel/mutex.c
--- oldtree/kernel/mutex.c	2006-02-19 11:41:06.174404448 +0000
+++ newtree/kernel/mutex.c	2006-02-21 15:58:28.865758296 +0000
@@ -125,10 +125,11 @@
 	struct task_struct *task = current;
 	struct mutex_waiter waiter;
 	unsigned int old_val;
+	unsigned long flags;
 
 	debug_mutex_init_waiter(&waiter);
 
-	spin_lock_mutex(&lock->wait_lock);
+	spin_lock_mutex(&lock->wait_lock, flags);
 
 	debug_mutex_add_waiter(lock, &waiter, task->thread_info, ip);
 
@@ -157,7 +158,7 @@
 		if (unlikely(state == TASK_INTERRUPTIBLE &&
 						signal_pending(task))) {
 			mutex_remove_waiter(lock, &waiter, task->thread_info);
-			spin_unlock_mutex(&lock->wait_lock);
+			spin_unlock_mutex(&lock->wait_lock, flags);
 
 			debug_mutex_free_waiter(&waiter);
 			return -EINTR;
@@ -165,9 +166,9 @@
 		__set_task_state(task, state);
 
 		/* didnt get the lock, go to sleep: */
-		spin_unlock_mutex(&lock->wait_lock);
+		spin_unlock_mutex(&lock->wait_lock, flags);
 		schedule();
-		spin_lock_mutex(&lock->wait_lock);
+		spin_lock_mutex(&lock->wait_lock, flags);
 	}
 
 	/* got the lock - rejoice! */
@@ -178,7 +179,7 @@
 	if (likely(list_empty(&lock->wait_list)))
 		atomic_set(&lock->count, 0);
 
-	spin_unlock_mutex(&lock->wait_lock);
+	spin_unlock_mutex(&lock->wait_lock, flags);
 
 	debug_mutex_free_waiter(&waiter);
 
@@ -203,10 +204,11 @@
 __mutex_unlock_slowpath(atomic_t *lock_count __IP_DECL__)
 {
 	struct mutex *lock = container_of(lock_count, struct mutex, count);
+	unsigned long flags;
 
 	DEBUG_WARN_ON(lock->owner != current_thread_info());
 
-	spin_lock_mutex(&lock->wait_lock);
+	spin_lock_mutex(&lock->wait_lock, flags);
 
 	/*
 	 * some architectures leave the lock unlocked in the fastpath failure
@@ -231,7 +233,7 @@
 
 	debug_mutex_clear_owner(lock);
 
-	spin_unlock_mutex(&lock->wait_lock);
+	spin_unlock_mutex(&lock->wait_lock, flags);
 }
 
 /*
@@ -276,9 +278,10 @@
 static inline int __mutex_trylock_slowpath(atomic_t *lock_count)
 {
 	struct mutex *lock = container_of(lock_count, struct mutex, count);
+	unsigned long flags;
 	int prev;
 
-	spin_lock_mutex(&lock->wait_lock);
+	spin_lock_mutex(&lock->wait_lock, flags);
 
 	prev = atomic_xchg(&lock->count, -1);
 	if (likely(prev == 1))
@@ -287,7 +290,7 @@
 	if (likely(list_empty(&lock->wait_list)))
 		atomic_set(&lock->count, 0);
 
-	spin_unlock_mutex(&lock->wait_lock);
+	spin_unlock_mutex(&lock->wait_lock, flags);
 
 	return prev == 1;
 }
diff -urN oldtree/kernel/mutex.h newtree/kernel/mutex.h
--- oldtree/kernel/mutex.h	2006-02-19 11:41:06.175404296 +0000
+++ newtree/kernel/mutex.h	2006-02-21 15:58:28.878756320 +0000
@@ -9,8 +9,10 @@
  * !CONFIG_DEBUG_MUTEXES case. Most of them are NOPs:
  */
 
-#define spin_lock_mutex(lock)			spin_lock(lock)
-#define spin_unlock_mutex(lock)			spin_unlock(lock)
+#define spin_lock_mutex(lock, flags) \
+		do { spin_lock(lock); (void)(flags); } while (0)
+#define spin_unlock_mutex(lock, flags) \
+		do { spin_unlock(lock); (void)(flags); } while (0)
 #define mutex_remove_waiter(lock, waiter, ti) \
 		__list_del((waiter)->list.prev, (waiter)->list.next)
 
diff -urN oldtree/kernel/params.c newtree/kernel/params.c
--- oldtree/kernel/params.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/kernel/params.c	2006-02-21 15:58:12.776204280 +0000
@@ -638,13 +638,8 @@
 	if (!attribute->show)
 		return -EIO;
 
-	if (!try_module_get(mk->mod))
-		return -ENODEV;
-
 	ret = attribute->show(attribute, mk->mod, buf);
 
-	module_put(mk->mod);
-
 	return ret;
 }
 
@@ -662,13 +657,8 @@
 	if (!attribute->store)
 		return -EIO;
 
-	if (!try_module_get(mk->mod))
-		return -ENODEV;
-
 	ret = attribute->store(attribute, mk->mod, buf, len);
 
-	module_put(mk->mod);
-
 	return ret;
 }
 
diff -urN oldtree/kernel/posix-timers.c newtree/kernel/posix-timers.c
--- oldtree/kernel/posix-timers.c	2006-02-19 11:41:06.179403688 +0000
+++ newtree/kernel/posix-timers.c	2006-02-21 15:58:23.849520880 +0000
@@ -35,6 +35,7 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/time.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
diff -urN oldtree/kernel/power/Kconfig newtree/kernel/power/Kconfig
--- oldtree/kernel/power/Kconfig	2006-02-19 11:41:06.180403536 +0000
+++ newtree/kernel/power/Kconfig	2006-02-21 15:58:36.947529680 +0000
@@ -38,7 +38,7 @@
 
 config SOFTWARE_SUSPEND
 	bool "Software Suspend"
-	depends on PM && SWAP && (X86 && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP)
+	depends on PM && SWAP && (X86 && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP) && (BROKEN || !FRV)
 	---help---
 	  Enable the possibility of suspending the machine.
 	  It doesn't need APM.
diff -urN oldtree/kernel/power/pm.c newtree/kernel/power/pm.c
--- oldtree/kernel/power/pm.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/kernel/power/pm.c	2006-02-21 15:58:23.850520728 +0000
@@ -25,6 +25,7 @@
 #include <linux/pm.h>
 #include <linux/pm_legacy.h>
 #include <linux/interrupt.h>
+#include <linux/mutex.h>
 
 int pm_active;
 
@@ -40,7 +41,7 @@
  *	until a resume but that will be fine.
  */
  
-static DECLARE_MUTEX(pm_devs_lock);
+static DEFINE_MUTEX(pm_devs_lock);
 static LIST_HEAD(pm_devs);
 
 /**
@@ -67,9 +68,9 @@
 		dev->id = id;
 		dev->callback = callback;
 
-		down(&pm_devs_lock);
+		mutex_lock(&pm_devs_lock);
 		list_add(&dev->entry, &pm_devs);
-		up(&pm_devs_lock);
+		mutex_unlock(&pm_devs_lock);
 	}
 	return dev;
 }
@@ -85,9 +86,9 @@
 void pm_unregister(struct pm_dev *dev)
 {
 	if (dev) {
-		down(&pm_devs_lock);
+		mutex_lock(&pm_devs_lock);
 		list_del(&dev->entry);
-		up(&pm_devs_lock);
+		mutex_unlock(&pm_devs_lock);
 
 		kfree(dev);
 	}
@@ -118,7 +119,7 @@
 	if (!callback)
 		return;
 
-	down(&pm_devs_lock);
+	mutex_lock(&pm_devs_lock);
 	entry = pm_devs.next;
 	while (entry != &pm_devs) {
 		struct pm_dev *dev = list_entry(entry, struct pm_dev, entry);
@@ -126,7 +127,7 @@
 		if (dev->callback == callback)
 			__pm_unregister(dev);
 	}
-	up(&pm_devs_lock);
+	mutex_unlock(&pm_devs_lock);
 }
 
 /**
@@ -234,7 +235,7 @@
 {
 	struct list_head *entry;
 	
-	down(&pm_devs_lock);
+	mutex_lock(&pm_devs_lock);
 	entry = pm_devs.next;
 	while (entry != &pm_devs) {
 		struct pm_dev *dev = list_entry(entry, struct pm_dev, entry);
@@ -246,13 +247,13 @@
 				 */
 				if (rqst == PM_SUSPEND)
 					pm_undo_all(dev);
-				up(&pm_devs_lock);
+				mutex_unlock(&pm_devs_lock);
 				return status;
 			}
 		}
 		entry = entry->next;
 	}
-	up(&pm_devs_lock);
+	mutex_unlock(&pm_devs_lock);
 	return 0;
 }
 
diff -urN oldtree/kernel/power/snapshot.c newtree/kernel/power/snapshot.c
--- oldtree/kernel/power/snapshot.c	2006-02-19 11:41:06.182403232 +0000
+++ newtree/kernel/power/snapshot.c	2006-02-21 15:58:23.172623784 +0000
@@ -80,7 +80,7 @@
 		void *kaddr;
 		unsigned long pfn = zone_pfn + zone->zone_start_pfn;
 
-		if (!(pfn%1000))
+		if (!(pfn%10000))
 			printk(".");
 		if (!pfn_valid(pfn))
 			continue;
@@ -119,13 +119,14 @@
 	struct zone *zone;
 	int res = 0;
 
-	pr_debug("swsusp: Saving Highmem\n");
+	pr_debug("swsusp: Saving Highmem");
 	for_each_zone (zone) {
 		if (is_highmem(zone))
 			res = save_highmem_zone(zone);
 		if (res)
 			return res;
 	}
+	printk("\n");
 	return 0;
 }
 
diff -urN oldtree/kernel/profile.c newtree/kernel/profile.c
--- oldtree/kernel/profile.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/kernel/profile.c	2006-02-21 15:58:23.850520728 +0000
@@ -23,6 +23,7 @@
 #include <linux/cpu.h>
 #include <linux/profile.h>
 #include <linux/highmem.h>
+#include <linux/mutex.h>
 #include <asm/sections.h>
 #include <asm/semaphore.h>
 
@@ -44,7 +45,7 @@
 #ifdef CONFIG_SMP
 static DEFINE_PER_CPU(struct profile_hit *[2], cpu_profile_hits);
 static DEFINE_PER_CPU(int, cpu_profile_flip);
-static DECLARE_MUTEX(profile_flip_mutex);
+static DEFINE_MUTEX(profile_flip_mutex);
 #endif /* CONFIG_SMP */
 
 static int __init profile_setup(char * str)
@@ -243,7 +244,7 @@
 {
 	int i, j, cpu;
 
-	down(&profile_flip_mutex);
+	mutex_lock(&profile_flip_mutex);
 	j = per_cpu(cpu_profile_flip, get_cpu());
 	put_cpu();
 	on_each_cpu(__profile_flip_buffers, NULL, 0, 1);
@@ -259,14 +260,14 @@
 			hits[i].hits = hits[i].pc = 0;
 		}
 	}
-	up(&profile_flip_mutex);
+	mutex_unlock(&profile_flip_mutex);
 }
 
 static void profile_discard_flip_buffers(void)
 {
 	int i, cpu;
 
-	down(&profile_flip_mutex);
+	mutex_lock(&profile_flip_mutex);
 	i = per_cpu(cpu_profile_flip, get_cpu());
 	put_cpu();
 	on_each_cpu(__profile_flip_buffers, NULL, 0, 1);
@@ -274,7 +275,7 @@
 		struct profile_hit *hits = per_cpu(cpu_profile_hits, cpu)[i];
 		memset(hits, 0, NR_PROFILE_HIT*sizeof(struct profile_hit));
 	}
-	up(&profile_flip_mutex);
+	mutex_unlock(&profile_flip_mutex);
 }
 
 void profile_hit(int type, void *__pc)
diff -urN oldtree/kernel/rcupdate.c newtree/kernel/rcupdate.c
--- oldtree/kernel/rcupdate.c	2006-02-19 11:41:06.187402472 +0000
+++ newtree/kernel/rcupdate.c	2006-02-21 15:58:23.723540032 +0000
@@ -47,6 +47,7 @@
 #include <linux/notifier.h>
 #include <linux/rcupdate.h>
 #include <linux/cpu.h>
+#include <linux/mutex.h>
 
 /* Definition for rcupdate control block. */
 struct rcu_ctrlblk rcu_ctrlblk = {
@@ -100,7 +101,7 @@
 }
 
 static atomic_t rcu_barrier_cpu_count;
-static struct semaphore rcu_barrier_sema;
+static DEFINE_MUTEX(rcu_barrier_mutex);
 static struct completion rcu_barrier_completion;
 
 /**
@@ -175,13 +176,13 @@
 void rcu_barrier(void)
 {
 	BUG_ON(in_interrupt());
-	/* Take cpucontrol semaphore to protect against CPU hotplug */
-	down(&rcu_barrier_sema);
+	/* Take cpucontrol mutex to protect against CPU hotplug */
+	mutex_lock(&rcu_barrier_mutex);
 	init_completion(&rcu_barrier_completion);
 	atomic_set(&rcu_barrier_cpu_count, 0);
 	on_each_cpu(rcu_barrier_func, NULL, 0, 1);
 	wait_for_completion(&rcu_barrier_completion);
-	up(&rcu_barrier_sema);
+	mutex_unlock(&rcu_barrier_mutex);
 }
 EXPORT_SYMBOL_GPL(rcu_barrier);
 
@@ -514,7 +515,6 @@
  */
 void __init rcu_init(void)
 {
-	sema_init(&rcu_barrier_sema, 1);
 	rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE,
 			(void *)(long)smp_processor_id());
 	/* Register notifier for non-boot CPUs */
@@ -569,7 +569,7 @@
 
 module_param(maxbatch, int, 0);
 EXPORT_SYMBOL_GPL(rcu_batches_completed);
-EXPORT_SYMBOL(call_rcu);  /* WARNING: GPL-only in April 2006. */
-EXPORT_SYMBOL(call_rcu_bh);  /* WARNING: GPL-only in April 2006. */
+EXPORT_SYMBOL_GPL_FUTURE(call_rcu);	/* WARNING: GPL-only in April 2006. */
+EXPORT_SYMBOL_GPL_FUTURE(call_rcu_bh);	/* WARNING: GPL-only in April 2006. */
 EXPORT_SYMBOL_GPL(synchronize_rcu);
-EXPORT_SYMBOL(synchronize_kernel);  /* WARNING: GPL-only in April 2006. */
+EXPORT_SYMBOL_GPL_FUTURE(synchronize_kernel); /* WARNING: GPL-only in April 2006. */
diff -urN oldtree/kernel/signal.c newtree/kernel/signal.c
--- oldtree/kernel/signal.c	2006-02-19 11:41:06.195401256 +0000
+++ newtree/kernel/signal.c	2006-02-21 15:58:30.670483936 +0000
@@ -1120,27 +1120,37 @@
 /*
  * Must be called under rcu_read_lock() or with tasklist_lock read-held.
  */
+struct sighand_struct *lock_task_sighand(struct task_struct *tsk, unsigned long *flags)
+{
+	struct sighand_struct *sighand;
+
+	for (;;) {
+		sighand = rcu_dereference(tsk->sighand);
+		if (unlikely(sighand == NULL))
+			break;
+
+		spin_lock_irqsave(&sighand->siglock, *flags);
+		if (likely(sighand == tsk->sighand))
+			break;
+		spin_unlock_irqrestore(&sighand->siglock, *flags);
+	}
+
+	return sighand;
+}
+
 int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
 {
 	unsigned long flags;
-	struct sighand_struct *sp;
 	int ret;
 
-retry:
 	ret = check_kill_permission(sig, info, p);
-	if (!ret && sig && (sp = rcu_dereference(p->sighand))) {
-		spin_lock_irqsave(&sp->siglock, flags);
-		if (p->sighand != sp) {
-			spin_unlock_irqrestore(&sp->siglock, flags);
-			goto retry;
-		}
-		if ((atomic_read(&sp->count) == 0) ||
-				(atomic_read(&p->usage) == 0)) {
-			spin_unlock_irqrestore(&sp->siglock, flags);
-			return -ESRCH;
+
+	if (!ret && sig) {
+		ret = -ESRCH;
+		if (lock_task_sighand(p, &flags)) {
+			ret = __group_send_sig_info(sig, info, p);
+			unlock_task_sighand(p, &flags);
 		}
-		ret = __group_send_sig_info(sig, info, p);
-		spin_unlock_irqrestore(&sp->siglock, flags);
 	}
 
 	return ret;
@@ -1988,7 +1998,7 @@
 			continue;
 
 		/* Init gets no signals it doesn't want.  */
-		if (current->pid == 1)
+		if (current == child_reaper)
 			continue;
 
 		if (sig_kernel_stop(signr)) {
diff -urN oldtree/kernel/spinlock.c newtree/kernel/spinlock.c
--- oldtree/kernel/spinlock.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/kernel/spinlock.c	2006-02-21 15:58:29.099722728 +0000
@@ -179,16 +179,16 @@
 #define BUILD_LOCK_OPS(op, locktype)					\
 void __lockfunc _##op##_lock(locktype##_t *lock)			\
 {									\
-	preempt_disable();						\
 	for (;;) {							\
+		preempt_disable();					\
 		if (likely(_raw_##op##_trylock(lock)))			\
 			break;						\
 		preempt_enable();					\
+									\
 		if (!(lock)->break_lock)				\
 			(lock)->break_lock = 1;				\
 		while (!op##_can_lock(lock) && (lock)->break_lock)	\
 			cpu_relax();					\
-		preempt_disable();					\
 	}								\
 	(lock)->break_lock = 0;						\
 }									\
@@ -199,19 +199,18 @@
 {									\
 	unsigned long flags;						\
 									\
-	preempt_disable();						\
 	for (;;) {							\
+		preempt_disable();					\
 		local_irq_save(flags);					\
 		if (likely(_raw_##op##_trylock(lock)))			\
 			break;						\
 		local_irq_restore(flags);				\
-									\
 		preempt_enable();					\
+									\
 		if (!(lock)->break_lock)				\
 			(lock)->break_lock = 1;				\
 		while (!op##_can_lock(lock) && (lock)->break_lock)	\
 			cpu_relax();					\
-		preempt_disable();					\
 	}								\
 	(lock)->break_lock = 0;						\
 	return flags;							\
diff -urN oldtree/kernel/synchro-test.c newtree/kernel/synchro-test.c
--- oldtree/kernel/synchro-test.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/kernel/synchro-test.c	2006-02-21 15:58:31.992282992 +0000
@@ -0,0 +1,527 @@
+/* synchro-test.c: run some threads to test the synchronisation primitives
+ *
+ * Copyright (C) 2005, 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * The module should be run as something like:
+ *
+ *	insmod synchro-test.ko rd=2 wr=2
+ *	insmod synchro-test.ko mx=1
+ *	insmod synchro-test.ko sm=2 ism=1
+ *	insmod synchro-test.ko sm=2 ism=2
+ *
+ * See Documentation/synchro-test.txt for more information.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/moduleparam.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+#include <asm/atomic.h>
+#include <linux/personality.h>
+#include <linux/smp_lock.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+
+#define MAX_THREADS 64
+
+/*
+ * Turn on self-validation if we do a one-shot boot-time test:
+ */
+#ifndef MODULE
+# define VALIDATE_OPERATORS
+#endif
+
+static int nummx;
+static int numsm, seminit = 4;
+static int numrd, numwr, numdg;
+static int elapse = 5, load = 2, do_sched, interval = 2;
+static int verbose = 0;
+
+MODULE_AUTHOR("David Howells");
+MODULE_DESCRIPTION("Synchronisation primitive test demo");
+MODULE_LICENSE("GPL");
+
+module_param_named(v, verbose, int, 0);
+MODULE_PARM_DESC(verbose, "Verbosity");
+
+module_param_named(mx, nummx, int, 0);
+MODULE_PARM_DESC(nummx, "Number of mutex threads");
+
+module_param_named(sm, numsm, int, 0);
+MODULE_PARM_DESC(numsm, "Number of semaphore threads");
+
+module_param_named(ism, seminit, int, 0);
+MODULE_PARM_DESC(seminit, "Initial semaphore value");
+
+module_param_named(rd, numrd, int, 0);
+MODULE_PARM_DESC(numrd, "Number of reader threads");
+
+module_param_named(wr, numwr, int, 0);
+MODULE_PARM_DESC(numwr, "Number of writer threads");
+
+module_param_named(dg, numdg, int, 0);
+MODULE_PARM_DESC(numdg, "Number of downgrader threads");
+
+module_param(elapse, int, 0);
+MODULE_PARM_DESC(elapse, "Number of seconds to run for");
+
+module_param(load, int, 0);
+MODULE_PARM_DESC(load, "Length of load in uS");
+
+module_param(interval, int, 0);
+MODULE_PARM_DESC(interval, "Length of interval in uS before re-getting lock");
+
+module_param(do_sched, int, 0);
+MODULE_PARM_DESC(do_sched, "True if each thread should schedule regularly");
+
+/* the semaphores under test */
+static struct mutex ____cacheline_aligned mutex;
+static struct semaphore ____cacheline_aligned sem;
+static struct rw_semaphore ____cacheline_aligned rwsem;
+
+static atomic_t ____cacheline_aligned do_stuff		= ATOMIC_INIT(0);
+
+#ifdef VALIDATE_OPERATORS
+static atomic_t ____cacheline_aligned mutexes		= ATOMIC_INIT(0);
+static atomic_t ____cacheline_aligned semaphores	= ATOMIC_INIT(0);
+static atomic_t ____cacheline_aligned readers		= ATOMIC_INIT(0);
+static atomic_t ____cacheline_aligned writers		= ATOMIC_INIT(0);
+#endif
+
+static unsigned int ____cacheline_aligned mutexes_taken		[MAX_THREADS];
+static unsigned int ____cacheline_aligned semaphores_taken	[MAX_THREADS];
+static unsigned int ____cacheline_aligned reads_taken		[MAX_THREADS];
+static unsigned int ____cacheline_aligned writes_taken		[MAX_THREADS];
+static unsigned int ____cacheline_aligned downgrades_taken	[MAX_THREADS];
+
+static struct completion ____cacheline_aligned mx_comp[MAX_THREADS];
+static struct completion ____cacheline_aligned sm_comp[MAX_THREADS];
+static struct completion ____cacheline_aligned rd_comp[MAX_THREADS];
+static struct completion ____cacheline_aligned wr_comp[MAX_THREADS];
+static struct completion ____cacheline_aligned dg_comp[MAX_THREADS];
+
+static struct timer_list ____cacheline_aligned timer;
+
+#define ACCOUNT(var, N) var##_taken[N]++;
+
+#ifdef VALIDATE_OPERATORS
+#define TRACK(var, dir) atomic_##dir(&(var))
+
+#define CHECK(var, cond, val)						\
+do {									\
+	int x = atomic_read(&(var));					\
+	if (unlikely(!(x cond (val))))					\
+		printk("check [%s %s %d, == %d] failed in %s\n",	\
+		       #var, #cond, (val), x, __func__);		\
+} while (0)
+
+#else
+#define TRACK(var, dir)		do {} while(0)
+#define CHECK(var, cond, val)	do {} while(0)
+#endif
+
+static inline void do_mutex_lock(unsigned int N)
+{
+	mutex_lock(&mutex);
+
+	ACCOUNT(mutexes, N);
+	TRACK(mutexes, inc);
+	CHECK(mutexes, ==, 1);
+}
+
+static inline void do_mutex_unlock(unsigned int N)
+{
+	CHECK(mutexes, ==, 1);
+	TRACK(mutexes, dec);
+
+	mutex_unlock(&mutex);
+}
+
+static inline void do_down(unsigned int N)
+{
+	CHECK(mutexes, <, seminit);
+
+	down(&sem);
+
+	ACCOUNT(semaphores, N);
+	TRACK(semaphores, inc);
+}
+
+static inline void do_up(unsigned int N)
+{
+	CHECK(semaphores, >, 0);
+	TRACK(semaphores, dec);
+
+	up(&sem);
+}
+
+static inline void do_down_read(unsigned int N)
+{
+	down_read(&rwsem);
+
+	ACCOUNT(reads, N);
+	TRACK(readers, inc);
+	CHECK(readers, >, 0);
+	CHECK(writers, ==, 0);
+}
+
+static inline void do_up_read(unsigned int N)
+{
+	CHECK(readers, >, 0);
+	CHECK(writers, ==, 0);
+	TRACK(readers, dec);
+
+	up_read(&rwsem);
+}
+
+static inline void do_down_write(unsigned int N)
+{
+	down_write(&rwsem);
+
+	ACCOUNT(writes, N);
+	TRACK(writers, inc);
+	CHECK(writers, ==, 1);
+	CHECK(readers, ==, 0);
+}
+
+static inline void do_up_write(unsigned int N)
+{
+	CHECK(writers, ==, 1);
+	CHECK(readers, ==, 0);
+	TRACK(writers, dec);
+
+	up_write(&rwsem);
+}
+
+static inline void do_downgrade_write(unsigned int N)
+{
+	CHECK(writers, ==, 1);
+	CHECK(readers, ==, 0);
+	TRACK(writers, dec);
+	TRACK(readers, inc);
+
+	downgrade_write(&rwsem);
+
+	ACCOUNT(downgrades, N);
+}
+
+static inline void sched(void)
+{
+	if (do_sched)
+		schedule();
+}
+
+static int mutexer(void *arg)
+{
+	unsigned int N = (unsigned long) arg;
+
+	daemonize("Mutex%u", N);
+	set_user_nice(current, 19);
+
+	while (atomic_read(&do_stuff)) {
+		do_mutex_lock(N);
+		if (load)
+			udelay(load);
+		do_mutex_unlock(N);
+		sched();
+		if (interval)
+			udelay(interval);
+	}
+
+	if (verbose >= 2)
+		printk("%s: done\n", current->comm);
+	complete_and_exit(&mx_comp[N], 0);
+}
+
+static int semaphorer(void *arg)
+{
+	unsigned int N = (unsigned long) arg;
+
+	daemonize("Sem%u", N);
+	set_user_nice(current, 19);
+
+	while (atomic_read(&do_stuff)) {
+		do_down(N);
+		if (load)
+			udelay(load);
+		do_up(N);
+		sched();
+		if (interval)
+			udelay(interval);
+	}
+
+	if (verbose >= 2)
+		printk("%s: done\n", current->comm);
+	complete_and_exit(&sm_comp[N], 0);
+}
+
+static int reader(void *arg)
+{
+	unsigned int N = (unsigned long) arg;
+
+	daemonize("Read%u", N);
+	set_user_nice(current, 19);
+
+	while (atomic_read(&do_stuff)) {
+		do_down_read(N);
+#ifdef LOAD_TEST
+		if (load)
+			udelay(load);
+#endif
+		do_up_read(N);
+		sched();
+		if (interval)
+			udelay(interval);
+	}
+
+	if (verbose >= 2)
+		printk("%s: done\n", current->comm);
+	complete_and_exit(&rd_comp[N], 0);
+}
+
+static int writer(void *arg)
+{
+	unsigned int N = (unsigned long) arg;
+
+	daemonize("Write%u", N);
+	set_user_nice(current, 19);
+
+	while (atomic_read(&do_stuff)) {
+		do_down_write(N);
+#ifdef LOAD_TEST
+		if (load)
+			udelay(load);
+#endif
+		do_up_write(N);
+		sched();
+		if (interval)
+			udelay(interval);
+	}
+
+	if (verbose >= 2)
+		printk("%s: done\n", current->comm);
+	complete_and_exit(&wr_comp[N], 0);
+}
+
+static int downgrader(void *arg)
+{
+	unsigned int N = (unsigned long) arg;
+
+	daemonize("Down%u", N);
+	set_user_nice(current, 19);
+
+	while (atomic_read(&do_stuff)) {
+		do_down_write(N);
+#ifdef LOAD_TEST
+		if (load)
+			udelay(load);
+#endif
+		do_downgrade_write(N);
+#ifdef LOAD_TEST
+		if (load)
+			udelay(load);
+#endif
+		do_up_read(N);
+		sched();
+		if (interval)
+			udelay(interval);
+	}
+
+	if (verbose >= 2)
+		printk("%s: done\n", current->comm);
+	complete_and_exit(&dg_comp[N], 0);
+}
+
+static void stop_test(unsigned long dummy)
+{
+	atomic_set(&do_stuff, 0);
+}
+
+static unsigned int total(const char *what, unsigned int counts[], int num)
+{
+	unsigned int tot = 0, max = 0, min = UINT_MAX, zeros = 0, cnt;
+	int loop;
+
+	for (loop = 0; loop < num; loop++) {
+		cnt = counts[loop];
+
+		if (cnt == 0) {
+			zeros++;
+			min = 0;
+			continue;
+		}
+
+		tot += cnt;
+		if (tot > max)
+			max = tot;
+		if (tot < min)
+			min = tot;
+	}
+
+	if (verbose && tot > 0) {
+		printk("%s:", what);
+
+		for (loop = 0; loop < num; loop++) {
+			cnt = counts[loop];
+
+			if (cnt == 0)
+				printk(" zzz");
+			else
+				printk(" %d%%", cnt * 100 / tot);
+		}
+
+		printk("\n");
+	}
+
+	return tot;
+}
+
+/*****************************************************************************/
+/*
+ *
+ */
+static int __init do_tests(void)
+{
+	unsigned long loop;
+	unsigned int mutex_total, sem_total, rd_total, wr_total, dg_total;
+
+	if (nummx < 0 || nummx > MAX_THREADS ||
+	    numsm < 0 || numsm > MAX_THREADS ||
+	    numrd < 0 || numrd > MAX_THREADS ||
+	    numwr < 0 || numwr > MAX_THREADS ||
+	    numdg < 0 || numdg > MAX_THREADS ||
+	    seminit < 1 ||
+	    elapse < 1 ||
+	    load < 0 || load > 999 ||
+	    interval < 0 || interval > 999
+	    ) {
+		printk("Parameter out of range\n");
+		return -ERANGE;
+	}
+
+	if ((nummx | numsm | numrd | numwr | numdg) == 0) {
+		int num = num_online_cpus();
+
+		if (num > MAX_THREADS)
+			num = MAX_THREADS;
+		nummx = numsm = numrd = numwr = numdg = num;
+
+		load = 1;
+		interval = 1;
+		do_sched = 1;
+		printk("No parameters - using defaults.\n");
+	}
+
+	if (verbose)
+		printk("\nStarting synchronisation primitive tests...\n");
+
+	mutex_init(&mutex);
+	sema_init(&sem, seminit);
+	init_rwsem(&rwsem);
+	atomic_set(&do_stuff, 1);
+
+	/* kick off all the children */
+	for (loop = 0; loop < MAX_THREADS; loop++) {
+		if (loop < nummx) {
+			init_completion(&mx_comp[loop]);
+			kernel_thread(mutexer, (void *) loop, 0);
+		}
+
+		if (loop < numsm) {
+			init_completion(&sm_comp[loop]);
+			kernel_thread(semaphorer, (void *) loop, 0);
+		}
+
+		if (loop < numrd) {
+			init_completion(&rd_comp[loop]);
+			kernel_thread(reader, (void *) loop, 0);
+		}
+
+		if (loop < numwr) {
+			init_completion(&wr_comp[loop]);
+			kernel_thread(writer, (void *) loop, 0);
+		}
+
+		if (loop < numdg) {
+			init_completion(&dg_comp[loop]);
+			kernel_thread(downgrader, (void *) loop, 0);
+		}
+	}
+
+	/* set a stop timer */
+	init_timer(&timer);
+	timer.function = stop_test;
+	timer.expires = jiffies + elapse * HZ;
+	add_timer(&timer);
+
+	/* now wait until it's all done */
+	for (loop = 0; loop < nummx; loop++)
+		wait_for_completion(&mx_comp[loop]);
+
+	for (loop = 0; loop < numsm; loop++)
+		wait_for_completion(&sm_comp[loop]);
+
+	for (loop = 0; loop < numrd; loop++)
+		wait_for_completion(&rd_comp[loop]);
+
+	for (loop = 0; loop < numwr; loop++)
+		wait_for_completion(&wr_comp[loop]);
+
+	for (loop = 0; loop < numdg; loop++)
+		wait_for_completion(&dg_comp[loop]);
+
+	atomic_set(&do_stuff, 0);
+	del_timer(&timer);
+
+	if (mutex_is_locked(&mutex))
+		printk(KERN_ERR "Mutex is still locked!\n");
+
+	/* count up */
+	mutex_total	= total("MTX", mutexes_taken, nummx);
+	sem_total	= total("SEM", semaphores_taken, numsm);
+	rd_total	= total("RD ", reads_taken, numrd);
+	wr_total	= total("WR ", writes_taken, numwr);
+	dg_total	= total("DG ", downgrades_taken, numdg);
+
+	/* print the results */
+	if (verbose) {
+		printk("mutexes taken: %u\n", mutex_total);
+		printk("semaphores taken: %u\n", sem_total);
+		printk("reads taken: %u\n", rd_total);
+		printk("writes taken: %u\n", wr_total);
+		printk("downgrades taken: %u\n", dg_total);
+	}
+	else {
+		char buf[30];
+
+		sprintf(buf, "%d/%d", interval, load);
+
+		printk("%3d %3d %3d %3d %3d %c %5s %9u %9u %9u %9u %9u\n",
+		       nummx, numsm, numrd, numwr, numdg,
+		       do_sched ? 's' : '-',
+		       buf,
+		       mutex_total,
+		       sem_total,
+		       rd_total,
+		       wr_total,
+		       dg_total);
+	}
+
+	/* tell insmod to discard the module */
+	if (verbose)
+		printk("Tests complete\n");
+	return -ENOANO;
+
+} /* end do_tests() */
+
+module_init(do_tests);
diff -urN oldtree/kernel/sys.c newtree/kernel/sys.c
--- oldtree/kernel/sys.c	2006-02-19 11:41:06.196401104 +0000
+++ newtree/kernel/sys.c	2006-02-21 15:58:30.230550816 +0000
@@ -1227,7 +1227,7 @@
 	struct pid *pid;
 	int err = -EPERM;
 
-	down(&tty_sem);
+	mutex_lock(&tty_mutex);
 	write_lock_irq(&tasklist_lock);
 
 	pid = find_pid(PIDTYPE_PGID, group_leader->pid);
@@ -1241,7 +1241,7 @@
 	err = process_group(group_leader);
 out:
 	write_unlock_irq(&tasklist_lock);
-	up(&tty_sem);
+	mutex_unlock(&tty_mutex);
 	return err;
 }
 
@@ -1630,20 +1630,21 @@
 asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim)
 {
 	struct rlimit new_rlim, *old_rlim;
+	unsigned long it_prof_secs;
 	int retval;
 
 	if (resource >= RLIM_NLIMITS)
 		return -EINVAL;
-	if(copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
+	if (copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
 		return -EFAULT;
-       if (new_rlim.rlim_cur > new_rlim.rlim_max)
-               return -EINVAL;
+	if (new_rlim.rlim_cur > new_rlim.rlim_max)
+		return -EINVAL;
 	old_rlim = current->signal->rlim + resource;
 	if ((new_rlim.rlim_max > old_rlim->rlim_max) &&
 	    !capable(CAP_SYS_RESOURCE))
 		return -EPERM;
 	if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > NR_OPEN)
-			return -EPERM;
+		return -EPERM;
 
 	retval = security_task_setrlimit(resource, &new_rlim);
 	if (retval)
@@ -1653,19 +1654,22 @@
 	*old_rlim = new_rlim;
 	task_unlock(current->group_leader);
 
-	if (resource == RLIMIT_CPU && new_rlim.rlim_cur != RLIM_INFINITY &&
-	    (cputime_eq(current->signal->it_prof_expires, cputime_zero) ||
-	     new_rlim.rlim_cur <= cputime_to_secs(
-		     current->signal->it_prof_expires))) {
+	if (resource != RLIMIT_CPU)
+		goto out;
+	if (new_rlim.rlim_cur == RLIM_INFINITY)
+		goto out;
+
+	it_prof_secs = cputime_to_secs(current->signal->it_prof_expires);
+	if (it_prof_secs == 0 || new_rlim.rlim_cur <= it_prof_secs) {
 		cputime_t cputime = secs_to_cputime(new_rlim.rlim_cur);
+
 		read_lock(&tasklist_lock);
 		spin_lock_irq(&current->sighand->siglock);
-		set_process_cpu_timer(current, CPUCLOCK_PROF,
-				      &cputime, NULL);
+		set_process_cpu_timer(current, CPUCLOCK_PROF, &cputime, NULL);
 		spin_unlock_irq(&current->sighand->siglock);
 		read_unlock(&tasklist_lock);
 	}
-
+out:
 	return 0;
 }
 
@@ -1677,9 +1681,6 @@
  * a lot simpler!  (Which we're not doing right now because we're not
  * measuring them yet).
  *
- * This expects to be called with tasklist_lock read-locked or better,
- * and the siglock not locked.  It may momentarily take the siglock.
- *
  * When sampling multiple threads for RUSAGE_SELF, under SMP we might have
  * races with threads incrementing their own counters.  But since word
  * reads are atomic, we either get new values or old values and we don't
@@ -1687,6 +1688,25 @@
  * the c* fields from p->signal from races with exit.c updating those
  * fields when reaping, so a sample either gets all the additions of a
  * given child after it's reaped, or none so this sample is before reaping.
+ *
+ * tasklist_lock locking optimisation:
+ * If we are current and single threaded, we do not need to take the tasklist
+ * lock or the siglock.  No one else can take our signal_struct away,
+ * no one else can reap the children to update signal->c* counters, and
+ * no one else can race with the signal-> fields.
+ * If we do not take the tasklist_lock, the signal-> fields could be read
+ * out of order while another thread was just exiting. So we place a
+ * read memory barrier when we avoid the lock.  On the writer side,
+ * write memory barrier is implied in  __exit_signal as __exit_signal releases
+ * the siglock spinlock after updating the signal-> fields.
+ *
+ * We don't really need the siglock when we access the non c* fields
+ * of the signal_struct (for RUSAGE_SELF) even in multithreaded
+ * case, since we take the tasklist lock for read and the non c* signal->
+ * fields are updated only in __exit_signal, which is called with
+ * tasklist_lock taken for write, hence these two threads cannot execute
+ * concurrently.
+ *
  */
 
 static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
@@ -1694,13 +1714,23 @@
 	struct task_struct *t;
 	unsigned long flags;
 	cputime_t utime, stime;
+	int need_lock = 0;
 
 	memset((char *) r, 0, sizeof *r);
+	utime = stime = cputime_zero;
 
-	if (unlikely(!p->signal))
-		return;
+	if (p != current || !thread_group_empty(p))
+		need_lock = 1;
 
-	utime = stime = cputime_zero;
+	if (need_lock) {
+		read_lock(&tasklist_lock);
+		if (unlikely(!p->signal)) {
+			read_unlock(&tasklist_lock);
+			return;
+		}
+	} else
+		/* See locking comments above */
+		smp_rmb();
 
 	switch (who) {
 		case RUSAGE_BOTH:
@@ -1740,6 +1770,8 @@
 			BUG();
 	}
 
+	if (need_lock)
+		read_unlock(&tasklist_lock);
 	cputime_to_timeval(utime, &r->ru_utime);
 	cputime_to_timeval(stime, &r->ru_stime);
 }
@@ -1747,9 +1779,7 @@
 int getrusage(struct task_struct *p, int who, struct rusage __user *ru)
 {
 	struct rusage r;
-	read_lock(&tasklist_lock);
 	k_getrusage(p, who, &r);
-	read_unlock(&tasklist_lock);
 	return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
 }
 
diff -urN oldtree/kernel/sysctl.c newtree/kernel/sysctl.c
--- oldtree/kernel/sysctl.c	2006-02-19 11:41:06.198400800 +0000
+++ newtree/kernel/sysctl.c	2006-02-21 15:58:08.776812280 +0000
@@ -44,14 +44,12 @@
 #include <linux/limits.h>
 #include <linux/dcache.h>
 #include <linux/syscalls.h>
+#include <linux/nfs_fs.h>
+#include <linux/acpi.h>
 
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 
-#ifdef CONFIG_ROOT_NFS
-#include <linux/nfs_fs.h>
-#endif
-
 #if defined(CONFIG_SYSCTL)
 
 /* External variables not in a header file. */
@@ -656,6 +654,16 @@
 		.proc_handler	= &proc_dointvec,
 	},
 #endif
+#ifdef CONFIG_ACPI_SLEEP
+	{
+		.ctl_name	= KERN_ACPI_VIDEO_FLAGS,
+		.procname	= "acpi_video_flags",
+		.data		= &acpi_video_flags,
+		.maxlen		= sizeof (unsigned long),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+#endif
 	{ .ctl_name = 0 }
 };
 
diff -urN oldtree/lib/Kconfig.debug newtree/lib/Kconfig.debug
--- oldtree/lib/Kconfig.debug	2006-02-19 11:41:06.202400192 +0000
+++ newtree/lib/Kconfig.debug	2006-02-21 15:58:37.482448360 +0000
@@ -23,6 +23,15 @@
 	  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
 	  unless you really know what this hack does.
 
+config DEBUG_SHIRQ
+       bool "Debug shared IRQ handlers"
+       depends on GENERIC_HARDIRQS
+       help
+         Enable this to generate a spurious interrupt as soon as a shared interrupt
+	 handler is registered, and just before one is deregistered. Drivers ought
+	 to be able to handle interrupts coming in at those points; some don't and
+	 need to be caught.
+
 config DEBUG_KERNEL
 	bool "Kernel debugging"
 	help
@@ -195,6 +204,17 @@
 	  some architectures or if you use external debuggers.
 	  If you don't debug the kernel, you can say N.
 
+config UNWIND_INFO
+	bool "Compile the kernel with frame unwind information"
+	depends on !IA64
+	depends on !MODULES || !(MIPS || PARISC || PPC || SUPERH || SPARC64 || V850)
+	default DEBUG_KERNEL
+	help
+	  If you say Y here the resulting kernel image will be slightly larger
+	  but not slower, and it will give very useful debugging information.
+	  If you don't debug the kernel, you can say N, but we may not be able
+	  to solve problems without frame unwind information or frame pointers.
+
 config FORCED_INLINING
 	bool "Force gcc to inline functions marked 'inline'"
 	depends on DEBUG_KERNEL
@@ -222,3 +242,17 @@
 	  at boot time (you probably don't).
 	  Say M if you want the RCU torture tests to build as a module.
 	  Say N if you are unsure.
+
+config DEBUG_SYNCHRO_TEST
+	tristate "Synchronisation primitive testing module"
+	depends on DEBUG_KERNEL
+	default n
+	help
+	  This option provides a kernel module that can thrash the sleepable
+	  synchronisation primitives (mutexes and semaphores).
+
+	  You should say N or M here. Whilst the module can be built in, it's
+	  not recommended as it requires module parameters supplying to get it
+	  to do anything.
+
+	  See Documentation/synchro-test.txt.
diff -urN oldtree/lib/bitmap.c newtree/lib/bitmap.c
--- oldtree/lib/bitmap.c	2006-02-19 11:41:06.204399888 +0000
+++ newtree/lib/bitmap.c	2006-02-21 15:58:29.251699624 +0000
@@ -677,39 +677,38 @@
 EXPORT_SYMBOL(bitmap_bitremap);
 
 /**
- *	bitmap_find_free_region - find a contiguous aligned mem region
+ * bitmap_find_free_region - find a contiguous aligned mem region
  *	@bitmap: an array of unsigned longs corresponding to the bitmap
  *	@bits: number of bits in the bitmap
  *	@order: region size to find (size is actually 1<<order)
  *
- * This is used to allocate a memory region from a bitmap.  The idea is
- * that the region has to be 1<<order sized and 1<<order aligned (this
- * makes the search algorithm much faster).
+ * Find a sequence of free (zero) bits in a bitmap and allocate
+ * them (set them to one).  Only consider sequences of length a
+ * power ('order') of two, aligned to that power of two, which
+ * makes the search algorithm much faster.
  *
- * The region is marked as set bits in the bitmap if a free one is
- * found.
- *
- * Returns either beginning of region or negative error
+ * Return the bit offset in bitmap of the allocated sequence,
+ * or -errno on failure.
  */
 int bitmap_find_free_region(unsigned long *bitmap, int bits, int order)
 {
 	unsigned long mask;
-	int pages = 1 << order;
+	int nbits = 1 << order;
 	int i;
 
-	if(pages > BITS_PER_LONG)
+	if (nbits > BITS_PER_LONG)
 		return -EINVAL;
 
 	/* make a mask of the order */
-	mask = (1ul << (pages - 1));
+	mask = (1UL << (nbits - 1));
 	mask += mask - 1;
 
-	/* run up the bitmap pages bits at a time */
-	for (i = 0; i < bits; i += pages) {
-		int index = i/BITS_PER_LONG;
+	/* run up the bitmap nbits at a time */
+	for (i = 0; i < bits; i += nbits) {
+		int index = i / BITS_PER_LONG;
 		int offset = i - (index * BITS_PER_LONG);
-		if((bitmap[index] & (mask << offset)) == 0) {
-			/* set region in bimap */
+		if ((bitmap[index] & (mask << offset)) == 0) {
+			/* set region in bitmap */
 			bitmap[index] |= (mask << offset);
 			return i;
 		}
@@ -719,7 +718,7 @@
 EXPORT_SYMBOL(bitmap_find_free_region);
 
 /**
- *	bitmap_release_region - release allocated bitmap region
+ * bitmap_release_region - release allocated bitmap region
  *	@bitmap: a pointer to the bitmap
  *	@pos: the beginning of the region
  *	@order: the order of the bits to release (number is 1<<order)
@@ -729,27 +728,40 @@
  */
 void bitmap_release_region(unsigned long *bitmap, int pos, int order)
 {
-	int pages = 1 << order;
-	unsigned long mask = (1ul << (pages - 1));
-	int index = pos/BITS_PER_LONG;
+	int nbits = 1 << order;
+	unsigned long mask = (1UL << (nbits - 1));
+	int index = pos / BITS_PER_LONG;
 	int offset = pos - (index * BITS_PER_LONG);
+
 	mask += mask - 1;
 	bitmap[index] &= ~(mask << offset);
 }
 EXPORT_SYMBOL(bitmap_release_region);
 
+/**
+ * bitmap_allocate_region - allocate bitmap region
+ *	@bitmap: a pointer to the bitmap
+ *	@pos: the beginning of the region
+ *	@order: the order of the bits to allocate (number is 1<<order)
+ *
+ * Allocate (set bits in) a specified region of a bitmap.
+ * Return 0 on success, or -EBUSY if specified region wasn't
+ * free (not all bits were zero).
+ */
 int bitmap_allocate_region(unsigned long *bitmap, int pos, int order)
 {
-	int pages = 1 << order;
-	unsigned long mask = (1ul << (pages - 1));
-	int index = pos/BITS_PER_LONG;
+	int nbits = 1 << order;
+	unsigned long mask = (1UL << (nbits - 1));
+	int index = pos / BITS_PER_LONG;
 	int offset = pos - (index * BITS_PER_LONG);
 
-	/* We don't do regions of pages > BITS_PER_LONG.  The
+	/*
+	 * We don't do regions of nbits > BITS_PER_LONG.  The
 	 * algorithm would be a simple look for multiple zeros in the
 	 * array, but there's no driver today that needs this.  If you
-	 * trip this BUG(), you get to code it... */
-	BUG_ON(pages > BITS_PER_LONG);
+	 * trip this BUG(), you get to code it...
+	 */
+	BUG_ON(nbits > BITS_PER_LONG);
 	mask += mask - 1;
 	if (bitmap[index] & (mask << offset))
 		return -EBUSY;
diff -urN oldtree/lib/extable.c newtree/lib/extable.c
--- oldtree/lib/extable.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/lib/extable.c	2006-02-21 15:58:17.566476048 +0000
@@ -1,5 +1,4 @@
 /*
- * lib/extable.c
  * Derived from arch/ppc/mm/extable.c and arch/i386/mm/extable.c.
  *
  * Copyright (C) 2004 Paul Mackerras, IBM Corp.
diff -urN oldtree/lib/iomap_copy.c newtree/lib/iomap_copy.c
--- oldtree/lib/iomap_copy.c	2006-02-19 11:41:06.205399736 +0000
+++ newtree/lib/iomap_copy.c	2006-02-21 15:58:36.953528768 +0000
@@ -15,8 +15,8 @@
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
-#include <linux/io.h>
 #include <linux/module.h>
+#include <linux/io.h>
 
 /**
  * __iowrite32_copy - copy data to MMIO space, in 32-bit units
diff -urN oldtree/lib/kobject.c newtree/lib/kobject.c
--- oldtree/lib/kobject.c	2006-02-19 11:41:06.206399584 +0000
+++ newtree/lib/kobject.c	2006-02-21 15:58:12.345269792 +0000
@@ -128,6 +128,7 @@
 {
 	kref_init(&kobj->kref);
 	INIT_LIST_HEAD(&kobj->entry);
+	init_waitqueue_head(&kobj->poll);
 	kobj->kset = kset_get(kobj->kset);
 }
 
diff -urN oldtree/lib/kref.c newtree/lib/kref.c
--- oldtree/lib/kref.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/lib/kref.c	2006-02-21 15:58:12.554238024 +0000
@@ -52,7 +52,12 @@
 	WARN_ON(release == NULL);
 	WARN_ON(release == (void (*)(struct kref *))kfree);
 
-	if (atomic_dec_and_test(&kref->refcount)) {
+	/*
+	 * if current count is one, we are the last user and can release object
+	 * right now, avoiding an atomic operation on 'refcount'
+	 */
+	if ((atomic_read(&kref->refcount) == 1) ||
+	    (atomic_dec_and_test(&kref->refcount))) {
 		release(kref);
 		return 1;
 	}
diff -urN oldtree/lib/parser.c newtree/lib/parser.c
--- oldtree/lib/parser.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/lib/parser.c	2006-02-21 15:58:23.522570584 +0000
@@ -140,6 +140,64 @@
 }
 
 /**
+ * match_u64: scan a number in the given base from a substring_t
+ * @s: substring to be scanned
+ * @result: resulting integer on success
+ * @base: base to use when converting string
+ *
+ * Description: Given a &substring_t and a base, attempts to parse the substring
+ * as a number in that base. On success, sets @result to the u64 represented
+ * by the string and returns 0. Returns either -ENOMEM or -EINVAL on failure.
+ */
+int match_u64(substring_t *s, u64 *result, int base)
+{
+        char *endp;
+        char *buf;
+        int ret;
+
+        buf = kmalloc(s->to - s->from + 1, GFP_KERNEL);
+        if (!buf)
+                return -ENOMEM;
+        memcpy(buf, s->from, s->to - s->from);
+        buf[s->to - s->from] = '\0';
+        *result = simple_strtoull(buf, &endp, base);
+        ret = 0;
+        if (endp == buf)
+                ret = -EINVAL;
+        kfree(buf);
+        return ret;
+}
+
+/**
+ * match_s64: scan a number in the given base from a substring_t
+ * @s: substring to be scanned
+ * @result: resulting integer on success
+ * @base: base to use when converting string
+ *
+ * Description: Given a &substring_t and a base, attempts to parse the substring
+ * as a number in that base. On success, sets @result to the s64 represented
+ * by the string and returns 0. Returns either -ENOMEM or -EINVAL on failure.
+ */
+int match_s64(substring_t *s, s64 *result, int base)
+{
+        char *endp;
+        char *buf;
+        int ret;
+
+        buf = kmalloc(s->to - s->from + 1, GFP_KERNEL);
+        if (!buf)
+                return -ENOMEM;
+        memcpy(buf, s->from, s->to - s->from);
+        buf[s->to - s->from] = '\0';
+        *result = simple_strtoll(buf, &endp, base);
+        ret = 0;
+        if (endp == buf)
+                ret = -EINVAL;
+        kfree(buf);
+        return ret;
+}
+
+/**
  * match_int: - scan a decimal representation of an integer from a substring_t
  * @s: substring_t to be scanned
  * @result: resulting integer on success
@@ -218,3 +276,5 @@
 EXPORT_SYMBOL(match_hex);
 EXPORT_SYMBOL(match_strcpy);
 EXPORT_SYMBOL(match_strdup);
+EXPORT_SYMBOL(match_u64);
+EXPORT_SYMBOL(match_s64);
diff -urN oldtree/lib/radix-tree.c newtree/lib/radix-tree.c
--- oldtree/lib/radix-tree.c	2006-02-19 11:41:06.208399280 +0000
+++ newtree/lib/radix-tree.c	2006-02-21 15:58:33.868997688 +0000
@@ -134,6 +134,7 @@
 out:
 	return ret;
 }
+EXPORT_SYMBOL(radix_tree_preload);
 
 static inline void tag_set(struct radix_tree_node *node, int tag, int offset)
 {
diff -urN oldtree/lib/reed_solomon/reed_solomon.c newtree/lib/reed_solomon/reed_solomon.c
--- oldtree/lib/reed_solomon/reed_solomon.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/lib/reed_solomon/reed_solomon.c	2006-02-21 15:58:23.851520576 +0000
@@ -44,12 +44,13 @@
 #include <linux/module.h>
 #include <linux/rslib.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
 #include <asm/semaphore.h>
 
 /* This list holds all currently allocated rs control structures */
 static LIST_HEAD (rslist);
 /* Protection for the list */
-static DECLARE_MUTEX(rslistlock);
+static DEFINE_MUTEX(rslistlock);
 
 /**
  * rs_init - Initialize a Reed-Solomon codec
@@ -161,7 +162,7 @@
  */
 void free_rs(struct rs_control *rs)
 {
-	down(&rslistlock);
+	mutex_lock(&rslistlock);
 	rs->users--;
 	if(!rs->users) {
 		list_del(&rs->list);
@@ -170,7 +171,7 @@
 		kfree(rs->genpoly);
 		kfree(rs);
 	}
-	up(&rslistlock);
+	mutex_unlock(&rslistlock);
 }
 
 /**
@@ -201,7 +202,7 @@
 	if (nroots < 0 || nroots >= (1<<symsize))
 		return NULL;
 
-	down(&rslistlock);
+	mutex_lock(&rslistlock);
 
 	/* Walk through the list and look for a matching entry */
 	list_for_each(tmp, &rslist) {
@@ -228,7 +229,7 @@
 		list_add(&rs->list, &rslist);
 	}
 out:
-	up(&rslistlock);
+	mutex_unlock(&rslistlock);
 	return rs;
 }
 
diff -urN oldtree/mm/filemap.c newtree/mm/filemap.c
--- oldtree/mm/filemap.c	2006-02-19 11:41:06.215398216 +0000
+++ newtree/mm/filemap.c	2006-02-21 15:58:33.883995408 +0000
@@ -29,6 +29,7 @@
 #include <linux/blkdev.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
+#include <linux/cpuset.h>
 #include "filemap.h"
 /*
  * FIXME: remove all knowledge of the buffer layer from the core VM
@@ -119,6 +120,7 @@
 	mapping->nrpages--;
 	pagecache_acct(-1);
 }
+EXPORT_SYMBOL(__remove_from_page_cache);
 
 void remove_from_page_cache(struct page *page)
 {
@@ -130,6 +132,7 @@
 	__remove_from_page_cache(page);
 	write_unlock_irq(&mapping->tree_lock);
 }
+EXPORT_SYMBOL(remove_from_page_cache);
 
 static int sync_page(void *word)
 {
@@ -172,7 +175,7 @@
  * dirty pages that lie within the byte offsets <start, end>
  * @mapping:	address space structure to write
  * @start:	offset in bytes where the range starts
- * @end:	offset in bytes where the range ends
+ * @end:	offset in bytes where the range ends (inclusive)
  * @sync_mode:	enable synchronous operation
  *
  * If sync_mode is WB_SYNC_ALL then this is a "data integrity" operation, as
@@ -272,6 +275,7 @@
 
 	return ret;
 }
+EXPORT_SYMBOL(add_to_page_cache_lru);
 
 /*
  * Write and wait upon all the pages in the passed range.  This is a "data
@@ -365,6 +369,12 @@
 }
 EXPORT_SYMBOL(filemap_write_and_wait);
 
+/*
+ * Write out and wait upon file offsets lstart->lend, inclusive.
+ *
+ * Note that `lend' is inclusive (describes the last byte to be written) so
+ * that this function can be used to write to the very end-of-file (end = -1).
+ */
 int filemap_write_and_wait_range(struct address_space *mapping,
 				 loff_t lstart, loff_t lend)
 {
@@ -425,6 +435,28 @@
 	return ret;
 }
 
+#ifdef CONFIG_NUMA
+struct page *page_cache_alloc(struct address_space *x)
+{
+	if (cpuset_do_page_mem_spread()) {
+		int n = cpuset_mem_spread_node();
+		return alloc_pages_node(n, mapping_gfp_mask(x), 0);
+	}
+	return alloc_pages(mapping_gfp_mask(x), 0);
+}
+EXPORT_SYMBOL(page_cache_alloc);
+
+struct page *page_cache_alloc_cold(struct address_space *x)
+{
+	if (cpuset_do_page_mem_spread()) {
+		int n = cpuset_mem_spread_node();
+		return alloc_pages_node(n, mapping_gfp_mask(x)|__GFP_COLD, 0);
+	}
+	return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD, 0);
+}
+EXPORT_SYMBOL(page_cache_alloc_cold);
+#endif
+
 /*
  * In order to wait for pages to become available there must be
  * waitqueues associated with pages. By using a hash table of
@@ -665,6 +697,7 @@
 	read_unlock_irq(&mapping->tree_lock);
 	return ret;
 }
+EXPORT_SYMBOL(find_get_pages);
 
 /*
  * Like find_get_pages, except we only return pages which are tagged with
@@ -686,6 +719,7 @@
 	read_unlock_irq(&mapping->tree_lock);
 	return ret;
 }
+EXPORT_SYMBOL(find_get_pages_tag);
 
 /*
  * Same as grab_cache_page, but do not wait if the page is unavailable.
diff -urN oldtree/mm/highmem.c newtree/mm/highmem.c
--- oldtree/mm/highmem.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/mm/highmem.c	2006-02-21 15:58:30.715477096 +0000
@@ -26,18 +26,14 @@
 #include <linux/init.h>
 #include <linux/hash.h>
 #include <linux/highmem.h>
+#include <linux/blktrace_api.h>
 #include <asm/tlbflush.h>
 
 static mempool_t *page_pool, *isa_page_pool;
 
-static void *page_pool_alloc_isa(gfp_t gfp_mask, void *data)
+static void *mempool_alloc_pages_isa(gfp_t gfp_mask, void *data)
 {
-	return alloc_page(gfp_mask | GFP_DMA);
-}
-
-static void page_pool_free(void *page, void *data)
-{
-	__free_page(page);
+	return mempool_alloc_pages(gfp_mask | GFP_DMA, data);
 }
 
 /*
@@ -50,11 +46,6 @@
  */
 #ifdef CONFIG_HIGHMEM
 
-static void *page_pool_alloc(gfp_t gfp_mask, void *data)
-{
-	return alloc_page(gfp_mask);
-}
-
 static int pkmap_count[LAST_PKMAP];
 static unsigned int last_pkmap_nr;
 static  __cacheline_aligned_in_smp DEFINE_SPINLOCK(kmap_lock);
@@ -228,7 +219,7 @@
 	if (!i.totalhigh)
 		return 0;
 
-	page_pool = mempool_create(POOL_SIZE, page_pool_alloc, page_pool_free, NULL);
+	page_pool = mempool_create_page_pool(POOL_SIZE, 0);
 	if (!page_pool)
 		BUG();
 	printk("highmem bounce pool size: %d pages\n", POOL_SIZE);
@@ -271,7 +262,8 @@
 	if (isa_page_pool)
 		return 0;
 
-	isa_page_pool = mempool_create(ISA_POOL_SIZE, page_pool_alloc_isa, page_pool_free, NULL);
+	isa_page_pool = mempool_create(ISA_POOL_SIZE, mempool_alloc_pages_isa,
+				       mempool_free_pages, (void *) 0);
 	if (!isa_page_pool)
 		BUG();
 
@@ -336,7 +328,7 @@
 	bio_put(bio);
 }
 
-static int bounce_end_io_write(struct bio *bio, unsigned int bytes_done,int err)
+static int bounce_end_io_write(struct bio *bio, unsigned int bytes_done, int err)
 {
 	if (bio->bi_size)
 		return 1;
@@ -383,7 +375,7 @@
 }
 
 static void __blk_queue_bounce(request_queue_t *q, struct bio **bio_orig,
-			mempool_t *pool)
+			       mempool_t *pool)
 {
 	struct page *page;
 	struct bio *bio = NULL;
@@ -483,6 +475,8 @@
 		pool = isa_page_pool;
 	}
 
+	blk_add_trace_bio(q, *bio_orig, BLK_TA_BOUNCE);
+
 	/*
 	 * slow path
 	 */
diff -urN oldtree/mm/hugetlb.c newtree/mm/hugetlb.c
--- oldtree/mm/hugetlb.c	2006-02-19 11:41:06.217397912 +0000
+++ newtree/mm/hugetlb.c	2006-02-21 15:58:22.133781712 +0000
@@ -64,7 +64,7 @@
 	return page;
 }
 
-static struct page *alloc_fresh_huge_page(void)
+static int alloc_fresh_huge_page(void)
 {
 	static int nid = 0;
 	struct page *page;
@@ -72,12 +72,15 @@
 					HUGETLB_PAGE_ORDER);
 	nid = (nid + 1) % num_online_nodes();
 	if (page) {
+		page[1].lru.next = (void *)free_huge_page;	/* dtor */
 		spin_lock(&hugetlb_lock);
 		nr_huge_pages++;
 		nr_huge_pages_node[page_to_nid(page)]++;
 		spin_unlock(&hugetlb_lock);
+		put_page(page); /* free it into the hugepage allocator */
+		return 1;
 	}
-	return page;
+	return 0;
 }
 
 void free_huge_page(struct page *page)
@@ -85,7 +88,6 @@
 	BUG_ON(page_count(page));
 
 	INIT_LIST_HEAD(&page->lru);
-	page[1].lru.next = NULL;			/* reset dtor */
 
 	spin_lock(&hugetlb_lock);
 	enqueue_huge_page(page);
@@ -105,7 +107,6 @@
 	}
 	spin_unlock(&hugetlb_lock);
 	set_page_count(page, 1);
-	page[1].lru.next = (void *)free_huge_page;	/* set dtor */
 	for (i = 0; i < (HPAGE_SIZE/PAGE_SIZE); ++i)
 		clear_user_highpage(&page[i], addr);
 	return page;
@@ -114,7 +115,6 @@
 static int __init hugetlb_init(void)
 {
 	unsigned long i;
-	struct page *page;
 
 	if (HPAGE_SHIFT == 0)
 		return 0;
@@ -123,12 +123,8 @@
 		INIT_LIST_HEAD(&hugepage_freelists[i]);
 
 	for (i = 0; i < max_huge_pages; ++i) {
-		page = alloc_fresh_huge_page();
-		if (!page)
+		if (!alloc_fresh_huge_page())
 			break;
-		spin_lock(&hugetlb_lock);
-		enqueue_huge_page(page);
-		spin_unlock(&hugetlb_lock);
 	}
 	max_huge_pages = free_huge_pages = nr_huge_pages = i;
 	printk("Total HugeTLB memory allocated, %ld\n", free_huge_pages);
@@ -154,8 +150,8 @@
 		page[i].flags &= ~(1 << PG_locked | 1 << PG_error | 1 << PG_referenced |
 				1 << PG_dirty | 1 << PG_active | 1 << PG_reserved |
 				1 << PG_private | 1<< PG_writeback);
-		set_page_count(&page[i], 0);
 	}
+	page[1].lru.next = NULL;
 	set_page_count(page, 1);
 	__free_pages(page, HUGETLB_PAGE_ORDER);
 }
@@ -188,12 +184,8 @@
 static unsigned long set_max_huge_pages(unsigned long count)
 {
 	while (count > nr_huge_pages) {
-		struct page *page = alloc_fresh_huge_page();
-		if (!page)
+		if (!alloc_fresh_huge_page())
 			return nr_huge_pages;
-		spin_lock(&hugetlb_lock);
-		enqueue_huge_page(page);
-		spin_unlock(&hugetlb_lock);
 	}
 	if (count >= nr_huge_pages)
 		return nr_huge_pages;
diff -urN oldtree/mm/mempolicy.c newtree/mm/mempolicy.c
--- oldtree/mm/mempolicy.c	2006-02-19 11:41:06.221397304 +0000
+++ newtree/mm/mempolicy.c	2006-02-21 15:58:29.642640192 +0000
@@ -421,6 +421,37 @@
 	return mpol_check_policy(mode, nodes);
 }
 
+
+/*
+ * Update task->flags PF_MEMPOLICY bit: set iff non-default
+ * mempolicy.  Allows more rapid checking of this (combined perhaps
+ * with other PF_* flag bits) on memory allocation hot code paths.
+ *
+ * If called from outside this file, the task 'p' should -only- be
+ * a newly forked child not yet visible on the task list, because
+ * manipulating the task flags of a visible task is not safe.
+ *
+ * The above limitation is why this routine has the funny name
+ * mpol_fix_fork_child_flag().
+ *
+ * It is also safe to call this with a task pointer of current,
+ * which the static wrapper mpol_set_task_struct_flag() does,
+ * for use within this file.
+ */
+
+void mpol_fix_fork_child_flag(struct task_struct *p)
+{
+	if (p->mempolicy)
+		p->flags |= PF_MEMPOLICY;
+	else
+		p->flags &= ~PF_MEMPOLICY;
+}
+
+static void mpol_set_task_struct_flag(void)
+{
+	mpol_fix_fork_child_flag(current);
+}
+
 /* Set the process memory policy */
 long do_set_mempolicy(int mode, nodemask_t *nodes)
 {
@@ -433,6 +464,7 @@
 		return PTR_ERR(new);
 	mpol_free(current->mempolicy);
 	current->mempolicy = new;
+	mpol_set_task_struct_flag();
 	if (new && new->policy == MPOL_INTERLEAVE)
 		current->il_next = first_node(new->v.nodes);
 	return 0;
diff -urN oldtree/mm/mempool.c newtree/mm/mempool.c
--- oldtree/mm/mempool.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/mm/mempool.c	2006-02-21 15:58:30.783466760 +0000
@@ -289,3 +289,45 @@
 	kmem_cache_free(mem, element);
 }
 EXPORT_SYMBOL(mempool_free_slab);
+
+/*
+ * A commonly used alloc and free fn that kmalloc/kfrees the amount of memory
+ * specfied by pool_data
+ */
+void *mempool_kmalloc(gfp_t gfp_mask, void *pool_data)
+{
+	size_t size = (size_t)(long)pool_data;
+	return kmalloc(size, gfp_mask);
+}
+EXPORT_SYMBOL(mempool_kmalloc);
+
+void *mempool_kzalloc(gfp_t gfp_mask, void *pool_data)
+{
+	size_t size = (size_t) pool_data;
+	return kzalloc(size, gfp_mask);
+}
+EXPORT_SYMBOL(mempool_kzalloc);
+
+void mempool_kfree(void *element, void *pool_data)
+{
+	kfree(element);
+}
+EXPORT_SYMBOL(mempool_kfree);
+
+/*
+ * A simple mempool-backed page allocator that allocates pages
+ * of the order specified by pool_data.
+ */
+void *mempool_alloc_pages(gfp_t gfp_mask, void *pool_data)
+{
+	int order = (int)(long)pool_data;
+	return alloc_pages(gfp_mask, order);
+}
+EXPORT_SYMBOL(mempool_alloc_pages);
+
+void mempool_free_pages(void *element, void *pool_data)
+{
+	int order = (int)(long)pool_data;
+	__free_pages(element, order);
+}
+EXPORT_SYMBOL(mempool_free_pages);
diff -urN oldtree/mm/page-writeback.c newtree/mm/page-writeback.c
--- oldtree/mm/page-writeback.c	2006-02-19 11:41:06.226396544 +0000
+++ newtree/mm/page-writeback.c	2006-02-21 15:58:29.909599608 +0000
@@ -255,8 +255,9 @@
 }
 
 /**
- * balance_dirty_pages_ratelimited - balance dirty memory state
+ * balance_dirty_pages_ratelimited_nr - balance dirty memory state
  * @mapping: address_space which was dirtied
+ * @nr_pages: number of pages which the caller has just dirtied
  *
  * Processes which are dirtying memory should call in here once for each page
  * which was newly dirtied.  The function will periodically check the system's
@@ -267,10 +268,12 @@
  * limit we decrease the ratelimiting by a lot, to prevent individual processes
  * from overshooting the limit by (ratelimit_pages) each.
  */
-void balance_dirty_pages_ratelimited(struct address_space *mapping)
+void balance_dirty_pages_ratelimited_nr(struct address_space *mapping,
+					unsigned long nr_pages_dirtied)
 {
-	static DEFINE_PER_CPU(int, ratelimits) = 0;
-	long ratelimit;
+	static DEFINE_PER_CPU(unsigned long, ratelimits) = 0;
+	unsigned long ratelimit;
+	unsigned long *p;
 
 	ratelimit = ratelimit_pages;
 	if (dirty_exceeded)
@@ -280,15 +283,18 @@
 	 * Check the rate limiting. Also, we do not want to throttle real-time
 	 * tasks in balance_dirty_pages(). Period.
 	 */
-	if (get_cpu_var(ratelimits)++ >= ratelimit) {
-		__get_cpu_var(ratelimits) = 0;
-		put_cpu_var(ratelimits);
+	preempt_disable();
+	p =  &__get_cpu_var(ratelimits);
+	*p += nr_pages_dirtied;
+	if (unlikely(*p >= ratelimit)) {
+		*p = 0;
+		preempt_enable();
 		balance_dirty_pages(mapping);
 		return;
 	}
-	put_cpu_var(ratelimits);
+	preempt_enable();
 }
-EXPORT_SYMBOL(balance_dirty_pages_ratelimited);
+EXPORT_SYMBOL(balance_dirty_pages_ratelimited_nr);
 
 void throttle_vm_writeout(void)
 {
@@ -621,8 +627,6 @@
  */
 int __set_page_dirty_nobuffers(struct page *page)
 {
-	int ret = 0;
-
 	if (!TestSetPageDirty(page)) {
 		struct address_space *mapping = page_mapping(page);
 		struct address_space *mapping2;
@@ -644,8 +648,9 @@
 							I_DIRTY_PAGES);
 			}
 		}
+		return 1;
 	}
-	return ret;
+	return 0;
 }
 EXPORT_SYMBOL(__set_page_dirty_nobuffers);
 
@@ -675,8 +680,10 @@
 			return (*spd)(page);
 		return __set_page_dirty_buffers(page);
 	}
-	if (!PageDirty(page))
-		SetPageDirty(page);
+	if (!PageDirty(page)) {
+		if (!TestSetPageDirty(page))
+			return 1;
+	}
 	return 0;
 }
 EXPORT_SYMBOL(set_page_dirty);
diff -urN oldtree/mm/page_alloc.c newtree/mm/page_alloc.c
--- oldtree/mm/page_alloc.c	2006-02-19 11:41:06.228396240 +0000
+++ newtree/mm/page_alloc.c	2006-02-21 15:58:29.518659040 +0000
@@ -927,7 +927,8 @@
 		goto got_pg;
 
 	do {
-		wakeup_kswapd(*z, order);
+		if (cpuset_zone_allowed(*z, gfp_mask))
+			wakeup_kswapd(*z, order);
 	} while (*(++z));
 
 	/*
diff -urN oldtree/mm/readahead.c newtree/mm/readahead.c
--- oldtree/mm/readahead.c	2006-02-19 11:41:06.229396088 +0000
+++ newtree/mm/readahead.c	2006-02-21 15:58:33.110113056 +0000
@@ -38,6 +38,7 @@
 	ra->ra_pages = mapping->backing_dev_info->ra_pages;
 	ra->prev_page = -1;
 }
+EXPORT_SYMBOL_GPL(file_ra_state_init);
 
 /*
  * Return max readahead size for this inode in number-of-pages.
@@ -541,6 +542,7 @@
 out:
 	return ra->prev_page + 1;
 }
+EXPORT_SYMBOL(page_cache_readahead);
 
 /*
  * handle_ra_miss() is called when it is known that a page which should have
@@ -558,6 +560,7 @@
 	ra->flags &= ~RA_FLAG_INCACHE;
 	ra->cache_hit = 0;
 }
+EXPORT_SYMBOL(handle_ra_miss);
 
 /*
  * Given a desired number of PAGE_CACHE_SIZE readahead pages, return a
diff -urN oldtree/mm/slab.c newtree/mm/slab.c
--- oldtree/mm/slab.c	2006-02-19 11:41:06.239394568 +0000
+++ newtree/mm/slab.c	2006-02-21 15:58:29.644639888 +0000
@@ -94,6 +94,7 @@
 #include	<linux/interrupt.h>
 #include	<linux/init.h>
 #include	<linux/compiler.h>
+#include	<linux/cpuset.h>
 #include	<linux/seq_file.h>
 #include	<linux/notifier.h>
 #include	<linux/kallsyms.h>
@@ -173,12 +174,12 @@
 			 SLAB_NO_REAP | SLAB_CACHE_DMA | \
 			 SLAB_MUST_HWCACHE_ALIGN | SLAB_STORE_USER | \
 			 SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \
-			 SLAB_DESTROY_BY_RCU)
+			 SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD)
 #else
 # define CREATE_MASK	(SLAB_HWCACHE_ALIGN | SLAB_NO_REAP | \
 			 SLAB_CACHE_DMA | SLAB_MUST_HWCACHE_ALIGN | \
 			 SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \
-			 SLAB_DESTROY_BY_RCU)
+			 SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD)
 #endif
 
 /*
@@ -830,6 +831,7 @@
 
 #ifdef CONFIG_NUMA
 static void *__cache_alloc_node(struct kmem_cache *, gfp_t, int);
+static void *alternate_node_alloc(struct kmem_cache *, gfp_t);
 
 static struct array_cache **alloc_alien_cache(int node, int limit)
 {
@@ -2725,11 +2727,11 @@
 	struct array_cache *ac;
 
 #ifdef CONFIG_NUMA
-	if (unlikely(current->mempolicy && !in_interrupt())) {
-		int nid = slab_node(current->mempolicy);
-
-		if (nid != numa_node_id())
-			return __cache_alloc_node(cachep, flags, nid);
+	if (unlikely(current->flags & (PF_SPREAD_PAGE | PF_SPREAD_SLAB |
+							PF_MEMPOLICY))) {
+		objp = alternate_node_alloc(cachep, flags);
+		if (objp != NULL)
+			return objp;
 	}
 #endif
 
@@ -2765,6 +2767,28 @@
 
 #ifdef CONFIG_NUMA
 /*
+ * Try allocating on another node if PF_SPREAD_PAGE|PF_SPREAD_SLAB|PF_MEMPOLICY.
+ *
+ * If we are in_interrupt, then process context, including cpusets and
+ * mempolicy, may not apply and should not be used for allocation policy.
+ */
+static void *alternate_node_alloc(struct kmem_cache *cachep, gfp_t flags)
+{
+	int nid_alloc, nid_here;
+
+	if (in_interrupt())
+		return NULL;
+	nid_alloc = nid_here = numa_node_id();
+	if (cpuset_do_slab_mem_spread() && (cachep->flags & SLAB_MEM_SPREAD))
+		nid_alloc = cpuset_mem_spread_node();
+	else if (current->mempolicy)
+		nid_alloc = slab_node(current->mempolicy);
+	if (nid_alloc != nid_here)
+		return __cache_alloc_node(cachep, flags, nid_alloc);
+	return NULL;
+}
+
+/*
  * A interface to enable slab creation on nodeid
  */
 static void *__cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid)
diff -urN oldtree/mm/truncate.c newtree/mm/truncate.c
--- oldtree/mm/truncate.c	2006-02-19 11:41:06.245393656 +0000
+++ newtree/mm/truncate.c	2006-02-21 15:58:33.845001336 +0000
@@ -67,6 +67,13 @@
 	if (PagePrivate(page) && !try_to_release_page(page, 0))
 		return 0;
 
+	/*
+	 * file system may manually remove page from the page
+	 * cache in ->releasepage(). Check for this.
+	 */
+	if (page->mapping != mapping)
+		return 0;
+
 	write_lock_irq(&mapping->tree_lock);
 	if (PageDirty(page)) {
 		write_unlock_irq(&mapping->tree_lock);
diff -urN oldtree/mm/vmscan.c newtree/mm/vmscan.c
--- oldtree/mm/vmscan.c	2006-02-19 11:41:06.247393352 +0000
+++ newtree/mm/vmscan.c	2006-02-21 15:58:33.847001032 +0000
@@ -552,6 +552,11 @@
 		if (PagePrivate(page)) {
 			if (!try_to_release_page(page, sc->gfp_mask))
 				goto activate_locked;
+			/*
+			 * file system may manually remove page from the page
+			 * cache in ->releasepage(). Check for this.
+			 */
+			mapping = page_mapping(page);
 			if (!mapping && page_count(page) == 1)
 				goto free_it;
 		}
diff -urN oldtree/net/802/tr.c newtree/net/802/tr.c
--- oldtree/net/802/tr.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/802/tr.c	2006-02-21 15:58:36.965526944 +0000
@@ -165,7 +165,7 @@
 	 */
 	 
 	if(trllc->ethertype != htons(ETH_P_IP)) {
-		printk("tr_rebuild_header: Don't know how to resolve type %04X addresses ?\n",(unsigned int)htons(trllc->ethertype));
+		printk("tr_rebuild_header: Don't know how to resolve type %04X addresses ?\n", ntohs(trllc->ethertype));
 		return 0;
 	}
 
@@ -187,7 +187,7 @@
  *	it via SNAP.
  */
  
-unsigned short tr_type_trans(struct sk_buff *skb, struct net_device *dev) 
+__be16 tr_type_trans(struct sk_buff *skb, struct net_device *dev) 
 {
 
 	struct trh_hdr *trh=(struct trh_hdr *)skb->data;
@@ -230,15 +230,15 @@
 	 */
 
 	if (trllc->dsap == EXTENDED_SAP &&
-	    (trllc->ethertype == ntohs(ETH_P_IP) ||
-	     trllc->ethertype == ntohs(ETH_P_IPV6) ||
-	     trllc->ethertype == ntohs(ETH_P_ARP)))
+	    (trllc->ethertype == htons(ETH_P_IP) ||
+	     trllc->ethertype == htons(ETH_P_IPV6) ||
+	     trllc->ethertype == htons(ETH_P_ARP)))
 	{
 		skb_pull(skb, sizeof(struct trllc));
 		return trllc->ethertype;
 	}
 
-	return ntohs(ETH_P_TR_802_2);
+	return htons(ETH_P_TR_802_2);
 }
 
 /*
diff -urN oldtree/net/8021q/vlan.c newtree/net/8021q/vlan.c
--- oldtree/net/8021q/vlan.c	2006-02-19 11:41:06.249393048 +0000
+++ newtree/net/8021q/vlan.c	2006-02-21 15:58:16.289670152 +0000
@@ -69,7 +69,7 @@
 
 /* Bits of netdev state that are propagated from real device to virtual */
 #define VLAN_LINK_STATE_MASK \
-	((1<<__LINK_STATE_PRESENT)|(1<<__LINK_STATE_NOCARRIER))
+	((1<<__LINK_STATE_PRESENT)|(1<<__LINK_STATE_NOCARRIER)|(1<<__LINK_STATE_DORMANT))
 
 /* End of global variables definitions. */
 
@@ -344,6 +344,26 @@
 	new_dev->do_ioctl = vlan_dev_ioctl;
 }
 
+static void vlan_transfer_operstate(const struct net_device *dev, struct net_device *vlandev)
+{
+	/* Have to respect userspace enforced dormant state
+	 * of real device, also must allow supplicant running
+	 * on VLAN device
+	 */
+	if (dev->operstate == IF_OPER_DORMANT)
+		netif_dormant_on(vlandev);
+	else
+		netif_dormant_off(vlandev);
+
+	if (netif_carrier_ok(dev)) {
+		if (!netif_carrier_ok(vlandev))
+			netif_carrier_on(vlandev);
+	} else {
+		if (netif_carrier_ok(vlandev))
+			netif_carrier_off(vlandev);
+	}
+}
+
 /*  Attach a VLAN device to a mac address (ie Ethernet Card).
  *  Returns the device that was created, or NULL if there was
  *  an error of some kind.
@@ -450,7 +470,7 @@
 	new_dev->flags = real_dev->flags;
 	new_dev->flags &= ~IFF_UP;
 
-	new_dev->state = real_dev->state & VLAN_LINK_STATE_MASK;
+	new_dev->state = real_dev->state & ~(1<<__LINK_STATE_START);
 
 	/* need 4 bytes for extra VLAN header info,
 	 * hope the underlying device can handle it.
@@ -498,6 +518,10 @@
 	if (register_netdevice(new_dev))
 		goto out_free_newdev;
 
+	new_dev->iflink = real_dev->ifindex;
+	vlan_transfer_operstate(real_dev, new_dev);
+	linkwatch_fire_event(new_dev); /* _MUST_ call rfc2863_policy() */
+	
 	/* So, got the sucker initialized, now lets place
 	 * it into our local structure.
 	 */
@@ -573,25 +597,12 @@
 	switch (event) {
 	case NETDEV_CHANGE:
 		/* Propagate real device state to vlan devices */
-		flgs = dev->state & VLAN_LINK_STATE_MASK;
 		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
 			vlandev = grp->vlan_devices[i];
 			if (!vlandev)
 				continue;
 
-			if (netif_carrier_ok(dev)) {
-				if (!netif_carrier_ok(vlandev))
-					netif_carrier_on(vlandev);
-			} else {
-				if (netif_carrier_ok(vlandev))
-					netif_carrier_off(vlandev);
-			}
-
-			if ((vlandev->state & VLAN_LINK_STATE_MASK) != flgs) {
-				vlandev->state = (vlandev->state &~ VLAN_LINK_STATE_MASK) 
-					| flgs;
-				netdev_state_change(vlandev);
-			}
+			vlan_transfer_operstate(dev, vlandev);
 		}
 		break;
 
diff -urN oldtree/net/8021q/vlan_dev.c newtree/net/8021q/vlan_dev.c
--- oldtree/net/8021q/vlan_dev.c	2006-02-19 11:41:06.250392896 +0000
+++ newtree/net/8021q/vlan_dev.c	2006-02-21 15:58:36.964527096 +0000
@@ -62,7 +62,7 @@
 	default:
 		printk(VLAN_DBG
 		       "%s: unable to resolve type %X addresses.\n", 
-		       dev->name, (int)veth->h_vlan_encapsulated_proto);
+		       dev->name, ntohs(veth->h_vlan_encapsulated_proto));
 	 
 		memcpy(veth->h_source, dev->dev_addr, ETH_ALEN);
 		break;
diff -urN oldtree/net/Kconfig newtree/net/Kconfig
--- oldtree/net/Kconfig	2006-02-19 11:41:06.250392896 +0000
+++ newtree/net/Kconfig	2006-02-21 15:58:15.719756792 +0000
@@ -224,6 +224,9 @@
 source "net/bluetooth/Kconfig"
 source "net/ieee80211/Kconfig"
 
+config WIRELESS_EXT
+	bool
+
 endif   # if NET
 endmenu # Networking
 
diff -urN oldtree/net/appletalk/ddp.c newtree/net/appletalk/ddp.c
--- oldtree/net/appletalk/ddp.c	2006-02-19 11:41:06.252392592 +0000
+++ newtree/net/appletalk/ddp.c	2006-02-21 15:58:36.968526488 +0000
@@ -1005,7 +1005,7 @@
 	return sum;
 }
 
-static unsigned short atalk_checksum(const struct sk_buff *skb, int len)
+static __be16 atalk_checksum(const struct sk_buff *skb, int len)
 {
 	unsigned long sum;
 
@@ -1013,7 +1013,7 @@
 	sum = atalk_sum_skb(skb, 4, len-4, 0);
 
 	/* Use 0xFFFF for 0. 0 itself means none */
-	return sum ? htons((unsigned short)sum) : 0xFFFF;
+	return sum ? htons((unsigned short)sum) : htons(0xFFFF);
 }
 
 static struct proto ddp_proto = {
@@ -1292,7 +1292,7 @@
 #endif
 
 static void atalk_route_packet(struct sk_buff *skb, struct net_device *dev,
-			       struct ddpehdr *ddp, struct ddpebits *ddphv,
+			       struct ddpehdr *ddp, __u16 len_hops,
 			       int origlen)
 {
 	struct atalk_route *rt;
@@ -1320,10 +1320,12 @@
 
 	/* Route the packet */
 	rt = atrtr_find(&ta);
-	if (!rt || ddphv->deh_hops == DDP_MAXHOPS)
+	/* increment hops count */
+	len_hops += 1 << 10;
+	if (!rt || !(len_hops & (15 << 10)))
 		goto free_it;
+
 	/* FIXME: use skb->cb to be able to use shared skbs */
-	ddphv->deh_hops++;
 
 	/*
 	 * Route goes through another gateway, so set the target to the
@@ -1338,11 +1340,10 @@
         /* Fix up skb->len field */
         skb_trim(skb, min_t(unsigned int, origlen,
 			    (rt->dev->hard_header_len +
-			     ddp_dl->header_length + ddphv->deh_len)));
+			     ddp_dl->header_length + (len_hops & 1023))));
 
-	/* Mend the byte order */
 	/* FIXME: use skb->cb to be able to use shared skbs */
-	*((__u16 *)ddp) = ntohs(*((__u16 *)ddphv));
+	ddp->deh_len_hops = htons(len_hops);
 
 	/*
 	 * Send the buffer onwards
@@ -1397,7 +1398,7 @@
 	struct atalk_iface *atif;
 	struct sockaddr_at tosat;
         int origlen;
-        struct ddpebits ddphv;
+	__u16 len_hops;
 
 	/* Don't mangle buffer if shared */
 	if (!(skb = skb_share_check(skb, GFP_ATOMIC))) 
@@ -1409,16 +1410,11 @@
 
 	ddp = ddp_hdr(skb);
 
-	/*
-	 *	Fix up the length field	[Ok this is horrible but otherwise
-	 *	I end up with unions of bit fields and messy bit field order
-	 *	compiler/endian dependencies..]
-	 */
-	*((__u16 *)&ddphv) = ntohs(*((__u16 *)ddp));
+	len_hops = ntohs(ddp->deh_len_hops);
 
 	/* Trim buffer in case of stray trailing data */
 	origlen = skb->len;
-	skb_trim(skb, min_t(unsigned int, skb->len, ddphv.deh_len));
+	skb_trim(skb, min_t(unsigned int, skb->len, len_hops & 1023));
 
 	/*
 	 * Size check to see if ddp->deh_len was crap
@@ -1433,7 +1429,7 @@
 	 * valid for net byte orders all over the networking code...
 	 */
 	if (ddp->deh_sum &&
-	    atalk_checksum(skb, ddphv.deh_len) != ddp->deh_sum)
+	    atalk_checksum(skb, len_hops & 1023) != ddp->deh_sum)
 		/* Not a valid AppleTalk frame - dustbin time */
 		goto freeit;
 
@@ -1447,7 +1443,7 @@
 		/* Not ours, so we route the packet via the correct
 		 * AppleTalk iface
 		 */
-		atalk_route_packet(skb, dev, ddp, &ddphv, origlen);
+		atalk_route_packet(skb, dev, ddp, len_hops, origlen);
 		goto out;
 	}
 
@@ -1492,7 +1488,7 @@
 		/* Find our address */
 		struct atalk_addr *ap = atalk_find_dev_addr(dev);
 
-		if (!ap || skb->len < sizeof(struct ddpshdr))
+		if (!ap || skb->len < sizeof(__be16) || skb->len > 1023)
 			goto freeit;
 
 		/* Don't mangle buffer if shared */
@@ -1522,11 +1518,8 @@
 		/*
 		 * Not sure about this bit...
 		 */
-		ddp->deh_len   = skb->len;
-		ddp->deh_hops  = DDP_MAXHOPS;	/* Non routable, so force a drop
-						   if we slip up later */
-		/* Mend the byte order */
-		*((__u16 *)ddp) = htons(*((__u16 *)ddp));
+		/* Non routable, so force a drop if we slip up later */
+		ddp->deh_len_hops = htons(skb->len + (DDP_MAXHOPS << 10));
 	}
 	skb->h.raw = skb->data;
 
@@ -1625,16 +1618,7 @@
 	SOCK_DEBUG(sk, "SK %p: Begin build.\n", sk);
 
 	ddp = (struct ddpehdr *)skb_put(skb, sizeof(struct ddpehdr));
-	ddp->deh_pad  = 0;
-	ddp->deh_hops = 0;
-	ddp->deh_len  = len + sizeof(*ddp);
-	/*
-	 * Fix up the length field [Ok this is horrible but otherwise
-	 * I end up with unions of bit fields and messy bit field order
-	 * compiler/endian dependencies..
-	 */
-	*((__u16 *)ddp) = ntohs(*((__u16 *)ddp));
-
+	ddp->deh_len_hops  = htons(len + sizeof(*ddp));
 	ddp->deh_dnet  = usat->sat_addr.s_net;
 	ddp->deh_snet  = at->src_net;
 	ddp->deh_dnode = usat->sat_addr.s_node;
@@ -1715,8 +1699,8 @@
 	struct sockaddr_at *sat = (struct sockaddr_at *)msg->msg_name;
 	struct ddpehdr *ddp;
 	int copied = 0;
+	int offset = 0;
 	int err = 0;
-        struct ddpebits ddphv;
 	struct sk_buff *skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
 						flags & MSG_DONTWAIT, &err);
 	if (!skb)
@@ -1724,25 +1708,18 @@
 
 	/* FIXME: use skb->cb to be able to use shared skbs */
 	ddp = ddp_hdr(skb);
-	*((__u16 *)&ddphv) = ntohs(*((__u16 *)ddp));
+	copied = ntohs(ddp->deh_len_hops) & 1023;
 
-	if (sk->sk_type == SOCK_RAW) {
-		copied = ddphv.deh_len;
-		if (copied > size) {
-			copied = size;
-			msg->msg_flags |= MSG_TRUNC;
-		}
+	if (sk->sk_type != SOCK_RAW) {
+		offset = sizeof(*ddp);
+		copied -= offset;
+	}
 
-		err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
-	} else {
-		copied = ddphv.deh_len - sizeof(*ddp);
-		if (copied > size) {
-			copied = size;
-			msg->msg_flags |= MSG_TRUNC;
-		}
-		err = skb_copy_datagram_iovec(skb, sizeof(*ddp),
-					      msg->msg_iov, copied);
+	if (copied > size) {
+		copied = size;
+		msg->msg_flags |= MSG_TRUNC;
 	}
+	err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copied);
 
 	if (!err) {
 		if (sat) {
diff -urN oldtree/net/atm/common.c newtree/net/atm/common.c
--- oldtree/net/atm/common.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/atm/common.c	2006-02-21 15:58:16.804591872 +0000
@@ -451,12 +451,12 @@
 		dev = try_then_request_module(atm_dev_lookup(itf), "atm-device-%d", itf);
 	} else {
 		dev = NULL;
-		down(&atm_dev_mutex);
+		mutex_lock(&atm_dev_mutex);
 		if (!list_empty(&atm_devs)) {
 			dev = list_entry(atm_devs.next, struct atm_dev, dev_list);
 			atm_dev_hold(dev);
 		}
-		up(&atm_dev_mutex);
+		mutex_unlock(&atm_dev_mutex);
 	}
 	if (!dev)
 		return -ENODEV;
diff -urN oldtree/net/atm/ioctl.c newtree/net/atm/ioctl.c
--- oldtree/net/atm/ioctl.c	2006-02-19 11:41:06.253392440 +0000
+++ newtree/net/atm/ioctl.c	2006-02-21 15:58:16.619619992 +0000
@@ -18,6 +18,7 @@
 #include <linux/atmmpc.h>
 #include <net/atmclip.h>
 #include <linux/atmlec.h>
+#include <linux/mutex.h>
 #include <asm/ioctls.h>
 
 #include "resources.h"
@@ -25,22 +26,22 @@
 #include "common.h"
 
 
-static DECLARE_MUTEX(ioctl_mutex);
+static DEFINE_MUTEX(ioctl_mutex);
 static LIST_HEAD(ioctl_list);
 
 
 void register_atm_ioctl(struct atm_ioctl *ioctl)
 {
-	down(&ioctl_mutex);
+	mutex_lock(&ioctl_mutex);
 	list_add_tail(&ioctl->list, &ioctl_list);
-	up(&ioctl_mutex);
+	mutex_unlock(&ioctl_mutex);
 }
 
 void deregister_atm_ioctl(struct atm_ioctl *ioctl)
 {
-	down(&ioctl_mutex);
+	mutex_lock(&ioctl_mutex);
 	list_del(&ioctl->list);
-	up(&ioctl_mutex);
+	mutex_unlock(&ioctl_mutex);
 }
 
 EXPORT_SYMBOL(register_atm_ioctl);
@@ -137,7 +138,7 @@
 
 	error = -ENOIOCTLCMD;
 
-	down(&ioctl_mutex);
+	mutex_lock(&ioctl_mutex);
 	list_for_each(pos, &ioctl_list) {
 		struct atm_ioctl * ic = list_entry(pos, struct atm_ioctl, list);
 		if (try_module_get(ic->owner)) {
@@ -147,7 +148,7 @@
 				break;
 		}
 	}
-	up(&ioctl_mutex);
+	mutex_unlock(&ioctl_mutex);
 
 	if (error != -ENOIOCTLCMD)
 		goto done;
diff -urN oldtree/net/atm/mpc.c newtree/net/atm/mpc.c
--- oldtree/net/atm/mpc.c	2006-02-19 11:41:06.256391984 +0000
+++ newtree/net/atm/mpc.c	2006-02-21 15:58:36.972525880 +0000
@@ -229,20 +229,15 @@
 /* this is buggered - we need locking for qos_head */
 void atm_mpoa_disp_qos(struct seq_file *m)
 {
-	unsigned char *ip;
-	char ipaddr[16];
 	struct atm_mpoa_qos *qos;
 
 	qos = qos_head;
 	seq_printf(m, "QoS entries for shortcuts:\n");
 	seq_printf(m, "IP address\n  TX:max_pcr pcr     min_pcr max_cdv max_sdu\n  RX:max_pcr pcr     min_pcr max_cdv max_sdu\n");
 
-	ipaddr[sizeof(ipaddr)-1] = '\0';
 	while (qos != NULL) {
-		ip = (unsigned char *)&qos->ipaddr;
-		sprintf(ipaddr, "%u.%u.%u.%u", NIPQUAD(ip));
 		seq_printf(m, "%u.%u.%u.%u\n     %-7d %-7d %-7d %-7d %-7d\n     %-7d %-7d %-7d %-7d %-7d\n",
-				NIPQUAD(ipaddr),
+				NIPQUAD(qos->ipaddr),
 				qos->qos.txtp.max_pcr, qos->qos.txtp.pcr, qos->qos.txtp.min_pcr, qos->qos.txtp.max_cdv, qos->qos.txtp.max_sdu,
 				qos->qos.rxtp.max_pcr, qos->qos.rxtp.pcr, qos->qos.rxtp.min_pcr, qos->qos.rxtp.max_cdv, qos->qos.rxtp.max_sdu);
 		qos = qos->next;
@@ -572,7 +567,6 @@
 	struct atmmpc_ioc ioc_data;
 	in_cache_entry *in_entry;
 	uint32_t  ipaddr;
-	unsigned char *ip;
 
 	bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmmpc_ioc));
 	if (bytes_left != 0) {
@@ -595,9 +589,8 @@
 			if (in_entry != NULL) mpc->in_ops->put(in_entry);
 			return -EINVAL;
 		}
-		ip = (unsigned char*)&in_entry->ctrl_info.in_dst_ip;
 		printk("mpoa: (%s) mpc_vcc_attach: attaching ingress SVC, entry = %u.%u.%u.%u\n",
-		       mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
+		       mpc->dev->name, NIPQUAD(in_entry->ctrl_info.in_dst_ip));
 		in_entry->shortcut = vcc;
 		mpc->in_ops->put(in_entry);
 	} else {
@@ -628,10 +621,8 @@
 	dprintk("mpoa: (%s) mpc_vcc_close:\n", dev->name);
 	in_entry = mpc->in_ops->get_by_vcc(vcc, mpc);
 	if (in_entry) {
-		unsigned char *ip __attribute__ ((unused)) =
-		    (unsigned char *)&in_entry->ctrl_info.in_dst_ip;
 		dprintk("mpoa: (%s) mpc_vcc_close: ingress SVC closed ip = %u.%u.%u.%u\n",
-		       mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
+		       mpc->dev->name, NIPQUAD(in_entry->ctrl_info.in_dst_ip));
 		in_entry->shortcut = NULL;
 		mpc->in_ops->put(in_entry);
 	}
@@ -1083,7 +1074,6 @@
 static void check_qos_and_open_shortcut(struct k_message *msg, struct mpoa_client *client, in_cache_entry *entry)
 {
 	uint32_t dst_ip = msg->content.in_info.in_dst_ip;
-	unsigned char *ip __attribute__ ((unused)) = (unsigned char *)&dst_ip;
 	struct atm_mpoa_qos *qos = atm_mpoa_search_qos(dst_ip);
 	eg_cache_entry *eg_entry = client->eg_ops->get_by_src_ip(dst_ip, client);
 
@@ -1097,7 +1087,7 @@
 				    entry->shortcut = eg_entry->shortcut;
 		}
 	 	if(entry->shortcut){
-			dprintk("mpoa: (%s) using egress SVC to reach %u.%u.%u.%u\n",client->dev->name, NIPQUAD(ip));
+			dprintk("mpoa: (%s) using egress SVC to reach %u.%u.%u.%u\n",client->dev->name, NIPQUAD(dst_ip));
 			client->eg_ops->put(eg_entry);
 			return;
 		}
@@ -1119,12 +1109,9 @@
 
 static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc)
 {
-	unsigned char *ip;
-
 	uint32_t dst_ip = msg->content.in_info.in_dst_ip;
 	in_cache_entry *entry = mpc->in_ops->get(dst_ip, mpc);
-	ip = (unsigned char *)&dst_ip;
-	dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %u.%u.%u.%u\n", mpc->dev->name, NIPQUAD(ip));
+	dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %u.%u.%u.%u\n", mpc->dev->name, NIPQUAD(dst_ip));
 	ddprintk("mpoa: (%s) MPOA_res_reply_rcvd() entry = %p", mpc->dev->name, entry);
 	if(entry == NULL){
 		printk("\nmpoa: (%s) ARGH, received res. reply for an entry that doesn't exist.\n", mpc->dev->name);
@@ -1169,18 +1156,17 @@
 {
 	uint32_t dst_ip = msg->content.in_info.in_dst_ip;
 	uint32_t mask = msg->ip_mask;
-	unsigned char *ip = (unsigned char *)&dst_ip;
 	in_cache_entry *entry = mpc->in_ops->get_with_mask(dst_ip, mpc, mask);
 
 	if(entry == NULL){
 		printk("mpoa: (%s) ingress_purge_rcvd: purge for a non-existing entry, ", mpc->dev->name);
-		printk("ip = %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]);
+		printk("ip = %u.%u.%u.%u\n", NIPQUAD(dst_ip));
 		return;
 	}
 
 	do {
 		dprintk("mpoa: (%s) ingress_purge_rcvd: removing an ingress entry, ip = %u.%u.%u.%u\n" ,
-			mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
+			mpc->dev->name, NIPQUAD(dst_ip));
 		write_lock_bh(&mpc->ingress_lock);
 		mpc->in_ops->remove_entry(entry, mpc);
 		write_unlock_bh(&mpc->ingress_lock);
diff -urN oldtree/net/atm/mpoa_caches.c newtree/net/atm/mpoa_caches.c
--- oldtree/net/atm/mpoa_caches.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/atm/mpoa_caches.c	2006-02-21 15:58:36.973525728 +0000
@@ -87,7 +87,6 @@
 static in_cache_entry *in_cache_add_entry(uint32_t dst_ip,
 					  struct mpoa_client *client)
 {
-	unsigned char *ip __attribute__ ((unused)) = (unsigned char *)&dst_ip;
 	in_cache_entry* entry = kmalloc(sizeof(in_cache_entry), GFP_KERNEL);
 
 	if (entry == NULL) {
@@ -95,7 +94,7 @@
 		return NULL;
 	}
 
-	dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]);
+	dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %u.%u.%u.%u\n", NIPQUAD(dst_ip));
 	memset(entry,0,sizeof(in_cache_entry));
 
 	atomic_set(&entry->use, 1);
@@ -152,10 +151,7 @@
 
 	if( entry->count > mpc->parameters.mpc_p1 &&
 	    entry->entry_state == INGRESS_INVALID){
-		unsigned char *ip __attribute__ ((unused)) =
-		    (unsigned char *)&entry->ctrl_info.in_dst_ip;
-
-		dprintk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %u.%u.%u.%u, sending MPOA res req\n", mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
+		dprintk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %u.%u.%u.%u, sending MPOA res req\n", mpc->dev->name, NIPQUAD(entry->ctrl_info.in_dst_ip));
 		entry->entry_state = INGRESS_RESOLVING;
 		msg.type =  SND_MPOA_RES_RQST;
 		memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN );
@@ -187,11 +183,9 @@
 {
 	struct atm_vcc *vcc;
 	struct k_message msg;
-	unsigned char *ip;
 
 	vcc = entry->shortcut;
-	ip = (unsigned char *)&entry->ctrl_info.in_dst_ip;
-	dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %u.%u.%u.%u\n",ip[0], ip[1], ip[2], ip[3]);
+	dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %u.%u.%u.%u\n",NIPQUAD(entry->ctrl_info.in_dst_ip));
 
 	if (entry->prev != NULL)
 		entry->prev->next = entry->next;
@@ -223,7 +217,6 @@
    but an easy one... */
 static void clear_count_and_expired(struct mpoa_client *client)
 {
-	unsigned char *ip;
 	in_cache_entry *entry, *next_entry;
 	struct timeval now;
 
@@ -236,8 +229,7 @@
 		next_entry = entry->next;
 		if((now.tv_sec - entry->tv.tv_sec)
 		   > entry->ctrl_info.holding_time){
-			ip = (unsigned char*)&entry->ctrl_info.in_dst_ip;
-			dprintk("mpoa: mpoa_caches.c: holding time expired, ip = %u.%u.%u.%u\n", NIPQUAD(ip));
+			dprintk("mpoa: mpoa_caches.c: holding time expired, ip = %u.%u.%u.%u\n", NIPQUAD(entry->ctrl_info.in_dst_ip));
 			client->in_ops->remove_entry(entry, client);
 		}
 		entry = next_entry;
@@ -455,7 +447,6 @@
 
 static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, struct mpoa_client *client)
 {
-	unsigned char *ip;
 	eg_cache_entry *entry = kmalloc(sizeof(eg_cache_entry), GFP_KERNEL);
 
 	if (entry == NULL) {
@@ -463,8 +454,7 @@
 		return NULL;
 	}
 
-	ip = (unsigned char *)&msg->content.eg_info.eg_dst_ip;
-	dprintk("mpoa: mpoa_caches.c: adding an egress entry, ip = %u.%u.%u.%u, this should be our IP\n", NIPQUAD(ip));
+	dprintk("mpoa: mpoa_caches.c: adding an egress entry, ip = %u.%u.%u.%u, this should be our IP\n", NIPQUAD(msg->content.eg_info.eg_dst_ip));
 	memset(entry, 0, sizeof(eg_cache_entry));
 
 	atomic_set(&entry->use, 1);
@@ -481,8 +471,8 @@
 	do_gettimeofday(&(entry->tv));
 	entry->entry_state = EGRESS_RESOLVED;
 	dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry cache_id %lu\n", ntohl(entry->ctrl_info.cache_id));
-	ip = (unsigned char *)&entry->ctrl_info.mps_ip;
-	dprintk("mpoa: mpoa_caches.c: mps_ip = %u.%u.%u.%u\n", NIPQUAD(ip));
+	dprintk("mpoa: mpoa_caches.c: mps_ip = %u.%u.%u.%u\n",
+		NIPQUAD(entry->ctrl_info.mps_ip));
 	atomic_inc(&entry->use);
 
 	write_unlock_irq(&client->egress_lock);
diff -urN oldtree/net/atm/resources.c newtree/net/atm/resources.c
--- oldtree/net/atm/resources.c	2006-02-19 11:41:06.257391832 +0000
+++ newtree/net/atm/resources.c	2006-02-21 15:58:16.814590352 +0000
@@ -18,6 +18,8 @@
 #include <linux/bitops.h>
 #include <linux/capability.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
+
 #include <net/sock.h>	 /* for struct sock */
 
 #include "common.h"
@@ -26,7 +28,7 @@
 
 
 LIST_HEAD(atm_devs);
-DECLARE_MUTEX(atm_dev_mutex);
+DEFINE_MUTEX(atm_dev_mutex);
 
 static struct atm_dev *__alloc_atm_dev(const char *type)
 {
@@ -65,9 +67,9 @@
 {
 	struct atm_dev *dev;
 
-	down(&atm_dev_mutex);
+	mutex_lock(&atm_dev_mutex);
 	dev = __atm_dev_lookup(number);
-	up(&atm_dev_mutex);
+	mutex_unlock(&atm_dev_mutex);
 	return dev;
 }
 
@@ -83,11 +85,11 @@
 		    type);
 		return NULL;
 	}
-	down(&atm_dev_mutex);
+	mutex_lock(&atm_dev_mutex);
 	if (number != -1) {
 		if ((inuse = __atm_dev_lookup(number))) {
 			atm_dev_put(inuse);
-			up(&atm_dev_mutex);
+			mutex_unlock(&atm_dev_mutex);
 			kfree(dev);
 			return NULL;
 		}
@@ -112,12 +114,12 @@
 		printk(KERN_ERR "atm_dev_register: "
 		       "atm_proc_dev_register failed for dev %s\n",
 		       type);
-		up(&atm_dev_mutex);
+		mutex_unlock(&atm_dev_mutex);
 		kfree(dev);
 		return NULL;
 	}
 	list_add_tail(&dev->dev_list, &atm_devs);
-	up(&atm_dev_mutex);
+	mutex_unlock(&atm_dev_mutex);
 
 	return dev;
 }
@@ -133,9 +135,9 @@
 	 * with same number can appear, such we need deregister proc, 
 	 * release async all vccs and remove them from vccs list too
 	 */
-	down(&atm_dev_mutex);
+	mutex_lock(&atm_dev_mutex);
 	list_del(&dev->dev_list);
-	up(&atm_dev_mutex);
+	mutex_unlock(&atm_dev_mutex);
 
 	atm_dev_release_vccs(dev);
 	atm_proc_dev_deregister(dev);
@@ -196,16 +198,16 @@
 				return -EFAULT;
 			if (get_user(len, &iobuf->length))
 				return -EFAULT;
-			down(&atm_dev_mutex);
+			mutex_lock(&atm_dev_mutex);
 			list_for_each(p, &atm_devs)
 				size += sizeof(int);
 			if (size > len) {
-				up(&atm_dev_mutex);
+				mutex_unlock(&atm_dev_mutex);
 				return -E2BIG;
 			}
 			tmp_buf = kmalloc(size, GFP_ATOMIC);
 			if (!tmp_buf) {
-				up(&atm_dev_mutex);
+				mutex_unlock(&atm_dev_mutex);
 				return -ENOMEM;
 			}
 			tmp_p = tmp_buf;
@@ -213,7 +215,7 @@
 				dev = list_entry(p, struct atm_dev, dev_list);
 				*tmp_p++ = dev->number;
 			}
-			up(&atm_dev_mutex);
+			mutex_unlock(&atm_dev_mutex);
 		        error = ((copy_to_user(buf, tmp_buf, size)) ||
 					put_user(size, &iobuf->length))
 						? -EFAULT : 0;
@@ -400,13 +402,13 @@
 
 void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos)
 {
- 	down(&atm_dev_mutex);
+ 	mutex_lock(&atm_dev_mutex);
 	return *pos ? dev_get_idx(*pos) : (void *) 1;
 }
 
 void atm_dev_seq_stop(struct seq_file *seq, void *v)
 {
- 	up(&atm_dev_mutex);
+ 	mutex_unlock(&atm_dev_mutex);
 }
  
 void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
diff -urN oldtree/net/atm/resources.h newtree/net/atm/resources.h
--- oldtree/net/atm/resources.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/atm/resources.h	2006-02-21 15:58:16.814590352 +0000
@@ -8,10 +8,11 @@
 
 #include <linux/config.h>
 #include <linux/atmdev.h>
+#include <linux/mutex.h>
 
 
 extern struct list_head atm_devs;
-extern struct semaphore atm_dev_mutex;
+extern struct mutex atm_dev_mutex;
 
 int atm_dev_ioctl(unsigned int cmd, void __user *arg);
 
diff -urN oldtree/net/bluetooth/bnep/bnep.h newtree/net/bluetooth/bnep/bnep.h
--- oldtree/net/bluetooth/bnep/bnep.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/bluetooth/bnep/bnep.h	2006-02-21 15:58:36.974525576 +0000
@@ -95,14 +95,14 @@
 struct bnep_set_filter_req {
 	__u8  type;
 	__u8  ctrl;
-	__u16 len;
+	__be16 len;
 	__u8  list[0];
 } __attribute__((packed));
 
 struct bnep_control_rsp {
 	__u8  type;
 	__u8  ctrl;
-	__u16 resp;
+	__be16 resp;
 } __attribute__((packed));
 
 struct bnep_ext_hdr {
@@ -143,8 +143,8 @@
 };
 
 struct bnep_proto_filter {
-	__u16 start;
-	__u16 end;
+	__be16 start;
+	__be16 end;
 };
 
 int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock);
diff -urN oldtree/net/bluetooth/bnep/core.c newtree/net/bluetooth/bnep/core.c
--- oldtree/net/bluetooth/bnep/core.c	2006-02-19 11:41:06.261391224 +0000
+++ newtree/net/bluetooth/bnep/core.c	2006-02-21 15:58:36.982524360 +0000
@@ -128,7 +128,7 @@
 }
 #endif
 
-static int bnep_ctrl_set_netfilter(struct bnep_session *s, u16 *data, int len)
+static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len)
 {
 	int n;
 
@@ -180,7 +180,7 @@
 	if (len < 2)
 		return -EILSEQ;
 
-	n = ntohs(get_unaligned((u16 *) data)); 
+	n = ntohs(get_unaligned((__be16 *) data)); 
 	data += 2; len -= 2;
 
 	if (len < n)
@@ -332,7 +332,7 @@
 	if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
 		goto badframe;
 
-	s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2));
+	s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
 
 	if (type & BNEP_EXT_HEADER) {
 		if (bnep_rx_extension(s, skb) < 0)
@@ -343,7 +343,7 @@
 	if (ntohs(s->eh.h_proto) == 0x8100) {
 		if (!skb_pull(skb, 4))
 			goto badframe;
-		s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2));
+		s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
 	}
 	
 	/* We have to alloc new skb and copy data here :(. Because original skb
@@ -365,7 +365,7 @@
 	case BNEP_COMPRESSED_SRC_ONLY:
 		memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
 		memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
-		put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2));
+		put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
 		break;
 
 	case BNEP_COMPRESSED_DST_ONLY:
@@ -375,7 +375,7 @@
 
 	case BNEP_GENERAL:
 		memcpy(__skb_put(nskb, ETH_ALEN * 2), skb->mac.raw, ETH_ALEN * 2);
-		put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2));
+		put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
 		break;
 	}
 
diff -urN oldtree/net/bluetooth/bnep/netdev.c newtree/net/bluetooth/bnep/netdev.c
--- oldtree/net/bluetooth/bnep/netdev.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/bluetooth/bnep/netdev.c	2006-02-21 15:58:36.983524208 +0000
@@ -156,7 +156,7 @@
 
 #ifdef CONFIG_BT_BNEP_PROTO_FILTER
 /* Determine ether protocol. Based on eth_type_trans. */
-static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
+static inline __be16 bnep_net_eth_proto(struct sk_buff *skb)
 {
 	struct ethhdr *eh = (void *) skb->data;
 	
@@ -171,7 +171,7 @@
 
 static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
 {
-	u16 proto = bnep_net_eth_proto(skb);
+	__be16 proto = bnep_net_eth_proto(skb);
 	struct bnep_proto_filter *f = s->proto_filter;
 	int i;
 	
diff -urN oldtree/net/bluetooth/hci_event.c newtree/net/bluetooth/hci_event.c
--- oldtree/net/bluetooth/hci_event.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/bluetooth/hci_event.c	2006-02-21 15:58:31.955288616 +0000
@@ -322,7 +322,7 @@
 		hdev->acl_mtu  = __le16_to_cpu(bs->acl_mtu);
 		hdev->sco_mtu  = bs->sco_mtu ? bs->sco_mtu : 64;
 		hdev->acl_pkts = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt);
-		hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt);
+		hdev->sco_pkts = hdev->sco_cnt = (bs->sco_max_pkt ? __le16_to_cpu(bs->sco_max_pkt) : 8);
 
 		BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
 			hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts);
diff -urN oldtree/net/bluetooth/l2cap.c newtree/net/bluetooth/l2cap.c
--- oldtree/net/bluetooth/l2cap.c	2006-02-19 11:41:06.265390616 +0000
+++ newtree/net/bluetooth/l2cap.c	2006-02-21 15:58:36.984524056 +0000
@@ -208,7 +208,7 @@
 }
 
 /* ---- Socket interface ---- */
-static struct sock *__l2cap_get_sock_by_addr(u16 psm, bdaddr_t *src)
+static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
 {
 	struct sock *sk;
 	struct hlist_node *node;
@@ -223,7 +223,7 @@
 /* Find socket with psm and source bdaddr.
  * Returns closest match.
  */
-static struct sock *__l2cap_get_sock_by_psm(int state, u16 psm, bdaddr_t *src)
+static struct sock *__l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src)
 {
 	struct sock *sk = NULL, *sk1 = NULL;
 	struct hlist_node *node;
@@ -247,7 +247,7 @@
 
 /* Find socket with given address (psm, src).
  * Returns locked socket */
-static inline struct sock *l2cap_get_sock_by_psm(int state, u16 psm, bdaddr_t *src)
+static inline struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src)
 {
 	struct sock *s;
 	read_lock(&l2cap_sk_list.lock);
@@ -721,7 +721,7 @@
 	lh->len = __cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
 
 	if (sk->sk_type == SOCK_DGRAM)
-		put_unaligned(l2cap_pi(sk)->psm, (u16 *) skb_put(skb, 2));
+		put_unaligned(l2cap_pi(sk)->psm, (__le16 *) skb_put(skb, 2));
 
 	if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
 		err = -EFAULT;
@@ -1252,11 +1252,11 @@
 		break;
 
 	case 2:
-		*val = __le16_to_cpu(*((u16 *)opt->val));
+		*val = __le16_to_cpu(*((__le16 *)opt->val));
 		break;
 
 	case 4:
-		*val = __le32_to_cpu(*((u32 *)opt->val));
+		*val = __le32_to_cpu(*((__le32 *)opt->val));
 		break;
 
 	default:
@@ -1319,11 +1319,11 @@
 		break;
 
 	case 2:
-		*((u16 *) opt->val) = __cpu_to_le16(val);
+		*((__le16 *) opt->val) = __cpu_to_le16(val);
 		break;
 
 	case 4:
-		*((u32 *) opt->val) = __cpu_to_le32(val);
+		*((__le32 *) opt->val) = __cpu_to_le32(val);
 		break;
 
 	default:
@@ -1402,7 +1402,7 @@
 	int result = 0, status = 0;
 
 	u16 dcid = 0, scid = __le16_to_cpu(req->scid);
-	u16 psm  = req->psm;
+	__le16 psm  = req->psm;
 
 	BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
 
@@ -1542,7 +1542,7 @@
 	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
 		return -ENOENT;
 
-	l2cap_parse_conf_req(sk, req->data, cmd->len - sizeof(*req));
+	l2cap_parse_conf_req(sk, req->data, __le16_to_cpu(cmd->len) - sizeof(*req));
 
 	if (flags & 0x0001) {
 		/* Incomplete config. Send empty response. */
@@ -1726,15 +1726,16 @@
 	l2cap_raw_recv(conn, skb);
 
 	while (len >= L2CAP_CMD_HDR_SIZE) {
+		int this_len;
 		memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
 		data += L2CAP_CMD_HDR_SIZE;
 		len  -= L2CAP_CMD_HDR_SIZE;
 
-		cmd.len = __le16_to_cpu(cmd.len);
+		this_len = __le16_to_cpu(cmd.len);
 
-		BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident);
+		BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, this_len, cmd.ident);
 
-		if (cmd.len > len || !cmd.ident) {
+		if (this_len > len || !cmd.ident) {
 			BT_DBG("corrupted command");
 			break;
 		}
@@ -1769,7 +1770,7 @@
 			break;
 
 		case L2CAP_ECHO_REQ:
-			l2cap_send_cmd(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data);
+			l2cap_send_cmd(conn, cmd.ident, L2CAP_ECHO_RSP, this_len, data);
 			break;
 
 		case L2CAP_ECHO_RSP:
@@ -1798,8 +1799,8 @@
 			l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
 		}
 
-		data += cmd.len;
-		len  -= cmd.len;
+		data += this_len;
+		len  -= this_len;
 	}
 
 	kfree_skb(skb);
@@ -1839,7 +1840,7 @@
 	return 0;
 }
 
-static inline int l2cap_conless_channel(struct l2cap_conn *conn, u16 psm, struct sk_buff *skb)
+static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
 {
 	struct sock *sk;
 
@@ -1869,7 +1870,8 @@
 static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
 {
 	struct l2cap_hdr *lh = (void *) skb->data;
-	u16 cid, psm, len;
+	u16 cid, len;
+	__le16 psm;
 
 	skb_pull(skb, L2CAP_HDR_SIZE);
 	cid = __le16_to_cpu(lh->cid);
@@ -1883,7 +1885,7 @@
 		break;
 
 	case 0x0002:
-		psm = get_unaligned((u16 *) skb->data);
+		psm = get_unaligned((__le16 *) skb->data);
 		skb_pull(skb, 2);
 		l2cap_conless_channel(conn, psm, skb);
 		break;
diff -urN oldtree/net/bluetooth/rfcomm/core.c newtree/net/bluetooth/rfcomm/core.c
--- oldtree/net/bluetooth/rfcomm/core.c	2006-02-19 11:41:06.266390464 +0000
+++ newtree/net/bluetooth/rfcomm/core.c	2006-02-21 15:58:36.985523904 +0000
@@ -37,6 +37,8 @@
 #include <linux/wait.h>
 #include <linux/device.h>
 #include <linux/net.h>
+#include <linux/mutex.h>
+
 #include <net/sock.h>
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
@@ -57,9 +59,9 @@
 
 static struct task_struct *rfcomm_thread;
 
-static DECLARE_MUTEX(rfcomm_sem);
-#define rfcomm_lock()	down(&rfcomm_sem);
-#define rfcomm_unlock()	up(&rfcomm_sem);
+static DEFINE_MUTEX(rfcomm_mutex);
+#define rfcomm_lock()	mutex_lock(&rfcomm_mutex)
+#define rfcomm_unlock()	mutex_unlock(&rfcomm_mutex)
 
 static unsigned long rfcomm_event;
 
@@ -1011,7 +1013,7 @@
 
 	if (len > 127) {
 		hdr = (void *) skb_push(skb, 4);
-		put_unaligned(htobs(__len16(len)), (u16 *) &hdr->len);
+		put_unaligned(htobs(__len16(len)), (__le16 *) &hdr->len);
 	} else {
 		hdr = (void *) skb_push(skb, 3);
 		hdr->len = __len8(len);
diff -urN oldtree/net/bridge/netfilter/ebt_arpreply.c newtree/net/bridge/netfilter/ebt_arpreply.c
--- oldtree/net/bridge/netfilter/ebt_arpreply.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/bridge/netfilter/ebt_arpreply.c	2006-02-21 15:58:36.989523296 +0000
@@ -20,7 +20,7 @@
    const void *data, unsigned int datalen)
 {
 	struct ebt_arpreply_info *info = (struct ebt_arpreply_info *)data;
-	u32 _sip, *siptr, _dip, *diptr;
+	__be32 _sip, *siptr, _dip, *diptr;
 	struct arphdr _ah, *ap;
 	unsigned char _sha[ETH_ALEN], *shp;
 	struct sk_buff *skb = *pskb;
diff -urN oldtree/net/bridge/netfilter/ebtables.c newtree/net/bridge/netfilter/ebtables.c
--- oldtree/net/bridge/netfilter/ebtables.c	2006-02-19 11:41:06.278388640 +0000
+++ newtree/net/bridge/netfilter/ebtables.c	2006-02-21 15:58:16.816590048 +0000
@@ -35,6 +35,7 @@
 #define ASSERT_READ_LOCK(x)
 #define ASSERT_WRITE_LOCK(x)
 #include <linux/netfilter_ipv4/listhelp.h>
+#include <linux/mutex.h>
 
 #if 0
 /* use this for remote debugging
@@ -81,7 +82,7 @@
 
 
 
-static DECLARE_MUTEX(ebt_mutex);
+static DEFINE_MUTEX(ebt_mutex);
 static LIST_HEAD(ebt_tables);
 static LIST_HEAD(ebt_targets);
 static LIST_HEAD(ebt_matches);
@@ -296,18 +297,18 @@
 /* If it succeeds, returns element and locks mutex */
 static inline void *
 find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
-   struct semaphore *mutex)
+   struct mutex *mutex)
 {
 	void *ret;
 
-	*error = down_interruptible(mutex);
+	*error = mutex_lock_interruptible(mutex);
 	if (*error != 0)
 		return NULL;
 
 	ret = list_named_find(head, name);
 	if (!ret) {
 		*error = -ENOENT;
-		up(mutex);
+		mutex_unlock(mutex);
 	}
 	return ret;
 }
@@ -317,7 +318,7 @@
 #else
 static void *
 find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
-   int *error, struct semaphore *mutex)
+   int *error, struct mutex *mutex)
 {
 	void *ret;
 
@@ -331,25 +332,25 @@
 #endif
 
 static inline struct ebt_table *
-find_table_lock(const char *name, int *error, struct semaphore *mutex)
+find_table_lock(const char *name, int *error, struct mutex *mutex)
 {
 	return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);
 }
 
 static inline struct ebt_match *
-find_match_lock(const char *name, int *error, struct semaphore *mutex)
+find_match_lock(const char *name, int *error, struct mutex *mutex)
 {
 	return find_inlist_lock(&ebt_matches, name, "ebt_", error, mutex);
 }
 
 static inline struct ebt_watcher *
-find_watcher_lock(const char *name, int *error, struct semaphore *mutex)
+find_watcher_lock(const char *name, int *error, struct mutex *mutex)
 {
 	return find_inlist_lock(&ebt_watchers, name, "ebt_", error, mutex);
 }
 
 static inline struct ebt_target *
-find_target_lock(const char *name, int *error, struct semaphore *mutex)
+find_target_lock(const char *name, int *error, struct mutex *mutex)
 {
 	return find_inlist_lock(&ebt_targets, name, "ebt_", error, mutex);
 }
@@ -369,10 +370,10 @@
 		return ret;
 	m->u.match = match;
 	if (!try_module_get(match->me)) {
-		up(&ebt_mutex);
+		mutex_unlock(&ebt_mutex);
 		return -ENOENT;
 	}
-	up(&ebt_mutex);
+	mutex_unlock(&ebt_mutex);
 	if (match->check &&
 	   match->check(name, hookmask, e, m->data, m->match_size) != 0) {
 		BUGPRINT("match->check failed\n");
@@ -398,10 +399,10 @@
 		return ret;
 	w->u.watcher = watcher;
 	if (!try_module_get(watcher->me)) {
-		up(&ebt_mutex);
+		mutex_unlock(&ebt_mutex);
 		return -ENOENT;
 	}
-	up(&ebt_mutex);
+	mutex_unlock(&ebt_mutex);
 	if (watcher->check &&
 	   watcher->check(name, hookmask, e, w->data, w->watcher_size) != 0) {
 		BUGPRINT("watcher->check failed\n");
@@ -638,11 +639,11 @@
 	if (!target)
 		goto cleanup_watchers;
 	if (!try_module_get(target->me)) {
-		up(&ebt_mutex);
+		mutex_unlock(&ebt_mutex);
 		ret = -ENOENT;
 		goto cleanup_watchers;
 	}
-	up(&ebt_mutex);
+	mutex_unlock(&ebt_mutex);
 
 	t->u.target = target;
 	if (t->u.target == &ebt_standard_target) {
@@ -1015,7 +1016,7 @@
 
 	t->private = newinfo;
 	write_unlock_bh(&t->lock);
-	up(&ebt_mutex);
+	mutex_unlock(&ebt_mutex);
 	/* so, a user can change the chains while having messed up her counter
 	   allocation. Only reason why this is done is because this way the lock
 	   is held only once, while this doesn't bring the kernel into a
@@ -1045,7 +1046,7 @@
 	return ret;
 
 free_unlock:
-	up(&ebt_mutex);
+	mutex_unlock(&ebt_mutex);
 free_iterate:
 	EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
 	   ebt_cleanup_entry, NULL);
@@ -1068,69 +1069,69 @@
 {
 	int ret;
 
-	ret = down_interruptible(&ebt_mutex);
+	ret = mutex_lock_interruptible(&ebt_mutex);
 	if (ret != 0)
 		return ret;
 	if (!list_named_insert(&ebt_targets, target)) {
-		up(&ebt_mutex);
+		mutex_unlock(&ebt_mutex);
 		return -EEXIST;
 	}
-	up(&ebt_mutex);
+	mutex_unlock(&ebt_mutex);
 
 	return 0;
 }
 
 void ebt_unregister_target(struct ebt_target *target)
 {
-	down(&ebt_mutex);
+	mutex_lock(&ebt_mutex);
 	LIST_DELETE(&ebt_targets, target);
-	up(&ebt_mutex);
+	mutex_unlock(&ebt_mutex);
 }
 
 int ebt_register_match(struct ebt_match *match)
 {
 	int ret;
 
-	ret = down_interruptible(&ebt_mutex);
+	ret = mutex_lock_interruptible(&ebt_mutex);
 	if (ret != 0)
 		return ret;
 	if (!list_named_insert(&ebt_matches, match)) {
-		up(&ebt_mutex);
+		mutex_unlock(&ebt_mutex);
 		return -EEXIST;
 	}
-	up(&ebt_mutex);
+	mutex_unlock(&ebt_mutex);
 
 	return 0;
 }
 
 void ebt_unregister_match(struct ebt_match *match)
 {
-	down(&ebt_mutex);
+	mutex_lock(&ebt_mutex);
 	LIST_DELETE(&ebt_matches, match);
-	up(&ebt_mutex);
+	mutex_unlock(&ebt_mutex);
 }
 
 int ebt_register_watcher(struct ebt_watcher *watcher)
 {
 	int ret;
 
-	ret = down_interruptible(&ebt_mutex);
+	ret = mutex_lock_interruptible(&ebt_mutex);
 	if (ret != 0)
 		return ret;
 	if (!list_named_insert(&ebt_watchers, watcher)) {
-		up(&ebt_mutex);
+		mutex_unlock(&ebt_mutex);
 		return -EEXIST;
 	}
-	up(&ebt_mutex);
+	mutex_unlock(&ebt_mutex);
 
 	return 0;
 }
 
 void ebt_unregister_watcher(struct ebt_watcher *watcher)
 {
-	down(&ebt_mutex);
+	mutex_lock(&ebt_mutex);
 	LIST_DELETE(&ebt_watchers, watcher);
-	up(&ebt_mutex);
+	mutex_unlock(&ebt_mutex);
 }
 
 int ebt_register_table(struct ebt_table *table)
@@ -1178,7 +1179,7 @@
 
 	table->private = newinfo;
 	rwlock_init(&table->lock);
-	ret = down_interruptible(&ebt_mutex);
+	ret = mutex_lock_interruptible(&ebt_mutex);
 	if (ret != 0)
 		goto free_chainstack;
 
@@ -1194,10 +1195,10 @@
 		goto free_unlock;
 	}
 	list_prepend(&ebt_tables, table);
-	up(&ebt_mutex);
+	mutex_unlock(&ebt_mutex);
 	return 0;
 free_unlock:
-	up(&ebt_mutex);
+	mutex_unlock(&ebt_mutex);
 free_chainstack:
 	if (newinfo->chainstack) {
 		for_each_cpu(i)
@@ -1218,9 +1219,9 @@
 		BUGPRINT("Request to unregister NULL table!!!\n");
 		return;
 	}
-	down(&ebt_mutex);
+	mutex_lock(&ebt_mutex);
 	LIST_DELETE(&ebt_tables, table);
-	up(&ebt_mutex);
+	mutex_unlock(&ebt_mutex);
 	vfree(table->private->entries);
 	if (table->private->chainstack) {
 		for_each_cpu(i)
@@ -1281,7 +1282,7 @@
 	write_unlock_bh(&t->lock);
 	ret = 0;
 unlock_mutex:
-	up(&ebt_mutex);
+	mutex_unlock(&ebt_mutex);
 free_tmp:
 	vfree(tmp);
 	return ret;
@@ -1328,7 +1329,7 @@
 	return 0;
 }
 
-/* called with ebt_mutex down */
+/* called with ebt_mutex locked */
 static int copy_everything_to_user(struct ebt_table *t, void __user *user,
    int *len, int cmd)
 {
@@ -1440,7 +1441,7 @@
 	case EBT_SO_GET_INIT_INFO:
 		if (*len != sizeof(struct ebt_replace)){
 			ret = -EINVAL;
-			up(&ebt_mutex);
+			mutex_unlock(&ebt_mutex);
 			break;
 		}
 		if (cmd == EBT_SO_GET_INFO) {
@@ -1452,7 +1453,7 @@
 			tmp.entries_size = t->table->entries_size;
 			tmp.valid_hooks = t->table->valid_hooks;
 		}
-		up(&ebt_mutex);
+		mutex_unlock(&ebt_mutex);
 		if (copy_to_user(user, &tmp, *len) != 0){
 			BUGPRINT("c2u Didn't work\n");
 			ret = -EFAULT;
@@ -1464,11 +1465,11 @@
 	case EBT_SO_GET_ENTRIES:
 	case EBT_SO_GET_INIT_ENTRIES:
 		ret = copy_everything_to_user(t, user, len, cmd);
-		up(&ebt_mutex);
+		mutex_unlock(&ebt_mutex);
 		break;
 
 	default:
-		up(&ebt_mutex);
+		mutex_unlock(&ebt_mutex);
 		ret = -EINVAL;
 	}
 
@@ -1484,9 +1485,9 @@
 {
 	int ret;
 
-	down(&ebt_mutex);
+	mutex_lock(&ebt_mutex);
 	list_named_insert(&ebt_targets, &ebt_standard_target);
-	up(&ebt_mutex);
+	mutex_unlock(&ebt_mutex);
 	if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0)
 		return ret;
 
diff -urN oldtree/net/core/Makefile newtree/net/core/Makefile
--- oldtree/net/core/Makefile	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/core/Makefile	2006-02-21 15:58:15.726755728 +0000
@@ -14,5 +14,5 @@
 obj-$(CONFIG_SYSFS) += net-sysfs.o
 obj-$(CONFIG_NET_DIVERT) += dv.o
 obj-$(CONFIG_NET_PKTGEN) += pktgen.o
-obj-$(CONFIG_NET_RADIO) += wireless.o
+obj-$(CONFIG_WIRELESS_EXT) += wireless.o
 obj-$(CONFIG_NETPOLL) += netpoll.o
diff -urN oldtree/net/core/dev.c newtree/net/core/dev.c
--- oldtree/net/core/dev.c	2006-02-19 11:41:06.281388184 +0000
+++ newtree/net/core/dev.c	2006-02-21 15:58:36.993522688 +0000
@@ -81,6 +81,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/mutex.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/socket.h>
@@ -110,10 +111,8 @@
 #include <linux/netpoll.h>
 #include <linux/rcupdate.h>
 #include <linux/delay.h>
-#ifdef CONFIG_NET_RADIO
-#include <linux/wireless.h>		/* Note : will define WIRELESS_EXT */
+#include <linux/wireless.h>
 #include <net/iw_handler.h>
-#endif	/* CONFIG_NET_RADIO */
 #include <asm/current.h>
 
 /*
@@ -1579,7 +1578,7 @@
 	struct packet_type *ptype, *pt_prev;
 	struct net_device *orig_dev;
 	int ret = NET_RX_DROP;
-	unsigned short type;
+	__be16 type;
 
 	/* if we've gotten here through NAPI, check netpoll */
 	if (skb->dev->poll && netpoll_rx(skb))
@@ -2028,7 +2027,7 @@
 	.release = seq_release,
 };
 
-#ifdef WIRELESS_EXT
+#ifdef CONFIG_WIRELESS_EXT
 extern int wireless_proc_init(void);
 #else
 #define wireless_proc_init() 0
@@ -2152,12 +2151,20 @@
 
 	flags = (dev->flags & ~(IFF_PROMISC |
 				IFF_ALLMULTI |
-				IFF_RUNNING)) | 
+				IFF_RUNNING |
+				IFF_LOWER_UP |
+				IFF_DORMANT)) | 
 		(dev->gflags & (IFF_PROMISC |
 				IFF_ALLMULTI));
 
-	if (netif_running(dev) && netif_carrier_ok(dev))
-		flags |= IFF_RUNNING;
+	if (netif_running(dev)) {
+		if (netif_oper_up(dev))
+			flags |= IFF_RUNNING;
+		if (netif_carrier_ok(dev))
+			flags |= IFF_LOWER_UP;
+		if (netif_dormant(dev))
+			flags |= IFF_DORMANT;
+	}		
 
 	return flags;
 }
@@ -2436,9 +2443,9 @@
 	 */
 
 	if (cmd == SIOCGIFCONF) {
-		rtnl_shlock();
+		rtnl_lock();
 		ret = dev_ifconf((char __user *) arg);
-		rtnl_shunlock();
+		rtnl_unlock();
 		return ret;
 	}
 	if (cmd == SIOCGIFNAME)
@@ -2582,7 +2589,7 @@
 					ret = -EFAULT;
 				return ret;
 			}
-#ifdef WIRELESS_EXT
+#ifdef CONFIG_WIRELESS_EXT
 			/* Take care of Wireless Extensions */
 			if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
 				/* If command is `set a parameter', or
@@ -2603,7 +2610,7 @@
 					ret = -EFAULT;
 				return ret;
 			}
-#endif	/* WIRELESS_EXT */
+#endif	/* CONFIG_WIRELESS_EXT */
 			return -EINVAL;
 	}
 }
@@ -2847,7 +2854,7 @@
 	rebroadcast_time = warning_time = jiffies;
 	while (atomic_read(&dev->refcnt) != 0) {
 		if (time_after(jiffies, rebroadcast_time + 1 * HZ)) {
-			rtnl_shlock();
+			rtnl_lock();
 
 			/* Rebroadcast unregister notification */
 			notifier_call_chain(&netdev_chain,
@@ -2864,7 +2871,7 @@
 				linkwatch_run_queue();
 			}
 
-			rtnl_shunlock();
+			__rtnl_unlock();
 
 			rebroadcast_time = jiffies;
 		}
@@ -2902,7 +2909,7 @@
  * 2) Since we run with the RTNL semaphore not held, we can sleep
  *    safely in order to wait for the netdev refcnt to drop to zero.
  */
-static DECLARE_MUTEX(net_todo_run_mutex);
+static DEFINE_MUTEX(net_todo_run_mutex);
 void netdev_run_todo(void)
 {
 	struct list_head list = LIST_HEAD_INIT(list);
@@ -2910,7 +2917,7 @@
 
 
 	/* Need to guard against multiple cpu's getting out of order. */
-	down(&net_todo_run_mutex);
+	mutex_lock(&net_todo_run_mutex);
 
 	/* Not safe to do outside the semaphore.  We must not return
 	 * until all unregister events invoked by the local processor
@@ -2967,7 +2974,7 @@
 	}
 
 out:
-	up(&net_todo_run_mutex);
+	mutex_unlock(&net_todo_run_mutex);
 }
 
 /**
diff -urN oldtree/net/core/dv.c newtree/net/core/dv.c
--- oldtree/net/core/dv.c	2006-02-19 11:41:06.282388032 +0000
+++ newtree/net/core/dv.c	2006-02-21 15:58:36.995522384 +0000
@@ -86,17 +86,18 @@
 /*
  * Adds a tcp/udp (source or dest) port to an array
  */
-static int add_port(u16 ports[], u16 port)
+static int add_port(__be16 ports[], u16 hport)
 {
 	int i;
+	__be16 port;
 
-	if (port == 0)
+	if (hport == 0)
 		return -EINVAL;
 
 	/* Storing directly in network format for performance,
 	 * thanks Dave :)
 	 */
-	port = htons(port);
+	port = htons(hport);
 
 	for (i = 0; i < MAX_DIVERT_PORTS; i++) {
 		if (ports[i] == port)
@@ -116,17 +117,18 @@
 /*
  * Removes a port from an array tcp/udp (source or dest)
  */
-static int remove_port(u16 ports[], u16 port)
+static int remove_port(__be16 ports[], u16 hport)
 {
 	int i;
+	__be16 port;
 
-	if (port == 0)
+	if (hport == 0)
 		return -EINVAL;
 	
 	/* Storing directly in network format for performance,
 	 * thanks Dave !
 	 */
-	port = htons(port);
+	port = htons(hport);
 
 	for (i = 0; i < MAX_DIVERT_PORTS; i++) {
 		if (ports[i] == port) {
@@ -454,7 +456,8 @@
 	struct tcphdr			*tcph;
 	struct udphdr			*udph;
 	struct divert_blk		*divert = skb->dev->divert;
-	int				i, src, dst;
+	int				i;
+	__be16				src, dst;
 	unsigned char			*skb_data_end = skb->data + skb->len;
 
 	/* Packet is already aimed at us, return */
diff -urN oldtree/net/core/filter.c newtree/net/core/filter.c
--- oldtree/net/core/filter.c	2006-02-19 11:41:06.284387728 +0000
+++ newtree/net/core/filter.c	2006-02-21 15:58:36.995522384 +0000
@@ -177,7 +177,7 @@
 load_w:
 			ptr = load_pointer(skb, k, 4, &tmp);
 			if (ptr != NULL) {
-				A = ntohl(*(u32 *)ptr);
+				A = ntohl(*(__be32 *)ptr);
 				continue;
 			}
 			break;
@@ -186,7 +186,7 @@
 load_h:
 			ptr = load_pointer(skb, k, 2, &tmp);
 			if (ptr != NULL) {
-				A = ntohs(*(u16 *)ptr);
+				A = ntohs(*(__be16 *)ptr);
 				continue;
 			}
 			break;
@@ -260,7 +260,7 @@
 		 */
 		switch (k-SKF_AD_OFF) {
 		case SKF_AD_PROTOCOL:
-			A = htons(skb->protocol);
+			A = ntohs(skb->protocol);
 			continue;
 		case SKF_AD_PKTTYPE:
 			A = skb->pkt_type;
diff -urN oldtree/net/core/flow.c newtree/net/core/flow.c
--- oldtree/net/core/flow.c	2006-02-19 11:41:06.284387728 +0000
+++ newtree/net/core/flow.c	2006-02-21 15:58:16.637617256 +0000
@@ -20,6 +20,7 @@
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <linux/cpumask.h>
+#include <linux/mutex.h>
 #include <net/flow.h>
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
@@ -287,11 +288,11 @@
 void flow_cache_flush(void)
 {
 	struct flow_flush_info info;
-	static DECLARE_MUTEX(flow_flush_sem);
+	static DEFINE_MUTEX(flow_flush_sem);
 
 	/* Don't want cpus going down or up during this. */
 	lock_cpu_hotplug();
-	down(&flow_flush_sem);
+	mutex_lock(&flow_flush_sem);
 	atomic_set(&info.cpuleft, num_online_cpus());
 	init_completion(&info.completion);
 
@@ -301,7 +302,7 @@
 	local_bh_enable();
 
 	wait_for_completion(&info.completion);
-	up(&flow_flush_sem);
+	mutex_unlock(&flow_flush_sem);
 	unlock_cpu_hotplug();
 }
 
diff -urN oldtree/net/core/link_watch.c newtree/net/core/link_watch.c
--- oldtree/net/core/link_watch.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/core/link_watch.c	2006-02-21 15:58:16.578626224 +0000
@@ -49,6 +49,45 @@
 /* Avoid kmalloc() for most systems */
 static struct lw_event singleevent;
 
+static unsigned char default_operstate(const struct net_device *dev)
+{
+	if (!netif_carrier_ok(dev))
+		return (dev->ifindex != dev->iflink ?
+			IF_OPER_LOWERLAYERDOWN : IF_OPER_DOWN);
+
+	if (netif_dormant(dev))
+		return IF_OPER_DORMANT;
+
+	return IF_OPER_UP;
+}	
+
+
+static void rfc2863_policy(struct net_device *dev)
+{
+	unsigned char operstate = default_operstate(dev);
+	
+	if (operstate == dev->operstate)
+		return;
+
+	write_lock_bh(&dev_base_lock);
+
+	switch(dev->link_mode) {
+	case IF_LINK_MODE_DORMANT:
+		if (operstate == IF_OPER_UP)
+			operstate = IF_OPER_DORMANT;
+		break;
+
+	case IF_LINK_MODE_DEFAULT:
+	default:
+		break;
+	};
+
+	dev->operstate = operstate;
+
+	write_unlock_bh(&dev_base_lock);
+}
+
+	
 /* Must be called with the rtnl semaphore held */
 void linkwatch_run_queue(void)
 {
@@ -74,6 +113,7 @@
 		 */
 		clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state);
 
+		rfc2863_policy(dev);
 		if (dev->flags & IFF_UP) {
 			if (netif_carrier_ok(dev)) {
 				WARN_ON(dev->qdisc_sleeping == &noop_qdisc);
@@ -99,9 +139,9 @@
 	linkwatch_nextevent = jiffies + HZ;
 	clear_bit(LW_RUNNING, &linkwatch_flags);
 
-	rtnl_shlock();
+	rtnl_lock();
 	linkwatch_run_queue();
-	rtnl_shunlock();
+	rtnl_unlock();
 }
 
 
diff -urN oldtree/net/core/neighbour.c newtree/net/core/neighbour.c
--- oldtree/net/core/neighbour.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/core/neighbour.c	2006-02-21 15:58:36.997522080 +0000
@@ -750,11 +750,13 @@
 					  neigh->used + neigh->parms->delay_probe_time)) {
 			NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
 			neigh->nud_state = NUD_DELAY;
+			neigh->updated = jiffies;
 			neigh_suspect(neigh);
 			next = now + neigh->parms->delay_probe_time;
 		} else {
 			NEIGH_PRINTK2("neigh %p is suspected.\n", neigh);
 			neigh->nud_state = NUD_STALE;
+			neigh->updated = jiffies;
 			neigh_suspect(neigh);
 		}
 	} else if (state & NUD_DELAY) {
@@ -762,11 +764,13 @@
 				   neigh->confirmed + neigh->parms->delay_probe_time)) {
 			NEIGH_PRINTK2("neigh %p is now reachable.\n", neigh);
 			neigh->nud_state = NUD_REACHABLE;
+			neigh->updated = jiffies;
 			neigh_connect(neigh);
 			next = neigh->confirmed + neigh->parms->reachable_time;
 		} else {
 			NEIGH_PRINTK2("neigh %p is probed.\n", neigh);
 			neigh->nud_state = NUD_PROBE;
+			neigh->updated = jiffies;
 			atomic_set(&neigh->probes, 0);
 			next = now + neigh->parms->retrans_time;
 		}
@@ -780,6 +784,7 @@
 		struct sk_buff *skb;
 
 		neigh->nud_state = NUD_FAILED;
+		neigh->updated = jiffies; 
 		notify = 1;
 		NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
 		NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
@@ -843,10 +848,12 @@
 		if (neigh->parms->mcast_probes + neigh->parms->app_probes) {
 			atomic_set(&neigh->probes, neigh->parms->ucast_probes);
 			neigh->nud_state     = NUD_INCOMPLETE;
+			neigh->updated = jiffies;
 			neigh_hold(neigh);
 			neigh_add_timer(neigh, now + 1);
 		} else {
 			neigh->nud_state = NUD_FAILED;
+			neigh->updated = jiffies;
 			write_unlock_bh(&neigh->lock);
 
 			if (skb)
@@ -857,6 +864,7 @@
 		NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
 		neigh_hold(neigh);
 		neigh->nud_state = NUD_DELAY;
+		neigh->updated = jiffies;
 		neigh_add_timer(neigh,
 				jiffies + neigh->parms->delay_probe_time);
 	}
@@ -1072,7 +1080,7 @@
 }
 
 static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst,
-			  u16 protocol)
+			  __be16 protocol)
 {
 	struct hh_cache	*hh;
 	struct net_device *dev = dst->dev;
diff -urN oldtree/net/core/net-sysfs.c newtree/net/core/net-sysfs.c
--- oldtree/net/core/net-sysfs.c	2006-02-19 11:41:06.285387576 +0000
+++ newtree/net/core/net-sysfs.c	2006-02-21 15:58:16.299668632 +0000
@@ -91,6 +91,7 @@
 NETDEVICE_SHOW(ifindex, fmt_dec);
 NETDEVICE_SHOW(features, fmt_long_hex);
 NETDEVICE_SHOW(type, fmt_dec);
+NETDEVICE_SHOW(link_mode, fmt_dec);
 
 /* use same locking rules as GIFHWADDR ioctl's */
 static ssize_t format_addr(char *buf, const unsigned char *addr, int len)
@@ -133,6 +134,43 @@
 	return -EINVAL;
 }
 
+static ssize_t show_dormant(struct class_device *dev, char *buf)
+{
+	struct net_device *netdev = to_net_dev(dev);
+
+	if (netif_running(netdev))
+		return sprintf(buf, fmt_dec, !!netif_dormant(netdev));
+
+	return -EINVAL;
+}
+
+static const char *operstates[] = {
+	"unknown",
+	"notpresent", /* currently unused */
+	"down",
+	"lowerlayerdown",
+	"testing", /* currently unused */
+	"dormant",
+	"up"
+};
+	
+static ssize_t show_operstate(struct class_device *dev, char *buf)
+{
+	const struct net_device *netdev = to_net_dev(dev);
+	unsigned char operstate;
+
+	read_lock(&dev_base_lock);
+	operstate = netdev->operstate;
+	if (!netif_running(netdev))
+		operstate = IF_OPER_DOWN;
+	read_unlock(&dev_base_lock);
+
+	if (operstate >= sizeof(operstates))
+		return -EINVAL; /* should not happen */
+
+	return sprintf(buf, "%s\n", operstates[operstate]);
+}
+
 /* read-write attributes */
 NETDEVICE_SHOW(mtu, fmt_dec);
 
@@ -190,9 +228,12 @@
 	__ATTR(ifindex, S_IRUGO, show_ifindex, NULL),
 	__ATTR(features, S_IRUGO, show_features, NULL),
 	__ATTR(type, S_IRUGO, show_type, NULL),
+	__ATTR(link_mode, S_IRUGO, show_link_mode, NULL),
 	__ATTR(address, S_IRUGO, show_address, NULL),
 	__ATTR(broadcast, S_IRUGO, show_broadcast, NULL),
 	__ATTR(carrier, S_IRUGO, show_carrier, NULL),
+	__ATTR(dormant, S_IRUGO, show_dormant, NULL),
+	__ATTR(operstate, S_IRUGO, show_operstate, NULL),
 	__ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu),
 	__ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags),
 	__ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len,
diff -urN oldtree/net/core/netpoll.c newtree/net/core/netpoll.c
--- oldtree/net/core/netpoll.c	2006-02-19 11:41:06.286387424 +0000
+++ newtree/net/core/netpoll.c	2006-02-21 15:58:36.997522080 +0000
@@ -361,7 +361,7 @@
 	struct arphdr *arp;
 	unsigned char *arp_ptr;
 	int size, type = ARPOP_REPLY, ptype = ETH_P_ARP;
-	u32 sip, tip;
+	__be32 sip, tip;
 	struct sk_buff *send_skb;
 	struct netpoll *np = NULL;
 
@@ -669,14 +669,14 @@
 		printk(KERN_INFO "%s: device %s not up yet, forcing it\n",
 		       np->name, np->dev_name);
 
-		rtnl_shlock();
+		rtnl_lock();
 		if (dev_change_flags(ndev, ndev->flags | IFF_UP) < 0) {
 			printk(KERN_ERR "%s: failed to open %s\n",
 			       np->name, np->dev_name);
-			rtnl_shunlock();
+			rtnl_unlock();
 			goto release;
 		}
-		rtnl_shunlock();
+		rtnl_unlock();
 
 		atleast = jiffies + HZ/10;
  		atmost = jiffies + 4*HZ;
diff -urN oldtree/net/core/pktgen.c newtree/net/core/pktgen.c
--- oldtree/net/core/pktgen.c	2006-02-19 11:41:06.287387272 +0000
+++ newtree/net/core/pktgen.c	2006-02-21 15:58:16.639616952 +0000
@@ -125,6 +125,7 @@
 #include <linux/capability.h>
 #include <linux/delay.h>
 #include <linux/timer.h>
+#include <linux/mutex.h>
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
@@ -179,8 +180,8 @@
 #define T_REMDEV      (1<<3)  /* Remove all devs */
 
 /* Locks */
-#define   thread_lock()        down(&pktgen_sem)
-#define   thread_unlock()      up(&pktgen_sem)
+#define   thread_lock()        mutex_lock(&pktgen_mutex)
+#define   thread_unlock()      mutex_unlock(&pktgen_mutex)
 
 /* If lock -- can be removed after some work */
 #define   if_lock(t)           spin_lock(&(t->if_lock));
@@ -491,7 +492,7 @@
 static int pg_clone_skb_d;
 static int debug;
 
-static DECLARE_MUTEX(pktgen_sem);
+static DEFINE_MUTEX(pktgen_mutex);
 static struct pktgen_thread *pktgen_threads = NULL;
 
 static struct notifier_block pktgen_notifier_block = {
diff -urN oldtree/net/core/rtnetlink.c newtree/net/core/rtnetlink.c
--- oldtree/net/core/rtnetlink.c	2006-02-19 11:41:06.288387120 +0000
+++ newtree/net/core/rtnetlink.c	2006-02-21 15:58:16.579626072 +0000
@@ -35,6 +35,7 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/security.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -51,25 +52,31 @@
 #include <net/pkt_sched.h>
 #include <net/netlink.h>
 
-DECLARE_MUTEX(rtnl_sem);
+static DEFINE_MUTEX(rtnl_mutex);
 
 void rtnl_lock(void)
 {
-	rtnl_shlock();
+	mutex_lock(&rtnl_mutex);
 }
 
-int rtnl_lock_interruptible(void)
+void __rtnl_unlock(void)
 {
-	return down_interruptible(&rtnl_sem);
+	mutex_unlock(&rtnl_mutex);
 }
- 
+
 void rtnl_unlock(void)
 {
-	rtnl_shunlock();
-
+	mutex_unlock(&rtnl_mutex);
+	if (rtnl && rtnl->sk_receive_queue.qlen)
+		rtnl->sk_data_ready(rtnl, 0);
 	netdev_run_todo();
 }
 
+int rtnl_trylock(void)
+{
+	return mutex_trylock(&rtnl_mutex);
+}
+
 int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len)
 {
 	memset(tb, 0, sizeof(struct rtattr*)*maxattr);
@@ -179,6 +186,33 @@
 }
 
 
+static void set_operstate(struct net_device *dev, unsigned char transition)
+{
+	unsigned char operstate = dev->operstate;
+
+	switch(transition) {
+	case IF_OPER_UP:
+		if ((operstate == IF_OPER_DORMANT ||
+		     operstate == IF_OPER_UNKNOWN) &&
+		    !netif_dormant(dev))
+			operstate = IF_OPER_UP;
+		break;
+
+	case IF_OPER_DORMANT:
+		if (operstate == IF_OPER_UP ||
+		    operstate == IF_OPER_UNKNOWN)
+			operstate = IF_OPER_DORMANT;
+		break;
+	};
+
+	if (dev->operstate != operstate) {
+		write_lock_bh(&dev_base_lock);
+		dev->operstate = operstate;
+		write_unlock_bh(&dev_base_lock);
+		netdev_state_change(dev);
+	}	
+}
+
 static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
 				 int type, u32 pid, u32 seq, u32 change, 
 				 unsigned int flags)
@@ -209,6 +243,13 @@
 	}
 
 	if (1) {
+		u8 operstate = netif_running(dev)?dev->operstate:IF_OPER_DOWN;
+		u8 link_mode = dev->link_mode;
+		RTA_PUT(skb, IFLA_OPERSTATE, sizeof(operstate), &operstate);
+		RTA_PUT(skb, IFLA_LINKMODE, sizeof(link_mode), &link_mode);
+	}	
+
+	if (1) {
 		struct rtnl_link_ifmap map = {
 			.mem_start   = dev->mem_start,
 			.mem_end     = dev->mem_end,
@@ -399,6 +440,22 @@
 		dev->weight = *((u32 *) RTA_DATA(ida[IFLA_WEIGHT - 1]));
 	}
 
+	if (ida[IFLA_OPERSTATE - 1]) {
+		if (ida[IFLA_OPERSTATE - 1]->rta_len != RTA_LENGTH(sizeof(u8)))
+			goto out;
+
+		set_operstate(dev, *((u8 *) RTA_DATA(ida[IFLA_OPERSTATE - 1])));
+	}	
+
+	if (ida[IFLA_LINKMODE - 1]) {
+		if (ida[IFLA_LINKMODE - 1]->rta_len != RTA_LENGTH(sizeof(u8)))
+			goto out;
+
+		write_lock_bh(&dev_base_lock);
+		dev->link_mode = *((u8 *) RTA_DATA(ida[IFLA_LINKMODE - 1]));
+		write_unlock_bh(&dev_base_lock);
+	}
+
 	if (ifm->ifi_index >= 0 && ida[IFLA_IFNAME - 1]) {
 		char ifname[IFNAMSIZ];
 
@@ -575,9 +632,9 @@
 	unsigned int qlen = 0;
 
 	do {
-		rtnl_lock();
+		mutex_lock(&rtnl_mutex);
 		netlink_run_queue(sk, &qlen, &rtnetlink_rcv_msg);
-		up(&rtnl_sem);
+		mutex_unlock(&rtnl_mutex);
 
 		netdev_run_todo();
 	} while (qlen);
@@ -654,6 +711,5 @@
 EXPORT_SYMBOL(rtnetlink_put_metrics);
 EXPORT_SYMBOL(rtnl);
 EXPORT_SYMBOL(rtnl_lock);
-EXPORT_SYMBOL(rtnl_lock_interruptible);
-EXPORT_SYMBOL(rtnl_sem);
+EXPORT_SYMBOL(rtnl_trylock);
 EXPORT_SYMBOL(rtnl_unlock);
diff -urN oldtree/net/core/sysctl_net_core.c newtree/net/core/sysctl_net_core.c
--- oldtree/net/core/sysctl_net_core.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/core/sysctl_net_core.c	2006-02-21 15:58:16.302668176 +0000
@@ -26,6 +26,11 @@
 extern char sysctl_divert_version[];
 #endif /* CONFIG_NET_DIVERT */
 
+#ifdef CONFIG_XFRM
+extern u32 sysctl_xfrm_aevent_etime;
+extern u32 sysctl_xfrm_aevent_rseqth;
+#endif
+
 ctl_table core_table[] = {
 #ifdef CONFIG_NET
 	{
@@ -111,6 +116,24 @@
 		.proc_handler	= &proc_dostring
 	},
 #endif /* CONFIG_NET_DIVERT */
+#ifdef CONFIG_XFRM
+	{
+		.ctl_name	= NET_CORE_AEVENT_ETIME,
+		.procname	= "xfrm_aevent_etime",
+		.data		= &sysctl_xfrm_aevent_etime,
+		.maxlen		= sizeof(u32),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec
+	},
+	{
+		.ctl_name	= NET_CORE_AEVENT_RSEQTH,
+		.procname	= "xfrm_aevent_rseqth",
+		.data		= &sysctl_xfrm_aevent_rseqth,
+		.maxlen		= sizeof(u32),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec
+	},
+#endif /* CONFIG_XFRM */
 #endif /* CONFIG_NET */
 	{
 		.ctl_name	= NET_CORE_SOMAXCONN,
diff -urN oldtree/net/dccp/Kconfig newtree/net/dccp/Kconfig
--- oldtree/net/dccp/Kconfig	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/dccp/Kconfig	2006-02-21 15:58:16.302668176 +0000
@@ -24,6 +24,10 @@
 	def_tristate y if (IP_DCCP = y && INET_DIAG = y)
 	def_tristate m
 
+config IP_DCCP_ACKVEC
+	depends on IP_DCCP
+	def_bool N
+
 source "net/dccp/ccids/Kconfig"
 
 menu "DCCP Kernel Hacking"
diff -urN oldtree/net/dccp/Makefile newtree/net/dccp/Makefile
--- oldtree/net/dccp/Makefile	2006-02-19 11:41:06.293386360 +0000
+++ newtree/net/dccp/Makefile	2006-02-21 15:58:16.302668176 +0000
@@ -4,7 +4,7 @@
 
 obj-$(CONFIG_IP_DCCP) += dccp.o
 
-dccp-y := ccid.o input.o ipv4.o minisocks.o options.o output.o proto.o \
+dccp-y := ccid.o feat.o input.o ipv4.o minisocks.o options.o output.o proto.o \
 	  timer.o
 
 dccp-$(CONFIG_IP_DCCP_ACKVEC) += ackvec.o
diff -urN oldtree/net/dccp/ackvec.c newtree/net/dccp/ackvec.c
--- oldtree/net/dccp/ackvec.c	2006-02-19 11:41:06.293386360 +0000
+++ newtree/net/dccp/ackvec.c	2006-02-21 15:58:16.304667872 +0000
@@ -13,18 +13,77 @@
 #include "dccp.h"
 
 #include <linux/dccp.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
 #include <linux/skbuff.h>
+#include <linux/slab.h>
 
 #include <net/sock.h>
 
+static kmem_cache_t *dccp_ackvec_slab;
+static kmem_cache_t *dccp_ackvec_record_slab;
+
+static struct dccp_ackvec_record *dccp_ackvec_record_new(void)
+{
+	struct dccp_ackvec_record *avr =
+			kmem_cache_alloc(dccp_ackvec_record_slab, GFP_ATOMIC);
+
+	if (avr != NULL)
+		INIT_LIST_HEAD(&avr->dccpavr_node);
+
+	return avr;
+}
+
+static void dccp_ackvec_record_delete(struct dccp_ackvec_record *avr)
+{
+	if (unlikely(avr == NULL))
+		return;
+	/* Check if deleting a linked record */
+	WARN_ON(!list_empty(&avr->dccpavr_node));
+	kmem_cache_free(dccp_ackvec_record_slab, avr);
+}
+ 
+static void dccp_ackvec_insert_avr(struct dccp_ackvec *av, 
+				   struct dccp_ackvec_record *avr)
+{
+	/*
+	 * AVRs are sorted by seqno. Since we are sending them in order, we
+	 * just add the AVR at the head of the list.
+	 * -sorbo.
+	 */
+	if (!list_empty(&av->dccpav_records)) {
+		const struct dccp_ackvec_record *head =
+					list_entry(av->dccpav_records.next,
+						   struct dccp_ackvec_record,
+						   dccpavr_node);
+		BUG_ON(before48(avr->dccpavr_ack_seqno,
+				head->dccpavr_ack_seqno));
+	}
+
+	list_add(&avr->dccpavr_node, &av->dccpav_records);
+}
+
 int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
+#ifdef CONFIG_IP_DCCP_DEBUG
+	const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
+				"CLIENT tx: " : "server tx: ";
+#endif
 	struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
 	int len = av->dccpav_vec_len + 2;
 	struct timeval now;
 	u32 elapsed_time;
 	unsigned char *to, *from;
+	struct dccp_ackvec_record *avr;
+
+	if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
+		return -1;
+
+	avr = dccp_ackvec_record_new();
+	if (avr == NULL)
+		return -1;
 
 	dccp_timestamp(sk, &now);
 	elapsed_time = timeval_delta(&now, &av->dccpav_time) / 10;
@@ -32,19 +91,6 @@
 	if (elapsed_time != 0)
 		dccp_insert_option_elapsed_time(sk, skb, elapsed_time);
 
-	if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
-		return -1;
-
-	/*
-	 * XXX: now we have just one ack vector sent record, so
-	 * we have to wait for it to be cleared.
-	 *
-	 * Of course this is not acceptable, but this is just for
-	 * basic testing now.
-	 */
-	if (av->dccpav_ack_seqno != DCCP_MAX_SEQNO + 1)
-		return -1;
-
 	DCCP_SKB_CB(skb)->dccpd_opt_len += len;
 
 	to    = skb_push(skb, len);
@@ -55,8 +101,8 @@
 	from = av->dccpav_buf + av->dccpav_buf_head;
 
 	/* Check if buf_head wraps */
-	if ((int)av->dccpav_buf_head + len > av->dccpav_vec_len) {
-		const u32 tailsize = av->dccpav_vec_len - av->dccpav_buf_head;
+	if ((int)av->dccpav_buf_head + len > DCCP_MAX_ACKVEC_LEN) {
+		const u32 tailsize = DCCP_MAX_ACKVEC_LEN - av->dccpav_buf_head;
 
 		memcpy(to, from, tailsize);
 		to   += tailsize;
@@ -73,45 +119,37 @@
 	 *	sequence number it used for the ack packet; ack_ptr will equal
 	 *	buf_head; ack_ackno will equal buf_ackno; and ack_nonce will
 	 *	equal buf_nonce.
-	 *
-	 * This implemention uses just one ack record for now.
 	 */
-	av->dccpav_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq;
-	av->dccpav_ack_ptr   = av->dccpav_buf_head;
-	av->dccpav_ack_ackno = av->dccpav_buf_ackno;
-	av->dccpav_ack_nonce = av->dccpav_buf_nonce;
-	av->dccpav_sent_len  = av->dccpav_vec_len;
+	avr->dccpavr_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq;
+	avr->dccpavr_ack_ptr   = av->dccpav_buf_head;
+	avr->dccpavr_ack_ackno = av->dccpav_buf_ackno;
+	avr->dccpavr_ack_nonce = av->dccpav_buf_nonce;
+	avr->dccpavr_sent_len  = av->dccpav_vec_len;
+
+	dccp_ackvec_insert_avr(av, avr);
 
 	dccp_pr_debug("%sACK Vector 0, len=%d, ack_seqno=%llu, "
 		      "ack_ackno=%llu\n",
-		      debug_prefix, av->dccpav_sent_len,
-		      (unsigned long long)av->dccpav_ack_seqno,
-		      (unsigned long long)av->dccpav_ack_ackno);
-	return -1;
+		      debug_prefix, avr->dccpavr_sent_len,
+		      (unsigned long long)avr->dccpavr_ack_seqno,
+		      (unsigned long long)avr->dccpavr_ack_ackno);
+	return 0;
 }
 
-struct dccp_ackvec *dccp_ackvec_alloc(const unsigned int len,
-				      const gfp_t priority)
+struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority)
 {
-	struct dccp_ackvec *av;
-
-	BUG_ON(len == 0);
+	struct dccp_ackvec *av = kmem_cache_alloc(dccp_ackvec_slab, priority);
 
-	if (len > DCCP_MAX_ACKVEC_LEN)
-		return NULL;
-
-	av = kmalloc(sizeof(*av) + len, priority);
 	if (av != NULL) {
-		av->dccpav_buf_len	= len;
 		av->dccpav_buf_head	=
-			av->dccpav_buf_tail = av->dccpav_buf_len - 1;
-		av->dccpav_buf_ackno	=
-			av->dccpav_ack_ackno = av->dccpav_ack_seqno = ~0LLU;
+			av->dccpav_buf_tail = DCCP_MAX_ACKVEC_LEN - 1;
+		av->dccpav_buf_ackno	= DCCP_MAX_SEQNO + 1;
 		av->dccpav_buf_nonce = av->dccpav_buf_nonce = 0;
 		av->dccpav_ack_ptr	= 0;
 		av->dccpav_time.tv_sec	= 0;
 		av->dccpav_time.tv_usec	= 0;
 		av->dccpav_sent_len	= av->dccpav_vec_len = 0;
+		INIT_LIST_HEAD(&av->dccpav_records);
 	}
 
 	return av;
@@ -119,7 +157,20 @@
 
 void dccp_ackvec_free(struct dccp_ackvec *av)
 {
-	kfree(av);
+	if (unlikely(av == NULL))
+		return;
+
+	if (!list_empty(&av->dccpav_records)) {
+		struct dccp_ackvec_record *avr, *next;
+
+		list_for_each_entry_safe(avr, next, &av->dccpav_records,
+					 dccpavr_node) {
+			list_del_init(&avr->dccpavr_node);
+			dccp_ackvec_record_delete(avr);
+		}
+	}
+
+	kmem_cache_free(dccp_ackvec_slab, av);
 }
 
 static inline u8 dccp_ackvec_state(const struct dccp_ackvec *av,
@@ -146,7 +197,7 @@
 	unsigned int gap;
 	long new_head;
 
-	if (av->dccpav_vec_len + packets > av->dccpav_buf_len)
+	if (av->dccpav_vec_len + packets > DCCP_MAX_ACKVEC_LEN)
 		return -ENOBUFS;
 
 	gap	 = packets - 1;
@@ -158,7 +209,7 @@
 			       gap + new_head + 1);
 			gap = -new_head;
 		}
-		new_head += av->dccpav_buf_len;
+		new_head += DCCP_MAX_ACKVEC_LEN;
 	} 
 
 	av->dccpav_buf_head = new_head;
@@ -251,7 +302,7 @@
 				goto out_duplicate;
 
 			delta -= len + 1;
-			if (++index == av->dccpav_buf_len)
+			if (++index == DCCP_MAX_ACKVEC_LEN)
 				index = 0;
 		}
 	}
@@ -297,44 +348,50 @@
 }
 #endif
 
-static void dccp_ackvec_throw_away_ack_record(struct dccp_ackvec *av)
+static void dccp_ackvec_throw_record(struct dccp_ackvec *av,
+				     struct dccp_ackvec_record *avr)
 {
-	/*
-	 * As we're keeping track of the ack vector size (dccpav_vec_len) and
-	 * the sent ack vector size (dccpav_sent_len) we don't need
-	 * dccpav_buf_tail at all, but keep this code here as in the future
-	 * we'll implement a vector of ack records, as suggested in
-	 * draft-ietf-dccp-spec-11.txt Appendix A. -acme
-	 */
-#if 0
-	u32 new_buf_tail = av->dccpav_ack_ptr + 1;
-	if (new_buf_tail >= av->dccpav_vec_len)
-		new_buf_tail -= av->dccpav_vec_len;
-	av->dccpav_buf_tail = new_buf_tail;
-#endif
-	av->dccpav_vec_len -= av->dccpav_sent_len;
+	struct dccp_ackvec_record *next;
+
+	av->dccpav_buf_tail = avr->dccpavr_ack_ptr - 1;
+	if (av->dccpav_buf_tail == 0)
+		av->dccpav_buf_tail = DCCP_MAX_ACKVEC_LEN - 1;
+
+	av->dccpav_vec_len -= avr->dccpavr_sent_len;
+
+	/* free records */
+	list_for_each_entry_safe_from(avr, next, &av->dccpav_records,
+				      dccpavr_node) {
+		list_del_init(&avr->dccpavr_node);
+		dccp_ackvec_record_delete(avr);
+	}
 }
 
 void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av, struct sock *sk,
 				 const u64 ackno)
 {
-	/* Check if we actually sent an ACK vector */
-	if (av->dccpav_ack_seqno == DCCP_MAX_SEQNO + 1)
-		return;
+	struct dccp_ackvec_record *avr;
 
-	if (ackno == av->dccpav_ack_seqno) {
+	/*
+	 * If we traverse backwards, it should be faster when we have large
+	 * windows. We will be receiving ACKs for stuff we sent a while back
+	 * -sorbo.
+	 */
+	list_for_each_entry_reverse(avr, &av->dccpav_records, dccpavr_node) {
+		if (ackno == avr->dccpavr_ack_seqno) {
 #ifdef CONFIG_IP_DCCP_DEBUG
-		struct dccp_sock *dp = dccp_sk(sk);
-		const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
-					"CLIENT rx ack: " : "server rx ack: ";
+			struct dccp_sock *dp = dccp_sk(sk);
+			const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
+						"CLIENT rx ack: " : "server rx ack: ";
 #endif
-		dccp_pr_debug("%sACK packet 0, len=%d, ack_seqno=%llu, "
-			      "ack_ackno=%llu, ACKED!\n",
-			      debug_prefix, 1,
-			      (unsigned long long)av->dccpav_ack_seqno,
-			      (unsigned long long)av->dccpav_ack_ackno);
-		dccp_ackvec_throw_away_ack_record(av);
-		av->dccpav_ack_seqno = DCCP_MAX_SEQNO + 1;
+			dccp_pr_debug("%sACK packet 0, len=%d, ack_seqno=%llu, "
+				      "ack_ackno=%llu, ACKED!\n",
+				      debug_prefix, 1,
+				      (unsigned long long)avr->dccpavr_ack_seqno,
+				      (unsigned long long)avr->dccpavr_ack_ackno);
+			dccp_ackvec_throw_record(av, avr);
+			break;
+		}
 	}
 }
 
@@ -344,28 +401,20 @@
 					    const unsigned char *vector)
 {
 	unsigned char i;
+	struct dccp_ackvec_record *avr;
 
 	/* Check if we actually sent an ACK vector */
-	if (av->dccpav_ack_seqno == DCCP_MAX_SEQNO + 1)
+	if (list_empty(&av->dccpav_records))
 		return;
-	/*
-	 * We're in the receiver half connection, so if the received an ACK
-	 * vector ackno (e.g. 50) before dccpav_ack_seqno (e.g. 52), we're
-	 * not interested.
-	 *
-	 * Extra explanation with example:
-	 * 
-	 * if we received an ACK vector with ackno 50, it can only be acking
-	 * 50, 49, 48, etc, not 52 (the seqno for the ACK vector we sent).
-	 */
-	/* dccp_pr_debug("is %llu < %llu? ", ackno, av->dccpav_ack_seqno); */
-	if (before48(ackno, av->dccpav_ack_seqno)) {
-		/* dccp_pr_debug_cat("yes\n"); */
-		return;
-	}
-	/* dccp_pr_debug_cat("no\n"); */
 
 	i = len;
+	/*
+	 * XXX
+	 * I think it might be more efficient to work backwards. See comment on
+	 * rcv_ackno. -sorbo.
+	 */
+	avr = list_entry(av->dccpav_records.next, struct dccp_ackvec_record,
+			 dccpavr_node);
 	while (i--) {
 		const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK;
 		u64 ackno_end_rl;
@@ -373,14 +422,20 @@
 		dccp_set_seqno(&ackno_end_rl, ackno - rl);
 
 		/*
-		 * dccp_pr_debug("is %llu <= %llu <= %llu? ", ackno_end_rl,
-		 * av->dccpav_ack_seqno, ackno);
+		 * If our AVR sequence number is greater than the ack, go
+		 * forward in the AVR list until it is not so.
 		 */
-		if (between48(av->dccpav_ack_seqno, ackno_end_rl, ackno)) {
+		list_for_each_entry_from(avr, &av->dccpav_records,
+					 dccpavr_node) {
+			if (!after48(avr->dccpavr_ack_seqno, ackno))
+				goto found;
+		}
+		/* End of the dccpav_records list, not found, exit */
+		break;
+found:
+		if (between48(avr->dccpavr_ack_seqno, ackno_end_rl, ackno)) {
 			const u8 state = (*vector &
 					  DCCP_ACKVEC_STATE_MASK) >> 6;
-			/* dccp_pr_debug_cat("yes\n"); */
-
 			if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED) {
 #ifdef CONFIG_IP_DCCP_DEBUG
 				struct dccp_sock *dp = dccp_sk(sk);
@@ -393,19 +448,16 @@
 					      "ACKED!\n",
 					      debug_prefix, len,
 					      (unsigned long long)
-					      av->dccpav_ack_seqno,
+					      avr->dccpavr_ack_seqno,
 					      (unsigned long long)
-					      av->dccpav_ack_ackno);
-				dccp_ackvec_throw_away_ack_record(av);
+					      avr->dccpavr_ack_ackno);
+				dccp_ackvec_throw_record(av, avr);
 			}
 			/*
-			 * If dccpav_ack_seqno was not received, no problem
-			 * we'll send another ACK vector.
+			 * If it wasn't received, continue scanning... we might
+			 * find another one.
 			 */
-			av->dccpav_ack_seqno = DCCP_MAX_SEQNO + 1;
-			break;
 		}
-		/* dccp_pr_debug_cat("no\n"); */
 
 		dccp_set_seqno(&ackno, ackno_end_rl - 1);
 		++vector;
@@ -424,3 +476,43 @@
 				        len, value);
 	return 0;
 }
+
+static char dccp_ackvec_slab_msg[] __initdata =
+	KERN_CRIT "DCCP: Unable to create ack vectors slab caches\n";
+
+int __init dccp_ackvec_init(void)
+{
+	dccp_ackvec_slab = kmem_cache_create("dccp_ackvec",
+					     sizeof(struct dccp_ackvec), 0,
+					     SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (dccp_ackvec_slab == NULL)
+		goto out_err;
+
+	dccp_ackvec_record_slab =
+			kmem_cache_create("dccp_ackvec_record",
+					  sizeof(struct dccp_ackvec_record),
+					  0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (dccp_ackvec_record_slab == NULL)
+		goto out_destroy_slab;
+
+	return 0;
+
+out_destroy_slab:
+	kmem_cache_destroy(dccp_ackvec_slab);
+	dccp_ackvec_slab = NULL;
+out_err:
+	printk(dccp_ackvec_slab_msg);
+	return -ENOBUFS;
+}
+
+void dccp_ackvec_exit(void)
+{
+	if (dccp_ackvec_slab != NULL) {
+		kmem_cache_destroy(dccp_ackvec_slab);
+		dccp_ackvec_slab = NULL;
+	}
+	if (dccp_ackvec_record_slab != NULL) {
+		kmem_cache_destroy(dccp_ackvec_record_slab);
+		dccp_ackvec_record_slab = NULL;
+	}
+}
diff -urN oldtree/net/dccp/ackvec.h newtree/net/dccp/ackvec.h
--- oldtree/net/dccp/ackvec.h	2006-02-19 11:41:06.294386208 +0000
+++ newtree/net/dccp/ackvec.h	2006-02-21 15:58:16.306667568 +0000
@@ -13,6 +13,7 @@
 
 #include <linux/config.h>
 #include <linux/compiler.h>
+#include <linux/list.h>
 #include <linux/time.h>
 #include <linux/types.h>
 
@@ -42,39 +43,57 @@
  * Ack Vectors it has recently sent. For each packet sent carrying an
  * Ack Vector, it remembers four variables:
  *
- * @dccpav_ack_seqno - the Sequence Number used for the packet
- * 		       (HC-Receiver seqno)
  * @dccpav_ack_ptr - the value of buf_head at the time of acknowledgement.
- * @dccpav_ack_ackno - the Acknowledgement Number used for the packet
- * 		       (HC-Sender seqno)
+ * @dccpav_records - list of dccp_ackvec_record
  * @dccpav_ack_nonce - the one-bit sum of the ECN Nonces for all State 0.
  *
- * @dccpav_buf_len	- circular buffer length
  * @dccpav_time		- the time in usecs
  * @dccpav_buf - circular buffer of acknowledgeable packets
  */
 struct dccp_ackvec {
 	u64		dccpav_buf_ackno;
-	u64		dccpav_ack_seqno;
-	u64		dccpav_ack_ackno;
+	struct list_head dccpav_records;
 	struct timeval	dccpav_time;
 	u8		dccpav_buf_head;
 	u8		dccpav_buf_tail;
 	u8		dccpav_ack_ptr;
 	u8		dccpav_sent_len;
 	u8		dccpav_vec_len;
-	u8		dccpav_buf_len;
 	u8		dccpav_buf_nonce;
 	u8		dccpav_ack_nonce;
-	u8		dccpav_buf[0];
+	u8		dccpav_buf[DCCP_MAX_ACKVEC_LEN];
+};
+
+/** struct dccp_ackvec_record - ack vector record
+ *
+ * ACK vector record as defined in Appendix A of spec. 
+ *
+ * The list is sorted by dccpavr_ack_seqno
+ *
+ * @dccpavr_node - node in dccpav_records
+ * @dccpavr_ack_seqno - sequence number of the packet this record was sent on
+ * @dccpavr_ack_ackno - sequence number being acknowledged
+ * @dccpavr_ack_ptr - pointer into dccpav_buf where this record starts
+ * @dccpavr_ack_nonce - dccpav_ack_nonce at the time this record was sent
+ * @dccpavr_sent_len - lenght of the record in dccpav_buf
+ */
+struct dccp_ackvec_record {
+	struct list_head dccpavr_node;
+	u64		 dccpavr_ack_seqno;
+	u64		 dccpavr_ack_ackno;
+	u8		 dccpavr_ack_ptr;
+	u8		 dccpavr_ack_nonce;
+	u8		 dccpavr_sent_len;
 };
 
 struct sock;
 struct sk_buff;
 
 #ifdef CONFIG_IP_DCCP_ACKVEC
-extern struct dccp_ackvec *dccp_ackvec_alloc(unsigned int len,
-					  const gfp_t priority);
+extern int dccp_ackvec_init(void);
+extern void dccp_ackvec_exit(void);
+
+extern struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority);
 extern void dccp_ackvec_free(struct dccp_ackvec *av);
 
 extern int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
@@ -92,8 +111,16 @@
 	return av->dccpav_sent_len != av->dccpav_vec_len;
 }
 #else /* CONFIG_IP_DCCP_ACKVEC */
-static inline struct dccp_ackvec *dccp_ackvec_alloc(unsigned int len,
-					   const gfp_t priority)
+static inline int dccp_ackvec_init(void)
+{
+	return 0;
+}
+
+static inline void dccp_ackvec_exit(void)
+{
+}
+
+static inline struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority)
 {
 	return NULL;
 }
diff -urN oldtree/net/dccp/ccid.c newtree/net/dccp/ccid.c
--- oldtree/net/dccp/ccid.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/dccp/ccid.c	2006-02-21 15:58:16.306667568 +0000
@@ -59,9 +59,6 @@
 {
 	int err;
 
-	if (ccid->ccid_init == NULL)
-		return -1;
-
 	ccids_write_lock();
 	err = -EEXIST;
 	if (ccids[ccid->ccid_id] == NULL) {
@@ -106,7 +103,7 @@
 	if (!try_module_get(ccid->ccid_owner))
 		goto out_err;
 
-	if (ccid->ccid_init(sk) != 0)
+	if (ccid->ccid_init != NULL && ccid->ccid_init(sk) != 0)
 		goto out_module_put;
 out:
 	ccids_read_unlock();
diff -urN oldtree/net/dccp/ccids/Kconfig newtree/net/dccp/ccids/Kconfig
--- oldtree/net/dccp/ccids/Kconfig	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/dccp/ccids/Kconfig	2006-02-21 15:58:16.307667416 +0000
@@ -1,6 +1,34 @@
 menu "DCCP CCIDs Configuration (EXPERIMENTAL)"
 	depends on IP_DCCP && EXPERIMENTAL
 
+config IP_DCCP_CCID2
+	tristate "CCID2 (TCP) (EXPERIMENTAL)"
+	depends on IP_DCCP
+	select IP_DCCP_ACKVEC
+	---help---
+	  CCID 2, TCP-like Congestion Control, denotes Additive Increase,
+	  Multiplicative Decrease (AIMD) congestion control with behavior
+	  modelled directly on TCP, including congestion window, slow start,
+	  timeouts, and so forth [RFC 2581].  CCID 2 achieves maximum
+	  bandwidth over the long term, consistent with the use of end-to-end
+	  congestion control, but halves its congestion window in response to
+	  each congestion event.  This leads to the abrupt rate changes
+	  typical of TCP.  Applications should use CCID 2 if they prefer
+	  maximum bandwidth utilization to steadiness of rate.  This is often
+	  the case for applications that are not playing their data directly
+	  to the user.  For example, a hypothetical application that
+	  transferred files over DCCP, using application-level retransmissions
+	  for lost packets, would prefer CCID 2 to CCID 3.  On-line games may
+	  also prefer CCID 2.
+
+	  CCID 2 is further described in:
+	  http://www.icir.org/kohler/dccp/draft-ietf-dccp-ccid2-10.txt
+
+	  This text was extracted from:
+	  http://www.icir.org/kohler/dccp/draft-ietf-dccp-spec-13.txt
+
+	  If in doubt, say M.
+
 config IP_DCCP_CCID3
 	tristate "CCID3 (TFRC) (EXPERIMENTAL)"
 	depends on IP_DCCP
@@ -15,10 +43,15 @@
 	  suitable than CCID 2 for applications such streaming media where a
 	  relatively smooth sending rate is of importance.
 
-	  CCID 3 is further described in [CCID 3 PROFILE]. The TFRC
-	  congestion control algorithms were initially described in RFC 3448.
+	  CCID 3 is further described in:
+
+	  http://www.icir.org/kohler/dccp/draft-ietf-dccp-ccid3-11.txt.
+
+	  The TFRC congestion control algorithms were initially described in
+	  RFC 3448.
 
-	  This text was extracted from draft-ietf-dccp-spec-11.txt.
+	  This text was extracted from:
+	  http://www.icir.org/kohler/dccp/draft-ietf-dccp-spec-13.txt
 	  
 	  If in doubt, say M.
 
diff -urN oldtree/net/dccp/ccids/Makefile newtree/net/dccp/ccids/Makefile
--- oldtree/net/dccp/ccids/Makefile	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/dccp/ccids/Makefile	2006-02-21 15:58:16.307667416 +0000
@@ -2,4 +2,8 @@
 
 dccp_ccid3-y := ccid3.o
 
+obj-$(CONFIG_IP_DCCP_CCID2) += dccp_ccid2.o
+
+dccp_ccid2-y := ccid2.o
+
 obj-y += lib/
diff -urN oldtree/net/dccp/ccids/ccid2.c newtree/net/dccp/ccids/ccid2.c
--- oldtree/net/dccp/ccids/ccid2.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/net/dccp/ccids/ccid2.c	2006-02-21 15:58:16.308667264 +0000
@@ -0,0 +1,842 @@
+/*
+ *  net/dccp/ccids/ccid2.c
+ *
+ *  Copyright (c) 2005, 2006 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *
+ *  Changes to meet Linux coding standards, and DCCP infrastructure fixes.
+ *
+ *  Copyright (c) 2006 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This implementation should follow: draft-ietf-dccp-ccid2-10.txt
+ *
+ * BUGS:
+ * - sequence number wrapping
+ * - jiffies wrapping
+ */
+
+#include <linux/config.h>
+#include "../ccid.h"
+#include "../dccp.h"
+#include "ccid2.h"
+
+static int ccid2_debug;
+
+#if 0
+#define CCID2_DEBUG
+#endif
+
+#ifdef CCID2_DEBUG
+#define ccid2_pr_debug(format, a...) \
+        do { if (ccid2_debug) \
+                printk(KERN_DEBUG "%s: " format, __FUNCTION__, ##a); \
+        } while (0)
+#else
+#define ccid2_pr_debug(format, a...)
+#endif
+
+static const int ccid2_seq_len = 128;
+
+static inline struct ccid2_hc_tx_sock *ccid2_hc_tx_sk(const struct sock *sk)
+{
+	return dccp_sk(sk)->dccps_hc_tx_ccid_private;
+}
+
+static inline struct ccid2_hc_rx_sock *ccid2_hc_rx_sk(const struct sock *sk)
+{
+	return dccp_sk(sk)->dccps_hc_rx_ccid_private;
+}
+
+#ifdef CCID2_DEBUG
+static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx)
+{
+	int len = 0;
+	struct ccid2_seq *seqp;
+	int pipe = 0;
+
+	seqp = hctx->ccid2hctx_seqh;
+
+	/* there is data in the chain */
+	if (seqp != hctx->ccid2hctx_seqt) {
+		seqp = seqp->ccid2s_prev;
+		len++;
+		if (!seqp->ccid2s_acked)
+			pipe++;
+	
+		while (seqp != hctx->ccid2hctx_seqt) {
+			struct ccid2_seq *prev;
+
+			prev = seqp->ccid2s_prev;
+			len++;
+			if (!prev->ccid2s_acked)
+				pipe++;
+
+			/* packets are sent sequentially */
+			BUG_ON(seqp->ccid2s_seq <= prev->ccid2s_seq);
+			BUG_ON(seqp->ccid2s_sent < prev->ccid2s_sent);
+			BUG_ON(len > ccid2_seq_len);
+
+			seqp = prev;
+		}
+	}
+
+	BUG_ON(pipe != hctx->ccid2hctx_pipe);
+	ccid2_pr_debug("len of chain=%d\n", len);
+
+	do {
+		seqp = seqp->ccid2s_prev;
+		len++;
+		BUG_ON(len > ccid2_seq_len);
+	} while(seqp != hctx->ccid2hctx_seqh);
+
+	BUG_ON(len != ccid2_seq_len);
+	ccid2_pr_debug("total len=%d\n", len);
+}
+#else
+#define ccid2_hc_tx_check_sanity(hctx) do {} while (0)
+#endif
+
+static int ccid2_hc_tx_send_packet(struct sock *sk,
+				   struct sk_buff *skb, int len)
+{
+	struct ccid2_hc_tx_sock *hctx;
+	
+	switch (DCCP_SKB_CB(skb)->dccpd_type) {
+	case 0: /* XXX data packets from userland come through like this */
+	case DCCP_PKT_DATA:
+	case DCCP_PKT_DATAACK:
+		break;
+	/* No congestion control on other packets */
+	default:
+		return 0;
+	}
+
+        hctx = ccid2_hc_tx_sk(sk);
+
+	ccid2_pr_debug("pipe=%d cwnd=%d\n", hctx->ccid2hctx_pipe,
+		       hctx->ccid2hctx_cwnd);
+	
+	if (hctx->ccid2hctx_pipe < hctx->ccid2hctx_cwnd) {
+		/* OK we can send... make sure previous packet was sent off */
+		if (!hctx->ccid2hctx_sendwait) {
+			hctx->ccid2hctx_sendwait = 1;
+			return 0;
+		}
+	}
+
+	return 100; /* XXX */
+}
+
+static void ccid2_change_l_ack_ratio(struct sock *sk, int val)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	/*
+	 * XXX I don't really agree with val != 2.  If cwnd is 1, ack ratio
+	 * should be 1... it shouldn't be allowed to become 2.
+	 * -sorbo.
+	 */
+	if (val != 2) {
+		struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+		int max = hctx->ccid2hctx_cwnd / 2;
+
+		/* round up */
+		if (hctx->ccid2hctx_cwnd & 1)
+			max++;
+
+		if (val > max)
+			val = max;
+	}
+
+	ccid2_pr_debug("changing local ack ratio to %d\n", val);
+	WARN_ON(val <= 0);
+	dp->dccps_l_ack_ratio = val;
+}
+
+static void ccid2_change_cwnd(struct sock *sk, int val)
+{
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+
+	if (val == 0)
+		val = 1;
+
+	/* XXX do we need to change ack ratio? */
+	ccid2_pr_debug("change cwnd to %d\n", val);
+	
+	BUG_ON(val < 1);
+	hctx->ccid2hctx_cwnd = val;
+}
+
+static void ccid2_start_rto_timer(struct sock *sk);
+
+static void ccid2_hc_tx_rto_expire(unsigned long data)
+{
+	struct sock *sk = (struct sock *)data;
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+	long s;
+
+	/* XXX I don't think i'm locking correctly
+	 * -sorbo.
+	 */
+	bh_lock_sock(sk);
+	if (sock_owned_by_user(sk)) {
+		sk_reset_timer(sk, &hctx->ccid2hctx_rtotimer,
+			       jiffies + HZ / 5);
+		goto out;
+	}
+
+	ccid2_pr_debug("RTO_EXPIRE\n");
+
+	ccid2_hc_tx_check_sanity(hctx);
+
+	/* back-off timer */
+	hctx->ccid2hctx_rto <<= 1;
+
+	s = hctx->ccid2hctx_rto / HZ;
+	if (s > 60)
+		hctx->ccid2hctx_rto = 60 * HZ;
+
+	ccid2_start_rto_timer(sk);
+
+	/* adjust pipe, cwnd etc */
+	hctx->ccid2hctx_pipe = 0;
+	hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd >> 1;
+	if (hctx->ccid2hctx_ssthresh < 2)
+		hctx->ccid2hctx_ssthresh = 2;
+	ccid2_change_cwnd(sk, 1);
+
+	/* clear state about stuff we sent */
+	hctx->ccid2hctx_seqt	= hctx->ccid2hctx_seqh;
+	hctx->ccid2hctx_ssacks	= 0;
+	hctx->ccid2hctx_acks	= 0;
+	hctx->ccid2hctx_sent	= 0;
+
+	/* clear ack ratio state. */
+	hctx->ccid2hctx_arsent	 = 0;
+	hctx->ccid2hctx_ackloss  = 0;
+	hctx->ccid2hctx_rpseq	 = 0;
+	hctx->ccid2hctx_rpdupack = -1;
+	ccid2_change_l_ack_ratio(sk, 1);
+	ccid2_hc_tx_check_sanity(hctx);
+out:
+	bh_unlock_sock(sk);
+	sock_put(sk);
+}
+
+static void ccid2_start_rto_timer(struct sock *sk)
+{
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+
+	ccid2_pr_debug("setting RTO timeout=%ld\n", hctx->ccid2hctx_rto);
+
+	BUG_ON(timer_pending(&hctx->ccid2hctx_rtotimer));
+	sk_reset_timer(sk, &hctx->ccid2hctx_rtotimer,
+		       jiffies + hctx->ccid2hctx_rto);
+}
+
+static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, int len)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+	u64 seq;
+
+	ccid2_hc_tx_check_sanity(hctx);
+
+	BUG_ON(!hctx->ccid2hctx_sendwait);
+	hctx->ccid2hctx_sendwait = 0;
+	hctx->ccid2hctx_pipe++;
+	BUG_ON(hctx->ccid2hctx_pipe < 0);
+
+	/* There is an issue.  What if another packet is sent between
+	 * packet_send() and packet_sent().  Then the sequence number would be
+	 * wrong.
+	 * -sorbo.
+	 */
+	seq = dp->dccps_gss;
+
+	hctx->ccid2hctx_seqh->ccid2s_seq   = seq;
+	hctx->ccid2hctx_seqh->ccid2s_acked = 0;
+	hctx->ccid2hctx_seqh->ccid2s_sent  = jiffies;
+	hctx->ccid2hctx_seqh = hctx->ccid2hctx_seqh->ccid2s_next;
+
+	ccid2_pr_debug("cwnd=%d pipe=%d\n", hctx->ccid2hctx_cwnd, 
+		       hctx->ccid2hctx_pipe);
+	
+	if (hctx->ccid2hctx_seqh == hctx->ccid2hctx_seqt) {
+		/* XXX allocate more space */
+		WARN_ON(1);
+	}
+
+	hctx->ccid2hctx_sent++;
+
+	/* Ack Ratio.  Need to maintain a concept of how many windows we sent */
+	hctx->ccid2hctx_arsent++;
+	/* We had an ack loss in this window... */
+	if (hctx->ccid2hctx_ackloss) {
+		if (hctx->ccid2hctx_arsent >= hctx->ccid2hctx_cwnd) {
+			hctx->ccid2hctx_arsent = 0;
+			hctx->ccid2hctx_ackloss = 0;
+		}
+	}
+	/* No acks lost up to now... */
+	else {
+		/* decrease ack ratio if enough packets were sent */
+		if (dp->dccps_l_ack_ratio > 1) {
+			/* XXX don't calculate denominator each time */
+			int denom;
+
+			denom = dp->dccps_l_ack_ratio * dp->dccps_l_ack_ratio - 
+				dp->dccps_l_ack_ratio;
+			denom = hctx->ccid2hctx_cwnd * hctx->ccid2hctx_cwnd / denom;
+
+			if (hctx->ccid2hctx_arsent >= denom) {
+				ccid2_change_l_ack_ratio(sk, dp->dccps_l_ack_ratio - 1);
+				hctx->ccid2hctx_arsent = 0;
+			}
+		}
+		/* we can't increase ack ratio further [1] */
+		else {
+			hctx->ccid2hctx_arsent = 0; /* or maybe set it to cwnd*/
+		}
+	}
+
+	/* setup RTO timer */
+	if (!timer_pending(&hctx->ccid2hctx_rtotimer)) {
+		ccid2_start_rto_timer(sk);
+	}
+#ifdef CCID2_DEBUG
+	ccid2_pr_debug("pipe=%d\n", hctx->ccid2hctx_pipe);
+	ccid2_pr_debug("Sent: seq=%llu\n", seq);
+	do {
+		struct ccid2_seq *seqp = hctx->ccid2hctx_seqt;
+
+		while (seqp != hctx->ccid2hctx_seqh) {
+			ccid2_pr_debug("out seq=%llu acked=%d time=%lu\n",
+			       	       seqp->ccid2s_seq, seqp->ccid2s_acked, 
+				       seqp->ccid2s_sent);
+			seqp = seqp->ccid2s_next;
+		}
+	} while(0);
+	ccid2_pr_debug("=========\n");
+	ccid2_hc_tx_check_sanity(hctx);
+#endif
+}
+
+/* XXX Lame code duplication!
+ * returns -1 if none was found.
+ * else returns the next offset to use in the function call.
+ */
+static int ccid2_ackvector(struct sock *sk, struct sk_buff *skb, int offset,
+			   unsigned char **vec, unsigned char *veclen)
+{
+        const struct dccp_hdr *dh = dccp_hdr(skb);
+        unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb);
+        unsigned char *opt_ptr;
+        const unsigned char *opt_end = (unsigned char *)dh +
+                                        (dh->dccph_doff * 4);
+        unsigned char opt, len;
+        unsigned char *value;
+
+	BUG_ON(offset < 0);
+	options += offset;
+	opt_ptr = options;
+	if (opt_ptr >= opt_end)
+		return -1;
+
+	while (opt_ptr != opt_end) {
+                opt   = *opt_ptr++;
+                len   = 0;
+                value = NULL;
+
+                /* Check if this isn't a single byte option */
+                if (opt > DCCPO_MAX_RESERVED) {
+                        if (opt_ptr == opt_end)
+                                goto out_invalid_option;
+
+                        len = *opt_ptr++;
+                        if (len < 3)
+                                goto out_invalid_option;
+                        /*
+                         * Remove the type and len fields, leaving
+                         * just the value size
+                         */
+                        len     -= 2;
+                        value   = opt_ptr;
+                        opt_ptr += len;
+
+                        if (opt_ptr > opt_end)
+                                goto out_invalid_option;
+                }
+
+		switch (opt) {
+		case DCCPO_ACK_VECTOR_0:
+		case DCCPO_ACK_VECTOR_1:
+			*vec	= value;
+			*veclen = len;
+			return offset + (opt_ptr - options);
+			break;
+		}
+	}
+
+	return -1;
+	
+out_invalid_option:
+	BUG_ON(1); /* should never happen... options were previously parsed ! */
+	return -1;
+}
+
+static void ccid2_hc_tx_kill_rto_timer(struct sock *sk)
+{
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+
+	sk_stop_timer(sk, &hctx->ccid2hctx_rtotimer);
+	ccid2_pr_debug("deleted RTO timer\n");
+}
+
+static inline void ccid2_new_ack(struct sock *sk, 
+			         struct ccid2_seq *seqp,
+				 unsigned int *maxincr)
+{
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+
+	/* slow start */
+	if (hctx->ccid2hctx_cwnd < hctx->ccid2hctx_ssthresh) {
+		hctx->ccid2hctx_acks = 0;
+
+		/* We can increase cwnd at most maxincr [ack_ratio/2] */
+		if (*maxincr) {
+			/* increase every 2 acks */
+			hctx->ccid2hctx_ssacks++;
+			if (hctx->ccid2hctx_ssacks == 2) {
+				ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd + 1);
+				hctx->ccid2hctx_ssacks = 0;
+				*maxincr = *maxincr - 1;
+			}
+		}
+		/* increased cwnd enough for this single ack */
+		else {
+			hctx->ccid2hctx_ssacks = 0;
+		}
+	}
+	else {
+		hctx->ccid2hctx_ssacks = 0;
+		hctx->ccid2hctx_acks++;
+
+		if (hctx->ccid2hctx_acks >= hctx->ccid2hctx_cwnd) {
+			ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd + 1);
+			hctx->ccid2hctx_acks = 0;
+		}
+	}
+
+	/* update RTO */
+	if (hctx->ccid2hctx_srtt == -1 ||
+	    (jiffies - hctx->ccid2hctx_lastrtt) >= hctx->ccid2hctx_srtt) {
+		unsigned long r = jiffies - seqp->ccid2s_sent;
+		int s;
+
+		/* first measurement */
+		if (hctx->ccid2hctx_srtt == -1) {
+			ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n", 
+			       	       r, jiffies, seqp->ccid2s_seq);
+			hctx->ccid2hctx_srtt = r;
+			hctx->ccid2hctx_rttvar = r >> 1;
+		}
+		else {
+			/* RTTVAR */
+			long tmp = hctx->ccid2hctx_srtt - r;
+			if (tmp < 0)
+				tmp *= -1;
+			
+			tmp >>= 2;
+			hctx->ccid2hctx_rttvar *= 3;
+			hctx->ccid2hctx_rttvar >>= 2;
+			hctx->ccid2hctx_rttvar += tmp;
+
+			/* SRTT */
+			hctx->ccid2hctx_srtt *= 7;
+			hctx->ccid2hctx_srtt >>= 3;
+			tmp = r >> 3;
+			hctx->ccid2hctx_srtt += tmp;
+		}
+		s = hctx->ccid2hctx_rttvar << 2;
+		/* clock granularity is 1 when based on jiffies */
+		if (!s)
+			s = 1;
+		hctx->ccid2hctx_rto = hctx->ccid2hctx_srtt + s;
+
+		/* must be at least a second */
+		s = hctx->ccid2hctx_rto / HZ;
+		/* DCCP doesn't require this [but I like it cuz my code sux] */
+#if 1
+		if (s < 1)
+			hctx->ccid2hctx_rto = HZ;
+#endif			
+		/* max 60 seconds */	
+		if (s > 60)
+			hctx->ccid2hctx_rto = HZ * 60;
+
+		hctx->ccid2hctx_lastrtt = jiffies;
+
+		ccid2_pr_debug("srtt: %ld rttvar: %ld rto: %ld (HZ=%d) R=%lu\n",
+		       	       hctx->ccid2hctx_srtt, hctx->ccid2hctx_rttvar,
+		       	       hctx->ccid2hctx_rto, HZ, r);
+		hctx->ccid2hctx_sent = 0;
+	}
+
+	/* we got a new ack, so re-start RTO timer */
+	ccid2_hc_tx_kill_rto_timer(sk);
+	ccid2_start_rto_timer(sk);
+}
+
+static void ccid2_hc_tx_dec_pipe(struct sock *sk)
+{
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+	
+	hctx->ccid2hctx_pipe--;
+	BUG_ON(hctx->ccid2hctx_pipe < 0);
+
+	if (hctx->ccid2hctx_pipe == 0)
+		ccid2_hc_tx_kill_rto_timer(sk);
+}
+
+static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+	u64 ackno, seqno;
+	struct ccid2_seq *seqp;
+	unsigned char *vector;
+	unsigned char veclen;
+	int offset = 0;
+	int done = 0;
+	int loss = 0;
+	unsigned int maxincr = 0;
+
+	ccid2_hc_tx_check_sanity(hctx);
+	/* check reverse path congestion */
+	seqno = DCCP_SKB_CB(skb)->dccpd_seq;
+
+	/* XXX this whole "algorithm" is broken.  Need to fix it to keep track
+	 * of the seqnos of the dupacks so that rpseq and rpdupack are correct
+	 * -sorbo.
+	 */
+	/* need to bootstrap */
+	if (hctx->ccid2hctx_rpdupack == -1) {
+		hctx->ccid2hctx_rpdupack = 0;
+		hctx->ccid2hctx_rpseq = seqno;
+	}
+	else {
+		/* check if packet is consecutive */
+		if ((hctx->ccid2hctx_rpseq + 1) == seqno) {
+			hctx->ccid2hctx_rpseq++;
+		}
+		/* it's a later packet */
+		else if (after48(seqno, hctx->ccid2hctx_rpseq)) {
+			hctx->ccid2hctx_rpdupack++;
+			
+			/* check if we got enough dupacks */
+			if (hctx->ccid2hctx_rpdupack >=
+			    hctx->ccid2hctx_numdupack) {
+
+				hctx->ccid2hctx_rpdupack = -1; /* XXX lame */
+				hctx->ccid2hctx_rpseq = 0;
+
+				ccid2_change_l_ack_ratio(sk, dp->dccps_l_ack_ratio << 1);
+			}
+		}
+	}
+
+	/* check forward path congestion */
+	/* still didn't send out new data packets */
+	if (hctx->ccid2hctx_seqh == hctx->ccid2hctx_seqt)
+		return;
+
+	switch (DCCP_SKB_CB(skb)->dccpd_type) {
+	case DCCP_PKT_ACK:
+	case DCCP_PKT_DATAACK:
+		break;
+	
+	default:
+		return;
+	}
+
+	ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq;
+	seqp = hctx->ccid2hctx_seqh->ccid2s_prev;
+
+	/* If in slow-start, cwnd can increase at most Ack Ratio / 2 packets for
+	 * this single ack.  I round up.
+	 * -sorbo.
+	 */
+	maxincr = dp->dccps_l_ack_ratio >> 1;
+	maxincr++;
+
+	/* go through all ack vectors */
+	while ((offset = ccid2_ackvector(sk, skb, offset, 
+					 &vector, &veclen)) != -1) {
+		/* go through this ack vector */
+		while (veclen--) {
+			const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK;
+			u64 ackno_end_rl;
+
+			dccp_set_seqno(&ackno_end_rl, ackno - rl);
+			ccid2_pr_debug("ackvec start:%llu end:%llu\n", ackno, 
+				       ackno_end_rl);
+			/* if the seqno we are analyzing is larger than the
+			 * current ackno, then move towards the tail of our
+			 * seqnos.
+			 */
+			while (after48(seqp->ccid2s_seq, ackno)) {
+				if (seqp == hctx->ccid2hctx_seqt) {
+					done = 1;
+					break;
+				}
+				seqp = seqp->ccid2s_prev;
+			}
+			if (done)
+				break;
+
+			/* check all seqnos in the range of the vector
+			 * run length 
+			 */
+			while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) {
+				const u8 state = (*vector & 
+						  DCCP_ACKVEC_STATE_MASK) >> 6;
+			
+				/* new packet received or marked */
+				if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED &&
+				    !seqp->ccid2s_acked) {
+				    	if (state == 
+					    DCCP_ACKVEC_STATE_ECN_MARKED) {
+						loss = 1;
+					}
+					else {
+						ccid2_new_ack(sk, seqp,
+							      &maxincr);
+					}
+
+					seqp->ccid2s_acked = 1;
+					ccid2_pr_debug("Got ack for %llu\n",
+					       	       seqp->ccid2s_seq);
+					ccid2_hc_tx_dec_pipe(sk);
+				}
+				if (seqp == hctx->ccid2hctx_seqt) {
+					done = 1;
+					break;
+				}
+				seqp = seqp->ccid2s_next;
+			}
+			if (done)
+				break;
+			       
+
+			dccp_set_seqno(&ackno, ackno_end_rl - 1);
+			vector++;
+		}
+		if (done)
+			break;
+	}
+
+	/* The state about what is acked should be correct now
+	 * Check for NUMDUPACK
+	 */
+	seqp = hctx->ccid2hctx_seqh->ccid2s_prev;
+	done = 0;
+	while (1) {
+		if (seqp->ccid2s_acked) {
+			done++;
+			if (done == hctx->ccid2hctx_numdupack) {
+				break;
+			}	
+		}
+		if (seqp == hctx->ccid2hctx_seqt) {
+			break;
+		}
+		seqp = seqp->ccid2s_prev;
+	}
+
+	/* If there are at least 3 acknowledgements, anything unacknowledged
+	 * below the last sequence number is considered lost
+	 */
+	if (done == hctx->ccid2hctx_numdupack) {
+		struct ccid2_seq *last_acked = seqp;
+
+		/* check for lost packets */
+		while (1) {
+			if (!seqp->ccid2s_acked) {
+				loss = 1;
+				ccid2_hc_tx_dec_pipe(sk);
+			}
+			if (seqp == hctx->ccid2hctx_seqt)
+				break;
+			seqp = seqp->ccid2s_prev;
+		}
+
+		hctx->ccid2hctx_seqt = last_acked;
+	}
+
+	/* trim acked packets in tail */
+	while (hctx->ccid2hctx_seqt != hctx->ccid2hctx_seqh) {
+		if (!hctx->ccid2hctx_seqt->ccid2s_acked)
+			break;
+		
+		hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqt->ccid2s_next;
+	}
+
+	if (loss) {
+		/* XXX do bit shifts guarantee a 0 as the new bit? */
+		ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd >> 1);
+		hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd;
+		if (hctx->ccid2hctx_ssthresh < 2)
+			hctx->ccid2hctx_ssthresh = 2;
+	}
+
+	ccid2_hc_tx_check_sanity(hctx);
+}
+
+static int ccid2_hc_tx_init(struct sock *sk)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+        struct ccid2_hc_tx_sock *hctx;
+	int seqcount = ccid2_seq_len;
+	int i;
+
+        dp->dccps_hc_tx_ccid_private = kzalloc(sizeof(*hctx), gfp_any());
+        if (dp->dccps_hc_tx_ccid_private == NULL)
+                return -ENOMEM;
+
+        hctx = ccid2_hc_tx_sk(sk);
+
+	/* XXX init variables with proper values */
+	hctx->ccid2hctx_cwnd	  = 1;
+	hctx->ccid2hctx_ssthresh  = 10;
+	hctx->ccid2hctx_numdupack = 3;
+
+	/* XXX init ~ to window size... */
+	hctx->ccid2hctx_seqbuf = kmalloc(sizeof(*hctx->ccid2hctx_seqbuf) *
+					 seqcount, gfp_any());
+	if (hctx->ccid2hctx_seqbuf == NULL) {
+		kfree(dp->dccps_hc_tx_ccid_private);
+		dp->dccps_hc_tx_ccid_private = NULL;
+		return -ENOMEM;
+	}
+	for (i = 0; i < (seqcount - 1); i++) {
+		hctx->ccid2hctx_seqbuf[i].ccid2s_next = 
+					&hctx->ccid2hctx_seqbuf[i + 1];
+		hctx->ccid2hctx_seqbuf[i + 1].ccid2s_prev = 
+					&hctx->ccid2hctx_seqbuf[i];
+	}
+	hctx->ccid2hctx_seqbuf[seqcount - 1].ccid2s_next =
+					hctx->ccid2hctx_seqbuf;
+	hctx->ccid2hctx_seqbuf->ccid2s_prev =
+					&hctx->ccid2hctx_seqbuf[seqcount - 1];
+
+	hctx->ccid2hctx_seqh	 = hctx->ccid2hctx_seqbuf;
+	hctx->ccid2hctx_seqt	 = hctx->ccid2hctx_seqh;
+	hctx->ccid2hctx_sent	 = 0;
+	hctx->ccid2hctx_rto	 = 3 * HZ;
+	hctx->ccid2hctx_srtt	 = -1;
+	hctx->ccid2hctx_rttvar	 = -1;
+	hctx->ccid2hctx_lastrtt  = 0;
+	hctx->ccid2hctx_rpdupack = -1;
+
+	hctx->ccid2hctx_rtotimer.function = &ccid2_hc_tx_rto_expire;
+	hctx->ccid2hctx_rtotimer.data	  = (unsigned long)sk;
+	init_timer(&hctx->ccid2hctx_rtotimer);
+
+	ccid2_hc_tx_check_sanity(hctx);
+	return 0;
+}
+
+static void ccid2_hc_tx_exit(struct sock *sk)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+        struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+
+	ccid2_hc_tx_kill_rto_timer(sk);
+
+	kfree(hctx->ccid2hctx_seqbuf);
+
+	kfree(dp->dccps_hc_tx_ccid_private);
+	dp->dccps_hc_tx_ccid_private = NULL;
+}
+
+static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
+{
+	const struct dccp_sock *dp = dccp_sk(sk);
+	struct ccid2_hc_rx_sock *hcrx = ccid2_hc_rx_sk(sk);
+
+	switch (DCCP_SKB_CB(skb)->dccpd_type) {
+	case DCCP_PKT_DATA:
+	case DCCP_PKT_DATAACK:
+		hcrx->ccid2hcrx_data++;
+		if (hcrx->ccid2hcrx_data >= dp->dccps_r_ack_ratio) {
+			dccp_send_ack(sk);
+			hcrx->ccid2hcrx_data = 0;
+		}
+		break;
+	}
+}
+
+static int ccid2_hc_rx_init(struct sock *sk)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+        dp->dccps_hc_rx_ccid_private = kzalloc(sizeof(struct ccid2_hc_rx_sock),
+					       gfp_any());
+        return dp->dccps_hc_rx_ccid_private == NULL ? -ENOMEM : 0;
+}
+
+static void ccid2_hc_rx_exit(struct sock *sk)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+
+	kfree(dp->dccps_hc_rx_ccid_private);
+	dp->dccps_hc_rx_ccid_private = NULL;
+}
+
+static struct ccid ccid2 = {
+	.ccid_id		= 2,
+	.ccid_name		= "ccid2",
+	.ccid_owner		= THIS_MODULE,
+	.ccid_hc_tx_init	= ccid2_hc_tx_init,
+	.ccid_hc_tx_exit	= ccid2_hc_tx_exit,
+	.ccid_hc_tx_send_packet	= ccid2_hc_tx_send_packet,
+	.ccid_hc_tx_packet_sent	= ccid2_hc_tx_packet_sent,
+	.ccid_hc_tx_packet_recv	= ccid2_hc_tx_packet_recv,
+	.ccid_hc_rx_init	= ccid2_hc_rx_init,
+	.ccid_hc_rx_exit	= ccid2_hc_rx_exit,
+	.ccid_hc_rx_packet_recv	= ccid2_hc_rx_packet_recv,
+};
+
+module_param(ccid2_debug, int, 0444);
+MODULE_PARM_DESC(ccid2_debug, "Enable debug messages");
+ 
+static __init int ccid2_module_init(void)
+{
+	return ccid_register(&ccid2);
+}
+module_init(ccid2_module_init);
+
+static __exit void ccid2_module_exit(void)
+{
+	ccid_unregister(&ccid2);
+}
+module_exit(ccid2_module_exit);
+
+MODULE_AUTHOR("Andrea Bittau <a.bittau@cs.ucl.ac.uk>");
+MODULE_DESCRIPTION("DCCP TCP CCID2 CCID");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("net-dccp-ccid-2");
diff -urN oldtree/net/dccp/ccids/ccid2.h newtree/net/dccp/ccids/ccid2.h
--- oldtree/net/dccp/ccids/ccid2.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/net/dccp/ccids/ccid2.h	2006-02-21 15:58:16.308667264 +0000
@@ -0,0 +1,69 @@
+/*
+ *  net/dccp/ccids/ccid2.h
+ *
+ *  Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _DCCP_CCID2_H_
+#define _DCCP_CCID2_H_
+
+struct ccid2_seq {
+	u64			ccid2s_seq;
+	unsigned long		ccid2s_sent;
+	int			ccid2s_acked;
+	struct ccid2_seq	*ccid2s_prev;
+	struct ccid2_seq	*ccid2s_next;
+};
+
+/** struct ccid2_hc_tx_sock - CCID2 TX half connection
+ *
+ * @ccid2hctx_ssacks - ACKs recv in slow start
+ * @ccid2hctx_acks - ACKS recv in AI phase
+ * @ccid2hctx_sent - packets sent in this window
+ * @ccid2hctx_lastrtt -time RTT was last measured
+ * @ccid2hctx_arsent - packets sent [ack ratio]
+ * @ccid2hctx_ackloss - ack was lost in this win
+ * @ccid2hctx_rpseq - last consecutive seqno
+ * @ccid2hctx_rpdupack - dupacks since rpseq
+*/
+struct ccid2_hc_tx_sock {
+	int			ccid2hctx_cwnd;
+	int			ccid2hctx_ssacks;
+	int			ccid2hctx_acks;
+	int			ccid2hctx_ssthresh;
+	int			ccid2hctx_pipe;
+	int			ccid2hctx_numdupack;
+	struct ccid2_seq	*ccid2hctx_seqbuf;
+	struct ccid2_seq	*ccid2hctx_seqh;
+	struct ccid2_seq	*ccid2hctx_seqt;
+	long			ccid2hctx_rto;
+	long			ccid2hctx_srtt;
+	long			ccid2hctx_rttvar;
+	int			ccid2hctx_sent;
+	unsigned long		ccid2hctx_lastrtt;
+	struct timer_list	ccid2hctx_rtotimer;
+	unsigned long		ccid2hctx_arsent;
+	int			ccid2hctx_ackloss;
+	u64			ccid2hctx_rpseq;
+	int			ccid2hctx_rpdupack;
+	int			ccid2hctx_sendwait;
+};
+
+struct ccid2_hc_rx_sock {
+	int	ccid2hcrx_data;
+};
+
+#endif /* _DCCP_CCID2_H_ */
diff -urN oldtree/net/dccp/ccids/ccid3.c newtree/net/dccp/ccids/ccid3.c
--- oldtree/net/dccp/ccids/ccid3.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/dccp/ccids/ccid3.c	2006-02-21 15:58:16.309667112 +0000
@@ -76,15 +76,6 @@
 static struct dccp_rx_hist *ccid3_rx_hist;
 static struct dccp_li_hist *ccid3_li_hist;
 
-static int ccid3_init(struct sock *sk)
-{
-	return 0;
-}
-
-static void ccid3_exit(struct sock *sk)
-{
-}
-
 /* TFRC sender states */
 enum ccid3_hc_tx_states {
        	TFRC_SSTATE_NO_SENT = 1,
@@ -316,8 +307,6 @@
 
 	switch (hctx->ccid3hctx_state) {
 	case TFRC_SSTATE_NO_SENT:
-		hctx->ccid3hctx_no_feedback_timer.function = ccid3_hc_tx_no_feedback_timer;
-		hctx->ccid3hctx_no_feedback_timer.data     = (unsigned long)sk;
 		sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
 			       jiffies + usecs_to_jiffies(TFRC_INITIAL_TIMEOUT));
 		hctx->ccid3hctx_last_win_count	 = 0;
@@ -681,6 +670,9 @@
 	hctx->ccid3hctx_t_rto = USEC_PER_SEC;
 	hctx->ccid3hctx_state = TFRC_SSTATE_NO_SENT;
 	INIT_LIST_HEAD(&hctx->ccid3hctx_hist);
+
+	hctx->ccid3hctx_no_feedback_timer.function = ccid3_hc_tx_no_feedback_timer;
+	hctx->ccid3hctx_no_feedback_timer.data     = (unsigned long)sk;
 	init_timer(&hctx->ccid3hctx_no_feedback_timer);
 
 	return 0;
@@ -1178,8 +1170,6 @@
 	.ccid_id		   = 3,
 	.ccid_name		   = "ccid3",
 	.ccid_owner		   = THIS_MODULE,
-	.ccid_init		   = ccid3_init,
-	.ccid_exit		   = ccid3_exit,
 	.ccid_hc_tx_init	   = ccid3_hc_tx_init,
 	.ccid_hc_tx_exit	   = ccid3_hc_tx_exit,
 	.ccid_hc_tx_send_packet	   = ccid3_hc_tx_send_packet,
diff -urN oldtree/net/dccp/feat.c newtree/net/dccp/feat.c
--- oldtree/net/dccp/feat.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/net/dccp/feat.c	2006-02-21 15:58:16.310666960 +0000
@@ -0,0 +1,554 @@
+/*
+ *  net/dccp/feat.c
+ *
+ *  An implementation of the DCCP protocol
+ *  Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include "dccp.h"
+#include "feat.h"
+
+#define DCCP_FEAT_SP_NOAGREE (-123)
+
+int dccp_feat_change(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len,
+		     gfp_t gfp)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct dccp_opt_pend *opt;
+	
+	dccp_pr_debug("feat change type=%d feat=%d\n", type, feature);
+
+	/* check if that feature is already being negotiated */
+	list_for_each_entry(opt, &dp->dccps_options.dccpo_pending,
+			    dccpop_node) {
+		/* ok we found a negotiation for this option already */
+		if (opt->dccpop_feat == feature && opt->dccpop_type == type) {
+			dccp_pr_debug("Replacing old\n");
+			/* replace */
+			BUG_ON(opt->dccpop_val == NULL);
+			kfree(opt->dccpop_val);
+			opt->dccpop_val	 = val;
+			opt->dccpop_len	 = len;
+			opt->dccpop_conf = 0;
+			return 0;
+		}
+	}
+
+	/* negotiation for a new feature */
+	opt = kmalloc(sizeof(*opt), gfp);
+	if (opt == NULL)
+		return -ENOMEM;
+
+	opt->dccpop_type = type;
+	opt->dccpop_feat = feature;
+	opt->dccpop_len	 = len;
+	opt->dccpop_val	 = val;
+	opt->dccpop_conf = 0;
+	opt->dccpop_sc	 = NULL;
+
+	BUG_ON(opt->dccpop_val == NULL);
+
+	list_add_tail(&opt->dccpop_node, &dp->dccps_options.dccpo_pending);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(dccp_feat_change);
+
+/* XXX taking only u8 vals */
+static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val)
+{
+	/* FIXME implement */
+	dccp_pr_debug("changing [%d] feat %d to %d\n", type, feat, val);
+	return 0;
+}
+
+static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt,
+			       u8 *rpref, u8 rlen)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	u8 *spref, slen, *res = NULL;
+	int i, j, rc, agree = 1;
+
+	BUG_ON(rpref == NULL);
+
+	/* check if we are the black sheep */
+	if (dp->dccps_role == DCCP_ROLE_CLIENT) {
+		spref = rpref;
+		slen  = rlen;
+		rpref = opt->dccpop_val;
+		rlen  = opt->dccpop_len;
+	} else {
+		spref = opt->dccpop_val;
+		slen  = opt->dccpop_len;
+	}
+	/*
+	 * Now we have server preference list in spref and client preference in
+	 * rpref
+	 */
+	BUG_ON(spref == NULL);
+	BUG_ON(rpref == NULL);
+
+	/* FIXME sanity check vals */
+
+	/* Are values in any order?  XXX Lame "algorithm" here */
+	/* XXX assume values are 1 byte */
+	for (i = 0; i < slen; i++) {
+		for (j = 0; j < rlen; j++) {
+			if (spref[i] == rpref[j]) {
+				res = &spref[i];
+				break;
+			}	
+		}
+		if (res)
+			break;
+	}
+
+	/* we didn't agree on anything */
+	if (res == NULL) {
+		/* confirm previous value */
+		switch (opt->dccpop_feat) {
+		case DCCPF_CCID:
+			/* XXX did i get this right? =P */
+			if (opt->dccpop_type == DCCPO_CHANGE_L)
+				res = &dp->dccps_options.dccpo_tx_ccid;
+			else
+				res = &dp->dccps_options.dccpo_rx_ccid;
+			break;
+
+		default:
+			WARN_ON(1); /* XXX implement res */
+			return -EFAULT;
+		}
+		
+		dccp_pr_debug("Don't agree... reconfirming %d\n", *res);
+		agree = 0; /* this is used for mandatory options... */
+	}
+
+	/* need to put result and our preference list */
+	/* XXX assume 1 byte vals */
+	rlen = 1 + opt->dccpop_len;
+	rpref = kmalloc(rlen, GFP_ATOMIC);
+	if (rpref == NULL)
+		return -ENOMEM;
+
+	*rpref = *res;
+	memcpy(&rpref[1], opt->dccpop_val, opt->dccpop_len);
+
+	/* put it in the "confirm queue" */
+	if (opt->dccpop_sc == NULL) {
+		opt->dccpop_sc = kmalloc(sizeof(*opt->dccpop_sc), GFP_ATOMIC);
+		if (opt->dccpop_sc == NULL) {
+			kfree(rpref);
+			return -ENOMEM;
+		}
+	} else {
+		/* recycle the confirm slot */
+		BUG_ON(opt->dccpop_sc->dccpoc_val == NULL);
+		kfree(opt->dccpop_sc->dccpoc_val);
+		dccp_pr_debug("recycling confirm slot\n");
+	}
+	memset(opt->dccpop_sc, 0, sizeof(*opt->dccpop_sc));
+
+	opt->dccpop_sc->dccpoc_val = rpref;
+	opt->dccpop_sc->dccpoc_len = rlen;
+	
+	/* update the option on our side [we are about to send the confirm] */
+	rc = dccp_feat_update(sk, opt->dccpop_type, opt->dccpop_feat, *res);
+	if (rc) {
+		kfree(opt->dccpop_sc->dccpoc_val);
+		kfree(opt->dccpop_sc);
+		opt->dccpop_sc = 0;
+		return rc;
+	}
+	
+	dccp_pr_debug("Will confirm %d\n", *rpref);
+
+	/* say we want to change to X but we just got a confirm X, suppress our
+	 * change
+	 */
+	if (!opt->dccpop_conf) {
+		if (*opt->dccpop_val == *res)
+			opt->dccpop_conf = 1;
+		dccp_pr_debug("won't ask for change of same feature\n");
+	}
+
+	return agree ? 0 : DCCP_FEAT_SP_NOAGREE; /* used for mandatory opts */
+}
+
+static int dccp_feat_sp(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct dccp_opt_pend *opt;
+	int rc = 1;
+	u8 t;
+
+	/*
+	 * We received a CHANGE.  We gotta match it against our own preference
+	 * list.  If we got a CHANGE_R it means it's a change for us, so we need
+	 * to compare our CHANGE_L list.
+	 */
+	if (type == DCCPO_CHANGE_L)
+		t = DCCPO_CHANGE_R;
+	else
+		t = DCCPO_CHANGE_L;
+	
+	/* find our preference list for this feature */
+	list_for_each_entry(opt, &dp->dccps_options.dccpo_pending,
+			    dccpop_node) {
+		if (opt->dccpop_type != t || opt->dccpop_feat != feature)
+			continue;
+		
+		/* find the winner from the two preference lists */
+		rc = dccp_feat_reconcile(sk, opt, val, len);
+		break;
+	}
+
+	/* We didn't deal with the change.  This can happen if we have no
+	 * preference list for the feature.  In fact, it just shouldn't
+	 * happen---if we understand a feature, we should have a preference list
+	 * with at least the default value.
+	 */
+	BUG_ON(rc == 1);
+
+	return rc;
+}
+
+static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
+{
+	struct dccp_opt_pend *opt;
+	struct dccp_sock *dp = dccp_sk(sk);
+	u8 *copy;
+	int rc;
+
+	/* NN features must be change L */
+	if (type == DCCPO_CHANGE_R) {
+		dccp_pr_debug("received CHANGE_R %d for NN feat %d\n",
+			      type, feature);
+		return -EFAULT;
+	}
+
+	/* XXX sanity check opt val */
+
+	/* copy option so we can confirm it */
+	opt = kzalloc(sizeof(*opt), GFP_ATOMIC);
+	if (opt == NULL)
+		return -ENOMEM;
+
+	copy = kmalloc(len, GFP_ATOMIC);
+	if (copy == NULL) {
+		kfree(opt);
+		return -ENOMEM;
+	}
+	memcpy(copy, val, len);
+
+	opt->dccpop_type = DCCPO_CONFIRM_R; /* NN can only confirm R */
+	opt->dccpop_feat = feature;
+	opt->dccpop_val	 = copy;
+	opt->dccpop_len	 = len;
+
+	/* change feature */
+	rc = dccp_feat_update(sk, type, feature, *val);
+	if (rc) {
+		kfree(opt->dccpop_val);
+		kfree(opt);
+		return rc;
+	}
+
+	dccp_pr_debug("Confirming NN feature %d (val=%d)\n", feature, *copy);
+	list_add_tail(&opt->dccpop_node, &dp->dccps_options.dccpo_conf);
+
+	return 0;
+}
+
+static void dccp_feat_empty_confirm(struct sock *sk, u8 type, u8 feature)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	/* XXX check if other confirms for that are queued and recycle slot */
+	struct dccp_opt_pend *opt = kzalloc(sizeof(*opt), GFP_ATOMIC);
+
+	if (opt == NULL) {
+		/* XXX what do we do?  Ignoring should be fine.  It's a change
+		 * after all =P
+		 */
+		return;
+	}
+	
+	opt->dccpop_type = type == DCCPO_CHANGE_L ? DCCPO_CONFIRM_R :
+						    DCCPO_CONFIRM_L;
+	opt->dccpop_feat = feature;
+	opt->dccpop_val	 = 0;
+	opt->dccpop_len	 = 0;
+
+	/* change feature */
+	dccp_pr_debug("Empty confirm feature %d type %d\n", feature, type);
+	list_add_tail(&opt->dccpop_node, &dp->dccps_options.dccpo_conf);
+}
+
+static void dccp_feat_flush_confirm(struct sock *sk)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	/* Check if there is anything to confirm in the first place */
+	int yes = !list_empty(&dp->dccps_options.dccpo_conf);
+
+	if (!yes) {
+		struct dccp_opt_pend *opt;
+
+		list_for_each_entry(opt, &dp->dccps_options.dccpo_pending,
+				    dccpop_node) {
+			if (opt->dccpop_conf) {
+				yes = 1;
+				break;
+			}
+		}
+	}
+
+	if (!yes)
+		return;
+
+	/* OK there is something to confirm... */
+	/* XXX check if packet is in flight?  Send delayed ack?? */
+	if (sk->sk_state == DCCP_OPEN)
+		dccp_send_ack(sk);
+}
+
+int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
+{
+	int rc;
+
+	dccp_pr_debug("got feat change type=%d feat=%d\n", type, feature);
+
+	/* figure out if it's SP or NN feature */
+	switch (feature) {
+	/* deal with SP features */
+	case DCCPF_CCID:
+		rc = dccp_feat_sp(sk, type, feature, val, len);
+		break;
+
+	/* deal with NN features */
+	case DCCPF_ACK_RATIO:
+		rc = dccp_feat_nn(sk, type, feature, val, len);
+		break;
+
+	/* XXX implement other features */
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	/* check if there were problems changing features */
+	if (rc) {
+		/* If we don't agree on SP, we sent a confirm for old value.
+		 * However we propagate rc to caller in case option was
+		 * mandatory
+		 */
+		if (rc != DCCP_FEAT_SP_NOAGREE)
+			dccp_feat_empty_confirm(sk, type, feature);
+	}
+
+	/* generate the confirm [if required] */
+	dccp_feat_flush_confirm(sk);
+
+	return rc;
+}
+
+EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
+
+int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
+			   u8 *val, u8 len)
+{
+	u8 t;
+	struct dccp_opt_pend *opt;
+	struct dccp_sock *dp = dccp_sk(sk);
+	int rc = 1;
+	int all_confirmed = 1;
+
+	dccp_pr_debug("got feat confirm type=%d feat=%d\n", type, feature);
+
+	/* XXX sanity check type & feat */
+
+	/* locate our change request */
+	t = type == DCCPO_CONFIRM_L ? DCCPO_CHANGE_R : DCCPO_CHANGE_L;
+
+	list_for_each_entry(opt, &dp->dccps_options.dccpo_pending,
+			    dccpop_node) {
+		if (!opt->dccpop_conf && opt->dccpop_type == t &&
+		    opt->dccpop_feat == feature) {
+			/* we found it */
+			/* XXX do sanity check */
+			
+			opt->dccpop_conf = 1;
+
+			/* We got a confirmation---change the option */
+			dccp_feat_update(sk, opt->dccpop_type,
+					 opt->dccpop_feat, *val);
+
+			dccp_pr_debug("feat %d type %d confirmed %d\n",
+				      feature, type, *val);
+			rc = 0;
+			break;
+		}
+
+		if (!opt->dccpop_conf)
+			all_confirmed = 0;
+	}
+
+	/* fix re-transmit timer */
+	/* XXX gotta make sure that no option negotiation occurs during
+	 * connection shutdown.  Consider that the CLOSEREQ is sent and timer is
+	 * on.  if all options are confirmed it might kill timer which should
+	 * remain alive until close is received.
+	 */
+	if (all_confirmed) {
+		dccp_pr_debug("clear feat negotiation timer %p\n", sk);
+		inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
+	}
+
+	if (rc)
+		dccp_pr_debug("feat %d type %d never requested\n",
+			      feature, type);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv);
+
+void dccp_feat_clean(struct sock *sk)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct dccp_opt_pend *opt, *next;
+
+	list_for_each_entry_safe(opt, next, &dp->dccps_options.dccpo_pending,
+				 dccpop_node) {
+                BUG_ON(opt->dccpop_val == NULL);
+                kfree(opt->dccpop_val);
+		
+		if (opt->dccpop_sc != NULL) {
+			BUG_ON(opt->dccpop_sc->dccpoc_val == NULL);
+			kfree(opt->dccpop_sc->dccpoc_val);
+			kfree(opt->dccpop_sc);
+		}	
+
+                kfree(opt);
+        }
+	INIT_LIST_HEAD(&dp->dccps_options.dccpo_pending);
+
+	list_for_each_entry_safe(opt, next, &dp->dccps_options.dccpo_conf,
+				 dccpop_node) {
+		BUG_ON(opt == NULL);
+		if (opt->dccpop_val != NULL)
+			kfree(opt->dccpop_val);
+		kfree(opt);
+	}
+	INIT_LIST_HEAD(&dp->dccps_options.dccpo_conf);
+}
+
+EXPORT_SYMBOL_GPL(dccp_feat_clean);
+
+/* this is to be called only when a listening sock creates its child.  It is
+ * assumed by the function---the confirm is not duplicated, but rather it is
+ * "passed on".
+ */
+int dccp_feat_clone(struct sock *oldsk, struct sock *newsk)
+{
+	struct dccp_sock *olddp = dccp_sk(oldsk);
+	struct dccp_sock *newdp = dccp_sk(newsk);
+	struct dccp_opt_pend *opt;
+	int rc = 0;
+
+	INIT_LIST_HEAD(&newdp->dccps_options.dccpo_pending);
+	INIT_LIST_HEAD(&newdp->dccps_options.dccpo_conf);
+
+	list_for_each_entry(opt, &olddp->dccps_options.dccpo_pending,
+			    dccpop_node) {
+		struct dccp_opt_pend *newopt;
+		/* copy the value of the option */
+		u8 *val = kmalloc(opt->dccpop_len, GFP_ATOMIC);
+
+		if (val == NULL)
+			goto out_clean;
+		memcpy(val, opt->dccpop_val, opt->dccpop_len);
+
+		newopt = kmalloc(sizeof(*newopt), GFP_ATOMIC);
+		if (newopt == NULL) {
+			kfree(val);
+			goto out_clean;
+		}
+
+		/* insert the option */	
+		memcpy(newopt, opt, sizeof(*newopt));
+		newopt->dccpop_val = val;
+		list_add_tail(&newopt->dccpop_node, 
+			      &newdp->dccps_options.dccpo_pending);
+		
+		/* XXX what happens with backlogs and multiple connections at
+		 * once...
+		 */
+		/* the master socket no longer needs to worry about confirms */
+		opt->dccpop_sc = 0; /* it's not a memleak---new socket has it */
+		
+		/* reset state for a new socket */
+		opt->dccpop_conf = 0;
+	}
+
+	/* XXX not doing anything about the conf queue */
+
+out:
+	return rc;
+
+out_clean:
+	dccp_feat_clean(newsk);
+	rc = -ENOMEM;
+	goto out;
+}
+
+EXPORT_SYMBOL_GPL(dccp_feat_clone);
+
+static int __dccp_feat_init(struct sock *sk, u8 type, u8 feat, u8 *val, u8 len)
+{
+	int rc = -ENOMEM;
+	u8 *copy = kmalloc(len, GFP_KERNEL);
+
+	if (copy != NULL) {
+		memcpy(copy, val, len);
+		rc = dccp_feat_change(sk, type, feat, copy, len, GFP_KERNEL);
+		if (rc)
+			kfree(copy);
+	}
+	return rc;
+}
+
+int dccp_feat_init(struct sock *sk)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	int rc;
+
+	INIT_LIST_HEAD(&dp->dccps_options.dccpo_pending);
+	INIT_LIST_HEAD(&dp->dccps_options.dccpo_conf);
+
+	/* CCID L */
+	rc = __dccp_feat_init(sk, DCCPO_CHANGE_L, DCCPF_CCID,
+			      &dp->dccps_options.dccpo_tx_ccid, 1);
+	if (rc)
+		goto out;
+
+	/* CCID R */
+	rc = __dccp_feat_init(sk, DCCPO_CHANGE_R, DCCPF_CCID,
+			      &dp->dccps_options.dccpo_rx_ccid, 1);
+	if (rc)
+		goto out;
+
+	/* Ack ratio */
+	rc = __dccp_feat_init(sk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO,
+			      &dp->dccps_options.dccpo_ack_ratio, 1);
+out:
+	return rc;
+}
+
+EXPORT_SYMBOL_GPL(dccp_feat_init);
diff -urN oldtree/net/dccp/feat.h newtree/net/dccp/feat.h
--- oldtree/net/dccp/feat.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/net/dccp/feat.h	2006-02-21 15:58:16.310666960 +0000
@@ -0,0 +1,28 @@
+#ifndef _DCCP_FEAT_H
+#define _DCCP_FEAT_H
+/*
+ *  net/dccp/feat.h
+ *
+ *  An implementation of the DCCP protocol
+ *  Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *
+ *	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/types.h>
+
+struct sock;
+
+extern int  dccp_feat_change(struct sock *sk, u8 type, u8 feature, 
+			     u8 *val, u8 len, gfp_t gfp);
+extern int  dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature,
+				  u8 *val, u8 len);
+extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
+				   u8 *val, u8 len);
+extern void dccp_feat_clean(struct sock *sk);
+extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
+extern int  dccp_feat_init(struct sock *sk);
+
+#endif /* _DCCP_FEAT_H */
diff -urN oldtree/net/dccp/input.c newtree/net/dccp/input.c
--- oldtree/net/dccp/input.c	2006-02-19 11:41:06.296385904 +0000
+++ newtree/net/dccp/input.c	2006-02-21 15:58:16.311666808 +0000
@@ -300,6 +300,9 @@
 			goto out_invalid_packet;
 		}
 
+		if (dccp_parse_options(sk, skb))
+			goto out_invalid_packet;
+
                 if (dp->dccps_options.dccpo_send_ack_vector &&
                     dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
                                     DCCP_SKB_CB(skb)->dccpd_seq,
diff -urN oldtree/net/dccp/ipv4.c newtree/net/dccp/ipv4.c
--- oldtree/net/dccp/ipv4.c	2006-02-19 11:41:06.298385600 +0000
+++ newtree/net/dccp/ipv4.c	2006-02-21 15:58:36.998521928 +0000
@@ -28,6 +28,7 @@
 #include "ackvec.h"
 #include "ccid.h"
 #include "dccp.h"
+#include "feat.h"
 
 struct inet_hashinfo __cacheline_aligned dccp_hashinfo = {
 	.lhash_lock	= RW_LOCK_UNLOCKED,
@@ -61,7 +62,7 @@
 	struct dccp_sock *dp = dccp_sk(sk);
 	const struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
 	struct rtable *rt;
-	u32 daddr, nexthop;
+	__be32 daddr, nexthop;
 	int tmp;
 	int err;
 
@@ -535,7 +536,8 @@
 	if (req == NULL)
 		goto drop;
 
-	/* FIXME: process options */
+	if (dccp_parse_options(sk, skb))
+		goto drop;
 
 	dccp_openreq_init(req, &dp, skb);
 
@@ -1041,13 +1043,6 @@
 	dccp_options_init(&dp->dccps_options);
 	do_gettimeofday(&dp->dccps_epoch);
 
-	if (dp->dccps_options.dccpo_send_ack_vector) {
-		dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(DCCP_MAX_ACKVEC_LEN,
-							   GFP_KERNEL);
-		if (dp->dccps_hc_rx_ackvec == NULL)
-			return -ENOMEM;
-	}
-
 	/*
 	 * FIXME: We're hardcoding the CCID, and doing this at this point makes
 	 * the listening (master) sock get CCID control blocks, which is not
@@ -1056,6 +1051,13 @@
 	 * setsockopt(CCIDs-I-want/accept). -acme
 	 */
 	if (likely(!dccp_ctl_socket_init)) {
+		int rc;
+
+		if (dp->dccps_options.dccpo_send_ack_vector) {
+			dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL);
+			if (dp->dccps_hc_rx_ackvec == NULL)
+				return -ENOMEM;
+		}
 		dp->dccps_hc_rx_ccid = ccid_init(dp->dccps_options.dccpo_rx_ccid,
 						 sk);
 		dp->dccps_hc_tx_ccid = ccid_init(dp->dccps_options.dccpo_tx_ccid,
@@ -1071,8 +1073,16 @@
 			dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
 			return -ENOMEM;
 		}
-	} else
+
+		rc = dccp_feat_init(sk);
+		if (rc)
+			return rc;
+	} else {
+		/* control socket doesn't need feat nego */
+		INIT_LIST_HEAD(&dp->dccps_options.dccpo_pending);
+		INIT_LIST_HEAD(&dp->dccps_options.dccpo_conf);
 		dccp_ctl_socket_init = 0;
+	}	
 
 	dccp_init_xmit_timers(sk);
 	icsk->icsk_rto = DCCP_TIMEOUT_INIT;
@@ -1083,6 +1093,7 @@
 	dp->dccps_mss_cache = 536;
 	dp->dccps_role = DCCP_ROLE_UNDEFINED;
 	dp->dccps_service = DCCP_SERVICE_INVALID_VALUE;
+	dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1;
 
 	return 0;
 }
@@ -1119,6 +1130,9 @@
 	ccid_exit(dp->dccps_hc_tx_ccid, sk);
 	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
 
+	/* clean up feature negotiation state */
+	dccp_feat_clean(sk);
+
 	return 0;
 }
 
diff -urN oldtree/net/dccp/minisocks.c newtree/net/dccp/minisocks.c
--- oldtree/net/dccp/minisocks.c	2006-02-19 11:41:06.300385296 +0000
+++ newtree/net/dccp/minisocks.c	2006-02-21 15:58:16.313666504 +0000
@@ -22,6 +22,7 @@
 #include "ackvec.h"
 #include "ccid.h"
 #include "dccp.h"
+#include "feat.h"
 
 struct inet_timewait_death_row dccp_death_row = {
 	.sysctl_max_tw_buckets = NR_FILE * 2,
@@ -114,10 +115,12 @@
 		newicsk->icsk_rto	   = DCCP_TIMEOUT_INIT;
 		do_gettimeofday(&newdp->dccps_epoch);
 
+		if (dccp_feat_clone(sk, newsk))
+			goto out_free;
+
 		if (newdp->dccps_options.dccpo_send_ack_vector) {
 			newdp->dccps_hc_rx_ackvec =
-				dccp_ackvec_alloc(DCCP_MAX_ACKVEC_LEN,
-						  GFP_ATOMIC);
+						dccp_ackvec_alloc(GFP_ATOMIC);
 			/*
 			 * XXX: We're using the same CCIDs set on the parent,
 			 * i.e. sk_clone copied the master sock and left the
diff -urN oldtree/net/dccp/options.c newtree/net/dccp/options.c
--- oldtree/net/dccp/options.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/dccp/options.c	2006-02-21 15:58:16.314666352 +0000
@@ -21,12 +21,14 @@
 #include "ackvec.h"
 #include "ccid.h"
 #include "dccp.h"
+#include "feat.h"
 
 /* stores the default values for new connection. may be changed with sysctl */
 static const struct dccp_options dccpo_default_values = {
 	.dccpo_sequence_window	  = DCCPF_INITIAL_SEQUENCE_WINDOW,
 	.dccpo_rx_ccid		  = DCCPF_INITIAL_CCID,
 	.dccpo_tx_ccid		  = DCCPF_INITIAL_CCID,
+	.dccpo_ack_ratio	  = DCCPF_INITIAL_ACK_RATIO,
 	.dccpo_send_ack_vector	  = DCCPF_INITIAL_SEND_ACK_VECTOR,
 	.dccpo_send_ndp_count	  = DCCPF_INITIAL_SEND_NDP_COUNT,
 };
@@ -69,6 +71,8 @@
 	unsigned char opt, len;
 	unsigned char *value;
 	u32 elapsed_time;
+	int rc;
+	int mandatory = 0;
 
 	memset(opt_recv, 0, sizeof(*opt_recv));
 
@@ -100,6 +104,11 @@
 		switch (opt) {
 		case DCCPO_PADDING:
 			break;
+		case DCCPO_MANDATORY:
+			if (mandatory)
+				goto out_invalid_option;
+			mandatory = 1;
+			break;
 		case DCCPO_NDP_COUNT:
 			if (len > 3)
 				goto out_invalid_option;
@@ -108,6 +117,31 @@
 			dccp_pr_debug("%sNDP count=%d\n", debug_prefix,
 				      opt_recv->dccpor_ndp);
 			break;
+		case DCCPO_CHANGE_L:
+			/* fall through */
+		case DCCPO_CHANGE_R:
+			if (len < 2)
+				goto out_invalid_option;
+			rc = dccp_feat_change_recv(sk, opt, *value, value + 1,
+						   len - 1);
+			/*
+			 * When there is a change error, change_recv is
+			 * responsible for dealing with it.  i.e. reply with an
+			 * empty confirm.
+			 * If the change was mandatory, then we need to die.
+			 */
+			if (rc && mandatory)
+				goto out_invalid_option;
+			break;
+		case DCCPO_CONFIRM_L:
+			/* fall through */
+		case DCCPO_CONFIRM_R:
+			if (len < 2)
+				goto out_invalid_option;
+			if (dccp_feat_confirm_recv(sk, opt, *value,
+						   value + 1, len - 1))
+				goto out_invalid_option;
+			break;
 		case DCCPO_ACK_VECTOR_0:
 		case DCCPO_ACK_VECTOR_1:
 			if (pkt_type == DCCP_PKT_DATA)
@@ -208,6 +242,9 @@
 				sk, opt, len);
 			break;
 	        }
+
+		if (opt != DCCPO_MANDATORY)
+			mandatory = 0;
 	}
 
 	return 0;
@@ -356,7 +393,7 @@
 {
 	struct timeval tv;
 	u32 now;
-	
+
 	dccp_timestamp(sk, &tv);
 	now = timeval_usecs(&tv) / 10;
 	/* yes this will overflow but that is the point as we want a
@@ -402,7 +439,7 @@
 	tstamp_echo = htonl(dp->dccps_timestamp_echo);
 	memcpy(to, &tstamp_echo, 4);
 	to += 4;
-	
+
 	if (elapsed_time_len == 2) {
 		const u16 var16 = htons((u16)elapsed_time);
 		memcpy(to, &var16, 2);
@@ -421,6 +458,93 @@
 	dp->dccps_timestamp_time.tv_usec = 0;
 }
 
+static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
+			        u8 *val, u8 len)
+{
+	u8 *to;
+
+	if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 3 > DCCP_MAX_OPT_LEN) {
+		LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small"
+			       " to insert feature %d option!\n", feat);
+		return -1;
+	}
+
+	DCCP_SKB_CB(skb)->dccpd_opt_len += len + 3;
+
+	to    = skb_push(skb, len + 3);
+	*to++ = type;
+	*to++ = len + 3;
+	*to++ = feat;
+
+	if (len)
+		memcpy(to, val, len);
+	dccp_pr_debug("option %d feat %d len %d\n", type, feat, len);
+
+	return 0;
+}
+
+static void dccp_insert_feat(struct sock *sk, struct sk_buff *skb)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct dccp_opt_pend *opt, *next;
+	int change = 0;
+
+	/* confirm any options [NN opts] */
+	list_for_each_entry_safe(opt, next, &dp->dccps_options.dccpo_conf,
+				 dccpop_node) {
+		dccp_insert_feat_opt(skb, opt->dccpop_type,
+				     opt->dccpop_feat, opt->dccpop_val,
+				     opt->dccpop_len);
+		/* fear empty confirms */
+		if (opt->dccpop_val)
+			kfree(opt->dccpop_val);
+		kfree(opt);
+	}
+	INIT_LIST_HEAD(&dp->dccps_options.dccpo_conf);
+
+	/* see which features we need to send */
+	list_for_each_entry(opt, &dp->dccps_options.dccpo_pending,
+			    dccpop_node) {
+		/* see if we need to send any confirm */
+		if (opt->dccpop_sc) {
+			dccp_insert_feat_opt(skb, opt->dccpop_type + 1,
+					     opt->dccpop_feat,
+					     opt->dccpop_sc->dccpoc_val,
+					     opt->dccpop_sc->dccpoc_len);
+
+			BUG_ON(!opt->dccpop_sc->dccpoc_val);
+			kfree(opt->dccpop_sc->dccpoc_val);
+			kfree(opt->dccpop_sc);
+			opt->dccpop_sc = NULL;
+		}
+
+		/* any option not confirmed, re-send it */
+		if (!opt->dccpop_conf) {
+			dccp_insert_feat_opt(skb, opt->dccpop_type,
+					     opt->dccpop_feat, opt->dccpop_val,
+					     opt->dccpop_len);
+			change++;
+		}
+	}
+
+	/* Retransmit timer.
+	 * If this is the master listening sock, we don't set a timer on it.  It
+	 * should be fine because if the dude doesn't receive our RESPONSE
+	 * [which will contain the CHANGE] he will send another REQUEST which
+	 * will "retrnasmit" the change.
+	 */
+	if (change && dp->dccps_role != DCCP_ROLE_LISTEN) {
+		dccp_pr_debug("reset feat negotiation timer %p\n", sk);
+
+		/* XXX don't reset the timer on re-transmissions.  I.e. reset it
+		 * only when sending new stuff i guess.  Currently the timer
+		 * never backs off because on re-transmission it just resets it!
+		 */
+		inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
+					  inet_csk(sk)->icsk_rto, DCCP_RTO_MAX);
+	}
+}
+
 void dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
@@ -447,6 +571,17 @@
 		dp->dccps_hc_tx_insert_options = 0;
 	}
 
+	/* Feature negotiation */
+	switch(DCCP_SKB_CB(skb)->dccpd_type) {
+		/* Data packets can't do feat negotiation */
+	case DCCP_PKT_DATA:
+	case DCCP_PKT_DATAACK:
+		break;
+	default:
+		dccp_insert_feat(sk, skb);
+		break;
+	}
+
 	/* XXX: insert other options when appropriate */
 
 	if (DCCP_SKB_CB(skb)->dccpd_opt_len != 0) {
diff -urN oldtree/net/dccp/output.c newtree/net/dccp/output.c
--- oldtree/net/dccp/output.c	2006-02-19 11:41:06.301385144 +0000
+++ newtree/net/dccp/output.c	2006-02-21 15:58:16.315666200 +0000
@@ -64,6 +64,10 @@
 		case DCCP_PKT_DATAACK:
 			break;
 
+		case DCCP_PKT_REQUEST:
+			set_ack = 0;
+			/* fall through */
+
 		case DCCP_PKT_SYNC:
 		case DCCP_PKT_SYNCACK:
 			ackno = dcb->dccpd_seq;
diff -urN oldtree/net/dccp/proto.c newtree/net/dccp/proto.c
--- oldtree/net/dccp/proto.c	2006-02-19 11:41:06.302384992 +0000
+++ newtree/net/dccp/proto.c	2006-02-21 15:58:16.316666048 +0000
@@ -37,6 +37,7 @@
 
 #include "ccid.h"
 #include "dccp.h"
+#include "feat.h"
 
 DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly;
 
@@ -255,6 +256,39 @@
 	return 0;
 }
 
+/* byte 1 is feature.  the rest is the preference list */
+static int dccp_setsockopt_change(struct sock *sk, int type,
+				  struct dccp_so_feat __user *optval)
+{
+	struct dccp_so_feat opt;
+	u8 *val;
+	int rc;
+
+	if (copy_from_user(&opt, optval, sizeof(opt)))
+		return -EFAULT;
+
+	val = kmalloc(opt.dccpsf_len, GFP_KERNEL);
+	if (!val)
+		return -ENOMEM;
+	
+	if (copy_from_user(val, opt.dccpsf_val, opt.dccpsf_len)) {
+		rc = -EFAULT;
+		goto out_free_val;
+	}
+
+	rc = dccp_feat_change(sk, type, opt.dccpsf_feat, val, opt.dccpsf_len,
+			      GFP_KERNEL);
+	if (rc)
+		goto out_free_val;
+
+out:
+	return rc;
+
+out_free_val:
+	kfree(val);
+	goto out;
+}
+
 int dccp_setsockopt(struct sock *sk, int level, int optname,
 		    char __user *optval, int optlen)
 {
@@ -284,6 +318,25 @@
 	case DCCP_SOCKOPT_PACKET_SIZE:
 		dp->dccps_packet_size = val;
 		break;
+
+	case DCCP_SOCKOPT_CHANGE_L:
+		if (optlen != sizeof(struct dccp_so_feat))
+			err = -EINVAL;
+		else
+			err = dccp_setsockopt_change(sk, DCCPO_CHANGE_L,
+					             (struct dccp_so_feat *)
+						     optval);
+		break;
+
+	case DCCP_SOCKOPT_CHANGE_R:
+		if (optlen != sizeof(struct dccp_so_feat))
+			err = -EINVAL;
+		else
+			err = dccp_setsockopt_change(sk, DCCPO_CHANGE_R,
+						     (struct dccp_so_feat *)
+						     optval);
+		break;
+
 	default:
 		err = -ENOPROTOOPT;
 		break;
@@ -799,6 +852,7 @@
 	if (rc)
 		goto out;
 
+	rc = -ENOBUFS;
 	dccp_hashinfo.bind_bucket_cachep =
 		kmem_cache_create("dccp_bind_bucket",
 				  sizeof(struct inet_bind_bucket), 0,
@@ -866,7 +920,8 @@
 		INIT_HLIST_HEAD(&dccp_hashinfo.bhash[i].chain);
 	}
 
-	if (init_dccp_v4_mibs())
+	rc = init_dccp_v4_mibs();
+	if (rc)
 		goto out_free_dccp_bhash;
 
 	rc = -EAGAIN;
@@ -875,11 +930,17 @@
 
 	inet_register_protosw(&dccp_v4_protosw);
 
-	rc = dccp_ctl_sock_init();
+	rc = dccp_ackvec_init();
 	if (rc)
 		goto out_unregister_protosw;
+
+	rc = dccp_ctl_sock_init();
+	if (rc)
+		goto out_ackvec_exit;
 out:
 	return rc;
+out_ackvec_exit:
+	dccp_ackvec_exit();
 out_unregister_protosw:
 	inet_unregister_protosw(&dccp_v4_protosw);
 	inet_del_protocol(&dccp_protocol, IPPROTO_DCCP);
@@ -921,6 +982,7 @@
 			     sizeof(struct inet_ehash_bucket)));
 	kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
 	proto_unregister(&dccp_prot);
+	dccp_ackvec_exit();
 }
 
 module_init(dccp_init);
diff -urN oldtree/net/dccp/timer.c newtree/net/dccp/timer.c
--- oldtree/net/dccp/timer.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/dccp/timer.c	2006-02-21 15:58:16.325664680 +0000
@@ -141,6 +141,17 @@
 {
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
+	/* retransmit timer is used for feature negotiation throughout
+	 * connection.  In this case, no packet is re-transmitted, but rather an
+	 * ack is generated and pending changes are splaced into its options.
+	 */
+	if (sk->sk_send_head == NULL) {
+		dccp_pr_debug("feat negotiation retransmit timeout %p\n", sk);
+		if (sk->sk_state == DCCP_OPEN)
+			dccp_send_ack(sk);
+		goto backoff;
+	}
+
 	/*
 	 * sk->sk_send_head has to have one skb with
 	 * DCCP_SKB_CB(skb)->dccpd_type set to one of the retransmittable DCCP
@@ -177,6 +188,7 @@
 		goto out;
 	}
 
+backoff:
 	icsk->icsk_backoff++;
 	icsk->icsk_retransmits++;
 
diff -urN oldtree/net/ethernet/eth.c newtree/net/ethernet/eth.c
--- oldtree/net/ethernet/eth.c	2006-02-19 11:41:06.307384232 +0000
+++ newtree/net/ethernet/eth.c	2006-02-21 15:58:37.001521472 +0000
@@ -212,7 +212,7 @@
 
 int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh)
 {
-	unsigned short type = hh->hh_type;
+	__be16 type = hh->hh_type;
 	struct ethhdr *eth;
 	struct net_device *dev = neigh->dev;
 
diff -urN oldtree/net/ieee80211/ieee80211_crypt.c newtree/net/ieee80211/ieee80211_crypt.c
--- oldtree/net/ieee80211/ieee80211_crypt.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/ieee80211/ieee80211_crypt.c	2006-02-21 15:58:15.736754208 +0000
@@ -18,7 +18,6 @@
 #include <linux/string.h>
 #include <net/ieee80211.h>
 
-
 MODULE_AUTHOR("Jouni Malinen");
 MODULE_DESCRIPTION("HostAP crypto");
 MODULE_LICENSE("GPL");
@@ -33,11 +32,11 @@
 
 void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force)
 {
- 	struct ieee80211_crypt_data *entry, *next;
+	struct ieee80211_crypt_data *entry, *next;
 	unsigned long flags;
 
 	spin_lock_irqsave(&ieee->lock, flags);
- 	list_for_each_entry_safe(entry, next, &ieee->crypt_deinit_list, list) {
+	list_for_each_entry_safe(entry, next, &ieee->crypt_deinit_list, list) {
 		if (atomic_read(&entry->refcnt) != 0 && !force)
 			continue;
 
@@ -141,9 +140,9 @@
 	spin_unlock_irqrestore(&ieee80211_crypto_lock, flags);
 	return -EINVAL;
 
- found:
+      found:
 	printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm "
-			  "'%s'\n", ops->name);
+	       "'%s'\n", ops->name);
 	list_del(&alg->list);
 	spin_unlock_irqrestore(&ieee80211_crypto_lock, flags);
 	kfree(alg);
@@ -163,7 +162,7 @@
 	spin_unlock_irqrestore(&ieee80211_crypto_lock, flags);
 	return NULL;
 
- found:
+      found:
 	spin_unlock_irqrestore(&ieee80211_crypto_lock, flags);
 	return alg->ops;
 }
diff -urN oldtree/net/ieee80211/ieee80211_crypt_ccmp.c newtree/net/ieee80211/ieee80211_crypt_ccmp.c
--- oldtree/net/ieee80211/ieee80211_crypt_ccmp.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/ieee80211/ieee80211_crypt_ccmp.c	2006-02-21 15:58:15.737754056 +0000
@@ -190,7 +190,8 @@
 	ieee80211_ccmp_aes_encrypt(tfm, b0, s0);
 }
 
-static int ieee80211_ccmp_hdr(struct sk_buff *skb, int hdr_len, void *priv)
+static int ieee80211_ccmp_hdr(struct sk_buff *skb, int hdr_len,
+			      u8 *aeskey, int keylen, void *priv)
 {
 	struct ieee80211_ccmp_data *key = priv;
 	int i;
@@ -199,6 +200,9 @@
 	if (skb_headroom(skb) < CCMP_HDR_LEN || skb->len < hdr_len)
 		return -1;
 
+	if (aeskey != NULL && keylen >= CCMP_TK_LEN)
+		memcpy(aeskey, key->key, CCMP_TK_LEN);
+
 	pos = skb_push(skb, CCMP_HDR_LEN);
 	memmove(pos, pos + CCMP_HDR_LEN, hdr_len);
 	pos += hdr_len;
@@ -238,7 +242,7 @@
 		return -1;
 
 	data_len = skb->len - hdr_len;
-	len = ieee80211_ccmp_hdr(skb, hdr_len, priv);
+	len = ieee80211_ccmp_hdr(skb, hdr_len, NULL, 0, priv);
 	if (len < 0)
 		return -1;
 
diff -urN oldtree/net/ieee80211/ieee80211_crypt_tkip.c newtree/net/ieee80211/ieee80211_crypt_tkip.c
--- oldtree/net/ieee80211/ieee80211_crypt_tkip.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/ieee80211/ieee80211_crypt_tkip.c	2006-02-21 15:58:15.738753904 +0000
@@ -80,10 +80,9 @@
 {
 	struct ieee80211_tkip_data *priv;
 
-	priv = kmalloc(sizeof(*priv), GFP_ATOMIC);
+	priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
 	if (priv == NULL)
 		goto fail;
-	memset(priv, 0, sizeof(*priv));
 
 	priv->key_idx = key_idx;
 
@@ -271,34 +270,33 @@
 #endif
 }
 
-static u8 *ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len, void *priv)
+static int ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
+			      u8 * rc4key, int keylen, void *priv)
 {
 	struct ieee80211_tkip_data *tkey = priv;
 	int len;
-	u8 *rc4key, *pos, *icv;
+	u8 *pos;
 	struct ieee80211_hdr_4addr *hdr;
-	u32 crc;
 
 	hdr = (struct ieee80211_hdr_4addr *)skb->data;
 
 	if (skb_headroom(skb) < 8 || skb->len < hdr_len)
-		return NULL;
+		return -1;
+
+	if (rc4key == NULL || keylen < 16)
+		return -1;
 
 	if (!tkey->tx_phase1_done) {
 		tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
 				   tkey->tx_iv32);
 		tkey->tx_phase1_done = 1;
 	}
-	rc4key = kmalloc(16, GFP_ATOMIC);
-	if (!rc4key)
-		return NULL;
 	tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
 
 	len = skb->len - hdr_len;
 	pos = skb_push(skb, 8);
 	memmove(pos, pos + 8, hdr_len);
 	pos += hdr_len;
-	icv = skb_put(skb, 4);
 
 	*pos++ = *rc4key;
 	*pos++ = *(rc4key + 1);
@@ -309,28 +307,28 @@
 	*pos++ = (tkey->tx_iv32 >> 16) & 0xff;
 	*pos++ = (tkey->tx_iv32 >> 24) & 0xff;
 
-	crc = ~crc32_le(~0, pos, len);
-	icv[0] = crc;
-	icv[1] = crc >> 8;
-	icv[2] = crc >> 16;
-	icv[3] = crc >> 24;
+	tkey->tx_iv16++;
+	if (tkey->tx_iv16 == 0) {
+		tkey->tx_phase1_done = 0;
+		tkey->tx_iv32++;
+	}
 
-	return rc4key;
+	return 8;
 }
 
 static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
 {
 	struct ieee80211_tkip_data *tkey = priv;
 	int len;
-	const u8 *rc4key;
-	u8 *pos;
+	u8 rc4key[16], *pos, *icv;
+	u32 crc;
 	struct scatterlist sg;
 
 	if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
 		if (net_ratelimit()) {
 			struct ieee80211_hdr_4addr *hdr =
 			    (struct ieee80211_hdr_4addr *)skb->data;
-			printk(KERN_DEBUG "TKIP countermeasures: dropped "
+			printk(KERN_DEBUG ": TKIP countermeasures: dropped "
 			       "TX packet to " MAC_FMT "\n",
 			       MAC_ARG(hdr->addr1));
 		}
@@ -343,22 +341,23 @@
 	len = skb->len - hdr_len;
 	pos = skb->data + hdr_len;
 
-	rc4key = ieee80211_tkip_hdr(skb, hdr_len, priv);
-	if (!rc4key)
+	if ((ieee80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0)
 		return -1;
 
+	icv = skb_put(skb, 4);
+
+	crc = ~crc32_le(~0, pos, len);
+	icv[0] = crc;
+	icv[1] = crc >> 8;
+	icv[2] = crc >> 16;
+	icv[3] = crc >> 24;
+
 	crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16);
 	sg.page = virt_to_page(pos);
 	sg.offset = offset_in_page(pos);
 	sg.length = len + 4;
 	crypto_cipher_encrypt(tkey->tfm_arc4, &sg, &sg, len + 4);
 
-	tkey->tx_iv16++;
-	if (tkey->tx_iv16 == 0) {
-		tkey->tx_phase1_done = 0;
-		tkey->tx_iv32++;
-	}
-
 	return 0;
 }
 
@@ -379,7 +378,7 @@
 
 	if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
 		if (net_ratelimit()) {
-			printk(KERN_DEBUG "TKIP countermeasures: dropped "
+			printk(KERN_DEBUG ": TKIP countermeasures: dropped "
 			       "received packet from " MAC_FMT "\n",
 			       MAC_ARG(hdr->addr2));
 		}
@@ -695,6 +694,7 @@
 	.name = "TKIP",
 	.init = ieee80211_tkip_init,
 	.deinit = ieee80211_tkip_deinit,
+	.build_iv = ieee80211_tkip_hdr,
 	.encrypt_mpdu = ieee80211_tkip_encrypt,
 	.decrypt_mpdu = ieee80211_tkip_decrypt,
 	.encrypt_msdu = ieee80211_michael_mic_add,
diff -urN oldtree/net/ieee80211/ieee80211_crypt_wep.c newtree/net/ieee80211/ieee80211_crypt_wep.c
--- oldtree/net/ieee80211/ieee80211_crypt_wep.c	2006-02-19 11:41:06.307384232 +0000
+++ newtree/net/ieee80211/ieee80211_crypt_wep.c	2006-02-21 15:58:15.738753904 +0000
@@ -76,7 +76,8 @@
 }
 
 /* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */
-static int prism2_wep_build_iv(struct sk_buff *skb, int hdr_len, void *priv)
+static int prism2_wep_build_iv(struct sk_buff *skb, int hdr_len,
+			       u8 *key, int keylen, void *priv)
 {
 	struct prism2_wep_data *wep = priv;
 	u32 klen, len;
@@ -131,7 +132,7 @@
 		return -1;
 	
 	/* add the IV to the frame */
-	if (prism2_wep_build_iv(skb, hdr_len, priv))
+	if (prism2_wep_build_iv(skb, hdr_len, NULL, 0, priv))
 		return -1;
 	
 	/* Copy the IV into the first 3 bytes of the key */
diff -urN oldtree/net/ieee80211/ieee80211_geo.c newtree/net/ieee80211/ieee80211_geo.c
--- oldtree/net/ieee80211/ieee80211_geo.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/ieee80211/ieee80211_geo.c	2006-02-21 15:58:15.739753752 +0000
@@ -58,13 +58,15 @@
 			 * this is a B only channel, we don't see it
 			 * as valid. */
 			if ((ieee->geo.bg[i].channel == channel) &&
+			    !(ieee->geo.bg[i].flags & IEEE80211_CH_INVALID) &&
 			    (!(ieee->mode & IEEE_G) ||
 			     !(ieee->geo.bg[i].flags & IEEE80211_CH_B_ONLY)))
 				return IEEE80211_24GHZ_BAND;
 
 	if (ieee->freq_band & IEEE80211_52GHZ_BAND)
 		for (i = 0; i < ieee->geo.a_channels; i++)
-			if (ieee->geo.a[i].channel == channel)
+			if ((ieee->geo.a[i].channel == channel) &&
+			    !(ieee->geo.a[i].flags & IEEE80211_CH_INVALID))
 				return IEEE80211_52GHZ_BAND;
 
 	return 0;
@@ -133,6 +135,41 @@
 	return &ieee->geo;
 }
 
+u8 ieee80211_get_channel_flags(struct ieee80211_device * ieee, u8 channel)
+{
+	int index = ieee80211_channel_to_index(ieee, channel);
+
+	if (index == -1)
+		return IEEE80211_CH_INVALID;
+
+	if (channel <= IEEE80211_24GHZ_CHANNELS)
+		return ieee->geo.bg[index].flags;
+
+	return ieee->geo.a[index].flags;
+}
+
+static const struct ieee80211_channel bad_channel = {
+	.channel = 0,
+	.flags = IEEE80211_CH_INVALID,
+	.max_power = 0,
+};
+
+const struct ieee80211_channel *ieee80211_get_channel(struct ieee80211_device
+						      *ieee, u8 channel)
+{
+	int index = ieee80211_channel_to_index(ieee, channel);
+
+	if (index == -1)
+		return &bad_channel;
+
+	if (channel <= IEEE80211_24GHZ_CHANNELS)
+		return &ieee->geo.bg[index];
+
+	return &ieee->geo.a[index];
+}
+
+EXPORT_SYMBOL(ieee80211_get_channel);
+EXPORT_SYMBOL(ieee80211_get_channel_flags);
 EXPORT_SYMBOL(ieee80211_is_valid_channel);
 EXPORT_SYMBOL(ieee80211_freq_to_channel);
 EXPORT_SYMBOL(ieee80211_channel_to_index);
diff -urN oldtree/net/ieee80211/ieee80211_module.c newtree/net/ieee80211/ieee80211_module.c
--- oldtree/net/ieee80211/ieee80211_module.c	2006-02-19 11:41:06.308384080 +0000
+++ newtree/net/ieee80211/ieee80211_module.c	2006-02-21 15:58:15.739753752 +0000
@@ -82,10 +82,28 @@
 	return 0;
 }
 
+void ieee80211_network_reset(struct ieee80211_network *network)
+{
+	if (!network)
+		return;
+
+	if (network->ibss_dfs) {
+		kfree(network->ibss_dfs);
+		network->ibss_dfs = NULL;
+	}
+}
+
 static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
 {
+	int i;
+
 	if (!ieee->networks)
 		return;
+
+	for (i = 0; i < MAX_NETWORK_COUNT; i++)
+		if (ieee->networks[i].ibss_dfs)
+			kfree(ieee->networks[i].ibss_dfs);
+
 	kfree(ieee->networks);
 	ieee->networks = NULL;
 }
diff -urN oldtree/net/ieee80211/ieee80211_rx.c newtree/net/ieee80211/ieee80211_rx.c
--- oldtree/net/ieee80211/ieee80211_rx.c	2006-02-19 11:41:06.309383928 +0000
+++ newtree/net/ieee80211/ieee80211_rx.c	2006-02-21 15:58:15.741753448 +0000
@@ -369,8 +369,8 @@
 
 	/* Put this code here so that we avoid duplicating it in all
 	 * Rx paths. - Jean II */
+#ifdef CONFIG_WIRELESS_EXT
 #ifdef IW_WIRELESS_SPY		/* defined in iw_handler.h */
-#ifdef CONFIG_NET_RADIO
 	/* If spy monitoring on */
 	if (ieee->spy_data.spy_number > 0) {
 		struct iw_quality wstats;
@@ -397,8 +397,8 @@
 		/* Update spy records */
 		wireless_spy_update(ieee->dev, hdr->addr2, &wstats);
 	}
-#endif				/* CONFIG_NET_RADIO */
 #endif				/* IW_WIRELESS_SPY */
+#endif				/* CONFIG_WIRELESS_EXT */
 
 #ifdef NOT_YET
 	hostap_update_rx_stats(local->ap, hdr, rx_stats);
@@ -574,7 +574,7 @@
 	/* skb: hdr + (possibly fragmented) plaintext payload */
 	// PR: FIXME: hostap has additional conditions in the "if" below:
 	// ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
-	if ((frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) {
+	if ((frag != 0) || (fc & IEEE80211_FCTL_MOREFRAGS)) {
 		int flen;
 		struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr);
 		IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag);
@@ -754,7 +754,14 @@
 		memset(skb->cb, 0, sizeof(skb->cb));
 		skb->dev = dev;
 		skb->ip_summed = CHECKSUM_NONE;	/* 802.11 crc not sufficient */
-		netif_rx(skb);
+		if (netif_rx(skb) == NET_RX_DROP) {
+			/* netif_rx always succeeds, but it might drop
+			 * the packet.  If it drops the packet, we log that
+			 * in our stats. */
+			IEEE80211_DEBUG_DROP
+			    ("RX: netif_rx dropped the packet\n");
+			stats->rx_dropped++;
+		}
 	}
 
       rx_exit:
@@ -930,6 +937,45 @@
 	return rc;
 }
 
+#ifdef CONFIG_IEEE80211_DEBUG
+#define MFIE_STRING(x) case MFIE_TYPE_ ##x: return #x
+
+static const char *get_info_element_string(u16 id)
+{
+	switch (id) {
+		MFIE_STRING(SSID);
+		MFIE_STRING(RATES);
+		MFIE_STRING(FH_SET);
+		MFIE_STRING(DS_SET);
+		MFIE_STRING(CF_SET);
+		MFIE_STRING(TIM);
+		MFIE_STRING(IBSS_SET);
+		MFIE_STRING(COUNTRY);
+		MFIE_STRING(HOP_PARAMS);
+		MFIE_STRING(HOP_TABLE);
+		MFIE_STRING(REQUEST);
+		MFIE_STRING(CHALLENGE);
+		MFIE_STRING(POWER_CONSTRAINT);
+		MFIE_STRING(POWER_CAPABILITY);
+		MFIE_STRING(TPC_REQUEST);
+		MFIE_STRING(TPC_REPORT);
+		MFIE_STRING(SUPP_CHANNELS);
+		MFIE_STRING(CSA);
+		MFIE_STRING(MEASURE_REQUEST);
+		MFIE_STRING(MEASURE_REPORT);
+		MFIE_STRING(QUIET);
+		MFIE_STRING(IBSS_DFS);
+		MFIE_STRING(ERP_INFO);
+		MFIE_STRING(RSN);
+		MFIE_STRING(RATES_EX);
+		MFIE_STRING(GENERIC);
+		MFIE_STRING(QOS_PARAMETER);
+	default:
+		return "UNKNOWN";
+	}
+}
+#endif
+
 static int ieee80211_parse_info_param(struct ieee80211_info_element
 				      *info_element, u16 length,
 				      struct ieee80211_network *network)
@@ -1040,7 +1086,9 @@
 			break;
 
 		case MFIE_TYPE_TIM:
-			IEEE80211_DEBUG_MGMT("MFIE_TYPE_TIM: ignored\n");
+			network->tim.tim_count = info_element->data[0];
+			network->tim.tim_period = info_element->data[1];
+			IEEE80211_DEBUG_MGMT("MFIE_TYPE_TIM: partially ignored\n");
 			break;
 
 		case MFIE_TYPE_ERP_INFO:
@@ -1091,10 +1139,49 @@
 			printk(KERN_ERR
 			       "QoS Error need to parse QOS_PARAMETER IE\n");
 			break;
+			/* 802.11h */
+		case MFIE_TYPE_POWER_CONSTRAINT:
+			network->power_constraint = info_element->data[0];
+			network->flags |= NETWORK_HAS_POWER_CONSTRAINT;
+			break;
+
+		case MFIE_TYPE_CSA:
+			network->power_constraint = info_element->data[0];
+			network->flags |= NETWORK_HAS_CSA;
+			break;
+
+		case MFIE_TYPE_QUIET:
+			network->quiet.count = info_element->data[0];
+			network->quiet.period = info_element->data[1];
+			network->quiet.duration = info_element->data[2];
+			network->quiet.offset = info_element->data[3];
+			network->flags |= NETWORK_HAS_QUIET;
+			break;
+
+		case MFIE_TYPE_IBSS_DFS:
+			if (network->ibss_dfs)
+				break;
+			network->ibss_dfs =
+			    kmalloc(info_element->len, GFP_ATOMIC);
+			if (!network->ibss_dfs)
+				return 1;
+			memcpy(network->ibss_dfs, info_element->data,
+			       info_element->len);
+			network->flags |= NETWORK_HAS_IBSS_DFS;
+			break;
+
+		case MFIE_TYPE_TPC_REPORT:
+			network->tpc_report.transmit_power =
+			    info_element->data[0];
+			network->tpc_report.link_margin = info_element->data[1];
+			network->flags |= NETWORK_HAS_TPC_REPORT;
+			break;
 
 		default:
-			IEEE80211_DEBUG_MGMT("unsupported IE %d\n",
-					     info_element->id);
+			IEEE80211_DEBUG_MGMT
+			    ("Unsupported info element: %s (%d)\n",
+			     get_info_element_string(info_element->id),
+			     info_element->id);
 			break;
 		}
 
@@ -1110,7 +1197,9 @@
 static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct ieee80211_assoc_response
 				       *frame, struct ieee80211_rx_stats *stats)
 {
-	struct ieee80211_network network_resp;
+	struct ieee80211_network network_resp = {
+		.ibss_dfs = NULL,
+	};
 	struct ieee80211_network *network = &network_resp;
 	struct net_device *dev = ieee->dev;
 
@@ -1253,6 +1342,9 @@
 	int qos_active;
 	u8 old_param;
 
+	ieee80211_network_reset(dst);
+	dst->ibss_dfs = src->ibss_dfs;
+
 	memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats));
 	dst->capability = src->capability;
 	memcpy(dst->rates, src->rates, src->rates_len);
@@ -1269,6 +1361,7 @@
 	dst->listen_interval = src->listen_interval;
 	dst->atim_window = src->atim_window;
 	dst->erp_value = src->erp_value;
+	dst->tim = src->tim;
 
 	memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len);
 	dst->wpa_ie_len = src->wpa_ie_len;
@@ -1313,7 +1406,9 @@
 						    *stats)
 {
 	struct net_device *dev = ieee->dev;
-	struct ieee80211_network network;
+	struct ieee80211_network network = {
+		.ibss_dfs = NULL,
+	};
 	struct ieee80211_network *target;
 	struct ieee80211_network *oldest = NULL;
 #ifdef CONFIG_IEEE80211_DEBUG
@@ -1388,6 +1483,7 @@
 					     escape_essid(target->ssid,
 							  target->ssid_len),
 					     MAC_ARG(target->bssid));
+			ieee80211_network_reset(target);
 		} else {
 			/* Otherwise just pull from the free list */
 			target = list_entry(ieee->network_free_list.next,
@@ -1406,6 +1502,7 @@
 				     "BEACON" : "PROBE RESPONSE");
 #endif
 		memcpy(target, &network, sizeof(*target));
+		network.ibss_dfs = NULL;
 		list_add_tail(&target->list, &ieee->network_list);
 	} else {
 		IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n",
@@ -1417,6 +1514,7 @@
 						frame_ctl)) ?
 				     "BEACON" : "PROBE RESPONSE");
 		update_network(target, &network);
+		network.ibss_dfs = NULL;
 	}
 
 	spin_unlock_irqrestore(&ieee->lock, flags);
@@ -1501,10 +1599,43 @@
 					      header);
 		break;
 
+	case IEEE80211_STYPE_ACTION:
+		IEEE80211_DEBUG_MGMT("ACTION\n");
+		if (ieee->handle_action)
+			ieee->handle_action(ieee->dev,
+					    (struct ieee80211_action *)
+					    header, stats);
+		break;
+
+	case IEEE80211_STYPE_REASSOC_REQ:
+		IEEE80211_DEBUG_MGMT("received reassoc (%d)\n",
+				     WLAN_FC_GET_STYPE(le16_to_cpu
+						       (header->frame_ctl)));
+
+		IEEE80211_WARNING("%s: IEEE80211_REASSOC_REQ received\n",
+				  ieee->dev->name);
+		if (ieee->handle_reassoc_request != NULL)
+			ieee->handle_reassoc_request(ieee->dev,
+						    (struct ieee80211_reassoc_request *)
+						     header);
+		break;
+
+	case IEEE80211_STYPE_ASSOC_REQ:
+		IEEE80211_DEBUG_MGMT("received assoc (%d)\n",
+				     WLAN_FC_GET_STYPE(le16_to_cpu
+						       (header->frame_ctl)));
+
+		IEEE80211_WARNING("%s: IEEE80211_ASSOC_REQ received\n",
+				  ieee->dev->name);
+		if (ieee->handle_assoc_request != NULL)
+			ieee->handle_assoc_request(ieee->dev);
+		break;
+
 	case IEEE80211_STYPE_DEAUTH:
-		printk("DEAUTH from AP\n");
+		IEEE80211_DEBUG_MGMT("DEAUTH\n");
 		if (ieee->handle_deauth != NULL)
-			ieee->handle_deauth(ieee->dev, (struct ieee80211_auth *)
+			ieee->handle_deauth(ieee->dev,
+					    (struct ieee80211_deauth *)
 					    header);
 		break;
 	default:
diff -urN oldtree/net/ieee80211/ieee80211_tx.c newtree/net/ieee80211/ieee80211_tx.c
--- oldtree/net/ieee80211/ieee80211_tx.c	2006-02-19 11:41:06.310383776 +0000
+++ newtree/net/ieee80211/ieee80211_tx.c	2006-02-21 15:58:15.742753296 +0000
@@ -56,7 +56,18 @@
       `--------------------------------------------------|         |------'
 Total: 28 non-data bytes                                 `----.----'
                                                               |
-       .- 'Frame data' expands to <---------------------------'
+       .- 'Frame data' expands, if WEP enabled, to <----------'
+       |
+       V
+      ,-----------------------.
+Bytes |  4  |   0-2296  |  4  |
+      |-----|-----------|-----|
+Desc. | IV  | Encrypted | ICV |
+      |     | Packet    |     |
+      `-----|           |-----'
+            `-----.-----'
+                  |
+       .- 'Encrypted Packet' expands to
        |
        V
       ,---------------------------------------------------.
@@ -65,18 +76,7 @@
 Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP      |
       | DSAP | SSAP |         |          |      | Packet  |
       | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8|      |         |
-      `-----------------------------------------|         |
-Total: 8 non-data bytes                         `----.----'
-                                                     |
-       .- 'IP Packet' expands, if WEP enabled, to <--'
-       |
-       V
-      ,-----------------------.
-Bytes |  4  |   0-2296  |  4  |
-      |-----|-----------|-----|
-Desc. | IV  | Encrypted | ICV |
-      |     | IP Packet |     |
-      `-----------------------'
+      `----------------------------------------------------
 Total: 8 non-data bytes
 
 802.3 Ethernet Data Frame
@@ -470,7 +470,9 @@
 			atomic_inc(&crypt->refcnt);
 			if (crypt->ops->build_iv)
 				crypt->ops->build_iv(skb_frag, hdr_len,
-						     crypt->priv);
+				      ieee->sec.keys[ieee->sec.active_key],
+				      ieee->sec.key_sizes[ieee->sec.active_key],
+				      crypt->priv);
 			atomic_dec(&crypt->refcnt);
 		}
 
diff -urN oldtree/net/ieee80211/ieee80211_wx.c newtree/net/ieee80211/ieee80211_wx.c
--- oldtree/net/ieee80211/ieee80211_wx.c	2006-02-19 11:41:06.311383624 +0000
+++ newtree/net/ieee80211/ieee80211_wx.c	2006-02-21 15:58:15.742753296 +0000
@@ -149,9 +149,7 @@
 		iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID |
 		    IW_QUAL_LEVEL_INVALID;
 		iwe.u.qual.qual = 0;
-		iwe.u.qual.level = 0;
 	} else {
-		iwe.u.qual.level = network->stats.rssi;
 		if (ieee->perfect_rssi == ieee->worst_rssi)
 			iwe.u.qual.qual = 100;
 		else
@@ -179,6 +177,13 @@
 		iwe.u.qual.noise = network->stats.noise;
 	}
 
+	if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) {
+		iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
+		iwe.u.qual.level = 0;
+	} else {
+		iwe.u.qual.level = network->stats.signal;
+	}
+
 	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
 
 	iwe.cmd = IWEVCUSTOM;
@@ -229,6 +234,28 @@
 	if (iwe.u.data.length)
 		start = iwe_stream_add_point(start, stop, &iwe, custom);
 
+	/* Add spectrum management information */
+	iwe.cmd = -1;
+	p = custom;
+	p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: ");
+
+	if (ieee80211_get_channel_flags(ieee, network->channel) &
+	    IEEE80211_CH_INVALID) {
+		iwe.cmd = IWEVCUSTOM;
+		p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID ");
+	}
+
+	if (ieee80211_get_channel_flags(ieee, network->channel) &
+	    IEEE80211_CH_RADAR_DETECT) {
+		iwe.cmd = IWEVCUSTOM;
+		p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS ");
+	}
+
+	if (iwe.cmd == IWEVCUSTOM) {
+		iwe.u.data.length = p - custom;
+		start = iwe_stream_add_point(start, stop, &iwe, custom);
+	}
+
 	return start;
 }
 
@@ -734,9 +761,98 @@
 	return 0;
 }
 
+int ieee80211_wx_set_auth(struct net_device *dev,
+			  struct iw_request_info *info,
+			  union iwreq_data *wrqu,
+			  char *extra)
+{
+	struct ieee80211_device *ieee = netdev_priv(dev);
+	unsigned long flags;
+	int err = 0;
+
+	spin_lock_irqsave(&ieee->lock, flags);
+	
+	switch (wrqu->param.flags & IW_AUTH_INDEX) {
+	case IW_AUTH_WPA_VERSION:
+	case IW_AUTH_CIPHER_PAIRWISE:
+	case IW_AUTH_CIPHER_GROUP:
+	case IW_AUTH_KEY_MGMT:
+		/*
+		 * Host AP driver does not use these parameters and allows
+		 * wpa_supplicant to control them internally.
+		 */
+		break;
+	case IW_AUTH_TKIP_COUNTERMEASURES:
+		break;		/* FIXME */
+	case IW_AUTH_DROP_UNENCRYPTED:
+		ieee->drop_unencrypted = !!wrqu->param.value;
+		break;
+	case IW_AUTH_80211_AUTH_ALG:
+		break;		/* FIXME */
+	case IW_AUTH_WPA_ENABLED:
+		ieee->privacy_invoked = ieee->wpa_enabled = !!wrqu->param.value;
+		break;
+	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+		ieee->ieee802_1x = !!wrqu->param.value;
+		break;
+	case IW_AUTH_PRIVACY_INVOKED:
+		ieee->privacy_invoked = !!wrqu->param.value;
+		break;
+	default:
+		err = -EOPNOTSUPP;
+		break;
+	}
+	spin_unlock_irqrestore(&ieee->lock, flags);
+	return err;
+}
+
+int ieee80211_wx_get_auth(struct net_device *dev,
+			  struct iw_request_info *info,
+			  union iwreq_data *wrqu,
+			  char *extra)
+{
+	struct ieee80211_device *ieee = netdev_priv(dev);
+	unsigned long flags;
+	int err = 0;
+
+	spin_lock_irqsave(&ieee->lock, flags);
+	
+	switch (wrqu->param.flags & IW_AUTH_INDEX) {
+	case IW_AUTH_WPA_VERSION:
+	case IW_AUTH_CIPHER_PAIRWISE:
+	case IW_AUTH_CIPHER_GROUP:
+	case IW_AUTH_KEY_MGMT:
+	case IW_AUTH_TKIP_COUNTERMEASURES:		/* FIXME */
+	case IW_AUTH_80211_AUTH_ALG:			/* FIXME */
+		/*
+		 * Host AP driver does not use these parameters and allows
+		 * wpa_supplicant to control them internally.
+		 */
+		err = -EOPNOTSUPP;
+		break;
+	case IW_AUTH_DROP_UNENCRYPTED:
+		wrqu->param.value = ieee->drop_unencrypted;
+		break;
+	case IW_AUTH_WPA_ENABLED:
+		wrqu->param.value = ieee->wpa_enabled;
+		break;
+	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+		wrqu->param.value = ieee->ieee802_1x;
+		break;
+	default:
+		err = -EOPNOTSUPP;
+		break;
+	}
+	spin_unlock_irqrestore(&ieee->lock, flags);
+	return err;
+}
+
 EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
 EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
 
 EXPORT_SYMBOL(ieee80211_wx_get_scan);
 EXPORT_SYMBOL(ieee80211_wx_set_encode);
 EXPORT_SYMBOL(ieee80211_wx_get_encode);
+
+EXPORT_SYMBOL_GPL(ieee80211_wx_set_auth);
+EXPORT_SYMBOL_GPL(ieee80211_wx_get_auth);
diff -urN oldtree/net/ipv4/af_inet.c newtree/net/ipv4/af_inet.c
--- oldtree/net/ipv4/af_inet.c	2006-02-19 11:41:06.312383472 +0000
+++ newtree/net/ipv4/af_inet.c	2006-02-21 15:58:37.006520712 +0000
@@ -643,7 +643,7 @@
 		sin->sin_port = inet->dport;
 		sin->sin_addr.s_addr = inet->daddr;
 	} else {
-		__u32 addr = inet->rcv_saddr;
+		__be32 addr = inet->rcv_saddr;
 		if (!addr)
 			addr = inet->saddr;
 		sin->sin_port = inet->sport;
@@ -982,9 +982,9 @@
 	struct inet_sock *inet = inet_sk(sk);
 	int err;
 	struct rtable *rt;
-	__u32 old_saddr = inet->saddr;
-	__u32 new_saddr;
-	__u32 daddr = inet->daddr;
+	__be32 old_saddr = inet->saddr;
+	__be32 new_saddr;
+	__be32 daddr = inet->daddr;
 
 	if (inet->opt && inet->opt->srr)
 		daddr = inet->opt->faddr;
@@ -1031,7 +1031,7 @@
 {
 	struct inet_sock *inet = inet_sk(sk);
 	struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0);
-	u32 daddr;
+	__be32 daddr;
 	int err;
 
 	/* Route is OK, nothing to do. */
diff -urN oldtree/net/ipv4/ah4.c newtree/net/ipv4/ah4.c
--- oldtree/net/ipv4/ah4.c	2006-02-19 11:41:06.313383320 +0000
+++ newtree/net/ipv4/ah4.c	2006-02-21 15:58:37.007520560 +0000
@@ -14,7 +14,7 @@
  * into IP header for icv calculation. Options are already checked
  * for validity, so paranoia is not required. */
 
-static int ip_clear_mutable_options(struct iphdr *iph, u32 *daddr)
+static int ip_clear_mutable_options(struct iphdr *iph, __be32 *daddr)
 {
 	unsigned char * optptr = (unsigned char*)(iph+1);
 	int  l = iph->ihl*4 - sizeof(struct iphdr);
@@ -97,6 +97,7 @@
 	ah->reserved = 0;
 	ah->spi = x->id.spi;
 	ah->seq_no = htonl(++x->replay.oseq);
+	xfrm_aevent_doreplay(x);
 	ahp->icv(ahp, skb, ah->auth_data);
 
 	top_iph->tos = iph->tos;
@@ -155,7 +156,7 @@
 	iph->frag_off = 0;
 	iph->check = 0;
 	if (iph->ihl != 5) {
-		u32 dummy;
+		__be32 dummy;
 		if (ip_clear_mutable_options(iph, &dummy))
 			goto out;
 	}
diff -urN oldtree/net/ipv4/arp.c newtree/net/ipv4/arp.c
--- oldtree/net/ipv4/arp.c	2006-02-19 11:41:06.313383320 +0000
+++ newtree/net/ipv4/arp.c	2006-02-21 15:58:37.008520408 +0000
@@ -204,7 +204,7 @@
 	.gc_thresh3 =	1024,
 };
 
-int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir)
+int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir)
 {
 	switch (dev->type) {
 	case ARPHRD_ETHER:
@@ -235,7 +235,7 @@
 
 static int arp_constructor(struct neighbour *neigh)
 {
-	u32 addr = *(u32*)neigh->primary_key;
+	__be32 addr = *(__be32*)neigh->primary_key;
 	struct net_device *dev = neigh->dev;
 	struct in_device *in_dev;
 	struct neigh_parms *parms;
@@ -331,10 +331,10 @@
 
 static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
 {
-	u32 saddr = 0;
+	__be32 saddr = 0;
 	u8  *dst_ha = NULL;
 	struct net_device *dev = neigh->dev;
-	u32 target = *(u32*)neigh->primary_key;
+	__be32 target = *(__be32*)neigh->primary_key;
 	int probes = atomic_read(&neigh->probes);
 	struct in_device *in_dev = in_dev_get(dev);
 
@@ -386,7 +386,7 @@
 }
 
 static int arp_ignore(struct in_device *in_dev, struct net_device *dev,
-		      u32 sip, u32 tip)
+		      __be32 sip, __be32 tip)
 {
 	int scope;
 
@@ -421,7 +421,7 @@
 	return !inet_confirm_addr(dev, sip, tip, scope);
 }
 
-static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev)
+static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev)
 {
 	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = sip,
 						 .saddr = tip } } };
@@ -450,7 +450,7 @@
  *	is allowed to use this function, it is scheduled to be removed. --ANK
  */
 
-static int arp_set_predefined(int addr_hint, unsigned char * haddr, u32 paddr, struct net_device * dev)
+static int arp_set_predefined(int addr_hint, unsigned char * haddr, __be32 paddr, struct net_device * dev)
 {
 	switch (addr_hint) {
 	case RTN_LOCAL:
@@ -471,7 +471,7 @@
 int arp_find(unsigned char *haddr, struct sk_buff *skb)
 {
 	struct net_device *dev = skb->dev;
-	u32 paddr;
+	__be32 paddr;
 	struct neighbour *n;
 
 	if (!skb->dst) {
@@ -512,7 +512,7 @@
 	if (dev == NULL)
 		return -EINVAL;
 	if (n == NULL) {
-		u32 nexthop = ((struct rtable*)dst)->rt_gateway;
+		__be32 nexthop = ((struct rtable*)dst)->rt_gateway;
 		if (dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT))
 			nexthop = 0;
 		n = __neigh_lookup_errno(
@@ -561,8 +561,8 @@
  *	Create an arp packet. If (dest_hw == NULL), we create a broadcast
  *	message.
  */
-struct sk_buff *arp_create(int type, int ptype, u32 dest_ip,
-			   struct net_device *dev, u32 src_ip,
+struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
+			   struct net_device *dev, __be32 src_ip,
 			   unsigned char *dest_hw, unsigned char *src_hw,
 			   unsigned char *target_hw)
 {
@@ -676,8 +676,8 @@
 /*
  *	Create and send an arp packet.
  */
-void arp_send(int type, int ptype, u32 dest_ip, 
-	      struct net_device *dev, u32 src_ip, 
+void arp_send(int type, int ptype, __be32 dest_ip, 
+	      struct net_device *dev, __be32 src_ip, 
 	      unsigned char *dest_hw, unsigned char *src_hw,
 	      unsigned char *target_hw)
 {
@@ -711,7 +711,7 @@
 	unsigned char *arp_ptr;
 	struct rtable *rt;
 	unsigned char *sha, *tha;
-	u32 sip, tip;
+	__be32 sip, tip;
 	u16 dev_type = dev->type;
 	int addr_type;
 	struct neighbour *n;
@@ -969,13 +969,13 @@
 
 static int arp_req_set(struct arpreq *r, struct net_device * dev)
 {
-	u32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
+	__be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
 	struct neighbour *neigh;
 	int err;
 
 	if (r->arp_flags&ATF_PUBL) {
-		u32 mask = ((struct sockaddr_in *) &r->arp_netmask)->sin_addr.s_addr;
-		if (mask && mask != 0xFFFFFFFF)
+		__be32 mask = ((struct sockaddr_in *) &r->arp_netmask)->sin_addr.s_addr;
+		if (mask && mask != htonl(0xFFFFFFFF))
 			return -EINVAL;
 		if (!dev && (r->arp_flags & ATF_COM)) {
 			dev = dev_getbyhwaddr(r->arp_ha.sa_family, r->arp_ha.sa_data);
@@ -1063,7 +1063,7 @@
 
 static int arp_req_get(struct arpreq *r, struct net_device *dev)
 {
-	u32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
+	__be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
 	struct neighbour *neigh;
 	int err = -ENXIO;
 
@@ -1084,13 +1084,13 @@
 static int arp_req_delete(struct arpreq *r, struct net_device * dev)
 {
 	int err;
-	u32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
+	__be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
 	struct neighbour *neigh;
 
 	if (r->arp_flags & ATF_PUBL) {
-		u32 mask =
+		__be32 mask =
 		       ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr;
-		if (mask == 0xFFFFFFFF)
+		if (mask == htonl(0xFFFFFFFF))
 			return pneigh_delete(&arp_tbl, &ip, dev);
 		if (mask == 0) {
 			if (dev == NULL) {
diff -urN oldtree/net/ipv4/datagram.c newtree/net/ipv4/datagram.c
--- oldtree/net/ipv4/datagram.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/ipv4/datagram.c	2006-02-21 15:58:37.009520256 +0000
@@ -26,7 +26,7 @@
 	struct inet_sock *inet = inet_sk(sk);
 	struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
 	struct rtable *rt;
-	u32 saddr;
+	__be32 saddr;
 	int oif;
 	int err;
 
diff -urN oldtree/net/ipv4/devinet.c newtree/net/ipv4/devinet.c
--- oldtree/net/ipv4/devinet.c	2006-02-19 11:41:06.314383168 +0000
+++ newtree/net/ipv4/devinet.c	2006-02-21 15:58:37.015519344 +0000
@@ -217,7 +217,7 @@
 	call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
 }
 
-int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b)
+int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
 {
 	rcu_read_lock();
 	for_primary_ifa(in_dev) {
@@ -408,8 +408,8 @@
 
 /* Called only from RTNL semaphored context. No locks. */
 
-struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix,
-				    u32 mask)
+struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
+				    __be32 mask)
 {
 	ASSERT_RTNL();
 
@@ -442,7 +442,7 @@
 		     rtattr_strcmp(rta[IFA_LABEL - 1], ifa->ifa_label)) ||
 		    (rta[IFA_ADDRESS - 1] &&
 		     (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
-		      !inet_ifa_match(*(u32*)RTA_DATA(rta[IFA_ADDRESS - 1]),
+		      !inet_ifa_match(*(__be32*)RTA_DATA(rta[IFA_ADDRESS - 1]),
 			      	      ifa))))
 			continue;
 		inet_del_ifa(in_dev, ifap, 1);
@@ -509,20 +509,20 @@
  *	Determine a default network mask, based on the IP address.
  */
 
-static __inline__ int inet_abc_len(u32 addr)
+static __inline__ int inet_abc_len(__be32 addr)
 {
 	int rc = -1;	/* Something else, probably a multicast. */
 
   	if (ZERONET(addr))
   		rc = 0;
 	else {
-		addr = ntohl(addr);
+		__u32 haddr = ntohl(addr);
 
-		if (IN_CLASSA(addr))
+		if (IN_CLASSA(haddr))
 			rc = 8;
-		else if (IN_CLASSB(addr))
+		else if (IN_CLASSB(haddr))
 			rc = 16;
-		else if (IN_CLASSC(addr))
+		else if (IN_CLASSC(haddr))
 			rc = 24;
 	}
 
@@ -737,7 +737,7 @@
 			break;
 		ret = 0;
 		if (ifa->ifa_mask != sin->sin_addr.s_addr) {
-			u32 old_mask = ifa->ifa_mask;
+			__be32 old_mask = ifa->ifa_mask;
 			inet_del_ifa(in_dev, ifap, 0);
 			ifa->ifa_mask = sin->sin_addr.s_addr;
 			ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
@@ -808,9 +808,9 @@
 	return done;
 }
 
-u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
+__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
 {
-	u32 addr = 0;
+	__be32 addr = 0;
 	struct in_device *in_dev;
 
 	rcu_read_lock();
@@ -859,11 +859,11 @@
 	return addr;
 }
 
-static u32 confirm_addr_indev(struct in_device *in_dev, u32 dst,
-			      u32 local, int scope)
+static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
+			      __be32 local, int scope)
 {
 	int same = 0;
-	u32 addr = 0;
+	__be32 addr = 0;
 
 	for_ifa(in_dev) {
 		if (!addr &&
@@ -903,9 +903,9 @@
  * - local: address, 0=autoselect the local address
  * - scope: maximum allowed scope value for the local address
  */
-u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope)
+__be32 inet_confirm_addr(const struct net_device *dev, __be32 dst, __be32 local, int scope)
 {
-	u32 addr = 0;
+	__be32 addr = 0;
 	struct in_device *in_dev;
 
 	if (dev) {
diff -urN oldtree/net/ipv4/esp4.c newtree/net/ipv4/esp4.c
--- oldtree/net/ipv4/esp4.c	2006-02-19 11:41:06.315383016 +0000
+++ newtree/net/ipv4/esp4.c	2006-02-21 15:58:37.015519344 +0000
@@ -71,7 +71,7 @@
 	if (x->encap) {
 		struct xfrm_encap_tmpl *encap = x->encap;
 		struct udphdr *uh;
-		u32 *udpdata32;
+		__be32 *udpdata32;
 
 		uh = (struct udphdr *)esph;
 		uh->source = encap->encap_sport;
@@ -85,7 +85,7 @@
 			esph = (struct ip_esp_hdr *)(uh + 1);
 			break;
 		case UDP_ENCAP_ESPINUDP_NON_IKE:
-			udpdata32 = (u32 *)(uh + 1);
+			udpdata32 = (__be32 *)(uh + 1);
 			udpdata32[0] = udpdata32[1] = 0;
 			esph = (struct ip_esp_hdr *)(udpdata32 + 2);
 			break;
@@ -97,6 +97,7 @@
 
 	esph->spi = x->id.spi;
 	esph->seq_no = htonl(++x->replay.oseq);
+	xfrm_aevent_doreplay(x);
 
 	if (esp->conf.ivlen)
 		crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm));
diff -urN oldtree/net/ipv4/fib_frontend.c newtree/net/ipv4/fib_frontend.c
--- oldtree/net/ipv4/fib_frontend.c	2006-02-19 11:41:06.315383016 +0000
+++ newtree/net/ipv4/fib_frontend.c	2006-02-21 15:58:37.016519192 +0000
@@ -102,7 +102,7 @@
  *	Find the first device with a given source address.
  */
 
-struct net_device * ip_dev_find(u32 addr)
+struct net_device * ip_dev_find(__be32 addr)
 {
 	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
 	struct fib_result res;
@@ -126,7 +126,7 @@
 	return dev;
 }
 
-unsigned inet_addr_type(u32 addr)
+unsigned inet_addr_type(__be32 addr)
 {
 	struct flowi		fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
 	struct fib_result	res;
@@ -160,8 +160,8 @@
    - check, that packet arrived from expected physical interface.
  */
 
-int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
-			struct net_device *dev, u32 *spec_dst, u32 *itag)
+int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
+			struct net_device *dev, __be32 *spec_dst, u32 *itag)
 {
 	struct in_device *in_dev;
 	struct flowi fl = { .nl_u = { .ip4_u =
@@ -367,7 +367,7 @@
    only when netlink is already locked.
  */
 
-static void fib_magic(int cmd, int type, u32 dst, int dst_len, struct in_ifaddr *ifa)
+static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa)
 {
 	struct fib_table * tb;
 	struct {
@@ -414,9 +414,9 @@
 	struct in_device *in_dev = ifa->ifa_dev;
 	struct net_device *dev = in_dev->dev;
 	struct in_ifaddr *prim = ifa;
-	u32 mask = ifa->ifa_mask;
-	u32 addr = ifa->ifa_local;
-	u32 prefix = ifa->ifa_address&mask;
+	__be32 mask = ifa->ifa_mask;
+	__be32 addr = ifa->ifa_local;
+	__be32 prefix = ifa->ifa_address&mask;
 
 	if (ifa->ifa_flags&IFA_F_SECONDARY) {
 		prim = inet_ifa_byprefix(in_dev, prefix, mask);
@@ -432,7 +432,7 @@
 		return;
 
 	/* Add broadcast address, if it is explicitly assigned. */
-	if (ifa->ifa_broadcast && ifa->ifa_broadcast != 0xFFFFFFFF)
+	if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF))
 		fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
 
 	if (!ZERONET(prefix) && !(ifa->ifa_flags&IFA_F_SECONDARY) &&
@@ -454,8 +454,8 @@
 	struct net_device *dev = in_dev->dev;
 	struct in_ifaddr *ifa1;
 	struct in_ifaddr *prim = ifa;
-	u32 brd = ifa->ifa_address|~ifa->ifa_mask;
-	u32 any = ifa->ifa_address&ifa->ifa_mask;
+	__be32 brd = ifa->ifa_address|~ifa->ifa_mask;
+	__be32 any = ifa->ifa_address&ifa->ifa_mask;
 #define LOCAL_OK	1
 #define BRD_OK		2
 #define BRD0_OK		4
diff -urN oldtree/net/ipv4/fib_hash.c newtree/net/ipv4/fib_hash.c
--- oldtree/net/ipv4/fib_hash.c	2006-02-19 11:41:06.316382864 +0000
+++ newtree/net/ipv4/fib_hash.c	2006-02-21 15:58:37.017519040 +0000
@@ -52,7 +52,7 @@
 struct fib_node {
 	struct hlist_node	fn_hash;
 	struct list_head	fn_alias;
-	u32			fn_key;
+	__be32			fn_key;
 };
 
 struct fn_zone {
@@ -65,7 +65,7 @@
 #define FZ_HASHMASK(fz)		((fz)->fz_hashmask)
 
 	int			fz_order;	/* Zone order		*/
-	u32			fz_mask;
+	__be32			fz_mask;
 #define FZ_MASK(fz)		((fz)->fz_mask)
 };
 
@@ -78,7 +78,7 @@
 	struct fn_zone	*fn_zone_list;
 };
 
-static inline u32 fn_hash(u32 key, struct fn_zone *fz)
+static inline u32 fn_hash(__be32 key, struct fn_zone *fz)
 {
 	u32 h = ntohl(key)>>(32 - fz->fz_order);
 	h ^= (h>>20);
@@ -88,7 +88,7 @@
 	return h;
 }
 
-static inline u32 fz_key(u32 dst, struct fn_zone *fz)
+static inline __be32 fz_key(__be32 dst, struct fn_zone *fz)
 {
 	return dst & FZ_MASK(fz);
 }
@@ -256,7 +256,7 @@
 		struct hlist_head *head;
 		struct hlist_node *node;
 		struct fib_node *f;
-		u32 k = fz_key(flp->fl4_dst, fz);
+		__be32 k = fz_key(flp->fl4_dst, fz);
 
 		head = &fz->fz_hash[fn_hash(k, fz)];
 		hlist_for_each_entry(f, node, head, fn_hash) {
@@ -367,7 +367,7 @@
 }
 
 /* Return the node in FZ matching KEY. */
-static struct fib_node *fib_find_node(struct fn_zone *fz, u32 key)
+static struct fib_node *fib_find_node(struct fn_zone *fz, __be32 key)
 {
 	struct hlist_head *head = &fz->fz_hash[fn_hash(key, fz)];
 	struct hlist_node *node;
@@ -393,7 +393,7 @@
 	int z = r->rtm_dst_len;
 	int type = r->rtm_type;
 	u8 tos = r->rtm_tos;
-	u32 key;
+	__be32 key;
 	int err;
 
 	if (z > 32)
@@ -404,7 +404,7 @@
 
 	key = 0;
 	if (rta->rta_dst) {
-		u32 dst;
+		__be32 dst;
 		memcpy(&dst, rta->rta_dst, 4);
 		if (dst & ~FZ_MASK(fz))
 			return -EINVAL;
@@ -548,7 +548,7 @@
 	struct fib_alias *fa, *fa_to_delete;
 	int z = r->rtm_dst_len;
 	struct fn_zone *fz;
-	u32 key;
+	__be32 key;
 	u8 tos = r->rtm_tos;
 
 	if (z > 32)
@@ -558,7 +558,7 @@
 
 	key = 0;
 	if (rta->rta_dst) {
-		u32 dst;
+		__be32 dst;
 		memcpy(&dst, rta->rta_dst, 4);
 		if (dst & ~FZ_MASK(fz))
 			return -EINVAL;
@@ -974,7 +974,7 @@
 	read_unlock(&fib_hash_lock);
 }
 
-static unsigned fib_flag_trans(int type, u32 mask, struct fib_info *fi)
+static unsigned fib_flag_trans(int type, __be32 mask, struct fib_info *fi)
 {
 	static const unsigned type2flags[RTN_MAX + 1] = {
 		[7] = RTF_REJECT, [8] = RTF_REJECT,
@@ -983,7 +983,7 @@
 
 	if (fi && fi->fib_nh->nh_gw)
 		flags |= RTF_GATEWAY;
-	if (mask == 0xFFFFFFFF)
+	if (mask == htonl(0xFFFFFFFF))
 		flags |= RTF_HOST;
 	flags |= RTF_UP;
 	return flags;
@@ -999,7 +999,7 @@
 {
 	struct fib_iter_state *iter;
 	char bf[128];
-	u32 prefix, mask;
+	__be32 prefix, mask;
 	unsigned flags;
 	struct fib_node *f;
 	struct fib_alias *fa;
diff -urN oldtree/net/ipv4/fib_lookup.h newtree/net/ipv4/fib_lookup.h
--- oldtree/net/ipv4/fib_lookup.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/ipv4/fib_lookup.h	2006-02-21 15:58:37.017519040 +0000
@@ -20,7 +20,7 @@
 /* Exported by fib_semantics.c */
 extern int fib_semantic_match(struct list_head *head,
 			      const struct flowi *flp,
-			      struct fib_result *res, __u32 zone, __u32 mask,
+			      struct fib_result *res, __be32 zone, __be32 mask,
 				int prefixlen);
 extern void fib_release_info(struct fib_info *);
 extern struct fib_info *fib_create_info(const struct rtmsg *r,
@@ -33,7 +33,7 @@
 			 u8 tb_id, u8 type, u8 scope, void *dst,
 			 int dst_len, u8 tos, struct fib_info *fi,
 			 unsigned int);
-extern void rtmsg_fib(int event, u32 key, struct fib_alias *fa,
+extern void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
 		      int z, int tb_id,
 		      struct nlmsghdr *n, struct netlink_skb_parms *req);
 extern struct fib_alias *fib_find_alias(struct list_head *fah,
diff -urN oldtree/net/ipv4/fib_rules.c newtree/net/ipv4/fib_rules.c
--- oldtree/net/ipv4/fib_rules.c	2006-02-19 11:41:06.317382712 +0000
+++ newtree/net/ipv4/fib_rules.c	2006-02-21 15:58:37.018518888 +0000
@@ -40,6 +40,8 @@
 #include <linux/skbuff.h>
 #include <linux/netlink.h>
 #include <linux/init.h>
+#include <linux/list.h>
+#include <linux/rcupdate.h>
 
 #include <net/ip.h>
 #include <net/protocol.h>
@@ -52,17 +54,17 @@
 
 struct fib_rule
 {
-	struct fib_rule *r_next;
+	struct hlist_node hlist;
 	atomic_t	r_clntref;
 	u32		r_preference;
 	unsigned char	r_table;
 	unsigned char	r_action;
 	unsigned char	r_dst_len;
 	unsigned char	r_src_len;
-	u32		r_src;
-	u32		r_srcmask;
-	u32		r_dst;
-	u32		r_dstmask;
+	__be32		r_src;
+	__be32		r_srcmask;
+	__be32		r_dst;
+	__be32		r_dstmask;
 	u32		r_srcmap;
 	u8		r_flags;
 	u8		r_tos;
@@ -75,6 +77,7 @@
 #endif
 	char		r_ifname[IFNAMSIZ];
 	int		r_dead;
+	struct		rcu_head rcu;
 };
 
 static struct fib_rule default_rule = {
@@ -85,7 +88,6 @@
 };
 
 static struct fib_rule main_rule = {
-	.r_next =	&default_rule,
 	.r_clntref =	ATOMIC_INIT(2),
 	.r_preference =	0x7FFE,
 	.r_table =	RT_TABLE_MAIN,
@@ -93,23 +95,24 @@
 };
 
 static struct fib_rule local_rule = {
-	.r_next =	&main_rule,
 	.r_clntref =	ATOMIC_INIT(2),
 	.r_table =	RT_TABLE_LOCAL,
 	.r_action =	RTN_UNICAST,
 };
 
-static struct fib_rule *fib_rules = &local_rule;
-static DEFINE_RWLOCK(fib_rules_lock);
+static struct hlist_head fib_rules;
+
+/* writer func called from netlink -- rtnl_sem hold*/
 
 int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 {
 	struct rtattr **rta = arg;
 	struct rtmsg *rtm = NLMSG_DATA(nlh);
-	struct fib_rule *r, **rp;
+	struct fib_rule *r;
+	struct hlist_node *node;
 	int err = -ESRCH;
 
-	for (rp=&fib_rules; (r=*rp) != NULL; rp=&r->r_next) {
+	hlist_for_each_entry(r, node, &fib_rules, hlist) {
 		if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 4) == 0) &&
 		    rtm->rtm_src_len == r->r_src_len &&
 		    rtm->rtm_dst_len == r->r_dst_len &&
@@ -126,10 +129,8 @@
 			if (r == &local_rule)
 				break;
 
-			write_lock_bh(&fib_rules_lock);
-			*rp = r->r_next;
+			hlist_del_rcu(&r->hlist);			
 			r->r_dead = 1;
-			write_unlock_bh(&fib_rules_lock);
 			fib_rule_put(r);
 			err = 0;
 			break;
@@ -150,21 +151,30 @@
 	return NULL;
 }
 
+static inline void fib_rule_put_rcu(struct rcu_head *head)
+{
+	struct fib_rule *r = container_of(head, struct fib_rule, rcu);
+	kfree(r);
+}
+
 void fib_rule_put(struct fib_rule *r)
 {
 	if (atomic_dec_and_test(&r->r_clntref)) {
 		if (r->r_dead)
-			kfree(r);
+			call_rcu(&r->rcu, fib_rule_put_rcu);
 		else
 			printk("Freeing alive rule %p\n", r);
 	}
 }
 
+/* writer func called from netlink -- rtnl_sem hold*/
+
 int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 {
 	struct rtattr **rta = arg;
 	struct rtmsg *rtm = NLMSG_DATA(nlh);
-	struct fib_rule *r, *new_r, **rp;
+	struct fib_rule *r, *new_r, *last = NULL;
+	struct hlist_node *node = NULL;
 	unsigned char table_id;
 
 	if (rtm->rtm_src_len > 32 || rtm->rtm_dst_len > 32 ||
@@ -188,6 +198,7 @@
 	if (!new_r)
 		return -ENOMEM;
 	memset(new_r, 0, sizeof(*new_r));
+
 	if (rta[RTA_SRC-1])
 		memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 4);
 	if (rta[RTA_DST-1])
@@ -220,28 +231,28 @@
 	if (rta[RTA_FLOW-1])
 		memcpy(&new_r->r_tclassid, RTA_DATA(rta[RTA_FLOW-1]), 4);
 #endif
+	r = container_of(fib_rules.first, struct fib_rule, hlist);
 
-	rp = &fib_rules;
 	if (!new_r->r_preference) {
-		r = fib_rules;
-		if (r && (r = r->r_next) != NULL) {
-			rp = &fib_rules->r_next;
+		if (r && r->hlist.next != NULL) {
+			r = container_of(r->hlist.next, struct fib_rule, hlist);
 			if (r->r_preference)
 				new_r->r_preference = r->r_preference - 1;
 		}
 	}
-
-	while ( (r = *rp) != NULL ) {
+	
+	hlist_for_each_entry(r, node, &fib_rules, hlist) {
 		if (r->r_preference > new_r->r_preference)
 			break;
-		rp = &r->r_next;
+		last = r;
 	}
-
-	new_r->r_next = r;
 	atomic_inc(&new_r->r_clntref);
-	write_lock_bh(&fib_rules_lock);
-	*rp = new_r;
-	write_unlock_bh(&fib_rules_lock);
+
+	if (last)
+		hlist_add_after_rcu(&last->hlist, &new_r->hlist);
+	else
+		hlist_add_before_rcu(&new_r->hlist, &r->hlist);
+
 	return 0;
 }
 
@@ -254,30 +265,30 @@
 }
 #endif
 
+/* callers should hold rtnl semaphore */
 
 static void fib_rules_detach(struct net_device *dev)
 {
+	struct hlist_node *node;
 	struct fib_rule *r;
 
-	for (r=fib_rules; r; r=r->r_next) {
-		if (r->r_ifindex == dev->ifindex) {
-			write_lock_bh(&fib_rules_lock);
+	hlist_for_each_entry(r, node, &fib_rules, hlist) {
+		if (r->r_ifindex == dev->ifindex) 
 			r->r_ifindex = -1;
-			write_unlock_bh(&fib_rules_lock);
-		}
+		
 	}
 }
 
+/* callers should hold rtnl semaphore */
+
 static void fib_rules_attach(struct net_device *dev)
 {
+	struct hlist_node *node;
 	struct fib_rule *r;
 
-	for (r=fib_rules; r; r=r->r_next) {
-		if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) {
-			write_lock_bh(&fib_rules_lock);
+	hlist_for_each_entry(r, node, &fib_rules, hlist) {
+		if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) 
 			r->r_ifindex = dev->ifindex;
-			write_unlock_bh(&fib_rules_lock);
-		}
 	}
 }
 
@@ -286,14 +297,17 @@
 	int err;
 	struct fib_rule *r, *policy;
 	struct fib_table *tb;
+	struct hlist_node *node;
 
-	u32 daddr = flp->fl4_dst;
-	u32 saddr = flp->fl4_src;
+	__be32 daddr = flp->fl4_dst;
+	__be32 saddr = flp->fl4_src;
 
 FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u ",
 	NIPQUAD(flp->fl4_dst), NIPQUAD(flp->fl4_src));
-	read_lock(&fib_rules_lock);
-	for (r = fib_rules; r; r=r->r_next) {
+
+	rcu_read_lock();
+
+	hlist_for_each_entry_rcu(r, node, &fib_rules, hlist) {
 		if (((saddr^r->r_src) & r->r_srcmask) ||
 		    ((daddr^r->r_dst) & r->r_dstmask) ||
 		    (r->r_tos && r->r_tos != flp->fl4_tos) ||
@@ -309,14 +323,14 @@
 			policy = r;
 			break;
 		case RTN_UNREACHABLE:
-			read_unlock(&fib_rules_lock);
+			rcu_read_unlock();
 			return -ENETUNREACH;
 		default:
 		case RTN_BLACKHOLE:
-			read_unlock(&fib_rules_lock);
+			rcu_read_unlock();
 			return -EINVAL;
 		case RTN_PROHIBIT:
-			read_unlock(&fib_rules_lock);
+			rcu_read_unlock();
 			return -EACCES;
 		}
 
@@ -327,16 +341,16 @@
 			res->r = policy;
 			if (policy)
 				atomic_inc(&policy->r_clntref);
-			read_unlock(&fib_rules_lock);
+			rcu_read_unlock();
 			return 0;
 		}
 		if (err < 0 && err != -EAGAIN) {
-			read_unlock(&fib_rules_lock);
+			rcu_read_unlock();
 			return err;
 		}
 	}
 FRprintk("FAILURE\n");
-	read_unlock(&fib_rules_lock);
+	rcu_read_unlock();
 	return -ENETUNREACH;
 }
 
@@ -414,20 +428,25 @@
 	return -1;
 }
 
+/* callers should hold rtnl semaphore */
+
 int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	int idx;
+	int idx = 0;
 	int s_idx = cb->args[0];
 	struct fib_rule *r;
+	struct hlist_node *node;
+
+	rcu_read_lock();
+	hlist_for_each_entry(r, node, &fib_rules, hlist) {
 
-	read_lock(&fib_rules_lock);
-	for (r=fib_rules, idx=0; r; r = r->r_next, idx++) {
 		if (idx < s_idx)
 			continue;
 		if (inet_fill_rule(skb, r, cb, NLM_F_MULTI) < 0)
 			break;
+		idx++;
 	}
-	read_unlock(&fib_rules_lock);
+	rcu_read_unlock();
 	cb->args[0] = idx;
 
 	return skb->len;
@@ -435,5 +454,9 @@
 
 void __init fib_rules_init(void)
 {
+	INIT_HLIST_HEAD(&fib_rules);
+	hlist_add_head(&local_rule.hlist, &fib_rules);
+	hlist_add_after(&local_rule.hlist, &main_rule.hlist);
+	hlist_add_after(&main_rule.hlist, &default_rule.hlist);
 	register_netdevice_notifier(&fib_rules_notifier);
 }
diff -urN oldtree/net/ipv4/fib_semantics.c newtree/net/ipv4/fib_semantics.c
--- oldtree/net/ipv4/fib_semantics.c	2006-02-19 11:41:06.317382712 +0000
+++ newtree/net/ipv4/fib_semantics.c	2006-02-21 15:58:37.019518736 +0000
@@ -203,7 +203,7 @@
 	unsigned int val = fi->fib_nhs;
 
 	val ^= fi->fib_protocol;
-	val ^= fi->fib_prefsrc;
+	val ^= (__force u32)fi->fib_prefsrc;
 	val ^= fi->fib_priority;
 
 	return (val ^ (val >> 7) ^ (val >> 12)) & mask;
@@ -248,7 +248,7 @@
    Used only by redirect accept routine.
  */
 
-int ip_fib_check_default(u32 gw, struct net_device *dev)
+int ip_fib_check_default(__be32 gw, struct net_device *dev)
 {
 	struct hlist_head *head;
 	struct hlist_node *node;
@@ -273,7 +273,7 @@
 	return -1;
 }
 
-void rtmsg_fib(int event, u32 key, struct fib_alias *fa,
+void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
 	       int z, int tb_id,
 	       struct nlmsghdr *n, struct netlink_skb_parms *req)
 {
@@ -422,7 +422,7 @@
 	
 	for_nexthops(fi) {
 		int attrlen = nhlen - sizeof(struct rtnexthop);
-		u32 gw;
+		__be32 gw;
 
 		if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0)
 			return -EINVAL;
@@ -564,11 +564,11 @@
 	return 0;
 }
 
-static inline unsigned int fib_laddr_hashfn(u32 val)
+static inline unsigned int fib_laddr_hashfn(__be32 val)
 {
 	unsigned int mask = (fib_hash_size - 1);
 
-	return (val ^ (val >> 7) ^ (val >> 14)) & mask;
+	return ((__force u32)val ^ ((__force u32)val >> 7) ^ ((__force u32)val >> 14)) & mask;
 }
 
 static struct hlist_head *fib_hash_alloc(int bytes)
@@ -858,7 +858,7 @@
 
 /* Note! fib_semantic_match intentionally uses  RCU list functions. */
 int fib_semantic_match(struct list_head *head, const struct flowi *flp,
-		       struct fib_result *res, __u32 zone, __u32 mask, 
+		       struct fib_result *res, __be32 zone, __be32 mask, 
 			int prefixlen)
 {
 	struct fib_alias *fa;
@@ -934,7 +934,7 @@
 
 /* Find appropriate source address to this destination */
 
-u32 __fib_res_prefsrc(struct fib_result *res)
+__be32 __fib_res_prefsrc(struct fib_result *res)
 {
 	return inet_select_addr(FIB_RES_DEV(*res), FIB_RES_GW(*res), res->scope);
 }
@@ -1016,7 +1016,7 @@
 		    struct kern_rta *rta, struct rtentry *r)
 {
 	int    plen;
-	u32    *ptr;
+	__be32    *ptr;
 
 	memset(rtm, 0, sizeof(*rtm));
 	memset(rta, 0, sizeof(*rta));
@@ -1034,7 +1034,7 @@
 	plen = 32;
 	ptr = &((struct sockaddr_in*)&r->rt_dst)->sin_addr.s_addr;
 	if (!(r->rt_flags&RTF_HOST)) {
-		u32 mask = ((struct sockaddr_in*)&r->rt_genmask)->sin_addr.s_addr;
+		__be32 mask = ((struct sockaddr_in*)&r->rt_genmask)->sin_addr.s_addr;
 		if (r->rt_genmask.sa_family != AF_INET) {
 			if (mask || r->rt_genmask.sa_family)
 				return -EAFNOSUPPORT;
@@ -1160,7 +1160,7 @@
    - device went down -> we must shutdown all nexthops going via it.
  */
 
-int fib_sync_down(u32 local, struct net_device *dev, int force)
+int fib_sync_down(__be32 local, struct net_device *dev, int force)
 {
 	int ret = 0;
 	int scope = RT_SCOPE_NOWHERE;
diff -urN oldtree/net/ipv4/icmp.c newtree/net/ipv4/icmp.c
--- oldtree/net/ipv4/icmp.c	2006-02-19 11:41:06.320382256 +0000
+++ newtree/net/ipv4/icmp.c	2006-02-21 15:58:37.020518584 +0000
@@ -105,7 +105,7 @@
 
 	struct {
 		struct icmphdr icmph;
-		__u32	       times[3];
+		__be32	       times[3];
 	} data;
 	int head_len;
 	struct ip_options replyopts;
@@ -382,7 +382,7 @@
 	struct inet_sock *inet = inet_sk(sk);
 	struct ipcm_cookie ipc;
 	struct rtable *rt = (struct rtable *)skb->dst;
-	u32 daddr;
+	__be32 daddr;
 
 	if (ip_options_echo(&icmp_param->replyopts, skb))
 		return;
@@ -430,14 +430,14 @@
  *			MUST reply to only the first fragment.
  */
 
-void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
+void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
 {
 	struct iphdr *iph;
 	int room;
 	struct icmp_bxm icmp_param;
 	struct rtable *rt = (struct rtable *)skb_in->dst;
 	struct ipcm_cookie ipc;
-	u32 saddr;
+	__be32 saddr;
 	u8  tos;
 
 	if (!rt)
@@ -730,7 +730,7 @@
 static void icmp_redirect(struct sk_buff *skb)
 {
 	struct iphdr *iph;
-	unsigned long ip;
+	__be32 ip;
 
 	if (skb->len < sizeof(struct iphdr))
 		goto out_err;
@@ -895,7 +895,7 @@
 	if (in_dev->ifa_list &&
 	    IN_DEV_LOG_MARTIANS(in_dev) &&
 	    IN_DEV_FORWARD(in_dev)) {
-		u32 _mask, *mp;
+		__be32 _mask, *mp;
 
 		mp = skb_header_pointer(skb, 0, sizeof(_mask), &_mask);
 		BUG_ON(mp == NULL);
diff -urN oldtree/net/ipv4/igmp.c newtree/net/ipv4/igmp.c
--- oldtree/net/ipv4/igmp.c	2006-02-19 11:41:06.321382104 +0000
+++ newtree/net/ipv4/igmp.c	2006-02-21 15:58:37.022518280 +0000
@@ -139,14 +139,14 @@
 		time_before(jiffies, (in_dev)->mr_v2_seen)))
 
 static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im);
-static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr);
+static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr);
 static void igmpv3_clear_delrec(struct in_device *in_dev);
 static int sf_setstate(struct ip_mc_list *pmc);
 static void sf_markstate(struct ip_mc_list *pmc);
 #endif
 static void ip_mc_clear_src(struct ip_mc_list *pmc);
-static int ip_mc_add_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
-			 int sfcount, __u32 *psfsrc, int delta);
+static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
+			 int sfcount, __be32 *psfsrc, int delta);
 
 static void ip_ma_put(struct ip_mc_list *im)
 {
@@ -427,7 +427,7 @@
 	first = 1;
 	psf_prev = NULL;
 	for (psf=*psf_list; psf; psf=psf_next) {
-		u32 *psrc;
+		__be32 *psrc;
 
 		psf_next = psf->sf_next;
 
@@ -440,7 +440,7 @@
 		if (isquery)
 			psf->sf_gsresp = 0;
 
-		if (AVAILABLE(skb) < sizeof(u32) +
+		if (AVAILABLE(skb) < sizeof(__be32) +
 		    first*sizeof(struct igmpv3_grec)) {
 			if (truncate && !first)
 				break;	 /* truncate these */
@@ -456,7 +456,7 @@
 			skb = add_grhead(skb, pmc, type, &pgr);
 			first = 0;
 		}
-		psrc = (u32 *)skb_put(skb, sizeof(u32));
+		psrc = (__be32 *)skb_put(skb, sizeof(__be32));
 		*psrc = psf->sf_inaddr;
 		scount++; stotal++;
 		if ((type == IGMPV3_ALLOW_NEW_SOURCES ||
@@ -631,8 +631,8 @@
 	struct igmphdr *ih;
 	struct rtable *rt;
 	struct net_device *dev = in_dev->dev;
-	u32	group = pmc ? pmc->multiaddr : 0;
-	u32	dst;
+	__be32	group = pmc ? pmc->multiaddr : 0;
+	__be32	dst;
 
 	if (type == IGMPV3_HOST_MEMBERSHIP_REPORT)
 		return igmpv3_send_report(in_dev, pmc);
@@ -749,7 +749,7 @@
 }
 
 /* mark EXCLUDE-mode sources */
-static int igmp_xmarksources(struct ip_mc_list *pmc, int nsrcs, __u32 *srcs)
+static int igmp_xmarksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs)
 {
 	struct ip_sf_list *psf;
 	int i, scount;
@@ -776,7 +776,7 @@
 	return 1;
 }
 
-static int igmp_marksources(struct ip_mc_list *pmc, int nsrcs, __u32 *srcs)
+static int igmp_marksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs)
 {
 	struct ip_sf_list *psf;
 	int i, scount;
@@ -804,7 +804,7 @@
 	return 1;
 }
 
-static void igmp_heard_report(struct in_device *in_dev, u32 group)
+static void igmp_heard_report(struct in_device *in_dev, __be32 group)
 {
 	struct ip_mc_list *im;
 
@@ -829,7 +829,7 @@
 	struct igmphdr 		*ih = skb->h.igmph;
 	struct igmpv3_query *ih3 = (struct igmpv3_query *)ih;
 	struct ip_mc_list	*im;
-	u32			group = ih->group;
+	__be32			group = ih->group;
 	int			max_delay;
 	int			mark = 0;
 
@@ -863,7 +863,7 @@
 		ih3 = (struct igmpv3_query *) skb->h.raw;
 		if (ih3->nsrcs) {
 			if (!pskb_may_pull(skb, sizeof(struct igmpv3_query) 
-					   + ntohs(ih3->nsrcs)*sizeof(__u32)))
+					   + ntohs(ih3->nsrcs)*sizeof(__be32)))
 				return;
 			ih3 = (struct igmpv3_query *) skb->h.raw;
 		}
@@ -986,7 +986,7 @@
  *	Add a filter to a device
  */
 
-static void ip_mc_filter_add(struct in_device *in_dev, u32 addr)
+static void ip_mc_filter_add(struct in_device *in_dev, __be32 addr)
 {
 	char buf[MAX_ADDR_LEN];
 	struct net_device *dev = in_dev->dev;
@@ -1006,7 +1006,7 @@
  *	Remove a filter from a device
  */
 
-static void ip_mc_filter_del(struct in_device *in_dev, u32 addr)
+static void ip_mc_filter_del(struct in_device *in_dev, __be32 addr)
 {
 	char buf[MAX_ADDR_LEN];
 	struct net_device *dev = in_dev->dev;
@@ -1057,7 +1057,7 @@
 	spin_unlock_bh(&in_dev->mc_tomb_lock);
 }
 
-static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr)
+static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr)
 {
 	struct ip_mc_list *pmc, *pmc_prev;
 	struct ip_sf_list *psf, *psf_next;
@@ -1195,7 +1195,7 @@
  *	A socket has joined a multicast group on device dev.
  */
 
-void ip_mc_inc_group(struct in_device *in_dev, u32 addr)
+void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
 {
 	struct ip_mc_list *im;
 
@@ -1254,7 +1254,7 @@
  *	A socket has left a multicast group on device dev
  */
 
-void ip_mc_dec_group(struct in_device *in_dev, u32 addr)
+void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
 {
 	struct ip_mc_list *i, **ip;
 	
@@ -1404,7 +1404,7 @@
 
 
 static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode,
-	__u32 *psfsrc)
+	__be32 *psfsrc)
 {
 	struct ip_sf_list *psf, *psf_prev;
 	int rv = 0;
@@ -1452,8 +1452,8 @@
 #define igmp_ifc_event(x)	do { } while (0)
 #endif
 
-static int ip_mc_del_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
-			 int sfcount, __u32 *psfsrc, int delta)
+static int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
+			 int sfcount, __be32 *psfsrc, int delta)
 {
 	struct ip_mc_list *pmc;
 	int	changerec = 0;
@@ -1519,7 +1519,7 @@
  * Add multicast single-source filter to the interface list
  */
 static int ip_mc_add1_src(struct ip_mc_list *pmc, int sfmode,
-	__u32 *psfsrc, int delta)
+	__be32 *psfsrc, int delta)
 {
 	struct ip_sf_list *psf, *psf_prev;
 
@@ -1626,8 +1626,8 @@
 /*
  * Add multicast source filter list to the interface list
  */
-static int ip_mc_add_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
-			 int sfcount, __u32 *psfsrc, int delta)
+static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
+			 int sfcount, __be32 *psfsrc, int delta)
 {
 	struct ip_mc_list *pmc;
 	int	isexclude;
@@ -1720,7 +1720,7 @@
 int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
 {
 	int err;
-	u32 addr = imr->imr_multiaddr.s_addr;
+	__be32 addr = imr->imr_multiaddr.s_addr;
 	struct ip_mc_socklist *iml=NULL, *i;
 	struct in_device *in_dev;
 	struct inet_sock *inet = inet_sk(sk);
@@ -1730,7 +1730,7 @@
 	if (!MULTICAST(addr))
 		return -EINVAL;
 
-	rtnl_shlock();
+	rtnl_lock();
 
 	in_dev = ip_mc_find_dev(imr);
 
@@ -1763,7 +1763,7 @@
 	ip_mc_inc_group(in_dev, addr);
 	err = 0;
 done:
-	rtnl_shunlock();
+	rtnl_unlock();
 	return err;
 }
 
@@ -1794,7 +1794,7 @@
 	struct inet_sock *inet = inet_sk(sk);
 	struct ip_mc_socklist *iml, **imlp;
 	struct in_device *in_dev;
-	u32 group = imr->imr_multiaddr.s_addr;
+	__be32 group = imr->imr_multiaddr.s_addr;
 	u32 ifindex;
 
 	rtnl_lock();
@@ -1826,7 +1826,7 @@
 {
 	int err;
 	struct ip_mreqn imr;
-	u32 addr = mreqs->imr_multiaddr;
+	__be32 addr = mreqs->imr_multiaddr;
 	struct ip_mc_socklist *pmc;
 	struct in_device *in_dev = NULL;
 	struct inet_sock *inet = inet_sk(sk);
@@ -1837,7 +1837,7 @@
 	if (!MULTICAST(addr))
 		return -EINVAL;
 
-	rtnl_shlock();
+	rtnl_lock();
 
 	imr.imr_multiaddr.s_addr = mreqs->imr_multiaddr;
 	imr.imr_address.s_addr = mreqs->imr_interface;
@@ -1880,7 +1880,7 @@
 		rv = !0;
 		for (i=0; i<psl->sl_count; i++) {
 			rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,
-				sizeof(__u32));
+				sizeof(__be32));
 			if (rv == 0)
 				break;
 		}
@@ -1932,7 +1932,7 @@
 	rv = 1;	/* > 0 for insert logic below if sl_count is 0 */
 	for (i=0; i<psl->sl_count; i++) {
 		rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,
-			sizeof(__u32));
+			sizeof(__be32));
 		if (rv == 0)
 			break;
 	}
@@ -1947,7 +1947,7 @@
 	ip_mc_add_src(in_dev, &mreqs->imr_multiaddr, omode, 1, 
 		&mreqs->imr_sourceaddr, 1);
 done:
-	rtnl_shunlock();
+	rtnl_unlock();
 	if (leavegroup)
 		return ip_mc_leave_group(sk, &imr);
 	return err;
@@ -1957,7 +1957,7 @@
 {
 	int err = 0;
 	struct ip_mreqn	imr;
-	u32 addr = msf->imsf_multiaddr;
+	__be32 addr = msf->imsf_multiaddr;
 	struct ip_mc_socklist *pmc;
 	struct in_device *in_dev;
 	struct inet_sock *inet = inet_sk(sk);
@@ -1970,7 +1970,7 @@
 	    msf->imsf_fmode != MCAST_EXCLUDE)
 		return -EINVAL;
 
-	rtnl_shlock();
+	rtnl_lock();
 
 	imr.imr_multiaddr.s_addr = msf->imsf_multiaddr;
 	imr.imr_address.s_addr = msf->imsf_interface;
@@ -2030,7 +2030,7 @@
 	pmc->sfmode = msf->imsf_fmode;
 	err = 0;
 done:
-	rtnl_shunlock();
+	rtnl_unlock();
 	if (leavegroup)
 		err = ip_mc_leave_group(sk, &imr);
 	return err;
@@ -2041,7 +2041,7 @@
 {
 	int err, len, count, copycount;
 	struct ip_mreqn	imr;
-	u32 addr = msf->imsf_multiaddr;
+	__be32 addr = msf->imsf_multiaddr;
 	struct ip_mc_socklist *pmc;
 	struct in_device *in_dev;
 	struct inet_sock *inet = inet_sk(sk);
@@ -2050,7 +2050,7 @@
 	if (!MULTICAST(addr))
 		return -EINVAL;
 
-	rtnl_shlock();
+	rtnl_lock();
 
 	imr.imr_multiaddr.s_addr = msf->imsf_multiaddr;
 	imr.imr_address.s_addr = msf->imsf_interface;
@@ -2072,7 +2072,7 @@
 		goto done;
 	msf->imsf_fmode = pmc->sfmode;
 	psl = pmc->sflist;
-	rtnl_shunlock();
+	rtnl_unlock();
 	if (!psl) {
 		len = 0;
 		count = 0;
@@ -2091,7 +2091,7 @@
 		return -EFAULT;
 	return 0;
 done:
-	rtnl_shunlock();
+	rtnl_unlock();
 	return err;
 }
 
@@ -2100,7 +2100,7 @@
 {
 	int err, i, count, copycount;
 	struct sockaddr_in *psin;
-	u32 addr;
+	__be32 addr;
 	struct ip_mc_socklist *pmc;
 	struct inet_sock *inet = inet_sk(sk);
 	struct ip_sf_socklist *psl;
@@ -2112,7 +2112,7 @@
 	if (!MULTICAST(addr))
 		return -EINVAL;
 
-	rtnl_shlock();
+	rtnl_lock();
 
 	err = -EADDRNOTAVAIL;
 
@@ -2125,7 +2125,7 @@
 		goto done;
 	gsf->gf_fmode = pmc->sfmode;
 	psl = pmc->sflist;
-	rtnl_shunlock();
+	rtnl_unlock();
 	count = psl ? psl->sl_count : 0;
 	copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
 	gsf->gf_numsrc = count;
@@ -2146,14 +2146,14 @@
 	}
 	return 0;
 done:
-	rtnl_shunlock();
+	rtnl_unlock();
 	return err;
 }
 
 /*
  * check if a multicast source filter allows delivery for a given <src,dst,intf>
  */
-int ip_mc_sf_allow(struct sock *sk, u32 loc_addr, u32 rmt_addr, int dif)
+int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif)
 {
 	struct inet_sock *inet = inet_sk(sk);
 	struct ip_mc_socklist *pmc;
@@ -2213,7 +2213,7 @@
 	rtnl_unlock();
 }
 
-int ip_check_mc(struct in_device *in_dev, u32 mc_addr, u32 src_addr, u16 proto)
+int ip_check_mc(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u16 proto)
 {
 	struct ip_mc_list *im;
 	struct ip_sf_list *psf;
@@ -2362,7 +2362,7 @@
 
 		seq_printf(seq,
 			   "\t\t\t\t%08lX %5d %d:%08lX\t\t%d\n",
-			   im->multiaddr, im->users,
+			   (unsigned long)im->multiaddr, im->users,
 			   im->tm_running, im->tm_running ?
 			   jiffies_to_clock_t(im->timer.expires-jiffies) : 0,
 			   im->reporter);
diff -urN oldtree/net/ipv4/inet_connection_sock.c newtree/net/ipv4/inet_connection_sock.c
--- oldtree/net/ipv4/inet_connection_sock.c	2006-02-19 11:41:06.323381800 +0000
+++ newtree/net/ipv4/inet_connection_sock.c	2006-02-21 15:58:37.023518128 +0000
@@ -40,7 +40,7 @@
 int inet_csk_bind_conflict(const struct sock *sk,
 			   const struct inet_bind_bucket *tb)
 {
-	const u32 sk_rcv_saddr = inet_rcv_saddr(sk);
+	const __be32 sk_rcv_saddr = inet_rcv_saddr(sk);
 	struct sock *sk2;
 	struct hlist_node *node;
 	int reuse = sk->sk_reuse;
@@ -53,7 +53,7 @@
 		     sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) {
 			if (!reuse || !sk2->sk_reuse ||
 			    sk2->sk_state == TCP_LISTEN) {
-				const u32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
+				const __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
 				if (!sk2_rcv_saddr || !sk_rcv_saddr ||
 				    sk2_rcv_saddr == sk_rcv_saddr)
 					break;
@@ -342,10 +342,10 @@
 
 EXPORT_SYMBOL_GPL(inet_csk_route_req);
 
-static inline u32 inet_synq_hash(const u32 raddr, const u16 rport,
+static inline u32 inet_synq_hash(const __be32 raddr, const __be16 rport,
 				 const u32 rnd, const u16 synq_hsize)
 {
-	return jhash_2words(raddr, (u32)rport, rnd) & (synq_hsize - 1);
+	return jhash_2words((__force u32)raddr, (__force u32)rport, rnd) & (synq_hsize - 1);
 }
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -356,8 +356,8 @@
 
 struct request_sock *inet_csk_search_req(const struct sock *sk,
 					 struct request_sock ***prevp,
-					 const __u16 rport, const __u32 raddr,
-					 const __u32 laddr)
+					 const __be16 rport, const __be32 raddr,
+					 const __be32 laddr)
 {
 	const struct inet_connection_sock *icsk = inet_csk(sk);
 	struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
diff -urN oldtree/net/ipv4/inet_diag.c newtree/net/ipv4/inet_diag.c
--- oldtree/net/ipv4/inet_diag.c	2006-02-19 11:41:06.325381496 +0000
+++ newtree/net/ipv4/inet_diag.c	2006-02-21 15:58:37.024517976 +0000
@@ -37,8 +37,8 @@
 static const struct inet_diag_handler **inet_diag_table;
 
 struct inet_diag_entry {
-	u32 *saddr;
-	u32 *daddr;
+	__be32 *saddr;
+	__be32 *daddr;
 	u16 sport;
 	u16 dport;
 	u16 family;
@@ -295,7 +295,7 @@
 	return err;
 }
 
-static int bitstring_match(const u32 *a1, const u32 *a2, int bits)
+static int bitstring_match(const __be32 *a1, const __be32 *a2, int bits)
 {
 	int words = bits >> 5;
 
@@ -306,8 +306,8 @@
 			return 0;
 	}
 	if (bits) {
-		__u32 w1, w2;
-		__u32 mask;
+		__be32 w1, w2;
+		__be32 mask;
 
 		w1 = a1[words];
 		w2 = a2[words];
@@ -353,7 +353,7 @@
 		case INET_DIAG_BC_S_COND:
 		case INET_DIAG_BC_D_COND: {
 			struct inet_diag_hostcond *cond;
-			u32 *addr;
+			__be32 *addr;
 
 			cond = (struct inet_diag_hostcond *)(op + 1);
 			if (cond->port != -1 &&
diff -urN oldtree/net/ipv4/inet_hashtables.c newtree/net/ipv4/inet_hashtables.c
--- oldtree/net/ipv4/inet_hashtables.c	2006-02-19 11:41:06.326381344 +0000
+++ newtree/net/ipv4/inet_hashtables.c	2006-02-21 15:58:37.025517824 +0000
@@ -129,7 +129,7 @@
  * remote address for the connection. So always assume those are both
  * wildcarded during the search since they can never be otherwise.
  */
-struct sock *__inet_lookup_listener(const struct hlist_head *head, const u32 daddr,
+struct sock *__inet_lookup_listener(const struct hlist_head *head, const __be32 daddr,
 				    const unsigned short hnum, const int dif)
 {
 	struct sock *result = NULL, *sk;
@@ -140,7 +140,7 @@
 		const struct inet_sock *inet = inet_sk(sk);
 
 		if (inet->num == hnum && !ipv6_only_sock(sk)) {
-			const __u32 rcv_saddr = inet->rcv_saddr;
+			const __be32 rcv_saddr = inet->rcv_saddr;
 			int score = sk->sk_family == PF_INET ? 1 : 0;
 
 			if (rcv_saddr) {
@@ -173,8 +173,8 @@
 {
 	struct inet_hashinfo *hinfo = death_row->hashinfo;
 	struct inet_sock *inet = inet_sk(sk);
-	u32 daddr = inet->rcv_saddr;
-	u32 saddr = inet->daddr;
+	__be32 daddr = inet->rcv_saddr;
+	__be32 saddr = inet->daddr;
 	int dif = sk->sk_bound_dev_if;
 	INET_ADDR_COOKIE(acookie, saddr, daddr)
 	const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
diff -urN oldtree/net/ipv4/inetpeer.c newtree/net/ipv4/inetpeer.c
--- oldtree/net/ipv4/inetpeer.c	2006-02-19 11:41:06.327381192 +0000
+++ newtree/net/ipv4/inetpeer.c	2006-02-21 15:58:37.027517520 +0000
@@ -166,7 +166,7 @@
 	for (u = peer_root; u != peer_avl_empty; ) {		\
 		if (daddr == u->v4daddr)			\
 			break;					\
-		if (daddr < u->v4daddr)				\
+		if ((__force u32)daddr < (__force u32)u->v4daddr)	\
 			v = &u->avl_left;			\
 		else						\
 			v = &u->avl_right;			\
@@ -371,7 +371,7 @@
 }
 
 /* Called with or without local BH being disabled. */
-struct inet_peer *inet_getpeer(__u32 daddr, int create)
+struct inet_peer *inet_getpeer(__be32 daddr, int create)
 {
 	struct inet_peer *p, *n;
 	struct inet_peer **stack[PEER_MAXDEPTH], ***stackptr;
diff -urN oldtree/net/ipv4/ip_fragment.c newtree/net/ipv4/ip_fragment.c
--- oldtree/net/ipv4/ip_fragment.c	2006-02-19 11:41:06.327381192 +0000
+++ newtree/net/ipv4/ip_fragment.c	2006-02-21 15:58:37.029517216 +0000
@@ -78,9 +78,9 @@
 	struct hlist_node list;
 	struct list_head lru_list;	/* lru list member 			*/
 	u32		user;
-	u32		saddr;
-	u32		daddr;
-	u16		id;
+	__be32		saddr;
+	__be32		daddr;
+	__be16		id;
 	u8		protocol;
 	u8		last_in;
 #define COMPLETE		4
@@ -124,9 +124,10 @@
 	write_unlock(&ipfrag_lock);
 }
 
-static unsigned int ipqhashfn(u16 id, u32 saddr, u32 daddr, u8 prot)
+static unsigned int ipqhashfn(__be16 id, __be32 saddr, __be32 daddr, u8 prot)
 {
-	return jhash_3words((u32)id << 16 | prot, saddr, daddr,
+	return jhash_3words((__force u32)id << 16 | prot,
+			    (__force u32)saddr, (__force u32)daddr,
 			    ipfrag_hash_rnd) & (IPQ_HASHSZ - 1);
 }
 
@@ -384,8 +385,8 @@
 static inline struct ipq *ip_find(struct iphdr *iph, u32 user)
 {
 	__be16 id = iph->id;
-	__u32 saddr = iph->saddr;
-	__u32 daddr = iph->daddr;
+	__be32 saddr = iph->saddr;
+	__be32 daddr = iph->daddr;
 	__u8 protocol = iph->protocol;
 	unsigned int hash = ipqhashfn(id, saddr, daddr, protocol);
 	struct ipq *qp;
diff -urN oldtree/net/ipv4/ip_gre.c newtree/net/ipv4/ip_gre.c
--- oldtree/net/ipv4/ip_gre.c	2006-02-19 11:41:06.329380888 +0000
+++ newtree/net/ipv4/ip_gre.c	2006-02-21 15:58:37.030517064 +0000
@@ -145,7 +145,7 @@
  */
 
 #define HASH_SIZE  16
-#define HASH(addr) ((addr^(addr>>4))&0xF)
+#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
 
 static struct ip_tunnel *tunnels[4][HASH_SIZE];
 
@@ -158,7 +158,7 @@
 
 /* Given src, dst and key, find appropriate for input tunnel. */
 
-static struct ip_tunnel * ipgre_tunnel_lookup(u32 remote, u32 local, u32 key)
+static struct ip_tunnel * ipgre_tunnel_lookup(__be32 remote, __be32 local, __be32 key)
 {
 	unsigned h0 = HASH(remote);
 	unsigned h1 = HASH(key);
@@ -195,9 +195,9 @@
 
 static struct ip_tunnel **ipgre_bucket(struct ip_tunnel *t)
 {
-	u32 remote = t->parms.iph.daddr;
-	u32 local = t->parms.iph.saddr;
-	u32 key = t->parms.i_key;
+	__be32 remote = t->parms.iph.daddr;
+	__be32 local = t->parms.iph.saddr;
+	__be32 key = t->parms.i_key;
 	unsigned h = HASH(key);
 	int prio = 0;
 
@@ -237,9 +237,9 @@
 
 static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int create)
 {
-	u32 remote = parms->iph.daddr;
-	u32 local = parms->iph.saddr;
-	u32 key = parms->i_key;
+	__be32 remote = parms->iph.daddr;
+	__be32 local = parms->iph.saddr;
+	__be32 key = parms->i_key;
 	struct ip_tunnel *t, **tp, *nt;
 	struct net_device *dev;
 	unsigned h = HASH(key);
@@ -320,12 +320,12 @@
  */
 
 	struct iphdr *iph = (struct iphdr*)skb->data;
-	u16	     *p = (u16*)(skb->data+(iph->ihl<<2));
+	__be16	     *p = (__be16*)(skb->data+(iph->ihl<<2));
 	int grehlen = (iph->ihl<<2) + 4;
 	int type = skb->h.icmph->type;
 	int code = skb->h.icmph->code;
 	struct ip_tunnel *t;
-	u16 flags;
+	__be16 flags;
 
 	flags = p[0];
 	if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) {
@@ -371,7 +371,7 @@
 	}
 
 	read_lock(&ipgre_lock);
-	t = ipgre_tunnel_lookup(iph->daddr, iph->saddr, (flags&GRE_KEY) ? *(((u32*)p) + (grehlen>>2) - 1) : 0);
+	t = ipgre_tunnel_lookup(iph->daddr, iph->saddr, (flags&GRE_KEY) ? *(((__be32*)p) + (grehlen>>2) - 1) : 0);
 	if (t == NULL || t->parms.iph.daddr == 0 || MULTICAST(t->parms.iph.daddr))
 		goto out;
 
@@ -389,13 +389,13 @@
 #else
 	struct iphdr *iph = (struct iphdr*)dp;
 	struct iphdr *eiph;
-	u16	     *p = (u16*)(dp+(iph->ihl<<2));
+	__be16	     *p = (__be16*)(dp+(iph->ihl<<2));
 	int type = skb->h.icmph->type;
 	int code = skb->h.icmph->code;
 	int rel_type = 0;
 	int rel_code = 0;
 	int rel_info = 0;
-	u16 flags;
+	__be16 flags;
 	int grehlen = (iph->ihl<<2) + 4;
 	struct sk_buff *skb2;
 	struct flowi fl;
@@ -554,9 +554,9 @@
 {
 	struct iphdr *iph;
 	u8     *h;
-	u16    flags;
+	__be16    flags;
 	u16    csum = 0;
-	u32    key = 0;
+	__be32 key = 0;
 	u32    seqno = 0;
 	struct ip_tunnel *tunnel;
 	int    offset = 4;
@@ -566,7 +566,7 @@
 
 	iph = skb->nh.iph;
 	h = skb->data;
-	flags = *(u16*)h;
+	flags = *(__be16*)h;
 
 	if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) {
 		/* - Version must be 0.
@@ -590,11 +590,11 @@
 			offset += 4;
 		}
 		if (flags&GRE_KEY) {
-			key = *(u32*)(h + offset);
+			key = *(__be32*)(h + offset);
 			offset += 4;
 		}
 		if (flags&GRE_SEQ) {
-			seqno = ntohl(*(u32*)(h + offset));
+			seqno = ntohl(*(__be32*)(h + offset));
 			offset += 4;
 		}
 	}
@@ -603,7 +603,7 @@
 	if ((tunnel = ipgre_tunnel_lookup(iph->saddr, iph->daddr, key)) != NULL) {
 		secpath_reset(skb);
 
-		skb->protocol = *(u16*)(h + 2);
+		skb->protocol = *(__be16*)(h + 2);
 		/* WCCP version 1 and 2 protocol decoding.
 		 * - Change protocol to IP
 		 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
@@ -672,13 +672,13 @@
 	struct iphdr  *old_iph = skb->nh.iph;
 	struct iphdr  *tiph;
 	u8     tos;
-	u16    df;
+	__be16 df;
 	struct rtable *rt;     			/* Route to the other host */
 	struct net_device *tdev;			/* Device to other host */
 	struct iphdr  *iph;			/* Our new IP header */
 	int    max_headroom;			/* The extra header space needed */
 	int    gre_hlen;
-	u32    dst;
+	__be32 dst;
 	int    mtu;
 
 	if (tunnel->recursion++) {
@@ -859,11 +859,11 @@
 			iph->ttl = dst_metric(&rt->u.dst, RTAX_HOPLIMIT);
 	}
 
-	((u16*)(iph+1))[0] = tunnel->parms.o_flags;
-	((u16*)(iph+1))[1] = skb->protocol;
+	((__be16*)(iph+1))[0] = tunnel->parms.o_flags;
+	((__be16*)(iph+1))[1] = skb->protocol;
 
 	if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) {
-		u32 *ptr = (u32*)(((u8*)iph) + tunnel->hlen - 4);
+		__be32 *ptr = (__be32*)(((u8*)iph) + tunnel->hlen - 4);
 
 		if (tunnel->parms.o_flags&GRE_SEQ) {
 			++tunnel->o_seqno;
@@ -876,7 +876,7 @@
 		}
 		if (tunnel->parms.o_flags&GRE_CSUM) {
 			*ptr = 0;
-			*(__u16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr));
+			*(__be16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr));
 		}
 	}
 
@@ -1067,7 +1067,7 @@
 {
 	struct ip_tunnel *t = netdev_priv(dev);
 	struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen);
-	u16 *p = (u16*)(iph+1);
+	__be16 *p = (__be16*)(iph+1);
 
 	memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
 	p[0]		= t->parms.o_flags;
diff -urN oldtree/net/ipv4/ip_options.c newtree/net/ipv4/ip_options.c
--- oldtree/net/ipv4/ip_options.c	2006-02-19 11:41:06.330380736 +0000
+++ newtree/net/ipv4/ip_options.c	2006-02-21 15:58:37.033516608 +0000
@@ -37,7 +37,7 @@
  */
 
 void ip_options_build(struct sk_buff * skb, struct ip_options * opt,
-			    u32 daddr, struct rtable *rt, int is_frag) 
+			    __be32 daddr, struct rtable *rt, int is_frag) 
 {
 	unsigned char * iph = skb->nh.raw;
 
@@ -56,7 +56,7 @@
 			ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, rt);
 		if (opt->ts_needtime) {
 			struct timeval tv;
-			__u32 midtime;
+			__be32 midtime;
 			do_gettimeofday(&tv);
 			midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
 			memcpy(iph+opt->ts+iph[opt->ts+2]-5, &midtime, 4);
@@ -90,7 +90,7 @@
 	unsigned char *sptr, *dptr;
 	int soffset, doffset;
 	int	optlen;
-	u32	daddr;
+	__be32	daddr;
 
 	memset(dopt, 0, sizeof(struct ip_options));
 
@@ -147,7 +147,7 @@
 					dopt->ts_needtime = 0;
 
 					if (soffset + 8 <= optlen) {
-						__u32 addr;
+						__be32 addr;
 
 						memcpy(&addr, sptr+soffset-1, 4);
 						if (inet_addr_type(addr) != RTN_LOCAL) {
@@ -164,7 +164,7 @@
 	}
 	if (sopt->srr) {
 		unsigned char * start = sptr+sopt->srr;
-		u32 faddr;
+		__be32 faddr;
 
 		optlen  = start[1];
 		soffset = start[2];
@@ -389,7 +389,7 @@
 					}
 					opt->ts = optptr - iph;
 					{
-						u32 addr;
+						__be32 addr;
 						memcpy(&addr, &optptr[optptr[2]-1], 4);
 						if (inet_addr_type(addr) == RTN_UNICAST)
 							break;
@@ -408,7 +408,7 @@
 				}
 				if (timeptr) {
 					struct timeval tv;
-					__u32  midtime;
+					__be32  midtime;
 					do_gettimeofday(&tv);
 					midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
 					memcpy(timeptr, &midtime, sizeof(__u32));
@@ -590,7 +590,7 @@
 {
 	struct ip_options *opt = &(IPCB(skb)->opt);
 	int srrspace, srrptr;
-	u32 nexthop;
+	__be32 nexthop;
 	struct iphdr *iph = skb->nh.iph;
 	unsigned char * optptr = skb->nh.raw + opt->srr;
 	struct rtable *rt = (struct rtable*)skb->dst;
diff -urN oldtree/net/ipv4/ip_output.c newtree/net/ipv4/ip_output.c
--- oldtree/net/ipv4/ip_output.c	2006-02-19 11:41:06.332380432 +0000
+++ newtree/net/ipv4/ip_output.c	2006-02-21 15:58:37.034516456 +0000
@@ -121,7 +121,7 @@
  *
  */
 int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
-			  u32 saddr, u32 daddr, struct ip_options *opt)
+			  __be32 saddr, __be32 daddr, struct ip_options *opt)
 {
 	struct inet_sock *inet = inet_sk(sk);
 	struct rtable *rt = (struct rtable *)skb->dst;
@@ -310,7 +310,7 @@
 	/* Make sure we can route this packet. */
 	rt = (struct rtable *)__sk_dst_check(sk, 0);
 	if (rt == NULL) {
-		u32 daddr;
+		__be32 daddr;
 
 		/* Use correct destination address if we have options. */
 		daddr = inet->daddr;
@@ -345,7 +345,7 @@
 
 	/* OK, we know where to send it, allocate and build IP header. */
 	iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));
-	*((__u16 *)iph)	= htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
+	*((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
 	iph->tot_len = htons(skb->len);
 	if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok)
 		iph->frag_off = htons(IP_DF);
@@ -1339,7 +1339,7 @@
 		char			data[40];
 	} replyopts;
 	struct ipcm_cookie ipc;
-	u32 daddr;
+	__be32 daddr;
 	struct rtable *rt = (struct rtable*)skb->dst;
 
 	if (ip_options_echo(&replyopts.opt, skb))
diff -urN oldtree/net/ipv4/ip_sockglue.c newtree/net/ipv4/ip_sockglue.c
--- oldtree/net/ipv4/ip_sockglue.c	2006-02-19 11:41:06.332380432 +0000
+++ newtree/net/ipv4/ip_sockglue.c	2006-02-21 15:58:37.035516304 +0000
@@ -231,7 +231,7 @@
 }
 
 void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err, 
-		   u16 port, u32 info, u8 *payload)
+		   __be16 port, u32 info, u8 *payload)
 {
 	struct inet_sock *inet = inet_sk(sk);
 	struct sock_exterr_skb *serr;
@@ -260,7 +260,7 @@
 		kfree_skb(skb);
 }
 
-void ip_local_error(struct sock *sk, int err, u32 daddr, u16 port, u32 info)
+void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 info)
 {
 	struct inet_sock *inet = inet_sk(sk);
 	struct sock_exterr_skb *serr;
@@ -332,7 +332,7 @@
 	sin = (struct sockaddr_in *)msg->msg_name;
 	if (sin) {
 		sin->sin_family = AF_INET;
-		sin->sin_addr.s_addr = *(u32*)(skb->nh.raw + serr->addr_offset);
+		sin->sin_addr.s_addr = *(__be32*)(skb->nh.raw + serr->addr_offset);
 		sin->sin_port = serr->port;
 		memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
 	}
diff -urN oldtree/net/ipv4/ipcomp.c newtree/net/ipv4/ipcomp.c
--- oldtree/net/ipv4/ipcomp.c	2006-02-19 11:41:06.333380280 +0000
+++ newtree/net/ipv4/ipcomp.c	2006-02-21 15:58:37.027517520 +0000
@@ -24,6 +24,7 @@
 #include <linux/list.h>
 #include <linux/vmalloc.h>
 #include <linux/rtnetlink.h>
+#include <linux/mutex.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
 #include <net/icmp.h>
@@ -36,7 +37,7 @@
 	int users;
 };
 
-static DECLARE_MUTEX(ipcomp_resource_sem);
+static DEFINE_MUTEX(ipcomp_resource_mutex);
 static void **ipcomp_scratches;
 static int ipcomp_scratch_users;
 static LIST_HEAD(ipcomp_tfms_list);
@@ -201,7 +202,7 @@
 
 static void ipcomp4_err(struct sk_buff *skb, u32 info)
 {
-	u32 spi;
+	__be32 spi;
 	struct iphdr *iph = (struct iphdr *)skb->data;
 	struct ip_comp_hdr *ipch = (struct ip_comp_hdr *)(skb->data+(iph->ihl<<2));
 	struct xfrm_state *x;
@@ -210,7 +211,7 @@
 	    skb->h.icmph->code != ICMP_FRAG_NEEDED)
 		return;
 
-	spi = ntohl(ntohs(ipch->cpi));
+	spi = htonl(ntohs(ipch->cpi));
 	x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr,
 	                      spi, IPPROTO_COMP, AF_INET);
 	if (!x)
@@ -253,7 +254,7 @@
 }
 
 /*
- * Must be protected by xfrm_cfg_sem.  State and tunnel user references are
+ * Must be protected by xfrm_cfg_mutex.  State and tunnel user references are
  * always incremented on success.
  */
 static int ipcomp_tunnel_attach(struct xfrm_state *x)
@@ -411,9 +412,9 @@
 	if (!ipcd)
 		return;
 	xfrm_state_delete_tunnel(x);
-	down(&ipcomp_resource_sem);
+	mutex_lock(&ipcomp_resource_mutex);
 	ipcomp_free_data(ipcd);
-	up(&ipcomp_resource_sem);
+	mutex_unlock(&ipcomp_resource_mutex);
 	kfree(ipcd);
 }
 
@@ -440,14 +441,14 @@
 	if (x->props.mode)
 		x->props.header_len += sizeof(struct iphdr);
 
-	down(&ipcomp_resource_sem);
+	mutex_lock(&ipcomp_resource_mutex);
 	if (!ipcomp_alloc_scratches())
 		goto error;
 
 	ipcd->tfms = ipcomp_alloc_tfms(x->calg->alg_name);
 	if (!ipcd->tfms)
 		goto error;
-	up(&ipcomp_resource_sem);
+	mutex_unlock(&ipcomp_resource_mutex);
 
 	if (x->props.mode) {
 		err = ipcomp_tunnel_attach(x);
@@ -464,10 +465,10 @@
 	return err;
 
 error_tunnel:
-	down(&ipcomp_resource_sem);
+	mutex_lock(&ipcomp_resource_mutex);
 error:
 	ipcomp_free_data(ipcd);
-	up(&ipcomp_resource_sem);
+	mutex_unlock(&ipcomp_resource_mutex);
 	kfree(ipcd);
 	goto out;
 }
diff -urN oldtree/net/ipv4/ipconfig.c newtree/net/ipv4/ipconfig.c
--- oldtree/net/ipv4/ipconfig.c	2006-02-19 11:41:06.334380128 +0000
+++ newtree/net/ipv4/ipconfig.c	2006-02-21 15:58:37.028517368 +0000
@@ -130,19 +130,19 @@
 
 static int ic_host_name_set __initdata = 0;	/* Host name set by us? */
 
-u32 ic_myaddr = INADDR_NONE;		/* My IP address */
-static u32 ic_netmask = INADDR_NONE;	/* Netmask for local subnet */
-u32 ic_gateway = INADDR_NONE;	/* Gateway IP address */
+__be32 ic_myaddr = INADDR_NONE;		/* My IP address */
+static __be32 ic_netmask = INADDR_NONE;	/* Netmask for local subnet */
+__be32 ic_gateway = INADDR_NONE;	/* Gateway IP address */
 
-u32 ic_servaddr = INADDR_NONE;	/* Boot server IP address */
+__be32 ic_servaddr = INADDR_NONE;	/* Boot server IP address */
 
-u32 root_server_addr = INADDR_NONE;	/* Address of NFS server */
+__be32 root_server_addr = INADDR_NONE;	/* Address of NFS server */
 u8 root_server_path[256] = { 0, };	/* Path to mount as root */
 
 /* Persistent data: */
 
 static int ic_proto_used;			/* Protocol used, if any */
-static u32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */
+static __be32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */
 static u8 ic_domain[64];		/* DNS (not NIS) domain name */
 
 /*
@@ -173,7 +173,7 @@
 	struct net_device *dev;
 	unsigned short flags;
 	short able;
-	u32 xid;
+	__be32 xid;
 };
 
 static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */
@@ -186,7 +186,7 @@
 	unsigned short oflags;
 
 	last = &ic_first_dev;
-	rtnl_shlock();
+	rtnl_lock();
 
 	/* bring loopback device up first */
 	if (dev_change_flags(&loopback_dev, loopback_dev.flags | IFF_UP) < 0)
@@ -215,7 +215,7 @@
 				continue;
 			}
 			if (!(d = kmalloc(sizeof(struct ic_device), GFP_KERNEL))) {
-				rtnl_shunlock();
+				rtnl_unlock();
 				return -1;
 			}
 			d->dev = dev;
@@ -232,7 +232,7 @@
 				dev->name, able, d->xid));
 		}
 	}
-	rtnl_shunlock();
+	rtnl_unlock();
 
 	*last = NULL;
 
@@ -251,7 +251,7 @@
 	struct ic_device *d, *next;
 	struct net_device *dev;
 
-	rtnl_shlock();
+	rtnl_lock();
 	next = ic_first_dev;
 	while ((d = next)) {
 		next = d->next;
@@ -262,7 +262,7 @@
 		}
 		kfree(d);
 	}
-	rtnl_shunlock();
+	rtnl_unlock();
 }
 
 /*
@@ -270,7 +270,7 @@
  */
 
 static inline void
-set_sockaddr(struct sockaddr_in *sin, u32 addr, u16 port)
+set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port)
 {
 	sin->sin_family = AF_INET;
 	sin->sin_addr.s_addr = addr;
@@ -421,7 +421,7 @@
 {
 	struct arphdr *rarp;
 	unsigned char *rarp_ptr;
-	unsigned long sip, tip;
+	__be32 sip, tip;
 	unsigned char *sha, *tha;		/* s for "source", t for "target" */
 	struct ic_device *d;
 
@@ -531,13 +531,13 @@
 	u8 htype;		/* HW address type */
 	u8 hlen;		/* HW address length */
 	u8 hops;		/* Used only by gateways */
-	u32 xid;		/* Transaction ID */
-	u16 secs;		/* Seconds since we started */
-	u16 flags;		/* Just what it says */
-	u32 client_ip;		/* Client's IP address if known */
-	u32 your_ip;		/* Assigned IP address */
-	u32 server_ip;		/* (Next, e.g. NFS) Server's IP address */
-	u32 relay_ip;		/* IP address of BOOTP relay */
+	__be32 xid;		/* Transaction ID */
+	__be16 secs;		/* Seconds since we started */
+	__be16 flags;		/* Just what it says */
+	__be32 client_ip;	/* Client's IP address if known */
+	__be32 your_ip;		/* Assigned IP address */
+	__be32 server_ip;	/* (Next, e.g. NFS) Server's IP address */
+	__be32 relay_ip;	/* IP address of BOOTP relay */
 	u8 hw_addr[16];		/* Client's HW address */
 	u8 serv_name[64];	/* Server host name */
 	u8 boot_file[128];	/* Name of boot file */
@@ -918,7 +918,7 @@
 
 #ifdef IPCONFIG_DHCP
 		if (ic_proto_enabled & IC_USE_DHCP) {
-			u32 server_id = INADDR_NONE;
+			__be32 server_id = INADDR_NONE;
 			int mt = 0;
 
 			ext = &b->exten[4];
@@ -1214,9 +1214,9 @@
  *  need to have root_server_addr set _before_ IPConfig gets called as it
  *  can override it.
  */
-u32 __init root_nfs_parse_addr(char *name)
+__be32 __init root_nfs_parse_addr(char *name)
 {
-	u32 addr;
+	__be32 addr;
 	int octets = 0;
 	char *cp, *cq;
 
@@ -1249,7 +1249,7 @@
 
 static int __init ip_auto_config(void)
 {
-	u32 addr;
+	__be32 addr;
 
 #ifdef CONFIG_PROC_FS
 	proc_net_fops_create("pnp", S_IRUGO, &pnp_seq_fops);
diff -urN oldtree/net/ipv4/ipip.c newtree/net/ipv4/ipip.c
--- oldtree/net/ipv4/ipip.c	2006-02-19 11:41:06.335379976 +0000
+++ newtree/net/ipv4/ipip.c	2006-02-21 15:58:37.031516912 +0000
@@ -120,7 +120,7 @@
 #include <net/xfrm.h>
 
 #define HASH_SIZE  16
-#define HASH(addr) ((addr^(addr>>4))&0xF)
+#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
 
 static int ipip_fb_tunnel_init(struct net_device *dev);
 static int ipip_tunnel_init(struct net_device *dev);
@@ -136,7 +136,7 @@
 
 static DEFINE_RWLOCK(ipip_lock);
 
-static struct ip_tunnel * ipip_tunnel_lookup(u32 remote, u32 local)
+static struct ip_tunnel * ipip_tunnel_lookup(__be32 remote, __be32 local)
 {
 	unsigned h0 = HASH(remote);
 	unsigned h1 = HASH(local);
@@ -162,8 +162,8 @@
 
 static struct ip_tunnel **ipip_bucket(struct ip_tunnel *t)
 {
-	u32 remote = t->parms.iph.daddr;
-	u32 local = t->parms.iph.saddr;
+	__be32 remote = t->parms.iph.daddr;
+	__be32 local = t->parms.iph.saddr;
 	unsigned h = 0;
 	int prio = 0;
 
@@ -205,8 +205,8 @@
 
 static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int create)
 {
-	u32 remote = parms->iph.daddr;
-	u32 local = parms->iph.saddr;
+	__be32 remote = parms->iph.daddr;
+	__be32 local = parms->iph.saddr;
 	struct ip_tunnel *t, **tp, *nt;
 	struct net_device *dev;
 	unsigned h = 0;
@@ -519,13 +519,13 @@
 	struct net_device_stats *stats = &tunnel->stat;
 	struct iphdr  *tiph = &tunnel->parms.iph;
 	u8     tos = tunnel->parms.iph.tos;
-	u16    df = tiph->frag_off;
+	__be16 df = tiph->frag_off;
 	struct rtable *rt;     			/* Route to the other host */
 	struct net_device *tdev;			/* Device to other host */
 	struct iphdr  *old_iph = skb->nh.iph;
 	struct iphdr  *iph;			/* Our new IP header */
 	int    max_headroom;			/* The extra header space needed */
-	u32    dst = tiph->daddr;
+	__be32 dst = tiph->daddr;
 	int    mtu;
 
 	if (tunnel->recursion++) {
diff -urN oldtree/net/ipv4/ipmr.c newtree/net/ipv4/ipmr.c
--- oldtree/net/ipv4/ipmr.c	2006-02-19 11:41:06.336379824 +0000
+++ newtree/net/ipv4/ipmr.c	2006-02-21 15:58:37.032516760 +0000
@@ -462,7 +462,7 @@
 	return 0;
 }
 
-static struct mfc_cache *ipmr_cache_find(__u32 origin, __u32 mcastgrp)
+static struct mfc_cache *ipmr_cache_find(__be32 origin, __be32 mcastgrp)
 {
 	int line=MFC_HASH(mcastgrp,origin);
 	struct mfc_cache *c;
@@ -1097,7 +1097,7 @@
  *	important for multicast video.
  */
  
-static void ip_encap(struct sk_buff *skb, u32 saddr, u32 daddr)
+static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
 {
 	struct iphdr *iph = (struct iphdr *)skb_push(skb,sizeof(struct iphdr));
 
diff -urN oldtree/net/ipv4/ipvs/ip_vs_app.c newtree/net/ipv4/ipvs/ip_vs_app.c
--- oldtree/net/ipv4/ipvs/ip_vs_app.c	2006-02-19 11:41:06.336379824 +0000
+++ newtree/net/ipv4/ipvs/ip_vs_app.c	2006-02-21 15:58:16.817589896 +0000
@@ -31,6 +31,7 @@
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/mutex.h>
 
 #include <net/ip_vs.h>
 
@@ -40,7 +41,7 @@
 
 /* ipvs application list head */
 static LIST_HEAD(ip_vs_app_list);
-static DECLARE_MUTEX(__ip_vs_app_mutex);
+static DEFINE_MUTEX(__ip_vs_app_mutex);
 
 
 /*
@@ -173,11 +174,11 @@
 {
 	int result;
 
-	down(&__ip_vs_app_mutex);
+	mutex_lock(&__ip_vs_app_mutex);
 
 	result = ip_vs_app_inc_new(app, proto, port);
 
-	up(&__ip_vs_app_mutex);
+	mutex_unlock(&__ip_vs_app_mutex);
 
 	return result;
 }
@@ -191,11 +192,11 @@
 	/* increase the module use count */
 	ip_vs_use_count_inc();
 
-	down(&__ip_vs_app_mutex);
+	mutex_lock(&__ip_vs_app_mutex);
 
 	list_add(&app->a_list, &ip_vs_app_list);
 
-	up(&__ip_vs_app_mutex);
+	mutex_unlock(&__ip_vs_app_mutex);
 
 	return 0;
 }
@@ -209,7 +210,7 @@
 {
 	struct ip_vs_app *inc, *nxt;
 
-	down(&__ip_vs_app_mutex);
+	mutex_lock(&__ip_vs_app_mutex);
 
 	list_for_each_entry_safe(inc, nxt, &app->incs_list, a_list) {
 		ip_vs_app_inc_release(inc);
@@ -217,7 +218,7 @@
 
 	list_del(&app->a_list);
 
-	up(&__ip_vs_app_mutex);
+	mutex_unlock(&__ip_vs_app_mutex);
 
 	/* decrease the module use count */
 	ip_vs_use_count_dec();
@@ -498,7 +499,7 @@
 
 static void *ip_vs_app_seq_start(struct seq_file *seq, loff_t *pos)
 {
-	down(&__ip_vs_app_mutex);
+	mutex_lock(&__ip_vs_app_mutex);
 
 	return *pos ? ip_vs_app_idx(*pos - 1) : SEQ_START_TOKEN;
 }
@@ -530,7 +531,7 @@
 
 static void ip_vs_app_seq_stop(struct seq_file *seq, void *v)
 {
-	up(&__ip_vs_app_mutex);
+	mutex_unlock(&__ip_vs_app_mutex);
 }
 
 static int ip_vs_app_seq_show(struct seq_file *seq, void *v)
diff -urN oldtree/net/ipv4/ipvs/ip_vs_conn.c newtree/net/ipv4/ipvs/ip_vs_conn.c
--- oldtree/net/ipv4/ipvs/ip_vs_conn.c	2006-02-19 11:41:06.337379672 +0000
+++ newtree/net/ipv4/ipvs/ip_vs_conn.c	2006-02-21 15:58:37.039515696 +0000
@@ -115,9 +115,9 @@
 /*
  *	Returns hash value for IPVS connection entry
  */
-static unsigned int ip_vs_conn_hashkey(unsigned proto, __u32 addr, __u16 port)
+static unsigned int ip_vs_conn_hashkey(unsigned proto, __be32 addr, __be16 port)
 {
-	return jhash_3words(addr, port, proto, ip_vs_conn_rnd)
+	return jhash_3words((__force u32)addr, (__force u32)port, proto, ip_vs_conn_rnd)
 		& IP_VS_CONN_TAB_MASK;
 }
 
@@ -188,7 +188,7 @@
  *	d_addr, d_port: pkt dest address (load balancer)
  */
 static inline struct ip_vs_conn *__ip_vs_conn_in_get
-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
 {
 	unsigned hash;
 	struct ip_vs_conn *cp;
@@ -215,7 +215,7 @@
 }
 
 struct ip_vs_conn *ip_vs_conn_in_get
-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
 {
 	struct ip_vs_conn *cp;
 
@@ -234,7 +234,7 @@
 
 /* Get reference to connection template */
 struct ip_vs_conn *ip_vs_ct_in_get
-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
 {
 	unsigned hash;
 	struct ip_vs_conn *cp;
@@ -274,7 +274,7 @@
  *	d_addr, d_port: pkt dest address (foreign host)
  */
 struct ip_vs_conn *ip_vs_conn_out_get
-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
 {
 	unsigned hash;
 	struct ip_vs_conn *cp, *ret=NULL;
@@ -324,7 +324,7 @@
 /*
  *	Fill a no_client_port connection with a client port number
  */
-void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __u16 cport)
+void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport)
 {
 	if (ip_vs_conn_unhash(cp)) {
 		spin_lock(&cp->lock);
@@ -508,10 +508,10 @@
 		/*
 		 * Invalidate the connection template
 		 */
-		if (ct->vport != 65535) {
+		if (ct->vport != htons(0xffff)) {
 			if (ip_vs_conn_unhash(ct)) {
-				ct->dport = 65535;
-				ct->vport = 65535;
+				ct->dport = htons(0xffff);
+				ct->vport = htons(0xffff);
 				ct->cport = 0;
 				ip_vs_conn_hash(ct);
 			}
@@ -596,8 +596,8 @@
  *	Create a new connection entry and hash it into the ip_vs_conn_tab
  */
 struct ip_vs_conn *
-ip_vs_conn_new(int proto, __u32 caddr, __u16 cport, __u32 vaddr, __u16 vport,
-	       __u32 daddr, __u16 dport, unsigned flags,
+ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport,
+	       __be32 daddr, __be16 dport, unsigned flags,
 	       struct ip_vs_dest *dest)
 {
 	struct ip_vs_conn *cp;
diff -urN oldtree/net/ipv4/ipvs/ip_vs_core.c newtree/net/ipv4/ipvs/ip_vs_core.c
--- oldtree/net/ipv4/ipvs/ip_vs_core.c	2006-02-19 11:41:06.338379520 +0000
+++ newtree/net/ipv4/ipvs/ip_vs_core.c	2006-02-21 15:58:37.040515544 +0000
@@ -209,14 +209,14 @@
 static struct ip_vs_conn *
 ip_vs_sched_persist(struct ip_vs_service *svc,
 		    const struct sk_buff *skb,
-		    __u16 ports[2])
+		    __be16 ports[2])
 {
 	struct ip_vs_conn *cp = NULL;
 	struct iphdr *iph = skb->nh.iph;
 	struct ip_vs_dest *dest;
 	struct ip_vs_conn *ct;
-	__u16  dport;	 /* destination port to forward */
-	__u32  snet;	 /* source network of the client, after masking */
+	__be16  dport;	 /* destination port to forward */
+	__be32  snet;	 /* source network of the client, after masking */
 
 	/* Mask saddr with the netmask to adjust template granularity */
 	snet = iph->saddr & svc->netmask;
@@ -383,7 +383,7 @@
 	struct ip_vs_conn *cp = NULL;
 	struct iphdr *iph = skb->nh.iph;
 	struct ip_vs_dest *dest;
-	__u16 _ports[2], *pptr;
+	__be16 _ports[2], *pptr;
 
 	pptr = skb_header_pointer(skb, iph->ihl*4,
 				  sizeof(_ports), _ports);
@@ -446,7 +446,7 @@
 int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
 		struct ip_vs_protocol *pp)
 {
-	__u16 _ports[2], *pptr;
+	__be16 _ports[2], *pptr;
 	struct iphdr *iph = skb->nh.iph;
 
 	pptr = skb_header_pointer(skb, iph->ihl*4,
@@ -576,7 +576,7 @@
 
 	/* the TCP/UDP port */
 	if (IPPROTO_TCP == ciph->protocol || IPPROTO_UDP == ciph->protocol) {
-		__u16 *ports = (void *)ciph + ciph->ihl*4;
+		__be16 *ports = (void *)ciph + ciph->ihl*4;
 
 		if (inout)
 			ports[1] = cp->vport;
@@ -775,7 +775,7 @@
 		if (sysctl_ip_vs_nat_icmp_send &&
 		    (pp->protocol == IPPROTO_TCP ||
 		     pp->protocol == IPPROTO_UDP)) {
-			__u16 _ports[2], *pptr;
+			__be16 _ports[2], *pptr;
 
 			pptr = skb_header_pointer(skb, ihl,
 						  sizeof(_ports), _ports);
diff -urN oldtree/net/ipv4/ipvs/ip_vs_ctl.c newtree/net/ipv4/ipvs/ip_vs_ctl.c
--- oldtree/net/ipv4/ipvs/ip_vs_ctl.c	2006-02-19 11:41:06.339379368 +0000
+++ newtree/net/ipv4/ipvs/ip_vs_ctl.c	2006-02-21 15:58:37.049514176 +0000
@@ -34,6 +34,7 @@
 
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4.h>
+#include <linux/mutex.h>
 
 #include <net/ip.h>
 #include <net/route.h>
@@ -44,7 +45,7 @@
 #include <net/ip_vs.h>
 
 /* semaphore for IPVS sockopts. And, [gs]etsockopt may sleep. */
-static DECLARE_MUTEX(__ip_vs_mutex);
+static DEFINE_MUTEX(__ip_vs_mutex);
 
 /* lock for service table */
 static DEFINE_RWLOCK(__ip_vs_svc_lock);
@@ -282,7 +283,7 @@
  *	Returns hash value for virtual service
  */
 static __inline__ unsigned
-ip_vs_svc_hashkey(unsigned proto, __u32 addr, __u16 port)
+ip_vs_svc_hashkey(unsigned proto, __be32 addr, __be16 port)
 {
 	register unsigned porth = ntohs(port);
 
@@ -364,7 +365,7 @@
  *	Get service by {proto,addr,port} in the service table.
  */
 static __inline__ struct ip_vs_service *
-__ip_vs_service_get(__u16 protocol, __u32 vaddr, __u16 vport)
+__ip_vs_service_get(__u16 protocol, __be32 vaddr, __be16 vport)
 {
 	unsigned hash;
 	struct ip_vs_service *svc;
@@ -409,7 +410,7 @@
 }
 
 struct ip_vs_service *
-ip_vs_service_get(__u32 fwmark, __u16 protocol, __u32 vaddr, __u16 vport)
+ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport)
 {
 	struct ip_vs_service *svc;
 
@@ -479,7 +480,7 @@
 /*
  *	Returns hash value for real service
  */
-static __inline__ unsigned ip_vs_rs_hashkey(__u32 addr, __u16 port)
+static __inline__ unsigned ip_vs_rs_hashkey(__be32 addr, __be16 port)
 {
 	register unsigned porth = ntohs(port);
 
@@ -530,7 +531,7 @@
  *	Lookup real service by <proto,addr,port> in the real service table.
  */
 struct ip_vs_dest *
-ip_vs_lookup_real_service(__u16 protocol, __u32 daddr, __u16 dport)
+ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
 {
 	unsigned hash;
 	struct ip_vs_dest *dest;
@@ -561,7 +562,7 @@
  *	Lookup destination by {addr,port} in the given service
  */
 static struct ip_vs_dest *
-ip_vs_lookup_dest(struct ip_vs_service *svc, __u32 daddr, __u16 dport)
+ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
 {
 	struct ip_vs_dest *dest;
 
@@ -590,7 +591,7 @@
  *  scheduling.
  */
 static struct ip_vs_dest *
-ip_vs_trash_get_dest(struct ip_vs_service *svc, __u32 daddr, __u16 dport)
+ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
 {
 	struct ip_vs_dest *dest, *nxt;
 
@@ -773,8 +774,8 @@
 ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
 {
 	struct ip_vs_dest *dest;
-	__u32 daddr = udest->addr;
-	__u16 dport = udest->port;
+	__be32 daddr = udest->addr;
+	__be16 dport = udest->port;
 	int ret;
 
 	EnterFunction(2);
@@ -879,8 +880,8 @@
 ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
 {
 	struct ip_vs_dest *dest;
-	__u32 daddr = udest->addr;
-	__u16 dport = udest->port;
+	__be32 daddr = udest->addr;
+	__be16 dport = udest->port;
 
 	EnterFunction(2);
 
@@ -991,8 +992,8 @@
 ip_vs_del_dest(struct ip_vs_service *svc,struct ip_vs_dest_user *udest)
 {
 	struct ip_vs_dest *dest;
-	__u32 daddr = udest->addr;
-	__u16 dport = udest->port;
+	__be32 daddr = udest->addr;
+	__be16 dport = udest->port;
 
 	EnterFunction(2);
 
@@ -1950,7 +1951,7 @@
 	/* increase the module use count */
 	ip_vs_use_count_inc();
 
-	if (down_interruptible(&__ip_vs_mutex)) {
+	if (mutex_lock_interruptible(&__ip_vs_mutex)) {
 		ret = -ERESTARTSYS;
 		goto out_dec;
 	}
@@ -2041,7 +2042,7 @@
 		ip_vs_service_put(svc);
 
   out_unlock:
-	up(&__ip_vs_mutex);
+	mutex_unlock(&__ip_vs_mutex);
   out_dec:
 	/* decrease the module use count */
 	ip_vs_use_count_dec();
@@ -2211,7 +2212,7 @@
 	if (copy_from_user(arg, user, get_arglen[GET_CMDID(cmd)]) != 0)
 		return -EFAULT;
 
-	if (down_interruptible(&__ip_vs_mutex))
+	if (mutex_lock_interruptible(&__ip_vs_mutex))
 		return -ERESTARTSYS;
 
 	switch (cmd) {
@@ -2330,7 +2331,7 @@
 	}
 
   out:
-	up(&__ip_vs_mutex);
+	mutex_unlock(&__ip_vs_mutex);
 	return ret;
 }
 
diff -urN oldtree/net/ipv4/ipvs/ip_vs_dh.c newtree/net/ipv4/ipvs/ip_vs_dh.c
--- oldtree/net/ipv4/ipvs/ip_vs_dh.c	2006-02-19 11:41:06.339379368 +0000
+++ newtree/net/ipv4/ipvs/ip_vs_dh.c	2006-02-21 15:58:37.050514024 +0000
@@ -66,7 +66,7 @@
 /*
  *	Returns hash value for IPVS DH entry
  */
-static inline unsigned ip_vs_dh_hashkey(__u32 addr)
+static inline unsigned ip_vs_dh_hashkey(__be32 addr)
 {
 	return (ntohl(addr)*2654435761UL) & IP_VS_DH_TAB_MASK;
 }
@@ -76,7 +76,7 @@
  *      Get ip_vs_dest associated with supplied parameters.
  */
 static inline struct ip_vs_dest *
-ip_vs_dh_get(struct ip_vs_dh_bucket *tbl, __u32 addr)
+ip_vs_dh_get(struct ip_vs_dh_bucket *tbl, __be32 addr)
 {
 	return (tbl[ip_vs_dh_hashkey(addr)]).dest;
 }
diff -urN oldtree/net/ipv4/ipvs/ip_vs_ftp.c newtree/net/ipv4/ipvs/ip_vs_ftp.c
--- oldtree/net/ipv4/ipvs/ip_vs_ftp.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/ipv4/ipvs/ip_vs_ftp.c	2006-02-21 15:58:37.060512504 +0000
@@ -81,7 +81,7 @@
  */
 static int ip_vs_ftp_get_addrport(char *data, char *data_limit,
 				  const char *pattern, size_t plen, char term,
-				  __u32 *addr, __u16 *port,
+				  __be32 *addr, __be16 *port,
 				  char **start, char **end)
 {
 	unsigned char p[6];
@@ -147,8 +147,8 @@
 	struct tcphdr *th;
 	char *data, *data_limit;
 	char *start, *end;
-	__u32 from;
-	__u16 port;
+	__be32 from;
+	__be16 port;
 	struct ip_vs_conn *n_cp;
 	char buf[24];		/* xxx.xxx.xxx.xxx,ppp,ppp\000 */
 	unsigned buf_len;
diff -urN oldtree/net/ipv4/ipvs/ip_vs_lblc.c newtree/net/ipv4/ipvs/ip_vs_lblc.c
--- oldtree/net/ipv4/ipvs/ip_vs_lblc.c	2006-02-19 11:41:06.340379216 +0000
+++ newtree/net/ipv4/ipvs/ip_vs_lblc.c	2006-02-21 15:58:37.060512504 +0000
@@ -87,7 +87,7 @@
  */
 struct ip_vs_lblc_entry {
 	struct list_head        list;
-	__u32                   addr;           /* destination IP address */
+	__be32                  addr;           /* destination IP address */
 	struct ip_vs_dest       *dest;          /* real server (cache) */
 	unsigned long           lastuse;        /* last used time */
 };
@@ -160,7 +160,7 @@
  *      IP address to a server.
  */
 static inline struct ip_vs_lblc_entry *
-ip_vs_lblc_new(__u32 daddr, struct ip_vs_dest *dest)
+ip_vs_lblc_new(__be32 daddr, struct ip_vs_dest *dest)
 {
 	struct ip_vs_lblc_entry *en;
 
@@ -195,7 +195,7 @@
 /*
  *	Returns hash value for IPVS LBLC entry
  */
-static inline unsigned ip_vs_lblc_hashkey(__u32 addr)
+static inline unsigned ip_vs_lblc_hashkey(__be32 addr)
 {
 	return (ntohl(addr)*2654435761UL) & IP_VS_LBLC_TAB_MASK;
 }
@@ -234,7 +234,7 @@
  *  Get ip_vs_lblc_entry associated with supplied parameters.
  */
 static inline struct ip_vs_lblc_entry *
-ip_vs_lblc_get(struct ip_vs_lblc_table *tbl, __u32 addr)
+ip_vs_lblc_get(struct ip_vs_lblc_table *tbl, __be32 addr)
 {
 	unsigned hash;
 	struct ip_vs_lblc_entry *en;
diff -urN oldtree/net/ipv4/ipvs/ip_vs_lblcr.c newtree/net/ipv4/ipvs/ip_vs_lblcr.c
--- oldtree/net/ipv4/ipvs/ip_vs_lblcr.c	2006-02-19 11:41:06.341379064 +0000
+++ newtree/net/ipv4/ipvs/ip_vs_lblcr.c	2006-02-21 15:58:37.061512352 +0000
@@ -276,7 +276,7 @@
  */
 struct ip_vs_lblcr_entry {
 	struct list_head        list;
-	__u32                   addr;           /* destination IP address */
+	__be32                   addr;           /* destination IP address */
 	struct ip_vs_dest_set   set;            /* destination server set */
 	unsigned long           lastuse;        /* last used time */
 };
@@ -348,7 +348,7 @@
  *      new/free a ip_vs_lblcr_entry, which is a mapping of a destination
  *      IP address to a server.
  */
-static inline struct ip_vs_lblcr_entry *ip_vs_lblcr_new(__u32 daddr)
+static inline struct ip_vs_lblcr_entry *ip_vs_lblcr_new(__be32 daddr)
 {
 	struct ip_vs_lblcr_entry *en;
 
@@ -381,7 +381,7 @@
 /*
  *	Returns hash value for IPVS LBLCR entry
  */
-static inline unsigned ip_vs_lblcr_hashkey(__u32 addr)
+static inline unsigned ip_vs_lblcr_hashkey(__be32 addr)
 {
 	return (ntohl(addr)*2654435761UL) & IP_VS_LBLCR_TAB_MASK;
 }
@@ -420,7 +420,7 @@
  *  Get ip_vs_lblcr_entry associated with supplied parameters.
  */
 static inline struct ip_vs_lblcr_entry *
-ip_vs_lblcr_get(struct ip_vs_lblcr_table *tbl, __u32 addr)
+ip_vs_lblcr_get(struct ip_vs_lblcr_table *tbl, __be32 addr)
 {
 	unsigned hash;
 	struct ip_vs_lblcr_entry *en;
diff -urN oldtree/net/ipv4/ipvs/ip_vs_proto.c newtree/net/ipv4/ipvs/ip_vs_proto.c
--- oldtree/net/ipv4/ipvs/ip_vs_proto.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/ipv4/ipvs/ip_vs_proto.c	2006-02-21 15:58:37.062512200 +0000
@@ -176,7 +176,7 @@
 			pp->name, NIPQUAD(ih->saddr),
 			NIPQUAD(ih->daddr));
 	else {
-		__u16 _ports[2], *pptr
+		__be16 _ports[2], *pptr
 ;
 		pptr = skb_header_pointer(skb, offset + ih->ihl*4,
 					  sizeof(_ports), _ports);
diff -urN oldtree/net/ipv4/ipvs/ip_vs_proto_tcp.c newtree/net/ipv4/ipvs/ip_vs_proto_tcp.c
--- oldtree/net/ipv4/ipvs/ip_vs_proto_tcp.c	2006-02-19 11:41:06.342378912 +0000
+++ newtree/net/ipv4/ipvs/ip_vs_proto_tcp.c	2006-02-21 15:58:37.062512200 +0000
@@ -29,7 +29,7 @@
 tcp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
 		const struct iphdr *iph, unsigned int proto_off, int inverse)
 {
-	__u16 _ports[2], *pptr;
+	__be16 _ports[2], *pptr;
 
 	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
 	if (pptr == NULL)
@@ -50,7 +50,7 @@
 tcp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
 		 const struct iphdr *iph, unsigned int proto_off, int inverse)
 {
-	__u16 _ports[2], *pptr;
+	__be16 _ports[2], *pptr;
 
 	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
 	if (pptr == NULL)
@@ -112,12 +112,12 @@
 
 
 static inline void
-tcp_fast_csum_update(struct tcphdr *tcph, u32 oldip, u32 newip,
-		     u16 oldport, u16 newport)
+tcp_fast_csum_update(struct tcphdr *tcph, __be32 oldip, __be32 newip,
+		     __be16 oldport, __be16 newport)
 {
 	tcph->check =
 		ip_vs_check_diff(~oldip, newip,
-				 ip_vs_check_diff(oldport ^ 0xFFFF,
+				 ip_vs_check_diff(oldport ^ htonl(0xFFFF),
 						  newport, tcph->check));
 }
 
diff -urN oldtree/net/ipv4/ipvs/ip_vs_proto_udp.c newtree/net/ipv4/ipvs/ip_vs_proto_udp.c
--- oldtree/net/ipv4/ipvs/ip_vs_proto_udp.c	2006-02-19 11:41:06.343378760 +0000
+++ newtree/net/ipv4/ipvs/ip_vs_proto_udp.c	2006-02-21 15:58:37.063512048 +0000
@@ -29,7 +29,7 @@
 		const struct iphdr *iph, unsigned int proto_off, int inverse)
 {
 	struct ip_vs_conn *cp;
-	__u16 _ports[2], *pptr;
+	__be16 _ports[2], *pptr;
 
 	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
 	if (pptr == NULL)
@@ -54,7 +54,7 @@
 		 const struct iphdr *iph, unsigned int proto_off, int inverse)
 {
 	struct ip_vs_conn *cp;
-	__u16 _ports[2], *pptr;
+	__be16 _ports[2], *pptr;
 
 	pptr = skb_header_pointer(skb, skb->nh.iph->ihl*4,
 				  sizeof(_ports), _ports);
@@ -117,15 +117,15 @@
 
 
 static inline void
-udp_fast_csum_update(struct udphdr *uhdr, u32 oldip, u32 newip,
-		     u16 oldport, u16 newport)
+udp_fast_csum_update(struct udphdr *uhdr, __be32 oldip, __be32 newip,
+		     __be16 oldport, __be16 newport)
 {
 	uhdr->check =
 		ip_vs_check_diff(~oldip, newip,
-				 ip_vs_check_diff(oldport ^ 0xFFFF,
+				 ip_vs_check_diff(oldport ^ htonl(0xFFFF),
 						  newport, uhdr->check));
 	if (!uhdr->check)
-		uhdr->check = 0xFFFF;
+		uhdr->check = htonl(0xFFFF);
 }
 
 static int
@@ -173,7 +173,7 @@
 						cp->protocol,
 						(*pskb)->csum);
 		if (udph->check == 0)
-			udph->check = 0xFFFF;
+			udph->check = htonl(0xFFFF);
 		IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
 			  pp->name, udph->check,
 			  (char*)&(udph->check) - (char*)udph);
diff -urN oldtree/net/ipv4/ipvs/ip_vs_sh.c newtree/net/ipv4/ipvs/ip_vs_sh.c
--- oldtree/net/ipv4/ipvs/ip_vs_sh.c	2006-02-19 11:41:06.344378608 +0000
+++ newtree/net/ipv4/ipvs/ip_vs_sh.c	2006-02-21 15:58:37.064511896 +0000
@@ -63,7 +63,7 @@
 /*
  *	Returns hash value for IPVS SH entry
  */
-static inline unsigned ip_vs_sh_hashkey(__u32 addr)
+static inline unsigned ip_vs_sh_hashkey(__be32 addr)
 {
 	return (ntohl(addr)*2654435761UL) & IP_VS_SH_TAB_MASK;
 }
@@ -73,7 +73,7 @@
  *      Get ip_vs_dest associated with supplied parameters.
  */
 static inline struct ip_vs_dest *
-ip_vs_sh_get(struct ip_vs_sh_bucket *tbl, __u32 addr)
+ip_vs_sh_get(struct ip_vs_sh_bucket *tbl, __be32 addr)
 {
 	return (tbl[ip_vs_sh_hashkey(addr)]).dest;
 }
diff -urN oldtree/net/ipv4/ipvs/ip_vs_sync.c newtree/net/ipv4/ipvs/ip_vs_sync.c
--- oldtree/net/ipv4/ipvs/ip_vs_sync.c	2006-02-19 11:41:06.344378608 +0000
+++ newtree/net/ipv4/ipvs/ip_vs_sync.c	2006-02-21 15:58:37.066511592 +0000
@@ -48,16 +48,16 @@
 
 	/* Protocol, addresses and port numbers */
 	__u8			protocol;       /* Which protocol (TCP/UDP) */
-	__u16			cport;
-	__u16                   vport;
-	__u16                   dport;
-	__u32                   caddr;          /* client address */
-	__u32                   vaddr;          /* virtual address */
-	__u32                   daddr;          /* destination address */
+	__be16			cport;
+	__be16                  vport;
+	__be16                  dport;
+	__be32                  caddr;          /* client address */
+	__be32                  vaddr;          /* virtual address */
+	__be32                  daddr;          /* destination address */
 
 	/* Flags and state transition */
-	__u16                   flags;          /* status flags */
-	__u16                   state;          /* state info */
+	__be16                  flags;          /* status flags */
+	__be16                  state;          /* state info */
 
 	/* The sequence options start here */
 };
@@ -464,7 +464,7 @@
 static int bind_mcastif_addr(struct socket *sock, char *ifname)
 {
 	struct net_device *dev;
-	u32 addr;
+	__be32 addr;
 	struct sockaddr_in sin;
 
 	if ((dev = __dev_get_by_name(ifname)) == NULL)
diff -urN oldtree/net/ipv4/ipvs/ip_vs_xmit.c newtree/net/ipv4/ipvs/ip_vs_xmit.c
--- oldtree/net/ipv4/ipvs/ip_vs_xmit.c	2006-02-19 11:41:06.345378456 +0000
+++ newtree/net/ipv4/ipvs/ip_vs_xmit.c	2006-02-21 15:58:37.066511592 +0000
@@ -232,7 +232,7 @@
 
 	/* check if it is a connection of no-client-port */
 	if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) {
-		__u16 _pt, *p;
+		__be16 _pt, *p;
 		p = skb_header_pointer(skb, iph->ihl*4, sizeof(_pt), &_pt);
 		if (p == NULL)
 			goto tx_error;
diff -urN oldtree/net/ipv4/netfilter/Kconfig newtree/net/ipv4/netfilter/Kconfig
--- oldtree/net/ipv4/netfilter/Kconfig	2006-02-19 11:41:06.346378304 +0000
+++ newtree/net/ipv4/netfilter/Kconfig	2006-02-21 15:58:16.332663616 +0000
@@ -303,16 +303,6 @@
 	  destination IP' or `500pps from any given source IP'  with a single
 	  IPtables rule.
 
-config IP_NF_MATCH_POLICY
-       tristate "IPsec policy match support"
-       depends on IP_NF_IPTABLES && XFRM
-       help
-         Policy matching allows you to match packets based on the
-         IPsec policy that was used during decapsulation/will
-         be used during encapsulation.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 # `filter', generic and specific targets
 config IP_NF_FILTER
 	tristate "Packet filtering"
diff -urN oldtree/net/ipv4/netfilter/Makefile newtree/net/ipv4/netfilter/Makefile
--- oldtree/net/ipv4/netfilter/Makefile	2006-02-19 11:41:06.346378304 +0000
+++ newtree/net/ipv4/netfilter/Makefile	2006-02-21 15:58:16.333663464 +0000
@@ -57,7 +57,6 @@
 obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o
 obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
 obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
-obj-$(CONFIG_IP_NF_MATCH_POLICY) += ipt_policy.o
 
 # targets
 obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
diff -urN oldtree/net/ipv4/netfilter/arp_tables.c newtree/net/ipv4/netfilter/arp_tables.c
--- oldtree/net/ipv4/netfilter/arp_tables.c	2006-02-19 11:41:06.348378000 +0000
+++ newtree/net/ipv4/netfilter/arp_tables.c	2006-02-21 15:58:37.067511440 +0000
@@ -22,7 +22,7 @@
 #include <linux/init.h>
 
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_arp/arp_tables.h>
@@ -83,7 +83,7 @@
 {
 	char *arpptr = (char *)(arphdr + 1);
 	char *src_devaddr, *tgt_devaddr;
-	u32 src_ipaddr, tgt_ipaddr;
+	__be32 src_ipaddr, tgt_ipaddr;
 	int i, ret;
 
 #define FWINV(bool,invflg) ((bool) ^ !!(arpinfo->invflags & invflg))
@@ -208,6 +208,7 @@
 			       const struct net_device *in,
 			       const struct net_device *out,
 			       unsigned int hooknum,
+			       const struct xt_target *target,
 			       const void *targinfo,
 			       void *userinfo)
 {
@@ -300,6 +301,7 @@
 				verdict = t->u.kernel.target->target(pskb,
 								     in, out,
 								     hook,
+								     t->u.kernel.target,
 								     t->data,
 								     userdata);
 
@@ -480,26 +482,31 @@
 	}
 	t->u.kernel.target = target;
 
+	ret = xt_check_target(target, NF_ARP, t->u.target_size - sizeof(*t),
+			      name, e->comefrom, 0, 0);
+	if (ret)
+		goto err;
+			    
 	if (t->u.kernel.target == &arpt_standard_target) {
 		if (!standard_check(t, size)) {
 			ret = -EINVAL;
 			goto out;
 		}
 	} else if (t->u.kernel.target->checkentry
-		   && !t->u.kernel.target->checkentry(name, e, t->data,
+		   && !t->u.kernel.target->checkentry(name, e, target, t->data,
 						      t->u.target_size
 						      - sizeof(*t),
 						      e->comefrom)) {
-		module_put(t->u.kernel.target->me);
 		duprintf("arp_tables: check failed for `%s'.\n",
 			 t->u.kernel.target->name);
 		ret = -EINVAL;
-		goto out;
+		goto err;
 	}
 
 	(*i)++;
 	return 0;
-
+err:
+	module_put(t->u.kernel.target->me);
 out:
 	return ret;
 }
@@ -555,7 +562,7 @@
 
 	t = arpt_get_target(e);
 	if (t->u.kernel.target->destroy)
-		t->u.kernel.target->destroy(t->data,
+		t->u.kernel.target->destroy(t->u.kernel.target, t->data,
 					    t->u.target_size - sizeof(*t));
 	module_put(t->u.kernel.target->me);
 	return 0;
@@ -1138,11 +1145,13 @@
 /* The built-in targets: standard (NULL) and error. */
 static struct arpt_target arpt_standard_target = {
 	.name		= ARPT_STANDARD_TARGET,
+	.targetsize	= sizeof(int),
 };
 
 static struct arpt_target arpt_error_target = {
 	.name		= ARPT_ERROR_TARGET,
 	.target		= arpt_error,
+	.targetsize	= ARPT_FUNCTION_MAXNAMELEN,
 };
 
 static struct nf_sockopt_ops arpt_sockopts = {
diff -urN oldtree/net/ipv4/netfilter/arpt_mangle.c newtree/net/ipv4/netfilter/arpt_mangle.c
--- oldtree/net/ipv4/netfilter/arpt_mangle.c	2006-02-19 11:41:06.349377848 +0000
+++ newtree/net/ipv4/netfilter/arpt_mangle.c	2006-02-21 15:58:16.334663312 +0000
@@ -8,9 +8,10 @@
 MODULE_DESCRIPTION("arptables arp payload mangle target");
 
 static unsigned int
-target(struct sk_buff **pskb, const struct net_device *in,
-   const struct net_device *out, unsigned int hooknum, const void *targinfo,
-   void *userinfo)
+target(struct sk_buff **pskb,
+       const struct net_device *in, const struct net_device *out,
+       unsigned int hooknum, const struct xt_target *target,
+       const void *targinfo, void *userinfo)
 {
 	const struct arpt_mangle *mangle = targinfo;
 	struct arphdr *arp;
@@ -65,8 +66,8 @@
 }
 
 static int
-checkentry(const char *tablename, const void *e, void *targinfo,
-   unsigned int targinfosize, unsigned int hook_mask)
+checkentry(const char *tablename, const void *e, const struct xt_target *target,
+           void *targinfo, unsigned int targinfosize, unsigned int hook_mask)
 {
 	const struct arpt_mangle *mangle = targinfo;
 
@@ -80,12 +81,12 @@
 	return 1;
 }
 
-static struct arpt_target arpt_mangle_reg
-= {
-        .name		= "mangle",
-        .target		= target,
-        .checkentry	= checkentry,
-        .me		= THIS_MODULE,
+static struct arpt_target arpt_mangle_reg = {
+	.name		= "mangle",
+	.target		= target,
+	.targetsize	= sizeof(struct arpt_mangle),
+	.checkentry	= checkentry,
+	.me		= THIS_MODULE,
 };
 
 static int __init init(void)
diff -urN oldtree/net/ipv4/netfilter/ip_conntrack_amanda.c newtree/net/ipv4/netfilter/ip_conntrack_amanda.c
--- oldtree/net/ipv4/netfilter/ip_conntrack_amanda.c	2006-02-19 11:41:06.350377696 +0000
+++ newtree/net/ipv4/netfilter/ip_conntrack_amanda.c	2006-02-21 15:58:37.068511288 +0000
@@ -118,11 +118,11 @@
 		exp->tuple.dst.protonum = IPPROTO_TCP;
 		exp->tuple.dst.u.tcp.port = htons(port);
 
-		exp->mask.src.ip = 0xFFFFFFFF;
+		exp->mask.src.ip = htonl(0xFFFFFFFF);
 		exp->mask.src.u.tcp.port = 0;
-		exp->mask.dst.ip = 0xFFFFFFFF;
+		exp->mask.dst.ip = htonl(0xFFFFFFFF);
 		exp->mask.dst.protonum = 0xFF;
-		exp->mask.dst.u.tcp.port = 0xFFFF;
+		exp->mask.dst.u.tcp.port = htons(0xFFFF);
 
 		if (ip_nat_amanda_hook)
 			ret = ip_nat_amanda_hook(pskb, ctinfo,
diff -urN oldtree/net/ipv4/netfilter/ip_conntrack_core.c newtree/net/ipv4/netfilter/ip_conntrack_core.c
--- oldtree/net/ipv4/netfilter/ip_conntrack_core.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/ipv4/netfilter/ip_conntrack_core.c	2006-02-21 15:58:37.076510072 +0000
@@ -151,8 +151,8 @@
 static u_int32_t __hash_conntrack(const struct ip_conntrack_tuple *tuple,
 			    unsigned int size, unsigned int rnd)
 {
-	return (jhash_3words(tuple->src.ip,
-	                     (tuple->dst.ip ^ tuple->dst.protonum),
+	return (jhash_3words((__force u32)tuple->src.ip,
+	                     ((__force u32)tuple->dst.ip ^ tuple->dst.protonum),
 	                     (tuple->src.u.all | (tuple->dst.u.all << 16)),
 	                     rnd) % size);
 }
@@ -1169,9 +1169,9 @@
 int ip_ct_port_tuple_to_nfattr(struct sk_buff *skb,
 			       const struct ip_conntrack_tuple *tuple)
 {
-	NFA_PUT(skb, CTA_PROTO_SRC_PORT, sizeof(u_int16_t),
+	NFA_PUT(skb, CTA_PROTO_SRC_PORT, sizeof(__be16),
 		&tuple->src.u.tcp.port);
-	NFA_PUT(skb, CTA_PROTO_DST_PORT, sizeof(u_int16_t),
+	NFA_PUT(skb, CTA_PROTO_DST_PORT, sizeof(__be16),
 		&tuple->dst.u.tcp.port);
 	return 0;
 
@@ -1186,9 +1186,9 @@
 		return -EINVAL;
 
 	t->src.u.tcp.port =
-		*(u_int16_t *)NFA_DATA(tb[CTA_PROTO_SRC_PORT-1]);
+		*(__be16 *)NFA_DATA(tb[CTA_PROTO_SRC_PORT-1]);
 	t->dst.u.tcp.port =
-		*(u_int16_t *)NFA_DATA(tb[CTA_PROTO_DST_PORT-1]);
+		*(__be16 *)NFA_DATA(tb[CTA_PROTO_DST_PORT-1]);
 
 	return 0;
 }
diff -urN oldtree/net/ipv4/netfilter/ip_conntrack_ftp.c newtree/net/ipv4/netfilter/ip_conntrack_ftp.c
--- oldtree/net/ipv4/netfilter/ip_conntrack_ftp.c	2006-02-19 11:41:06.350377696 +0000
+++ newtree/net/ipv4/netfilter/ip_conntrack_ftp.c	2006-02-21 15:58:37.087508400 +0000
@@ -417,8 +417,8 @@
 	exp->tuple.src.u.tcp.port = 0; /* Don't care. */
 	exp->tuple.dst.protonum = IPPROTO_TCP;
 	exp->mask = ((struct ip_conntrack_tuple)
-		{ { 0xFFFFFFFF, { 0 } },
-		  { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }});
+		{ { htonl(0xFFFFFFFF), { 0 } },
+		  { htonl(0xFFFFFFFF), { .tcp = { htons(0xFFFF) } }, 0xFF }});
 
 	exp->expectfn = NULL;
 	exp->flags = 0;
@@ -480,7 +480,7 @@
 	for (i = 0; i < ports_c; i++) {
 		ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
 		ftp[i].tuple.dst.protonum = IPPROTO_TCP;
-		ftp[i].mask.src.u.tcp.port = 0xFFFF;
+		ftp[i].mask.src.u.tcp.port = htons(0xFFFF);
 		ftp[i].mask.dst.protonum = 0xFF;
 		ftp[i].max_expected = 1;
 		ftp[i].timeout = 5 * 60; /* 5 minutes */
diff -urN oldtree/net/ipv4/netfilter/ip_conntrack_helper_pptp.c newtree/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
--- oldtree/net/ipv4/netfilter/ip_conntrack_helper_pptp.c	2006-02-19 11:41:06.351377544 +0000
+++ newtree/net/ipv4/netfilter/ip_conntrack_helper_pptp.c	2006-02-21 15:58:37.088508248 +0000
@@ -259,11 +259,11 @@
 
 	memcpy(&exp_orig->tuple, &exp_tuples[0], sizeof(exp_orig->tuple));
 
-	exp_orig->mask.src.ip = 0xffffffff;
+	exp_orig->mask.src.ip = htonl(0xffffffff);
 	exp_orig->mask.src.u.all = 0;
 	exp_orig->mask.dst.u.all = 0;
 	exp_orig->mask.dst.u.gre.key = htons(0xffff);
-	exp_orig->mask.dst.ip = 0xffffffff;
+	exp_orig->mask.dst.ip = htonl(0xffffffff);
 	exp_orig->mask.dst.protonum = 0xff;
 		
 	exp_orig->master = master;
diff -urN oldtree/net/ipv4/netfilter/ip_conntrack_irc.c newtree/net/ipv4/netfilter/ip_conntrack_irc.c
--- oldtree/net/ipv4/netfilter/ip_conntrack_irc.c	2006-02-19 11:41:06.351377544 +0000
+++ newtree/net/ipv4/netfilter/ip_conntrack_irc.c	2006-02-21 15:58:37.090507944 +0000
@@ -219,7 +219,8 @@
 				    IPPROTO_TCP }});
 			exp->mask = ((struct ip_conntrack_tuple)
 				{ { 0, { 0 } },
-				  { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }});
+				  { htonl(0xFFFFFFFF),
+					{ .tcp = { htons(0xFFFF) } }, 0xFF }});
 			exp->expectfn = NULL;
 			exp->flags = 0;
 			if (ip_nat_irc_hook)
@@ -267,7 +268,7 @@
 		hlpr = &irc_helpers[i];
 		hlpr->tuple.src.u.tcp.port = htons(ports[i]);
 		hlpr->tuple.dst.protonum = IPPROTO_TCP;
-		hlpr->mask.src.u.tcp.port = 0xFFFF;
+		hlpr->mask.src.u.tcp.port = htons(0xFFFF);
 		hlpr->mask.dst.protonum = 0xFF;
 		hlpr->max_expected = max_dcc_channels;
 		hlpr->timeout = dcc_timeout;
diff -urN oldtree/net/ipv4/netfilter/ip_conntrack_netbios_ns.c newtree/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
--- oldtree/net/ipv4/netfilter/ip_conntrack_netbios_ns.c	2006-02-19 11:41:06.352377392 +0000
+++ newtree/net/ipv4/netfilter/ip_conntrack_netbios_ns.c	2006-02-21 15:58:37.091507792 +0000
@@ -47,7 +47,7 @@
 	struct iphdr *iph = (*pskb)->nh.iph;
 	struct rtable *rt = (struct rtable *)(*pskb)->dst;
 	struct in_device *in_dev;
-	u_int32_t mask = 0;
+	__be32 mask = 0;
 
 	/* we're only interested in locally generated packets */
 	if ((*pskb)->sk == NULL)
@@ -77,12 +77,12 @@
 		goto out;
 
 	exp->tuple                = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
-	exp->tuple.src.u.udp.port = ntohs(NMBD_PORT);
+	exp->tuple.src.u.udp.port = htons(NMBD_PORT);
 
 	exp->mask.src.ip          = mask;
-	exp->mask.src.u.udp.port  = 0xFFFF;
-	exp->mask.dst.ip          = 0xFFFFFFFF;
-	exp->mask.dst.u.udp.port  = 0xFFFF;
+	exp->mask.src.u.udp.port  = htons(0xFFFF);
+	exp->mask.dst.ip          = htonl(0xFFFFFFFF);
+	exp->mask.dst.u.udp.port  = htons(0xFFFF);
 	exp->mask.dst.protonum    = 0xFF;
 
 	exp->expectfn             = NULL;
@@ -114,7 +114,7 @@
 		.src = {
 			.u = {
 				.udp = {
-					.port	= 0xFFFF,
+					.port	= __constant_htons(0xFFFF),
 				}
 			}
 		},
diff -urN oldtree/net/ipv4/netfilter/ip_conntrack_netlink.c newtree/net/ipv4/netfilter/ip_conntrack_netlink.c
--- oldtree/net/ipv4/netfilter/ip_conntrack_netlink.c	2006-02-19 11:41:06.353377240 +0000
+++ newtree/net/ipv4/netfilter/ip_conntrack_netlink.c	2006-02-21 15:58:37.092507640 +0000
@@ -82,8 +82,8 @@
 	int ret;
 	
 	nest_parms = NFA_NEST(skb, CTA_TUPLE_IP);
-	NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), &tuple->src.ip);
-	NFA_PUT(skb, CTA_IP_V4_DST, sizeof(u_int32_t), &tuple->dst.ip);
+	NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(__be32), &tuple->src.ip);
+	NFA_PUT(skb, CTA_IP_V4_DST, sizeof(__be32), &tuple->dst.ip);
 	NFA_NEST_END(skb, nest_parms);
 
 	nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO);
@@ -99,7 +99,7 @@
 static inline int
 ctnetlink_dump_status(struct sk_buff *skb, const struct ip_conntrack *ct)
 {
-	u_int32_t status = htonl((u_int32_t) ct->status);
+	__be32 status = htonl((u_int32_t) ct->status);
 	NFA_PUT(skb, CTA_STATUS, sizeof(status), &status);
 	return 0;
 
@@ -111,7 +111,7 @@
 ctnetlink_dump_timeout(struct sk_buff *skb, const struct ip_conntrack *ct)
 {
 	long timeout_l = ct->timeout.expires - jiffies;
-	u_int32_t timeout;
+	__be32 timeout;
 
 	if (timeout_l < 0)
 		timeout = 0;
@@ -181,13 +181,13 @@
 {
 	enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;
 	struct nfattr *nest_count = NFA_NEST(skb, type);
-	u_int32_t tmp;
+	__be32 tmp;
 
 	tmp = htonl(ct->counters[dir].packets);
-	NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp);
+	NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(__be32), &tmp);
 
 	tmp = htonl(ct->counters[dir].bytes);
-	NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(u_int32_t), &tmp);
+	NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(__be32), &tmp);
 
 	NFA_NEST_END(skb, nest_count);
 
@@ -204,9 +204,9 @@
 static inline int
 ctnetlink_dump_mark(struct sk_buff *skb, const struct ip_conntrack *ct)
 {
-	u_int32_t mark = htonl(ct->mark);
+	__be32 mark = htonl(ct->mark);
 
-	NFA_PUT(skb, CTA_MARK, sizeof(u_int32_t), &mark);
+	NFA_PUT(skb, CTA_MARK, sizeof(__be32), &mark);
 	return 0;
 
 nfattr_failure:
@@ -219,8 +219,8 @@
 static inline int
 ctnetlink_dump_id(struct sk_buff *skb, const struct ip_conntrack *ct)
 {
-	u_int32_t id = htonl(ct->id);
-	NFA_PUT(skb, CTA_ID, sizeof(u_int32_t), &id);
+	__be32 id = htonl(ct->id);
+	NFA_PUT(skb, CTA_ID, sizeof(__be32), &id);
 	return 0;
 
 nfattr_failure:
@@ -230,9 +230,9 @@
 static inline int
 ctnetlink_dump_use(struct sk_buff *skb, const struct ip_conntrack *ct)
 {
-	u_int32_t use = htonl(atomic_read(&ct->ct_general.use));
+	__be32 use = htonl(atomic_read(&ct->ct_general.use));
 	
-	NFA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use);
+	NFA_PUT(skb, CTA_USE, sizeof(__be32), &use);
 	return 0;
 
 nfattr_failure:
@@ -327,9 +327,10 @@
 		group = NFNLGRP_CONNTRACK_UPDATE;
 	} else 
 		return NOTIFY_DONE;
-	
-  /* FIXME: Check if there are any listeners before, don't hurt performance */
-	
+
+	if (!nfnetlink_has_listeners(group))
+		return NOTIFY_DONE;
+
 	skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
 	if (!skb)
 		return NOTIFY_DONE;
@@ -467,8 +468,8 @@
 #endif
 
 static const size_t cta_min_ip[CTA_IP_MAX] = {
-	[CTA_IP_V4_SRC-1]	= sizeof(u_int32_t),
-	[CTA_IP_V4_DST-1]	= sizeof(u_int32_t),
+	[CTA_IP_V4_SRC-1]	= sizeof(__be32),
+	[CTA_IP_V4_DST-1]	= sizeof(__be32),
 };
 
 static inline int
@@ -485,11 +486,11 @@
 
 	if (!tb[CTA_IP_V4_SRC-1])
 		return -EINVAL;
-	tuple->src.ip = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]);
+	tuple->src.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_SRC-1]);
 
 	if (!tb[CTA_IP_V4_DST-1])
 		return -EINVAL;
-	tuple->dst.ip = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]);
+	tuple->dst.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_DST-1]);
 
 	DEBUGP("leaving\n");
 
@@ -612,8 +613,8 @@
 }
 
 static const size_t cta_min_nat[CTA_NAT_MAX] = {
-	[CTA_NAT_MINIP-1]       = sizeof(u_int32_t),
-	[CTA_NAT_MAXIP-1]       = sizeof(u_int32_t),
+	[CTA_NAT_MINIP-1]       = sizeof(__be32),
+	[CTA_NAT_MAXIP-1]       = sizeof(__be32),
 };
 
 static inline int
@@ -633,12 +634,12 @@
 		return -EINVAL;
 
 	if (tb[CTA_NAT_MINIP-1])
-		range->min_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MINIP-1]);
+		range->min_ip = *(__be32 *)NFA_DATA(tb[CTA_NAT_MINIP-1]);
 
 	if (!tb[CTA_NAT_MAXIP-1])
 		range->max_ip = range->min_ip;
 	else
-		range->max_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MAXIP-1]);
+		range->max_ip = *(__be32 *)NFA_DATA(tb[CTA_NAT_MAXIP-1]);
 
 	if (range->min_ip)
 		range->flags |= IP_NAT_RANGE_MAP_IPS;
@@ -673,11 +674,11 @@
 }
 
 static const size_t cta_min[CTA_MAX] = {
-	[CTA_STATUS-1] 		= sizeof(u_int32_t),
-	[CTA_TIMEOUT-1] 	= sizeof(u_int32_t),
-	[CTA_MARK-1]		= sizeof(u_int32_t),
-	[CTA_USE-1]		= sizeof(u_int32_t),
-	[CTA_ID-1]		= sizeof(u_int32_t)
+	[CTA_STATUS-1] 		= sizeof(__be32),
+	[CTA_TIMEOUT-1] 	= sizeof(__be32),
+	[CTA_MARK-1]		= sizeof(__be32),
+	[CTA_USE-1]		= sizeof(__be32),
+	[CTA_ID-1]		= sizeof(__be32)
 };
 
 static int
@@ -716,7 +717,7 @@
 	ct = tuplehash_to_ctrack(h);
 	
 	if (cda[CTA_ID-1]) {
-		u_int32_t id = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_ID-1]));
+		u_int32_t id = ntohl(*(__be32 *)NFA_DATA(cda[CTA_ID-1]));
 		if (ct->id != id) {
 			ip_conntrack_put(ct);
 			return -ENOENT;
@@ -826,7 +827,7 @@
 ctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[])
 {
 	unsigned long d;
-	unsigned status = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1]));
+	unsigned status = ntohl(*(__be32 *)NFA_DATA(cda[CTA_STATUS-1]));
 	d = ct->status ^ status;
 
 	if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
@@ -930,7 +931,7 @@
 static inline int
 ctnetlink_change_timeout(struct ip_conntrack *ct, struct nfattr *cda[])
 {
-	u_int32_t timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));
+	u_int32_t timeout = ntohl(*(__be32 *)NFA_DATA(cda[CTA_TIMEOUT-1]));
 	
 	if (!del_timer(&ct->timeout))
 		return -ETIME;
@@ -993,7 +994,7 @@
 
 #if defined(CONFIG_IP_NF_CONNTRACK_MARK)
 	if (cda[CTA_MARK-1])
-		ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
+		ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1]));
 #endif
 
 	DEBUGP("all done\n");
@@ -1016,7 +1017,7 @@
 
 	if (!cda[CTA_TIMEOUT-1])
 		goto err;
-	ct->timeout.expires = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));
+	ct->timeout.expires = ntohl(*(__be32 *)NFA_DATA(cda[CTA_TIMEOUT-1]));
 
 	ct->timeout.expires = jiffies + ct->timeout.expires * HZ;
 	ct->status |= IPS_CONFIRMED;
@@ -1033,7 +1034,7 @@
 
 #if defined(CONFIG_IP_NF_CONNTRACK_MARK)
 	if (cda[CTA_MARK-1])
-		ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
+		ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1]));
 #endif
 
 	ct->helper = ip_conntrack_helper_find_get(rtuple);
@@ -1138,8 +1139,8 @@
                           const struct ip_conntrack_expect *exp)
 {
 	struct ip_conntrack *master = exp->master;
-	u_int32_t timeout = htonl((exp->timeout.expires - jiffies) / HZ);
-	u_int32_t id = htonl(exp->id);
+	__be32 timeout = htonl((exp->timeout.expires - jiffies) / HZ);
+	__be32 id = htonl(exp->id);
 
 	if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0)
 		goto nfattr_failure;
@@ -1150,8 +1151,8 @@
 				 CTA_EXPECT_MASTER) < 0)
 		goto nfattr_failure;
 	
-	NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(timeout), &timeout);
-	NFA_PUT(skb, CTA_EXPECT_ID, sizeof(u_int32_t), &id);
+	NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(__be32), &timeout);
+	NFA_PUT(skb, CTA_EXPECT_ID, sizeof(__be32), &id);
 
 	return 0;
 	
@@ -1269,8 +1270,8 @@
 }
 
 static const size_t cta_min_exp[CTA_EXPECT_MAX] = {
-	[CTA_EXPECT_TIMEOUT-1]          = sizeof(u_int32_t),
-	[CTA_EXPECT_ID-1]               = sizeof(u_int32_t)
+	[CTA_EXPECT_TIMEOUT-1]          = sizeof(__be32),
+	[CTA_EXPECT_ID-1]               = sizeof(__be32)
 };
 
 static int
@@ -1318,7 +1319,7 @@
 		return -ENOENT;
 
 	if (cda[CTA_EXPECT_ID-1]) {
-		u_int32_t id = *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
+		__be32 id = *(__be32 *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
 		if (exp->id != ntohl(id)) {
 			ip_conntrack_expect_put(exp);
 			return -ENOENT;
@@ -1372,8 +1373,8 @@
 			return -ENOENT;
 
 		if (cda[CTA_EXPECT_ID-1]) {
-			u_int32_t id = 
-				*(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
+			__be32 id = 
+				*(__be32 *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
 			if (exp->id != ntohl(id)) {
 				ip_conntrack_expect_put(exp);
 				return -ENOENT;
diff -urN oldtree/net/ipv4/netfilter/ip_conntrack_proto_icmp.c newtree/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
--- oldtree/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	2006-02-19 11:41:06.354377088 +0000
+++ newtree/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	2006-02-21 15:58:37.100506424 +0000
@@ -272,7 +272,7 @@
 static int icmp_tuple_to_nfattr(struct sk_buff *skb,
 				const struct ip_conntrack_tuple *t)
 {
-	NFA_PUT(skb, CTA_PROTO_ICMP_ID, sizeof(u_int16_t),
+	NFA_PUT(skb, CTA_PROTO_ICMP_ID, sizeof(__be16),
 		&t->src.u.icmp.id);
 	NFA_PUT(skb, CTA_PROTO_ICMP_TYPE, sizeof(u_int8_t),
 		&t->dst.u.icmp.type);
@@ -298,7 +298,7 @@
 	tuple->dst.u.icmp.code =
 			*(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]);
 	tuple->src.u.icmp.id =
-			*(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]);
+			*(__be16 *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]);
 
 	if (tuple->dst.u.icmp.type >= sizeof(invmap)
 	    || !invmap[tuple->dst.u.icmp.type])
diff -urN oldtree/net/ipv4/netfilter/ip_conntrack_proto_sctp.c newtree/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
--- oldtree/net/ipv4/netfilter/ip_conntrack_proto_sctp.c	2006-02-19 11:41:06.355376936 +0000
+++ newtree/net/ipv4/netfilter/ip_conntrack_proto_sctp.c	2006-02-21 15:58:37.104505816 +0000
@@ -210,7 +210,7 @@
 for (offset = skb->nh.iph->ihl * 4 + sizeof(sctp_sctphdr_t), count = 0;	\
 	offset < skb->len &&						\
 	(sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch));	\
-	offset += (htons(sch->length) + 3) & ~3, count++)
+	offset += (ntohs(sch->length) + 3) & ~3, count++)
 
 /* Some validity checks to make sure the chunks are fine */
 static int do_basic_checks(struct ip_conntrack *conntrack,
diff -urN oldtree/net/ipv4/netfilter/ip_conntrack_proto_tcp.c newtree/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- oldtree/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	2006-02-19 11:41:06.356376784 +0000
+++ newtree/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	2006-02-21 15:58:37.115504144 +0000
@@ -520,8 +520,8 @@
 
 	/* Fast path for timestamp-only option */
 	if (length == TCPOLEN_TSTAMP_ALIGNED*4
-	    && *(__u32 *)ptr ==
-	        __constant_ntohl((TCPOPT_NOP << 24) 
+	    && *(__be32 *)ptr ==
+	        __constant_htonl((TCPOPT_NOP << 24) 
 	        		 | (TCPOPT_NOP << 16)
 	        		 | (TCPOPT_TIMESTAMP << 8)
 	        		 | TCPOLEN_TIMESTAMP))
@@ -552,7 +552,7 @@
 			    	for (i = 0;
 			    	     i < (opsize - TCPOLEN_SACK_BASE);
 			    	     i += TCPOLEN_SACK_PERBLOCK) {
-					tmp = ntohl(*((u_int32_t *)(ptr+i)+1));
+					tmp = ntohl(*((__be32 *)(ptr+i)+1));
 					
 					if (after(tmp, *sack))
 						*sack = tmp;
diff -urN oldtree/net/ipv4/netfilter/ip_conntrack_tftp.c newtree/net/ipv4/netfilter/ip_conntrack_tftp.c
--- oldtree/net/ipv4/netfilter/ip_conntrack_tftp.c	2006-02-19 11:41:06.358376480 +0000
+++ newtree/net/ipv4/netfilter/ip_conntrack_tftp.c	2006-02-21 15:58:37.122503080 +0000
@@ -70,10 +70,10 @@
 			return NF_DROP;
 
 		exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
-		exp->mask.src.ip = 0xffffffff;
+		exp->mask.src.ip = htonl(0xffffffff);
 		exp->mask.src.u.udp.port = 0;
-		exp->mask.dst.ip = 0xffffffff;
-		exp->mask.dst.u.udp.port = 0xffff;
+		exp->mask.dst.ip = htonl(0xffffffff);
+		exp->mask.dst.u.udp.port = htons(0xffff);
 		exp->mask.dst.protonum = 0xff;
 		exp->expectfn = NULL;
 		exp->flags = 0;
@@ -129,7 +129,7 @@
 		tftp[i].tuple.dst.protonum = IPPROTO_UDP;
 		tftp[i].tuple.src.u.udp.port = htons(ports[i]);
 		tftp[i].mask.dst.protonum = 0xFF;
-		tftp[i].mask.src.u.udp.port = 0xFFFF;
+		tftp[i].mask.src.u.udp.port = htons(0xFFFF);
 		tftp[i].max_expected = 1;
 		tftp[i].timeout = 5 * 60; /* 5 minutes */
 		tftp[i].me = THIS_MODULE;
diff -urN oldtree/net/ipv4/netfilter/ip_nat_core.c newtree/net/ipv4/netfilter/ip_nat_core.c
--- oldtree/net/ipv4/netfilter/ip_nat_core.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/ipv4/netfilter/ip_nat_core.c	2006-02-21 15:58:37.127502320 +0000
@@ -86,7 +86,7 @@
 hash_by_src(const struct ip_conntrack_tuple *tuple)
 {
 	/* Original src, to ensure we map it consistently if poss. */
-	return jhash_3words(tuple->src.ip, tuple->src.u.all,
+	return jhash_3words((__force u32)tuple->src.ip, tuple->src.u.all,
 			    tuple->dst.protonum, 0) % ip_nat_htable_size;
 }
 
@@ -206,7 +206,7 @@
 		    const struct ip_conntrack *conntrack,
 		    enum ip_nat_manip_type maniptype)
 {
-	u_int32_t *var_ipp;
+	__be32 *var_ipp;
 	/* Host order */
 	u_int32_t minip, maxip, j;
 
@@ -233,7 +233,7 @@
 	 * like this), even across reboots. */
 	minip = ntohl(range->min_ip);
 	maxip = ntohl(range->max_ip);
-	j = jhash_2words(tuple->src.ip, tuple->dst.ip, 0);
+	j = jhash_2words((__force u32)tuple->src.ip, (__force u32)tuple->dst.ip, 0);
 	*var_ipp = htonl(minip + j % (maxip - minip + 1));
 }
 
@@ -550,9 +550,9 @@
 ip_nat_port_range_to_nfattr(struct sk_buff *skb, 
 			    const struct ip_nat_range *range)
 {
-	NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(u_int16_t),
+	NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(__be16),
 		&range->min.tcp.port);
-	NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(u_int16_t),
+	NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(__be16),
 		&range->max.tcp.port);
 
 	return 0;
@@ -571,7 +571,7 @@
 	if (tb[CTA_PROTONAT_PORT_MIN-1]) {
 		ret = 1;
 		range->min.tcp.port = 
-			*(u_int16_t *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]);
+			*(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]);
 	}
 	
 	if (!tb[CTA_PROTONAT_PORT_MAX-1]) {
@@ -580,7 +580,7 @@
 	} else {
 		ret = 1;
 		range->max.tcp.port = 
-			*(u_int16_t *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]);
+			*(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]);
 	}
 
 	return ret;
diff -urN oldtree/net/ipv4/netfilter/ip_nat_ftp.c newtree/net/ipv4/netfilter/ip_nat_ftp.c
--- oldtree/net/ipv4/netfilter/ip_nat_ftp.c	2006-02-19 11:41:06.358376480 +0000
+++ newtree/net/ipv4/netfilter/ip_nat_ftp.c	2006-02-21 15:58:37.140500344 +0000
@@ -34,7 +34,7 @@
 
 static int
 mangle_rfc959_packet(struct sk_buff **pskb,
-		     u_int32_t newip,
+		     __be32 newip,
 		     u_int16_t port,
 		     unsigned int matchoff,
 		     unsigned int matchlen,
@@ -57,7 +57,7 @@
 /* |1|132.235.1.2|6275| */
 static int
 mangle_eprt_packet(struct sk_buff **pskb,
-		   u_int32_t newip,
+		   __be32 newip,
 		   u_int16_t port,
 		   unsigned int matchoff,
 		   unsigned int matchlen,
@@ -79,7 +79,7 @@
 /* |1|132.235.1.2|6275| */
 static int
 mangle_epsv_packet(struct sk_buff **pskb,
-		   u_int32_t newip,
+		   __be32 newip,
 		   u_int16_t port,
 		   unsigned int matchoff,
 		   unsigned int matchlen,
@@ -98,7 +98,7 @@
 					matchlen, buffer, strlen(buffer));
 }
 
-static int (*mangle[])(struct sk_buff **, u_int32_t, u_int16_t,
+static int (*mangle[])(struct sk_buff **, __be32, u_int16_t,
 		     unsigned int,
 		     unsigned int,
 		     struct ip_conntrack *,
@@ -120,7 +120,7 @@
 			       struct ip_conntrack_expect *exp,
 			       u32 *seq)
 {
-	u_int32_t newip;
+	__be32 newip;
 	u_int16_t port;
 	int dir = CTINFO2DIR(ctinfo);
 	struct ip_conntrack *ct = exp->master;
diff -urN oldtree/net/ipv4/netfilter/ip_nat_helper.c newtree/net/ipv4/netfilter/ip_nat_helper.c
--- oldtree/net/ipv4/netfilter/ip_nat_helper.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/ipv4/netfilter/ip_nat_helper.c	2006-02-21 15:58:37.145499584 +0000
@@ -268,7 +268,7 @@
 	    struct ip_nat_seq *natseq)
 {
 	while (sackoff < sackend) {
-		struct tcp_sack_block *sack;
+		struct tcp_sack_block_wire *sack;
 		u_int32_t new_start_seq, new_end_seq;
 
 		sack = (void *)skb->data + sackoff;
diff -urN oldtree/net/ipv4/netfilter/ip_nat_helper_pptp.c newtree/net/ipv4/netfilter/ip_nat_helper_pptp.c
--- oldtree/net/ipv4/netfilter/ip_nat_helper_pptp.c	2006-02-19 11:41:06.359376328 +0000
+++ newtree/net/ipv4/netfilter/ip_nat_helper_pptp.c	2006-02-21 15:58:37.145499584 +0000
@@ -52,6 +52,8 @@
 
 #define IP_NAT_PPTP_VERSION "3.0"
 
+#define REQ_CID(req, off)		(*(u_int16_t *)((char *)(req) + (off)))
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
 MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP");
@@ -148,7 +150,8 @@
 {
 	struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
 	struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
-	u_int16_t msg, new_callid;
+	u_int16_t msg;
+	__be16 new_callid;
 	unsigned int cid_off;
 
 	new_callid = htons(ct_pptp_info->pns_call_id);
@@ -198,7 +201,7 @@
 	/* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass
 	 * down to here */
 	DEBUGP("altering call id from 0x%04x to 0x%04x\n",
-		ntohs(*(u_int16_t *)pptpReq + cid_off), ntohs(new_callid));
+		ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_callid));
 
 	/* mangle packet */
 	if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
@@ -296,7 +299,8 @@
 		 union pptp_ctrl_union *pptpReq)
 {
 	struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
-	u_int16_t msg, new_cid = 0, new_pcid;
+	u_int16_t msg;
+	__be16 new_cid = 0, new_pcid;
 	unsigned int pcid_off, cid_off = 0;
 
 	new_pcid = htons(nat_pptp_info->pns_call_id);
@@ -342,7 +346,7 @@
 
 	/* mangle packet */
 	DEBUGP("altering peer call id from 0x%04x to 0x%04x\n",
-		ntohs(*(u_int16_t *)pptpReq + pcid_off), ntohs(new_pcid));
+		ntohs(REQ_CID(pptpReq, pcid_off)), ntohs(new_pcid));
 
 	if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
 	                             pcid_off + sizeof(struct pptp_pkt_hdr) +
@@ -353,7 +357,7 @@
 
 	if (new_cid) {
 		DEBUGP("altering call id from 0x%04x to 0x%04x\n",
-			ntohs(*(u_int16_t *)pptpReq + cid_off), ntohs(new_cid));
+			ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_cid));
 		if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
 		                             cid_off + sizeof(struct pptp_pkt_hdr) +
 					     sizeof(struct PptpControlHeader),
diff -urN oldtree/net/ipv4/netfilter/ip_nat_proto_gre.c newtree/net/ipv4/netfilter/ip_nat_proto_gre.c
--- oldtree/net/ipv4/netfilter/ip_nat_proto_gre.c	2006-02-19 11:41:06.360376176 +0000
+++ newtree/net/ipv4/netfilter/ip_nat_proto_gre.c	2006-02-21 15:58:37.147499280 +0000
@@ -49,7 +49,7 @@
 	     const union ip_conntrack_manip_proto *min,
 	     const union ip_conntrack_manip_proto *max)
 {
-	u_int32_t key;
+	__be32 key;
 
 	if (maniptype == IP_NAT_MANIP_SRC)
 		key = tuple->src.u.gre.key;
@@ -68,7 +68,7 @@
 		 const struct ip_conntrack *conntrack)
 {
 	static u_int16_t key;
-	u_int16_t *keyptr;
+	__be16 *keyptr;
 	unsigned int min, i, range_size;
 
 	if (maniptype == IP_NAT_MANIP_SRC)
diff -urN oldtree/net/ipv4/netfilter/ip_nat_proto_icmp.c newtree/net/ipv4/netfilter/ip_nat_proto_icmp.c
--- oldtree/net/ipv4/netfilter/ip_nat_proto_icmp.c	2006-02-19 11:41:06.360376176 +0000
+++ newtree/net/ipv4/netfilter/ip_nat_proto_icmp.c	2006-02-21 15:58:37.148499128 +0000
@@ -67,7 +67,7 @@
 
 	hdr = (struct icmphdr *)((*pskb)->data + hdroff);
 
-	hdr->checksum = ip_nat_cheat_check(hdr->un.echo.id ^ 0xFFFF,
+	hdr->checksum = ip_nat_cheat_check(hdr->un.echo.id ^ htons(0xFFFF),
 					    tuple->src.u.icmp.id,
 					    hdr->checksum);
 	hdr->un.echo.id = tuple->src.u.icmp.id;
diff -urN oldtree/net/ipv4/netfilter/ip_nat_proto_tcp.c newtree/net/ipv4/netfilter/ip_nat_proto_tcp.c
--- oldtree/net/ipv4/netfilter/ip_nat_proto_tcp.c	2006-02-19 11:41:06.361376024 +0000
+++ newtree/net/ipv4/netfilter/ip_nat_proto_tcp.c	2006-02-21 15:58:37.148499128 +0000
@@ -24,7 +24,7 @@
 	     const union ip_conntrack_manip_proto *min,
 	     const union ip_conntrack_manip_proto *max)
 {
-	u_int16_t port;
+	__be16 port;
 
 	if (maniptype == IP_NAT_MANIP_SRC)
 		port = tuple->src.u.tcp.port;
@@ -42,7 +42,7 @@
 		 const struct ip_conntrack *conntrack)
 {
 	static u_int16_t port;
-	u_int16_t *portptr;
+	__be16 *portptr;
 	unsigned int range_size, min, i;
 
 	if (maniptype == IP_NAT_MANIP_SRC)
@@ -93,8 +93,8 @@
 	struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
 	struct tcphdr *hdr;
 	unsigned int hdroff = iphdroff + iph->ihl*4;
-	u32 oldip, newip;
-	u16 *portptr, newport, oldport;
+	__be32 oldip, newip;
+	__be16 *portptr, newport, oldport;
 	int hdrsize = 8; /* TCP connection tracking guarantees this much */
 
 	/* this could be a inner header returned in icmp packet; in such
@@ -130,7 +130,7 @@
 		return 1;
 
 	hdr->check = ip_nat_cheat_check(~oldip, newip,
-					ip_nat_cheat_check(oldport ^ 0xFFFF,
+					ip_nat_cheat_check(oldport ^ htons(0xFFFF),
 							   newport,
 							   hdr->check));
 	return 1;
diff -urN oldtree/net/ipv4/netfilter/ip_nat_proto_udp.c newtree/net/ipv4/netfilter/ip_nat_proto_udp.c
--- oldtree/net/ipv4/netfilter/ip_nat_proto_udp.c	2006-02-19 11:41:06.361376024 +0000
+++ newtree/net/ipv4/netfilter/ip_nat_proto_udp.c	2006-02-21 15:58:37.148499128 +0000
@@ -24,7 +24,7 @@
 	     const union ip_conntrack_manip_proto *min,
 	     const union ip_conntrack_manip_proto *max)
 {
-	u_int16_t port;
+	__be16 port;
 
 	if (maniptype == IP_NAT_MANIP_SRC)
 		port = tuple->src.u.udp.port;
@@ -42,7 +42,7 @@
 		 const struct ip_conntrack *conntrack)
 {
 	static u_int16_t port;
-	u_int16_t *portptr;
+	__be16 *portptr;
 	unsigned int range_size, min, i;
 
 	if (maniptype == IP_NAT_MANIP_SRC)
@@ -91,8 +91,8 @@
 	struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
 	struct udphdr *hdr;
 	unsigned int hdroff = iphdroff + iph->ihl*4;
-	u32 oldip, newip;
-	u16 *portptr, newport;
+	__be32 oldip, newip;
+	__be16 *portptr, newport;
 
 	if (!skb_make_writable(pskb, hdroff + sizeof(*hdr)))
 		return 0;
@@ -115,7 +115,7 @@
 	}
 	if (hdr->check) /* 0 is a special case meaning no checksum */
 		hdr->check = ip_nat_cheat_check(~oldip, newip,
-					ip_nat_cheat_check(*portptr ^ 0xFFFF,
+					ip_nat_cheat_check(*portptr ^ htons(0xFFFF),
 							   newport,
 							   hdr->check));
 	*portptr = newport;
diff -urN oldtree/net/ipv4/netfilter/ip_nat_rule.c newtree/net/ipv4/netfilter/ip_nat_rule.c
--- oldtree/net/ipv4/netfilter/ip_nat_rule.c	2006-02-19 11:41:06.362375872 +0000
+++ newtree/net/ipv4/netfilter/ip_nat_rule.c	2006-02-21 15:58:37.149498976 +0000
@@ -103,6 +103,7 @@
 				    const struct net_device *in,
 				    const struct net_device *out,
 				    unsigned int hooknum,
+				    const struct ipt_target *target,
 				    const void *targinfo,
 				    void *userinfo)
 {
@@ -123,7 +124,7 @@
 }
 
 /* Before 2.6.11 we did implicit source NAT if required. Warn about change. */
-static void warn_if_extra_mangle(u32 dstip, u32 srcip)
+static void warn_if_extra_mangle(__be32 dstip, __be32 srcip)
 {
 	static int warned = 0;
 	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dstip } } };
@@ -145,6 +146,7 @@
 				    const struct net_device *in,
 				    const struct net_device *out,
 				    unsigned int hooknum,
+				    const struct ipt_target *target,
 				    const void *targinfo,
 				    void *userinfo)
 {
@@ -170,6 +172,7 @@
 
 static int ipt_snat_checkentry(const char *tablename,
 			       const void *entry,
+			       const struct ipt_target *target,
 			       void *targinfo,
 			       unsigned int targinfosize,
 			       unsigned int hook_mask)
@@ -181,28 +184,12 @@
 		printk("SNAT: multiple ranges no longer supported\n");
 		return 0;
 	}
-
-	if (targinfosize != IPT_ALIGN(sizeof(struct ip_nat_multi_range_compat))) {
-		DEBUGP("SNAT: Target size %u wrong for %u ranges\n",
-		       targinfosize, mr->rangesize);
-		return 0;
-	}
-
-	/* Only allow these for NAT. */
-	if (strcmp(tablename, "nat") != 0) {
-		DEBUGP("SNAT: wrong table %s\n", tablename);
-		return 0;
-	}
-
-	if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) {
-		DEBUGP("SNAT: hook mask 0x%x bad\n", hook_mask);
-		return 0;
-	}
 	return 1;
 }
 
 static int ipt_dnat_checkentry(const char *tablename,
 			       const void *entry,
+			       const struct ipt_target *target,
 			       void *targinfo,
 			       unsigned int targinfosize,
 			       unsigned int hook_mask)
@@ -214,24 +201,6 @@
 		printk("DNAT: multiple ranges no longer supported\n");
 		return 0;
 	}
-
-	if (targinfosize != IPT_ALIGN(sizeof(struct ip_nat_multi_range_compat))) {
-		DEBUGP("DNAT: Target size %u wrong for %u ranges\n",
-		       targinfosize, mr->rangesize);
-		return 0;
-	}
-
-	/* Only allow these for NAT. */
-	if (strcmp(tablename, "nat") != 0) {
-		DEBUGP("DNAT: wrong table %s\n", tablename);
-		return 0;
-	}
-
-	if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))) {
-		DEBUGP("DNAT: hook mask 0x%x bad\n", hook_mask);
-		return 0;
-	}
-	
 	return 1;
 }
 
@@ -244,7 +213,7 @@
 	   per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
 	   Use reply in case it's already been mangled (eg local packet).
 	*/
-	u_int32_t ip
+	__be32 ip
 		= (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
 		   ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip
 		   : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip);
@@ -261,7 +230,7 @@
                              struct ip_nat_info *info,
                              unsigned int hooknum)
 {
-	u_int32_t ip
+	__be32 ip
 		= (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
 		   ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip
 		   : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip);
@@ -299,12 +268,18 @@
 static struct ipt_target ipt_snat_reg = {
 	.name		= "SNAT",
 	.target		= ipt_snat_target,
+	.targetsize	= sizeof(struct ip_nat_multi_range_compat),
+	.table		= "nat",
+	.hooks		= 1 << NF_IP_POST_ROUTING,
 	.checkentry	= ipt_snat_checkentry,
 };
 
 static struct ipt_target ipt_dnat_reg = {
 	.name		= "DNAT",
 	.target		= ipt_dnat_target,
+	.targetsize	= sizeof(struct ip_nat_multi_range_compat),
+	.table		= "nat",
+	.hooks		= 1 << NF_IP_PRE_ROUTING,
 	.checkentry	= ipt_dnat_checkentry,
 };
 
diff -urN oldtree/net/ipv4/netfilter/ip_nat_snmp_basic.c newtree/net/ipv4/netfilter/ip_nat_snmp_basic.c
--- oldtree/net/ipv4/netfilter/ip_nat_snmp_basic.c	2006-02-19 11:41:06.363375720 +0000
+++ newtree/net/ipv4/netfilter/ip_nat_snmp_basic.c	2006-02-21 15:58:37.150498824 +0000
@@ -1209,7 +1209,7 @@
                           struct sk_buff **pskb)
 {
 	struct iphdr *iph = (*pskb)->nh.iph;
-	struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl);
+	struct udphdr *udph = (struct udphdr *)((__be32 *)iph + iph->ihl);
 	u_int16_t udplen = ntohs(udph->len);
 	u_int16_t paylen = udplen - sizeof(struct udphdr);
 	int dir = CTINFO2DIR(ctinfo);
diff -urN oldtree/net/ipv4/netfilter/ip_queue.c newtree/net/ipv4/netfilter/ip_queue.c
--- oldtree/net/ipv4/netfilter/ip_queue.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/ipv4/netfilter/ip_queue.c	2006-02-21 15:58:16.641616648 +0000
@@ -35,6 +35,7 @@
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
 #include <linux/security.h>
+#include <linux/mutex.h>
 #include <net/sock.h>
 #include <net/route.h>
 
@@ -61,7 +62,7 @@
 static unsigned int queue_user_dropped = 0;
 static struct sock *ipqnl;
 static LIST_HEAD(queue_list);
-static DECLARE_MUTEX(ipqnl_sem);
+static DEFINE_MUTEX(ipqnl_mutex);
 
 static void
 ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict)
@@ -539,7 +540,7 @@
 	struct sk_buff *skb;
 	unsigned int qlen;
 
-	down(&ipqnl_sem);
+	mutex_lock(&ipqnl_mutex);
 			
 	for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) {
 		skb = skb_dequeue(&sk->sk_receive_queue);
@@ -547,7 +548,7 @@
 		kfree_skb(skb);
 	}
 		
-	up(&ipqnl_sem);
+	mutex_unlock(&ipqnl_mutex);
 }
 
 static int
@@ -708,8 +709,8 @@
 	
 cleanup_ipqnl:
 	sock_release(ipqnl->sk_socket);
-	down(&ipqnl_sem);
-	up(&ipqnl_sem);
+	mutex_lock(&ipqnl_mutex);
+	mutex_unlock(&ipqnl_mutex);
 	
 cleanup_netlink_notifier:
 	netlink_unregister_notifier(&ipq_nl_notifier);
diff -urN oldtree/net/ipv4/netfilter/ip_tables.c newtree/net/ipv4/netfilter/ip_tables.c
--- oldtree/net/ipv4/netfilter/ip_tables.c	2006-02-19 11:41:06.367375112 +0000
+++ newtree/net/ipv4/netfilter/ip_tables.c	2006-02-21 15:58:16.818589744 +0000
@@ -25,7 +25,7 @@
 #include <linux/icmp.h>
 #include <net/ip.h>
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <linux/proc_fs.h>
 #include <linux/err.h>
 #include <linux/cpumask.h>
@@ -179,6 +179,7 @@
 	  const struct net_device *in,
 	  const struct net_device *out,
 	  unsigned int hooknum,
+	  const struct xt_target *target,
 	  const void *targinfo,
 	  void *userinfo)
 {
@@ -197,8 +198,8 @@
 	     int *hotdrop)
 {
 	/* Stop iteration if it doesn't match */
-	if (!m->u.kernel.match->match(skb, in, out, m->data, offset, 
-	    skb->nh.iph->ihl*4, hotdrop))
+	if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
+				      offset, skb->nh.iph->ihl*4, hotdrop))
 		return 1;
 	else
 		return 0;
@@ -305,6 +306,7 @@
 				verdict = t->u.kernel.target->target(pskb,
 								     in, out,
 								     hook,
+								     t->u.kernel.target,
 								     t->data,
 								     userdata);
 
@@ -464,7 +466,7 @@
 		return 1;
 
 	if (m->u.kernel.match->destroy)
-		m->u.kernel.match->destroy(m->data,
+		m->u.kernel.match->destroy(m->u.kernel.match, m->data,
 					   m->u.match_size - sizeof(*m));
 	module_put(m->u.kernel.match->me);
 	return 0;
@@ -477,21 +479,12 @@
 	struct ipt_standard_target *targ = (void *)t;
 
 	/* Check standard info. */
-	if (t->u.target_size
-	    != IPT_ALIGN(sizeof(struct ipt_standard_target))) {
-		duprintf("standard_check: target size %u != %u\n",
-			 t->u.target_size,
-			 IPT_ALIGN(sizeof(struct ipt_standard_target)));
-		return 0;
-	}
-
 	if (targ->verdict >= 0
 	    && targ->verdict > max_offset - sizeof(struct ipt_entry)) {
 		duprintf("ipt_standard_check: bad verdict (%i)\n",
 			 targ->verdict);
 		return 0;
 	}
-
 	if (targ->verdict < -NF_MAX_VERDICT - 1) {
 		duprintf("ipt_standard_check: bad negative verdict (%i)\n",
 			 targ->verdict);
@@ -508,6 +501,7 @@
 	    unsigned int *i)
 {
 	struct ipt_match *match;
+	int ret;
 
 	match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
 						   m->u.user.revision),
@@ -518,18 +512,27 @@
 	}
 	m->u.kernel.match = match;
 
+	ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m),
+			     name, hookmask, ip->proto,
+			     ip->invflags & IPT_INV_PROTO);
+	if (ret)
+		goto err;
+
 	if (m->u.kernel.match->checkentry
-	    && !m->u.kernel.match->checkentry(name, ip, m->data,
+	    && !m->u.kernel.match->checkentry(name, ip, match, m->data,
 					      m->u.match_size - sizeof(*m),
 					      hookmask)) {
-		module_put(m->u.kernel.match->me);
 		duprintf("ip_tables: check failed for `%s'.\n",
 			 m->u.kernel.match->name);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err;
 	}
 
 	(*i)++;
 	return 0;
+err:
+	module_put(m->u.kernel.match->me);
+	return ret;
 }
 
 static struct ipt_target ipt_standard_target;
@@ -565,26 +568,32 @@
 	}
 	t->u.kernel.target = target;
 
+	ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
+			      name, e->comefrom, e->ip.proto,
+			      e->ip.invflags & IPT_INV_PROTO);
+	if (ret)
+		goto err;
+
 	if (t->u.kernel.target == &ipt_standard_target) {
 		if (!standard_check(t, size)) {
 			ret = -EINVAL;
 			goto cleanup_matches;
 		}
 	} else if (t->u.kernel.target->checkentry
-		   && !t->u.kernel.target->checkentry(name, e, t->data,
+		   && !t->u.kernel.target->checkentry(name, e, target, t->data,
 						      t->u.target_size
 						      - sizeof(*t),
 						      e->comefrom)) {
-		module_put(t->u.kernel.target->me);
 		duprintf("ip_tables: check failed for `%s'.\n",
 			 t->u.kernel.target->name);
 		ret = -EINVAL;
-		goto cleanup_matches;
+		goto err;
 	}
 
 	(*i)++;
 	return 0;
-
+ err:
+	module_put(t->u.kernel.target->me);
  cleanup_matches:
 	IPT_MATCH_ITERATE(e, cleanup_match, &j);
 	return ret;
@@ -645,7 +654,7 @@
 	IPT_MATCH_ITERATE(e, cleanup_match, NULL);
 	t = ipt_get_target(e);
 	if (t->u.kernel.target->destroy)
-		t->u.kernel.target->destroy(t->data,
+		t->u.kernel.target->destroy(t->u.kernel.target, t->data,
 					    t->u.target_size - sizeof(*t));
 	module_put(t->u.kernel.target->me);
 	return 0;
@@ -1277,6 +1286,7 @@
 icmp_match(const struct sk_buff *skb,
 	   const struct net_device *in,
 	   const struct net_device *out,
+	   const struct xt_match *match,
 	   const void *matchinfo,
 	   int offset,
 	   unsigned int protoff,
@@ -1310,28 +1320,27 @@
 static int
 icmp_checkentry(const char *tablename,
 	   const void *info,
+	   const struct xt_match *match,
 	   void *matchinfo,
 	   unsigned int matchsize,
 	   unsigned int hook_mask)
 {
-	const struct ipt_ip *ip = info;
 	const struct ipt_icmp *icmpinfo = matchinfo;
 
-	/* Must specify proto == ICMP, and no unknown invflags */
-	return ip->proto == IPPROTO_ICMP
-		&& !(ip->invflags & IPT_INV_PROTO)
-		&& matchsize == IPT_ALIGN(sizeof(struct ipt_icmp))
-		&& !(icmpinfo->invflags & ~IPT_ICMP_INV);
+	/* Must specify no unknown invflags */
+	return !(icmpinfo->invflags & ~IPT_ICMP_INV);
 }
 
 /* The built-in targets: standard (NULL) and error. */
 static struct ipt_target ipt_standard_target = {
 	.name		= IPT_STANDARD_TARGET,
+	.targetsize	= sizeof(int),
 };
 
 static struct ipt_target ipt_error_target = {
 	.name		= IPT_ERROR_TARGET,
 	.target		= ipt_error,
+	.targetsize	= IPT_FUNCTION_MAXNAMELEN,
 };
 
 static struct nf_sockopt_ops ipt_sockopts = {
@@ -1346,8 +1355,10 @@
 
 static struct ipt_match icmp_matchstruct = {
 	.name		= "icmp",
-	.match		= &icmp_match,
-	.checkentry	= &icmp_checkentry,
+	.match		= icmp_match,
+	.matchsize	= sizeof(struct ipt_icmp),
+	.proto		= IPPROTO_ICMP,
+	.checkentry	= icmp_checkentry,
 };
 
 static int __init init(void)
diff -urN oldtree/net/ipv4/netfilter/ipt_CLUSTERIP.c newtree/net/ipv4/netfilter/ipt_CLUSTERIP.c
--- oldtree/net/ipv4/netfilter/ipt_CLUSTERIP.c	2006-02-19 11:41:06.369374808 +0000
+++ newtree/net/ipv4/netfilter/ipt_CLUSTERIP.c	2006-02-21 15:58:37.152498520 +0000
@@ -53,7 +53,7 @@
 	atomic_t entries;			/* number of entries/rules
 						 * referencing us */
 
-	u_int32_t clusterip;			/* the IP address */
+	__be32 clusterip;			/* the IP address */
 	u_int8_t clustermac[ETH_ALEN];		/* the MAC address */
 	struct net_device *dev;			/* device */
 	u_int16_t num_total_nodes;		/* total number of nodes */
@@ -120,7 +120,7 @@
 }
 
 static struct clusterip_config *
-__clusterip_config_find(u_int32_t clusterip)
+__clusterip_config_find(__be32 clusterip)
 {
 	struct list_head *pos;
 
@@ -137,7 +137,7 @@
 }
 
 static inline struct clusterip_config *
-clusterip_config_find_get(u_int32_t clusterip, int entry)
+clusterip_config_find_get(__be32 clusterip, int entry)
 {
 	struct clusterip_config *c;
 
@@ -167,7 +167,7 @@
 }
 
 static struct clusterip_config *
-clusterip_config_init(struct ipt_clusterip_tgt_info *i, u_int32_t ip,
+clusterip_config_init(struct ipt_clusterip_tgt_info *i, __be32 ip,
 			struct net_device *dev)
 {
 	struct clusterip_config *c;
@@ -311,6 +311,7 @@
        const struct net_device *in,
        const struct net_device *out,
        unsigned int hooknum,
+       const struct xt_target *target,
        const void *targinfo,
        void *userinfo)
 {
@@ -380,6 +381,7 @@
 static int
 checkentry(const char *tablename,
 	   const void *e_void,
+	   const struct xt_target *target,
            void *targinfo,
            unsigned int targinfosize,
            unsigned int hook_mask)
@@ -389,13 +391,6 @@
 
 	struct clusterip_config *config;
 
-	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_clusterip_tgt_info))) {
-		printk(KERN_WARNING "CLUSTERIP: targinfosize %u != %Zu\n",
-		       targinfosize,
-		       IPT_ALIGN(sizeof(struct ipt_clusterip_tgt_info)));
-		return 0;
-	}
-
 	if (cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP &&
 	    cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT &&
 	    cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT_DPT) {
@@ -404,7 +399,7 @@
 		return 0;
 
 	}
-	if (e->ip.dmsk.s_addr != 0xffffffff
+	if (e->ip.dmsk.s_addr != htonl(0xffffffff)
 	    || e->ip.dst.s_addr == 0) {
 		printk(KERN_ERR "CLUSTERIP: Please specify destination IP\n");
 		return 0;
@@ -465,9 +460,10 @@
 }
 
 /* drop reference count of cluster config when rule is deleted */
-static void destroy(void *matchinfo, unsigned int matchinfosize)
+static void destroy(const struct xt_target *target, void *targinfo,
+		    unsigned int targinfosize)
 {
-	struct ipt_clusterip_tgt_info *cipinfo = matchinfo;
+	struct ipt_clusterip_tgt_info *cipinfo = targinfo;
 
 	/* if no more entries are referencing the config, remove it
 	 * from the list and destroy the proc entry */
@@ -476,12 +472,13 @@
 	clusterip_config_put(cipinfo->config);
 }
 
-static struct ipt_target clusterip_tgt = { 
-	.name = "CLUSTERIP",
-	.target = &target, 
-	.checkentry = &checkentry, 
-	.destroy = &destroy,
-	.me = THIS_MODULE
+static struct ipt_target clusterip_tgt = {
+	.name		= "CLUSTERIP",
+	.target		= target,
+	.targetsize	= sizeof(struct ipt_clusterip_tgt_info),
+	.checkentry	= checkentry,
+	.destroy	= destroy,
+	.me		= THIS_MODULE
 };
 
 
@@ -492,9 +489,9 @@
 /* hardcoded for 48bit ethernet and 32bit ipv4 addresses */
 struct arp_payload {
 	u_int8_t src_hw[ETH_ALEN];
-	u_int32_t src_ip;
+	__be32 src_ip;
 	u_int8_t dst_hw[ETH_ALEN];
-	u_int32_t dst_ip;
+	__be32 dst_ip;
 } __attribute__ ((packed));
 
 #ifdef CLUSTERIP_DEBUG
diff -urN oldtree/net/ipv4/netfilter/ipt_DSCP.c newtree/net/ipv4/netfilter/ipt_DSCP.c
--- oldtree/net/ipv4/netfilter/ipt_DSCP.c	2006-02-19 11:41:06.370374656 +0000
+++ newtree/net/ipv4/netfilter/ipt_DSCP.c	2006-02-21 15:58:37.152498520 +0000
@@ -29,6 +29,7 @@
        const struct net_device *in,
        const struct net_device *out,
        unsigned int hooknum,
+       const struct xt_target *target,
        const void *targinfo,
        void *userinfo)
 {
@@ -37,12 +38,12 @@
 
 
 	if (((*pskb)->nh.iph->tos & IPT_DSCP_MASK) != sh_dscp) {
-		u_int16_t diffs[2];
+		__be16 diffs[2];
 
 		if (!skb_make_writable(pskb, sizeof(struct iphdr)))
 			return NF_DROP;
 
-		diffs[0] = htons((*pskb)->nh.iph->tos) ^ 0xFFFF;
+		diffs[0] = htons((*pskb)->nh.iph->tos) ^ htons(0xFFFF);
 		(*pskb)->nh.iph->tos = ((*pskb)->nh.iph->tos & ~IPT_DSCP_MASK)
 			| sh_dscp;
 		diffs[1] = htons((*pskb)->nh.iph->tos);
@@ -50,7 +51,7 @@
 			= csum_fold(csum_partial((char *)diffs,
 						 sizeof(diffs),
 						 (*pskb)->nh.iph->check
-						 ^ 0xFFFF));
+						 ^ htons(0xFFFF)));
 	}
 	return IPT_CONTINUE;
 }
@@ -58,35 +59,25 @@
 static int
 checkentry(const char *tablename,
 	   const void *e_void,
+	   const struct xt_target *target,
            void *targinfo,
            unsigned int targinfosize,
            unsigned int hook_mask)
 {
 	const u_int8_t dscp = ((struct ipt_DSCP_info *)targinfo)->dscp;
 
-	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_DSCP_info))) {
-		printk(KERN_WARNING "DSCP: targinfosize %u != %Zu\n",
-		       targinfosize,
-		       IPT_ALIGN(sizeof(struct ipt_DSCP_info)));
-		return 0;
-	}
-
-	if (strcmp(tablename, "mangle") != 0) {
-		printk(KERN_WARNING "DSCP: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
-		return 0;
-	}
-
 	if ((dscp > IPT_DSCP_MAX)) {
 		printk(KERN_WARNING "DSCP: dscp %x out of range\n", dscp);
 		return 0;
 	}
-
 	return 1;
 }
 
 static struct ipt_target ipt_dscp_reg = {
 	.name		= "DSCP",
 	.target		= target,
+	.targetsize	= sizeof(struct ipt_DSCP_info),
+	.table		= "mangle",
 	.checkentry	= checkentry,
 	.me		= THIS_MODULE,
 };
diff -urN oldtree/net/ipv4/netfilter/ipt_ECN.c newtree/net/ipv4/netfilter/ipt_ECN.c
--- oldtree/net/ipv4/netfilter/ipt_ECN.c	2006-02-19 11:41:06.371374504 +0000
+++ newtree/net/ipv4/netfilter/ipt_ECN.c	2006-02-21 15:58:37.152498520 +0000
@@ -29,12 +29,12 @@
 {
 	if (((*pskb)->nh.iph->tos & IPT_ECN_IP_MASK)
 	    != (einfo->ip_ect & IPT_ECN_IP_MASK)) {
-		u_int16_t diffs[2];
+		__be16 diffs[2];
 
 		if (!skb_make_writable(pskb, sizeof(struct iphdr)))
 			return 0;
 
-		diffs[0] = htons((*pskb)->nh.iph->tos) ^ 0xFFFF;
+		diffs[0] = htons((*pskb)->nh.iph->tos) ^ htons(0xFFFF);
 		(*pskb)->nh.iph->tos &= ~IPT_ECN_IP_MASK;
 		(*pskb)->nh.iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK);
 		diffs[1] = htons((*pskb)->nh.iph->tos);
@@ -42,7 +42,7 @@
 			= csum_fold(csum_partial((char *)diffs,
 						 sizeof(diffs),
 						 (*pskb)->nh.iph->check
-						 ^0xFFFF));
+						 ^htons(0xFFFF)));
 	} 
 	return 1;
 }
@@ -52,7 +52,7 @@
 set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo, int inward)
 {
 	struct tcphdr _tcph, *tcph;
-	u_int16_t diffs[2];
+	__be16 diffs[2];
 
 	/* Not enought header? */
 	tcph = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
@@ -80,12 +80,12 @@
 	if (einfo->operation & IPT_ECN_OP_SET_CWR)
 		tcph->cwr = einfo->proto.tcp.cwr;
 	diffs[1] = ((u_int16_t *)tcph)[6];
-	diffs[0] = diffs[0] ^ 0xFFFF;
+	diffs[0] = diffs[0] ^ htons(0xFFFF);
 
 	if ((*pskb)->ip_summed != CHECKSUM_UNNECESSARY)
 		tcph->check = csum_fold(csum_partial((char *)diffs,
 						     sizeof(diffs),
-						     tcph->check^0xFFFF));
+						     tcph->check^htons(0xFFFF)));
 	return 1;
 }
 
@@ -94,6 +94,7 @@
        const struct net_device *in,
        const struct net_device *out,
        unsigned int hooknum,
+       const struct xt_target *target,
        const void *targinfo,
        void *userinfo)
 {
@@ -114,6 +115,7 @@
 static int
 checkentry(const char *tablename,
 	   const void *e_void,
+	   const struct xt_target *target,
            void *targinfo,
            unsigned int targinfosize,
            unsigned int hook_mask)
@@ -121,18 +123,6 @@
 	const struct ipt_ECN_info *einfo = (struct ipt_ECN_info *)targinfo;
 	const struct ipt_entry *e = e_void;
 
-	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ECN_info))) {
-		printk(KERN_WARNING "ECN: targinfosize %u != %Zu\n",
-		       targinfosize,
-		       IPT_ALIGN(sizeof(struct ipt_ECN_info)));
-		return 0;
-	}
-
-	if (strcmp(tablename, "mangle") != 0) {
-		printk(KERN_WARNING "ECN: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
-		return 0;
-	}
-
 	if (einfo->operation & IPT_ECN_OP_MASK) {
 		printk(KERN_WARNING "ECN: unsupported ECN operation %x\n",
 			einfo->operation);
@@ -143,20 +133,20 @@
 			einfo->ip_ect);
 		return 0;
 	}
-
 	if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR))
 	    && (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & IPT_INV_PROTO))) {
 		printk(KERN_WARNING "ECN: cannot use TCP operations on a "
 		       "non-tcp rule\n");
 		return 0;
 	}
-
 	return 1;
 }
 
 static struct ipt_target ipt_ecn_reg = {
 	.name		= "ECN",
 	.target		= target,
+	.targetsize	= sizeof(struct ipt_ECN_info),
+	.table		= "mangle",
 	.checkentry	= checkentry,
 	.me		= THIS_MODULE,
 };
diff -urN oldtree/net/ipv4/netfilter/ipt_LOG.c newtree/net/ipv4/netfilter/ipt_LOG.c
--- oldtree/net/ipv4/netfilter/ipt_LOG.c	2006-02-19 11:41:06.371374504 +0000
+++ newtree/net/ipv4/netfilter/ipt_LOG.c	2006-02-21 15:58:16.386655408 +0000
@@ -415,6 +415,7 @@
 	       const struct net_device *in,
 	       const struct net_device *out,
 	       unsigned int hooknum,
+	       const struct xt_target *target,
 	       const void *targinfo,
 	       void *userinfo)
 {
@@ -432,35 +433,29 @@
 
 static int ipt_log_checkentry(const char *tablename,
 			      const void *e,
+			      const struct xt_target *target,
 			      void *targinfo,
 			      unsigned int targinfosize,
 			      unsigned int hook_mask)
 {
 	const struct ipt_log_info *loginfo = targinfo;
 
-	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_log_info))) {
-		DEBUGP("LOG: targinfosize %u != %u\n",
-		       targinfosize, IPT_ALIGN(sizeof(struct ipt_log_info)));
-		return 0;
-	}
-
 	if (loginfo->level >= 8) {
 		DEBUGP("LOG: level %u >= 8\n", loginfo->level);
 		return 0;
 	}
-
 	if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
 		DEBUGP("LOG: prefix term %i\n",
 		       loginfo->prefix[sizeof(loginfo->prefix)-1]);
 		return 0;
 	}
-
 	return 1;
 }
 
 static struct ipt_target ipt_log_reg = {
 	.name		= "LOG",
 	.target		= ipt_log_target,
+	.targetsize	= sizeof(struct ipt_log_info),
 	.checkentry	= ipt_log_checkentry,
 	.me		= THIS_MODULE,
 };
diff -urN oldtree/net/ipv4/netfilter/ipt_MASQUERADE.c newtree/net/ipv4/netfilter/ipt_MASQUERADE.c
--- oldtree/net/ipv4/netfilter/ipt_MASQUERADE.c	2006-02-19 11:41:06.372374352 +0000
+++ newtree/net/ipv4/netfilter/ipt_MASQUERADE.c	2006-02-21 15:58:37.153498368 +0000
@@ -41,25 +41,13 @@
 static int
 masquerade_check(const char *tablename,
 		 const void *e,
+		 const struct xt_target *target,
 		 void *targinfo,
 		 unsigned int targinfosize,
 		 unsigned int hook_mask)
 {
 	const struct ip_nat_multi_range_compat *mr = targinfo;
 
-	if (strcmp(tablename, "nat") != 0) {
-		DEBUGP("masquerade_check: bad table `%s'.\n", tablename);
-		return 0;
-	}
-	if (targinfosize != IPT_ALIGN(sizeof(*mr))) {
-		DEBUGP("masquerade_check: size %u != %u.\n",
-		       targinfosize, sizeof(*mr));
-		return 0;
-	}
-	if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) {
-		DEBUGP("masquerade_check: bad hooks %x.\n", hook_mask);
-		return 0;
-	}
 	if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
 		DEBUGP("masquerade_check: bad MAP_IPS.\n");
 		return 0;
@@ -76,6 +64,7 @@
 		  const struct net_device *in,
 		  const struct net_device *out,
 		  unsigned int hooknum,
+		  const struct xt_target *target,
 		  const void *targinfo,
 		  void *userinfo)
 {
@@ -84,7 +73,7 @@
 	const struct ip_nat_multi_range_compat *mr;
 	struct ip_nat_range newrange;
 	struct rtable *rt;
-	u_int32_t newsrc;
+	__be32 newsrc;
 
 	IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
 
@@ -179,6 +168,9 @@
 static struct ipt_target masquerade = {
 	.name		= "MASQUERADE",
 	.target		= masquerade_target,
+	.targetsize	= sizeof(struct ip_nat_multi_range_compat),
+	.table		= "nat",
+	.hooks		= 1 << NF_IP_POST_ROUTING,
 	.checkentry	= masquerade_check,
 	.me		= THIS_MODULE,
 };
diff -urN oldtree/net/ipv4/netfilter/ipt_NETMAP.c newtree/net/ipv4/netfilter/ipt_NETMAP.c
--- oldtree/net/ipv4/netfilter/ipt_NETMAP.c	2006-02-19 11:41:06.372374352 +0000
+++ newtree/net/ipv4/netfilter/ipt_NETMAP.c	2006-02-21 15:58:37.154498216 +0000
@@ -32,25 +32,13 @@
 static int
 check(const char *tablename,
       const void *e,
+      const struct xt_target *target,
       void *targinfo,
       unsigned int targinfosize,
       unsigned int hook_mask)
 {
 	const struct ip_nat_multi_range_compat *mr = targinfo;
 
-	if (strcmp(tablename, "nat") != 0) {
-		DEBUGP(MODULENAME":check: bad table `%s'.\n", tablename);
-		return 0;
-	}
-	if (targinfosize != IPT_ALIGN(sizeof(*mr))) {
-		DEBUGP(MODULENAME":check: size %u.\n", targinfosize);
-		return 0;
-	}
-	if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING) |
-	                  (1 << NF_IP_LOCAL_OUT))) {
-		DEBUGP(MODULENAME":check: bad hooks %x.\n", hook_mask);
-		return 0;
-	}
 	if (!(mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)) {
 		DEBUGP(MODULENAME":check: bad MAP_IPS.\n");
 		return 0;
@@ -67,12 +55,13 @@
        const struct net_device *in,
        const struct net_device *out,
        unsigned int hooknum,
+       const struct xt_target *target,
        const void *targinfo,
        void *userinfo)
 {
 	struct ip_conntrack *ct;
 	enum ip_conntrack_info ctinfo;
-	u_int32_t new_ip, netmask;
+	__be32 new_ip, netmask;
 	const struct ip_nat_multi_range_compat *mr = targinfo;
 	struct ip_nat_range newrange;
 
@@ -101,6 +90,10 @@
 static struct ipt_target target_module = { 
 	.name 		= MODULENAME,
 	.target 	= target, 
+	.targetsize	= sizeof(struct ip_nat_multi_range_compat),
+	.table		= "nat",
+	.hooks		= (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING) |
+			  (1 << NF_IP_LOCAL_OUT),
 	.checkentry 	= check,
     	.me 		= THIS_MODULE 
 };
diff -urN oldtree/net/ipv4/netfilter/ipt_REDIRECT.c newtree/net/ipv4/netfilter/ipt_REDIRECT.c
--- oldtree/net/ipv4/netfilter/ipt_REDIRECT.c	2006-02-19 11:41:06.373374200 +0000
+++ newtree/net/ipv4/netfilter/ipt_REDIRECT.c	2006-02-21 15:58:37.155498064 +0000
@@ -34,24 +34,13 @@
 static int
 redirect_check(const char *tablename,
 	       const void *e,
+	       const struct xt_target *target,
 	       void *targinfo,
 	       unsigned int targinfosize,
 	       unsigned int hook_mask)
 {
 	const struct ip_nat_multi_range_compat *mr = targinfo;
 
-	if (strcmp(tablename, "nat") != 0) {
-		DEBUGP("redirect_check: bad table `%s'.\n", table);
-		return 0;
-	}
-	if (targinfosize != IPT_ALIGN(sizeof(*mr))) {
-		DEBUGP("redirect_check: size %u.\n", targinfosize);
-		return 0;
-	}
-	if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))) {
-		DEBUGP("redirect_check: bad hooks %x.\n", hook_mask);
-		return 0;
-	}
 	if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
 		DEBUGP("redirect_check: bad MAP_IPS.\n");
 		return 0;
@@ -68,12 +57,13 @@
 		const struct net_device *in,
 		const struct net_device *out,
 		unsigned int hooknum,
+		const struct xt_target *target,
 		const void *targinfo,
 		void *userinfo)
 {
 	struct ip_conntrack *ct;
 	enum ip_conntrack_info ctinfo;
-	u_int32_t newdst;
+	__be32 newdst;
 	const struct ip_nat_multi_range_compat *mr = targinfo;
 	struct ip_nat_range newrange;
 
@@ -115,6 +105,9 @@
 static struct ipt_target redirect_reg = {
 	.name		= "REDIRECT",
 	.target		= redirect_target,
+	.targetsize	= sizeof(struct ip_nat_multi_range_compat),
+	.table		= "nat",
+	.hooks		= (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT),
 	.checkentry	= redirect_check,
 	.me		= THIS_MODULE,
 };
diff -urN oldtree/net/ipv4/netfilter/ipt_REJECT.c newtree/net/ipv4/netfilter/ipt_REJECT.c
--- oldtree/net/ipv4/netfilter/ipt_REJECT.c	2006-02-19 11:41:06.374374048 +0000
+++ newtree/net/ipv4/netfilter/ipt_REJECT.c	2006-02-21 15:58:37.155498064 +0000
@@ -104,8 +104,8 @@
 	struct iphdr *iph = oldskb->nh.iph;
 	struct tcphdr _otcph, *oth, *tcph;
 	struct rtable *rt;
-	u_int16_t tmp_port;
-	u_int32_t tmp_addr;
+	__be16 tmp_port;
+	__be32 tmp_addr;
 	unsigned int tcplen;
 	int needs_ack;
 	int hh_len;
@@ -236,6 +236,7 @@
 			   const struct net_device *in,
 			   const struct net_device *out,
 			   unsigned int hooknum,
+			   const struct xt_target *target,
 			   const void *targinfo,
 			   void *userinfo)
 {
@@ -283,6 +284,7 @@
 
 static int check(const char *tablename,
 		 const void *e_void,
+		 const struct xt_target *target,
 		 void *targinfo,
 		 unsigned int targinfosize,
 		 unsigned int hook_mask)
@@ -290,23 +292,6 @@
  	const struct ipt_reject_info *rejinfo = targinfo;
 	const struct ipt_entry *e = e_void;
 
- 	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_reject_info))) {
-  		DEBUGP("REJECT: targinfosize %u != 0\n", targinfosize);
-  		return 0;
-  	}
-
-	/* Only allow these for packet filtering. */
-	if (strcmp(tablename, "filter") != 0) {
-		DEBUGP("REJECT: bad table `%s'.\n", tablename);
-		return 0;
-	}
-	if ((hook_mask & ~((1 << NF_IP_LOCAL_IN)
-			   | (1 << NF_IP_FORWARD)
-			   | (1 << NF_IP_LOCAL_OUT))) != 0) {
-		DEBUGP("REJECT: bad hook mask %X\n", hook_mask);
-		return 0;
-	}
-
 	if (rejinfo->with == IPT_ICMP_ECHOREPLY) {
 		printk("REJECT: ECHOREPLY no longer supported.\n");
 		return 0;
@@ -318,13 +303,16 @@
 			return 0;
 		}
 	}
-
 	return 1;
 }
 
 static struct ipt_target ipt_reject_reg = {
 	.name		= "REJECT",
 	.target		= reject,
+	.targetsize	= sizeof(struct ipt_reject_info),
+	.table		= "filter",
+	.hooks		= (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) |
+			  (1 << NF_IP_LOCAL_OUT),
 	.checkentry	= check,
 	.me		= THIS_MODULE,
 };
diff -urN oldtree/net/ipv4/netfilter/ipt_SAME.c newtree/net/ipv4/netfilter/ipt_SAME.c
--- oldtree/net/ipv4/netfilter/ipt_SAME.c	2006-02-19 11:41:06.374374048 +0000
+++ newtree/net/ipv4/netfilter/ipt_SAME.c	2006-02-21 15:58:37.156497912 +0000
@@ -50,6 +50,7 @@
 static int
 same_check(const char *tablename,
 	      const void *e,
+	      const struct xt_target *target,
 	      void *targinfo,
 	      unsigned int targinfosize,
 	      unsigned int hook_mask)
@@ -59,18 +60,6 @@
 
 	mr->ipnum = 0;
 
-	if (strcmp(tablename, "nat") != 0) {
-		DEBUGP("same_check: bad table `%s'.\n", tablename);
-		return 0;
-	}
-	if (targinfosize != IPT_ALIGN(sizeof(*mr))) {
-		DEBUGP("same_check: size %u.\n", targinfosize);
-		return 0;
-	}
-	if (hook_mask & ~(1 << NF_IP_PRE_ROUTING | 1 << NF_IP_POST_ROUTING)) {
-		DEBUGP("same_check: bad hooks %x.\n", hook_mask);
-		return 0;
-	}
 	if (mr->rangesize < 1) {
 		DEBUGP("same_check: need at least one dest range.\n");
 		return 0;
@@ -127,7 +116,7 @@
 }
 
 static void 
-same_destroy(void *targinfo,
+same_destroy(const struct xt_target *target, void *targinfo,
 		unsigned int targinfosize)
 {
 	struct ipt_same_info *mr = targinfo;
@@ -143,12 +132,14 @@
 		const struct net_device *in,
 		const struct net_device *out,
 		unsigned int hooknum,
+		const struct xt_target *target,
 		const void *targinfo,
 		void *userinfo)
 {
 	struct ip_conntrack *ct;
 	enum ip_conntrack_info ctinfo;
-	u_int32_t tmpip, aindex, new_ip;
+	u_int32_t tmpip, aindex;
+	__be32 new_ip;
 	const struct ipt_same_info *same = targinfo;
 	struct ip_nat_range newrange;
 	const struct ip_conntrack_tuple *t;
@@ -191,6 +182,9 @@
 static struct ipt_target same_reg = { 
 	.name		= "SAME",
 	.target		= same_target,
+	.targetsize	= sizeof(struct ipt_same_info),
+	.table		= "nat",
+	.hooks		= (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_POST_ROUTING),
 	.checkentry	= same_check,
 	.destroy	= same_destroy,
 	.me		= THIS_MODULE,
diff -urN oldtree/net/ipv4/netfilter/ipt_TCPMSS.c newtree/net/ipv4/netfilter/ipt_TCPMSS.c
--- oldtree/net/ipv4/netfilter/ipt_TCPMSS.c	2006-02-19 11:41:06.375373896 +0000
+++ newtree/net/ipv4/netfilter/ipt_TCPMSS.c	2006-02-21 15:58:37.156497912 +0000
@@ -48,13 +48,15 @@
 		  const struct net_device *in,
 		  const struct net_device *out,
 		  unsigned int hooknum,
+		  const struct xt_target *target,
 		  const void *targinfo,
 		  void *userinfo)
 {
 	const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
 	struct tcphdr *tcph;
 	struct iphdr *iph;
-	u_int16_t tcplen, newtotlen, oldval, newmss;
+	u_int16_t tcplen, newmss;
+	__be16 newtotlen, oldval;
 	unsigned int i;
 	u_int8_t *opt;
 
@@ -118,7 +120,7 @@
 			opt[i+2] = (newmss & 0xff00) >> 8;
 			opt[i+3] = (newmss & 0x00ff);
 
-			tcph->check = cheat_check(htons(oldmss)^0xFFFF,
+			tcph->check = cheat_check(htons(oldmss)^htons(0xFFFF),
 						  htons(newmss),
 						  tcph->check);
 
@@ -160,7 +162,7 @@
  	opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
 	memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
 
-	tcph->check = cheat_check(htons(tcplen) ^ 0xFFFF,
+	tcph->check = cheat_check(htons(tcplen) ^ htons(0xFFFF),
 				  htons(tcplen + TCPOLEN_MSS), tcph->check);
 	tcplen += TCPOLEN_MSS;
 
@@ -171,13 +173,13 @@
 
 	tcph->check = cheat_check(~0, *((u_int32_t *)opt), tcph->check);
 
-	oldval = ((u_int16_t *)tcph)[6];
+	oldval = ((__be16 *)tcph)[6];
 	tcph->doff += TCPOLEN_MSS/4;
-	tcph->check = cheat_check(oldval ^ 0xFFFF,
-				  ((u_int16_t *)tcph)[6], tcph->check);
+	tcph->check = cheat_check(oldval ^ htons(0xFFFF),
+				  ((__be16 *)tcph)[6], tcph->check);
 
 	newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS);
-	iph->check = cheat_check(iph->tot_len ^ 0xFFFF,
+	iph->check = cheat_check(iph->tot_len ^ htons(0xFFFF),
 				 newtotlen, iph->check);
 	iph->tot_len = newtotlen;
 
@@ -211,6 +213,7 @@
 static int
 ipt_tcpmss_checkentry(const char *tablename,
 		      const void *e_void,
+		      const struct xt_target *target,
 		      void *targinfo,
 		      unsigned int targinfosize,
 		      unsigned int hook_mask)
@@ -218,13 +221,6 @@
 	const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
 	const struct ipt_entry *e = e_void;
 
-	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_tcpmss_info))) {
-		DEBUGP("ipt_tcpmss_checkentry: targinfosize %u != %u\n",
-		       targinfosize, IPT_ALIGN(sizeof(struct ipt_tcpmss_info)));
-		return 0;
-	}
-
-
 	if((tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) && 
 			((hook_mask & ~((1 << NF_IP_FORWARD)
 			   	| (1 << NF_IP_LOCAL_OUT)
@@ -233,11 +229,8 @@
 		return 0;
 	}
 
-	if (e->ip.proto == IPPROTO_TCP
-	    && !(e->ip.invflags & IPT_INV_PROTO)
-	    && IPT_MATCH_ITERATE(e, find_syn_match))
+	if (IPT_MATCH_ITERATE(e, find_syn_match))
 		return 1;
-
 	printk("TCPMSS: Only works on TCP SYN packets\n");
 	return 0;
 }
@@ -245,6 +238,8 @@
 static struct ipt_target ipt_tcpmss_reg = {
 	.name		= "TCPMSS",
 	.target		= ipt_tcpmss_target,
+	.targetsize	= sizeof(struct ipt_tcpmss_info),
+	.proto		= IPPROTO_TCP,
 	.checkentry	= ipt_tcpmss_checkentry,
 	.me		= THIS_MODULE,
 };
diff -urN oldtree/net/ipv4/netfilter/ipt_TOS.c newtree/net/ipv4/netfilter/ipt_TOS.c
--- oldtree/net/ipv4/netfilter/ipt_TOS.c	2006-02-19 11:41:06.375373896 +0000
+++ newtree/net/ipv4/netfilter/ipt_TOS.c	2006-02-21 15:58:37.156497912 +0000
@@ -25,18 +25,19 @@
        const struct net_device *in,
        const struct net_device *out,
        unsigned int hooknum,
+       const struct xt_target *target,
        const void *targinfo,
        void *userinfo)
 {
 	const struct ipt_tos_target_info *tosinfo = targinfo;
 
 	if (((*pskb)->nh.iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) {
-		u_int16_t diffs[2];
+		__be16 diffs[2];
 
 		if (!skb_make_writable(pskb, sizeof(struct iphdr)))
 			return NF_DROP;
 
-		diffs[0] = htons((*pskb)->nh.iph->tos) ^ 0xFFFF;
+		diffs[0] = htons((*pskb)->nh.iph->tos) ^ htons(0xFFFF);
 		(*pskb)->nh.iph->tos
 			= ((*pskb)->nh.iph->tos & IPTOS_PREC_MASK)
 			| tosinfo->tos;
@@ -45,7 +46,7 @@
 			= csum_fold(csum_partial((char *)diffs,
 						 sizeof(diffs),
 						 (*pskb)->nh.iph->check
-						 ^0xFFFF));
+						 ^htons(0xFFFF)));
 	}
 	return IPT_CONTINUE;
 }
@@ -53,24 +54,13 @@
 static int
 checkentry(const char *tablename,
 	   const void *e_void,
+	   const struct xt_target *target,
            void *targinfo,
            unsigned int targinfosize,
            unsigned int hook_mask)
 {
 	const u_int8_t tos = ((struct ipt_tos_target_info *)targinfo)->tos;
 
-	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_tos_target_info))) {
-		printk(KERN_WARNING "TOS: targinfosize %u != %Zu\n",
-		       targinfosize,
-		       IPT_ALIGN(sizeof(struct ipt_tos_target_info)));
-		return 0;
-	}
-
-	if (strcmp(tablename, "mangle") != 0) {
-		printk(KERN_WARNING "TOS: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
-		return 0;
-	}
-
 	if (tos != IPTOS_LOWDELAY
 	    && tos != IPTOS_THROUGHPUT
 	    && tos != IPTOS_RELIABILITY
@@ -79,13 +69,14 @@
 		printk(KERN_WARNING "TOS: bad tos value %#x\n", tos);
 		return 0;
 	}
-
 	return 1;
 }
 
 static struct ipt_target ipt_tos_reg = {
 	.name		= "TOS",
 	.target		= target,
+	.targetsize	= sizeof(struct ipt_tos_target_info),
+	.table		= "mangle",
 	.checkentry	= checkentry,
 	.me		= THIS_MODULE,
 };
diff -urN oldtree/net/ipv4/netfilter/ipt_TTL.c newtree/net/ipv4/netfilter/ipt_TTL.c
--- oldtree/net/ipv4/netfilter/ipt_TTL.c	2006-02-19 11:41:06.375373896 +0000
+++ newtree/net/ipv4/netfilter/ipt_TTL.c	2006-02-21 15:58:37.157497760 +0000
@@ -20,13 +20,14 @@
 MODULE_LICENSE("GPL");
 
 static unsigned int 
-ipt_ttl_target(struct sk_buff **pskb, const struct net_device *in, 
-		const struct net_device *out, unsigned int hooknum, 
-		const void *targinfo, void *userinfo)
+ipt_ttl_target(struct sk_buff **pskb,
+	       const struct net_device *in, const struct net_device *out,
+	       unsigned int hooknum, const struct xt_target *target,
+	       const void *targinfo, void *userinfo)
 {
 	struct iphdr *iph;
 	const struct ipt_TTL_info *info = targinfo;
-	u_int16_t diffs[2];
+	__be16 diffs[2];
 	int new_ttl;
 
 	if (!skb_make_writable(pskb, (*pskb)->len))
@@ -54,12 +55,12 @@
 	}
 
 	if (new_ttl != iph->ttl) {
-		diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF;
+		diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ htons(0xFFFF);
 		iph->ttl = new_ttl;
 		diffs[1] = htons(((unsigned)iph->ttl) << 8);
 		iph->check = csum_fold(csum_partial((char *)diffs,
 						    sizeof(diffs),
-						    iph->check^0xFFFF));
+						    iph->check^htons(0xFFFF)));
 	}
 
 	return IPT_CONTINUE;
@@ -67,40 +68,28 @@
 
 static int ipt_ttl_checkentry(const char *tablename,
 		const void *e,
+		const struct xt_target *target,
 		void *targinfo,
 		unsigned int targinfosize,
 		unsigned int hook_mask)
 {
 	struct ipt_TTL_info *info = targinfo;
 
-	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) {
-		printk(KERN_WARNING "ipt_TTL: targinfosize %u != %Zu\n",
-				targinfosize,
-				IPT_ALIGN(sizeof(struct ipt_TTL_info)));
-		return 0;
-	}
-
-	if (strcmp(tablename, "mangle")) {
-		printk(KERN_WARNING "ipt_TTL: can only be called from "
-			"\"mangle\" table, not \"%s\"\n", tablename);
-		return 0;
-	}
-
 	if (info->mode > IPT_TTL_MAXMODE) {
 		printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n", 
 			info->mode);
 		return 0;
 	}
-
 	if ((info->mode != IPT_TTL_SET) && (info->ttl == 0))
 		return 0;
-
 	return 1;
 }
 
 static struct ipt_target ipt_TTL = { 
 	.name 		= "TTL",
 	.target 	= ipt_ttl_target, 
+	.targetsize	= sizeof(struct ipt_TTL_info),
+	.table		= "mangle",
 	.checkentry 	= ipt_ttl_checkentry, 
 	.me 		= THIS_MODULE,
 };
diff -urN oldtree/net/ipv4/netfilter/ipt_ULOG.c newtree/net/ipv4/netfilter/ipt_ULOG.c
--- oldtree/net/ipv4/netfilter/ipt_ULOG.c	2006-02-19 11:41:06.376373744 +0000
+++ newtree/net/ipv4/netfilter/ipt_ULOG.c	2006-02-21 15:58:16.390654800 +0000
@@ -303,6 +303,7 @@
 				    const struct net_device *in,
 				    const struct net_device *out,
 				    unsigned int hooknum,
+				    const struct xt_target *target,
 				    const void *targinfo, void *userinfo)
 {
 	struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
@@ -339,42 +340,37 @@
 
 static int ipt_ulog_checkentry(const char *tablename,
 			       const void *e,
+			       const struct xt_target *target,
 			       void *targinfo,
 			       unsigned int targinfosize,
 			       unsigned int hookmask)
 {
 	struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
 
-	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ulog_info))) {
-		DEBUGP("ipt_ULOG: targinfosize %u != 0\n", targinfosize);
-		return 0;
-	}
-
 	if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') {
 		DEBUGP("ipt_ULOG: prefix term %i\n",
 		       loginfo->prefix[sizeof(loginfo->prefix) - 1]);
 		return 0;
 	}
-
 	if (loginfo->qthreshold > ULOG_MAX_QLEN) {
 		DEBUGP("ipt_ULOG: queue threshold %i > MAX_QLEN\n",
 			loginfo->qthreshold);
 		return 0;
 	}
-
 	return 1;
 }
 
 static struct ipt_target ipt_ulog_reg = {
 	.name		= "ULOG",
 	.target		= ipt_ulog_target,
+	.targetsize	= sizeof(struct ipt_ulog_info),
 	.checkentry	= ipt_ulog_checkentry,
 	.me		= THIS_MODULE,
 };
 
 static struct nf_logger ipt_ulog_logger = {
 	.name		= "ipt_ULOG",
-	.logfn		= &ipt_logfn,
+	.logfn		= ipt_logfn,
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/ipv4/netfilter/ipt_addrtype.c newtree/net/ipv4/netfilter/ipt_addrtype.c
--- oldtree/net/ipv4/netfilter/ipt_addrtype.c	2006-02-19 11:41:06.376373744 +0000
+++ newtree/net/ipv4/netfilter/ipt_addrtype.c	2006-02-21 15:58:37.151498672 +0000
@@ -22,13 +22,14 @@
 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
 MODULE_DESCRIPTION("iptables addrtype match");
 
-static inline int match_type(u_int32_t addr, u_int16_t mask)
+static inline int match_type(__be32 addr, u_int16_t mask)
 {
 	return !!(mask & (1 << inet_addr_type(addr)));
 }
 
-static int match(const struct sk_buff *skb, const struct net_device *in,
-		 const struct net_device *out, const void *matchinfo,
+static int match(const struct sk_buff *skb,
+		 const struct net_device *in, const struct net_device *out,
+		 const struct xt_match *match, const void *matchinfo,
 		 int offset, unsigned int protoff, int *hotdrop)
 {
 	const struct ipt_addrtype_info *info = matchinfo;
@@ -43,23 +44,10 @@
 	return ret;
 }
 
-static int checkentry(const char *tablename, const void *ip,
-		      void *matchinfo, unsigned int matchsize,
-		      unsigned int hook_mask)
-{
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_addrtype_info))) {
-		printk(KERN_ERR "ipt_addrtype: invalid size (%u != %Zu)\n",
-		       matchsize, IPT_ALIGN(sizeof(struct ipt_addrtype_info)));
-		return 0;
-	}
-
-	return 1;
-}
-
 static struct ipt_match addrtype_match = {
 	.name		= "addrtype",
 	.match		= match,
-	.checkentry	= checkentry,
+	.matchsize	= sizeof(struct ipt_addrtype_info),
 	.me		= THIS_MODULE
 };
 
diff -urN oldtree/net/ipv4/netfilter/ipt_ah.c newtree/net/ipv4/netfilter/ipt_ah.c
--- oldtree/net/ipv4/netfilter/ipt_ah.c	2006-02-19 11:41:06.377373592 +0000
+++ newtree/net/ipv4/netfilter/ipt_ah.c	2006-02-21 15:58:16.391654648 +0000
@@ -39,6 +39,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -71,37 +72,27 @@
 static int
 checkentry(const char *tablename,
 	   const void *ip_void,
+	   const struct xt_match *match,
 	   void *matchinfo,
 	   unsigned int matchinfosize,
 	   unsigned int hook_mask)
 {
 	const struct ipt_ah *ahinfo = matchinfo;
-	const struct ipt_ip *ip = ip_void;
 
-	/* Must specify proto == AH, and no unknown invflags */
-	if (ip->proto != IPPROTO_AH || (ip->invflags & IPT_INV_PROTO)) {
-		duprintf("ipt_ah: Protocol %u != %u\n", ip->proto,
-			 IPPROTO_AH);
-		return 0;
-	}
-	if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_ah))) {
-		duprintf("ipt_ah: matchsize %u != %u\n",
-			 matchinfosize, IPT_ALIGN(sizeof(struct ipt_ah)));
-		return 0;
-	}
+	/* Must specify no unknown invflags */
 	if (ahinfo->invflags & ~IPT_AH_INV_MASK) {
-		duprintf("ipt_ah: unknown flags %X\n",
-			 ahinfo->invflags);
+		duprintf("ipt_ah: unknown flags %X\n", ahinfo->invflags);
 		return 0;
 	}
-
 	return 1;
 }
 
 static struct ipt_match ah_match = {
 	.name		= "ah",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct ipt_ah),
+	.proto		= IPPROTO_AH,
+	.checkentry	= checkentry,
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/ipv4/netfilter/ipt_dscp.c newtree/net/ipv4/netfilter/ipt_dscp.c
--- oldtree/net/ipv4/netfilter/ipt_dscp.c	2006-02-19 11:41:06.379373288 +0000
+++ newtree/net/ipv4/netfilter/ipt_dscp.c	2006-02-21 15:58:16.391654648 +0000
@@ -19,8 +19,9 @@
 MODULE_DESCRIPTION("iptables DSCP matching module");
 MODULE_LICENSE("GPL");
 
-static int match(const struct sk_buff *skb, const struct net_device *in,
-		 const struct net_device *out, const void *matchinfo,
+static int match(const struct sk_buff *skb,
+		 const struct net_device *in, const struct net_device *out,
+		 const struct xt_match *match, const void *matchinfo,
 		 int offset, unsigned int protoff, int *hotdrop)
 {
 	const struct ipt_dscp_info *info = matchinfo;
@@ -31,20 +32,10 @@
 	return ((iph->tos&IPT_DSCP_MASK) == sh_dscp) ^ info->invert;
 }
 
-static int checkentry(const char *tablename, const void *ip,
-		      void *matchinfo, unsigned int matchsize,
-		      unsigned int hook_mask)
-{
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_dscp_info)))
-		return 0;
-
-	return 1;
-}
-
 static struct ipt_match dscp_match = {
 	.name		= "dscp",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct ipt_dscp_info),
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/ipv4/netfilter/ipt_ecn.c newtree/net/ipv4/netfilter/ipt_ecn.c
--- oldtree/net/ipv4/netfilter/ipt_ecn.c	2006-02-19 11:41:06.380373136 +0000
+++ newtree/net/ipv4/netfilter/ipt_ecn.c	2006-02-21 15:58:16.392654496 +0000
@@ -65,8 +65,9 @@
 	return 1;
 }
 
-static int match(const struct sk_buff *skb, const struct net_device *in,
-		 const struct net_device *out, const void *matchinfo,
+static int match(const struct sk_buff *skb,
+		 const struct net_device *in, const struct net_device *out,
+		 const struct xt_match *match, const void *matchinfo,
 		 int offset, unsigned int protoff, int *hotdrop)
 {
 	const struct ipt_ecn_info *info = matchinfo;
@@ -86,15 +87,13 @@
 }
 
 static int checkentry(const char *tablename, const void *ip_void,
+		      const struct xt_match *match,
 		      void *matchinfo, unsigned int matchsize,
 		      unsigned int hook_mask)
 {
 	const struct ipt_ecn_info *info = matchinfo;
 	const struct ipt_ip *ip = ip_void;
 
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_ecn_info)))
-		return 0;
-
 	if (info->operation & IPT_ECN_OP_MATCH_MASK)
 		return 0;
 
@@ -113,8 +112,9 @@
 
 static struct ipt_match ecn_match = {
 	.name		= "ecn",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct ipt_ecn_info),
+	.checkentry	= checkentry,
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/ipv4/netfilter/ipt_esp.c newtree/net/ipv4/netfilter/ipt_esp.c
--- oldtree/net/ipv4/netfilter/ipt_esp.c	2006-02-19 11:41:06.380373136 +0000
+++ newtree/net/ipv4/netfilter/ipt_esp.c	2006-02-21 15:58:16.392654496 +0000
@@ -40,6 +40,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -72,37 +73,27 @@
 static int
 checkentry(const char *tablename,
 	   const void *ip_void,
+	   const struct xt_match *match,
 	   void *matchinfo,
 	   unsigned int matchinfosize,
 	   unsigned int hook_mask)
 {
 	const struct ipt_esp *espinfo = matchinfo;
-	const struct ipt_ip *ip = ip_void;
 
-	/* Must specify proto == ESP, and no unknown invflags */
-	if (ip->proto != IPPROTO_ESP || (ip->invflags & IPT_INV_PROTO)) {
-		duprintf("ipt_esp: Protocol %u != %u\n", ip->proto,
-			 IPPROTO_ESP);
-		return 0;
-	}
-	if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_esp))) {
-		duprintf("ipt_esp: matchsize %u != %u\n",
-			 matchinfosize, IPT_ALIGN(sizeof(struct ipt_esp)));
-		return 0;
-	}
+	/* Must specify no unknown invflags */
 	if (espinfo->invflags & ~IPT_ESP_INV_MASK) {
-		duprintf("ipt_esp: unknown flags %X\n",
-			 espinfo->invflags);
+		duprintf("ipt_esp: unknown flags %X\n", espinfo->invflags);
 		return 0;
 	}
-
 	return 1;
 }
 
 static struct ipt_match esp_match = {
 	.name		= "esp",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct ipt_esp),
+	.proto		= IPPROTO_ESP,
+	.checkentry	= checkentry,
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/ipv4/netfilter/ipt_hashlimit.c newtree/net/ipv4/netfilter/ipt_hashlimit.c
--- oldtree/net/ipv4/netfilter/ipt_hashlimit.c	2006-02-19 11:41:06.381372984 +0000
+++ newtree/net/ipv4/netfilter/ipt_hashlimit.c	2006-02-21 15:58:37.153498368 +0000
@@ -40,6 +40,7 @@
 
 /* FIXME: this is just for IP_NF_ASSERRT */
 #include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/mutex.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
@@ -52,11 +53,11 @@
 /* hash table crap */
 
 struct dsthash_dst {
-	u_int32_t src_ip;
-	u_int32_t dst_ip;
+	__be32 src_ip;
+	__be32 dst_ip;
 	/* ports have to be consecutive !!! */
-	u_int16_t src_port;
-	u_int16_t dst_port;
+	__be16 src_port;
+	__be16 dst_port;
 };
 
 struct dsthash_ent {
@@ -92,7 +93,7 @@
 };
 
 static DEFINE_SPINLOCK(hashlimit_lock);	/* protects htables list */
-static DECLARE_MUTEX(hlimit_mutex);	/* additional checkentry protection */
+static DEFINE_MUTEX(hlimit_mutex);	/* additional checkentry protection */
 static HLIST_HEAD(hashlimit_htables);
 static kmem_cache_t *hashlimit_cachep __read_mostly;
 
@@ -107,8 +108,10 @@
 static inline u_int32_t
 hash_dst(const struct ipt_hashlimit_htable *ht, const struct dsthash_dst *dst)
 {
-	return (jhash_3words(dst->dst_ip, (dst->dst_port<<16 | dst->src_port), 
-			     dst->src_ip, ht->rnd) % ht->cfg.size);
+	return (jhash_3words((__force u32)dst->dst_ip,
+			    ((__force u32)dst->dst_port<<16 |
+			     (__force u32)dst->src_port), 
+			     (__force u32)dst->src_ip, ht->rnd) % ht->cfg.size);
 }
 
 static inline struct dsthash_ent *
@@ -381,7 +384,7 @@
 }
 
 static inline int get_ports(const struct sk_buff *skb, int offset, 
-			    u16 ports[2])
+			    __be16 ports[2])
 {
 	union {
 		struct tcphdr th;
@@ -427,6 +430,7 @@
 hashlimit_match(const struct sk_buff *skb,
 		const struct net_device *in,
 		const struct net_device *out,
+		const struct xt_match *match,
 		const void *matchinfo,
 		int offset,
 		unsigned int protoff,
@@ -447,7 +451,7 @@
 		dst.src_ip = skb->nh.iph->saddr;
 	if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DPT
 	    ||hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SPT) {
-		u_int16_t ports[2];
+		__be16 ports[2];
 		if (get_ports(skb, offset, ports)) {
 			/* We've been asked to examine this packet, and we
 		 	  can't.  Hence, no choice but to drop. */
@@ -506,15 +510,13 @@
 static int
 hashlimit_checkentry(const char *tablename,
 		     const void *inf,
+		     const struct xt_match *match,
 		     void *matchinfo,
 		     unsigned int matchsize,
 		     unsigned int hook_mask)
 {
 	struct ipt_hashlimit_info *r = matchinfo;
 
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_hashlimit_info)))
-		return 0;
-
 	/* Check for overflow. */
 	if (r->cfg.burst == 0
 	    || user2credits(r->cfg.avg * r->cfg.burst) < 
@@ -543,13 +545,13 @@
 	 * call vmalloc, and that can sleep.  And we cannot just re-search
 	 * the list of htable's in htable_create(), since then we would
 	 * create duplicate proc files. -HW */
-	down(&hlimit_mutex);
+	mutex_lock(&hlimit_mutex);
 	r->hinfo = htable_find_get(r->name);
 	if (!r->hinfo && (htable_create(r) != 0)) {
-		up(&hlimit_mutex);
+		mutex_unlock(&hlimit_mutex);
 		return 0;
 	}
-	up(&hlimit_mutex);
+	mutex_unlock(&hlimit_mutex);
 
 	/* Ugly hack: For SMP, we only want to use one set */
 	r->u.master = r;
@@ -558,19 +560,21 @@
 }
 
 static void
-hashlimit_destroy(void *matchinfo, unsigned int matchsize)
+hashlimit_destroy(const struct xt_match *match, void *matchinfo,
+		  unsigned int matchsize)
 {
 	struct ipt_hashlimit_info *r = (struct ipt_hashlimit_info *) matchinfo;
 
 	htable_put(r->hinfo);
 }
 
-static struct ipt_match ipt_hashlimit = { 
-	.name = "hashlimit", 
-	.match = hashlimit_match, 
-	.checkentry = hashlimit_checkentry, 
-	.destroy = hashlimit_destroy,
-	.me = THIS_MODULE 
+static struct ipt_match ipt_hashlimit = {
+	.name		= "hashlimit",
+	.match		= hashlimit_match,
+	.matchsize	= sizeof(struct ipt_hashlimit_info),
+	.checkentry	= hashlimit_checkentry,
+	.destroy	= hashlimit_destroy,
+	.me		= THIS_MODULE
 };
 
 /* PROC stuff */
diff -urN oldtree/net/ipv4/netfilter/ipt_iprange.c newtree/net/ipv4/netfilter/ipt_iprange.c
--- oldtree/net/ipv4/netfilter/ipt_iprange.c	2006-02-19 11:41:06.382372832 +0000
+++ newtree/net/ipv4/netfilter/ipt_iprange.c	2006-02-21 15:58:16.393654344 +0000
@@ -27,6 +27,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset, unsigned int protoff, int *hotdrop)
 {
@@ -62,27 +63,12 @@
 	return 1;
 }
 
-static int check(const char *tablename,
-		 const void *inf,
-		 void *matchinfo,
-		 unsigned int matchsize,
-		 unsigned int hook_mask)
-{
-	/* verify size */
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_iprange_info)))
-		return 0;
-
-	return 1;
-}
-
-static struct ipt_match iprange_match = 
-{ 
-	.list = { NULL, NULL }, 
-	.name = "iprange", 
-	.match = &match, 
-	.checkentry = &check, 
-	.destroy = NULL, 
-	.me = THIS_MODULE
+static struct ipt_match iprange_match = {
+	.name		= "iprange",
+	.match		= match,
+	.matchsize	= sizeof(struct ipt_iprange_info),
+	.destroy	= NULL,
+	.me		= THIS_MODULE
 };
 
 static int __init init(void)
diff -urN oldtree/net/ipv4/netfilter/ipt_multiport.c newtree/net/ipv4/netfilter/ipt_multiport.c
--- oldtree/net/ipv4/netfilter/ipt_multiport.c	2006-02-19 11:41:06.384372528 +0000
+++ newtree/net/ipv4/netfilter/ipt_multiport.c	2006-02-21 15:58:37.154498216 +0000
@@ -95,12 +95,13 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
       int *hotdrop)
 {
-	u16 _ports[2], *pptr;
+	__be16 _ports[2], *pptr;
 	const struct ipt_multiport *multiinfo = matchinfo;
 
 	if (offset)
@@ -127,12 +128,13 @@
 match_v1(const struct sk_buff *skb,
 	 const struct net_device *in,
 	 const struct net_device *out,
+	 const struct xt_match *match,
 	 const void *matchinfo,
 	 int offset,
 	 unsigned int protoff,
 	 int *hotdrop)
 {
-	u16 _ports[2], *pptr;
+	__be16 _ports[2], *pptr;
 	const struct ipt_multiport_v1 *multiinfo = matchinfo;
 
 	if (offset)
@@ -153,40 +155,19 @@
 	return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1]));
 }
 
-/* Called when user tries to insert an entry of this type. */
-static int
-checkentry(const char *tablename,
-	   const void *ip,
-	   void *matchinfo,
-	   unsigned int matchsize,
-	   unsigned int hook_mask)
-{
-	return (matchsize == IPT_ALIGN(sizeof(struct ipt_multiport)));
-}
-
-static int
-checkentry_v1(const char *tablename,
-	      const void *ip,
-	      void *matchinfo,
-	      unsigned int matchsize,
-	      unsigned int hook_mask)
-{
-	return (matchsize == IPT_ALIGN(sizeof(struct ipt_multiport_v1)));
-}
-
 static struct ipt_match multiport_match = {
 	.name		= "multiport",
 	.revision	= 0,
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct ipt_multiport),
 	.me		= THIS_MODULE,
 };
 
 static struct ipt_match multiport_match_v1 = {
 	.name		= "multiport",
 	.revision	= 1,
-	.match		= &match_v1,
-	.checkentry	= &checkentry_v1,
+	.match		= match_v1,
+	.matchsize	= sizeof(struct ipt_multiport_v1),
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/ipv4/netfilter/ipt_owner.c newtree/net/ipv4/netfilter/ipt_owner.c
--- oldtree/net/ipv4/netfilter/ipt_owner.c	2006-02-19 11:41:06.384372528 +0000
+++ newtree/net/ipv4/netfilter/ipt_owner.c	2006-02-21 15:58:16.394654192 +0000
@@ -25,6 +25,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -53,37 +54,27 @@
 static int
 checkentry(const char *tablename,
            const void *ip,
+	   const struct xt_match *match,
            void *matchinfo,
            unsigned int matchsize,
            unsigned int hook_mask)
 {
 	const struct ipt_owner_info *info = matchinfo;
 
-        if (hook_mask
-            & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING))) {
-                printk("ipt_owner: only valid for LOCAL_OUT or POST_ROUTING.\n");
-                return 0;
-        }
-
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_owner_info))) {
-		printk("Matchsize %u != %Zu\n", matchsize,
-		       IPT_ALIGN(sizeof(struct ipt_owner_info)));
-		return 0;
-	}
-
 	if (info->match & (IPT_OWNER_PID|IPT_OWNER_SID|IPT_OWNER_COMM)) {
 		printk("ipt_owner: pid, sid and command matching "
 		       "not supported anymore\n");
 		return 0;
 	}
-
 	return 1;
 }
 
 static struct ipt_match owner_match = {
 	.name		= "owner",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct ipt_owner_info),
+	.hooks		= (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING),
+	.checkentry	= checkentry,
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/ipv4/netfilter/ipt_policy.c newtree/net/ipv4/netfilter/ipt_policy.c
--- oldtree/net/ipv4/netfilter/ipt_policy.c	2006-02-19 11:41:06.386372224 +0000
+++ newtree/net/ipv4/netfilter/ipt_policy.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,176 +0,0 @@
-/* IP tables module for matching IPsec policy
- *
- * Copyright (c) 2004,2005 Patrick McHardy, <kaber@trash.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <net/xfrm.h>
-
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_policy.h>
-
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_DESCRIPTION("IPtables IPsec policy matching module");
-MODULE_LICENSE("GPL");
-
-
-static inline int
-match_xfrm_state(struct xfrm_state *x, const struct ipt_policy_elem *e)
-{
-#define MATCH_ADDR(x,y,z)	(!e->match.x ||				     \
-		                 ((e->x.a4.s_addr == (e->y.a4.s_addr & (z))) \
-				  ^ e->invert.x))
-#define MATCH(x,y)		(!e->match.x || ((e->x == (y)) ^ e->invert.x))
-
-	return MATCH_ADDR(saddr, smask, x->props.saddr.a4) &&
-	       MATCH_ADDR(daddr, dmask, x->id.daddr.a4) &&
-	       MATCH(proto, x->id.proto) &&
-	       MATCH(mode, x->props.mode) &&
-	       MATCH(spi, x->id.spi) &&
-	       MATCH(reqid, x->props.reqid);
-}
-
-static int
-match_policy_in(const struct sk_buff *skb, const struct ipt_policy_info *info)
-{
-	const struct ipt_policy_elem *e;
-	struct sec_path *sp = skb->sp;
-	int strict = info->flags & IPT_POLICY_MATCH_STRICT;
-	int i, pos;
-
-	if (sp == NULL)
-		return -1;
-	if (strict && info->len != sp->len)
-		return 0;
-
-	for (i = sp->len - 1; i >= 0; i--) {
-		pos = strict ? i - sp->len + 1 : 0;
-		if (pos >= info->len)
-			return 0;
-		e = &info->pol[pos];
-
-		if (match_xfrm_state(sp->x[i].xvec, e)) {
-			if (!strict)
-				return 1;
-		} else if (strict)
-			return 0;
-	}
-
-	return strict ? 1 : 0;
-}
-
-static int
-match_policy_out(const struct sk_buff *skb, const struct ipt_policy_info *info)
-{
-	const struct ipt_policy_elem *e;
-	struct dst_entry *dst = skb->dst;
-	int strict = info->flags & IPT_POLICY_MATCH_STRICT;
-	int i, pos;
-
-	if (dst->xfrm == NULL)
-		return -1;
-
-	for (i = 0; dst && dst->xfrm; dst = dst->child, i++) {
-		pos = strict ? i : 0;
-		if (pos >= info->len)
-			return 0;
-		e = &info->pol[pos];
-
-		if (match_xfrm_state(dst->xfrm, e)) {
-			if (!strict)
-				return 1;
-		} else if (strict)
-			return 0;
-	}
-
-	return strict ? i == info->len : 0;
-}
-
-static int match(const struct sk_buff *skb,
-                 const struct net_device *in,
-                 const struct net_device *out,
-                 const void *matchinfo,
-                 int offset,
-                 unsigned int protoff,
-                 int *hotdrop)
-{
-	const struct ipt_policy_info *info = matchinfo;
-	int ret;
-
-	if (info->flags & IPT_POLICY_MATCH_IN)
-		ret = match_policy_in(skb, info);
-	else
-		ret = match_policy_out(skb, info);
-
-	if (ret < 0)
-		ret = info->flags & IPT_POLICY_MATCH_NONE ? 1 : 0;
-	else if (info->flags & IPT_POLICY_MATCH_NONE)
-		ret = 0;
-
-	return ret;
-}
-
-static int checkentry(const char *tablename, const void *ip_void,
-                      void *matchinfo, unsigned int matchsize,
-                      unsigned int hook_mask)
-{
-	struct ipt_policy_info *info = matchinfo;
-
-	if (matchsize != IPT_ALIGN(sizeof(*info))) {
-		printk(KERN_ERR "ipt_policy: matchsize %u != %zu\n",
-		       matchsize, IPT_ALIGN(sizeof(*info)));
-		return 0;
-	}
-	if (!(info->flags & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT))) {
-		printk(KERN_ERR "ipt_policy: neither incoming nor "
-		                "outgoing policy selected\n");
-		return 0;
-	}
-	if (hook_mask & (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_LOCAL_IN)
-	    && info->flags & IPT_POLICY_MATCH_OUT) {
-		printk(KERN_ERR "ipt_policy: output policy not valid in "
-		                "PRE_ROUTING and INPUT\n");
-		return 0;
-	}
-	if (hook_mask & (1 << NF_IP_POST_ROUTING | 1 << NF_IP_LOCAL_OUT)
-	    && info->flags & IPT_POLICY_MATCH_IN) {
-		printk(KERN_ERR "ipt_policy: input policy not valid in "
-		                "POST_ROUTING and OUTPUT\n");
-		return 0;
-	}
-	if (info->len > IPT_POLICY_MAX_ELEM) {
-		printk(KERN_ERR "ipt_policy: too many policy elements\n");
-		return 0;
-	}
-
-	return 1;
-}
-
-static struct ipt_match policy_match = {
-	.name		= "policy",
-	.match		= match,
-	.checkentry 	= checkentry,
-	.me		= THIS_MODULE,
-};
-
-static int __init init(void)
-{
-	return ipt_register_match(&policy_match);
-}
-
-static void __exit fini(void)
-{
-	ipt_unregister_match(&policy_match);
-}
-
-module_init(init);
-module_exit(fini);
diff -urN oldtree/net/ipv4/netfilter/ipt_recent.c newtree/net/ipv4/netfilter/ipt_recent.c
--- oldtree/net/ipv4/netfilter/ipt_recent.c	2006-02-19 11:41:06.387372072 +0000
+++ newtree/net/ipv4/netfilter/ipt_recent.c	2006-02-21 15:58:37.155498064 +0000
@@ -53,7 +53,7 @@
 
 /* Structure of our list of recently seen addresses. */
 struct recent_ip_list {
-	u_int32_t addr;
+	__be32 addr;
 	u_int8_t  ttl;
 	unsigned long last_seen;
 	unsigned long *last_pkts;
@@ -102,16 +102,17 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
       int *hotdrop);
 
 /* Function to hash a given address into the hash table of table_size size */
-static int hash_func(unsigned int addr, int table_size)
+static int hash_func(__be32 addr, int table_size)
 {
 	int result = 0;
-	unsigned int value = addr;
+	unsigned int value = (__force unsigned int)addr;
 	do { result ^= value; } while((value >>= HASH_LOG));
 
 #ifdef DEBUG
@@ -185,14 +186,14 @@
 	char c, *cp;
 	union iaddr {
 		uint8_t bytes[4];
-		uint32_t word;
+		__be32 word;
 	} res;
 	uint8_t *pp = res.bytes;
 	int digit;
 
 	char buffer[20];
 	int len, check_set = 0, count;
-	u_int32_t addr = 0;
+	__be32 addr = 0;
 	struct sk_buff *skb;
 	struct ipt_recent_info *info;
 	struct recent_ip_tables *curr_table;
@@ -318,7 +319,7 @@
 	skb->nh.iph->daddr = 0;
 	/* Clear ttl since we have no way of knowing it */
 	skb->nh.iph->ttl = 0;
-	match(skb,NULL,NULL,info,0,0,NULL);
+	match(skb,NULL,NULL,NULL,info,0,0,NULL);
 
 	kfree(skb->nh.iph);
 out_free_skb:
@@ -356,6 +357,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -364,7 +366,8 @@
 	int pkt_count, hits_found, ans;
 	unsigned long now;
 	const struct ipt_recent_info *info = matchinfo;
-	u_int32_t addr = 0, time_temp;
+	__be32 addr = 0;
+	u_int32_t time_temp;
 	u_int8_t ttl = skb->nh.iph->ttl;
 	int *hash_table;
 	int orig_hash_result, hash_result, temp, location = 0, time_loc, end_collision_chain = -1;
@@ -406,7 +409,10 @@
 	spin_lock_bh(&curr_table->list_lock);
 
 	r_list = curr_table->table;
-	if(info->side == IPT_RECENT_DEST) addr = skb->nh.iph->daddr; else addr = skb->nh.iph->saddr;
+	if (info->side == IPT_RECENT_DEST)
+		addr = skb->nh.iph->daddr;
+	else
+		addr = skb->nh.iph->saddr;
 
 	if(!addr) { 
 #ifdef DEBUG
@@ -657,6 +663,7 @@
 static int
 checkentry(const char *tablename,
            const void *ip,
+	   const struct xt_match *match,
            void *matchinfo,
            unsigned int matchsize,
            unsigned int hook_mask)
@@ -670,8 +677,6 @@
 	if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() entered.\n");
 #endif
 
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_recent_info))) return 0;
-
 	/* seconds and hit_count only valid for CHECK/UPDATE */
 	if(info->check_set & IPT_RECENT_SET) { flag++; if(info->seconds || info->hit_count) return 0; }
 	if(info->check_set & IPT_RECENT_REMOVE) { flag++; if(info->seconds || info->hit_count) return 0; }
@@ -871,7 +876,7 @@
  * up its memory.
  */
 static void
-destroy(void *matchinfo, unsigned int matchsize)
+destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize)
 {
 	const struct ipt_recent_info *info = matchinfo;
 	struct recent_ip_tables *curr_table, *last_table;
@@ -951,12 +956,13 @@
 /* This is the structure we pass to ipt_register to register our
  * module with iptables.
  */
-static struct ipt_match recent_match = { 
-  .name = "recent", 
-  .match = &match, 
-  .checkentry = &checkentry, 
-  .destroy = &destroy, 
-  .me = THIS_MODULE
+static struct ipt_match recent_match = {
+	.name		= "recent",
+	.match		= match,
+	.matchsize	= sizeof(struct ipt_recent_info),
+	.checkentry	= checkentry,
+	.destroy	= destroy,
+	.me		= THIS_MODULE
 };
 
 /* Kernel module initialization. */
diff -urN oldtree/net/ipv4/netfilter/ipt_tos.c newtree/net/ipv4/netfilter/ipt_tos.c
--- oldtree/net/ipv4/netfilter/ipt_tos.c	2006-02-19 11:41:06.389371768 +0000
+++ newtree/net/ipv4/netfilter/ipt_tos.c	2006-02-21 15:58:16.397653736 +0000
@@ -21,6 +21,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -31,23 +32,10 @@
 	return (skb->nh.iph->tos == info->tos) ^ info->invert;
 }
 
-static int
-checkentry(const char *tablename,
-           const void *ip,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_tos_info)))
-		return 0;
-
-	return 1;
-}
-
 static struct ipt_match tos_match = {
 	.name		= "tos",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct ipt_tos_info),
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/ipv4/netfilter/ipt_ttl.c newtree/net/ipv4/netfilter/ipt_ttl.c
--- oldtree/net/ipv4/netfilter/ipt_ttl.c	2006-02-19 11:41:06.389371768 +0000
+++ newtree/net/ipv4/netfilter/ipt_ttl.c	2006-02-21 15:58:16.397653736 +0000
@@ -19,8 +19,9 @@
 MODULE_DESCRIPTION("IP tables TTL matching module");
 MODULE_LICENSE("GPL");
 
-static int match(const struct sk_buff *skb, const struct net_device *in,
-		 const struct net_device *out, const void *matchinfo,
+static int match(const struct sk_buff *skb,
+		 const struct net_device *in, const struct net_device *out,
+		 const struct xt_match *match, const void *matchinfo,
 		 int offset, unsigned int protoff, int *hotdrop)
 {
 	const struct ipt_ttl_info *info = matchinfo;
@@ -47,20 +48,10 @@
 	return 0;
 }
 
-static int checkentry(const char *tablename, const void  *ip,
-		      void *matchinfo, unsigned int matchsize,
-		      unsigned int hook_mask)
-{
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_ttl_info)))
-		return 0;
-
-	return 1;
-}
-
 static struct ipt_match ttl_match = {
 	.name		= "ttl",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct ipt_ttl_info),
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/ipv4/netfilter/iptable_mangle.c newtree/net/ipv4/netfilter/iptable_mangle.c
--- oldtree/net/ipv4/netfilter/iptable_mangle.c	2006-02-19 11:41:06.390371616 +0000
+++ newtree/net/ipv4/netfilter/iptable_mangle.c	2006-02-21 15:58:37.151498672 +0000
@@ -132,7 +132,7 @@
 {
 	unsigned int ret;
 	u_int8_t tos;
-	u_int32_t saddr, daddr;
+	__be32 saddr, daddr;
 	unsigned long nfmark;
 
 	/* root is playing with raw sockets. */
diff -urN oldtree/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c newtree/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
--- oldtree/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c	2006-02-19 11:41:06.391371464 +0000
+++ newtree/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c	2006-02-21 15:58:16.398653584 +0000
@@ -141,19 +141,21 @@
 {
 	struct nf_conn *ct;
 	enum ip_conntrack_info ctinfo;
+	struct nf_conn_help *help;
 
 	/* This is where we call the helper: as the packet goes out. */
 	ct = nf_ct_get(*pskb, &ctinfo);
-	if (ct && ct->helper) {
-		unsigned int ret;
-		ret = ct->helper->help(pskb,
-				       (*pskb)->nh.raw - (*pskb)->data
-						       + (*pskb)->nh.iph->ihl*4,
-				       ct, ctinfo);
-		if (ret != NF_ACCEPT)
-			return ret;
-	}
-	return NF_ACCEPT;
+	if (!ct)
+		return NF_ACCEPT;
+
+	help = nfct_help(ct);
+	if (!help || !help->helper)
+		return NF_ACCEPT;
+
+	return help->helper->help(pskb,
+			       (*pskb)->nh.raw - (*pskb)->data
+					       + (*pskb)->nh.iph->ihl*4,
+			       ct, ctinfo);
 }
 
 static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
diff -urN oldtree/net/ipv4/netfilter.c newtree/net/ipv4/netfilter.c
--- oldtree/net/ipv4/netfilter.c	2006-02-19 11:41:06.392371312 +0000
+++ newtree/net/ipv4/netfilter.c	2006-02-21 15:58:37.067511440 +0000
@@ -128,8 +128,8 @@
  */
 
 struct ip_rt_info {
-	u_int32_t daddr;
-	u_int32_t saddr;
+	__be32 daddr;
+	__be32 saddr;
 	u_int8_t tos;
 };
 
diff -urN oldtree/net/ipv4/raw.c newtree/net/ipv4/raw.c
--- oldtree/net/ipv4/raw.c	2006-02-19 11:41:06.393371160 +0000
+++ newtree/net/ipv4/raw.c	2006-02-21 15:58:37.157497760 +0000
@@ -382,8 +382,8 @@
 	struct ipcm_cookie ipc;
 	struct rtable *rt = NULL;
 	int free = 0;
-	u32 daddr;
-	u32 saddr;
+	__be32 daddr;
+	__be32 saddr;
 	u8  tos;
 	int err;
 
@@ -814,8 +814,8 @@
 static __inline__ char *get_raw_sock(struct sock *sp, char *tmpbuf, int i)
 {
 	struct inet_sock *inet = inet_sk(sp);
-	unsigned int dest = inet->daddr,
-		     src = inet->rcv_saddr;
+	__be32 dest = inet->daddr,
+	       src = inet->rcv_saddr;
 	__u16 destp = 0,
 	      srcp  = inet->num;
 
diff -urN oldtree/net/ipv4/route.c newtree/net/ipv4/route.c
--- oldtree/net/ipv4/route.c	2006-02-19 11:41:06.395370856 +0000
+++ newtree/net/ipv4/route.c	2006-02-21 15:58:37.160497304 +0000
@@ -253,6 +253,10 @@
 		& rt_hash_mask);
 }
 
+#define rt_hash(daddr, saddr, idx, tos) \
+	rt_hash_code((__force u32)(__be32)(daddr),\
+		     (__force u32)(__be32)(saddr) ^ ((idx) << 5), (tos))
+
 #ifdef CONFIG_PROC_FS
 struct rt_cache_iter_state {
 	int bucket;
@@ -1066,7 +1070,7 @@
 	u32 salt;
 
 	spin_lock_bh(&ip_fb_id_lock);
-	salt = secure_ip_id(ip_fallback_id ^ iph->daddr);
+	salt = secure_ip_id(ip_fallback_id ^ (__force u32)iph->daddr);
 	iph->id = htons(salt & 0xFFFF);
 	ip_fallback_id = salt;
 	spin_unlock_bh(&ip_fb_id_lock);
@@ -1110,13 +1114,13 @@
 	spin_unlock_bh(rt_hash_lock_addr(hash));
 }
 
-void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
-		    u32 saddr, u8 tos, struct net_device *dev)
+void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
+		    __be32 saddr, u8 tos, struct net_device *dev)
 {
 	int i, k;
 	struct in_device *in_dev = in_dev_get(dev);
 	struct rtable *rth, **rthp;
-	u32  skeys[2] = { saddr, 0 };
+	__be32  skeys[2] = { saddr, 0 };
 	int  ikeys[2] = { dev->ifindex, 0 };
 
 	tos &= IPTOS_RT_MASK;
@@ -1140,9 +1144,7 @@
 
 	for (i = 0; i < 2; i++) {
 		for (k = 0; k < 2; k++) {
-			unsigned hash = rt_hash_code(daddr,
-						     skeys[i] ^ (ikeys[k] << 5),
-						     tos);
+			unsigned hash = rt_hash(daddr, skeys[i], ikeys[k], tos);
 
 			rthp=&rt_hash_table[hash].chain;
 
@@ -1251,10 +1253,8 @@
 			ret = NULL;
 		} else if ((rt->rt_flags & RTCF_REDIRECTED) ||
 			   rt->u.dst.expires) {
-			unsigned hash = rt_hash_code(rt->fl.fl4_dst,
-						     rt->fl.fl4_src ^
-							(rt->fl.oif << 5),
-						     rt->fl.fl4_tos);
+			unsigned hash = rt_hash(rt->fl.fl4_dst, rt->fl.fl4_src,
+						rt->fl.oif, rt->fl.fl4_tos);
 #if RT_CACHE_DEBUG >= 1
 			printk(KERN_DEBUG "ip_rt_advice: redirect to "
 					  "%u.%u.%u.%u/%02x dropped\n",
@@ -1389,8 +1389,8 @@
 	int i;
 	unsigned short old_mtu = ntohs(iph->tot_len);
 	struct rtable *rth;
-	u32  skeys[2] = { iph->saddr, 0, };
-	u32  daddr = iph->daddr;
+	__be32  skeys[2] = { iph->saddr, 0, };
+	__be32  daddr = iph->daddr;
 	u8   tos = iph->tos & IPTOS_RT_MASK;
 	unsigned short est_mtu = 0;
 
@@ -1398,7 +1398,7 @@
 		return 0;
 
 	for (i = 0; i < 2; i++) {
-		unsigned hash = rt_hash_code(daddr, skeys[i], tos);
+		unsigned hash = rt_hash(daddr, skeys[i], 0, tos);
 
 		rcu_read_lock();
 		for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
@@ -1523,7 +1523,7 @@
 
 void ip_rt_get_source(u8 *addr, struct rtable *rt)
 {
-	u32 src;
+	__be32 src;
 	struct fib_result res;
 
 	if (rt->fl.iif == 0)
@@ -1589,12 +1589,12 @@
         rt->rt_type = res->type;
 }
 
-static int ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr,
+static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 				u8 tos, struct net_device *dev, int our)
 {
 	unsigned hash;
 	struct rtable *rth;
-	u32 spec_dst;
+	__be32 spec_dst;
 	struct in_device *in_dev = in_dev_get(dev);
 	u32 itag = 0;
 
@@ -1658,7 +1658,7 @@
 	RT_CACHE_STAT_INC(in_slow_mc);
 
 	in_dev_put(in_dev);
-	hash = rt_hash_code(daddr, saddr ^ (dev->ifindex << 5), tos);
+	hash = rt_hash(daddr, saddr, dev->ifindex, tos);
 	return rt_intern_hash(hash, rth, (struct rtable**) &skb->dst);
 
 e_nobufs:
@@ -1674,8 +1674,8 @@
 static void ip_handle_martian_source(struct net_device *dev,
 				     struct in_device *in_dev,
 				     struct sk_buff *skb,
-				     u32 daddr,
-				     u32 saddr) 
+				     __be32 daddr,
+				     __be32 saddr) 
 {
 	RT_CACHE_STAT_INC(in_martian_src);
 #ifdef CONFIG_IP_ROUTE_VERBOSE
@@ -1705,7 +1705,7 @@
 static inline int __mkroute_input(struct sk_buff *skb, 
 				  struct fib_result* res, 
 				  struct in_device *in_dev, 
-				  u32 daddr, u32 saddr, u32 tos, 
+				  __be32 daddr, __be32 saddr, u32 tos, 
 				  struct rtable **result) 
 {
 
@@ -1713,7 +1713,8 @@
 	int err;
 	struct in_device *out_dev;
 	unsigned flags = 0;
-	u32 spec_dst, itag;
+	__be32 spec_dst;
+	u32 itag;
 
 	/* get a working reference to the output device */
 	out_dev = in_dev_get(FIB_RES_DEV(*res));
@@ -1806,7 +1807,7 @@
 				       struct fib_result* res, 
 				       const struct flowi *fl,
 				       struct in_device *in_dev,
-				       u32 daddr, u32 saddr, u32 tos)
+				       __be32 daddr, __be32 saddr, u32 tos)
 {
 	struct rtable* rth = NULL;
 	int err;
@@ -1823,7 +1824,7 @@
 		return err;
 
 	/* put it into the cache */
-	hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos);
+	hash = rt_hash(daddr, saddr, fl->iif, tos);
 	return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);	
 }
 
@@ -1831,7 +1832,7 @@
 				   struct fib_result* res, 
 				   const struct flowi *fl,
 				   struct in_device *in_dev,
-				   u32 daddr, u32 saddr, u32 tos)
+				   __be32 daddr, __be32 saddr, u32 tos)
 {
 #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
 	struct rtable* rth = NULL, *rtres;
@@ -1864,7 +1865,7 @@
 			return err;
 
 		/* put it into the cache */
-		hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos);
+		hash = rt_hash(daddr, saddr, fl->iif, tos);
 		err = rt_intern_hash(hash, rth, &rtres);
 		if (err)
 			return err;
@@ -1894,7 +1895,7 @@
  *	2. IP spoofing attempts are filtered with 100% of guarantee.
  */
 
-static int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
+static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 			       u8 tos, struct net_device *dev)
 {
 	struct fib_result res;
@@ -1913,7 +1914,7 @@
 	u32		itag = 0;
 	struct rtable * rth;
 	unsigned	hash;
-	u32		spec_dst;
+	__be32		spec_dst;
 	int		err = -EINVAL;
 	int		free_res = 0;
 
@@ -1929,7 +1930,7 @@
 	if (MULTICAST(saddr) || BADCLASS(saddr) || LOOPBACK(saddr))
 		goto martian_source;
 
-	if (daddr == 0xFFFFFFFF || (saddr == 0 && daddr == 0))
+	if (daddr == htonl(0xFFFFFFFF) || (saddr == 0 && daddr == 0))
 		goto brd_input;
 
 	/* Accept zero addresses only to limited broadcast;
@@ -2041,7 +2042,7 @@
 		rth->rt_flags 	&= ~RTCF_LOCAL;
 	}
 	rth->rt_type	= res.type;
-	hash = rt_hash_code(daddr, saddr ^ (fl.iif << 5), tos);
+	hash = rt_hash(daddr, saddr, fl.iif, tos);
 	err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
 	goto done;
 
@@ -2080,7 +2081,7 @@
 	goto e_inval;
 }
 
-int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
+int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 		   u8 tos, struct net_device *dev)
 {
 	struct rtable * rth;
@@ -2088,7 +2089,7 @@
 	int iif = dev->ifindex;
 
 	tos &= IPTOS_RT_MASK;
-	hash = rt_hash_code(daddr, saddr ^ (iif << 5), tos);
+	hash = rt_hash(daddr, saddr, iif, tos);
 
 	rcu_read_lock();
 	for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
@@ -2162,7 +2163,7 @@
 	if (LOOPBACK(fl->fl4_src) && !(dev_out->flags&IFF_LOOPBACK))
 		return -EINVAL;
 
-	if (fl->fl4_dst == 0xFFFFFFFF)
+	if (fl->fl4_dst == htonl(0xFFFFFFFF))
 		res->type = RTN_BROADCAST;
 	else if (MULTICAST(fl->fl4_dst))
 		res->type = RTN_MULTICAST;
@@ -2288,8 +2289,8 @@
 	if (err == 0) {
 		u32 tos = RT_FL_TOS(oldflp);
 
-		hash = rt_hash_code(oldflp->fl4_dst, 
-				    oldflp->fl4_src ^ (oldflp->oif << 5), tos);
+		hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src,
+			       oldflp->oif, tos);
 		err = rt_intern_hash(hash, rth, rp);
 	}
 	
@@ -2332,9 +2333,8 @@
 			if (err != 0)
 				goto cleanup;
 
-			hash = rt_hash_code(oldflp->fl4_dst, 
-					    oldflp->fl4_src ^
-					    (oldflp->oif << 5), tos);
+			hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src,
+					oldflp->oif, tos);
 			err = rt_intern_hash(hash, rth, rp);
 
 			/* forward hop information to multipath impl. */
@@ -2413,7 +2413,7 @@
 		 */
 
 		if (oldflp->oif == 0
-		    && (MULTICAST(oldflp->fl4_dst) || oldflp->fl4_dst == 0xFFFFFFFF)) {
+		    && (MULTICAST(oldflp->fl4_dst) || oldflp->fl4_dst == htonl(0xFFFFFFFF))) {
 			/* Special hack: user can direct multicasts
 			   and limited broadcast via necessary interface
 			   without fiddling with IP_MULTICAST_IF or IP_PKTINFO.
@@ -2450,7 +2450,7 @@
 			goto out;	/* Wrong error code */
 		}
 
-		if (LOCAL_MCAST(oldflp->fl4_dst) || oldflp->fl4_dst == 0xFFFFFFFF) {
+		if (LOCAL_MCAST(oldflp->fl4_dst) || oldflp->fl4_dst == htonl(0xFFFFFFFF)) {
 			if (!fl.fl4_src)
 				fl.fl4_src = inet_select_addr(dev_out, 0,
 							      RT_SCOPE_LINK);
@@ -2563,7 +2563,7 @@
 	unsigned hash;
 	struct rtable *rth;
 
-	hash = rt_hash_code(flp->fl4_dst, flp->fl4_src ^ (flp->oif << 5), flp->fl4_tos);
+	hash = rt_hash(flp->fl4_dst, flp->fl4_src, flp->oif, flp->fl4_tos);
 
 	rcu_read_lock_bh();
 	for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
@@ -2702,7 +2702,7 @@
 	RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci);
 	if (rt->fl.iif) {
 #ifdef CONFIG_IP_MROUTE
-		u32 dst = rt->rt_dst;
+		__be32 dst = rt->rt_dst;
 
 		if (MULTICAST(dst) && !LOCAL_MCAST(dst) &&
 		    ipv4_devconf.mc_forwarding) {
@@ -2737,8 +2737,8 @@
 	struct rtattr **rta = arg;
 	struct rtmsg *rtm = NLMSG_DATA(nlh);
 	struct rtable *rt = NULL;
-	u32 dst = 0;
-	u32 src = 0;
+	__be32 dst = 0;
+	__be32 src = 0;
 	int iif = 0;
 	int err = -ENOBUFS;
 	struct sk_buff *skb;
diff -urN oldtree/net/ipv4/syncookies.c newtree/net/ipv4/syncookies.c
--- oldtree/net/ipv4/syncookies.c	2006-02-19 11:41:06.395370856 +0000
+++ newtree/net/ipv4/syncookies.c	2006-02-21 15:58:37.161497152 +0000
@@ -35,23 +35,23 @@
 #define COOKIEBITS 24	/* Upper bits store count */
 #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
 
-static u32 cookie_hash(u32 saddr, u32 daddr, u32 sport, u32 dport,
+static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport,
 		       u32 count, int c)
 {
 	__u32 tmp[16 + 5 + SHA_WORKSPACE_WORDS];
 
 	memcpy(tmp + 3, syncookie_secret[c], sizeof(syncookie_secret[c]));
-	tmp[0] = saddr;
-	tmp[1] = daddr;
-	tmp[2] = (sport << 16) + dport;
+	tmp[0] = (__force u32)saddr;
+	tmp[1] = (__force u32)daddr;
+	tmp[2] = ((__force u32)sport << 16) + (__force u32)dport;
 	tmp[3] = count;
 	sha_transform(tmp + 16, (__u8 *)tmp, tmp + 16 + 5);
 
 	return tmp[17];
 }
 
-static __u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr, __u16 sport,
-				   __u16 dport, __u32 sseq, __u32 count,
+static __u32 secure_tcp_syn_cookie(__be32 saddr, __be32 daddr, __be16 sport,
+				   __be16 dport, __u32 sseq, __u32 count,
 				   __u32 data)
 {
 	/*
@@ -80,8 +80,8 @@
  * "maxdiff" if the current (passed-in) "count".  The return value
  * is (__u32)-1 if this test fails.
  */
-static __u32 check_tcp_syn_cookie(__u32 cookie, __u32 saddr, __u32 daddr,
-				  __u16 sport, __u16 dport, __u32 sseq,
+static __u32 check_tcp_syn_cookie(__u32 cookie, __be32 saddr, __be32 daddr,
+				  __be16 sport, __be16 dport, __u32 sseq,
 				  __u32 count, __u32 maxdiff)
 {
 	__u32 diff;
@@ -216,7 +216,7 @@
 
 	ireq = inet_rsk(req);
 	treq = tcp_rsk(req);
-	treq->rcv_isn		= htonl(skb->h.th->seq) - 1;
+	treq->rcv_isn		= ntohl(skb->h.th->seq) - 1;
 	treq->snt_isn		= cookie; 
 	req->mss		= mss;
  	ireq->rmt_port		= skb->h.th->source;
diff -urN oldtree/net/ipv4/sysctl_net_ipv4.c newtree/net/ipv4/sysctl_net_ipv4.c
--- oldtree/net/ipv4/sysctl_net_ipv4.c	2006-02-19 11:41:06.396370704 +0000
+++ newtree/net/ipv4/sysctl_net_ipv4.c	2006-02-21 15:58:16.402652976 +0000
@@ -664,6 +664,22 @@
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec,
 	},
+	{
+		.ctl_name	= NET_TCP_MTU_PROBING,
+		.procname	= "tcp_mtu_probing",
+		.data		= &sysctl_tcp_mtu_probing,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+	{
+		.ctl_name	= NET_TCP_BASE_MSS,
+		.procname	= "tcp_base_mss",
+		.data		= &sysctl_tcp_base_mss,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
 
 	{ .ctl_name = 0 }
 };
diff -urN oldtree/net/ipv4/tcp_input.c newtree/net/ipv4/tcp_input.c
--- oldtree/net/ipv4/tcp_input.c	2006-02-19 11:41:06.402369792 +0000
+++ newtree/net/ipv4/tcp_input.c	2006-02-21 15:58:37.163496848 +0000
@@ -933,7 +933,7 @@
 	const struct inet_connection_sock *icsk = inet_csk(sk);
 	struct tcp_sock *tp = tcp_sk(sk);
 	unsigned char *ptr = ack_skb->h.raw + TCP_SKB_CB(ack_skb)->sacked;
-	struct tcp_sack_block *sp = (struct tcp_sack_block *)(ptr+2);
+	struct tcp_sack_block_wire *sp = (struct tcp_sack_block_wire *)(ptr+2);
 	int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3;
 	int reord = tp->packets_out;
 	int prior_fackets;
@@ -1891,6 +1891,34 @@
 	}
 }
 
+static void tcp_mtup_probe_failed(struct sock *sk)
+{
+	struct inet_connection_sock *icsk = inet_csk(sk);
+	
+	icsk->icsk_mtup.search_high = icsk->icsk_mtup.probe_size - 1;
+	icsk->icsk_mtup.probe_size = 0;
+}
+
+static void tcp_mtup_probe_success(struct sock *sk, struct sk_buff *skb)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct inet_connection_sock *icsk = inet_csk(sk);
+	
+	/* FIXME: breaks with very large cwnd */
+	tp->prior_ssthresh = tcp_current_ssthresh(sk);
+	tp->snd_cwnd = tp->snd_cwnd *
+		       tcp_mss_to_mtu(sk, tp->mss_cache) /
+		       icsk->icsk_mtup.probe_size;
+	tp->snd_cwnd_cnt = 0;
+	tp->snd_cwnd_stamp = tcp_time_stamp;
+	tp->rcv_ssthresh = tcp_current_ssthresh(sk);
+	
+	icsk->icsk_mtup.search_low = icsk->icsk_mtup.probe_size;
+	icsk->icsk_mtup.probe_size = 0;
+	tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
+}
+
+
 /* Process an event, which can update packets-in-flight not trivially.
  * Main goal of this function is to calculate new estimate for left_out,
  * taking into account both packets sitting in receiver's buffer and
@@ -2023,6 +2051,17 @@
 			return;
 		}
 
+		/* MTU probe failure: don't reduce cwnd */
+		if (icsk->icsk_ca_state < TCP_CA_CWR &&
+		    icsk->icsk_mtup.probe_size &&
+		    tp->snd_una == icsk->icsk_mtup.probe_seq_start) {
+			tcp_mtup_probe_failed(sk);
+			/* Restores the reduction we did in tcp_mtup_probe() */
+			tp->snd_cwnd++;
+			tcp_simple_retransmit(sk);
+			return;
+		}
+
 		/* Otherwise enter Recovery state */
 
 		if (IsReno(tp))
@@ -2242,6 +2281,13 @@
 			acked |= FLAG_SYN_ACKED;
 			tp->retrans_stamp = 0;
 		}
+		
+		/* MTU probing checks */
+		if (icsk->icsk_mtup.probe_size) {
+			if (!after(icsk->icsk_mtup.probe_seq_end, TCP_SKB_CB(skb)->end_seq)) {
+				tcp_mtup_probe_success(sk, skb);
+			}
+		}
 
 		if (sacked) {
 			if (sacked & TCPCB_RETRANS) {
@@ -2567,7 +2613,7 @@
 	  			switch(opcode) {
 				case TCPOPT_MSS:
 					if(opsize==TCPOLEN_MSS && th->syn && !estab) {
-						u16 in_mss = ntohs(get_unaligned((__u16 *)ptr));
+						u16 in_mss = ntohs(get_unaligned((__be16 *)ptr));
 						if (in_mss) {
 							if (opt_rx->user_mss && opt_rx->user_mss < in_mss)
 								in_mss = opt_rx->user_mss;
@@ -2595,8 +2641,8 @@
 						if ((estab && opt_rx->tstamp_ok) ||
 						    (!estab && sysctl_tcp_timestamps)) {
 							opt_rx->saw_tstamp = 1;
-							opt_rx->rcv_tsval = ntohl(get_unaligned((__u32 *)ptr));
-							opt_rx->rcv_tsecr = ntohl(get_unaligned((__u32 *)(ptr+4)));
+							opt_rx->rcv_tsval = ntohl(get_unaligned((__be32 *)ptr));
+							opt_rx->rcv_tsecr = ntohl(get_unaligned((__be32 *)(ptr+4)));
 						}
 					}
 					break;
@@ -2633,8 +2679,8 @@
 		return 0;
 	} else if (tp->rx_opt.tstamp_ok &&
 		   th->doff == (sizeof(struct tcphdr)>>2)+(TCPOLEN_TSTAMP_ALIGNED>>2)) {
-		__u32 *ptr = (__u32 *)(th + 1);
-		if (*ptr == ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
+		__be32 *ptr = (__be32 *)(th + 1);
+		if (*ptr == htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
 				  | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
 			tp->rx_opt.saw_tstamp = 1;
 			++ptr;
@@ -3804,10 +3850,10 @@
 
 		/* Check timestamp */
 		if (tcp_header_len == sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) {
-			__u32 *ptr = (__u32 *)(th + 1);
+			__be32 *ptr = (__be32 *)(th + 1);
 
 			/* No? Slow path! */
-			if (*ptr != ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
+			if (*ptr != htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
 					  | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP))
 				goto slow_path;
 
@@ -4101,6 +4147,7 @@
 		if (tp->rx_opt.sack_ok && sysctl_tcp_fack)
 			tp->rx_opt.sack_ok |= 2;
 
+		tcp_mtup_init(sk);
 		tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
 		tcp_initialize_rcv_mss(sk);
 
@@ -4211,6 +4258,7 @@
 		if (tp->ecn_flags&TCP_ECN_OK)
 			sock_set_flag(sk, SOCK_NO_LARGESEND);
 
+		tcp_mtup_init(sk);
 		tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
 		tcp_initialize_rcv_mss(sk);
 
@@ -4399,6 +4447,7 @@
 				 */
 				tp->lsndtime = tcp_time_stamp;
 
+				tcp_mtup_init(sk);
 				tcp_initialize_rcv_mss(sk);
 				tcp_init_buffer_space(sk);
 				tcp_fast_path_on(tp);
diff -urN oldtree/net/ipv4/tcp_ipv4.c newtree/net/ipv4/tcp_ipv4.c
--- oldtree/net/ipv4/tcp_ipv4.c	2006-02-19 11:41:06.403369640 +0000
+++ newtree/net/ipv4/tcp_ipv4.c	2006-02-21 15:58:37.164496696 +0000
@@ -159,7 +159,7 @@
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
 	struct rtable *rt;
-	u32 daddr, nexthop;
+	__be32 daddr, nexthop;
 	int tmp;
 	int err;
 
@@ -716,8 +716,8 @@
 	struct inet_request_sock *ireq;
 	struct tcp_options_received tmp_opt;
 	struct request_sock *req;
-	__u32 saddr = skb->nh.iph->saddr;
-	__u32 daddr = skb->nh.iph->daddr;
+	__be32 saddr = skb->nh.iph->saddr;
+	__be32 daddr = skb->nh.iph->daddr;
 	__u32 isn = TCP_SKB_CB(skb)->when;
 	struct dst_entry *dst = NULL;
 #ifdef CONFIG_SYN_COOKIES
@@ -900,6 +900,7 @@
 		inet_csk(newsk)->icsk_ext_hdr_len = newinet->opt->optlen;
 	newinet->id = newtp->write_seq ^ jiffies;
 
+	tcp_mtup_init(newsk);
 	tcp_sync_mss(newsk, dst_mtu(dst));
 	newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
 	tcp_initialize_rcv_mss(newsk);
@@ -1683,8 +1684,8 @@
 	struct tcp_sock *tp = tcp_sk(sp);
 	const struct inet_connection_sock *icsk = inet_csk(sp);
 	struct inet_sock *inet = inet_sk(sp);
-	unsigned int dest = inet->daddr;
-	unsigned int src = inet->rcv_saddr;
+	__be32 dest = inet->daddr;
+	__be32 src = inet->rcv_saddr;
 	__u16 destp = ntohs(inet->dport);
 	__u16 srcp = ntohs(inet->sport);
 
@@ -1722,7 +1723,7 @@
 
 static void get_timewait4_sock(struct inet_timewait_sock *tw, char *tmpbuf, int i)
 {
-	unsigned int dest, src;
+	__be32 dest, src;
 	__u16 destp, srcp;
 	int ttd = tw->tw_ttd - jiffies;
 
diff -urN oldtree/net/ipv4/tcp_minisocks.c newtree/net/ipv4/tcp_minisocks.c
--- oldtree/net/ipv4/tcp_minisocks.c	2006-02-19 11:41:06.404369488 +0000
+++ newtree/net/ipv4/tcp_minisocks.c	2006-02-21 15:58:37.165496544 +0000
@@ -458,7 +458,7 @@
 			   struct request_sock **prev)
 {
 	struct tcphdr *th = skb->h.th;
-	u32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK);
+	__be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK);
 	int paws_reject = 0;
 	struct tcp_options_received tmp_opt;
 	struct sock *child;
diff -urN oldtree/net/ipv4/tcp_output.c newtree/net/ipv4/tcp_output.c
--- oldtree/net/ipv4/tcp_output.c	2006-02-19 11:41:06.405369336 +0000
+++ newtree/net/ipv4/tcp_output.c	2006-02-21 15:58:37.166496392 +0000
@@ -51,6 +51,12 @@
  */
 int sysctl_tcp_tso_win_divisor = 3;
 
+int sysctl_tcp_mtu_probing = 0;
+int sysctl_tcp_base_mss = 512;
+
+EXPORT_SYMBOL(sysctl_tcp_mtu_probing);
+EXPORT_SYMBOL(sysctl_tcp_base_mss);
+
 static void update_send_head(struct sock *sk, struct tcp_sock *tp,
 			     struct sk_buff *skb)
 {
@@ -250,7 +256,7 @@
 	return new_win;
 }
 
-static void tcp_build_and_update_options(__u32 *ptr, struct tcp_sock *tp,
+static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp,
 					 __u32 tstamp)
 {
 	if (tp->rx_opt.tstamp_ok) {
@@ -286,7 +292,7 @@
  * MAX_SYN_SIZE to match the new maximum number of options that you
  * can generate.
  */
-static void tcp_syn_build_options(__u32 *ptr, int mss, int ts, int sack,
+static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack,
 				  int offer_wscale, int wscale, __u32 tstamp,
 				  __u32 ts_recent)
 {
@@ -405,7 +411,7 @@
 	th->dest		= inet->dport;
 	th->seq			= htonl(tcb->seq);
 	th->ack_seq		= htonl(tp->rcv_nxt);
-	*(((__u16 *)th) + 6)	= htons(((tcp_header_size >> 2) << 12) |
+	*(((__be16 *)th) + 6)	= htons(((tcp_header_size >> 2) << 12) |
 					tcb->flags);
 
 	if (unlikely(tcb->flags & TCPCB_FLAG_SYN)) {
@@ -426,7 +432,7 @@
 	}
 
 	if (unlikely(tcb->flags & TCPCB_FLAG_SYN)) {
-		tcp_syn_build_options((__u32 *)(th + 1),
+		tcp_syn_build_options((__be32 *)(th + 1),
 				      tcp_advertise_mss(sk),
 				      (sysctl_flags & SYSCTL_FLAG_TSTAMPS),
 				      (sysctl_flags & SYSCTL_FLAG_SACK),
@@ -435,7 +441,7 @@
 				      tcb->when,
 				      tp->rx_opt.ts_recent);
 	} else {
-		tcp_build_and_update_options((__u32 *)(th + 1),
+		tcp_build_and_update_options((__be32 *)(th + 1),
 					     tp, tcb->when);
 		TCP_ECN_send(sk, tp, skb, tcp_header_size);
 	}
@@ -681,6 +687,62 @@
 	return 0;
 }
 
+/* Not accounting for SACKs here. */
+int tcp_mtu_to_mss(struct sock *sk, int pmtu)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct inet_connection_sock *icsk = inet_csk(sk);
+	int mss_now;
+
+	/* Calculate base mss without TCP options:
+	   It is MMS_S - sizeof(tcphdr) of rfc1122
+	 */
+	mss_now = pmtu - icsk->icsk_af_ops->net_header_len - sizeof(struct tcphdr);
+
+	/* Clamp it (mss_clamp does not include tcp options) */
+	if (mss_now > tp->rx_opt.mss_clamp)
+		mss_now = tp->rx_opt.mss_clamp;
+
+	/* Now subtract optional transport overhead */
+	mss_now -= icsk->icsk_ext_hdr_len;
+
+	/* Then reserve room for full set of TCP options and 8 bytes of data */
+	if (mss_now < 48)
+		mss_now = 48;
+
+	/* Now subtract TCP options size, not including SACKs */
+	mss_now -= tp->tcp_header_len - sizeof(struct tcphdr);
+	
+	return mss_now;
+}
+
+/* Inverse of above */
+int tcp_mss_to_mtu(struct sock *sk, int mss)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct inet_connection_sock *icsk = inet_csk(sk);
+	int mtu;
+	
+	mtu = mss +
+	      tp->tcp_header_len +
+	      icsk->icsk_ext_hdr_len +
+	      icsk->icsk_af_ops->net_header_len;
+	
+	return mtu;
+}
+
+void tcp_mtup_init(struct sock *sk)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct inet_connection_sock *icsk = inet_csk(sk);
+	
+	icsk->icsk_mtup.enabled = sysctl_tcp_mtu_probing > 1;
+	icsk->icsk_mtup.search_high = tp->rx_opt.mss_clamp + sizeof(struct tcphdr) +
+	                       icsk->icsk_af_ops->net_header_len;
+	icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, sysctl_tcp_base_mss);
+	icsk->icsk_mtup.probe_size = 0;
+}
+
 /* This function synchronize snd mss to current pmtu/exthdr set.
 
    tp->rx_opt.user_mss is mss set by user by TCP_MAXSEG. It does NOT counts
@@ -708,25 +770,12 @@
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct inet_connection_sock *icsk = inet_csk(sk);
-	/* Calculate base mss without TCP options:
-	   It is MMS_S - sizeof(tcphdr) of rfc1122
-	 */
-	int mss_now = (pmtu - icsk->icsk_af_ops->net_header_len -
-		       sizeof(struct tcphdr));
-
-	/* Clamp it (mss_clamp does not include tcp options) */
-	if (mss_now > tp->rx_opt.mss_clamp)
-		mss_now = tp->rx_opt.mss_clamp;
-
-	/* Now subtract optional transport overhead */
-	mss_now -= icsk->icsk_ext_hdr_len;
+	int mss_now;
 
-	/* Then reserve room for full set of TCP options and 8 bytes of data */
-	if (mss_now < 48)
-		mss_now = 48;
+	if (icsk->icsk_mtup.search_high > pmtu)
+		icsk->icsk_mtup.search_high = pmtu;
 
-	/* Now subtract TCP options size, not including SACKs */
-	mss_now -= tp->tcp_header_len - sizeof(struct tcphdr);
+	mss_now = tcp_mtu_to_mss(sk, pmtu);
 
 	/* Bound mss with half of window */
 	if (tp->max_window && mss_now > (tp->max_window>>1))
@@ -734,6 +783,8 @@
 
 	/* And store cached results */
 	icsk->icsk_pmtu_cookie = pmtu;
+	if (icsk->icsk_mtup.enabled)
+		mss_now = min(mss_now, tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_low));
 	tp->mss_cache = mss_now;
 
 	return mss_now;
@@ -1059,6 +1110,140 @@
 	return 1;
 }
 
+/* Create a new MTU probe if we are ready.
+ * Returns 0 if we should wait to probe (no cwnd available),
+ *         1 if a probe was sent,
+ *         -1 otherwise */
+static int tcp_mtu_probe(struct sock *sk)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct inet_connection_sock *icsk = inet_csk(sk);
+	struct sk_buff *skb, *nskb, *next;
+	int len;
+	int probe_size;
+	unsigned int pif;
+	int copy;
+	int mss_now;
+	
+	/* Not currently probing/verifying,
+	 * not in recovery,
+	 * have enough cwnd, and
+	 * not SACKing (the variable headers throw things off) */
+	if (!icsk->icsk_mtup.enabled ||
+	    icsk->icsk_mtup.probe_size ||
+	    inet_csk(sk)->icsk_ca_state != TCP_CA_Open ||
+	    tp->snd_cwnd < 11 ||
+	    tp->rx_opt.eff_sacks)
+		return -1;
+	
+	/* Very simple search strategy: just double the MSS. */
+	mss_now = tcp_current_mss(sk, 0);
+	probe_size = 2*tp->mss_cache;
+	if (probe_size > tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_high)) {
+		/* TODO: set timer for probe_converge_event */
+		return -1;
+	}
+
+	/* Have enough data in the send queue to probe? */
+	len = 0;
+	if ((skb = sk->sk_send_head) == NULL)
+		return -1;
+	while ((len += skb->len) < probe_size && !tcp_skb_is_last(sk, skb))
+		skb = skb->next;
+	if (len < probe_size)
+		return -1;
+	
+	/* Receive window check. */
+	if (after(TCP_SKB_CB(skb)->seq + probe_size, tp->snd_una + tp->snd_wnd)) {
+		if (tp->snd_wnd < probe_size)
+			return -1;
+		else
+			return 0;
+	}
+	
+	/* Do we need to wait to drain cwnd? */
+	pif = tcp_packets_in_flight(tp);
+	if (pif + 2 > tp->snd_cwnd) {
+		/* With no packets in flight, don't stall. */
+		if (pif == 0)
+			return -1;
+		else
+			return 0;
+	}
+	
+	/* We're allowed to probe.  Build it now. */
+	if ((nskb = sk_stream_alloc_skb(sk, probe_size, GFP_ATOMIC)) == NULL)
+		return -1;
+	sk_charge_skb(sk, nskb);
+	
+	skb = sk->sk_send_head;
+	__skb_insert(nskb, skb->prev, skb, &sk->sk_write_queue);
+	sk->sk_send_head = nskb;
+	
+	TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(skb)->seq;
+	TCP_SKB_CB(nskb)->end_seq = TCP_SKB_CB(skb)->seq + probe_size;
+	TCP_SKB_CB(nskb)->flags = TCPCB_FLAG_ACK;
+	TCP_SKB_CB(nskb)->sacked = 0;
+	nskb->csum = 0;
+	if (skb->ip_summed == CHECKSUM_HW)
+		nskb->ip_summed = CHECKSUM_HW;
+	
+	len = 0;
+	while (len < probe_size) {
+		next = skb->next;
+		
+		copy = min_t(int, skb->len, probe_size - len);
+		if (nskb->ip_summed)
+			skb_copy_bits(skb, 0, skb_put(nskb, copy), copy);
+		else
+			nskb->csum = skb_copy_and_csum_bits(skb, 0,
+			                 skb_put(nskb, copy), copy, nskb->csum);
+		
+		if (skb->len <= copy) {
+			/* We've eaten all the data from this skb.
+			 * Throw it away. */
+			TCP_SKB_CB(nskb)->flags |= TCP_SKB_CB(skb)->flags;
+			__skb_unlink(skb, &sk->sk_write_queue);
+			sk_stream_free_skb(sk, skb);
+		} else {
+			TCP_SKB_CB(nskb)->flags |= TCP_SKB_CB(skb)->flags &
+			                           ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH);
+			if (!skb_shinfo(skb)->nr_frags) {
+				skb_pull(skb, copy);
+				if (skb->ip_summed != CHECKSUM_HW)
+					skb->csum = csum_partial(skb->data, skb->len, 0);
+			} else {
+				__pskb_trim_head(skb, copy);
+				tcp_set_skb_tso_segs(sk, skb, mss_now);
+			}
+			TCP_SKB_CB(skb)->seq += copy;
+		}
+		
+		len += copy;
+		skb = next;
+	}
+	tcp_init_tso_segs(sk, nskb, nskb->len);
+	
+	/* We're ready to send.  If this fails, the probe will
+	 * be resegmented into mss-sized pieces by tcp_write_xmit(). */
+	TCP_SKB_CB(nskb)->when = tcp_time_stamp;
+	if (!tcp_transmit_skb(sk, nskb, 1, GFP_ATOMIC)) {
+		/* Decrement cwnd here because we are sending 
+		* effectively two packets. */
+		tp->snd_cwnd--;
+		update_send_head(sk, tp, nskb);
+		
+		icsk->icsk_mtup.probe_size = tcp_mss_to_mtu(sk, nskb->len);
+		icsk->icsk_mtup.probe_seq_start = TCP_SKB_CB(nskb)->seq;
+		icsk->icsk_mtup.probe_seq_end = TCP_SKB_CB(nskb)->end_seq;
+		
+		return 1;
+	}
+	
+	return -1;
+}
+
+
 /* This routine writes packets to the network.  It advances the
  * send_head.  This happens as incoming acks open up the remote
  * window for us.
@@ -1072,6 +1257,7 @@
 	struct sk_buff *skb;
 	unsigned int tso_segs, sent_pkts;
 	int cwnd_quota;
+	int result;
 
 	/* If we are closed, the bytes will have to remain here.
 	 * In time closedown will finish, we empty the write queue and all
@@ -1081,12 +1267,20 @@
 		return 0;
 
 	sent_pkts = 0;
+	
+	/* Do MTU probing. */
+	if ((result = tcp_mtu_probe(sk)) == 0) {
+		return 0;
+	} else if (result > 0) {
+		sent_pkts = 1;
+	}
+	
 	while ((skb = sk->sk_send_head)) {
 		unsigned int limit;
 
 		tso_segs = tcp_init_tso_segs(sk, skb, mss_now);
 		BUG_ON(!tso_segs);
-
+		
 		cwnd_quota = tcp_cwnd_test(tp, skb);
 		if (!cwnd_quota)
 			break;
@@ -1451,9 +1645,15 @@
 int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
+	struct inet_connection_sock *icsk = inet_csk(sk);
  	unsigned int cur_mss = tcp_current_mss(sk, 0);
 	int err;
-
+	
+	/* Inconslusive MTU probe */
+	if (icsk->icsk_mtup.probe_size) {
+		icsk->icsk_mtup.probe_size = 0;
+	}
+	
 	/* Do not sent more than we queued. 1/4 is reserved for possible
 	 * copying overhead: fragmentation, tunneling, mangling etc.
 	 */
@@ -1849,7 +2049,7 @@
 	th->window = htons(req->rcv_wnd);
 
 	TCP_SKB_CB(skb)->when = tcp_time_stamp;
-	tcp_syn_build_options((__u32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok,
+	tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok,
 			      ireq->sack_ok, ireq->wscale_ok, ireq->rcv_wscale,
 			      TCP_SKB_CB(skb)->when,
 			      req->ts_recent);
@@ -1879,6 +2079,7 @@
 	if (tp->rx_opt.user_mss)
 		tp->rx_opt.mss_clamp = tp->rx_opt.user_mss;
 	tp->max_window = 0;
+	tcp_mtup_init(sk);
 	tcp_sync_mss(sk, dst_mtu(dst));
 
 	if (!tp->window_clamp)
@@ -2176,3 +2377,4 @@
 EXPORT_SYMBOL(tcp_simple_retransmit);
 EXPORT_SYMBOL(tcp_sync_mss);
 EXPORT_SYMBOL(sysctl_tcp_tso_win_divisor);
+EXPORT_SYMBOL(tcp_mtup_init);
diff -urN oldtree/net/ipv4/tcp_timer.c newtree/net/ipv4/tcp_timer.c
--- oldtree/net/ipv4/tcp_timer.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/ipv4/tcp_timer.c	2006-02-21 15:58:37.166496392 +0000
@@ -119,8 +119,10 @@
 /* A write timeout has occurred. Process the after effects. */
 static int tcp_write_timeout(struct sock *sk)
 {
-	const struct inet_connection_sock *icsk = inet_csk(sk);
+	struct inet_connection_sock *icsk = inet_csk(sk);
+	struct tcp_sock *tp = tcp_sk(sk);
 	int retry_until;
+	int mss;
 
 	if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
 		if (icsk->icsk_retransmits)
@@ -128,25 +130,19 @@
 		retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries;
 	} else {
 		if (icsk->icsk_retransmits >= sysctl_tcp_retries1) {
-			/* NOTE. draft-ietf-tcpimpl-pmtud-01.txt requires pmtu black
-			   hole detection. :-(
-
-			   It is place to make it. It is not made. I do not want
-			   to make it. It is disgusting. It does not work in any
-			   case. Let me to cite the same draft, which requires for
-			   us to implement this:
-
-   "The one security concern raised by this memo is that ICMP black holes
-   are often caused by over-zealous security administrators who block
-   all ICMP messages.  It is vitally important that those who design and
-   deploy security systems understand the impact of strict filtering on
-   upper-layer protocols.  The safest web site in the world is worthless
-   if most TCP implementations cannot transfer data from it.  It would
-   be far nicer to have all of the black holes fixed rather than fixing
-   all of the TCP implementations."
-
-                           Golden words :-).
-		   */
+			/* Black hole detection */
+			if (sysctl_tcp_mtu_probing) {
+				if (!icsk->icsk_mtup.enabled) {
+					icsk->icsk_mtup.enabled = 1;
+					tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
+				} else {
+					mss = min(sysctl_tcp_base_mss,
+					          tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_low)/2);
+					mss = max(mss, 68 - tp->tcp_header_len);
+					icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, mss);
+					tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
+				}
+			}
 
 			dst_negative_advice(&sk->sk_dst_cache);
 		}
@@ -301,7 +297,7 @@
 		if (net_ratelimit()) {
 			struct inet_sock *inet = inet_sk(sk);
 			printk(KERN_DEBUG "TCP: Treason uncloaked! Peer %u.%u.%u.%u:%u/%u shrinks window %u:%u. Repaired.\n",
-			       NIPQUAD(inet->daddr), htons(inet->dport),
+			       NIPQUAD(inet->daddr), ntohs(inet->dport),
 			       inet->num, tp->snd_una, tp->snd_nxt);
 		}
 #endif
diff -urN oldtree/net/ipv4/udp.c newtree/net/ipv4/udp.c
--- oldtree/net/ipv4/udp.c	2006-02-19 11:41:06.407369032 +0000
+++ newtree/net/ipv4/udp.c	2006-02-21 15:58:37.168496088 +0000
@@ -221,8 +221,8 @@
 /* UDP is nearly always wildcards out the wazoo, it makes no sense to try
  * harder than this. -DaveM
  */
-static struct sock *udp_v4_lookup_longway(u32 saddr, u16 sport,
-					  u32 daddr, u16 dport, int dif)
+static struct sock *udp_v4_lookup_longway(__be32 saddr, __be16 sport,
+					  __be32 daddr, __be16 dport, int dif)
 {
 	struct sock *sk, *result = NULL;
 	struct hlist_node *node;
@@ -266,8 +266,8 @@
 	return result;
 }
 
-static __inline__ struct sock *udp_v4_lookup(u32 saddr, u16 sport,
-					     u32 daddr, u16 dport, int dif)
+static __inline__ struct sock *udp_v4_lookup(__be32 saddr, __be16 sport,
+					     __be32 daddr, __be16 dport, int dif)
 {
 	struct sock *sk;
 
@@ -280,8 +280,8 @@
 }
 
 static inline struct sock *udp_v4_mcast_next(struct sock *sk,
-					     u16 loc_port, u32 loc_addr,
-					     u16 rmt_port, u32 rmt_addr,
+					     __be16 loc_port, __be32 loc_addr,
+					     __be16 rmt_port, __be32 rmt_addr,
 					     int dif)
 {
 	struct hlist_node *node;
@@ -476,7 +476,7 @@
 }
 
 
-static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr, unsigned long base)
+static unsigned short udp_check(struct udphdr *uh, int len, __be32 saddr, __be32 daddr, unsigned long base)
 {
 	return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base));
 }
@@ -491,8 +491,8 @@
 	struct rtable *rt = NULL;
 	int free = 0;
 	int connected = 0;
-	u32 daddr, faddr, saddr;
-	u16 dport;
+	__be32 daddr, faddr, saddr;
+	__be16 dport;
 	u8  tos;
 	int err;
 	int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
@@ -898,7 +898,7 @@
 	int iphlen, len;
   
 	__u8 *udpdata = (__u8 *)uh + sizeof(struct udphdr);
-	__u32 *udpdata32 = (__u32 *)udpdata;
+	__be32 *udpdata32 = (__be32 *)udpdata;
 	__u16 encap_type = up->encap_type;
 
 	/* if we're overly short, let UDP handle it */
@@ -1043,7 +1043,7 @@
  *	so we don't need to lock the hashes.
  */
 static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh,
-				 u32 saddr, u32 daddr)
+				 __be32 saddr, __be32 daddr)
 {
 	struct sock *sk;
 	int dif;
@@ -1084,7 +1084,7 @@
  * including udp header and folding it to skb->csum.
  */
 static void udp_checksum_init(struct sk_buff *skb, struct udphdr *uh,
-			     unsigned short ulen, u32 saddr, u32 daddr)
+			     unsigned short ulen, __be32 saddr, __be32 daddr)
 {
 	if (uh->check == 0) {
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1109,8 +1109,8 @@
   	struct udphdr *uh;
 	unsigned short ulen;
 	struct rtable *rt = (struct rtable*)skb->dst;
-	u32 saddr = skb->nh.iph->saddr;
-	u32 daddr = skb->nh.iph->daddr;
+	__be32 saddr = skb->nh.iph->saddr;
+	__be32 daddr = skb->nh.iph->daddr;
 	int len = skb->len;
 
 	/*
@@ -1494,8 +1494,8 @@
 static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket)
 {
 	struct inet_sock *inet = inet_sk(sp);
-	unsigned int dest = inet->daddr;
-	unsigned int src  = inet->rcv_saddr;
+	__be32 dest = inet->daddr;
+	__be32 src  = inet->rcv_saddr;
 	__u16 destp	  = ntohs(inet->dport);
 	__u16 srcp	  = ntohs(inet->sport);
 
diff -urN oldtree/net/ipv4/xfrm4_input.c newtree/net/ipv4/xfrm4_input.c
--- oldtree/net/ipv4/xfrm4_input.c	2006-02-19 11:41:06.409368728 +0000
+++ newtree/net/ipv4/xfrm4_input.c	2006-02-21 15:58:37.168496088 +0000
@@ -33,7 +33,7 @@
 		IP_ECN_set_ce(inner_iph);
 }
 
-static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
+static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
 {
 	switch (nexthdr) {
 	case IPPROTO_IPIP:
@@ -67,7 +67,7 @@
 int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
 {
 	int err;
-	u32 spi, seq;
+	__be32 spi, seq;
 	struct sec_decap_state xfrm_vec[XFRM_MAX_DEPTH];
 	struct xfrm_state *x;
 	int xfrm_nr = 0;
diff -urN oldtree/net/ipv4/xfrm4_policy.c newtree/net/ipv4/xfrm4_policy.c
--- oldtree/net/ipv4/xfrm4_policy.c	2006-02-19 11:41:06.410368576 +0000
+++ newtree/net/ipv4/xfrm4_policy.c	2006-02-21 15:58:37.168496088 +0000
@@ -55,8 +55,8 @@
 	struct dst_entry *dst, *dst_prev;
 	struct rtable *rt0 = (struct rtable*)(*dst_p);
 	struct rtable *rt = rt0;
-	u32 remote = fl->fl4_dst;
-	u32 local  = fl->fl4_src;
+	__be32 remote = fl->fl4_dst;
+	__be32 local  = fl->fl4_src;
 	struct flowi fl_tunnel = {
 		.nl_u = {
 			.ip4_u = {
@@ -183,7 +183,7 @@
 		case IPPROTO_SCTP:
 		case IPPROTO_DCCP:
 			if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
-				u16 *ports = (u16 *)xprth;
+				__be16 *ports = (__be16 *)xprth;
 
 				fl->fl_ip_sport = ports[0];
 				fl->fl_ip_dport = ports[1];
@@ -201,7 +201,7 @@
 
 		case IPPROTO_ESP:
 			if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
-				u32 *ehdr = (u32 *)xprth;
+				__be32 *ehdr = (__be32 *)xprth;
 
 				fl->fl_ipsec_spi = ehdr[0];
 			}
@@ -209,7 +209,7 @@
 
 		case IPPROTO_AH:
 			if (pskb_may_pull(skb, xprth + 8 - skb->data)) {
-				u32 *ah_hdr = (u32*)xprth;
+				__be32 *ah_hdr = (__be32*)xprth;
 
 				fl->fl_ipsec_spi = ah_hdr[1];
 			}
@@ -217,9 +217,9 @@
 
 		case IPPROTO_COMP:
 			if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
-				u16 *ipcomp_hdr = (u16 *)xprth;
+				__be16 *ipcomp_hdr = (__be16 *)xprth;
 
-				fl->fl_ipsec_spi = ntohl(ntohs(ipcomp_hdr[1]));
+				fl->fl_ipsec_spi = htonl(ntohs(ipcomp_hdr[1]));
 			}
 			break;
 		default:
diff -urN oldtree/net/ipv4/xfrm4_state.c newtree/net/ipv4/xfrm4_state.c
--- oldtree/net/ipv4/xfrm4_state.c	2006-02-19 11:41:06.410368576 +0000
+++ newtree/net/ipv4/xfrm4_state.c	2006-02-21 15:58:37.169495936 +0000
@@ -29,9 +29,9 @@
 	x->sel.daddr.a4 = fl->fl4_dst;
 	x->sel.saddr.a4 = fl->fl4_src;
 	x->sel.dport = xfrm_flowi_dport(fl);
-	x->sel.dport_mask = ~0;
+	x->sel.dport_mask = htons(0xffff);
 	x->sel.sport = xfrm_flowi_sport(fl);
-	x->sel.sport_mask = ~0;
+	x->sel.sport_mask = htons(0xffff);
 	x->sel.prefixlen_d = 32;
 	x->sel.prefixlen_s = 32;
 	x->sel.proto = fl->proto;
@@ -63,7 +63,7 @@
 }
 
 static struct xfrm_state *
-__xfrm4_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto)
+__xfrm4_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto)
 {
 	unsigned h = __xfrm4_spi_hash(daddr, spi, proto);
 	struct xfrm_state *x;
diff -urN oldtree/net/ipv4/xfrm4_tunnel.c newtree/net/ipv4/xfrm4_tunnel.c
--- oldtree/net/ipv4/xfrm4_tunnel.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/ipv4/xfrm4_tunnel.c	2006-02-21 15:58:16.641616648 +0000
@@ -5,6 +5,7 @@
 
 #include <linux/skbuff.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <net/xfrm.h>
 #include <net/ip.h>
 #include <net/protocol.h>
@@ -26,19 +27,19 @@
 }
 
 static struct xfrm_tunnel *ipip_handler;
-static DECLARE_MUTEX(xfrm4_tunnel_sem);
+static DEFINE_MUTEX(xfrm4_tunnel_mutex);
 
 int xfrm4_tunnel_register(struct xfrm_tunnel *handler)
 {
 	int ret;
 
-	down(&xfrm4_tunnel_sem);
+	mutex_lock(&xfrm4_tunnel_mutex);
 	ret = 0;
 	if (ipip_handler != NULL)
 		ret = -EINVAL;
 	if (!ret)
 		ipip_handler = handler;
-	up(&xfrm4_tunnel_sem);
+	mutex_unlock(&xfrm4_tunnel_mutex);
 
 	return ret;
 }
@@ -49,13 +50,13 @@
 {
 	int ret;
 
-	down(&xfrm4_tunnel_sem);
+	mutex_lock(&xfrm4_tunnel_mutex);
 	ret = 0;
 	if (ipip_handler != handler)
 		ret = -EINVAL;
 	if (!ret)
 		ipip_handler = NULL;
-	up(&xfrm4_tunnel_sem);
+	mutex_unlock(&xfrm4_tunnel_mutex);
 
 	synchronize_net();
 
diff -urN oldtree/net/ipv6/Kconfig newtree/net/ipv6/Kconfig
--- oldtree/net/ipv6/Kconfig	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/ipv6/Kconfig	2006-02-21 15:58:16.413651304 +0000
@@ -6,8 +6,6 @@
 config IPV6
 	tristate "The IPv6 protocol"
 	default m
-	select CRYPTO if IPV6_PRIVACY
-	select CRYPTO_MD5 if IPV6_PRIVACY
 	---help---
 	  This is complemental support for the IP version 6.
 	  You will still be able to do traditional IPv4 networking as well.
@@ -22,7 +20,7 @@
 	  module will be called ipv6.
 
 config IPV6_PRIVACY
-	bool "IPv6: Privacy Extensions (RFC 3041) support"
+	bool "IPv6: Privacy Extensions support"
 	depends on IPV6
 	---help---
 	  Privacy Extensions for Stateless Address Autoconfiguration in IPv6
@@ -30,6 +28,9 @@
 	  pseudo-random global-scope unicast address(es) will assigned to
 	  your interface(s).
 	
+	  We use our standard pseudo random algorithm to generate randomized
+	  interface identifier, instead of one described in RFC 3041.
+	
 	  By default, kernel do not generate temporary addresses.
 	  To use temporary addresses, do
 	
@@ -37,6 +38,25 @@
 
 	  See <file:Documentation/networking/ip-sysctl.txt> for details.
 
+config IPV6_ROUTER_PREF
+	bool "IPv6: Router Preference (RFC 4191) support"
+	depends on IPV6
+	---help---
+	  Router Preference is an optional extension to the Router
+	  Advertisement message to improve the ability of hosts
+	  to pick more appropriate router, especially when the hosts
+	  is placed in a multi-homed network.
+
+	  If unsure, say N.
+
+config IPV6_ROUTE_INFO
+	bool "IPv6: Route Information (RFC 4191) support (EXPERIMENTAL)"
+	depends on IPV6_ROUTER_PREF && EXPERIMENTAL
+	---help---
+	  This is experimental support of Route Information.
+
+	  If unsure, say N.
+
 config INET6_AH
 	tristate "IPv6: AH transformation"
 	depends on IPV6
diff -urN oldtree/net/ipv6/addrconf.c newtree/net/ipv6/addrconf.c
--- oldtree/net/ipv6/addrconf.c	2006-02-19 11:41:06.412368272 +0000
+++ newtree/net/ipv6/addrconf.c	2006-02-21 15:58:16.416650848 +0000
@@ -78,8 +78,6 @@
 
 #ifdef CONFIG_IPV6_PRIVACY
 #include <linux/random.h>
-#include <linux/crypto.h>
-#include <linux/scatterlist.h>
 #endif
 
 #include <asm/uaccess.h>
@@ -110,8 +108,6 @@
 static void ipv6_regen_rndid(unsigned long data);
 
 static int desync_factor = MAX_DESYNC_FACTOR * HZ;
-static struct crypto_tfm *md5_tfm;
-static DEFINE_SPINLOCK(md5_tfm_lock);
 #endif
 
 static int ipv6_count_addresses(struct inet6_dev *idev);
@@ -169,6 +165,15 @@
 	.max_desync_factor	= MAX_DESYNC_FACTOR,
 #endif
 	.max_addresses		= IPV6_MAX_ADDRESSES,
+	.accept_ra_defrtr	= 1,
+	.accept_ra_pinfo	= 1,
+#ifdef CONFIG_IPV6_ROUTER_PREF
+	.accept_ra_rtr_pref	= 1,
+	.rtr_probe_interval	= 60 * HZ,
+#ifdef CONFIG_IPV6_ROUTE_INFO
+	.accept_ra_rt_info_max_plen = 0,
+#endif
+#endif
 };
 
 static struct ipv6_devconf ipv6_devconf_dflt = {
@@ -190,6 +195,15 @@
 	.max_desync_factor	= MAX_DESYNC_FACTOR,
 #endif
 	.max_addresses		= IPV6_MAX_ADDRESSES,
+	.accept_ra_defrtr	= 1,
+	.accept_ra_pinfo	= 1,
+#ifdef CONFIG_IPV6_ROUTER_PREF
+	.accept_ra_rtr_pref	= 1,
+	.rtr_probe_interval	= 60 * HZ,
+#ifdef CONFIG_IPV6_ROUTE_INFO
+	.accept_ra_rt_info_max_plen = 0,
+#endif
+#endif
 };
 
 /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
@@ -371,8 +385,6 @@
 		in6_dev_hold(ndev);
 
 #ifdef CONFIG_IPV6_PRIVACY
-		get_random_bytes(ndev->rndid, sizeof(ndev->rndid));
-		get_random_bytes(ndev->entropy, sizeof(ndev->entropy));
 		init_timer(&ndev->regen_timer);
 		ndev->regen_timer.function = ipv6_regen_rndid;
 		ndev->regen_timer.data = (unsigned long) ndev;
@@ -1305,52 +1317,67 @@
 	__ipv6_dev_ac_dec(ifp->idev, &addr);
 }
 
+static int addrconf_ifid_eui48(u8 *eui, struct net_device *dev)
+{
+	if (dev->addr_len != ETH_ALEN)
+		return -1;
+	memcpy(eui, dev->dev_addr, 3);
+	memcpy(eui + 5, dev->dev_addr + 3, 3);
+
+	/*
+	 * The zSeries OSA network cards can be shared among various
+	 * OS instances, but the OSA cards have only one MAC address.
+	 * This leads to duplicate address conflicts in conjunction
+	 * with IPv6 if more than one instance uses the same card.
+	 * 
+	 * The driver for these cards can deliver a unique 16-bit
+	 * identifier for each instance sharing the same card.  It is
+	 * placed instead of 0xFFFE in the interface identifier.  The
+	 * "u" bit of the interface identifier is not inverted in this
+	 * case.  Hence the resulting interface identifier has local
+	 * scope according to RFC2373.
+	 */
+	if (dev->dev_id) {
+		eui[3] = (dev->dev_id >> 8) & 0xFF;
+		eui[4] = dev->dev_id & 0xFF;
+	} else {
+		eui[3] = 0xFF;
+		eui[4] = 0xFE;
+		eui[0] ^= 2;
+	}
+	return 0;
+}
+
+static int addrconf_ifid_arcnet(u8 *eui, struct net_device *dev)
+{
+	/* XXX: inherit EUI-64 from other interface -- yoshfuji */
+	if (dev->addr_len != ARCNET_ALEN)
+		return -1;
+	memset(eui, 0, 7);
+	eui[7] = *(u8*)dev->dev_addr;
+	return 0;
+}
+
+static int addrconf_ifid_infiniband(u8 *eui, struct net_device *dev)
+{
+	if (dev->addr_len != INFINIBAND_ALEN)
+		return -1;
+	memcpy(eui, dev->dev_addr + 12, 8);
+	eui[0] |= 2;
+	return 0;
+}
+
 static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
 {
 	switch (dev->type) {
 	case ARPHRD_ETHER:
 	case ARPHRD_FDDI:
 	case ARPHRD_IEEE802_TR:
-		if (dev->addr_len != ETH_ALEN)
-			return -1;
-		memcpy(eui, dev->dev_addr, 3);
-		memcpy(eui + 5, dev->dev_addr + 3, 3);
-
-		/*
-		 * The zSeries OSA network cards can be shared among various
-		 * OS instances, but the OSA cards have only one MAC address.
-		 * This leads to duplicate address conflicts in conjunction
-		 * with IPv6 if more than one instance uses the same card.
-		 * 
-		 * The driver for these cards can deliver a unique 16-bit
-		 * identifier for each instance sharing the same card.  It is
-		 * placed instead of 0xFFFE in the interface identifier.  The
-		 * "u" bit of the interface identifier is not inverted in this
-		 * case.  Hence the resulting interface identifier has local
-		 * scope according to RFC2373.
-		 */
-		if (dev->dev_id) {
-			eui[3] = (dev->dev_id >> 8) & 0xFF;
-			eui[4] = dev->dev_id & 0xFF;
-		} else {
-			eui[3] = 0xFF;
-			eui[4] = 0xFE;
-			eui[0] ^= 2;
-		}
-		return 0;
+		return addrconf_ifid_eui48(eui, dev);
 	case ARPHRD_ARCNET:
-		/* XXX: inherit EUI-64 from other interface -- yoshfuji */
-		if (dev->addr_len != ARCNET_ALEN)
-			return -1;
-		memset(eui, 0, 7);
-		eui[7] = *(u8*)dev->dev_addr;
-		return 0;
+		return addrconf_ifid_arcnet(eui, dev);
 	case ARPHRD_INFINIBAND:
-		if (dev->addr_len != INFINIBAND_ALEN)
-			return -1;
-		memcpy(eui, dev->dev_addr + 12, 8);
-		eui[0] |= 2;
-		return 0;
+		return addrconf_ifid_infiniband(eui, dev);
 	}
 	return -1;
 }
@@ -1376,34 +1403,9 @@
 /* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */
 static int __ipv6_regen_rndid(struct inet6_dev *idev)
 {
-	struct net_device *dev;
-	struct scatterlist sg[2];
-
-	sg_set_buf(&sg[0], idev->entropy, 8);
-	sg_set_buf(&sg[1], idev->work_eui64, 8);
-
-	dev = idev->dev;
-
-	if (ipv6_generate_eui64(idev->work_eui64, dev)) {
-		printk(KERN_INFO
-			"__ipv6_regen_rndid(idev=%p): cannot get EUI64 identifier; use random bytes.\n",
-			idev);
-		get_random_bytes(idev->work_eui64, sizeof(idev->work_eui64));
-	}
 regen:
-	spin_lock(&md5_tfm_lock);
-	if (unlikely(md5_tfm == NULL)) {
-		spin_unlock(&md5_tfm_lock);
-		return -1;
-	}
-	crypto_digest_init(md5_tfm);
-	crypto_digest_update(md5_tfm, sg, 2);
-	crypto_digest_final(md5_tfm, idev->work_digest);
-	spin_unlock(&md5_tfm_lock);
-
-	memcpy(idev->rndid, &idev->work_digest[0], 8);
+	get_random_bytes(idev->rndid, sizeof(idev->rndid));
 	idev->rndid[0] &= ~0x02;
-	memcpy(idev->entropy, &idev->work_digest[8], 8);
 
 	/*
 	 * <draft-ietf-ipngwg-temp-addresses-v2-00.txt>:
@@ -2143,7 +2145,6 @@
 		return;
 	}
 	ip6_tnl_add_linklocal(idev);
-	addrconf_add_mroute(dev);
 }
 
 static int addrconf_notify(struct notifier_block *this, unsigned long event, 
@@ -3133,6 +3134,15 @@
 	array[DEVCONF_MAX_DESYNC_FACTOR] = cnf->max_desync_factor;
 #endif
 	array[DEVCONF_MAX_ADDRESSES] = cnf->max_addresses;
+	array[DEVCONF_ACCEPT_RA_DEFRTR] = cnf->accept_ra_defrtr;
+	array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo;
+#ifdef CONFIG_IPV6_ROUTER_PREF
+	array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref;
+	array[DEVCONF_RTR_PROBE_INTERVAL] = cnf->rtr_probe_interval;
+#ifdef CONFIV_IPV6_ROUTE_INFO
+	array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen;
+#endif
+#endif
 }
 
 static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, 
@@ -3586,6 +3596,51 @@
 			.proc_handler	=	&proc_dointvec,
 		},
 		{
+			.ctl_name	=	NET_IPV6_ACCEPT_RA_DEFRTR,
+			.procname	=	"accept_ra_defrtr",
+         		.data		=	&ipv6_devconf.accept_ra_defrtr,
+			.maxlen		=	sizeof(int),
+			.mode		=	0644,
+         		.proc_handler	=	&proc_dointvec,
+		},
+		{
+			.ctl_name	=	NET_IPV6_ACCEPT_RA_PINFO,
+			.procname	=	"accept_ra_pinfo",
+         		.data		=	&ipv6_devconf.accept_ra_pinfo,
+			.maxlen		=	sizeof(int),
+			.mode		=	0644,
+         		.proc_handler	=	&proc_dointvec,
+		},
+#ifdef CONFIG_IPV6_ROUTER_PREF
+		{
+			.ctl_name	=	NET_IPV6_ACCEPT_RA_RTR_PREF,
+			.procname	=	"accept_ra_rtr_pref",
+			.data		=	&ipv6_devconf.accept_ra_rtr_pref,
+			.maxlen		=	sizeof(int),
+			.mode		=	0644,
+			.proc_handler	=	&proc_dointvec,
+		},
+		{
+			.ctl_name	=	NET_IPV6_RTR_PROBE_INTERVAL,
+			.procname	=	"router_probe_interval",
+			.data		=	&ipv6_devconf.rtr_probe_interval,
+			.maxlen		=	sizeof(int),
+			.mode		=	0644,
+			.proc_handler	=	&proc_dointvec_jiffies,
+			.strategy	=	&sysctl_jiffies,
+		},
+#ifdef CONFIV_IPV6_ROUTE_INFO
+		{
+			.ctl_name	=	NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN,
+			.procname	=	"accept_ra_rt_info_max_plen",
+			.data		=	&ipv6_devconf.accept_ra_rt_info_max_plen,
+			.maxlen		=	sizeof(int),
+			.mode		=	0644,
+			.proc_handler	=	&proc_dointvec,
+		},
+#endif
+#endif
+		{
 			.ctl_name	=	0,	/* sentinel */
 		}
 	},
@@ -3760,13 +3815,6 @@
 
 	register_netdevice_notifier(&ipv6_dev_notf);
 
-#ifdef CONFIG_IPV6_PRIVACY
-	md5_tfm = crypto_alloc_tfm("md5", 0);
-	if (unlikely(md5_tfm == NULL))
-		printk(KERN_WARNING
-			"failed to load transform for md5\n");
-#endif
-
 	addrconf_verify(0);
 	rtnetlink_links[PF_INET6] = inet6_rtnetlink_table;
 #ifdef CONFIG_SYSCTL
@@ -3829,11 +3877,6 @@
 
 	rtnl_unlock();
 
-#ifdef CONFIG_IPV6_PRIVACY
-	crypto_free_tfm(md5_tfm);
-	md5_tfm = NULL;
-#endif
-
 #ifdef CONFIG_PROC_FS
 	proc_net_remove("if_inet6");
 #endif
diff -urN oldtree/net/ipv6/af_inet6.c newtree/net/ipv6/af_inet6.c
--- oldtree/net/ipv6/af_inet6.c	2006-02-19 11:41:06.413368120 +0000
+++ newtree/net/ipv6/af_inet6.c	2006-02-21 15:58:37.200491224 +0000
@@ -244,7 +244,7 @@
 	struct sock *sk = sock->sk;
 	struct inet_sock *inet = inet_sk(sk);
 	struct ipv6_pinfo *np = inet6_sk(sk);
-	__u32 v4addr = 0;
+	__be32 v4addr = 0;
 	unsigned short snum;
 	int addr_type = 0;
 	int err = 0;
diff -urN oldtree/net/ipv6/ah6.c newtree/net/ipv6/ah6.c
--- oldtree/net/ipv6/ah6.c	2006-02-19 11:41:06.414367968 +0000
+++ newtree/net/ipv6/ah6.c	2006-02-21 15:58:37.200491224 +0000
@@ -213,6 +213,7 @@
 	ah->reserved = 0;
 	ah->spi = x->id.spi;
 	ah->seq_no = htonl(++x->replay.oseq);
+	xfrm_aevent_doreplay(x);
 	ahp->icv(ahp, skb, ah->auth_data);
 
 	err = 0;
@@ -318,7 +319,7 @@
 }
 
 static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 
-                    int type, int code, int offset, __u32 info)
+                    int type, int code, int offset, __be32 info)
 {
 	struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
 	struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+offset);
diff -urN oldtree/net/ipv6/datagram.c newtree/net/ipv6/datagram.c
--- oldtree/net/ipv6/datagram.c	2006-02-19 11:41:06.416367664 +0000
+++ newtree/net/ipv6/datagram.c	2006-02-21 15:58:37.201491072 +0000
@@ -200,7 +200,7 @@
 }
 
 void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, 
-		     u16 port, u32 info, u8 *payload)
+		     __be16 port, u32 info, u8 *payload)
 {
 	struct ipv6_pinfo *np  = inet6_sk(sk);
 	struct icmp6hdr *icmph = (struct icmp6hdr *)skb->h.raw;
@@ -311,13 +311,13 @@
 			ipv6_addr_copy(&sin->sin6_addr,
 			  (struct in6_addr *)(skb->nh.raw + serr->addr_offset));
 			if (np->sndflow)
-				sin->sin6_flowinfo = *(u32*)(skb->nh.raw + serr->addr_offset - 24) & IPV6_FLOWINFO_MASK;
+				sin->sin6_flowinfo = *(__be32*)(skb->nh.raw + serr->addr_offset - 24) & IPV6_FLOWINFO_MASK;
 			if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
 				sin->sin6_scope_id = IP6CB(skb)->iif;
 		} else {
 			ipv6_addr_set(&sin->sin6_addr, 0, 0,
 				      htonl(0xffff),
-				      *(u32*)(skb->nh.raw + serr->addr_offset));
+				      *(__be32*)(skb->nh.raw + serr->addr_offset));
 		}
 	}
 
@@ -390,12 +390,12 @@
 	}
 
 	if (np->rxopt.bits.rxtclass) {
-		int tclass = (ntohl(*(u32 *)skb->nh.ipv6h) >> 20) & 0xff;
+		int tclass = (ntohl(*(__be32 *)skb->nh.ipv6h) >> 20) & 0xff;
 		put_cmsg(msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass);
 	}
 
-	if (np->rxopt.bits.rxflow && (*(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK)) {
-		u32 flowinfo = *(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK;
+	if (np->rxopt.bits.rxflow && (*(__be32*)skb->nh.raw & IPV6_FLOWINFO_MASK)) {
+		__be32 flowinfo = *(__be32*)skb->nh.raw & IPV6_FLOWINFO_MASK;
 		put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo);
 	}
 
@@ -553,12 +553,12 @@
 			}
 
 			if (fl->fl6_flowlabel&IPV6_FLOWINFO_MASK) {
-				if ((fl->fl6_flowlabel^*(u32 *)CMSG_DATA(cmsg))&~IPV6_FLOWINFO_MASK) {
+				if ((fl->fl6_flowlabel^*(__be32 *)CMSG_DATA(cmsg))&~IPV6_FLOWINFO_MASK) {
 					err = -EINVAL;
 					goto exit_f;
 				}
 			}
-			fl->fl6_flowlabel = IPV6_FLOWINFO_MASK & *(u32 *)CMSG_DATA(cmsg);
+			fl->fl6_flowlabel = IPV6_FLOWINFO_MASK & *(__be32 *)CMSG_DATA(cmsg);
 			break;
 
 		case IPV6_2292HOPOPTS:
diff -urN oldtree/net/ipv6/esp6.c newtree/net/ipv6/esp6.c
--- oldtree/net/ipv6/esp6.c	2006-02-19 11:41:06.416367664 +0000
+++ newtree/net/ipv6/esp6.c	2006-02-21 15:58:16.417650696 +0000
@@ -94,6 +94,7 @@
 
 	esph->spi = x->id.spi;
 	esph->seq_no = htonl(++x->replay.oseq);
+	xfrm_aevent_doreplay(x);
 
 	if (esp->conf.ivlen)
 		crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm));
diff -urN oldtree/net/ipv6/icmp.c newtree/net/ipv6/icmp.c
--- oldtree/net/ipv6/icmp.c	2006-02-19 11:41:06.418367360 +0000
+++ newtree/net/ipv6/icmp.c	2006-02-21 15:58:37.235485904 +0000
@@ -528,7 +528,7 @@
 	icmpv6_xmit_unlock();
 }
 
-static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info)
+static void icmpv6_notify(struct sk_buff *skb, int type, int code, __be32 info)
 {
 	struct in6_addr *saddr, *daddr;
 	struct inet6_protocol *ipprot;
diff -urN oldtree/net/ipv6/inet6_hashtables.c newtree/net/ipv6/inet6_hashtables.c
--- oldtree/net/ipv6/inet6_hashtables.c	2006-02-19 11:41:06.419367208 +0000
+++ newtree/net/ipv6/inet6_hashtables.c	2006-02-21 15:58:37.236485752 +0000
@@ -67,8 +67,8 @@
 EXPORT_SYMBOL_GPL(inet6_lookup_listener);
 
 struct sock *inet6_lookup(struct inet_hashinfo *hashinfo,
-			  const struct in6_addr *saddr, const u16 sport,
-			  const struct in6_addr *daddr, const u16 dport,
+			  const struct in6_addr *saddr, const __be16 sport,
+			  const struct in6_addr *daddr, const __be16 dport,
 			  const int dif)
 {
 	struct sock *sk;
diff -urN oldtree/net/ipv6/ip6_fib.c newtree/net/ipv6/ip6_fib.c
--- oldtree/net/ipv6/ip6_fib.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/ipv6/ip6_fib.c	2006-02-21 15:58:16.418650544 +0000
@@ -1105,7 +1105,6 @@
 	if (rt->rt6i_flags&RTF_EXPIRES && rt->rt6i_expires) {
 		if (time_after(now, rt->rt6i_expires)) {
 			RT6_TRACE("expiring %p\n", rt);
-			rt6_reset_dflt_pointer(rt);
 			return -1;
 		}
 		gc_args.more++;
diff -urN oldtree/net/ipv6/ip6_flowlabel.c newtree/net/ipv6/ip6_flowlabel.c
--- oldtree/net/ipv6/ip6_flowlabel.c	2006-02-19 11:41:06.419367208 +0000
+++ newtree/net/ipv6/ip6_flowlabel.c	2006-02-21 15:58:37.257482560 +0000
@@ -62,7 +62,7 @@
 static DEFINE_RWLOCK(ip6_sk_fl_lock);
 
 
-static __inline__ struct ip6_flowlabel * __fl_lookup(u32 label)
+static __inline__ struct ip6_flowlabel * __fl_lookup(__be32 label)
 {
 	struct ip6_flowlabel *fl;
 
@@ -73,7 +73,7 @@
 	return NULL;
 }
 
-static struct ip6_flowlabel * fl_lookup(u32 label)
+static struct ip6_flowlabel * fl_lookup(__be32 label)
 {
 	struct ip6_flowlabel *fl;
 
@@ -154,7 +154,7 @@
 	write_unlock(&ip6_fl_lock);
 }
 
-static int fl_intern(struct ip6_flowlabel *fl, __u32 label)
+static int fl_intern(struct ip6_flowlabel *fl, __be32 label)
 {
 	fl->label = label & IPV6_FLOWLABEL_MASK;
 
@@ -183,7 +183,7 @@
 
 /* Socket flowlabel lists */
 
-struct ip6_flowlabel * fl6_sock_lookup(struct sock *sk, u32 label)
+struct ip6_flowlabel * fl6_sock_lookup(struct sock *sk, __be32 label)
 {
 	struct ipv6_fl_socklist *sfl;
 	struct ipv6_pinfo *np = inet6_sk(sk);
diff -urN oldtree/net/ipv6/ip6_output.c newtree/net/ipv6/ip6_output.c
--- oldtree/net/ipv6/ip6_output.c	2006-02-19 11:41:06.420367056 +0000
+++ newtree/net/ipv6/ip6_output.c	2006-02-21 15:58:37.320472984 +0000
@@ -217,7 +217,7 @@
 	if (tclass < 0)
 		tclass = 0;
 
-	*(u32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl->fl6_flowlabel;
+	*(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl->fl6_flowlabel;
 
 	hdr->payload_len = htons(seg_len);
 	hdr->nexthdr = proto;
@@ -267,7 +267,7 @@
 	hdr = (struct ipv6hdr *) skb_put(skb, sizeof(struct ipv6hdr));
 	skb->nh.ipv6h = hdr;
 
-	*(u32*)hdr = htonl(0x60000000);
+	*(__be32*)hdr = htonl(0x60000000);
 
 	hdr->payload_len = htons(len);
 	hdr->nexthdr = proto;
@@ -497,7 +497,7 @@
 	struct ipv6hdr *tmp_hdr;
 	struct frag_hdr *fh;
 	unsigned int mtu, hlen, left, len;
-	u32 frag_id = 0;
+	__be32 frag_id = 0;
 	int ptr, offset = 0, err=0;
 	u8 *prevhdr, nexthdr = 0;
 
@@ -1172,7 +1172,7 @@
 
 	skb->nh.ipv6h = hdr = (struct ipv6hdr*) skb_push(skb, sizeof(struct ipv6hdr));
 	
-	*(u32*)hdr = fl->fl6_flowlabel |
+	*(__be32*)hdr = fl->fl6_flowlabel |
 		     htonl(0x60000000 | ((int)np->cork.tclass << 20));
 
 	if (skb->len <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN)
diff -urN oldtree/net/ipv6/ip6_tunnel.c newtree/net/ipv6/ip6_tunnel.c
--- oldtree/net/ipv6/ip6_tunnel.c	2006-02-19 11:41:06.421366904 +0000
+++ newtree/net/ipv6/ip6_tunnel.c	2006-02-21 15:58:37.321472832 +0000
@@ -393,7 +393,7 @@
 
 static void 
 ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-	   int type, int code, int offset, __u32 info)
+	   int type, int code, int offset, __be32 info)
 {
 	struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data;
 	struct ip6_tnl *t;
diff -urN oldtree/net/ipv6/ipcomp6.c newtree/net/ipv6/ipcomp6.c
--- oldtree/net/ipv6/ipcomp6.c	2006-02-19 11:41:06.422366752 +0000
+++ newtree/net/ipv6/ipcomp6.c	2006-02-21 15:58:37.322472680 +0000
@@ -50,6 +50,7 @@
 #include <net/protocol.h>
 #include <linux/ipv6.h>
 #include <linux/icmpv6.h>
+#include <linux/mutex.h>
 
 struct ipcomp6_tfms {
 	struct list_head list;
@@ -57,7 +58,7 @@
 	int users;
 };
 
-static DECLARE_MUTEX(ipcomp6_resource_sem);
+static DEFINE_MUTEX(ipcomp6_resource_mutex);
 static void **ipcomp6_scratches;
 static int ipcomp6_scratch_users;
 static LIST_HEAD(ipcomp6_tfms_list);
@@ -197,9 +198,9 @@
 }
 
 static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-		                int type, int code, int offset, __u32 info)
+		                int type, int code, int offset, __be32 info)
 {
-	u32 spi;
+	__be32 spi;
 	struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
 	struct ipv6_comp_hdr *ipcomph = (struct ipv6_comp_hdr*)(skb->data+offset);
 	struct xfrm_state *x;
@@ -207,7 +208,7 @@
 	if (type != ICMPV6_DEST_UNREACH && type != ICMPV6_PKT_TOOBIG)
 		return;
 
-	spi = ntohl(ntohs(ipcomph->cpi));
+	spi = htonl(ntohs(ipcomph->cpi));
 	x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6);
 	if (!x)
 		return;
@@ -250,7 +251,7 @@
 {
 	int err = 0;
 	struct xfrm_state *t = NULL;
-	u32 spi;
+	__be32 spi;
 
 	spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&x->props.saddr);
 	if (spi)
@@ -286,8 +287,8 @@
 
 	for_each_cpu(i) {
 		void *scratch = *per_cpu_ptr(scratches, i);
-		if (scratch)
-			vfree(scratch);
+
+		vfree(scratch);
 	}
 
 	free_percpu(scratches);
@@ -405,9 +406,9 @@
 	if (!ipcd)
 		return;
 	xfrm_state_delete_tunnel(x);
-	down(&ipcomp6_resource_sem);
+	mutex_lock(&ipcomp6_resource_mutex);
 	ipcomp6_free_data(ipcd);
-	up(&ipcomp6_resource_sem);
+	mutex_unlock(&ipcomp6_resource_mutex);
 	kfree(ipcd);
 
 	xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr);
@@ -436,14 +437,14 @@
 	if (x->props.mode)
 		x->props.header_len += sizeof(struct ipv6hdr);
 	
-	down(&ipcomp6_resource_sem);
+	mutex_lock(&ipcomp6_resource_mutex);
 	if (!ipcomp6_alloc_scratches())
 		goto error;
 
 	ipcd->tfms = ipcomp6_alloc_tfms(x->calg->alg_name);
 	if (!ipcd->tfms)
 		goto error;
-	up(&ipcomp6_resource_sem);
+	mutex_unlock(&ipcomp6_resource_mutex);
 
 	if (x->props.mode) {
 		err = ipcomp6_tunnel_attach(x);
@@ -459,10 +460,10 @@
 out:
 	return err;
 error_tunnel:
-	down(&ipcomp6_resource_sem);
+	mutex_lock(&ipcomp6_resource_mutex);
 error:
 	ipcomp6_free_data(ipcd);
-	up(&ipcomp6_resource_sem);
+	mutex_unlock(&ipcomp6_resource_mutex);
 	kfree(ipcd);
 
 	goto out;
diff -urN oldtree/net/ipv6/ndisc.c newtree/net/ipv6/ndisc.c
--- oldtree/net/ipv6/ndisc.c	2006-02-19 11:41:06.425366296 +0000
+++ newtree/net/ipv6/ndisc.c	2006-02-21 15:58:16.420650240 +0000
@@ -156,7 +156,11 @@
 
 /* ND options */
 struct ndisc_options {
-	struct nd_opt_hdr *nd_opt_array[__ND_OPT_MAX];
+	struct nd_opt_hdr *nd_opt_array[__ND_OPT_ARRAY_MAX];
+#ifdef CONFIG_IPV6_ROUTE_INFO
+	struct nd_opt_hdr *nd_opts_ri;
+	struct nd_opt_hdr *nd_opts_ri_end;
+#endif
 };
 
 #define nd_opts_src_lladdr	nd_opt_array[ND_OPT_SOURCE_LL_ADDR]
@@ -255,6 +259,13 @@
 			if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0)
 				ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
 			break;
+#ifdef CONFIG_IPV6_ROUTE_INFO
+		case ND_OPT_ROUTE_INFO:
+			ndopts->nd_opts_ri_end = nd_opt;
+			if (!ndopts->nd_opts_ri)
+				ndopts->nd_opts_ri = nd_opt;
+			break;
+#endif
 		default:
 			/*
 			 * Unknown options must be silently ignored,
@@ -1019,10 +1030,11 @@
         struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw;
 	struct neighbour *neigh = NULL;
 	struct inet6_dev *in6_dev;
-	struct rt6_info *rt;
+	struct rt6_info *rt = NULL;
 	int lifetime;
 	struct ndisc_options ndopts;
 	int optlen;
+	unsigned int pref = 0;
 
 	__u8 * opt = (__u8 *)(ra_msg + 1);
 
@@ -1081,8 +1093,19 @@
 				(ra_msg->icmph.icmp6_addrconf_other ?
 					IF_RA_OTHERCONF : 0);
 
+	if (!in6_dev->cnf.accept_ra_defrtr)
+		goto skip_defrtr;
+
 	lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
 
+#ifdef CONFIG_IPV6_ROUTER_PREF
+	pref = ra_msg->icmph.icmp6_router_pref;
+	/* 10b is handled as if it were 00b (medium) */
+	if (pref == ICMPV6_ROUTER_PREF_INVALID ||
+	    in6_dev->cnf.accept_ra_rtr_pref)
+		pref = ICMPV6_ROUTER_PREF_MEDIUM;
+#endif
+
 	rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
 
 	if (rt)
@@ -1098,7 +1121,7 @@
 		ND_PRINTK3(KERN_DEBUG
 			   "ICMPv6 RA: adding default router.\n");
 
-		rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
+		rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev, pref);
 		if (rt == NULL) {
 			ND_PRINTK0(KERN_ERR
 				   "ICMPv6 RA: %s() failed to add default route.\n",
@@ -1117,6 +1140,8 @@
 			return;
 		}
 		neigh->flags |= NTF_ROUTER;
+	} else if (rt) {
+		rt->rt6i_flags |= (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
 	}
 
 	if (rt)
@@ -1128,6 +1153,8 @@
 			rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit;
 	}
 
+skip_defrtr:
+
 	/*
 	 *	Update Reachable Time and Retrans Timer
 	 */
@@ -1186,7 +1213,21 @@
 			     NEIGH_UPDATE_F_ISROUTER);
 	}
 
-	if (ndopts.nd_opts_pi) {
+#ifdef CONFIG_IPV6_ROUTE_INFO
+	if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
+		struct nd_opt_hdr *p;
+		for (p = ndopts.nd_opts_ri;
+		     p;
+		     p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
+			if (((struct route_info *)p)->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
+				continue;
+			rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3,
+				      &skb->nh.ipv6h->saddr);
+		}
+	}
+#endif
+
+	if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
 		struct nd_opt_hdr *p;
 		for (p = ndopts.nd_opts_pi;
 		     p;
diff -urN oldtree/net/ipv6/netfilter/Kconfig newtree/net/ipv6/netfilter/Kconfig
--- oldtree/net/ipv6/netfilter/Kconfig	2006-02-19 11:41:06.425366296 +0000
+++ newtree/net/ipv6/netfilter/Kconfig	2006-02-21 15:58:16.420650240 +0000
@@ -133,16 +133,6 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP6_NF_MATCH_POLICY
-	tristate "IPsec policy match support"
-	depends on IP6_NF_IPTABLES && XFRM
-	help
-	  Policy matching allows you to match packets based on the
-	  IPsec policy that was used during decapsulation/will
-	  be used during encapsulation.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 # The targets
 config IP6_NF_FILTER
 	tristate "Packet filtering"
diff -urN oldtree/net/ipv6/netfilter/Makefile newtree/net/ipv6/netfilter/Makefile
--- oldtree/net/ipv6/netfilter/Makefile	2006-02-19 11:41:06.426366144 +0000
+++ newtree/net/ipv6/netfilter/Makefile	2006-02-21 15:58:16.421650088 +0000
@@ -9,7 +9,6 @@
 obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
 obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
 obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o
-obj-$(CONFIG_IP6_NF_MATCH_POLICY) += ip6t_policy.o
 obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
 obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
 obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
diff -urN oldtree/net/ipv6/netfilter/ip6_queue.c newtree/net/ipv6/netfilter/ip6_queue.c
--- oldtree/net/ipv6/netfilter/ip6_queue.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/ipv6/netfilter/ip6_queue.c	2006-02-21 15:58:16.643616344 +0000
@@ -35,6 +35,7 @@
 #include <linux/spinlock.h>
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
+#include <linux/mutex.h>
 #include <net/sock.h>
 #include <net/ipv6.h>
 #include <net/ip6_route.h>
@@ -65,7 +66,7 @@
 static unsigned int queue_user_dropped = 0;
 static struct sock *ipqnl;
 static LIST_HEAD(queue_list);
-static DECLARE_MUTEX(ipqnl_sem);
+static DEFINE_MUTEX(ipqnl_mutex);
 
 static void
 ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict)
@@ -537,7 +538,7 @@
 	struct sk_buff *skb;
 	unsigned int qlen;
 
-	down(&ipqnl_sem);
+	mutex_lock(&ipqnl_mutex);
 			
 	for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) {
 		skb = skb_dequeue(&sk->sk_receive_queue);
@@ -545,7 +546,7 @@
 		kfree_skb(skb);
 	}
 		
-	up(&ipqnl_sem);
+	mutex_unlock(&ipqnl_mutex);
 }
 
 static int
@@ -704,8 +705,8 @@
 	
 cleanup_ipqnl:
 	sock_release(ipqnl->sk_socket);
-	down(&ipqnl_sem);
-	up(&ipqnl_sem);
+	mutex_lock(&ipqnl_mutex);
+	mutex_unlock(&ipqnl_mutex);
 	
 cleanup_netlink_notifier:
 	netlink_unregister_notifier(&ipq_nl_notifier);
diff -urN oldtree/net/ipv6/netfilter/ip6_tables.c newtree/net/ipv6/netfilter/ip6_tables.c
--- oldtree/net/ipv6/netfilter/ip6_tables.c	2006-02-19 11:41:06.451362344 +0000
+++ newtree/net/ipv6/netfilter/ip6_tables.c	2006-02-21 15:58:16.819589592 +0000
@@ -29,7 +29,7 @@
 #include <linux/icmpv6.h>
 #include <net/ipv6.h>
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <linux/proc_fs.h>
 #include <linux/cpumask.h>
 
@@ -94,19 +94,6 @@
 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
 #endif
 
-int
-ip6_masked_addrcmp(const struct in6_addr *addr1, const struct in6_addr *mask,
-                   const struct in6_addr *addr2)
-{
-	int i;
-	for( i = 0; i < 16; i++){
-		if((addr1->s6_addr[i] & mask->s6_addr[i]) != 
-		   (addr2->s6_addr[i] & mask->s6_addr[i]))
-			return 1;
-	}
-	return 0;
-}
-
 /* Check for an extension */
 int 
 ip6t_ext_hdr(u8 nexthdr)
@@ -135,10 +122,10 @@
 
 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
 
-	if (FWINV(ip6_masked_addrcmp(&ipv6->saddr, &ip6info->smsk,
-	                             &ip6info->src), IP6T_INV_SRCIP)
-	    || FWINV(ip6_masked_addrcmp(&ipv6->daddr, &ip6info->dmsk,
-	                                &ip6info->dst), IP6T_INV_DSTIP)) {
+	if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
+	                               &ip6info->src), IP6T_INV_SRCIP)
+	    || FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
+	                                  &ip6info->dst), IP6T_INV_DSTIP)) {
 		dprintf("Source or dest mismatch.\n");
 /*
 		dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
@@ -232,6 +219,7 @@
 	  const struct net_device *in,
 	  const struct net_device *out,
 	  unsigned int hooknum,
+	  const struct xt_target *target,
 	  const void *targinfo,
 	  void *userinfo)
 {
@@ -251,7 +239,7 @@
 	     int *hotdrop)
 {
 	/* Stop iteration if it doesn't match */
-	if (!m->u.kernel.match->match(skb, in, out, m->data,
+	if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
 				      offset, protoff, hotdrop))
 		return 1;
 	else
@@ -373,6 +361,7 @@
 				verdict = t->u.kernel.target->target(pskb,
 								     in, out,
 								     hook,
+								     t->u.kernel.target,
 								     t->data,
 								     userdata);
 
@@ -531,7 +520,7 @@
 		return 1;
 
 	if (m->u.kernel.match->destroy)
-		m->u.kernel.match->destroy(m->data,
+		m->u.kernel.match->destroy(m->u.kernel.match, m->data,
 					   m->u.match_size - sizeof(*m));
 	module_put(m->u.kernel.match->me);
 	return 0;
@@ -544,21 +533,12 @@
 	struct ip6t_standard_target *targ = (void *)t;
 
 	/* Check standard info. */
-	if (t->u.target_size
-	    != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
-		duprintf("standard_check: target size %u != %u\n",
-			 t->u.target_size,
-			 IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
-		return 0;
-	}
-
 	if (targ->verdict >= 0
 	    && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
 		duprintf("ip6t_standard_check: bad verdict (%i)\n",
 			 targ->verdict);
 		return 0;
 	}
-
 	if (targ->verdict < -NF_MAX_VERDICT - 1) {
 		duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
 			 targ->verdict);
@@ -575,6 +555,7 @@
 	    unsigned int *i)
 {
 	struct ip6t_match *match;
+	int ret;
 
 	match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
 			      		m->u.user.revision),
@@ -585,18 +566,27 @@
 	}
 	m->u.kernel.match = match;
 
+	ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m),
+			     name, hookmask, ipv6->proto,
+			     ipv6->invflags & IP6T_INV_PROTO);
+	if (ret)
+		goto err;
+
 	if (m->u.kernel.match->checkentry
-	    && !m->u.kernel.match->checkentry(name, ipv6, m->data,
+	    && !m->u.kernel.match->checkentry(name, ipv6, match,  m->data,
 					      m->u.match_size - sizeof(*m),
 					      hookmask)) {
-		module_put(m->u.kernel.match->me);
 		duprintf("ip_tables: check failed for `%s'.\n",
 			 m->u.kernel.match->name);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err;
 	}
 
 	(*i)++;
 	return 0;
+err:
+	module_put(m->u.kernel.match->me);
+	return ret;
 }
 
 static struct ip6t_target ip6t_standard_target;
@@ -632,26 +622,32 @@
 	}
 	t->u.kernel.target = target;
 
+	ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t),
+			      name, e->comefrom, e->ipv6.proto,
+			      e->ipv6.invflags & IP6T_INV_PROTO);
+	if (ret)
+		goto err;
+	
 	if (t->u.kernel.target == &ip6t_standard_target) {
 		if (!standard_check(t, size)) {
 			ret = -EINVAL;
 			goto cleanup_matches;
 		}
 	} else if (t->u.kernel.target->checkentry
-		   && !t->u.kernel.target->checkentry(name, e, t->data,
+		   && !t->u.kernel.target->checkentry(name, e, target, t->data,
 						      t->u.target_size
 						      - sizeof(*t),
 						      e->comefrom)) {
-		module_put(t->u.kernel.target->me);
 		duprintf("ip_tables: check failed for `%s'.\n",
 			 t->u.kernel.target->name);
 		ret = -EINVAL;
-		goto cleanup_matches;
+		goto err;
 	}
 
 	(*i)++;
 	return 0;
-
+ err:
+	module_put(t->u.kernel.target->me);
  cleanup_matches:
 	IP6T_MATCH_ITERATE(e, cleanup_match, &j);
 	return ret;
@@ -712,7 +708,7 @@
 	IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
 	t = ip6t_get_target(e);
 	if (t->u.kernel.target->destroy)
-		t->u.kernel.target->destroy(t->data,
+		t->u.kernel.target->destroy(t->u.kernel.target, t->data,
 					    t->u.target_size - sizeof(*t));
 	module_put(t->u.kernel.target->me);
 	return 0;
@@ -1333,6 +1329,7 @@
 icmp6_match(const struct sk_buff *skb,
 	   const struct net_device *in,
 	   const struct net_device *out,
+	   const struct xt_match *match,
 	   const void *matchinfo,
 	   int offset,
 	   unsigned int protoff,
@@ -1365,28 +1362,27 @@
 static int
 icmp6_checkentry(const char *tablename,
 	   const void *entry,
+	   const struct xt_match *match,
 	   void *matchinfo,
 	   unsigned int matchsize,
 	   unsigned int hook_mask)
 {
-	const struct ip6t_ip6 *ipv6 = entry;
 	const struct ip6t_icmp *icmpinfo = matchinfo;
 
-	/* Must specify proto == ICMP, and no unknown invflags */
-	return ipv6->proto == IPPROTO_ICMPV6
-		&& !(ipv6->invflags & IP6T_INV_PROTO)
-		&& matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
-		&& !(icmpinfo->invflags & ~IP6T_ICMP_INV);
+	/* Must specify no unknown invflags */
+	return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
 }
 
 /* The built-in targets: standard (NULL) and error. */
 static struct ip6t_target ip6t_standard_target = {
 	.name		= IP6T_STANDARD_TARGET,
+	.targetsize	= sizeof(int),
 };
 
 static struct ip6t_target ip6t_error_target = {
 	.name		= IP6T_ERROR_TARGET,
 	.target		= ip6t_error,
+	.targetsize	= IP6T_FUNCTION_MAXNAMELEN,
 };
 
 static struct nf_sockopt_ops ip6t_sockopts = {
@@ -1402,7 +1398,9 @@
 static struct ip6t_match icmp6_matchstruct = {
 	.name		= "icmp6",
 	.match		= &icmp6_match,
-	.checkentry	= &icmp6_checkentry,
+	.matchsize	= sizeof(struct ip6t_icmp),
+	.checkentry	= icmp6_checkentry,
+	.proto		= IPPROTO_ICMPV6,
 };
 
 static int __init init(void)
@@ -1515,7 +1513,6 @@
 EXPORT_SYMBOL(ip6t_do_table);
 EXPORT_SYMBOL(ip6t_ext_hdr);
 EXPORT_SYMBOL(ipv6_find_hdr);
-EXPORT_SYMBOL(ip6_masked_addrcmp);
 
 module_init(init);
 module_exit(fini);
diff -urN oldtree/net/ipv6/netfilter/ip6t_HL.c newtree/net/ipv6/netfilter/ip6t_HL.c
--- oldtree/net/ipv6/netfilter/ip6t_HL.c	2006-02-19 11:41:06.451362344 +0000
+++ newtree/net/ipv6/netfilter/ip6t_HL.c	2006-02-21 15:58:16.423649784 +0000
@@ -21,6 +21,7 @@
 				   const struct net_device *in,
 				   const struct net_device *out,
 				   unsigned int hooknum,
+				   const struct xt_target *target,
 				   const void *targinfo, void *userinfo)
 {
 	struct ipv6hdr *ip6h;
@@ -63,43 +64,31 @@
 
 static int ip6t_hl_checkentry(const char *tablename,
 		const void *entry,
+		const struct xt_target *target,
 		void *targinfo,
 		unsigned int targinfosize,
 		unsigned int hook_mask)
 {
 	struct ip6t_HL_info *info = targinfo;
 
-	if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HL_info))) {
-		printk(KERN_WARNING "ip6t_HL: targinfosize %u != %Zu\n",
-				targinfosize,
-				IP6T_ALIGN(sizeof(struct ip6t_HL_info)));
-		return 0;	
-	}	
-
-	if (strcmp(tablename, "mangle")) {
-		printk(KERN_WARNING "ip6t_HL: can only be called from "
-			"\"mangle\" table, not \"%s\"\n", tablename);
-		return 0;
-	}
-
 	if (info->mode > IP6T_HL_MAXMODE) {
 		printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n", 
 			info->mode);
 		return 0;
 	}
-
 	if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) {
 		printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't "
 			"make sense with value 0\n");
 		return 0;
 	}
-	
 	return 1;
 }
 
 static struct ip6t_target ip6t_HL = { 
 	.name 		= "HL", 
 	.target		= ip6t_hl_target, 
+	.targetsize	= sizeof(struct ip6t_HL_info),
+	.table		= "mangle",
 	.checkentry	= ip6t_hl_checkentry, 
 	.me		= THIS_MODULE
 };
diff -urN oldtree/net/ipv6/netfilter/ip6t_LOG.c newtree/net/ipv6/netfilter/ip6t_LOG.c
--- oldtree/net/ipv6/netfilter/ip6t_LOG.c	2006-02-19 11:41:06.452362192 +0000
+++ newtree/net/ipv6/netfilter/ip6t_LOG.c	2006-02-21 15:58:16.423649784 +0000
@@ -426,6 +426,7 @@
 		const struct net_device *in,
 		const struct net_device *out,
 		unsigned int hooknum,
+		const struct xt_target *target,
 		const void *targinfo,
 		void *userinfo)
 {
@@ -444,35 +445,29 @@
 
 static int ip6t_log_checkentry(const char *tablename,
 			       const void *entry,
+			       const struct xt_target *target,
 			       void *targinfo,
 			       unsigned int targinfosize,
 			       unsigned int hook_mask)
 {
 	const struct ip6t_log_info *loginfo = targinfo;
 
-	if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_log_info))) {
-		DEBUGP("LOG: targinfosize %u != %u\n",
-		       targinfosize, IP6T_ALIGN(sizeof(struct ip6t_log_info)));
-		return 0;
-	}
-
 	if (loginfo->level >= 8) {
 		DEBUGP("LOG: level %u >= 8\n", loginfo->level);
 		return 0;
 	}
-
 	if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
 		DEBUGP("LOG: prefix term %i\n",
 		       loginfo->prefix[sizeof(loginfo->prefix)-1]);
 		return 0;
 	}
-
 	return 1;
 }
 
 static struct ip6t_target ip6t_log_reg = {
 	.name 		= "LOG",
 	.target 	= ip6t_log_target, 
+	.targetsize	= sizeof(struct ip6t_log_info),
 	.checkentry	= ip6t_log_checkentry, 
 	.me 		= THIS_MODULE,
 };
diff -urN oldtree/net/ipv6/netfilter/ip6t_REJECT.c newtree/net/ipv6/netfilter/ip6t_REJECT.c
--- oldtree/net/ipv6/netfilter/ip6t_REJECT.c	2006-02-19 11:41:06.453362040 +0000
+++ newtree/net/ipv6/netfilter/ip6t_REJECT.c	2006-02-21 15:58:16.424649632 +0000
@@ -179,6 +179,7 @@
 			   const struct net_device *in,
 			   const struct net_device *out,
 			   unsigned int hooknum,
+			   const struct xt_target *target,
 			   const void *targinfo,
 			   void *userinfo)
 {
@@ -221,6 +222,7 @@
 
 static int check(const char *tablename,
 		 const void *entry,
+		 const struct xt_target *target,
 		 void *targinfo,
 		 unsigned int targinfosize,
 		 unsigned int hook_mask)
@@ -228,24 +230,6 @@
  	const struct ip6t_reject_info *rejinfo = targinfo;
 	const struct ip6t_entry *e = entry;
 
- 	if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) {
-  		DEBUGP("ip6t_REJECT: targinfosize %u != 0\n", targinfosize);
-  		return 0;
-  	}
-
-	/* Only allow these for packet filtering. */
-	if (strcmp(tablename, "filter") != 0) {
-		DEBUGP("ip6t_REJECT: bad table `%s'.\n", tablename);
-		return 0;
-	}
-
-	if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN)
-			   | (1 << NF_IP6_FORWARD)
-			   | (1 << NF_IP6_LOCAL_OUT))) != 0) {
-		DEBUGP("ip6t_REJECT: bad hook mask %X\n", hook_mask);
-		return 0;
-	}
-
 	if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
 		printk("ip6t_REJECT: ECHOREPLY is not supported.\n");
 		return 0;
@@ -257,13 +241,16 @@
 			return 0;
 		}
 	}
-
 	return 1;
 }
 
 static struct ip6t_target ip6t_reject_reg = {
 	.name		= "REJECT",
 	.target		= reject6_target,
+	.targetsize	= sizeof(struct ip6t_reject_info),
+	.table		= "filter",
+	.hooks		= (1 << NF_IP6_LOCAL_IN) | (1 << NF_IP6_FORWARD) |
+			  (1 << NF_IP6_LOCAL_OUT),
 	.checkentry	= check,
 	.me		= THIS_MODULE
 };
diff -urN oldtree/net/ipv6/netfilter/ip6t_ah.c newtree/net/ipv6/netfilter/ip6t_ah.c
--- oldtree/net/ipv6/netfilter/ip6t_ah.c	2006-02-19 11:41:06.453362040 +0000
+++ newtree/net/ipv6/netfilter/ip6t_ah.c	2006-02-21 15:58:16.424649632 +0000
@@ -44,6 +44,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -99,17 +100,13 @@
 static int
 checkentry(const char *tablename,
           const void *entry,
+	  const struct xt_match *match,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
 {
 	const struct ip6t_ah *ahinfo = matchinfo;
 
-	if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_ah))) {
-		DEBUGP("ip6t_ah: matchsize %u != %u\n",
-		       matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_ah)));
-		return 0;
-	}
 	if (ahinfo->invflags & ~IP6T_AH_INV_MASK) {
 		DEBUGP("ip6t_ah: unknown flags %X\n", ahinfo->invflags);
 		return 0;
@@ -119,8 +116,9 @@
 
 static struct ip6t_match ah_match = {
 	.name		= "ah",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct ip6t_ah),
+	.checkentry	= checkentry,
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/ipv6/netfilter/ip6t_dst.c newtree/net/ipv6/netfilter/ip6t_dst.c
--- oldtree/net/ipv6/netfilter/ip6t_dst.c	2006-02-19 11:41:06.454361888 +0000
+++ newtree/net/ipv6/netfilter/ip6t_dst.c	2006-02-21 15:58:16.425649480 +0000
@@ -55,6 +55,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -179,22 +180,17 @@
 static int
 checkentry(const char *tablename,
 	   const void *info,
+	   const struct xt_match *match,
 	   void *matchinfo,
 	   unsigned int matchinfosize,
 	   unsigned int hook_mask)
 {
 	const struct ip6t_opts *optsinfo = matchinfo;
 
-	if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) {
-		DEBUGP("ip6t_opts: matchsize %u != %u\n",
-		       matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts)));
-		return 0;
-	}
 	if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
 		DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags);
 		return 0;
 	}
-
 	return 1;
 }
 
@@ -204,8 +200,9 @@
 #else
 	.name		= "dst",
 #endif
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct ip6t_opts),
+	.checkentry	= checkentry,
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/ipv6/netfilter/ip6t_esp.c newtree/net/ipv6/netfilter/ip6t_esp.c
--- oldtree/net/ipv6/netfilter/ip6t_esp.c	2006-02-19 11:41:06.454361888 +0000
+++ newtree/net/ipv6/netfilter/ip6t_esp.c	2006-02-21 15:58:16.425649480 +0000
@@ -44,6 +44,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -77,17 +78,13 @@
 static int
 checkentry(const char *tablename,
 	   const void *ip,
+	   const struct xt_match *match,
 	   void *matchinfo,
 	   unsigned int matchinfosize,
 	   unsigned int hook_mask)
 {
 	const struct ip6t_esp *espinfo = matchinfo;
 
-	if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_esp))) {
-		DEBUGP("ip6t_esp: matchsize %u != %u\n",
-			 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_esp)));
-		return 0;
-	}
 	if (espinfo->invflags & ~IP6T_ESP_INV_MASK) {
 		DEBUGP("ip6t_esp: unknown flags %X\n",
 			 espinfo->invflags);
@@ -98,8 +95,9 @@
 
 static struct ip6t_match esp_match = {
 	.name		= "esp",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct ip6t_esp),
+	.checkentry	= checkentry,
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/ipv6/netfilter/ip6t_eui64.c newtree/net/ipv6/netfilter/ip6t_eui64.c
--- oldtree/net/ipv6/netfilter/ip6t_eui64.c	2006-02-19 11:41:06.455361736 +0000
+++ newtree/net/ipv6/netfilter/ip6t_eui64.c	2006-02-21 15:58:16.425649480 +0000
@@ -22,6 +22,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -60,30 +61,12 @@
 	return 0;
 }
 
-static int
-ip6t_eui64_checkentry(const char *tablename,
-		      const void *ip,
-		      void *matchinfo,
-		      unsigned int matchsize,
-		      unsigned int hook_mask)
-{
-	if (hook_mask
-	    & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) |
-		(1 << NF_IP6_FORWARD))) {
-		printk("ip6t_eui64: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
-		return 0;
-	}
-
-	if (matchsize != IP6T_ALIGN(sizeof(int)))
-		return 0;
-
-	return 1;
-}
-
 static struct ip6t_match eui64_match = {
 	.name		= "eui64",
-	.match		= &match,
-	.checkentry	= &ip6t_eui64_checkentry,
+	.match		= match,
+	.matchsize	= sizeof(int),
+	.hooks		= (1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) |
+			  (1 << NF_IP6_FORWARD),
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/ipv6/netfilter/ip6t_frag.c newtree/net/ipv6/netfilter/ip6t_frag.c
--- oldtree/net/ipv6/netfilter/ip6t_frag.c	2006-02-19 11:41:06.455361736 +0000
+++ newtree/net/ipv6/netfilter/ip6t_frag.c	2006-02-21 15:58:16.426649328 +0000
@@ -43,6 +43,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -116,29 +117,25 @@
 static int
 checkentry(const char *tablename,
 	   const void *ip,
+	   const struct xt_match *match,
 	   void *matchinfo,
 	   unsigned int matchinfosize,
 	   unsigned int hook_mask)
 {
 	const struct ip6t_frag *fraginfo = matchinfo;
 
-	if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_frag))) {
-		DEBUGP("ip6t_frag: matchsize %u != %u\n",
-		       matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_frag)));
-		return 0;
-	}
 	if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) {
 		DEBUGP("ip6t_frag: unknown flags %X\n", fraginfo->invflags);
 		return 0;
 	}
-
 	return 1;
 }
 
 static struct ip6t_match frag_match = {
 	.name		= "frag",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct ip6t_frag),
+	.checkentry	= checkentry,
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/ipv6/netfilter/ip6t_hbh.c newtree/net/ipv6/netfilter/ip6t_hbh.c
--- oldtree/net/ipv6/netfilter/ip6t_hbh.c	2006-02-19 11:41:06.456361584 +0000
+++ newtree/net/ipv6/netfilter/ip6t_hbh.c	2006-02-21 15:58:16.426649328 +0000
@@ -55,6 +55,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -179,22 +180,17 @@
 static int
 checkentry(const char *tablename,
 	   const void *entry,
+	   const struct xt_match *match,
 	   void *matchinfo,
 	   unsigned int matchinfosize,
 	   unsigned int hook_mask)
 {
 	const struct ip6t_opts *optsinfo = matchinfo;
 
-	if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) {
-		DEBUGP("ip6t_opts: matchsize %u != %u\n",
-		       matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts)));
-		return 0;
-	}
 	if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
 		DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags);
 		return 0;
 	}
-
 	return 1;
 }
 
@@ -204,8 +200,9 @@
 #else
 	.name		= "dst",
 #endif
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct ip6t_opts),
+	.checkentry	= checkentry,
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/ipv6/netfilter/ip6t_hl.c newtree/net/ipv6/netfilter/ip6t_hl.c
--- oldtree/net/ipv6/netfilter/ip6t_hl.c	2006-02-19 11:41:06.456361584 +0000
+++ newtree/net/ipv6/netfilter/ip6t_hl.c	2006-02-21 15:58:16.427649176 +0000
@@ -18,10 +18,10 @@
 MODULE_DESCRIPTION("IP tables Hop Limit matching module");
 MODULE_LICENSE("GPL");
 
-static int match(const struct sk_buff *skb, const struct net_device *in,
-		 const struct net_device *out, const void *matchinfo,
-		 int offset, unsigned int protoff,
-		 int *hotdrop)
+static int match(const struct sk_buff *skb,
+		 const struct net_device *in, const struct net_device *out,
+		 const struct xt_match *match, const void *matchinfo,
+		 int offset, unsigned int protoff, int *hotdrop)
 {
 	const struct ip6t_hl_info *info = matchinfo;
 	const struct ipv6hdr *ip6h = skb->nh.ipv6h;
@@ -48,20 +48,10 @@
 	return 0;
 }
 
-static int checkentry(const char *tablename, const void *entry,
-		      void *matchinfo, unsigned int matchsize,
-		      unsigned int hook_mask)
-{
-	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_hl_info)))
-		return 0;
-
-	return 1;
-}
-
 static struct ip6t_match hl_match = {
 	.name		= "hl",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct ip6t_hl_info),
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/ipv6/netfilter/ip6t_ipv6header.c newtree/net/ipv6/netfilter/ip6t_ipv6header.c
--- oldtree/net/ipv6/netfilter/ip6t_ipv6header.c	2006-02-19 11:41:06.457361432 +0000
+++ newtree/net/ipv6/netfilter/ip6t_ipv6header.c	2006-02-21 15:58:16.427649176 +0000
@@ -29,6 +29,7 @@
 ipv6header_match(const struct sk_buff *skb,
 		 const struct net_device *in,
 		 const struct net_device *out,
+		 const struct xt_match *match,
 		 const void *matchinfo,
 		 int offset,
 		 unsigned int protoff,
@@ -125,17 +126,13 @@
 static int
 ipv6header_checkentry(const char *tablename,
 		      const void *ip,
+		      const struct xt_match *match,
 		      void *matchinfo,
 		      unsigned int matchsize,
 		      unsigned int hook_mask)
 {
 	const struct ip6t_ipv6header_info *info = matchinfo;
 
-	/* Check for obvious errors */
-	/* This match is valid in all hooks! */
-	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info)))
-		return 0;
-
 	/* invflags is 0 or 0xff in hard mode */
 	if ((!info->modeflag) && info->invflags != 0x00 &&
 	    info->invflags != 0xFF)
@@ -147,6 +144,7 @@
 static struct ip6t_match ip6t_ipv6header_match = {
 	.name		= "ipv6header",
 	.match		= &ipv6header_match,
+	.matchsize	= sizeof(struct ip6t_ipv6header_info),
 	.checkentry	= &ipv6header_checkentry,
 	.destroy	= NULL,
 	.me		= THIS_MODULE,
diff -urN oldtree/net/ipv6/netfilter/ip6t_multiport.c newtree/net/ipv6/netfilter/ip6t_multiport.c
--- oldtree/net/ipv6/netfilter/ip6t_multiport.c	2006-02-19 11:41:06.459361128 +0000
+++ newtree/net/ipv6/netfilter/ip6t_multiport.c	2006-02-21 15:58:16.428649024 +0000
@@ -51,6 +51,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -85,6 +86,7 @@
 static int
 checkentry(const char *tablename,
 	   const void *info,
+	   const struct xt_match *match,
 	   void *matchinfo,
 	   unsigned int matchsize,
 	   unsigned int hook_mask)
@@ -92,13 +94,9 @@
 	const struct ip6t_ip6 *ip = info;
 	const struct ip6t_multiport *multiinfo = matchinfo;
 
-	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_multiport)))
-		return 0;
-
 	/* Must specify proto == TCP/UDP, no unknown flags or bad count */
 	return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
 		&& !(ip->invflags & IP6T_INV_PROTO)
-		&& matchsize == IP6T_ALIGN(sizeof(struct ip6t_multiport))
 		&& (multiinfo->flags == IP6T_MULTIPORT_SOURCE
 		    || multiinfo->flags == IP6T_MULTIPORT_DESTINATION
 		    || multiinfo->flags == IP6T_MULTIPORT_EITHER)
@@ -107,8 +105,9 @@
 
 static struct ip6t_match multiport_match = {
 	.name		= "multiport",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct ip6t_multiport),
+	.checkentry	= checkentry,
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/ipv6/netfilter/ip6t_owner.c newtree/net/ipv6/netfilter/ip6t_owner.c
--- oldtree/net/ipv6/netfilter/ip6t_owner.c	2006-02-19 11:41:06.460360976 +0000
+++ newtree/net/ipv6/netfilter/ip6t_owner.c	2006-02-21 15:58:16.428649024 +0000
@@ -26,6 +26,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -54,34 +55,27 @@
 static int
 checkentry(const char *tablename,
 	   const void *ip,
+	   const struct xt_match *match,
 	   void *matchinfo,
 	   unsigned int matchsize,
 	   unsigned int hook_mask)
 {
 	const struct ip6t_owner_info *info = matchinfo;
 
-	if (hook_mask
-	    & ~((1 << NF_IP6_LOCAL_OUT) | (1 << NF_IP6_POST_ROUTING))) {
-		printk("ip6t_owner: only valid for LOCAL_OUT or POST_ROUTING.\n");
-		return 0;
-	}
-
-	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_owner_info)))
-		return 0;
-
 	if (info->match & (IP6T_OWNER_PID | IP6T_OWNER_SID)) {
 		printk("ipt_owner: pid and sid matching "
 		       "not supported anymore\n");
 		return 0;
 	}
-
 	return 1;
 }
 
 static struct ip6t_match owner_match = {
 	.name		= "owner",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct ip6t_owner_info),
+	.hooks		= (1 << NF_IP6_LOCAL_OUT) | (1 << NF_IP6_POST_ROUTING),
+	.checkentry	= checkentry,
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/ipv6/netfilter/ip6t_policy.c newtree/net/ipv6/netfilter/ip6t_policy.c
--- oldtree/net/ipv6/netfilter/ip6t_policy.c	2006-02-19 11:41:06.461360824 +0000
+++ newtree/net/ipv6/netfilter/ip6t_policy.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,176 +0,0 @@
-/* IP tables module for matching IPsec policy
- *
- * Copyright (c) 2004,2005 Patrick McHardy, <kaber@trash.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <net/xfrm.h>
-
-#include <linux/netfilter_ipv6.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter_ipv6/ip6t_policy.h>
-
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_DESCRIPTION("IPtables IPsec policy matching module");
-MODULE_LICENSE("GPL");
-
-
-static inline int
-match_xfrm_state(struct xfrm_state *x, const struct ip6t_policy_elem *e)
-{
-#define MATCH_ADDR(x,y,z)	(!e->match.x ||				       \
-				 ((!ip6_masked_addrcmp(&e->x.a6, &e->y.a6, z)) \
-				  ^ e->invert.x))
-#define MATCH(x,y)		(!e->match.x || ((e->x == (y)) ^ e->invert.x))
-	
-	return MATCH_ADDR(saddr, smask, (struct in6_addr *)&x->props.saddr.a6) &&
-	       MATCH_ADDR(daddr, dmask, (struct in6_addr *)&x->id.daddr.a6) &&
-	       MATCH(proto, x->id.proto) &&
-	       MATCH(mode, x->props.mode) &&
-	       MATCH(spi, x->id.spi) &&
-	       MATCH(reqid, x->props.reqid);
-}
-
-static int
-match_policy_in(const struct sk_buff *skb, const struct ip6t_policy_info *info)
-{
-	const struct ip6t_policy_elem *e;
-	struct sec_path *sp = skb->sp;
-	int strict = info->flags & IP6T_POLICY_MATCH_STRICT;
-	int i, pos;
-
-	if (sp == NULL)
-		return -1;
-	if (strict && info->len != sp->len)
-		return 0;
-
-	for (i = sp->len - 1; i >= 0; i--) {
-		pos = strict ? i - sp->len + 1 : 0;
-		if (pos >= info->len)
-			return 0;
-		e = &info->pol[pos];
-
-		if (match_xfrm_state(sp->x[i].xvec, e)) {
-			if (!strict)
-				return 1;
-		} else if (strict)
-			return 0;
-	}
-
-	return strict ? 1 : 0;
-}
-
-static int
-match_policy_out(const struct sk_buff *skb, const struct ip6t_policy_info *info)
-{
-	const struct ip6t_policy_elem *e;
-	struct dst_entry *dst = skb->dst;
-	int strict = info->flags & IP6T_POLICY_MATCH_STRICT;
-	int i, pos;
-
-	if (dst->xfrm == NULL)
-		return -1;
-
-	for (i = 0; dst && dst->xfrm; dst = dst->child, i++) {
-		pos = strict ? i : 0;
-		if (pos >= info->len)
-			return 0;
-		e = &info->pol[pos];
-
-		if (match_xfrm_state(dst->xfrm, e)) {
-			if (!strict)
-				return 1;
-		} else if (strict)
-			return 0;
-	}
-
-	return strict ? i == info->len : 0;
-}
-
-static int match(const struct sk_buff *skb,
-                 const struct net_device *in,
-                 const struct net_device *out,
-                 const void *matchinfo,
-		 int offset,
-		 unsigned int protoff,
-		 int *hotdrop)
-{
-	const struct ip6t_policy_info *info = matchinfo;
-	int ret;
-
-	if (info->flags & IP6T_POLICY_MATCH_IN)
-		ret = match_policy_in(skb, info);
-	else
-		ret = match_policy_out(skb, info);
-
-	if (ret < 0)
-		ret = info->flags & IP6T_POLICY_MATCH_NONE ? 1 : 0;
-	else if (info->flags & IP6T_POLICY_MATCH_NONE)
-		ret = 0;
-
-	return ret;
-}
-
-static int checkentry(const char *tablename, const void *ip_void,
-                      void *matchinfo, unsigned int matchsize,
-                      unsigned int hook_mask)
-{
-	struct ip6t_policy_info *info = matchinfo;
-
-	if (matchsize != IP6T_ALIGN(sizeof(*info))) {
-		printk(KERN_ERR "ip6t_policy: matchsize %u != %zu\n",
-		       matchsize, IP6T_ALIGN(sizeof(*info)));
-		return 0;
-	}
-	if (!(info->flags & (IP6T_POLICY_MATCH_IN|IP6T_POLICY_MATCH_OUT))) {
-		printk(KERN_ERR "ip6t_policy: neither incoming nor "
-		                "outgoing policy selected\n");
-		return 0;
-	}
-	if (hook_mask & (1 << NF_IP6_PRE_ROUTING | 1 << NF_IP6_LOCAL_IN)
-	    && info->flags & IP6T_POLICY_MATCH_OUT) {
-		printk(KERN_ERR "ip6t_policy: output policy not valid in "
-		                "PRE_ROUTING and INPUT\n");
-		return 0;
-	}
-	if (hook_mask & (1 << NF_IP6_POST_ROUTING | 1 << NF_IP6_LOCAL_OUT)
-	    && info->flags & IP6T_POLICY_MATCH_IN) {
-		printk(KERN_ERR "ip6t_policy: input policy not valid in "
-		                "POST_ROUTING and OUTPUT\n");
-		return 0;
-	}
-	if (info->len > IP6T_POLICY_MAX_ELEM) {
-		printk(KERN_ERR "ip6t_policy: too many policy elements\n");
-		return 0;
-	}
-
-	return 1;
-}
-
-static struct ip6t_match policy_match = {
-	.name		= "policy",
-	.match		= match,
-	.checkentry 	= checkentry,
-	.me		= THIS_MODULE,
-};
-
-static int __init init(void)
-{
-	return ip6t_register_match(&policy_match);
-}
-
-static void __exit fini(void)
-{
-	ip6t_unregister_match(&policy_match);
-}
-
-module_init(init);
-module_exit(fini);
diff -urN oldtree/net/ipv6/netfilter/ip6t_rt.c newtree/net/ipv6/netfilter/ip6t_rt.c
--- oldtree/net/ipv6/netfilter/ip6t_rt.c	2006-02-19 11:41:06.461360824 +0000
+++ newtree/net/ipv6/netfilter/ip6t_rt.c	2006-02-21 15:58:16.429648872 +0000
@@ -45,6 +45,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -194,17 +195,13 @@
 static int
 checkentry(const char *tablename,
 	   const void *entry,
+	   const struct xt_match *match,
 	   void *matchinfo,
 	   unsigned int matchinfosize,
 	   unsigned int hook_mask)
 {
 	const struct ip6t_rt *rtinfo = matchinfo;
 
-	if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_rt))) {
-		DEBUGP("ip6t_rt: matchsize %u != %u\n",
-		       matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_rt)));
-		return 0;
-	}
 	if (rtinfo->invflags & ~IP6T_RT_INV_MASK) {
 		DEBUGP("ip6t_rt: unknown flags %X\n", rtinfo->invflags);
 		return 0;
@@ -222,8 +219,9 @@
 
 static struct ip6t_match rt_match = {
 	.name		= "rt",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct ip6t_rt),
+	.checkentry	= checkentry,
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c newtree/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
--- oldtree/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c	2006-02-19 11:41:06.463360520 +0000
+++ newtree/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c	2006-02-21 15:58:16.430648720 +0000
@@ -179,31 +179,36 @@
 				 int (*okfn)(struct sk_buff *))
 {
 	struct nf_conn *ct;
+	struct nf_conn_help *help;
 	enum ip_conntrack_info ctinfo;
+	unsigned int ret, protoff;
+	unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1)
+			      - (*pskb)->data;
+	unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr;
+
 
 	/* This is where we call the helper: as the packet goes out. */
 	ct = nf_ct_get(*pskb, &ctinfo);
-	if (ct && ct->helper) {
-		unsigned int ret, protoff;
-		unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1)
-				      - (*pskb)->data;
-		unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr;
-
-		protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
-						 (*pskb)->len - extoff);
-		if (protoff < 0 || protoff > (*pskb)->len ||
-		    pnum == NEXTHDR_FRAGMENT) {
-			DEBUGP("proto header not found\n");
-			return NF_ACCEPT;
-		}
+	if (!ct)
+		goto out;
 
-		ret = ct->helper->help(pskb, protoff, ct, ctinfo);
-		if (ret != NF_ACCEPT)
-			return ret;
+	help = nfct_help(ct);
+	if (!help || !help->helper)
+		goto out;
+
+	protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
+					 (*pskb)->len - extoff);
+	if (protoff < 0 || protoff > (*pskb)->len ||
+	    pnum == NEXTHDR_FRAGMENT) {
+		DEBUGP("proto header not found\n");
+		return NF_ACCEPT;
 	}
 
+	ret = help->helper->help(pskb, protoff, ct, ctinfo);
+	if (ret != NF_ACCEPT)
+		return ret;
+out:
 	/* We've seen it coming out the other side: confirm it */
-
 	return nf_conntrack_confirm(pskb);
 }
 
diff -urN oldtree/net/ipv6/netfilter/nf_conntrack_reasm.c newtree/net/ipv6/netfilter/nf_conntrack_reasm.c
--- oldtree/net/ipv6/netfilter/nf_conntrack_reasm.c	2006-02-19 11:41:06.465360216 +0000
+++ newtree/net/ipv6/netfilter/nf_conntrack_reasm.c	2006-02-21 15:58:16.430648720 +0000
@@ -313,8 +313,8 @@
 #ifdef CONFIG_SMP
 	hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) {
 		if (fq->id == fq_in->id && 
-		    !ipv6_addr_cmp(&fq_in->saddr, &fq->saddr) &&
-		    !ipv6_addr_cmp(&fq_in->daddr, &fq->daddr)) {
+		    ipv6_addr_equal(&fq_in->saddr, &fq->saddr) &&
+		    ipv6_addr_equal(&fq_in->daddr, &fq->daddr)) {
 			atomic_inc(&fq->refcnt);
 			write_unlock(&nf_ct_frag6_lock);
 			fq_in->last_in |= COMPLETE;
@@ -376,8 +376,8 @@
 	read_lock(&nf_ct_frag6_lock);
 	hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) {
 		if (fq->id == id && 
-		    !ipv6_addr_cmp(src, &fq->saddr) &&
-		    !ipv6_addr_cmp(dst, &fq->daddr)) {
+		    ipv6_addr_equal(src, &fq->saddr) &&
+		    ipv6_addr_equal(dst, &fq->daddr)) {
 			atomic_inc(&fq->refcnt);
 			read_unlock(&nf_ct_frag6_lock);
 			return fq;
diff -urN oldtree/net/ipv6/raw.c newtree/net/ipv6/raw.c
--- oldtree/net/ipv6/raw.c	2006-02-19 11:41:06.466360064 +0000
+++ newtree/net/ipv6/raw.c	2006-02-21 15:58:37.325472224 +0000
@@ -193,7 +193,7 @@
 	struct inet_sock *inet = inet_sk(sk);
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct sockaddr_in6 *addr = (struct sockaddr_in6 *) uaddr;
-	__u32 v4addr = 0;
+	__be32 v4addr = 0;
 	int addr_type;
 	int err;
 
@@ -263,7 +263,7 @@
 
 void rawv6_err(struct sock *sk, struct sk_buff *skb,
 	       struct inet6_skb_parm *opt,
-	       int type, int code, int offset, u32 info)
+	       int type, int code, int offset, __be32 info)
 {
 	struct inet_sock *inet = inet_sk(sk);
 	struct ipv6_pinfo *np = inet6_sk(sk);
diff -urN oldtree/net/ipv6/route.c newtree/net/ipv6/route.c
--- oldtree/net/ipv6/route.c	2006-02-19 11:41:06.468359760 +0000
+++ newtree/net/ipv6/route.c	2006-02-21 15:58:16.434648112 +0000
@@ -72,6 +72,10 @@
 #define RT6_TRACE(x...) do { ; } while (0)
 #endif
 
+#define CLONE_OFFLINK_ROUTE 0
+
+#define RT6_SELECT_F_IFACE	0x1
+#define RT6_SELECT_F_REACHABLE	0x2
 
 static int ip6_rt_max_size = 4096;
 static int ip6_rt_gc_min_interval = HZ / 2;
@@ -94,6 +98,14 @@
 static void		ip6_link_failure(struct sk_buff *skb);
 static void		ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
 
+#ifdef CONFIG_IPV6_ROUTE_INFO
+static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixlen,
+					   struct in6_addr *gwaddr, int ifindex,
+					   unsigned pref);
+static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixlen,
+					   struct in6_addr *gwaddr, int ifindex);
+#endif
+
 static struct dst_ops ip6_dst_ops = {
 	.family			=	AF_INET6,
 	.protocol		=	__constant_htons(ETH_P_IPV6),
@@ -214,150 +226,211 @@
 	return rt;
 }
 
+#ifdef CONFIG_IPV6_ROUTER_PREF
+static void rt6_probe(struct rt6_info *rt)
+{
+	struct neighbour *neigh = rt ? rt->rt6i_nexthop : NULL;
+	/*
+	 * Okay, this does not seem to be appropriate
+	 * for now, however, we need to check if it
+	 * is really so; aka Router Reachability Probing.
+	 *
+	 * Router Reachability Probe MUST be rate-limited
+	 * to no more than one per minute.
+	 */
+	if (!neigh || (neigh->nud_state & NUD_VALID))
+		return;
+	read_lock_bh(&neigh->lock);
+	if (!(neigh->nud_state & NUD_VALID) &&
+	    time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
+		struct in6_addr mcaddr;
+		struct in6_addr *target;
+
+		neigh->updated = jiffies;
+		read_unlock_bh(&neigh->lock);
+
+		target = (struct in6_addr *)&neigh->primary_key;
+		addrconf_addr_solict_mult(target, &mcaddr);
+		ndisc_send_ns(rt->rt6i_dev, NULL, target, &mcaddr, NULL);
+	} else
+		read_unlock_bh(&neigh->lock);
+}
+#else
+static inline void rt6_probe(struct rt6_info *rt)
+{
+	return;
+}
+#endif
+
 /*
- *	pointer to the last default router chosen. BH is disabled locally.
+ * Default Router Selection (RFC 2461 6.3.6)
  */
-static struct rt6_info *rt6_dflt_pointer;
-static DEFINE_SPINLOCK(rt6_dflt_lock);
+static int inline rt6_check_dev(struct rt6_info *rt, int oif)
+{
+	struct net_device *dev = rt->rt6i_dev;
+	if (!oif || dev->ifindex == oif)
+		return 2;
+	if ((dev->flags & IFF_LOOPBACK) &&
+	    rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
+		return 1;
+	return 0;
+}
 
-void rt6_reset_dflt_pointer(struct rt6_info *rt)
+static int inline rt6_check_neigh(struct rt6_info *rt)
 {
-	spin_lock_bh(&rt6_dflt_lock);
-	if (rt == NULL || rt == rt6_dflt_pointer) {
-		RT6_TRACE("reset default router: %p->NULL\n", rt6_dflt_pointer);
-		rt6_dflt_pointer = NULL;
+	struct neighbour *neigh = rt->rt6i_nexthop;
+	int m = 0;
+	if (neigh) {
+		read_lock_bh(&neigh->lock);
+		if (neigh->nud_state & NUD_VALID)
+			m = 1;
+		read_unlock_bh(&neigh->lock);
 	}
-	spin_unlock_bh(&rt6_dflt_lock);
+	return m;
 }
 
-/* Default Router Selection (RFC 2461 6.3.6) */
-static struct rt6_info *rt6_best_dflt(struct rt6_info *rt, int oif)
+static int rt6_score_route(struct rt6_info *rt, int oif,
+			   int strict)
 {
-	struct rt6_info *match = NULL;
-	struct rt6_info *sprt;
-	int mpri = 0;
-
-	for (sprt = rt; sprt; sprt = sprt->u.next) {
-		struct neighbour *neigh;
-		int m = 0;
-
-		if (!oif ||
-		    (sprt->rt6i_dev &&
-		     sprt->rt6i_dev->ifindex == oif))
-			m += 8;
+	int m = rt6_check_dev(rt, oif);
+	if (!m && (strict & RT6_SELECT_F_IFACE))
+		return -1;
+#ifdef CONFIG_IPV6_ROUTER_PREF
+	m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
+#endif
+	if (rt6_check_neigh(rt))
+		m |= 16;
+	else if (strict & RT6_SELECT_F_REACHABLE)
+		return -1;
+	return m;
+}
 
-		if (rt6_check_expired(sprt))
-			continue;
+static struct rt6_info *rt6_select(struct rt6_info **head, int oif,
+				   int strict)
+{
+	struct rt6_info *match = NULL, *last = NULL;
+	struct rt6_info *rt, *rt0 = *head;
+	u32 metric;
+	int mpri = -1;
 
-		if (sprt == rt6_dflt_pointer)
-			m += 4;
+	RT6_TRACE("%s(head=%p(*head=%p), oif=%d)\n",
+		  __FUNCTION__, head, head ? *head : NULL, oif);
 
-		if ((neigh = sprt->rt6i_nexthop) != NULL) {
-			read_lock_bh(&neigh->lock);
-			switch (neigh->nud_state) {
-			case NUD_REACHABLE:
-				m += 3;
-				break;
+	for (rt = rt0, metric = rt0->rt6i_metric;
+	     rt && rt->rt6i_metric == metric;
+	     rt = rt->u.next) {
+		int m;
 
-			case NUD_STALE:
-			case NUD_DELAY:
-			case NUD_PROBE:
-				m += 2;
-				break;
+		if (rt6_check_expired(rt))
+			continue;
 
-			case NUD_NOARP:
-			case NUD_PERMANENT:
-				m += 1;
-				break;
+		last = rt;
 
-			case NUD_INCOMPLETE:
-			default:
-				read_unlock_bh(&neigh->lock);
-				continue;
-			}
-			read_unlock_bh(&neigh->lock);
-		} else {
+		m = rt6_score_route(rt, oif, strict);
+		if (m < 0)
 			continue;
-		}
 
-		if (m > mpri || m >= 12) {
-			match = sprt;
+		if (m > mpri) {
+			rt6_probe(match);
+			match = rt;
 			mpri = m;
-			if (m >= 12) {
-				/* we choose the last default router if it
-				 * is in (probably) reachable state.
-				 * If route changed, we should do pmtu
-				 * discovery. --yoshfuji
-				 */
-				break;
-			}
+		} else {
+			rt6_probe(rt);
 		}
 	}
 
-	spin_lock(&rt6_dflt_lock);
-	if (!match) {
-		/*
-		 *	No default routers are known to be reachable.
-		 *	SHOULD round robin
-		 */
-		if (rt6_dflt_pointer) {
-			for (sprt = rt6_dflt_pointer->u.next;
-			     sprt; sprt = sprt->u.next) {
-				if (sprt->u.dst.obsolete <= 0 &&
-				    sprt->u.dst.error == 0 &&
-				    !rt6_check_expired(sprt)) {
-					match = sprt;
-					break;
-				}
-			}
-			for (sprt = rt;
-			     !match && sprt;
-			     sprt = sprt->u.next) {
-				if (sprt->u.dst.obsolete <= 0 &&
-				    sprt->u.dst.error == 0 &&
-				    !rt6_check_expired(sprt)) {
-					match = sprt;
-					break;
-				}
-				if (sprt == rt6_dflt_pointer)
-					break;
-			}
-		}
+	if (!match &&
+	    (strict & RT6_SELECT_F_REACHABLE) &&
+	    last && last != rt0) {
+		/* no entries matched; do round-robin */
+		*head = rt0->u.next;
+		rt0->u.next = last->u.next;
+		last->u.next = rt0;
 	}
 
-	if (match) {
-		if (rt6_dflt_pointer != match)
-			RT6_TRACE("changed default router: %p->%p\n",
-				  rt6_dflt_pointer, match);
-		rt6_dflt_pointer = match;
+	RT6_TRACE("%s() => %p, score=%d\n",
+		  __FUNCTION__, match, mpri);
+
+	return (match ? match : &ip6_null_entry);
+}
+
+#ifdef CONFIG_IPV6_ROUTE_INFO
+int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
+		  struct in6_addr *gwaddr)
+{
+	struct route_info *rinfo = (struct route_info *) opt;
+	struct in6_addr prefix_buf, *prefix;
+	unsigned int pref;
+	u32 lifetime;
+	struct rt6_info *rt;
+
+	if (len < sizeof(struct route_info)) {
+		return -EINVAL;
 	}
-	spin_unlock(&rt6_dflt_lock);
 
-	if (!match) {
-		/*
-		 * Last Resort: if no default routers found, 
-		 * use addrconf default route.
-		 * We don't record this route.
-		 */
-		for (sprt = ip6_routing_table.leaf;
-		     sprt; sprt = sprt->u.next) {
-			if (!rt6_check_expired(sprt) &&
-			    (sprt->rt6i_flags & RTF_DEFAULT) &&
-			    (!oif ||
-			     (sprt->rt6i_dev &&
-			      sprt->rt6i_dev->ifindex == oif))) {
-				match = sprt;
-				break;
-			}
+	/* Sanity check for prefix_len and length */
+	if (rinfo->length > 3) {
+		return -EINVAL;
+	} else if (rinfo->prefix_len > 128) {
+		return -EINVAL;
+	} else if (rinfo->prefix_len > 64) {
+		if (rinfo->length < 2) {
+			return -EINVAL;
 		}
-		if (!match) {
-			/* no default route.  give up. */
-			match = &ip6_null_entry;
+	} else if (rinfo->prefix_len > 0) {
+		if (rinfo->length < 1) {
+			return -EINVAL;
 		}
 	}
 
-	return match;
+	pref = rinfo->route_pref;
+	if (pref == ICMPV6_ROUTER_PREF_INVALID)
+		pref = ICMPV6_ROUTER_PREF_MEDIUM;
+
+	lifetime = htonl(rinfo->lifetime);
+	if (lifetime == 0xffffffff) {
+		/* infinity */
+	} else if (lifetime > 0x7fffffff/HZ) {
+		/* Avoid arithmetic overflow */
+		lifetime = 0x7fffffff/HZ - 1;
+	}
+
+	if (rinfo->length == 3)
+		prefix = (struct in6_addr *)rinfo->prefix;
+	else {
+		/* this function is safe */
+		ipv6_addr_prefix(&prefix_buf,
+				 (struct in6_addr *)rinfo->prefix,
+				 rinfo->prefix_len);
+		prefix = &prefix_buf;
+	}
+
+	rt = rt6_get_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex);
+
+	if (rt && !lifetime) {
+		ip6_del_rt(rt, NULL, NULL, NULL);
+		rt = NULL;
+	}
+
+	if (!rt && lifetime)
+		rt = rt6_add_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
+					pref);
+	else if (rt)
+		rt->rt6i_flags = RTF_ROUTEINFO |
+				 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
+
+	if (rt) {
+		if (lifetime == 0xffffffff) {
+			rt->rt6i_flags &= ~RTF_EXPIRES;
+		} else {
+			rt->rt6i_expires = jiffies + HZ * lifetime;
+			rt->rt6i_flags |= RTF_EXPIRES;
+		}
+		dst_release(&rt->u.dst);
+	}
+	return 0;
 }
+#endif
 
 struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,
 			    int oif, int strict)
@@ -397,14 +470,9 @@
 	return err;
 }
 
-/* No rt6_lock! If COW failed, the function returns dead route entry
-   with dst->error set to errno value.
- */
-
-static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr,
-				struct in6_addr *saddr, struct netlink_skb_parms *req)
+static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr,
+				      struct in6_addr *saddr)
 {
-	int err;
 	struct rt6_info *rt;
 
 	/*
@@ -435,25 +503,30 @@
 
 		rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway);
 
-		dst_hold(&rt->u.dst);
-
-		err = ip6_ins_rt(rt, NULL, NULL, req);
-		if (err == 0)
-			return rt;
+	}
 
-		rt->u.dst.error = err;
+	return rt;
+}
 
-		return rt;
+static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *daddr)
+{
+	struct rt6_info *rt = ip6_rt_copy(ort);
+	if (rt) {
+		ipv6_addr_copy(&rt->rt6i_dst.addr, daddr);
+		rt->rt6i_dst.plen = 128;
+		rt->rt6i_flags |= RTF_CACHE;
+		if (rt->rt6i_flags & RTF_REJECT)
+			rt->u.dst.error = ort->u.dst.error;
+		rt->u.dst.flags |= DST_HOST;
+		rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop);
 	}
-	dst_hold(&ip6_null_entry.u.dst);
-	return &ip6_null_entry;
+	return rt;
 }
 
 #define BACKTRACK() \
-if (rt == &ip6_null_entry && strict) { \
+if (rt == &ip6_null_entry) { \
        while ((fn = fn->parent) != NULL) { \
 		if (fn->fn_flags & RTN_ROOT) { \
-			dst_hold(&rt->u.dst); \
 			goto out; \
 		} \
 		if (fn->fn_flags & RTN_RTINFO) \
@@ -465,115 +538,138 @@
 void ip6_route_input(struct sk_buff *skb)
 {
 	struct fib6_node *fn;
-	struct rt6_info *rt;
+	struct rt6_info *rt, *nrt;
 	int strict;
 	int attempts = 3;
+	int err;
+	int reachable = RT6_SELECT_F_REACHABLE;
 
-	strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL);
+	strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0;
 
 relookup:
 	read_lock_bh(&rt6_lock);
 
+restart_2:
 	fn = fib6_lookup(&ip6_routing_table, &skb->nh.ipv6h->daddr,
 			 &skb->nh.ipv6h->saddr);
 
 restart:
-	rt = fn->leaf;
-
-	if ((rt->rt6i_flags & RTF_CACHE)) {
-		rt = rt6_device_match(rt, skb->dev->ifindex, strict);
-		BACKTRACK();
-		dst_hold(&rt->u.dst);
-		goto out;
-	}
-
-	rt = rt6_device_match(rt, skb->dev->ifindex, strict);
+	rt = rt6_select(&fn->leaf, skb->dev->ifindex, strict | reachable);
 	BACKTRACK();
+	if (rt == &ip6_null_entry ||
+	    rt->rt6i_flags & RTF_CACHE)
+		goto out;
 
-	if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
-		struct rt6_info *nrt;
-		dst_hold(&rt->u.dst);
-		read_unlock_bh(&rt6_lock);
+	dst_hold(&rt->u.dst);
+	read_unlock_bh(&rt6_lock);
 
-		nrt = rt6_cow(rt, &skb->nh.ipv6h->daddr,
-			      &skb->nh.ipv6h->saddr,
-			      &NETLINK_CB(skb));
+	if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
+		nrt = rt6_alloc_cow(rt, &skb->nh.ipv6h->daddr, &skb->nh.ipv6h->saddr);
+	else {
+#if CLONE_OFFLINK_ROUTE 
+		nrt = rt6_alloc_clone(rt, &skb->nh.ipv6h->daddr);
+#else
+		goto out2;
+#endif
+	}
 
-		dst_release(&rt->u.dst);
-		rt = nrt;
+	dst_release(&rt->u.dst);
+	rt = nrt ? : &ip6_null_entry;
 
-		if (rt->u.dst.error != -EEXIST || --attempts <= 0)
+	dst_hold(&rt->u.dst);
+	if (nrt) {
+		err = ip6_ins_rt(nrt, NULL, NULL, &NETLINK_CB(skb));
+		if (!err)
 			goto out2;
-
-		/* Race condition! In the gap, when rt6_lock was
-		   released someone could insert this route.  Relookup.
-		*/
-		dst_release(&rt->u.dst);
-		goto relookup;
 	}
-	dst_hold(&rt->u.dst);
+
+	if (--attempts <= 0)
+		goto out2;
+
+	/*
+	 * Race condition! In the gap, when rt6_lock was
+	 * released someone could insert this route.  Relookup.
+	 */
+	dst_release(&rt->u.dst);
+	goto relookup;
 
 out:
+	if (reachable) {
+		reachable = 0;
+		goto restart_2;
+	}
+	dst_hold(&rt->u.dst);
 	read_unlock_bh(&rt6_lock);
 out2:
 	rt->u.dst.lastuse = jiffies;
 	rt->u.dst.__use++;
 	skb->dst = (struct dst_entry *) rt;
+	return;
 }
 
 struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
 {
 	struct fib6_node *fn;
-	struct rt6_info *rt;
+	struct rt6_info *rt, *nrt;
 	int strict;
 	int attempts = 3;
+	int err;
+	int reachable = RT6_SELECT_F_REACHABLE;
 
-	strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL);
+	strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0;
 
 relookup:
 	read_lock_bh(&rt6_lock);
 
+restart_2:
 	fn = fib6_lookup(&ip6_routing_table, &fl->fl6_dst, &fl->fl6_src);
 
 restart:
-	rt = fn->leaf;
-
-	if ((rt->rt6i_flags & RTF_CACHE)) {
-		rt = rt6_device_match(rt, fl->oif, strict);
-		BACKTRACK();
-		dst_hold(&rt->u.dst);
+	rt = rt6_select(&fn->leaf, fl->oif, strict | reachable);
+	BACKTRACK();
+	if (rt == &ip6_null_entry ||
+	    rt->rt6i_flags & RTF_CACHE)
 		goto out;
-	}
-	if (rt->rt6i_flags & RTF_DEFAULT) {
-		if (rt->rt6i_metric >= IP6_RT_PRIO_ADDRCONF)
-			rt = rt6_best_dflt(rt, fl->oif);
-	} else {
-		rt = rt6_device_match(rt, fl->oif, strict);
-		BACKTRACK();
-	}
 
-	if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
-		struct rt6_info *nrt;
-		dst_hold(&rt->u.dst);
-		read_unlock_bh(&rt6_lock);
+	dst_hold(&rt->u.dst);
+	read_unlock_bh(&rt6_lock);
 
-		nrt = rt6_cow(rt, &fl->fl6_dst, &fl->fl6_src, NULL);
+	if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
+		nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src);
+	else {
+#if CLONE_OFFLINK_ROUTE
+		nrt = rt6_alloc_clone(rt, &fl->fl6_dst);
+#else
+		goto out2;
+#endif
+	}
 
-		dst_release(&rt->u.dst);
-		rt = nrt;
+	dst_release(&rt->u.dst);
+	rt = nrt ? : &ip6_null_entry;
 
-		if (rt->u.dst.error != -EEXIST || --attempts <= 0)
+	dst_hold(&rt->u.dst);
+	if (nrt) {
+		err = ip6_ins_rt(nrt, NULL, NULL, NULL);
+		if (!err)
 			goto out2;
-
-		/* Race condition! In the gap, when rt6_lock was
-		   released someone could insert this route.  Relookup.
-		*/
-		dst_release(&rt->u.dst);
-		goto relookup;
 	}
-	dst_hold(&rt->u.dst);
+
+	if (--attempts <= 0)
+		goto out2;
+
+	/*
+	 * Race condition! In the gap, when rt6_lock was
+	 * released someone could insert this route.  Relookup.
+	 */
+	dst_release(&rt->u.dst);
+	goto relookup;
 
 out:
+	if (reachable) {
+		reachable = 0;
+		goto restart_2;
+	}
+	dst_hold(&rt->u.dst);
 	read_unlock_bh(&rt6_lock);
 out2:
 	rt->u.dst.lastuse = jiffies;
@@ -999,8 +1095,6 @@
 
 	write_lock_bh(&rt6_lock);
 
-	rt6_reset_dflt_pointer(NULL);
-
 	err = fib6_del(rt, nlh, _rtattr, req);
 	dst_release(&rt->u.dst);
 
@@ -1050,59 +1144,63 @@
 void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr,
 		  struct neighbour *neigh, u8 *lladdr, int on_link)
 {
-	struct rt6_info *rt, *nrt;
-
-	/* Locate old route to this destination. */
-	rt = rt6_lookup(dest, NULL, neigh->dev->ifindex, 1);
-
-	if (rt == NULL)
-		return;
-
-	if (neigh->dev != rt->rt6i_dev)
-		goto out;
+	struct rt6_info *rt, *nrt = NULL;
+	int strict;
+	struct fib6_node *fn;
 
 	/*
-	 * Current route is on-link; redirect is always invalid.
-	 * 
-	 * Seems, previous statement is not true. It could
-	 * be node, which looks for us as on-link (f.e. proxy ndisc)
-	 * But then router serving it might decide, that we should
-	 * know truth 8)8) --ANK (980726).
+	 * Get the "current" route for this destination and
+	 * check if the redirect has come from approriate router.
+	 *
+	 * RFC 2461 specifies that redirects should only be
+	 * accepted if they come from the nexthop to the target.
+	 * Due to the way the routes are chosen, this notion
+	 * is a bit fuzzy and one might need to check all possible
+	 * routes.
 	 */
-	if (!(rt->rt6i_flags&RTF_GATEWAY))
-		goto out;
+	strict = ipv6_addr_type(dest) & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL);
 
-	/*
-	 *	RFC 2461 specifies that redirects should only be
-	 *	accepted if they come from the nexthop to the target.
-	 *	Due to the way default routers are chosen, this notion
-	 *	is a bit fuzzy and one might need to check all default
-	 *	routers.
-	 */
-	if (!ipv6_addr_equal(saddr, &rt->rt6i_gateway)) {
-		if (rt->rt6i_flags & RTF_DEFAULT) {
-			struct rt6_info *rt1;
-
-			read_lock(&rt6_lock);
-			for (rt1 = ip6_routing_table.leaf; rt1; rt1 = rt1->u.next) {
-				if (ipv6_addr_equal(saddr, &rt1->rt6i_gateway)) {
-					dst_hold(&rt1->u.dst);
-					dst_release(&rt->u.dst);
-					read_unlock(&rt6_lock);
-					rt = rt1;
-					goto source_ok;
-				}
-			}
-			read_unlock(&rt6_lock);
+	read_lock_bh(&rt6_lock);
+	fn = fib6_lookup(&ip6_routing_table, dest, NULL);
+restart:
+	for (rt = fn->leaf; rt; rt = rt->u.next) {
+		/*
+		 * Current route is on-link; redirect is always invalid.
+		 * 
+		 * Seems, previous statement is not true. It could
+		 * be node, which looks for us as on-link (f.e. proxy ndisc)
+		 * But then router serving it might decide, that we should
+		 * know truth 8)8) --ANK (980726).
+		 */
+		if (rt6_check_expired(rt))
+			continue;
+		if (!(rt->rt6i_flags & RTF_GATEWAY))
+			continue;
+		if (neigh->dev != rt->rt6i_dev)
+			continue;
+		if (!ipv6_addr_equal(saddr, &rt->rt6i_gateway))
+			continue;
+		break;
+	}
+	if (rt)
+		dst_hold(&rt->u.dst);
+	else if (strict) {
+		while ((fn = fn->parent) != NULL) {
+			if (fn->fn_flags & RTN_ROOT)
+				break;
+			if (fn->fn_flags & RTN_RTINFO)
+				goto restart;
 		}
+	}
+	read_unlock_bh(&rt6_lock);
+	
+	if (!rt) {
 		if (net_ratelimit())
 			printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop "
 			       "for redirect target\n");
-		goto out;
+		return;
 	}
 
-source_ok:
-
 	/*
 	 *	We have finally decided to accept it.
 	 */
@@ -1210,38 +1308,27 @@
 	   1. It is connected route. Action: COW
 	   2. It is gatewayed route or NONEXTHOP route. Action: clone it.
 	 */
-	if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
-		nrt = rt6_cow(rt, daddr, saddr, NULL);
-		if (!nrt->u.dst.error) {
-			nrt->u.dst.metrics[RTAX_MTU-1] = pmtu;
-			if (allfrag)
-				nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
-			/* According to RFC 1981, detecting PMTU increase shouldn't be
-			   happened within 5 mins, the recommended timer is 10 mins.
-			   Here this route expiration time is set to ip6_rt_mtu_expires
-			   which is 10 mins. After 10 mins the decreased pmtu is expired
-			   and detecting PMTU increase will be automatically happened.
-			 */
-			dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
-			nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES;
-		}
-		dst_release(&nrt->u.dst);
-	} else {
-		nrt = ip6_rt_copy(rt);
-		if (nrt == NULL)
-			goto out;
-		ipv6_addr_copy(&nrt->rt6i_dst.addr, daddr);
-		nrt->rt6i_dst.plen = 128;
-		nrt->u.dst.flags |= DST_HOST;
-		nrt->rt6i_nexthop = neigh_clone(rt->rt6i_nexthop);
-		dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
-		nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES;
+	if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
+		nrt = rt6_alloc_cow(rt, daddr, saddr);
+	else
+		nrt = rt6_alloc_clone(rt, daddr);
+
+	if (nrt) {
 		nrt->u.dst.metrics[RTAX_MTU-1] = pmtu;
 		if (allfrag)
 			nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
+		
+		/* According to RFC 1981, detecting PMTU increase shouldn't be
+		 * happened within 5 mins, the recommended timer is 10 mins.
+		 * Here this route expiration time is set to ip6_rt_mtu_expires
+		 * which is 10 mins. After 10 mins the decreased pmtu is expired
+		 * and detecting PMTU increase will be automatically happened.
+		 */
+		dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
+		nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES;
+
 		ip6_ins_rt(nrt, NULL, NULL, NULL);
 	}
-
 out:
 	dst_release(&rt->u.dst);
 }
@@ -1280,6 +1367,57 @@
 	return rt;
 }
 
+#ifdef CONFIG_IPV6_ROUTE_INFO
+static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixlen,
+					   struct in6_addr *gwaddr, int ifindex)
+{
+	struct fib6_node *fn;
+	struct rt6_info *rt = NULL;
+
+	write_lock_bh(&rt6_lock);
+	fn = fib6_locate(&ip6_routing_table, prefix ,prefixlen, NULL, 0);
+	if (!fn)
+		goto out;
+
+	for (rt = fn->leaf; rt; rt = rt->u.next) {
+		if (rt->rt6i_dev->ifindex != ifindex)
+			continue;
+		if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
+			continue;
+		if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
+			continue;
+		dst_hold(&rt->u.dst);
+		break;
+	}
+out:
+	write_unlock_bh(&rt6_lock);
+	return rt;
+}
+
+static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixlen,
+					   struct in6_addr *gwaddr, int ifindex,
+					   unsigned pref)
+{
+	struct in6_rtmsg rtmsg;
+
+	memset(&rtmsg, 0, sizeof(rtmsg));
+	rtmsg.rtmsg_type = RTMSG_NEWROUTE;
+	ipv6_addr_copy(&rtmsg.rtmsg_dst, prefix);
+	rtmsg.rtmsg_dst_len = prefixlen;
+	ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr);
+	rtmsg.rtmsg_metric = 1024;
+	rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | RTF_UP | RTF_PREF(pref);
+	/* We should treat it as a default route if prefix length is 0. */
+	if (!prefixlen)
+		rtmsg.rtmsg_flags |= RTF_DEFAULT;
+	rtmsg.rtmsg_ifindex = ifindex;
+
+	ip6_route_add(&rtmsg, NULL, NULL, NULL);
+
+	return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex);
+}
+#endif
+	
 struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev)
 {	
 	struct rt6_info *rt;
@@ -1290,6 +1428,7 @@
 	write_lock_bh(&rt6_lock);
 	for (rt = fn->leaf; rt; rt=rt->u.next) {
 		if (dev == rt->rt6i_dev &&
+		    ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
 		    ipv6_addr_equal(&rt->rt6i_gateway, addr))
 			break;
 	}
@@ -1300,7 +1439,8 @@
 }
 
 struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
-				     struct net_device *dev)
+				     struct net_device *dev,
+				     unsigned int pref)
 {
 	struct in6_rtmsg rtmsg;
 
@@ -1308,7 +1448,8 @@
 	rtmsg.rtmsg_type = RTMSG_NEWROUTE;
 	ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr);
 	rtmsg.rtmsg_metric = 1024;
-	rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES;
+	rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES |
+			    RTF_PREF(pref);
 
 	rtmsg.rtmsg_ifindex = dev->ifindex;
 
@@ -1326,8 +1467,6 @@
 		if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) {
 			dst_hold(&rt->u.dst);
 
-			rt6_reset_dflt_pointer(NULL);
-
 			read_unlock_bh(&rt6_lock);
 
 			ip6_del_rt(rt, NULL, NULL, NULL);
diff -urN oldtree/net/ipv6/tcp_ipv6.c newtree/net/ipv6/tcp_ipv6.c
--- oldtree/net/ipv6/tcp_ipv6.c	2006-02-19 11:41:06.471359304 +0000
+++ newtree/net/ipv6/tcp_ipv6.c	2006-02-21 15:58:37.326472072 +0000
@@ -310,7 +310,7 @@
 }
 
 static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-		int type, int code, int offset, __u32 info)
+		int type, int code, int offset, __be32 info)
 {
 	struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
 	const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
@@ -987,6 +987,7 @@
 		inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
 						     newnp->opt->opt_flen);
 
+	tcp_mtup_init(newsk);
 	tcp_sync_mss(newsk, dst_mtu(dst));
 	newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
 	tcp_initialize_rcv_mss(newsk);
diff -urN oldtree/net/ipv6/udp.c newtree/net/ipv6/udp.c
--- oldtree/net/ipv6/udp.c	2006-02-19 11:41:06.472359152 +0000
+++ newtree/net/ipv6/udp.c	2006-02-21 15:58:37.328471768 +0000
@@ -311,7 +311,7 @@
 }
 
 static void udpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-	       int type, int code, int offset, __u32 info)
+	       int type, int code, int offset, __be32 info)
 {
 	struct ipv6_pinfo *np;
 	struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
diff -urN oldtree/net/ipv6/xfrm6_input.c newtree/net/ipv6/xfrm6_input.c
--- oldtree/net/ipv6/xfrm6_input.c	2006-02-19 11:41:06.473359000 +0000
+++ newtree/net/ipv6/xfrm6_input.c	2006-02-21 15:58:37.328471768 +0000
@@ -28,11 +28,11 @@
 		IP6_ECN_set_ce(inner_iph);
 }
 
-int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi)
+int xfrm6_rcv_spi(struct sk_buff **pskb, __be32 spi)
 {
 	struct sk_buff *skb = *pskb;
 	int err;
-	u32 seq;
+	__be32 seq;
 	struct sec_decap_state xfrm_vec[XFRM_MAX_DEPTH];
 	struct xfrm_state *x;
 	int xfrm_nr = 0;
diff -urN oldtree/net/ipv6/xfrm6_policy.c newtree/net/ipv6/xfrm6_policy.c
--- oldtree/net/ipv6/xfrm6_policy.c	2006-02-19 11:41:06.474358848 +0000
+++ newtree/net/ipv6/xfrm6_policy.c	2006-02-21 15:58:37.329471616 +0000
@@ -215,7 +215,7 @@
 		case IPPROTO_SCTP:
 		case IPPROTO_DCCP:
 			if (pskb_may_pull(skb, skb->nh.raw + offset + 4 - skb->data)) {
-				u16 *ports = (u16 *)exthdr;
+				__be16 *ports = (__be16 *)exthdr;
 
 				fl->fl_ip_sport = ports[0];
 				fl->fl_ip_dport = ports[1];
diff -urN oldtree/net/ipv6/xfrm6_state.c newtree/net/ipv6/xfrm6_state.c
--- oldtree/net/ipv6/xfrm6_state.c	2006-02-19 11:41:06.474358848 +0000
+++ newtree/net/ipv6/xfrm6_state.c	2006-02-21 15:58:37.329471616 +0000
@@ -29,9 +29,9 @@
 	ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, &fl->fl6_dst);
 	ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, &fl->fl6_src);
 	x->sel.dport = xfrm_flowi_dport(fl);
-	x->sel.dport_mask = ~0;
+	x->sel.dport_mask = htons(0xffff);
 	x->sel.sport = xfrm_flowi_sport(fl);
-	x->sel.sport_mask = ~0;
+	x->sel.sport_mask = htons(0xffff);
 	x->sel.prefixlen_d = 128;
 	x->sel.prefixlen_s = 128;
 	x->sel.proto = fl->proto;
@@ -64,7 +64,7 @@
 }
 
 static struct xfrm_state *
-__xfrm6_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto)
+__xfrm6_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto)
 {
 	unsigned h = __xfrm6_spi_hash(daddr, spi, proto);
 	struct xfrm_state *x;
diff -urN oldtree/net/ipv6/xfrm6_tunnel.c newtree/net/ipv6/xfrm6_tunnel.c
--- oldtree/net/ipv6/xfrm6_tunnel.c	2006-02-19 11:41:06.475358696 +0000
+++ newtree/net/ipv6/xfrm6_tunnel.c	2006-02-21 15:58:37.329471616 +0000
@@ -31,6 +31,7 @@
 #include <net/protocol.h>
 #include <linux/ipv6.h>
 #include <linux/icmpv6.h>
+#include <linux/mutex.h>
 
 #ifdef CONFIG_IPV6_XFRM6_TUNNEL_DEBUG
 # define X6TDEBUG	3
@@ -117,7 +118,7 @@
 
 	X6TPRINTK3(KERN_DEBUG "%s(addr=%p)\n", __FUNCTION__, addr);
 
-	h = addr->a6[0] ^ addr->a6[1] ^ addr->a6[2] ^ addr->a6[3];
+	h = (__force u32)(addr->a6[0] ^ addr->a6[1] ^ addr->a6[2] ^ addr->a6[3]);
 	h ^= h >> 16;
 	h ^= h >> 8;
 	h &= XFRM6_TUNNEL_SPI_BYADDR_HSIZE - 1;
@@ -201,7 +202,7 @@
 	return NULL;
 }
 
-u32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
+__be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
 {
 	struct xfrm6_tunnel_spi *x6spi;
 	u32 spi;
@@ -212,7 +213,7 @@
 	x6spi = __xfrm6_tunnel_spi_lookup(saddr);
 	spi = x6spi ? x6spi->spi : 0;
 	read_unlock_bh(&xfrm6_tunnel_spi_lock);
-	return spi;
+	return (__force __be32)spi;
 }
 
 EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup);
@@ -285,7 +286,7 @@
 	return spi;
 }
 
-u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr)
+__be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr)
 {
 	struct xfrm6_tunnel_spi *x6spi;
 	u32 spi;
@@ -303,7 +304,7 @@
 
 	X6TPRINTK3(KERN_DEBUG "%s() = %u\n", __FUNCTION__, spi);
 
-	return spi;
+	return (__force __be32)spi;
 }
 
 EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi);
@@ -357,19 +358,19 @@
 }
 
 static struct xfrm6_tunnel *xfrm6_tunnel_handler;
-static DECLARE_MUTEX(xfrm6_tunnel_sem);
+static DEFINE_MUTEX(xfrm6_tunnel_mutex);
 
 int xfrm6_tunnel_register(struct xfrm6_tunnel *handler)
 {
 	int ret;
 
-	down(&xfrm6_tunnel_sem);
+	mutex_lock(&xfrm6_tunnel_mutex);
 	ret = 0;
 	if (xfrm6_tunnel_handler != NULL)
 		ret = -EINVAL;
 	if (!ret)
 		xfrm6_tunnel_handler = handler;
-	up(&xfrm6_tunnel_sem);
+	mutex_unlock(&xfrm6_tunnel_mutex);
 
 	return ret;
 }
@@ -380,13 +381,13 @@
 {
 	int ret;
 
-	down(&xfrm6_tunnel_sem);
+	mutex_lock(&xfrm6_tunnel_mutex);
 	ret = 0;
 	if (xfrm6_tunnel_handler != handler)
 		ret = -EINVAL;
 	if (!ret)
 		xfrm6_tunnel_handler = NULL;
-	up(&xfrm6_tunnel_sem);
+	mutex_unlock(&xfrm6_tunnel_mutex);
 
 	synchronize_net();
 
@@ -400,7 +401,7 @@
 	struct sk_buff *skb = *pskb;
 	struct xfrm6_tunnel *handler = xfrm6_tunnel_handler;
 	struct ipv6hdr *iph = skb->nh.ipv6h;
-	u32 spi;
+	__be32 spi;
 
 	/* device-like_ip6ip6_handler() */
 	if (handler && handler->handler(pskb) == 0)
@@ -411,7 +412,7 @@
 }
 
 static void xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-			     int type, int code, int offset, __u32 info)
+			     int type, int code, int offset, __be32 info)
 {
 	struct xfrm6_tunnel *handler = xfrm6_tunnel_handler;
 
diff -urN oldtree/net/key/af_key.c newtree/net/key/af_key.c
--- oldtree/net/key/af_key.c	2006-02-19 11:41:06.483357480 +0000
+++ newtree/net/key/af_key.c	2006-02-21 15:58:16.645616040 +0000
@@ -2651,6 +2651,8 @@
 		return key_notify_sa(x, c);
 	case XFRM_MSG_FLUSHSA:
 		return key_notify_sa_flush(c);
+	case XFRM_MSG_NEWAE: /* not yet supported */
+		break;
 	default:
 		printk("pfkey: Unknown SA event %d\n", c->event);
 		break;
@@ -3078,9 +3080,9 @@
 	if (!hdr)
 		goto out;
 
-	down(&xfrm_cfg_sem);
+	mutex_lock(&xfrm_cfg_mutex);
 	err = pfkey_process(sk, skb, hdr);
-	up(&xfrm_cfg_sem);
+	mutex_unlock(&xfrm_cfg_mutex);
 
 out:
 	if (err && hdr && pfkey_error(hdr, err, sk) == 0)
diff -urN oldtree/net/netfilter/Kconfig newtree/net/netfilter/Kconfig
--- oldtree/net/netfilter/Kconfig	2006-02-19 11:41:06.485357176 +0000
+++ newtree/net/netfilter/Kconfig	2006-02-21 15:58:16.442646896 +0000
@@ -279,6 +279,16 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config NETFILTER_XT_MATCH_POLICY
+	tristate 'IPsec "policy" match support'
+	depends on NETFILTER_XTABLES && XFRM
+	help
+	  Policy matching allows you to match packets based on the
+	  IPsec policy that was used during decapsulation/will 
+	  be used during encapsulation.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_MATCH_PHYSDEV
 	tristate '"physdev" match support'
 	depends on NETFILTER_XTABLES && BRIDGE_NETFILTER
diff -urN oldtree/net/netfilter/Makefile newtree/net/netfilter/Makefile
--- oldtree/net/netfilter/Makefile	2006-02-19 11:41:06.486357024 +0000
+++ newtree/net/netfilter/Makefile	2006-02-21 15:58:16.442646896 +0000
@@ -40,6 +40,7 @@
 obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) += xt_mark.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o
diff -urN oldtree/net/netfilter/nf_conntrack_core.c newtree/net/netfilter/nf_conntrack_core.c
--- oldtree/net/netfilter/nf_conntrack_core.c	2006-02-19 11:41:06.487356872 +0000
+++ newtree/net/netfilter/nf_conntrack_core.c	2006-02-21 15:58:16.820589440 +0000
@@ -3,7 +3,7 @@
    extension. */
 
 /* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2005 Netfilter Core Team <coreteam@netfilter.org>
+ * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
  * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,9 @@
  *	- generalize L3 protocol denendent part.
  * 23 Mar 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
  *	- add support various size of conntrack structures.
+ * 26 Jan 2006: Harald Welte <laforge@netfilter.org>
+ * 	- restructure nf_conn (introduce nf_conn_help)
+ * 	- redesign 'features' how they were originally intended
  *
  * Derived from net/ipv4/netfilter/ip_conntrack_core.c
  */
@@ -55,7 +58,7 @@
 #include <net/netfilter/nf_conntrack_core.h>
 #include <linux/netfilter_ipv4/listhelp.h>
 
-#define NF_CONNTRACK_VERSION	"0.4.1"
+#define NF_CONNTRACK_VERSION	"0.5.0"
 
 #if 0
 #define DEBUGP printk
@@ -182,7 +185,7 @@
 DEFINE_RWLOCK(nf_ct_cache_lock);
 
 /* This avoids calling kmem_cache_create() with same name simultaneously */
-DECLARE_MUTEX(nf_ct_cache_mutex);
+static DEFINE_MUTEX(nf_ct_cache_mutex);
 
 extern struct nf_conntrack_protocol nf_conntrack_generic_protocol;
 struct nf_conntrack_protocol *
@@ -259,21 +262,8 @@
 				nf_conntrack_hash_rnd);
 }
 
-/* Initialize "struct nf_conn" which has spaces for helper */
-static int
-init_conntrack_for_helper(struct nf_conn *conntrack, u_int32_t features)
-{
-
-	conntrack->help = (union nf_conntrack_help *)
-		(((unsigned long)conntrack->data
-		  + (__alignof__(union nf_conntrack_help) - 1))
-		 & (~((unsigned long)(__alignof__(union nf_conntrack_help) -1))));
-	return 0;
-}
-
 int nf_conntrack_register_cache(u_int32_t features, const char *name,
-				size_t size,
-				int (*init)(struct nf_conn *, u_int32_t))
+				size_t size)
 {
 	int ret = 0;
 	char *cache_name;
@@ -288,7 +278,7 @@
 		return -EINVAL;
 	}
 
-	down(&nf_ct_cache_mutex);
+	mutex_lock(&nf_ct_cache_mutex);
 
 	write_lock_bh(&nf_ct_cache_lock);
 	/* e.g: multiple helpers are loaded */
@@ -296,8 +286,7 @@
 		DEBUGP("nf_conntrack_register_cache: already resisterd.\n");
 		if ((!strncmp(nf_ct_cache[features].name, name,
 			      NF_CT_FEATURES_NAMELEN))
-		    && nf_ct_cache[features].size == size
-		    && nf_ct_cache[features].init_conntrack == init) {
+		    && nf_ct_cache[features].size == size) {
 			DEBUGP("nf_conntrack_register_cache: reusing.\n");
 			nf_ct_cache[features].use++;
 			ret = 0;
@@ -305,7 +294,7 @@
 			ret = -EBUSY;
 
 		write_unlock_bh(&nf_ct_cache_lock);
-		up(&nf_ct_cache_mutex);
+		mutex_unlock(&nf_ct_cache_mutex);
 		return ret;
 	}
 	write_unlock_bh(&nf_ct_cache_lock);
@@ -340,7 +329,6 @@
 	write_lock_bh(&nf_ct_cache_lock);
 	nf_ct_cache[features].use = 1;
 	nf_ct_cache[features].size = size;
-	nf_ct_cache[features].init_conntrack = init;
 	nf_ct_cache[features].cachep = cachep;
 	nf_ct_cache[features].name = cache_name;
 	write_unlock_bh(&nf_ct_cache_lock);
@@ -350,7 +338,7 @@
 out_free_name:
 	kfree(cache_name);
 out_up_mutex:
-	up(&nf_ct_cache_mutex);
+	mutex_unlock(&nf_ct_cache_mutex);
 	return ret;
 }
 
@@ -365,19 +353,18 @@
 	 * slab cache.
 	 */
 	DEBUGP("nf_conntrack_unregister_cache: 0x%04x\n", features);
-	down(&nf_ct_cache_mutex);
+	mutex_lock(&nf_ct_cache_mutex);
 
 	write_lock_bh(&nf_ct_cache_lock);
 	if (--nf_ct_cache[features].use > 0) {
 		write_unlock_bh(&nf_ct_cache_lock);
-		up(&nf_ct_cache_mutex);
+		mutex_unlock(&nf_ct_cache_mutex);
 		return;
 	}
 	cachep = nf_ct_cache[features].cachep;
 	name = nf_ct_cache[features].name;
 	nf_ct_cache[features].cachep = NULL;
 	nf_ct_cache[features].name = NULL;
-	nf_ct_cache[features].init_conntrack = NULL;
 	nf_ct_cache[features].size = 0;
 	write_unlock_bh(&nf_ct_cache_lock);
 
@@ -386,7 +373,7 @@
 	kmem_cache_destroy(cachep);
 	kfree(name);
 
-	up(&nf_ct_cache_mutex);
+	mutex_unlock(&nf_ct_cache_mutex);
 }
 
 int
@@ -432,11 +419,15 @@
 /* nf_conntrack_expect helper functions */
 void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
 {
+	struct nf_conn_help *master_help = nfct_help(exp->master);
+
+	NF_CT_ASSERT(master_help);
 	ASSERT_WRITE_LOCK(&nf_conntrack_lock);
 	NF_CT_ASSERT(!timer_pending(&exp->timeout));
+
 	list_del(&exp->list);
 	NF_CT_STAT_INC(expect_delete);
-	exp->master->expecting--;
+	master_help->expecting--;
 	nf_conntrack_expect_put(exp);
 }
 
@@ -508,9 +499,10 @@
 void nf_ct_remove_expectations(struct nf_conn *ct)
 {
 	struct nf_conntrack_expect *i, *tmp;
+	struct nf_conn_help *help = nfct_help(ct);
 
 	/* Optimization: most connection never expect any others. */
-	if (ct->expecting == 0)
+	if (!help || help->expecting == 0)
 		return;
 
 	list_for_each_entry_safe(i, tmp, &nf_conntrack_expect_list, list) {
@@ -713,6 +705,7 @@
 			  conntrack_tuple_cmp,
 			  struct nf_conntrack_tuple_hash *,
 			  &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) {
+		struct nf_conn_help *help;
 		/* Remove from unconfirmed list */
 		list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
 
@@ -726,7 +719,8 @@
 		set_bit(IPS_CONFIRMED_BIT, &ct->status);
 		NF_CT_STAT_INC(insert);
 		write_unlock_bh(&nf_conntrack_lock);
-		if (ct->helper)
+		help = nfct_help(ct);
+		if (help && help->helper)
 			nf_conntrack_event_cache(IPCT_HELPER, *pskb);
 #ifdef CONFIG_NF_NAT_NEEDED
 		if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) ||
@@ -842,8 +836,9 @@
 {
 	struct nf_conn *conntrack = NULL;
 	u_int32_t features = 0;
+	struct nf_conntrack_helper *helper;
 
-	if (!nf_conntrack_hash_rnd_initted) {
+	if (unlikely(!nf_conntrack_hash_rnd_initted)) {
 		get_random_bytes(&nf_conntrack_hash_rnd, 4);
 		nf_conntrack_hash_rnd_initted = 1;
 	}
@@ -863,8 +858,11 @@
 
 	/*  find features needed by this conntrack. */
 	features = l3proto->get_features(orig);
+
+	/* FIXME: protect helper list per RCU */
 	read_lock_bh(&nf_conntrack_lock);
-	if (__nf_ct_helper_find(repl) != NULL)
+	helper = __nf_ct_helper_find(repl);
+	if (helper)
 		features |= NF_CT_F_HELP;
 	read_unlock_bh(&nf_conntrack_lock);
 
@@ -872,7 +870,7 @@
 
 	read_lock_bh(&nf_ct_cache_lock);
 
-	if (!nf_ct_cache[features].use) {
+	if (unlikely(!nf_ct_cache[features].use)) {
 		DEBUGP("nf_conntrack_alloc: not supported features = 0x%x\n",
 			features);
 		goto out;
@@ -886,12 +884,10 @@
 
 	memset(conntrack, 0, nf_ct_cache[features].size);
 	conntrack->features = features;
-	if (nf_ct_cache[features].init_conntrack &&
-	    nf_ct_cache[features].init_conntrack(conntrack, features) < 0) {
-		DEBUGP("nf_conntrack_alloc: failed to init\n");
-		kmem_cache_free(nf_ct_cache[features].cachep, conntrack);
-		conntrack = NULL;
-		goto out;
+	if (helper) {
+		struct nf_conn_help *help = nfct_help(conntrack);
+		NF_CT_ASSERT(help);
+		help->helper = helper;
 	}
 
 	atomic_set(&conntrack->ct_general.use, 1);
@@ -972,11 +968,8 @@
 #endif
 		nf_conntrack_get(&conntrack->master->ct_general);
 		NF_CT_STAT_INC(expect_new);
-	} else {
-		conntrack->helper = __nf_ct_helper_find(&repl_tuple);
-
+	} else
 		NF_CT_STAT_INC(new);
-        }
 
 	/* Overload tuple linked list to put us in unconfirmed list. */
 	list_add(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list, &unconfirmed);
@@ -1206,14 +1199,16 @@
 
 static void nf_conntrack_expect_insert(struct nf_conntrack_expect *exp)
 {
+	struct nf_conn_help *master_help = nfct_help(exp->master);
+
 	atomic_inc(&exp->use);
-	exp->master->expecting++;
+	master_help->expecting++;
 	list_add(&exp->list, &nf_conntrack_expect_list);
 
 	init_timer(&exp->timeout);
 	exp->timeout.data = (unsigned long)exp;
 	exp->timeout.function = expectation_timed_out;
-	exp->timeout.expires = jiffies + exp->master->helper->timeout * HZ;
+	exp->timeout.expires = jiffies + master_help->helper->timeout * HZ;
 	add_timer(&exp->timeout);
 
 	exp->id = ++nf_conntrack_expect_next_id;
@@ -1239,10 +1234,12 @@
 
 static inline int refresh_timer(struct nf_conntrack_expect *i)
 {
+	struct nf_conn_help *master_help = nfct_help(i->master);
+
 	if (!del_timer(&i->timeout))
 		return 0;
 
-	i->timeout.expires = jiffies + i->master->helper->timeout*HZ;
+	i->timeout.expires = jiffies + master_help->helper->timeout*HZ;
 	add_timer(&i->timeout);
 	return 1;
 }
@@ -1251,8 +1248,11 @@
 {
 	struct nf_conntrack_expect *i;
 	struct nf_conn *master = expect->master;
+	struct nf_conn_help *master_help = nfct_help(master);
 	int ret;
 
+	NF_CT_ASSERT(master_help);
+
 	DEBUGP("nf_conntrack_expect_related %p\n", related_to);
 	DEBUGP("tuple: "); NF_CT_DUMP_TUPLE(&expect->tuple);
 	DEBUGP("mask:  "); NF_CT_DUMP_TUPLE(&expect->mask);
@@ -1271,8 +1271,8 @@
 		}
 	}
 	/* Will be over limit? */
-	if (master->helper->max_expected && 
-	    master->expecting >= master->helper->max_expected)
+	if (master_help->helper->max_expected && 
+	    master_help->expecting >= master_help->helper->max_expected)
 		evict_oldest_expect(master);
 
 	nf_conntrack_expect_insert(expect);
@@ -1283,24 +1283,6 @@
 	return ret;
 }
 
-/* Alter reply tuple (maybe alter helper).  This is for NAT, and is
-   implicitly racy: see __nf_conntrack_confirm */
-void nf_conntrack_alter_reply(struct nf_conn *conntrack,
-			      const struct nf_conntrack_tuple *newreply)
-{
-	write_lock_bh(&nf_conntrack_lock);
-	/* Should be unconfirmed, so not in hash table yet */
-	NF_CT_ASSERT(!nf_ct_is_confirmed(conntrack));
-
-	DEBUGP("Altering reply tuple of %p to ", conntrack);
-	NF_CT_DUMP_TUPLE(newreply);
-
-	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
-	if (!conntrack->master && conntrack->expecting == 0)
-		conntrack->helper = __nf_ct_helper_find(newreply);
-	write_unlock_bh(&nf_conntrack_lock);
-}
-
 int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
 {
 	int ret;
@@ -1308,9 +1290,8 @@
 
 	ret = nf_conntrack_register_cache(NF_CT_F_HELP, "nf_conntrack:help",
 					  sizeof(struct nf_conn)
-					  + sizeof(union nf_conntrack_help)
-					  + __alignof__(union nf_conntrack_help),
-					  init_conntrack_for_helper);
+					  + sizeof(struct nf_conn_help)
+					  + __alignof__(struct nf_conn_help));
 	if (ret < 0) {
 		printk(KERN_ERR "nf_conntrack_helper_reigster: Unable to create slab cache for conntracks\n");
 		return ret;
@@ -1338,9 +1319,12 @@
 static inline int unhelp(struct nf_conntrack_tuple_hash *i,
 			 const struct nf_conntrack_helper *me)
 {
-	if (nf_ct_tuplehash_to_ctrack(i)->helper == me) {
-		nf_conntrack_event(IPCT_HELPER, nf_ct_tuplehash_to_ctrack(i));
-		nf_ct_tuplehash_to_ctrack(i)->helper = NULL;
+	struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(i);
+	struct nf_conn_help *help = nfct_help(ct);
+
+	if (help && help->helper == me) {
+		nf_conntrack_event(IPCT_HELPER, ct);
+		help->helper = NULL;
 	}
 	return 0;
 }
@@ -1356,7 +1340,8 @@
 
 	/* Get rid of expectations */
 	list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, list) {
-		if (exp->master->helper == me && del_timer(&exp->timeout)) {
+		struct nf_conn_help *help = nfct_help(exp->master);
+		if (help->helper == me && del_timer(&exp->timeout)) {
 			nf_ct_unlink_expect(exp);
 			nf_conntrack_expect_put(exp);
 		}
@@ -1423,6 +1408,8 @@
 
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_conntrack.h>
+#include <linux/mutex.h>
+
 
 /* Generic function for tcp/udp/sctp/dccp and alike. This needs to be
  * in ip_conntrack_core, since we don't want the protocols to autoload
@@ -1697,7 +1684,7 @@
 	}
 
 	ret = nf_conntrack_register_cache(NF_CT_F_BASIC, "nf_conntrack:basic",
-					  sizeof(struct nf_conn), NULL);
+					  sizeof(struct nf_conn));
 	if (ret < 0) {
 		printk(KERN_ERR "Unable to create nf_conn slab cache\n");
 		goto err_free_hash;
diff -urN oldtree/net/netfilter/nf_conntrack_ftp.c newtree/net/netfilter/nf_conntrack_ftp.c
--- oldtree/net/netfilter/nf_conntrack_ftp.c	2006-02-19 11:41:06.488356720 +0000
+++ newtree/net/netfilter/nf_conntrack_ftp.c	2006-02-21 15:58:16.445646440 +0000
@@ -440,7 +440,7 @@
 	u32 seq;
 	int dir = CTINFO2DIR(ctinfo);
 	unsigned int matchlen, matchoff;
-	struct ip_ct_ftp_master *ct_ftp_info = &ct->help->ct_ftp_info;
+	struct ip_ct_ftp_master *ct_ftp_info = &nfct_help(ct)->help.ct_ftp_info;
 	struct nf_conntrack_expect *exp;
 	struct nf_conntrack_man cmd = {};
 
diff -urN oldtree/net/netfilter/nf_conntrack_netlink.c newtree/net/netfilter/nf_conntrack_netlink.c
--- oldtree/net/netfilter/nf_conntrack_netlink.c	2006-02-19 11:41:06.490356416 +0000
+++ newtree/net/netfilter/nf_conntrack_netlink.c	2006-02-21 15:58:16.446646288 +0000
@@ -2,7 +2,7 @@
  * protocol helpers and general trouble making from userspace.
  *
  * (C) 2001 by Jay Schulist <jschlst@samba.org>
- * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2002-2006 by Harald Welte <laforge@gnumonks.org>
  * (C) 2003 by Patrick Mchardy <kaber@trash.net>
  * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
  *
@@ -44,7 +44,7 @@
 
 MODULE_LICENSE("GPL");
 
-static char __initdata version[] = "0.92";
+static char __initdata version[] = "0.93";
 
 #if 0
 #define DEBUGP printk
@@ -165,15 +165,16 @@
 ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct)
 {
 	struct nfattr *nest_helper;
+	const struct nf_conn_help *help = nfct_help(ct);
 
-	if (!ct->helper)
+	if (!help || !help->helper)
 		return 0;
 		
 	nest_helper = NFA_NEST(skb, CTA_HELP);
-	NFA_PUT(skb, CTA_HELP_NAME, strlen(ct->helper->name), ct->helper->name);
+	NFA_PUT(skb, CTA_HELP_NAME, strlen(help->helper->name), help->helper->name);
 
-	if (ct->helper->to_nfattr)
-		ct->helper->to_nfattr(skb, ct);
+	if (help->helper->to_nfattr)
+		help->helper->to_nfattr(skb, ct);
 
 	NFA_NEST_END(skb, nest_helper);
 
@@ -337,9 +338,10 @@
 		group = NFNLGRP_CONNTRACK_UPDATE;
 	} else
 		return NOTIFY_DONE;
-	
-  /* FIXME: Check if there are any listeners before, don't hurt performance */
-	
+
+	if (!nfnetlink_has_listeners(group))
+		return NOTIFY_DONE;
+
 	skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
 	if (!skb)
 		return NOTIFY_DONE;
@@ -903,11 +905,17 @@
 ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[])
 {
 	struct nf_conntrack_helper *helper;
+	struct nf_conn_help *help = nfct_help(ct);
 	char *helpname;
 	int err;
 
 	DEBUGP("entered %s\n", __FUNCTION__);
 
+	if (!help) {
+		/* FIXME: we need to reallocate and rehash */
+		return -EBUSY;
+	}
+
 	/* don't change helper of sibling connections */
 	if (ct->master)
 		return -EINVAL;
@@ -924,18 +932,18 @@
 			return -EINVAL;
 	}
 
-	if (ct->helper) {
+	if (help->helper) {
 		if (!helper) {
 			/* we had a helper before ... */
 			nf_ct_remove_expectations(ct);
-			ct->helper = NULL;
+			help->helper = NULL;
 		} else {
 			/* need to zero data of old helper */
-			memset(&ct->help, 0, sizeof(ct->help));
+			memset(&help->help, 0, sizeof(help->help));
 		}
 	}
 	
-	ct->helper = helper;
+	help->helper = helper;
 
 	return 0;
 }
@@ -1050,14 +1058,9 @@
 		ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
 #endif
 
-	ct->helper = nf_ct_helper_find_get(rtuple);
-
 	add_timer(&ct->timeout);
 	nf_conntrack_hash_insert(ct);
 
-	if (ct->helper)
-		nf_ct_helper_put(ct->helper);
-
 	DEBUGP("conntrack with id %u inserted\n", ct->id);
 	return 0;
 
@@ -1417,7 +1420,8 @@
 		}
 		list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list,
 					 list) {
-			if (exp->master->helper == h 
+			struct nf_conn_help *m_help = nfct_help(exp->master);
+			if (m_help->helper == h 
 			    && del_timer(&exp->timeout)) {
 				nf_ct_unlink_expect(exp);
 				nf_conntrack_expect_put(exp);
@@ -1452,6 +1456,7 @@
 	struct nf_conntrack_tuple_hash *h = NULL;
 	struct nf_conntrack_expect *exp;
 	struct nf_conn *ct;
+	struct nf_conn_help *help;
 	int err = 0;
 
 	DEBUGP("entered %s\n", __FUNCTION__);
@@ -1472,8 +1477,9 @@
 	if (!h)
 		return -ENOENT;
 	ct = nf_ct_tuplehash_to_ctrack(h);
+	help = nfct_help(ct);
 
-	if (!ct->helper) {
+	if (!help || !help->helper) {
 		/* such conntrack hasn't got any helper, abort */
 		err = -EINVAL;
 		goto out;
diff -urN oldtree/net/netfilter/nf_conntrack_standalone.c newtree/net/netfilter/nf_conntrack_standalone.c
--- oldtree/net/netfilter/nf_conntrack_standalone.c	2006-02-19 11:41:06.495355656 +0000
+++ newtree/net/netfilter/nf_conntrack_standalone.c	2006-02-21 15:58:16.450645680 +0000
@@ -839,7 +839,6 @@
 EXPORT_SYMBOL(nf_conntrack_protocol_register);
 EXPORT_SYMBOL(nf_conntrack_protocol_unregister);
 EXPORT_SYMBOL(nf_ct_invert_tuplepr);
-EXPORT_SYMBOL(nf_conntrack_alter_reply);
 EXPORT_SYMBOL(nf_conntrack_destroyed);
 EXPORT_SYMBOL(need_conntrack);
 EXPORT_SYMBOL(nf_conntrack_helper_register);
diff -urN oldtree/net/netfilter/nf_sockopt.c newtree/net/netfilter/nf_sockopt.c
--- oldtree/net/netfilter/nf_sockopt.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/netfilter/nf_sockopt.c	2006-02-21 15:58:16.646615888 +0000
@@ -4,6 +4,7 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/netfilter.h>
+#include <linux/mutex.h>
 #include <net/sock.h>
 
 #include "nf_internals.h"
@@ -11,7 +12,7 @@
 /* Sockopts only registered and called from user context, so
    net locking would be overkill.  Also, [gs]etsockopt calls may
    sleep. */
-static DECLARE_MUTEX(nf_sockopt_mutex);
+static DEFINE_MUTEX(nf_sockopt_mutex);
 static LIST_HEAD(nf_sockopts);
 
 /* Do exclusive ranges overlap? */
@@ -26,7 +27,7 @@
 	struct list_head *i;
 	int ret = 0;
 
-	if (down_interruptible(&nf_sockopt_mutex) != 0)
+	if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)
 		return -EINTR;
 
 	list_for_each(i, &nf_sockopts) {
@@ -48,7 +49,7 @@
 
 	list_add(&reg->list, &nf_sockopts);
 out:
-	up(&nf_sockopt_mutex);
+	mutex_unlock(&nf_sockopt_mutex);
 	return ret;
 }
 EXPORT_SYMBOL(nf_register_sockopt);
@@ -57,18 +58,18 @@
 {
 	/* No point being interruptible: we're probably in cleanup_module() */
  restart:
-	down(&nf_sockopt_mutex);
+	mutex_lock(&nf_sockopt_mutex);
 	if (reg->use != 0) {
 		/* To be woken by nf_sockopt call... */
 		/* FIXME: Stuart Young's name appears gratuitously. */
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		reg->cleanup_task = current;
-		up(&nf_sockopt_mutex);
+		mutex_unlock(&nf_sockopt_mutex);
 		schedule();
 		goto restart;
 	}
 	list_del(&reg->list);
-	up(&nf_sockopt_mutex);
+	mutex_unlock(&nf_sockopt_mutex);
 }
 EXPORT_SYMBOL(nf_unregister_sockopt);
 
@@ -80,7 +81,7 @@
 	struct nf_sockopt_ops *ops;
 	int ret;
 
-	if (down_interruptible(&nf_sockopt_mutex) != 0)
+	if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)
 		return -EINTR;
 
 	list_for_each(i, &nf_sockopts) {
@@ -90,7 +91,7 @@
 				if (val >= ops->get_optmin
 				    && val < ops->get_optmax) {
 					ops->use++;
-					up(&nf_sockopt_mutex);
+					mutex_unlock(&nf_sockopt_mutex);
 					ret = ops->get(sk, val, opt, len);
 					goto out;
 				}
@@ -98,22 +99,22 @@
 				if (val >= ops->set_optmin
 				    && val < ops->set_optmax) {
 					ops->use++;
-					up(&nf_sockopt_mutex);
+					mutex_unlock(&nf_sockopt_mutex);
 					ret = ops->set(sk, val, opt, *len);
 					goto out;
 				}
 			}
 		}
 	}
-	up(&nf_sockopt_mutex);
+	mutex_unlock(&nf_sockopt_mutex);
 	return -ENOPROTOOPT;
 	
  out:
-	down(&nf_sockopt_mutex);
+	mutex_lock(&nf_sockopt_mutex);
 	ops->use--;
 	if (ops->cleanup_task)
 		wake_up_process(ops->cleanup_task);
-	up(&nf_sockopt_mutex);
+	mutex_unlock(&nf_sockopt_mutex);
 	return ret;
 }
 
diff -urN oldtree/net/netfilter/nfnetlink.c newtree/net/netfilter/nfnetlink.c
--- oldtree/net/netfilter/nfnetlink.c	2006-02-19 11:41:06.496355504 +0000
+++ newtree/net/netfilter/nfnetlink.c	2006-02-21 15:58:16.451645528 +0000
@@ -191,6 +191,12 @@
         return 0;
 }
 
+int nfnetlink_has_listeners(unsigned int group)
+{
+	return netlink_has_listeners(nfnl, group);
+}
+EXPORT_SYMBOL_GPL(nfnetlink_has_listeners);
+
 int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo)
 {
 	gfp_t allocation = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
diff -urN oldtree/net/netfilter/nfnetlink_log.c newtree/net/netfilter/nfnetlink_log.c
--- oldtree/net/netfilter/nfnetlink_log.c	2006-02-19 11:41:06.496355504 +0000
+++ newtree/net/netfilter/nfnetlink_log.c	2006-02-21 15:58:16.452645376 +0000
@@ -11,6 +11,10 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
+ * 2006-01-26 Harald Welte <laforge@netfilter.org>
+ * 	- Add optional local and global sequence number to detect lost 
+ * 	  events from userspace
+ *
  */
 #include <linux/module.h>
 #include <linux/skbuff.h>
@@ -68,11 +72,14 @@
 	unsigned int nlbufsiz;		/* netlink buffer allocation size */
 	unsigned int qthreshold;	/* threshold of the queue */
 	u_int32_t copy_range;
+	u_int32_t seq;			/* instance-local sequential counter */
 	u_int16_t group_num;		/* number of this queue */
+	u_int16_t flags;
 	u_int8_t copy_mode;	
 };
 
 static DEFINE_RWLOCK(instances_lock);
+static atomic_t global_seq;
 
 #define INSTANCE_BUCKETS	16
 static struct hlist_head instance_table[INSTANCE_BUCKETS];
@@ -310,6 +317,16 @@
 	return 0;
 }
 
+static int
+nfulnl_set_flags(struct nfulnl_instance *inst, u_int16_t flags)
+{
+	spin_lock_bh(&inst->lock);
+	inst->flags = ntohs(flags);
+	spin_unlock_bh(&inst->lock);
+
+	return 0;
+}
+
 static struct sk_buff *nfulnl_alloc_skb(unsigned int inst_size, 
 					unsigned int pkt_size)
 {
@@ -377,6 +394,8 @@
 	spin_unlock_bh(&inst->lock);
 }
 
+/* This is an inline function, we don't really care about a long
+ * list of arguments */
 static inline int 
 __build_packet_message(struct nfulnl_instance *inst,
 			const struct sk_buff *skb, 
@@ -515,6 +534,17 @@
 			read_unlock_bh(&skb->sk->sk_callback_lock);
 	}
 
+	/* local sequence number */
+	if (inst->flags & NFULNL_CFG_F_SEQ) {
+		tmp_uint = htonl(inst->seq++);
+		NFA_PUT(inst->skb, NFULA_SEQ, sizeof(tmp_uint), &tmp_uint);
+	}
+	/* global sequence number */
+	if (inst->flags & NFULNL_CFG_F_SEQ_GLOBAL) {
+		tmp_uint = atomic_inc_return(&global_seq);
+		NFA_PUT(inst->skb, NFULA_SEQ_GLOBAL, sizeof(tmp_uint), &tmp_uint);
+	}
+
 	if (data_len) {
 		struct nfattr *nfa;
 		int size = NFA_LENGTH(data_len);
@@ -607,6 +637,11 @@
 
 	spin_lock_bh(&inst->lock);
 
+	if (inst->flags & NFULNL_CFG_F_SEQ)
+		size += NFA_SPACE(sizeof(u_int32_t));
+	if (inst->flags & NFULNL_CFG_F_SEQ_GLOBAL)
+		size += NFA_SPACE(sizeof(u_int32_t));
+
 	qthreshold = inst->qthreshold;
 	/* per-rule qthreshold overrides per-instance */
 	if (qthreshold > li->u.ulog.qthreshold)
@@ -736,10 +771,14 @@
 	[NFULA_TIMESTAMP-1]	= sizeof(struct nfulnl_msg_packet_timestamp),
 	[NFULA_IFINDEX_INDEV-1]	= sizeof(u_int32_t),
 	[NFULA_IFINDEX_OUTDEV-1]= sizeof(u_int32_t),
+	[NFULA_IFINDEX_PHYSINDEV-1]	= sizeof(u_int32_t),
+	[NFULA_IFINDEX_PHYSOUTDEV-1]	= sizeof(u_int32_t),
 	[NFULA_HWADDR-1]	= sizeof(struct nfulnl_msg_packet_hw),
 	[NFULA_PAYLOAD-1]	= 0,
 	[NFULA_PREFIX-1]	= 0,
 	[NFULA_UID-1]		= sizeof(u_int32_t),
+	[NFULA_SEQ-1]		= sizeof(u_int32_t),
+	[NFULA_SEQ_GLOBAL-1]	= sizeof(u_int32_t),
 };
 
 static const int nfula_cfg_min[NFULA_CFG_MAX] = {
@@ -748,6 +787,7 @@
 	[NFULA_CFG_TIMEOUT-1]	= sizeof(u_int32_t),
 	[NFULA_CFG_QTHRESH-1]	= sizeof(u_int32_t),
 	[NFULA_CFG_NLBUFSIZ-1]	= sizeof(u_int32_t),
+	[NFULA_CFG_FLAGS-1]	= sizeof(u_int16_t),
 };
 
 static int
@@ -859,6 +899,12 @@
 		nfulnl_set_qthresh(inst, ntohl(qthresh));
 	}
 
+	if (nfula[NFULA_CFG_FLAGS-1]) {
+		u_int16_t flags =
+			*(u_int16_t *)NFA_DATA(nfula[NFULA_CFG_FLAGS-1]);
+		nfulnl_set_flags(inst, ntohl(flags));
+	}
+
 out_put:
 	instance_put(inst);
 	return ret;
diff -urN oldtree/net/netfilter/x_tables.c newtree/net/netfilter/x_tables.c
--- oldtree/net/netfilter/x_tables.c	2006-02-19 11:41:06.499355048 +0000
+++ newtree/net/netfilter/x_tables.c	2006-02-21 15:58:27.375984776 +0000
@@ -21,10 +21,12 @@
 #include <linux/seq_file.h>
 #include <linux/string.h>
 #include <linux/vmalloc.h>
+#include <linux/mutex.h>
 
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_arp.h>
 
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
 MODULE_DESCRIPTION("[ip,ip6,arp]_tables backend module");
@@ -32,7 +34,7 @@
 #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
 
 struct xt_af {
-	struct semaphore mutex;
+	struct mutex mutex;
 	struct list_head match;
 	struct list_head target;
 	struct list_head tables;
@@ -52,17 +54,23 @@
 	MATCH,
 };
 
+static const char *xt_prefix[NPROTO] = {
+	[AF_INET] 	= "ip",
+	[AF_INET6] 	= "ip6",
+	[NF_ARP]	= "arp",
+};
+
 /* Registration hooks for targets. */
 int
 xt_register_target(int af, struct xt_target *target)
 {
 	int ret;
 
-	ret = down_interruptible(&xt[af].mutex);
+	ret = mutex_lock_interruptible(&xt[af].mutex);
 	if (ret != 0)
 		return ret;
 	list_add(&target->list, &xt[af].target);
-	up(&xt[af].mutex);
+	mutex_unlock(&xt[af].mutex);
 	return ret;
 }
 EXPORT_SYMBOL(xt_register_target);
@@ -70,9 +78,9 @@
 void
 xt_unregister_target(int af, struct xt_target *target)
 {
-	down(&xt[af].mutex);
+	mutex_lock(&xt[af].mutex);
 	LIST_DELETE(&xt[af].target, target);
-	up(&xt[af].mutex);
+	mutex_unlock(&xt[af].mutex);
 }
 EXPORT_SYMBOL(xt_unregister_target);
 
@@ -81,12 +89,12 @@
 {
 	int ret;
 
-	ret = down_interruptible(&xt[af].mutex);
+	ret = mutex_lock_interruptible(&xt[af].mutex);
 	if (ret != 0)
 		return ret;
 
 	list_add(&match->list, &xt[af].match);
-	up(&xt[af].mutex);
+	mutex_unlock(&xt[af].mutex);
 
 	return ret;
 }
@@ -95,9 +103,9 @@
 void
 xt_unregister_match(int af, struct xt_match *match)
 {
-	down(&xt[af].mutex);
+	mutex_lock(&xt[af].mutex);
 	LIST_DELETE(&xt[af].match, match);
-	up(&xt[af].mutex);
+	mutex_unlock(&xt[af].mutex);
 }
 EXPORT_SYMBOL(xt_unregister_match);
 
@@ -114,21 +122,21 @@
 	struct xt_match *m;
 	int err = 0;
 
-	if (down_interruptible(&xt[af].mutex) != 0)
+	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
 		return ERR_PTR(-EINTR);
 
 	list_for_each_entry(m, &xt[af].match, list) {
 		if (strcmp(m->name, name) == 0) {
 			if (m->revision == revision) {
 				if (try_module_get(m->me)) {
-					up(&xt[af].mutex);
+					mutex_unlock(&xt[af].mutex);
 					return m;
 				}
 			} else
 				err = -EPROTOTYPE; /* Found something. */
 		}
 	}
-	up(&xt[af].mutex);
+	mutex_unlock(&xt[af].mutex);
 	return ERR_PTR(err);
 }
 EXPORT_SYMBOL(xt_find_match);
@@ -139,37 +147,31 @@
 	struct xt_target *t;
 	int err = 0;
 
-	if (down_interruptible(&xt[af].mutex) != 0)
+	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
 		return ERR_PTR(-EINTR);
 
 	list_for_each_entry(t, &xt[af].target, list) {
 		if (strcmp(t->name, name) == 0) {
 			if (t->revision == revision) {
 				if (try_module_get(t->me)) {
-					up(&xt[af].mutex);
+					mutex_unlock(&xt[af].mutex);
 					return t;
 				}
 			} else
 				err = -EPROTOTYPE; /* Found something. */
 		}
 	}
-	up(&xt[af].mutex);
+	mutex_unlock(&xt[af].mutex);
 	return ERR_PTR(err);
 }
 EXPORT_SYMBOL(xt_find_target);
 
-static const char *xt_prefix[NPROTO] = {
-	[AF_INET] 	= "ipt_%s",
-	[AF_INET6] 	= "ip6t_%s",
-	[NF_ARP]	= "arpt_%s",
-};
-
 struct xt_target *xt_request_find_target(int af, const char *name, u8 revision)
 {
 	struct xt_target *target;
 
 	target = try_then_request_module(xt_find_target(af, name, revision),
-					 xt_prefix[af], name);
+					 "%st_%s", xt_prefix[af], name);
 	if (IS_ERR(target) || !target)
 		return NULL;
 	return target;
@@ -214,7 +216,7 @@
 {
 	int have_rev, best = -1;
 
-	if (down_interruptible(&xt[af].mutex) != 0) {
+	if (mutex_lock_interruptible(&xt[af].mutex) != 0) {
 		*err = -EINTR;
 		return 1;
 	}
@@ -222,7 +224,7 @@
 		have_rev = target_revfn(af, name, revision, &best);
 	else
 		have_rev = match_revfn(af, name, revision, &best);
-	up(&xt[af].mutex);
+	mutex_unlock(&xt[af].mutex);
 
 	/* Nothing at all?  Return 0 to try loading module. */
 	if (best == -1) {
@@ -237,6 +239,64 @@
 }
 EXPORT_SYMBOL_GPL(xt_find_revision);
 
+int xt_check_match(const struct xt_match *match, unsigned short family,
+                   unsigned int size, const char *table, unsigned int hook_mask,
+		   unsigned short proto, int inv_proto)
+{
+	if (XT_ALIGN(match->matchsize) != size) {
+		printk("%s_tables: %s match: invalid size %Zu != %u\n",
+		       xt_prefix[family], match->name,
+		       XT_ALIGN(match->matchsize), size);
+		return -EINVAL;
+	}
+	if (match->table && strcmp(match->table, table)) {
+		printk("%s_tables: %s match: only valid in %s table, not %s\n",
+		       xt_prefix[family], match->name, match->table, table);
+		return -EINVAL;
+	}
+	if (match->hooks && (hook_mask & ~match->hooks) != 0) {
+		printk("%s_tables: %s match: bad hook_mask %u\n",
+		       xt_prefix[family], match->name, hook_mask);
+		return -EINVAL;
+	}
+	if (match->proto && (match->proto != proto || inv_proto)) {
+		printk("%s_tables: %s match: only valid for protocol %u\n",
+		       xt_prefix[family], match->name, match->proto);
+		return -EINVAL;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(xt_check_match);
+
+int xt_check_target(const struct xt_target *target, unsigned short family,
+		    unsigned int size, const char *table, unsigned int hook_mask,
+		    unsigned short proto, int inv_proto)
+{
+	if (XT_ALIGN(target->targetsize) != size) {
+		printk("%s_tables: %s target: invalid size %Zu != %u\n",
+		       xt_prefix[family], target->name,
+		       XT_ALIGN(target->targetsize), size);
+		return -EINVAL;
+	}
+	if (target->table && strcmp(target->table, table)) {
+		printk("%s_tables: %s target: only valid in %s table, not %s\n",
+		       xt_prefix[family], target->name, target->table, table);
+		return -EINVAL;
+	}
+	if (target->hooks && (hook_mask & ~target->hooks) != 0) {
+		printk("%s_tables: %s target: bad hook_mask %u\n",
+		       xt_prefix[family], target->name, hook_mask);
+		return -EINVAL;
+	}
+	if (target->proto && (target->proto != proto || inv_proto)) {
+		printk("%s_tables: %s target: only valid for protocol %u\n",
+		       xt_prefix[family], target->name, target->proto);
+		return -EINVAL;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(xt_check_target);
+
 struct xt_table_info *xt_alloc_table_info(unsigned int size)
 {
 	struct xt_table_info *newinfo;
@@ -290,20 +350,20 @@
 {
 	struct xt_table *t;
 
-	if (down_interruptible(&xt[af].mutex) != 0)
+	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
 		return ERR_PTR(-EINTR);
 
 	list_for_each_entry(t, &xt[af].tables, list)
 		if (strcmp(t->name, name) == 0 && try_module_get(t->me))
 			return t;
-	up(&xt[af].mutex);
+	mutex_unlock(&xt[af].mutex);
 	return NULL;
 }
 EXPORT_SYMBOL_GPL(xt_find_table_lock);
 
 void xt_table_unlock(struct xt_table *table)
 {
-	up(&xt[table->af].mutex);
+	mutex_unlock(&xt[table->af].mutex);
 }
 EXPORT_SYMBOL_GPL(xt_table_unlock);
 
@@ -343,7 +403,7 @@
 	int ret;
 	struct xt_table_info *private;
 
-	ret = down_interruptible(&xt[table->af].mutex);
+	ret = mutex_lock_interruptible(&xt[table->af].mutex);
 	if (ret != 0)
 		return ret;
 
@@ -369,7 +429,7 @@
 
 	ret = 0;
  unlock:
-	up(&xt[table->af].mutex);
+	mutex_unlock(&xt[table->af].mutex);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(xt_register_table);
@@ -378,10 +438,10 @@
 {
 	struct xt_table_info *private;
 
-	down(&xt[table->af].mutex);
+	mutex_lock(&xt[table->af].mutex);
 	private = table->private;
 	LIST_DELETE(&xt[table->af].tables, table);
-	up(&xt[table->af].mutex);
+	mutex_unlock(&xt[table->af].mutex);
 
 	return private;
 }
@@ -445,7 +505,7 @@
 	if (!list)
 		return NULL;
 
-	if (down_interruptible(&xt[af].mutex) != 0)
+	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
 		return NULL;
 	
 	return xt_get_idx(list, seq, *pos);
@@ -474,7 +534,7 @@
 	struct proc_dir_entry *pde = seq->private;
 	u_int16_t af = (unsigned long)pde->data & 0xffff;
 
-	up(&xt[af].mutex);
+	mutex_unlock(&xt[af].mutex);
 }
 
 static int xt_name_seq_show(struct seq_file *seq, void *v)
@@ -606,7 +666,7 @@
 		return -ENOMEM;
 
 	for (i = 0; i < NPROTO; i++) {
-		init_MUTEX(&xt[i].mutex);
+		mutex_init(&xt[i].mutex);
 		INIT_LIST_HEAD(&xt[i].target);
 		INIT_LIST_HEAD(&xt[i].match);
 		INIT_LIST_HEAD(&xt[i].tables);
diff -urN oldtree/net/netfilter/xt_CLASSIFY.c newtree/net/netfilter/xt_CLASSIFY.c
--- oldtree/net/netfilter/xt_CLASSIFY.c	2006-02-19 11:41:06.499355048 +0000
+++ newtree/net/netfilter/xt_CLASSIFY.c	2006-02-21 15:58:16.454645072 +0000
@@ -28,6 +28,7 @@
        const struct net_device *in,
        const struct net_device *out,
        unsigned int hooknum,
+       const struct xt_target *target,
        const void *targinfo,
        void *userinfo)
 {
@@ -39,47 +40,22 @@
 	return XT_CONTINUE;
 }
 
-static int
-checkentry(const char *tablename,
-           const void *e,
-           void *targinfo,
-           unsigned int targinfosize,
-           unsigned int hook_mask)
-{
-	if (targinfosize != XT_ALIGN(sizeof(struct xt_classify_target_info))){
-		printk(KERN_ERR "CLASSIFY: invalid size (%u != %Zu).\n",
-		       targinfosize,
-		       XT_ALIGN(sizeof(struct xt_classify_target_info)));
-		return 0;
-	}
-	
-	if (hook_mask & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) |
-	                  (1 << NF_IP_POST_ROUTING))) {
-		printk(KERN_ERR "CLASSIFY: only valid in LOCAL_OUT, FORWARD "
-		                "and POST_ROUTING.\n");
-		return 0;
-	}
-
-	if (strcmp(tablename, "mangle") != 0) {
-		printk(KERN_ERR "CLASSIFY: can only be called from "
-		                "\"mangle\" table, not \"%s\".\n",
-		                tablename);
-		return 0;
-	}
-
-	return 1;
-}
-
 static struct xt_target classify_reg = { 
 	.name 		= "CLASSIFY", 
 	.target 	= target,
-	.checkentry	= checkentry,
+	.targetsize	= sizeof(struct xt_classify_target_info),
+	.table		= "mangle",
+	.hooks		= (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) |
+		          (1 << NF_IP_POST_ROUTING),
 	.me 		= THIS_MODULE,
 };
 static struct xt_target classify6_reg = { 
 	.name 		= "CLASSIFY", 
 	.target 	= target,
-	.checkentry	= checkentry,
+	.targetsize	= sizeof(struct xt_classify_target_info),
+	.table		= "mangle",
+	.hooks		= (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) |
+		          (1 << NF_IP_POST_ROUTING),
 	.me 		= THIS_MODULE,
 };
 
diff -urN oldtree/net/netfilter/xt_CONNMARK.c newtree/net/netfilter/xt_CONNMARK.c
--- oldtree/net/netfilter/xt_CONNMARK.c	2006-02-19 11:41:06.499355048 +0000
+++ newtree/net/netfilter/xt_CONNMARK.c	2006-02-21 15:58:16.454645072 +0000
@@ -37,6 +37,7 @@
        const struct net_device *in,
        const struct net_device *out,
        unsigned int hooknum,
+       const struct xt_target *target,
        const void *targinfo,
        void *userinfo)
 {
@@ -74,17 +75,12 @@
 static int
 checkentry(const char *tablename,
 	   const void *entry,
+	   const struct xt_target *target,
 	   void *targinfo,
 	   unsigned int targinfosize,
 	   unsigned int hook_mask)
 {
 	struct xt_connmark_target_info *matchinfo = targinfo;
-	if (targinfosize != XT_ALIGN(sizeof(struct xt_connmark_target_info))) {
-		printk(KERN_WARNING "CONNMARK: targinfosize %u != %Zu\n",
-		       targinfosize,
-		       XT_ALIGN(sizeof(struct xt_connmark_target_info)));
-		return 0;
-	}
 
 	if (matchinfo->mode == XT_CONNMARK_RESTORE) {
 	    if (strcmp(tablename, "mangle") != 0) {
@@ -102,16 +98,19 @@
 }
 
 static struct xt_target connmark_reg = {
-	.name = "CONNMARK",
-	.target = &target,
-	.checkentry = &checkentry,
-	.me = THIS_MODULE
+	.name		= "CONNMARK",
+	.target		= target,
+	.targetsize	= sizeof(struct xt_connmark_target_info),
+	.checkentry	= checkentry,
+	.me		= THIS_MODULE
 };
+
 static struct xt_target connmark6_reg = {
-	.name = "CONNMARK",
-	.target = &target,
-	.checkentry = &checkentry,
-	.me = THIS_MODULE
+	.name		= "CONNMARK",
+	.target		= target,
+	.targetsize	= sizeof(struct xt_connmark_target_info),
+	.checkentry	= checkentry,
+	.me		= THIS_MODULE
 };
 
 static int __init init(void)
diff -urN oldtree/net/netfilter/xt_MARK.c newtree/net/netfilter/xt_MARK.c
--- oldtree/net/netfilter/xt_MARK.c	2006-02-19 11:41:06.500354896 +0000
+++ newtree/net/netfilter/xt_MARK.c	2006-02-21 15:58:16.454645072 +0000
@@ -26,6 +26,7 @@
 	  const struct net_device *in,
 	  const struct net_device *out,
 	  unsigned int hooknum,
+	  const struct xt_target *target,
 	  const void *targinfo,
 	  void *userinfo)
 {
@@ -42,6 +43,7 @@
 	  const struct net_device *in,
 	  const struct net_device *out,
 	  unsigned int hooknum,
+	  const struct xt_target *target,
 	  const void *targinfo,
 	  void *userinfo)
 {
@@ -72,53 +74,30 @@
 static int
 checkentry_v0(const char *tablename,
 	      const void *entry,
+	      const struct xt_target *target,
 	      void *targinfo,
 	      unsigned int targinfosize,
 	      unsigned int hook_mask)
 {
 	struct xt_mark_target_info *markinfo = targinfo;
 
-	if (targinfosize != XT_ALIGN(sizeof(struct xt_mark_target_info))) {
-		printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n",
-		       targinfosize,
-		       XT_ALIGN(sizeof(struct xt_mark_target_info)));
-		return 0;
-	}
-
-	if (strcmp(tablename, "mangle") != 0) {
-		printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
-		return 0;
-	}
-
 	if (markinfo->mark > 0xffffffff) {
 		printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
 		return 0;
 	}
-
 	return 1;
 }
 
 static int
 checkentry_v1(const char *tablename,
 	      const void *entry,
+	      const struct xt_target *target,
 	      void *targinfo,
 	      unsigned int targinfosize,
 	      unsigned int hook_mask)
 {
 	struct xt_mark_target_info_v1 *markinfo = targinfo;
 
-	if (targinfosize != XT_ALIGN(sizeof(struct xt_mark_target_info_v1))){
-		printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n",
-		       targinfosize,
-		       XT_ALIGN(sizeof(struct xt_mark_target_info_v1)));
-		return 0;
-	}
-
-	if (strcmp(tablename, "mangle") != 0) {
-		printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
-		return 0;
-	}
-
 	if (markinfo->mode != XT_MARK_SET
 	    && markinfo->mode != XT_MARK_AND
 	    && markinfo->mode != XT_MARK_OR) {
@@ -126,18 +105,18 @@
 		       markinfo->mode);
 		return 0;
 	}
-
 	if (markinfo->mark > 0xffffffff) {
 		printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
 		return 0;
 	}
-
 	return 1;
 }
 
 static struct xt_target ipt_mark_reg_v0 = {
 	.name		= "MARK",
 	.target		= target_v0,
+	.targetsize	= sizeof(struct xt_mark_target_info),
+	.table		= "mangle",
 	.checkentry	= checkentry_v0,
 	.me		= THIS_MODULE,
 	.revision	= 0,
@@ -146,6 +125,8 @@
 static struct xt_target ipt_mark_reg_v1 = {
 	.name		= "MARK",
 	.target		= target_v1,
+	.targetsize	= sizeof(struct xt_mark_target_info_v1),
+	.table		= "mangle",
 	.checkentry	= checkentry_v1,
 	.me		= THIS_MODULE,
 	.revision	= 1,
@@ -154,6 +135,8 @@
 static struct xt_target ip6t_mark_reg_v0 = {
 	.name		= "MARK",
 	.target		= target_v0,
+	.targetsize	= sizeof(struct xt_mark_target_info),
+	.table		= "mangle",
 	.checkentry	= checkentry_v0,
 	.me		= THIS_MODULE,
 	.revision	= 0,
diff -urN oldtree/net/netfilter/xt_NFQUEUE.c newtree/net/netfilter/xt_NFQUEUE.c
--- oldtree/net/netfilter/xt_NFQUEUE.c	2006-02-19 11:41:06.500354896 +0000
+++ newtree/net/netfilter/xt_NFQUEUE.c	2006-02-21 15:58:16.455644920 +0000
@@ -28,6 +28,7 @@
        const struct net_device *in,
        const struct net_device *out,
        unsigned int hooknum,
+       const struct xt_target *target,
        const void *targinfo,
        void *userinfo)
 {
@@ -36,41 +37,24 @@
 	return NF_QUEUE_NR(tinfo->queuenum);
 }
 
-static int
-checkentry(const char *tablename,
-	   const void *entry,
-           void *targinfo,
-           unsigned int targinfosize,
-           unsigned int hook_mask)
-{
-	if (targinfosize != XT_ALIGN(sizeof(struct xt_NFQ_info))) {
-		printk(KERN_WARNING "NFQUEUE: targinfosize %u != %Zu\n",
-		       targinfosize,
-		       XT_ALIGN(sizeof(struct xt_NFQ_info)));
-		return 0;
-	}
-
-	return 1;
-}
-
 static struct xt_target ipt_NFQ_reg = {
 	.name		= "NFQUEUE",
 	.target		= target,
-	.checkentry	= checkentry,
+	.targetsize	= sizeof(struct xt_NFQ_info),
 	.me		= THIS_MODULE,
 };
 
 static struct xt_target ip6t_NFQ_reg = {
 	.name		= "NFQUEUE",
 	.target		= target,
-	.checkentry	= checkentry,
+	.targetsize	= sizeof(struct xt_NFQ_info),
 	.me		= THIS_MODULE,
 };
 
 static struct xt_target arpt_NFQ_reg = {
 	.name		= "NFQUEUE",
 	.target		= target,
-	.checkentry	= checkentry,
+	.targetsize	= sizeof(struct xt_NFQ_info),
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/netfilter/xt_NOTRACK.c newtree/net/netfilter/xt_NOTRACK.c
--- oldtree/net/netfilter/xt_NOTRACK.c	2006-02-19 11:41:06.500354896 +0000
+++ newtree/net/netfilter/xt_NOTRACK.c	2006-02-21 15:58:16.455644920 +0000
@@ -15,6 +15,7 @@
        const struct net_device *in,
        const struct net_device *out,
        unsigned int hooknum,
+       const struct xt_target *target,
        const void *targinfo,
        void *userinfo)
 {
@@ -33,38 +34,20 @@
 	return XT_CONTINUE;
 }
 
-static int
-checkentry(const char *tablename,
-	   const void *entry,
-           void *targinfo,
-           unsigned int targinfosize,
-           unsigned int hook_mask)
-{
-	if (targinfosize != 0) {
-		printk(KERN_WARNING "NOTRACK: targinfosize %u != 0\n",
-		       targinfosize);
-		return 0;
-	}
-
-	if (strcmp(tablename, "raw") != 0) {
-		printk(KERN_WARNING "NOTRACK: can only be called from \"raw\" table, not \"%s\"\n", tablename);
-		return 0;
-	}
-
-	return 1;
-}
-
-static struct xt_target notrack_reg = { 
-	.name = "NOTRACK", 
-	.target = target, 
-	.checkentry = checkentry,
-	.me = THIS_MODULE,
+static struct xt_target notrack_reg = {
+	.name		= "NOTRACK",
+	.target		= target,
+	.targetsize	= 0,
+	.table		= "raw",
+	.me		= THIS_MODULE,
 };
-static struct xt_target notrack6_reg = { 
-	.name = "NOTRACK", 
-	.target = target, 
-	.checkentry = checkentry,
-	.me = THIS_MODULE,
+
+static struct xt_target notrack6_reg = {
+	.name		= "NOTRACK",
+	.target		= target,
+	.targetsize	= 0,
+	.table		= "raw",
+	.me		= THIS_MODULE,
 };
 
 static int __init init(void)
diff -urN oldtree/net/netfilter/xt_comment.c newtree/net/netfilter/xt_comment.c
--- oldtree/net/netfilter/xt_comment.c	2006-02-19 11:41:06.501354744 +0000
+++ newtree/net/netfilter/xt_comment.c	2006-02-21 15:58:16.455644920 +0000
@@ -19,6 +19,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protooff,
@@ -28,30 +29,17 @@
 	return 1;
 }
 
-static int
-checkentry(const char *tablename,
-           const void *ip,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-	/* Check the size */
-	if (matchsize != XT_ALIGN(sizeof(struct xt_comment_info)))
-		return 0;
-	return 1;
-}
-
 static struct xt_match comment_match = {
 	.name		= "comment",
 	.match		= match,
-	.checkentry	= checkentry,
+	.matchsize	= sizeof(struct xt_comment_info),
 	.me		= THIS_MODULE
 };
 
 static struct xt_match comment6_match = {
 	.name		= "comment",
 	.match		= match,
-	.checkentry	= checkentry,
+	.matchsize	= sizeof(struct xt_comment_info),
 	.me		= THIS_MODULE
 };
 
diff -urN oldtree/net/netfilter/xt_connbytes.c newtree/net/netfilter/xt_connbytes.c
--- oldtree/net/netfilter/xt_connbytes.c	2006-02-19 11:41:06.501354744 +0000
+++ newtree/net/netfilter/xt_connbytes.c	2006-02-21 15:58:16.456644768 +0000
@@ -44,6 +44,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -122,15 +123,13 @@
 
 static int check(const char *tablename,
 		 const void *ip,
+		 const struct xt_match *match,
 		 void *matchinfo,
 		 unsigned int matchsize,
 		 unsigned int hook_mask)
 {
 	const struct xt_connbytes_info *sinfo = matchinfo;
 
-	if (matchsize != XT_ALIGN(sizeof(struct xt_connbytes_info)))
-		return 0;
-
 	if (sinfo->what != XT_CONNBYTES_PKTS &&
 	    sinfo->what != XT_CONNBYTES_BYTES &&
 	    sinfo->what != XT_CONNBYTES_AVGPKT)
@@ -146,14 +145,16 @@
 
 static struct xt_match connbytes_match = {
 	.name		= "connbytes",
-	.match		= &match,
-	.checkentry	= &check,
+	.match		= match,
+	.checkentry	= check,
+	.matchsize	= sizeof(struct xt_connbytes_info),
 	.me		= THIS_MODULE
 };
 static struct xt_match connbytes6_match = {
 	.name		= "connbytes",
-	.match		= &match,
-	.checkentry	= &check,
+	.match		= match,
+	.checkentry	= check,
+	.matchsize	= sizeof(struct xt_connbytes_info),
 	.me		= THIS_MODULE
 };
 
diff -urN oldtree/net/netfilter/xt_connmark.c newtree/net/netfilter/xt_connmark.c
--- oldtree/net/netfilter/xt_connmark.c	2006-02-19 11:41:06.501354744 +0000
+++ newtree/net/netfilter/xt_connmark.c	2006-02-21 15:58:16.456644768 +0000
@@ -35,6 +35,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -52,37 +53,36 @@
 static int
 checkentry(const char *tablename,
 	   const void *ip,
+	   const struct xt_match *match,
 	   void *matchinfo,
 	   unsigned int matchsize,
 	   unsigned int hook_mask)
 {
-	struct xt_connmark_info *cm = 
-				(struct xt_connmark_info *)matchinfo;
-	if (matchsize != XT_ALIGN(sizeof(struct xt_connmark_info)))
-		return 0;
+	struct xt_connmark_info *cm = (struct xt_connmark_info *)matchinfo;
 
 	if (cm->mark > 0xffffffff || cm->mask > 0xffffffff) {
 		printk(KERN_WARNING "connmark: only support 32bit mark\n");
 		return 0;
 	}
-
 	return 1;
 }
 
 static struct xt_match connmark_match = {
-	.name = "connmark",
-	.match = &match,
-	.checkentry = &checkentry,
-	.me = THIS_MODULE
+	.name		= "connmark",
+	.match		= match,
+	.matchsize	= sizeof(struct xt_connmark_info),
+	.checkentry	= checkentry,
+	.me		= THIS_MODULE
 };
+
 static struct xt_match connmark6_match = {
-	.name = "connmark",
-	.match = &match,
-	.checkentry = &checkentry,
-	.me = THIS_MODULE
+	.name		= "connmark",
+	.match		= match,
+	.matchsize	= sizeof(struct xt_connmark_info),
+	.checkentry	= checkentry,
+	.me		= THIS_MODULE
 };
 
-
 static int __init init(void)
 {
 	int ret;
diff -urN oldtree/net/netfilter/xt_conntrack.c newtree/net/netfilter/xt_conntrack.c
--- oldtree/net/netfilter/xt_conntrack.c	2006-02-19 11:41:06.502354592 +0000
+++ newtree/net/netfilter/xt_conntrack.c	2006-02-21 15:58:16.457644616 +0000
@@ -32,6 +32,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -118,6 +119,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -201,22 +203,10 @@
 
 #endif /* CONFIG_NF_IP_CONNTRACK */
 
-static int check(const char *tablename,
-		 const void *ip,
-		 void *matchinfo,
-		 unsigned int matchsize,
-		 unsigned int hook_mask)
-{
-	if (matchsize != XT_ALIGN(sizeof(struct xt_conntrack_info)))
-		return 0;
-
-	return 1;
-}
-
 static struct xt_match conntrack_match = {
 	.name		= "conntrack",
-	.match		= &match,
-	.checkentry	= &check,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_conntrack_info),
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/netfilter/xt_dccp.c newtree/net/netfilter/xt_dccp.c
--- oldtree/net/netfilter/xt_dccp.c	2006-02-19 11:41:06.502354592 +0000
+++ newtree/net/netfilter/xt_dccp.c	2006-02-21 15:58:16.457644616 +0000
@@ -95,6 +95,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -129,56 +130,34 @@
 static int
 checkentry(const char *tablename,
 	   const void *inf,
+	   const struct xt_match *match,
 	   void *matchinfo,
 	   unsigned int matchsize,
 	   unsigned int hook_mask)
 {
-	const struct ipt_ip *ip = inf;
-	const struct xt_dccp_info *info;
+	const struct xt_dccp_info *info = matchinfo;
 
-	info = (const struct xt_dccp_info *)matchinfo;
-
-	return ip->proto == IPPROTO_DCCP
-		&& !(ip->invflags & XT_INV_PROTO)
-		&& matchsize == XT_ALIGN(sizeof(struct xt_dccp_info))
-		&& !(info->flags & ~XT_DCCP_VALID_FLAGS)
-		&& !(info->invflags & ~XT_DCCP_VALID_FLAGS)
-		&& !(info->invflags & ~info->flags);
-}
-
-static int
-checkentry6(const char *tablename,
-	   const void *inf,
-	   void *matchinfo,
-	   unsigned int matchsize,
-	   unsigned int hook_mask)
-{
-	const struct ip6t_ip6 *ip = inf;
-	const struct xt_dccp_info *info;
-
-	info = (const struct xt_dccp_info *)matchinfo;
-
-	return ip->proto == IPPROTO_DCCP
-		&& !(ip->invflags & XT_INV_PROTO)
-		&& matchsize == XT_ALIGN(sizeof(struct xt_dccp_info))
-		&& !(info->flags & ~XT_DCCP_VALID_FLAGS)
+	return !(info->flags & ~XT_DCCP_VALID_FLAGS)
 		&& !(info->invflags & ~XT_DCCP_VALID_FLAGS)
 		&& !(info->invflags & ~info->flags);
 }
 
-
 static struct xt_match dccp_match = 
 { 
 	.name 		= "dccp",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_dccp_info),
+	.proto		= IPPROTO_DCCP,
+	.checkentry	= checkentry,
 	.me 		= THIS_MODULE,
 };
 static struct xt_match dccp6_match = 
 { 
 	.name 		= "dccp",
-	.match		= &match,
-	.checkentry	= &checkentry6,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_dccp_info),
+	.proto		= IPPROTO_DCCP,
+	.checkentry	= checkentry,
 	.me 		= THIS_MODULE,
 };
 
diff -urN oldtree/net/netfilter/xt_helper.c newtree/net/netfilter/xt_helper.c
--- oldtree/net/netfilter/xt_helper.c	2006-02-19 11:41:06.503354440 +0000
+++ newtree/net/netfilter/xt_helper.c	2006-02-21 15:58:16.458644464 +0000
@@ -42,6 +42,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -89,6 +90,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -96,6 +98,7 @@
 {
 	const struct xt_helper_info *info = matchinfo;
 	struct nf_conn *ct;
+	struct nf_conn_help *master_help;
 	enum ip_conntrack_info ctinfo;
 	int ret = info->invert;
 	
@@ -111,7 +114,8 @@
 	}
 
 	read_lock_bh(&nf_conntrack_lock);
-	if (!ct->master->helper) {
+	master_help = nfct_help(ct->master);
+	if (!master_help || !master_help->helper) {
 		DEBUGP("xt_helper: master ct %p has no helper\n", 
 			exp->expectant);
 		goto out_unlock;
@@ -123,8 +127,8 @@
 	if (info->name[0] == '\0')
 		ret ^= 1;
 	else
-		ret ^= !strncmp(ct->master->helper->name, info->name, 
-		                strlen(ct->master->helper->name));
+		ret ^= !strncmp(master_help->helper->name, info->name, 
+		                strlen(master_help->helper->name));
 out_unlock:
 	read_unlock_bh(&nf_conntrack_lock);
 	return ret;
@@ -133,6 +137,7 @@
 
 static int check(const char *tablename,
 		 const void *inf,
+		 const struct xt_match *match,
 		 void *matchinfo,
 		 unsigned int matchsize,
 		 unsigned int hook_mask)
@@ -140,24 +145,21 @@
 	struct xt_helper_info *info = matchinfo;
 
 	info->name[29] = '\0';
-
-	/* verify size */
-	if (matchsize != XT_ALIGN(sizeof(struct xt_helper_info)))
-		return 0;
-
 	return 1;
 }
 
 static struct xt_match helper_match = {
 	.name		= "helper",
-	.match		= &match,
-	.checkentry	= &check,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_helper_info),
+	.checkentry	= check,
 	.me		= THIS_MODULE,
 };
 static struct xt_match helper6_match = {
 	.name		= "helper",
-	.match		= &match,
-	.checkentry	= &check,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_helper_info),
+	.checkentry	= check,
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/netfilter/xt_length.c newtree/net/netfilter/xt_length.c
--- oldtree/net/netfilter/xt_length.c	2006-02-19 11:41:06.503354440 +0000
+++ newtree/net/netfilter/xt_length.c	2006-02-21 15:58:16.458644464 +0000
@@ -24,6 +24,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -39,6 +40,7 @@
 match6(const struct sk_buff *skb,
        const struct net_device *in,
        const struct net_device *out,
+       const struct xt_match *match,
        const void *matchinfo,
        int offset,
        unsigned int protoff,
@@ -50,29 +52,17 @@
 	return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
 }
 
-static int
-checkentry(const char *tablename,
-           const void *ip,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-	if (matchsize != XT_ALIGN(sizeof(struct xt_length_info)))
-		return 0;
-
-	return 1;
-}
-
 static struct xt_match length_match = {
 	.name		= "length",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_length_info),
 	.me		= THIS_MODULE,
 };
+
 static struct xt_match length6_match = {
 	.name		= "length",
-	.match		= &match6,
-	.checkentry	= &checkentry,
+	.match		= match6,
+	.matchsize	= sizeof(struct xt_length_info),
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/netfilter/xt_limit.c newtree/net/netfilter/xt_limit.c
--- oldtree/net/netfilter/xt_limit.c	2006-02-19 11:41:06.504354288 +0000
+++ newtree/net/netfilter/xt_limit.c	2006-02-21 15:58:16.458644464 +0000
@@ -68,6 +68,7 @@
 ipt_limit_match(const struct sk_buff *skb,
 		const struct net_device *in,
 		const struct net_device *out,
+		const struct xt_match *match,
 		const void *matchinfo,
 		int offset,
 		unsigned int protoff,
@@ -107,15 +108,13 @@
 static int
 ipt_limit_checkentry(const char *tablename,
 		     const void *inf,
+		     const struct xt_match *match,
 		     void *matchinfo,
 		     unsigned int matchsize,
 		     unsigned int hook_mask)
 {
 	struct xt_rateinfo *r = matchinfo;
 
-	if (matchsize != XT_ALIGN(sizeof(struct xt_rateinfo)))
-		return 0;
-
 	/* Check for overflow. */
 	if (r->burst == 0
 	    || user2credits(r->avg * r->burst) < user2credits(r->avg)) {
@@ -140,12 +139,14 @@
 static struct xt_match ipt_limit_reg = {
 	.name		= "limit",
 	.match		= ipt_limit_match,
+	.matchsize	= sizeof(struct xt_rateinfo),
 	.checkentry	= ipt_limit_checkentry,
 	.me		= THIS_MODULE,
 };
 static struct xt_match limit6_reg = {
 	.name		= "limit",
 	.match		= ipt_limit_match,
+	.matchsize	= sizeof(struct xt_rateinfo),
 	.checkentry	= ipt_limit_checkentry,
 	.me		= THIS_MODULE,
 };
diff -urN oldtree/net/netfilter/xt_mac.c newtree/net/netfilter/xt_mac.c
--- oldtree/net/netfilter/xt_mac.c	2006-02-19 11:41:06.504354288 +0000
+++ newtree/net/netfilter/xt_mac.c	2006-02-21 15:58:16.467643096 +0000
@@ -27,6 +27,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -42,37 +43,20 @@
 		^ info->invert));
 }
 
-static int
-ipt_mac_checkentry(const char *tablename,
-		   const void *inf,
-		   void *matchinfo,
-		   unsigned int matchsize,
-		   unsigned int hook_mask)
-{
-	/* FORWARD isn't always valid, but it's nice to be able to do --RR */
-	if (hook_mask
-	    & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN)
-		| (1 << NF_IP_FORWARD))) {
-		printk("xt_mac: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
-		return 0;
-	}
-
-	if (matchsize != XT_ALIGN(sizeof(struct xt_mac_info)))
-		return 0;
-
-	return 1;
-}
-
 static struct xt_match mac_match = {
 	.name		= "mac",
-	.match		= &match,
-	.checkentry	= &ipt_mac_checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_mac_info),
+	.hooks		= (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) |
+			  (1 << NF_IP_FORWARD),
 	.me		= THIS_MODULE,
 };
 static struct xt_match mac6_match = {
 	.name		= "mac",
-	.match		= &match,
-	.checkentry	= &ipt_mac_checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_mac_info),
+	.hooks		= (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) |
+			  (1 << NF_IP_FORWARD),
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/netfilter/xt_mark.c newtree/net/netfilter/xt_mark.c
--- oldtree/net/netfilter/xt_mark.c	2006-02-19 11:41:06.504354288 +0000
+++ newtree/net/netfilter/xt_mark.c	2006-02-21 15:58:16.467643096 +0000
@@ -23,6 +23,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -36,34 +37,33 @@
 static int
 checkentry(const char *tablename,
            const void *entry,
+	   const struct xt_match *match,
            void *matchinfo,
            unsigned int matchsize,
            unsigned int hook_mask)
 {
 	struct xt_mark_info *minfo = (struct xt_mark_info *) matchinfo;
 
-	if (matchsize != XT_ALIGN(sizeof(struct xt_mark_info)))
-		return 0;
-
 	if (minfo->mark > 0xffffffff || minfo->mask > 0xffffffff) {
 		printk(KERN_WARNING "mark: only supports 32bit mark\n");
 		return 0;
 	}
-
 	return 1;
 }
 
 static struct xt_match mark_match = {
 	.name		= "mark",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_mark_info),
+	.checkentry	= checkentry,
 	.me		= THIS_MODULE,
 };
 
 static struct xt_match mark6_match = {
 	.name		= "mark",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_mark_info),
+	.checkentry	= checkentry,
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/netfilter/xt_physdev.c newtree/net/netfilter/xt_physdev.c
--- oldtree/net/netfilter/xt_physdev.c	2006-02-19 11:41:06.505354136 +0000
+++ newtree/net/netfilter/xt_physdev.c	2006-02-21 15:58:16.467643096 +0000
@@ -26,6 +26,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -102,14 +103,13 @@
 static int
 checkentry(const char *tablename,
 		       const void *ip,
+		       const struct xt_match *match,
 		       void *matchinfo,
 		       unsigned int matchsize,
 		       unsigned int hook_mask)
 {
 	const struct xt_physdev_info *info = matchinfo;
 
-	if (matchsize != XT_ALIGN(sizeof(struct xt_physdev_info)))
-		return 0;
 	if (!(info->bitmask & XT_PHYSDEV_OP_MASK) ||
 	    info->bitmask & ~XT_PHYSDEV_OP_MASK)
 		return 0;
@@ -118,15 +118,17 @@
 
 static struct xt_match physdev_match = {
 	.name		= "physdev",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_physdev_info),
+	.checkentry	= checkentry,
 	.me		= THIS_MODULE,
 };
 
 static struct xt_match physdev6_match = {
 	.name		= "physdev",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_physdev_info),
+	.checkentry	= checkentry,
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/netfilter/xt_pkttype.c newtree/net/netfilter/xt_pkttype.c
--- oldtree/net/netfilter/xt_pkttype.c	2006-02-19 11:41:06.505354136 +0000
+++ newtree/net/netfilter/xt_pkttype.c	2006-02-21 15:58:16.468642944 +0000
@@ -22,6 +22,7 @@
 static int match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -32,32 +33,20 @@
 	return (skb->pkt_type == info->pkttype) ^ info->invert;
 }
 
-static int checkentry(const char *tablename,
-		   const void *ip,
-		   void *matchinfo,
-		   unsigned int matchsize,
-		   unsigned int hook_mask)
-{
-	if (matchsize != XT_ALIGN(sizeof(struct xt_pkttype_info)))
-		return 0;
-
-	return 1;
-}
-
 static struct xt_match pkttype_match = {
 	.name		= "pkttype",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_pkttype_info),
 	.me		= THIS_MODULE,
 };
+
 static struct xt_match pkttype6_match = {
 	.name		= "pkttype",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_pkttype_info),
 	.me		= THIS_MODULE,
 };
 
-
 static int __init init(void)
 {
 	int ret;
diff -urN oldtree/net/netfilter/xt_policy.c newtree/net/netfilter/xt_policy.c
--- oldtree/net/netfilter/xt_policy.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/net/netfilter/xt_policy.c	2006-02-21 15:58:16.468642944 +0000
@@ -0,0 +1,209 @@
+/* IP tables module for matching IPsec policy
+ *
+ * Copyright (c) 2004,2005 Patrick McHardy, <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <net/xfrm.h>
+
+#include <linux/netfilter/xt_policy.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_DESCRIPTION("Xtables IPsec policy matching module");
+MODULE_LICENSE("GPL");
+
+static inline int
+xt_addr_cmp(const union xt_policy_addr *a1, const union xt_policy_addr *m,
+	    const union xt_policy_addr *a2, unsigned short family)
+{
+	switch (family) {
+	case AF_INET:
+		return (a1->a4.s_addr ^ a2->a4.s_addr) & m->a4.s_addr;
+	case AF_INET6:
+		return ipv6_masked_addr_cmp(&a1->a6, &m->a6, &a2->a6);
+	}
+	return 0;
+}
+
+static inline int
+match_xfrm_state(struct xfrm_state *x, const struct xt_policy_elem *e,
+		 unsigned short family)
+{
+#define MATCH_ADDR(x,y,z)	(!e->match.x ||			       \
+				 (xt_addr_cmp(&e->x, &e->y, z, family) \
+				  ^ e->invert.x))
+#define MATCH(x,y)		(!e->match.x || ((e->x == (y)) ^ e->invert.x))
+
+	return MATCH_ADDR(saddr, smask, (union xt_policy_addr *)&x->props.saddr) &&
+	       MATCH_ADDR(daddr, dmask, (union xt_policy_addr *)&x->id.daddr.a4) &&
+	       MATCH(proto, x->id.proto) &&
+	       MATCH(mode, x->props.mode) &&
+	       MATCH(spi, x->id.spi) &&
+	       MATCH(reqid, x->props.reqid);
+}
+
+static int
+match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info,
+		unsigned short family)
+{
+	const struct xt_policy_elem *e;
+	struct sec_path *sp = skb->sp;
+	int strict = info->flags & XT_POLICY_MATCH_STRICT;
+	int i, pos;
+
+	if (sp == NULL)
+		return -1;
+	if (strict && info->len != sp->len)
+		return 0;
+
+	for (i = sp->len - 1; i >= 0; i--) {
+		pos = strict ? i - sp->len + 1 : 0;
+		if (pos >= info->len)
+			return 0;
+		e = &info->pol[pos];
+
+		if (match_xfrm_state(sp->x[i].xvec, e, family)) {
+			if (!strict)
+				return 1;
+		} else if (strict)
+			return 0;
+	}
+
+	return strict ? 1 : 0;
+}
+
+static int
+match_policy_out(const struct sk_buff *skb, const struct xt_policy_info *info,
+		 unsigned short family)
+{
+	const struct xt_policy_elem *e;
+	struct dst_entry *dst = skb->dst;
+	int strict = info->flags & XT_POLICY_MATCH_STRICT;
+	int i, pos;
+
+	if (dst->xfrm == NULL)
+		return -1;
+
+	for (i = 0; dst && dst->xfrm; dst = dst->child, i++) {
+		pos = strict ? i : 0;
+		if (pos >= info->len)
+			return 0;
+		e = &info->pol[pos];
+
+		if (match_xfrm_state(dst->xfrm, e, family)) {
+			if (!strict)
+				return 1;
+		} else if (strict)
+			return 0;
+	}
+
+	return strict ? i == info->len : 0;
+}
+
+static int match(const struct sk_buff *skb,
+                 const struct net_device *in,
+                 const struct net_device *out,
+                 const struct xt_match *match,
+                 const void *matchinfo,
+                 int offset,
+                 unsigned int protoff,
+                 int *hotdrop)
+{
+	const struct xt_policy_info *info = matchinfo;
+	int ret;
+
+	if (info->flags & XT_POLICY_MATCH_IN)
+		ret = match_policy_in(skb, info, match->family);
+	else
+		ret = match_policy_out(skb, info, match->family);
+
+	if (ret < 0)
+		ret = info->flags & XT_POLICY_MATCH_NONE ? 1 : 0;
+	else if (info->flags & XT_POLICY_MATCH_NONE)
+		ret = 0;
+
+	return ret;
+}
+
+static int checkentry(const char *tablename, const void *ip_void,
+                      const struct xt_match *match,
+                      void *matchinfo, unsigned int matchsize,
+                      unsigned int hook_mask)
+{
+	struct xt_policy_info *info = matchinfo;
+
+	if (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT))) {
+		printk(KERN_ERR "xt_policy: neither incoming nor "
+		                "outgoing policy selected\n");
+		return 0;
+	}
+	/* hook values are equal for IPv4 and IPv6 */
+	if (hook_mask & (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_LOCAL_IN)
+	    && info->flags & XT_POLICY_MATCH_OUT) {
+		printk(KERN_ERR "xt_policy: output policy not valid in "
+		                "PRE_ROUTING and INPUT\n");
+		return 0;
+	}
+	if (hook_mask & (1 << NF_IP_POST_ROUTING | 1 << NF_IP_LOCAL_OUT)
+	    && info->flags & XT_POLICY_MATCH_IN) {
+		printk(KERN_ERR "xt_policy: input policy not valid in "
+		                "POST_ROUTING and OUTPUT\n");
+		return 0;
+	}
+	if (info->len > XT_POLICY_MAX_ELEM) {
+		printk(KERN_ERR "xt_policy: too many policy elements\n");
+		return 0;
+	}
+	return 1;
+}
+
+static struct xt_match policy_match = {
+	.name		= "policy",
+	.family		= AF_INET,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_policy_info),
+	.checkentry 	= checkentry,
+	.me		= THIS_MODULE,
+};
+
+static struct xt_match policy6_match = {
+	.name		= "policy",
+	.family		= AF_INET6,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_policy_info),
+	.checkentry	= checkentry,
+	.me		= THIS_MODULE,
+};
+
+static int __init init(void)
+{
+	int ret;
+
+	ret = xt_register_match(AF_INET, &policy_match);
+	if (ret)
+		return ret;
+	ret = xt_register_match(AF_INET6, &policy6_match);
+	if (ret)
+		xt_unregister_match(AF_INET, &policy_match);
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	xt_unregister_match(AF_INET6, &policy6_match);
+	xt_unregister_match(AF_INET, &policy_match);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_ALIAS("ipt_policy");
+MODULE_ALIAS("ip6t_policy");
diff -urN oldtree/net/netfilter/xt_realm.c newtree/net/netfilter/xt_realm.c
--- oldtree/net/netfilter/xt_realm.c	2006-02-19 11:41:06.505354136 +0000
+++ newtree/net/netfilter/xt_realm.c	2006-02-21 15:58:16.468642944 +0000
@@ -27,6 +27,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -38,30 +39,12 @@
 	return (info->id == (dst->tclassid & info->mask)) ^ info->invert;
 }
 
-static int check(const char *tablename,
-                 const void *ip,
-                 void *matchinfo,
-                 unsigned int matchsize,
-                 unsigned int hook_mask)
-{
-	if (hook_mask
-	    & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) |
-	        (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_LOCAL_IN))) {
-		printk("xt_realm: only valid for POST_ROUTING, LOCAL_OUT, "
-		       "LOCAL_IN or FORWARD.\n");
-		return 0;
-	}
-	if (matchsize != XT_ALIGN(sizeof(struct xt_realm_info))) {
-		printk("xt_realm: invalid matchsize.\n");
-		return 0;
-	}
-	return 1;
-}
-
 static struct xt_match realm_match = {
 	.name		= "realm",
-	.match		= match, 
-	.checkentry	= check,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_realm_info),
+	.hooks		= (1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) |
+			  (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_LOCAL_IN),
 	.me		= THIS_MODULE
 };
 
diff -urN oldtree/net/netfilter/xt_sctp.c newtree/net/netfilter/xt_sctp.c
--- oldtree/net/netfilter/xt_sctp.c	2006-02-19 11:41:06.506353984 +0000
+++ newtree/net/netfilter/xt_sctp.c	2006-02-21 15:58:16.469642792 +0000
@@ -123,6 +123,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -162,19 +163,14 @@
 static int
 checkentry(const char *tablename,
 	   const void *inf,
+	   const struct xt_match *match,
 	   void *matchinfo,
 	   unsigned int matchsize,
 	   unsigned int hook_mask)
 {
-	const struct xt_sctp_info *info;
-	const struct ipt_ip *ip = inf;
-
-	info = (const struct xt_sctp_info *)matchinfo;
+	const struct xt_sctp_info *info = matchinfo;
 
-	return ip->proto == IPPROTO_SCTP
-		&& !(ip->invflags & XT_INV_PROTO)
-		&& matchsize == XT_ALIGN(sizeof(struct xt_sctp_info))
-		&& !(info->flags & ~XT_SCTP_VALID_FLAGS)
+	return !(info->flags & ~XT_SCTP_VALID_FLAGS)
 		&& !(info->invflags & ~XT_SCTP_VALID_FLAGS)
 		&& !(info->invflags & ~info->flags)
 		&& ((!(info->flags & XT_SCTP_CHUNK_TYPES)) || 
@@ -184,47 +180,23 @@
 				| SCTP_CHUNK_MATCH_ONLY)));
 }
 
-static int
-checkentry6(const char *tablename,
-	   const void *inf,
-	   void *matchinfo,
-	   unsigned int matchsize,
-	   unsigned int hook_mask)
-{
-	const struct xt_sctp_info *info;
-	const struct ip6t_ip6 *ip = inf;
-
-	info = (const struct xt_sctp_info *)matchinfo;
-
-	return ip->proto == IPPROTO_SCTP
-		&& !(ip->invflags & XT_INV_PROTO)
-		&& matchsize == XT_ALIGN(sizeof(struct xt_sctp_info))
-		&& !(info->flags & ~XT_SCTP_VALID_FLAGS)
-		&& !(info->invflags & ~XT_SCTP_VALID_FLAGS)
-		&& !(info->invflags & ~info->flags)
-		&& ((!(info->flags & XT_SCTP_CHUNK_TYPES)) || 
-			(info->chunk_match_type &
-				(SCTP_CHUNK_MATCH_ALL 
-				| SCTP_CHUNK_MATCH_ANY
-				| SCTP_CHUNK_MATCH_ONLY)));
-}
-
-
-static struct xt_match sctp_match = 
-{ 
-	.name = "sctp",
-	.match = &match,
-	.checkentry = &checkentry,
-	.me = THIS_MODULE
-};
-static struct xt_match sctp6_match = 
-{ 
-	.name = "sctp",
-	.match = &match,
-	.checkentry = &checkentry6,
-	.me = THIS_MODULE
+static struct xt_match sctp_match = {
+	.name		= "sctp",
+	.match		= match,
+	.matchsize	= sizeof(struct xt_sctp_info),
+	.proto		= IPPROTO_SCTP,
+	.checkentry	= checkentry,
+	.me		= THIS_MODULE
 };
 
+static struct xt_match sctp6_match = {
+	.name		= "sctp",
+	.match		= match,
+	.matchsize	= sizeof(struct xt_sctp_info),
+	.proto		= IPPROTO_SCTP,
+	.checkentry	= checkentry,
+	.me		= THIS_MODULE
+};
 
 static int __init init(void)
 {
diff -urN oldtree/net/netfilter/xt_state.c newtree/net/netfilter/xt_state.c
--- oldtree/net/netfilter/xt_state.c	2006-02-19 11:41:06.506353984 +0000
+++ newtree/net/netfilter/xt_state.c	2006-02-21 15:58:16.469642792 +0000
@@ -24,6 +24,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -43,29 +44,17 @@
 	return (sinfo->statemask & statebit);
 }
 
-static int check(const char *tablename,
-		 const void *ip,
-		 void *matchinfo,
-		 unsigned int matchsize,
-		 unsigned int hook_mask)
-{
-	if (matchsize != XT_ALIGN(sizeof(struct xt_state_info)))
-		return 0;
-
-	return 1;
-}
-
 static struct xt_match state_match = {
 	.name		= "state",
-	.match		= &match,
-	.checkentry	= &check,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_state_info),
 	.me		= THIS_MODULE,
 };
 
 static struct xt_match state6_match = {
 	.name		= "state",
-	.match		= &match,
-	.checkentry	= &check,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_state_info),
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/netfilter/xt_string.c newtree/net/netfilter/xt_string.c
--- oldtree/net/netfilter/xt_string.c	2006-02-19 11:41:06.506353984 +0000
+++ newtree/net/netfilter/xt_string.c	2006-02-21 15:58:16.470642640 +0000
@@ -24,6 +24,7 @@
 static int match(const struct sk_buff *skb,
 		 const struct net_device *in,
 		 const struct net_device *out,
+		 const struct xt_match *match,
 		 const void *matchinfo,
 		 int offset,
 		 unsigned int protoff,
@@ -43,6 +44,7 @@
 
 static int checkentry(const char *tablename,
 		      const void *ip,
+		      const struct xt_match *match,
 		      void *matchinfo,
 		      unsigned int matchsize,
 		      unsigned int hook_mask)
@@ -50,9 +52,6 @@
 	struct xt_string_info *conf = matchinfo;
 	struct ts_config *ts_conf;
 
-	if (matchsize != XT_ALIGN(sizeof(struct xt_string_info)))
-		return 0;
-
 	/* Damn, can't handle this case properly with iptables... */
 	if (conf->from_offset > conf->to_offset)
 		return 0;
@@ -67,7 +66,8 @@
 	return 1;
 }
 
-static void destroy(void *matchinfo, unsigned int matchsize)
+static void destroy(const struct xt_match *match, void *matchinfo,
+		    unsigned int matchsize)
 {
 	textsearch_destroy(STRING_TEXT_PRIV(matchinfo)->config);
 }
@@ -75,6 +75,7 @@
 static struct xt_match string_match = {
 	.name 		= "string",
 	.match 		= match,
+	.matchsize	= sizeof(struct xt_string_info),
 	.checkentry	= checkentry,
 	.destroy 	= destroy,
 	.me 		= THIS_MODULE
@@ -82,6 +83,7 @@
 static struct xt_match string6_match = {
 	.name 		= "string",
 	.match 		= match,
+	.matchsize	= sizeof(struct xt_string_info),
 	.checkentry	= checkentry,
 	.destroy 	= destroy,
 	.me 		= THIS_MODULE
diff -urN oldtree/net/netfilter/xt_tcpmss.c newtree/net/netfilter/xt_tcpmss.c
--- oldtree/net/netfilter/xt_tcpmss.c	2006-02-19 11:41:06.507353832 +0000
+++ newtree/net/netfilter/xt_tcpmss.c	2006-02-21 15:58:16.470642640 +0000
@@ -81,6 +81,7 @@
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -92,58 +93,19 @@
 			       info->invert, hotdrop);
 }
 
-static int
-checkentry(const char *tablename,
-           const void *ipinfo,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-	const struct ipt_ip *ip = ipinfo;
-	if (matchsize != XT_ALIGN(sizeof(struct xt_tcpmss_match_info)))
-		return 0;
-
-	/* Must specify -p tcp */
-	if (ip->proto != IPPROTO_TCP || (ip->invflags & IPT_INV_PROTO)) {
-		printk("tcpmss: Only works on TCP packets\n");
-		return 0;
-	}
-
-	return 1;
-}
-
-static int
-checkentry6(const char *tablename,
-	   const void *ipinfo,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-	const struct ip6t_ip6 *ip = ipinfo;
-
-	if (matchsize != XT_ALIGN(sizeof(struct xt_tcpmss_match_info)))
-		return 0;
-
-	/* Must specify -p tcp */
-	if (ip->proto != IPPROTO_TCP || (ip->invflags & XT_INV_PROTO)) {
-		printk("tcpmss: Only works on TCP packets\n");
-		return 0;
-	}
-
-	return 1;
-}
-
 static struct xt_match tcpmss_match = {
 	.name		= "tcpmss",
-	.match		= &match,
-	.checkentry	= &checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_tcpmss_match_info),
+	.proto		= IPPROTO_TCP,
 	.me		= THIS_MODULE,
 };
 
 static struct xt_match tcpmss6_match = {
 	.name		= "tcpmss",
-	.match		= &match,
-	.checkentry	= &checkentry6,
+	.match		= match,
+	.matchsize	= sizeof(struct xt_tcpmss_match_info),
+	.proto		= IPPROTO_TCP,
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/netfilter/xt_tcpudp.c newtree/net/netfilter/xt_tcpudp.c
--- oldtree/net/netfilter/xt_tcpudp.c	2006-02-19 11:41:06.507353832 +0000
+++ newtree/net/netfilter/xt_tcpudp.c	2006-02-21 15:58:16.471642488 +0000
@@ -74,6 +74,7 @@
 tcp_match(const struct sk_buff *skb,
 	  const struct net_device *in,
 	  const struct net_device *out,
+	  const struct xt_match *match,
 	  const void *matchinfo,
 	  int offset,
 	  unsigned int protoff,
@@ -138,43 +139,22 @@
 static int
 tcp_checkentry(const char *tablename,
 	       const void *info,
+	       const struct xt_match *match,
 	       void *matchinfo,
 	       unsigned int matchsize,
 	       unsigned int hook_mask)
 {
-	const struct ipt_ip *ip = info;
 	const struct xt_tcp *tcpinfo = matchinfo;
 
-	/* Must specify proto == TCP, and no unknown invflags */
-	return ip->proto == IPPROTO_TCP
-		&& !(ip->invflags & XT_INV_PROTO)
-		&& matchsize == XT_ALIGN(sizeof(struct xt_tcp))
-		&& !(tcpinfo->invflags & ~XT_TCP_INV_MASK);
+	/* Must specify no unknown invflags */
+	return !(tcpinfo->invflags & ~XT_TCP_INV_MASK);
 }
 
-/* Called when user tries to insert an entry of this type. */
-static int
-tcp6_checkentry(const char *tablename,
-	       const void *entry,
-	       void *matchinfo,
-	       unsigned int matchsize,
-	       unsigned int hook_mask)
-{
-	const struct ip6t_ip6 *ipv6 = entry;
-	const struct xt_tcp *tcpinfo = matchinfo;
-
-	/* Must specify proto == TCP, and no unknown invflags */
-	return ipv6->proto == IPPROTO_TCP
-		&& !(ipv6->invflags & XT_INV_PROTO)
-		&& matchsize == XT_ALIGN(sizeof(struct xt_tcp))
-		&& !(tcpinfo->invflags & ~XT_TCP_INV_MASK);
-}
-
-
 static int
 udp_match(const struct sk_buff *skb,
 	  const struct net_device *in,
 	  const struct net_device *out,
+	  const struct xt_match *match,
 	  const void *matchinfo,
 	  int offset,
 	  unsigned int protoff,
@@ -208,87 +188,49 @@
 static int
 udp_checkentry(const char *tablename,
 	       const void *info,
+	       const struct xt_match *match,
 	       void *matchinfo,
-	       unsigned int matchinfosize,
-	       unsigned int hook_mask)
-{
-	const struct ipt_ip *ip = info;
-	const struct xt_udp *udpinfo = matchinfo;
-
-	/* Must specify proto == UDP, and no unknown invflags */
-	if (ip->proto != IPPROTO_UDP || (ip->invflags & XT_INV_PROTO)) {
-		duprintf("ipt_udp: Protocol %u != %u\n", ip->proto,
-			 IPPROTO_UDP);
-		return 0;
-	}
-	if (matchinfosize != XT_ALIGN(sizeof(struct xt_udp))) {
-		duprintf("ipt_udp: matchsize %u != %u\n",
-			 matchinfosize, XT_ALIGN(sizeof(struct xt_udp)));
-		return 0;
-	}
-	if (udpinfo->invflags & ~XT_UDP_INV_MASK) {
-		duprintf("ipt_udp: unknown flags %X\n",
-			 udpinfo->invflags);
-		return 0;
-	}
-
-	return 1;
-}
-
-/* Called when user tries to insert an entry of this type. */
-static int
-udp6_checkentry(const char *tablename,
-	       const void *entry,
-	       void *matchinfo,
-	       unsigned int matchinfosize,
+	       unsigned int matchsize,
 	       unsigned int hook_mask)
 {
-	const struct ip6t_ip6 *ipv6 = entry;
-	const struct xt_udp *udpinfo = matchinfo;
+	const struct xt_tcp *udpinfo = matchinfo;
 
-	/* Must specify proto == UDP, and no unknown invflags */
-	if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & XT_INV_PROTO)) {
-		duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
-			 IPPROTO_UDP);
-		return 0;
-	}
-	if (matchinfosize != XT_ALIGN(sizeof(struct xt_udp))) {
-		duprintf("ip6t_udp: matchsize %u != %u\n",
-			 matchinfosize, XT_ALIGN(sizeof(struct xt_udp)));
-		return 0;
-	}
-	if (udpinfo->invflags & ~XT_UDP_INV_MASK) {
-		duprintf("ip6t_udp: unknown flags %X\n",
-			 udpinfo->invflags);
-		return 0;
-	}
-
-	return 1;
+	/* Must specify no unknown invflags */
+	return !(udpinfo->invflags & ~XT_UDP_INV_MASK);
 }
 
 static struct xt_match tcp_matchstruct = {
 	.name		= "tcp",
-	.match		= &tcp_match,
-	.checkentry	= &tcp_checkentry,
+	.match		= tcp_match,
+	.matchsize	= sizeof(struct xt_tcp),
+	.proto		= IPPROTO_TCP,
+	.checkentry	= tcp_checkentry,
 	.me		= THIS_MODULE,
 };
+
 static struct xt_match tcp6_matchstruct = {
 	.name		= "tcp",
-	.match		= &tcp_match,
-	.checkentry	= &tcp6_checkentry,
+	.match		= tcp_match,
+	.matchsize	= sizeof(struct xt_tcp),
+	.proto		= IPPROTO_TCP,
+	.checkentry	= tcp_checkentry,
 	.me		= THIS_MODULE,
 };
 
 static struct xt_match udp_matchstruct = {
 	.name		= "udp",
-	.match		= &udp_match,
-	.checkentry	= &udp_checkentry,
+	.match		= udp_match,
+	.matchsize	= sizeof(struct xt_udp),
+	.proto		= IPPROTO_UDP,
+	.checkentry	= udp_checkentry,
 	.me		= THIS_MODULE,
 };
 static struct xt_match udp6_matchstruct = {
 	.name		= "udp",
-	.match		= &udp_match,
-	.checkentry	= &udp6_checkentry,
+	.match		= udp_match,
+	.matchsize	= sizeof(struct xt_udp),
+	.proto		= IPPROTO_UDP,
+	.checkentry	= udp_checkentry,
 	.me		= THIS_MODULE,
 };
 
diff -urN oldtree/net/netlink/af_netlink.c newtree/net/netlink/af_netlink.c
--- oldtree/net/netlink/af_netlink.c	2006-02-19 11:41:06.508353680 +0000
+++ newtree/net/netlink/af_netlink.c	2006-02-21 15:58:16.472642336 +0000
@@ -106,6 +106,7 @@
 struct netlink_table {
 	struct nl_pid_hash hash;
 	struct hlist_head mc_list;
+	unsigned long *listeners;
 	unsigned int nl_nonroot;
 	unsigned int groups;
 	struct module *module;
@@ -296,6 +297,24 @@
 
 static const struct proto_ops netlink_ops;
 
+static void
+netlink_update_listeners(struct sock *sk)
+{
+	struct netlink_table *tbl = &nl_table[sk->sk_protocol];
+	struct hlist_node *node;
+	unsigned long mask;
+	unsigned int i;
+
+	for (i = 0; i < NLGRPSZ(tbl->groups)/sizeof(unsigned long); i++) {
+		mask = 0;
+		sk_for_each_bound(sk, node, &tbl->mc_list)
+			mask |= nlk_sk(sk)->groups[i];
+		tbl->listeners[i] = mask;
+	}
+	/* this function is only called with the netlink table "grabbed", which
+	 * makes sure updates are visible before bind or setsockopt return. */
+}
+
 static int netlink_insert(struct sock *sk, u32 pid)
 {
 	struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash;
@@ -456,12 +475,14 @@
 	if (nlk->module)
 		module_put(nlk->module);
 
+	netlink_table_grab();
 	if (nlk->flags & NETLINK_KERNEL_SOCKET) {
-		netlink_table_grab();
+		kfree(nl_table[sk->sk_protocol].listeners);
 		nl_table[sk->sk_protocol].module = NULL;
 		nl_table[sk->sk_protocol].registered = 0;
-		netlink_table_ungrab();
-	}
+	} else if (nlk->subscriptions)
+		netlink_update_listeners(sk);
+	netlink_table_ungrab();
 
 	kfree(nlk->groups);
 	nlk->groups = NULL;
@@ -589,6 +610,7 @@
 	                                 hweight32(nladdr->nl_groups) -
 	                                 hweight32(nlk->groups[0]));
 	nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | nladdr->nl_groups; 
+	netlink_update_listeners(sk);
 	netlink_table_ungrab();
 
 	return 0;
@@ -807,6 +829,17 @@
 	return netlink_sendskb(sk, skb, ssk->sk_protocol);
 }
 
+int netlink_has_listeners(struct sock *sk, unsigned int group)
+{
+	int res = 0;
+
+	BUG_ON(!(nlk_sk(sk)->flags & NETLINK_KERNEL_SOCKET));
+	if (group - 1 < nl_table[sk->sk_protocol].groups)
+		res = test_bit(group - 1, nl_table[sk->sk_protocol].listeners);
+	return res;
+}
+EXPORT_SYMBOL_GPL(netlink_has_listeners);
+
 static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb)
 {
 	struct netlink_sock *nlk = nlk_sk(sk);
@@ -1011,6 +1044,7 @@
 		else
 			__clear_bit(val - 1, nlk->groups);
 		netlink_update_subscriptions(sk, subscriptions);
+		netlink_update_listeners(sk);
 		netlink_table_ungrab();
 		err = 0;
 		break;
@@ -1236,6 +1270,7 @@
 	struct socket *sock;
 	struct sock *sk;
 	struct netlink_sock *nlk;
+	unsigned long *listeners = NULL;
 
 	if (!nl_table)
 		return NULL;
@@ -1249,6 +1284,13 @@
 	if (__netlink_create(sock, unit) < 0)
 		goto out_sock_release;
 
+	if (groups < 32)
+		groups = 32;
+
+	listeners = kzalloc(NLGRPSZ(groups), GFP_KERNEL);
+	if (!listeners)
+		goto out_sock_release;
+
 	sk = sock->sk;
 	sk->sk_data_ready = netlink_data_ready;
 	if (input)
@@ -1261,7 +1303,8 @@
 	nlk->flags |= NETLINK_KERNEL_SOCKET;
 
 	netlink_table_grab();
-	nl_table[unit].groups = groups < 32 ? 32 : groups;
+	nl_table[unit].groups = groups;
+	nl_table[unit].listeners = listeners;
 	nl_table[unit].module = module;
 	nl_table[unit].registered = 1;
 	netlink_table_ungrab();
@@ -1269,6 +1312,7 @@
 	return sk;
 
 out_sock_release:
+	kfree(listeners);
 	sock_release(sock);
 	return NULL;
 }
diff -urN oldtree/net/netlink/genetlink.c newtree/net/netlink/genetlink.c
--- oldtree/net/netlink/genetlink.c	2006-02-19 11:41:06.509353528 +0000
+++ newtree/net/netlink/genetlink.c	2006-02-21 15:58:24.281455216 +0000
@@ -13,26 +13,27 @@
 #include <linux/socket.h>
 #include <linux/string.h>
 #include <linux/skbuff.h>
+#include <linux/mutex.h>
 #include <net/sock.h>
 #include <net/genetlink.h>
 
 struct sock *genl_sock = NULL;
 
-static DECLARE_MUTEX(genl_sem); /* serialization of message processing */
+static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */
 
 static void genl_lock(void)
 {
-	down(&genl_sem);
+	mutex_lock(&genl_mutex);
 }
 
 static int genl_trylock(void)
 {
-	return down_trylock(&genl_sem);
+	return !mutex_trylock(&genl_mutex);
 }
 
 static void genl_unlock(void)
 {
-	up(&genl_sem);
+	mutex_unlock(&genl_mutex);
 
 	if (genl_sock && genl_sock->sk_receive_queue.qlen)
 		genl_sock->sk_data_ready(genl_sock, 0);
diff -urN oldtree/net/sched/act_ipt.c newtree/net/sched/act_ipt.c
--- oldtree/net/sched/act_ipt.c	2006-02-19 11:41:06.519352008 +0000
+++ newtree/net/sched/act_ipt.c	2006-02-21 15:58:16.473642184 +0000
@@ -70,7 +70,8 @@
 	t->u.kernel.target = target;
 
 	if (t->u.kernel.target->checkentry
-	    && !t->u.kernel.target->checkentry(table, NULL, t->data,
+	    && !t->u.kernel.target->checkentry(table, NULL,
+		    			       t->u.kernel.target, t->data,
 					       t->u.target_size - sizeof(*t),
 					       hook)) {
 		DPRINTK("ipt_init_target: check failed for `%s'.\n",
@@ -86,7 +87,7 @@
 ipt_destroy_target(struct ipt_entry_target *t)
 {
 	if (t->u.kernel.target->destroy)
-		t->u.kernel.target->destroy(t->data,
+		t->u.kernel.target->destroy(t->u.kernel.target, t->data,
 		                            t->u.target_size - sizeof(*t));
         module_put(t->u.kernel.target->me);
 }
@@ -224,8 +225,9 @@
 	/* iptables targets take a double skb pointer in case the skb
 	 * needs to be replaced. We don't own the skb, so this must not
 	 * happen. The pskb_expand_head above should make sure of this */
-	ret = p->t->u.kernel.target->target(&skb, skb->dev, NULL,
-					    p->hook, p->t->data, NULL);
+	ret = p->t->u.kernel.target->target(&skb, skb->dev, NULL, p->hook,
+					    p->t->u.kernel.target, p->t->data,
+					    NULL);
 	switch (ret) {
 	case NF_ACCEPT:
 		result = TC_ACT_OK;
diff -urN oldtree/net/sched/sch_atm.c newtree/net/sched/sch_atm.c
--- oldtree/net/sched/sch_atm.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/sched/sch_atm.c	2006-02-21 15:58:16.474642032 +0000
@@ -638,6 +638,7 @@
 	    sch,p,flow,skb,tcm);
 	if (!find_flow(p,flow)) return -EINVAL;
 	tcm->tcm_handle = flow->classid;
+	tcm->tcm_info = flow->q->handle;
 	rta = (struct rtattr *) b;
 	RTA_PUT(skb,TCA_OPTIONS,0,NULL);
 	RTA_PUT(skb,TCA_ATM_HDR,flow->hdr_len,flow->hdr);
diff -urN oldtree/net/sched/sch_dsmark.c newtree/net/sched/sch_dsmark.c
--- oldtree/net/sched/sch_dsmark.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/sched/sch_dsmark.c	2006-02-21 15:58:16.475641880 +0000
@@ -438,6 +438,7 @@
 		return -EINVAL;
 
 	tcm->tcm_handle = TC_H_MAKE(TC_H_MAJ(sch->handle), cl-1);
+	tcm->tcm_info = p->q->handle;
 
 	opts = RTA_NEST(skb, TCA_OPTIONS);
 	RTA_PUT_U8(skb,TCA_DSMARK_MASK, p->mask[cl-1]);
diff -urN oldtree/net/sched/sch_netem.c newtree/net/sched/sch_netem.c
--- oldtree/net/sched/sch_netem.c	2006-02-19 11:41:06.529350488 +0000
+++ newtree/net/sched/sch_netem.c	2006-02-21 15:58:16.475641880 +0000
@@ -252,9 +252,9 @@
 static unsigned int netem_drop(struct Qdisc* sch)
 {
 	struct netem_sched_data *q = qdisc_priv(sch);
-	unsigned int len;
+	unsigned int len = 0;
 
-	if ((len = q->qdisc->ops->drop(q->qdisc)) != 0) {
+	if (q->qdisc->ops->drop && (len = q->qdisc->ops->drop(q->qdisc)) != 0) {
 		sch->q.qlen--;
 		sch->qstats.drops++;
 	}
diff -urN oldtree/net/sched/sch_prio.c newtree/net/sched/sch_prio.c
--- oldtree/net/sched/sch_prio.c	2006-02-19 11:41:06.530350336 +0000
+++ newtree/net/sched/sch_prio.c	2006-02-21 15:58:16.476641728 +0000
@@ -165,7 +165,7 @@
 
 	for (prio = q->bands-1; prio >= 0; prio--) {
 		qdisc = q->queues[prio];
-		if ((len = qdisc->ops->drop(qdisc)) != 0) {
+		if (qdisc->ops->drop && (len = qdisc->ops->drop(qdisc)) != 0) {
 			sch->q.qlen--;
 			return len;
 		}
diff -urN oldtree/net/sched/sch_red.c newtree/net/sched/sch_red.c
--- oldtree/net/sched/sch_red.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/sched/sch_red.c	2006-02-21 15:58:16.515635800 +0000
@@ -44,6 +44,7 @@
 	unsigned char		flags;
 	struct red_parms	parms;
 	struct red_stats	stats;
+	struct Qdisc		*qdisc;
 };
 
 static inline int red_use_ecn(struct red_sched_data *q)
@@ -59,8 +60,10 @@
 static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 {
 	struct red_sched_data *q = qdisc_priv(sch);
+	struct Qdisc *child = q->qdisc;
+	int ret;
 
-	q->parms.qavg = red_calc_qavg(&q->parms, sch->qstats.backlog);
+	q->parms.qavg = red_calc_qavg(&q->parms, child->qstats.backlog);
 
 	if (red_is_idling(&q->parms))
 		red_end_of_idle_period(&q->parms);
@@ -91,11 +94,16 @@
 			break;
 	}
 
-	if (sch->qstats.backlog + skb->len <= q->limit)
-		return qdisc_enqueue_tail(skb, sch);
-
-	q->stats.pdrop++;
-	return qdisc_drop(skb, sch);
+	ret = child->enqueue(skb, child);
+	if (likely(ret == NET_XMIT_SUCCESS)) {
+		sch->bstats.bytes += skb->len;
+		sch->bstats.packets++;
+		sch->q.qlen++;
+	} else {
+		q->stats.pdrop++;
+		sch->qstats.drops++;
+	}
+	return ret;
 
 congestion_drop:
 	qdisc_drop(skb, sch);
@@ -105,21 +113,30 @@
 static int red_requeue(struct sk_buff *skb, struct Qdisc* sch)
 {
 	struct red_sched_data *q = qdisc_priv(sch);
+	struct Qdisc *child = q->qdisc;
+	int ret;
 
 	if (red_is_idling(&q->parms))
 		red_end_of_idle_period(&q->parms);
 
-	return qdisc_requeue(skb, sch);
+	ret = child->ops->requeue(skb, child);
+	if (likely(ret == NET_XMIT_SUCCESS)) {
+		sch->qstats.requeues++;
+		sch->q.qlen++;
+	}
+	return ret;
 }
 
 static struct sk_buff * red_dequeue(struct Qdisc* sch)
 {
 	struct sk_buff *skb;
 	struct red_sched_data *q = qdisc_priv(sch);
+	struct Qdisc *child = q->qdisc;
 
-	skb = qdisc_dequeue_head(sch);
-
-	if (skb == NULL && !red_is_idling(&q->parms))
+	skb = child->dequeue(child);
+	if (skb)
+		sch->q.qlen--;
+	else if (!red_is_idling(&q->parms))
 		red_start_of_idle_period(&q->parms);
 
 	return skb;
@@ -127,14 +144,14 @@
 
 static unsigned int red_drop(struct Qdisc* sch)
 {
-	struct sk_buff *skb;
 	struct red_sched_data *q = qdisc_priv(sch);
+	struct Qdisc *child = q->qdisc;
+	unsigned int len;
 
-	skb = qdisc_dequeue_tail(sch);
-	if (skb) {
-		unsigned int len = skb->len;
+	if (child->ops->drop && (len = child->ops->drop(child)) > 0) {
 		q->stats.other++;
-		qdisc_drop(skb, sch);
+		sch->qstats.drops++;
+		sch->q.qlen--;
 		return len;
 	}
 
@@ -148,15 +165,48 @@
 {
 	struct red_sched_data *q = qdisc_priv(sch);
 
-	qdisc_reset_queue(sch);
+	qdisc_reset(q->qdisc);
+	sch->q.qlen = 0;
 	red_restart(&q->parms);
 }
 
+static void red_destroy(struct Qdisc *sch)
+{
+	struct red_sched_data *q = qdisc_priv(sch);
+	qdisc_destroy(q->qdisc);
+}
+
+static struct Qdisc *red_create_dflt(struct net_device *dev, u32 limit)
+{
+	struct Qdisc *q = qdisc_create_dflt(dev, &bfifo_qdisc_ops);
+	struct rtattr *rta;
+	int ret;
+
+	if (q) {
+		rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)),
+		              GFP_KERNEL);
+		if (rta) {
+			rta->rta_type = RTM_NEWQDISC;
+			rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt));
+			((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit;
+
+			ret = q->ops->change(q, rta);
+			kfree(rta);
+
+			if (ret == 0)
+				return q;
+		}
+		qdisc_destroy(q);
+	}
+	return NULL;
+}
+
 static int red_change(struct Qdisc *sch, struct rtattr *opt)
 {
 	struct red_sched_data *q = qdisc_priv(sch);
 	struct rtattr *tb[TCA_RED_MAX];
 	struct tc_red_qopt *ctl;
+	struct Qdisc *child = NULL;
 
 	if (opt == NULL || rtattr_parse_nested(tb, TCA_RED_MAX, opt))
 		return -EINVAL;
@@ -169,9 +219,17 @@
 
 	ctl = RTA_DATA(tb[TCA_RED_PARMS-1]);
 
+	if (ctl->limit > 0) {
+		child = red_create_dflt(sch->dev, ctl->limit);
+		if (child == NULL)
+			return -ENOMEM;
+	}
+
 	sch_tree_lock(sch);
 	q->flags = ctl->flags;
 	q->limit = ctl->limit;
+	if (child)
+		qdisc_destroy(xchg(&q->qdisc, child));
 
 	red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog,
 				 ctl->Plog, ctl->Scell_log,
@@ -186,6 +244,9 @@
 
 static int red_init(struct Qdisc* sch, struct rtattr *opt)
 {
+	struct red_sched_data *q = qdisc_priv(sch);
+
+	q->qdisc = &noop_qdisc;
 	return red_change(sch, opt);
 }
 
@@ -224,15 +285,101 @@
 	return gnet_stats_copy_app(d, &st, sizeof(st));
 }
 
+static int red_dump_class(struct Qdisc *sch, unsigned long cl,
+			  struct sk_buff *skb, struct tcmsg *tcm)
+{
+	struct red_sched_data *q = qdisc_priv(sch);
+	
+	if (cl != 1)
+		return -ENOENT;
+	tcm->tcm_handle |= TC_H_MIN(1);
+	tcm->tcm_info = q->qdisc->handle;
+	return 0;
+}
+
+static int red_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
+		     struct Qdisc **old)
+{
+	struct red_sched_data *q = qdisc_priv(sch);
+
+	if (new == NULL)
+		new = &noop_qdisc;
+
+	sch_tree_lock(sch);
+	*old = xchg(&q->qdisc, new);
+	qdisc_reset(*old);
+	sch->q.qlen = 0;
+	sch_tree_unlock(sch);
+	return 0;
+}
+
+static struct Qdisc *red_leaf(struct Qdisc *sch, unsigned long arg)
+{
+	struct red_sched_data *q = qdisc_priv(sch);
+	return q->qdisc;
+}
+
+static unsigned long red_get(struct Qdisc *sch, u32 classid)
+{
+	return 1;
+}
+
+static void red_put(struct Qdisc *sch, unsigned long arg)
+{
+	return;
+}
+
+static int red_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
+			    struct rtattr **tca, unsigned long *arg)
+{
+	return -ENOSYS;
+}
+
+static int red_delete(struct Qdisc *sch, unsigned long cl)
+{
+	return -ENOSYS;
+}
+
+static void red_walk(struct Qdisc *sch, struct qdisc_walker *walker)
+{
+	if (!walker->stop) {
+		if (walker->count >= walker->skip)
+			if (walker->fn(sch, 1, walker) < 0) {
+				walker->stop = 1;
+				return;
+			}
+		walker->count++;
+	}
+}
+
+static struct tcf_proto **red_find_tcf(struct Qdisc *sch, unsigned long cl)
+{
+	return NULL;
+}
+
+static struct Qdisc_class_ops red_class_ops = {
+	.graft		=	red_graft,
+	.leaf		=	red_leaf,
+	.get		=	red_get,
+	.put		=	red_put,
+	.change		=	red_change_class,
+	.delete		=	red_delete,
+	.walk		=	red_walk,
+	.tcf_chain	=	red_find_tcf,
+	.dump		=	red_dump_class,
+};
+
 static struct Qdisc_ops red_qdisc_ops = {
 	.id		=	"red",
 	.priv_size	=	sizeof(struct red_sched_data),
+	.cl_ops		=	&red_class_ops,
 	.enqueue	=	red_enqueue,
 	.dequeue	=	red_dequeue,
 	.requeue	=	red_requeue,
 	.drop		=	red_drop,
 	.init		=	red_init,
 	.reset		=	red_reset,
+	.destroy	=	red_destroy,
 	.change		=	red_change,
 	.dump		=	red_dump,
 	.dump_stats	=	red_dump_stats,
diff -urN oldtree/net/sched/sch_sfq.c newtree/net/sched/sch_sfq.c
--- oldtree/net/sched/sch_sfq.c	2006-02-19 11:41:06.530350336 +0000
+++ newtree/net/sched/sch_sfq.c	2006-02-21 15:58:16.516635648 +0000
@@ -232,6 +232,7 @@
 		sfq_dec(q, x);
 		sch->q.qlen--;
 		sch->qstats.drops++;
+		sch->qstats.backlog -= len;
 		return len;
 	}
 
@@ -248,6 +249,7 @@
 		sch->q.qlen--;
 		q->ht[q->hash[d]] = SFQ_DEPTH;
 		sch->qstats.drops++;
+		sch->qstats.backlog -= len;
 		return len;
 	}
 
@@ -266,6 +268,7 @@
 		q->ht[hash] = x = q->dep[SFQ_DEPTH].next;
 		q->hash[x] = hash;
 	}
+	sch->qstats.backlog += skb->len;
 	__skb_queue_tail(&q->qs[x], skb);
 	sfq_inc(q, x);
 	if (q->qs[x].qlen == 1) {		/* The flow is new */
@@ -301,6 +304,7 @@
 		q->ht[hash] = x = q->dep[SFQ_DEPTH].next;
 		q->hash[x] = hash;
 	}
+	sch->qstats.backlog += skb->len;
 	__skb_queue_head(&q->qs[x], skb);
 	sfq_inc(q, x);
 	if (q->qs[x].qlen == 1) {		/* The flow is new */
@@ -344,6 +348,7 @@
 	skb = __skb_dequeue(&q->qs[a]);
 	sfq_dec(q, a);
 	sch->q.qlen--;
+	sch->qstats.backlog -= skb->len;
 
 	/* Is the slot empty? */
 	if (q->qs[a].qlen == 0) {
diff -urN oldtree/net/sched/sch_tbf.c newtree/net/sched/sch_tbf.c
--- oldtree/net/sched/sch_tbf.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/sched/sch_tbf.c	2006-02-21 15:58:16.517635496 +0000
@@ -177,9 +177,9 @@
 static unsigned int tbf_drop(struct Qdisc* sch)
 {
 	struct tbf_sched_data *q = qdisc_priv(sch);
-	unsigned int len;
+	unsigned int len = 0;
 
-	if ((len = q->qdisc->ops->drop(q->qdisc)) != 0) {
+	if (q->qdisc->ops->drop && (len = q->qdisc->ops->drop(q->qdisc)) != 0) {
 		sch->q.qlen--;
 		sch->qstats.drops++;
 	}
@@ -341,13 +341,14 @@
 	if (max_size < 0)
 		goto done;
 
-	if (q->qdisc == &noop_qdisc) {
+	if (qopt->limit > 0) {
 		if ((child = tbf_create_dflt_qdisc(sch->dev, qopt->limit)) == NULL)
 			goto done;
 	}
 
 	sch_tree_lock(sch);
-	if (child) q->qdisc = child;
+	if (child)
+		qdisc_destroy(xchg(&q->qdisc, child));
 	q->limit = qopt->limit;
 	q->mtu = qopt->mtu;
 	q->max_size = max_size;
diff -urN oldtree/net/sctp/ipv6.c newtree/net/sctp/ipv6.c
--- oldtree/net/sctp/ipv6.c	2006-02-19 11:41:06.536349424 +0000
+++ newtree/net/sctp/ipv6.c	2006-02-21 15:58:37.334470856 +0000
@@ -85,7 +85,7 @@
 
 /* ICMP error handler. */
 SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-			     int type, int code, int offset, __u32 info)
+			     int type, int code, int offset, __be32 info)
 {
 	struct inet6_dev *idev;
 	struct ipv6hdr *iph = (struct ipv6hdr *)skb->data;
diff -urN oldtree/net/socket.c newtree/net/socket.c
--- oldtree/net/socket.c	2006-02-19 11:41:06.550347296 +0000
+++ newtree/net/socket.c	2006-02-21 15:58:17.005561320 +0000
@@ -68,6 +68,7 @@
 #include <linux/netdevice.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/mutex.h>
 #include <linux/wanrouter.h>
 #include <linux/if_bridge.h>
 #include <linux/if_frad.h>
@@ -84,10 +85,7 @@
 #include <linux/compat.h>
 #include <linux/kmod.h>
 #include <linux/audit.h>
-
-#ifdef CONFIG_NET_RADIO
-#include <linux/wireless.h>		/* Note : will define WIRELESS_EXT */
-#endif	/* CONFIG_NET_RADIO */
+#include <linux/wireless.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -109,6 +107,10 @@
 			      struct poll_table_struct *wait);
 static long sock_ioctl(struct file *file,
 		      unsigned int cmd, unsigned long arg);
+#ifdef CONFIG_COMPAT
+static long compat_sock_ioctl(struct file *file,
+		      unsigned int cmd, unsigned long arg);
+#endif
 static int sock_fasync(int fd, struct file *filp, int on);
 static ssize_t sock_readv(struct file *file, const struct iovec *vector,
 			  unsigned long count, loff_t *ppos);
@@ -130,6 +132,9 @@
 	.aio_write =	sock_aio_write,
 	.poll =		sock_poll,
 	.unlocked_ioctl = sock_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = compat_sock_ioctl,
+#endif
 	.mmap =		sock_mmap,
 	.open =		sock_no_open,	/* special open code to disallow open via /proc */
 	.release =	sock_close,
@@ -351,8 +356,8 @@
 /*
  *	Obtains the first available file descriptor and sets it up for use.
  *
- *	This function creates file structure and maps it to fd space
- *	of current process. On success it returns file descriptor
+ *	These functions create file structures and maps them to fd space
+ *	of the current process. On success it returns file descriptor
  *	and file struct implicitly stored in sock->file.
  *	Note that another thread may close file descriptor before we return
  *	from this function. We use the fact that now we do not refer
@@ -365,52 +370,67 @@
  *	but we take care of internal coherence yet.
  */
 
-int sock_map_fd(struct socket *sock)
+static int sock_alloc_fd(struct file **filep)
 {
 	int fd;
-	struct qstr this;
-	char name[32];
-
-	/*
-	 *	Find a file descriptor suitable for return to the user. 
-	 */
 
 	fd = get_unused_fd();
-	if (fd >= 0) {
+	if (likely(fd >= 0)) {
 		struct file *file = get_empty_filp();
 
-		if (!file) {
+		*filep = file;
+		if (unlikely(!file)) {
 			put_unused_fd(fd);
-			fd = -ENFILE;
-			goto out;
+			return -ENFILE;
 		}
+	} else
+		*filep = NULL;
+	return fd;
+}
 
-		this.len = sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino);
-		this.name = name;
-		this.hash = SOCK_INODE(sock)->i_ino;
-
-		file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);
-		if (!file->f_dentry) {
-			put_filp(file);
+static int sock_attach_fd(struct socket *sock, struct file *file)
+{
+	struct qstr this;
+	char name[32];
+
+	this.len = sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino);
+	this.name = name;
+	this.hash = SOCK_INODE(sock)->i_ino;
+
+	file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);
+	if (unlikely(!file->f_dentry))
+		return -ENOMEM;
+
+	file->f_dentry->d_op = &sockfs_dentry_operations;
+	d_add(file->f_dentry, SOCK_INODE(sock));
+	file->f_vfsmnt = mntget(sock_mnt);
+	file->f_mapping = file->f_dentry->d_inode->i_mapping;
+
+	sock->file = file;
+	file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops;
+	file->f_mode = FMODE_READ | FMODE_WRITE;
+	file->f_flags = O_RDWR;
+	file->f_pos = 0;
+	file->private_data = sock;
+
+	return 0;
+}
+
+int sock_map_fd(struct socket *sock)
+{
+	struct file *newfile;
+	int fd = sock_alloc_fd(&newfile);
+
+	if (likely(fd >= 0)) {
+		int err = sock_attach_fd(sock, newfile);
+
+		if (unlikely(err < 0)) {
+			put_filp(newfile);
 			put_unused_fd(fd);
-			fd = -ENOMEM;
-			goto out;
+			return err;
 		}
-		file->f_dentry->d_op = &sockfs_dentry_operations;
-		d_add(file->f_dentry, SOCK_INODE(sock));
-		file->f_vfsmnt = mntget(sock_mnt);
-		file->f_mapping = file->f_dentry->d_inode->i_mapping;
-
-		sock->file = file;
-		file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops;
-		file->f_mode = FMODE_READ | FMODE_WRITE;
-		file->f_flags = O_RDWR;
-		file->f_pos = 0;
-		file->private_data = sock;
-		fd_install(fd, file);
+		fd_install(fd, newfile);
 	}
-
-out:
 	return fd;
 }
 
@@ -792,36 +812,36 @@
  * with module unload.
  */
 
-static DECLARE_MUTEX(br_ioctl_mutex);
+static DEFINE_MUTEX(br_ioctl_mutex);
 static int (*br_ioctl_hook)(unsigned int cmd, void __user *arg) = NULL;
 
 void brioctl_set(int (*hook)(unsigned int, void __user *))
 {
-	down(&br_ioctl_mutex);
+	mutex_lock(&br_ioctl_mutex);
 	br_ioctl_hook = hook;
-	up(&br_ioctl_mutex);
+	mutex_unlock(&br_ioctl_mutex);
 }
 EXPORT_SYMBOL(brioctl_set);
 
-static DECLARE_MUTEX(vlan_ioctl_mutex);
+static DEFINE_MUTEX(vlan_ioctl_mutex);
 static int (*vlan_ioctl_hook)(void __user *arg);
 
 void vlan_ioctl_set(int (*hook)(void __user *))
 {
-	down(&vlan_ioctl_mutex);
+	mutex_lock(&vlan_ioctl_mutex);
 	vlan_ioctl_hook = hook;
-	up(&vlan_ioctl_mutex);
+	mutex_unlock(&vlan_ioctl_mutex);
 }
 EXPORT_SYMBOL(vlan_ioctl_set);
 
-static DECLARE_MUTEX(dlci_ioctl_mutex);
+static DEFINE_MUTEX(dlci_ioctl_mutex);
 static int (*dlci_ioctl_hook)(unsigned int, void __user *);
 
 void dlci_ioctl_set(int (*hook)(unsigned int, void __user *))
 {
-	down(&dlci_ioctl_mutex);
+	mutex_lock(&dlci_ioctl_mutex);
 	dlci_ioctl_hook = hook;
-	up(&dlci_ioctl_mutex);
+	mutex_unlock(&dlci_ioctl_mutex);
 }
 EXPORT_SYMBOL(dlci_ioctl_set);
 
@@ -840,11 +860,11 @@
 	if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
 		err = dev_ioctl(cmd, argp);
 	} else
-#ifdef WIRELESS_EXT
+#ifdef CONFIG_WIRELESS_EXT
 	if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
 		err = dev_ioctl(cmd, argp);
 	} else
-#endif	/* WIRELESS_EXT */
+#endif	/* CONFIG_WIRELESS_EXT */
 	switch (cmd) {
 		case FIOSETOWN:
 		case SIOCSPGRP:
@@ -865,10 +885,10 @@
 			if (!br_ioctl_hook)
 				request_module("bridge");
 
-			down(&br_ioctl_mutex);
+			mutex_lock(&br_ioctl_mutex);
 			if (br_ioctl_hook) 
 				err = br_ioctl_hook(cmd, argp);
-			up(&br_ioctl_mutex);
+			mutex_unlock(&br_ioctl_mutex);
 			break;
 		case SIOCGIFVLAN:
 		case SIOCSIFVLAN:
@@ -876,10 +896,10 @@
 			if (!vlan_ioctl_hook)
 				request_module("8021q");
 
-			down(&vlan_ioctl_mutex);
+			mutex_lock(&vlan_ioctl_mutex);
 			if (vlan_ioctl_hook)
 				err = vlan_ioctl_hook(argp);
-			up(&vlan_ioctl_mutex);
+			mutex_unlock(&vlan_ioctl_mutex);
 			break;
 		case SIOCGIFDIVERT:
 		case SIOCSIFDIVERT:
@@ -893,9 +913,9 @@
 				request_module("dlci");
 
 			if (dlci_ioctl_hook) {
-				down(&dlci_ioctl_mutex);
+				mutex_lock(&dlci_ioctl_mutex);
 				err = dlci_ioctl_hook(cmd, argp);
-				up(&dlci_ioctl_mutex);
+				mutex_unlock(&dlci_ioctl_mutex);
 			}
 			break;
 		default:
@@ -1352,7 +1372,8 @@
 asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int __user *upeer_addrlen)
 {
 	struct socket *sock, *newsock;
-	int err, len;
+	struct file *newfile;
+	int err, len, newfd;
 	char address[MAX_SOCK_ADDR];
 
 	sock = sockfd_lookup(fd, &err);
@@ -1372,28 +1393,38 @@
 	 */
 	__module_get(newsock->ops->owner);
 
+	newfd = sock_alloc_fd(&newfile);
+	if (unlikely(newfd < 0)) {
+		err = newfd;
+		goto out_release;
+	}
+
+	err = sock_attach_fd(newsock, newfile);
+	if (err < 0)
+		goto out_fd;
+
 	err = security_socket_accept(sock, newsock);
 	if (err)
-		goto out_release;
+		goto out_fd;
 
 	err = sock->ops->accept(sock, newsock, sock->file->f_flags);
 	if (err < 0)
-		goto out_release;
+		goto out_fd;
 
 	if (upeer_sockaddr) {
 		if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 2)<0) {
 			err = -ECONNABORTED;
-			goto out_release;
+			goto out_fd;
 		}
 		err = move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen);
 		if (err < 0)
-			goto out_release;
+			goto out_fd;
 	}
 
 	/* File flags are not inherited via accept() unlike another OSes. */
 
-	if ((err = sock_map_fd(newsock)) < 0)
-		goto out_release;
+	fd_install(newfd, newfile);
+	err = newfd;
 
 	security_socket_post_accept(sock, newsock);
 
@@ -1401,6 +1432,9 @@
 	sockfd_put(sock);
 out:
 	return err;
+out_fd:
+	put_filp(newfile);
+	put_unused_fd(newfd);
 out_release:
 	sock_release(newsock);
 	goto out_put;
@@ -2089,6 +2123,20 @@
 }
 #endif /* CONFIG_PROC_FS */
 
+#ifdef CONFIG_COMPAT
+static long compat_sock_ioctl(struct file *file, unsigned cmd,
+				unsigned long arg)
+{
+	struct socket *sock = file->private_data;
+	int ret = -ENOIOCTLCMD;
+
+	if (sock->ops->compat_ioctl)
+		ret = sock->ops->compat_ioctl(sock, cmd, arg);
+
+	return ret;
+}
+#endif
+
 /* ABI emulation layers need these two */
 EXPORT_SYMBOL(move_addr_to_kernel);
 EXPORT_SYMBOL(move_addr_to_user);
diff -urN oldtree/net/sunrpc/auth.c newtree/net/sunrpc/auth.c
--- oldtree/net/sunrpc/auth.c	2006-02-19 11:41:06.551347144 +0000
+++ newtree/net/sunrpc/auth.c	2006-02-21 15:58:37.342469640 +0000
@@ -319,8 +319,8 @@
 	task->tk_msg.rpc_cred = NULL;
 }
 
-u32 *
-rpcauth_marshcred(struct rpc_task *task, u32 *p)
+__be32 *
+rpcauth_marshcred(struct rpc_task *task, __be32 *p)
 {
 	struct rpc_cred	*cred = task->tk_msg.rpc_cred;
 
@@ -330,8 +330,8 @@
 	return cred->cr_ops->crmarshal(task, p);
 }
 
-u32 *
-rpcauth_checkverf(struct rpc_task *task, u32 *p)
+__be32 *
+rpcauth_checkverf(struct rpc_task *task, __be32 *p)
 {
 	struct rpc_cred	*cred = task->tk_msg.rpc_cred;
 
@@ -343,7 +343,7 @@
 
 int
 rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp,
-		u32 *data, void *obj)
+		__be32 *data, void *obj)
 {
 	struct rpc_cred *cred = task->tk_msg.rpc_cred;
 
@@ -357,7 +357,7 @@
 
 int
 rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
-		u32 *data, void *obj)
+		__be32 *data, void *obj)
 {
 	struct rpc_cred *cred = task->tk_msg.rpc_cred;
 
diff -urN oldtree/net/sunrpc/auth_gss/auth_gss.c newtree/net/sunrpc/auth_gss/auth_gss.c
--- oldtree/net/sunrpc/auth_gss/auth_gss.c	2006-02-19 11:41:06.552346992 +0000
+++ newtree/net/sunrpc/auth_gss/auth_gss.c	2006-02-21 15:58:37.352468120 +0000
@@ -832,14 +832,14 @@
 * Marshal credentials.
 * Maybe we should keep a cached credential for performance reasons.
 */
-static u32 *
-gss_marshal(struct rpc_task *task, u32 *p)
+static __be32 *
+gss_marshal(struct rpc_task *task, __be32 *p)
 {
 	struct rpc_cred *cred = task->tk_msg.rpc_cred;
 	struct gss_cred	*gss_cred = container_of(cred, struct gss_cred,
 						 gc_base);
 	struct gss_cl_ctx	*ctx = gss_cred_get_ctx(cred);
-	u32		*cred_len;
+	__be32		*cred_len;
 	struct rpc_rqst *req = task->tk_rqstp;
 	u32             maj_stat = 0;
 	struct xdr_netobj mic;
@@ -900,12 +900,12 @@
 	return 0;
 }
 
-static u32 *
-gss_validate(struct rpc_task *task, u32 *p)
+static __be32 *
+gss_validate(struct rpc_task *task, __be32 *p)
 {
 	struct rpc_cred *cred = task->tk_msg.rpc_cred;
 	struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
-	u32		seq;
+	__be32		seq;
 	struct kvec	iov;
 	struct xdr_buf	verf_buf;
 	struct xdr_netobj mic;
@@ -946,13 +946,14 @@
 
 static inline int
 gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
-		kxdrproc_t encode, struct rpc_rqst *rqstp, u32 *p, void *obj)
+		kxdrproc_t encode, struct rpc_rqst *rqstp, __be32 *p, void *obj)
 {
 	struct xdr_buf	*snd_buf = &rqstp->rq_snd_buf;
 	struct xdr_buf	integ_buf;
-	u32             *integ_len = NULL;
+	__be32          *integ_len = NULL;
 	struct xdr_netobj mic;
-	u32		offset, *q;
+	u32		offset;
+	__be32		*q;
 	struct kvec	*iov;
 	u32             maj_stat = 0;
 	int		status = -EIO;
@@ -1038,13 +1039,13 @@
 
 static inline int
 gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
-		kxdrproc_t encode, struct rpc_rqst *rqstp, u32 *p, void *obj)
+		kxdrproc_t encode, struct rpc_rqst *rqstp, __be32 *p, void *obj)
 {
 	struct xdr_buf	*snd_buf = &rqstp->rq_snd_buf;
 	u32		offset;
 	u32             maj_stat;
 	int		status;
-	u32		*opaque_len;
+	__be32		*opaque_len;
 	struct page	**inpages;
 	int		first;
 	int		pad;
@@ -1101,7 +1102,7 @@
 
 static int
 gss_wrap_req(struct rpc_task *task,
-	     kxdrproc_t encode, void *rqstp, u32 *p, void *obj)
+	     kxdrproc_t encode, void *rqstp, __be32 *p, void *obj)
 {
 	struct rpc_cred *cred = task->tk_msg.rpc_cred;
 	struct gss_cred	*gss_cred = container_of(cred, struct gss_cred,
@@ -1138,7 +1139,7 @@
 
 static inline int
 gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
-		struct rpc_rqst *rqstp, u32 **p)
+		struct rpc_rqst *rqstp, __be32 **p)
 {
 	struct xdr_buf	*rcv_buf = &rqstp->rq_rcv_buf;
 	struct xdr_buf integ_buf;
@@ -1175,7 +1176,7 @@
 
 static inline int
 gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
-		struct rpc_rqst *rqstp, u32 **p)
+		struct rpc_rqst *rqstp, __be32 **p)
 {
 	struct xdr_buf  *rcv_buf = &rqstp->rq_rcv_buf;
 	u32 offset;
@@ -1204,13 +1205,13 @@
 
 static int
 gss_unwrap_resp(struct rpc_task *task,
-		kxdrproc_t decode, void *rqstp, u32 *p, void *obj)
+		kxdrproc_t decode, void *rqstp, __be32 *p, void *obj)
 {
 	struct rpc_cred *cred = task->tk_msg.rpc_cred;
 	struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
 			gc_base);
 	struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
-	u32		*savedp = p;
+	__be32		*savedp = p;
 	struct kvec	*head = ((struct rpc_rqst *)rqstp)->rq_rcv_buf.head;
 	int		savedlen = head->iov_len;
 	int             status = -EIO;
diff -urN oldtree/net/sunrpc/auth_gss/gss_krb5_seal.c newtree/net/sunrpc/auth_gss/gss_krb5_seal.c
--- oldtree/net/sunrpc/auth_gss/gss_krb5_seal.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/sunrpc/auth_gss/gss_krb5_seal.c	2006-02-21 15:58:37.357467360 +0000
@@ -111,7 +111,7 @@
 	krb5_hdr = ptr - 2;
 	msg_start = krb5_hdr + 24;
 
-	*(u16 *)(krb5_hdr + 2) = htons(ctx->signalg);
+	*(__be16 *)(krb5_hdr + 2) = htons(ctx->signalg);
 	memset(krb5_hdr + 4, 0xff, 4);
 
 	if (make_checksum(checksum_type, krb5_hdr, 8, text, 0, &md5cksum))
diff -urN oldtree/net/sunrpc/auth_gss/gss_krb5_wrap.c newtree/net/sunrpc/auth_gss/gss_krb5_wrap.c
--- oldtree/net/sunrpc/auth_gss/gss_krb5_wrap.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/sunrpc/auth_gss/gss_krb5_wrap.c	2006-02-21 15:58:37.367465840 +0000
@@ -175,9 +175,9 @@
 	msg_start = krb5_hdr + 24;
 	/* XXXJBF: */ BUG_ON(buf->head[0].iov_base + offset + headlen != msg_start + blocksize);
 
-	*(u16 *)(krb5_hdr + 2) = htons(kctx->signalg);
+	*(__be16 *)(krb5_hdr + 2) = htons(kctx->signalg);
 	memset(krb5_hdr + 4, 0xff, 4);
-	*(u16 *)(krb5_hdr + 4) = htons(kctx->sealalg);
+	*(__be16 *)(krb5_hdr + 4) = htons(kctx->sealalg);
 
 	make_confounder(msg_start, blocksize);
 
diff -urN oldtree/net/sunrpc/auth_gss/svcauth_gss.c newtree/net/sunrpc/auth_gss/svcauth_gss.c
--- oldtree/net/sunrpc/auth_gss/svcauth_gss.c	2006-02-19 11:41:06.555346536 +0000
+++ newtree/net/sunrpc/auth_gss/svcauth_gss.c	2006-02-21 15:58:37.368465688 +0000
@@ -509,7 +509,7 @@
 
 	if (argv->iov_len < 4)
 		return -1;
-	o->len = ntohl(svc_getu32(argv));
+	o->len = svc_getnl(argv);
 	l = round_up_to_quad(o->len);
 	if (argv->iov_len < l)
 		return -1;
@@ -526,7 +526,7 @@
 
 	if (resv->iov_len + 4 > PAGE_SIZE)
 		return -1;
-	svc_putu32(resv, htonl(o->len));
+	svc_putnl(resv, o->len);
 	p = resv->iov_base + resv->iov_len;
 	resv->iov_len += round_up_to_quad(o->len);
 	if (resv->iov_len > PAGE_SIZE)
@@ -542,7 +542,7 @@
  */
 static int
 gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci,
-		  u32 *rpcstart, struct rpc_gss_wire_cred *gc, u32 *authp)
+		  u32 *rpcstart, struct rpc_gss_wire_cred *gc, __be32 *authp)
 {
 	struct gss_ctx		*ctx_id = rsci->mechctx;
 	struct xdr_buf		rpchdr;
@@ -559,7 +559,7 @@
 	*authp = rpc_autherr_badverf;
 	if (argv->iov_len < 4)
 		return SVC_DENIED;
-	flavor = ntohl(svc_getu32(argv));
+	flavor = svc_getnl(argv);
 	if (flavor != RPC_AUTH_GSS)
 		return SVC_DENIED;
 	if (svc_safe_getnetobj(argv, &checksum))
@@ -603,14 +603,14 @@
 static int
 gss_write_verf(struct svc_rqst *rqstp, struct gss_ctx *ctx_id, u32 seq)
 {
-	u32			xdr_seq;
+	__be32			xdr_seq;
 	u32			maj_stat;
 	struct xdr_buf		verf_data;
 	struct xdr_netobj	mic;
-	u32			*p;
+	__be32			*p;
 	struct kvec		iov;
 
-	svc_putu32(rqstp->rq_res.head, htonl(RPC_AUTH_GSS));
+	svc_putnl(rqstp->rq_res.head, RPC_AUTH_GSS);
 	xdr_seq = htonl(seq);
 
 	iov.iov_base = &xdr_seq;
@@ -684,7 +684,7 @@
 static inline int
 read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj)
 {
-	u32     raw;
+	__be32  raw;
 	int     status;
 
 	status = read_bytes_from_xdr_buf(buf, base, &raw, sizeof(*obj));
@@ -707,7 +707,7 @@
 	struct xdr_netobj mic;
 	struct xdr_buf integ_buf;
 
-	integ_len = ntohl(svc_getu32(&buf->head[0]));
+	integ_len = svc_getnl(&buf->head[0]);
 	if (integ_len & 3)
 		goto out;
 	if (integ_len > buf->len)
@@ -727,7 +727,7 @@
 	maj_stat = gss_verify_mic(ctx, &integ_buf, &mic);
 	if (maj_stat != GSS_S_COMPLETE)
 		goto out;
-	if (ntohl(svc_getu32(&buf->head[0])) != seq)
+	if (svc_getnl(&buf->head[0]) != seq)
 		goto out;
 	stat = 0;
 out:
@@ -739,7 +739,7 @@
 	struct rpc_gss_wire_cred	clcred;
 	/* pointer to the beginning of the procedure-specific results,
 	 * which may be encrypted/checksummed in svcauth_gss_release: */
-	u32				*body_start;
+	__be32				*body_start;
 	struct rsc			*rsci;
 };
 
@@ -780,7 +780,7 @@
  * response here and return SVC_COMPLETE.
  */
 static int
-svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
+svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
 {
 	struct kvec	*argv = &rqstp->rq_arg.head[0];
 	struct kvec	*resv = &rqstp->rq_res.head[0];
@@ -791,7 +791,7 @@
 	struct rsc	*rsci = NULL;
 	struct rsi	*rsip, rsikey;
 	u32		*rpcstart;
-	u32		*reject_stat = resv->iov_base + resv->iov_len;
+	__be32		*reject_stat = resv->iov_base + resv->iov_len;
 	int		ret;
 
 	dprintk("RPC:      svcauth_gss: argv->iov_len = %zd\n",argv->iov_len);
@@ -819,12 +819,12 @@
 
 	if (argv->iov_len < 5 * 4)
 		goto auth_err;
-	crlen = ntohl(svc_getu32(argv));
-	if (ntohl(svc_getu32(argv)) != RPC_GSS_VERSION)
+	crlen = svc_getnl(argv);
+	if (svc_getnl(argv) != RPC_GSS_VERSION)
 		goto auth_err;
-	gc->gc_proc = ntohl(svc_getu32(argv));
-	gc->gc_seq = ntohl(svc_getu32(argv));
-	gc->gc_svc = ntohl(svc_getu32(argv));
+	gc->gc_proc = svc_getnl(argv);
+	gc->gc_seq = svc_getnl(argv);
+	gc->gc_svc = svc_getnl(argv);
 	if (svc_safe_getnetobj(argv, &gc->gc_ctx))
 		goto auth_err;
 	if (crlen != round_up_to_quad(gc->gc_ctx.len) + 5 * 4)
@@ -850,9 +850,9 @@
 	case RPC_GSS_PROC_CONTINUE_INIT:
 		if (argv->iov_len < 2 * 4)
 			goto auth_err;
-		if (ntohl(svc_getu32(argv)) != RPC_AUTH_NULL)
+		if (svc_getnl(argv) != RPC_AUTH_NULL)
 			goto auth_err;
-		if (ntohl(svc_getu32(argv)) != 0)
+		if (svc_getnl(argv) != 0)
 			goto auth_err;
 		break;
 	case RPC_GSS_PROC_DATA:
@@ -910,14 +910,14 @@
 				goto drop;
 			if (resv->iov_len + 4 > PAGE_SIZE)
 				goto drop;
-			svc_putu32(resv, rpc_success);
+			svc_putnl(resv, RPC_SUCCESS);
 			if (svc_safe_putnetobj(resv, &rsip->out_handle))
 				goto drop;
 			if (resv->iov_len + 3 * 4 > PAGE_SIZE)
 				goto drop;
-			svc_putu32(resv, htonl(rsip->major_status));
-			svc_putu32(resv, htonl(rsip->minor_status));
-			svc_putu32(resv, htonl(GSS_SEQ_WIN));
+			svc_putnl(resv, rsip->major_status);
+			svc_putnl(resv, rsip->minor_status);
+			svc_putnl(resv, GSS_SEQ_WIN);
 			if (svc_safe_putnetobj(resv, &rsip->out_token))
 				goto drop;
 			rqstp->rq_client = NULL;
@@ -927,7 +927,7 @@
 		set_bit(CACHE_NEGATIVE, &rsci->h.flags);
 		if (resv->iov_len + 4 > PAGE_SIZE)
 			goto drop;
-		svc_putu32(resv, rpc_success);
+		svc_putnl(resv, RPC_SUCCESS);
 		goto complete;
 	case RPC_GSS_PROC_DATA:
 		*authp = rpcsec_gsserr_ctxproblem;
@@ -983,7 +983,7 @@
 	struct xdr_buf integ_buf;
 	struct xdr_netobj mic;
 	struct kvec *resv;
-	u32 *p;
+	__be32 *p;
 	int integ_offset, integ_len;
 	int stat = -EINVAL;
 
@@ -1039,7 +1039,7 @@
 		mic.data = (u8 *)resv->iov_base + resv->iov_len + 4;
 		if (gss_get_mic(gsd->rsci->mechctx, &integ_buf, &mic))
 			goto out_err;
-		svc_putu32(resv, htonl(mic.len));
+		svc_putnl(resv, mic.len);
 		memset(mic.data + mic.len, 0,
 				round_up_to_quad(mic.len) - mic.len);
 		resv->iov_len += XDR_QUADLEN(mic.len) << 2;
diff -urN oldtree/net/sunrpc/auth_null.c newtree/net/sunrpc/auth_null.c
--- oldtree/net/sunrpc/auth_null.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/sunrpc/auth_null.c	2006-02-21 15:58:37.368465688 +0000
@@ -60,8 +60,8 @@
 /*
  * Marshal credential.
  */
-static u32 *
-nul_marshal(struct rpc_task *task, u32 *p)
+static __be32 *
+nul_marshal(struct rpc_task *task, __be32 *p)
 {
 	*p++ = htonl(RPC_AUTH_NULL);
 	*p++ = 0;
@@ -81,8 +81,8 @@
 	return 0;
 }
 
-static u32 *
-nul_validate(struct rpc_task *task, u32 *p)
+static __be32 *
+nul_validate(struct rpc_task *task, __be32 *p)
 {
 	rpc_authflavor_t	flavor;
 	u32			size;
diff -urN oldtree/net/sunrpc/auth_unix.c newtree/net/sunrpc/auth_unix.c
--- oldtree/net/sunrpc/auth_unix.c	2006-02-19 11:41:06.555346536 +0000
+++ newtree/net/sunrpc/auth_unix.c	2006-02-21 15:58:37.369465536 +0000
@@ -137,12 +137,12 @@
  * Marshal credentials.
  * Maybe we should keep a cached credential for performance reasons.
  */
-static u32 *
-unx_marshal(struct rpc_task *task, u32 *p)
+static __be32 *
+unx_marshal(struct rpc_task *task, __be32 *p)
 {
 	struct rpc_clnt	*clnt = task->tk_client;
 	struct unx_cred	*cred = (struct unx_cred *) task->tk_msg.rpc_cred;
-	u32		*base, *hold;
+	__be32		*base, *hold;
 	int		i;
 
 	*p++ = htonl(RPC_AUTH_UNIX);
@@ -178,8 +178,8 @@
 	return 0;
 }
 
-static u32 *
-unx_validate(struct rpc_task *task, u32 *p)
+static __be32 *
+unx_validate(struct rpc_task *task, __be32 *p)
 {
 	rpc_authflavor_t	flavor;
 	u32			size;
diff -urN oldtree/net/sunrpc/cache.c newtree/net/sunrpc/cache.c
--- oldtree/net/sunrpc/cache.c	2006-02-19 11:41:06.556346384 +0000
+++ newtree/net/sunrpc/cache.c	2006-02-21 15:58:16.648615584 +0000
@@ -26,6 +26,7 @@
 #include <linux/proc_fs.h>
 #include <linux/net.h>
 #include <linux/workqueue.h>
+#include <linux/mutex.h>
 #include <asm/ioctls.h>
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/cache.h>
@@ -532,7 +533,7 @@
  */
 
 static DEFINE_SPINLOCK(queue_lock);
-static DECLARE_MUTEX(queue_io_sem);
+static DEFINE_MUTEX(queue_io_mutex);
 
 struct cache_queue {
 	struct list_head	list;
@@ -561,7 +562,7 @@
 	if (count == 0)
 		return 0;
 
-	down(&queue_io_sem); /* protect against multiple concurrent
+	mutex_lock(&queue_io_mutex); /* protect against multiple concurrent
 			      * readers on this file */
  again:
 	spin_lock(&queue_lock);
@@ -574,7 +575,7 @@
 	}
 	if (rp->q.list.next == &cd->queue) {
 		spin_unlock(&queue_lock);
-		up(&queue_io_sem);
+		mutex_unlock(&queue_io_mutex);
 		BUG_ON(rp->offset);
 		return 0;
 	}
@@ -621,11 +622,11 @@
 	}
 	if (err == -EAGAIN)
 		goto again;
-	up(&queue_io_sem);
+	mutex_unlock(&queue_io_mutex);
 	return err ? err :  count;
 }
 
-static char write_buf[8192]; /* protected by queue_io_sem */
+static char write_buf[8192]; /* protected by queue_io_mutex */
 
 static ssize_t
 cache_write(struct file *filp, const char __user *buf, size_t count,
@@ -639,10 +640,10 @@
 	if (count >= sizeof(write_buf))
 		return -EINVAL;
 
-	down(&queue_io_sem);
+	mutex_lock(&queue_io_mutex);
 
 	if (copy_from_user(write_buf, buf, count)) {
-		up(&queue_io_sem);
+		mutex_unlock(&queue_io_mutex);
 		return -EFAULT;
 	}
 	write_buf[count] = '\0';
@@ -651,7 +652,7 @@
 	else
 		err = -EINVAL;
 
-	up(&queue_io_sem);
+	mutex_unlock(&queue_io_mutex);
 	return err ? err : count;
 }
 
diff -urN oldtree/net/sunrpc/clnt.c newtree/net/sunrpc/clnt.c
--- oldtree/net/sunrpc/clnt.c	2006-02-19 11:41:06.557346232 +0000
+++ newtree/net/sunrpc/clnt.c	2006-02-21 15:58:37.370465384 +0000
@@ -61,8 +61,8 @@
 static void	call_timeout(struct rpc_task *task);
 static void	call_connect(struct rpc_task *task);
 static void	call_connect_status(struct rpc_task *task);
-static u32 *	call_header(struct rpc_task *task);
-static u32 *	call_verify(struct rpc_task *task);
+static __be32 *	call_header(struct rpc_task *task);
+static __be32 *	call_verify(struct rpc_task *task);
 
 
 static int
@@ -713,7 +713,7 @@
 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 	unsigned int	bufsiz;
 	kxdrproc_t	encode;
-	u32		*p;
+	__be32		*p;
 
 	dprintk("RPC: %4d call_encode (status %d)\n", 
 				task->tk_pid, task->tk_status);
@@ -1021,7 +1021,7 @@
 	struct rpc_clnt	*clnt = task->tk_client;
 	struct rpc_rqst	*req = task->tk_rqstp;
 	kxdrproc_t	decode = task->tk_msg.rpc_proc->p_decode;
-	u32		*p;
+	__be32		*p;
 
 	dprintk("RPC: %4d call_decode (status %d)\n", 
 				task->tk_pid, task->tk_status);
@@ -1113,12 +1113,12 @@
 /*
  * Call header serialization
  */
-static u32 *
+static __be32 *
 call_header(struct rpc_task *task)
 {
 	struct rpc_clnt *clnt = task->tk_client;
 	struct rpc_rqst	*req = task->tk_rqstp;
-	u32		*p = req->rq_svec[0].iov_base;
+	__be32		*p = req->rq_svec[0].iov_base;
 
 	/* FIXME: check buffer size? */
 
@@ -1137,12 +1137,13 @@
 /*
  * Reply header verification
  */
-static u32 *
+static __be32 *
 call_verify(struct rpc_task *task)
 {
 	struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0];
 	int len = task->tk_rqstp->rq_rcv_buf.len >> 2;
-	u32	*p = iov->iov_base, n;
+	__be32	*p = iov->iov_base;
+	u32 n;
 	int error = -EACCES;
 
 	if ((len -= 3) < 0)
@@ -1208,7 +1209,7 @@
 		printk(KERN_WARNING "call_verify: auth check failed\n");
 		goto out_garbage;		/* bad verifier, retry */
 	}
-	len = p - (u32 *)iov->iov_base - 1;
+	len = p - (__be32 *)iov->iov_base - 1;
 	if (len < 0)
 		goto out_overflow;
 	switch ((n = ntohl(*p++))) {
@@ -1263,12 +1264,12 @@
 	goto out_garbage;
 }
 
-static int rpcproc_encode_null(void *rqstp, u32 *data, void *obj)
+static int rpcproc_encode_null(void *rqstp, __be32 *data, void *obj)
 {
 	return 0;
 }
 
-static int rpcproc_decode_null(void *rqstp, u32 *data, void *obj)
+static int rpcproc_decode_null(void *rqstp, __be32 *data, void *obj)
 {
 	return 0;
 }
diff -urN oldtree/net/sunrpc/pmap_clnt.c newtree/net/sunrpc/pmap_clnt.c
--- oldtree/net/sunrpc/pmap_clnt.c	2006-02-19 11:41:06.558346080 +0000
+++ newtree/net/sunrpc/pmap_clnt.c	2006-02-21 15:58:37.371465232 +0000
@@ -226,7 +226,7 @@
  * XDR encode/decode functions for PMAP
  */
 static int
-xdr_encode_mapping(struct rpc_rqst *req, u32 *p, struct rpc_portmap *map)
+xdr_encode_mapping(struct rpc_rqst *req, __be32 *p, struct rpc_portmap *map)
 {
 	dprintk("RPC: xdr_encode_mapping(%d, %d, %d, %d)\n",
 		map->pm_prog, map->pm_vers, map->pm_prot, map->pm_port);
@@ -240,14 +240,14 @@
 }
 
 static int
-xdr_decode_port(struct rpc_rqst *req, u32 *p, unsigned short *portp)
+xdr_decode_port(struct rpc_rqst *req, __be32 *p, unsigned short *portp)
 {
 	*portp = (unsigned short) ntohl(*p++);
 	return 0;
 }
 
 static int
-xdr_decode_bool(struct rpc_rqst *req, u32 *p, unsigned int *boolp)
+xdr_decode_bool(struct rpc_rqst *req, __be32 *p, unsigned int *boolp)
 {
 	*boolp = (unsigned int) ntohl(*p++);
 	return 0;
diff -urN oldtree/net/sunrpc/sched.c newtree/net/sunrpc/sched.c
--- oldtree/net/sunrpc/sched.c	2006-02-19 11:41:06.560345776 +0000
+++ newtree/net/sunrpc/sched.c	2006-02-21 15:58:30.971438184 +0000
@@ -18,6 +18,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/xprt.h>
@@ -62,7 +63,7 @@
 /*
  * rpciod-related stuff
  */
-static DECLARE_MUTEX(rpciod_sema);
+static DEFINE_MUTEX(rpciod_mutex);
 static unsigned int		rpciod_users;
 static struct workqueue_struct *rpciod_workqueue;
 
@@ -1050,7 +1051,7 @@
 	struct workqueue_struct *wq;
 	int error = 0;
 
-	down(&rpciod_sema);
+	mutex_lock(&rpciod_mutex);
 	dprintk("rpciod_up: users %d\n", rpciod_users);
 	rpciod_users++;
 	if (rpciod_workqueue)
@@ -1073,14 +1074,14 @@
 	rpciod_workqueue = wq;
 	error = 0;
 out:
-	up(&rpciod_sema);
+	mutex_unlock(&rpciod_mutex);
 	return error;
 }
 
 void
 rpciod_down(void)
 {
-	down(&rpciod_sema);
+	mutex_lock(&rpciod_mutex);
 	dprintk("rpciod_down sema %d\n", rpciod_users);
 	if (rpciod_users) {
 		if (--rpciod_users)
@@ -1097,7 +1098,7 @@
 	destroy_workqueue(rpciod_workqueue);
 	rpciod_workqueue = NULL;
  out:
-	up(&rpciod_sema);
+	mutex_unlock(&rpciod_mutex);
 }
 
 #ifdef RPC_DEBUG
@@ -1161,16 +1162,12 @@
 					     NULL, NULL);
 	if (!rpc_buffer_slabp)
 		goto err_nomem;
-	rpc_task_mempool = mempool_create(RPC_TASK_POOLSIZE,
-					    mempool_alloc_slab,
-					    mempool_free_slab,
-					    rpc_task_slabp);
+	rpc_task_mempool = mempool_create_slab_pool(RPC_TASK_POOLSIZE,
+						    rpc_task_slabp);
 	if (!rpc_task_mempool)
 		goto err_nomem;
-	rpc_buffer_mempool = mempool_create(RPC_BUFFER_POOLSIZE,
-					    mempool_alloc_slab,
-					    mempool_free_slab,
-					    rpc_buffer_slabp);
+	rpc_buffer_mempool = mempool_create_slab_pool(RPC_BUFFER_POOLSIZE,
+						      rpc_buffer_slabp);
 	if (!rpc_buffer_mempool)
 		goto err_nomem;
 	return 0;
diff -urN oldtree/net/sunrpc/svc.c newtree/net/sunrpc/svc.c
--- oldtree/net/sunrpc/svc.c	2006-02-19 11:41:06.561345624 +0000
+++ newtree/net/sunrpc/svc.c	2006-02-21 15:58:37.373464928 +0000
@@ -258,11 +258,11 @@
 	struct kvec *		argv = &rqstp->rq_arg.head[0];
 	struct kvec *		resv = &rqstp->rq_res.head[0];
 	kxdrproc_t		xdr;
-	u32			*statp;
-	u32			dir, prog, vers, proc,
-				auth_stat, rpc_stat;
+	__be32			*statp;
+	u32			dir, prog, vers, proc;
+	__be32			auth_stat, rpc_stat;
 	int			auth_res;
-	u32			*accept_statp;
+	__be32			*accept_statp;
 
 	rpc_stat = rpc_success;
 
@@ -288,11 +288,11 @@
 	rqstp->rq_xid = svc_getu32(argv);
 	svc_putu32(resv, rqstp->rq_xid);
 
-	dir  = ntohl(svc_getu32(argv));
-	vers = ntohl(svc_getu32(argv));
+	dir  = svc_getnl(argv);
+	vers = svc_getnl(argv);
 
 	/* First words of reply: */
-	svc_putu32(resv, xdr_one);		/* REPLY */
+	svc_putnl(resv, 1);		/* REPLY */
 
 	if (dir != 0)		/* direction != CALL */
 		goto err_bad_dir;
@@ -302,11 +302,11 @@
 	/* Save position in case we later decide to reject: */
 	accept_statp = resv->iov_base + resv->iov_len;
 
-	svc_putu32(resv, xdr_zero);		/* ACCEPT */
+	svc_putnl(resv, 0);		/* ACCEPT */
 
-	rqstp->rq_prog = prog = ntohl(svc_getu32(argv));	/* program number */
-	rqstp->rq_vers = vers = ntohl(svc_getu32(argv));	/* version number */
-	rqstp->rq_proc = proc = ntohl(svc_getu32(argv));	/* procedure number */
+	rqstp->rq_prog = prog = svc_getnl(argv);	/* program number */
+	rqstp->rq_vers = vers = svc_getnl(argv);	/* version number */
+	rqstp->rq_proc = proc = svc_getnl(argv);	/* procedure number */
 
 	progp = serv->sv_program;
 
@@ -360,7 +360,7 @@
 
 	/* Build the reply header. */
 	statp = resv->iov_base +resv->iov_len;
-	svc_putu32(resv, rpc_success);		/* RPC_SUCCESS */
+	svc_putnl(resv, RPC_SUCCESS);
 
 	/* Bump per-procedure stats counter */
 	procp->pc_count++;
@@ -438,10 +438,10 @@
 
 err_bad_rpc:
 	serv->sv_stats->rpcbadfmt++;
-	svc_putu32(resv, xdr_one);	/* REJECT */
-	svc_putu32(resv, xdr_zero);	/* RPC_MISMATCH */
-	svc_putu32(resv, xdr_two);	/* Only RPCv2 supported */
-	svc_putu32(resv, xdr_two);
+	svc_putnl(resv, 1);	/* REJECT */
+	svc_putnl(resv, 0);	/* RPC_MISMATCH */
+	svc_putnl(resv, 2);	/* Only RPCv2 supported */
+	svc_putnl(resv, 2);
 	goto sendit;
 
 err_bad_auth:
@@ -449,15 +449,15 @@
 	serv->sv_stats->rpcbadauth++;
 	/* Restore write pointer to location of accept status: */
 	xdr_ressize_check(rqstp, accept_statp);
-	svc_putu32(resv, xdr_one);	/* REJECT */
-	svc_putu32(resv, xdr_one);	/* AUTH_ERROR */
-	svc_putu32(resv, auth_stat);	/* status */
+	svc_putnl(resv, 1);	/* REJECT */
+	svc_putnl(resv, 1);	/* AUTH_ERROR */
+	svc_putnl(resv, ntohl(auth_stat));	/* status */
 	goto sendit;
 
 err_bad_prog:
 	dprintk("svc: unknown program %d\n", prog);
 	serv->sv_stats->rpcbadfmt++;
-	svc_putu32(resv, rpc_prog_unavail);
+	svc_putnl(resv, RPC_PROG_UNAVAIL);
 	goto sendit;
 
 err_bad_vers:
@@ -465,9 +465,9 @@
 	printk("svc: unknown version (%d)\n", vers);
 #endif
 	serv->sv_stats->rpcbadfmt++;
-	svc_putu32(resv, rpc_prog_mismatch);
-	svc_putu32(resv, htonl(progp->pg_lovers));
-	svc_putu32(resv, htonl(progp->pg_hivers));
+	svc_putnl(resv, RPC_PROG_MISMATCH);
+	svc_putnl(resv, progp->pg_lovers);
+	svc_putnl(resv, progp->pg_hivers);
 	goto sendit;
 
 err_bad_proc:
@@ -475,7 +475,7 @@
 	printk("svc: unknown procedure (%d)\n", proc);
 #endif
 	serv->sv_stats->rpcbadfmt++;
-	svc_putu32(resv, rpc_proc_unavail);
+	svc_putnl(resv, RPC_PROC_UNAVAIL);
 	goto sendit;
 
 err_garbage:
@@ -485,6 +485,6 @@
 	rpc_stat = rpc_garbage_args;
 err_bad:
 	serv->sv_stats->rpcbadfmt++;
-	svc_putu32(resv, rpc_stat);
+	svc_putnl(resv, ntohl(rpc_stat));
 	goto sendit;
 }
diff -urN oldtree/net/sunrpc/svcauth.c newtree/net/sunrpc/svcauth.c
--- oldtree/net/sunrpc/svcauth.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/sunrpc/svcauth.c	2006-02-21 15:58:37.371465232 +0000
@@ -35,14 +35,14 @@
 };
 
 int
-svc_authenticate(struct svc_rqst *rqstp, u32 *authp)
+svc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
 {
 	rpc_authflavor_t	flavor;
 	struct auth_ops		*aops;
 
 	*authp = rpc_auth_ok;
 
-	flavor = ntohl(svc_getu32(&rqstp->rq_arg.head[0]));
+	flavor = svc_getnl(&rqstp->rq_arg.head[0]);
 
 	dprintk("svc: svc_authenticate (%d)\n", flavor);
 
diff -urN oldtree/net/sunrpc/svcauth_unix.c newtree/net/sunrpc/svcauth_unix.c
--- oldtree/net/sunrpc/svcauth_unix.c	2006-02-19 11:41:06.562345472 +0000
+++ newtree/net/sunrpc/svcauth_unix.c	2006-02-21 15:58:37.372465080 +0000
@@ -141,7 +141,7 @@
 {
 	char text_addr[20];
 	struct ip_map *im = container_of(h, struct ip_map, h);
-	__u32 addr = im->m_addr.s_addr;
+	__be32 addr = im->m_addr.s_addr;
 	
 	snprintf(text_addr, 20, "%u.%u.%u.%u",
 		 ntohl(addr) >> 24 & 0xff,
@@ -243,10 +243,10 @@
 
 	seq_printf(m, "%s %d.%d.%d.%d %s\n",
 		   im->m_class,
-		   htonl(addr.s_addr) >> 24 & 0xff,
-		   htonl(addr.s_addr) >> 16 & 0xff,
-		   htonl(addr.s_addr) >>  8 & 0xff,
-		   htonl(addr.s_addr) >>  0 & 0xff,
+		   ntohl(addr.s_addr) >> 24 & 0xff,
+		   ntohl(addr.s_addr) >> 16 & 0xff,
+		   ntohl(addr.s_addr) >>  8 & 0xff,
+		   ntohl(addr.s_addr) >>  0 & 0xff,
 		   dom
 		   );
 	return 0;
@@ -369,7 +369,7 @@
 }
 
 static int
-svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp)
+svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
 {
 	struct kvec	*argv = &rqstp->rq_arg.head[0];
 	struct kvec	*resv = &rqstp->rq_res.head[0];
@@ -431,7 +431,7 @@
 
 
 static int
-svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp)
+svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
 {
 	struct kvec	*argv = &rqstp->rq_arg.head[0];
 	struct kvec	*resv = &rqstp->rq_res.head[0];
@@ -447,22 +447,22 @@
 
 	svc_getu32(argv);			/* length */
 	svc_getu32(argv);			/* time stamp */
-	slen = XDR_QUADLEN(ntohl(svc_getu32(argv)));	/* machname length */
+	slen = XDR_QUADLEN(svc_getnl(argv));	/* machname length */
 	if (slen > 64 || (len -= (slen + 3)*4) < 0)
 		goto badcred;
 	argv->iov_base = (void*)((u32*)argv->iov_base + slen);	/* skip machname */
 	argv->iov_len -= slen*4;
 
-	cred->cr_uid = ntohl(svc_getu32(argv));		/* uid */
-	cred->cr_gid = ntohl(svc_getu32(argv));		/* gid */
-	slen = ntohl(svc_getu32(argv));			/* gids length */
+	cred->cr_uid = svc_getnl(argv);		/* uid */
+	cred->cr_gid = svc_getnl(argv);		/* gid */
+	slen = svc_getnl(argv);			/* gids length */
 	if (slen > 16 || (len -= (slen + 2)*4) < 0)
 		goto badcred;
 	cred->cr_group_info = groups_alloc(slen);
 	if (cred->cr_group_info == NULL)
 		return SVC_DROP;
 	for (i = 0; i < slen; i++)
-		GROUP_AT(cred->cr_group_info, i) = ntohl(svc_getu32(argv));
+		GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv);
 
 	if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) {
 		*authp = rpc_autherr_badverf;
diff -urN oldtree/net/sunrpc/svcsock.c newtree/net/sunrpc/svcsock.c
--- oldtree/net/sunrpc/svcsock.c	2006-02-19 11:41:06.563345320 +0000
+++ newtree/net/sunrpc/svcsock.c	2006-02-21 15:58:37.374464776 +0000
@@ -1040,7 +1040,7 @@
 {
 	struct xdr_buf	*xbufp = &rqstp->rq_res;
 	int sent;
-	u32 reclen;
+	__be32 reclen;
 
 	/* Set up the first element of the reply kvec.
 	 * Any other kvecs that may be in use have been taken
@@ -1296,13 +1296,13 @@
 		xb->page_len +
 		xb->tail[0].iov_len;
 
-	/* Grab svsk->sk_sem to serialize outgoing data. */
-	down(&svsk->sk_sem);
+	/* Grab svsk->sk_mutex to serialize outgoing data. */
+	mutex_lock(&svsk->sk_mutex);
 	if (test_bit(SK_DEAD, &svsk->sk_flags))
 		len = -ENOTCONN;
 	else
 		len = svsk->sk_sendto(rqstp);
-	up(&svsk->sk_sem);
+	mutex_unlock(&svsk->sk_mutex);
 	svc_sock_release(rqstp);
 
 	if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN)
@@ -1351,7 +1351,7 @@
 	svsk->sk_lastrecv = get_seconds();
 	INIT_LIST_HEAD(&svsk->sk_deferred);
 	INIT_LIST_HEAD(&svsk->sk_ready);
-	sema_init(&svsk->sk_sem, 1);
+	mutex_init(&svsk->sk_mutex);
 
 	/* Initialize the socket */
 	if (sock->type == SOCK_DGRAM)
diff -urN oldtree/net/sunrpc/xdr.c newtree/net/sunrpc/xdr.c
--- oldtree/net/sunrpc/xdr.c	2006-02-19 11:41:06.564345168 +0000
+++ newtree/net/sunrpc/xdr.c	2006-02-21 15:58:37.375464624 +0000
@@ -18,8 +18,8 @@
 /*
  * XDR functions for basic NFS types
  */
-u32 *
-xdr_encode_netobj(u32 *p, const struct xdr_netobj *obj)
+__be32 *
+xdr_encode_netobj(__be32 *p, const struct xdr_netobj *obj)
 {
 	unsigned int	quadlen = XDR_QUADLEN(obj->len);
 
@@ -29,8 +29,8 @@
 	return p + XDR_QUADLEN(obj->len);
 }
 
-u32 *
-xdr_decode_netobj(u32 *p, struct xdr_netobj *obj)
+__be32 *
+xdr_decode_netobj(__be32 *p, struct xdr_netobj *obj)
 {
 	unsigned int	len;
 
@@ -55,7 +55,7 @@
  * Returns the updated current XDR buffer position
  *
  */
-u32 *xdr_encode_opaque_fixed(u32 *p, const void *ptr, unsigned int nbytes)
+__be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int nbytes)
 {
 	if (likely(nbytes != 0)) {
 		unsigned int quadlen = XDR_QUADLEN(nbytes);
@@ -79,21 +79,21 @@
  *
  * Returns the updated current XDR buffer position
  */
-u32 *xdr_encode_opaque(u32 *p, const void *ptr, unsigned int nbytes)
+__be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int nbytes)
 {
 	*p++ = htonl(nbytes);
 	return xdr_encode_opaque_fixed(p, ptr, nbytes);
 }
 EXPORT_SYMBOL(xdr_encode_opaque);
 
-u32 *
-xdr_encode_string(u32 *p, const char *string)
+__be32 *
+xdr_encode_string(__be32 *p, const char *string)
 {
 	return xdr_encode_array(p, string, strlen(string));
 }
 
-u32 *
-xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen)
+__be32 *
+xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen)
 {
 	unsigned int	len;
 
@@ -433,7 +433,7 @@
  *	 of the buffer length, and takes care of adjusting the kvec
  *	 length for us.
  */
-void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
+void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
 {
 	struct kvec *iov = buf->head;
 	int scratch_len = buf->buflen - buf->page_len - buf->tail[0].iov_len;
@@ -441,8 +441,8 @@
 	BUG_ON(scratch_len < 0);
 	xdr->buf = buf;
 	xdr->iov = iov;
-	xdr->p = (uint32_t *)((char *)iov->iov_base + iov->iov_len);
-	xdr->end = (uint32_t *)((char *)iov->iov_base + scratch_len);
+	xdr->p = (__be32 *)((char *)iov->iov_base + iov->iov_len);
+	xdr->end = (__be32 *)((char *)iov->iov_base + scratch_len);
 	BUG_ON(iov->iov_len > scratch_len);
 
 	if (p != xdr->p && p != NULL) {
@@ -466,10 +466,10 @@
  * bytes of data. If so, update the total xdr_buf length, and
  * adjust the length of the current kvec.
  */
-uint32_t * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes)
+__be32 * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes)
 {
-	uint32_t *p = xdr->p;
-	uint32_t *q;
+	__be32 *p = xdr->p;
+	__be32 *q;
 
 	/* align nbytes on the next 32-bit boundary */
 	nbytes += 3;
@@ -525,7 +525,7 @@
  * @buf: pointer to XDR buffer from which to decode data
  * @p: current pointer inside XDR buffer
  */
-void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
+void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
 {
 	struct kvec *iov = buf->head;
 	unsigned int len = iov->iov_len;
@@ -535,7 +535,7 @@
 	xdr->buf = buf;
 	xdr->iov = iov;
 	xdr->p = p;
-	xdr->end = (uint32_t *)((char *)iov->iov_base + len);
+	xdr->end = (__be32 *)((char *)iov->iov_base + len);
 }
 EXPORT_SYMBOL(xdr_init_decode);
 
@@ -549,10 +549,10 @@
  * If so return the current pointer, then update the current
  * pointer position.
  */
-uint32_t * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
+__be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
 {
-	uint32_t *p = xdr->p;
-	uint32_t *q = p + XDR_QUADLEN(nbytes);
+	__be32 *p = xdr->p;
+	__be32 *q = p + XDR_QUADLEN(nbytes);
 
 	if (unlikely(q > xdr->end || q < p))
 		return NULL;
@@ -601,8 +601,8 @@
 	 * Position current pointer at beginning of tail, and
 	 * set remaining message length.
 	 */
-	xdr->p = (uint32_t *)((char *)iov->iov_base + padding);
-	xdr->end = (uint32_t *)((char *)iov->iov_base + end);
+	xdr->p = (__be32 *)((char *)iov->iov_base + padding);
+	xdr->end = (__be32 *)((char *)iov->iov_base + end);
 }
 EXPORT_SYMBOL(xdr_read_pages);
 
@@ -720,7 +720,7 @@
 int
 xdr_decode_word(struct xdr_buf *buf, int base, u32 *obj)
 {
-	u32	raw;
+	__be32	raw;
 	int	status;
 
 	status = read_bytes_from_xdr_buf(buf, base, &raw, sizeof(*obj));
@@ -733,7 +733,7 @@
 int
 xdr_encode_word(struct xdr_buf *buf, int base, u32 obj)
 {
-	u32	raw = htonl(obj);
+	__be32	raw = htonl(obj);
 
 	return write_bytes_to_xdr_buf(buf, base, &raw, sizeof(obj));
 }
diff -urN oldtree/net/sunrpc/xprt.c newtree/net/sunrpc/xprt.c
--- oldtree/net/sunrpc/xprt.c	2006-02-19 11:41:06.564345168 +0000
+++ newtree/net/sunrpc/xprt.c	2006-02-21 15:58:37.376464472 +0000
@@ -598,7 +598,7 @@
  * @xid: RPC XID of incoming reply
  *
  */
-struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid)
+struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid)
 {
 	struct list_head *pos;
 	struct rpc_rqst	*req = NULL;
@@ -811,7 +811,7 @@
 	spin_unlock(&xprt->reserve_lock);
 }
 
-static inline u32 xprt_alloc_xid(struct rpc_xprt *xprt)
+static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt)
 {
 	return xprt->xid++;
 }
diff -urN oldtree/net/sunrpc/xprtsock.c newtree/net/sunrpc/xprtsock.c
--- oldtree/net/sunrpc/xprtsock.c	2006-02-19 11:41:06.565345016 +0000
+++ newtree/net/sunrpc/xprtsock.c	2006-02-21 15:58:37.377464320 +0000
@@ -483,7 +483,8 @@
 	struct rpc_rqst *rovr;
 	struct sk_buff *skb;
 	int err, repsize, copied;
-	u32 _xid, *xp;
+	u32 _xid;
+	__be32 *xp;
 
 	read_lock(&sk->sk_callback_lock);
 	dprintk("RPC:      xs_udp_data_ready...\n");
diff -urN oldtree/net/tipc/bcast.c newtree/net/tipc/bcast.c
--- oldtree/net/tipc/bcast.c	2006-02-19 11:41:06.568344560 +0000
+++ newtree/net/tipc/bcast.c	2006-02-21 15:58:16.958568464 +0000
@@ -314,7 +314,8 @@
  * Only tipc_net_lock set.
  */
 
-void tipc_bclink_peek_nack(u32 dest, u32 sender_tag, u32 gap_after, u32 gap_to)
+static void tipc_bclink_peek_nack(u32 dest, u32 sender_tag, u32 gap_after,
+				  u32 gap_to)
 {
 	struct node *n_ptr = tipc_node_find(dest);
 	u32 my_after, my_to;
@@ -525,9 +526,9 @@
  * Returns 0 if packet sent successfully, non-zero if not
  */
 
-int tipc_bcbearer_send(struct sk_buff *buf,
-		       struct tipc_bearer *unused1,
-		       struct tipc_media_addr *unused2)
+static int tipc_bcbearer_send(struct sk_buff *buf,
+			      struct tipc_bearer *unused1,
+			      struct tipc_media_addr *unused2)
 {
 	static int send_count = 0;
 
diff -urN oldtree/net/tipc/cluster.c newtree/net/tipc/cluster.c
--- oldtree/net/tipc/cluster.c	2006-02-19 11:41:06.571344104 +0000
+++ newtree/net/tipc/cluster.c	2006-02-21 15:58:16.959568312 +0000
@@ -44,9 +44,8 @@
 #include "msg.h"
 #include "bearer.h"
 
-void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf, 
-			 u32 lower, u32 upper);
-struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest);
+static void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf,
+				u32 lower, u32 upper);
 
 struct node **tipc_local_nodes = 0;
 struct node_map tipc_cltr_bcast_nodes = {0,{0,}};
@@ -229,7 +228,7 @@
  *    Routing table management: See description in node.c
  */
 
-struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest)
+static struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest)
 {
 	u32 size = INT_H_SIZE + data_size;
 	struct sk_buff *buf = buf_acquire(size);
@@ -495,8 +494,8 @@
  * tipc_cltr_multicast - multicast message to local nodes 
  */
 
-void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf, 
-			 u32 lower, u32 upper)
+static void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf,
+				u32 lower, u32 upper)
 {
 	struct sk_buff *buf_copy;
 	struct node *n_ptr;
diff -urN oldtree/net/tipc/config.c newtree/net/tipc/config.c
--- oldtree/net/tipc/config.c	2006-02-19 11:41:06.572343952 +0000
+++ newtree/net/tipc/config.c	2006-02-21 15:58:37.377464320 +0000
@@ -107,7 +107,7 @@
 struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value)
 {
 	struct sk_buff *buf;
-	u32 value_net;
+	__be32 value_net;
 
 	buf = tipc_cfg_reply_alloc(TLV_SPACE(sizeof(value)));
 	if (buf) {
@@ -284,8 +284,7 @@
 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 
-	addr = *(u32 *)TLV_DATA(req_tlv_area);
-	addr = ntohl(addr);
+	addr = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 	if (addr == tipc_own_addr)
 		return tipc_cfg_reply_none();
 	if (!tipc_addr_node_valid(addr))
@@ -310,8 +309,7 @@
 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 
-	value = *(u32 *)TLV_DATA(req_tlv_area);
-	value = ntohl(value);
+	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 	tipc_remote_management = (value != 0);
 	return tipc_cfg_reply_none();
 }
@@ -323,8 +321,7 @@
 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 
-	value = *(u32 *)TLV_DATA(req_tlv_area);
-	value = ntohl(value);
+	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 	if (value != delimit(value, 1, 65535))
 		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 						   " (max publications must be 1-65535)");
@@ -339,8 +336,7 @@
 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 
-	value = *(u32 *)TLV_DATA(req_tlv_area);
-	value = ntohl(value);
+	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 	if (value != delimit(value, 1, 65535))
 		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 						   " (max subscriptions must be 1-65535");
@@ -355,8 +351,7 @@
 
 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
-	value = *(u32 *)TLV_DATA(req_tlv_area);
-	value = ntohl(value);
+	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 	if (value != delimit(value, 127, 65535))
 		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 						   " (max ports must be 127-65535)");
@@ -403,8 +398,7 @@
 
 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
-	value = *(u32 *)TLV_DATA(req_tlv_area);
-	value = ntohl(value);
+	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 	if (value != delimit(value, 1, 255))
 		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 						   " (max zones must be 1-255)");
@@ -417,8 +411,7 @@
 
 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
-	value = *(u32 *)TLV_DATA(req_tlv_area);
-	value = ntohl(value);
+	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 	if (value != 1)
 		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
 						   " (max clusters fixed at 1)");
@@ -431,8 +424,7 @@
 
 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
-	value = *(u32 *)TLV_DATA(req_tlv_area);
-	value = ntohl(value);
+	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 	if (value != delimit(value, 8, 2047))
 		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 						   " (max nodes must be 8-2047)");
@@ -445,8 +437,7 @@
 
 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
-	value = *(u32 *)TLV_DATA(req_tlv_area);
-	value = ntohl(value);
+	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 	if (value != 0)
 		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
 						   " (max secondary nodes fixed at 0)");
@@ -459,8 +450,7 @@
 
 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
-	value = *(u32 *)TLV_DATA(req_tlv_area);
-	value = ntohl(value);
+	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 	if (value != delimit(value, 1, 9999))
 		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 						   " (network id must be 1-9999)");
diff -urN oldtree/net/tipc/dbg.c newtree/net/tipc/dbg.c
--- oldtree/net/tipc/dbg.c	2006-02-19 11:41:06.575343496 +0000
+++ newtree/net/tipc/dbg.c	2006-02-21 15:58:37.378464168 +0000
@@ -351,8 +351,7 @@
 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 
-	value = *(u32 *)TLV_DATA(req_tlv_area);
-	value = ntohl(value);
+	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 	if (value != delimit(value, 0, 32768))
 		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 						   " (log size must be 0-32768)");
diff -urN oldtree/net/tipc/discover.c newtree/net/tipc/discover.c
--- oldtree/net/tipc/discover.c	2006-02-19 11:41:06.576343344 +0000
+++ newtree/net/tipc/discover.c	2006-02-21 15:58:16.960568160 +0000
@@ -110,10 +110,10 @@
  * @b_ptr: ptr to bearer issuing message
  */
 
-struct sk_buff *tipc_disc_init_msg(u32 type,
-				   u32 req_links,
-				   u32 dest_domain,
-				   struct bearer *b_ptr)
+static struct sk_buff *tipc_disc_init_msg(u32 type,
+					  u32 req_links,
+					  u32 dest_domain,
+					  struct bearer *b_ptr)
 {
 	struct sk_buff *buf = buf_acquire(DSC_H_SIZE);
 	struct tipc_msg *msg;
diff -urN oldtree/net/tipc/name_distr.c newtree/net/tipc/name_distr.c
--- oldtree/net/tipc/name_distr.c	2006-02-19 11:41:06.585341976 +0000
+++ newtree/net/tipc/name_distr.c	2006-02-21 15:58:37.379464016 +0000
@@ -66,11 +66,11 @@
  */
 
 struct distr_item {
-	u32 type;
-	u32 lower;
-	u32 upper;
-	u32 ref;
-	u32 key;
+	__be32 type;
+	__be32 lower;
+	__be32 upper;
+	__be32 ref;
+	__be32 key;
 };
 
 /**
diff -urN oldtree/net/tipc/name_table.c newtree/net/tipc/name_table.c
--- oldtree/net/tipc/name_table.c	2006-02-19 11:41:06.587341672 +0000
+++ newtree/net/tipc/name_table.c	2006-02-21 15:58:16.964567552 +0000
@@ -46,7 +46,7 @@
 #include "cluster.h"
 #include "bcast.h"
 
-int tipc_nametbl_size = 1024;		/* must be a power of 2 */
+static int tipc_nametbl_size = 1024;	/* must be a power of 2 */
 
 /**
  * struct sub_seq - container for all published instances of a name sequence
@@ -142,7 +142,7 @@
  * tipc_subseq_alloc - allocate a specified number of sub-sequence structures
  */
 
-struct sub_seq *tipc_subseq_alloc(u32 cnt)
+static struct sub_seq *tipc_subseq_alloc(u32 cnt)
 {
 	u32 sz = cnt * sizeof(struct sub_seq);
 	struct sub_seq *sseq = (struct sub_seq *)kmalloc(sz, GFP_ATOMIC);
@@ -158,7 +158,8 @@
  * Allocates a single sub-sequence structure and sets it to all 0's.
  */
 
-struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_head)
+static struct name_seq *tipc_nameseq_create(u32 type,
+					    struct hlist_head *seq_head)
 {
 	struct name_seq *nseq = 
 		(struct name_seq *)kmalloc(sizeof(*nseq), GFP_ATOMIC);
@@ -243,9 +244,11 @@
  * tipc_nameseq_insert_publ - 
  */
 
-struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
-					u32 type, u32 lower, u32 upper,
-					u32 scope, u32 node, u32 port, u32 key)
+static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
+						    u32 type, u32 lower,
+						    u32 upper,
+						    u32 scope, u32 node,
+						    u32 port, u32 key)
 {
 	struct subscription *s;
 	struct subscription *st;
@@ -369,8 +372,9 @@
  * tipc_nameseq_remove_publ -
  */
 
-struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst,
-					     u32 node, u32 ref, u32 key)
+static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq,
+						    u32 inst, u32 node,
+						    u32 ref, u32 key)
 {
 	struct publication *publ;
 	struct publication *prev;
@@ -487,7 +491,8 @@
  * sequence overlapping with the requested sequence
  */
 
-void tipc_nameseq_subscribe(struct name_seq *nseq, struct subscription *s)
+static void tipc_nameseq_subscribe(struct name_seq *nseq,
+				   struct subscription *s)
 {
 	struct sub_seq *sseq = nseq->sseqs;
 
@@ -983,6 +988,7 @@
 	}
 }
 
+#if 0
 void tipc_nametbl_print(struct print_buf *buf, const char *str)
 {
 	tipc_printf(buf, str);
@@ -990,6 +996,7 @@
 	nametbl_list(buf, 0, 0, 0, 0);
 	read_unlock_bh(&tipc_nametbl_lock);
 }
+#endif  /*  0  */
 
 #define MAX_NAME_TBL_QUERY 32768
 
@@ -1023,10 +1030,12 @@
 	return buf;
 }
 
+#if 0
 void tipc_nametbl_dump(void)
 {
 	nametbl_list(TIPC_CONS, 0, 0, 0, 0);
 }
+#endif  /*  0  */
 
 int tipc_nametbl_init(void)
 {
diff -urN oldtree/net/tipc/net.c newtree/net/tipc/net.c
--- oldtree/net/tipc/net.c	2006-02-19 11:41:06.588341520 +0000
+++ newtree/net/tipc/net.c	2006-02-21 15:58:16.965567400 +0000
@@ -128,13 +128,14 @@
 	return tipc_zone_select_router(tipc_net.zones[tipc_zone(addr)], addr, ref);
 }
 
-
+#if 0
 u32 tipc_net_next_node(u32 a)
 {
 	if (tipc_net.zones[tipc_zone(a)])
 		return tipc_zone_next_node(a);
 	return 0;
 }
+#endif  /*  0  */
 
 void tipc_net_remove_as_router(u32 router)
 {
diff -urN oldtree/net/tipc/node.c newtree/net/tipc/node.c
--- oldtree/net/tipc/node.c	2006-02-19 11:41:06.590341216 +0000
+++ newtree/net/tipc/node.c	2006-02-21 15:58:37.379464016 +0000
@@ -214,7 +214,7 @@
 		(n_ptr->active_links[0] != n_ptr->active_links[1]));
 }
 
-int tipc_node_has_active_routes(struct node *n_ptr)
+static int tipc_node_has_active_routes(struct node *n_ptr)
 {
 	return (n_ptr && (n_ptr->last_router >= 0));
 }
@@ -590,8 +590,7 @@
 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 
-	domain = *(u32 *)TLV_DATA(req_tlv_area);
-	domain = ntohl(domain);
+	domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 	if (!tipc_addr_domain_valid(domain))
 		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 						   " (network address)");
@@ -631,8 +630,7 @@
 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 
-	domain = *(u32 *)TLV_DATA(req_tlv_area);
-	domain = ntohl(domain);
+	domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 	if (!tipc_addr_domain_valid(domain))
 		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 						   " (network address)");
@@ -650,8 +648,7 @@
 
 	/* Add TLV for broadcast link */
 
-        link_info.dest = tipc_own_addr & 0xfffff00;
-	link_info.dest = htonl(link_info.dest);
+        link_info.dest = htonl(tipc_own_addr & 0xfffff00);
         link_info.up = htonl(1);
         sprintf(link_info.str, tipc_bclink_name);
 	tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info));
diff -urN oldtree/net/unix/af_unix.c newtree/net/unix/af_unix.c
--- oldtree/net/unix/af_unix.c	2006-02-19 11:41:06.601339544 +0000
+++ newtree/net/unix/af_unix.c	2006-02-21 15:58:16.823588984 +0000
@@ -566,7 +566,7 @@
 	u->mnt	  = NULL;
 	spin_lock_init(&u->lock);
 	atomic_set(&u->inflight, sock ? 0 : -1);
-	init_MUTEX(&u->readsem); /* single task reading lock */
+	mutex_init(&u->readlock); /* single task reading lock */
 	init_waitqueue_head(&u->peer_wait);
 	unix_insert_socket(unix_sockets_unbound, sk);
 out:
@@ -623,7 +623,7 @@
 	struct unix_address * addr;
 	int err;
 
-	down(&u->readsem);
+	mutex_lock(&u->readlock);
 
 	err = 0;
 	if (u->addr)
@@ -661,7 +661,7 @@
 	spin_unlock(&unix_table_lock);
 	err = 0;
 
-out:	up(&u->readsem);
+out:	mutex_unlock(&u->readlock);
 	return err;
 }
 
@@ -744,7 +744,7 @@
 		goto out;
 	addr_len = err;
 
-	down(&u->readsem);
+	mutex_lock(&u->readlock);
 
 	err = -EINVAL;
 	if (u->addr)
@@ -816,7 +816,7 @@
 out_unlock:
 	spin_unlock(&unix_table_lock);
 out_up:
-	up(&u->readsem);
+	mutex_unlock(&u->readlock);
 out:
 	return err;
 
@@ -1545,7 +1545,7 @@
 
 	msg->msg_namelen = 0;
 
-	down(&u->readsem);
+	mutex_lock(&u->readlock);
 
 	skb = skb_recv_datagram(sk, flags, noblock, &err);
 	if (!skb)
@@ -1600,7 +1600,7 @@
 out_free:
 	skb_free_datagram(sk,skb);
 out_unlock:
-	up(&u->readsem);
+	mutex_unlock(&u->readlock);
 out:
 	return err;
 }
@@ -1676,7 +1676,7 @@
 		memset(&tmp_scm, 0, sizeof(tmp_scm));
 	}
 
-	down(&u->readsem);
+	mutex_lock(&u->readlock);
 
 	do
 	{
@@ -1700,7 +1700,7 @@
 			err = -EAGAIN;
 			if (!timeo)
 				break;
-			up(&u->readsem);
+			mutex_unlock(&u->readlock);
 
 			timeo = unix_stream_data_wait(sk, timeo);
 
@@ -1708,7 +1708,7 @@
 				err = sock_intr_errno(timeo);
 				goto out;
 			}
-			down(&u->readsem);
+			mutex_lock(&u->readlock);
 			continue;
 		}
 
@@ -1774,7 +1774,7 @@
 		}
 	} while (size);
 
-	up(&u->readsem);
+	mutex_unlock(&u->readlock);
 	scm_recv(sock, msg, siocb->scm, flags);
 out:
 	return copied ? : err;
diff -urN oldtree/net/unix/garbage.c newtree/net/unix/garbage.c
--- oldtree/net/unix/garbage.c	2006-02-19 11:41:06.602339392 +0000
+++ newtree/net/unix/garbage.c	2006-02-21 15:58:16.658614064 +0000
@@ -76,6 +76,7 @@
 #include <linux/netdevice.h>
 #include <linux/file.h>
 #include <linux/proc_fs.h>
+#include <linux/mutex.h>
 
 #include <net/sock.h>
 #include <net/af_unix.h>
@@ -169,7 +170,7 @@
 
 void unix_gc(void)
 {
-	static DECLARE_MUTEX(unix_gc_sem);
+	static DEFINE_MUTEX(unix_gc_sem);
 	int i;
 	struct sock *s;
 	struct sk_buff_head hitlist;
@@ -179,7 +180,7 @@
 	 *	Avoid a recursive GC.
 	 */
 
-	if (down_trylock(&unix_gc_sem))
+	if (!mutex_trylock(&unix_gc_sem))
 		return;
 
 	spin_lock(&unix_table_lock);
@@ -308,5 +309,5 @@
 	 */
 
 	__skb_queue_purge(&hitlist);
-	up(&unix_gc_sem);
+	mutex_unlock(&unix_gc_sem);
 }
diff -urN oldtree/net/xfrm/xfrm_input.c newtree/net/xfrm/xfrm_input.c
--- oldtree/net/xfrm/xfrm_input.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/net/xfrm/xfrm_input.c	2006-02-21 15:58:37.385463104 +0000
@@ -46,7 +46,7 @@
 
 /* Fetch spi and seq from ipsec header */
 
-int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
+int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
 {
 	int offset, offset_seq;
 
@@ -62,7 +62,7 @@
 	case IPPROTO_COMP:
 		if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr)))
 			return -EINVAL;
-		*spi = ntohl(ntohs(*(u16*)(skb->h.raw + 2)));
+		*spi = htonl(ntohs(*(__be16*)(skb->h.raw + 2)));
 		*seq = 0;
 		return 0;
 	default:
@@ -72,8 +72,8 @@
 	if (!pskb_may_pull(skb, 16))
 		return -EINVAL;
 
-	*spi = *(u32*)(skb->h.raw + offset);
-	*seq = *(u32*)(skb->h.raw + offset_seq);
+	*spi = *(__be32*)(skb->h.raw + offset);
+	*seq = *(__be32*)(skb->h.raw + offset_seq);
 	return 0;
 }
 EXPORT_SYMBOL(xfrm_parse_spi);
diff -urN oldtree/net/xfrm/xfrm_policy.c newtree/net/xfrm/xfrm_policy.c
--- oldtree/net/xfrm/xfrm_policy.c	2006-02-19 11:41:06.606338784 +0000
+++ newtree/net/xfrm/xfrm_policy.c	2006-02-21 15:58:16.658614064 +0000
@@ -26,8 +26,8 @@
 #include <net/xfrm.h>
 #include <net/ip.h>
 
-DECLARE_MUTEX(xfrm_cfg_sem);
-EXPORT_SYMBOL(xfrm_cfg_sem);
+DEFINE_MUTEX(xfrm_cfg_mutex);
+EXPORT_SYMBOL(xfrm_cfg_mutex);
 
 static DEFINE_RWLOCK(xfrm_policy_lock);
 
@@ -203,7 +203,7 @@
 	}
 
 	if (warn)
-		km_policy_expired(xp, dir, 0);
+		km_policy_expired(xp, dir, 0, 0);
 	if (next != LONG_MAX &&
 	    !mod_timer(&xp->timer, jiffies + make_jiffies(next)))
 		xfrm_pol_hold(xp);
@@ -216,7 +216,7 @@
 expired:
 	read_unlock(&xp->lock);
 	if (!xfrm_policy_delete(xp, dir))
-		km_policy_expired(xp, dir, 1);
+		km_policy_expired(xp, dir, 1, 0);
 	xfrm_pol_put(xp);
 }
 
@@ -621,6 +621,7 @@
 	}
 	return -ENOENT;
 }
+EXPORT_SYMBOL(xfrm_policy_delete);
 
 int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
 {
diff -urN oldtree/net/xfrm/xfrm_state.c newtree/net/xfrm/xfrm_state.c
--- oldtree/net/xfrm/xfrm_state.c	2006-02-19 11:41:06.607338632 +0000
+++ newtree/net/xfrm/xfrm_state.c	2006-02-21 15:58:37.386462952 +0000
@@ -20,6 +20,15 @@
 #include <linux/module.h>
 #include <asm/uaccess.h>
 
+struct sock *xfrm_nl;
+EXPORT_SYMBOL(xfrm_nl);
+
+u32 sysctl_xfrm_aevent_etime = XFRM_AE_ETIME;
+EXPORT_SYMBOL(sysctl_xfrm_aevent_etime);
+
+u32 sysctl_xfrm_aevent_rseqth = XFRM_AE_SEQT_SIZE;
+EXPORT_SYMBOL(sysctl_xfrm_aevent_rseqth);
+
 /* Each xfrm_state may be linked to two tables:
 
    1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl)
@@ -50,18 +59,20 @@
 
 static int xfrm_state_gc_flush_bundles;
 
-static int __xfrm_state_delete(struct xfrm_state *x);
+int __xfrm_state_delete(struct xfrm_state *x);
 
 static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family);
 static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
 
-static int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
-static void km_state_expired(struct xfrm_state *x, int hard);
+int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
+void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
 
 static void xfrm_state_gc_destroy(struct xfrm_state *x)
 {
 	if (del_timer(&x->timer))
 		BUG();
+	if (del_timer(&x->rtimer))
+		BUG();
 	kfree(x->aalg);
 	kfree(x->ealg);
 	kfree(x->calg);
@@ -153,7 +164,7 @@
 
 	x->km.dying = warn;
 	if (warn)
-		km_state_expired(x, 0);
+		km_state_expired(x, 0, 0);
 resched:
 	if (next != LONG_MAX &&
 	    !mod_timer(&x->timer, jiffies + make_jiffies(next)))
@@ -168,13 +179,15 @@
 		goto resched;
 	}
 	if (!__xfrm_state_delete(x) && x->id.spi)
-		km_state_expired(x, 1);
+		km_state_expired(x, 1, 0);
 
 out:
 	spin_unlock(&x->lock);
 	xfrm_state_put(x);
 }
 
+static void xfrm_replay_timer_handler(unsigned long data);
+
 struct xfrm_state *xfrm_state_alloc(void)
 {
 	struct xfrm_state *x;
@@ -190,11 +203,16 @@
 		init_timer(&x->timer);
 		x->timer.function = xfrm_timer_handler;
 		x->timer.data	  = (unsigned long)x;
+		init_timer(&x->rtimer);
+		x->rtimer.function = xfrm_replay_timer_handler;
+		x->rtimer.data     = (unsigned long)x;
 		x->curlft.add_time = (unsigned long)xtime.tv_sec;
 		x->lft.soft_byte_limit = XFRM_INF;
 		x->lft.soft_packet_limit = XFRM_INF;
 		x->lft.hard_byte_limit = XFRM_INF;
 		x->lft.hard_packet_limit = XFRM_INF;
+		x->replay_maxage = 0;
+		x->replay_maxdiff = 0;
 		spin_lock_init(&x->lock);
 	}
 	return x;
@@ -212,7 +230,7 @@
 }
 EXPORT_SYMBOL(__xfrm_state_destroy);
 
-static int __xfrm_state_delete(struct xfrm_state *x)
+int __xfrm_state_delete(struct xfrm_state *x)
 {
 	int err = -ESRCH;
 
@@ -228,6 +246,8 @@
 		spin_unlock(&xfrm_state_lock);
 		if (del_timer(&x->timer))
 			atomic_dec(&x->refcnt);
+		if (del_timer(&x->rtimer))
+			atomic_dec(&x->refcnt);
 
 		/* The number two in this test is the reference
 		 * mentioned in the comment below plus the reference
@@ -249,6 +269,7 @@
 
 	return err;
 }
+EXPORT_SYMBOL(__xfrm_state_delete);
 
 int xfrm_state_delete(struct xfrm_state *x)
 {
@@ -426,6 +447,10 @@
 	if (!mod_timer(&x->timer, jiffies + HZ))
 		xfrm_state_hold(x);
 
+	if (x->replay_maxage &&
+	    !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
+		xfrm_state_hold(x);
+
 	wake_up(&km_waitq);
 }
 
@@ -580,7 +605,7 @@
 	    (x->curlft.bytes >= x->lft.soft_byte_limit ||
 	     x->curlft.packets >= x->lft.soft_packet_limit)) {
 		x->km.dying = 1;
-		km_state_expired(x, 0);
+		km_state_expired(x, 0, 0);
 	}
 	return 0;
 }
@@ -610,7 +635,7 @@
 EXPORT_SYMBOL(xfrm_state_check);
 
 struct xfrm_state *
-xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto,
+xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto,
 		  unsigned short family)
 {
 	struct xfrm_state *x;
@@ -687,7 +712,7 @@
 EXPORT_SYMBOL(xfrm_get_acqseq);
 
 void
-xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi)
+xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi)
 {
 	u32 h;
 	struct xfrm_state *x0;
@@ -704,10 +729,10 @@
 		x->id.spi = minspi;
 	} else {
 		u32 spi = 0;
-		minspi = ntohl(minspi);
-		maxspi = ntohl(maxspi);
-		for (h=0; h<maxspi-minspi+1; h++) {
-			spi = minspi + net_random()%(maxspi-minspi+1);
+		u32 low = ntohl(minspi);
+		u32 high = ntohl(maxspi);
+		for (h=0; h<high-low+1; h++) {
+			spi = low + net_random()%(high-low+1);
 			x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);
 			if (x0 == NULL) {
 				x->id.spi = htonl(spi);
@@ -762,11 +787,65 @@
 }
 EXPORT_SYMBOL(xfrm_state_walk);
 
-int xfrm_replay_check(struct xfrm_state *x, u32 seq)
+
+void xfrm_replay_notify(struct xfrm_state *x, int event)
 {
-	u32 diff;
+	struct km_event c;
+	/* we send notify messages in case
+	 *  1. we updated on of the sequence numbers, and the seqno difference
+	 *     is at least x->replay_maxdiff, in this case we also update the
+	 *     timeout of our timer function
+	 *  2. if x->replay_maxage has elapsed since last update,
+	 *     and there were changes
+	 *
+	 *  The state structure must be locked!
+	 */
+
+	switch (event) {
+	case XFRM_REPLAY_UPDATE:
+		if (x->replay_maxdiff &&
+		    (x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
+		    (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff))
+			return;
 
-	seq = ntohl(seq);
+		break;
+
+	case XFRM_REPLAY_TIMEOUT:
+		if ((x->replay.seq == x->preplay.seq) &&
+		    (x->replay.bitmap == x->preplay.bitmap) &&
+		    (x->replay.oseq == x->preplay.oseq))
+			return;
+
+		break;
+	}
+
+	memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
+	c.event = XFRM_MSG_NEWAE; 
+	c.data.aevent = event;
+	km_state_notify(x, &c);
+
+	if (x->replay_maxage && 
+	    !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
+		xfrm_state_hold(x);
+}
+EXPORT_SYMBOL(xfrm_replay_notify);
+
+static void xfrm_replay_timer_handler(unsigned long data)
+{
+	struct xfrm_state *x = (struct xfrm_state*)data;
+
+	spin_lock(&x->lock);
+
+	if (xfrm_aevent_is_on() && x->km.state == XFRM_STATE_VALID)
+		xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT);
+
+	spin_unlock(&x->lock);
+}
+
+int xfrm_replay_check(struct xfrm_state *x, __be32 net_seq)
+{
+	u32 diff;
+	u32 seq = ntohl(net_seq);
 
 	if (unlikely(seq == 0))
 		return -EINVAL;
@@ -788,11 +867,10 @@
 }
 EXPORT_SYMBOL(xfrm_replay_check);
 
-void xfrm_replay_advance(struct xfrm_state *x, u32 seq)
+void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
 {
 	u32 diff;
-
-	seq = ntohl(seq);
+	u32 seq = ntohl(net_seq);
 
 	if (seq > x->replay.seq) {
 		diff = seq - x->replay.seq;
@@ -805,6 +883,9 @@
 		diff = x->replay.seq - seq;
 		x->replay.bitmap |= (1U << diff);
 	}
+
+	if (xfrm_aevent_is_on())
+		xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
 }
 EXPORT_SYMBOL(xfrm_replay_advance);
 
@@ -835,11 +916,12 @@
 EXPORT_SYMBOL(km_policy_notify);
 EXPORT_SYMBOL(km_state_notify);
 
-static void km_state_expired(struct xfrm_state *x, int hard)
+void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
 {
 	struct km_event c;
 
 	c.data.hard = hard;
+	c.pid = pid;
 	c.event = XFRM_MSG_EXPIRE;
 	km_state_notify(x, &c);
 
@@ -847,11 +929,12 @@
 		wake_up(&km_waitq);
 }
 
+EXPORT_SYMBOL(km_state_expired);
 /*
  * We send to all registered managers regardless of failure
  * We are happy with one success
 */
-static int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
+int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
 {
 	int err = -EINVAL, acqret;
 	struct xfrm_mgr *km;
@@ -865,6 +948,7 @@
 	read_unlock(&xfrm_km_lock);
 	return err;
 }
+EXPORT_SYMBOL(km_query);
 
 int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport)
 {
@@ -883,17 +967,19 @@
 }
 EXPORT_SYMBOL(km_new_mapping);
 
-void km_policy_expired(struct xfrm_policy *pol, int dir, int hard)
+void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
 {
 	struct km_event c;
 
 	c.data.hard = hard;
+	c.pid = pid;
 	c.event = XFRM_MSG_POLEXPIRE;
 	km_policy_notify(pol, dir, &c);
 
 	if (hard)
 		wake_up(&km_waitq);
 }
+EXPORT_SYMBOL(km_policy_expired);
 
 int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
 {
diff -urN oldtree/net/xfrm/xfrm_user.c newtree/net/xfrm/xfrm_user.c
--- oldtree/net/xfrm/xfrm_user.c	2006-02-19 11:41:06.608338480 +0000
+++ newtree/net/xfrm/xfrm_user.c	2006-02-21 15:58:16.659613912 +0000
@@ -28,8 +28,6 @@
 #include <net/netlink.h>
 #include <asm/uaccess.h>
 
-static struct sock *xfrm_nl;
-
 static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type)
 {
 	struct rtattr *rt = xfrma[type - 1];
@@ -276,6 +274,56 @@
 	x->props.flags = p->flags;
 }
 
+/* 
+ * someday when pfkey also has support, we could have the code
+ * somehow made shareable and move it to xfrm_state.c - JHS
+ *
+*/
+static int xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **xfrma)
+{
+	int err = - EINVAL;
+	struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1];
+	struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1];
+	struct rtattr *et = xfrma[XFRMA_ETIMER_THRESH-1];
+	struct rtattr *rt = xfrma[XFRMA_REPLAY_THRESH-1];
+
+	if (rp) {
+		struct xfrm_replay_state *replay;
+		if (RTA_PAYLOAD(rp) < sizeof(*replay))
+			goto error;
+		replay = RTA_DATA(rp);
+		memcpy(&x->replay, replay, sizeof(*replay));
+		memcpy(&x->preplay, replay, sizeof(*replay));
+	}
+
+	if (lt) {
+		struct xfrm_lifetime_cur *ltime;
+		if (RTA_PAYLOAD(lt) < sizeof(*ltime))
+			goto error;
+		ltime = RTA_DATA(lt);
+		x->curlft.bytes = ltime->bytes;
+		x->curlft.packets = ltime->packets;
+		x->curlft.add_time = ltime->add_time;
+		x->curlft.use_time = ltime->use_time;
+	}
+
+	if (et) {
+		if (RTA_PAYLOAD(et) < sizeof(u32))
+			goto error;
+		x->replay_maxage = *(u32*)RTA_DATA(et);
+	}
+
+	if (rt) {
+		if (RTA_PAYLOAD(rt) < sizeof(u32))
+			goto error;
+		x->replay_maxdiff = *(u32*)RTA_DATA(rt);
+	}
+
+	return 0;
+error:
+	return err;
+}
+
 static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p,
 					       struct rtattr **xfrma,
 					       int *errp)
@@ -311,6 +359,18 @@
 		goto error;
 
 	x->km.seq = p->seq;
+	x->replay_maxdiff = sysctl_xfrm_aevent_rseqth;
+	/* sysctl_xfrm_aevent_etime is in 100ms units */
+	x->replay_maxage = (sysctl_xfrm_aevent_etime*HZ)/XFRM_AE_ETH_M;
+	x->preplay.bitmap = 0;
+	x->preplay.seq = x->replay.seq+x->replay_maxdiff;
+	x->preplay.oseq = x->replay.oseq +x->replay_maxdiff;
+
+	/* override default values from above */
+
+	err = xfrm_update_ae_params(x, (struct rtattr **)xfrma);
+	if (err	< 0)
+		goto error;
 
 	return x;
 
@@ -1025,9 +1085,142 @@
 	return 0;
 }
 
-static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+
+static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c)
+{
+	struct xfrm_aevent_id *id;
+	struct nlmsghdr *nlh;
+	struct xfrm_lifetime_cur ltime;
+	unsigned char *b = skb->tail;
+
+	nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id));
+	id = NLMSG_DATA(nlh);
+	nlh->nlmsg_flags = 0;
+
+	id->sa_id.daddr = x->id.daddr;
+	id->sa_id.spi = x->id.spi;
+	id->sa_id.family = x->props.family;
+	id->sa_id.proto = x->id.proto;
+	id->flags = c->data.aevent;
+
+	RTA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay);
+
+	ltime.bytes = x->curlft.bytes; 
+	ltime.packets = x->curlft.packets;
+	ltime.add_time = x->curlft.add_time;
+	ltime.use_time = x->curlft.use_time;
+
+	RTA_PUT(skb, XFRMA_LTIME_VAL, sizeof(struct xfrm_lifetime_cur), &ltime);
+
+	if (id->flags&XFRM_AE_RTHR) {
+		RTA_PUT(skb,XFRMA_REPLAY_THRESH,sizeof(u32),&x->replay_maxdiff);
+	}
+
+	if (id->flags&XFRM_AE_ETHR) {
+		u32 etimer = x->replay_maxage*10/HZ;
+		RTA_PUT(skb,XFRMA_ETIMER_THRESH,sizeof(u32),&etimer);
+	}
+
+	nlh->nlmsg_len = skb->tail - b;
+	return skb->len;
+
+rtattr_failure:
+nlmsg_failure:
+	skb_trim(skb, b - skb->data);
+	return -1;
+}
+
+static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
 {
+	struct xfrm_state *x;
+	struct sk_buff *r_skb;
+	int err;
 	struct km_event c;
+	struct xfrm_aevent_id *p = NLMSG_DATA(nlh);
+	int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id));
+	struct xfrm_usersa_id *id = &p->sa_id;
+
+	len += RTA_SPACE(sizeof(struct xfrm_replay_state));
+	len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur));
+
+	if (p->flags&XFRM_AE_RTHR)
+		len+=RTA_SPACE(sizeof(u32));
+
+	if (p->flags&XFRM_AE_ETHR) 
+		len+=RTA_SPACE(sizeof(u32));
+
+	r_skb = alloc_skb(len, GFP_ATOMIC);
+	if (r_skb == NULL) 
+		return -ENOMEM;
+
+	x = xfrm_state_lookup(&id->daddr, id->spi, id->proto, id->family);
+	if (x == NULL) {
+		kfree(r_skb);
+		return -ESRCH;
+	}
+
+	/* 
+	 * XXX: is this lock really needed - none of the other
+	 * gets lock (the concern is things getting updated
+	 * while we are still reading) - jhs
+	*/
+	spin_lock_bh(&x->lock);
+	c.data.aevent = p->flags;
+	c.seq = nlh->nlmsg_seq;
+	c.pid = nlh->nlmsg_pid;
+
+	if (build_aevent(r_skb, x, &c) < 0)
+		BUG();
+	err = netlink_unicast(xfrm_nl, r_skb,
+			      NETLINK_CB(skb).pid, MSG_DONTWAIT);
+	spin_unlock_bh(&x->lock);
+	xfrm_state_put(x);
+	return err;
+}
+
+static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+{
+	struct xfrm_state *x;
+	struct km_event c;
+	int err = - EINVAL;
+	struct xfrm_aevent_id *p = NLMSG_DATA(nlh);
+	struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1];
+	struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1];
+
+	if (!lt && !rp)
+		return err;
+
+	/* pedantic mode - thou shalt sayeth replaceth */
+	if (!(nlh->nlmsg_flags&NLM_F_REPLACE))
+		return err;
+
+	x = xfrm_state_lookup(&p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family);
+	if (x == NULL)
+		return -ESRCH;
+
+	if (x->km.state != XFRM_STATE_VALID)
+		goto out;
+
+	spin_lock_bh(&x->lock);
+	err = xfrm_update_ae_params(x,(struct rtattr **)xfrma);
+	spin_unlock_bh(&x->lock);
+	if (err	< 0) 
+		goto out;
+
+	c.event = nlh->nlmsg_type;
+	c.seq = nlh->nlmsg_seq;
+	c.pid = nlh->nlmsg_pid;
+	c.data.aevent = XFRM_AE_CU;
+	km_state_notify(x, &c);
+	err = 0;
+out:
+	xfrm_state_put(x);
+	return err;
+}
+
+static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+{
+struct km_event c;
 
 	xfrm_policy_flush();
 	c.event = nlh->nlmsg_type;
@@ -1037,6 +1230,139 @@
 	return 0;
 }
 
+static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+{
+	struct xfrm_policy *xp;
+	struct xfrm_user_polexpire *up = NLMSG_DATA(nlh);
+	struct xfrm_userpolicy_info *p = &up->pol;
+	int err = -ENOENT;
+
+	if (p->index)
+		xp = xfrm_policy_byid(p->dir, p->index, 0);
+	else {
+		struct rtattr **rtattrs = (struct rtattr **)xfrma;
+		struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1];
+		struct xfrm_policy tmp;
+
+		err = verify_sec_ctx_len(rtattrs);
+		if (err)
+			return err;
+
+		memset(&tmp, 0, sizeof(struct xfrm_policy));
+		if (rt) {
+			struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt);
+
+			if ((err = security_xfrm_policy_alloc(&tmp, uctx)))
+				return err;
+		}
+		xp = xfrm_policy_bysel_ctx(p->dir, &p->sel, tmp.security, 0);
+		security_xfrm_policy_free(&tmp);
+	}
+
+	if (xp == NULL)
+		return err;
+											read_lock(&xp->lock);
+	if (xp->dead) {
+		read_unlock(&xp->lock);
+		goto out;
+	}
+
+	read_unlock(&xp->lock);
+	err = 0;
+	if (up->hard) {
+		xfrm_policy_delete(xp, p->dir);
+	} else {
+		// reset the timers here?
+		printk("Dont know what to do with soft policy expire\n");
+	}
+	km_policy_expired(xp, p->dir, up->hard, current->pid);
+
+out:
+	xfrm_pol_put(xp);
+	return err;
+}
+
+static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+{
+	struct xfrm_state *x;
+	int err;
+	struct xfrm_user_expire *ue = NLMSG_DATA(nlh);
+	struct xfrm_usersa_info *p = &ue->state;
+
+	x = xfrm_state_lookup(&p->id.daddr, p->id.spi, p->id.proto, p->family);
+		err = -ENOENT;
+
+	if (x == NULL)
+		return err;
+
+	err = -EINVAL;
+
+	spin_lock_bh(&x->lock);
+	if (x->km.state != XFRM_STATE_VALID)
+		goto out;
+	km_state_expired(x, ue->hard, current->pid);
+
+	if (ue->hard) 
+		__xfrm_state_delete(x);
+out:
+	spin_unlock_bh(&x->lock);
+	xfrm_state_put(x);
+	return err;
+}
+
+static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+{
+	struct xfrm_policy *xp;
+	struct xfrm_user_tmpl *ut;
+	int i;
+	struct rtattr *rt = xfrma[XFRMA_TMPL-1];
+
+	struct xfrm_user_acquire *ua = NLMSG_DATA(nlh);
+	struct xfrm_state *x = xfrm_state_alloc();
+	int err = -ENOMEM;
+
+	if (!x)
+		return err;
+
+	err = verify_newpolicy_info(&ua->policy);
+	if (err) {
+		printk("BAD policy passed\n");
+		kfree(x);
+		return err;
+	}
+
+	/*   build an XP */
+	xp = xfrm_policy_construct(&ua->policy, (struct rtattr **) xfrma, &err);        if (!xp) {
+		kfree(x);
+		return err;
+	}
+
+	memcpy(&x->id, &ua->id, sizeof(ua->id));
+	memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr));
+	memcpy(&x->sel, &ua->sel, sizeof(ua->sel));
+
+	ut = RTA_DATA(rt);
+	/* extract the templates and for each call km_key */
+	for (i = 0; i < xp->xfrm_nr; i++, ut++) {
+		struct xfrm_tmpl *t = &xp->xfrm_vec[i];
+		memcpy(&x->id, &t->id, sizeof(x->id));
+		x->props.mode = t->mode;
+		x->props.reqid = t->reqid;
+		x->props.family = ut->family;
+		t->aalgos = ua->aalgos;
+		t->ealgos = ua->ealgos;
+		t->calgos = ua->calgos;
+		err = km_query(x, t, xp);
+
+	}
+
+	kfree(x);
+	kfree(xp);
+	
+	return 0;
+}
+
+
 #define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type))
 
 static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
@@ -1054,6 +1380,8 @@
 	[XFRM_MSG_POLEXPIRE   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire),
 	[XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush),
 	[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0),
+	[XFRM_MSG_NEWAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
+	[XFRM_MSG_GETAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
 };
 
 #undef XMSGSIZE
@@ -1071,10 +1399,15 @@
 	[XFRM_MSG_GETPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_get_policy,
 						   .dump = xfrm_dump_policy   },
 	[XFRM_MSG_ALLOCSPI    - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi },
+	[XFRM_MSG_ACQUIRE     - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire   },
+	[XFRM_MSG_EXPIRE      - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire },
 	[XFRM_MSG_UPDPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_add_policy    },
 	[XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = { .doit = xfrm_add_sa        },
+	[XFRM_MSG_POLEXPIRE   - XFRM_MSG_BASE] = { .doit = xfrm_add_pol_expire},
 	[XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa      },
 	[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy  },
+	[XFRM_MSG_NEWAE       - XFRM_MSG_BASE] = { .doit = xfrm_new_ae  },
+	[XFRM_MSG_GETAE       - XFRM_MSG_BASE] = { .doit = xfrm_get_ae  },
 };
 
 static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
@@ -1156,26 +1489,26 @@
 	unsigned int qlen = 0;
 
 	do {
-		down(&xfrm_cfg_sem);
+		mutex_lock(&xfrm_cfg_mutex);
 		netlink_run_queue(sk, &qlen, &xfrm_user_rcv_msg);
-		up(&xfrm_cfg_sem);
+		mutex_unlock(&xfrm_cfg_mutex);
 
 	} while (qlen);
 }
 
-static int build_expire(struct sk_buff *skb, struct xfrm_state *x, int hard)
+static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c)
 {
 	struct xfrm_user_expire *ue;
 	struct nlmsghdr *nlh;
 	unsigned char *b = skb->tail;
 
-	nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_EXPIRE,
+	nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_EXPIRE,
 			sizeof(*ue));
 	ue = NLMSG_DATA(nlh);
 	nlh->nlmsg_flags = 0;
 
 	copy_to_user_state(x, &ue->state);
-	ue->hard = (hard != 0) ? 1 : 0;
+	ue->hard = (c->data.hard != 0) ? 1 : 0;
 
 	nlh->nlmsg_len = skb->tail - b;
 	return skb->len;
@@ -1194,13 +1527,31 @@
 	if (skb == NULL)
 		return -ENOMEM;
 
-	if (build_expire(skb, x, c->data.hard) < 0)
+	if (build_expire(skb, x, c) < 0)
 		BUG();
 
 	NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE;
 	return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC);
 }
 
+static int xfrm_aevent_state_notify(struct xfrm_state *x, struct km_event *c)
+{
+	struct sk_buff *skb;
+	int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id));
+
+	len += RTA_SPACE(sizeof(struct xfrm_replay_state));
+	len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur));
+	skb = alloc_skb(len, GFP_ATOMIC);
+	if (skb == NULL)
+		return -ENOMEM;
+
+	if (build_aevent(skb, x, c) < 0)
+		BUG();
+
+	NETLINK_CB(skb).dst_group = XFRMNLGRP_AEVENTS;
+	return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC);
+}
+
 static int xfrm_notify_sa_flush(struct km_event *c)
 {
 	struct xfrm_usersa_flush *p;
@@ -1313,6 +1664,8 @@
 	switch (c->event) {
 	case XFRM_MSG_EXPIRE:
 		return xfrm_exp_state_notify(x, c);
+	case XFRM_MSG_NEWAE:
+		return xfrm_aevent_state_notify(x, c);
 	case XFRM_MSG_DELSA:
 	case XFRM_MSG_UPDSA:
 	case XFRM_MSG_NEWSA:
@@ -1443,13 +1796,14 @@
 }
 
 static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp,
-			   int dir, int hard)
+			   int dir, struct km_event *c)
 {
 	struct xfrm_user_polexpire *upe;
 	struct nlmsghdr *nlh;
+	int hard = c->data.hard;
 	unsigned char *b = skb->tail;
 
-	nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe));
+	nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe));
 	upe = NLMSG_DATA(nlh);
 	nlh->nlmsg_flags = 0;
 
@@ -1480,7 +1834,7 @@
 	if (skb == NULL)
 		return -ENOMEM;
 
-	if (build_polexpire(skb, xp, dir, c->data.hard) < 0)
+	if (build_polexpire(skb, xp, dir, c) < 0)
 		BUG();
 
 	NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE;
@@ -1618,3 +1972,4 @@
 module_exit(xfrm_user_exit);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM);
+
diff -urN oldtree/scripts/extract-ikconfig newtree/scripts/extract-ikconfig
--- oldtree/scripts/extract-ikconfig	2006-01-03 03:21:10.000000000 +0000
+++ newtree/scripts/extract-ikconfig	2006-02-21 15:58:29.480664816 +0000
@@ -4,6 +4,7 @@
 # $arg1 is [b]zImage filename
 
 binoffset="./scripts/binoffset"
+test -e $binoffset || cc -o $binoffset ./scripts/binoffset.c || exit 1
 
 IKCFG_ST="0x49 0x4b 0x43 0x46 0x47 0x5f 0x53 0x54"
 IKCFG_ED="0x49 0x4b 0x43 0x46 0x47 0x5f 0x45 0x44"
@@ -20,7 +21,7 @@
     let start="$start + 8"
     let size="$end - $start"
 
-    head --bytes="$end" "$file" | tail --bytes="$size" | zcat
+    dd if="$file" ibs=1 skip="$start" count="$size" 2>/dev/null | zcat
 
     clean_up
     exit 0
@@ -45,7 +46,7 @@
 	exit 1
 fi
 
-TMPFILE="/tmp/ikconfig-$$"
+TMPFILE=`mktemp -t ikconfig-XXXXXX` || exit 1
 image="$1"
 
 # vmlinux: Attempt to dump the configuration from the file directly
diff -urN oldtree/scripts/genksyms/keywords.c_shipped newtree/scripts/genksyms/keywords.c_shipped
--- oldtree/scripts/genksyms/keywords.c_shipped	2006-02-19 11:41:06.614337568 +0000
+++ newtree/scripts/genksyms/keywords.c_shipped	2006-02-21 15:58:12.670220392 +0000
@@ -52,9 +52,9 @@
       71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
       71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
       71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
-      71, 71, 71, 71, 71, 71, 71, 71, 71, 15,
-      71, 71, 71, 71, 71, 71, 15, 71, 71, 71,
-      10, 71, 71, 71, 71, 71, 71, 71, 71, 71,
+      71, 71, 71, 71, 71, 71, 71, 71, 71,  0,
+      71, 71, 71, 71, 71, 71, 35, 71, 71, 71,
+       5, 71, 71, 71, 71, 71, 71, 71, 71, 71,
       71, 71, 71, 71, 71,  0, 71,  0, 71,  5,
        5,  0, 10, 20, 71, 25, 71, 71, 20,  0,
       20, 30, 25, 71, 10,  5,  0, 20, 15, 71,
@@ -84,9 +84,9 @@
 {
   enum
     {
-      TOTAL_KEYWORDS = 41,
+      TOTAL_KEYWORDS = 42,
       MIN_WORD_LENGTH = 3,
-      MAX_WORD_LENGTH = 17,
+      MAX_WORD_LENGTH = 24,
       MIN_HASH_VALUE = 3,
       MAX_HASH_VALUE = 70
     };
@@ -94,104 +94,105 @@
   static const struct resword wordlist[] =
     {
       {""}, {""}, {""},
-#line 24 "scripts/genksyms/keywords.gperf"
+#line 25 "scripts/genksyms/keywords.gperf"
       {"asm", ASM_KEYW},
       {""},
-#line 7 "scripts/genksyms/keywords.gperf"
+#line 8 "scripts/genksyms/keywords.gperf"
       {"__asm", ASM_KEYW},
       {""},
-#line 8 "scripts/genksyms/keywords.gperf"
+#line 9 "scripts/genksyms/keywords.gperf"
       {"__asm__", ASM_KEYW},
       {""},
-#line 21 "scripts/genksyms/keywords.gperf"
+#line 22 "scripts/genksyms/keywords.gperf"
       {"_restrict", RESTRICT_KEYW},
-#line 50 "scripts/genksyms/keywords.gperf"
+#line 51 "scripts/genksyms/keywords.gperf"
       {"__typeof__", TYPEOF_KEYW},
-#line 9 "scripts/genksyms/keywords.gperf"
+#line 10 "scripts/genksyms/keywords.gperf"
       {"__attribute", ATTRIBUTE_KEYW},
-#line 11 "scripts/genksyms/keywords.gperf"
+#line 12 "scripts/genksyms/keywords.gperf"
       {"__const", CONST_KEYW},
-#line 10 "scripts/genksyms/keywords.gperf"
+#line 11 "scripts/genksyms/keywords.gperf"
       {"__attribute__", ATTRIBUTE_KEYW},
-#line 12 "scripts/genksyms/keywords.gperf"
+#line 13 "scripts/genksyms/keywords.gperf"
       {"__const__", CONST_KEYW},
-#line 16 "scripts/genksyms/keywords.gperf"
+#line 17 "scripts/genksyms/keywords.gperf"
       {"__signed__", SIGNED_KEYW},
-#line 42 "scripts/genksyms/keywords.gperf"
+#line 43 "scripts/genksyms/keywords.gperf"
       {"static", STATIC_KEYW},
       {""},
-#line 15 "scripts/genksyms/keywords.gperf"
+#line 16 "scripts/genksyms/keywords.gperf"
       {"__signed", SIGNED_KEYW},
-#line 30 "scripts/genksyms/keywords.gperf"
+#line 31 "scripts/genksyms/keywords.gperf"
       {"char", CHAR_KEYW},
       {""},
-#line 43 "scripts/genksyms/keywords.gperf"
+#line 44 "scripts/genksyms/keywords.gperf"
       {"struct", STRUCT_KEYW},
-#line 22 "scripts/genksyms/keywords.gperf"
-      {"__restrict__", RESTRICT_KEYW},
 #line 23 "scripts/genksyms/keywords.gperf"
+      {"__restrict__", RESTRICT_KEYW},
+#line 24 "scripts/genksyms/keywords.gperf"
       {"restrict", RESTRICT_KEYW},
-#line 33 "scripts/genksyms/keywords.gperf"
+#line 34 "scripts/genksyms/keywords.gperf"
       {"enum", ENUM_KEYW},
-#line 17 "scripts/genksyms/keywords.gperf"
+#line 18 "scripts/genksyms/keywords.gperf"
       {"__volatile", VOLATILE_KEYW},
-#line 34 "scripts/genksyms/keywords.gperf"
+#line 35 "scripts/genksyms/keywords.gperf"
       {"extern", EXTERN_KEYW},
-#line 18 "scripts/genksyms/keywords.gperf"
+#line 19 "scripts/genksyms/keywords.gperf"
       {"__volatile__", VOLATILE_KEYW},
-#line 37 "scripts/genksyms/keywords.gperf"
+#line 38 "scripts/genksyms/keywords.gperf"
       {"int", INT_KEYW},
-      {""},
-#line 31 "scripts/genksyms/keywords.gperf"
-      {"const", CONST_KEYW},
+#line 7 "scripts/genksyms/keywords.gperf"
+      {"EXPORT_SYMBOL_GPL_FUTURE", EXPORT_SYMBOL_KEYW},
 #line 32 "scripts/genksyms/keywords.gperf"
+      {"const", CONST_KEYW},
+#line 33 "scripts/genksyms/keywords.gperf"
       {"double", DOUBLE_KEYW},
       {""},
-#line 13 "scripts/genksyms/keywords.gperf"
+#line 14 "scripts/genksyms/keywords.gperf"
       {"__inline", INLINE_KEYW},
-#line 29 "scripts/genksyms/keywords.gperf"
+#line 30 "scripts/genksyms/keywords.gperf"
       {"auto", AUTO_KEYW},
-#line 14 "scripts/genksyms/keywords.gperf"
+#line 15 "scripts/genksyms/keywords.gperf"
       {"__inline__", INLINE_KEYW},
-#line 41 "scripts/genksyms/keywords.gperf"
+#line 42 "scripts/genksyms/keywords.gperf"
       {"signed", SIGNED_KEYW},
       {""},
-#line 46 "scripts/genksyms/keywords.gperf"
+#line 47 "scripts/genksyms/keywords.gperf"
       {"unsigned", UNSIGNED_KEYW},
       {""},
-#line 40 "scripts/genksyms/keywords.gperf"
+#line 41 "scripts/genksyms/keywords.gperf"
       {"short", SHORT_KEYW},
-#line 49 "scripts/genksyms/keywords.gperf"
+#line 50 "scripts/genksyms/keywords.gperf"
       {"typeof", TYPEOF_KEYW},
-#line 44 "scripts/genksyms/keywords.gperf"
+#line 45 "scripts/genksyms/keywords.gperf"
       {"typedef", TYPEDEF_KEYW},
-#line 48 "scripts/genksyms/keywords.gperf"
+#line 49 "scripts/genksyms/keywords.gperf"
       {"volatile", VOLATILE_KEYW},
       {""},
-#line 35 "scripts/genksyms/keywords.gperf"
+#line 36 "scripts/genksyms/keywords.gperf"
       {"float", FLOAT_KEYW},
       {""}, {""},
-#line 39 "scripts/genksyms/keywords.gperf"
+#line 40 "scripts/genksyms/keywords.gperf"
       {"register", REGISTER_KEYW},
-#line 47 "scripts/genksyms/keywords.gperf"
+#line 48 "scripts/genksyms/keywords.gperf"
       {"void", VOID_KEYW},
       {""},
-#line 36 "scripts/genksyms/keywords.gperf"
+#line 37 "scripts/genksyms/keywords.gperf"
       {"inline", INLINE_KEYW},
       {""},
 #line 5 "scripts/genksyms/keywords.gperf"
       {"EXPORT_SYMBOL", EXPORT_SYMBOL_KEYW},
       {""},
-#line 20 "scripts/genksyms/keywords.gperf"
+#line 21 "scripts/genksyms/keywords.gperf"
       {"_Bool", BOOL_KEYW},
       {""},
 #line 6 "scripts/genksyms/keywords.gperf"
       {"EXPORT_SYMBOL_GPL", EXPORT_SYMBOL_KEYW},
       {""}, {""}, {""}, {""}, {""}, {""},
-#line 38 "scripts/genksyms/keywords.gperf"
+#line 39 "scripts/genksyms/keywords.gperf"
       {"long", LONG_KEYW},
       {""}, {""}, {""}, {""}, {""},
-#line 45 "scripts/genksyms/keywords.gperf"
+#line 46 "scripts/genksyms/keywords.gperf"
       {"union", UNION_KEYW}
     };
 
diff -urN oldtree/scripts/genksyms/keywords.gperf newtree/scripts/genksyms/keywords.gperf
--- oldtree/scripts/genksyms/keywords.gperf	2006-01-03 03:21:10.000000000 +0000
+++ newtree/scripts/genksyms/keywords.gperf	2006-02-21 15:58:12.669220544 +0000
@@ -4,6 +4,7 @@
 %%
 EXPORT_SYMBOL, EXPORT_SYMBOL_KEYW
 EXPORT_SYMBOL_GPL, EXPORT_SYMBOL_KEYW
+EXPORT_SYMBOL_GPL_FUTURE, EXPORT_SYMBOL_KEYW
 __asm, ASM_KEYW
 __asm__, ASM_KEYW
 __attribute, ATTRIBUTE_KEYW
diff -urN oldtree/scripts/kconfig/Makefile newtree/scripts/kconfig/Makefile
--- oldtree/scripts/kconfig/Makefile	2006-02-19 11:41:06.622336352 +0000
+++ newtree/scripts/kconfig/Makefile	2006-02-21 15:58:37.398461128 +0000
@@ -54,7 +54,11 @@
 	$< -n arch/$(ARCH)/Kconfig
 
 allmodconfig: $(obj)/conf
+ifdef FIXED_CONF
+	$< -M $(FIXED_CONF) arch/$(ARCH)/Kconfig
+else
 	$< -m arch/$(ARCH)/Kconfig
+endif
 
 defconfig: $(obj)/conf
 ifeq ($(KBUILD_DEFCONFIG),)
diff -urN oldtree/scripts/kconfig/conf.c newtree/scripts/kconfig/conf.c
--- oldtree/scripts/kconfig/conf.c	2006-02-19 11:41:06.623336200 +0000
+++ newtree/scripts/kconfig/conf.c	2006-02-21 15:58:37.395461584 +0000
@@ -23,6 +23,7 @@
 	set_default,
 	set_yes,
 	set_mod,
+	set_Mod,
 	set_no,
 	set_random
 } input_mode = ask_all;
@@ -140,7 +141,14 @@
 			line[2] = 0;
 			break;
 		}
+	case set_Mod:
 	case set_mod:
+		if (input_mode == set_Mod && sym_has_value(sym)) {
+			printf("%s\n", def);
+			line[0] = '\n';
+			line[1] = 0;
+			return;
+		}
 		if (type == S_TRISTATE) {
 			if (sym_tristate_within_range(sym, mod)) {
 				line[0] = 'm';
@@ -389,6 +397,7 @@
 		case set_default:
 		case set_yes:
 		case set_mod:
+		case set_Mod:
 		case set_no:
 			cnt = def;
 			printf("%d\n", cnt);
@@ -534,6 +543,15 @@
 		case 'n':
 			input_mode = set_no;
 			break;
+		case 'M':
+			defconfig_file = av[i++];
+			if (!defconfig_file) {
+				printf("%s: No default config file specified\n",
+					av[0]);
+				exit(1);
+			}
+			input_mode = set_Mod;
+			break;
 		case 'm':
 			input_mode = set_mod;
 			break;
@@ -557,6 +575,7 @@
 	conf_parse(name);
 	//zconfdump(stdout);
 	switch (input_mode) {
+	case set_Mod:
 	case set_default:
 		if (!defconfig_file)
 			defconfig_file = conf_get_default_confname();
diff -urN oldtree/scripts/kconfig/lxdialog/colors.h newtree/scripts/kconfig/lxdialog/colors.h
--- oldtree/scripts/kconfig/lxdialog/colors.h	2006-02-19 11:41:06.627335592 +0000
+++ newtree/scripts/kconfig/lxdialog/colors.h	2006-02-21 15:58:37.545438784 +0000
@@ -37,7 +37,7 @@
 #define DIALOG_BG                    COLOR_WHITE
 #define DIALOG_HL                    FALSE
 
-#define TITLE_FG                     COLOR_YELLOW
+#define TITLE_FG                     COLOR_BLUE
 #define TITLE_BG                     COLOR_WHITE
 #define TITLE_HL                     TRUE
 
@@ -109,7 +109,7 @@
 #define ITEM_SELECTED_BG             COLOR_BLUE
 #define ITEM_SELECTED_HL             TRUE
 
-#define TAG_FG                       COLOR_YELLOW
+#define TAG_FG                       COLOR_BLUE
 #define TAG_BG                       COLOR_WHITE
 #define TAG_HL                       TRUE
 
@@ -117,7 +117,7 @@
 #define TAG_SELECTED_BG              COLOR_BLUE
 #define TAG_SELECTED_HL              TRUE
 
-#define TAG_KEY_FG                   COLOR_YELLOW
+#define TAG_KEY_FG                   COLOR_BLUE
 #define TAG_KEY_BG                   COLOR_WHITE
 #define TAG_KEY_HL                   TRUE
 
diff -urN oldtree/scripts/ver_linux newtree/scripts/ver_linux
--- oldtree/scripts/ver_linux	2006-01-03 03:21:10.000000000 +0000
+++ newtree/scripts/ver_linux	2006-02-21 15:58:34.162953000 +0000
@@ -42,7 +42,7 @@
 reiserfsck -V 2>&1 | grep reiserfsck | awk \
 'NR==1{print "reiserfsprogs         ", $2}'
 
-fsck.reiser4 -V 2>&1 | grep fsck.reiser4 | awk \
+fsck.reiser4 -V 2>&1 | grep ^fsck.reiser4 | awk \
 'NR==1{print "reiser4progs          ", $2}'
 
 xfs_db -V 2>&1 | grep version | awk \
diff -urN oldtree/security/dummy.c newtree/security/dummy.c
--- oldtree/security/dummy.c	2006-02-19 11:41:06.648332400 +0000
+++ newtree/security/dummy.c	2006-02-21 15:58:11.838346856 +0000
@@ -378,7 +378,7 @@
 	return 0;
 }
 
-static int dummy_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
+static int dummy_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
 {
 	return -EOPNOTSUPP;
 }
@@ -393,6 +393,11 @@
 	return 0;
 }
 
+static const char *dummy_inode_xattr_getsuffix(void)
+{
+	return NULL;
+}
+
 static int dummy_file_permission (struct file *file, int mask)
 {
 	return 0;
@@ -558,6 +563,11 @@
 	return 0;
 }
 
+static int dummy_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
+{
+	return -EOPNOTSUPP;
+}
+
 static int dummy_msg_msg_alloc_security (struct msg_msg *msg)
 {
 	return 0;
@@ -925,6 +935,7 @@
 	set_to_dummy_if_null(ops, inode_getxattr);
 	set_to_dummy_if_null(ops, inode_listxattr);
 	set_to_dummy_if_null(ops, inode_removexattr);
+	set_to_dummy_if_null(ops, inode_xattr_getsuffix);
 	set_to_dummy_if_null(ops, inode_getsecurity);
 	set_to_dummy_if_null(ops, inode_setsecurity);
 	set_to_dummy_if_null(ops, inode_listsecurity);
@@ -959,6 +970,7 @@
 	set_to_dummy_if_null(ops, task_reparent_to_init);
  	set_to_dummy_if_null(ops, task_to_inode);
 	set_to_dummy_if_null(ops, ipc_permission);
+	set_to_dummy_if_null(ops, ipc_getsecurity);
 	set_to_dummy_if_null(ops, msg_msg_alloc_security);
 	set_to_dummy_if_null(ops, msg_msg_free_security);
 	set_to_dummy_if_null(ops, msg_queue_alloc_security);
diff -urN oldtree/security/keys/process_keys.c newtree/security/keys/process_keys.c
--- oldtree/security/keys/process_keys.c	2006-02-19 11:41:06.653331640 +0000
+++ newtree/security/keys/process_keys.c	2006-02-21 15:58:22.610709208 +0000
@@ -16,11 +16,12 @@
 #include <linux/keyctl.h>
 #include <linux/fs.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include "internal.h"
 
 /* session keyring create vs join semaphore */
-static DECLARE_MUTEX(key_session_sem);
+static DEFINE_MUTEX(key_session_mutex);
 
 /* the root user's tracking struct */
 struct key_user root_key_user = {
@@ -711,7 +712,7 @@
 	}
 
 	/* allow the user to join or create a named keyring */
-	down(&key_session_sem);
+	mutex_lock(&key_session_mutex);
 
 	/* look for an existing keyring of this name */
 	keyring = find_keyring_by_name(name, 0);
@@ -737,7 +738,7 @@
 	key_put(keyring);
 
 error2:
-	up(&key_session_sem);
+	mutex_unlock(&key_session_mutex);
 error:
 	return ret;
 
diff -urN oldtree/security/seclvl.c newtree/security/seclvl.c
--- oldtree/security/seclvl.c	2006-02-19 11:41:06.656331184 +0000
+++ newtree/security/seclvl.c	2006-02-21 15:58:22.637705104 +0000
@@ -8,6 +8,7 @@
  * Copyright (c) 2001 WireX Communications, Inc <chris@wirex.com>
  * Copyright (c) 2001 Greg Kroah-Hartman <greg@kroah.com>
  * Copyright (c) 2002 International Business Machines <robb@austin.ibm.com>
+ * Copyright (c) 2006 Davi E. M. Arnaut <davi.arnaut@gmail.com>
  *
  *	This program is free software; you can redistribute it and/or modify
  *	it under the terms of the GNU General Public License as published by
@@ -31,6 +32,7 @@
 #include <linux/kobject.h>
 #include <linux/crypto.h>
 #include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
 #include <linux/gfp.h>
 #include <linux/sysfs.h>
 
@@ -194,35 +196,27 @@
  * people...
  */
 static int
-plaintext_to_sha1(unsigned char *hash, const char *plaintext, int len)
+plaintext_to_sha1(unsigned char *hash, const char *plaintext, unsigned int len)
 {
-	char *pgVirtAddr;
 	struct crypto_tfm *tfm;
-	struct scatterlist sg[1];
+	struct scatterlist sg;
 	if (len > PAGE_SIZE) {
 		seclvl_printk(0, KERN_ERR, "Plaintext password too large (%d "
 			      "characters).  Largest possible is %lu "
 			      "bytes.\n", len, PAGE_SIZE);
-		return -ENOMEM;
+		return -EINVAL;
 	}
 	tfm = crypto_alloc_tfm("sha1", CRYPTO_TFM_REQ_MAY_SLEEP);
 	if (tfm == NULL) {
 		seclvl_printk(0, KERN_ERR,
 			      "Failed to load transform for SHA1\n");
-		return -ENOSYS;
+		return -EINVAL;
 	}
-	// Just get a new page; don't play around with page boundaries
-	// and scatterlists.
-	pgVirtAddr = (char *)__get_free_page(GFP_KERNEL);
-	sg[0].page = virt_to_page(pgVirtAddr);
-	sg[0].offset = 0;
-	sg[0].length = len;
-	strncpy(pgVirtAddr, plaintext, len);
+	sg_init_one(&sg, (u8 *)plaintext, len);
 	crypto_digest_init(tfm);
-	crypto_digest_update(tfm, sg, 1);
+	crypto_digest_update(tfm, &sg, 1);
 	crypto_digest_final(tfm, hash);
 	crypto_free_tfm(tfm);
-	free_page((unsigned long)pgVirtAddr);
 	return 0;
 }
 
@@ -234,11 +228,9 @@
 passwd_write_file(struct file * file, const char __user * buf,
 				size_t count, loff_t *ppos)
 {
-	int i;
+	char *p;
+	unsigned int len;
 	unsigned char tmp[SHA1_DIGEST_SIZE];
-	char *page;
-	int rc;
-	int len;
 
 	if (!*passwd && !*sha1_passwd) {
 		seclvl_printk(0, KERN_ERR, "Attempt to password-unlock the "
@@ -251,38 +243,39 @@
 		return -EINVAL;
 	}
 
-	if (count < 0 || count >= PAGE_SIZE)
+	if (count >= PAGE_SIZE)
 		return -EINVAL;
 	if (*ppos != 0)
 		return -EINVAL;
-	page = (char *)get_zeroed_page(GFP_KERNEL);
-	if (!page)
+	p = kmalloc(count, GFP_KERNEL);
+	if (!p)
 		return -ENOMEM;
 	len = -EFAULT;
-	if (copy_from_user(page, buf, count))
+	if (copy_from_user(p, buf, count))
 		goto out;
 	
-	len = strlen(page);
+	len = count;
 	/* ``echo "secret" > seclvl/passwd'' includes a newline */
-	if (page[len - 1] == '\n')
+	if (p[len - 1] == '\n')
 		len--;
 	/* Hash the password, then compare the hashed values */
-	if ((rc = plaintext_to_sha1(tmp, page, len))) {
+	if ((len = plaintext_to_sha1(tmp, p, len))) {
 		seclvl_printk(0, KERN_ERR, "Error hashing password: rc = "
-			      "[%d]\n", rc);
-		return rc;
-	}
-	for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
-		if (hashedPassword[i] != tmp[i])
-			return -EPERM;
+			      "[%d]\n", len);
+		goto out;
 	}
+
+	len = -EPERM;
+	if (memcmp(hashedPassword, tmp, SHA1_DIGEST_SIZE))
+		goto out;
+
 	seclvl_printk(0, KERN_INFO,
 		      "Password accepted; seclvl reduced to 0.\n");
 	seclvl = 0;
 	len = count;
 
 out:
-	free_page((unsigned long)page);
+	kfree (p);
 	return len;
 }
 
@@ -295,13 +288,11 @@
  */
 static int seclvl_ptrace(struct task_struct *parent, struct task_struct *child)
 {
-	if (seclvl >= 0) {
-		if (child->pid == 1) {
-			seclvl_printk(1, KERN_WARNING, "Attempt to ptrace "
-				      "the init process dissallowed in "
-				      "secure level %d\n", seclvl);
-			return -EPERM;
-		}
+	if (seclvl >= 0 && child->pid == 1) {
+		seclvl_printk(1, KERN_WARNING, "Attempt to ptrace "
+			      "the init process dissallowed in "
+			      "secure level %d\n", seclvl);
+		return -EPERM;
 	}
 	return 0;
 }
@@ -312,55 +303,54 @@
  */
 static int seclvl_capable(struct task_struct *tsk, int cap)
 {
+	int rc = 0;
+
 	/* init can do anything it wants */
 	if (tsk->pid == 1)
 		return 0;
 
-	switch (seclvl) {
-	case 2:
-		/* fall through */
-	case 1:
-		if (cap == CAP_LINUX_IMMUTABLE) {
+	if (seclvl > 0) {
+		rc = -EPERM;
+
+		if (cap == CAP_LINUX_IMMUTABLE)
 			seclvl_printk(1, KERN_WARNING, "Attempt to modify "
 				      "the IMMUTABLE and/or APPEND extended "
 				      "attribute on a file with the IMMUTABLE "
 				      "and/or APPEND extended attribute set "
 				      "denied in seclvl [%d]\n", seclvl);
-			return -EPERM;
-		} else if (cap == CAP_SYS_RAWIO) {	// Somewhat broad...
+		else if (cap == CAP_SYS_RAWIO)
 			seclvl_printk(1, KERN_WARNING, "Attempt to perform "
 				      "raw I/O while in secure level [%d] "
 				      "denied\n", seclvl);
-			return -EPERM;
-		} else if (cap == CAP_NET_ADMIN) {
+		else if (cap == CAP_NET_ADMIN)
 			seclvl_printk(1, KERN_WARNING, "Attempt to perform "
 				      "network administrative task while "
 				      "in secure level [%d] denied\n", seclvl);
-			return -EPERM;
-		} else if (cap == CAP_SETUID) {
+		else if (cap == CAP_SETUID)
 			seclvl_printk(1, KERN_WARNING, "Attempt to setuid "
 				      "while in secure level [%d] denied\n",
 				      seclvl);
-			return -EPERM;
-		} else if (cap == CAP_SETGID) {
+		else if (cap == CAP_SETGID)
 			seclvl_printk(1, KERN_WARNING, "Attempt to setgid "
 				      "while in secure level [%d] denied\n",
 				      seclvl);
-		} else if (cap == CAP_SYS_MODULE) {
+		else if (cap == CAP_SYS_MODULE)
 			seclvl_printk(1, KERN_WARNING, "Attempt to perform "
 				      "a module operation while in secure "
 				      "level [%d] denied\n", seclvl);
-			return -EPERM;
-		}
-		break;
-	default:
-		break;
-	}
-	/* from dummy.c */
-	if (cap_is_fs_cap(cap) ? tsk->fsuid == 0 : tsk->euid == 0)
-		return 0;	/* capability granted */
-	seclvl_printk(1, KERN_WARNING, "Capability denied\n");
-	return -EPERM;		/* capability denied */
+		else
+			rc = 0;
+	}
+
+	if (!rc) {
+		if (!(cap_is_fs_cap(cap) ? tsk->fsuid == 0 : tsk->euid == 0))
+			rc = -EPERM;
+	}
+
+	if (rc)
+		seclvl_printk(1, KERN_WARNING, "Capability denied\n");
+
+	return rc;
 }
 
 /**
@@ -466,12 +456,9 @@
 static void seclvl_file_free_security(struct file *filp)
 {
 	struct dentry *dentry = filp->f_dentry;
-	struct inode *inode = NULL;
 
-	if (dentry) {
-		inode = dentry->d_inode;
-		seclvl_bd_release(inode);
-	}
+	if (dentry)
+		seclvl_bd_release(dentry->d_inode);
 }
 
 /**
@@ -479,9 +466,7 @@
  */
 static int seclvl_umount(struct vfsmount *mnt, int flags)
 {
-	if (current->pid == 1)
-		return 0;
-	if (seclvl == 2) {
+	if (current->pid != 1 && seclvl == 2) {
 		seclvl_printk(1, KERN_WARNING, "Attempt to unmount in secure "
 			      "level %d\n", seclvl);
 		return -EPERM;
@@ -505,8 +490,9 @@
 static int processPassword(void)
 {
 	int rc = 0;
-	hashedPassword[0] = '\0';
 	if (*passwd) {
+		char *p;
+
 		if (*sha1_passwd) {
 			seclvl_printk(0, KERN_ERR, "Error: Both "
 				      "passwd and sha1_passwd "
@@ -514,12 +500,16 @@
 				      "exclusive.\n");
 			return -EINVAL;
 		}
-		if ((rc = plaintext_to_sha1(hashedPassword, passwd,
-					    strlen(passwd)))) {
+
+		p = kstrdup(passwd, GFP_KERNEL);
+		if (p == NULL)
+			return -ENOMEM;
+
+		if ((rc = plaintext_to_sha1(hashedPassword, p, strlen(p))))
 			seclvl_printk(0, KERN_ERR, "Error: SHA1 support not "
 				      "in kernel\n");
-			return rc;
-		}
+
+		kfree (p);
 		/* All static data goes to the BSS, which zero's the
 		 * plaintext password out for us. */
 	} else if (*sha1_passwd) {	// Base 16
@@ -542,7 +532,7 @@
 			sha1_passwd[i + 2] = tmp;
 		}
 	}
-	return 0;
+	return rc;
 }
 
 /**
@@ -552,28 +542,46 @@
 
 static int seclvlfs_register(void)
 {
+	int rc = 0;
+
 	dir_ino = securityfs_create_dir("seclvl", NULL);
-	if (!dir_ino)
-		return -EFAULT;
+
+	if (IS_ERR(dir_ino))
+		return PTR_ERR(dir_ino);
 
 	seclvl_ino = securityfs_create_file("seclvl", S_IRUGO | S_IWUSR,
 				dir_ino, &seclvl, &seclvl_file_ops);
-	if (!seclvl_ino)
+	if (IS_ERR(seclvl_ino)) {
+		rc = PTR_ERR(seclvl_ino);
 		goto out_deldir;
+	}
 	if (*passwd || *sha1_passwd) {
 		passwd_ino = securityfs_create_file("passwd", S_IRUGO | S_IWUSR,
 				dir_ino, NULL, &passwd_file_ops);
-		if (!passwd_ino)
+		if (IS_ERR(passwd_ino)) {
+			rc = PTR_ERR(passwd_ino);
 			goto out_delf;
+		}
 	}
-	return 0;
+	return rc;
+
+out_delf:
+	securityfs_remove(seclvl_ino);
 
 out_deldir:
 	securityfs_remove(dir_ino);
-out_delf:
+
+	return rc;
+}
+
+static void seclvlfs_unregister(void)
+{
 	securityfs_remove(seclvl_ino);
 
-	return -EFAULT;
+	if (*passwd || *sha1_passwd)
+		securityfs_remove(passwd_ino);
+
+	securityfs_remove(dir_ino);
 }
 
 /**
@@ -600,6 +608,11 @@
 			      "module parameter(s): rc = [%d]\n", rc);
 		goto exit;
 	}
+
+	if ((rc = seclvlfs_register())) {
+		seclvl_printk(0, KERN_ERR, "Error registering with sysfs\n");
+		goto exit;
+	}
 	/* register ourselves with the security framework */
 	if (register_security(&seclvl_ops)) {
 		seclvl_printk(0, KERN_ERR,
@@ -611,20 +624,17 @@
 			seclvl_printk(0, KERN_ERR, "seclvl: Failure "
 				      "registering with primary security "
 				      "module.\n");
+			seclvlfs_unregister();
 			goto exit;
 		}		/* if primary module registered */
 		secondary = 1;
 	}			/* if we registered ourselves with the security framework */
-	if ((rc = seclvlfs_register())) {
-		seclvl_printk(0, KERN_ERR, "Error registering with sysfs\n");
-		goto exit;
-	}
+
 	seclvl_printk(0, KERN_INFO, "seclvl: Successfully initialized.\n");
  exit:
-	if (rc) {
+	if (rc)
 		printk(KERN_ERR "seclvl: Error during initialization: rc = "
 		       "[%d]\n", rc);
-	}
 	return rc;
 }
 
@@ -633,17 +643,14 @@
  */
 static void __exit seclvl_exit(void)
 {
-	securityfs_remove(seclvl_ino);
-	if (*passwd || *sha1_passwd)
-		securityfs_remove(passwd_ino);
-	securityfs_remove(dir_ino);
-	if (secondary == 1) {
+	seclvlfs_unregister();
+
+	if (secondary)
 		mod_unreg_security(MY_NAME, &seclvl_ops);
-	} else if (unregister_security(&seclvl_ops)) {
+	else if (unregister_security(&seclvl_ops))
 		seclvl_printk(0, KERN_INFO,
 			      "seclvl: Failure unregistering with the "
 			      "kernel\n");
-	}
 }
 
 module_init(seclvl_init);
diff -urN oldtree/security/selinux/hooks.c newtree/security/selinux/hooks.c
--- oldtree/security/selinux/hooks.c	2006-02-19 11:41:06.659330728 +0000
+++ newtree/security/selinux/hooks.c	2006-02-21 15:58:11.851344880 +0000
@@ -117,6 +117,32 @@
 static LIST_HEAD(superblock_security_head);
 static DEFINE_SPINLOCK(sb_security_lock);
 
+/* Return security context for a given sid or just the context 
+   length if the buffer is null or length is 0 */
+static int selinux_getsecurity(u32 sid, void *buffer, size_t size)
+{
+	char *context;
+	unsigned len;
+	int rc;
+
+	rc = security_sid_to_context(sid, &context, &len);
+	if (rc)
+		return rc;
+
+	if (!buffer || !size)
+		goto getsecurity_exit;
+
+	if (size < len) {
+		len = -ERANGE;
+		goto getsecurity_exit;
+	}
+	memcpy(buffer, context, len);
+
+getsecurity_exit:
+	kfree(context);
+	return len;
+}
+
 /* Allocate and free functions for each kind of security blob. */
 
 static int task_alloc_security(struct task_struct *task)
@@ -2209,6 +2235,11 @@
 	return -EACCES;
 }
 
+static const char *selinux_inode_xattr_getsuffix(void)
+{
+      return XATTR_SELINUX_SUFFIX;
+}
+
 /*
  * Copy the in-core inode security context value to the user.  If the
  * getxattr() prior to this succeeded, check to see if we need to
@@ -2216,47 +2247,14 @@
  *
  * Permission check is handled by selinux_inode_getxattr hook.
  */
-static int selinux_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
+static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
 {
 	struct inode_security_struct *isec = inode->i_security;
-	char *context;
-	unsigned len;
-	int rc;
-
-	if (strcmp(name, XATTR_SELINUX_SUFFIX)) {
-		rc = -EOPNOTSUPP;
-		goto out;
-	}
-
-	rc = security_sid_to_context(isec->sid, &context, &len);
-	if (rc)
-		goto out;
-
-	/* Probe for required buffer size */
-	if (!buffer || !size) {
-		rc = len;
-		goto out_free;
-	}
 
-	if (size < len) {
-		rc = -ERANGE;
-		goto out_free;
-	}
+	if (strcmp(name, XATTR_SELINUX_SUFFIX))
+		return -EOPNOTSUPP;
 
-	if (err > 0) {
-		if ((len == err) && !(memcmp(context, buffer, len))) {
-			/* Don't need to canonicalize value */
-			rc = err;
-			goto out_free;
-		}
-		memset(buffer, 0, size);
-	}
-	memcpy(buffer, context, len);
-	rc = len;
-out_free:
-	kfree(context);
-out:
-	return rc;
+	return selinux_getsecurity(isec->sid, buffer, size);
 }
 
 static int selinux_inode_setsecurity(struct inode *inode, const char *name,
@@ -4022,6 +4020,13 @@
 	return ipc_has_perm(ipcp, av);
 }
 
+static int selinux_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
+{
+	struct ipc_security_struct *isec = ipcp->security;
+
+	return selinux_getsecurity(isec->sid, buffer, size);
+}
+
 /* module stacking operations */
 static int selinux_register_security (const char *name, struct security_operations *ops)
 {
@@ -4063,8 +4068,7 @@
 			       char *name, void *value, size_t size)
 {
 	struct task_security_struct *tsec;
-	u32 sid, len;
-	char *context;
+	u32 sid;
 	int error;
 
 	if (current != p) {
@@ -4073,9 +4077,6 @@
 			return error;
 	}
 
-	if (!size)
-		return -ERANGE;
-
 	tsec = p->security;
 
 	if (!strcmp(name, "current"))
@@ -4092,16 +4093,7 @@
 	if (!sid)
 		return 0;
 
-	error = security_sid_to_context(sid, &context, &len);
-	if (error)
-		return error;
-	if (len > size) {
-		kfree(context);
-		return -ERANGE;
-	}
-	memcpy(value, context, len);
-	kfree(context);
-	return len;
+	return selinux_getsecurity(sid, value, size);
 }
 
 static int selinux_setprocattr(struct task_struct *p,
@@ -4259,6 +4251,7 @@
 	.inode_getxattr =		selinux_inode_getxattr,
 	.inode_listxattr =		selinux_inode_listxattr,
 	.inode_removexattr =		selinux_inode_removexattr,
+	.inode_xattr_getsuffix =        selinux_inode_xattr_getsuffix,
 	.inode_getsecurity =            selinux_inode_getsecurity,
 	.inode_setsecurity =            selinux_inode_setsecurity,
 	.inode_listsecurity =           selinux_inode_listsecurity,
@@ -4296,6 +4289,7 @@
 	.task_to_inode =                selinux_task_to_inode,
 
 	.ipc_permission =		selinux_ipc_permission,
+	.ipc_getsecurity =		selinux_ipc_getsecurity,
 
 	.msg_msg_alloc_security =	selinux_msg_msg_alloc_security,
 	.msg_msg_free_security =	selinux_msg_msg_free_security,
diff -urN oldtree/security/selinux/nlmsgtab.c newtree/security/selinux/nlmsgtab.c
--- oldtree/security/selinux/nlmsgtab.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/security/selinux/nlmsgtab.c	2006-02-21 15:58:16.526634128 +0000
@@ -88,8 +88,15 @@
 	{ XFRM_MSG_DELPOLICY,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
 	{ XFRM_MSG_GETPOLICY,	NETLINK_XFRM_SOCKET__NLMSG_READ  },
 	{ XFRM_MSG_ALLOCSPI,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_ACQUIRE,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_EXPIRE,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
 	{ XFRM_MSG_UPDPOLICY,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
 	{ XFRM_MSG_UPDSA,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_POLEXPIRE,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_FLUSHSA,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_FLUSHPOLICY,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_NEWAE,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+	{ XFRM_MSG_GETAE,	NETLINK_XFRM_SOCKET__NLMSG_READ  },
 };
 
 static struct nlmsg_perm nlmsg_audit_perms[] =
@@ -99,6 +106,9 @@
 	{ AUDIT_LIST,		NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
 	{ AUDIT_ADD,		NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
 	{ AUDIT_DEL,		NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
+	{ AUDIT_LIST_RULES,	NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
+	{ AUDIT_ADD_RULE,	NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
+	{ AUDIT_DEL_RULE,	NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
 	{ AUDIT_USER,		NETLINK_AUDIT_SOCKET__NLMSG_RELAY    },
 	{ AUDIT_SIGNAL_INFO,	NETLINK_AUDIT_SOCKET__NLMSG_READ     },
 };
@@ -145,8 +155,10 @@
 		break;
 
 	case SECCLASS_NETLINK_AUDIT_SOCKET:
-		if (nlmsg_type >= AUDIT_FIRST_USER_MSG &&
-		    nlmsg_type <= AUDIT_LAST_USER_MSG) {
+		if ((nlmsg_type >= AUDIT_FIRST_USER_MSG &&
+		     nlmsg_type <= AUDIT_LAST_USER_MSG) ||
+		    (nlmsg_type >= AUDIT_FIRST_USER_MSG2 &&
+                     nlmsg_type <= AUDIT_LAST_USER_MSG2)) {
 			*perm = NETLINK_AUDIT_SOCKET__NLMSG_RELAY;
 		} else {
 			err = nlmsg_perm(nlmsg_type, perm, nlmsg_audit_perms,
diff -urN oldtree/security/selinux/selinuxfs.c newtree/security/selinux/selinuxfs.c
--- oldtree/security/selinux/selinuxfs.c	2006-02-19 11:41:06.664329968 +0000
+++ newtree/security/selinux/selinuxfs.c	2006-02-21 15:58:22.611709056 +0000
@@ -21,8 +21,10 @@
 #include <linux/major.h>
 #include <linux/seq_file.h>
 #include <linux/percpu.h>
+#include <linux/audit.h>
+#include <linux/mutex.h>
+
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
 
 /* selinuxfs pseudo filesystem for exporting the security policy API.
    Based on the proc code and the fs/nfsd/nfsctl.c code. */
@@ -44,7 +46,7 @@
 __setup("checkreqprot=", checkreqprot_setup);
 
 
-static DECLARE_MUTEX(sel_sem);
+static DEFINE_MUTEX(sel_mutex);
 
 /* global data for booleans */
 static struct dentry *bool_dir = NULL;
@@ -126,6 +128,10 @@
 		length = task_has_security(current, SECURITY__SETENFORCE);
 		if (length)
 			goto out;
+		audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
+			"enforcing=%d old_enforcing=%d auid=%u", new_value, 
+			selinux_enforcing,
+			audit_get_loginuid(current->audit_context));
 		selinux_enforcing = new_value;
 		if (selinux_enforcing)
 			avc_ss_reset(0);
@@ -176,6 +182,9 @@
 		length = selinux_disable();
 		if (length < 0)
 			goto out;
+		audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
+			"selinux=0 auid=%u",
+			audit_get_loginuid(current->audit_context));
 	}
 
 	length = count;
@@ -230,7 +239,7 @@
 	ssize_t length;
 	void *data = NULL;
 
-	down(&sel_sem);
+	mutex_lock(&sel_mutex);
 
 	length = task_has_security(current, SECURITY__LOAD_POLICY);
 	if (length)
@@ -261,8 +270,11 @@
 		length = ret;
 	else
 		length = count;
+	audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
+		"policy loaded auid=%u",
+		audit_get_loginuid(current->audit_context));
 out:
-	up(&sel_sem);
+	mutex_unlock(&sel_mutex);
 	vfree(data);
 	return length;
 }
@@ -714,7 +726,7 @@
 	int cur_enforcing;
 	struct inode *inode;
 
-	down(&sel_sem);
+	mutex_lock(&sel_mutex);
 
 	ret = -EFAULT;
 
@@ -759,7 +771,7 @@
 	*ppos = end;
 	ret = count;
 out:
-	up(&sel_sem);
+	mutex_unlock(&sel_mutex);
 	if (page)
 		free_page((unsigned long)page);
 	return ret;
@@ -773,7 +785,7 @@
 	int new_value;
 	struct inode *inode;
 
-	down(&sel_sem);
+	mutex_lock(&sel_mutex);
 
 	length = task_has_security(current, SECURITY__SETBOOL);
 	if (length)
@@ -812,7 +824,7 @@
 	length = count;
 
 out:
-	up(&sel_sem);
+	mutex_unlock(&sel_mutex);
 	if (page)
 		free_page((unsigned long) page);
 	return length;
@@ -831,7 +843,7 @@
 	ssize_t length = -EFAULT;
 	int new_value;
 
-	down(&sel_sem);
+	mutex_lock(&sel_mutex);
 
 	length = task_has_security(current, SECURITY__SETBOOL);
 	if (length)
@@ -869,7 +881,7 @@
 	length = count;
 
 out:
-	up(&sel_sem);
+	mutex_unlock(&sel_mutex);
 	if (page)
 		free_page((unsigned long) page);
 	return length;
diff -urN oldtree/security/selinux/ss/services.c newtree/security/selinux/ss/services.c
--- oldtree/security/selinux/ss/services.c	2006-02-19 11:41:06.666329664 +0000
+++ newtree/security/selinux/ss/services.c	2006-02-21 15:58:22.612708904 +0000
@@ -27,6 +27,7 @@
 #include <linux/in.h>
 #include <linux/sched.h>
 #include <linux/audit.h>
+#include <linux/mutex.h>
 #include <asm/semaphore.h>
 #include "flask.h"
 #include "avc.h"
@@ -48,9 +49,9 @@
 #define POLICY_RDUNLOCK read_unlock(&policy_rwlock)
 #define POLICY_WRUNLOCK write_unlock_irq(&policy_rwlock)
 
-static DECLARE_MUTEX(load_sem);
-#define LOAD_LOCK down(&load_sem)
-#define LOAD_UNLOCK up(&load_sem)
+static DEFINE_MUTEX(load_sem);
+#define LOAD_LOCK mutex_lock(&load_sem)
+#define LOAD_UNLOCK mutex_unlock(&load_sem)
 
 static struct sidtab sidtab;
 struct policydb policydb;
@@ -1758,19 +1759,22 @@
 		goto out;
 	}
 
-	printk(KERN_INFO "security: committed booleans { ");
 	for (i = 0; i < len; i++) {
+		if (!!values[i] != policydb.bool_val_to_struct[i]->state) {
+			audit_log(current->audit_context, GFP_ATOMIC,
+				AUDIT_MAC_CONFIG_CHANGE,
+				"bool=%s val=%d old_val=%d auid=%u",
+				policydb.p_bool_val_to_name[i],
+				!!values[i],
+				policydb.bool_val_to_struct[i]->state,
+				audit_get_loginuid(current->audit_context));
+		}
 		if (values[i]) {
 			policydb.bool_val_to_struct[i]->state = 1;
 		} else {
 			policydb.bool_val_to_struct[i]->state = 0;
 		}
-		if (i != 0)
-			printk(", ");
-		printk("%s:%d", policydb.p_bool_val_to_name[i],
-		       policydb.bool_val_to_struct[i]->state);
 	}
-	printk(" }\n");
 
 	for (cur = policydb.cond_list; cur != NULL; cur = cur->next) {
 		rc = evaluate_cond_node(&policydb, cur);
diff -urN oldtree/sound/arm/aaci.c newtree/sound/arm/aaci.c
--- oldtree/sound/arm/aaci.c	2006-02-19 11:41:06.669329208 +0000
+++ newtree/sound/arm/aaci.c	2006-02-21 15:58:11.226439880 +0000
@@ -73,7 +73,7 @@
 	if (ac97->num >= 4)
 		return;
 
-	down(&aaci->ac97_sem);
+	mutex_lock(&aaci->ac97_sem);
 
 	aaci_ac97_select_codec(aaci, ac97);
 
@@ -91,7 +91,7 @@
 		v = readl(aaci->base + AACI_SLFR);
 	} while (v & (SLFR_1TXB|SLFR_2TXB));
 
-	up(&aaci->ac97_sem);
+	mutex_unlock(&aaci->ac97_sem);
 }
 
 /*
@@ -105,7 +105,7 @@
 	if (ac97->num >= 4)
 		return ~0;
 
-	down(&aaci->ac97_sem);
+	mutex_lock(&aaci->ac97_sem);
 
 	aaci_ac97_select_codec(aaci, ac97);
 
@@ -145,7 +145,7 @@
 		v = ~0;
 	}
 
-	up(&aaci->ac97_sem);
+	mutex_unlock(&aaci->ac97_sem);
 	return v;
 }
 
@@ -783,7 +783,7 @@
 		 card->shortname, dev->res.start, dev->irq[0]);
 
 	aaci = card->private_data;
-	init_MUTEX(&aaci->ac97_sem);
+	mutex_init(&aaci->ac97_sem);
 	spin_lock_init(&aaci->lock);
 	aaci->card = card;
 	aaci->dev = dev;
diff -urN oldtree/sound/arm/aaci.h newtree/sound/arm/aaci.h
--- oldtree/sound/arm/aaci.h	2006-02-19 11:41:06.669329208 +0000
+++ newtree/sound/arm/aaci.h	2006-02-21 15:58:11.227439728 +0000
@@ -227,7 +227,7 @@
 	unsigned int		fifosize;
 
 	/* AC'97 */
-	struct semaphore	ac97_sem;
+	struct mutex		ac97_sem;
 	ac97_bus_t		*ac97_bus;
 
 	u32			maincr;
diff -urN oldtree/sound/arm/pxa2xx-ac97.c newtree/sound/arm/pxa2xx-ac97.c
--- oldtree/sound/arm/pxa2xx-ac97.c	2006-02-19 11:41:06.671328904 +0000
+++ newtree/sound/arm/pxa2xx-ac97.c	2006-02-21 15:58:11.228439576 +0000
@@ -25,7 +25,7 @@
 #include <sound/initval.h>
 
 #include <asm/irq.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/hardware.h>
 #include <asm/arch/pxa-regs.h>
 #include <asm/arch/audio.h>
@@ -33,7 +33,7 @@
 #include "pxa2xx-pcm.h"
 
 
-static DECLARE_MUTEX(car_mutex);
+static DEFINE_MUTEX(car_mutex);
 static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
 static volatile long gsr_bits;
 
@@ -52,7 +52,7 @@
 	unsigned short val = -1;
 	volatile u32 *reg_addr;
 
-	down(&car_mutex);
+	mutex_lock(&car_mutex);
 
 	/* set up primary or secondary codec space */
 	reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE;
@@ -79,7 +79,7 @@
 	/* but we've just started another cycle... */
 	wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1);
 
-out:	up(&car_mutex);
+out:	mutex_unlock(&car_mutex);
 	return val;
 }
 
@@ -87,7 +87,7 @@
 {
 	volatile u32 *reg_addr;
 
-	down(&car_mutex);
+	mutex_lock(&car_mutex);
 
 	/* set up primary or secondary codec space */
 	reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE;
@@ -101,7 +101,7 @@
 		printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n",
 				__FUNCTION__, reg, GSR | gsr_bits);
 
-	up(&car_mutex);
+	mutex_unlock(&car_mutex);
 }
 
 static void pxa2xx_ac97_reset(struct snd_ac97 *ac97)
diff -urN oldtree/sound/core/Kconfig newtree/sound/core/Kconfig
--- oldtree/sound/core/Kconfig	2006-02-19 11:41:06.673328600 +0000
+++ newtree/sound/core/Kconfig	2006-02-21 15:58:11.228439576 +0000
@@ -73,6 +73,15 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-pcm-oss.
 
+config SND_PCM_OSS_PLUGINS
+	bool "OSS PCM (digital audio) API - Include plugin system"
+	depends on SND_PCM_OSS
+        default y
+	help
+          If you disable this option, the ALSA's OSS PCM API will not
+          support conversion of channels, formats and rates. It will
+          behave like most of new OSS/Free drivers in 2.4/2.6 kernels.
+
 config SND_SEQUENCER_OSS
 	bool "OSS Sequencer API"
 	depends on SND && SND_SEQUENCER
@@ -130,6 +139,15 @@
 	  Say Y here to support the obsolete ALSA PCM API (ver.0.9.0 rc3
 	  or older).
 
+config SND_VERBOSE_PROCFS
+	bool "Verbose procfs contents"
+	depends on SND
+	default y
+	help
+	  Say Y here to include code for verbose procfs contents (provides
+          usefull information to developers when a problem occurs). On the
+          other side, it makes the ALSA subsystem larger.
+
 config SND_VERBOSE_PRINTK
 	bool "Verbose printk"
 	depends on SND
diff -urN oldtree/sound/core/hwdep.c newtree/sound/core/hwdep.c
--- oldtree/sound/core/hwdep.c	2006-02-19 11:41:06.678327840 +0000
+++ newtree/sound/core/hwdep.c	2006-02-21 15:58:11.229439424 +0000
@@ -25,6 +25,7 @@
 #include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/time.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/minors.h>
@@ -36,7 +37,7 @@
 MODULE_LICENSE("GPL");
 
 static LIST_HEAD(snd_hwdep_devices);
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
 
 static int snd_hwdep_free(struct snd_hwdep *hwdep);
 static int snd_hwdep_dev_free(struct snd_device *device);
@@ -111,7 +112,7 @@
 
 	init_waitqueue_entry(&wait, current);
 	add_wait_queue(&hw->open_wait, &wait);
-	down(&hw->open_mutex);
+	mutex_lock(&hw->open_mutex);
 	while (1) {
 		if (hw->exclusive && hw->used > 0) {
 			err = -EBUSY;
@@ -128,9 +129,9 @@
 		} else
 			break;
 		set_current_state(TASK_INTERRUPTIBLE);
-		up(&hw->open_mutex);
+		mutex_unlock(&hw->open_mutex);
 		schedule();
-		down(&hw->open_mutex);
+		mutex_lock(&hw->open_mutex);
 		if (signal_pending(current)) {
 			err = -ERESTARTSYS;
 			break;
@@ -147,7 +148,7 @@
 				hw->ops.release(hw, file);
 		}
 	}
-	up(&hw->open_mutex);
+	mutex_unlock(&hw->open_mutex);
 	if (err < 0)
 		module_put(hw->card->module);
 	return err;
@@ -157,7 +158,7 @@
 {
 	int err = -ENXIO;
 	struct snd_hwdep *hw = file->private_data;
-	down(&hw->open_mutex);
+	mutex_lock(&hw->open_mutex);
 	if (hw->ops.release) {
 		err = hw->ops.release(hw, file);
 		wake_up(&hw->open_wait);
@@ -165,7 +166,7 @@
 	if (hw->used > 0)
 		hw->used--;
 	snd_card_file_remove(hw->card, file);
-	up(&hw->open_mutex);
+	mutex_unlock(&hw->open_mutex);
 	module_put(hw->card->module);
 	return err;
 }
@@ -272,7 +273,7 @@
 
 			if (get_user(device, (int __user *)arg))
 				return -EFAULT;
-			down(&register_mutex);
+			mutex_lock(&register_mutex);
 			device = device < 0 ? 0 : device + 1;
 			while (device < SNDRV_MINOR_HWDEPS) {
 				if (snd_hwdep_search(card, device))
@@ -281,7 +282,7 @@
 			}
 			if (device >= SNDRV_MINOR_HWDEPS)
 				device = -1;
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			if (put_user(device, (int __user *)arg))
 				return -EFAULT;
 			return 0;
@@ -294,13 +295,13 @@
 
 			if (get_user(device, &info->device))
 				return -EFAULT;
-			down(&register_mutex);
+			mutex_lock(&register_mutex);
 			hwdep = snd_hwdep_search(card, device);
 			if (hwdep)
 				err = snd_hwdep_info(hwdep, info);
 			else
 				err = -ENXIO;
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			return err;
 		}
 	}
@@ -375,7 +376,7 @@
 		return err;
 	}
 	init_waitqueue_head(&hwdep->open_wait);
-	init_MUTEX(&hwdep->open_mutex);
+	mutex_init(&hwdep->open_mutex);
 	*rhwdep = hwdep;
 	return 0;
 }
@@ -401,9 +402,9 @@
 	int err;
 	char name[32];
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	if (snd_hwdep_search(hwdep->card, hwdep->device)) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -EBUSY;
 	}
 	list_add_tail(&hwdep->list, &snd_hwdep_devices);
@@ -414,7 +415,7 @@
 		snd_printk(KERN_ERR "unable to register hardware dependent device %i:%i\n",
 			   hwdep->card->number, hwdep->device);
 		list_del(&hwdep->list);
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return err;
 	}
 #ifdef CONFIG_SND_OSSEMUL
@@ -434,7 +435,7 @@
 		}
 	}
 #endif
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return 0;
 }
 
@@ -443,9 +444,9 @@
 	struct snd_hwdep *hwdep = device->device_data;
 
 	snd_assert(hwdep != NULL, return -ENXIO);
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -EINVAL;
 	}
 #ifdef CONFIG_SND_OSSEMUL
@@ -454,7 +455,7 @@
 #endif
 	snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device);
 	list_del(&hwdep->list);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return snd_hwdep_free(hwdep);
 }
 
@@ -469,13 +470,13 @@
 	struct list_head *p;
 	struct snd_hwdep *hwdep;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	list_for_each(p, &snd_hwdep_devices) {
 		hwdep = list_entry(p, struct snd_hwdep, list);
 		snd_iprintf(buffer, "%02i-%02i: %s\n",
 			    hwdep->card->number, hwdep->device, hwdep->name);
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 }
 
 static struct snd_info_entry *snd_hwdep_proc_entry;
diff -urN oldtree/sound/core/info.c newtree/sound/core/info.c
--- oldtree/sound/core/info.c	2006-02-19 11:41:06.680327536 +0000
+++ newtree/sound/core/info.c	2006-02-21 15:58:11.230439272 +0000
@@ -31,6 +31,7 @@
 #include <sound/version.h>
 #include <linux/proc_fs.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/mutex.h>
 #include <stdarg.h>
 
 /*
@@ -68,7 +69,7 @@
 	return 1;
 }
 
-static DECLARE_MUTEX(info_mutex);
+static DEFINE_MUTEX(info_mutex);
 
 struct snd_info_private_data {
 	struct snd_info_buffer *rbuffer;
@@ -265,11 +266,11 @@
 	struct proc_dir_entry *p;
 	int mode, err;
 
-	down(&info_mutex);
+	mutex_lock(&info_mutex);
 	p = PDE(inode);
 	entry = p == NULL ? NULL : (struct snd_info_entry *)p->data;
 	if (entry == NULL || entry->disconnected) {
-		up(&info_mutex);
+		mutex_unlock(&info_mutex);
 		return -ENODEV;
 	}
 	if (!try_module_get(entry->module)) {
@@ -361,13 +362,13 @@
 		break;
 	}
 	file->private_data = data;
-	up(&info_mutex);
+	mutex_unlock(&info_mutex);
 	if (entry->content == SNDRV_INFO_CONTENT_TEXT &&
 	    (mode == O_RDONLY || mode == O_RDWR)) {
 		if (entry->c.text.read) {
-			down(&entry->access);
+			mutex_lock(&entry->access);
 			entry->c.text.read(entry, data->rbuffer);
-			up(&entry->access);
+			mutex_unlock(&entry->access);
 		}
 	}
 	return 0;
@@ -375,7 +376,7 @@
       __error:
 	module_put(entry->module);
       __error1:
-	up(&info_mutex);
+	mutex_unlock(&info_mutex);
 	return err;
 }
 
@@ -747,7 +748,7 @@
 	}
 	entry->mode = S_IFREG | S_IRUGO;
 	entry->content = SNDRV_INFO_CONTENT_TEXT;
-	init_MUTEX(&entry->access);
+	mutex_init(&entry->access);
 	return entry;
 }
 
@@ -896,10 +897,10 @@
 
 	snd_assert(entry != NULL, return -ENXIO);
 	root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
-	down(&info_mutex);
+	mutex_lock(&info_mutex);
 	p = snd_create_proc_entry(entry->name, entry->mode, root);
 	if (!p) {
-		up(&info_mutex);
+		mutex_unlock(&info_mutex);
 		return -ENOMEM;
 	}
 	p->owner = entry->module;
@@ -908,7 +909,7 @@
 	p->size = entry->size;
 	p->data = entry;
 	entry->p = p;
-	up(&info_mutex);
+	mutex_unlock(&info_mutex);
 	return 0;
 }
 
@@ -929,9 +930,9 @@
 	snd_assert(entry->p != NULL, return -ENXIO);
 	root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
 	snd_assert(root, return -ENXIO);
-	down(&info_mutex);
+	mutex_lock(&info_mutex);
 	snd_remove_proc_entry(root, entry->p);
-	up(&info_mutex);
+	mutex_unlock(&info_mutex);
 	snd_info_free_entry(entry);
 	return 0;
 }
diff -urN oldtree/sound/core/info_oss.c newtree/sound/core/info_oss.c
--- oldtree/sound/core/info_oss.c	2006-02-19 11:41:06.680327536 +0000
+++ newtree/sound/core/info_oss.c	2006-02-21 15:58:11.231439120 +0000
@@ -28,6 +28,7 @@
 #include <sound/info.h>
 #include <sound/version.h>
 #include <linux/utsname.h>
+#include <linux/mutex.h>
 
 #if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
 
@@ -35,7 +36,7 @@
  *  OSS compatible part
  */
 
-static DECLARE_MUTEX(strings);
+static DEFINE_MUTEX(strings);
 static char *snd_sndstat_strings[SNDRV_CARDS][SNDRV_OSS_INFO_DEV_COUNT];
 static struct snd_info_entry *snd_sndstat_proc_entry;
 
@@ -45,7 +46,7 @@
 
 	snd_assert(dev >= 0 && dev < SNDRV_OSS_INFO_DEV_COUNT, return -ENXIO);
 	snd_assert(num >= 0 && num < SNDRV_CARDS, return -ENXIO);
-	down(&strings);
+	mutex_lock(&strings);
 	if (string == NULL) {
 		if ((x = snd_sndstat_strings[num][dev]) != NULL) {
 			kfree(x);
@@ -54,12 +55,12 @@
 	} else {
 		x = kstrdup(string, GFP_KERNEL);
 		if (x == NULL) {
-			up(&strings);
+			mutex_unlock(&strings);
 			return -ENOMEM;
 		}
 	}
 	snd_sndstat_strings[num][dev] = x;
-	up(&strings);
+	mutex_unlock(&strings);
 	return 0;
 }
 
@@ -71,7 +72,7 @@
 	char *str;
 
 	snd_iprintf(buf, "\n%s:", id);
-	down(&strings);
+	mutex_lock(&strings);
 	for (idx = 0; idx < SNDRV_CARDS; idx++) {
 		str = snd_sndstat_strings[idx][dev];
 		if (str) {
@@ -82,7 +83,7 @@
 			snd_iprintf(buf, "%i: %s\n", idx, str);
 		}
 	}
-	up(&strings);
+	mutex_unlock(&strings);
 	if (ok < 0)
 		snd_iprintf(buf, " NOT ENABLED IN CONFIG\n");
 	return ok;
diff -urN oldtree/sound/core/init.c newtree/sound/core/init.c
--- oldtree/sound/core/init.c	2006-02-19 11:41:06.682327232 +0000
+++ newtree/sound/core/init.c	2006-02-21 15:58:11.232438968 +0000
@@ -145,7 +145,7 @@
 	init_waitqueue_head(&card->shutdown_sleep);
 	INIT_WORK(&card->free_workq, snd_card_free_thread, card);
 #ifdef CONFIG_PM
-	init_MUTEX(&card->power_lock);
+	mutex_init(&card->power_lock);
 	init_waitqueue_head(&card->power_sleep);
 #endif
 	/* the control interface cannot be accessed from the user space until */
diff -urN oldtree/sound/core/memalloc.c newtree/sound/core/memalloc.c
--- oldtree/sound/core/memalloc.c	2006-02-19 11:41:06.682327232 +0000
+++ newtree/sound/core/memalloc.c	2006-02-21 15:58:11.232438968 +0000
@@ -31,7 +31,7 @@
 #include <asm/uaccess.h>
 #include <linux/dma-mapping.h>
 #include <linux/moduleparam.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <sound/memalloc.h>
 #ifdef CONFIG_SBUS
 #include <asm/sbus.h>
@@ -54,7 +54,7 @@
 /*
  */
 
-static DECLARE_MUTEX(list_mutex);
+static DEFINE_MUTEX(list_mutex);
 static LIST_HEAD(mem_list_head);
 
 /* buffer preservation list */
@@ -83,7 +83,7 @@
  *  Hacks
  */
 
-#if defined(__i386__) || defined(__ppc__) || defined(__x86_64__)
+#if defined(__i386__)
 /*
  * A hack to allocate large buffers via dma_alloc_coherent()
  *
@@ -141,10 +141,6 @@
 
 #endif /* arch */
 
-#if ! defined(__arm__)
-#define NEED_RESERVE_PAGES
-#endif
-
 /*
  *
  *  Generic memory allocators
@@ -163,20 +159,6 @@
 	snd_allocated_pages -= 1 << order;
 }
 
-static void mark_pages(struct page *page, int order)
-{
-	struct page *last_page = page + (1 << order);
-	while (page < last_page)
-		SetPageReserved(page++);
-}
-
-static void unmark_pages(struct page *page, int order)
-{
-	struct page *last_page = page + (1 << order);
-	while (page < last_page)
-		ClearPageReserved(page++);
-}
-
 /**
  * snd_malloc_pages - allocate pages with the given size
  * @size: the size to allocate in bytes
@@ -195,10 +177,8 @@
 	snd_assert(gfp_flags != 0, return NULL);
 	gfp_flags |= __GFP_COMP;	/* compound page lets parts be mapped */
 	pg = get_order(size);
-	if ((res = (void *) __get_free_pages(gfp_flags, pg)) != NULL) {
-		mark_pages(virt_to_page(res), pg);
+	if ((res = (void *) __get_free_pages(gfp_flags, pg)) != NULL)
 		inc_snd_pages(pg);
-	}
 	return res;
 }
 
@@ -217,7 +197,6 @@
 		return;
 	pg = get_order(size);
 	dec_snd_pages(pg);
-	unmark_pages(virt_to_page(ptr), pg);
 	free_pages((unsigned long) ptr, pg);
 }
 
@@ -242,12 +221,8 @@
 		| __GFP_NORETRY /* don't trigger OOM-killer */
 		| __GFP_NOWARN; /* no stack trace print - this call is non-critical */
 	res = dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags);
-	if (res != NULL) {
-#ifdef NEED_RESERVE_PAGES
-		mark_pages(virt_to_page(res), pg); /* should be dma_to_page() */
-#endif
+	if (res != NULL)
 		inc_snd_pages(pg);
-	}
 
 	return res;
 }
@@ -262,9 +237,6 @@
 		return;
 	pg = get_order(size);
 	dec_snd_pages(pg);
-#ifdef NEED_RESERVE_PAGES
-	unmark_pages(virt_to_page(ptr), pg); /* should be dma_to_page() */
-#endif
 	dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma);
 }
 
@@ -440,7 +412,7 @@
 
 	snd_assert(dmab, return 0);
 
-	down(&list_mutex);
+	mutex_lock(&list_mutex);
 	list_for_each(p, &mem_list_head) {
 		mem = list_entry(p, struct snd_mem_list, list);
 		if (mem->id == id &&
@@ -452,11 +424,11 @@
 			if (dmab->dev.dev == NULL)
 				dmab->dev.dev = dev;
 			kfree(mem);
-			up(&list_mutex);
+			mutex_unlock(&list_mutex);
 			return dmab->bytes;
 		}
 	}
-	up(&list_mutex);
+	mutex_unlock(&list_mutex);
 	return 0;
 }
 
@@ -477,11 +449,11 @@
 	mem = kmalloc(sizeof(*mem), GFP_KERNEL);
 	if (! mem)
 		return -ENOMEM;
-	down(&list_mutex);
+	mutex_lock(&list_mutex);
 	mem->buffer = *dmab;
 	mem->id = id;
 	list_add_tail(&mem->list, &mem_list_head);
-	up(&list_mutex);
+	mutex_unlock(&list_mutex);
 	return 0;
 }
 
@@ -493,7 +465,7 @@
 	struct list_head *p;
 	struct snd_mem_list *mem;
 
-	down(&list_mutex);
+	mutex_lock(&list_mutex);
 	while (! list_empty(&mem_list_head)) {
 		p = mem_list_head.next;
 		mem = list_entry(p, struct snd_mem_list, list);
@@ -501,7 +473,7 @@
 		snd_dma_free_pages(&mem->buffer);
 		kfree(mem);
 	}
-	up(&list_mutex);
+	mutex_unlock(&list_mutex);
 }
 
 
@@ -522,7 +494,7 @@
 	int devno;
 	static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" };
 
-	down(&list_mutex);
+	mutex_lock(&list_mutex);
 	len += snprintf(page + len, count - len,
 			"pages  : %li bytes (%li pages per %likB)\n",
 			pages * PAGE_SIZE, pages, PAGE_SIZE / 1024);
@@ -537,7 +509,7 @@
 				"  addr = 0x%lx, size = %d bytes\n",
 				(unsigned long)mem->buffer.addr, (int)mem->buffer.bytes);
 	}
-	up(&list_mutex);
+	mutex_unlock(&list_mutex);
 	return len;
 }
 
diff -urN oldtree/sound/core/oss/copy.c newtree/sound/core/oss/copy.c
--- oldtree/sound/core/oss/copy.c	2006-02-19 11:41:06.683327080 +0000
+++ newtree/sound/core/oss/copy.c	2006-02-21 15:58:11.233438816 +0000
@@ -20,6 +20,9 @@
  */
 
 #include <sound/driver.h>
+
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -85,3 +88,5 @@
 	*r_plugin = plugin;
 	return 0;
 }
+
+#endif
diff -urN oldtree/sound/core/oss/io.c newtree/sound/core/oss/io.c
--- oldtree/sound/core/oss/io.c	2006-02-19 11:41:06.683327080 +0000
+++ newtree/sound/core/oss/io.c	2006-02-21 15:58:11.236438360 +0000
@@ -20,6 +20,9 @@
  */
   
 #include <sound/driver.h>
+
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -132,3 +135,5 @@
 	*r_plugin = plugin;
 	return 0;
 }
+
+#endif
diff -urN oldtree/sound/core/oss/linear.c newtree/sound/core/oss/linear.c
--- oldtree/sound/core/oss/linear.c	2006-02-19 11:41:06.683327080 +0000
+++ newtree/sound/core/oss/linear.c	2006-02-21 15:58:11.236438360 +0000
@@ -21,6 +21,9 @@
  */
 
 #include <sound/driver.h>
+
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -103,7 +106,7 @@
 	return frames;
 }
 
-int conv_index(int src_format, int dst_format)
+static int conv_index(int src_format, int dst_format)
 {
 	int src_endian, dst_endian, sign, src_width, dst_width;
 
@@ -156,3 +159,5 @@
 	*r_plugin = plugin;
 	return 0;
 }
+
+#endif
diff -urN oldtree/sound/core/oss/mixer_oss.c newtree/sound/core/oss/mixer_oss.c
--- oldtree/sound/core/oss/mixer_oss.c	2006-02-19 11:41:06.685326776 +0000
+++ newtree/sound/core/oss/mixer_oss.c	2006-02-21 15:58:11.238438056 +0000
@@ -1095,7 +1095,7 @@
 	struct snd_mixer_oss *mixer = entry->private_data;
 	int i;
 
-	down(&mixer->reg_mutex);
+	mutex_lock(&mixer->reg_mutex);
 	for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) {
 		struct slot *p;
 
@@ -1110,7 +1110,7 @@
 		else
 			snd_iprintf(buffer, "\"\" 0\n");
 	}
-	up(&mixer->reg_mutex);
+	mutex_unlock(&mixer->reg_mutex);
 }
 
 static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
@@ -1134,9 +1134,9 @@
 		cptr = snd_info_get_str(str, cptr, sizeof(str));
 		if (! *str) {
 			/* remove the entry */
-			down(&mixer->reg_mutex);
+			mutex_lock(&mixer->reg_mutex);
 			mixer_slot_clear(&mixer->slots[ch]);
-			up(&mixer->reg_mutex);
+			mutex_unlock(&mixer->reg_mutex);
 			continue;
 		}
 		snd_info_get_str(idxstr, cptr, sizeof(idxstr));
@@ -1145,7 +1145,7 @@
 			snd_printk(KERN_ERR "mixer_oss: invalid index %d\n", idx);
 			continue;
 		}
-		down(&mixer->reg_mutex);
+		mutex_lock(&mixer->reg_mutex);
 		slot = (struct slot *)mixer->slots[ch].private_data;
 		if (slot && slot->assigned &&
 		    slot->assigned->index == idx && ! strcmp(slot->assigned->name, str))
@@ -1168,7 +1168,7 @@
 			kfree(tbl);
 		}
 	__unlock:
-		up(&mixer->reg_mutex);
+		mutex_unlock(&mixer->reg_mutex);
 	}
 }
 
@@ -1288,7 +1288,7 @@
 		mixer = kcalloc(2, sizeof(*mixer), GFP_KERNEL);
 		if (mixer == NULL)
 			return -ENOMEM;
-		init_MUTEX(&mixer->reg_mutex);
+		mutex_init(&mixer->reg_mutex);
 		sprintf(name, "mixer%i%i", card->number, 0);
 		if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER,
 						   card, 0,
diff -urN oldtree/sound/core/oss/mulaw.c newtree/sound/core/oss/mulaw.c
--- oldtree/sound/core/oss/mulaw.c	2006-02-19 11:41:06.686326624 +0000
+++ newtree/sound/core/oss/mulaw.c	2006-02-21 15:58:11.239437904 +0000
@@ -22,6 +22,9 @@
  */
   
 #include <sound/driver.h>
+
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -262,6 +265,25 @@
 	return frames;
 }
 
+static int getput_index(int format)
+{
+	int sign, width, endian;
+	sign = !snd_pcm_format_signed(format);
+	width = snd_pcm_format_width(format) / 8 - 1;
+	if (width < 0 || width > 3) {
+		snd_printk(KERN_ERR "snd-pcm-oss: invalid format %d\n", format);
+		width = 0;
+	}
+#ifdef SNDRV_LITTLE_ENDIAN
+	endian = snd_pcm_format_big_endian(format);
+#else
+	endian = snd_pcm_format_little_endian(format);
+#endif
+	if (endian < 0)
+		endian = 0;
+	return width * 4 + endian * 2 + sign;
+}
+
 int snd_pcm_plugin_build_mulaw(struct snd_pcm_substream *plug,
 			       struct snd_pcm_plugin_format *src_format,
 			       struct snd_pcm_plugin_format *dst_format,
@@ -306,3 +328,5 @@
 	*r_plugin = plugin;
 	return 0;
 }
+
+#endif
diff -urN oldtree/sound/core/oss/pcm_oss.c newtree/sound/core/oss/pcm_oss.c
--- oldtree/sound/core/oss/pcm_oss.c	2006-02-19 11:41:06.689326168 +0000
+++ newtree/sound/core/oss/pcm_oss.c	2006-02-21 15:58:11.241437600 +0000
@@ -78,6 +78,7 @@
 	set_fs(fs);
 }
 
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
 static int snd_pcm_oss_plugin_clear(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
@@ -122,6 +123,7 @@
 	}
 	return 0;
 }
+#endif /* CONFIG_SND_PCM_OSS_PLUGINS */
 
 static long snd_pcm_oss_bytes(struct snd_pcm_substream *substream, long frames)
 {
@@ -412,6 +414,7 @@
 	oss_frame_size = snd_pcm_format_physical_width(params_format(params)) *
 			 params_channels(params) / 8;
 
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
 	snd_pcm_oss_plugin_clear(substream);
 	if (!direct) {
 		/* add necessary plugins */
@@ -441,6 +444,7 @@
 			}
 		}
 	}
+#endif
 
 	err = snd_pcm_oss_period_size(substream, params, sparams);
 	if (err < 0)
@@ -498,11 +502,13 @@
 	runtime->oss.periods = params_periods(sparams);
 	oss_period_size = snd_pcm_plug_client_size(substream, params_period_size(sparams));
 	snd_assert(oss_period_size >= 0, err = -EINVAL; goto failure);
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
 	if (runtime->oss.plugin_first) {
 		err = snd_pcm_plug_alloc(substream, oss_period_size);
 		if (err < 0)
 			goto failure;
 	}
+#endif
 	oss_period_size *= oss_frame_size;
 
 	oss_buffer_size = oss_period_size * runtime->oss.periods;
@@ -784,6 +790,7 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_pcm_sframes_t frames, frames1;
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
 	if (runtime->oss.plugin_first) {
 		struct snd_pcm_plugin_channel *channels;
 		size_t oss_frame_bytes = (runtime->oss.plugin_first->src_width * runtime->oss.plugin_first->src_format.channels) / 8;
@@ -800,7 +807,9 @@
 		if (frames1 <= 0)
 			return frames1;
 		bytes = frames1 * oss_frame_bytes;
-	} else {
+	} else
+#endif
+	{
 		frames = bytes_to_frames(runtime, bytes);
 		frames1 = snd_pcm_oss_write3(substream, buf, frames, in_kernel);
 		if (frames1 <= 0)
@@ -871,6 +880,7 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_pcm_sframes_t frames, frames1;
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
 	char __user *final_dst = (char __user *)buf;
 	if (runtime->oss.plugin_first) {
 		struct snd_pcm_plugin_channel *channels;
@@ -887,7 +897,9 @@
 		bytes = frames1 * oss_frame_bytes;
 		if (!in_kernel && copy_to_user(final_dst, buf, bytes))
 			return -EFAULT;
-	} else {
+	} else
+#endif
+	{
 		frames = bytes_to_frames(runtime, bytes);
 		frames1 = snd_pcm_oss_read3(substream, buf, frames, in_kernel);
 		if (frames1 <= 0)
@@ -1631,10 +1643,10 @@
 	const char *ptr, *ptrl;
 	struct snd_pcm_oss_setup *setup;
 
-	down(&pcm->streams[stream].oss.setup_mutex);
+	mutex_lock(&pcm->streams[stream].oss.setup_mutex);
 	for (setup = pcm->streams[stream].oss.setup_list; setup; setup = setup->next) {
 		if (!strcmp(setup->task_name, task_name)) {
-			up(&pcm->streams[stream].oss.setup_mutex);
+			mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
 			return setup;
 		}
 	}
@@ -1650,12 +1662,12 @@
 	}
 	for (setup = pcm->streams[stream].oss.setup_list; setup; setup = setup->next) {
 		if (!strcmp(setup->task_name, ptrl)) {
-			up(&pcm->streams[stream].oss.setup_mutex);
+			mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
 			return setup;
 		}
 	}
       __not_found:
-	up(&pcm->streams[stream].oss.setup_mutex);
+	mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
 	return NULL;
 }
 
@@ -1692,7 +1704,9 @@
 	struct snd_pcm_runtime *runtime;
 	runtime = substream->runtime;
 	vfree(runtime->oss.buffer);
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
 	snd_pcm_oss_plugin_clear(substream);
+#endif
 	substream->oss.file = NULL;
 	substream->oss.oss = 0;
 }
@@ -1881,7 +1895,7 @@
 
 	init_waitqueue_entry(&wait, current);
 	add_wait_queue(&pcm->open_wait, &wait);
-	down(&pcm->open_mutex);
+	mutex_lock(&pcm->open_mutex);
 	while (1) {
 		err = snd_pcm_oss_open_file(file, pcm, &pcm_oss_file,
 					    iminor(inode), psetup, csetup);
@@ -1895,16 +1909,16 @@
 		} else
 			break;
 		set_current_state(TASK_INTERRUPTIBLE);
-		up(&pcm->open_mutex);
+		mutex_unlock(&pcm->open_mutex);
 		schedule();
-		down(&pcm->open_mutex);
+		mutex_lock(&pcm->open_mutex);
 		if (signal_pending(current)) {
 			err = -ERESTARTSYS;
 			break;
 		}
 	}
 	remove_wait_queue(&pcm->open_wait, &wait);
-	up(&pcm->open_mutex);
+	mutex_unlock(&pcm->open_mutex);
 	if (err < 0)
 		goto __error;
 	return err;
@@ -1930,9 +1944,9 @@
 	snd_assert(substream != NULL, return -ENXIO);
 	pcm = substream->pcm;
 	snd_pcm_oss_sync(pcm_oss_file);
-	down(&pcm->open_mutex);
+	mutex_lock(&pcm->open_mutex);
 	snd_pcm_oss_release_file(pcm_oss_file);
-	up(&pcm->open_mutex);
+	mutex_unlock(&pcm->open_mutex);
 	wake_up(&pcm->open_wait);
 	module_put(pcm->card->module);
 	snd_card_file_remove(pcm->card, file);
@@ -2246,8 +2260,10 @@
 		if ((err = snd_pcm_oss_change_params(substream)) < 0)
 			return err;
 	}
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
 	if (runtime->oss.plugin_first != NULL)
 		return -EIO;
+#endif
 
 	if (area->vm_pgoff != 0)
 		return -EINVAL;
@@ -2277,7 +2293,7 @@
 {
 	struct snd_pcm_str *pstr = entry->private_data;
 	struct snd_pcm_oss_setup *setup = pstr->oss.setup_list;
-	down(&pstr->oss.setup_mutex);
+	mutex_lock(&pstr->oss.setup_mutex);
 	while (setup) {
 		snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n",
 			    setup->task_name,
@@ -2291,7 +2307,7 @@
 			    setup->nosilence ? " no-silence" : "");
 		setup = setup->next;
 	}
-	up(&pstr->oss.setup_mutex);
+	mutex_unlock(&pstr->oss.setup_mutex);
 }
 
 static void snd_pcm_oss_proc_free_setup_list(struct snd_pcm_str * pstr)
@@ -2321,12 +2337,12 @@
 	struct snd_pcm_oss_setup *setup, *setup1, template;
 
 	while (!snd_info_get_line(buffer, line, sizeof(line))) {
-		down(&pstr->oss.setup_mutex);
+		mutex_lock(&pstr->oss.setup_mutex);
 		memset(&template, 0, sizeof(template));
 		ptr = snd_info_get_str(task_name, line, sizeof(task_name));
 		if (!strcmp(task_name, "clear") || !strcmp(task_name, "erase")) {
 			snd_pcm_oss_proc_free_setup_list(pstr);
-			up(&pstr->oss.setup_mutex);
+			mutex_unlock(&pstr->oss.setup_mutex);
 			continue;
 		}
 		for (setup = pstr->oss.setup_list; setup; setup = setup->next) {
@@ -2378,7 +2394,7 @@
 		}
 		if (setup)
 			*setup = template;
-		up(&pstr->oss.setup_mutex);
+		mutex_unlock(&pstr->oss.setup_mutex);
 	}
 }
 
diff -urN oldtree/sound/core/oss/pcm_plugin.c newtree/sound/core/oss/pcm_plugin.c
--- oldtree/sound/core/oss/pcm_plugin.c	2006-02-19 11:41:06.690326016 +0000
+++ newtree/sound/core/oss/pcm_plugin.c	2006-02-21 15:58:11.243437296 +0000
@@ -25,6 +25,9 @@
 #endif
 
 #include <sound/driver.h>
+
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/vmalloc.h>
@@ -36,26 +39,6 @@
 #define snd_pcm_plug_first(plug) ((plug)->runtime->oss.plugin_first)
 #define snd_pcm_plug_last(plug) ((plug)->runtime->oss.plugin_last)
 
-static int snd_pcm_plugin_src_channels_mask(struct snd_pcm_plugin *plugin,
-					    unsigned long *dst_vmask,
-					    unsigned long **src_vmask)
-{
-	unsigned long *vmask = plugin->src_vmask;
-	bitmap_copy(vmask, dst_vmask, plugin->src_format.channels);
-	*src_vmask = vmask;
-	return 0;
-}
-
-static int snd_pcm_plugin_dst_channels_mask(struct snd_pcm_plugin *plugin,
-					    unsigned long *src_vmask,
-					    unsigned long **dst_vmask)
-{
-	unsigned long *vmask = plugin->dst_vmask;
-	bitmap_copy(vmask, src_vmask, plugin->dst_format.channels);
-	*dst_vmask = vmask;
-	return 0;
-}
-
 /*
  *  because some cards might have rates "very close", we ignore
  *  all "resampling" requests within +-5%
@@ -193,19 +176,7 @@
 		snd_pcm_plugin_free(plugin);
 		return -ENOMEM;
 	}
-	plugin->src_vmask = bitmap_alloc(src_format->channels);
-	if (plugin->src_vmask == NULL) {
-		snd_pcm_plugin_free(plugin);
-		return -ENOMEM;
-	}
-	plugin->dst_vmask = bitmap_alloc(dst_format->channels);
-	if (plugin->dst_vmask == NULL) {
-		snd_pcm_plugin_free(plugin);
-		return -ENOMEM;
-	}
 	plugin->client_channels = snd_pcm_plugin_client_channels;
-	plugin->src_channels_mask = snd_pcm_plugin_src_channels_mask;
-	plugin->dst_channels_mask = snd_pcm_plugin_dst_channels_mask;
 	*ret = plugin;
 	return 0;
 }
@@ -218,8 +189,6 @@
 		plugin->private_free(plugin);
 	kfree(plugin->buf_channels);
 	vfree(plugin->buf);
-	kfree(plugin->src_vmask);
-	kfree(plugin->dst_vmask);
 	kfree(plugin);
 	return 0;
 }
@@ -429,24 +398,14 @@
 		 dstformat.channels);
 
 	/* Format change (linearization) */
-	if ((srcformat.format != dstformat.format ||
-	     !rate_match(srcformat.rate, dstformat.rate) ||
-	     srcformat.channels != dstformat.channels) &&
-	    !snd_pcm_format_linear(srcformat.format)) {
-		if (snd_pcm_format_linear(dstformat.format))
-			tmpformat.format = dstformat.format;
-		else
-			tmpformat.format = SNDRV_PCM_FORMAT_S16;
-		switch (srcformat.format) {
-		case SNDRV_PCM_FORMAT_MU_LAW:
-			err = snd_pcm_plugin_build_mulaw(plug,
-							 &srcformat, &tmpformat,
-							 &plugin);
-			break;
-		default:
+	if (! rate_match(srcformat.rate, dstformat.rate) &&
+	    ! snd_pcm_format_linear(srcformat.format)) {
+		if (srcformat.format != SNDRV_PCM_FORMAT_MU_LAW)
 			return -EINVAL;
-		}
-		pdprintf("format change: src=%i, dst=%i returns %i\n", srcformat.format, tmpformat.format, err);
+		tmpformat.format = SNDRV_PCM_FORMAT_S16;
+		err = snd_pcm_plugin_build_mulaw(plug,
+						 &srcformat, &tmpformat,
+						 &plugin);
 		if (err < 0)
 			return err;
 		err = snd_pcm_plugin_append(plugin);
@@ -460,35 +419,11 @@
 
 	/* channels reduction */
 	if (srcformat.channels > dstformat.channels) {
-		int sv = srcformat.channels;
-		int dv = dstformat.channels;
-		int *ttable = kcalloc(dv * sv, sizeof(*ttable), GFP_KERNEL);
-		if (ttable == NULL)
-			return -ENOMEM;
-#if 1
-		if (sv == 2 && dv == 1) {
-			ttable[0] = HALF;
-			ttable[1] = HALF;
-		} else
-#endif
-		{
-			int v;
-			for (v = 0; v < dv; ++v)
-				ttable[v * sv + v] = FULL;
-		}
 		tmpformat.channels = dstformat.channels;
-		if (rate_match(srcformat.rate, dstformat.rate) &&
-		    snd_pcm_format_linear(dstformat.format))
-			tmpformat.format = dstformat.format;
-		err = snd_pcm_plugin_build_route(plug,
-						 &srcformat, &tmpformat,
-						 ttable, &plugin);
-		kfree(ttable);
+		err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin);
 		pdprintf("channels reduction: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
-		if (err < 0) {
-			snd_pcm_plugin_free(plugin);
+		if (err < 0)
 			return err;
-		}
 		err = snd_pcm_plugin_append(plugin);
 		if (err < 0) {
 			snd_pcm_plugin_free(plugin);
@@ -500,18 +435,29 @@
 
 	/* rate resampling */
 	if (!rate_match(srcformat.rate, dstformat.rate)) {
+		if (srcformat.format != SNDRV_PCM_FORMAT_S16) {
+			/* convert to S16 for resampling */
+			tmpformat.format = SNDRV_PCM_FORMAT_S16;
+			err = snd_pcm_plugin_build_linear(plug,
+							  &srcformat, &tmpformat,
+							  &plugin);
+			if (err < 0)
+				return err;
+			err = snd_pcm_plugin_append(plugin);
+			if (err < 0) {
+				snd_pcm_plugin_free(plugin);
+				return err;
+			}
+			srcformat = tmpformat;
+			src_access = dst_access;
+		}
 		tmpformat.rate = dstformat.rate;
-		if (srcformat.channels == dstformat.channels &&
-		    snd_pcm_format_linear(dstformat.format))
-			tmpformat.format = dstformat.format;
         	err = snd_pcm_plugin_build_rate(plug,
         					&srcformat, &tmpformat,
 						&plugin);
 		pdprintf("rate down resampling: src=%i, dst=%i returns %i\n", srcformat.rate, tmpformat.rate, err);
-		if (err < 0) {
-			snd_pcm_plugin_free(plugin);
+		if (err < 0)
 			return err;
-		}      					    
 		err = snd_pcm_plugin_append(plugin);
 		if (err < 0) {
 			snd_pcm_plugin_free(plugin);
@@ -521,56 +467,11 @@
 		src_access = dst_access;
         }
 
-	/* channels extension  */
-	if (srcformat.channels < dstformat.channels) {
-		int sv = srcformat.channels;
-		int dv = dstformat.channels;
-		int *ttable = kcalloc(dv * sv, sizeof(*ttable), GFP_KERNEL);
-		if (ttable == NULL)
-			return -ENOMEM;
-#if 0
-		{
-			int v;
-			for (v = 0; v < sv; ++v)
-				ttable[v * sv + v] = FULL;
-		}
-#else
-		{
-			/* Playback is spreaded on all channels */
-			int vd, vs;
-			for (vd = 0, vs = 0; vd < dv; ++vd) {
-				ttable[vd * sv + vs] = FULL;
-				vs++;
-				if (vs == sv)
-					vs = 0;
-			}
-		}
-#endif
-		tmpformat.channels = dstformat.channels;
-		if (snd_pcm_format_linear(dstformat.format))
-			tmpformat.format = dstformat.format;
-		err = snd_pcm_plugin_build_route(plug,
-						 &srcformat, &tmpformat,
-						 ttable, &plugin);
-		kfree(ttable);
-		pdprintf("channels extension: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
-		if (err < 0) {
-			snd_pcm_plugin_free(plugin);
-			return err;
-		}      					    
-		err = snd_pcm_plugin_append(plugin);
-		if (err < 0) {
-			snd_pcm_plugin_free(plugin);
-			return err;
-		}
-		srcformat = tmpformat;
-		src_access = dst_access;
-	}
-
 	/* format change */
 	if (srcformat.format != dstformat.format) {
 		tmpformat.format = dstformat.format;
-		if (tmpformat.format == SNDRV_PCM_FORMAT_MU_LAW) {
+		if (srcformat.format == SNDRV_PCM_FORMAT_MU_LAW ||
+		    tmpformat.format == SNDRV_PCM_FORMAT_MU_LAW) {
 			err = snd_pcm_plugin_build_mulaw(plug,
 							 &srcformat, &tmpformat,
 							 &plugin);
@@ -595,6 +496,22 @@
 		src_access = dst_access;
 	}
 
+	/* channels extension */
+	if (srcformat.channels < dstformat.channels) {
+		tmpformat.channels = dstformat.channels;
+		err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin);
+		pdprintf("channels extension: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
+		if (err < 0)
+			return err;
+		err = snd_pcm_plugin_append(plugin);
+		if (err < 0) {
+			snd_pcm_plugin_free(plugin);
+			return err;
+		}
+		srcformat = tmpformat;
+		src_access = dst_access;
+	}
+
 	/* de-interleave */
 	if (src_access != dst_access) {
 		err = snd_pcm_plugin_build_copy(plug,
@@ -650,92 +567,6 @@
 	return count;
 }
 
-static int snd_pcm_plug_playback_channels_mask(struct snd_pcm_substream *plug,
-					       unsigned long *client_vmask)
-{
-	struct snd_pcm_plugin *plugin = snd_pcm_plug_last(plug);
-	if (plugin == NULL) {
-		return 0;
-	} else {
-		int schannels = plugin->dst_format.channels;
-		DECLARE_BITMAP(bs, schannels);
-		unsigned long *srcmask;
-		unsigned long *dstmask = bs;
-		int err;
-		bitmap_fill(dstmask, schannels);
-
-		while (1) {
-			err = plugin->src_channels_mask(plugin, dstmask, &srcmask);
-			if (err < 0)
-				return err;
-			dstmask = srcmask;
-			if (plugin->prev == NULL)
-				break;
-			plugin = plugin->prev;
-		}
-		bitmap_and(client_vmask, client_vmask, dstmask, plugin->src_format.channels);
-		return 0;
-	}
-}
-
-static int snd_pcm_plug_playback_disable_useless_channels(struct snd_pcm_substream *plug,
-							  struct snd_pcm_plugin_channel *src_channels)
-{
-	struct snd_pcm_plugin *plugin = snd_pcm_plug_first(plug);
-	unsigned int nchannels = plugin->src_format.channels;
-	DECLARE_BITMAP(bs, nchannels);
-	unsigned long *srcmask = bs;
-	int err;
-	unsigned int channel;
-	for (channel = 0; channel < nchannels; channel++) {
-		if (src_channels[channel].enabled)
-			set_bit(channel, srcmask);
-		else
-			clear_bit(channel, srcmask);
-	}
-	err = snd_pcm_plug_playback_channels_mask(plug, srcmask);
-	if (err < 0)
-		return err;
-	for (channel = 0; channel < nchannels; channel++) {
-		if (!test_bit(channel, srcmask))
-			src_channels[channel].enabled = 0;
-	}
-	return 0;
-}
-
-static int snd_pcm_plug_capture_disable_useless_channels(struct snd_pcm_substream *plug,
-							 struct snd_pcm_plugin_channel *src_channels,
-							 struct snd_pcm_plugin_channel *client_channels)
-{
-	struct snd_pcm_plugin *plugin = snd_pcm_plug_last(plug);
-	unsigned int nchannels = plugin->dst_format.channels;
-	DECLARE_BITMAP(bs, nchannels);
-	unsigned long *dstmask = bs;
-	unsigned long *srcmask;
-	int err;
-	unsigned int channel;
-	for (channel = 0; channel < nchannels; channel++) {
-		if (client_channels[channel].enabled)
-			set_bit(channel, dstmask);
-		else
-			clear_bit(channel, dstmask);
-	}
-	while (plugin) {
-		err = plugin->src_channels_mask(plugin, dstmask, &srcmask);
-		if (err < 0)
-			return err;
-		dstmask = srcmask;
-		plugin = plugin->prev;
-	}
-	plugin = snd_pcm_plug_first(plug);
-	nchannels = plugin->src_format.channels;
-	for (channel = 0; channel < nchannels; channel++) {
-		if (!test_bit(channel, dstmask))
-			src_channels[channel].enabled = 0;
-	}
-	return 0;
-}
-
 snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, struct snd_pcm_plugin_channel *src_channels, snd_pcm_uframes_t size)
 {
 	struct snd_pcm_plugin *plugin, *next;
@@ -743,9 +574,6 @@
 	int err;
 	snd_pcm_sframes_t frames = size;
 
-	if ((err = snd_pcm_plug_playback_disable_useless_channels(plug, src_channels)) < 0)
-		return err;
-	
 	plugin = snd_pcm_plug_first(plug);
 	while (plugin && frames > 0) {
 		if ((next = plugin->next) != NULL) {
@@ -790,10 +618,6 @@
 				return err;
 			}
 			frames = err;
-			if (!plugin->prev) {
-				if ((err = snd_pcm_plug_capture_disable_useless_channels(plug, dst_channels, dst_channels_final)) < 0)
-					return err;
-			}
 		} else {
 			dst_channels = dst_channels_final;
 		}
@@ -916,3 +740,5 @@
 	}
 	return 0;
 }
+
+#endif
diff -urN oldtree/sound/core/oss/pcm_plugin.h newtree/sound/core/oss/pcm_plugin.h
--- oldtree/sound/core/oss/pcm_plugin.h	2006-02-19 11:41:06.691325864 +0000
+++ newtree/sound/core/oss/pcm_plugin.h	2006-02-21 15:58:11.243437296 +0000
@@ -22,12 +22,7 @@
  *
  */
 
-#include <linux/bitmap.h>
-
-static inline unsigned long *bitmap_alloc(unsigned int nbits)
-{
-	return kmalloc(BITS_TO_LONGS(nbits), GFP_KERNEL);
-}
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
 
 #define snd_pcm_plug_stream(plug) ((plug)->stream)
 
@@ -69,12 +64,6 @@
 	snd_pcm_sframes_t (*client_channels)(struct snd_pcm_plugin *plugin,
 					     snd_pcm_uframes_t frames,
 					     struct snd_pcm_plugin_channel **channels);
-	int (*src_channels_mask)(struct snd_pcm_plugin *plugin,
-				 unsigned long *dst_vmask,
-				 unsigned long **src_vmask);
-	int (*dst_channels_mask)(struct snd_pcm_plugin *plugin,
-				 unsigned long *src_vmask,
-				 unsigned long **dst_vmask);
 	snd_pcm_sframes_t (*transfer)(struct snd_pcm_plugin *plugin,
 				      const struct snd_pcm_plugin_channel *src_channels,
 				      struct snd_pcm_plugin_channel *dst_channels,
@@ -90,8 +79,6 @@
 	char *buf;
 	snd_pcm_uframes_t buf_frames;
 	struct snd_pcm_plugin_channel *buf_channels;
-	unsigned long *src_vmask;
-	unsigned long *dst_vmask;
 	char extra_data[0];
 };
 
@@ -128,7 +115,6 @@
 int snd_pcm_plugin_build_route(struct snd_pcm_substream *handle,
 			       struct snd_pcm_plugin_format *src_format,
 			       struct snd_pcm_plugin_format *dst_format,
-			       int *ttable,
 		               struct snd_pcm_plugin **r_plugin);
 int snd_pcm_plugin_build_copy(struct snd_pcm_substream *handle,
 			      struct snd_pcm_plugin_format *src_format,
@@ -181,15 +167,13 @@
 				     void **bufs, snd_pcm_uframes_t frames,
 				     int in_kernel);
 
-#define ROUTE_PLUGIN_RESOLUTION 16
+#else
+
+static inline snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size) { return drv_size; }
+static inline snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t clt_size) { return clt_size; }
+static inline int snd_pcm_plug_slave_format(int format, struct snd_mask *format_mask) { return format; }
 
-int getput_index(int format);
-int copy_index(int format);
-int conv_index(int src_format, int dst_format);
-
-void zero_channel(struct snd_pcm_plugin *plugin,
-		  const struct snd_pcm_plugin_channel *dst_channel,
-		  size_t samples);
+#endif
 
 #ifdef PLUGIN_DEBUG
 #define pdprintf( fmt, args... ) printk( "plugin: " fmt, ##args)
diff -urN oldtree/sound/core/oss/plugin_ops.h newtree/sound/core/oss/plugin_ops.h
--- oldtree/sound/core/oss/plugin_ops.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/core/oss/plugin_ops.h	2006-02-21 15:58:11.244437144 +0000
@@ -362,172 +362,6 @@
 }
 #endif
 
-#if 0
-#ifdef GET32_LABELS
-/* src_wid src_endswap unsigned */
-static void *get32_labels[4 * 2 * 2] = {
-	&&get32_xxx1_1000,	 /*  8h -> 32h */
-	&&get32_xxx1_9000,	 /*  8h ^> 32h */
-	&&get32_xxx1_1000,	 /*  8s -> 32h */
-	&&get32_xxx1_9000,	 /*  8s ^> 32h */
-	&&get32_xx12_1200,	 /* 16h -> 32h */
-	&&get32_xx12_9200,	 /* 16h ^> 32h */
-	&&get32_xx12_2100,	 /* 16s -> 32h */
-	&&get32_xx12_A100,	 /* 16s ^> 32h */
-	&&get32_x123_1230,	 /* 24h -> 32h */
-	&&get32_x123_9230,	 /* 24h ^> 32h */
-	&&get32_123x_3210,	 /* 24s -> 32h */
-	&&get32_123x_B210,	 /* 24s ^> 32h */
-	&&get32_1234_1234,	 /* 32h -> 32h */
-	&&get32_1234_9234,	 /* 32h ^> 32h */
-	&&get32_1234_4321,	 /* 32s -> 32h */
-	&&get32_1234_C321,	 /* 32s ^> 32h */
-};
-#endif
-
-#ifdef GET32_END
-while (0) {
-get32_xxx1_1000: sample = (u_int32_t)as_u8(src) << 24; goto GET32_END;
-get32_xxx1_9000: sample = (u_int32_t)(as_u8(src) ^ 0x80) << 24; goto GET32_END;
-get32_xx12_1200: sample = (u_int32_t)as_u16(src) << 16; goto GET32_END;
-get32_xx12_9200: sample = (u_int32_t)(as_u16(src) ^ 0x8000) << 16; goto GET32_END;
-get32_xx12_2100: sample = (u_int32_t)swab16(as_u16(src)) << 16; goto GET32_END;
-get32_xx12_A100: sample = (u_int32_t)swab16(as_u16(src) ^ 0x80) << 16; goto GET32_END;
-get32_x123_1230: sample = as_u32(src) << 8; goto GET32_END;
-get32_x123_9230: sample = (as_u32(src) << 8) ^ 0x80000000; goto GET32_END;
-get32_123x_3210: sample = swab32(as_u32(src) >> 8); goto GET32_END;
-get32_123x_B210: sample = swab32((as_u32(src) >> 8) ^ 0x80); goto GET32_END;
-get32_1234_1234: sample = as_u32(src); goto GET32_END;
-get32_1234_9234: sample = as_u32(src) ^ 0x80000000; goto GET32_END;
-get32_1234_4321: sample = swab32(as_u32(src)); goto GET32_END;
-get32_1234_C321: sample = swab32(as_u32(src) ^ 0x80); goto GET32_END;
-}
-#endif
-#endif
-
-#ifdef PUT_U32_LABELS
-/* dst_wid dst_endswap unsigned */
-static void *put_u32_labels[4 * 2 * 2] = {
-	&&put_u32_1234_xxx9,	 /* u32h ->  s8h */
-	&&put_u32_1234_xxx1,	 /* u32h ->  u8h */
-	&&put_u32_1234_xxx9,	 /* u32h ->  s8s */
-	&&put_u32_1234_xxx1,	 /* u32h ->  u8s */
-	&&put_u32_1234_xx92,	 /* u32h -> s16h */
-	&&put_u32_1234_xx12,	 /* u32h -> u16h */
-	&&put_u32_1234_xx29,	 /* u32h -> s16s */
-	&&put_u32_1234_xx21,	 /* u32h -> u16s */
-	&&put_u32_1234_x923,	 /* u32h -> s24h */
-	&&put_u32_1234_x123,	 /* u32h -> u24h */
-	&&put_u32_1234_329x,	 /* u32h -> s24s */
-	&&put_u32_1234_321x,	 /* u32h -> u24s */
-	&&put_u32_1234_9234,	 /* u32h -> s32h */
-	&&put_u32_1234_1234,	 /* u32h -> u32h */
-	&&put_u32_1234_4329,	 /* u32h -> s32s */
-	&&put_u32_1234_4321,	 /* u32h -> u32s */
-};
-#endif
-
-#ifdef PUT_U32_END
-while (0) {
-put_u32_1234_xxx1: as_u8(dst) = sample >> 24; goto PUT_U32_END;
-put_u32_1234_xxx9: as_u8(dst) = (sample >> 24) ^ 0x80; goto PUT_U32_END;
-put_u32_1234_xx12: as_u16(dst) = sample >> 16; goto PUT_U32_END;
-put_u32_1234_xx92: as_u16(dst) = (sample >> 16) ^ 0x8000; goto PUT_U32_END;
-put_u32_1234_xx21: as_u16(dst) = swab16(sample >> 16); goto PUT_U32_END;
-put_u32_1234_xx29: as_u16(dst) = swab16(sample >> 16) ^ 0x80; goto PUT_U32_END;
-put_u32_1234_x123: as_u32(dst) = sample >> 8; goto PUT_U32_END;
-put_u32_1234_x923: as_u32(dst) = (sample >> 8) ^ 0x800000; goto PUT_U32_END;
-put_u32_1234_321x: as_u32(dst) = swab32(sample) << 8; goto PUT_U32_END;
-put_u32_1234_329x: as_u32(dst) = (swab32(sample) ^ 0x80) << 8; goto PUT_U32_END;
-put_u32_1234_1234: as_u32(dst) = sample; goto PUT_U32_END;
-put_u32_1234_9234: as_u32(dst) = sample ^ 0x80000000; goto PUT_U32_END;
-put_u32_1234_4321: as_u32(dst) = swab32(sample); goto PUT_U32_END;
-put_u32_1234_4329: as_u32(dst) = swab32(sample) ^ 0x80; goto PUT_U32_END;
-}
-#endif
-
-#ifdef GET_U_LABELS
-/* width endswap unsigned*/
-static void *get_u_labels[4 * 2 * 2] = {
-	&&get_u_s8,	/* s8  ->  u8  */
-	&&get_u_u8,	/* u8  ->  u8  */
-	&&get_u_s8,	/* s8  ->  u8  */
-	&&get_u_u8,	/* u8  ->  u8  */
-	&&get_u_s16h,	/* s16h -> u16h */
-	&&get_u_u16h,	/* u16h -> u16h */
-	&&get_u_s16s,	/* s16s -> u16h */
-	&&get_u_u16s,	/* u16s -> u16h */
-	&&get_u_s24h,	/* s24h -> u32h */
-	&&get_u_u24h,	/* u24h -> u32h */
-	&&get_u_s24s,	/* s24s -> u32h */
-	&&get_u_u24s,	/* u24s -> u32h */
-	&&get_u_s32h,	/* s32h -> u32h */
-	&&get_u_u32h,	/* u32h -> u32h */
-	&&get_u_s32s,	/* s32s -> u32h */
-	&&get_u_u32s,	/* u32s -> u32h */
-};
-#endif
-
-#ifdef GET_U_END
-while (0) {
-get_u_s8: sample = as_u8(src) ^ 0x80; goto GET_U_END;
-get_u_u8: sample = as_u8(src); goto GET_U_END;
-get_u_s16h: sample = as_u16(src) ^ 0x8000; goto GET_U_END;
-get_u_u16h: sample = as_u16(src); goto GET_U_END;
-get_u_s16s: sample = swab16(as_u16(src) ^ 0x80); goto GET_U_END;
-get_u_u16s: sample = swab16(as_u16(src)); goto GET_U_END;
-get_u_s24h: sample = (as_u32(src) ^ 0x800000); goto GET_U_END;
-get_u_u24h: sample = as_u32(src); goto GET_U_END;
-get_u_s24s: sample = swab32(as_u32(src) ^ 0x800000); goto GET_U_END;
-get_u_u24s: sample = swab32(as_u32(src)); goto GET_U_END;
-get_u_s32h: sample = as_u32(src) ^ 0x80000000; goto GET_U_END;
-get_u_u32h: sample = as_u32(src); goto GET_U_END;
-get_u_s32s: sample = swab32(as_u32(src) ^ 0x80); goto GET_U_END;
-get_u_u32s: sample = swab32(as_u32(src)); goto GET_U_END;
-}
-#endif
-
-#if 0
-#ifdef PUT_LABELS
-/* width endswap unsigned */
-static void *put_labels[4 * 2 * 2] = {
-	&&put_s8,	/* s8  ->  s8  */
-	&&put_u8,	/* u8  ->  s8  */
-	&&put_s8,	/* s8  ->  s8  */
-	&&put_u8,	/* u8  ->  s8  */
-	&&put_s16h,	/* s16h -> s16h */
-	&&put_u16h,	/* u16h -> s16h */
-	&&put_s16s,	/* s16s -> s16h */
-	&&put_u16s,	/* u16s -> s16h */
-	&&put_s24h,	/* s24h -> s32h */
-	&&put_u24h,	/* u24h -> s32h */
-	&&put_s24s,	/* s24s -> s32h */
-	&&put_u24s,	/* u24s -> s32h */
-	&&put_s32h,	/* s32h -> s32h */
-	&&put_u32h,	/* u32h -> s32h */
-	&&put_s32s,	/* s32s -> s32h */
-	&&put_u32s,	/* u32s -> s32h */
-};
-#endif
-
-#ifdef PUT_END
-put_s8: as_s8(dst) = sample; goto PUT_END;
-put_u8: as_u8(dst) = sample ^ 0x80; goto PUT_END;
-put_s16h: as_s16(dst) = sample; goto PUT_END;
-put_u16h: as_u16(dst) = sample ^ 0x8000; goto PUT_END;
-put_s16s: as_s16(dst) = swab16(sample); goto PUT_END;
-put_u16s: as_u16(dst) = swab16(sample ^ 0x80); goto PUT_END;
-put_s24h: as_s24(dst) = sample & 0xffffff; goto PUT_END;
-put_u24h: as_u24(dst) = sample ^ 0x80000000; goto PUT_END;
-put_s24s: as_s24(dst) = swab32(sample & 0xffffff); goto PUT_END;
-put_u24s: as_u24(dst) = swab32(sample ^ 0x80); goto PUT_END;
-put_s32h: as_s32(dst) = sample; goto PUT_END;
-put_u32h: as_u32(dst) = sample ^ 0x80000000; goto PUT_END;
-put_s32s: as_s32(dst) = swab32(sample); goto PUT_END;
-put_u32s: as_u32(dst) = swab32(sample ^ 0x80); goto PUT_END;
-#endif
-#endif
-
 #undef as_u8
 #undef as_u16
 #undef as_u32
diff -urN oldtree/sound/core/oss/rate.c newtree/sound/core/oss/rate.c
--- oldtree/sound/core/oss/rate.c	2006-02-19 11:41:06.692325712 +0000
+++ newtree/sound/core/oss/rate.c	2006-02-21 15:58:11.245436992 +0000
@@ -20,6 +20,9 @@
  */
   
 #include <sound/driver.h>
+
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -47,7 +50,6 @@
 	unsigned int pitch;
 	unsigned int pos;
 	rate_f func;
-	int get, put;
 	snd_pcm_sframes_t old_src_frames, old_dst_frames;
 	struct rate_channel channels[0];
 };
@@ -71,21 +73,12 @@
 	unsigned int pos = 0;
 	signed int val;
 	signed short S1, S2;
-	char *src, *dst;
+	signed short *src, *dst;
 	unsigned int channel;
 	int src_step, dst_step;
 	int src_frames1, dst_frames1;
 	struct rate_priv *data = (struct rate_priv *)plugin->extra_data;
 	struct rate_channel *rchannels = data->channels;
-
-#define GET_S16_LABELS
-#define PUT_S16_LABELS
-#include "plugin_ops.h"
-#undef GET_S16_LABELS
-#undef PUT_S16_LABELS
-	void *get = get_s16_labels[data->get];
-	void *put = put_s16_labels[data->put];
-	signed short sample = 0;
 	
 	for (channel = 0; channel < plugin->src_format.channels; channel++) {
 		pos = data->pos;
@@ -98,10 +91,12 @@
 			continue;
 		}
 		dst_channels[channel].enabled = 1;
-		src = (char *)src_channels[channel].area.addr + src_channels[channel].area.first / 8;
-		dst = (char *)dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
-		src_step = src_channels[channel].area.step / 8;
-		dst_step = dst_channels[channel].area.step / 8;
+		src = (signed short *)src_channels[channel].area.addr +
+			src_channels[channel].area.first / 8 / 2;
+		dst = (signed short *)dst_channels[channel].area.addr +
+			dst_channels[channel].area.first / 8 / 2;
+		src_step = src_channels[channel].area.step / 8 / 2;
+		dst_step = dst_channels[channel].area.step / 8 / 2;
 		src_frames1 = src_frames;
 		dst_frames1 = dst_frames;
 		while (dst_frames1-- > 0) {
@@ -109,12 +104,7 @@
 				pos &= R_MASK;
 				S1 = S2;
 				if (src_frames1-- > 0) {
-					goto *get;
-#define GET_S16_END after_get
-#include "plugin_ops.h"
-#undef GET_S16_END
-				after_get:
-					S2 = sample;
+					S2 = *src;
 					src += src_step;
 				}
 			}
@@ -123,12 +113,7 @@
 				val = -32768;
 			else if (val > 32767)
 				val = 32767;
-			sample = val;
-			goto *put;
-#define PUT_S16_END after_put
-#include "plugin_ops.h"
-#undef PUT_S16_END
-		after_put:
+			*dst = val;
 			dst += dst_step;
 			pos += data->pitch;
 		}
@@ -147,21 +132,12 @@
 	unsigned int pos = 0;
 	signed int val;
 	signed short S1, S2;
-	char *src, *dst;
+	signed short *src, *dst;
 	unsigned int channel;
 	int src_step, dst_step;
 	int src_frames1, dst_frames1;
 	struct rate_priv *data = (struct rate_priv *)plugin->extra_data;
 	struct rate_channel *rchannels = data->channels;
-	
-#define GET_S16_LABELS
-#define PUT_S16_LABELS
-#include "plugin_ops.h"
-#undef GET_S16_LABELS
-#undef PUT_S16_LABELS
-	void *get = get_s16_labels[data->get];
-	void *put = put_s16_labels[data->put];
-	signed short sample = 0;
 
 	for (channel = 0; channel < plugin->src_format.channels; ++channel) {
 		pos = data->pos;
@@ -174,21 +150,18 @@
 			continue;
 		}
 		dst_channels[channel].enabled = 1;
-		src = (char *)src_channels[channel].area.addr + src_channels[channel].area.first / 8;
-		dst = (char *)dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
-		src_step = src_channels[channel].area.step / 8;
-		dst_step = dst_channels[channel].area.step / 8;
+		src = (signed short *)src_channels[channel].area.addr +
+			src_channels[channel].area.first / 8 / 2;
+		dst = (signed short *)dst_channels[channel].area.addr +
+			dst_channels[channel].area.first / 8 / 2;
+		src_step = src_channels[channel].area.step / 8 / 2;
+		dst_step = dst_channels[channel].area.step / 8 / 2;
 		src_frames1 = src_frames;
 		dst_frames1 = dst_frames;
 		while (dst_frames1 > 0) {
 			S1 = S2;
 			if (src_frames1-- > 0) {
-				goto *get;
-#define GET_S16_END after_get
-#include "plugin_ops.h"
-#undef GET_S16_END
-			after_get:
-				S2 = sample;
+				S1 = *src;
 				src += src_step;
 			}
 			if (pos & ~R_MASK) {
@@ -198,12 +171,7 @@
 					val = -32768;
 				else if (val > 32767)
 					val = 32767;
-				sample = val;
-				goto *put;
-#define PUT_S16_END after_put
-#include "plugin_ops.h"
-#undef PUT_S16_END
-			after_put:
+				*dst = val;
 				dst += dst_step;
 				dst_frames1--;
 			}
@@ -343,8 +311,8 @@
 
 	snd_assert(src_format->channels == dst_format->channels, return -ENXIO);
 	snd_assert(src_format->channels > 0, return -ENXIO);
-	snd_assert(snd_pcm_format_linear(src_format->format) != 0, return -ENXIO);
-	snd_assert(snd_pcm_format_linear(dst_format->format) != 0, return -ENXIO);
+	snd_assert(src_format->format == SNDRV_PCM_FORMAT_S16, return -ENXIO);
+	snd_assert(dst_format->format == SNDRV_PCM_FORMAT_S16, return -ENXIO);
 	snd_assert(src_format->rate != dst_format->rate, return -ENXIO);
 
 	err = snd_pcm_plugin_build(plug, "rate conversion",
@@ -355,11 +323,6 @@
 	if (err < 0)
 		return err;
 	data = (struct rate_priv *)plugin->extra_data;
-	data->get = getput_index(src_format->format);
-	snd_assert(data->get >= 0 && data->get < 4*2*2, return -EINVAL);
-	data->put = getput_index(dst_format->format);
-	snd_assert(data->put >= 0 && data->put < 4*2*2, return -EINVAL);
-
 	if (src_format->rate < dst_format->rate) {
 		data->pitch = ((src_format->rate << SHIFT) + (dst_format->rate >> 1)) / dst_format->rate;
 		data->func = resample_expand;
@@ -377,3 +340,5 @@
 	*r_plugin = plugin;
 	return 0;
 }
+
+#endif
diff -urN oldtree/sound/core/oss/route.c newtree/sound/core/oss/route.c
--- oldtree/sound/core/oss/route.c	2006-02-19 11:41:06.693325560 +0000
+++ newtree/sound/core/oss/route.c	2006-02-21 15:58:11.246436840 +0000
@@ -1,5 +1,5 @@
 /*
- *  Attenuated route Plug-In
+ *  Route Plug-In
  *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
  *
  *
@@ -20,502 +20,93 @@
  */
 
 #include <sound/driver.h>
+
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include "pcm_plugin.h"
 
-/* The best possible hack to support missing optimization in gcc 2.7.2.3 */
-#if ROUTE_PLUGIN_RESOLUTION & (ROUTE_PLUGIN_RESOLUTION - 1) != 0
-#define div(a) a /= ROUTE_PLUGIN_RESOLUTION
-#elif ROUTE_PLUGIN_RESOLUTION == 16
-#define div(a) a >>= 4
-#else
-#error "Add some code here"
-#endif
-
-struct ttable_dst;
-
-typedef void (*route_channel_f)(struct snd_pcm_plugin *plugin,
-				const struct snd_pcm_plugin_channel *src_channels,
-				struct snd_pcm_plugin_channel *dst_channel,
-				struct ttable_dst *ttable, snd_pcm_uframes_t frames);
-
-struct ttable_src {
-	int channel;
-	int as_int;
-};
-
-struct ttable_dst {
-	int att;	/* Attenuated */
-	unsigned int nsrcs;
-	struct ttable_src *srcs;
-	route_channel_f func;
-};
-
-struct route_priv {
-	enum {R_UINT32=0, R_UINT64=1} sum_type;
-	int get, put;
-	int conv;
-	int src_sample_size;
-	struct ttable_dst ttable[0];
-};
-
-union sum {
-	u_int32_t as_uint32;
-	u_int64_t as_uint64;
-};
-
-
-static void route_to_channel_from_zero(struct snd_pcm_plugin *plugin,
-				       const struct snd_pcm_plugin_channel *src_channels,
-				       struct snd_pcm_plugin_channel *dst_channel,
-				       struct ttable_dst *ttable,
-				       snd_pcm_uframes_t frames)
-{
-	if (dst_channel->wanted)
-		snd_pcm_area_silence(&dst_channel->area, 0, frames, plugin->dst_format.format);
-	dst_channel->enabled = 0;
-}
-
-static void route_to_channel_from_one(struct snd_pcm_plugin *plugin,
-				      const struct snd_pcm_plugin_channel *src_channels,
-				      struct snd_pcm_plugin_channel *dst_channel,
-				      struct ttable_dst *ttable,
-				      snd_pcm_uframes_t frames)
+static void zero_areas(struct snd_pcm_plugin_channel *dvp, int ndsts,
+		       snd_pcm_uframes_t frames, int format)
 {
-#define CONV_LABELS
-#include "plugin_ops.h"
-#undef CONV_LABELS
-	struct route_priv *data = (struct route_priv *)plugin->extra_data;
-	void *conv;
-	const struct snd_pcm_plugin_channel *src_channel = NULL;
-	unsigned int srcidx;
-	char *src, *dst;
-	int src_step, dst_step;
-	for (srcidx = 0; srcidx < ttable->nsrcs; ++srcidx) {
-		src_channel = &src_channels[ttable->srcs[srcidx].channel];
-		if (src_channel->area.addr != NULL)
-			break;
-	}
-	if (srcidx == ttable->nsrcs) {
-		route_to_channel_from_zero(plugin, src_channels, dst_channel, ttable, frames);
-		return;
-	}
-
-	dst_channel->enabled = 1;
-	conv = conv_labels[data->conv];
-	src = src_channel->area.addr + src_channel->area.first / 8;
-	src_step = src_channel->area.step / 8;
-	dst = dst_channel->area.addr + dst_channel->area.first / 8;
-	dst_step = dst_channel->area.step / 8;
-	while (frames-- > 0) {
-		goto *conv;
-#define CONV_END after
-#include "plugin_ops.h"
-#undef CONV_END
-	after:
-		src += src_step;
-		dst += dst_step;
+	int dst = 0;
+	for (; dst < ndsts; ++dst) {
+		if (dvp->wanted)
+			snd_pcm_area_silence(&dvp->area, 0, frames, format);
+		dvp->enabled = 0;
+		dvp++;
 	}
 }
 
-static void route_to_channel(struct snd_pcm_plugin *plugin,
-			     const struct snd_pcm_plugin_channel *src_channels,
+static inline void copy_area(const struct snd_pcm_plugin_channel *src_channel,
 			     struct snd_pcm_plugin_channel *dst_channel,
-			     struct ttable_dst *ttable, snd_pcm_uframes_t frames)
+			     snd_pcm_uframes_t frames, int format)
 {
-#define GET_U_LABELS
-#define PUT_U32_LABELS
-#include "plugin_ops.h"
-#undef GET_U_LABELS
-#undef PUT_U32_LABELS
-	static void *zero_labels[2] = { &&zero_int32, &&zero_int64 };
-	/* sum_type att */
-	static void *add_labels[2 * 2] = { &&add_int32_noatt, &&add_int32_att,
-				    &&add_int64_noatt, &&add_int64_att,
-	};
-	/* sum_type att shift */
-	static void *norm_labels[2 * 2 * 4] = { NULL,
-					 &&norm_int32_8_noatt,
-					 &&norm_int32_16_noatt,
-					 &&norm_int32_24_noatt,
-					 NULL,
-					 &&norm_int32_8_att,
-					 &&norm_int32_16_att,
-					 &&norm_int32_24_att,
-					 &&norm_int64_0_noatt,
-					 &&norm_int64_8_noatt,
-					 &&norm_int64_16_noatt,
-					 &&norm_int64_24_noatt,
-					 &&norm_int64_0_att,
-					 &&norm_int64_8_att,
-					 &&norm_int64_16_att,
-					 &&norm_int64_24_att,
-	};
-	struct route_priv *data = (struct route_priv *)plugin->extra_data;
-	void *zero, *get, *add, *norm, *put_u32;
-	int nsrcs = ttable->nsrcs;
-	char *dst;
-	int dst_step;
-	char *srcs[nsrcs];
-	int src_steps[nsrcs];
-	struct ttable_src src_tt[nsrcs];
-	u_int32_t sample = 0;
-	int srcidx, srcidx1 = 0;
-	for (srcidx = 0; srcidx < nsrcs; ++srcidx) {
-		const struct snd_pcm_plugin_channel *src_channel = &src_channels[ttable->srcs[srcidx].channel];
-		if (!src_channel->enabled)
-			continue;
-		srcs[srcidx1] = src_channel->area.addr + src_channel->area.first / 8;
-		src_steps[srcidx1] = src_channel->area.step / 8;
-		src_tt[srcidx1] = ttable->srcs[srcidx];
-		srcidx1++;
-	}
-	nsrcs = srcidx1;
-	if (nsrcs == 0) {
-		route_to_channel_from_zero(plugin, src_channels, dst_channel, ttable, frames);
-		return;
-	} else if (nsrcs == 1 && src_tt[0].as_int == ROUTE_PLUGIN_RESOLUTION) {
-		route_to_channel_from_one(plugin, src_channels, dst_channel, ttable, frames);
-		return;
-	}
-
 	dst_channel->enabled = 1;
-	zero = zero_labels[data->sum_type];
-	get = get_u_labels[data->get];
-	add = add_labels[data->sum_type * 2 + ttable->att];
-	norm = norm_labels[data->sum_type * 8 + ttable->att * 4 + 4 - data->src_sample_size];
-	put_u32 = put_u32_labels[data->put];
-	dst = dst_channel->area.addr + dst_channel->area.first / 8;
-	dst_step = dst_channel->area.step / 8;
-
-	while (frames-- > 0) {
-		struct ttable_src *ttp = src_tt;
-		union sum sum;
-
-		/* Zero sum */
-		goto *zero;
-	zero_int32:
-		sum.as_uint32 = 0;
-		goto zero_end;
-	zero_int64: 
-		sum.as_uint64 = 0;
-		goto zero_end;
-	zero_end:
-		for (srcidx = 0; srcidx < nsrcs; ++srcidx) {
-			char *src = srcs[srcidx];
-			
-			/* Get sample */
-			goto *get;
-#define GET_U_END after_get
-#include "plugin_ops.h"
-#undef GET_U_END
-		after_get:
-
-			/* Sum */
-			goto *add;
-		add_int32_att:
-			sum.as_uint32 += sample * ttp->as_int;
-			goto after_sum;
-		add_int32_noatt:
-			if (ttp->as_int)
-				sum.as_uint32 += sample;
-			goto after_sum;
-		add_int64_att:
-			sum.as_uint64 += (u_int64_t) sample * ttp->as_int;
-			goto after_sum;
-		add_int64_noatt:
-			if (ttp->as_int)
-				sum.as_uint64 += sample;
-			goto after_sum;
-		after_sum:
-			srcs[srcidx] += src_steps[srcidx];
-			ttp++;
-		}
-		
-		/* Normalization */
-		goto *norm;
-	norm_int32_8_att:
-		sum.as_uint64 = sum.as_uint32;
-	norm_int64_8_att:
-		sum.as_uint64 <<= 8;
-	norm_int64_0_att:
-		div(sum.as_uint64);
-		goto norm_int;
-
-	norm_int32_16_att:
-		sum.as_uint64 = sum.as_uint32;
-	norm_int64_16_att:
-		sum.as_uint64 <<= 16;
-		div(sum.as_uint64);
-		goto norm_int;
-
-	norm_int32_24_att:
-		sum.as_uint64 = sum.as_uint32;
-	norm_int64_24_att:
-		sum.as_uint64 <<= 24;
-		div(sum.as_uint64);
-		goto norm_int;
-
-	norm_int32_8_noatt:
-		sum.as_uint64 = sum.as_uint32;
-	norm_int64_8_noatt:
-		sum.as_uint64 <<= 8;
-		goto norm_int;
-
-	norm_int32_16_noatt:
-		sum.as_uint64 = sum.as_uint32;
-	norm_int64_16_noatt:
-		sum.as_uint64 <<= 16;
-		goto norm_int;
-
-	norm_int32_24_noatt:
-		sum.as_uint64 = sum.as_uint32;
-	norm_int64_24_noatt:
-		sum.as_uint64 <<= 24;
-		goto norm_int;
-
-	norm_int64_0_noatt:
-	norm_int:
-		if (sum.as_uint64 > (u_int32_t)0xffffffff)
-			sample = (u_int32_t)0xffffffff;
-		else
-			sample = sum.as_uint64;
-		goto after_norm;
-
-	after_norm:
-		
-		/* Put sample */
-		goto *put_u32;
-#define PUT_U32_END after_put_u32
-#include "plugin_ops.h"
-#undef PUT_U32_END
-	after_put_u32:
-		
-		dst += dst_step;
-	}
-}
-
-static int route_src_channels_mask(struct snd_pcm_plugin *plugin,
-				   unsigned long *dst_vmask,
-				   unsigned long **src_vmask)
-{
-	struct route_priv *data = (struct route_priv *)plugin->extra_data;
-	int schannels = plugin->src_format.channels;
-	int dchannels = plugin->dst_format.channels;
-	unsigned long *vmask = plugin->src_vmask;
-	int channel;
-	struct ttable_dst *dp = data->ttable;
-	bitmap_zero(vmask, schannels);
-	for (channel = 0; channel < dchannels; channel++, dp++) {
-		unsigned int src;
-		struct ttable_src *sp;
-		if (!test_bit(channel, dst_vmask))
-			continue;
-		sp = dp->srcs;
-		for (src = 0; src < dp->nsrcs; src++, sp++)
-			set_bit(sp->channel, vmask);
-	}
-	*src_vmask = vmask;
-	return 0;
-}
-
-static int route_dst_channels_mask(struct snd_pcm_plugin *plugin,
-				   unsigned long *src_vmask,
-				   unsigned long **dst_vmask)
-{
-	struct route_priv *data = (struct route_priv *)plugin->extra_data;
-	int dchannels = plugin->dst_format.channels;
-	unsigned long *vmask = plugin->dst_vmask;
-	int channel;
-	struct ttable_dst *dp = data->ttable;
-	bitmap_zero(vmask, dchannels);
-	for (channel = 0; channel < dchannels; channel++, dp++) {
-		unsigned int src;
-		struct ttable_src *sp;
-		sp = dp->srcs;
-		for (src = 0; src < dp->nsrcs; src++, sp++) {
-			if (test_bit(sp->channel, src_vmask)) {
-				set_bit(channel, vmask);
-				break;
-			}
-		}
-	}
-	*dst_vmask = vmask;
-	return 0;
-}
-
-static void route_free(struct snd_pcm_plugin *plugin)
-{
-	struct route_priv *data = (struct route_priv *)plugin->extra_data;
-	unsigned int dst_channel;
-	for (dst_channel = 0; dst_channel < plugin->dst_format.channels; ++dst_channel) {
-		kfree(data->ttable[dst_channel].srcs);
-	}
-}
-
-static int route_load_ttable(struct snd_pcm_plugin *plugin, 
-			     const int *src_ttable)
-{
-	struct route_priv *data;
-	unsigned int src_channel, dst_channel;
-	const int *sptr;
-	struct ttable_dst *dptr;
-	if (src_ttable == NULL)
-		return 0;
-	data = (struct route_priv *)plugin->extra_data;
-	dptr = data->ttable;
-	sptr = src_ttable;
-	plugin->private_free = route_free;
-	for (dst_channel = 0; dst_channel < plugin->dst_format.channels; ++dst_channel) {
-		int t = 0;
-		int att = 0;
-		int nsrcs = 0;
-		struct ttable_src srcs[plugin->src_format.channels];
-		for (src_channel = 0; src_channel < plugin->src_format.channels; ++src_channel) {
-			snd_assert(*sptr >= 0 || *sptr <= FULL, return -ENXIO);
-			if (*sptr != 0) {
-				srcs[nsrcs].channel = src_channel;
-				srcs[nsrcs].as_int = *sptr;
-				if (*sptr != FULL)
-					att = 1;
-				t += *sptr;
-				nsrcs++;
-			}
-			sptr++;
-		}
-		dptr->att = att;
-		dptr->nsrcs = nsrcs;
-		if (nsrcs == 0)
-			dptr->func = route_to_channel_from_zero;
-		else if (nsrcs == 1 && !att)
-			dptr->func = route_to_channel_from_one;
-		else
-			dptr->func = route_to_channel;
-		if (nsrcs > 0) {
-                        int srcidx;
-			dptr->srcs = kcalloc(nsrcs, sizeof(*srcs), GFP_KERNEL);
-                        for(srcidx = 0; srcidx < nsrcs; srcidx++)
-				dptr->srcs[srcidx] = srcs[srcidx];
-		} else
-			dptr->srcs = NULL;
-		dptr++;
-	}
-	return 0;
+	snd_pcm_area_copy(&src_channel->area, 0, &dst_channel->area, 0, frames, format);
 }
 
 static snd_pcm_sframes_t route_transfer(struct snd_pcm_plugin *plugin,
-			      const struct snd_pcm_plugin_channel *src_channels,
-			      struct snd_pcm_plugin_channel *dst_channels,
-			      snd_pcm_uframes_t frames)
+					const struct snd_pcm_plugin_channel *src_channels,
+					struct snd_pcm_plugin_channel *dst_channels,
+					snd_pcm_uframes_t frames)
 {
-	struct route_priv *data;
-	int src_nchannels, dst_nchannels;
-	int dst_channel;
-	struct ttable_dst *ttp;
+	int nsrcs, ndsts, dst;
 	struct snd_pcm_plugin_channel *dvp;
+	int format;
 
 	snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
 	if (frames == 0)
 		return 0;
-	data = (struct route_priv *)plugin->extra_data;
 
-	src_nchannels = plugin->src_format.channels;
-	dst_nchannels = plugin->dst_format.channels;
+	nsrcs = plugin->src_format.channels;
+	ndsts = plugin->dst_format.channels;
 
-#ifdef CONFIG_SND_DEBUG
-	{
-		int src_channel;
-		for (src_channel = 0; src_channel < src_nchannels; ++src_channel) {
-			snd_assert(src_channels[src_channel].area.first % 8 == 0 ||
-				   src_channels[src_channel].area.step % 8 == 0,
-				   return -ENXIO);
-		}
-		for (dst_channel = 0; dst_channel < dst_nchannels; ++dst_channel) {
-			snd_assert(dst_channels[dst_channel].area.first % 8 == 0 ||
-				   dst_channels[dst_channel].area.step % 8 == 0,
-				   return -ENXIO);
+	format = plugin->dst_format.format;
+	dvp = dst_channels;
+	if (nsrcs <= 1) {
+		/* expand to all channels */
+		for (dst = 0; dst < ndsts; ++dst) {
+			copy_area(src_channels, dvp, frames, format);
+			dvp++;
 		}
+		return frames;
 	}
-#endif
 
-	ttp = data->ttable;
-	dvp = dst_channels;
-	for (dst_channel = 0; dst_channel < dst_nchannels; ++dst_channel) {
-		ttp->func(plugin, src_channels, dvp, ttp, frames);
+	for (dst = 0; dst < ndsts && dst < nsrcs; ++dst) {
+		copy_area(src_channels, dvp, frames, format);
 		dvp++;
-		ttp++;
+		src_channels++;
 	}
+	if (dst < ndsts)
+		zero_areas(dvp, ndsts - dst, frames, format);
 	return frames;
 }
 
-int getput_index(int format)
-{
-	int sign, width, endian;
-	sign = !snd_pcm_format_signed(format);
-	width = snd_pcm_format_width(format) / 8 - 1;
-	if (width < 0 || width > 3) {
-		snd_printk(KERN_ERR "snd-pcm-oss: invalid format %d\n", format);
-		width = 0;
-	}
-#ifdef SNDRV_LITTLE_ENDIAN
-	endian = snd_pcm_format_big_endian(format);
-#else
-	endian = snd_pcm_format_little_endian(format);
-#endif
-	if (endian < 0)
-		endian = 0;
-	return width * 4 + endian * 2 + sign;
-}
-
 int snd_pcm_plugin_build_route(struct snd_pcm_substream *plug,
 			       struct snd_pcm_plugin_format *src_format,
 			       struct snd_pcm_plugin_format *dst_format,
-			       int *ttable,
 			       struct snd_pcm_plugin **r_plugin)
 {
-	struct route_priv *data;
 	struct snd_pcm_plugin *plugin;
 	int err;
 
 	snd_assert(r_plugin != NULL, return -ENXIO);
 	*r_plugin = NULL;
 	snd_assert(src_format->rate == dst_format->rate, return -ENXIO);
-	snd_assert(snd_pcm_format_linear(src_format->format) != 0 &&
-		   snd_pcm_format_linear(dst_format->format) != 0,
-		   return -ENXIO);
-
-	err = snd_pcm_plugin_build(plug, "attenuated route conversion",
-				   src_format, dst_format,
-				   sizeof(struct route_priv) +
-				   sizeof(data->ttable[0]) * dst_format->channels,
-				   &plugin);
+	snd_assert(src_format->format == dst_format->format, return -ENXIO);
+
+	err = snd_pcm_plugin_build(plug, "route conversion",
+				   src_format, dst_format, 0, &plugin);
 	if (err < 0)
 		return err;
 
-	data = (struct route_priv *)plugin->extra_data;
-
-	data->get = getput_index(src_format->format);
-	snd_assert(data->get >= 0 && data->get < 4*2*2, return -EINVAL);
-	data->put = getput_index(dst_format->format);
-	snd_assert(data->get >= 0 && data->get < 4*2*2, return -EINVAL);
-	data->conv = conv_index(src_format->format, dst_format->format);
-
-	if (snd_pcm_format_width(src_format->format) == 32)
-		data->sum_type = R_UINT64;
-	else
-		data->sum_type = R_UINT32;
-	data->src_sample_size = snd_pcm_format_width(src_format->format) / 8;
-
-	if ((err = route_load_ttable(plugin, ttable)) < 0) {
-		snd_pcm_plugin_free(plugin);
-		return err;
-	}
 	plugin->transfer = route_transfer;
-	plugin->src_channels_mask = route_src_channels_mask;
-	plugin->dst_channels_mask = route_dst_channels_mask;
 	*r_plugin = plugin;
 	return 0;
 }
+
+#endif
diff -urN oldtree/sound/core/pcm.c newtree/sound/core/pcm.c
--- oldtree/sound/core/pcm.c	2006-02-19 11:41:06.698324800 +0000
+++ newtree/sound/core/pcm.c	2006-02-21 15:58:11.247436688 +0000
@@ -23,6 +23,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/time.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/pcm.h>
@@ -35,7 +36,7 @@
 
 static LIST_HEAD(snd_pcm_devices);
 static LIST_HEAD(snd_pcm_notify_list);
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
 
 static int snd_pcm_free(struct snd_pcm *pcm);
 static int snd_pcm_dev_free(struct snd_device *device);
@@ -67,7 +68,7 @@
 
 			if (get_user(device, (int __user *)arg))
 				return -EFAULT;
-			down(&register_mutex);
+			mutex_lock(&register_mutex);
 			device = device < 0 ? 0 : device + 1;
 			while (device < SNDRV_PCM_DEVICES) {
 				if (snd_pcm_search(card, device))
@@ -76,7 +77,7 @@
 			}
 			if (device == SNDRV_PCM_DEVICES)
 				device = -1;
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			if (put_user(device, (int __user *)arg))
 				return -EFAULT;
 			return 0;
@@ -100,7 +101,7 @@
 				return -EINVAL;
 			if (get_user(subdevice, &info->subdevice))
 				return -EFAULT;
-			down(&register_mutex);
+			mutex_lock(&register_mutex);
 			pcm = snd_pcm_search(card, device);
 			if (pcm == NULL) {
 				err = -ENXIO;
@@ -125,7 +126,7 @@
 			}
 			err = snd_pcm_info_user(substream, info);
 		_error:
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			return err;
 		}
 	case SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE:
@@ -140,6 +141,9 @@
 	}
 	return -ENOIOCTLCMD;
 }
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_SND_VERBOSE_PROCFS)
+
 #define STATE(v) [SNDRV_PCM_STATE_##v] = #v
 #define STREAM(v) [SNDRV_PCM_STREAM_##v] = #v
 #define READY(v) [SNDRV_PCM_READY_##v] = #v
@@ -197,7 +201,6 @@
 	return snd_pcm_format_names[format];
 }
 
-#ifdef CONFIG_PROC_FS
 static char *snd_pcm_stream_names[] = {
 	STREAM(PLAYBACK),
 	STREAM(CAPTURE),
@@ -260,6 +263,7 @@
 
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
 #include <linux/soundcard.h>
+
 static const char *snd_pcm_oss_format_name(int format)
 {
 	switch (format) {
@@ -622,7 +626,7 @@
 	struct snd_pcm_substream *substream, *prev;
 
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
-	init_MUTEX(&pstr->oss.setup_mutex);
+	mutex_init(&pstr->oss.setup_mutex);
 #endif
 	pstr->stream = stream;
 	pstr->pcm = pcm;
@@ -716,7 +720,7 @@
 		snd_pcm_free(pcm);
 		return err;
 	}
-	init_MUTEX(&pcm->open_mutex);
+	mutex_init(&pcm->open_mutex);
 	init_waitqueue_head(&pcm->open_wait);
 	if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) {
 		snd_pcm_free(pcm);
@@ -902,9 +906,9 @@
 	struct snd_pcm *pcm = device->device_data;
 
 	snd_assert(pcm != NULL && device != NULL, return -ENXIO);
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	if (snd_pcm_search(pcm->card, pcm->device)) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -EBUSY;
 	}
 	list_add_tail(&pcm->list, &snd_pcm_devices);
@@ -928,7 +932,7 @@
 					       pcm, str)) < 0)
 		{
 			list_del(&pcm->list);
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			return err;
 		}
 		for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
@@ -939,7 +943,7 @@
 		notify = list_entry(list, struct snd_pcm_notify, list);
 		notify->n_register(pcm);
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return 0;
 }
 
@@ -950,7 +954,7 @@
 	struct snd_pcm_substream *substream;
 	int cidx;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	list_del_init(&pcm->list);
 	for (cidx = 0; cidx < 2; cidx++)
 		for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
@@ -961,7 +965,7 @@
 		notify = list_entry(list, struct snd_pcm_notify, list);
 		notify->n_disconnect(pcm);
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return 0;
 }
 
@@ -973,7 +977,7 @@
 	struct snd_pcm *pcm = device->device_data;
 
 	snd_assert(pcm != NULL, return -ENXIO);
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	list_del(&pcm->list);
 	for (cidx = 0; cidx < 2; cidx++) {
 		devtype = -1;
@@ -994,7 +998,7 @@
 		notify = list_entry(list, struct snd_pcm_notify, list);
 		notify->n_unregister(pcm);
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return snd_pcm_free(pcm);
 }
 
@@ -1003,7 +1007,7 @@
 	struct list_head *p;
 
 	snd_assert(notify != NULL && notify->n_register != NULL && notify->n_unregister != NULL, return -EINVAL);
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	if (nfree) {
 		list_del(&notify->list);
 		list_for_each(p, &snd_pcm_devices)
@@ -1014,7 +1018,7 @@
 		list_for_each(p, &snd_pcm_devices)
 			notify->n_register(list_entry(p, struct snd_pcm, list));
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return 0;
 }
 
@@ -1029,7 +1033,7 @@
 	struct list_head *p;
 	struct snd_pcm *pcm;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	list_for_each(p, &snd_pcm_devices) {
 		pcm = list_entry(p, struct snd_pcm, list);
 		snd_iprintf(buffer, "%02i-%02i: %s : %s",
@@ -1042,7 +1046,7 @@
 				    pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count);
 		snd_iprintf(buffer, "\n");
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 }
 
 static struct snd_info_entry *snd_pcm_proc_entry = NULL;
@@ -1101,7 +1105,6 @@
 EXPORT_SYMBOL(snd_pcm_notify);
 EXPORT_SYMBOL(snd_pcm_open_substream);
 EXPORT_SYMBOL(snd_pcm_release_substream);
-EXPORT_SYMBOL(snd_pcm_format_name);
   /* pcm_native.c */
 EXPORT_SYMBOL(snd_pcm_link_rwlock);
 #ifdef CONFIG_PM
diff -urN oldtree/sound/core/pcm_native.c newtree/sound/core/pcm_native.c
--- oldtree/sound/core/pcm_native.c	2006-02-19 11:41:06.709323128 +0000
+++ newtree/sound/core/pcm_native.c	2006-02-21 15:58:11.250436232 +0000
@@ -2112,7 +2112,7 @@
 	}
 	init_waitqueue_entry(&wait, current);
 	add_wait_queue(&pcm->open_wait, &wait);
-	down(&pcm->open_mutex);
+	mutex_lock(&pcm->open_mutex);
 	while (1) {
 		err = snd_pcm_open_file(file, pcm, stream, &pcm_file);
 		if (err >= 0)
@@ -2125,16 +2125,16 @@
 		} else
 			break;
 		set_current_state(TASK_INTERRUPTIBLE);
-		up(&pcm->open_mutex);
+		mutex_unlock(&pcm->open_mutex);
 		schedule();
-		down(&pcm->open_mutex);
+		mutex_lock(&pcm->open_mutex);
 		if (signal_pending(current)) {
 			err = -ERESTARTSYS;
 			break;
 		}
 	}
 	remove_wait_queue(&pcm->open_wait, &wait);
-	up(&pcm->open_mutex);
+	mutex_unlock(&pcm->open_mutex);
 	if (err < 0)
 		goto __error;
 	return err;
@@ -2160,9 +2160,9 @@
 	pcm = substream->pcm;
 	snd_pcm_drop(substream);
 	fasync_helper(-1, file, 0, &substream->runtime->fasync);
-	down(&pcm->open_mutex);
+	mutex_lock(&pcm->open_mutex);
 	snd_pcm_release_file(pcm_file);
-	up(&pcm->open_mutex);
+	mutex_unlock(&pcm->open_mutex);
 	wake_up(&pcm->open_wait);
 	module_put(pcm->card->module);
 	snd_card_file_remove(pcm->card, file);
diff -urN oldtree/sound/core/rawmidi.c newtree/sound/core/rawmidi.c
--- oldtree/sound/core/rawmidi.c	2006-02-19 11:41:06.712322672 +0000
+++ newtree/sound/core/rawmidi.c	2006-02-21 15:58:11.252435928 +0000
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/wait.h>
+#include <linux/mutex.h>
 #include <linux/moduleparam.h>
 #include <linux/delay.h>
 #include <linux/wait.h>
@@ -57,7 +58,7 @@
 static int snd_rawmidi_dev_unregister(struct snd_device *device);
 
 static LIST_HEAD(snd_rawmidi_devices);
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
 
 static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device)
 {
@@ -237,9 +238,9 @@
 
 	if (rfile)
 		rfile->input = rfile->output = NULL;
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	rmidi = snd_rawmidi_search(card, device);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	if (rmidi == NULL) {
 		err = -ENODEV;
 		goto __error1;
@@ -249,7 +250,7 @@
 		goto __error1;
 	}
 	if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
-		down(&rmidi->open_mutex);
+		mutex_lock(&rmidi->open_mutex);
 	if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
 		if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT)) {
 			err = -ENXIO;
@@ -359,7 +360,7 @@
 		soutput = NULL;
 	}
 	if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
-		up(&rmidi->open_mutex);
+		mutex_unlock(&rmidi->open_mutex);
 	if (rfile) {
 		rfile->rmidi = rmidi;
 		rfile->input = sinput;
@@ -374,7 +375,7 @@
 		snd_rawmidi_runtime_free(soutput);
 	module_put(rmidi->card->module);
 	if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
-		up(&rmidi->open_mutex);
+		mutex_unlock(&rmidi->open_mutex);
       __error1:
 	return err;
 }
@@ -422,7 +423,7 @@
 	}
 	init_waitqueue_entry(&wait, current);
 	add_wait_queue(&rmidi->open_wait, &wait);
-	down(&rmidi->open_mutex);
+	mutex_lock(&rmidi->open_mutex);
 	while (1) {
 		subdevice = -1;
 		down_read(&card->controls_rwsem);
@@ -446,9 +447,9 @@
 		} else
 			break;
 		set_current_state(TASK_INTERRUPTIBLE);
-		up(&rmidi->open_mutex);
+		mutex_unlock(&rmidi->open_mutex);
 		schedule();
-		down(&rmidi->open_mutex);
+		mutex_lock(&rmidi->open_mutex);
 		if (signal_pending(current)) {
 			err = -ERESTARTSYS;
 			break;
@@ -467,7 +468,7 @@
 		snd_card_file_remove(card, file);
 		kfree(rawmidi_file);
 	}
-	up(&rmidi->open_mutex);
+	mutex_unlock(&rmidi->open_mutex);
 	return err;
 }
 
@@ -480,7 +481,7 @@
 	snd_assert(rfile != NULL, return -ENXIO);
 	snd_assert(rfile->input != NULL || rfile->output != NULL, return -ENXIO);
 	rmidi = rfile->rmidi;
-	down(&rmidi->open_mutex);
+	mutex_lock(&rmidi->open_mutex);
 	if (rfile->input != NULL) {
 		substream = rfile->input;
 		rfile->input = NULL;
@@ -514,7 +515,7 @@
 		}
 		rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened--;
 	}
-	up(&rmidi->open_mutex);
+	mutex_unlock(&rmidi->open_mutex);
 	module_put(rmidi->card->module);
 	return 0;
 }
@@ -576,9 +577,9 @@
 	struct snd_rawmidi_substream *substream;
 	struct list_head *list;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	rmidi = snd_rawmidi_search(card, info->device);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	if (!rmidi)
 		return -ENXIO;
 	if (info->stream < 0 || info->stream > 1)
@@ -818,7 +819,7 @@
 		
 		if (get_user(device, (int __user *)argp))
 			return -EFAULT;
-		down(&register_mutex);
+		mutex_lock(&register_mutex);
 		device = device < 0 ? 0 : device + 1;
 		while (device < SNDRV_RAWMIDI_DEVICES) {
 			if (snd_rawmidi_search(card, device))
@@ -827,7 +828,7 @@
 		}
 		if (device == SNDRV_RAWMIDI_DEVICES)
 			device = -1;
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		if (put_user(device, (int __user *)argp))
 			return -EFAULT;
 		return 0;
@@ -1314,7 +1315,7 @@
 
 	rmidi = entry->private_data;
 	snd_iprintf(buffer, "%s\n\n", rmidi->name);
-	down(&rmidi->open_mutex);
+	mutex_lock(&rmidi->open_mutex);
 	if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) {
 		list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) {
 			substream = list_entry(list, struct snd_rawmidi_substream, list);
@@ -1355,7 +1356,7 @@
 			}
 		}
 	}
-	up(&rmidi->open_mutex);
+	mutex_unlock(&rmidi->open_mutex);
 }
 
 /*
@@ -1436,7 +1437,7 @@
 	}
 	rmidi->card = card;
 	rmidi->device = device;
-	init_MUTEX(&rmidi->open_mutex);
+	mutex_init(&rmidi->open_mutex);
 	init_waitqueue_head(&rmidi->open_wait);
 	if (id != NULL)
 		strlcpy(rmidi->id, id, sizeof(rmidi->id));
@@ -1507,9 +1508,9 @@
 
 	if (rmidi->device >= SNDRV_RAWMIDI_DEVICES)
 		return -ENOMEM;
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	if (snd_rawmidi_search(rmidi->card, rmidi->device)) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -EBUSY;
 	}
 	list_add_tail(&rmidi->list, &snd_rawmidi_devices);
@@ -1519,14 +1520,14 @@
 				       &snd_rawmidi_f_ops, rmidi, name)) < 0) {
 		snd_printk(KERN_ERR "unable to register rawmidi device %i:%i\n", rmidi->card->number, rmidi->device);
 		list_del(&rmidi->list);
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return err;
 	}
 	if (rmidi->ops && rmidi->ops->dev_register &&
 	    (err = rmidi->ops->dev_register(rmidi)) < 0) {
 		snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
 		list_del(&rmidi->list);
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return err;
 	}
 #ifdef CONFIG_SND_OSSEMUL
@@ -1553,7 +1554,7 @@
 		}
 	}
 #endif /* CONFIG_SND_OSSEMUL */
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	sprintf(name, "midi%d", rmidi->device);
 	entry = snd_info_create_card_entry(rmidi->card, name, rmidi->card->proc_root);
 	if (entry) {
@@ -1583,9 +1584,9 @@
 {
 	struct snd_rawmidi *rmidi = device->device_data;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	list_del_init(&rmidi->list);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return 0;
 }
 
@@ -1594,7 +1595,7 @@
 	struct snd_rawmidi *rmidi = device->device_data;
 
 	snd_assert(rmidi != NULL, return -ENXIO);
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	list_del(&rmidi->list);
 	if (rmidi->proc_entry) {
 		snd_info_unregister(rmidi->proc_entry);
@@ -1616,7 +1617,7 @@
 	if (rmidi->ops && rmidi->ops->dev_unregister)
 		rmidi->ops->dev_unregister(rmidi);
 	snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 	if (rmidi->seq_dev) {
 		snd_device_free(rmidi->card, rmidi->seq_dev);
diff -urN oldtree/sound/core/seq/oss/seq_oss.c newtree/sound/core/seq/oss/seq_oss.c
--- oldtree/sound/core/seq/oss/seq_oss.c	2006-02-19 11:41:06.716322064 +0000
+++ newtree/sound/core/seq/oss/seq_oss.c	2006-02-21 15:58:11.252435928 +0000
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/initval.h>
@@ -124,7 +125,7 @@
  * ALSA minor device interface
  */
 
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
 
 static int
 odev_open(struct inode *inode, struct file *file)
@@ -136,9 +137,9 @@
 	else
 		level = SNDRV_SEQ_OSS_MODE_SYNTH;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	rc = snd_seq_oss_open(file, level);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 
 	return rc;
 }
@@ -153,9 +154,9 @@
 
 	snd_seq_oss_drain_write(dp);
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	snd_seq_oss_release(dp);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 
 	return 0;
 }
@@ -224,13 +225,13 @@
 {
 	int rc;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER,
 					  NULL, 0,
 					  &seq_oss_f_ops, NULL,
 					  SNDRV_SEQ_OSS_DEVNAME)) < 0) {
 		snd_printk(KERN_ERR "can't register device seq\n");
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return rc;
 	}
 	if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC,
@@ -239,24 +240,24 @@
 					  SNDRV_SEQ_OSS_DEVNAME)) < 0) {
 		snd_printk(KERN_ERR "can't register device music\n");
 		snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0);
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return rc;
 	}
 	debug_printk(("device registered\n"));
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return 0;
 }
 
 static void
 unregister_device(void)
 {
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	debug_printk(("device unregistered\n"));
 	if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, NULL, 0) < 0)		
 		snd_printk(KERN_ERR "error unregister device music\n");
 	if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0) < 0)
 		snd_printk(KERN_ERR "error unregister device seq\n");
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 }
 
 /*
@@ -270,12 +271,12 @@
 static void
 info_read(struct snd_info_entry *entry, struct snd_info_buffer *buf)
 {
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	snd_iprintf(buf, "OSS sequencer emulation version %s\n", SNDRV_SEQ_OSS_VERSION_STR);
 	snd_seq_oss_system_info_read(buf);
 	snd_seq_oss_synth_info_read(buf);
 	snd_seq_oss_midi_info_read(buf);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 }
 
 
diff -urN oldtree/sound/core/seq/seq_clientmgr.c newtree/sound/core/seq/seq_clientmgr.c
--- oldtree/sound/core/seq/seq_clientmgr.c	2006-02-19 11:41:06.728320240 +0000
+++ newtree/sound/core/seq/seq_clientmgr.c	2006-02-21 15:58:11.254435624 +0000
@@ -67,7 +67,7 @@
 #define SNDRV_SEQ_LFLG_OPEN	(SNDRV_SEQ_LFLG_INPUT|SNDRV_SEQ_LFLG_OUTPUT)
 
 static DEFINE_SPINLOCK(clients_lock);
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
 
 /*
  * client table
@@ -237,7 +237,7 @@
 	client->type = NO_CLIENT;
 	snd_use_lock_init(&client->use_lock);
 	rwlock_init(&client->ports_lock);
-	init_MUTEX(&client->ports_mutex);
+	mutex_init(&client->ports_mutex);
 	INIT_LIST_HEAD(&client->ports_list_head);
 
 	/* find free slot in the client table */
@@ -290,7 +290,7 @@
 
 static void seq_free_client(struct snd_seq_client * client)
 {
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	switch (client->type) {
 	case NO_CLIENT:
 		snd_printk(KERN_WARNING "Seq: Trying to free unused client %d\n",
@@ -306,7 +306,7 @@
 		snd_printk(KERN_ERR "Seq: Trying to free client %d with undefined type = %d\n",
 			   client->number, client->type);
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 
 	snd_seq_system_client_ev_client_exit(client->number);
 }
@@ -322,11 +322,11 @@
 	struct snd_seq_client *client;
 	struct snd_seq_user_client *user;
 
-	if (down_interruptible(&register_mutex))
+	if (mutex_lock_interruptible(&register_mutex))
 		return -ERESTARTSYS;
 	client = seq_create_client1(-1, SNDRV_SEQ_DEFAULT_EVENTS);
 	if (client == NULL) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -ENOMEM;	/* failure code */
 	}
 
@@ -346,14 +346,14 @@
 		if (user->fifo == NULL) {
 			seq_free_client1(client);
 			kfree(client);
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			return -ENOMEM;
 		}
 	}
 
 	usage_alloc(&client_usage, 1);
 	client->type = USER_CLIENT;
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 
 	c = client->number;
 	file->private_data = client;
@@ -1743,7 +1743,7 @@
 	if (queue == NULL)
 		return -EINVAL;
 
-	if (down_interruptible(&queue->timer_mutex)) {
+	if (mutex_lock_interruptible(&queue->timer_mutex)) {
 		queuefree(queue);
 		return -ERESTARTSYS;
 	}
@@ -1756,7 +1756,7 @@
 		timer.u.alsa.id = tmr->alsa_id;
 		timer.u.alsa.resolution = tmr->preferred_resolution;
 	}
-	up(&queue->timer_mutex);
+	mutex_unlock(&queue->timer_mutex);
 	queuefree(queue);
 	
 	if (copy_to_user(arg, &timer, sizeof(timer)))
@@ -1785,7 +1785,7 @@
 		q = queueptr(timer.queue);
 		if (q == NULL)
 			return -ENXIO;
-		if (down_interruptible(&q->timer_mutex)) {
+		if (mutex_lock_interruptible(&q->timer_mutex)) {
 			queuefree(q);
 			return -ERESTARTSYS;
 		}
@@ -1797,7 +1797,7 @@
 			tmr->preferred_resolution = timer.u.alsa.resolution;
 		}
 		result = snd_seq_queue_timer_open(timer.queue);
-		up(&q->timer_mutex);
+		mutex_unlock(&q->timer_mutex);
 		queuefree(q);
 	} else {
 		return -EPERM;
@@ -2230,7 +2230,7 @@
 	if (card == NULL && client_index >= SNDRV_SEQ_GLOBAL_CLIENTS)
 		return -EINVAL;
 
-	if (down_interruptible(&register_mutex))
+	if (mutex_lock_interruptible(&register_mutex))
 		return -ERESTARTSYS;
 
 	if (card) {
@@ -2243,7 +2243,7 @@
 	/* empty write queue as default */
 	client = seq_create_client1(client_index, 0);
 	if (client == NULL) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -EBUSY;	/* failure code */
 	}
 	usage_alloc(&client_usage, 1);
@@ -2256,7 +2256,7 @@
 	va_end(args);
 
 	client->type = KERNEL_CLIENT;
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 
 	/* make others aware this new client */
 	snd_seq_system_client_ev_client_start(client->number);
@@ -2464,7 +2464,7 @@
 {
 	struct list_head *l;
 
-	down(&client->ports_mutex);
+	mutex_lock(&client->ports_mutex);
 	list_for_each(l, &client->ports_list_head) {
 		struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list);
 		snd_iprintf(buffer, "  Port %3d : \"%s\" (%c%c%c%c)\n",
@@ -2476,7 +2476,7 @@
 		snd_seq_info_dump_subscribers(buffer, &p->c_src, 1, "    Connecting To: ");
 		snd_seq_info_dump_subscribers(buffer, &p->c_dest, 0, "    Connected From: ");
 	}
-	up(&client->ports_mutex);
+	mutex_unlock(&client->ports_mutex);
 }
 
 
@@ -2550,16 +2550,16 @@
 {
 	int err;
 
-	if (down_interruptible(&register_mutex))
+	if (mutex_lock_interruptible(&register_mutex))
 		return -ERESTARTSYS;
 
 	if ((err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0,
 				       &snd_seq_f_ops, NULL, "seq")) < 0) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return err;
 	}
 	
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 
 	return 0;
 }
diff -urN oldtree/sound/core/seq/seq_clientmgr.h newtree/sound/core/seq/seq_clientmgr.h
--- oldtree/sound/core/seq/seq_clientmgr.h	2006-02-19 11:41:06.729320088 +0000
+++ newtree/sound/core/seq/seq_clientmgr.h	2006-02-21 15:58:11.255435472 +0000
@@ -58,7 +58,7 @@
 	int num_ports;		/* number of ports */
 	struct list_head ports_list_head;
 	rwlock_t ports_lock;
-	struct semaphore ports_mutex;
+	struct mutex ports_mutex;
 	int convert32;		/* convert 32->64bit */
 
 	/* output pool */
diff -urN oldtree/sound/core/seq/seq_device.c newtree/sound/core/seq/seq_device.c
--- oldtree/sound/core/seq/seq_device.c	2006-02-19 11:41:06.730319936 +0000
+++ newtree/sound/core/seq/seq_device.c	2006-02-21 15:58:11.256435320 +0000
@@ -45,6 +45,7 @@
 #include <sound/initval.h>
 #include <linux/kmod.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
 
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("ALSA sequencer device management");
@@ -69,7 +70,7 @@
 	struct list_head dev_list;	/* list of devices */
 	int num_devices;	/* number of associated devices */
 	int num_init_devices;	/* number of initialized devices */
-	struct semaphore reg_mutex;
+	struct mutex reg_mutex;
 
 	struct list_head list;	/* next driver */
 };
@@ -77,7 +78,7 @@
 
 static LIST_HEAD(opslist);
 static int num_ops;
-static DECLARE_MUTEX(ops_mutex);
+static DEFINE_MUTEX(ops_mutex);
 #ifdef CONFIG_PROC_FS
 static struct snd_info_entry *info_entry = NULL;
 #endif
@@ -108,7 +109,7 @@
 {
 	struct list_head *head;
 
-	down(&ops_mutex);
+	mutex_lock(&ops_mutex);
 	list_for_each(head, &opslist) {
 		struct ops_list *ops = list_entry(head, struct ops_list, list);
 		snd_iprintf(buffer, "snd-%s%s%s%s,%d\n",
@@ -118,7 +119,7 @@
 				ops->driver & DRIVER_LOCKED ? ",locked" : "",
 				ops->num_devices);
 	}
-	up(&ops_mutex);	
+	mutex_unlock(&ops_mutex);
 }
 #endif
  
@@ -154,20 +155,20 @@
 	if (! current->fs->root)
 		return;
 
-	down(&ops_mutex);
+	mutex_lock(&ops_mutex);
 	list_for_each(head, &opslist) {
 		struct ops_list *ops = list_entry(head, struct ops_list, list);
 		if (! (ops->driver & DRIVER_LOADED) &&
 		    ! (ops->driver & DRIVER_REQUESTED)) {
 			ops->used++;
-			up(&ops_mutex);
+			mutex_unlock(&ops_mutex);
 			ops->driver |= DRIVER_REQUESTED;
 			request_module("snd-%s", ops->id);
-			down(&ops_mutex);
+			mutex_lock(&ops_mutex);
 			ops->used--;
 		}
 	}
-	up(&ops_mutex);
+	mutex_unlock(&ops_mutex);
 #endif
 }
 
@@ -214,10 +215,10 @@
 	dev->status = SNDRV_SEQ_DEVICE_FREE;
 
 	/* add this device to the list */
-	down(&ops->reg_mutex);
+	mutex_lock(&ops->reg_mutex);
 	list_add_tail(&dev->list, &ops->dev_list);
 	ops->num_devices++;
-	up(&ops->reg_mutex);
+	mutex_unlock(&ops->reg_mutex);
 
 	unlock_driver(ops);
 	
@@ -246,10 +247,10 @@
 		return -ENXIO;
 
 	/* remove the device from the list */
-	down(&ops->reg_mutex);
+	mutex_lock(&ops->reg_mutex);
 	list_del(&dev->list);
 	ops->num_devices--;
-	up(&ops->reg_mutex);
+	mutex_unlock(&ops->reg_mutex);
 
 	free_device(dev, ops);
 	if (dev->private_free)
@@ -344,7 +345,7 @@
 		return -EBUSY;
 	}
 
-	down(&ops->reg_mutex);
+	mutex_lock(&ops->reg_mutex);
 	/* copy driver operators */
 	ops->ops = *entry;
 	ops->driver |= DRIVER_LOADED;
@@ -355,7 +356,7 @@
 		struct snd_seq_device *dev = list_entry(head, struct snd_seq_device, list);
 		init_device(dev, ops);
 	}
-	up(&ops->reg_mutex);
+	mutex_unlock(&ops->reg_mutex);
 
 	unlock_driver(ops);
 	snd_seq_autoload_unlock();
@@ -378,17 +379,17 @@
 
 	/* set up driver entry */
 	strlcpy(ops->id, id, sizeof(ops->id));
-	init_MUTEX(&ops->reg_mutex);
+	mutex_init(&ops->reg_mutex);
 	ops->driver = DRIVER_EMPTY;
 	INIT_LIST_HEAD(&ops->dev_list);
 	/* lock this instance */
 	ops->used = 1;
 
 	/* register driver entry */
-	down(&ops_mutex);
+	mutex_lock(&ops_mutex);
 	list_add_tail(&ops->list, &opslist);
 	num_ops++;
-	up(&ops_mutex);
+	mutex_unlock(&ops_mutex);
 
 	return ops;
 }
@@ -414,7 +415,7 @@
 	}
 
 	/* close and release all devices associated with this driver */
-	down(&ops->reg_mutex);
+	mutex_lock(&ops->reg_mutex);
 	ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */
 	list_for_each(head, &ops->dev_list) {
 		struct snd_seq_device *dev = list_entry(head, struct snd_seq_device, list);
@@ -425,7 +426,7 @@
 	if (ops->num_init_devices > 0)
 		snd_printk(KERN_ERR "free_driver: init_devices > 0!! (%d)\n",
 			   ops->num_init_devices);
-	up(&ops->reg_mutex);
+	mutex_unlock(&ops->reg_mutex);
 
 	unlock_driver(ops);
 
@@ -443,7 +444,7 @@
 {
 	struct list_head *head;
 
-	down(&ops_mutex);
+	mutex_lock(&ops_mutex);
 	head = opslist.next;
 	while (head != &opslist) {
 		struct ops_list *ops = list_entry(head, struct ops_list, list);
@@ -456,7 +457,7 @@
 		} else
 			head = head->next;
 	}
-	up(&ops_mutex);
+	mutex_unlock(&ops_mutex);
 }
 
 /*
@@ -519,16 +520,16 @@
 {
 	struct list_head *head;
 
-	down(&ops_mutex);
+	mutex_lock(&ops_mutex);
 	list_for_each(head, &opslist) {
 		struct ops_list *ops = list_entry(head, struct ops_list, list);
 		if (strcmp(ops->id, id) == 0) {
 			ops->used++;
-			up(&ops_mutex);
+			mutex_unlock(&ops_mutex);
 			return ops;
 		}
 	}
-	up(&ops_mutex);
+	mutex_unlock(&ops_mutex);
 	if (create_if_empty)
 		return create_driver(id);
 	return NULL;
@@ -536,9 +537,9 @@
 
 static void unlock_driver(struct ops_list *ops)
 {
-	down(&ops_mutex);
+	mutex_lock(&ops_mutex);
 	ops->used--;
-	up(&ops_mutex);
+	mutex_unlock(&ops_mutex);
 }
 
 
diff -urN oldtree/sound/core/seq/seq_instr.c newtree/sound/core/seq/seq_instr.c
--- oldtree/sound/core/seq/seq_instr.c	2006-02-19 11:41:06.734319328 +0000
+++ newtree/sound/core/seq/seq_instr.c	2006-02-21 15:58:11.256435320 +0000
@@ -36,7 +36,7 @@
 	if (!(list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT)) {
 		spin_lock_irqsave(&list->ops_lock, list->ops_flags);
 	} else {
-		down(&list->ops_mutex);
+		mutex_lock(&list->ops_mutex);
 	}
 }
 
@@ -45,7 +45,7 @@
 	if (!(list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT)) {
 		spin_unlock_irqrestore(&list->ops_lock, list->ops_flags);
 	} else {
-		up(&list->ops_mutex);
+		mutex_unlock(&list->ops_mutex);
 	}
 }
 
@@ -82,7 +82,7 @@
 		return NULL;
 	spin_lock_init(&list->lock);
 	spin_lock_init(&list->ops_lock);
-	init_MUTEX(&list->ops_mutex);
+	mutex_init(&list->ops_mutex);
 	list->owner = -1;
 	return list;
 }
diff -urN oldtree/sound/core/seq/seq_midi.c newtree/sound/core/seq/seq_midi.c
--- oldtree/sound/core/seq/seq_midi.c	2006-02-19 11:41:06.736319024 +0000
+++ newtree/sound/core/seq/seq_midi.c	2006-02-21 15:58:11.257435168 +0000
@@ -32,7 +32,7 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/moduleparam.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/rawmidi.h>
 #include <sound/seq_kernel.h>
@@ -70,7 +70,7 @@
 };
 
 static struct seq_midisynth_client *synths[SNDRV_CARDS];
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
 
 /* handle rawmidi input event (MIDI v1.0 stream) */
 static void snd_midi_input_event(struct snd_rawmidi_substream *substream)
@@ -308,13 +308,13 @@
 	if (ports > (256 / SNDRV_RAWMIDI_DEVICES))
 		ports = 256 / SNDRV_RAWMIDI_DEVICES;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	client = synths[card->number];
 	if (client == NULL) {
 		newclient = 1;
 		client = kzalloc(sizeof(*client), GFP_KERNEL);
 		if (client == NULL) {
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			kfree(info);
 			return -ENOMEM;
 		}
@@ -324,7 +324,7 @@
 				(const char *)info->name : "External MIDI");
 		if (client->seq_client < 0) {
 			kfree(client);
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			kfree(info);
 			return -ENOMEM;
 		}
@@ -397,7 +397,7 @@
 	client->num_ports++;
 	if (newclient)
 		synths[card->number] = client;
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	kfree(info);
 	kfree(port);
 	return 0;	/* success */
@@ -414,7 +414,7 @@
 	}
 	kfree(info);
 	kfree(port);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return -ENOMEM;
 }
 
@@ -427,10 +427,10 @@
 	struct snd_card *card = dev->card;
 	int device = dev->device, p, ports;
 	
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	client = synths[card->number];
 	if (client == NULL || client->ports[device] == NULL) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -ENODEV;
 	}
 	ports = client->ports_per_device[device];
@@ -446,7 +446,7 @@
 		synths[card->number] = NULL;
 		kfree(client);
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return 0;
 }
 
diff -urN oldtree/sound/core/seq/seq_ports.c newtree/sound/core/seq/seq_ports.c
--- oldtree/sound/core/seq/seq_ports.c	2006-02-19 11:41:06.739318568 +0000
+++ newtree/sound/core/seq/seq_ports.c	2006-02-21 15:58:11.258435016 +0000
@@ -159,7 +159,7 @@
 	port_subs_info_init(&new_port->c_dest);
 
 	num = port >= 0 ? port : 0;
-	down(&client->ports_mutex);
+	mutex_lock(&client->ports_mutex);
 	write_lock_irqsave(&client->ports_lock, flags);
 	list_for_each(l, &client->ports_list_head) {
 		struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list);
@@ -173,7 +173,7 @@
 	client->num_ports++;
 	new_port->addr.port = num;	/* store the port number in the port */
 	write_unlock_irqrestore(&client->ports_lock, flags);
-	up(&client->ports_mutex);
+	mutex_unlock(&client->ports_mutex);
 	sprintf(new_port->name, "port-%d", num);
 
 	return new_port;
@@ -292,7 +292,7 @@
 	struct list_head *l;
 	struct snd_seq_client_port *found = NULL;
 
-	down(&client->ports_mutex);
+	mutex_lock(&client->ports_mutex);
 	write_lock_irqsave(&client->ports_lock, flags);
 	list_for_each(l, &client->ports_list_head) {
 		struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list);
@@ -305,7 +305,7 @@
 		}
 	}
 	write_unlock_irqrestore(&client->ports_lock, flags);
-	up(&client->ports_mutex);
+	mutex_unlock(&client->ports_mutex);
 	if (found)
 		return port_delete(client, found);
 	else
@@ -321,7 +321,7 @@
 	/* move the port list to deleted_list, and
 	 * clear the port list in the client data.
 	 */
-	down(&client->ports_mutex);
+	mutex_lock(&client->ports_mutex);
 	write_lock_irqsave(&client->ports_lock, flags);
 	if (! list_empty(&client->ports_list_head)) {
 		__list_add(&deleted_list,
@@ -341,7 +341,7 @@
 		snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port);
 		port_delete(client, port);
 	}
-	up(&client->ports_mutex);
+	mutex_unlock(&client->ports_mutex);
 	return 0;
 }
 
diff -urN oldtree/sound/core/seq/seq_queue.c newtree/sound/core/seq/seq_queue.c
--- oldtree/sound/core/seq/seq_queue.c	2006-02-19 11:41:06.743317960 +0000
+++ newtree/sound/core/seq/seq_queue.c	2006-02-21 15:58:11.259434864 +0000
@@ -119,7 +119,7 @@
 
 	spin_lock_init(&q->owner_lock);
 	spin_lock_init(&q->check_lock);
-	init_MUTEX(&q->timer_mutex);
+	mutex_init(&q->timer_mutex);
 	snd_use_lock_init(&q->use_lock);
 	q->queue = -1;
 
@@ -516,7 +516,7 @@
 	queue = queueptr(queueid);
 	if (queue == NULL)
 		return -EINVAL;
-	down(&queue->timer_mutex);
+	mutex_lock(&queue->timer_mutex);
 	if (use) {
 		if (!test_and_set_bit(client, queue->clients_bitmap))
 			queue->clients++;
@@ -531,7 +531,7 @@
 	} else {
 		snd_seq_timer_close(queue);
 	}
-	up(&queue->timer_mutex);
+	mutex_unlock(&queue->timer_mutex);
 	queuefree(queue);
 	return 0;
 }
diff -urN oldtree/sound/core/seq/seq_queue.h newtree/sound/core/seq/seq_queue.h
--- oldtree/sound/core/seq/seq_queue.h	2006-02-19 11:41:06.743317960 +0000
+++ newtree/sound/core/seq/seq_queue.h	2006-02-21 15:58:11.259434864 +0000
@@ -54,7 +54,7 @@
 	/* clients which uses this queue (bitmap) */
 	DECLARE_BITMAP(clients_bitmap, SNDRV_SEQ_MAX_CLIENTS);
 	unsigned int clients;	/* users of this queue */
-	struct semaphore timer_mutex;
+	struct mutex timer_mutex;
 
 	snd_use_lock_t use_lock;
 };
diff -urN oldtree/sound/core/sound.c newtree/sound/core/sound.c
--- oldtree/sound/core/sound.c	2006-02-19 11:41:06.749317048 +0000
+++ newtree/sound/core/sound.c	2006-02-21 15:58:11.260434712 +0000
@@ -33,6 +33,7 @@
 #include <sound/initval.h>
 #include <linux/kmod.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/mutex.h>
 
 #define SNDRV_OS_MINORS 256
 
@@ -61,7 +62,7 @@
 int snd_ecards_limit;
 
 static struct snd_minor *snd_minors[SNDRV_OS_MINORS];
-static DECLARE_MUTEX(sound_mutex);
+static DEFINE_MUTEX(sound_mutex);
 
 extern struct class *sound_class;
 
@@ -122,13 +123,13 @@
 
 	if (minor > ARRAY_SIZE(snd_minors))
 		return NULL;
-	down(&sound_mutex);
+	mutex_lock(&sound_mutex);
 	mreg = snd_minors[minor];
 	if (mreg && mreg->type == type)
 		private_data = mreg->private_data;
 	else
 		private_data = NULL;
-	up(&sound_mutex);
+	mutex_unlock(&sound_mutex);
 	return private_data;
 }
 
@@ -256,7 +257,7 @@
 	preg->f_ops = f_ops;
 	preg->private_data = private_data;
 	strcpy(preg->name, name);
-	down(&sound_mutex);
+	mutex_lock(&sound_mutex);
 #ifdef CONFIG_SND_DYNAMIC_MINORS
 	minor = snd_find_free_minor();
 #else
@@ -265,7 +266,7 @@
 		minor = -EBUSY;
 #endif
 	if (minor < 0) {
-		up(&sound_mutex);
+		mutex_unlock(&sound_mutex);
 		kfree(preg);
 		return minor;
 	}
@@ -276,7 +277,7 @@
 		device = card->dev;
 	class_device_create(sound_class, NULL, MKDEV(major, minor), device, "%s", name);
 
-	up(&sound_mutex);
+	mutex_unlock(&sound_mutex);
 	return 0;
 }
 
@@ -297,7 +298,7 @@
 	struct snd_minor *mptr;
 
 	cardnum = card ? card->number : -1;
-	down(&sound_mutex);
+	mutex_lock(&sound_mutex);
 	for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor)
 		if ((mptr = snd_minors[minor]) != NULL &&
 		    mptr->type == type &&
@@ -305,7 +306,7 @@
 		    mptr->device == dev)
 			break;
 	if (minor == ARRAY_SIZE(snd_minors)) {
-		up(&sound_mutex);
+		mutex_unlock(&sound_mutex);
 		return -EINVAL;
 	}
 
@@ -315,7 +316,7 @@
 	class_device_destroy(sound_class, MKDEV(major, minor));
 
 	snd_minors[minor] = NULL;
-	up(&sound_mutex);
+	mutex_unlock(&sound_mutex);
 	kfree(mptr);
 	return 0;
 }
@@ -354,7 +355,7 @@
 	int minor;
 	struct snd_minor *mptr;
 
-	down(&sound_mutex);
+	mutex_lock(&sound_mutex);
 	for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) {
 		if (!(mptr = snd_minors[minor]))
 			continue;
@@ -371,7 +372,7 @@
 			snd_iprintf(buffer, "%3i:        : %s\n", minor,
 				    snd_device_type_name(mptr->type));
 	}
-	up(&sound_mutex);
+	mutex_unlock(&sound_mutex);
 }
 
 int __init snd_minor_info_init(void)
diff -urN oldtree/sound/core/sound_oss.c newtree/sound/core/sound_oss.c
--- oldtree/sound/core/sound_oss.c	2006-02-19 11:41:06.750316896 +0000
+++ newtree/sound/core/sound_oss.c	2006-02-21 15:58:11.261434560 +0000
@@ -34,11 +34,12 @@
 #include <sound/minors.h>
 #include <sound/info.h>
 #include <linux/sound.h>
+#include <linux/mutex.h>
 
 #define SNDRV_OSS_MINORS 128
 
 static struct snd_minor *snd_oss_minors[SNDRV_OSS_MINORS];
-static DECLARE_MUTEX(sound_oss_mutex);
+static DEFINE_MUTEX(sound_oss_mutex);
 
 void *snd_lookup_oss_minor_data(unsigned int minor, int type)
 {
@@ -47,13 +48,13 @@
 
 	if (minor > ARRAY_SIZE(snd_oss_minors))
 		return NULL;
-	down(&sound_oss_mutex);
+	mutex_lock(&sound_oss_mutex);
 	mreg = snd_oss_minors[minor];
 	if (mreg && mreg->type == type)
 		private_data = mreg->private_data;
 	else
 		private_data = NULL;
-	up(&sound_oss_mutex);
+	mutex_unlock(&sound_oss_mutex);
 	return private_data;
 }
 
@@ -117,7 +118,7 @@
 	preg->device = dev;
 	preg->f_ops = f_ops;
 	preg->private_data = private_data;
-	down(&sound_oss_mutex);
+	mutex_lock(&sound_oss_mutex);
 	snd_oss_minors[minor] = preg;
 	minor_unit = SNDRV_MINOR_OSS_DEVICE(minor);
 	switch (minor_unit) {
@@ -143,7 +144,7 @@
 			goto __end;
 		snd_oss_minors[track2] = preg;
 	}
-	up(&sound_oss_mutex);
+	mutex_unlock(&sound_oss_mutex);
 	return 0;
 
       __end:
@@ -152,7 +153,7 @@
       	if (register1 >= 0)
       		unregister_sound_special(register1);
 	snd_oss_minors[minor] = NULL;
-	up(&sound_oss_mutex);
+	mutex_unlock(&sound_oss_mutex);
 	kfree(preg);
       	return -EBUSY;
 }
@@ -168,10 +169,10 @@
 		return 0;
 	if (minor < 0)
 		return minor;
-	down(&sound_oss_mutex);
+	mutex_lock(&sound_oss_mutex);
 	mptr = snd_oss_minors[minor];
 	if (mptr == NULL) {
-		up(&sound_oss_mutex);
+		mutex_unlock(&sound_oss_mutex);
 		return -ENOENT;
 	}
 	unregister_sound_special(minor);
@@ -191,7 +192,7 @@
 		snd_oss_minors[track2] = NULL;
 	}
 	snd_oss_minors[minor] = NULL;
-	up(&sound_oss_mutex);
+	mutex_unlock(&sound_oss_mutex);
 	kfree(mptr);
 	return 0;
 }
@@ -229,7 +230,7 @@
 	int minor;
 	struct snd_minor *mptr;
 
-	down(&sound_oss_mutex);
+	mutex_lock(&sound_oss_mutex);
 	for (minor = 0; minor < SNDRV_OSS_MINORS; ++minor) {
 		if (!(mptr = snd_oss_minors[minor]))
 			continue;
@@ -241,7 +242,7 @@
 			snd_iprintf(buffer, "%3i:       : %s\n", minor,
 				    snd_oss_device_type_name(mptr->type));
 	}
-	up(&sound_oss_mutex);
+	mutex_unlock(&sound_oss_mutex);
 }
 
 
diff -urN oldtree/sound/core/timer.c newtree/sound/core/timer.c
--- oldtree/sound/core/timer.c	2006-02-19 11:41:06.752316592 +0000
+++ newtree/sound/core/timer.c	2006-02-21 15:58:11.263434256 +0000
@@ -25,6 +25,7 @@
 #include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/time.h>
+#include <linux/mutex.h>
 #include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <sound/core.h>
@@ -70,7 +71,7 @@
 	struct timespec tstamp;		/* trigger tstamp */
 	wait_queue_head_t qchange_sleep;
 	struct fasync_struct *fasync;
-	struct semaphore tread_sem;
+	struct mutex tread_sem;
 };
 
 /* list of timers */
@@ -82,7 +83,7 @@
 /* lock for slave active lists */
 static DEFINE_SPINLOCK(slave_active_lock);
 
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
 
 static int snd_timer_free(struct snd_timer *timer);
 static int snd_timer_dev_free(struct snd_device *device);
@@ -252,10 +253,10 @@
 			snd_printd("invalid slave class %i\n", tid->dev_sclass);
 			return -EINVAL;
 		}
-		down(&register_mutex);
+		mutex_lock(&register_mutex);
 		timeri = snd_timer_instance_new(owner, NULL);
 		if (!timeri) {
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			return -ENOMEM;
 		}
 		timeri->slave_class = tid->dev_sclass;
@@ -263,37 +264,37 @@
 		timeri->flags |= SNDRV_TIMER_IFLG_SLAVE;
 		list_add_tail(&timeri->open_list, &snd_timer_slave_list);
 		snd_timer_check_slave(timeri);
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		*ti = timeri;
 		return 0;
 	}
 
 	/* open a master instance */
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	timer = snd_timer_find(tid);
 #ifdef CONFIG_KMOD
 	if (timer == NULL) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		snd_timer_request(tid);
-		down(&register_mutex);
+		mutex_lock(&register_mutex);
 		timer = snd_timer_find(tid);
 	}
 #endif
 	if (!timer) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -ENODEV;
 	}
 	if (!list_empty(&timer->open_list_head)) {
 		timeri = list_entry(timer->open_list_head.next,
 				    struct snd_timer_instance, open_list);
 		if (timeri->flags & SNDRV_TIMER_IFLG_EXCLUSIVE) {
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			return -EBUSY;
 		}
 	}
 	timeri = snd_timer_instance_new(owner, timer);
 	if (!timeri) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -ENOMEM;
 	}
 	timeri->slave_class = tid->dev_sclass;
@@ -302,7 +303,7 @@
 		timer->hw.open(timer);
 	list_add_tail(&timeri->open_list, &timer->open_list_head);
 	snd_timer_check_master(timeri);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	*ti = timeri;
 	return 0;
 }
@@ -333,9 +334,9 @@
 			spin_lock_irq(&slave_active_lock);
 		}
 		spin_unlock_irq(&slave_active_lock);
-		down(&register_mutex);
+		mutex_lock(&register_mutex);
 		list_del(&timeri->open_list);
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 	} else {
 		timer = timeri->timer;
 		/* wait, until the active callback is finished */
@@ -346,7 +347,7 @@
 			spin_lock_irq(&timer->lock);
 		}
 		spin_unlock_irq(&timer->lock);
-		down(&register_mutex);
+		mutex_lock(&register_mutex);
 		list_del(&timeri->open_list);
 		if (timer && list_empty(&timer->open_list_head) &&
 		    timer->hw.close)
@@ -362,7 +363,7 @@
 			slave->timer = NULL;
 			spin_unlock_irq(&slave_active_lock);
 		}
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 	}
 	if (timeri->private_free)
 		timeri->private_free(timeri);
@@ -835,7 +836,7 @@
 	    !timer->hw.resolution && timer->hw.c_resolution == NULL)
 	    	return -EINVAL;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	list_for_each(p, &snd_timer_list) {
 		timer1 = list_entry(p, struct snd_timer, device_list);
 		if (timer1->tmr_class > timer->tmr_class)
@@ -857,11 +858,11 @@
 		if (timer1->tmr_subdevice < timer->tmr_subdevice)
 			continue;
 		/* conflicts.. */
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -EBUSY;
 	}
 	list_add_tail(&timer->device_list, p);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return 0;
 }
 
@@ -871,7 +872,7 @@
 	struct snd_timer_instance *ti;
 
 	snd_assert(timer != NULL, return -ENXIO);
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	if (! list_empty(&timer->open_list_head)) {
 		snd_printk(KERN_WARNING "timer 0x%lx is busy?\n", (long)timer);
 		list_for_each_safe(p, n, &timer->open_list_head) {
@@ -881,7 +882,7 @@
 		}
 	}
 	list_del(&timer->device_list);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return snd_timer_free(timer);
 }
 
@@ -1065,7 +1066,7 @@
 	struct snd_timer_instance *ti;
 	struct list_head *p, *q;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	list_for_each(p, &snd_timer_list) {
 		timer = list_entry(p, struct snd_timer, device_list);
 		switch (timer->tmr_class) {
@@ -1105,7 +1106,7 @@
 		}
 		spin_unlock_irqrestore(&timer->lock, flags);
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 }
 
 static struct snd_info_entry *snd_timer_proc_entry = NULL;
@@ -1269,7 +1270,7 @@
 		return -ENOMEM;
 	spin_lock_init(&tu->qlock);
 	init_waitqueue_head(&tu->qchange_sleep);
-	init_MUTEX(&tu->tread_sem);
+	mutex_init(&tu->tread_sem);
 	tu->ticks = 1;
 	tu->queue_size = 128;
 	tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read),
@@ -1325,7 +1326,7 @@
 
 	if (copy_from_user(&id, _tid, sizeof(id)))
 		return -EFAULT;
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	if (id.dev_class < 0) {		/* first item */
 		if (list_empty(&snd_timer_list))
 			snd_timer_user_zero_id(&id);
@@ -1407,7 +1408,7 @@
 			snd_timer_user_zero_id(&id);
 		}
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	if (copy_to_user(_tid, &id, sizeof(*_tid)))
 		return -EFAULT;
 	return 0;
@@ -1432,7 +1433,7 @@
 	tid = ginfo->tid;
 	memset(ginfo, 0, sizeof(*ginfo));
 	ginfo->tid = tid;
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	t = snd_timer_find(&tid);
 	if (t != NULL) {
 		ginfo->card = t->card ? t->card->number : -1;
@@ -1451,7 +1452,7 @@
 	} else {
 		err = -ENODEV;
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	if (err >= 0 && copy_to_user(_ginfo, ginfo, sizeof(*ginfo)))
 		err = -EFAULT;
 	kfree(ginfo);
@@ -1467,7 +1468,7 @@
 
 	if (copy_from_user(&gparams, _gparams, sizeof(gparams)))
 		return -EFAULT;
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	t = snd_timer_find(&gparams.tid);
 	if (!t) {
 		err = -ENODEV;
@@ -1483,7 +1484,7 @@
 	}
 	err = t->hw.set_period(t, gparams.period_num, gparams.period_den);
 _error:
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return err;
 }
 
@@ -1500,7 +1501,7 @@
 	tid = gstatus.tid;
 	memset(&gstatus, 0, sizeof(gstatus));
 	gstatus.tid = tid;
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	t = snd_timer_find(&tid);
 	if (t != NULL) {
 		if (t->hw.c_resolution)
@@ -1517,7 +1518,7 @@
 	} else {
 		err = -ENODEV;
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus)))
 		err = -EFAULT;
 	return err;
@@ -1532,7 +1533,7 @@
 	int err = 0;
 
 	tu = file->private_data;
-	down(&tu->tread_sem);
+	mutex_lock(&tu->tread_sem);
 	if (tu->timeri) {
 		snd_timer_close(tu->timeri);
 		tu->timeri = NULL;
@@ -1576,7 +1577,7 @@
 	}
 
       __err:
-      	up(&tu->tread_sem);
+      	mutex_unlock(&tu->tread_sem);
 	return err;
 }
 
@@ -1797,17 +1798,17 @@
 	{
 		int xarg;
 
-		down(&tu->tread_sem);
+		mutex_lock(&tu->tread_sem);
 		if (tu->timeri)	{	/* too late */
-			up(&tu->tread_sem);
+			mutex_unlock(&tu->tread_sem);
 			return -EBUSY;
 		}
 		if (get_user(xarg, p)) {
-			up(&tu->tread_sem);
+			mutex_unlock(&tu->tread_sem);
 			return -EFAULT;
 		}
 		tu->tread = xarg ? 1 : 0;
-		up(&tu->tread_sem);
+		mutex_unlock(&tu->tread_sem);
 		return 0;
 	}
 	case SNDRV_TIMER_IOCTL_GINFO:
diff -urN oldtree/sound/drivers/opl3/opl3_lib.c newtree/sound/drivers/opl3/opl3_lib.c
--- oldtree/sound/drivers/opl3/opl3_lib.c	2006-02-19 11:41:06.759315528 +0000
+++ newtree/sound/drivers/opl3/opl3_lib.c	2006-02-21 15:58:11.264434104 +0000
@@ -358,7 +358,7 @@
 	opl3->hardware = hardware;
 	spin_lock_init(&opl3->reg_lock);
 	spin_lock_init(&opl3->timer_lock);
-	init_MUTEX(&opl3->access_mutex);
+	mutex_init(&opl3->access_mutex);
 
 	if ((err = snd_device_new(card, SNDRV_DEV_CODEC, opl3, &ops)) < 0) {
 		snd_opl3_free(opl3);
diff -urN oldtree/sound/drivers/opl3/opl3_seq.c newtree/sound/drivers/opl3/opl3_seq.c
--- oldtree/sound/drivers/opl3/opl3_seq.c	2006-02-19 11:41:06.761315224 +0000
+++ newtree/sound/drivers/opl3/opl3_seq.c	2006-02-21 15:58:11.265433952 +0000
@@ -52,13 +52,13 @@
 {
 	int idx;
 
-	down(&opl3->access_mutex);
+	mutex_lock(&opl3->access_mutex);
 	if (opl3->used) {
-		up(&opl3->access_mutex);
+		mutex_unlock(&opl3->access_mutex);
 		return -EBUSY;
 	}
 	opl3->used++;
-	up(&opl3->access_mutex);
+	mutex_unlock(&opl3->access_mutex);
 
 	snd_opl3_reset(opl3);
 
@@ -91,9 +91,9 @@
 	spin_unlock_irqrestore(&opl3->sys_timer_lock, flags);
 
 	snd_opl3_reset(opl3);
-	down(&opl3->access_mutex);
+	mutex_lock(&opl3->access_mutex);
 	opl3->used--;
-	up(&opl3->access_mutex);
+	mutex_unlock(&opl3->access_mutex);
 }
 
 static int snd_opl3_synth_use(void *private_data, struct snd_seq_port_subscribe * info)
diff -urN oldtree/sound/drivers/opl3/opl3_synth.c newtree/sound/drivers/opl3/opl3_synth.c
--- oldtree/sound/drivers/opl3/opl3_synth.c	2006-02-19 11:41:06.762315072 +0000
+++ newtree/sound/drivers/opl3/opl3_synth.c	2006-02-21 15:58:11.265433952 +0000
@@ -76,13 +76,13 @@
 {
 	struct snd_opl3 *opl3 = hw->private_data;
 
-	down(&opl3->access_mutex);
+	mutex_lock(&opl3->access_mutex);
 	if (opl3->used) {
-		up(&opl3->access_mutex);
+		mutex_unlock(&opl3->access_mutex);
 		return -EAGAIN;
 	}
 	opl3->used++;
-	up(&opl3->access_mutex);
+	mutex_unlock(&opl3->access_mutex);
 
 	return 0;
 }
@@ -179,9 +179,9 @@
 	struct snd_opl3 *opl3 = hw->private_data;
 
 	snd_opl3_reset(opl3);
-	down(&opl3->access_mutex);
+	mutex_lock(&opl3->access_mutex);
 	opl3->used--;
-	up(&opl3->access_mutex);
+	mutex_unlock(&opl3->access_mutex);
 
 	return 0;
 }
diff -urN oldtree/sound/drivers/opl4/opl4_lib.c newtree/sound/drivers/opl4/opl4_lib.c
--- oldtree/sound/drivers/opl4/opl4_lib.c	2006-02-19 11:41:06.762315072 +0000
+++ newtree/sound/drivers/opl4/opl4_lib.c	2006-02-21 15:58:11.275432432 +0000
@@ -214,7 +214,7 @@
 	opl4->fm_port = fm_port;
 	opl4->pcm_port = pcm_port;
 	spin_lock_init(&opl4->reg_lock);
-	init_MUTEX(&opl4->access_mutex);
+	mutex_init(&opl4->access_mutex);
 
 	err = snd_opl4_detect(opl4);
 	if (err < 0) {
diff -urN oldtree/sound/drivers/opl4/opl4_local.h newtree/sound/drivers/opl4/opl4_local.h
--- oldtree/sound/drivers/opl4/opl4_local.h	2006-02-19 11:41:06.763314920 +0000
+++ newtree/sound/drivers/opl4/opl4_local.h	2006-02-21 15:58:11.275432432 +0000
@@ -182,7 +182,7 @@
 	struct snd_info_entry *proc_entry;
 	int memory_access;
 #endif
-	struct semaphore access_mutex;
+	struct mutex access_mutex;
 
 #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
 	int used;
diff -urN oldtree/sound/drivers/opl4/opl4_proc.c newtree/sound/drivers/opl4/opl4_proc.c
--- oldtree/sound/drivers/opl4/opl4_proc.c	2006-02-19 11:41:06.764314768 +0000
+++ newtree/sound/drivers/opl4/opl4_proc.c	2006-02-21 15:58:11.276432280 +0000
@@ -28,13 +28,13 @@
 {
 	struct snd_opl4 *opl4 = entry->private_data;
 
-	down(&opl4->access_mutex);
+	mutex_lock(&opl4->access_mutex);
 	if (opl4->memory_access) {
-		up(&opl4->access_mutex);
+		mutex_unlock(&opl4->access_mutex);
 		return -EBUSY;
 	}
 	opl4->memory_access++;
-	up(&opl4->access_mutex);
+	mutex_unlock(&opl4->access_mutex);
 	return 0;
 }
 
@@ -43,9 +43,9 @@
 {
 	struct snd_opl4 *opl4 = entry->private_data;
 
-	down(&opl4->access_mutex);
+	mutex_lock(&opl4->access_mutex);
 	opl4->memory_access--;
-	up(&opl4->access_mutex);
+	mutex_unlock(&opl4->access_mutex);
 	return 0;
 }
 
diff -urN oldtree/sound/drivers/opl4/opl4_seq.c newtree/sound/drivers/opl4/opl4_seq.c
--- oldtree/sound/drivers/opl4/opl4_seq.c	2006-02-19 11:41:06.764314768 +0000
+++ newtree/sound/drivers/opl4/opl4_seq.c	2006-02-21 15:58:11.276432280 +0000
@@ -62,10 +62,10 @@
 	struct snd_opl4 *opl4 = private_data;
 	int err;
 
-	down(&opl4->access_mutex);
+	mutex_lock(&opl4->access_mutex);
 
 	if (opl4->used) {
-		up(&opl4->access_mutex);
+		mutex_unlock(&opl4->access_mutex);
 		return -EBUSY;
 	}
 	opl4->used++;
@@ -73,12 +73,12 @@
 	if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) {
 		err = snd_opl4_seq_use_inc(opl4);
 		if (err < 0) {
-			up(&opl4->access_mutex);
+			mutex_unlock(&opl4->access_mutex);
 			return err;
 		}
 	}
 
-	up(&opl4->access_mutex);
+	mutex_unlock(&opl4->access_mutex);
 
 	snd_opl4_synth_reset(opl4);
 	return 0;
@@ -90,9 +90,9 @@
 
 	snd_opl4_synth_shutdown(opl4);
 
-	down(&opl4->access_mutex);
+	mutex_lock(&opl4->access_mutex);
 	opl4->used--;
-	up(&opl4->access_mutex);
+	mutex_unlock(&opl4->access_mutex);
 
 	if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM)
 		snd_opl4_seq_use_dec(opl4);
diff -urN oldtree/sound/drivers/vx/vx_core.c newtree/sound/drivers/vx/vx_core.c
--- oldtree/sound/drivers/vx/vx_core.c	2006-02-19 11:41:06.771313704 +0000
+++ newtree/sound/drivers/vx/vx_core.c	2006-02-21 15:58:11.277432128 +0000
@@ -778,7 +778,7 @@
 	chip->type = hw->type;
 	chip->ops = ops;
 	tasklet_init(&chip->tq, vx_interrupt, (unsigned long)chip);
-	init_MUTEX(&chip->mixer_mutex);
+	mutex_init(&chip->mixer_mutex);
 
 	chip->card = card;
 	card->private_data = chip;
diff -urN oldtree/sound/drivers/vx/vx_mixer.c newtree/sound/drivers/vx/vx_mixer.c
--- oldtree/sound/drivers/vx/vx_mixer.c	2006-02-19 11:41:06.773313400 +0000
+++ newtree/sound/drivers/vx/vx_mixer.c	2006-02-21 15:58:11.278431976 +0000
@@ -427,10 +427,10 @@
 {
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
 	int codec = kcontrol->id.index;
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->output_level[codec][0];
 	ucontrol->value.integer.value[1] = chip->output_level[codec][1];
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -438,7 +438,7 @@
 {
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
 	int codec = kcontrol->id.index;
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	if (ucontrol->value.integer.value[0] != chip->output_level[codec][0] ||
 	    ucontrol->value.integer.value[1] != chip->output_level[codec][1]) {
 		vx_set_analog_output_level(chip, codec,
@@ -446,10 +446,10 @@
 					   ucontrol->value.integer.value[1]);
 		chip->output_level[codec][0] = ucontrol->value.integer.value[0];
 		chip->output_level[codec][1] = ucontrol->value.integer.value[1];
-		up(&chip->mixer_mutex);
+		mutex_unlock(&chip->mixer_mutex);
 		return 1;
 	}
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -502,14 +502,14 @@
 static int vx_audio_src_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	if (chip->audio_source_target != ucontrol->value.enumerated.item[0]) {
 		chip->audio_source_target = ucontrol->value.enumerated.item[0];
 		vx_sync_audio_source(chip);
-		up(&chip->mixer_mutex);
+		mutex_unlock(&chip->mixer_mutex);
 		return 1;
 	}
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -550,14 +550,14 @@
 static int vx_clock_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	if (chip->clock_mode != ucontrol->value.enumerated.item[0]) {
 		chip->clock_mode = ucontrol->value.enumerated.item[0];
 		vx_set_clock(chip, chip->freq);
-		up(&chip->mixer_mutex);
+		mutex_unlock(&chip->mixer_mutex);
 		return 1;
 	}
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -587,10 +587,10 @@
 	int audio = kcontrol->private_value & 0xff;
 	int capture = (kcontrol->private_value >> 8) & 1;
 
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->audio_gain[capture][audio];
 	ucontrol->value.integer.value[1] = chip->audio_gain[capture][audio+1];
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -600,15 +600,15 @@
 	int audio = kcontrol->private_value & 0xff;
 	int capture = (kcontrol->private_value >> 8) & 1;
 
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	if (ucontrol->value.integer.value[0] != chip->audio_gain[capture][audio] ||
 	    ucontrol->value.integer.value[1] != chip->audio_gain[capture][audio+1]) {
 		vx_set_audio_gain(chip, audio, capture, ucontrol->value.integer.value[0]);
 		vx_set_audio_gain(chip, audio+1, capture, ucontrol->value.integer.value[1]);
-		up(&chip->mixer_mutex);
+		mutex_unlock(&chip->mixer_mutex);
 		return 1;
 	}
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -617,10 +617,10 @@
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
 	int audio = kcontrol->private_value & 0xff;
 
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->audio_monitor[audio];
 	ucontrol->value.integer.value[1] = chip->audio_monitor[audio+1];
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -629,17 +629,17 @@
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
 	int audio = kcontrol->private_value & 0xff;
 
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	if (ucontrol->value.integer.value[0] != chip->audio_monitor[audio] ||
 	    ucontrol->value.integer.value[1] != chip->audio_monitor[audio+1]) {
 		vx_set_monitor_level(chip, audio, ucontrol->value.integer.value[0],
 				     chip->audio_monitor_active[audio]);
 		vx_set_monitor_level(chip, audio+1, ucontrol->value.integer.value[1],
 				     chip->audio_monitor_active[audio+1]);
-		up(&chip->mixer_mutex);
+		mutex_unlock(&chip->mixer_mutex);
 		return 1;
 	}
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -657,10 +657,10 @@
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
 	int audio = kcontrol->private_value & 0xff;
 
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->audio_active[audio];
 	ucontrol->value.integer.value[1] = chip->audio_active[audio+1];
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -669,15 +669,15 @@
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
 	int audio = kcontrol->private_value & 0xff;
 
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	if (ucontrol->value.integer.value[0] != chip->audio_active[audio] ||
 	    ucontrol->value.integer.value[1] != chip->audio_active[audio+1]) {
 		vx_set_audio_switch(chip, audio, ucontrol->value.integer.value[0]);
 		vx_set_audio_switch(chip, audio+1, ucontrol->value.integer.value[1]);
-		up(&chip->mixer_mutex);
+		mutex_unlock(&chip->mixer_mutex);
 		return 1;
 	}
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -686,10 +686,10 @@
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
 	int audio = kcontrol->private_value & 0xff;
 
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->audio_monitor_active[audio];
 	ucontrol->value.integer.value[1] = chip->audio_monitor_active[audio+1];
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -698,17 +698,17 @@
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
 	int audio = kcontrol->private_value & 0xff;
 
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	if (ucontrol->value.integer.value[0] != chip->audio_monitor_active[audio] ||
 	    ucontrol->value.integer.value[1] != chip->audio_monitor_active[audio+1]) {
 		vx_set_monitor_level(chip, audio, chip->audio_monitor[audio],
 				     ucontrol->value.integer.value[0]);
 		vx_set_monitor_level(chip, audio+1, chip->audio_monitor[audio+1],
 				     ucontrol->value.integer.value[1]);
-		up(&chip->mixer_mutex);
+		mutex_unlock(&chip->mixer_mutex);
 		return 1;
 	}
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -756,12 +756,12 @@
 {
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
 
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	ucontrol->value.iec958.status[0] = (chip->uer_bits >> 0) & 0xff;
 	ucontrol->value.iec958.status[1] = (chip->uer_bits >> 8) & 0xff;
 	ucontrol->value.iec958.status[2] = (chip->uer_bits >> 16) & 0xff;
 	ucontrol->value.iec958.status[3] = (chip->uer_bits >> 24) & 0xff;
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
         return 0;
 }
 
@@ -783,14 +783,14 @@
 	      (ucontrol->value.iec958.status[1] << 8) |
 	      (ucontrol->value.iec958.status[2] << 16) |
 	      (ucontrol->value.iec958.status[3] << 24);
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	if (chip->uer_bits != val) {
 		chip->uer_bits = val;
 		vx_set_iec958_status(chip, val);
-		up(&chip->mixer_mutex);
+		mutex_unlock(&chip->mixer_mutex);
 		return 1;
 	}
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
diff -urN oldtree/sound/i2c/cs8427.c newtree/sound/i2c/cs8427.c
--- oldtree/sound/i2c/cs8427.c	2006-02-19 11:41:06.776312944 +0000
+++ newtree/sound/i2c/cs8427.c	2006-02-21 15:58:11.280431672 +0000
@@ -291,11 +291,13 @@
 {
 	struct cs8427 *chip;
 	unsigned long end_time;
-	int data;
+	int data, aes3input = 0;
 
 	snd_assert(cs8427, return);
 	chip = cs8427->private_data;
 	snd_i2c_lock(cs8427->bus);
+	if ((chip->regmap[CS8427_REG_CLOCKSOURCE] & CS8427_RXDAES3INPUT) == CS8427_RXDAES3INPUT)  /* AES3 bit is set */
+		aes3input = 1;
 	chip->regmap[CS8427_REG_CLOCKSOURCE] &= ~(CS8427_RUN | CS8427_RXDMASK);
 	snd_cs8427_reg_write(cs8427, CS8427_REG_CLOCKSOURCE,
 			     chip->regmap[CS8427_REG_CLOCKSOURCE]);
@@ -316,7 +318,8 @@
 	}
 	snd_i2c_lock(cs8427->bus);
 	chip->regmap[CS8427_REG_CLOCKSOURCE] &= ~CS8427_RXDMASK;
-	chip->regmap[CS8427_REG_CLOCKSOURCE] |= CS8427_RXDAES3INPUT;
+	if (aes3input)
+		chip->regmap[CS8427_REG_CLOCKSOURCE] |= CS8427_RXDAES3INPUT;
 	snd_cs8427_reg_write(cs8427, CS8427_REG_CLOCKSOURCE,
 			     chip->regmap[CS8427_REG_CLOCKSOURCE]);
 	snd_i2c_unlock(cs8427->bus);
diff -urN oldtree/sound/i2c/i2c.c newtree/sound/i2c/i2c.c
--- oldtree/sound/i2c/i2c.c	2006-02-19 11:41:06.777312792 +0000
+++ newtree/sound/i2c/i2c.c	2006-02-21 15:58:11.281431520 +0000
@@ -88,7 +88,7 @@
 	bus = kzalloc(sizeof(*bus), GFP_KERNEL);
 	if (bus == NULL)
 		return -ENOMEM;
-	init_MUTEX(&bus->lock_mutex);
+	mutex_init(&bus->lock_mutex);
 	INIT_LIST_HEAD(&bus->devices);
 	INIT_LIST_HEAD(&bus->buses);
 	bus->card = card;
diff -urN oldtree/sound/isa/ad1848/ad1848_lib.c newtree/sound/isa/ad1848/ad1848_lib.c
--- oldtree/sound/isa/ad1848/ad1848_lib.c	2006-02-19 11:41:06.789310968 +0000
+++ newtree/sound/isa/ad1848/ad1848_lib.c	2006-02-21 15:58:11.374417384 +0000
@@ -387,9 +387,9 @@
 {
 	unsigned long flags;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	if (chip->mode & AD1848_MODE_OPEN) {
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return -EAGAIN;
 	}
 	snd_ad1848_mce_down(chip);
@@ -432,7 +432,7 @@
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 
 	chip->mode = mode;
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 
 	return 0;
 }
@@ -441,9 +441,9 @@
 {
 	unsigned long flags;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	if (!chip->mode) {
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return;
 	}
 	/* disable IRQ */
@@ -471,7 +471,7 @@
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 
 	chip->mode = 0;
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 }
 
 /*
@@ -889,7 +889,7 @@
 	if (chip == NULL)
 		return -ENOMEM;
 	spin_lock_init(&chip->reg_lock);
-	init_MUTEX(&chip->open_mutex);
+	mutex_init(&chip->open_mutex);
 	chip->card = card;
 	chip->port = port;
 	chip->irq = -1;
diff -urN oldtree/sound/isa/cs423x/cs4231_lib.c newtree/sound/isa/cs423x/cs4231_lib.c
--- oldtree/sound/isa/cs423x/cs4231_lib.c	2006-02-19 11:41:06.795310056 +0000
+++ newtree/sound/isa/cs423x/cs4231_lib.c	2006-02-21 15:58:11.376417080 +0000
@@ -531,7 +531,7 @@
 	unsigned long flags;
 	int full_calib = 1;
 
-	down(&chip->mce_mutex);
+	mutex_lock(&chip->mce_mutex);
 	snd_cs4231_calibrate_mute(chip, 1);
 	if (chip->hardware == CS4231_HW_CS4231A ||
 	    (chip->hardware & CS4231_HW_CS4232_MASK)) {
@@ -560,7 +560,7 @@
 		snd_cs4231_mce_down(chip);
 	}
 	snd_cs4231_calibrate_mute(chip, 0);
-	up(&chip->mce_mutex);
+	mutex_unlock(&chip->mce_mutex);
 }
 
 static void snd_cs4231_capture_format(struct snd_cs4231 *chip,
@@ -570,7 +570,7 @@
 	unsigned long flags;
 	int full_calib = 1;
 
-	down(&chip->mce_mutex);
+	mutex_lock(&chip->mce_mutex);
 	snd_cs4231_calibrate_mute(chip, 1);
 	if (chip->hardware == CS4231_HW_CS4231A ||
 	    (chip->hardware & CS4231_HW_CS4232_MASK)) {
@@ -603,7 +603,7 @@
 		snd_cs4231_mce_down(chip);
 	}
 	snd_cs4231_calibrate_mute(chip, 0);
-	up(&chip->mce_mutex);
+	mutex_unlock(&chip->mce_mutex);
 }
 
 /*
@@ -709,15 +709,15 @@
 {
 	unsigned long flags;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	if ((chip->mode & mode) ||
 	    ((chip->mode & CS4231_MODE_OPEN) && chip->single_dma)) {
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return -EAGAIN;
 	}
 	if (chip->mode & CS4231_MODE_OPEN) {
 		chip->mode |= mode;
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return 0;
 	}
 	/* ok. now enable and ack CODEC IRQ */
@@ -737,7 +737,7 @@
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 
 	chip->mode = mode;
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	return 0;
 }
 
@@ -745,10 +745,10 @@
 {
 	unsigned long flags;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	chip->mode &= ~mode;
 	if (chip->mode & CS4231_MODE_OPEN) {
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return;
 	}
 	snd_cs4231_calibrate_mute(chip, 1);
@@ -785,7 +785,7 @@
 	snd_cs4231_calibrate_mute(chip, 0);
 
 	chip->mode = 0;
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 }
 
 /*
@@ -1408,8 +1408,8 @@
 	chip->hwshare = hwshare;
 
 	spin_lock_init(&chip->reg_lock);
-	init_MUTEX(&chip->mce_mutex);
-	init_MUTEX(&chip->open_mutex);
+	mutex_init(&chip->mce_mutex);
+	mutex_init(&chip->open_mutex);
 	chip->card = card;
 	chip->rate_constraint = snd_cs4231_xrate;
 	chip->set_playback_format = snd_cs4231_playback_format;
@@ -1538,8 +1538,8 @@
 		return err;
 
 	spin_lock_init(&chip->reg_lock);
-	init_MUTEX(&chip->mce_mutex);
-	init_MUTEX(&chip->open_mutex);
+	mutex_init(&chip->mce_mutex);
+	mutex_init(&chip->open_mutex);
 
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs4231_playback_ops);
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cs4231_capture_ops);
diff -urN oldtree/sound/isa/cs423x/cs4236_lib.c newtree/sound/isa/cs423x/cs4236_lib.c
--- oldtree/sound/isa/cs423x/cs4236_lib.c	2006-02-19 11:41:06.797309752 +0000
+++ newtree/sound/isa/cs423x/cs4236_lib.c	2006-02-21 15:58:11.377416928 +0000
@@ -841,7 +841,7 @@
 	
 	enable = ucontrol->value.integer.value[0] & 1;
 
-	down(&chip->mce_mutex);
+	mutex_lock(&chip->mce_mutex);
 	snd_cs4231_mce_up(chip);
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x0e) | (0<<2) | (enable << 1);
@@ -854,7 +854,7 @@
 	snd_cs4236_ctrl_out(chip, 4, val);
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 	snd_cs4231_mce_down(chip);
-	up(&chip->mce_mutex);
+	mutex_unlock(&chip->mce_mutex);
 
 #if 0
 	printk("set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
diff -urN oldtree/sound/isa/es18xx.c newtree/sound/isa/es18xx.c
--- oldtree/sound/isa/es18xx.c	2006-02-19 11:41:06.814307168 +0000
+++ newtree/sound/isa/es18xx.c	2006-02-21 15:58:11.379416624 +0000
@@ -49,6 +49,10 @@
  * - contrarily to some pages in DS_1869.PDF the rates can be set
  *   independently.
  *
+ * - Zoom Video is implemented by sharing the FM DAC, thus the user can
+ *   have either FM playback or Video playback but not both simultaneously.
+ *   The Video Playback Switch mixer control toggles this choice.
+ *
  * BUGS:
  *
  * - There is a major trouble I noted:
@@ -63,7 +67,16 @@
  *
  */
 
-
+/*
+ * ES1879 NOTES:
+ * - When Zoom Video is enabled (reg 0x71 bit 6 toggled on) the PCM playback
+ *   seems to be effected (speaker_test plays a lower frequency). Can't find
+ *   anything in the datasheet to account for this, so a Video Playback Switch
+ *   control has been included to allow ZV to be enabled only when necessary.
+ *   Then again on at least one test system the 0x71 bit 6 enable bit is not 
+ *   needed for ZV, so maybe the datasheet is entirely wrong here.
+ */
+ 
 #include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
@@ -148,7 +161,7 @@
 #define ES18XX_DUPLEX_SAME 0x0010	/* Playback and record must share the same rate */
 #define ES18XX_NEW_RATE	0x0020	/* More precise rate setting */
 #define ES18XX_AUXB	0x0040	/* AuxB mixer control */
-#define ES18XX_HWV	0x0080	/* Has hardware volume */
+#define ES18XX_HWV	0x0080	/* Has seperate hardware volume mixer controls*/
 #define ES18XX_MONO	0x0100	/* Mono_in mixer control */
 #define ES18XX_I2S	0x0200	/* I2S mixer control */
 #define ES18XX_MUTEREC	0x0400	/* Record source can be muted */
@@ -788,9 +801,12 @@
 
 	/* Hardware volume */
 	if (status & HWV_IRQ) {
-		int split = snd_es18xx_mixer_read(chip, 0x64) & 0x80;
-		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_switch->id);
-		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_volume->id);
+		int split = 0;
+		if (chip->caps & ES18XX_HWV) {
+			split = snd_es18xx_mixer_read(chip, 0x64) & 0x80;
+			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_switch->id);
+			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_volume->id);
+		}
 		if (!split) {
 			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id);
 			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id);
@@ -939,37 +955,118 @@
  *  MIXER part
  */
 
+/* Record source mux routines:
+ * Depending on the chipset this mux switches between 4, 5, or 8 possible inputs.
+ * bit table for the 4/5 source mux:
+ * reg 1C:
+ *  b2 b1 b0   muxSource
+ *   x  0  x   microphone
+ *   0  1  x   CD
+ *   1  1  0   line
+ *   1  1  1   mixer
+ * if it's "mixer" and it's a 5 source mux chipset then reg 7A bit 3 determines
+ * either the play mixer or the capture mixer.
+ *
+ * "map4Source" translates from source number to reg bit pattern
+ * "invMap4Source" translates from reg bit pattern to source number
+ */
+
 static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[8] = {
+	static char *texts4Source[4] = {
+		"Mic", "CD", "Line", "Master"
+	};
+	static char *texts5Source[5] = {
+		"Mic", "CD", "Line", "Master", "Mix"
+	};
+	static char *texts8Source[8] = {
 		"Mic", "Mic Master", "CD", "AOUT",
 		"Mic1", "Mix", "Line", "Master"
 	};
+	struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);
 
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
-	uinfo->value.enumerated.items = 8;
-	if (uinfo->value.enumerated.item > 7)
-		uinfo->value.enumerated.item = 7;
-	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	switch (chip->version) {
+	case 0x1868:
+	case 0x1878:
+		uinfo->value.enumerated.items = 4;
+		if (uinfo->value.enumerated.item > 3)
+			uinfo->value.enumerated.item = 3;
+		strcpy(uinfo->value.enumerated.name, texts4Source[uinfo->value.enumerated.item]);
+		break;
+	case 0x1887:
+	case 0x1888:
+		uinfo->value.enumerated.items = 5;
+		if (uinfo->value.enumerated.item > 4)
+			uinfo->value.enumerated.item = 4;
+		strcpy(uinfo->value.enumerated.name, texts5Source[uinfo->value.enumerated.item]);
+		break;
+	case 0x1869: /* DS somewhat contradictory for 1869: could be be 5 or 8 */
+	case 0x1879:
+		uinfo->value.enumerated.items = 8;
+		if (uinfo->value.enumerated.item > 7)
+			uinfo->value.enumerated.item = 7;
+		strcpy(uinfo->value.enumerated.name, texts8Source[uinfo->value.enumerated.item]);
+		break;
+	default:
+		return -EINVAL;
+	}
 	return 0;
 }
 
 static int snd_es18xx_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
+	static unsigned char invMap4Source[8] = {0, 0, 1, 1, 0, 0, 2, 3};
 	struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);
-	ucontrol->value.enumerated.item[0] = snd_es18xx_mixer_read(chip, 0x1c) & 0x07;
+	int muxSource = snd_es18xx_mixer_read(chip, 0x1c) & 0x07;
+	if (!(chip->version == 0x1869 || chip->version == 0x1879)) {
+		muxSource = invMap4Source[muxSource];
+		if (muxSource==3 && 
+		    (chip->version == 0x1887 || chip->version == 0x1888) &&
+		    (snd_es18xx_mixer_read(chip, 0x7a) & 0x08)
+		) 
+			muxSource = 4;
+	}
+	ucontrol->value.enumerated.item[0] = muxSource;
 	return 0;
 }
 
 static int snd_es18xx_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
+	static unsigned char map4Source[4] = {0, 2, 6, 7};
 	struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);
 	unsigned char val = ucontrol->value.enumerated.item[0];
-	
-	if (val > 7)
+	unsigned char retVal = 0;
+
+	switch (chip->version) {
+ /* 5 source chips */
+	case 0x1887:
+	case 0x1888:
+		if (val > 4)
+			return -EINVAL;
+		if (val == 4) {
+			retVal = snd_es18xx_mixer_bits(chip, 0x7a, 0x08, 0x08) != 0x08;
+			val = 3;
+		} else
+			retVal = snd_es18xx_mixer_bits(chip, 0x7a, 0x08, 0x00) != 0x00;
+ /* 4 source chips */
+	case 0x1868:
+	case 0x1878:
+		if (val > 3)
+			return -EINVAL;
+		val = map4Source[val];
+		break;
+ /* 8 source chips */
+	case 0x1869:
+	case 0x1879:
+		if (val > 7)
+			return -EINVAL;
+		break;
+	default:
 		return -EINVAL;
-	return snd_es18xx_mixer_bits(chip, 0x1c, 0x07, val) != val;
+	}
+	return (snd_es18xx_mixer_bits(chip, 0x1c, 0x07, val) != val) || retVal;
 }
 
 static int snd_es18xx_info_spatializer_enable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
@@ -1191,19 +1288,22 @@
 	return change;
 }
 
+/* Mixer controls
+ * These arrays contain setup data for mixer controls.
+ * 
+ * The controls that are universal to all chipsets are fully initialized
+ * here.
+ */
 static struct snd_kcontrol_new snd_es18xx_base_controls[] = {
 ES18XX_DOUBLE("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0),
 ES18XX_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1),
 ES18XX_DOUBLE("Line Playback Volume", 0, 0x3e, 0x3e, 4, 0, 15, 0),
 ES18XX_DOUBLE("CD Playback Volume", 0, 0x38, 0x38, 4, 0, 15, 0),
 ES18XX_DOUBLE("FM Playback Volume", 0, 0x36, 0x36, 4, 0, 15, 0),
-ES18XX_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),
 ES18XX_DOUBLE("Mic Playback Volume", 0, 0x1a, 0x1a, 4, 0, 15, 0),
 ES18XX_DOUBLE("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0),
-ES18XX_SINGLE("PC Speaker Playback Volume", 0, 0x3c, 0, 7, 0),
 ES18XX_SINGLE("Record Monitor", 0, 0xa8, 3, 1, 0),
 ES18XX_DOUBLE("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0),
-ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
 {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Capture Source",
@@ -1213,19 +1313,37 @@
 }
 };
 
-static struct snd_kcontrol_new snd_es18xx_mono_in_control = 
-ES18XX_DOUBLE("Mono Input Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0);
-
 static struct snd_kcontrol_new snd_es18xx_recmix_controls[] = {
 ES18XX_DOUBLE("PCM Capture Volume", 0, 0x69, 0x69, 4, 0, 15, 0),
 ES18XX_DOUBLE("Mic Capture Volume", 0, 0x68, 0x68, 4, 0, 15, 0),
 ES18XX_DOUBLE("Line Capture Volume", 0, 0x6e, 0x6e, 4, 0, 15, 0),
 ES18XX_DOUBLE("FM Capture Volume", 0, 0x6b, 0x6b, 4, 0, 15, 0),
-ES18XX_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0),
 ES18XX_DOUBLE("CD Capture Volume", 0, 0x6a, 0x6a, 4, 0, 15, 0),
 ES18XX_DOUBLE("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0)
 };
 
+/*
+ * The chipset specific mixer controls
+ */
+static struct snd_kcontrol_new snd_es18xx_opt_speaker =
+	ES18XX_SINGLE("PC Speaker Playback Volume", 0, 0x3c, 0, 7, 0);
+
+static struct snd_kcontrol_new snd_es18xx_opt_1869[] = {
+ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
+ES18XX_SINGLE("Video Playback Switch", 0, 0x7f, 0, 1, 0),
+ES18XX_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),
+ES18XX_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0)
+};
+
+static struct snd_kcontrol_new snd_es18xx_opt_1878 =
+	ES18XX_DOUBLE("Video Playback Volume", 0, 0x68, 0x68, 4, 0, 15, 0);
+
+static struct snd_kcontrol_new snd_es18xx_opt_1879[] = {
+ES18XX_SINGLE("Video Playback Switch", 0, 0x71, 6, 1, 0),
+ES18XX_DOUBLE("Video Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),
+ES18XX_DOUBLE("Video Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0)
+};
+
 static struct snd_kcontrol_new snd_es18xx_pcm1_controls[] = {
 ES18XX_DOUBLE("PCM Playback Volume", 0, 0x14, 0x14, 4, 0, 15, 0),
 };
@@ -1270,7 +1388,6 @@
 ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0),
 };
 
-#if 0
 static int __devinit snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg)
 {
 	int data;
@@ -1281,7 +1398,6 @@
         spin_unlock_irqrestore(&chip->ctrl_lock, flags);
 	return data;
 }
-#endif
 
 static void __devinit snd_es18xx_config_write(struct snd_es18xx *chip, 
 					      unsigned char reg, unsigned char data)
@@ -1427,6 +1543,17 @@
 		snd_es18xx_mixer_write(chip, 0x58, 0x94);
 		snd_es18xx_mixer_write(chip, 0x5a, 0x80);
 	}
+	/* Flip the "enable I2S" bits for those chipsets that need it */
+	switch (chip->version) {
+	case 0x1879:
+		//Leaving I2S enabled on the 1879 screws up the PCM playback (rate effected somehow)
+		//so a Switch control has been added to toggle this 0x71 bit on/off:
+		//snd_es18xx_mixer_bits(chip, 0x71, 0x40, 0x40);
+		/* Note: we fall through on purpose here. */
+	case 0x1878:
+		snd_es18xx_config_write(chip, 0x29, snd_es18xx_config_read(chip, 0x29) | 0x40);
+		break;
+	}
 	/* Mute input source */
 	if (chip->caps & ES18XX_MUTEREC)
 		mask = 0x10;
@@ -1476,11 +1603,14 @@
 	}
 			
         outb(0x40, chip->port + 0x04);
+	udelay(10);
 	hi = inb(chip->port + 0x05);
+	udelay(10);
 	lo = inb(chip->port + 0x05);
 	if (hi != lo) {
 		chip->version = hi << 8 | lo;
 		chip->ctrl_port = inb(chip->port + 0x05) << 8;
+		udelay(10);
 		chip->ctrl_port += inb(chip->port + 0x05);
 
 		if ((chip->res_ctrl_port = request_region(chip->ctrl_port, 8, "ES18xx - CTRL")) == NULL) {
@@ -1519,22 +1649,22 @@
 
 	switch (chip->version) {
 	case 0x1868:
-		chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_CONTROL | ES18XX_HWV;
+		chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_CONTROL;
 		break;
 	case 0x1869:
 		chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_MONO | ES18XX_MUTEREC | ES18XX_CONTROL | ES18XX_HWV;
 		break;
 	case 0x1878:
-		chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_I2S | ES18XX_CONTROL | ES18XX_HWV;
+		chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_I2S | ES18XX_CONTROL;
 		break;
 	case 0x1879:
 		chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_I2S | ES18XX_CONTROL | ES18XX_HWV;
 		break;
 	case 0x1887:
-		chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME | ES18XX_HWV;
+		chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME;
 		break;
 	case 0x1888:
-		chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME | ES18XX_HWV;
+		chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME;
 		break;
 	default:
 		snd_printk(KERN_ERR "[0x%lx] unsupported chip ES%x\n",
@@ -1778,10 +1908,6 @@
 		}
 	}
 
-	if (chip->caps & ES18XX_MONO) {
-		if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_mono_in_control, chip))) < 0)
-			return err;
-	}
 	if (chip->caps & ES18XX_RECMIX) {
 		for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_recmix_controls); idx++) {
 			if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_recmix_controls[idx], chip))) < 0)
@@ -1819,6 +1945,36 @@
 			
 		}
 	}
+	/* finish initializing other chipset specific controls
+	 */
+	if (chip->version != 0x1868) {
+		err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_opt_speaker,
+						     chip));
+		if (err < 0)
+			return err;
+	}
+	if (chip->version == 0x1869) {
+		for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_opt_1869); idx++) {
+			err = snd_ctl_add(card,
+					  snd_ctl_new1(&snd_es18xx_opt_1869[idx],
+						       chip));
+			if (err < 0)
+				return err;
+		}
+	} else if (chip->version == 0x1878) {
+		err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_opt_1878,
+						     chip));
+		if (err < 0)
+			return err;
+	} else if (chip->version == 0x1879) {
+		for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_opt_1879); idx++) {
+			err = snd_ctl_add(card,
+					  snd_ctl_new1(&snd_es18xx_opt_1879[idx],
+						       chip));
+			if (err < 0)
+				return err;
+		}
+	}
 	return 0;
 }
        
diff -urN oldtree/sound/isa/gus/gus_dma.c newtree/sound/isa/gus/gus_dma.c
--- oldtree/sound/isa/gus/gus_dma.c	2006-02-19 11:41:06.814307168 +0000
+++ newtree/sound/isa/gus/gus_dma.c	2006-02-21 15:58:11.380416472 +0000
@@ -149,10 +149,10 @@
 
 int snd_gf1_dma_init(struct snd_gus_card * gus)
 {
-	down(&gus->dma_mutex);
+	mutex_lock(&gus->dma_mutex);
 	gus->gf1.dma_shared++;
 	if (gus->gf1.dma_shared > 1) {
-		up(&gus->dma_mutex);
+		mutex_unlock(&gus->dma_mutex);
 		return 0;
 	}
 	gus->gf1.interrupt_handler_dma_write = snd_gf1_dma_interrupt;
@@ -160,7 +160,7 @@
 	gus->gf1.dma_data_pcm_last =
 	gus->gf1.dma_data_synth = 
 	gus->gf1.dma_data_synth_last = NULL;
-	up(&gus->dma_mutex);
+	mutex_unlock(&gus->dma_mutex);
 	return 0;
 }
 
@@ -168,7 +168,7 @@
 {
 	struct snd_gf1_dma_block *block;
 
-	down(&gus->dma_mutex);
+	mutex_lock(&gus->dma_mutex);
 	gus->gf1.dma_shared--;
 	if (!gus->gf1.dma_shared) {
 		snd_dma_disable(gus->gf1.dma1);
@@ -185,7 +185,7 @@
 		gus->gf1.dma_data_pcm_last =
 		gus->gf1.dma_data_synth_last = NULL;
 	}
-	up(&gus->dma_mutex);
+	mutex_unlock(&gus->dma_mutex);
 	return 0;
 }
 
diff -urN oldtree/sound/isa/gus/gus_main.c newtree/sound/isa/gus/gus_main.c
--- oldtree/sound/isa/gus/gus_main.c	2006-02-19 11:41:06.817306712 +0000
+++ newtree/sound/isa/gus/gus_main.c	2006-02-21 15:58:11.381416320 +0000
@@ -225,7 +225,7 @@
 	spin_lock_init(&gus->dma_lock);
 	spin_lock_init(&gus->pcm_volume_level_lock);
 	spin_lock_init(&gus->uart_cmd_lock);
-	init_MUTEX(&gus->dma_mutex);
+	mutex_init(&gus->dma_mutex);
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, gus, &ops)) < 0) {
 		snd_gus_free(gus);
 		return err;
diff -urN oldtree/sound/isa/gus/gus_mem.c newtree/sound/isa/gus/gus_mem.c
--- oldtree/sound/isa/gus/gus_mem.c	2006-02-19 11:41:06.818306560 +0000
+++ newtree/sound/isa/gus/gus_mem.c	2006-02-21 15:58:11.382416168 +0000
@@ -34,9 +34,9 @@
 void snd_gf1_mem_lock(struct snd_gf1_mem * alloc, int xup)
 {
 	if (!xup) {
-		down(&alloc->memory_mutex);
+		mutex_lock(&alloc->memory_mutex);
 	} else {
-		up(&alloc->memory_mutex);
+		mutex_unlock(&alloc->memory_mutex);
 	}
 }
 
@@ -59,7 +59,7 @@
 				alloc->first = nblock;
 			else
 				nblock->prev->next = nblock;
-			up(&alloc->memory_mutex);
+			mutex_unlock(&alloc->memory_mutex);
 			return NULL;
 		}
 		pblock = pblock->next;
@@ -80,7 +80,7 @@
 {
 	if (block->share) {	/* ok.. shared block */
 		block->share--;
-		up(&alloc->memory_mutex);
+		mutex_unlock(&alloc->memory_mutex);
 		return 0;
 	}
 	if (alloc->first == block) {
@@ -244,7 +244,7 @@
 #endif
 
 	alloc = &gus->gf1.mem_alloc;
-	init_MUTEX(&alloc->memory_mutex);
+	mutex_init(&alloc->memory_mutex);
 	alloc->first = alloc->last = NULL;
 	if (!gus->gf1.memory)
 		return 0;
@@ -299,7 +299,7 @@
 
 	gus = entry->private_data;
 	alloc = &gus->gf1.mem_alloc;
-	down(&alloc->memory_mutex);
+	mutex_lock(&alloc->memory_mutex);
 	snd_iprintf(buffer, "8-bit banks       : \n    ");
 	for (i = 0; i < 4; i++)
 		snd_iprintf(buffer, "0x%06x (%04ik)%s", alloc->banks_8[i].address, alloc->banks_8[i].size >> 10, i + 1 < 4 ? "," : "");
@@ -343,7 +343,7 @@
 	}
 	snd_iprintf(buffer, "  Total: memory = %i, used = %i, free = %i\n",
 		    total, used, total - used);
-	up(&alloc->memory_mutex);
+	mutex_unlock(&alloc->memory_mutex);
 #if 0
 	ultra_iprintf(buffer, "  Verify: free = %i, max 8-bit block = %i, max 16-bit block = %i\n",
 		      ultra_memory_free_size(card, &card->gf1.mem_alloc),
diff -urN oldtree/sound/isa/gus/gus_synth.c newtree/sound/isa/gus/gus_synth.c
--- oldtree/sound/isa/gus/gus_synth.c	2006-02-19 11:41:06.823305800 +0000
+++ newtree/sound/isa/gus/gus_synth.c	2006-02-21 15:58:11.382416168 +0000
@@ -55,9 +55,9 @@
 
 	if (info->voices > 32)
 		return -EINVAL;
-	down(&gus->register_mutex);
+	mutex_lock(&gus->register_mutex);
 	if (!snd_gus_use_inc(gus)) {
-		up(&gus->register_mutex);
+		mutex_unlock(&gus->register_mutex);
 		return -EFAULT;
 	}
 	for (idx = 0; idx < info->voices; idx++) {
@@ -65,12 +65,12 @@
 		if (voice == NULL) {
 			snd_gus_synth_free_voices(gus, info->sender.client, info->sender.port);
 			snd_gus_use_dec(gus);
-			up(&gus->register_mutex);
+			mutex_unlock(&gus->register_mutex);
 			return -EBUSY;
 		}
 		voice->index = idx;
 	}
-	up(&gus->register_mutex);
+	mutex_unlock(&gus->register_mutex);
 	return 0;
 }
 
@@ -79,10 +79,10 @@
 	struct snd_gus_port * port = private_data;
 	struct snd_gus_card * gus = port->gus;
 
-	down(&gus->register_mutex);
+	mutex_lock(&gus->register_mutex);
 	snd_gus_synth_free_voices(gus, info->sender.client, info->sender.port);
 	snd_gus_use_dec(gus);
-	up(&gus->register_mutex);
+	mutex_unlock(&gus->register_mutex);
 	return 0;
 }
 
@@ -223,7 +223,7 @@
 	if (gus == NULL)
 		return -EINVAL;
 
-	init_MUTEX(&gus->register_mutex);
+	mutex_init(&gus->register_mutex);
 	gus->gf1.seq_client = -1;
 	
 	/* allocate new client */
diff -urN oldtree/sound/isa/sb/sb16_csp.c newtree/sound/isa/sb/sb16_csp.c
--- oldtree/sound/isa/sb/sb16_csp.c	2006-02-19 11:41:06.859300328 +0000
+++ newtree/sound/isa/sb/sb16_csp.c	2006-02-21 15:58:11.383416016 +0000
@@ -138,7 +138,7 @@
 	p->ops.csp_stop = snd_sb_csp_stop;
 	p->ops.csp_qsound_transfer = snd_sb_csp_qsound_transfer;
 
-	init_MUTEX(&p->access_mutex);
+	mutex_init(&p->access_mutex);
 	sprintf(hw->name, "CSP v%d.%d", (version >> 4), (version & 0x0f));
 	hw->iface = SNDRV_HWDEP_IFACE_SB16CSP;
 	hw->private_data = p;
@@ -265,13 +265,13 @@
  */
 static int snd_sb_csp_use(struct snd_sb_csp * p)
 {
-	down(&p->access_mutex);
+	mutex_lock(&p->access_mutex);
 	if (p->used) {
-		up(&p->access_mutex);
+		mutex_unlock(&p->access_mutex);
 		return -EAGAIN;
 	}
 	p->used++;
-	up(&p->access_mutex);
+	mutex_unlock(&p->access_mutex);
 
 	return 0;
 
@@ -282,9 +282,9 @@
  */
 static int snd_sb_csp_unuse(struct snd_sb_csp * p)
 {
-	down(&p->access_mutex);
+	mutex_lock(&p->access_mutex);
 	p->used--;
-	up(&p->access_mutex);
+	mutex_unlock(&p->access_mutex);
 
 	return 0;
 }
diff -urN oldtree/sound/oss/Kconfig newtree/sound/oss/Kconfig
--- oldtree/sound/oss/Kconfig	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/oss/Kconfig	2006-02-21 15:58:30.191556744 +0000
@@ -21,7 +21,7 @@
 
 config SOUND_BT878
 	tristate "BT878 audio dma"
-	depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
+	depends on SOUND_PRIME && PCI
 	---help---
 	  Audio DMA support for bt878 based grabber boards.  As you might have
 	  already noticed, bt878 is listed with two functions in /proc/pci.
@@ -76,7 +76,7 @@
 
 config SOUND_EMU10K1
 	tristate "Creative SBLive! (EMU10K1)"
-	depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
+	depends on SOUND_PRIME && PCI
 	---help---
 	  Say Y or M if you have a PCI sound card using the EMU10K1 chipset,
 	  such as the Creative SBLive!, SB PCI512 or Emu-APS.
@@ -102,7 +102,7 @@
 
 config SOUND_FUSION
 	tristate "Crystal SoundFusion (CS4280/461x)"
-	depends on SOUND_PRIME && PCI
+	depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
 	help
 	  This module drives the Crystal SoundFusion devices (CS4280/46xx
 	  series) when wired as native sound drivers with AC97 codecs.  If
@@ -140,7 +140,7 @@
 
 config SOUND_ES1371
 	tristate "Creative Ensoniq AudioPCI 97 (ES1371)"
-	depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
+	depends on SOUND_PRIME && PCI
 	help
 	  Say Y or M if you have a PCI sound card utilizing the Ensoniq
 	  ES1371 chipset, such as Ensoniq's AudioPCI97. To find out if
@@ -571,7 +571,7 @@
 
 config SOUND_AD1889
 	tristate "AD1889 based cards (AD1819 codec) (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && SOUND_OSS && PCI
+	depends on EXPERIMENTAL && SOUND_OSS && PCI && OBSOLETE_OSS_DRIVER
 	help
 	  Say M here if you have a sound card based on the Analog Devices
 	  AD1889 chip.
@@ -742,7 +742,7 @@
 
 config SOUND_NM256
 	tristate "NM256AV/NM256ZX audio support"
-	depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
+	depends on SOUND_OSS
 	help
 	  Say M here to include audio support for the NeoMagic 256AV/256ZX
 	  chipsets. These are the audio chipsets found in the Sony
@@ -919,7 +919,7 @@
 
 config SOUND_YM3812
 	tristate "Yamaha FM synthesizer (YM3812/OPL-3) support"
-	depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
+	depends on SOUND_OSS
 	---help---
 	  Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
 	  Answering Y is usually a safe and recommended choice, however some
@@ -947,7 +947,7 @@
 
 config SOUND_OPL3SA2
 	tristate "Yamaha OPL3-SA2 and SA3 based PnP cards"
-	depends on SOUND_OSS
+	depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
 	help
 	  Say Y or M if you have a card based on one of these Yamaha sound
 	  chipsets or the "SAx", which is actually a SA3. Read
diff -urN oldtree/sound/oss/ac97_codec.c newtree/sound/oss/ac97_codec.c
--- oldtree/sound/oss/ac97_codec.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/oss/ac97_codec.c	2006-02-21 15:58:28.603798120 +0000
@@ -55,7 +55,7 @@
 #include <linux/pci.h>
 #include <linux/ac97_codec.h>
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #define CODEC_ID_BUFSZ 14
 
@@ -304,7 +304,7 @@
 
 static LIST_HEAD(codecs);
 static LIST_HEAD(codec_drivers);
-static DECLARE_MUTEX(codec_sem);
+static DEFINE_MUTEX(codec_mutex);
 
 /* reads the given OSS mixer from the ac97 the caller must have insured that the ac97 knows
    about that given mixer, and should be holding a spinlock for the card */
@@ -769,9 +769,9 @@
 {
 	/* Remove from the list first, we don't want to be
 	   "rediscovered" */
-	down(&codec_sem);
+	mutex_lock(&codec_mutex);
 	list_del(&codec->list);
-	up(&codec_sem);
+	mutex_unlock(&codec_mutex);
 	/*
 	 *	The driver needs to deal with internal
 	 *	locking to avoid accidents here. 
@@ -889,7 +889,7 @@
 	 *	callbacks.
 	 */
 	 
-	down(&codec_sem);
+	mutex_lock(&codec_mutex);
 	list_add(&codec->list, &codecs);
 
 	list_for_each(l, &codec_drivers) {
@@ -903,7 +903,7 @@
 		}
 	}
 
-	up(&codec_sem);
+	mutex_unlock(&codec_mutex);
 	return 1;
 }
 
@@ -1439,7 +1439,7 @@
 	struct list_head *l;
 	struct ac97_codec *c;
 	
-	down(&codec_sem);
+	mutex_lock(&codec_mutex);
 	INIT_LIST_HEAD(&driver->list);
 	list_add(&driver->list, &codec_drivers);
 	
@@ -1452,7 +1452,7 @@
 			continue;
 		c->driver = driver;
 	}
-	up(&codec_sem);
+	mutex_unlock(&codec_mutex);
 	return 0;
 }
 
@@ -1471,7 +1471,7 @@
 	struct list_head *l;
 	struct ac97_codec *c;
 	
-	down(&codec_sem);
+	mutex_lock(&codec_mutex);
 	list_del_init(&driver->list);
 
 	list_for_each(l, &codecs)
@@ -1483,7 +1483,7 @@
 		}
 	}
 	
-	up(&codec_sem);
+	mutex_unlock(&codec_mutex);
 }
 
 EXPORT_SYMBOL_GPL(ac97_unregister_driver);
@@ -1494,14 +1494,14 @@
 	struct ac97_codec *c;
 	
 	if (remove_master) {
-		down(&codec_sem);
+		mutex_lock(&codec_mutex);
 		list_for_each(l, &codecs)
 		{
 			c = list_entry(l, struct ac97_codec, list);
 			if (supported_mixer(c, SOUND_MIXER_PHONEOUT))
 				c->supported_mixers &= ~SOUND_MASK_PHONEOUT;
 		}
-		up(&codec_sem);
+		mutex_unlock(&codec_mutex);
 	} else
 		ac97_hw[SOUND_MIXER_PHONEOUT].offset = AC97_MASTER_VOL_STEREO;
 
diff -urN oldtree/sound/oss/aci.c newtree/sound/oss/aci.c
--- oldtree/sound/oss/aci.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/oss/aci.c	2006-02-21 15:58:26.442126744 +0000
@@ -56,7 +56,8 @@
 #include <linux/module.h> 
 #include <linux/proc_fs.h>
 #include <linux/slab.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include "sound_config.h"
@@ -79,7 +80,7 @@
 			 * checked with ACI versions prior to 0xb0	*/
 
 static int mixer_device;
-static struct semaphore aci_sem;
+static struct mutex aci_mutex;
 
 #ifdef MODULE
 static int reset;
@@ -212,7 +213,7 @@
 	int write[] = {write1, write2, write3};
 	int read = -EINTR, i;
 
-	if (down_interruptible(&aci_sem))
+	if (mutex_lock_interruptible(&aci_mutex))
 		goto out;
 
 	for (i=0; i<3; i++) {
@@ -227,7 +228,7 @@
 	}
 	
 	read = aci_rawread();
-out_up:	up(&aci_sem);
+out_up:	mutex_unlock(&aci_mutex);
 out:	return read;
 }
 
@@ -603,7 +604,7 @@
 	char *boardname;
 	int i, rc = -EBUSY;
 
-	init_MUTEX(&aci_sem);
+	mutex_init(&aci_mutex);
 
 	outb(0xE3, 0xf8f); /* Write MAD16 password */
 	aci_port = (inb(0xf90) & 0x10) ?
diff -urN oldtree/sound/oss/ad1889.c newtree/sound/oss/ad1889.c
--- oldtree/sound/oss/ad1889.c	2006-02-19 11:41:06.876297744 +0000
+++ newtree/sound/oss/ad1889.c	2006-02-21 15:58:26.443126592 +0000
@@ -38,6 +38,7 @@
 #include <linux/ac97_codec.h>
 #include <linux/sound.h>
 #include <linux/interrupt.h>
+#include <linux/mutex.h>
 
 #include <asm/delay.h>
 #include <asm/io.h>
@@ -238,7 +239,7 @@
 
 	for (i = 0; i < AD_MAX_STATES; i++) {
 		dev->state[i].card = dev;
-		init_MUTEX(&dev->state[i].sem);
+		mutex_init(&dev->state[i].mutex);
 		init_waitqueue_head(&dev->state[i].dmabuf.wait);
 	}
 
@@ -461,7 +462,7 @@
 	ssize_t ret = 0;
 	DECLARE_WAITQUEUE(wait, current);
 
-	down(&state->sem);
+	mutex_lock(&state->mutex);
 #if 0
 	if (dmabuf->mapped) {
 		ret = -ENXIO;
@@ -546,7 +547,7 @@
 err2:
 	remove_wait_queue(&state->dmabuf.wait, &wait);
 err1:
-	up(&state->sem);
+	mutex_unlock(&state->mutex);
 	return ret;
 }
 
diff -urN oldtree/sound/oss/ad1889.h newtree/sound/oss/ad1889.h
--- oldtree/sound/oss/ad1889.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/oss/ad1889.h	2006-02-21 15:58:26.473122032 +0000
@@ -100,7 +100,7 @@
 		unsigned int subdivision;
 	} dmabuf;
 
-	struct semaphore sem;
+	struct mutex mutex;
 } ad1889_state_t;
 
 typedef struct ad1889_dev {
diff -urN oldtree/sound/oss/ali5455.c newtree/sound/oss/ali5455.c
--- oldtree/sound/oss/ali5455.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/oss/ali5455.c	2006-02-21 15:58:26.475121728 +0000
@@ -64,6 +64,8 @@
 #include <linux/smp_lock.h>
 #include <linux/ac97_codec.h>
 #include <linux/interrupt.h>
+#include <linux/mutex.h>
+
 #include <asm/uaccess.h>
 
 #ifndef PCI_DEVICE_ID_ALI_5455
@@ -234,7 +236,7 @@
 	struct ali_card *card;	/* Card info */
 
 	/* single open lock mechanism, only used for recording */
-	struct semaphore open_sem;
+	struct mutex open_mutex;
 	wait_queue_head_t open_wait;
 
 	/* file mode */
@@ -2807,7 +2809,7 @@
 	state->card = card;
 	state->magic = ALI5455_STATE_MAGIC;
 	init_waitqueue_head(&dmabuf->wait);
-	init_MUTEX(&state->open_sem);
+	mutex_init(&state->open_mutex);
 	file->private_data = state;
 	dmabuf->trigger = 0;
 	/* allocate hardware channels */
@@ -3359,7 +3361,7 @@
 		state->card = card;
 		state->magic = ALI5455_STATE_MAGIC;
 		init_waitqueue_head(&dmabuf->wait);
-		init_MUTEX(&state->open_sem);
+		mutex_init(&state->open_mutex);
 		dmabuf->fmt = ALI5455_FMT_STEREO | ALI5455_FMT_16BIT;
 		dmabuf->trigger = PCM_ENABLE_OUTPUT;
 		ali_set_dac_rate(state, 48000);
diff -urN oldtree/sound/oss/au1000.c newtree/sound/oss/au1000.c
--- oldtree/sound/oss/au1000.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/oss/au1000.c	2006-02-21 15:58:26.477121424 +0000
@@ -68,6 +68,8 @@
 #include <linux/smp_lock.h>
 #include <linux/ac97_codec.h>
 #include <linux/interrupt.h>
+#include <linux/mutex.h>
+
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/mach-au1x00/au1000.h>
@@ -120,8 +122,8 @@
 	int             no_vra;	// do not use VRA
 
 	spinlock_t      lock;
-	struct semaphore open_sem;
-	struct semaphore sem;
+	struct mutex open_mutex;
+	struct mutex sem;
 	mode_t          open_mode;
 	wait_queue_head_t open_wait;
 
@@ -1106,7 +1108,7 @@
 
 	count *= db->cnt_factor;
 
-	down(&s->sem);
+	mutex_lock(&s->sem);
 	add_wait_queue(&db->wait, &wait);
 
 	while (count > 0) {
@@ -1125,14 +1127,14 @@
 						ret = -EAGAIN;
 					goto out;
 				}
-				up(&s->sem);
+				mutex_unlock(&s->sem);
 				schedule();
 				if (signal_pending(current)) {
 					if (!ret)
 						ret = -ERESTARTSYS;
 					goto out2;
 				}
-				down(&s->sem);
+				mutex_lock(&s->sem);
 			}
 		} while (avail <= 0);
 
@@ -1159,7 +1161,7 @@
 	}			// while (count > 0)
 
 out:
-	up(&s->sem);
+	mutex_unlock(&s->sem);
 out2:
 	remove_wait_queue(&db->wait, &wait);
 	set_current_state(TASK_RUNNING);
@@ -1187,7 +1189,7 @@
 
 	count *= db->cnt_factor;
 
-	down(&s->sem);	
+	mutex_lock(&s->sem);
 	add_wait_queue(&db->wait, &wait);
 
 	while (count > 0) {
@@ -1204,14 +1206,14 @@
 						ret = -EAGAIN;
 					goto out;
 				}
-				up(&s->sem);
+				mutex_unlock(&s->sem);
 				schedule();
 				if (signal_pending(current)) {
 					if (!ret)
 						ret = -ERESTARTSYS;
 					goto out2;
 				}
-				down(&s->sem);
+				mutex_lock(&s->sem);
 			}
 		} while (avail <= 0);
 
@@ -1240,7 +1242,7 @@
 	}			// while (count > 0)
 
 out:
-	up(&s->sem);
+	mutex_unlock(&s->sem);
 out2:
 	remove_wait_queue(&db->wait, &wait);
 	set_current_state(TASK_RUNNING);
@@ -1298,7 +1300,7 @@
 	dbg("%s", __FUNCTION__);
     
 	lock_kernel();
-	down(&s->sem);
+	mutex_lock(&s->sem);
 	if (vma->vm_flags & VM_WRITE)
 		db = &s->dma_dac;
 	else if (vma->vm_flags & VM_READ)
@@ -1324,7 +1326,7 @@
 	vma->vm_flags &= ~VM_IO;
 	db->mapped = 1;
 out:
-	up(&s->sem);
+	mutex_unlock(&s->sem);
 	unlock_kernel();
 	return ret;
 }
@@ -1829,21 +1831,21 @@
 	
 	file->private_data = s;
 	/* wait for device to become free */
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	while (s->open_mode & file->f_mode) {
 		if (file->f_flags & O_NONBLOCK) {
-			up(&s->open_sem);
+			mutex_unlock(&s->open_mutex);
 			return -EBUSY;
 		}
 		add_wait_queue(&s->open_wait, &wait);
 		__set_current_state(TASK_INTERRUPTIBLE);
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		schedule();
 		remove_wait_queue(&s->open_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&s->open_sem);
+		mutex_lock(&s->open_mutex);
 	}
 
 	stop_dac(s);
@@ -1879,8 +1881,8 @@
 	}
 
 	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	up(&s->open_sem);
-	init_MUTEX(&s->sem);
+	mutex_unlock(&s->open_mutex);
+	mutex_init(&s->sem);
 	return nonseekable_open(inode, file);
 }
 
@@ -1896,7 +1898,7 @@
 		lock_kernel();
 	}
 
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	if (file->f_mode & FMODE_WRITE) {
 		stop_dac(s);
 		dealloc_dmabuf(s, &s->dma_dac);
@@ -1906,7 +1908,7 @@
 		dealloc_dmabuf(s, &s->dma_adc);
 	}
 	s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	wake_up(&s->open_wait);
 	unlock_kernel();
 	return 0;
@@ -1996,7 +1998,7 @@
 	init_waitqueue_head(&s->dma_adc.wait);
 	init_waitqueue_head(&s->dma_dac.wait);
 	init_waitqueue_head(&s->open_wait);
-	init_MUTEX(&s->open_sem);
+	mutex_init(&s->open_mutex);
 	spin_lock_init(&s->lock);
 	s->codec.private_data = s;
 	s->codec.id = 0;
diff -urN oldtree/sound/oss/au1550_ac97.c newtree/sound/oss/au1550_ac97.c
--- oldtree/sound/oss/au1550_ac97.c	2006-02-19 11:41:06.877297592 +0000
+++ newtree/sound/oss/au1550_ac97.c	2006-02-21 15:58:26.504117320 +0000
@@ -52,6 +52,8 @@
 #include <linux/spinlock.h>
 #include <linux/smp_lock.h>
 #include <linux/ac97_codec.h>
+#include <linux/mutex.h>
+
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
@@ -90,8 +92,8 @@
 	int             no_vra;		/* do not use VRA */
 
 	spinlock_t      lock;
-	struct semaphore open_sem;
-	struct semaphore sem;
+	struct mutex open_mutex;
+	struct mutex sem;
 	mode_t          open_mode;
 	wait_queue_head_t open_wait;
 
@@ -1044,7 +1046,7 @@
 
 	count *= db->cnt_factor;
 
-	down(&s->sem);
+	mutex_lock(&s->sem);
 	add_wait_queue(&db->wait, &wait);
 
 	while (count > 0) {
@@ -1064,14 +1066,14 @@
 						ret = -EAGAIN;
 					goto out;
 				}
-				up(&s->sem);
+				mutex_unlock(&s->sem);
 				schedule();
 				if (signal_pending(current)) {
 					if (!ret)
 						ret = -ERESTARTSYS;
 					goto out2;
 				}
-				down(&s->sem);
+				mutex_lock(&s->sem);
 			}
 		} while (avail <= 0);
 
@@ -1099,7 +1101,7 @@
 	}			/* while (count > 0) */
 
 out:
-	up(&s->sem);
+	mutex_unlock(&s->sem);
 out2:
 	remove_wait_queue(&db->wait, &wait);
 	set_current_state(TASK_RUNNING);
@@ -1125,7 +1127,7 @@
 
 	count *= db->cnt_factor;
 
-	down(&s->sem);
+	mutex_lock(&s->sem);
 	add_wait_queue(&db->wait, &wait);
 
 	while (count > 0) {
@@ -1143,14 +1145,14 @@
 						ret = -EAGAIN;
 					goto out;
 				}
-				up(&s->sem);
+				mutex_unlock(&s->sem);
 				schedule();
 				if (signal_pending(current)) {
 					if (!ret)
 						ret = -ERESTARTSYS;
 					goto out2;
 				}
-				down(&s->sem);
+				mutex_lock(&s->sem);
 			}
 		} while (avail <= 0);
 
@@ -1196,7 +1198,7 @@
 	}			/* while (count > 0) */
 
 out:
-	up(&s->sem);
+	mutex_unlock(&s->sem);
 out2:
 	remove_wait_queue(&db->wait, &wait);
 	set_current_state(TASK_RUNNING);
@@ -1253,7 +1255,7 @@
 	int ret = 0;
 
 	lock_kernel();
-	down(&s->sem);
+	mutex_lock(&s->sem);
 	if (vma->vm_flags & VM_WRITE)
 		db = &s->dma_dac;
 	else if (vma->vm_flags & VM_READ)
@@ -1279,7 +1281,7 @@
 	vma->vm_flags &= ~VM_IO;
 	db->mapped = 1;
 out:
-	up(&s->sem);
+	mutex_unlock(&s->sem);
 	unlock_kernel();
 	return ret;
 }
@@ -1790,21 +1792,21 @@
 
 	file->private_data = s;
 	/* wait for device to become free */
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	while (s->open_mode & file->f_mode) {
 		if (file->f_flags & O_NONBLOCK) {
-			up(&s->open_sem);
+			mutex_unlock(&s->open_mutex);
 			return -EBUSY;
 		}
 		add_wait_queue(&s->open_wait, &wait);
 		__set_current_state(TASK_INTERRUPTIBLE);
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		schedule();
 		remove_wait_queue(&s->open_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&s->open_sem);
+		mutex_lock(&s->open_mutex);
 	}
 
 	stop_dac(s);
@@ -1840,8 +1842,8 @@
 	}
 
 	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	up(&s->open_sem);
-	init_MUTEX(&s->sem);
+	mutex_unlock(&s->open_mutex);
+	mutex_init(&s->sem);
 	return 0;
 }
 
@@ -1858,7 +1860,7 @@
 		lock_kernel();
 	}
 
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	if (file->f_mode & FMODE_WRITE) {
 		stop_dac(s);
 		kfree(s->dma_dac.rawbuf);
@@ -1870,7 +1872,7 @@
 		s->dma_adc.rawbuf = NULL;
 	}
 	s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	wake_up(&s->open_wait);
 	unlock_kernel();
 	return 0;
@@ -1902,7 +1904,7 @@
 	init_waitqueue_head(&s->dma_adc.wait);
 	init_waitqueue_head(&s->dma_dac.wait);
 	init_waitqueue_head(&s->open_wait);
-	init_MUTEX(&s->open_sem);
+	mutex_init(&s->open_mutex);
 	spin_lock_init(&s->lock);
 
 	s->codec = ac97_alloc_codec();
diff -urN oldtree/sound/oss/btaudio.c newtree/sound/oss/btaudio.c
--- oldtree/sound/oss/btaudio.c	2006-02-19 11:41:06.878297440 +0000
+++ newtree/sound/oss/btaudio.c	2006-02-21 15:58:26.505117168 +0000
@@ -32,6 +32,8 @@
 #include <linux/soundcard.h>
 #include <linux/slab.h>
 #include <linux/kdev_t.h>
+#include <linux/mutex.h>
+
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
@@ -108,7 +110,7 @@
 
 	/* locking */
 	int            users;
-	struct semaphore lock;
+	struct mutex lock;
 
 	/* risc instructions */
 	unsigned int   risc_size;
@@ -440,7 +442,7 @@
 static int btaudio_dsp_open(struct inode *inode, struct file *file,
 			    struct btaudio *bta, int analog)
 {
-	down(&bta->lock);
+	mutex_lock(&bta->lock);
 	if (bta->users)
 		goto busy;
 	bta->users++;
@@ -452,11 +454,11 @@
 	bta->read_count = 0;
 	bta->sampleshift = 0;
 
-	up(&bta->lock);
+	mutex_unlock(&bta->lock);
 	return 0;
 
  busy:
-	up(&bta->lock);
+	mutex_unlock(&bta->lock);
 	return -EBUSY;
 }
 
@@ -496,11 +498,11 @@
 {
 	struct btaudio *bta = file->private_data;
 
-	down(&bta->lock);
+	mutex_lock(&bta->lock);
 	if (bta->recording)
 		stop_recording(bta);
 	bta->users--;
-	up(&bta->lock);
+	mutex_unlock(&bta->lock);
 	return 0;
 }
 
@@ -513,7 +515,7 @@
 	DECLARE_WAITQUEUE(wait, current);
 
 	add_wait_queue(&bta->readq, &wait);
-	down(&bta->lock);
+	mutex_lock(&bta->lock);
 	while (swcount > 0) {
 		if (0 == bta->read_count) {
 			if (!bta->recording) {
@@ -528,10 +530,10 @@
 					ret = -EAGAIN;
 				break;
 			}
-			up(&bta->lock);
+			mutex_unlock(&bta->lock);
 			current->state = TASK_INTERRUPTIBLE;
 			schedule();
-			down(&bta->lock);
+			mutex_lock(&bta->lock);
 			if(signal_pending(current)) {
 				if (0 == ret)
 					ret = -EINTR;
@@ -604,7 +606,7 @@
 		if (bta->read_offset == bta->buf_size)
 			bta->read_offset = 0;
 	}
-	up(&bta->lock);
+	mutex_unlock(&bta->lock);
 	remove_wait_queue(&bta->readq, &wait);
 	current->state = TASK_RUNNING;
 	return ret;
@@ -651,10 +653,10 @@
 			bta->decimation  = 0;
 		}
 		if (bta->recording) {
-			down(&bta->lock);
+			mutex_lock(&bta->lock);
 			stop_recording(bta);
 			start_recording(bta);
-			up(&bta->lock);
+			mutex_unlock(&bta->lock);
 		}
 		/* fall through */
         case SOUND_PCM_READ_RATE:
@@ -716,10 +718,10 @@
 			else
 				bta->bits = 16;
 			if (bta->recording) {
-				down(&bta->lock);
+				mutex_lock(&bta->lock);
 				stop_recording(bta);
 				start_recording(bta);
-				up(&bta->lock);
+				mutex_unlock(&bta->lock);
 			}
 		}
 		if (debug)
@@ -736,9 +738,9 @@
 
         case SNDCTL_DSP_RESET:
 		if (bta->recording) {
-			down(&bta->lock);
+			mutex_lock(&bta->lock);
 			stop_recording(bta);
-			up(&bta->lock);
+			mutex_unlock(&bta->lock);
 		}
 		return 0;
         case SNDCTL_DSP_GETBLKSIZE:
@@ -941,7 +943,7 @@
 	if (rate)
 		bta->rate = rate;
 	
-	init_MUTEX(&bta->lock);
+	mutex_init(&bta->lock);
         init_waitqueue_head(&bta->readq);
 
 	if (-1 != latency) {
diff -urN oldtree/sound/oss/cmpci.c newtree/sound/oss/cmpci.c
--- oldtree/sound/oss/cmpci.c	2006-02-19 11:41:06.879297288 +0000
+++ newtree/sound/oss/cmpci.c	2006-02-21 15:58:33.183101960 +0000
@@ -138,6 +138,8 @@
 #endif
 #ifdef CONFIG_SOUND_CMPCI_JOYSTICK
 #include <linux/gameport.h>
+#include <linux/mutex.h>
+
 #endif
 
 /* --------------------------------------------------------------------- */
@@ -392,7 +394,7 @@
 	unsigned char fmt, enable;
 
 	spinlock_t lock;
-	struct semaphore open_sem;
+	struct mutex open_mutex;
 	mode_t open_mode;
 	wait_queue_head_t open_wait;
 
@@ -1711,7 +1713,7 @@
 	case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
 		if (get_user(val, p))
 			return -EFAULT;
-		i = generic_hweight32(val);
+		i = hweight32(val);
 		for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
 			if (!(val & (1 << i)))
 				continue;
@@ -2825,21 +2827,21 @@
        	VALIDATE_STATE(s);
 	file->private_data = s;
 	/* wait for device to become free */
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	while (s->open_mode & file->f_mode) {
 		if (file->f_flags & O_NONBLOCK) {
-			up(&s->open_sem);
+			mutex_unlock(&s->open_mutex);
 			return -EBUSY;
 		}
 		add_wait_queue(&s->open_wait, &wait);
 		__set_current_state(TASK_INTERRUPTIBLE);
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		schedule();
 		remove_wait_queue(&s->open_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&s->open_sem);
+		mutex_lock(&s->open_mutex);
 	}
 	if (file->f_mode & FMODE_READ) {
 		s->status &= ~DO_BIGENDIAN_R;
@@ -2867,7 +2869,7 @@
 	}
 	set_fmt(s, fmtm, fmts);
 	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	return nonseekable_open(inode, file);
 }
 
@@ -2879,7 +2881,7 @@
 	lock_kernel();
 	if (file->f_mode & FMODE_WRITE)
 		drain_dac(s, file->f_flags & O_NONBLOCK);
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	if (file->f_mode & FMODE_WRITE) {
 		stop_dac(s);
 
@@ -2903,7 +2905,7 @@
 		s->status &= ~DO_BIGENDIAN_R;
 	}
 	s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE));
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	wake_up(&s->open_wait);
 	unlock_kernel();
 	return 0;
@@ -3080,7 +3082,7 @@
 	init_waitqueue_head(&s->dma_adc.wait);
 	init_waitqueue_head(&s->dma_dac.wait);
 	init_waitqueue_head(&s->open_wait);
-	init_MUTEX(&s->open_sem);
+	mutex_init(&s->open_mutex);
 	spin_lock_init(&s->lock);
 	s->magic = CM_MAGIC;
 	s->dev = pcidev;
diff -urN oldtree/sound/oss/cs4281/cs4281m.c newtree/sound/oss/cs4281/cs4281m.c
--- oldtree/sound/oss/cs4281/cs4281m.c	2006-02-19 11:41:06.881296984 +0000
+++ newtree/sound/oss/cs4281/cs4281m.c	2006-02-21 15:58:28.625794776 +0000
@@ -245,9 +245,9 @@
 	void *tmpbuff;		// tmp buffer for sample conversions
 	unsigned ena;
 	spinlock_t lock;
-	struct semaphore open_sem;
-	struct semaphore open_sem_adc;
-	struct semaphore open_sem_dac;
+	struct mutex open_sem;
+	struct mutex open_sem_adc;
+	struct mutex open_sem_dac;
 	mode_t open_mode;
 	wait_queue_head_t open_wait;
 	wait_queue_head_t open_wait_adc;
@@ -3598,20 +3598,20 @@
 
 	if (file->f_mode & FMODE_WRITE) {
 		drain_dac(s, file->f_flags & O_NONBLOCK);
-		down(&s->open_sem_dac);
+		mutex_lock(&s->open_sem_dac);
 		stop_dac(s);
 		dealloc_dmabuf(s, &s->dma_dac);
 		s->open_mode &= ~FMODE_WRITE;
-		up(&s->open_sem_dac);
+		mutex_unlock(&s->open_sem_dac);
 		wake_up(&s->open_wait_dac);
 	}
 	if (file->f_mode & FMODE_READ) {
 		drain_adc(s, file->f_flags & O_NONBLOCK);
-		down(&s->open_sem_adc);
+		mutex_lock(&s->open_sem_adc);
 		stop_adc(s);
 		dealloc_dmabuf(s, &s->dma_adc);
 		s->open_mode &= ~FMODE_READ;
-		up(&s->open_sem_adc);
+		mutex_unlock(&s->open_sem_adc);
 		wake_up(&s->open_wait_adc);
 	}
 	return 0;
@@ -3651,33 +3651,33 @@
 		return -ENODEV;
 	}
 	if (file->f_mode & FMODE_WRITE) {
-		down(&s->open_sem_dac);
+		mutex_lock(&s->open_sem_dac);
 		while (s->open_mode & FMODE_WRITE) {
 			if (file->f_flags & O_NONBLOCK) {
-				up(&s->open_sem_dac);
+				mutex_unlock(&s->open_sem_dac);
 				return -EBUSY;
 			}
-			up(&s->open_sem_dac);
+			mutex_unlock(&s->open_sem_dac);
 			interruptible_sleep_on(&s->open_wait_dac);
 
 			if (signal_pending(current))
 				return -ERESTARTSYS;
-			down(&s->open_sem_dac);
+			mutex_lock(&s->open_sem_dac);
 		}
 	}
 	if (file->f_mode & FMODE_READ) {
-		down(&s->open_sem_adc);
+		mutex_lock(&s->open_sem_adc);
 		while (s->open_mode & FMODE_READ) {
 			if (file->f_flags & O_NONBLOCK) {
-				up(&s->open_sem_adc);
+				mutex_unlock(&s->open_sem_adc);
 				return -EBUSY;
 			}
-			up(&s->open_sem_adc);
+			mutex_unlock(&s->open_sem_adc);
 			interruptible_sleep_on(&s->open_wait_adc);
 
 			if (signal_pending(current))
 				return -ERESTARTSYS;
-			down(&s->open_sem_adc);
+			mutex_lock(&s->open_sem_adc);
 		}
 	}
 	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
@@ -3691,7 +3691,7 @@
 		s->ena &= ~FMODE_READ;
 		s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags =
 		    s->dma_adc.subdivision = 0;
-		up(&s->open_sem_adc);
+		mutex_unlock(&s->open_sem_adc);
 
 		if (prog_dmabuf_adc(s)) {
 			CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR
@@ -3711,7 +3711,7 @@
 		s->ena &= ~FMODE_WRITE;
 		s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags =
 		    s->dma_dac.subdivision = 0;
-		up(&s->open_sem_dac);
+		mutex_unlock(&s->open_sem_dac);
 
 		if (prog_dmabuf_dac(s)) {
 			CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR
@@ -3978,17 +3978,17 @@
 	VALIDATE_STATE(s);
 	file->private_data = s;
 	// wait for device to become free 
-	down(&s->open_sem);
+	mutex_lock(&s->open_sem);
 	while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
 		if (file->f_flags & O_NONBLOCK) {
-			up(&s->open_sem);
+			mutex_unlock(&s->open_sem);
 			return -EBUSY;
 		}
-		up(&s->open_sem);
+		mutex_unlock(&s->open_sem);
 		interruptible_sleep_on(&s->open_wait);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&s->open_sem);
+		mutex_lock(&s->open_sem);
 	}
 	spin_lock_irqsave(&s->lock, flags);
 	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
@@ -4018,7 +4018,7 @@
 	    (file->
 	     f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ |
 					    FMODE_MIDI_WRITE);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_sem);
 	return nonseekable_open(inode, file);
 }
 
@@ -4057,7 +4057,7 @@
 		remove_wait_queue(&s->midi.owait, &wait);
 		current->state = TASK_RUNNING;
 	}
-	down(&s->open_sem);
+	mutex_lock(&s->open_sem);
 	s->open_mode &=
 	    (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ |
 						     FMODE_MIDI_WRITE);
@@ -4067,7 +4067,7 @@
 		del_timer(&s->midi.timer);
 	}
 	spin_unlock_irqrestore(&s->lock, flags);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_sem);
 	wake_up(&s->open_wait);
 	return 0;
 }
@@ -4300,9 +4300,9 @@
 	init_waitqueue_head(&s->open_wait_dac);
 	init_waitqueue_head(&s->midi.iwait);
 	init_waitqueue_head(&s->midi.owait);
-	init_MUTEX(&s->open_sem);
-	init_MUTEX(&s->open_sem_adc);
-	init_MUTEX(&s->open_sem_dac);
+	mutex_init(&s->open_sem);
+	mutex_init(&s->open_sem_adc);
+	mutex_init(&s->open_sem_dac);
 	spin_lock_init(&s->lock);
 	s->pBA0phys = pci_resource_start(pcidev, 0);
 	s->pBA1phys = pci_resource_start(pcidev, 1);
diff -urN oldtree/sound/oss/cs46xx.c newtree/sound/oss/cs46xx.c
--- oldtree/sound/oss/cs46xx.c	2006-02-19 11:41:06.885296376 +0000
+++ newtree/sound/oss/cs46xx.c	2006-02-21 15:58:26.536112456 +0000
@@ -90,6 +90,7 @@
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/ac97_codec.h>
+#include <linux/mutex.h>
 
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -238,7 +239,7 @@
 	struct cs_card *card;	/* Card info */
 
 	/* single open lock mechanism, only used for recording */
-	struct semaphore open_sem;
+	struct mutex open_mutex;
 	wait_queue_head_t open_wait;
 
 	/* file mode */
@@ -297,7 +298,7 @@
 		unsigned subdivision;
 	} dmabuf;
 	/* Guard against mmap/write/read races */
-	struct semaphore sem;
+	struct mutex sem;
 };
 
 struct cs_card {
@@ -375,7 +376,7 @@
 		unsigned char ibuf[CS_MIDIINBUF];
 		unsigned char obuf[CS_MIDIOUTBUF];
 		mode_t open_mode;
-		struct semaphore open_sem;
+		struct mutex open_mutex;
 	} midi;
 	struct cs46xx_pm pm;
 };
@@ -1428,9 +1429,9 @@
 {
 	int ret;
 	
-	down(&state->sem);
+	mutex_lock(&state->sem);
 	ret = __prog_dmabuf(state);
-	up(&state->sem);
+	mutex_unlock(&state->sem);
 	
 	return ret;
 }
@@ -1831,17 +1832,17 @@
 
         file->private_data = card;
         /* wait for device to become free */
-        down(&card->midi.open_sem);
+        mutex_lock(&card->midi.open_mutex);
         while (card->midi.open_mode & file->f_mode) {
                 if (file->f_flags & O_NONBLOCK) {
-                        up(&card->midi.open_sem);
+                        mutex_unlock(&card->midi.open_mutex);
                         return -EBUSY;
                 }
-                up(&card->midi.open_sem);
+                mutex_unlock(&card->midi.open_mutex);
                 interruptible_sleep_on(&card->midi.open_wait);
                 if (signal_pending(current))
                         return -ERESTARTSYS;
-                down(&card->midi.open_sem);
+                mutex_lock(&card->midi.open_mutex);
         }
         spin_lock_irqsave(&card->midi.lock, flags);
         if (!(card->midi.open_mode & (FMODE_READ | FMODE_WRITE))) {
@@ -1859,7 +1860,7 @@
         }
         spin_unlock_irqrestore(&card->midi.lock, flags);
         card->midi.open_mode |= (file->f_mode & (FMODE_READ | FMODE_WRITE));
-        up(&card->midi.open_sem);
+        mutex_unlock(&card->midi.open_mutex);
         return 0;
 }
 
@@ -1891,9 +1892,9 @@
                 remove_wait_queue(&card->midi.owait, &wait);
                 current->state = TASK_RUNNING;
         }
-        down(&card->midi.open_sem);
+        mutex_lock(&card->midi.open_mutex);
         card->midi.open_mode &= (~(file->f_mode & (FMODE_READ | FMODE_WRITE)));
-        up(&card->midi.open_sem);
+        mutex_unlock(&card->midi.open_mutex);
         wake_up(&card->midi.open_wait);
         return 0;
 }
@@ -2081,7 +2082,7 @@
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
 	
-	down(&state->sem);
+	mutex_lock(&state->sem);
 	if (!dmabuf->ready && (ret = __prog_dmabuf(state)))
 		goto out2;
 
@@ -2114,13 +2115,13 @@
 				if (!ret) ret = -EAGAIN;
 				goto out;
  			}
-			up(&state->sem);
+			mutex_unlock(&state->sem);
 			schedule();
 			if (signal_pending(current)) {
 				if(!ret) ret = -ERESTARTSYS;
 				goto out;
 			}
-			down(&state->sem);
+			mutex_lock(&state->sem);
 			if (dmabuf->mapped) 
 			{
 				if(!ret)
@@ -2155,7 +2156,7 @@
 out:
 	remove_wait_queue(&state->dmabuf.wait, &wait);
 out2:
-	up(&state->sem);
+	mutex_unlock(&state->sem);
 	set_current_state(TASK_RUNNING);
 	CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4, 
 		printk("cs46xx: cs_read()- %zd\n",ret) );
@@ -2184,7 +2185,7 @@
 		return -EFAULT;
 	dmabuf = &state->dmabuf;
 
-	down(&state->sem);
+	mutex_lock(&state->sem);
 	if (dmabuf->mapped)
 	{
 		ret = -ENXIO;
@@ -2240,13 +2241,13 @@
 				if (!ret) ret = -EAGAIN;
 				goto out;
  			}
-			up(&state->sem);
+			mutex_unlock(&state->sem);
 			schedule();
  			if (signal_pending(current)) {
 				if(!ret) ret = -ERESTARTSYS;
 				goto out;
  			}
-			down(&state->sem);
+			mutex_lock(&state->sem);
 			if (dmabuf->mapped)
 			{
 				if(!ret)
@@ -2278,7 +2279,7 @@
 		start_dac(state);
 	}
 out:
-	up(&state->sem);
+	mutex_unlock(&state->sem);
 	remove_wait_queue(&state->dmabuf.wait, &wait);
 	set_current_state(TASK_RUNNING);
 
@@ -2411,7 +2412,7 @@
 		goto out;
 	}
 
-	down(&state->sem);	
+	mutex_lock(&state->sem);
 	dmabuf = &state->dmabuf;
 	if (cs4x_pgoff(vma) != 0)
 	{
@@ -2438,7 +2439,7 @@
 
 	CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_mmap()-\n") );
 out:
-	up(&state->sem);
+	mutex_unlock(&state->sem);
 	return ret;	
 }
 
@@ -3200,7 +3201,7 @@
 			if (state == NULL)
 				return -ENOMEM;
 			memset(state, 0, sizeof(struct cs_state));
-			init_MUTEX(&state->sem);
+			mutex_init(&state->sem);
 			dmabuf = &state->dmabuf;
 			dmabuf->pbuf = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 			if(dmabuf->pbuf==NULL)
@@ -3241,10 +3242,10 @@
 		state->virt = 0;
 		state->magic = CS_STATE_MAGIC;
 		init_waitqueue_head(&dmabuf->wait);
-		init_MUTEX(&state->open_sem);
+		mutex_init(&state->open_mutex);
 		file->private_data = card;
 
-		down(&state->open_sem);
+		mutex_lock(&state->open_mutex);
 
 		/* set default sample format. According to OSS Programmer's Guide  /dev/dsp
 		   should be default to unsigned 8-bits, mono, with sample rate 8kHz and
@@ -3260,7 +3261,7 @@
 		cs_set_divisor(dmabuf);
 
 		state->open_mode |= FMODE_READ;
-		up(&state->open_sem);
+		mutex_unlock(&state->open_mutex);
 	}
 	if(file->f_mode & FMODE_WRITE)
 	{
@@ -3271,7 +3272,7 @@
 			if (state == NULL)
 				return -ENOMEM;
 			memset(state, 0, sizeof(struct cs_state));
-			init_MUTEX(&state->sem);
+			mutex_init(&state->sem);
 			dmabuf = &state->dmabuf;
 			dmabuf->pbuf = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 			if(dmabuf->pbuf==NULL)
@@ -3312,10 +3313,10 @@
 		state->virt = 1;
 		state->magic = CS_STATE_MAGIC;
 		init_waitqueue_head(&dmabuf->wait);
-		init_MUTEX(&state->open_sem);
+		mutex_init(&state->open_mutex);
 		file->private_data = card;
 
-		down(&state->open_sem);
+		mutex_lock(&state->open_mutex);
 
 		/* set default sample format. According to OSS Programmer's Guide  /dev/dsp
 		   should be default to unsigned 8-bits, mono, with sample rate 8kHz and
@@ -3331,7 +3332,7 @@
 		cs_set_divisor(dmabuf);
 
 		state->open_mode |= FMODE_WRITE;
-		up(&state->open_sem);
+		mutex_unlock(&state->open_mutex);
 		if((ret = prog_dmabuf(state)))
 			return ret;
 	}
@@ -3363,14 +3364,14 @@
 			cs_clear_tail(state);
 			drain_dac(state, file->f_flags & O_NONBLOCK);
 			/* stop DMA state machine and free DMA buffers/channels */
-			down(&state->open_sem);
+			mutex_lock(&state->open_mutex);
 			stop_dac(state);
 			dealloc_dmabuf(state);
 			state->card->free_pcm_channel(state->card, dmabuf->channel->num);
 			free_page((unsigned long)state->dmabuf.pbuf);
 
-			/* we're covered by the open_sem */
-			up(&state->open_sem);
+			/* we're covered by the open_mutex */
+			mutex_unlock(&state->open_mutex);
 			state->card->states[state->virt] = NULL;
 			state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
 
@@ -3395,14 +3396,14 @@
 		{
 			CS_DBGOUT(CS_RELEASE, 2, printk("cs46xx: cs_release() FMODE_READ\n") );
 			dmabuf = &state->dmabuf;
-			down(&state->open_sem);
+			mutex_lock(&state->open_mutex);
 			stop_adc(state);
 			dealloc_dmabuf(state);
 			state->card->free_pcm_channel(state->card, dmabuf->channel->num);
 			free_page((unsigned long)state->dmabuf.pbuf);
 
-			/* we're covered by the open_sem */
-			up(&state->open_sem);
+			/* we're covered by the open_mutex */
+			mutex_unlock(&state->open_mutex);
 			state->card->states[state->virt] = NULL;
 			state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
 
@@ -5507,7 +5508,7 @@
 	}
 
         init_waitqueue_head(&card->midi.open_wait);
-        init_MUTEX(&card->midi.open_sem);
+        mutex_init(&card->midi.open_mutex);
         init_waitqueue_head(&card->midi.iwait);
         init_waitqueue_head(&card->midi.owait);
         cs461x_pokeBA0(card, BA0_MIDCR, MIDCR_MRST);   
diff -urN oldtree/sound/oss/dmasound/dmasound_awacs.c newtree/sound/oss/dmasound/dmasound_awacs.c
--- oldtree/sound/oss/dmasound/dmasound_awacs.c	2006-02-19 11:41:06.889295768 +0000
+++ newtree/sound/oss/dmasound/dmasound_awacs.c	2006-02-21 15:58:28.679786568 +0000
@@ -80,7 +80,7 @@
 #include <linux/kmod.h>
 #include <linux/interrupt.h>
 #include <linux/input.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #ifdef CONFIG_ADB_CUDA
 #include <linux/cuda.h>
 #endif
@@ -130,7 +130,7 @@
 static char awacs_name[64];
 static int awacs_revision;
 static int awacs_sleeping;
-static DECLARE_MUTEX(dmasound_sem);
+static DEFINE_MUTEX(dmasound_mutex);
 
 static int sound_device_id;		/* exists after iMac revA */
 static int hw_can_byteswap = 1 ;	/* most pmac sound h/w can */
@@ -312,11 +312,11 @@
 extern int daca_leave_sleep(void);
 
 #define TRY_LOCK()	\
-	if ((rc = down_interruptible(&dmasound_sem)) != 0)	\
+	if ((rc = mutex_lock_interruptible(&dmasound_mutex)) != 0)	\
 		return rc;
-#define LOCK()		down(&dmasound_sem);
+#define LOCK()		mutex_lock(&dmasound_mutex);
 
-#define UNLOCK()	up(&dmasound_sem);
+#define UNLOCK()	mutex_unlock(&dmasound_mutex);
 
 /* We use different versions that the ones provided in dmasound.h
  * 
diff -urN oldtree/sound/oss/emu10k1/hwaccess.h newtree/sound/oss/emu10k1/hwaccess.h
--- oldtree/sound/oss/emu10k1/hwaccess.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/oss/emu10k1/hwaccess.h	2006-02-21 15:58:28.765773496 +0000
@@ -181,7 +181,7 @@
 	struct emu10k1_mpuout	*mpuout;
 	struct emu10k1_mpuin	*mpuin;
 
-	struct semaphore	open_sem;
+	struct mutex		open_sem;
 	mode_t			open_mode;
 	wait_queue_head_t	open_wait;
 
diff -urN oldtree/sound/oss/emu10k1/main.c newtree/sound/oss/emu10k1/main.c
--- oldtree/sound/oss/emu10k1/main.c	2006-02-19 11:41:06.893295160 +0000
+++ newtree/sound/oss/emu10k1/main.c	2006-02-21 15:58:28.837762552 +0000
@@ -1320,7 +1320,7 @@
 	card->is_aps = (subsysvid == EMU_APS_SUBID);
 
 	spin_lock_init(&card->lock);
-	init_MUTEX(&card->open_sem);
+	mutex_init(&card->open_sem);
 	card->open_mode = 0;
 	init_waitqueue_head(&card->open_wait);
 
diff -urN oldtree/sound/oss/emu10k1/midi.c newtree/sound/oss/emu10k1/midi.c
--- oldtree/sound/oss/emu10k1/midi.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/oss/emu10k1/midi.c	2006-02-21 15:58:28.839762248 +0000
@@ -110,21 +110,21 @@
 #endif
 
 	/* Wait for device to become free */
-	down(&card->open_sem);
+	mutex_lock(&card->open_sem);
 	while (card->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
 		if (file->f_flags & O_NONBLOCK) {
-			up(&card->open_sem);
+			mutex_unlock(&card->open_sem);
 			return -EBUSY;
 		}
 
-		up(&card->open_sem);
+		mutex_unlock(&card->open_sem);
 		interruptible_sleep_on(&card->open_wait);
 
 		if (signal_pending(current)) {
 			return -ERESTARTSYS;
 		}
 
-		down(&card->open_sem);
+		mutex_lock(&card->open_sem);
 	}
 
 	if ((midi_dev = (struct emu10k1_mididevice *) kmalloc(sizeof(*midi_dev), GFP_KERNEL)) == NULL)
@@ -183,7 +183,7 @@
 
 	card->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
 
-	up(&card->open_sem);
+	mutex_unlock(&card->open_sem);
 
 	return nonseekable_open(inode, file);
 }
@@ -234,9 +234,9 @@
 
 	kfree(midi_dev);
 
-	down(&card->open_sem);
+	mutex_lock(&card->open_sem);
 	card->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE));
-	up(&card->open_sem);
+	mutex_unlock(&card->open_sem);
 	wake_up_interruptible(&card->open_wait);
 
 	unlock_kernel();
diff -urN oldtree/sound/oss/es1370.c newtree/sound/oss/es1370.c
--- oldtree/sound/oss/es1370.c	2006-02-19 11:41:06.896294704 +0000
+++ newtree/sound/oss/es1370.c	2006-02-21 15:58:26.538112152 +0000
@@ -157,6 +157,7 @@
 #include <linux/gameport.h>
 #include <linux/wait.h>
 #include <linux/dma-mapping.h>
+#include <linux/mutex.h>
 
 #include <asm/io.h>
 #include <asm/page.h>
@@ -346,7 +347,7 @@
 	unsigned sctrl;
 
 	spinlock_t lock;
-	struct semaphore open_sem;
+	struct mutex open_mutex;
 	mode_t open_mode;
 	wait_queue_head_t open_wait;
 
@@ -393,7 +394,7 @@
 	struct gameport *gameport;
 #endif
 
-	struct semaphore sem;
+	struct mutex mutex;
 };
 
 /* --------------------------------------------------------------------- */
@@ -1159,7 +1160,7 @@
 		return -ENXIO;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
-	down(&s->sem);	
+	mutex_lock(&s->mutex);
 	if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
 		goto out;
         
@@ -1183,14 +1184,14 @@
 					ret = -EAGAIN;
 				goto out;
 			}
-			up(&s->sem);
+			mutex_unlock(&s->mutex);
 			schedule();
 			if (signal_pending(current)) {
 				if (!ret)
 					ret = -ERESTARTSYS;
 				goto out;
 			}
-			down(&s->sem);
+			mutex_lock(&s->mutex);
 			if (s->dma_adc.mapped)
 			{
 				ret = -ENXIO;
@@ -1215,7 +1216,7 @@
 			start_adc(s);
 	}
 out:
-	up(&s->sem);
+	mutex_unlock(&s->mutex);
         remove_wait_queue(&s->dma_adc.wait, &wait);
 	set_current_state(TASK_RUNNING);
 	return ret;
@@ -1235,7 +1236,7 @@
 		return -ENXIO;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
-	down(&s->sem);	
+	mutex_lock(&s->mutex);
 	if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
 		goto out;
 	ret = 0;
@@ -1263,14 +1264,14 @@
 					ret = -EAGAIN;
 				goto out;
 			}
-			up(&s->sem);
+			mutex_unlock(&s->mutex);
 			schedule();
 			if (signal_pending(current)) {
 				if (!ret)
 					ret = -ERESTARTSYS;
 				goto out;	
 			}
-			down(&s->sem);
+			mutex_lock(&s->mutex);
 			if (s->dma_dac2.mapped)
 			{
 			ret = -ENXIO;
@@ -1296,7 +1297,7 @@
 			start_dac2(s);
 	}
 out:
-	up(&s->sem);
+	mutex_unlock(&s->mutex);
         remove_wait_queue(&s->dma_dac2.wait, &wait);
 	set_current_state(TASK_RUNNING);
 	return ret;
@@ -1348,7 +1349,7 @@
 
 	VALIDATE_STATE(s);
 	lock_kernel();
-	down(&s->sem);
+	mutex_lock(&s->mutex);
 	if (vma->vm_flags & VM_WRITE) {
 		if ((ret = prog_dmabuf_dac2(s)) != 0) {
 			goto out;
@@ -1380,7 +1381,7 @@
 	}
 	db->mapped = 1;
 out:
-	up(&s->sem);
+	mutex_unlock(&s->mutex);
 	unlock_kernel();
 	return ret;
 }
@@ -1752,21 +1753,21 @@
        	VALIDATE_STATE(s);
 	file->private_data = s;
 	/* wait for device to become free */
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	while (s->open_mode & file->f_mode) {
 		if (file->f_flags & O_NONBLOCK) {
-			up(&s->open_sem);
+			mutex_unlock(&s->open_mutex);
 			return -EBUSY;
 		}
 		add_wait_queue(&s->open_wait, &wait);
 		__set_current_state(TASK_INTERRUPTIBLE);
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		schedule();
 		remove_wait_queue(&s->open_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&s->open_sem);
+		mutex_lock(&s->open_mutex);
 	}
 	spin_lock_irqsave(&s->lock, flags);
 	if (!(s->open_mode & (FMODE_READ|FMODE_WRITE)))
@@ -1793,8 +1794,8 @@
 	outl(s->ctrl, s->io+ES1370_REG_CONTROL);
 	spin_unlock_irqrestore(&s->lock, flags);
 	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	up(&s->open_sem);
-	init_MUTEX(&s->sem);
+	mutex_unlock(&s->open_mutex);
+	mutex_init(&s->mutex);
 	return nonseekable_open(inode, file);
 }
 
@@ -1806,7 +1807,7 @@
 	lock_kernel();
 	if (file->f_mode & FMODE_WRITE)
 		drain_dac2(s, file->f_flags & O_NONBLOCK);
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	if (file->f_mode & FMODE_WRITE) {
 		stop_dac2(s);
 		synchronize_irq(s->irq);
@@ -1818,7 +1819,7 @@
 	}
 	s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE));
 	wake_up(&s->open_wait);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	unlock_kernel();
 	return 0;
 }
@@ -2198,21 +2199,21 @@
 		return -EINVAL;
        	file->private_data = s;
 	/* wait for device to become free */
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	while (s->open_mode & FMODE_DAC) {
 		if (file->f_flags & O_NONBLOCK) {
-			up(&s->open_sem);
+			mutex_unlock(&s->open_mutex);
 			return -EBUSY;
 		}
 		add_wait_queue(&s->open_wait, &wait);
 		__set_current_state(TASK_INTERRUPTIBLE);
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		schedule();
 		remove_wait_queue(&s->open_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&s->open_sem);
+		mutex_lock(&s->open_mutex);
 	}
 	s->dma_dac1.ossfragshift = s->dma_dac1.ossmaxfrags = s->dma_dac1.subdivision = 0;
 	s->dma_dac1.enabled = 1;
@@ -2227,7 +2228,7 @@
 	outl(s->ctrl, s->io+ES1370_REG_CONTROL);
 	spin_unlock_irqrestore(&s->lock, flags);
 	s->open_mode |= FMODE_DAC;
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	return nonseekable_open(inode, file);
 }
 
@@ -2238,12 +2239,12 @@
 	VALIDATE_STATE(s);
 	lock_kernel();
 	drain_dac1(s, file->f_flags & O_NONBLOCK);
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	stop_dac1(s);
 	dealloc_dmabuf(s, &s->dma_dac1);
 	s->open_mode &= ~FMODE_DAC;
 	wake_up(&s->open_wait);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	unlock_kernel();
 	return 0;
 }
@@ -2430,21 +2431,21 @@
        	VALIDATE_STATE(s);
 	file->private_data = s;
 	/* wait for device to become free */
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
 		if (file->f_flags & O_NONBLOCK) {
-			up(&s->open_sem);
+			mutex_unlock(&s->open_mutex);
 			return -EBUSY;
 		}
 		add_wait_queue(&s->open_wait, &wait);
 		__set_current_state(TASK_INTERRUPTIBLE);
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		schedule();
 		remove_wait_queue(&s->open_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&s->open_sem);
+		mutex_lock(&s->open_mutex);
 	}
 	spin_lock_irqsave(&s->lock, flags);
 	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
@@ -2465,7 +2466,7 @@
 	es1370_handle_midi(s);
 	spin_unlock_irqrestore(&s->lock, flags);
 	s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	return nonseekable_open(inode, file);
 }
 
@@ -2499,7 +2500,7 @@
 		remove_wait_queue(&s->midi.owait, &wait);
 		set_current_state(TASK_RUNNING);
 	}
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
 	spin_lock_irqsave(&s->lock, flags);
 	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
@@ -2508,7 +2509,7 @@
 	}
 	spin_unlock_irqrestore(&s->lock, flags);
 	wake_up(&s->open_wait);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	unlock_kernel();
 	return 0;
 }
@@ -2638,7 +2639,7 @@
 	init_waitqueue_head(&s->open_wait);
 	init_waitqueue_head(&s->midi.iwait);
 	init_waitqueue_head(&s->midi.owait);
-	init_MUTEX(&s->open_sem);
+	mutex_init(&s->open_mutex);
 	spin_lock_init(&s->lock);
 	s->magic = ES1370_MAGIC;
 	s->dev = pcidev;
diff -urN oldtree/sound/oss/es1371.c newtree/sound/oss/es1371.c
--- oldtree/sound/oss/es1371.c	2006-02-19 11:41:06.898294400 +0000
+++ newtree/sound/oss/es1371.c	2006-02-21 15:58:26.565108048 +0000
@@ -129,6 +129,7 @@
 #include <linux/gameport.h>
 #include <linux/wait.h>
 #include <linux/dma-mapping.h>
+#include <linux/mutex.h>
 
 #include <asm/io.h>
 #include <asm/page.h>
@@ -419,7 +420,7 @@
 	unsigned dac1rate, dac2rate, adcrate;
 
 	spinlock_t lock;
-	struct semaphore open_sem;
+	struct mutex open_mutex;
 	mode_t open_mode;
 	wait_queue_head_t open_wait;
 
@@ -462,7 +463,7 @@
 	struct gameport *gameport;
 #endif
 
-	struct semaphore sem;
+	struct mutex sem;
 };
 
 /* --------------------------------------------------------------------- */
@@ -1346,7 +1347,7 @@
 		return -ENXIO;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
-	down(&s->sem);
+	mutex_lock(&s->sem);
 	if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
 		goto out2;
 	
@@ -1370,14 +1371,14 @@
 					ret = -EAGAIN;
 				goto out;
 			}
-			up(&s->sem);
+			mutex_unlock(&s->sem);
 			schedule();
 			if (signal_pending(current)) {
 				if (!ret)
 					ret = -ERESTARTSYS;
 				goto out2;
 			}
-			down(&s->sem);
+			mutex_lock(&s->sem);
 			if (s->dma_adc.mapped)
 			{
 				ret = -ENXIO;
@@ -1402,7 +1403,7 @@
 			start_adc(s);
 	}
 out:
-	up(&s->sem);
+	mutex_unlock(&s->sem);
 out2:
 	remove_wait_queue(&s->dma_adc.wait, &wait);
 	set_current_state(TASK_RUNNING);
@@ -1423,7 +1424,7 @@
 		return -ENXIO;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
-	down(&s->sem);	
+	mutex_lock(&s->sem);
 	if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
 		goto out3;
 	ret = 0;
@@ -1451,14 +1452,14 @@
 					ret = -EAGAIN;
 				goto out;
 			}	
-			up(&s->sem);
+			mutex_unlock(&s->sem);
 			schedule();
 			if (signal_pending(current)) {
 				if (!ret)
 					ret = -ERESTARTSYS;
 				goto out2;
 			}
-			down(&s->sem);
+			mutex_lock(&s->sem);
 			if (s->dma_dac2.mapped)
 			{
 				ret = -ENXIO;
@@ -1484,7 +1485,7 @@
 			start_dac2(s);
 	}
 out:
-	up(&s->sem);
+	mutex_unlock(&s->sem);
 out2:
 	remove_wait_queue(&s->dma_dac2.wait, &wait);
 out3:	
@@ -1538,7 +1539,7 @@
 
 	VALIDATE_STATE(s);
 	lock_kernel();
-	down(&s->sem);
+	mutex_lock(&s->sem);
 	
 	if (vma->vm_flags & VM_WRITE) {
 		if ((ret = prog_dmabuf_dac2(s)) != 0) {
@@ -1571,7 +1572,7 @@
 	}
 	db->mapped = 1;
 out:
-	up(&s->sem);
+	mutex_unlock(&s->sem);
 	unlock_kernel();
 	return ret;
 }
@@ -1938,21 +1939,21 @@
        	VALIDATE_STATE(s);
 	file->private_data = s;
 	/* wait for device to become free */
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	while (s->open_mode & file->f_mode) {
 		if (file->f_flags & O_NONBLOCK) {
-			up(&s->open_sem);
+			mutex_unlock(&s->open_mutex);
 			return -EBUSY;
 		}
 		add_wait_queue(&s->open_wait, &wait);
 		__set_current_state(TASK_INTERRUPTIBLE);
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		schedule();
 		remove_wait_queue(&s->open_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&s->open_sem);
+		mutex_lock(&s->open_mutex);
 	}
 	if (file->f_mode & FMODE_READ) {
 		s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
@@ -1982,8 +1983,8 @@
 	outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
 	spin_unlock_irqrestore(&s->lock, flags);
 	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	up(&s->open_sem);
-	init_MUTEX(&s->sem);
+	mutex_unlock(&s->open_mutex);
+	mutex_init(&s->sem);
 	return nonseekable_open(inode, file);
 }
 
@@ -1995,7 +1996,7 @@
 	lock_kernel();
 	if (file->f_mode & FMODE_WRITE)
 		drain_dac2(s, file->f_flags & O_NONBLOCK);
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	if (file->f_mode & FMODE_WRITE) {
 		stop_dac2(s);
 		dealloc_dmabuf(s, &s->dma_dac2);
@@ -2005,7 +2006,7 @@
 		dealloc_dmabuf(s, &s->dma_adc);
 	}
 	s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE));
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	wake_up(&s->open_wait);
 	unlock_kernel();
 	return 0;
@@ -2377,21 +2378,21 @@
 		return -EINVAL;
        	file->private_data = s;
 	/* wait for device to become free */
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	while (s->open_mode & FMODE_DAC) {
 		if (file->f_flags & O_NONBLOCK) {
-			up(&s->open_sem);
+			mutex_unlock(&s->open_mutex);
 			return -EBUSY;
 		}
 		add_wait_queue(&s->open_wait, &wait);
 		__set_current_state(TASK_INTERRUPTIBLE);
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		schedule();
 		remove_wait_queue(&s->open_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&s->open_sem);
+		mutex_lock(&s->open_mutex);
 	}
 	s->dma_dac1.ossfragshift = s->dma_dac1.ossmaxfrags = s->dma_dac1.subdivision = 0;
 	s->dma_dac1.enabled = 1;
@@ -2405,7 +2406,7 @@
 	outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
 	spin_unlock_irqrestore(&s->lock, flags);
 	s->open_mode |= FMODE_DAC;
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	return nonseekable_open(inode, file);
 }
 
@@ -2416,11 +2417,11 @@
 	VALIDATE_STATE(s);
 	lock_kernel();
 	drain_dac1(s, file->f_flags & O_NONBLOCK);
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	stop_dac1(s);
 	dealloc_dmabuf(s, &s->dma_dac1);
 	s->open_mode &= ~FMODE_DAC;
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	wake_up(&s->open_wait);
 	unlock_kernel();
 	return 0;
@@ -2608,21 +2609,21 @@
        	VALIDATE_STATE(s);
 	file->private_data = s;
 	/* wait for device to become free */
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
 		if (file->f_flags & O_NONBLOCK) {
-			up(&s->open_sem);
+			mutex_unlock(&s->open_mutex);
 			return -EBUSY;
 		}
 		add_wait_queue(&s->open_wait, &wait);
 		__set_current_state(TASK_INTERRUPTIBLE);
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		schedule();
 		remove_wait_queue(&s->open_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&s->open_sem);
+		mutex_lock(&s->open_mutex);
 	}
 	spin_lock_irqsave(&s->lock, flags);
 	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
@@ -2643,7 +2644,7 @@
 	es1371_handle_midi(s);
 	spin_unlock_irqrestore(&s->lock, flags);
 	s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	return nonseekable_open(inode, file);
 }
 
@@ -2676,7 +2677,7 @@
 		remove_wait_queue(&s->midi.owait, &wait);
 		set_current_state(TASK_RUNNING);
 	}
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
 	spin_lock_irqsave(&s->lock, flags);
 	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
@@ -2684,7 +2685,7 @@
 		outl(s->ctrl, s->io+ES1371_REG_CONTROL);
 	}
 	spin_unlock_irqrestore(&s->lock, flags);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	wake_up(&s->open_wait);
 	unlock_kernel();
 	return 0;
@@ -2884,7 +2885,7 @@
 	init_waitqueue_head(&s->open_wait);
 	init_waitqueue_head(&s->midi.iwait);
 	init_waitqueue_head(&s->midi.owait);
-	init_MUTEX(&s->open_sem);
+	mutex_init(&s->open_mutex);
 	spin_lock_init(&s->lock);
 	s->magic = ES1371_MAGIC;
 	s->dev = pcidev;
diff -urN oldtree/sound/oss/esssolo1.c newtree/sound/oss/esssolo1.c
--- oldtree/sound/oss/esssolo1.c	2006-02-19 11:41:06.899294248 +0000
+++ newtree/sound/oss/esssolo1.c	2006-02-21 15:58:26.595103488 +0000
@@ -105,6 +105,8 @@
 #include <linux/gameport.h>
 #include <linux/wait.h>
 #include <linux/dma-mapping.h>
+#include <linux/mutex.h>
+
 
 #include <asm/io.h>
 #include <asm/page.h>
@@ -191,7 +193,7 @@
 	unsigned ena;
 
 	spinlock_t lock;
-	struct semaphore open_sem;
+	struct mutex open_mutex;
 	mode_t open_mode;
 	wait_queue_head_t open_wait;
 
@@ -1581,7 +1583,7 @@
 	lock_kernel();
 	if (file->f_mode & FMODE_WRITE)
 		drain_dac(s, file->f_flags & O_NONBLOCK);
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	if (file->f_mode & FMODE_WRITE) {
 		stop_dac(s);
 		outb(0, s->iobase+6);  /* disable DMA */
@@ -1595,7 +1597,7 @@
 	}
 	s->open_mode &= ~(FMODE_READ | FMODE_WRITE);
 	wake_up(&s->open_wait);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	unlock_kernel();
 	return 0;
 }
@@ -1624,21 +1626,21 @@
        	VALIDATE_STATE(s);
 	file->private_data = s;
 	/* wait for device to become free */
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	while (s->open_mode & (FMODE_READ | FMODE_WRITE)) {
 		if (file->f_flags & O_NONBLOCK) {
-			up(&s->open_sem);
+			mutex_unlock(&s->open_mutex);
 			return -EBUSY;
 		}
 		add_wait_queue(&s->open_wait, &wait);
 		__set_current_state(TASK_INTERRUPTIBLE);
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		schedule();
 		remove_wait_queue(&s->open_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&s->open_sem);
+		mutex_lock(&s->open_mutex);
 	}
 	s->fmt = AFMT_U8;
 	s->channels = 1;
@@ -1650,7 +1652,7 @@
 	s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
 	s->dma_dac.enabled = 1;
 	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	prog_codec(s);
 	return nonseekable_open(inode, file);
 }
@@ -1911,21 +1913,21 @@
        	VALIDATE_STATE(s);
 	file->private_data = s;
 	/* wait for device to become free */
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
 		if (file->f_flags & O_NONBLOCK) {
-			up(&s->open_sem);
+			mutex_unlock(&s->open_mutex);
 			return -EBUSY;
 		}
 		add_wait_queue(&s->open_wait, &wait);
 		__set_current_state(TASK_INTERRUPTIBLE);
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		schedule();
 		remove_wait_queue(&s->open_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&s->open_sem);
+		mutex_lock(&s->open_mutex);
 	}
 	spin_lock_irqsave(&s->lock, flags);
 	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
@@ -1951,7 +1953,7 @@
 	}
 	spin_unlock_irqrestore(&s->lock, flags);
 	s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	return nonseekable_open(inode, file);
 }
 
@@ -1985,7 +1987,7 @@
 		remove_wait_queue(&s->midi.owait, &wait);
 		set_current_state(TASK_RUNNING);
 	}
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
 	spin_lock_irqsave(&s->lock, flags);
 	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
@@ -1994,7 +1996,7 @@
 	}
 	spin_unlock_irqrestore(&s->lock, flags);
 	wake_up(&s->open_wait);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	unlock_kernel();
 	return 0;
 }
@@ -2132,24 +2134,24 @@
        	VALIDATE_STATE(s);
 	file->private_data = s;
 	/* wait for device to become free */
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	while (s->open_mode & FMODE_DMFM) {
 		if (file->f_flags & O_NONBLOCK) {
-			up(&s->open_sem);
+			mutex_unlock(&s->open_mutex);
 			return -EBUSY;
 		}
 		add_wait_queue(&s->open_wait, &wait);
 		__set_current_state(TASK_INTERRUPTIBLE);
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		schedule();
 		remove_wait_queue(&s->open_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&s->open_sem);
+		mutex_lock(&s->open_mutex);
 	}
 	if (!request_region(s->sbbase, FMSYNTH_EXTENT, "ESS Solo1")) {
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		printk(KERN_ERR "solo1: FM synth io ports in use, opl3 loaded?\n");
 		return -EBUSY;
 	}
@@ -2161,7 +2163,7 @@
 	outb(5, s->sbbase+2);
 	outb(1, s->sbbase+3);  /* enable OPL3 */
 	s->open_mode |= FMODE_DMFM;
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	return nonseekable_open(inode, file);
 }
 
@@ -2172,7 +2174,7 @@
 
 	VALIDATE_STATE(s);
 	lock_kernel();
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	s->open_mode &= ~FMODE_DMFM;
 	for (regb = 0xb0; regb < 0xb9; regb++) {
 		outb(regb, s->sbbase);
@@ -2182,7 +2184,7 @@
 	}
 	release_region(s->sbbase, FMSYNTH_EXTENT);
 	wake_up(&s->open_wait);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	unlock_kernel();
 	return 0;
 }
@@ -2362,7 +2364,7 @@
 	init_waitqueue_head(&s->open_wait);
 	init_waitqueue_head(&s->midi.iwait);
 	init_waitqueue_head(&s->midi.owait);
-	init_MUTEX(&s->open_sem);
+	mutex_init(&s->open_mutex);
 	spin_lock_init(&s->lock);
 	s->magic = SOLO1_MAGIC;
 	s->dev = pcidev;
diff -urN oldtree/sound/oss/forte.c newtree/sound/oss/forte.c
--- oldtree/sound/oss/forte.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/oss/forte.c	2006-02-21 15:58:26.597103184 +0000
@@ -43,6 +43,7 @@
 #include <linux/interrupt.h>
 
 #include <linux/proc_fs.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -185,7 +186,7 @@
 	unsigned long		iobase;
 	int			irq;
 
-	struct semaphore	open_sem; 	/* Device access */
+	struct mutex		open_mutex; 	/* Device access */
 	spinlock_t		lock;		/* State */
 
 	spinlock_t		ac97_lock;
@@ -1242,13 +1243,13 @@
 	struct forte_chip *chip = forte; /* FIXME: HACK FROM HELL! */
 
 	if (file->f_flags & O_NONBLOCK) {
-		if (down_trylock (&chip->open_sem)) {
+		if (!mutex_trylock(&chip->open_mutex)) {
 			DPRINTK ("%s: returning -EAGAIN\n", __FUNCTION__);
 			return -EAGAIN;
 		}
 	}
 	else {
-		if (down_interruptible (&chip->open_sem)) {
+		if (mutex_lock_interruptible(&chip->open_mutex)) {
 			DPRINTK ("%s: returning -ERESTARTSYS\n", __FUNCTION__);
 			return -ERESTARTSYS;
 		}
@@ -1302,7 +1303,7 @@
 		spin_unlock_irq (&chip->lock);
 	}
 
-	up (&chip->open_sem);
+	mutex_unlock(&chip->open_mutex);
 
 	return ret;
 }
@@ -2011,7 +2012,7 @@
 	memset (chip, 0, sizeof (struct forte_chip));
 	chip->pci_dev = pci_dev;
 
-	init_MUTEX(&chip->open_sem);
+	mutex_init(&chip->open_mutex);
 	spin_lock_init (&chip->lock);
 	spin_lock_init (&chip->ac97_lock);
 
diff -urN oldtree/sound/oss/hal2.c newtree/sound/oss/hal2.c
--- oldtree/sound/oss/hal2.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/oss/hal2.c	2006-02-21 15:58:26.598103032 +0000
@@ -32,6 +32,8 @@
 #include <linux/dma-mapping.h>
 #include <linux/sound.h>
 #include <linux/soundcard.h>
+#include <linux/mutex.h>
+
 
 #include <asm/io.h>
 #include <asm/sgi/hpc3.h>
@@ -92,7 +94,7 @@
 
 	wait_queue_head_t dma_wait;
 	spinlock_t lock;
-	struct semaphore sem;
+	struct mutex sem;
 
 	int usecount;			/* recording and playback are
 					 * independent */
@@ -1178,7 +1180,7 @@
 
 	if (!count)
 		return 0;
-	if (down_interruptible(&adc->sem))
+	if (mutex_lock_interruptible(&adc->sem))
 		return -EINTR;
 	if (file->f_flags & O_NONBLOCK) {
 		err = hal2_get_buffer(hal2, buffer, count);
@@ -1217,7 +1219,7 @@
 			}
 		} while (count > 0 && err >= 0);
 	}
-	up(&adc->sem);
+	mutex_unlock(&adc->sem);
 
 	return err;
 }
@@ -1232,7 +1234,7 @@
 
 	if (!count)
 		return 0;
-	if (down_interruptible(&dac->sem))
+	if (mutex_lock_interruptible(&dac->sem))
 		return -EINTR;
 	if (file->f_flags & O_NONBLOCK) {
 		err = hal2_add_buffer(hal2, buf, count);
@@ -1271,7 +1273,7 @@
 			}
 		} while (count > 0 && err >= 0);
 	}
-	up(&dac->sem);
+	mutex_unlock(&dac->sem);
 
 	return err;
 }
@@ -1356,20 +1358,20 @@
 	if (file->f_mode & FMODE_READ) {
 		struct hal2_codec *adc = &hal2->adc;
 
-		down(&adc->sem);
+		mutex_lock(&adc->sem);
 		hal2_stop_adc(hal2);
 		hal2_free_adc_dmabuf(adc);
 		adc->usecount--;
-		up(&adc->sem);
+		mutex_unlock(&adc->sem);
 	}
 	if (file->f_mode & FMODE_WRITE) {
 		struct hal2_codec *dac = &hal2->dac;
 
-		down(&dac->sem);
+		mutex_lock(&dac->sem);
 		hal2_sync_dac(hal2);
 		hal2_free_dac_dmabuf(dac);
 		dac->usecount--;
-		up(&dac->sem);
+		mutex_unlock(&dac->sem);
 	}
 
 	return 0;
@@ -1400,7 +1402,7 @@
 	codec->pbus.pbusnr = index;
 	codec->pbus.pbus = &hpc3->pbdma[index];
 	init_waitqueue_head(&codec->dma_wait);
-	init_MUTEX(&codec->sem);
+	mutex_init(&codec->sem);
 	spin_lock_init(&codec->lock);
 }
 
diff -urN oldtree/sound/oss/i810_audio.c newtree/sound/oss/i810_audio.c
--- oldtree/sound/oss/i810_audio.c	2006-02-19 11:41:06.902293792 +0000
+++ newtree/sound/oss/i810_audio.c	2006-02-21 15:58:26.625098928 +0000
@@ -100,6 +100,8 @@
 #include <linux/smp_lock.h>
 #include <linux/ac97_codec.h>
 #include <linux/bitops.h>
+#include <linux/mutex.h>
+
 #include <asm/uaccess.h>
 
 #define DRIVER_VERSION "1.01"
@@ -331,7 +333,7 @@
 	struct i810_card *card;	/* Card info */
 
 	/* single open lock mechanism, only used for recording */
-	struct semaphore open_sem;
+	struct mutex open_mutex;
 	wait_queue_head_t open_wait;
 
 	/* file mode */
@@ -2597,7 +2599,7 @@
 	state->card = card;
 	state->magic = I810_STATE_MAGIC;
 	init_waitqueue_head(&dmabuf->wait);
-	init_MUTEX(&state->open_sem);
+	mutex_init(&state->open_mutex);
 	file->private_data = state;
 	dmabuf->trigger = 0;
 
@@ -3213,7 +3215,7 @@
 		state->card = card;
 		state->magic = I810_STATE_MAGIC;
 		init_waitqueue_head(&dmabuf->wait);
-		init_MUTEX(&state->open_sem);
+		mutex_init(&state->open_mutex);
 		dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT;
 		dmabuf->trigger = PCM_ENABLE_OUTPUT;
 		i810_set_spdif_output(state, -1, 0);
diff -urN oldtree/sound/oss/ite8172.c newtree/sound/oss/ite8172.c
--- oldtree/sound/oss/ite8172.c	2006-02-19 11:41:06.903293640 +0000
+++ newtree/sound/oss/ite8172.c	2006-02-21 15:58:26.627098624 +0000
@@ -71,6 +71,8 @@
 #include <linux/smp_lock.h>
 #include <linux/ac97_codec.h>
 #include <linux/interrupt.h>
+#include <linux/mutex.h>
+
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/uaccess.h>
@@ -304,7 +306,7 @@
 	unsigned dacrate, adcrate;
 
 	spinlock_t lock;
-	struct semaphore open_sem;
+	struct mutex open_mutex;
 	mode_t open_mode;
 	wait_queue_head_t open_wait;
 
@@ -1801,21 +1803,21 @@
 	}
 	file->private_data = s;
 	/* wait for device to become free */
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	while (s->open_mode & file->f_mode) {
 		if (file->f_flags & O_NONBLOCK) {
-			up(&s->open_sem);
+			mutex_unlock(&s->open_mutex);
 			return -EBUSY;
 		}
 		add_wait_queue(&s->open_wait, &wait);
 		__set_current_state(TASK_INTERRUPTIBLE);
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		schedule();
 		remove_wait_queue(&s->open_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&s->open_sem);
+		mutex_lock(&s->open_mutex);
 	}
 
 	spin_lock_irqsave(&s->lock, flags);
@@ -1850,7 +1852,7 @@
 	spin_unlock_irqrestore(&s->lock, flags);
 
 	s->open_mode |= (file->f_mode & (FMODE_READ | FMODE_WRITE));
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	return nonseekable_open(inode, file);
 }
 
@@ -1864,7 +1866,7 @@
 	lock_kernel();
 	if (file->f_mode & FMODE_WRITE)
 		drain_dac(s, file->f_flags & O_NONBLOCK);
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	if (file->f_mode & FMODE_WRITE) {
 		stop_dac(s);
 		dealloc_dmabuf(s, &s->dma_dac);
@@ -1874,7 +1876,7 @@
 		dealloc_dmabuf(s, &s->dma_adc);
 	}
 	s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	wake_up(&s->open_wait);
 	unlock_kernel();
 	return 0;
@@ -1997,7 +1999,7 @@
 	init_waitqueue_head(&s->dma_adc.wait);
 	init_waitqueue_head(&s->dma_dac.wait);
 	init_waitqueue_head(&s->open_wait);
-	init_MUTEX(&s->open_sem);
+	mutex_init(&s->open_mutex);
 	spin_lock_init(&s->lock);
 	s->dev = pcidev;
 	s->io = pci_resource_start(pcidev, 0);
diff -urN oldtree/sound/oss/maestro.c newtree/sound/oss/maestro.c
--- oldtree/sound/oss/maestro.c	2006-02-19 11:41:06.905293336 +0000
+++ newtree/sound/oss/maestro.c	2006-02-21 15:58:26.656094216 +0000
@@ -223,6 +223,8 @@
 #include <linux/reboot.h>
 #include <linux/bitops.h>
 #include <linux/wait.h>
+#include <linux/mutex.h>
+
 
 #include <asm/current.h>
 #include <asm/dma.h>
@@ -397,7 +399,7 @@
 	/* this locks around the oss state in the driver */
 	spinlock_t lock;
 	/* only let 1 be opening at a time */
-	struct semaphore open_sem;
+	struct mutex open_mutex;
 	wait_queue_head_t open_wait;
 	mode_t open_mode;
 
@@ -3020,26 +3022,26 @@
        	VALIDATE_STATE(s);
 	file->private_data = s;
 	/* wait for device to become free */
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	while (s->open_mode & file->f_mode) {
 		if (file->f_flags & O_NONBLOCK) {
-			up(&s->open_sem);
+			mutex_unlock(&s->open_mutex);
 			return -EWOULDBLOCK;
 		}
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		interruptible_sleep_on(&s->open_wait);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&s->open_sem);
+		mutex_lock(&s->open_mutex);
 	}
 
 	/* under semaphore.. */
 	if ((s->card->dmapages==NULL) && allocate_buffers(s)) {
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		return -ENOMEM;
 	}
 
-	/* we're covered by the open_sem */
+	/* we're covered by the open_mutex */
 	if( ! s->card->dsps_open )  {
 		maestro_power(s->card,ACPI_D0);
 		start_bob(s);
@@ -3076,7 +3078,7 @@
 	set_fmt(s, fmtm, fmts);
 	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
 
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	return nonseekable_open(inode, file);
 }
 
@@ -3089,7 +3091,7 @@
 	lock_kernel();
 	if (file->f_mode & FMODE_WRITE)
 		drain_dac(s, file->f_flags & O_NONBLOCK);
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	if (file->f_mode & FMODE_WRITE) {
 		stop_dac(s);
 	}
@@ -3098,7 +3100,7 @@
 	}
 		
 	s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
-	/* we're covered by the open_sem */
+	/* we're covered by the open_mutex */
 	M_printk("maestro: %d dsps now alive\n",s->card->dsps_open-1);
 	if( --s->card->dsps_open <= 0) {
 		s->card->dsps_open = 0;
@@ -3106,7 +3108,7 @@
 		free_buffers(s);
 		maestro_power(s->card,ACPI_D2);
 	}
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	wake_up(&s->open_wait);
 	unlock_kernel();
 	return 0;
@@ -3466,7 +3468,7 @@
 		init_waitqueue_head(&s->dma_dac.wait);
 		init_waitqueue_head(&s->open_wait);
 		spin_lock_init(&s->lock);
-		init_MUTEX(&s->open_sem);
+		mutex_init(&s->open_mutex);
 		s->magic = ESS_STATE_MAGIC;
 		
 		s->apu[0] = 6*i;
diff -urN oldtree/sound/oss/maestro3.c newtree/sound/oss/maestro3.c
--- oldtree/sound/oss/maestro3.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/oss/maestro3.c	2006-02-21 15:58:26.629098320 +0000
@@ -144,6 +144,8 @@
 #include <linux/spinlock.h>
 #include <linux/ac97_codec.h>
 #include <linux/wait.h>
+#include <linux/mutex.h>
+
 
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -205,7 +207,7 @@
 		when irqhandler uses s->lock
 		and m3_assp_read uses card->lock ?
 		*/
-    struct semaphore open_sem;
+    struct mutex open_mutex;
     wait_queue_head_t open_wait;
     mode_t open_mode;
 
@@ -2013,17 +2015,17 @@
     file->private_data = s;
 
     /* wait for device to become free */
-    down(&s->open_sem);
+    mutex_lock(&s->open_mutex);
     while (s->open_mode & file->f_mode) {
         if (file->f_flags & O_NONBLOCK) {
-            up(&s->open_sem);
+            mutex_unlock(&s->open_mutex);
             return -EWOULDBLOCK;
         }
-        up(&s->open_sem);
+        mutex_unlock(&s->open_mutex);
         interruptible_sleep_on(&s->open_wait);
         if (signal_pending(current))
             return -ERESTARTSYS;
-        down(&s->open_sem);
+        mutex_lock(&s->open_mutex);
     }
     
     spin_lock_irqsave(&c->lock, flags);
@@ -2047,7 +2049,7 @@
     set_fmt(s, fmtm, fmts);
     s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
 
-    up(&s->open_sem);
+    mutex_unlock(&s->open_mutex);
     spin_unlock_irqrestore(&c->lock, flags);
     return nonseekable_open(inode, file);
 }
@@ -2062,7 +2064,7 @@
     if (file->f_mode & FMODE_WRITE)
         drain_dac(s, file->f_flags & O_NONBLOCK);
 
-    down(&s->open_sem);
+    mutex_lock(&s->open_mutex);
     spin_lock_irqsave(&card->lock, flags);
 
     if (file->f_mode & FMODE_WRITE) {
@@ -2083,7 +2085,7 @@
     s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
 
     spin_unlock_irqrestore(&card->lock, flags);
-    up(&s->open_sem);
+    mutex_unlock(&s->open_mutex);
     wake_up(&s->open_wait);
 
     return 0;
@@ -2679,7 +2681,7 @@
         init_waitqueue_head(&s->dma_adc.wait);
         init_waitqueue_head(&s->dma_dac.wait);
         init_waitqueue_head(&s->open_wait);
-        init_MUTEX(&(s->open_sem));
+        mutex_init(&(s->open_mutex));
         s->magic = M3_STATE_MAGIC;
 
         m3_assp_client_init(s);
diff -urN oldtree/sound/oss/nec_vrc5477.c newtree/sound/oss/nec_vrc5477.c
--- oldtree/sound/oss/nec_vrc5477.c	2006-02-19 11:41:06.907293032 +0000
+++ newtree/sound/oss/nec_vrc5477.c	2006-02-21 15:58:26.658093912 +0000
@@ -78,6 +78,8 @@
 #include <linux/spinlock.h>
 #include <linux/smp_lock.h>
 #include <linux/ac97_codec.h>
+#include <linux/mutex.h>
+
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/uaccess.h>
@@ -198,7 +200,7 @@
 	unsigned short extended_status;
 
 	spinlock_t lock;
-	struct semaphore open_sem;
+	struct mutex open_mutex;
 	mode_t open_mode;
 	wait_queue_head_t open_wait;
 
@@ -1617,22 +1619,22 @@
 	file->private_data = s;
 
 	/* wait for device to become free */
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	while (s->open_mode & file->f_mode) {
 
 		if (file->f_flags & O_NONBLOCK) {
-			up(&s->open_sem);
+			mutex_unlock(&s->open_mutex);
 			return -EBUSY;
 		}
 		add_wait_queue(&s->open_wait, &wait);
 		__set_current_state(TASK_INTERRUPTIBLE);
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		schedule();
 		remove_wait_queue(&s->open_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&s->open_sem);
+		mutex_lock(&s->open_mutex);
 	}
 
 	spin_lock_irqsave(&s->lock, flags);
@@ -1659,7 +1661,7 @@
  bailout:
 	spin_unlock_irqrestore(&s->lock, flags);
 
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	return ret;
 }
 
@@ -1671,7 +1673,7 @@
 	lock_kernel();
 	if (file->f_mode & FMODE_WRITE)
 		drain_dac(s, file->f_flags & O_NONBLOCK);
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	if (file->f_mode & FMODE_WRITE) {
 		stop_dac(s);
 		dealloc_dmabuf(s, &s->dma_dac);
@@ -1681,7 +1683,7 @@
 		dealloc_dmabuf(s, &s->dma_adc);
 	}
 	s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	wake_up(&s->open_wait);
 	unlock_kernel();
 	return 0;
@@ -1867,7 +1869,7 @@
 	init_waitqueue_head(&s->dma_adc.wait);
 	init_waitqueue_head(&s->dma_dac.wait);
 	init_waitqueue_head(&s->open_wait);
-	init_MUTEX(&s->open_sem);
+	mutex_init(&s->open_mutex);
 	spin_lock_init(&s->lock);
 
 	s->dev = pcidev;
diff -urN oldtree/sound/oss/rme96xx.c newtree/sound/oss/rme96xx.c
--- oldtree/sound/oss/rme96xx.c	2006-02-19 11:41:06.910292576 +0000
+++ newtree/sound/oss/rme96xx.c	2006-02-21 15:58:26.659093760 +0000
@@ -58,6 +58,7 @@
 #include <linux/interrupt.h>
 #include <linux/poll.h>
 #include <linux/wait.h>
+#include <linux/mutex.h>
 
 #include <asm/dma.h>
 #include <asm/page.h>
@@ -326,7 +327,7 @@
 
 		/* waiting and locking */
 		wait_queue_head_t wait;
-		struct semaphore  open_sem;
+		struct mutex  open_mutex;
 		wait_queue_head_t open_wait;
 
 	} dma[RME96xx_MAX_DEVS]; 
@@ -842,7 +843,7 @@
 
 static int rme96xx_dmabuf_init(rme96xx_info * s,struct dmabuf* dma,int ioffset,int ooffset) {
 
-	init_MUTEX(&dma->open_sem);
+	mutex_init(&dma->open_mutex);
 	init_waitqueue_head(&dma->open_wait);
 	init_waitqueue_head(&dma->wait);
 	dma->s = s; 
@@ -1469,21 +1470,21 @@
 	dma = &s->dma[devnum];
 	f->private_data = dma;
 	/* wait for device to become free */
-	down(&dma->open_sem);
+	mutex_lock(&dma->open_mutex);
 	while (dma->open_mode & f->f_mode) {
 		if (f->f_flags & O_NONBLOCK) {
-			up(&dma->open_sem);
+			mutex_unlock(&dma->open_mutex);
 			return -EBUSY;
 		}
 		add_wait_queue(&dma->open_wait, &wait);
 		__set_current_state(TASK_INTERRUPTIBLE);
-		up(&dma->open_sem);
+		mutex_unlock(&dma->open_mutex);
 		schedule();
 		remove_wait_queue(&dma->open_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&dma->open_sem);
+		mutex_lock(&dma->open_mutex);
 	}
 
 	COMM                ("hardware open")
@@ -1492,7 +1493,7 @@
 
 	dma->open_mode |= (f->f_mode & (FMODE_READ | FMODE_WRITE));
 	dma->opened = 1;
-	up(&dma->open_sem);
+	mutex_unlock(&dma->open_mutex);
 
 	DBG(printk("device num %d open finished\n",devnum));
 	return 0;
@@ -1524,7 +1525,7 @@
 	}
 
 	wake_up(&dma->open_wait);
-	up(&dma->open_sem);
+	mutex_unlock(&dma->open_mutex);
 
 	return 0;
 }
diff -urN oldtree/sound/oss/sonicvibes.c newtree/sound/oss/sonicvibes.c
--- oldtree/sound/oss/sonicvibes.c	2006-02-19 11:41:06.911292424 +0000
+++ newtree/sound/oss/sonicvibes.c	2006-02-21 15:58:26.686089656 +0000
@@ -116,6 +116,8 @@
 #include <linux/spinlock.h>
 #include <linux/smp_lock.h>
 #include <linux/gameport.h>
+#include <linux/mutex.h>
+
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -328,7 +330,7 @@
 	unsigned char fmt, enable;
 
 	spinlock_t lock;
-	struct semaphore open_sem;
+	struct mutex open_mutex;
 	mode_t open_mode;
 	wait_queue_head_t open_wait;
 
@@ -1922,21 +1924,21 @@
        	VALIDATE_STATE(s);
 	file->private_data = s;
 	/* wait for device to become free */
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	while (s->open_mode & file->f_mode) {
 		if (file->f_flags & O_NONBLOCK) {
-			up(&s->open_sem);
+			mutex_unlock(&s->open_mutex);
 			return -EBUSY;
 		}
 		add_wait_queue(&s->open_wait, &wait);
 		__set_current_state(TASK_INTERRUPTIBLE);
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		schedule();
 		remove_wait_queue(&s->open_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&s->open_sem);
+		mutex_lock(&s->open_mutex);
 	}
 	if (file->f_mode & FMODE_READ) {
 		fmtm &= ~((SV_CFMT_STEREO | SV_CFMT_16BIT) << SV_CFMT_CSHIFT);
@@ -1956,7 +1958,7 @@
 	}
 	set_fmt(s, fmtm, fmts);
 	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	return nonseekable_open(inode, file);
 }
 
@@ -1968,7 +1970,7 @@
 	lock_kernel();
 	if (file->f_mode & FMODE_WRITE)
 		drain_dac(s, file->f_flags & O_NONBLOCK);
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	if (file->f_mode & FMODE_WRITE) {
 		stop_dac(s);
 		dealloc_dmabuf(s, &s->dma_dac);
@@ -1979,7 +1981,7 @@
 	}
 	s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE));
 	wake_up(&s->open_wait);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	unlock_kernel();
 	return 0;
 }
@@ -2167,21 +2169,21 @@
        	VALIDATE_STATE(s);
 	file->private_data = s;
 	/* wait for device to become free */
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
 		if (file->f_flags & O_NONBLOCK) {
-			up(&s->open_sem);
+			mutex_unlock(&s->open_mutex);
 			return -EBUSY;
 		}
 		add_wait_queue(&s->open_wait, &wait);
 		__set_current_state(TASK_INTERRUPTIBLE);
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		schedule();
 		remove_wait_queue(&s->open_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&s->open_sem);
+		mutex_lock(&s->open_mutex);
 	}
 	spin_lock_irqsave(&s->lock, flags);
 	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
@@ -2210,7 +2212,7 @@
 	}
 	spin_unlock_irqrestore(&s->lock, flags);
 	s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	return nonseekable_open(inode, file);
 }
 
@@ -2248,7 +2250,7 @@
 		remove_wait_queue(&s->midi.owait, &wait);
 		set_current_state(TASK_RUNNING);
 	}
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
 	spin_lock_irqsave(&s->lock, flags);
 	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
@@ -2257,7 +2259,7 @@
 	}
 	spin_unlock_irqrestore(&s->lock, flags);
 	wake_up(&s->open_wait);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	unlock_kernel();
 	return 0;
 }
@@ -2388,21 +2390,21 @@
        	VALIDATE_STATE(s);
 	file->private_data = s;
 	/* wait for device to become free */
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	while (s->open_mode & FMODE_DMFM) {
 		if (file->f_flags & O_NONBLOCK) {
-			up(&s->open_sem);
+			mutex_unlock(&s->open_mutex);
 			return -EBUSY;
 		}
 		add_wait_queue(&s->open_wait, &wait);
 		__set_current_state(TASK_INTERRUPTIBLE);
-		up(&s->open_sem);
+		mutex_unlock(&s->open_mutex);
 		schedule();
 		remove_wait_queue(&s->open_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
-		down(&s->open_sem);
+		mutex_lock(&s->open_mutex);
 	}
 	/* init the stuff */
 	outb(1, s->iosynth);
@@ -2412,7 +2414,7 @@
 	outb(5, s->iosynth+2);
 	outb(1, s->iosynth+3);  /* enable OPL3 */
 	s->open_mode |= FMODE_DMFM;
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	return nonseekable_open(inode, file);
 }
 
@@ -2423,7 +2425,7 @@
 
 	VALIDATE_STATE(s);
 	lock_kernel();
-	down(&s->open_sem);
+	mutex_lock(&s->open_mutex);
 	s->open_mode &= ~FMODE_DMFM;
 	for (regb = 0xb0; regb < 0xb9; regb++) {
 		outb(regb, s->iosynth);
@@ -2432,7 +2434,7 @@
 		outb(0, s->iosynth+3);
 	}
 	wake_up(&s->open_wait);
-	up(&s->open_sem);
+	mutex_unlock(&s->open_mutex);
 	unlock_kernel();
 	return 0;
 }
@@ -2582,7 +2584,7 @@
 	init_waitqueue_head(&s->open_wait);
 	init_waitqueue_head(&s->midi.iwait);
 	init_waitqueue_head(&s->midi.owait);
-	init_MUTEX(&s->open_sem);
+	mutex_init(&s->open_mutex);
 	spin_lock_init(&s->lock);
 	s->magic = SV_MAGIC;
 	s->dev = pcidev;
diff -urN oldtree/sound/oss/swarm_cs4297a.c newtree/sound/oss/swarm_cs4297a.c
--- oldtree/sound/oss/swarm_cs4297a.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/oss/swarm_cs4297a.c	2006-02-21 15:58:26.689089200 +0000
@@ -76,6 +76,7 @@
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #include <asm/byteorder.h>
 #include <asm/dma.h>
@@ -291,9 +292,9 @@
 	unsigned conversion:1;	// conversion from 16 to 8 bit in progress
 	unsigned ena;
 	spinlock_t lock;
-	struct semaphore open_sem;
-	struct semaphore open_sem_adc;
-	struct semaphore open_sem_dac;
+	struct mutex open_mutex;
+	struct mutex open_sem_adc;
+	struct mutex open_sem_dac;
 	mode_t open_mode;
 	wait_queue_head_t open_wait;
 	wait_queue_head_t open_wait_adc;
@@ -2352,20 +2353,20 @@
 
 	if (file->f_mode & FMODE_WRITE) {
 		drain_dac(s, file->f_flags & O_NONBLOCK);
-		down(&s->open_sem_dac);
+		mutex_lock(&s->open_sem_dac);
 		stop_dac(s);
 		dealloc_dmabuf(s, &s->dma_dac);
 		s->open_mode &= ~FMODE_WRITE;
-		up(&s->open_sem_dac);
+		mutex_unlock(&s->open_sem_dac);
 		wake_up(&s->open_wait_dac);
 	}
 	if (file->f_mode & FMODE_READ) {
 		drain_adc(s, file->f_flags & O_NONBLOCK);
-		down(&s->open_sem_adc);
+		mutex_lock(&s->open_sem_adc);
 		stop_adc(s);
 		dealloc_dmabuf(s, &s->dma_adc);
 		s->open_mode &= ~FMODE_READ;
-		up(&s->open_sem_adc);
+		mutex_unlock(&s->open_sem_adc);
 		wake_up(&s->open_wait_adc);
 	}
 	return 0;
@@ -2413,37 +2414,37 @@
                                 ;
                 }
           
-		down(&s->open_sem_dac);
+		mutex_lock(&s->open_sem_dac);
 		while (s->open_mode & FMODE_WRITE) {
 			if (file->f_flags & O_NONBLOCK) {
-				up(&s->open_sem_dac);
+				mutex_unlock(&s->open_sem_dac);
 				return -EBUSY;
 			}
-			up(&s->open_sem_dac);
+			mutex_unlock(&s->open_sem_dac);
 			interruptible_sleep_on(&s->open_wait_dac);
 
 			if (signal_pending(current)) {
                                 printk("open - sig pending\n");
 				return -ERESTARTSYS;
                         }
-			down(&s->open_sem_dac);
+			mutex_lock(&s->open_sem_dac);
 		}
 	}
 	if (file->f_mode & FMODE_READ) {
-		down(&s->open_sem_adc);
+		mutex_lock(&s->open_sem_adc);
 		while (s->open_mode & FMODE_READ) {
 			if (file->f_flags & O_NONBLOCK) {
-				up(&s->open_sem_adc);
+				mutex_unlock(&s->open_sem_adc);
 				return -EBUSY;
 			}
-			up(&s->open_sem_adc);
+			mutex_unlock(&s->open_sem_adc);
 			interruptible_sleep_on(&s->open_wait_adc);
 
 			if (signal_pending(current)) {
                                 printk("open - sig pending\n");
 				return -ERESTARTSYS;
                         }
-			down(&s->open_sem_adc);
+			mutex_lock(&s->open_sem_adc);
 		}
 	}
 	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
@@ -2456,7 +2457,7 @@
 		s->ena &= ~FMODE_READ;
 		s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags =
 		    s->dma_adc.subdivision = 0;
-		up(&s->open_sem_adc);
+		mutex_unlock(&s->open_sem_adc);
 
 		if (prog_dmabuf_adc(s)) {
 			CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR
@@ -2474,7 +2475,7 @@
 		s->ena &= ~FMODE_WRITE;
 		s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags =
 		    s->dma_dac.subdivision = 0;
-		up(&s->open_sem_dac);
+		mutex_unlock(&s->open_sem_dac);
 
 		if (prog_dmabuf_dac(s)) {
 			CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR
@@ -2631,8 +2632,8 @@
 	init_waitqueue_head(&s->open_wait);
 	init_waitqueue_head(&s->open_wait_adc);
 	init_waitqueue_head(&s->open_wait_dac);
-	init_MUTEX(&s->open_sem_adc);
-	init_MUTEX(&s->open_sem_dac);
+	mutex_init(&s->open_sem_adc);
+	mutex_init(&s->open_sem_dac);
 	spin_lock_init(&s->lock);
 
         s->irq = K_INT_SER_1;
diff -urN oldtree/sound/oss/trident.c newtree/sound/oss/trident.c
--- oldtree/sound/oss/trident.c	2006-02-19 11:41:06.913292120 +0000
+++ newtree/sound/oss/trident.c	2006-02-21 15:58:26.726083576 +0000
@@ -190,7 +190,7 @@
  *
  *	Lock order (high->low)
  *		lock	-	hardware lock
- *		open_sem - 	guard opens
+ *		open_mutex - 	guard opens
  *		sem	-	guard dmabuf, write re-entry etc
  */
 
@@ -216,6 +216,8 @@
 #include <linux/pm.h>
 #include <linux/gameport.h>
 #include <linux/kernel.h>
+#include <linux/mutex.h>
+
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -349,7 +351,7 @@
 	unsigned chans_num;
 	unsigned long fmt_flag;
 	/* Guard against mmap/write/read races */
-	struct semaphore sem;
+	struct mutex sem;
 
 };
 
@@ -402,7 +404,7 @@
 	struct trident_card *next;
 
 	/* single open lock mechanism, only used for recording */
-	struct semaphore open_sem;
+	struct mutex open_mutex;
 
 	/* The trident has a certain amount of cross channel interaction
 	   so we use a single per card lock */
@@ -1881,7 +1883,7 @@
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
 
-	down(&state->sem);
+	mutex_lock(&state->sem);
 	if (!dmabuf->ready && (ret = prog_dmabuf_record(state)))
 		goto out;
 
@@ -1913,7 +1915,7 @@
 				goto out;
 			}
 
-			up(&state->sem);
+			mutex_unlock(&state->sem);
 			/* No matter how much space left in the buffer, */ 
 			/* we have to wait until CSO == ESO/2 or CSO == ESO */ 
 			/* when address engine interrupts */
@@ -1940,7 +1942,7 @@
 					ret = -ERESTARTSYS;
 				goto out;
 			}
-			down(&state->sem);
+			mutex_lock(&state->sem);
 			if (dmabuf->mapped) {
 				if (!ret)
 					ret = -ENXIO;
@@ -1968,7 +1970,7 @@
 		start_adc(state);
 	}
 out:
-	up(&state->sem);
+	mutex_unlock(&state->sem);
 	return ret;
 }
 
@@ -1996,7 +1998,7 @@
 	 *      Guard against an mmap or ioctl while writing
 	 */
 
-	down(&state->sem);
+	mutex_lock(&state->sem);
 
 	if (dmabuf->mapped) {
 		ret = -ENXIO;
@@ -2045,7 +2047,7 @@
 			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
 			tmo >>= sample_shift[dmabuf->fmt];
 			unlock_set_fmt(state);
-			up(&state->sem);
+			mutex_unlock(&state->sem);
 
 			/* There are two situations when sleep_on_timeout */ 
 			/* returns, one is when the interrupt is serviced */ 
@@ -2073,7 +2075,7 @@
 					ret = -ERESTARTSYS;
 				goto out_nolock;
 			}
-			down(&state->sem);
+			mutex_lock(&state->sem);
 			if (dmabuf->mapped) {
 				if (!ret)
 					ret = -ENXIO;
@@ -2131,7 +2133,7 @@
 		start_dac(state);
 	}
 out:
-	up(&state->sem);
+	mutex_unlock(&state->sem);
 out_nolock:
 	return ret;
 }
@@ -2152,24 +2154,24 @@
 	 *      prog_dmabuf events
 	 */
 
-	down(&state->sem);
+	mutex_lock(&state->sem);
 
 	if (file->f_mode & FMODE_WRITE) {
 		if (!dmabuf->ready && prog_dmabuf_playback(state)) {
-			up(&state->sem);
+			mutex_unlock(&state->sem);
 			return 0;
 		}
 		poll_wait(file, &dmabuf->wait, wait);
 	}
 	if (file->f_mode & FMODE_READ) {
 		if (!dmabuf->ready && prog_dmabuf_record(state)) {
-			up(&state->sem);
+			mutex_unlock(&state->sem);
 			return 0;
 		}
 		poll_wait(file, &dmabuf->wait, wait);
 	}
 
-	up(&state->sem);
+	mutex_unlock(&state->sem);
 
 	spin_lock_irqsave(&state->card->lock, flags);
 	trident_update_ptr(state);
@@ -2207,7 +2209,7 @@
 	 *      a read or write against an mmap.
 	 */
 
-	down(&state->sem);
+	mutex_lock(&state->sem);
 
 	if (vma->vm_flags & VM_WRITE) {
 		if ((ret = prog_dmabuf_playback(state)) != 0)
@@ -2232,7 +2234,7 @@
 	dmabuf->mapped = 1;
 	ret = 0;
 out:
-	up(&state->sem);
+	mutex_unlock(&state->sem);
 	return ret;
 }
 
@@ -2429,15 +2431,15 @@
 							unlock_set_fmt(state);
 							break;
 						}
-						down(&state->card->open_sem);
+						mutex_lock(&state->card->open_mutex);
 						ret = ali_allocate_other_states_resources(state, 6);
 						if (ret < 0) {
-							up(&state->card->open_sem);
+							mutex_unlock(&state->card->open_mutex);
 							unlock_set_fmt(state);
 							break;
 						}
 						state->card->multi_channel_use_count++;
-						up(&state->card->open_sem);
+						mutex_unlock(&state->card->open_mutex);
 					} else
 						val = 2;	/*yield to 2-channels */
 				} else
@@ -2727,11 +2729,11 @@
 
 	/* find an available virtual channel (instance of /dev/dsp) */
 	while (card != NULL) {
-		down(&card->open_sem);
+		mutex_lock(&card->open_mutex);
 		if (file->f_mode & FMODE_READ) {
 			/* Skip opens on cards that are in 6 channel mode */
 			if (card->multi_channel_use_count > 0) {
-				up(&card->open_sem);
+				mutex_unlock(&card->open_mutex);
 				card = card->next;
 				continue;
 			}
@@ -2740,16 +2742,16 @@
 			if (card->states[i] == NULL) {
 				state = card->states[i] = kmalloc(sizeof(*state), GFP_KERNEL);
 				if (state == NULL) {
-					up(&card->open_sem);
+					mutex_unlock(&card->open_mutex);
 					return -ENOMEM;
 				}
 				memset(state, 0, sizeof(*state));
-				init_MUTEX(&state->sem);
+				mutex_init(&state->sem);
 				dmabuf = &state->dmabuf;
 				goto found_virt;
 			}
 		}
-		up(&card->open_sem);
+		mutex_unlock(&card->open_mutex);
 		card = card->next;
 	}
 	/* no more virtual channel avaiable */
@@ -2816,7 +2818,7 @@
 	}
 
 	state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	up(&card->open_sem);
+	mutex_unlock(&card->open_mutex);
 
 	pr_debug("trident: open virtual channel %d, hard channel %d\n",
 		 state->virt, dmabuf->channel->num);
@@ -2845,7 +2847,7 @@
 		 state->virt, dmabuf->channel->num);
 
 	/* stop DMA state machine and free DMA buffers/channels */
-	down(&card->open_sem);
+	mutex_lock(&card->open_mutex);
 
 	if (file->f_mode & FMODE_WRITE) {
 		stop_dac(state);
@@ -2878,8 +2880,8 @@
 	card->states[state->virt] = NULL;
 	kfree(state);
 
-	/* we're covered by the open_sem */
-	up(&card->open_sem);
+	/* we're covered by the open_mutex */
+	mutex_unlock(&card->open_mutex);
 
 	return 0;
 }
@@ -4405,7 +4407,7 @@
 	card->banks[BANK_B].addresses = &bank_b_addrs;
 	card->banks[BANK_B].bitmap = 0UL;
 
-	init_MUTEX(&card->open_sem);
+	mutex_init(&card->open_mutex);
 	spin_lock_init(&card->lock);
 	init_timer(&card->timer);
 
diff -urN oldtree/sound/oss/via82cxxx_audio.c newtree/sound/oss/via82cxxx_audio.c
--- oldtree/sound/oss/via82cxxx_audio.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/oss/via82cxxx_audio.c	2006-02-21 15:58:26.730082968 +0000
@@ -38,7 +38,8 @@
 #include <linux/dma-mapping.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
 #include "sound_config.h"
 #include "dev_table.h"
 #include "mpu401.h"
@@ -311,8 +312,8 @@
 	
 	int mixer_vol;		/* 8233/35 volume  - not yet implemented */
 
-	struct semaphore syscall_sem;
-	struct semaphore open_sem;
+	struct mutex syscall_mutex;
+	struct mutex open_mutex;
 
 	/* The 8233/8235 have 4 DX audio channels, two record and
 	   one six channel out. We bind ch_in to DX 1, ch_out to multichannel
@@ -505,10 +506,10 @@
 	nonblock = 0;
 
 	if (nonblock) {
-		if (down_trylock (&card->syscall_sem))
+		if (!mutex_trylock(&card->syscall_mutex))
 			return -EAGAIN;
 	} else {
-		if (down_interruptible (&card->syscall_sem))
+		if (mutex_lock_interruptible(&card->syscall_mutex))
 			return -ERESTARTSYS;
 	}
 
@@ -1609,7 +1610,7 @@
 #endif
 	rc = codec->mixer_ioctl(codec, cmd, arg);
 
-	up (&card->syscall_sem);
+	mutex_unlock(&card->syscall_mutex);
 
 out:
 	DPRINTK ("EXIT, returning %d\n", rc);
@@ -2228,7 +2229,7 @@
 	if (wr)
 		card->ch_out.is_mapped = 1;
 
-	up (&card->syscall_sem);
+	mutex_unlock(&card->syscall_mutex);
 	rc = 0;
 
 out:
@@ -2256,7 +2257,7 @@
 	/* Thomas Sailer:
 	 * But also to ourselves, release semaphore if we do so */
 	if (need_resched()) {
-		up(&card->syscall_sem);
+		mutex_unlock(&card->syscall_mutex);
 		schedule ();
 		ret = via_syscall_down (card, nonblock);
 		if (ret)
@@ -2286,7 +2287,7 @@
 			break;
 		}
 
-		up(&card->syscall_sem);
+		mutex_unlock(&card->syscall_mutex);
 
 		DPRINTK ("Sleeping on block %d\n", n);
 		schedule();
@@ -2402,7 +2403,7 @@
 	rc = via_dsp_do_read (card, buffer, count, nonblock);
 
 out_up:
-	up (&card->syscall_sem);
+	mutex_unlock(&card->syscall_mutex);
 out:
 	DPRINTK ("EXIT, returning %ld\n",(long) rc);
 	return rc;
@@ -2426,7 +2427,7 @@
 	/* Thomas Sailer:
 	 * But also to ourselves, release semaphore if we do so */
 	if (need_resched()) {
-		up(&card->syscall_sem);
+		mutex_unlock(&card->syscall_mutex);
 		schedule ();
 		ret = via_syscall_down (card, nonblock);
 		if (ret)
@@ -2456,7 +2457,7 @@
 			break;
 		}
 
-		up(&card->syscall_sem);
+		mutex_unlock(&card->syscall_mutex);
 
 		DPRINTK ("Sleeping on page %d, tmp==%d, ir==%d\n", n, tmp, chan->is_record);
 		schedule();
@@ -2585,7 +2586,7 @@
 	rc = via_dsp_do_write (card, buffer, count, nonblock);
 
 out_up:
-	up (&card->syscall_sem);
+	mutex_unlock(&card->syscall_mutex);
 out:
 	DPRINTK ("EXIT, returning %ld\n",(long) rc);
 	return rc;
@@ -2634,7 +2635,7 @@
  *	Sleeps until all playback has been flushed to the audio
  *	hardware.
  *
- *	Locking: inside card->syscall_sem
+ *	Locking: inside card->syscall_mutex
  */
 
 static int via_dsp_drain_playback (struct via_info *card,
@@ -2692,7 +2693,7 @@
 			printk (KERN_ERR "sleeping but not active\n");
 #endif
 
-		up(&card->syscall_sem);
+		mutex_unlock(&card->syscall_mutex);
 
 		DPRINTK ("sleeping, nbufs=%d\n", atomic_read (&chan->n_frags));
 		schedule();
@@ -2748,7 +2749,7 @@
  *
  *	Handles SNDCTL_DSP_GETISPACE and SNDCTL_DSP_GETOSPACE.
  *
- *	Locking: inside card->syscall_sem
+ *	Locking: inside card->syscall_mutex
  */
 
 static int via_dsp_ioctl_space (struct via_info *card,
@@ -2793,7 +2794,7 @@
  *
  *	Handles SNDCTL_DSP_GETIPTR and SNDCTL_DSP_GETOPTR.
  *
- *	Locking: inside card->syscall_sem
+ *	Locking: inside card->syscall_mutex
  */
 
 static int via_dsp_ioctl_ptr (struct via_info *card,
@@ -3221,7 +3222,7 @@
 		break;
 	}
 
-	up (&card->syscall_sem);
+	mutex_unlock(&card->syscall_mutex);
 	DPRINTK ("EXIT, returning %d\n", rc);
 	return rc;
 }
@@ -3264,12 +3265,12 @@
 
 match:
 	if (nonblock) {
-		if (down_trylock (&card->open_sem)) {
+		if (!mutex_trylock(&card->open_mutex)) {
 			DPRINTK ("EXIT, returning -EAGAIN\n");
 			return -EAGAIN;
 		}
 	} else {
-		if (down_interruptible (&card->open_sem)) {
+		if (mutex_lock_interruptible(&card->open_mutex)) {
 			DPRINTK ("EXIT, returning -ERESTARTSYS\n");
 			return -ERESTARTSYS;
 		}
@@ -3355,8 +3356,8 @@
 		via_chan_buffer_free (card, &card->ch_in);
 	}
 
-	up (&card->syscall_sem);
-	up (&card->open_sem);
+	mutex_unlock(&card->syscall_mutex);
+	mutex_unlock(&card->open_mutex);
 
 	DPRINTK ("EXIT, returning 0\n");
 	return 0;
@@ -3414,8 +3415,8 @@
 	card->card_num = via_num_cards++;
 	spin_lock_init (&card->lock);
 	spin_lock_init (&card->ac97_lock);
-	init_MUTEX (&card->syscall_sem);
-	init_MUTEX (&card->open_sem);
+	mutex_init(&card->syscall_mutex);
+	mutex_init(&card->open_mutex);
 
 	/* we must init these now, in case the intr handler needs them */
 	via_chan_init_defaults (card, &card->ch_out);
diff -urN oldtree/sound/oss/vwsnd.c newtree/sound/oss/vwsnd.c
--- oldtree/sound/oss/vwsnd.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/oss/vwsnd.c	2006-02-21 15:58:26.855063968 +0000
@@ -94,7 +94,7 @@
  *	Open will block until the previous client has closed the
  *	device, unless O_NONBLOCK is specified.
  *
- *	The semaphore devc->io_sema serializes PCM I/O syscalls.  This
+ *	The semaphore devc->io_mutex serializes PCM I/O syscalls.  This
  *	is unnecessary in Linux 2.2, because the kernel lock
  *	serializes read, write, and ioctl globally, but it's there,
  *	ready for the brave, new post-kernel-lock world.
@@ -105,7 +105,7 @@
  *	area it owns and update its pointers.  See pcm_output() and
  *	pcm_input() for most of the gory stuff.
  *
- *	devc->mix_sema serializes all mixer ioctls.  This is also
+ *	devc->mix_mutex serializes all mixer ioctls.  This is also
  *	redundant because of the kernel lock.
  *
  *	The lowest level lock is lith->lithium_lock.  It is a
@@ -148,7 +148,8 @@
 #include <linux/smp_lock.h>
 #include <linux/wait.h>
 #include <linux/interrupt.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
 #include <asm/mach-visws/cobalt.h>
 
 #include "sound_config.h"
@@ -1447,11 +1448,11 @@
  *
  *	port->lock protects: hwstate, flags, swb_[iu]_avail.
  *
- *	devc->io_sema protects: swstate, sw_*, swb_[iu]_idx.
+ *	devc->io_mutex protects: swstate, sw_*, swb_[iu]_idx.
  *
  *	everything else is only written by open/release or
  *	pcm_{setup,shutdown}(), which are serialized by a
- *	combination of devc->open_sema and devc->io_sema.
+ *	combination of devc->open_mutex and devc->io_mutex.
  */
 
 typedef struct vwsnd_port {
@@ -1507,9 +1508,9 @@
 	int		audio_minor;	/* minor number of audio device */
 	int		mixer_minor;	/* minor number of mixer device */
 
-	struct semaphore open_sema;
-	struct semaphore io_sema;
-	struct semaphore mix_sema;
+	struct mutex open_mutex;
+	struct mutex io_mutex;
+	struct mutex mix_mutex;
 	mode_t		open_mode;
 	wait_queue_head_t open_wait;
 
@@ -1633,7 +1634,7 @@
  * mode-setting ioctls have been done, but before the first I/O is
  * done.
  *
- * Locking: called with devc->io_sema held.
+ * Locking: called with devc->io_mutex held.
  *
  * Returns 0 on success, -errno on failure.
  */
@@ -2319,9 +2320,9 @@
 	vwsnd_dev_t *devc = file->private_data;
 	ssize_t ret;
 
-	down(&devc->io_sema);
+	mutex_lock(&devc->io_mutex);
 	ret = vwsnd_audio_do_read(file, buffer, count, ppos);
-	up(&devc->io_sema);
+	mutex_unlock(&devc->io_mutex);
 	return ret;
 }
 
@@ -2394,9 +2395,9 @@
 	vwsnd_dev_t *devc = file->private_data;
 	ssize_t ret;
 
-	down(&devc->io_sema);
+	mutex_lock(&devc->io_mutex);
 	ret = vwsnd_audio_do_write(file, buffer, count, ppos);
-	up(&devc->io_sema);
+	mutex_unlock(&devc->io_mutex);
 	return ret;
 }
 
@@ -2891,9 +2892,9 @@
 	vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
 	int ret;
 
-	down(&devc->io_sema);
+	mutex_lock(&devc->io_mutex);
 	ret = vwsnd_audio_do_ioctl(inode, file, cmd, arg);
-	up(&devc->io_sema);
+	mutex_unlock(&devc->io_mutex);
 	return ret;
 }
 
@@ -2929,9 +2930,9 @@
 		return -ENODEV;
 	}
 
-	down(&devc->open_sema);
+	mutex_lock(&devc->open_mutex);
 	while (devc->open_mode & file->f_mode) {
-		up(&devc->open_sema);
+		mutex_unlock(&devc->open_mutex);
 		if (file->f_flags & O_NONBLOCK) {
 			DEC_USE_COUNT;
 			return -EBUSY;
@@ -2941,10 +2942,10 @@
 			DEC_USE_COUNT;
 			return -ERESTARTSYS;
 		}
-		down(&devc->open_sema);
+		mutex_lock(&devc->open_mutex);
 	}
 	devc->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	up(&devc->open_sema);
+	mutex_unlock(&devc->open_mutex);
 
 	/* get default sample format from minor number. */
 
@@ -2960,7 +2961,7 @@
 
 	/* Initialize vwsnd_ports. */
 
-	down(&devc->io_sema);
+	mutex_lock(&devc->io_mutex);
 	{
 		if (file->f_mode & FMODE_READ) {
 			devc->rport.swstate        = SW_INITIAL;
@@ -2987,7 +2988,7 @@
 			devc->wport.frag_count     = 0;
 		}
 	}
-	up(&devc->io_sema);
+	mutex_unlock(&devc->io_mutex);
 
 	file->private_data = devc;
 	DBGRV();
@@ -3005,7 +3006,7 @@
 	int err = 0;
 
 	lock_kernel();
-	down(&devc->io_sema);
+	mutex_lock(&devc->io_mutex);
 	{
 		DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
 
@@ -3022,13 +3023,13 @@
 		if (wport)
 			wport->swstate = SW_OFF;
 	}
-	up(&devc->io_sema);
+	mutex_unlock(&devc->io_mutex);
 
-	down(&devc->open_sema);
+	mutex_lock(&devc->open_mutex);
 	{
 		devc->open_mode &= ~file->f_mode;
 	}
-	up(&devc->open_sema);
+	mutex_unlock(&devc->open_mutex);
 	wake_up(&devc->open_wait);
 	DEC_USE_COUNT;
 	DBGR();
@@ -3213,7 +3214,7 @@
 
 	DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg);
 
-	down(&devc->mix_sema);
+	mutex_lock(&devc->mix_mutex);
 	{
 		if ((cmd & ~nrmask) == MIXER_READ(0))
 			retval = mixer_read_ioctl(devc, nr, (void __user *) arg);
@@ -3222,7 +3223,7 @@
 		else
 			retval = -EINVAL;
 	}
-	up(&devc->mix_sema);
+	mutex_unlock(&devc->mix_mutex);
 	return retval;
 }
 
@@ -3376,9 +3377,9 @@
 
 	/* Initialize as much of *devc as possible */
 
-	init_MUTEX(&devc->open_sema);
-	init_MUTEX(&devc->io_sema);
-	init_MUTEX(&devc->mix_sema);
+	mutex_init(&devc->open_mutex);
+	mutex_init(&devc->io_mutex);
+	mutex_init(&devc->mix_mutex);
 	devc->open_mode = 0;
 	spin_lock_init(&devc->rport.lock);
 	init_waitqueue_head(&devc->rport.queue);
diff -urN oldtree/sound/oss/ymfpci.c newtree/sound/oss/ymfpci.c
--- oldtree/sound/oss/ymfpci.c	2006-02-19 11:41:06.915291816 +0000
+++ newtree/sound/oss/ymfpci.c	2006-02-21 15:58:26.902056824 +0000
@@ -1918,10 +1918,10 @@
 	if (unit == NULL)
 		return -ENODEV;
 
-	down(&unit->open_sem);
+	mutex_lock(&unit->open_mutex);
 
 	if ((state = ymf_state_alloc(unit)) == NULL) {
-		up(&unit->open_sem);
+		mutex_unlock(&unit->open_mutex);
 		return -ENOMEM;
 	}
 	list_add_tail(&state->chain, &unit->states);
@@ -1956,7 +1956,7 @@
 	ymfpci_writeb(unit, YDSXGR_TIMERCTRL,
 	    (YDSXGR_TIMERCTRL_TEN|YDSXGR_TIMERCTRL_TIEN));
 #endif
-	up(&unit->open_sem);
+	mutex_unlock(&unit->open_mutex);
 
 	return nonseekable_open(inode, file);
 
@@ -1974,7 +1974,7 @@
 	list_del(&state->chain);
 	kfree(state);
 
-	up(&unit->open_sem);
+	mutex_unlock(&unit->open_mutex);
 	return err;
 }
 
@@ -1987,7 +1987,7 @@
 	ymfpci_writeb(unit, YDSXGR_TIMERCTRL, 0);
 #endif
 
-	down(&unit->open_sem);
+	mutex_lock(&unit->open_mutex);
 
 	/*
 	 * XXX Solve the case of O_NONBLOCK close - don't deallocate here.
@@ -2004,7 +2004,7 @@
 	file->private_data = NULL;	/* Can you tell I programmed Solaris */
 	kfree(state);
 
-	up(&unit->open_sem);
+	mutex_unlock(&unit->open_mutex);
 
 	return 0;
 }
@@ -2532,7 +2532,7 @@
 	spin_lock_init(&codec->reg_lock);
 	spin_lock_init(&codec->voice_lock);
 	spin_lock_init(&codec->ac97_lock);
-	init_MUTEX(&codec->open_sem);
+	mutex_init(&codec->open_mutex);
 	INIT_LIST_HEAD(&codec->states);
 	codec->pci = pcidev;
 
diff -urN oldtree/sound/oss/ymfpci.h newtree/sound/oss/ymfpci.h
--- oldtree/sound/oss/ymfpci.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/oss/ymfpci.h	2006-02-21 15:58:26.922053784 +0000
@@ -22,6 +22,7 @@
  *
  */
 #include <linux/config.h>
+#include <linux/mutex.h>
 
 /*
  *  Direct registers
@@ -279,7 +280,7 @@
 
 	/* soundcore stuff */
 	int dev_audio;
-	struct semaphore open_sem;
+	struct mutex open_mutex;
 
 	struct list_head ymf_devs;
 	struct list_head states;	/* List of states for this unit */
diff -urN oldtree/sound/pci/ac97/ac97_codec.c newtree/sound/pci/ac97/ac97_codec.c
--- oldtree/sound/pci/ac97/ac97_codec.c	2006-02-19 11:41:06.922290752 +0000
+++ newtree/sound/pci/ac97/ac97_codec.c	2006-02-21 15:58:11.398413736 +0000
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
@@ -296,11 +297,11 @@
 {
 	if (!snd_ac97_valid_reg(ac97, reg))
 		return;
-	down(&ac97->reg_mutex);
+	mutex_lock(&ac97->reg_mutex);
 	ac97->regs[reg] = value;
 	ac97->bus->ops->write(ac97, reg, value);
 	set_bit(reg, ac97->reg_accessed);
-	up(&ac97->reg_mutex);
+	mutex_unlock(&ac97->reg_mutex);
 }
 
 /**
@@ -321,14 +322,14 @@
 
 	if (!snd_ac97_valid_reg(ac97, reg))
 		return -EINVAL;
-	down(&ac97->reg_mutex);
+	mutex_lock(&ac97->reg_mutex);
 	change = ac97->regs[reg] != value;
 	if (change) {
 		ac97->regs[reg] = value;
 		ac97->bus->ops->write(ac97, reg, value);
 	}
 	set_bit(reg, ac97->reg_accessed);
-	up(&ac97->reg_mutex);
+	mutex_unlock(&ac97->reg_mutex);
 	return change;
 }
 
@@ -351,9 +352,9 @@
 
 	if (!snd_ac97_valid_reg(ac97, reg))
 		return -EINVAL;
-	down(&ac97->reg_mutex);
+	mutex_lock(&ac97->reg_mutex);
 	change = snd_ac97_update_bits_nolock(ac97, reg, mask, value);
-	up(&ac97->reg_mutex);
+	mutex_unlock(&ac97->reg_mutex);
 	return change;
 }
 
@@ -380,12 +381,12 @@
 	int change;
 	unsigned short old, new, cfg;
 
-	down(&ac97->page_mutex);
+	mutex_lock(&ac97->page_mutex);
 	old = ac97->spec.ad18xx.pcmreg[codec];
 	new = (old & ~mask) | value;
 	change = old != new;
 	if (change) {
-		down(&ac97->reg_mutex);
+		mutex_lock(&ac97->reg_mutex);
 		cfg = snd_ac97_read_cache(ac97, AC97_AD_SERIAL_CFG);
 		ac97->spec.ad18xx.pcmreg[codec] = new;
 		/* select single codec */
@@ -397,9 +398,9 @@
 		/* select all codecs */
 		ac97->bus->ops->write(ac97, AC97_AD_SERIAL_CFG,
 				 cfg | 0x7000);
-		up(&ac97->reg_mutex);
+		mutex_unlock(&ac97->reg_mutex);
 	}
-	up(&ac97->page_mutex);
+	mutex_unlock(&ac97->page_mutex);
 	return change;
 }
 
@@ -467,7 +468,7 @@
 	    (ac97->ext_id & AC97_EI_REV_MASK) >= AC97_EI_REV_23 &&
 	    (reg >= 0x60 && reg < 0x70)) {
 		unsigned short page = (kcontrol->private_value >> 26) & 0x0f;
-		down(&ac97->page_mutex); /* lock paging */
+		mutex_lock(&ac97->page_mutex); /* lock paging */
 		page_save = snd_ac97_read(ac97, AC97_INT_PAGING) & AC97_PAGE_MASK;
 		snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page);
 	}
@@ -478,7 +479,7 @@
 {
 	if (page_save >= 0) {
 		snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save);
-		up(&ac97->page_mutex); /* unlock paging */
+		mutex_unlock(&ac97->page_mutex); /* unlock paging */
 	}
 }
 
@@ -674,12 +675,12 @@
 {
 	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
 
-	down(&ac97->reg_mutex);
+	mutex_lock(&ac97->reg_mutex);
 	ucontrol->value.iec958.status[0] = ac97->spdif_status & 0xff;
 	ucontrol->value.iec958.status[1] = (ac97->spdif_status >> 8) & 0xff;
 	ucontrol->value.iec958.status[2] = (ac97->spdif_status >> 16) & 0xff;
 	ucontrol->value.iec958.status[3] = (ac97->spdif_status >> 24) & 0xff;
-	up(&ac97->reg_mutex);
+	mutex_unlock(&ac97->reg_mutex);
 	return 0;
 }
                         
@@ -718,7 +719,7 @@
 		}
 	}
 
-	down(&ac97->reg_mutex);
+	mutex_lock(&ac97->reg_mutex);
 	change = ac97->spdif_status != new;
 	ac97->spdif_status = new;
 
@@ -746,7 +747,7 @@
 			snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */
                 }
 	}
-	up(&ac97->reg_mutex);
+	mutex_unlock(&ac97->reg_mutex);
 
 	return change;
 }
@@ -763,7 +764,7 @@
 
 	value = (ucontrol->value.integer.value[0] & mask);
 
-	down(&ac97->reg_mutex);
+	mutex_lock(&ac97->reg_mutex);
 	mask <<= shift;
 	value <<= shift;
 	old = snd_ac97_read_cache(ac97, reg);
@@ -777,7 +778,7 @@
 		if (extst & AC97_EA_SPDIF)
 			snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */
 	}
-	up(&ac97->reg_mutex);
+	mutex_unlock(&ac97->reg_mutex);
 	return change;
 }
 
@@ -888,10 +889,10 @@
 	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
 	int codec = kcontrol->private_value & 3;
 	
-	down(&ac97->page_mutex);
+	mutex_lock(&ac97->page_mutex);
 	ucontrol->value.integer.value[0] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 0) & 31);
 	ucontrol->value.integer.value[1] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 8) & 31);
-	up(&ac97->page_mutex);
+	mutex_unlock(&ac97->page_mutex);
 	return 0;
 }
 
@@ -1856,8 +1857,8 @@
 	ac97->limited_regs = template->limited_regs;
 	memcpy(ac97->reg_accessed, template->reg_accessed, sizeof(ac97->reg_accessed));
 	bus->codec[ac97->num] = ac97;
-	init_MUTEX(&ac97->reg_mutex);
-	init_MUTEX(&ac97->page_mutex);
+	mutex_init(&ac97->reg_mutex);
+	mutex_init(&ac97->page_mutex);
 
 #ifdef CONFIG_PCI
 	if (ac97->pci) {
diff -urN oldtree/sound/pci/ac97/ac97_patch.c newtree/sound/pci/ac97/ac97_patch.c
--- oldtree/sound/pci/ac97/ac97_patch.c	2006-02-19 11:41:06.926290144 +0000
+++ newtree/sound/pci/ac97/ac97_patch.c	2006-02-21 15:58:11.400413432 +0000
@@ -27,6 +27,8 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/control.h>
@@ -55,12 +57,12 @@
 	unsigned short page_save;
 	int ret;
 
-	down(&ac97->page_mutex);
+	mutex_lock(&ac97->page_mutex);
 	page_save = snd_ac97_read(ac97, AC97_INT_PAGING) & AC97_PAGE_MASK;
 	snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page);
 	ret = snd_ac97_update_bits(ac97, reg, mask, value);
 	snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save);
-	up(&ac97->page_mutex); /* unlock paging */
+	mutex_unlock(&ac97->page_mutex); /* unlock paging */
 	return ret;
 }
 
@@ -897,12 +899,12 @@
 	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
 	int err;
 
-	down(&ac97->page_mutex);
+	mutex_lock(&ac97->page_mutex);
 	snd_ac97_write(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
 	err = snd_ac97_update_bits(ac97, AC97_SIGMATEL_BIAS2, 0x0010,
 				   (ucontrol->value.integer.value[0] & 1) << 4);
 	snd_ac97_write(ac97, AC97_SIGMATEL_BIAS1, 0);
-	up(&ac97->page_mutex);
+	mutex_unlock(&ac97->page_mutex);
 	return err;
 }
 
diff -urN oldtree/sound/pci/ac97/ac97_pcm.c newtree/sound/pci/ac97/ac97_pcm.c
--- oldtree/sound/pci/ac97/ac97_pcm.c	2006-02-19 11:41:06.927289992 +0000
+++ newtree/sound/pci/ac97/ac97_pcm.c	2006-02-21 15:58:11.401413280 +0000
@@ -27,6 +27,8 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/control.h>
@@ -206,7 +208,7 @@
 		mask = AC97_SC_SPSR_MASK;
 	}
 
-	down(&ac97->reg_mutex);
+	mutex_lock(&ac97->reg_mutex);
 	old = snd_ac97_read(ac97, reg) & mask;
 	if (old != bits) {
 		snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0);
@@ -231,7 +233,7 @@
 		ac97->spdif_status = sbits;
 	}
 	snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF);
-	up(&ac97->reg_mutex);
+	mutex_unlock(&ac97->reg_mutex);
 	return 0;
 }
 
diff -urN oldtree/sound/pci/ac97/ac97_proc.c newtree/sound/pci/ac97/ac97_proc.c
--- oldtree/sound/pci/ac97/ac97_proc.c	2006-02-19 11:41:06.929289688 +0000
+++ newtree/sound/pci/ac97/ac97_proc.c	2006-02-21 15:58:11.402413128 +0000
@@ -24,6 +24,8 @@
 
 #include <sound/driver.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/ac97_codec.h>
 #include <sound/asoundef.h>
@@ -338,7 +340,7 @@
 {
 	struct snd_ac97 *ac97 = entry->private_data;
 	
-	down(&ac97->page_mutex);
+	mutex_lock(&ac97->page_mutex);
 	if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) {	// Analog Devices AD1881/85/86
 		int idx;
 		for (idx = 0; idx < 3; idx++)
@@ -364,7 +366,7 @@
 	} else {
 		snd_ac97_proc_read_main(ac97, buffer, 0);
 	}
-	up(&ac97->page_mutex);
+	mutex_unlock(&ac97->page_mutex);
 }
 
 #ifdef CONFIG_SND_DEBUG
@@ -374,7 +376,7 @@
 	struct snd_ac97 *ac97 = entry->private_data;
 	char line[64];
 	unsigned int reg, val;
-	down(&ac97->page_mutex);
+	mutex_lock(&ac97->page_mutex);
 	while (!snd_info_get_line(buffer, line, sizeof(line))) {
 		if (sscanf(line, "%x %x", &reg, &val) != 2)
 			continue;
@@ -382,7 +384,7 @@
 		if (reg < 0x80 && (reg & 1) == 0 && val <= 0xffff)
 			snd_ac97_write_cache(ac97, reg, val);
 	}
-	up(&ac97->page_mutex);
+	mutex_unlock(&ac97->page_mutex);
 }
 #endif
 
@@ -401,7 +403,7 @@
 {
 	struct snd_ac97 *ac97 = entry->private_data;
 
-	down(&ac97->page_mutex);
+	mutex_lock(&ac97->page_mutex);
 	if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) {	// Analog Devices AD1881/85/86
 
 		int idx;
@@ -417,7 +419,7 @@
 	} else {
 		snd_ac97_proc_regs_read_main(ac97, buffer, 0);
 	}	
-	up(&ac97->page_mutex);
+	mutex_unlock(&ac97->page_mutex);
 }
 
 void snd_ac97_proc_init(struct snd_ac97 * ac97)
diff -urN oldtree/sound/pci/ac97/ak4531_codec.c newtree/sound/pci/ac97/ak4531_codec.c
--- oldtree/sound/pci/ac97/ak4531_codec.c	2006-02-19 11:41:06.929289688 +0000
+++ newtree/sound/pci/ac97/ak4531_codec.c	2006-02-21 15:58:11.403412976 +0000
@@ -23,6 +23,8 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/ak4531_codec.h>
 
@@ -82,9 +84,9 @@
 	int invert = (kcontrol->private_value >> 22) & 1;
 	int val;
 
-	down(&ak4531->reg_mutex);
+	mutex_lock(&ak4531->reg_mutex);
 	val = (ak4531->regs[reg] >> shift) & mask;
-	up(&ak4531->reg_mutex);
+	mutex_unlock(&ak4531->reg_mutex);
 	if (invert) {
 		val = mask - val;
 	}
@@ -107,11 +109,11 @@
 		val = mask - val;
 	}
 	val <<= shift;
-	down(&ak4531->reg_mutex);
+	mutex_lock(&ak4531->reg_mutex);
 	val = (ak4531->regs[reg] & ~(mask << shift)) | val;
 	change = val != ak4531->regs[reg];
 	ak4531->write(ak4531, reg, ak4531->regs[reg] = val);
-	up(&ak4531->reg_mutex);
+	mutex_unlock(&ak4531->reg_mutex);
 	return change;
 }
 
@@ -143,10 +145,10 @@
 	int invert = (kcontrol->private_value >> 22) & 1;
 	int left, right;
 
-	down(&ak4531->reg_mutex);
+	mutex_lock(&ak4531->reg_mutex);
 	left = (ak4531->regs[left_reg] >> left_shift) & mask;
 	right = (ak4531->regs[right_reg] >> right_shift) & mask;
-	up(&ak4531->reg_mutex);
+	mutex_unlock(&ak4531->reg_mutex);
 	if (invert) {
 		left = mask - left;
 		right = mask - right;
@@ -176,7 +178,7 @@
 	}
 	left <<= left_shift;
 	right <<= right_shift;
-	down(&ak4531->reg_mutex);
+	mutex_lock(&ak4531->reg_mutex);
 	if (left_reg == right_reg) {
 		left = (ak4531->regs[left_reg] & ~((mask << left_shift) | (mask << right_shift))) | left | right;
 		change = left != ak4531->regs[left_reg];
@@ -188,7 +190,7 @@
 		ak4531->write(ak4531, left_reg, ak4531->regs[left_reg] = left);
 		ak4531->write(ak4531, right_reg, ak4531->regs[right_reg] = right);
 	}
-	up(&ak4531->reg_mutex);
+	mutex_unlock(&ak4531->reg_mutex);
 	return change;
 }
 
@@ -215,12 +217,12 @@
 	int left_shift = (kcontrol->private_value >> 16) & 0x0f;
 	int right_shift = (kcontrol->private_value >> 24) & 0x0f;
 
-	down(&ak4531->reg_mutex);
+	mutex_lock(&ak4531->reg_mutex);
 	ucontrol->value.integer.value[0] = (ak4531->regs[reg1] >> left_shift) & 1;
 	ucontrol->value.integer.value[1] = (ak4531->regs[reg2] >> left_shift) & 1;
 	ucontrol->value.integer.value[2] = (ak4531->regs[reg1] >> right_shift) & 1;
 	ucontrol->value.integer.value[3] = (ak4531->regs[reg2] >> right_shift) & 1;
-	up(&ak4531->reg_mutex);
+	mutex_unlock(&ak4531->reg_mutex);
 	return 0;
 }
 
@@ -234,7 +236,7 @@
 	int change;
 	int val1, val2;
 
-	down(&ak4531->reg_mutex);
+	mutex_lock(&ak4531->reg_mutex);
 	val1 = ak4531->regs[reg1] & ~((1 << left_shift) | (1 << right_shift));
 	val2 = ak4531->regs[reg2] & ~((1 << left_shift) | (1 << right_shift));
 	val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift;
@@ -244,7 +246,7 @@
 	change = val1 != ak4531->regs[reg1] || val2 != ak4531->regs[reg2];
 	ak4531->write(ak4531, reg1, ak4531->regs[reg1] = val1);
 	ak4531->write(ak4531, reg2, ak4531->regs[reg2] = val2);
-	up(&ak4531->reg_mutex);
+	mutex_unlock(&ak4531->reg_mutex);
 	return change;
 }
 
@@ -366,7 +368,7 @@
 	if (ak4531 == NULL)
 		return -ENOMEM;
 	*ak4531 = *_ak4531;
-	init_MUTEX(&ak4531->reg_mutex);
+	mutex_init(&ak4531->reg_mutex);
 	if ((err = snd_component_add(card, "AK4531")) < 0) {
 		snd_ak4531_free(ak4531);
 		return err;
diff -urN oldtree/sound/pci/atiixp.c newtree/sound/pci/atiixp.c
--- oldtree/sound/pci/atiixp.c	2006-02-19 11:41:06.944287408 +0000
+++ newtree/sound/pci/atiixp.c	2006-02-21 15:58:11.406412520 +0000
@@ -27,6 +27,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -277,7 +278,7 @@
 	unsigned int codec_not_ready_bits;	/* for codec detection */
 
 	int spdif_over_aclink;		/* passed from the module option */
-	struct semaphore open_mutex;	/* playback open mutex */
+	struct mutex open_mutex;	/* playback open mutex */
 };
 
 
@@ -1051,9 +1052,9 @@
 	struct atiixp *chip = snd_pcm_substream_chip(substream);
 	int err;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0);
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	if (err < 0)
 		return err;
 	substream->runtime->hw.channels_max = chip->max_channels;
@@ -1068,9 +1069,9 @@
 {
 	struct atiixp *chip = snd_pcm_substream_chip(substream);
 	int err;
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	return err;
 }
 
@@ -1090,12 +1091,12 @@
 {
 	struct atiixp *chip = snd_pcm_substream_chip(substream);
 	int err;
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	if (chip->spdif_over_aclink) /* share DMA_PLAYBACK */
 		err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 2);
 	else
 		err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_SPDIF], -1);
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	return err;
 }
 
@@ -1103,12 +1104,12 @@
 {
 	struct atiixp *chip = snd_pcm_substream_chip(substream);
 	int err;
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	if (chip->spdif_over_aclink)
 		err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
 	else
 		err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_SPDIF]);
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	return err;
 }
 
@@ -1560,7 +1561,7 @@
 	}
 
 	spin_lock_init(&chip->reg_lock);
-	init_MUTEX(&chip->open_mutex);
+	mutex_init(&chip->open_mutex);
 	chip->card = card;
 	chip->pci = pci;
 	chip->irq = -1;
diff -urN oldtree/sound/pci/atiixp_modem.c newtree/sound/pci/atiixp_modem.c
--- oldtree/sound/pci/atiixp_modem.c	2006-02-19 11:41:06.945287256 +0000
+++ newtree/sound/pci/atiixp_modem.c	2006-02-21 15:58:11.408412216 +0000
@@ -27,6 +27,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -255,7 +256,7 @@
 	unsigned int codec_not_ready_bits;	/* for codec detection */
 
 	int spdif_over_aclink;		/* passed from the module option */
-	struct semaphore open_mutex;	/* playback open mutex */
+	struct mutex open_mutex;	/* playback open mutex */
 };
 
 
@@ -911,9 +912,9 @@
 	struct atiixp_modem *chip = snd_pcm_substream_chip(substream);
 	int err;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0);
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	if (err < 0)
 		return err;
 	return 0;
@@ -923,9 +924,9 @@
 {
 	struct atiixp_modem *chip = snd_pcm_substream_chip(substream);
 	int err;
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	return err;
 }
 
@@ -1233,7 +1234,7 @@
 	}
 
 	spin_lock_init(&chip->reg_lock);
-	init_MUTEX(&chip->open_mutex);
+	mutex_init(&chip->open_mutex);
 	chip->card = card;
 	chip->pci = pci;
 	chip->irq = -1;
diff -urN oldtree/sound/pci/au88x0/au88x0.c newtree/sound/pci/au88x0/au88x0.c
--- oldtree/sound/pci/au88x0/au88x0.c	2006-02-19 11:41:06.946287104 +0000
+++ newtree/sound/pci/au88x0/au88x0.c	2006-02-21 15:58:11.408412216 +0000
@@ -151,14 +151,18 @@
 	// check PCI availability (DMA).
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
-	if (pci_set_dma_mask(pci, DMA_32BIT_MASK)) {
+	if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 ||
+	    pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) {
 		printk(KERN_ERR "error to set DMA mask\n");
+		pci_disable_device(pci);
 		return -ENXIO;
 	}
 
 	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-	if (chip == NULL)
+	if (chip == NULL) {
+		pci_disable_device(pci);
 		return -ENOMEM;
+	}
 
 	chip->card = card;
 
@@ -208,6 +212,8 @@
 		goto alloc_out;
 	}
 
+	snd_card_set_dev(card, &pci->dev);
+
 	*rchip = chip;
 
 	return 0;
diff -urN oldtree/sound/pci/au88x0/au88x0.h newtree/sound/pci/au88x0/au88x0.h
--- oldtree/sound/pci/au88x0/au88x0.h	2006-02-19 11:41:06.947286952 +0000
+++ newtree/sound/pci/au88x0/au88x0.h	2006-02-21 15:58:11.415411152 +0000
@@ -39,8 +39,8 @@
 #include "au88x0_wt.h"
 #endif
 
-#define	hwread(x,y) readl((x)+((y)>>2))
-#define	hwwrite(x,y,z) writel((z),(x)+((y)>>2))
+#define	hwread(x,y) readl((x)+(y))
+#define	hwwrite(x,y,z) writel((z),(x)+(y))
 
 /* Vortex MPU401 defines. */
 #define	MIDI_CLOCK_DIV		0x61
@@ -113,7 +113,7 @@
 	//int this_08;          /* Still unknown */
 	int fifo_enabled;	/* this_24 */
 	int fifo_status;	/* this_1c */
-	int dma_ctrl;		/* this_78 (ADB), this_7c (WT) */
+	u32 dma_ctrl;		/* this_78 (ADB), this_7c (WT) */
 	int dma_unknown;	/* this_74 (ADB), this_78 (WT). WDM: +8 */
 	int cfg0;
 	int cfg1;
@@ -178,7 +178,7 @@
 
 	/* PCI hardware resources */
 	unsigned long io;
-	unsigned long __iomem *mmio;
+	void __iomem *mmio;
 	unsigned int irq;
 	spinlock_t lock;
 
@@ -201,14 +201,14 @@
 				     int count);
 static void vortex_adbdma_setmode(vortex_t * vortex, int adbdma, int ie,
 				  int dir, int fmt, int d,
-				  unsigned long offset);
+				  u32 offset);
 static void vortex_adbdma_setstartbuffer(vortex_t * vortex, int adbdma, int sb);
 #ifndef CHIP_AU8810
 static void vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma,
 				    struct snd_sg_buf * sgbuf, int size,
 				    int count);
 static void vortex_wtdma_setmode(vortex_t * vortex, int wtdma, int ie, int fmt, int d,	/*int e, */
-				 unsigned long offset);
+				 u32 offset);
 static void vortex_wtdma_setstartbuffer(vortex_t * vortex, int wtdma, int sb);
 #endif
 
diff -urN oldtree/sound/pci/au88x0/au88x0_core.c newtree/sound/pci/au88x0/au88x0_core.c
--- oldtree/sound/pci/au88x0/au88x0_core.c	2006-02-19 11:41:06.949286648 +0000
+++ newtree/sound/pci/au88x0/au88x0_core.c	2006-02-21 15:58:11.421410240 +0000
@@ -376,7 +376,7 @@
 
 static void vortex_mixer_init(vortex_t * vortex)
 {
-	unsigned long addr;
+	u32 addr;
 	int x;
 
 	// FIXME: get rid of this crap.
@@ -639,7 +639,7 @@
 
 static void vortex_srcblock_init(vortex_t * vortex)
 {
-	unsigned long addr;
+	u32 addr;
 	int x;
 	hwwrite(vortex->mmio, VORTEX_SRC_SOURCESIZE, 0x1ff);
 	/*
@@ -1035,7 +1035,7 @@
 static void vortex_fifo_init(vortex_t * vortex)
 {
 	int x;
-	unsigned long addr;
+	u32 addr;
 
 	/* ADB DMA channels fifos. */
 	addr = VORTEX_FIFO_ADBCTRL + ((NR_ADB - 1) * 4);
@@ -1054,7 +1054,7 @@
 		hwwrite(vortex->mmio, addr, FIFO_U0);
 		if (hwread(vortex->mmio, addr) != FIFO_U0)
 			printk(KERN_ERR
-			       "bad wt fifo reset (0x%08lx, 0x%08x)!\n",
+			       "bad wt fifo reset (0x%08x, 0x%08x)!\n",
 			       addr, hwread(vortex->mmio, addr));
 		vortex_fifo_clearwtdata(vortex, x, FIFO_SIZE);
 		addr -= 4;
@@ -1152,7 +1152,7 @@
 
 static void
 vortex_adbdma_setmode(vortex_t * vortex, int adbdma, int ie, int dir,
-		      int fmt, int d, unsigned long offset)
+		      int fmt, int d, u32 offset)
 {
 	stream_t *dma = &vortex->dma_adb[adbdma];
 
@@ -1411,7 +1411,7 @@
 
 static void
 vortex_wtdma_setmode(vortex_t * vortex, int wtdma, int ie, int fmt, int d,
-		     /*int e, */ unsigned long offset)
+		     /*int e, */ u32 offset)
 {
 	stream_t *dma = &vortex->dma_wt[wtdma];
 
diff -urN oldtree/sound/pci/au88x0/au88x0_eq.c newtree/sound/pci/au88x0/au88x0_eq.c
--- oldtree/sound/pci/au88x0/au88x0_eq.c	2006-02-19 11:41:06.950286496 +0000
+++ newtree/sound/pci/au88x0/au88x0_eq.c	2006-02-21 15:58:11.423409936 +0000
@@ -377,23 +377,23 @@
 
 #endif
 /* Global Control */
-static void vortex_EqHw_SetControlReg(vortex_t * vortex, unsigned long reg)
+static void vortex_EqHw_SetControlReg(vortex_t * vortex, u32 reg)
 {
 	hwwrite(vortex->mmio, 0x2b440, reg);
 }
 
-static void vortex_EqHw_SetSampleRate(vortex_t * vortex, int sr)
+static void vortex_EqHw_SetSampleRate(vortex_t * vortex, u32 sr)
 {
 	hwwrite(vortex->mmio, 0x2b440, ((sr & 0x1f) << 3) | 0xb800);
 }
 
 #if 0
-static void vortex_EqHw_GetControlReg(vortex_t * vortex, unsigned long *reg)
+static void vortex_EqHw_GetControlReg(vortex_t * vortex, u32 *reg)
 {
 	*reg = hwread(vortex->mmio, 0x2b440);
 }
 
-static void vortex_EqHw_GetSampleRate(vortex_t * vortex, int *sr)
+static void vortex_EqHw_GetSampleRate(vortex_t * vortex, u32 *sr)
 {
 	*sr = (hwread(vortex->mmio, 0x2b440) >> 3) & 0x1f;
 }
@@ -554,7 +554,7 @@
 
 #if 0
 static int
-vortex_Eqlzr_GetAllBands(vortex_t * vortex, u16 * gains, unsigned long *cnt)
+vortex_Eqlzr_GetAllBands(vortex_t * vortex, u16 * gains, s32 *cnt)
 {
 	eqlzr_t *eq = &(vortex->eq);
 	int si = 0;
@@ -586,7 +586,7 @@
 }
 
 static int
-vortex_Eqlzr_SetAllBands(vortex_t * vortex, u16 gains[], unsigned long count)
+vortex_Eqlzr_SetAllBands(vortex_t * vortex, u16 gains[], s32 count)
 {
 	eqlzr_t *eq = &(vortex->eq);
 	int i;
@@ -604,11 +604,10 @@
 }
 
 static void
-vortex_Eqlzr_SetA3dBypassGain(vortex_t * vortex, unsigned long a,
-			      unsigned long b)
+vortex_Eqlzr_SetA3dBypassGain(vortex_t * vortex, u32 a, u32 b)
 {
 	eqlzr_t *eq = &(vortex->eq);
-	int eax, ebx;
+	u32 eax, ebx;
 
 	eq->this58 = a;
 	eq->this5c = b;
@@ -624,7 +623,7 @@
 static void vortex_Eqlzr_ProgramA3dBypassGain(vortex_t * vortex)
 {
 	eqlzr_t *eq = &(vortex->eq);
-	int eax, ebx;
+	u32 eax, ebx;
 
 	if (eq->this54)
 		eax = eq->this0e;
@@ -641,7 +640,7 @@
 		vortex_EqHw_ZeroA3DIO(vortex);
 }
 
-static void vortex_Eqlzr_SetBypass(vortex_t * vortex, long bp)
+static void vortex_Eqlzr_SetBypass(vortex_t * vortex, u32 bp)
 {
 	eqlzr_t *eq = &(vortex->eq);
 	
@@ -651,8 +650,8 @@
 		vortex_EqHw_SetBypassGain(vortex, eq->this08, eq->this08);
 	} else {
 		/* EQ disabled. */
-		vortex_EqHw_SetLeftGainsTarget(vortex, (u16 *) (eq->this14));
-		vortex_EqHw_SetRightGainsTarget(vortex, (u16 *) (eq->this14));
+		vortex_EqHw_SetLeftGainsTarget(vortex, eq->this14_array);
+		vortex_EqHw_SetRightGainsTarget(vortex, eq->this14_array);
 		vortex_EqHw_SetBypassGain(vortex, eq->this0c, eq->this0c);
 	}
 	vortex_Eqlzr_ProgramA3dBypassGain(vortex);
@@ -706,7 +705,7 @@
 	eq->this5c = 0xffff;
 
 	/* Set gains. */
-	memset(eq->this14, 0, 2 * 10);
+	memset(eq->this14_array, 0, sizeof(eq->this14_array));
 
 	/* Actual init. */
 	vortex_EqHw_ZeroState(vortex);
@@ -792,7 +791,7 @@
 {
 	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
 	int i = kcontrol->private_value;
-	u16 gainL, gainR;
+	u16 gainL = 0, gainR = 0;
 
 	vortex_Eqlzr_GetLeftGain(vortex, i, &gainL);
 	vortex_Eqlzr_GetRightGain(vortex, i, &gainR);
@@ -806,7 +805,7 @@
 {
 	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
 	int changed = 0, i = kcontrol->private_value;
-	u16 gainL, gainR;
+	u16 gainL = 0, gainR = 0;
 
 	vortex_Eqlzr_GetLeftGain(vortex, i, &gainL);
 	vortex_Eqlzr_GetRightGain(vortex, i, &gainR);
diff -urN oldtree/sound/pci/au88x0/au88x0_eq.h newtree/sound/pci/au88x0/au88x0_eq.h
--- oldtree/sound/pci/au88x0/au88x0_eq.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/pci/au88x0/au88x0_eq.h	2006-02-21 15:58:11.423409936 +0000
@@ -13,31 +13,28 @@
 typedef struct {
 	u16 LeftCoefs[50];	//0x4
 	u16 RightCoefs[50];	// 0x68
-	u16 LeftGains[20];	//0xd0
-	u16 RightGains[20];	//0xe4
+	u16 LeftGains[10];	//0xd0
+	u16 RightGains[10];	//0xe4
 } auxxEqCoeffSet_t;
 
 typedef struct {
-	unsigned int *this00;	/*CAsp4HwIO */
-	long this04;		/* How many filters for each side (default = 10) */
-	long this08;		/* inited to cero. Stereo flag? */
+	s32 this04;		/* How many filters for each side (default = 10) */
+	s32 this08;		/* inited to cero. Stereo flag? */
 } eqhw_t;
 
 typedef struct {
-	unsigned int *this00;	/*CAsp4Core */
 	eqhw_t this04;		/* CHwEq */
-	short this08;		/* Bad codec flag ? SetBypassGain: bypass gain */
-	short this0a;
-	short this0c;		/* SetBypassGain: bypass gain when this28 is not set. */
-	short this0e;
+	u16 this08;		/* Bad codec flag ? SetBypassGain: bypass gain */
+	u16 this0a;
+	u16 this0c;		/* SetBypassGain: bypass gain when this28 is not set. */
+	u16 this0e;
 
-	long this10;		/* How many gains are used for each side (right or left). */
-	u16 this14[32];		/* SetLeftGainsTarget: Left (and right?) EQ gains  */
-	long this24;
-	long this28;		/* flag related to EQ enabled or not. Gang flag ? */
-	long this54;		/* SetBypass */
-	long this58;
-	long this5c;
+	s32 this10;		/* How many gains are used for each side (right or left). */
+	u16 this14_array[10];	/* SetLeftGainsTarget: Left (and right?) EQ gains  */
+	s32 this28;		/* flag related to EQ enabled or not. Gang flag ? */
+	s32 this54;		/* SetBypass */
+	s32 this58;
+	s32 this5c;
 	/*0x60 */ auxxEqCoeffSet_t coefset;
 	/* 50 u16 word each channel. */
 	u16 this130[20];	/* Left and Right gains */
diff -urN oldtree/sound/pci/au88x0/au88x0_eqdata.c newtree/sound/pci/au88x0/au88x0_eqdata.c
--- oldtree/sound/pci/au88x0/au88x0_eqdata.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/pci/au88x0/au88x0_eqdata.c	2006-02-21 15:58:11.423409936 +0000
@@ -104,7 +104,11 @@
 };
 
 /*_rodataba0:*/
-static long eq_levels[32] = {
+static u16 eq_levels[64] = {
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
diff -urN oldtree/sound/pci/au88x0/au88x0_mpu401.c newtree/sound/pci/au88x0/au88x0_mpu401.c
--- oldtree/sound/pci/au88x0/au88x0_mpu401.c	2006-02-19 11:41:06.951286344 +0000
+++ newtree/sound/pci/au88x0/au88x0_mpu401.c	2006-02-21 15:58:11.424409784 +0000
@@ -95,7 +95,7 @@
 		return temp;
 	}
 #else
-	port = (unsigned long)(vortex->mmio + (VORTEX_MIDI_DATA >> 2));
+	port = (unsigned long)(vortex->mmio + VORTEX_MIDI_DATA);
 	if ((temp =
 	     snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port,
 				 1, 0, 0, &rmidi)) != 0) {
@@ -105,7 +105,7 @@
 		return temp;
 	}
 	mpu = rmidi->private_data;
-	mpu->cport = (unsigned long)(vortex->mmio + (VORTEX_MIDI_CMD >> 2));
+	mpu->cport = (unsigned long)(vortex->mmio + VORTEX_MIDI_CMD);
 #endif
 	vortex->rmidi = rmidi;
 	return 0;
diff -urN oldtree/sound/pci/au88x0/au88x0_synth.c newtree/sound/pci/au88x0/au88x0_synth.c
--- oldtree/sound/pci/au88x0/au88x0_synth.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/pci/au88x0/au88x0_synth.c	2006-02-21 15:58:11.425409632 +0000
@@ -32,7 +32,7 @@
 					unsigned char mix, int a);
 static void vortex_fifo_wtinitialize(vortex_t * vortex, int fifo, int j);
 static int vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
-			    unsigned long val);
+			    u32 val);
 
 /* WT */
 
@@ -166,7 +166,7 @@
 /* WT hardware abstraction layer generic register interface. */
 static int
 vortex_wt_SetReg2(vortex_t * vortex, unsigned char reg, int wt,
-		  unsigned short val)
+		  u16 val)
 {
 	/*
 	   int eax, edx;
@@ -190,7 +190,7 @@
 #endif
 static int
 vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
-		 unsigned long val)
+		 u32 val)
 {
 	int ecx;
 
@@ -279,7 +279,7 @@
 
 static void vortex_wt_init(vortex_t * vortex)
 {
-	int var4, var8, varc, var10 = 0, edi;
+	u32 var4, var8, varc, var10 = 0, edi;
 
 	var10 &= 0xFFFFFFE3;
 	var10 |= 0x22;
@@ -353,7 +353,7 @@
 static void vortex_wt_SetFrequency(vortex_t * vortex, int wt, unsigned int sr)
 {
 	wt_voice_t *voice = &(vortex->wt_voice[wt]);
-	long int eax, edx;
+	u32 eax, edx;
 
 	//FIXME: 64 bit operation.
 	eax = ((sr << 0xf) * 0x57619F1) & 0xffffffff;
diff -urN oldtree/sound/pci/au88x0/au88x0_wt.h newtree/sound/pci/au88x0/au88x0_wt.h
--- oldtree/sound/pci/au88x0/au88x0_wt.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/pci/au88x0/au88x0_wt.h	2006-02-21 15:58:11.425409632 +0000
@@ -53,11 +53,11 @@
 #endif
 
 typedef struct {
-	unsigned int parm0;	/* this_1E4 */
-	unsigned int parm1;	/* this_1E8 */
-	unsigned int parm2;	/* this_1EC */
-	unsigned int parm3;	/* this_1F0 */
-	unsigned int this_1D0;
+	u32 parm0;	/* this_1E4 */
+	u32 parm1;	/* this_1E8 */
+	u32 parm2;	/* this_1EC */
+	u32 parm3;	/* this_1F0 */
+	u32 this_1D0;
 } wt_voice_t;
 
 #endif				/* _AU88X0_WT_H */
diff -urN oldtree/sound/pci/au88x0/au88x0_xtalk.c newtree/sound/pci/au88x0/au88x0_xtalk.c
--- oldtree/sound/pci/au88x0/au88x0_xtalk.c	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/pci/au88x0/au88x0_xtalk.c	2006-02-21 15:58:11.426409480 +0000
@@ -562,7 +562,7 @@
 vortex_XtalkHw_SetDelay(vortex_t * vortex, unsigned short right,
 			unsigned short left)
 {
-	int esp0 = 0;
+	u32 esp0 = 0;
 
 	esp0 &= 0x1FFFFFFF;
 	esp0 |= 0xA0000000;
@@ -632,18 +632,18 @@
 /* Control/Global stuff */
 
 #if 0
-static void vortex_XtalkHw_SetControlReg(vortex_t * vortex, unsigned long ctrl)
+static void vortex_XtalkHw_SetControlReg(vortex_t * vortex, u32 ctrl)
 {
 	hwwrite(vortex->mmio, 0x24660, ctrl);
 }
-static void vortex_XtalkHw_GetControlReg(vortex_t * vortex, unsigned long *ctrl)
+static void vortex_XtalkHw_GetControlReg(vortex_t * vortex, u32 *ctrl)
 {
 	*ctrl = hwread(vortex->mmio, 0x24660);
 }
 #endif
-static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, int sr)
+static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, u32 sr)
 {
-	int temp;
+	u32 temp;
 
 	temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000;
 	temp = (temp & 0xffffff07) | ((sr & 0x1f) << 3);
@@ -651,7 +651,7 @@
 }
 
 #if 0
-static void vortex_XtalkHw_GetSampleRate(vortex_t * vortex, int *sr)
+static void vortex_XtalkHw_GetSampleRate(vortex_t * vortex, u32 *sr)
 {
 	*sr = (hwread(vortex->mmio, 0x24660) >> 3) & 0x1f;
 }
@@ -659,7 +659,7 @@
 #endif
 static void vortex_XtalkHw_Enable(vortex_t * vortex)
 {
-	int temp;
+	u32 temp;
 
 	temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000;
 	temp |= 1;
@@ -669,7 +669,7 @@
 
 static void vortex_XtalkHw_Disable(vortex_t * vortex)
 {
-	int temp;
+	u32 temp;
 
 	temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000;
 	temp &= 0xfffffffe;
diff -urN oldtree/sound/pci/au88x0/au88x0_xtalk.h newtree/sound/pci/au88x0/au88x0_xtalk.h
--- oldtree/sound/pci/au88x0/au88x0_xtalk.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/pci/au88x0/au88x0_xtalk.h	2006-02-21 15:58:11.426409480 +0000
@@ -39,16 +39,16 @@
 #define XT_SPEAKER1		3
 #define XT_DIAMOND		4
 
-typedef long xtalk_dline_t[XTDLINE_SZ];
-typedef short xtalk_gains_t[XTGAINS_SZ];
-typedef short xtalk_instate_t[XTINST_SZ];
-typedef short xtalk_coefs_t[5][5];
-typedef short xtalk_state_t[5][4];
+typedef u32 xtalk_dline_t[XTDLINE_SZ];
+typedef u16 xtalk_gains_t[XTGAINS_SZ];
+typedef u16 xtalk_instate_t[XTINST_SZ];
+typedef u16 xtalk_coefs_t[5][5];
+typedef u16 xtalk_state_t[5][4];
 
 static void vortex_XtalkHw_SetGains(vortex_t * vortex,
 				    xtalk_gains_t const gains);
 static void vortex_XtalkHw_SetGainsAllChan(vortex_t * vortex);
-static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, int sr);
+static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, u32 sr);
 static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex);
 static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex);
 static void vortex_XtalkHw_ProgramXtalkWide(vortex_t * vortex);
diff -urN oldtree/sound/pci/cmipci.c newtree/sound/pci/cmipci.c
--- oldtree/sound/pci/cmipci.c	2006-02-19 11:41:06.987280872 +0000
+++ newtree/sound/pci/cmipci.c	2006-02-21 15:58:11.431408720 +0000
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/gameport.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -439,7 +440,7 @@
 	struct snd_pcm_hardware *hw_info[3]; /* for playbacks */
 
 	int opened[2];	/* open mode */
-	struct semaphore open_mutex;
+	struct mutex open_mutex;
 
 	unsigned int mixer_insensitive: 1;
 	struct snd_kcontrol *mixer_res_ctl[CM_SAVED_MIXERS];
@@ -641,14 +642,14 @@
 {
 	struct cmipci *cm = snd_pcm_substream_chip(substream);
 	if (params_channels(hw_params) > 2) {
-		down(&cm->open_mutex);
+		mutex_lock(&cm->open_mutex);
 		if (cm->opened[CM_CH_PLAY]) {
-			up(&cm->open_mutex);
+			mutex_unlock(&cm->open_mutex);
 			return -EBUSY;
 		}
 		/* reserve the channel A */
 		cm->opened[CM_CH_PLAY] = CM_OPEN_PLAYBACK_MULTI;
-		up(&cm->open_mutex);
+		mutex_unlock(&cm->open_mutex);
 	}
 	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
 }
@@ -1461,9 +1462,9 @@
 	 * pcm framework doesn't pass file pointer before actually opened,
 	 * we can't know whether blocking mode or not in open callback..
 	 */
-	down(&cm->open_mutex);
+	mutex_lock(&cm->open_mutex);
 	if (cm->opened[ch]) {
-		up(&cm->open_mutex);
+		mutex_unlock(&cm->open_mutex);
 		return -EBUSY;
 	}
 	cm->opened[ch] = mode;
@@ -1475,7 +1476,7 @@
 		snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_ENDBDAC);
 		spin_unlock_irq(&cm->reg_lock);
 	}
-	up(&cm->open_mutex);
+	mutex_unlock(&cm->open_mutex);
 	return 0;
 }
 
@@ -1483,7 +1484,7 @@
 {
 	int ch = mode & CM_OPEN_CH_MASK;
 
-	down(&cm->open_mutex);
+	mutex_lock(&cm->open_mutex);
 	if (cm->opened[ch] == mode) {
 		if (cm->channel[ch].substream) {
 			snd_cmipci_ch_reset(cm, ch);
@@ -1499,7 +1500,7 @@
 			spin_unlock_irq(&cm->reg_lock);
 		}
 	}
-	up(&cm->open_mutex);
+	mutex_unlock(&cm->open_mutex);
 }
 
 /*
@@ -1546,7 +1547,7 @@
 	if ((err = open_device_check(cm, CM_OPEN_PLAYBACK2, substream)) < 0) /* use channel B */
 		return err;
 	runtime->hw = snd_cmipci_playback2;
-	down(&cm->open_mutex);
+	mutex_lock(&cm->open_mutex);
 	if (! cm->opened[CM_CH_PLAY]) {
 		if (cm->can_multi_ch) {
 			runtime->hw.channels_max = cm->max_channels;
@@ -1559,7 +1560,7 @@
 		}
 		snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000);
 	}
-	up(&cm->open_mutex);
+	mutex_unlock(&cm->open_mutex);
 	return 0;
 }
 
@@ -2844,7 +2845,7 @@
 	}
 
 	spin_lock_init(&cm->reg_lock);
-	init_MUTEX(&cm->open_mutex);
+	mutex_init(&cm->open_mutex);
 	cm->device = pci->device;
 	cm->card = card;
 	cm->pci = pci;
diff -urN oldtree/sound/pci/cs46xx/cs46xx_lib.c newtree/sound/pci/cs46xx/cs46xx_lib.c
--- oldtree/sound/pci/cs46xx/cs46xx_lib.c	2006-02-19 11:41:06.994279808 +0000
+++ newtree/sound/pci/cs46xx/cs46xx_lib.c	2006-02-21 15:58:11.434408264 +0000
@@ -53,6 +53,8 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/gameport.h>
+#include <linux/mutex.h>
+
 
 #include <sound/core.h>
 #include <sound/control.h>
@@ -909,22 +911,22 @@
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
 	snd_assert (sample_rate != 0, return -ENXIO);
 
-	down (&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 
 	if (_cs46xx_adjust_sample_rate (chip,cpcm,sample_rate)) {
-		up (&chip->spos_mutex);
+		mutex_unlock(&chip->spos_mutex);
 		return -ENXIO;
 	}
 
 	snd_assert (cpcm->pcm_channel != NULL);
 	if (!cpcm->pcm_channel) {
-		up (&chip->spos_mutex);
+		mutex_unlock(&chip->spos_mutex);
 		return -ENXIO;
 	}
 
 
 	if (cs46xx_dsp_pcm_channel_set_period (chip,cpcm->pcm_channel,period_size)) {
-		 up (&chip->spos_mutex);
+		 mutex_unlock(&chip->spos_mutex);
 		 return -EINVAL;
 	 }
 
@@ -965,7 +967,7 @@
 		}
 		if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) {
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-			up (&chip->spos_mutex);
+			mutex_unlock(&chip->spos_mutex);
 #endif
 			return err;
 		}
@@ -989,7 +991,7 @@
 	}
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-	up (&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 #endif
 
 	return 0;
@@ -1319,7 +1321,7 @@
 
 	cpcm->substream = substream;
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-	down (&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	cpcm->pcm_channel = NULL; 
 	cpcm->pcm_channel_id = pcm_channel_id;
 
@@ -1328,7 +1330,7 @@
 				   SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 
 				   &hw_constraints_period_sizes);
 
-	up (&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 #else
 	chip->playback_pcm = cpcm; /* HACK */
 #endif
@@ -1367,9 +1369,9 @@
 
 	snd_printdd("open raw iec958 channel\n");
 
-	down (&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	cs46xx_iec958_pre_open (chip);
-	up (&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return _cs46xx_playback_open_channel(substream,DSP_IEC958_CHANNEL);
 }
@@ -1385,9 +1387,9 @@
 
 	err = snd_cs46xx_playback_close(substream);
 
-	down (&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	cs46xx_iec958_post_close (chip);
-	up (&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return err;
 }
@@ -1428,12 +1430,12 @@
 	if (!cpcm) return -ENXIO;
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-	down (&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	if (cpcm->pcm_channel) {
 		cs46xx_dsp_destroy_pcm_channel(chip,cpcm->pcm_channel);
 		cpcm->pcm_channel = NULL;
 	}
-	up (&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 #else
 	chip->playback_pcm = NULL;
 #endif
@@ -1848,7 +1850,7 @@
 
 	switch (kcontrol->private_value) {
 	case CS46XX_MIXER_SPDIF_OUTPUT_ELEMENT:
-		down (&chip->spos_mutex);
+		mutex_lock(&chip->spos_mutex);
 		change = (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED);
 		if (ucontrol->value.integer.value[0] && !change) 
 			cs46xx_dsp_enable_spdif_out(chip);
@@ -1856,7 +1858,7 @@
 			cs46xx_dsp_disable_spdif_out(chip);
 
 		res = (change != (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED));
-		up (&chip->spos_mutex);
+		mutex_unlock(&chip->spos_mutex);
 		break;
 	case CS46XX_MIXER_SPDIF_INPUT_ELEMENT:
 		change = chip->dsp_spos_instance->spdif_status_in;
@@ -1997,12 +1999,12 @@
 	struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol);
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-	down (&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	ucontrol->value.iec958.status[0] = _wrap_all_bits((ins->spdif_csuv_default >> 24) & 0xff);
 	ucontrol->value.iec958.status[1] = _wrap_all_bits((ins->spdif_csuv_default >> 16) & 0xff);
 	ucontrol->value.iec958.status[2] = 0;
 	ucontrol->value.iec958.status[3] = _wrap_all_bits((ins->spdif_csuv_default) & 0xff);
-	up (&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
@@ -2015,7 +2017,7 @@
 	unsigned int val;
 	int change;
 
-	down (&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	val = ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[0]) << 24) |
 		((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[2]) << 16) |
 		((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[3]))  |
@@ -2029,7 +2031,7 @@
 	if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) )
 		cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV,val);
 
-	up (&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return change;
 }
@@ -2050,12 +2052,12 @@
 	struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol);
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-	down (&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	ucontrol->value.iec958.status[0] = _wrap_all_bits((ins->spdif_csuv_stream >> 24) & 0xff);
 	ucontrol->value.iec958.status[1] = _wrap_all_bits((ins->spdif_csuv_stream >> 16) & 0xff);
 	ucontrol->value.iec958.status[2] = 0;
 	ucontrol->value.iec958.status[3] = _wrap_all_bits((ins->spdif_csuv_stream) & 0xff);
-	up (&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
@@ -2068,7 +2070,7 @@
 	unsigned int val;
 	int change;
 
-	down (&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	val = ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[0]) << 24) |
 		((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[1]) << 16) |
 		((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[3])) |
@@ -2082,7 +2084,7 @@
 	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN )
 		cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV,val);
 
-	up (&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return change;
 }
@@ -3755,7 +3757,7 @@
 	}
 	spin_lock_init(&chip->reg_lock);
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-	init_MUTEX(&chip->spos_mutex);
+	mutex_init(&chip->spos_mutex);
 #endif
 	chip->card = card;
 	chip->pci = pci;
diff -urN oldtree/sound/pci/cs46xx/dsp_spos.c newtree/sound/pci/cs46xx/dsp_spos.c
--- oldtree/sound/pci/cs46xx/dsp_spos.c	2006-02-19 11:41:06.997279352 +0000
+++ newtree/sound/pci/cs46xx/dsp_spos.c	2006-02-21 15:58:11.436407960 +0000
@@ -28,6 +28,8 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/info.h>
@@ -287,7 +289,7 @@
 
 	snd_assert(ins != NULL, return);
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	for (i = 0; i < ins->nscb; ++i) {
 		if (ins->scbs[i].deleted) continue;
 
@@ -298,7 +300,7 @@
 	vfree(ins->symbol_table.symbols);
 	kfree(ins->modules);
 	kfree(ins);
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 }
 
 int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module)
@@ -497,7 +499,7 @@
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 	int i,j;
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	snd_iprintf(buffer, "MODULES:\n");
 	for ( i = 0; i < ins->nmodules; ++i ) {
 		snd_iprintf(buffer, "\n%s:\n", ins->modules[i].module_name);
@@ -510,7 +512,7 @@
 				    desc->segment_type,desc->offset, desc->size);
 		}
 	}
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 }
 
 static void cs46xx_dsp_proc_task_tree_read (struct snd_info_entry *entry,
@@ -521,7 +523,7 @@
 	int i, j, col;
 	void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	snd_iprintf(buffer, "TASK TREES:\n");
 	for ( i = 0; i < ins->ntask; ++i) {
 		snd_iprintf(buffer,"\n%04x %s:\n",ins->tasks[i].address,ins->tasks[i].task_name);
@@ -538,7 +540,7 @@
 	}
 
 	snd_iprintf(buffer,"\n");  
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 }
 
 static void cs46xx_dsp_proc_scb_read (struct snd_info_entry *entry,
@@ -548,7 +550,7 @@
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 	int i;
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	snd_iprintf(buffer, "SCB's:\n");
 	for ( i = 0; i < ins->nscb; ++i) {
 		if (ins->scbs[i].deleted)
@@ -571,7 +573,7 @@
 	}
 
 	snd_iprintf(buffer,"\n");
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 }
 
 static void cs46xx_dsp_proc_parameter_dump_read (struct snd_info_entry *entry,
@@ -852,14 +854,14 @@
 	}
 	ins->proc_scb_info_entry = entry;
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	/* register/update SCB's entries on proc */
 	for (i = 0; i < ins->nscb; ++i) {
 		if (ins->scbs[i].deleted) continue;
 
 		cs46xx_dsp_proc_register_scb_desc (chip, (ins->scbs + i));
 	}
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
@@ -899,12 +901,12 @@
 		ins->proc_task_info_entry = NULL;
 	}
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	for (i = 0; i < ins->nscb; ++i) {
 		if (ins->scbs[i].deleted) continue;
 		cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
 	}
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	if (ins->proc_dsp_dir) {
 		snd_info_unregister (ins->proc_dsp_dir);
@@ -1694,7 +1696,7 @@
 	snd_assert (ins->asynch_rx_scb == NULL,return -EINVAL);
 	snd_assert (ins->spdif_in_src != NULL,return -EINVAL);
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 
 	if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_INPUT_CTRL_ENABLED) ) {
 		/* time countdown enable */
@@ -1738,7 +1740,7 @@
 
 	/* monitor state */
 	ins->spdif_status_in = 1;
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
@@ -1750,7 +1752,7 @@
 	snd_assert (ins->asynch_rx_scb != NULL, return -EINVAL);
 	snd_assert (ins->spdif_in_src != NULL,return -EINVAL);	
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 
 	/* Remove the asynchronous receiver SCB */
 	cs46xx_dsp_remove_scb (chip,ins->asynch_rx_scb);
@@ -1760,7 +1762,7 @@
 
 	/* monitor state */
 	ins->spdif_status_in = 0;
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	/* restore amplifier */
 	chip->active_ctrl(chip, -1);
@@ -1776,10 +1778,10 @@
 	snd_assert (ins->pcm_input == NULL,return -EINVAL);
 	snd_assert (ins->ref_snoop_scb != NULL,return -EINVAL);
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	ins->pcm_input = cs46xx_add_record_source(chip,ins->ref_snoop_scb,PCMSERIALIN_PCM_SCB_ADDR,
                                                   "PCMSerialInput_Wave");
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
@@ -1790,10 +1792,10 @@
 
 	snd_assert (ins->pcm_input != NULL,return -EINVAL);
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	cs46xx_dsp_remove_scb (chip,ins->pcm_input);
 	ins->pcm_input = NULL;
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
@@ -1805,10 +1807,10 @@
 	snd_assert (ins->adc_input == NULL,return -EINVAL);
 	snd_assert (ins->codec_in_scb != NULL,return -EINVAL);
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	ins->adc_input = cs46xx_add_record_source(chip,ins->codec_in_scb,PCMSERIALIN_SCB_ADDR,
 						  "PCMSerialInput_ADC");
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
@@ -1819,10 +1821,10 @@
 
 	snd_assert (ins->adc_input != NULL,return -EINVAL);
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	cs46xx_dsp_remove_scb (chip,ins->adc_input);
 	ins->adc_input = NULL;
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
@@ -1869,7 +1871,7 @@
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 	struct dsp_scb_descriptor * scb; 
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	
 	/* main output */
 	scb = ins->master_mix_scb->sub_list_ptr;
@@ -1888,7 +1890,7 @@
 	ins->dac_volume_left = left;
 	ins->dac_volume_right = right;
 
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
@@ -1897,7 +1899,7 @@
 {
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 
 	if (ins->asynch_rx_scb != NULL)
 		cs46xx_dsp_scb_set_volume (chip,ins->asynch_rx_scb,
@@ -1906,7 +1908,7 @@
 	ins->spdif_input_volume_left = left;
 	ins->spdif_input_volume_right = right;
 
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
diff -urN oldtree/sound/pci/cs46xx/dsp_spos_scb_lib.c newtree/sound/pci/cs46xx/dsp_spos_scb_lib.c
--- oldtree/sound/pci/cs46xx/dsp_spos_scb_lib.c	2006-02-19 11:41:07.000278896 +0000
+++ newtree/sound/pci/cs46xx/dsp_spos_scb_lib.c	2006-02-21 15:58:11.437407808 +0000
@@ -28,6 +28,8 @@
 #include <linux/pm.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/info.h>
@@ -77,7 +79,7 @@
 
 	ins = chip->dsp_spos_instance;
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
 
 	for (col = 0,j = 0;j < 0x10; j++,col++) {
@@ -105,7 +107,7 @@
 		    scb->task_entry->address);
 
 	snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count);  
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 }
 #endif
 
diff -urN oldtree/sound/pci/emu10k1/emu10k1_main.c newtree/sound/pci/emu10k1/emu10k1_main.c
--- oldtree/sound/pci/emu10k1/emu10k1_main.c	2006-02-19 11:41:07.009277528 +0000
+++ newtree/sound/pci/emu10k1/emu10k1_main.c	2006-02-21 15:58:11.440407352 +0000
@@ -36,6 +36,8 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/mutex.h>
+
 
 #include <sound/core.h>
 #include <sound/emu10k1.h>
@@ -1097,8 +1099,7 @@
 	spin_lock_init(&emu->voice_lock);
 	spin_lock_init(&emu->synth_lock);
 	spin_lock_init(&emu->memblk_lock);
-	init_MUTEX(&emu->ptb_lock);
-	init_MUTEX(&emu->fx8010.lock);
+	mutex_init(&emu->fx8010.lock);
 	INIT_LIST_HEAD(&emu->mapped_link_head);
 	INIT_LIST_HEAD(&emu->mapped_order_link_head);
 	emu->pci = pci;
diff -urN oldtree/sound/pci/emu10k1/emufx.c newtree/sound/pci/emu10k1/emufx.c
--- oldtree/sound/pci/emu10k1/emufx.c	2006-02-19 11:41:07.016276464 +0000
+++ newtree/sound/pci/emu10k1/emufx.c	2006-02-21 15:58:11.444406744 +0000
@@ -32,6 +32,8 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/emu10k1.h>
 
@@ -874,7 +876,7 @@
 {
 	int err = 0;
 
-	down(&emu->fx8010.lock);
+	mutex_lock(&emu->fx8010.lock);
 	if ((err = snd_emu10k1_verify_controls(emu, icode)) < 0)
 		goto __error;
 	strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name));
@@ -897,7 +899,7 @@
 	else
 		snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
       __error:
-	up(&emu->fx8010.lock);
+	mutex_unlock(&emu->fx8010.lock);
 	return err;
 }
 
@@ -906,7 +908,7 @@
 {
 	int err;
 
-	down(&emu->fx8010.lock);
+	mutex_lock(&emu->fx8010.lock);
 	strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name));
 	/* ok, do the main job */
 	err = snd_emu10k1_gpr_peek(emu, icode);
@@ -916,7 +918,7 @@
 		err = snd_emu10k1_code_peek(emu, icode);
 	if (err >= 0)
 		err = snd_emu10k1_list_controls(emu, icode);
-	up(&emu->fx8010.lock);
+	mutex_unlock(&emu->fx8010.lock);
 	return err;
 }
 
@@ -932,7 +934,7 @@
 	if (ipcm->channels > 32)
 		return -EINVAL;
 	pcm = &emu->fx8010.pcm[ipcm->substream];
-	down(&emu->fx8010.lock);
+	mutex_lock(&emu->fx8010.lock);
 	spin_lock_irq(&emu->reg_lock);
 	if (pcm->opened) {
 		err = -EBUSY;
@@ -962,7 +964,7 @@
 	}
       __error:
 	spin_unlock_irq(&emu->reg_lock);
-	up(&emu->fx8010.lock);
+	mutex_unlock(&emu->fx8010.lock);
 	return err;
 }
 
@@ -976,7 +978,7 @@
 	if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
 		return -EINVAL;
 	pcm = &emu->fx8010.pcm[ipcm->substream];
-	down(&emu->fx8010.lock);
+	mutex_lock(&emu->fx8010.lock);
 	spin_lock_irq(&emu->reg_lock);
 	ipcm->channels = pcm->channels;
 	ipcm->tram_start = pcm->tram_start;
@@ -992,7 +994,7 @@
 	ipcm->res1 = ipcm->res2 = 0;
 	ipcm->pad = 0;
 	spin_unlock_irq(&emu->reg_lock);
-	up(&emu->fx8010.lock);
+	mutex_unlock(&emu->fx8010.lock);
 	return err;
 }
 
@@ -2308,9 +2310,9 @@
 			return -EPERM;
 		if (get_user(addr, (unsigned int __user *)argp))
 			return -EFAULT;
-		down(&emu->fx8010.lock);
+		mutex_lock(&emu->fx8010.lock);
 		res = snd_emu10k1_fx8010_tram_setup(emu, addr);
-		up(&emu->fx8010.lock);
+		mutex_unlock(&emu->fx8010.lock);
 		return res;
 	case SNDRV_EMU10K1_IOCTL_STOP:
 		if (!capable(CAP_SYS_ADMIN))
diff -urN oldtree/sound/pci/emu10k1/memory.c newtree/sound/pci/emu10k1/memory.c
--- oldtree/sound/pci/emu10k1/memory.c	2006-02-19 11:41:07.024275248 +0000
+++ newtree/sound/pci/emu10k1/memory.c	2006-02-21 15:58:11.446406440 +0000
@@ -24,6 +24,8 @@
 #include <sound/driver.h>
 #include <linux/pci.h>
 #include <linux/time.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/emu10k1.h>
 
@@ -302,10 +304,10 @@
 	hdr = emu->memhdr;
 	snd_assert(hdr, return NULL);
 
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	blk = search_empty(emu, runtime->dma_bytes);
 	if (blk == NULL) {
-		up(&hdr->block_mutex);
+		mutex_unlock(&hdr->block_mutex);
 		return NULL;
 	}
 	/* fill buffer addresses but pointers are not stored so that
@@ -318,14 +320,14 @@
 		if (idx >= sgbuf->pages) {
 			printk(KERN_ERR "emu: pages overflow! (%d-%d) for %d\n",
 			       blk->first_page, blk->last_page, sgbuf->pages);
-			up(&hdr->block_mutex);
+			mutex_unlock(&hdr->block_mutex);
 			return NULL;
 		}
 #endif
 		addr = sgbuf->table[idx].addr;
 		if (! is_valid_page(emu, addr)) {
 			printk(KERN_ERR "emu: failure page = %d\n", idx);
-			up(&hdr->block_mutex);
+			mutex_unlock(&hdr->block_mutex);
 			return NULL;
 		}
 		emu->page_addr_table[page] = addr;
@@ -337,10 +339,10 @@
 	err = snd_emu10k1_memblk_map(emu, blk);
 	if (err < 0) {
 		__snd_util_mem_free(hdr, (struct snd_util_memblk *)blk);
-		up(&hdr->block_mutex);
+		mutex_unlock(&hdr->block_mutex);
 		return NULL;
 	}
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return (struct snd_util_memblk *)blk;
 }
 
@@ -369,19 +371,19 @@
 	struct snd_emu10k1_memblk *blk;
 	struct snd_util_memhdr *hdr = hw->memhdr; 
 
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	blk = (struct snd_emu10k1_memblk *)__snd_util_mem_alloc(hdr, size);
 	if (blk == NULL) {
-		up(&hdr->block_mutex);
+		mutex_unlock(&hdr->block_mutex);
 		return NULL;
 	}
 	if (synth_alloc_pages(hw, blk)) {
 		__snd_util_mem_free(hdr, (struct snd_util_memblk *)blk);
-		up(&hdr->block_mutex);
+		mutex_unlock(&hdr->block_mutex);
 		return NULL;
 	}
 	snd_emu10k1_memblk_map(hw, blk);
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return (struct snd_util_memblk *)blk;
 }
 
@@ -396,14 +398,14 @@
 	struct snd_emu10k1_memblk *blk = (struct snd_emu10k1_memblk *)memblk;
 	unsigned long flags;
 
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	spin_lock_irqsave(&emu->memblk_lock, flags);
 	if (blk->mapped_page >= 0)
 		unmap_memblk(emu, blk);
 	spin_unlock_irqrestore(&emu->memblk_lock, flags);
 	synth_free_pages(emu, blk);
 	 __snd_util_mem_free(hdr, memblk);
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return 0;
 }
 
diff -urN oldtree/sound/pci/ens1370.c newtree/sound/pci/ens1370.c
--- oldtree/sound/pci/ens1370.c	2006-02-19 11:41:07.033273880 +0000
+++ newtree/sound/pci/ens1370.c	2006-02-21 15:58:11.456404920 +0000
@@ -35,6 +35,8 @@
 #include <linux/slab.h>
 #include <linux/gameport.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
@@ -379,7 +381,7 @@
 
 struct ensoniq {
 	spinlock_t reg_lock;
-	struct semaphore src_mutex;
+	struct mutex src_mutex;
 
 	int irq;
 
@@ -609,7 +611,7 @@
 	struct ensoniq *ensoniq = ac97->private_data;
 	unsigned int t, x;
 
-	down(&ensoniq->src_mutex);
+	mutex_lock(&ensoniq->src_mutex);
 	for (t = 0; t < POLL_COUNT; t++) {
 		if (!(inl(ES_REG(ensoniq, 1371_CODEC)) & ES_1371_CODEC_WIP)) {
 			/* save the current state for latter */
@@ -634,11 +636,11 @@
 			/* restore SRC reg */
 			snd_es1371_wait_src_ready(ensoniq);
 			outl(x, ES_REG(ensoniq, 1371_SMPRATE));
-			up(&ensoniq->src_mutex);
+			mutex_unlock(&ensoniq->src_mutex);
 			return;
 		}
 	}
-	up(&ensoniq->src_mutex);
+	mutex_unlock(&ensoniq->src_mutex);
 	snd_printk(KERN_ERR "codec write timeout at 0x%lx [0x%x]\n",
 		   ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC)));
 }
@@ -650,7 +652,7 @@
 	unsigned int t, x, fail = 0;
 
       __again:
-	down(&ensoniq->src_mutex);
+	mutex_lock(&ensoniq->src_mutex);
 	for (t = 0; t < POLL_COUNT; t++) {
 		if (!(inl(ES_REG(ensoniq, 1371_CODEC)) & ES_1371_CODEC_WIP)) {
 			/* save the current state for latter */
@@ -683,11 +685,11 @@
 			/* now wait for the stinkin' data (RDY) */
 			for (t = 0; t < POLL_COUNT; t++) {
 				if ((x = inl(ES_REG(ensoniq, 1371_CODEC))) & ES_1371_CODEC_RDY) {
-					up(&ensoniq->src_mutex);
+					mutex_unlock(&ensoniq->src_mutex);
 					return ES_1371_CODEC_READ(x);
 				}
 			}
-			up(&ensoniq->src_mutex);
+			mutex_unlock(&ensoniq->src_mutex);
 			if (++fail > 10) {
 				snd_printk(KERN_ERR "codec read timeout (final) "
 					   "at 0x%lx, reg = 0x%x [0x%x]\n",
@@ -698,7 +700,7 @@
 			goto __again;
 		}
 	}
-	up(&ensoniq->src_mutex);
+	mutex_unlock(&ensoniq->src_mutex);
 	snd_printk(KERN_ERR "es1371: codec read timeout at 0x%lx [0x%x]\n",
 		   ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC)));
 	return 0;
@@ -717,7 +719,7 @@
 {
 	unsigned int n, truncm, freq, result;
 
-	down(&ensoniq->src_mutex);
+	mutex_lock(&ensoniq->src_mutex);
 	n = rate / 3000;
 	if ((1 << n) & ((1 << 15) | (1 << 13) | (1 << 11) | (1 << 9)))
 		n--;
@@ -742,14 +744,14 @@
 	snd_es1371_src_write(ensoniq, ES_SMPREG_ADC + ES_SMPREG_VFREQ_FRAC, freq & 0x7fff);
 	snd_es1371_src_write(ensoniq, ES_SMPREG_VOL_ADC, n << 8);
 	snd_es1371_src_write(ensoniq, ES_SMPREG_VOL_ADC + 1, n << 8);
-	up(&ensoniq->src_mutex);
+	mutex_unlock(&ensoniq->src_mutex);
 }
 
 static void snd_es1371_dac1_rate(struct ensoniq * ensoniq, unsigned int rate)
 {
 	unsigned int freq, r;
 
-	down(&ensoniq->src_mutex);
+	mutex_lock(&ensoniq->src_mutex);
 	freq = ((rate << 15) + 1500) / 3000;
 	r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE |
 						   ES_1371_DIS_P2 | ES_1371_DIS_R1)) |
@@ -763,14 +765,14 @@
 	r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE |
 						   ES_1371_DIS_P2 | ES_1371_DIS_R1));
 	outl(r, ES_REG(ensoniq, 1371_SMPRATE));
-	up(&ensoniq->src_mutex);
+	mutex_unlock(&ensoniq->src_mutex);
 }
 
 static void snd_es1371_dac2_rate(struct ensoniq * ensoniq, unsigned int rate)
 {
 	unsigned int freq, r;
 
-	down(&ensoniq->src_mutex);
+	mutex_lock(&ensoniq->src_mutex);
 	freq = ((rate << 15) + 1500) / 3000;
 	r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE |
 						   ES_1371_DIS_P1 | ES_1371_DIS_R1)) |
@@ -785,7 +787,7 @@
 	r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE |
 						   ES_1371_DIS_P1 | ES_1371_DIS_R1));
 	outl(r, ES_REG(ensoniq, 1371_SMPRATE));
-	up(&ensoniq->src_mutex);
+	mutex_unlock(&ensoniq->src_mutex);
 }
 
 #endif /* CHIP1371 */
@@ -2061,6 +2063,13 @@
 #ifdef CHIP1371	
 	snd_ac97_suspend(ensoniq->u.es1371.ac97);
 #else
+	/* try to reset AK4531 */
+	outw(ES_1370_CODEC_WRITE(AK4531_RESET, 0x02), ES_REG(ensoniq, 1370_CODEC));
+	inw(ES_REG(ensoniq, 1370_CODEC));
+	udelay(100);
+	outw(ES_1370_CODEC_WRITE(AK4531_RESET, 0x03), ES_REG(ensoniq, 1370_CODEC));
+	inw(ES_REG(ensoniq, 1370_CODEC));
+	udelay(100);
 	snd_ak4531_suspend(ensoniq->u.es1370.ak4531);
 #endif	
 	pci_set_power_state(pci, PCI_D3hot);
@@ -2116,7 +2125,7 @@
 		return -ENOMEM;
 	}
 	spin_lock_init(&ensoniq->reg_lock);
-	init_MUTEX(&ensoniq->src_mutex);
+	mutex_init(&ensoniq->src_mutex);
 	ensoniq->card = card;
 	ensoniq->pci = pci;
 	ensoniq->irq = -1;
diff -urN oldtree/sound/pci/es1968.c newtree/sound/pci/es1968.c
--- oldtree/sound/pci/es1968.c	2006-02-19 11:41:07.039272968 +0000
+++ newtree/sound/pci/es1968.c	2006-02-21 15:58:11.458404616 +0000
@@ -103,6 +103,8 @@
 #include <linux/slab.h>
 #include <linux/gameport.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/mpu401.h>
@@ -569,7 +571,7 @@
 	u16 maestro_map[32];
 	int bobclient;		/* active timer instancs */
 	int bob_freq;		/* timer frequency */
-	struct semaphore memory_mutex;	/* memory lock */
+	struct mutex memory_mutex;	/* memory lock */
 
 	/* APU states */
 	unsigned char apu[NR_APUS];
@@ -1356,13 +1358,13 @@
 	struct list_head *p;
 	int max_size = 0;
 	
-	down(&chip->memory_mutex);
+	mutex_lock(&chip->memory_mutex);
 	list_for_each(p, &chip->buf_list) {
 		struct esm_memory *buf = list_entry(p, struct esm_memory, list);
 		if (buf->empty && buf->buf.bytes > max_size)
 			max_size = buf->buf.bytes;
 	}
-	up(&chip->memory_mutex);
+	mutex_unlock(&chip->memory_mutex);
 	if (max_size >= 128*1024)
 		max_size = 127*1024;
 	return max_size;
@@ -1375,20 +1377,20 @@
 	struct list_head *p;
 	
 	size = ((size + ESM_MEM_ALIGN - 1) / ESM_MEM_ALIGN) * ESM_MEM_ALIGN;
-	down(&chip->memory_mutex);
+	mutex_lock(&chip->memory_mutex);
 	list_for_each(p, &chip->buf_list) {
 		buf = list_entry(p, struct esm_memory, list);
 		if (buf->empty && buf->buf.bytes >= size)
 			goto __found;
 	}
-	up(&chip->memory_mutex);
+	mutex_unlock(&chip->memory_mutex);
 	return NULL;
 
 __found:
 	if (buf->buf.bytes > size) {
 		struct esm_memory *chunk = kmalloc(sizeof(*chunk), GFP_KERNEL);
 		if (chunk == NULL) {
-			up(&chip->memory_mutex);
+			mutex_unlock(&chip->memory_mutex);
 			return NULL;
 		}
 		chunk->buf = buf->buf;
@@ -1400,7 +1402,7 @@
 		list_add(&chunk->list, &buf->list);
 	}
 	buf->empty = 0;
-	up(&chip->memory_mutex);
+	mutex_unlock(&chip->memory_mutex);
 	return buf;
 }
 
@@ -1409,7 +1411,7 @@
 {
 	struct esm_memory *chunk;
 
-	down(&chip->memory_mutex);
+	mutex_lock(&chip->memory_mutex);
 	buf->empty = 1;
 	if (buf->list.prev != &chip->buf_list) {
 		chunk = list_entry(buf->list.prev, struct esm_memory, list);
@@ -1428,7 +1430,7 @@
 			kfree(chunk);
 		}
 	}
-	up(&chip->memory_mutex);
+	mutex_unlock(&chip->memory_mutex);
 }
 
 static void snd_es1968_free_dmabuf(struct es1968 *chip)
@@ -2579,7 +2581,7 @@
 	INIT_LIST_HEAD(&chip->buf_list);
 	INIT_LIST_HEAD(&chip->substream_list);
 	spin_lock_init(&chip->ac97_lock);
-	init_MUTEX(&chip->memory_mutex);
+	mutex_init(&chip->memory_mutex);
 	tasklet_init(&chip->hwvol_tq, es1968_update_hw_volume, (unsigned long)chip);
 	chip->card = card;
 	chip->pci = pci;
diff -urN oldtree/sound/pci/hda/hda_codec.c newtree/sound/pci/hda/hda_codec.c
--- oldtree/sound/pci/hda/hda_codec.c	2006-02-19 11:41:07.043272360 +0000
+++ newtree/sound/pci/hda/hda_codec.c	2006-02-21 15:58:11.460404312 +0000
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include "hda_codec.h"
 #include <sound/asoundef.h>
@@ -76,12 +77,12 @@
 				unsigned int verb, unsigned int parm)
 {
 	unsigned int res;
-	down(&codec->bus->cmd_mutex);
+	mutex_lock(&codec->bus->cmd_mutex);
 	if (! codec->bus->ops.command(codec, nid, direct, verb, parm))
 		res = codec->bus->ops.get_response(codec);
 	else
 		res = (unsigned int)-1;
-	up(&codec->bus->cmd_mutex);
+	mutex_unlock(&codec->bus->cmd_mutex);
 	return res;
 }
 
@@ -101,9 +102,9 @@
 			 unsigned int verb, unsigned int parm)
 {
 	int err;
-	down(&codec->bus->cmd_mutex);
+	mutex_lock(&codec->bus->cmd_mutex);
 	err = codec->bus->ops.command(codec, nid, direct, verb, parm);
-	up(&codec->bus->cmd_mutex);
+	mutex_unlock(&codec->bus->cmd_mutex);
 	return err;
 }
 
@@ -371,7 +372,7 @@
 	bus->modelname = temp->modelname;
 	bus->ops = temp->ops;
 
-	init_MUTEX(&bus->cmd_mutex);
+	mutex_init(&bus->cmd_mutex);
 	INIT_LIST_HEAD(&bus->codec_list);
 
 	if ((err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops)) < 0) {
@@ -523,7 +524,7 @@
 
 	codec->bus = bus;
 	codec->addr = codec_addr;
-	init_MUTEX(&codec->spdif_mutex);
+	mutex_init(&codec->spdif_mutex);
 	init_amp_hash(codec);
 
 	list_add_tail(&codec->list, &bus->codec_list);
@@ -881,12 +882,12 @@
 	unsigned long pval;
 	int err;
 
-	down(&codec->spdif_mutex); /* reuse spdif_mutex */
+	mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
 	pval = kcontrol->private_value;
 	kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */
 	err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
 	kcontrol->private_value = pval;
-	up(&codec->spdif_mutex);
+	mutex_unlock(&codec->spdif_mutex);
 	return err;
 }
 
@@ -896,7 +897,7 @@
 	unsigned long pval;
 	int i, indices, err = 0, change = 0;
 
-	down(&codec->spdif_mutex); /* reuse spdif_mutex */
+	mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
 	pval = kcontrol->private_value;
 	indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT;
 	for (i = 0; i < indices; i++) {
@@ -907,7 +908,7 @@
 		change |= err;
 	}
 	kcontrol->private_value = pval;
-	up(&codec->spdif_mutex);
+	mutex_unlock(&codec->spdif_mutex);
 	return err < 0 ? err : change;
 }
 
@@ -1011,7 +1012,7 @@
 	unsigned short val;
 	int change;
 
-	down(&codec->spdif_mutex);
+	mutex_lock(&codec->spdif_mutex);
 	codec->spdif_status = ucontrol->value.iec958.status[0] |
 		((unsigned int)ucontrol->value.iec958.status[1] << 8) |
 		((unsigned int)ucontrol->value.iec958.status[2] << 16) |
@@ -1026,7 +1027,7 @@
 		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_2, val >> 8);
 	}
 
-	up(&codec->spdif_mutex);
+	mutex_unlock(&codec->spdif_mutex);
 	return change;
 }
 
@@ -1054,7 +1055,7 @@
 	unsigned short val;
 	int change;
 
-	down(&codec->spdif_mutex);
+	mutex_lock(&codec->spdif_mutex);
 	val = codec->spdif_ctls & ~1;
 	if (ucontrol->value.integer.value[0])
 		val |= 1;
@@ -1066,7 +1067,7 @@
 				    AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT |
 				    AC_AMP_SET_OUTPUT | ((val & 1) ? 0 : 0x80));
 	}
-	up(&codec->spdif_mutex);
+	mutex_unlock(&codec->spdif_mutex);
 	return change;
 }
 
@@ -1150,13 +1151,13 @@
 	unsigned int val = !!ucontrol->value.integer.value[0];
 	int change;
 
-	down(&codec->spdif_mutex);
+	mutex_lock(&codec->spdif_mutex);
 	change = codec->spdif_in_enable != val;
 	if (change || codec->in_resume) {
 		codec->spdif_in_enable = val;
 		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, val);
 	}
-	up(&codec->spdif_mutex);
+	mutex_unlock(&codec->spdif_mutex);
 	return change;
 }
 
@@ -1824,13 +1825,13 @@
  */
 int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout)
 {
-	down(&codec->spdif_mutex);
+	mutex_lock(&codec->spdif_mutex);
 	if (mout->dig_out_used) {
-		up(&codec->spdif_mutex);
+		mutex_unlock(&codec->spdif_mutex);
 		return -EBUSY; /* already being used */
 	}
 	mout->dig_out_used = HDA_DIG_EXCLUSIVE;
-	up(&codec->spdif_mutex);
+	mutex_unlock(&codec->spdif_mutex);
 	return 0;
 }
 
@@ -1839,9 +1840,9 @@
  */
 int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout)
 {
-	down(&codec->spdif_mutex);
+	mutex_lock(&codec->spdif_mutex);
 	mout->dig_out_used = 0;
-	up(&codec->spdif_mutex);
+	mutex_unlock(&codec->spdif_mutex);
 	return 0;
 }
 
@@ -1869,7 +1870,7 @@
 	int chs = substream->runtime->channels;
 	int i;
 
-	down(&codec->spdif_mutex);
+	mutex_lock(&codec->spdif_mutex);
 	if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
 		if (chs == 2 &&
 		    snd_hda_is_supported_format(codec, mout->dig_out_nid, format) &&
@@ -1883,7 +1884,7 @@
 			snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0);
 		}
 	}
-	up(&codec->spdif_mutex);
+	mutex_unlock(&codec->spdif_mutex);
 
 	/* front */
 	snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 0, format);
@@ -1914,12 +1915,12 @@
 		snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
 	if (mout->hp_nid)
 		snd_hda_codec_setup_stream(codec, mout->hp_nid, 0, 0, 0);
-	down(&codec->spdif_mutex);
+	mutex_lock(&codec->spdif_mutex);
 	if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
 		snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0);
 		mout->dig_out_used = 0;
 	}
-	up(&codec->spdif_mutex);
+	mutex_unlock(&codec->spdif_mutex);
 	return 0;
 }
 
diff -urN oldtree/sound/pci/hda/hda_codec.h newtree/sound/pci/hda/hda_codec.h
--- oldtree/sound/pci/hda/hda_codec.h	2006-02-19 11:41:07.044272208 +0000
+++ newtree/sound/pci/hda/hda_codec.h	2006-02-21 15:58:11.466403400 +0000
@@ -438,7 +438,7 @@
 	struct list_head codec_list;
 	struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; /* caddr -> codec */
 
-	struct semaphore cmd_mutex;
+	struct mutex cmd_mutex;
 
 	/* unsolicited event queue */
 	struct hda_bus_unsolicited *unsol;
@@ -559,7 +559,7 @@
 	int amp_info_size;
 	struct hda_amp_info *amp_info;
 
-	struct semaphore spdif_mutex;
+	struct mutex spdif_mutex;
 	unsigned int spdif_status;	/* IEC958 status bits */
 	unsigned short spdif_ctls;	/* SPDIF control bits */
 	unsigned int spdif_in_enable;	/* SPDIF input enable? */
diff -urN oldtree/sound/pci/hda/hda_intel.c newtree/sound/pci/hda/hda_intel.c
--- oldtree/sound/pci/hda/hda_intel.c	2006-02-19 11:41:07.047271752 +0000
+++ newtree/sound/pci/hda/hda_intel.c	2006-02-21 15:58:11.476401880 +0000
@@ -43,6 +43,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include "hda_codec.h"
@@ -53,6 +54,7 @@
 static char *model;
 static int position_fix;
 static int probe_mask = -1;
+static int single_cmd;
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
@@ -64,6 +66,8 @@
 MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size).");
 module_param(probe_mask, int, 0444);
 MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
+module_param(single_cmd, bool, 0444);
+MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs (for debugging only).");
 
 
 /* just for backward compatibility */
@@ -235,12 +239,6 @@
 #define NVIDIA_HDA_ENABLE_COHBITS     0x0f
 
 /*
- * Use CORB/RIRB for communication from/to codecs.
- * This is the way recommended by Intel (see below).
- */
-#define USE_CORB_RIRB
-
-/*
  */
 
 struct azx_dev {
@@ -300,7 +298,7 @@
 
 	/* locks */
 	spinlock_t reg_lock;
-	struct semaphore open_mutex;
+	struct mutex open_mutex;
 
 	/* streams (x num_streams) */
 	struct azx_dev *azx_dev;
@@ -325,6 +323,7 @@
 	/* flags */
 	int position_fix;
 	unsigned int initialized: 1;
+	unsigned int single_cmd: 1;
 };
 
 /* driver types */
@@ -388,7 +387,6 @@
  * Interface for HD codec
  */
 
-#ifdef USE_CORB_RIRB
 /*
  * CORB / RIRB interface
  */
@@ -436,11 +434,7 @@
 	/* set N=1, get RIRB response interrupt for new entry */
 	azx_writew(chip, RINTCNT, 1);
 	/* enable rirb dma and response irq */
-#ifdef USE_CORB_RIRB
 	azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
-#else
-	azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN);
-#endif
 	chip->rirb.rp = chip->rirb.cmds = 0;
 }
 
@@ -528,7 +522,6 @@
 	return chip->rirb.res; /* the last value */
 }
 
-#else
 /*
  * Use the single immediate command instead of CORB/RIRB for simplicity
  *
@@ -539,13 +532,10 @@
  *       I left the codes, however, for debugging/testing purposes.
  */
 
-#define azx_alloc_cmd_io(chip)	0
-#define azx_init_cmd_io(chip)
-#define azx_free_cmd_io(chip)
-
 /* send a command */
-static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
-			unsigned int verb, unsigned int para)
+static int azx_single_send_cmd(struct hda_codec *codec, hda_nid_t nid,
+			       int direct, unsigned int verb,
+			       unsigned int para)
 {
 	struct azx *chip = codec->bus->private_data;
 	u32 val;
@@ -573,7 +563,7 @@
 }
 
 /* receive a response */
-static unsigned int azx_get_response(struct hda_codec *codec)
+static unsigned int azx_single_get_response(struct hda_codec *codec)
 {
 	struct azx *chip = codec->bus->private_data;
 	int timeout = 50;
@@ -588,10 +578,6 @@
 	return (unsigned int)-1;
 }
 
-#define azx_update_rirb(chip)
-
-#endif /* USE_CORB_RIRB */
-
 /* reset codec link */
 static int azx_reset(struct azx *chip)
 {
@@ -737,7 +723,8 @@
 	azx_int_enable(chip);
 
 	/* initialize the codec command I/O */
-	azx_init_cmd_io(chip);
+	if (! chip->single_cmd)
+		azx_init_cmd_io(chip);
 
 	/* program the position buffer */
 	azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
@@ -796,7 +783,7 @@
 	/* clear rirb int */
 	status = azx_readb(chip, RIRBSTS);
 	if (status & RIRB_INT_MASK) {
-		if (status & RIRB_INT_RESPONSE)
+		if (! chip->single_cmd && (status & RIRB_INT_RESPONSE))
 			azx_update_rirb(chip);
 		azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
 	}
@@ -913,8 +900,13 @@
 	bus_temp.private_data = chip;
 	bus_temp.modelname = model;
 	bus_temp.pci = chip->pci;
-	bus_temp.ops.command = azx_send_cmd;
-	bus_temp.ops.get_response = azx_get_response;
+	if (chip->single_cmd) {
+		bus_temp.ops.command = azx_single_send_cmd;
+		bus_temp.ops.get_response = azx_single_get_response;
+	} else {
+		bus_temp.ops.command = azx_send_cmd;
+		bus_temp.ops.get_response = azx_get_response;
+	}
 
 	if ((err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus)) < 0)
 		return err;
@@ -1002,10 +994,10 @@
 	unsigned long flags;
 	int err;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	azx_dev = azx_assign_device(chip, substream->stream);
 	if (azx_dev == NULL) {
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return -EBUSY;
 	}
 	runtime->hw = azx_pcm_hw;
@@ -1017,7 +1009,7 @@
 	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
 	if ((err = hinfo->ops.open(hinfo, apcm->codec, substream)) < 0) {
 		azx_release_device(azx_dev);
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return err;
 	}
 	spin_lock_irqsave(&chip->reg_lock, flags);
@@ -1026,7 +1018,7 @@
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 
 	runtime->private_data = azx_dev;
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	return 0;
 }
 
@@ -1038,14 +1030,14 @@
 	struct azx_dev *azx_dev = get_azx_dev(substream);
 	unsigned long flags;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	azx_dev->substream = NULL;
 	azx_dev->running = 0;
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 	azx_release_device(azx_dev);
 	hinfo->ops.close(hinfo, apcm->codec, substream);
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	return 0;
 }
 
@@ -1316,7 +1308,8 @@
 	for (i = 0; i < chip->pcm_devs; i++)
 		snd_pcm_suspend_all(chip->pcm[i]);
 	snd_hda_suspend(chip->bus, state);
-	azx_free_cmd_io(chip);
+	if (! chip->single_cmd)
+		azx_free_cmd_io(chip);
 	pci_disable_device(pci);
 	pci_save_state(pci);
 	return 0;
@@ -1354,7 +1347,8 @@
 		azx_int_clear(chip);
 
 		/* disable CORB/RIRB */
-		azx_free_cmd_io(chip);
+		if (! chip->single_cmd)
+			azx_free_cmd_io(chip);
 
 		/* disable position buffer */
 		azx_writel(chip, DPLBASE, 0);
@@ -1415,13 +1409,14 @@
 	}
 
 	spin_lock_init(&chip->reg_lock);
-	init_MUTEX(&chip->open_mutex);
+	mutex_init(&chip->open_mutex);
 	chip->card = card;
 	chip->pci = pci;
 	chip->irq = -1;
 	chip->driver_type = driver_type;
 
 	chip->position_fix = position_fix ? position_fix : POS_FIX_POSBUF;
+	chip->single_cmd = single_cmd;
 
 #if BITS_PER_LONG != 64
 	/* Fix up base address on ULI M5461 */
@@ -1492,8 +1487,9 @@
 		goto errout;
 	}
 	/* allocate CORB/RIRB */
-	if ((err = azx_alloc_cmd_io(chip)) < 0)
-		goto errout;
+	if (! chip->single_cmd)
+		if ((err = azx_alloc_cmd_io(chip)) < 0)
+			goto errout;
 
 	/* initialize streams */
 	azx_init_stream(chip);
diff -urN oldtree/sound/pci/hda/patch_analog.c newtree/sound/pci/hda/patch_analog.c
--- oldtree/sound/pci/hda/patch_analog.c	2006-02-19 11:41:07.051271144 +0000
+++ newtree/sound/pci/hda/patch_analog.c	2006-02-21 15:58:11.478401576 +0000
@@ -23,6 +23,8 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
@@ -60,7 +62,7 @@
 	/* PCM information */
 	struct hda_pcm pcm_rec[2];	/* used in alc_build_pcms() */
 
-	struct semaphore amp_mutex;	/* PCM volume/mute control mutex */
+	struct mutex amp_mutex;	/* PCM volume/mute control mutex */
 	unsigned int spdif_route;
 
 	/* dynamic controls, init_verbs and input_mux */
@@ -371,9 +373,9 @@
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct ad198x_spec *ad = codec->spec;
 
-	down(&ad->amp_mutex);
+	mutex_lock(&ad->amp_mutex);
 	snd_hda_mixer_amp_volume_get(kcontrol, ucontrol);
-	up(&ad->amp_mutex);
+	mutex_unlock(&ad->amp_mutex);
 	return 0;
 }
 
@@ -383,13 +385,13 @@
 	struct ad198x_spec *ad = codec->spec;
 	int i, change = 0;
 
-	down(&ad->amp_mutex);
+	mutex_lock(&ad->amp_mutex);
 	for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) {
 		kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT);
 		change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
 	}
 	kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT);
-	up(&ad->amp_mutex);
+	mutex_unlock(&ad->amp_mutex);
 	return change;
 }
 
@@ -400,9 +402,9 @@
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct ad198x_spec *ad = codec->spec;
 
-	down(&ad->amp_mutex);
+	mutex_lock(&ad->amp_mutex);
 	snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
-	up(&ad->amp_mutex);
+	mutex_unlock(&ad->amp_mutex);
 	return 0;
 }
 
@@ -412,13 +414,13 @@
 	struct ad198x_spec *ad = codec->spec;
 	int i, change = 0;
 
-	down(&ad->amp_mutex);
+	mutex_lock(&ad->amp_mutex);
 	for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) {
 		kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT);
 		change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
 	}
 	kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT);
-	up(&ad->amp_mutex);
+	mutex_unlock(&ad->amp_mutex);
 	return change;
 }
 
@@ -544,7 +546,7 @@
 	if (spec == NULL)
 		return -ENOMEM;
 
-	init_MUTEX(&spec->amp_mutex);
+	mutex_init(&spec->amp_mutex);
 	codec->spec = spec;
 
 	spec->multiout.max_channels = 6;
@@ -708,7 +710,7 @@
 	if (spec == NULL)
 		return -ENOMEM;
 
-	init_MUTEX(&spec->amp_mutex);
+	mutex_init(&spec->amp_mutex);
 	codec->spec = spec;
 
 	spec->multiout.max_channels = 2;
@@ -854,7 +856,7 @@
 	if (spec == NULL)
 		return -ENOMEM;
 
-	init_MUTEX(&spec->amp_mutex);
+	mutex_init(&spec->amp_mutex);
 	codec->spec = spec;
 
 	spec->multiout.max_channels = 2;
@@ -2032,7 +2034,7 @@
 	if (spec == NULL)
 		return -ENOMEM;
 
-	init_MUTEX(&spec->amp_mutex);
+	mutex_init(&spec->amp_mutex);
 	codec->spec = spec;
 
 	if (codec->revision_id == AD1988A_REV2)
diff -urN oldtree/sound/pci/ice1712/aureon.c newtree/sound/pci/ice1712/aureon.c
--- oldtree/sound/pci/ice1712/aureon.c	2006-02-19 11:41:07.064269168 +0000
+++ newtree/sound/pci/ice1712/aureon.c	2006-02-21 15:58:11.480401272 +0000
@@ -53,6 +53,8 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 
 #include "ice1712.h"
@@ -210,14 +212,14 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned short vol;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 
 	vol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
 	ucontrol->value.integer.value[0] = 0x1F - (vol & 0x1F);
 	if (kcontrol->private_value & AUREON_AC97_STEREO)
 		ucontrol->value.integer.value[1] = 0x1F - ((vol >> 8) & 0x1F);
 
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -252,11 +254,11 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 
 	ucontrol->value.integer.value[0] = aureon_ac97_read(ice, kcontrol->private_value & 0x7F) & 0x8000 ? 0 : 1;
 
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -288,11 +290,11 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 
 	ucontrol->value.integer.value[0] = aureon_ac97_read(ice, AC97_MIC) & 0x0020 ? 0 : 1;
 
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -322,36 +324,48 @@
 {
 	unsigned int tmp;
 	int i;
+	unsigned int mosi, clk;
 
 	tmp = snd_ice1712_gpio_read(ice);
 
-	snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_SPI_MOSI|AUREON_SPI_CLK|
-					 AUREON_WM_CS|AUREON_CS8415_CS));
-	tmp |= AUREON_WM_RW;
+	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT) {
+		snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS));
+		mosi = PRODIGY_SPI_MOSI;
+		clk = PRODIGY_SPI_CLK;
+	}
+	else {
+		snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_SPI_MOSI|AUREON_SPI_CLK|
+						 AUREON_WM_CS|AUREON_CS8415_CS));
+		mosi = AUREON_SPI_MOSI;
+		clk = AUREON_SPI_CLK;
+		
+		tmp |= AUREON_WM_RW;
+	}
+	
 	tmp &= ~cs;
 	snd_ice1712_gpio_write(ice, tmp);
 	udelay(1);
 
 	for (i = bits - 1; i >= 0; i--) {
-		tmp &= ~AUREON_SPI_CLK;
+		tmp &= ~clk;
 		snd_ice1712_gpio_write(ice, tmp);
 		udelay(1);
 		if (data & (1 << i))
-			tmp |= AUREON_SPI_MOSI;
+			tmp |= mosi;
 		else
-			tmp &= ~AUREON_SPI_MOSI;
+			tmp &= ~mosi;
 		snd_ice1712_gpio_write(ice, tmp);
 		udelay(1);
-		tmp |= AUREON_SPI_CLK;
+		tmp |= clk;
 		snd_ice1712_gpio_write(ice, tmp);
 		udelay(1);
 	}
 
-	tmp &= ~AUREON_SPI_CLK;
+	tmp &= ~clk;
 	tmp |= cs;
 	snd_ice1712_gpio_write(ice, tmp);
 	udelay(1);
-	tmp |= AUREON_SPI_CLK;
+	tmp |= clk;
 	snd_ice1712_gpio_write(ice, tmp);
 	udelay(1);
 }
@@ -440,7 +454,9 @@
  */
 static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
 {
-	aureon_spi_write(ice, AUREON_WM_CS, (reg << 9) | (val & 0x1ff), 16);
+	aureon_spi_write(ice,
+			(ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ? PRODIGY_WM_CS : AUREON_WM_CS),
+			(reg << 9) | (val & 0x1ff), 16);
 }
 
 /*
@@ -474,11 +490,11 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 
 	ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX1) >> 1) & 0x01;
 
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -543,9 +559,9 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -768,11 +784,11 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned short val;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
 	val = val > PCM_MIN ? (val - PCM_MIN) : 0;
 	ucontrol->value.integer.value[0] = val;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -813,12 +829,12 @@
 	unsigned short val;
 	int i;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	for (i = 0; i < 2; i++) {
 		val = wm_get(ice, WM_ADC_GAIN + i);
 		ucontrol->value.integer.value[i] = ~val>>5 & 0x1;
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -860,13 +876,13 @@
 	int i, idx;
 	unsigned short vol;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	for (i = 0; i < 2; i++) {
 		idx = WM_ADC_GAIN + i;
 		vol = wm_get(ice, idx) & 0x1f;
 		ucontrol->value.integer.value[i] = vol;
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -937,11 +953,11 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned short val;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	val = wm_get(ice, WM_ADC_MUX);
 	ucontrol->value.integer.value[0] = val & 7;
 	ucontrol->value.integer.value[1] = (val >> 4) & 7;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -1659,7 +1675,7 @@
 				return err;
 		}
 	}
-	else {
+	else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
 		for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) {
 			err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice));
 			if (err < 0)
@@ -1667,7 +1683,7 @@
 		}
 	}
 
-	{
+	if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
 		unsigned char id;
 		snd_ice1712_save_gpio_status(ice);
 		id = aureon_cs8415_get(ice, CS8415_ID);
@@ -1822,7 +1838,8 @@
 	udelay(1);
 
 	/* initialize WM8770 codec */
-	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71)
+	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 ||
+		ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT)
 		p = wm_inits_prodigy;
 	else
 		p = wm_inits_aureon;
@@ -1830,11 +1847,13 @@
 		wm_put(ice, p[0], p[1]);
 
 	/* initialize CS8415A codec */
-	for (p = cs_inits; *p != (unsigned short)-1; p++)
-		aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24);
-	ice->spec.aureon.cs8415_mux = 1;
+	if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
+		for (p = cs_inits; *p != (unsigned short)-1; p++)
+			aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24);
+		ice->spec.aureon.cs8415_mux = 1;
 
-	aureon_set_headphone_amp(ice, 1);
+		aureon_set_headphone_amp(ice, 1);
+	}
 
 	snd_ice1712_restore_gpio_status(ice);
 	
@@ -1902,6 +1921,23 @@
 	0x00,	/* GPIO_STATE2 */
 };
 
+static unsigned char prodigy71lt_eeprom[] __devinitdata = {
+	0x0b,	/* SYSCINF: clock 512, spdif-in/ADC, 4DACs */
+	0x80,	/* ACLINK: I2S */
+	0xfc,	/* I2S: vol, 96k, 24bit, 192k */
+	0xc3,	/* SPDUF: out-en, out-int */
+	0x00,	/* GPIO_DIR */
+	0x07,	/* GPIO_DIR1 */
+	0x00,	/* GPIO_DIR2 */
+	0xff,	/* GPIO_MASK */
+	0xf8,	/* GPIO_MASK1 */
+	0xff,	/* GPIO_MASK2 */
+	0x00,	/* GPIO_STATE */
+	0x00,	/* GPIO_STATE1 */
+	0x00,	/* GPIO_STATE2 */
+};
+	
+
 /* entry point */
 struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
 	{
@@ -1944,5 +1980,15 @@
 		.eeprom_data = prodigy71_eeprom,
 		.driver = "Prodigy71", /* should be identical with Aureon71 */
 	},
+	{
+		.subvendor = VT1724_SUBDEVICE_PRODIGY71LT,
+		.name = "Audiotrak Prodigy 7.1 LT",
+		.model = "prodigy71lt",
+		.chip_init = aureon_init,
+		.build_controls = aureon_add_controls,
+		.eeprom_size = sizeof(prodigy71lt_eeprom),
+		.eeprom_data = prodigy71lt_eeprom,
+		.driver = "Prodigy71LT",
+	},
 	{ } /* terminator */
 };
diff -urN oldtree/sound/pci/ice1712/aureon.h newtree/sound/pci/ice1712/aureon.h
--- oldtree/sound/pci/ice1712/aureon.h	2006-01-03 03:21:10.000000000 +0000
+++ newtree/sound/pci/ice1712/aureon.h	2006-02-21 15:58:11.490399752 +0000
@@ -27,12 +27,14 @@
 #define  AUREON_DEVICE_DESC 	       "{Terratec,Aureon 5.1 Sky},"\
 				       "{Terratec,Aureon 7.1 Space},"\
 				       "{Terratec,Aureon 7.1 Universe}," \
-					"{AudioTrak,Prodigy 7.1},"
+					"{AudioTrak,Prodigy 7.1}," \
+					"{AudioTrak,Prodigy 7.1 LT},"
 
 #define VT1724_SUBDEVICE_AUREON51_SKY	0x3b154711	/* Aureon 5.1 Sky */
 #define VT1724_SUBDEVICE_AUREON71_SPACE	0x3b154511	/* Aureon 7.1 Space */
 #define VT1724_SUBDEVICE_AUREON71_UNIVERSE	0x3b155311	/* Aureon 7.1 Universe */
 #define VT1724_SUBDEVICE_PRODIGY71	0x33495345	/* PRODIGY 7.1 */
+#define VT1724_SUBDEVICE_PRODIGY71LT	0x32315441	/* PRODIGY 7.1 LT */
 
 extern struct snd_ice1712_card_info  snd_vt1724_aureon_cards[];
 
@@ -53,4 +55,8 @@
 #define AUREON_AC97_DATA_HIGH	(1 << 8)
 #define AUREON_AC97_DATA_MASK	0xFF
 
+#define PRODIGY_WM_CS		(1 << 8)
+#define PRODIGY_SPI_MOSI	(1 << 10)
+#define PRODIGY_SPI_CLK		(1 << 9)
+
 #endif /* __SOUND_AUREON_H */
diff -urN oldtree/sound/pci/ice1712/delta.c newtree/sound/pci/ice1712/delta.c
--- oldtree/sound/pci/ice1712/delta.c	2006-02-19 11:41:07.065269016 +0000
+++ newtree/sound/pci/ice1712/delta.c	2006-02-21 15:58:11.491399600 +0000
@@ -28,6 +28,8 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/cs8427.h>
 #include <sound/asoundef.h>
@@ -130,13 +132,13 @@
 	int res = count;
 	unsigned char tmp;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	tmp = ap_cs8427_codec_select(ice);
 	ap_cs8427_write_byte(ice, (device->addr << 1) | 0, tmp); /* address + write mode */
 	while (count-- > 0)
 		ap_cs8427_write_byte(ice, *bytes++, tmp);
 	ap_cs8427_codec_deassert(ice, tmp);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return res;
 }
 
@@ -147,13 +149,13 @@
 	int res = count;
 	unsigned char tmp;
 	
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	tmp = ap_cs8427_codec_select(ice);
 	ap_cs8427_write_byte(ice, (device->addr << 1) | 1, tmp); /* address + read mode */
 	while (count-- > 0)
 		*bytes++ = ap_cs8427_read_byte(ice, tmp);
 	ap_cs8427_codec_deassert(ice, tmp);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return res;
 }
 
@@ -180,7 +182,7 @@
 	/* send byte to transmitter */
 	mask1 = ICE1712_DELTA_SPDIF_OUT_STAT_CLOCK;
 	mask2 = ICE1712_DELTA_SPDIF_OUT_STAT_DATA;
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
 	for (idx = 7; idx >= 0; idx--) {
 		tmp &= ~(mask1 | mask2);
@@ -194,7 +196,7 @@
 	}
 	tmp &= ~mask1;
 	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 
@@ -296,14 +298,14 @@
 	if (rate == 0)	/* no hint - S/PDIF input is master, simply return */
 		return;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
 	tmp2 = tmp & ~ICE1712_DELTA_DFS;
 	if (rate > 48000)
 		tmp2 |= ICE1712_DELTA_DFS;
 	if (tmp != tmp2)
 		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp2);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 /*
@@ -318,9 +320,9 @@
 		return;
 
 	/* check before reset ak4524 to avoid unnecessary clicks */
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	tmp2 = tmp & ~ICE1712_DELTA_DFS; 
 	if (rate > 48000)
 		tmp2 |= ICE1712_DELTA_DFS;
@@ -329,12 +331,12 @@
 
 	/* do it again */
 	snd_akm4xxx_reset(ak, 1);
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ~ICE1712_DELTA_DFS;
 	if (rate > 48000)
 		tmp |= ICE1712_DELTA_DFS;
 	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	snd_akm4xxx_reset(ak, 0);
 }
 
diff -urN oldtree/sound/pci/ice1712/hoontech.c newtree/sound/pci/ice1712/hoontech.c
--- oldtree/sound/pci/ice1712/hoontech.c	2006-02-19 11:41:07.067268712 +0000
+++ newtree/sound/pci/ice1712/hoontech.c	2006-02-21 15:58:11.491399600 +0000
@@ -27,6 +27,8 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 
 #include "ice1712.h"
@@ -48,31 +50,31 @@
 
 static void __devinit snd_ice1712_stdsp24_darear(struct snd_ice1712 *ice, int activate)
 {
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ICE1712_STDSP24_0_DAREAR(ice->spec.hoontech.boxbits, activate);
 	snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[0]);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 static void __devinit snd_ice1712_stdsp24_mute(struct snd_ice1712 *ice, int activate)
 {
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ICE1712_STDSP24_3_MUTE(ice->spec.hoontech.boxbits, activate);
 	snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 static void __devinit snd_ice1712_stdsp24_insel(struct snd_ice1712 *ice, int activate)
 {
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ICE1712_STDSP24_3_INSEL(ice->spec.hoontech.boxbits, activate);
 	snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 static void __devinit snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, int box, int chn, int activate)
 {
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 
 	/* select box */
 	ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, box);
@@ -115,12 +117,12 @@
 	ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, 0);
 	snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]);
 
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 static void __devinit snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int box, int master)
 {
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 
 	/* select box */
 	ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, box);
@@ -141,15 +143,15 @@
 	ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 1);
 	snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]);
 
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 static void __devinit snd_ice1712_stdsp24_midi2(struct snd_ice1712 *ice, int activate)
 {
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ICE1712_STDSP24_3_MIDI2(ice->spec.hoontech.boxbits, activate);
 	snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 static int __devinit snd_ice1712_hoontech_init(struct snd_ice1712 *ice)
diff -urN oldtree/sound/pci/ice1712/ice1712.c newtree/sound/pci/ice1712/ice1712.c
--- oldtree/sound/pci/ice1712/ice1712.c	2006-02-19 11:41:07.072267952 +0000
+++ newtree/sound/pci/ice1712/ice1712.c	2006-02-21 15:58:11.496398840 +0000
@@ -55,6 +55,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/cs8427.h>
 #include <sound/info.h>
@@ -316,7 +317,6 @@
 	inb(ICEREG(ice, DATA)); /* dummy read for pci-posting */
 }
 
-
 /*
  *
  * CS8427 interface
@@ -396,6 +396,20 @@
 	return 0;
 }
 
+static void snd_ice1712_set_input_clock_source(struct snd_ice1712 *ice, int spdif_is_master)
+{
+        /* change CS8427 clock source too */
+        if (ice->cs8427)
+                snd_ice1712_cs8427_set_input_clock(ice, spdif_is_master);
+	/* notify ak4524 chip as well */
+	if (spdif_is_master) {
+		unsigned int i;
+		for (i = 0; i < ice->akm_codecs; i++) {
+			if (ice->akm[i].ops.set_rate_val)
+				ice->akm[i].ops.set_rate_val(&ice->akm[i], 0);
+		}
+	}
+}
 
 /*
  *  Interrupt handler
@@ -1856,20 +1870,8 @@
 	spin_unlock_irq(&ice->reg_lock);
 
 	if ((oval & ICE1712_SPDIF_MASTER) !=
-	    (inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER)) {
-		/* change CS8427 clock source too */
-		if (ice->cs8427) {
-			snd_ice1712_cs8427_set_input_clock(ice, is_spdif_master(ice));
-		}
-		/* notify ak4524 chip as well */
-		if (is_spdif_master(ice)) {
-			unsigned int i;
-			for (i = 0; i < ice->akm_codecs; i++) {
-				if (ice->akm[i].ops.set_rate_val)
-					ice->akm[i].ops.set_rate_val(&ice->akm[i], 0);
-			}
-		}
-	}
+	    (inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER))
+	        snd_ice1712_set_input_clock_source(ice, is_spdif_master(ice));
 
 	return change;
 }
@@ -2557,9 +2559,9 @@
 		cs8427_timeout = 1000;
 	ice->cs8427_timeout = cs8427_timeout;
 	spin_lock_init(&ice->reg_lock);
-	init_MUTEX(&ice->gpio_mutex);
-	init_MUTEX(&ice->i2c_mutex);
-	init_MUTEX(&ice->open_mutex);
+	mutex_init(&ice->gpio_mutex);
+	mutex_init(&ice->i2c_mutex);
+	mutex_init(&ice->open_mutex);
 	ice->gpio.set_mask = snd_ice1712_set_gpio_mask;
 	ice->gpio.set_dir = snd_ice1712_set_gpio_dir;
 	ice->gpio.set_data = snd_ice1712_set_gpio_data;
@@ -2735,6 +2737,8 @@
 			}
 	}
 
+	snd_ice1712_set_input_clock_source(ice, 0);
+
 	sprintf(card->longname, "%s at 0x%lx, irq %i",
 		card->shortname, ice->port, ice->irq);
 
diff -urN oldtree/sound/pci/ice1712/ice1712.h newtree/sound/pci/ice1712/ice1712.h
--- oldtree/sound/pci/ice1712/ice1712.h	2006-02-19 11:41:07.073267800 +0000
+++ newtree/sound/pci/ice1712/ice1712.h	2006-02-21 15:58:11.497398688 +0000
@@ -334,7 +334,7 @@
 	unsigned int num_total_adcs;	/* total ADCs */
 	unsigned int cur_rate;		/* current rate */
 
-	struct semaphore open_mutex;
+	struct mutex open_mutex;
 	struct snd_pcm_substream *pcm_reserved[4];
 	struct snd_pcm_hw_constraint_list *hw_rates; /* card-specific rate constraints */
 
@@ -342,7 +342,7 @@
 	struct snd_akm4xxx *akm;
 	struct snd_ice1712_spdif spdif;
 
-	struct semaphore i2c_mutex;	/* I2C mutex for ICE1724 registers */
+	struct mutex i2c_mutex;	/* I2C mutex for ICE1724 registers */
 	struct snd_i2c_bus *i2c;		/* I2C bus */
 	struct snd_i2c_device *cs8427;	/* CS8427 I2C device */
 	unsigned int cs8427_timeout;	/* CS8427 reset timeout in HZ/100 */
@@ -360,7 +360,7 @@
 		void (*set_pro_rate)(struct snd_ice1712 *ice, unsigned int rate);
 		void (*i2s_mclk_changed)(struct snd_ice1712 *ice);
 	} gpio;
-	struct semaphore gpio_mutex;
+	struct mutex gpio_mutex;
 
 	/* other board-specific data */
 	union {
@@ -423,7 +423,7 @@
  */
 static inline void snd_ice1712_save_gpio_status(struct snd_ice1712 *ice)
 {
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ice->gpio.saved[0] = ice->gpio.direction;
 	ice->gpio.saved[1] = ice->gpio.write_mask;
 }
@@ -434,7 +434,7 @@
 	ice->gpio.set_mask(ice, ice->gpio.saved[1]);
 	ice->gpio.direction = ice->gpio.saved[0];
 	ice->gpio.write_mask = ice->gpio.saved[1];
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 /* for bit controls */
diff -urN oldtree/sound/pci/ice1712/ice1724.c newtree/sound/pci/ice1712/ice1724.c
--- oldtree/sound/pci/ice1712/ice1724.c	2006-02-19 11:41:07.077267192 +0000
+++ newtree/sound/pci/ice1712/ice1724.c	2006-02-21 15:58:11.499398384 +0000
@@ -30,6 +30,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/mpu401.h>
@@ -487,7 +488,7 @@
 	int i, chs;
 
 	chs = params_channels(hw_params);
-	down(&ice->open_mutex);
+	mutex_lock(&ice->open_mutex);
 	/* mark surround channels */
 	if (substream == ice->playback_pro_substream) {
 		/* PDMA0 can be multi-channel up to 8 */
@@ -495,7 +496,7 @@
 		for (i = 0; i < chs; i++) {
 			if (ice->pcm_reserved[i] &&
 			    ice->pcm_reserved[i] != substream) {
-				up(&ice->open_mutex);
+				mutex_unlock(&ice->open_mutex);
 				return -EBUSY;
 			}
 			ice->pcm_reserved[i] = substream;
@@ -510,7 +511,7 @@
 			if (ice->playback_con_substream_ds[i] == substream) {
 				if (ice->pcm_reserved[i] &&
 				    ice->pcm_reserved[i] != substream) {
-					up(&ice->open_mutex);
+					mutex_unlock(&ice->open_mutex);
 					return -EBUSY;
 				}
 				ice->pcm_reserved[i] = substream;
@@ -518,7 +519,7 @@
 			}
 		}
 	}
-	up(&ice->open_mutex);
+	mutex_unlock(&ice->open_mutex);
 	snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0);
 	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
 }
@@ -528,12 +529,12 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 	int i;
 
-	down(&ice->open_mutex);
+	mutex_lock(&ice->open_mutex);
 	/* unmark surround channels */
 	for (i = 0; i < 3; i++)
 		if (ice->pcm_reserved[i] == substream)
 			ice->pcm_reserved[i] = NULL;
-	up(&ice->open_mutex);
+	mutex_unlock(&ice->open_mutex);
 	return snd_pcm_lib_free_pages(substream);
 }
 
@@ -778,7 +779,7 @@
 	snd_pcm_set_sync(substream);
 	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
 	set_rate_constraints(ice, substream);
-	down(&ice->open_mutex);
+	mutex_lock(&ice->open_mutex);
 	/* calculate the currently available channels */
 	for (chs = 0; chs < 3; chs++) {
 		if (ice->pcm_reserved[chs])
@@ -788,7 +789,7 @@
 	runtime->hw.channels_max = chs;
 	if (chs > 2) /* channels must be even */
 		snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
-	up(&ice->open_mutex);
+	mutex_unlock(&ice->open_mutex);
 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
 				   VT1724_BUFFER_ALIGN);
 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
@@ -1128,13 +1129,13 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
-	down(&ice->open_mutex);
+	mutex_lock(&ice->open_mutex);
 	/* already used by PDMA0? */
 	if (ice->pcm_reserved[substream->number]) {
-		up(&ice->open_mutex);
+		mutex_unlock(&ice->open_mutex);
 		return -EBUSY; /* FIXME: should handle blocking mode properly */
 	}
-	up(&ice->open_mutex);
+	mutex_unlock(&ice->open_mutex);
 	runtime->private_data = &vt1724_playback_dma_regs[substream->number];
 	ice->playback_con_substream_ds[substream->number] = substream;
 	runtime->hw = snd_vt1724_2ch_stereo;
@@ -1978,12 +1979,12 @@
 {
 	unsigned char val;
 
-	down(&ice->i2c_mutex);
+	mutex_lock(&ice->i2c_mutex);
 	outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR));
 	outb(dev & ~VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR));
 	wait_i2c_busy(ice);
 	val = inb(ICEREG1724(ice, I2C_DATA));
-	up(&ice->i2c_mutex);
+	mutex_unlock(&ice->i2c_mutex);
 	//printk("i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val);
 	return val;
 }
@@ -1991,14 +1992,14 @@
 void snd_vt1724_write_i2c(struct snd_ice1712 *ice,
 			  unsigned char dev, unsigned char addr, unsigned char data)
 {
-	down(&ice->i2c_mutex);
+	mutex_lock(&ice->i2c_mutex);
 	wait_i2c_busy(ice);
 	//printk("i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data);
 	outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR));
 	outb(data, ICEREG1724(ice, I2C_DATA));
 	outb(dev | VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR));
 	wait_i2c_busy(ice);
-	up(&ice->i2c_mutex);
+	mutex_unlock(&ice->i2c_mutex);
 }
 
 static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice,
@@ -2229,9 +2230,9 @@
 	}
 	ice->vt1724 = 1;
 	spin_lock_init(&ice->reg_lock);
-	init_MUTEX(&ice->gpio_mutex);
-	init_MUTEX(&ice->open_mutex);
-	init_MUTEX(&ice->i2c_mutex);
+	mutex_init(&ice->gpio_mutex);
+	mutex_init(&ice->open_mutex);
+	mutex_init(&ice->i2c_mutex);
 	ice->gpio.set_mask = snd_vt1724_set_gpio_mask;
 	ice->gpio.set_dir = snd_vt1724_set_gpio_dir;
 	ice->gpio.set_data = snd_vt1724_set_gpio_data;
diff -urN oldtree/sound/pci/ice1712/phase.c newtree/sound/pci/ice1712/phase.c
--- oldtree/sound/pci/ice1712/phase.c	2006-02-19 11:41:07.078267040 +0000
+++ newtree/sound/pci/ice1712/phase.c	2006-02-21 15:58:11.500398232 +0000
@@ -39,6 +39,8 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 
 #include "ice1712.h"
@@ -273,9 +275,9 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -584,11 +586,11 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned short val;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
 	val = val > PCM_MIN ? (val - PCM_MIN) : 0;
 	ucontrol->value.integer.value[0] = val;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
diff -urN oldtree/sound/pci/ice1712/pontis.c newtree/sound/pci/ice1712/pontis.c
--- oldtree/sound/pci/ice1712/pontis.c	2006-02-19 11:41:07.080266736 +0000
+++ newtree/sound/pci/ice1712/pontis.c	2006-02-21 15:58:11.501398080 +0000
@@ -27,6 +27,8 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/info.h>
 
@@ -124,13 +126,13 @@
 	unsigned short val;
 	int i;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	for (i = 0; i < 2; i++) {
 		val = wm_get(ice, WM_DAC_ATTEN_L + i) & 0xff;
 		val = val > DAC_MIN ? (val - DAC_MIN) : 0;
 		ucontrol->value.integer.value[i] = val;
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -140,7 +142,7 @@
 	unsigned short oval, nval;
 	int i, idx, change = 0;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	for (i = 0; i < 2; i++) {
 		nval = ucontrol->value.integer.value[i];
 		nval = (nval ? (nval + DAC_MIN) : 0) & 0xff;
@@ -152,7 +154,7 @@
 			change = 1;
 		}
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return change;
 }
 
@@ -179,13 +181,13 @@
 	unsigned short val;
 	int i;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	for (i = 0; i < 2; i++) {
 		val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff;
 		val = val > ADC_MIN ? (val - ADC_MIN) : 0;
 		ucontrol->value.integer.value[i] = val;
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -195,7 +197,7 @@
 	unsigned short ovol, nvol;
 	int i, idx, change = 0;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	for (i = 0; i < 2; i++) {
 		nvol = ucontrol->value.integer.value[i];
 		nvol = nvol ? (nvol + ADC_MIN) : 0;
@@ -206,7 +208,7 @@
 			change = 1;
 		}
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return change;
 }
 
@@ -227,9 +229,9 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	int bit = kcontrol->private_value;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ucontrol->value.integer.value[0] = (wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -240,7 +242,7 @@
 	unsigned short oval, nval;
 	int change;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	nval = oval = wm_get(ice, WM_ADC_MUX);
 	if (ucontrol->value.integer.value[0])
 		nval |= (1 << bit);
@@ -250,7 +252,7 @@
 	if (change) {
 		wm_put(ice, WM_ADC_MUX, nval);
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -270,9 +272,9 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -282,7 +284,7 @@
 	unsigned short val, oval;
 	int change = 0;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	val = oval = wm_get(ice, WM_OUT_MUX);
 	if (ucontrol->value.integer.value[0])
 		val |= 0x04;
@@ -292,7 +294,7 @@
 		wm_put(ice, WM_OUT_MUX, val);
 		change = 1;
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return change;
 }
 
@@ -312,9 +314,9 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -324,7 +326,7 @@
 	unsigned short val, oval;
 	int change = 0;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	oval = wm_get(ice, WM_DAC_CTRL1);
 	val = oval & 0x0f;
 	if (ucontrol->value.integer.value[0])
@@ -336,7 +338,7 @@
 		wm_put_nocache(ice, WM_DAC_CTRL1, val);
 		change = 1;
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return change;
 }
 
@@ -449,9 +451,9 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ucontrol->value.enumerated.item[0] = ice->gpio.saved[0];
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -461,14 +463,14 @@
 	unsigned char val;
 	int change = 0;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	if (ucontrol->value.enumerated.item[0] != ice->gpio.saved[0]) {
 		ice->gpio.saved[0] = ucontrol->value.enumerated.item[0] & 3;
 		val = 0x80 | (ice->gpio.saved[0] << 3);
 		spi_write(ice, CS_DEV, 0x04, val);
 		change = 1;
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -488,10 +490,10 @@
 static int pontis_gpio_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	/* 4-7 reserved */
 	ucontrol->value.integer.value[0] = (~ice->gpio.write_mask & 0xffff) | 0x00f0;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 	
@@ -500,22 +502,22 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned int val;
 	int changed;
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	/* 4-7 reserved */
 	val = (~ucontrol->value.integer.value[0] & 0xffff) | 0x00f0;
 	changed = val != ice->gpio.write_mask;
 	ice->gpio.write_mask = val;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return changed;
 }
 
 static int pontis_gpio_dir_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	/* 4-7 reserved */
 	ucontrol->value.integer.value[0] = ice->gpio.direction & 0xff0f;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 	
@@ -524,23 +526,23 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned int val;
 	int changed;
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	/* 4-7 reserved */
 	val = ucontrol->value.integer.value[0] & 0xff0f;
 	changed = (val != ice->gpio.direction);
 	ice->gpio.direction = val;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return changed;
 }
 
 static int pontis_gpio_data_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
 	snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);
 	ucontrol->value.integer.value[0] = snd_ice1712_gpio_read(ice) & 0xffff;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -549,7 +551,7 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned int val, nval;
 	int changed = 0;
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
 	snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);
 	val = snd_ice1712_gpio_read(ice) & 0xffff;
@@ -558,7 +560,7 @@
 		snd_ice1712_gpio_write(ice, nval);
 		changed = 1;
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return changed;
 }
 
@@ -651,14 +653,14 @@
 	struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
 	char line[64];
 	unsigned int reg, val;
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	while (!snd_info_get_line(buffer, line, sizeof(line))) {
 		if (sscanf(line, "%x %x", &reg, &val) != 2)
 			continue;
 		if (reg <= 0x17 && val <= 0xffff)
 			wm_put(ice, reg, val);
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
@@ -666,12 +668,12 @@
 	struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
 	int reg, val;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	for (reg = 0; reg <= 0x17; reg++) {
 		val = wm_get(ice, reg);
 		snd_iprintf(buffer, "%02x = %04x\n", reg, val);
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 static void wm_proc_init(struct snd_ice1712 *ice)
@@ -690,14 +692,14 @@
 	struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
 	int reg, val;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	for (reg = 0; reg <= 0x26; reg++) {
 		val = spi_read(ice, CS_DEV, reg);
 		snd_iprintf(buffer, "%02x = %02x\n", reg, val);
 	}
 	val = spi_read(ice, CS_DEV, 0x7f);
 	snd_iprintf(buffer, "%02x = %02x\n", 0x7f, val);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 static void cs_proc_init(struct snd_ice1712 *ice)
diff -urN oldtree/sound/pci/intel8x0.c newtree/sound/pci/intel8x0.c
--- oldtree/sound/pci/intel8x0.c	2006-02-19 11:41:07.086265824 +0000
+++ newtree/sound/pci/intel8x0.c	2006-02-21 15:58:11.503397776 +0000
@@ -178,6 +178,8 @@
 #define   ICH_SAMPLE_CAP	0x00c00000	/* ICH4: sample capability bits (RO) */
 #define   ICH_SAMPLE_16_20	0x00400000	/* ICH4: 16- and 20-bit samples */
 #define   ICH_MULTICHAN_CAP	0x00300000	/* ICH4: multi-channel capability bits (RO) */
+#define   ICH_SIS_TRI		0x00080000	/* SIS: tertiary resume irq */
+#define   ICH_SIS_TCR		0x00040000	/* SIS: tertiary codec ready */
 #define   ICH_MD3		0x00020000	/* modem power down semaphore */
 #define   ICH_AD3		0x00010000	/* audio power down semaphore */
 #define   ICH_RCS		0x00008000	/* read completion status */
@@ -398,6 +400,10 @@
 	struct snd_ac97_bus *ac97_bus;
 	struct snd_ac97 *ac97[3];
 	unsigned int ac97_sdin[3];
+	unsigned int max_codecs, ncodecs;
+	unsigned int *codec_bit;
+	unsigned int codec_isr_bits;
+	unsigned int codec_ready_bits;
 
 	spinlock_t reg_lock;
 	
@@ -516,18 +522,6 @@
  * access to AC97 codec via normal i/o (for ICH and SIS7012)
  */
 
-/* return the GLOB_STA bit for the corresponding codec */
-static unsigned int get_ich_codec_bit(struct intel8x0 *chip, unsigned int codec)
-{
-	static unsigned int codec_bit[3] = {
-		ICH_PCR, ICH_SCR, ICH_TCR
-	};
-	snd_assert(codec < 3, return ICH_PCR);
-	if (chip->device_type == DEVICE_INTEL_ICH4)
-		codec = chip->ac97_sdin[codec];
-	return codec_bit[codec];
-}
-
 static int snd_intel8x0_codec_semaphore(struct intel8x0 *chip, unsigned int codec)
 {
 	int time;
@@ -537,9 +531,9 @@
 	if (chip->in_sdin_init) {
 		/* we don't know the ready bit assignment at the moment */
 		/* so we check any */
-		codec = ICH_PCR | ICH_SCR | ICH_TCR;
+		codec = chip->codec_isr_bits;
 	} else {
-		codec = get_ich_codec_bit(chip, codec);
+		codec = chip->codec_bit[chip->ac97_sdin[codec]];
 	}
 
 	/* codec ready ? */
@@ -596,7 +590,7 @@
 		if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) {
 			/* reset RCS and preserve other R/WC bits */
 			iputdword(chip, ICHREG(GLOB_STA), tmp &
-				  ~(ICH_SRI|ICH_PRI|ICH_TRI|ICH_GSCI));
+				  ~(chip->codec_ready_bits | ICH_GSCI));
 			if (! chip->in_ac97_init)
 				snd_printk(KERN_ERR "codec_read %d: read timeout for register 0x%x\n", ac97->num, reg);
 			res = 0xffff;
@@ -605,7 +599,8 @@
 	return res;
 }
 
-static void snd_intel8x0_codec_read_test(struct intel8x0 *chip, unsigned int codec)
+static void __devinit snd_intel8x0_codec_read_test(struct intel8x0 *chip,
+						   unsigned int codec)
 {
 	unsigned int tmp;
 
@@ -614,7 +609,7 @@
 		if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) {
 			/* reset RCS and preserve other R/WC bits */
 			iputdword(chip, ICHREG(GLOB_STA), tmp &
-				  ~(ICH_SRI|ICH_PRI|ICH_TRI|ICH_GSCI));
+				  ~(chip->codec_ready_bits | ICH_GSCI));
 		}
 	}
 }
@@ -2078,23 +2073,24 @@
 	if (chip->device_type != DEVICE_ALI) {
 		glob_sta = igetdword(chip, ICHREG(GLOB_STA));
 		ops = &standard_bus_ops;
-		if (chip->device_type == DEVICE_INTEL_ICH4) {
-			codecs = 0;
-			if (glob_sta & ICH_PCR)
-				codecs++;
-			if (glob_sta & ICH_SCR)
-				codecs++;
-			if (glob_sta & ICH_TCR)
-				codecs++;
-			chip->in_sdin_init = 1;
-			for (i = 0; i < codecs; i++) {
-				snd_intel8x0_codec_read_test(chip, i);
-				chip->ac97_sdin[i] = igetbyte(chip, ICHREG(SDM)) & ICH_LDI_MASK;
-			}
-			chip->in_sdin_init = 0;
-		} else {
-			codecs = glob_sta & ICH_SCR ? 2 : 1;
-		}
+		chip->in_sdin_init = 1;
+		codecs = 0;
+		for (i = 0; i < chip->max_codecs; i++) {
+			if (! (glob_sta & chip->codec_bit[i]))
+				continue;
+			if (chip->device_type == DEVICE_INTEL_ICH4) {
+				snd_intel8x0_codec_read_test(chip, codecs);
+				chip->ac97_sdin[codecs] =
+					igetbyte(chip, ICHREG(SDM)) & ICH_LDI_MASK;
+				snd_assert(chip->ac97_sdin[codecs] < 3,
+					   chip->ac97_sdin[codecs] = 0);
+			} else
+				chip->ac97_sdin[codecs] = i;
+			codecs++;
+		}
+		chip->in_sdin_init = 0;
+		if (! codecs)
+			codecs = 1;
 	} else {
 		ops = &ali_bus_ops;
 		codecs = 1;
@@ -2120,6 +2116,7 @@
 	else
 		pbus->dra = 1;
 	chip->ac97_bus = pbus;
+	chip->ncodecs = codecs;
 
 	ac97.pci = chip->pci;
 	for (i = 0; i < codecs; i++) {
@@ -2264,7 +2261,7 @@
 		end_time = jiffies + HZ;
 		do {
 			status = igetdword(chip, ICHREG(GLOB_STA)) &
-				(ICH_PCR | ICH_SCR | ICH_TCR);
+				chip->codec_isr_bits;
 			if (status)
 				break;
 			schedule_timeout_uninterruptible(1);
@@ -2276,32 +2273,27 @@
 			return -EIO;
 		}
 
-		if (chip->device_type == DEVICE_INTEL_ICH4)
-			/* ICH4 can have three codecs */
-			nstatus = ICH_PCR | ICH_SCR | ICH_TCR;
-		else
-			/* others up to two codecs */
-			nstatus = ICH_PCR | ICH_SCR;
-
 		/* wait for other codecs ready status. */
 		end_time = jiffies + HZ / 4;
-		while (status != nstatus && time_after_eq(end_time, jiffies)) {
+		while (status != chip->codec_isr_bits &&
+		       time_after_eq(end_time, jiffies)) {
 			schedule_timeout_uninterruptible(1);
-			status |= igetdword(chip, ICHREG(GLOB_STA)) & nstatus;
+			status |= igetdword(chip, ICHREG(GLOB_STA)) &
+				chip->codec_isr_bits;
 		}
 
 	} else {
 		/* resume phase */
 		int i;
 		status = 0;
-		for (i = 0; i < 3; i++)
+		for (i = 0; i < chip->ncodecs; i++)
 			if (chip->ac97[i])
-				status |= get_ich_codec_bit(chip, i);
+				status |= chip->codec_bit[chip->ac97_sdin[i]];
 		/* wait until all the probed codecs are ready */
 		end_time = jiffies + HZ;
 		do {
 			nstatus = igetdword(chip, ICHREG(GLOB_STA)) &
-				(ICH_PCR | ICH_SCR | ICH_TCR);
+				chip->codec_isr_bits;
 			if (status == nstatus)
 				break;
 			schedule_timeout_uninterruptible(1);
@@ -2447,7 +2439,7 @@
 			}
 		}
 	}
-	for (i = 0; i < 3; i++)
+	for (i = 0; i < chip->ncodecs; i++)
 		snd_ac97_suspend(chip->ac97[i]);
 	if (chip->device_type == DEVICE_INTEL_ICH4)
 		chip->sdm_saved = igetbyte(chip, ICHREG(SDM));
@@ -2488,7 +2480,7 @@
 	if (chip->fix_nocache)
 		fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1);
 
-	for (i = 0; i < 3; i++)
+	for (i = 0; i < chip->ncodecs; i++)
 		snd_ac97_resume(chip->ac97[i]);
 
 	/* refill nocache */
@@ -2619,12 +2611,20 @@
 	snd_iprintf(buffer, "Global status         : 0x%08x\n", tmp);
 	if (chip->device_type == DEVICE_INTEL_ICH4)
 		snd_iprintf(buffer, "SDM                   : 0x%08x\n", igetdword(chip, ICHREG(SDM)));
-	snd_iprintf(buffer, "AC'97 codecs ready    :%s%s%s%s\n",
-			tmp & ICH_PCR ? " primary" : "",
-			tmp & ICH_SCR ? " secondary" : "",
-			tmp & ICH_TCR ? " tertiary" : "",
-			(tmp & (ICH_PCR | ICH_SCR | ICH_TCR)) == 0 ? " none" : "");
-	if (chip->device_type == DEVICE_INTEL_ICH4)
+	snd_iprintf(buffer, "AC'97 codecs ready    :");
+	if (tmp & chip->codec_isr_bits) {
+		int i;
+		static const char *codecs[3] = {
+			"primary", "secondary", "tertiary"
+		};
+		for (i = 0; i < chip->max_codecs; i++)
+			if (tmp & chip->codec_bit[i])
+				snd_iprintf(buffer, " %s", codecs[i]);
+	} else
+		snd_iprintf(buffer, " none");
+	snd_iprintf(buffer, "\n");
+	if (chip->device_type == DEVICE_INTEL_ICH4 ||
+	    chip->device_type == DEVICE_SIS)
 		snd_iprintf(buffer, "AC'97 codecs SDIN     : %i %i %i\n",
 			chip->ac97_sdin[0],
 			chip->ac97_sdin[1],
@@ -2653,6 +2653,13 @@
 	unsigned int offset;
 };
 
+static unsigned int ich_codec_bits[3] = {
+	ICH_PCR, ICH_SCR, ICH_TCR
+};
+static unsigned int sis_codec_bits[3] = {
+	ICH_PCR, ICH_SCR, ICH_SIS_TCR
+};
+
 static int __devinit snd_intel8x0_create(struct snd_card *card,
 					 struct pci_dev *pci,
 					 unsigned long device_type,
@@ -2835,6 +2842,29 @@
 	pci_set_master(pci);
 	synchronize_irq(chip->irq);
 
+	switch(chip->device_type) {
+	case DEVICE_INTEL_ICH4:
+		/* ICH4 can have three codecs */
+		chip->max_codecs = 3;
+		chip->codec_bit = ich_codec_bits;
+		chip->codec_ready_bits = ICH_PRI | ICH_SRI | ICH_TRI;
+		break;
+	case DEVICE_SIS:
+		/* recent SIS7012 can have three codecs */
+		chip->max_codecs = 3;
+		chip->codec_bit = sis_codec_bits;
+		chip->codec_ready_bits = ICH_PRI | ICH_SRI | ICH_SIS_TRI;
+		break;
+	default:
+		/* others up to two codecs */
+		chip->max_codecs = 2;
+		chip->codec_bit = ich_codec_bits;
+		chip->codec_ready_bits = ICH_PRI | ICH_SRI;
+		break;
+	}
+	for (i = 0; i < chip->max_codecs; i++)
+		chip->codec_isr_bits |= chip->codec_bit[i];
+
 	if ((err = snd_intel8x0_chip_init(chip, 1)) < 0) {
 		snd_intel8x0_free(chip);
 		return err;
diff -urN oldtree/sound/pci/korg1212/korg1212.c newtree/sound/pci/korg1212/korg1212.c
--- oldtree/sound/pci/korg1212/korg1212.c	2006-02-19 11:41:07.092264912 +0000
+++ newtree/sound/pci/korg1212/korg1212.c	2006-02-21 15:58:11.506397320 +0000
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/wait.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 
 #include <sound/core.h>
 #include <sound/info.h>
@@ -325,7 +326,7 @@
         int irq;
 
         spinlock_t    lock;
-	struct semaphore open_mutex;
+	struct mutex open_mutex;
 
 	struct timer_list timer;	/* timer callback for checking ack of stop request */
 	int stop_pending_cnt;		/* counter for stop pending check */
@@ -667,13 +668,13 @@
 {
 	K1212_DEBUG_PRINTK("K1212_DEBUG: OpenCard [%s] %d\n",
 			   stateName[korg1212->cardState], korg1212->opencnt);
-	down(&korg1212->open_mutex);
+	mutex_lock(&korg1212->open_mutex);
         if (korg1212->opencnt++ == 0) {
 		snd_korg1212_TurnOffIdleMonitor(korg1212);
 		snd_korg1212_setCardState(korg1212, K1212_STATE_OPEN);
 	}
 
-	up(&korg1212->open_mutex);
+	mutex_unlock(&korg1212->open_mutex);
         return 1;
 }
 
@@ -682,9 +683,9 @@
 	K1212_DEBUG_PRINTK("K1212_DEBUG: CloseCard [%s] %d\n",
 			   stateName[korg1212->cardState], korg1212->opencnt);
 
-	down(&korg1212->open_mutex);
+	mutex_lock(&korg1212->open_mutex);
 	if (--(korg1212->opencnt)) {
-		up(&korg1212->open_mutex);
+		mutex_unlock(&korg1212->open_mutex);
 		return 0;
 	}
 
@@ -695,7 +696,7 @@
 			K1212_DEBUG_PRINTK("K1212_DEBUG: CloseCard - RC = %d [%s]\n",
 					   rc, stateName[korg1212->cardState]);
 		if (rc != K1212_CMDRET_Success) {
-			up(&korg1212->open_mutex);
+			mutex_unlock(&korg1212->open_mutex);
                         return 0;
 		}
         } else if (korg1212->cardState > K1212_STATE_SETUP) {
@@ -707,7 +708,7 @@
                 snd_korg1212_setCardState(korg1212, K1212_STATE_READY);
 	}
 
-	up(&korg1212->open_mutex);
+	mutex_unlock(&korg1212->open_mutex);
         return 0;
 }
 
@@ -2179,7 +2180,7 @@
 
         init_waitqueue_head(&korg1212->wait);
         spin_lock_init(&korg1212->lock);
-	init_MUTEX(&korg1212->open_mutex);
+	mutex_init(&korg1212->open_mutex);
 	init_timer(&korg1212->timer);
 	korg1212->timer.function = snd_korg1212_timer_func;
 	korg1212->timer.data = (unsigned long)korg1212;
diff -urN oldtree/sound/pci/mixart/mixart.c newtree/sound/pci/mixart/mixart.c
--- oldtree/sound/pci/mixart/mixart.c	2006-02-19 11:41:07.096264304 +0000
+++ newtree/sound/pci/mixart/mixart.c	2006-02-21 15:58:11.507397168 +0000
@@ -26,6 +26,7 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/info.h>
@@ -589,7 +590,7 @@
 	/*  set up format for the stream */
 	format = params_format(hw);
 
-	down(&mgr->setup_mutex);
+	mutex_lock(&mgr->setup_mutex);
 
 	/* update the stream levels */
 	if( stream->pcm_number <= MIXART_PCM_DIGITAL ) {
@@ -628,7 +629,7 @@
 				bufferinfo[i].available_length,
 				subs->number);
 	}
-	up(&mgr->setup_mutex);
+	mutex_unlock(&mgr->setup_mutex);
 
 	return err;
 }
@@ -700,7 +701,7 @@
 	int err = 0;
 	int pcm_number;
 
-	down(&mgr->setup_mutex);
+	mutex_lock(&mgr->setup_mutex);
 
 	if ( pcm == chip->pcm ) {
 		pcm_number = MIXART_PCM_ANALOG;
@@ -758,7 +759,7 @@
 	}
 
  _exit_open:
-	up(&mgr->setup_mutex);
+	mutex_unlock(&mgr->setup_mutex);
 
 	return err;
 }
@@ -775,7 +776,7 @@
 	int err = 0;
 	int pcm_number;
 
-	down(&mgr->setup_mutex);
+	mutex_lock(&mgr->setup_mutex);
 
 	if ( pcm == chip->pcm ) {
 		pcm_number = MIXART_PCM_ANALOG;
@@ -836,7 +837,7 @@
 	}
 
  _exit_open:
-	up(&mgr->setup_mutex);
+	mutex_unlock(&mgr->setup_mutex);
 
 	return err;
 }
@@ -849,7 +850,7 @@
 	struct mixart_mgr *mgr = chip->mgr;
 	struct mixart_stream *stream = subs->runtime->private_data;
 
-	down(&mgr->setup_mutex);
+	mutex_lock(&mgr->setup_mutex);
 
 	snd_printdd("snd_mixart_close C%d/P%d/Sub%d\n", chip->chip_idx, stream->pcm_number, subs->number);
 
@@ -868,7 +869,7 @@
 	stream->status    = MIXART_STREAM_STATUS_FREE;
 	stream->substream = NULL;
 
-	up(&mgr->setup_mutex);
+	mutex_unlock(&mgr->setup_mutex);
 	return 0;
 }
 
@@ -1335,12 +1336,12 @@
 	mgr->msg_fifo_writeptr = 0;
 
 	spin_lock_init(&mgr->msg_lock);
-	init_MUTEX(&mgr->msg_mutex);
+	mutex_init(&mgr->msg_mutex);
 	init_waitqueue_head(&mgr->msg_sleep);
 	atomic_set(&mgr->msg_processed, 0);
 
 	/* init setup mutex*/
-	init_MUTEX(&mgr->setup_mutex);
+	mutex_init(&mgr->setup_mutex);
 
 	/* init message taslket */
 	tasklet_init(&mgr->msg_taskq, snd_mixart_msg_tasklet, (unsigned long) mgr);
diff -urN oldtree/sound/pci/mixart/mixart.h newtree/sound/pci/mixart/mixart.h
--- oldtree/sound/pci/mixart/mixart.h	2006-02-19 11:41:07.097264152 +0000
+++ newtree/sound/pci/mixart/mixart.h	2006-02-21 15:58:11.508397016 +0000
@@ -24,6 +24,7 @@
 #define __SOUND_MIXART_H
 
 #include <linux/interrupt.h>
+#include <linux/mutex.h>
 #include <sound/pcm.h>
 
 #define MIXART_DRIVER_VERSION	0x000100	/* 0.1.0 */
@@ -92,9 +93,9 @@
 
 	spinlock_t lock;              /* interrupt spinlock */
 	spinlock_t msg_lock;          /* mailbox spinlock */
-	struct semaphore msg_mutex;   /* mutex for blocking_requests */
+	struct mutex msg_mutex;   /* mutex for blocking_requests */
 
-	struct semaphore setup_mutex; /* mutex used in hw_params, open and close */
+	struct mutex setup_mutex; /* mutex used in hw_params, open and close */
 
 	/* hardware interface */
 	unsigned int dsp_loaded;      /* bit flags of loaded dsp indices */
@@ -107,7 +108,7 @@
 	int sample_rate;
 	int ref_count_rate;
 
-	struct semaphore mixer_mutex; /* mutex for mixer */
+	struct mutex mixer_mutex; /* mutex for mixer */
 
 };
 
diff -urN oldtree/sound/pci/mixart/mixart_core.c newtree/sound/pci/mixart/mixart_core.c
--- oldtree/sound/pci/mixart/mixart_core.c	2006-02-19 11:41:07.098264000 +0000
+++ newtree/sound/pci/mixart/mixart_core.c	2006-02-21 15:58:11.508397016 +0000
@@ -22,6 +22,8 @@
 
 #include <sound/driver.h>
 #include <linux/interrupt.h>
+#include <linux/mutex.h>
+
 #include <asm/io.h>
 #include <sound/core.h>
 #include "mixart.h"
@@ -239,7 +241,7 @@
 	wait_queue_t wait;
 	long timeout;
 
-	down(&mgr->msg_mutex);
+	mutex_lock(&mgr->msg_mutex);
 
 	init_waitqueue_entry(&wait, current);
 
@@ -248,7 +250,7 @@
 	err = send_msg(mgr, request, max_resp_size, 1, &msg_frame);  /* send and mark the answer pending */
 	if (err) {
 		spin_unlock_irq(&mgr->msg_lock);
-		up(&mgr->msg_mutex);
+		mutex_unlock(&mgr->msg_mutex);
 		return err;
 	}
 
@@ -260,7 +262,7 @@
 
 	if (! timeout) {
 		/* error - no ack */
-		up(&mgr->msg_mutex);
+		mutex_unlock(&mgr->msg_mutex);
 		snd_printk(KERN_ERR "error: no reponse on msg %x\n", msg_frame);
 		return -EIO;
 	}
@@ -276,7 +278,7 @@
 	if( request->message_id != resp.message_id )
 		snd_printk(KERN_ERR "REPONSE ERROR!\n");
 
-	up(&mgr->msg_mutex);
+	mutex_unlock(&mgr->msg_mutex);
 	return err;
 }
 
@@ -292,7 +294,7 @@
 	snd_assert((notif_event & MSG_TYPE_MASK) == MSG_TYPE_NOTIFY, return -EINVAL);
 	snd_assert((notif_event & MSG_CANCEL_NOTIFY_MASK) == 0, return -EINVAL);
 
-	down(&mgr->msg_mutex);
+	mutex_lock(&mgr->msg_mutex);
 
 	init_waitqueue_entry(&wait, current);
 
@@ -301,7 +303,7 @@
 	err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, &notif_event);  /* send and mark the notification event pending */
 	if(err) {
 		spin_unlock_irq(&mgr->msg_lock);
-		up(&mgr->msg_mutex);
+		mutex_unlock(&mgr->msg_mutex);
 		return err;
 	}
 
@@ -313,12 +315,12 @@
 
 	if (! timeout) {
 		/* error - no ack */
-		up(&mgr->msg_mutex);
+		mutex_unlock(&mgr->msg_mutex);
 		snd_printk(KERN_ERR "error: notification %x not received\n", notif_event);
 		return -EIO;
 	}
 
-	up(&mgr->msg_mutex);
+	mutex_unlock(&mgr->msg_mutex);
 	return 0;
 }
 
diff -urN oldtree/sound/pci/mixart/mixart_mixer.c newtree/sound/pci/mixart/mixart_mixer.c
--- oldtree/sound/pci/mixart/mixart_mixer.c	2006-02-19 11:41:07.105262936 +0000
+++ newtree/sound/pci/mixart/mixart_mixer.c	2006-02-21 15:58:11.510396712 +0000
@@ -24,6 +24,8 @@
 #include <linux/time.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include "mixart.h"
 #include "mixart_core.h"
@@ -353,7 +355,7 @@
 static int mixart_analog_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	if(kcontrol->private_value == 0) {	/* playback */
 		ucontrol->value.integer.value[0] = chip->analog_playback_volume[0];
 		ucontrol->value.integer.value[1] = chip->analog_playback_volume[1];
@@ -361,7 +363,7 @@
 		ucontrol->value.integer.value[0] = chip->analog_capture_volume[0];
 		ucontrol->value.integer.value[1] = chip->analog_capture_volume[1];
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -371,7 +373,7 @@
 	int changed = 0;
 	int is_capture, i;
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	is_capture = (kcontrol->private_value != 0);
 	for(i=0; i<2; i++) {
 		int  new_volume = ucontrol->value.integer.value[i];
@@ -382,7 +384,7 @@
 		}
 	}
 	if(changed)	mixart_update_analog_audio_level(chip, is_capture);
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -408,10 +410,10 @@
 {
 	struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->analog_playback_active[0];
 	ucontrol->value.integer.value[1] = chip->analog_playback_active[1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -419,7 +421,7 @@
 {
 	struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
 	int i, changed = 0;
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	for(i=0; i<2; i++) {
 		if(chip->analog_playback_active[i] != ucontrol->value.integer.value[i]) {
 			chip->analog_playback_active[i] = ucontrol->value.integer.value[i];
@@ -427,7 +429,7 @@
 		}
 	}
 	if(changed)	mixart_update_analog_audio_level(chip, 0); /* update playback levels */
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -817,7 +819,7 @@
 	int *stored_volume;
 	int is_capture = kcontrol->private_value & MIXART_VOL_REC_MASK;
 	int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK;
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	if(is_capture) {
 		if(is_aes)	stored_volume = chip->digital_capture_volume[1];	/* AES capture */
 		else		stored_volume = chip->digital_capture_volume[0];	/* analog capture */
@@ -828,7 +830,7 @@
 	}
 	ucontrol->value.integer.value[0] = stored_volume[0];
 	ucontrol->value.integer.value[1] = stored_volume[1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -841,7 +843,7 @@
 	int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK;
 	int* stored_volume;
 	int i;
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	if(is_capture) {
 		if(is_aes)	stored_volume = chip->digital_capture_volume[1];	/* AES capture */
 		else		stored_volume = chip->digital_capture_volume[0];	/* analog capture */
@@ -860,7 +862,7 @@
 		if(is_capture)	mixart_update_capture_stream_level(chip, is_aes);
 		else		mixart_update_playback_stream_level(chip, is_aes, idx);
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -880,12 +882,12 @@
 	struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
 	snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	if(kcontrol->private_value & MIXART_VOL_AES_MASK)	/* AES playback */
 		idx += MIXART_PLAYBACK_STREAMS;
 	ucontrol->value.integer.value[0] = chip->digital_playback_active[idx][0];
 	ucontrol->value.integer.value[1] = chip->digital_playback_active[idx][1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -897,7 +899,7 @@
 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
 	int i, j;
 	snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	j = idx;
 	if(is_aes)	j += MIXART_PLAYBACK_STREAMS;
 	for(i=0; i<2; i++) {
@@ -907,7 +909,7 @@
 		}
 	}
 	if(changed)	mixart_update_playback_stream_level(chip, is_aes, idx);
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -956,10 +958,10 @@
 static int mixart_monitor_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->monitoring_volume[0];
 	ucontrol->value.integer.value[1] = chip->monitoring_volume[1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -968,7 +970,7 @@
 	struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
 	int changed = 0;
 	int i;
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	for(i=0; i<2; i++) {
 		if(chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) {
 			chip->monitoring_volume[i] = ucontrol->value.integer.value[i];
@@ -976,7 +978,7 @@
 			changed = 1;
 		}
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -995,10 +997,10 @@
 static int mixart_monitor_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->monitoring_active[0];
 	ucontrol->value.integer.value[1] = chip->monitoring_active[1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -1007,7 +1009,7 @@
 	struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
 	int changed = 0;
 	int i;
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	for(i=0; i<2; i++) {
 		if(chip->monitoring_active[i] != ucontrol->value.integer.value[i]) {
 			chip->monitoring_active[i] = ucontrol->value.integer.value[i];
@@ -1029,7 +1031,7 @@
 		}
 	}
 
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return (changed != 0);
 }
 
@@ -1059,7 +1061,7 @@
 	struct snd_mixart *chip;
 	int err, i;
 
-	init_MUTEX(&mgr->mixer_mutex); /* can be in another place */
+	mutex_init(&mgr->mixer_mutex); /* can be in another place */
 
 	for(i=0; i<mgr->num_cards; i++) {
 		struct snd_kcontrol_new temp;
diff -urN oldtree/sound/pci/nm256/nm256.c newtree/sound/pci/nm256/nm256.c
--- oldtree/sound/pci/nm256/nm256.c	2006-02-19 11:41:07.107262632 +0000
+++ newtree/sound/pci/nm256/nm256.c	2006-02-21 15:58:11.511396560 +0000
@@ -32,6 +32,8 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -235,7 +237,7 @@
 	int irq_acks;
 	irqreturn_t (*interrupt)(int, void *, struct pt_regs *);
 	int badintrcount;		/* counter to check bogus interrupts */
-	struct semaphore irq_mutex;
+	struct mutex irq_mutex;
 
 	struct nm256_stream streams[2];
 
@@ -459,32 +461,32 @@
 /* acquire interrupt */
 static int snd_nm256_acquire_irq(struct nm256 *chip)
 {
-	down(&chip->irq_mutex);
+	mutex_lock(&chip->irq_mutex);
 	if (chip->irq < 0) {
 		if (request_irq(chip->pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ,
 				chip->card->driver, chip)) {
 			snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->pci->irq);
-			up(&chip->irq_mutex);
+			mutex_unlock(&chip->irq_mutex);
 			return -EBUSY;
 		}
 		chip->irq = chip->pci->irq;
 	}
 	chip->irq_acks++;
-	up(&chip->irq_mutex);
+	mutex_unlock(&chip->irq_mutex);
 	return 0;
 }
 
 /* release interrupt */
 static void snd_nm256_release_irq(struct nm256 *chip)
 {
-	down(&chip->irq_mutex);
+	mutex_lock(&chip->irq_mutex);
 	if (chip->irq_acks > 0)
 		chip->irq_acks--;
 	if (chip->irq_acks == 0 && chip->irq >= 0) {
 		free_irq(chip->irq, chip);
 		chip->irq = -1;
 	}
-	up(&chip->irq_mutex);
+	mutex_unlock(&chip->irq_mutex);
 }
 
 /*
@@ -1407,7 +1409,7 @@
 	chip->use_cache = use_cache;
 	spin_lock_init(&chip->reg_lock);
 	chip->irq = -1;
-	init_MUTEX(&chip->irq_mutex);
+	mutex_init(&chip->irq_mutex);
 
 	/* store buffer sizes in bytes */
 	chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize = playback_bufsize * 1024;
diff -urN oldtree/sound/pci/pcxhr/pcxhr.c newtree/sound/pci/pcxhr/pcxhr.c
--- oldtree/sound/pci/pcxhr/pcxhr.c	2006-02-19 11:41:07.110262176 +0000
+++ newtree/sound/pci/pcxhr/pcxhr.c	2006-02-21 15:58:11.513396256 +0000
@@ -28,6 +28,8 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/info.h>
@@ -518,7 +520,7 @@
 	struct timeval my_tv1, my_tv2;
 	do_gettimeofday(&my_tv1);
 #endif
-	down(&mgr->setup_mutex);
+	mutex_lock(&mgr->setup_mutex);
 
 	/* check the pipes concerned and build pipe_array */
 	for (i = 0; i < mgr->num_cards; i++) {
@@ -537,7 +539,7 @@
 		}
 	}
 	if (capture_mask == 0 && playback_mask == 0) {
-		up(&mgr->setup_mutex);
+		mutex_unlock(&mgr->setup_mutex);
 		snd_printk(KERN_ERR "pcxhr_trigger_tasklet : no pipes\n");
 		return;
 	}
@@ -548,7 +550,7 @@
 	/* synchronous stop of all the pipes concerned */
 	err = pcxhr_set_pipe_state(mgr,  playback_mask, capture_mask, 0);
 	if (err) {
-		up(&mgr->setup_mutex);
+		mutex_unlock(&mgr->setup_mutex);
 		snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error stop pipes (P%x C%x)\n",
 			   playback_mask, capture_mask);
 		return;
@@ -592,7 +594,7 @@
 	/* synchronous start of all the pipes concerned */
 	err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1);
 	if (err) {
-		up(&mgr->setup_mutex);
+		mutex_unlock(&mgr->setup_mutex);
 		snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error start pipes (P%x C%x)\n",
 			   playback_mask, capture_mask);
 		return;
@@ -619,7 +621,7 @@
 	}
 	spin_unlock_irqrestore(&mgr->lock, flags);
 
-	up(&mgr->setup_mutex);
+	mutex_unlock(&mgr->setup_mutex);
 
 #ifdef CONFIG_SND_DEBUG_DETECT
 	do_gettimeofday(&my_tv2);
@@ -728,7 +730,7 @@
 	}
 	*/
 
-	down(&mgr->setup_mutex);
+	mutex_lock(&mgr->setup_mutex);
 
 	do {
 		/* if the stream was stopped before, format and buffer were reset */
@@ -755,7 +757,7 @@
 		}
 	} while(0);	/* do only once (so we can use break instead of goto) */
 
-	up(&mgr->setup_mutex);
+	mutex_unlock(&mgr->setup_mutex);
 
 	return err;
 }
@@ -780,7 +782,7 @@
 	/*  set up format for the stream */
 	format = params_format(hw);
 
-	down(&mgr->setup_mutex);
+	mutex_lock(&mgr->setup_mutex);
 
 	stream->channels = channels;
 	stream->format = format;
@@ -789,7 +791,7 @@
 	/*
 	err = pcxhr_set_format(stream);
 	if(err) {
-		up(&mgr->setup_mutex);
+		mutex_unlock(&mgr->setup_mutex);
 		return err;
 	}
 	*/
@@ -801,7 +803,7 @@
 		err = pcxhr_update_r_buffer(stream);
 	}
 	*/
-	up(&mgr->setup_mutex);
+	mutex_unlock(&mgr->setup_mutex);
 
 	return err;
 }
@@ -847,7 +849,7 @@
 	struct pcxhr_stream    *stream;
 	int                 is_capture;
 
-	down(&mgr->setup_mutex);
+	mutex_lock(&mgr->setup_mutex);
 
 	/* copy the struct snd_pcm_hardware struct */
 	runtime->hw = pcxhr_caps;
@@ -871,7 +873,7 @@
 		/* streams in use */
 		snd_printk(KERN_ERR "pcxhr_open chip%d subs%d in use\n",
 			   chip->chip_idx, subs->number);
-		up(&mgr->setup_mutex);
+		mutex_unlock(&mgr->setup_mutex);
 		return -EBUSY;
 	}
 
@@ -887,7 +889,7 @@
 						     &external_rate) ||
 			    external_rate == 0) {
 				/* cannot detect the external clock rate */
-				up(&mgr->setup_mutex);
+				mutex_unlock(&mgr->setup_mutex);
 				return -EBUSY;
 			}
 			runtime->hw.rate_min = runtime->hw.rate_max = external_rate;
@@ -905,7 +907,7 @@
 
 	mgr->ref_count_rate++;
 
-	up(&mgr->setup_mutex);
+	mutex_unlock(&mgr->setup_mutex);
 	return 0;
 }
 
@@ -916,7 +918,7 @@
 	struct pcxhr_mgr *mgr = chip->mgr;
 	struct pcxhr_stream *stream = subs->runtime->private_data;
 
-	down(&mgr->setup_mutex);
+	mutex_lock(&mgr->setup_mutex);
 
 	snd_printdd("pcxhr_close chip%d subs%d\n", chip->chip_idx, subs->number);
 
@@ -929,7 +931,7 @@
 	stream->status    = PCXHR_STREAM_STATUS_FREE;
 	stream->substream = NULL;
 
-	up(&mgr->setup_mutex);
+	mutex_unlock(&mgr->setup_mutex);
 
 	return 0;
 }
@@ -1264,7 +1266,7 @@
 	spin_lock_init(&mgr->msg_lock);
 
 	/* init setup mutex*/
-	init_MUTEX(&mgr->setup_mutex);
+	mutex_init(&mgr->setup_mutex);
 
 	/* init taslket */
 	tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet, (unsigned long) mgr);
diff -urN oldtree/sound/pci/pcxhr/pcxhr.h newtree/sound/pci/pcxhr/pcxhr.h
--- oldtree/sound/pci/pcxhr/pcxhr.h	2006-02-19 11:41:07.110262176 +0000
+++ newtree/sound/pci/pcxhr/pcxhr.h	2006-02-21 15:58:11.514396104 +0000
@@ -24,6 +24,7 @@
 #define __SOUND_PCXHR_H
 
 #include <linux/interrupt.h>
+#include <linux/mutex.h>
 #include <sound/pcm.h>
 
 #define PCXHR_DRIVER_VERSION		0x000804	/* 0.8.4 */
@@ -76,8 +77,8 @@
 	spinlock_t lock;		/* interrupt spinlock */
 	spinlock_t msg_lock;		/* message spinlock */
 
-	struct semaphore setup_mutex;	/* mutex used in hw_params, open and close */
-	struct semaphore mixer_mutex;	/* mutex for mixer */
+	struct mutex setup_mutex;	/* mutex used in hw_params, open and close */
+	struct mutex mixer_mutex;	/* mutex for mixer */
 
 	/* hardware interface */
 	unsigned int dsp_loaded;	/* bit flags of loaded dsp indices */
diff -urN oldtree/sound/pci/pcxhr/pcxhr_core.c newtree/sound/pci/pcxhr/pcxhr_core.c
--- oldtree/sound/pci/pcxhr/pcxhr_core.c	2006-02-19 11:41:07.112261872 +0000
+++ newtree/sound/pci/pcxhr/pcxhr_core.c	2006-02-21 15:58:11.515395952 +0000
@@ -1176,7 +1176,7 @@
 		mgr->dsp_time_last = dsp_time_new;
 
 		if (timer_toggle == mgr->timer_toggle)
-			snd_printk(KERN_ERR "ERROR TIMER TOGGLE\n");
+			snd_printdd("ERROR TIMER TOGGLE\n");
 		mgr->timer_toggle = timer_toggle;
 
 		reg &= ~PCXHR_IRQ_TIMER;
diff -urN oldtree/sound/pci/pcxhr/pcxhr_mixer.c newtree/sound/pci/pcxhr/pcxhr_mixer.c
--- oldtree/sound/pci/pcxhr/pcxhr_mixer.c	2006-02-19 11:41:07.116261264 +0000
+++ newtree/sound/pci/pcxhr/pcxhr_mixer.c	2006-02-21 15:58:11.516395800 +0000
@@ -25,6 +25,7 @@
 #include <linux/time.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include "pcxhr.h"
 #include "pcxhr_hwdep.h"
@@ -92,7 +93,7 @@
 				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	if (kcontrol->private_value == 0) {	/* playback */
 		ucontrol->value.integer.value[0] = chip->analog_playback_volume[0];
 		ucontrol->value.integer.value[1] = chip->analog_playback_volume[1];
@@ -100,7 +101,7 @@
 		ucontrol->value.integer.value[0] = chip->analog_capture_volume[0];
 		ucontrol->value.integer.value[1] = chip->analog_capture_volume[1];
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -111,7 +112,7 @@
 	int changed = 0;
 	int is_capture, i;
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	is_capture = (kcontrol->private_value != 0);
 	for (i = 0; i < 2; i++) {
 		int  new_volume = ucontrol->value.integer.value[i];
@@ -123,7 +124,7 @@
 			pcxhr_update_analog_audio_level(chip, is_capture, i);
 		}
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -150,10 +151,10 @@
 {
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->analog_playback_active[0];
 	ucontrol->value.integer.value[1] = chip->analog_playback_active[1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -162,7 +163,7 @@
 {
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
 	int i, changed = 0;
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	for(i = 0; i < 2; i++) {
 		if (chip->analog_playback_active[i] != ucontrol->value.integer.value[i]) {
 			chip->analog_playback_active[i] = ucontrol->value.integer.value[i];
@@ -170,7 +171,7 @@
 			pcxhr_update_analog_audio_level(chip, 0, i);	/* update playback levels */
 		}
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -299,14 +300,14 @@
 	int *stored_volume;
 	int is_capture = kcontrol->private_value;
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	if (is_capture)
 		stored_volume = chip->digital_capture_volume;		/* digital capture */
 	else
 		stored_volume = chip->digital_playback_volume[idx];	/* digital playback */
 	ucontrol->value.integer.value[0] = stored_volume[0];
 	ucontrol->value.integer.value[1] = stored_volume[1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -320,7 +321,7 @@
 	int *stored_volume;
 	int i;
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	if (is_capture)
 		stored_volume = chip->digital_capture_volume;		/* digital capture */
 	else
@@ -335,7 +336,7 @@
 	}
 	if (! is_capture && changed)
 		pcxhr_update_playback_stream_level(chip, idx);	/* update playback volume */
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -356,10 +357,10 @@
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->digital_playback_active[idx][0];
 	ucontrol->value.integer.value[1] = chip->digital_playback_active[idx][1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -370,7 +371,7 @@
 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
 	int i, j;
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	j = idx;
 	for (i = 0; i < 2; i++) {
 		if (chip->digital_playback_active[j][i] != ucontrol->value.integer.value[i]) {
@@ -380,7 +381,7 @@
 	}
 	if (changed)
 		pcxhr_update_playback_stream_level(chip, idx);
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -402,10 +403,10 @@
 				 struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->monitoring_volume[0];
 	ucontrol->value.integer.value[1] = chip->monitoring_volume[1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -416,7 +417,7 @@
 	int changed = 0;
 	int i;
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	for (i = 0; i < 2; i++) {
 		if (chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) {
 			chip->monitoring_volume[i] = ucontrol->value.integer.value[i];
@@ -426,7 +427,7 @@
 			changed = 1;
 		}
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -446,10 +447,10 @@
 				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->monitoring_active[0];
 	ucontrol->value.integer.value[1] = chip->monitoring_active[1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -460,7 +461,7 @@
 	int changed = 0;
 	int i;
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	for (i = 0; i < 2; i++) {
 		if (chip->monitoring_active[i] != ucontrol->value.integer.value[i]) {
 			chip->monitoring_active[i] = ucontrol->value.integer.value[i];
@@ -474,7 +475,7 @@
 		/* update right monitoring volume and mute */
 		pcxhr_update_audio_pipe_level(chip, 0, 1);
 
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return (changed != 0);
 }
 
@@ -571,13 +572,13 @@
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
 	int ret = 0;
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) {
 		chip->audio_capture_source = ucontrol->value.enumerated.item[0];
 		pcxhr_set_audio_source(chip);
 		ret = 1;
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return ret;
 }
 
@@ -636,9 +637,9 @@
 	struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol);
 	int rate, ret = 0;
 
-	down(&mgr->mixer_mutex);
+	mutex_lock(&mgr->mixer_mutex);
 	if (mgr->use_clock_type != ucontrol->value.enumerated.item[0]) {
-		down(&mgr->setup_mutex);
+		mutex_lock(&mgr->setup_mutex);
 		mgr->use_clock_type = ucontrol->value.enumerated.item[0];
 		if (mgr->use_clock_type)
 			pcxhr_get_external_clock(mgr, mgr->use_clock_type, &rate);
@@ -649,10 +650,10 @@
 			if (mgr->sample_rate)
 				mgr->sample_rate = rate;
 		}
-		up(&mgr->setup_mutex);
+		mutex_unlock(&mgr->setup_mutex);
 		ret = 1;	/* return 1 even if the set was not done. ok ? */
 	}
-	up(&mgr->mixer_mutex);
+	mutex_unlock(&mgr->mixer_mutex);
 	return ret;
 }
 
@@ -685,7 +686,7 @@
 	struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol);
 	int i, err, rate;
 
-	down(&mgr->mixer_mutex);
+	mutex_lock(&mgr->mixer_mutex);
 	for(i = 0; i < 3 + mgr->capture_chips; i++) {
 		if (i == PCXHR_CLOCK_TYPE_INTERNAL)
 			rate = mgr->sample_rate_real;
@@ -696,7 +697,7 @@
 		}
 		ucontrol->value.integer.value[i] = rate;
 	}
-	up(&mgr->mixer_mutex);
+	mutex_unlock(&mgr->mixer_mutex);
 	return 0;
 }
 
@@ -765,7 +766,7 @@
 	unsigned char aes_bits;
 	int i, err;
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	for(i = 0; i < 5; i++) {
 		if (kcontrol->private_value == 0)	/* playback */
 			aes_bits = chip->aes_bits[i];
@@ -776,7 +777,7 @@
 		}
 		ucontrol->value.iec958.status[i] = aes_bits;
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
         return 0;
 }
 
@@ -828,14 +829,14 @@
 	int i, changed = 0;
 
 	/* playback */
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	for (i = 0; i < 5; i++) {
 		if (ucontrol->value.iec958.status[i] != chip->aes_bits[i]) {
 			pcxhr_iec958_update_byte(chip, i, ucontrol->value.iec958.status[i]);
 			changed = 1;
 		}
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -916,7 +917,7 @@
 	struct snd_pcxhr *chip;
 	int err, i;
 
-	init_MUTEX(&mgr->mixer_mutex); /* can be in another place */
+	mutex_init(&mgr->mixer_mutex); /* can be in another place */
 
 	for (i = 0; i < mgr->num_cards; i++) {
 		struct snd_kcontrol_new temp;
diff -urN oldtree/sound/pci/trident/trident_memory.c newtree/sound/pci/trident/trident_memory.c
--- oldtree/sound/pci/trident/trident_memory.c	2006-02-19 11:41:07.149256248 +0000
+++ newtree/sound/pci/trident/trident_memory.c	2006-02-21 15:58:11.518395496 +0000
@@ -27,6 +27,8 @@
 #include <asm/io.h>
 #include <linux/pci.h>
 #include <linux/time.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/trident.h>
 
@@ -201,16 +203,16 @@
 
 	
 
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	blk = search_empty(hdr, runtime->dma_bytes);
 	if (blk == NULL) {
-		up(&hdr->block_mutex);
+		mutex_unlock(&hdr->block_mutex);
 		return NULL;
 	}
 	if (lastpg(blk) - firstpg(blk) >= sgbuf->pages) {
 		snd_printk(KERN_ERR "page calculation doesn't match: allocated pages = %d, trident = %d/%d\n", sgbuf->pages, firstpg(blk), lastpg(blk));
 		__snd_util_mem_free(hdr, blk);
-		up(&hdr->block_mutex);
+		mutex_unlock(&hdr->block_mutex);
 		return NULL;
 	}
 			   
@@ -221,12 +223,12 @@
 		unsigned long ptr = (unsigned long)sgbuf->table[idx].buf;
 		if (! is_valid_page(addr)) {
 			__snd_util_mem_free(hdr, blk);
-			up(&hdr->block_mutex);
+			mutex_unlock(&hdr->block_mutex);
 			return NULL;
 		}
 		set_tlb_bus(trident, page, ptr, addr);
 	}
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return blk;
 }
 
@@ -248,10 +250,10 @@
 	hdr = trident->tlb.memhdr;
 	snd_assert(hdr != NULL, return NULL);
 
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	blk = search_empty(hdr, runtime->dma_bytes);
 	if (blk == NULL) {
-		up(&hdr->block_mutex);
+		mutex_unlock(&hdr->block_mutex);
 		return NULL;
 	}
 			   
@@ -262,12 +264,12 @@
 	     ptr += SNDRV_TRIDENT_PAGE_SIZE, addr += SNDRV_TRIDENT_PAGE_SIZE) {
 		if (! is_valid_page(addr)) {
 			__snd_util_mem_free(hdr, blk);
-			up(&hdr->block_mutex);
+			mutex_unlock(&hdr->block_mutex);
 			return NULL;
 		}
 		set_tlb_bus(trident, page, ptr, addr);
 	}
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return blk;
 }
 
@@ -300,13 +302,13 @@
 	snd_assert(blk != NULL, return -EINVAL);
 
 	hdr = trident->tlb.memhdr;
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	/* reset TLB entries */
 	for (page = firstpg(blk); page <= lastpg(blk); page++)
 		set_silent_tlb(trident, page);
 	/* free memory block */
 	__snd_util_mem_free(hdr, blk);
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return 0;
 }
 
@@ -332,18 +334,18 @@
 	struct snd_util_memblk *blk;
 	struct snd_util_memhdr *hdr = hw->tlb.memhdr; 
 
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	blk = __snd_util_mem_alloc(hdr, size);
 	if (blk == NULL) {
-		up(&hdr->block_mutex);
+		mutex_unlock(&hdr->block_mutex);
 		return NULL;
 	}
 	if (synth_alloc_pages(hw, blk)) {
 		__snd_util_mem_free(hdr, blk);
-		up(&hdr->block_mutex);
+		mutex_unlock(&hdr->block_mutex);
 		return NULL;
 	}
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return blk;
 }
 
@@ -356,10 +358,10 @@
 {
 	struct snd_util_memhdr *hdr = hw->tlb.memhdr; 
 
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	synth_free_pages(hw, blk);
 	 __snd_util_mem_free(hdr, blk);
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return 0;
 }
 
diff -urN oldtree/sound/pci/vx222/vx222_ops.c newtree/sound/pci/vx222/vx222_ops.c
--- oldtree/sound/pci/vx222/vx222_ops.c	2006-02-19 11:41:07.161254424 +0000
+++ newtree/sound/pci/vx222/vx222_ops.c	2006-02-21 15:58:11.521395040 +0000
@@ -24,6 +24,8 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/control.h>
 #include <asm/io.h>
@@ -861,10 +863,10 @@
 {
 	struct vx_core *_chip = snd_kcontrol_chip(kcontrol);
 	struct snd_vx222 *chip = (struct snd_vx222 *)_chip;
-	down(&_chip->mixer_mutex);
+	mutex_lock(&_chip->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->input_level[0];
 	ucontrol->value.integer.value[1] = chip->input_level[1];
-	up(&_chip->mixer_mutex);
+	mutex_unlock(&_chip->mixer_mutex);
 	return 0;
 }
 
@@ -872,16 +874,16 @@
 {
 	struct vx_core *_chip = snd_kcontrol_chip(kcontrol);
 	struct snd_vx222 *chip = (struct snd_vx222 *)_chip;
-	down(&_chip->mixer_mutex);
+	mutex_lock(&_chip->mixer_mutex);
 	if (chip->input_level[0] != ucontrol->value.integer.value[0] ||
 	    chip->input_level[1] != ucontrol->value.integer.value[1]) {
 		chip->input_level[0] = ucontrol->value.integer.value[0];
 		chip->input_level[1] = ucontrol->value.integer.value[1];
 		vx2_set_input_level(chip);
-		up(&_chip->mixer_mutex);
+		mutex_unlock(&_chip->mixer_mutex);
 		return 1;
 	}
-	up(&_chip->mixer_mutex);
+	mutex_unlock(&_chip->mixer_mutex);
 	return 0;
 }
 
@@ -907,14 +909,14 @@
 {
 	struct vx_core *_chip = snd_kcontrol_chip(kcontrol);
 	struct snd_vx222 *chip = (struct snd_vx222 *)_chip;
-	down(&_chip->mixer_mutex);
+	mutex_lock(&_chip->mixer_mutex);
 	if (chip->mic_level != ucontrol->value.integer.value[0]) {
 		chip->mic_level = ucontrol->value.integer.value[0];
 		vx2_set_input_level(chip);
-		up(&_chip->mixer_mutex);
+		mutex_unlock(&_chip->mixer_mutex);
 		return 1;
 	}
-	up(&_chip->mixer_mutex);
+	mutex_unlock(&_chip->mixer_mutex);
 	return 0;
 }
 
diff -urN oldtree/sound/pci/ymfpci/ymfpci.c newtree/sound/pci/ymfpci/ymfpci.c
--- oldtree/sound/pci/ymfpci/ymfpci.c	2006-02-19 11:41:07.161254424 +0000
+++ newtree/sound/pci/ymfpci/ymfpci.c	2006-02-21 15:58:11.522394888 +0000
@@ -49,6 +49,7 @@
 static long joystick_port[SNDRV_CARDS];
 #endif
 static int rear_switch[SNDRV_CARDS];
+static int rear_swap[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 1 };
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the Yamaha DS-1 PCI soundcard.");
@@ -66,6 +67,8 @@
 #endif
 module_param_array(rear_switch, bool, NULL, 0444);
 MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch");
+module_param_array(rear_swap, bool, NULL, 0444);
+MODULE_PARM_DESC(rear_swap, "Swap rear channels (must be enabled for correct IEC958 (S/PDIF)) output");
 
 static struct pci_device_id snd_ymfpci_ids[] = {
         { 0x1073, 0x0004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* YMF724 */
@@ -295,7 +298,7 @@
 		snd_card_free(card);
 		return err;
 	}
-	if ((err = snd_ymfpci_mixer(chip, rear_switch[dev])) < 0) {
+	if ((err = snd_ymfpci_mixer(chip, rear_switch[dev], rear_swap[dev])) < 0) {
 		snd_card_free(card);
 		return err;
 	}
diff -urN oldtree/sound/pci/ymfpci/ymfpci_main.c newtree/sound/pci/ymfpci/ymfpci_main.c
--- oldtree/sound/pci/ymfpci/ymfpci_main.c	2006-02-19 11:41:07.164253968 +0000
+++ newtree/sound/pci/ymfpci/ymfpci_main.c	2006-02-21 15:58:11.524394584 +0000
@@ -536,15 +536,30 @@
 			}
 		}
 		if (ypcm->output_rear) {
-			if (use_left) {
-				bank->eff2_gain =
-				bank->eff2_gain_end = vol_left;
-			}
-			if (use_right) {
-				bank->eff3_gain =
-				bank->eff3_gain_end = vol_right;
-			}
-		}
+		        if (!ypcm->swap_rear) {
+        			if (use_left) {
+        				bank->eff2_gain =
+        				bank->eff2_gain_end = vol_left;
+        			}
+        			if (use_right) {
+        				bank->eff3_gain =
+        				bank->eff3_gain_end = vol_right;
+        			}
+		        } else {
+        			/* The SPDIF out channels seem to be swapped, so we have
+        			 * to swap them here, too.  The rear analog out channels
+        			 * will be wrong, but otherwise AC3 would not work.
+        			 */
+        			if (use_left) {
+        				bank->eff3_gain =
+        				bank->eff3_gain_end = vol_left;
+        			}
+        			if (use_right) {
+        				bank->eff2_gain =
+        				bank->eff2_gain_end = vol_right;
+        			}
+        		}
+                }
 	}
 }
 
@@ -894,6 +909,7 @@
 	ypcm = runtime->private_data;
 	ypcm->output_front = 1;
 	ypcm->output_rear = chip->mode_dup4ch ? 1 : 0;
+	ypcm->swap_rear = chip->rear_swap;
 	spin_lock_irq(&chip->reg_lock);
 	if (ypcm->output_rear) {
 		ymfpci_open_extension(chip);
@@ -1734,7 +1750,7 @@
 	chip->ac97 = NULL;
 }
 
-int __devinit snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch)
+int __devinit snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch, int rear_swap)
 {
 	struct snd_ac97_template ac97;
 	struct snd_kcontrol *kctl;
@@ -1746,6 +1762,7 @@
 		.read = snd_ymfpci_codec_read,
 	};
 
+	chip->rear_swap = rear_swap;
 	if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus)) < 0)
 		return err;
 	chip->ac97_bus->private_free = snd_ymfpci_mixer_free_ac97_bus;
@@ -2293,6 +2310,7 @@
 		return -EIO;
 	}
 
+	chip->rear_swap = 1;
 	if ((err = snd_ymfpci_ac3_init(chip)) < 0) {
 		snd_ymfpci_free(chip);
 		return err;
diff -urN oldtree/sound/pcmcia/vx/vxp_mixer.c newtree/sound/pcmcia/vx/vxp_mixer.c
--- oldtree/sound/pcmcia/vx/vxp_mixer.c	2006-02-19 11:41:07.168253360 +0000
+++ newtree/sound/pcmcia/vx/vxp_mixer.c	2006-02-21 15:58:11.524394584 +0000
@@ -52,14 +52,14 @@
 {
 	struct vx_core *_chip = snd_kcontrol_chip(kcontrol);
 	struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip;
-	down(&_chip->mixer_mutex);
+	mutex_lock(&_chip->mixer_mutex);
 	if (chip->mic_level != ucontrol->value.integer.value[0]) {
 		vx_set_mic_level(_chip, ucontrol->value.integer.value[0]);
 		chip->mic_level = ucontrol->value.integer.value[0];
-		up(&_chip->mixer_mutex);
+		mutex_unlock(&_chip->mixer_mutex);
 		return 1;
 	}
-	up(&_chip->mixer_mutex);
+	mutex_unlock(&_chip->mixer_mutex);
 	return 0;
 }
 
@@ -95,14 +95,14 @@
 {
 	struct vx_core *_chip = snd_kcontrol_chip(kcontrol);
 	struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip;
-	down(&_chip->mixer_mutex);
+	mutex_lock(&_chip->mixer_mutex);
 	if (chip->mic_level != ucontrol->value.integer.value[0]) {
 		vx_set_mic_boost(_chip, ucontrol->value.integer.value[0]);
 		chip->mic_level = ucontrol->value.integer.value[0];
-		up(&_chip->mixer_mutex);
+		mutex_unlock(&_chip->mixer_mutex);
 		return 1;
 	}
-	up(&_chip->mixer_mutex);
+	mutex_unlock(&_chip->mixer_mutex);
 	return 0;
 }
 
diff -urN oldtree/sound/sparc/cs4231.c newtree/sound/sparc/cs4231.c
--- oldtree/sound/sparc/cs4231.c	2006-02-19 11:41:07.186250624 +0000
+++ newtree/sound/sparc/cs4231.c	2006-02-21 15:58:11.531393520 +0000
@@ -115,8 +115,8 @@
 	unsigned char		image[32];	/* registers image */
 	int			mce_bit;
 	int			calibrate_mute;
-	struct semaphore	mce_mutex;
-	struct semaphore	open_mutex;
+	struct mutex		mce_mutex;
+	struct mutex		open_mutex;
 
 	union {
 #ifdef SBUS_SUPPORT
@@ -775,7 +775,7 @@
 {
 	unsigned long flags;
 
-	down(&chip->mce_mutex);
+	mutex_lock(&chip->mce_mutex);
 	snd_cs4231_calibrate_mute(chip, 1);
 
 	snd_cs4231_mce_up(chip);
@@ -790,7 +790,7 @@
 	snd_cs4231_mce_down(chip);
 
 	snd_cs4231_calibrate_mute(chip, 0);
-	up(&chip->mce_mutex);
+	mutex_unlock(&chip->mce_mutex);
 }
 
 static void snd_cs4231_capture_format(struct snd_cs4231 *chip, struct snd_pcm_hw_params *params,
@@ -798,7 +798,7 @@
 {
 	unsigned long flags;
 
-	down(&chip->mce_mutex);
+	mutex_lock(&chip->mce_mutex);
 	snd_cs4231_calibrate_mute(chip, 1);
 
 	snd_cs4231_mce_up(chip);
@@ -819,7 +819,7 @@
 	snd_cs4231_mce_down(chip);
 
 	snd_cs4231_calibrate_mute(chip, 0);
-	up(&chip->mce_mutex);
+	mutex_unlock(&chip->mce_mutex);
 }
 
 /*
@@ -933,14 +933,14 @@
 {
 	unsigned long flags;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	if ((chip->mode & mode)) {
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return -EAGAIN;
 	}
 	if (chip->mode & CS4231_MODE_OPEN) {
 		chip->mode |= mode;
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return 0;
 	}
 	/* ok. now enable and ack CODEC IRQ */
@@ -960,7 +960,7 @@
 	spin_unlock_irqrestore(&chip->lock, flags);
 
 	chip->mode = mode;
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	return 0;
 }
 
@@ -968,10 +968,10 @@
 {
 	unsigned long flags;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	chip->mode &= ~mode;
 	if (chip->mode & CS4231_MODE_OPEN) {
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return;
 	}
 	snd_cs4231_calibrate_mute(chip, 1);
@@ -1008,7 +1008,7 @@
 	snd_cs4231_calibrate_mute(chip, 0);
 
 	chip->mode = 0;
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 }
 
 /*
@@ -1969,8 +1969,8 @@
 	spin_lock_init(&chip->lock);
 	spin_lock_init(&chip->c_dma.sbus_info.lock);
 	spin_lock_init(&chip->p_dma.sbus_info.lock);
-	init_MUTEX(&chip->mce_mutex);
-	init_MUTEX(&chip->open_mutex);
+	mutex_init(&chip->mce_mutex);
+	mutex_init(&chip->open_mutex);
 	chip->card = card;
 	chip->dev_u.sdev = sdev;
 	chip->regs_size = sdev->reg_addrs[0].reg_size;
@@ -2157,8 +2157,8 @@
 	spin_lock_init(&chip->lock);
 	spin_lock_init(&chip->c_dma.ebus_info.lock);
 	spin_lock_init(&chip->p_dma.ebus_info.lock);
-	init_MUTEX(&chip->mce_mutex);
-	init_MUTEX(&chip->open_mutex);
+	mutex_init(&chip->mce_mutex);
+	mutex_init(&chip->open_mutex);
 	chip->flags |= CS4231_FLAG_EBUS;
 	chip->card = card;
 	chip->dev_u.pdev = edev->bus->self;
diff -urN oldtree/sound/synth/emux/emux.c newtree/sound/synth/emux/emux.c
--- oldtree/sound/synth/emux/emux.c	2006-02-19 11:41:07.189250168 +0000
+++ newtree/sound/synth/emux/emux.c	2006-02-21 15:58:11.532393368 +0000
@@ -45,7 +45,7 @@
 		return -ENOMEM;
 
 	spin_lock_init(&emu->voice_lock);
-	init_MUTEX(&emu->register_mutex);
+	mutex_init(&emu->register_mutex);
 
 	emu->client = -1;
 #ifdef CONFIG_SND_SEQUENCER_OSS
diff -urN oldtree/sound/synth/emux/emux_oss.c newtree/sound/synth/emux/emux_oss.c
--- oldtree/sound/synth/emux/emux_oss.c	2006-02-19 11:41:07.192249712 +0000
+++ newtree/sound/synth/emux/emux_oss.c	2006-02-21 15:58:11.535392912 +0000
@@ -117,10 +117,10 @@
 	emu = closure;
 	snd_assert(arg != NULL && emu != NULL, return -ENXIO);
 
-	down(&emu->register_mutex);
+	mutex_lock(&emu->register_mutex);
 
 	if (!snd_emux_inc_count(emu)) {
-		up(&emu->register_mutex);
+		mutex_unlock(&emu->register_mutex);
 		return -EFAULT;
 	}
 
@@ -134,7 +134,7 @@
 	if (p == NULL) {
 		snd_printk("can't create port\n");
 		snd_emux_dec_count(emu);
-		up(&emu->register_mutex);
+		mutex_unlock(&emu->register_mutex);
 		return -ENOMEM;
 	}
 
@@ -148,7 +148,7 @@
 
 	snd_emux_reset_port(p);
 
-	up(&emu->register_mutex);
+	mutex_unlock(&emu->register_mutex);
 	return 0;
 }
 
@@ -191,13 +191,13 @@
 	emu = p->emu;
 	snd_assert(emu != NULL, return -ENXIO);
 
-	down(&emu->register_mutex);
+	mutex_lock(&emu->register_mutex);
 	snd_emux_sounds_off_all(p);
 	snd_soundfont_close_check(emu->sflist, SF_CLIENT_NO(p->chset.port));
 	snd_seq_event_port_detach(p->chset.client, p->chset.port);
 	snd_emux_dec_count(emu);
 
-	up(&emu->register_mutex);
+	mutex_unlock(&emu->register_mutex);
 	return 0;
 }
 
diff -urN oldtree/sound/synth/emux/emux_proc.c newtree/sound/synth/emux/emux_proc.c
--- oldtree/sound/synth/emux/emux_proc.c	2006-02-19 11:41:07.193249560 +0000
+++ newtree/sound/synth/emux/emux_proc.c	2006-02-21 15:58:11.536392760 +0000
@@ -37,7 +37,7 @@
 	int i;
 
 	emu = entry->private_data;
-	down(&emu->register_mutex);
+	mutex_lock(&emu->register_mutex);
 	if (emu->name)
 		snd_iprintf(buf, "Device: %s\n", emu->name);
 	snd_iprintf(buf, "Ports: %d\n", emu->num_ports);
@@ -56,13 +56,13 @@
 		snd_iprintf(buf, "Memory Size: 0\n");
 	}
 	if (emu->sflist) {
-		down(&emu->sflist->presets_mutex);
+		mutex_lock(&emu->sflist->presets_mutex);
 		snd_iprintf(buf, "SoundFonts: %d\n", emu->sflist->fonts_size);
 		snd_iprintf(buf, "Instruments: %d\n", emu->sflist->zone_counter);
 		snd_iprintf(buf, "Samples: %d\n", emu->sflist->sample_counter);
 		snd_iprintf(buf, "Locked Instruments: %d\n", emu->sflist->zone_locked);
 		snd_iprintf(buf, "Locked Samples: %d\n", emu->sflist->sample_locked);
-		up(&emu->sflist->presets_mutex);
+		mutex_unlock(&emu->sflist->presets_mutex);
 	}
 #if 0  /* debug */
 	if (emu->voices[0].state != SNDRV_EMUX_ST_OFF && emu->voices[0].ch >= 0) {
@@ -103,7 +103,7 @@
 		snd_iprintf(buf, "sample_mode=%x, rate=%x\n", vp->reg.sample_mode, vp->reg.rate_offset);
 	}
 #endif
-	up(&emu->register_mutex);
+	mutex_unlock(&emu->register_mutex);
 }
 
 
diff -urN oldtree/sound/synth/emux/emux_seq.c newtree/sound/synth/emux/emux_seq.c
--- oldtree/sound/synth/emux/emux_seq.c	2006-02-19 11:41:07.193249560 +0000
+++ newtree/sound/synth/emux/emux_seq.c	2006-02-21 15:58:11.537392608 +0000
@@ -123,12 +123,12 @@
 	if (emu->voices)
 		snd_emux_terminate_all(emu);
 		
-	down(&emu->register_mutex);
+	mutex_lock(&emu->register_mutex);
 	if (emu->client >= 0) {
 		snd_seq_delete_kernel_client(emu->client);
 		emu->client = -1;
 	}
-	up(&emu->register_mutex);
+	mutex_unlock(&emu->register_mutex);
 }
 
 
@@ -311,10 +311,10 @@
 	emu = p->emu;
 	snd_assert(emu != NULL, return -EINVAL);
 
-	down(&emu->register_mutex);
+	mutex_lock(&emu->register_mutex);
 	snd_emux_init_port(p);
 	snd_emux_inc_count(emu);
-	up(&emu->register_mutex);
+	mutex_unlock(&emu->register_mutex);
 	return 0;
 }
 
@@ -332,10 +332,10 @@
 	emu = p->emu;
 	snd_assert(emu != NULL, return -EINVAL);
 
-	down(&emu->register_mutex);
+	mutex_lock(&emu->register_mutex);
 	snd_emux_sounds_off_all(p);
 	snd_emux_dec_count(emu);
-	up(&emu->register_mutex);
+	mutex_unlock(&emu->register_mutex);
 	return 0;
 }
 
diff -urN oldtree/sound/synth/emux/soundfont.c newtree/sound/synth/emux/soundfont.c
--- oldtree/sound/synth/emux/soundfont.c	2006-02-19 11:41:07.198248800 +0000
+++ newtree/sound/synth/emux/soundfont.c	2006-02-21 15:58:11.538392456 +0000
@@ -79,7 +79,7 @@
 lock_preset(struct snd_sf_list *sflist)
 {
 	unsigned long flags;
-	down(&sflist->presets_mutex);
+	mutex_lock(&sflist->presets_mutex);
 	spin_lock_irqsave(&sflist->lock, flags);
 	sflist->presets_locked = 1;
 	spin_unlock_irqrestore(&sflist->lock, flags);
@@ -96,7 +96,7 @@
 	spin_lock_irqsave(&sflist->lock, flags);
 	sflist->presets_locked = 0;
 	spin_unlock_irqrestore(&sflist->lock, flags);
-	up(&sflist->presets_mutex);
+	mutex_unlock(&sflist->presets_mutex);
 }
 
 
@@ -1390,7 +1390,7 @@
 	if ((sflist = kzalloc(sizeof(*sflist), GFP_KERNEL)) == NULL)
 		return NULL;
 
-	init_MUTEX(&sflist->presets_mutex);
+	mutex_init(&sflist->presets_mutex);
 	spin_lock_init(&sflist->lock);
 	sflist->memhdr = hdr;
 
diff -urN oldtree/sound/synth/util_mem.c newtree/sound/synth/util_mem.c
--- oldtree/sound/synth/util_mem.c	2006-02-19 11:41:07.199248648 +0000
+++ newtree/sound/synth/util_mem.c	2006-02-21 15:58:11.538392456 +0000
@@ -18,6 +18,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
+#include <linux/mutex.h>
 #include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -42,7 +43,7 @@
 	if (hdr == NULL)
 		return NULL;
 	hdr->size = memsize;
-	init_MUTEX(&hdr->block_mutex);
+	mutex_init(&hdr->block_mutex);
 	INIT_LIST_HEAD(&hdr->block);
 
 	return hdr;
@@ -136,9 +137,9 @@
 snd_util_mem_alloc(struct snd_util_memhdr *hdr, int size)
 {
 	struct snd_util_memblk *blk;
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	blk = __snd_util_mem_alloc(hdr, size);
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return blk;
 }
 
@@ -163,9 +164,9 @@
 {
 	snd_assert(hdr && blk, return -EINVAL);
 
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	__snd_util_mem_free(hdr, blk);
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return 0;
 }
 
@@ -175,9 +176,9 @@
 int snd_util_mem_avail(struct snd_util_memhdr *hdr)
 {
 	unsigned int size;
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	size = hdr->size - hdr->used;
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return size;
 }
 
diff -urN oldtree/sound/usb/usbaudio.c newtree/sound/usb/usbaudio.c
--- oldtree/sound/usb/usbaudio.c	2006-02-19 11:41:07.202248192 +0000
+++ newtree/sound/usb/usbaudio.c	2006-02-21 15:58:11.541392000 +0000
@@ -47,6 +47,7 @@
 #include <linux/usb.h>
 #include <linux/vmalloc.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/pcm.h>
@@ -202,7 +203,7 @@
  * the all interfaces on the same card as one sound device.
  */
 
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
 static struct snd_usb_audio *usb_chip[SNDRV_CARDS];
 
 
@@ -475,6 +476,18 @@
 	return 0;
 }
 
+/* determine the number of frames in the next packet */
+static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs)
+{
+	if (subs->fill_max)
+		return subs->maxframesize;
+	else {
+		subs->phase = (subs->phase & 0xffff)
+			+ (subs->freqm << subs->datainterval);
+		return min(subs->phase >> 16, subs->maxframesize);
+	}
+}
+
 /*
  * Prepare urb for streaming before playback starts.
  *
@@ -492,16 +505,7 @@
 	urb->dev = ctx->subs->dev;
 	urb->number_of_packets = subs->packs_per_ms;
 	for (i = 0; i < subs->packs_per_ms; ++i) {
-		/* calculate the size of a packet */
-		if (subs->fill_max)
-			counts = subs->maxframesize; /* fixed */
-		else {
-			subs->phase = (subs->phase & 0xffff)
-				+ (subs->freqm << subs->datainterval);
-			counts = subs->phase >> 16;
-			if (counts > subs->maxframesize)
-				counts = subs->maxframesize;
-		}
+		counts = snd_usb_audio_next_packet_size(subs);
 		urb->iso_frame_desc[i].offset = offs * stride;
 		urb->iso_frame_desc[i].length = counts * stride;
 		offs += counts;
@@ -538,16 +542,7 @@
 	urb->number_of_packets = 0;
 	spin_lock_irqsave(&subs->lock, flags);
 	for (i = 0; i < ctx->packets; i++) {
-		/* calculate the size of a packet */
-		if (subs->fill_max)
-			counts = subs->maxframesize; /* fixed */
-		else {
-			subs->phase = (subs->phase & 0xffff)
-				+ (subs->freqm << subs->datainterval);
-			counts = subs->phase >> 16;
-			if (counts > subs->maxframesize)
-				counts = subs->maxframesize;
-		}
+		counts = snd_usb_audio_next_packet_size(subs);
 		/* set up descriptor */
 		urb->iso_frame_desc[i].offset = offs * stride;
 		urb->iso_frame_desc[i].length = counts * stride;
@@ -1390,8 +1385,8 @@
 	channels = params_channels(hw_params);
 	fmt = find_format(subs, format, rate, channels);
 	if (! fmt) {
-		snd_printd(KERN_DEBUG "cannot set format: format = %s, rate = %d, channels = %d\n",
-			   snd_pcm_format_name(format), rate, channels);
+		snd_printd(KERN_DEBUG "cannot set format: format = 0x%x, rate = %d, channels = %d\n",
+			   format, rate, channels);
 		return -EINVAL;
 	}
 
@@ -2017,6 +2012,8 @@
 };
 
 
+#if defined(CONFIG_PROCFS) && defined(CONFIG_SND_VERBOSE_PROCFS)
+
 /*
  * proc interface for list the supported pcm formats
  */
@@ -2032,7 +2029,7 @@
 		fp = list_entry(p, struct audioformat, list);
 		snd_iprintf(buffer, "  Interface %d\n", fp->iface);
 		snd_iprintf(buffer, "    Altset %d\n", fp->altsetting);
-		snd_iprintf(buffer, "    Format: %s\n", snd_pcm_format_name(fp->format));
+		snd_iprintf(buffer, "    Format: 0x%x\n", fp->format);
 		snd_iprintf(buffer, "    Channels: %d\n", fp->channels);
 		snd_iprintf(buffer, "    Endpoint: %d %s (%s)\n",
 			    fp->endpoint & USB_ENDPOINT_NUMBER_MASK,
@@ -2107,6 +2104,13 @@
 		snd_info_set_text_ops(entry, stream, 1024, proc_pcm_format_read);
 }
 
+#else
+
+static inline void proc_pcm_format_add(struct snd_usb_stream *stream)
+{
+}
+
+#endif
 
 /*
  * initialize the substream instance.
@@ -3282,7 +3286,7 @@
 
 	/* check whether it's already registered */
 	chip = NULL;
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	for (i = 0; i < SNDRV_CARDS; i++) {
 		if (usb_chip[i] && usb_chip[i]->dev == dev) {
 			if (usb_chip[i]->shutdown) {
@@ -3335,13 +3339,13 @@
 
 	usb_chip[chip->index] = chip;
 	chip->num_interfaces++;
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return chip;
 
  __error:
 	if (chip && !chip->num_interfaces)
 		snd_card_free(chip->card);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
  __err_val:
 	return NULL;
 }
@@ -3361,7 +3365,7 @@
 
 	chip = ptr;
 	card = chip->card;
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	chip->shutdown = 1;
 	chip->num_interfaces--;
 	if (chip->num_interfaces <= 0) {
@@ -3379,10 +3383,10 @@
 			snd_usb_mixer_disconnect(p);
 		}
 		usb_chip[chip->index] = NULL;
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		snd_card_free(card);
 	} else {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 	}
 }
 
diff -urN oldtree/sound/usb/usbmidi.c newtree/sound/usb/usbmidi.c
--- oldtree/sound/usb/usbmidi.c	2006-02-19 11:41:07.204247888 +0000
+++ newtree/sound/usb/usbmidi.c	2006-02-21 15:58:11.542391848 +0000
@@ -1082,6 +1082,8 @@
 	{ USB_ID(0x0582, 0x004d), 0, "%s MIDI" },
 	{ USB_ID(0x0582, 0x004d), 1, "%s 1" },
 	{ USB_ID(0x0582, 0x004d), 2, "%s 2" },
+	/* Edirol UM-3EX */
+	{ USB_ID(0x0582, 0x009a), 3, "%s Control" },
 	/* M-Audio MidiSport 8x8 */
 	{ USB_ID(0x0763, 0x1031), 8, "%s Control" },
 	{ USB_ID(0x0763, 0x1033), 8, "%s Control" },
diff -urN oldtree/sound/usb/usbquirks.h newtree/sound/usb/usbquirks.h
--- oldtree/sound/usb/usbquirks.h	2006-02-19 11:41:07.210246976 +0000
+++ newtree/sound/usb/usbquirks.h	2006-02-21 15:58:11.543391696 +0000
@@ -294,7 +294,8 @@
 	}
 },
 {
-	/* a later revision uses ID 0x0099 */
+	/* Has ID 0x0099 when not in "Advanced Driver" mode.
+	 * The UM-2EX has only one input, but we cannot detect this. */
 	USB_DEVICE(0x0582, 0x0005),
 	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
 		.vendor_name = "EDIROL",
@@ -385,7 +386,7 @@
 	}
 },
 {
-	/* a later revision uses ID 0x009d */
+	/* has ID 0x009d when not in "Advanced Driver" mode */
 	USB_DEVICE(0x0582, 0x0009),
 	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
 		.vendor_name = "EDIROL",
@@ -1090,6 +1091,53 @@
 		}
 	}
 },
+	/* TODO: add Edirol UA-101 support */
+{
+	/* has ID 0x0081 when not in "Advanced Driver" mode */
+	USB_DEVICE(0x0582, 0x0080),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "Roland",
+		.product_name = "G-70",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const struct snd_usb_midi_endpoint_info) {
+			.out_cables = 0x0001,
+			.in_cables  = 0x0001
+		}
+	}
+},
+	/* TODO: add Roland V-SYNTH XT support */
+	/* TODO: add BOSS GT-PRO support */
+{
+	/* has ID 0x008c when not in "Advanced Driver" mode */
+	USB_DEVICE(0x0582, 0x008b),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "EDIROL",
+		.product_name = "PC-50",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const struct snd_usb_midi_endpoint_info) {
+			.out_cables = 0x0001,
+			.in_cables  = 0x0001
+		}
+	}
+},
+	/* TODO: add Edirol PC-80 support */
+	/* TODO: add Edirol UA-1EX support */
+{
+	USB_DEVICE(0x0582, 0x009a),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "EDIROL",
+		.product_name = "UM-3EX",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const struct snd_usb_midi_endpoint_info) {
+			.out_cables = 0x000f,
+			.in_cables  = 0x000f
+		}
+	}
+},
+	/* TODO: add Edirol MD-P1 support */
 
 /* Guillemot devices */
 {
@@ -1111,15 +1159,6 @@
 		}
 	}
 },
-	/* TODO: add Edirol UA-101 support */
-	/* TODO: add Roland G-70 support */
-	/* TODO: add Roland V-SYNTH XT support */
-	/* TODO: add BOSS GT-PRO support */
-	/* TODO: add Edirol PC-50 support */
-	/* TODO: add Edirol PC-80 support */
-	/* TODO: add Edirol UA-1EX support */
-	/* TODO: add Edirol UM-3 support */
-	/* TODO: add Edirol MD-P1 support */
 
 /* Midiman/M-Audio devices */
 {
diff -urN oldtree/sound/usb/usx2y/usbusx2y.c newtree/sound/usb/usx2y/usbusx2y.c
--- oldtree/sound/usb/usx2y/usbusx2y.c	2006-02-19 11:41:07.212246672 +0000
+++ newtree/sound/usb/usx2y/usbusx2y.c	2006-02-21 15:58:11.545391392 +0000
@@ -351,7 +351,7 @@
 	usX2Y(card)->chip.dev = device;
 	usX2Y(card)->chip.card = card;
 	init_waitqueue_head(&usX2Y(card)->prepare_wait_queue);
-	init_MUTEX (&usX2Y(card)->prepare_mutex);
+	mutex_init(&usX2Y(card)->prepare_mutex);
 	INIT_LIST_HEAD(&usX2Y(card)->chip.midi_list);
 	strcpy(card->driver, "USB "NAME_ALLCAPS"");
 	sprintf(card->shortname, "TASCAM "NAME_ALLCAPS"");
diff -urN oldtree/sound/usb/usx2y/usbusx2y.h newtree/sound/usb/usx2y/usbusx2y.h
--- oldtree/sound/usb/usx2y/usbusx2y.h	2006-02-19 11:41:07.213246520 +0000
+++ newtree/sound/usb/usx2y/usbusx2y.h	2006-02-21 15:58:11.545391392 +0000
@@ -34,7 +34,7 @@
 	unsigned int		rate,
 				format;
 	int			chip_status;
-	struct semaphore	prepare_mutex;
+	struct mutex		prepare_mutex;
 	struct us428ctls_sharedmem	*us428ctls_sharedmem;
 	int			wait_iso_frame;
 	wait_queue_head_t	us428ctls_wait_queue_head;
diff -urN oldtree/sound/usb/usx2y/usbusx2yaudio.c newtree/sound/usb/usx2y/usbusx2yaudio.c
--- oldtree/sound/usb/usx2y/usbusx2yaudio.c	2006-02-19 11:41:07.214246368 +0000
+++ newtree/sound/usb/usx2y/usbusx2yaudio.c	2006-02-21 15:58:11.546391240 +0000
@@ -811,7 +811,7 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_usX2Y_substream *subs = runtime->private_data;
-	down(&subs->usX2Y->prepare_mutex);
+	mutex_lock(&subs->usX2Y->prepare_mutex);
 	snd_printdd("snd_usX2Y_hw_free(%p)\n", substream);
 
 	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
@@ -832,7 +832,7 @@
 			usX2Y_urbs_release(subs);
 		}
 	}
-	up(&subs->usX2Y->prepare_mutex);
+	mutex_unlock(&subs->usX2Y->prepare_mutex);
 	return snd_pcm_lib_free_pages(substream);
 }
 /*
@@ -849,7 +849,7 @@
 	int err = 0;
 	snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
 
-	down(&usX2Y->prepare_mutex);
+	mutex_lock(&usX2Y->prepare_mutex);
 	usX2Y_subs_prepare(subs);
 // Start hardware streams
 // SyncStream first....
@@ -869,7 +869,7 @@
 		err = usX2Y_urbs_start(subs);
 
  up_prepare_mutex:
-	up(&usX2Y->prepare_mutex);
+	mutex_unlock(&usX2Y->prepare_mutex);
 	return err;
 }
 
diff -urN oldtree/sound/usb/usx2y/usx2yhwdeppcm.c newtree/sound/usb/usx2y/usx2yhwdeppcm.c
--- oldtree/sound/usb/usx2y/usx2yhwdeppcm.c	2006-02-19 11:41:07.216246064 +0000
+++ newtree/sound/usb/usx2y/usx2yhwdeppcm.c	2006-02-21 15:58:11.547391088 +0000
@@ -366,7 +366,7 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_usX2Y_substream *subs = runtime->private_data,
 		*cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
-	down(&subs->usX2Y->prepare_mutex);
+	mutex_lock(&subs->usX2Y->prepare_mutex);
 	snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream);
 
 	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
@@ -395,7 +395,7 @@
 				usX2Y_usbpcm_urbs_release(cap_subs2);
 		}
 	}
-	up(&subs->usX2Y->prepare_mutex);
+	mutex_unlock(&subs->usX2Y->prepare_mutex);
 	return snd_pcm_lib_free_pages(substream);
 }
 
@@ -503,7 +503,7 @@
 		memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
 	}
 
-	down(&usX2Y->prepare_mutex);
+	mutex_lock(&usX2Y->prepare_mutex);
 	usX2Y_subs_prepare(subs);
 // Start hardware streams
 // SyncStream first....
@@ -544,7 +544,7 @@
 		usX2Y->hwdep_pcm_shm->capture_iso_start = -1;
 
  up_prepare_mutex:
-	up(&usX2Y->prepare_mutex);
+	mutex_unlock(&usX2Y->prepare_mutex);
 	return err;
 }
 
@@ -621,7 +621,7 @@
 		if (dev->type != SNDRV_DEV_PCM)
 			continue;
 		pcm = dev->device_data;
-		down(&pcm->open_mutex);
+		mutex_lock(&pcm->open_mutex);
 	}
 	list_for_each(list, &card->devices) {
 		int s;
@@ -650,7 +650,7 @@
 		if (dev->type != SNDRV_DEV_PCM)
 			continue;
 		pcm = dev->device_data;
-		up(&pcm->open_mutex);
+		mutex_unlock(&pcm->open_mutex);
 	}
 }
 
